tcl8.4.20/0000755003604700454610000000000012153151143010701 5ustar dgp771divtcl8.4.20/tools/0000755003604700454610000000000012153151143012041 5ustar dgp771divtcl8.4.20/tools/man2html.tcl0000644003604700454610000000762611737050675014321 0ustar dgp771div#!/proj/tcl/install/5.x-sparc/bin/tclsh7.5 if [catch { # man2html.tcl -- # # This file contains procedures that work in conjunction with the # man2tcl program to generate a HTML files from Tcl manual entries. # # Copyright (c) 1996 by Sun Microsystems, Inc. set homeDir /home/rjohnson/Projects/tools/generic # sarray - # # Save an array to a file so that it can be sourced. # # Arguments: # file - Name of the output file # args - Name of the arrays to save # proc sarray {file args} { set file [open $file w] foreach a $args { upvar $a array if ![array exists array] { puts "sarray: \"$a\" isn't an array" break } foreach name [lsort [array names array]] { regsub -all " " $name "\\ " name1 puts $file "set ${a}($name1) \{$array($name)\}" } } close $file } # footer -- # # Builds footer info for HTML pages # # Arguments: # None proc footer {packages} { lappend f "
" set h {[} foreach package $packages { lappend h "$package" lappend h "|" } lappend f [join [lreplace $h end end {]} ] " "] lappend f "
" lappend f "
Copyright © 1989-1994 The Regents of the University of California."
    lappend f "Copyright © 1994-1996 Sun Microsystems, Inc."
    lappend f "
" return [join $f "\n"] } # doDir -- # # Given a directory as argument, translate all the man pages in # that directory. # # Arguments: # dir - Name of the directory. proc doDir dir { foreach f [lsort [glob -directory $dir "*.\[13n\]"]] { do $f ;# defined in man2html1.tcl & man2html2.tcl } } if {$argc < 2} { puts stderr "usage: $argv0 html_dir tcl_dir packages..." puts stderr "usage: $argv0 -clean html_dir" exit 1 } if {[lindex $argv 0] == "-clean"} { set html_dir [lindex $argv 1] puts -nonewline "recursively remove: $html_dir? " flush stdout if {[gets stdin] == "y"} { puts "removing: $html_dir" exec rm -r $html_dir } exit 0 } set html_dir [lindex $argv 0] set tcl_dir [lindex $argv 1] set packages [lrange $argv 2 end] #### need to add glob capability to packages #### # make sure there are doc directories for each package foreach i $packages { if ![file exists $tcl_dir/$i/doc] { puts stderr "Error: doc directory for package $i is missing" exit 1 } if ![file isdirectory $tcl_dir/$i/doc] { puts stderr "Error: $tcl_dir/$i/doc is not a directory" exit 1 } } # we want to start with a clean sheet if [file exists $html_dir] { puts stderr "Error: HTML directory already exists" exit 1 } else { exec mkdir $html_dir } set footer [footer $packages] # make the hyperlink arrays and contents.html for all packages foreach package $packages { global homeDir exec mkdir $html_dir/$package # build hyperlink database arrays: NAME_file and KEY_file # puts "\nScanning man pages in $tcl_dir/$package/doc..." source $homeDir/man2html1.tcl doDir $tcl_dir/$package/doc # clean up the NAME_file and KEY_file database arrays # catch {unset KEY_file()} foreach name [lsort [array names NAME_file]] { set file_name $NAME_file($name) if {[llength $file_name] > 1} { set file_name [lsort $file_name] puts stdout "Warning: '$name' multiply defined in: $file_name; using last" set NAME_file($name) [lindex $file_name end] } } # sarray $html_dir/$package/xref.tcl NAME_file KEY_file # build the contents file from NAME_file # puts "\nGenerating contents.html for $package" doContents $html_dir/$package/contents.html $lib ;# defined in man2html1.tcl # now translate the man pages to HTML pages # source $homeDir/man2html2.tcl puts "\nBuilding html pages from man pages in $tcl_dir/$package/doc..." doDir $tcl_dir/$package/doc unset NAME_file } } result] { global errorInfo puts stderr $result puts stderr "in" puts stderr $errorInfo } tcl8.4.20/tools/tcl.hpj.in0000644003604700454610000000053712153151143013740 0ustar dgp771div; This file is maintained by HCW. Do not modify this file directly. [OPTIONS] HCW=0 LCID=0x409 0x0 0x0 ;English (United States) REPORT=Yes TITLE=Tcl/Tk Reference Manual CNT=tcl84.cnt COPYRIGHT=Copyright ТЉ 2000 Ajuba Solutions HLP=tcl84.hlp [FILES] tcl.rtf [WINDOWS] main="Tcl/Tk Reference Manual",,0 [CONFIG] BrowseButtons() tcl8.4.20/tools/tclSplash.bmp0000644003604700454610000047435611737050675014540 0ustar dgp771divBMюx6(еUИtМ†„‚‚ТТ„BФЦЦDBЂдВDBBМŠRЬІ†ўўФžЂТЌb фЦ†„bBьжŽьцЦфццдЖŽdbbФ†*дЎZФž"Ќb*„ТТфжЦФ–”B2ЄЂЂєіцФ–†ФžZькЊєіоьцж„bЂTRRДrфЦVœR"$&&М†Ьž„ЂТДvFмЦЎджжЬЎžlnnєііфЮІDBbМ†jдВІДЖЖŒŽŽдЎ>ЄbЄbVфжžЬš:bТфЦjМŽ„BBфв†єюЦДz.˜J*”––ФоТєюжьожќўіЬЮЮЬІЌjJєюцЌj"ФЂЂФžzœR:Œ:2ЬІмЦЖЌЊЊДv^Д†zМООнЦz„BЂдЎ†мЦ–Єb>ьоŽэцЮмО–ФbbФ–"дЎjЬІ*ьоЦФ–ЬЂjэцоМzЄZ"НŽфЮЖмКžМŽ†мТJЌn„bТОŽ œNB”J2мооД††ЄZBТдЖ2МŠbЬЂšЬž Ќj|zz422„ЂтЂт„bтФž–ЬЂ2ФB„BbDbТDBТФЂтМ†:ьцОДrrДzzЌj2Ќjb LJJмО†\ZZФŽrмЖBьоžœžž<::фТfДrRфЮ–ФŽ2Фž†ДzдЖrдЎЎФТТФТЂЌjVМŽzфЮzМŽ–ьоОЬš.дІмКЊьоЖєЪІмОЖмЦОмЦžЌbJœNNфЮЦ„bbдЖЖфж–ЦЂbєњўЬІІМ†ZМŠМŠrфЪrфвОЬІ:”F>фттtrrДn&ЬІžдЊдОІ„††ЄІІьоЎTVVЌЎЎДvVмЦЦмВ&єіюЄbќўў№юю”::дООœN2ьк–М† ЬІŽЌb2фжЮФ– ”B:œR*ЬžЬЎІфЮЎдЎFфжІєюЮєюоЬІ дЎrьоЮФ–ЄZ*МŽŽЌj мОŽФžŽДz фЮЮфжжьооЌbBДvbЬžєцЦьццЬž"єцжќііЌbФŽеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееP1оееееееее0ЪGжееежЫ§еееxЮеее§ееееењ›[3ееееЫ8ееееM90еее3Ю30еееMЪ3ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее§ПžЎ§ееееее[ЭЭ†8еее›*&•*›еееM”—Юеее8*†ееееx§еееееееx•‚2*—xееж&x&GеееG—*еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЁнёPеееееx*†[еееœ&њP‚&еееLXKЛеее‚M*Gееее0Лееее•еее[†ж8LЮее•&””9еееxL*еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееежSm}Pеее3›”œ9жеее•M0‚&еее†8еееее‚00*GееежM2њЛеее•еее†9x›†8еег†*Gеее”›§еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееоž §е姆&&xее§X‚œœ*8еее†ЮеееееЪ‚x0*GеееG&†‚xеее•ееењЭ*•*ХњеежLЪ0*9ее囆—ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееMЭœ9еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее§Sй’/еее38ЫЮ3еееKЫЫЛееењЮњеееееM83ж80еее[ЫЫЫЫжеее[MееееxЮЫ8xеееЛ8њг80ееењ8Ы[3ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее&ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее/н)S§ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЭееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееJѓѓєѓєо3ееееееееPєооооооPkmOеееееееееееегшbhhhhќеееееееееее§PIPшPшIќIP§еееPљљљљљDbееееееееKbљљљDљљљчеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее&ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее‡ЕUзЕZбееееееееоЈOFйссаПВKіmн/ееееееееее§СъŽs€€€€ f4§Kеееееееељххх>ЌЌ\цгеЏћџпхЉееееееее\|NNјNrЉееееееееееееееееееееееееееееЭœ9MЭЭЭеееХœœЭ9ееееее&9ееееФ†&ееХ†&Э9ееее9œœЭ9ее9&&ЭЭеMЭЭ&ЭееЭ&œœ&9еееееХХ9Э&ЭЭеее9œœЭ9еее9œœЭХее&†ФеееЭЯЭХФеееХœЭœ9еее9&ЭЭЭе9&ЭЭ9еЭ&ЭЭ9еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееKњ‡рU‘3§ееееееее3ж F))ЈJг§еOmmЩееееееееееEя€Ef–ъЂlfPееееееееPцхЂuТЃхьeљKPЏтћ§ееееееееKгšШNN|Ь#KеееееееееееееееееееееееееееФ†ЯXеX‚9еее‚XееXХееееееееXее&œееФ†Хее&XееXХее99ееееФœеее&9ееФ†&еееЭеФеФœеее&XееXХеXФее&†ееXееXЭееœееФ†ЭееФ†&еее99еее99еее99ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееѕ“з<еееееееееее§аFйіоееееа)mЩеееееееее_sў€fќЛK§I№lђ!еееееееееuшг§ЬЌџIеK\џпDKееееееееееCNщCKеееееееееееееееееееееееееееееХMеее9XееXХееее2ееееХХ9ееееXееЭеее&еХееееЭееXXеееее&еееЭееее9MееXЫееееЭееХееееЭеXХеееXXеMXеееЯЯееееXXеХеее9MееXXеееXXеееXXеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЄррбееееееееееб`FFЁ§ееее6mmЩ§еееееееoЦ€s§ееееееKфОђЃKееееееееŸ+ЂТќеееее$iџеIgееееееееееш™NN|IееееееееееееееееееееееееееееееЯЯееееXXее&еееееееееœФœеееееееееееXЯе&MеееееееXXеееееЭеее&ееееФХееЫXееееЭее&MееееееФФееФЯMеееееXХеееееееЯœееееФХееXXеееXXеееXXеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееє<рюеееееееее§ wйіВеееее6m) геееееег!;!шеееееееееЃ'ЋеееЛЛЛеЛŸn>шеееееехџiЏег,§еееееееее"­NN@KееееееееееееееееееееееееееееееЭееееXXееЭеееееееееX9еœееееееееФ9‚XеЭееееееееXXеееееЭеееЭеееееЭееЫXееееЭееЭеееееееееXЭЭееееееXXеееееее&еееее&ееXXеееXXеееXXеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛю<њеееегњњkѓYFFOЎЖСЖСЖаmmНpЩpЩЩpЩ^EЦcееееееееееkЂЂ>ЃЃЃЃ–_Ÿ_fue\Ÿ_ŸŸŸх"Ћ\цIшшш#геегЉјNШKеееKееееееееееееееееееееееееее&ееееXXее&&Э&Э&&ее&ее9ХеееееееФЯЭMее&ееееееееXXеееееЭеее&еееееЭееXXееееЭее&ееееееееЭœ9еееееееXXеееееееЭеееееЭееXXеееXXеееXXеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее§ѕєєJиИИИ‡Њ“У<“її“ЇЇЇ<йFййіДііOіэm)эQQЦдEыеееееееееее ''ЂЂЂЂл+u+ЂЂu+iuiiiџџiћћ,­Тg|g|:™™™,јNN@РЉšššЬDчч#Kееееееееееееееееееееœ†ееееXXее9Xеее9XеФЭеееЯеееееееЭ&еееее9ФеееееееXXеееееЭеееЭееееФЭееXXееееЭее9ФееееееXЯеееееееееФ9еееееееЯœееееФХееXXеееXXеееXXееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееѓЄуМyy‘‘ЕЕЕ<ЕЕЕУUУTУvTwйFwFFFFсссссmm)mmmzmzzдў;ўŽееееееееееееfЂ'ЂЂЂЂЂЂЂ'џЂџAџџјјV,јNјNШ­вв||((@@aЙкDеееееееееееееееее9еееЫXееФ9еееХе9Xеее&9ееееее&еее9XеФ9еееХЯееЫХеФФееЭеее&еееХXееXXееееЭееФ9еееХЯеXXееЭеееееееœœееееХеее9MееXœеее9ХеееХXееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееPєѕ1Uv‡ИиБу‡~ПTFFЇ66666}6’)m’а а .Ц;; ееееееееееее'ђОee>>>ЌџuˆТТТТТтџџgх™iјˆР\Љ\"цјNVDчI#ЛеееееееееееееееееееееееееееееЭ†еФЯXеееXЯеЫХеXЯXФеMХЯXеееееXеЯXееXXеXЯеMЭЭХЯФЫЭееXЯХ9XЭœееХХXФXЭеееXXеXЯееЯЭеФЭ&еееееее†ЭеФЯMееœЯФеX†ЭееХ&ЭX9Я9ХX9†ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееж<рМЛееее§уwFйеееееее6m)SJPkшPkJj;ўjееееееееееее4'О_ЋЋЋЋчkP4ОЂЌшшш#Iџi"еееехееееешNјј@KееееееееееееееееееееееееееееееееееMХ&Э2XееееХЭЭMееXXXXеXXXееееееФХЭЭ9ееееMХЭЭ9ееXЭФФХXФXХ9ееX9ХеЭЭ9еееM9ХXMФXХ9ееееMХЭЭ9ееее9ЭЭХееееееее9ЭЭХееееXЭЭЭMеееMXХMФ9ЭЭMеХЭХееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛ‡U‘PеееежїFFДЛеееееееП)m Лееееежf;jееееееееееее4'Ђеееееее"e>шеееK4eџPееееI­ЏееееејN,ЏеееееееееееееееееееееееееееееееееееееееXXеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееœXееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееоЕУѓKеееєйwFЧееееееееПm) гееееегSў;Кееееееееееее4'ЂoеееееееЏeЂˆќе§гŸтџџТDKееее§хј\геее§™јјr#еееееееееееееееееееееееееееееееееееееееЫXееееееееееееееееееееееееееееееееееееееееееееееееееееХXеееееееееееееееXXееее2Xеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееежqqееееёw`њееееееее6zm §ееееежj;jееееееееееее4'Ђoеееееее"ee\\Тuџuљееееееец:IеееЬV щкееееееееееееееееееееееееееееееееееееееееXXеееееееееееееееееееееееееееееееееееееееееееееееееееXееееееееееееееееееееXеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееИvvжеежДwF §ееееееееПm) геееее§Sў;jееееееееееее4'ЂoеееееееЏe'ueˆ iџО\KеееееееешвпцKеK@јвIеееееееееееееееееееееееееееееееееееееееЯXееееееееееееееееееееееееееееееееееееееееееееееееееееХXеееееееееееееееееееееХXееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееењЄKеБTTВKееееееееПmm Kееееежj;jееееееееееее4'Ђoеееееее"eeцbD4ˆi=§ееееееееKCr§ељ|јNЛеееееееееееееееееееееееееееееееееееееееееФеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее‡vї§еЈFїѕеееееееее6m) геееее3S;jееееееееееее4'ЂoеееееееЏe'ТkееKцьт#еееееееееgDе=,јVЬеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееєђ'ЃќKеееPbfue\ŸТџхIееееееееееееIтNŸKееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееJ“qгеееееееееоаДээmэ.мееС EўдўsŽъњееееееќj ђЂђ+>СKееЌ+ђџnnuџ:_#Kееееееееееее§Р|љеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееегЛееееееееееЛжжжжKееЛжP§PPKеееееее§KPPЛеееPKKееееееееееееееегKKееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЭХФееееееееееXXЫеееЭееееееееЫХ‚XеееееееX‚œXФеееееЭееее9ЯXеееееееееееXЫXееееЭXееееееее&еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее&Xеееееееее†XXXX&ее&ееееееееXXXЭеее2ХXеее‚ХXХœ9ееее&еееее&XФееееееееее†XXЫX‚Эеее&œееееееееXХXMееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее9†œеееееееее‚ХееееXœее9еееееееХеееЫ9ееXXеее9œеœ†еее9ееееЭееееееееееее‚ХееееХ9ееœеееееееееФœееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее&ЭееееееееЭеееееееееее&ееееееееXееееЭееXXеее&9ееее&2еееЭееее&ееееееееееееЯеееее&Xее9ЭЭЭееееееееее9ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЭ†еееееее&еееееееееееЭееееееееXеее&ЭееXXеееЭееееееееЭееееееееееееееееЭееееееЭ‚ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее†ХœееееееЯЭ&Эеееееее†еееееееееее9ееФ‚Xеее&ееееее9ее†ееее9еееееееееееЭееееее&еееееееее&&ЭЭЭЭ&&&&ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееXЫеXХееееееœ†&&ЫФееееXХеееееееее2ЭееееЭеее9Эеееее‚œеXXеееЭеееееееееееX‚Фееее2еееееееееœееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееXXеФ‚ееееееXЯMеX‚œееееX‚ееееееее&œXеееее&ееееЭеееееXXеX‚еееЭеееееееееееФ‚Xеее&ХеееееееееXXXXXXXXXееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее‚Xееœ9еееееœXееM&еееЮ9еееееееMееееее&ееееХЭеееееXXеЮ9ееХЭееееееееееееMœе&œеееееееееœ9еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЯMеее9Xеееее9Хееееее†ХХХФее&ееееXеееXеееЯXееееXXе†ХХХXXеееееееееееее&Эеееееееееееее&ХееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЭеееееХ‚еееееXееееMеее&Xœ‚œеMееееXеееееееM‚‚еее‚œее&XХœ‚Xееееееееееееее9еееееееееееееееХ&еее9еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЭеееееXœееееееХ&ее&ееееЭXХXееееееœееееееееMœеееЭеееЭXœXеееееееееееее†2&9еееееееееееееœ9ееХЭееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЭ9ееееее&еееееееЭœœЭеееXее9еееЭ†œеЫееееее9ЭœЭеееXее9†еееееееееееее†Mее92ееееееееееееееЭœеXЭееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее&еееееееMœЭееееееееXXXееееXXXXXеееXXXееееMXXXXXеXXЫXXMееееееееXXXXееееXXXXXеееXXXMееееееееееееееЭееееЭееееееееееееееХ‚еXЭееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЭееееееее†еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееXееееееееееееееœЭЮЯееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее‚еееееееееœXееееееееееееееееееееееееееееееееееееееееееXXXMееееееееееееееееееееееееееееееееееееееееееееœЭееееXееееееееееееееее‚œXееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЭеееееееееXœееееееееееееееееееееееееееееееееееееееееееХЭееееееееееееееееееееееееееееееееееееееееееее‚Я&ее9XееееееееееееееееXXеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЭЯ&ееееее9œ&ееееееееееееееееееееееееееееееееееееееееX†ееееееееееееееееееееееееееееееееееееееееееееMЭЭЯХееееееееееееееееееХXеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЭЭЭЭЭЭЭMеееееееЭЭЭЭMееееееееееееееееееееееееееееееееееееееееMЭЭЭMеееееееееееееееееееееееееееееееееееееееееееееее9ЭЭЭЭ9ееееееееееееееееееее9ЭЭЭеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее33ееееЛ§Леееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее{{Œ‹]--ƒ8oo3ЛЛЛееЛеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛ§3§ЛЛЛЛЛЛЛЛ§ЛЛеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее‹{{{{{{{{{{{{{{‹%Œ›ƒЮ8o3ЛеKKЛЛЛ3ЛЛеееееееееееееееееееееееееееееееееее3Л3ЛеЛЛЛЛЛЛЛЛЛ§еееееееееЛ33ж3oooo8ƒ-ƒ-ƒG-G-G-t%tƒееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее]{{{{{{{{{{{{{{{{{{{{{{{{{‹Œ…G--ƒo33ЛЛ§Л§ЛЛЛЛЛЛЛЛЛеееееееееееЛ33ж3oo/-ƒЮƒG-G-G-Gtt‹‹‹‹‹{{{{{{{{{{{{{{{{{{{{{{{-ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееt{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹%--ƒG-G-G-G-]t‹‹Œ‹{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее§-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{Hееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{HеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛG{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{Hееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{3еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееж-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{Лееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееƒ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{Леееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееж-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{Лееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееƒ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹ЛеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛ-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹Лееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее[{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛo{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееH{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹Лееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееo{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{tеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{-Kееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееж{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{-еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{-еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее3{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее‹{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛ‹{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{H‹{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее3‹{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹Л{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{Ѕееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее‹{{{{{{{{{{{{{‹ƒƒƒt{{{{{{{{{{{-ƒƒ-‹{{{{{{{{ttttttŒ{{{{{{{{-3{{{{{{{{{{-ƒƒƒ‹{{{{{{{tttttŒ‹ttttt‹{{{{{{{{{{{{{{{{{{{Сееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее{{{{{{{{{{{{{Hежƒƒƒ{{{{{{{{‹3H{‹ƒG{{{{{{{‹-Hе§8-{{{{{{{{ƒo{{{{{{{{{tеЛHƒH{{{{{{-ƒеЛ3-‹‹ƒее3ƒt{{{{{{{{{{{{{{{{{{{Hееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее‹{{{{{{{{{{{{{ЛеЛ{{-{{{{{{{‹ЛЛ…{{{{ƒ‹{{{{{{{{ƒЛе-{{{{{{{{{{H-{{{{{{{{{ƒЛе-{t{{{{{{{ŒЛKH{{{ƒееH{{{{{{{{{{{{{{{{{{{{{Лееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее{{{{{{{{{{{{{Леж{{{{{{{{{{ƒе3‹{{{{Œƒ{{{{{{{{ƒЛ§-{{{{{{{{{‹Л{{{{{{{{{ƒЛЛG{{{{{{{{{{ŒеЛH{{ƒЛЛ3{{{{{{{{{{{{{{{{{{{{{Лееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее…{{{{{{{{{{{{{ЛЛЛ{{{{{{{{{{ЛеЛ‹{{{{{{{{{{{{{ƒЛе-{{{{{{{{{…3‹{{{{{{{{{ƒЛе-{{{{{{{{{{ŒЛеH{tЛеЛ‹{{{{{{{{{{{{{{{{{{{{{{Леееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее§…{{{{{{{{{{{{{Леж{{{{{{{{{Œееж‹{{{{{{{{{{{{{{ƒеЛG{{{{{{{{{ƒo{{{{{{{{{{ƒе§-{{{{{{{{{{ŒееH‹ЛЛ3G{{{{{{{{{{{{{{{{{{{{{{{еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее-{{{{{{{{{{{{{ЛеЛ{{{{{{{{{ееЛ‹{{{{{{{{{{{{{{ƒЛе-{{{{{{{{{Hƒ{{{{{{{{{{ƒЛе-{{{{{{{{{{ŒЛеH[ееƒ{{{{{{{{{{{{{{{{{{{{{{{{KееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛЛG{{{{{{{{{{{{{Леж{{{{{{{{{{HЛ3‹{{‹ƒ8Œ{{{{{{{{ƒЛ§-{{{{{{{{{ЛG{{{{{{{{{{ƒеЛG{{{{{{{{{{Œее8‹Лж{{{{{{{{{{{{{{{{{{{{{{{{‹еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее-{{{{{{{{{{{{{ЛеЛ{{{{{{{{{{ƒее‹{{-§е-{{{{{{{{ƒЛе-{{{{{{{{‹е‹{{{{{{{{{{ƒее-{{{{{{{{{{ŒЛеH{‹Mt{{{{{{{{{{{{{{{{{{{{{{{‹ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее§-{{{{{{{{{{{{{ее3{{{{{{{{{{{HЛ-{{‹ЛЛG{{{{{{{{ƒеЛG{{{{{{{{-Л{{{{{{{{{{ƒе3-{{{{{{{{{{Œееo{{‹Ht{{{{{{{{{{{{{{{{{{{{{{‹еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее-{{{{{{{{{{{-MKееHH-{{{{{{{{ЅЛ‹{‹H8{{{{{{{{{ƒЛе-{{{{{{{{-ж{{{{{{{{{‹oЛееHHƒ{{{{{{{{ŒKеH{{tƒж-…t{{{{{{{{{{{{{{{{{{{‹ЛеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛG{{{{{{{{{{{Œ‹ЛеЛŒ{{{{{{{{{{{---{{{{{{{{{{ƒЛ§-{{{{{{{{Mƒ{{{{{{{{{{‹ƒЛЛƒŒ{{{{{{{{ŒеЛo{{G--G-]{{{{{{{{{{{{{{{{{{{tееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛƒ{{{{{{{{{{{{{ЛЛЛ{{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒЛе-{{{{{{{{Лƒ{{{{{{{{{{{ƒее-{{{{{{{{{{ŒKеH{{{{{{{{{{{{{{{{{{{{{{{{{{{-KееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛ§-{{{{{{{{{{{{{Л§ж{{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒеЛG{{{{{{{‹еG{{{{{{{{{{{ƒЛе›{{{{{{{{{{ŒеЛo{{{{{{{{{{{{{{{{{{{{{{{{{{{-ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛƒ{{{{{{{{{{{{{‹%{{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒЛе-{{{{{{{-е‹{{{{{{{{{{{‹%Œ{{{{{{{{{{ŒЛеH{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛ-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒе§-{{{{{{{ƒе{{{{{{{{{{{{{{{{{{{{{{{{{ŒеKo{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒЛе-{{{{{{{8Л{{{{{{{{{{{{{{{{{{{{{{{{{{ŒееH{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛo{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒЛЛG{{{{{{{Лo{{{{{{{{{{{{{{{{{{{{{{{{{{?еKo{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееH{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{Œƒo3ж-{{{{{{{Л[{{{{{{{{{{{{{{{{{{{{{{{{ƒ8oЛЅ{{{{{{{{{{{{{{{{{{{{{{{{{{{еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееo{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹§ƒ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ЅеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{-Л›55{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{Сеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееж{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ŠŒƒK&Š{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{HеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{BB{ƒЛзŒ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{Hеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееж{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{——з{0жз{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ЛеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛ‹{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{›!Š{ЛH-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{Леееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее3Œ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{[}‹е8]ƒ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ЛееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееŒ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹H!‹е›з-t{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ŒKееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹}{tе}%o{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее‹{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{[Gз{-е!зƒ-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒЮз{ЅЛvto{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее‹{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹ЛŠ{8ЛŠС‹{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹Леееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее§‹{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ЅЊ5{H3зƒƒ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{tеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее‹{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹ЛŒЛKtЛ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{-еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛЛG{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ЅеTŒЛ]Л{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{-еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹Лее[{%еHз0-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее§-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒЛ3o-Gзз{%еЎ8-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ССt{{Šз{%еІ›H{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛG{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{Œ-{{{{Šз{%еЊR3{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛ-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‚Š{›е!!еŒ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛ§-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{Š{Rе}з5UзКе{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{[ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛƒ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹5{‡еd{{{Š›Лt{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{HееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛ-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{t5{[еЕŠ{{-HЛ3-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{Hеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееƒ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{Œ%{[Лdз{…ƒжее-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{3еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееKЛo{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{-Š{[ЛЭ{{{-ЛG{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ЛеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееH{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒŠŒ{HЛ‚{{{{-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ЛееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛo{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒзŒHеTŒ‹{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ЛеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееH{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹-U{HЛŠ-t{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹Леееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееж{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒŒ{ЛЛTз{Ѕ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{8Œ{ЛеŒ-H{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееж{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{M{ЛЛT{Сt{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹8{Ле{ƒ[{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹Леееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее3{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{-ƒŠз{ЛЛTŠ{‹Л{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{…еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее‹{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒ-Šз{ЛеŠ{‹Л‹{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{-KеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{M‹‚{{ЛЛTз{{3-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{-ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛ‹{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{3‹з{{3ез{ŒЛ-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{-ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛ‹{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹жŒ{{ЛеTŒtе{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{-еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее‹{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{t3Œ{{HЛ-Л‹{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{-M{{HЛTƒе{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееt{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒ85Œ{[еŠЛ‹{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее]{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{8Š{ЅЛЭŠƒ3‹{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{Hеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееt{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒз{8еdзƒЛt{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{Сееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее§-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{жƒ‚{-еЕƒЛG{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{Hеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹3-5{-еd-Лƒ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ЛееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛG{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹3-Š{-е}›§-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ЛееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛ-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹Л-Š{tе!%ЛH{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{Лееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее§-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{tеGз{‹ЛЊе3{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛƒ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{-е›з{‹ЛІзее‹{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹3ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛ-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{-еЊз{ŒЛ8зHе{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееƒ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{-ЛЩ{{С[-Лƒ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹ЛееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛЮ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{-Л8{HMtе8{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹Леееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее[{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{-ЛH{8ЛеЛ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹Леееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееежƒ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒеЛŠ{-ЛзŠ-еее‹{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{Леееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееƒ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ЛеŠ{tЛŠ{{‹-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{3ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееж-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ееRTз{‹еT{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{Hеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееƒ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ЛееЛ8Ез{ŒЛdз{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее§ƒ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{-еЛж%ŠŒH}‚{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{Gее‹{{Š{[›Š{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{-KееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееG{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{-Л{{{зŠ{›7{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{-еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{-t{{{{‚з{%8з-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{-еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее]{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{Œ]M%-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееt{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{[ŠС‹{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹ЛеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛ‹{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ŒŠ{›TU-H{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее‹{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‚Œ—dŒЛ-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ŒЛееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{Š}Šƒе{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{Лееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее‹{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{]!зtЛƒ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{3еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{%TзŒЛ3‹{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{HеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{%vƒЛ[{{{{{?{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒЛееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееж{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ХŠ‹еЛ‹{{{{{„{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{›‚{Ле{{{{{ {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееKж{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{Њ{ƒее{{{{?„{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{-еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{G‹Ле-{{{{{ ?{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{-KееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееKЛo{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{8Š{ее[{{{{{„ {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееH{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{Hз{8ее{{{{{? {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛo{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{СзŒƒее]{{{{{ „{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее[{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{H‹ЛЛ-{{{{{„ ?{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ŒЛееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееежƒ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{H}Š‹Л§-{{{{{? {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееƒ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{8›з{ЛеH{{{{{{ {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{3еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееж-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{-MHеж{{{{{{ {{{{{{{{{{{{{{{{{{{{{{{{{{{{{Hееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{„{{{{{{{{{{tЛ5HЛЛ{{{{{{? {{{{{{{{{{{{{{{{{{{{{{{{{{{{{8еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее§-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ {{{{{{{{{{‹ЛЕŠЅЛж{{{{{{? {{{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{?{{{{{{{{{{3ІBЛеH{{{{{{{ „{{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛG{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ {{{{{{{{{{{ƒжзŠзBdRеее8{{{{{{{„ {{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ ?{{{{{{{{{{…ЛЗ{{-Сееееееƒ{{{{{{{? ?{{{{{{{{?{{{{{{{{{{{{{{{{{{-ЛееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛ%{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ {{{{{{{{{{{е8‚{{{{{ƒHЛЛЛ{{{{{{{? {{{{{{{{? {{{{{{{{{{{{{{{{{‹ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее‹{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ {{{{{{{{{{{8еB5{{{{{{{‹G{{{{{{{{{ {{{{{{{{{?{{{{{{{{{{{{{{{{‹ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ {{{{{{{{{{{‹еGŒ{{{{{{{{{{{{{{{{{{ {{{{{{{{{„ {{{{{{{{{{{{{{{{‹ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее‹{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ {{{{{{{{{{{{oЛ‰Š{{{{{{{{{{{{{{{{{{ {{{{{{{{„ ?{{{{{{{{{{{{{{{{ЛееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееKŒ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ {{{{{{{{{{{{-Л!{{{{{{{{{{{{{{{{{ {{{{{{{{„ {{{{{{{{{{{{{{{{еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛŒ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ ?{{{{{{{{{{{{3ЛBз{{{{{{{{{{{{{{{{{ {{{{{{{{ {{{{{{{{{{{{{{{{3ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееж{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{„ ?{{{{{{{{{{{{-еGз{{{{{{{{{{{{{{{? {{{{{{{? {{{{{{{{{{{{{{{{HееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛ‹{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ „{{{{{{{{{{{{{3е{{{{{{{{{{{{{?„ {{{{{{{„ {{{{{{{{{{{{{{{{8ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееж{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{? {{{{{{{{{{{{{tKM‚{{{{{{{{{{{{{{ {{{{{{{? {{{{{{{{{{{{{{{{{ƒееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{? {{{{{{{{{{{{{{ƒЛRŠ{{{{{{{{{{{{{{{{{{{{{{{{ {{{{{{{{{{{{{{{{{{ƒеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееKж{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ ?{{{{{{{{{{{{{‹Ле!{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{-ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ ?{{{{{{{{{{{{{{GЛе{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{-ЛееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛo{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{„ {{{{{{{{{{{{{{{ƒеЛз{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{tееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееС{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{? {{{{{{{{{{{{{{{{СеЛŠ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееж{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{? {{{{{{{{{{{{{{{{‹ееЛœ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееƒ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{?{{{{{ {{{{{{{{{{{{{{{{]ЛеЛd{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹Лееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее§ƒ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{?{{{{{„ {{{{{{{{{{{{{{{{{-Лее›&{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееƒ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{? {{{{{{{{{{{{{{{{{{ƒ§ееАB-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{3еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛЛG{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{„{{{{{{ {{{{{{{{{{{{{{{{{{{ƒееее!Š{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{Hеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{? {{{{{{ „{{{{{{{{{{{{{{{{{{{-ЛеееHК%[0{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{Сееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее§-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{?{{{{{{? ?{{{{{{{{{{{{{{{{{{{-ееееееЛHЛЛ3G{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ {{{{{{{ {{{{{{{{{{{{{{{{{{{{Лееееееее[{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{-еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееG{{{{{{{{{{{{{{{{{{{{{{{{{{{{{? {{{{{{{„ {{{{{{{{{{{{{{{{{{{{{‹ƒЛееKK§Ю{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{? ?{{{{{{? ?{{{{{{{{{{{{{{{{{{{{{{ƒoo8-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{-KееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееŒ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{? {{{{{{{„ {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{tеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееt{{{{{{{{{{{{{{{{{{{{{{{{{{{{{? {{{{{{{? „{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹ЛеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛ‹{{{{{{{{{{{{{{{{{{{{{{{{{{{{{? {{{{{{{{ {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹Лееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее‹{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ ?{{{{{{{? {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹Лееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее{{{{{{{{{{{{{{{{{{{{{{{{{{{{{? {{{{{{{{„ „{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{Лееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее‹{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ ?{{{{{{{{ „{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{3еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ „{{{{{{{{„ ?{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{HеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛ‹{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{? ?{{{{{{{{ „ {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееж{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{? {{{{{{{{? {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{? ?{{{{{{{{? {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{-KеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛж{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{?{{{{{{{{{{? {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{-еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееH{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{-ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееKo{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{…еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееH{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹Леееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее§Ю{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееƒ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹Лееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееежƒ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{Лееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееƒ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{3еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееж-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{Hееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{[еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее§-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее-{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ƒеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛG{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{-ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееt{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{-еееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееЛt{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹ƒHHHHЅƒƒƒ---t‹‹‹‹{{{{{{{{{{{{{{{{{tееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее‹{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{tHееееееееееееееееееееееееHЅЅƒƒƒƒ---tt-ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееƒ‹‹‹Œ‹{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹ƒееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееHHƒƒƒ----…‹‹‹‹‹{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{-ЅеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееHHЅƒƒƒ---tt‹‹‹‹{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{‹ƒееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееHHЅЅƒƒ--tt‹‹‹‹Œ{{{{{{{{{{{tЅеееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееHHЅƒƒƒееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееtcl8.4.20/tools/man2html1.tcl0000644003604700454610000001237711737050675014401 0ustar dgp771div# man2html1.tcl -- # # This file defines procedures that are used during the first pass of the # man page to html conversion process. It is sourced by h.tcl. # # Copyright (c) 1996 by Sun Microsystems, Inc. # Global variables used by these scripts: # # state - state variable that controls action of text proc. # # curFile - tail of current man page. # # file - file pointer; for both xref.tcl and contents.html # # NAME_file - array indexed by NAME and containing file names used # for hyperlinks. # # KEY_file - array indexed by KEYWORD and containing file names used # for hyperlinks. # # lib - contains package name. Used to label section in contents.html # # inDT - in dictionary term. # text -- # # This procedure adds entries to the hypertext arrays NAME_file # and KEY_file. # # DT: might do this: if first word of $dt matches $name and [llength $name==1] # and [llength $dt > 1], then add to NAME_file. # # Arguments: # string - Text to index. proc text string { global state curFile NAME_file KEY_file inDT switch $state { NAME { foreach i [split $string ","] { lappend NAME_file([string trim $i]) $curFile } } KEY { foreach i [split $string ","] { lappend KEY_file([string trim $i]) $curFile } } DT - OFF - DASH {} default { puts stderr "text: unknown state: $state" } } } # macro -- # # This procedure is invoked to process macro invocations that start # with "." (instead of '). # # Arguments: # name - The name of the macro (without the "."). # args - Any additional arguments to the macro. proc macro {name args} { switch $name { SH { global state switch $args { NAME { if {$state == "INIT" } { set state NAME } } DESCRIPTION {set state DT} INTRODUCTION {set state DT} KEYWORDS {set state KEY} default {set state OFF} } } TP { global inDT set inDT 1 } TH { global lib state inDT set inDT 0 set state INIT if {[llength $args] != 5} { set args [join $args " "] puts stderr "Bad .TH macro: .$name $args" } set lib [lindex $args 3] ;# Tcl or Tk } } } # dash -- # # This procedure is invoked to handle dash characters ("\-" in # troff). It only function in pass1 is to terminate the NAME state. # # Arguments: # None. proc dash {} { global state if {$state == "NAME"} { set state DASH } } # newline -- # # This procedure is invoked to handle newlines in the troff input. # It's only purpose is to terminate a DT (dictionary term). # # Arguments: # None. proc newline {} { global inDT set inDT 0 } # initGlobals, tab, font, char, macro2 -- # # These procedures do nothing during the first pass. # # Arguments: # None. proc initGlobals {} {} proc tab {} {} proc font type {} proc char name {} proc macro2 {name args} {} # doListing -- # # Writes an ls like list to a file. Searches NAME_file for entries # that match the input pattern. # # Arguments: # file - Output file pointer. # pattern - glob style match pattern proc doListing {file pattern} { global NAME_file set max_len 0 foreach name [lsort [array names NAME_file]] { set ref $NAME_file($name) if [string match $pattern $ref] { lappend type $name if {[string length $name] > $max_len} { set max_len [string length $name] } } } if [catch {llength $type} ] { puts stderr " doListing: no names matched pattern ($pattern)" return } incr max_len set ncols [expr 90/$max_len] set nrows [expr int( ceil( [llength $type] / $ncols. ) ) ] # ? max_len ncols nrows set index 0 foreach f $type { lappend row([expr $index % $nrows]) $f incr index } puts -nonewline $file "
"
    for {set i 0} {$i<$nrows} {incr i} {
	foreach name $row($i) {
	    set str [format "%-*s" $max_len $name]
	    regsub $name $str "$name" str
	    puts -nonewline $file $str
	}
	puts $file {}
    }
    puts $file "
" } # doContents -- # # Generates a HTML contents file using the NAME_file array # as its input database. # # Arguments: # file - name of the contents file. # packageName - string used in the title and sub-heads of the HTML page. Normally # name of the package without version numbers. proc doContents {file packageName} { global footer set file [open $file w] puts $file "$packageName Manual" puts $file "

$packageName

" doListing $file "*.1" puts $file "

$packageName Commands

" doListing $file "*.n" puts $file "

$packageName Library

" doListing $file "*.3" puts $file $footer puts $file "" close $file } # do -- # # This is the toplevel procedure that searches a man page # for hypertext links. It builds a data base consisting of # two arrays: NAME_file and KEY file. It runs the man2tcl # program to turn the man page into a script, then it evals # that script. # # Arguments: # fileName - Name of the file to scan. proc do fileName { global curFile set curFile [file tail $fileName] set file stdout puts " Pass 1 -- $fileName" flush stdout if [catch {eval [exec man2tcl [glob $fileName]]} msg] { global errorInfo puts stderr $msg puts "in" puts $errorInfo exit 1 } } tcl8.4.20/tools/genStubs.tcl0000644003604700454610000006764512052456744014376 0ustar dgp771div# genStubs.tcl -- # # This script generates a set of stub files for a given # interface. # # # Copyright (c) 1998-1999 by Scriptics Corporation. # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. package require Tcl 8 namespace eval genStubs { # libraryName -- # # The name of the entire library. This value is used to compute # the USE_*_STUBS macro and the name of the init file. variable libraryName "UNKNOWN" # interfaces -- # # An array indexed by interface name that is used to maintain # the set of valid interfaces. The value is empty. array set interfaces {} # curName -- # # The name of the interface currently being defined. variable curName "UNKNOWN" # scspec -- # # Storage class specifier for external function declarations. # Normally "EXTERN", may be set to something like XYZAPI # variable scspec "EXTERN" # epoch, revision -- # # The epoch and revision numbers of the interface currently being defined. # (@@@TODO: should be an array mapping interface names -> numbers) # variable epoch {} variable revision 0 # hooks -- # # An array indexed by interface name that contains the set of # subinterfaces that should be defined for a given interface. array set hooks {} # stubs -- # # This three dimensional array is indexed first by interface name, # second by platform name, and third by a numeric offset or the # constant "lastNum". The lastNum entry contains the largest # numeric offset used for a given interface/platform combo. Each # numeric offset contains the C function specification that # should be used for the given entry in the stub table. The spec # consists of a list in the form returned by parseDecl. array set stubs {} # outDir -- # # The directory where the generated files should be placed. variable outDir . } # genStubs::library -- # # This function is used in the declarations file to set the name # of the library that the interfaces are associated with (e.g. "tcl"). # This value will be used to define the inline conditional macro. # # Arguments: # name The library name. # # Results: # None. proc genStubs::library {name} { variable libraryName $name } # genStubs::interface -- # # This function is used in the declarations file to set the name # of the interface currently being defined. # # Arguments: # name The name of the interface. # # Results: # None. proc genStubs::interface {name} { variable curName $name variable interfaces set interfaces($name) {} return } # genStubs::scspec -- # # Define the storage class macro used for external function declarations. # Typically, this will be a macro like XYZAPI or EXTERN that # expands to either DLLIMPORT or DLLEXPORT, depending on whether # -DBUILD_XYZ has been set. # proc genStubs::scspec {value} { variable scspec $value } # genStubs::epoch -- # # Define the epoch number for this library. The epoch # should be incrememented when a release is made that # contains incompatible changes to the public API. # proc genStubs::epoch {value} { variable epoch $value } # genStubs::hooks -- # # This function defines the subinterface hooks for the current # interface. # # Arguments: # names The ordered list of interfaces that are reachable through the # hook vector. # # Results: # None. proc genStubs::hooks {names} { variable curName variable hooks set hooks($curName) $names return } # genStubs::declare -- # # This function is used in the declarations file to declare a new # interface entry. # # Arguments: # index The index number of the interface. # platform The platform the interface belongs to. Should be one # of generic, win, unix, or macosx or aqua or x11. # decl The C function declaration, or {} for an undefined # entry. # # Results: # None. proc genStubs::declare {args} { variable stubs variable curName variable revision incr revision if {[llength $args] == 2} { lassign $args index decl set platformList generic } elseif {[llength $args] == 3} { lassign $args index platformList decl } else { puts stderr "wrong # args: declare $args" return } # Check for duplicate declarations, then add the declaration and # bump the lastNum counter if necessary. foreach platform $platformList { if {[info exists stubs($curName,$platform,$index)]} { puts stderr "Duplicate entry: declare $args" } } regsub -all const $decl CONST decl regsub -all _XCONST $decl _Xconst decl regsub -all "\[ \t\n\]+" [string trim $decl] " " decl set decl [parseDecl $decl] foreach platform $platformList { if {$decl != ""} { set stubs($curName,$platform,$index) $decl if {![info exists stubs($curName,$platform,lastNum)] \ || ($index > $stubs($curName,$platform,lastNum))} { set stubs($curName,$platform,lastNum) $index } } } return } # genStubs::export -- # # This function is used in the declarations file to declare a symbol # that is exported from the library but is not in the stubs table. # # Arguments: # decl The C function declaration, or {} for an undefined # entry. # # Results: # None. proc genStubs::export {args} { if {[llength $args] != 1} { puts stderr "wrong # args: export $args" } return } # genStubs::rewriteFile -- # # This function replaces the machine generated portion of the # specified file with new contents. It looks for the !BEGIN! and # !END! comments to determine where to place the new text. # # Arguments: # file The name of the file to modify. # text The new text to place in the file. # # Results: # None. proc genStubs::rewriteFile {file text} { if {![file exists $file]} { puts stderr "Cannot find file: $file" return } set in [open ${file} r] set out [open ${file}.new w] fconfigure $out -translation lf while {![eof $in]} { set line [gets $in] if {[regexp {!BEGIN!} $line]} { break } puts $out $line } puts $out "/* !BEGIN!: Do not edit below this line. */" puts $out $text while {![eof $in]} { set line [gets $in] if {[regexp {!END!} $line]} { break } } puts $out "/* !END!: Do not edit above this line. */" puts -nonewline $out [read $in] close $in close $out file rename -force ${file}.new ${file} return } # genStubs::addPlatformGuard -- # # Wrap a string inside a platform #ifdef. # # Arguments: # plat Platform to test. # # Results: # Returns the original text inside an appropriate #ifdef. proc genStubs::addPlatformGuard {plat iftxt {eltxt {}} {withCygwin 0}} { set text "" switch $plat { win { append text "#if defined(__WIN32__)" if {$withCygwin} { append text " || defined(__CYGWIN__)" } append text " /* WIN */\n${iftxt}" if {$eltxt != ""} { append text "#else /* WIN */\n${eltxt}" } append text "#endif /* WIN */\n" } unix { append text "#if !defined(__WIN32__)" if {$withCygwin} { append text " && !defined(__CYGWIN__)" } append text " && !defined(MAC_OSX_TCL)\ /* UNIX */\n${iftxt}" if {$eltxt != ""} { append text "#else /* UNIX */\n${eltxt}" } append text "#endif /* UNIX */\n" } macosx { append text "#ifdef MAC_OSX_TCL /* MACOSX */\n${iftxt}" if {$eltxt != ""} { append text "#else /* MACOSX */\n${eltxt}" } append text "#endif /* MACOSX */\n" } aqua { append text "#ifdef MAC_OSX_TK /* AQUA */\n${iftxt}" if {$eltxt != ""} { append text "#else /* AQUA */\n${eltxt}" } append text "#endif /* AQUA */\n" } x11 { append text "#if !(defined(__WIN32__)" if {$withCygwin} { append text " || defined(__CYGWIN__)" } append text " || defined(MAC_OSX_TK))\ /* X11 */\n${iftxt}" if {$eltxt != ""} { append text "#else /* X11 */\n${eltxt}" } append text "#endif /* X11 */\n" } default { append text "${iftxt}${eltxt}" } } return $text } # genStubs::emitSlots -- # # Generate the stub table slots for the given interface. If there # are no generic slots, then one table is generated for each # platform, otherwise one table is generated for all platforms. # # Arguments: # name The name of the interface being emitted. # textVar The variable to use for output. # # Results: # None. proc genStubs::emitSlots {name textVar} { upvar $textVar text forAllStubs $name makeSlot 1 text {" VOID *reserved$i;\n"} return } # genStubs::parseDecl -- # # Parse a C function declaration into its component parts. # # Arguments: # decl The function declaration. # # Results: # Returns a list of the form {returnType name args}. The args # element consists of a list of type/name pairs, or a single # element "void". If the function declaration is malformed # then an error is displayed and the return value is {}. proc genStubs::parseDecl {decl} { if {![regexp {^(.*)\((.*)\)$} $decl all prefix args]} { set prefix $decl set args {} } set prefix [string trim $prefix] if {![regexp {^(.+[ ][*]*)([^ *]+)$} $prefix all rtype fname]} { puts stderr "Bad return type: $decl" return } set rtype [string trim $rtype] if {$args == ""} { return [list $rtype $fname {}] } foreach arg [split $args ,] { lappend argList [string trim $arg] } if {![string compare [lindex $argList end] "..."]} { set args TCL_VARARGS foreach arg [lrange $argList 0 end-1] { set argInfo [parseArg $arg] if {[llength $argInfo] == 2 || [llength $argInfo] == 3} { lappend args $argInfo } else { puts stderr "Bad argument: '$arg' in '$decl'" return } } } else { set args {} foreach arg $argList { set argInfo [parseArg $arg] if {![string compare $argInfo "void"]} { lappend args "void" break } elseif {[llength $argInfo] == 2 || [llength $argInfo] == 3} { lappend args $argInfo } else { puts stderr "Bad argument: '$arg' in '$decl'" return } } } return [list $rtype $fname $args] } # genStubs::parseArg -- # # This function parses a function argument into a type and name. # # Arguments: # arg The argument to parse. # # Results: # Returns a list of type and name with an optional third array # indicator. If the argument is malformed, returns "". proc genStubs::parseArg {arg} { if {![regexp {^(.+[ ][*]*)([^][ *]+)(\[\])?$} $arg all type name array]} { if {$arg == "void"} { return $arg } else { return } } set result [list [string trim $type] $name] if {$array != ""} { lappend result $array } return $result } # genStubs::makeDecl -- # # Generate the prototype for a function. # # Arguments: # name The interface name. # decl The function declaration. # index The slot index for this function. # # Results: # Returns the formatted declaration string. proc genStubs::makeDecl {name decl index} { variable scspec lassign $decl rtype fname args append text "/* $index */\n" if {($rtype != "void") && ($rtype != "pascal void")} { regsub -all void $rtype VOID rtype } set line "$scspec $rtype" set count [expr {2 - ([string length $line] / 8)}] append line [string range "\t\t\t" 0 $count] set pad [expr {24 - [string length $line]}] if {$pad <= 0} { append line " " set pad 0 } if {$args == ""} { append line $fname append text $line append text ";\n" return $text } append line "$fname _ANSI_ARGS_(" regsub -all void $args VOID args set arg1 [lindex $args 0] switch -exact $arg1 { VOID { append line "(void)" } TCL_VARARGS { set arg [lindex $args 1] append line "TCL_VARARGS([lindex $arg 0],[lindex $arg 1])" } default { set sep "(" foreach arg $args { append line $sep set next {} append next [lindex $arg 0] if {[string index $next end] != "*"} { append next " " } append next [lindex $arg 1] [lindex $arg 2] if {[string length $line] + [string length $next] \ + $pad > 76} { append text [string trimright $line] \n set line "\t\t\t\t" set pad 28 } append line $next set sep ", " } append line ")" } } return "$text$line);\n" } # genStubs::makeMacro -- # # Generate the inline macro for a function. # # Arguments: # name The interface name. # decl The function declaration. # index The slot index for this function. # # Results: # Returns the formatted macro definition. proc genStubs::makeMacro {name decl index} { lassign $decl rtype fname args set lfname [string tolower [string index $fname 0]] append lfname [string range $fname 1 end] set text "#ifndef $fname\n#define $fname" set arg1 [lindex $args 0] set argList "" switch -exact $arg1 { void { set argList "()" } TCL_VARARGS { } default { set sep "(" foreach arg $args { append argList $sep [lindex $arg 1] set sep ", " } append argList ")" } } append text " \\\n\t(${name}StubsPtr->$lfname)" append text " /* $index */\n#endif\n" return $text } # genStubs::makeSlot -- # # Generate the stub table entry for a function. # # Arguments: # name The interface name. # decl The function declaration. # index The slot index for this function. # # Results: # Returns the formatted table entry. proc genStubs::makeSlot {name decl index} { lassign $decl rtype fname args set lfname [string tolower [string index $fname 0]] append lfname [string range $fname 1 end] set text " " if {$args == ""} { append text $rtype " *" $lfname "; /* $index */\n" return $text } if {($rtype != "void") && ($rtype != "pascal void")} { regsub -all void $rtype VOID rtype } if {[string range $rtype end-8 end] == "__stdcall"} { append text [string trim [string range $rtype 0 end-9]] " (__stdcall *" $lfname ") _ANSI_ARGS_(" } else { append text $rtype " (*" $lfname ") _ANSI_ARGS_(" } regsub -all void $args VOID args set arg1 [lindex $args 0] switch -exact $arg1 { VOID { append text "(void)" } TCL_VARARGS { set sep "(" foreach arg [lrange $args 1 end] { append text $sep [lindex $arg 0] if {[string index $text end] != "*"} { append text " " } append text [lindex $arg 1] [lindex $arg 2] set sep ", " } append text ", ...)" } default { set sep "(" foreach arg $args { append text $sep [lindex $arg 0] if {[string index $text end] != "*"} { append text " " } append text [lindex $arg 1] [lindex $arg 2] set sep ", " } append text ")" } } append text "); /* $index */\n" return $text } # genStubs::makeInit -- # # Generate the prototype for a function. # # Arguments: # name The interface name. # decl The function declaration. # index The slot index for this function. # # Results: # Returns the formatted declaration string. proc genStubs::makeInit {name decl index} { if {[lindex $decl 2] == ""} { append text " &" [lindex $decl 1] ", /* " $index " */\n" } else { append text " " [lindex $decl 1] ", /* " $index " */\n" } return $text } # genStubs::forAllStubs -- # # This function iterates over all of the platforms and invokes # a callback for each slot. The result of the callback is then # placed inside appropriate platform guards. # # Arguments: # name The interface name. # slotProc The proc to invoke to handle the slot. It will # have the interface name, the declaration, and # the index appended. # onAll If 1, emit the skip string even if there are # definitions for one or more platforms. # textVar The variable to use for output. # skipString The string to emit if a slot is skipped. This # string will be subst'ed in the loop so "$i" can # be used to substitute the index value. # # Results: # None. proc genStubs::forAllStubs {name slotProc onAll textVar {skipString {"/* Slot $i is reserved */\n"}}} { variable stubs upvar $textVar text set plats [array names stubs $name,*,lastNum] if {[info exists stubs($name,generic,lastNum)]} { # Emit integrated stubs block set lastNum -1 foreach plat [array names stubs $name,*,lastNum] { if {$stubs($plat) > $lastNum} { set lastNum $stubs($plat) } } for {set i 0} {$i <= $lastNum} {incr i} { set slots [array names stubs $name,*,$i] set emit 0 if {[info exists stubs($name,generic,$i)]} { if {[llength $slots] > 1} { puts stderr "conflicting generic and platform entries:\ $name $i" } append text [$slotProc $name $stubs($name,generic,$i) $i] set emit 1 } elseif {[llength $slots] > 0} { array set slot {unix 0 x11 0 win 0 macosx 0 aqua 0} foreach s $slots { set slot([lindex [split $s ,] 1]) 1 } # "aqua", "macosx" and "x11" are special cases: # "macosx" implies "unix", "aqua" implies "macosx" and "x11" # implies "unix", so we need to be careful not to emit # duplicate stubs entries: if {($slot(unix) && $slot(macosx)) || ( ($slot(unix) || $slot(macosx)) && ($slot(x11) || $slot(aqua)))} { puts stderr "conflicting platform entries: $name $i" } ## unix ## set temp {} set plat unix if {!$slot(aqua) && !$slot(x11)} { if {$slot($plat)} { append temp [$slotProc $name $stubs($name,$plat,$i) $i] } elseif {$onAll} { eval {append temp} $skipString } } if {$temp ne ""} { append text [addPlatformGuard $plat $temp] set emit 1 } ## x11 ## set temp {} set plat x11 if {!$slot(unix) && !$slot(macosx)} { if {$slot($plat)} { append temp [$slotProc $name $stubs($name,$plat,$i) $i] } elseif {$onAll} { eval {append temp} $skipString } } if {$temp ne ""} { append text [addPlatformGuard $plat $temp] set emit 1 } ## win ## set temp {} set plat win if {$slot($plat)} { append temp [$slotProc $name $stubs($name,$plat,$i) $i] } elseif {$onAll} { eval {append temp} $skipString } if {$temp ne ""} { append text [addPlatformGuard $plat $temp] set emit 1 } ## macosx ## set temp {} set plat macosx if {!$slot(aqua) && !$slot(x11)} { if {$slot($plat)} { append temp [$slotProc $name $stubs($name,$plat,$i) $i] } elseif {$slot(unix)} { append temp [$slotProc $name $stubs($name,unix,$i) $i] } elseif {$onAll} { eval {append temp} $skipString } } if {$temp ne ""} { append text [addPlatformGuard $plat $temp] set emit 1 } ## aqua ## set temp {} set plat aqua if {!$slot(unix) && !$slot(macosx)} { if {[string range $skipString 1 2] ne "/*"} { # genStubs.tcl previously had a bug here causing it to # erroneously generate both a unix entry and an aqua # entry for a given stubs table slot. To preserve # backwards compatibility, generate a dummy stubs entry # before every aqua entry (note that this breaks the # correspondence between emitted entry number and # actual position of the entry in the stubs table, e.g. # TkIntStubs entry 113 for aqua is in fact at position # 114 in the table, entry 114 at position 116 etc). eval {append temp} $skipString set temp "[string range $temp 0 end-1] /*\ Dummy entry for stubs table backwards\ compatibility */\n" } if {$slot($plat)} { append temp [$slotProc $name $stubs($name,$plat,$i) $i] } elseif {$onAll} { eval {append temp} $skipString } } if {$temp ne ""} { append text [addPlatformGuard $plat $temp] set emit 1 } } if {!$emit} { eval {append text} $skipString } } } else { # Emit separate stubs blocks per platform array set block {unix 0 x11 0 win 0 macosx 0 aqua 0} foreach s [array names stubs $name,*,lastNum] { set block([lindex [split $s ,] 1]) 1 } ## unix ## if {$block(unix) && !$block(x11)} { set temp {} set plat unix set lastNum $stubs($name,$plat,lastNum) for {set i 0} {$i <= $lastNum} {incr i} { if {[info exists stubs($name,$plat,$i)]} { append temp [$slotProc $name $stubs($name,$plat,$i) $i] } else { eval {append temp} $skipString } } append text [addPlatformGuard $plat $temp {} true] } ## win ## if {$block(win)} { set temp {} set plat win set lastNum $stubs($name,$plat,lastNum) for {set i 0} {$i <= $lastNum} {incr i} { if {[info exists stubs($name,$plat,$i)]} { append temp [$slotProc $name $stubs($name,$plat,$i) $i] } else { eval {append temp} $skipString } } append text [addPlatformGuard $plat $temp {} true] } ## macosx ## if {($block(unix) || $block(macosx)) && !$block(aqua) && !$block(x11)} { set temp {} set lastNum -1 foreach plat {unix macosx} { if {$block($plat)} { set lastNum [expr {$lastNum > $stubs($name,$plat,lastNum) ? $lastNum : $stubs($name,$plat,lastNum)}] } } for {set i 0} {$i <= $lastNum} {incr i} { set emit 0 foreach plat {unix macosx} { if {[info exists stubs($name,$plat,$i)]} { append temp [$slotProc $name $stubs($name,$plat,$i) $i] set emit 1 break } } if {!$emit} { eval {append temp} $skipString } } append text [addPlatformGuard macosx $temp] } ## aqua ## if {$block(aqua)} { set temp {} set lastNum -1 foreach plat {unix macosx aqua} { if {$block($plat)} { set lastNum [expr {$lastNum > $stubs($name,$plat,lastNum) ? $lastNum : $stubs($name,$plat,lastNum)}] } } for {set i 0} {$i <= $lastNum} {incr i} { set emit 0 foreach plat {unix macosx aqua} { if {[info exists stubs($name,$plat,$i)]} { append temp [$slotProc $name $stubs($name,$plat,$i) $i] set emit 1 break } } if {!$emit} { eval {append temp} $skipString } } append text [addPlatformGuard aqua $temp] } ## x11 ## if {$block(x11)} { set temp {} set lastNum -1 foreach plat {unix macosx x11} { if {$block($plat)} { set lastNum [expr {$lastNum > $stubs($name,$plat,lastNum) ? $lastNum : $stubs($name,$plat,lastNum)}] } } for {set i 0} {$i <= $lastNum} {incr i} { set emit 0 foreach plat {unix macosx x11} { if {[info exists stubs($name,$plat,$i)]} { if {$plat ne "macosx"} { append temp [$slotProc $name \ $stubs($name,$plat,$i) $i] } else { eval {set etxt} $skipString append temp [addPlatformGuard $plat [$slotProc \ $name $stubs($name,$plat,$i) $i] $etxt true] } set emit 1 break } } if {!$emit} { eval {append temp} $skipString } } append text [addPlatformGuard x11 $temp {} true] } } } # genStubs::emitDeclarations -- # # This function emits the function declarations for this interface. # # Arguments: # name The interface name. # textVar The variable to use for output. # # Results: # None. proc genStubs::emitDeclarations {name textVar} { upvar $textVar text append text "\n/*\n * Exported function declarations:\n */\n\n" forAllStubs $name makeDecl 0 text return } # genStubs::emitMacros -- # # This function emits the inline macros for an interface. # # Arguments: # name The name of the interface being emitted. # textVar The variable to use for output. # # Results: # None. proc genStubs::emitMacros {name textVar} { variable libraryName upvar $textVar text set upName [string toupper $libraryName] append text "\n#if defined(USE_${upName}_STUBS) &&\ !defined(USE_${upName}_STUB_PROCS)\n" append text "\n/*\n * Inline function declarations:\n */\n\n" forAllStubs $name makeMacro 0 text append text "\n#endif /* defined(USE_${upName}_STUBS) &&\ !defined(USE_${upName}_STUB_PROCS) */\n" return } # genStubs::emitHeader -- # # This function emits the body of the Decls.h file for # the specified interface. # # Arguments: # name The name of the interface being emitted. # # Results: # None. proc genStubs::emitHeader {name} { variable outDir variable hooks variable epoch variable revision set capName [string toupper [string index $name 0]] append capName [string range $name 1 end] if {$epoch != ""} { set CAPName [string toupper $name] append text "\n" append text "#define ${CAPName}_STUBS_EPOCH $epoch\n" append text "#define ${CAPName}_STUBS_REVISION $revision\n" } emitDeclarations $name text if {[info exists hooks($name)]} { append text "\ntypedef struct ${capName}StubHooks {\n" foreach hook $hooks($name) { set capHook [string toupper [string index $hook 0]] append capHook [string range $hook 1 end] append text " struct ${capHook}Stubs *${hook}Stubs;\n" } append text "} ${capName}StubHooks;\n" } append text "\ntypedef struct ${capName}Stubs {\n" append text " int magic;\n" if {$epoch != ""} { append text " int epoch;\n" append text " int revision;\n" } append text " struct ${capName}StubHooks *hooks;\n\n" emitSlots $name text append text "} ${capName}Stubs;\n\n" append text "#ifdef __cplusplus\nextern \"C\" {\n#endif\n" append text "extern ${capName}Stubs *${name}StubsPtr;\n" append text "#ifdef __cplusplus\n}\n#endif\n" emitMacros $name text rewriteFile [file join $outDir ${name}Decls.h] $text return } # genStubs::emitInit -- # # Generate the table initializers for an interface. # # Arguments: # name The name of the interface to initialize. # textVar The variable to use for output. # # Results: # Returns the formatted output. proc genStubs::emitInit {name textVar} { variable hooks variable epoch upvar $textVar text set capName [string toupper [string index $name 0]] append capName [string range $name 1 end] if {[info exists hooks($name)]} { append text "\nstatic ${capName}StubHooks ${name}StubHooks = \{\n" set sep " " foreach sub $hooks($name) { append text $sep "&${sub}Stubs" set sep ",\n " } append text "\n\};\n" } append text "\n${capName}Stubs ${name}Stubs = \{\n" append text " TCL_STUB_MAGIC,\n" if {$epoch != ""} { set CAPName [string toupper $name] append text " ${CAPName}_STUBS_EPOCH,\n" append text " ${CAPName}_STUBS_REVISION,\n" } if {[info exists hooks($name)]} { append text " &${name}StubHooks,\n" } else { append text " NULL,\n" } forAllStubs $name makeInit 1 text {" NULL, /* $i */\n"} append text "\};\n" return } # genStubs::emitInits -- # # This function emits the body of the StubInit.c file for # the specified interface. # # Arguments: # name The name of the interface being emitted. # # Results: # None. proc genStubs::emitInits {} { variable hooks variable outDir variable libraryName variable interfaces # Assuming that dependencies only go one level deep, we need to emit # all of the leaves first to avoid needing forward declarations. set leaves {} set roots {} foreach name [lsort [array names interfaces]] { if {[info exists hooks($name)]} { lappend roots $name } else { lappend leaves $name } } foreach name $leaves { emitInit $name text } foreach name $roots { emitInit $name text } rewriteFile [file join $outDir ${libraryName}StubInit.c] $text } # genStubs::init -- # # This is the main entry point. # # Arguments: # None. # # Results: # None. proc genStubs::init {} { global argv argv0 variable outDir variable interfaces if {[llength $argv] < 2} { puts stderr "usage: $argv0 outDir declFile ?declFile...?" exit 1 } set outDir [lindex $argv 0] foreach file [lrange $argv 1 end] { source $file } foreach name [lsort [array names interfaces]] { puts "Emitting $name" emitHeader $name } emitInits } # lassign -- # # This function emulates the TclX lassign command. # # Arguments: # valueList A list containing the values to be assigned. # args The list of variables to be assigned. # # Results: # Returns any values that were not assigned to variables. if {[string length [namespace which lassign]] == 0} { proc lassign {valueList args} { if {[llength $args] == 0} { error "wrong # args: should be \"lassign list varName ?varName ...?\"" } uplevel [list foreach $args $valueList {break}] return [lrange $valueList [llength $args] end] } } genStubs::init tcl8.4.20/tools/configure.in0000644003604700454610000000240711737050674014373 0ustar dgp771divdnl This file is an input file used by the GNU "autoconf" program to dnl generate the file "configure", which is run to configure the dnl Makefile in this directory. AC_INIT(man2tcl.c) # Recover information that Tcl computed with its configure script. #-------------------------------------------------------------------- # See if there was a command-line option for where Tcl is; if # not, assume that its top-level directory is a sibling of ours. #-------------------------------------------------------------------- DEF_VER=8.4 AC_ARG_WITH(tcl, [ --with-tcl=DIR use Tcl $DEF_VER binaries from DIR], TCL_BIN_DIR=$withval, TCL_BIN_DIR=`cd ../../tcl$DEF_VER$TCL_PATCH_LEVEL/unix; pwd`) if test ! -d $TCL_BIN_DIR; then AC_MSG_ERROR(Tcl directory $TCL_BIN_DIR doesn't exist) fi if test ! -f $TCL_BIN_DIR/tclConfig.sh; then AC_MSG_ERROR(There's no tclConfig.sh in $TCL_BIN_DIR; perhaps you didn't specify the Tcl *build* directory (not the toplevel Tcl directory) or you forgot to configure Tcl?) fi . $TCL_BIN_DIR/tclConfig.sh TCL_WIN_VERSION=$TCL_MAJOR_VERSION$TCL_MINOR_VERSION AC_SUBST(TCL_WIN_VERSION) CC=$TCL_CC AC_SUBST(CC) AC_SUBST(TCL_VERSION) AC_SUBST(TCL_PATCH_LEVEL) AC_SUBST(TCL_SRC_DIR) AC_SUBST(TCL_BIN_DIR) AC_OUTPUT(Makefile tcl.hpj) tcl8.4.20/tools/eolFix.tcl0000644003604700454610000000330211737050675014010 0ustar dgp771div## Super aggressive EOL-fixer! ## ## Will even understand screwed up ones like CRCRLF. ## (found in bad CVS repositories, caused by spacey developers ## abusing CVS) ## ## davygrvy@pobox.com 3:41 PM 10/12/2001 ## package provide EOL-fix 1.1 namespace eval ::EOL { variable outMode crlf } proc EOL::fix {filename {newfilename ""}} { variable outMode if {![file exists $filename]} { return } puts "EOL Fixing: $filename" file rename ${filename} ${filename}.o set fhnd [open ${filename}.o r] if {$newfilename != ""} { set newfhnd [open ${newfilename} w] } else { set newfhnd [open ${filename} w] } fconfigure $newfhnd -translation [list auto $outMode] seek $fhnd 0 end set theEnd [tell $fhnd] seek $fhnd 0 start fconfigure $fhnd -translation binary -buffersize $theEnd set rawFile [read $fhnd $theEnd] close $fhnd regsub -all {(\r)|(\r){1,2}(\n)} $rawFile "\n" rawFile set lineList [split $rawFile \n] foreach line $lineList { puts $newfhnd $line } close $newfhnd file delete ${filename}.o } proc EOL::fixall {args} { if {[llength $args] == 0} { puts stderr "no files to fix" exit 1 } else { set cmd [lreplace $args -1 -1 glob -nocomplain] } foreach f [eval $cmd] { if {[file isfile $f]} {fix $f} } } if {$tcl_interactive == 0 && $argc > 0} { if {[string index [lindex $argv 0] 0] == "-"} { switch -- [lindex $argv 0] { -cr { set ::EOL::outMode cr } -crlf { set ::EOL::outMode crlf } -lf { set ::EOL::outMode lf } default { puts stderr "improper mode switch" ; exit 1 } } set argv [lrange $argv 1 end] } eval EOL::fixall $argv } else { return } tcl8.4.20/tools/man2html2.tcl0000644003604700454610000004216211737050675014375 0ustar dgp771div# man2html2.tcl -- # # This file defines procedures that are used during the second pass of the # man page to html conversion process. It is sourced by man2html.tcl. # # Copyright (c) 1996 by Sun Microsystems, Inc. # Global variables used by these scripts: # # NAME_file - array indexed by NAME and containing file names used # for hyperlinks. # # textState - state variable defining action of 'text' proc. # # nestStk - stack oriented list containing currently active # HTML tags (UL, OL, DL). Local to 'nest' proc. # # inDT - set by 'TPmacro', cleared by 'newline'. Used to insert # the
tag while in a dictionary list
. # # curFont - Name of special font that is currently in # use. Null means the default paragraph font # is being used. # # file - Where to output the generated HTML. # # fontStart - Array to map font names to starting sequences. # # fontEnd - Array to map font names to ending sequences. # # noFillCount - Non-zero means don't fill the next $noFillCount # lines: force a line break at each newline. Zero # means filling is enabled, so don't output line # breaks for each newline. # # footer - info inserted at bottom of each page. Normally read # from the xref.tcl file # initGlobals -- # # This procedure is invoked to set the initial values of all of the # global variables, before processing a man page. # # Arguments: # None. proc initGlobals {} { global file noFillCount textState global fontStart fontEnd curFont inPRE charCnt nest init set inPRE 0 set textState 0 set curFont "" set fontStart(Code) "" set fontStart(Emphasis) "" set fontEnd(Code) "" set fontEnd(Emphasis) "" set noFillCount 0 set charCnt 0 setTabs 0.5i } # beginFont -- # # Arranges for future text to use a special font, rather than # the default paragraph font. # # Arguments: # font - Name of new font to use. proc beginFont font { global curFont file fontStart if {$curFont == $font} { return } endFont puts -nonewline $file $fontStart($font) set curFont $font } # endFont -- # # Reverts to the default font for the paragraph type. # # Arguments: # None. proc endFont {} { global curFont file fontEnd if {$curFont != ""} { puts -nonewline $file $fontEnd($curFont) set curFont "" } } # text -- # # This procedure adds text to the current paragraph. If this is # the first text in the paragraph then header information for the # paragraph is output before the text. # # Arguments: # string - Text to output in the paragraph. proc text string { global file textState inDT charCnt set pos [string first "\t" $string] if {$pos >= 0} { text [string range $string 0 [expr $pos-1]] tab text [string range $string [expr $pos+1] end] return } incr charCnt [string length $string] regsub -all {&} $string {\&} string regsub -all {<} $string {\<} string regsub -all {>} $string {\>} string regsub -all {"} $string {\"} string switch $textState { REF { if {$inDT == {}} { set string [insertRef $string] } } SEE { global NAME_file foreach i [split $string] { if ![regexp -nocase {^[a-z_]+} [string trim $i] i ] { # puts "Warning: $i in SEE ALSO not found" continue } if ![catch {set ref $NAME_file($i)} ] { regsub $i $string "$i" string } } } } puts -nonewline $file "$string" } # insertRef -- # # # Arguments: # string - Text to output in the paragraph. proc insertRef string { global NAME_file self set path {} if ![catch {set ref $NAME_file([string trim $string])} ] { if {"$ref.html" != $self} { set string "$string" # puts "insertRef: $self $ref.html ---$string--" } } return $string } # macro -- # # This procedure is invoked to process macro invocations that start # with "." (instead of '). # # Arguments: # name - The name of the macro (without the "."). # args - Any additional arguments to the macro. proc macro {name args} { switch $name { AP { if {[llength $args] != 3} { puts stderr "Bad .AP macro: .$name [join $args " "]" } setTabs {1.25i 2.5i 3.75i} TPmacro {} font B text "[lindex $args 0] " font I text "[lindex $args 1]" font R text " ([lindex $args 2])" newline } AS {} ;# next page and previous page br { lineBreak } BS {} BE {} CE { global file noFillCount inPRE puts $file set inPRE 0 } CS { ;# code section global file noFillCount inPRE puts -nonewline $file
	    set inPRE 1
	}
	DE {
	    global file noFillCount inPRE
	    puts $file 
set inPRE 0 set noFillCount 0 } DS { global file noFillCount inPRE puts -nonewline $file
	    set noFillCount 10000000
	    set inPRE 1
	}
	fi {
	    global noFillCount
	    set noFillCount 0
	}
	IP {
	    IPmacro $args
	}
	LP {
	    nest decr
	    nest incr
	    newPara
	}
	ne {
	}
	nf {
	    global noFillCount
	    set noFillCount 1000000
	}
	OP {
	    global inDT file inPRE 
	    if {[llength $args] != 3} {
		puts stderr "Bad .OP macro: .$name [join $args " "]"
	    }
	    nest para DL DT
	    set inPRE 1
	    puts -nonewline $file 
				
	    setTabs 4c
	    text "Command-Line Name:"
	    tab
	    font B
	    set x [lindex $args 0]
	    regsub -all {\\-} $x - x
	    text $x
	    newline
	    font R
	    text "Database Name:"
	    tab
	    font B
	    text [lindex $args 1]
	    newline
	    font R
	    text "Database Class:"
	    tab
	    font B
	    text [lindex $args 2]
	    font R
	    puts -nonewline $file 
set inDT "\n
" ;# next newline writes inDT set inPRE 0 newline } PP { nest decr nest incr newPara } RE { nest decr } RS { nest incr } SE { global noFillCount textState inPRE file font R puts -nonewline $file
set inPRE 0 set noFillCount 0 nest reset newPara text "See the " font B set temp $textState set textState REF text options set textState $temp font R text " manual entry for detailed descriptions of the above options." } SH { SHmacro $args } SO { global noFillCount inPRE file SHmacro "STANDARD OPTIONS" setTabs {4c 8c 12c} set noFillCount 1000000 puts -nonewline $file
	    set inPRE 1
	    font B
	}
	so {
	    if {$args != "man.macros"} {
		puts stderr "Unknown macro: .$name [join $args " "]"
	    }
	}
	sp {					;# needs work
	    if {$args == ""} {
		set count 1
	    } else {
		set count [lindex $args 0]
	    }
	    while {$count > 0} {
		lineBreak
		incr count -1
	    }
	}
	ta {
	    setTabs $args
	}
	TH {
	    THmacro $args
	}
	TP {
	    TPmacro $args
	}
	UL {					;# underline
	    global file
	    puts -nonewline $file ""
	    text [lindex $args 0]
	    puts -nonewline $file ""
	    if {[llength $args] == 2} {
		text [lindex $args 1]
	    }
	}
	VE {
#	    global file
#	    puts -nonewline $file ""
	}
	VS {
#	    global file
#	    if {[llength $args] > 0} {
#		puts -nonewline $file "
" # } # puts -nonewline $file "" } default { puts stderr "Unknown macro: .$name [join $args " "]" } } # global nestStk; puts "$name [format "%-20s" $args] $nestStk" # flush stdout; flush stderr } # font -- # # This procedure is invoked to handle font changes in the text # being output. # # Arguments: # type - Type of font: R, I, B, or S. proc font type { global textState switch $type { P - R { endFont if {$textState == "REF"} { set textState INSERT } } B { beginFont Code if {$textState == "INSERT"} { set textState REF } } I { beginFont Emphasis } S { } default { puts stderr "Unknown font: $type" } } } # formattedText -- # # Insert a text string that may also have \fB-style font changes # and a few other backslash sequences in it. # # Arguments: # text - Text to insert. proc formattedText text { # puts "formattedText: $text" while {$text != ""} { set index [string first \\ $text] if {$index < 0} { text $text return } text [string range $text 0 [expr $index-1]] set c [string index $text [expr $index+1]] switch -- $c { f { font [string index $text [expr $index+2]] set text [string range $text [expr $index+3] end] } e { text \\ set text [string range $text [expr $index+2] end] } - { dash set text [string range $text [expr $index+2] end] } | { set text [string range $text [expr $index+2] end] } default { puts stderr "Unknown sequence: \\$c" set text [string range $text [expr $index+2] end] } } } } # dash -- # # This procedure is invoked to handle dash characters ("\-" in # troff). It outputs a special dash character. # # Arguments: # None. proc dash {} { global textState charCnt if {$textState == "NAME"} { set textState 0 } incr charCnt text "-" } # tab -- # # This procedure is invoked to handle tabs in the troff input. # Right now it does nothing. # # Arguments: # None. proc tab {} { global inPRE charCnt tabString # ? charCnt if {$inPRE == 1} { set pos [expr $charCnt % [string length $tabString] ] set spaces [string first "1" [string range $tabString $pos end] ] text [format "%*s" [incr spaces] " "] } else { # puts "tab: found tab outside of
 block"
    }
}


# setTabs --
#
# This procedure handles the ".ta" macro, which sets tab stops.
#
# Arguments:
# tabList -	List of tab stops, each consisting of a number
#			followed by "i" (inch) or "c" (cm).

proc setTabs {tabList} {
    global file breakPending tabString

#	puts "setTabs: --$tabList--"
    set last 0
    set tabString {}
    set charsPerInch 14.
    set numTabs [llength $tabList]
    foreach arg $tabList {
	if {[scan $arg "%f%s" distance units] != 2} {
	    puts stderr "bad distance \"$arg\""
	    return 0
    	}
	switch -- $units {
	    c	{
		set distance [expr $distance * $charsPerInch / 2.54 ]
	    }
	    i	{
		set distance [expr $distance * $charsPerInch]
	    }
	    default {
		puts stderr "bad units in distance \"$arg\""
		continue
	    }
    	}
#		? distance
    	lappend tabString [format "%*s1" [expr round($distance-$last-1)] " "]
    	set last $distance
    }
    set tabString [join $tabString {}]
#	puts "setTabs: --$tabString--"
}



# lineBreak --
#
# Generates a line break in the HTML output.
#
# Arguments:
# None.

proc lineBreak {} {
    global file inPRE
    puts $file "
" } # newline -- # # This procedure is invoked to handle newlines in the troff input. # It outputs either a space character or a newline character, depending # on fill mode. # # Arguments: # None. proc newline {} { global noFillCount file inDT inPRE charCnt if {$inDT != {} } { puts $file "\n$inDT" set inDT {} } elseif {$noFillCount == 0 || $inPRE == 1} { puts $file {} } else { lineBreak incr noFillCount -1 } set charCnt 0 } # char -- # # This procedure is called to handle a special character. # # Arguments: # name - Special character named in troff \x or \(xx construct. proc char name { global file charCnt incr charCnt # puts "char: $name" switch -exact $name { \\0 { ;# \0 puts -nonewline $file " " } \\\\ { ;# \ puts -nonewline $file "\\" } \\(+- { ;# +/- puts -nonewline $file "±" } \\% {} ;# \% \\| { ;# \| } default { puts stderr "Unknown character: $name" } } } # macro2 -- # # This procedure handles macros that are invoked with a leading "'" # character instead of space. Right now it just generates an # error diagnostic. # # Arguments: # name - The name of the macro (without the "."). # args - Any additional arguments to the macro. proc macro2 {name args} { puts stderr "Unknown macro: '$name [join $args " "]" } # SHmacro -- # # Subsection head; handles the .SH macro. # # Arguments: # name - Section name. proc SHmacro argList { global file noFillCount textState charCnt set args [join $argList " "] if {[llength $argList] < 1} { puts stderr "Bad .SH macro: .$name $args" } set noFillCount 0 nest reset puts -nonewline $file "

" text $args puts $file "

" # ? args textState # control what the text proc does with text switch $args { NAME {set textState NAME} DESCRIPTION {set textState INSERT} INTRODUCTION {set textState INSERT} "WIDGET-SPECIFIC OPTIONS" {set textState INSERT} "SEE ALSO" {set textState SEE} KEYWORDS {set textState 0} } set charCnt 0 } # IPmacro -- # # This procedure is invoked to handle ".IP" macros, which may take any # of the following forms: # # .IP [1] Translate to a "1Step" paragraph. # .IP [x] (x > 1) Translate to a "Step" paragraph. # .IP Translate to a "Bullet" paragraph. # .IP text count Translate to a FirstBody paragraph with special # indent and tab stop based on "count", and tab after # "text". # # Arguments: # argList - List of arguments to the .IP macro. # # HTML limitations: 'count' in '.IP text count' is ignored. proc IPmacro argList { global file setTabs 0.5i set length [llength $argList] if {$length == 0} { nest para UL LI return } if {$length == 1} { nest para OL LI return } if {$length > 1} { nest para DL DT formattedText [lindex $argList 0] puts $file "\n
" return } puts stderr "Bad .IP macro: .IP [join $argList " "]" } # TPmacro -- # # This procedure is invoked to handle ".TP" macros, which may take any # of the following forms: # # .TP x Translate to an indented paragraph with the # specified indent (in 100 twip units). # .TP Translate to an indented paragraph with # default indent. # # Arguments: # argList - List of arguments to the .IP macro. # # HTML limitations: 'x' in '.TP x' is ignored. proc TPmacro {argList} { global inDT nest para DL DT set inDT "\n
" ;# next newline writes inDT setTabs 0.5i } # THmacro -- # # This procedure handles the .TH macro. It generates the non-scrolling # header section for a given man page, and enters information into the # table of contents. The .TH macro has the following form: # # .TH name section date footer header # # Arguments: # argList - List of arguments to the .TH macro. proc THmacro {argList} { global file if {[llength $argList] != 5} { set args [join $argList " "] puts stderr "Bad .TH macro: .$name $args" } set name [lindex $argList 0] ;# Tcl_UpVar set page [lindex $argList 1] ;# 3 set vers [lindex $argList 2] ;# 7.4 set lib [lindex $argList 3] ;# Tcl set pname [lindex $argList 4] ;# {Tcl Library Procedures} puts -nonewline $file "" text "$lib - $name ($page)" puts $file "\n" puts -nonewline $file "

" text $pname puts $file "

\n" } # newPara -- # # This procedure sets the left and hanging indents for a line. # Indents are specified in units of inches or centimeters, and are # relative to the current nesting level and left margin. # # Arguments: # None proc newPara {} { global file nestStk if {[lindex $nestStk end] != "NEW" } { nest decr } puts -nonewline $file "

" } # nest -- # # This procedure takes care of inserting the tags associated with the # IP, TP, RS, RE, LP and PP macros. Only 'nest para' takes arguments. # # Arguments: # op - operation: para, incr, decr, reset, init # listStart - begin list tag: OL, UL, DL. # listItem - item tag: LI, LI, DT. proc nest {op {listStart "NEW"} {listItem {} } } { global file nestStk inDT charCnt # puts "nest: $op $listStart $listItem" switch $op { para { set top [lindex $nestStk end] if {$top == "NEW" } { set nestStk [lreplace $nestStk end end $listStart] puts $file "<$listStart>" } elseif {$top != $listStart} { puts stderr "nest para: bad stack" exit 1 } puts $file "\n<$listItem>" set charCnt 0 } incr { lappend nestStk NEW } decr { if {[llength $nestStk] == 0} { puts stderr "nest error: nest length is zero" set nestStk NEW } set tag [lindex $nestStk end] if {$tag != "NEW"} { puts $file "" } set nestStk [lreplace $nestStk end end] } reset { while {[llength $nestStk] > 0} { nest decr } set nestStk NEW } init { set nestStk NEW set inDT {} } } set charCnt 0 } # do -- # # This is the toplevel procedure that translates a man page # to Frame. It runs the man2tcl program to turn the man page # into a script, then it evals that script. # # Arguments: # fileName - Name of the file to translate. proc do fileName { global file self html_dir package footer set self "[file tail $fileName].html" set file [open "$html_dir/$package/$self" w] puts " Pass 2 -- $fileName" flush stdout initGlobals if [catch {eval [exec man2tcl [glob $fileName]]} msg] { global errorInfo puts stderr $msg puts "in" puts stderr $errorInfo exit 1 } nest reset puts $file $footer puts $file "" close $file } tcl8.4.20/tools/Makefile.in0000644003604700454610000000271511737050674014131 0ustar dgp771div# This makefile is used to convert Tcl manual pages into various # alternate formats: # # Windows help file: 1. Build the winhelp target on Unix # 2. Build the helpfile target on Windows # # HTML: 1. Build the html target on Unix TCL = tcl@TCL_VERSION@ TK = tk@TCL_VERSION@ VER = @TCL_WIN_VERSION@ TCL_BIN_DIR = @TCL_BIN_DIR@ TCL_SOURCE = @TCL_SRC_DIR@ TK_SOURCE = $(TCL_SOURCE)/../$(TK) PRO_SOURCE = $(TCL_SOURCE)/../pro ITCL_SOURCE = $(TCL_SOURCE)/../itcl3.1.0 TCL_DOCS = $(TCL_SOURCE)/doc/*.[13n] TK_DOCS = $(TK_SOURCE)/doc/*.[13n] PRO_DOCS = \ $(PRO_SOURCE)/doc/man/procheck.1 \ $(PRO_SOURCE)/doc/man/prodebug.1 \ $(PRO_SOURCE)/doc/man/prodebug.n \ $(PRO_SOURCE)/doc/man/prolicense.1 ITCL_DOCS = \ $(ITCL_SOURCE)/itcl/doc/*.[13n] \ $(ITCL_SOURCE)/itk/doc/*.[13n] # $(ITCL_SOURCE)/iwidgets3.0.0/doc/*.[13n] COREDOCS = $(TCL_DOCS) $(TK_DOCS) #PRODOCS = $(COREDOCS) $(PRO_DOCS) $(ITCL_DOCS) PRODOCS = $(COREDOCS) $(PRO_DOCS) TCLSH = $(TCL_BIN_DIR)/tclsh CC = @CC@ # # Targets # all: core pro: $(MAKE) DOCS="$(PRODOCS)" VER="" rtf core: $(MAKE) DOCS="$(COREDOCS)" rtf rtf: $(TCL_SOURCE)/tools/man2help.tcl man2tcl $(DOCS) LD_LIBRARY_PATH=$(TCL_BIN_DIR) \ TCL_LIBRARY=$(TCL_SOURCE)/library \ $(TCLSH) $(TCL_SOURCE)/tools/man2help.tcl tcl "$(VER)" $(DOCS) winhelp: tcl.rtf man2tcl: $(TCL_SOURCE)/tools/man2tcl.c $(CC) $(CFLAGS) -o man2tcl $(TCL_SOURCE)/tools/man2tcl.c clean: -rm -f man2tcl *.o *.cnt *.rtf helpfile: hcw /c /e tcl.hpj tcl8.4.20/tools/configure0000755003604700454610000006676711737050674014014 0ustar dgp771div#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated automatically using autoconf version 2.13 # Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. # Defaults: ac_help= ac_default_prefix=/usr/local # Any additions from configure.in: ac_help="$ac_help --with-tcl=DIR use Tcl $DEF_VER binaries from DIR" # Initialize some variables set by options. # The variables have the same names as the options, with # dashes changed to underlines. build=NONE cache_file=./config.cache exec_prefix=NONE host=NONE no_create= nonopt=NONE no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= target=NONE verbose= x_includes=NONE x_libraries=NONE bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datadir='${prefix}/share' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' libdir='${exec_prefix}/lib' includedir='${prefix}/include' oldincludedir='/usr/include' infodir='${prefix}/info' mandir='${prefix}/man' # Initialize some other variables. subdirs= MFLAGS= MAKEFLAGS= SHELL=${CONFIG_SHELL-/bin/sh} # Maximum number of lines to put in a shell here document. ac_max_here_lines=12 ac_prev= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval "$ac_prev=\$ac_option" ac_prev= continue fi case "$ac_option" in -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; *) ac_optarg= ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case "$ac_option" in -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir="$ac_optarg" ;; -build | --build | --buil | --bui | --bu) ac_prev=build ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build="$ac_optarg" ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file="$ac_optarg" ;; -datadir | --datadir | --datadi | --datad | --data | --dat | --da) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ | --da=*) datadir="$ac_optarg" ;; -disable-* | --disable-*) ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } fi ac_feature=`echo $ac_feature| sed 's/-/_/g'` eval "enable_${ac_feature}=no" ;; -enable-* | --enable-*) ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } fi ac_feature=`echo $ac_feature| sed 's/-/_/g'` case "$ac_option" in *=*) ;; *) ac_optarg=yes ;; esac eval "enable_${ac_feature}='$ac_optarg'" ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix="$ac_optarg" ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he) # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat << EOF Usage: configure [options] [host] Options: [defaults in brackets after descriptions] Configuration: --cache-file=FILE cache test results in FILE --help print this message --no-create do not create output files --quiet, --silent do not print \`checking...' messages --version print the version of autoconf that created configure Directory and file names: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [same as prefix] --bindir=DIR user executables in DIR [EPREFIX/bin] --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] --libexecdir=DIR program executables in DIR [EPREFIX/libexec] --datadir=DIR read-only architecture-independent data in DIR [PREFIX/share] --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data in DIR [PREFIX/com] --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] --libdir=DIR object code libraries in DIR [EPREFIX/lib] --includedir=DIR C header files in DIR [PREFIX/include] --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] --infodir=DIR info documentation in DIR [PREFIX/info] --mandir=DIR man documentation in DIR [PREFIX/man] --srcdir=DIR find the sources in DIR [configure dir or ..] --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names EOF cat << EOF Host type: --build=BUILD configure for building on BUILD [BUILD=HOST] --host=HOST configure for HOST [guessed] --target=TARGET configure for TARGET [TARGET=HOST] Features and packages: --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --x-includes=DIR X include files are in DIR --x-libraries=DIR X library files are in DIR EOF if test -n "$ac_help"; then echo "--enable and --with options recognized:$ac_help" fi exit 0 ;; -host | --host | --hos | --ho) ac_prev=host ;; -host=* | --host=* | --hos=* | --ho=*) host="$ac_optarg" ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir="$ac_optarg" ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir="$ac_optarg" ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir="$ac_optarg" ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir="$ac_optarg" ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst \ | --locals | --local | --loca | --loc | --lo) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* \ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) localstatedir="$ac_optarg" ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir="$ac_optarg" ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir="$ac_optarg" ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix="$ac_optarg" ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix="$ac_optarg" ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix="$ac_optarg" ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name="$ac_optarg" ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir="$ac_optarg" ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir="$ac_optarg" ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site="$ac_optarg" ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir="$ac_optarg" ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir="$ac_optarg" ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target="$ac_optarg" ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers) echo "configure generated by autoconf version 2.13" exit 0 ;; -with-* | --with-*) ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } fi ac_package=`echo $ac_package| sed 's/-/_/g'` case "$ac_option" in *=*) ;; *) ac_optarg=yes ;; esac eval "with_${ac_package}='$ac_optarg'" ;; -without-* | --without-*) ac_package=`echo $ac_option|sed -e 's/-*without-//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } fi ac_package=`echo $ac_package| sed 's/-/_/g'` eval "with_${ac_package}=no" ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes="$ac_optarg" ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries="$ac_optarg" ;; -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } ;; *) if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then echo "configure: warning: $ac_option: invalid host type" 1>&2 fi if test "x$nonopt" != xNONE; then { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } fi nonopt="$ac_option" ;; esac done if test -n "$ac_prev"; then { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } fi trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 # File descriptor usage: # 0 standard input # 1 file creation # 2 errors and warnings # 3 some systems may open it to /dev/tty # 4 used on the Kubota Titan # 6 checking for... messages and results # 5 compiler messages saved in config.log if test "$silent" = yes; then exec 6>/dev/null else exec 6>&1 fi exec 5>./config.log echo "\ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. " 1>&5 # Strip out --no-create and --no-recursion so they do not pile up. # Also quote any args containing shell metacharacters. ac_configure_args= for ac_arg do case "$ac_arg" in -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c) ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) ac_configure_args="$ac_configure_args '$ac_arg'" ;; *) ac_configure_args="$ac_configure_args $ac_arg" ;; esac done # NLS nuisances. # Only set these to C if already set. These must not be set unconditionally # because not all systems understand e.g. LANG=C (notably SCO). # Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! # Non-C LC_CTYPE values break the ctype check. if test "${LANG+set}" = set; then LANG=C; export LANG; fi if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -rf conftest* confdefs.h # AIX cpp loses on an empty file, so make sure it contains at least a newline. echo > confdefs.h # A filename unique to this package, relative to the directory that # configure is in, which we can look for to find out if srcdir is correct. ac_unique_file=man2tcl.c # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then its parent. ac_prog=$0 ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. srcdir=$ac_confdir if test ! -r $srcdir/$ac_unique_file; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r $srcdir/$ac_unique_file; then if test "$ac_srcdir_defaulted" = yes; then { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } else { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } fi fi srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` # Prefer explicitly selected file to automatically selected ones. if test -z "$CONFIG_SITE"; then if test "x$prefix" != xNONE; then CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" else CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi fi for ac_site_file in $CONFIG_SITE; do if test -r "$ac_site_file"; then echo "loading site script $ac_site_file" . "$ac_site_file" fi done if test -r "$cache_file"; then echo "loading cache $cache_file" . $cache_file else echo "creating cache $cache_file" > $cache_file fi ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. ac_cpp='$CPP $CPPFLAGS' ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' cross_compiling=$ac_cv_prog_cc_cross ac_exeext= ac_objext=o if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then ac_n= ac_c=' ' ac_t=' ' else ac_n=-n ac_c= ac_t= fi else ac_n= ac_c='\c' ac_t= fi # Recover information that Tcl computed with its configure script. #-------------------------------------------------------------------- # See if there was a command-line option for where Tcl is; if # not, assume that its top-level directory is a sibling of ours. #-------------------------------------------------------------------- DEF_VER=8.4 # Check whether --with-tcl or --without-tcl was given. if test "${with_tcl+set}" = set; then withval="$with_tcl" TCL_BIN_DIR=$withval else TCL_BIN_DIR=`cd ../../tcl$DEF_VER$TCL_PATCH_LEVEL/unix; pwd` fi if test ! -d $TCL_BIN_DIR; then { echo "configure: error: Tcl directory $TCL_BIN_DIR doesn't exist" 1>&2; exit 1; } fi if test ! -f $TCL_BIN_DIR/tclConfig.sh; then { echo "configure: error: There's no tclConfig.sh in $TCL_BIN_DIR; perhaps you didn't specify the Tcl *build* directory (not the toplevel Tcl directory) or you forgot to configure Tcl?" 1>&2; exit 1; } fi . $TCL_BIN_DIR/tclConfig.sh TCL_WIN_VERSION=$TCL_MAJOR_VERSION$TCL_MINOR_VERSION CC=$TCL_CC trap '' 1 2 15 cat > confcache <<\EOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs. It is not useful on other systems. # If it contains results you don't want to keep, you may remove or edit it. # # By default, configure uses ./config.cache as the cache file, # creating it if it does not exist already. You can give configure # the --cache-file=FILE option to use a different cache file; that is # what configure does when it calls configure scripts in # subdirectories, so they share the cache. # Giving --cache-file=/dev/null disables caching, for debugging configure. # config.status only pays attention to the cache file if you give it the # --recheck option to rerun configure. # EOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, don't put newlines in cache variables' values. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. (set) 2>&1 | case `(ac_space=' '; set | grep ac_space) 2>&1` in *ac_space=\ *) # `set' does not quote correctly, so add quotes (double-quote substitution # turns \\\\ into \\, and sed turns \\ into \). sed -n \ -e "s/'/'\\\\''/g" \ -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" ;; *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' ;; esac >> confcache if cmp -s $cache_file confcache; then : else if test -w $cache_file; then echo "updating cache $cache_file" cat confcache > $cache_file else echo "not updating unwritable cache $cache_file" fi fi rm -f confcache trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Any assignment to VPATH causes Sun make to only execute # the first set of double-colon rules, so remove it if not needed. # If there is a colon in the path, we need to keep it. if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' fi trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. cat > conftest.defs <<\EOF s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%-D\1=\2%g s%[ `~#$^&*(){}\\|;'"<>?]%\\&%g s%\[%\\&%g s%\]%\\&%g s%\$%$$%g EOF DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '` rm -f conftest.defs # Without the "./", some shells look in PATH for config.status. : ${CONFIG_STATUS=./config.status} echo creating $CONFIG_STATUS rm -f $CONFIG_STATUS cat > $CONFIG_STATUS </dev/null | sed 1q`: # # $0 $ac_configure_args # # Compiler output produced by configure, useful for debugging # configure, is in ./config.log if it exists. ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" for ac_option do case "\$ac_option" in -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; -version | --version | --versio | --versi | --vers | --ver | --ve | --v) echo "$CONFIG_STATUS generated by autoconf version 2.13" exit 0 ;; -help | --help | --hel | --he | --h) echo "\$ac_cs_usage"; exit 0 ;; *) echo "\$ac_cs_usage"; exit 1 ;; esac done ac_given_srcdir=$srcdir trap 'rm -fr `echo "Makefile tcl.hpj" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 EOF cat >> $CONFIG_STATUS < conftest.subs <<\\CEOF $ac_vpsub $extrasub s%@SHELL@%$SHELL%g s%@CFLAGS@%$CFLAGS%g s%@CPPFLAGS@%$CPPFLAGS%g s%@CXXFLAGS@%$CXXFLAGS%g s%@FFLAGS@%$FFLAGS%g s%@DEFS@%$DEFS%g s%@LDFLAGS@%$LDFLAGS%g s%@LIBS@%$LIBS%g s%@exec_prefix@%$exec_prefix%g s%@prefix@%$prefix%g s%@program_transform_name@%$program_transform_name%g s%@bindir@%$bindir%g s%@sbindir@%$sbindir%g s%@libexecdir@%$libexecdir%g s%@datadir@%$datadir%g s%@sysconfdir@%$sysconfdir%g s%@sharedstatedir@%$sharedstatedir%g s%@localstatedir@%$localstatedir%g s%@libdir@%$libdir%g s%@includedir@%$includedir%g s%@oldincludedir@%$oldincludedir%g s%@infodir@%$infodir%g s%@mandir@%$mandir%g s%@TCL_WIN_VERSION@%$TCL_WIN_VERSION%g s%@CC@%$CC%g s%@TCL_VERSION@%$TCL_VERSION%g s%@TCL_PATCH_LEVEL@%$TCL_PATCH_LEVEL%g s%@TCL_SRC_DIR@%$TCL_SRC_DIR%g s%@TCL_BIN_DIR@%$TCL_BIN_DIR%g CEOF EOF cat >> $CONFIG_STATUS <<\EOF # Split the substitutions into bite-sized pieces for seds with # small command number limits, like on Digital OSF/1 and HP-UX. ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. ac_file=1 # Number of current file. ac_beg=1 # First line for current file. ac_end=$ac_max_sed_cmds # Line after last line for current file. ac_more_lines=: ac_sed_cmds="" while $ac_more_lines; do if test $ac_beg -gt 1; then sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file else sed "${ac_end}q" conftest.subs > conftest.s$ac_file fi if test ! -s conftest.s$ac_file; then ac_more_lines=false rm -f conftest.s$ac_file else if test -z "$ac_sed_cmds"; then ac_sed_cmds="sed -f conftest.s$ac_file" else ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" fi ac_file=`expr $ac_file + 1` ac_beg=$ac_end ac_end=`expr $ac_end + $ac_max_sed_cmds` fi done if test -z "$ac_sed_cmds"; then ac_sed_cmds=cat fi EOF cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". case "$ac_file" in *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; *) ac_file_in="${ac_file}.in" ;; esac # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. # Remove last slash and all that follows it. Not all systems have dirname. ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then # The file is in a subdirectory. test ! -d "$ac_dir" && mkdir "$ac_dir" ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" # A "../" for each directory in $ac_dir_suffix. ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` else ac_dir_suffix= ac_dots= fi case "$ac_given_srcdir" in .) srcdir=. if test -z "$ac_dots"; then top_srcdir=. else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; *) # Relative path. srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" top_srcdir="$ac_dots$ac_given_srcdir" ;; esac echo creating "$ac_file" rm -f "$ac_file" configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." case "$ac_file" in *Makefile*) ac_comsub="1i\\ # $configure_input" ;; *) ac_comsub= ;; esac ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` sed -e "$ac_comsub s%@configure_input@%$configure_input%g s%@srcdir@%$srcdir%g s%@top_srcdir@%$top_srcdir%g " $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file fi; done rm -f conftest.s* EOF cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF exit 0 EOF chmod +x $CONFIG_STATUS rm -fr confdefs* $ac_clean_files test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 tcl8.4.20/tools/man2tcl.c0000644003604700454610000002050211737050675013563 0ustar dgp771div/* * man2tcl.c -- * * This file contains a program that turns a man page of the * form used for Tcl and Tk into a Tcl script that invokes * a Tcl command for each construct in the man page. The * script can then be eval'ed to translate the manual entry * into some other format such as MIF or HTML. * * Usage: * * man2tcl ?fileName? * * Copyright (c) 1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ static char sccsid[] = "@(#) man2tcl.c 1.3 95/08/12 17:34:08"; #include #include #include #ifndef NO_ERRNO_H #include #endif /* * Imported things that aren't defined in header files: */ /* * Some define errno to be something complex and * thread-aware; in that case we definitely do not want to declare * errno ourselves! */ #ifndef errno extern int errno; #endif /* * Current line number, used for error messages. */ static int lineNumber; /* * The variable below is set to 1 if an error occurs anywhere * while reading in the file. */ static int status; /* * The variable below is set to 1 if output should be generated. * If it's 0, it means we're doing a pre-pass to make sure that * the file can be properly parsed. */ static int writeOutput; /* * Prototypes for procedures defined in this file: */ static void DoMacro(char *line); static void DoText(char *line); static void QuoteText(char *string, int count); /* *---------------------------------------------------------------------- * * main -- * * This procedure is the main program, which does all of the work * of the program. * * Results: * None: exits with a 0 return status to indicate success, or * 1 to indicate that there were problems in the translation. * * Side effects: * A Tcl script is output to standard output. Error messages may * be output on standard error. * *---------------------------------------------------------------------- */ int main(argc, argv) int argc; /* Number of command-line arguments. */ char **argv; /* Values of command-line arguments. */ { FILE *f; #define MAX_LINE_SIZE 1000 char line[MAX_LINE_SIZE]; char *p; /* * Find the file to read, and open it if it isn't stdin. */ if (argc == 1) { f = stdin; } else if (argc == 2) { f = fopen(argv[1], "r"); if (f == NULL) { fprintf(stderr, "Couldn't read \"%s\": %s\n", argv[1], strerror(errno)); exit(1); } } else { fprintf(stderr, "Usage: %s ?fileName?\n", argv[0]); } /* * Make two passes over the file. In the first pass, just check * to make sure we can handle everything. If there are problems, * generate output and stop. If everything is OK, make a second * pass to actually generate output. */ for (writeOutput = 0; writeOutput < 2; writeOutput++) { lineNumber = 0; status = 0; while (fgets(line, MAX_LINE_SIZE, f) != NULL) { for (p = line; *p != 0; p++) { if (*p == '\n') { *p = 0; break; } } lineNumber++; if ((line[0] == '\'') && (line[1] == '\\') && (line[2] == '\"')) { /* * This line is a comment. Ignore it. */ continue; } if (strlen(line) >= MAX_LINE_SIZE -1) { fprintf(stderr, "Too long line. Max is %d chars.\n", MAX_LINE_SIZE - 1); exit(1); } if ((line[0] == '.') || (line[0] == '\'')) { /* * This line is a macro invocation. */ DoMacro(line); } else { /* * This line is text, possibly with formatting characters * embedded in it. */ DoText(line); } } if (status != 0) { break; } fseek(f, 0, SEEK_SET); } exit(status); } /* *---------------------------------------------------------------------- * * DoMacro -- * * This procedure is called to handle a macro invocation. * It parses the arguments to the macro and generates a * Tcl command to handle the invocation. * * Results: * None. * * Side effects: * A Tcl command is written to stdout. * *---------------------------------------------------------------------- */ static void DoMacro(line) char *line; /* The line of text that contains the * macro invocation. */ { char *p, *end; /* * If there is no macro name, then just skip the whole line. */ if ((line[1] == 0) || (isspace(line[1]))) { return; } if (writeOutput) { printf("macro"); } if (*line != '.') { if (writeOutput) { printf("2"); } } /* * Parse the arguments to the macro (including the name), in order. */ p = line+1; while (1) { if (writeOutput) { putc(' ', stdout); } if (*p == '"') { /* * The argument is delimited by quotes. */ for (end = p+1; *end != '"'; end++) { if (*end == 0) { fprintf(stderr, "Unclosed quote in macro call on line %d.\n", lineNumber); status = 1; break; } } QuoteText(p+1, (end-(p+1))); } else { for (end = p+1; (*end != 0) && !isspace(*end); end++) { /* Empty loop body. */ } QuoteText(p, end-p); } if (*end == 0) { break; } p = end+1; while (isspace(*p)) { /* * Skip empty space before next argument. */ p++; } if (*p == 0) { break; } } if (writeOutput) { putc('\n', stdout); } } /* *---------------------------------------------------------------------- * * DoText -- * * This procedure is called to handle a line of troff text. * It parses the text, generating Tcl commands for text and * for formatting stuff such as font changes. * * Results: * None. * * Side effects: * Tcl commands are written to stdout. * *---------------------------------------------------------------------- */ static void DoText(line) char *line; /* The line of text. */ { char *p, *end; /* * Divide the line up into pieces consisting of backslash sequences, * tabs, and other text. */ p = line; while (*p != 0) { if (*p == '\t') { if (writeOutput) { printf("tab\n"); } p++; } else if (*p != '\\') { /* * Ordinary text. */ for (end = p+1; (*end != '\\') && (*end != 0); end++) { /* Empty loop body. */ } if (writeOutput) { printf("text "); } QuoteText(p, end-p); if (writeOutput) { putc('\n', stdout); } p = end; } else { /* * A backslash sequence. There are particular ones * that we understand; output an error message for * anything else and just ignore the backslash. */ p++; if (*p == 'f') { /* * Font change. */ if (writeOutput) { printf("font %c\n", p[1]); } p += 2; } else if (*p == '-') { if (writeOutput) { printf("dash\n"); } p++; } else if (*p == 'e') { if (writeOutput) { printf("text \\\\\n"); } p++; } else if (*p == '.') { if (writeOutput) { printf("text .\n"); } p++; } else if (*p == '&') { p++; } else if (*p == '(') { if ((p[1] == 0) || (p[2] == 0)) { fprintf(stderr, "Bad \\( sequence on line %d.\n", lineNumber); status = 1; } else { if (writeOutput) { printf("char {\\(%c%c}\n", p[1], p[2]); } p += 3; } } else if (*p != 0) { if (writeOutput) { printf("char {\\%c}\n", *p); } p++; } } } if (writeOutput) { printf("newline\n"); } } /* *---------------------------------------------------------------------- * * QuoteText -- * * Copy the "string" argument to stdout, adding quote characters * around any special Tcl characters so that they'll just be treated * as ordinary text. * * Results: * None. * * Side effects: * Text is written to stdout. * *---------------------------------------------------------------------- */ static void QuoteText(string, count) char *string; /* The line of text. */ int count; /* Number of characters to write from string. */ { if (count == 0) { if (writeOutput) { printf("{}"); } return; } for ( ; count > 0; string++, count--) { if ((*string == '$') || (*string == '[') || (*string == '{') || (*string == ' ') || (*string == ';') || (*string == '\\') || (*string == '"') || (*string == '\t')) { if (writeOutput) { putc('\\', stdout); } } if (writeOutput) { putc(*string, stdout); } } } tcl8.4.20/tools/cvtEOL.tcl0000644003604700454610000000156011737050674013721 0ustar dgp771div# cvtEOL.tcl -- # # This file contains a script to parse a Tcl/Tk distribution and # convert the EOL from \n to \r on all text files. # # Copyright (c) 1996-1997 by Sun Microsystems, Inc. # # Convert files in the distribution to Mac style # set distDir [lindex $argv 0] set dirs {unix mac generic win library compat tests unix/dltest \ library/demos library/demos/images bitmaps xlib xlib/X11 .} set files {*.c *.y *.h *.r *.tcl *.test *.rc *.bc *.vc *.bmp *.html \ *.in *.notes *.terms all defs \ README ToDo changes tclIndex configure install-sh mkLinks \ square widget rmt ixset hello browse rolodex tcolor timer} foreach x $dirs { if [catch {cd $distDir/$x}] continue puts "Working on $x..." foreach y [eval glob $files] { exec chmod 666 $y exec cp $y $y.tmp exec tr \012 \015 < $y.tmp > $y exec chmod 444 $y exec rm $y.tmp } } tcl8.4.20/tools/man2help.tcl0000644003604700454610000000626411737050675014302 0ustar dgp771div# man2help.tcl -- # # This file defines procedures that work in conjunction with the # man2tcl program to generate a Windows help file from Tcl manual # entries. # # Copyright (c) 1996 by Sun Microsystems, Inc. # # PASS 1 # set man2tclprog [file join [file dirname [info script]] man2tcl.exe] proc generateContents {basename version files} { global curID topics set curID 0 foreach f $files { puts "Pass 1 -- $f" flush stdout doFile $f } set fd [open [file join [file dirname [info script]] $basename$version.cnt] w] fconfigure $fd -translation crlf puts $fd ":Base $basename$version.hlp" foreach package [getPackages] { foreach section [getSections $package] { if {![info exists lastSection]} { set lastSection {} } if {[string compare $lastSection $section]} { puts $fd "1 $section" } set lastSection $section set lastTopic {} foreach topic [getTopics $package $section] { if {[string compare $lastTopic $topic]} { set id $topics($package,$section,$topic) puts $fd "2 $topic=$id" set lastTopic $topic } } } } close $fd } # # PASS 2 # proc generateHelp {basename files} { global curID topics keywords file id_keywords set curID 0 foreach key [array names keywords] { foreach id $keywords($key) { lappend id_keywords($id) $key } } set file [open [file join [file dirname [info script]] $basename.rtf] w] fconfigure $file -translation crlf puts $file "\{\\rtf1\\ansi \\deff0\\deflang1033\{\\fonttbl\{\\f0\\froman\\fcharset0\\fprq2 Times New Roman\;\}\{\\f1\\fmodern\\fcharset0\\fprq1 Courier New\;\}\}" foreach f $files { puts "Pass 2 -- $f" flush stdout initGlobals doFile $f pageBreak } puts $file "\}" close $file } # doFile -- # # Given a file as argument, translate the file to a tcl script and # evaluate it. # # Arguments: # file - Name of file to translate. proc doFile {file} { global man2tclprog if {[catch {eval [exec $man2tclprog [glob $file]]} msg]} { global errorInfo puts stderr $msg puts "in" puts $errorInfo exit 1 } } # doDir -- # # Given a directory as argument, translate all the man pages in # that directory. # # Arguments: # dir - Name of the directory. proc doDir dir { puts "Generating man pages for $dir..." foreach f [lsort [glob -directory $dir "*.\[13n\]"]] { doFile $f } } # process command line arguments if {$argc < 3} { puts stderr "usage: $argv0 \[options\] projectName version manFiles..." exit 1 } set arg 0 if {![string compare [lindex $argv $arg] "-bitmap"]} { set bitmap [lindex $argv [incr arg]] incr arg } set baseName [lindex $argv $arg] set version [lindex $argv [incr arg]] set files {} foreach i [lrange $argv [incr arg] end] { set i [file join $i] if {[file isdir $i]} { foreach f [lsort [glob -directory $i "*.\[13n\]"]] { lappend files $f } } elseif {[file exists $i]} { lappend files $i } } source [file join [file dirname [info script]] index.tcl] generateContents $baseName $version $files source [file join [file dirname [info script]] man2help2.tcl] generateHelp $baseName $files tcl8.4.20/tools/tcl.wse.in0000644003604700454610000021151712153151143013757 0ustar dgp771divDocument Type: WSE item: Global Version=6.01 Title=Tcl 8.4 for Windows Installation Flags=00010100 Languages=65 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Japanese Font Name=MS Gothic Japanese Font Size=10 Start Gradient=0 0 255 End Gradient=0 0 0 Windows Flags=00000000000000010010110000001000 Log Pathname=%MAINDIR%\INSTALL.LOG Message Font=MS Sans Serif Font Size=8 Disk Label=tcl8.4.20 Disk Filename=setup Patch Flags=0000000000000001 Patch Threshold=85 Patch Memory=4000 Variable Name1=_SYS_ Variable Default1=C:\WINDOWS\SYSTEM Variable Flags1=00001000 Variable Name2=_ODBC16_ Variable Default2=C:\WINDOWS\SYSTEM Variable Flags2=00001000 Variable Name3=_WISE_ Variable Default3=${__WISE__} Variable Flags3=00001000 end item: Open/Close INSTALL.LOG Flags=00000001 end item: Check if File/Dir Exists Pathname=%SYS% Flags=10000100 end item: Set Variable Variable=SYS Value=%WIN% end item: End Block end item: Set Variable Variable=VER Value=8.4 end item: Set Variable Variable=PATCHLEVEL Value=${__TCL_PATCH_LEVEL__} end item: Set Variable Variable=APPTITLE Value=Tcl/Tk %PATCHLEVEL% for Windows end item: Set Variable Variable=URL Value=http://www.tcl.tk/ end item: Set Variable Variable=GROUP Value=Tcl end item: Set Variable Variable=DISABLED Value=! end item: Set Variable Variable=MAINDIR Value=Tcl end item: Check Configuration Flags=10111011 end item: Get Registry Key Value Variable=PROGRAM_FILES Key=SOFTWARE\Microsoft\Windows\CurrentVersion Default=C:\Program Files Value Name=ProgramFilesDir Flags=00000100 end item: Set Variable Variable=MAINDIR Value=%PROGRAM_FILES%\%MAINDIR% end item: Set Variable Variable=EXPLORER Value=1 end item: Else Statement end item: Set Variable Variable=MAINDIR Value=C:\%MAINDIR% end item: End Block end item: Set Variable Variable=BACKUP Value=%MAINDIR%\BACKUP end item: Set Variable Variable=DOBACKUP Value=B end item: Set Variable Variable=BRANDING Value=0 end remarked item: If/While Statement Variable=BRANDING Value=1 end remarked item: Read INI Value Variable=NAME Pathname=%INST%\CUSTDATA.INI Section=Registration Item=Name end remarked item: Read INI Value Variable=COMPANY Pathname=%INST%\CUSTDATA.INI Section=Registration Item=Company end remarked item: If/While Statement Variable=NAME end remarked item: Set Variable Variable=DOBRAND Value=1 end remarked item: End Block end remarked item: End Block end item: Set Variable Variable=TYPE Value=C end item: Set Variable Variable=COMPONENTS Value=ABC end item: Wizard Block Direction Variable=DIRECTION Display Variable=DISPLAY X Position=0 Y Position=0 Filler Color=8421440 Flags=00000001 end item: Custom Dialog Set Name=Splash Display Variable=DISPLAY item: Dialog Title=%APPTITLE% Installation Title French=Bienvenue Title German=Willkommen Title Portuguese=Bem-vindo Title Spanish=Bienvenido Title Italian=Benvenuto Title Danish=Velkommen Title Dutch=Welkom Title Norwegian=Velkommen Title Swedish=VУЏТПТНlkommen Width=273 Height=250 Font Name=Helv Font Size=8 item: Push Button Rectangle=166 214 208 228 Variable=DIRECTION Value=N Create Flags=01010000000000010000000000000001 Text=&Next > end item: Push Button Rectangle=212 214 254 228 Action=3 Create Flags=01010000000000010000000000000000 Text=Cancel end item: Static Rectangle=0 0 268 233 Action=2 Enabled Color=00000000000000001111111111111111 Create Flags=01010000000000000000000000001011 Pathname=${__TCLBASEDIR__}\tools\white.bmp end item: Static Rectangle=5 5 268 215 Destination Dialog=1 Action=2 Enabled Color=00000000000000001111111111111111 Create Flags=01010000000000000000000000001011 Pathname=${__TCLBASEDIR__}\tools\tclSplash.bmp end end end item: End Block end item: Wizard Block Direction Variable=DIRECTION Display Variable=DISPLAY Bitmap Pathname=%_WISE_%\DIALOGS\TEMPLATE\WIZARD.BMP X Position=9 Y Position=10 Filler Color=8421440 Dialog=Welcome Dialog=Select Destination Directory Dialog=Select Installation Type Dialog=Select Components Dialog=Select Program Manager Group Variable= Variable= Variable= Variable=TYPE Variable=EXPLORER Value= Value= Value= Value=C Value=1 Compare=0 Compare=0 Compare=0 Compare=1 Compare=0 Flags=00000011 end item: Custom Dialog Set Name=Welcome Display Variable=DISPLAY item: Dialog Title=%APPTITLE% Installation Title French=Installation de %APPTITLE% Title German=Installation von %APPTITLE% Title Spanish=InstalaciУЏТПТНn de %APPTITLE% Title Italian=Installazione di %APPTITLE% Width=271 Height=224 Font Name=Helv Font Size=8 item: Static Rectangle=86 8 258 42 Create Flags=01010000000000000000000000000000 Flags=0000000000000001 Name=Times New Roman Font Style=-24 0 0 0 700 255 0 0 0 3 2 1 18 Text=Welcome! Text French=Bienvenue ! Text German=Willkommen! Text Spanish=УЏТПТНBienvenido! Text Italian=Benvenuti! end item: Push Button Rectangle=150 187 195 202 Variable=DIRECTION Value=N Create Flags=01010000000000010000000000000001 Text=&Next > Text French=&Suite > Text German=&Weiter > Text Spanish=&Siguiente > Text Italian=&Avanti > end item: Push Button Rectangle=105 187 150 202 Variable=DISABLED Value=! Create Flags=01010000000000010000000000000000 Text=< &Back Text French=< &Retour Text German=< &ZurУЏТПТНck Text Spanish=< &AtrУЏТПТНs Text Italian=< &Indietro end item: Push Button Rectangle=211 187 256 202 Action=3 Create Flags=01010000000000010000000000000000 Text=&Cancel Text French=&Annuler Text German=&Abbrechen Text Spanish=&Cancelar Text Italian=&Annulla end item: Static Rectangle=85 41 255 130 Create Flags=01010000000000000000000000000000 Text=This installation program will install %APPTITLE%. Text= Text=Press the Next button to start the installation. You can press the Exit Setup button now if you do not want to install %APPTITLE% at this time. Text= Text=It is strongly recommended that you exit all Windows programs before running this installation program. Text French=Ce programme d'installation va installer %APPTITLE%. Text French= Text French=Cliquez sur le bouton Suite pour dУЏТПТНmarrer l'installation. Vous pouvez cliquer sur le bouton Quitter l'installation si vous ne voulez pas installer %APPTITLE% tout de suite. Text German=Mit diesem Installationsprogramm wird %APPTITLE% installiert. Text German= Text German=Klicken Sie auf "Weiter", um mit der Installation zu beginnen. Klicken Sie auf "Abbrechen", um die Installation von %APPTITLE% abzubrechen. Text Spanish=Este programa de instalaciУЏТПТНn instalarУЏТПТН %APPTITLE%. Text Spanish= Text Spanish=Presione el botУЏТПТНn Siguiente para iniciar la instalaciУЏТПТНn. Puede presionar el botУЏТПТНn Salir de instalaciУЏТПТНn si no desea instalar %APPTITLE% en este momento. Text Italian=Questo programma installerУЏТПТН %APPTITLE%. Text Italian= Text Italian=Per avvviare l'installazione premere il pulsante Avanti. Se non si desidera installare %APPTITLE% ora, premere il pulsante Esci dall'installazione. end item: Static Rectangle=8 180 256 181 Action=3 Create Flags=01010000000000000000000000000111 end end end item: Custom Dialog Set Name=Select Destination Directory Display Variable=DISPLAY item: Dialog Title=%APPTITLE% Installation Title French=Installation de %APPTITLE% Title German=Installation von %APPTITLE% Title Spanish=InstalaciУЏТПТНn de %APPTITLE% Title Italian=Installazione di %APPTITLE% Width=271 Height=224 Font Name=Helv Font Size=8 item: Push Button Rectangle=150 187 195 202 Variable=DIRECTION Value=N Create Flags=01010000000000010000000000000001 Text=&Next > Text French=&Suite > Text German=&Weiter > Text Spanish=&Siguiente > Text Italian=&Avanti > end item: Push Button Rectangle=105 187 150 202 Variable=DIRECTION Value=B Create Flags=01010000000000010000000000000000 Flags=0000000000000001 Text=< &Back Text French=< &Retour Text German=< &ZurУЏТПТНck Text Spanish=< &AtrУЏТПТНs Text Italian=< &Indietro end item: Push Button Rectangle=211 187 256 202 Action=3 Create Flags=01010000000000010000000000000000 Text=&Cancel Text French=&Annuler Text German=&Abbrechen Text Spanish=&Cancelar Text Italian=&Annulla end item: Static Rectangle=8 180 256 181 Action=3 Create Flags=01010000000000000000000000000111 end item: Static Rectangle=86 8 258 42 Create Flags=01010000000000000000000000000000 Flags=0000000000000001 Name=Times New Roman Font Style=-24 0 0 0 700 255 0 0 0 3 2 1 18 Text=Select Destination Directory Text French=SУЏТПТНlectionner le rУЏТПТНpertoire de destination Text German=Zielverzeichnis wУЏТПТНhlen Text Spanish=Seleccione el directorio de destino Text Italian=Selezionare Directory di destinazione end item: Static Rectangle=86 39 256 114 Create Flags=01010000000000000000000000000000 Text=Please select the directory where the %APPTITLE% files are to be installed. Text= Text=To install in the default directory below, click Next. Text= Text=To install in a different directory, click Browse and select another directory. Text French=Veuillez sУЏТПТНlectionner le rУЏТПТНpertoire dans lequel les fichiers %APPTITLE% doivent УЏТПТНtre installУЏТПТНs. Text German=Geben Sie an, in welchem Verzeichnis die %APPTITLE%-Dateien installiert werden sollen. Text Spanish=Por favor seleccione el directorio donde desee instalar los archivos de %APPTITLE%. Text Italian=Selezionare la directory dove verranno installati i file %APPTITLE%. end item: Static Rectangle=86 130 256 157 Action=1 Create Flags=01010000000000000000000000000111 end item: Push Button Rectangle=205 138 250 153 Variable=MAINDIR_SAVE Value=%MAINDIR% Destination Dialog=1 Action=2 Create Flags=01010000000000010000000000000000 Text=Browse Text French=Parcourir Text German=Durchsuchen Text Spanish=Buscar Text Italian=Sfoglie end item: Static Rectangle=91 140 198 151 Create Flags=01010000000000000000000000000000 Text=%MAINDIR% Text French=%MAINDIR% Text German=%MAINDIR% Text Spanish=%MAINDIR% Text Italian=%MAINDIR% end end item: Dialog Title=Select Destination Directory Title French=SУЏТПТНlectionner le rУЏТПТНpertoire de destination Title German=Zielverzeichnis wУЏТПТНhlen Title Spanish=Seleccione el directorio de destino Title Italian=Selezionare Directory di destinazione Width=221 Height=173 Font Name=Helv Font Size=8 item: Listbox Rectangle=5 5 163 149 Variable=MAINDIR Create Flags=01010000100000010000000101000000 Flags=0000110000100010 Text=%MAINDIR% Text French=%MAINDIR% Text German=%MAINDIR% Text Spanish=%MAINDIR% Text Italian=%MAINDIR% end item: Push Button Rectangle=167 6 212 21 Create Flags=01010000000000010000000000000001 Text=OK Text French=OK Text German=OK Text Spanish=Aceptar Text Italian=OK end item: Push Button Rectangle=167 25 212 40 Variable=MAINDIR Value=%MAINDIR_SAVE% Create Flags=01010000000000010000000000000000 Flags=0000000000000001 Text=Cancel Text French=Annuler Text German=Abbrechen Text Spanish=Cancelar Text Italian=Annulla end end end remarked item: Custom Dialog Set Name=Select Installation Type Display Variable=DISPLAY item: Dialog Title=%APPTITLE% Installation Title French=Installation de %APPTITLE% Title German=Installation von %APPTITLE% Title Spanish=InstalaciУЏТПТНn de %APPTITLE% Title Italian=Installazione di %APPTITLE% Width=271 Height=224 Font Name=Helv Font Size=8 item: Push Button Rectangle=150 187 195 202 Variable=DIRECTION Value=N Create Flags=01010000000000010000000000000001 Text=&Next > Text French=&Suite > Text German=&Weiter > Text Spanish=&Siguiente > Text Italian=&Avanti > end item: Push Button Rectangle=105 187 150 202 Variable=DIRECTION Value=B Create Flags=01010000000000010000000000000000 Text=< &Back Text French=< &Retour Text German=< &ZurУЏТПТНck Text Spanish=< &AtrУЏТПТНs Text Italian=< &Indietro end item: Push Button Rectangle=211 187 256 202 Action=3 Create Flags=01010000000000010000000000000000 Text=&Cancel Text French=&Annuler Text German=&Abbrechen Text Spanish=&Cancelar Text Italian=&Annulla end item: Static Rectangle=8 180 256 181 Action=3 Create Flags=01010000000000000000000000000111 end item: Static Rectangle=86 8 258 42 Create Flags=01010000000000000000000000000000 Flags=0000000000000001 Name=Times New Roman Font Style=-24 0 0 0 700 255 0 0 0 3 2 1 18 Text=Select Installation Type Text French=SУЏТПТНlectionner les composants Text German=Komponenten auswУЏТПТНhlen Text Spanish=Seleccione componentes Text Italian=Selezionare i componenti end item: Static Rectangle=194 162 242 172 Variable=COMPONENTS Value=MAINDIR Create Flags=01010000000000000000000000000010 end item: Static Rectangle=194 153 242 162 Variable=COMPONENTS Create Flags=01010000000000000000000000000010 end item: Static Rectangle=107 153 196 164 Create Flags=01010000000000000000000000000000 Text=Disk Space Required: Text French=Espace disque requis : Text German=Notwendiger Speicherplatz: Text Spanish=Espacio requerido en el disco: Text Italian=Spazio su disco necessario: end item: Static Rectangle=107 162 196 172 Create Flags=01010000000000000000000000000000 Text=Disk Space Remaining: Text French=Espace disque disponible : Text German=Verbleibender Speicherplatz: Text Spanish=Espacio en disco disponible: Text Italian=Spazio su disco disponibile: end item: Static Rectangle=86 145 256 175 Action=1 Create Flags=01010000000000000000000000000111 end item: Static Rectangle=86 42 256 61 Create Flags=01010000000000000000000000000000 Text=Choose which type of installation to perform by selecting one of the buttons below. Text French=Choisissez les composants que vous voulez installer en cochant les cases ci-dessous. Text German=WУЏТПТНhlen Sie die zu installierenden Komponenten, indem Sie in die entsprechenden KУЏТПТНstchen klicken. Text Spanish=Elija los componentes que desee instalar marcando los cuadros de abajo. Text Italian=Scegliere quali componenti installare selezionando le caselle sottostanti. end item: Radio Button Rectangle=86 74 256 128 Variable=TYPE Create Flags=01010000000000010000000000001001 Text=&Full Installation (Recommended) Text=&Minimal Installation Text=C&ustom Installation Text= end end end item: Custom Dialog Set Name=Select Components Display Variable=DISPLAY item: Dialog Title=%APPTITLE% Installation Title French=Installation de %APPTITLE% Title German=Installation von %APPTITLE% Title Spanish=InstalaciУЏТПТНn de %APPTITLE% Title Italian=Installazione di %APPTITLE% Width=271 Height=224 Font Name=Helv Font Size=8 item: Push Button Rectangle=150 187 195 202 Variable=DIRECTION Value=N Create Flags=01010000000000010000000000000001 Text=&Next > Text French=&Suite > Text German=&Weiter > Text Spanish=&Siguiente > Text Italian=&Avanti > end item: Push Button Rectangle=105 187 150 202 Variable=DIRECTION Value=B Create Flags=01010000000000010000000000000000 Text=< &Back Text French=< &Retour Text German=< &ZurУЏТПТНck Text Spanish=< &AtrУЏТПТНs Text Italian=< &Indietro end item: Push Button Rectangle=211 187 256 202 Action=3 Create Flags=01010000000000010000000000000000 Text=&Cancel Text French=&Annuler Text German=&Abbrechen Text Spanish=&Cancelar Text Italian=&Annulla end item: Static Rectangle=8 180 256 181 Action=3 Create Flags=01010000000000000000000000000111 end item: Static Rectangle=86 8 258 42 Create Flags=01010000000000000000000000000000 Flags=0000000000000001 Name=Times New Roman Font Style=-24 0 0 0 700 255 0 0 0 3 2 1 18 Text=Select Components Text French=SУЏТПТНlectionner les composants Text German=Komponenten auswУЏТПТНhlen Text Spanish=Seleccione componentes Text Italian=Selezionare i componenti end item: Checkbox Rectangle=86 75 256 129 Variable=COMPONENTS Create Flags=01010000000000010000000000000011 Flags=0000000000000110 Text=Tcl Run-Time Files Text=Example Scripts Text=Help Files Text=Header and Library Files Text= Text French=Tcl Run-Time Files Text French=Example Scripts Text French=Help Files Text French=Header and Library Files Text French= Text German=Tcl Run-Time Files Text German=Example Scripts Text German=Help Files Text German=Header and Library Files Text German= Text Spanish=Tcl Run-Time Files Text Spanish=Example Scripts Text Spanish=Help Files Text Spanish=Header and Library Files Text Spanish= Text Italian=Tcl Run-Time Files Text Italian=Example Scripts Text Italian=Help Files Text Italian=Header and Library Files Text Italian= end item: Static Rectangle=194 162 242 172 Variable=COMPONENTS Value=MAINDIR Create Flags=01010000000000000000000000000010 end item: Static Rectangle=194 153 242 162 Variable=COMPONENTS Create Flags=01010000000000000000000000000010 end item: Static Rectangle=107 153 196 164 Create Flags=01010000000000000000000000000000 Text=Disk Space Required: Text French=Espace disque requis : Text German=Notwendiger Speicherplatz: Text Spanish=Espacio requerido en el disco: Text Italian=Spazio su disco necessario: end item: Static Rectangle=107 162 196 172 Create Flags=01010000000000000000000000000000 Text=Disk Space Remaining: Text French=Espace disque disponible : Text German=Verbleibender Speicherplatz: Text Spanish=Espacio en disco disponible: Text Italian=Spazio su disco disponibile: end item: Static Rectangle=86 145 256 175 Action=1 Create Flags=01010000000000000000000000000111 end item: Static Rectangle=86 42 256 61 Create Flags=01010000000000000000000000000000 Text=Choose which components to install by checking the boxes below. Text French=Choisissez les composants que vous voulez installer en cochant les cases ci-dessous. Text German=WУЏТПТНhlen Sie die zu installierenden Komponenten, indem Sie in die entsprechenden KУЏТПТНstchen klicken. Text Spanish=Elija los componentes que desee instalar marcando los cuadros de abajo. Text Italian=Scegliere quali componenti installare selezionando le caselle sottostanti. end end end item: Custom Dialog Set Name=Select Program Manager Group Display Variable=DISPLAY item: Dialog Title=%APPTITLE% Installation Title French=Installation de %APPTITLE% Title German=Installation von %APPTITLE% Title Spanish=InstalaciУЏТПТНn de %APPTITLE% Title Italian=Installazione di %APPTITLE% Width=271 Height=224 Font Name=Helv Font Size=8 item: Push Button Rectangle=150 187 195 202 Variable=DIRECTION Value=N Create Flags=01010000000000010000000000000001 Text=&Next > Text French=&Suite > Text German=&Weiter > Text Spanish=&Siguiente > Text Italian=&Avanti > end item: Push Button Rectangle=105 187 150 202 Variable=DIRECTION Value=B Create Flags=01010000000000010000000000000000 Flags=0000000000000001 Text=< &Back Text French=< &Retour Text German=< &ZurУЏТПТНck Text Spanish=< &AtrУЏТПТНs Text Italian=< &Indietro end item: Push Button Rectangle=211 187 256 202 Action=3 Create Flags=01010000000000010000000000000000 Text=&Cancel Text French=&Annuler Text German=&Abbrechen Text Spanish=&Cancelar Text Italian=&Annulla end item: Static Rectangle=8 180 256 181 Action=3 Create Flags=01010000000000000000000000000111 end item: Static Rectangle=86 8 258 42 Create Flags=01010000000000000000000000000000 Flags=0000000000000001 Name=Times New Roman Font Style=-24 0 0 0 700 255 0 0 0 3 2 1 18 Text=Select ProgMan Group Text French=SУЏТПТНlectionner le groupe du Gestionnaire de programme Text German=Bestimmung der Programm-Managergruppe Text Spanish=Seleccione grupo del Administrador de programas Text Italian=Selezionare il gruppo ProgMan end item: Static Rectangle=86 44 256 68 Create Flags=01010000000000000000000000000000 Text=Enter the name of the Program Manager group to add the %APPTITLE% icons to: Text French=Entrez le nom du groupe du Gestionnaire de programme dans lequel vous souhaitez ajouter les icУЏТПТНnes de %APPTITLE% : Text German=Geben Sie den Namen der Programmgruppe ein, der das Symbol %APPTITLE% hinzugefУЏТПТНgt werden soll: Text Spanish=Escriba el nombre del grupo del Administrador de programas en el que desea agregar los iconos de %APPTITLE%: Text Italian=Inserire il nome del gruppo Program Manager per aggiungere le icone %APPTITLE% a: end item: Combobox Rectangle=86 69 256 175 Variable=GROUP Create Flags=01010000000000010000001000000001 Flags=0000000000000001 Text=%GROUP% Text French=%GROUP% Text German=%GROUP% Text Spanish=%GROUP% Text Italian=%GROUP% end end end item: Custom Dialog Set Name=Start Installation Display Variable=DISPLAY item: Dialog Title=%APPTITLE% Installation Title French=Installation de %APPTITLE% Title German=Installation von %APPTITLE% Title Spanish=InstalaciУЏТПТНn de %APPTITLE% Title Italian=Installazione di %APPTITLE% Width=271 Height=224 Font Name=Helv Font Size=8 item: Push Button Rectangle=150 187 195 202 Variable=DIRECTION Value=N Create Flags=01010000000000010000000000000001 Text=&Next > Text French=&Suite > Text German=&Weiter > Text Spanish=&Siguiente > Text Italian=&Avanti > end item: Push Button Rectangle=105 187 150 202 Variable=DIRECTION Value=B Create Flags=01010000000000010000000000000000 Text=< &Back Text French=< &Retour Text German=< &ZurУЏТПТНck Text Spanish=< &AtrУЏТПТНs Text Italian=< &Indietro end item: Push Button Rectangle=211 187 256 202 Action=3 Create Flags=01010000000000010000000000000000 Text=&Cancel Text French=&Annuler Text German=&Abbrechen Text Spanish=&Cancelar Text Italian=&Annulla end item: Static Rectangle=8 180 256 181 Action=3 Create Flags=01010000000000000000000000000111 end item: Static Rectangle=86 8 258 42 Create Flags=01010000000000000000000000000000 Flags=0000000000000001 Name=Times New Roman Font Style=-24 0 0 0 700 255 0 0 0 3 2 1 18 Text=Ready to Install! Text French=PrУЏТПТНt УЏТПТН installer ! Text German=Installationsbereit! Text Spanish=УЏТПТНPreparado para la instalaciУЏТПТНn! Text Italian=Pronto per l'installazione! end item: Static Rectangle=86 42 256 102 Create Flags=01010000000000000000000000000000 Text=You are now ready to install %APPTITLE%. Text= Text=Press the Next button to begin the installation or the Back button to reenter the installation information. Text French=Vous УЏТПТНtes maintenant prУЏТПТНt УЏТПТН installer les fichiers %APPTITLE%. Text French= Text French=Cliquez sur le bouton Suite pour commencer l'installation ou sur le bouton Retour pour entrer les informations d'installation УЏТПТН nouveau. Text German=Sie kУЏТПТНnnen %APPTITLE% nun installieren. Text German= Text German=Klicken Sie auf "Weiter", um mit der Installation zu beginnen. Klicken Sie auf "ZurУЏТПТНck", um die Installationsinformationen neu einzugeben. Text Spanish=Ya estУЏТПТН listo para instalar %APPTITLE%. Text Spanish= Text Spanish=Presione el botУЏТПТНn Siguiente para comenzar la instalaciУЏТПТНn o presione AtrУЏТПТНs para volver a ingresar la informaciУЏТПТНn para la instalaciУЏТПТНn. Text Italian=Ora УЏТПТН possibile installare %APPTITLE%. Text Italian= Text Italian=Premere il pulsante Avanti per avviare l'installazione o il pulsante Indietro per reinserire le informazioni di installazione. end end end item: If/While Statement Variable=DISPLAY Value=Select Destination Directory end item: Set Variable Variable=BACKUP Value=%MAINDIR%\BACKUP end item: End Block end item: End Block end item: If/While Statement Variable=TYPE Value=B end item: Set Variable Variable=COMPONENTS Value=A end item: End Block end item: If/While Statement Variable=DOBACKUP Value=A end item: Set Variable Variable=BACKUPDIR Value=%BACKUP% end item: End Block end remarked item: If/While Statement Variable=BRANDING Value=1 end remarked item: If/While Statement Variable=DOBRAND Value=1 end remarked item: Edit INI File Pathname=%INST%\CUSTDATA.INI Settings=[Registration] Settings=NAME=%NAME% Settings=COMPANY=%COMPANY% Settings= end remarked item: End Block end remarked item: End Block end item: Set Variable Variable=MAINDIRSHORT Value=%MAINDIR% Flags=00010100 end item: Open/Close INSTALL.LOG end item: Check Disk Space Component=COMPONENTS end item: Install File Source=${__TCLBASEDIR__}\license.txt Destination=%MAINDIR%\license.txt Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\win\Readme.txt Destination=%MAINDIR%\Readme.txt Flags=0000000000000010 end item: If/While Statement Variable=COMPONENTS Value=D Flags=00001010 end item: Install File Source=${__TKBASEDIR__}\win\release\tk84.lib Destination=%MAINDIR%\lib\tk84.lib Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\win\release\tkstub84.lib Destination=%MAINDIR%\lib\tkstub84.lib Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\win\release\tcl84.lib Destination=%MAINDIR%\lib\tcl84.lib Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\win\release\tclstub84.lib Destination=%MAINDIR%\lib\tclstub84.lib Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\xlib\X11\Xutil.h Destination=%MAINDIR%\include\X11\Xutil.h Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\xlib\X11\Xlib.h Destination=%MAINDIR%\include\X11\Xlib.h Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\xlib\X11\Xfuncproto.h Destination=%MAINDIR%\include\X11\Xfuncproto.h Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\xlib\X11\Xatom.h Destination=%MAINDIR%\include\X11\Xatom.h Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\xlib\X11\X.h Destination=%MAINDIR%\include\X11\X.h Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\xlib\X11\keysymdef.h Destination=%MAINDIR%\include\X11\keysymdef.h Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\xlib\X11\keysym.h Destination=%MAINDIR%\include\X11\keysym.h Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\xlib\X11\cursorfont.h Destination=%MAINDIR%\include\X11\cursorfont.h Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\generic\tk.h Destination=%MAINDIR%\include\tk.h Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\generic\tkDecls.h Destination=%MAINDIR%\include\tkDecls.h Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\generic\tkPlatDecls.h Destination=%MAINDIR%\include\tkPlatDecls.h Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\generic\tkIntXlibDecls.h Destination=%MAINDIR%\include\tkIntXlibDecls.h Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\generic\tcl.h Destination=%MAINDIR%\include\tcl.h Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\generic\tclDecls.h Destination=%MAINDIR%\include\tclDecls.h Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\generic\tclPlatDecls.h Destination=%MAINDIR%\include\tclPlatDecls.h Flags=0000000000000010 end item: End Block end item: If/While Statement Variable=COMPONENTS Value=A Flags=00001010 end item: Install File Source=${__TCLBASEDIR__}\library\msgcat\pkgIndex.tcl Destination=%MAINDIR%\lib\tcl%VER%\msgcat1.2\pkgIndex.tcl Flags=0000000010000010 end item: Install File Source=${__TCLBASEDIR__}\library\msgcat\msgcat.tcl Destination=%MAINDIR%\lib\tcl%VER%\msgcat1.2\msgcat.tcl Flags=0000000010000010 end item: Install File Source=${__TCLBASEDIR__}\library\tcltest\pkgIndex.tcl Destination=%MAINDIR%\lib\tcl%VER%\tcltest2.0\pkgIndex.tcl Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\tcltest\tcltest.tcl Destination=%MAINDIR%\lib\tcl%VER%\tcltest2.0\tcltest.tcl Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\symbol.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\symbol.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\shiftjis.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\shiftjis.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\macUkraine.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\macUkraine.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\macTurkish.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\macTurkish.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\macThai.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\macThai.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\macRomania.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\macRomania.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\macRoman.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\macRoman.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\macJapan.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\macJapan.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\macIceland.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\macIceland.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\macGreek.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\macGreek.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\macDingbats.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\macDingbats.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\macCyrillic.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\macCyrillic.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\macCroatian.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\macCroatian.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\macCentEuro.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\macCentEuro.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\ksc5601.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\ksc5601.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\koi8-r.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\koi8-r.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\jis0212.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\jis0212.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\jis0208.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\jis0208.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\jis0201.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\jis0201.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\iso8859-15.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\iso8859-15.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\iso8859-9.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\iso8859-9.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\iso8859-8.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\iso8859-8.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\iso8859-7.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\iso8859-7.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\iso8859-6.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\iso8859-6.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\iso8859-5.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\iso8859-5.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\iso8859-4.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\iso8859-4.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\iso8859-3.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\iso8859-3.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\iso8859-2.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\iso8859-2.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\iso8859-1.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\iso8859-1.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\iso2022.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\iso2022.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\iso2022-kr.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\iso2022-kr.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\iso2022-jp.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\iso2022-jp.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\gb2312.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\gb2312.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\gb1988.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\gb1988.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\gb12345.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\gb12345.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\euc-cn.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\euc-cn.enc Flags=0000000010000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\euc-jp.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\euc-jp.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\euc-kr.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\euc-kr.enc Flags=0000000010000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\dingbats.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\dingbats.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\cp950.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp950.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\cp949.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp949.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\cp936.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp936.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\cp932.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp932.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\cp874.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp874.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\cp869.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp869.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\cp866.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp866.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\cp865.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp865.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\cp864.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp864.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\cp863.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp863.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\cp862.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp862.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\cp861.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp861.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\cp860.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp860.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\cp857.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp857.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\cp855.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp855.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\cp852.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp852.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\cp850.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp850.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\cp775.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp775.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\cp737.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp737.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\cp437.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp437.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\cp1258.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp1258.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\cp1257.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp1257.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\cp1256.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp1256.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\cp1255.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp1255.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\cp1254.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp1254.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\cp1253.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp1253.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\cp1252.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp1252.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\cp1251.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp1251.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\cp1250.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp1250.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\ascii.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\ascii.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\encoding\big5.enc Destination=%MAINDIR%\lib\tcl%VER%\encoding\big5.enc Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\opt\pkgIndex.tcl Destination=%MAINDIR%\lib\tcl%VER%\opt0.4\pkgIndex.tcl Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\opt\optparse.tcl Destination=%MAINDIR%\lib\tcl%VER%\opt0.4\optparse.tcl Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\http\pkgIndex.tcl Destination=%MAINDIR%\lib\tcl%VER%\http2.5\pkgIndex.tcl Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\http\http.tcl Destination=%MAINDIR%\lib\tcl%VER%\http2.5\http.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\msgbox.tcl Destination=%MAINDIR%\lib\tk%VER%\msgbox.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\optMenu.tcl Destination=%MAINDIR%\lib\tk%VER%\optMenu.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\clrpick.tcl Destination=%MAINDIR%\lib\tk%VER%\clrpick.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\entry.tcl Destination=%MAINDIR%\lib\tk%VER%\entry.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\spinbox.tcl Destination=%MAINDIR%\lib\tk%VER%\spinbox.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\comdlg.tcl Destination=%MAINDIR%\lib\tk%VER%\comdlg.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\bgerror.tcl Destination=%MAINDIR%\lib\tk%VER%\bgerror.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\obsolete.tcl Destination=%MAINDIR%\lib\tk%VER%\obsolete.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\button.tcl Destination=%MAINDIR%\lib\tk%VER%\button.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\xmfbox.tcl Destination=%MAINDIR%\lib\tk%VER%\xmfbox.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\console.tcl Destination=%MAINDIR%\lib\tk%VER%\console.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\listbox.tcl Destination=%MAINDIR%\lib\tk%VER%\listbox.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\menu.tcl Destination=%MAINDIR%\lib\tk%VER%\menu.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\dialog.tcl Destination=%MAINDIR%\lib\tk%VER%\dialog.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\focus.tcl Destination=%MAINDIR%\lib\tk%VER%\focus.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\palette.tcl Destination=%MAINDIR%\lib\tk%VER%\palette.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\tkfbox.tcl Destination=%MAINDIR%\lib\tk%VER%\tkfbox.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\tk.tcl Destination=%MAINDIR%\lib\tk%VER%\tk.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\text.tcl Destination=%MAINDIR%\lib\tk%VER%\text.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\tearoff.tcl Destination=%MAINDIR%\lib\tk%VER%\tearoff.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\tclIndex Destination=%MAINDIR%\lib\tk%VER%\tclIndex Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\scrlbar.tcl Destination=%MAINDIR%\lib\tk%VER%\scrlbar.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\scale.tcl Destination=%MAINDIR%\lib\tk%VER%\scale.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\safetk.tcl Destination=%MAINDIR%\lib\tk%VER%\safetk.tcl Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\http1.0\pkgIndex.tcl Destination=%MAINDIR%\lib\tcl%VER%\http1.0\pkgIndex.tcl Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\http1.0\http.tcl Destination=%MAINDIR%\lib\tcl%VER%\http1.0\http.tcl Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\reg\pkgIndex.tcl Destination=%MAINDIR%\lib\tcl%VER%\reg1.2\pkgIndex.tcl Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\win\release\tclreg12.dll Destination=%MAINDIR%\lib\tcl%VER%\reg1.2\tclreg10.dll Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\dde\pkgIndex.tcl Destination=%MAINDIR%\lib\tcl%VER%\dde1.3\pkgIndex.tcl Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\win\release\tcldde13.dll Destination=%MAINDIR%\lib\tcl%VER%\dde1.2\tcldde13.dll Flags=0000000000000010 end item: Install File Source=C:\WINNT\SYSTEM32\Msvcrt.dll Destination=%MAINDIR%\bin\msvcrt.dll Flags=0010001000000011 end item: Install File Source=${__TKBASEDIR__}\win\release\wish84.exe Destination=%MAINDIR%\bin\wish84.exe Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\win\release\tclsh84.exe Destination=%MAINDIR%\bin\tclsh84.exe Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\win\release\tclpip84.dll Destination=%MAINDIR%\bin\tclpip84.dll Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\win\release\tcl84.dll Destination=%MAINDIR%\bin\tcl84.dll Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\win\release\tk84.dll Destination=%MAINDIR%\bin\tk84.dll Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\auto.tcl Destination=%MAINDIR%\lib\tcl%VER%\auto.tcl Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\history.tcl Destination=%MAINDIR%\lib\tcl%VER%\history.tcl Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\init.tcl Destination=%MAINDIR%\lib\tcl%VER%\init.tcl Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\package.tcl Destination=%MAINDIR%\lib\tcl%VER%\package.tcl Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\parray.tcl Destination=%MAINDIR%\lib\tcl%VER%\parray.tcl Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\safe.tcl Destination=%MAINDIR%\lib\tcl%VER%\safe.tcl Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\tclIndex Destination=%MAINDIR%\lib\tcl%VER%\tclIndex Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\library\word.tcl Destination=%MAINDIR%\lib\tcl%VER%\word.tcl Flags=0000000000000010 end item: End Block end item: If/While Statement Variable=COMPONENTS Value=B Flags=00001010 end item: Install File Source=${__TKBASEDIR__}\library\images\tai-ku.gif Destination=%MAINDIR%\lib\tk%VER%\images\tai-ku.gif Flags=0000000010000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\images\teapot.ppm Destination=%MAINDIR%\lib\tk%VER%\demos\images\teapot.ppm Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\images\tcllogo.gif Destination=%MAINDIR%\lib\tk%VER%\demos\images\tcllogo.gif Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\images\pattern.bmp Destination=%MAINDIR%\lib\tk%VER%\demos\images\pattern.bmp Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\images\noletter.bmp Destination=%MAINDIR%\lib\tk%VER%\demos\images\noletter.bmp Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\images\letters.bmp Destination=%MAINDIR%\lib\tk%VER%\demos\images\letters.bmp Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\images\gray25.bmp Destination=%MAINDIR%\lib\tk%VER%\demos\images\gray25.bmp Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\images\flagup.bmp Destination=%MAINDIR%\lib\tk%VER%\demos\images\flagup.bmp Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\images\flagdown.bmp Destination=%MAINDIR%\lib\tk%VER%\demos\images\flagdown.bmp Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\images\face.bmp Destination=%MAINDIR%\lib\tk%VER%\demos\images\face.bmp Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\images\earthris.gif Destination=%MAINDIR%\lib\tk%VER%\demos\images\earthris.gif Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\images\earth.gif Destination=%MAINDIR%\lib\tk%VER%\demos\images\earth.gif Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\vscale.tcl Destination=%MAINDIR%\lib\tk%VER%\demos\vscale.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\twind.tcl Destination=%MAINDIR%\lib\tk%VER%\demos\twind.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\text.tcl Destination=%MAINDIR%\lib\tk%VER%\demos\text.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\style.tcl Destination=%MAINDIR%\lib\tk%VER%\demos\style.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\states.tcl Destination=%MAINDIR%\lib\tk%VER%\demos\states.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\search.tcl Destination=%MAINDIR%\lib\tk%VER%\demos\search.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\sayings.tcl Destination=%MAINDIR%\lib\tk%VER%\demos\sayings.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\ruler.tcl Destination=%MAINDIR%\lib\tk%VER%\demos\ruler.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\radio.tcl Destination=%MAINDIR%\lib\tk%VER%\demos\radio.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\puzzle.tcl Destination=%MAINDIR%\lib\tk%VER%\demos\puzzle.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\plot.tcl Destination=%MAINDIR%\lib\tk%VER%\demos\plot.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\msgbox.tcl Destination=%MAINDIR%\lib\tk%VER%\demos\msgbox.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\menubu.tcl Destination=%MAINDIR%\lib\tk%VER%\demos\menubu.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\menu.tcl Destination=%MAINDIR%\lib\tk%VER%\demos\menu.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\label.tcl Destination=%MAINDIR%\lib\tk%VER%\demos\label.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\items.tcl Destination=%MAINDIR%\lib\tk%VER%\demos\items.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\image2.tcl Destination=%MAINDIR%\lib\tk%VER%\demos\image2.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\image1.tcl Destination=%MAINDIR%\lib\tk%VER%\demos\image1.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\icon.tcl Destination=%MAINDIR%\lib\tk%VER%\demos\icon.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\hscale.tcl Destination=%MAINDIR%\lib\tk%VER%\demos\hscale.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\form.tcl Destination=%MAINDIR%\lib\tk%VER%\demos\form.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\ixset Destination=%MAINDIR%\lib\tk%VER%\demos\ixset.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\rolodex Destination=%MAINDIR%\lib\tk%VER%\demos\rolodex.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\square Destination=%MAINDIR%\lib\tk%VER%\demos\square.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\Readme Destination=%MAINDIR%\lib\tk%VER%\demos\Readme Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\hello Destination=%MAINDIR%\lib\tk%VER%\demos\hello.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\tclIndex Destination=%MAINDIR%\lib\tk%VER%\demos\tclIndex Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\browse Destination=%MAINDIR%\lib\tk%VER%\demos\browse.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\timer Destination=%MAINDIR%\lib\tk%VER%\demos\timer.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\widget Destination=%MAINDIR%\lib\tk%VER%\demos\widget.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\tcolor Destination=%MAINDIR%\lib\tk%VER%\demos\tcolor.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\rmt Destination=%MAINDIR%\lib\tk%VER%\demos\rmt.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\floor.tcl Destination=%MAINDIR%\lib\tk%VER%\demos\floor.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\filebox.tcl Destination=%MAINDIR%\lib\tk%VER%\demos\filebox.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\images\pwrdLogo75.gif Destination=%MAINDIR%\lib\tk%VER%\images\pwrdLogo75.gif Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\images\pwrdLogo200.gif Destination=%MAINDIR%\lib\tk%VER%\images\pwrdLogo200.gif Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\images\pwrdLogo175.gif Destination=%MAINDIR%\lib\tk%VER%\images\pwrdLogo175.gif Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\images\pwrdLogo150.gif Destination=%MAINDIR%\lib\tk%VER%\images\pwrdLogo150.gif Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\images\pwrdLogo100.gif Destination=%MAINDIR%\lib\tk%VER%\images\pwrdLogo100.gif Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\images\logoMed.gif Destination=%MAINDIR%\lib\tk%VER%\images\logoMed.gif Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\images\logoLarge.gif Destination=%MAINDIR%\lib\tk%VER%\images\logoLarge.gif Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\images\logo64.gif Destination=%MAINDIR%\lib\tk%VER%\images\logo64.gif Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\images\logo100.gif Destination=%MAINDIR%\lib\tk%VER%\images\logo100.gif Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\images\Readme Destination=%MAINDIR%\lib\tk%VER%\images\Readme Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\arrow.tcl Destination=%MAINDIR%\lib\tk%VER%\demos\arrow.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\bind.tcl Destination=%MAINDIR%\lib\tk%VER%\demos\bind.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\bitmap.tcl Destination=%MAINDIR%\lib\tk%VER%\demos\bitmap.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\button.tcl Destination=%MAINDIR%\lib\tk%VER%\demos\button.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\check.tcl Destination=%MAINDIR%\lib\tk%VER%\demos\check.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\clrpick.tcl Destination=%MAINDIR%\lib\tk%VER%\demos\clrpick.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\colors.tcl Destination=%MAINDIR%\lib\tk%VER%\demos\colors.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\cscroll.tcl Destination=%MAINDIR%\lib\tk%VER%\demos\cscroll.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\ctext.tcl Destination=%MAINDIR%\lib\tk%VER%\demos\ctext.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\dialog1.tcl Destination=%MAINDIR%\lib\tk%VER%\demos\dialog1.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\dialog2.tcl Destination=%MAINDIR%\lib\tk%VER%\demos\dialog2.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\entry1.tcl Destination=%MAINDIR%\lib\tk%VER%\demos\entry1.tcl Flags=0000000000000010 end item: Install File Source=${__TKBASEDIR__}\library\demos\entry2.tcl Destination=%MAINDIR%\lib\tk%VER%\demos\entry2.tcl Flags=0000000000000010 end item: End Block end item: If/While Statement Variable=COMPONENTS Value=C Flags=00001010 end item: Install File Source=${__TCLBASEDIR__}\tools\tcl84.cnt Destination=%MAINDIR%\doc\tcl84.cnt Flags=0000000000000010 end item: Install File Source=${__TCLBASEDIR__}\tools\tcl84.hlp Destination=%MAINDIR%\doc\tcl84.hlp Flags=0000000000000010 end item: End Block end item: Set Variable Variable=MAINDIR Value=%MAINDIR% Flags=00010100 end item: Include Script Pathname=\\pop\tools\1.2\win32-ix86\wise\INCLUDE\uninstal.wse end item: Check Configuration Flags=10111011 end item: Get Registry Key Value Variable=GROUPDIR Key=Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders Default=%WIN%\Start Menu\Programs Value Name=Programs Flags=00000010 end item: Set Variable Variable=GROUP Value=%GROUPDIR%\%GROUP% end item: If/While Statement Variable=COMPONENTS Value=A Flags=00001010 end item: Create Shortcut Source=%MAINDIR%\bin\wish84.exe Destination=%GROUP%\Wish.lnk Working Directory=%MAINDIR% end item: End Block end item: If/While Statement Variable=COMPONENTS Value=A Flags=00001010 end item: Create Shortcut Source=%MAINDIR%\bin\tclsh84.exe Destination=%GROUP%\Tclsh.lnk Working Directory=%MAINDIR% Key Type=1536 Flags=00000001 end item: End Block end item: If/While Statement Variable=COMPONENTS Value=C Flags=00001010 end item: Create Shortcut Source=%MAINDIR%\doc\tcl84.hlp Destination=%GROUP%\Tcl Help.lnk Working Directory=%MAINDIR% end item: End Block end item: Create Shortcut Source=%MAINDIR%\Readme.txt Destination=%GROUP%\Readme.lnk Working Directory=%MAINDIR% end item: If/While Statement Variable=COMPONENTS Value=B Flags=00001010 end item: Create Shortcut Source=%MAINDIR%\lib\tk%VER%\demos\widget.tcl Destination=%GROUP%\Widget Tour.lnk Working Directory=%MAINDIR% Key Type=1536 Flags=00000001 end item: End Block end item: Else Statement end item: If/While Statement Variable=COMPONENTS Value=B Flags=00001010 end item: Add ProgMan Icon Group=%GROUP% Icon Name=Widget Tour Command Line=%MAINDIR%\lib\tk%VER%\demos\widget.tcl Icon Pathname=%MAINDIR%\bin\wish84.exe Default Directory=%MAINDIR% end item: End Block end item: If/While Statement Variable=COMPONENTS Value=C Flags=00001010 end item: Add ProgMan Icon Group=%GROUP% Icon Name=Tcl Help Command Line=%MAINDIR%\doc\tcl84.hlp Default Directory=%MAINDIR% end item: End Block end item: Add ProgMan Icon Group=%GROUP% Icon Name=Readme Command Line=%MAINDIR%\Readme.txt Default Directory=%MAINDIR% end item: If/While Statement Variable=COMPONENTS Value=A Flags=00001010 end item: Add ProgMan Icon Group=%GROUP% Icon Name=Wish Command Line=%MAINDIR%\bin\wish84.exe Default Directory=%MAINDIR% end item: End Block end item: If/While Statement Variable=COMPONENTS Value=A Flags=00001010 end item: Add ProgMan Icon Group=%GROUP% Icon Name=Tclsh Command Line=%MAINDIR%\bin\tclsh84.exe Default Directory=%MAINDIR% end item: End Block end item: End Block end item: Self-Register OCXs/DLLs Description=Updating System Configuration, Please Wait... end item: Edit Registry Total Keys=1 Key=SOFTWARE\Scriptics\Tcl\%VER% New Value=%MAINDIR% Value Name=Root Root=2 end item: Edit Registry Total Keys=1 Key=TclScript\DefaultIcon New Value=%MAINDIR%\bin\tk84.dll end item: Edit Registry Total Keys=1 Key=.tcl New Value=TclScript end item: Edit Registry Total Keys=1 Key=TclScript New Value=TclScript end item: Edit Registry Total Keys=1 Key=TclScript\shell\open\command New Value=%MAINDIRSHORT%\bin\wish84.exe "%%1" %%* end item: Edit Registry Total Keys=1 Key=TclScript\shell\edit New Value=&Edit end item: Edit Registry Total Keys=1 Key=TclScript\shell\edit\command New Value=notepad "%%1" end item: Add Directory to Path Directory=%MAINDIR%\bin end item: Check Configuration Flags=10111011 end item: Set Variable Variable=TO_SCRIPTICS Value=A end item: Else Statement end item: Set Variable Variable=TO_SCRIPTICS end item: End Block end item: Wizard Block Direction Variable=DIRECTION Display Variable=DISPLAY Bitmap Pathname=%_WISE_%\DIALOGS\TEMPLATE\WIZARD.BMP X Position=9 Y Position=10 Filler Color=8421440 Flags=00000011 end item: Custom Dialog Set Name=Finished Display Variable=DISPLAY item: Dialog Title=%APPTITLE% Installation Title French=Installation de %APPTITLE% Title German=Installation von %APPTITLE% Title Spanish=InstalaciУЏТПТНn de %APPTITLE% Title Italian=Installazione di %APPTITLE% Width=271 Height=224 Font Name=Helv Font Size=8 item: Push Button Rectangle=150 187 195 202 Variable=DIRECTION Value=N Create Flags=01010000000000010000000000000001 Text=&Finish Text French=&Fin Text German=&Weiter Text Spanish=&Terminar Text Italian=&Fine end item: Push Button Rectangle=105 187 150 202 Variable=DISABLED Value=! Create Flags=01010000000000010000000000000000 Text=< &Back Text French=< &Retour Text German=< &ZurУЏТПТНck Text Spanish=< &AtrУЏТПТНs Text Italian=< &Indietro end item: Push Button Rectangle=211 187 256 202 Variable=DISABLED Value=! Action=3 Create Flags=01010000000000010000000000000000 Text=&Cancel Text French=&Annuler Text German=&Abbrechen Text Spanish=&Cancelar Text Italian=&Annulla end item: Static Rectangle=8 180 256 181 Action=3 Create Flags=01010000000000000000000000000111 end item: Static Rectangle=86 8 258 42 Create Flags=01010000000000000000000000000000 Flags=0000000000000001 Name=Times New Roman Font Style=-24 0 0 0 700 255 0 0 0 3 2 1 18 Text=Installation Completed! Text French=Installation terminУЏТПТНe ! Text German=Die Installation ist abgeschlossen! Text Spanish=УЏТПТНInstalaciУЏТПТНn terminada! Text Italian=Installazione completata! end item: Static Rectangle=86 42 256 153 Create Flags=01010000000000000000000000000000 Text=%APPTITLE% has been successfully installed. Text= Text=Click the Finish button to exit this installation. Text= Text=You can learn more about Tcl/Tk %VER%, including release notes, updates, tutorials, and more at %URL%. Check the box below to start your web browser and go there now. Text= Text=The installer may ask you to reboot your computer, this is to update your PATH and is not necessary to do immediately. Text French=%APPTITLE% est maintenant installУЏТПТН. Text French= Text French=Cliquez sur le bouton Fin pour quitter l'installation. Text German=%APPTITLE% wurde erfolgreich installiert. Text German= Text German=Klicken Sie auf "Weiter", um die Installation zu beenden. Text Spanish=%APPTITLE% se ha instalado con УЏТПТНxito. Text Spanish= Text Spanish=Presione el botУЏТПТНn Terminar para salir de esta instalaciУЏТПТНn. Text Italian=L'installazione %APPTITLE% УЏТПТН stata portata a termine con successo. Text Italian= Text Italian=Premere il pulsante Fine per uscire dall'installazione. end item: Checkbox Rectangle=88 143 245 157 Variable=TO_SCRIPTICS Enabled Color=00000000000000001111111111111111 Create Flags=01010000000000010000000000000011 Text=Show me important information about Text= end item: Static Rectangle=99 156 245 170 Enabled Color=00000000000000001111111111111111 Create Flags=01010000000000000000000000000000 Text=Tcl/Tk %VER% and TclPro end end end item: End Block end item: Check Configuration Flags=10111011 end item: If/While Statement Variable=TO_SCRIPTICS Value=A Flags=00000010 end item: Execute Program Command Line=%URL% end item: End Block end item: Execute Program Pathname=explorer Command Line=%GROUP% end item: End Block end tcl8.4.20/tools/uniParse.tcl0000644003604700454610000002461611737050675014363 0ustar dgp771div# uniParse.tcl -- # # This program parses the UnicodeData file and generates the # corresponding tclUniData.c file with compressed character # data tables. The input to this program should be the latest # UnicodeData file from: # ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt # # Copyright (c) 1998-1999 by Scriptics Corporation. # All rights reserved. namespace eval uni { set shift 5; # number of bits of data within a page # This value can be adjusted to find the # best split to minimize table size variable pMap; # map from page to page index, each entry is # an index into the pages table, indexed by # page number variable pages; # map from page index to page info, each # entry is a list of indices into the groups # table, the list is indexed by the offset variable groups; # list of character info values, indexed by # group number, initialized with the # unassigned character group variable categories { Cn Lu Ll Lt Lm Lo Mn Me Mc Nd Nl No Zs Zl Zp Cc Cf Co Cs Pc Pd Ps Pe Pi Pf Po Sm Sc Sk So }; # Ordered list of character categories, must # match the enumeration in the header file. } proc uni::getValue {items index} { variable categories # Extract character info set category [lindex $items 2] if {[scan [lindex $items 12] %x toupper] == 1} { set toupper [expr {$index - $toupper}] } else { set toupper 0 } if {[scan [lindex $items 13] %x tolower] == 1} { set tolower [expr {$tolower - $index}] } else { set tolower 0 } if {[scan [lindex $items 14] %x totitle] == 1} { set totitle [expr {$index - $totitle}] } elseif {$tolower} { set totitle 0 } else { set totitle $toupper } set categoryIndex [lsearch -exact $categories $category] if {$categoryIndex < 0} { error "Unexpected character category: $index($category)" } return [list $categoryIndex $toupper $tolower $totitle] } proc uni::getGroup {value} { variable groups set gIndex [lsearch -exact $groups $value] if {$gIndex == -1} { set gIndex [llength $groups] lappend groups $value } return $gIndex } proc uni::addPage {info} { variable pMap variable pages variable shift set pIndex [lsearch -exact $pages $info] if {$pIndex == -1} { set pIndex [llength $pages] lappend pages $info } lappend pMap [expr {$pIndex << $shift}] return } proc uni::buildTables {data} { variable shift variable pMap {} variable pages {} variable groups {{0 0 0 0}} variable next 0 set info {} ;# temporary page info set mask [expr {(1 << $shift) - 1}] foreach line [split $data \n] { if {$line eq ""} { if {!($next & $mask)} { # next character is already on page boundary continue } # fill remaining page set line [format %X [expr {($next-1)|$mask}]] append line ";;Cn;0;ON;;;;;N;;;;;\n" } set items [split $line \;] scan [lindex $items 0] %x index if {$index > 0x2ffff} then { # Ignore non-BMP characters, as long as Tcl doesn't support them continue } set index [format %d $index] set gIndex [getGroup [getValue $items $index]] # Since the input table omits unassigned characters, these will # show up as gaps in the index sequence. There are a few special cases # where the gaps correspond to a uniform block of assigned characters. # These are indicated as such in the character name. # Enter all unassigned characters up to the current character. if {($index > $next) \ && ![regexp "Last>$" [lindex $items 1]]} { for {} {$next < $index} {incr next} { lappend info 0 if {($next & $mask) == $mask} { addPage $info set info {} } } } # Enter all assigned characters up to the current character for {set i $next} {$i <= $index} {incr i} { # Add the group index to the info for the current page lappend info $gIndex # If this is the last entry in the page, add the page if {($i & $mask) == $mask} { addPage $info set info {} } } set next [expr {$index + 1}] } return } proc uni::main {} { global argc argv0 argv variable pMap variable pages variable groups variable shift variable next if {$argc != 2} { puts stderr "\nusage: $argv0 \n" exit 1 } set f [open [lindex $argv 0] r] set data [read $f] close $f buildTables $data puts "X = [llength $pMap] Y= [llength $pages] A= [llength $groups]" set size [expr {[llength $pMap]*2 + ([llength $pages]<<$shift)}] puts "shift = $shift, space = $size" set f [open [file join [lindex $argv 1] tclUniData.c] w] fconfigure $f -translation lf puts $f "/* * tclUniData.c -- * * Declarations of Unicode character information tables. This file is * automatically generated by the tools/uniParse.tcl script. Do not * modify this file by hand. * * Copyright (c) 1998 by Scriptics Corporation. * All rights reserved. */ /* * A 16-bit Unicode character is split into two parts in order to index * into the following tables. The lower OFFSET_BITS comprise an offset * into a page of characters. The upper bits comprise the page number. */ #define OFFSET_BITS $shift /* * The pageMap is indexed by page number and returns an alternate page number * that identifies a unique page of characters. Many Unicode characters map * to the same alternate page number. */ static CONST unsigned short pageMap\[\] = {" set line " " set last [expr {[llength $pMap] - 1}] for {set i 0} {$i <= $last} {incr i} { if {$i == [expr {0x10000 >> $shift}]} { set line [string trimright $line " \t,"] puts $f $line set lastpage [expr {[lindex $line end] >> $shift}] puts stdout "lastpage: $lastpage" puts $f "#if TCL_UTF_MAX > 3" set line " ," } append line [lindex $pMap $i] if {$i != $last} { append line ", " } if {[string length $line] > 70} { puts $f [string trimright $line] set line " " } } puts $f $line puts $f "#endif /* TCL_UTF_MAX > 3 */" puts $f "}; /* * The groupMap is indexed by combining the alternate page number with * the page offset and returns a group number that identifies a unique * set of character attributes. */ static CONST unsigned char groupMap\[\] = {" set line " " set lasti [expr {[llength $pages] - 1}] for {set i 0} {$i <= $lasti} {incr i} { set page [lindex $pages $i] set lastj [expr {[llength $page] - 1}] if {$i == ($lastpage + 1)} { puts $f [string trimright $line " \t,"] puts $f "#if TCL_UTF_MAX > 3" set line " ," } for {set j 0} {$j <= $lastj} {incr j} { append line [lindex $page $j] if {$j != $lastj || $i != $lasti} { append line ", " } if {[string length $line] > 70} { puts $f [string trimright $line] set line " " } } } puts $f $line puts $f "#endif /* TCL_UTF_MAX > 3 */" puts $f "}; /* * Each group represents a unique set of character attributes. The attributes * are encoded into a 32-bit value as follows: * * Bits 0-4 Character category: see the constants listed below. * * Bits 5-7 Case delta type: 000 = identity * 010 = add delta for lower * 011 = add delta for lower, add 1 for title * 100 = subtract delta for title/upper * 101 = sub delta for upper, sub 1 for title * 110 = sub delta for upper, add delta for lower * * Bits 8-31 Case delta: delta for case conversions. This should be the * highest field so we can easily sign extend. */ static CONST int groups\[\] = {" set line " " set last [expr {[llength $groups] - 1}] for {set i 0} {$i <= $last} {incr i} { foreach {type toupper tolower totitle} [lindex $groups $i] {} # Compute the case conversion type and delta if {$totitle} { if {$totitle == $toupper} { # subtract delta for title or upper set case 4 set delta $toupper if {$tolower} { error "New case conversion type needed: $toupper $tolower $totitle" } } elseif {$toupper} { # subtract delta for upper, subtract 1 for title set case 5 set delta $toupper if {($totitle != 1) || $tolower} { error "New case conversion type needed: $toupper $tolower $totitle" } } else { # add delta for lower, add 1 for title set case 3 set delta $tolower if {$totitle != -1} { error "New case conversion type needed: $toupper $tolower $totitle" } } } elseif {$toupper} { # subtract delta for upper, add delta for lower set case 6 set delta $toupper if {$tolower != $toupper} { error "New case conversion type needed: $toupper $tolower $totitle" } } elseif {$tolower} { # add delta for lower set case 2 set delta $tolower } else { # noop set case 0 set delta 0 } append line [expr {($delta << 8) | ($case << 5) | $type}] if {$i != $last} { append line ", " } if {[string length $line] > 65} { puts $f [string trimright $line] set line " " } } puts $f $line puts -nonewline $f "}; #if TCL_UTF_MAX > 3 # define UNICODE_OUT_OF_RANGE(ch) (((ch) & 0x1fffff) >= [format 0x%x $next]) #else # define UNICODE_OUT_OF_RANGE(ch) (((ch) & 0x1f0000) != 0) #endif /* * The following constants are used to determine the category of a * Unicode character. */ enum { UNASSIGNED, UPPERCASE_LETTER, LOWERCASE_LETTER, TITLECASE_LETTER, MODIFIER_LETTER, OTHER_LETTER, NON_SPACING_MARK, ENCLOSING_MARK, COMBINING_SPACING_MARK, DECIMAL_DIGIT_NUMBER, LETTER_NUMBER, OTHER_NUMBER, SPACE_SEPARATOR, LINE_SEPARATOR, PARAGRAPH_SEPARATOR, CONTROL, FORMAT, PRIVATE_USE, SURROGATE, CONNECTOR_PUNCTUATION, DASH_PUNCTUATION, OPEN_PUNCTUATION, CLOSE_PUNCTUATION, INITIAL_QUOTE_PUNCTUATION, FINAL_QUOTE_PUNCTUATION, OTHER_PUNCTUATION, MATH_SYMBOL, CURRENCY_SYMBOL, MODIFIER_SYMBOL, OTHER_SYMBOL }; /* * The following macros extract the fields of the character info. The * GetDelta() macro is complicated because we can't rely on the C compiler * to do sign extension on right shifts. */ #define GetCaseType(info) (((info) & 0xe0) >> 5) #define GetCategory(ch) (GetUniCharInfo(ch) & 0x1f) #define GetDelta(info) ((info) >> 8) /* * This macro extracts the information about a character from the * Unicode character tables. */ #define GetUniCharInfo(ch) (groups\[groupMap\[pageMap\[((ch) & 0xffff) >> OFFSET_BITS\] | ((ch) & ((1 << OFFSET_BITS)-1))\]\]) " close $f } uni::main return tcl8.4.20/tools/man2help2.tcl0000644003604700454610000004674311737050675014372 0ustar dgp771div# man2help2.tcl -- # # This file defines procedures that are used during the second pass of # the man page conversion. It converts the man format input to rtf # form suitable for use by the Windows help compiler. # # Copyright (c) 1996 by Sun Microsystems, Inc. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # Global variables used by these scripts: # # state - state variable that controls action of text proc. # # topics - array indexed by (package,section,topic) with value # of topic ID. # # keywords - array indexed by keyword string with value of topic ID. # # curID - current topic ID, starts at 0 and is incremented for # each new topic file. # # curPkg - current package name (e.g. Tcl). # # curSect - current section title (e.g. "Tcl Built-In Commands"). # # initGlobals -- # # This procedure is invoked to set the initial values of all of the # global variables, before processing a man page. # # Arguments: # None. proc initGlobals {} { uplevel \#0 unset state global state chars set state(paragraphPending) 0 set state(breakPending) 0 set state(firstIndent) 0 set state(leftIndent) 0 set state(inTP) 0 set state(paragraph) 0 set state(textState) 0 set state(curFont) "" set state(startCode) "{\\b " set state(startEmphasis) "{\\i " set state(endCode) "}" set state(endEmphasis) "}" set state(noFill) 0 set state(charCnt) 0 set state(offset) [getTwips 0.5i] set state(leftMargin) [getTwips 0.5i] set state(nestingLevel) 0 set state(intl) 0 set state(sb) 0 setTabs 0.5i # set up international character table array set chars { o^ F4 } } # beginFont -- # # Arranges for future text to use a special font, rather than # the default paragraph font. # # Arguments: # font - Name of new font to use. proc beginFont {font} { global file state textSetup if {[string equal $state(curFont) $font]} { return } endFont puts -nonewline $file $state(start$font) set state(curFont) $font } # endFont -- # # Reverts to the default font for the paragraph type. # # Arguments: # None. proc endFont {} { global state file if {[string compare $state(curFont) ""]} { puts -nonewline $file $state(end$state(curFont)) set state(curFont) "" } } # textSetup -- # # This procedure is called the first time that text is output for a # paragraph. It outputs the header information for the paragraph. # # Arguments: # None. proc textSetup {} { global file state if $state(breakPending) { puts $file "\\line" } if $state(paragraphPending) { puts $file [format "\\par\n\\pard\\fi%.0f\\li%.0f" \ $state(firstIndent) $state(leftIndent)] foreach tab $state(tabs) { puts $file [format "\\tx%.0f" $tab] } set state(tabs) {} if {$state(sb)} { puts $file "\\sb$state(sb)" set state(sb) 0 } } set state(breakPending) 0 set state(paragraphPending) 0 } # text -- # # This procedure adds text to the current state(paragraph). If this is # the first text in the state(paragraph) then header information for the # state(paragraph) is output before the text. # # Arguments: # string - Text to output in the state(paragraph). proc text {string} { global file state chars textSetup set string [string map [list \ "\\" "\\\\" \ "\{" "\\\{" \ "\}" "\\\}" \ "\t" {\tab } \ '' "\\rdblquote " \ `` "\\ldblquote " \ ] $string] # Check if this is the beginning of an international character string. # If so, look up the sequence in the chars table and substitute the # appropriate hex value. if {$state(intl)} { if {[regexp {^'([^']*)'} $string dummy ch]} { if {[info exists chars($ch)]} { regsub {^'[^']*'} $string "\\\\'$chars($ch)" string } else { puts stderr "Unknown international character '$ch'" } } set state(intl) 0 } switch $state(textState) { REF { if {$state(inTP) == 0} { set string [insertRef $string] } } SEE { global topics curPkg curSect foreach i [split $string] { if {![regexp -nocase {^[a-z_0-9]+} [string trim $i] i ]} { continue } if {![catch {set ref $topics($curPkg,$curSect,$i)} ]} { regsub $i $string [link $i $ref] string } } } KEY { return } } puts -nonewline $file "$string" } # insertRef -- # # This procedure looks for a string in the cross reference table and # generates a hot-link to the appropriate topic. Tries to find the # nearest reference in the manual. # # Arguments: # string - Text to output in the state(paragraph). proc insertRef {string} { global NAME_file curPkg curSect topics curID set path {} set string [string trim $string] set ref {} if {[info exists topics($curPkg,$curSect,$string)]} { set ref $topics($curPkg,$curSect,$string) } else { set sites [array names topics "$curPkg,*,$string"] set count [llength $sites] if {$count > 0} { set ref $topics([lindex $sites 0]) } else { set sites [array names topics "*,*,$string"] set count [llength $sites] if {$count > 0} { set ref $topics([lindex $sites 0]) } } } if {($ref != {}) && ($ref != $curID)} { set string [link $string $ref] } return $string } # macro -- # # This procedure is invoked to process macro invocations that start # with "." (instead of '). # # Arguments: # name - The name of the macro (without the "."). # args - Any additional arguments to the macro. proc macro {name args} { global state file switch $name { AP { if {[llength $args] != 3 && [llength $args] != 2} { puts stderr "Bad .AP macro: .$name [join $args " "]" } newPara 3.75i -3.75i setTabs {1.25i 2.5i 3.75i} font B text [lindex $args 0] tab font I text [lindex $args 1] tab font R if {[llength $args] == 3} { text "([lindex $args 2])" } tab } AS { # next page and previous page } br { lineBreak } BS {} BE {} CE { puts -nonewline $::file "\\f0\\fs20 " set state(noFill) 0 set state(breakPending) 0 newPara "" set state(leftIndent) [expr {$state(leftIndent) - $state(offset)}] set state(sb) 80 } CS { # code section set state(noFill) 1 newPara "" set state(leftIndent) [expr {$state(leftIndent) + $state(offset)}] set state(sb) 80 puts -nonewline $::file "\\f1\\fs18 " } DE { set state(noFill) 0 decrNestingLevel newPara 0i } DS { set state(noFill) 1 incrNestingLevel newPara 0i } fi { set state(noFill) 0 } IP { IPmacro $args } LP { newPara 0i set state(sb) 80 } ne { } nf { set state(noFill) 1 } OP { if {[llength $args] != 3} { puts stderr "Bad .OP macro: .$name [join $args " "]" } set state(nestingLevel) 0 newPara 0i set state(sb) 120 setTabs 4c text "Command-Line Name:" tab font B set x [lindex $args 0] regsub -all {\\-} $x - x text $x lineBreak font R text "Database Name:" tab font B text [lindex $args 1] lineBreak font R text "Database Class:" tab font B text [lindex $args 2] font R set state(inTP) 0 newPara 0.5i set state(sb) 80 } PP { newPara 0i set state(sb) 120 } RE { decrNestingLevel } RS { incrNestingLevel } SE { font R set state(noFill) 0 set state(nestingLevel) 0 newPara 0i text "See the " font B set temp $state(textState) set state(textState) REF text options set state(textState) $temp font R text " manual entry for detailed descriptions of the above options." } SH { SHmacro $args } SO { SHmacro "STANDARD OPTIONS" set state(nestingLevel) 0 newPara 0i setTabs {4c 8c 12c} font B set state(noFill) 1 } so { if {$args != "man.macros"} { puts stderr "Unknown macro: .$name [join $args " "]" } } sp { ;# needs work if {$args == ""} { set count 1 } else { set count [lindex $args 0] } while {$count > 0} { lineBreak incr count -1 } } ta { setTabs $args } TH { THmacro $args } TP { TPmacro $args } UL { ;# underline puts -nonewline $file "{\\ul " text [lindex $args 0] puts -nonewline $file "}" if {[llength $args] == 2} { text [lindex $args 1] } } VE {} VS {} default { puts stderr "Unknown macro: .$name [join $args " "]" } } } # link -- # # This procedure returns the string for a hot link to a different # context location. # # Arguments: # label - String to display in hot-spot. # id - Context string to jump to. proc link {label id} { return "{\\uldb $label}{\\v $id}" } # font -- # # This procedure is invoked to handle font changes in the text # being output. # # Arguments: # type - Type of font: R, I, B, or S. proc font {type} { global state switch $type { P - R { endFont if {$state(textState) == "REF"} { set state(textState) INSERT } } C - B { beginFont Code if {$state(textState) == "INSERT"} { set state(textState) REF } } I { beginFont Emphasis } S { } default { puts stderr "Unknown font: $type" } } } # formattedText -- # # Insert a text string that may also have \fB-style font changes # and a few other backslash sequences in it. # # Arguments: # text - Text to insert. proc formattedText {text} { global chars while {$text != ""} { set index [string first \\ $text] if {$index < 0} { text $text return } text [string range $text 0 [expr {$index-1}]] set c [string index $text [expr {$index+1}]] switch -- $c { f { font [string index $text [expr {$index+2}]] set text [string range $text [expr {$index+3}] end] } e { text "\\" set text [string range $text [expr {$index+2}] end] } - { dash set text [string range $text [expr {$index+2}] end] } | { set text [string range $text [expr {$index+2}] end] } o { text "\\'" regexp {'([^']*)'(.*)} $text all ch text text $chars($ch) } default { puts stderr "Unknown sequence: \\$c" set text [string range $text [expr {$index+2}] end] } } } } # dash -- # # This procedure is invoked to handle dash characters ("\-" in # troff). It outputs a special dash character. # # Arguments: # None. proc dash {} { global state if {[string equal $state(textState) "NAME"]} { set state(textState) 0 } text "-" } # tab -- # # This procedure is invoked to handle tabs in the troff input. # Right now it does nothing. # # Arguments: # None. proc tab {} { global file textSetup puts -nonewline $file "\\tab " } # setTabs -- # # This procedure handles the ".ta" macro, which sets tab stops. # # Arguments: # tabList - List of tab stops, each consisting of a number # followed by "i" (inch) or "c" (cm). proc setTabs {tabList} { global file state set state(tabs) {} foreach arg $tabList { set distance [expr {$state(leftMargin) \ + ($state(offset) * $state(nestingLevel)) + [getTwips $arg]}] lappend state(tabs) [expr {round($distance)}] } } # lineBreak -- # # Generates a line break in the HTML output. # # Arguments: # None. proc lineBreak {} { global state textSetup set state(breakPending) 1 } # newline -- # # This procedure is invoked to handle newlines in the troff input. # It outputs either a space character or a newline character, depending # on fill mode. # # Arguments: # None. proc newline {} { global state if {$state(inTP)} { set state(inTP) 0 lineBreak } elseif {$state(noFill)} { lineBreak } else { text " " } } # pageBreak -- # # This procedure is invoked to generate a page break. # # Arguments: # None. proc pageBreak {} { global file curVer if {[string equal $curVer ""]} { puts $file {\page} } else { puts $file {\par} puts $file {\pard\sb400\qc} puts $file "Last change: $curVer\\page" } } # char -- # # This procedure is called to handle a special character. # # Arguments: # name - Special character named in troff \x or \(xx construct. proc char {name} { global file state switch -exact $name { \\o { set state(intl) 1 } \\\ { textSetup puts -nonewline $file " " } \\0 { textSetup puts -nonewline $file " \\emspace " } \\\\ { textSetup puts -nonewline $file "\\\\" } \\(+- { textSetup puts -nonewline $file "\\'b1 " } \\% - \\| { } \\(bu { textSetup puts -nonewline $file "З" } default { puts stderr "Unknown character: $name" } } } # macro2 -- # # This procedure handles macros that are invoked with a leading "'" # character instead of space. Right now it just generates an # error diagnostic. # # Arguments: # name - The name of the macro (without the "."). # args - Any additional arguments to the macro. proc macro2 {name args} { puts stderr "Unknown macro: '$name [join $args " "]" } # SHmacro -- # # Subsection head; handles the .SH macro. # # Arguments: # name - Section name. proc SHmacro {argList} { global file state set args [join $argList " "] if {[llength $argList] < 1} { puts stderr "Bad .SH macro: .SH $args" } # control what the text proc does with text switch $args { NAME {set state(textState) NAME} DESCRIPTION {set state(textState) INSERT} INTRODUCTION {set state(textState) INSERT} "WIDGET-SPECIFIC OPTIONS" {set state(textState) INSERT} "SEE ALSO" {set state(textState) SEE} KEYWORDS {set state(textState) KEY; return} } if {$state(breakPending) != -1} { set state(breakPending) 1 } else { set state(breakPending) 0 } set state(noFill) 0 nextPara 0i font B text $args font R nextPara .5i } # IPmacro -- # # This procedure is invoked to handle ".IP" macros, which may take any # of the following forms: # # .IP [1] Translate to a "1Step" state(paragraph). # .IP [x] (x > 1) Translate to a "Step" state(paragraph). # .IP Translate to a "Bullet" state(paragraph). # .IP text count Translate to a FirstBody state(paragraph) with special # indent and tab stop based on "count", and tab after # "text". # # Arguments: # argList - List of arguments to the .IP macro. # # HTML limitations: 'count' in '.IP text count' is ignored. proc IPmacro {argList} { global file state set length [llength $argList] if {$length == 0} { newPara 0.5i return } if {$length == 1} { newPara 0.5i -0.5i set state(sb) 80 setTabs 0.5i formattedText [lindex $argList 0] tab return } if {$length == 2} { set count [lindex $argList 1] set tab [expr $count * 0.1]i newPara $tab -$tab set state(sb) 80 setTabs $tab formattedText [lindex $argList 0] tab return } puts stderr "Bad .IP macro: .IP [join $argList " "]" } # TPmacro -- # # This procedure is invoked to handle ".TP" macros, which may take any # of the following forms: # # .TP x Translate to an state(indent)ed state(paragraph) with the # specified state(indent) (in 100 twip units). # .TP Translate to an state(indent)ed state(paragraph) with # default state(indent). # # Arguments: # argList - List of arguments to the .IP macro. # # HTML limitations: 'x' in '.TP x' is ignored. proc TPmacro {argList} { global state set length [llength $argList] if {$length == 0} { set val 0.5i } else { set val [expr {([lindex $argList 0] * 100.0)/1440}]i } newPara $val -$val setTabs $val set state(inTP) 1 set state(sb) 120 } # THmacro -- # # This procedure handles the .TH macro. It generates the non-scrolling # header section for a given man page, and enters information into the # table of contents. The .TH macro has the following form: # # .TH name section date footer header # # Arguments: # argList - List of arguments to the .TH macro. proc THmacro {argList} { global file curPkg curSect curID id_keywords state curVer bitmap if {[llength $argList] != 5} { set args [join $argList " "] puts stderr "Bad .TH macro: .TH $args" } incr curID set name [lindex $argList 0] ;# Tcl_UpVar set page [lindex $argList 1] ;# 3 set curVer [lindex $argList 2] ;# 7.4 set curPkg [lindex $argList 3] ;# Tcl set curSect [lindex $argList 4] ;# {Tcl Library Procedures} regsub -all {\\ } $curSect { } curSect ;# Clean up for [incr\ Tcl] puts $file "#{\\footnote $curID}" ;# Context string puts $file "\${\\footnote $name}" ;# Topic title set browse "${curSect}${name}" regsub -all {[ _-]} $browse {} browse puts $file "+{\\footnote $browse}" ;# Browse sequence # Suppress duplicates foreach i $id_keywords($curID) { set keys($i) 1 } foreach i [array names keys] { set i [string trim $i] if {[string length $i] > 0} { puts $file "K{\\footnote $i}" ;# Keyword strings } } unset keys puts $file "\\pard\\tx3000\\sb100\\sa100\\fs24\\keepn" font B text $name tab text $curSect font R if {[info exists bitmap]} { # a right justified bitmap puts $file "\\\{bmrt $bitmap\\\}" } puts $file "\\fs20" set state(breakPending) -1 } # nextPara -- # # Set the indents for a new paragraph, and start a paragraph break # # Arguments: # leftIndent - The new left margin for body lines. # firstIndent - The offset from the left margin for the first line. proc nextPara {leftIndent {firstIndent 0i}} { global state set state(leftIndent) [getTwips $leftIndent] set state(firstIndent) [getTwips $firstIndent] set state(paragraphPending) 1 } # newPara -- # # This procedure sets the left and hanging state(indent)s for a line. # State(Indent)s are specified in units of inches or centimeters, and are # relative to the current nesting level and left margin. # # Arguments: # leftState(Indent) - The new left margin for lines after the first. # firstState(Indent) - The new left margin for the first line of a state(paragraph). proc newPara {leftIndent {firstIndent 0i}} { global state file if $state(paragraph) { puts -nonewline $file "\\line\n" } if {$leftIndent != ""} { set state(leftIndent) [expr {$state(leftMargin) \ + ($state(offset) * $state(nestingLevel)) \ + [getTwips $leftIndent]}] } set state(firstIndent) [getTwips $firstIndent] set state(paragraphPending) 1 } # getTwips -- # # This procedure converts a distance in inches or centimeters into # twips (1/1440 of an inch). # # Arguments: # arg - A number followed by "i" or "c" proc getTwips {arg} { if {[scan $arg "%f%s" distance units] != 2} { puts stderr "bad distance \"$arg\"" return 0 } switch -- $units { c { set distance [expr {$distance * 567}] } i { set distance [expr {$distance * 1440}] } default { puts stderr "bad units in distance \"$arg\"" continue } } return $distance } # incrNestingLevel -- # # This procedure does the work of the .RS macro, which increments # the number of state(indent)ations that affect things like .PP. # # Arguments: # None. proc incrNestingLevel {} { global state incr state(nestingLevel) set oldp $state(paragraph) set state(paragraph) 0 newPara 0i set state(paragraph) $oldp } # decrNestingLevel -- # # This procedure does the work of the .RE macro, which decrements # the number of indentations that affect things like .PP. # # Arguments: # None. proc decrNestingLevel {} { global state if {$state(nestingLevel) == 0} { puts stderr "Nesting level decremented below 0" } else { incr state(nestingLevel) -1 } } tcl8.4.20/tools/tcltk-man2html.tcl0000755003604700454610000013617312153117057015432 0ustar dgp771div#!/bin/sh # The next line is executed by /bin/sh, but not tcl \ exec tclsh "$0" ${1+"$@"} package require Tcl 8.4 # Convert Ousterhout format man pages into highly crosslinked # hypertext. # # Along the way detect many unmatched font changes and other odd # things. # # Note well, this program is a hack rather than a piece of software # engineering. In that sense it's probably a good example of things # that a scripting language, like Tcl, can do well. It is offered as # an example of how someone might convert a specific set of man pages # into hypertext, not as a general solution to the problem. If you # try to use this, you'll be very much on your own. # # Copyright (c) 1995-1997 Roger E. Critchlow Jr # # The authors hereby grant permission to use, copy, modify, distribute, # and license this software and its documentation for any purpose, provided # that existing copyright notices are retained in all copies and that this # notice is included verbatim in any distributions. No written agreement, # license, or royalty fee is required for any of the authorized uses. # Modifications to this software may be copyrighted by their authors # and need not follow the licensing terms described here, provided that # the new terms are clearly indicated on the first page of each file where # they apply. # # IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY # FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES # ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY # DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE # IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE # NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR # MODIFICATIONS. # # Revisions: # May 15, 1995 - initial release # May 16, 1995 - added a back to home link to toplevel table of # contents. # May 18, 1995 - broke toplevel table of contents into separate # pages for each section, and broke long table of contents # into a one page for each man page. # Mar 10, 1996 - updated for tcl7.5b3/tk4.1b3 # Apr 14, 1996 - incorporated command line parsing from Tom Tromey, # -- thanks Tom. # - updated for tcl7.5/tk4.1 final release. # - converted to same copyright as the man pages. # Sep 14, 1996 - made various modifications for tcl7.6b1/tk4.2b1 # Oct 18, 1996 - added tcl7.6/tk4.2 to the list of distributions. # Oct 22, 1996 - major hacking on indentation code and elsewhere. # Mar 4, 1997 - # May 28, 1997 - added tcl8.0b1/tk8.0b1 to the list of distributions # - cleaned source for tclsh8.0 execution # - renamed output files for windoze installation # - added spaces to tables # Oct 24, 1997 - moved from 8.0b1 to 8.0 release # set Version "0.32" proc parse_command_line {} { global argv Version # These variables determine where the man pages come from and where # the converted pages go to. global tcltkdir tkdir tcldir webdir build_tcl build_tk # Set defaults based on original code. set tcltkdir ../.. set tkdir {} set tcldir {} set webdir ../html set build_tcl 0 set build_tk 0 # Default search version is a glob pattern set useversion {{,[8-9].[0-9]{,.[0-9]{,[0-9]}}}} # Handle arguments a la GNU: # --version # --useversion= # --help # --srcdir=/path # --htmldir=/path foreach option $argv { switch -glob -- $option { --version { puts "tcltk-man-html $Version" exit 0 } --help { puts "usage: tcltk-man-html \[OPTION\] ...\n" puts " --help print this help, then exit" puts " --version print version number, then exit" puts " --srcdir=DIR find tcl and tk source below DIR" puts " --htmldir=DIR put generated HTML in DIR" puts " --tcl build tcl help" puts " --tk build tk help" puts " --useversion version of tcl/tk to search for" exit 0 } --srcdir=* { # length of "--srcdir=" is 9. set tcltkdir [string range $option 9 end] } --htmldir=* { # length of "--htmldir=" is 10 set webdir [string range $option 10 end] } --useversion=* { # length of "--useversion=" is 13 set useversion [string range $option 13 end] } --tcl { set build_tcl 1 } --tk { set build_tk 1 } default { puts stderr "tcltk-man-html: unrecognized option -- `$option'" exit 1 } } } if {!$build_tcl && !$build_tk} {set build_tcl 1; set build_tk 1} if {$build_tcl} { # Find Tcl. set tcldir [lindex [lsort [glob -nocomplain -tails -type d \ -directory $tcltkdir tcl$useversion]] end] if {$tcldir == ""} then { puts stderr "tcltk-man-html: couldn't find Tcl below $tcltkdir" exit 1 } puts "using Tcl source directory $tcldir" } if {$build_tk} { # Find Tk. set tkdir [lindex [lsort [glob -nocomplain -tails -type d \ -directory $tcltkdir tk$useversion]] end] if {$tkdir == ""} then { puts stderr "tcltk-man-html: couldn't find Tk below $tcltkdir" exit 1 } puts "using Tk source directory $tkdir" } # the title for the man pages overall global overall_title set overall_title "" if {$build_tcl} {append overall_title "[capitalize $tcldir]"} if {$build_tcl && $build_tk} {append overall_title "/"} if {$build_tk} {append overall_title "[capitalize $tkdir]"} append overall_title " Manual" } proc capitalize {string} { return [string toupper $string 0] } ## ## ## set manual(report-level) 1 proc manerror {msg} { global manual set name {} set subj {} if {[info exists manual(name)]} { set name $manual(name) } if {[info exists manual(section)] && [string length $manual(section)]} { puts stderr "$name: $manual(section): $msg" } else { puts stderr "$name: $msg" } } proc manreport {level msg} { global manual if {$level < $manual(report-level)} { manerror $msg } } proc fatal {msg} { global manual manerror $msg exit 1 } ## ## parsing ## proc unquote arg { return [string map [list \" {}] $arg] } proc parse-directive {line codename restname} { upvar $codename code $restname rest return [regexp {^(\.[.a-zA-Z0-9]*) *(.*)} $line all code rest] } proc process-text {text} { global manual # preprocess text set text [string map [list \ {\&} "\t" \ {&} {&} \ {\\} {\} \ {\e} {\} \ {\ } { } \ {\|} { } \ {\0} { } \ {\%} {} \ "\\\n" "\n" \ \" {"} \ {<} {<} \ {>} {>} \ {\(+-} {±} \ {\fP} {\fR} \ {\.} . \ {\(bu} {•} \ ] $text] regsub -all {\\o'o\^'} $text {\ô} text; # o-circumflex in re_syntax.n regsub -all {\\-\\\|\\-} $text -- text; # two hyphens regsub -all -- {\\-\\\^\\-} $text -- text; # two hyphens regsub -all {\\-} $text - text; # a hyphen regsub -all "\\\\\n" $text "\\\\n" text; # backslashed newline while {[string first "\\" $text] >= 0} { # C R if {[regsub {^([^\\]*)\\fC([^\\]*)\\fR(.*)$} $text \ {\1\2\3} text]} continue # B R if {[regsub {^([^\\]*)\\fB([^\\]*)\\fR(.*)$} $text \ {\1\2\3} text]} continue # B I if {[regsub {^([^\\]*)\\fB([^\\]*)\\fI(.*)$} $text \ {\1\2\\fI\3} text]} continue # I R if {[regsub {^([^\\]*)\\fI([^\\]*)\\fR(.*)$} $text \ {\1\2\3} text]} continue # I B if {[regsub {^([^\\]*)\\fI([^\\]*)\\fB(.*)$} $text \ {\1\2\\fB\3} text]} continue # B B, I I, R R if {[regsub {^([^\\]*)\\fB([^\\]*)\\fB(.*)$} $text \ {\1\\fB\2\3} ntext] || [regsub {^([^\\]*)\\fI([^\\]*)\\fI(.*)$} $text \ {\1\\fI\2\3} ntext] || [regsub {^([^\\]*)\\fR([^\\]*)\\fR(.*)$} $text \ {\1\\fR\2\3} ntext]} { manerror "process-text: impotent font change: $text" set text $ntext continue } # unrecognized manerror "process-text: uncaught backslash: $text" set text [string map [list "\\" "#92;"] $text] } return $text } ## ## pass 2 text input and matching ## proc open-text {} { global manual set manual(text-length) [llength $manual(text)] set manual(text-pointer) 0 } proc more-text {} { global manual return [expr {$manual(text-pointer) < $manual(text-length)}] } proc next-text {} { global manual if {[more-text]} { set text [lindex $manual(text) $manual(text-pointer)] incr manual(text-pointer) return $text } manerror "read past end of text" error "fatal" } proc is-a-directive {line} { return [string match .* $line] } proc split-directive {line opname restname} { upvar $opname op $restname rest set op [string range $line 0 2] set rest [string trim [string range $line 3 end]] } proc next-op-is {op restname} { global manual upvar $restname rest if {[more-text]} { set text [lindex $manual(text) $manual(text-pointer)] if {[string equal -length 3 $text $op]} { set rest [string range $text 4 end] incr manual(text-pointer) return 1 } } return 0 } proc backup-text {n} { global manual if {$manual(text-pointer)-$n >= 0} { incr manual(text-pointer) -$n } } proc match-text args { global manual set nargs [llength $args] if {$manual(text-pointer) + $nargs > $manual(text-length)} { return 0 } set nback 0 foreach arg $args { if {![more-text]} { backup-text $nback return 0 } set arg [string trim $arg] set targ [string trim [lindex $manual(text) $manual(text-pointer)]] if {[string equal $arg $targ]} { incr nback incr manual(text-pointer) continue } if {[regexp {^@(\w+)$} $arg all name]} { upvar $name var set var $targ incr nback incr manual(text-pointer) continue } if {[regexp -nocase {^(\.[A-Z][A-Z])@(\w+)$} $arg all op name]\ && [string equal $op [lindex $targ 0]]} { upvar $name var set var [lrange $targ 1 end] incr nback incr manual(text-pointer) continue } backup-text $nback return 0 } return 1 } proc expand-next-text {n} { global manual return [join [lrange $manual(text) $manual(text-pointer) \ [expr {$manual(text-pointer)+$n-1}]] \n\n] } ## ## pass 2 output ## proc man-puts {text} { global manual lappend manual(output-$manual(wing-file)-$manual(name)) $text } ## ## build hypertext links to tables of contents ## proc long-toc {text} { global manual set here M[incr manual(section-toc-n)] set there L[incr manual(long-toc-n)] lappend manual(section-toc) \ "

$text" return "$text" } proc option-toc {name class switch} { global manual if {[string equal $manual(section) "WIDGET-SPECIFIC OPTIONS"]} { # link the defined option into the long table of contents set link [long-toc "$switch, $name, $class"] regsub -- "$switch, $name, $class" $link "$switch" link return $link } elseif {[string equal $manual(name):$manual(section) \ "options:DESCRIPTION"]} { # link the defined standard option to the long table of # contents and make a target for the standard option references # from other man pages. set first [lindex $switch 0] set here M$first set there L[incr manual(long-toc-n)] set manual(standard-option-$first) "$switch, $name, $class" lappend manual(section-toc) "
$switch, $name, $class" return "$switch" } else { error "option-toc in $manual(name) section $manual(section)" } } proc std-option-toc {name} { global manual if {[info exists manual(standard-option-$name)]} { lappend manual(section-toc)
$manual(standard-option-$name) return $manual(standard-option-$name) } set here M[incr manual(section-toc-n)] set there L[incr manual(long-toc-n)] set other M$name lappend manual(section-toc) "
$name" return "$name" } ## ## process the widget option section ## in widget and options man pages ## proc output-widget-options {rest} { global manual man-puts
lappend manual(section-toc)
backup-text 1 set para {} while {[next-op-is .OP rest]} { switch -exact [llength $rest] { 3 { foreach {switch name class} $rest { break } } 5 { set switch [lrange $rest 0 2] set name [lindex $rest 3] set class [lindex $rest 4] } default { fatal "bad .OP $rest" } } if {![regexp {^(<.>)([-\w ]+)()$} $switch all oswitch switch cswitch]} { if {![regexp {^(<.>)([-\w ]+) or ([-\w ]+)()$} $switch all oswitch switch1 switch2 cswitch]} { error "not Switch: $switch" } else { set switch "$switch1$cswitch or $oswitch$switch2" } } if {![regexp {^(<.>)([\w]*)()$} $name all oname name cname]} { error "not Name: $name" } if {![regexp {^(<.>)([\w]*)()$} $class all oclass class cclass]} { error "not Class: $class" } man-puts "$para
Command-Line Name: $oswitch[option-toc $name $class $switch]$cswitch" man-puts "
Database Name: $oname$name$cname" man-puts "
Database Class: $oclass$class$cclass" man-puts
[next-text] set para

} man-puts

lappend manual(section-toc)
} ## ## process .RS lists ## proc output-RS-list {} { global manual if {[next-op-is .IP rest]} { output-IP-list .RS .IP $rest if {[match-text .RE .sp .RS @rest .IP @rest2]} { man-puts

$rest output-IP-list .RS .IP $rest2 } if {[match-text .RE .sp .RS @rest .RE]} { man-puts

$rest return } if {[next-op-is .RE rest]} { return } } man-puts

while {[more-text]} { set line [next-text] if {[is-a-directive $line]} { split-directive $line code rest switch -exact $code { .RE { break } .SH - .SS { manerror "unbalanced .RS at section end" backup-text 1 break } default { output-directive $line } } } else { man-puts $line } } man-puts
} ## ## process .IP lists which may be plain indents, ## numeric lists, or definition lists ## proc output-IP-list {context code rest} { global manual if {![string length $rest]} { # blank label, plain indent, no contents entry man-puts
while {[more-text]} { set line [next-text] if {[is-a-directive $line]} { split-directive $line code rest if {[string equal $code ".IP"] && [string equal $rest {}]} { man-puts "

" continue } if {[lsearch {.br .DS .RS} $code] >= 0} { output-directive $line } else { backup-text 1 break } } else { man-puts $line } } man-puts

} else { # labelled list, make contents if { [string compare $context ".SH"] && [string compare $context ".SS"] } then { man-puts

} man-puts

lappend manual(section-toc)
backup-text 1 set accept_RE 0 set para {} while {[more-text]} { set line [next-text] if {[is-a-directive $line]} { split-directive $line code rest switch -exact $code { .IP { if {$accept_RE} { output-IP-list .IP $code $rest continue } if {[string equal $manual(section) "ARGUMENTS"] || \ [regexp {^\[\d+\]$} $rest]} { man-puts "$para
$rest
" } elseif {[string equal {•} $rest]} { man-puts "$para
$rest " } else { man-puts "$para
[long-toc $rest]
" } if {[string equal $manual(name):$manual(section) \ "selection:DESCRIPTION"]} { if {[match-text .RE @rest .RS .RS]} { man-puts
[long-toc $rest]
} } } .sp - .br - .DS - .CS { output-directive $line } .RS { if {[match-text .RS]} { output-directive $line incr accept_RE 1 } elseif {[match-text .CS]} { output-directive .CS incr accept_RE 1 } elseif {[match-text .PP]} { output-directive .PP incr accept_RE 1 } elseif {[match-text .DS]} { output-directive .DS incr accept_RE 1 } else { output-directive $line } } .PP { if {[match-text @rest1 .br @rest2 .RS]} { # yet another nroff kludge as above man-puts "$para
[long-toc $rest1]" man-puts "
[long-toc $rest2]
" incr accept_RE 1 } elseif {[match-text @rest .RE]} { # gad, this is getting ridiculous if {!$accept_RE} { man-puts "

$rest

" backup-text 1 set para {} break } else { man-puts "

$rest" incr accept_RE -1 } } elseif {$accept_RE} { output-directive $line } else { backup-text 1 break } } .RE { if {!$accept_RE} { backup-text 1 break } incr accept_RE -1 } default { backup-text 1 break } } } else { man-puts $line } set para

} man-puts "$para

" lappend manual(section-toc)
if {$accept_RE} { manerror "missing .RE in output-IP-list" } } } ## ## handle the NAME section lines ## there's only one line in the NAME section, ## consisting of a comma separated list of names, ## followed by a hyphen and a short description. ## proc output-name {line} { global manual # split name line into pieces regexp {^([^-]+) - (.*)$} $line all head tail # output line to manual page untouched man-puts $line # output line to long table of contents lappend manual(section-toc)
$line
# separate out the names for future reference foreach name [split $head ,] { set name [string trim $name] if {[llength $name] > 1} { manerror "name has a space: {$name}\nfrom: $line" } lappend manual(wing-toc) $name lappend manual(name-$name) $manual(wing-file)/$manual(name) } } ## ## build a cross-reference link if appropriate ## proc cross-reference {ref} { global manual if {[string match Tcl_* $ref]} { set lref $ref } elseif {[string match Tk_* $ref]} { set lref $ref } elseif {[string equal $ref "Tcl"]} { set lref $ref } else { set lref [string tolower $ref] } ## ## nothing to reference ## if {![info exists manual(name-$lref)]} { foreach name {array file history info interp string trace after clipboard grab image option pack place selection tk tkwait update winfo wm} { if {[regexp "^$name \[a-z0-9]*\$" $lref] && \ [info exists manual(name-$name)] && \ [string compare $manual(tail) "$name.n"]} { return "$ref" } } if {[lsearch {stdin stdout stderr end} $lref] >= 0} { # no good place to send these # tcl tokens? # also end } return $ref } ## ## would be a self reference ## foreach name $manual(name-$lref) { if {[lsearch $name $manual(wing-file)/$manual(name)] >= 0} { return $ref } } ## ## multiple choices for reference ## if {[llength $manual(name-$lref)] > 1} { set tcl_i [lsearch -glob $manual(name-$lref) *TclCmd*] set tcl_ref [lindex $manual(name-$lref) $tcl_i] set tk_i [lsearch -glob $manual(name-$lref) *TkCmd*] set tk_ref [lindex $manual(name-$lref) $tk_i] if {$tcl_i >= 0 && "$manual(wing-file)" == {TclCmd} \ || "$manual(wing-file)" == {TclLib}} { return "$ref" } if {$tk_i >= 0 && "$manual(wing-file)" == {TkCmd} \ || "$manual(wing-file)" == {TkLib}} { return "$ref" } if {"$lref" == {exit} && "$manual(tail)" == {tclsh.1} && $tcl_i >= 0} { return "$ref" } puts stderr "multiple cross reference to $ref in $manual(name-$lref) from $manual(wing-file)/$manual(tail)" return $ref } ## ## exceptions, sigh, to the rule ## switch $manual(tail) { canvas.n { if {$lref == {focus}} { upvar tail tail set clue [string first command $tail] if {$clue < 0 || $clue > 5} { return $ref } } if {[lsearch {bitmap image text} $lref] >= 0} { return $ref } } checkbutton.n - radiobutton.n { if {[lsearch {image} $lref] >= 0} { return $ref } } menu.n { if {[lsearch {checkbutton radiobutton} $lref] >= 0} { return $ref } } options.n { if {[lsearch {bitmap image set} $lref] >= 0} { return $ref } } regexp.n { if {[lsearch {string} $lref] >= 0} { return $ref } } source.n { if {[lsearch {text} $lref] >= 0} { return $ref } } history.n { if {[lsearch {exec} $lref] >= 0} { return $ref } } return.n { if {[lsearch {error continue break} $lref] >= 0} { return $ref } } scrollbar.n { if {[lsearch {set} $lref] >= 0} { return $ref } } } ## ## return the cross reference ## return "$ref" } ## ## reference generation errors ## proc reference-error {msg text} { global manual puts stderr "$manual(tail): $msg: {$text}" return $text } ## ## insert as many cross references into this text string as are appropriate ## proc insert-cross-references {text} { global manual ## ## we identify cross references by: ## ``quotation'' ## emboldening ## Tcl_ prefix ## Tk_ prefix ## [a-zA-Z0-9]+ manual entry ## and we avoid messing with already anchored text ## ## ## find where each item lives ## array set offset [list \ anchor [string first {} $text] \ quote [string first {``} $text] \ end-quote [string first {''} $text] \ bold [string first {} $text] \ end-bold [string first {} $text] \ tcl [string first {Tcl_} $text] \ tk [string first {Tk_} $text] \ Tcl1 [string first {Tcl manual entry} $text] \ Tcl2 [string first {Tcl overview manual entry} $text] \ ] ## ## accumulate a list ## foreach name [array names offset] { if {$offset($name) >= 0} { set invert($offset($name)) $name lappend offsets $offset($name) } } ## ## if nothing, then we're done. ## if {![info exists offsets]} { return $text } ## ## sort the offsets ## set offsets [lsort -integer $offsets] ## ## see which we want to use ## switch -exact $invert([lindex $offsets 0]) { anchor { if {$offset(end-anchor) < 0} { return [reference-error {Missing end anchor} $text] } set head [string range $text 0 $offset(end-anchor)] set tail [string range $text [expr {$offset(end-anchor)+1}] end] return $head[insert-cross-references $tail] } quote { if {$offset(end-quote) < 0} { return [reference-error "Missing end quote" $text] } if {$invert([lindex $offsets 1]) == "tk"} { set offsets [lreplace $offsets 1 1] } if {$invert([lindex $offsets 1]) == "tcl"} { set offsets [lreplace $offsets 1 1] } switch -exact $invert([lindex $offsets 1]) { end-quote { set head [string range $text 0 [expr {$offset(quote)-1}]] set body [string range $text [expr {$offset(quote)+2}] \ [expr {$offset(end-quote)-1}]] set tail [string range $text \ [expr {$offset(end-quote)+2}] end] return "$head``[cross-reference $body]''[insert-cross-references $tail]" } bold - anchor { set head [string range $text \ 0 [expr {$offset(end-quote)+1}]] set tail [string range $text \ [expr {$offset(end-quote)+2}] end] return "$head[insert-cross-references $tail]" } } return [reference-error "Uncaught quote case" $text] } bold { if {$offset(end-bold) < 0} { return $text } if {$invert([lindex $offsets 1]) == "tk"} { set offsets [lreplace $offsets 1 1] } if {$invert([lindex $offsets 1]) == "tcl"} { set offsets [lreplace $offsets 1 1] } switch -exact $invert([lindex $offsets 1]) { end-bold { set head [string range $text 0 [expr {$offset(bold)-1}]] set body [string range $text [expr {$offset(bold)+3}] \ [expr {$offset(end-bold)-1}]] set tail [string range $text \ [expr {$offset(end-bold)+4}] end] return "$head[cross-reference $body][insert-cross-references $tail]" } anchor { set head [string range $text \ 0 [expr {$offset(end-bold)+3}]] set tail [string range $text \ [expr {$offset(end-bold)+4}] end] return "$head[insert-cross-references $tail]" } } return [reference-error "Uncaught bold case" $text] } tk { set head [string range $text 0 [expr {$offset(tk)-1}]] set tail [string range $text $offset(tk) end] if {![regexp {^(Tk_\w+)(.*)$} $tail all body tail]} { return [reference-error "Tk regexp failed" $text] } return $head[cross-reference $body][insert-cross-references $tail] } tcl { set head [string range $text 0 [expr {$offset(tcl)-1}]] set tail [string range $text $offset(tcl) end] if {![regexp {^(Tcl_\w+)(.*)$} $tail all body tail]} { return [reference-error {Tcl regexp failed} $text] } return $head[cross-reference $body][insert-cross-references $tail] } Tcl1 - Tcl2 { set off [lindex $offsets 0] set head [string range $text 0 [expr {$off-1}]] set body Tcl set tail [string range $text [expr {$off+3}] end] return $head[cross-reference $body][insert-cross-references $tail] } end-anchor - end-bold - end-quote { return [reference-error "Out of place $invert([lindex $offsets 0])" $text] } } } ## ## process formatting directives ## proc output-directive {line} { global manual # process format directive split-directive $line code rest switch -exact $code { .BS - .BE { # man-puts
} .SH - .SS { # drain any open lists # announce the subject set manual(section) $rest # start our own stack of stuff set manual($manual(name)-$manual(section)) {} lappend manual(has-$manual(section)) $manual(name) if {[string compare .SS $code]} { man-puts "

[long-toc $manual(section)]

" } else { man-puts "

[long-toc $manual(section)]

" } # some sections can simply free wheel their way through the text # some sections can be processed in their own loops switch -exact $manual(section) { NAME { if {[lsearch {CrtImgType.3 CrtItemType.3 CrtPhImgFmt.3} $manual(tail)] >= 0} { # these manual pages have two NAME sections if {[info exists manual($manual(tail)-NAME)]} { return } set manual($manual(tail)-NAME) 1 } set names {} while {1} { set line [next-text] if {[is-a-directive $line]} { backup-text 1 output-name [join $names { }] return } else { lappend names [string trim $line] } } } SYNOPSIS { lappend manual(section-toc)
while {1} { if {[next-op-is .nf rest] || [next-op-is .br rest] || [next-op-is .fi rest]} { continue } if {[next-op-is .SH rest] || [next-op-is .SS rest] || [next-op-is .BE rest] || [next-op-is .SO rest]} { backup-text 1 break } if {[next-op-is .sp rest]} { #man-puts

continue } set more [next-text] if {[is-a-directive $more]} { manerror "in SYNOPSIS found $more" backup-text 1 break } else { foreach more [split $more \n] { man-puts $more
if {[lsearch {TclLib TkLib} $manual(wing-file)] < 0} { lappend manual(section-toc)

$more } } } } lappend manual(section-toc)
return } {SEE ALSO} { while {[more-text]} { if {[next-op-is .SH rest] || [next-op-is .SS rest]} { backup-text 1 return } set more [next-text] if {[is-a-directive $more]} { manerror "$more" backup-text 1 return } set nmore {} foreach cr [split $more ,] { set cr [string trim $cr] if {![regexp {^.*$} $cr]} { set cr $cr } if {[regexp {^(.*)\([13n]\)$} $cr all name]} { set cr $name } lappend nmore $cr } man-puts [join $nmore {, }] } return } KEYWORDS { while {[more-text]} { if {[next-op-is .SH rest] || [next-op-is .SS rest]} { backup-text 1 return } set more [next-text] if {[is-a-directive $more]} { manerror "$more" backup-text 1 return } set keys {} foreach key [split $more ,] { set key [string trim $key] lappend manual(keyword-$key) [list $manual(name) $manual(wing-file)/$manual(name).htm] set initial [string toupper [string index $key 0]] lappend keys "
$key" } man-puts [join $keys {, }] } return } } if {[next-op-is .IP rest]} { output-IP-list $code .IP $rest return } if {[next-op-is .PP rest]} { return } return } .SO { if {[match-text @stuff .SE]} { output-directive {.SH STANDARD OPTIONS} set opts {} foreach line [split $stuff \n] { foreach option [split $line \t] { lappend opts $option } } man-puts
lappend manual(section-toc)
foreach option [lsort $opts] { man-puts "
[std-option-toc $option]" } man-puts
lappend manual(section-toc)
} else { manerror "unexpected .SO format:\n[expand-next-text 2]" } } .OP { output-widget-options $rest return } .IP { output-IP-list .IP .IP $rest return } .PP { man-puts

} .RS { output-RS-list return } .RE { manerror "unexpected .RE" return } .br { man-puts
return } .DE { manerror "unexpected .DE" return } .DS { if {[next-op-is .ta rest]} { } if {[match-text @stuff .DE]} { man-puts

$stuff
} elseif {[match-text .fi @ul1 @ul2 .nf @stuff .DE]} { man-puts "
[lindex $ul1 1][lindex $ul2 1]\n$stuff
" } else { manerror "unexpected .DS format:\n[expand-next-text 2]" } return } .CS { if {[next-op-is .ta rest]} { } if {[match-text @stuff .CE]} { man-puts
$stuff
} else { manerror "unexpected .CS format:\n[expand-next-text 2]" } return } .CE { manerror "unexpected .CE" return } .sp { man-puts

} .ta { # these are tab stop settings for short tables switch -exact $manual(name):$manual(section) { {bind:MODIFIERS} - {bind:EVENT TYPES} - {bind:BINDING SCRIPTS AND SUBSTITUTIONS} - {expr:OPERANDS} - {expr:MATH FUNCTIONS} - {history:DESCRIPTION} - {history:HISTORY REVISION} - {re_syntax:BRACKET EXPRESSIONS} - {switch:DESCRIPTION} - {upvar:DESCRIPTION} { return; # fix.me } default { manerror "ignoring $line" } } } .nf { if {[match-text @more .fi]} { foreach more [split $more \n] { man-puts $more
} } elseif {[match-text .RS @more .RE .fi]} { man-puts

foreach more [split $more \n] { man-puts $more
} man-puts
} elseif {[match-text .RS @more .RS @more2 .RE .RE .fi]} { man-puts
foreach more [split $more \n] { man-puts $more
} man-puts
foreach more2 [split $more2 \n] { man-puts $more2
} man-puts
} elseif {[match-text .RS @more .RS @more2 .RE @more3 .RE .fi]} { man-puts
foreach more [split $more \n] { man-puts $more
} man-puts
foreach more2 [split $more2 \n] { man-puts $more2
} man-puts
foreach more3 [split $more3 \n] { man-puts $more3
} man-puts
} elseif {[match-text .sp .RS @more .RS @more2 .sp .RE .RE .fi]} { man-puts

foreach more [split $more \n] { man-puts $more
} man-puts
foreach more2 [split $more2 \n] { man-puts $more2
} man-puts

} elseif {[match-text .RS .sp @more .sp .RE .fi]} { man-puts

foreach more [split $more \n] { man-puts $more
} man-puts

} else { manerror "ignoring $line" } } .fi { manerror "ignoring $line" } .na - .ad - .UL - .ne { manerror "ignoring $line" } default { manerror "unrecognized format directive: $line" } } } ## ## merge copyright listings ## proc merge-copyrights {l1 l2} { foreach copyright [concat $l1 $l2] { if {[regexp {^Copyright +\(c\) +(\d+) +(by +)?(\w.*)$} $copyright all date by who]} { lappend dates($who) $date continue } if {[regexp {^Copyright +\(c\) +(\d+)-(\d+) +(by +)?(\w.*)$} $copyright all from to by who]} { for {set date $from} {$date <= $to} {incr date} { lappend dates($who) $date } continue } if {[regexp {^Copyright +\(c\) +(\d+), *(\d+) +(by +)?(\w.*)$} $copyright all date1 date2 by who]} { lappend dates($who) $date1 $date2 continue } puts "oops: $copyright" } foreach who [array names dates] { set list [lsort $dates($who)] if {[llength $list] == 1 || [lindex $list 0] == [lrange $list end end]} { lappend merge "Copyright (c) [lindex $list 0] $who" } else { lappend merge "Copyright (c) [lindex $list 0]-[lrange $list end end] $who" } } return [lsort $merge] } proc makedirhier {dir} { if {![file isdirectory $dir] && \ [catch {file mkdir $dir} error]} { return -code error "cannot create directory $dir: $error" } } ## ## foreach of the man directories specified by args ## convert manpages into hypertext in the directory ## specified by html. ## proc make-man-pages {html args} { global env manual overall_title tcltkdesc makedirhier $html set manual(short-toc-n) 1 set manual(short-toc-fp) [open $html/contents.htm w] puts $manual(short-toc-fp) "$overall_title" puts $manual(short-toc-fp) "


$overall_title


" set manual(merge-copyrights) {} foreach arg $args { if {$arg == ""} {continue} set manual(wing-glob) [lindex $arg 0] set manual(wing-name) [lindex $arg 1] set manual(wing-file) [lindex $arg 2] set manual(wing-description) [lindex $arg 3] set manual(wing-copyrights) {} makedirhier $html/$manual(wing-file) set manual(wing-toc-fp) [open $html/$manual(wing-file)/contents.htm w] # whistle puts stderr "scanning section $manual(wing-name)" # put the entry for this section into the short table of contents puts $manual(short-toc-fp) "
$manual(wing-name)
$manual(wing-description)" # initialize the wing table of contents puts $manual(wing-toc-fp) "$manual(wing-name) Manual" puts $manual(wing-toc-fp) "

$manual(wing-name)


" # initialize the short table of contents for this section set manual(wing-toc) {} # initialize the man directory for this section makedirhier $html/$manual(wing-file) # initialize the long table of contents for this section set manual(long-toc-n) 1 # get the manual pages for this section set manual(pages) [lsort [glob $manual(wing-glob)]] if {[lsearch -glob $manual(pages) */options.n] >= 0} { set n [lsearch $manual(pages) */options.n] set manual(pages) "[lindex $manual(pages) $n] [lreplace $manual(pages) $n $n]" } # set manual(pages) [lrange $manual(pages) 0 5] foreach manual(page) $manual(pages) { # whistle puts stderr "scanning page $manual(page)" set manual(tail) [file tail $manual(page)] set manual(name) [file root $manual(tail)] set manual(section) {} if {[lsearch {case pack-old menubar} $manual(name)] >= 0} { # obsolete manerror "discarding $manual(name)" continue } set manual(infp) [open $manual(page)] set manual(text) {} set manual(partial-text) {} foreach p {.RS .DS .CS .SO} { set manual($p) 0 } set manual(stack) {} set manual(section) {} set manual(section-toc) {} set manual(section-toc-n) 1 set manual(copyrights) {} lappend manual(all-pages) $manual(wing-file)/$manual(tail) manreport 100 $manual(name) while {[gets $manual(infp) line] >= 0} { manreport 100 $line if {[regexp {^[`'][/\\]} $line]} { if {[regexp {Copyright \(c\).*$} $line copyright]} { lappend manual(copyrights) $copyright } # comment continue } if {"$line" == {'}} { # comment continue } if {[parse-directive $line code rest]} { switch -exact $code { .ad - .na - .so - .ne - .AS - .VE - .VS - . { # ignore continue } } if {"$manual(partial-text)" != {}} { lappend manual(text) [process-text $manual(partial-text)] set manual(partial-text) {} } switch -exact $code { .SH - .SS { if {[llength $rest] == 0} { gets $manual(infp) rest } lappend manual(text) "$code [unquote $rest]" } .TH { lappend manual(text) "$code [unquote $rest]" } .HS - .UL - .ta { lappend manual(text) "$code [unquote $rest]" } .BS - .BE - .br - .fi - .sp - .nf { if {"$rest" != {}} { manerror "unexpected argument: $line" } lappend manual(text) $code } .AP { lappend manual(text) [concat .IP [process-text "[lindex $rest 0] \\fB[lindex $rest 1]\\fR ([lindex $rest 2])"]] } .IP { regexp {^(.*) +\d+$} $rest all rest lappend manual(text) ".IP [process-text [unquote [string trim $rest]]]" } .TP { while {[is-a-directive [set next [gets $manual(infp)]]]} { manerror "ignoring $next after .TP" } if {"$next" != {'}} { lappend manual(text) ".IP [process-text $next]" } } .OP { lappend manual(text) [concat .OP [process-text \ "\\fB[lindex $rest 0]\\fR \\fB[lindex $rest 1]\\fR \\fB[lindex $rest 2]\\fR"]] } .PP - .LP { lappend manual(text) {.PP} } .RS { incr manual(.RS) lappend manual(text) $code } .RE { incr manual(.RS) -1 lappend manual(text) $code } .SO { incr manual(.SO) lappend manual(text) $code } .SE { incr manual(.SO) -1 lappend manual(text) $code } .DS { incr manual(.DS) lappend manual(text) $code } .DE { incr manual(.DS) -1 lappend manual(text) $code } .CS { incr manual(.CS) lappend manual(text) $code } .CE { incr manual(.CS) -1 lappend manual(text) $code } .de { while {[gets $manual(infp) line] >= 0} { if {[string match "..*" $line]} { break } } } .. { error "found .. outside of .de" } default { manerror "unrecognized format directive: $line" } } } else { if {$manual(partial-text) == ""} { set manual(partial-text) $line } else { append manual(partial-text) \n$line } } } if {$manual(partial-text) != ""} { lappend manual(text) [process-text $manual(partial-text)] } close $manual(infp) # fixups if {$manual(.RS) != 0} { if {$manual(name) != "selection"} { puts "unbalanced .RS .RE" } } if {$manual(.DS) != 0} { puts "unbalanced .DS .DE" } if {$manual(.CS) != 0} { puts "unbalanced .CS .CE" } if {$manual(.SO) != 0} { puts "unbalanced .SO .SE" } # output conversion open-text if {[next-op-is .HS rest]} { set manual($manual(name)-title) \ "[lrange $rest 1 end] [lindex $rest 0] manual page" while {[more-text]} { set line [next-text] if {[is-a-directive $line]} { output-directive $line } else { man-puts $line } } man-puts
		foreach copyright $manual(copyrights) {
		    man-puts "Copyright © [lrange $copyright 2 end]"
		}
		man-puts "Copyright © 1995-1997 Roger E. Critchlow Jr.
" set manual(wing-copyrights) [merge-copyrights $manual(wing-copyrights) $manual(copyrights)] } elseif {[next-op-is .TH rest]} { set manual($manual(name)-title) "[lrange $rest 4 end] - [lindex $rest 0] manual page" while {[more-text]} { set line [next-text] if {[is-a-directive $line]} { output-directive $line } else { man-puts $line } } man-puts
		foreach copyright $manual(copyrights) {
		    man-puts "Copyright © [lrange $copyright 2 end]"
		}
		man-puts "Copyright © 1995-1997 Roger E. Critchlow Jr.
" set manual(wing-copyrights) [merge-copyrights $manual(wing-copyrights) $manual(copyrights)] } else { manerror "no .HS or .TH record found" } # # make the long table of contents for this page # set manual(toc-$manual(wing-file)-$manual(name)) [concat
$manual(section-toc)

] } # # make the wing table of contents for the section # set width 0 foreach name $manual(wing-toc) { if {[string length $name] > $width} { set width [string length $name] } } set perline [expr {120 / $width}] set nrows [expr {([llength $manual(wing-toc)]+$perline)/$perline}] set n 0 catch {unset rows} foreach name [lsort $manual(wing-toc)] { set tail $manual(name-$name) if {[llength $tail] > 1} { manerror "$name is defined in more than one file: $tail" set tail [lindex $tail [expr {[llength $tail]-1}]] } set tail [file tail $tail] append rows([expr {$n%$nrows}]) \ " $name" incr n } puts $manual(wing-toc-fp) foreach row [lsort -integer [array names rows]] { puts $manual(wing-toc-fp) $rows($row) } puts $manual(wing-toc-fp)
# # insert wing copyrights # puts $manual(wing-toc-fp) "
"
	foreach copyright $manual(wing-copyrights) {
	    puts $manual(wing-toc-fp) "Copyright © [lrange $copyright 2 end]"
	}
	puts $manual(wing-toc-fp) "Copyright © 1995-1997 Roger E. Critchlow Jr."
	puts $manual(wing-toc-fp) "
" close $manual(wing-toc-fp) set manual(merge-copyrights) [merge-copyrights $manual(merge-copyrights) $manual(wing-copyrights)] } ## ## build the keyword index. ## proc strcasecmp {a b} { return [string compare -nocase $a $b] } set keys [lsort -command strcasecmp [array names manual keyword-*]] makedirhier $html/Keywords catch {eval file delete -- [glob $html/Keywords/*]} puts $manual(short-toc-fp) "
Keywords
The keywords from the $tcltkdesc man pages." set keyfp [open $html/Keywords/contents.htm w] puts $keyfp "$tcltkdesc Keywords" puts $keyfp "

$tcltkdesc Keywords


" foreach a {A B C D E F G H I J K L M N O P Q R S T U V W X Y Z} { puts $keyfp "$a" set afp [open $html/Keywords/$a.htm w] puts $afp "$tcltkdesc Keywords - $a" puts $afp "

$tcltkdesc Keywords - $a


" foreach b {A B C D E F G H I J K L M N O P Q R S T U V W X Y Z} { puts $afp "$b" } puts $afp "


" foreach k $keys { if {[string match -nocase "keyword-${a}*" $k]} { set k [string range $k 8 end] puts $afp "
$k
" set refs {} foreach man $manual(keyword-$k) { set name [lindex $man 0] set file [lindex $man 1] lappend refs "$name" } puts $afp [join $refs {, }] } } puts $afp "

"
	# insert merged copyrights
	foreach copyright $manual(merge-copyrights) {
	    puts $afp "Copyright © [lrange $copyright 2 end]"
	}
	puts $afp "Copyright © 1995-1997 Roger E. Critchlow Jr."
	puts $afp "
" close $afp } puts $keyfp "
"

    # insert merged copyrights
    foreach copyright $manual(merge-copyrights) {
	puts $keyfp "Copyright © [lrange $copyright 2 end]"
    }
    puts $keyfp "Copyright © 1995-1997 Roger E. Critchlow Jr."
    puts $keyfp 

close $keyfp ## ## finish off short table of contents ## puts $manual(short-toc-fp) {
Source
More information about these man pages.} puts $manual(short-toc-fp) "

"
    # insert merged copyrights
    foreach copyright $manual(merge-copyrights) {
	puts $manual(short-toc-fp) "Copyright © [lrange $copyright 2 end]"
    }
    puts $manual(short-toc-fp) "Copyright © 1995-1997 Roger E. Critchlow Jr."
    puts $manual(short-toc-fp) "
" close $manual(short-toc-fp) ## ## output man pages ## unset manual(section) foreach path $manual(all-pages) { set manual(wing-file) [file dirname $path] set manual(tail) [file tail $path] set manual(name) [file root $manual(tail)] set text $manual(output-$manual(wing-file)-$manual(name)) set ntext 0 foreach item $text { incr ntext [llength [split $item \n]] incr ntext } set toc $manual(toc-$manual(wing-file)-$manual(name)) set ntoc 0 foreach item $toc { incr ntoc [llength [split $item \n]] incr ntoc } puts stderr "rescanning page $manual(name) $ntoc/$ntext" set manual(outfp) [open $html/$manual(wing-file)/$manual(name).htm w] puts $manual(outfp) "$manual($manual(name)-title)" if {($ntext > 60) && ($ntoc > 32) || [lsearch { Hash LinkVar SetVar TraceVar ConfigWidg CrtImgType CrtItemType CrtPhImgFmt DoOneEvent GetBitmap GetColor GetCursor GetDash GetJustify GetPixels GetVisual ParseArgv QueueEvent } $manual(tail)] >= 0} { foreach item $toc { puts $manual(outfp) $item } } foreach item $text { puts $manual(outfp) [insert-cross-references $item] } puts $manual(outfp) close $manual(outfp) } return {} } parse_command_line set tcltkdesc ""; set cmdesc ""; set appdir "" if {$build_tcl} {append tcltkdesc "Tcl"; append cmdesc "Tcl"; append appdir "$tcldir"} if {$build_tcl && $build_tk} {append tcltkdesc "/"; append cmdesc " and "; append appdir ","} if {$build_tk} {append tcltkdesc "Tk"; append cmdesc "Tk"; append appdir "$tkdir"} set usercmddesc "The interpreters which implement $cmdesc." set tclcmddesc {The commands which the tclsh interpreter implements.} set tkcmddesc {The additional commands which the wish interpreter implements.} set tcllibdesc {The C functions which a Tcl extended C program may use.} set tklibdesc {The additional C functions which a Tk extended C program may use.} if {1} { if {[catch { make-man-pages $webdir \ "$tcltkdir/{$appdir}/doc/*.1 \"$tcltkdesc Applications\" UserCmd {$usercmddesc}" \ [expr {$build_tcl ? "$tcltkdir/$tcldir/doc/*.n {Tcl Commands} TclCmd {$tclcmddesc}" : ""}] \ [expr {$build_tk ? "$tcltkdir/$tkdir/doc/*.n {Tk Commands} TkCmd {$tkcmddesc}" : ""}] \ [expr {$build_tcl ? "$tcltkdir/$tcldir/doc/*.3 {Tcl Library} TclLib {$tcllibdesc}" : ""}] \ [expr {$build_tk ? "$tcltkdir/$tkdir/doc/*.3 {Tk Library} TkLib {$tklibdesc}" : ""}] } error]} { puts $error\n$errorInfo } } tcl8.4.20/tools/index.tcl0000644003604700454610000001030311737050675013670 0ustar dgp771div# index.tcl -- # # This file defines procedures that are used during the first pass of # the man page conversion. It is used to extract information used to # generate a table of contents and a keyword list. # # Copyright (c) 1996 by Sun Microsystems, Inc. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # Global variables used by these scripts: # # state - state variable that controls action of text proc. # # topics - array indexed by (package,section,topic) with value # of topic ID. # # keywords - array indexed by keyword string with value of topic ID. # # curID - current topic ID, starts at 0 and is incremented for # each new topic file. # # curPkg - current package name (e.g. Tcl). # # curSect - current section title (e.g. "Tcl Built-In Commands"). # # getPackages -- # # Generate a sorted list of package names from the topics array. # # Arguments: # none. proc getPackages {} { global topics foreach i [array names topics] { regsub {^(.*),.*,.*$} $i {\1} i set temp($i) {} } lsort [array names temp] } # getSections -- # # Generate a sorted list of section titles in the specified package # from the topics array. # # Arguments: # pkg - Name of package to search. proc getSections {pkg} { global topics regsub -all {[][*?\\]} $pkg {\\&} pkg foreach i [array names topics "${pkg},*"] { regsub {^.*,(.*),.*$} $i {\1} i set temp($i) {} } lsort [array names temp] } # getTopics -- # # Generate a sorted list of topics in the specified section of the # specified package from the topics array. # # Arguments: # pkg - Name of package to search. # sect - Name of section to search. proc getTopics {pkg sect} { global topics regsub -all {[][*?\\]} $pkg {\\&} pkg regsub -all {[][*?\\]} $sect {\\&} sect foreach i [array names topics "${pkg},${sect},*"] { regsub {^.*,.*,(.*)$} $i {\1} i set temp($i) {} } lsort [array names temp] } # text -- # # This procedure adds entries to the hypertext arrays topics and keywords. # # Arguments: # string - Text to index. proc text string { global state curID curPkg curSect topics keywords switch $state { NAME { foreach i [split $string ","] { set topic [string trim $i] set index "$curPkg,$curSect,$topic" if {[info exists topics($index)] && [string compare $topics($index) $curID] != 0} { puts stderr "duplicate topic $topic in $curPkg" } set topics($index) $curID lappend keywords($topic) $curID } } KEY { foreach i [split $string ","] { lappend keywords([string trim $i]) $curID } } DT - OFF - DASH {} default { puts stderr "text: unknown state: $state" } } } # macro -- # # This procedure is invoked to process macro invocations that start # with "." (instead of '). # # Arguments: # name - The name of the macro (without the "."). # args - Any additional arguments to the macro. proc macro {name args} { switch $name { SH { global state switch $args { NAME { if {$state == "INIT" } { set state NAME } } DESCRIPTION {set state DT} INTRODUCTION {set state DT} KEYWORDS {set state KEY} default {set state OFF} } } TH { global state curID curPkg curSect topics keywords set state INIT if {[llength $args] != 5} { set args [join $args " "] puts stderr "Bad .TH macro: .$name $args" } incr curID set topic [lindex $args 0] ;# Tcl_UpVar set curPkg [lindex $args 3] ;# Tcl set curSect [lindex $args 4] ;# {Tcl Library Procedures} regsub -all {\\ } $curSect { } curSect set index "$curPkg,$curSect,$topic" set topics($index) $curID lappend keywords($topic) $curID } } } # dash -- # # This procedure is invoked to handle dash characters ("\-" in # troff). It only function in pass1 is to terminate the NAME state. # # Arguments: # None. proc dash {} { global state if {$state == "NAME"} { set state DASH } } # initGlobals, tab, font, char, macro2 -- # # These procedures do nothing during the first pass. # # Arguments: # None. proc initGlobals {} {} proc newline {} {} proc tab {} {} proc font type {} proc char name {} proc macro2 {name args} {} tcl8.4.20/tools/uniClass.tcl0000644003604700454610000000645611737050675014360 0ustar dgp771div#!/bin/sh # The next line is executed by /bin/sh, but not tcl \ exec tclsh "$0" ${1+"$@"} # # uniClass.tcl -- # # Generates the character ranges and singletons that are used in # generic/regc_locale.c for translation of character classes. # This file must be generated using a tclsh that contains the # correct corresponding tclUniData.c file (generated by uniParse.tcl) # in order for the class ranges to match. # proc emitRange {first last} { global ranges numranges chars numchars extchars extranges if {$first < ($last-1)} { if {!$extranges && ($first) > 0xffff} { set extranges 1 set numranges 0 set ranges [string trimright $ranges " \n\r\t,"] append ranges "\n#if TCL_UTF_MAX > 4\n ," } append ranges [format "{0x%x, 0x%x}, " \ $first $last] if {[incr numranges] % 4 == 0} { set ranges [string trimright $ranges] append ranges "\n " } } else { if {!$extchars && ($first) > 0xffff} { set extchars 1 set numchars 0 set chars [string trimright $chars " \n\r\t,"] append chars "\n#if TCL_UTF_MAX > 4\n ," } append chars [format "0x%x, " $first] incr numchars if {$numchars % 9 == 0} { set chars [string trimright $chars] append chars "\n " } if {$first != $last} { append chars [format "0x%x, " $last] incr numchars if {$numchars % 9 == 0} { append chars "\n " } } } } proc genTable {type} { global first last ranges numranges chars numchars extchars extranges set first -2 set last -2 set ranges " " set numranges 0 set chars " " set numchars 0 set extchars 0 set extranges 0 for {set i 0} {$i <= 0x10ffff} {incr i} { if {$i == 0xd800} { # Skip surrogates set i 0xdc00 } if {[string is $type [format %c $i]]} { if {$i == ($last + 1)} { set last $i } else { if {$first > 0} { emitRange $first $last } set first $i set last $i } } } emitRange $first $last set ranges [string trimright $ranges "\t\n ,"] if {$extranges} { append ranges "\n#endif" } set chars [string trimright $chars "\t\n ,"] if {$extchars} { append chars "\n#endif" } if {$ranges ne ""} { puts "static CONST crange ${type}RangeTable\[\] = {\n$ranges\n};\n" puts "#define NUM_[string toupper $type]_RANGE (sizeof(${type}RangeTable)/sizeof(crange))\n" } else { puts "/* no contiguous ranges of $type characters */\n" } if {$chars ne ""} { puts "static CONST chr ${type}CharTable\[\] = {\n$chars\n};\n" puts "#define NUM_[string toupper $type]_CHAR (sizeof(${type}CharTable)/sizeof(chr))\n" } else { puts "/*\n * no singletons of $type characters.\n */\n" } } puts "/* * Declarations of Unicode character ranges. This code * is automatically generated by the tools/uniClass.tcl script * and used in generic/regc_locale.c. Do not modify by hand. */ " foreach {type desc} { alpha "alphabetic characters" control "control characters" digit "decimal digit characters" punct "punctuation characters" space "white space characters" lower "lowercase characters" upper "uppercase characters" graph "unicode print characters excluding space" } { puts "/*\n * Unicode: $desc.\n */\n" genTable $type } puts "/* * End of auto-generated Unicode character ranges declarations. */" tcl8.4.20/tools/regexpTestLib.tcl0000644003604700454610000001671611737050675015360 0ustar dgp771div# regexpTestLib.tcl -- # # This file contains tcl procedures used by spencer2testregexp.tcl and # spencer2regexp.tcl, which are programs written to convert Henry # Spencer's test suite to tcl test files. # # Copyright (c) 1996 by Sun Microsystems, Inc. proc readInputFile {} { global inFileName global lineArray set fileId [open $inFileName r] set i 0 while {[gets $fileId line] >= 0} { set len [string length $line] if {($len > 0) && ([string index $line [expr $len - 1]] == "\\")} { if {[info exists lineArray(c$i)] == 0} { set lineArray(c$i) 1 } else { incr lineArray(c$i) } set line [string range $line 0 [expr $len - 2]] append lineArray($i) $line continue } if {[info exists lineArray(c$i)] == 0} { set lineArray(c$i) 1 } else { incr lineArray(c$i) } append lineArray($i) $line incr i } close $fileId return $i } # # strings with embedded @'s are truncated # unpreceeded @'s are replaced by {} # proc removeAts {ls} { set len [llength $ls] set newLs {} foreach item $ls { regsub @.* $item "" newItem lappend newLs $newItem } return $newLs } proc convertErrCode {code} { set errMsg "couldn't compile regular expression pattern:" if {[string compare $code "INVARG"] == 0} { return "$errMsg invalid argument to regex routine" } elseif {[string compare $code "BADRPT"] == 0} { return "$errMsg ?+* follows nothing" } elseif {[string compare $code "BADBR"] == 0} { return "$errMsg invalid repetition count(s)" } elseif {[string compare $code "BADOPT"] == 0} { return "$errMsg invalid embedded option" } elseif {[string compare $code "EPAREN"] == 0} { return "$errMsg unmatched ()" } elseif {[string compare $code "EBRACE"] == 0} { return "$errMsg unmatched {}" } elseif {[string compare $code "EBRACK"] == 0} { return "$errMsg unmatched \[\]" } elseif {[string compare $code "ERANGE"] == 0} { return "$errMsg invalid character range" } elseif {[string compare $code "ECTYPE"] == 0} { return "$errMsg invalid character class" } elseif {[string compare $code "ECOLLATE"] == 0} { return "$errMsg invalid collating element" } elseif {[string compare $code "EESCAPE"] == 0} { return "$errMsg invalid escape sequence" } elseif {[string compare $code "BADPAT"] == 0} { return "$errMsg invalid regular expression" } elseif {[string compare $code "ESUBREG"] == 0} { return "$errMsg invalid backreference number" } elseif {[string compare $code "IMPOSS"] == 0} { return "$errMsg can never match" } return "$errMsg $code" } proc writeOutputFile {numLines fcn} { global outFileName global lineArray # open output file and write file header info to it. set fileId [open $outFileName w] puts $fileId "# Commands covered: $fcn" puts $fileId "#" puts $fileId "# This Tcl-generated file contains tests for the $fcn tcl command." puts $fileId "# Sourcing this file into Tcl runs the tests and generates output for" puts $fileId "# errors. No output means no errors were found. Setting VERBOSE to" puts $fileId "# -1 will run tests that are known to fail." puts $fileId "#" puts $fileId "# Copyright (c) 1998 Sun Microsystems, Inc." puts $fileId "#" puts $fileId "# See the file \"license.terms\" for information on usage and redistribution" puts $fileId "# of this file, and for a DISCLAIMER OF ALL WARRANTIES." puts $fileId "#" puts $fileId "\# SCCS: \%Z\% \%M\% \%I\% \%E\% \%U\%" puts $fileId "\nproc print \{arg\} \{puts \$arg\}\n" puts $fileId "if \{\[string compare test \[info procs test\]\] == 1\} \{" puts $fileId " source defs ; set VERBOSE -1\n\}\n" puts $fileId "if \{\$VERBOSE != -1\} \{" puts $fileId " proc print \{arg\} \{\}\n\}\n" puts $fileId "#" puts $fileId "# The remainder of this file is Tcl tests that have been" puts $fileId "# converted from Henry Spencer's regexp test suite." puts $fileId "#\n" set lineNum 0 set srcLineNum 1 while {$lineNum < $numLines} { set currentLine $lineArray($lineNum) # copy comment string to output file and continue if {[string index $currentLine 0] == "#"} { puts $fileId $currentLine incr srcLineNum $lineArray(c$lineNum) incr lineNum continue } set len [llength $currentLine] # copy empty string to output file and continue if {$len == 0} { puts $fileId "\n" incr srcLineNum $lineArray(c$lineNum) incr lineNum continue } if {($len < 3)} { puts "warning: test is too short --\n\t$currentLine" incr srcLineNum $lineArray(c$lineNum) incr lineNum continue } puts $fileId [convertTestLine $currentLine $len $lineNum $srcLineNum] incr srcLineNum $lineArray(c$lineNum) incr lineNum } close $fileId } proc convertTestLine {currentLine len lineNum srcLineNum} { regsub -all {(?b)\\} $currentLine {\\\\} currentLine set re [lindex $currentLine 0] set flags [lindex $currentLine 1] set str [lindex $currentLine 2] # based on flags, decide whether to skip the test if {[findSkipFlag $flags]} { regsub -all {\[|\]|\(|\)|\{|\}|\#} $currentLine {\&} line set msg "\# skipping char mapping test from line $srcLineNum\n" append msg "print \{... skip test from line $srcLineNum: $line\}" return $msg } # perform mapping if '=' flag exists set noBraces 0 if {[regexp {=|>} $flags] == 1} { regsub -all {_} $currentLine {\\ } currentLine regsub -all {A} $currentLine {\\007} currentLine regsub -all {B} $currentLine {\\b} currentLine regsub -all {E} $currentLine {\\033} currentLine regsub -all {F} $currentLine {\\f} currentLine regsub -all {N} $currentLine {\\n} currentLine # if and \r substitutions are made, do not wrap re, flags, # str, and result in braces set noBraces [regsub -all {R} $currentLine {\\\u000D} currentLine] regsub -all {T} $currentLine {\\t} currentLine regsub -all {V} $currentLine {\\v} currentLine if {[regexp {=} $flags] == 1} { set re [lindex $currentLine 0] } set str [lindex $currentLine 2] } set flags [removeFlags $flags] # find the test result set numVars [expr $len - 3] set vars {} set vals {} set result 0 set v 0 if {[regsub {\*} "$flags" "" newFlags] == 1} { # an error is expected if {[string compare $str "EMPTY"] == 0} { # empty regexp is not an error # skip this test return "\# skipping the empty-re test from line $srcLineNum\n" } set flags $newFlags set result "\{1 \{[convertErrCode $str]\}\}" } elseif {$numVars > 0} { # at least 1 match is made if {[regexp {s} $flags] == 1} { set result "\{0 1\}" } else { while {$v < $numVars} { append vars " var($v)" append vals " \$var($v)" incr v } set tmp [removeAts [lrange $currentLine 3 $len]] set result "\{0 \{1 $tmp\}\}" if {$noBraces} { set result "\[subst $result\]" } } } else { # no match is made set result "\{0 0\}" } # set up the test and write it to the output file set cmd [prepareCmd $flags $re $str $vars $noBraces] if {$cmd == -1} { return "\# skipping test with metasyntax from line $srcLineNum\n" } set test "test regexp-1.$srcLineNum \{converted from line $srcLineNum\} \{\n" append test "\tcatch {unset var}\n" append test "\tlist \[catch \{ \n" append test "\t\tset match \[$cmd\] \n" append test "\t\tlist \$match $vals \n" append test "\t\} msg\] \$msg \n" append test "\} $result \n" return $test } tcl8.4.20/tools/feather.bmp0000644003604700454610000000406611737050675014204 0ustar dgp771divBM66( ФФ€€€€€€€€€РРРРмР№ЪІ @ ` €   Р р@@ @@@`@€@ @Р@р`` `@```€` `Р`р€€ €@€`€€€ €Р€р    @ ` €   Р рРР Р@Р`ЈРРРРррр р@р`р€р рРрр@@ @@@`@€@ @Р@р@ @ @ @@ `@ €@  @ Р@ р@@@@ @@@@@`@@€@@ @@Р@@р@`@` @`@@``@`€@` @`Р@`р@€@€ @€@@€`@€€@€ @€Р@€р@ @  @ @@ `@ €@  @ Р@ р@Р@Р @Р@@Р`@Р€@Р @РР@Рр@р@р @р@@р`@р€@р @рР@рр€€ €@€`€€€ €Р€р€ € € @€ `€ €€  € Р€ р€@€@ €@@€@`€@€€@ €@Р€@р€`€` €`@€``€`€€` €`Р€`р€€€€ €€@€€`€€€€€ €€Р€€р€ €  € @€ `€ €€  € Р€ р€Р€Р €Р@€Р`€Р€€Р €РР€Рр€р€р €р@€р`€р€€р €рР€ррРР Р@Р`ЈРРРРрР Р Р @Р `Р €Р  Р РР рР@Р@ Р@@Р@`Р@€Р@ Р@РР@рР`Р` Р`@Р``Р`€Р` Р`РР`рЈЈ Р€@Р€`Р€€Р€ Р€РР€рР Р  Р @Р `Р €Р  Р РР рРРРР РР@РР`РР€РР №ћџЄ  €€€џџџџџџџџџџџџћћЄћћћћћћћћћћћћћћћћћћћћћћћћћћћћћћћЄћћћћћћћћћћћћћћћћћћћћћћћћћћћћћћћЄћћћћћћћћћћћћћћћћћћћћћћћћћћћћћћћЄћћћћћћћћћћћћћћћћћћћћћћћћћћћћћћћћЄћћћћћћћћћћћћћћћћћћћћћћћћћћћћћћћћћћћћћћћћЄЄћћћћћћћћћћћћћЄћЄаРРРћћћћћћћћћЄЄћћћћћћћћћћћћЄћЄРРРРРРћћћћћћћћћћЄћћћћћћћћћћћќЄћаРРРРРРћћћћћћћћћЄћћћћћћћћћћРќїаРРРРРРРћћћћЄЄћћћћћћћћћћћћћРќќїРРРРРРРРћћћћћЄћћћћћћћћћћћћћРќќЄРРРРРРРРћћћћћЄћћћћћћћћћћћћРќќќаРРРРРРРРћћћћћЄћћћћћћћћћћћРќќќќаРРРРРРРРћћћћћћћћћћћћћћћћћРќќќќаРРРРРРРћћћћћћћћћћћћћћћћћРќќќќќаРРРРРРћћћћћћћћћћћћћћћћћћРќќќќќїРРРРРРћћћћћћћћћћћћћћћћћРќќќќќїРРРРРРРћћћћћћћћћћћћћћћћРќќќќаќїРРРРРРРћћћћћћћћћћћћћћћћРќаќќќќЄРРРРРРРћћћћћћћћћћћћћћћћРќќќќаќаЄРРРРРРћћћћћћћћћћћћћћћћРќќаќаќа›РРРРРРћћћћћћћћћћћћћћћћРќќаќаааќРРРРРРћћћћћћћћЄћћћћћћћћРаќаќаааќРРРРРћћћћћћћЄћћћЄћћћћћРаќаааааќРРРРРћћћћћћћћЄћћћЄћћћћћРќааааааќРРРРћћћћћћћЄћћћћЄћћћћћРРќаааааќРРРРћћћћћћћћЄћћћћЄћћћћћћРќаааааќРРРћћћћћћћћЄћћћћЄЄћћћћћРРќааааќРРРћћћћћћћћћЄћћћћћЄЄћћћћћРРќаааќРРћћћћћћћћћћћћћћћћћћћћћћћћРРРќаќРћћћћћћћћћћћћћћћћћћћћћћћћћћћРРРРћћtcl8.4.20/tools/checkLibraryDoc.tcl0000755003604700454610000001630211737050674015620 0ustar dgp771div# checkLibraryDoc.tcl -- # # This script attempts to determine what APIs exist in the source base that # have not been documented. By grepping through all of the doc/*.3 man # pages, looking for "Pkg_*" (e.g., Tcl_ or Tk_), and comparing this list # against the list of Pkg_ APIs found in the source (e.g., tcl8.2/*/*.[ch]) # we create six lists: # 1) APIs in Source not in Docs. # 2) APIs in Docs not in Source. # 3) Internal APIs and structs. # 4) Misc APIs and structs that we are not documenting. # 5) Command APIs (e.g., Tcl_ArrayObjCmd.) # 6) Proc pointers (e.g., Tcl_CloseProc.) # # Note: Each list is "a best guess" approximation. If developers write # non-standard code, this script will produce erroneous results. Each # list should be carefully checked for accuracy. # # Copyright (c) 1998-1999 by Scriptics Corporation. # All rights reserved. lappend auto_path "c:/program\ files/tclpro1.2/win32-ix86/bin" #lappend auto_path "/home/surles/cvs/tclx8.0/tcl/unix" if {[catch {package require Tclx}]} { puts "error: could not load TclX. Please set TCL_LIBRARY." exit 1 } # A list of structs that are known to be undocumented. set StructList { Tcl_AsyncHandler \ Tcl_CallFrame \ Tcl_Condition \ Tcl_Encoding \ Tcl_EncodingState \ Tcl_EncodingType \ Tcl_HashEntry \ Tcl_HashSearch \ Tcl_HashTable \ Tcl_Mutex \ Tcl_Pid \ Tcl_QueuePosition \ Tcl_ResolvedVarInfo \ Tcl_SavedResult \ Tcl_ThreadDataKey \ Tcl_ThreadId \ Tcl_Time \ Tcl_TimerToken \ Tcl_Token \ Tcl_Trace \ Tcl_Value \ Tcl_ValueType \ Tcl_Var \ Tk_3DBorder \ Tk_ArgvInfo \ Tk_BindingTable \ Tk_Canvas \ Tk_CanvasTextInfo \ Tk_ConfigSpec \ Tk_ConfigTypes \ Tk_Cursor \ Tk_CustomOption \ Tk_ErrorHandler \ Tk_FakeWin \ Tk_Font \ Tk_FontMetrics \ Tk_GeomMgr \ Tk_Image \ Tk_ImageMaster \ Tk_ImageType \ Tk_Item \ Tk_ItemType \ Tk_OptionSpec\ Tk_OptionTable \ Tk_OptionType \ Tk_PhotoHandle \ Tk_PhotoImageBlock \ Tk_PhotoImageFormat \ Tk_PostscriptInfo \ Tk_SavedOption \ Tk_SavedOptions \ Tk_SegType \ Tk_TextLayout \ Tk_Window \ } # Misc junk that appears in the comments of the source. This just # allows us to filter comments that "fool" the script. set CommentList { Tcl_Create\[Obj\]Command \ Tcl_DecrRefCount\\n \ Tcl_NewObj\\n \ Tk_GetXXX \ } # Main entry point to this script. proc main {} { global argv0 global argv set len [llength $argv] if {($len != 2) && ($len != 3)} { puts "usage: $argv0 pkgName pkgDir \[outFile\]" puts " pkgName == Tcl,Tk" puts " pkgDir == /home/surles/cvs/tcl8.2" exit 1 } set pkg [lindex $argv 0] set dir [lindex $argv 1] if {[llength $argv] == 3} { set file [open [lindex $argv 2] w] } else { set file stdout } foreach {c d} [compare [grepCode $dir $pkg] [grepDocs $dir $pkg]] {} filter $c $d $dir $pkg $file if {$file != "stdout"} { close $file } return } # Intersect the two list and write out the sets of APIs in one # list that is not in the other. proc compare {list1 list2} { set inter [intersect3 $list1 $list2] return [list [lindex $inter 0] [lindex $inter 2]] } # Filter the lists into the six lists we report on. Then write # the results to the file. proc filter {code docs dir pkg {outFile stdout}} { set apis {} # A list of Tcl command APIs. These are not documented. # This list should just be verified for accuracy. set cmds {} # A list of proc pointer structs. These are not documented. # This list should just be verified for accuracy. set procs {} # A list of internal declarations. These are not documented. # This list should just be verified for accuracy. set decls [grepDecl $dir $pkg] # A list of misc. procedure declarations that are not documented. # This list should just be verified for accuracy. set misc [grepMisc $dir $pkg] set pat1 ".*(${pkg}_\[A-z0-9]+).*$" # A list of APIs in the source, not in the docs. # This list should just be verified for accuracy. foreach x $code { if {[string match *Cmd $x]} { if {[string match ${pkg}* $x]} { lappend cmds $x } } elseif {[string match *Proc $x]} { if {[string match ${pkg}* $x]} { lappend procs $x } } elseif {[lsearch -exact $decls $x] >= 0} { # No Op. } elseif {[lsearch -exact $misc $x] >= 0} { # No Op. } else { lappend apis $x } } dump $apis "APIs in Source not in Docs." $outFile dump $docs "APIs in Docs not in Source." $outFile dump $decls "Internal APIs and structs." $outFile dump $misc "Misc APIs and structs that we are not documenting." $outFile dump $cmds "Command APIs." $outFile dump $procs "Proc pointers." $outFile return } # Print the list of APIs if the list is not null. proc dump {list title file} { if {$list != {}} { puts $file "" puts $file $title puts $file "---------------------------------------------------------" foreach x $list { puts $file $x } } } # Grep into "dir/*/*.[ch]" looking for APIs that match $pkg_*. # (e.g., Tcl_Exit). Return a list of APIs. proc grepCode {dir pkg} { set apis [myGrep "${pkg}_\.\*" "${dir}/\*/\*\.\[ch\]"] set pat1 ".*(${pkg}_\[A-z0-9]+).*$" foreach a $apis { if {[regexp -- $pat1 $a main n1]} { set result([string trim $n1]) 1 } } return [lsort [array names result]] } # Grep into "dir/doc/*.3" looking for APIs that match $pkg_*. # (e.g., Tcl_Exit). Return a list of APIs. proc grepDocs {dir pkg} { set apis [myGrep "\\fB${pkg}_\.\*\\fR" "${dir}/doc/\*\.3"] set pat1 ".*(${pkg}_\[A-z0-9]+)\\\\fR.*$" foreach a $apis { if {[regexp -- $pat1 $a main n1]} { set result([string trim $n1]) 1 } } return [lsort [array names result]] } # Grep into "generic/pkgIntDecls.h" looking for APIs that match $pkg_*. # (e.g., Tcl_Export). Return a list of APIs. proc grepDecl {dir pkg} { set file [file join $dir generic "[string tolower $pkg]IntDecls.h"] set apis [myGrep "^EXTERN.*\[ \t\]${pkg}_.*" $file] set pat1 ".*(${pkg}_\[A-z0-9]+).*$" foreach a $apis { if {[regexp -- $pat1 $a main n1]} { set result([string trim $n1]) 1 } } return [lsort [array names result]] } # Grep into "*/*.[ch]" looking for APIs that match $pkg_Db*. # (e.g., Tcl_DbCkalloc). Return a list of APIs. proc grepMisc {dir pkg} { global CommentList global StructList set apis [myGrep "^EXTERN.*\[ \t\]${pkg}_Db.*" "${dir}/\*/\*\.\[ch\]"] set pat1 ".*(${pkg}_\[A-z0-9]+).*$" foreach a $apis { if {[regexp -- $pat1 $a main n1]} { set dbg([string trim $n1]) 1 } } set result {} eval {lappend result} $StructList eval {lappend result} [lsort [array names dbg]] eval {lappend result} $CommentList return $result } proc myGrep {searchPat globPat} { set result {} foreach file [glob -nocomplain $globPat] { set file [open $file r] set data [read $file] close $file foreach line [split $data "\n"] { if {[regexp "^.*${searchPat}.*\$" $line]} { lappend result $line } } } return $result } main tcl8.4.20/tools/README0000644003604700454610000000164011737050674012740 0ustar dgp771divThis directory contains unsupported tools used to build parts of Tcl for distribution. uniParse.tcl -- Script for converting the Unicode character database into a compact table stored in generic/tclUniData.c. uniClass.tcl -- Script for generating regexp class tables from the Tcl "string is" classes Generating HTML files. The tcl-tk-man-html.tcl script from Robert Critchlow generates a nice set of HTML with good cross references. Use it like tclsh tcl-tk-man-html.tcl --htmldir=/tmp/tcl8.2 This script is very picky about the organization of man pages, effectively acting as a style enforcer. Generating Windows Help Files: 1) Build tcl in the ../unix directory 2) On UNIX, (after autoconf and configure), do make this converts the Nroff to RTF files. 2) On Windows, convert the RTF to a Help doc, do nmake helpfile Generating Windows binary distribution. Update and compile the WYSE tcl.wse configuration. tcl8.4.20/tools/genWinImage.tcl0000644003604700454610000000733011737050675014761 0ustar dgp771div# genWinImage.tcl -- # # This script generates the Windows installer. # # Copyright (c) 1999 by Scriptics Corporation. # All rights reserved. # This file is insensitive to the directory from which it is invoked. namespace eval genWinImage { # toolsDir -- # # This variable points to the platform specific tools directory. variable toolsDir # tclBuildDir -- # # This variable points to the directory containing the Tcl built tree. variable tclBuildDir # tkBuildDir -- # # This variable points to the directory containing the Tk built tree. variable tkBuildDir # our script name at runtime variable script [info script] } # genWinImage::init -- # # This is the main entry point. # # Arguments: # None. # # Results: # None. proc genWinImage::init {} { global tcl_platform argv argv0 variable tclBuildDir variable tkBuildDir variable toolsDir variable script puts "\n--- $script started: \ [clock format [clock seconds] -format "%Y%m%d-%H:%M"] --\n" if {$tcl_platform(platform) != "windows"} { puts stderr "ERROR: Cannot build TCL.EXE on Unix systems" exit 1 } if {[llength $argv] != 3} { puts stderr "usage: $argv0 " exit 0 } set tclBuildDir [lindex $argv 0] set tkBuildDir [lindex $argv 1] set toolsDir [lindex $argv 2] generateInstallers puts "\n--- $script finished: \ [clock format [clock seconds] -format "%Y%m%d-%H:%M"] --\n\n" } # genWinImage::makeTextFile -- # # Convert the input file into a CRLF terminated text file. # # Arguments: # infile The input file to convert. # outfile The location where the text file should be stored. # # Results: # None. proc genWinImage::makeTextFile {infile outfile} { set f [open $infile r] set text [read $f] close $f set f [open $outfile w] fconfigure $f -translation crlf puts -nonewline $f $text close $f } # genWinImage::generateInstallers -- # # Perform substitutions on the pro.wse.in file and then # invoke the WSE script twice; once for CD and once for web. # # Arguments: # None. # # Results: # Leaves proweb.exe and procd.exe sitting in the curent directory. proc genWinImage::generateInstallers {} { variable toolsDir variable tclBuildDir variable tkBuildDir # Now read the "pro/srcs/install/pro.wse.in" file, have Tcl make # appropriate substitutions, write out the resulting file in a # current-working-directory. Use this new file to perform installation # image creation. Note that we have to use this technique to set # the value of _WISE_ because wise32 won't use a /d switch for this # variable. set __TCLBASEDIR__ [file native $tclBuildDir] set __TKBASEDIR__ [file native $tkBuildDir] set __WISE__ [file native [file join $toolsDir wise]] set f [open [file join $__TCLBASEDIR__ generic/tcl.h] r] set s [read $f] close $f regexp {TCL_PATCH_LEVEL\s*\"([^\"]*)\"} $s dummy __TCL_PATCH_LEVEL__ set f [open tcl.wse.in r] set s [read $f] close $f set s [subst -nocommands -nobackslashes $s] set f [open tcl.wse w] puts $f $s close $f # Ensure the text files are CRLF terminated makeTextFile [file join $tclBuildDir win/README.binary] \ [file join $tclBuildDir win/readme.txt] makeTextFile [file join $tclBuildDir license.terms] \ [file join $tclBuildDir license.txt] set wise32ProgFilePath [file native [file join $__WISE__ wise32.exe]] # Run the Wise installer to create the Windows install images. if {[catch {exec [file native $wise32ProgFilePath] /c tcl.wse} errMsg]} { puts stderr "ERROR: $errMsg" } else { puts "\"TCL.EXE\" created." } return } genWinImage::init tcl8.4.20/tools/white.bmp0000644003604700454610000005005211737050675013702 0ustar dgp771divBM*P>(еUьOttџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџџјtcl8.4.20/generic/0000755003604700454610000000000012153151142012314 5ustar dgp771divtcl8.4.20/generic/regexec.c0000644003604700454610000006737311737050674014141 0ustar dgp771div/* * re_*exec and friends - match REs * * Copyright (c) 1998, 1999 Henry Spencer. All rights reserved. * * Development of this software was funded, in part, by Cray Research Inc., * UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics * Corporation, none of whom are responsible for the results. The author * thanks all of them. * * Redistribution and use in source and binary forms -- with or without * modification -- are permitted for any purpose, provided that * redistributions in source form retain this entire copyright notice and * indicate the origin and nature of any modifications. * * I'd appreciate being given credit for this package in the documentation * of software which uses it, but that is not a requirement. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * HENRY SPENCER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include "regguts.h" /* lazy-DFA representation */ struct arcp { /* "pointer" to an outarc */ struct sset *ss; color co; }; struct sset { /* state set */ unsigned *states; /* pointer to bitvector */ unsigned hash; /* hash of bitvector */ # define HASH(bv, nw) (((nw) == 1) ? *(bv) : hash(bv, nw)) # define HIT(h,bv,ss,nw) ((ss)->hash == (h) && ((nw) == 1 || \ memcmp(VS(bv), VS((ss)->states), (nw)*sizeof(unsigned)) == 0)) int flags; # define STARTER 01 /* the initial state set */ # define POSTSTATE 02 /* includes the goal state */ # define LOCKED 04 /* locked in cache */ # define NOPROGRESS 010 /* zero-progress state set */ struct arcp ins; /* chain of inarcs pointing here */ chr *lastseen; /* last entered on arrival here */ struct sset **outs; /* outarc vector indexed by color */ struct arcp *inchain; /* chain-pointer vector for outarcs */ }; struct dfa { int nssets; /* size of cache */ int nssused; /* how many entries occupied yet */ int nstates; /* number of states */ int ncolors; /* length of outarc and inchain vectors */ int wordsper; /* length of state-set bitvectors */ struct sset *ssets; /* state-set cache */ unsigned *statesarea; /* bitvector storage */ unsigned *work; /* pointer to work area within statesarea */ struct sset **outsarea; /* outarc-vector storage */ struct arcp *incarea; /* inchain storage */ struct cnfa *cnfa; struct colormap *cm; chr *lastpost; /* location of last cache-flushed success */ chr *lastnopr; /* location of last cache-flushed NOPROGRESS */ struct sset *search; /* replacement-search-pointer memory */ int cptsmalloced; /* were the areas individually malloced? */ char *mallocarea; /* self, or master malloced area, or NULL */ }; #define WORK 1 /* number of work bitvectors needed */ /* setup for non-malloc allocation for small cases */ #define FEWSTATES 20 /* must be less than UBITS */ #define FEWCOLORS 15 struct smalldfa { struct dfa dfa; struct sset ssets[FEWSTATES*2]; unsigned statesarea[FEWSTATES*2 + WORK]; struct sset *outsarea[FEWSTATES*2 * FEWCOLORS]; struct arcp incarea[FEWSTATES*2 * FEWCOLORS]; }; #define DOMALLOC ((struct smalldfa *)NULL) /* force malloc */ /* internal variables, bundled for easy passing around */ struct vars { regex_t *re; struct guts *g; int eflags; /* copies of arguments */ size_t nmatch; regmatch_t *pmatch; rm_detail_t *details; chr *start; /* start of string */ chr *stop; /* just past end of string */ int err; /* error code if any (0 none) */ regoff_t *mem; /* memory vector for backtracking */ struct smalldfa dfa1; struct smalldfa dfa2; }; #define VISERR(vv) ((vv)->err != 0) /* have we seen an error yet? */ #define ISERR() VISERR(v) #define VERR(vv,e) (((vv)->err) ? (vv)->err : ((vv)->err = (e))) #define ERR(e) VERR(v, e) /* record an error */ #define NOERR() {if (ISERR()) return v->err;} /* if error seen, return it */ #define OFF(p) ((p) - v->start) #define LOFF(p) ((long)OFF(p)) /* * forward declarations */ /* =====^!^===== begin forwards =====^!^===== */ /* automatically gathered by fwd; do not hand-edit */ /* === regexec.c === */ int exec _ANSI_ARGS_((regex_t *, CONST chr *, size_t, rm_detail_t *, size_t, regmatch_t [], int)); static int find _ANSI_ARGS_((struct vars *, struct cnfa *, struct colormap *)); static int cfind _ANSI_ARGS_((struct vars *, struct cnfa *, struct colormap *)); static int cfindloop _ANSI_ARGS_((struct vars *, struct cnfa *, struct colormap *, struct dfa *, struct dfa *, chr **)); static VOID zapsubs _ANSI_ARGS_((regmatch_t *, size_t)); static VOID zapmem _ANSI_ARGS_((struct vars *, struct subre *)); static VOID subset _ANSI_ARGS_((struct vars *, struct subre *, chr *, chr *)); static int dissect _ANSI_ARGS_((struct vars *, struct subre *, chr *, chr *)); static int condissect _ANSI_ARGS_((struct vars *, struct subre *, chr *, chr *)); static int altdissect _ANSI_ARGS_((struct vars *, struct subre *, chr *, chr *)); static int cdissect _ANSI_ARGS_((struct vars *, struct subre *, chr *, chr *)); static int ccondissect _ANSI_ARGS_((struct vars *, struct subre *, chr *, chr *)); static int crevdissect _ANSI_ARGS_((struct vars *, struct subre *, chr *, chr *)); static int cbrdissect _ANSI_ARGS_((struct vars *, struct subre *, chr *, chr *)); static int caltdissect _ANSI_ARGS_((struct vars *, struct subre *, chr *, chr *)); /* === rege_dfa.c === */ static chr *longest _ANSI_ARGS_((struct vars *, struct dfa *, chr *, chr *, int *)); static chr *shortest _ANSI_ARGS_((struct vars *, struct dfa *, chr *, chr *, chr *, chr **, int *)); static chr *lastcold _ANSI_ARGS_((struct vars *, struct dfa *)); static struct dfa *newdfa _ANSI_ARGS_((struct vars *, struct cnfa *, struct colormap *, struct smalldfa *)); static VOID freedfa _ANSI_ARGS_((struct dfa *)); static unsigned hash _ANSI_ARGS_((unsigned *, int)); static struct sset *initialize _ANSI_ARGS_((struct vars *, struct dfa *, chr *)); static struct sset *miss _ANSI_ARGS_((struct vars *, struct dfa *, struct sset *, pcolor, chr *, chr *)); static int lacon _ANSI_ARGS_((struct vars *, struct cnfa *, chr *, pcolor)); static struct sset *getvacant _ANSI_ARGS_((struct vars *, struct dfa *, chr *, chr *)); static struct sset *pickss _ANSI_ARGS_((struct vars *, struct dfa *, chr *, chr *)); /* automatically gathered by fwd; do not hand-edit */ /* =====^!^===== end forwards =====^!^===== */ /* - exec - match regular expression ^ int exec(regex_t *, CONST chr *, size_t, rm_detail_t *, ^ size_t, regmatch_t [], int); */ int exec(re, string, len, details, nmatch, pmatch, flags) regex_t *re; CONST chr *string; size_t len; rm_detail_t *details; size_t nmatch; regmatch_t pmatch[]; int flags; { struct vars var; register struct vars *v = &var; int st; size_t n; int backref; # define LOCALMAT 20 regmatch_t mat[LOCALMAT]; # define LOCALMEM 40 regoff_t mem[LOCALMEM]; /* sanity checks */ if (re == NULL || string == NULL || re->re_magic != REMAGIC) return REG_INVARG; if (re->re_csize != sizeof(chr)) return REG_MIXED; /* setup */ v->re = re; v->g = (struct guts *)re->re_guts; if ((v->g->cflags®_EXPECT) && details == NULL) return REG_INVARG; if (v->g->info®_UIMPOSSIBLE) return REG_NOMATCH; backref = (v->g->info®_UBACKREF) ? 1 : 0; v->eflags = flags; if (v->g->cflags®_NOSUB) nmatch = 0; /* override client */ v->nmatch = nmatch; if (backref) { /* need work area */ if (v->g->nsub + 1 <= LOCALMAT) v->pmatch = mat; else v->pmatch = (regmatch_t *)MALLOC((v->g->nsub + 1) * sizeof(regmatch_t)); if (v->pmatch == NULL) return REG_ESPACE; v->nmatch = v->g->nsub + 1; } else v->pmatch = pmatch; v->details = details; v->start = (chr *)string; v->stop = (chr *)string + len; v->err = 0; if (backref) { /* need retry memory */ assert(v->g->ntree >= 0); n = (size_t)v->g->ntree; if (n <= LOCALMEM) v->mem = mem; else v->mem = (regoff_t *)MALLOC(n*sizeof(regoff_t)); if (v->mem == NULL) { if (v->pmatch != pmatch && v->pmatch != mat) FREE(v->pmatch); return REG_ESPACE; } } else v->mem = NULL; /* do it */ assert(v->g->tree != NULL); if (backref) st = cfind(v, &v->g->tree->cnfa, &v->g->cmap); else st = find(v, &v->g->tree->cnfa, &v->g->cmap); /* copy (portion of) match vector over if necessary */ if (st == REG_OKAY && v->pmatch != pmatch && nmatch > 0) { zapsubs(pmatch, nmatch); n = (nmatch < v->nmatch) ? nmatch : v->nmatch; memcpy(VS(pmatch), VS(v->pmatch), n*sizeof(regmatch_t)); } /* clean up */ if (v->pmatch != pmatch && v->pmatch != mat) FREE(v->pmatch); if (v->mem != NULL && v->mem != mem) FREE(v->mem); return st; } /* - find - find a match for the main NFA (no-complications case) ^ static int find(struct vars *, struct cnfa *, struct colormap *); */ static int find(v, cnfa, cm) struct vars *v; struct cnfa *cnfa; struct colormap *cm; { struct dfa *s; struct dfa *d; chr *begin; chr *end = NULL; chr *cold; chr *open; /* open and close of range of possible starts */ chr *close; int hitend; int shorter = (v->g->tree->flags&SHORTER) ? 1 : 0; /* first, a shot with the search RE */ s = newdfa(v, &v->g->search, cm, &v->dfa1); assert(!(ISERR() && s != NULL)); NOERR(); MDEBUG(("\nsearch at %ld\n", LOFF(v->start))); cold = NULL; close = shortest(v, s, v->start, v->start, v->stop, &cold, (int *)NULL); freedfa(s); NOERR(); if (v->g->cflags®_EXPECT) { assert(v->details != NULL); if (cold != NULL) v->details->rm_extend.rm_so = OFF(cold); else v->details->rm_extend.rm_so = OFF(v->stop); v->details->rm_extend.rm_eo = OFF(v->stop); /* unknown */ } if (close == NULL) /* not found */ return REG_NOMATCH; if (v->nmatch == 0) /* found, don't need exact location */ return REG_OKAY; /* find starting point and match */ assert(cold != NULL); open = cold; cold = NULL; MDEBUG(("between %ld and %ld\n", LOFF(open), LOFF(close))); d = newdfa(v, cnfa, cm, &v->dfa1); assert(!(ISERR() && d != NULL)); NOERR(); for (begin = open; begin <= close; begin++) { MDEBUG(("\nfind trying at %ld\n", LOFF(begin))); if (shorter) end = shortest(v, d, begin, begin, v->stop, (chr **)NULL, &hitend); else end = longest(v, d, begin, v->stop, &hitend); NOERR(); if (hitend && cold == NULL) cold = begin; if (end != NULL) break; /* NOTE BREAK OUT */ } assert(end != NULL); /* search RE succeeded so loop should */ freedfa(d); /* and pin down details */ assert(v->nmatch > 0); v->pmatch[0].rm_so = OFF(begin); v->pmatch[0].rm_eo = OFF(end); if (v->g->cflags®_EXPECT) { if (cold != NULL) v->details->rm_extend.rm_so = OFF(cold); else v->details->rm_extend.rm_so = OFF(v->stop); v->details->rm_extend.rm_eo = OFF(v->stop); /* unknown */ } if (v->nmatch == 1) /* no need for submatches */ return REG_OKAY; /* submatches */ zapsubs(v->pmatch, v->nmatch); return dissect(v, v->g->tree, begin, end); } /* - cfind - find a match for the main NFA (with complications) ^ static int cfind(struct vars *, struct cnfa *, struct colormap *); */ static int cfind(v, cnfa, cm) struct vars *v; struct cnfa *cnfa; struct colormap *cm; { struct dfa *s; struct dfa *d; chr *cold = NULL; /* silence gcc 4 warning */ int ret; s = newdfa(v, &v->g->search, cm, &v->dfa1); NOERR(); d = newdfa(v, cnfa, cm, &v->dfa2); if (ISERR()) { assert(d == NULL); freedfa(s); return v->err; } ret = cfindloop(v, cnfa, cm, d, s, &cold); freedfa(d); freedfa(s); NOERR(); if (v->g->cflags®_EXPECT) { assert(v->details != NULL); if (cold != NULL) v->details->rm_extend.rm_so = OFF(cold); else v->details->rm_extend.rm_so = OFF(v->stop); v->details->rm_extend.rm_eo = OFF(v->stop); /* unknown */ } return ret; } /* - cfindloop - the heart of cfind ^ static int cfindloop(struct vars *, struct cnfa *, struct colormap *, ^ struct dfa *, struct dfa *, chr **); */ static int cfindloop(v, cnfa, cm, d, s, coldp) struct vars *v; struct cnfa *cnfa; struct colormap *cm; struct dfa *d; struct dfa *s; chr **coldp; /* where to put coldstart pointer */ { chr *begin; chr *end; chr *cold; chr *open; /* open and close of range of possible starts */ chr *close; chr *estart; chr *estop; int er; int shorter = v->g->tree->flags&SHORTER; int hitend; assert(d != NULL && s != NULL); cold = NULL; close = v->start; do { MDEBUG(("\ncsearch at %ld\n", LOFF(close))); close = shortest(v, s, close, close, v->stop, &cold, (int *)NULL); if (close == NULL) break; /* NOTE BREAK */ assert(cold != NULL); open = cold; cold = NULL; MDEBUG(("cbetween %ld and %ld\n", LOFF(open), LOFF(close))); for (begin = open; begin <= close; begin++) { MDEBUG(("\ncfind trying at %ld\n", LOFF(begin))); estart = begin; estop = v->stop; for (;;) { if (shorter) end = shortest(v, d, begin, estart, estop, (chr **)NULL, &hitend); else end = longest(v, d, begin, estop, &hitend); if (hitend && cold == NULL) cold = begin; if (end == NULL) break; /* NOTE BREAK OUT */ MDEBUG(("tentative end %ld\n", LOFF(end))); zapsubs(v->pmatch, v->nmatch); zapmem(v, v->g->tree); er = cdissect(v, v->g->tree, begin, end); if (er == REG_OKAY) { if (v->nmatch > 0) { v->pmatch[0].rm_so = OFF(begin); v->pmatch[0].rm_eo = OFF(end); } *coldp = cold; return REG_OKAY; } if (er != REG_NOMATCH) { ERR(er); return er; } if ((shorter) ? end == estop : end == begin) { /* no point in trying again */ *coldp = cold; return REG_NOMATCH; } /* go around and try again */ if (shorter) estart = end + 1; else estop = end - 1; } } } while (close < v->stop); *coldp = cold; return REG_NOMATCH; } /* - zapsubs - initialize the subexpression matches to "no match" ^ static VOID zapsubs(regmatch_t *, size_t); */ static VOID zapsubs(p, n) regmatch_t *p; size_t n; { size_t i; for (i = n-1; i > 0; i--) { p[i].rm_so = -1; p[i].rm_eo = -1; } } /* - zapmem - initialize the retry memory of a subtree to zeros ^ static VOID zapmem(struct vars *, struct subre *); */ static VOID zapmem(v, t) struct vars *v; struct subre *t; { if (t == NULL) return; assert(v->mem != NULL); v->mem[t->retry] = 0; if (t->op == '(') { assert(t->subno > 0); v->pmatch[t->subno].rm_so = -1; v->pmatch[t->subno].rm_eo = -1; } if (t->left != NULL) zapmem(v, t->left); if (t->right != NULL) zapmem(v, t->right); } /* - subset - set any subexpression relevant to a successful subre ^ static VOID subset(struct vars *, struct subre *, chr *, chr *); */ static VOID subset(v, sub, begin, end) struct vars *v; struct subre *sub; chr *begin; chr *end; { int n = sub->subno; assert(n > 0); if ((size_t)n >= v->nmatch) return; MDEBUG(("setting %d\n", n)); v->pmatch[n].rm_so = OFF(begin); v->pmatch[n].rm_eo = OFF(end); } /* - dissect - determine subexpression matches (uncomplicated case) ^ static int dissect(struct vars *, struct subre *, chr *, chr *); */ static int /* regexec return code */ dissect(v, t, begin, end) struct vars *v; struct subre *t; chr *begin; /* beginning of relevant substring */ chr *end; /* end of same */ { assert(t != NULL); MDEBUG(("dissect %ld-%ld\n", LOFF(begin), LOFF(end))); switch (t->op) { case '=': /* terminal node */ assert(t->left == NULL && t->right == NULL); return REG_OKAY; /* no action, parent did the work */ break; case '|': /* alternation */ assert(t->left != NULL); return altdissect(v, t, begin, end); break; case 'b': /* back ref -- shouldn't be calling us! */ return REG_ASSERT; break; case '.': /* concatenation */ assert(t->left != NULL && t->right != NULL); return condissect(v, t, begin, end); break; case '(': /* capturing */ assert(t->left != NULL && t->right == NULL); assert(t->subno > 0); subset(v, t, begin, end); return dissect(v, t->left, begin, end); break; default: return REG_ASSERT; break; } } /* - condissect - determine concatenation subexpression matches (uncomplicated) ^ static int condissect(struct vars *, struct subre *, chr *, chr *); */ static int /* regexec return code */ condissect(v, t, begin, end) struct vars *v; struct subre *t; chr *begin; /* beginning of relevant substring */ chr *end; /* end of same */ { struct dfa *d; struct dfa *d2; chr *mid; int i; int shorter = (t->left->flags&SHORTER) ? 1 : 0; chr *stop = (shorter) ? end : begin; assert(t->op == '.'); assert(t->left != NULL && t->left->cnfa.nstates > 0); assert(t->right != NULL && t->right->cnfa.nstates > 0); d = newdfa(v, &t->left->cnfa, &v->g->cmap, &v->dfa1); NOERR(); d2 = newdfa(v, &t->right->cnfa, &v->g->cmap, &v->dfa2); if (ISERR()) { assert(d2 == NULL); freedfa(d); return v->err; } /* pick a tentative midpoint */ if (shorter) mid = shortest(v, d, begin, begin, end, (chr **)NULL, (int *)NULL); else mid = longest(v, d, begin, end, (int *)NULL); if (mid == NULL) { freedfa(d); freedfa(d2); return REG_ASSERT; } MDEBUG(("tentative midpoint %ld\n", LOFF(mid))); /* iterate until satisfaction or failure */ while (longest(v, d2, mid, end, (int *)NULL) != end) { /* that midpoint didn't work, find a new one */ if (mid == stop) { /* all possibilities exhausted! */ MDEBUG(("no midpoint!\n")); freedfa(d); freedfa(d2); return REG_ASSERT; } if (shorter) mid = shortest(v, d, begin, mid+1, end, (chr **)NULL, (int *)NULL); else mid = longest(v, d, begin, mid-1, (int *)NULL); if (mid == NULL) { /* failed to find a new one! */ MDEBUG(("failed midpoint!\n")); freedfa(d); freedfa(d2); return REG_ASSERT; } MDEBUG(("new midpoint %ld\n", LOFF(mid))); } /* satisfaction */ MDEBUG(("successful\n")); freedfa(d); freedfa(d2); i = dissect(v, t->left, begin, mid); if (i != REG_OKAY) return i; return dissect(v, t->right, mid, end); } /* - altdissect - determine alternative subexpression matches (uncomplicated) ^ static int altdissect(struct vars *, struct subre *, chr *, chr *); */ static int /* regexec return code */ altdissect(v, t, begin, end) struct vars *v; struct subre *t; chr *begin; /* beginning of relevant substring */ chr *end; /* end of same */ { struct dfa *d; int i; assert(t != NULL); assert(t->op == '|'); for (i = 0; t != NULL; t = t->right, i++) { MDEBUG(("trying %dth\n", i)); assert(t->left != NULL && t->left->cnfa.nstates > 0); d = newdfa(v, &t->left->cnfa, &v->g->cmap, &v->dfa1); if (ISERR()) return v->err; if (longest(v, d, begin, end, (int *)NULL) == end) { MDEBUG(("success\n")); freedfa(d); return dissect(v, t->left, begin, end); } freedfa(d); } return REG_ASSERT; /* none of them matched?!? */ } /* - cdissect - determine subexpression matches (with complications) * The retry memory stores the offset of the trial midpoint from begin, * plus 1 so that 0 uniquely means "clean slate". ^ static int cdissect(struct vars *, struct subre *, chr *, chr *); */ static int /* regexec return code */ cdissect(v, t, begin, end) struct vars *v; struct subre *t; chr *begin; /* beginning of relevant substring */ chr *end; /* end of same */ { int er; assert(t != NULL); MDEBUG(("cdissect %ld-%ld %c\n", LOFF(begin), LOFF(end), t->op)); switch (t->op) { case '=': /* terminal node */ assert(t->left == NULL && t->right == NULL); return REG_OKAY; /* no action, parent did the work */ break; case '|': /* alternation */ assert(t->left != NULL); return caltdissect(v, t, begin, end); break; case 'b': /* back ref -- shouldn't be calling us! */ assert(t->left == NULL && t->right == NULL); return cbrdissect(v, t, begin, end); break; case '.': /* concatenation */ assert(t->left != NULL && t->right != NULL); return ccondissect(v, t, begin, end); break; case '(': /* capturing */ assert(t->left != NULL && t->right == NULL); assert(t->subno > 0); er = cdissect(v, t->left, begin, end); if (er == REG_OKAY) subset(v, t, begin, end); return er; break; default: return REG_ASSERT; break; } } /* - ccondissect - concatenation subexpression matches (with complications) * The retry memory stores the offset of the trial midpoint from begin, * plus 1 so that 0 uniquely means "clean slate". ^ static int ccondissect(struct vars *, struct subre *, chr *, chr *); */ static int /* regexec return code */ ccondissect(v, t, begin, end) struct vars *v; struct subre *t; chr *begin; /* beginning of relevant substring */ chr *end; /* end of same */ { struct dfa *d; struct dfa *d2; chr *mid; int er; assert(t->op == '.'); assert(t->left != NULL && t->left->cnfa.nstates > 0); assert(t->right != NULL && t->right->cnfa.nstates > 0); if (t->left->flags&SHORTER) /* reverse scan */ return crevdissect(v, t, begin, end); d = newdfa(v, &t->left->cnfa, &v->g->cmap, DOMALLOC); if (ISERR()) return v->err; d2 = newdfa(v, &t->right->cnfa, &v->g->cmap, DOMALLOC); if (ISERR()) { freedfa(d); return v->err; } MDEBUG(("cconcat %d\n", t->retry)); /* pick a tentative midpoint */ if (v->mem[t->retry] == 0) { mid = longest(v, d, begin, end, (int *)NULL); if (mid == NULL) { freedfa(d); freedfa(d2); return REG_NOMATCH; } MDEBUG(("tentative midpoint %ld\n", LOFF(mid))); v->mem[t->retry] = (mid - begin) + 1; } else { mid = begin + (v->mem[t->retry] - 1); MDEBUG(("working midpoint %ld\n", LOFF(mid))); } /* iterate until satisfaction or failure */ for (;;) { /* try this midpoint on for size */ if (longest(v, d2, mid, end, NULL) == end) { er = cdissect(v, t->left, begin, mid); if (er == REG_OKAY) { er = cdissect(v, t->right, mid, end); if (er == REG_OKAY) { /* satisfaction */ MDEBUG(("successful\n")); freedfa(d); freedfa(d2); return REG_OKAY; } } if ((er != REG_OKAY) && (er != REG_NOMATCH)) { freedfa(d); freedfa(d2); return er; } } /* that midpoint didn't work, find a new one */ if (mid == begin) { /* all possibilities exhausted */ MDEBUG(("%d no midpoint\n", t->retry)); freedfa(d); freedfa(d2); return REG_NOMATCH; } mid = longest(v, d, begin, mid-1, (int *)NULL); if (mid == NULL) { /* failed to find a new one */ MDEBUG(("%d failed midpoint\n", t->retry)); freedfa(d); freedfa(d2); return REG_NOMATCH; } MDEBUG(("%d: new midpoint %ld\n", t->retry, LOFF(mid))); v->mem[t->retry] = (mid - begin) + 1; zapmem(v, t->left); zapmem(v, t->right); } } /* - crevdissect - determine backref shortest-first subexpression matches * The retry memory stores the offset of the trial midpoint from begin, * plus 1 so that 0 uniquely means "clean slate". ^ static int crevdissect(struct vars *, struct subre *, chr *, chr *); */ static int /* regexec return code */ crevdissect(v, t, begin, end) struct vars *v; struct subre *t; chr *begin; /* beginning of relevant substring */ chr *end; /* end of same */ { struct dfa *d; struct dfa *d2; chr *mid; int er; assert(t->op == '.'); assert(t->left != NULL && t->left->cnfa.nstates > 0); assert(t->right != NULL && t->right->cnfa.nstates > 0); assert(t->left->flags&SHORTER); /* concatenation -- need to split the substring between parts */ d = newdfa(v, &t->left->cnfa, &v->g->cmap, DOMALLOC); if (ISERR()) return v->err; d2 = newdfa(v, &t->right->cnfa, &v->g->cmap, DOMALLOC); if (ISERR()) { freedfa(d); return v->err; } MDEBUG(("crev %d\n", t->retry)); /* pick a tentative midpoint */ if (v->mem[t->retry] == 0) { mid = shortest(v, d, begin, begin, end, (chr **)NULL, (int *)NULL); if (mid == NULL) { freedfa(d); freedfa(d2); return REG_NOMATCH; } MDEBUG(("tentative midpoint %ld\n", LOFF(mid))); v->mem[t->retry] = (mid - begin) + 1; } else { mid = begin + (v->mem[t->retry] - 1); MDEBUG(("working midpoint %ld\n", LOFF(mid))); } /* iterate until satisfaction or failure */ for (;;) { /* try this midpoint on for size */ if (longest(v, d2, mid, end, NULL) == end) { er = cdissect(v, t->left, begin, mid); if (er == REG_OKAY) { er = cdissect(v, t->right, mid, end); if (er == REG_OKAY) { /* satisfaction */ MDEBUG(("successful\n")); freedfa(d); freedfa(d2); return REG_OKAY; } } if (er != REG_OKAY && er != REG_NOMATCH) { freedfa(d); freedfa(d2); return er; } } /* that midpoint didn't work, find a new one */ if (mid == end) { /* all possibilities exhausted */ MDEBUG(("%d no midpoint\n", t->retry)); freedfa(d); freedfa(d2); return REG_NOMATCH; } mid = shortest(v, d, begin, mid+1, end, (chr **)NULL, (int *)NULL); if (mid == NULL) { /* failed to find a new one */ MDEBUG(("%d failed midpoint\n", t->retry)); freedfa(d); freedfa(d2); return REG_NOMATCH; } MDEBUG(("%d: new midpoint %ld\n", t->retry, LOFF(mid))); v->mem[t->retry] = (mid - begin) + 1; zapmem(v, t->left); zapmem(v, t->right); } } /* - cbrdissect - determine backref subexpression matches ^ static int cbrdissect(struct vars *, struct subre *, chr *, chr *); */ static int /* regexec return code */ cbrdissect(v, t, begin, end) struct vars *v; struct subre *t; chr *begin; /* beginning of relevant substring */ chr *end; /* end of same */ { int i; int n = t->subno; size_t len; chr *paren; chr *p; chr *stop; int min = t->min; int max = t->max; assert(t != NULL); assert(t->op == 'b'); assert(n >= 0); assert((size_t)n < v->nmatch); MDEBUG(("cbackref n%d %d{%d-%d}\n", t->retry, n, min, max)); if (v->pmatch[n].rm_so == -1) return REG_NOMATCH; paren = v->start + v->pmatch[n].rm_so; len = v->pmatch[n].rm_eo - v->pmatch[n].rm_so; /* no room to maneuver -- retries are pointless */ if (v->mem[t->retry]) return REG_NOMATCH; v->mem[t->retry] = 1; /* special-case zero-length string */ if (len == 0) { if (begin == end) return REG_OKAY; return REG_NOMATCH; } /* and too-short string */ assert(end >= begin); if ((size_t)(end - begin) < len) return REG_NOMATCH; stop = end - len; /* count occurrences */ i = 0; for (p = begin; p <= stop && (i < max || max == INFINITY); p += len) { if ((*v->g->compare)(paren, p, len) != 0) break; i++; } MDEBUG(("cbackref found %d\n", i)); /* and sort it out */ if (p != end) /* didn't consume all of it */ return REG_NOMATCH; if (min <= i && (i <= max || max == INFINITY)) return REG_OKAY; return REG_NOMATCH; /* out of range */ } /* - caltdissect - determine alternative subexpression matches (w. complications) ^ static int caltdissect(struct vars *, struct subre *, chr *, chr *); */ static int /* regexec return code */ caltdissect(v, t, begin, end) struct vars *v; struct subre *t; chr *begin; /* beginning of relevant substring */ chr *end; /* end of same */ { struct dfa *d; int er; # define UNTRIED 0 /* not yet tried at all */ # define TRYING 1 /* top matched, trying submatches */ # define TRIED 2 /* top didn't match or submatches exhausted */ if (t == NULL) return REG_NOMATCH; assert(t->op == '|'); if (v->mem[t->retry] == TRIED) return caltdissect(v, t->right, begin, end); MDEBUG(("calt n%d\n", t->retry)); assert(t->left != NULL); if (v->mem[t->retry] == UNTRIED) { d = newdfa(v, &t->left->cnfa, &v->g->cmap, DOMALLOC); if (ISERR()) return v->err; if (longest(v, d, begin, end, (int *)NULL) != end) { freedfa(d); v->mem[t->retry] = TRIED; return caltdissect(v, t->right, begin, end); } freedfa(d); MDEBUG(("calt matched\n")); v->mem[t->retry] = TRYING; } er = cdissect(v, t->left, begin, end); if (er != REG_NOMATCH) return er; v->mem[t->retry] = TRIED; return caltdissect(v, t->right, begin, end); } #include "rege_dfa.c" tcl8.4.20/generic/regerrs.h0000644003604700454610000000224412133546537014156 0ustar dgp771div{ REG_OKAY, "REG_OKAY", "no errors detected" }, { REG_NOMATCH, "REG_NOMATCH", "failed to match" }, { REG_BADPAT, "REG_BADPAT", "invalid regexp (reg version 0.8)" }, { REG_ECOLLATE, "REG_ECOLLATE", "invalid collating element" }, { REG_ECTYPE, "REG_ECTYPE", "invalid character class" }, { REG_EESCAPE, "REG_EESCAPE", "invalid escape \\ sequence" }, { REG_ESUBREG, "REG_ESUBREG", "invalid backreference number" }, { REG_EBRACK, "REG_EBRACK", "brackets [] not balanced" }, { REG_EPAREN, "REG_EPAREN", "parentheses () not balanced" }, { REG_EBRACE, "REG_EBRACE", "braces {} not balanced" }, { REG_BADBR, "REG_BADBR", "invalid repetition count(s)" }, { REG_ERANGE, "REG_ERANGE", "invalid character range" }, { REG_ESPACE, "REG_ESPACE", "out of memory" }, { REG_BADRPT, "REG_BADRPT", "quantifier operand invalid" }, { REG_ASSERT, "REG_ASSERT", "\"can't happen\" -- you found a bug" }, { REG_INVARG, "REG_INVARG", "invalid argument to regex function" }, { REG_MIXED, "REG_MIXED", "character widths of regex and string differ" }, { REG_BADOPT, "REG_BADOPT", "invalid embedded option" }, { REG_ETOOBIG, "REG_ETOOBIG", "nfa has too many states" }, { REG_ECOLORS, "REG_ECOLORS", "too many colors" }, tcl8.4.20/generic/tclIO.c0000644003604700454610000105561612133546540013520 0ustar dgp771div/* * tclIO.c -- * * This file provides the generic portions (those that are the same on * all platforms and for all channel types) of Tcl's IO facilities. * * Copyright (c) 1998-2000 Ajuba Solutions * Copyright (c) 1995-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" #include "tclIO.h" #include #ifndef TCL_INHERIT_STD_CHANNELS #define TCL_INHERIT_STD_CHANNELS 1 #endif /* * For each channel handler registered in a call to Tcl_CreateChannelHandler, * there is one record of the following type. All of records for a specific * channel are chained together in a singly linked list which is stored in * the channel structure. */ typedef struct ChannelHandler { Channel *chanPtr; /* The channel structure for this channel. */ int mask; /* Mask of desired events. */ Tcl_ChannelProc *proc; /* Procedure to call in the type of * Tcl_CreateChannelHandler. */ ClientData clientData; /* Argument to pass to procedure. */ struct ChannelHandler *nextPtr; /* Next one in list of registered handlers. */ } ChannelHandler; /* * This structure keeps track of the current ChannelHandler being invoked in * the current invocation of ChannelHandlerEventProc. There is a potential * problem if a ChannelHandler is deleted while it is the current one, since * ChannelHandlerEventProc needs to look at the nextPtr field. To handle this * problem, structures of the type below indicate the next handler to be * processed for any (recursively nested) dispatches in progress. The * nextHandlerPtr field is updated if the handler being pointed to is deleted. * The nextPtr field is used to chain together all recursive invocations, so * that Tcl_DeleteChannelHandler can find all the recursively nested * invocations of ChannelHandlerEventProc and compare the handler being * deleted against the NEXT handler to be invoked in that invocation; when it * finds such a situation, Tcl_DeleteChannelHandler updates the nextHandlerPtr * field of the structure to the next handler. */ typedef struct NextChannelHandler { ChannelHandler *nextHandlerPtr; /* The next handler to be invoked in * this invocation. */ struct NextChannelHandler *nestedHandlerPtr; /* Next nested invocation of * ChannelHandlerEventProc. */ } NextChannelHandler; /* * The following structure describes the event that is added to the Tcl * event queue by the channel handler check procedure. */ typedef struct ChannelHandlerEvent { Tcl_Event header; /* Standard header for all events. */ Channel *chanPtr; /* The channel that is ready. */ int readyMask; /* Events that have occurred. */ } ChannelHandlerEvent; /* * The following structure is used by Tcl_GetsObj() to encapsulates the * state for a "gets" operation. */ typedef struct GetsState { Tcl_Obj *objPtr; /* The object to which UTF-8 characters * will be appended. */ char **dstPtr; /* Pointer into objPtr's string rep where * next character should be stored. */ Tcl_Encoding encoding; /* The encoding to use to convert raw bytes * to UTF-8. */ ChannelBuffer *bufPtr; /* The current buffer of raw bytes being * emptied. */ Tcl_EncodingState state; /* The encoding state just before the last * external to UTF-8 conversion in * FilterInputBytes(). */ int rawRead; /* The number of bytes removed from bufPtr * in the last call to FilterInputBytes(). */ int bytesWrote; /* The number of bytes of UTF-8 data * appended to objPtr during the last call to * FilterInputBytes(). */ int charsWrote; /* The corresponding number of UTF-8 * characters appended to objPtr during the * last call to FilterInputBytes(). */ int totalChars; /* The total number of UTF-8 characters * appended to objPtr so far, just before the * last call to FilterInputBytes(). */ } GetsState; /* * The following structure encapsulates the state for a background channel * copy. Note that the data buffer for the copy will be appended to this * structure. */ typedef struct CopyState { struct Channel *readPtr; /* Pointer to input channel. */ struct Channel *writePtr; /* Pointer to output channel. */ int readFlags; /* Original read channel flags. */ int writeFlags; /* Original write channel flags. */ int toRead; /* Number of bytes to copy, or -1. */ int total; /* Total bytes transferred (written). */ Tcl_Interp *interp; /* Interp that started the copy. */ Tcl_Obj *cmdPtr; /* Command to be invoked at completion. */ int bufSize; /* Size of appended buffer. */ char buffer[1]; /* Copy buffer, this must be the last * field. */ } CopyState; /* * All static variables used in this file are collected into a single * instance of the following structure. For multi-threaded implementations, * there is one instance of this structure for each thread. * * Notice that different structures with the same name appear in other * files. The structure defined below is used in this file only. */ typedef struct ThreadSpecificData { /* * This variable holds the list of nested ChannelHandlerEventProc * invocations. */ NextChannelHandler *nestedHandlerPtr; /* * List of all channels currently open, indexed by ChannelState, * as only one ChannelState exists per set of stacked channels. */ ChannelState *firstCSPtr; #ifdef oldcode /* * Has a channel exit handler been created yet? */ int channelExitHandlerCreated; /* * Has the channel event source been created and registered with the * notifier? */ int channelEventSourceCreated; #endif /* * Static variables to hold channels for stdin, stdout and stderr. */ Tcl_Channel stdinChannel; int stdinInitialized; Tcl_Channel stdoutChannel; int stdoutInitialized; Tcl_Channel stderrChannel; int stderrInitialized; } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; /* * Structure to record a close callback. One such record exists for * each close callback registered for a channel. */ typedef struct CloseCallback { Tcl_CloseProc *proc; /* The procedure to call. */ ClientData clientData; /* Arbitrary one-word data to pass * to the callback. */ struct CloseCallback *nextPtr; /* For chaining close callbacks. */ } CloseCallback; /* * Static functions in this file: */ static ChannelBuffer * AllocChannelBuffer _ANSI_ARGS_((int length)); static void ChannelTimerProc _ANSI_ARGS_(( ClientData clientData)); static int CheckChannelErrors _ANSI_ARGS_((ChannelState *statePtr, int direction)); static int CheckFlush _ANSI_ARGS_((Channel *chanPtr, ChannelBuffer *bufPtr, int newlineFlag)); static int CheckForDeadChannel _ANSI_ARGS_((Tcl_Interp *interp, ChannelState *statePtr)); static void CheckForStdChannelsBeingClosed _ANSI_ARGS_(( Tcl_Channel chan)); static void CleanupChannelHandlers _ANSI_ARGS_(( Tcl_Interp *interp, Channel *chanPtr)); static int CloseChannel _ANSI_ARGS_((Tcl_Interp *interp, Channel *chanPtr, int errorCode)); static void CommonGetsCleanup _ANSI_ARGS_((Channel *chanPtr, Tcl_Encoding encoding)); static int CopyAndTranslateBuffer _ANSI_ARGS_(( ChannelState *statePtr, char *result, int space)); static int CopyBuffer _ANSI_ARGS_(( Channel *chanPtr, char *result, int space)); static int CopyData _ANSI_ARGS_((CopyState *csPtr, int mask)); static void CopyEventProc _ANSI_ARGS_((ClientData clientData, int mask)); static void CreateScriptRecord _ANSI_ARGS_(( Tcl_Interp *interp, Channel *chanPtr, int mask, Tcl_Obj *scriptPtr)); static void DeleteChannelTable _ANSI_ARGS_(( ClientData clientData, Tcl_Interp *interp)); static void DeleteScriptRecord _ANSI_ARGS_((Tcl_Interp *interp, Channel *chanPtr, int mask)); static int DetachChannel _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Channel chan)); static void DiscardInputQueued _ANSI_ARGS_((ChannelState *statePtr, int discardSavedBuffers)); static void DiscardOutputQueued _ANSI_ARGS_(( ChannelState *chanPtr)); static int DoRead _ANSI_ARGS_((Channel *chanPtr, char *srcPtr, int slen)); static int DoWrite _ANSI_ARGS_((Channel *chanPtr, CONST char *src, int srcLen)); static int DoReadChars _ANSI_ARGS_ ((Channel* chan, Tcl_Obj* objPtr, int toRead, int appendFlag)); static int DoWriteChars _ANSI_ARGS_ ((Channel* chan, CONST char* src, int len)); static int FilterInputBytes _ANSI_ARGS_((Channel *chanPtr, GetsState *statePtr)); static int FlushChannel _ANSI_ARGS_((Tcl_Interp *interp, Channel *chanPtr, int calledFromAsyncFlush)); static Tcl_HashTable * GetChannelTable _ANSI_ARGS_((Tcl_Interp *interp)); static int GetInput _ANSI_ARGS_((Channel *chanPtr)); static int HaveVersion _ANSI_ARGS_((Tcl_ChannelType *typePtr, Tcl_ChannelTypeVersion minimumVersion)); static void PeekAhead _ANSI_ARGS_((Channel *chanPtr, char **dstEndPtr, GetsState *gsPtr)); static int ReadBytes _ANSI_ARGS_((ChannelState *statePtr, Tcl_Obj *objPtr, int charsLeft, int *offsetPtr)); static int ReadChars _ANSI_ARGS_((ChannelState *statePtr, Tcl_Obj *objPtr, int charsLeft, int *offsetPtr, int *factorPtr)); static void RecycleBuffer _ANSI_ARGS_((ChannelState *statePtr, ChannelBuffer *bufPtr, int mustDiscard)); static int StackSetBlockMode _ANSI_ARGS_((Channel *chanPtr, int mode)); static int SetBlockMode _ANSI_ARGS_((Tcl_Interp *interp, Channel *chanPtr, int mode)); static void StopCopy _ANSI_ARGS_((CopyState *csPtr)); static int TranslateInputEOL _ANSI_ARGS_((ChannelState *statePtr, char *dst, CONST char *src, int *dstLenPtr, int *srcLenPtr)); static int TranslateOutputEOL _ANSI_ARGS_((ChannelState *statePtr, char *dst, CONST char *src, int *dstLenPtr, int *srcLenPtr)); static void UpdateInterest _ANSI_ARGS_((Channel *chanPtr)); static int WriteBytes _ANSI_ARGS_((Channel *chanPtr, CONST char *src, int srcLen)); static int WriteChars _ANSI_ARGS_((Channel *chanPtr, CONST char *src, int srcLen)); #define BUSY_STATE(st,fl) \ ((((st)->csPtrR) && ((fl) & TCL_READABLE)) || \ (((st)->csPtrW) && ((fl) & TCL_WRITABLE))) #define MAX_CHANNEL_BUFFER_SIZE (1024*1024) /* *--------------------------------------------------------------------------- * * TclInitIOSubsystem -- * * Initialize all resources used by this subsystem on a per-process * basis. * * Results: * None. * * Side effects: * Depends on the memory subsystems. * *--------------------------------------------------------------------------- */ void TclInitIOSubsystem() { /* * By fetching thread local storage we take care of * allocating it for each thread. */ (void) TCL_TSD_INIT(&dataKey); } /* *------------------------------------------------------------------------- * * TclFinalizeIOSubsystem -- * * Releases all resources used by this subsystem on a per-thread * basis. Closes all extant channels that have not already been * closed because they were not owned by any interp. * * Results: * None. * * Side effects: * Depends on encoding and memory subsystems. * *------------------------------------------------------------------------- */ /* ARGSUSED */ void TclFinalizeIOSubsystem(void) { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); Channel *chanPtr = NULL; /* Iterates over open channels. */ ChannelState *statePtr; /* State of channel stack */ int active = 1; /* Flag == 1 while there's still work to do */ /* * Walk all channel state structures known to this thread and * close corresponding channels. */ while (active) { /* * Iterate through the open channel list, and find the first * channel that isn't dead. We start from the head of the list * each time, because the close action on one channel can close * others. */ active = 0; for (statePtr = tsdPtr->firstCSPtr; statePtr != NULL; statePtr = statePtr->nextCSPtr) { chanPtr = statePtr->topChanPtr; if (!(statePtr->flags & (CHANNEL_INCLOSE|CHANNEL_CLOSED|CHANNEL_DEAD))) { active = 1; break; } } /* * We've found a live channel. Close it. */ if (active) { /* * Set the channel back into blocking mode to ensure that we * wait for all data to flush out. */ (void) Tcl_SetChannelOption(NULL, (Tcl_Channel) chanPtr, "-blocking", "on"); if ((chanPtr == (Channel *) tsdPtr->stdinChannel) || (chanPtr == (Channel *) tsdPtr->stdoutChannel) || (chanPtr == (Channel *) tsdPtr->stderrChannel)) { /* * Decrement the refcount which was earlier artificially * bumped up to keep the channel from being closed. */ statePtr->refCount--; } if (statePtr->refCount <= 0) { /* * Close it only if the refcount indicates that the channel * is not referenced from any interpreter. If it is, that * interpreter will close the channel when it gets destroyed. */ (void) Tcl_Close(NULL, (Tcl_Channel) chanPtr); } else { /* * The refcount is greater than zero, so flush the channel. */ Tcl_Flush((Tcl_Channel) chanPtr); /* * Call the device driver to actually close the underlying * device for this channel. */ if (chanPtr->typePtr->closeProc != TCL_CLOSE2PROC) { (chanPtr->typePtr->closeProc)(chanPtr->instanceData, NULL); } else { (chanPtr->typePtr->close2Proc)(chanPtr->instanceData, NULL, 0); } /* * Finally, we clean up the fields in the channel data * structure since all of them have been deleted already. * We mark the channel with CHANNEL_DEAD to prevent any * further IO operations * on it. */ chanPtr->instanceData = NULL; statePtr->flags |= CHANNEL_DEAD; } } } TclpFinalizeSockets(); TclpFinalizePipes(); } /* *---------------------------------------------------------------------- * * Tcl_SetStdChannel -- * * This function is used to change the channels that are used * for stdin/stdout/stderr in new interpreters. * * Results: * None * * Side effects: * None. * *---------------------------------------------------------------------- */ void Tcl_SetStdChannel(channel, type) Tcl_Channel channel; int type; /* One of TCL_STDIN, TCL_STDOUT, TCL_STDERR. */ { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); switch (type) { case TCL_STDIN: tsdPtr->stdinInitialized = 1; tsdPtr->stdinChannel = channel; break; case TCL_STDOUT: tsdPtr->stdoutInitialized = 1; tsdPtr->stdoutChannel = channel; break; case TCL_STDERR: tsdPtr->stderrInitialized = 1; tsdPtr->stderrChannel = channel; break; } } /* *---------------------------------------------------------------------- * * Tcl_GetStdChannel -- * * Returns the specified standard channel. * * Results: * Returns the specified standard channel, or NULL. * * Side effects: * May cause the creation of a standard channel and the underlying * file. * *---------------------------------------------------------------------- */ Tcl_Channel Tcl_GetStdChannel(type) int type; /* One of TCL_STDIN, TCL_STDOUT, TCL_STDERR. */ { Tcl_Channel channel = NULL; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); /* * If the channels were not created yet, create them now and * store them in the static variables. */ switch (type) { case TCL_STDIN: if (!tsdPtr->stdinInitialized) { tsdPtr->stdinChannel = TclpGetDefaultStdChannel(TCL_STDIN); tsdPtr->stdinInitialized = 1; /* * Artificially bump the refcount to ensure that the channel * is only closed on exit. * * NOTE: Must only do this if stdinChannel is not NULL. It * can be NULL in situations where Tcl is unable to connect * to the standard input. */ if (tsdPtr->stdinChannel != (Tcl_Channel) NULL) { (void) Tcl_RegisterChannel((Tcl_Interp *) NULL, tsdPtr->stdinChannel); } } channel = tsdPtr->stdinChannel; break; case TCL_STDOUT: if (!tsdPtr->stdoutInitialized) { tsdPtr->stdoutChannel = TclpGetDefaultStdChannel(TCL_STDOUT); tsdPtr->stdoutInitialized = 1; if (tsdPtr->stdoutChannel != (Tcl_Channel) NULL) { (void) Tcl_RegisterChannel((Tcl_Interp *) NULL, tsdPtr->stdoutChannel); } } channel = tsdPtr->stdoutChannel; break; case TCL_STDERR: if (!tsdPtr->stderrInitialized) { tsdPtr->stderrChannel = TclpGetDefaultStdChannel(TCL_STDERR); tsdPtr->stderrInitialized = 1; if (tsdPtr->stderrChannel != (Tcl_Channel) NULL) { (void) Tcl_RegisterChannel((Tcl_Interp *) NULL, tsdPtr->stderrChannel); } } channel = tsdPtr->stderrChannel; break; } return channel; } /* *---------------------------------------------------------------------- * * Tcl_CreateCloseHandler * * Creates a close callback which will be called when the channel is * closed. * * Results: * None. * * Side effects: * Causes the callback to be called in the future when the channel * will be closed. * *---------------------------------------------------------------------- */ void Tcl_CreateCloseHandler(chan, proc, clientData) Tcl_Channel chan; /* The channel for which to create the * close callback. */ Tcl_CloseProc *proc; /* The callback routine to call when the * channel will be closed. */ ClientData clientData; /* Arbitrary data to pass to the * close callback. */ { ChannelState *statePtr; CloseCallback *cbPtr; statePtr = ((Channel *) chan)->state; cbPtr = (CloseCallback *) ckalloc((unsigned) sizeof(CloseCallback)); cbPtr->proc = proc; cbPtr->clientData = clientData; cbPtr->nextPtr = statePtr->closeCbPtr; statePtr->closeCbPtr = cbPtr; } /* *---------------------------------------------------------------------- * * Tcl_DeleteCloseHandler -- * * Removes a callback that would have been called on closing * the channel. If there is no matching callback then this * function has no effect. * * Results: * None. * * Side effects: * The callback will not be called in the future when the channel * is eventually closed. * *---------------------------------------------------------------------- */ void Tcl_DeleteCloseHandler(chan, proc, clientData) Tcl_Channel chan; /* The channel for which to cancel the * close callback. */ Tcl_CloseProc *proc; /* The procedure for the callback to * remove. */ ClientData clientData; /* The callback data for the callback * to remove. */ { ChannelState *statePtr; CloseCallback *cbPtr, *cbPrevPtr; statePtr = ((Channel *) chan)->state; for (cbPtr = statePtr->closeCbPtr, cbPrevPtr = (CloseCallback *) NULL; cbPtr != (CloseCallback *) NULL; cbPtr = cbPtr->nextPtr) { if ((cbPtr->proc == proc) && (cbPtr->clientData == clientData)) { if (cbPrevPtr == (CloseCallback *) NULL) { statePtr->closeCbPtr = cbPtr->nextPtr; } else { cbPrevPtr->nextPtr = cbPtr->nextPtr; } ckfree((char *) cbPtr); break; } else { cbPrevPtr = cbPtr; } } } /* *---------------------------------------------------------------------- * * GetChannelTable -- * * Gets and potentially initializes the channel table for an * interpreter. If it is initializing the table it also inserts * channels for stdin, stdout and stderr if the interpreter is * trusted. * * Results: * A pointer to the hash table created, for use by the caller. * * Side effects: * Initializes the channel table for an interpreter. May create * channels for stdin, stdout and stderr. * *---------------------------------------------------------------------- */ static Tcl_HashTable * GetChannelTable(interp) Tcl_Interp *interp; { Tcl_HashTable *hTblPtr; /* Hash table of channels. */ Tcl_Channel stdinChan, stdoutChan, stderrChan; hTblPtr = (Tcl_HashTable *) Tcl_GetAssocData(interp, "tclIO", NULL); if (hTblPtr == (Tcl_HashTable *) NULL) { hTblPtr = (Tcl_HashTable *) ckalloc((unsigned) sizeof(Tcl_HashTable)); Tcl_InitHashTable(hTblPtr, TCL_STRING_KEYS); (void) Tcl_SetAssocData(interp, "tclIO", (Tcl_InterpDeleteProc *) DeleteChannelTable, (ClientData) hTblPtr); /* * If the interpreter is trusted (not "safe"), insert channels * for stdin, stdout and stderr (possibly creating them in the * process). */ if (Tcl_IsSafe(interp) == 0) { stdinChan = Tcl_GetStdChannel(TCL_STDIN); if (stdinChan != NULL) { Tcl_RegisterChannel(interp, stdinChan); } stdoutChan = Tcl_GetStdChannel(TCL_STDOUT); if (stdoutChan != NULL) { Tcl_RegisterChannel(interp, stdoutChan); } stderrChan = Tcl_GetStdChannel(TCL_STDERR); if (stderrChan != NULL) { Tcl_RegisterChannel(interp, stderrChan); } } } return hTblPtr; } /* *---------------------------------------------------------------------- * * DeleteChannelTable -- * * Deletes the channel table for an interpreter, closing any open * channels whose refcount reaches zero. This procedure is invoked * when an interpreter is deleted, via the AssocData cleanup * mechanism. * * Results: * None. * * Side effects: * Deletes the hash table of channels. May close channels. May flush * output on closed channels. Removes any channeEvent handlers that were * registered in this interpreter. * *---------------------------------------------------------------------- */ static void DeleteChannelTable(clientData, interp) ClientData clientData; /* The per-interpreter data structure. */ Tcl_Interp *interp; /* The interpreter being deleted. */ { Tcl_HashTable *hTblPtr; /* The hash table. */ Tcl_HashSearch hSearch; /* Search variable. */ Tcl_HashEntry *hPtr; /* Search variable. */ Channel *chanPtr; /* Channel being deleted. */ ChannelState *statePtr; /* State of Channel being deleted. */ EventScriptRecord *sPtr, *prevPtr, *nextPtr; /* Variables to loop over all channel events * registered, to delete the ones that refer * to the interpreter being deleted. */ /* * Delete all the registered channels - this will close channels whose * refcount reaches zero. */ hTblPtr = (Tcl_HashTable *) clientData; for (hPtr = Tcl_FirstHashEntry(hTblPtr, &hSearch); hPtr != (Tcl_HashEntry *) NULL; hPtr = Tcl_FirstHashEntry(hTblPtr, &hSearch)) { chanPtr = (Channel *) Tcl_GetHashValue(hPtr); statePtr = chanPtr->state; /* * Remove any fileevents registered in this interpreter. */ for (sPtr = statePtr->scriptRecordPtr, prevPtr = (EventScriptRecord *) NULL; sPtr != (EventScriptRecord *) NULL; sPtr = nextPtr) { nextPtr = sPtr->nextPtr; if (sPtr->interp == interp) { if (prevPtr == (EventScriptRecord *) NULL) { statePtr->scriptRecordPtr = nextPtr; } else { prevPtr->nextPtr = nextPtr; } Tcl_DeleteChannelHandler((Tcl_Channel) chanPtr, TclChannelEventScriptInvoker, (ClientData) sPtr); Tcl_DecrRefCount(sPtr->scriptPtr); ckfree((char *) sPtr); } else { prevPtr = sPtr; } } /* * Cannot call Tcl_UnregisterChannel because that procedure calls * Tcl_GetAssocData to get the channel table, which might already * be inaccessible from the interpreter structure. Instead, we * emulate the behavior of Tcl_UnregisterChannel directly here. */ Tcl_DeleteHashEntry(hPtr); statePtr->refCount--; if (statePtr->refCount <= 0) { if (!(statePtr->flags & BG_FLUSH_SCHEDULED)) { (void) Tcl_Close(interp, (Tcl_Channel) chanPtr); } } } Tcl_DeleteHashTable(hTblPtr); ckfree((char *) hTblPtr); } /* *---------------------------------------------------------------------- * * CheckForStdChannelsBeingClosed -- * * Perform special handling for standard channels being closed. When * given a standard channel, if the refcount is now 1, it means that * the last reference to the standard channel is being explicitly * closed. Now bump the refcount artificially down to 0, to ensure the * normal handling of channels being closed will occur. Also reset the * static pointer to the channel to NULL, to avoid dangling references. * * Results: * None. * * Side effects: * Manipulates the refcount on standard channels. May smash the global * static pointer to a standard channel. * *---------------------------------------------------------------------- */ static void CheckForStdChannelsBeingClosed(chan) Tcl_Channel chan; { ChannelState *statePtr = ((Channel *) chan)->state; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (tsdPtr->stdinInitialized && tsdPtr->stdinChannel != NULL && statePtr == ((Channel *)tsdPtr->stdinChannel)->state) { if (statePtr->refCount < 2) { statePtr->refCount = 0; tsdPtr->stdinChannel = NULL; return; } } else if (tsdPtr->stdoutInitialized && tsdPtr->stdoutChannel != NULL && statePtr == ((Channel *)tsdPtr->stdoutChannel)->state) { if (statePtr->refCount < 2) { statePtr->refCount = 0; tsdPtr->stdoutChannel = NULL; return; } } else if (tsdPtr->stderrInitialized && tsdPtr->stderrChannel != NULL && statePtr == ((Channel *)tsdPtr->stderrChannel)->state) { if (statePtr->refCount < 2) { statePtr->refCount = 0; tsdPtr->stderrChannel = NULL; return; } } } /* *---------------------------------------------------------------------- * * Tcl_IsStandardChannel -- * * Test if the given channel is a standard channel. No attempt * is made to check if the channel or the standard channels * are initialized or otherwise valid. * * Results: * Returns 1 if true, 0 if false. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_IsStandardChannel(chan) Tcl_Channel chan; /* Channel to check. */ { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if ((chan == tsdPtr->stdinChannel) || (chan == tsdPtr->stdoutChannel) || (chan == tsdPtr->stderrChannel)) { return 1; } else { return 0; } } /* *---------------------------------------------------------------------- * * Tcl_RegisterChannel -- * * Adds an already-open channel to the channel table of an interpreter. * If the interpreter passed as argument is NULL, it only increments * the channel refCount. * * Results: * None. * * Side effects: * May increment the reference count of a channel. * *---------------------------------------------------------------------- */ void Tcl_RegisterChannel(interp, chan) Tcl_Interp *interp; /* Interpreter in which to add the channel. */ Tcl_Channel chan; /* The channel to add to this interpreter * channel table. */ { Tcl_HashTable *hTblPtr; /* Hash table of channels. */ Tcl_HashEntry *hPtr; /* Search variable. */ int new; /* Is the hash entry new or does it exist? */ Channel *chanPtr; /* The actual channel. */ ChannelState *statePtr; /* State of the actual channel. */ /* * Always (un)register bottom-most channel in the stack. This makes * management of the channel list easier because no manipulation is * necessary during (un)stack operation. */ chanPtr = ((Channel *) chan)->state->bottomChanPtr; statePtr = chanPtr->state; if (statePtr->channelName == (CONST char *) NULL) { panic("Tcl_RegisterChannel: channel without name"); } if (interp != (Tcl_Interp *) NULL) { hTblPtr = GetChannelTable(interp); hPtr = Tcl_CreateHashEntry(hTblPtr, statePtr->channelName, &new); if (new == 0) { if (chan == (Tcl_Channel) Tcl_GetHashValue(hPtr)) { return; } panic("Tcl_RegisterChannel: duplicate channel names"); } Tcl_SetHashValue(hPtr, (ClientData) chanPtr); } statePtr->refCount++; } /* *---------------------------------------------------------------------- * * Tcl_UnregisterChannel -- * * Deletes the hash entry for a channel associated with an interpreter. * If the interpreter given as argument is NULL, it only decrements the * reference count. (This all happens in the Tcl_DetachChannel helper * function). * * Finally, if the reference count of the channel drops to zero, * it is deleted. * * Results: * A standard Tcl result. * * Side effects: * Calls Tcl_DetachChannel which deletes the hash entry for a channel * associated with an interpreter. * * May delete the channel, which can have a variety of consequences, * especially if we are forced to close the channel. * *---------------------------------------------------------------------- */ int Tcl_UnregisterChannel(interp, chan) Tcl_Interp *interp; /* Interpreter in which channel is defined. */ Tcl_Channel chan; /* Channel to delete. */ { ChannelState *statePtr; /* State of the real channel. */ statePtr = ((Channel *) chan)->state->bottomChanPtr->state; if (statePtr->flags & CHANNEL_INCLOSE) { if (interp != (Tcl_Interp*) NULL) { Tcl_AppendResult(interp, "Illegal recursive call to close through close-handler of channel", (char *) NULL); } return TCL_ERROR; } if (DetachChannel(interp, chan) != TCL_OK) { return TCL_OK; } statePtr = ((Channel *) chan)->state->bottomChanPtr->state; /* * Perform special handling for standard channels being closed. If the * refCount is now 1 it means that the last reference to the standard * channel is being explicitly closed, so bump the refCount down * artificially to 0. This will ensure that the channel is actually * closed, below. Also set the static pointer to NULL for the channel. */ CheckForStdChannelsBeingClosed(chan); /* * If the refCount reached zero, close the actual channel. */ if (statePtr->refCount <= 0) { /* * Ensure that if there is another buffer, it gets flushed * whether or not we are doing a background flush. */ if ((statePtr->curOutPtr != NULL) && (statePtr->curOutPtr->nextAdded > statePtr->curOutPtr->nextRemoved)) { statePtr->flags |= BUFFER_READY; } Tcl_Preserve((ClientData)statePtr); if (!(statePtr->flags & BG_FLUSH_SCHEDULED)) { /* We don't want to re-enter Tcl_Close */ if (!(statePtr->flags & CHANNEL_CLOSED)) { if (Tcl_Close(interp, chan) != TCL_OK) { statePtr->flags |= CHANNEL_CLOSED; Tcl_Release((ClientData)statePtr); return TCL_ERROR; } } } statePtr->flags |= CHANNEL_CLOSED; Tcl_Release((ClientData)statePtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_DetachChannel -- * * Deletes the hash entry for a channel associated with an interpreter. * If the interpreter given as argument is NULL, it only decrements the * reference count. Even if the ref count drops to zero, the * channel is NOT closed or cleaned up. This allows a channel to * be detached from an interpreter and left in the same state it * was in when it was originally returned by 'Tcl_OpenFileChannel', * for example. * * This function cannot be used on the standard channels, and * will return TCL_ERROR if that is attempted. * * This function should only be necessary for special purposes * in which you need to generate a pristine channel from one * that has already been used. All ordinary purposes will almost * always want to use Tcl_UnregisterChannel instead. * * Provided the channel is not attached to any other interpreter, * it can then be closed with Tcl_Close, rather than with * Tcl_UnregisterChannel. * * Results: * A standard Tcl result. If the channel is not currently registered * with the given interpreter, TCL_ERROR is returned, otherwise * TCL_OK. However no error messages are left in the interp's result. * * Side effects: * Deletes the hash entry for a channel associated with an * interpreter. * *---------------------------------------------------------------------- */ int Tcl_DetachChannel(interp, chan) Tcl_Interp *interp; /* Interpreter in which channel is defined. */ Tcl_Channel chan; /* Channel to delete. */ { if (Tcl_IsStandardChannel(chan)) { return TCL_ERROR; } return DetachChannel(interp, chan); } /* *---------------------------------------------------------------------- * * DetachChannel -- * * Deletes the hash entry for a channel associated with an interpreter. * If the interpreter given as argument is NULL, it only decrements the * reference count. Even if the ref count drops to zero, the * channel is NOT closed or cleaned up. This allows a channel to * be detached from an interpreter and left in the same state it * was in when it was originally returned by 'Tcl_OpenFileChannel', * for example. * * Results: * A standard Tcl result. If the channel is not currently registered * with the given interpreter, TCL_ERROR is returned, otherwise * TCL_OK. However no error messages are left in the interp's result. * * Side effects: * Deletes the hash entry for a channel associated with an * interpreter. * *---------------------------------------------------------------------- */ static int DetachChannel(interp, chan) Tcl_Interp *interp; /* Interpreter in which channel is defined. */ Tcl_Channel chan; /* Channel to delete. */ { Tcl_HashTable *hTblPtr; /* Hash table of channels. */ Tcl_HashEntry *hPtr; /* Search variable. */ Channel *chanPtr; /* The real IO channel. */ ChannelState *statePtr; /* State of the real channel. */ /* * Always (un)register bottom-most channel in the stack. This makes * management of the channel list easier because no manipulation is * necessary during (un)stack operation. */ chanPtr = ((Channel *) chan)->state->bottomChanPtr; statePtr = chanPtr->state; if (interp != (Tcl_Interp *) NULL) { hTblPtr = (Tcl_HashTable *) Tcl_GetAssocData(interp, "tclIO", NULL); if (hTblPtr == (Tcl_HashTable *) NULL) { return TCL_ERROR; } hPtr = Tcl_FindHashEntry(hTblPtr, statePtr->channelName); if (hPtr == (Tcl_HashEntry *) NULL) { return TCL_ERROR; } if ((Channel *) Tcl_GetHashValue(hPtr) != chanPtr) { return TCL_ERROR; } Tcl_DeleteHashEntry(hPtr); /* * Remove channel handlers that refer to this interpreter, so that they * will not be present if the actual close is delayed and more events * happen on the channel. This may occur if the channel is shared * between several interpreters, or if the channel has async * flushing active. */ CleanupChannelHandlers(interp, chanPtr); } statePtr->refCount--; return TCL_OK; } /* *--------------------------------------------------------------------------- * * Tcl_GetChannel -- * * Finds an existing Tcl_Channel structure by name in a given * interpreter. This function is public because it is used by * channel-type-specific functions. * * Results: * A Tcl_Channel or NULL on failure. If failed, interp's result * object contains an error message. *modePtr is filled with the * modes in which the channel was opened. * * Side effects: * None. * *--------------------------------------------------------------------------- */ Tcl_Channel Tcl_GetChannel(interp, chanName, modePtr) Tcl_Interp *interp; /* Interpreter in which to find or create * the channel. */ CONST char *chanName; /* The name of the channel. */ int *modePtr; /* Where to store the mode in which the * channel was opened? Will contain an ORed * combination of TCL_READABLE and * TCL_WRITABLE, if non-NULL. */ { Channel *chanPtr; /* The actual channel. */ Tcl_HashTable *hTblPtr; /* Hash table of channels. */ Tcl_HashEntry *hPtr; /* Search variable. */ CONST char *name; /* Translated name. */ /* * Substitute "stdin", etc. Note that even though we immediately * find the channel using Tcl_GetStdChannel, we still need to look * it up in the specified interpreter to ensure that it is present * in the channel table. Otherwise, safe interpreters would always * have access to the standard channels. */ name = chanName; if ((chanName[0] == 's') && (chanName[1] == 't')) { chanPtr = NULL; if (strcmp(chanName, "stdin") == 0) { chanPtr = (Channel *) Tcl_GetStdChannel(TCL_STDIN); } else if (strcmp(chanName, "stdout") == 0) { chanPtr = (Channel *) Tcl_GetStdChannel(TCL_STDOUT); } else if (strcmp(chanName, "stderr") == 0) { chanPtr = (Channel *) Tcl_GetStdChannel(TCL_STDERR); } if (chanPtr != NULL) { name = chanPtr->state->channelName; } } hTblPtr = GetChannelTable(interp); hPtr = Tcl_FindHashEntry(hTblPtr, name); if (hPtr == (Tcl_HashEntry *) NULL) { Tcl_AppendResult(interp, "can not find channel named \"", chanName, "\"", (char *) NULL); return NULL; } /* * Always return bottom-most channel in the stack. This one lives * the longest - other channels may go away unnoticed. * The other APIs compensate where necessary to retrieve the * topmost channel again. */ chanPtr = (Channel *) Tcl_GetHashValue(hPtr); chanPtr = chanPtr->state->bottomChanPtr; if (modePtr != NULL) { *modePtr = (chanPtr->state->flags & (TCL_READABLE|TCL_WRITABLE)); } return (Tcl_Channel) chanPtr; } /* *---------------------------------------------------------------------- * * Tcl_CreateChannel -- * * Creates a new entry in the hash table for a Tcl_Channel * record. * * Results: * Returns the new Tcl_Channel. * * Side effects: * Creates a new Tcl_Channel instance and inserts it into the * hash table. * *---------------------------------------------------------------------- */ Tcl_Channel Tcl_CreateChannel(typePtr, chanName, instanceData, mask) Tcl_ChannelType *typePtr; /* The channel type record. */ CONST char *chanName; /* Name of channel to record. */ ClientData instanceData; /* Instance specific data. */ int mask; /* TCL_READABLE & TCL_WRITABLE to indicate * if the channel is readable, writable. */ { Channel *chanPtr; /* The channel structure newly created. */ ChannelState *statePtr; /* The stack-level independent state info * for the channel. */ CONST char *name; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); /* * With the change of the Tcl_ChannelType structure to use a version in * 8.3.2+, we have to make sure that our assumption that the structure * remains a binary compatible size is true. * * If this assertion fails on some system, then it can be removed * only if the user recompiles code with older channel drivers in * the new system as well. */ assert(sizeof(Tcl_ChannelTypeVersion) == sizeof(Tcl_DriverBlockModeProc*)); /* * JH: We could subsequently memset these to 0 to avoid the * numerous assignments to 0/NULL below. */ chanPtr = (Channel *) ckalloc((unsigned) sizeof(Channel)); statePtr = (ChannelState *) ckalloc((unsigned) sizeof(ChannelState)); chanPtr->state = statePtr; chanPtr->instanceData = instanceData; chanPtr->typePtr = typePtr; /* * Set all the bits that are part of the stack-independent state * information for the channel. */ if (chanName != (char *) NULL) { char *tmp = ckalloc((unsigned) (strlen(chanName) + 1)); statePtr->channelName = tmp; strcpy(tmp, chanName); } else { panic("Tcl_CreateChannel: NULL channel name"); } statePtr->flags = mask; /* * Set the channel to system default encoding. */ statePtr->encoding = NULL; name = Tcl_GetEncodingName(NULL); if (strcmp(name, "binary") != 0) { statePtr->encoding = Tcl_GetEncoding(NULL, name); } statePtr->inputEncodingState = NULL; statePtr->inputEncodingFlags = TCL_ENCODING_START; statePtr->outputEncodingState = NULL; statePtr->outputEncodingFlags = TCL_ENCODING_START; /* * Set the channel up initially in AUTO input translation mode to * accept "\n", "\r" and "\r\n". Output translation mode is set to * a platform specific default value. The eofChar is set to 0 for both * input and output, so that Tcl does not look for an in-file EOF * indicator (e.g. ^Z) and does not append an EOF indicator to files. */ statePtr->inputTranslation = TCL_TRANSLATE_AUTO; statePtr->outputTranslation = TCL_PLATFORM_TRANSLATION; statePtr->inEofChar = 0; statePtr->outEofChar = 0; statePtr->unreportedError = 0; statePtr->refCount = 0; statePtr->closeCbPtr = (CloseCallback *) NULL; statePtr->curOutPtr = (ChannelBuffer *) NULL; statePtr->outQueueHead = (ChannelBuffer *) NULL; statePtr->outQueueTail = (ChannelBuffer *) NULL; statePtr->saveInBufPtr = (ChannelBuffer *) NULL; statePtr->inQueueHead = (ChannelBuffer *) NULL; statePtr->inQueueTail = (ChannelBuffer *) NULL; statePtr->chPtr = (ChannelHandler *) NULL; statePtr->interestMask = 0; statePtr->scriptRecordPtr = (EventScriptRecord *) NULL; statePtr->bufSize = CHANNELBUFFER_DEFAULT_SIZE; statePtr->timer = NULL; statePtr->csPtrR = NULL; statePtr->csPtrW = NULL; statePtr->outputStage = NULL; if ((statePtr->encoding != NULL) && (statePtr->flags & TCL_WRITABLE)) { statePtr->outputStage = (char *) ckalloc((unsigned) (statePtr->bufSize + 2)); } /* * As we are creating the channel, it is obviously the top for now */ statePtr->topChanPtr = chanPtr; statePtr->bottomChanPtr = chanPtr; chanPtr->downChanPtr = (Channel *) NULL; chanPtr->upChanPtr = (Channel *) NULL; chanPtr->inQueueHead = (ChannelBuffer*) NULL; chanPtr->inQueueTail = (ChannelBuffer*) NULL; /* * Link the channel into the list of all channels; create an on-exit * handler if there is not one already, to close off all the channels * in the list on exit. * * JH: Could call Tcl_SpliceChannel, but need to avoid NULL check. * * TIP #218. * AK: Just initialize the field to NULL before invoking Tcl_SpliceChannel * We need Tcl_SpliceChannel, for the threadAction calls. * There is no real reason to duplicate all of this. * NOTE: All drivers using thread actions now have to perform their TSD * manipulation only in their thread action proc. Doing it when * creating their instance structures will collide with the thread * action activity and lead to damaged lists. */ statePtr->nextCSPtr = (ChannelState *) NULL; Tcl_SpliceChannel ((Tcl_Channel) chanPtr); /* * Install this channel in the first empty standard channel slot, if * the channel was previously closed explicitly. */ #if TCL_INHERIT_STD_CHANNELS if ((tsdPtr->stdinChannel == NULL) && (tsdPtr->stdinInitialized == 1)) { Tcl_SetStdChannel((Tcl_Channel) chanPtr, TCL_STDIN); Tcl_RegisterChannel((Tcl_Interp *) NULL, (Tcl_Channel) chanPtr); } else if ((tsdPtr->stdoutChannel == NULL) && (tsdPtr->stdoutInitialized == 1)) { Tcl_SetStdChannel((Tcl_Channel) chanPtr, TCL_STDOUT); Tcl_RegisterChannel((Tcl_Interp *) NULL, (Tcl_Channel) chanPtr); } else if ((tsdPtr->stderrChannel == NULL) && (tsdPtr->stderrInitialized == 1)) { Tcl_SetStdChannel((Tcl_Channel) chanPtr, TCL_STDERR); Tcl_RegisterChannel((Tcl_Interp *) NULL, (Tcl_Channel) chanPtr); } #endif return (Tcl_Channel) chanPtr; } /* *---------------------------------------------------------------------- * * Tcl_StackChannel -- * * Replaces an entry in the hash table for a Tcl_Channel * record. The replacement is a new channel with same name, * it supercedes the replaced channel. Input and output of * the superceded channel is now going through the newly * created channel and allows the arbitrary filtering/manipulation * of the dataflow. * * Andreas Kupries , 12/13/1998 * "Trf-Patch for filtering channels" * * Results: * Returns the new Tcl_Channel, which actually contains the * saved information about prevChan. * * Side effects: * A new channel structure is allocated and linked below * the existing channel. The channel operations and client * data of the existing channel are copied down to the newly * created channel, and the current channel has its operations * replaced by the new typePtr. * *---------------------------------------------------------------------- */ Tcl_Channel Tcl_StackChannel(interp, typePtr, instanceData, mask, prevChan) Tcl_Interp *interp; /* The interpreter we are working in */ Tcl_ChannelType *typePtr; /* The channel type record for the new * channel. */ ClientData instanceData; /* Instance specific data for the new * channel. */ int mask; /* TCL_READABLE & TCL_WRITABLE to indicate * if the channel is readable, writable. */ Tcl_Channel prevChan; /* The channel structure to replace */ { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); Channel *chanPtr, *prevChanPtr; ChannelState *statePtr; /* * Find the given channel in the list of all channels. * If we don't find it, then it was never registered correctly. * * This operation should occur at the top of a channel stack. */ statePtr = (ChannelState *) tsdPtr->firstCSPtr; prevChanPtr = ((Channel *) prevChan)->state->topChanPtr; while ((statePtr != NULL) && (statePtr->topChanPtr != prevChanPtr)) { statePtr = statePtr->nextCSPtr; } if (statePtr == NULL) { if (interp) { Tcl_AppendResult(interp, "couldn't find state for channel \"", Tcl_GetChannelName(prevChan), "\"", (char *) NULL); } return (Tcl_Channel) NULL; } /* * Here we check if the given "mask" matches the "flags" * of the already existing channel. * * | - | R | W | RW | * --+---+---+---+----+ <=> 0 != (chan->mask & prevChan->mask) * - | | | | | * R | | + | | + | The superceding channel is allowed to * W | | | + | + | restrict the capabilities of the * RW| | + | + | + | superceded one ! * --+---+---+---+----+ */ if ((mask & (statePtr->flags & (TCL_READABLE | TCL_WRITABLE))) == 0) { if (interp) { Tcl_AppendResult(interp, "reading and writing both disallowed for channel \"", Tcl_GetChannelName(prevChan), "\"", (char *) NULL); } return (Tcl_Channel) NULL; } /* * Flush the buffers. This ensures that any data still in them * at this time is not handled by the new transformation. Restrict * this to writable channels. Take care to hide a possible bg-copy * in progress from Tcl_Flush and the CheckForChannelErrors inside. */ if ((mask & TCL_WRITABLE) != 0) { CopyState *csPtrR; CopyState *csPtrW; csPtrR = statePtr->csPtrR; statePtr->csPtrR = (CopyState*) NULL; csPtrW = statePtr->csPtrW; statePtr->csPtrW = (CopyState*) NULL; if (Tcl_Flush((Tcl_Channel) prevChanPtr) != TCL_OK) { statePtr->csPtrR = csPtrR; statePtr->csPtrW = csPtrW; if (interp) { Tcl_AppendResult(interp, "could not flush channel \"", Tcl_GetChannelName(prevChan), "\"", (char *) NULL); } return (Tcl_Channel) NULL; } statePtr->csPtrR = csPtrR; statePtr->csPtrW = csPtrW; } /* * Discard any input in the buffers. They are not yet read by the * user of the channel, so they have to go through the new * transformation before reading. As the buffers contain the * untransformed form their contents are not only useless but actually * distorts our view of the system. * * To preserve the information without having to read them again and * to avoid problems with the location in the channel (seeking might * be impossible) we move the buffers from the common state structure * into the channel itself. We use the buffers in the channel below * the new transformation to hold the data. In the future this allows * us to write transformations which pre-read data and push the unused * part back when they are going away. */ if (((mask & TCL_READABLE) != 0) && (statePtr->inQueueHead != (ChannelBuffer*) NULL)) { /* * Remark: It is possible that the channel buffers contain data from * some earlier push-backs. */ statePtr->inQueueTail->nextPtr = prevChanPtr->inQueueHead; prevChanPtr->inQueueHead = statePtr->inQueueHead; if (prevChanPtr->inQueueTail == (ChannelBuffer*) NULL) { prevChanPtr->inQueueTail = statePtr->inQueueTail; } statePtr->inQueueHead = (ChannelBuffer*) NULL; statePtr->inQueueTail = (ChannelBuffer*) NULL; } chanPtr = (Channel *) ckalloc((unsigned) sizeof(Channel)); /* * Save some of the current state into the new structure, * reinitialize the parts which will stay with the transformation. * * Remarks: */ chanPtr->state = statePtr; chanPtr->instanceData = instanceData; chanPtr->typePtr = typePtr; chanPtr->downChanPtr = prevChanPtr; chanPtr->upChanPtr = (Channel *) NULL; chanPtr->inQueueHead = (ChannelBuffer*) NULL; chanPtr->inQueueTail = (ChannelBuffer*) NULL; /* * Place new block at the head of a possibly existing list of previously * stacked channels. */ prevChanPtr->upChanPtr = chanPtr; statePtr->topChanPtr = chanPtr; return (Tcl_Channel) chanPtr; } /* *---------------------------------------------------------------------- * * Tcl_UnstackChannel -- * * Unstacks an entry in the hash table for a Tcl_Channel * record. This is the reverse to 'Tcl_StackChannel'. * * Results: * A standard Tcl result. * * Side effects: * If TCL_ERROR is returned, the posix error code will be set * with Tcl_SetErrno. * *---------------------------------------------------------------------- */ int Tcl_UnstackChannel (interp, chan) Tcl_Interp *interp; /* The interpreter we are working in */ Tcl_Channel chan; /* The channel to unstack */ { Channel *chanPtr = (Channel *) chan; ChannelState *statePtr = chanPtr->state; int result = 0; /* * This operation should occur at the top of a channel stack. */ chanPtr = statePtr->topChanPtr; if (chanPtr->downChanPtr != (Channel *) NULL) { /* * Instead of manipulating the per-thread / per-interp list/hashtable * of registered channels we wind down the state of the transformation, * and then restore the state of underlying channel into the old * structure. */ Channel *downChanPtr = chanPtr->downChanPtr; /* * Flush the buffers. This ensures that any data still in them * at this time _is_ handled by the transformation we are unstacking * right now. Restrict this to writable channels. Take care to hide * a possible bg-copy in progress from Tcl_Flush and the * CheckForChannelErrors inside. */ if (statePtr->flags & TCL_WRITABLE) { CopyState *csPtrR; CopyState *csPtrW; csPtrR = statePtr->csPtrR; statePtr->csPtrR = (CopyState*) NULL; csPtrW = statePtr->csPtrW; statePtr->csPtrW = (CopyState*) NULL; if (Tcl_Flush((Tcl_Channel) chanPtr) != TCL_OK) { statePtr->csPtrR = csPtrR; statePtr->csPtrW = csPtrW; if (interp) { Tcl_AppendResult(interp, "could not flush channel \"", Tcl_GetChannelName((Tcl_Channel) chanPtr), "\"", (char *) NULL); } return TCL_ERROR; } statePtr->csPtrR = csPtrR; statePtr->csPtrW = csPtrW; } /* * Anything in the input queue and the push-back buffers of * the transformation going away is transformed data, but not * yet read. As unstacking means that the caller does not want * to see transformed data any more we have to discard these * bytes. To avoid writing an analogue to 'DiscardInputQueued' * we move the information in the push back buffers to the * input queue and then call 'DiscardInputQueued' on that. */ if (((statePtr->flags & TCL_READABLE) != 0) && ((statePtr->inQueueHead != (ChannelBuffer*) NULL) || (chanPtr->inQueueHead != (ChannelBuffer*) NULL))) { if ((statePtr->inQueueHead != (ChannelBuffer*) NULL) && (chanPtr->inQueueHead != (ChannelBuffer*) NULL)) { statePtr->inQueueTail->nextPtr = chanPtr->inQueueHead; statePtr->inQueueTail = chanPtr->inQueueTail; statePtr->inQueueHead = statePtr->inQueueTail; } else if (chanPtr->inQueueHead != (ChannelBuffer*) NULL) { statePtr->inQueueHead = chanPtr->inQueueHead; statePtr->inQueueTail = chanPtr->inQueueTail; } chanPtr->inQueueHead = (ChannelBuffer*) NULL; chanPtr->inQueueTail = (ChannelBuffer*) NULL; DiscardInputQueued (statePtr, 0); } statePtr->topChanPtr = downChanPtr; downChanPtr->upChanPtr = (Channel *) NULL; /* * Leave this link intact for closeproc * chanPtr->downChanPtr = (Channel *) NULL; */ /* * Close and free the channel driver state. */ if (chanPtr->typePtr->closeProc != TCL_CLOSE2PROC) { result = (chanPtr->typePtr->closeProc)(chanPtr->instanceData, interp); } else { result = (chanPtr->typePtr->close2Proc)(chanPtr->instanceData, interp, 0); } chanPtr->typePtr = NULL; /* * AK: Tcl_NotifyChannel may hold a reference to this block of memory */ Tcl_EventuallyFree((ClientData) chanPtr, TCL_DYNAMIC); UpdateInterest(downChanPtr); if (result != 0) { Tcl_SetErrno(result); return TCL_ERROR; } } else { /* * This channel does not cover another one. * Simply do a close, if necessary. */ if (statePtr->refCount <= 0) { if (Tcl_Close(interp, chan) != TCL_OK) { return TCL_ERROR; } } } return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_GetStackedChannel -- * * Determines whether the specified channel is stacked upon another. * * Results: * NULL if the channel is not stacked upon another one, or a reference * to the channel it is stacked upon. This reference can be used in * queries, but modification is not allowed. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_Channel Tcl_GetStackedChannel(chan) Tcl_Channel chan; { Channel *chanPtr = (Channel *) chan; /* The actual channel. */ return (Tcl_Channel) chanPtr->downChanPtr; } /* *---------------------------------------------------------------------- * * Tcl_GetTopChannel -- * * Returns the top channel of a channel stack. * * Results: * NULL if the channel is not stacked upon another one, or a reference * to the channel it is stacked upon. This reference can be used in * queries, but modification is not allowed. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_Channel Tcl_GetTopChannel(chan) Tcl_Channel chan; { Channel *chanPtr = (Channel *) chan; /* The actual channel. */ return (Tcl_Channel) chanPtr->state->topChanPtr; } /* *---------------------------------------------------------------------- * * Tcl_GetChannelInstanceData -- * * Returns the client data associated with a channel. * * Results: * The client data. * * Side effects: * None. * *---------------------------------------------------------------------- */ ClientData Tcl_GetChannelInstanceData(chan) Tcl_Channel chan; /* Channel for which to return client data. */ { Channel *chanPtr = (Channel *) chan; /* The actual channel. */ return chanPtr->instanceData; } /* *---------------------------------------------------------------------- * * Tcl_GetChannelThread -- * * Given a channel structure, returns the thread managing it. * TIP #10 * * Results: * Returns the id of the thread managing the channel. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_ThreadId Tcl_GetChannelThread(chan) Tcl_Channel chan; /* The channel to return managing thread for. */ { Channel *chanPtr = (Channel *) chan; /* The actual channel. */ return chanPtr->state->managingThread; } /* *---------------------------------------------------------------------- * * Tcl_GetChannelType -- * * Given a channel structure, returns the channel type structure. * * Results: * Returns a pointer to the channel type structure. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_ChannelType * Tcl_GetChannelType(chan) Tcl_Channel chan; /* The channel to return type for. */ { Channel *chanPtr = (Channel *) chan; /* The actual channel. */ return chanPtr->typePtr; } /* *---------------------------------------------------------------------- * * Tcl_GetChannelMode -- * * Computes a mask indicating whether the channel is open for * reading and writing. * * Results: * An OR-ed combination of TCL_READABLE and TCL_WRITABLE. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_GetChannelMode(chan) Tcl_Channel chan; /* The channel for which the mode is * being computed. */ { ChannelState *statePtr = ((Channel *) chan)->state; /* State of actual channel. */ return (statePtr->flags & (TCL_READABLE | TCL_WRITABLE)); } /* *---------------------------------------------------------------------- * * Tcl_GetChannelName -- * * Returns the string identifying the channel name. * * Results: * The string containing the channel name. This memory is * owned by the generic layer and should not be modified by * the caller. * * Side effects: * None. * *---------------------------------------------------------------------- */ CONST char * Tcl_GetChannelName(chan) Tcl_Channel chan; /* The channel for which to return the name. */ { ChannelState *statePtr; /* State of actual channel. */ statePtr = ((Channel *) chan)->state; return statePtr->channelName; } /* *---------------------------------------------------------------------- * * Tcl_GetChannelHandle -- * * Returns an OS handle associated with a channel. * * Results: * Returns TCL_OK and places the handle in handlePtr, or returns * TCL_ERROR on failure. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_GetChannelHandle(chan, direction, handlePtr) Tcl_Channel chan; /* The channel to get file from. */ int direction; /* TCL_WRITABLE or TCL_READABLE. */ ClientData *handlePtr; /* Where to store handle */ { Channel *chanPtr; /* The actual channel. */ ClientData handle; int result; chanPtr = ((Channel *) chan)->state->bottomChanPtr; result = (chanPtr->typePtr->getHandleProc)(chanPtr->instanceData, direction, &handle); if (handlePtr) { *handlePtr = handle; } return result; } /* *--------------------------------------------------------------------------- * * AllocChannelBuffer -- * * A channel buffer has BUFFER_PADDING bytes extra at beginning to * hold any bytes of a native-encoding character that got split by * the end of the previous buffer and need to be moved to the * beginning of the next buffer to make a contiguous string so it * can be converted to UTF-8. * * A channel buffer has BUFFER_PADDING bytes extra at the end to * hold any bytes of a native-encoding character (generated from a * UTF-8 character) that overflow past the end of the buffer and * need to be moved to the next buffer. * * Results: * A newly allocated channel buffer. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static ChannelBuffer * AllocChannelBuffer(length) int length; /* Desired length of channel buffer. */ { ChannelBuffer *bufPtr; int n; n = length + CHANNELBUFFER_HEADER_SIZE + BUFFER_PADDING + BUFFER_PADDING; bufPtr = (ChannelBuffer *) ckalloc((unsigned) n); bufPtr->nextAdded = BUFFER_PADDING; bufPtr->nextRemoved = BUFFER_PADDING; bufPtr->bufLength = length + BUFFER_PADDING; bufPtr->nextPtr = (ChannelBuffer *) NULL; return bufPtr; } /* *---------------------------------------------------------------------- * * RecycleBuffer -- * * Helper function to recycle input and output buffers. Ensures * that two input buffers are saved (one in the input queue and * another in the saveInBufPtr field) and that curOutPtr is set * to a buffer. Only if these conditions are met is the buffer * freed to the OS. * * Results: * None. * * Side effects: * May free a buffer to the OS. * *---------------------------------------------------------------------- */ static void RecycleBuffer(statePtr, bufPtr, mustDiscard) ChannelState *statePtr; /* ChannelState in which to recycle buffers. */ ChannelBuffer *bufPtr; /* The buffer to recycle. */ int mustDiscard; /* If nonzero, free the buffer to the * OS, always. */ { /* * Do we have to free the buffer to the OS? */ if (mustDiscard) { ckfree((char *) bufPtr); return; } /* * Only save buffers which are at least as big as the requested * buffersize for the channel. This is to honor dynamic changes * of the buffersize made by the user. */ if ((bufPtr->bufLength - BUFFER_PADDING) < statePtr->bufSize) { ckfree((char *) bufPtr); return; } /* * Only save buffers for the input queue if the channel is readable. */ if (statePtr->flags & TCL_READABLE) { if (statePtr->inQueueHead == (ChannelBuffer *) NULL) { statePtr->inQueueHead = bufPtr; statePtr->inQueueTail = bufPtr; goto keepit; } if (statePtr->saveInBufPtr == (ChannelBuffer *) NULL) { statePtr->saveInBufPtr = bufPtr; goto keepit; } } /* * Only save buffers for the output queue if the channel is writable. */ if (statePtr->flags & TCL_WRITABLE) { if (statePtr->curOutPtr == (ChannelBuffer *) NULL) { statePtr->curOutPtr = bufPtr; goto keepit; } } /* * If we reached this code we return the buffer to the OS. */ ckfree((char *) bufPtr); return; keepit: bufPtr->nextRemoved = BUFFER_PADDING; bufPtr->nextAdded = BUFFER_PADDING; bufPtr->nextPtr = (ChannelBuffer *) NULL; } /* *---------------------------------------------------------------------- * * DiscardOutputQueued -- * * Discards all output queued in the output queue of a channel. * * Results: * None. * * Side effects: * Recycles buffers. * *---------------------------------------------------------------------- */ static void DiscardOutputQueued(statePtr) ChannelState *statePtr; /* ChannelState for which to discard output. */ { ChannelBuffer *bufPtr; while (statePtr->outQueueHead != (ChannelBuffer *) NULL) { bufPtr = statePtr->outQueueHead; statePtr->outQueueHead = bufPtr->nextPtr; RecycleBuffer(statePtr, bufPtr, 0); } statePtr->outQueueHead = (ChannelBuffer *) NULL; statePtr->outQueueTail = (ChannelBuffer *) NULL; } /* *---------------------------------------------------------------------- * * CheckForDeadChannel -- * * This function checks is a given channel is Dead. * (A channel that has been closed but not yet deallocated.) * * Results: * True (1) if channel is Dead, False (0) if channel is Ok * * Side effects: * None * *---------------------------------------------------------------------- */ static int CheckForDeadChannel(interp, statePtr) Tcl_Interp *interp; /* For error reporting (can be NULL) */ ChannelState *statePtr; /* The channel state to check. */ { if (statePtr->flags & CHANNEL_DEAD) { Tcl_SetErrno(EINVAL); if (interp) { Tcl_AppendResult(interp, "unable to access channel: invalid channel", (char *) NULL); } return 1; } return 0; } /* *---------------------------------------------------------------------- * * FlushChannel -- * * This function flushes as much of the queued output as is possible * now. If calledFromAsyncFlush is nonzero, it is being called in an * event handler to flush channel output asynchronously. * * Results: * 0 if successful, else the error code that was returned by the * channel type operation. * * Side effects: * May produce output on a channel. May block indefinitely if the * channel is synchronous. May schedule an async flush on the channel. * May recycle memory for buffers in the output queue. * *---------------------------------------------------------------------- */ static int FlushChannel(interp, chanPtr, calledFromAsyncFlush) Tcl_Interp *interp; /* For error reporting during close. */ Channel *chanPtr; /* The channel to flush on. */ int calledFromAsyncFlush; /* If nonzero then we are being * called from an asynchronous * flush callback. */ { ChannelState *statePtr = chanPtr->state; /* State of the channel stack. */ ChannelBuffer *bufPtr; /* Iterates over buffered output * queue. */ int toWrite; /* Amount of output data in current * buffer available to be written. */ int written; /* Amount of output data actually * written in current round. */ int errorCode = 0; /* Stores POSIX error codes from * channel driver operations. */ int wroteSome = 0; /* Set to one if any data was * written to the driver. */ /* * Prevent writing on a dead channel -- a channel that has been closed * but not yet deallocated. This can occur if the exit handler for the * channel deallocation runs before all channels are deregistered in * all interpreters. */ if (CheckForDeadChannel(interp, statePtr)) return -1; /* * Loop over the queued buffers and attempt to flush as * much as possible of the queued output to the channel. */ while (1) { /* * If the queue is empty and there is a ready current buffer, OR if * the current buffer is full, then move the current buffer to the * queue. */ if (((statePtr->curOutPtr != (ChannelBuffer *) NULL) && (statePtr->curOutPtr->nextAdded == statePtr->curOutPtr->bufLength)) || ((statePtr->flags & BUFFER_READY) && (statePtr->outQueueHead == (ChannelBuffer *) NULL))) { statePtr->flags &= (~(BUFFER_READY)); statePtr->curOutPtr->nextPtr = (ChannelBuffer *) NULL; if (statePtr->outQueueHead == (ChannelBuffer *) NULL) { statePtr->outQueueHead = statePtr->curOutPtr; } else { statePtr->outQueueTail->nextPtr = statePtr->curOutPtr; } statePtr->outQueueTail = statePtr->curOutPtr; statePtr->curOutPtr = (ChannelBuffer *) NULL; } bufPtr = statePtr->outQueueHead; /* * If we are not being called from an async flush and an async * flush is active, we just return without producing any output. */ if ((!calledFromAsyncFlush) && (statePtr->flags & BG_FLUSH_SCHEDULED)) { return 0; } /* * If the output queue is still empty, break out of the while loop. */ if (bufPtr == (ChannelBuffer *) NULL) { break; /* Out of the "while (1)". */ } /* * Produce the output on the channel. */ toWrite = bufPtr->nextAdded - bufPtr->nextRemoved; if (toWrite == 0) { written = 0; } else { written = (chanPtr->typePtr->outputProc) (chanPtr->instanceData, bufPtr->buf + bufPtr->nextRemoved, toWrite, &errorCode); } /* * If the write failed completely attempt to start the asynchronous * flush mechanism and break out of this loop - do not attempt to * write any more output at this time. */ if (written < 0) { /* * If the last attempt to write was interrupted, simply retry. */ if (errorCode == EINTR) { errorCode = 0; continue; } /* * If the channel is non-blocking and we would have blocked, * start a background flushing handler and break out of the loop. */ if ((errorCode == EWOULDBLOCK) || (errorCode == EAGAIN)) { /* * This used to check for CHANNEL_NONBLOCKING, and panic * if the channel was blocking. However, it appears * that setting stdin to -blocking 0 has some effect on * the stdout when it's a tty channel (dup'ed underneath) */ if (!(statePtr->flags & BG_FLUSH_SCHEDULED)) { statePtr->flags |= BG_FLUSH_SCHEDULED; UpdateInterest(chanPtr); } errorCode = 0; break; } /* * Decide whether to report the error upwards or defer it. */ if (calledFromAsyncFlush) { if (statePtr->unreportedError == 0) { statePtr->unreportedError = errorCode; } } else { Tcl_SetErrno(errorCode); if (interp != NULL) { /* * Casting away CONST here is safe because the * TCL_VOLATILE flag guarantees CONST treatment * of the Posix error string. */ Tcl_SetResult(interp, (char *) Tcl_PosixError(interp), TCL_VOLATILE); } } /* * When we get an error we throw away all the output * currently queued. */ DiscardOutputQueued(statePtr); continue; } else { wroteSome = 1; } bufPtr->nextRemoved += written; /* * If this buffer is now empty, recycle it. */ if (bufPtr->nextRemoved == bufPtr->nextAdded) { statePtr->outQueueHead = bufPtr->nextPtr; if (statePtr->outQueueHead == (ChannelBuffer *) NULL) { statePtr->outQueueTail = (ChannelBuffer *) NULL; } RecycleBuffer(statePtr, bufPtr, 0); } } /* Closes "while (1)". */ /* * If we wrote some data while flushing in the background, we are done. * We can't finish the background flush until we run out of data and * the channel becomes writable again. This ensures that all of the * pending data has been flushed at the system level. */ if (statePtr->flags & BG_FLUSH_SCHEDULED) { if (wroteSome) { return errorCode; } else if (statePtr->outQueueHead == (ChannelBuffer *) NULL) { statePtr->flags &= (~(BG_FLUSH_SCHEDULED)); (chanPtr->typePtr->watchProc)(chanPtr->instanceData, statePtr->interestMask); } } /* * If the channel is flagged as closed, delete it when the refCount * drops to zero, the output queue is empty and there is no output * in the current output buffer. */ if ((statePtr->flags & CHANNEL_CLOSED) && (statePtr->refCount <= 0) && (statePtr->outQueueHead == (ChannelBuffer *) NULL) && ((statePtr->curOutPtr == (ChannelBuffer *) NULL) || (statePtr->curOutPtr->nextAdded == statePtr->curOutPtr->nextRemoved))) { return CloseChannel(interp, chanPtr, errorCode); } return errorCode; } /* *---------------------------------------------------------------------- * * CloseChannel -- * * Utility procedure to close a channel and free associated resources. * * If the channel was stacked, then the it will copy the necessary * elements of the NEXT channel into the TOP channel, in essence * unstacking the channel. The NEXT channel will then be freed. * * If the channel was not stacked, then we will free all the bits * for the TOP channel, including the data structure itself. * * Results: * 1 if the channel was stacked, 0 otherwise. * * Side effects: * May close the actual channel; may free memory. * May change the value of errno. * *---------------------------------------------------------------------- */ static int CloseChannel(interp, chanPtr, errorCode) Tcl_Interp *interp; /* For error reporting. */ Channel *chanPtr; /* The channel to close. */ int errorCode; /* Status of operation so far. */ { int result = 0; /* Of calling driver close * operation. */ ChannelState *statePtr; /* state of the channel stack. */ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (chanPtr == NULL) { return result; } statePtr = chanPtr->state; /* * No more input can be consumed so discard any leftover input. */ DiscardInputQueued(statePtr, 1); /* * Discard a leftover buffer in the current output buffer field. */ if (statePtr->curOutPtr != (ChannelBuffer *) NULL) { ckfree((char *) statePtr->curOutPtr); statePtr->curOutPtr = (ChannelBuffer *) NULL; } /* * The caller guarantees that there are no more buffers * queued for output. */ if (statePtr->outQueueHead != (ChannelBuffer *) NULL) { panic("TclFlush, closed channel: queued output left"); } /* * If the EOF character is set in the channel, append that to the * output device. */ if ((statePtr->outEofChar != 0) && (statePtr->flags & TCL_WRITABLE)) { int dummy; char c; c = (char) statePtr->outEofChar; (chanPtr->typePtr->outputProc) (chanPtr->instanceData, &c, 1, &dummy); } /* * Remove this channel from of the list of all channels. */ Tcl_CutChannel((Tcl_Channel) chanPtr); /* * Close and free the channel driver state. */ if (chanPtr->typePtr->closeProc != TCL_CLOSE2PROC) { result = (chanPtr->typePtr->closeProc)(chanPtr->instanceData, interp); } else { result = (chanPtr->typePtr->close2Proc)(chanPtr->instanceData, interp, 0); } /* * Some resources can be cleared only if the bottom channel * in a stack is closed. All the other channels in the stack * are not allowed to remove. */ if (chanPtr == statePtr->bottomChanPtr) { if (statePtr->channelName != (char *) NULL) { ckfree((char *) statePtr->channelName); statePtr->channelName = NULL; } Tcl_FreeEncoding(statePtr->encoding); if (statePtr->outputStage != NULL) { ckfree((char *) statePtr->outputStage); statePtr->outputStage = (char *) NULL; } } /* * If we are being called synchronously, report either * any latent error on the channel or the current error. */ if (statePtr->unreportedError != 0) { errorCode = statePtr->unreportedError; } if (errorCode == 0) { errorCode = result; if (errorCode != 0) { Tcl_SetErrno(errorCode); } } /* * Cancel any outstanding timer. */ Tcl_DeleteTimerHandler(statePtr->timer); /* * Mark the channel as deleted by clearing the type structure. */ if (chanPtr->downChanPtr != (Channel *) NULL) { Channel *downChanPtr = chanPtr->downChanPtr; statePtr->nextCSPtr = tsdPtr->firstCSPtr; tsdPtr->firstCSPtr = statePtr; statePtr->topChanPtr = downChanPtr; downChanPtr->upChanPtr = (Channel *) NULL; chanPtr->typePtr = NULL; Tcl_EventuallyFree((ClientData) chanPtr, TCL_DYNAMIC); return Tcl_Close(interp, (Tcl_Channel) downChanPtr); } /* * There is only the TOP Channel, so we free the remaining * pointers we have and then ourselves. Since this is the * last of the channels in the stack, make sure to free the * ChannelState structure associated with it. We use * Tcl_EventuallyFree to allow for any last */ chanPtr->typePtr = NULL; Tcl_EventuallyFree((ClientData) statePtr, TCL_DYNAMIC); Tcl_EventuallyFree((ClientData) chanPtr, TCL_DYNAMIC); return errorCode; } /* *---------------------------------------------------------------------- * * Tcl_CutChannel -- * * Removes a channel from the (thread-)global list of all channels * (in that thread). This is actually the statePtr for the stack * of channel. * * Results: * Nothing. * * Side effects: * Resets the field 'nextCSPtr' of the specified channel state to NULL. * * NOTE: * The channel to cut out of the list must not be referenced * in any interpreter. This is something this procedure cannot * check (despite the refcount) because the caller usually wants * fiddle with the channel (like transfering it to a different * thread) and thus keeps the refcount artifically high to prevent * its destruction. * *---------------------------------------------------------------------- */ void Tcl_CutChannel(chan) Tcl_Channel chan; /* The channel being removed. Must * not be referenced in any * interpreter. */ { ThreadSpecificData* tsdPtr = TCL_TSD_INIT(&dataKey); ChannelState *prevCSPtr; /* Preceding channel state in list of * all states - used to splice a * channel out of the list on close. */ ChannelState *statePtr = ((Channel *) chan)->state; /* state of the channel stack. */ Tcl_DriverThreadActionProc *threadActionProc; /* * Remove this channel from of the list of all channels * (in the current thread). */ if (tsdPtr->firstCSPtr && (statePtr == tsdPtr->firstCSPtr)) { tsdPtr->firstCSPtr = statePtr->nextCSPtr; } else { for (prevCSPtr = tsdPtr->firstCSPtr; prevCSPtr && (prevCSPtr->nextCSPtr != statePtr); prevCSPtr = prevCSPtr->nextCSPtr) { /* Empty loop body. */ } if (prevCSPtr == (ChannelState *) NULL) { panic("FlushChannel: damaged channel list"); } prevCSPtr->nextCSPtr = statePtr->nextCSPtr; } statePtr->nextCSPtr = (ChannelState *) NULL; /* TIP #218, Channel Thread Actions */ threadActionProc = Tcl_ChannelThreadActionProc (Tcl_GetChannelType (chan)); if (threadActionProc != NULL) { (*threadActionProc) (Tcl_GetChannelInstanceData(chan), TCL_CHANNEL_THREAD_REMOVE); } } /* *---------------------------------------------------------------------- * * Tcl_SpliceChannel -- * * Adds a channel to the (thread-)global list of all channels * (in that thread). Expects that the field 'nextChanPtr' in * the channel is set to NULL. * * Results: * Nothing. * * Side effects: * Nothing. * * NOTE: * The channel to splice into the list must not be referenced in any * interpreter. This is something this procedure cannot check * (despite the refcount) because the caller usually wants figgle * with the channel (like transfering it to a different thread) * and thus keeps the refcount artifically high to prevent its * destruction. * *---------------------------------------------------------------------- */ void Tcl_SpliceChannel(chan) Tcl_Channel chan; /* The channel being added. Must * not be referenced in any * interpreter. */ { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); ChannelState *statePtr = ((Channel *) chan)->state; Tcl_DriverThreadActionProc *threadActionProc; if (statePtr->nextCSPtr != (ChannelState *) NULL) { panic("Tcl_SpliceChannel: trying to add channel used in different list"); } statePtr->nextCSPtr = tsdPtr->firstCSPtr; tsdPtr->firstCSPtr = statePtr; /* * TIP #10. Mark the current thread as the new one managing this * channel. Note: 'Tcl_GetCurrentThread' returns sensible * values even for a non-threaded core. */ statePtr->managingThread = Tcl_GetCurrentThread (); /* TIP #218, Channel Thread Actions */ threadActionProc = Tcl_ChannelThreadActionProc (Tcl_GetChannelType (chan)); if (threadActionProc != NULL) { (*threadActionProc) (Tcl_GetChannelInstanceData(chan), TCL_CHANNEL_THREAD_INSERT); } } /* *---------------------------------------------------------------------- * * Tcl_Close -- * * Closes a channel. * * Results: * A standard Tcl result. * * Side effects: * Closes the channel if this is the last reference. * * NOTE: * Tcl_Close removes the channel as far as the user is concerned. * However, it may continue to exist for a while longer if it has * a background flush scheduled. The device itself is eventually * closed and the channel record removed, in CloseChannel, above. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_Close(interp, chan) Tcl_Interp *interp; /* Interpreter for errors. */ Tcl_Channel chan; /* The channel being closed. Must * not be referenced in any * interpreter. */ { CloseCallback *cbPtr; /* Iterate over close callbacks * for this channel. */ Channel *chanPtr; /* The real IO channel. */ ChannelState *statePtr; /* State of real IO channel. */ int result; /* Of calling FlushChannel. */ if (chan == (Tcl_Channel) NULL) { return TCL_OK; } /* * Perform special handling for standard channels being closed. If the * refCount is now 1 it means that the last reference to the standard * channel is being explicitly closed, so bump the refCount down * artificially to 0. This will ensure that the channel is actually * closed, below. Also set the static pointer to NULL for the channel. */ CheckForStdChannelsBeingClosed(chan); /* * This operation should occur at the top of a channel stack. */ chanPtr = (Channel *) chan; statePtr = chanPtr->state; chanPtr = statePtr->topChanPtr; if (statePtr->refCount > 0) { panic("called Tcl_Close on channel with refCount > 0"); } if (statePtr->flags & CHANNEL_INCLOSE) { if (interp) { Tcl_AppendResult(interp, "Illegal recursive call to close through close-handler of channel", (char *) NULL); } return TCL_ERROR; } statePtr->flags |= CHANNEL_INCLOSE; /* * When the channel has an escape sequence driven encoding such as * iso2022, the terminated escape sequence must write to the buffer. */ if ((statePtr->encoding != NULL) && (statePtr->curOutPtr != NULL) && (CheckChannelErrors(statePtr, TCL_WRITABLE) == 0)) { statePtr->outputEncodingFlags |= TCL_ENCODING_END; WriteChars(chanPtr, "", 0); } Tcl_ClearChannelHandlers(chan); /* * Invoke the registered close callbacks and delete their records. */ while (statePtr->closeCbPtr != (CloseCallback *) NULL) { cbPtr = statePtr->closeCbPtr; statePtr->closeCbPtr = cbPtr->nextPtr; (cbPtr->proc) (cbPtr->clientData); ckfree((char *) cbPtr); } statePtr->flags &= ~CHANNEL_INCLOSE; /* * Ensure that the last output buffer will be flushed. */ if ((statePtr->curOutPtr != (ChannelBuffer *) NULL) && (statePtr->curOutPtr->nextAdded > statePtr->curOutPtr->nextRemoved)) { statePtr->flags |= BUFFER_READY; } /* * If this channel supports it, close the read side, since we don't need it * anymore and this will help avoid deadlocks on some channel types. */ if (chanPtr->typePtr->closeProc == TCL_CLOSE2PROC) { result = (chanPtr->typePtr->close2Proc)(chanPtr->instanceData, interp, TCL_CLOSE_READ); } else { result = 0; } /* * The call to FlushChannel will flush any queued output and invoke * the close function of the channel driver, or it will set up the * channel to be flushed and closed asynchronously. */ statePtr->flags |= CHANNEL_CLOSED; if ((FlushChannel(interp, chanPtr, 0) != 0) || (result != 0)) { return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_ClearChannelHandlers -- * * Removes all channel handlers and event scripts from the channel, * cancels all background copies involving the channel and any interest * in events. * * Results: * None. * * Side effects: * See above. Deallocates memory. * *---------------------------------------------------------------------- */ void Tcl_ClearChannelHandlers (channel) Tcl_Channel channel; { ChannelHandler *chPtr, *chNext; /* Iterate over channel handlers. */ EventScriptRecord *ePtr, *eNextPtr; /* Iterate over eventscript records. */ Channel *chanPtr; /* The real IO channel. */ ChannelState *statePtr; /* State of real IO channel. */ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); NextChannelHandler *nhPtr; /* * This operation should occur at the top of a channel stack. */ chanPtr = (Channel *) channel; statePtr = chanPtr->state; chanPtr = statePtr->topChanPtr; /* * Cancel any outstanding timer. */ Tcl_DeleteTimerHandler(statePtr->timer); /* * Remove any references to channel handlers for this channel that * may be about to be invoked. */ for (nhPtr = tsdPtr->nestedHandlerPtr; nhPtr != (NextChannelHandler *) NULL; nhPtr = nhPtr->nestedHandlerPtr) { if (nhPtr->nextHandlerPtr && (nhPtr->nextHandlerPtr->chanPtr == chanPtr)) { nhPtr->nextHandlerPtr = NULL; } } /* * Remove all the channel handler records attached to the channel * itself. */ for (chPtr = statePtr->chPtr; chPtr != (ChannelHandler *) NULL; chPtr = chNext) { chNext = chPtr->nextPtr; ckfree((char *) chPtr); } statePtr->chPtr = (ChannelHandler *) NULL; /* * Cancel any pending copy operation. */ StopCopy(statePtr->csPtrR); StopCopy(statePtr->csPtrW); /* * Must set the interest mask now to 0, otherwise infinite loops * will occur if Tcl_DoOneEvent is called before the channel is * finally deleted in FlushChannel. This can happen if the channel * has a background flush active. */ statePtr->interestMask = 0; /* * Remove any EventScript records for this channel. */ for (ePtr = statePtr->scriptRecordPtr; ePtr != (EventScriptRecord *) NULL; ePtr = eNextPtr) { eNextPtr = ePtr->nextPtr; Tcl_DecrRefCount(ePtr->scriptPtr); ckfree((char *) ePtr); } statePtr->scriptRecordPtr = (EventScriptRecord *) NULL; } /* *---------------------------------------------------------------------- * * Tcl_Write -- * * Puts a sequence of bytes into an output buffer, may queue the * buffer for output if it gets full, and also remembers whether the * current buffer is ready e.g. if it contains a newline and we are in * line buffering mode. Compensates stacking, i.e. will redirect the * data from the specified channel to the topmost channel in a stack. * * No encoding conversions are applied to the bytes being read. * * Results: * The number of bytes written or -1 in case of error. If -1, * Tcl_GetErrno will return the error code. * * Side effects: * May buffer up output and may cause output to be produced on the * channel. * *---------------------------------------------------------------------- */ int Tcl_Write(chan, src, srcLen) Tcl_Channel chan; /* The channel to buffer output for. */ CONST char *src; /* Data to queue in output buffer. */ int srcLen; /* Length of data in bytes, or < 0 for * strlen(). */ { /* * Always use the topmost channel of the stack */ Channel *chanPtr; ChannelState *statePtr; /* state info for channel */ statePtr = ((Channel *) chan)->state; chanPtr = statePtr->topChanPtr; if (CheckChannelErrors(statePtr, TCL_WRITABLE) != 0) { return -1; } if (srcLen < 0) { srcLen = strlen(src); } return DoWrite(chanPtr, src, srcLen); } /* *---------------------------------------------------------------------- * * Tcl_WriteRaw -- * * Puts a sequence of bytes into an output buffer, may queue the * buffer for output if it gets full, and also remembers whether the * current buffer is ready e.g. if it contains a newline and we are in * line buffering mode. Writes directly to the driver of the channel, * does not compensate for stacking. * * No encoding conversions are applied to the bytes being read. * * Results: * The number of bytes written or -1 in case of error. If -1, * Tcl_GetErrno will return the error code. * * Side effects: * May buffer up output and may cause output to be produced on the * channel. * *---------------------------------------------------------------------- */ int Tcl_WriteRaw(chan, src, srcLen) Tcl_Channel chan; /* The channel to buffer output for. */ CONST char *src; /* Data to queue in output buffer. */ int srcLen; /* Length of data in bytes, or < 0 for * strlen(). */ { Channel *chanPtr = ((Channel *) chan); ChannelState *statePtr = chanPtr->state; /* state info for channel */ int errorCode, written; if (CheckChannelErrors(statePtr, TCL_WRITABLE | CHANNEL_RAW_MODE) != 0) { return -1; } if (srcLen < 0) { srcLen = strlen(src); } /* * Go immediately to the driver, do all the error handling by ourselves. * The code was stolen from 'FlushChannel'. */ written = (chanPtr->typePtr->outputProc) (chanPtr->instanceData, src, srcLen, &errorCode); if (written < 0) { Tcl_SetErrno(errorCode); } return written; } /* *--------------------------------------------------------------------------- * * Tcl_WriteChars -- * * Takes a sequence of UTF-8 characters and converts them for output * using the channel's current encoding, may queue the buffer for * output if it gets full, and also remembers whether the current * buffer is ready e.g. if it contains a newline and we are in * line buffering mode. Compensates stacking, i.e. will redirect the * data from the specified channel to the topmost channel in a stack. * * Results: * The number of bytes written or -1 in case of error. If -1, * Tcl_GetErrno will return the error code. * * Side effects: * May buffer up output and may cause output to be produced on the * channel. * *---------------------------------------------------------------------- */ int Tcl_WriteChars(chan, src, len) Tcl_Channel chan; /* The channel to buffer output for. */ CONST char *src; /* UTF-8 characters to queue in output buffer. */ int len; /* Length of string in bytes, or < 0 for * strlen(). */ { ChannelState *statePtr; /* state info for channel */ statePtr = ((Channel *) chan)->state; if (CheckChannelErrors(statePtr, TCL_WRITABLE) != 0) { return -1; } return DoWriteChars ((Channel*) chan, src, len); } /* *--------------------------------------------------------------------------- * * DoWriteChars -- * * Takes a sequence of UTF-8 characters and converts them for output * using the channel's current encoding, may queue the buffer for * output if it gets full, and also remembers whether the current * buffer is ready e.g. if it contains a newline and we are in * line buffering mode. Compensates stacking, i.e. will redirect the * data from the specified channel to the topmost channel in a stack. * * Results: * The number of bytes written or -1 in case of error. If -1, * Tcl_GetErrno will return the error code. * * Side effects: * May buffer up output and may cause output to be produced on the * channel. * *---------------------------------------------------------------------- */ static int DoWriteChars(chanPtr, src, len) Channel* chanPtr; /* The channel to buffer output for. */ CONST char *src; /* UTF-8 characters to queue in output buffer. */ int len; /* Length of string in bytes, or < 0 for * strlen(). */ { /* * Always use the topmost channel of the stack */ ChannelState *statePtr; /* state info for channel */ statePtr = chanPtr->state; chanPtr = statePtr->topChanPtr; if (len < 0) { len = strlen(src); } if (statePtr->encoding == NULL) { /* * Inefficient way to convert UTF-8 to byte-array, but the * code parallels the way it is done for objects. */ Tcl_Obj *objPtr; int result; objPtr = Tcl_NewStringObj(src, len); src = (char *) Tcl_GetByteArrayFromObj(objPtr, &len); result = WriteBytes(chanPtr, src, len); Tcl_DecrRefCount(objPtr); return result; } return WriteChars(chanPtr, src, len); } /* *--------------------------------------------------------------------------- * * Tcl_WriteObj -- * * Takes the Tcl object and queues its contents for output. If the * encoding of the channel is NULL, takes the byte-array representation * of the object and queues those bytes for output. Otherwise, takes * the characters in the UTF-8 (string) representation of the object * and converts them for output using the channel's current encoding. * May flush internal buffers to output if one becomes full or is ready * for some other reason, e.g. if it contains a newline and the channel * is in line buffering mode. * * Results: * The number of bytes written or -1 in case of error. If -1, * Tcl_GetErrno() will return the error code. * * Side effects: * May buffer up output and may cause output to be produced on the * channel. * *---------------------------------------------------------------------- */ int Tcl_WriteObj(chan, objPtr) Tcl_Channel chan; /* The channel to buffer output for. */ Tcl_Obj *objPtr; /* The object to write. */ { /* * Always use the topmost channel of the stack */ Channel *chanPtr; ChannelState *statePtr; /* state info for channel */ char *src; int srcLen; statePtr = ((Channel *) chan)->state; chanPtr = statePtr->topChanPtr; if (CheckChannelErrors(statePtr, TCL_WRITABLE) != 0) { return -1; } if (statePtr->encoding == NULL) { src = (char *) Tcl_GetByteArrayFromObj(objPtr, &srcLen); return WriteBytes(chanPtr, src, srcLen); } else { src = Tcl_GetStringFromObj(objPtr, &srcLen); return WriteChars(chanPtr, src, srcLen); } } /* *---------------------------------------------------------------------- * * WriteBytes -- * * Write a sequence of bytes into an output buffer, may queue the * buffer for output if it gets full, and also remembers whether the * current buffer is ready e.g. if it contains a newline and we are in * line buffering mode. * * Results: * The number of bytes written or -1 in case of error. If -1, * Tcl_GetErrno will return the error code. * * Side effects: * May buffer up output and may cause output to be produced on the * channel. * *---------------------------------------------------------------------- */ static int WriteBytes(chanPtr, src, srcLen) Channel *chanPtr; /* The channel to buffer output for. */ CONST char *src; /* Bytes to write. */ int srcLen; /* Number of bytes to write. */ { ChannelState *statePtr = chanPtr->state; /* state info for channel */ ChannelBuffer *bufPtr; char *dst; int dstMax, sawLF, savedLF, total, dstLen, toWrite; total = 0; sawLF = 0; savedLF = 0; /* * Loop over all bytes in src, storing them in output buffer with * proper EOL translation. */ while (srcLen + savedLF > 0) { bufPtr = statePtr->curOutPtr; if (bufPtr == NULL) { bufPtr = AllocChannelBuffer(statePtr->bufSize); statePtr->curOutPtr = bufPtr; } dst = bufPtr->buf + bufPtr->nextAdded; dstMax = bufPtr->bufLength - bufPtr->nextAdded; dstLen = dstMax; toWrite = dstLen; if (toWrite > srcLen) { toWrite = srcLen; } if (savedLF) { /* * A '\n' was left over from last call to TranslateOutputEOL() * and we need to store it in this buffer. If the channel is * line-based, we will need to flush it. */ *dst++ = '\n'; dstLen--; sawLF++; } sawLF += TranslateOutputEOL(statePtr, dst, src, &dstLen, &toWrite); dstLen += savedLF; savedLF = 0; if (dstLen > dstMax) { savedLF = 1; dstLen = dstMax; } bufPtr->nextAdded += dstLen; if (CheckFlush(chanPtr, bufPtr, sawLF) != 0) { return -1; } total += dstLen; src += toWrite; srcLen -= toWrite; sawLF = 0; } return total; } /* *---------------------------------------------------------------------- * * WriteChars -- * * Convert UTF-8 bytes to the channel's external encoding and * write the produced bytes into an output buffer, may queue the * buffer for output if it gets full, and also remembers whether the * current buffer is ready e.g. if it contains a newline and we are in * line buffering mode. * * Results: * The number of bytes written or -1 in case of error. If -1, * Tcl_GetErrno will return the error code. * * Side effects: * May buffer up output and may cause output to be produced on the * channel. * *---------------------------------------------------------------------- */ static int WriteChars(chanPtr, src, srcLen) Channel *chanPtr; /* The channel to buffer output for. */ CONST char *src; /* UTF-8 string to write. */ int srcLen; /* Length of UTF-8 string in bytes. */ { ChannelState *statePtr = chanPtr->state; /* state info for channel */ ChannelBuffer *bufPtr; char *dst, *stage; int saved, savedLF, sawLF, total, dstLen, stageMax, dstWrote; int stageLen, toWrite, stageRead, endEncoding, result; int consumedSomething; Tcl_Encoding encoding; char safe[BUFFER_PADDING]; total = 0; sawLF = 0; savedLF = 0; saved = 0; encoding = statePtr->encoding; /* * Write the terminated escape sequence even if srcLen is 0. */ endEncoding = ((statePtr->outputEncodingFlags & TCL_ENCODING_END) != 0); /* * Loop over all UTF-8 characters in src, storing them in staging buffer * with proper EOL translation. */ consumedSomething = 1; while (consumedSomething && (srcLen + savedLF + endEncoding > 0)) { consumedSomething = 0; stage = statePtr->outputStage; stageMax = statePtr->bufSize; stageLen = stageMax; toWrite = stageLen; if (toWrite > srcLen) { toWrite = srcLen; } if (savedLF) { /* * A '\n' was left over from last call to TranslateOutputEOL() * and we need to store it in the staging buffer. If the * channel is line-based, we will need to flush the output * buffer (after translating the staging buffer). */ *stage++ = '\n'; stageLen--; sawLF++; } sawLF += TranslateOutputEOL(statePtr, stage, src, &stageLen, &toWrite); stage -= savedLF; stageLen += savedLF; savedLF = 0; if (stageLen > stageMax) { savedLF = 1; stageLen = stageMax; } src += toWrite; srcLen -= toWrite; /* * Loop over all UTF-8 characters in staging buffer, converting them * to external encoding, storing them in output buffer. */ while (stageLen + saved + endEncoding > 0) { bufPtr = statePtr->curOutPtr; if (bufPtr == NULL) { bufPtr = AllocChannelBuffer(statePtr->bufSize); statePtr->curOutPtr = bufPtr; } dst = bufPtr->buf + bufPtr->nextAdded; dstLen = bufPtr->bufLength - bufPtr->nextAdded; if (saved != 0) { /* * Here's some translated bytes left over from the last * buffer that we need to stick at the beginning of this * buffer. */ memcpy((VOID *) dst, (VOID *) safe, (size_t) saved); bufPtr->nextAdded += saved; dst += saved; dstLen -= saved; saved = 0; } result = Tcl_UtfToExternal(NULL, encoding, stage, stageLen, statePtr->outputEncodingFlags, &statePtr->outputEncodingState, dst, dstLen + BUFFER_PADDING, &stageRead, &dstWrote, NULL); /* Fix for SF #506297, reported by Martin Forssen * . * * The encoding chosen in the script exposing the bug writes out * three intro characters when TCL_ENCODING_START is set, but does * not consume any input as TCL_ENCODING_END is cleared. As some * output was generated the enclosing loop calls UtfToExternal * again, again with START set. Three more characters in the out * and still no use of input ... To break this infinite loop we * remove TCL_ENCODING_START from the set of flags after the first * call (no condition is required, the later calls remove an unset * flag, which is a no-op). This causes the subsequent calls to * UtfToExternal to consume and convert the actual input. */ statePtr->outputEncodingFlags &= ~TCL_ENCODING_START; /* * The following code must be executed only when result is not 0. */ if (result && ((stageRead + dstWrote) == 0)) { /* * We have an incomplete UTF-8 character at the end of the * staging buffer. It will get moved to the beginning of the * staging buffer followed by more bytes from src. */ src -= stageLen; srcLen += stageLen; stageLen = 0; savedLF = 0; break; } bufPtr->nextAdded += dstWrote; if (bufPtr->nextAdded > bufPtr->bufLength) { /* * When translating from UTF-8 to external encoding, we * allowed the translation to produce a character that * crossed the end of the output buffer, so that we would * get a completely full buffer before flushing it. The * extra bytes will be moved to the beginning of the next * buffer. */ saved = bufPtr->nextAdded - bufPtr->bufLength; memcpy((VOID *) safe, (VOID *) (dst + dstLen), (size_t) saved); bufPtr->nextAdded = bufPtr->bufLength; } if (CheckFlush(chanPtr, bufPtr, sawLF) != 0) { return -1; } total += dstWrote; stage += stageRead; stageLen -= stageRead; sawLF = 0; consumedSomething = 1; /* * If all translated characters are written to the buffer, * endEncoding is set to 0 because the escape sequence may be * output. */ if ((stageLen + saved == 0) && (result == 0)) { endEncoding = 0; } } } /* If nothing was written and it happened because there was no progress * in the UTF conversion, we throw an error. */ if (!consumedSomething && (total == 0)) { Tcl_SetErrno (EINVAL); return -1; } return total; } /* *--------------------------------------------------------------------------- * * TranslateOutputEOL -- * * Helper function for WriteBytes() and WriteChars(). Converts the * '\n' characters in the source buffer into the appropriate EOL * form specified by the output translation mode. * * EOL translation stops either when the source buffer is empty * or the output buffer is full. * * When converting to CRLF mode and there is only 1 byte left in * the output buffer, this routine stores the '\r' in the last * byte and then stores the '\n' in the byte just past the end of the * buffer. The caller is responsible for passing in a buffer that * is large enough to hold the extra byte. * * Results: * The return value is 1 if a '\n' was translated from the source * buffer, or 0 otherwise -- this can be used by the caller to * decide to flush a line-based channel even though the channel * buffer is not full. * * *dstLenPtr is filled with how many bytes of the output buffer * were used. As mentioned above, this can be one more that * the output buffer's specified length if a CRLF was stored. * * *srcLenPtr is filled with how many bytes of the source buffer * were consumed. * * Side effects: * It may be obvious, but bears mentioning that when converting * in CRLF mode (which requires two bytes of storage in the output * buffer), the number of bytes consumed from the source buffer * will be less than the number of bytes stored in the output buffer. * *--------------------------------------------------------------------------- */ static int TranslateOutputEOL(statePtr, dst, src, dstLenPtr, srcLenPtr) ChannelState *statePtr; /* Channel being read, for translation and * buffering modes. */ char *dst; /* Output buffer filled with UTF-8 chars by * applying appropriate EOL translation to * source characters. */ CONST char *src; /* Source UTF-8 characters. */ int *dstLenPtr; /* On entry, the maximum length of output * buffer in bytes. On exit, the number of * bytes actually used in output buffer. */ int *srcLenPtr; /* On entry, the length of source buffer. * On exit, the number of bytes read from * the source buffer. */ { char *dstEnd; int srcLen, newlineFound; newlineFound = 0; srcLen = *srcLenPtr; switch (statePtr->outputTranslation) { case TCL_TRANSLATE_LF: { for (dstEnd = dst + srcLen; dst < dstEnd; ) { if (*src == '\n') { newlineFound = 1; } *dst++ = *src++; } *dstLenPtr = srcLen; break; } case TCL_TRANSLATE_CR: { for (dstEnd = dst + srcLen; dst < dstEnd;) { if (*src == '\n') { *dst++ = '\r'; newlineFound = 1; src++; } else { *dst++ = *src++; } } *dstLenPtr = srcLen; break; } case TCL_TRANSLATE_CRLF: { /* * Since this causes the number of bytes to grow, we * start off trying to put 'srcLen' bytes into the * output buffer, but allow it to store more bytes, as * long as there's still source bytes and room in the * output buffer. */ char *dstStart, *dstMax; CONST char *srcStart; dstStart = dst; dstMax = dst + *dstLenPtr; srcStart = src; if (srcLen < *dstLenPtr) { dstEnd = dst + srcLen; } else { dstEnd = dst + *dstLenPtr; } while (dst < dstEnd) { if (*src == '\n') { if (dstEnd < dstMax) { dstEnd++; } *dst++ = '\r'; newlineFound = 1; } *dst++ = *src++; } *srcLenPtr = src - srcStart; *dstLenPtr = dst - dstStart; break; } default: { break; } } return newlineFound; } /* *--------------------------------------------------------------------------- * * CheckFlush -- * * Helper function for WriteBytes() and WriteChars(). If the * channel buffer is ready to be flushed, flush it. * * Results: * The return value is -1 if there was a problem flushing the * channel buffer, or 0 otherwise. * * Side effects: * The buffer will be recycled if it is flushed. * *--------------------------------------------------------------------------- */ static int CheckFlush(chanPtr, bufPtr, newlineFlag) Channel *chanPtr; /* Channel being read, for buffering mode. */ ChannelBuffer *bufPtr; /* Channel buffer to possibly flush. */ int newlineFlag; /* Non-zero if a the channel buffer * contains a newline. */ { ChannelState *statePtr = chanPtr->state; /* state info for channel */ /* * The current buffer is ready for output: * 1. if it is full. * 2. if it contains a newline and this channel is line-buffered. * 3. if it contains any output and this channel is unbuffered. */ if ((statePtr->flags & BUFFER_READY) == 0) { if (bufPtr->nextAdded == bufPtr->bufLength) { statePtr->flags |= BUFFER_READY; } else if (statePtr->flags & CHANNEL_LINEBUFFERED) { if (newlineFlag != 0) { statePtr->flags |= BUFFER_READY; } } else if (statePtr->flags & CHANNEL_UNBUFFERED) { statePtr->flags |= BUFFER_READY; } } if (statePtr->flags & BUFFER_READY) { if (FlushChannel(NULL, chanPtr, 0) != 0) { return -1; } } return 0; } /* *--------------------------------------------------------------------------- * * Tcl_Gets -- * * Reads a complete line of input from the channel into a Tcl_DString. * * Results: * Length of line read (in characters) or -1 if error, EOF, or blocked. * If -1, use Tcl_GetErrno() to retrieve the POSIX error code for the * error or condition that occurred. * * Side effects: * May flush output on the channel. May cause input to be consumed * from the channel. * *--------------------------------------------------------------------------- */ int Tcl_Gets(chan, lineRead) Tcl_Channel chan; /* Channel from which to read. */ Tcl_DString *lineRead; /* The line read will be appended to this * DString as UTF-8 characters. The caller * must have initialized it and is responsible * for managing the storage. */ { Tcl_Obj *objPtr; int charsStored, length; char *string; objPtr = Tcl_NewObj(); charsStored = Tcl_GetsObj(chan, objPtr); if (charsStored > 0) { string = Tcl_GetStringFromObj(objPtr, &length); Tcl_DStringAppend(lineRead, string, length); } Tcl_DecrRefCount(objPtr); return charsStored; } /* *--------------------------------------------------------------------------- * * Tcl_GetsObj -- * * Accumulate input from the input channel until end-of-line or * end-of-file has been seen. Bytes read from the input channel * are converted to UTF-8 using the encoding specified by the * channel. * * Results: * Number of characters accumulated in the object or -1 if error, * blocked, or EOF. If -1, use Tcl_GetErrno() to retrieve the * POSIX error code for the error or condition that occurred. * * Side effects: * Consumes input from the channel. * * On reading EOF, leave channel pointing at EOF char. * On reading EOL, leave channel pointing after EOL, but don't * return EOL in dst buffer. * *--------------------------------------------------------------------------- */ int Tcl_GetsObj(chan, objPtr) Tcl_Channel chan; /* Channel from which to read. */ Tcl_Obj *objPtr; /* The line read will be appended to this * object as UTF-8 characters. */ { GetsState gs; Channel *chanPtr = (Channel *) chan; ChannelState *statePtr = chanPtr->state; /* state info for channel */ ChannelBuffer *bufPtr; int inEofChar, skip, copiedTotal, oldLength, oldFlags, oldRemoved; Tcl_Encoding encoding; char *dst, *dstEnd, *eol, *eof; Tcl_EncodingState oldState; /* * This operation should occur at the top of a channel stack. */ chanPtr = statePtr->topChanPtr; if (CheckChannelErrors(statePtr, TCL_READABLE) != 0) { copiedTotal = -1; goto done; } bufPtr = statePtr->inQueueHead; encoding = statePtr->encoding; /* * Preserved so we can restore the channel's state in case we don't * find a newline in the available input. */ Tcl_GetStringFromObj(objPtr, &oldLength); oldFlags = statePtr->inputEncodingFlags; oldState = statePtr->inputEncodingState; oldRemoved = BUFFER_PADDING; if (bufPtr != NULL) { oldRemoved = bufPtr->nextRemoved; } /* * If there is no encoding, use "iso8859-1" -- Tcl_GetsObj() doesn't * produce ByteArray objects. To avoid circularity problems, * "iso8859-1" is builtin to Tcl. */ if (encoding == NULL) { encoding = Tcl_GetEncoding(NULL, "iso8859-1"); } /* * Object used by FilterInputBytes to keep track of how much data has * been consumed from the channel buffers. */ gs.objPtr = objPtr; gs.dstPtr = &dst; gs.encoding = encoding; gs.bufPtr = bufPtr; gs.state = oldState; gs.rawRead = 0; gs.bytesWrote = 0; gs.charsWrote = 0; gs.totalChars = 0; dst = objPtr->bytes + oldLength; dstEnd = dst; skip = 0; eof = NULL; inEofChar = statePtr->inEofChar; while (1) { if (dst >= dstEnd) { if (FilterInputBytes(chanPtr, &gs) != 0) { goto restore; } dstEnd = dst + gs.bytesWrote; } /* * Remember if EOF char is seen, then look for EOL anyhow, because * the EOL might be before the EOF char. */ if (inEofChar != '\0') { for (eol = dst; eol < dstEnd; eol++) { if (*eol == inEofChar) { dstEnd = eol; eof = eol; break; } } } /* * On EOL, leave current file position pointing after the EOL, but * don't store the EOL in the output string. */ switch (statePtr->inputTranslation) { case TCL_TRANSLATE_LF: { for (eol = dst; eol < dstEnd; eol++) { if (*eol == '\n') { skip = 1; goto goteol; } } break; } case TCL_TRANSLATE_CR: { for (eol = dst; eol < dstEnd; eol++) { if (*eol == '\r') { skip = 1; goto goteol; } } break; } case TCL_TRANSLATE_CRLF: { for (eol = dst; eol < dstEnd; eol++) { if (*eol == '\r') { eol++; if (eol >= dstEnd) { int offset; offset = eol - objPtr->bytes; dst = dstEnd; if (FilterInputBytes(chanPtr, &gs) != 0) { goto restore; } dstEnd = dst + gs.bytesWrote; eol = objPtr->bytes + offset; if (eol >= dstEnd) { skip = 0; goto goteol; } } if (*eol == '\n') { eol--; skip = 2; goto goteol; } } } break; } case TCL_TRANSLATE_AUTO: { eol = dst; skip = 1; if (statePtr->flags & INPUT_SAW_CR) { statePtr->flags &= ~INPUT_SAW_CR; if (*eol == '\n') { /* * Skip the raw bytes that make up the '\n'. */ char tmp[1 + TCL_UTF_MAX]; int rawRead; bufPtr = gs.bufPtr; Tcl_ExternalToUtf(NULL, gs.encoding, bufPtr->buf + bufPtr->nextRemoved, gs.rawRead, statePtr->inputEncodingFlags, &gs.state, tmp, 1 + TCL_UTF_MAX, &rawRead, NULL, NULL); bufPtr->nextRemoved += rawRead; gs.rawRead -= rawRead; gs.bytesWrote--; gs.charsWrote--; memmove(dst, dst + 1, (size_t) (dstEnd - dst)); dstEnd--; } } for (eol = dst; eol < dstEnd; eol++) { if (*eol == '\r') { eol++; if (eol == dstEnd) { /* * If buffer ended on \r, peek ahead to see if a * \n is available. */ int offset; offset = eol - objPtr->bytes; dst = dstEnd; PeekAhead(chanPtr, &dstEnd, &gs); eol = objPtr->bytes + offset; if (eol >= dstEnd) { eol--; statePtr->flags |= INPUT_SAW_CR; goto goteol; } } if (*eol == '\n') { skip++; } eol--; goto goteol; } else if (*eol == '\n') { goto goteol; } } } } if (eof != NULL) { /* * EOF character was seen. On EOF, leave current file position * pointing at the EOF character, but don't store the EOF * character in the output string. */ dstEnd = eof; statePtr->flags |= (CHANNEL_EOF | CHANNEL_STICKY_EOF); statePtr->inputEncodingFlags |= TCL_ENCODING_END; } if (statePtr->flags & CHANNEL_EOF) { skip = 0; eol = dstEnd; if (eol == objPtr->bytes + oldLength) { /* * If we didn't append any bytes before encountering EOF, * caller needs to see -1. */ Tcl_SetObjLength(objPtr, oldLength); CommonGetsCleanup(chanPtr, encoding); copiedTotal = -1; goto done; } goto goteol; } dst = dstEnd; } /* * Found EOL or EOF, but the output buffer may now contain too many * UTF-8 characters. We need to know how many raw bytes correspond to * the number of UTF-8 characters we want, plus how many raw bytes * correspond to the character(s) making up EOL (if any), so we can * remove the correct number of bytes from the channel buffer. */ goteol: bufPtr = gs.bufPtr; statePtr->inputEncodingState = gs.state; Tcl_ExternalToUtf(NULL, gs.encoding, bufPtr->buf + bufPtr->nextRemoved, gs.rawRead, statePtr->inputEncodingFlags, &statePtr->inputEncodingState, dst, eol - dst + skip + TCL_UTF_MAX, &gs.rawRead, NULL, &gs.charsWrote); bufPtr->nextRemoved += gs.rawRead; /* * Recycle all the emptied buffers. */ Tcl_SetObjLength(objPtr, eol - objPtr->bytes); CommonGetsCleanup(chanPtr, encoding); statePtr->flags &= ~CHANNEL_BLOCKED; copiedTotal = gs.totalChars + gs.charsWrote - skip; goto done; /* * Couldn't get a complete line. This only happens if we get a error * reading from the channel or we are non-blocking and there wasn't * an EOL or EOF in the data available. */ restore: bufPtr = statePtr->inQueueHead; bufPtr->nextRemoved = oldRemoved; for (bufPtr = bufPtr->nextPtr; bufPtr != NULL; bufPtr = bufPtr->nextPtr) { bufPtr->nextRemoved = BUFFER_PADDING; } CommonGetsCleanup(chanPtr, encoding); statePtr->inputEncodingState = oldState; statePtr->inputEncodingFlags = oldFlags; Tcl_SetObjLength(objPtr, oldLength); /* * We didn't get a complete line so we need to indicate to UpdateInterest * that the gets blocked. It will wait for more data instead of firing * a timer, avoiding a busy wait. This is where we are assuming that the * next operation is a gets. No more file events will be delivered on * this channel until new data arrives or some operation is performed * on the channel (e.g. gets, read, fconfigure) that changes the blocking * state. Note that this means a file event will not be delivered even * though a read would be able to consume the buffered data. */ statePtr->flags |= CHANNEL_NEED_MORE_DATA; copiedTotal = -1; done: /* * Update the notifier state so we don't block while there is still * data in the buffers. */ UpdateInterest(chanPtr); return copiedTotal; } /* *--------------------------------------------------------------------------- * * FilterInputBytes -- * * Helper function for Tcl_GetsObj. Produces UTF-8 characters from * raw bytes read from the channel. * * Consumes available bytes from channel buffers. When channel * buffers are exhausted, reads more bytes from channel device into * a new channel buffer. It is the caller's responsibility to * free the channel buffers that have been exhausted. * * Results: * The return value is -1 if there was an error reading from the * channel, 0 otherwise. * * Side effects: * Status object keeps track of how much data from channel buffers * has been consumed and where UTF-8 bytes should be stored. * *--------------------------------------------------------------------------- */ static int FilterInputBytes(chanPtr, gsPtr) Channel *chanPtr; /* Channel to read. */ GetsState *gsPtr; /* Current state of gets operation. */ { ChannelState *statePtr = chanPtr->state; /* state info for channel */ ChannelBuffer *bufPtr; char *raw, *rawStart, *rawEnd; char *dst; int offset, toRead, dstNeeded, spaceLeft, result, rawLen, length; Tcl_Obj *objPtr; #define ENCODING_LINESIZE 20 /* Lower bound on how many bytes to convert * at a time. Since we don't know a priori * how many bytes of storage this many source * bytes will use, we actually need at least * ENCODING_LINESIZE * TCL_MAX_UTF bytes of * room. */ objPtr = gsPtr->objPtr; /* * Subtract the number of bytes that were removed from channel buffer * during last call. */ bufPtr = gsPtr->bufPtr; if (bufPtr != NULL) { bufPtr->nextRemoved += gsPtr->rawRead; if (bufPtr->nextRemoved >= bufPtr->nextAdded) { bufPtr = bufPtr->nextPtr; } } gsPtr->totalChars += gsPtr->charsWrote; if ((bufPtr == NULL) || (bufPtr->nextAdded == BUFFER_PADDING)) { /* * All channel buffers were exhausted and the caller still hasn't * seen EOL. Need to read more bytes from the channel device. * Side effect is to allocate another channel buffer. */ read: if (statePtr->flags & CHANNEL_BLOCKED) { if (statePtr->flags & CHANNEL_NONBLOCKING) { gsPtr->charsWrote = 0; gsPtr->rawRead = 0; return -1; } statePtr->flags &= ~CHANNEL_BLOCKED; } if (GetInput(chanPtr) != 0) { gsPtr->charsWrote = 0; gsPtr->rawRead = 0; return -1; } bufPtr = statePtr->inQueueTail; gsPtr->bufPtr = bufPtr; } /* * Convert some of the bytes from the channel buffer to UTF-8. Space in * objPtr's string rep is used to hold the UTF-8 characters. Grow the * string rep if we need more space. */ rawStart = bufPtr->buf + bufPtr->nextRemoved; raw = rawStart; rawEnd = bufPtr->buf + bufPtr->nextAdded; rawLen = rawEnd - rawStart; dst = *gsPtr->dstPtr; offset = dst - objPtr->bytes; toRead = ENCODING_LINESIZE; if (toRead > rawLen) { toRead = rawLen; } dstNeeded = toRead * TCL_UTF_MAX + 1; spaceLeft = objPtr->length - offset - TCL_UTF_MAX - 1; if (dstNeeded > spaceLeft) { length = offset * 2; if (offset < dstNeeded) { length = offset + dstNeeded; } length += TCL_UTF_MAX + 1; Tcl_SetObjLength(objPtr, length); spaceLeft = length - offset; dst = objPtr->bytes + offset; *gsPtr->dstPtr = dst; } gsPtr->state = statePtr->inputEncodingState; result = Tcl_ExternalToUtf(NULL, gsPtr->encoding, raw, rawLen, statePtr->inputEncodingFlags, &statePtr->inputEncodingState, dst, spaceLeft, &gsPtr->rawRead, &gsPtr->bytesWrote, &gsPtr->charsWrote); /* * Make sure that if we go through 'gets', that we reset the * TCL_ENCODING_START flag still. [Bug #523988] */ statePtr->inputEncodingFlags &= ~TCL_ENCODING_START; if (result == TCL_CONVERT_MULTIBYTE) { /* * The last few bytes in this channel buffer were the start of a * multibyte sequence. If this buffer was full, then move them to * the next buffer so the bytes will be contiguous. */ ChannelBuffer *nextPtr; int extra; nextPtr = bufPtr->nextPtr; if (bufPtr->nextAdded < bufPtr->bufLength) { if (gsPtr->rawRead > 0) { /* * Some raw bytes were converted to UTF-8. Fall through, * returning those UTF-8 characters because a EOL might be * present in them. */ } else if (statePtr->flags & CHANNEL_EOF) { /* * There was a partial character followed by EOF on the * device. Fall through, returning that nothing was found. */ bufPtr->nextRemoved = bufPtr->nextAdded; } else { /* * There are no more cached raw bytes left. See if we can * get some more. */ goto read; } } else { if (nextPtr == NULL) { nextPtr = AllocChannelBuffer(statePtr->bufSize); bufPtr->nextPtr = nextPtr; statePtr->inQueueTail = nextPtr; } extra = rawLen - gsPtr->rawRead; memcpy((VOID *) (nextPtr->buf + BUFFER_PADDING - extra), (VOID *) (raw + gsPtr->rawRead), (size_t) extra); nextPtr->nextRemoved -= extra; bufPtr->nextAdded -= extra; } } gsPtr->bufPtr = bufPtr; return 0; } /* *--------------------------------------------------------------------------- * * PeekAhead -- * * Helper function used by Tcl_GetsObj(). Called when we've seen a * \r at the end of the UTF-8 string and want to look ahead one * character to see if it is a \n. * * Results: * *gsPtr->dstPtr is filled with a pointer to the start of the range of * UTF-8 characters that were found by peeking and *dstEndPtr is filled * with a pointer to the bytes just after the end of the range. * * Side effects: * If no more raw bytes were available in one of the channel buffers, * tries to perform a non-blocking read to get more bytes from the * channel device. * *--------------------------------------------------------------------------- */ static void PeekAhead(chanPtr, dstEndPtr, gsPtr) Channel *chanPtr; /* The channel to read. */ char **dstEndPtr; /* Filled with pointer to end of new range * of UTF-8 characters. */ GetsState *gsPtr; /* Current state of gets operation. */ { ChannelState *statePtr = chanPtr->state; /* state info for channel */ ChannelBuffer *bufPtr; Tcl_DriverBlockModeProc *blockModeProc; int bytesLeft; bufPtr = gsPtr->bufPtr; /* * If there's any more raw input that's still buffered, we'll peek into * that. Otherwise, only get more data from the channel driver if it * looks like there might actually be more data. The assumption is that * if the channel buffer is filled right up to the end, then there * might be more data to read. */ blockModeProc = NULL; if (bufPtr->nextPtr == NULL) { bytesLeft = bufPtr->nextAdded - (bufPtr->nextRemoved + gsPtr->rawRead); if (bytesLeft == 0) { if (bufPtr->nextAdded < bufPtr->bufLength) { /* * Don't peek ahead if last read was short read. */ goto cleanup; } if ((statePtr->flags & CHANNEL_NONBLOCKING) == 0) { blockModeProc = Tcl_ChannelBlockModeProc(chanPtr->typePtr); if (blockModeProc == NULL) { /* * Don't peek ahead if cannot set non-blocking mode. */ goto cleanup; } StackSetBlockMode(chanPtr, TCL_MODE_NONBLOCKING); } } } if (FilterInputBytes(chanPtr, gsPtr) == 0) { *dstEndPtr = *gsPtr->dstPtr + gsPtr->bytesWrote; } if (blockModeProc != NULL) { StackSetBlockMode(chanPtr, TCL_MODE_BLOCKING); } return; cleanup: bufPtr->nextRemoved += gsPtr->rawRead; gsPtr->rawRead = 0; gsPtr->totalChars += gsPtr->charsWrote; gsPtr->bytesWrote = 0; gsPtr->charsWrote = 0; } /* *--------------------------------------------------------------------------- * * CommonGetsCleanup -- * * Helper function for Tcl_GetsObj() to restore the channel after * a "gets" operation. * * Results: * None. * * Side effects: * Encoding may be freed. * *--------------------------------------------------------------------------- */ static void CommonGetsCleanup(chanPtr, encoding) Channel *chanPtr; Tcl_Encoding encoding; { ChannelState *statePtr = chanPtr->state; /* state info for channel */ ChannelBuffer *bufPtr, *nextPtr; bufPtr = statePtr->inQueueHead; for ( ; bufPtr != NULL; bufPtr = nextPtr) { nextPtr = bufPtr->nextPtr; if (bufPtr->nextRemoved < bufPtr->nextAdded) { break; } RecycleBuffer(statePtr, bufPtr, 0); } statePtr->inQueueHead = bufPtr; if (bufPtr == NULL) { statePtr->inQueueTail = NULL; } else { /* * If any multi-byte characters were split across channel buffer * boundaries, the split-up bytes were moved to the next channel * buffer by FilterInputBytes(). Move the bytes back to their * original buffer because the caller could change the channel's * encoding which could change the interpretation of whether those * bytes really made up multi-byte characters after all. */ nextPtr = bufPtr->nextPtr; for ( ; nextPtr != NULL; nextPtr = bufPtr->nextPtr) { int extra; extra = bufPtr->bufLength - bufPtr->nextAdded; if (extra > 0) { memcpy((VOID *) (bufPtr->buf + bufPtr->nextAdded), (VOID *) (nextPtr->buf + BUFFER_PADDING - extra), (size_t) extra); bufPtr->nextAdded += extra; nextPtr->nextRemoved = BUFFER_PADDING; } bufPtr = nextPtr; } } if (statePtr->encoding == NULL) { Tcl_FreeEncoding(encoding); } } /* *---------------------------------------------------------------------- * * Tcl_Read -- * * Reads a given number of bytes from a channel. EOL and EOF * translation is done on the bytes being read, so the the number * of bytes consumed from the channel may not be equal to the * number of bytes stored in the destination buffer. * * No encoding conversions are applied to the bytes being read. * * Results: * The number of bytes read, or -1 on error. Use Tcl_GetErrno() * to retrieve the error code for the error that occurred. * * Side effects: * May cause input to be buffered. * *---------------------------------------------------------------------- */ int Tcl_Read(chan, dst, bytesToRead) Tcl_Channel chan; /* The channel from which to read. */ char *dst; /* Where to store input read. */ int bytesToRead; /* Maximum number of bytes to read. */ { Channel *chanPtr = (Channel *) chan; ChannelState *statePtr = chanPtr->state; /* state info for channel */ /* * This operation should occur at the top of a channel stack. */ chanPtr = statePtr->topChanPtr; if (CheckChannelErrors(statePtr, TCL_READABLE) != 0) { return -1; } return DoRead(chanPtr, dst, bytesToRead); } /* *---------------------------------------------------------------------- * * Tcl_ReadRaw -- * * Reads a given number of bytes from a channel. EOL and EOF * translation is done on the bytes being read, so the the number * of bytes consumed from the channel may not be equal to the * number of bytes stored in the destination buffer. * * No encoding conversions are applied to the bytes being read. * * Results: * The number of bytes read, or -1 on error. Use Tcl_GetErrno() * to retrieve the error code for the error that occurred. * * Side effects: * May cause input to be buffered. * *---------------------------------------------------------------------- */ int Tcl_ReadRaw(chan, bufPtr, bytesToRead) Tcl_Channel chan; /* The channel from which to read. */ char *bufPtr; /* Where to store input read. */ int bytesToRead; /* Maximum number of bytes to read. */ { Channel *chanPtr = (Channel *) chan; ChannelState *statePtr = chanPtr->state; /* state info for channel */ int nread, result; int copied, copiedNow; /* * The check below does too much because it will reject a call to this * function with a channel which is part of an 'fcopy'. But we have to * allow this here or else the chaining in the transformation drivers * will fail with 'file busy' error instead of retrieving and * transforming the data to copy. * * We let the check procedure now believe that there is no fcopy in * progress. A better solution than this might be an additional flag * argument to switch off specific checks. */ if (CheckChannelErrors(statePtr, TCL_READABLE | CHANNEL_RAW_MODE) != 0) { return -1; } /* * Check for information in the push-back buffers. If there is * some, use it. Go to the driver only if there is none (anymore) * and the caller requests more bytes. */ for (copied = 0; copied < bytesToRead; copied += copiedNow) { copiedNow = CopyBuffer(chanPtr, bufPtr + copied, bytesToRead - copied); if (copiedNow == 0) { if (statePtr->flags & CHANNEL_EOF) { goto done; } if (statePtr->flags & CHANNEL_BLOCKED) { if (statePtr->flags & CHANNEL_NONBLOCKING) { goto done; } statePtr->flags &= (~(CHANNEL_BLOCKED)); } #ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING /* [SF Tcl Bug 943274]. Better emulation of non-blocking * channels for channels without BlockModeProc, by keeping * track of true fileevents generated by the OS == Data * waiting and reading if and only if we are sure to have * data. */ if ((statePtr->flags & CHANNEL_NONBLOCKING) && (Tcl_ChannelBlockModeProc(chanPtr->typePtr) == NULL) && !(statePtr->flags & CHANNEL_HAS_MORE_DATA)) { /* We bypass the driver, it would block, as no data is available */ nread = -1; result = EWOULDBLOCK; } else { #endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */ /* * Now go to the driver to get as much as is possible to * fill the remaining request. Do all the error handling * by ourselves. The code was stolen from 'GetInput' and * slightly adapted (different return value here). * * The case of 'bytesToRead == 0' at this point cannot happen. */ nread = (chanPtr->typePtr->inputProc)(chanPtr->instanceData, bufPtr + copied, bytesToRead - copied, &result); #ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING } #endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */ if (nread > 0) { /* * If we get a short read, signal up that we may be * BLOCKED. We should avoid calling the driver because * on some platforms we will block in the low level * reading code even though the channel is set into * nonblocking mode. */ if (nread < (bytesToRead - copied)) { statePtr->flags |= CHANNEL_BLOCKED; } #ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING if (nread <= (bytesToRead - copied)) { /* [SF Tcl Bug 943274] We have read the available * data, clear flag */ statePtr->flags &= ~CHANNEL_HAS_MORE_DATA; } #endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */ } else if (nread == 0) { statePtr->flags |= CHANNEL_EOF; statePtr->inputEncodingFlags |= TCL_ENCODING_END; } else if (nread < 0) { if ((result == EWOULDBLOCK) || (result == EAGAIN)) { if (copied > 0) { /* * Information that was copied earlier has precedence * over EAGAIN/WOULDBLOCK handling. */ return copied; } statePtr->flags |= CHANNEL_BLOCKED; result = EAGAIN; } Tcl_SetErrno(result); return -1; } return copied + nread; } } done: return copied; } /* *--------------------------------------------------------------------------- * * Tcl_ReadChars -- * * Reads from the channel until the requested number of characters * have been seen, EOF is seen, or the channel would block. EOL * and EOF translation is done. If reading binary data, the raw * bytes are wrapped in a Tcl byte array object. Otherwise, the raw * bytes are converted to UTF-8 using the channel's current encoding * and stored in a Tcl string object. * * Results: * The number of characters read, or -1 on error. Use Tcl_GetErrno() * to retrieve the error code for the error that occurred. * * Side effects: * May cause input to be buffered. * *--------------------------------------------------------------------------- */ int Tcl_ReadChars(chan, objPtr, toRead, appendFlag) Tcl_Channel chan; /* The channel to read. */ Tcl_Obj *objPtr; /* Input data is stored in this object. */ int toRead; /* Maximum number of characters to store, * or -1 to read all available data (up to EOF * or when channel blocks). */ int appendFlag; /* If non-zero, data read from the channel * will be appended to the object. Otherwise, * the data will replace the existing contents * of the object. */ { Channel* chanPtr = (Channel *) chan; ChannelState* statePtr = chanPtr->state; /* state info for channel */ /* * This operation should occur at the top of a channel stack. */ chanPtr = statePtr->topChanPtr; if (CheckChannelErrors(statePtr, TCL_READABLE) != 0) { /* * Update the notifier state so we don't block while there is still * data in the buffers. */ UpdateInterest(chanPtr); return -1; } return DoReadChars (chanPtr, objPtr, toRead, appendFlag); } /* *--------------------------------------------------------------------------- * * DoReadChars -- * * Reads from the channel until the requested number of characters * have been seen, EOF is seen, or the channel would block. EOL * and EOF translation is done. If reading binary data, the raw * bytes are wrapped in a Tcl byte array object. Otherwise, the raw * bytes are converted to UTF-8 using the channel's current encoding * and stored in a Tcl string object. * * Results: * The number of characters read, or -1 on error. Use Tcl_GetErrno() * to retrieve the error code for the error that occurred. * * Side effects: * May cause input to be buffered. * *--------------------------------------------------------------------------- */ static int DoReadChars(chanPtr, objPtr, toRead, appendFlag) Channel* chanPtr; /* The channel to read. */ Tcl_Obj *objPtr; /* Input data is stored in this object. */ int toRead; /* Maximum number of characters to store, * or -1 to read all available data (up to EOF * or when channel blocks). */ int appendFlag; /* If non-zero, data read from the channel * will be appended to the object. Otherwise, * the data will replace the existing contents * of the object. */ { ChannelState *statePtr = chanPtr->state; /* state info for channel */ ChannelBuffer *bufPtr; int offset, factor, copied, copiedNow, result; Tcl_Encoding encoding; #define UTF_EXPANSION_FACTOR 1024 /* * This operation should occur at the top of a channel stack. */ chanPtr = statePtr->topChanPtr; encoding = statePtr->encoding; factor = UTF_EXPANSION_FACTOR; if (appendFlag == 0) { if (encoding == NULL) { Tcl_SetByteArrayLength(objPtr, 0); } else { Tcl_SetObjLength(objPtr, 0); /* * We're going to access objPtr->bytes directly, so * we must ensure that this is actually a string * object (otherwise it might have been pure Unicode). */ Tcl_GetString(objPtr); } offset = 0; } else { if (encoding == NULL) { Tcl_GetByteArrayFromObj(objPtr, &offset); } else { Tcl_GetStringFromObj(objPtr, &offset); } } for (copied = 0; (unsigned) toRead > 0; ) { copiedNow = -1; if (statePtr->inQueueHead != NULL) { if (encoding == NULL) { copiedNow = ReadBytes(statePtr, objPtr, toRead, &offset); } else { copiedNow = ReadChars(statePtr, objPtr, toRead, &offset, &factor); } /* * If the current buffer is empty recycle it. */ bufPtr = statePtr->inQueueHead; if (bufPtr->nextRemoved == bufPtr->nextAdded) { ChannelBuffer *nextPtr; nextPtr = bufPtr->nextPtr; RecycleBuffer(statePtr, bufPtr, 0); statePtr->inQueueHead = nextPtr; if (nextPtr == NULL) { statePtr->inQueueTail = NULL; } } } if (copiedNow < 0) { if (statePtr->flags & CHANNEL_EOF) { break; } if (statePtr->flags & CHANNEL_BLOCKED) { if (statePtr->flags & CHANNEL_NONBLOCKING) { break; } statePtr->flags &= ~CHANNEL_BLOCKED; } result = GetInput(chanPtr); if (result != 0) { if (result == EAGAIN) { break; } copied = -1; goto done; } } else { copied += copiedNow; toRead -= copiedNow; } } statePtr->flags &= ~CHANNEL_BLOCKED; if (encoding == NULL) { Tcl_SetByteArrayLength(objPtr, offset); } else { Tcl_SetObjLength(objPtr, offset); } done: /* * Update the notifier state so we don't block while there is still * data in the buffers. */ UpdateInterest(chanPtr); return copied; } /* *--------------------------------------------------------------------------- * * ReadBytes -- * * Reads from the channel until the requested number of bytes have * been seen, EOF is seen, or the channel would block. Bytes from * the channel are stored in objPtr as a ByteArray object. EOL * and EOF translation are done. * * 'bytesToRead' can safely be a very large number because * space is only allocated to hold data read from the channel * as needed. * * Results: * The return value is the number of bytes appended to the object * and *offsetPtr is filled with the total number of bytes in the * object (greater than the return value if there were already bytes * in the object). * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int ReadBytes(statePtr, objPtr, bytesToRead, offsetPtr) ChannelState *statePtr; /* State of the channel to read. */ Tcl_Obj *objPtr; /* Input data is appended to this ByteArray * object. Its length is how much space * has been allocated to hold data, not how * many bytes of data have been stored in the * object. */ int bytesToRead; /* Maximum number of bytes to store, * or < 0 to get all available bytes. * Bytes are obtained from the first * buffer in the queue -- even if this number * is larger than the number of bytes * available in the first buffer, only the * bytes from the first buffer are * returned. */ int *offsetPtr; /* On input, contains how many bytes of * objPtr have been used to hold data. On * output, filled with how many bytes are now * being used. */ { int toRead, srcLen, offset, length, srcRead, dstWrote; ChannelBuffer *bufPtr; char *src, *dst; offset = *offsetPtr; bufPtr = statePtr->inQueueHead; src = bufPtr->buf + bufPtr->nextRemoved; srcLen = bufPtr->nextAdded - bufPtr->nextRemoved; toRead = bytesToRead; if ((unsigned) toRead > (unsigned) srcLen) { toRead = srcLen; } dst = (char *) Tcl_GetByteArrayFromObj(objPtr, &length); if (toRead > length - offset - 1) { /* * Double the existing size of the object or make enough room to * hold all the characters we may get from the source buffer, * whichever is larger. */ length = offset * 2; if (offset < toRead) { length = offset + toRead + 1; } dst = (char *) Tcl_SetByteArrayLength(objPtr, length); } dst += offset; if (statePtr->flags & INPUT_NEED_NL) { statePtr->flags &= ~INPUT_NEED_NL; if ((srcLen == 0) || (*src != '\n')) { *dst = '\r'; *offsetPtr += 1; return 1; } *dst++ = '\n'; src++; srcLen--; toRead--; } srcRead = srcLen; dstWrote = toRead; if (TranslateInputEOL(statePtr, dst, src, &dstWrote, &srcRead) != 0) { if (dstWrote == 0) { return -1; } } bufPtr->nextRemoved += srcRead; *offsetPtr += dstWrote; return dstWrote; } /* *--------------------------------------------------------------------------- * * ReadChars -- * * Reads from the channel until the requested number of UTF-8 * characters have been seen, EOF is seen, or the channel would * block. Raw bytes from the channel are converted to UTF-8 * and stored in objPtr. EOL and EOF translation is done. * * 'charsToRead' can safely be a very large number because * space is only allocated to hold data read from the channel * as needed. * * Results: * The return value is the number of characters appended to * the object, *offsetPtr is filled with the number of bytes that * were appended, and *factorPtr is filled with the expansion * factor used to guess how many bytes of UTF-8 to allocate to * hold N source bytes. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int ReadChars(statePtr, objPtr, charsToRead, offsetPtr, factorPtr) ChannelState *statePtr; /* State of channel to read. */ Tcl_Obj *objPtr; /* Input data is appended to this object. * objPtr->length is how much space has been * allocated to hold data, not how many bytes * of data have been stored in the object. */ int charsToRead; /* Maximum number of characters to store, * or -1 to get all available characters. * Characters are obtained from the first * buffer in the queue -- even if this number * is larger than the number of characters * available in the first buffer, only the * characters from the first buffer are * returned. */ int *offsetPtr; /* On input, contains how many bytes of * objPtr have been used to hold data. On * output, filled with how many bytes are now * being used. */ int *factorPtr; /* On input, contains a guess of how many * bytes need to be allocated to hold the * result of converting N source bytes to * UTF-8. On output, contains another guess * based on the data seen so far. */ { int toRead, factor, offset, spaceLeft, length, srcLen, dstNeeded; int srcRead, dstWrote, numChars, dstRead; ChannelBuffer *bufPtr; char *src, *dst; Tcl_EncodingState oldState; int encEndFlagSuppressed = 0; factor = *factorPtr; offset = *offsetPtr; bufPtr = statePtr->inQueueHead; src = bufPtr->buf + bufPtr->nextRemoved; srcLen = bufPtr->nextAdded - bufPtr->nextRemoved; toRead = charsToRead; if ((unsigned)toRead > (unsigned)srcLen) { toRead = srcLen; } /* * 'factor' is how much we guess that the bytes in the source buffer * will expand when converted to UTF-8 chars. This guess comes from * analyzing how many characters were produced by the previous * pass. */ dstNeeded = toRead * factor / UTF_EXPANSION_FACTOR; spaceLeft = objPtr->length - offset - TCL_UTF_MAX - 1; if (dstNeeded > spaceLeft) { /* * Double the existing size of the object or make enough room to * hold all the characters we want from the source buffer, * whichever is larger. */ length = offset * 2; if (offset < dstNeeded) { length = offset + dstNeeded; } spaceLeft = length - offset; length += TCL_UTF_MAX + 1; Tcl_SetObjLength(objPtr, length); } if (toRead == srcLen) { /* * Want to convert the whole buffer in one pass. If we have * enough space, convert it using all available space in object * rather than using the factor. */ dstNeeded = spaceLeft; } dst = objPtr->bytes + offset; /* * SF Tcl Bug 1462248 * The cause of the crash reported in the referenced bug is this: * * - ReadChars, called with a single buffer, with a incomplete * multi-byte character at the end (only the first byte of it). * - Encoding translation fails, asks for more data * - Data is read, and eof is reached, TCL_ENCODING_END (TEE) is set. * - ReadChar is called again, converts the first buffer, but due * to TEE it does not check for incomplete multi-byte data, and the * character just after the end of the first buffer is a valid * completion of the multi-byte header in the actual buffer. The * conversion reads more characters from the buffer then present. * This causes nextRemoved to overshoot nextAdded and the next * reads compute a negative srcLen, cause further translations to * fail, causing copying of data into the next buffer using bad * arguments, causing the mecpy for to eventually fail. * * In the end it is a memory access bug spiraling out of control * if the conditions are _just so_. And ultimate cause is that TEE * is given to a conversion where it should not. TEE signals that * this is the last buffer. Except in our case it is not. * * My solution is to suppress TEE if the first buffer is not the * last. We will eventually need it given that EOF has been * reached, but not right now. This is what the new flag * "endEncSuppressFlag" is for. * * The bug in 'Tcl_Utf2UtfProc' where it read from memory behind * the actual buffer has been fixed as well, and fixes the problem * with the crash too, but this would still allow the generic * layer to accidentially break a multi-byte sequence if the * conditions are just right, because again the ExternalToUtf * would be successful where it should not. */ if ((statePtr->inputEncodingFlags & TCL_ENCODING_END) && (bufPtr->nextPtr != NULL)) { /* TEE is set for a buffer which is not the last. Squash it * for now, and restore it later, before yielding control to * our caller. */ statePtr->inputEncodingFlags &= ~TCL_ENCODING_END; encEndFlagSuppressed = 1; } oldState = statePtr->inputEncodingState; if (statePtr->flags & INPUT_NEED_NL) { /* * We want a '\n' because the last character we saw was '\r'. */ statePtr->flags &= ~INPUT_NEED_NL; Tcl_ExternalToUtf(NULL, statePtr->encoding, src, srcLen, statePtr->inputEncodingFlags, &statePtr->inputEncodingState, dst, TCL_UTF_MAX + 1, &srcRead, &dstWrote, &numChars); if ((dstWrote > 0) && (*dst == '\n')) { /* * The next char was a '\n'. Consume it and produce a '\n'. */ bufPtr->nextRemoved += srcRead; } else { /* * The next char was not a '\n'. Produce a '\r'. */ *dst = '\r'; } statePtr->inputEncodingFlags &= ~TCL_ENCODING_START; *offsetPtr += 1; if (encEndFlagSuppressed) { statePtr->inputEncodingFlags |= TCL_ENCODING_END; } return 1; } Tcl_ExternalToUtf(NULL, statePtr->encoding, src, srcLen, statePtr->inputEncodingFlags, &statePtr->inputEncodingState, dst, dstNeeded + TCL_UTF_MAX, &srcRead, &dstWrote, &numChars); if (encEndFlagSuppressed) { statePtr->inputEncodingFlags |= TCL_ENCODING_END; } if (srcRead == 0) { /* * Not enough bytes in src buffer to make a complete char. Copy * the bytes to the next buffer to make a new contiguous string, * then tell the caller to fill the buffer with more bytes. */ ChannelBuffer *nextPtr; nextPtr = bufPtr->nextPtr; if (nextPtr == NULL) { if (srcLen > 0) { /* * There isn't enough data in the buffers to complete the next * character, so we need to wait for more data before the next * file event can be delivered. * * SF #478856. * * The exception to this is if the input buffer was * completely empty before we tried to convert its * contents. Nothing in, nothing out, and no incomplete * character data. The conversion before the current one * was complete. */ statePtr->flags |= CHANNEL_NEED_MORE_DATA; } return -1; } /* Space is made at the beginning of the buffer to copy the * previous unused bytes there. Check first if the buffer we * are using actually has enough space at its beginning for * the data we are copying. Because if not we will write over the * buffer management information, especially the 'nextPtr'. * * Note that the BUFFER_PADDING (See AllocChannelBuffer) is * used to prevent exactly this situation. I.e. it should * never happen. Therefore it is ok to panic should it happen * despite the precautions. */ if (nextPtr->nextRemoved - srcLen < 0) { Tcl_Panic ("Buffer Underflow, BUFFER_PADDING not enough"); } nextPtr->nextRemoved -= srcLen; memcpy((VOID *) (nextPtr->buf + nextPtr->nextRemoved), (VOID *) src, (size_t) srcLen); RecycleBuffer(statePtr, bufPtr, 0); statePtr->inQueueHead = nextPtr; return ReadChars(statePtr, objPtr, charsToRead, offsetPtr, factorPtr); } dstRead = dstWrote; if (TranslateInputEOL(statePtr, dst, dst, &dstWrote, &dstRead) != 0) { /* * Hit EOF char. How many bytes of src correspond to where the * EOF was located in dst? Run the conversion again with an * output buffer just big enough to hold the data so we can * get the correct value for srcRead. */ if (dstWrote == 0) { return -1; } statePtr->inputEncodingState = oldState; Tcl_ExternalToUtf(NULL, statePtr->encoding, src, srcLen, statePtr->inputEncodingFlags, &statePtr->inputEncodingState, dst, dstRead + TCL_UTF_MAX, &srcRead, &dstWrote, &numChars); TranslateInputEOL(statePtr, dst, dst, &dstWrote, &dstRead); } /* * The number of characters that we got may be less than the number * that we started with because "\r\n" sequences may have been * turned into just '\n' in dst. */ numChars -= (dstRead - dstWrote); if ((unsigned) numChars > (unsigned) toRead) { /* * Got too many chars. */ CONST char *eof; eof = Tcl_UtfAtIndex(dst, toRead); statePtr->inputEncodingState = oldState; Tcl_ExternalToUtf(NULL, statePtr->encoding, src, srcLen, statePtr->inputEncodingFlags, &statePtr->inputEncodingState, dst, eof - dst + TCL_UTF_MAX, &srcRead, &dstWrote, &numChars); dstRead = dstWrote; TranslateInputEOL(statePtr, dst, dst, &dstWrote, &dstRead); numChars -= (dstRead - dstWrote); } statePtr->inputEncodingFlags &= ~TCL_ENCODING_START; bufPtr->nextRemoved += srcRead; if (dstWrote > srcRead + 1) { *factorPtr = dstWrote * UTF_EXPANSION_FACTOR / srcRead; } *offsetPtr += dstWrote; return numChars; } /* *--------------------------------------------------------------------------- * * TranslateInputEOL -- * * Perform input EOL and EOF translation on the source buffer, * leaving the translated result in the destination buffer. * * Results: * The return value is 1 if the EOF character was found when copying * bytes to the destination buffer, 0 otherwise. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int TranslateInputEOL(statePtr, dstStart, srcStart, dstLenPtr, srcLenPtr) ChannelState *statePtr; /* Channel being read, for EOL translation * and EOF character. */ char *dstStart; /* Output buffer filled with chars by * applying appropriate EOL translation to * source characters. */ CONST char *srcStart; /* Source characters. */ int *dstLenPtr; /* On entry, the maximum length of output * buffer in bytes; must be <= *srcLenPtr. On * exit, the number of bytes actually used in * output buffer. */ int *srcLenPtr; /* On entry, the length of source buffer. * On exit, the number of bytes read from * the source buffer. */ { int dstLen, srcLen, inEofChar; CONST char *eof; dstLen = *dstLenPtr; eof = NULL; inEofChar = statePtr->inEofChar; if (inEofChar != '\0') { /* * Find EOF in translated buffer then compress out the EOL. The * source buffer may be much longer than the destination buffer -- * we only want to return EOF if the EOF has been copied to the * destination buffer. */ CONST char *src, *srcMax; srcMax = srcStart + *srcLenPtr; for (src = srcStart; src < srcMax; src++) { if (*src == inEofChar) { eof = src; srcLen = src - srcStart; if (srcLen < dstLen) { dstLen = srcLen; } *srcLenPtr = srcLen; break; } } } switch (statePtr->inputTranslation) { case TCL_TRANSLATE_LF: { if (dstStart != srcStart) { memcpy((VOID *) dstStart, (VOID *) srcStart, (size_t) dstLen); } srcLen = dstLen; break; } case TCL_TRANSLATE_CR: { char *dst, *dstEnd; if (dstStart != srcStart) { memcpy((VOID *) dstStart, (VOID *) srcStart, (size_t) dstLen); } dstEnd = dstStart + dstLen; for (dst = dstStart; dst < dstEnd; dst++) { if (*dst == '\r') { *dst = '\n'; } } srcLen = dstLen; break; } case TCL_TRANSLATE_CRLF: { char *dst; CONST char *src, *srcEnd, *srcMax; dst = dstStart; src = srcStart; srcEnd = srcStart + dstLen; srcMax = srcStart + *srcLenPtr; for ( ; src < srcEnd; ) { if (*src == '\r') { src++; if (src >= srcMax) { statePtr->flags |= INPUT_NEED_NL; } else if (*src == '\n') { *dst++ = *src++; } else { *dst++ = '\r'; } } else { *dst++ = *src++; } } srcLen = src - srcStart; dstLen = dst - dstStart; break; } case TCL_TRANSLATE_AUTO: { char *dst; CONST char *src, *srcEnd, *srcMax; dst = dstStart; src = srcStart; srcEnd = srcStart + dstLen; srcMax = srcStart + *srcLenPtr; if ((statePtr->flags & INPUT_SAW_CR) && (src < srcMax)) { if (*src == '\n') { src++; } statePtr->flags &= ~INPUT_SAW_CR; } for ( ; src < srcEnd; ) { if (*src == '\r') { src++; if (src >= srcMax) { statePtr->flags |= INPUT_SAW_CR; } else if (*src == '\n') { if (srcEnd < srcMax) { srcEnd++; } src++; } *dst++ = '\n'; } else { *dst++ = *src++; } } srcLen = src - srcStart; dstLen = dst - dstStart; break; } default: { /* lint. */ return 0; } } *dstLenPtr = dstLen; if ((eof != NULL) && (srcStart + srcLen >= eof)) { /* * EOF character was seen in EOL translated range. Leave current * file position pointing at the EOF character, but don't store the * EOF character in the output string. */ statePtr->flags |= (CHANNEL_EOF | CHANNEL_STICKY_EOF); statePtr->inputEncodingFlags |= TCL_ENCODING_END; statePtr->flags &= ~(INPUT_SAW_CR | INPUT_NEED_NL); return 1; } *srcLenPtr = srcLen; return 0; } /* *---------------------------------------------------------------------- * * Tcl_Ungets -- * * Causes the supplied string to be added to the input queue of * the channel, at either the head or tail of the queue. * * Results: * The number of bytes stored in the channel, or -1 on error. * * Side effects: * Adds input to the input queue of a channel. * *---------------------------------------------------------------------- */ int Tcl_Ungets(chan, str, len, atEnd) Tcl_Channel chan; /* The channel for which to add the input. */ CONST char *str; /* The input itself. */ int len; /* The length of the input. */ int atEnd; /* If non-zero, add at end of queue; otherwise * add at head of queue. */ { Channel *chanPtr; /* The real IO channel. */ ChannelState *statePtr; /* State of actual channel. */ ChannelBuffer *bufPtr; /* Buffer to contain the data. */ int i, flags; chanPtr = (Channel *) chan; statePtr = chanPtr->state; /* * This operation should occur at the top of a channel stack. */ chanPtr = statePtr->topChanPtr; /* * CheckChannelErrors clears too many flag bits in this one case. */ flags = statePtr->flags; if (CheckChannelErrors(statePtr, TCL_READABLE) != 0) { len = -1; goto done; } statePtr->flags = flags; /* * If we have encountered a sticky EOF, just punt without storing. * (sticky EOF is set if we have seen the input eofChar, to prevent * reading beyond the eofChar). Otherwise, clear the EOF flags, and * clear the BLOCKED bit. We want to discover these conditions anew * in each operation. */ if (statePtr->flags & CHANNEL_STICKY_EOF) { goto done; } statePtr->flags &= (~(CHANNEL_BLOCKED | CHANNEL_EOF)); bufPtr = AllocChannelBuffer(len); for (i = 0; i < len; i++) { bufPtr->buf[bufPtr->nextAdded++] = str[i]; } if (statePtr->inQueueHead == (ChannelBuffer *) NULL) { bufPtr->nextPtr = (ChannelBuffer *) NULL; statePtr->inQueueHead = bufPtr; statePtr->inQueueTail = bufPtr; } else if (atEnd) { bufPtr->nextPtr = (ChannelBuffer *) NULL; statePtr->inQueueTail->nextPtr = bufPtr; statePtr->inQueueTail = bufPtr; } else { bufPtr->nextPtr = statePtr->inQueueHead; statePtr->inQueueHead = bufPtr; } done: /* * Update the notifier state so we don't block while there is still * data in the buffers. */ UpdateInterest(chanPtr); return len; } /* *---------------------------------------------------------------------- * * Tcl_Flush -- * * Flushes output data on a channel. * * Results: * A standard Tcl result. * * Side effects: * May flush output queued on this channel. * *---------------------------------------------------------------------- */ int Tcl_Flush(chan) Tcl_Channel chan; /* The Channel to flush. */ { int result; /* Of calling FlushChannel. */ Channel *chanPtr = (Channel *) chan; /* The actual channel. */ ChannelState *statePtr = chanPtr->state; /* State of actual channel. */ /* * This operation should occur at the top of a channel stack. */ chanPtr = statePtr->topChanPtr; if (CheckChannelErrors(statePtr, TCL_WRITABLE) != 0) { return -1; } /* * Force current output buffer to be output also. */ if ((statePtr->curOutPtr != NULL) && (statePtr->curOutPtr->nextAdded > 0)) { statePtr->flags |= BUFFER_READY; } result = FlushChannel(NULL, chanPtr, 0); if (result != 0) { return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * DiscardInputQueued -- * * Discards any input read from the channel but not yet consumed * by Tcl reading commands. * * Results: * None. * * Side effects: * May discard input from the channel. If discardLastBuffer is zero, * leaves one buffer in place for back-filling. * *---------------------------------------------------------------------- */ static void DiscardInputQueued(statePtr, discardSavedBuffers) ChannelState *statePtr; /* Channel on which to discard * the queued input. */ int discardSavedBuffers; /* If non-zero, discard all buffers including * last one. */ { ChannelBuffer *bufPtr, *nxtPtr; /* Loop variables. */ bufPtr = statePtr->inQueueHead; statePtr->inQueueHead = (ChannelBuffer *) NULL; statePtr->inQueueTail = (ChannelBuffer *) NULL; for (; bufPtr != (ChannelBuffer *) NULL; bufPtr = nxtPtr) { nxtPtr = bufPtr->nextPtr; RecycleBuffer(statePtr, bufPtr, discardSavedBuffers); } /* * If discardSavedBuffers is nonzero, must also discard any previously * saved buffer in the saveInBufPtr field. */ if (discardSavedBuffers) { if (statePtr->saveInBufPtr != (ChannelBuffer *) NULL) { ckfree((char *) statePtr->saveInBufPtr); statePtr->saveInBufPtr = (ChannelBuffer *) NULL; } } } /* *--------------------------------------------------------------------------- * * GetInput -- * * Reads input data from a device into a channel buffer. * * Results: * The return value is the Posix error code if an error occurred while * reading from the file, or 0 otherwise. * * Side effects: * Reads from the underlying device. * *--------------------------------------------------------------------------- */ static int GetInput(chanPtr) Channel *chanPtr; /* Channel to read input from. */ { int toRead; /* How much to read? */ int result; /* Of calling driver. */ int nread; /* How much was read from channel? */ ChannelBuffer *bufPtr; /* New buffer to add to input queue. */ ChannelState *statePtr = chanPtr->state; /* state info for channel */ /* * Prevent reading from a dead channel -- a channel that has been closed * but not yet deallocated, which can happen if the exit handler for * channel cleanup has run but the channel is still registered in some * interpreter. */ if (CheckForDeadChannel(NULL, statePtr)) { return EINVAL; } /* * First check for more buffers in the pushback area of the * topmost channel in the stack and use them. They can be the * result of a transformation which went away without reading all * the information placed in the area when it was stacked. * * Two possibilities for the state: No buffers in it, or a single * empty buffer. In the latter case we can recycle it now. */ if (chanPtr->inQueueHead != (ChannelBuffer*) NULL) { if (statePtr->inQueueHead != (ChannelBuffer*) NULL) { RecycleBuffer(statePtr, statePtr->inQueueHead, 0); statePtr->inQueueHead = (ChannelBuffer*) NULL; } statePtr->inQueueHead = chanPtr->inQueueHead; statePtr->inQueueTail = chanPtr->inQueueTail; chanPtr->inQueueHead = (ChannelBuffer*) NULL; chanPtr->inQueueTail = (ChannelBuffer*) NULL; return 0; } /* * Nothing in the pushback area, fall back to the usual handling * (driver, etc.) */ /* * See if we can fill an existing buffer. If we can, read only * as much as will fit in it. Otherwise allocate a new buffer, * add it to the input queue and attempt to fill it to the max. */ bufPtr = statePtr->inQueueTail; if ((bufPtr != NULL) && (bufPtr->nextAdded < bufPtr->bufLength)) { toRead = bufPtr->bufLength - bufPtr->nextAdded; } else { bufPtr = statePtr->saveInBufPtr; statePtr->saveInBufPtr = NULL; /* * Check the actual buffersize against the requested * buffersize. Buffers which are smaller than requested are * squashed. This is done to honor dynamic changes of the * buffersize made by the user. */ if ((bufPtr != NULL) && ((bufPtr->bufLength - BUFFER_PADDING) < statePtr->bufSize)) { ckfree((char *) bufPtr); bufPtr = NULL; } if (bufPtr == NULL) { bufPtr = AllocChannelBuffer(statePtr->bufSize); } bufPtr->nextPtr = (ChannelBuffer *) NULL; /* SF #427196: Use the actual size of the buffer to determine * the number of bytes to read from the channel and not the * size for new buffers. They can be different if the * buffersize was changed between reads. * * Note: This affects performance negatively if the buffersize * was extended but this small buffer is reused for all * subsequent reads. The system never uses buffers with the * requested bigger size in that case. An adjunct patch could * try and delete all unused buffers it encounters and which * are smaller than the formally requested buffersize. */ toRead = bufPtr->bufLength - bufPtr->nextAdded; if (statePtr->inQueueTail == NULL) { statePtr->inQueueHead = bufPtr; } else { statePtr->inQueueTail->nextPtr = bufPtr; } statePtr->inQueueTail = bufPtr; } /* * If EOF is set, we should avoid calling the driver because on some * platforms it is impossible to read from a device after EOF. */ if (statePtr->flags & CHANNEL_EOF) { return 0; } #ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING /* [SF Tcl Bug 943274]. Better emulation of non-blocking channels * for channels without BlockModeProc, by keeping track of true * fileevents generated by the OS == Data waiting and reading if * and only if we are sure to have data. */ if ((statePtr->flags & CHANNEL_NONBLOCKING) && (Tcl_ChannelBlockModeProc(chanPtr->typePtr) == NULL) && !(statePtr->flags & CHANNEL_HAS_MORE_DATA)) { /* Bypass the driver, it would block, as no data is available */ nread = -1; result = EWOULDBLOCK; } else { #endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */ nread = (chanPtr->typePtr->inputProc)(chanPtr->instanceData, bufPtr->buf + bufPtr->nextAdded, toRead, &result); #ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING } #endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */ if (nread > 0) { bufPtr->nextAdded += nread; /* * If we get a short read, signal up that we may be BLOCKED. We * should avoid calling the driver because on some platforms we * will block in the low level reading code even though the * channel is set into nonblocking mode. */ if (nread < toRead) { statePtr->flags |= CHANNEL_BLOCKED; } #ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING if (nread <= toRead) { /* [SF Tcl Bug 943274] We have read the available data, * clear flag */ statePtr->flags &= ~CHANNEL_HAS_MORE_DATA; } #endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */ } else if (nread == 0) { statePtr->flags |= CHANNEL_EOF; statePtr->inputEncodingFlags |= TCL_ENCODING_END; } else if (nread < 0) { if ((result == EWOULDBLOCK) || (result == EAGAIN)) { statePtr->flags |= CHANNEL_BLOCKED; result = EAGAIN; } Tcl_SetErrno(result); return result; } return 0; } /* *---------------------------------------------------------------------- * * Tcl_Seek -- * * Implements seeking on Tcl Channels. This is a public function * so that other C facilities may be implemented on top of it. * * Results: * The new access point or -1 on error. If error, use Tcl_GetErrno() * to retrieve the POSIX error code for the error that occurred. * * Side effects: * May flush output on the channel. May discard queued input. * *---------------------------------------------------------------------- */ Tcl_WideInt Tcl_Seek(chan, offset, mode) Tcl_Channel chan; /* The channel on which to seek. */ Tcl_WideInt offset; /* Offset to seek to. */ int mode; /* Relative to which location to seek? */ { Channel *chanPtr = (Channel *) chan; /* The real IO channel. */ ChannelState *statePtr = chanPtr->state; /* state info for channel */ int inputBuffered, outputBuffered; /* # bytes held in buffers. */ int result; /* Of device driver operations. */ Tcl_WideInt curPos; /* Position on the device. */ int wasAsync; /* Was the channel nonblocking before the * seek operation? If so, must restore to * nonblocking mode after the seek. */ if (CheckChannelErrors(statePtr, TCL_WRITABLE | TCL_READABLE) != 0) { return Tcl_LongAsWide(-1); } /* * Disallow seek on dead channels -- channels that have been closed but * not yet been deallocated. Such channels can be found if the exit * handler for channel cleanup has run but the channel is still * registered in an interpreter. */ if (CheckForDeadChannel(NULL, statePtr)) { return Tcl_LongAsWide(-1); } /* * This operation should occur at the top of a channel stack. */ chanPtr = statePtr->topChanPtr; /* * Disallow seek on channels whose type does not have a seek procedure * defined. This means that the channel does not support seeking. */ if (chanPtr->typePtr->seekProc == (Tcl_DriverSeekProc *) NULL) { Tcl_SetErrno(EINVAL); return Tcl_LongAsWide(-1); } /* * Compute how much input and output is buffered. If both input and * output is buffered, cannot compute the current position. */ inputBuffered = Tcl_InputBuffered(chan); outputBuffered = Tcl_OutputBuffered(chan); if ((inputBuffered != 0) && (outputBuffered != 0)) { Tcl_SetErrno(EFAULT); return Tcl_LongAsWide(-1); } /* * If we are seeking relative to the current position, compute the * corrected offset taking into account the amount of unread input. */ if (mode == SEEK_CUR) { offset -= inputBuffered; } /* * Discard any queued input - this input should not be read after * the seek. */ DiscardInputQueued(statePtr, 0); /* * Reset EOF and BLOCKED flags. We invalidate them by moving the * access point. Also clear CR related flags. */ statePtr->flags &= (~(CHANNEL_EOF | CHANNEL_STICKY_EOF | CHANNEL_BLOCKED | INPUT_SAW_CR)); /* * If the channel is in asynchronous output mode, switch it back * to synchronous mode and cancel any async flush that may be * scheduled. After the flush, the channel will be put back into * asynchronous output mode. */ wasAsync = 0; if (statePtr->flags & CHANNEL_NONBLOCKING) { wasAsync = 1; result = StackSetBlockMode(chanPtr, TCL_MODE_BLOCKING); if (result != 0) { return Tcl_LongAsWide(-1); } statePtr->flags &= (~(CHANNEL_NONBLOCKING)); if (statePtr->flags & BG_FLUSH_SCHEDULED) { statePtr->flags &= (~(BG_FLUSH_SCHEDULED)); } } /* * If the flush fails we cannot recover the original position. In * that case the seek is not attempted because we do not know where * the access position is - instead we return the error. FlushChannel * has already called Tcl_SetErrno() to report the error upwards. * If the flush succeeds we do the seek also. */ if (FlushChannel(NULL, chanPtr, 0) != 0) { curPos = -1; } else { /* * Now seek to the new position in the channel as requested by the * caller. Note that we prefer the wideSeekProc if that is * available and non-NULL... */ if (HaveVersion(chanPtr->typePtr, TCL_CHANNEL_VERSION_3) && chanPtr->typePtr->wideSeekProc != NULL) { curPos = (chanPtr->typePtr->wideSeekProc) (chanPtr->instanceData, offset, mode, &result); } else if (offset < Tcl_LongAsWide(LONG_MIN) || offset > Tcl_LongAsWide(LONG_MAX)) { result = EOVERFLOW; curPos = Tcl_LongAsWide(-1); } else { curPos = Tcl_LongAsWide((chanPtr->typePtr->seekProc) ( chanPtr->instanceData, Tcl_WideAsLong(offset), mode, &result)); } if (curPos == Tcl_LongAsWide(-1)) { Tcl_SetErrno(result); } } /* * Restore to nonblocking mode if that was the previous behavior. * * NOTE: Even if there was an async flush active we do not restore * it now because we already flushed all the queued output, above. */ if (wasAsync) { statePtr->flags |= CHANNEL_NONBLOCKING; result = StackSetBlockMode(chanPtr, TCL_MODE_NONBLOCKING); if (result != 0) { return Tcl_LongAsWide(-1); } } return curPos; } /* *---------------------------------------------------------------------- * * Tcl_Tell -- * * Returns the position of the next character to be read/written on * this channel. * * Results: * A nonnegative integer on success, -1 on failure. If failed, * use Tcl_GetErrno() to retrieve the POSIX error code for the * error that occurred. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_WideInt Tcl_Tell(chan) Tcl_Channel chan; /* The channel to return pos for. */ { Channel *chanPtr = (Channel *) chan; /* The real IO channel. */ ChannelState *statePtr = chanPtr->state; /* state info for channel */ int inputBuffered, outputBuffered; /* # bytes held in buffers. */ int result; /* Of calling device driver. */ Tcl_WideInt curPos; /* Position on device. */ if (CheckChannelErrors(statePtr, TCL_WRITABLE | TCL_READABLE) != 0) { return Tcl_LongAsWide(-1); } /* * Disallow tell on dead channels -- channels that have been closed but * not yet been deallocated. Such channels can be found if the exit * handler for channel cleanup has run but the channel is still * registered in an interpreter. */ if (CheckForDeadChannel(NULL, statePtr)) { return Tcl_LongAsWide(-1); } /* * This operation should occur at the top of a channel stack. */ chanPtr = statePtr->topChanPtr; /* * Disallow tell on channels whose type does not have a seek procedure * defined. This means that the channel does not support seeking. */ if (chanPtr->typePtr->seekProc == (Tcl_DriverSeekProc *) NULL) { Tcl_SetErrno(EINVAL); return Tcl_LongAsWide(-1); } /* * Compute how much input and output is buffered. If both input and * output is buffered, cannot compute the current position. */ inputBuffered = Tcl_InputBuffered(chan); outputBuffered = Tcl_OutputBuffered(chan); if ((inputBuffered != 0) && (outputBuffered != 0)) { Tcl_SetErrno(EFAULT); return Tcl_LongAsWide(-1); } /* * Get the current position in the device and compute the position * where the next character will be read or written. Note that we * prefer the wideSeekProc if that is available and non-NULL... */ if (HaveVersion(chanPtr->typePtr, TCL_CHANNEL_VERSION_3) && chanPtr->typePtr->wideSeekProc != NULL) { curPos = (chanPtr->typePtr->wideSeekProc) (chanPtr->instanceData, Tcl_LongAsWide(0), SEEK_CUR, &result); } else { curPos = Tcl_LongAsWide((chanPtr->typePtr->seekProc) ( chanPtr->instanceData, 0, SEEK_CUR, &result)); } if (curPos == Tcl_LongAsWide(-1)) { Tcl_SetErrno(result); return Tcl_LongAsWide(-1); } if (inputBuffered != 0) { return curPos - inputBuffered; } return curPos + outputBuffered; } /* *--------------------------------------------------------------------------- * * Tcl_SeekOld, Tcl_TellOld -- * * Backward-compatability versions of the seek/tell interface that * do not support 64-bit offsets. This interface is not documented * or expected to be supported indefinitely. * * Results: * As for Tcl_Seek and Tcl_Tell respectively, except truncated to * whatever value will fit in an 'int'. * * Side effects: * As for Tcl_Seek and Tcl_Tell respectively. * *--------------------------------------------------------------------------- */ int Tcl_SeekOld(chan, offset, mode) Tcl_Channel chan; /* The channel on which to seek. */ int offset; /* Offset to seek to. */ int mode; /* Relative to which location to seek? */ { Tcl_WideInt wOffset, wResult; wOffset = Tcl_LongAsWide((long)offset); wResult = Tcl_Seek(chan, wOffset, mode); return (int)Tcl_WideAsLong(wResult); } int Tcl_TellOld(chan) Tcl_Channel chan; /* The channel to return pos for. */ { Tcl_WideInt wResult; wResult = Tcl_Tell(chan); return (int)Tcl_WideAsLong(wResult); } /* *--------------------------------------------------------------------------- * * CheckChannelErrors -- * * See if the channel is in an ready state and can perform the * desired operation. * * Results: * The return value is 0 if the channel is OK, otherwise the * return value is -1 and errno is set to indicate the error. * * Side effects: * May clear the EOF and/or BLOCKED bits if reading from channel. * *--------------------------------------------------------------------------- */ static int CheckChannelErrors(statePtr, flags) ChannelState *statePtr; /* Channel to check. */ int flags; /* Test if channel supports desired operation: * TCL_READABLE, TCL_WRITABLE. Also indicates * Raw read or write for special close * processing*/ { int direction = flags & (TCL_READABLE|TCL_WRITABLE); /* * Check for unreported error. */ if (statePtr->unreportedError != 0) { Tcl_SetErrno(statePtr->unreportedError); statePtr->unreportedError = 0; return -1; } /* * Only the raw read and write operations are allowed during close * in order to drain data from stacked channels. */ if ((statePtr->flags & CHANNEL_CLOSED) && ((flags & CHANNEL_RAW_MODE) == 0)) { Tcl_SetErrno(EACCES); return -1; } /* * Fail if the channel is not opened for desired operation. */ if ((statePtr->flags & direction) == 0) { Tcl_SetErrno(EACCES); return -1; } /* * Fail if the channel is in the middle of a background copy. * * Don't do this tests for raw channels here or else the chaining in the * transformation drivers will fail with 'file busy' error instead of * retrieving and transforming the data to copy. */ if (BUSY_STATE(statePtr,flags) && ((flags & CHANNEL_RAW_MODE) == 0)) { Tcl_SetErrno(EBUSY); return -1; } if (direction == TCL_READABLE) { /* * If we have not encountered a sticky EOF, clear the EOF bit * (sticky EOF is set if we have seen the input eofChar, to prevent * reading beyond the eofChar). Also, always clear the BLOCKED bit. * We want to discover these conditions anew in each operation. */ if ((statePtr->flags & CHANNEL_STICKY_EOF) == 0) { statePtr->flags &= ~CHANNEL_EOF; } statePtr->flags &= ~(CHANNEL_BLOCKED | CHANNEL_NEED_MORE_DATA); } return 0; } /* *---------------------------------------------------------------------- * * Tcl_Eof -- * * Returns 1 if the channel is at EOF, 0 otherwise. * * Results: * 1 or 0, always. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_Eof(chan) Tcl_Channel chan; /* Does this channel have EOF? */ { ChannelState *statePtr = ((Channel *) chan)->state; /* State of real channel structure. */ return ((statePtr->flags & CHANNEL_STICKY_EOF) || ((statePtr->flags & CHANNEL_EOF) && (Tcl_InputBuffered(chan) == 0))) ? 1 : 0; } /* *---------------------------------------------------------------------- * * Tcl_InputBlocked -- * * Returns 1 if input is blocked on this channel, 0 otherwise. * * Results: * 0 or 1, always. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_InputBlocked(chan) Tcl_Channel chan; /* Is this channel blocked? */ { ChannelState *statePtr = ((Channel *) chan)->state; /* State of real channel structure. */ return (statePtr->flags & CHANNEL_BLOCKED) ? 1 : 0; } /* *---------------------------------------------------------------------- * * Tcl_InputBuffered -- * * Returns the number of bytes of input currently buffered in the * common internal buffer of a channel. * * Results: * The number of input bytes buffered, or zero if the channel is not * open for reading. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_InputBuffered(chan) Tcl_Channel chan; /* The channel to query. */ { ChannelState *statePtr = ((Channel *) chan)->state; /* State of real channel structure. */ ChannelBuffer *bufPtr; int bytesBuffered; for (bytesBuffered = 0, bufPtr = statePtr->inQueueHead; bufPtr != (ChannelBuffer *) NULL; bufPtr = bufPtr->nextPtr) { bytesBuffered += (bufPtr->nextAdded - bufPtr->nextRemoved); } /* * Don't forget the bytes in the topmost pushback area. */ for (bufPtr = statePtr->topChanPtr->inQueueHead; bufPtr != (ChannelBuffer *) NULL; bufPtr = bufPtr->nextPtr) { bytesBuffered += (bufPtr->nextAdded - bufPtr->nextRemoved); } return bytesBuffered; } /* *---------------------------------------------------------------------- * * Tcl_OutputBuffered -- * * Returns the number of bytes of output currently buffered in the * common internal buffer of a channel. * * Results: * The number of output bytes buffered, or zero if the channel is not * open for writing. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_OutputBuffered(chan) Tcl_Channel chan; /* The channel to query. */ { ChannelState *statePtr = ((Channel *) chan)->state; /* State of real channel structure. */ ChannelBuffer *bufPtr; int bytesBuffered; for (bytesBuffered = 0, bufPtr = statePtr->outQueueHead; bufPtr != (ChannelBuffer *) NULL; bufPtr = bufPtr->nextPtr) { bytesBuffered += (bufPtr->nextAdded - bufPtr->nextRemoved); } if ((statePtr->curOutPtr != (ChannelBuffer *) NULL) && (statePtr->curOutPtr->nextAdded > statePtr->curOutPtr->nextRemoved)) { statePtr->flags |= BUFFER_READY; bytesBuffered += (statePtr->curOutPtr->nextAdded - statePtr->curOutPtr->nextRemoved); } return bytesBuffered; } /* *---------------------------------------------------------------------- * * Tcl_ChannelBuffered -- * * Returns the number of bytes of input currently buffered in the * internal buffer (push back area) of a channel. * * Results: * The number of input bytes buffered, or zero if the channel is not * open for reading. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_ChannelBuffered(chan) Tcl_Channel chan; /* The channel to query. */ { Channel *chanPtr = (Channel *) chan; /* real channel structure. */ ChannelBuffer *bufPtr; int bytesBuffered; for (bytesBuffered = 0, bufPtr = chanPtr->inQueueHead; bufPtr != (ChannelBuffer *) NULL; bufPtr = bufPtr->nextPtr) { bytesBuffered += (bufPtr->nextAdded - bufPtr->nextRemoved); } return bytesBuffered; } /* *---------------------------------------------------------------------- * * Tcl_SetChannelBufferSize -- * * Sets the size of buffers to allocate to store input or output * in the channel. The size must be between 1 byte and 1 MByte. * * Results: * None. * * Side effects: * Sets the size of buffers subsequently allocated for this channel. * *---------------------------------------------------------------------- */ void Tcl_SetChannelBufferSize(chan, sz) Tcl_Channel chan; /* The channel whose buffer size * to set. */ int sz; /* The size to set. */ { ChannelState *statePtr; /* State of real channel structure. */ /* * Clip the buffer size to force it into the [1,1M] range */ if (sz < 1) { sz = 1; } else if (sz > MAX_CHANNEL_BUFFER_SIZE) { sz = MAX_CHANNEL_BUFFER_SIZE; } statePtr = ((Channel *) chan)->state; statePtr->bufSize = sz; if (statePtr->outputStage != NULL) { ckfree((char *) statePtr->outputStage); statePtr->outputStage = NULL; } if ((statePtr->encoding != NULL) && (statePtr->flags & TCL_WRITABLE)) { statePtr->outputStage = (char *) ckalloc((unsigned) (statePtr->bufSize + 2)); } } /* *---------------------------------------------------------------------- * * Tcl_GetChannelBufferSize -- * * Retrieves the size of buffers to allocate for this channel. * * Results: * The size. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_GetChannelBufferSize(chan) Tcl_Channel chan; /* The channel for which to find the * buffer size. */ { ChannelState *statePtr = ((Channel *) chan)->state; /* State of real channel structure. */ return statePtr->bufSize; } /* *---------------------------------------------------------------------- * * Tcl_BadChannelOption -- * * This procedure generates a "bad option" error message in an * (optional) interpreter. It is used by channel drivers when * a invalid Set/Get option is requested. Its purpose is to concatenate * the generic options list to the specific ones and factorize * the generic options error message string. * * Results: * TCL_ERROR. * * Side effects: * An error message is generated in interp's result object to * indicate that a command was invoked with the a bad option * The message has the form * bad option "blah": should be one of * <...generic options...>+<...specific options...> * "blah" is the optionName argument and "" * is a space separated list of specific option words. * The function takes good care of inserting minus signs before * each option, commas after, and an "or" before the last option. * *---------------------------------------------------------------------- */ int Tcl_BadChannelOption(interp, optionName, optionList) Tcl_Interp *interp; /* Current interpreter. (can be NULL)*/ CONST char *optionName; /* 'bad option' name */ CONST char *optionList; /* Specific options list to append * to the standard generic options. * can be NULL for generic options * only. */ { if (interp) { CONST char *genericopt = "blocking buffering buffersize encoding eofchar translation"; CONST char **argv; int argc, i; Tcl_DString ds; Tcl_DStringInit(&ds); Tcl_DStringAppend(&ds, genericopt, -1); if (optionList && (*optionList)) { Tcl_DStringAppend(&ds, " ", 1); Tcl_DStringAppend(&ds, optionList, -1); } if (Tcl_SplitList(interp, Tcl_DStringValue(&ds), &argc, &argv) != TCL_OK) { panic("malformed option list in channel driver"); } Tcl_ResetResult(interp); Tcl_AppendResult(interp, "bad option \"", optionName, "\": should be one of ", (char *) NULL); argc--; for (i = 0; i < argc; i++) { Tcl_AppendResult(interp, "-", argv[i], ", ", (char *) NULL); } Tcl_AppendResult(interp, "or -", argv[i], (char *) NULL); Tcl_DStringFree(&ds); ckfree((char *) argv); } Tcl_SetErrno(EINVAL); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * Tcl_GetChannelOption -- * * Gets a mode associated with an IO channel. If the optionName arg * is non NULL, retrieves the value of that option. If the optionName * arg is NULL, retrieves a list of alternating option names and * values for the given channel. * * Results: * A standard Tcl result. Also sets the supplied DString to the * string value of the option(s) returned. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_GetChannelOption(interp, chan, optionName, dsPtr) Tcl_Interp *interp; /* For error reporting - can be NULL. */ Tcl_Channel chan; /* Channel on which to get option. */ CONST char *optionName; /* Option to get. */ Tcl_DString *dsPtr; /* Where to store value(s). */ { size_t len; /* Length of optionName string. */ char optionVal[128]; /* Buffer for sprintf. */ Channel *chanPtr = (Channel *) chan; ChannelState *statePtr = chanPtr->state; /* state info for channel */ int flags; /* * Disallow options on dead channels -- channels that have been closed but * not yet been deallocated. Such channels can be found if the exit * handler for channel cleanup has run but the channel is still * registered in an interpreter. */ if (CheckForDeadChannel(interp, statePtr)) { return TCL_ERROR; } /* * This operation should occur at the top of a channel stack. */ chanPtr = statePtr->topChanPtr; /* * If we are in the middle of a background copy, use the saved flags. */ if (statePtr->csPtrR) { flags = statePtr->csPtrR->readFlags; } else if (statePtr->csPtrW) { flags = statePtr->csPtrW->writeFlags; } else { flags = statePtr->flags; } /* * If the optionName is NULL it means that we want a list of all * options and values. */ if (optionName == (char *) NULL) { len = 0; } else { len = strlen(optionName); } if ((len == 0) || ((len > 2) && (optionName[1] == 'b') && (strncmp(optionName, "-blocking", len) == 0))) { if (len == 0) { Tcl_DStringAppendElement(dsPtr, "-blocking"); } Tcl_DStringAppendElement(dsPtr, (flags & CHANNEL_NONBLOCKING) ? "0" : "1"); if (len > 0) { return TCL_OK; } } if ((len == 0) || ((len > 7) && (optionName[1] == 'b') && (strncmp(optionName, "-buffering", len) == 0))) { if (len == 0) { Tcl_DStringAppendElement(dsPtr, "-buffering"); } if (flags & CHANNEL_LINEBUFFERED) { Tcl_DStringAppendElement(dsPtr, "line"); } else if (flags & CHANNEL_UNBUFFERED) { Tcl_DStringAppendElement(dsPtr, "none"); } else { Tcl_DStringAppendElement(dsPtr, "full"); } if (len > 0) { return TCL_OK; } } if ((len == 0) || ((len > 7) && (optionName[1] == 'b') && (strncmp(optionName, "-buffersize", len) == 0))) { if (len == 0) { Tcl_DStringAppendElement(dsPtr, "-buffersize"); } TclFormatInt(optionVal, statePtr->bufSize); Tcl_DStringAppendElement(dsPtr, optionVal); if (len > 0) { return TCL_OK; } } if ((len == 0) || ((len > 2) && (optionName[1] == 'e') && (strncmp(optionName, "-encoding", len) == 0))) { if (len == 0) { Tcl_DStringAppendElement(dsPtr, "-encoding"); } if (statePtr->encoding == NULL) { Tcl_DStringAppendElement(dsPtr, "binary"); } else { Tcl_DStringAppendElement(dsPtr, Tcl_GetEncodingName(statePtr->encoding)); } if (len > 0) { return TCL_OK; } } if ((len == 0) || ((len > 2) && (optionName[1] == 'e') && (strncmp(optionName, "-eofchar", len) == 0))) { if (len == 0) { Tcl_DStringAppendElement(dsPtr, "-eofchar"); } if (((flags & (TCL_READABLE|TCL_WRITABLE)) == (TCL_READABLE|TCL_WRITABLE)) && (len == 0)) { Tcl_DStringStartSublist(dsPtr); } if (flags & TCL_READABLE) { if (statePtr->inEofChar == 0) { Tcl_DStringAppendElement(dsPtr, ""); } else { char buf[4]; sprintf(buf, "%c", statePtr->inEofChar); Tcl_DStringAppendElement(dsPtr, buf); } } if (flags & TCL_WRITABLE) { if (statePtr->outEofChar == 0) { Tcl_DStringAppendElement(dsPtr, ""); } else { char buf[4]; sprintf(buf, "%c", statePtr->outEofChar); Tcl_DStringAppendElement(dsPtr, buf); } } if ( !(flags & (TCL_READABLE|TCL_WRITABLE))) { /* Not readable or writable (server socket) */ Tcl_DStringAppendElement(dsPtr, ""); } if (((flags & (TCL_READABLE|TCL_WRITABLE)) == (TCL_READABLE|TCL_WRITABLE)) && (len == 0)) { Tcl_DStringEndSublist(dsPtr); } if (len > 0) { return TCL_OK; } } if ((len == 0) || ((len > 1) && (optionName[1] == 't') && (strncmp(optionName, "-translation", len) == 0))) { if (len == 0) { Tcl_DStringAppendElement(dsPtr, "-translation"); } if (((flags & (TCL_READABLE|TCL_WRITABLE)) == (TCL_READABLE|TCL_WRITABLE)) && (len == 0)) { Tcl_DStringStartSublist(dsPtr); } if (flags & TCL_READABLE) { if (statePtr->inputTranslation == TCL_TRANSLATE_AUTO) { Tcl_DStringAppendElement(dsPtr, "auto"); } else if (statePtr->inputTranslation == TCL_TRANSLATE_CR) { Tcl_DStringAppendElement(dsPtr, "cr"); } else if (statePtr->inputTranslation == TCL_TRANSLATE_CRLF) { Tcl_DStringAppendElement(dsPtr, "crlf"); } else { Tcl_DStringAppendElement(dsPtr, "lf"); } } if (flags & TCL_WRITABLE) { if (statePtr->outputTranslation == TCL_TRANSLATE_AUTO) { Tcl_DStringAppendElement(dsPtr, "auto"); } else if (statePtr->outputTranslation == TCL_TRANSLATE_CR) { Tcl_DStringAppendElement(dsPtr, "cr"); } else if (statePtr->outputTranslation == TCL_TRANSLATE_CRLF) { Tcl_DStringAppendElement(dsPtr, "crlf"); } else { Tcl_DStringAppendElement(dsPtr, "lf"); } } if ( !(flags & (TCL_READABLE|TCL_WRITABLE))) { /* Not readable or writable (server socket) */ Tcl_DStringAppendElement(dsPtr, "auto"); } if (((flags & (TCL_READABLE|TCL_WRITABLE)) == (TCL_READABLE|TCL_WRITABLE)) && (len == 0)) { Tcl_DStringEndSublist(dsPtr); } if (len > 0) { return TCL_OK; } } if (chanPtr->typePtr->getOptionProc != (Tcl_DriverGetOptionProc *) NULL) { /* * let the driver specific handle additional options * and result code and message. */ return (chanPtr->typePtr->getOptionProc) (chanPtr->instanceData, interp, optionName, dsPtr); } else { /* * no driver specific options case. */ if (len == 0) { return TCL_OK; } return Tcl_BadChannelOption(interp, optionName, NULL); } } /* *--------------------------------------------------------------------------- * * Tcl_SetChannelOption -- * * Sets an option on a channel. * * Results: * A standard Tcl result. On error, sets interp's result object * if interp is not NULL. * * Side effects: * May modify an option on a device. * *--------------------------------------------------------------------------- */ int Tcl_SetChannelOption(interp, chan, optionName, newValue) Tcl_Interp *interp; /* For error reporting - can be NULL. */ Tcl_Channel chan; /* Channel on which to set mode. */ CONST char *optionName; /* Which option to set? */ CONST char *newValue; /* New value for option. */ { Channel *chanPtr = (Channel *) chan; /* The real IO channel. */ ChannelState *statePtr = chanPtr->state; /* state info for channel */ size_t len; /* Length of optionName string. */ int argc; CONST char **argv; /* * If the channel is in the middle of a background copy, fail. */ if (statePtr->csPtrR || statePtr->csPtrW) { if (interp) { Tcl_AppendResult(interp, "unable to set channel options: background copy in progress", (char *) NULL); } return TCL_ERROR; } /* * Disallow options on dead channels -- channels that have been closed but * not yet been deallocated. Such channels can be found if the exit * handler for channel cleanup has run but the channel is still * registered in an interpreter. */ if (CheckForDeadChannel(NULL, statePtr)) { return TCL_ERROR; } /* * This operation should occur at the top of a channel stack. */ chanPtr = statePtr->topChanPtr; len = strlen(optionName); if ((len > 2) && (optionName[1] == 'b') && (strncmp(optionName, "-blocking", len) == 0)) { int newMode; if (Tcl_GetBoolean(interp, newValue, &newMode) == TCL_ERROR) { return TCL_ERROR; } if (newMode) { newMode = TCL_MODE_BLOCKING; } else { newMode = TCL_MODE_NONBLOCKING; } return SetBlockMode(interp, chanPtr, newMode); } else if ((len > 7) && (optionName[1] == 'b') && (strncmp(optionName, "-buffering", len) == 0)) { len = strlen(newValue); if ((newValue[0] == 'f') && (strncmp(newValue, "full", len) == 0)) { statePtr->flags &= (~(CHANNEL_UNBUFFERED|CHANNEL_LINEBUFFERED)); } else if ((newValue[0] == 'l') && (strncmp(newValue, "line", len) == 0)) { statePtr->flags &= (~(CHANNEL_UNBUFFERED)); statePtr->flags |= CHANNEL_LINEBUFFERED; } else if ((newValue[0] == 'n') && (strncmp(newValue, "none", len) == 0)) { statePtr->flags &= (~(CHANNEL_LINEBUFFERED)); statePtr->flags |= CHANNEL_UNBUFFERED; } else { if (interp) { Tcl_AppendResult(interp, "bad value for -buffering: ", "must be one of full, line, or none", (char *) NULL); return TCL_ERROR; } } return TCL_OK; } else if ((len > 7) && (optionName[1] == 'b') && (strncmp(optionName, "-buffersize", len) == 0)) { int newBufferSize; if (Tcl_GetInt(interp, newValue, &newBufferSize) == TCL_ERROR) { return TCL_ERROR; } Tcl_SetChannelBufferSize(chan, newBufferSize); } else if ((len > 2) && (optionName[1] == 'e') && (strncmp(optionName, "-encoding", len) == 0)) { Tcl_Encoding encoding; if ((newValue[0] == '\0') || (strcmp(newValue, "binary") == 0)) { encoding = NULL; } else { encoding = Tcl_GetEncoding(interp, newValue); if (encoding == NULL) { return TCL_ERROR; } } /* * When the channel has an escape sequence driven encoding such as * iso2022, the terminated escape sequence must write to the buffer. */ if ((statePtr->encoding != NULL) && (statePtr->curOutPtr != NULL) && (CheckChannelErrors(statePtr, TCL_WRITABLE) == 0)) { statePtr->outputEncodingFlags |= TCL_ENCODING_END; WriteChars(chanPtr, "", 0); } Tcl_FreeEncoding(statePtr->encoding); statePtr->encoding = encoding; statePtr->inputEncodingState = NULL; statePtr->inputEncodingFlags = TCL_ENCODING_START; statePtr->outputEncodingState = NULL; statePtr->outputEncodingFlags = TCL_ENCODING_START; statePtr->flags &= ~CHANNEL_NEED_MORE_DATA; UpdateInterest(chanPtr); } else if ((len > 2) && (optionName[1] == 'e') && (strncmp(optionName, "-eofchar", len) == 0)) { if (Tcl_SplitList(interp, newValue, &argc, &argv) == TCL_ERROR) { return TCL_ERROR; } if (argc == 0) { statePtr->inEofChar = 0; statePtr->outEofChar = 0; } else if (argc == 1) { if (statePtr->flags & TCL_WRITABLE) { statePtr->outEofChar = (int) argv[0][0]; } if (statePtr->flags & TCL_READABLE) { statePtr->inEofChar = (int) argv[0][0]; } } else if (argc != 2) { if (interp) { Tcl_AppendResult(interp, "bad value for -eofchar: should be a list of zero,", " one, or two elements", (char *) NULL); } ckfree((char *) argv); return TCL_ERROR; } else { if (statePtr->flags & TCL_READABLE) { statePtr->inEofChar = (int) argv[0][0]; } if (statePtr->flags & TCL_WRITABLE) { statePtr->outEofChar = (int) argv[1][0]; } } if (argv != NULL) { ckfree((char *) argv); } /* * [SF Tcl Bug 930851] Reset EOF and BLOCKED flags. Changing * the character which signals eof can transform a current eof * condition into a 'go ahead'. Ditto for blocked. */ statePtr->flags &= (~(CHANNEL_EOF | CHANNEL_STICKY_EOF | CHANNEL_BLOCKED)); return TCL_OK; } else if ((len > 1) && (optionName[1] == 't') && (strncmp(optionName, "-translation", len) == 0)) { CONST char *readMode, *writeMode; if (Tcl_SplitList(interp, newValue, &argc, &argv) == TCL_ERROR) { return TCL_ERROR; } if (argc == 1) { readMode = (statePtr->flags & TCL_READABLE) ? argv[0] : NULL; writeMode = (statePtr->flags & TCL_WRITABLE) ? argv[0] : NULL; } else if (argc == 2) { readMode = (statePtr->flags & TCL_READABLE) ? argv[0] : NULL; writeMode = (statePtr->flags & TCL_WRITABLE) ? argv[1] : NULL; } else { if (interp) { Tcl_AppendResult(interp, "bad value for -translation: must be a one or two", " element list", (char *) NULL); } ckfree((char *) argv); return TCL_ERROR; } if (readMode) { TclEolTranslation translation; if (*readMode == '\0') { translation = statePtr->inputTranslation; } else if (strcmp(readMode, "auto") == 0) { translation = TCL_TRANSLATE_AUTO; } else if (strcmp(readMode, "binary") == 0) { translation = TCL_TRANSLATE_LF; statePtr->inEofChar = 0; Tcl_FreeEncoding(statePtr->encoding); statePtr->encoding = NULL; } else if (strcmp(readMode, "lf") == 0) { translation = TCL_TRANSLATE_LF; } else if (strcmp(readMode, "cr") == 0) { translation = TCL_TRANSLATE_CR; } else if (strcmp(readMode, "crlf") == 0) { translation = TCL_TRANSLATE_CRLF; } else if (strcmp(readMode, "platform") == 0) { translation = TCL_PLATFORM_TRANSLATION; } else { if (interp) { Tcl_AppendResult(interp, "bad value for -translation: ", "must be one of auto, binary, cr, lf, crlf,", " or platform", (char *) NULL); } ckfree((char *) argv); return TCL_ERROR; } /* * Reset the EOL flags since we need to look at any buffered * data to see if the new translation mode allows us to * complete the line. */ if (translation != statePtr->inputTranslation) { statePtr->inputTranslation = translation; statePtr->flags &= ~(INPUT_SAW_CR); statePtr->flags &= ~(CHANNEL_NEED_MORE_DATA); UpdateInterest(chanPtr); } } if (writeMode) { if (*writeMode == '\0') { /* Do nothing. */ } else if (strcmp(writeMode, "auto") == 0) { /* * This is a hack to get TCP sockets to produce output * in CRLF mode if they are being set into AUTO mode. * A better solution for achieving this effect will be * coded later. */ if (strcmp(Tcl_ChannelName(chanPtr->typePtr), "tcp") == 0) { statePtr->outputTranslation = TCL_TRANSLATE_CRLF; } else { statePtr->outputTranslation = TCL_PLATFORM_TRANSLATION; } } else if (strcmp(writeMode, "binary") == 0) { statePtr->outEofChar = 0; statePtr->outputTranslation = TCL_TRANSLATE_LF; Tcl_FreeEncoding(statePtr->encoding); statePtr->encoding = NULL; } else if (strcmp(writeMode, "lf") == 0) { statePtr->outputTranslation = TCL_TRANSLATE_LF; } else if (strcmp(writeMode, "cr") == 0) { statePtr->outputTranslation = TCL_TRANSLATE_CR; } else if (strcmp(writeMode, "crlf") == 0) { statePtr->outputTranslation = TCL_TRANSLATE_CRLF; } else if (strcmp(writeMode, "platform") == 0) { statePtr->outputTranslation = TCL_PLATFORM_TRANSLATION; } else { if (interp) { Tcl_AppendResult(interp, "bad value for -translation: ", "must be one of auto, binary, cr, lf, crlf,", " or platform", (char *) NULL); } ckfree((char *) argv); return TCL_ERROR; } } ckfree((char *) argv); return TCL_OK; } else if (chanPtr->typePtr->setOptionProc != NULL) { return (*chanPtr->typePtr->setOptionProc)(chanPtr->instanceData, interp, optionName, newValue); } else { return Tcl_BadChannelOption(interp, optionName, (char *) NULL); } /* * If bufsize changes, need to get rid of old utility buffer. */ if (statePtr->saveInBufPtr != NULL) { RecycleBuffer(statePtr, statePtr->saveInBufPtr, 1); statePtr->saveInBufPtr = NULL; } if (statePtr->inQueueHead != NULL) { if ((statePtr->inQueueHead->nextPtr == NULL) && (statePtr->inQueueHead->nextAdded == statePtr->inQueueHead->nextRemoved)) { RecycleBuffer(statePtr, statePtr->inQueueHead, 1); statePtr->inQueueHead = NULL; statePtr->inQueueTail = NULL; } } /* * If encoding or bufsize changes, need to update output staging buffer. */ if (statePtr->outputStage != NULL) { ckfree((char *) statePtr->outputStage); statePtr->outputStage = NULL; } if ((statePtr->encoding != NULL) && (statePtr->flags & TCL_WRITABLE)) { statePtr->outputStage = (char *) ckalloc((unsigned) (statePtr->bufSize + 2)); } return TCL_OK; } /* *---------------------------------------------------------------------- * * CleanupChannelHandlers -- * * Removes channel handlers that refer to the supplied interpreter, * so that if the actual channel is not closed now, these handlers * will not run on subsequent events on the channel. This would be * erroneous, because the interpreter no longer has a reference to * this channel. * * Results: * None. * * Side effects: * Removes channel handlers. * *---------------------------------------------------------------------- */ static void CleanupChannelHandlers(interp, chanPtr) Tcl_Interp *interp; Channel *chanPtr; { ChannelState *statePtr = chanPtr->state; /* state info for channel */ EventScriptRecord *sPtr, *prevPtr, *nextPtr; /* * Remove fileevent records on this channel that refer to the * given interpreter. */ for (sPtr = statePtr->scriptRecordPtr, prevPtr = (EventScriptRecord *) NULL; sPtr != (EventScriptRecord *) NULL; sPtr = nextPtr) { nextPtr = sPtr->nextPtr; if (sPtr->interp == interp) { if (prevPtr == (EventScriptRecord *) NULL) { statePtr->scriptRecordPtr = nextPtr; } else { prevPtr->nextPtr = nextPtr; } Tcl_DeleteChannelHandler((Tcl_Channel) chanPtr, TclChannelEventScriptInvoker, (ClientData) sPtr); Tcl_DecrRefCount(sPtr->scriptPtr); ckfree((char *) sPtr); } else { prevPtr = sPtr; } } } /* *---------------------------------------------------------------------- * * Tcl_NotifyChannel -- * * This procedure is called by a channel driver when a driver * detects an event on a channel. This procedure is responsible * for actually handling the event by invoking any channel * handler callbacks. * * Results: * None. * * Side effects: * Whatever the channel handler callback procedure does. * *---------------------------------------------------------------------- */ void Tcl_NotifyChannel(channel, mask) Tcl_Channel channel; /* Channel that detected an event. */ int mask; /* OR'ed combination of TCL_READABLE, * TCL_WRITABLE, or TCL_EXCEPTION: indicates * which events were detected. */ { Channel *chanPtr = (Channel *) channel; ChannelState *statePtr = chanPtr->state; /* state info for channel */ ChannelHandler *chPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); NextChannelHandler nh; Channel* upChanPtr; Tcl_ChannelType* upTypePtr; #ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING /* [SF Tcl Bug 943274] * For a non-blocking channel without blockmodeproc we keep track * of actual input coming from the OS so that we can do a credible * imitation of non-blocking behaviour. */ if ((mask & TCL_READABLE) && (statePtr->flags & CHANNEL_NONBLOCKING) && (Tcl_ChannelBlockModeProc(chanPtr->typePtr) == NULL) && !(statePtr->flags & CHANNEL_TIMER_FEV)) { statePtr->flags |= CHANNEL_HAS_MORE_DATA; } #endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */ /* * In contrast to the other API functions this procedure walks towards * the top of a stack and not down from it. * * The channel calling this procedure is the one who generated the event, * and thus does not take part in handling it. IOW, its HandlerProc is * not called, instead we begin with the channel above it. * * This behaviour also allows the transformation channels to * generate their own events and pass them upward. */ while (mask && (chanPtr->upChanPtr != ((Channel*) NULL))) { Tcl_DriverHandlerProc* upHandlerProc; upChanPtr = chanPtr->upChanPtr; upTypePtr = upChanPtr->typePtr; upHandlerProc = Tcl_ChannelHandlerProc(upTypePtr); if (upHandlerProc != NULL) { mask = (*upHandlerProc) (upChanPtr->instanceData, mask); } /* ELSE: * Ignore transformations which are unable to handle the event * coming from below. Assume that they don't change the mask and * pass it on. */ chanPtr = upChanPtr; } channel = (Tcl_Channel) chanPtr; /* * Here we have either reached the top of the stack or the mask is * empty. We break out of the procedure if it is the latter. */ if (!mask) { return; } /* * We are now above the topmost channel in a stack and have events * left. Now call the channel handlers as usual. * * Preserve the channel struct in case the script closes it. */ Tcl_Preserve((ClientData) channel); Tcl_Preserve((ClientData) statePtr); /* * If we are flushing in the background, be sure to call FlushChannel * for writable events. Note that we have to discard the writable * event so we don't call any write handlers before the flush is * complete. */ if ((statePtr->flags & BG_FLUSH_SCHEDULED) && (mask & TCL_WRITABLE)) { FlushChannel(NULL, chanPtr, 1); mask &= ~TCL_WRITABLE; } /* * Add this invocation to the list of recursive invocations of * ChannelHandlerEventProc. */ nh.nextHandlerPtr = (ChannelHandler *) NULL; nh.nestedHandlerPtr = tsdPtr->nestedHandlerPtr; tsdPtr->nestedHandlerPtr = &nh; for (chPtr = statePtr->chPtr; chPtr != (ChannelHandler *) NULL; ) { /* * If this channel handler is interested in any of the events that * have occurred on the channel, invoke its procedure. */ if ((chPtr->mask & mask) != 0) { nh.nextHandlerPtr = chPtr->nextPtr; (*(chPtr->proc))(chPtr->clientData, mask); chPtr = nh.nextHandlerPtr; } else { chPtr = chPtr->nextPtr; } } /* * Update the notifier interest, since it may have changed after * invoking event handlers. Skip that if the channel was deleted * in the call to the channel handler. */ if (chanPtr->typePtr != NULL) { UpdateInterest(chanPtr); } Tcl_Release((ClientData) statePtr); Tcl_Release((ClientData) channel); tsdPtr->nestedHandlerPtr = nh.nestedHandlerPtr; } /* *---------------------------------------------------------------------- * * UpdateInterest -- * * Arrange for the notifier to call us back at appropriate times * based on the current state of the channel. * * Results: * None. * * Side effects: * May schedule a timer or driver handler. * *---------------------------------------------------------------------- */ static void UpdateInterest(chanPtr) Channel *chanPtr; /* Channel to update. */ { ChannelState *statePtr = chanPtr->state; /* state info for channel */ int mask = statePtr->interestMask; /* * If there are flushed buffers waiting to be written, then * we need to watch for the channel to become writable. */ if (statePtr->flags & BG_FLUSH_SCHEDULED) { mask |= TCL_WRITABLE; } /* * If there is data in the input queue, and we aren't waiting for more * data, then we need to schedule a timer so we don't block in the * notifier. Also, cancel the read interest so we don't get duplicate * events. */ if (mask & TCL_READABLE) { if (!(statePtr->flags & CHANNEL_NEED_MORE_DATA) && (statePtr->inQueueHead != (ChannelBuffer *) NULL) && (statePtr->inQueueHead->nextRemoved < statePtr->inQueueHead->nextAdded)) { mask &= ~TCL_READABLE; /* * Andreas Kupries, April 11, 2003 * * Some operating systems (Solaris 2.6 and higher (but not * Solaris 2.5, go figure)) generate READABLE and * EXCEPTION events when select()'ing [*] on a plain file, * even if EOF was not yet reached. This is a problem in * the following situation: * * - An extension asks to get both READABLE and EXCEPTION * events. * - It reads data into a buffer smaller than the buffer * used by Tcl itself. * - It does not process all events in the event queue, but * only only one, at least in some situations. * * In that case we can get into a situation where * * - Tcl drops READABLE here, because it has data in its own * buffers waiting to be read by the extension. * - A READABLE event is syntesized via timer. * - The OS still reports the EXCEPTION condition on the file. * - And the extension gets the EXCPTION event first, and * handles this as EOF. * * End result ==> Premature end of reading from a file. * * The concrete example is 'Expect', and its [expect] * command (and at the C-level, deep in the bowels of * Expect, 'exp_get_next_event'. See marker 'SunOS' for * commentary in that function too). * * [*] As the Tcl notifier does. See also for marker * 'SunOS' in file 'exp_event.c' of Expect. * * Our solution here is to drop the interest in the * EXCEPTION events too. This compiles on all platforms, * and also passes the testsuite on all of them. */ mask &= ~TCL_EXCEPTION; if (!statePtr->timer) { statePtr->timer = Tcl_CreateTimerHandler(0, ChannelTimerProc, (ClientData) chanPtr); } } } (chanPtr->typePtr->watchProc)(chanPtr->instanceData, mask); } /* *---------------------------------------------------------------------- * * ChannelTimerProc -- * * Timer handler scheduled by UpdateInterest to monitor the * channel buffers until they are empty. * * Results: * None. * * Side effects: * May invoke channel handlers. * *---------------------------------------------------------------------- */ static void ChannelTimerProc(clientData) ClientData clientData; { Channel *chanPtr = (Channel *) clientData; ChannelState *statePtr = chanPtr->state; /* state info for channel */ if (!(statePtr->flags & CHANNEL_NEED_MORE_DATA) && (statePtr->interestMask & TCL_READABLE) && (statePtr->inQueueHead != (ChannelBuffer *) NULL) && (statePtr->inQueueHead->nextRemoved < statePtr->inQueueHead->nextAdded)) { /* * Restart the timer in case a channel handler reenters the * event loop before UpdateInterest gets called by Tcl_NotifyChannel. */ statePtr->timer = Tcl_CreateTimerHandler(0, ChannelTimerProc, (ClientData) chanPtr); #ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING /* Set the TIMER flag to notify the higher levels that the * driver might have no data for us. We do this only if we are * in non-blocking mode and the driver has no BlockModeProc * because only then we really don't know if the driver will * block or not. A similar test is done in "PeekAhead". */ if ((statePtr->flags & CHANNEL_NONBLOCKING) && (Tcl_ChannelBlockModeProc(chanPtr->typePtr) == NULL)) { statePtr->flags |= CHANNEL_TIMER_FEV; } #endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */ Tcl_Preserve((ClientData) statePtr); Tcl_NotifyChannel((Tcl_Channel)chanPtr, TCL_READABLE); #ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING statePtr->flags &= ~CHANNEL_TIMER_FEV; #endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */ Tcl_Release((ClientData) statePtr); } else { statePtr->timer = NULL; UpdateInterest(chanPtr); } } /* *---------------------------------------------------------------------- * * Tcl_CreateChannelHandler -- * * Arrange for a given procedure to be invoked whenever the * channel indicated by the chanPtr arg becomes readable or * writable. * * Results: * None. * * Side effects: * From now on, whenever the I/O channel given by chanPtr becomes * ready in the way indicated by mask, proc will be invoked. * See the manual entry for details on the calling sequence * to proc. If there is already an event handler for chan, proc * and clientData, then the mask will be updated. * *---------------------------------------------------------------------- */ void Tcl_CreateChannelHandler(chan, mask, proc, clientData) Tcl_Channel chan; /* The channel to create the handler for. */ int mask; /* OR'ed combination of TCL_READABLE, * TCL_WRITABLE, and TCL_EXCEPTION: * indicates conditions under which * proc should be called. Use 0 to * disable a registered handler. */ Tcl_ChannelProc *proc; /* Procedure to call for each * selected event. */ ClientData clientData; /* Arbitrary data to pass to proc. */ { ChannelHandler *chPtr; Channel *chanPtr = (Channel *) chan; ChannelState *statePtr = chanPtr->state; /* state info for channel */ /* * Check whether this channel handler is not already registered. If * it is not, create a new record, else reuse existing record (smash * current values). */ for (chPtr = statePtr->chPtr; chPtr != (ChannelHandler *) NULL; chPtr = chPtr->nextPtr) { if ((chPtr->chanPtr == chanPtr) && (chPtr->proc == proc) && (chPtr->clientData == clientData)) { break; } } if (chPtr == (ChannelHandler *) NULL) { chPtr = (ChannelHandler *) ckalloc((unsigned) sizeof(ChannelHandler)); chPtr->mask = 0; chPtr->proc = proc; chPtr->clientData = clientData; chPtr->chanPtr = chanPtr; chPtr->nextPtr = statePtr->chPtr; statePtr->chPtr = chPtr; } /* * The remainder of the initialization below is done regardless of * whether or not this is a new record or a modification of an old * one. */ chPtr->mask = mask; /* * Recompute the interest mask for the channel - this call may actually * be disabling an existing handler. */ statePtr->interestMask = 0; for (chPtr = statePtr->chPtr; chPtr != (ChannelHandler *) NULL; chPtr = chPtr->nextPtr) { statePtr->interestMask |= chPtr->mask; } UpdateInterest(statePtr->topChanPtr); } /* *---------------------------------------------------------------------- * * Tcl_DeleteChannelHandler -- * * Cancel a previously arranged callback arrangement for an IO * channel. * * Results: * None. * * Side effects: * If a callback was previously registered for this chan, proc and * clientData , it is removed and the callback will no longer be called * when the channel becomes ready for IO. * *---------------------------------------------------------------------- */ void Tcl_DeleteChannelHandler(chan, proc, clientData) Tcl_Channel chan; /* The channel for which to remove the * callback. */ Tcl_ChannelProc *proc; /* The procedure in the callback to delete. */ ClientData clientData; /* The client data in the callback * to delete. */ { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); ChannelHandler *chPtr, *prevChPtr; Channel *chanPtr = (Channel *) chan; ChannelState *statePtr = chanPtr->state; /* state info for channel */ NextChannelHandler *nhPtr; /* * Find the entry and the previous one in the list. */ for (prevChPtr = (ChannelHandler *) NULL, chPtr = statePtr->chPtr; chPtr != (ChannelHandler *) NULL; chPtr = chPtr->nextPtr) { if ((chPtr->chanPtr == chanPtr) && (chPtr->clientData == clientData) && (chPtr->proc == proc)) { break; } prevChPtr = chPtr; } /* * If not found, return without doing anything. */ if (chPtr == (ChannelHandler *) NULL) { return; } /* * If ChannelHandlerEventProc is about to process this handler, tell it to * process the next one instead - we are going to delete *this* one. */ for (nhPtr = tsdPtr->nestedHandlerPtr; nhPtr != (NextChannelHandler *) NULL; nhPtr = nhPtr->nestedHandlerPtr) { if (nhPtr->nextHandlerPtr == chPtr) { nhPtr->nextHandlerPtr = chPtr->nextPtr; } } /* * Splice it out of the list of channel handlers. */ if (prevChPtr == (ChannelHandler *) NULL) { statePtr->chPtr = chPtr->nextPtr; } else { prevChPtr->nextPtr = chPtr->nextPtr; } ckfree((char *) chPtr); /* * Recompute the interest list for the channel, so that infinite loops * will not result if Tcl_DeleteChannelHandler is called inside an * event. */ statePtr->interestMask = 0; for (chPtr = statePtr->chPtr; chPtr != (ChannelHandler *) NULL; chPtr = chPtr->nextPtr) { statePtr->interestMask |= chPtr->mask; } UpdateInterest(statePtr->topChanPtr); } /* *---------------------------------------------------------------------- * * DeleteScriptRecord -- * * Delete a script record for this combination of channel, interp * and mask. * * Results: * None. * * Side effects: * Deletes a script record and cancels a channel event handler. * *---------------------------------------------------------------------- */ static void DeleteScriptRecord(interp, chanPtr, mask) Tcl_Interp *interp; /* Interpreter in which script was to be * executed. */ Channel *chanPtr; /* The channel for which to delete the * script record (if any). */ int mask; /* Events in mask must exactly match mask * of script to delete. */ { ChannelState *statePtr = chanPtr->state; /* state info for channel */ EventScriptRecord *esPtr, *prevEsPtr; for (esPtr = statePtr->scriptRecordPtr, prevEsPtr = (EventScriptRecord *) NULL; esPtr != (EventScriptRecord *) NULL; prevEsPtr = esPtr, esPtr = esPtr->nextPtr) { if ((esPtr->interp == interp) && (esPtr->mask == mask)) { if (esPtr == statePtr->scriptRecordPtr) { statePtr->scriptRecordPtr = esPtr->nextPtr; } else { prevEsPtr->nextPtr = esPtr->nextPtr; } Tcl_DeleteChannelHandler((Tcl_Channel) chanPtr, TclChannelEventScriptInvoker, (ClientData) esPtr); Tcl_DecrRefCount(esPtr->scriptPtr); ckfree((char *) esPtr); break; } } } /* *---------------------------------------------------------------------- * * CreateScriptRecord -- * * Creates a record to store a script to be executed when a specific * event fires on a specific channel. * * Results: * None. * * Side effects: * Causes the script to be stored for later execution. * *---------------------------------------------------------------------- */ static void CreateScriptRecord(interp, chanPtr, mask, scriptPtr) Tcl_Interp *interp; /* Interpreter in which to execute * the stored script. */ Channel *chanPtr; /* Channel for which script is to * be stored. */ int mask; /* Set of events for which script * will be invoked. */ Tcl_Obj *scriptPtr; /* Pointer to script object. */ { ChannelState *statePtr = chanPtr->state; /* state info for channel */ EventScriptRecord *esPtr; for (esPtr = statePtr->scriptRecordPtr; esPtr != (EventScriptRecord *) NULL; esPtr = esPtr->nextPtr) { if ((esPtr->interp == interp) && (esPtr->mask == mask)) { Tcl_DecrRefCount(esPtr->scriptPtr); esPtr->scriptPtr = (Tcl_Obj *) NULL; break; } } if (esPtr == (EventScriptRecord *) NULL) { esPtr = (EventScriptRecord *) ckalloc((unsigned) sizeof(EventScriptRecord)); Tcl_CreateChannelHandler((Tcl_Channel) chanPtr, mask, TclChannelEventScriptInvoker, (ClientData) esPtr); esPtr->nextPtr = statePtr->scriptRecordPtr; statePtr->scriptRecordPtr = esPtr; } esPtr->chanPtr = chanPtr; esPtr->interp = interp; esPtr->mask = mask; Tcl_IncrRefCount(scriptPtr); esPtr->scriptPtr = scriptPtr; } /* *---------------------------------------------------------------------- * * TclChannelEventScriptInvoker -- * * Invokes a script scheduled by "fileevent" for when the channel * becomes ready for IO. This function is invoked by the channel * handler which was created by the Tcl "fileevent" command. * * Results: * None. * * Side effects: * Whatever the script does. * *---------------------------------------------------------------------- */ void TclChannelEventScriptInvoker(clientData, mask) ClientData clientData; /* The script+interp record. */ int mask; /* Not used. */ { Tcl_Interp *interp; /* Interpreter in which to eval the script. */ Channel *chanPtr; /* The channel for which this handler is * registered. */ EventScriptRecord *esPtr; /* The event script + interpreter to eval it * in. */ int result; /* Result of call to eval script. */ esPtr = (EventScriptRecord *) clientData; chanPtr = esPtr->chanPtr; mask = esPtr->mask; interp = esPtr->interp; /* * We must preserve the interpreter so we can report errors on it * later. Note that we do not need to preserve the channel because * that is done by Tcl_NotifyChannel before calling channel handlers. */ Tcl_Preserve((ClientData) interp); Tcl_Preserve((ClientData) chanPtr); result = Tcl_EvalObjEx(interp, esPtr->scriptPtr, TCL_EVAL_GLOBAL); /* * On error, cause a background error and remove the channel handler * and the script record. * * NOTE: Must delete channel handler before causing the background error * because the background error may want to reinstall the handler. */ if (result != TCL_OK) { if (chanPtr->typePtr != NULL) { DeleteScriptRecord(interp, chanPtr, mask); } Tcl_BackgroundError(interp); } Tcl_Release((ClientData) chanPtr); Tcl_Release((ClientData) interp); } /* *---------------------------------------------------------------------- * * Tcl_FileEventObjCmd -- * * This procedure implements the "fileevent" Tcl command. See the * user documentation for details on what it does. This command is * based on the Tk command "fileevent" which in turn is based on work * contributed by Mark Diekhans. * * Results: * A standard Tcl result. * * Side effects: * May create a channel handler for the specified channel. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_FileEventObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter in which the channel * for which to create the handler * is found. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Channel *chanPtr; /* The channel to create * the handler for. */ ChannelState *statePtr; /* state info for channel */ Tcl_Channel chan; /* The opaque type for the channel. */ char *chanName; int modeIndex; /* Index of mode argument. */ int mask; static CONST char *modeOptions[] = {"readable", "writable", NULL}; static CONST int maskArray[] = {TCL_READABLE, TCL_WRITABLE}; if ((objc != 3) && (objc != 4)) { Tcl_WrongNumArgs(interp, 1, objv, "channelId event ?script?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[2], modeOptions, "event name", 0, &modeIndex) != TCL_OK) { return TCL_ERROR; } mask = maskArray[modeIndex]; chanName = Tcl_GetString(objv[1]); chan = Tcl_GetChannel(interp, chanName, NULL); if (chan == (Tcl_Channel) NULL) { return TCL_ERROR; } chanPtr = (Channel *) chan; statePtr = chanPtr->state; if ((statePtr->flags & mask) == 0) { Tcl_AppendResult(interp, "channel is not ", (mask == TCL_READABLE) ? "readable" : "writable", (char *) NULL); return TCL_ERROR; } /* * If we are supposed to return the script, do so. */ if (objc == 3) { EventScriptRecord *esPtr; for (esPtr = statePtr->scriptRecordPtr; esPtr != (EventScriptRecord *) NULL; esPtr = esPtr->nextPtr) { if ((esPtr->interp == interp) && (esPtr->mask == mask)) { Tcl_SetObjResult(interp, esPtr->scriptPtr); break; } } return TCL_OK; } /* * If we are supposed to delete a stored script, do so. */ if (*(Tcl_GetString(objv[3])) == '\0') { DeleteScriptRecord(interp, chanPtr, mask); return TCL_OK; } /* * Make the script record that will link between the event and the * script to invoke. This also creates a channel event handler which * will evaluate the script in the supplied interpreter. */ CreateScriptRecord(interp, chanPtr, mask, objv[3]); return TCL_OK; } /* *---------------------------------------------------------------------- * * TclCopyChannel -- * * This routine copies data from one channel to another, either * synchronously or asynchronously. If a command script is * supplied, the operation runs in the background. The script * is invoked when the copy completes. Otherwise the function * waits until the copy is completed before returning. * * Results: * A standard Tcl result. * * Side effects: * May schedule a background copy operation that causes both * channels to be marked busy. * *---------------------------------------------------------------------- */ int TclCopyChannel(interp, inChan, outChan, toRead, cmdPtr) Tcl_Interp *interp; /* Current interpreter. */ Tcl_Channel inChan; /* Channel to read from. */ Tcl_Channel outChan; /* Channel to write to. */ int toRead; /* Amount of data to copy, or -1 for all. */ Tcl_Obj *cmdPtr; /* Pointer to script to execute or NULL. */ { Channel *inPtr = (Channel *) inChan; Channel *outPtr = (Channel *) outChan; ChannelState *inStatePtr, *outStatePtr; int readFlags, writeFlags; CopyState *csPtr; int nonBlocking = (cmdPtr) ? CHANNEL_NONBLOCKING : 0; inStatePtr = inPtr->state; outStatePtr = outPtr->state; if (BUSY_STATE(inStatePtr,TCL_READABLE)) { if (interp) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "channel \"", Tcl_GetChannelName(inChan), "\" is busy", NULL); } return TCL_ERROR; } if (BUSY_STATE(outStatePtr,TCL_WRITABLE)) { if (interp) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "channel \"", Tcl_GetChannelName(outChan), "\" is busy", NULL); } return TCL_ERROR; } readFlags = inStatePtr->flags; writeFlags = outStatePtr->flags; /* * Set up the blocking mode appropriately. Background copies need * non-blocking channels. Foreground copies need blocking channels. * If there is an error, restore the old blocking mode. */ if (nonBlocking != (readFlags & CHANNEL_NONBLOCKING)) { if (SetBlockMode(interp, inPtr, nonBlocking ? TCL_MODE_NONBLOCKING : TCL_MODE_BLOCKING) != TCL_OK) { return TCL_ERROR; } } if (inPtr != outPtr) { if (nonBlocking != (writeFlags & CHANNEL_NONBLOCKING)) { if (SetBlockMode(NULL, outPtr, nonBlocking ? TCL_MODE_NONBLOCKING : TCL_MODE_BLOCKING) != TCL_OK) { if (nonBlocking != (readFlags & CHANNEL_NONBLOCKING)) { SetBlockMode(NULL, inPtr, (readFlags & CHANNEL_NONBLOCKING) ? TCL_MODE_NONBLOCKING : TCL_MODE_BLOCKING); return TCL_ERROR; } } } } /* * Make sure the output side is unbuffered. */ outStatePtr->flags = (outStatePtr->flags & ~(CHANNEL_LINEBUFFERED)) | CHANNEL_UNBUFFERED; /* * Allocate a new CopyState to maintain info about the current copy in * progress. This structure will be deallocated when the copy is * completed. */ csPtr = (CopyState*) ckalloc(sizeof(CopyState) + inStatePtr->bufSize); csPtr->bufSize = inStatePtr->bufSize; csPtr->readPtr = inPtr; csPtr->writePtr = outPtr; csPtr->readFlags = readFlags; csPtr->writeFlags = writeFlags; csPtr->toRead = toRead; csPtr->total = 0; csPtr->interp = interp; if (cmdPtr) { Tcl_IncrRefCount(cmdPtr); } csPtr->cmdPtr = cmdPtr; inStatePtr->csPtrR = csPtr; outStatePtr->csPtrW = csPtr; /* * Start copying data between the channels. */ return CopyData(csPtr, 0); } /* *---------------------------------------------------------------------- * * CopyData -- * * This function implements the lowest level of the copying * mechanism for TclCopyChannel. * * Results: * Returns TCL_OK on success, else TCL_ERROR. * * Side effects: * Moves data between channels, may create channel handlers. * *---------------------------------------------------------------------- */ static int CopyData(csPtr, mask) CopyState *csPtr; /* State of copy operation. */ int mask; /* Current channel event flags. */ { Tcl_Interp *interp; Tcl_Obj *cmdPtr, *errObj = NULL, *bufObj = NULL; Tcl_Channel inChan, outChan; ChannelState *inStatePtr, *outStatePtr; int result = TCL_OK, size, total, sizeb; char* buffer; int inBinary, outBinary, sameEncoding; /* Encoding control */ int underflow; /* input underflow */ inChan = (Tcl_Channel) csPtr->readPtr; outChan = (Tcl_Channel) csPtr->writePtr; inStatePtr = csPtr->readPtr->state; outStatePtr = csPtr->writePtr->state; interp = csPtr->interp; cmdPtr = csPtr->cmdPtr; /* * Copy the data the slow way, using the translation mechanism. * * Note: We have make sure that we use the topmost channel in a stack * for the copying. The caller uses Tcl_GetChannel to access it, and * thus gets the bottom of the stack. */ inBinary = (inStatePtr->encoding == NULL); outBinary = (outStatePtr->encoding == NULL); sameEncoding = (inStatePtr->encoding == outStatePtr->encoding); if (!(inBinary || sameEncoding)) { bufObj = Tcl_NewObj (); Tcl_IncrRefCount (bufObj); } while (csPtr->toRead != 0) { /* * Check for unreported background errors. */ if (inStatePtr->unreportedError != 0) { Tcl_SetErrno(inStatePtr->unreportedError); inStatePtr->unreportedError = 0; goto readError; } if (outStatePtr->unreportedError != 0) { Tcl_SetErrno(outStatePtr->unreportedError); outStatePtr->unreportedError = 0; goto writeError; } if (cmdPtr && (mask == 0)) { /* * In async mode, we skip reading synchronously and fake an * underflow instead to prime the readable fileevent. */ size = 0; underflow = 1; } else { /* * Read up to bufSize bytes. */ if ((csPtr->toRead == -1) || (csPtr->toRead > csPtr->bufSize)) { sizeb = csPtr->bufSize; } else { sizeb = csPtr->toRead; } if (inBinary || sameEncoding) { size = DoRead(inStatePtr->topChanPtr, csPtr->buffer, sizeb); } else { size = DoReadChars(inStatePtr->topChanPtr, bufObj, sizeb, 0 /* No append */); } underflow = (size >= 0) && (size < sizeb); /* input underflow */ } if (size < 0) { readError: errObj = Tcl_NewObj(); Tcl_AppendStringsToObj(errObj, "error reading \"", Tcl_GetChannelName(inChan), "\": ", Tcl_PosixError(interp), (char *) NULL); break; } else if (underflow) { /* * We had an underflow on the read side. If we are at * EOF, and not in the synchronous part of an asynchronous * fcopy, then the copying is done, otherwise set up a * channel handler to detect when the channel becomes * readable again. */ if ((size == 0) && Tcl_Eof(inChan) && !(cmdPtr && (mask == 0))) { break; } if (((!Tcl_Eof(inChan)) || (cmdPtr && (mask == 0))) && !(mask & TCL_READABLE)) { if (mask & TCL_WRITABLE) { Tcl_DeleteChannelHandler(outChan, CopyEventProc, (ClientData) csPtr); } Tcl_CreateChannelHandler(inChan, TCL_READABLE, CopyEventProc, (ClientData) csPtr); } if (size == 0) { if (bufObj != (Tcl_Obj*) NULL) { Tcl_DecrRefCount (bufObj); bufObj = (Tcl_Obj*) NULL; } return TCL_OK; } } /* * Now write the buffer out. */ if (inBinary || sameEncoding) { buffer = csPtr->buffer; sizeb = size; } else { buffer = Tcl_GetStringFromObj (bufObj, &sizeb); } if (outBinary || sameEncoding) { sizeb = DoWrite(outStatePtr->topChanPtr, buffer, sizeb); } else { sizeb = DoWriteChars(outStatePtr->topChanPtr, buffer, sizeb); } /* * [Bug 2895565]. At this point 'size' still contains the number of * bytes or characters which have been read. We keep this to later to * update the totals and toRead information, see marker (UP) below. We * must not overwrite it with 'sizeb', which is the number of written * bytes or characters, and both EOL translation and encoding * conversion may have changed this number unpredictably in relation * to 'size' (It can be smaller or larger, in the latter case able to * drive toRead below -1, causing infinite looping). Completely * unsuitable for updating totals and toRead. */ if (sizeb < 0) { writeError: errObj = Tcl_NewObj(); Tcl_AppendStringsToObj(errObj, "error writing \"", Tcl_GetChannelName(outChan), "\": ", Tcl_PosixError(interp), (char *) NULL); break; } /* * Update the current byte count. Do it now so the count is * valid before a return or break takes us out of the loop. * The invariant at the top of the loop should be that * csPtr->toRead holds the number of bytes left to copy. */ if (csPtr->toRead != -1) { csPtr->toRead -= size; } csPtr->total += size; /* * Break loop if EOF && (size>0) */ if (Tcl_Eof(inChan)) { break; } /* * Check to see if the write is happening in the background. If so, * stop copying and wait for the channel to become writable again. * After input underflow we already installed a readable handler * therefore we don't need a writable handler. */ if ( ! underflow && (outStatePtr->flags & BG_FLUSH_SCHEDULED) ) { if (!(mask & TCL_WRITABLE)) { if (mask & TCL_READABLE) { Tcl_DeleteChannelHandler(inChan, CopyEventProc, (ClientData) csPtr); } Tcl_CreateChannelHandler(outChan, TCL_WRITABLE, CopyEventProc, (ClientData) csPtr); } if (bufObj != (Tcl_Obj*) NULL) { Tcl_DecrRefCount (bufObj); bufObj = (Tcl_Obj*) NULL; } return TCL_OK; } /* * For background copies, we only do one buffer per invocation so * we don't starve the rest of the system. */ if (cmdPtr && (csPtr->toRead != 0)) { /* * The first time we enter this code, there won't be a * channel handler established yet, so do it here. */ if (mask == 0) { Tcl_CreateChannelHandler(outChan, TCL_WRITABLE, CopyEventProc, (ClientData) csPtr); } if (bufObj != (Tcl_Obj*) NULL) { Tcl_DecrRefCount (bufObj); bufObj = (Tcl_Obj*) NULL; } return TCL_OK; } } /* while */ if (bufObj != (Tcl_Obj*) NULL) { Tcl_DecrRefCount (bufObj); bufObj = (Tcl_Obj*) NULL; } /* * Make the callback or return the number of bytes transferred. * The local total is used because StopCopy frees csPtr. */ total = csPtr->total; if (cmdPtr && interp) { /* * Get a private copy of the command so we can mutate it * by adding arguments. Note that StopCopy frees our saved * reference to the original command obj. */ cmdPtr = Tcl_DuplicateObj(cmdPtr); Tcl_IncrRefCount(cmdPtr); StopCopy(csPtr); Tcl_Preserve((ClientData) interp); Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewIntObj(total)); if (errObj) { Tcl_ListObjAppendElement(interp, cmdPtr, errObj); } if (Tcl_EvalObjEx(interp, cmdPtr, TCL_EVAL_GLOBAL) != TCL_OK) { Tcl_BackgroundError(interp); result = TCL_ERROR; } Tcl_DecrRefCount(cmdPtr); Tcl_Release((ClientData) interp); } else { StopCopy(csPtr); if (interp) { if (errObj) { Tcl_SetObjResult(interp, errObj); result = TCL_ERROR; } else { Tcl_ResetResult(interp); Tcl_SetIntObj(Tcl_GetObjResult(interp), total); } } } return result; } /* *---------------------------------------------------------------------- * * DoRead -- * * Reads a given number of bytes from a channel. * * No encoding conversions are applied to the bytes being read. * * Results: * The number of characters read, or -1 on error. Use Tcl_GetErrno() * to retrieve the error code for the error that occurred. * * Side effects: * May cause input to be buffered. * *---------------------------------------------------------------------- */ static int DoRead(chanPtr, bufPtr, toRead) Channel *chanPtr; /* The channel from which to read. */ char *bufPtr; /* Where to store input read. */ int toRead; /* Maximum number of bytes to read. */ { ChannelState *statePtr = chanPtr->state; /* state info for channel */ int copied; /* How many characters were copied into * the result string? */ int copiedNow; /* How many characters were copied from * the current input buffer? */ int result; /* Of calling GetInput. */ /* * If we have not encountered a sticky EOF, clear the EOF bit. Either * way clear the BLOCKED bit. We want to discover these anew during * each operation. */ if (!(statePtr->flags & CHANNEL_STICKY_EOF)) { statePtr->flags &= ~CHANNEL_EOF; } statePtr->flags &= ~(CHANNEL_BLOCKED | CHANNEL_NEED_MORE_DATA); for (copied = 0; copied < toRead; copied += copiedNow) { copiedNow = CopyAndTranslateBuffer(statePtr, bufPtr + copied, toRead - copied); if (copiedNow == 0) { if (statePtr->flags & CHANNEL_EOF) { goto done; } if (statePtr->flags & CHANNEL_BLOCKED) { if (statePtr->flags & CHANNEL_NONBLOCKING) { goto done; } statePtr->flags &= (~(CHANNEL_BLOCKED)); } result = GetInput(chanPtr); if (result != 0) { if (result != EAGAIN) { copied = -1; } goto done; } } } statePtr->flags &= (~(CHANNEL_BLOCKED)); done: /* * Update the notifier state so we don't block while there is still * data in the buffers. */ UpdateInterest(chanPtr); return copied; } /* *---------------------------------------------------------------------- * * CopyAndTranslateBuffer -- * * Copy at most one buffer of input to the result space, doing * eol translations according to mode in effect currently. * * Results: * Number of bytes stored in the result buffer (as opposed to the * number of bytes read from the channel). May return * zero if no input is available to be translated. * * Side effects: * Consumes buffered input. May deallocate one buffer. * *---------------------------------------------------------------------- */ static int CopyAndTranslateBuffer(statePtr, result, space) ChannelState *statePtr; /* Channel state from which to read input. */ char *result; /* Where to store the copied input. */ int space; /* How many bytes are available in result * to store the copied input? */ { ChannelBuffer *bufPtr; /* The buffer from which to copy bytes. */ int bytesInBuffer; /* How many bytes are available to be * copied in the current input buffer? */ int copied; /* How many characters were already copied * into the destination space? */ int i; /* Iterates over the copied input looking * for the input eofChar. */ /* * If there is no input at all, return zero. The invariant is that either * there is no buffer in the queue, or if the first buffer is empty, it * is also the last buffer (and thus there is no input in the queue). * Note also that if the buffer is empty, we leave it in the queue. */ if (statePtr->inQueueHead == (ChannelBuffer *) NULL) { return 0; } bufPtr = statePtr->inQueueHead; bytesInBuffer = bufPtr->nextAdded - bufPtr->nextRemoved; copied = 0; switch (statePtr->inputTranslation) { case TCL_TRANSLATE_LF: { if (bytesInBuffer == 0) { return 0; } /* * Copy the current chunk into the result buffer. */ if (bytesInBuffer < space) { space = bytesInBuffer; } memcpy((VOID *) result, (VOID *) (bufPtr->buf + bufPtr->nextRemoved), (size_t) space); bufPtr->nextRemoved += space; copied = space; break; } case TCL_TRANSLATE_CR: { char *end; if (bytesInBuffer == 0) { return 0; } /* * Copy the current chunk into the result buffer, then * replace all \r with \n. */ if (bytesInBuffer < space) { space = bytesInBuffer; } memcpy((VOID *) result, (VOID *) (bufPtr->buf + bufPtr->nextRemoved), (size_t) space); bufPtr->nextRemoved += space; copied = space; for (end = result + copied; result < end; result++) { if (*result == '\r') { *result = '\n'; } } break; } case TCL_TRANSLATE_CRLF: { char *src, *end, *dst; int curByte; /* * If there is a held-back "\r" at EOF, produce it now. */ if (bytesInBuffer == 0) { if ((statePtr->flags & (INPUT_SAW_CR | CHANNEL_EOF)) == (INPUT_SAW_CR | CHANNEL_EOF)) { result[0] = '\r'; statePtr->flags &= ~INPUT_SAW_CR; return 1; } return 0; } /* * Copy the current chunk and replace "\r\n" with "\n" * (but not standalone "\r"!). */ if (bytesInBuffer < space) { space = bytesInBuffer; } memcpy((VOID *) result, (VOID *) (bufPtr->buf + bufPtr->nextRemoved), (size_t) space); bufPtr->nextRemoved += space; copied = space; end = result + copied; dst = result; for (src = result; src < end; src++) { curByte = *src; if (curByte == '\n') { statePtr->flags &= ~INPUT_SAW_CR; } else if (statePtr->flags & INPUT_SAW_CR) { statePtr->flags &= ~INPUT_SAW_CR; *dst = '\r'; dst++; } if (curByte == '\r') { statePtr->flags |= INPUT_SAW_CR; } else { *dst = (char) curByte; dst++; } } copied = dst - result; break; } case TCL_TRANSLATE_AUTO: { char *src, *end, *dst; int curByte; if (bytesInBuffer == 0) { return 0; } /* * Loop over the current buffer, converting "\r" and "\r\n" * to "\n". */ if (bytesInBuffer < space) { space = bytesInBuffer; } memcpy((VOID *) result, (VOID *) (bufPtr->buf + bufPtr->nextRemoved), (size_t) space); bufPtr->nextRemoved += space; copied = space; end = result + copied; dst = result; for (src = result; src < end; src++) { curByte = *src; if (curByte == '\r') { statePtr->flags |= INPUT_SAW_CR; *dst = '\n'; dst++; } else { if ((curByte != '\n') || !(statePtr->flags & INPUT_SAW_CR)) { *dst = (char) curByte; dst++; } statePtr->flags &= ~INPUT_SAW_CR; } } copied = dst - result; break; } default: { panic("unknown eol translation mode"); } } /* * If an in-stream EOF character is set for this channel, check that * the input we copied so far does not contain the EOF char. If it does, * copy only up to and excluding that character. */ if (statePtr->inEofChar != 0) { for (i = 0; i < copied; i++) { if (result[i] == (char) statePtr->inEofChar) { /* * Set sticky EOF so that no further input is presented * to the caller. */ statePtr->flags |= (CHANNEL_EOF | CHANNEL_STICKY_EOF); statePtr->inputEncodingFlags |= TCL_ENCODING_END; copied = i; break; } } } /* * If the current buffer is empty recycle it. */ if (bufPtr->nextRemoved == bufPtr->nextAdded) { statePtr->inQueueHead = bufPtr->nextPtr; if (statePtr->inQueueHead == (ChannelBuffer *) NULL) { statePtr->inQueueTail = (ChannelBuffer *) NULL; } RecycleBuffer(statePtr, bufPtr, 0); } /* * Return the number of characters copied into the result buffer. * This may be different from the number of bytes consumed, because * of EOL translations. */ return copied; } /* *---------------------------------------------------------------------- * * CopyBuffer -- * * Copy at most one buffer of input to the result space. * * Results: * Number of bytes stored in the result buffer. May return * zero if no input is available. * * Side effects: * Consumes buffered input. May deallocate one buffer. * *---------------------------------------------------------------------- */ static int CopyBuffer(chanPtr, result, space) Channel *chanPtr; /* Channel from which to read input. */ char *result; /* Where to store the copied input. */ int space; /* How many bytes are available in result * to store the copied input? */ { ChannelBuffer *bufPtr; /* The buffer from which to copy bytes. */ int bytesInBuffer; /* How many bytes are available to be * copied in the current input buffer? */ int copied; /* How many characters were already copied * into the destination space? */ /* * If there is no input at all, return zero. The invariant is that * either there is no buffer in the queue, or if the first buffer * is empty, it is also the last buffer (and thus there is no * input in the queue). Note also that if the buffer is empty, we * don't leave it in the queue, but recycle it. */ if (chanPtr->inQueueHead == (ChannelBuffer *) NULL) { return 0; } bufPtr = chanPtr->inQueueHead; bytesInBuffer = bufPtr->nextAdded - bufPtr->nextRemoved; copied = 0; if (bytesInBuffer == 0) { RecycleBuffer(chanPtr->state, bufPtr, 0); chanPtr->inQueueHead = (ChannelBuffer*) NULL; chanPtr->inQueueTail = (ChannelBuffer*) NULL; return 0; } /* * Copy the current chunk into the result buffer. */ if (bytesInBuffer < space) { space = bytesInBuffer; } memcpy((VOID *) result, (VOID *) (bufPtr->buf + bufPtr->nextRemoved), (size_t) space); bufPtr->nextRemoved += space; copied = space; /* * We don't care about in-stream EOF characters here as the data * read here may still flow through one or more transformations, * i.e. is not in its final state yet. */ /* * If the current buffer is empty recycle it. */ if (bufPtr->nextRemoved == bufPtr->nextAdded) { chanPtr->inQueueHead = bufPtr->nextPtr; if (chanPtr->inQueueHead == (ChannelBuffer *) NULL) { chanPtr->inQueueTail = (ChannelBuffer *) NULL; } RecycleBuffer(chanPtr->state, bufPtr, 0); } /* * Return the number of characters copied into the result buffer. */ return copied; } /* *---------------------------------------------------------------------- * * DoWrite -- * * Puts a sequence of characters into an output buffer, may queue the * buffer for output if it gets full, and also remembers whether the * current buffer is ready e.g. if it contains a newline and we are in * line buffering mode. * * Results: * The number of bytes written or -1 in case of error. If -1, * Tcl_GetErrno will return the error code. * * Side effects: * May buffer up output and may cause output to be produced on the * channel. * *---------------------------------------------------------------------- */ static int DoWrite(chanPtr, src, srcLen) Channel *chanPtr; /* The channel to buffer output for. */ CONST char *src; /* Data to write. */ int srcLen; /* Number of bytes to write. */ { ChannelState *statePtr = chanPtr->state; /* state info for channel */ ChannelBuffer *outBufPtr; /* Current output buffer. */ int foundNewline; /* Did we find a newline in output? */ char *dPtr; CONST char *sPtr; /* Search variables for newline. */ int crsent; /* In CRLF eol translation mode, * remember the fact that a CR was * output to the channel without * its following NL. */ int i; /* Loop index for newline search. */ int destCopied; /* How many bytes were used in this * destination buffer to hold the * output? */ int totalDestCopied; /* How many bytes total were * copied to the channel buffer? */ int srcCopied; /* How many bytes were copied from * the source string? */ char *destPtr; /* Where in line to copy to? */ /* * If we are in network (or windows) translation mode, record the fact * that we have not yet sent a CR to the channel. */ crsent = 0; /* * Loop filling buffers and flushing them until all output has been * consumed. */ srcCopied = 0; totalDestCopied = 0; while (srcLen > 0) { /* * Make sure there is a current output buffer to accept output. */ if (statePtr->curOutPtr == (ChannelBuffer *) NULL) { statePtr->curOutPtr = AllocChannelBuffer(statePtr->bufSize); } outBufPtr = statePtr->curOutPtr; destCopied = outBufPtr->bufLength - outBufPtr->nextAdded; if (destCopied > srcLen) { destCopied = srcLen; } destPtr = outBufPtr->buf + outBufPtr->nextAdded; switch (statePtr->outputTranslation) { case TCL_TRANSLATE_LF: srcCopied = destCopied; memcpy((VOID *) destPtr, (VOID *) src, (size_t) destCopied); break; case TCL_TRANSLATE_CR: srcCopied = destCopied; memcpy((VOID *) destPtr, (VOID *) src, (size_t) destCopied); for (dPtr = destPtr; dPtr < destPtr + destCopied; dPtr++) { if (*dPtr == '\n') { *dPtr = '\r'; } } break; case TCL_TRANSLATE_CRLF: for (srcCopied = 0, dPtr = destPtr, sPtr = src; dPtr < destPtr + destCopied; dPtr++, sPtr++, srcCopied++) { if (*sPtr == '\n') { if (crsent) { *dPtr = '\n'; crsent = 0; } else { *dPtr = '\r'; crsent = 1; sPtr--, srcCopied--; } } else { *dPtr = *sPtr; } } break; case TCL_TRANSLATE_AUTO: panic("Tcl_Write: AUTO output translation mode not supported"); default: panic("Tcl_Write: unknown output translation mode"); } /* * The current buffer is ready for output if it is full, or if it * contains a newline and this channel is line-buffered, or if it * contains any output and this channel is unbuffered. */ outBufPtr->nextAdded += destCopied; if (!(statePtr->flags & BUFFER_READY)) { if (outBufPtr->nextAdded == outBufPtr->bufLength) { statePtr->flags |= BUFFER_READY; } else if (statePtr->flags & CHANNEL_LINEBUFFERED) { for (sPtr = src, i = 0, foundNewline = 0; (i < srcCopied) && (!foundNewline); i++, sPtr++) { if (*sPtr == '\n') { foundNewline = 1; break; } } if (foundNewline) { statePtr->flags |= BUFFER_READY; } } else if (statePtr->flags & CHANNEL_UNBUFFERED) { statePtr->flags |= BUFFER_READY; } } totalDestCopied += srcCopied; src += srcCopied; srcLen -= srcCopied; if (statePtr->flags & BUFFER_READY) { if (FlushChannel(NULL, chanPtr, 0) != 0) { return -1; } } } /* Closes "while" */ return totalDestCopied; } /* *---------------------------------------------------------------------- * * CopyEventProc -- * * This routine is invoked as a channel event handler for * the background copy operation. It is just a trivial wrapper * around the CopyData routine. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void CopyEventProc(clientData, mask) ClientData clientData; int mask; { (void) CopyData((CopyState *)clientData, mask); } /* *---------------------------------------------------------------------- * * StopCopy -- * * This routine halts a copy that is in progress. * * Results: * None. * * Side effects: * Removes any pending channel handlers and restores the blocking * and buffering modes of the channels. The CopyState is freed. * *---------------------------------------------------------------------- */ static void StopCopy(csPtr) CopyState *csPtr; /* State for bg copy to stop . */ { ChannelState *inStatePtr, *outStatePtr; int nonBlocking; if (!csPtr) { return; } inStatePtr = csPtr->readPtr->state; outStatePtr = csPtr->writePtr->state; /* * Restore the old blocking mode and output buffering mode. */ nonBlocking = (csPtr->readFlags & CHANNEL_NONBLOCKING); if (nonBlocking != (inStatePtr->flags & CHANNEL_NONBLOCKING)) { SetBlockMode(NULL, csPtr->readPtr, nonBlocking ? TCL_MODE_NONBLOCKING : TCL_MODE_BLOCKING); } if (csPtr->readPtr != csPtr->writePtr) { nonBlocking = (csPtr->writeFlags & CHANNEL_NONBLOCKING); if (nonBlocking != (outStatePtr->flags & CHANNEL_NONBLOCKING)) { SetBlockMode(NULL, csPtr->writePtr, nonBlocking ? TCL_MODE_NONBLOCKING : TCL_MODE_BLOCKING); } } outStatePtr->flags &= ~(CHANNEL_LINEBUFFERED | CHANNEL_UNBUFFERED); outStatePtr->flags |= csPtr->writeFlags & (CHANNEL_LINEBUFFERED | CHANNEL_UNBUFFERED); if (csPtr->cmdPtr) { Tcl_DeleteChannelHandler((Tcl_Channel)csPtr->readPtr, CopyEventProc, (ClientData)csPtr); if (csPtr->readPtr != csPtr->writePtr) { Tcl_DeleteChannelHandler((Tcl_Channel)csPtr->writePtr, CopyEventProc, (ClientData)csPtr); } Tcl_DecrRefCount(csPtr->cmdPtr); } inStatePtr->csPtrR = NULL; outStatePtr->csPtrW = NULL; ckfree((char*) csPtr); } /* *---------------------------------------------------------------------- * * StackSetBlockMode -- * * This function sets the blocking mode for a channel, iterating * through each channel in a stack and updates the state flags. * * Results: * 0 if OK, result code from failed blockModeProc otherwise. * * Side effects: * Modifies the blocking mode of the channel and possibly generates * an error. * *---------------------------------------------------------------------- */ static int StackSetBlockMode(chanPtr, mode) Channel *chanPtr; /* Channel to modify. */ int mode; /* One of TCL_MODE_BLOCKING or * TCL_MODE_NONBLOCKING. */ { int result = 0; Tcl_DriverBlockModeProc *blockModeProc; /* * Start at the top of the channel stack */ chanPtr = chanPtr->state->topChanPtr; while (chanPtr != (Channel *) NULL) { blockModeProc = Tcl_ChannelBlockModeProc(chanPtr->typePtr); if (blockModeProc != NULL) { result = (*blockModeProc) (chanPtr->instanceData, mode); if (result != 0) { Tcl_SetErrno(result); return result; } } chanPtr = chanPtr->downChanPtr; } return 0; } /* *---------------------------------------------------------------------- * * SetBlockMode -- * * This function sets the blocking mode for a channel and updates * the state flags. * * Results: * A standard Tcl result. * * Side effects: * Modifies the blocking mode of the channel and possibly generates * an error. * *---------------------------------------------------------------------- */ static int SetBlockMode(interp, chanPtr, mode) Tcl_Interp *interp; /* Interp for error reporting. */ Channel *chanPtr; /* Channel to modify. */ int mode; /* One of TCL_MODE_BLOCKING or * TCL_MODE_NONBLOCKING. */ { ChannelState *statePtr = chanPtr->state; /* state info for channel */ int result = 0; result = StackSetBlockMode(chanPtr, mode); if (result != 0) { if (interp != (Tcl_Interp *) NULL) { Tcl_AppendResult(interp, "error setting blocking mode: ", Tcl_PosixError(interp), (char *) NULL); } return TCL_ERROR; } if (mode == TCL_MODE_BLOCKING) { statePtr->flags &= (~(CHANNEL_NONBLOCKING | BG_FLUSH_SCHEDULED)); } else { statePtr->flags |= CHANNEL_NONBLOCKING; } return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_GetChannelNames -- * * Return the names of all open channels in the interp. * * Results: * TCL_OK or TCL_ERROR. * * Side effects: * Interp result modified with list of channel names. * *---------------------------------------------------------------------- */ int Tcl_GetChannelNames(interp) Tcl_Interp *interp; /* Interp for error reporting. */ { return Tcl_GetChannelNamesEx(interp, (char *) NULL); } /* *---------------------------------------------------------------------- * * Tcl_GetChannelNamesEx -- * * Return the names of open channels in the interp filtered * filtered through a pattern. If pattern is NULL, it returns * all the open channels. * * Results: * TCL_OK or TCL_ERROR. * * Side effects: * Interp result modified with list of channel names. * *---------------------------------------------------------------------- */ int Tcl_GetChannelNamesEx(interp, pattern) Tcl_Interp *interp; /* Interp for error reporting. */ CONST char *pattern; /* pattern to filter on. */ { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); ChannelState *statePtr; CONST char *name; /* name for channel */ Tcl_Obj *resultPtr; /* pointer to result object */ Tcl_HashTable *hTblPtr; /* Hash table of channels. */ Tcl_HashEntry *hPtr; /* Search variable. */ Tcl_HashSearch hSearch; /* Search variable. */ if (interp == (Tcl_Interp *) NULL) { return TCL_OK; } /* * Get the channel table that stores the channels registered * for this interpreter. */ hTblPtr = GetChannelTable(interp); resultPtr = Tcl_GetObjResult(interp); for (hPtr = Tcl_FirstHashEntry(hTblPtr, &hSearch); hPtr != (Tcl_HashEntry *) NULL; hPtr = Tcl_NextHashEntry(&hSearch)) { statePtr = ((Channel *) Tcl_GetHashValue(hPtr))->state; if (statePtr->topChanPtr == (Channel *) tsdPtr->stdinChannel) { name = "stdin"; } else if (statePtr->topChanPtr == (Channel *) tsdPtr->stdoutChannel) { name = "stdout"; } else if (statePtr->topChanPtr == (Channel *) tsdPtr->stderrChannel) { name = "stderr"; } else { /* * This is also stored in Tcl_GetHashKey(hTblPtr, hPtr), * but it's simpler to just grab the name from the statePtr. */ name = statePtr->channelName; } if (((pattern == NULL) || Tcl_StringMatch(name, pattern)) && (Tcl_ListObjAppendElement(interp, resultPtr, Tcl_NewStringObj(name, -1)) != TCL_OK)) { return TCL_ERROR; } } return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_IsChannelRegistered -- * * Checks whether the channel is associated with the interp. * See also Tcl_RegisterChannel and Tcl_UnregisterChannel. * * Results: * 0 if the channel is not registered in the interpreter, 1 else. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_IsChannelRegistered (interp, chan) Tcl_Interp* interp; /* The interp to query of the channel */ Tcl_Channel chan; /* The channel to check */ { Tcl_HashTable *hTblPtr; /* Hash table of channels. */ Tcl_HashEntry *hPtr; /* Search variable. */ Channel *chanPtr; /* The real IO channel. */ ChannelState *statePtr; /* State of the real channel. */ /* * Always check bottom-most channel in the stack. This is the one * that gets registered. */ chanPtr = ((Channel *) chan)->state->bottomChanPtr; statePtr = chanPtr->state; hTblPtr = (Tcl_HashTable *) Tcl_GetAssocData(interp, "tclIO", NULL); if (hTblPtr == (Tcl_HashTable *) NULL) { return 0; } hPtr = Tcl_FindHashEntry(hTblPtr, statePtr->channelName); if (hPtr == (Tcl_HashEntry *) NULL) { return 0; } if ((Channel *) Tcl_GetHashValue(hPtr) != chanPtr) { return 0; } return 1; } /* *---------------------------------------------------------------------- * * Tcl_IsChannelShared -- * * Checks whether the channel is shared by multiple interpreters. * * Results: * A boolean value (0 = Not shared, 1 = Shared). * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_IsChannelShared (chan) Tcl_Channel chan; /* The channel to query */ { ChannelState *statePtr = ((Channel *) chan)->state; /* State of real channel structure. */ return ((statePtr->refCount > 1) ? 1 : 0); } /* *---------------------------------------------------------------------- * * Tcl_IsChannelExisting -- * * Checks whether a channel of the given name exists in the * (thread)-global list of all channels. * See Tcl_GetChannelNamesEx for function exposed at the Tcl level. * * Results: * A boolean value (0 = Does not exist, 1 = Does exist). * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_IsChannelExisting(chanName) CONST char* chanName; /* The name of the channel to look for. */ { ChannelState *statePtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); CONST char *name; int chanNameLen; chanNameLen = strlen(chanName); for (statePtr = tsdPtr->firstCSPtr; statePtr != NULL; statePtr = statePtr->nextCSPtr) { if (statePtr->topChanPtr == (Channel *) tsdPtr->stdinChannel) { name = "stdin"; } else if (statePtr->topChanPtr == (Channel *) tsdPtr->stdoutChannel) { name = "stdout"; } else if (statePtr->topChanPtr == (Channel *) tsdPtr->stderrChannel) { name = "stderr"; } else { name = statePtr->channelName; } /* Bug 2333466. Include \0 in the compare to prevent partial matching on prefixes. */ if ((*chanName == *name) && (memcmp(name, chanName, (size_t) chanNameLen+1) == 0)) { return 1; } } return 0; } /* *---------------------------------------------------------------------- * * Tcl_ChannelName -- * * Return the name of the channel type. * * Results: * A pointer the name of the channel type. * * Side effects: * None. * *---------------------------------------------------------------------- */ CONST char * Tcl_ChannelName(chanTypePtr) Tcl_ChannelType *chanTypePtr; /* Pointer to channel type. */ { return chanTypePtr->typeName; } /* *---------------------------------------------------------------------- * * Tcl_ChannelVersion -- * * Return the of version of the channel type. * * Results: * One of the TCL_CHANNEL_VERSION_* constants from tcl.h * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_ChannelTypeVersion Tcl_ChannelVersion(chanTypePtr) Tcl_ChannelType *chanTypePtr; /* Pointer to channel type. */ { if (chanTypePtr->version == TCL_CHANNEL_VERSION_2) { return TCL_CHANNEL_VERSION_2; } else if (chanTypePtr->version == TCL_CHANNEL_VERSION_3) { return TCL_CHANNEL_VERSION_3; } else if (chanTypePtr->version == TCL_CHANNEL_VERSION_4) { return TCL_CHANNEL_VERSION_4; } else { /* * In = ((int)minimumVersion); } /* *---------------------------------------------------------------------- * * Tcl_ChannelBlockModeProc -- * * Return the Tcl_DriverBlockModeProc of the channel type. * * Results: * A pointer to the proc. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_DriverBlockModeProc * Tcl_ChannelBlockModeProc(chanTypePtr) Tcl_ChannelType *chanTypePtr; /* Pointer to channel type. */ { if (HaveVersion(chanTypePtr, TCL_CHANNEL_VERSION_2)) { return chanTypePtr->blockModeProc; } else { /* * The v1 structure had the blockModeProc in a different place. */ return (Tcl_DriverBlockModeProc *) (chanTypePtr->version); } } /* *---------------------------------------------------------------------- * * Tcl_ChannelCloseProc -- * * Return the Tcl_DriverCloseProc of the channel type. * * Results: * A pointer to the proc. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_DriverCloseProc * Tcl_ChannelCloseProc(chanTypePtr) Tcl_ChannelType *chanTypePtr; /* Pointer to channel type. */ { return chanTypePtr->closeProc; } /* *---------------------------------------------------------------------- * * Tcl_ChannelClose2Proc -- * * Return the Tcl_DriverClose2Proc of the channel type. * * Results: * A pointer to the proc. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_DriverClose2Proc * Tcl_ChannelClose2Proc(chanTypePtr) Tcl_ChannelType *chanTypePtr; /* Pointer to channel type. */ { return chanTypePtr->close2Proc; } /* *---------------------------------------------------------------------- * * Tcl_ChannelInputProc -- * * Return the Tcl_DriverInputProc of the channel type. * * Results: * A pointer to the proc. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_DriverInputProc * Tcl_ChannelInputProc(chanTypePtr) Tcl_ChannelType *chanTypePtr; /* Pointer to channel type. */ { return chanTypePtr->inputProc; } /* *---------------------------------------------------------------------- * * Tcl_ChannelOutputProc -- * * Return the Tcl_DriverOutputProc of the channel type. * * Results: * A pointer to the proc. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_DriverOutputProc * Tcl_ChannelOutputProc(chanTypePtr) Tcl_ChannelType *chanTypePtr; /* Pointer to channel type. */ { return chanTypePtr->outputProc; } /* *---------------------------------------------------------------------- * * Tcl_ChannelSeekProc -- * * Return the Tcl_DriverSeekProc of the channel type. * * Results: * A pointer to the proc. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_DriverSeekProc * Tcl_ChannelSeekProc(chanTypePtr) Tcl_ChannelType *chanTypePtr; /* Pointer to channel type. */ { return chanTypePtr->seekProc; } /* *---------------------------------------------------------------------- * * Tcl_ChannelSetOptionProc -- * * Return the Tcl_DriverSetOptionProc of the channel type. * * Results: * A pointer to the proc. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_DriverSetOptionProc * Tcl_ChannelSetOptionProc(chanTypePtr) Tcl_ChannelType *chanTypePtr; /* Pointer to channel type. */ { return chanTypePtr->setOptionProc; } /* *---------------------------------------------------------------------- * * Tcl_ChannelGetOptionProc -- * * Return the Tcl_DriverGetOptionProc of the channel type. * * Results: * A pointer to the proc. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_DriverGetOptionProc * Tcl_ChannelGetOptionProc(chanTypePtr) Tcl_ChannelType *chanTypePtr; /* Pointer to channel type. */ { return chanTypePtr->getOptionProc; } /* *---------------------------------------------------------------------- * * Tcl_ChannelWatchProc -- * * Return the Tcl_DriverWatchProc of the channel type. * * Results: * A pointer to the proc. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_DriverWatchProc * Tcl_ChannelWatchProc(chanTypePtr) Tcl_ChannelType *chanTypePtr; /* Pointer to channel type. */ { return chanTypePtr->watchProc; } /* *---------------------------------------------------------------------- * * Tcl_ChannelGetHandleProc -- * * Return the Tcl_DriverGetHandleProc of the channel type. * * Results: * A pointer to the proc. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_DriverGetHandleProc * Tcl_ChannelGetHandleProc(chanTypePtr) Tcl_ChannelType *chanTypePtr; /* Pointer to channel type. */ { return chanTypePtr->getHandleProc; } /* *---------------------------------------------------------------------- * * Tcl_ChannelFlushProc -- * * Return the Tcl_DriverFlushProc of the channel type. * * Results: * A pointer to the proc. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_DriverFlushProc * Tcl_ChannelFlushProc(chanTypePtr) Tcl_ChannelType *chanTypePtr; /* Pointer to channel type. */ { if (HaveVersion(chanTypePtr, TCL_CHANNEL_VERSION_2)) { return chanTypePtr->flushProc; } else { return NULL; } } /* *---------------------------------------------------------------------- * * Tcl_ChannelHandlerProc -- * * Return the Tcl_DriverHandlerProc of the channel type. * * Results: * A pointer to the proc. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_DriverHandlerProc * Tcl_ChannelHandlerProc(chanTypePtr) Tcl_ChannelType *chanTypePtr; /* Pointer to channel type. */ { if (HaveVersion(chanTypePtr, TCL_CHANNEL_VERSION_2)) { return chanTypePtr->handlerProc; } else { return NULL; } } /* *---------------------------------------------------------------------- * * Tcl_ChannelWideSeekProc -- * * Return the Tcl_DriverWideSeekProc of the channel type. * * Results: * A pointer to the proc. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_DriverWideSeekProc * Tcl_ChannelWideSeekProc(chanTypePtr) Tcl_ChannelType *chanTypePtr; /* Pointer to channel type. */ { if (HaveVersion(chanTypePtr, TCL_CHANNEL_VERSION_3)) { return chanTypePtr->wideSeekProc; } else { return NULL; } } /* *---------------------------------------------------------------------- * * Tcl_ChannelThreadActionProc -- * * Return the Tcl_DriverThreadActionProc of the channel type. * * Results: * A pointer to the proc. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_DriverThreadActionProc * Tcl_ChannelThreadActionProc(chanTypePtr) Tcl_ChannelType *chanTypePtr; /* Pointer to channel type. */ { if (HaveVersion(chanTypePtr, TCL_CHANNEL_VERSION_4)) { return chanTypePtr->threadActionProc; } else { return NULL; } } #if 0 /* For future debugging work, a simple function to print the flags of * a channel in semi-readable form. */ static int DumpFlags (str, flags) char* str; int flags; { char buf [20]; int i = 0; if (flags & TCL_READABLE) {buf[i] = 'r';} else {buf [i]='_';}; i++; if (flags & TCL_WRITABLE) {buf[i] = 'w';} else {buf [i]='_';}; i++; if (flags & CHANNEL_NONBLOCKING) {buf[i] = 'n';} else {buf [i]='_';}; i++; if (flags & CHANNEL_LINEBUFFERED) {buf[i] = 'l';} else {buf [i]='_';}; i++; if (flags & CHANNEL_UNBUFFERED) {buf[i] = 'u';} else {buf [i]='_';}; i++; if (flags & BUFFER_READY) {buf[i] = 'R';} else {buf [i]='_';}; i++; if (flags & BG_FLUSH_SCHEDULED) {buf[i] = 'F';} else {buf [i]='_';}; i++; if (flags & CHANNEL_CLOSED) {buf[i] = 'c';} else {buf [i]='_';}; i++; if (flags & CHANNEL_EOF) {buf[i] = 'E';} else {buf [i]='_';}; i++; if (flags & CHANNEL_STICKY_EOF) {buf[i] = 'S';} else {buf [i]='_';}; i++; if (flags & CHANNEL_BLOCKED) {buf[i] = 'B';} else {buf [i]='_';}; i++; if (flags & INPUT_SAW_CR) {buf[i] = '/';} else {buf [i]='_';}; i++; if (flags & INPUT_NEED_NL) {buf[i] = '*';} else {buf [i]='_';}; i++; if (flags & CHANNEL_DEAD) {buf[i] = 'D';} else {buf [i]='_';}; i++; if (flags & CHANNEL_RAW_MODE) {buf[i] = 'R';} else {buf [i]='_';}; i++; #ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING if (flags & CHANNEL_TIMER_FEV) {buf[i] = 'T';} else {buf [i]='_';}; i++; if (flags & CHANNEL_HAS_MORE_DATA) {buf[i] = 'H';} else {buf [i]='_';}; i++; #endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */ if (flags & CHANNEL_INCLOSE) {buf[i] = 'x';} else {buf [i]='_';}; i++; buf [i] ='\0'; fprintf (stderr,"%s: %s\n", str, buf); fflush(stderr); return 0; } #endif tcl8.4.20/generic/tclEnv.c0000644003604700454610000004454512052456743013744 0ustar dgp771div/* * tclEnv.c -- * * Tcl support for environment variables, including a setenv * procedure. This file contains the generic portion of the * environment module. It is primarily responsible for keeping * the "env" arrays in sync with the system environment variables. * * Copyright (c) 1991-1994 The Regents of the University of California. * Copyright (c) 1994-1998 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" TCL_DECLARE_MUTEX(envMutex) /* To serialize access to environ */ static int cacheSize = 0; /* Number of env strings in environCache. */ static char **environCache = NULL; /* Array containing all of the environment * strings that Tcl has allocated. */ #ifndef USE_PUTENV static char **ourEnviron = NULL;/* Cache of the array that we allocate. * We need to track this in case another * subsystem swaps around the environ array * like we do. */ static int environSize = 0; /* Non-zero means that the environ array was * malloced and has this many total entries * allocated to it (not all may be in use at * once). Zero means that the environment * array is in its original static state. */ #endif /* * Declarations for local procedures defined in this file: */ static char * EnvTraceProc _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, CONST char *name1, CONST char *name2, int flags)); static void ReplaceString _ANSI_ARGS_((CONST char *oldStr, char *newStr)); void TclSetEnv _ANSI_ARGS_((CONST char *name, CONST char *value)); void TclUnsetEnv _ANSI_ARGS_((CONST char *name)); /* *---------------------------------------------------------------------- * * TclSetupEnv -- * * This procedure is invoked for an interpreter to make environment * variables accessible from that interpreter via the "env" * associative array. * * Results: * None. * * Side effects: * The interpreter is added to a list of interpreters managed * by us, so that its view of envariables can be kept consistent * with the view in other interpreters. If this is the first * call to TclSetupEnv, then additional initialization happens, * such as copying the environment to dynamically-allocated space * for ease of management. * *---------------------------------------------------------------------- */ void TclSetupEnv(interp) Tcl_Interp *interp; /* Interpreter whose "env" array is to be * managed. */ { Tcl_DString envString; char *p1, *p2; int i; /* * Synchronize the values in the environ array with the contents * of the Tcl "env" variable. To do this: * 1) Remove the trace that fires when the "env" var is unset. * 2) Unset the "env" variable. * 3) If there are no environ variables, create an empty "env" * array. Otherwise populate the array with current values. * 4) Add a trace that synchronizes the "env" array. */ Tcl_UntraceVar2(interp, "env", (char *) NULL, TCL_GLOBAL_ONLY | TCL_TRACE_WRITES | TCL_TRACE_UNSETS | TCL_TRACE_READS | TCL_TRACE_ARRAY, EnvTraceProc, (ClientData) NULL); Tcl_UnsetVar2(interp, "env", (char *) NULL, TCL_GLOBAL_ONLY); if (environ[0] == NULL) { Tcl_Obj *varNamePtr; varNamePtr = Tcl_NewStringObj("env", -1); Tcl_IncrRefCount(varNamePtr); TclArraySet(interp, varNamePtr, NULL); Tcl_DecrRefCount(varNamePtr); } else { Tcl_MutexLock(&envMutex); for (i = 0; environ[i] != NULL; i++) { p1 = Tcl_ExternalToUtfDString(NULL, environ[i], -1, &envString); p2 = strchr(p1, '='); if (p2 == NULL) { /* * This condition seem to happen occasionally under some * versions of Solaris; ignore the entry. */ continue; } p2++; p2[-1] = '\0'; Tcl_SetVar2(interp, "env", p1, p2, TCL_GLOBAL_ONLY); Tcl_DStringFree(&envString); } Tcl_MutexUnlock(&envMutex); } Tcl_TraceVar2(interp, "env", (char *) NULL, TCL_GLOBAL_ONLY | TCL_TRACE_WRITES | TCL_TRACE_UNSETS | TCL_TRACE_READS | TCL_TRACE_ARRAY, EnvTraceProc, (ClientData) NULL); } /* *---------------------------------------------------------------------- * * TclSetEnv -- * * Set an environment variable, replacing an existing value * or creating a new variable if there doesn't exist a variable * by the given name. This procedure is intended to be a * stand-in for the UNIX "setenv" procedure so that applications * using that procedure will interface properly to Tcl. To make * it a stand-in, the Makefile must define "TclSetEnv" to "setenv". * * Results: * None. * * Side effects: * The environ array gets updated. * *---------------------------------------------------------------------- */ void TclSetEnv(name, value) CONST char *name; /* Name of variable whose value is to be * set (UTF-8). */ CONST char *value; /* New value for variable (UTF-8). */ { Tcl_DString envString; int index, length, nameLength; char *p, *oldValue; CONST char *p2; /* * Figure out where the entry is going to go. If the name doesn't * already exist, enlarge the array if necessary to make room. If the * name exists, free its old entry. */ Tcl_MutexLock(&envMutex); index = TclpFindVariable(name, &length); if (index == -1) { #ifndef USE_PUTENV /* * We need to handle the case where the environment may be changed * outside our control. environSize is only valid if the current * environment is the one we allocated. [Bug 979640] */ if ((ourEnviron != environ) || ((length + 2) > environSize)) { char **newEnviron; newEnviron = (char **) ckalloc((unsigned) ((length + 5) * sizeof(char *))); memcpy((VOID *) newEnviron, (VOID *) environ, length*sizeof(char *)); if ((environSize != 0) && (ourEnviron != NULL)) { ckfree((char *) ourEnviron); } environ = ourEnviron = newEnviron; environSize = length + 5; } index = length; environ[index + 1] = NULL; #endif oldValue = NULL; nameLength = strlen(name); } else { CONST char *env; /* * Compare the new value to the existing value. If they're * the same then quit immediately (e.g. don't rewrite the * value or propagate it to other interpreters). Otherwise, * when there are N interpreters there will be N! propagations * of the same value among the interpreters. */ env = Tcl_ExternalToUtfDString(NULL, environ[index], -1, &envString); if (strcmp(value, (env + length + 1)) == 0) { Tcl_DStringFree(&envString); Tcl_MutexUnlock(&envMutex); return; } Tcl_DStringFree(&envString); oldValue = environ[index]; nameLength = length; } /* * Create a new entry. Build a complete UTF string that contains * a "name=value" pattern. Then convert the string to the native * encoding, and set the environ array value. */ p = (char *) ckalloc((unsigned) (nameLength + strlen(value) + 2)); strcpy(p, name); p[nameLength] = '='; strcpy(p+nameLength+1, value); p2 = Tcl_UtfToExternalDString(NULL, p, -1, &envString); /* * Copy the native string to heap memory. */ p = (char *) ckrealloc(p, (unsigned) (strlen(p2) + 1)); strcpy(p, p2); Tcl_DStringFree(&envString); #ifdef USE_PUTENV /* * Update the system environment. */ putenv(p); index = TclpFindVariable(name, &length); #else environ[index] = p; #endif /* * Watch out for versions of putenv that copy the string (e.g. VC++). * In this case we need to free the string immediately. Otherwise * update the string in the cache. */ if ((index != -1) && (environ[index] == p)) { ReplaceString(oldValue, p); #ifdef HAVE_PUTENV_THAT_COPIES } else { /* This putenv() copies instead of taking ownership */ ckfree(p); #endif } Tcl_MutexUnlock(&envMutex); if (!strcmp(name, "HOME")) { /* * If the user's home directory has changed, we must invalidate * the filesystem cache, because '~' expansions will now be * incorrect. */ Tcl_FSMountsChanged(NULL); } } /* *---------------------------------------------------------------------- * * Tcl_PutEnv -- * * Set an environment variable. Similar to setenv except that * the information is passed in a single string of the form * NAME=value, rather than as separate name strings. This procedure * is intended to be a stand-in for the UNIX "putenv" procedure * so that applications using that procedure will interface * properly to Tcl. To make it a stand-in, the Makefile will * define "Tcl_PutEnv" to "putenv". * * Results: * None. * * Side effects: * The environ array gets updated, as do all of the interpreters * that we manage. * *---------------------------------------------------------------------- */ int Tcl_PutEnv(string) CONST char *string; /* Info about environment variable in the * form NAME=value. (native) */ { Tcl_DString nameString; CONST char *name; char *value; if (string == NULL) { return 0; } /* * First convert the native string to UTF. Then separate the * string into name and value parts, and call TclSetEnv to do * all of the real work. */ name = Tcl_ExternalToUtfDString(NULL, string, -1, &nameString); value = strchr(name, '='); if ((value != NULL) && (value != name)) { value[0] = '\0'; TclSetEnv(name, value+1); } Tcl_DStringFree(&nameString); return 0; } /* *---------------------------------------------------------------------- * * TclUnsetEnv -- * * Remove an environment variable, updating the "env" arrays * in all interpreters managed by us. This function is intended * to replace the UNIX "unsetenv" function (but to do this the * Makefile must be modified to redefine "TclUnsetEnv" to * "unsetenv". * * Results: * None. * * Side effects: * Interpreters are updated, as is environ. * *---------------------------------------------------------------------- */ void TclUnsetEnv(name) CONST char *name; /* Name of variable to remove (UTF-8). */ { char *oldValue; int length; int index; #ifdef USE_PUTENV_FOR_UNSET Tcl_DString envString; char *string; #else char **envPtr; #endif Tcl_MutexLock(&envMutex); index = TclpFindVariable(name, &length); /* * First make sure that the environment variable exists to avoid * doing needless work and to avoid recursion on the unset. */ if (index == -1) { Tcl_MutexUnlock(&envMutex); return; } /* * Remember the old value so we can free it if Tcl created the string. */ oldValue = environ[index]; /* * Update the system environment. This must be done before we * update the interpreters or we will recurse. */ #ifdef USE_PUTENV_FOR_UNSET /* * For those platforms that support putenv to unset, Linux indicates * that no = should be included, and Windows requires it. */ #ifdef WIN32 string = ckalloc((unsigned int) length+2); memcpy((VOID *) string, (VOID *) name, (size_t) length); string[length] = '='; string[length+1] = '\0'; #else string = ckalloc((unsigned int) length+1); memcpy((VOID *) string, (VOID *) name, (size_t) length); string[length] = '\0'; #endif Tcl_UtfToExternalDString(NULL, string, -1, &envString); string = ckrealloc(string, (unsigned) (Tcl_DStringLength(&envString)+1)); strcpy(string, Tcl_DStringValue(&envString)); Tcl_DStringFree(&envString); putenv(string); /* * Watch out for versions of putenv that copy the string (e.g. VC++). * In this case we need to free the string immediately. Otherwise * update the string in the cache. */ if (environ[index] == string) { ReplaceString(oldValue, string); #ifdef HAVE_PUTENV_THAT_COPIES } else { /* This putenv() copies instead of taking ownership */ ckfree(string); #endif } #else for (envPtr = environ+index+1; ; envPtr++) { envPtr[-1] = *envPtr; if (*envPtr == NULL) { break; } } ReplaceString(oldValue, NULL); #endif Tcl_MutexUnlock(&envMutex); } /* *--------------------------------------------------------------------------- * * TclGetEnv -- * * Retrieve the value of an environment variable. * * Results: * The result is a pointer to a string specifying the value of the * environment variable, or NULL if that environment variable does * not exist. Storage for the result string is allocated in valuePtr; * the caller must call Tcl_DStringFree() when the result is no * longer needed. * * Side effects: * None. * *---------------------------------------------------------------------- */ CONST char * TclGetEnv(name, valuePtr) CONST char *name; /* Name of environment variable to find * (UTF-8). */ Tcl_DString *valuePtr; /* Uninitialized or free DString in which * the value of the environment variable is * stored. */ { int length, index; CONST char *result; Tcl_MutexLock(&envMutex); index = TclpFindVariable(name, &length); result = NULL; if (index != -1) { Tcl_DString envStr; result = Tcl_ExternalToUtfDString(NULL, environ[index], -1, &envStr); result += length; if (*result == '=') { result++; Tcl_DStringInit(valuePtr); Tcl_DStringAppend(valuePtr, result, -1); result = Tcl_DStringValue(valuePtr); } else { result = NULL; } Tcl_DStringFree(&envStr); } Tcl_MutexUnlock(&envMutex); return result; } /* *---------------------------------------------------------------------- * * EnvTraceProc -- * * This procedure is invoked whenever an environment variable * is read, modified or deleted. It propagates the change to the global * "environ" array. * * Results: * Always returns NULL to indicate success. * * Side effects: * Environment variable changes get propagated. If the whole * "env" array is deleted, then we stop managing things for * this interpreter (usually this happens because the whole * interpreter is being deleted). * *---------------------------------------------------------------------- */ /* ARGSUSED */ static char * EnvTraceProc(clientData, interp, name1, name2, flags) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter whose "env" variable is * being modified. */ CONST char *name1; /* Better be "env". */ CONST char *name2; /* Name of variable being modified, or NULL * if whole array is being deleted (UTF-8). */ int flags; /* Indicates what's happening. */ { /* * For array traces, let TclSetupEnv do all the work. */ if (flags & TCL_TRACE_ARRAY) { TclSetupEnv(interp); return NULL; } /* * If name2 is NULL, then return and do nothing. */ if (name2 == NULL) { return NULL; } /* * If a value is being set, call TclSetEnv to do all of the work. */ if (flags & TCL_TRACE_WRITES) { CONST char *value; value = Tcl_GetVar2(interp, "env", name2, TCL_GLOBAL_ONLY); TclSetEnv(name2, value); } /* * If a value is being read, call TclGetEnv to do all of the work. */ if (flags & TCL_TRACE_READS) { Tcl_DString valueString; CONST char *value; value = TclGetEnv(name2, &valueString); if (value == NULL) { return "no such variable"; } Tcl_SetVar2(interp, name1, name2, value, 0); Tcl_DStringFree(&valueString); } /* * For unset traces, let TclUnsetEnv do all the work. */ if (flags & TCL_TRACE_UNSETS) { TclUnsetEnv(name2); } return NULL; } /* *---------------------------------------------------------------------- * * ReplaceString -- * * Replace one string with another in the environment variable * cache. The cache keeps track of all of the environment * variables that Tcl has modified so they can be freed later. * * Results: * None. * * Side effects: * May free the old string. * *---------------------------------------------------------------------- */ static void ReplaceString(oldStr, newStr) CONST char *oldStr; /* Old environment string. */ char *newStr; /* New environment string. */ { int i; char **newCache; /* * Check to see if the old value was allocated by Tcl. If so, * it needs to be deallocated to avoid memory leaks. Note that this * algorithm is O(n), not O(1). This will result in n-squared behavior * if lots of environment changes are being made. */ for (i = 0; i < cacheSize; i++) { if ((environCache[i] == oldStr) || (environCache[i] == NULL)) { break; } } if (i < cacheSize) { /* * Replace or delete the old value. */ if (environCache[i]) { ckfree(environCache[i]); } if (newStr) { environCache[i] = newStr; } else { for (; i < cacheSize-1; i++) { environCache[i] = environCache[i+1]; } environCache[cacheSize-1] = NULL; } } else { int allocatedSize = (cacheSize + 5) * sizeof(char *); /* * We need to grow the cache in order to hold the new string. */ newCache = (char **) ckalloc((unsigned) allocatedSize); (VOID *) memset(newCache, (int) 0, (size_t) allocatedSize); if (environCache) { memcpy((VOID *) newCache, (VOID *) environCache, (size_t) (cacheSize * sizeof(char*))); ckfree((char *) environCache); } environCache = newCache; environCache[cacheSize] = newStr; environCache[cacheSize+1] = NULL; cacheSize += 5; } } /* *---------------------------------------------------------------------- * * TclFinalizeEnvironment -- * * This function releases any storage allocated by this module * that isn't still in use by the global environment. Any * strings that are still in the environment will be leaked. * * Results: * None. * * Side effects: * May deallocate storage. * *---------------------------------------------------------------------- */ void TclFinalizeEnvironment() { /* * For now we just deallocate the cache array and none of the environment * strings. This may leak more memory that strictly necessary, since some * of the strings may no longer be in the environment. However, * determining which ones are ok to delete is n-squared, and is pretty * unlikely, so we don't bother. */ if (environCache) { ckfree((char *) environCache); environCache = NULL; cacheSize = 0; #ifndef USE_PUTENV environSize = 0; #endif } } /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ tcl8.4.20/generic/tclHistory.c0000644003604700454610000000733611737050674014654 0ustar dgp771div/* * tclHistory.c -- * * This module and the Tcl library file history.tcl together implement * Tcl command history. Tcl_RecordAndEval(Obj) can be called to record * commands ("events") before they are executed. Commands defined in * history.tcl may be used to perform history substitutions. * * Copyright (c) 1990-1993 The Regents of the University of California. * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" /* *---------------------------------------------------------------------- * * Tcl_RecordAndEval -- * * This procedure adds its command argument to the current list of * recorded events and then executes the command by calling * Tcl_Eval. * * Results: * The return value is a standard Tcl return value, the result of * executing cmd. * * Side effects: * The command is recorded and executed. * *---------------------------------------------------------------------- */ int Tcl_RecordAndEval(interp, cmd, flags) Tcl_Interp *interp; /* Token for interpreter in which command * will be executed. */ CONST char *cmd; /* Command to record. */ int flags; /* Additional flags. TCL_NO_EVAL means * only record: don't execute command. * TCL_EVAL_GLOBAL means use Tcl_GlobalEval * instead of Tcl_Eval. */ { register Tcl_Obj *cmdPtr; int length = strlen(cmd); int result; if (length > 0) { /* * Call Tcl_RecordAndEvalObj to do the actual work. */ cmdPtr = Tcl_NewStringObj(cmd, length); Tcl_IncrRefCount(cmdPtr); result = Tcl_RecordAndEvalObj(interp, cmdPtr, flags); /* * Move the interpreter's object result to the string result, * then reset the object result. */ Tcl_SetResult(interp, TclGetString(Tcl_GetObjResult(interp)), TCL_VOLATILE); /* * Discard the Tcl object created to hold the command. */ Tcl_DecrRefCount(cmdPtr); } else { /* * An empty string. Just reset the interpreter's result. */ Tcl_ResetResult(interp); result = TCL_OK; } return result; } /* *---------------------------------------------------------------------- * * Tcl_RecordAndEvalObj -- * * This procedure adds the command held in its argument object to the * current list of recorded events and then executes the command by * calling Tcl_EvalObj. * * Results: * The return value is a standard Tcl return value, the result of * executing the command. * * Side effects: * The command is recorded and executed. * *---------------------------------------------------------------------- */ int Tcl_RecordAndEvalObj(interp, cmdPtr, flags) Tcl_Interp *interp; /* Token for interpreter in which command * will be executed. */ Tcl_Obj *cmdPtr; /* Points to object holding the command to * record and execute. */ int flags; /* Additional flags. TCL_NO_EVAL means * record only: don't execute the command. * TCL_EVAL_GLOBAL means evaluate the * script in global variable context instead * of the current procedure. */ { int result; Tcl_Obj *list[3]; register Tcl_Obj *objPtr; /* * Do recording by eval'ing a tcl history command: history add $cmd. */ list[0] = Tcl_NewStringObj("history", -1); list[1] = Tcl_NewStringObj("add", -1); list[2] = cmdPtr; objPtr = Tcl_NewListObj(3, list); Tcl_IncrRefCount(objPtr); (void) Tcl_EvalObjEx(interp, objPtr, TCL_EVAL_GLOBAL); Tcl_DecrRefCount(objPtr); /* * Execute the command. */ result = TCL_OK; if (!(flags & TCL_NO_EVAL)) { result = Tcl_EvalObjEx(interp, cmdPtr, flags & TCL_EVAL_GLOBAL); } return result; } tcl8.4.20/generic/tclPort.h0000644003604700454610000000175212052456744014137 0ustar dgp771div/* * tclPort.h -- * * This header file handles porting issues that occur because * of differences between systems. It reads in platform specific * portability files. * * Copyright (c) 1994-1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef _TCLPORT #define _TCLPORT #include "tcl.h" #if defined(__WIN32__) # include "tclWinPort.h" #else # include "tclUnixPort.h" #endif #if !defined(LLONG_MIN) # ifdef TCL_WIDE_INT_IS_LONG # define LLONG_MIN LONG_MIN # else # ifdef LLONG_BIT # define LLONG_MIN ((Tcl_WideInt)(Tcl_LongAsWide(1)<<(LLONG_BIT-1))) # else /* Assume we're on a system with a 64-bit 'long long' type */ # define LLONG_MIN ((Tcl_WideInt)(Tcl_LongAsWide(1)<<63)) # endif # endif /* Assume that if LLONG_MIN is undefined, then so is LLONG_MAX */ # define LLONG_MAX (~LLONG_MIN) #endif #endif /* _TCLPORT */ tcl8.4.20/generic/tclUtil.c0000644003604700454610000022377212133546540014125 0ustar dgp771div/* * tclUtil.c -- * * This file contains utility procedures that are used by many Tcl * commands. * * Copyright (c) 1987-1993 The Regents of the University of California. * Copyright (c) 1994-1998 Sun Microsystems, Inc. * Copyright (c) 2001 by Kevin B. Kenny. All rights reserved. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" /* * The following variable holds the full path name of the binary * from which this application was executed, or NULL if it isn't * know. The value of the variable is set by the procedure * Tcl_FindExecutable. The storage space is dynamically allocated. */ char *tclExecutableName = NULL; char *tclNativeExecutableName = NULL; /* * The following values are used in the flags returned by Tcl_ScanElement * and used by Tcl_ConvertElement. The value TCL_DONT_USE_BRACES is also * defined in tcl.h; make sure its value doesn't overlap with any of the * values below. * * TCL_DONT_USE_BRACES - 1 means the string mustn't be enclosed in * braces (e.g. it contains unmatched braces, * or ends in a backslash character, or user * just doesn't want braces); handle all * special characters by adding backslashes. * USE_BRACES - 1 means the string contains a special * character that can be handled simply by * enclosing the entire argument in braces. * BRACES_UNMATCHED - 1 means that braces aren't properly matched * in the argument. */ #define USE_BRACES 2 #define BRACES_UNMATCHED 4 /* * Data structures for process-global values. */ typedef void (InitPGVProc) _ANSI_ARGS_ ((char **valuePtr, int *lengthPtr)); /* * A ProcessGlobalValue struct exists for each internal value in Tcl that is * to be shared among several threads. Each thread sees a (Tcl_Obj) copy of * the value, and the master is kept as a counted string, with epoch and mutex * control. Each ProcessGlobalValue struct should be a static variable in some * file. */ typedef struct ProcessGlobalValue { int epoch; /* Epoch counter to detect changes in the * master value. */ int numBytes; /* Length of the master string. */ char *value; /* The master string value. */ InitPGVProc *proc; /* A procedure to initialize the master string * copy when a "get" request comes in before * any "set" request has been received. */ Tcl_Mutex mutex; /* Enforce orderly access from multiple * threads. */ Tcl_ThreadDataKey key; /* Key for per-thread data holding the * (Tcl_Obj) copy for each thread. */ } PGV; /* * The following values determine the precision used when converting * floating-point values to strings. This information is linked to all * of the tcl_precision variables in all interpreters via the procedure * TclPrecTraceProc. */ static InitPGVProc InitPrecision; static PGV precision = { 0, 0, NULL, InitPrecision, NULL, NULL }; /* * Prototypes for procedures defined later in this file. */ static void ClearHash _ANSI_ARGS_((Tcl_HashTable *tablePtr)); static void FreePGV _ANSI_ARGS_((ClientData clientData)); static void FreeThreadHash _ANSI_ARGS_((ClientData clientData)); static Tcl_HashTable * GetThreadHash _ANSI_ARGS_(( Tcl_ThreadDataKey *keyPtr)); static void UpdateStringOfEndOffset _ANSI_ARGS_((Tcl_Obj* objPtr)); static int SetEndOffsetFromAny _ANSI_ARGS_((Tcl_Interp* interp, Tcl_Obj* objPtr)); static void SetPGV _ANSI_ARGS_((PGV *pgvPtr, Tcl_Obj *newValue)); static Tcl_Obj * GetPGV _ANSI_ARGS_((PGV *pgvPtr)); /* * The following is the Tcl object type definition for an object * that represents a list index in the form, "end-offset". It is * used as a performance optimization in TclGetIntForIndex. The * internal rep is an integer, so no memory management is required * for it. */ Tcl_ObjType tclEndOffsetType = { "end-offset", /* name */ (Tcl_FreeInternalRepProc*) NULL, /* freeIntRepProc */ (Tcl_DupInternalRepProc*) NULL, /* dupIntRepProc */ UpdateStringOfEndOffset, /* updateStringProc */ SetEndOffsetFromAny }; /* *---------------------------------------------------------------------- * * TclFindElement -- * * Given a pointer into a Tcl list, locate the first (or next) * element in the list. * * Results: * The return value is normally TCL_OK, which means that the * element was successfully located. If TCL_ERROR is returned * it means that list didn't have proper list structure; * the interp's result contains a more detailed error message. * * If TCL_OK is returned, then *elementPtr will be set to point to the * first element of list, and *nextPtr will be set to point to the * character just after any white space following the last character * that's part of the element. If this is the last argument in the * list, then *nextPtr will point just after the last character in the * list (i.e., at the character at list+listLength). If sizePtr is * non-NULL, *sizePtr is filled in with the number of characters in the * element. If the element is in braces, then *elementPtr will point * to the character after the opening brace and *sizePtr will not * include either of the braces. If there isn't an element in the list, * *sizePtr will be zero, and both *elementPtr and *termPtr will point * just after the last character in the list. Note: this procedure does * NOT collapse backslash sequences. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclFindElement(interp, list, listLength, elementPtr, nextPtr, sizePtr, bracePtr) Tcl_Interp *interp; /* Interpreter to use for error reporting. * If NULL, then no error message is left * after errors. */ CONST char *list; /* Points to the first byte of a string * containing a Tcl list with zero or more * elements (possibly in braces). */ int listLength; /* Number of bytes in the list's string. */ CONST char **elementPtr; /* Where to put address of first significant * character in first element of list. */ CONST char **nextPtr; /* Fill in with location of character just * after all white space following end of * argument (next arg or end of list). */ int *sizePtr; /* If non-zero, fill in with size of * element. */ int *bracePtr; /* If non-zero, fill in with non-zero/zero * to indicate that arg was/wasn't * in braces. */ { CONST char *p = list; CONST char *elemStart; /* Points to first byte of first element. */ CONST char *limit; /* Points just after list's last byte. */ int openBraces = 0; /* Brace nesting level during parse. */ int inQuotes = 0; int size = 0; /* lint. */ int numChars; CONST char *p2; /* * Skim off leading white space and check for an opening brace or * quote. We treat embedded NULLs in the list as bytes belonging to * a list element. */ limit = (list + listLength); while ((p < limit) && (isspace(UCHAR(*p)))) { /* INTL: ISO space. */ p++; } if (p == limit) { /* no element found */ elemStart = limit; goto done; } if (*p == '{') { openBraces = 1; p++; } else if (*p == '"') { inQuotes = 1; p++; } elemStart = p; if (bracePtr != 0) { *bracePtr = openBraces; } /* * Find element's end (a space, close brace, or the end of the string). */ while (p < limit) { switch (*p) { /* * Open brace: don't treat specially unless the element is in * braces. In this case, keep a nesting count. */ case '{': if (openBraces != 0) { openBraces++; } break; /* * Close brace: if element is in braces, keep nesting count and * quit when the last close brace is seen. */ case '}': if (openBraces > 1) { openBraces--; } else if (openBraces == 1) { size = (p - elemStart); p++; if ((p >= limit) || isspace(UCHAR(*p))) { /* INTL: ISO space. */ goto done; } /* * Garbage after the closing brace; return an error. */ if (interp != NULL) { char buf[100]; p2 = p; while ((p2 < limit) && (!isspace(UCHAR(*p2))) /* INTL: ISO space. */ && (p2 < p+20)) { p2++; } sprintf(buf, "list element in braces followed by \"%.*s\" instead of space", (int) (p2-p), p); Tcl_SetResult(interp, buf, TCL_VOLATILE); } return TCL_ERROR; } break; /* * Backslash: skip over everything up to the end of the * backslash sequence. */ case '\\': { TclParseBackslash(p, limit - p, &numChars, NULL); p += (numChars - 1); break; } /* * Space: ignore if element is in braces or quotes; otherwise * terminate element. */ case ' ': case '\f': case '\n': case '\r': case '\t': case '\v': if ((openBraces == 0) && !inQuotes) { size = (p - elemStart); goto done; } break; /* * Double-quote: if element is in quotes then terminate it. */ case '"': if (inQuotes) { size = (p - elemStart); p++; if ((p >= limit) || isspace(UCHAR(*p))) { /* INTL: ISO space */ goto done; } /* * Garbage after the closing quote; return an error. */ if (interp != NULL) { char buf[100]; p2 = p; while ((p2 < limit) && (!isspace(UCHAR(*p2))) /* INTL: ISO space */ && (p2 < p+20)) { p2++; } sprintf(buf, "list element in quotes followed by \"%.*s\" %s", (int) (p2-p), p, "instead of space"); Tcl_SetResult(interp, buf, TCL_VOLATILE); } return TCL_ERROR; } break; } p++; } /* * End of list: terminate element. */ if (p == limit) { if (openBraces != 0) { if (interp != NULL) { Tcl_SetResult(interp, "unmatched open brace in list", TCL_STATIC); } return TCL_ERROR; } else if (inQuotes) { if (interp != NULL) { Tcl_SetResult(interp, "unmatched open quote in list", TCL_STATIC); } return TCL_ERROR; } size = (p - elemStart); } done: while ((p < limit) && (isspace(UCHAR(*p)))) { /* INTL: ISO space. */ p++; } *elementPtr = elemStart; *nextPtr = p; if (sizePtr != 0) { *sizePtr = size; } return TCL_OK; } /* *---------------------------------------------------------------------- * * TclCopyAndCollapse -- * * Copy a string and eliminate any backslashes that aren't in braces. * * Results: * Count bytes get copied from src to dst. Along the way, backslash * sequences are substituted in the copy. After scanning count bytes * from src, a null character is placed at the end of dst. Returns * the number of bytes that got written to dst. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclCopyAndCollapse(count, src, dst) int count; /* Number of bytes to copy from src. */ CONST char *src; /* Copy from here... */ char *dst; /* ... to here. */ { int newCount = 0; while (count > 0) { char c = *src; if (c == '\\') { int numRead; int backslashCount = TclParseBackslash(src, count, &numRead, dst); dst += backslashCount; newCount += backslashCount; src += numRead; count -= numRead; } else { *dst = c; dst++; newCount++; src++; count--; } } *dst = 0; return newCount; } /* *---------------------------------------------------------------------- * * Tcl_SplitList -- * * Splits a list up into its constituent fields. * * Results * The return value is normally TCL_OK, which means that * the list was successfully split up. If TCL_ERROR is * returned, it means that "list" didn't have proper list * structure; the interp's result will contain a more detailed * error message. * * *argvPtr will be filled in with the address of an array * whose elements point to the elements of list, in order. * *argcPtr will get filled in with the number of valid elements * in the array. A single block of memory is dynamically allocated * to hold both the argv array and a copy of the list (with * backslashes and braces removed in the standard way). * The caller must eventually free this memory by calling free() * on *argvPtr. Note: *argvPtr and *argcPtr are only modified * if the procedure returns normally. * * Side effects: * Memory is allocated. * *---------------------------------------------------------------------- */ int Tcl_SplitList(interp, list, argcPtr, argvPtr) Tcl_Interp *interp; /* Interpreter to use for error reporting. * If NULL, no error message is left. */ CONST char *list; /* Pointer to string with list structure. */ int *argcPtr; /* Pointer to location to fill in with * the number of elements in the list. */ CONST char ***argvPtr; /* Pointer to place to store pointer to * array of pointers to list elements. */ { CONST char **argv; CONST char *l; char *p; int length, size, i, result, elSize, brace; CONST char *element; /* * Figure out how much space to allocate. There must be enough * space for both the array of pointers and also for a copy of * the list. To estimate the number of pointers needed, count * the number of space characters in the list. */ for (size = 2, l = list; *l != 0; l++) { if (isspace(UCHAR(*l))) { /* INTL: ISO space. */ size++; /* Consecutive space can only count as a single list delimiter */ while (1) { char next = *(l + 1); if (next == '\0') { break; } ++l; if (isspace(UCHAR(next))) { continue; } break; } } } length = l - list; argv = (CONST char **) ckalloc((unsigned) ((size * sizeof(char *)) + length + 1)); for (i = 0, p = ((char *) argv) + size*sizeof(char *); *list != 0; i++) { CONST char *prevList = list; result = TclFindElement(interp, list, length, &element, &list, &elSize, &brace); length -= (list - prevList); if (result != TCL_OK) { ckfree((char *) argv); return result; } if (*element == 0) { break; } if (i >= size) { ckfree((char *) argv); if (interp != NULL) { Tcl_SetResult(interp, "internal error in Tcl_SplitList", TCL_STATIC); } return TCL_ERROR; } argv[i] = p; if (brace) { memcpy((VOID *) p, (VOID *) element, (size_t) elSize); p += elSize; *p = 0; p++; } else { TclCopyAndCollapse(elSize, element, p); p += elSize+1; } } argv[i] = NULL; *argvPtr = argv; *argcPtr = i; return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_ScanElement -- * * This procedure is a companion procedure to Tcl_ConvertElement. * It scans a string to see what needs to be done to it (e.g. add * backslashes or enclosing braces) to make the string into a * valid Tcl list element. * * Results: * The return value is an overestimate of the number of characters * that will be needed by Tcl_ConvertElement to produce a valid * list element from string. The word at *flagPtr is filled in * with a value needed by Tcl_ConvertElement when doing the actual * conversion. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_ScanElement(string, flagPtr) register CONST char *string; /* String to convert to list element. */ register int *flagPtr; /* Where to store information to guide * Tcl_ConvertCountedElement. */ { return Tcl_ScanCountedElement(string, -1, flagPtr); } /* *---------------------------------------------------------------------- * * Tcl_ScanCountedElement -- * * This procedure is a companion procedure to * Tcl_ConvertCountedElement. It scans a string to see what * needs to be done to it (e.g. add backslashes or enclosing * braces) to make the string into a valid Tcl list element. * If length is -1, then the string is scanned up to the first * null byte. * * Results: * The return value is an overestimate of the number of characters * that will be needed by Tcl_ConvertCountedElement to produce a * valid list element from string. The word at *flagPtr is * filled in with a value needed by Tcl_ConvertCountedElement * when doing the actual conversion. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_ScanCountedElement(string, length, flagPtr) CONST char *string; /* String to convert to Tcl list element. */ int length; /* Number of bytes in string, or -1. */ int *flagPtr; /* Where to store information to guide * Tcl_ConvertElement. */ { int flags, nestingLevel; register CONST char *p, *lastChar; /* * This procedure and Tcl_ConvertElement together do two things: * * 1. They produce a proper list, one that will yield back the * argument strings when evaluated or when disassembled with * Tcl_SplitList. This is the most important thing. * * 2. They try to produce legible output, which means minimizing the * use of backslashes (using braces instead). However, there are * some situations where backslashes must be used (e.g. an element * like "{abc": the leading brace will have to be backslashed. * For each element, one of three things must be done: * * (a) Use the element as-is (it doesn't contain any special * characters). This is the most desirable option. * * (b) Enclose the element in braces, but leave the contents alone. * This happens if the element contains embedded space, or if it * contains characters with special interpretation ($, [, ;, or \), * or if it starts with a brace or double-quote, or if there are * no characters in the element. * * (c) Don't enclose the element in braces, but add backslashes to * prevent special interpretation of special characters. This is a * last resort used when the argument would normally fall under case * (b) but contains unmatched braces. It also occurs if the last * character of the argument is a backslash or if the element contains * a backslash followed by newline. * * The procedure figures out how many bytes will be needed to store * the result (actually, it overestimates). It also collects information * about the element in the form of a flags word. * * Note: list elements produced by this procedure and * Tcl_ConvertCountedElement must have the property that they can be * enclosing in curly braces to make sub-lists. This means, for * example, that we must not leave unmatched curly braces in the * resulting list element. This property is necessary in order for * procedures like Tcl_DStringStartSublist to work. */ nestingLevel = 0; flags = 0; if (string == NULL) { string = ""; } if (length == -1) { length = strlen(string); } lastChar = string + length; p = string; if ((p == lastChar) || (*p == '{') || (*p == '"')) { flags |= USE_BRACES; } for ( ; p < lastChar; p++) { switch (*p) { case '{': nestingLevel++; break; case '}': nestingLevel--; if (nestingLevel < 0) { flags |= TCL_DONT_USE_BRACES|BRACES_UNMATCHED; } break; case '[': case '$': case ';': case ' ': case '\f': case '\n': case '\r': case '\t': case '\v': flags |= USE_BRACES; break; case '\\': if ((p+1 == lastChar) || (p[1] == '\n')) { flags = TCL_DONT_USE_BRACES | BRACES_UNMATCHED; } else { int size; TclParseBackslash(p, lastChar - p, &size, NULL); p += size-1; flags |= USE_BRACES; } break; } } if (nestingLevel != 0) { flags = TCL_DONT_USE_BRACES | BRACES_UNMATCHED; } *flagPtr = flags; /* * Allow enough space to backslash every character plus leave * two spaces for braces. */ return 2*(p-string) + 2; } /* *---------------------------------------------------------------------- * * Tcl_ConvertElement -- * * This is a companion procedure to Tcl_ScanElement. Given * the information produced by Tcl_ScanElement, this procedure * converts a string to a list element equal to that string. * * Results: * Information is copied to *dst in the form of a list element * identical to src (i.e. if Tcl_SplitList is applied to dst it * will produce a string identical to src). The return value is * a count of the number of characters copied (not including the * terminating NULL character). * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_ConvertElement(src, dst, flags) register CONST char *src; /* Source information for list element. */ register char *dst; /* Place to put list-ified element. */ register int flags; /* Flags produced by Tcl_ScanElement. */ { return Tcl_ConvertCountedElement(src, -1, dst, flags); } /* *---------------------------------------------------------------------- * * Tcl_ConvertCountedElement -- * * This is a companion procedure to Tcl_ScanCountedElement. Given * the information produced by Tcl_ScanCountedElement, this * procedure converts a string to a list element equal to that * string. * * Results: * Information is copied to *dst in the form of a list element * identical to src (i.e. if Tcl_SplitList is applied to dst it * will produce a string identical to src). The return value is * a count of the number of characters copied (not including the * terminating NULL character). * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_ConvertCountedElement(src, length, dst, flags) register CONST char *src; /* Source information for list element. */ int length; /* Number of bytes in src, or -1. */ char *dst; /* Place to put list-ified element. */ int flags; /* Flags produced by Tcl_ScanElement. */ { register char *p = dst; register CONST char *lastChar; /* * See the comment block at the beginning of the Tcl_ScanElement * code for details of how this works. */ if (src && length == -1) { length = strlen(src); } if ((src == NULL) || (length == 0)) { p[0] = '{'; p[1] = '}'; p[2] = 0; return 2; } lastChar = src + length; if ((flags & USE_BRACES) && !(flags & TCL_DONT_USE_BRACES)) { *p = '{'; p++; for ( ; src != lastChar; src++, p++) { *p = *src; } *p = '}'; p++; } else { if (*src == '{') { /* * Can't have a leading brace unless the whole element is * enclosed in braces. Add a backslash before the brace. * Furthermore, this may destroy the balance between open * and close braces, so set BRACES_UNMATCHED. */ p[0] = '\\'; p[1] = '{'; p += 2; src++; flags |= BRACES_UNMATCHED; } for (; src != lastChar; src++) { switch (*src) { case ']': case '[': case '$': case ';': case ' ': case '\\': case '"': *p = '\\'; p++; break; case '{': case '}': /* * It may not seem necessary to backslash braces, but * it is. The reason for this is that the resulting * list element may actually be an element of a sub-list * enclosed in braces (e.g. if Tcl_DStringStartSublist * has been invoked), so there may be a brace mismatch * if the braces aren't backslashed. */ if (flags & BRACES_UNMATCHED) { *p = '\\'; p++; } break; case '\f': *p = '\\'; p++; *p = 'f'; p++; continue; case '\n': *p = '\\'; p++; *p = 'n'; p++; continue; case '\r': *p = '\\'; p++; *p = 'r'; p++; continue; case '\t': *p = '\\'; p++; *p = 't'; p++; continue; case '\v': *p = '\\'; p++; *p = 'v'; p++; continue; } *p = *src; p++; } } *p = '\0'; return p-dst; } /* *---------------------------------------------------------------------- * * Tcl_Merge -- * * Given a collection of strings, merge them together into a * single string that has proper Tcl list structured (i.e. * Tcl_SplitList may be used to retrieve strings equal to the * original elements, and Tcl_Eval will parse the string back * into its original elements). * * Results: * The return value is the address of a dynamically-allocated * string containing the merged list. * * Side effects: * None. * *---------------------------------------------------------------------- */ char * Tcl_Merge(argc, argv) int argc; /* How many strings to merge. */ CONST char * CONST *argv; /* Array of string values. */ { # define LOCAL_SIZE 20 int localFlags[LOCAL_SIZE], *flagPtr; int numChars; char *result; char *dst; int i; /* * Pass 1: estimate space, gather flags. */ if (argc <= LOCAL_SIZE) { flagPtr = localFlags; } else { flagPtr = (int *) ckalloc((unsigned) argc*sizeof(int)); } numChars = 1; for (i = 0; i < argc; i++) { numChars += Tcl_ScanElement(argv[i], &flagPtr[i]) + 1; } /* * Pass two: copy into the result area. */ result = (char *) ckalloc((unsigned) numChars); dst = result; for (i = 0; i < argc; i++) { numChars = Tcl_ConvertElement(argv[i], dst, flagPtr[i]); dst += numChars; *dst = ' '; dst++; } if (dst == result) { *dst = 0; } else { dst[-1] = 0; } if (flagPtr != localFlags) { ckfree((char *) flagPtr); } return result; } /* *---------------------------------------------------------------------- * * Tcl_Backslash -- * * Figure out how to handle a backslash sequence. * * Results: * The return value is the character that should be substituted * in place of the backslash sequence that starts at src. If * readPtr isn't NULL then it is filled in with a count of the * number of characters in the backslash sequence. * * Side effects: * None. * *---------------------------------------------------------------------- */ char Tcl_Backslash(src, readPtr) CONST char *src; /* Points to the backslash character of * a backslash sequence. */ int *readPtr; /* Fill in with number of characters read * from src, unless NULL. */ { char buf[TCL_UTF_MAX]; Tcl_UniChar ch; Tcl_UtfBackslash(src, readPtr, buf); TclUtfToUniChar(buf, &ch); return (char) ch; } /* *---------------------------------------------------------------------- * * Tcl_Concat -- * * Concatenate a set of strings into a single large string. * * Results: * The return value is dynamically-allocated string containing * a concatenation of all the strings in argv, with spaces between * the original argv elements. * * Side effects: * Memory is allocated for the result; the caller is responsible * for freeing the memory. * *---------------------------------------------------------------------- */ char * Tcl_Concat(argc, argv) int argc; /* Number of strings to concatenate. */ CONST char * CONST *argv; /* Array of strings to concatenate. */ { int totalSize, i; char *p; char *result; for (totalSize = 1, i = 0; i < argc; i++) { totalSize += strlen(argv[i]) + 1; } result = (char *) ckalloc((unsigned) totalSize); if (argc == 0) { *result = '\0'; return result; } for (p = result, i = 0; i < argc; i++) { CONST char *element; int length; /* * Clip white space off the front and back of the string * to generate a neater result, and ignore any empty * elements. */ element = argv[i]; while (isspace(UCHAR(*element))) { /* INTL: ISO space. */ element++; } for (length = strlen(element); (length > 0) && (isspace(UCHAR(element[length-1]))) /* INTL: ISO space. */ && ((length < 2) || (element[length-2] != '\\')); length--) { /* Null loop body. */ } if (length == 0) { continue; } memcpy((VOID *) p, (VOID *) element, (size_t) length); p += length; *p = ' '; p++; } if (p != result) { p[-1] = 0; } else { *p = 0; } return result; } /* *---------------------------------------------------------------------- * * Tcl_ConcatObj -- * * Concatenate the strings from a set of objects into a single string * object with spaces between the original strings. * * Results: * The return value is a new string object containing a concatenation * of the strings in objv. Its ref count is zero. * * Side effects: * A new object is created. * *---------------------------------------------------------------------- */ Tcl_Obj * Tcl_ConcatObj(objc, objv) int objc; /* Number of objects to concatenate. */ Tcl_Obj *CONST objv[]; /* Array of objects to concatenate. */ { int allocSize, finalSize, length, elemLength, i; char *p; char *element; char *concatStr; Tcl_Obj *objPtr; /* * Check first to see if all the items are of list type. If so, * we will concat them together as lists, and return a list object. * This is only valid when the lists have no current string * representation, since we don't know what the original type was. * An original string rep may have lost some whitespace info when * converted which could be important. */ for (i = 0; i < objc; i++) { objPtr = objv[i]; if ((objPtr->typePtr != &tclListType) || (objPtr->bytes != NULL)) { break; } } if (i == objc) { Tcl_Obj **listv; int listc; objPtr = Tcl_NewListObj(0, NULL); for (i = 0; i < objc; i++) { /* * Tcl_ListObjAppendList could be used here, but this saves * us a bit of type checking (since we've already done it) * Use of INT_MAX tells us to always put the new stuff on * the end. It will be set right in Tcl_ListObjReplace. */ Tcl_ListObjGetElements(NULL, objv[i], &listc, &listv); Tcl_ListObjReplace(NULL, objPtr, INT_MAX, 0, listc, listv); } return objPtr; } allocSize = 0; for (i = 0; i < objc; i++) { objPtr = objv[i]; element = Tcl_GetStringFromObj(objPtr, &length); if ((element != NULL) && (length > 0)) { allocSize += (length + 1); } } if (allocSize == 0) { allocSize = 1; /* enough for the NULL byte at end */ } /* * Allocate storage for the concatenated result. Note that allocSize * is one more than the total number of characters, and so includes * room for the terminating NULL byte. */ concatStr = (char *) ckalloc((unsigned) allocSize); /* * Now concatenate the elements. Clip white space off the front and back * to generate a neater result, and ignore any empty elements. Also put * a null byte at the end. */ finalSize = 0; if (objc == 0) { *concatStr = '\0'; } else { p = concatStr; for (i = 0; i < objc; i++) { objPtr = objv[i]; element = Tcl_GetStringFromObj(objPtr, &elemLength); while ((elemLength > 0) && (UCHAR(*element) < 127) && isspace(UCHAR(*element))) { /* INTL: ISO C space. */ element++; elemLength--; } /* * Trim trailing white space. But, be careful not to trim * a space character if it is preceded by a backslash: in * this case it could be significant. */ while ((elemLength > 0) && (UCHAR(element[elemLength-1]) < 127) && isspace(UCHAR(element[elemLength-1])) /* INTL: ISO C space. */ && ((elemLength < 2) || (element[elemLength-2] != '\\'))) { elemLength--; } if (elemLength == 0) { continue; /* nothing left of this element */ } memcpy((VOID *) p, (VOID *) element, (size_t) elemLength); p += elemLength; *p = ' '; p++; finalSize += (elemLength + 1); } if (p != concatStr) { p[-1] = 0; finalSize -= 1; /* we overwrote the final ' ' */ } else { *p = 0; } } TclNewObj(objPtr); objPtr->bytes = concatStr; objPtr->length = finalSize; return objPtr; } /* *---------------------------------------------------------------------- * * Tcl_StringMatch -- * * See if a particular string matches a particular pattern. * * Results: * The return value is 1 if string matches pattern, and * 0 otherwise. The matching operation permits the following * special characters in the pattern: *?\[] (see the manual * entry for details on what these mean). * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_StringMatch(string, pattern) CONST char *string; /* String. */ CONST char *pattern; /* Pattern, which may contain special * characters. */ { return Tcl_StringCaseMatch(string, pattern, 0); } /* *---------------------------------------------------------------------- * * Tcl_StringCaseMatch -- * * See if a particular string matches a particular pattern. * Allows case insensitivity. * * Results: * The return value is 1 if string matches pattern, and * 0 otherwise. The matching operation permits the following * special characters in the pattern: *?\[] (see the manual * entry for details on what these mean). * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_StringCaseMatch(string, pattern, nocase) CONST char *string; /* String. */ CONST char *pattern; /* Pattern, which may contain special * characters. */ int nocase; /* 0 for case sensitive, 1 for insensitive */ { int p, charLen; CONST char *pstart = pattern; Tcl_UniChar ch1, ch2; while (1) { p = *pattern; /* * See if we're at the end of both the pattern and the string. If * so, we succeeded. If we're at the end of the pattern but not at * the end of the string, we failed. */ if (p == '\0') { return (*string == '\0'); } if ((*string == '\0') && (p != '*')) { return 0; } /* * Check for a "*" as the next pattern character. It matches * any substring. We handle this by calling ourselves * recursively for each postfix of string, until either we * match or we reach the end of the string. */ if (p == '*') { /* * Skip all successive *'s in the pattern */ while (*(++pattern) == '*') {} p = *pattern; if (p == '\0') { return 1; } /* * This is a special case optimization for single-byte utf. */ if (UCHAR(*pattern) < 0x80) { ch2 = (Tcl_UniChar) (nocase ? tolower(UCHAR(*pattern)) : UCHAR(*pattern)); } else { Tcl_UtfToUniChar(pattern, &ch2); if (nocase) { ch2 = Tcl_UniCharToLower(ch2); } } while (1) { /* * Optimization for matching - cruise through the string * quickly if the next char in the pattern isn't a special * character */ if ((p != '[') && (p != '?') && (p != '\\')) { if (nocase) { while (*string) { charLen = TclUtfToUniChar(string, &ch1); if (ch2==ch1 || ch2==Tcl_UniCharToLower(ch1)) { break; } string += charLen; } } else { /* * There's no point in trying to make this code * shorter, as the number of bytes you want to * compare each time is non-constant. */ while (*string) { charLen = TclUtfToUniChar(string, &ch1); if (ch2 == ch1) { break; } string += charLen; } } } if (Tcl_StringCaseMatch(string, pattern, nocase)) { return 1; } if (*string == '\0') { return 0; } string += TclUtfToUniChar(string, &ch1); } } /* * Check for a "?" as the next pattern character. It matches * any single character. */ if (p == '?') { pattern++; string += TclUtfToUniChar(string, &ch1); continue; } /* * Check for a "[" as the next pattern character. It is followed * by a list of characters that are acceptable, or by a range * (two characters separated by "-"). */ if (p == '[') { Tcl_UniChar startChar, endChar; pattern++; if (UCHAR(*string) < 0x80) { ch1 = (Tcl_UniChar) (nocase ? tolower(UCHAR(*string)) : UCHAR(*string)); string++; } else { string += Tcl_UtfToUniChar(string, &ch1); if (nocase) { ch1 = Tcl_UniCharToLower(ch1); } } while (1) { if ((*pattern == ']') || (*pattern == '\0')) { return 0; } if (UCHAR(*pattern) < 0x80) { startChar = (Tcl_UniChar) (nocase ? tolower(UCHAR(*pattern)) : UCHAR(*pattern)); pattern++; } else { pattern += Tcl_UtfToUniChar(pattern, &startChar); if (nocase) { startChar = Tcl_UniCharToLower(startChar); } } if (*pattern == '-') { pattern++; if (*pattern == '\0') { return 0; } if (UCHAR(*pattern) < 0x80) { endChar = (Tcl_UniChar) (nocase ? tolower(UCHAR(*pattern)) : UCHAR(*pattern)); pattern++; } else { pattern += Tcl_UtfToUniChar(pattern, &endChar); if (nocase) { endChar = Tcl_UniCharToLower(endChar); } } if (((startChar <= ch1) && (ch1 <= endChar)) || ((endChar <= ch1) && (ch1 <= startChar))) { /* * Matches ranges of form [a-z] or [z-a]. */ break; } } else if (startChar == ch1) { break; } } while (*pattern != ']') { if (*pattern == '\0') { pattern = Tcl_UtfPrev(pattern, pstart); break; } pattern++; } pattern++; continue; } /* * If the next pattern character is '\', just strip off the '\' * so we do exact matching on the character that follows. */ if (p == '\\') { pattern++; if (*pattern == '\0') { return 0; } } /* * There's no special character. Just make sure that the next * bytes of each string match. */ string += TclUtfToUniChar(string, &ch1); pattern += TclUtfToUniChar(pattern, &ch2); if (nocase) { if (Tcl_UniCharToLower(ch1) != Tcl_UniCharToLower(ch2)) { return 0; } } else if (ch1 != ch2) { return 0; } } } /* *---------------------------------------------------------------------- * * TclMatchIsTrivial -- * * Test whether a particular glob pattern is a trivial pattern. * (i.e. where matching is the same as equality testing). * * Results: * A boolean indicating whether the pattern is free of all of the * glob special chars. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclMatchIsTrivial(pattern) CONST char *pattern; { CONST char *p = pattern; while (1) { switch (*p++) { case '\0': return 1; case '*': case '?': case '[': case '\\': return 0; } } } /* *---------------------------------------------------------------------- * * Tcl_DStringInit -- * * Initializes a dynamic string, discarding any previous contents * of the string (Tcl_DStringFree should have been called already * if the dynamic string was previously in use). * * Results: * None. * * Side effects: * The dynamic string is initialized to be empty. * *---------------------------------------------------------------------- */ void Tcl_DStringInit(dsPtr) Tcl_DString *dsPtr; /* Pointer to structure for dynamic string. */ { dsPtr->string = dsPtr->staticSpace; dsPtr->length = 0; dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE; dsPtr->staticSpace[0] = '\0'; } /* *---------------------------------------------------------------------- * * Tcl_DStringAppend -- * * Append more characters to the current value of a dynamic string. * * Results: * The return value is a pointer to the dynamic string's new value. * * Side effects: * Length bytes from string (or all of string if length is less * than zero) are added to the current value of the string. Memory * gets reallocated if needed to accomodate the string's new size. * *---------------------------------------------------------------------- */ char * Tcl_DStringAppend(dsPtr, string, length) Tcl_DString *dsPtr; /* Structure describing dynamic string. */ CONST char *string; /* String to append. If length is -1 then * this must be null-terminated. */ int length; /* Number of characters from string to * append. If < 0, then append all of string, * up to null at end. */ { int newSize; char *dst; CONST char *end; if (length < 0) { length = strlen(string); } newSize = length + dsPtr->length; /* * Allocate a larger buffer for the string if the current one isn't * large enough. Allocate extra space in the new buffer so that there * will be room to grow before we have to allocate again. */ if (newSize >= dsPtr->spaceAvl) { dsPtr->spaceAvl = newSize * 2; if (dsPtr->string == dsPtr->staticSpace) { char *newString; newString = (char *) ckalloc((unsigned) dsPtr->spaceAvl); memcpy((VOID *) newString, (VOID *) dsPtr->string, (size_t) dsPtr->length); dsPtr->string = newString; } else { dsPtr->string = (char *) ckrealloc((VOID *) dsPtr->string, (size_t) dsPtr->spaceAvl); } } /* * Copy the new string into the buffer at the end of the old * one. */ for (dst = dsPtr->string + dsPtr->length, end = string+length; string < end; string++, dst++) { *dst = *string; } *dst = '\0'; dsPtr->length += length; return dsPtr->string; } /* *---------------------------------------------------------------------- * * Tcl_DStringAppendElement -- * * Append a list element to the current value of a dynamic string. * * Results: * The return value is a pointer to the dynamic string's new value. * * Side effects: * String is reformatted as a list element and added to the current * value of the string. Memory gets reallocated if needed to * accomodate the string's new size. * *---------------------------------------------------------------------- */ char * Tcl_DStringAppendElement(dsPtr, string) Tcl_DString *dsPtr; /* Structure describing dynamic string. */ CONST char *string; /* String to append. Must be * null-terminated. */ { int newSize, flags, strSize; char *dst; strSize = ((string == NULL) ? 0 : strlen(string)); newSize = Tcl_ScanCountedElement(string, strSize, &flags) + dsPtr->length + 1; /* * Allocate a larger buffer for the string if the current one isn't * large enough. Allocate extra space in the new buffer so that there * will be room to grow before we have to allocate again. * SPECIAL NOTE: must use memcpy, not strcpy, to copy the string * to a larger buffer, since there may be embedded NULLs in the * string in some cases. */ if (newSize >= dsPtr->spaceAvl) { dsPtr->spaceAvl = newSize * 2; if (dsPtr->string == dsPtr->staticSpace) { char *newString; newString = (char *) ckalloc((unsigned) dsPtr->spaceAvl); memcpy((VOID *) newString, (VOID *) dsPtr->string, (size_t) dsPtr->length); dsPtr->string = newString; } else { dsPtr->string = (char *) ckrealloc((VOID *) dsPtr->string, (size_t) dsPtr->spaceAvl); } } /* * Convert the new string to a list element and copy it into the * buffer at the end, with a space, if needed. */ dst = dsPtr->string + dsPtr->length; if (TclNeedSpace(dsPtr->string, dst)) { *dst = ' '; dst++; dsPtr->length++; } dsPtr->length += Tcl_ConvertCountedElement(string, strSize, dst, flags); return dsPtr->string; } /* *---------------------------------------------------------------------- * * Tcl_DStringSetLength -- * * Change the length of a dynamic string. This can cause the * string to either grow or shrink, depending on the value of * length. * * Results: * None. * * Side effects: * The length of dsPtr is changed to length and a null byte is * stored at that position in the string. If length is larger * than the space allocated for dsPtr, then a panic occurs. * *---------------------------------------------------------------------- */ void Tcl_DStringSetLength(dsPtr, length) Tcl_DString *dsPtr; /* Structure describing dynamic string. */ int length; /* New length for dynamic string. */ { int newsize; if (length < 0) { length = 0; } if (length >= dsPtr->spaceAvl) { /* * There are two interesting cases here. In the first case, the user * may be trying to allocate a large buffer of a specific size. It * would be wasteful to overallocate that buffer, so we just allocate * enough for the requested size plus the trailing null byte. In the * second case, we are growing the buffer incrementally, so we need * behavior similar to Tcl_DStringAppend. The requested length will * usually be a small delta above the current spaceAvl, so we'll end up * doubling the old size. This won't grow the buffer quite as quickly, * but it should be close enough. */ newsize = dsPtr->spaceAvl * 2; if (length < newsize) { dsPtr->spaceAvl = newsize; } else { dsPtr->spaceAvl = length + 1; } if (dsPtr->string == dsPtr->staticSpace) { char *newString; newString = (char *) ckalloc((unsigned) dsPtr->spaceAvl); memcpy((VOID *) newString, (VOID *) dsPtr->string, (size_t) dsPtr->length); dsPtr->string = newString; } else { dsPtr->string = (char *) ckrealloc((VOID *) dsPtr->string, (size_t) dsPtr->spaceAvl); } } dsPtr->length = length; dsPtr->string[length] = 0; } /* *---------------------------------------------------------------------- * * Tcl_DStringFree -- * * Frees up any memory allocated for the dynamic string and * reinitializes the string to an empty state. * * Results: * None. * * Side effects: * The previous contents of the dynamic string are lost, and * the new value is an empty string. * *---------------------------------------------------------------------- */ void Tcl_DStringFree(dsPtr) Tcl_DString *dsPtr; /* Structure describing dynamic string. */ { if (dsPtr->string != dsPtr->staticSpace) { ckfree(dsPtr->string); } dsPtr->string = dsPtr->staticSpace; dsPtr->length = 0; dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE; dsPtr->staticSpace[0] = '\0'; } /* *---------------------------------------------------------------------- * * Tcl_DStringResult -- * * This procedure moves the value of a dynamic string into an * interpreter as its string result. Afterwards, the dynamic string * is reset to an empty string. * * Results: * None. * * Side effects: * The string is "moved" to interp's result, and any existing * string result for interp is freed. dsPtr is reinitialized to * an empty string. * *---------------------------------------------------------------------- */ void Tcl_DStringResult(interp, dsPtr) Tcl_Interp *interp; /* Interpreter whose result is to be reset. */ Tcl_DString *dsPtr; /* Dynamic string that is to become the * result of interp. */ { Tcl_ResetResult(interp); if (dsPtr->string != dsPtr->staticSpace) { interp->result = dsPtr->string; interp->freeProc = TCL_DYNAMIC; } else if (dsPtr->length < TCL_RESULT_SIZE) { interp->result = ((Interp *) interp)->resultSpace; strcpy(interp->result, dsPtr->string); } else { Tcl_SetResult(interp, dsPtr->string, TCL_VOLATILE); } dsPtr->string = dsPtr->staticSpace; dsPtr->length = 0; dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE; dsPtr->staticSpace[0] = '\0'; } /* *---------------------------------------------------------------------- * * Tcl_DStringGetResult -- * * This procedure moves an interpreter's result into a dynamic string. * * Results: * None. * * Side effects: * The interpreter's string result is cleared, and the previous * contents of dsPtr are freed. * * If the string result is empty, the object result is moved to the * string result, then the object result is reset. * *---------------------------------------------------------------------- */ void Tcl_DStringGetResult(interp, dsPtr) Tcl_Interp *interp; /* Interpreter whose result is to be reset. */ Tcl_DString *dsPtr; /* Dynamic string that is to become the * result of interp. */ { Interp *iPtr = (Interp *) interp; if (dsPtr->string != dsPtr->staticSpace) { ckfree(dsPtr->string); } /* * If the string result is empty, move the object result to the * string result, then reset the object result. */ if (*(iPtr->result) == 0) { Tcl_SetResult(interp, TclGetString(Tcl_GetObjResult(interp)), TCL_VOLATILE); } dsPtr->length = strlen(iPtr->result); if (iPtr->freeProc != NULL) { if (iPtr->freeProc == TCL_DYNAMIC) { dsPtr->string = iPtr->result; dsPtr->spaceAvl = dsPtr->length+1; } else { dsPtr->string = (char *) ckalloc((unsigned) (dsPtr->length+1)); strcpy(dsPtr->string, iPtr->result); (*iPtr->freeProc)(iPtr->result); } dsPtr->spaceAvl = dsPtr->length+1; iPtr->freeProc = NULL; } else { if (dsPtr->length < TCL_DSTRING_STATIC_SIZE) { dsPtr->string = dsPtr->staticSpace; dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE; } else { dsPtr->string = (char *) ckalloc((unsigned) (dsPtr->length + 1)); dsPtr->spaceAvl = dsPtr->length + 1; } strcpy(dsPtr->string, iPtr->result); } iPtr->result = iPtr->resultSpace; iPtr->resultSpace[0] = 0; } /* *---------------------------------------------------------------------- * * Tcl_DStringStartSublist -- * * This procedure adds the necessary information to a dynamic * string (e.g. " {" to start a sublist. Future element * appends will be in the sublist rather than the main list. * * Results: * None. * * Side effects: * Characters get added to the dynamic string. * *---------------------------------------------------------------------- */ void Tcl_DStringStartSublist(dsPtr) Tcl_DString *dsPtr; /* Dynamic string. */ { if (TclNeedSpace(dsPtr->string, dsPtr->string + dsPtr->length)) { Tcl_DStringAppend(dsPtr, " {", -1); } else { Tcl_DStringAppend(dsPtr, "{", -1); } } /* *---------------------------------------------------------------------- * * Tcl_DStringEndSublist -- * * This procedure adds the necessary characters to a dynamic * string to end a sublist (e.g. "}"). Future element appends * will be in the enclosing (sub)list rather than the current * sublist. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Tcl_DStringEndSublist(dsPtr) Tcl_DString *dsPtr; /* Dynamic string. */ { Tcl_DStringAppend(dsPtr, "}", -1); } /* *---------------------------------------------------------------------- * * InitPrecision -- * * Set the default value for tcl_precision to 12. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void InitPrecision(valuePtr, lengthPtr) char **valuePtr; int *lengthPtr; { *lengthPtr = 2; *valuePtr = ckalloc(3); memcpy(*valuePtr, "12", 3); } /* *---------------------------------------------------------------------- * * Tcl_PrintDouble -- * * Given a floating-point value, this procedure converts it to * an ASCII string using. * * Results: * The ASCII equivalent of "value" is written at "dst". It is * written using the current precision, and it is guaranteed to * contain a decimal point or exponent, so that it looks like * a floating-point value and not an integer. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Tcl_PrintDouble(interp, value, dst) Tcl_Interp *interp; /* Interpreter whose tcl_precision * variable used to be used to control * printing. It's ignored now. */ double value; /* Value to print as string. */ char *dst; /* Where to store converted value; * must have at least TCL_DOUBLE_SPACE * characters. */ { char *p, c; char format[10]; Tcl_UniChar ch; Tcl_Obj *precisionObj = GetPGV(&precision); sprintf(format, "%%.%sg", Tcl_GetString(precisionObj)); sprintf(dst, format, value); /* * If the ASCII result looks like an integer, add ".0" so that it * doesn't look like an integer anymore. This prevents floating-point * values from being converted to integers unintentionally. * Check for ASCII specifically to speed up the function. */ for (p = dst; *p != 0; ) { if (UCHAR(*p) < 0x80) { c = *p++; } else { p += Tcl_UtfToUniChar(p, &ch); c = UCHAR(ch); } if ((c == '.') || isalpha(UCHAR(c))) { /* INTL: ISO only. */ return; } } p[0] = '.'; p[1] = '0'; p[2] = 0; } /* *---------------------------------------------------------------------- * * TclPrecTraceProc -- * * This procedure is invoked whenever the variable "tcl_precision" * is written. * * Results: * Returns NULL if all went well, or an error message if the * new value for the variable doesn't make sense. * * Side effects: * If the new value doesn't make sense then this procedure * undoes the effect of the variable modification. Otherwise * it modifies the format string that's used by Tcl_PrintDouble. * *---------------------------------------------------------------------- */ /* ARGSUSED */ char * TclPrecTraceProc(clientData, interp, name1, name2, flags) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter containing variable. */ CONST char *name1; /* Name of variable. */ CONST char *name2; /* Second part of variable name. */ int flags; /* Information about what happened. */ { CONST char *value; char *end; int prec; /* * If the variable is unset, then recreate the trace. */ if (flags & TCL_TRACE_UNSETS) { if ((flags & TCL_TRACE_DESTROYED) && !Tcl_InterpDeleted(interp)) { Tcl_TraceVar2(interp, name1, name2, TCL_GLOBAL_ONLY|TCL_TRACE_READS|TCL_TRACE_WRITES |TCL_TRACE_UNSETS, TclPrecTraceProc, clientData); } return (char *) NULL; } /* * When the variable is read, reset its value from our shared * value. This is needed in case the variable was modified in * some other interpreter so that this interpreter's value is * out of date. */ if (flags & TCL_TRACE_READS) { Tcl_SetVar2Ex(interp, name1, name2, GetPGV(&precision), flags & TCL_GLOBAL_ONLY); return (char *) NULL; } /* * The variable is being written. Check the new value and disallow * it if it isn't reasonable or if this is a safe interpreter (we * don't want safe interpreters messing up the precision of other * interpreters). */ if (Tcl_IsSafe(interp)) { Tcl_SetVar2Ex(interp, name1, name2, GetPGV(&precision), flags & TCL_GLOBAL_ONLY); return "can't modify precision from a safe interpreter"; } value = Tcl_GetVar2(interp, name1, name2, flags & TCL_GLOBAL_ONLY); if (value == NULL) { value = ""; } prec = strtoul(value, &end, 10); if ((prec <= 0) || (prec > TCL_MAX_PREC) || (end == value) || (*end != 0)) { Tcl_SetVar2Ex(interp, name1, name2, GetPGV(&precision), flags & TCL_GLOBAL_ONLY); return "improper value for precision"; } SetPGV(&precision, Tcl_NewIntObj(prec)); return (char *) NULL; } /* *---------------------------------------------------------------------- * * TclNeedSpace -- * * This procedure checks to see whether it is appropriate to * add a space before appending a new list element to an * existing string. * * Results: * The return value is 1 if a space is appropriate, 0 otherwise. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclNeedSpace(start, end) CONST char *start; /* First character in string. */ CONST char *end; /* End of string (place where space will * be added, if appropriate). */ { /* * A space is needed unless either * (a) we're at the start of the string, or */ if (end == start) { return 0; } /* * (b) we're at the start of a nested list-element, quoted with an * open curly brace; we can be nested arbitrarily deep, so long * as the first curly brace starts an element, so backtrack over * open curly braces that are trailing characters of the string; and */ end = Tcl_UtfPrev(end, start); while (*end == '{') { if (end == start) { return 0; } end = Tcl_UtfPrev(end, start); } /* * (c) the trailing character of the string is already a list-element * separator (according to TclFindElement); that is, one of these * characters: * \u0009 \t TAB * \u000A \n NEWLINE * \u000B \v VERTICAL TAB * \u000C \f FORM FEED * \u000D \r CARRIAGE RETURN * \u0020 SPACE * with the condition that the penultimate character is not a * backslash. */ if (*end > 0x20) { /* * Performance tweak. All ASCII spaces are <= 0x20. So get * a quick answer for most characters before comparing against * all spaces in the switch below. * * NOTE: Remove this if other Unicode spaces ever get accepted * as list-element separators. */ return 1; } switch (*end) { case ' ': case '\t': case '\n': case '\r': case '\v': case '\f': if ((end == start) || (end[-1] != '\\')) { return 0; } } return 1; } /* *---------------------------------------------------------------------- * * TclFormatInt -- * * This procedure formats an integer into a sequence of decimal digit * characters in a buffer. If the integer is negative, a minus sign is * inserted at the start of the buffer. A null character is inserted at * the end of the formatted characters. It is the caller's * responsibility to ensure that enough storage is available. This * procedure has the effect of sprintf(buffer, "%d", n) but is faster. * * Results: * An integer representing the number of characters formatted, not * including the terminating \0. * * Side effects: * The formatted characters are written into the storage pointer to * by the "buffer" argument. * *---------------------------------------------------------------------- */ int TclFormatInt(buffer, n) char *buffer; /* Points to the storage into which the * formatted characters are written. */ long n; /* The integer to format. */ { long intVal; int i; int numFormatted, j; char *digits = "0123456789"; /* * Check first whether "n" is zero. */ if (n == 0) { buffer[0] = '0'; buffer[1] = 0; return 1; } /* * Check whether "n" is the maximum negative value. This is * -2^(m-1) for an m-bit word, and has no positive equivalent; * negating it produces the same value. */ intVal = -n; /* [Bug 3390638] Workaround for*/ if (n == -n || intVal == n) { /* broken compiler optimizers. */ sprintf(buffer, "%ld", n); return strlen(buffer); } /* * Generate the characters of the result backwards in the buffer. */ intVal = (n < 0? -n : n); i = 0; buffer[0] = '\0'; do { i++; buffer[i] = digits[intVal % 10]; intVal = intVal/10; } while (intVal > 0); if (n < 0) { i++; buffer[i] = '-'; } numFormatted = i; /* * Now reverse the characters. */ for (j = 0; j < i; j++, i--) { char tmp = buffer[i]; buffer[i] = buffer[j]; buffer[j] = tmp; } return numFormatted; } /* *---------------------------------------------------------------------- * * TclLooksLikeInt -- * * This procedure decides whether the leading characters of a * string look like an integer or something else (such as a * floating-point number or string). * * Results: * The return value is 1 if the leading characters of p look * like a valid Tcl integer. If they look like a floating-point * number (e.g. "e01" or "2.4"), or if they don't look like a * number at all, then 0 is returned. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclLooksLikeInt(bytes, length) register CONST char *bytes; /* Points to first byte of the string. */ int length; /* Number of bytes in the string. If < 0 * bytes up to the first null byte are * considered (if they may appear in an * integer). */ { register CONST char *p; if ((bytes == NULL) && (length > 0)) { Tcl_Panic("TclLooksLikeInt: cannot scan %d bytes from NULL", length); } if (length < 0) { length = (bytes? strlen(bytes) : 0); } p = bytes; while (length && isspace(UCHAR(*p))) { /* INTL: ISO space. */ length--; p++; } if (length == 0) { return 0; } if ((*p == '+') || (*p == '-')) { p++; length--; } return (0 != TclParseInteger(p, length)); } /* *---------------------------------------------------------------------- * * TclGetIntForIndex -- * * This procedure returns an integer corresponding to the list index * held in a Tcl object. The Tcl object's value is expected to be * either an integer or a string of the form "end([+-]integer)?". * * Results: * The return value is normally TCL_OK, which means that the index was * successfully stored into the location referenced by "indexPtr". If * the Tcl object referenced by "objPtr" has the value "end", the * value stored is "endValue". If "objPtr"s values is not of the form * "end([+-]integer)?" and * can not be converted to an integer, TCL_ERROR is returned and, if * "interp" is non-NULL, an error message is left in the interpreter's * result object. * * Side effects: * The object referenced by "objPtr" might be converted to an * integer, wide integer, or end-based-index object. * *---------------------------------------------------------------------- */ int TclGetIntForIndex(interp, objPtr, endValue, indexPtr) Tcl_Interp *interp; /* Interpreter to use for error reporting. * If NULL, then no error message is left * after errors. */ Tcl_Obj *objPtr; /* Points to an object containing either * "end" or an integer. */ int endValue; /* The value to be stored at "indexPtr" if * "objPtr" holds "end". */ int *indexPtr; /* Location filled in with an integer * representing an index. */ { if (Tcl_GetIntFromObj(NULL, objPtr, indexPtr) == TCL_OK) { return TCL_OK; } if (SetEndOffsetFromAny(NULL, objPtr) == TCL_OK) { /* * If the object is already an offset from the end of the * list, or can be converted to one, use it. */ *indexPtr = endValue + objPtr->internalRep.longValue; } else { /* * Report a parse error. */ if (interp != NULL) { char *bytes = Tcl_GetString(objPtr); /* * The result might not be empty; this resets it which * should be both a cheap operation, and of little problem * because this is an error-generation path anyway. */ Tcl_ResetResult(interp); Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "bad index \"", bytes, "\": must be integer or end?-integer?", (char *) NULL); if (!strncmp(bytes, "end-", 3)) { bytes += 3; } TclCheckBadOctal(interp, bytes); } return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * UpdateStringOfEndOffset -- * * Update the string rep of a Tcl object holding an "end-offset" * expression. * * Results: * None. * * Side effects: * Stores a valid string in the object's string rep. * * This procedure does NOT free any earlier string rep. If it is * called on an object that already has a valid string rep, it will * leak memory. * *---------------------------------------------------------------------- */ static void UpdateStringOfEndOffset(objPtr) register Tcl_Obj* objPtr; { char buffer[TCL_INTEGER_SPACE + sizeof("end") + 1]; register int len; strcpy(buffer, "end"); len = sizeof("end") - 1; if (objPtr->internalRep.longValue != 0) { buffer[len++] = '-'; len += TclFormatInt(buffer+len, -(objPtr->internalRep.longValue)); } objPtr->bytes = ckalloc((unsigned) (len+1)); strcpy(objPtr->bytes, buffer); objPtr->length = len; } /* *---------------------------------------------------------------------- * * SetEndOffsetFromAny -- * * Look for a string of the form "end-offset" and convert it * to an internal representation holding the offset. * * Results: * Returns TCL_OK if ok, TCL_ERROR if the string was badly formed. * * Side effects: * If interp is not NULL, stores an error message in the * interpreter result. * *---------------------------------------------------------------------- */ static int SetEndOffsetFromAny(interp, objPtr) Tcl_Interp* interp; /* Tcl interpreter or NULL */ Tcl_Obj* objPtr; /* Pointer to the object to parse */ { int offset; /* Offset in the "end-offset" expression */ Tcl_ObjType* oldTypePtr = objPtr->typePtr; /* Old internal rep type of the object */ register char* bytes; /* String rep of the object */ int length; /* Length of the object's string rep */ /* If it's already the right type, we're fine. */ if (objPtr->typePtr == &tclEndOffsetType) { return TCL_OK; } /* Check for a string rep of the right form. */ bytes = Tcl_GetStringFromObj(objPtr, &length); if ((*bytes != 'e') || (strncmp(bytes, "end", (size_t)((length > 3) ? 3 : length)) != 0)) { if (interp != NULL) { Tcl_ResetResult(interp); Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "bad index \"", bytes, "\": must be end?-integer?", (char*) NULL); } return TCL_ERROR; } /* Convert the string rep */ if (length <= 3) { offset = 0; } else if ((length > 4) && (bytes[3] == '-')) { /* * This is our limited string expression evaluator. Pass everything * after "end-" to Tcl_GetInt, then reverse for offset. */ if (Tcl_GetInt(interp, bytes+4, &offset) != TCL_OK) { return TCL_ERROR; } offset = -offset; } else { /* * Conversion failed. Report the error. */ if (interp != NULL) { Tcl_ResetResult(interp); Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "bad index \"", bytes, "\": must be integer or end?-integer?", (char *) NULL); } return TCL_ERROR; } /* * The conversion succeeded. Free the old internal rep and set * the new one. */ if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) { oldTypePtr->freeIntRepProc(objPtr); } objPtr->internalRep.longValue = offset; objPtr->typePtr = &tclEndOffsetType; return TCL_OK; } /* *---------------------------------------------------------------------- * * TclCheckBadOctal -- * * This procedure checks for a bad octal value and appends a * meaningful error to the interp's result. * * Results: * 1 if the argument was a bad octal, else 0. * * Side effects: * The interpreter's result is modified. * *---------------------------------------------------------------------- */ int TclCheckBadOctal(interp, value) Tcl_Interp *interp; /* Interpreter to use for error reporting. * If NULL, then no error message is left * after errors. */ CONST char *value; /* String to check. */ { register CONST char *p = value; /* * A frequent mistake is invalid octal values due to an unwanted * leading zero. Try to generate a meaningful error message. */ while (isspace(UCHAR(*p))) { /* INTL: ISO space. */ p++; } if (*p == '+' || *p == '-') { p++; } if (*p == '0') { while (isdigit(UCHAR(*p))) { /* INTL: digit. */ p++; } while (isspace(UCHAR(*p))) { /* INTL: ISO space. */ p++; } if (*p == '\0') { /* Reached end of string */ if (interp != NULL) { /* * Don't reset the result here because we want this result * to be added to an existing error message as extra info. */ Tcl_AppendResult(interp, " (looks like invalid octal number)", (char *) NULL); } return 1; } } return 0; } /* *---------------------------------------------------------------------- * * ClearHash -- * * Remove all the entries in the hash table *tablePtr. * *---------------------------------------------------------------------- */ static void ClearHash(tablePtr) Tcl_HashTable *tablePtr; { Tcl_HashSearch search; Tcl_HashEntry *hPtr; for (hPtr = Tcl_FirstHashEntry(tablePtr, &search); hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { Tcl_Obj *objPtr = (Tcl_Obj *) Tcl_GetHashValue(hPtr); Tcl_DecrRefCount(objPtr); Tcl_DeleteHashEntry(hPtr); } } /* *---------------------------------------------------------------------- * * GetThreadHash -- * * Get a thread-specific (Tcl_HashTable *) associated with a thread data * key. * * Results: * The Tcl_HashTable * corresponding to *keyPtr. * * Side effects: * The first call on a keyPtr in each thread creates a new Tcl_HashTable, * and registers a thread exit handler to dispose of it. * *---------------------------------------------------------------------- */ static Tcl_HashTable * GetThreadHash(keyPtr) Tcl_ThreadDataKey *keyPtr; { Tcl_HashTable **tablePtrPtr = (Tcl_HashTable **) Tcl_GetThreadData(keyPtr, (int) sizeof(Tcl_HashTable *)); if (NULL == *tablePtrPtr) { *tablePtrPtr = (Tcl_HashTable *)ckalloc(sizeof(Tcl_HashTable)); Tcl_CreateThreadExitHandler(FreeThreadHash, (ClientData)*tablePtrPtr); Tcl_InitHashTable(*tablePtrPtr, TCL_ONE_WORD_KEYS); } return *tablePtrPtr; } /* *---------------------------------------------------------------------- * * FreeThreadHash -- * * Thread exit handler used by GetThreadHash to dispose of a thread hash * table. * * Side effects: * Frees a Tcl_HashTable. * *---------------------------------------------------------------------- */ static void FreeThreadHash(clientData) ClientData clientData; { Tcl_HashTable *tablePtr = (Tcl_HashTable *) clientData; ClearHash(tablePtr); Tcl_DeleteHashTable(tablePtr); ckfree((char *) tablePtr); } /* *---------------------------------------------------------------------- * * FreePGV -- * * Exit handler used by (Set|Get)PGV to cleanup a PGV at exit. * *---------------------------------------------------------------------- */ static void FreePGV(clientData) ClientData clientData; { PGV *pgvPtr = (PGV *) clientData; pgvPtr->epoch++; pgvPtr->numBytes = 0; ckfree(pgvPtr->value); pgvPtr->value = NULL; Tcl_MutexFinalize(&pgvPtr->mutex); } /* *---------------------------------------------------------------------- * * SetPGV -- * * Utility routine to set a global value shared by all threads in the * process while keeping a thread-local copy as well. * *---------------------------------------------------------------------- */ static void SetPGV(pgvPtr, newValue) PGV *pgvPtr; Tcl_Obj *newValue; { CONST char *bytes; Tcl_HashTable *cacheMap; Tcl_HashEntry *hPtr; int dummy; Tcl_MutexLock(&pgvPtr->mutex); /* * Fill the global string value. */ pgvPtr->epoch++; if (NULL != pgvPtr->value) { ckfree(pgvPtr->value); } else { Tcl_CreateExitHandler(FreePGV, (ClientData) pgvPtr); } bytes = Tcl_GetStringFromObj(newValue, &pgvPtr->numBytes); pgvPtr->value = ckalloc((unsigned) pgvPtr->numBytes + 1); memcpy(pgvPtr->value, bytes, (unsigned) pgvPtr->numBytes + 1); /* * Fill the local thread copy directly with the Tcl_Obj value to avoid * loss of the intrep. Increment newValue refCount early to handle case * where we set a PGV to itself. */ Tcl_IncrRefCount(newValue); cacheMap = GetThreadHash(&pgvPtr->key); ClearHash(cacheMap); hPtr = Tcl_CreateHashEntry(cacheMap, (char *) pgvPtr->epoch, &dummy); Tcl_SetHashValue(hPtr, (ClientData) newValue); Tcl_MutexUnlock(&pgvPtr->mutex); } /* *---------------------------------------------------------------------- * * GetPGV -- * * Retrieve a global value shared among all threads of the process, * preferring a thread-local copy as long as it remains valid. * * Results: * Returns a (Tcl_Obj *) that holds a copy of the global value. * *---------------------------------------------------------------------- */ static Tcl_Obj * GetPGV(pgvPtr) PGV *pgvPtr; { Tcl_Obj *value = NULL; Tcl_HashTable *cacheMap; Tcl_HashEntry *hPtr; int epoch = pgvPtr->epoch; cacheMap = GetThreadHash(&pgvPtr->key); hPtr = Tcl_FindHashEntry(cacheMap, (char *) epoch); if (NULL == hPtr) { int dummy; /* * No cache for the current epoch - must be a new one. * * First, clear the cacheMap, as anything in it must refer to some * expired epoch. */ ClearHash(cacheMap); /* * If no thread has set the shared value, call the initializer. */ Tcl_MutexLock(&pgvPtr->mutex); if ((NULL == pgvPtr->value) && (pgvPtr->proc)) { pgvPtr->epoch++; (*(pgvPtr->proc))(&pgvPtr->value, &pgvPtr->numBytes); if (pgvPtr->value == NULL) { Tcl_Panic("PGV Initializer did not initialize"); } Tcl_CreateExitHandler(FreePGV, (ClientData) pgvPtr); } /* * Store a copy of the shared value in our epoch-indexed cache. */ value = Tcl_NewStringObj(pgvPtr->value, pgvPtr->numBytes); hPtr = Tcl_CreateHashEntry(cacheMap, (char *) pgvPtr->epoch, &dummy); Tcl_MutexUnlock(&pgvPtr->mutex); Tcl_SetHashValue(hPtr, (ClientData) value); Tcl_IncrRefCount(value); } return (Tcl_Obj *) Tcl_GetHashValue(hPtr); } /* *---------------------------------------------------------------------- * * Tcl_GetNameOfExecutable -- * * This procedure simply returns a pointer to the internal full * path name of the executable file as computed by * Tcl_FindExecutable. This procedure call is the C API * equivalent to the "info nameofexecutable" command. * * Results: * A pointer to the internal string or NULL if the internal full * path name has not been computed or unknown. * * Side effects: * The object referenced by "objPtr" might be converted to an * integer object. * *---------------------------------------------------------------------- */ CONST char * Tcl_GetNameOfExecutable() { return tclExecutableName; } /* *---------------------------------------------------------------------- * * TclpGetTime -- * * Deprecated synonym for Tcl_GetTime. * * Results: * None. * * Side effects: * Stores current time in the buffer designated by "timePtr" * * This procedure is provided for the benefit of extensions written * before Tcl_GetTime was exported from the library. * *---------------------------------------------------------------------- */ void TclpGetTime(timePtr) Tcl_Time* timePtr; { Tcl_GetTime(timePtr); } tcl8.4.20/generic/regc_lex.c0000644003604700454610000006005312052456743014271 0ustar dgp771div/* * lexical analyzer * This file is #included by regcomp.c. * * Copyright (c) 1998, 1999 Henry Spencer. All rights reserved. * * Development of this software was funded, in part, by Cray Research Inc., * UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics * Corporation, none of whom are responsible for the results. The author * thanks all of them. * * Redistribution and use in source and binary forms -- with or without * modification -- are permitted for any purpose, provided that * redistributions in source form retain this entire copyright notice and * indicate the origin and nature of any modifications. * * I'd appreciate being given credit for this package in the documentation * of software which uses it, but that is not a requirement. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * HENRY SPENCER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ /* scanning macros (know about v) */ #define ATEOS() (v->now >= v->stop) #define HAVE(n) (v->stop - v->now >= (n)) #define NEXT1(c) (!ATEOS() && *v->now == CHR(c)) #define NEXT2(a,b) (HAVE(2) && *v->now == CHR(a) && *(v->now+1) == CHR(b)) #define NEXT3(a,b,c) (HAVE(3) && *v->now == CHR(a) && \ *(v->now+1) == CHR(b) && \ *(v->now+2) == CHR(c)) #define SET(c) (v->nexttype = (c)) #define SETV(c, n) (v->nexttype = (c), v->nextvalue = (n)) #define RET(c) return (SET(c), 1) #define RETV(c, n) return (SETV(c, n), 1) #define FAILW(e) return (ERR(e), 0) /* ERR does SET(EOS) */ #define LASTTYPE(t) (v->lasttype == (t)) /* lexical contexts */ #define L_ERE 1 /* mainline ERE/ARE */ #define L_BRE 2 /* mainline BRE */ #define L_Q 3 /* REG_QUOTE */ #define L_EBND 4 /* ERE/ARE bound */ #define L_BBND 5 /* BRE bound */ #define L_BRACK 6 /* brackets */ #define L_CEL 7 /* collating element */ #define L_ECL 8 /* equivalence class */ #define L_CCL 9 /* character class */ #define INTOCON(c) (v->lexcon = (c)) #define INCON(con) (v->lexcon == (con)) /* construct pointer past end of chr array */ #define ENDOF(array) ((array) + sizeof(array)/sizeof(chr)) /* - lexstart - set up lexical stuff, scan leading options ^ static VOID lexstart(struct vars *); */ static VOID lexstart(v) struct vars *v; { prefixes(v); /* may turn on new type bits etc. */ NOERR(); if (v->cflags®_QUOTE) { assert(!(v->cflags&(REG_ADVANCED|REG_EXPANDED|REG_NEWLINE))); INTOCON(L_Q); } else if (v->cflags®_EXTENDED) { assert(!(v->cflags®_QUOTE)); INTOCON(L_ERE); } else { assert(!(v->cflags&(REG_QUOTE|REG_ADVF))); INTOCON(L_BRE); } v->nexttype = EMPTY; /* remember we were at the start */ next(v); /* set up the first token */ } /* - prefixes - implement various special prefixes ^ static VOID prefixes(struct vars *); */ static VOID prefixes(v) struct vars *v; { /* literal string doesn't get any of this stuff */ if (v->cflags®_QUOTE) return; /* initial "***" gets special things */ if (HAVE(4) && NEXT3('*', '*', '*')) switch (*(v->now + 3)) { case CHR('?'): /* "***?" error, msg shows version */ ERR(REG_BADPAT); return; /* proceed no further */ break; case CHR('='): /* "***=" shifts to literal string */ NOTE(REG_UNONPOSIX); v->cflags |= REG_QUOTE; v->cflags &= ~(REG_ADVANCED|REG_EXPANDED|REG_NEWLINE); v->now += 4; return; /* and there can be no more prefixes */ break; case CHR(':'): /* "***:" shifts to AREs */ NOTE(REG_UNONPOSIX); v->cflags |= REG_ADVANCED; v->now += 4; break; default: /* otherwise *** is just an error */ ERR(REG_BADRPT); return; break; } /* BREs and EREs don't get embedded options */ if ((v->cflags®_ADVANCED) != REG_ADVANCED) return; /* embedded options (AREs only) */ if (HAVE(3) && NEXT2('(', '?') && iscalpha(*(v->now + 2))) { NOTE(REG_UNONPOSIX); v->now += 2; for (; !ATEOS() && iscalpha(*v->now); v->now++) switch (*v->now) { case CHR('b'): /* BREs (but why???) */ v->cflags &= ~(REG_ADVANCED|REG_QUOTE); break; case CHR('c'): /* case sensitive */ v->cflags &= ~REG_ICASE; break; case CHR('e'): /* plain EREs */ v->cflags |= REG_EXTENDED; v->cflags &= ~(REG_ADVF|REG_QUOTE); break; case CHR('i'): /* case insensitive */ v->cflags |= REG_ICASE; break; case CHR('m'): /* Perloid synonym for n */ case CHR('n'): /* \n affects ^ $ . [^ */ v->cflags |= REG_NEWLINE; break; case CHR('p'): /* ~Perl, \n affects . [^ */ v->cflags |= REG_NLSTOP; v->cflags &= ~REG_NLANCH; break; case CHR('q'): /* literal string */ v->cflags |= REG_QUOTE; v->cflags &= ~REG_ADVANCED; break; case CHR('s'): /* single line, \n ordinary */ v->cflags &= ~REG_NEWLINE; break; case CHR('t'): /* tight syntax */ v->cflags &= ~REG_EXPANDED; break; case CHR('w'): /* weird, \n affects ^ $ only */ v->cflags &= ~REG_NLSTOP; v->cflags |= REG_NLANCH; break; case CHR('x'): /* expanded syntax */ v->cflags |= REG_EXPANDED; break; default: ERR(REG_BADOPT); return; } if (!NEXT1(')')) { ERR(REG_BADOPT); return; } v->now++; if (v->cflags®_QUOTE) v->cflags &= ~(REG_EXPANDED|REG_NEWLINE); } } /* - lexnest - "call a subroutine", interpolating string at the lexical level * Note, this is not a very general facility. There are a number of * implicit assumptions about what sorts of strings can be subroutines. ^ static VOID lexnest(struct vars *, chr *, chr *); */ static VOID lexnest(v, beginp, endp) struct vars *v; CONST chr *beginp; /* start of interpolation */ CONST chr *endp; /* one past end of interpolation */ { assert(v->savenow == NULL); /* only one level of nesting */ v->savenow = v->now; v->savestop = v->stop; v->now = beginp; v->stop = endp; } /* * string constants to interpolate as expansions of things like \d */ static CONST chr backd[] = { /* \d */ CHR('['), CHR('['), CHR(':'), CHR('d'), CHR('i'), CHR('g'), CHR('i'), CHR('t'), CHR(':'), CHR(']'), CHR(']') }; static CONST chr backD[] = { /* \D */ CHR('['), CHR('^'), CHR('['), CHR(':'), CHR('d'), CHR('i'), CHR('g'), CHR('i'), CHR('t'), CHR(':'), CHR(']'), CHR(']') }; static CONST chr brbackd[] = { /* \d within brackets */ CHR('['), CHR(':'), CHR('d'), CHR('i'), CHR('g'), CHR('i'), CHR('t'), CHR(':'), CHR(']') }; static CONST chr backs[] = { /* \s */ CHR('['), CHR('['), CHR(':'), CHR('s'), CHR('p'), CHR('a'), CHR('c'), CHR('e'), CHR(':'), CHR(']'), CHR(']') }; static CONST chr backS[] = { /* \S */ CHR('['), CHR('^'), CHR('['), CHR(':'), CHR('s'), CHR('p'), CHR('a'), CHR('c'), CHR('e'), CHR(':'), CHR(']'), CHR(']') }; static CONST chr brbacks[] = { /* \s within brackets */ CHR('['), CHR(':'), CHR('s'), CHR('p'), CHR('a'), CHR('c'), CHR('e'), CHR(':'), CHR(']') }; static CONST chr backw[] = { /* \w */ CHR('['), CHR('['), CHR(':'), CHR('a'), CHR('l'), CHR('n'), CHR('u'), CHR('m'), CHR(':'), CHR(']'), CHR('_'), CHR(']') }; static CONST chr backW[] = { /* \W */ CHR('['), CHR('^'), CHR('['), CHR(':'), CHR('a'), CHR('l'), CHR('n'), CHR('u'), CHR('m'), CHR(':'), CHR(']'), CHR('_'), CHR(']') }; static CONST chr brbackw[] = { /* \w within brackets */ CHR('['), CHR(':'), CHR('a'), CHR('l'), CHR('n'), CHR('u'), CHR('m'), CHR(':'), CHR(']'), CHR('_') }; /* - lexword - interpolate a bracket expression for word characters * Possibly ought to inquire whether there is a "word" character class. ^ static VOID lexword(struct vars *); */ static VOID lexword(v) struct vars *v; { lexnest(v, backw, ENDOF(backw)); } /* - next - get next token ^ static int next(struct vars *); */ static int /* 1 normal, 0 failure */ next(v) struct vars *v; { chr c; /* errors yield an infinite sequence of failures */ if (ISERR()) return 0; /* the error has set nexttype to EOS */ /* remember flavor of last token */ v->lasttype = v->nexttype; /* REG_BOSONLY */ if (v->nexttype == EMPTY && (v->cflags®_BOSONLY)) { /* at start of a REG_BOSONLY RE */ RETV(SBEGIN, 0); /* same as \A */ } /* if we're nested and we've hit end, return to outer level */ if (v->savenow != NULL && ATEOS()) { v->now = v->savenow; v->stop = v->savestop; v->savenow = v->savestop = NULL; } /* skip white space etc. if appropriate (not in literal or []) */ if (v->cflags®_EXPANDED) switch (v->lexcon) { case L_ERE: case L_BRE: case L_EBND: case L_BBND: skip(v); break; } /* handle EOS, depending on context */ if (ATEOS()) { switch (v->lexcon) { case L_ERE: case L_BRE: case L_Q: RET(EOS); break; case L_EBND: case L_BBND: FAILW(REG_EBRACE); break; case L_BRACK: case L_CEL: case L_ECL: case L_CCL: FAILW(REG_EBRACK); break; } assert(NOTREACHED); } /* okay, time to actually get a character */ c = *v->now++; /* deal with the easy contexts, punt EREs to code below */ switch (v->lexcon) { case L_BRE: /* punt BREs to separate function */ return brenext(v, c); break; case L_ERE: /* see below */ break; case L_Q: /* literal strings are easy */ RETV(PLAIN, c); break; case L_BBND: /* bounds are fairly simple */ case L_EBND: switch (c) { case CHR('0'): case CHR('1'): case CHR('2'): case CHR('3'): case CHR('4'): case CHR('5'): case CHR('6'): case CHR('7'): case CHR('8'): case CHR('9'): RETV(DIGIT, (chr)DIGITVAL(c)); break; case CHR(','): RET(','); break; case CHR('}'): /* ERE bound ends with } */ if (INCON(L_EBND)) { INTOCON(L_ERE); if ((v->cflags®_ADVF) && NEXT1('?')) { v->now++; NOTE(REG_UNONPOSIX); RETV('}', 0); } RETV('}', 1); } else FAILW(REG_BADBR); break; case CHR('\\'): /* BRE bound ends with \} */ if (INCON(L_BBND) && NEXT1('}')) { v->now++; INTOCON(L_BRE); RET('}'); } else FAILW(REG_BADBR); break; default: FAILW(REG_BADBR); break; } assert(NOTREACHED); break; case L_BRACK: /* brackets are not too hard */ switch (c) { case CHR(']'): if (LASTTYPE('[')) RETV(PLAIN, c); else { INTOCON((v->cflags®_EXTENDED) ? L_ERE : L_BRE); RET(']'); } break; case CHR('\\'): NOTE(REG_UBBS); if (!(v->cflags®_ADVF)) RETV(PLAIN, c); NOTE(REG_UNONPOSIX); if (ATEOS()) FAILW(REG_EESCAPE); (DISCARD)lexescape(v); switch (v->nexttype) { /* not all escapes okay here */ case PLAIN: return 1; break; case CCLASS: switch (v->nextvalue) { case 'd': lexnest(v, brbackd, ENDOF(brbackd)); break; case 's': lexnest(v, brbacks, ENDOF(brbacks)); break; case 'w': lexnest(v, brbackw, ENDOF(brbackw)); break; default: FAILW(REG_EESCAPE); break; } /* lexnest done, back up and try again */ v->nexttype = v->lasttype; return next(v); break; } /* not one of the acceptable escapes */ FAILW(REG_EESCAPE); break; case CHR('-'): if (LASTTYPE('[') || NEXT1(']')) RETV(PLAIN, c); else RETV(RANGE, c); break; case CHR('['): if (ATEOS()) FAILW(REG_EBRACK); switch (*v->now++) { case CHR('.'): INTOCON(L_CEL); /* might or might not be locale-specific */ RET(COLLEL); break; case CHR('='): INTOCON(L_ECL); NOTE(REG_ULOCALE); RET(ECLASS); break; case CHR(':'): INTOCON(L_CCL); NOTE(REG_ULOCALE); RET(CCLASS); break; default: /* oops */ v->now--; RETV(PLAIN, c); break; } assert(NOTREACHED); break; default: RETV(PLAIN, c); break; } assert(NOTREACHED); break; case L_CEL: /* collating elements are easy */ if (c == CHR('.') && NEXT1(']')) { v->now++; INTOCON(L_BRACK); RETV(END, '.'); } else RETV(PLAIN, c); break; case L_ECL: /* ditto equivalence classes */ if (c == CHR('=') && NEXT1(']')) { v->now++; INTOCON(L_BRACK); RETV(END, '='); } else RETV(PLAIN, c); break; case L_CCL: /* ditto character classes */ if (c == CHR(':') && NEXT1(']')) { v->now++; INTOCON(L_BRACK); RETV(END, ':'); } else RETV(PLAIN, c); break; default: assert(NOTREACHED); break; } /* that got rid of everything except EREs and AREs */ assert(INCON(L_ERE)); /* deal with EREs and AREs, except for backslashes */ switch (c) { case CHR('|'): RET('|'); break; case CHR('*'): if ((v->cflags®_ADVF) && NEXT1('?')) { v->now++; NOTE(REG_UNONPOSIX); RETV('*', 0); } RETV('*', 1); break; case CHR('+'): if ((v->cflags®_ADVF) && NEXT1('?')) { v->now++; NOTE(REG_UNONPOSIX); RETV('+', 0); } RETV('+', 1); break; case CHR('?'): if ((v->cflags®_ADVF) && NEXT1('?')) { v->now++; NOTE(REG_UNONPOSIX); RETV('?', 0); } RETV('?', 1); break; case CHR('{'): /* bounds start or plain character */ if (v->cflags®_EXPANDED) skip(v); if (ATEOS() || !iscdigit(*v->now)) { NOTE(REG_UBRACES); NOTE(REG_UUNSPEC); RETV(PLAIN, c); } else { NOTE(REG_UBOUNDS); INTOCON(L_EBND); RET('{'); } assert(NOTREACHED); break; case CHR('('): /* parenthesis, or advanced extension */ if ((v->cflags®_ADVF) && NEXT1('?')) { NOTE(REG_UNONPOSIX); v->now++; switch (*v->now++) { case CHR(':'): /* non-capturing paren */ RETV('(', 0); break; case CHR('#'): /* comment */ while (!ATEOS() && *v->now != CHR(')')) v->now++; if (!ATEOS()) v->now++; assert(v->nexttype == v->lasttype); return next(v); break; case CHR('='): /* positive lookahead */ NOTE(REG_ULOOKAHEAD); RETV(LACON, 1); break; case CHR('!'): /* negative lookahead */ NOTE(REG_ULOOKAHEAD); RETV(LACON, 0); break; default: FAILW(REG_BADRPT); break; } assert(NOTREACHED); } if (v->cflags®_NOSUB) RETV('(', 0); /* all parens non-capturing */ else RETV('(', 1); break; case CHR(')'): if (LASTTYPE('(')) { NOTE(REG_UUNSPEC); } RETV(')', c); break; case CHR('['): /* easy except for [[:<:]] and [[:>:]] */ if (HAVE(6) && *(v->now+0) == CHR('[') && *(v->now+1) == CHR(':') && (*(v->now+2) == CHR('<') || *(v->now+2) == CHR('>')) && *(v->now+3) == CHR(':') && *(v->now+4) == CHR(']') && *(v->now+5) == CHR(']')) { c = *(v->now+2); v->now += 6; NOTE(REG_UNONPOSIX); RET((c == CHR('<')) ? '<' : '>'); } INTOCON(L_BRACK); if (NEXT1('^')) { v->now++; RETV('[', 0); } RETV('[', 1); break; case CHR('.'): RET('.'); break; case CHR('^'): RET('^'); break; case CHR('$'): RET('$'); break; case CHR('\\'): /* mostly punt backslashes to code below */ if (ATEOS()) FAILW(REG_EESCAPE); break; default: /* ordinary character */ RETV(PLAIN, c); break; } /* ERE/ARE backslash handling; backslash already eaten */ assert(!ATEOS()); if (!(v->cflags®_ADVF)) { /* only AREs have non-trivial escapes */ if (iscalnum(*v->now)) { NOTE(REG_UBSALNUM); NOTE(REG_UUNSPEC); } RETV(PLAIN, *v->now++); } (DISCARD)lexescape(v); if (ISERR()) FAILW(REG_EESCAPE); if (v->nexttype == CCLASS) { /* fudge at lexical level */ switch (v->nextvalue) { case 'd': lexnest(v, backd, ENDOF(backd)); break; case 'D': lexnest(v, backD, ENDOF(backD)); break; case 's': lexnest(v, backs, ENDOF(backs)); break; case 'S': lexnest(v, backS, ENDOF(backS)); break; case 'w': lexnest(v, backw, ENDOF(backw)); break; case 'W': lexnest(v, backW, ENDOF(backW)); break; default: assert(NOTREACHED); FAILW(REG_ASSERT); break; } /* lexnest done, back up and try again */ v->nexttype = v->lasttype; return next(v); } /* otherwise, lexescape has already done the work */ return !ISERR(); } /* - lexescape - parse an ARE backslash escape (backslash already eaten) * Note slightly nonstandard use of the CCLASS type code. ^ static int lexescape(struct vars *); */ static int /* not actually used, but convenient for RETV */ lexescape(v) struct vars *v; { chr c; static CONST chr alert[] = { CHR('a'), CHR('l'), CHR('e'), CHR('r'), CHR('t') }; static CONST chr esc[] = { CHR('E'), CHR('S'), CHR('C') }; CONST chr *save; assert(v->cflags®_ADVF); assert(!ATEOS()); c = *v->now++; if (!iscalnum(c)) RETV(PLAIN, c); NOTE(REG_UNONPOSIX); switch (c) { case CHR('a'): RETV(PLAIN, chrnamed(v, alert, ENDOF(alert), CHR('\007'))); break; case CHR('A'): RETV(SBEGIN, 0); break; case CHR('b'): RETV(PLAIN, CHR('\b')); break; case CHR('B'): RETV(PLAIN, CHR('\\')); break; case CHR('c'): NOTE(REG_UUNPORT); if (ATEOS()) FAILW(REG_EESCAPE); RETV(PLAIN, (chr)(*v->now++ & 037)); break; case CHR('d'): NOTE(REG_ULOCALE); RETV(CCLASS, 'd'); break; case CHR('D'): NOTE(REG_ULOCALE); RETV(CCLASS, 'D'); break; case CHR('e'): NOTE(REG_UUNPORT); RETV(PLAIN, chrnamed(v, esc, ENDOF(esc), CHR('\033'))); break; case CHR('f'): RETV(PLAIN, CHR('\f')); break; case CHR('m'): RET('<'); break; case CHR('M'): RET('>'); break; case CHR('n'): RETV(PLAIN, CHR('\n')); break; case CHR('r'): RETV(PLAIN, CHR('\r')); break; case CHR('s'): NOTE(REG_ULOCALE); RETV(CCLASS, 's'); break; case CHR('S'): NOTE(REG_ULOCALE); RETV(CCLASS, 'S'); break; case CHR('t'): RETV(PLAIN, CHR('\t')); break; case CHR('u'): c = lexdigits(v, 16, 4, 4); if (ISERR()) FAILW(REG_EESCAPE); RETV(PLAIN, c); break; case CHR('U'): c = lexdigits(v, 16, 8, 8); if (ISERR()) FAILW(REG_EESCAPE); RETV(PLAIN, c); break; case CHR('v'): RETV(PLAIN, CHR('\v')); break; case CHR('w'): NOTE(REG_ULOCALE); RETV(CCLASS, 'w'); break; case CHR('W'): NOTE(REG_ULOCALE); RETV(CCLASS, 'W'); break; case CHR('x'): NOTE(REG_UUNPORT); c = lexdigits(v, 16, 1, 255); /* REs >255 long outside spec */ if (ISERR()) FAILW(REG_EESCAPE); RETV(PLAIN, c); break; case CHR('y'): NOTE(REG_ULOCALE); RETV(WBDRY, 0); break; case CHR('Y'): NOTE(REG_ULOCALE); RETV(NWBDRY, 0); break; case CHR('Z'): RETV(SEND, 0); break; case CHR('1'): case CHR('2'): case CHR('3'): case CHR('4'): case CHR('5'): case CHR('6'): case CHR('7'): case CHR('8'): case CHR('9'): save = v->now; v->now--; /* put first digit back */ c = lexdigits(v, 10, 1, 255); /* REs >255 long outside spec */ if (ISERR()) FAILW(REG_EESCAPE); /* ugly heuristic (first test is "exactly 1 digit?") */ if (v->now-save == 0 || ((int)c > 0 && (int)c <= v->nsubexp)) { NOTE(REG_UBACKREF); RETV(BACKREF, (chr)c); } /* oops, doesn't look like it's a backref after all... */ v->now = save; /* and fall through into octal number */ case CHR('0'): NOTE(REG_UUNPORT); v->now--; /* put first digit back */ c = lexdigits(v, 8, 1, 3); if (ISERR()) FAILW(REG_EESCAPE); RETV(PLAIN, c); break; default: assert(iscalpha(c)); FAILW(REG_EESCAPE); /* unknown alphabetic escape */ break; } assert(NOTREACHED); } /* - lexdigits - slurp up digits and return chr value ^ static chr lexdigits(struct vars *, int, int, int); */ static chr /* chr value; errors signalled via ERR */ lexdigits(v, base, minlen, maxlen) struct vars *v; int base; int minlen; int maxlen; { uchr n; /* unsigned to avoid overflow misbehavior */ int len; chr c; int d; CONST uchr ub = (uchr) base; n = 0; for (len = 0; len < maxlen && !ATEOS(); len++) { c = *v->now++; switch (c) { case CHR('0'): case CHR('1'): case CHR('2'): case CHR('3'): case CHR('4'): case CHR('5'): case CHR('6'): case CHR('7'): case CHR('8'): case CHR('9'): d = DIGITVAL(c); break; case CHR('a'): case CHR('A'): d = 10; break; case CHR('b'): case CHR('B'): d = 11; break; case CHR('c'): case CHR('C'): d = 12; break; case CHR('d'): case CHR('D'): d = 13; break; case CHR('e'): case CHR('E'): d = 14; break; case CHR('f'): case CHR('F'): d = 15; break; default: v->now--; /* oops, not a digit at all */ d = -1; break; } if (d >= base) { /* not a plausible digit */ v->now--; d = -1; } if (d < 0) break; /* NOTE BREAK OUT */ n = n*ub + (uchr)d; } if (len < minlen) ERR(REG_EESCAPE); return (chr)n; } /* - brenext - get next BRE token * This is much like EREs except for all the stupid backslashes and the * context-dependency of some things. ^ static int brenext(struct vars *, pchr); */ static int /* 1 normal, 0 failure */ brenext(v, pc) struct vars *v; pchr pc; { chr c = (chr)pc; switch (c) { case CHR('*'): if (LASTTYPE(EMPTY) || LASTTYPE('(') || LASTTYPE('^')) RETV(PLAIN, c); RET('*'); break; case CHR('['): if (HAVE(6) && *(v->now+0) == CHR('[') && *(v->now+1) == CHR(':') && (*(v->now+2) == CHR('<') || *(v->now+2) == CHR('>')) && *(v->now+3) == CHR(':') && *(v->now+4) == CHR(']') && *(v->now+5) == CHR(']')) { c = *(v->now+2); v->now += 6; NOTE(REG_UNONPOSIX); RET((c == CHR('<')) ? '<' : '>'); } INTOCON(L_BRACK); if (NEXT1('^')) { v->now++; RETV('[', 0); } RETV('[', 1); break; case CHR('.'): RET('.'); break; case CHR('^'): if (LASTTYPE(EMPTY)) RET('^'); if (LASTTYPE('(')) { NOTE(REG_UUNSPEC); RET('^'); } RETV(PLAIN, c); break; case CHR('$'): if (v->cflags®_EXPANDED) skip(v); if (ATEOS()) RET('$'); if (NEXT2('\\', ')')) { NOTE(REG_UUNSPEC); RET('$'); } RETV(PLAIN, c); break; case CHR('\\'): break; /* see below */ default: RETV(PLAIN, c); break; } assert(c == CHR('\\')); if (ATEOS()) FAILW(REG_EESCAPE); c = *v->now++; switch (c) { case CHR('{'): INTOCON(L_BBND); NOTE(REG_UBOUNDS); RET('{'); break; case CHR('('): RETV('(', 1); break; case CHR(')'): RETV(')', c); break; case CHR('<'): NOTE(REG_UNONPOSIX); RET('<'); break; case CHR('>'): NOTE(REG_UNONPOSIX); RET('>'); break; case CHR('1'): case CHR('2'): case CHR('3'): case CHR('4'): case CHR('5'): case CHR('6'): case CHR('7'): case CHR('8'): case CHR('9'): NOTE(REG_UBACKREF); RETV(BACKREF, (chr)DIGITVAL(c)); break; default: if (iscalnum(c)) { NOTE(REG_UBSALNUM); NOTE(REG_UUNSPEC); } RETV(PLAIN, c); break; } assert(NOTREACHED); } /* - skip - skip white space and comments in expanded form ^ static VOID skip(struct vars *); */ static VOID skip(v) struct vars *v; { CONST chr *start = v->now; assert(v->cflags®_EXPANDED); for (;;) { while (!ATEOS() && iscspace(*v->now)) v->now++; if (ATEOS() || *v->now != CHR('#')) break; /* NOTE BREAK OUT */ assert(NEXT1('#')); while (!ATEOS() && *v->now != CHR('\n')) v->now++; /* leave the newline to be picked up by the iscspace loop */ } if (v->now != start) NOTE(REG_UNONPOSIX); } /* - newline - return the chr for a newline * This helps confine use of CHR to this source file. ^ static chr newline(NOPARMS); */ static chr newline() { return CHR('\n'); } /* - ch - return the chr sequence for regc_locale.c's fake collating element ch * This helps confine use of CHR to this source file. Beware that the caller * knows how long the sequence is. ^ #ifdef REG_DEBUG ^ static chr *ch(NOPARMS); ^ #endif */ #ifdef REG_DEBUG static CONST chr * ch() { static CONST chr chstr[] = { CHR('c'), CHR('h'), CHR('\0') }; return chstr; } #endif /* - chrnamed - return the chr known by a given (chr string) name * The code is a bit clumsy, but this routine gets only such specialized * use that it hardly matters. ^ static chr chrnamed(struct vars *, chr *, chr *, pchr); */ static chr chrnamed(v, startp, endp, lastresort) struct vars *v; CONST chr *startp; /* start of name */ CONST chr *endp; /* just past end of name */ pchr lastresort; /* what to return if name lookup fails */ { celt c; int errsave; int e; struct cvec *cv; errsave = v->err; v->err = 0; c = element(v, startp, endp); e = v->err; v->err = errsave; if (e != 0) return (chr)lastresort; cv = range(v, c, c, 0); if (cv->nchrs == 0) return (chr)lastresort; return cv->chrs[0]; } tcl8.4.20/generic/tclIntPlatDecls.h0000644003604700454610000005052512052456744015543 0ustar dgp771div/* * tclIntPlatDecls.h -- * * This file contains the declarations for all platform dependent * unsupported functions that are exported by the Tcl library. These * interfaces are not guaranteed to remain the same between * versions. Use at your own risk. * * Copyright (c) 1998-1999 by Scriptics Corporation. * All rights reserved. */ #ifndef _TCLINTPLATDECLS #define _TCLINTPLATDECLS #ifdef __WIN32__ # define Tcl_DirEntry void # define DIR void #endif /* * WARNING: This file is automatically generated by the tools/genStubs.tcl * script. Any modifications to the function declarations below should be made * in the generic/tclInt.decls script. */ /* !BEGIN!: Do not edit below this line. */ /* * Exported function declarations: */ #if !defined(__WIN32__) && !defined(__CYGWIN__) && !defined(MAC_OSX_TCL) /* UNIX */ /* 0 */ EXTERN void TclGetAndDetachPids _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Channel chan)); /* 1 */ EXTERN int TclpCloseFile _ANSI_ARGS_((TclFile file)); /* 2 */ EXTERN Tcl_Channel TclpCreateCommandChannel _ANSI_ARGS_(( TclFile readFile, TclFile writeFile, TclFile errorFile, int numPids, Tcl_Pid *pidPtr)); /* 3 */ EXTERN int TclpCreatePipe _ANSI_ARGS_((TclFile *readPipe, TclFile *writePipe)); /* 4 */ EXTERN int TclpCreateProcess _ANSI_ARGS_((Tcl_Interp *interp, int argc, CONST char **argv, TclFile inputFile, TclFile outputFile, TclFile errorFile, Tcl_Pid *pidPtr)); /* Slot 5 is reserved */ /* 6 */ EXTERN TclFile TclpMakeFile _ANSI_ARGS_((Tcl_Channel channel, int direction)); /* 7 */ EXTERN TclFile TclpOpenFile _ANSI_ARGS_((CONST char *fname, int mode)); /* 8 */ EXTERN int TclUnixWaitForFile _ANSI_ARGS_((int fd, int mask, int timeout)); /* 9 */ EXTERN TclFile TclpCreateTempFile _ANSI_ARGS_((CONST char *contents)); /* 10 */ EXTERN Tcl_DirEntry * TclpReaddir _ANSI_ARGS_((DIR *dir)); /* 11 */ EXTERN struct tm * TclpLocaltime_unix _ANSI_ARGS_(( TclpTime_t_CONST clock)); /* 12 */ EXTERN struct tm * TclpGmtime_unix _ANSI_ARGS_((TclpTime_t_CONST clock)); /* 13 */ EXTERN char * TclpInetNtoa _ANSI_ARGS_((struct in_addr addr)); /* Slot 14 is reserved */ /* Slot 15 is reserved */ /* Slot 16 is reserved */ /* Slot 17 is reserved */ /* Slot 18 is reserved */ /* Slot 19 is reserved */ /* Slot 20 is reserved */ /* Slot 21 is reserved */ /* Slot 22 is reserved */ /* Slot 23 is reserved */ /* Slot 24 is reserved */ /* Slot 25 is reserved */ /* Slot 26 is reserved */ /* Slot 27 is reserved */ /* Slot 28 is reserved */ /* 29 */ EXTERN int TclWinCPUID _ANSI_ARGS_((unsigned int index, unsigned int *regs)); #endif /* UNIX */ #if defined(__WIN32__) || defined(__CYGWIN__) /* WIN */ /* 0 */ EXTERN void TclWinConvertError _ANSI_ARGS_((DWORD errCode)); /* 1 */ EXTERN void TclWinConvertWSAError _ANSI_ARGS_((DWORD errCode)); /* 2 */ EXTERN struct servent * TclWinGetServByName _ANSI_ARGS_((CONST char *nm, CONST char *proto)); /* 3 */ EXTERN int TclWinGetSockOpt _ANSI_ARGS_((SOCKET s, int level, int optname, char *optval, int *optlen)); /* 4 */ EXTERN HINSTANCE TclWinGetTclInstance _ANSI_ARGS_((void)); /* 5 */ EXTERN int TclUnixWaitForFile _ANSI_ARGS_((int fd, int mask, int timeout)); /* 6 */ EXTERN unsigned short TclWinNToHS _ANSI_ARGS_((unsigned short ns)); /* 7 */ EXTERN int TclWinSetSockOpt _ANSI_ARGS_((SOCKET s, int level, int optname, CONST char *optval, int optlen)); /* 8 */ EXTERN int TclpGetPid _ANSI_ARGS_((Tcl_Pid pid)); /* 9 */ EXTERN int TclWinGetPlatformId _ANSI_ARGS_((void)); /* 10 */ EXTERN Tcl_DirEntry * TclpReaddir _ANSI_ARGS_((DIR *dir)); /* 11 */ EXTERN void TclGetAndDetachPids _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Channel chan)); /* 12 */ EXTERN int TclpCloseFile _ANSI_ARGS_((TclFile file)); /* 13 */ EXTERN Tcl_Channel TclpCreateCommandChannel _ANSI_ARGS_(( TclFile readFile, TclFile writeFile, TclFile errorFile, int numPids, Tcl_Pid *pidPtr)); /* 14 */ EXTERN int TclpCreatePipe _ANSI_ARGS_((TclFile *readPipe, TclFile *writePipe)); /* 15 */ EXTERN int TclpCreateProcess _ANSI_ARGS_((Tcl_Interp *interp, int argc, CONST char **argv, TclFile inputFile, TclFile outputFile, TclFile errorFile, Tcl_Pid *pidPtr)); /* 16 */ EXTERN int TclpIsAtty _ANSI_ARGS_((int fd)); /* Slot 17 is reserved */ /* 18 */ EXTERN TclFile TclpMakeFile _ANSI_ARGS_((Tcl_Channel channel, int direction)); /* 19 */ EXTERN TclFile TclpOpenFile _ANSI_ARGS_((CONST char *fname, int mode)); /* 20 */ EXTERN void TclWinAddProcess _ANSI_ARGS_((HANDLE hProcess, DWORD id)); /* 21 */ EXTERN char * TclpInetNtoa _ANSI_ARGS_((struct in_addr addr)); /* 22 */ EXTERN TclFile TclpCreateTempFile _ANSI_ARGS_((CONST char *contents)); /* 23 */ EXTERN char * TclpGetTZName _ANSI_ARGS_((int isdst)); /* 24 */ EXTERN char * TclWinNoBackslash _ANSI_ARGS_((char *path)); /* 25 */ EXTERN TclPlatformType * TclWinGetPlatform _ANSI_ARGS_((void)); /* 26 */ EXTERN void TclWinSetInterfaces _ANSI_ARGS_((int wide)); /* 27 */ EXTERN void TclWinFlushDirtyChannels _ANSI_ARGS_((void)); /* 28 */ EXTERN void TclWinResetInterfaces _ANSI_ARGS_((void)); /* 29 */ EXTERN int TclWinCPUID _ANSI_ARGS_((unsigned int index, unsigned int *regs)); #endif /* WIN */ #ifdef MAC_OSX_TCL /* MACOSX */ /* 0 */ EXTERN void TclGetAndDetachPids _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Channel chan)); /* 1 */ EXTERN int TclpCloseFile _ANSI_ARGS_((TclFile file)); /* 2 */ EXTERN Tcl_Channel TclpCreateCommandChannel _ANSI_ARGS_(( TclFile readFile, TclFile writeFile, TclFile errorFile, int numPids, Tcl_Pid *pidPtr)); /* 3 */ EXTERN int TclpCreatePipe _ANSI_ARGS_((TclFile *readPipe, TclFile *writePipe)); /* 4 */ EXTERN int TclpCreateProcess _ANSI_ARGS_((Tcl_Interp *interp, int argc, CONST char **argv, TclFile inputFile, TclFile outputFile, TclFile errorFile, Tcl_Pid *pidPtr)); /* Slot 5 is reserved */ /* 6 */ EXTERN TclFile TclpMakeFile _ANSI_ARGS_((Tcl_Channel channel, int direction)); /* 7 */ EXTERN TclFile TclpOpenFile _ANSI_ARGS_((CONST char *fname, int mode)); /* 8 */ EXTERN int TclUnixWaitForFile _ANSI_ARGS_((int fd, int mask, int timeout)); /* 9 */ EXTERN TclFile TclpCreateTempFile _ANSI_ARGS_((CONST char *contents)); /* 10 */ EXTERN Tcl_DirEntry * TclpReaddir _ANSI_ARGS_((DIR *dir)); /* 11 */ EXTERN struct tm * TclpLocaltime_unix _ANSI_ARGS_(( TclpTime_t_CONST clock)); /* 12 */ EXTERN struct tm * TclpGmtime_unix _ANSI_ARGS_((TclpTime_t_CONST clock)); /* 13 */ EXTERN char * TclpInetNtoa _ANSI_ARGS_((struct in_addr addr)); /* Slot 14 is reserved */ /* Slot 15 is reserved */ /* Slot 16 is reserved */ /* Slot 17 is reserved */ /* Slot 18 is reserved */ /* Slot 19 is reserved */ /* Slot 20 is reserved */ /* Slot 21 is reserved */ /* Slot 22 is reserved */ /* Slot 23 is reserved */ /* Slot 24 is reserved */ /* Slot 25 is reserved */ /* Slot 26 is reserved */ /* Slot 27 is reserved */ /* Slot 28 is reserved */ /* 29 */ EXTERN int TclWinCPUID _ANSI_ARGS_((unsigned int index, unsigned int *regs)); #endif /* MACOSX */ typedef struct TclIntPlatStubs { int magic; struct TclIntPlatStubHooks *hooks; #if !defined(__WIN32__) && !defined(__CYGWIN__) && !defined(MAC_OSX_TCL) /* UNIX */ void (*tclGetAndDetachPids) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Channel chan)); /* 0 */ int (*tclpCloseFile) _ANSI_ARGS_((TclFile file)); /* 1 */ Tcl_Channel (*tclpCreateCommandChannel) _ANSI_ARGS_((TclFile readFile, TclFile writeFile, TclFile errorFile, int numPids, Tcl_Pid *pidPtr)); /* 2 */ int (*tclpCreatePipe) _ANSI_ARGS_((TclFile *readPipe, TclFile *writePipe)); /* 3 */ int (*tclpCreateProcess) _ANSI_ARGS_((Tcl_Interp *interp, int argc, CONST char **argv, TclFile inputFile, TclFile outputFile, TclFile errorFile, Tcl_Pid *pidPtr)); /* 4 */ VOID *reserved5; TclFile (*tclpMakeFile) _ANSI_ARGS_((Tcl_Channel channel, int direction)); /* 6 */ TclFile (*tclpOpenFile) _ANSI_ARGS_((CONST char *fname, int mode)); /* 7 */ int (*tclUnixWaitForFile) _ANSI_ARGS_((int fd, int mask, int timeout)); /* 8 */ TclFile (*tclpCreateTempFile) _ANSI_ARGS_((CONST char *contents)); /* 9 */ Tcl_DirEntry * (*tclpReaddir) _ANSI_ARGS_((DIR *dir)); /* 10 */ struct tm * (*tclpLocaltime_unix) _ANSI_ARGS_((TclpTime_t_CONST clock)); /* 11 */ struct tm * (*tclpGmtime_unix) _ANSI_ARGS_((TclpTime_t_CONST clock)); /* 12 */ char * (*tclpInetNtoa) _ANSI_ARGS_((struct in_addr addr)); /* 13 */ VOID *reserved14; VOID *reserved15; VOID *reserved16; VOID *reserved17; VOID *reserved18; VOID *reserved19; VOID *reserved20; VOID *reserved21; VOID *reserved22; VOID *reserved23; VOID *reserved24; VOID *reserved25; VOID *reserved26; VOID *reserved27; VOID *reserved28; int (*tclWinCPUID) _ANSI_ARGS_((unsigned int index, unsigned int *regs)); /* 29 */ #endif /* UNIX */ #if defined(__WIN32__) || defined(__CYGWIN__) /* WIN */ void (*tclWinConvertError) _ANSI_ARGS_((DWORD errCode)); /* 0 */ void (*tclWinConvertWSAError) _ANSI_ARGS_((DWORD errCode)); /* 1 */ struct servent * (*tclWinGetServByName) _ANSI_ARGS_((CONST char *nm, CONST char *proto)); /* 2 */ int (*tclWinGetSockOpt) _ANSI_ARGS_((SOCKET s, int level, int optname, char *optval, int *optlen)); /* 3 */ HINSTANCE (*tclWinGetTclInstance) _ANSI_ARGS_((void)); /* 4 */ int (*tclUnixWaitForFile) _ANSI_ARGS_((int fd, int mask, int timeout)); /* 5 */ unsigned short (*tclWinNToHS) _ANSI_ARGS_((unsigned short ns)); /* 6 */ int (*tclWinSetSockOpt) _ANSI_ARGS_((SOCKET s, int level, int optname, CONST char *optval, int optlen)); /* 7 */ int (*tclpGetPid) _ANSI_ARGS_((Tcl_Pid pid)); /* 8 */ int (*tclWinGetPlatformId) _ANSI_ARGS_((void)); /* 9 */ Tcl_DirEntry * (*tclpReaddir) _ANSI_ARGS_((DIR *dir)); /* 10 */ void (*tclGetAndDetachPids) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Channel chan)); /* 11 */ int (*tclpCloseFile) _ANSI_ARGS_((TclFile file)); /* 12 */ Tcl_Channel (*tclpCreateCommandChannel) _ANSI_ARGS_((TclFile readFile, TclFile writeFile, TclFile errorFile, int numPids, Tcl_Pid *pidPtr)); /* 13 */ int (*tclpCreatePipe) _ANSI_ARGS_((TclFile *readPipe, TclFile *writePipe)); /* 14 */ int (*tclpCreateProcess) _ANSI_ARGS_((Tcl_Interp *interp, int argc, CONST char **argv, TclFile inputFile, TclFile outputFile, TclFile errorFile, Tcl_Pid *pidPtr)); /* 15 */ int (*tclpIsAtty) _ANSI_ARGS_((int fd)); /* 16 */ VOID *reserved17; TclFile (*tclpMakeFile) _ANSI_ARGS_((Tcl_Channel channel, int direction)); /* 18 */ TclFile (*tclpOpenFile) _ANSI_ARGS_((CONST char *fname, int mode)); /* 19 */ void (*tclWinAddProcess) _ANSI_ARGS_((HANDLE hProcess, DWORD id)); /* 20 */ char * (*tclpInetNtoa) _ANSI_ARGS_((struct in_addr addr)); /* 21 */ TclFile (*tclpCreateTempFile) _ANSI_ARGS_((CONST char *contents)); /* 22 */ char * (*tclpGetTZName) _ANSI_ARGS_((int isdst)); /* 23 */ char * (*tclWinNoBackslash) _ANSI_ARGS_((char *path)); /* 24 */ TclPlatformType * (*tclWinGetPlatform) _ANSI_ARGS_((void)); /* 25 */ void (*tclWinSetInterfaces) _ANSI_ARGS_((int wide)); /* 26 */ void (*tclWinFlushDirtyChannels) _ANSI_ARGS_((void)); /* 27 */ void (*tclWinResetInterfaces) _ANSI_ARGS_((void)); /* 28 */ int (*tclWinCPUID) _ANSI_ARGS_((unsigned int index, unsigned int *regs)); /* 29 */ #endif /* WIN */ #ifdef MAC_OSX_TCL /* MACOSX */ void (*tclGetAndDetachPids) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Channel chan)); /* 0 */ int (*tclpCloseFile) _ANSI_ARGS_((TclFile file)); /* 1 */ Tcl_Channel (*tclpCreateCommandChannel) _ANSI_ARGS_((TclFile readFile, TclFile writeFile, TclFile errorFile, int numPids, Tcl_Pid *pidPtr)); /* 2 */ int (*tclpCreatePipe) _ANSI_ARGS_((TclFile *readPipe, TclFile *writePipe)); /* 3 */ int (*tclpCreateProcess) _ANSI_ARGS_((Tcl_Interp *interp, int argc, CONST char **argv, TclFile inputFile, TclFile outputFile, TclFile errorFile, Tcl_Pid *pidPtr)); /* 4 */ VOID *reserved5; TclFile (*tclpMakeFile) _ANSI_ARGS_((Tcl_Channel channel, int direction)); /* 6 */ TclFile (*tclpOpenFile) _ANSI_ARGS_((CONST char *fname, int mode)); /* 7 */ int (*tclUnixWaitForFile) _ANSI_ARGS_((int fd, int mask, int timeout)); /* 8 */ TclFile (*tclpCreateTempFile) _ANSI_ARGS_((CONST char *contents)); /* 9 */ Tcl_DirEntry * (*tclpReaddir) _ANSI_ARGS_((DIR *dir)); /* 10 */ struct tm * (*tclpLocaltime_unix) _ANSI_ARGS_((TclpTime_t_CONST clock)); /* 11 */ struct tm * (*tclpGmtime_unix) _ANSI_ARGS_((TclpTime_t_CONST clock)); /* 12 */ char * (*tclpInetNtoa) _ANSI_ARGS_((struct in_addr addr)); /* 13 */ VOID *reserved14; VOID *reserved15; VOID *reserved16; VOID *reserved17; VOID *reserved18; VOID *reserved19; VOID *reserved20; VOID *reserved21; VOID *reserved22; VOID *reserved23; VOID *reserved24; VOID *reserved25; VOID *reserved26; VOID *reserved27; VOID *reserved28; int (*tclWinCPUID) _ANSI_ARGS_((unsigned int index, unsigned int *regs)); /* 29 */ #endif /* MACOSX */ } TclIntPlatStubs; #ifdef __cplusplus extern "C" { #endif extern TclIntPlatStubs *tclIntPlatStubsPtr; #ifdef __cplusplus } #endif #if defined(USE_TCL_STUBS) && !defined(USE_TCL_STUB_PROCS) /* * Inline function declarations: */ #if !defined(__WIN32__) && !defined(__CYGWIN__) && !defined(MAC_OSX_TCL) /* UNIX */ #ifndef TclGetAndDetachPids #define TclGetAndDetachPids \ (tclIntPlatStubsPtr->tclGetAndDetachPids) /* 0 */ #endif #ifndef TclpCloseFile #define TclpCloseFile \ (tclIntPlatStubsPtr->tclpCloseFile) /* 1 */ #endif #ifndef TclpCreateCommandChannel #define TclpCreateCommandChannel \ (tclIntPlatStubsPtr->tclpCreateCommandChannel) /* 2 */ #endif #ifndef TclpCreatePipe #define TclpCreatePipe \ (tclIntPlatStubsPtr->tclpCreatePipe) /* 3 */ #endif #ifndef TclpCreateProcess #define TclpCreateProcess \ (tclIntPlatStubsPtr->tclpCreateProcess) /* 4 */ #endif /* Slot 5 is reserved */ #ifndef TclpMakeFile #define TclpMakeFile \ (tclIntPlatStubsPtr->tclpMakeFile) /* 6 */ #endif #ifndef TclpOpenFile #define TclpOpenFile \ (tclIntPlatStubsPtr->tclpOpenFile) /* 7 */ #endif #ifndef TclUnixWaitForFile #define TclUnixWaitForFile \ (tclIntPlatStubsPtr->tclUnixWaitForFile) /* 8 */ #endif #ifndef TclpCreateTempFile #define TclpCreateTempFile \ (tclIntPlatStubsPtr->tclpCreateTempFile) /* 9 */ #endif #ifndef TclpReaddir #define TclpReaddir \ (tclIntPlatStubsPtr->tclpReaddir) /* 10 */ #endif #ifndef TclpLocaltime_unix #define TclpLocaltime_unix \ (tclIntPlatStubsPtr->tclpLocaltime_unix) /* 11 */ #endif #ifndef TclpGmtime_unix #define TclpGmtime_unix \ (tclIntPlatStubsPtr->tclpGmtime_unix) /* 12 */ #endif #ifndef TclpInetNtoa #define TclpInetNtoa \ (tclIntPlatStubsPtr->tclpInetNtoa) /* 13 */ #endif /* Slot 14 is reserved */ /* Slot 15 is reserved */ /* Slot 16 is reserved */ /* Slot 17 is reserved */ /* Slot 18 is reserved */ /* Slot 19 is reserved */ /* Slot 20 is reserved */ /* Slot 21 is reserved */ /* Slot 22 is reserved */ /* Slot 23 is reserved */ /* Slot 24 is reserved */ /* Slot 25 is reserved */ /* Slot 26 is reserved */ /* Slot 27 is reserved */ /* Slot 28 is reserved */ #ifndef TclWinCPUID #define TclWinCPUID \ (tclIntPlatStubsPtr->tclWinCPUID) /* 29 */ #endif #endif /* UNIX */ #if defined(__WIN32__) || defined(__CYGWIN__) /* WIN */ #ifndef TclWinConvertError #define TclWinConvertError \ (tclIntPlatStubsPtr->tclWinConvertError) /* 0 */ #endif #ifndef TclWinConvertWSAError #define TclWinConvertWSAError \ (tclIntPlatStubsPtr->tclWinConvertWSAError) /* 1 */ #endif #ifndef TclWinGetServByName #define TclWinGetServByName \ (tclIntPlatStubsPtr->tclWinGetServByName) /* 2 */ #endif #ifndef TclWinGetSockOpt #define TclWinGetSockOpt \ (tclIntPlatStubsPtr->tclWinGetSockOpt) /* 3 */ #endif #ifndef TclWinGetTclInstance #define TclWinGetTclInstance \ (tclIntPlatStubsPtr->tclWinGetTclInstance) /* 4 */ #endif #ifndef TclUnixWaitForFile #define TclUnixWaitForFile \ (tclIntPlatStubsPtr->tclUnixWaitForFile) /* 5 */ #endif #ifndef TclWinNToHS #define TclWinNToHS \ (tclIntPlatStubsPtr->tclWinNToHS) /* 6 */ #endif #ifndef TclWinSetSockOpt #define TclWinSetSockOpt \ (tclIntPlatStubsPtr->tclWinSetSockOpt) /* 7 */ #endif #ifndef TclpGetPid #define TclpGetPid \ (tclIntPlatStubsPtr->tclpGetPid) /* 8 */ #endif #ifndef TclWinGetPlatformId #define TclWinGetPlatformId \ (tclIntPlatStubsPtr->tclWinGetPlatformId) /* 9 */ #endif #ifndef TclpReaddir #define TclpReaddir \ (tclIntPlatStubsPtr->tclpReaddir) /* 10 */ #endif #ifndef TclGetAndDetachPids #define TclGetAndDetachPids \ (tclIntPlatStubsPtr->tclGetAndDetachPids) /* 11 */ #endif #ifndef TclpCloseFile #define TclpCloseFile \ (tclIntPlatStubsPtr->tclpCloseFile) /* 12 */ #endif #ifndef TclpCreateCommandChannel #define TclpCreateCommandChannel \ (tclIntPlatStubsPtr->tclpCreateCommandChannel) /* 13 */ #endif #ifndef TclpCreatePipe #define TclpCreatePipe \ (tclIntPlatStubsPtr->tclpCreatePipe) /* 14 */ #endif #ifndef TclpCreateProcess #define TclpCreateProcess \ (tclIntPlatStubsPtr->tclpCreateProcess) /* 15 */ #endif #ifndef TclpIsAtty #define TclpIsAtty \ (tclIntPlatStubsPtr->tclpIsAtty) /* 16 */ #endif /* Slot 17 is reserved */ #ifndef TclpMakeFile #define TclpMakeFile \ (tclIntPlatStubsPtr->tclpMakeFile) /* 18 */ #endif #ifndef TclpOpenFile #define TclpOpenFile \ (tclIntPlatStubsPtr->tclpOpenFile) /* 19 */ #endif #ifndef TclWinAddProcess #define TclWinAddProcess \ (tclIntPlatStubsPtr->tclWinAddProcess) /* 20 */ #endif #ifndef TclpInetNtoa #define TclpInetNtoa \ (tclIntPlatStubsPtr->tclpInetNtoa) /* 21 */ #endif #ifndef TclpCreateTempFile #define TclpCreateTempFile \ (tclIntPlatStubsPtr->tclpCreateTempFile) /* 22 */ #endif #ifndef TclpGetTZName #define TclpGetTZName \ (tclIntPlatStubsPtr->tclpGetTZName) /* 23 */ #endif #ifndef TclWinNoBackslash #define TclWinNoBackslash \ (tclIntPlatStubsPtr->tclWinNoBackslash) /* 24 */ #endif #ifndef TclWinGetPlatform #define TclWinGetPlatform \ (tclIntPlatStubsPtr->tclWinGetPlatform) /* 25 */ #endif #ifndef TclWinSetInterfaces #define TclWinSetInterfaces \ (tclIntPlatStubsPtr->tclWinSetInterfaces) /* 26 */ #endif #ifndef TclWinFlushDirtyChannels #define TclWinFlushDirtyChannels \ (tclIntPlatStubsPtr->tclWinFlushDirtyChannels) /* 27 */ #endif #ifndef TclWinResetInterfaces #define TclWinResetInterfaces \ (tclIntPlatStubsPtr->tclWinResetInterfaces) /* 28 */ #endif #ifndef TclWinCPUID #define TclWinCPUID \ (tclIntPlatStubsPtr->tclWinCPUID) /* 29 */ #endif #endif /* WIN */ #ifdef MAC_OSX_TCL /* MACOSX */ #ifndef TclGetAndDetachPids #define TclGetAndDetachPids \ (tclIntPlatStubsPtr->tclGetAndDetachPids) /* 0 */ #endif #ifndef TclpCloseFile #define TclpCloseFile \ (tclIntPlatStubsPtr->tclpCloseFile) /* 1 */ #endif #ifndef TclpCreateCommandChannel #define TclpCreateCommandChannel \ (tclIntPlatStubsPtr->tclpCreateCommandChannel) /* 2 */ #endif #ifndef TclpCreatePipe #define TclpCreatePipe \ (tclIntPlatStubsPtr->tclpCreatePipe) /* 3 */ #endif #ifndef TclpCreateProcess #define TclpCreateProcess \ (tclIntPlatStubsPtr->tclpCreateProcess) /* 4 */ #endif /* Slot 5 is reserved */ #ifndef TclpMakeFile #define TclpMakeFile \ (tclIntPlatStubsPtr->tclpMakeFile) /* 6 */ #endif #ifndef TclpOpenFile #define TclpOpenFile \ (tclIntPlatStubsPtr->tclpOpenFile) /* 7 */ #endif #ifndef TclUnixWaitForFile #define TclUnixWaitForFile \ (tclIntPlatStubsPtr->tclUnixWaitForFile) /* 8 */ #endif #ifndef TclpCreateTempFile #define TclpCreateTempFile \ (tclIntPlatStubsPtr->tclpCreateTempFile) /* 9 */ #endif #ifndef TclpReaddir #define TclpReaddir \ (tclIntPlatStubsPtr->tclpReaddir) /* 10 */ #endif #ifndef TclpLocaltime_unix #define TclpLocaltime_unix \ (tclIntPlatStubsPtr->tclpLocaltime_unix) /* 11 */ #endif #ifndef TclpGmtime_unix #define TclpGmtime_unix \ (tclIntPlatStubsPtr->tclpGmtime_unix) /* 12 */ #endif #ifndef TclpInetNtoa #define TclpInetNtoa \ (tclIntPlatStubsPtr->tclpInetNtoa) /* 13 */ #endif /* Slot 14 is reserved */ /* Slot 15 is reserved */ /* Slot 16 is reserved */ /* Slot 17 is reserved */ /* Slot 18 is reserved */ /* Slot 19 is reserved */ /* Slot 20 is reserved */ /* Slot 21 is reserved */ /* Slot 22 is reserved */ /* Slot 23 is reserved */ /* Slot 24 is reserved */ /* Slot 25 is reserved */ /* Slot 26 is reserved */ /* Slot 27 is reserved */ /* Slot 28 is reserved */ #ifndef TclWinCPUID #define TclWinCPUID \ (tclIntPlatStubsPtr->tclWinCPUID) /* 29 */ #endif #endif /* MACOSX */ #endif /* defined(USE_TCL_STUBS) && !defined(USE_TCL_STUB_PROCS) */ /* !END!: Do not edit above this line. */ #undef TclpLocaltime_unix #undef TclpGmtime_unix #if !defined(__WIN32__) && !defined(__CYGWIN__) # undef TclpGetPid # define TclpGetPid(pid) ((unsigned long) (pid)) #endif #endif /* _TCLINTPLATDECLS */ tcl8.4.20/generic/tclCompile.h0000644003604700454610000014141512133546537014604 0ustar dgp771div/* * tclCompile.h -- * * Copyright (c) 1996-1998 Sun Microsystems, Inc. * Copyright (c) 1998-2000 by Scriptics Corporation. * Copyright (c) 2001 by Kevin B. Kenny. All rights reserved. * Copyright (c) 2007 Daniel A. Steffen * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef _TCLCOMPILATION #define _TCLCOMPILATION 1 #ifndef _TCLINT #include "tclInt.h" #endif /* _TCLINT */ #ifdef BUILD_tcl # undef TCL_STORAGE_CLASS # define TCL_STORAGE_CLASS DLLEXPORT #endif /* *------------------------------------------------------------------------ * Variables related to compilation. These are used in tclCompile.c, * tclExecute.c, tclBasic.c, and their clients. *------------------------------------------------------------------------ */ #ifdef TCL_COMPILE_DEBUG /* * Variable that controls whether compilation tracing is enabled and, if so, * what level of tracing is desired: * 0: no compilation tracing * 1: summarize compilation of top level cmds and proc bodies * 2: display all instructions of each ByteCode compiled * This variable is linked to the Tcl variable "tcl_traceCompile". */ extern int tclTraceCompile; #endif #ifdef TCL_COMPILE_DEBUG /* * Variable that controls whether execution tracing is enabled and, if so, * what level of tracing is desired: * 0: no execution tracing * 1: trace invocations of Tcl procs only * 2: trace invocations of all (not compiled away) commands * 3: display each instruction executed * This variable is linked to the Tcl variable "tcl_traceExec". */ extern int tclTraceExec; #endif /* *------------------------------------------------------------------------ * Data structures related to compilation. *------------------------------------------------------------------------ */ /* * The structure used to implement Tcl "exceptions" (exceptional returns): * for example, those generated in loops by the break and continue commands, * and those generated by scripts and caught by the catch command. This * ExceptionRange structure describes a range of code (e.g., a loop body), * the kind of exceptions (e.g., a break or continue) that might occur, and * the PC offsets to jump to if a matching exception does occur. Exception * ranges can nest so this structure includes a nesting level that is used * at runtime to find the closest exception range surrounding a PC. For * example, when a break command is executed, the ExceptionRange structure * for the most deeply nested loop, if any, is found and used. These * structures are also generated for the "next" subcommands of for loops * since a break there terminates the for command. This means a for command * actually generates two LoopInfo structures. */ typedef enum { LOOP_EXCEPTION_RANGE, /* Exception's range is part of a loop. * Break and continue "exceptions" cause * jumps to appropriate PC offsets. */ CATCH_EXCEPTION_RANGE /* Exception's range is controlled by a * catch command. Errors in the range cause * a jump to a catch PC offset. */ } ExceptionRangeType; typedef struct ExceptionRange { ExceptionRangeType type; /* The kind of ExceptionRange. */ int nestingLevel; /* Static depth of the exception range. * Used to find the most deeply-nested * range surrounding a PC at runtime. */ int codeOffset; /* Offset of the first instruction byte of * the code range. */ int numCodeBytes; /* Number of bytes in the code range. */ int breakOffset; /* If LOOP_EXCEPTION_RANGE, the target PC * offset for a break command in the range. */ int continueOffset; /* If LOOP_EXCEPTION_RANGE and not -1, the * target PC offset for a continue command in * the code range. Otherwise, ignore this range * when processing a continue command. */ int catchOffset; /* If a CATCH_EXCEPTION_RANGE, the target PC * offset for any "exception" in range. */ } ExceptionRange; /* * Structure used to map between instruction pc and source locations. It * defines for each compiled Tcl command its code's starting offset and * its source's starting offset and length. Note that the code offset * increases monotonically: that is, the table is sorted in code offset * order. The source offset is not monotonic. */ typedef struct CmdLocation { int codeOffset; /* Offset of first byte of command code. */ int numCodeBytes; /* Number of bytes for command's code. */ int srcOffset; /* Offset of first char of the command. */ int numSrcBytes; /* Number of command source chars. */ } CmdLocation; #ifdef TCL_TIP280 /* * TIP #280 * Structure to record additional location information for byte code. * This information is internal and not saved. I.e. tbcload'ed code * will not have this information. It records the lines for all words * of all commands found in the byte code. The association with a * ByteCode structure BC is done through the 'lineBCPtr' HashTable in * Interp, keyed by the address of BC. Also recorded is information * coming from the context, i.e. type of the frame and associated * information, like the path of a sourced file. */ typedef struct ECL { int srcOffset; /* cmd location to find the entry */ int nline; /* Number of words in the command */ int* line; /* line information for all words in the command */ int** next; /* Transient information during compile, ICL tracking */ } ECL; typedef struct ExtCmdLoc { int type; /* Context type */ Tcl_Obj* path; /* Path of the sourced file the command is in */ ECL* loc; /* Command word locations (lines) */ int nloc; /* Number of allocated entries in 'loc' */ int nuloc; /* Number of used entries in 'loc' */ Tcl_HashTable litInfo; /* Indexed by bytecode 'PC', to have the * information accessible per command and * argument, not per whole bytecode. Value is * index of command in 'loc', giving us the * literals to associate with line * information as command argument, see * TclArgumentBCEnter() */ } ExtCmdLoc; #endif /* * CompileProcs need the ability to record information during compilation * that can be used by bytecode instructions during execution. The AuxData * structure provides this "auxiliary data" mechanism. An arbitrary number * of these structures can be stored in the ByteCode record (during * compilation they are stored in a CompileEnv structure). Each AuxData * record holds one word of client-specified data (often a pointer) and is * given an index that instructions can later use to look up the structure * and its data. * * The following definitions declare the types of procedures that are called * to duplicate or free this auxiliary data when the containing ByteCode * objects are duplicated and freed. Pointers to these procedures are kept * in the AuxData structure. */ typedef ClientData (AuxDataDupProc) _ANSI_ARGS_((ClientData clientData)); typedef void (AuxDataFreeProc) _ANSI_ARGS_((ClientData clientData)); /* * We define a separate AuxDataType struct to hold type-related information * for the AuxData structure. This separation makes it possible for clients * outside of the TCL core to manipulate (in a limited fashion!) AuxData; * for example, it makes it possible to pickle and unpickle AuxData structs. */ typedef struct AuxDataType { char *name; /* the name of the type. Types can be * registered and found by name */ AuxDataDupProc *dupProc; /* Callback procedure to invoke when the * aux data is duplicated (e.g., when the * ByteCode structure containing the aux * data is duplicated). NULL means just * copy the source clientData bits; no * proc need be called. */ AuxDataFreeProc *freeProc; /* Callback procedure to invoke when the * aux data is freed. NULL means no * proc need be called. */ } AuxDataType; /* * The definition of the AuxData structure that holds information created * during compilation by CompileProcs and used by instructions during * execution. */ typedef struct AuxData { AuxDataType *type; /* pointer to the AuxData type associated with * this ClientData. */ ClientData clientData; /* The compilation data itself. */ } AuxData; /* * Structure defining the compilation environment. After compilation, fields * describing bytecode instructions are copied out into the more compact * ByteCode structure defined below. */ #define COMPILEENV_INIT_CODE_BYTES 250 #define COMPILEENV_INIT_NUM_OBJECTS 60 #define COMPILEENV_INIT_EXCEPT_RANGES 5 #define COMPILEENV_INIT_CMD_MAP_SIZE 40 #define COMPILEENV_INIT_AUX_DATA_SIZE 5 typedef struct CompileEnv { Interp *iPtr; /* Interpreter containing the code being * compiled. Commands and their compile * procs are specific to an interpreter so * the code emitted will depend on the * interpreter. */ char *source; /* The source string being compiled by * SetByteCodeFromAny. This pointer is not * owned by the CompileEnv and must not be * freed or changed by it. */ int numSrcBytes; /* Number of bytes in source. */ Proc *procPtr; /* If a procedure is being compiled, a * pointer to its Proc structure; otherwise * NULL. Used to compile local variables. * Set from information provided by * ObjInterpProc in tclProc.c. */ int numCommands; /* Number of commands compiled. */ int exceptDepth; /* Current exception range nesting level; * -1 if not in any range currently. */ int maxExceptDepth; /* Max nesting level of exception ranges; * -1 if no ranges have been compiled. */ int maxStackDepth; /* Maximum number of stack elements needed * to execute the code. Set by compilation * procedures before returning. */ int currStackDepth; /* Current stack depth. */ LiteralTable localLitTable; /* Contains LiteralEntry's describing * all Tcl objects referenced by this * compiled code. Indexed by the string * representations of the literals. Used to * avoid creating duplicate objects. */ unsigned char *codeStart; /* Points to the first byte of the code. */ unsigned char *codeNext; /* Points to next code array byte to use. */ unsigned char *codeEnd; /* Points just after the last allocated * code array byte. */ int mallocedCodeArray; /* Set 1 if code array was expanded * and codeStart points into the heap.*/ LiteralEntry *literalArrayPtr; /* Points to start of LiteralEntry array. */ int literalArrayNext; /* Index of next free object array entry. */ int literalArrayEnd; /* Index just after last obj array entry. */ int mallocedLiteralArray; /* 1 if object array was expanded and * objArray points into the heap, else 0. */ ExceptionRange *exceptArrayPtr; /* Points to start of the ExceptionRange * array. */ int exceptArrayNext; /* Next free ExceptionRange array index. * exceptArrayNext is the number of ranges * and (exceptArrayNext-1) is the index of * the current range's array entry. */ int exceptArrayEnd; /* Index after the last ExceptionRange * array entry. */ int mallocedExceptArray; /* 1 if ExceptionRange array was expanded * and exceptArrayPtr points in heap, * else 0. */ CmdLocation *cmdMapPtr; /* Points to start of CmdLocation array. * numCommands is the index of the next * entry to use; (numCommands-1) is the * entry index for the last command. */ int cmdMapEnd; /* Index after last CmdLocation entry. */ int mallocedCmdMap; /* 1 if command map array was expanded and * cmdMapPtr points in the heap, else 0. */ AuxData *auxDataArrayPtr; /* Points to auxiliary data array start. */ int auxDataArrayNext; /* Next free compile aux data array index. * auxDataArrayNext is the number of aux * data items and (auxDataArrayNext-1) is * index of current aux data array entry. */ int auxDataArrayEnd; /* Index after last aux data array entry. */ int mallocedAuxDataArray; /* 1 if aux data array was expanded and * auxDataArrayPtr points in heap else 0. */ unsigned char staticCodeSpace[COMPILEENV_INIT_CODE_BYTES]; /* Initial storage for code. */ LiteralEntry staticLiteralSpace[COMPILEENV_INIT_NUM_OBJECTS]; /* Initial storage of LiteralEntry array. */ ExceptionRange staticExceptArraySpace[COMPILEENV_INIT_EXCEPT_RANGES]; /* Initial ExceptionRange array storage. */ CmdLocation staticCmdMapSpace[COMPILEENV_INIT_CMD_MAP_SIZE]; /* Initial storage for cmd location map. */ AuxData staticAuxDataArraySpace[COMPILEENV_INIT_AUX_DATA_SIZE]; /* Initial storage for aux data array. */ #ifdef TCL_TIP280 /* TIP #280 */ ExtCmdLoc* extCmdMapPtr; /* Extended command location information * for 'info frame'. */ int line; /* First line of the script, based on the * invoking context, then the line of the * command currently compiled. */ ContLineLoc* clLoc; /* If not NULL, the table holding the * locations of the invisible continuation * lines in the input script, to adjust the * line counter. */ int* clNext; /* If not NULL, it refers to the next slot in * clLoc to check for an invisible * continuation line. */ #endif } CompileEnv; /* * The structure defining the bytecode instructions resulting from compiling * a Tcl script. Note that this structure is variable length: a single heap * object is allocated to hold the ByteCode structure immediately followed * by the code bytes, the literal object array, the ExceptionRange array, * the CmdLocation map, and the compilation AuxData array. */ /* * A PRECOMPILED bytecode struct is one that was generated from a compiled * image rather than implicitly compiled from source */ #define TCL_BYTECODE_PRECOMPILED 0x0001 typedef struct ByteCode { TclHandle interpHandle; /* Handle for interpreter containing the * compiled code. Commands and their compile * procs are specific to an interpreter so the * code emitted will depend on the * interpreter. */ int compileEpoch; /* Value of iPtr->compileEpoch when this * ByteCode was compiled. Used to invalidate * code when, e.g., commands with compile * procs are redefined. */ Namespace *nsPtr; /* Namespace context in which this code * was compiled. If the code is executed * if a different namespace, it must be * recompiled. */ int nsEpoch; /* Value of nsPtr->resolverEpoch when this * ByteCode was compiled. Used to invalidate * code when new namespace resolution rules * are put into effect. */ int refCount; /* Reference count: set 1 when created * plus 1 for each execution of the code * currently active. This structure can be * freed when refCount becomes zero. */ unsigned int flags; /* flags describing state for the codebyte. * this variable holds ORed values from the * TCL_BYTECODE_ masks defined above */ char *source; /* The source string from which this * ByteCode was compiled. Note that this * pointer is not owned by the ByteCode and * must not be freed or modified by it. */ Proc *procPtr; /* If the ByteCode was compiled from a * procedure body, this is a pointer to its * Proc structure; otherwise NULL. This * pointer is also not owned by the ByteCode * and must not be freed by it. */ size_t structureSize; /* Number of bytes in the ByteCode structure * itself. Does not include heap space for * literal Tcl objects or storage referenced * by AuxData entries. */ int numCommands; /* Number of commands compiled. */ int numSrcBytes; /* Number of source bytes compiled. */ int numCodeBytes; /* Number of code bytes. */ int numLitObjects; /* Number of objects in literal array. */ int numExceptRanges; /* Number of ExceptionRange array elems. */ int numAuxDataItems; /* Number of AuxData items. */ int numCmdLocBytes; /* Number of bytes needed for encoded * command location information. */ int maxExceptDepth; /* Maximum nesting level of ExceptionRanges; * -1 if no ranges were compiled. */ int maxStackDepth; /* Maximum number of stack elements needed * to execute the code. */ unsigned char *codeStart; /* Points to the first byte of the code. * This is just after the final ByteCode * member cmdMapPtr. */ Tcl_Obj **objArrayPtr; /* Points to the start of the literal * object array. This is just after the * last code byte. */ ExceptionRange *exceptArrayPtr; /* Points to the start of the ExceptionRange * array. This is just after the last * object in the object array. */ AuxData *auxDataArrayPtr; /* Points to the start of the auxiliary data * array. This is just after the last entry * in the ExceptionRange array. */ unsigned char *codeDeltaStart; /* Points to the first of a sequence of * bytes that encode the change in the * starting offset of each command's code. * If -127<=delta<=127, it is encoded as 1 * byte, otherwise 0xFF (128) appears and * the delta is encoded by the next 4 bytes. * Code deltas are always positive. This * sequence is just after the last entry in * the AuxData array. */ unsigned char *codeLengthStart; /* Points to the first of a sequence of * bytes that encode the length of each * command's code. The encoding is the same * as for code deltas. Code lengths are * always positive. This sequence is just * after the last entry in the code delta * sequence. */ unsigned char *srcDeltaStart; /* Points to the first of a sequence of * bytes that encode the change in the * starting offset of each command's source. * The encoding is the same as for code * deltas. Source deltas can be negative. * This sequence is just after the last byte * in the code length sequence. */ unsigned char *srcLengthStart; /* Points to the first of a sequence of * bytes that encode the length of each * command's source. The encoding is the * same as for code deltas. Source lengths * are always positive. This sequence is * just after the last byte in the source * delta sequence. */ #ifdef TCL_COMPILE_STATS Tcl_Time createTime; /* Absolute time when the ByteCode was * created. */ #endif /* TCL_COMPILE_STATS */ } ByteCode; /* * Opcodes for the Tcl bytecode instructions. These must correspond to * the entries in the table of instruction descriptions, * tclInstructionTable, in tclCompile.c. Also, the order and number of * the expression opcodes (e.g., INST_LOR) must match the entries in * the array operatorStrings in tclExecute.c. */ /* Opcodes 0 to 9 */ #define INST_DONE 0 #define INST_PUSH1 1 #define INST_PUSH4 2 #define INST_POP 3 #define INST_DUP 4 #define INST_CONCAT1 5 #define INST_INVOKE_STK1 6 #define INST_INVOKE_STK4 7 #define INST_EVAL_STK 8 #define INST_EXPR_STK 9 /* Opcodes 10 to 23 */ #define INST_LOAD_SCALAR1 10 #define INST_LOAD_SCALAR4 11 #define INST_LOAD_SCALAR_STK 12 #define INST_LOAD_ARRAY1 13 #define INST_LOAD_ARRAY4 14 #define INST_LOAD_ARRAY_STK 15 #define INST_LOAD_STK 16 #define INST_STORE_SCALAR1 17 #define INST_STORE_SCALAR4 18 #define INST_STORE_SCALAR_STK 19 #define INST_STORE_ARRAY1 20 #define INST_STORE_ARRAY4 21 #define INST_STORE_ARRAY_STK 22 #define INST_STORE_STK 23 /* Opcodes 24 to 33 */ #define INST_INCR_SCALAR1 24 #define INST_INCR_SCALAR_STK 25 #define INST_INCR_ARRAY1 26 #define INST_INCR_ARRAY_STK 27 #define INST_INCR_STK 28 #define INST_INCR_SCALAR1_IMM 29 #define INST_INCR_SCALAR_STK_IMM 30 #define INST_INCR_ARRAY1_IMM 31 #define INST_INCR_ARRAY_STK_IMM 32 #define INST_INCR_STK_IMM 33 /* Opcodes 34 to 39 */ #define INST_JUMP1 34 #define INST_JUMP4 35 #define INST_JUMP_TRUE1 36 #define INST_JUMP_TRUE4 37 #define INST_JUMP_FALSE1 38 #define INST_JUMP_FALSE4 39 /* Opcodes 40 to 64 */ #define INST_LOR 40 #define INST_LAND 41 #define INST_BITOR 42 #define INST_BITXOR 43 #define INST_BITAND 44 #define INST_EQ 45 #define INST_NEQ 46 #define INST_LT 47 #define INST_GT 48 #define INST_LE 49 #define INST_GE 50 #define INST_LSHIFT 51 #define INST_RSHIFT 52 #define INST_ADD 53 #define INST_SUB 54 #define INST_MULT 55 #define INST_DIV 56 #define INST_MOD 57 #define INST_UPLUS 58 #define INST_UMINUS 59 #define INST_BITNOT 60 #define INST_LNOT 61 #define INST_CALL_BUILTIN_FUNC1 62 #define INST_CALL_FUNC1 63 #define INST_TRY_CVT_TO_NUMERIC 64 /* Opcodes 65 to 66 */ #define INST_BREAK 65 #define INST_CONTINUE 66 /* Opcodes 67 to 68 */ #define INST_FOREACH_START4 67 #define INST_FOREACH_STEP4 68 /* Opcodes 69 to 72 */ #define INST_BEGIN_CATCH4 69 #define INST_END_CATCH 70 #define INST_PUSH_RESULT 71 #define INST_PUSH_RETURN_CODE 72 /* Opcodes 73 to 78 */ #define INST_STR_EQ 73 #define INST_STR_NEQ 74 #define INST_STR_CMP 75 #define INST_STR_LEN 76 #define INST_STR_INDEX 77 #define INST_STR_MATCH 78 /* Opcodes 78 to 81 */ #define INST_LIST 79 #define INST_LIST_INDEX 80 #define INST_LIST_LENGTH 81 /* Opcodes 82 to 87 */ #define INST_APPEND_SCALAR1 82 #define INST_APPEND_SCALAR4 83 #define INST_APPEND_ARRAY1 84 #define INST_APPEND_ARRAY4 85 #define INST_APPEND_ARRAY_STK 86 #define INST_APPEND_STK 87 /* Opcodes 88 to 93 */ #define INST_LAPPEND_SCALAR1 88 #define INST_LAPPEND_SCALAR4 89 #define INST_LAPPEND_ARRAY1 90 #define INST_LAPPEND_ARRAY4 91 #define INST_LAPPEND_ARRAY_STK 92 #define INST_LAPPEND_STK 93 /* TIP #22 - LINDEX operator with flat arg list */ #define INST_LIST_INDEX_MULTI 94 /* * TIP #33 - 'lset' command. Code gen also required a Forth-like * OVER operation. */ #define INST_OVER 95 #define INST_LSET_LIST 96 #define INST_LSET_FLAT 97 /* The last opcode */ #define LAST_INST_OPCODE 97 /* * Table describing the Tcl bytecode instructions: their name (for * displaying code), total number of code bytes required (including * operand bytes), and a description of the type of each operand. * These operand types include signed and unsigned integers of length * one and four bytes. The unsigned integers are used for indexes or * for, e.g., the count of objects to push in a "push" instruction. */ #define MAX_INSTRUCTION_OPERANDS 2 typedef enum InstOperandType { OPERAND_NONE, OPERAND_INT1, /* One byte signed integer. */ OPERAND_INT4, /* Four byte signed integer. */ OPERAND_UINT1, /* One byte unsigned integer. */ OPERAND_UINT4 /* Four byte unsigned integer. */ } InstOperandType; typedef struct InstructionDesc { char *name; /* Name of instruction. */ int numBytes; /* Total number of bytes for instruction. */ int stackEffect; /* The worst-case balance stack effect of the * instruction, used for stack requirements * computations. The value INT_MIN signals * that the instruction's worst case effect * is (1-opnd1). */ int numOperands; /* Number of operands. */ InstOperandType opTypes[MAX_INSTRUCTION_OPERANDS]; /* The type of each operand. */ } InstructionDesc; extern InstructionDesc tclInstructionTable[]; /* * Definitions of the values of the INST_CALL_BUILTIN_FUNC instruction's * operand byte. Each value denotes a builtin Tcl math function. These * values must correspond to the entries in the tclBuiltinFuncTable array * below and to the values stored in the tclInt.h MathFunc structure's * builtinFuncIndex field. */ #define BUILTIN_FUNC_ACOS 0 #define BUILTIN_FUNC_ASIN 1 #define BUILTIN_FUNC_ATAN 2 #define BUILTIN_FUNC_ATAN2 3 #define BUILTIN_FUNC_CEIL 4 #define BUILTIN_FUNC_COS 5 #define BUILTIN_FUNC_COSH 6 #define BUILTIN_FUNC_EXP 7 #define BUILTIN_FUNC_FLOOR 8 #define BUILTIN_FUNC_FMOD 9 #define BUILTIN_FUNC_HYPOT 10 #define BUILTIN_FUNC_LOG 11 #define BUILTIN_FUNC_LOG10 12 #define BUILTIN_FUNC_POW 13 #define BUILTIN_FUNC_SIN 14 #define BUILTIN_FUNC_SINH 15 #define BUILTIN_FUNC_SQRT 16 #define BUILTIN_FUNC_TAN 17 #define BUILTIN_FUNC_TANH 18 #define BUILTIN_FUNC_ABS 19 #define BUILTIN_FUNC_DOUBLE 20 #define BUILTIN_FUNC_INT 21 #define BUILTIN_FUNC_RAND 22 #define BUILTIN_FUNC_ROUND 23 #define BUILTIN_FUNC_SRAND 24 #define BUILTIN_FUNC_WIDE 25 #define LAST_BUILTIN_FUNC 25 /* * Table describing the built-in math functions. Entries in this table are * indexed by the values of the INST_CALL_BUILTIN_FUNC instruction's * operand byte. */ typedef int (CallBuiltinFuncProc) _ANSI_ARGS_((Tcl_Interp *interp, ExecEnv *eePtr, ClientData clientData)); typedef struct { char *name; /* Name of function. */ int numArgs; /* Number of arguments for function. */ Tcl_ValueType argTypes[MAX_MATH_ARGS]; /* Acceptable types for each argument. */ CallBuiltinFuncProc *proc; /* Procedure implementing this function. */ ClientData clientData; /* Additional argument to pass to the * function when invoking it. */ } BuiltinFunc; extern BuiltinFunc tclBuiltinFuncTable[]; /* * Compilation of some Tcl constructs such as if commands and the logical or * (||) and logical and (&&) operators in expressions requires the * generation of forward jumps. Since the PC target of these jumps isn't * known when the jumps are emitted, we record the offset of each jump in an * array of JumpFixup structures. There is one array for each sequence of * jumps to one target PC. When we learn the target PC, we update the jumps * with the correct distance. Also, if the distance is too great (> 127 * bytes), we replace the single-byte jump with a four byte jump * instruction, move the instructions after the jump down, and update the * code offsets for any commands between the jump and the target. */ typedef enum { TCL_UNCONDITIONAL_JUMP, TCL_TRUE_JUMP, TCL_FALSE_JUMP } TclJumpType; typedef struct JumpFixup { TclJumpType jumpType; /* Indicates the kind of jump. */ int codeOffset; /* Offset of the first byte of the one-byte * forward jump's code. */ int cmdIndex; /* Index of the first command after the one * for which the jump was emitted. Used to * update the code offsets for subsequent * commands if the two-byte jump at jumpPc * must be replaced with a five-byte one. */ int exceptIndex; /* Index of the first range entry in the * ExceptionRange array after the current * one. This field is used to adjust the * code offsets in subsequent ExceptionRange * records when a jump is grown from 2 bytes * to 5 bytes. */ } JumpFixup; #define JUMPFIXUP_INIT_ENTRIES 10 typedef struct JumpFixupArray { JumpFixup *fixup; /* Points to start of jump fixup array. */ int next; /* Index of next free array entry. */ int end; /* Index of last usable entry in array. */ int mallocedArray; /* 1 if array was expanded and fixups points * into the heap, else 0. */ JumpFixup staticFixupSpace[JUMPFIXUP_INIT_ENTRIES]; /* Initial storage for jump fixup array. */ } JumpFixupArray; /* * The structure describing one variable list of a foreach command. Note * that only foreach commands inside procedure bodies are compiled inline so * a ForeachVarList structure always describes local variables. Furthermore, * only scalar variables are supported for inline-compiled foreach loops. */ typedef struct ForeachVarList { int numVars; /* The number of variables in the list. */ int varIndexes[1]; /* An array of the indexes ("slot numbers") * for each variable in the procedure's * array of local variables. Only scalar * variables are supported. The actual * size of this field will be large enough * to numVars indexes. THIS MUST BE THE * LAST FIELD IN THE STRUCTURE! */ } ForeachVarList; /* * Structure used to hold information about a foreach command that is needed * during program execution. These structures are stored in CompileEnv and * ByteCode structures as auxiliary data. */ typedef struct ForeachInfo { int numLists; /* The number of both the variable and value * lists of the foreach command. */ int firstValueTemp; /* Index of the first temp var in a proc * frame used to point to a value list. */ int loopCtTemp; /* Index of temp var in a proc frame * holding the loop's iteration count. Used * to determine next value list element to * assign each loop var. */ ForeachVarList *varLists[1];/* An array of pointers to ForeachVarList * structures describing each var list. The * actual size of this field will be large * enough to numVars indexes. THIS MUST BE * THE LAST FIELD IN THE STRUCTURE! */ } ForeachInfo; extern AuxDataType tclForeachInfoType; /* *---------------------------------------------------------------- * Procedures exported by tclBasic.c to be used within the engine. *---------------------------------------------------------------- */ EXTERN int TclEvalObjvInternal _ANSI_ARGS_((Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], CONST char *command, int length, int flags)); EXTERN int TclInterpReady _ANSI_ARGS_((Tcl_Interp *interp)); /* *---------------------------------------------------------------- * Procedures exported by the engine to be used by tclBasic.c *---------------------------------------------------------------- */ #ifndef TCL_TIP280 EXTERN int TclCompEvalObj _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr)); #else EXTERN int TclCompEvalObj _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr, CONST CmdFrame* invoker, int word)); #endif /* *---------------------------------------------------------------- * Procedures shared among Tcl bytecode compilation and execution * modules but not used outside: *---------------------------------------------------------------- */ EXTERN void TclCleanupByteCode _ANSI_ARGS_((ByteCode *codePtr)); EXTERN int TclCompileCmdWord _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Token *tokenPtr, int count, CompileEnv *envPtr)); EXTERN int TclCompileExpr _ANSI_ARGS_((Tcl_Interp *interp, CONST char *script, int numBytes, CompileEnv *envPtr)); EXTERN int TclCompileExprWords _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Token *tokenPtr, int numWords, CompileEnv *envPtr)); EXTERN int TclCompileScript _ANSI_ARGS_((Tcl_Interp *interp, CONST char *script, int numBytes, int nested, CompileEnv *envPtr)); EXTERN int TclCompileTokens _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Token *tokenPtr, int count, CompileEnv *envPtr)); EXTERN int TclCreateAuxData _ANSI_ARGS_((ClientData clientData, AuxDataType *typePtr, CompileEnv *envPtr)); EXTERN int TclCreateExceptRange _ANSI_ARGS_(( ExceptionRangeType type, CompileEnv *envPtr)); EXTERN ExecEnv * TclCreateExecEnv _ANSI_ARGS_((Tcl_Interp *interp)); EXTERN void TclDeleteExecEnv _ANSI_ARGS_((ExecEnv *eePtr)); EXTERN void TclDeleteLiteralTable _ANSI_ARGS_(( Tcl_Interp *interp, LiteralTable *tablePtr)); EXTERN void TclEmitForwardJump _ANSI_ARGS_((CompileEnv *envPtr, TclJumpType jumpType, JumpFixup *jumpFixupPtr)); EXTERN ExceptionRange * TclGetExceptionRangeForPc _ANSI_ARGS_(( unsigned char *pc, int catchOnly, ByteCode* codePtr)); EXTERN void TclExpandJumpFixupArray _ANSI_ARGS_(( JumpFixupArray *fixupArrayPtr)); EXTERN void TclFinalizeAuxDataTypeTable _ANSI_ARGS_((void)); EXTERN int TclFindCompiledLocal _ANSI_ARGS_((CONST char *name, int nameChars, int create, int flags, Proc *procPtr)); EXTERN LiteralEntry * TclLookupLiteralEntry _ANSI_ARGS_(( Tcl_Interp *interp, Tcl_Obj *objPtr)); EXTERN int TclFixupForwardJump _ANSI_ARGS_(( CompileEnv *envPtr, JumpFixup *jumpFixupPtr, int jumpDist, int distThreshold)); EXTERN void TclFreeCompileEnv _ANSI_ARGS_((CompileEnv *envPtr)); EXTERN void TclFreeJumpFixupArray _ANSI_ARGS_(( JumpFixupArray *fixupArrayPtr)); EXTERN void TclInitAuxDataTypeTable _ANSI_ARGS_((void)); EXTERN void TclInitByteCodeObj _ANSI_ARGS_((Tcl_Obj *objPtr, CompileEnv *envPtr)); #ifndef TCL_TIP280 EXTERN void TclInitCompileEnv _ANSI_ARGS_((Tcl_Interp *interp, CompileEnv *envPtr, char *string, int numBytes)); #else EXTERN void TclInitCompileEnv _ANSI_ARGS_((Tcl_Interp *interp, CompileEnv *envPtr, char *string, int numBytes, CONST CmdFrame* invoker, int word)); #endif EXTERN void TclInitJumpFixupArray _ANSI_ARGS_(( JumpFixupArray *fixupArrayPtr)); EXTERN void TclInitLiteralTable _ANSI_ARGS_(( LiteralTable *tablePtr)); #ifdef TCL_COMPILE_STATS EXTERN char * TclLiteralStats _ANSI_ARGS_(( LiteralTable *tablePtr)); EXTERN int TclLog2 _ANSI_ARGS_((int value)); #endif #ifdef TCL_COMPILE_DEBUG EXTERN void TclPrintByteCodeObj _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr)); #endif EXTERN int TclPrintInstruction _ANSI_ARGS_((ByteCode* codePtr, unsigned char *pc)); EXTERN void TclPrintObject _ANSI_ARGS_((FILE *outFile, Tcl_Obj *objPtr, int maxChars)); EXTERN void TclPrintSource _ANSI_ARGS_((FILE *outFile, CONST char *string, int maxChars)); EXTERN void TclRegisterAuxDataType _ANSI_ARGS_((AuxDataType *typePtr)); EXTERN int TclRegisterLiteral _ANSI_ARGS_((CompileEnv *envPtr, char *bytes, int length, int onHeap)); EXTERN void TclReleaseLiteral _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr)); EXTERN void TclSetCmdNameObj _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr, Command *cmdPtr)); #ifdef TCL_COMPILE_DEBUG EXTERN void TclVerifyGlobalLiteralTable _ANSI_ARGS_(( Interp *iPtr)); EXTERN void TclVerifyLocalLiteralTable _ANSI_ARGS_(( CompileEnv *envPtr)); #endif EXTERN int TclCompileVariableCmd _ANSI_ARGS_(( Tcl_Interp *interp, Tcl_Parse *parsePtr, CompileEnv *envPtr)); /* *---------------------------------------------------------------- * Macros used by Tcl bytecode compilation and execution modules * inside the Tcl core but not used outside. *---------------------------------------------------------------- */ /* * Form of TclRegisterLiteral with onHeap == 0. * In that case, it is safe to cast away CONSTness, and it * is cleanest to do that here, all in one place. */ #define TclRegisterNewLiteral(envPtr, bytes, length) \ TclRegisterLiteral(envPtr, (char *)(bytes), length, /*onHeap*/ 0) /* * Macro used to update the stack requirements. * It is called by the macros TclEmitOpCode, TclEmitInst1 and * TclEmitInst4. * Remark that the very last instruction of a bytecode always * reduces the stack level: INST_DONE or INST_POP, so that the * maxStackdepth is always updated. */ #define TclUpdateStackReqs(op, i, envPtr) \ {\ int delta = tclInstructionTable[(op)].stackEffect;\ if (delta) {\ if (delta < 0) {\ if((envPtr)->maxStackDepth < (envPtr)->currStackDepth) {\ (envPtr)->maxStackDepth = (envPtr)->currStackDepth;\ }\ if (delta == INT_MIN) {\ delta = 1 - (i);\ }\ }\ (envPtr)->currStackDepth += delta;\ }\ } /* * Macro to emit an opcode byte into a CompileEnv's code array. * The ANSI C "prototype" for this macro is: * * EXTERN void TclEmitOpcode _ANSI_ARGS_((unsigned char op, * CompileEnv *envPtr)); */ #define TclEmitOpcode(op, envPtr) \ if ((envPtr)->codeNext == (envPtr)->codeEnd) \ TclExpandCodeArray(envPtr); \ *(envPtr)->codeNext++ = (unsigned char) (op);\ TclUpdateStackReqs(op, 0, envPtr) /* * Macro to emit an integer operand. * The ANSI C "prototype" for this macro is: * * EXTERN void TclEmitInt1 _ANSI_ARGS_((int i, CompileEnv *envPtr)); */ #define TclEmitInt1(i, envPtr) \ if ((envPtr)->codeNext == (envPtr)->codeEnd) \ TclExpandCodeArray(envPtr); \ *(envPtr)->codeNext++ = (unsigned char) ((unsigned int) (i)) /* * Macros to emit an instruction with signed or unsigned integer operands. * Four byte integers are stored in "big-endian" order with the high order * byte stored at the lowest address. * The ANSI C "prototypes" for these macros are: * * EXTERN void TclEmitInstInt1 _ANSI_ARGS_((unsigned char op, int i, * CompileEnv *envPtr)); * EXTERN void TclEmitInstInt4 _ANSI_ARGS_((unsigned char op, int i, * CompileEnv *envPtr)); */ #define TclEmitInstInt1(op, i, envPtr) \ if (((envPtr)->codeNext + 2) > (envPtr)->codeEnd) { \ TclExpandCodeArray(envPtr); \ } \ *(envPtr)->codeNext++ = (unsigned char) (op); \ *(envPtr)->codeNext++ = (unsigned char) ((unsigned int) (i));\ TclUpdateStackReqs(op, i, envPtr) #define TclEmitInstInt4(op, i, envPtr) \ if (((envPtr)->codeNext + 5) > (envPtr)->codeEnd) { \ TclExpandCodeArray(envPtr); \ } \ *(envPtr)->codeNext++ = (unsigned char) (op); \ *(envPtr)->codeNext++ = \ (unsigned char) ((unsigned int) (i) >> 24); \ *(envPtr)->codeNext++ = \ (unsigned char) ((unsigned int) (i) >> 16); \ *(envPtr)->codeNext++ = \ (unsigned char) ((unsigned int) (i) >> 8); \ *(envPtr)->codeNext++ = \ (unsigned char) ((unsigned int) (i) );\ TclUpdateStackReqs(op, i, envPtr) /* * Macro to push a Tcl object onto the Tcl evaluation stack. It emits the * object's one or four byte array index into the CompileEnv's code * array. These support, respectively, a maximum of 256 (2**8) and 2**32 * objects in a CompileEnv. The ANSI C "prototype" for this macro is: * * EXTERN void TclEmitPush _ANSI_ARGS_((int objIndex, CompileEnv *envPtr)); */ #define TclEmitPush(objIndex, envPtr) \ {\ register int objIndexCopy = (objIndex);\ if (objIndexCopy <= 255) { \ TclEmitInstInt1(INST_PUSH1, objIndexCopy, (envPtr)); \ } else { \ TclEmitInstInt4(INST_PUSH4, objIndexCopy, (envPtr)); \ }\ } /* * Macros to update a (signed or unsigned) integer starting at a pointer. * The two variants depend on the number of bytes. The ANSI C "prototypes" * for these macros are: * * EXTERN void TclStoreInt1AtPtr _ANSI_ARGS_((int i, unsigned char *p)); * EXTERN void TclStoreInt4AtPtr _ANSI_ARGS_((int i, unsigned char *p)); */ #define TclStoreInt1AtPtr(i, p) \ *(p) = (unsigned char) ((unsigned int) (i)) #define TclStoreInt4AtPtr(i, p) \ *(p) = (unsigned char) ((unsigned int) (i) >> 24); \ *(p+1) = (unsigned char) ((unsigned int) (i) >> 16); \ *(p+2) = (unsigned char) ((unsigned int) (i) >> 8); \ *(p+3) = (unsigned char) ((unsigned int) (i) ) /* * Macros to update instructions at a particular pc with a new op code * and a (signed or unsigned) int operand. The ANSI C "prototypes" for * these macros are: * * EXTERN void TclUpdateInstInt1AtPc _ANSI_ARGS_((unsigned char op, int i, * unsigned char *pc)); * EXTERN void TclUpdateInstInt4AtPc _ANSI_ARGS_((unsigned char op, int i, * unsigned char *pc)); */ #define TclUpdateInstInt1AtPc(op, i, pc) \ *(pc) = (unsigned char) (op); \ TclStoreInt1AtPtr((i), ((pc)+1)) #define TclUpdateInstInt4AtPc(op, i, pc) \ *(pc) = (unsigned char) (op); \ TclStoreInt4AtPtr((i), ((pc)+1)) /* * Macros to get a signed integer (GET_INT{1,2}) or an unsigned int * (GET_UINT{1,2}) from a pointer. There are two variants for each * return type that depend on the number of bytes fetched. * The ANSI C "prototypes" for these macros are: * * EXTERN int TclGetInt1AtPtr _ANSI_ARGS_((unsigned char *p)); * EXTERN int TclGetInt4AtPtr _ANSI_ARGS_((unsigned char *p)); * EXTERN unsigned int TclGetUInt1AtPtr _ANSI_ARGS_((unsigned char *p)); * EXTERN unsigned int TclGetUInt4AtPtr _ANSI_ARGS_((unsigned char *p)); */ /* * The TclGetInt1AtPtr macro is tricky because we want to do sign * extension on the 1-byte value. Unfortunately the "char" type isn't * signed on all platforms so sign-extension doesn't always happen * automatically. Sometimes we can explicitly declare the pointer to be * signed, but other times we have to explicitly sign-extend the value * in software. */ #ifndef __CHAR_UNSIGNED__ # define TclGetInt1AtPtr(p) ((int) *((char *) p)) #else # ifdef HAVE_SIGNED_CHAR # define TclGetInt1AtPtr(p) ((int) *((signed char *) p)) # else # define TclGetInt1AtPtr(p) (((int) *((char *) p)) \ | ((*(p) & 0200) ? (-256) : 0)) # endif #endif #define TclGetInt4AtPtr(p) (((int) TclGetInt1AtPtr(p) << 24) | \ (*((p)+1) << 16) | \ (*((p)+2) << 8) | \ (*((p)+3))) #define TclGetUInt1AtPtr(p) ((unsigned int) *(p)) #define TclGetUInt4AtPtr(p) ((unsigned int) (*(p) << 24) | \ (*((p)+1) << 16) | \ (*((p)+2) << 8) | \ (*((p)+3))) /* * Macros used to compute the minimum and maximum of two integers. * The ANSI C "prototypes" for these macros are: * * EXTERN int TclMin _ANSI_ARGS_((int i, int j)); * EXTERN int TclMax _ANSI_ARGS_((int i, int j)); */ #define TclMin(i, j) ((((int) i) < ((int) j))? (i) : (j)) #define TclMax(i, j) ((((int) i) > ((int) j))? (i) : (j)) /* * DTrace probe macros (NOPs if DTrace support is not enabled). */ /* * Define the following macros to enable debug logging of the DTrace proc, * cmd, and inst probes. Note that this does _not_ require a platform with * DTrace, it simply logs all probe output to /tmp/tclDTraceDebug-[pid].log. * * If the second macro is defined, logging to file starts immediately, * otherwise only after the first call to [tcl::dtrace]. Note that the debug * probe data is always computed, even when it is not logged to file. * * Defining the third macro enables debug logging of inst probes (disabled * by default due to the significant performance impact). */ /* #define TCL_DTRACE_DEBUG 1 #define TCL_DTRACE_DEBUG_LOG_ENABLED 1 #define TCL_DTRACE_DEBUG_INST_PROBES 1 */ #if !(defined(TCL_DTRACE_DEBUG) && defined(__GNUC__)) #ifdef USE_DTRACE #include "tclDTrace.h" #if defined(__GNUC__) && __GNUC__ > 2 /* Use gcc branch prediction hint to minimize cost of DTrace ENABLED checks. */ #define unlikely(x) (__builtin_expect((x), 0)) #else #define unlikely(x) (x) #endif #define TCL_DTRACE_PROC_ENTRY_ENABLED() unlikely(TCL_PROC_ENTRY_ENABLED()) #define TCL_DTRACE_PROC_RETURN_ENABLED() unlikely(TCL_PROC_RETURN_ENABLED()) #define TCL_DTRACE_PROC_RESULT_ENABLED() unlikely(TCL_PROC_RESULT_ENABLED()) #define TCL_DTRACE_PROC_ARGS_ENABLED() unlikely(TCL_PROC_ARGS_ENABLED()) #define TCL_DTRACE_PROC_ENTRY(a0, a1, a2) TCL_PROC_ENTRY(a0, a1, a2) #define TCL_DTRACE_PROC_RETURN(a0, a1) TCL_PROC_RETURN(a0, a1) #define TCL_DTRACE_PROC_RESULT(a0, a1, a2, a3) TCL_PROC_RESULT(a0, a1, a2, a3) #define TCL_DTRACE_PROC_ARGS(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) \ TCL_PROC_ARGS(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) #define TCL_DTRACE_CMD_ENTRY_ENABLED() unlikely(TCL_CMD_ENTRY_ENABLED()) #define TCL_DTRACE_CMD_RETURN_ENABLED() unlikely(TCL_CMD_RETURN_ENABLED()) #define TCL_DTRACE_CMD_RESULT_ENABLED() unlikely(TCL_CMD_RESULT_ENABLED()) #define TCL_DTRACE_CMD_ARGS_ENABLED() unlikely(TCL_CMD_ARGS_ENABLED()) #define TCL_DTRACE_CMD_ENTRY(a0, a1, a2) TCL_CMD_ENTRY(a0, a1, a2) #define TCL_DTRACE_CMD_RETURN(a0, a1) TCL_CMD_RETURN(a0, a1) #define TCL_DTRACE_CMD_RESULT(a0, a1, a2, a3) TCL_CMD_RESULT(a0, a1, a2, a3) #define TCL_DTRACE_CMD_ARGS(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) \ TCL_CMD_ARGS(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) #define TCL_DTRACE_INST_START_ENABLED() unlikely(TCL_INST_START_ENABLED()) #define TCL_DTRACE_INST_DONE_ENABLED() unlikely(TCL_INST_DONE_ENABLED()) #define TCL_DTRACE_INST_START(a0, a1, a2) TCL_INST_START(a0, a1, a2) #define TCL_DTRACE_INST_DONE(a0, a1, a2) TCL_INST_DONE(a0, a1, a2) #define TCL_DTRACE_TCL_PROBE_ENABLED() unlikely(TCL_TCL_PROBE_ENABLED()) #define TCL_DTRACE_TCL_PROBE(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) \ TCL_TCL_PROBE(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) #define TCL_DTRACE_DEBUG_LOG() #else /* USE_DTRACE */ #define TCL_DTRACE_PROC_ENTRY_ENABLED() 0 #define TCL_DTRACE_PROC_RETURN_ENABLED() 0 #define TCL_DTRACE_PROC_RESULT_ENABLED() 0 #define TCL_DTRACE_PROC_ARGS_ENABLED() 0 #define TCL_DTRACE_PROC_ENTRY(a0, a1, a2) {} #define TCL_DTRACE_PROC_RETURN(a0, a1) {} #define TCL_DTRACE_PROC_RESULT(a0, a1, a2, a3) {} #define TCL_DTRACE_PROC_ARGS(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) {} #define TCL_DTRACE_CMD_ENTRY_ENABLED() 0 #define TCL_DTRACE_CMD_RETURN_ENABLED() 0 #define TCL_DTRACE_CMD_RESULT_ENABLED() 0 #define TCL_DTRACE_CMD_ARGS_ENABLED() 0 #define TCL_DTRACE_CMD_ENTRY(a0, a1, a2) {} #define TCL_DTRACE_CMD_RETURN(a0, a1) {} #define TCL_DTRACE_CMD_RESULT(a0, a1, a2, a3) {} #define TCL_DTRACE_CMD_ARGS(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) {} #define TCL_DTRACE_INST_START_ENABLED() 0 #define TCL_DTRACE_INST_DONE_ENABLED() 0 #define TCL_DTRACE_INST_START(a0, a1, a2) {} #define TCL_DTRACE_INST_DONE(a0, a1, a2) {} #define TCL_DTRACE_TCL_PROBE_ENABLED() 0 #define TCL_DTRACE_TCL_PROBE(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) {} #endif /* USE_DTRACE */ #else /* TCL_DTRACE_DEBUG */ #define USE_DTRACE 1 #if !defined(TCL_DTRACE_DEBUG_LOG_ENABLED) || !(TCL_DTRACE_DEBUG_LOG_ENABLED) #undef TCL_DTRACE_DEBUG_LOG_ENABLED #define TCL_DTRACE_DEBUG_LOG_ENABLED 0 #endif #if !defined(TCL_DTRACE_DEBUG_INST_PROBES) || !(TCL_DTRACE_DEBUG_INST_PROBES) #undef TCL_DTRACE_DEBUG_INST_PROBES #define TCL_DTRACE_DEBUG_INST_PROBES 0 #endif MODULE_SCOPE int tclDTraceDebugEnabled, tclDTraceDebugIndent; MODULE_SCOPE FILE *tclDTraceDebugLog; MODULE_SCOPE void TclDTraceOpenDebugLog(void); MODULE_SCOPE void TclDTraceInfo(Tcl_Obj *info, char **args, int *argsi); #define TCL_DTRACE_DEBUG_LOG() \ int tclDTraceDebugEnabled = TCL_DTRACE_DEBUG_LOG_ENABLED;\ int tclDTraceDebugIndent = 0; \ FILE *tclDTraceDebugLog = NULL; \ void TclDTraceOpenDebugLog(void) { char n[35]; \ sprintf(n, "/tmp/tclDTraceDebug-%lu.log", (unsigned long) getpid()); \ tclDTraceDebugLog = fopen(n, "a"); } \ #define TclDTraceDbgMsg(p, m, ...) do { if (tclDTraceDebugEnabled) { \ int _l, _t = 0; if (!tclDTraceDebugLog) { TclDTraceOpenDebugLog(); } \ fprintf(tclDTraceDebugLog, "%.12s:%.4d:%n", strrchr(__FILE__, '/') + \ 1, __LINE__, &_l); _t += _l; \ fprintf(tclDTraceDebugLog, " %.*s():%n", (_t < 18 ? 18 - _t : 0) + \ 18, __func__, &_l); _t += _l; \ fprintf(tclDTraceDebugLog, "%*s" p "%n", (_t < 40 ? 40 - _t : 0) + \ 2 * tclDTraceDebugIndent, "", &_l); _t += _l; \ fprintf(tclDTraceDebugLog, "%*s" m "\n", (_t < 64 ? 64 - _t : 1), "", \ ##__VA_ARGS__); fflush(tclDTraceDebugLog); \ } } while (0) #define TCL_DTRACE_PROC_ENTRY_ENABLED() 1 #define TCL_DTRACE_PROC_RETURN_ENABLED() 1 #define TCL_DTRACE_PROC_RESULT_ENABLED() 1 #define TCL_DTRACE_PROC_ARGS_ENABLED() 1 #define TCL_DTRACE_PROC_ENTRY(a0, a1, a2) \ tclDTraceDebugIndent++; \ TclDTraceDbgMsg("-> proc-entry", "%s %d %p", a0, a1, a2) #define TCL_DTRACE_PROC_RETURN(a0, a1) \ TclDTraceDbgMsg("<- proc-return", "%s %d", a0, a1); \ tclDTraceDebugIndent-- #define TCL_DTRACE_PROC_RESULT(a0, a1, a2, a3) \ TclDTraceDbgMsg(" | proc-result", "%s %d %s %p", a0, a1, a2, a3) #define TCL_DTRACE_PROC_ARGS(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) \ TclDTraceDbgMsg(" | proc-args", "%s %s %s %s %s %s %s %s %s %s", a0, \ a1, a2, a3, a4, a5, a6, a7, a8, a9) #define TCL_DTRACE_CMD_ENTRY_ENABLED() 1 #define TCL_DTRACE_CMD_RETURN_ENABLED() 1 #define TCL_DTRACE_CMD_RESULT_ENABLED() 1 #define TCL_DTRACE_CMD_ARGS_ENABLED() 1 #define TCL_DTRACE_CMD_ENTRY(a0, a1, a2) \ tclDTraceDebugIndent++; \ TclDTraceDbgMsg("-> cmd-entry", "%s %d %p", a0, a1, a2) #define TCL_DTRACE_CMD_RETURN(a0, a1) \ TclDTraceDbgMsg("<- cmd-return", "%s %d", a0, a1); \ tclDTraceDebugIndent-- #define TCL_DTRACE_CMD_RESULT(a0, a1, a2, a3) \ TclDTraceDbgMsg(" | cmd-result", "%s %d %s %p", a0, a1, a2, a3) #define TCL_DTRACE_CMD_ARGS(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) \ TclDTraceDbgMsg(" | cmd-args", "%s %s %s %s %s %s %s %s %s %s", a0, \ a1, a2, a3, a4, a5, a6, a7, a8, a9) #define TCL_DTRACE_INST_START_ENABLED() TCL_DTRACE_DEBUG_INST_PROBES #define TCL_DTRACE_INST_DONE_ENABLED() TCL_DTRACE_DEBUG_INST_PROBES #define TCL_DTRACE_INST_START(a0, a1, a2) \ TclDTraceDbgMsg(" | inst-start", "%s %d %p", a0, a1, a2) #define TCL_DTRACE_INST_DONE(a0, a1, a2) \ TclDTraceDbgMsg(" | inst-end", "%s %d %p", a0, a1, a2) #define TCL_DTRACE_TCL_PROBE_ENABLED() 1 #define TCL_DTRACE_TCL_PROBE(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) \ tclDTraceDebugEnabled = 1; \ TclDTraceDbgMsg(" | tcl-probe", "%s %s %s %s %s %s %s %s %s %s", a0, \ a1, a2, a3, a4, a5, a6, a7, a8, a9) #endif /* TCL_DTRACE_DEBUG */ # undef TCL_STORAGE_CLASS # define TCL_STORAGE_CLASS DLLIMPORT #endif /* _TCLCOMPILATION */ tcl8.4.20/generic/tclCmdIL.c0000644003604700454610000035616311737050674014150 0ustar dgp771div/* * tclCmdIL.c -- * * This file contains the top-level command routines for most of * the Tcl built-in commands whose names begin with the letters * I through L. It contains only commands in the generic core * (i.e. those that don't depend much upon UNIX facilities). * * Copyright (c) 1987-1993 The Regents of the University of California. * Copyright (c) 1993-1997 Lucent Technologies. * Copyright (c) 1994-1997 Sun Microsystems, Inc. * Copyright (c) 1998-1999 by Scriptics Corporation. * Copyright (c) 2001 by Kevin B. Kenny. All rights reserved. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" #include "tclRegexp.h" /* * During execution of the "lsort" command, structures of the following * type are used to arrange the objects being sorted into a collection * of linked lists. */ typedef struct SortElement { Tcl_Obj *objPtr; /* Object being sorted. */ int count; /* number of same elements in list */ struct SortElement *nextPtr; /* Next element in the list, or * NULL for end of list. */ } SortElement; /* * The "lsort" command needs to pass certain information down to the * function that compares two list elements, and the comparison function * needs to pass success or failure information back up to the top-level * "lsort" command. The following structure is used to pass this * information. */ typedef struct SortInfo { int isIncreasing; /* Nonzero means sort in increasing order. */ int sortMode; /* The sort mode. One of SORTMODE_* * values defined below */ Tcl_Obj *compareCmdPtr; /* The Tcl comparison command when sortMode * is SORTMODE_COMMAND. Pre-initialized to * hold base of command.*/ int index; /* If the -index option was specified, this * holds the index of the list element * to extract for comparison. If -index * wasn't specified, this is -1. */ Tcl_Interp *interp; /* The interpreter in which the sortis * being done. */ int resultCode; /* Completion code for the lsort command. * If an error occurs during the sort this * is changed from TCL_OK to TCL_ERROR. */ } SortInfo; /* * The "sortMode" field of the SortInfo structure can take on any of the * following values. */ #define SORTMODE_ASCII 0 #define SORTMODE_INTEGER 1 #define SORTMODE_REAL 2 #define SORTMODE_COMMAND 3 #define SORTMODE_DICTIONARY 4 /* * Magic values for the index field of the SortInfo structure. * Note that the index "end-1" will be translated to SORTIDX_END-1, etc. */ #define SORTIDX_NONE -1 /* Not indexed; use whole value. */ #define SORTIDX_END -2 /* Indexed from end. */ /* * Forward declarations for procedures defined in this file: */ static void AppendLocals _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *listPtr, CONST char *pattern, int includeLinks)); static int DictionaryCompare _ANSI_ARGS_((char *left, char *right)); static int InfoArgsCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int InfoBodyCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int InfoCmdCountCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int InfoCommandsCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int InfoCompleteCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int InfoDefaultCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int InfoExistsCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); #ifdef TCL_TIP280 /* TIP #280 - New 'info' subcommand 'frame' */ static int InfoFrameCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); #endif static int InfoFunctionsCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int InfoGlobalsCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int InfoHostnameCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int InfoLevelCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int InfoLibraryCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int InfoLoadedCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int InfoLocalsCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int InfoNameOfExecutableCmd _ANSI_ARGS_(( ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int InfoPatchLevelCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int InfoProcsCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int InfoScriptCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int InfoSharedlibCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int InfoTclVersionCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int InfoVarsCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static SortElement * MergeSort _ANSI_ARGS_((SortElement *headPt, SortInfo *infoPtr)); static SortElement * MergeLists _ANSI_ARGS_((SortElement *leftPtr, SortElement *rightPtr, SortInfo *infoPtr)); static int SortCompare _ANSI_ARGS_((Tcl_Obj *firstPtr, Tcl_Obj *second, SortInfo *infoPtr)); /* *---------------------------------------------------------------------- * * Tcl_IfObjCmd -- * * This procedure is invoked to process the "if" Tcl command. * See the user documentation for details on what it does. * * With the bytecode compiler, this procedure is only called when * a command name is computed at runtime, and is "if" or the name * to which "if" was renamed: e.g., "set z if; $z 1 {puts foo}" * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_IfObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int thenScriptIndex = 0; /* then script to be evaled after syntax check */ #ifdef TCL_TIP280 Interp* iPtr = (Interp*) interp; #endif int i, result, value; char *clause; i = 1; while (1) { /* * At this point in the loop, objv and objc refer to an expression * to test, either for the main expression or an expression * following an "elseif". The arguments after the expression must * be "then" (optional) and a script to execute if the expression is * true. */ if (i >= objc) { clause = Tcl_GetString(objv[i-1]); Tcl_AppendResult(interp, "wrong # args: no expression after \"", clause, "\" argument", (char *) NULL); return TCL_ERROR; } if (!thenScriptIndex) { result = Tcl_ExprBooleanObj(interp, objv[i], &value); if (result != TCL_OK) { return result; } } i++; if (i >= objc) { missingScript: clause = Tcl_GetString(objv[i-1]); Tcl_AppendResult(interp, "wrong # args: no script following \"", clause, "\" argument", (char *) NULL); return TCL_ERROR; } clause = Tcl_GetString(objv[i]); if ((i < objc) && (strcmp(clause, "then") == 0)) { i++; } if (i >= objc) { goto missingScript; } if (value) { thenScriptIndex = i; value = 0; } /* * The expression evaluated to false. Skip the command, then * see if there is an "else" or "elseif" clause. */ i++; if (i >= objc) { if (thenScriptIndex) { #ifndef TCL_TIP280 return Tcl_EvalObjEx(interp, objv[thenScriptIndex], 0); #else /* TIP #280. Make invoking context available to branch */ return TclEvalObjEx(interp, objv[thenScriptIndex], 0, iPtr->cmdFramePtr,thenScriptIndex); #endif } return TCL_OK; } clause = Tcl_GetString(objv[i]); if ((clause[0] == 'e') && (strcmp(clause, "elseif") == 0)) { i++; continue; } break; } /* * Couldn't find a "then" or "elseif" clause to execute. Check now * for an "else" clause. We know that there's at least one more * argument when we get here. */ if (strcmp(clause, "else") == 0) { i++; if (i >= objc) { Tcl_AppendResult(interp, "wrong # args: no script following \"else\" argument", (char *) NULL); return TCL_ERROR; } } if (i < objc - 1) { Tcl_AppendResult(interp, "wrong # args: extra words after \"else\" clause in \"if\" command", (char *) NULL); return TCL_ERROR; } if (thenScriptIndex) { #ifndef TCL_TIP280 return Tcl_EvalObjEx(interp, objv[thenScriptIndex], 0); #else /* TIP #280. Make invoking context available to branch/else */ return TclEvalObjEx(interp, objv[thenScriptIndex], 0, iPtr->cmdFramePtr,thenScriptIndex); #endif } #ifndef TCL_TIP280 return Tcl_EvalObjEx(interp, objv[i], 0); #else return TclEvalObjEx(interp, objv[i], 0, iPtr->cmdFramePtr,i); #endif } /* *---------------------------------------------------------------------- * * Tcl_IncrObjCmd -- * * This procedure is invoked to process the "incr" Tcl command. * See the user documentation for details on what it does. * * With the bytecode compiler, this procedure is only called when * a command name is computed at runtime, and is "incr" or the name * to which "incr" was renamed: e.g., "set z incr; $z i -1" * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_IncrObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { long incrAmount; Tcl_Obj *newValuePtr; if ((objc != 2) && (objc != 3)) { Tcl_WrongNumArgs(interp, 1, objv, "varName ?increment?"); return TCL_ERROR; } /* * Calculate the amount to increment by. */ if (objc == 2) { incrAmount = 1; } else { if (Tcl_GetLongFromObj(interp, objv[2], &incrAmount) != TCL_OK) { Tcl_AddErrorInfo(interp, "\n (reading increment)"); return TCL_ERROR; } /* * Need to be a bit cautious to ensure that [expr]-like rules * are enforced for interpretation of wide integers, despite * the fact that the underlying API itself is a 'long' only one. */ if (objv[2]->typePtr == &tclIntType) { incrAmount = objv[2]->internalRep.longValue; } else if (objv[2]->typePtr == &tclWideIntType) { TclGetLongFromWide(incrAmount,objv[2]); } else { Tcl_WideInt wide; if (Tcl_GetWideIntFromObj(interp, objv[2], &wide) != TCL_OK) { Tcl_AddErrorInfo(interp, "\n (reading increment)"); return TCL_ERROR; } incrAmount = Tcl_WideAsLong(wide); if ((wide <= Tcl_LongAsWide(LONG_MAX)) && (wide >= Tcl_LongAsWide(LONG_MIN))) { objv[2]->typePtr = &tclIntType; objv[2]->internalRep.longValue = incrAmount; } } } /* * Increment the variable's value. */ newValuePtr = TclIncrVar2(interp, objv[1], (Tcl_Obj *) NULL, incrAmount, TCL_LEAVE_ERR_MSG); if (newValuePtr == NULL) { return TCL_ERROR; } /* * Set the interpreter's object result to refer to the variable's new * value object. */ Tcl_SetObjResult(interp, newValuePtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_InfoObjCmd -- * * This procedure is invoked to process the "info" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_InfoObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Arbitrary value passed to the command. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { static CONST char *subCmds[] = { "args", "body", "cmdcount", "commands", "complete", "default", "exists", #ifdef TCL_TIP280 "frame", #endif "functions", "globals", "hostname", "level", "library", "loaded", "locals", "nameofexecutable", "patchlevel", "procs", "script", "sharedlibextension", "tclversion", "vars", (char *) NULL}; enum ISubCmdIdx { IArgsIdx, IBodyIdx, ICmdCountIdx, ICommandsIdx, ICompleteIdx, IDefaultIdx, IExistsIdx, #ifdef TCL_TIP280 IFrameIdx, #endif IFunctionsIdx, IGlobalsIdx, IHostnameIdx, ILevelIdx, ILibraryIdx, ILoadedIdx, ILocalsIdx, INameOfExecutableIdx, IPatchLevelIdx, IProcsIdx, IScriptIdx, ISharedLibExtensionIdx, ITclVersionIdx, IVarsIdx }; int index, result; if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?"); return TCL_ERROR; } result = Tcl_GetIndexFromObj(interp, objv[1], subCmds, "option", 0, (int *) &index); if (result != TCL_OK) { return result; } switch (index) { case IArgsIdx: result = InfoArgsCmd(clientData, interp, objc, objv); break; case IBodyIdx: result = InfoBodyCmd(clientData, interp, objc, objv); break; case ICmdCountIdx: result = InfoCmdCountCmd(clientData, interp, objc, objv); break; case ICommandsIdx: result = InfoCommandsCmd(clientData, interp, objc, objv); break; case ICompleteIdx: result = InfoCompleteCmd(clientData, interp, objc, objv); break; case IDefaultIdx: result = InfoDefaultCmd(clientData, interp, objc, objv); break; case IExistsIdx: result = InfoExistsCmd(clientData, interp, objc, objv); break; #ifdef TCL_TIP280 case IFrameIdx: /* TIP #280 - New method 'frame' */ result = InfoFrameCmd(clientData, interp, objc, objv); break; #endif case IFunctionsIdx: result = InfoFunctionsCmd(clientData, interp, objc, objv); break; case IGlobalsIdx: result = InfoGlobalsCmd(clientData, interp, objc, objv); break; case IHostnameIdx: result = InfoHostnameCmd(clientData, interp, objc, objv); break; case ILevelIdx: result = InfoLevelCmd(clientData, interp, objc, objv); break; case ILibraryIdx: result = InfoLibraryCmd(clientData, interp, objc, objv); break; case ILoadedIdx: result = InfoLoadedCmd(clientData, interp, objc, objv); break; case ILocalsIdx: result = InfoLocalsCmd(clientData, interp, objc, objv); break; case INameOfExecutableIdx: result = InfoNameOfExecutableCmd(clientData, interp, objc, objv); break; case IPatchLevelIdx: result = InfoPatchLevelCmd(clientData, interp, objc, objv); break; case IProcsIdx: result = InfoProcsCmd(clientData, interp, objc, objv); break; case IScriptIdx: result = InfoScriptCmd(clientData, interp, objc, objv); break; case ISharedLibExtensionIdx: result = InfoSharedlibCmd(clientData, interp, objc, objv); break; case ITclVersionIdx: result = InfoTclVersionCmd(clientData, interp, objc, objv); break; case IVarsIdx: result = InfoVarsCmd(clientData, interp, objc, objv); break; } return result; } /* *---------------------------------------------------------------------- * * InfoArgsCmd -- * * Called to implement the "info args" command that returns the * argument list for a procedure. Handles the following syntax: * * info args procName * * Results: * Returns TCL_OK if successful and TCL_ERROR if there is an error. * * Side effects: * Returns a result in the interpreter's result object. If there is * an error, the result is an error message. * *---------------------------------------------------------------------- */ static int InfoArgsCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { register Interp *iPtr = (Interp *) interp; char *name; Proc *procPtr; CompiledLocal *localPtr; Tcl_Obj *listObjPtr; if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "procname"); return TCL_ERROR; } name = Tcl_GetString(objv[2]); procPtr = TclFindProc(iPtr, name); if (procPtr == NULL) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "\"", name, "\" isn't a procedure", (char *) NULL); return TCL_ERROR; } /* * Build a return list containing the arguments. */ listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); for (localPtr = procPtr->firstLocalPtr; localPtr != NULL; localPtr = localPtr->nextPtr) { if (TclIsVarArgument(localPtr)) { Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewStringObj(localPtr->name, -1)); } } Tcl_SetObjResult(interp, listObjPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * InfoBodyCmd -- * * Called to implement the "info body" command that returns the body * for a procedure. Handles the following syntax: * * info body procName * * Results: * Returns TCL_OK if successful and TCL_ERROR if there is an error. * * Side effects: * Returns a result in the interpreter's result object. If there is * an error, the result is an error message. * *---------------------------------------------------------------------- */ static int InfoBodyCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { register Interp *iPtr = (Interp *) interp; char *name; Proc *procPtr; Tcl_Obj *bodyPtr, *resultPtr; if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "procname"); return TCL_ERROR; } name = Tcl_GetString(objv[2]); procPtr = TclFindProc(iPtr, name); if (procPtr == NULL) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "\"", name, "\" isn't a procedure", (char *) NULL); return TCL_ERROR; } /* * Here we used to return procPtr->bodyPtr, except when the body was * bytecompiled - in that case, the return was a copy of the body's * string rep. In order to better isolate the implementation details * of the compiler/engine subsystem, we now always return a copy of * the string rep. It is important to return a copy so that later * manipulations of the object do not invalidate the internal rep. */ bodyPtr = procPtr->bodyPtr; if (bodyPtr->bytes == NULL) { /* * The string rep might not be valid if the procedure has * never been run before. [Bug #545644] */ (void) Tcl_GetString(bodyPtr); } resultPtr = Tcl_NewStringObj(bodyPtr->bytes, bodyPtr->length); Tcl_SetObjResult(interp, resultPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * InfoCmdCountCmd -- * * Called to implement the "info cmdcount" command that returns the * number of commands that have been executed. Handles the following * syntax: * * info cmdcount * * Results: * Returns TCL_OK if successful and TCL_ERROR if there is an error. * * Side effects: * Returns a result in the interpreter's result object. If there is * an error, the result is an error message. * *---------------------------------------------------------------------- */ static int InfoCmdCountCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Interp *iPtr = (Interp *) interp; if (objc != 2) { Tcl_WrongNumArgs(interp, 2, objv, NULL); return TCL_ERROR; } Tcl_SetIntObj(Tcl_GetObjResult(interp), iPtr->cmdCount); return TCL_OK; } /* *---------------------------------------------------------------------- * * InfoCommandsCmd -- * * Called to implement the "info commands" command that returns the * list of commands in the interpreter that match an optional pattern. * The pattern, if any, consists of an optional sequence of namespace * names separated by "::" qualifiers, which is followed by a * glob-style pattern that restricts which commands are returned. * Handles the following syntax: * * info commands ?pattern? * * Results: * Returns TCL_OK if successful and TCL_ERROR if there is an error. * * Side effects: * Returns a result in the interpreter's result object. If there is * an error, the result is an error message. * *---------------------------------------------------------------------- */ static int InfoCommandsCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { char *cmdName, *pattern; CONST char *simplePattern; register Tcl_HashEntry *entryPtr; Tcl_HashSearch search; Namespace *nsPtr; Namespace *globalNsPtr = (Namespace *) Tcl_GetGlobalNamespace(interp); Namespace *currNsPtr = (Namespace *) Tcl_GetCurrentNamespace(interp); Tcl_Obj *listPtr, *elemObjPtr; int specificNsInPattern = 0; /* Init. to avoid compiler warning. */ Tcl_Command cmd; /* * Get the pattern and find the "effective namespace" in which to * list commands. */ if (objc == 2) { simplePattern = NULL; nsPtr = currNsPtr; specificNsInPattern = 0; } else if (objc == 3) { /* * From the pattern, get the effective namespace and the simple * pattern (no namespace qualifiers or ::'s) at the end. If an * error was found while parsing the pattern, return it. Otherwise, * if the namespace wasn't found, just leave nsPtr NULL: we will * return an empty list since no commands there can be found. */ Namespace *dummy1NsPtr, *dummy2NsPtr; pattern = Tcl_GetString(objv[2]); TclGetNamespaceForQualName(interp, pattern, (Namespace *) NULL, /*flags*/ 0, &nsPtr, &dummy1NsPtr, &dummy2NsPtr, &simplePattern); if (nsPtr != NULL) { /* we successfully found the pattern's ns */ specificNsInPattern = (strcmp(simplePattern, pattern) != 0); } } else { Tcl_WrongNumArgs(interp, 2, objv, "?pattern?"); return TCL_ERROR; } /* * Exit as quickly as possible if we couldn't find the namespace. */ if (nsPtr == NULL) { return TCL_OK; } /* * Scan through the effective namespace's command table and create a * list with all commands that match the pattern. If a specific * namespace was requested in the pattern, qualify the command names * with the namespace name. */ listPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); if (simplePattern != NULL && TclMatchIsTrivial(simplePattern)) { /* * Special case for when the pattern doesn't include any of * glob's special characters. This lets us avoid scans of any * hash tables. */ entryPtr = Tcl_FindHashEntry(&nsPtr->cmdTable, simplePattern); if (entryPtr != NULL) { if (specificNsInPattern) { cmd = (Tcl_Command) Tcl_GetHashValue(entryPtr); elemObjPtr = Tcl_NewObj(); Tcl_GetCommandFullName(interp, cmd, elemObjPtr); } else { cmdName = Tcl_GetHashKey(&nsPtr->cmdTable, entryPtr); elemObjPtr = Tcl_NewStringObj(cmdName, -1); } Tcl_ListObjAppendElement(interp, listPtr, elemObjPtr); } else if ((nsPtr != globalNsPtr) && !specificNsInPattern) { entryPtr = Tcl_FindHashEntry(&globalNsPtr->cmdTable, simplePattern); if (entryPtr != NULL) { cmdName = Tcl_GetHashKey(&globalNsPtr->cmdTable, entryPtr); Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewStringObj(cmdName, -1)); } } } else { entryPtr = Tcl_FirstHashEntry(&nsPtr->cmdTable, &search); while (entryPtr != NULL) { cmdName = Tcl_GetHashKey(&nsPtr->cmdTable, entryPtr); if ((simplePattern == NULL) || Tcl_StringMatch(cmdName, simplePattern)) { if (specificNsInPattern) { cmd = (Tcl_Command) Tcl_GetHashValue(entryPtr); elemObjPtr = Tcl_NewObj(); Tcl_GetCommandFullName(interp, cmd, elemObjPtr); } else { elemObjPtr = Tcl_NewStringObj(cmdName, -1); } Tcl_ListObjAppendElement(interp, listPtr, elemObjPtr); } entryPtr = Tcl_NextHashEntry(&search); } /* * If the effective namespace isn't the global :: namespace, and a * specific namespace wasn't requested in the pattern, then add in * all global :: commands that match the simple pattern. Of course, * we add in only those commands that aren't hidden by a command in * the effective namespace. */ if ((nsPtr != globalNsPtr) && !specificNsInPattern) { entryPtr = Tcl_FirstHashEntry(&globalNsPtr->cmdTable, &search); while (entryPtr != NULL) { cmdName = Tcl_GetHashKey(&globalNsPtr->cmdTable, entryPtr); if ((simplePattern == NULL) || Tcl_StringMatch(cmdName, simplePattern)) { if (Tcl_FindHashEntry(&nsPtr->cmdTable, cmdName) == NULL) { Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewStringObj(cmdName, -1)); } } entryPtr = Tcl_NextHashEntry(&search); } } } Tcl_SetObjResult(interp, listPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * InfoCompleteCmd -- * * Called to implement the "info complete" command that determines * whether a string is a complete Tcl command. Handles the following * syntax: * * info complete command * * Results: * Returns TCL_OK if successful and TCL_ERROR if there is an error. * * Side effects: * Returns a result in the interpreter's result object. If there is * an error, the result is an error message. * *---------------------------------------------------------------------- */ static int InfoCompleteCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "command"); return TCL_ERROR; } if (TclObjCommandComplete(objv[2])) { Tcl_SetIntObj(Tcl_GetObjResult(interp), 1); } else { Tcl_SetIntObj(Tcl_GetObjResult(interp), 0); } return TCL_OK; } /* *---------------------------------------------------------------------- * * InfoDefaultCmd -- * * Called to implement the "info default" command that returns the * default value for a procedure argument. Handles the following * syntax: * * info default procName arg varName * * Results: * Returns TCL_OK if successful and TCL_ERROR if there is an error. * * Side effects: * Returns a result in the interpreter's result object. If there is * an error, the result is an error message. * *---------------------------------------------------------------------- */ static int InfoDefaultCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Interp *iPtr = (Interp *) interp; char *procName, *argName, *varName; Proc *procPtr; CompiledLocal *localPtr; Tcl_Obj *valueObjPtr; if (objc != 5) { Tcl_WrongNumArgs(interp, 2, objv, "procname arg varname"); return TCL_ERROR; } procName = Tcl_GetString(objv[2]); argName = Tcl_GetString(objv[3]); procPtr = TclFindProc(iPtr, procName); if (procPtr == NULL) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "\"", procName, "\" isn't a procedure", (char *) NULL); return TCL_ERROR; } for (localPtr = procPtr->firstLocalPtr; localPtr != NULL; localPtr = localPtr->nextPtr) { if (TclIsVarArgument(localPtr) && (strcmp(argName, localPtr->name) == 0)) { if (localPtr->defValuePtr != NULL) { valueObjPtr = Tcl_ObjSetVar2(interp, objv[4], NULL, localPtr->defValuePtr, 0); if (valueObjPtr == NULL) { defStoreError: varName = Tcl_GetString(objv[4]); Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "couldn't store default value in variable \"", varName, "\"", (char *) NULL); return TCL_ERROR; } Tcl_SetIntObj(Tcl_GetObjResult(interp), 1); } else { Tcl_Obj *nullObjPtr = Tcl_NewObj(); Tcl_IncrRefCount(nullObjPtr); valueObjPtr = Tcl_ObjSetVar2(interp, objv[4], NULL, nullObjPtr, 0); Tcl_DecrRefCount(nullObjPtr); /* free unneeded obj */ if (valueObjPtr == NULL) { goto defStoreError; } Tcl_SetIntObj(Tcl_GetObjResult(interp), 0); } return TCL_OK; } } Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "procedure \"", procName, "\" doesn't have an argument \"", argName, "\"", (char *) NULL); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * InfoExistsCmd -- * * Called to implement the "info exists" command that determines * whether a variable exists. Handles the following syntax: * * info exists varName * * Results: * Returns TCL_OK if successful and TCL_ERROR if there is an error. * * Side effects: * Returns a result in the interpreter's result object. If there is * an error, the result is an error message. * *---------------------------------------------------------------------- */ static int InfoExistsCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { char *varName; Var *varPtr; if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "varName"); return TCL_ERROR; } varName = Tcl_GetString(objv[2]); varPtr = TclVarTraceExists(interp, varName); if ((varPtr != NULL) && !TclIsVarUndefined(varPtr)) { Tcl_SetIntObj(Tcl_GetObjResult(interp), 1); } else { Tcl_SetIntObj(Tcl_GetObjResult(interp), 0); } return TCL_OK; } #ifdef TCL_TIP280 /* *---------------------------------------------------------------------- * * InfoFrameCmd -- * TIP #280 * * Called to implement the "info frame" command that returns the * location of either the currently executing command, or its caller. * Handles the following syntax: * * info frame ?number? * * Results: * Returns TCL_OK if successful and TCL_ERROR if there is an error. * * Side effects: * Returns a result in the interpreter's result object. If there is * an error, the result is an error message. * *---------------------------------------------------------------------- */ static int InfoFrameCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Interp *iPtr = (Interp *) interp; if (objc == 2) { /* just "info frame" */ int levels = (iPtr->cmdFramePtr == NULL ? 0 : iPtr->cmdFramePtr->level); Tcl_SetObjResult(interp, Tcl_NewIntObj (levels)); return TCL_OK; } else if (objc == 3) { /* "info frame level" */ int level; CmdFrame *framePtr; if (Tcl_GetIntFromObj(interp, objv[2], &level) != TCL_OK) { return TCL_ERROR; } if (level <= 0) { /* Relative adressing */ if (iPtr->cmdFramePtr == NULL) { levelError: Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "bad level \"", Tcl_GetString(objv[2]), "\"", (char *) NULL); return TCL_ERROR; } /* Convert to absolute. */ level += iPtr->cmdFramePtr->level; } for (framePtr = iPtr->cmdFramePtr; framePtr != NULL; framePtr = framePtr->nextPtr) { if (framePtr->level == level) { break; } } if (framePtr == NULL) { goto levelError; } /* * Pull the information and construct the dictionary to return, as * list. Regarding use of the CmdFrame fields see tclInt.h, and its * definition. */ { Tcl_Obj* lv [20]; /* Keep uptodate when more keys are added to the dict */ int lc = 0; /* This array is indexed by the TCL_LOCATION_... values, except * for _LAST. */ static CONST char* typeString [TCL_LOCATION_LAST] = { "eval", "eval", "eval", "precompiled", "source", "proc" }; Proc* procPtr = framePtr->framePtr ? framePtr->framePtr->procPtr : NULL; switch (framePtr->type) { case TCL_LOCATION_EVAL: /* Evaluation, dynamic script. Type, line, cmd, the latter * through str. */ lv [lc ++] = Tcl_NewStringObj ("type",-1); lv [lc ++] = Tcl_NewStringObj (typeString [framePtr->type],-1); lv [lc ++] = Tcl_NewStringObj ("line",-1); lv [lc ++] = Tcl_NewIntObj (framePtr->line[0]); lv [lc ++] = Tcl_NewStringObj ("cmd",-1); lv [lc ++] = Tcl_NewStringObj (framePtr->cmd.str.cmd, framePtr->cmd.str.len); break; case TCL_LOCATION_EVAL_LIST: /* List optimized evaluation. Type, line, cmd, the latter * through listPtr, possibly a frame. */ lv [lc ++] = Tcl_NewStringObj ("type",-1); lv [lc ++] = Tcl_NewStringObj (typeString [framePtr->type],-1); lv [lc ++] = Tcl_NewStringObj ("line",-1); lv [lc ++] = Tcl_NewIntObj (1); /* We put a duplicate of the command list obj into the result * to ensure that the 'pure List'-property of the command * itself is not destroyed. Otherwise the query here would * disable the list optimization path in Tcl_EvalObjEx. */ lv [lc ++] = Tcl_NewStringObj ("cmd",-1); lv [lc ++] = Tcl_DuplicateObj (framePtr->cmd.listPtr); break; case TCL_LOCATION_PREBC: /* Precompiled. Result contains the type as signal, nothing * else */ lv [lc ++] = Tcl_NewStringObj ("type",-1); lv [lc ++] = Tcl_NewStringObj (typeString [framePtr->type],-1); break; case TCL_LOCATION_BC: { /* Execution of bytecode. Talk to the BC engine to fill out * the frame. */ CmdFrame f = *framePtr; /* Note: Type BC => f.data.eval.path is not used. * f.data.tebc.codePtr is used instead. */ TclGetSrcInfoForPc (&f); /* Now filled: cmd.str.(cmd,len), line */ /* Possibly modified: type, path! */ lv [lc ++] = Tcl_NewStringObj ("type",-1); lv [lc ++] = Tcl_NewStringObj (typeString [f.type],-1); lv [lc ++] = Tcl_NewStringObj ("line",-1); lv [lc ++] = Tcl_NewIntObj (f.line[0]); if (f.type == TCL_LOCATION_SOURCE) { lv [lc ++] = Tcl_NewStringObj ("file",-1); lv [lc ++] = f.data.eval.path; /* Death of reference by TclGetSrcInfoForPc */ Tcl_DecrRefCount (f.data.eval.path); } lv [lc ++] = Tcl_NewStringObj ("cmd",-1); lv [lc ++] = Tcl_NewStringObj (f.cmd.str.cmd, f.cmd.str.len); break; } case TCL_LOCATION_SOURCE: /* Evaluation of a script file */ lv [lc ++] = Tcl_NewStringObj ("type",-1); lv [lc ++] = Tcl_NewStringObj (typeString [framePtr->type],-1); lv [lc ++] = Tcl_NewStringObj ("line",-1); lv [lc ++] = Tcl_NewIntObj (framePtr->line[0]); lv [lc ++] = Tcl_NewStringObj ("file",-1); lv [lc ++] = framePtr->data.eval.path; /* Refcount framePtr->data.eval.path goes up when lv * is converted into the result list object. */ lv [lc ++] = Tcl_NewStringObj ("cmd",-1); lv [lc ++] = Tcl_NewStringObj (framePtr->cmd.str.cmd, framePtr->cmd.str.len); break; case TCL_LOCATION_PROC: Tcl_Panic ("TCL_LOCATION_PROC found in standard frame"); break; } /* * 'proc'. Common to all frame types. Conditional on having an * associated Procedure CallFrame. */ if (procPtr != NULL) { Tcl_HashEntry* namePtr = procPtr->cmdPtr->hPtr; /* * ITcl seems to provide us with weird, maybe bogus Command * structures (methods?) which may have no HashEntry pointing * to the name information, or a HashEntry without owning * HashTable. Therefore check again that our data is valid. */ if (namePtr && namePtr->tablePtr) { char* procName = Tcl_GetHashKey (namePtr->tablePtr, namePtr); char* nsName = procPtr->cmdPtr->nsPtr->fullName; lv [lc ++] = Tcl_NewStringObj ("proc",-1); lv [lc ++] = Tcl_NewStringObj (nsName,-1); if (strcmp (nsName, "::") != 0) { Tcl_AppendToObj (lv [lc-1], "::", -1); } Tcl_AppendToObj (lv [lc-1], procName, -1); } } /* 'level'. Common to all frame types. Conditional on having an * associated _visible_ CallFrame */ if ((framePtr->framePtr != NULL) && (iPtr->varFramePtr != NULL)) { CallFrame* current = framePtr->framePtr; CallFrame* top = iPtr->varFramePtr; CallFrame* idx; for (idx = top; idx != NULL; idx = idx->callerVarPtr) { if (idx == current) { int c = framePtr->framePtr->level; int t = iPtr->varFramePtr->level; lv [lc ++] = Tcl_NewStringObj ("level",-1); lv [lc ++] = Tcl_NewIntObj (t - c); break; } } } Tcl_SetObjResult(interp, Tcl_NewListObj (lc, lv)); return TCL_OK; } } Tcl_WrongNumArgs(interp, 2, objv, "?number?"); return TCL_ERROR; } #endif /* *---------------------------------------------------------------------- * * InfoFunctionsCmd -- * * Called to implement the "info functions" command that returns the * list of math functions matching an optional pattern. Handles the * following syntax: * * info functions ?pattern? * * Results: * Returns TCL_OK if successful and TCL_ERROR if there is an error. * * Side effects: * Returns a result in the interpreter's result object. If there is * an error, the result is an error message. * *---------------------------------------------------------------------- */ static int InfoFunctionsCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { char *pattern; Tcl_Obj *listPtr; if (objc == 2) { pattern = NULL; } else if (objc == 3) { pattern = Tcl_GetString(objv[2]); } else { Tcl_WrongNumArgs(interp, 2, objv, "?pattern?"); return TCL_ERROR; } listPtr = Tcl_ListMathFuncs(interp, pattern); if (listPtr == NULL) { return TCL_ERROR; } Tcl_SetObjResult(interp, listPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * InfoGlobalsCmd -- * * Called to implement the "info globals" command that returns the list * of global variables matching an optional pattern. Handles the * following syntax: * * info globals ?pattern? * * Results: * Returns TCL_OK if successful and TCL_ERROR if there is an error. * * Side effects: * Returns a result in the interpreter's result object. If there is * an error, the result is an error message. * *---------------------------------------------------------------------- */ static int InfoGlobalsCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { char *varName, *pattern; Namespace *globalNsPtr = (Namespace *) Tcl_GetGlobalNamespace(interp); register Tcl_HashEntry *entryPtr; Tcl_HashSearch search; Var *varPtr; Tcl_Obj *listPtr; if (objc == 2) { pattern = NULL; } else if (objc == 3) { pattern = Tcl_GetString(objv[2]); /* * Strip leading global-namespace qualifiers. [Bug 1057461] */ if (pattern[0] == ':' && pattern[1] == ':') { while (*pattern == ':') { pattern++; } } } else { Tcl_WrongNumArgs(interp, 2, objv, "?pattern?"); return TCL_ERROR; } /* * Scan through the global :: namespace's variable table and create a * list of all global variables that match the pattern. */ listPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); if (pattern != NULL && TclMatchIsTrivial(pattern)) { entryPtr = Tcl_FindHashEntry(&globalNsPtr->varTable, pattern); if (entryPtr != NULL) { varPtr = (Var *) Tcl_GetHashValue(entryPtr); if (!TclIsVarUndefined(varPtr)) { Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewStringObj(pattern, -1)); } } } else { for (entryPtr = Tcl_FirstHashEntry(&globalNsPtr->varTable, &search); entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) { varPtr = (Var *) Tcl_GetHashValue(entryPtr); if (TclIsVarUndefined(varPtr)) { continue; } varName = Tcl_GetHashKey(&globalNsPtr->varTable, entryPtr); if ((pattern == NULL) || Tcl_StringMatch(varName, pattern)) { Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewStringObj(varName, -1)); } } } Tcl_SetObjResult(interp, listPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * InfoHostnameCmd -- * * Called to implement the "info hostname" command that returns the * host name. Handles the following syntax: * * info hostname * * Results: * Returns TCL_OK if successful and TCL_ERROR if there is an error. * * Side effects: * Returns a result in the interpreter's result object. If there is * an error, the result is an error message. * *---------------------------------------------------------------------- */ static int InfoHostnameCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { CONST char *name; if (objc != 2) { Tcl_WrongNumArgs(interp, 2, objv, NULL); return TCL_ERROR; } name = Tcl_GetHostName(); if (name) { Tcl_SetStringObj(Tcl_GetObjResult(interp), name, -1); return TCL_OK; } else { Tcl_SetStringObj(Tcl_GetObjResult(interp), "unable to determine name of host", -1); return TCL_ERROR; } } /* *---------------------------------------------------------------------- * * InfoLevelCmd -- * * Called to implement the "info level" command that returns * information about the call stack. Handles the following syntax: * * info level ?number? * * Results: * Returns TCL_OK if successful and TCL_ERROR if there is an error. * * Side effects: * Returns a result in the interpreter's result object. If there is * an error, the result is an error message. * *---------------------------------------------------------------------- */ static int InfoLevelCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Interp *iPtr = (Interp *) interp; int level; CallFrame *framePtr; Tcl_Obj *listPtr; if (objc == 2) { /* just "info level" */ if (iPtr->varFramePtr == NULL) { Tcl_SetIntObj(Tcl_GetObjResult(interp), 0); } else { Tcl_SetIntObj(Tcl_GetObjResult(interp), iPtr->varFramePtr->level); } return TCL_OK; } else if (objc == 3) { if (Tcl_GetIntFromObj(interp, objv[2], &level) != TCL_OK) { return TCL_ERROR; } if (level <= 0) { if (iPtr->varFramePtr == NULL) { levelError: Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "bad level \"", Tcl_GetString(objv[2]), "\"", (char *) NULL); return TCL_ERROR; } level += iPtr->varFramePtr->level; } for (framePtr = iPtr->varFramePtr; framePtr != NULL; framePtr = framePtr->callerVarPtr) { if (framePtr->level == level) { break; } } if (framePtr == NULL) { goto levelError; } listPtr = Tcl_NewListObj(framePtr->objc, framePtr->objv); Tcl_SetObjResult(interp, listPtr); return TCL_OK; } Tcl_WrongNumArgs(interp, 2, objv, "?number?"); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * InfoLibraryCmd -- * * Called to implement the "info library" command that returns the * library directory for the Tcl installation. Handles the following * syntax: * * info library * * Results: * Returns TCL_OK if successful and TCL_ERROR if there is an error. * * Side effects: * Returns a result in the interpreter's result object. If there is * an error, the result is an error message. * *---------------------------------------------------------------------- */ static int InfoLibraryCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { CONST char *libDirName; if (objc != 2) { Tcl_WrongNumArgs(interp, 2, objv, NULL); return TCL_ERROR; } libDirName = Tcl_GetVar(interp, "tcl_library", TCL_GLOBAL_ONLY); if (libDirName != NULL) { Tcl_SetStringObj(Tcl_GetObjResult(interp), libDirName, -1); return TCL_OK; } Tcl_SetStringObj(Tcl_GetObjResult(interp), "no library has been specified for Tcl", -1); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * InfoLoadedCmd -- * * Called to implement the "info loaded" command that returns the * packages that have been loaded into an interpreter. Handles the * following syntax: * * info loaded ?interp? * * Results: * Returns TCL_OK if successful and TCL_ERROR if there is an error. * * Side effects: * Returns a result in the interpreter's result object. If there is * an error, the result is an error message. * *---------------------------------------------------------------------- */ static int InfoLoadedCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { char *interpName; int result; if ((objc != 2) && (objc != 3)) { Tcl_WrongNumArgs(interp, 2, objv, "?interp?"); return TCL_ERROR; } if (objc == 2) { /* get loaded pkgs in all interpreters */ interpName = NULL; } else { /* get pkgs just in specified interp */ interpName = Tcl_GetString(objv[2]); } result = TclGetLoadedPackages(interp, interpName); return result; } /* *---------------------------------------------------------------------- * * InfoLocalsCmd -- * * Called to implement the "info locals" command to return a list of * local variables that match an optional pattern. Handles the * following syntax: * * info locals ?pattern? * * Results: * Returns TCL_OK if successful and TCL_ERROR if there is an error. * * Side effects: * Returns a result in the interpreter's result object. If there is * an error, the result is an error message. * *---------------------------------------------------------------------- */ static int InfoLocalsCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Interp *iPtr = (Interp *) interp; char *pattern; Tcl_Obj *listPtr; if (objc == 2) { pattern = NULL; } else if (objc == 3) { pattern = Tcl_GetString(objv[2]); } else { Tcl_WrongNumArgs(interp, 2, objv, "?pattern?"); return TCL_ERROR; } if (iPtr->varFramePtr == NULL || !iPtr->varFramePtr->isProcCallFrame) { return TCL_OK; } /* * Return a list containing names of first the compiled locals (i.e. the * ones stored in the call frame), then the variables in the local hash * table (if one exists). */ listPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); AppendLocals(interp, listPtr, pattern, 0); Tcl_SetObjResult(interp, listPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * AppendLocals -- * * Append the local variables for the current frame to the * specified list object. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void AppendLocals(interp, listPtr, pattern, includeLinks) Tcl_Interp *interp; /* Current interpreter. */ Tcl_Obj *listPtr; /* List object to append names to. */ CONST char *pattern; /* Pattern to match against. */ int includeLinks; /* 1 if upvars should be included, else 0. */ { Interp *iPtr = (Interp *) interp; CompiledLocal *localPtr; Var *varPtr; int i, localVarCt; char *varName; Tcl_HashTable *localVarTablePtr; register Tcl_HashEntry *entryPtr; Tcl_HashSearch search; localPtr = iPtr->varFramePtr->procPtr->firstLocalPtr; localVarCt = iPtr->varFramePtr->numCompiledLocals; varPtr = iPtr->varFramePtr->compiledLocals; localVarTablePtr = iPtr->varFramePtr->varTablePtr; for (i = 0; i < localVarCt; i++) { /* * Skip nameless (temporary) variables and undefined variables */ if (!TclIsVarTemporary(localPtr) && !TclIsVarUndefined(varPtr) && (includeLinks || !TclIsVarLink(varPtr))) { varName = varPtr->name; if ((pattern == NULL) || Tcl_StringMatch(varName, pattern)) { Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewStringObj(varName, -1)); } } varPtr++; localPtr = localPtr->nextPtr; } if (localVarTablePtr != NULL) { for (entryPtr = Tcl_FirstHashEntry(localVarTablePtr, &search); entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) { varPtr = (Var *) Tcl_GetHashValue(entryPtr); if (!TclIsVarUndefined(varPtr) && (includeLinks || !TclIsVarLink(varPtr))) { varName = Tcl_GetHashKey(localVarTablePtr, entryPtr); if ((pattern == NULL) || Tcl_StringMatch(varName, pattern)) { Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewStringObj(varName, -1)); } } } } } /* *---------------------------------------------------------------------- * * InfoNameOfExecutableCmd -- * * Called to implement the "info nameofexecutable" command that returns * the name of the binary file running this application. Handles the * following syntax: * * info nameofexecutable * * Results: * Returns TCL_OK if successful and TCL_ERROR if there is an error. * * Side effects: * Returns a result in the interpreter's result object. If there is * an error, the result is an error message. * *---------------------------------------------------------------------- */ static int InfoNameOfExecutableCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { CONST char *nameOfExecutable; if (objc != 2) { Tcl_WrongNumArgs(interp, 2, objv, NULL); return TCL_ERROR; } nameOfExecutable = Tcl_GetNameOfExecutable(); if (nameOfExecutable != NULL) { Tcl_SetStringObj(Tcl_GetObjResult(interp), nameOfExecutable, -1); } return TCL_OK; } /* *---------------------------------------------------------------------- * * InfoPatchLevelCmd -- * * Called to implement the "info patchlevel" command that returns the * default value for an argument to a procedure. Handles the following * syntax: * * info patchlevel * * Results: * Returns TCL_OK if successful and TCL_ERROR if there is an error. * * Side effects: * Returns a result in the interpreter's result object. If there is * an error, the result is an error message. * *---------------------------------------------------------------------- */ static int InfoPatchLevelCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { CONST char *patchlevel; if (objc != 2) { Tcl_WrongNumArgs(interp, 2, objv, NULL); return TCL_ERROR; } patchlevel = Tcl_GetVar(interp, "tcl_patchLevel", (TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG)); if (patchlevel != NULL) { Tcl_SetStringObj(Tcl_GetObjResult(interp), patchlevel, -1); return TCL_OK; } return TCL_ERROR; } /* *---------------------------------------------------------------------- * * InfoProcsCmd -- * * Called to implement the "info procs" command that returns the * list of procedures in the interpreter that match an optional pattern. * The pattern, if any, consists of an optional sequence of namespace * names separated by "::" qualifiers, which is followed by a * glob-style pattern that restricts which commands are returned. * Handles the following syntax: * * info procs ?pattern? * * Results: * Returns TCL_OK if successful and TCL_ERROR if there is an error. * * Side effects: * Returns a result in the interpreter's result object. If there is * an error, the result is an error message. * *---------------------------------------------------------------------- */ static int InfoProcsCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { char *cmdName, *pattern; CONST char *simplePattern; Namespace *nsPtr; #ifdef INFO_PROCS_SEARCH_GLOBAL_NS Namespace *globalNsPtr = (Namespace *) Tcl_GetGlobalNamespace(interp); #endif Namespace *currNsPtr = (Namespace *) Tcl_GetCurrentNamespace(interp); Tcl_Obj *listPtr, *elemObjPtr; int specificNsInPattern = 0; /* Init. to avoid compiler warning. */ register Tcl_HashEntry *entryPtr; Tcl_HashSearch search; Command *cmdPtr, *realCmdPtr; /* * Get the pattern and find the "effective namespace" in which to * list procs. */ if (objc == 2) { simplePattern = NULL; nsPtr = currNsPtr; specificNsInPattern = 0; } else if (objc == 3) { /* * From the pattern, get the effective namespace and the simple * pattern (no namespace qualifiers or ::'s) at the end. If an * error was found while parsing the pattern, return it. Otherwise, * if the namespace wasn't found, just leave nsPtr NULL: we will * return an empty list since no commands there can be found. */ Namespace *dummy1NsPtr, *dummy2NsPtr; pattern = Tcl_GetString(objv[2]); TclGetNamespaceForQualName(interp, pattern, (Namespace *) NULL, /*flags*/ 0, &nsPtr, &dummy1NsPtr, &dummy2NsPtr, &simplePattern); if (nsPtr != NULL) { /* we successfully found the pattern's ns */ specificNsInPattern = (strcmp(simplePattern, pattern) != 0); } } else { Tcl_WrongNumArgs(interp, 2, objv, "?pattern?"); return TCL_ERROR; } if (nsPtr == NULL) { return TCL_OK; } /* * Scan through the effective namespace's command table and create a * list with all procs that match the pattern. If a specific * namespace was requested in the pattern, qualify the command names * with the namespace name. */ listPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); #ifndef INFO_PROCS_SEARCH_GLOBAL_NS if (simplePattern != NULL && TclMatchIsTrivial(simplePattern)) { entryPtr = Tcl_FindHashEntry(&nsPtr->cmdTable, simplePattern); if (entryPtr != NULL) { cmdPtr = (Command *) Tcl_GetHashValue(entryPtr); if (!TclIsProc(cmdPtr)) { realCmdPtr = (Command *) TclGetOriginalCommand((Tcl_Command) cmdPtr); if (realCmdPtr != NULL && TclIsProc(realCmdPtr)) { goto simpleProcOK; } } else { simpleProcOK: if (specificNsInPattern) { elemObjPtr = Tcl_NewObj(); Tcl_GetCommandFullName(interp, (Tcl_Command) cmdPtr, elemObjPtr); } else { elemObjPtr = Tcl_NewStringObj(simplePattern, -1); } Tcl_ListObjAppendElement(interp, listPtr, elemObjPtr); } } } else #endif /* !INFO_PROCS_SEARCH_GLOBAL_NS */ { entryPtr = Tcl_FirstHashEntry(&nsPtr->cmdTable, &search); while (entryPtr != NULL) { cmdName = Tcl_GetHashKey(&nsPtr->cmdTable, entryPtr); if ((simplePattern == NULL) || Tcl_StringMatch(cmdName, simplePattern)) { cmdPtr = (Command *) Tcl_GetHashValue(entryPtr); if (!TclIsProc(cmdPtr)) { realCmdPtr = (Command *) TclGetOriginalCommand((Tcl_Command) cmdPtr); if (realCmdPtr != NULL && TclIsProc(realCmdPtr)) { goto procOK; } } else { procOK: if (specificNsInPattern) { elemObjPtr = Tcl_NewObj(); Tcl_GetCommandFullName(interp, (Tcl_Command) cmdPtr, elemObjPtr); } else { elemObjPtr = Tcl_NewStringObj(cmdName, -1); } Tcl_ListObjAppendElement(interp, listPtr, elemObjPtr); } } entryPtr = Tcl_NextHashEntry(&search); } /* * If the effective namespace isn't the global :: namespace, and a * specific namespace wasn't requested in the pattern, then add in * all global :: procs that match the simple pattern. Of course, * we add in only those procs that aren't hidden by a proc in * the effective namespace. */ #ifdef INFO_PROCS_SEARCH_GLOBAL_NS /* * If "info procs" worked like "info commands", returning the * commands also seen in the global namespace, then you would * include this code. As this could break backwards compatibilty * with 8.0-8.2, we decided not to "fix" it in 8.3, leaving the * behavior slightly different. */ if ((nsPtr != globalNsPtr) && !specificNsInPattern) { entryPtr = Tcl_FirstHashEntry(&globalNsPtr->cmdTable, &search); while (entryPtr != NULL) { cmdName = Tcl_GetHashKey(&globalNsPtr->cmdTable, entryPtr); if ((simplePattern == NULL) || Tcl_StringMatch(cmdName, simplePattern)) { if (Tcl_FindHashEntry(&nsPtr->cmdTable, cmdName) == NULL) { cmdPtr = (Command *) Tcl_GetHashValue(entryPtr); realCmdPtr = (Command *) TclGetOriginalCommand( (Tcl_Command) cmdPtr); if (TclIsProc(cmdPtr) || ((realCmdPtr != NULL) && TclIsProc(realCmdPtr))) { Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewStringObj(cmdName, -1)); } } } entryPtr = Tcl_NextHashEntry(&search); } } #endif } Tcl_SetObjResult(interp, listPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * InfoScriptCmd -- * * Called to implement the "info script" command that returns the * script file that is currently being evaluated. Handles the * following syntax: * * info script ?newName? * * If newName is specified, it will set that as the internal name. * * Results: * Returns TCL_OK if successful and TCL_ERROR if there is an error. * * Side effects: * Returns a result in the interpreter's result object. If there is * an error, the result is an error message. It may change the * internal script filename. * *---------------------------------------------------------------------- */ static int InfoScriptCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Interp *iPtr = (Interp *) interp; if ((objc != 2) && (objc != 3)) { Tcl_WrongNumArgs(interp, 2, objv, "?filename?"); return TCL_ERROR; } if (objc == 3) { if (iPtr->scriptFile != NULL) { Tcl_DecrRefCount(iPtr->scriptFile); } iPtr->scriptFile = objv[2]; Tcl_IncrRefCount(iPtr->scriptFile); } if (iPtr->scriptFile != NULL) { Tcl_SetObjResult(interp, iPtr->scriptFile); } return TCL_OK; } /* *---------------------------------------------------------------------- * * InfoSharedlibCmd -- * * Called to implement the "info sharedlibextension" command that * returns the file extension used for shared libraries. Handles the * following syntax: * * info sharedlibextension * * Results: * Returns TCL_OK if successful and TCL_ERROR if there is an error. * * Side effects: * Returns a result in the interpreter's result object. If there is * an error, the result is an error message. * *---------------------------------------------------------------------- */ static int InfoSharedlibCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { if (objc != 2) { Tcl_WrongNumArgs(interp, 2, objv, NULL); return TCL_ERROR; } #ifdef TCL_SHLIB_EXT Tcl_SetStringObj(Tcl_GetObjResult(interp), TCL_SHLIB_EXT, -1); #endif return TCL_OK; } /* *---------------------------------------------------------------------- * * InfoTclVersionCmd -- * * Called to implement the "info tclversion" command that returns the * version number for this Tcl library. Handles the following syntax: * * info tclversion * * Results: * Returns TCL_OK if successful and TCL_ERROR if there is an error. * * Side effects: * Returns a result in the interpreter's result object. If there is * an error, the result is an error message. * *---------------------------------------------------------------------- */ static int InfoTclVersionCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { CONST char *version; if (objc != 2) { Tcl_WrongNumArgs(interp, 2, objv, NULL); return TCL_ERROR; } version = Tcl_GetVar(interp, "tcl_version", (TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG)); if (version != NULL) { Tcl_SetStringObj(Tcl_GetObjResult(interp), version, -1); return TCL_OK; } return TCL_ERROR; } /* *---------------------------------------------------------------------- * * InfoVarsCmd -- * * Called to implement the "info vars" command that returns the * list of variables in the interpreter that match an optional pattern. * The pattern, if any, consists of an optional sequence of namespace * names separated by "::" qualifiers, which is followed by a * glob-style pattern that restricts which variables are returned. * Handles the following syntax: * * info vars ?pattern? * * Results: * Returns TCL_OK if successful and TCL_ERROR if there is an error. * * Side effects: * Returns a result in the interpreter's result object. If there is * an error, the result is an error message. * *---------------------------------------------------------------------- */ static int InfoVarsCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Interp *iPtr = (Interp *) interp; char *varName, *pattern; CONST char *simplePattern; register Tcl_HashEntry *entryPtr; Tcl_HashSearch search; Var *varPtr; Namespace *nsPtr; Namespace *globalNsPtr = (Namespace *) Tcl_GetGlobalNamespace(interp); Namespace *currNsPtr = (Namespace *) Tcl_GetCurrentNamespace(interp); Tcl_Obj *listPtr, *elemObjPtr; int specificNsInPattern = 0; /* Init. to avoid compiler warning. */ /* * Get the pattern and find the "effective namespace" in which to * list variables. We only use this effective namespace if there's * no active Tcl procedure frame. */ if (objc == 2) { simplePattern = NULL; nsPtr = currNsPtr; specificNsInPattern = 0; } else if (objc == 3) { /* * From the pattern, get the effective namespace and the simple * pattern (no namespace qualifiers or ::'s) at the end. If an * error was found while parsing the pattern, return it. Otherwise, * if the namespace wasn't found, just leave nsPtr NULL: we will * return an empty list since no variables there can be found. */ Namespace *dummy1NsPtr, *dummy2NsPtr; pattern = Tcl_GetString(objv[2]); TclGetNamespaceForQualName(interp, pattern, (Namespace *) NULL, /*flags*/ 0, &nsPtr, &dummy1NsPtr, &dummy2NsPtr, &simplePattern); if (nsPtr != NULL) { /* we successfully found the pattern's ns */ specificNsInPattern = (strcmp(simplePattern, pattern) != 0); } } else { Tcl_WrongNumArgs(interp, 2, objv, "?pattern?"); return TCL_ERROR; } /* * If the namespace specified in the pattern wasn't found, just return. */ if (nsPtr == NULL) { return TCL_OK; } listPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); if ((iPtr->varFramePtr == NULL) || !iPtr->varFramePtr->isProcCallFrame || specificNsInPattern) { /* * There is no frame pointer, the frame pointer was pushed only * to activate a namespace, or we are in a procedure call frame * but a specific namespace was specified. Create a list containing * only the variables in the effective namespace's variable table. */ if (simplePattern != NULL && TclMatchIsTrivial(simplePattern)) { /* * If we can just do hash lookups, that simplifies things * a lot. */ entryPtr = Tcl_FindHashEntry(&nsPtr->varTable, simplePattern); if (entryPtr != NULL) { varPtr = (Var *) Tcl_GetHashValue(entryPtr); if (!TclIsVarUndefined(varPtr) || (varPtr->flags & VAR_NAMESPACE_VAR)) { if (specificNsInPattern) { elemObjPtr = Tcl_NewObj(); Tcl_GetVariableFullName(interp, (Tcl_Var) varPtr, elemObjPtr); } else { elemObjPtr = Tcl_NewStringObj(simplePattern, -1); } Tcl_ListObjAppendElement(interp, listPtr, elemObjPtr); } } else if ((nsPtr != globalNsPtr) && !specificNsInPattern) { entryPtr = Tcl_FindHashEntry(&globalNsPtr->varTable, simplePattern); if (entryPtr != NULL) { varPtr = (Var *) Tcl_GetHashValue(entryPtr); if (!TclIsVarUndefined(varPtr) || (varPtr->flags & VAR_NAMESPACE_VAR)) { Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewStringObj(simplePattern, -1)); } } } } else { /* * Have to scan the tables of variables. */ entryPtr = Tcl_FirstHashEntry(&nsPtr->varTable, &search); while (entryPtr != NULL) { varPtr = (Var *) Tcl_GetHashValue(entryPtr); if (!TclIsVarUndefined(varPtr) || (varPtr->flags & VAR_NAMESPACE_VAR)) { varName = Tcl_GetHashKey(&nsPtr->varTable, entryPtr); if ((simplePattern == NULL) || Tcl_StringMatch(varName, simplePattern)) { if (specificNsInPattern) { elemObjPtr = Tcl_NewObj(); Tcl_GetVariableFullName(interp, (Tcl_Var) varPtr, elemObjPtr); } else { elemObjPtr = Tcl_NewStringObj(varName, -1); } Tcl_ListObjAppendElement(interp, listPtr, elemObjPtr); } } entryPtr = Tcl_NextHashEntry(&search); } /* * If the effective namespace isn't the global :: * namespace, and a specific namespace wasn't requested in * the pattern (i.e., the pattern only specifies variable * names), then add in all global :: variables that match * the simple pattern. Of course, add in only those * variables that aren't hidden by a variable in the * effective namespace. */ if ((nsPtr != globalNsPtr) && !specificNsInPattern) { entryPtr = Tcl_FirstHashEntry(&globalNsPtr->varTable, &search); while (entryPtr != NULL) { varPtr = (Var *) Tcl_GetHashValue(entryPtr); if (!TclIsVarUndefined(varPtr) || (varPtr->flags & VAR_NAMESPACE_VAR)) { varName = Tcl_GetHashKey(&globalNsPtr->varTable, entryPtr); if ((simplePattern == NULL) || Tcl_StringMatch(varName, simplePattern)) { if (Tcl_FindHashEntry(&nsPtr->varTable, varName) == NULL) { Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewStringObj(varName, -1)); } } } entryPtr = Tcl_NextHashEntry(&search); } } } } else if (((Interp *)interp)->varFramePtr->procPtr != NULL) { AppendLocals(interp, listPtr, simplePattern, 1); } Tcl_SetObjResult(interp, listPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_JoinObjCmd -- * * This procedure is invoked to process the "join" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl object result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_JoinObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* The argument objects. */ { char *joinString, *bytes; int joinLength, listLen, length, i, result; Tcl_Obj **elemPtrs; Tcl_Obj *resObjPtr; if (objc == 2) { joinString = " "; joinLength = 1; } else if (objc == 3) { joinString = Tcl_GetStringFromObj(objv[2], &joinLength); } else { Tcl_WrongNumArgs(interp, 1, objv, "list ?joinString?"); return TCL_ERROR; } /* * Make sure the list argument is a list object and get its length and * a pointer to its array of element pointers. */ result = Tcl_ListObjGetElements(interp, objv[1], &listLen, &elemPtrs); if (result != TCL_OK) { return result; } /* * Now concatenate strings to form the "joined" result. We append * directly into the interpreter's result object. */ resObjPtr = Tcl_GetObjResult(interp); for (i = 0; i < listLen; i++) { bytes = Tcl_GetStringFromObj(elemPtrs[i], &length); if (i > 0) { Tcl_AppendToObj(resObjPtr, joinString, joinLength); } Tcl_AppendToObj(resObjPtr, bytes, length); } return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_LindexObjCmd -- * * This object-based procedure is invoked to process the "lindex" Tcl * command. See the user documentation for details on what it does. * * Results: * A standard Tcl object result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_LindexObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Tcl_Obj *elemPtr; /* Pointer to the element being extracted */ if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "list ?index...?"); return TCL_ERROR; } /* * If objc == 3, then objv[ 2 ] may be either a single index or * a list of indices: go to TclLindexList to determine which. * If objc >= 4, or objc == 2, then objv[ 2 .. objc-2 ] are all * single indices and processed as such in TclLindexFlat. */ if ( objc == 3 ) { elemPtr = TclLindexList( interp, objv[ 1 ], objv[ 2 ] ); } else { elemPtr = TclLindexFlat( interp, objv[ 1 ], objc-2, objv+2 ); } /* * Set the interpreter's object result to the last element extracted */ if ( elemPtr == NULL ) { return TCL_ERROR; } else { Tcl_SetObjResult(interp, elemPtr); Tcl_DecrRefCount( elemPtr ); return TCL_OK; } } /* *---------------------------------------------------------------------- * * TclLindexList -- * * This procedure handles the 'lindex' command when objc==3. * * Results: * Returns a pointer to the object extracted, or NULL if an * error occurred. * * Side effects: * None. * * If objv[1] can be parsed as a list, TclLindexList handles extraction * of the desired element locally. Otherwise, it invokes * TclLindexFlat to treat objv[1] as a scalar. * * The reference count of the returned object includes one reference * corresponding to the pointer returned. Thus, the calling code will * usually do something like: * Tcl_SetObjResult( interp, result ); * Tcl_DecrRefCount( result ); * *---------------------------------------------------------------------- */ Tcl_Obj * TclLindexList( interp, listPtr, argPtr ) Tcl_Interp* interp; /* Tcl interpreter */ Tcl_Obj* listPtr; /* List being unpacked */ Tcl_Obj* argPtr; /* Index or index list */ { Tcl_Obj **elemPtrs; /* Elements of the list being manipulated. */ int listLen; /* Length of the list being manipulated. */ int index; /* Index into the list */ int result; /* Result returned from a Tcl library call */ int i; /* Current index number */ Tcl_Obj** indices; /* Array of list indices */ int indexCount; /* Size of the array of list indices */ Tcl_Obj* oldListPtr; /* Temp location to preserve the list * pointer when replacing it with a sublist */ /* * Determine whether argPtr designates a list or a single index. * We have to be careful about the order of the checks to avoid * repeated shimmering; see TIP#22 and TIP#33 for the details. */ if ( argPtr->typePtr != &tclListType && TclGetIntForIndex( NULL , argPtr, 0, &index ) == TCL_OK ) { /* * argPtr designates a single index. */ return TclLindexFlat( interp, listPtr, 1, &argPtr ); } else if ( Tcl_ListObjGetElements( NULL, argPtr, &indexCount, &indices ) != TCL_OK ) { /* * argPtr designates something that is neither an index nor a * well-formed list. Report the error via TclLindexFlat. */ return TclLindexFlat( interp, listPtr, 1, &argPtr ); } /* * Record the reference to the list that we are maintaining in * the activation record. */ Tcl_IncrRefCount( listPtr ); /* * argPtr designates a list, and the 'else if' above has parsed it * into indexCount and indices. */ for ( i = 0; i < indexCount; ++i ) { /* * Convert the current listPtr to a list if necessary. */ result = Tcl_ListObjGetElements( interp, listPtr, &listLen, &elemPtrs); if (result != TCL_OK) { Tcl_DecrRefCount( listPtr ); return NULL; } /* * Get the index from indices[ i ] */ result = TclGetIntForIndex( interp, indices[ i ], /*endValue*/ (listLen - 1), &index ); if ( result != TCL_OK ) { /* * Index could not be parsed */ Tcl_DecrRefCount( listPtr ); return NULL; } else if ( index < 0 || index >= listLen ) { /* * Index is out of range */ Tcl_DecrRefCount( listPtr ); listPtr = Tcl_NewObj(); Tcl_IncrRefCount( listPtr ); return listPtr; } /* * Make sure listPtr still refers to a list object. * If it shared a Tcl_Obj structure with the arguments, then * it might have just been converted to something else. */ if (listPtr->typePtr != &tclListType) { result = Tcl_ListObjGetElements(interp, listPtr, &listLen, &elemPtrs); if (result != TCL_OK) { Tcl_DecrRefCount( listPtr ); return NULL; } } /* * Extract the pointer to the appropriate element */ oldListPtr = listPtr; listPtr = elemPtrs[ index ]; Tcl_IncrRefCount( listPtr ); Tcl_DecrRefCount( oldListPtr ); /* * The work we did above may have caused the internal rep * of *argPtr to change to something else. Get it back. */ result = Tcl_ListObjGetElements( interp, argPtr, &indexCount, &indices ); if ( result != TCL_OK ) { /* * This can't happen unless some extension corrupted a Tcl_Obj. */ Tcl_DecrRefCount( listPtr ); return NULL; } } /* end for */ /* * Return the last object extracted. Its reference count will include * the reference being returned. */ return listPtr; } /* *---------------------------------------------------------------------- * * TclLindexFlat -- * * This procedure handles the 'lindex' command, given that the * arguments to the command are known to be a flat list. * * Results: * Returns a standard Tcl result. * * Side effects: * None. * * This procedure is called from either tclExecute.c or * Tcl_LindexObjCmd whenever either is presented with * objc == 2 or objc >= 4. It is also called from TclLindexList * for the objc==3 case once it is determined that objv[2] cannot * be parsed as a list. * *---------------------------------------------------------------------- */ Tcl_Obj * TclLindexFlat( interp, listPtr, indexCount, indexArray ) Tcl_Interp* interp; /* Tcl interpreter */ Tcl_Obj* listPtr; /* Tcl object representing the list */ int indexCount; /* Count of indices */ Tcl_Obj* CONST indexArray[]; /* Array of pointers to Tcl objects * representing the indices in the * list */ { int i; /* Current list index */ int result; /* Result of Tcl library calls */ int listLen; /* Length of the current list being * processed */ Tcl_Obj** elemPtrs; /* Array of pointers to the elements * of the current list */ int index; /* Parsed version of the current element * of indexArray */ Tcl_Obj* oldListPtr; /* Temporary to hold listPtr so that * its ref count can be decremented. */ /* * Record the reference to the 'listPtr' object that we are * maintaining in the C activation record. */ Tcl_IncrRefCount( listPtr ); for ( i = 0; i < indexCount; ++i ) { /* * Convert the current listPtr to a list if necessary. */ result = Tcl_ListObjGetElements(interp, listPtr, &listLen, &elemPtrs); if (result != TCL_OK) { Tcl_DecrRefCount( listPtr ); return NULL; } /* * Get the index from objv[i] */ result = TclGetIntForIndex( interp, indexArray[ i ], /*endValue*/ (listLen - 1), &index ); if ( result != TCL_OK ) { /* Index could not be parsed */ Tcl_DecrRefCount( listPtr ); return NULL; } else if ( index < 0 || index >= listLen ) { /* * Index is out of range */ Tcl_DecrRefCount( listPtr ); listPtr = Tcl_NewObj(); Tcl_IncrRefCount( listPtr ); return listPtr; } /* * Make sure listPtr still refers to a list object. * It might have been converted to something else above * if objv[1] overlaps with one of the other parameters. */ if (listPtr->typePtr != &tclListType) { result = Tcl_ListObjGetElements(interp, listPtr, &listLen, &elemPtrs); if (result != TCL_OK) { Tcl_DecrRefCount( listPtr ); return NULL; } } /* * Extract the pointer to the appropriate element */ oldListPtr = listPtr; listPtr = elemPtrs[ index ]; Tcl_IncrRefCount( listPtr ); Tcl_DecrRefCount( oldListPtr ); } return listPtr; } /* *---------------------------------------------------------------------- * * Tcl_LinsertObjCmd -- * * This object-based procedure is invoked to process the "linsert" Tcl * command. See the user documentation for details on what it does. * * Results: * A new Tcl list object formed by inserting zero or more elements * into a list. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_LinsertObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ register int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Tcl_Obj *listPtr; int index, isDuplicate, len, result; if (objc < 4) { Tcl_WrongNumArgs(interp, 1, objv, "list index element ?element ...?"); return TCL_ERROR; } result = Tcl_ListObjLength(interp, objv[1], &len); if (result != TCL_OK) { return result; } /* * Get the index. "end" is interpreted to be the index after the last * element, such that using it will cause any inserted elements to be * appended to the list. */ result = TclGetIntForIndex(interp, objv[2], /*end*/ len, &index); if (result != TCL_OK) { return result; } if (index > len) { index = len; } /* * If the list object is unshared we can modify it directly. Otherwise * we create a copy to modify: this is "copy on write". */ listPtr = objv[1]; isDuplicate = 0; if (Tcl_IsShared(listPtr)) { listPtr = Tcl_DuplicateObj(listPtr); isDuplicate = 1; } if ((objc == 4) && (index == len)) { /* * Special case: insert one element at the end of the list. */ result = Tcl_ListObjAppendElement(interp, listPtr, objv[3]); } else if (objc > 3) { result = Tcl_ListObjReplace(interp, listPtr, index, 0, (objc-3), &(objv[3])); } if (result != TCL_OK) { if (isDuplicate) { Tcl_DecrRefCount(listPtr); /* free unneeded obj */ } return result; } /* * Set the interpreter's object result. */ Tcl_SetObjResult(interp, listPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_ListObjCmd -- * * This procedure is invoked to process the "list" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl object result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_ListObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ register int objc; /* Number of arguments. */ register Tcl_Obj *CONST objv[]; /* The argument objects. */ { /* * If there are no list elements, the result is an empty object. * Otherwise modify the interpreter's result object to be a list object. */ if (objc > 1) { Tcl_SetListObj(Tcl_GetObjResult(interp), (objc-1), &(objv[1])); } return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_LlengthObjCmd -- * * This object-based procedure is invoked to process the "llength" Tcl * command. See the user documentation for details on what it does. * * Results: * A standard Tcl object result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_LlengthObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ register Tcl_Obj *CONST objv[]; /* Argument objects. */ { int listLen, result; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "list"); return TCL_ERROR; } result = Tcl_ListObjLength(interp, objv[1], &listLen); if (result != TCL_OK) { return result; } /* * Set the interpreter's object result to an integer object holding the * length. */ Tcl_SetIntObj(Tcl_GetObjResult(interp), listLen); return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_LrangeObjCmd -- * * This procedure is invoked to process the "lrange" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl object result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_LrangeObjCmd(notUsed, interp, objc, objv) ClientData notUsed; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ register Tcl_Obj *CONST objv[]; /* Argument objects. */ { Tcl_Obj *listPtr; Tcl_Obj **elemPtrs; int listLen, first, last, numElems, result; if (objc != 4) { Tcl_WrongNumArgs(interp, 1, objv, "list first last"); return TCL_ERROR; } /* * Make sure the list argument is a list object and get its length and * a pointer to its array of element pointers. */ listPtr = objv[1]; result = Tcl_ListObjGetElements(interp, listPtr, &listLen, &elemPtrs); if (result != TCL_OK) { return result; } /* * Get the first and last indexes. */ result = TclGetIntForIndex(interp, objv[2], /*endValue*/ (listLen - 1), &first); if (result != TCL_OK) { return result; } if (first < 0) { first = 0; } result = TclGetIntForIndex(interp, objv[3], /*endValue*/ (listLen - 1), &last); if (result != TCL_OK) { return result; } if (last >= listLen) { last = (listLen - 1); } if (first > last) { return TCL_OK; /* the result is an empty object */ } /* * Make sure listPtr still refers to a list object. It might have been * converted to an int above if the argument objects were shared. */ if (listPtr->typePtr != &tclListType) { result = Tcl_ListObjGetElements(interp, listPtr, &listLen, &elemPtrs); if (result != TCL_OK) { return result; } } /* * Extract a range of fields. We modify the interpreter's result object * to be a list object containing the specified elements. */ numElems = (last - first + 1); Tcl_SetListObj(Tcl_GetObjResult(interp), numElems, &(elemPtrs[first])); return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_LreplaceObjCmd -- * * This object-based procedure is invoked to process the "lreplace" * Tcl command. See the user documentation for details on what it does. * * Results: * A new Tcl list object formed by replacing zero or more elements of * a list. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_LreplaceObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { register Tcl_Obj *listPtr; int isDuplicate, first, last, listLen, numToDelete, result; if (objc < 4) { Tcl_WrongNumArgs(interp, 1, objv, "list first last ?element element ...?"); return TCL_ERROR; } result = Tcl_ListObjLength(interp, objv[1], &listLen); if (result != TCL_OK) { return result; } /* * Get the first and last indexes. "end" is interpreted to be the index * for the last element, such that using it will cause that element to * be included for deletion. */ result = TclGetIntForIndex(interp, objv[2], /*end*/ (listLen - 1), &first); if (result != TCL_OK) { return result; } result = TclGetIntForIndex(interp, objv[3], /*end*/ (listLen - 1), &last); if (result != TCL_OK) { return result; } if (first < 0) { first = 0; } /* * Complain if the user asked for a start element that is greater than the * list length. This won't ever trigger for the "end*" case as that will * be properly constrained by TclGetIntForIndex because we use listLen-1 * (to allow for replacing the last elem). */ if ((first >= listLen) && (listLen > 0)) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "list doesn't contain element ", Tcl_GetString(objv[2]), (int *) NULL); return TCL_ERROR; } if (last >= listLen) { last = (listLen - 1); } if (first <= last) { numToDelete = (last - first + 1); } else { numToDelete = 0; } /* * If the list object is unshared we can modify it directly, otherwise * we create a copy to modify: this is "copy on write". */ listPtr = objv[1]; isDuplicate = 0; if (Tcl_IsShared(listPtr)) { listPtr = Tcl_DuplicateObj(listPtr); isDuplicate = 1; } if (objc > 4) { result = Tcl_ListObjReplace(interp, listPtr, first, numToDelete, (objc-4), &(objv[4])); } else { result = Tcl_ListObjReplace(interp, listPtr, first, numToDelete, 0, NULL); } if (result != TCL_OK) { if (isDuplicate) { Tcl_DecrRefCount(listPtr); /* free unneeded obj */ } return result; } /* * Set the interpreter's object result. */ Tcl_SetObjResult(interp, listPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_LsearchObjCmd -- * * This procedure is invoked to process the "lsearch" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ int Tcl_LsearchObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument values. */ { char *bytes, *patternBytes; int i, match, mode, index, result, listc, length, elemLen; int dataType, isIncreasing, lower, upper, patInt, objInt; int offset, allMatches, inlineReturn, negatedMatch; double patDouble, objDouble; Tcl_Obj *patObj, **listv, *listPtr, *startPtr; Tcl_RegExp regexp = NULL; static CONST char *options[] = { "-all", "-ascii", "-decreasing", "-dictionary", "-exact", "-glob", "-increasing", "-inline", "-integer", "-not", "-real", "-regexp", "-sorted", "-start", NULL }; enum options { LSEARCH_ALL, LSEARCH_ASCII, LSEARCH_DECREASING, LSEARCH_DICTIONARY, LSEARCH_EXACT, LSEARCH_GLOB, LSEARCH_INCREASING, LSEARCH_INLINE, LSEARCH_INTEGER, LSEARCH_NOT, LSEARCH_REAL, LSEARCH_REGEXP, LSEARCH_SORTED, LSEARCH_START }; enum datatypes { ASCII, DICTIONARY, INTEGER, REAL }; enum modes { EXACT, GLOB, REGEXP, SORTED }; mode = GLOB; dataType = ASCII; isIncreasing = 1; allMatches = 0; inlineReturn = 0; negatedMatch = 0; listPtr = NULL; startPtr = NULL; offset = 0; if (objc < 3) { Tcl_WrongNumArgs(interp, 1, objv, "?options? list pattern"); return TCL_ERROR; } for (i = 1; i < objc-2; i++) { if (Tcl_GetIndexFromObj(interp, objv[i], options, "option", 0, &index) != TCL_OK) { if (startPtr) { Tcl_DecrRefCount(startPtr); } return TCL_ERROR; } switch ((enum options) index) { case LSEARCH_ALL: /* -all */ allMatches = 1; break; case LSEARCH_ASCII: /* -ascii */ dataType = ASCII; break; case LSEARCH_DECREASING: /* -decreasing */ isIncreasing = 0; break; case LSEARCH_DICTIONARY: /* -dictionary */ dataType = DICTIONARY; break; case LSEARCH_EXACT: /* -increasing */ mode = EXACT; break; case LSEARCH_GLOB: /* -glob */ mode = GLOB; break; case LSEARCH_INCREASING: /* -increasing */ isIncreasing = 1; break; case LSEARCH_INLINE: /* -inline */ inlineReturn = 1; break; case LSEARCH_INTEGER: /* -integer */ dataType = INTEGER; break; case LSEARCH_NOT: /* -not */ negatedMatch = 1; break; case LSEARCH_REAL: /* -real */ dataType = REAL; break; case LSEARCH_REGEXP: /* -regexp */ mode = REGEXP; break; case LSEARCH_SORTED: /* -sorted */ mode = SORTED; break; case LSEARCH_START: /* -start */ /* * If there was a previous -start option, release its saved * index because it will either be replaced or there will be * an error. */ if (startPtr) { Tcl_DecrRefCount(startPtr); } if (i > objc-4) { Tcl_AppendResult(interp, "missing starting index", NULL); return TCL_ERROR; } i++; if (objv[i] == objv[objc - 2]) { /* * Take copy to prevent shimmering problems. Note * that it does not matter if the index obj is also a * component of the list being searched. We only need * to copy where the list and the index are * one-and-the-same. */ startPtr = Tcl_DuplicateObj(objv[i]); } else { startPtr = objv[i]; Tcl_IncrRefCount(startPtr); } } } if ((enum modes) mode == REGEXP) { /* * We can shimmer regexp/list if listv[i] == pattern, so get the * regexp rep before the list rep. First time round, omit the interp * and hope that the compilation will succeed. If it fails, we'll * recompile in "expensive" mode with a place to put error messages. */ regexp = Tcl_GetRegExpFromObj(NULL, objv[objc - 1], TCL_REG_ADVANCED | TCL_REG_NOSUB); if (regexp == NULL) { /* * Failed to compile the RE. Try again without the TCL_REG_NOSUB * flag in case the RE had sub-expressions in it [Bug 1366683]. * If this fails, an error message will be left in the * interpreter. */ regexp = Tcl_GetRegExpFromObj(interp, objv[objc - 1], TCL_REG_ADVANCED); } if (regexp == NULL) { if (startPtr) { Tcl_DecrRefCount(startPtr); } return TCL_ERROR; } } /* * Make sure the list argument is a list object and get its length and * a pointer to its array of element pointers. */ result = Tcl_ListObjGetElements(interp, objv[objc - 2], &listc, &listv); if (result != TCL_OK) { if (startPtr) { Tcl_DecrRefCount(startPtr); } return result; } /* * Get the user-specified start offset. */ if (startPtr) { result = TclGetIntForIndex(interp, startPtr, listc-1, &offset); Tcl_DecrRefCount(startPtr); if (result != TCL_OK) { return result; } /* * If the search started past the end of the list, we just return a * "did not match anything at all" result straight away. [Bug 1374778] */ if (offset > listc-1) { if (allMatches || inlineReturn) { Tcl_ResetResult(interp); } else { Tcl_SetObjResult(interp, Tcl_NewIntObj(-1)); } return TCL_OK; } if (offset < 0) { offset = 0; } } patObj = objv[objc - 1]; patternBytes = NULL; if ((enum modes) mode == EXACT || (enum modes) mode == SORTED) { switch ((enum datatypes) dataType) { case ASCII: case DICTIONARY: patternBytes = Tcl_GetStringFromObj(patObj, &length); break; case INTEGER: result = Tcl_GetIntFromObj(interp, patObj, &patInt); if (result != TCL_OK) { return result; } Tcl_ListObjGetElements(NULL, objv[objc - 2], &listc, &listv); break; case REAL: result = Tcl_GetDoubleFromObj(interp, patObj, &patDouble); if (result != TCL_OK) { return result; } Tcl_ListObjGetElements(NULL, objv[objc - 2], &listc, &listv); break; } } else { patternBytes = Tcl_GetStringFromObj(patObj, &length); } /* * Set default index value to -1, indicating failure; if we find the * item in the course of our search, index will be set to the correct * value. */ index = -1; match = 0; if ((enum modes) mode == SORTED && !allMatches && !negatedMatch) { /* * If the data is sorted, we can do a more intelligent search. * Note that there is no point in being smart when -all was * specified; in that case, we have to look at all items anyway, * and there is no sense in doing this when the match sense is * inverted. */ lower = offset - 1; upper = listc; while (lower + 1 != upper) { i = (lower + upper)/2; switch ((enum datatypes) dataType) { case ASCII: bytes = Tcl_GetString(listv[i]); match = strcmp(patternBytes, bytes); break; case DICTIONARY: bytes = Tcl_GetString(listv[i]); match = DictionaryCompare(patternBytes, bytes); break; case INTEGER: result = Tcl_GetIntFromObj(interp, listv[i], &objInt); if (result != TCL_OK) { return result; } if (patInt == objInt) { match = 0; } else if (patInt < objInt) { match = -1; } else { match = 1; } break; case REAL: result = Tcl_GetDoubleFromObj(interp, listv[i], &objDouble); if (result != TCL_OK) { return result; } if (patDouble == objDouble) { match = 0; } else if (patDouble < objDouble) { match = -1; } else { match = 1; } break; } if (match == 0) { /* * Normally, binary search is written to stop when it * finds a match. If there are duplicates of an element in * the list, our first match might not be the first occurance. * Consider: 0 0 0 1 1 1 2 2 2 * To maintain consistancy with standard lsearch semantics, * we must find the leftmost occurance of the pattern in the * list. Thus we don't just stop searching here. This * variation means that a search always makes log n * comparisons (normal binary search might "get lucky" with * an early comparison). */ index = i; upper = i; } else if (match > 0) { if (isIncreasing) { lower = i; } else { upper = i; } } else { if (isIncreasing) { upper = i; } else { lower = i; } } } } else { /* * We need to do a linear search, because (at least one) of: * - our matcher can only tell equal vs. not equal * - our matching sense is negated * - we're building a list of all matched items */ if (allMatches) { listPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); } for (i = offset; i < listc; i++) { match = 0; switch ((enum modes) mode) { case SORTED: case EXACT: switch ((enum datatypes) dataType) { case ASCII: bytes = Tcl_GetStringFromObj(listv[i], &elemLen); if (length == elemLen) { match = (memcmp(bytes, patternBytes, (size_t) length) == 0); } break; case DICTIONARY: bytes = Tcl_GetString(listv[i]); match = (DictionaryCompare(bytes, patternBytes) == 0); break; case INTEGER: result = Tcl_GetIntFromObj(interp, listv[i], &objInt); if (result != TCL_OK) { if (listPtr) { Tcl_DecrRefCount(listPtr); } return result; } match = (objInt == patInt); break; case REAL: result = Tcl_GetDoubleFromObj(interp, listv[i], &objDouble); if (result != TCL_OK) { if (listPtr) { Tcl_DecrRefCount(listPtr); } return result; } match = (objDouble == patDouble); break; } break; case GLOB: match = Tcl_StringMatch(Tcl_GetString(listv[i]), patternBytes); break; case REGEXP: match = Tcl_RegExpExecObj(interp, regexp, listv[i], 0, 0, 0); if (match < 0) { Tcl_DecrRefCount(patObj); if (listPtr) { Tcl_DecrRefCount(listPtr); } return TCL_ERROR; } break; } /* * Invert match condition for -not */ if (negatedMatch) { match = !match; } if (match != 0) { if (!allMatches) { index = i; break; } else if (inlineReturn) { /* * Note that these appends are not expected to fail. */ Tcl_ListObjAppendElement(interp, listPtr, listv[i]); } else { Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewIntObj(i)); } } } } /* * Return everything or a single value. */ if (allMatches) { Tcl_SetObjResult(interp, listPtr); } else if (!inlineReturn) { Tcl_SetIntObj(Tcl_GetObjResult(interp), index); } else if (index < 0) { /* * Is this superfluous? The result should be a blank object * by default... */ Tcl_SetObjResult(interp, Tcl_NewObj()); } else { Tcl_SetObjResult(interp, listv[index]); } return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_LsetObjCmd -- * * This procedure is invoked to process the "lset" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ int Tcl_LsetObjCmd( clientData, interp, objc, objv ) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument values. */ { Tcl_Obj* listPtr; /* Pointer to the list being altered. */ Tcl_Obj* finalValuePtr; /* Value finally assigned to the variable */ /* Check parameter count */ if ( objc < 3 ) { Tcl_WrongNumArgs( interp, 1, objv, "listVar index ?index...? value" ); return TCL_ERROR; } /* Look up the list variable's value */ listPtr = Tcl_ObjGetVar2( interp, objv[ 1 ], (Tcl_Obj*) NULL, TCL_LEAVE_ERR_MSG ); if ( listPtr == NULL ) { return TCL_ERROR; } /* * Substitute the value in the value. Return either the value or * else an unshared copy of it. */ if ( objc == 4 ) { finalValuePtr = TclLsetList( interp, listPtr, objv[ 2 ], objv[ 3 ] ); } else { finalValuePtr = TclLsetFlat( interp, listPtr, objc-3, objv+2, objv[ objc-1 ] ); } /* * If substitution has failed, bail out. */ if ( finalValuePtr == NULL ) { return TCL_ERROR; } /* Finally, update the variable so that traces fire. */ listPtr = Tcl_ObjSetVar2( interp, objv[1], NULL, finalValuePtr, TCL_LEAVE_ERR_MSG ); Tcl_DecrRefCount( finalValuePtr ); if ( listPtr == NULL ) { return TCL_ERROR; } /* Return the new value of the variable as the interpreter result. */ Tcl_SetObjResult( interp, listPtr ); return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_LsortObjCmd -- * * This procedure is invoked to process the "lsort" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ int Tcl_LsortObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument values. */ { int i, index, unique; Tcl_Obj *resultPtr; int length; Tcl_Obj *cmdPtr, **listObjPtrs; SortElement *elementArray; SortElement *elementPtr; SortInfo sortInfo; /* Information about this sort that * needs to be passed to the * comparison function */ static CONST char *switches[] = { "-ascii", "-command", "-decreasing", "-dictionary", "-increasing", "-index", "-integer", "-real", "-unique", (char *) NULL }; resultPtr = Tcl_GetObjResult(interp); if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "?options? list"); return TCL_ERROR; } /* * Parse arguments to set up the mode for the sort. */ sortInfo.isIncreasing = 1; sortInfo.sortMode = SORTMODE_ASCII; sortInfo.index = SORTIDX_NONE; sortInfo.interp = interp; sortInfo.resultCode = TCL_OK; cmdPtr = NULL; unique = 0; for (i = 1; i < objc-1; i++) { if (Tcl_GetIndexFromObj(interp, objv[i], switches, "option", 0, &index) != TCL_OK) { return TCL_ERROR; } switch (index) { case 0: /* -ascii */ sortInfo.sortMode = SORTMODE_ASCII; break; case 1: /* -command */ if (i == (objc-2)) { Tcl_AppendToObj(resultPtr, "\"-command\" option must be followed by comparison command", -1); return TCL_ERROR; } sortInfo.sortMode = SORTMODE_COMMAND; cmdPtr = objv[i+1]; i++; break; case 2: /* -decreasing */ sortInfo.isIncreasing = 0; break; case 3: /* -dictionary */ sortInfo.sortMode = SORTMODE_DICTIONARY; break; case 4: /* -increasing */ sortInfo.isIncreasing = 1; break; case 5: /* -index */ if (i == (objc-2)) { Tcl_AppendToObj(resultPtr, "\"-index\" option must be followed by list index", -1); return TCL_ERROR; } if (TclGetIntForIndex(interp, objv[i+1], SORTIDX_END, &sortInfo.index) != TCL_OK) { return TCL_ERROR; } i++; break; case 6: /* -integer */ sortInfo.sortMode = SORTMODE_INTEGER; break; case 7: /* -real */ sortInfo.sortMode = SORTMODE_REAL; break; case 8: /* -unique */ unique = 1; break; } } if (sortInfo.sortMode == SORTMODE_COMMAND) { /* * The existing command is a list. We want to flatten it, append * two dummy arguments on the end, and replace these arguments * later. */ Tcl_Obj *newCommandPtr = Tcl_DuplicateObj(cmdPtr); Tcl_Obj *newObjPtr = Tcl_NewObj(); Tcl_IncrRefCount(newCommandPtr); if (Tcl_ListObjAppendElement(interp, newCommandPtr, newObjPtr) != TCL_OK) { Tcl_DecrRefCount(newCommandPtr); Tcl_IncrRefCount(newObjPtr); Tcl_DecrRefCount(newObjPtr); return TCL_ERROR; } Tcl_ListObjAppendElement(interp, newCommandPtr, Tcl_NewObj()); sortInfo.compareCmdPtr = newCommandPtr; } sortInfo.resultCode = Tcl_ListObjGetElements(interp, objv[objc-1], &length, &listObjPtrs); if (sortInfo.resultCode != TCL_OK || length <= 0) { goto done; } elementArray = (SortElement *) ckalloc(length * sizeof(SortElement)); for (i=0; i < length; i++){ elementArray[i].objPtr = listObjPtrs[i]; elementArray[i].count = 0; elementArray[i].nextPtr = &elementArray[i+1]; /* * When sorting using a command, we are reentrant and therefore might * have the representation of the list being sorted shimmered out from * underneath our feet. Increment the reference counts of the elements * to sort to prevent this. [Bug 1675116] */ Tcl_IncrRefCount(elementArray[i].objPtr); } elementArray[length-1].nextPtr = NULL; elementPtr = MergeSort(elementArray, &sortInfo); if (sortInfo.resultCode == TCL_OK) { /* * Note: must clear the interpreter's result object: it could * have been set by the -command script. */ Tcl_ResetResult(interp); resultPtr = Tcl_GetObjResult(interp); if (unique) { for (; elementPtr != NULL; elementPtr = elementPtr->nextPtr){ if (elementPtr->count == 0) { Tcl_ListObjAppendElement(interp, resultPtr, elementPtr->objPtr); } } } else { for (; elementPtr != NULL; elementPtr = elementPtr->nextPtr){ Tcl_ListObjAppendElement(interp, resultPtr, elementPtr->objPtr); } } } for (i=0; inextPtr; elementPtr->nextPtr = 0; for (i = 0; (i < NUM_LISTS) && (subList[i] != NULL); i++){ elementPtr = MergeLists(subList[i], elementPtr, infoPtr); subList[i] = NULL; } if (i >= NUM_LISTS) { i = NUM_LISTS-1; } subList[i] = elementPtr; } elementPtr = NULL; for (i = 0; i < NUM_LISTS; i++){ elementPtr = MergeLists(subList[i], elementPtr, infoPtr); } return elementPtr; } /* *---------------------------------------------------------------------- * * MergeLists - * * This procedure combines two sorted lists of SortElement structures * into a single sorted list. * * Results: * The unified list of SortElement structures. * * Side effects: * None, unless a user-defined comparison command does something * weird. * *---------------------------------------------------------------------- */ static SortElement * MergeLists(leftPtr, rightPtr, infoPtr) SortElement *leftPtr; /* First list to be merged; may be * NULL. */ SortElement *rightPtr; /* Second list to be merged; may be * NULL. */ SortInfo *infoPtr; /* Information needed by the * comparison operator. */ { SortElement *headPtr; SortElement *tailPtr; int cmp; if (leftPtr == NULL) { return rightPtr; } if (rightPtr == NULL) { return leftPtr; } cmp = SortCompare(leftPtr->objPtr, rightPtr->objPtr, infoPtr); if (cmp > 0) { tailPtr = rightPtr; rightPtr = rightPtr->nextPtr; } else { if (cmp == 0) { leftPtr->count++; } tailPtr = leftPtr; leftPtr = leftPtr->nextPtr; } headPtr = tailPtr; while ((leftPtr != NULL) && (rightPtr != NULL)) { cmp = SortCompare(leftPtr->objPtr, rightPtr->objPtr, infoPtr); if (cmp > 0) { tailPtr->nextPtr = rightPtr; tailPtr = rightPtr; rightPtr = rightPtr->nextPtr; } else { if (cmp == 0) { leftPtr->count++; } tailPtr->nextPtr = leftPtr; tailPtr = leftPtr; leftPtr = leftPtr->nextPtr; } } if (leftPtr != NULL) { tailPtr->nextPtr = leftPtr; } else { tailPtr->nextPtr = rightPtr; } return headPtr; } /* *---------------------------------------------------------------------- * * SortCompare -- * * This procedure is invoked by MergeLists to determine the proper * ordering between two elements. * * Results: * A negative results means the the first element comes before the * second, and a positive results means that the second element * should come first. A result of zero means the two elements * are equal and it doesn't matter which comes first. * * Side effects: * None, unless a user-defined comparison command does something * weird. * *---------------------------------------------------------------------- */ static int SortCompare(objPtr1, objPtr2, infoPtr) Tcl_Obj *objPtr1, *objPtr2; /* Values to be compared. */ SortInfo *infoPtr; /* Information passed from the * top-level "lsort" command */ { int order, listLen, index; Tcl_Obj *objPtr; char buffer[TCL_INTEGER_SPACE]; order = 0; if (infoPtr->resultCode != TCL_OK) { /* * Once an error has occurred, skip any future comparisons * so as to preserve the error message in sortInterp->result. */ return order; } if (infoPtr->index != SORTIDX_NONE) { /* * The "-index" option was specified. Treat each object as a * list, extract the requested element from each list, and * compare the elements, not the lists. "end"-relative indices * are signaled here with large negative values. */ if (Tcl_ListObjLength(infoPtr->interp, objPtr1, &listLen) != TCL_OK) { infoPtr->resultCode = TCL_ERROR; return order; } if (infoPtr->index < SORTIDX_NONE) { index = listLen + infoPtr->index + 1; } else { index = infoPtr->index; } if (Tcl_ListObjIndex(infoPtr->interp, objPtr1, index, &objPtr) != TCL_OK) { infoPtr->resultCode = TCL_ERROR; return order; } if (objPtr == NULL) { objPtr = objPtr1; missingElement: TclFormatInt(buffer, infoPtr->index); Tcl_AppendStringsToObj(Tcl_GetObjResult(infoPtr->interp), "element ", buffer, " missing from sublist \"", Tcl_GetString(objPtr), "\"", (char *) NULL); infoPtr->resultCode = TCL_ERROR; return order; } objPtr1 = objPtr; if (Tcl_ListObjLength(infoPtr->interp, objPtr2, &listLen) != TCL_OK) { infoPtr->resultCode = TCL_ERROR; return order; } if (infoPtr->index < SORTIDX_NONE) { index = listLen + infoPtr->index + 1; } else { index = infoPtr->index; } if (Tcl_ListObjIndex(infoPtr->interp, objPtr2, index, &objPtr) != TCL_OK) { infoPtr->resultCode = TCL_ERROR; return order; } if (objPtr == NULL) { objPtr = objPtr2; goto missingElement; } objPtr2 = objPtr; } if (infoPtr->sortMode == SORTMODE_ASCII) { order = strcmp(Tcl_GetString(objPtr1), Tcl_GetString(objPtr2)); } else if (infoPtr->sortMode == SORTMODE_DICTIONARY) { order = DictionaryCompare( Tcl_GetString(objPtr1), Tcl_GetString(objPtr2)); } else if (infoPtr->sortMode == SORTMODE_INTEGER) { long a, b; if ((Tcl_GetLongFromObj(infoPtr->interp, objPtr1, &a) != TCL_OK) || (Tcl_GetLongFromObj(infoPtr->interp, objPtr2, &b) != TCL_OK)) { infoPtr->resultCode = TCL_ERROR; return order; } if (a > b) { order = 1; } else if (b > a) { order = -1; } } else if (infoPtr->sortMode == SORTMODE_REAL) { double a, b; if ((Tcl_GetDoubleFromObj(infoPtr->interp, objPtr1, &a) != TCL_OK) || (Tcl_GetDoubleFromObj(infoPtr->interp, objPtr2, &b) != TCL_OK)) { infoPtr->resultCode = TCL_ERROR; return order; } if (a > b) { order = 1; } else if (b > a) { order = -1; } } else { Tcl_Obj **objv, *paramObjv[2]; int objc; paramObjv[0] = objPtr1; paramObjv[1] = objPtr2; /* * We made space in the command list for the two things to * compare. Replace them and evaluate the result. */ Tcl_ListObjLength(infoPtr->interp, infoPtr->compareCmdPtr, &objc); Tcl_ListObjReplace(infoPtr->interp, infoPtr->compareCmdPtr, objc - 2, 2, 2, paramObjv); Tcl_ListObjGetElements(infoPtr->interp, infoPtr->compareCmdPtr, &objc, &objv); infoPtr->resultCode = Tcl_EvalObjv(infoPtr->interp, objc, objv, 0); if (infoPtr->resultCode != TCL_OK) { Tcl_AddErrorInfo(infoPtr->interp, "\n (-compare command)"); return order; } /* * Parse the result of the command. */ if (Tcl_GetIntFromObj(infoPtr->interp, Tcl_GetObjResult(infoPtr->interp), &order) != TCL_OK) { Tcl_ResetResult(infoPtr->interp); Tcl_AppendToObj(Tcl_GetObjResult(infoPtr->interp), "-compare command returned non-integer result", -1); infoPtr->resultCode = TCL_ERROR; return order; } } if (!infoPtr->isIncreasing) { order = -order; } return order; } /* *---------------------------------------------------------------------- * * DictionaryCompare * * This function compares two strings as if they were being used in * an index or card catalog. The case of alphabetic characters is * ignored, except to break ties. Thus "B" comes before "b" but * after "a". Also, integers embedded in the strings compare in * numerical order. In other words, "x10y" comes after "x9y", not * before it as it would when using strcmp(). * * Results: * A negative result means that the first element comes before the * second, and a positive result means that the second element * should come first. A result of zero means the two elements * are equal and it doesn't matter which comes first. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int DictionaryCompare(left, right) char *left, *right; /* The strings to compare */ { Tcl_UniChar uniLeft, uniRight, uniLeftLower, uniRightLower; int diff, zeros; int secondaryDiff = 0; while (1) { if (isdigit(UCHAR(*right)) /* INTL: digit */ && isdigit(UCHAR(*left))) { /* INTL: digit */ /* * There are decimal numbers embedded in the two * strings. Compare them as numbers, rather than * strings. If one number has more leading zeros than * the other, the number with more leading zeros sorts * later, but only as a secondary choice. */ zeros = 0; while ((*right == '0') && (isdigit(UCHAR(right[1])))) { right++; zeros--; } while ((*left == '0') && (isdigit(UCHAR(left[1])))) { left++; zeros++; } if (secondaryDiff == 0) { secondaryDiff = zeros; } /* * The code below compares the numbers in the two * strings without ever converting them to integers. It * does this by first comparing the lengths of the * numbers and then comparing the digit values. */ diff = 0; while (1) { if (diff == 0) { diff = UCHAR(*left) - UCHAR(*right); } right++; left++; if (!isdigit(UCHAR(*right))) { /* INTL: digit */ if (isdigit(UCHAR(*left))) { /* INTL: digit */ return 1; } else { /* * The two numbers have the same length. See * if their values are different. */ if (diff != 0) { return diff; } break; } } else if (!isdigit(UCHAR(*left))) { /* INTL: digit */ return -1; } } continue; } /* * Convert character to Unicode for comparison purposes. If either * string is at the terminating null, do a byte-wise comparison and * bail out immediately. */ if ((*left != '\0') && (*right != '\0')) { left += Tcl_UtfToUniChar(left, &uniLeft); right += Tcl_UtfToUniChar(right, &uniRight); /* * Convert both chars to lower for the comparison, because * dictionary sorts are case insensitve. Covert to lower, not * upper, so chars between Z and a will sort before A (where most * other interesting punctuations occur) */ uniLeftLower = Tcl_UniCharToLower(uniLeft); uniRightLower = Tcl_UniCharToLower(uniRight); } else { diff = UCHAR(*left) - UCHAR(*right); break; } diff = uniLeftLower - uniRightLower; if (diff) { return diff; } else if (secondaryDiff == 0) { if (Tcl_UniCharIsUpper(uniLeft) && Tcl_UniCharIsLower(uniRight)) { secondaryDiff = -1; } else if (Tcl_UniCharIsUpper(uniRight) && Tcl_UniCharIsLower(uniLeft)) { secondaryDiff = 1; } } } if (diff == 0) { diff = secondaryDiff; } return diff; } /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ tcl8.4.20/generic/tclPreserve.c0000644003604700454610000003202511737050674014777 0ustar dgp771div/* * tclPreserve.c -- * * This file contains a collection of procedures that are used * to make sure that widget records and other data structures * aren't reallocated when there are nested procedures that * depend on their existence. * * Copyright (c) 1991-1994 The Regents of the University of California. * Copyright (c) 1994-1998 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" /* * The following data structure is used to keep track of all the * Tcl_Preserve calls that are still in effect. It grows as needed * to accommodate any number of calls in effect. */ typedef struct { ClientData clientData; /* Address of preserved block. */ int refCount; /* Number of Tcl_Preserve calls in effect * for block. */ int mustFree; /* Non-zero means Tcl_EventuallyFree was * called while a Tcl_Preserve call was in * effect, so the structure must be freed * when refCount becomes zero. */ Tcl_FreeProc *freeProc; /* Procedure to call to free. */ } Reference; static Reference *refArray; /* First in array of references. */ static int spaceAvl = 0; /* Total number of structures available * at *firstRefPtr. */ static int inUse = 0; /* Count of structures currently in use * in refArray. */ #define INITIAL_SIZE 2 TCL_DECLARE_MUTEX(preserveMutex)/* To protect the above statics */ /* * The following data structure is used to keep track of whether an * arbitrary block of memory has been deleted. This is used by the * TclHandle code to avoid the more time-expensive algorithm of * Tcl_Preserve(). This mechanism is mainly used when we have lots of * references to a few big, expensive objects that we don't want to live * any longer than necessary. */ typedef struct HandleStruct { VOID *ptr; /* Pointer to the memory block being * tracked. This field will become NULL when * the memory block is deleted. This field * must be the first in the structure. */ #ifdef TCL_MEM_DEBUG VOID *ptr2; /* Backup copy of the abpve pointer used to * ensure that the contents of the handle are * not changed by anyone else. */ #endif int refCount; /* Number of TclHandlePreserve() calls in * effect on this handle. */ } HandleStruct; /* *---------------------------------------------------------------------- * * TclFinalizePreserve -- * * Called during exit processing to clean up the reference array. * * Results: * None. * * Side effects: * Frees the storage of the reference array. * *---------------------------------------------------------------------- */ /* ARGSUSED */ void TclFinalizePreserve() { Tcl_MutexLock(&preserveMutex); if (spaceAvl != 0) { ckfree((char *) refArray); refArray = (Reference *) NULL; inUse = 0; spaceAvl = 0; } Tcl_MutexUnlock(&preserveMutex); } /* *---------------------------------------------------------------------- * * Tcl_Preserve -- * * This procedure is used by a procedure to declare its interest * in a particular block of memory, so that the block will not be * reallocated until a matching call to Tcl_Release has been made. * * Results: * None. * * Side effects: * Information is retained so that the block of memory will * not be freed until at least the matching call to Tcl_Release. * *---------------------------------------------------------------------- */ void Tcl_Preserve(clientData) ClientData clientData; /* Pointer to malloc'ed block of memory. */ { Reference *refPtr; int i; /* * See if there is already a reference for this pointer. If so, * just increment its reference count. */ Tcl_MutexLock(&preserveMutex); for (i = 0, refPtr = refArray; i < inUse; i++, refPtr++) { if (refPtr->clientData == clientData) { refPtr->refCount++; Tcl_MutexUnlock(&preserveMutex); return; } } /* * Make a reference array if it doesn't already exist, or make it * bigger if it is full. */ if (inUse == spaceAvl) { if (spaceAvl == 0) { refArray = (Reference *) ckalloc((unsigned) (INITIAL_SIZE*sizeof(Reference))); spaceAvl = INITIAL_SIZE; } else { Reference *new; new = (Reference *) ckalloc((unsigned) (2*spaceAvl*sizeof(Reference))); memcpy((VOID *) new, (VOID *) refArray, spaceAvl*sizeof(Reference)); ckfree((char *) refArray); refArray = new; spaceAvl *= 2; } } /* * Make a new entry for the new reference. */ refPtr = &refArray[inUse]; refPtr->clientData = clientData; refPtr->refCount = 1; refPtr->mustFree = 0; refPtr->freeProc = TCL_STATIC; inUse += 1; Tcl_MutexUnlock(&preserveMutex); } /* *---------------------------------------------------------------------- * * Tcl_Release -- * * This procedure is called to cancel a previous call to * Tcl_Preserve, thereby allowing a block of memory to be * freed (if no one else cares about it). * * Results: * None. * * Side effects: * If Tcl_EventuallyFree has been called for clientData, and if * no other call to Tcl_Preserve is still in effect, the block of * memory is freed. * *---------------------------------------------------------------------- */ void Tcl_Release(clientData) ClientData clientData; /* Pointer to malloc'ed block of memory. */ { Reference *refPtr; int mustFree; Tcl_FreeProc *freeProc; int i; Tcl_MutexLock(&preserveMutex); for (i = 0, refPtr = refArray; i < inUse; i++, refPtr++) { if (refPtr->clientData != clientData) { continue; } refPtr->refCount--; if (refPtr->refCount == 0) { /* * Must remove information from the slot before calling freeProc * to avoid reentrancy problems if the freeProc calls Tcl_Preserve * on the same clientData. Copy down the last reference in the * array to overwrite the current slot. */ freeProc = refPtr->freeProc; mustFree = refPtr->mustFree; inUse--; if (i < inUse) { refArray[i] = refArray[inUse]; } if (mustFree) { if (freeProc == TCL_DYNAMIC) { ckfree((char *) clientData); } else { Tcl_MutexUnlock(&preserveMutex); (*freeProc)((char *) clientData); return; } } } Tcl_MutexUnlock(&preserveMutex); return; } Tcl_MutexUnlock(&preserveMutex); /* * Reference not found. This is a bug in the caller. */ panic("Tcl_Release couldn't find reference for 0x%x", clientData); } /* *---------------------------------------------------------------------- * * Tcl_EventuallyFree -- * * Free up a block of memory, unless a call to Tcl_Preserve is in * effect for that block. In this case, defer the free until all * calls to Tcl_Preserve have been undone by matching calls to * Tcl_Release. * * Results: * None. * * Side effects: * Ptr may be released by calling free(). * *---------------------------------------------------------------------- */ void Tcl_EventuallyFree(clientData, freeProc) ClientData clientData; /* Pointer to malloc'ed block of memory. */ Tcl_FreeProc *freeProc; /* Procedure to actually do free. */ { Reference *refPtr; int i; /* * See if there is a reference for this pointer. If so, set its * "mustFree" flag (the flag had better not be set already!). */ Tcl_MutexLock(&preserveMutex); for (i = 0, refPtr = refArray; i < inUse; i++, refPtr++) { if (refPtr->clientData != clientData) { continue; } if (refPtr->mustFree) { panic("Tcl_EventuallyFree called twice for 0x%x\n", clientData); } refPtr->mustFree = 1; refPtr->freeProc = freeProc; Tcl_MutexUnlock(&preserveMutex); return; } Tcl_MutexUnlock(&preserveMutex); /* * No reference for this block. Free it now. */ if (freeProc == TCL_DYNAMIC) { ckfree((char *) clientData); } else { (*freeProc)((char *)clientData); } } /* *--------------------------------------------------------------------------- * * TclHandleCreate -- * * Allocate a handle that contains enough information to determine * if an arbitrary malloc'd block has been deleted. This is * used to avoid the more time-expensive algorithm of Tcl_Preserve(). * * Results: * The return value is a TclHandle that refers to the given malloc'd * block. Doubly dereferencing the returned handle will give * back the pointer to the block, or will give NULL if the block has * been deleted. * * Side effects: * The caller must keep track of this handle (generally by storing * it in a field in the malloc'd block) and call TclHandleFree() * on this handle when the block is deleted. Everything else that * wishes to keep track of whether the malloc'd block has been deleted * should use calls to TclHandlePreserve() and TclHandleRelease() * on the associated handle. * *--------------------------------------------------------------------------- */ TclHandle TclHandleCreate(ptr) VOID *ptr; /* Pointer to an arbitrary block of memory * to be tracked for deletion. Must not be * NULL. */ { HandleStruct *handlePtr; handlePtr = (HandleStruct *) ckalloc(sizeof(HandleStruct)); handlePtr->ptr = ptr; #ifdef TCL_MEM_DEBUG handlePtr->ptr2 = ptr; #endif handlePtr->refCount = 0; return (TclHandle) handlePtr; } /* *--------------------------------------------------------------------------- * * TclHandleFree -- * * Called when the arbitrary malloc'd block associated with the * handle is being deleted. Modifies the handle so that doubly * dereferencing it will give NULL. This informs any user of the * handle that the block of memory formerly referenced by the * handle has been freed. * * Results: * None. * * Side effects: * If nothing is referring to the handle, the handle will be reclaimed. * *--------------------------------------------------------------------------- */ void TclHandleFree(handle) TclHandle handle; /* Previously created handle associated * with a malloc'd block that is being * deleted. The handle is modified so that * doubly dereferencing it will give NULL. */ { HandleStruct *handlePtr; handlePtr = (HandleStruct *) handle; #ifdef TCL_MEM_DEBUG if (handlePtr->refCount == 0x61616161) { panic("using previously disposed TclHandle %x", handlePtr); } if (handlePtr->ptr2 != handlePtr->ptr) { panic("someone has changed the block referenced by the handle %x\nfrom %x to %x", handlePtr, handlePtr->ptr2, handlePtr->ptr); } #endif handlePtr->ptr = NULL; if (handlePtr->refCount == 0) { ckfree((char *) handlePtr); } } /* *--------------------------------------------------------------------------- * * TclHandlePreserve -- * * Declare an interest in the arbitrary malloc'd block associated * with the handle. * * Results: * The return value is the handle argument, with its ref count * incremented. * * Side effects: * For each call to TclHandlePreserve(), there should be a matching * call to TclHandleRelease() when the caller is no longer interested * in the malloc'd block associated with the handle. * *--------------------------------------------------------------------------- */ TclHandle TclHandlePreserve(handle) TclHandle handle; /* Declare an interest in the block of * memory referenced by this handle. */ { HandleStruct *handlePtr; handlePtr = (HandleStruct *) handle; #ifdef TCL_MEM_DEBUG if (handlePtr->refCount == 0x61616161) { panic("using previously disposed TclHandle %x", handlePtr); } if ((handlePtr->ptr != NULL) && (handlePtr->ptr != handlePtr->ptr2)) { panic("someone has changed the block referenced by the handle %x\nfrom %x to %x", handlePtr, handlePtr->ptr2, handlePtr->ptr); } #endif handlePtr->refCount++; return handle; } /* *--------------------------------------------------------------------------- * * TclHandleRelease -- * * This procedure is called to release an interest in the malloc'd * block associated with the handle. * * Results: * None. * * Side effects: * The ref count of the handle is decremented. If the malloc'd block * has been freed and if no one is using the handle any more, the * handle will be reclaimed. * *--------------------------------------------------------------------------- */ void TclHandleRelease(handle) TclHandle handle; /* Unregister interest in the block of * memory referenced by this handle. */ { HandleStruct *handlePtr; handlePtr = (HandleStruct *) handle; #ifdef TCL_MEM_DEBUG if (handlePtr->refCount == 0x61616161) { panic("using previously disposed TclHandle %x", handlePtr); } if ((handlePtr->ptr != NULL) && (handlePtr->ptr != handlePtr->ptr2)) { panic("someone has changed the block referenced by the handle %x\nfrom %x to %x", handlePtr, handlePtr->ptr2, handlePtr->ptr); } #endif handlePtr->refCount--; if ((handlePtr->refCount == 0) && (handlePtr->ptr == NULL)) { ckfree((char *) handlePtr); } } tcl8.4.20/generic/tclCompExpr.c0000644003604700454610000006676012052456743014754 0ustar dgp771div/* * tclCompExpr.c -- * * This file contains the code to compile Tcl expressions. * * Copyright (c) 1997 Sun Microsystems, Inc. * Copyright (c) 1998-2000 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclCompile.h" /* * The stuff below is a bit of a hack so that this file can be used in * environments that include no UNIX, i.e. no errno: just arrange to use * the errno from tclExecute.c here. */ #ifndef TCL_GENERIC_ONLY #include "tclPort.h" #else #define NO_ERRNO_H #endif #ifdef NO_ERRNO_H extern int errno; /* Use errno from tclExecute.c. */ #define ERANGE 34 #endif /* * Boolean variable that controls whether expression compilation tracing * is enabled. */ #ifdef TCL_COMPILE_DEBUG static int traceExprComp = 0; #endif /* TCL_COMPILE_DEBUG */ /* * The ExprInfo structure describes the state of compiling an expression. * A pointer to an ExprInfo record is passed among the routines in * this module. */ typedef struct ExprInfo { Tcl_Interp *interp; /* Used for error reporting. */ Tcl_Parse *parsePtr; /* Structure filled with information about * the parsed expression. */ CONST char *expr; /* The expression that was originally passed * to TclCompileExpr. */ CONST char *lastChar; /* Points just after last byte of expr. */ int hasOperators; /* Set 1 if the expr has operators; 0 if * expr is only a primary. If 1 after * compiling an expr, a tryCvtToNumeric * instruction is emitted to convert the * primary to a number if possible. */ } ExprInfo; /* * Definitions of numeric codes representing each expression operator. * The order of these must match the entries in the operatorTable below. * Also the codes for the relational operators (OP_LESS, OP_GREATER, * OP_LE, OP_GE, OP_EQ, and OP_NE) must be consecutive and in that order. * Note that OP_PLUS and OP_MINUS represent both unary and binary operators. */ #define OP_MULT 0 #define OP_DIVIDE 1 #define OP_MOD 2 #define OP_PLUS 3 #define OP_MINUS 4 #define OP_LSHIFT 5 #define OP_RSHIFT 6 #define OP_LESS 7 #define OP_GREATER 8 #define OP_LE 9 #define OP_GE 10 #define OP_EQ 11 #define OP_NEQ 12 #define OP_BITAND 13 #define OP_BITXOR 14 #define OP_BITOR 15 #define OP_LAND 16 #define OP_LOR 17 #define OP_QUESTY 18 #define OP_LNOT 19 #define OP_BITNOT 20 #define OP_STREQ 21 #define OP_STRNEQ 22 /* * Table describing the expression operators. Entries in this table must * correspond to the definitions of numeric codes for operators just above. */ static int opTableInitialized = 0; /* 0 means not yet initialized. */ TCL_DECLARE_MUTEX(opMutex) typedef struct OperatorDesc { CONST char *name; /* Name of the operator. */ int numOperands; /* Number of operands. 0 if the operator * requires special handling. */ int instruction; /* Instruction opcode for the operator. * Ignored if numOperands is 0. */ } OperatorDesc; static CONST OperatorDesc operatorTable[] = { {"*", 2, INST_MULT}, {"/", 2, INST_DIV}, {"%", 2, INST_MOD}, {"+", 0, 0}, {"-", 0, 0}, {"<<", 2, INST_LSHIFT}, {">>", 2, INST_RSHIFT}, {"<", 2, INST_LT}, {">", 2, INST_GT}, {"<=", 2, INST_LE}, {">=", 2, INST_GE}, {"==", 2, INST_EQ}, {"!=", 2, INST_NEQ}, {"&", 2, INST_BITAND}, {"^", 2, INST_BITXOR}, {"|", 2, INST_BITOR}, {"&&", 0, 0}, {"||", 0, 0}, {"?", 0, 0}, {"!", 1, INST_LNOT}, {"~", 1, INST_BITNOT}, {"eq", 2, INST_STR_EQ}, {"ne", 2, INST_STR_NEQ}, {NULL, 0, 0} }; /* * Hashtable used to map the names of expression operators to the index * of their OperatorDesc description. */ static Tcl_HashTable opHashTable; /* * Declarations for local procedures to this file: */ static int CompileCondExpr _ANSI_ARGS_(( Tcl_Token *exprTokenPtr, ExprInfo *infoPtr, CompileEnv *envPtr, Tcl_Token **endPtrPtr)); static int CompileLandOrLorExpr _ANSI_ARGS_(( Tcl_Token *exprTokenPtr, int opIndex, ExprInfo *infoPtr, CompileEnv *envPtr, Tcl_Token **endPtrPtr)); static int CompileMathFuncCall _ANSI_ARGS_(( Tcl_Token *exprTokenPtr, CONST char *funcName, ExprInfo *infoPtr, CompileEnv *envPtr, Tcl_Token **endPtrPtr)); static int CompileSubExpr _ANSI_ARGS_(( Tcl_Token *exprTokenPtr, ExprInfo *infoPtr, CompileEnv *envPtr)); static void LogSyntaxError _ANSI_ARGS_((ExprInfo *infoPtr)); /* * Macro used to debug the execution of the expression compiler. */ #ifdef TCL_COMPILE_DEBUG #define TRACE(exprBytes, exprLength, tokenBytes, tokenLength) \ if (traceExprComp) { \ fprintf(stderr, "CompileSubExpr: \"%.*s\", token \"%.*s\"\n", \ (exprLength), (exprBytes), (tokenLength), (tokenBytes)); \ } #else #define TRACE(exprBytes, exprLength, tokenBytes, tokenLength) #endif /* TCL_COMPILE_DEBUG */ /* *---------------------------------------------------------------------- * * TclCompileExpr -- * * This procedure compiles a string containing a Tcl expression into * Tcl bytecodes. This procedure is the top-level interface to the * the expression compilation module, and is used by such public * procedures as Tcl_ExprString, Tcl_ExprStringObj, Tcl_ExprLong, * Tcl_ExprDouble, Tcl_ExprBoolean, and Tcl_ExprBooleanObj. * * Results: * The return value is TCL_OK on a successful compilation and TCL_ERROR * on failure. If TCL_ERROR is returned, then the interpreter's result * contains an error message. * * Side effects: * Adds instructions to envPtr to evaluate the expression at runtime. * *---------------------------------------------------------------------- */ int TclCompileExpr(interp, script, numBytes, envPtr) Tcl_Interp *interp; /* Used for error reporting. */ CONST char *script; /* The source script to compile. */ int numBytes; /* Number of bytes in script. If < 0, the * string consists of all bytes up to the * first null character. */ CompileEnv *envPtr; /* Holds resulting instructions. */ { ExprInfo info; Tcl_Parse parse; Tcl_HashEntry *hPtr; int new, i, code; /* * If this is the first time we've been called, initialize the table * of expression operators. */ if (numBytes < 0) { numBytes = (script? strlen(script) : 0); } if (!opTableInitialized) { Tcl_MutexLock(&opMutex); if (!opTableInitialized) { Tcl_InitHashTable(&opHashTable, TCL_STRING_KEYS); for (i = 0; operatorTable[i].name != NULL; i++) { hPtr = Tcl_CreateHashEntry(&opHashTable, operatorTable[i].name, &new); if (new) { Tcl_SetHashValue(hPtr, (ClientData) i); } } opTableInitialized = 1; } Tcl_MutexUnlock(&opMutex); } /* * Initialize the structure containing information abvout this * expression compilation. */ info.interp = interp; info.parsePtr = &parse; info.expr = script; info.lastChar = (script + numBytes); info.hasOperators = 0; /* * Parse the expression then compile it. */ code = Tcl_ParseExpr(interp, script, numBytes, &parse); if (code != TCL_OK) { goto done; } #ifdef TCL_TIP280 /* TIP #280 : Track Lines within the expression */ TclAdvanceLines (&envPtr->line, script, parse.tokenPtr->start); #endif code = CompileSubExpr(parse.tokenPtr, &info, envPtr); if (code != TCL_OK) { Tcl_FreeParse(&parse); goto done; } if (!info.hasOperators) { /* * Attempt to convert the primary's object to an int or double. * This is done in order to support Tcl's policy of interpreting * operands if at all possible as first integers, else * floating-point numbers. */ TclEmitOpcode(INST_TRY_CVT_TO_NUMERIC, envPtr); } Tcl_FreeParse(&parse); done: return code; } /* *---------------------------------------------------------------------- * * TclFinalizeCompilation -- * * Clean up the compilation environment so it can later be * properly reinitialized. This procedure is called by Tcl_Finalize(). * * Results: * None. * * Side effects: * Cleans up the compilation environment. At the moment, just the * table of expression operators is freed. * *---------------------------------------------------------------------- */ void TclFinalizeCompilation() { Tcl_MutexLock(&opMutex); if (opTableInitialized) { Tcl_DeleteHashTable(&opHashTable); opTableInitialized = 0; } Tcl_MutexUnlock(&opMutex); } /* *---------------------------------------------------------------------- * * CompileSubExpr -- * * Given a pointer to a TCL_TOKEN_SUB_EXPR token describing a * subexpression, this procedure emits instructions to evaluate the * subexpression at runtime. * * Results: * The return value is TCL_OK on a successful compilation and TCL_ERROR * on failure. If TCL_ERROR is returned, then the interpreter's result * contains an error message. * * Side effects: * Adds instructions to envPtr to evaluate the subexpression. * *---------------------------------------------------------------------- */ static int CompileSubExpr(exprTokenPtr, infoPtr, envPtr) Tcl_Token *exprTokenPtr; /* Points to TCL_TOKEN_SUB_EXPR token * to compile. */ ExprInfo *infoPtr; /* Describes the compilation state for the * expression being compiled. */ CompileEnv *envPtr; /* Holds resulting instructions. */ { Tcl_Interp *interp = infoPtr->interp; Tcl_Token *tokenPtr, *endPtr = NULL; /* silence gcc 4 warning */ Tcl_Token *afterSubexprPtr; CONST OperatorDesc *opDescPtr; Tcl_HashEntry *hPtr; CONST char *operator; Tcl_DString opBuf; int objIndex, opIndex, length, code; char buffer[TCL_UTF_MAX]; if (exprTokenPtr->type != TCL_TOKEN_SUB_EXPR) { panic("CompileSubExpr: token type %d not TCL_TOKEN_SUB_EXPR\n", exprTokenPtr->type); } code = TCL_OK; /* * Switch on the type of the first token after the subexpression token. * After processing it, advance tokenPtr to point just after the * subexpression's last token. */ tokenPtr = exprTokenPtr+1; TRACE(exprTokenPtr->start, exprTokenPtr->size, tokenPtr->start, tokenPtr->size); switch (tokenPtr->type) { case TCL_TOKEN_WORD: code = TclCompileTokens(interp, tokenPtr+1, tokenPtr->numComponents, envPtr); if (code != TCL_OK) { goto done; } tokenPtr += (tokenPtr->numComponents + 1); break; case TCL_TOKEN_TEXT: if (tokenPtr->size > 0) { objIndex = TclRegisterNewLiteral(envPtr, tokenPtr->start, tokenPtr->size); } else { objIndex = TclRegisterNewLiteral(envPtr, "", 0); } TclEmitPush(objIndex, envPtr); tokenPtr += 1; break; case TCL_TOKEN_BS: length = TclParseBackslash(tokenPtr->start, tokenPtr->size, (int *) NULL, buffer); if (length > 0) { objIndex = TclRegisterNewLiteral(envPtr, buffer, length); } else { objIndex = TclRegisterNewLiteral(envPtr, "", 0); } TclEmitPush(objIndex, envPtr); tokenPtr += 1; break; case TCL_TOKEN_COMMAND: code = TclCompileScript(interp, tokenPtr->start+1, tokenPtr->size-2, /*nested*/ 0, envPtr); if (code != TCL_OK) { goto done; } tokenPtr += 1; break; case TCL_TOKEN_VARIABLE: code = TclCompileTokens(interp, tokenPtr, 1, envPtr); if (code != TCL_OK) { goto done; } tokenPtr += (tokenPtr->numComponents + 1); break; case TCL_TOKEN_SUB_EXPR: code = CompileSubExpr(tokenPtr, infoPtr, envPtr); if (code != TCL_OK) { goto done; } tokenPtr += (tokenPtr->numComponents + 1); break; case TCL_TOKEN_OPERATOR: /* * Look up the operator. If the operator isn't found, treat it * as a math function. */ Tcl_DStringInit(&opBuf); operator = Tcl_DStringAppend(&opBuf, tokenPtr->start, tokenPtr->size); hPtr = Tcl_FindHashEntry(&opHashTable, operator); if (hPtr == NULL) { code = CompileMathFuncCall(exprTokenPtr, operator, infoPtr, envPtr, &endPtr); Tcl_DStringFree(&opBuf); if (code != TCL_OK) { goto done; } tokenPtr = endPtr; break; } Tcl_DStringFree(&opBuf); opIndex = (int) Tcl_GetHashValue(hPtr); opDescPtr = &(operatorTable[opIndex]); /* * If the operator is "normal", compile it using information * from the operator table. */ if (opDescPtr->numOperands > 0) { tokenPtr++; code = CompileSubExpr(tokenPtr, infoPtr, envPtr); if (code != TCL_OK) { goto done; } tokenPtr += (tokenPtr->numComponents + 1); if (opDescPtr->numOperands == 2) { code = CompileSubExpr(tokenPtr, infoPtr, envPtr); if (code != TCL_OK) { goto done; } tokenPtr += (tokenPtr->numComponents + 1); } TclEmitOpcode(opDescPtr->instruction, envPtr); infoPtr->hasOperators = 1; break; } /* * The operator requires special treatment, and is either * "+" or "-", or one of "&&", "||" or "?". */ switch (opIndex) { case OP_PLUS: case OP_MINUS: tokenPtr++; code = CompileSubExpr(tokenPtr, infoPtr, envPtr); if (code != TCL_OK) { goto done; } tokenPtr += (tokenPtr->numComponents + 1); /* * Check whether the "+" or "-" is unary. */ afterSubexprPtr = exprTokenPtr + exprTokenPtr->numComponents+1; if (tokenPtr == afterSubexprPtr) { TclEmitOpcode(((opIndex==OP_PLUS)? INST_UPLUS : INST_UMINUS), envPtr); break; } /* * The "+" or "-" is binary. */ code = CompileSubExpr(tokenPtr, infoPtr, envPtr); if (code != TCL_OK) { goto done; } tokenPtr += (tokenPtr->numComponents + 1); TclEmitOpcode(((opIndex==OP_PLUS)? INST_ADD : INST_SUB), envPtr); break; case OP_LAND: case OP_LOR: code = CompileLandOrLorExpr(exprTokenPtr, opIndex, infoPtr, envPtr, &endPtr); if (code != TCL_OK) { goto done; } tokenPtr = endPtr; break; case OP_QUESTY: code = CompileCondExpr(exprTokenPtr, infoPtr, envPtr, &endPtr); if (code != TCL_OK) { goto done; } tokenPtr = endPtr; break; default: panic("CompileSubExpr: unexpected operator %d requiring special treatment\n", opIndex); } /* end switch on operator requiring special treatment */ infoPtr->hasOperators = 1; break; default: panic("CompileSubExpr: unexpected token type %d\n", tokenPtr->type); } /* * Verify that the subexpression token had the required number of * subtokens: that we've advanced tokenPtr just beyond the * subexpression's last token. For example, a "*" subexpression must * contain the tokens for exactly two operands. */ if (tokenPtr != (exprTokenPtr + exprTokenPtr->numComponents+1)) { LogSyntaxError(infoPtr); code = TCL_ERROR; } done: return code; } /* *---------------------------------------------------------------------- * * CompileLandOrLorExpr -- * * This procedure compiles a Tcl logical and ("&&") or logical or * ("||") subexpression. * * Results: * The return value is TCL_OK on a successful compilation and TCL_ERROR * on failure. If TCL_OK is returned, a pointer to the token just after * the last one in the subexpression is stored at the address in * endPtrPtr. If TCL_ERROR is returned, then the interpreter's result * contains an error message. * * Side effects: * Adds instructions to envPtr to evaluate the expression at runtime. * *---------------------------------------------------------------------- */ static int CompileLandOrLorExpr(exprTokenPtr, opIndex, infoPtr, envPtr, endPtrPtr) Tcl_Token *exprTokenPtr; /* Points to TCL_TOKEN_SUB_EXPR token * containing the "&&" or "||" operator. */ int opIndex; /* A code describing the expression * operator: either OP_LAND or OP_LOR. */ ExprInfo *infoPtr; /* Describes the compilation state for the * expression being compiled. */ CompileEnv *envPtr; /* Holds resulting instructions. */ Tcl_Token **endPtrPtr; /* If successful, a pointer to the token * just after the last token in the * subexpression is stored here. */ { JumpFixup shortCircuitFixup; /* Used to fix up the short circuit jump * after the first subexpression. */ JumpFixup lhsTrueFixup, lhsEndFixup; /* Used to fix up jumps used to convert the * first operand to 0 or 1. */ Tcl_Token *tokenPtr; int dist, code; int savedStackDepth = envPtr->currStackDepth; /* * Emit code for the first operand. */ tokenPtr = exprTokenPtr+2; code = CompileSubExpr(tokenPtr, infoPtr, envPtr); if (code != TCL_OK) { goto done; } tokenPtr += (tokenPtr->numComponents + 1); /* * Convert the first operand to the result that Tcl requires: * "0" or "1". Eventually we'll use a new instruction for this. */ TclEmitForwardJump(envPtr, TCL_TRUE_JUMP, &lhsTrueFixup); TclEmitPush(TclRegisterNewLiteral(envPtr, "0", 1), envPtr); TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &lhsEndFixup); dist = (envPtr->codeNext - envPtr->codeStart) - lhsTrueFixup.codeOffset; if (TclFixupForwardJump(envPtr, &lhsTrueFixup, dist, 127)) { badDist: panic("CompileLandOrLorExpr: bad jump distance %d\n", dist); } envPtr->currStackDepth = savedStackDepth; TclEmitPush(TclRegisterNewLiteral(envPtr, "1", 1), envPtr); dist = (envPtr->codeNext - envPtr->codeStart) - lhsEndFixup.codeOffset; if (TclFixupForwardJump(envPtr, &lhsEndFixup, dist, 127)) { goto badDist; } /* * Emit the "short circuit" jump around the rest of the expression. * Duplicate the "0" or "1" on top of the stack first to keep the * jump from consuming it. */ TclEmitOpcode(INST_DUP, envPtr); TclEmitForwardJump(envPtr, ((opIndex==OP_LAND)? TCL_FALSE_JUMP : TCL_TRUE_JUMP), &shortCircuitFixup); /* * Emit code for the second operand. */ code = CompileSubExpr(tokenPtr, infoPtr, envPtr); if (code != TCL_OK) { goto done; } tokenPtr += (tokenPtr->numComponents + 1); /* * Emit a "logical and" or "logical or" instruction. This does not try * to "short- circuit" the evaluation of both operands, but instead * ensures that we either have a "1" or a "0" result. */ TclEmitOpcode(((opIndex==OP_LAND)? INST_LAND : INST_LOR), envPtr); /* * Now that we know the target of the forward jump, update it with the * correct distance. */ dist = (envPtr->codeNext - envPtr->codeStart) - shortCircuitFixup.codeOffset; TclFixupForwardJump(envPtr, &shortCircuitFixup, dist, 127); *endPtrPtr = tokenPtr; done: envPtr->currStackDepth = savedStackDepth + 1; return code; } /* *---------------------------------------------------------------------- * * CompileCondExpr -- * * This procedure compiles a Tcl conditional expression: * condExpr ::= lorExpr ['?' condExpr ':' condExpr] * * Results: * The return value is TCL_OK on a successful compilation and TCL_ERROR * on failure. If TCL_OK is returned, a pointer to the token just after * the last one in the subexpression is stored at the address in * endPtrPtr. If TCL_ERROR is returned, then the interpreter's result * contains an error message. * * Side effects: * Adds instructions to envPtr to evaluate the expression at runtime. * *---------------------------------------------------------------------- */ static int CompileCondExpr(exprTokenPtr, infoPtr, envPtr, endPtrPtr) Tcl_Token *exprTokenPtr; /* Points to TCL_TOKEN_SUB_EXPR token * containing the "?" operator. */ ExprInfo *infoPtr; /* Describes the compilation state for the * expression being compiled. */ CompileEnv *envPtr; /* Holds resulting instructions. */ Tcl_Token **endPtrPtr; /* If successful, a pointer to the token * just after the last token in the * subexpression is stored here. */ { JumpFixup jumpAroundThenFixup, jumpAroundElseFixup; /* Used to update or replace one-byte jumps * around the then and else expressions when * their target PCs are determined. */ Tcl_Token *tokenPtr; int elseCodeOffset, dist, code; int savedStackDepth = envPtr->currStackDepth; /* * Emit code for the test. */ tokenPtr = exprTokenPtr+2; code = CompileSubExpr(tokenPtr, infoPtr, envPtr); if (code != TCL_OK) { goto done; } tokenPtr += (tokenPtr->numComponents + 1); /* * Emit the jump to the "else" expression if the test was false. */ TclEmitForwardJump(envPtr, TCL_FALSE_JUMP, &jumpAroundThenFixup); /* * Compile the "then" expression. Note that if a subexpression is only * a primary, we need to try to convert it to numeric. We do this to * support Tcl's policy of interpreting operands if at all possible as * first integers, else floating-point numbers. */ infoPtr->hasOperators = 0; code = CompileSubExpr(tokenPtr, infoPtr, envPtr); if (code != TCL_OK) { goto done; } tokenPtr += (tokenPtr->numComponents + 1); if (!infoPtr->hasOperators) { TclEmitOpcode(INST_TRY_CVT_TO_NUMERIC, envPtr); } /* * Emit an unconditional jump around the "else" condExpr. */ TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &jumpAroundElseFixup); /* * Compile the "else" expression. */ envPtr->currStackDepth = savedStackDepth; elseCodeOffset = (envPtr->codeNext - envPtr->codeStart); infoPtr->hasOperators = 0; code = CompileSubExpr(tokenPtr, infoPtr, envPtr); if (code != TCL_OK) { goto done; } tokenPtr += (tokenPtr->numComponents + 1); if (!infoPtr->hasOperators) { TclEmitOpcode(INST_TRY_CVT_TO_NUMERIC, envPtr); } /* * Fix up the second jump around the "else" expression. */ dist = (envPtr->codeNext - envPtr->codeStart) - jumpAroundElseFixup.codeOffset; if (TclFixupForwardJump(envPtr, &jumpAroundElseFixup, dist, 127)) { /* * Update the else expression's starting code offset since it * moved down 3 bytes too. */ elseCodeOffset += 3; } /* * Fix up the first jump to the "else" expression if the test was false. */ dist = (elseCodeOffset - jumpAroundThenFixup.codeOffset); TclFixupForwardJump(envPtr, &jumpAroundThenFixup, dist, 127); *endPtrPtr = tokenPtr; done: envPtr->currStackDepth = savedStackDepth + 1; return code; } /* *---------------------------------------------------------------------- * * CompileMathFuncCall -- * * This procedure compiles a call on a math function in an expression: * mathFuncCall ::= funcName '(' [condExpr {',' condExpr}] ')' * * Results: * The return value is TCL_OK on a successful compilation and TCL_ERROR * on failure. If TCL_OK is returned, a pointer to the token just after * the last one in the subexpression is stored at the address in * endPtrPtr. If TCL_ERROR is returned, then the interpreter's result * contains an error message. * * Side effects: * Adds instructions to envPtr to evaluate the math function at * runtime. * *---------------------------------------------------------------------- */ static int CompileMathFuncCall(exprTokenPtr, funcName, infoPtr, envPtr, endPtrPtr) Tcl_Token *exprTokenPtr; /* Points to TCL_TOKEN_SUB_EXPR token * containing the math function call. */ CONST char *funcName; /* Name of the math function. */ ExprInfo *infoPtr; /* Describes the compilation state for the * expression being compiled. */ CompileEnv *envPtr; /* Holds resulting instructions. */ Tcl_Token **endPtrPtr; /* If successful, a pointer to the token * just after the last token in the * subexpression is stored here. */ { Tcl_Interp *interp = infoPtr->interp; Interp *iPtr = (Interp *) interp; MathFunc *mathFuncPtr; Tcl_HashEntry *hPtr; Tcl_Token *tokenPtr, *afterSubexprPtr; int code, i; /* * Look up the MathFunc record for the function. */ code = TCL_OK; hPtr = Tcl_FindHashEntry(&iPtr->mathFuncTable, funcName); if (hPtr == NULL) { Tcl_ResetResult(interp); Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "unknown math function \"", funcName, "\"", (char *) NULL); code = TCL_ERROR; goto done; } mathFuncPtr = (MathFunc *) Tcl_GetHashValue(hPtr); /* * If not a builtin function, push an object with the function's name. */ if (mathFuncPtr->builtinFuncIndex < 0) { TclEmitPush(TclRegisterNewLiteral(envPtr, funcName, -1), envPtr); } /* * Compile any arguments for the function. */ tokenPtr = exprTokenPtr+2; afterSubexprPtr = exprTokenPtr + (exprTokenPtr->numComponents + 1); if (mathFuncPtr->numArgs > 0) { for (i = 0; i < mathFuncPtr->numArgs; i++) { if (tokenPtr == afterSubexprPtr) { Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "too few arguments for math function", -1); code = TCL_ERROR; goto done; } code = CompileSubExpr(tokenPtr, infoPtr, envPtr); if (code != TCL_OK) { goto done; } tokenPtr += (tokenPtr->numComponents + 1); } if (tokenPtr != afterSubexprPtr) { Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "too many arguments for math function", -1); code = TCL_ERROR; goto done; } } else if (tokenPtr != afterSubexprPtr) { Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "too many arguments for math function", -1); code = TCL_ERROR; goto done; } /* * Compile the call on the math function. Note that the "objc" argument * count for non-builtin functions is incremented by 1 to include the * function name itself. */ if (mathFuncPtr->builtinFuncIndex >= 0) { /* a builtin function */ /* * Adjust the current stack depth by the number of arguments * of the builtin function. This cannot be handled by the * TclEmitInstInt1 macro as the number of arguments is not * passed as an operand. */ if (envPtr->maxStackDepth < envPtr->currStackDepth) { envPtr->maxStackDepth = envPtr->currStackDepth; } TclEmitInstInt1(INST_CALL_BUILTIN_FUNC1, mathFuncPtr->builtinFuncIndex, envPtr); envPtr->currStackDepth -= mathFuncPtr->numArgs; } else { TclEmitInstInt1(INST_CALL_FUNC1, (mathFuncPtr->numArgs+1), envPtr); } *endPtrPtr = afterSubexprPtr; done: return code; } /* *---------------------------------------------------------------------- * * LogSyntaxError -- * * This procedure is invoked after an error occurs when compiling an * expression. It sets the interpreter result to an error message * describing the error. * * Results: * None. * * Side effects: * Sets the interpreter result to an error message describing the * expression that was being compiled when the error occurred. * *---------------------------------------------------------------------- */ static void LogSyntaxError(infoPtr) ExprInfo *infoPtr; /* Describes the compilation state for the * expression being compiled. */ { int numBytes = (infoPtr->lastChar - infoPtr->expr); char buffer[100]; sprintf(buffer, "syntax error in expression \"%.*s\"", ((numBytes > 60)? 60 : numBytes), infoPtr->expr); Tcl_ResetResult(infoPtr->interp); Tcl_AppendStringsToObj(Tcl_GetObjResult(infoPtr->interp), buffer, (char *) NULL); } tcl8.4.20/generic/tclIO.h0000644003604700454610000003067312133546540013520 0ustar dgp771div/* * tclIO.h -- * * This file provides the generic portions (those that are the same on * all platforms and for all channel types) of Tcl's IO facilities. * * Copyright (c) 1998-2000 Ajuba Solutions * Copyright (c) 1995-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ /* * Make sure that both EAGAIN and EWOULDBLOCK are defined. This does not * compile on systems where neither is defined. We want both defined so * that we can test safely for both. In the code we still have to test for * both because there may be systems on which both are defined and have * different values. */ #if ((!defined(EWOULDBLOCK)) && (defined(EAGAIN))) # define EWOULDBLOCK EAGAIN #endif #if ((!defined(EAGAIN)) && (defined(EWOULDBLOCK))) # define EAGAIN EWOULDBLOCK #endif #if ((!defined(EAGAIN)) && (!defined(EWOULDBLOCK))) error one of EWOULDBLOCK or EAGAIN must be defined #endif /* * struct ChannelBuffer: * * Buffers data being sent to or from a channel. */ typedef struct ChannelBuffer { int nextAdded; /* The next position into which a character * will be put in the buffer. */ int nextRemoved; /* Position of next byte to be removed * from the buffer. */ int bufLength; /* How big is the buffer? */ struct ChannelBuffer *nextPtr; /* Next buffer in chain. */ char buf[4]; /* Placeholder for real buffer. The real * buffer occuppies this space + bufSize-4 * bytes. This must be the last field in * the structure. */ } ChannelBuffer; #define CHANNELBUFFER_HEADER_SIZE (sizeof(ChannelBuffer) - 4) /* * How much extra space to allocate in buffer to hold bytes from previous * buffer (when converting to UTF-8) or to hold bytes that will go to * next buffer (when converting from UTF-8). */ #define BUFFER_PADDING 16 /* * The following defines the *default* buffer size for channels. */ #define CHANNELBUFFER_DEFAULT_SIZE (1024 * 4) /* * The following structure describes the information saved from a call to * "fileevent". This is used later when the event being waited for to * invoke the saved script in the interpreter designed in this record. */ typedef struct EventScriptRecord { struct Channel *chanPtr; /* The channel for which this script is * registered. This is used only when an * error occurs during evaluation of the * script, to delete the handler. */ Tcl_Obj *scriptPtr; /* Script to invoke. */ Tcl_Interp *interp; /* In what interpreter to invoke script? */ int mask; /* Events must overlap current mask for the * stored script to be invoked. */ struct EventScriptRecord *nextPtr; /* Next in chain of records. */ } EventScriptRecord; /* * struct Channel: * * One of these structures is allocated for each open channel. It contains data * specific to the channel but which belongs to the generic part of the Tcl * channel mechanism, and it points at an instance specific (and type * specific) * instance data, and at a channel type structure. */ typedef struct Channel { struct ChannelState *state; /* Split out state information */ ClientData instanceData; /* Instance-specific data provided by * creator of channel. */ Tcl_ChannelType *typePtr; /* Pointer to channel type structure. */ struct Channel *downChanPtr;/* Refers to channel this one was stacked * upon. This reference is NULL for normal * channels. See Tcl_StackChannel. */ struct Channel *upChanPtr; /* Refers to the channel above stacked this * one. NULL for the top most channel. */ /* * Intermediate buffers to hold pre-read data for consumption by a * newly stacked transformation. See 'Tcl_StackChannel'. */ ChannelBuffer *inQueueHead; /* Points at first buffer in input queue. */ ChannelBuffer *inQueueTail; /* Points at last buffer in input queue. */ } Channel; /* * struct ChannelState: * * One of these structures is allocated for each open channel. It contains data * specific to the channel but which belongs to the generic part of the Tcl * channel mechanism, and it points at an instance specific (and type * specific) * instance data, and at a channel type structure. */ typedef struct ChannelState { CONST char *channelName; /* The name of the channel instance in Tcl * commands. Storage is owned by the generic IO * code, is dynamically allocated. */ int flags; /* ORed combination of the flags defined * below. */ Tcl_Encoding encoding; /* Encoding to apply when reading or writing * data on this channel. NULL means no * encoding is applied to data. */ Tcl_EncodingState inputEncodingState; /* Current encoding state, used when converting * input data bytes to UTF-8. */ int inputEncodingFlags; /* Encoding flags to pass to conversion * routine when converting input data bytes to * UTF-8. May be TCL_ENCODING_START before * converting first byte and TCL_ENCODING_END * when EOF is seen. */ Tcl_EncodingState outputEncodingState; /* Current encoding state, used when converting * UTF-8 to output data bytes. */ int outputEncodingFlags; /* Encoding flags to pass to conversion * routine when converting UTF-8 to output * data bytes. May be TCL_ENCODING_START * before converting first byte and * TCL_ENCODING_END when EOF is seen. */ TclEolTranslation inputTranslation; /* What translation to apply for end of line * sequences on input? */ TclEolTranslation outputTranslation; /* What translation to use for generating * end of line sequences in output? */ int inEofChar; /* If nonzero, use this as a signal of EOF * on input. */ int outEofChar; /* If nonzero, append this to the channel * when it is closed if it is open for * writing. */ int unreportedError; /* Non-zero if an error report was deferred * because it happened in the background. The * value is the POSIX error code. */ int refCount; /* How many interpreters hold references to * this IO channel? */ struct CloseCallback *closeCbPtr; /* Callbacks registered to be called when the * channel is closed. */ char *outputStage; /* Temporary staging buffer used when * translating EOL before converting from * UTF-8 to external form. */ ChannelBuffer *curOutPtr; /* Current output buffer being filled. */ ChannelBuffer *outQueueHead;/* Points at first buffer in output queue. */ ChannelBuffer *outQueueTail;/* Points at last buffer in output queue. */ ChannelBuffer *saveInBufPtr;/* Buffer saved for input queue - eliminates * need to allocate a new buffer for "gets" * that crosses buffer boundaries. */ ChannelBuffer *inQueueHead; /* Points at first buffer in input queue. */ ChannelBuffer *inQueueTail; /* Points at last buffer in input queue. */ struct ChannelHandler *chPtr;/* List of channel handlers registered * for this channel. */ int interestMask; /* Mask of all events this channel has * handlers for. */ EventScriptRecord *scriptRecordPtr; /* Chain of all scripts registered for * event handlers ("fileevent") on this * channel. */ int bufSize; /* What size buffers to allocate? */ Tcl_TimerToken timer; /* Handle to wakeup timer for this channel. */ struct CopyState *csPtrR; /* State of background copy for which channel * is input, or NULL. */ struct CopyState *csPtrW; /* State of background copy for which channel * is output, or NULL. */ Channel *topChanPtr; /* Refers to topmost channel in a stack. * Never NULL. */ Channel *bottomChanPtr; /* Refers to bottommost channel in a stack. * This channel can be relied on to live as * long as the channel state. Never NULL. */ struct ChannelState *nextCSPtr; /* Next in list of channels currently open. */ Tcl_ThreadId managingThread; /* TIP #10: Id of the thread managing * this stack of channels. */ } ChannelState; /* * Values for the flags field in Channel. Any ORed combination of the * following flags can be stored in the field. These flags record various * options and state bits about the channel. In addition to the flags below, * the channel can also have TCL_READABLE (1<<1) and TCL_WRITABLE (1<<2) set. */ #define CHANNEL_NONBLOCKING (1<<3) /* Channel is currently in * nonblocking mode. */ #define CHANNEL_LINEBUFFERED (1<<4) /* Output to the channel must be * flushed after every newline. */ #define CHANNEL_UNBUFFERED (1<<5) /* Output to the channel must always * be flushed immediately. */ #define BUFFER_READY (1<<6) /* Current output buffer (the * curOutPtr field in the * channel structure) should be * output as soon as possible even * though it may not be full. */ #define BG_FLUSH_SCHEDULED (1<<7) /* A background flush of the * queued output buffers has been * scheduled. */ #define CHANNEL_CLOSED (1<<8) /* Channel has been closed. No * further Tcl-level IO on the * channel is allowed. */ #define CHANNEL_EOF (1<<9) /* EOF occurred on this channel. * This bit is cleared before every * input operation. */ #define CHANNEL_STICKY_EOF (1<<10) /* EOF occurred on this channel because * we saw the input eofChar. This bit * prevents clearing of the EOF bit * before every input operation. */ #define CHANNEL_BLOCKED (1<<11) /* EWOULDBLOCK or EAGAIN occurred * on this channel. This bit is * cleared before every input or * output operation. */ #define INPUT_SAW_CR (1<<12) /* Channel is in CRLF eol input * translation mode and the last * byte seen was a "\r". */ #define INPUT_NEED_NL (1<<15) /* Saw a '\r' at end of last buffer, * and there should be a '\n' at * beginning of next buffer. */ #define CHANNEL_DEAD (1<<13) /* The channel has been closed by * the exit handler (on exit) but * not deallocated. When any IO * operation sees this flag on a * channel, it does not call driver * level functions to avoid referring * to deallocated data. */ #define CHANNEL_NEED_MORE_DATA (1<<14) /* The last input operation failed * because there was not enough data * to complete the operation. This * flag is set when gets fails to * get a complete line or when read * fails to get a complete character. * When set, file events will not be * delivered for buffered data until * the state of the channel changes. */ #define CHANNEL_RAW_MODE (1<<16) /* When set, notes that the Raw API is * being used. */ #ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING #define CHANNEL_TIMER_FEV (1<<17) /* When set the event we are * notified by is a fileevent * generated by a timer. We * don't know if the driver * has more data and should * not try to read from it. If * the system needs more than * is in the buffers out read * routines will simulate a * short read (0 characters * read) */ #define CHANNEL_HAS_MORE_DATA (1<<18) /* Set by NotifyChannel for a * channel if and only if the * channel is configured * non-blocking, the driver * for said channel has no * blockmodeproc, and data has * arrived for reading at the * OS level). A GetInput will * pass reading from the * driver if the channel is * non-blocking, without * blockmode proc and the flag * has not been set. A read * will be performed if the * flag is set. This will * reset the flag as well. */ #endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */ #define CHANNEL_INCLOSE (1<<19) /* Channel is currently being * closed. Its structures are * still live and usable, but * it may not be closed again * from within the close handler. */ tcl8.4.20/generic/tclTestObj.c0000644003604700454610000010754412133546540014560 0ustar dgp771div/* * tclTestObj.c -- * * This file contains C command procedures for the additional Tcl * commands that are used for testing implementations of the Tcl object * types. These commands are not normally included in Tcl * applications; they're only used for testing. * * Copyright (c) 1995-1998 Sun Microsystems, Inc. * Copyright (c) 1999 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" /* * An array of Tcl_Obj pointers used in the commands that operate on or get * the values of Tcl object-valued variables. varPtr[i] is the i-th * variable's Tcl_Obj *. */ #define NUMBER_OF_OBJECT_VARS 20 static Tcl_Obj *varPtr[NUMBER_OF_OBJECT_VARS]; /* * Forward declarations for procedures defined later in this file: */ static int CheckIfVarUnset _ANSI_ARGS_((Tcl_Interp *interp, int varIndex)); static int GetVariableIndex _ANSI_ARGS_((Tcl_Interp *interp, char *string, int *indexPtr)); static void SetVarToObj _ANSI_ARGS_((int varIndex, Tcl_Obj *objPtr)); int TclObjTest_Init _ANSI_ARGS_((Tcl_Interp *interp)); static int TestbooleanobjCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int TestconvertobjCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int TestdoubleobjCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int TestindexobjCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int TestintobjCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int TestobjCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int TeststringobjCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); typedef struct TestString { int numChars; size_t allocated; size_t uallocated; Tcl_UniChar unicode[2]; } TestString; /* *---------------------------------------------------------------------- * * TclObjTest_Init -- * * This procedure creates additional commands that are used to test the * Tcl object support. * * Results: * Returns a standard Tcl completion code, and leaves an error * message in the interp's result if an error occurs. * * Side effects: * Creates and registers several new testing commands. * *---------------------------------------------------------------------- */ int TclObjTest_Init(interp) Tcl_Interp *interp; { register int i; for (i = 0; i < NUMBER_OF_OBJECT_VARS; i++) { varPtr[i] = NULL; } Tcl_CreateObjCommand(interp, "testbooleanobj", TestbooleanobjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "testconvertobj", TestconvertobjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "testdoubleobj", TestdoubleobjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "testintobj", TestintobjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "testindexobj", TestindexobjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "testobj", TestobjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "teststringobj", TeststringobjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); return TCL_OK; } /* *---------------------------------------------------------------------- * * TestbooleanobjCmd -- * * This procedure implements the "testbooleanobj" command. It is used * to test the boolean Tcl object type implementation. * * Results: * A standard Tcl object result. * * Side effects: * Creates and frees boolean objects, and also converts objects to * have boolean type. * *---------------------------------------------------------------------- */ static int TestbooleanobjCmd(clientData, interp, objc, objv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int varIndex, boolValue; char *index, *subCmd; if (objc < 3) { wrongNumArgs: Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg ...?"); return TCL_ERROR; } index = Tcl_GetString(objv[2]); if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) { return TCL_ERROR; } subCmd = Tcl_GetString(objv[1]); if (strcmp(subCmd, "set") == 0) { if (objc != 4) { goto wrongNumArgs; } if (Tcl_GetBooleanFromObj(interp, objv[3], &boolValue) != TCL_OK) { return TCL_ERROR; } /* * If the object currently bound to the variable with index varIndex * has ref count 1 (i.e. the object is unshared) we can modify that * object directly. Otherwise, if RC>1 (i.e. the object is shared), * we must create a new object to modify/set and decrement the old * formerly-shared object's ref count. This is "copy on write". */ if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) { Tcl_SetBooleanObj(varPtr[varIndex], boolValue); } else { SetVarToObj(varIndex, Tcl_NewBooleanObj(boolValue)); } Tcl_SetObjResult(interp, varPtr[varIndex]); } else if (strcmp(subCmd, "get") == 0) { if (objc != 3) { goto wrongNumArgs; } if (CheckIfVarUnset(interp, varIndex)) { return TCL_ERROR; } Tcl_SetObjResult(interp, varPtr[varIndex]); } else if (strcmp(subCmd, "not") == 0) { if (objc != 3) { goto wrongNumArgs; } if (CheckIfVarUnset(interp, varIndex)) { return TCL_ERROR; } if (Tcl_GetBooleanFromObj(interp, varPtr[varIndex], &boolValue) != TCL_OK) { return TCL_ERROR; } if (!Tcl_IsShared(varPtr[varIndex])) { Tcl_SetBooleanObj(varPtr[varIndex], !boolValue); } else { SetVarToObj(varIndex, Tcl_NewBooleanObj(!boolValue)); } Tcl_SetObjResult(interp, varPtr[varIndex]); } else { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "bad option \"", Tcl_GetString(objv[1]), "\": must be set, get, or not", (char *) NULL); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * TestconvertobjCmd -- * * This procedure implements the "testconvertobj" command. It is used * to test converting objects to new types. * * Results: * A standard Tcl object result. * * Side effects: * Converts objects to new types. * *---------------------------------------------------------------------- */ static int TestconvertobjCmd(clientData, interp, objc, objv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { char *subCmd; char buf[20]; if (objc < 3) { wrongNumArgs: Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg ...?"); return TCL_ERROR; } subCmd = Tcl_GetString(objv[1]); if (strcmp(subCmd, "double") == 0) { double d; if (objc != 3) { goto wrongNumArgs; } if (Tcl_GetDoubleFromObj(interp, objv[2], &d) != TCL_OK) { return TCL_ERROR; } sprintf(buf, "%f", d); Tcl_AppendToObj(Tcl_GetObjResult(interp), buf, -1); } else { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "bad option \"", Tcl_GetString(objv[1]), "\": must be double", (char *) NULL); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * TestdoubleobjCmd -- * * This procedure implements the "testdoubleobj" command. It is used * to test the double-precision floating point Tcl object type * implementation. * * Results: * A standard Tcl object result. * * Side effects: * Creates and frees double objects, and also converts objects to * have double type. * *---------------------------------------------------------------------- */ static int TestdoubleobjCmd(clientData, interp, objc, objv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int varIndex; double doubleValue; char *index, *subCmd, *string; if (objc < 3) { wrongNumArgs: Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg ...?"); return TCL_ERROR; } index = Tcl_GetString(objv[2]); if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) { return TCL_ERROR; } subCmd = Tcl_GetString(objv[1]); if (strcmp(subCmd, "set") == 0) { if (objc != 4) { goto wrongNumArgs; } string = Tcl_GetString(objv[3]); if (Tcl_GetDouble(interp, string, &doubleValue) != TCL_OK) { return TCL_ERROR; } /* * If the object currently bound to the variable with index varIndex * has ref count 1 (i.e. the object is unshared) we can modify that * object directly. Otherwise, if RC>1 (i.e. the object is shared), * we must create a new object to modify/set and decrement the old * formerly-shared object's ref count. This is "copy on write". */ if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) { Tcl_SetDoubleObj(varPtr[varIndex], doubleValue); } else { SetVarToObj(varIndex, Tcl_NewDoubleObj(doubleValue)); } Tcl_SetObjResult(interp, varPtr[varIndex]); } else if (strcmp(subCmd, "get") == 0) { if (objc != 3) { goto wrongNumArgs; } if (CheckIfVarUnset(interp, varIndex)) { return TCL_ERROR; } Tcl_SetObjResult(interp, varPtr[varIndex]); } else if (strcmp(subCmd, "mult10") == 0) { if (objc != 3) { goto wrongNumArgs; } if (CheckIfVarUnset(interp, varIndex)) { return TCL_ERROR; } if (Tcl_GetDoubleFromObj(interp, varPtr[varIndex], &doubleValue) != TCL_OK) { return TCL_ERROR; } if (!Tcl_IsShared(varPtr[varIndex])) { Tcl_SetDoubleObj(varPtr[varIndex], (doubleValue * 10.0)); } else { SetVarToObj(varIndex, Tcl_NewDoubleObj( (doubleValue * 10.0) )); } Tcl_SetObjResult(interp, varPtr[varIndex]); } else if (strcmp(subCmd, "div10") == 0) { if (objc != 3) { goto wrongNumArgs; } if (CheckIfVarUnset(interp, varIndex)) { return TCL_ERROR; } if (Tcl_GetDoubleFromObj(interp, varPtr[varIndex], &doubleValue) != TCL_OK) { return TCL_ERROR; } if (!Tcl_IsShared(varPtr[varIndex])) { Tcl_SetDoubleObj(varPtr[varIndex], (doubleValue / 10.0)); } else { SetVarToObj(varIndex, Tcl_NewDoubleObj( (doubleValue / 10.0) )); } Tcl_SetObjResult(interp, varPtr[varIndex]); } else { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "bad option \"", Tcl_GetString(objv[1]), "\": must be set, get, mult10, or div10", (char *) NULL); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * TestindexobjCmd -- * * This procedure implements the "testindexobj" command. It is used to * test the index Tcl object type implementation. * * Results: * A standard Tcl object result. * * Side effects: * Creates and frees int objects, and also converts objects to * have int type. * *---------------------------------------------------------------------- */ static int TestindexobjCmd(clientData, interp, objc, objv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int allowAbbrev, index, index2, setError, i, result; CONST char **argv; static CONST char *tablePtr[] = {"a", "b", "check", (char *) NULL}; /* * Keep this structure declaration in sync with tclIndexObj.c */ struct IndexRep { VOID *tablePtr; /* Pointer to the table of strings */ int offset; /* Offset between table entries */ int index; /* Selected index into table. */ }; struct IndexRep *indexRep; if ((objc == 3) && (strcmp(Tcl_GetString(objv[1]), "check") == 0)) { /* * This code checks to be sure that the results of * Tcl_GetIndexFromObj are properly cached in the object and * returned on subsequent lookups. */ if (Tcl_GetIntFromObj(interp, objv[2], &index2) != TCL_OK) { return TCL_ERROR; } Tcl_GetIndexFromObj((Tcl_Interp *) NULL, objv[1], tablePtr, "token", 0, &index); indexRep = (struct IndexRep *) objv[1]->internalRep.otherValuePtr; indexRep->index = index2; result = Tcl_GetIndexFromObj((Tcl_Interp *) NULL, objv[1], tablePtr, "token", 0, &index); if (result == TCL_OK) { Tcl_SetIntObj(Tcl_GetObjResult(interp), index); } return result; } if (objc < 5) { Tcl_AppendToObj(Tcl_GetObjResult(interp), "wrong # args", -1); return TCL_ERROR; } if (Tcl_GetBooleanFromObj(interp, objv[1], &setError) != TCL_OK) { return TCL_ERROR; } if (Tcl_GetBooleanFromObj(interp, objv[2], &allowAbbrev) != TCL_OK) { return TCL_ERROR; } argv = (CONST char **) ckalloc((unsigned) ((objc-3) * sizeof(char *))); for (i = 4; i < objc; i++) { argv[i-4] = Tcl_GetString(objv[i]); } argv[objc-4] = NULL; /* * Tcl_GetIndexFromObj assumes that the table is statically-allocated * so that its address is different for each index object. If we * accidently allocate a table at the same address as that cached in * the index object, clear out the object's cached state. */ if ( objv[3]->typePtr != NULL && !strcmp( "index", objv[3]->typePtr->name ) ) { indexRep = (struct IndexRep *) objv[3]->internalRep.otherValuePtr; if (indexRep->tablePtr == (VOID *) argv) { objv[3]->typePtr->freeIntRepProc(objv[3]); objv[3]->typePtr = NULL; } } result = Tcl_GetIndexFromObj((setError? interp : NULL), objv[3], argv, "token", (allowAbbrev? 0 : TCL_EXACT), &index); ckfree((char *) argv); if (result == TCL_OK) { Tcl_SetIntObj(Tcl_GetObjResult(interp), index); } return result; } /* *---------------------------------------------------------------------- * * TestintobjCmd -- * * This procedure implements the "testintobj" command. It is used to * test the int Tcl object type implementation. * * Results: * A standard Tcl object result. * * Side effects: * Creates and frees int objects, and also converts objects to * have int type. * *---------------------------------------------------------------------- */ static int TestintobjCmd(clientData, interp, objc, objv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int intValue, varIndex, i; long longValue; char *index, *subCmd, *string; if (objc < 3) { wrongNumArgs: Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg ...?"); return TCL_ERROR; } index = Tcl_GetString(objv[2]); if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) { return TCL_ERROR; } subCmd = Tcl_GetString(objv[1]); if (strcmp(subCmd, "set") == 0) { if (objc != 4) { goto wrongNumArgs; } string = Tcl_GetString(objv[3]); if (Tcl_GetInt(interp, string, &i) != TCL_OK) { return TCL_ERROR; } intValue = i; /* * If the object currently bound to the variable with index varIndex * has ref count 1 (i.e. the object is unshared) we can modify that * object directly. Otherwise, if RC>1 (i.e. the object is shared), * we must create a new object to modify/set and decrement the old * formerly-shared object's ref count. This is "copy on write". */ if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) { Tcl_SetIntObj(varPtr[varIndex], intValue); } else { SetVarToObj(varIndex, Tcl_NewIntObj(intValue)); } Tcl_SetObjResult(interp, varPtr[varIndex]); } else if (strcmp(subCmd, "set2") == 0) { /* doesn't set result */ if (objc != 4) { goto wrongNumArgs; } string = Tcl_GetString(objv[3]); if (Tcl_GetInt(interp, string, &i) != TCL_OK) { return TCL_ERROR; } intValue = i; if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) { Tcl_SetIntObj(varPtr[varIndex], intValue); } else { SetVarToObj(varIndex, Tcl_NewIntObj(intValue)); } } else if (strcmp(subCmd, "setlong") == 0) { if (objc != 4) { goto wrongNumArgs; } string = Tcl_GetString(objv[3]); if (Tcl_GetInt(interp, string, &i) != TCL_OK) { return TCL_ERROR; } intValue = i; if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) { Tcl_SetLongObj(varPtr[varIndex], intValue); } else { SetVarToObj(varIndex, Tcl_NewLongObj(intValue)); } Tcl_SetObjResult(interp, varPtr[varIndex]); } else if (strcmp(subCmd, "setmaxlong") == 0) { long maxLong = LONG_MAX; if (objc != 3) { goto wrongNumArgs; } if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) { Tcl_SetLongObj(varPtr[varIndex], maxLong); } else { SetVarToObj(varIndex, Tcl_NewLongObj(maxLong)); } } else if (strcmp(subCmd, "ismaxlong") == 0) { if (objc != 3) { goto wrongNumArgs; } if (CheckIfVarUnset(interp, varIndex)) { return TCL_ERROR; } if (Tcl_GetLongFromObj(interp, varPtr[varIndex], &longValue) != TCL_OK) { return TCL_ERROR; } Tcl_AppendToObj(Tcl_GetObjResult(interp), ((longValue == LONG_MAX)? "1" : "0"), -1); } else if (strcmp(subCmd, "get") == 0) { if (objc != 3) { goto wrongNumArgs; } if (CheckIfVarUnset(interp, varIndex)) { return TCL_ERROR; } Tcl_SetObjResult(interp, varPtr[varIndex]); } else if (strcmp(subCmd, "get2") == 0) { if (objc != 3) { goto wrongNumArgs; } if (CheckIfVarUnset(interp, varIndex)) { return TCL_ERROR; } string = Tcl_GetString(varPtr[varIndex]); Tcl_AppendToObj(Tcl_GetObjResult(interp), string, -1); } else if (strcmp(subCmd, "inttoobigtest") == 0) { /* * If long ints have more bits than ints on this platform, verify * that Tcl_GetIntFromObj returns an error if the long int held * in an integer object's internal representation is too large * to fit in an int. */ if (objc != 3) { goto wrongNumArgs; } #if (INT_MAX == LONG_MAX) /* int is same size as long int */ Tcl_AppendToObj(Tcl_GetObjResult(interp), "1", -1); #else if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) { Tcl_SetLongObj(varPtr[varIndex], LONG_MAX); } else { SetVarToObj(varIndex, Tcl_NewLongObj(LONG_MAX)); } if (Tcl_GetIntFromObj(interp, varPtr[varIndex], &i) != TCL_OK) { Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "1", -1); return TCL_OK; } Tcl_AppendToObj(Tcl_GetObjResult(interp), "0", -1); #endif } else if (strcmp(subCmd, "mult10") == 0) { if (objc != 3) { goto wrongNumArgs; } if (CheckIfVarUnset(interp, varIndex)) { return TCL_ERROR; } if (Tcl_GetIntFromObj(interp, varPtr[varIndex], &intValue) != TCL_OK) { return TCL_ERROR; } if (!Tcl_IsShared(varPtr[varIndex])) { Tcl_SetIntObj(varPtr[varIndex], (intValue * 10)); } else { SetVarToObj(varIndex, Tcl_NewIntObj( (intValue * 10) )); } Tcl_SetObjResult(interp, varPtr[varIndex]); } else if (strcmp(subCmd, "div10") == 0) { if (objc != 3) { goto wrongNumArgs; } if (CheckIfVarUnset(interp, varIndex)) { return TCL_ERROR; } if (Tcl_GetIntFromObj(interp, varPtr[varIndex], &intValue) != TCL_OK) { return TCL_ERROR; } if (!Tcl_IsShared(varPtr[varIndex])) { Tcl_SetIntObj(varPtr[varIndex], (intValue / 10)); } else { SetVarToObj(varIndex, Tcl_NewIntObj( (intValue / 10) )); } Tcl_SetObjResult(interp, varPtr[varIndex]); } else { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "bad option \"", Tcl_GetString(objv[1]), "\": must be set, get, get2, mult10, or div10", (char *) NULL); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * TestobjCmd -- * * This procedure implements the "testobj" command. It is used to test * the type-independent portions of the Tcl object type implementation. * * Results: * A standard Tcl object result. * * Side effects: * Creates and frees objects. * *---------------------------------------------------------------------- */ static int TestobjCmd(clientData, interp, objc, objv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int varIndex, destIndex, i; char *index, *subCmd, *string; Tcl_ObjType *targetType; if (objc < 2) { wrongNumArgs: Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg ...?"); return TCL_ERROR; } subCmd = Tcl_GetString(objv[1]); if (strcmp(subCmd, "assign") == 0) { if (objc != 4) { goto wrongNumArgs; } index = Tcl_GetString(objv[2]); if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) { return TCL_ERROR; } if (CheckIfVarUnset(interp, varIndex)) { return TCL_ERROR; } string = Tcl_GetString(objv[3]); if (GetVariableIndex(interp, string, &destIndex) != TCL_OK) { return TCL_ERROR; } SetVarToObj(destIndex, varPtr[varIndex]); Tcl_SetObjResult(interp, varPtr[destIndex]); } else if (strcmp(subCmd, "bug3598580") == 0) { Tcl_Obj *listObjPtr, *elemObjPtr; if (objc != 2) { goto wrongNumArgs; } elemObjPtr = Tcl_NewIntObj(123); listObjPtr = Tcl_NewListObj(1, &elemObjPtr); /* Replace the single list element through itself, nonsense but legal. */ Tcl_ListObjReplace(interp, listObjPtr, 0, 1, 1, &elemObjPtr); Tcl_SetObjResult(interp, listObjPtr); return TCL_OK; } else if (strcmp(subCmd, "convert") == 0) { char *typeName; if (objc != 4) { goto wrongNumArgs; } index = Tcl_GetString(objv[2]); if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) { return TCL_ERROR; } if (CheckIfVarUnset(interp, varIndex)) { return TCL_ERROR; } typeName = Tcl_GetString(objv[3]); if ((targetType = Tcl_GetObjType(typeName)) == NULL) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "no type ", typeName, " found", (char *) NULL); return TCL_ERROR; } if (Tcl_ConvertToType(interp, varPtr[varIndex], targetType) != TCL_OK) { return TCL_ERROR; } Tcl_SetObjResult(interp, varPtr[varIndex]); } else if (strcmp(subCmd, "duplicate") == 0) { if (objc != 4) { goto wrongNumArgs; } index = Tcl_GetString(objv[2]); if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) { return TCL_ERROR; } if (CheckIfVarUnset(interp, varIndex)) { return TCL_ERROR; } string = Tcl_GetString(objv[3]); if (GetVariableIndex(interp, string, &destIndex) != TCL_OK) { return TCL_ERROR; } SetVarToObj(destIndex, Tcl_DuplicateObj(varPtr[varIndex])); Tcl_SetObjResult(interp, varPtr[destIndex]); } else if (strcmp(subCmd, "freeallvars") == 0) { if (objc != 2) { goto wrongNumArgs; } for (i = 0; i < NUMBER_OF_OBJECT_VARS; i++) { if (varPtr[i] != NULL) { Tcl_DecrRefCount(varPtr[i]); varPtr[i] = NULL; } } } else if ( strcmp ( subCmd, "invalidateStringRep" ) == 0 ) { if ( objc != 3 ) { goto wrongNumArgs; } index = Tcl_GetString( objv[2] ); if ( GetVariableIndex( interp, index, &varIndex ) != TCL_OK ) { return TCL_ERROR; } if (CheckIfVarUnset(interp, varIndex)) { return TCL_ERROR; } Tcl_InvalidateStringRep( varPtr[varIndex] ); Tcl_SetObjResult( interp, varPtr[varIndex] ); } else if (strcmp(subCmd, "newobj") == 0) { if (objc != 3) { goto wrongNumArgs; } index = Tcl_GetString(objv[2]); if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) { return TCL_ERROR; } SetVarToObj(varIndex, Tcl_NewObj()); Tcl_SetObjResult(interp, varPtr[varIndex]); } else if (strcmp(subCmd, "objtype") == 0) { char *typeName; /* * return an object containing the name of the argument's type * of internal rep. If none exists, return "none". */ if (objc != 3) { goto wrongNumArgs; } if (objv[2]->typePtr == NULL) { Tcl_SetObjResult(interp, Tcl_NewStringObj("none", -1)); } else { typeName = objv[2]->typePtr->name; Tcl_SetObjResult(interp, Tcl_NewStringObj(typeName, -1)); } } else if (strcmp(subCmd, "refcount") == 0) { char buf[TCL_INTEGER_SPACE]; if (objc != 3) { goto wrongNumArgs; } index = Tcl_GetString(objv[2]); if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) { return TCL_ERROR; } if (CheckIfVarUnset(interp, varIndex)) { return TCL_ERROR; } TclFormatInt(buf, varPtr[varIndex]->refCount); Tcl_SetResult(interp, buf, TCL_VOLATILE); } else if (strcmp(subCmd, "type") == 0) { if (objc != 3) { goto wrongNumArgs; } index = Tcl_GetString(objv[2]); if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) { return TCL_ERROR; } if (CheckIfVarUnset(interp, varIndex)) { return TCL_ERROR; } if (varPtr[varIndex]->typePtr == NULL) { /* a string! */ Tcl_AppendToObj(Tcl_GetObjResult(interp), "string", -1); } else { Tcl_AppendToObj(Tcl_GetObjResult(interp), varPtr[varIndex]->typePtr->name, -1); } } else if (strcmp(subCmd, "types") == 0) { if (objc != 2) { goto wrongNumArgs; } if (Tcl_AppendAllObjTypes(interp, Tcl_GetObjResult(interp)) != TCL_OK) { return TCL_ERROR; } } else { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "bad option \"", Tcl_GetString(objv[1]), "\": must be assign, convert, duplicate, freeallvars, ", "newobj, objcount, objtype, refcount, type, or types", (char *) NULL); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * TeststringobjCmd -- * * This procedure implements the "teststringobj" command. It is used to * test the string Tcl object type implementation. * * Results: * A standard Tcl object result. * * Side effects: * Creates and frees string objects, and also converts objects to * have string type. * *---------------------------------------------------------------------- */ static int TeststringobjCmd(clientData, interp, objc, objv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int varIndex, option, i, length; Tcl_UniChar *unicode; #define MAX_STRINGS 11 char *index, *string, *strings[MAX_STRINGS+1]; TestString *strPtr; static CONST char *options[] = { "append", "appendstrings", "get", "get2", "length", "length2", "set", "set2", "setlength", "ualloc", "getunicode", "appendself", "appendself2", (char *) NULL }; if (objc < 3) { wrongNumArgs: Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg ...?"); return TCL_ERROR; } index = Tcl_GetString(objv[2]); if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) { return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[1], options, "option", 0, &option) != TCL_OK) { return TCL_ERROR; } switch (option) { case 0: /* append */ if (objc != 5) { goto wrongNumArgs; } if (Tcl_GetIntFromObj(interp, objv[4], &length) != TCL_OK) { return TCL_ERROR; } if (varPtr[varIndex] == NULL) { SetVarToObj(varIndex, Tcl_NewObj()); } /* * If the object bound to variable "varIndex" is shared, we must * "copy on write" and append to a copy of the object. */ if (Tcl_IsShared(varPtr[varIndex])) { SetVarToObj(varIndex, Tcl_DuplicateObj(varPtr[varIndex])); } string = Tcl_GetString(objv[3]); Tcl_AppendToObj(varPtr[varIndex], string, length); Tcl_SetObjResult(interp, varPtr[varIndex]); break; case 1: /* appendstrings */ if (objc > (MAX_STRINGS+3)) { goto wrongNumArgs; } if (varPtr[varIndex] == NULL) { SetVarToObj(varIndex, Tcl_NewObj()); } /* * If the object bound to variable "varIndex" is shared, we must * "copy on write" and append to a copy of the object. */ if (Tcl_IsShared(varPtr[varIndex])) { SetVarToObj(varIndex, Tcl_DuplicateObj(varPtr[varIndex])); } for (i = 3; i < objc; i++) { strings[i-3] = Tcl_GetString(objv[i]); } for ( ; i < 12 + 3; i++) { strings[i - 3] = NULL; } Tcl_AppendStringsToObj(varPtr[varIndex], strings[0], strings[1], strings[2], strings[3], strings[4], strings[5], strings[6], strings[7], strings[8], strings[9], strings[10], strings[11]); Tcl_SetObjResult(interp, varPtr[varIndex]); break; case 2: /* get */ if (objc != 3) { goto wrongNumArgs; } if (CheckIfVarUnset(interp, varIndex)) { return TCL_ERROR; } Tcl_SetObjResult(interp, varPtr[varIndex]); break; case 3: /* get2 */ if (objc != 3) { goto wrongNumArgs; } if (CheckIfVarUnset(interp, varIndex)) { return TCL_ERROR; } string = Tcl_GetString(varPtr[varIndex]); Tcl_AppendToObj(Tcl_GetObjResult(interp), string, -1); break; case 4: /* length */ if (objc != 3) { goto wrongNumArgs; } Tcl_SetIntObj(Tcl_GetObjResult(interp), (varPtr[varIndex] != NULL) ? varPtr[varIndex]->length : -1); break; case 5: /* length2 */ if (objc != 3) { goto wrongNumArgs; } if (varPtr[varIndex] != NULL) { strPtr = (TestString *) (varPtr[varIndex])->internalRep.otherValuePtr; length = (int) strPtr->allocated; } else { length = -1; } Tcl_SetIntObj(Tcl_GetObjResult(interp), length); break; case 6: /* set */ if (objc != 4) { goto wrongNumArgs; } /* * If the object currently bound to the variable with index * varIndex has ref count 1 (i.e. the object is unshared) we * can modify that object directly. Otherwise, if RC>1 (i.e. * the object is shared), we must create a new object to * modify/set and decrement the old formerly-shared object's * ref count. This is "copy on write". */ string = Tcl_GetStringFromObj(objv[3], &length); if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) { Tcl_SetStringObj(varPtr[varIndex], string, length); } else { SetVarToObj(varIndex, Tcl_NewStringObj(string, length)); } Tcl_SetObjResult(interp, varPtr[varIndex]); break; case 7: /* set2 */ if (objc != 4) { goto wrongNumArgs; } SetVarToObj(varIndex, objv[3]); break; case 8: /* setlength */ if (objc != 4) { goto wrongNumArgs; } if (Tcl_GetIntFromObj(interp, objv[3], &length) != TCL_OK) { return TCL_ERROR; } if (varPtr[varIndex] != NULL) { Tcl_SetObjLength(varPtr[varIndex], length); } break; case 9: /* ualloc */ if (objc != 3) { goto wrongNumArgs; } if (varPtr[varIndex] != NULL) { strPtr = (TestString *) (varPtr[varIndex])->internalRep.otherValuePtr; length = (int) strPtr->uallocated; } else { length = -1; } Tcl_SetIntObj(Tcl_GetObjResult(interp), length); break; case 10: /* getunicode */ if (objc != 3) { goto wrongNumArgs; } Tcl_GetUnicodeFromObj(varPtr[varIndex], NULL); break; case 11: /* appendself */ if (objc != 4) { goto wrongNumArgs; } if (varPtr[varIndex] == NULL) { SetVarToObj(varIndex, Tcl_NewObj()); } /* * If the object bound to variable "varIndex" is shared, we must * "copy on write" and append to a copy of the object. */ if (Tcl_IsShared(varPtr[varIndex])) { SetVarToObj(varIndex, Tcl_DuplicateObj(varPtr[varIndex])); } string = Tcl_GetStringFromObj(varPtr[varIndex], &length); if (Tcl_GetIntFromObj(interp, objv[3], &i) != TCL_OK) { return TCL_ERROR; } if ((i < 0) || (i > length)) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "index value out of range", -1)); return TCL_ERROR; } Tcl_AppendToObj(varPtr[varIndex], string + i, length - i); Tcl_SetObjResult(interp, varPtr[varIndex]); break; case 12: /* appendself2 */ if (objc != 4) { goto wrongNumArgs; } if (varPtr[varIndex] == NULL) { SetVarToObj(varIndex, Tcl_NewObj()); } /* * If the object bound to variable "varIndex" is shared, we must * "copy on write" and append to a copy of the object. */ if (Tcl_IsShared(varPtr[varIndex])) { SetVarToObj(varIndex, Tcl_DuplicateObj(varPtr[varIndex])); } unicode = Tcl_GetUnicodeFromObj(varPtr[varIndex], &length); if (Tcl_GetIntFromObj(interp, objv[3], &i) != TCL_OK) { return TCL_ERROR; } if ((i < 0) || (i > length)) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "index value out of range", -1)); return TCL_ERROR; } Tcl_AppendUnicodeToObj(varPtr[varIndex], unicode + i, length - i); Tcl_SetObjResult(interp, varPtr[varIndex]); break; } return TCL_OK; } /* *---------------------------------------------------------------------- * * SetVarToObj -- * * Utility routine to assign a Tcl_Obj* to a test variable. The * Tcl_Obj* can be NULL. * * Results: * None. * * Side effects: * This routine handles ref counting details for assignment: * i.e. the old value's ref count must be decremented (if not NULL) and * the new one incremented (also if not NULL). * *---------------------------------------------------------------------- */ static void SetVarToObj(varIndex, objPtr) int varIndex; /* Designates the assignment variable. */ Tcl_Obj *objPtr; /* Points to object to assign to var. */ { if (varPtr[varIndex] != NULL) { Tcl_DecrRefCount(varPtr[varIndex]); } varPtr[varIndex] = objPtr; if (objPtr != NULL) { Tcl_IncrRefCount(objPtr); } } /* *---------------------------------------------------------------------- * * GetVariableIndex -- * * Utility routine to get a test variable index from the command line. * * Results: * A standard Tcl object result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int GetVariableIndex(interp, string, indexPtr) Tcl_Interp *interp; /* Interpreter for error reporting. */ char *string; /* String containing a variable index * specified as a nonnegative number less * than NUMBER_OF_OBJECT_VARS. */ int *indexPtr; /* Place to store converted result. */ { int index; if (Tcl_GetInt(interp, string, &index) != TCL_OK) { return TCL_ERROR; } if (index < 0 || index >= NUMBER_OF_OBJECT_VARS) { Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "bad variable index", -1); return TCL_ERROR; } *indexPtr = index; return TCL_OK; } /* *---------------------------------------------------------------------- * * CheckIfVarUnset -- * * Utility procedure that checks whether a test variable is readable: * i.e., that varPtr[varIndex] is non-NULL. * * Results: * 1 if the test variable is unset (NULL); 0 otherwise. * * Side effects: * Sets the interpreter result to an error message if the variable is * unset (NULL). * *---------------------------------------------------------------------- */ static int CheckIfVarUnset(interp, varIndex) Tcl_Interp *interp; /* Interpreter for error reporting. */ int varIndex; /* Index of the test variable to check. */ { if (varPtr[varIndex] == NULL) { char buf[32 + TCL_INTEGER_SPACE]; sprintf(buf, "variable %d is unset (NULL)", varIndex); Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), buf, -1); return 1; } return 0; } tcl8.4.20/generic/tclPanic.c0000644003604700454610000000626611737050674014246 0ustar dgp771div/* * tclPanic.c -- * * Source code for the "Tcl_Panic" library procedure for Tcl; * individual applications will probably call Tcl_SetPanicProc() * to set an application-specific panic procedure. * * Copyright (c) 1988-1993 The Regents of the University of California. * Copyright (c) 1994 Sun Microsystems, Inc. * Copyright (c) 1998-1999 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" /* * The panicProc variable contains a pointer to an application * specific panic procedure. */ static Tcl_PanicProc *panicProc = NULL; /* * The platformPanicProc variable contains a pointer to a platform * specific panic procedure, if any. ( TclpPanic may be NULL via * a macro. ) */ static Tcl_PanicProc * CONST platformPanicProc = TclpPanic; /* *---------------------------------------------------------------------- * * Tcl_SetPanicProc -- * * Replace the default panic behavior with the specified functiion. * * Results: * None. * * Side effects: * Sets the panicProc variable. * *---------------------------------------------------------------------- */ void Tcl_SetPanicProc(proc) Tcl_PanicProc *proc; { panicProc = proc; } /* *---------------------------------------------------------------------- * * Tcl_PanicVA -- * * Print an error message and kill the process. * * Results: * None. * * Side effects: * The process dies, entering the debugger if possible. * *---------------------------------------------------------------------- */ void Tcl_PanicVA (format, argList) CONST char *format; /* Format string, suitable for passing to * fprintf. */ va_list argList; /* Variable argument list. */ { char *arg1, *arg2, *arg3, *arg4; /* Additional arguments (variable in * number) to pass to fprintf. */ char *arg5, *arg6, *arg7, *arg8; arg1 = va_arg(argList, char *); arg2 = va_arg(argList, char *); arg3 = va_arg(argList, char *); arg4 = va_arg(argList, char *); arg5 = va_arg(argList, char *); arg6 = va_arg(argList, char *); arg7 = va_arg(argList, char *); arg8 = va_arg(argList, char *); if (panicProc != NULL) { (void) (*panicProc)(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); } else if (platformPanicProc != NULL) { (void) (*platformPanicProc)(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); } else { (void) fprintf(stderr, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); (void) fprintf(stderr, "\n"); (void) fflush(stderr); abort(); } } /* *---------------------------------------------------------------------- * * Tcl_Panic -- * * Print an error message and kill the process. * * Results: * None. * * Side effects: * The process dies, entering the debugger if possible. * *---------------------------------------------------------------------- */ /* VARARGS ARGSUSED */ void Tcl_Panic TCL_VARARGS_DEF(CONST char *,arg1) { va_list argList; CONST char *format; format = TCL_VARARGS_START(CONST char *,arg1,argList); Tcl_PanicVA(format, argList); va_end (argList); } tcl8.4.20/generic/tclUtf.c0000644003604700454610000013166411737050674013753 0ustar dgp771div/* * tclUtf.c -- * * Routines for manipulating UTF-8 strings. * * Copyright (c) 1997-1998 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" /* * Include the static character classification tables and macros. */ #include "tclUniData.c" /* * The following macros are used for fast character category tests. The * x_BITS values are shifted right by the category value to determine whether * the given category is included in the set. */ #define ALPHA_BITS ((1 << UPPERCASE_LETTER) | (1 << LOWERCASE_LETTER) \ | (1 << TITLECASE_LETTER) | (1 << MODIFIER_LETTER) | (1 << OTHER_LETTER)) #define CONTROL_BITS ((1 << CONTROL) | (1 << FORMAT) | (1 << PRIVATE_USE)) #define DIGIT_BITS (1 << DECIMAL_DIGIT_NUMBER) #define SPACE_BITS ((1 << SPACE_SEPARATOR) | (1 << LINE_SEPARATOR) \ | (1 << PARAGRAPH_SEPARATOR)) #define WORD_BITS (ALPHA_BITS | DIGIT_BITS | (1 << CONNECTOR_PUNCTUATION)) #define PUNCT_BITS ((1 << CONNECTOR_PUNCTUATION) | \ (1 << DASH_PUNCTUATION) | (1 << OPEN_PUNCTUATION) | \ (1 << CLOSE_PUNCTUATION) | (1 << INITIAL_QUOTE_PUNCTUATION) | \ (1 << FINAL_QUOTE_PUNCTUATION) | (1 << OTHER_PUNCTUATION)) #define GRAPH_BITS (WORD_BITS | PUNCT_BITS | \ (1 << NON_SPACING_MARK) | (1 << ENCLOSING_MARK) | \ (1 << COMBINING_SPACING_MARK) | (1 << LETTER_NUMBER) | \ (1 << OTHER_NUMBER) | \ (1 << MATH_SYMBOL) | (1 << CURRENCY_SYMBOL) | \ (1 << MODIFIER_SYMBOL) | (1 << OTHER_SYMBOL)) /* * Unicode characters less than this value are represented by themselves * in UTF-8 strings. */ #define UNICODE_SELF 0x80 /* * The following structures are used when mapping between Unicode (UCS-2) * and UTF-8. */ static CONST unsigned char totalBytes[256] = { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, #if TCL_UTF_MAX > 3 4,4,4,4,4,4,4,4, #else 1,1,1,1,1,1,1,1, #endif #if TCL_UTF_MAX > 4 5,5,5,5, #else 1,1,1,1, #endif #if TCL_UTF_MAX > 5 6,6,6,6 #else 1,1,1,1 #endif }; /* * Procedures used only in this module. */ static int UtfCount _ANSI_ARGS_((int ch)); /* *--------------------------------------------------------------------------- * * UtfCount -- * * Find the number of bytes in the Utf character "ch". * * Results: * The return values is the number of bytes in the Utf character "ch". * * Side effects: * None. * *--------------------------------------------------------------------------- */ INLINE static int UtfCount(ch) int ch; /* The Tcl_UniChar whose size is returned. */ { if ((ch > 0) && (ch < UNICODE_SELF)) { return 1; } if (ch <= 0x7FF) { return 2; } if (ch <= 0xFFFF) { return 3; } #if TCL_UTF_MAX > 3 if (ch <= 0x1FFFFF) { return 4; } if (ch <= 0x3FFFFFF) { return 5; } if (ch <= 0x7FFFFFFF) { return 6; } #endif return 3; } /* *--------------------------------------------------------------------------- * * Tcl_UniCharToUtf -- * * Store the given Tcl_UniChar as a sequence of UTF-8 bytes in the * provided buffer. Equivalent to Plan 9 runetochar(). * * Results: * The return values is the number of bytes in the buffer that * were consumed. * * Side effects: * None. * *--------------------------------------------------------------------------- */ INLINE int Tcl_UniCharToUtf(ch, str) int ch; /* The Tcl_UniChar to be stored in the * buffer. */ char *str; /* Buffer in which the UTF-8 representation * of the Tcl_UniChar is stored. Buffer must * be large enough to hold the UTF-8 character * (at most TCL_UTF_MAX bytes). */ { if ((ch > 0) && (ch < UNICODE_SELF)) { str[0] = (char) ch; return 1; } if (ch >= 0) { if (ch <= 0x7FF) { str[1] = (char) ((ch | 0x80) & 0xBF); str[0] = (char) ((ch >> 6) | 0xC0); return 2; } if (ch <= 0xFFFF) { three: str[2] = (char) ((ch | 0x80) & 0xBF); str[1] = (char) (((ch >> 6) | 0x80) & 0xBF); str[0] = (char) ((ch >> 12) | 0xE0); return 3; } #if TCL_UTF_MAX > 3 if (ch <= 0x1FFFFF) { str[3] = (char) ((ch | 0x80) & 0xBF); str[2] = (char) (((ch >> 6) | 0x80) & 0xBF); str[1] = (char) (((ch >> 12) | 0x80) & 0xBF); str[0] = (char) ((ch >> 18) | 0xF0); return 4; } if (ch <= 0x3FFFFFF) { str[4] = (char) ((ch | 0x80) & 0xBF); str[3] = (char) (((ch >> 6) | 0x80) & 0xBF); str[2] = (char) (((ch >> 12) | 0x80) & 0xBF); str[1] = (char) (((ch >> 18) | 0x80) & 0xBF); str[0] = (char) ((ch >> 24) | 0xF8); return 5; } if (ch <= 0x7FFFFFFF) { str[5] = (char) ((ch | 0x80) & 0xBF); str[4] = (char) (((ch >> 6) | 0x80) & 0xBF); str[3] = (char) (((ch >> 12) | 0x80) & 0xBF); str[2] = (char) (((ch >> 18) | 0x80) & 0xBF); str[1] = (char) (((ch >> 24) | 0x80) & 0xBF); str[0] = (char) ((ch >> 30) | 0xFC); return 6; } #endif } ch = 0xFFFD; goto three; } /* *--------------------------------------------------------------------------- * * Tcl_UniCharToUtfDString -- * * Convert the given Unicode string to UTF-8. * * Results: * The return value is a pointer to the UTF-8 representation of the * Unicode string. Storage for the return value is appended to the * end of dsPtr. * * Side effects: * None. * *--------------------------------------------------------------------------- */ char * Tcl_UniCharToUtfDString(wString, numChars, dsPtr) CONST Tcl_UniChar *wString; /* Unicode string to convert to UTF-8. */ int numChars; /* Length of Unicode string in Tcl_UniChars * (must be >= 0). */ Tcl_DString *dsPtr; /* UTF-8 representation of string is * appended to this previously initialized * DString. */ { CONST Tcl_UniChar *w, *wEnd; char *p, *string; int oldLength; /* * UTF-8 string length in bytes will be <= Unicode string length * * TCL_UTF_MAX. */ oldLength = Tcl_DStringLength(dsPtr); Tcl_DStringSetLength(dsPtr, (oldLength + numChars + 1) * TCL_UTF_MAX); string = Tcl_DStringValue(dsPtr) + oldLength; p = string; wEnd = wString + numChars; for (w = wString; w < wEnd; ) { p += Tcl_UniCharToUtf(*w, p); w++; } Tcl_DStringSetLength(dsPtr, oldLength + (p - string)); return string; } /* *--------------------------------------------------------------------------- * * Tcl_UtfToUniChar -- * * Extract the Tcl_UniChar represented by the UTF-8 string. Bad * UTF-8 sequences are converted to valid Tcl_UniChars and processing * continues. Equivalent to Plan 9 chartorune(). * * The caller must ensure that the source buffer is long enough that * this routine does not run off the end and dereference non-existent * memory looking for trail bytes. If the source buffer is known to * be '\0' terminated, this cannot happen. Otherwise, the caller * should call Tcl_UtfCharComplete() before calling this routine to * ensure that enough bytes remain in the string. * * Results: * *chPtr is filled with the Tcl_UniChar, and the return value is the * number of bytes from the UTF-8 string that were consumed. * * Side effects: * None. * *--------------------------------------------------------------------------- */ int Tcl_UtfToUniChar(str, chPtr) register CONST char *str; /* The UTF-8 string. */ register Tcl_UniChar *chPtr; /* Filled with the Tcl_UniChar represented * by the UTF-8 string. */ { register int byte; /* * Unroll 1 to 3 byte UTF-8 sequences, use loop to handle longer ones. */ byte = *((unsigned char *) str); if (byte < 0xC0) { /* * Handles properly formed UTF-8 characters between 0x01 and 0x7F. * Also treats \0 and naked trail bytes 0x80 to 0xBF as valid * characters representing themselves. */ *chPtr = (Tcl_UniChar) byte; return 1; } else if (byte < 0xE0) { if ((str[1] & 0xC0) == 0x80) { /* * Two-byte-character lead-byte followed by a trail-byte. */ *chPtr = (Tcl_UniChar) (((byte & 0x1F) << 6) | (str[1] & 0x3F)); return 2; } /* * A two-byte-character lead-byte not followed by trail-byte * represents itself. */ *chPtr = (Tcl_UniChar) byte; return 1; } else if (byte < 0xF0) { if (((str[1] & 0xC0) == 0x80) && ((str[2] & 0xC0) == 0x80)) { /* * Three-byte-character lead byte followed by two trail bytes. */ *chPtr = (Tcl_UniChar) (((byte & 0x0F) << 12) | ((str[1] & 0x3F) << 6) | (str[2] & 0x3F)); return 3; } /* * A three-byte-character lead-byte not followed by two trail-bytes * represents itself. */ *chPtr = (Tcl_UniChar) byte; return 1; } #if TCL_UTF_MAX > 3 else { int ch, total, trail; total = totalBytes[byte]; trail = total - 1; if (trail > 0) { ch = byte & (0x3F >> trail); do { str++; if ((*str & 0xC0) != 0x80) { *chPtr = byte; return 1; } ch <<= 6; ch |= (*str & 0x3F); trail--; } while (trail > 0); *chPtr = ch; return total; } } #endif *chPtr = (Tcl_UniChar) byte; return 1; } /* *--------------------------------------------------------------------------- * * Tcl_UtfToUniCharDString -- * * Convert the UTF-8 string to Unicode. * * Results: * The return value is a pointer to the Unicode representation of the * UTF-8 string. Storage for the return value is appended to the * end of dsPtr. The Unicode string is terminated with a Unicode * NULL character. * * Side effects: * None. * *--------------------------------------------------------------------------- */ Tcl_UniChar * Tcl_UtfToUniCharDString(string, length, dsPtr) CONST char *string; /* UTF-8 string to convert to Unicode. */ int length; /* Length of UTF-8 string in bytes, or -1 * for strlen(). */ Tcl_DString *dsPtr; /* Unicode representation of string is * appended to this previously initialized * DString. */ { Tcl_UniChar *w, *wString; CONST char *p, *end; int oldLength; if (length < 0) { length = strlen(string); } /* * Unicode string length in Tcl_UniChars will be <= UTF-8 string length * in bytes. */ oldLength = Tcl_DStringLength(dsPtr); Tcl_DStringSetLength(dsPtr, (int) ((oldLength + length + 1) * sizeof(Tcl_UniChar))); wString = (Tcl_UniChar *) (Tcl_DStringValue(dsPtr) + oldLength); w = wString; end = string + length; for (p = string; p < end; ) { p += TclUtfToUniChar(p, w); w++; } *w = '\0'; Tcl_DStringSetLength(dsPtr, (oldLength + ((char *) w - (char *) wString))); return wString; } /* *--------------------------------------------------------------------------- * * Tcl_UtfCharComplete -- * * Determine if the UTF-8 string of the given length is long enough * to be decoded by Tcl_UtfToUniChar(). This does not ensure that the * UTF-8 string is properly formed. Equivalent to Plan 9 fullrune(). * * Results: * The return value is 0 if the string is not long enough, non-zero * otherwise. * * Side effects: * None. * *--------------------------------------------------------------------------- */ int Tcl_UtfCharComplete(str, len) CONST char *str; /* String to check if first few bytes * contain a complete UTF-8 character. */ int len; /* Length of above string in bytes. */ { int ch; ch = *((unsigned char *) str); return len >= totalBytes[ch]; } /* *--------------------------------------------------------------------------- * * Tcl_NumUtfChars -- * * Returns the number of characters (not bytes) in the UTF-8 string, * not including the terminating NULL byte. This is equivalent to * Plan 9 utflen() and utfnlen(). * * Results: * As above. * * Side effects: * None. * *--------------------------------------------------------------------------- */ int Tcl_NumUtfChars(str, len) register CONST char *str; /* The UTF-8 string to measure. */ int len; /* The length of the string in bytes, or -1 * for strlen(string). */ { Tcl_UniChar ch; register Tcl_UniChar *chPtr = &ch; register int i; /* * The separate implementations are faster. * * Since this is a time-sensitive function, we also do the check for * the single-byte char case specially. */ i = 0; if (len < 0) { while (*str != '\0') { str += TclUtfToUniChar(str, chPtr); i++; } } else { register int n; while (len > 0) { if (UCHAR(*str) < 0xC0) { len--; str++; } else { n = Tcl_UtfToUniChar(str, chPtr); len -= n; str += n; } i++; } } return i; } /* *--------------------------------------------------------------------------- * * Tcl_UtfFindFirst -- * * Returns a pointer to the first occurance of the given Tcl_UniChar * in the NULL-terminated UTF-8 string. The NULL terminator is * considered part of the UTF-8 string. Equivalent to Plan 9 * utfrune(). * * Results: * As above. If the Tcl_UniChar does not exist in the given string, * the return value is NULL. * * Side effects: * None. * *--------------------------------------------------------------------------- */ CONST char * Tcl_UtfFindFirst(string, ch) CONST char *string; /* The UTF-8 string to be searched. */ int ch; /* The Tcl_UniChar to search for. */ { int len; Tcl_UniChar find; while (1) { len = TclUtfToUniChar(string, &find); if (find == ch) { return string; } if (*string == '\0') { return NULL; } string += len; } } /* *--------------------------------------------------------------------------- * * Tcl_UtfFindLast -- * * Returns a pointer to the last occurance of the given Tcl_UniChar * in the NULL-terminated UTF-8 string. The NULL terminator is * considered part of the UTF-8 string. Equivalent to Plan 9 * utfrrune(). * * Results: * As above. If the Tcl_UniChar does not exist in the given string, * the return value is NULL. * * Side effects: * None. * *--------------------------------------------------------------------------- */ CONST char * Tcl_UtfFindLast(string, ch) CONST char *string; /* The UTF-8 string to be searched. */ int ch; /* The Tcl_UniChar to search for. */ { int len; Tcl_UniChar find; CONST char *last; last = NULL; while (1) { len = TclUtfToUniChar(string, &find); if (find == ch) { last = string; } if (*string == '\0') { break; } string += len; } return last; } /* *--------------------------------------------------------------------------- * * Tcl_UtfNext -- * * Given a pointer to some current location in a UTF-8 string, * move forward one character. The caller must ensure that they * are not asking for the next character after the last character * in the string. * * Results: * The return value is the pointer to the next character in * the UTF-8 string. * * Side effects: * None. * *--------------------------------------------------------------------------- */ CONST char * Tcl_UtfNext(str) CONST char *str; /* The current location in the string. */ { Tcl_UniChar ch; return str + TclUtfToUniChar(str, &ch); } /* *--------------------------------------------------------------------------- * * Tcl_UtfPrev -- * * Given a pointer to some current location in a UTF-8 string, * move backwards one character. This works correctly when the * pointer is in the middle of a UTF-8 character. * * Results: * The return value is a pointer to the previous character in the * UTF-8 string. If the current location was already at the * beginning of the string, the return value will also be a * pointer to the beginning of the string. * * Side effects: * None. * *--------------------------------------------------------------------------- */ CONST char * Tcl_UtfPrev(str, start) CONST char *str; /* The current location in the string. */ CONST char *start; /* Pointer to the beginning of the * string, to avoid going backwards too * far. */ { CONST char *look; int i, byte; str--; look = str; for (i = 0; i < TCL_UTF_MAX; i++) { if (look < start) { if (str < start) { str = start; } break; } byte = *((unsigned char *) look); if (byte < 0x80) { break; } if (byte >= 0xC0) { return look; } look--; } return str; } /* *--------------------------------------------------------------------------- * * Tcl_UniCharAtIndex -- * * Returns the Unicode character represented at the specified * character (not byte) position in the UTF-8 string. * * Results: * As above. * * Side effects: * None. * *--------------------------------------------------------------------------- */ Tcl_UniChar Tcl_UniCharAtIndex(src, index) register CONST char *src; /* The UTF-8 string to dereference. */ register int index; /* The position of the desired character. */ { Tcl_UniChar ch; while (index >= 0) { index--; src += TclUtfToUniChar(src, &ch); } return ch; } /* *--------------------------------------------------------------------------- * * Tcl_UtfAtIndex -- * * Returns a pointer to the specified character (not byte) position * in the UTF-8 string. * * Results: * As above. * * Side effects: * None. * *--------------------------------------------------------------------------- */ CONST char * Tcl_UtfAtIndex(src, index) register CONST char *src; /* The UTF-8 string. */ register int index; /* The position of the desired character. */ { Tcl_UniChar ch; while (index > 0) { index--; src += TclUtfToUniChar(src, &ch); } return src; } /* *--------------------------------------------------------------------------- * * Tcl_UtfBackslash -- * * Figure out how to handle a backslash sequence. * * Results: * Stores the bytes represented by the backslash sequence in dst and * returns the number of bytes written to dst. At most TCL_UTF_MAX * bytes are written to dst; dst must have been large enough to accept * those bytes. If readPtr isn't NULL then it is filled in with a * count of the number of bytes in the backslash sequence. * * Side effects: * The maximum number of bytes it takes to represent a Unicode * character in UTF-8 is guaranteed to be less than the number of * bytes used to express the backslash sequence that represents * that Unicode character. If the target buffer into which the * caller is going to store the bytes that represent the Unicode * character is at least as large as the source buffer from which * the backslashed sequence was extracted, no buffer overruns should * occur. * *--------------------------------------------------------------------------- */ int Tcl_UtfBackslash(src, readPtr, dst) CONST char *src; /* Points to the backslash character of * a backslash sequence. */ int *readPtr; /* Fill in with number of characters read * from src, unless NULL. */ char *dst; /* Filled with the bytes represented by the * backslash sequence. */ { #define LINE_LENGTH 128 int numRead; int result; result = TclParseBackslash(src, LINE_LENGTH, &numRead, dst); if (numRead == LINE_LENGTH) { /* We ate a whole line. Pay the price of a strlen() */ result = TclParseBackslash(src, (int)strlen(src), &numRead, dst); } if (readPtr != NULL) { *readPtr = numRead; } return result; } /* *---------------------------------------------------------------------- * * Tcl_UtfToUpper -- * * Convert lowercase characters to uppercase characters in a UTF * string in place. The conversion may shrink the UTF string. * * Results: * Returns the number of bytes in the resulting string * excluding the trailing null. * * Side effects: * Writes a terminating null after the last converted character. * *---------------------------------------------------------------------- */ int Tcl_UtfToUpper(str) char *str; /* String to convert in place. */ { Tcl_UniChar ch, upChar; char *src, *dst; int bytes; /* * Iterate over the string until we hit the terminating null. */ src = dst = str; while (*src) { bytes = TclUtfToUniChar(src, &ch); upChar = Tcl_UniCharToUpper(ch); /* * To keep badly formed Utf strings from getting inflated by * the conversion (thereby causing a segfault), only copy the * upper case char to dst if its size is <= the original char. */ if (bytes < UtfCount(upChar)) { memcpy(dst, src, (size_t) bytes); dst += bytes; } else { dst += Tcl_UniCharToUtf(upChar, dst); } src += bytes; } *dst = '\0'; return (dst - str); } /* *---------------------------------------------------------------------- * * Tcl_UtfToLower -- * * Convert uppercase characters to lowercase characters in a UTF * string in place. The conversion may shrink the UTF string. * * Results: * Returns the number of bytes in the resulting string * excluding the trailing null. * * Side effects: * Writes a terminating null after the last converted character. * *---------------------------------------------------------------------- */ int Tcl_UtfToLower(str) char *str; /* String to convert in place. */ { Tcl_UniChar ch, lowChar; char *src, *dst; int bytes; /* * Iterate over the string until we hit the terminating null. */ src = dst = str; while (*src) { bytes = TclUtfToUniChar(src, &ch); lowChar = Tcl_UniCharToLower(ch); /* * To keep badly formed Utf strings from getting inflated by * the conversion (thereby causing a segfault), only copy the * lower case char to dst if its size is <= the original char. */ if (bytes < UtfCount(lowChar)) { memcpy(dst, src, (size_t) bytes); dst += bytes; } else { dst += Tcl_UniCharToUtf(lowChar, dst); } src += bytes; } *dst = '\0'; return (dst - str); } /* *---------------------------------------------------------------------- * * Tcl_UtfToTitle -- * * Changes the first character of a UTF string to title case or * uppercase and the rest of the string to lowercase. The * conversion happens in place and may shrink the UTF string. * * Results: * Returns the number of bytes in the resulting string * excluding the trailing null. * * Side effects: * Writes a terminating null after the last converted character. * *---------------------------------------------------------------------- */ int Tcl_UtfToTitle(str) char *str; /* String to convert in place. */ { Tcl_UniChar ch, titleChar, lowChar; char *src, *dst; int bytes; /* * Capitalize the first character and then lowercase the rest of the * characters until we get to a null. */ src = dst = str; if (*src) { bytes = TclUtfToUniChar(src, &ch); titleChar = Tcl_UniCharToTitle(ch); if (bytes < UtfCount(titleChar)) { memcpy(dst, src, (size_t) bytes); dst += bytes; } else { dst += Tcl_UniCharToUtf(titleChar, dst); } src += bytes; } while (*src) { bytes = TclUtfToUniChar(src, &ch); lowChar = Tcl_UniCharToLower(ch); if (bytes < UtfCount(lowChar)) { memcpy(dst, src, (size_t) bytes); dst += bytes; } else { dst += Tcl_UniCharToUtf(lowChar, dst); } src += bytes; } *dst = '\0'; return (dst - str); } /* *---------------------------------------------------------------------- * * TclpUtfNcmp2 -- * * Compare at most n bytes of utf-8 strings cs and ct. Both cs * and ct are assumed to be at least n bytes long. * * Results: * Return <0 if cs < ct, 0 if cs == ct, or >0 if cs > ct. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclpUtfNcmp2(cs, ct, n) CONST char *cs; /* UTF string to compare to ct. */ CONST char *ct; /* UTF string cs is compared to. */ unsigned long n; /* Number of *bytes* to compare. */ { /* * We can't simply call 'memcmp(cs, ct, n);' because we need to check * for Tcl's \xC0\x80 non-utf-8 null encoding. * Otherwise utf-8 lexes fine in the strcmp manner. */ register int result = 0; for ( ; n != 0; n--, cs++, ct++) { if (*cs != *ct) { result = UCHAR(*cs) - UCHAR(*ct); break; } } if (n && ((UCHAR(*cs) == 0xC0) || (UCHAR(*ct) == 0xC0))) { unsigned char c1, c2; c1 = ((UCHAR(*cs) == 0xC0) && (UCHAR(cs[1]) == 0x80)) ? 0 : UCHAR(*cs); c2 = ((UCHAR(*ct) == 0xC0) && (UCHAR(ct[1]) == 0x80)) ? 0 : UCHAR(*ct); result = (c1 - c2); } return result; } /* *---------------------------------------------------------------------- * * Tcl_UtfNcmp -- * * Compare at most n UTF chars of string cs to string ct. Both cs * and ct are assumed to be at least n UTF chars long. * * Results: * Return <0 if cs < ct, 0 if cs == ct, or >0 if cs > ct. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_UtfNcmp(cs, ct, n) CONST char *cs; /* UTF string to compare to ct. */ CONST char *ct; /* UTF string cs is compared to. */ unsigned long n; /* Number of UTF chars to compare. */ { Tcl_UniChar ch1, ch2; /* * Cannot use 'memcmp(cs, ct, n);' as byte representation of * \u0000 (the pair of bytes 0xc0,0x80) is larger than byte * representation of \u0001 (the byte 0x01.) */ while (n-- > 0) { /* * n must be interpreted as chars, not bytes. * This should be called only when both strings are of * at least n chars long (no need for \0 check) */ cs += TclUtfToUniChar(cs, &ch1); ct += TclUtfToUniChar(ct, &ch2); if (ch1 != ch2) { return (ch1 - ch2); } } return 0; } /* *---------------------------------------------------------------------- * * Tcl_UtfNcasecmp -- * * Compare at most n UTF chars of string cs to string ct case * insensitive. Both cs and ct are assumed to be at least n * UTF chars long. * * Results: * Return <0 if cs < ct, 0 if cs == ct, or >0 if cs > ct. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_UtfNcasecmp(cs, ct, n) CONST char *cs; /* UTF string to compare to ct. */ CONST char *ct; /* UTF string cs is compared to. */ unsigned long n; /* Number of UTF chars to compare. */ { Tcl_UniChar ch1, ch2; while (n-- > 0) { /* * n must be interpreted as chars, not bytes. * This should be called only when both strings are of * at least n chars long (no need for \0 check) */ cs += TclUtfToUniChar(cs, &ch1); ct += TclUtfToUniChar(ct, &ch2); if (ch1 != ch2) { ch1 = Tcl_UniCharToLower(ch1); ch2 = Tcl_UniCharToLower(ch2); if (ch1 != ch2) { return (ch1 - ch2); } } } return 0; } /* *---------------------------------------------------------------------- * * Tcl_UniCharToUpper -- * * Compute the uppercase equivalent of the given Unicode character. * * Results: * Returns the uppercase Unicode character. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_UniChar Tcl_UniCharToUpper(ch) int ch; /* Unicode character to convert. */ { int info = GetUniCharInfo(ch); if (GetCaseType(info) & 0x04) { ch -= GetDelta(info); } return (Tcl_UniChar) ch; } /* *---------------------------------------------------------------------- * * Tcl_UniCharToLower -- * * Compute the lowercase equivalent of the given Unicode character. * * Results: * Returns the lowercase Unicode character. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_UniChar Tcl_UniCharToLower(ch) int ch; /* Unicode character to convert. */ { int info = GetUniCharInfo(ch); if (GetCaseType(info) & 0x02) { ch += GetDelta(info); } return (Tcl_UniChar) ch; } /* *---------------------------------------------------------------------- * * Tcl_UniCharToTitle -- * * Compute the titlecase equivalent of the given Unicode character. * * Results: * Returns the titlecase Unicode character. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_UniChar Tcl_UniCharToTitle(ch) int ch; /* Unicode character to convert. */ { int info = GetUniCharInfo(ch); int mode = GetCaseType(info); if (mode & 0x1) { /* * Subtract or add one depending on the original case. */ ch += ((mode & 0x4) ? -1 : 1); } else if (mode == 0x4) { ch -= GetDelta(info); } return (Tcl_UniChar) ch; } /* *---------------------------------------------------------------------- * * Tcl_UniCharLen -- * * Find the length of a UniChar string. The str input must be null * terminated. * * Results: * Returns the length of str in UniChars (not bytes). * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_UniCharLen(str) CONST Tcl_UniChar *str; /* Unicode string to find length of. */ { int len = 0; while (*str != '\0') { len++; str++; } return len; } /* *---------------------------------------------------------------------- * * Tcl_UniCharNcmp -- * * Compare at most n unichars of string cs to string ct. Both cs * and ct are assumed to be at least n unichars long. * * Results: * Return <0 if cs < ct, 0 if cs == ct, or >0 if cs > ct. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_UniCharNcmp(cs, ct, n) CONST Tcl_UniChar *cs; /* Unicode string to compare to ct. */ CONST Tcl_UniChar *ct; /* Unicode string cs is compared to. */ unsigned long n; /* Number of unichars to compare. */ { #ifdef WORDS_BIGENDIAN /* * We are definitely on a big-endian machine; memcmp() is safe */ return memcmp(cs, ct, n*sizeof(Tcl_UniChar)); #else /* !WORDS_BIGENDIAN */ /* * We can't simply call memcmp() because that is not lexically correct. */ for ( ; n != 0; cs++, ct++, n--) { if (*cs != *ct) { return (*cs - *ct); } } return 0; #endif /* WORDS_BIGENDIAN */ } /* *---------------------------------------------------------------------- * * Tcl_UniCharNcasecmp -- * * Compare at most n unichars of string cs to string ct case * insensitive. Both cs and ct are assumed to be at least n * unichars long. * * Results: * Return <0 if cs < ct, 0 if cs == ct, or >0 if cs > ct. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_UniCharNcasecmp(cs, ct, n) CONST Tcl_UniChar *cs; /* Unicode string to compare to ct. */ CONST Tcl_UniChar *ct; /* Unicode string cs is compared to. */ unsigned long n; /* Number of unichars to compare. */ { for ( ; n != 0; n--, cs++, ct++) { if (*cs != *ct) { Tcl_UniChar lcs = Tcl_UniCharToLower(*cs); Tcl_UniChar lct = Tcl_UniCharToLower(*ct); if (lcs != lct) { return (lcs - lct); } } } return 0; } /* *---------------------------------------------------------------------- * * Tcl_UniCharIsAlnum -- * * Test if a character is an alphanumeric Unicode character. * * Results: * Returns 1 if character is alphanumeric. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_UniCharIsAlnum(ch) int ch; /* Unicode character to test. */ { return (((ALPHA_BITS | DIGIT_BITS) >> GetCategory(ch)) & 1); } /* *---------------------------------------------------------------------- * * Tcl_UniCharIsAlpha -- * * Test if a character is an alphabetic Unicode character. * * Results: * Returns 1 if character is alphabetic. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_UniCharIsAlpha(ch) int ch; /* Unicode character to test. */ { return ((ALPHA_BITS >> GetCategory(ch)) & 1); } /* *---------------------------------------------------------------------- * * Tcl_UniCharIsControl -- * * Test if a character is a Unicode control character. * * Results: * Returns non-zero if character is a control. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_UniCharIsControl(ch) int ch; /* Unicode character to test. */ { return ((CONTROL_BITS >> GetCategory(ch)) & 1); } /* *---------------------------------------------------------------------- * * Tcl_UniCharIsDigit -- * * Test if a character is a numeric Unicode character. * * Results: * Returns non-zero if character is a digit. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_UniCharIsDigit(ch) int ch; /* Unicode character to test. */ { return (GetCategory(ch) == DECIMAL_DIGIT_NUMBER); } /* *---------------------------------------------------------------------- * * Tcl_UniCharIsGraph -- * * Test if a character is any Unicode print character except space. * * Results: * Returns non-zero if character is printable, but not space. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_UniCharIsGraph(ch) int ch; /* Unicode character to test. */ { return ((GRAPH_BITS >> GetCategory(ch)) & 1); } /* *---------------------------------------------------------------------- * * Tcl_UniCharIsLower -- * * Test if a character is a lowercase Unicode character. * * Results: * Returns non-zero if character is lowercase. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_UniCharIsLower(ch) int ch; /* Unicode character to test. */ { return (GetCategory(ch) == LOWERCASE_LETTER); } /* *---------------------------------------------------------------------- * * Tcl_UniCharIsPrint -- * * Test if a character is a Unicode print character. * * Results: * Returns non-zero if character is printable. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_UniCharIsPrint(ch) int ch; /* Unicode character to test. */ { return (((GRAPH_BITS|SPACE_BITS) >> GetCategory(ch)) & 1); } /* *---------------------------------------------------------------------- * * Tcl_UniCharIsPunct -- * * Test if a character is a Unicode punctuation character. * * Results: * Returns non-zero if character is punct. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_UniCharIsPunct(ch) int ch; /* Unicode character to test. */ { return ((PUNCT_BITS >> GetCategory(ch)) & 1); } /* *---------------------------------------------------------------------- * * Tcl_UniCharIsSpace -- * * Test if a character is a whitespace Unicode character. * * Results: * Returns non-zero if character is a space. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_UniCharIsSpace(ch) int ch; /* Unicode character to test. */ { /* * If the character is within the first 127 characters, just use the * standard C function, otherwise consult the Unicode table. */ if (((Tcl_UniChar) ch) < ((Tcl_UniChar) 0x80)) { return isspace(UCHAR(ch)); /* INTL: ISO space */ } else { return ((SPACE_BITS >> GetCategory(ch)) & 1); } } /* *---------------------------------------------------------------------- * * Tcl_UniCharIsUpper -- * * Test if a character is a uppercase Unicode character. * * Results: * Returns non-zero if character is uppercase. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_UniCharIsUpper(ch) int ch; /* Unicode character to test. */ { return (GetCategory(ch) == UPPERCASE_LETTER); } /* *---------------------------------------------------------------------- * * Tcl_UniCharIsWordChar -- * * Test if a character is alphanumeric or a connector punctuation * mark. * * Results: * Returns 1 if character is a word character. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_UniCharIsWordChar(ch) int ch; /* Unicode character to test. */ { return ((WORD_BITS >> GetCategory(ch)) & 1); } /* *---------------------------------------------------------------------- * * Tcl_UniCharCaseMatch -- * * See if a particular Unicode string matches a particular pattern. * Allows case insensitivity. This is the Unicode equivalent of * the char* Tcl_StringCaseMatch. The UniChar strings must be * NULL-terminated. This has no provision for counted UniChar * strings, thus should not be used where NULLs are expected in the * UniChar string. Use TclUniCharMatch where possible. * * Results: * The return value is 1 if string matches pattern, and * 0 otherwise. The matching operation permits the following * special characters in the pattern: *?\[] (see the manual * entry for details on what these mean). * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_UniCharCaseMatch(string, pattern, nocase) CONST Tcl_UniChar *string; /* Unicode String. */ CONST Tcl_UniChar *pattern; /* Pattern, which may contain special * characters. */ int nocase; /* 0 for case sensitive, 1 for insensitive */ { Tcl_UniChar ch1, p; while (1) { p = *pattern; /* * See if we're at the end of both the pattern and the string. If * so, we succeeded. If we're at the end of the pattern but not at * the end of the string, we failed. */ if (p == 0) { return (*string == 0); } if ((*string == 0) && (p != '*')) { return 0; } /* * Check for a "*" as the next pattern character. It matches any * substring. We handle this by skipping all the characters up to the * next matching one in the pattern, and then calling ourselves * recursively for each postfix of string, until either we match or we * reach the end of the string. */ if (p == '*') { /* * Skip all successive *'s in the pattern */ while (*(++pattern) == '*') {} p = *pattern; if (p == 0) { return 1; } if (nocase) { p = Tcl_UniCharToLower(p); } while (1) { /* * Optimization for matching - cruise through the string * quickly if the next char in the pattern isn't a special * character */ if ((p != '[') && (p != '?') && (p != '\\')) { if (nocase) { while (*string && (p != *string) && (p != Tcl_UniCharToLower(*string))) { string++; } } else { while (*string && (p != *string)) { string++; } } } if (Tcl_UniCharCaseMatch(string, pattern, nocase)) { return 1; } if (*string == 0) { return 0; } string++; } } /* * Check for a "?" as the next pattern character. It matches * any single character. */ if (p == '?') { pattern++; string++; continue; } /* * Check for a "[" as the next pattern character. It is followed * by a list of characters that are acceptable, or by a range * (two characters separated by "-"). */ if (p == '[') { Tcl_UniChar startChar, endChar; pattern++; ch1 = (nocase ? Tcl_UniCharToLower(*string) : *string); string++; while (1) { if ((*pattern == ']') || (*pattern == 0)) { return 0; } startChar = (nocase ? Tcl_UniCharToLower(*pattern) : *pattern); pattern++; if (*pattern == '-') { pattern++; if (*pattern == 0) { return 0; } endChar = (nocase ? Tcl_UniCharToLower(*pattern) : *pattern); pattern++; if (((startChar <= ch1) && (ch1 <= endChar)) || ((endChar <= ch1) && (ch1 <= startChar))) { /* * Matches ranges of form [a-z] or [z-a]. */ break; } } else if (startChar == ch1) { break; } } while (*pattern != ']') { if (*pattern == 0) { pattern--; break; } pattern++; } pattern++; continue; } /* * If the next pattern character is '\', just strip off the '\' * so we do exact matching on the character that follows. */ if (p == '\\') { if (*(++pattern) == '\0') { return 0; } } /* * There's no special character. Just make sure that the next * bytes of each string match. */ if (nocase) { if (Tcl_UniCharToLower(*string) != Tcl_UniCharToLower(*pattern)) { return 0; } } else if (*string != *pattern) { return 0; } string++; pattern++; } } /* *---------------------------------------------------------------------- * * TclUniCharMatch -- * * See if a particular Unicode string matches a particular pattern. * Allows case insensitivity. This is the Unicode equivalent of the * char* Tcl_StringCaseMatch. This variant of Tcl_UniCharCaseMatch * uses counted Strings, so embedded NULLs are allowed. * * Results: * The return value is 1 if string matches pattern, and * 0 otherwise. The matching operation permits the following * special characters in the pattern: *?\[] (see the manual * entry for details on what these mean). * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclUniCharMatch(string, strLen, pattern, ptnLen, nocase) CONST Tcl_UniChar *string; /* Unicode String. */ int strLen; /* length of String */ CONST Tcl_UniChar *pattern; /* Pattern, which may contain special * characters. */ int ptnLen; /* length of Pattern */ int nocase; /* 0 for case sensitive, 1 for insensitive */ { CONST Tcl_UniChar *stringEnd, *patternEnd; Tcl_UniChar p; stringEnd = string + strLen; patternEnd = pattern + ptnLen; while (1) { /* * See if we're at the end of both the pattern and the string. If * so, we succeeded. If we're at the end of the pattern but not at * the end of the string, we failed. */ if (pattern == patternEnd) { return (string == stringEnd); } p = *pattern; if ((string == stringEnd) && (p != '*')) { return 0; } /* * Check for a "*" as the next pattern character. It matches any * substring. We handle this by skipping all the characters up to the * next matching one in the pattern, and then calling ourselves * recursively for each postfix of string, until either we match or we * reach the end of the string. */ if (p == '*') { /* * Skip all successive *'s in the pattern */ while (*(++pattern) == '*') {} if (pattern == patternEnd) { return 1; } p = *pattern; if (nocase) { p = Tcl_UniCharToLower(p); } while (1) { /* * Optimization for matching - cruise through the string * quickly if the next char in the pattern isn't a special * character */ if ((p != '[') && (p != '?') && (p != '\\')) { if (nocase) { while ((string < stringEnd) && (p != *string) && (p != Tcl_UniCharToLower(*string))) { string++; } } else { while ((string < stringEnd) && (p != *string)) { string++; } } } if (TclUniCharMatch(string, stringEnd - string, pattern, patternEnd - pattern, nocase)) { return 1; } if (string == stringEnd) { return 0; } string++; } } /* * Check for a "?" as the next pattern character. It matches * any single character. */ if (p == '?') { pattern++; string++; continue; } /* * Check for a "[" as the next pattern character. It is followed * by a list of characters that are acceptable, or by a range * (two characters separated by "-"). */ if (p == '[') { Tcl_UniChar ch1, startChar, endChar; pattern++; ch1 = (nocase ? Tcl_UniCharToLower(*string) : *string); string++; while (1) { if ((*pattern == ']') || (pattern == patternEnd)) { return 0; } startChar = (nocase ? Tcl_UniCharToLower(*pattern) : *pattern); pattern++; if (*pattern == '-') { pattern++; if (pattern == patternEnd) { return 0; } endChar = (nocase ? Tcl_UniCharToLower(*pattern) : *pattern); pattern++; if (((startChar <= ch1) && (ch1 <= endChar)) || ((endChar <= ch1) && (ch1 <= startChar))) { /* * Matches ranges of form [a-z] or [z-a]. */ break; } } else if (startChar == ch1) { break; } } while (*pattern != ']') { if (pattern == patternEnd) { pattern--; break; } pattern++; } pattern++; continue; } /* * If the next pattern character is '\', just strip off the '\' * so we do exact matching on the character that follows. */ if (p == '\\') { if (++pattern == patternEnd) { return 0; } } /* * There's no special character. Just make sure that the next * bytes of each string match. */ if (nocase) { if (Tcl_UniCharToLower(*string) != Tcl_UniCharToLower(*pattern)) { return 0; } } else if (*string != *pattern) { return 0; } string++; pattern++; } } tcl8.4.20/generic/rege_dfa.c0000644003604700454610000004270411737050674014242 0ustar dgp771div/* * DFA routines * This file is #included by regexec.c. * * Copyright (c) 1998, 1999 Henry Spencer. All rights reserved. * * Development of this software was funded, in part, by Cray Research Inc., * UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics * Corporation, none of whom are responsible for the results. The author * thanks all of them. * * Redistribution and use in source and binary forms -- with or without * modification -- are permitted for any purpose, provided that * redistributions in source form retain this entire copyright notice and * indicate the origin and nature of any modifications. * * I'd appreciate being given credit for this package in the documentation * of software which uses it, but that is not a requirement. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * HENRY SPENCER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ /* - longest - longest-preferred matching engine ^ static chr *longest(struct vars *, struct dfa *, chr *, chr *, int *); */ static chr * /* endpoint, or NULL */ longest(v, d, start, stop, hitstopp) struct vars *v; /* used only for debug and exec flags */ struct dfa *d; chr *start; /* where the match should start */ chr *stop; /* match must end at or before here */ int *hitstopp; /* record whether hit v->stop, if non-NULL */ { chr *cp; chr *realstop = (stop == v->stop) ? stop : stop + 1; color co; struct sset *css; struct sset *ss; chr *post; int i; struct colormap *cm = d->cm; /* initialize */ css = initialize(v, d, start); cp = start; if (hitstopp != NULL) *hitstopp = 0; /* startup */ FDEBUG(("+++ startup +++\n")); if (cp == v->start) { co = d->cnfa->bos[(v->eflags®_NOTBOL) ? 0 : 1]; FDEBUG(("color %ld\n", (long)co)); } else { co = GETCOLOR(cm, *(cp - 1)); FDEBUG(("char %c, color %ld\n", (char)*(cp-1), (long)co)); } css = miss(v, d, css, co, cp, start); if (css == NULL) return NULL; css->lastseen = cp; /* main loop */ if (v->eflags®_FTRACE) while (cp < realstop) { FDEBUG(("+++ at c%d +++\n", css - d->ssets)); co = GETCOLOR(cm, *cp); FDEBUG(("char %c, color %ld\n", (char)*cp, (long)co)); ss = css->outs[co]; if (ss == NULL) { ss = miss(v, d, css, co, cp+1, start); if (ss == NULL) break; /* NOTE BREAK OUT */ } cp++; ss->lastseen = cp; css = ss; } else while (cp < realstop) { co = GETCOLOR(cm, *cp); ss = css->outs[co]; if (ss == NULL) { ss = miss(v, d, css, co, cp+1, start); if (ss == NULL) break; /* NOTE BREAK OUT */ } cp++; ss->lastseen = cp; css = ss; } /* shutdown */ FDEBUG(("+++ shutdown at c%d +++\n", css - d->ssets)); if (cp == v->stop && stop == v->stop) { if (hitstopp != NULL) *hitstopp = 1; co = d->cnfa->eos[(v->eflags®_NOTEOL) ? 0 : 1]; FDEBUG(("color %ld\n", (long)co)); ss = miss(v, d, css, co, cp, start); /* special case: match ended at eol? */ if (ss != NULL && (ss->flags&POSTSTATE)) return cp; else if (ss != NULL) ss->lastseen = cp; /* to be tidy */ } /* find last match, if any */ post = d->lastpost; for (ss = d->ssets, i = d->nssused; i > 0; ss++, i--) if ((ss->flags&POSTSTATE) && post != ss->lastseen && (post == NULL || post < ss->lastseen)) post = ss->lastseen; if (post != NULL) /* found one */ return post - 1; return NULL; } /* - shortest - shortest-preferred matching engine ^ static chr *shortest(struct vars *, struct dfa *, chr *, chr *, chr *, ^ chr **, int *); */ static chr * /* endpoint, or NULL */ shortest(v, d, start, min, max, coldp, hitstopp) struct vars *v; struct dfa *d; chr *start; /* where the match should start */ chr *min; /* match must end at or after here */ chr *max; /* match must end at or before here */ chr **coldp; /* store coldstart pointer here, if nonNULL */ int *hitstopp; /* record whether hit v->stop, if non-NULL */ { chr *cp; chr *realmin = (min == v->stop) ? min : min + 1; chr *realmax = (max == v->stop) ? max : max + 1; color co; struct sset *css; struct sset *ss; struct colormap *cm = d->cm; /* initialize */ css = initialize(v, d, start); cp = start; if (hitstopp != NULL) *hitstopp = 0; /* startup */ FDEBUG(("--- startup ---\n")); if (cp == v->start) { co = d->cnfa->bos[(v->eflags®_NOTBOL) ? 0 : 1]; FDEBUG(("color %ld\n", (long)co)); } else { co = GETCOLOR(cm, *(cp - 1)); FDEBUG(("char %c, color %ld\n", (char)*(cp-1), (long)co)); } css = miss(v, d, css, co, cp, start); if (css == NULL) return NULL; css->lastseen = cp; ss = css; /* main loop */ if (v->eflags®_FTRACE) while (cp < realmax) { FDEBUG(("--- at c%d ---\n", css - d->ssets)); co = GETCOLOR(cm, *cp); FDEBUG(("char %c, color %ld\n", (char)*cp, (long)co)); ss = css->outs[co]; if (ss == NULL) { ss = miss(v, d, css, co, cp+1, start); if (ss == NULL) break; /* NOTE BREAK OUT */ } cp++; ss->lastseen = cp; css = ss; if ((ss->flags&POSTSTATE) && cp >= realmin) break; /* NOTE BREAK OUT */ } else while (cp < realmax) { co = GETCOLOR(cm, *cp); ss = css->outs[co]; if (ss == NULL) { ss = miss(v, d, css, co, cp+1, start); if (ss == NULL) break; /* NOTE BREAK OUT */ } cp++; ss->lastseen = cp; css = ss; if ((ss->flags&POSTSTATE) && cp >= realmin) break; /* NOTE BREAK OUT */ } if (ss == NULL) return NULL; if (coldp != NULL) /* report last no-progress state set, if any */ *coldp = lastcold(v, d); if ((ss->flags&POSTSTATE) && cp > min) { assert(cp >= realmin); cp--; } else if (cp == v->stop && max == v->stop) { co = d->cnfa->eos[(v->eflags®_NOTEOL) ? 0 : 1]; FDEBUG(("color %ld\n", (long)co)); ss = miss(v, d, css, co, cp, start); /* match might have ended at eol */ if ((ss == NULL || !(ss->flags&POSTSTATE)) && hitstopp != NULL) *hitstopp = 1; } if (ss == NULL || !(ss->flags&POSTSTATE)) return NULL; return cp; } /* - lastcold - determine last point at which no progress had been made ^ static chr *lastcold(struct vars *, struct dfa *); */ static chr * /* endpoint, or NULL */ lastcold(v, d) struct vars *v; struct dfa *d; { struct sset *ss; chr *nopr; int i; nopr = d->lastnopr; if (nopr == NULL) nopr = v->start; for (ss = d->ssets, i = d->nssused; i > 0; ss++, i--) if ((ss->flags&NOPROGRESS) && nopr < ss->lastseen) nopr = ss->lastseen; return nopr; } /* - newdfa - set up a fresh DFA ^ static struct dfa *newdfa(struct vars *, struct cnfa *, ^ struct colormap *, struct smalldfa *); */ static struct dfa * newdfa(v, cnfa, cm, small) struct vars *v; struct cnfa *cnfa; struct colormap *cm; struct smalldfa *small; /* preallocated space, may be NULL */ { struct dfa *d; size_t nss = cnfa->nstates * 2; int wordsper = (cnfa->nstates + UBITS - 1) / UBITS; struct smalldfa *smallwas = small; assert(cnfa != NULL && cnfa->nstates != 0); if (nss <= FEWSTATES && cnfa->ncolors <= FEWCOLORS) { assert(wordsper == 1); if (small == NULL) { small = (struct smalldfa *)MALLOC( sizeof(struct smalldfa)); if (small == NULL) { ERR(REG_ESPACE); return NULL; } } d = &small->dfa; d->ssets = small->ssets; d->statesarea = small->statesarea; d->work = &d->statesarea[nss]; d->outsarea = small->outsarea; d->incarea = small->incarea; d->cptsmalloced = 0; d->mallocarea = (smallwas == NULL) ? (char *)small : NULL; } else { d = (struct dfa *)MALLOC(sizeof(struct dfa)); if (d == NULL) { ERR(REG_ESPACE); return NULL; } d->ssets = (struct sset *)MALLOC(nss * sizeof(struct sset)); d->statesarea = (unsigned *)MALLOC((nss+WORK) * wordsper * sizeof(unsigned)); d->work = &d->statesarea[nss * wordsper]; d->outsarea = (struct sset **)MALLOC(nss * cnfa->ncolors * sizeof(struct sset *)); d->incarea = (struct arcp *)MALLOC(nss * cnfa->ncolors * sizeof(struct arcp)); d->cptsmalloced = 1; d->mallocarea = (char *)d; if (d->ssets == NULL || d->statesarea == NULL || d->outsarea == NULL || d->incarea == NULL) { freedfa(d); ERR(REG_ESPACE); return NULL; } } d->nssets = (v->eflags®_SMALL) ? 7 : nss; d->nssused = 0; d->nstates = cnfa->nstates; d->ncolors = cnfa->ncolors; d->wordsper = wordsper; d->cnfa = cnfa; d->cm = cm; d->lastpost = NULL; d->lastnopr = NULL; d->search = d->ssets; /* initialization of sset fields is done as needed */ return d; } /* - freedfa - free a DFA ^ static VOID freedfa(struct dfa *); */ static VOID freedfa(d) struct dfa *d; { if (d->cptsmalloced) { if (d->ssets != NULL) FREE(d->ssets); if (d->statesarea != NULL) FREE(d->statesarea); if (d->outsarea != NULL) FREE(d->outsarea); if (d->incarea != NULL) FREE(d->incarea); } if (d->mallocarea != NULL) FREE(d->mallocarea); } /* - hash - construct a hash code for a bitvector * There are probably better ways, but they're more expensive. ^ static unsigned hash(unsigned *, int); */ static unsigned hash(uv, n) unsigned *uv; int n; { int i; unsigned h; h = 0; for (i = 0; i < n; i++) h ^= uv[i]; return h; } /* - initialize - hand-craft a cache entry for startup, otherwise get ready ^ static struct sset *initialize(struct vars *, struct dfa *, chr *); */ static struct sset * initialize(v, d, start) struct vars *v; /* used only for debug flags */ struct dfa *d; chr *start; { struct sset *ss; int i; /* is previous one still there? */ if (d->nssused > 0 && (d->ssets[0].flags&STARTER)) ss = &d->ssets[0]; else { /* no, must (re)build it */ ss = getvacant(v, d, start, start); for (i = 0; i < d->wordsper; i++) ss->states[i] = 0; BSET(ss->states, d->cnfa->pre); ss->hash = HASH(ss->states, d->wordsper); assert(d->cnfa->pre != d->cnfa->post); ss->flags = STARTER|LOCKED|NOPROGRESS; /* lastseen dealt with below */ } for (i = 0; i < d->nssused; i++) d->ssets[i].lastseen = NULL; ss->lastseen = start; /* maybe untrue, but harmless */ d->lastpost = NULL; d->lastnopr = NULL; return ss; } /* - miss - handle a cache miss ^ static struct sset *miss(struct vars *, struct dfa *, struct sset *, ^ pcolor, chr *, chr *); */ static struct sset * /* NULL if goes to empty set */ miss(v, d, css, co, cp, start) struct vars *v; /* used only for debug flags */ struct dfa *d; struct sset *css; pcolor co; chr *cp; /* next chr */ chr *start; /* where the attempt got started */ { struct cnfa *cnfa = d->cnfa; int i; unsigned h; struct carc *ca; struct sset *p; int ispost; int noprogress; int gotstate; int dolacons; int sawlacons; /* for convenience, we can be called even if it might not be a miss */ if (css->outs[co] != NULL) { FDEBUG(("hit\n")); return css->outs[co]; } FDEBUG(("miss\n")); /* first, what set of states would we end up in? */ for (i = 0; i < d->wordsper; i++) d->work[i] = 0; ispost = 0; noprogress = 1; gotstate = 0; for (i = 0; i < d->nstates; i++) if (ISBSET(css->states, i)) for (ca = cnfa->states[i]+1; ca->co != COLORLESS; ca++) if (ca->co == co) { BSET(d->work, ca->to); gotstate = 1; if (ca->to == cnfa->post) ispost = 1; if (!cnfa->states[ca->to]->co) noprogress = 0; FDEBUG(("%d -> %d\n", i, ca->to)); } dolacons = (gotstate) ? (cnfa->flags&HASLACONS) : 0; sawlacons = 0; while (dolacons) { /* transitive closure */ dolacons = 0; for (i = 0; i < d->nstates; i++) if (ISBSET(d->work, i)) for (ca = cnfa->states[i]+1; ca->co != COLORLESS; ca++) { if (ca->co <= cnfa->ncolors) continue; /* NOTE CONTINUE */ sawlacons = 1; if (ISBSET(d->work, ca->to)) continue; /* NOTE CONTINUE */ if (!lacon(v, cnfa, cp, ca->co)) continue; /* NOTE CONTINUE */ BSET(d->work, ca->to); dolacons = 1; if (ca->to == cnfa->post) ispost = 1; if (!cnfa->states[ca->to]->co) noprogress = 0; FDEBUG(("%d :> %d\n", i, ca->to)); } } if (!gotstate) return NULL; h = HASH(d->work, d->wordsper); /* next, is that in the cache? */ for (p = d->ssets, i = d->nssused; i > 0; p++, i--) if (HIT(h, d->work, p, d->wordsper)) { FDEBUG(("cached c%d\n", p - d->ssets)); break; /* NOTE BREAK OUT */ } if (i == 0) { /* nope, need a new cache entry */ p = getvacant(v, d, cp, start); assert(p != css); for (i = 0; i < d->wordsper; i++) p->states[i] = d->work[i]; p->hash = h; p->flags = (ispost) ? POSTSTATE : 0; if (noprogress) p->flags |= NOPROGRESS; /* lastseen to be dealt with by caller */ } if (!sawlacons) { /* lookahead conds. always cache miss */ FDEBUG(("c%d[%d]->c%d\n", css - d->ssets, co, p - d->ssets)); css->outs[co] = p; css->inchain[co] = p->ins; p->ins.ss = css; p->ins.co = (color)co; } return p; } /* - lacon - lookahead-constraint checker for miss() ^ static int lacon(struct vars *, struct cnfa *, chr *, pcolor); */ static int /* predicate: constraint satisfied? */ lacon(v, pcnfa, cp, co) struct vars *v; struct cnfa *pcnfa; /* parent cnfa */ chr *cp; pcolor co; /* "color" of the lookahead constraint */ { int n; struct subre *sub; struct dfa *d; struct smalldfa sd; chr *end; n = co - pcnfa->ncolors; assert(n < v->g->nlacons && v->g->lacons != NULL); FDEBUG(("=== testing lacon %d\n", n)); sub = &v->g->lacons[n]; d = newdfa(v, &sub->cnfa, &v->g->cmap, &sd); if (d == NULL) { ERR(REG_ESPACE); return 0; } end = longest(v, d, cp, v->stop, (int *)NULL); freedfa(d); FDEBUG(("=== lacon %d match %d\n", n, (end != NULL))); return (sub->subno) ? (end != NULL) : (end == NULL); } /* - getvacant - get a vacant state set * This routine clears out the inarcs and outarcs, but does not otherwise * clear the innards of the state set -- that's up to the caller. ^ static struct sset *getvacant(struct vars *, struct dfa *, chr *, chr *); */ static struct sset * getvacant(v, d, cp, start) struct vars *v; /* used only for debug flags */ struct dfa *d; chr *cp; chr *start; { int i; struct sset *ss; struct sset *p; struct arcp ap; struct arcp lastap = {NULL, 0}; /* silence gcc 4 warning */ color co; ss = pickss(v, d, cp, start); assert(!(ss->flags&LOCKED)); /* clear out its inarcs, including self-referential ones */ ap = ss->ins; while ((p = ap.ss) != NULL) { co = ap.co; FDEBUG(("zapping c%d's %ld outarc\n", p - d->ssets, (long)co)); p->outs[co] = NULL; ap = p->inchain[co]; p->inchain[co].ss = NULL; /* paranoia */ } ss->ins.ss = NULL; /* take it off the inarc chains of the ssets reached by its outarcs */ for (i = 0; i < d->ncolors; i++) { p = ss->outs[i]; assert(p != ss); /* not self-referential */ if (p == NULL) continue; /* NOTE CONTINUE */ FDEBUG(("del outarc %d from c%d's in chn\n", i, p - d->ssets)); if (p->ins.ss == ss && p->ins.co == i) p->ins = ss->inchain[i]; else { assert(p->ins.ss != NULL); for (ap = p->ins; ap.ss != NULL && !(ap.ss == ss && ap.co == i); ap = ap.ss->inchain[ap.co]) lastap = ap; assert(ap.ss != NULL); lastap.ss->inchain[lastap.co] = ss->inchain[i]; } ss->outs[i] = NULL; ss->inchain[i].ss = NULL; } /* if ss was a success state, may need to remember location */ if ((ss->flags&POSTSTATE) && ss->lastseen != d->lastpost && (d->lastpost == NULL || d->lastpost < ss->lastseen)) d->lastpost = ss->lastseen; /* likewise for a no-progress state */ if ((ss->flags&NOPROGRESS) && ss->lastseen != d->lastnopr && (d->lastnopr == NULL || d->lastnopr < ss->lastseen)) d->lastnopr = ss->lastseen; return ss; } /* - pickss - pick the next stateset to be used ^ static struct sset *pickss(struct vars *, struct dfa *, chr *, chr *); */ static struct sset * pickss(v, d, cp, start) struct vars *v; /* used only for debug flags */ struct dfa *d; chr *cp; chr *start; { int i; struct sset *ss; struct sset *end; chr *ancient; /* shortcut for cases where cache isn't full */ if (d->nssused < d->nssets) { i = d->nssused; d->nssused++; ss = &d->ssets[i]; FDEBUG(("new c%d\n", i)); /* set up innards */ ss->states = &d->statesarea[i * d->wordsper]; ss->flags = 0; ss->ins.ss = NULL; ss->ins.co = WHITE; /* give it some value */ ss->outs = &d->outsarea[i * d->ncolors]; ss->inchain = &d->incarea[i * d->ncolors]; for (i = 0; i < d->ncolors; i++) { ss->outs[i] = NULL; ss->inchain[i].ss = NULL; } return ss; } /* look for oldest, or old enough anyway */ if (cp - start > d->nssets*2/3) /* oldest 33% are expendable */ ancient = cp - d->nssets*2/3; else ancient = start; for (ss = d->search, end = &d->ssets[d->nssets]; ss < end; ss++) if ((ss->lastseen == NULL || ss->lastseen < ancient) && !(ss->flags&LOCKED)) { d->search = ss + 1; FDEBUG(("replacing c%d\n", ss - d->ssets)); return ss; } for (ss = d->ssets, end = d->search; ss < end; ss++) if ((ss->lastseen == NULL || ss->lastseen < ancient) && !(ss->flags&LOCKED)) { d->search = ss + 1; FDEBUG(("replacing c%d\n", ss - d->ssets)); return ss; } /* nobody's old enough?!? -- something's really wrong */ FDEBUG(("can't find victim to replace!\n")); assert(NOTREACHED); ERR(REG_ASSERT); return d->ssets; } tcl8.4.20/generic/tclNotify.c0000644003604700454610000007550612052456744014466 0ustar dgp771div/* * tclNotify.c -- * * This file implements the generic portion of the Tcl notifier. * The notifier is lowest-level part of the event system. It * manages an event queue that holds Tcl_Event structures. The * platform specific portion of the notifier is defined in the * tcl*Notify.c files in each platform directory. * * Copyright (c) 1995-1997 Sun Microsystems, Inc. * Copyright (c) 1998 by Scriptics Corporation. * Copyright (c) 2003 by Kevin B. Kenny. All rights reserved. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" extern TclStubs tclStubs; /* * For each event source (created with Tcl_CreateEventSource) there * is a structure of the following type: */ typedef struct EventSource { Tcl_EventSetupProc *setupProc; Tcl_EventCheckProc *checkProc; ClientData clientData; struct EventSource *nextPtr; } EventSource; /* * The following structure keeps track of the state of the notifier on a * per-thread basis. The first three elements keep track of the event queue. * In addition to the first (next to be serviced) and last events in the queue, * we keep track of a "marker" event. This provides a simple priority * mechanism whereby events can be inserted at the front of the queue but * behind all other high-priority events already in the queue (this is used for * things like a sequence of Enter and Leave events generated during a grab in * Tk). These elements are protected by the queueMutex so that any thread * can queue an event on any notifier. Note that all of the values in this * structure will be initialized to 0. */ typedef struct ThreadSpecificData { Tcl_Event *firstEventPtr; /* First pending event, or NULL if none. */ Tcl_Event *lastEventPtr; /* Last pending event, or NULL if none. */ Tcl_Event *markerEventPtr; /* Last high-priority event in queue, or * NULL if none. */ Tcl_Mutex queueMutex; /* Mutex to protect access to the previous * three fields. */ int serviceMode; /* One of TCL_SERVICE_NONE or * TCL_SERVICE_ALL. */ int blockTimeSet; /* 0 means there is no maximum block * time: block forever. */ Tcl_Time blockTime; /* If blockTimeSet is 1, gives the * maximum elapsed time for the next block. */ int inTraversal; /* 1 if Tcl_SetMaxBlockTime is being * called during an event source traversal. */ EventSource *firstEventSourcePtr; /* Pointer to first event source in * list of event sources for this thread. */ Tcl_ThreadId threadId; /* Thread that owns this notifier instance. */ ClientData clientData; /* Opaque handle for platform specific * notifier. */ int initialized; /* 1 if notifier has been initialized. */ struct ThreadSpecificData *nextPtr; /* Next notifier in global list of notifiers. * Access is controlled by the listLock global * mutex. */ } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; /* * Global list of notifiers. Access to this list is controlled by the * listLock mutex. If this becomes a performance bottleneck, this could * be replaced with a hashtable. */ static ThreadSpecificData *firstNotifierPtr; TCL_DECLARE_MUTEX(listLock) /* * Declarations for routines used only in this file. */ static void QueueEvent _ANSI_ARGS_((ThreadSpecificData *tsdPtr, Tcl_Event* evPtr, Tcl_QueuePosition position)); /* *---------------------------------------------------------------------- * * TclInitNotifier -- * * Initialize the thread local data structures for the notifier * subsystem. * * Results: * None. * * Side effects: * Adds the current thread to the global list of notifiers. * *---------------------------------------------------------------------- */ void TclInitNotifier() { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); Tcl_MutexLock(&listLock); tsdPtr->threadId = Tcl_GetCurrentThread(); tsdPtr->clientData = tclStubs.tcl_InitNotifier(); tsdPtr->initialized = 1; tsdPtr->nextPtr = firstNotifierPtr; firstNotifierPtr = tsdPtr; Tcl_MutexUnlock(&listLock); } /* *---------------------------------------------------------------------- * * TclFinalizeNotifier -- * * Finalize the thread local data structures for the notifier * subsystem. * * Results: * None. * * Side effects: * Removes the notifier associated with the current thread from * the global notifier list. This is done only if the notifier * was initialized for this thread by call to TclInitNotifier(). * This is always true for threads which have been seeded with * an Tcl interpreter, since the call to Tcl_CreateInterp will, * among other things, call TclInitializeSubsystems() and this * one will, in turn, call the TclInitNotifier() for the thread. * For threads created without the Tcl interpreter, though, * nobody is explicitly nor implicitly calling the TclInitNotifier * hence, TclFinalizeNotifier should not be performed at all. * *---------------------------------------------------------------------- */ void TclFinalizeNotifier() { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); ThreadSpecificData **prevPtrPtr; Tcl_Event *evPtr, *hold; if (!tsdPtr->initialized) { return; /* Notifier not initialized for the current thread */ } Tcl_MutexLock(&(tsdPtr->queueMutex)); for (evPtr = tsdPtr->firstEventPtr; evPtr != (Tcl_Event *) NULL; ) { hold = evPtr; evPtr = evPtr->nextPtr; ckfree((char *) hold); } tsdPtr->firstEventPtr = NULL; tsdPtr->lastEventPtr = NULL; Tcl_MutexUnlock(&(tsdPtr->queueMutex)); Tcl_MutexLock(&listLock); if (tclStubs.tcl_FinalizeNotifier) { tclStubs.tcl_FinalizeNotifier(tsdPtr->clientData); } Tcl_MutexFinalize(&(tsdPtr->queueMutex)); for (prevPtrPtr = &firstNotifierPtr; *prevPtrPtr != NULL; prevPtrPtr = &((*prevPtrPtr)->nextPtr)) { if (*prevPtrPtr == tsdPtr) { *prevPtrPtr = tsdPtr->nextPtr; break; } } tsdPtr->initialized = 0; Tcl_MutexUnlock(&listLock); } /* *---------------------------------------------------------------------- * * Tcl_SetNotifier -- * * Install a set of alternate functions for use with the notifier. # In particular, this can be used to install the Xt-based * notifier for use with the Browser plugin. * * Results: * None. * * Side effects: * Overstomps part of the stub vector. This relies on hooks * added to the default procedures in case those are called * directly (i.e., not through the stub table.) * *---------------------------------------------------------------------- */ void Tcl_SetNotifier(notifierProcPtr) Tcl_NotifierProcs *notifierProcPtr; { #if !defined(__WIN32__) /* UNIX */ tclStubs.tcl_CreateFileHandler = notifierProcPtr->createFileHandlerProc; tclStubs.tcl_DeleteFileHandler = notifierProcPtr->deleteFileHandlerProc; #endif tclStubs.tcl_SetTimer = notifierProcPtr->setTimerProc; tclStubs.tcl_WaitForEvent = notifierProcPtr->waitForEventProc; tclStubs.tcl_InitNotifier = notifierProcPtr->initNotifierProc; tclStubs.tcl_FinalizeNotifier = notifierProcPtr->finalizeNotifierProc; tclStubs.tcl_AlertNotifier = notifierProcPtr->alertNotifierProc; tclStubs.tcl_ServiceModeHook = notifierProcPtr->serviceModeHookProc; } /* *---------------------------------------------------------------------- * * Tcl_CreateEventSource -- * * This procedure is invoked to create a new source of events. * The source is identified by a procedure that gets invoked * during Tcl_DoOneEvent to check for events on that source * and queue them. * * * Results: * None. * * Side effects: * SetupProc and checkProc will be invoked each time that Tcl_DoOneEvent * runs out of things to do. SetupProc will be invoked before * Tcl_DoOneEvent calls select or whatever else it uses to wait * for events. SetupProc typically calls functions like * Tcl_SetMaxBlockTime to indicate what to wait for. * * CheckProc is called after select or whatever operation was actually * used to wait. It figures out whether anything interesting actually * happened (e.g. by calling Tcl_AsyncReady), and then calls * Tcl_QueueEvent to queue any events that are ready. * * Each of these procedures is passed two arguments, e.g. * (*checkProc)(ClientData clientData, int flags)); * ClientData is the same as the clientData argument here, and flags * is a combination of things like TCL_FILE_EVENTS that indicates * what events are of interest: setupProc and checkProc use flags * to figure out whether their events are relevant or not. * *---------------------------------------------------------------------- */ void Tcl_CreateEventSource(setupProc, checkProc, clientData) Tcl_EventSetupProc *setupProc; /* Procedure to invoke to figure out * what to wait for. */ Tcl_EventCheckProc *checkProc; /* Procedure to call after waiting * to see what happened. */ ClientData clientData; /* One-word argument to pass to * setupProc and checkProc. */ { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); EventSource *sourcePtr = (EventSource *) ckalloc(sizeof(EventSource)); sourcePtr->setupProc = setupProc; sourcePtr->checkProc = checkProc; sourcePtr->clientData = clientData; sourcePtr->nextPtr = tsdPtr->firstEventSourcePtr; tsdPtr->firstEventSourcePtr = sourcePtr; } /* *---------------------------------------------------------------------- * * Tcl_DeleteEventSource -- * * This procedure is invoked to delete the source of events * given by proc and clientData. * * Results: * None. * * Side effects: * The given event source is cancelled, so its procedure will * never again be called. If no such source exists, nothing * happens. * *---------------------------------------------------------------------- */ void Tcl_DeleteEventSource(setupProc, checkProc, clientData) Tcl_EventSetupProc *setupProc; /* Procedure to invoke to figure out * what to wait for. */ Tcl_EventCheckProc *checkProc; /* Procedure to call after waiting * to see what happened. */ ClientData clientData; /* One-word argument to pass to * setupProc and checkProc. */ { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); EventSource *sourcePtr, *prevPtr; for (sourcePtr = tsdPtr->firstEventSourcePtr, prevPtr = NULL; sourcePtr != NULL; prevPtr = sourcePtr, sourcePtr = sourcePtr->nextPtr) { if ((sourcePtr->setupProc != setupProc) || (sourcePtr->checkProc != checkProc) || (sourcePtr->clientData != clientData)) { continue; } if (prevPtr == NULL) { tsdPtr->firstEventSourcePtr = sourcePtr->nextPtr; } else { prevPtr->nextPtr = sourcePtr->nextPtr; } ckfree((char *) sourcePtr); return; } } /* *---------------------------------------------------------------------- * * Tcl_QueueEvent -- * * Queue an event on the event queue associated with the * current thread. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Tcl_QueueEvent(evPtr, position) Tcl_Event* evPtr; /* Event to add to queue. The storage * space must have been allocated the caller * with malloc (ckalloc), and it becomes * the property of the event queue. It * will be freed after the event has been * handled. */ Tcl_QueuePosition position; /* One of TCL_QUEUE_TAIL, TCL_QUEUE_HEAD, * TCL_QUEUE_MARK. */ { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); QueueEvent(tsdPtr, evPtr, position); } /* *---------------------------------------------------------------------- * * Tcl_ThreadQueueEvent -- * * Queue an event on the specified thread's event queue. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Tcl_ThreadQueueEvent(threadId, evPtr, position) Tcl_ThreadId threadId; /* Identifier for thread to use. */ Tcl_Event* evPtr; /* Event to add to queue. The storage * space must have been allocated the caller * with malloc (ckalloc), and it becomes * the property of the event queue. It * will be freed after the event has been * handled. */ Tcl_QueuePosition position; /* One of TCL_QUEUE_TAIL, TCL_QUEUE_HEAD, * TCL_QUEUE_MARK. */ { ThreadSpecificData *tsdPtr; /* * Find the notifier associated with the specified thread. */ Tcl_MutexLock(&listLock); for (tsdPtr = firstNotifierPtr; tsdPtr && tsdPtr->threadId != threadId; tsdPtr = tsdPtr->nextPtr) { /* Empty loop body. */ } /* * Queue the event if there was a notifier associated with the thread. */ if (tsdPtr) { QueueEvent(tsdPtr, evPtr, position); } else { ckfree((char *) evPtr); } Tcl_MutexUnlock(&listLock); } /* *---------------------------------------------------------------------- * * QueueEvent -- * * Insert an event into the specified thread's event queue at one * of three positions: the head, the tail, or before a floating * marker. Events inserted before the marker will be processed in * first-in-first-out order, but before any events inserted at * the tail of the queue. Events inserted at the head of the * queue will be processed in last-in-first-out order. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void QueueEvent(tsdPtr, evPtr, position) ThreadSpecificData *tsdPtr; /* Handle to thread local data that indicates * which event queue to use. */ Tcl_Event* evPtr; /* Event to add to queue. The storage * space must have been allocated the caller * with malloc (ckalloc), and it becomes * the property of the event queue. It * will be freed after the event has been * handled. */ Tcl_QueuePosition position; /* One of TCL_QUEUE_TAIL, TCL_QUEUE_HEAD, * TCL_QUEUE_MARK. */ { Tcl_MutexLock(&(tsdPtr->queueMutex)); if (position == TCL_QUEUE_TAIL) { /* * Append the event on the end of the queue. */ evPtr->nextPtr = NULL; if (tsdPtr->firstEventPtr == NULL) { tsdPtr->firstEventPtr = evPtr; } else { tsdPtr->lastEventPtr->nextPtr = evPtr; } tsdPtr->lastEventPtr = evPtr; } else if (position == TCL_QUEUE_HEAD) { /* * Push the event on the head of the queue. */ evPtr->nextPtr = tsdPtr->firstEventPtr; if (tsdPtr->firstEventPtr == NULL) { tsdPtr->lastEventPtr = evPtr; } tsdPtr->firstEventPtr = evPtr; } else if (position == TCL_QUEUE_MARK) { /* * Insert the event after the current marker event and advance * the marker to the new event. */ if (tsdPtr->markerEventPtr == NULL) { evPtr->nextPtr = tsdPtr->firstEventPtr; tsdPtr->firstEventPtr = evPtr; } else { evPtr->nextPtr = tsdPtr->markerEventPtr->nextPtr; tsdPtr->markerEventPtr->nextPtr = evPtr; } tsdPtr->markerEventPtr = evPtr; if (evPtr->nextPtr == NULL) { tsdPtr->lastEventPtr = evPtr; } } Tcl_MutexUnlock(&(tsdPtr->queueMutex)); } /* *---------------------------------------------------------------------- * * Tcl_DeleteEvents -- * * Calls a procedure for each event in the queue and deletes those * for which the procedure returns 1. Events for which the * procedure returns 0 are left in the queue. Operates on the * queue associated with the current thread. * * Results: * None. * * Side effects: * Potentially removes one or more events from the event queue. * *---------------------------------------------------------------------- */ void Tcl_DeleteEvents(proc, clientData) Tcl_EventDeleteProc *proc; /* The procedure to call. */ ClientData clientData; /* type-specific data. */ { Tcl_Event *evPtr, *prevPtr, *hold; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); Tcl_MutexLock(&(tsdPtr->queueMutex)); for (prevPtr = (Tcl_Event *) NULL, evPtr = tsdPtr->firstEventPtr; evPtr != (Tcl_Event *) NULL; ) { if ((*proc) (evPtr, clientData) == 1) { if (tsdPtr->firstEventPtr == evPtr) { tsdPtr->firstEventPtr = evPtr->nextPtr; } else { prevPtr->nextPtr = evPtr->nextPtr; } if (evPtr->nextPtr == (Tcl_Event *) NULL) { tsdPtr->lastEventPtr = prevPtr; } if (tsdPtr->markerEventPtr == evPtr) { tsdPtr->markerEventPtr = prevPtr; } hold = evPtr; evPtr = evPtr->nextPtr; ckfree((char *) hold); } else { prevPtr = evPtr; evPtr = evPtr->nextPtr; } } Tcl_MutexUnlock(&(tsdPtr->queueMutex)); } /* *---------------------------------------------------------------------- * * Tcl_ServiceEvent -- * * Process one event from the event queue, or invoke an * asynchronous event handler. Operates on event queue for * current thread. * * Results: * The return value is 1 if the procedure actually found an event * to process. If no processing occurred, then 0 is returned. * * Side effects: * Invokes all of the event handlers for the highest priority * event in the event queue. May collapse some events into a * single event or discard stale events. * *---------------------------------------------------------------------- */ int Tcl_ServiceEvent(flags) int flags; /* Indicates what events should be processed. * May be any combination of TCL_WINDOW_EVENTS * TCL_FILE_EVENTS, TCL_TIMER_EVENTS, or other * flags defined elsewhere. Events not * matching this will be skipped for processing * later. */ { Tcl_Event *evPtr, *prevPtr; Tcl_EventProc *proc; int result; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); /* * Asynchronous event handlers are considered to be the highest * priority events, and so must be invoked before we process events * on the event queue. */ if (Tcl_AsyncReady()) { (void) Tcl_AsyncInvoke((Tcl_Interp *) NULL, 0); return 1; } /* * No event flags is equivalent to TCL_ALL_EVENTS. */ if ((flags & TCL_ALL_EVENTS) == 0) { flags |= TCL_ALL_EVENTS; } /* * Loop through all the events in the queue until we find one * that can actually be handled. */ Tcl_MutexLock(&(tsdPtr->queueMutex)); for (evPtr = tsdPtr->firstEventPtr; evPtr != NULL; evPtr = evPtr->nextPtr) { /* * Call the handler for the event. If it actually handles the * event then free the storage for the event. There are two * tricky things here, both stemming from the fact that the event * code may be re-entered while servicing the event: * * 1. Set the "proc" field to NULL. This is a signal to ourselves * that we shouldn't reexecute the handler if the event loop * is re-entered. * 2. When freeing the event, must search the queue again from the * front to find it. This is because the event queue could * change almost arbitrarily while handling the event, so we * can't depend on pointers found now still being valid when * the handler returns. */ proc = evPtr->proc; if (proc == NULL) { continue; } evPtr->proc = NULL; /* * Release the lock before calling the event procedure. This * allows other threads to post events if we enter a recursive * event loop in this thread. Note that we are making the assumption * that if the proc returns 0, the event is still in the list. */ Tcl_MutexUnlock(&(tsdPtr->queueMutex)); result = (*proc)(evPtr, flags); Tcl_MutexLock(&(tsdPtr->queueMutex)); if (result) { /* * The event was processed, so remove it from the queue. */ if (tsdPtr->firstEventPtr == evPtr) { tsdPtr->firstEventPtr = evPtr->nextPtr; if (evPtr->nextPtr == NULL) { tsdPtr->lastEventPtr = NULL; } if (tsdPtr->markerEventPtr == evPtr) { tsdPtr->markerEventPtr = NULL; } } else { for (prevPtr = tsdPtr->firstEventPtr; prevPtr && prevPtr->nextPtr != evPtr; prevPtr = prevPtr->nextPtr) { /* Empty loop body. */ } if (prevPtr) { prevPtr->nextPtr = evPtr->nextPtr; if (evPtr->nextPtr == NULL) { tsdPtr->lastEventPtr = prevPtr; } if (tsdPtr->markerEventPtr == evPtr) { tsdPtr->markerEventPtr = prevPtr; } } else { evPtr = NULL; } } if (evPtr) { ckfree((char *) evPtr); } Tcl_MutexUnlock(&(tsdPtr->queueMutex)); return 1; } else { /* * The event wasn't actually handled, so we have to restore * the proc field to allow the event to be attempted again. */ evPtr->proc = proc; } } Tcl_MutexUnlock(&(tsdPtr->queueMutex)); return 0; } /* *---------------------------------------------------------------------- * * Tcl_GetServiceMode -- * * This routine returns the current service mode of the notifier. * * Results: * Returns either TCL_SERVICE_ALL or TCL_SERVICE_NONE. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_GetServiceMode() { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); return tsdPtr->serviceMode; } /* *---------------------------------------------------------------------- * * Tcl_SetServiceMode -- * * This routine sets the current service mode of the tsdPtr-> * * Results: * Returns the previous service mode. * * Side effects: * Invokes the notifier service mode hook procedure. * *---------------------------------------------------------------------- */ int Tcl_SetServiceMode(mode) int mode; /* New service mode: TCL_SERVICE_ALL or * TCL_SERVICE_NONE */ { int oldMode; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); oldMode = tsdPtr->serviceMode; tsdPtr->serviceMode = mode; if (tclStubs.tcl_ServiceModeHook) { tclStubs.tcl_ServiceModeHook(mode); } return oldMode; } /* *---------------------------------------------------------------------- * * Tcl_SetMaxBlockTime -- * * This procedure is invoked by event sources to tell the notifier * how long it may block the next time it blocks. The timePtr * argument gives a maximum time; the actual time may be less if * some other event source requested a smaller time. * * Results: * None. * * Side effects: * May reduce the length of the next sleep in the tsdPtr-> * *---------------------------------------------------------------------- */ void Tcl_SetMaxBlockTime(timePtr) Tcl_Time *timePtr; /* Specifies a maximum elapsed time for * the next blocking operation in the * event tsdPtr-> */ { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (!tsdPtr->blockTimeSet || (timePtr->sec < tsdPtr->blockTime.sec) || ((timePtr->sec == tsdPtr->blockTime.sec) && (timePtr->usec < tsdPtr->blockTime.usec))) { tsdPtr->blockTime = *timePtr; tsdPtr->blockTimeSet = 1; } /* * If we are called outside an event source traversal, set the * timeout immediately. */ if (!tsdPtr->inTraversal) { if (tsdPtr->blockTimeSet) { Tcl_SetTimer(&tsdPtr->blockTime); } else { Tcl_SetTimer(NULL); } } } /* *---------------------------------------------------------------------- * * Tcl_DoOneEvent -- * * Process a single event of some sort. If there's no work to * do, wait for an event to occur, then process it. * * Results: * The return value is 1 if the procedure actually found an event * to process. If no processing occurred, then 0 is returned (this * can happen if the TCL_DONT_WAIT flag is set or if there are no * event handlers to wait for in the set specified by flags). * * Side effects: * May delay execution of process while waiting for an event, * unless TCL_DONT_WAIT is set in the flags argument. Event * sources are invoked to check for and queue events. Event * handlers may produce arbitrary side effects. * *---------------------------------------------------------------------- */ int Tcl_DoOneEvent(flags) int flags; /* Miscellaneous flag values: may be any * combination of TCL_DONT_WAIT, * TCL_WINDOW_EVENTS, TCL_FILE_EVENTS, * TCL_TIMER_EVENTS, TCL_IDLE_EVENTS, or * others defined by event sources. */ { int result = 0, oldMode; EventSource *sourcePtr; Tcl_Time *timePtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); /* * The first thing we do is to service any asynchronous event * handlers. */ if (Tcl_AsyncReady()) { (void) Tcl_AsyncInvoke((Tcl_Interp *) NULL, 0); return 1; } /* * No event flags is equivalent to TCL_ALL_EVENTS. */ if ((flags & TCL_ALL_EVENTS) == 0) { flags |= TCL_ALL_EVENTS; } /* * Set the service mode to none so notifier event routines won't * try to service events recursively. */ oldMode = tsdPtr->serviceMode; tsdPtr->serviceMode = TCL_SERVICE_NONE; /* * The core of this procedure is an infinite loop, even though * we only service one event. The reason for this is that we * may be processing events that don't do anything inside of Tcl. */ while (1) { /* * If idle events are the only things to service, skip the * main part of the loop and go directly to handle idle * events (i.e. don't wait even if TCL_DONT_WAIT isn't set). */ if ((flags & TCL_ALL_EVENTS) == TCL_IDLE_EVENTS) { flags = TCL_IDLE_EVENTS|TCL_DONT_WAIT; goto idleEvents; } /* * Ask Tcl to service a queued event, if there are any. */ if (Tcl_ServiceEvent(flags)) { result = 1; break; } /* * If TCL_DONT_WAIT is set, be sure to poll rather than * blocking, otherwise reset the block time to infinity. */ if (flags & TCL_DONT_WAIT) { tsdPtr->blockTime.sec = 0; tsdPtr->blockTime.usec = 0; tsdPtr->blockTimeSet = 1; } else { tsdPtr->blockTimeSet = 0; } /* * Set up all the event sources for new events. This will * cause the block time to be updated if necessary. */ tsdPtr->inTraversal = 1; for (sourcePtr = tsdPtr->firstEventSourcePtr; sourcePtr != NULL; sourcePtr = sourcePtr->nextPtr) { if (sourcePtr->setupProc) { (sourcePtr->setupProc)(sourcePtr->clientData, flags); } } tsdPtr->inTraversal = 0; if ((flags & TCL_DONT_WAIT) || tsdPtr->blockTimeSet) { timePtr = &tsdPtr->blockTime; } else { timePtr = NULL; } /* * Wait for a new event or a timeout. If Tcl_WaitForEvent * returns -1, we should abort Tcl_DoOneEvent. */ result = Tcl_WaitForEvent(timePtr); if (result < 0) { result = 0; break; } /* * Check all the event sources for new events. */ for (sourcePtr = tsdPtr->firstEventSourcePtr; sourcePtr != NULL; sourcePtr = sourcePtr->nextPtr) { if (sourcePtr->checkProc) { (sourcePtr->checkProc)(sourcePtr->clientData, flags); } } /* * Check for events queued by the notifier or event sources. */ if (Tcl_ServiceEvent(flags)) { result = 1; break; } /* * We've tried everything at this point, but nobody we know * about had anything to do. Check for idle events. If none, * either quit or go back to the top and try again. */ idleEvents: if (flags & TCL_IDLE_EVENTS) { if (TclServiceIdle()) { result = 1; break; } } if (flags & TCL_DONT_WAIT) { break; } /* * If Tcl_WaitForEvent has returned 1, * indicating that one system event has been dispatched * (and thus that some Tcl code might have been indirectly executed), * we break out of the loop. * We do this to give VwaitCmd for instance a chance to check * if that system event had the side effect of changing the * variable (so the vwait can return and unwind properly). * * NB: We will process idle events if any first, because * otherwise we might never do the idle events if the notifier * always gets system events. */ if (result) { break; } } tsdPtr->serviceMode = oldMode; return result; } /* *---------------------------------------------------------------------- * * Tcl_ServiceAll -- * * This routine checks all of the event sources, processes * events that are on the Tcl event queue, and then calls the * any idle handlers. Platform specific notifier callbacks that * generate events should call this routine before returning to * the system in order to ensure that Tcl gets a chance to * process the new events. * * Results: * Returns 1 if an event or idle handler was invoked, else 0. * * Side effects: * Anything that an event or idle handler may do. * *---------------------------------------------------------------------- */ int Tcl_ServiceAll() { int result = 0; EventSource *sourcePtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (tsdPtr->serviceMode == TCL_SERVICE_NONE) { return result; } /* * We need to turn off event servicing like we to in Tcl_DoOneEvent, * to avoid recursive calls. */ tsdPtr->serviceMode = TCL_SERVICE_NONE; /* * Check async handlers first. */ if (Tcl_AsyncReady()) { (void) Tcl_AsyncInvoke((Tcl_Interp *) NULL, 0); } /* * Make a single pass through all event sources, queued events, * and idle handlers. Note that we wait to update the notifier * timer until the end so we can avoid multiple changes. */ tsdPtr->inTraversal = 1; tsdPtr->blockTimeSet = 0; for (sourcePtr = tsdPtr->firstEventSourcePtr; sourcePtr != NULL; sourcePtr = sourcePtr->nextPtr) { if (sourcePtr->setupProc) { (sourcePtr->setupProc)(sourcePtr->clientData, TCL_ALL_EVENTS); } } for (sourcePtr = tsdPtr->firstEventSourcePtr; sourcePtr != NULL; sourcePtr = sourcePtr->nextPtr) { if (sourcePtr->checkProc) { (sourcePtr->checkProc)(sourcePtr->clientData, TCL_ALL_EVENTS); } } while (Tcl_ServiceEvent(0)) { result = 1; } if (TclServiceIdle()) { result = 1; } if (!tsdPtr->blockTimeSet) { Tcl_SetTimer(NULL); } else { Tcl_SetTimer(&tsdPtr->blockTime); } tsdPtr->inTraversal = 0; tsdPtr->serviceMode = TCL_SERVICE_ALL; return result; } /* *---------------------------------------------------------------------- * * Tcl_ThreadAlert -- * * This function wakes up the notifier associated with the * specified thread (if there is one). * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Tcl_ThreadAlert(threadId) Tcl_ThreadId threadId; /* Identifier for thread to use. */ { ThreadSpecificData *tsdPtr; /* * Find the notifier associated with the specified thread. * Note that we need to hold the listLock while calling * Tcl_AlertNotifier to avoid a race condition where * the specified thread might destroy its notifier. */ Tcl_MutexLock(&listLock); for (tsdPtr = firstNotifierPtr; tsdPtr; tsdPtr = tsdPtr->nextPtr) { if (tsdPtr->threadId == threadId) { if (tclStubs.tcl_AlertNotifier) { tclStubs.tcl_AlertNotifier(tsdPtr->clientData); } break; } } Tcl_MutexUnlock(&listLock); } tcl8.4.20/generic/regcustom.h0000644003604700454610000001015611737050674014517 0ustar dgp771div/* * Copyright (c) 1998, 1999 Henry Spencer. All rights reserved. * * Development of this software was funded, in part, by Cray Research Inc., * UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics * Corporation, none of whom are responsible for the results. The author * thanks all of them. * * Redistribution and use in source and binary forms -- with or without * modification -- are permitted for any purpose, provided that * redistributions in source form retain this entire copyright notice and * indicate the origin and nature of any modifications. * * I'd appreciate being given credit for this package in the documentation * of software which uses it, but that is not a requirement. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * HENRY SPENCER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* headers if any */ #include "tclInt.h" /* overrides for regguts.h definitions, if any */ #define FUNCPTR(name, args) (*name) _ANSI_ARGS_(args) #define MALLOC(n) ckalloc(n) #define FREE(p) ckfree(VS(p)) #define REALLOC(p,n) ckrealloc(VS(p),n) /* * Do not insert extras between the "begin" and "end" lines -- this * chunk is automatically extracted to be fitted into regex.h. */ /* --- begin --- */ /* ensure certain things don't sneak in from system headers */ #ifdef __REG_WIDE_T #undef __REG_WIDE_T #endif #ifdef __REG_WIDE_COMPILE #undef __REG_WIDE_COMPILE #endif #ifdef __REG_WIDE_EXEC #undef __REG_WIDE_EXEC #endif #ifdef __REG_REGOFF_T #undef __REG_REGOFF_T #endif #ifdef __REG_VOID_T #undef __REG_VOID_T #endif #ifdef __REG_CONST #undef __REG_CONST #endif #ifdef __REG_NOFRONT #undef __REG_NOFRONT #endif #ifdef __REG_NOCHAR #undef __REG_NOCHAR #endif /* interface types */ #define __REG_WIDE_T Tcl_UniChar #define __REG_REGOFF_T long /* not really right, but good enough... */ #define __REG_VOID_T VOID #define __REG_CONST CONST /* names and declarations */ #define __REG_WIDE_COMPILE TclReComp #define __REG_WIDE_EXEC TclReExec #define __REG_NOFRONT /* don't want regcomp() and regexec() */ #define __REG_NOCHAR /* or the char versions */ #define regfree TclReFree #define regerror TclReError /* --- end --- */ /* internal character type and related */ typedef Tcl_UniChar chr; /* the type itself */ typedef int pchr; /* what it promotes to */ typedef unsigned uchr; /* unsigned type that will hold a chr */ typedef int celt; /* type to hold chr, MCCE number, or NOCELT */ #define NOCELT (-1) /* celt value which is not valid chr or MCCE */ #define CHR(c) (UCHAR(c)) /* turn char literal into chr literal */ #define DIGITVAL(c) ((c)-'0') /* turn chr digit into its value */ #if TCL_UTF_MAX > 4 #define CHRBITS 32 /* bits in a chr; must not use sizeof */ #define CHR_MIN 0x00000000 /* smallest and largest chr; the value */ #define CHR_MAX 0xffffffff /* CHR_MAX-CHR_MIN+1 should fit in uchr */ #else #define CHRBITS 16 /* bits in a chr; must not use sizeof */ #define CHR_MIN 0x0000 /* smallest and largest chr; the value */ #define CHR_MAX 0xffff /* CHR_MAX-CHR_MIN+1 should fit in uchr */ #endif /* functions operating on chr */ #define iscalnum(x) Tcl_UniCharIsAlnum(x) #define iscalpha(x) Tcl_UniCharIsAlpha(x) #define iscdigit(x) Tcl_UniCharIsDigit(x) #define iscspace(x) Tcl_UniCharIsSpace(x) /* name the external functions */ #define compile TclReComp #define exec TclReExec /* enable/disable debugging code (by whether REG_DEBUG is defined or not) */ #if 0 /* no debug unless requested by makefile */ #define REG_DEBUG /* */ #endif /* and pick up the standard header */ #include "regex.h" tcl8.4.20/generic/tclCkalloc.c0000644003604700454610000010131312133546537014550 0ustar dgp771div/* * tclCkalloc.c -- * * Interface to malloc and free that provides support for debugging problems * involving overwritten, double freeing memory and loss of memory. * * Copyright (c) 1991-1994 The Regents of the University of California. * Copyright (c) 1994-1997 Sun Microsystems, Inc. * Copyright (c) 1998-1999 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * This code contributed by Karl Lehenbauer and Mark Diekhans */ #include "tclInt.h" #include "tclPort.h" #define FALSE 0 #define TRUE 1 #ifdef TCL_MEM_DEBUG /* * One of the following structures is allocated each time the * "memory tag" command is invoked, to hold the current tag. */ typedef struct MemTag { int refCount; /* Number of mem_headers referencing * this tag. */ char string[4]; /* Actual size of string will be as * large as needed for actual tag. This * must be the last field in the structure. */ } MemTag; #define TAG_SIZE(bytesInString) ((unsigned) sizeof(MemTag) + bytesInString - 3) static MemTag *curTagPtr = NULL;/* Tag to use in all future mem_headers * (set by "memory tag" command). */ /* * One of the following structures is allocated just before each * dynamically allocated chunk of memory, both to record information * about the chunk and to help detect chunk under-runs. */ #define LOW_GUARD_SIZE (8 + (32 - (sizeof(long) + sizeof(int)))%8) struct mem_header { struct mem_header *flink; struct mem_header *blink; MemTag *tagPtr; /* Tag from "memory tag" command; may be * NULL. */ CONST char *file; long length; int line; unsigned char low_guard[LOW_GUARD_SIZE]; /* Aligns body on 8-byte boundary, plus * provides at least 8 additional guard bytes * to detect underruns. */ char body[1]; /* First byte of client's space. Actual * size of this field will be larger than * one. */ }; static struct mem_header *allocHead = NULL; /* List of allocated structures */ #define GUARD_VALUE 0141 /* * The following macro determines the amount of guard space *above* each * chunk of memory. */ #define HIGH_GUARD_SIZE 8 /* * The following macro computes the offset of the "body" field within * mem_header. It is used to get back to the header pointer from the * body pointer that's used by clients. */ #define BODY_OFFSET \ ((size_t) (&((struct mem_header *) 0)->body)) static int total_mallocs = 0; static int total_frees = 0; static int current_bytes_malloced = 0; static int maximum_bytes_malloced = 0; static int current_malloc_packets = 0; static int maximum_malloc_packets = 0; static int break_on_malloc = 0; static int trace_on_at_malloc = 0; static int alloc_tracing = FALSE; static int init_malloced_bodies = TRUE; #ifdef MEM_VALIDATE static int validate_memory = TRUE; #else static int validate_memory = FALSE; #endif /* * The following variable indicates to TclFinalizeMemorySubsystem() * that it should dump out the state of memory before exiting. If the * value is non-NULL, it gives the name of the file in which to * dump memory usage information. */ char *tclMemDumpFileName = NULL; static char *onExitMemDumpFileName = NULL; static char dumpFile[100]; /* Records where to dump memory allocation * information. */ /* * Mutex to serialize allocations. This is a low-level mutex that must * be explicitly initialized. This is necessary because the self * initializing mutexes use ckalloc... */ static Tcl_Mutex *ckallocMutexPtr; static int ckallocInit = 0; /* * Prototypes for procedures defined in this file: */ static int CheckmemCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int argc, CONST char *argv[])); static int MemoryCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int argc, CONST char **argv)); static void ValidateMemory _ANSI_ARGS_(( struct mem_header *memHeaderP, CONST char *file, int line, int nukeGuards)); /* *---------------------------------------------------------------------- * * TclInitDbCkalloc -- * Initialize the locks used by the allocator. * This is only appropriate to call in a single threaded environment, * such as during TclInitSubsystems. * *---------------------------------------------------------------------- */ void TclInitDbCkalloc() { if (!ckallocInit) { ckallocInit = 1; ckallocMutexPtr = Tcl_GetAllocMutex(); #ifndef TCL_THREADS /* Silence compiler warning */ (void)ckallocMutexPtr; #endif } } /* *---------------------------------------------------------------------- * * TclDumpMemoryInfo -- * Display the global memory management statistics. * *---------------------------------------------------------------------- */ void TclDumpMemoryInfo(outFile) FILE *outFile; { fprintf(outFile,"total mallocs %10d\n", total_mallocs); fprintf(outFile,"total frees %10d\n", total_frees); fprintf(outFile,"current packets allocated %10d\n", current_malloc_packets); fprintf(outFile,"current bytes allocated %10d\n", current_bytes_malloced); fprintf(outFile,"maximum packets allocated %10d\n", maximum_malloc_packets); fprintf(outFile,"maximum bytes allocated %10d\n", maximum_bytes_malloced); } /* *---------------------------------------------------------------------- * * ValidateMemory -- * * Validate memory guard zones for a particular chunk of allocated * memory. * * Results: * None. * * Side effects: * Prints validation information about the allocated memory to stderr. * *---------------------------------------------------------------------- */ static void ValidateMemory(memHeaderP, file, line, nukeGuards) struct mem_header *memHeaderP; /* Memory chunk to validate */ CONST char *file; /* File containing the call to * Tcl_ValidateAllMemory */ int line; /* Line number of call to * Tcl_ValidateAllMemory */ int nukeGuards; /* If non-zero, indicates that the * memory guards are to be reset to 0 * after they have been printed */ { unsigned char *hiPtr; int idx; int guard_failed = FALSE; int byte; for (idx = 0; idx < LOW_GUARD_SIZE; idx++) { byte = *(memHeaderP->low_guard + idx); if (byte != GUARD_VALUE) { guard_failed = TRUE; fflush(stdout); byte &= 0xff; fprintf(stderr, "low guard byte %d is 0x%x \t%c\n", idx, byte, (isprint(UCHAR(byte)) ? byte : ' ')); /* INTL: bytes */ } } if (guard_failed) { TclDumpMemoryInfo (stderr); fprintf(stderr, "low guard failed at %lx, %s %d\n", (long unsigned int) memHeaderP->body, file, line); fflush(stderr); /* In case name pointer is bad. */ fprintf(stderr, "%ld bytes allocated at (%s %d)\n", memHeaderP->length, memHeaderP->file, memHeaderP->line); panic ("Memory validation failure"); } hiPtr = (unsigned char *)memHeaderP->body + memHeaderP->length; for (idx = 0; idx < HIGH_GUARD_SIZE; idx++) { byte = *(hiPtr + idx); if (byte != GUARD_VALUE) { guard_failed = TRUE; fflush (stdout); byte &= 0xff; fprintf(stderr, "hi guard byte %d is 0x%x \t%c\n", idx, byte, (isprint(UCHAR(byte)) ? byte : ' ')); /* INTL: bytes */ } } if (guard_failed) { TclDumpMemoryInfo (stderr); fprintf(stderr, "high guard failed at %lx, %s %d\n", (long unsigned int) memHeaderP->body, file, line); fflush(stderr); /* In case name pointer is bad. */ fprintf(stderr, "%ld bytes allocated at (%s %d)\n", memHeaderP->length, memHeaderP->file, memHeaderP->line); panic("Memory validation failure"); } if (nukeGuards) { memset ((char *) memHeaderP->low_guard, 0, LOW_GUARD_SIZE); memset ((char *) hiPtr, 0, HIGH_GUARD_SIZE); } } /* *---------------------------------------------------------------------- * * Tcl_ValidateAllMemory -- * * Validate memory guard regions for all allocated memory. * * Results: * None. * * Side effects: * Displays memory validation information to stderr. * *---------------------------------------------------------------------- */ void Tcl_ValidateAllMemory (file, line) CONST char *file; /* File from which Tcl_ValidateAllMemory was called */ int line; /* Line number of call to Tcl_ValidateAllMemory */ { struct mem_header *memScanP; if (!ckallocInit) { TclInitDbCkalloc(); } Tcl_MutexLock(ckallocMutexPtr); for (memScanP = allocHead; memScanP != NULL; memScanP = memScanP->flink) { ValidateMemory(memScanP, file, line, FALSE); } Tcl_MutexUnlock(ckallocMutexPtr); } /* *---------------------------------------------------------------------- * * Tcl_DumpActiveMemory -- * * Displays all allocated memory to a file; if no filename is given, * information will be written to stderr. * * Results: * Return TCL_ERROR if an error accessing the file occurs, `errno' * will have the file error number left in it. *---------------------------------------------------------------------- */ int Tcl_DumpActiveMemory (fileName) CONST char *fileName; /* Name of the file to write info to */ { FILE *fileP; struct mem_header *memScanP; char *address; if (fileName == NULL) { fileP = stderr; } else { fileP = fopen(fileName, "w"); if (fileP == NULL) { return TCL_ERROR; } } Tcl_MutexLock(ckallocMutexPtr); for (memScanP = allocHead; memScanP != NULL; memScanP = memScanP->flink) { address = &memScanP->body [0]; fprintf(fileP, "%8lx - %8lx %7ld @ %s %d %s", (long unsigned int) address, (long unsigned int) address + memScanP->length - 1, memScanP->length, memScanP->file, memScanP->line, (memScanP->tagPtr == NULL) ? "" : memScanP->tagPtr->string); (void) fputc('\n', fileP); } Tcl_MutexUnlock(ckallocMutexPtr); if (fileP != stderr) { fclose (fileP); } return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_DbCkalloc - debugging ckalloc * * Allocate the requested amount of space plus some extra for * guard bands at both ends of the request, plus a size, panicing * if there isn't enough space, then write in the guard bands * and return the address of the space in the middle that the * user asked for. * * The second and third arguments are file and line, these contain * the filename and line number corresponding to the caller. * These are sent by the ckalloc macro; it uses the preprocessor * autodefines __FILE__ and __LINE__. * *---------------------------------------------------------------------- */ char * Tcl_DbCkalloc(size, file, line) unsigned int size; CONST char *file; int line; { struct mem_header *result = NULL; if (validate_memory) Tcl_ValidateAllMemory (file, line); /* Don't let size argument to TclpAlloc overflow */ if (size <= UINT_MAX - HIGH_GUARD_SIZE - sizeof(struct mem_header)) { result = (struct mem_header *) TclpAlloc((unsigned)size + sizeof(struct mem_header) + HIGH_GUARD_SIZE); } if (result == NULL) { fflush(stdout); TclDumpMemoryInfo(stderr); panic("unable to alloc %u bytes, %s line %d", size, file, line); } /* * Fill in guard zones and size. Also initialize the contents of * the block with bogus bytes to detect uses of initialized data. * Link into allocated list. */ if (init_malloced_bodies) { memset ((VOID *) result, GUARD_VALUE, size + sizeof(struct mem_header) + HIGH_GUARD_SIZE); } else { memset ((char *) result->low_guard, GUARD_VALUE, LOW_GUARD_SIZE); memset (result->body + size, GUARD_VALUE, HIGH_GUARD_SIZE); } if (!ckallocInit) { TclInitDbCkalloc(); } Tcl_MutexLock(ckallocMutexPtr); result->length = size; result->tagPtr = curTagPtr; if (curTagPtr != NULL) { curTagPtr->refCount++; } result->file = file; result->line = line; result->flink = allocHead; result->blink = NULL; if (allocHead != NULL) allocHead->blink = result; allocHead = result; total_mallocs++; if (trace_on_at_malloc && (total_mallocs >= trace_on_at_malloc)) { (void) fflush(stdout); fprintf(stderr, "reached malloc trace enable point (%d)\n", total_mallocs); fflush(stderr); alloc_tracing = TRUE; trace_on_at_malloc = 0; } if (alloc_tracing) fprintf(stderr,"ckalloc %lx %u %s %d\n", (long unsigned int) result->body, size, file, line); if (break_on_malloc && (total_mallocs >= break_on_malloc)) { break_on_malloc = 0; (void) fflush(stdout); fprintf(stderr,"reached malloc break limit (%d)\n", total_mallocs); fprintf(stderr, "program will now enter C debugger\n"); (void) fflush(stderr); abort(); } current_malloc_packets++; if (current_malloc_packets > maximum_malloc_packets) maximum_malloc_packets = current_malloc_packets; current_bytes_malloced += size; if (current_bytes_malloced > maximum_bytes_malloced) maximum_bytes_malloced = current_bytes_malloced; Tcl_MutexUnlock(ckallocMutexPtr); return result->body; } char * Tcl_AttemptDbCkalloc(size, file, line) unsigned int size; CONST char *file; int line; { struct mem_header *result = NULL; if (validate_memory) Tcl_ValidateAllMemory (file, line); /* Don't let size argument to TclpAlloc overflow */ if (size <= UINT_MAX - HIGH_GUARD_SIZE - sizeof(struct mem_header)) { result = (struct mem_header *) TclpAlloc((unsigned)size + sizeof(struct mem_header) + HIGH_GUARD_SIZE); } if (result == NULL) { fflush(stdout); TclDumpMemoryInfo(stderr); return NULL; } /* * Fill in guard zones and size. Also initialize the contents of * the block with bogus bytes to detect uses of initialized data. * Link into allocated list. */ if (init_malloced_bodies) { memset ((VOID *) result, GUARD_VALUE, size + sizeof(struct mem_header) + HIGH_GUARD_SIZE); } else { memset ((char *) result->low_guard, GUARD_VALUE, LOW_GUARD_SIZE); memset (result->body + size, GUARD_VALUE, HIGH_GUARD_SIZE); } if (!ckallocInit) { TclInitDbCkalloc(); } Tcl_MutexLock(ckallocMutexPtr); result->length = size; result->tagPtr = curTagPtr; if (curTagPtr != NULL) { curTagPtr->refCount++; } result->file = file; result->line = line; result->flink = allocHead; result->blink = NULL; if (allocHead != NULL) allocHead->blink = result; allocHead = result; total_mallocs++; if (trace_on_at_malloc && (total_mallocs >= trace_on_at_malloc)) { (void) fflush(stdout); fprintf(stderr, "reached malloc trace enable point (%d)\n", total_mallocs); fflush(stderr); alloc_tracing = TRUE; trace_on_at_malloc = 0; } if (alloc_tracing) fprintf(stderr,"ckalloc %lx %u %s %d\n", (long unsigned int) result->body, size, file, line); if (break_on_malloc && (total_mallocs >= break_on_malloc)) { break_on_malloc = 0; (void) fflush(stdout); fprintf(stderr,"reached malloc break limit (%d)\n", total_mallocs); fprintf(stderr, "program will now enter C debugger\n"); (void) fflush(stderr); abort(); } current_malloc_packets++; if (current_malloc_packets > maximum_malloc_packets) maximum_malloc_packets = current_malloc_packets; current_bytes_malloced += size; if (current_bytes_malloced > maximum_bytes_malloced) maximum_bytes_malloced = current_bytes_malloced; Tcl_MutexUnlock(ckallocMutexPtr); return result->body; } /* *---------------------------------------------------------------------- * * Tcl_DbCkfree - debugging ckfree * * Verify that the low and high guards are intact, and if so * then free the buffer else panic. * * The guards are erased after being checked to catch duplicate * frees. * * The second and third arguments are file and line, these contain * the filename and line number corresponding to the caller. * These are sent by the ckfree macro; it uses the preprocessor * autodefines __FILE__ and __LINE__. * *---------------------------------------------------------------------- */ void Tcl_DbCkfree(ptr, file, line) char *ptr; CONST char *file; int line; { struct mem_header *memp; if (ptr == NULL) { return; } /* * The following cast is *very* tricky. Must convert the pointer * to an integer before doing arithmetic on it, because otherwise * the arithmetic will be done differently (and incorrectly) on * word-addressed machines such as Crays (will subtract only bytes, * even though BODY_OFFSET is in words on these machines). */ memp = (struct mem_header *) (((size_t) ptr) - BODY_OFFSET); if (alloc_tracing) { fprintf(stderr, "ckfree %lx %ld %s %d\n", (long unsigned int) memp->body, memp->length, file, line); } if (validate_memory) { Tcl_ValidateAllMemory(file, line); } Tcl_MutexLock(ckallocMutexPtr); ValidateMemory(memp, file, line, TRUE); if (init_malloced_bodies) { memset((VOID *) ptr, GUARD_VALUE, (size_t) memp->length); } total_frees++; current_malloc_packets--; current_bytes_malloced -= memp->length; if (memp->tagPtr != NULL) { memp->tagPtr->refCount--; if ((memp->tagPtr->refCount == 0) && (curTagPtr != memp->tagPtr)) { TclpFree((char *) memp->tagPtr); } } /* * Delink from allocated list */ if (memp->flink != NULL) memp->flink->blink = memp->blink; if (memp->blink != NULL) memp->blink->flink = memp->flink; if (allocHead == memp) allocHead = memp->flink; TclpFree((char *) memp); Tcl_MutexUnlock(ckallocMutexPtr); } /* *-------------------------------------------------------------------- * * Tcl_DbCkrealloc - debugging ckrealloc * * Reallocate a chunk of memory by allocating a new one of the * right size, copying the old data to the new location, and then * freeing the old memory space, using all the memory checking * features of this package. * *-------------------------------------------------------------------- */ char * Tcl_DbCkrealloc(ptr, size, file, line) char *ptr; unsigned int size; CONST char *file; int line; { char *new; unsigned int copySize; struct mem_header *memp; if (ptr == NULL) { return Tcl_DbCkalloc(size, file, line); } /* * See comment from Tcl_DbCkfree before you change the following * line. */ memp = (struct mem_header *) (((size_t) ptr) - BODY_OFFSET); copySize = size; if (copySize > (unsigned int) memp->length) { copySize = memp->length; } new = Tcl_DbCkalloc(size, file, line); memcpy((VOID *) new, (VOID *) ptr, (size_t) copySize); Tcl_DbCkfree(ptr, file, line); return new; } char * Tcl_AttemptDbCkrealloc(ptr, size, file, line) char *ptr; unsigned int size; CONST char *file; int line; { char *new; unsigned int copySize; struct mem_header *memp; if (ptr == NULL) { return Tcl_AttemptDbCkalloc(size, file, line); } /* * See comment from Tcl_DbCkfree before you change the following * line. */ memp = (struct mem_header *) (((size_t) ptr) - BODY_OFFSET); copySize = size; if (copySize > (unsigned int) memp->length) { copySize = memp->length; } new = Tcl_AttemptDbCkalloc(size, file, line); if (new == NULL) { return NULL; } memcpy((VOID *) new, (VOID *) ptr, (size_t) copySize); Tcl_DbCkfree(ptr, file, line); return new; } /* *---------------------------------------------------------------------- * * Tcl_Alloc, et al. -- * * These functions are defined in terms of the debugging versions * when TCL_MEM_DEBUG is set. * * Results: * Same as the debug versions. * * Side effects: * Same as the debug versions. * *---------------------------------------------------------------------- */ #undef Tcl_Alloc #undef Tcl_Free #undef Tcl_Realloc #undef Tcl_AttemptAlloc #undef Tcl_AttemptRealloc char * Tcl_Alloc(size) unsigned int size; { return Tcl_DbCkalloc(size, "unknown", 0); } char * Tcl_AttemptAlloc(size) unsigned int size; { return Tcl_AttemptDbCkalloc(size, "unknown", 0); } void Tcl_Free(ptr) char *ptr; { Tcl_DbCkfree(ptr, "unknown", 0); } char * Tcl_Realloc(ptr, size) char *ptr; unsigned int size; { return Tcl_DbCkrealloc(ptr, size, "unknown", 0); } char * Tcl_AttemptRealloc(ptr, size) char *ptr; unsigned int size; { return Tcl_AttemptDbCkrealloc(ptr, size, "unknown", 0); } /* *---------------------------------------------------------------------- * * MemoryCmd -- * Implements the Tcl "memory" command, which provides Tcl-level * control of Tcl memory debugging information. * memory active $file * memory break_on_malloc $count * memory info * memory init on|off * memory onexit $file * memory tag $string * memory trace on|off * memory trace_on_at_malloc $count * memory validate on|off * * Results: * Standard TCL results. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int MemoryCmd (clientData, interp, argc, argv) ClientData clientData; Tcl_Interp *interp; int argc; CONST char **argv; { CONST char *fileName; Tcl_DString buffer; int result; size_t len; if (argc < 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " option [args..]\"", (char *) NULL); return TCL_ERROR; } if ((strcmp(argv[1],"active") == 0) || (strcmp(argv[1],"display") == 0)) { if (argc != 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ", argv[1], " file\"", (char *) NULL); return TCL_ERROR; } fileName = Tcl_TranslateFileName(interp, argv[2], &buffer); if (fileName == NULL) { return TCL_ERROR; } result = Tcl_DumpActiveMemory (fileName); Tcl_DStringFree(&buffer); if (result != TCL_OK) { Tcl_AppendResult(interp, "error accessing ", argv[2], (char *) NULL); return TCL_ERROR; } return TCL_OK; } if (strcmp(argv[1],"break_on_malloc") == 0) { if (argc != 3) { goto argError; } if (Tcl_GetInt(interp, argv[2], &break_on_malloc) != TCL_OK) { return TCL_ERROR; } return TCL_OK; } if (strcmp(argv[1],"info") == 0) { char buf[400]; sprintf(buf, "%-25s %10d\n%-25s %10d\n%-25s %10d\n%-25s %10d\n%-25s %10d\n%-25s %10d\n", "total mallocs", total_mallocs, "total frees", total_frees, "current packets allocated", current_malloc_packets, "current bytes allocated", current_bytes_malloced, "maximum packets allocated", maximum_malloc_packets, "maximum bytes allocated", maximum_bytes_malloced); Tcl_SetResult(interp, buf, TCL_VOLATILE); return TCL_OK; } if (strcmp(argv[1],"init") == 0) { if (argc != 3) { goto bad_suboption; } init_malloced_bodies = (strcmp(argv[2],"on") == 0); return TCL_OK; } if (strcmp(argv[1],"onexit") == 0) { if (argc != 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " onexit file\"", (char *) NULL); return TCL_ERROR; } fileName = Tcl_TranslateFileName(interp, argv[2], &buffer); if (fileName == NULL) { return TCL_ERROR; } onExitMemDumpFileName = dumpFile; strcpy(onExitMemDumpFileName,fileName); Tcl_DStringFree(&buffer); return TCL_OK; } if (strcmp(argv[1],"tag") == 0) { if (argc != 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " tag string\"", (char *) NULL); return TCL_ERROR; } if ((curTagPtr != NULL) && (curTagPtr->refCount == 0)) { TclpFree((char *) curTagPtr); } len = strlen(argv[2]); curTagPtr = (MemTag *) TclpAlloc(TAG_SIZE(len)); curTagPtr->refCount = 0; memcpy(curTagPtr->string, argv[2], len + 1); return TCL_OK; } if (strcmp(argv[1],"trace") == 0) { if (argc != 3) { goto bad_suboption; } alloc_tracing = (strcmp(argv[2],"on") == 0); return TCL_OK; } if (strcmp(argv[1],"trace_on_at_malloc") == 0) { if (argc != 3) { goto argError; } if (Tcl_GetInt(interp, argv[2], &trace_on_at_malloc) != TCL_OK) { return TCL_ERROR; } return TCL_OK; } if (strcmp(argv[1],"validate") == 0) { if (argc != 3) { goto bad_suboption; } validate_memory = (strcmp(argv[2],"on") == 0); return TCL_OK; } Tcl_AppendResult(interp, "bad option \"", argv[1], "\": should be active, break_on_malloc, info, init, onexit, ", "tag, trace, trace_on_at_malloc, or validate", (char *) NULL); return TCL_ERROR; argError: Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ", argv[1], " count\"", (char *) NULL); return TCL_ERROR; bad_suboption: Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ", argv[1], " on|off\"", (char *) NULL); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * CheckmemCmd -- * * This is the command procedure for the "checkmem" command, which * causes the application to exit after printing information about * memory usage to the file passed to this command as its first * argument. * * Results: * Returns a standard Tcl completion code. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int CheckmemCmd(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter for evaluation. */ int argc; /* Number of arguments. */ CONST char *argv[]; /* String values of arguments. */ { if (argc != 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " fileName\"", (char *) NULL); return TCL_ERROR; } tclMemDumpFileName = dumpFile; strcpy(tclMemDumpFileName, argv[1]); return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_InitMemory -- * * Create the "memory" and "checkmem" commands in the given * interpreter. * * Results: * None. * * Side effects: * New commands are added to the interpreter. * *---------------------------------------------------------------------- */ void Tcl_InitMemory(interp) Tcl_Interp *interp; /* Interpreter in which commands should be added */ { TclInitDbCkalloc(); Tcl_CreateCommand (interp, "memory", MemoryCmd, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "checkmem", CheckmemCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); } #else /* TCL_MEM_DEBUG */ /* This is the !TCL_MEM_DEBUG case */ #undef Tcl_InitMemory #undef Tcl_DumpActiveMemory #undef Tcl_ValidateAllMemory /* *---------------------------------------------------------------------- * * Tcl_Alloc -- * Interface to TclpAlloc when TCL_MEM_DEBUG is disabled. It does check * that memory was actually allocated. * *---------------------------------------------------------------------- */ char * Tcl_Alloc (size) unsigned int size; { char *result; result = TclpAlloc(size); /* * Most systems will not alloc(0), instead bumping it to one so * that NULL isn't returned. Some systems (AIX, Tru64) will alloc(0) * by returning NULL, so we have to check that the NULL we get is * not in response to alloc(0). * * The ANSI spec actually says that systems either return NULL *or* * a special pointer on failure, but we only check for NULL */ if ((result == NULL) && size) { panic("unable to alloc %u bytes", size); } return result; } char * Tcl_DbCkalloc(size, file, line) unsigned int size; CONST char *file; int line; { char *result; result = (char *) TclpAlloc(size); if ((result == NULL) && size) { fflush(stdout); panic("unable to alloc %u bytes, %s line %d", size, file, line); } return result; } /* *---------------------------------------------------------------------- * * Tcl_AttemptAlloc -- * Interface to TclpAlloc when TCL_MEM_DEBUG is disabled. It does not * check that memory was actually allocated. * *---------------------------------------------------------------------- */ char * Tcl_AttemptAlloc (size) unsigned int size; { char *result; result = TclpAlloc(size); return result; } char * Tcl_AttemptDbCkalloc(size, file, line) unsigned int size; CONST char *file; int line; { char *result; result = (char *) TclpAlloc(size); return result; } /* *---------------------------------------------------------------------- * * Tcl_Realloc -- * Interface to TclpRealloc when TCL_MEM_DEBUG is disabled. It does * check that memory was actually allocated. * *---------------------------------------------------------------------- */ char * Tcl_Realloc(ptr, size) char *ptr; unsigned int size; { char *result; result = TclpRealloc(ptr, size); if ((result == NULL) && size) { panic("unable to realloc %u bytes", size); } return result; } char * Tcl_DbCkrealloc(ptr, size, file, line) char *ptr; unsigned int size; CONST char *file; int line; { char *result; result = (char *) TclpRealloc(ptr, size); if ((result == NULL) && size) { fflush(stdout); panic("unable to realloc %u bytes, %s line %d", size, file, line); } return result; } /* *---------------------------------------------------------------------- * * Tcl_AttemptRealloc -- * Interface to TclpRealloc when TCL_MEM_DEBUG is disabled. It does * not check that memory was actually allocated. * *---------------------------------------------------------------------- */ char * Tcl_AttemptRealloc(ptr, size) char *ptr; unsigned int size; { char *result; result = TclpRealloc(ptr, size); return result; } char * Tcl_AttemptDbCkrealloc(ptr, size, file, line) char *ptr; unsigned int size; CONST char *file; int line; { char *result; result = (char *) TclpRealloc(ptr, size); return result; } /* *---------------------------------------------------------------------- * * Tcl_Free -- * Interface to TclpFree when TCL_MEM_DEBUG is disabled. Done here * rather in the macro to keep some modules from being compiled with * TCL_MEM_DEBUG enabled and some with it disabled. * *---------------------------------------------------------------------- */ void Tcl_Free (ptr) char *ptr; { TclpFree(ptr); } void Tcl_DbCkfree(ptr, file, line) char *ptr; CONST char *file; int line; { TclpFree(ptr); } /* *---------------------------------------------------------------------- * * Tcl_InitMemory -- * Dummy initialization for memory command, which is only available * if TCL_MEM_DEBUG is on. * *---------------------------------------------------------------------- */ /* ARGSUSED */ void Tcl_InitMemory(interp) Tcl_Interp *interp; { } int Tcl_DumpActiveMemory(fileName) CONST char *fileName; { return TCL_OK; } void Tcl_ValidateAllMemory(file, line) CONST char *file; int line; { } void TclDumpMemoryInfo(outFile) FILE *outFile; { } #endif /* TCL_MEM_DEBUG */ /* *--------------------------------------------------------------------------- * * TclFinalizeMemorySubsystem -- * * This procedure is called to finalize all the structures that * are used by the memory allocator on a per-process basis. * * Results: * None. * * Side effects: * This subsystem is self-initializing, since memory can be * allocated before Tcl is formally initialized. After this call, * this subsystem has been reset to its initial state and is * usable again. * *--------------------------------------------------------------------------- */ void TclFinalizeMemorySubsystem() { #ifdef TCL_MEM_DEBUG if (tclMemDumpFileName != NULL) { Tcl_DumpActiveMemory(tclMemDumpFileName); } else if (onExitMemDumpFileName != NULL) { Tcl_DumpActiveMemory(onExitMemDumpFileName); } Tcl_MutexLock(ckallocMutexPtr); if (curTagPtr != NULL) { TclpFree((char *) curTagPtr); curTagPtr = NULL; } allocHead = NULL; Tcl_MutexUnlock(ckallocMutexPtr); #endif #if USE_TCLALLOC TclFinalizeAllocSubsystem(); #endif } tcl8.4.20/generic/tclListObj.c0000644003604700454610000014140312133546540014544 0ustar dgp771div/* * tclListObj.c -- * * This file contains procedures that implement the Tcl list object * type. * * Copyright (c) 1995-1997 Sun Microsystems, Inc. * Copyright (c) 1998 by Scriptics Corporation. * Copyright (c) 2001 by Kevin B. Kenny. All rights reserved. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" /* * Prototypes for procedures defined later in this file: */ static void DupListInternalRep _ANSI_ARGS_((Tcl_Obj *srcPtr, Tcl_Obj *copyPtr)); static void FreeListInternalRep _ANSI_ARGS_((Tcl_Obj *listPtr)); static int SetListFromAny _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr)); static void UpdateStringOfList _ANSI_ARGS_((Tcl_Obj *listPtr)); /* * The structure below defines the list Tcl object type by means of * procedures that can be invoked by generic object code. * * The internal representation of a list object is a two-pointer * representation. The first pointer designates a List structure that * contains an array of pointers to the element objects, together with * integers that represent the current element count and the allocated * size of the array. The second pointer is normally NULL; during * execution of functions in this file that operate on nested sublists, * it is occasionally used as working storage to avoid an auxiliary * stack. */ Tcl_ObjType tclListType = { "list", /* name */ FreeListInternalRep, /* freeIntRepProc */ DupListInternalRep, /* dupIntRepProc */ UpdateStringOfList, /* updateStringProc */ SetListFromAny /* setFromAnyProc */ }; /* *---------------------------------------------------------------------- * * Tcl_NewListObj -- * * This procedure is normally called when not debugging: i.e., when * TCL_MEM_DEBUG is not defined. It creates a new list object from an * (objc,objv) array: that is, each of the objc elements of the array * referenced by objv is inserted as an element into a new Tcl object. * * When TCL_MEM_DEBUG is defined, this procedure just returns the * result of calling the debugging version Tcl_DbNewListObj. * * Results: * A new list object is returned that is initialized from the object * pointers in objv. If objc is less than or equal to zero, an empty * object is returned. The new object's string representation * is left NULL. The resulting new list object has ref count 0. * * Side effects: * The ref counts of the elements in objv are incremented since the * resulting list now refers to them. * *---------------------------------------------------------------------- */ #ifdef TCL_MEM_DEBUG #undef Tcl_NewListObj Tcl_Obj * Tcl_NewListObj(objc, objv) int objc; /* Count of objects referenced by objv. */ Tcl_Obj *CONST objv[]; /* An array of pointers to Tcl objects. */ { return Tcl_DbNewListObj(objc, objv, "unknown", 0); } #else /* if not TCL_MEM_DEBUG */ Tcl_Obj * Tcl_NewListObj(objc, objv) int objc; /* Count of objects referenced by objv. */ Tcl_Obj *CONST objv[]; /* An array of pointers to Tcl objects. */ { register Tcl_Obj *listPtr; register Tcl_Obj **elemPtrs; register List *listRepPtr; int i; TclNewObj(listPtr); if (objc > 0) { Tcl_InvalidateStringRep(listPtr); elemPtrs = (Tcl_Obj **) ckalloc((unsigned) (objc * sizeof(Tcl_Obj *))); for (i = 0; i < objc; i++) { elemPtrs[i] = objv[i]; Tcl_IncrRefCount(elemPtrs[i]); } listRepPtr = (List *) ckalloc(sizeof(List)); listRepPtr->maxElemCount = objc; listRepPtr->elemCount = objc; listRepPtr->elements = elemPtrs; listPtr->internalRep.twoPtrValue.ptr1 = (VOID *) listRepPtr; listPtr->internalRep.twoPtrValue.ptr2 = NULL; listPtr->typePtr = &tclListType; } return listPtr; } #endif /* if TCL_MEM_DEBUG */ /* *---------------------------------------------------------------------- * * Tcl_DbNewListObj -- * * This procedure is normally called when debugging: i.e., when * TCL_MEM_DEBUG is defined. It creates new list objects. It is the * same as the Tcl_NewListObj procedure above except that it calls * Tcl_DbCkalloc directly with the file name and line number from its * caller. This simplifies debugging since then the [memory active] * command will report the correct file name and line number when * reporting objects that haven't been freed. * * When TCL_MEM_DEBUG is not defined, this procedure just returns the * result of calling Tcl_NewListObj. * * Results: * A new list object is returned that is initialized from the object * pointers in objv. If objc is less than or equal to zero, an empty * object is returned. The new object's string representation * is left NULL. The new list object has ref count 0. * * Side effects: * The ref counts of the elements in objv are incremented since the * resulting list now refers to them. * *---------------------------------------------------------------------- */ #ifdef TCL_MEM_DEBUG Tcl_Obj * Tcl_DbNewListObj(objc, objv, file, line) int objc; /* Count of objects referenced by objv. */ Tcl_Obj *CONST objv[]; /* An array of pointers to Tcl objects. */ CONST char *file; /* The name of the source file calling this * procedure; used for debugging. */ int line; /* Line number in the source file; used * for debugging. */ { register Tcl_Obj *listPtr; register Tcl_Obj **elemPtrs; register List *listRepPtr; int i; TclDbNewObj(listPtr, file, line); if (objc > 0) { Tcl_InvalidateStringRep(listPtr); elemPtrs = (Tcl_Obj **) ckalloc((unsigned) (objc * sizeof(Tcl_Obj *))); for (i = 0; i < objc; i++) { elemPtrs[i] = objv[i]; Tcl_IncrRefCount(elemPtrs[i]); } listRepPtr = (List *) ckalloc(sizeof(List)); listRepPtr->maxElemCount = objc; listRepPtr->elemCount = objc; listRepPtr->elements = elemPtrs; listPtr->internalRep.twoPtrValue.ptr1 = (VOID *) listRepPtr; listPtr->internalRep.twoPtrValue.ptr2 = NULL; listPtr->typePtr = &tclListType; } return listPtr; } #else /* if not TCL_MEM_DEBUG */ Tcl_Obj * Tcl_DbNewListObj(objc, objv, file, line) int objc; /* Count of objects referenced by objv. */ Tcl_Obj *CONST objv[]; /* An array of pointers to Tcl objects. */ CONST char *file; /* The name of the source file calling this * procedure; used for debugging. */ int line; /* Line number in the source file; used * for debugging. */ { return Tcl_NewListObj(objc, objv); } #endif /* TCL_MEM_DEBUG */ /* *---------------------------------------------------------------------- * * Tcl_SetListObj -- * * Modify an object to be a list containing each of the objc elements * of the object array referenced by objv. * * Results: * None. * * Side effects: * The object is made a list object and is initialized from the object * pointers in objv. If objc is less than or equal to zero, an empty * object is returned. The new object's string representation * is left NULL. The ref counts of the elements in objv are incremented * since the list now refers to them. The object's old string and * internal representations are freed and its type is set NULL. * *---------------------------------------------------------------------- */ void Tcl_SetListObj(objPtr, objc, objv) Tcl_Obj *objPtr; /* Object whose internal rep to init. */ int objc; /* Count of objects referenced by objv. */ Tcl_Obj *CONST objv[]; /* An array of pointers to Tcl objects. */ { register Tcl_Obj **elemPtrs; register List *listRepPtr; Tcl_ObjType *oldTypePtr = objPtr->typePtr; int i; if (Tcl_IsShared(objPtr)) { panic("Tcl_SetListObj called with shared object"); } /* * Free any old string rep and any internal rep for the old type. */ if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) { oldTypePtr->freeIntRepProc(objPtr); } objPtr->typePtr = NULL; Tcl_InvalidateStringRep(objPtr); /* * Set the object's type to "list" and initialize the internal rep. * However, if there are no elements to put in the list, just give * the object an empty string rep and a NULL type. */ if (objc > 0) { elemPtrs = (Tcl_Obj **) ckalloc((unsigned) (objc * sizeof(Tcl_Obj *))); for (i = 0; i < objc; i++) { elemPtrs[i] = objv[i]; Tcl_IncrRefCount(elemPtrs[i]); } listRepPtr = (List *) ckalloc(sizeof(List)); listRepPtr->maxElemCount = objc; listRepPtr->elemCount = objc; listRepPtr->elements = elemPtrs; objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) listRepPtr; objPtr->internalRep.twoPtrValue.ptr2 = NULL; objPtr->typePtr = &tclListType; } else { objPtr->bytes = tclEmptyStringRep; objPtr->length = 0; } } /* *---------------------------------------------------------------------- * * Tcl_ListObjGetElements -- * * This procedure returns an (objc,objv) array of the elements in a * list object. * * Results: * The return value is normally TCL_OK; in this case *objcPtr is set to * the count of list elements and *objvPtr is set to a pointer to an * array of (*objcPtr) pointers to each list element. If listPtr does * not refer to a list object and the object can not be converted to * one, TCL_ERROR is returned and an error message will be left in * the interpreter's result if interp is not NULL. * * The objects referenced by the returned array should be treated as * readonly and their ref counts are _not_ incremented; the caller must * do that if it holds on to a reference. Furthermore, the pointer * and length returned by this procedure may change as soon as any * procedure is called on the list object; be careful about retaining * the pointer in a local data structure. * * Side effects: * The possible conversion of the object referenced by listPtr * to a list object. * *---------------------------------------------------------------------- */ int Tcl_ListObjGetElements(interp, listPtr, objcPtr, objvPtr) Tcl_Interp *interp; /* Used to report errors if not NULL. */ register Tcl_Obj *listPtr; /* List object for which an element array * is to be returned. */ int *objcPtr; /* Where to store the count of objects * referenced by objv. */ Tcl_Obj ***objvPtr; /* Where to store the pointer to an array * of pointers to the list's objects. */ { register List *listRepPtr; if (listPtr->typePtr != &tclListType) { int result = SetListFromAny(interp, listPtr); if (result != TCL_OK) { return result; } } listRepPtr = (List *) listPtr->internalRep.twoPtrValue.ptr1; *objcPtr = listRepPtr->elemCount; *objvPtr = listRepPtr->elements; return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_ListObjAppendList -- * * This procedure appends the objects in the list referenced by * elemListPtr to the list object referenced by listPtr. If listPtr is * not already a list object, an attempt will be made to convert it to * one. * * Results: * The return value is normally TCL_OK. If listPtr or elemListPtr do * not refer to list objects and they can not be converted to one, * TCL_ERROR is returned and an error message is left in * the interpreter's result if interp is not NULL. * * Side effects: * The reference counts of the elements in elemListPtr are incremented * since the list now refers to them. listPtr and elemListPtr are * converted, if necessary, to list objects. Also, appending the * new elements may cause listObj's array of element pointers to grow. * listPtr's old string representation, if any, is invalidated. * *---------------------------------------------------------------------- */ int Tcl_ListObjAppendList(interp, listPtr, elemListPtr) Tcl_Interp *interp; /* Used to report errors if not NULL. */ register Tcl_Obj *listPtr; /* List object to append elements to. */ Tcl_Obj *elemListPtr; /* List obj with elements to append. */ { register List *listRepPtr; int listLen, objc, result; Tcl_Obj **objv; if (Tcl_IsShared(listPtr)) { panic("Tcl_ListObjAppendList called with shared object"); } if (listPtr->typePtr != &tclListType) { result = SetListFromAny(interp, listPtr); if (result != TCL_OK) { return result; } } listRepPtr = (List *) listPtr->internalRep.twoPtrValue.ptr1; listLen = listRepPtr->elemCount; result = Tcl_ListObjGetElements(interp, elemListPtr, &objc, &objv); if (result != TCL_OK) { return result; } /* * Insert objc new elements starting after the lists's last element. * Delete zero existing elements. */ return Tcl_ListObjReplace(interp, listPtr, listLen, 0, objc, objv); } /* *---------------------------------------------------------------------- * * Tcl_ListObjAppendElement -- * * This procedure is a special purpose version of * Tcl_ListObjAppendList: it appends a single object referenced by * objPtr to the list object referenced by listPtr. If listPtr is not * already a list object, an attempt will be made to convert it to one. * * Results: * The return value is normally TCL_OK; in this case objPtr is added * to the end of listPtr's list. If listPtr does not refer to a list * object and the object can not be converted to one, TCL_ERROR is * returned and an error message will be left in the interpreter's * result if interp is not NULL. * * Side effects: * The ref count of objPtr is incremented since the list now refers * to it. listPtr will be converted, if necessary, to a list object. * Also, appending the new element may cause listObj's array of element * pointers to grow. listPtr's old string representation, if any, * is invalidated. * *---------------------------------------------------------------------- */ int Tcl_ListObjAppendElement(interp, listPtr, objPtr) Tcl_Interp *interp; /* Used to report errors if not NULL. */ Tcl_Obj *listPtr; /* List object to append objPtr to. */ Tcl_Obj *objPtr; /* Object to append to listPtr's list. */ { register List *listRepPtr; register Tcl_Obj **elemPtrs; int numElems, numRequired; if (Tcl_IsShared(listPtr)) { panic("Tcl_ListObjAppendElement called with shared object"); } if (listPtr->typePtr != &tclListType) { int result = SetListFromAny(interp, listPtr); if (result != TCL_OK) { return result; } } listRepPtr = (List *) listPtr->internalRep.twoPtrValue.ptr1; elemPtrs = listRepPtr->elements; numElems = listRepPtr->elemCount; numRequired = numElems + 1 ; /* * If there is no room in the current array of element pointers, * allocate a new, larger array and copy the pointers to it. */ if (numRequired > listRepPtr->maxElemCount) { int newMax = (2 * numRequired); Tcl_Obj **newElemPtrs = (Tcl_Obj **) ckalloc((unsigned) (newMax * sizeof(Tcl_Obj *))); memcpy((VOID *) newElemPtrs, (VOID *) elemPtrs, (size_t) (numElems * sizeof(Tcl_Obj *))); listRepPtr->maxElemCount = newMax; listRepPtr->elements = newElemPtrs; ckfree((char *) elemPtrs); elemPtrs = newElemPtrs; } /* * Add objPtr to the end of listPtr's array of element * pointers. Increment the ref count for the (now shared) objPtr. */ elemPtrs[numElems] = objPtr; Tcl_IncrRefCount(objPtr); listRepPtr->elemCount++; /* * Invalidate any old string representation since the list's internal * representation has changed. */ Tcl_InvalidateStringRep(listPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_ListObjIndex -- * * This procedure returns a pointer to the index'th object from the * list referenced by listPtr. The first element has index 0. If index * is negative or greater than or equal to the number of elements in * the list, a NULL is returned. If listPtr is not a list object, an * attempt will be made to convert it to a list. * * Results: * The return value is normally TCL_OK; in this case objPtrPtr is set * to the Tcl_Obj pointer for the index'th list element or NULL if * index is out of range. This object should be treated as readonly and * its ref count is _not_ incremented; the caller must do that if it * holds on to the reference. If listPtr does not refer to a list and * can't be converted to one, TCL_ERROR is returned and an error * message is left in the interpreter's result if interp is not NULL. * * Side effects: * listPtr will be converted, if necessary, to a list object. * *---------------------------------------------------------------------- */ int Tcl_ListObjIndex(interp, listPtr, index, objPtrPtr) Tcl_Interp *interp; /* Used to report errors if not NULL. */ register Tcl_Obj *listPtr; /* List object to index into. */ register int index; /* Index of element to return. */ Tcl_Obj **objPtrPtr; /* The resulting Tcl_Obj* is stored here. */ { register List *listRepPtr; if (listPtr->typePtr != &tclListType) { int result = SetListFromAny(interp, listPtr); if (result != TCL_OK) { return result; } } listRepPtr = (List *) listPtr->internalRep.twoPtrValue.ptr1; if ((index < 0) || (index >= listRepPtr->elemCount)) { *objPtrPtr = NULL; } else { *objPtrPtr = listRepPtr->elements[index]; } return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_ListObjLength -- * * This procedure returns the number of elements in a list object. If * the object is not already a list object, an attempt will be made to * convert it to one. * * Results: * The return value is normally TCL_OK; in this case *intPtr will be * set to the integer count of list elements. If listPtr does not refer * to a list object and the object can not be converted to one, * TCL_ERROR is returned and an error message will be left in * the interpreter's result if interp is not NULL. * * Side effects: * The possible conversion of the argument object to a list object. * *---------------------------------------------------------------------- */ int Tcl_ListObjLength(interp, listPtr, intPtr) Tcl_Interp *interp; /* Used to report errors if not NULL. */ register Tcl_Obj *listPtr; /* List object whose #elements to return. */ register int *intPtr; /* The resulting int is stored here. */ { register List *listRepPtr; if (listPtr->typePtr != &tclListType) { int result = SetListFromAny(interp, listPtr); if (result != TCL_OK) { return result; } } listRepPtr = (List *) listPtr->internalRep.twoPtrValue.ptr1; *intPtr = listRepPtr->elemCount; return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_ListObjReplace -- * * This procedure replaces zero or more elements of the list referenced * by listPtr with the objects from an (objc,objv) array. * The objc elements of the array referenced by objv replace the * count elements in listPtr starting at first. * * If the argument first is zero or negative, it refers to the first * element. If first is greater than or equal to the number of elements * in the list, then no elements are deleted; the new elements are * appended to the list. Count gives the number of elements to * replace. If count is zero or negative then no elements are deleted; * the new elements are simply inserted before first. * * The argument objv refers to an array of objc pointers to the new * elements to be added to listPtr in place of those that were * deleted. If objv is NULL, no new elements are added. If listPtr is * not a list object, an attempt will be made to convert it to one. * * Results: * The return value is normally TCL_OK. If listPtr does * not refer to a list object and can not be converted to one, * TCL_ERROR is returned and an error message will be left in * the interpreter's result if interp is not NULL. * * Side effects: * The ref counts of the objc elements in objv are incremented since * the resulting list now refers to them. Similarly, the ref counts for * replaced objects are decremented. listPtr is converted, if * necessary, to a list object. listPtr's old string representation, if * any, is freed. * *---------------------------------------------------------------------- */ int Tcl_ListObjReplace(interp, listPtr, first, count, objc, objv) Tcl_Interp *interp; /* Used for error reporting if not NULL. */ Tcl_Obj *listPtr; /* List object whose elements to replace. */ int first; /* Index of first element to replace. */ int count; /* Number of elements to replace. */ int objc; /* Number of objects to insert. */ Tcl_Obj *CONST objv[]; /* An array of objc pointers to Tcl objects * to insert. */ { List *listRepPtr; register Tcl_Obj **elemPtrs, **newPtrs; Tcl_Obj *victimPtr; int numElems, numRequired, numAfterLast; int start, shift, newMax, i, j, result; if (Tcl_IsShared(listPtr)) { panic("Tcl_ListObjReplace called with shared object"); } if (listPtr->typePtr != &tclListType) { result = SetListFromAny(interp, listPtr); if (result != TCL_OK) { return result; } } listRepPtr = (List *) listPtr->internalRep.twoPtrValue.ptr1; elemPtrs = listRepPtr->elements; numElems = listRepPtr->elemCount; if (first < 0) { first = 0; } if (first >= numElems) { first = numElems; /* so we'll insert after last element */ } if (count < 0) { count = 0; } for (i = 0; i < objc; i++) { Tcl_IncrRefCount(objv[i]); } numRequired = (numElems - count + objc); if (numRequired <= listRepPtr->maxElemCount) { /* * Enough room in the current array. First "delete" count * elements starting at first. */ for (i = 0, j = first; i < count; i++, j++) { victimPtr = elemPtrs[j]; TclDecrRefCount(victimPtr); } /* * Shift the elements after the last one removed to their * new locations. */ start = (first + count); numAfterLast = (numElems - start); shift = (objc - count); /* numNewElems - numDeleted */ if ((numAfterLast > 0) && (shift != 0)) { Tcl_Obj **src, **dst; src = elemPtrs + start; dst = src + shift; memmove((VOID*) dst, (VOID*) src, (size_t) (numAfterLast * sizeof(Tcl_Obj*))); } /* * Insert the new elements into elemPtrs before "first". */ for (i = 0, j = first; i < objc; i++, j++) { elemPtrs[j] = objv[i]; } /* * Update the count of elements. */ listRepPtr->elemCount = numRequired; } else { /* * Not enough room in the current array. Allocate a larger array and * insert elements into it. */ newMax = (2 * numRequired); newPtrs = (Tcl_Obj **) ckalloc((unsigned) (newMax * sizeof(Tcl_Obj *))); /* * Copy over the elements before "first". */ if (first > 0) { memcpy((VOID *) newPtrs, (VOID *) elemPtrs, (size_t) (first * sizeof(Tcl_Obj *))); } /* * "Delete" count elements starting at first. */ for (i = 0, j = first; i < count; i++, j++) { victimPtr = elemPtrs[j]; TclDecrRefCount(victimPtr); } /* * Copy the elements after the last one removed, shifted to * their new locations. */ start = (first + count); numAfterLast = (numElems - start); if (numAfterLast > 0) { memcpy((VOID *) &(newPtrs[first + objc]), (VOID *) &(elemPtrs[start]), (size_t) (numAfterLast * sizeof(Tcl_Obj *))); } /* * Insert the new elements before "first" and update the * count of elements. */ for (i = 0, j = first; i < objc; i++, j++) { newPtrs[j] = objv[i]; } listRepPtr->elemCount = numRequired; listRepPtr->maxElemCount = newMax; listRepPtr->elements = newPtrs; ckfree((char *) elemPtrs); } /* * Invalidate and free any old string representation since it no longer * reflects the list's internal representation. */ Tcl_InvalidateStringRep(listPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * TclLsetList -- * * Core of the 'lset' command when objc == 4. Objv[2] may be * either a scalar index or a list of indices. * * Results: * Returns the new value of the list variable, or NULL if an * error occurs. * * Side effects: * Surgery is performed on the list value to produce the * result. * * On entry, the reference count of the variable value does not reflect * any references held on the stack. The first action of this function * is to determine whether the object is shared, and to duplicate it if * it is. The reference count of the duplicate is incremented. * At this point, the reference count will be 1 for either case, so that * the object will appear to be unshared. * * If an error occurs, and the object has been duplicated, the reference * count on the duplicate is decremented so that it is now 0: this dismisses * any memory that was allocated by this procedure. * * If no error occurs, the reference count of the original object is * incremented if the object has not been duplicated, and nothing is * done to a reference count of the duplicate. Now the reference count * of an unduplicated object is 2 (the returned pointer, plus the one * stored in the variable). The reference count of a duplicate object * is 1, reflecting that the returned pointer is the only active * reference. The caller is expected to store the returned value back * in the variable and decrement its reference count. (INST_STORE_* * does exactly this.) * * Tcl_LsetFlat and related functions maintain a linked list of * Tcl_Obj's whose string representations must be spoilt by threading * via 'ptr2' of the two-pointer internal representation. On entry * to Tcl_LsetList, the values of 'ptr2' are immaterial; on exit, * the 'ptr2' field of any Tcl_Obj that has been modified is set to * NULL. * *---------------------------------------------------------------------- */ Tcl_Obj* TclLsetList( interp, listPtr, indexArgPtr, valuePtr ) Tcl_Interp* interp; /* Tcl interpreter */ Tcl_Obj* listPtr; /* Pointer to the list being modified */ Tcl_Obj* indexArgPtr; /* Index or index-list arg to 'lset' */ Tcl_Obj* valuePtr; /* Value arg to 'lset' */ { int indexCount; /* Number of indices in the index list */ Tcl_Obj** indices; /* Vector of indices in the index list*/ int duplicated; /* Flag == 1 if the obj has been * duplicated, 0 otherwise */ Tcl_Obj* retValuePtr; /* Pointer to the list to be returned */ int index; /* Current index in the list - discarded */ int result; /* Status return from library calls */ Tcl_Obj* subListPtr; /* Pointer to the current sublist */ int elemCount; /* Count of elements in the current sublist */ Tcl_Obj** elemPtrs; /* Pointers to elements of current sublist */ Tcl_Obj* chainPtr; /* Pointer to the enclosing sublist * of the current sublist */ int i; /* * Determine whether the index arg designates a list or a single * index. We have to be careful about the order of the checks to * avoid repeated shimmering; see TIP #22 and #23 for details. */ if ( indexArgPtr->typePtr != &tclListType && TclGetIntForIndex( NULL, indexArgPtr, 0, &index ) == TCL_OK ) { /* * indexArgPtr designates a single index. */ return TclLsetFlat( interp, listPtr, 1, &indexArgPtr, valuePtr ); } else if ( Tcl_ListObjGetElements( NULL, indexArgPtr, &indexCount, &indices ) != TCL_OK ) { /* * indexArgPtr designates something that is neither an index nor a * well formed list. Report the error via TclLsetFlat. */ return TclLsetFlat( interp, listPtr, 1, &indexArgPtr, valuePtr ); } /* * At this point, we know that argPtr designates a well formed list, * and the 'else if' above has parsed it into indexCount and indices. * If there are no indices, simply return 'valuePtr', counting the * returned pointer as a reference. */ if ( indexCount == 0 ) { Tcl_IncrRefCount( valuePtr ); return valuePtr; } /* * Duplicate the list arg if necessary. */ if ( Tcl_IsShared( listPtr ) ) { duplicated = 1; listPtr = Tcl_DuplicateObj( listPtr ); Tcl_IncrRefCount( listPtr ); } else { duplicated = 0; } /* * It would be tempting simply to go off to TclLsetFlat to finish the * processing. Alas, it is also incorrect! The problem is that * 'indexArgPtr' may designate a sublist of 'listPtr' whose value * is to be manipulated. The fact that 'listPtr' is itself unshared * does not guarantee that no sublist is. Therefore, it's necessary * to replicate all the work here, expanding the index list on each * trip through the loop. */ /* * Anchor the linked list of Tcl_Obj's whose string reps must be * invalidated if the operation succeeds. */ retValuePtr = listPtr; chainPtr = NULL; /* * Handle each index arg by diving into the appropriate sublist */ for ( i = 0; ; ++i ) { /* * Take the sublist apart. */ result = Tcl_ListObjGetElements( interp, listPtr, &elemCount, &elemPtrs ); if ( result != TCL_OK ) { break; } listPtr->internalRep.twoPtrValue.ptr2 = (VOID *) chainPtr; /* * Reconstitute the index array */ result = Tcl_ListObjGetElements( interp, indexArgPtr, &indexCount, &indices ); if ( result != TCL_OK ) { /* * Shouldn't be able to get here, because we already * parsed the thing successfully once. */ break; } /* * Determine the index of the requested element. */ result = TclGetIntForIndex( interp, indices[ i ], (elemCount - 1), &index ); if ( result != TCL_OK ) { break; } /* * Check that the index is in range. */ if ( ( index < 0 ) || ( index >= elemCount ) ) { Tcl_SetObjResult( interp, Tcl_NewStringObj( "list index out of range", -1 ) ); result = TCL_ERROR; break; } /* * Break the loop after extracting the innermost sublist */ if ( i >= indexCount-1 ) { result = TCL_OK; break; } /* * Extract the appropriate sublist, and make sure that it is unshared. */ subListPtr = elemPtrs[ index ]; if ( Tcl_IsShared( subListPtr ) ) { subListPtr = Tcl_DuplicateObj( subListPtr ); result = TclListObjSetElement( interp, listPtr, index, subListPtr ); if ( result != TCL_OK ) { /* * We actually shouldn't be able to get here, because * we've already checked everything that TclListObjSetElement * checks. If we were to get here, it would result in leaking * subListPtr. */ break; } } /* * Chain the current sublist onto the linked list of Tcl_Obj's * whose string reps must be spoilt. */ chainPtr = listPtr; listPtr = subListPtr; } /* * Store the new element into the correct slot in the innermost sublist. */ if ( result == TCL_OK ) { result = TclListObjSetElement( interp, listPtr, index, valuePtr ); } if ( result == TCL_OK ) { listPtr->internalRep.twoPtrValue.ptr2 = (VOID *) chainPtr; /* Spoil all the string reps */ while ( listPtr != NULL ) { subListPtr = (Tcl_Obj *) listPtr->internalRep.twoPtrValue.ptr2; Tcl_InvalidateStringRep( listPtr ); listPtr->internalRep.twoPtrValue.ptr2 = NULL; listPtr = subListPtr; } /* Return the new list if everything worked. */ if ( !duplicated ) { Tcl_IncrRefCount( retValuePtr ); } return retValuePtr; } /* Clean up the one dangling reference otherwise */ if ( duplicated ) { Tcl_DecrRefCount( retValuePtr ); } return NULL; } /* *---------------------------------------------------------------------- * * TclLsetFlat -- * * Core of the 'lset' command when objc>=5. Objv[2], ... , * objv[objc-2] contain scalar indices. * * Results: * Returns the new value of the list variable, or NULL if an * error occurs. * * Side effects: * Surgery is performed on the list value to produce the * result. * * On entry, the reference count of the variable value does not reflect * any references held on the stack. The first action of this function * is to determine whether the object is shared, and to duplicate it if * it is. The reference count of the duplicate is incremented. * At this point, the reference count will be 1 for either case, so that * the object will appear to be unshared. * * If an error occurs, and the object has been duplicated, the reference * count on the duplicate is decremented so that it is now 0: this dismisses * any memory that was allocated by this procedure. * * If no error occurs, the reference count of the original object is * incremented if the object has not been duplicated, and nothing is * done to a reference count of the duplicate. Now the reference count * of an unduplicated object is 2 (the returned pointer, plus the one * stored in the variable). The reference count of a duplicate object * is 1, reflecting that the returned pointer is the only active * reference. The caller is expected to store the returned value back * in the variable and decrement its reference count. (INST_STORE_* * does exactly this.) * * Tcl_LsetList and related functions maintain a linked list of * Tcl_Obj's whose string representations must be spoilt by threading * via 'ptr2' of the two-pointer internal representation. On entry * to Tcl_LsetList, the values of 'ptr2' are immaterial; on exit, * the 'ptr2' field of any Tcl_Obj that has been modified is set to * NULL. * *---------------------------------------------------------------------- */ Tcl_Obj* TclLsetFlat( interp, listPtr, indexCount, indexArray, valuePtr ) Tcl_Interp* interp; /* Tcl interpreter */ Tcl_Obj* listPtr; /* Pointer to the list being modified */ int indexCount; /* Number of index args */ Tcl_Obj *CONST indexArray[]; /* Index args */ Tcl_Obj* valuePtr; /* Value arg to 'lset' */ { int duplicated; /* Flag == 1 if the obj has been * duplicated, 0 otherwise */ Tcl_Obj* retValuePtr; /* Pointer to the list to be returned */ int elemCount; /* Length of one sublist being changed */ Tcl_Obj** elemPtrs; /* Pointers to the elements of a sublist */ Tcl_Obj* subListPtr; /* Pointer to the current sublist */ int index; /* Index of the element to replace in the * current sublist */ Tcl_Obj* chainPtr; /* Pointer to the enclosing list of * the current sublist. */ int result; /* Status return from library calls */ int i; /* * If there are no indices, then simply return the new value, * counting the returned pointer as a reference */ if ( indexCount == 0 ) { Tcl_IncrRefCount( valuePtr ); return valuePtr; } /* * If the list is shared, make a private copy. */ if ( Tcl_IsShared( listPtr ) ) { duplicated = 1; listPtr = Tcl_DuplicateObj( listPtr ); Tcl_IncrRefCount( listPtr ); } else { duplicated = 0; } /* * Anchor the linked list of Tcl_Obj's whose string reps must be * invalidated if the operation succeeds. */ retValuePtr = listPtr; chainPtr = NULL; /* * Handle each index arg by diving into the appropriate sublist */ for ( i = 0; ; ++i ) { /* * Take the sublist apart. */ result = Tcl_ListObjGetElements( interp, listPtr, &elemCount, &elemPtrs ); if ( result != TCL_OK ) { break; } listPtr->internalRep.twoPtrValue.ptr2 = (VOID *) chainPtr; /* * Determine the index of the requested element. */ result = TclGetIntForIndex( interp, indexArray[ i ], (elemCount - 1), &index ); if ( result != TCL_OK ) { break; } /* * Check that the index is in range. */ if ( ( index < 0 ) || ( index >= elemCount ) ) { Tcl_SetObjResult( interp, Tcl_NewStringObj( "list index out of range", -1 ) ); result = TCL_ERROR; break; } /* * Break the loop after extracting the innermost sublist */ if ( i >= indexCount-1 ) { result = TCL_OK; break; } /* * Extract the appropriate sublist, and make sure that it is unshared. */ subListPtr = elemPtrs[ index ]; if ( Tcl_IsShared( subListPtr ) ) { subListPtr = Tcl_DuplicateObj( subListPtr ); result = TclListObjSetElement( interp, listPtr, index, subListPtr ); if ( result != TCL_OK ) { /* * We actually shouldn't be able to get here. * If we do, it would result in leaking subListPtr, * but everything's been validated already; the error * exit from TclListObjSetElement should never happen. */ break; } } /* * Chain the current sublist onto the linked list of Tcl_Obj's * whose string reps must be spoilt. */ chainPtr = listPtr; listPtr = subListPtr; } /* Store the result in the list element */ if ( result == TCL_OK ) { result = TclListObjSetElement( interp, listPtr, index, valuePtr ); } if ( result == TCL_OK ) { listPtr->internalRep.twoPtrValue.ptr2 = (VOID *) chainPtr; /* Spoil all the string reps */ while ( listPtr != NULL ) { subListPtr = (Tcl_Obj *) listPtr->internalRep.twoPtrValue.ptr2; Tcl_InvalidateStringRep( listPtr ); listPtr->internalRep.twoPtrValue.ptr2 = NULL; listPtr = subListPtr; } /* Return the new list if everything worked. */ if ( !duplicated ) { Tcl_IncrRefCount( retValuePtr ); } return retValuePtr; } /* Clean up the one dangling reference otherwise */ if ( duplicated ) { Tcl_DecrRefCount( retValuePtr ); } return NULL; } /* *---------------------------------------------------------------------- * * TclListObjSetElement -- * * Set a single element of a list to a specified value * * Results: * * The return value is normally TCL_OK. If listPtr does not * refer to a list object and cannot be converted to one, TCL_ERROR * is returned and an error message will be left in the interpreter * result if interp is not NULL. Similarly, if index designates * an element outside the range [0..listLength-1], where * listLength is the count of elements in the list object designated * by listPtr, TCL_ERROR is returned and an error message is left * in the interpreter result. * * Side effects: * * Panics if listPtr designates a shared object. Otherwise, attempts * to convert it to a list. Decrements the ref count of the object * at the specified index within the list, replaces with the * object designated by valuePtr, and increments the ref count * of the replacement object. * * It is the caller's responsibility to invalidate the string * representation of the object. * *---------------------------------------------------------------------- */ int TclListObjSetElement( interp, listPtr, index, valuePtr ) Tcl_Interp* interp; /* Tcl interpreter; used for error reporting * if not NULL */ Tcl_Obj* listPtr; /* List object in which element should be * stored */ int index; /* Index of element to store */ Tcl_Obj* valuePtr; /* Tcl object to store in the designated * list element */ { int result; /* Return value from this function */ List* listRepPtr; /* Internal representation of the list * being modified */ Tcl_Obj** elemPtrs; /* Pointers to elements of the list */ int elemCount; /* Number of elements in the list */ /* Ensure that the listPtr parameter designates an unshared list */ if ( Tcl_IsShared( listPtr ) ) { panic( "Tcl_ListObjSetElement called with shared object" ); } if ( listPtr->typePtr != &tclListType ) { result = SetListFromAny( interp, listPtr ); if ( result != TCL_OK ) { return result; } } listRepPtr = (List*) listPtr->internalRep.twoPtrValue.ptr1; elemPtrs = listRepPtr->elements; elemCount = listRepPtr->elemCount; /* Ensure that the index is in bounds */ if ( index < 0 || index >= elemCount ) { if ( interp != NULL ) { Tcl_SetObjResult( interp, Tcl_NewStringObj( "list index out of range", -1 ) ); return TCL_ERROR; } } /* Add a reference to the new list element */ Tcl_IncrRefCount( valuePtr ); /* Remove a reference from the old list element */ Tcl_DecrRefCount( elemPtrs[ index ] ); /* Stash the new object in the list */ elemPtrs[ index ] = valuePtr; return TCL_OK; } /* *---------------------------------------------------------------------- * * FreeListInternalRep -- * * Deallocate the storage associated with a list object's internal * representation. * * Results: * None. * * Side effects: * Frees listPtr's List* internal representation and sets listPtr's * internalRep.twoPtrValue.ptr1 to NULL. Decrements the ref counts * of all element objects, which may free them. * *---------------------------------------------------------------------- */ static void FreeListInternalRep(listPtr) Tcl_Obj *listPtr; /* List object with internal rep to free. */ { register List *listRepPtr = (List *) listPtr->internalRep.twoPtrValue.ptr1; register Tcl_Obj **elemPtrs = listRepPtr->elements; register Tcl_Obj *objPtr; int numElems = listRepPtr->elemCount; int i; for (i = 0; i < numElems; i++) { objPtr = elemPtrs[i]; Tcl_DecrRefCount(objPtr); } ckfree((char *) elemPtrs); ckfree((char *) listRepPtr); listPtr->internalRep.twoPtrValue.ptr1 = NULL; listPtr->internalRep.twoPtrValue.ptr2 = NULL; } /* *---------------------------------------------------------------------- * * DupListInternalRep -- * * Initialize the internal representation of a list Tcl_Obj to a * copy of the internal representation of an existing list object. * * Results: * None. * * Side effects: * "srcPtr"s list internal rep pointer should not be NULL and we assume * it is not NULL. We set "copyPtr"s internal rep to a pointer to a * newly allocated List structure that, in turn, points to "srcPtr"s * element objects. Those element objects are not actually copied but * are shared between "srcPtr" and "copyPtr". The ref count of each * element object is incremented. * *---------------------------------------------------------------------- */ static void DupListInternalRep(srcPtr, copyPtr) Tcl_Obj *srcPtr; /* Object with internal rep to copy. */ Tcl_Obj *copyPtr; /* Object with internal rep to set. */ { List *srcListRepPtr = (List *) srcPtr->internalRep.twoPtrValue.ptr1; int numElems = srcListRepPtr->elemCount; int maxElems = srcListRepPtr->maxElemCount; register Tcl_Obj **srcElemPtrs = srcListRepPtr->elements; register Tcl_Obj **copyElemPtrs; register List *copyListRepPtr; int i; /* * Allocate a new List structure that points to "srcPtr"s element * objects. Increment the ref counts for those (now shared) element * objects. */ copyElemPtrs = (Tcl_Obj **) ckalloc((unsigned) maxElems * sizeof(Tcl_Obj *)); for (i = 0; i < numElems; i++) { copyElemPtrs[i] = srcElemPtrs[i]; Tcl_IncrRefCount(copyElemPtrs[i]); } copyListRepPtr = (List *) ckalloc(sizeof(List)); copyListRepPtr->maxElemCount = maxElems; copyListRepPtr->elemCount = numElems; copyListRepPtr->elements = copyElemPtrs; copyPtr->internalRep.twoPtrValue.ptr1 = (VOID *) copyListRepPtr; copyPtr->internalRep.twoPtrValue.ptr2 = NULL; copyPtr->typePtr = &tclListType; } /* *---------------------------------------------------------------------- * * SetListFromAny -- * * Attempt to generate a list internal form for the Tcl object * "objPtr". * * Results: * The return value is TCL_OK or TCL_ERROR. If an error occurs during * conversion, an error message is left in the interpreter's result * unless "interp" is NULL. * * Side effects: * If no error occurs, a list is stored as "objPtr"s internal * representation. * *---------------------------------------------------------------------- */ static int SetListFromAny(interp, objPtr) Tcl_Interp *interp; /* Used for error reporting if not NULL. */ Tcl_Obj *objPtr; /* The object to convert. */ { Tcl_ObjType *oldTypePtr = objPtr->typePtr; char *string, *s; CONST char *elemStart, *nextElem; int lenRemain, length, estCount, elemSize, hasBrace, i, j, result; char *limit; /* Points just after string's last byte. */ register CONST char *p; register Tcl_Obj **elemPtrs; register Tcl_Obj *elemPtr; List *listRepPtr; /* * Get the string representation. Make it up-to-date if necessary. */ string = Tcl_GetStringFromObj(objPtr, &length); /* * Parse the string into separate string objects, and create a List * structure that points to the element string objects. We use a * modified version of Tcl_SplitList's implementation to avoid one * malloc and a string copy for each list element. First, estimate the * number of elements by counting the number of space characters in the * list. */ limit = (string + length); estCount = 1; for (p = string; p < limit; p++) { if (isspace(UCHAR(*p))) { /* INTL: ISO space. */ estCount++; } } /* * Allocate a new List structure with enough room for "estCount" * elements. Each element is a pointer to a Tcl_Obj with the appropriate * string rep. The initial "estCount" elements are set using the * corresponding "argv" strings. */ elemPtrs = (Tcl_Obj **) ckalloc((unsigned) (estCount * sizeof(Tcl_Obj *))); for (p = string, lenRemain = length, i = 0; lenRemain > 0; p = nextElem, lenRemain = (limit - nextElem), i++) { result = TclFindElement(interp, p, lenRemain, &elemStart, &nextElem, &elemSize, &hasBrace); if (result != TCL_OK) { for (j = 0; j < i; j++) { elemPtr = elemPtrs[j]; Tcl_DecrRefCount(elemPtr); } ckfree((char *) elemPtrs); return result; } if (elemStart >= limit) { break; } if (i > estCount) { panic("SetListFromAny: bad size estimate for list"); } /* * Allocate a Tcl object for the element and initialize it from the * "elemSize" bytes starting at "elemStart". */ s = ckalloc((unsigned) elemSize + 1); if (hasBrace) { memcpy((VOID *) s, (VOID *) elemStart, (size_t) elemSize); s[elemSize] = 0; } else { elemSize = TclCopyAndCollapse(elemSize, elemStart, s); } TclNewObj(elemPtr); elemPtr->bytes = s; elemPtr->length = elemSize; elemPtrs[i] = elemPtr; Tcl_IncrRefCount(elemPtr); /* since list now holds ref to it */ } listRepPtr = (List *) ckalloc(sizeof(List)); listRepPtr->maxElemCount = estCount; listRepPtr->elemCount = i; listRepPtr->elements = elemPtrs; /* * Free the old internalRep before setting the new one. We do this as * late as possible to allow the conversion code, in particular * Tcl_GetStringFromObj, to use that old internalRep. */ if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) { oldTypePtr->freeIntRepProc(objPtr); } objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) listRepPtr; objPtr->internalRep.twoPtrValue.ptr2 = NULL; objPtr->typePtr = &tclListType; return TCL_OK; } /* *---------------------------------------------------------------------- * * UpdateStringOfList -- * * Update the string representation for a list object. * Note: This procedure does not invalidate an existing old string rep * so storage will be lost if this has not already been done. * * Results: * None. * * Side effects: * The object's string is set to a valid string that results from * the list-to-string conversion. This string will be empty if the * list has no elements. The list internal representation * should not be NULL and we assume it is not NULL. * *---------------------------------------------------------------------- */ static void UpdateStringOfList(listPtr) Tcl_Obj *listPtr; /* List object with string rep to update. */ { # define LOCAL_SIZE 20 int localFlags[LOCAL_SIZE], *flagPtr; List *listRepPtr = (List *) listPtr->internalRep.twoPtrValue.ptr1; int numElems = listRepPtr->elemCount; register int i; char *elem, *dst; int length; /* * Convert each element of the list to string form and then convert it * to proper list element form, adding it to the result buffer. */ /* * Pass 1: estimate space, gather flags. */ if (numElems <= LOCAL_SIZE) { flagPtr = localFlags; } else { flagPtr = (int *) ckalloc((unsigned) numElems*sizeof(int)); } listPtr->length = 1; for (i = 0; i < numElems; i++) { elem = Tcl_GetStringFromObj(listRepPtr->elements[i], &length); listPtr->length += Tcl_ScanCountedElement(elem, length, &flagPtr[i]) + 1; /* * Check for continued sanity. [Bug 1267380] */ if (listPtr->length < 1) { Tcl_Panic("string representation size exceeds sane bounds"); } } /* * Pass 2: copy into string rep buffer. */ listPtr->bytes = ckalloc((unsigned) listPtr->length); dst = listPtr->bytes; for (i = 0; i < numElems; i++) { elem = Tcl_GetStringFromObj(listRepPtr->elements[i], &length); dst += Tcl_ConvertCountedElement(elem, length, dst, flagPtr[i]); *dst = ' '; dst++; } if (flagPtr != localFlags) { ckfree((char *) flagPtr); } if (dst == listPtr->bytes) { *dst = 0; } else { dst--; *dst = 0; } listPtr->length = dst - listPtr->bytes; } tcl8.4.20/generic/tclParseExpr.c0000644003604700454610000015655412052456744015132 0ustar dgp771div/* * tclParseExpr.c -- * * This file contains procedures that parse Tcl expressions. They * do so in a general-purpose fashion that can be used for many * different purposes, including compilation, direct execution, * code analysis, etc. * * Copyright (c) 1997 Sun Microsystems, Inc. * Copyright (c) 1998-2000 by Scriptics Corporation. * Contributions from Don Porter, NIST, 2002. (not subject to US copyright) * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" /* * The stuff below is a bit of a hack so that this file can be used in * environments that include no UNIX, i.e. no errno: just arrange to use * the errno from tclExecute.c here. */ #ifndef TCL_GENERIC_ONLY #include "tclPort.h" #else #define NO_ERRNO_H #endif #ifdef NO_ERRNO_H extern int errno; /* Use errno from tclExecute.c. */ #define ERANGE 34 #endif /* * Boolean variable that controls whether expression parse tracing * is enabled. */ #ifdef TCL_COMPILE_DEBUG static int traceParseExpr = 0; #endif /* TCL_COMPILE_DEBUG */ /* * The ParseInfo structure holds state while parsing an expression. * A pointer to an ParseInfo record is passed among the routines in * this module. */ typedef struct ParseInfo { Tcl_Parse *parsePtr; /* Points to structure to fill in with * information about the expression. */ int lexeme; /* Type of last lexeme scanned in expr. * See below for definitions. Corresponds to * size characters beginning at start. */ CONST char *start; /* First character in lexeme. */ int size; /* Number of bytes in lexeme. */ CONST char *next; /* Position of the next character to be * scanned in the expression string. */ CONST char *prevEnd; /* Points to the character just after the * last one in the previous lexeme. Used to * compute size of subexpression tokens. */ CONST char *originalExpr; /* Points to the start of the expression * originally passed to Tcl_ParseExpr. */ CONST char *lastChar; /* Points just after last byte of expr. */ } ParseInfo; /* * Definitions of the different lexemes that appear in expressions. The * order of these must match the corresponding entries in the * operatorStrings array below. * * Basic lexemes: */ #define LITERAL 0 #define FUNC_NAME 1 #define OPEN_BRACKET 2 #define OPEN_BRACE 3 #define OPEN_PAREN 4 #define CLOSE_PAREN 5 #define DOLLAR 6 #define QUOTE 7 #define COMMA 8 #define END 9 #define UNKNOWN 10 #define UNKNOWN_CHAR 11 /* * Binary numeric operators: */ #define MULT 12 #define DIVIDE 13 #define MOD 14 #define PLUS 15 #define MINUS 16 #define LEFT_SHIFT 17 #define RIGHT_SHIFT 18 #define LESS 19 #define GREATER 20 #define LEQ 21 #define GEQ 22 #define EQUAL 23 #define NEQ 24 #define BIT_AND 25 #define BIT_XOR 26 #define BIT_OR 27 #define AND 28 #define OR 29 #define QUESTY 30 #define COLON 31 /* * Unary operators. Unary minus and plus are represented by the (binary) * lexemes MINUS and PLUS. */ #define NOT 32 #define BIT_NOT 33 /* * Binary string operators: */ #define STREQ 34 #define STRNEQ 35 /* * Mapping from lexemes to strings; used for debugging messages. These * entries must match the order and number of the lexeme definitions above. */ static CONST char *CONST lexemeStrings[] = { "LITERAL", "FUNCNAME", "[", "{", "(", ")", "$", "\"", ",", "END", "UNKNOWN", "UNKNOWN_CHAR", "*", "/", "%", "+", "-", "<<", ">>", "<", ">", "<=", ">=", "==", "!=", "&", "^", "|", "&&", "||", "?", ":", "!", "~", "eq", "ne", }; /* * Declarations for local procedures to this file: */ static int GetLexeme _ANSI_ARGS_((ParseInfo *infoPtr)); static void LogSyntaxError _ANSI_ARGS_((ParseInfo *infoPtr, CONST char *extraInfo)); static int ParseAddExpr _ANSI_ARGS_((ParseInfo *infoPtr)); static int ParseBitAndExpr _ANSI_ARGS_((ParseInfo *infoPtr)); static int ParseBitOrExpr _ANSI_ARGS_((ParseInfo *infoPtr)); static int ParseBitXorExpr _ANSI_ARGS_((ParseInfo *infoPtr)); static int ParseCondExpr _ANSI_ARGS_((ParseInfo *infoPtr)); static int ParseEqualityExpr _ANSI_ARGS_((ParseInfo *infoPtr)); static int ParseLandExpr _ANSI_ARGS_((ParseInfo *infoPtr)); static int ParseLorExpr _ANSI_ARGS_((ParseInfo *infoPtr)); static int ParseMaxDoubleLength _ANSI_ARGS_((CONST char *string, CONST char *end)); static int ParseMultiplyExpr _ANSI_ARGS_((ParseInfo *infoPtr)); static int ParsePrimaryExpr _ANSI_ARGS_((ParseInfo *infoPtr)); static int ParseRelationalExpr _ANSI_ARGS_((ParseInfo *infoPtr)); static int ParseShiftExpr _ANSI_ARGS_((ParseInfo *infoPtr)); static int ParseUnaryExpr _ANSI_ARGS_((ParseInfo *infoPtr)); static void PrependSubExprTokens _ANSI_ARGS_((CONST char *op, int opBytes, CONST char *src, int srcBytes, int firstIndex, ParseInfo *infoPtr)); /* * Macro used to debug the execution of the recursive descent parser used * to parse expressions. */ #ifdef TCL_COMPILE_DEBUG #define HERE(production, level) \ if (traceParseExpr) { \ fprintf(stderr, "%*s%s: lexeme=%s, next=\"%.20s\"\n", \ (level), " ", (production), \ lexemeStrings[infoPtr->lexeme], infoPtr->next); \ } #else #define HERE(production, level) #endif /* TCL_COMPILE_DEBUG */ /* *---------------------------------------------------------------------- * * Tcl_ParseExpr -- * * Given a string, this procedure parses the first Tcl expression * in the string and returns information about the structure of * the expression. This procedure is the top-level interface to the * the expression parsing module. No more that numBytes bytes will * be scanned. * * Results: * The return value is TCL_OK if the command was parsed successfully * and TCL_ERROR otherwise. If an error occurs and interp isn't NULL * then an error message is left in its result. On a successful return, * parsePtr is filled in with information about the expression that * was parsed. * * Side effects: * If there is insufficient space in parsePtr to hold all the * information about the expression, then additional space is * malloc-ed. If the procedure returns TCL_OK then the caller must * eventually invoke Tcl_FreeParse to release any additional space * that was allocated. * *---------------------------------------------------------------------- */ int Tcl_ParseExpr(interp, string, numBytes, parsePtr) Tcl_Interp *interp; /* Used for error reporting. */ CONST char *string; /* The source string to parse. */ int numBytes; /* Number of bytes in string. If < 0, the * string consists of all bytes up to the * first null character. */ Tcl_Parse *parsePtr; /* Structure to fill with information about * the parsed expression; any previous * information in the structure is * ignored. */ { ParseInfo info; int code; if (numBytes < 0) { numBytes = (string? strlen(string) : 0); } #ifdef TCL_COMPILE_DEBUG if (traceParseExpr) { fprintf(stderr, "Tcl_ParseExpr: string=\"%.*s\"\n", numBytes, string); } #endif /* TCL_COMPILE_DEBUG */ parsePtr->commentStart = NULL; parsePtr->commentSize = 0; parsePtr->commandStart = NULL; parsePtr->commandSize = 0; parsePtr->numWords = 0; parsePtr->tokenPtr = parsePtr->staticTokens; parsePtr->numTokens = 0; parsePtr->tokensAvailable = NUM_STATIC_TOKENS; parsePtr->string = string; parsePtr->end = (string + numBytes); parsePtr->interp = interp; parsePtr->term = string; parsePtr->incomplete = 0; /* * Initialize the ParseInfo structure that holds state while parsing * the expression. */ info.parsePtr = parsePtr; info.lexeme = UNKNOWN; info.start = NULL; info.size = 0; info.next = string; info.prevEnd = string; info.originalExpr = string; info.lastChar = (string + numBytes); /* just after last char of expr */ /* * Get the first lexeme then parse the expression. */ code = GetLexeme(&info); if (code != TCL_OK) { goto error; } code = ParseCondExpr(&info); if (code != TCL_OK) { goto error; } if (info.lexeme != END) { LogSyntaxError(&info, "extra tokens at end of expression"); goto error; } return TCL_OK; error: if (parsePtr->tokenPtr != parsePtr->staticTokens) { ckfree((char *) parsePtr->tokenPtr); } return TCL_ERROR; } /* *---------------------------------------------------------------------- * * ParseCondExpr -- * * This procedure parses a Tcl conditional expression: * condExpr ::= lorExpr ['?' condExpr ':' condExpr] * * Note that this is the topmost recursive-descent parsing routine used * by Tcl_ParseExpr to parse expressions. This avoids an extra procedure * call since such a procedure would only return the result of calling * ParseCondExpr. Other recursive-descent procedures that need to parse * complete expressions also call ParseCondExpr. * * Results: * The return value is TCL_OK on a successful parse and TCL_ERROR * on failure. If TCL_ERROR is returned, then the interpreter's result * contains an error message. * * Side effects: * If there is insufficient space in parsePtr to hold all the * information about the subexpression, then additional space is * malloc-ed. * *---------------------------------------------------------------------- */ static int ParseCondExpr(infoPtr) ParseInfo *infoPtr; /* Holds the parse state for the * expression being parsed. */ { Tcl_Parse *parsePtr = infoPtr->parsePtr; Tcl_Token *tokenPtr, *firstTokenPtr, *condTokenPtr; int firstIndex, numToMove, code; CONST char *srcStart; HERE("condExpr", 1); srcStart = infoPtr->start; firstIndex = parsePtr->numTokens; code = ParseLorExpr(infoPtr); if (code != TCL_OK) { return code; } if (infoPtr->lexeme == QUESTY) { /* * Emit two tokens: one TCL_TOKEN_SUB_EXPR token for the entire * conditional expression, and a TCL_TOKEN_OPERATOR token for * the "?" operator. Note that these two tokens must be inserted * before the LOR operand tokens generated above. */ if ((parsePtr->numTokens + 1) >= parsePtr->tokensAvailable) { TclExpandTokenArray(parsePtr); } firstTokenPtr = &parsePtr->tokenPtr[firstIndex]; tokenPtr = (firstTokenPtr + 2); numToMove = (parsePtr->numTokens - firstIndex); memmove((VOID *) tokenPtr, (VOID *) firstTokenPtr, (size_t) (numToMove * sizeof(Tcl_Token))); parsePtr->numTokens += 2; tokenPtr = firstTokenPtr; tokenPtr->type = TCL_TOKEN_SUB_EXPR; tokenPtr->start = srcStart; tokenPtr++; tokenPtr->type = TCL_TOKEN_OPERATOR; tokenPtr->start = infoPtr->start; tokenPtr->size = 1; tokenPtr->numComponents = 0; /* * Skip over the '?'. */ code = GetLexeme(infoPtr); if (code != TCL_OK) { return code; } /* * Parse the "then" expression. */ code = ParseCondExpr(infoPtr); if (code != TCL_OK) { return code; } if (infoPtr->lexeme != COLON) { LogSyntaxError(infoPtr, "missing colon from ternary conditional"); return TCL_ERROR; } code = GetLexeme(infoPtr); /* skip over the ':' */ if (code != TCL_OK) { return code; } /* * Parse the "else" expression. */ code = ParseCondExpr(infoPtr); if (code != TCL_OK) { return code; } /* * Now set the size-related fields in the '?' subexpression token. */ condTokenPtr = &parsePtr->tokenPtr[firstIndex]; condTokenPtr->size = (infoPtr->prevEnd - srcStart); condTokenPtr->numComponents = parsePtr->numTokens - (firstIndex+1); } return TCL_OK; } /* *---------------------------------------------------------------------- * * ParseLorExpr -- * * This procedure parses a Tcl logical or expression: * lorExpr ::= landExpr {'||' landExpr} * * Results: * The return value is TCL_OK on a successful parse and TCL_ERROR * on failure. If TCL_ERROR is returned, then the interpreter's result * contains an error message. * * Side effects: * If there is insufficient space in parsePtr to hold all the * information about the subexpression, then additional space is * malloc-ed. * *---------------------------------------------------------------------- */ static int ParseLorExpr(infoPtr) ParseInfo *infoPtr; /* Holds the parse state for the * expression being parsed. */ { Tcl_Parse *parsePtr = infoPtr->parsePtr; int firstIndex, code; CONST char *srcStart, *operator; HERE("lorExpr", 2); srcStart = infoPtr->start; firstIndex = parsePtr->numTokens; code = ParseLandExpr(infoPtr); if (code != TCL_OK) { return code; } while (infoPtr->lexeme == OR) { operator = infoPtr->start; code = GetLexeme(infoPtr); /* skip over the '||' */ if (code != TCL_OK) { return code; } code = ParseLandExpr(infoPtr); if (code != TCL_OK) { return code; } /* * Generate tokens for the LOR subexpression and the '||' operator. */ PrependSubExprTokens(operator, 2, srcStart, (infoPtr->prevEnd - srcStart), firstIndex, infoPtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * ParseLandExpr -- * * This procedure parses a Tcl logical and expression: * landExpr ::= bitOrExpr {'&&' bitOrExpr} * * Results: * The return value is TCL_OK on a successful parse and TCL_ERROR * on failure. If TCL_ERROR is returned, then the interpreter's result * contains an error message. * * Side effects: * If there is insufficient space in parsePtr to hold all the * information about the subexpression, then additional space is * malloc-ed. * *---------------------------------------------------------------------- */ static int ParseLandExpr(infoPtr) ParseInfo *infoPtr; /* Holds the parse state for the * expression being parsed. */ { Tcl_Parse *parsePtr = infoPtr->parsePtr; int firstIndex, code; CONST char *srcStart, *operator; HERE("landExpr", 3); srcStart = infoPtr->start; firstIndex = parsePtr->numTokens; code = ParseBitOrExpr(infoPtr); if (code != TCL_OK) { return code; } while (infoPtr->lexeme == AND) { operator = infoPtr->start; code = GetLexeme(infoPtr); /* skip over the '&&' */ if (code != TCL_OK) { return code; } code = ParseBitOrExpr(infoPtr); if (code != TCL_OK) { return code; } /* * Generate tokens for the LAND subexpression and the '&&' operator. */ PrependSubExprTokens(operator, 2, srcStart, (infoPtr->prevEnd - srcStart), firstIndex, infoPtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * ParseBitOrExpr -- * * This procedure parses a Tcl bitwise or expression: * bitOrExpr ::= bitXorExpr {'|' bitXorExpr} * * Results: * The return value is TCL_OK on a successful parse and TCL_ERROR * on failure. If TCL_ERROR is returned, then the interpreter's result * contains an error message. * * Side effects: * If there is insufficient space in parsePtr to hold all the * information about the subexpression, then additional space is * malloc-ed. * *---------------------------------------------------------------------- */ static int ParseBitOrExpr(infoPtr) ParseInfo *infoPtr; /* Holds the parse state for the * expression being parsed. */ { Tcl_Parse *parsePtr = infoPtr->parsePtr; int firstIndex, code; CONST char *srcStart, *operator; HERE("bitOrExpr", 4); srcStart = infoPtr->start; firstIndex = parsePtr->numTokens; code = ParseBitXorExpr(infoPtr); if (code != TCL_OK) { return code; } while (infoPtr->lexeme == BIT_OR) { operator = infoPtr->start; code = GetLexeme(infoPtr); /* skip over the '|' */ if (code != TCL_OK) { return code; } code = ParseBitXorExpr(infoPtr); if (code != TCL_OK) { return code; } /* * Generate tokens for the BITOR subexpression and the '|' operator. */ PrependSubExprTokens(operator, 1, srcStart, (infoPtr->prevEnd - srcStart), firstIndex, infoPtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * ParseBitXorExpr -- * * This procedure parses a Tcl bitwise exclusive or expression: * bitXorExpr ::= bitAndExpr {'^' bitAndExpr} * * Results: * The return value is TCL_OK on a successful parse and TCL_ERROR * on failure. If TCL_ERROR is returned, then the interpreter's result * contains an error message. * * Side effects: * If there is insufficient space in parsePtr to hold all the * information about the subexpression, then additional space is * malloc-ed. * *---------------------------------------------------------------------- */ static int ParseBitXorExpr(infoPtr) ParseInfo *infoPtr; /* Holds the parse state for the * expression being parsed. */ { Tcl_Parse *parsePtr = infoPtr->parsePtr; int firstIndex, code; CONST char *srcStart, *operator; HERE("bitXorExpr", 5); srcStart = infoPtr->start; firstIndex = parsePtr->numTokens; code = ParseBitAndExpr(infoPtr); if (code != TCL_OK) { return code; } while (infoPtr->lexeme == BIT_XOR) { operator = infoPtr->start; code = GetLexeme(infoPtr); /* skip over the '^' */ if (code != TCL_OK) { return code; } code = ParseBitAndExpr(infoPtr); if (code != TCL_OK) { return code; } /* * Generate tokens for the XOR subexpression and the '^' operator. */ PrependSubExprTokens(operator, 1, srcStart, (infoPtr->prevEnd - srcStart), firstIndex, infoPtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * ParseBitAndExpr -- * * This procedure parses a Tcl bitwise and expression: * bitAndExpr ::= equalityExpr {'&' equalityExpr} * * Results: * The return value is TCL_OK on a successful parse and TCL_ERROR * on failure. If TCL_ERROR is returned, then the interpreter's result * contains an error message. * * Side effects: * If there is insufficient space in parsePtr to hold all the * information about the subexpression, then additional space is * malloc-ed. * *---------------------------------------------------------------------- */ static int ParseBitAndExpr(infoPtr) ParseInfo *infoPtr; /* Holds the parse state for the * expression being parsed. */ { Tcl_Parse *parsePtr = infoPtr->parsePtr; int firstIndex, code; CONST char *srcStart, *operator; HERE("bitAndExpr", 6); srcStart = infoPtr->start; firstIndex = parsePtr->numTokens; code = ParseEqualityExpr(infoPtr); if (code != TCL_OK) { return code; } while (infoPtr->lexeme == BIT_AND) { operator = infoPtr->start; code = GetLexeme(infoPtr); /* skip over the '&' */ if (code != TCL_OK) { return code; } code = ParseEqualityExpr(infoPtr); if (code != TCL_OK) { return code; } /* * Generate tokens for the BITAND subexpression and '&' operator. */ PrependSubExprTokens(operator, 1, srcStart, (infoPtr->prevEnd - srcStart), firstIndex, infoPtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * ParseEqualityExpr -- * * This procedure parses a Tcl equality (inequality) expression: * equalityExpr ::= relationalExpr * {('==' | '!=' | 'ne' | 'eq') relationalExpr} * * Results: * The return value is TCL_OK on a successful parse and TCL_ERROR * on failure. If TCL_ERROR is returned, then the interpreter's result * contains an error message. * * Side effects: * If there is insufficient space in parsePtr to hold all the * information about the subexpression, then additional space is * malloc-ed. * *---------------------------------------------------------------------- */ static int ParseEqualityExpr(infoPtr) ParseInfo *infoPtr; /* Holds the parse state for the * expression being parsed. */ { Tcl_Parse *parsePtr = infoPtr->parsePtr; int firstIndex, lexeme, code; CONST char *srcStart, *operator; HERE("equalityExpr", 7); srcStart = infoPtr->start; firstIndex = parsePtr->numTokens; code = ParseRelationalExpr(infoPtr); if (code != TCL_OK) { return code; } lexeme = infoPtr->lexeme; while ((lexeme == EQUAL) || (lexeme == NEQ) || (lexeme == STREQ) || (lexeme == STRNEQ)) { operator = infoPtr->start; code = GetLexeme(infoPtr); /* skip over ==, !=, 'eq' or 'ne' */ if (code != TCL_OK) { return code; } code = ParseRelationalExpr(infoPtr); if (code != TCL_OK) { return code; } /* * Generate tokens for the subexpression and '==', '!=', 'eq' or 'ne' * operator. */ PrependSubExprTokens(operator, 2, srcStart, (infoPtr->prevEnd - srcStart), firstIndex, infoPtr); lexeme = infoPtr->lexeme; } return TCL_OK; } /* *---------------------------------------------------------------------- * * ParseRelationalExpr -- * * This procedure parses a Tcl relational expression: * relationalExpr ::= shiftExpr {('<' | '>' | '<=' | '>=') shiftExpr} * * Results: * The return value is TCL_OK on a successful parse and TCL_ERROR * on failure. If TCL_ERROR is returned, then the interpreter's result * contains an error message. * * Side effects: * If there is insufficient space in parsePtr to hold all the * information about the subexpression, then additional space is * malloc-ed. * *---------------------------------------------------------------------- */ static int ParseRelationalExpr(infoPtr) ParseInfo *infoPtr; /* Holds the parse state for the * expression being parsed. */ { Tcl_Parse *parsePtr = infoPtr->parsePtr; int firstIndex, lexeme, operatorSize, code; CONST char *srcStart, *operator; HERE("relationalExpr", 8); srcStart = infoPtr->start; firstIndex = parsePtr->numTokens; code = ParseShiftExpr(infoPtr); if (code != TCL_OK) { return code; } lexeme = infoPtr->lexeme; while ((lexeme == LESS) || (lexeme == GREATER) || (lexeme == LEQ) || (lexeme == GEQ)) { operator = infoPtr->start; if ((lexeme == LEQ) || (lexeme == GEQ)) { operatorSize = 2; } else { operatorSize = 1; } code = GetLexeme(infoPtr); /* skip over the operator */ if (code != TCL_OK) { return code; } code = ParseShiftExpr(infoPtr); if (code != TCL_OK) { return code; } /* * Generate tokens for the subexpression and the operator. */ PrependSubExprTokens(operator, operatorSize, srcStart, (infoPtr->prevEnd - srcStart), firstIndex, infoPtr); lexeme = infoPtr->lexeme; } return TCL_OK; } /* *---------------------------------------------------------------------- * * ParseShiftExpr -- * * This procedure parses a Tcl shift expression: * shiftExpr ::= addExpr {('<<' | '>>') addExpr} * * Results: * The return value is TCL_OK on a successful parse and TCL_ERROR * on failure. If TCL_ERROR is returned, then the interpreter's result * contains an error message. * * Side effects: * If there is insufficient space in parsePtr to hold all the * information about the subexpression, then additional space is * malloc-ed. * *---------------------------------------------------------------------- */ static int ParseShiftExpr(infoPtr) ParseInfo *infoPtr; /* Holds the parse state for the * expression being parsed. */ { Tcl_Parse *parsePtr = infoPtr->parsePtr; int firstIndex, lexeme, code; CONST char *srcStart, *operator; HERE("shiftExpr", 9); srcStart = infoPtr->start; firstIndex = parsePtr->numTokens; code = ParseAddExpr(infoPtr); if (code != TCL_OK) { return code; } lexeme = infoPtr->lexeme; while ((lexeme == LEFT_SHIFT) || (lexeme == RIGHT_SHIFT)) { operator = infoPtr->start; code = GetLexeme(infoPtr); /* skip over << or >> */ if (code != TCL_OK) { return code; } code = ParseAddExpr(infoPtr); if (code != TCL_OK) { return code; } /* * Generate tokens for the subexpression and '<<' or '>>' operator. */ PrependSubExprTokens(operator, 2, srcStart, (infoPtr->prevEnd - srcStart), firstIndex, infoPtr); lexeme = infoPtr->lexeme; } return TCL_OK; } /* *---------------------------------------------------------------------- * * ParseAddExpr -- * * This procedure parses a Tcl addition expression: * addExpr ::= multiplyExpr {('+' | '-') multiplyExpr} * * Results: * The return value is TCL_OK on a successful parse and TCL_ERROR * on failure. If TCL_ERROR is returned, then the interpreter's result * contains an error message. * * Side effects: * If there is insufficient space in parsePtr to hold all the * information about the subexpression, then additional space is * malloc-ed. * *---------------------------------------------------------------------- */ static int ParseAddExpr(infoPtr) ParseInfo *infoPtr; /* Holds the parse state for the * expression being parsed. */ { Tcl_Parse *parsePtr = infoPtr->parsePtr; int firstIndex, lexeme, code; CONST char *srcStart, *operator; HERE("addExpr", 10); srcStart = infoPtr->start; firstIndex = parsePtr->numTokens; code = ParseMultiplyExpr(infoPtr); if (code != TCL_OK) { return code; } lexeme = infoPtr->lexeme; while ((lexeme == PLUS) || (lexeme == MINUS)) { operator = infoPtr->start; code = GetLexeme(infoPtr); /* skip over + or - */ if (code != TCL_OK) { return code; } code = ParseMultiplyExpr(infoPtr); if (code != TCL_OK) { return code; } /* * Generate tokens for the subexpression and '+' or '-' operator. */ PrependSubExprTokens(operator, 1, srcStart, (infoPtr->prevEnd - srcStart), firstIndex, infoPtr); lexeme = infoPtr->lexeme; } return TCL_OK; } /* *---------------------------------------------------------------------- * * ParseMultiplyExpr -- * * This procedure parses a Tcl multiply expression: * multiplyExpr ::= unaryExpr {('*' | '/' | '%') unaryExpr} * * Results: * The return value is TCL_OK on a successful parse and TCL_ERROR * on failure. If TCL_ERROR is returned, then the interpreter's result * contains an error message. * * Side effects: * If there is insufficient space in parsePtr to hold all the * information about the subexpression, then additional space is * malloc-ed. * *---------------------------------------------------------------------- */ static int ParseMultiplyExpr(infoPtr) ParseInfo *infoPtr; /* Holds the parse state for the * expression being parsed. */ { Tcl_Parse *parsePtr = infoPtr->parsePtr; int firstIndex, lexeme, code; CONST char *srcStart, *operator; HERE("multiplyExpr", 11); srcStart = infoPtr->start; firstIndex = parsePtr->numTokens; code = ParseUnaryExpr(infoPtr); if (code != TCL_OK) { return code; } lexeme = infoPtr->lexeme; while ((lexeme == MULT) || (lexeme == DIVIDE) || (lexeme == MOD)) { operator = infoPtr->start; code = GetLexeme(infoPtr); /* skip over * or / or % */ if (code != TCL_OK) { return code; } code = ParseUnaryExpr(infoPtr); if (code != TCL_OK) { return code; } /* * Generate tokens for the subexpression and * or / or % operator. */ PrependSubExprTokens(operator, 1, srcStart, (infoPtr->prevEnd - srcStart), firstIndex, infoPtr); lexeme = infoPtr->lexeme; } return TCL_OK; } /* *---------------------------------------------------------------------- * * ParseUnaryExpr -- * * This procedure parses a Tcl unary expression: * unaryExpr ::= ('+' | '-' | '~' | '!') unaryExpr | primaryExpr * * Results: * The return value is TCL_OK on a successful parse and TCL_ERROR * on failure. If TCL_ERROR is returned, then the interpreter's result * contains an error message. * * Side effects: * If there is insufficient space in parsePtr to hold all the * information about the subexpression, then additional space is * malloc-ed. * *---------------------------------------------------------------------- */ static int ParseUnaryExpr(infoPtr) ParseInfo *infoPtr; /* Holds the parse state for the * expression being parsed. */ { Tcl_Parse *parsePtr = infoPtr->parsePtr; int firstIndex, lexeme, code; CONST char *srcStart, *operator; HERE("unaryExpr", 12); srcStart = infoPtr->start; firstIndex = parsePtr->numTokens; lexeme = infoPtr->lexeme; if ((lexeme == PLUS) || (lexeme == MINUS) || (lexeme == BIT_NOT) || (lexeme == NOT)) { operator = infoPtr->start; code = GetLexeme(infoPtr); /* skip over the unary operator */ if (code != TCL_OK) { return code; } code = ParseUnaryExpr(infoPtr); if (code != TCL_OK) { return code; } /* * Generate tokens for the subexpression and the operator. */ PrependSubExprTokens(operator, 1, srcStart, (infoPtr->prevEnd - srcStart), firstIndex, infoPtr); } else { /* must be a primaryExpr */ code = ParsePrimaryExpr(infoPtr); if (code != TCL_OK) { return code; } } return TCL_OK; } /* *---------------------------------------------------------------------- * * ParsePrimaryExpr -- * * This procedure parses a Tcl primary expression: * primaryExpr ::= literal | varReference | quotedString | * '[' command ']' | mathFuncCall | '(' condExpr ')' * * Results: * The return value is TCL_OK on a successful parse and TCL_ERROR * on failure. If TCL_ERROR is returned, then the interpreter's result * contains an error message. * * Side effects: * If there is insufficient space in parsePtr to hold all the * information about the subexpression, then additional space is * malloc-ed. * *---------------------------------------------------------------------- */ static int ParsePrimaryExpr(infoPtr) ParseInfo *infoPtr; /* Holds the parse state for the * expression being parsed. */ { Tcl_Parse *parsePtr = infoPtr->parsePtr; Tcl_Interp *interp = parsePtr->interp; Tcl_Token *tokenPtr, *exprTokenPtr; Tcl_Parse nested; CONST char *dollarPtr, *stringStart, *termPtr, *src; int lexeme, exprIndex, firstIndex, numToMove, code; /* * We simply recurse on parenthesized subexpressions. */ HERE("primaryExpr", 13); lexeme = infoPtr->lexeme; if (lexeme == OPEN_PAREN) { code = GetLexeme(infoPtr); /* skip over the '(' */ if (code != TCL_OK) { return code; } code = ParseCondExpr(infoPtr); if (code != TCL_OK) { return code; } if (infoPtr->lexeme != CLOSE_PAREN) { LogSyntaxError(infoPtr, "looking for close parenthesis"); return TCL_ERROR; } code = GetLexeme(infoPtr); /* skip over the ')' */ if (code != TCL_OK) { return code; } return TCL_OK; } /* * Start a TCL_TOKEN_SUB_EXPR token for the primary. */ if (parsePtr->numTokens == parsePtr->tokensAvailable) { TclExpandTokenArray(parsePtr); } exprIndex = parsePtr->numTokens; exprTokenPtr = &parsePtr->tokenPtr[exprIndex]; exprTokenPtr->type = TCL_TOKEN_SUB_EXPR; exprTokenPtr->start = infoPtr->start; parsePtr->numTokens++; /* * Process the primary then finish setting the fields of the * TCL_TOKEN_SUB_EXPR token. Note that we can't use the pointer now * stored in "exprTokenPtr" in the code below since the token array * might be reallocated. */ firstIndex = parsePtr->numTokens; switch (lexeme) { case LITERAL: /* * Int or double number. */ tokenizeLiteral: if (parsePtr->numTokens == parsePtr->tokensAvailable) { TclExpandTokenArray(parsePtr); } tokenPtr = &parsePtr->tokenPtr[parsePtr->numTokens]; tokenPtr->type = TCL_TOKEN_TEXT; tokenPtr->start = infoPtr->start; tokenPtr->size = infoPtr->size; tokenPtr->numComponents = 0; parsePtr->numTokens++; exprTokenPtr = &parsePtr->tokenPtr[exprIndex]; exprTokenPtr->size = infoPtr->size; exprTokenPtr->numComponents = 1; break; case DOLLAR: /* * $var variable reference. */ dollarPtr = (infoPtr->next - 1); code = Tcl_ParseVarName(interp, dollarPtr, (infoPtr->lastChar - dollarPtr), parsePtr, 1); if (code != TCL_OK) { return code; } infoPtr->next = dollarPtr + parsePtr->tokenPtr[firstIndex].size; exprTokenPtr = &parsePtr->tokenPtr[exprIndex]; exprTokenPtr->size = parsePtr->tokenPtr[firstIndex].size; exprTokenPtr->numComponents = (parsePtr->tokenPtr[firstIndex].numComponents + 1); break; case QUOTE: /* * '"' string '"' */ stringStart = infoPtr->next; code = Tcl_ParseQuotedString(interp, infoPtr->start, (infoPtr->lastChar - stringStart), parsePtr, 1, &termPtr); if (code != TCL_OK) { return code; } infoPtr->next = termPtr; exprTokenPtr = &parsePtr->tokenPtr[exprIndex]; exprTokenPtr->size = (termPtr - exprTokenPtr->start); exprTokenPtr->numComponents = parsePtr->numTokens - firstIndex; /* * If parsing the quoted string resulted in more than one token, * insert a TCL_TOKEN_WORD token before them. This indicates that * the quoted string represents a concatenation of multiple tokens. */ if (exprTokenPtr->numComponents > 1) { if (parsePtr->numTokens >= parsePtr->tokensAvailable) { TclExpandTokenArray(parsePtr); } tokenPtr = &parsePtr->tokenPtr[firstIndex]; numToMove = (parsePtr->numTokens - firstIndex); memmove((VOID *) (tokenPtr + 1), (VOID *) tokenPtr, (size_t) (numToMove * sizeof(Tcl_Token))); parsePtr->numTokens++; exprTokenPtr = &parsePtr->tokenPtr[exprIndex]; exprTokenPtr->numComponents++; tokenPtr->type = TCL_TOKEN_WORD; tokenPtr->start = exprTokenPtr->start; tokenPtr->size = exprTokenPtr->size; tokenPtr->numComponents = (exprTokenPtr->numComponents - 1); } break; case OPEN_BRACKET: /* * '[' command {command} ']' */ if (parsePtr->numTokens == parsePtr->tokensAvailable) { TclExpandTokenArray(parsePtr); } tokenPtr = &parsePtr->tokenPtr[parsePtr->numTokens]; tokenPtr->type = TCL_TOKEN_COMMAND; tokenPtr->start = infoPtr->start; tokenPtr->numComponents = 0; parsePtr->numTokens++; /* * Call Tcl_ParseCommand repeatedly to parse the nested command(s) * to find their end, then throw away that parse information. */ src = infoPtr->next; while (1) { if (Tcl_ParseCommand(interp, src, (parsePtr->end - src), 1, &nested) != TCL_OK) { parsePtr->term = nested.term; parsePtr->errorType = nested.errorType; parsePtr->incomplete = nested.incomplete; return TCL_ERROR; } src = (nested.commandStart + nested.commandSize); /* * This is equivalent to Tcl_FreeParse(&nested), but * presumably inlined here for sake of runtime optimization */ if (nested.tokenPtr != nested.staticTokens) { ckfree((char *) nested.tokenPtr); } /* * Check for the closing ']' that ends the command substitution. * It must have been the last character of the parsed command. */ if ((nested.term < parsePtr->end) && (*nested.term == ']') && !nested.incomplete) { break; } if (src == parsePtr->end) { if (parsePtr->interp != NULL) { Tcl_SetResult(interp, "missing close-bracket", TCL_STATIC); } parsePtr->term = tokenPtr->start; parsePtr->errorType = TCL_PARSE_MISSING_BRACKET; parsePtr->incomplete = 1; return TCL_ERROR; } } tokenPtr->size = (src - tokenPtr->start); infoPtr->next = src; exprTokenPtr = &parsePtr->tokenPtr[exprIndex]; exprTokenPtr->size = (src - tokenPtr->start); exprTokenPtr->numComponents = 1; break; case OPEN_BRACE: /* * '{' string '}' */ code = Tcl_ParseBraces(interp, infoPtr->start, (infoPtr->lastChar - infoPtr->start), parsePtr, 1, &termPtr); if (code != TCL_OK) { return code; } infoPtr->next = termPtr; exprTokenPtr = &parsePtr->tokenPtr[exprIndex]; exprTokenPtr->size = (termPtr - infoPtr->start); exprTokenPtr->numComponents = parsePtr->numTokens - firstIndex; /* * If parsing the braced string resulted in more than one token, * insert a TCL_TOKEN_WORD token before them. This indicates that * the braced string represents a concatenation of multiple tokens. */ if (exprTokenPtr->numComponents > 1) { if (parsePtr->numTokens >= parsePtr->tokensAvailable) { TclExpandTokenArray(parsePtr); } tokenPtr = &parsePtr->tokenPtr[firstIndex]; numToMove = (parsePtr->numTokens - firstIndex); memmove((VOID *) (tokenPtr + 1), (VOID *) tokenPtr, (size_t) (numToMove * sizeof(Tcl_Token))); parsePtr->numTokens++; exprTokenPtr = &parsePtr->tokenPtr[exprIndex]; exprTokenPtr->numComponents++; tokenPtr->type = TCL_TOKEN_WORD; tokenPtr->start = exprTokenPtr->start; tokenPtr->size = exprTokenPtr->size; tokenPtr->numComponents = exprTokenPtr->numComponents-1; } break; /* * Disable attempt to support functions named "eq" or "ne". This * is unworkable in the Tcl 8.4.* releases. See Tcl Bugs 1971879 * and 1201589. * case STREQ: case STRNEQ: */ case FUNC_NAME: { /* * math_func '(' expr {',' expr} ')' */ ParseInfo savedInfo = *infoPtr; code = GetLexeme(infoPtr); /* skip over function name */ if (code != TCL_OK) { return code; } if (infoPtr->lexeme != OPEN_PAREN) { int code; Tcl_DString functionName; Tcl_HashEntry *hPtr; Interp *iPtr = (Interp *) infoPtr->parsePtr->interp; Tcl_Obj *objPtr = Tcl_NewStringObj(savedInfo.start, savedInfo.size); /* Check for boolean literals (true, false, yes, no, on, off) */ Tcl_IncrRefCount(objPtr); code = Tcl_ConvertToType(NULL, objPtr, &tclBooleanType); Tcl_DecrRefCount(objPtr); if (code == TCL_OK) { *infoPtr = savedInfo; goto tokenizeLiteral; } /* * Guess what kind of error we have by trying to tell * whether we have a function or variable name here. * Alas, this makes the parser more tightly bound with the * rest of the interpreter, but that is the only way to * give a sensible message here. Still, it is not too * serious as this is only done when generating an error. */ /* * Look up the name as a function name. We need a writable * copy (DString) so we can terminate it with a NULL for * the benefit of Tcl_FindHashEntry which operates on * NULL-terminated string keys. */ Tcl_DStringInit(&functionName); hPtr = Tcl_FindHashEntry(&iPtr->mathFuncTable, Tcl_DStringAppend(&functionName, savedInfo.start, savedInfo.size)); Tcl_DStringFree(&functionName); /* * Assume that we have an attempted variable reference * unless we've got a function name, as the set of * potential function names is typically much smaller. */ if (hPtr != NULL) { LogSyntaxError(infoPtr, "expected parenthesis enclosing function arguments"); } else { LogSyntaxError(infoPtr, "variable references require preceding $"); } return TCL_ERROR; } if (parsePtr->numTokens == parsePtr->tokensAvailable) { TclExpandTokenArray(parsePtr); } tokenPtr = &parsePtr->tokenPtr[parsePtr->numTokens]; tokenPtr->type = TCL_TOKEN_OPERATOR; tokenPtr->start = savedInfo.start; tokenPtr->size = savedInfo.size; tokenPtr->numComponents = 0; parsePtr->numTokens++; code = GetLexeme(infoPtr); /* skip over '(' */ if (code != TCL_OK) { return code; } while (infoPtr->lexeme != CLOSE_PAREN) { code = ParseCondExpr(infoPtr); if (code != TCL_OK) { return code; } if (infoPtr->lexeme == COMMA) { code = GetLexeme(infoPtr); /* skip over , */ if (code != TCL_OK) { return code; } } else if (infoPtr->lexeme != CLOSE_PAREN) { LogSyntaxError(infoPtr, "missing close parenthesis at end of function call"); return TCL_ERROR; } } exprTokenPtr = &parsePtr->tokenPtr[exprIndex]; exprTokenPtr->size = (infoPtr->next - exprTokenPtr->start); exprTokenPtr->numComponents = parsePtr->numTokens - firstIndex; break; } case COMMA: LogSyntaxError(infoPtr, "commas can only separate function arguments"); return TCL_ERROR; case END: LogSyntaxError(infoPtr, "premature end of expression"); return TCL_ERROR; case UNKNOWN: LogSyntaxError(infoPtr, "single equality character not legal in expressions"); return TCL_ERROR; case UNKNOWN_CHAR: LogSyntaxError(infoPtr, "character not legal in expressions"); return TCL_ERROR; case QUESTY: LogSyntaxError(infoPtr, "unexpected ternary 'then' separator"); return TCL_ERROR; case COLON: LogSyntaxError(infoPtr, "unexpected ternary 'else' separator"); return TCL_ERROR; case CLOSE_PAREN: LogSyntaxError(infoPtr, "unexpected close parenthesis"); return TCL_ERROR; default: { char buf[64]; sprintf(buf, "unexpected operator %s", lexemeStrings[lexeme]); LogSyntaxError(infoPtr, buf); return TCL_ERROR; } } /* * Advance to the next lexeme before returning. */ code = GetLexeme(infoPtr); if (code != TCL_OK) { return code; } parsePtr->term = infoPtr->next; return TCL_OK; } /* *---------------------------------------------------------------------- * * GetLexeme -- * * Lexical scanner for Tcl expressions: scans a single operator or * other syntactic element from an expression string. * * Results: * TCL_OK is returned unless an error occurred. In that case a standard * Tcl error code is returned and, if infoPtr->parsePtr->interp is * non-NULL, the interpreter's result is set to hold an error * message. TCL_ERROR is returned if an integer overflow, or a * floating-point overflow or underflow occurred while reading in a * number. If the lexical analysis is successful, infoPtr->lexeme * refers to the next symbol in the expression string, and * infoPtr->next is advanced past the lexeme. Also, if the lexeme is a * LITERAL or FUNC_NAME, then infoPtr->start is set to the first * character of the lexeme; otherwise it is set NULL. * * Side effects: * If there is insufficient space in parsePtr to hold all the * information about the subexpression, then additional space is * malloc-ed.. * *---------------------------------------------------------------------- */ static int GetLexeme(infoPtr) ParseInfo *infoPtr; /* Holds state needed to parse the expr, * including the resulting lexeme. */ { register CONST char *src; /* Points to current source char. */ char c; int offset, length, numBytes; Tcl_Parse *parsePtr = infoPtr->parsePtr; Tcl_Interp *interp = parsePtr->interp; Tcl_UniChar ch; /* * Record where the previous lexeme ended. Since we always read one * lexeme ahead during parsing, this helps us know the source length of * subexpression tokens. */ infoPtr->prevEnd = infoPtr->next; /* * Scan over leading white space at the start of a lexeme. */ src = infoPtr->next; numBytes = parsePtr->end - src; do { char type; int scanned = TclParseWhiteSpace(src, numBytes, parsePtr, &type); src += scanned; numBytes -= scanned; } while (numBytes && (*src == '\n') && (src++,numBytes--)); parsePtr->term = src; if (numBytes == 0) { infoPtr->lexeme = END; infoPtr->next = src; return TCL_OK; } /* * Try to parse the lexeme first as an integer or floating-point * number. Don't check for a number if the first character c is * "+" or "-". If we did, we might treat a binary operator as unary * by mistake, which would eventually cause a syntax error. */ c = *src; if ((c != '+') && (c != '-')) { CONST char *end = infoPtr->lastChar; if ((length = TclParseInteger(src, (end - src)))) { /* * First length bytes look like an integer. Verify by * attempting the conversion to the largest integer we have. */ int code; Tcl_WideInt wide; Tcl_Obj *value = Tcl_NewStringObj(src, length); Tcl_IncrRefCount(value); code = Tcl_GetWideIntFromObj(interp, value, &wide); Tcl_DecrRefCount(value); if (code == TCL_ERROR) { parsePtr->errorType = TCL_PARSE_BAD_NUMBER; return TCL_ERROR; } infoPtr->lexeme = LITERAL; infoPtr->start = src; infoPtr->size = length; infoPtr->next = (src + length); parsePtr->term = infoPtr->next; return TCL_OK; } else if ((length = ParseMaxDoubleLength(src, end))) { /* * There are length characters that could be a double. * Let strtod() tells us for sure. Need a writable copy * so we can set an terminating NULL to keep strtod from * scanning too far. */ char *startPtr, *termPtr; double doubleValue; Tcl_DString toParse; errno = 0; Tcl_DStringInit(&toParse); startPtr = Tcl_DStringAppend(&toParse, src, length); doubleValue = strtod(startPtr, &termPtr); Tcl_DStringFree(&toParse); if (termPtr != startPtr) { if (errno != 0) { if (interp != NULL) { TclExprFloatError(interp, doubleValue); } parsePtr->errorType = TCL_PARSE_BAD_NUMBER; return TCL_ERROR; } /* * startPtr was the start of a valid double, copied * from src. */ infoPtr->lexeme = LITERAL; infoPtr->start = src; if ((termPtr - startPtr) > length) { infoPtr->size = length; } else { infoPtr->size = (termPtr - startPtr); } infoPtr->next = src + infoPtr->size; parsePtr->term = infoPtr->next; return TCL_OK; } } } /* * Not an integer or double literal. Initialize the lexeme's fields * assuming the common case of a single character lexeme. */ infoPtr->start = src; infoPtr->size = 1; infoPtr->next = src+1; parsePtr->term = infoPtr->next; switch (*src) { case '[': infoPtr->lexeme = OPEN_BRACKET; return TCL_OK; case '{': infoPtr->lexeme = OPEN_BRACE; return TCL_OK; case '(': infoPtr->lexeme = OPEN_PAREN; return TCL_OK; case ')': infoPtr->lexeme = CLOSE_PAREN; return TCL_OK; case '$': infoPtr->lexeme = DOLLAR; return TCL_OK; case '\"': infoPtr->lexeme = QUOTE; return TCL_OK; case ',': infoPtr->lexeme = COMMA; return TCL_OK; case '*': infoPtr->lexeme = MULT; return TCL_OK; case '/': infoPtr->lexeme = DIVIDE; return TCL_OK; case '%': infoPtr->lexeme = MOD; return TCL_OK; case '+': infoPtr->lexeme = PLUS; return TCL_OK; case '-': infoPtr->lexeme = MINUS; return TCL_OK; case '?': infoPtr->lexeme = QUESTY; return TCL_OK; case ':': infoPtr->lexeme = COLON; return TCL_OK; case '<': infoPtr->lexeme = LESS; if ((infoPtr->lastChar - src) > 1) { switch (src[1]) { case '<': infoPtr->lexeme = LEFT_SHIFT; infoPtr->size = 2; infoPtr->next = src+2; break; case '=': infoPtr->lexeme = LEQ; infoPtr->size = 2; infoPtr->next = src+2; break; } } parsePtr->term = infoPtr->next; return TCL_OK; case '>': infoPtr->lexeme = GREATER; if ((infoPtr->lastChar - src) > 1) { switch (src[1]) { case '>': infoPtr->lexeme = RIGHT_SHIFT; infoPtr->size = 2; infoPtr->next = src+2; break; case '=': infoPtr->lexeme = GEQ; infoPtr->size = 2; infoPtr->next = src+2; break; } } parsePtr->term = infoPtr->next; return TCL_OK; case '=': infoPtr->lexeme = UNKNOWN; if ((src[1] == '=') && ((infoPtr->lastChar - src) > 1)) { infoPtr->lexeme = EQUAL; infoPtr->size = 2; infoPtr->next = src+2; } parsePtr->term = infoPtr->next; return TCL_OK; case '!': infoPtr->lexeme = NOT; if ((src[1] == '=') && ((infoPtr->lastChar - src) > 1)) { infoPtr->lexeme = NEQ; infoPtr->size = 2; infoPtr->next = src+2; } parsePtr->term = infoPtr->next; return TCL_OK; case '&': infoPtr->lexeme = BIT_AND; if ((src[1] == '&') && ((infoPtr->lastChar - src) > 1)) { infoPtr->lexeme = AND; infoPtr->size = 2; infoPtr->next = src+2; } parsePtr->term = infoPtr->next; return TCL_OK; case '^': infoPtr->lexeme = BIT_XOR; return TCL_OK; case '|': infoPtr->lexeme = BIT_OR; if ((src[1] == '|') && ((infoPtr->lastChar - src) > 1)) { infoPtr->lexeme = OR; infoPtr->size = 2; infoPtr->next = src+2; } parsePtr->term = infoPtr->next; return TCL_OK; case '~': infoPtr->lexeme = BIT_NOT; return TCL_OK; case 'e': if ((src[1] == 'q') && ((infoPtr->lastChar - src) > 1)) { infoPtr->lexeme = STREQ; infoPtr->size = 2; infoPtr->next = src+2; parsePtr->term = infoPtr->next; return TCL_OK; } else { goto checkFuncName; } case 'n': if ((src[1] == 'e') && ((infoPtr->lastChar - src) > 1)) { infoPtr->lexeme = STRNEQ; infoPtr->size = 2; infoPtr->next = src+2; parsePtr->term = infoPtr->next; return TCL_OK; } else { goto checkFuncName; } default: checkFuncName: length = (infoPtr->lastChar - src); if (Tcl_UtfCharComplete(src, length)) { offset = Tcl_UtfToUniChar(src, &ch); } else { char utfBytes[TCL_UTF_MAX]; memcpy(utfBytes, src, (size_t) length); utfBytes[length] = '\0'; offset = Tcl_UtfToUniChar(utfBytes, &ch); } c = UCHAR(ch); if (isalpha(UCHAR(c))) { /* INTL: ISO only. */ infoPtr->lexeme = FUNC_NAME; while (isalnum(UCHAR(c)) || (c == '_')) { /* INTL: ISO only. */ src += offset; length -= offset; if (Tcl_UtfCharComplete(src, length)) { offset = Tcl_UtfToUniChar(src, &ch); } else { char utfBytes[TCL_UTF_MAX]; memcpy(utfBytes, src, (size_t) length); utfBytes[length] = '\0'; offset = Tcl_UtfToUniChar(utfBytes, &ch); } c = UCHAR(ch); } infoPtr->size = (src - infoPtr->start); infoPtr->next = src; parsePtr->term = infoPtr->next; return TCL_OK; } infoPtr->lexeme = UNKNOWN_CHAR; return TCL_OK; } } /* *---------------------------------------------------------------------- * * TclParseInteger -- * * Scans up to numBytes bytes starting at src, and checks whether * the leading bytes look like an integer's string representation. * * Results: * Returns 0 if the leading bytes do not look like an integer. * Otherwise, returns the number of bytes examined that look * like an integer. This may be less than numBytes if the integer * is only the leading part of the string. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclParseInteger(string, numBytes) register CONST char *string;/* The string to examine. */ register int numBytes; /* Max number of bytes to scan. */ { register CONST char *p = string; /* Take care of introductory "0x" */ if ((numBytes > 1) && (p[0] == '0') && ((p[1] == 'x') || (p[1] == 'X'))) { int scanned; Tcl_UniChar ch; p+=2; numBytes -= 2; scanned = TclParseHex(p, numBytes, &ch); if (scanned) { return scanned + 2; } /* Recognize the 0 as valid integer, but x is left behind */ return 1; } while (numBytes && isdigit(UCHAR(*p))) { /* INTL: digit */ numBytes--; p++; } if (numBytes == 0) { return (p - string); } if ((*p != '.') && (*p != 'e') && (*p != 'E')) { return (p - string); } return 0; } /* *---------------------------------------------------------------------- * * ParseMaxDoubleLength -- * * Scans a sequence of bytes checking that the characters could * be in a string rep of a double. * * Results: * Returns the number of bytes starting with string, runing to, but * not including end, all of which could be part of a string rep. * of a double. Only character identity is used, no actual * parsing is done. * * The legal bytes are '0' - '9', 'A' - 'F', 'a' - 'f', * '.', '+', '-', 'i', 'I', 'n', 'N', 'p', 'P', 'x', and 'X'. * This covers the values "Inf" and "Nan" as well as the * decimal and hexadecimal representations recognized by a * C99-compliant strtod(). * * Side effects: * None. * *---------------------------------------------------------------------- */ static int ParseMaxDoubleLength(string, end) register CONST char *string;/* The string to examine. */ CONST char *end; /* Point to the first character past the end * of the string we are examining. */ { CONST char *p = string; while (p < end) { switch (*p) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'I': case 'N': case 'P': case 'X': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'i': case 'n': case 'p': case 'x': case '.': case '+': case '-': p++; break; default: goto done; } } done: return (p - string); } /* *---------------------------------------------------------------------- * * PrependSubExprTokens -- * * This procedure is called after the operands of an subexpression have * been parsed. It generates two tokens: a TCL_TOKEN_SUB_EXPR token for * the subexpression, and a TCL_TOKEN_OPERATOR token for its operator. * These two tokens are inserted before the operand tokens. * * Results: * None. * * Side effects: * If there is insufficient space in parsePtr to hold the new tokens, * additional space is malloc-ed. * *---------------------------------------------------------------------- */ static void PrependSubExprTokens(op, opBytes, src, srcBytes, firstIndex, infoPtr) CONST char *op; /* Points to first byte of the operator * in the source script. */ int opBytes; /* Number of bytes in the operator. */ CONST char *src; /* Points to first byte of the subexpression * in the source script. */ int srcBytes; /* Number of bytes in subexpression's * source. */ int firstIndex; /* Index of first token already emitted for * operator's first (or only) operand. */ ParseInfo *infoPtr; /* Holds the parse state for the * expression being parsed. */ { Tcl_Parse *parsePtr = infoPtr->parsePtr; Tcl_Token *tokenPtr, *firstTokenPtr; int numToMove; if ((parsePtr->numTokens + 1) >= parsePtr->tokensAvailable) { TclExpandTokenArray(parsePtr); } firstTokenPtr = &parsePtr->tokenPtr[firstIndex]; tokenPtr = (firstTokenPtr + 2); numToMove = (parsePtr->numTokens - firstIndex); memmove((VOID *) tokenPtr, (VOID *) firstTokenPtr, (size_t) (numToMove * sizeof(Tcl_Token))); parsePtr->numTokens += 2; tokenPtr = firstTokenPtr; tokenPtr->type = TCL_TOKEN_SUB_EXPR; tokenPtr->start = src; tokenPtr->size = srcBytes; tokenPtr->numComponents = parsePtr->numTokens - (firstIndex + 1); tokenPtr++; tokenPtr->type = TCL_TOKEN_OPERATOR; tokenPtr->start = op; tokenPtr->size = opBytes; tokenPtr->numComponents = 0; } /* *---------------------------------------------------------------------- * * LogSyntaxError -- * * This procedure is invoked after an error occurs when parsing an * expression. It sets the interpreter result to an error message * describing the error. * * Results: * None. * * Side effects: * Sets the interpreter result to an error message describing the * expression that was being parsed when the error occurred, and why * the parser considers that to be a syntax error at all. * *---------------------------------------------------------------------- */ static void LogSyntaxError(infoPtr, extraInfo) ParseInfo *infoPtr; /* Holds the parse state for the * expression being parsed. */ CONST char *extraInfo; /* String to provide extra information * about the syntax error. */ { int numBytes = (infoPtr->lastChar - infoPtr->originalExpr); char buffer[100]; if (numBytes > 60) { sprintf(buffer, "syntax error in expression \"%.60s...\"", infoPtr->originalExpr); } else { sprintf(buffer, "syntax error in expression \"%.*s\"", numBytes, infoPtr->originalExpr); } Tcl_ResetResult(infoPtr->parsePtr->interp); Tcl_AppendStringsToObj(Tcl_GetObjResult(infoPtr->parsePtr->interp), buffer, ": ", extraInfo, (char *) NULL); infoPtr->parsePtr->errorType = TCL_PARSE_SYNTAX; infoPtr->parsePtr->term = infoPtr->start; } tcl8.4.20/generic/regerror.c0000644003604700454610000000666212052456743014336 0ustar dgp771div/* * regerror - error-code expansion * * Copyright (c) 1998, 1999 Henry Spencer. All rights reserved. * * Development of this software was funded, in part, by Cray Research Inc., * UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics * Corporation, none of whom are responsible for the results. The author * thanks all of them. * * Redistribution and use in source and binary forms -- with or without * modification -- are permitted for any purpose, provided that * redistributions in source form retain this entire copyright notice and * indicate the origin and nature of any modifications. * * I'd appreciate being given credit for this package in the documentation * of software which uses it, but that is not a requirement. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * HENRY SPENCER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include "regguts.h" /* unknown-error explanation */ static CONST char unk[] = "*** unknown regex error code 0x%x ***"; /* struct to map among codes, code names, and explanations */ static struct rerr { int code; char *name; char *explain; } rerrs[] = { /* the actual table is built from regex.h */ # include "regerrs.h" { -1, "", "oops" }, /* explanation special-cased in code */ }; /* - regerror - the interface to error numbers */ /* ARGSUSED */ size_t /* actual space needed (including NUL) */ regerror(code, preg, errbuf, errbuf_size) int code; /* error code, or REG_ATOI or REG_ITOA */ CONST regex_t *preg; /* associated regex_t (unused at present) */ char *errbuf; /* result buffer (unless errbuf_size==0) */ size_t errbuf_size; /* available space in errbuf, can be 0 */ { struct rerr *r; char *msg; char convbuf[sizeof(unk)+50]; /* 50 = plenty for int */ size_t len; int icode; switch (code) { case REG_ATOI: /* convert name to number */ for (r = rerrs; r->code >= 0; r++) if (strcmp(r->name, errbuf) == 0) break; sprintf(convbuf, "%d", r->code); /* -1 for unknown */ msg = convbuf; break; case REG_ITOA: /* convert number to name */ icode = atoi(errbuf); /* not our problem if this fails */ for (r = rerrs; r->code >= 0; r++) if (r->code == icode) break; if (r->code >= 0) msg = r->name; else { /* unknown; tell him the number */ sprintf(convbuf, "REG_%u", (unsigned)icode); msg = convbuf; } break; default: /* a real, normal error code */ for (r = rerrs; r->code >= 0; r++) if (r->code == code) break; if (r->code >= 0) msg = r->explain; else { /* unknown; say so */ sprintf(convbuf, unk, code); msg = convbuf; } break; } len = strlen(msg) + 1; /* space needed, including NUL */ if (errbuf_size > 0) { if (errbuf_size > len) strcpy(errbuf, msg); else { /* truncate to fit */ strncpy(errbuf, msg, errbuf_size-1); errbuf[errbuf_size-1] = '\0'; } } return len; } tcl8.4.20/generic/regc_cvec.c0000644003604700454610000001127711737050674014427 0ustar dgp771div/* * Utility functions for handling cvecs * This file is #included by regcomp.c. * * Copyright (c) 1998, 1999 Henry Spencer. All rights reserved. * * Development of this software was funded, in part, by Cray Research Inc., * UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics * Corporation, none of whom are responsible for the results. The author * thanks all of them. * * Redistribution and use in source and binary forms -- with or without * modification -- are permitted for any purpose, provided that * redistributions in source form retain this entire copyright notice and * indicate the origin and nature of any modifications. * * I'd appreciate being given credit for this package in the documentation * of software which uses it, but that is not a requirement. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * HENRY SPENCER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ /* - newcvec - allocate a new cvec ^ static struct cvec *newcvec(int, int, int); */ static struct cvec * newcvec(nchrs, nranges, nmcces) int nchrs; /* to hold this many chrs... */ int nranges; /* ... and this many ranges... */ int nmcces; /* ... and this many MCCEs */ { size_t n; size_t nc; struct cvec *cv; nc = (size_t)nchrs + (size_t)nmcces*(MAXMCCE+1) + (size_t)nranges*2; n = sizeof(struct cvec) + (size_t)(nmcces-1)*sizeof(chr *) + nc*sizeof(chr); cv = (struct cvec *)MALLOC(n); if (cv == NULL) { return NULL; } cv->chrspace = nchrs; cv->chrs = (chr *)&cv->mcces[nmcces]; /* chrs just after MCCE ptrs */ cv->mccespace = nmcces; cv->ranges = cv->chrs + nchrs + nmcces*(MAXMCCE+1); cv->rangespace = nranges; return clearcvec(cv); } /* - clearcvec - clear a possibly-new cvec * Returns pointer as convenience. ^ static struct cvec *clearcvec(struct cvec *); */ static struct cvec * clearcvec(cv) struct cvec *cv; /* character vector */ { int i; assert(cv != NULL); cv->nchrs = 0; assert(cv->chrs == (chr *)&cv->mcces[cv->mccespace]); cv->nmcces = 0; cv->nmccechrs = 0; cv->nranges = 0; for (i = 0; i < cv->mccespace; i++) { cv->mcces[i] = NULL; } return cv; } /* - addchr - add a chr to a cvec ^ static VOID addchr(struct cvec *, pchr); */ static VOID addchr(cv, c) struct cvec *cv; /* character vector */ pchr c; /* character to add */ { assert(cv->nchrs < cv->chrspace - cv->nmccechrs); cv->chrs[cv->nchrs++] = (chr)c; } /* - addrange - add a range to a cvec ^ static VOID addrange(struct cvec *, pchr, pchr); */ static VOID addrange(cv, from, to) struct cvec *cv; /* character vector */ pchr from; /* first character of range */ pchr to; /* last character of range */ { assert(cv->nranges < cv->rangespace); cv->ranges[cv->nranges*2] = (chr)from; cv->ranges[cv->nranges*2 + 1] = (chr)to; cv->nranges++; } /* - haschr - does a cvec contain this chr? ^ static int haschr(struct cvec *, pchr); */ static int /* predicate */ haschr(cv, c) struct cvec *cv; /* character vector */ pchr c; /* character to test for */ { int i; chr *p; for (p = cv->chrs, i = cv->nchrs; i > 0; p++, i--) { if (*p == c) { return 1; } } for (p = cv->ranges, i = cv->nranges; i > 0; p += 2, i--) { if ((*p <= c) && (c <= *(p+1))) { return 1; } } return 0; } /* - getcvec - get a cvec, remembering it as v->cv ^ static struct cvec *getcvec(struct vars *, int, int); */ static struct cvec * getcvec(v, nchrs, nranges) struct vars *v; /* context */ int nchrs; /* to hold this many chrs... */ int nranges; /* ... and this many ranges... */ { if (v->cv != NULL && nchrs <= v->cv->chrspace && nranges <= v->cv->rangespace) { return clearcvec(v->cv); } if (v->cv != NULL) { freecvec(v->cv); } v->cv = newcvec(nchrs, nranges, 0); if (v->cv == NULL) { ERR(REG_ESPACE); } return v->cv; } /* - freecvec - free a cvec ^ static VOID freecvec(struct cvec *); */ static VOID freecvec(cv) struct cvec *cv; /* character vector */ { FREE(cv); } tcl8.4.20/generic/tclFCmd.c0000644003604700454610000007057212133546540014017 0ustar dgp771div/* * tclFCmd.c * * This file implements the generic portion of file manipulation * subcommands of the "file" command. * * Copyright (c) 1996-1998 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef _WIN64 /* See [Bug 3354324]: file mtime sets wrong time */ # define _USE_32BIT_TIME_T #endif #include #include "tclInt.h" #include "tclPort.h" /* * Declarations for local procedures defined in this file: */ static int CopyRenameOneFile _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr, int copyFlag, int force)); static Tcl_Obj * FileBasename _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *pathPtr)); static int FileCopyRename _ANSI_ARGS_((Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], int copyFlag)); static int FileForceOption _ANSI_ARGS_((Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], int *forcePtr)); /* *--------------------------------------------------------------------------- * * TclFileRenameCmd * * This procedure implements the "rename" subcommand of the "file" * command. Filename arguments need to be translated to native * format before being passed to platform-specific code that * implements rename functionality. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *--------------------------------------------------------------------------- */ int TclFileRenameCmd(interp, objc, objv) Tcl_Interp *interp; /* Interp for error reporting. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings passed to Tcl_FileCmd. */ { return FileCopyRename(interp, objc, objv, 0); } /* *--------------------------------------------------------------------------- * * TclFileCopyCmd * * This procedure implements the "copy" subcommand of the "file" * command. Filename arguments need to be translated to native * format before being passed to platform-specific code that * implements copy functionality. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *--------------------------------------------------------------------------- */ int TclFileCopyCmd(interp, objc, objv) Tcl_Interp *interp; /* Used for error reporting */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings passed to Tcl_FileCmd. */ { return FileCopyRename(interp, objc, objv, 1); } /* *--------------------------------------------------------------------------- * * FileCopyRename -- * * Performs the work of TclFileRenameCmd and TclFileCopyCmd. * See comments for those procedures. * * Results: * See above. * * Side effects: * See above. * *--------------------------------------------------------------------------- */ static int FileCopyRename(interp, objc, objv, copyFlag) Tcl_Interp *interp; /* Used for error reporting. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings passed to Tcl_FileCmd. */ int copyFlag; /* If non-zero, copy source(s). Otherwise, * rename them. */ { int i, result, force; Tcl_StatBuf statBuf; Tcl_Obj *target; i = FileForceOption(interp, objc - 2, objv + 2, &force); if (i < 0) { return TCL_ERROR; } i += 2; if ((objc - i) < 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetString(objv[0]), " ", Tcl_GetString(objv[1]), " ?options? source ?source ...? target\"", (char *) NULL); return TCL_ERROR; } /* * If target doesn't exist or isn't a directory, try the copy/rename. * More than 2 arguments is only valid if the target is an existing * directory. */ target = objv[objc - 1]; if (Tcl_FSConvertToPathType(interp, target) != TCL_OK) { return TCL_ERROR; } result = TCL_OK; /* * Call Tcl_FSStat() so that if target is a symlink that points to a * directory we will put the sources in that directory instead of * overwriting the symlink. */ if ((Tcl_FSStat(target, &statBuf) != 0) || !S_ISDIR(statBuf.st_mode)) { if ((objc - i) > 2) { errno = ENOTDIR; Tcl_PosixError(interp); Tcl_AppendResult(interp, "error ", ((copyFlag) ? "copying" : "renaming"), ": target \"", Tcl_GetString(target), "\" is not a directory", (char *) NULL); result = TCL_ERROR; } else { /* * Even though already have target == translated(objv[i+1]), * pass the original argument down, so if there's an error, the * error message will reflect the original arguments. */ result = CopyRenameOneFile(interp, objv[i], objv[i + 1], copyFlag, force); } return result; } /* * Move each source file into target directory. Extract the basename * from each source, and append it to the end of the target path. */ for ( ; i < objc - 1; i++) { Tcl_Obj *jargv[2]; Tcl_Obj *source, *newFileName; Tcl_Obj *temp; source = FileBasename(interp, objv[i]); if (source == NULL) { result = TCL_ERROR; break; } jargv[0] = objv[objc - 1]; jargv[1] = source; temp = Tcl_NewListObj(2, jargv); newFileName = Tcl_FSJoinPath(temp, -1); Tcl_IncrRefCount(newFileName); result = CopyRenameOneFile(interp, objv[i], newFileName, copyFlag, force); Tcl_DecrRefCount(newFileName); Tcl_DecrRefCount(temp); Tcl_DecrRefCount(source); if (result == TCL_ERROR) { break; } } return result; } /* *--------------------------------------------------------------------------- * * TclFileMakeDirsCmd * * This procedure implements the "mkdir" subcommand of the "file" * command. Filename arguments need to be translated to native * format before being passed to platform-specific code that * implements mkdir functionality. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ int TclFileMakeDirsCmd(interp, objc, objv) Tcl_Interp *interp; /* Used for error reporting. */ int objc; /* Number of arguments */ Tcl_Obj *CONST objv[]; /* Argument strings passed to Tcl_FileCmd. */ { Tcl_Obj *errfile; int result, i, j, pobjc; Tcl_Obj *split = NULL; Tcl_Obj *target = NULL; Tcl_StatBuf statBuf; errfile = NULL; result = TCL_OK; for (i = 2; i < objc; i++) { if (Tcl_FSConvertToPathType(interp, objv[i]) != TCL_OK) { result = TCL_ERROR; break; } split = Tcl_FSSplitPath(objv[i],&pobjc); if (pobjc == 0) { errno = ENOENT; errfile = objv[i]; break; } for (j = 0; j < pobjc; j++) { target = Tcl_FSJoinPath(split, j + 1); Tcl_IncrRefCount(target); /* * Call Tcl_FSStat() so that if target is a symlink that * points to a directory we will create subdirectories in * that directory. */ if (Tcl_FSStat(target, &statBuf) == 0) { if (!S_ISDIR(statBuf.st_mode)) { errno = EEXIST; errfile = target; goto done; } } else if (errno != ENOENT) { /* * If Tcl_FSStat() failed and the error is anything * other than non-existence of the target, throw the * error. */ errfile = target; goto done; } else if (Tcl_FSCreateDirectory(target) != TCL_OK) { /* * Create might have failed because of being in a race * condition with another process trying to create the * same subdirectory. */ if (errno == EEXIST) { if ((Tcl_FSStat(target, &statBuf) == 0) && S_ISDIR(statBuf.st_mode)) { /* * It is a directory that wasn't there before, * so keep going without error. */ Tcl_ResetResult(interp); } else { errfile = target; goto done; } } else { errfile = target; goto done; } } /* Forget about this sub-path */ Tcl_DecrRefCount(target); target = NULL; } Tcl_DecrRefCount(split); split = NULL; } done: if (errfile != NULL) { Tcl_AppendResult(interp, "can't create directory \"", Tcl_GetString(errfile), "\": ", Tcl_PosixError(interp), (char *) NULL); result = TCL_ERROR; } if (split != NULL) { Tcl_DecrRefCount(split); } if (target != NULL) { Tcl_DecrRefCount(target); } return result; } /* *---------------------------------------------------------------------- * * TclFileDeleteCmd * * This procedure implements the "delete" subcommand of the "file" * command. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ int TclFileDeleteCmd(interp, objc, objv) Tcl_Interp *interp; /* Used for error reporting */ int objc; /* Number of arguments */ Tcl_Obj *CONST objv[]; /* Argument strings passed to Tcl_FileCmd. */ { int i, force, result; Tcl_Obj *errfile; Tcl_Obj *errorBuffer = NULL; i = FileForceOption(interp, objc - 2, objv + 2, &force); if (i < 0) { return TCL_ERROR; } i += 2; if ((objc - i) < 1) { Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetString(objv[0]), " ", Tcl_GetString(objv[1]), " ?options? file ?file ...?\"", (char *) NULL); return TCL_ERROR; } errfile = NULL; result = TCL_OK; for ( ; i < objc; i++) { Tcl_StatBuf statBuf; errfile = objv[i]; if (Tcl_FSConvertToPathType(interp, objv[i]) != TCL_OK) { result = TCL_ERROR; goto done; } /* * Call lstat() to get info so can delete symbolic link itself. */ if (Tcl_FSLstat(objv[i], &statBuf) != 0) { /* * Trying to delete a file that does not exist is not * considered an error, just a no-op */ if (errno != ENOENT) { result = TCL_ERROR; } } else if (S_ISDIR(statBuf.st_mode)) { /* * We own a reference count on errorBuffer, if it was set * as a result of this call. */ result = Tcl_FSRemoveDirectory(objv[i], force, &errorBuffer); if (result != TCL_OK) { if ((force == 0) && (errno == EEXIST)) { Tcl_AppendResult(interp, "error deleting \"", Tcl_GetString(objv[i]), "\": directory not empty", (char *) NULL); Tcl_PosixError(interp); goto done; } /* * If possible, use the untranslated name for the file. */ errfile = errorBuffer; /* FS supposed to check between translated objv and errfile */ if (Tcl_FSEqualPaths(objv[i], errfile)) { errfile = objv[i]; } } } else { result = Tcl_FSDeleteFile(objv[i]); } if (result != TCL_OK) { result = TCL_ERROR; /* * It is important that we break on error, otherwise we * might end up owning reference counts on numerous * errorBuffers. */ break; } } if (result != TCL_OK) { if (errfile == NULL) { /* * We try to accomodate poor error results from our * Tcl_FS calls */ Tcl_AppendResult(interp, "error deleting unknown file: ", Tcl_PosixError(interp), (char *) NULL); } else { Tcl_AppendResult(interp, "error deleting \"", Tcl_GetString(errfile), "\": ", Tcl_PosixError(interp), (char *) NULL); } } done: if (errorBuffer != NULL) { Tcl_DecrRefCount(errorBuffer); } return result; } /* *--------------------------------------------------------------------------- * * CopyRenameOneFile * * Copies or renames specified source file or directory hierarchy * to the specified target. * * Results: * A standard Tcl result. * * Side effects: * Target is overwritten if the force flag is set. Attempting to * copy/rename a file onto a directory or a directory onto a file * will always result in an error. * *---------------------------------------------------------------------- */ static int CopyRenameOneFile(interp, source, target, copyFlag, force) Tcl_Interp *interp; /* Used for error reporting. */ Tcl_Obj *source; /* Pathname of file to copy. May need to * be translated. */ Tcl_Obj *target; /* Pathname of file to create/overwrite. * May need to be translated. */ int copyFlag; /* If non-zero, copy files. Otherwise, * rename them. */ int force; /* If non-zero, overwrite target file if it * exists. Otherwise, error if target already * exists. */ { int result; Tcl_Obj *errfile, *errorBuffer; /* If source is a link, then this is the real file/directory */ Tcl_Obj *actualSource = NULL; Tcl_StatBuf sourceStatBuf, targetStatBuf; if (Tcl_FSConvertToPathType(interp, source) != TCL_OK) { return TCL_ERROR; } if (Tcl_FSConvertToPathType(interp, target) != TCL_OK) { return TCL_ERROR; } errfile = NULL; errorBuffer = NULL; result = TCL_ERROR; /* * We want to copy/rename links and not the files they point to, so we * use lstat(). If target is a link, we also want to replace the * link and not the file it points to, so we also use lstat() on the * target. */ if (Tcl_FSLstat(source, &sourceStatBuf) != 0) { errfile = source; goto done; } if (Tcl_FSLstat(target, &targetStatBuf) != 0) { if (errno != ENOENT) { errfile = target; goto done; } } else { if (force == 0) { errno = EEXIST; errfile = target; goto done; } /* * Prevent copying or renaming a file onto itself. On Windows since * 8.5 we do get an inode number, however the unsigned short field is * insufficient to accept the Win32 API file id so it is truncated to * 16 bits and we get collisions. See bug #2015723. */ #if !defined(WIN32) && !defined(__CYGWIN__) if ((sourceStatBuf.st_ino != 0) && (targetStatBuf.st_ino != 0)) { if ((sourceStatBuf.st_ino == targetStatBuf.st_ino) && (sourceStatBuf.st_dev == targetStatBuf.st_dev)) { result = TCL_OK; goto done; } } #endif /* * Prevent copying/renaming a file onto a directory and * vice-versa. This is a policy decision based on the fact that * existing implementations of copy and rename on all platforms * also prevent this. */ if (S_ISDIR(sourceStatBuf.st_mode) && !S_ISDIR(targetStatBuf.st_mode)) { errno = EISDIR; Tcl_AppendResult(interp, "can't overwrite file \"", Tcl_GetString(target), "\" with directory \"", Tcl_GetString(source), "\"", (char *) NULL); goto done; } if (!S_ISDIR(sourceStatBuf.st_mode) && S_ISDIR(targetStatBuf.st_mode)) { errno = EISDIR; Tcl_AppendResult(interp, "can't overwrite directory \"", Tcl_GetString(target), "\" with file \"", Tcl_GetString(source), "\"", (char *) NULL); goto done; } } if (copyFlag == 0) { result = Tcl_FSRenameFile(source, target); if (result == TCL_OK) { goto done; } if (errno == EINVAL) { Tcl_AppendResult(interp, "error renaming \"", Tcl_GetString(source), "\" to \"", Tcl_GetString(target), "\": trying to rename a volume or ", "move a directory into itself", (char *) NULL); goto done; } else if (errno != EXDEV) { errfile = target; goto done; } /* * The rename failed because the move was across file systems. * Fall through to copy file and then remove original. Note that * the low-level Tcl_FSRenameFileProc in the filesystem is allowed * to implement cross-filesystem moves itself, if it desires. */ } actualSource = source; Tcl_IncrRefCount(actualSource); #if 0 #ifdef S_ISLNK /* * To add a flag to make 'copy' copy links instead of files, we could * add a condition to ignore this 'if' here. */ if (copyFlag && S_ISLNK(sourceStatBuf.st_mode)) { /* * We want to copy files not links. Therefore we must follow the * link. There are two purposes to this 'stat' call here. First * we want to know if the linked-file/dir actually exists, and * second, in the block of code which follows, some 20 lines * down, we want to check if the thing is a file or directory. */ if (Tcl_FSStat(source, &sourceStatBuf) != 0) { /* Actual file doesn't exist */ Tcl_AppendResult(interp, "error copying \"", Tcl_GetString(source), "\": the target of this link doesn't exist", (char *) NULL); goto done; } else { int counter = 0; while (1) { Tcl_Obj *path = Tcl_FSLink(actualSource, NULL, 0); if (path == NULL) { break; } Tcl_DecrRefCount(actualSource); actualSource = path; counter++; /* Arbitrary limit of 20 links to follow */ if (counter > 20) { /* Too many links */ Tcl_SetErrno(EMLINK); errfile = source; goto done; } } /* Now 'actualSource' is the correct file */ } } #endif #endif if (S_ISDIR(sourceStatBuf.st_mode)) { result = Tcl_FSCopyDirectory(actualSource, target, &errorBuffer); if (result != TCL_OK) { if (errno == EXDEV) { /* * The copy failed because we're trying to do a * cross-filesystem copy. We do this through our Tcl * library. */ Tcl_SavedResult savedResult; Tcl_Obj *copyCommand = Tcl_NewListObj(0,NULL); Tcl_IncrRefCount(copyCommand); Tcl_ListObjAppendElement(interp, copyCommand, Tcl_NewStringObj("::tcl::CopyDirectory",-1)); if (copyFlag) { Tcl_ListObjAppendElement(interp, copyCommand, Tcl_NewStringObj("copying",-1)); } else { Tcl_ListObjAppendElement(interp, copyCommand, Tcl_NewStringObj("renaming",-1)); } Tcl_ListObjAppendElement(interp, copyCommand, source); Tcl_ListObjAppendElement(interp, copyCommand, target); Tcl_SaveResult(interp, &savedResult); result = Tcl_EvalObjEx(interp, copyCommand, TCL_EVAL_GLOBAL | TCL_EVAL_DIRECT); Tcl_DecrRefCount(copyCommand); if (result != TCL_OK) { /* * There was an error in the Tcl-level copy. * We will pass on the Tcl error message and * can ensure this by setting errfile to NULL */ Tcl_DiscardResult(&savedResult); errfile = NULL; } else { /* The copy was successful */ Tcl_RestoreResult(interp, &savedResult); } } else { errfile = errorBuffer; if (Tcl_FSEqualPaths(errfile, source)) { errfile = source; } else if (Tcl_FSEqualPaths(errfile, target)) { errfile = target; } } } } else { result = Tcl_FSCopyFile(actualSource, target); if ((result != TCL_OK) && (errno == EXDEV)) { result = TclCrossFilesystemCopy(interp, source, target); } if (result != TCL_OK) { /* * We could examine 'errno' to double-check if the problem * was with the target, but we checked the source above, * so it should be quite clear */ errfile = target; } /* * We now need to reset the result, because the above call, * may have left set it. (Ideally we would prefer not to pass * an interpreter in above, but the channel IO code used by * TclCrossFilesystemCopy currently requires one) */ Tcl_ResetResult(interp); } if ((copyFlag == 0) && (result == TCL_OK)) { if (S_ISDIR(sourceStatBuf.st_mode)) { result = Tcl_FSRemoveDirectory(source, 1, &errorBuffer); if (result != TCL_OK) { if (Tcl_FSEqualPaths(errfile, source) == 0) { errfile = source; } } } else { result = Tcl_FSDeleteFile(source); if (result != TCL_OK) { errfile = source; } } if (result != TCL_OK) { Tcl_AppendResult(interp, "can't unlink \"", Tcl_GetString(errfile), "\": ", Tcl_PosixError(interp), (char *) NULL); errfile = NULL; } } done: if (errfile != NULL) { Tcl_AppendResult(interp, ((copyFlag) ? "error copying \"" : "error renaming \""), Tcl_GetString(source), (char *) NULL); if (errfile != source) { Tcl_AppendResult(interp, "\" to \"", Tcl_GetString(target), (char *) NULL); if (errfile != target) { Tcl_AppendResult(interp, "\": \"", Tcl_GetString(errfile), (char *) NULL); } } Tcl_AppendResult(interp, "\": ", Tcl_PosixError(interp), (char *) NULL); } if (errorBuffer != NULL) { Tcl_DecrRefCount(errorBuffer); } if (actualSource != NULL) { Tcl_DecrRefCount(actualSource); } return result; } /* *--------------------------------------------------------------------------- * * FileForceOption -- * * Helps parse command line options for file commands that take * the "-force" and "--" options. * * Results: * The return value is how many arguments from argv were consumed * by this function, or -1 if there was an error parsing the * options. If an error occurred, an error message is left in the * interp's result. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int FileForceOption(interp, objc, objv, forcePtr) Tcl_Interp *interp; /* Interp, for error return. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. First command line * option, if it exists, begins at 0. */ int *forcePtr; /* If the "-force" was specified, *forcePtr * is filled with 1, otherwise with 0. */ { int force, i; force = 0; for (i = 0; i < objc; i++) { if (Tcl_GetString(objv[i])[0] != '-') { break; } if (strcmp(Tcl_GetString(objv[i]), "-force") == 0) { force = 1; } else if (strcmp(Tcl_GetString(objv[i]), "--") == 0) { i++; break; } else { Tcl_AppendResult(interp, "bad option \"", Tcl_GetString(objv[i]), "\": should be -force or --", (char *)NULL); return -1; } } *forcePtr = force; return i; } /* *--------------------------------------------------------------------------- * * FileBasename -- * * Given a path in either tcl format (with / separators), or in the * platform-specific format for the current platform, return all the * characters in the path after the last directory separator. But, * if path is the root directory, returns no characters. * * Results: * Returns the string object that represents the basename. If there * is an error, an error message is left in interp, and NULL is * returned. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static Tcl_Obj * FileBasename(interp, pathPtr) Tcl_Interp *interp; /* Interp, for error return. */ Tcl_Obj *pathPtr; /* Path whose basename to extract. */ { int objc; Tcl_Obj *splitPtr; Tcl_Obj *resultPtr = NULL; splitPtr = Tcl_FSSplitPath(pathPtr, &objc); if (objc != 0) { if ((objc == 1) && (*Tcl_GetString(pathPtr) == '~')) { Tcl_DecrRefCount(splitPtr); if (Tcl_FSConvertToPathType(interp, pathPtr) != TCL_OK) { return NULL; } splitPtr = Tcl_FSSplitPath(pathPtr, &objc); } /* * Return the last component, unless it is the only component, and it * is the root of an absolute path. */ if (objc > 0) { Tcl_ListObjIndex(NULL, splitPtr, objc-1, &resultPtr); if ((objc == 1) && (Tcl_FSGetPathType(resultPtr) != TCL_PATH_RELATIVE)) { resultPtr = NULL; } } } if (resultPtr == NULL) { resultPtr = Tcl_NewObj(); } Tcl_IncrRefCount(resultPtr); Tcl_DecrRefCount(splitPtr); return resultPtr; } /* *---------------------------------------------------------------------- * * TclFileAttrsCmd -- * * Sets or gets the platform-specific attributes of a file. The * objc-objv points to the file name with the rest of the command * line following. This routine uses platform-specific tables of * option strings and callbacks. The callback to get the * attributes take three parameters: * Tcl_Interp *interp; The interp to report errors with. * Since this is an object-based API, * the object form of the result should * be used. * CONST char *fileName; This is extracted using * Tcl_TranslateFileName. * TclObj **attrObjPtrPtr; A new object to hold the attribute * is allocated and put here. * The first two parameters of the callback used to write out the * attributes are the same. The third parameter is: * CONST *attrObjPtr; A pointer to the object that has * the new attribute. * They both return standard TCL errors; if the routine to get * an attribute fails, no object is allocated and *attrObjPtrPtr * is unchanged. * * Results: * Standard TCL error. * * Side effects: * May set file attributes for the file name. * *---------------------------------------------------------------------- */ int TclFileAttrsCmd(interp, objc, objv) Tcl_Interp *interp; /* The interpreter for error reporting. */ int objc; /* Number of command line arguments. */ Tcl_Obj *CONST objv[]; /* The command line objects. */ { int result; CONST char ** attributeStrings; Tcl_Obj* objStrings = NULL; int numObjStrings = -1; Tcl_Obj *filePtr; if (objc < 3) { Tcl_WrongNumArgs(interp, 2, objv, "name ?option? ?value? ?option value ...?"); return TCL_ERROR; } filePtr = objv[2]; if (Tcl_FSConvertToPathType(interp, filePtr) != TCL_OK) { return TCL_ERROR; } objc -= 3; objv += 3; result = TCL_ERROR; Tcl_SetErrno(0); attributeStrings = Tcl_FSFileAttrStrings(filePtr, &objStrings); if (attributeStrings == NULL) { int index; Tcl_Obj *objPtr; if (objStrings == NULL) { if (Tcl_GetErrno() != 0) { /* * There was an error, probably that the filePtr is * not accepted by any filesystem */ Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "could not read \"", Tcl_GetString(filePtr), "\": ", Tcl_PosixError(interp), (char *) NULL); return TCL_ERROR; } goto end; } /* We own the object now */ Tcl_IncrRefCount(objStrings); /* Use objStrings as a list object */ if (Tcl_ListObjLength(interp, objStrings, &numObjStrings) != TCL_OK) { goto end; } attributeStrings = (CONST char **) ckalloc ((1+numObjStrings) * sizeof(char*)); for (index = 0; index < numObjStrings; index++) { Tcl_ListObjIndex(interp, objStrings, index, &objPtr); attributeStrings[index] = Tcl_GetString(objPtr); } attributeStrings[index] = NULL; } if (objc == 0) { /* * Get all attributes. */ int index; Tcl_Obj *listPtr; listPtr = Tcl_NewListObj(0, NULL); for (index = 0; attributeStrings[index] != NULL; index++) { Tcl_Obj *objPtr = Tcl_NewStringObj(attributeStrings[index], -1); Tcl_ListObjAppendElement(interp, listPtr, objPtr); /* We now forget about objPtr, it is in the list */ objPtr = NULL; if (Tcl_FSFileAttrsGet(interp, index, filePtr, &objPtr) != TCL_OK) { Tcl_DecrRefCount(listPtr); goto end; } Tcl_ListObjAppendElement(interp, listPtr, objPtr); } Tcl_SetObjResult(interp, listPtr); } else if (objc == 1) { /* * Get one attribute. */ int index; Tcl_Obj *objPtr = NULL; if (numObjStrings == 0) { Tcl_AppendResult(interp, "bad option \"", Tcl_GetString(objv[0]), "\", there are no file attributes" " in this filesystem.", (char *) NULL); goto end; } if (Tcl_GetIndexFromObj(interp, objv[0], attributeStrings, "option", 0, &index) != TCL_OK) { goto end; } if (numObjStrings != -1 && objv[0]->typePtr != NULL && objv[0]->typePtr->freeIntRepProc != NULL) { objv[0]->typePtr->freeIntRepProc(objv[0]); objv[0]->typePtr = NULL; } if (Tcl_FSFileAttrsGet(interp, index, filePtr, &objPtr) != TCL_OK) { goto end; } Tcl_SetObjResult(interp, objPtr); } else { /* * Set option/value pairs. */ int i, index; if (numObjStrings == 0) { Tcl_AppendResult(interp, "bad option \"", Tcl_GetString(objv[0]), "\", there are no file attributes" " in this filesystem.", (char *) NULL); goto end; } for (i = 0; i < objc ; i += 2) { if (Tcl_GetIndexFromObj(interp, objv[i], attributeStrings, "option", 0, &index) != TCL_OK) { goto end; } if (numObjStrings != -1 && objv[i]->typePtr != NULL && objv[i]->typePtr->freeIntRepProc != NULL) { objv[i]->typePtr->freeIntRepProc(objv[i]); objv[i]->typePtr = NULL; } if (i + 1 == objc) { Tcl_AppendResult(interp, "value for \"", Tcl_GetString(objv[i]), "\" missing", (char *) NULL); goto end; } if (Tcl_FSFileAttrsSet(interp, index, filePtr, objv[i + 1]) != TCL_OK) { goto end; } } } result = TCL_OK; end: if (numObjStrings != -1) { /* Free up the array we allocated */ ckfree((char*)attributeStrings); /* * We don't need this object that was passed to us * any more. */ if (objStrings != NULL) { Tcl_DecrRefCount(objStrings); } } return result; } tcl8.4.20/generic/regfronts.c0000644003604700454610000000453211737050674014514 0ustar dgp771div/* * regcomp and regexec - front ends to re_ routines * * Mostly for implementation of backward-compatibility kludges. Note * that these routines exist ONLY in char versions. * * Copyright (c) 1998, 1999 Henry Spencer. All rights reserved. * * Development of this software was funded, in part, by Cray Research Inc., * UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics * Corporation, none of whom are responsible for the results. The author * thanks all of them. * * Redistribution and use in source and binary forms -- with or without * modification -- are permitted for any purpose, provided that * redistributions in source form retain this entire copyright notice and * indicate the origin and nature of any modifications. * * I'd appreciate being given credit for this package in the documentation * of software which uses it, but that is not a requirement. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * HENRY SPENCER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include "regguts.h" /* - regcomp - compile regular expression */ int regcomp(re, str, flags) regex_t *re; CONST char *str; int flags; { size_t len; int f = flags; if (f®_PEND) { len = re->re_endp - str; f &= ~REG_PEND; } else len = strlen(str); return re_comp(re, str, len, f); } /* - regexec - execute regular expression */ int regexec(re, str, nmatch, pmatch, flags) regex_t *re; CONST char *str; size_t nmatch; regmatch_t pmatch[]; int flags; { CONST char *start; size_t len; int f = flags; if (f®_STARTEND) { start = str + pmatch[0].rm_so; len = pmatch[0].rm_eo - pmatch[0].rm_so; f &= ~REG_STARTEND; } else { start = str; len = strlen(str); } return re_exec(re, start, len, nmatch, pmatch, f); } tcl8.4.20/generic/tclIOUtil.c0000644003604700454610000056572512052456744014372 0ustar dgp771div/* * tclIOUtil.c -- * * This file contains the implementation of Tcl's generic * filesystem code, which supports a pluggable filesystem * architecture allowing both platform specific filesystems and * 'virtual filesystems'. All filesystem access should go through * the functions defined in this file. Most of this code was * contributed by Vince Darley. * * Parts of this file are based on code contributed by Karl * Lehenbauer, Mark Diekhans and Peter da Silva. * * Copyright (c) 1991-1994 The Regents of the University of California. * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef _WIN64 /* See [Bug 3354324]: file mtime sets wrong time */ # define _USE_32BIT_TIME_T #endif #include #include "tclInt.h" #include "tclPort.h" #ifdef __WIN32__ /* for tclWinProcs->useWide */ #include "tclWinInt.h" #endif /* * struct FilesystemRecord -- * * A filesystem record is used to keep track of each * filesystem currently registered with the core, * in a linked list. Pointers to these structures * are also kept by each "path" Tcl_Obj, and we must * retain a refCount on the number of such references. */ typedef struct FilesystemRecord { ClientData clientData; /* Client specific data for the new * filesystem (can be NULL) */ Tcl_Filesystem *fsPtr; /* Pointer to filesystem dispatch * table. */ int fileRefCount; /* How many Tcl_Obj's use this * filesystem. */ struct FilesystemRecord *nextPtr; /* The next filesystem registered * to Tcl, or NULL if no more. */ struct FilesystemRecord *prevPtr; /* The previous filesystem registered * to Tcl, or NULL if no more. */ } FilesystemRecord; /* * The internal TclFS API provides routines for handling and * manipulating paths efficiently, taking direct advantage of * the "path" Tcl_Obj type. * * These functions are not exported at all at present. */ int TclFSCwdPointerEquals _ANSI_ARGS_((Tcl_Obj* objPtr)); int TclFSMakePathFromNormalized _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr)); int TclFSNormalizeToUniquePath _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *pathPtr, int startAt)); Tcl_Obj* TclFSMakePathRelative _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Obj *cwdPtr)); Tcl_Obj* TclFSInternalToNormalized _ANSI_ARGS_(( Tcl_Filesystem *fromFilesystem, ClientData clientData, FilesystemRecord **fsRecPtrPtr)); int TclFSEnsureEpochOk _ANSI_ARGS_((Tcl_Obj* pathObjPtr, Tcl_Filesystem **fsPtrPtr)); void TclFSSetPathDetails _ANSI_ARGS_((Tcl_Obj *pathObjPtr, FilesystemRecord *fsRecPtr, ClientData clientData)); /* * Private variables for use in this file */ extern Tcl_Filesystem tclNativeFilesystem; extern int theFilesystemEpoch; /* * Private functions for use in this file */ static Tcl_PathType FSGetPathType _ANSI_ARGS_((Tcl_Obj *pathObjPtr, Tcl_Filesystem **filesystemPtrPtr, int *driveNameLengthPtr)); static Tcl_PathType GetPathType _ANSI_ARGS_((Tcl_Obj *pathObjPtr, Tcl_Filesystem **filesystemPtrPtr, int *driveNameLengthPtr, Tcl_Obj **driveNameRef)); static Tcl_FSPathInFilesystemProc NativePathInFilesystem; static Tcl_Obj* TclFSNormalizeAbsolutePath _ANSI_ARGS_((Tcl_Interp* interp, Tcl_Obj *pathPtr)); /* * Prototypes for procedures defined later in this file. */ static FilesystemRecord* FsGetFirstFilesystem(void); static void FsThrExitProc(ClientData cd); static Tcl_Obj* FsListMounts _ANSI_ARGS_((Tcl_Obj *pathPtr, CONST char *pattern)); static Tcl_Obj* FsAddMountsToGlobResult _ANSI_ARGS_((Tcl_Obj *result, Tcl_Obj *pathPtr, CONST char *pattern, Tcl_GlobTypeData *types)); #ifdef TCL_THREADS static void FsRecacheFilesystemList(void); #endif /* * These form part of the native filesystem support. They are needed * here because we have a few native filesystem functions (which are * the same for mac/win/unix) in this file. There is no need to place * them in tclInt.h, because they are not (and should not be) used * anywhere else. */ extern CONST char * tclpFileAttrStrings[]; extern CONST TclFileAttrProcs tclpFileAttrProcs[]; /* * The following functions are obsolete string based APIs, and should * be removed in a future release (Tcl 9 would be a good time). */ /* Obsolete */ int Tcl_Stat(path, oldStyleBuf) CONST char *path; /* Path of file to stat (in current CP). */ struct stat *oldStyleBuf; /* Filled with results of stat call. */ { int ret; Tcl_StatBuf buf; Tcl_Obj *pathPtr = Tcl_NewStringObj(path,-1); Tcl_IncrRefCount(pathPtr); ret = Tcl_FSStat(pathPtr, &buf); Tcl_DecrRefCount(pathPtr); if (ret != -1) { #ifndef TCL_WIDE_INT_IS_LONG # define OUT_OF_RANGE(x) \ (((Tcl_WideInt)(x)) < Tcl_LongAsWide(LONG_MIN) || \ ((Tcl_WideInt)(x)) > Tcl_LongAsWide(LONG_MAX)) #if defined(__GNUC__) && __GNUC__ >= 2 /* * Workaround gcc warning of "comparison is always false due to limited range of * data type" in this macro by checking max type size, and when necessary ANDing * with the complement of ULONG_MAX instead of the comparison: */ # define OUT_OF_URANGE(x) \ ((((Tcl_WideUInt)(~ (__typeof__(x)) 0)) > (Tcl_WideUInt)ULONG_MAX) && \ (((Tcl_WideUInt)(x)) & ~(Tcl_WideUInt)ULONG_MAX)) #else # define OUT_OF_URANGE(x) \ (((Tcl_WideUInt)(x)) > (Tcl_WideUInt)ULONG_MAX) #endif /* * Perform the result-buffer overflow check manually. * * Note that ino_t/ino64_t is unsigned... */ if (OUT_OF_URANGE(buf.st_ino) || OUT_OF_RANGE(buf.st_size) #ifdef HAVE_ST_BLOCKS || OUT_OF_RANGE(buf.st_blocks) #endif ) { #ifdef EFBIG errno = EFBIG; #else # ifdef EOVERFLOW errno = EOVERFLOW; # else # error "What status should be returned for file size out of range?" # endif #endif return -1; } # undef OUT_OF_RANGE # undef OUT_OF_URANGE #endif /* !TCL_WIDE_INT_IS_LONG */ /* * Copy across all supported fields, with possible type * coercions on those fields that change between the normal * and lf64 versions of the stat structure (on Solaris at * least.) This is slow when the structure sizes coincide, * but that's what you get for using an obsolete interface. */ oldStyleBuf->st_mode = buf.st_mode; oldStyleBuf->st_ino = (ino_t) buf.st_ino; oldStyleBuf->st_dev = buf.st_dev; oldStyleBuf->st_rdev = buf.st_rdev; oldStyleBuf->st_nlink = buf.st_nlink; oldStyleBuf->st_uid = buf.st_uid; oldStyleBuf->st_gid = buf.st_gid; oldStyleBuf->st_size = (off_t) buf.st_size; oldStyleBuf->st_atime = buf.st_atime; oldStyleBuf->st_mtime = buf.st_mtime; oldStyleBuf->st_ctime = buf.st_ctime; #ifdef HAVE_ST_BLOCKS oldStyleBuf->st_blksize = buf.st_blksize; oldStyleBuf->st_blocks = (blkcnt_t) buf.st_blocks; #endif } return ret; } /* Obsolete */ int Tcl_Access(path, mode) CONST char *path; /* Path of file to access (in current CP). */ int mode; /* Permission setting. */ { int ret; Tcl_Obj *pathPtr = Tcl_NewStringObj(path,-1); Tcl_IncrRefCount(pathPtr); ret = Tcl_FSAccess(pathPtr,mode); Tcl_DecrRefCount(pathPtr); return ret; } /* Obsolete */ Tcl_Channel Tcl_OpenFileChannel(interp, path, modeString, permissions) Tcl_Interp *interp; /* Interpreter for error reporting; * can be NULL. */ CONST char *path; /* Name of file to open. */ CONST char *modeString; /* A list of POSIX open modes or * a string such as "rw". */ int permissions; /* If the open involves creating a * file, with what modes to create * it? */ { Tcl_Channel ret; Tcl_Obj *pathPtr = Tcl_NewStringObj(path,-1); Tcl_IncrRefCount(pathPtr); ret = Tcl_FSOpenFileChannel(interp, pathPtr, modeString, permissions); Tcl_DecrRefCount(pathPtr); return ret; } /* Obsolete */ int Tcl_Chdir(dirName) CONST char *dirName; { int ret; Tcl_Obj *pathPtr = Tcl_NewStringObj(dirName,-1); Tcl_IncrRefCount(pathPtr); ret = Tcl_FSChdir(pathPtr); Tcl_DecrRefCount(pathPtr); return ret; } /* Obsolete */ char * Tcl_GetCwd(interp, cwdPtr) Tcl_Interp *interp; Tcl_DString *cwdPtr; { Tcl_Obj *cwd; cwd = Tcl_FSGetCwd(interp); if (cwd == NULL) { return NULL; } else { Tcl_DStringInit(cwdPtr); Tcl_DStringAppend(cwdPtr, Tcl_GetString(cwd), -1); Tcl_DecrRefCount(cwd); return Tcl_DStringValue(cwdPtr); } } /* Obsolete */ int Tcl_EvalFile(interp, fileName) Tcl_Interp *interp; /* Interpreter in which to process file. */ CONST char *fileName; /* Name of file to process. Tilde-substitution * will be performed on this name. */ { int ret; Tcl_Obj *pathPtr = Tcl_NewStringObj(fileName,-1); Tcl_IncrRefCount(pathPtr); ret = Tcl_FSEvalFile(interp, pathPtr); Tcl_DecrRefCount(pathPtr); return ret; } /* * The 3 hooks for Stat, Access and OpenFileChannel are obsolete. The * complete, general hooked filesystem APIs should be used instead. * This define decides whether to include the obsolete hooks and * related code. If these are removed, we'll also want to remove them * from stubs/tclInt. The only known users of these APIs are prowrap * and mktclapp. New code/extensions should not use them, since they * do not provide as full support as the full filesystem API. * * As soon as prowrap and mktclapp are updated to use the full * filesystem support, I suggest all these hooks are removed. */ #define USE_OBSOLETE_FS_HOOKS #ifdef USE_OBSOLETE_FS_HOOKS /* * The following typedef declarations allow for hooking into the chain * of functions maintained for 'Tcl_Stat(...)', 'Tcl_Access(...)' & * 'Tcl_OpenFileChannel(...)'. Basically for each hookable function * a linked list is defined. */ typedef struct StatProc { TclStatProc_ *proc; /* Function to process a 'stat()' call */ struct StatProc *nextPtr; /* The next 'stat()' function to call */ } StatProc; typedef struct AccessProc { TclAccessProc_ *proc; /* Function to process a 'access()' call */ struct AccessProc *nextPtr; /* The next 'access()' function to call */ } AccessProc; typedef struct OpenFileChannelProc { TclOpenFileChannelProc_ *proc; /* Function to process a * 'Tcl_OpenFileChannel()' call */ struct OpenFileChannelProc *nextPtr; /* The next 'Tcl_OpenFileChannel()' * function to call */ } OpenFileChannelProc; /* * For each type of (obsolete) hookable function, a static node is * declared to hold the function pointer for the "built-in" routine * (e.g. 'TclpStat(...)') and the respective list is initialized as a * pointer to that node. * * The "delete" functions (e.g. 'TclStatDeleteProc(...)') ensure that * these statically declared list entry cannot be inadvertently removed. * * This method avoids the need to call any sort of "initialization" * function. * * All three lists are protected by a global obsoleteFsHookMutex. */ static StatProc *statProcList = NULL; static AccessProc *accessProcList = NULL; static OpenFileChannelProc *openFileChannelProcList = NULL; TCL_DECLARE_MUTEX(obsoleteFsHookMutex) #endif /* USE_OBSOLETE_FS_HOOKS */ /* * Declare the native filesystem support. These functions should * be considered private to Tcl, and should really not be called * directly by any code other than this file (i.e. neither by * Tcl's core nor by extensions). Similarly, the old string-based * Tclp... native filesystem functions should not be called. * * The correct API to use now is the Tcl_FS... set of functions, * which ensure correct and complete virtual filesystem support. * * We cannot make all of these static, since some of them * are implemented in the platform-specific directories. */ static Tcl_FSFilesystemSeparatorProc NativeFilesystemSeparator; static Tcl_FSFreeInternalRepProc NativeFreeInternalRep; static Tcl_FSCreateInternalRepProc NativeCreateNativeRep; static Tcl_FSFileAttrStringsProc NativeFileAttrStrings; static Tcl_FSFileAttrsGetProc NativeFileAttrsGet; static Tcl_FSFileAttrsSetProc NativeFileAttrsSet; /* * The only reason these functions are not static is that they * are either called by code in the native (win/unix/mac) directories * or they are actually implemented in those directories. They * should simply not be called by code outside Tcl's native * filesystem core. i.e. they should be considered 'static' to * Tcl's filesystem code (if we ever built the native filesystem * support into a separate code library, this could actually be * enforced). */ Tcl_FSFilesystemPathTypeProc TclpFilesystemPathType; Tcl_FSInternalToNormalizedProc TclpNativeToNormalized; Tcl_FSStatProc TclpObjStat; Tcl_FSAccessProc TclpObjAccess; Tcl_FSMatchInDirectoryProc TclpMatchInDirectory; Tcl_FSGetCwdProc TclpObjGetCwd; Tcl_FSChdirProc TclpObjChdir; Tcl_FSLstatProc TclpObjLstat; Tcl_FSCopyFileProc TclpObjCopyFile; Tcl_FSDeleteFileProc TclpObjDeleteFile; Tcl_FSRenameFileProc TclpObjRenameFile; Tcl_FSCreateDirectoryProc TclpObjCreateDirectory; Tcl_FSCopyDirectoryProc TclpObjCopyDirectory; Tcl_FSRemoveDirectoryProc TclpObjRemoveDirectory; Tcl_FSUnloadFileProc TclpUnloadFile; Tcl_FSLinkProc TclpObjLink; Tcl_FSListVolumesProc TclpObjListVolumes; /* * Define the native filesystem dispatch table. If necessary, it * is ok to make this non-static, but it should only be accessed * by the functions actually listed within it (or perhaps other * helper functions of them). Anything which is not part of this * 'native filesystem implementation' should not be delving inside * here! */ Tcl_Filesystem tclNativeFilesystem = { "native", sizeof(Tcl_Filesystem), TCL_FILESYSTEM_VERSION_1, &NativePathInFilesystem, &TclNativeDupInternalRep, &NativeFreeInternalRep, &TclpNativeToNormalized, &NativeCreateNativeRep, &TclpObjNormalizePath, &TclpFilesystemPathType, &NativeFilesystemSeparator, &TclpObjStat, &TclpObjAccess, &TclpOpenFileChannel, &TclpMatchInDirectory, &TclpUtime, #ifndef S_IFLNK NULL, #else &TclpObjLink, #endif /* S_IFLNK */ &TclpObjListVolumes, &NativeFileAttrStrings, &NativeFileAttrsGet, &NativeFileAttrsSet, &TclpObjCreateDirectory, &TclpObjRemoveDirectory, &TclpObjDeleteFile, &TclpObjCopyFile, &TclpObjRenameFile, &TclpObjCopyDirectory, &TclpObjLstat, &TclpDlopen, &TclpObjGetCwd, &TclpObjChdir }; /* * Define the tail of the linked list. Note that for unconventional * uses of Tcl without a native filesystem, we may in the future wish * to modify the current approach of hard-coding the native filesystem * in the lookup list 'filesystemList' below. * * We initialize the record so that it thinks one file uses it. This * means it will never be freed. */ static FilesystemRecord nativeFilesystemRecord = { NULL, &tclNativeFilesystem, 1, NULL, NULL }; /* * This is incremented each time we modify the linked list of * filesystems. Any time it changes, all cached filesystem * representations are suspect and must be freed. * For multithreading builds, change of the filesystem epoch * will trigger cache cleanup in all threads. */ int theFilesystemEpoch = 0; /* * Stores the linked list of filesystems. A 1:1 copy of this * list is also maintained in the TSD for each thread. This * is to avoid synchronization issues. */ static FilesystemRecord *filesystemList = &nativeFilesystemRecord; TCL_DECLARE_MUTEX(filesystemMutex) /* * Used to implement Tcl_FSGetCwd in a file-system independent way. */ static Tcl_Obj* cwdPathPtr = NULL; static int cwdPathEpoch = 0; TCL_DECLARE_MUTEX(cwdMutex) /* * This structure holds per-thread private copies of * some global data. This way we avoid most of the * synchronization calls which boosts performance, at * cost of having to update this information each * time the corresponding epoch counter changes. * */ typedef struct ThreadSpecificData { int initialized; int cwdPathEpoch; int filesystemEpoch; Tcl_Obj *cwdPathPtr; FilesystemRecord *filesystemList; } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; /* * Declare fallback support function and * information for Tcl_FSLoadFile */ static Tcl_FSUnloadFileProc FSUnloadTempFile; /* * One of these structures is used each time we successfully load a * file from a file system by way of making a temporary copy of the * file on the native filesystem. We need to store both the actual * unloadProc/clientData combination which was used, and the original * and modified filenames, so that we can correctly undo the entire * operation when we want to unload the code. */ typedef struct FsDivertLoad { Tcl_LoadHandle loadHandle; Tcl_FSUnloadFileProc *unloadProcPtr; Tcl_Obj *divertedFile; Tcl_Filesystem *divertedFilesystem; ClientData divertedFileNativeRep; } FsDivertLoad; /* Now move on to the basic filesystem implementation */ static void FsThrExitProc(cd) ClientData cd; { ThreadSpecificData *tsdPtr = (ThreadSpecificData*)cd; FilesystemRecord *fsRecPtr = NULL, *tmpFsRecPtr = NULL; /* Trash the cwd copy */ if (tsdPtr->cwdPathPtr != NULL) { Tcl_DecrRefCount(tsdPtr->cwdPathPtr); tsdPtr->cwdPathPtr = NULL; } /* Trash the filesystems cache */ fsRecPtr = tsdPtr->filesystemList; while (fsRecPtr != NULL) { tmpFsRecPtr = fsRecPtr->nextPtr; if (--fsRecPtr->fileRefCount <= 0) { ckfree((char *)fsRecPtr); } fsRecPtr = tmpFsRecPtr; } tsdPtr->initialized = 0; } int TclFSCwdPointerEquals(objPtr) Tcl_Obj* objPtr; { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); Tcl_MutexLock(&cwdMutex); if (tsdPtr->cwdPathPtr == NULL) { if (cwdPathPtr == NULL) { tsdPtr->cwdPathPtr = NULL; } else { tsdPtr->cwdPathPtr = Tcl_DuplicateObj(cwdPathPtr); Tcl_IncrRefCount(tsdPtr->cwdPathPtr); } tsdPtr->cwdPathEpoch = cwdPathEpoch; } else if (tsdPtr->cwdPathEpoch != cwdPathEpoch) { Tcl_DecrRefCount(tsdPtr->cwdPathPtr); if (cwdPathPtr == NULL) { tsdPtr->cwdPathPtr = NULL; } else { tsdPtr->cwdPathPtr = Tcl_DuplicateObj(cwdPathPtr); Tcl_IncrRefCount(tsdPtr->cwdPathPtr); } } Tcl_MutexUnlock(&cwdMutex); if (tsdPtr->initialized == 0) { Tcl_CreateThreadExitHandler(FsThrExitProc, (ClientData)tsdPtr); tsdPtr->initialized = 1; } return (tsdPtr->cwdPathPtr == objPtr); } #ifdef TCL_THREADS static void FsRecacheFilesystemList(void) { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); FilesystemRecord *fsRecPtr, *tmpFsRecPtr = NULL; /* Trash the current cache */ fsRecPtr = tsdPtr->filesystemList; while (fsRecPtr != NULL) { tmpFsRecPtr = fsRecPtr->nextPtr; if (--fsRecPtr->fileRefCount <= 0) { ckfree((char *)fsRecPtr); } fsRecPtr = tmpFsRecPtr; } tsdPtr->filesystemList = NULL; /* * Code below operates on shared data. We * are already called under mutex lock so * we can safely proceed. */ /* Locate tail of the global filesystem list */ fsRecPtr = filesystemList; while (fsRecPtr != NULL) { tmpFsRecPtr = fsRecPtr; fsRecPtr = fsRecPtr->nextPtr; } /* Refill the cache honouring the order */ fsRecPtr = tmpFsRecPtr; while (fsRecPtr != NULL) { tmpFsRecPtr = (FilesystemRecord *)ckalloc(sizeof(FilesystemRecord)); *tmpFsRecPtr = *fsRecPtr; tmpFsRecPtr->nextPtr = tsdPtr->filesystemList; tmpFsRecPtr->prevPtr = NULL; if (tsdPtr->filesystemList) { tsdPtr->filesystemList->prevPtr = tmpFsRecPtr; } tsdPtr->filesystemList = tmpFsRecPtr; fsRecPtr = fsRecPtr->prevPtr; } /* Make sure the above gets released on thread exit */ if (tsdPtr->initialized == 0) { Tcl_CreateThreadExitHandler(FsThrExitProc, (ClientData)tsdPtr); tsdPtr->initialized = 1; } } #endif static FilesystemRecord * FsGetFirstFilesystem(void) { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); FilesystemRecord *fsRecPtr; #ifndef TCL_THREADS tsdPtr->filesystemEpoch = theFilesystemEpoch; fsRecPtr = filesystemList; #else Tcl_MutexLock(&filesystemMutex); if (tsdPtr->filesystemList == NULL || (tsdPtr->filesystemEpoch != theFilesystemEpoch)) { FsRecacheFilesystemList(); tsdPtr->filesystemEpoch = theFilesystemEpoch; } Tcl_MutexUnlock(&filesystemMutex); fsRecPtr = tsdPtr->filesystemList; #endif return fsRecPtr; } static void FsUpdateCwd(cwdObj) Tcl_Obj *cwdObj; { int len; char *str = NULL; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (cwdObj != NULL) { str = Tcl_GetStringFromObj(cwdObj, &len); } Tcl_MutexLock(&cwdMutex); if (cwdPathPtr != NULL) { Tcl_DecrRefCount(cwdPathPtr); } if (cwdObj == NULL) { cwdPathPtr = NULL; } else { /* This MUST be stored as string object! */ cwdPathPtr = Tcl_NewStringObj(str, len); Tcl_IncrRefCount(cwdPathPtr); } cwdPathEpoch++; tsdPtr->cwdPathEpoch = cwdPathEpoch; Tcl_MutexUnlock(&cwdMutex); if (tsdPtr->cwdPathPtr) { Tcl_DecrRefCount(tsdPtr->cwdPathPtr); } if (cwdObj == NULL) { tsdPtr->cwdPathPtr = NULL; } else { tsdPtr->cwdPathPtr = Tcl_NewStringObj(str, len); Tcl_IncrRefCount(tsdPtr->cwdPathPtr); } } /* *---------------------------------------------------------------------- * * TclFinalizeFilesystem -- * * Clean up the filesystem. After this, calls to all Tcl_FS... * functions will fail. * * We will later call TclResetFilesystem to restore the FS * to a pristine state. * * Results: * None. * * Side effects: * Frees any memory allocated by the filesystem. * *---------------------------------------------------------------------- */ void TclFinalizeFilesystem() { FilesystemRecord *fsRecPtr; /* * Assumption that only one thread is active now. Otherwise * we would need to put various mutexes around this code. */ if (cwdPathPtr != NULL) { Tcl_DecrRefCount(cwdPathPtr); cwdPathPtr = NULL; cwdPathEpoch = 0; } /* * Remove all filesystems, freeing any allocated memory * that is no longer needed */ fsRecPtr = filesystemList; while (fsRecPtr != NULL) { FilesystemRecord *tmpFsRecPtr = fsRecPtr->nextPtr; if (fsRecPtr->fileRefCount <= 0) { /* The native filesystem is static, so we don't free it */ if (fsRecPtr->fsPtr != &tclNativeFilesystem) { ckfree((char *)fsRecPtr); } } fsRecPtr = tmpFsRecPtr; } filesystemList = NULL; /* * Now filesystemList is NULL. This means that any attempt * to use the filesystem is likely to fail. */ statProcList = NULL; accessProcList = NULL; openFileChannelProcList = NULL; #ifdef __WIN32__ TclWinEncodingsCleanup(); #endif } /* *---------------------------------------------------------------------- * * TclResetFilesystem -- * * Restore the filesystem to a pristine state. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TclResetFilesystem() { filesystemList = &nativeFilesystemRecord; /* * Note, at this point, I believe nativeFilesystemRecord -> * fileRefCount should equal 1 and if not, we should try to track * down the cause. */ #ifdef __WIN32__ /* * Cleans up the win32 API filesystem proc lookup table. This must * happen very late in finalization so that deleting of copied * dlls can occur. */ TclWinResetInterfaces(); #endif } /* *---------------------------------------------------------------------- * * Tcl_FSRegister -- * * Insert the filesystem function table at the head of the list of * functions which are used during calls to all file-system * operations. The filesystem will be added even if it is * already in the list. (You can use Tcl_FSData to * check if it is in the list, provided the ClientData used was * not NULL). * * Note that the filesystem handling is head-to-tail of the list. * Each filesystem is asked in turn whether it can handle a * particular request, _until_ one of them says 'yes'. At that * point no further filesystems are asked. * * In particular this means if you want to add a diagnostic * filesystem (which simply reports all fs activity), it must be * at the head of the list: i.e. it must be the last registered. * * Results: * Normally TCL_OK; TCL_ERROR if memory for a new node in the list * could not be allocated. * * Side effects: * Memory allocated and modifies the link list for filesystems. * *---------------------------------------------------------------------- */ int Tcl_FSRegister(clientData, fsPtr) ClientData clientData; /* Client specific data for this fs */ Tcl_Filesystem *fsPtr; /* The filesystem record for the new fs. */ { FilesystemRecord *newFilesystemPtr; if (fsPtr == NULL) { return TCL_ERROR; } newFilesystemPtr = (FilesystemRecord *) ckalloc(sizeof(FilesystemRecord)); newFilesystemPtr->clientData = clientData; newFilesystemPtr->fsPtr = fsPtr; /* * We start with a refCount of 1. If this drops to zero, then * anyone is welcome to ckfree us. */ newFilesystemPtr->fileRefCount = 1; /* * Is this lock and wait strictly speaking necessary? Since any * iterators out there will have grabbed a copy of the head of * the list and be iterating away from that, if we add a new * element to the head of the list, it can't possibly have any * effect on any of their loops. In fact it could be better not * to wait, since we are adjusting the filesystem epoch, any * cached representations calculated by existing iterators are * going to have to be thrown away anyway. * * However, since registering and unregistering filesystems is * a very rare action, this is not a very important point. */ Tcl_MutexLock(&filesystemMutex); newFilesystemPtr->nextPtr = filesystemList; newFilesystemPtr->prevPtr = NULL; if (filesystemList) { filesystemList->prevPtr = newFilesystemPtr; } filesystemList = newFilesystemPtr; /* * Increment the filesystem epoch counter, since existing paths * might conceivably now belong to different filesystems. */ theFilesystemEpoch++; Tcl_MutexUnlock(&filesystemMutex); return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_FSUnregister -- * * Remove the passed filesystem from the list of filesystem * function tables. It also ensures that the built-in * (native) filesystem is not removable, although we may wish * to change that decision in the future to allow a smaller * Tcl core, in which the native filesystem is not used at * all (we could, say, initialise Tcl completely over a network * connection). * * Results: * TCL_OK if the procedure pointer was successfully removed, * TCL_ERROR otherwise. * * Side effects: * Memory may be deallocated (or will be later, once no "path" * objects refer to this filesystem), but the list of registered * filesystems is updated immediately. * *---------------------------------------------------------------------- */ int Tcl_FSUnregister(fsPtr) Tcl_Filesystem *fsPtr; /* The filesystem record to remove. */ { int retVal = TCL_ERROR; FilesystemRecord *fsRecPtr; Tcl_MutexLock(&filesystemMutex); /* * Traverse the 'filesystemList' looking for the particular node * whose 'fsPtr' member matches 'fsPtr' and remove that one from * the list. Ensure that the "default" node cannot be removed. */ fsRecPtr = filesystemList; while ((retVal == TCL_ERROR) && (fsRecPtr->fsPtr != &tclNativeFilesystem)) { if (fsRecPtr->fsPtr == fsPtr) { if (fsRecPtr->prevPtr) { fsRecPtr->prevPtr->nextPtr = fsRecPtr->nextPtr; } else { filesystemList = fsRecPtr->nextPtr; } if (fsRecPtr->nextPtr) { fsRecPtr->nextPtr->prevPtr = fsRecPtr->prevPtr; } /* * Increment the filesystem epoch counter, since existing * paths might conceivably now belong to different * filesystems. This should also ensure that paths which * have cached the filesystem which is about to be deleted * do not reference that filesystem (which would of course * lead to memory exceptions). */ theFilesystemEpoch++; fsRecPtr->fileRefCount--; if (fsRecPtr->fileRefCount <= 0) { ckfree((char *)fsRecPtr); } retVal = TCL_OK; } else { fsRecPtr = fsRecPtr->nextPtr; } } Tcl_MutexUnlock(&filesystemMutex); return (retVal); } /* *---------------------------------------------------------------------- * * Tcl_FSMatchInDirectory -- * * This routine is used by the globbing code to search a directory * for all files which match a given pattern. The appropriate * function for the filesystem to which pathPtr belongs will be * called. If pathPtr does not belong to any filesystem and if it * is NULL or the empty string, then we assume the pattern is to be * matched in the current working directory. To avoid each * filesystem's Tcl_FSMatchInDirectoryProc having to deal with this * issue, we create a pathPtr on the fly (equal to the cwd), and * then remove it from the results returned. This makes filesystems * easy to write, since they can assume the pathPtr passed to them * is an ordinary path. In fact this means we could remove such * special case handling from Tcl's native filesystems. * * If 'pattern' is NULL, then pathPtr is assumed to be a fully * specified path of a single file/directory which must be * checked for existence and correct type. * * Results: * * The return value is a standard Tcl result indicating whether an * error occurred in globbing. Error messages are placed in * interp, but good results are placed in the resultPtr given. * * Recursive searches, e.g. * * glob -dir $dir -join * pkgIndex.tcl * * which must recurse through each directory matching '*' are * handled internally by Tcl, by passing specific flags in a * modified 'types' parameter. This means the actual filesystem * only ever sees patterns which match in a single directory. * * Side effects: * The interpreter may have an error message inserted into it. * *---------------------------------------------------------------------- */ int Tcl_FSMatchInDirectory(interp, result, pathPtr, pattern, types) Tcl_Interp *interp; /* Interpreter to receive error messages. */ Tcl_Obj *result; /* List object to receive results. */ Tcl_Obj *pathPtr; /* Contains path to directory to search. */ CONST char *pattern; /* Pattern to match against. */ Tcl_GlobTypeData *types; /* Object containing list of acceptable types. * May be NULL. In particular the directory * flag is very important. */ { Tcl_Filesystem *fsPtr = Tcl_FSGetFileSystemForPath(pathPtr); if (fsPtr != NULL) { Tcl_FSMatchInDirectoryProc *proc = fsPtr->matchInDirectoryProc; if (proc != NULL) { int ret = (*proc)(interp, result, pathPtr, pattern, types); if (ret == TCL_OK && pattern != NULL) { result = FsAddMountsToGlobResult(result, pathPtr, pattern, types); } return ret; } } else { Tcl_Obj* cwd; int ret = -1; if (pathPtr != NULL) { int len; Tcl_GetStringFromObj(pathPtr,&len); if (len != 0) { /* * We have no idea how to match files in a directory * which belongs to no known filesystem */ Tcl_SetErrno(ENOENT); return -1; } } /* * We have an empty or NULL path. This is defined to mean we * must search for files within the current 'cwd'. We * therefore use that, but then since the proc we call will * return results which include the cwd we must then trim it * off the front of each path in the result. We choose to deal * with this here (in the generic code), since if we don't, * every single filesystem's implementation of * Tcl_FSMatchInDirectory will have to deal with it for us. */ cwd = Tcl_FSGetCwd(NULL); if (cwd == NULL) { if (interp != NULL) { Tcl_SetResult(interp, "glob couldn't determine " "the current working directory", TCL_STATIC); } return TCL_ERROR; } fsPtr = Tcl_FSGetFileSystemForPath(cwd); if (fsPtr != NULL) { Tcl_FSMatchInDirectoryProc *proc = fsPtr->matchInDirectoryProc; if (proc != NULL) { Tcl_Obj* tmpResultPtr = Tcl_NewListObj(0, NULL); Tcl_IncrRefCount(tmpResultPtr); ret = (*proc)(interp, tmpResultPtr, cwd, pattern, types); if (ret == TCL_OK) { int resLength; tmpResultPtr = FsAddMountsToGlobResult(tmpResultPtr, cwd, pattern, types); ret = Tcl_ListObjLength(interp, tmpResultPtr, &resLength); if (ret == TCL_OK) { int i; for (i = 0; i < resLength; i++) { Tcl_Obj *elt; Tcl_ListObjIndex(interp, tmpResultPtr, i, &elt); Tcl_ListObjAppendElement(interp, result, TclFSMakePathRelative(interp, elt, cwd)); } } } Tcl_DecrRefCount(tmpResultPtr); } } Tcl_DecrRefCount(cwd); return ret; } Tcl_SetErrno(ENOENT); return -1; } /* *---------------------------------------------------------------------- * * FsAddMountsToGlobResult -- * * This routine is used by the globbing code to take the results * of a directory listing and add any mounted paths to that * listing. This is required so that simple things like * 'glob *' merge mounts and listings correctly. * * Results: * * The passed in 'result' may be modified (in place, if * necessary), and the correct list is returned. * * Side effects: * None. * *---------------------------------------------------------------------- */ static Tcl_Obj* FsAddMountsToGlobResult(result, pathPtr, pattern, types) Tcl_Obj *result; /* The current list of matching paths */ Tcl_Obj *pathPtr; /* The directory in question */ CONST char *pattern; Tcl_GlobTypeData *types; { int mLength, gLength, i; int dir = (types == NULL || (types->type & TCL_GLOB_TYPE_DIR)); Tcl_Obj *mounts = FsListMounts(pathPtr, pattern); if (mounts == NULL) return result; if (Tcl_ListObjLength(NULL, mounts, &mLength) != TCL_OK || mLength == 0) { goto endOfMounts; } if (Tcl_ListObjLength(NULL, result, &gLength) != TCL_OK) { goto endOfMounts; } for (i = 0; i < mLength; i++) { Tcl_Obj *mElt; int j; int found = 0; Tcl_ListObjIndex(NULL, mounts, i, &mElt); for (j = 0; j < gLength; j++) { Tcl_Obj *gElt; Tcl_ListObjIndex(NULL, result, j, &gElt); if (Tcl_FSEqualPaths(mElt, gElt)) { found = 1; if (!dir) { /* We don't want to list this */ if (Tcl_IsShared(result)) { Tcl_Obj *newList; newList = Tcl_DuplicateObj(result); Tcl_DecrRefCount(result); result = newList; } Tcl_ListObjReplace(NULL, result, j, 1, 0, NULL); gLength--; } /* Break out of for loop */ break; } } if (!found && dir) { if (Tcl_IsShared(result)) { Tcl_Obj *newList; newList = Tcl_DuplicateObj(result); Tcl_DecrRefCount(result); result = newList; } Tcl_ListObjAppendElement(NULL, result, mElt); /* * No need to increment gLength, since we * don't want to compare mounts against * mounts. */ } } endOfMounts: Tcl_DecrRefCount(mounts); return result; } /* *---------------------------------------------------------------------- * * Tcl_FSMountsChanged -- * * Notify the filesystem that the available mounted filesystems * (or within any one filesystem type, the number or location of * mount points) have changed. * * Results: * None. * * Side effects: * The global filesystem variable 'theFilesystemEpoch' is * incremented. The effect of this is to make all cached * path representations invalid. Clearly it should only therefore * be called when it is really required! There are a few * circumstances when it should be called: * * (1) when a new filesystem is registered or unregistered. * Strictly speaking this is only necessary if the new filesystem * accepts file paths as is (normally the filesystem itself is * really a shell which hasn't yet had any mount points established * and so its 'pathInFilesystem' proc will always fail). However, * for safety, Tcl always calls this for you in these circumstances. * * (2) when additional mount points are established inside any * existing filesystem (except the native fs) * * (3) when any filesystem (except the native fs) changes the list * of available volumes. * * (4) when the mapping from a string representation of a file to * a full, normalized path changes. For example, if 'env(HOME)' * is modified, then any path containing '~' will map to a different * filesystem location. Therefore all such paths need to have * their internal representation invalidated. * * Tcl has no control over (2) and (3), so any registered filesystem * must make sure it calls this function when those situations * occur. * * (Note: the reason for the exception in 2,3 for the native * filesystem is that the native filesystem by default claims all * unknown files even if it really doesn't understand them or if * they don't exist). * *---------------------------------------------------------------------- */ void Tcl_FSMountsChanged(fsPtr) Tcl_Filesystem *fsPtr; { /* * We currently don't do anything with this parameter. We * could in the future only invalidate files for this filesystem * or otherwise take more advanced action. */ (void)fsPtr; /* * Increment the filesystem epoch counter, since existing paths * might now belong to different filesystems. */ Tcl_MutexLock(&filesystemMutex); theFilesystemEpoch++; Tcl_MutexUnlock(&filesystemMutex); } /* *---------------------------------------------------------------------- * * Tcl_FSData -- * * Retrieve the clientData field for the filesystem given, * or NULL if that filesystem is not registered. * * Results: * A clientData value, or NULL. Note that if the filesystem * was registered with a NULL clientData field, this function * will return that NULL value. * * Side effects: * None. * *---------------------------------------------------------------------- */ ClientData Tcl_FSData(fsPtr) Tcl_Filesystem *fsPtr; /* The filesystem record to query. */ { ClientData retVal = NULL; FilesystemRecord *fsRecPtr = FsGetFirstFilesystem(); /* * Traverse the 'filesystemList' looking for the particular node * whose 'fsPtr' member matches 'fsPtr' and remove that one from * the list. Ensure that the "default" node cannot be removed. */ while ((retVal == NULL) && (fsRecPtr != NULL)) { if (fsRecPtr->fsPtr == fsPtr) { retVal = fsRecPtr->clientData; } fsRecPtr = fsRecPtr->nextPtr; } return retVal; } /* *--------------------------------------------------------------------------- * * TclFSNormalizeAbsolutePath -- * * Description: * Takes an absolute path specification and computes a 'normalized' * path from it. * * A normalized path is one which has all '../', './' removed. * Also it is one which is in the 'standard' format for the native * platform. On MacOS, Unix, this means the path must be free of * symbolic links/aliases, and on Windows it means we want the * long form, with that long form's case-dependence (which gives * us a unique, case-dependent path). * * The behaviour of this function if passed a non-absolute path * is NOT defined. * * Results: * The result is returned in a Tcl_Obj with a refCount of 1, * which is therefore owned by the caller. It must be * freed (with Tcl_DecrRefCount) by the caller when no longer needed. * * Side effects: * None (beyond the memory allocation for the result). * * Special note: * This code is based on code from Matt Newman and Jean-Claude * Wippler, with additions from Vince Darley and is copyright * those respective authors. * *--------------------------------------------------------------------------- */ static Tcl_Obj * TclFSNormalizeAbsolutePath(interp, pathPtr) Tcl_Interp* interp; /* Interpreter to use */ Tcl_Obj *pathPtr; /* Absolute path to normalize */ { int splen = 0, nplen, eltLen, i; char *eltName; Tcl_Obj *retVal; Tcl_Obj *split; Tcl_Obj *elt; /* Split has refCount zero */ split = Tcl_FSSplitPath(pathPtr, &splen); /* * Modify the list of entries in place, by removing '.', and * removing '..' and the entry before -- unless that entry before * is the top-level entry, i.e. the name of a volume. */ nplen = 0; for (i = 0; i < splen; i++) { Tcl_ListObjIndex(NULL, split, nplen, &elt); eltName = Tcl_GetStringFromObj(elt, &eltLen); if ((eltLen == 1) && (eltName[0] == '.')) { Tcl_ListObjReplace(NULL, split, nplen, 1, 0, NULL); } else if ((eltLen == 2) && (eltName[0] == '.') && (eltName[1] == '.')) { if (nplen > 1) { nplen--; Tcl_ListObjReplace(NULL, split, nplen, 2, 0, NULL); } else { Tcl_ListObjReplace(NULL, split, nplen, 1, 0, NULL); } } else { nplen++; } } if (nplen > 0) { retVal = Tcl_FSJoinPath(split, nplen); /* * Now we have an absolute path, with no '..', '.' sequences, * but it still may not be in 'unique' form, depending on the * platform. For instance, Unix is case-sensitive, so the * path is ok. Windows is case-insensitive, and also has the * weird 'longname/shortname' thing (e.g. C:/Program Files/ and * C:/Progra~1/ are equivalent). MacOS is case-insensitive. * * Virtual file systems which may be registered may have * other criteria for normalizing a path. */ Tcl_IncrRefCount(retVal); TclFSNormalizeToUniquePath(interp, retVal, 0); /* * Since we know it is a normalized path, we can * actually convert this object into an "path" object for * greater efficiency */ TclFSMakePathFromNormalized(interp, retVal); } else { /* Init to an empty string */ retVal = Tcl_NewStringObj("",0); Tcl_IncrRefCount(retVal); } /* * We increment and then decrement the refCount of split to free * it. We do this right at the end, in case there are * optimisations in Tcl_FSJoinPath(split, nplen) above which would * let it make use of split more effectively if it has a refCount * of zero. Also we can't just decrement the ref count, in case * 'split' was actually returned by the join call above, in a * single-element optimisation when nplen == 1. */ Tcl_IncrRefCount(split); Tcl_DecrRefCount(split); /* This has a refCount of 1 for the caller */ return retVal; } /* *--------------------------------------------------------------------------- * * TclFSNormalizeToUniquePath -- * * Description: * Takes a path specification containing no ../, ./ sequences, * and converts it into a unique path for the given platform. * On MacOS, Unix, this means the path must be free of * symbolic links/aliases, and on Windows it means we want the * long form, with that long form's case-dependence (which gives * us a unique, case-dependent path). * * Results: * The pathPtr is modified in place. The return value is * the last byte offset which was recognised in the path * string. * * Side effects: * None (beyond the memory allocation for the result). * * Special notes: * If the filesystem-specific normalizePathProcs can re-introduce * ../, ./ sequences into the path, then this function will * not return the correct result. This may be possible with * symbolic links on unix/macos. * * Important assumption: if startAt is non-zero, it must point * to a directory separator that we know exists and is already * normalized (so it is important not to point to the char just * after the separator). *--------------------------------------------------------------------------- */ int TclFSNormalizeToUniquePath(interp, pathPtr, startAt) Tcl_Interp *interp; Tcl_Obj *pathPtr; int startAt; { FilesystemRecord *fsRecPtr, *firstFsRecPtr; /* * Call each of the "normalise path" functions in succession. This is * a special case, in which if we have a native filesystem handler, * we call it first. This is because the root of Tcl's filesystem * is always a native filesystem (i.e. '/' on unix is native). */ firstFsRecPtr = FsGetFirstFilesystem(); fsRecPtr = firstFsRecPtr; while (fsRecPtr != NULL) { if (fsRecPtr->fsPtr == &tclNativeFilesystem) { Tcl_FSNormalizePathProc *proc = fsRecPtr->fsPtr->normalizePathProc; if (proc != NULL) { startAt = (*proc)(interp, pathPtr, startAt); } break; } fsRecPtr = fsRecPtr->nextPtr; } fsRecPtr = firstFsRecPtr; while (fsRecPtr != NULL) { /* Skip the native system next time through */ if (fsRecPtr->fsPtr != &tclNativeFilesystem) { Tcl_FSNormalizePathProc *proc = fsRecPtr->fsPtr->normalizePathProc; if (proc != NULL) { startAt = (*proc)(interp, pathPtr, startAt); } /* * We could add an efficiency check like this: * * if (retVal == length-of(pathPtr)) {break;} * * but there's not much benefit. */ } fsRecPtr = fsRecPtr->nextPtr; } return startAt; } /* *--------------------------------------------------------------------------- * * TclGetOpenMode -- * * Description: * Computes a POSIX mode mask for opening a file, from a given string, * and also sets a flag to indicate whether the caller should seek to * EOF after opening the file. * * Results: * On success, returns mode to pass to "open". If an error occurs, the * return value is -1 and if interp is not NULL, sets interp's result * object to an error message. * * Side effects: * Sets the integer referenced by seekFlagPtr to 1 to tell the caller * to seek to EOF after opening the file. * * Special note: * This code is based on a prototype implementation contributed * by Mark Diekhans. * *--------------------------------------------------------------------------- */ int TclGetOpenMode(interp, string, seekFlagPtr) Tcl_Interp *interp; /* Interpreter to use for error * reporting - may be NULL. */ CONST char *string; /* Mode string, e.g. "r+" or * "RDONLY CREAT". */ int *seekFlagPtr; /* Set this to 1 if the caller * should seek to EOF during the * opening of the file. */ { int mode, modeArgc, c, i, gotRW; CONST char **modeArgv, *flag; #define RW_MODES (O_RDONLY|O_WRONLY|O_RDWR) /* * Check for the simpler fopen-like access modes (e.g. "r"). They * are distinguished from the POSIX access modes by the presence * of a lower-case first letter. */ *seekFlagPtr = 0; mode = 0; /* * Guard against international characters before using byte oriented * routines. */ if (!(string[0] & 0x80) && islower(UCHAR(string[0]))) { /* INTL: ISO only. */ switch (string[0]) { case 'r': mode = O_RDONLY; break; case 'w': mode = O_WRONLY|O_CREAT|O_TRUNC; break; case 'a': /* [Bug 680143]. * Added O_APPEND for proper automatic * seek-to-end-on-write by the OS. */ mode = O_WRONLY|O_CREAT|O_APPEND; *seekFlagPtr = 1; break; default: error: if (interp != (Tcl_Interp *) NULL) { Tcl_AppendResult(interp, "illegal access mode \"", string, "\"", (char *) NULL); } return -1; } if (string[1] == '+') { /* * Must remove the O_APPEND flag so that the seek command * works. [Bug 1773127] */ mode &= ~(O_RDONLY|O_WRONLY|O_APPEND); mode |= O_RDWR; if (string[2] != 0) { goto error; } } else if (string[1] != 0) { goto error; } return mode; } /* * The access modes are specified using a list of POSIX modes * such as O_CREAT. * * IMPORTANT NOTE: We rely on Tcl_SplitList working correctly when * a NULL interpreter is passed in. */ if (Tcl_SplitList(interp, string, &modeArgc, &modeArgv) != TCL_OK) { if (interp != (Tcl_Interp *) NULL) { Tcl_AddErrorInfo(interp, "\n while processing open access modes \""); Tcl_AddErrorInfo(interp, string); Tcl_AddErrorInfo(interp, "\""); } return -1; } gotRW = 0; for (i = 0; i < modeArgc; i++) { flag = modeArgv[i]; c = flag[0]; if ((c == 'R') && (strcmp(flag, "RDONLY") == 0)) { mode = (mode & ~RW_MODES) | O_RDONLY; gotRW = 1; } else if ((c == 'W') && (strcmp(flag, "WRONLY") == 0)) { mode = (mode & ~RW_MODES) | O_WRONLY; gotRW = 1; } else if ((c == 'R') && (strcmp(flag, "RDWR") == 0)) { mode = (mode & ~RW_MODES) | O_RDWR; gotRW = 1; } else if ((c == 'A') && (strcmp(flag, "APPEND") == 0)) { mode |= O_APPEND; *seekFlagPtr = 1; } else if ((c == 'C') && (strcmp(flag, "CREAT") == 0)) { mode |= O_CREAT; } else if ((c == 'E') && (strcmp(flag, "EXCL") == 0)) { mode |= O_EXCL; } else if ((c == 'N') && (strcmp(flag, "NOCTTY") == 0)) { #ifdef O_NOCTTY mode |= O_NOCTTY; #else if (interp != (Tcl_Interp *) NULL) { Tcl_AppendResult(interp, "access mode \"", flag, "\" not supported by this system", (char *) NULL); } ckfree((char *) modeArgv); return -1; #endif } else if ((c == 'N') && (strcmp(flag, "NONBLOCK") == 0)) { #if defined(O_NDELAY) || defined(O_NONBLOCK) # ifdef O_NONBLOCK mode |= O_NONBLOCK; # else mode |= O_NDELAY; # endif #else if (interp != (Tcl_Interp *) NULL) { Tcl_AppendResult(interp, "access mode \"", flag, "\" not supported by this system", (char *) NULL); } ckfree((char *) modeArgv); return -1; #endif } else if ((c == 'T') && (strcmp(flag, "TRUNC") == 0)) { mode |= O_TRUNC; } else { if (interp != (Tcl_Interp *) NULL) { Tcl_AppendResult(interp, "invalid access mode \"", flag, "\": must be RDONLY, WRONLY, RDWR, APPEND, CREAT", " EXCL, NOCTTY, NONBLOCK, or TRUNC", (char *) NULL); } ckfree((char *) modeArgv); return -1; } } ckfree((char *) modeArgv); if (!gotRW) { if (interp != (Tcl_Interp *) NULL) { Tcl_AppendResult(interp, "access mode must include either", " RDONLY, WRONLY, or RDWR", (char *) NULL); } return -1; } return mode; } /* *---------------------------------------------------------------------- * * Tcl_FSEvalFile -- * * Read in a file and process the entire file as one gigantic * Tcl command. * * Results: * A standard Tcl result, which is either the result of executing * the file or an error indicating why the file couldn't be read. * * Side effects: * Depends on the commands in the file. During the evaluation * of the contents of the file, iPtr->scriptFile is made to * point to pathPtr (the old value is cached and replaced when * this function returns). * *---------------------------------------------------------------------- */ int Tcl_FSEvalFile(interp, pathPtr) Tcl_Interp *interp; /* Interpreter in which to process file. */ Tcl_Obj *pathPtr; /* Path of file to process. Tilde-substitution * will be performed on this name. */ { int result, length; Tcl_StatBuf statBuf; Tcl_Obj *oldScriptFile; Interp *iPtr; char *string; Tcl_Channel chan; Tcl_Obj *objPtr; if (Tcl_FSGetNormalizedPath(interp, pathPtr) == NULL) { return TCL_ERROR; } result = TCL_ERROR; objPtr = Tcl_NewObj(); Tcl_IncrRefCount(objPtr); if (Tcl_FSStat(pathPtr, &statBuf) == -1) { Tcl_SetErrno(errno); Tcl_AppendResult(interp, "couldn't read file \"", Tcl_GetString(pathPtr), "\": ", Tcl_PosixError(interp), (char *) NULL); goto end; } chan = Tcl_FSOpenFileChannel(interp, pathPtr, "r", 0644); if (chan == (Tcl_Channel) NULL) { Tcl_ResetResult(interp); Tcl_AppendResult(interp, "couldn't read file \"", Tcl_GetString(pathPtr), "\": ", Tcl_PosixError(interp), (char *) NULL); goto end; } /* * The eofchar is \32 (^Z). This is the usual on Windows, but we * effect this cross-platform to allow for scripted documents. * [Bug: 2040] */ Tcl_SetChannelOption(interp, chan, "-eofchar", "\32"); /* Try to read first character of stream, so we can * check for utf-8 BOM to be handled especially. */ if (Tcl_ReadChars(chan, objPtr, 1, 0) < 0) { Tcl_Close(interp, chan); Tcl_AppendResult(interp, "couldn't read file \"", Tcl_GetString(pathPtr), "\": ", Tcl_PosixError(interp), NULL); goto end; } string = Tcl_GetString(objPtr); /* * If first character is not a BOM, append the remaining characters, * otherwise replace them [Bug 3466099]. */ if (Tcl_ReadChars(chan, objPtr, -1, memcmp(string, "\xef\xbb\xbf", 3)) < 0) { Tcl_Close(interp, chan); Tcl_AppendResult(interp, "couldn't read file \"", Tcl_GetString(pathPtr), "\": ", Tcl_PosixError(interp), NULL); goto end; } if (Tcl_Close(interp, chan) != TCL_OK) { goto end; } iPtr = (Interp *) interp; oldScriptFile = iPtr->scriptFile; iPtr->scriptFile = pathPtr; Tcl_IncrRefCount(iPtr->scriptFile); string = Tcl_GetStringFromObj(objPtr, &length); #ifdef TCL_TIP280 /* TIP #280 Force the evaluator to open a frame for a sourced * file. */ iPtr->evalFlags |= TCL_EVAL_FILE; #endif result = Tcl_EvalEx(interp, string, length, 0); /* * Now we have to be careful; the script may have changed the * iPtr->scriptFile value, so we must reset it without * assuming it still points to 'pathPtr'. */ if (iPtr->scriptFile != NULL) { Tcl_DecrRefCount(iPtr->scriptFile); } iPtr->scriptFile = oldScriptFile; if (result == TCL_RETURN) { result = TclUpdateReturnInfo(iPtr); } else if (result == TCL_ERROR) { char msg[200 + TCL_INTEGER_SPACE]; /* * Record information telling where the error occurred. */ sprintf(msg, "\n (file \"%.150s\" line %d)", Tcl_GetString(pathPtr), interp->errorLine); Tcl_AddErrorInfo(interp, msg); } end: Tcl_DecrRefCount(objPtr); return result; } /* *---------------------------------------------------------------------- * * Tcl_GetErrno -- * * Gets the current value of the Tcl error code variable. This is * currently the global variable "errno" but could in the future * change to something else. * * Results: * The value of the Tcl error code variable. * * Side effects: * None. Note that the value of the Tcl error code variable is * UNDEFINED if a call to Tcl_SetErrno did not precede this call. * *---------------------------------------------------------------------- */ int Tcl_GetErrno() { return errno; } /* *---------------------------------------------------------------------- * * Tcl_SetErrno -- * * Sets the Tcl error code variable to the supplied value. * * Results: * None. * * Side effects: * Modifies the value of the Tcl error code variable. * *---------------------------------------------------------------------- */ void Tcl_SetErrno(err) int err; /* The new value. */ { errno = err; } /* *---------------------------------------------------------------------- * * Tcl_PosixError -- * * This procedure is typically called after UNIX kernel calls * return errors. It stores machine-readable information about * the error in $errorCode returns an information string for * the caller's use. * * Results: * The return value is a human-readable string describing the * error. * * Side effects: * The global variable $errorCode is reset. * *---------------------------------------------------------------------- */ CONST char * Tcl_PosixError(interp) Tcl_Interp *interp; /* Interpreter whose $errorCode variable * is to be changed. */ { CONST char *id, *msg; msg = Tcl_ErrnoMsg(errno); id = Tcl_ErrnoId(); if (interp) { Tcl_SetErrorCode(interp, "POSIX", id, msg, (char *) NULL); } return msg; } /* *---------------------------------------------------------------------- * * Tcl_FSStat -- * * This procedure replaces the library version of stat and lsat. * * The appropriate function for the filesystem to which pathPtr * belongs will be called. * * Results: * See stat documentation. * * Side effects: * See stat documentation. * *---------------------------------------------------------------------- */ int Tcl_FSStat(pathPtr, buf) Tcl_Obj *pathPtr; /* Path of file to stat (in current CP). */ Tcl_StatBuf *buf; /* Filled with results of stat call. */ { Tcl_Filesystem *fsPtr; #ifdef USE_OBSOLETE_FS_HOOKS Tcl_StatBuf oldStyleStatBuffer; int retVal = -1; /* * Call each of the "stat" function in succession. A non-return * value of -1 indicates the particular function has succeeded. */ Tcl_MutexLock(&obsoleteFsHookMutex); if (statProcList != NULL) { StatProc *statProcPtr; char *path; Tcl_Obj *transPtr = Tcl_FSGetTranslatedPath(NULL, pathPtr); if (transPtr == NULL) { path = NULL; } else { path = Tcl_GetString(transPtr); } statProcPtr = statProcList; while ((retVal == -1) && (statProcPtr != NULL)) { retVal = (*statProcPtr->proc)(path, &oldStyleStatBuffer); statProcPtr = statProcPtr->nextPtr; } if (transPtr != NULL) { Tcl_DecrRefCount(transPtr); } } Tcl_MutexUnlock(&obsoleteFsHookMutex); if (retVal != -1) { /* * Note that EOVERFLOW is not a problem here, and these * assignments should all be widening (if not identity.) */ buf->st_mode = oldStyleStatBuffer.st_mode; buf->st_ino = oldStyleStatBuffer.st_ino; buf->st_dev = oldStyleStatBuffer.st_dev; buf->st_rdev = oldStyleStatBuffer.st_rdev; buf->st_nlink = oldStyleStatBuffer.st_nlink; buf->st_uid = oldStyleStatBuffer.st_uid; buf->st_gid = oldStyleStatBuffer.st_gid; buf->st_size = Tcl_LongAsWide(oldStyleStatBuffer.st_size); buf->st_atime = oldStyleStatBuffer.st_atime; buf->st_mtime = oldStyleStatBuffer.st_mtime; buf->st_ctime = oldStyleStatBuffer.st_ctime; #ifdef HAVE_ST_BLOCKS buf->st_blksize = oldStyleStatBuffer.st_blksize; buf->st_blocks = Tcl_LongAsWide(oldStyleStatBuffer.st_blocks); #endif return retVal; } #endif /* USE_OBSOLETE_FS_HOOKS */ fsPtr = Tcl_FSGetFileSystemForPath(pathPtr); if (fsPtr != NULL) { Tcl_FSStatProc *proc = fsPtr->statProc; if (proc != NULL) { return (*proc)(pathPtr, buf); } } Tcl_SetErrno(ENOENT); return -1; } /* *---------------------------------------------------------------------- * * Tcl_FSLstat -- * * This procedure replaces the library version of lstat. * The appropriate function for the filesystem to which pathPtr * belongs will be called. If no 'lstat' function is listed, * but a 'stat' function is, then Tcl will fall back on the * stat function. * * Results: * See lstat documentation. * * Side effects: * See lstat documentation. * *---------------------------------------------------------------------- */ int Tcl_FSLstat(pathPtr, buf) Tcl_Obj *pathPtr; /* Path of file to stat (in current CP). */ Tcl_StatBuf *buf; /* Filled with results of stat call. */ { Tcl_Filesystem *fsPtr = Tcl_FSGetFileSystemForPath(pathPtr); if (fsPtr != NULL) { Tcl_FSLstatProc *proc = fsPtr->lstatProc; if (proc != NULL) { return (*proc)(pathPtr, buf); } else { Tcl_FSStatProc *sproc = fsPtr->statProc; if (sproc != NULL) { return (*sproc)(pathPtr, buf); } } } Tcl_SetErrno(ENOENT); return -1; } /* *---------------------------------------------------------------------- * * Tcl_FSAccess -- * * This procedure replaces the library version of access. * The appropriate function for the filesystem to which pathPtr * belongs will be called. * * Results: * See access documentation. * * Side effects: * See access documentation. * *---------------------------------------------------------------------- */ int Tcl_FSAccess(pathPtr, mode) Tcl_Obj *pathPtr; /* Path of file to access (in current CP). */ int mode; /* Permission setting. */ { Tcl_Filesystem *fsPtr; #ifdef USE_OBSOLETE_FS_HOOKS int retVal = -1; /* * Call each of the "access" function in succession. A non-return * value of -1 indicates the particular function has succeeded. */ Tcl_MutexLock(&obsoleteFsHookMutex); if (accessProcList != NULL) { AccessProc *accessProcPtr; char *path; Tcl_Obj *transPtr = Tcl_FSGetTranslatedPath(NULL, pathPtr); if (transPtr == NULL) { path = NULL; } else { path = Tcl_GetString(transPtr); } accessProcPtr = accessProcList; while ((retVal == -1) && (accessProcPtr != NULL)) { retVal = (*accessProcPtr->proc)(path, mode); accessProcPtr = accessProcPtr->nextPtr; } if (transPtr != NULL) { Tcl_DecrRefCount(transPtr); } } Tcl_MutexUnlock(&obsoleteFsHookMutex); if (retVal != -1) { return retVal; } #endif /* USE_OBSOLETE_FS_HOOKS */ fsPtr = Tcl_FSGetFileSystemForPath(pathPtr); if (fsPtr != NULL) { Tcl_FSAccessProc *proc = fsPtr->accessProc; if (proc != NULL) { return (*proc)(pathPtr, mode); } } Tcl_SetErrno(ENOENT); return -1; } /* *---------------------------------------------------------------------- * * Tcl_FSOpenFileChannel -- * * The appropriate function for the filesystem to which pathPtr * belongs will be called. * * Results: * The new channel or NULL, if the named file could not be opened. * * Side effects: * May open the channel and may cause creation of a file on the * file system. * *---------------------------------------------------------------------- */ Tcl_Channel Tcl_FSOpenFileChannel(interp, pathPtr, modeString, permissions) Tcl_Interp *interp; /* Interpreter for error reporting; * can be NULL. */ Tcl_Obj *pathPtr; /* Name of file to open. */ CONST char *modeString; /* A list of POSIX open modes or * a string such as "rw". */ int permissions; /* If the open involves creating a * file, with what modes to create * it? */ { Tcl_Filesystem *fsPtr; #ifdef USE_OBSOLETE_FS_HOOKS Tcl_Channel retVal = NULL; /* * Call each of the "Tcl_OpenFileChannel" functions in succession. * A non-NULL return value indicates the particular function has * succeeded. */ Tcl_MutexLock(&obsoleteFsHookMutex); if (openFileChannelProcList != NULL) { OpenFileChannelProc *openFileChannelProcPtr; char *path; Tcl_Obj *transPtr = Tcl_FSGetTranslatedPath(interp, pathPtr); if (transPtr == NULL) { path = NULL; } else { path = Tcl_GetString(transPtr); } openFileChannelProcPtr = openFileChannelProcList; while ((retVal == NULL) && (openFileChannelProcPtr != NULL)) { retVal = (*openFileChannelProcPtr->proc)(interp, path, modeString, permissions); openFileChannelProcPtr = openFileChannelProcPtr->nextPtr; } if (transPtr != NULL) { Tcl_DecrRefCount(transPtr); } } Tcl_MutexUnlock(&obsoleteFsHookMutex); if (retVal != NULL) { return retVal; } #endif /* USE_OBSOLETE_FS_HOOKS */ /* * We need this just to ensure we return the correct error messages * under some circumstances. */ if (Tcl_FSGetNormalizedPath(interp, pathPtr) == NULL) { return NULL; } fsPtr = Tcl_FSGetFileSystemForPath(pathPtr); if (fsPtr != NULL) { Tcl_FSOpenFileChannelProc *proc = fsPtr->openFileChannelProc; if (proc != NULL) { int mode, seekFlag; mode = TclGetOpenMode(interp, modeString, &seekFlag); if (mode == -1) { return NULL; } retVal = (*proc)(interp, pathPtr, mode, permissions); if (retVal != NULL) { if (seekFlag) { if (Tcl_Seek(retVal, (Tcl_WideInt)0, SEEK_END) < (Tcl_WideInt)0) { if (interp != (Tcl_Interp *) NULL) { Tcl_AppendResult(interp, "could not seek to end of file while opening \"", Tcl_GetString(pathPtr), "\": ", Tcl_PosixError(interp), (char *) NULL); } Tcl_Close(NULL, retVal); return NULL; } } } return retVal; } } /* File doesn't belong to any filesystem that can open it */ Tcl_SetErrno(ENOENT); if (interp != NULL) { Tcl_AppendResult(interp, "couldn't open \"", Tcl_GetString(pathPtr), "\": ", Tcl_PosixError(interp), (char *) NULL); } return NULL; } /* *---------------------------------------------------------------------- * * Tcl_FSUtime -- * * This procedure replaces the library version of utime. * The appropriate function for the filesystem to which pathPtr * belongs will be called. * * Results: * See utime documentation. * * Side effects: * See utime documentation. * *---------------------------------------------------------------------- */ int Tcl_FSUtime (pathPtr, tval) Tcl_Obj *pathPtr; /* File to change access/modification times */ struct utimbuf *tval; /* Structure containing access/modification * times to use. Should not be modified. */ { Tcl_Filesystem *fsPtr = Tcl_FSGetFileSystemForPath(pathPtr); if (fsPtr != NULL) { Tcl_FSUtimeProc *proc = fsPtr->utimeProc; if (proc != NULL) { return (*proc)(pathPtr, tval); } } return -1; } /* *---------------------------------------------------------------------- * * NativeFileAttrStrings -- * * This procedure implements the platform dependent 'file * attributes' subcommand, for the native filesystem, for listing * the set of possible attribute strings. This function is part * of Tcl's native filesystem support, and is placed here because * it is shared by Unix, MacOS and Windows code. * * Results: * An array of strings * * Side effects: * None. * *---------------------------------------------------------------------- */ static CONST char** NativeFileAttrStrings(pathPtr, objPtrRef) Tcl_Obj *pathPtr; Tcl_Obj** objPtrRef; { return tclpFileAttrStrings; } /* *---------------------------------------------------------------------- * * NativeFileAttrsGet -- * * This procedure implements the platform dependent * 'file attributes' subcommand, for the native * filesystem, for 'get' operations. This function is part * of Tcl's native filesystem support, and is placed here * because it is shared by Unix, MacOS and Windows code. * * Results: * Standard Tcl return code. The object placed in objPtrRef * (if TCL_OK was returned) is likely to have a refCount of zero. * Either way we must either store it somewhere (e.g. the Tcl * result), or Incr/Decr its refCount to ensure it is properly * freed. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int NativeFileAttrsGet(interp, index, pathPtr, objPtrRef) Tcl_Interp *interp; /* The interpreter for error reporting. */ int index; /* index of the attribute command. */ Tcl_Obj *pathPtr; /* path of file we are operating on. */ Tcl_Obj **objPtrRef; /* for output. */ { return (*tclpFileAttrProcs[index].getProc)(interp, index, pathPtr, objPtrRef); } /* *---------------------------------------------------------------------- * * NativeFileAttrsSet -- * * This procedure implements the platform dependent * 'file attributes' subcommand, for the native * filesystem, for 'set' operations. This function is part * of Tcl's native filesystem support, and is placed here * because it is shared by Unix, MacOS and Windows code. * * Results: * Standard Tcl return code. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int NativeFileAttrsSet(interp, index, pathPtr, objPtr) Tcl_Interp *interp; /* The interpreter for error reporting. */ int index; /* index of the attribute command. */ Tcl_Obj *pathPtr; /* path of file we are operating on. */ Tcl_Obj *objPtr; /* set to this value. */ { return (*tclpFileAttrProcs[index].setProc)(interp, index, pathPtr, objPtr); } /* *---------------------------------------------------------------------- * * Tcl_FSFileAttrStrings -- * * This procedure implements part of the hookable 'file * attributes' subcommand. The appropriate function for the * filesystem to which pathPtr belongs will be called. * * Results: * The called procedure may either return an array of strings, * or may instead return NULL and place a Tcl list into the * given objPtrRef. Tcl will take that list and first increment * its refCount before using it. On completion of that use, Tcl * will decrement its refCount. Hence if the list should be * disposed of by Tcl when done, it should have a refCount of zero, * and if the list should not be disposed of, the filesystem * should ensure it retains a refCount on the object. * * Side effects: * None. * *---------------------------------------------------------------------- */ CONST char ** Tcl_FSFileAttrStrings(pathPtr, objPtrRef) Tcl_Obj* pathPtr; Tcl_Obj** objPtrRef; { Tcl_Filesystem *fsPtr = Tcl_FSGetFileSystemForPath(pathPtr); if (fsPtr != NULL) { Tcl_FSFileAttrStringsProc *proc = fsPtr->fileAttrStringsProc; if (proc != NULL) { return (*proc)(pathPtr, objPtrRef); } } Tcl_SetErrno(ENOENT); return NULL; } /* *---------------------------------------------------------------------- * * Tcl_FSFileAttrsGet -- * * This procedure implements read access for the hookable 'file * attributes' subcommand. The appropriate function for the * filesystem to which pathPtr belongs will be called. * * Results: * Standard Tcl return code. The object placed in objPtrRef * (if TCL_OK was returned) is likely to have a refCount of zero. * Either way we must either store it somewhere (e.g. the Tcl * result), or Incr/Decr its refCount to ensure it is properly * freed. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_FSFileAttrsGet(interp, index, pathPtr, objPtrRef) Tcl_Interp *interp; /* The interpreter for error reporting. */ int index; /* index of the attribute command. */ Tcl_Obj *pathPtr; /* filename we are operating on. */ Tcl_Obj **objPtrRef; /* for output. */ { Tcl_Filesystem *fsPtr = Tcl_FSGetFileSystemForPath(pathPtr); if (fsPtr != NULL) { Tcl_FSFileAttrsGetProc *proc = fsPtr->fileAttrsGetProc; if (proc != NULL) { return (*proc)(interp, index, pathPtr, objPtrRef); } } Tcl_SetErrno(ENOENT); return -1; } /* *---------------------------------------------------------------------- * * Tcl_FSFileAttrsSet -- * * This procedure implements write access for the hookable 'file * attributes' subcommand. The appropriate function for the * filesystem to which pathPtr belongs will be called. * * Results: * Standard Tcl return code. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_FSFileAttrsSet(interp, index, pathPtr, objPtr) Tcl_Interp *interp; /* The interpreter for error reporting. */ int index; /* index of the attribute command. */ Tcl_Obj *pathPtr; /* filename we are operating on. */ Tcl_Obj *objPtr; /* Input value. */ { Tcl_Filesystem *fsPtr = Tcl_FSGetFileSystemForPath(pathPtr); if (fsPtr != NULL) { Tcl_FSFileAttrsSetProc *proc = fsPtr->fileAttrsSetProc; if (proc != NULL) { return (*proc)(interp, index, pathPtr, objPtr); } } Tcl_SetErrno(ENOENT); return -1; } /* *---------------------------------------------------------------------- * * Tcl_FSGetCwd -- * * This function replaces the library version of getcwd(). * * Most VFS's will *not* implement a 'cwdProc'. Tcl now maintains * its own record (in a Tcl_Obj) of the cwd, and an attempt * is made to synchronise this with the cwd's containing filesystem, * if that filesystem provides a cwdProc (e.g. the native filesystem). * * Note that if Tcl's cwd is not in the native filesystem, then of * course Tcl's cwd and the native cwd are different: extensions * should therefore ensure they only access the cwd through this * function to avoid confusion. * * If a global cwdPathPtr already exists, it is cached in the thread's * private data structures and reference to the cached copy is returned, * subject to a synchronisation attempt in that cwdPathPtr's fs. * * Otherwise, the chain of functions that have been "inserted" * into the filesystem will be called in succession until either a * value other than NULL is returned, or the entire list is * visited. * * Results: * The result is a pointer to a Tcl_Obj specifying the current * directory, or NULL if the current directory could not be * determined. If NULL is returned, an error message is left in the * interp's result. * * The result already has its refCount incremented for the caller. * When it is no longer needed, that refCount should be decremented. * * Side effects: * Various objects may be freed and allocated. * *---------------------------------------------------------------------- */ Tcl_Obj* Tcl_FSGetCwd(interp) Tcl_Interp *interp; { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (TclFSCwdPointerEquals(NULL)) { FilesystemRecord *fsRecPtr; Tcl_Obj *retVal = NULL; /* * We've never been called before, try to find a cwd. Call * each of the "Tcl_GetCwd" function in succession. A non-NULL * return value indicates the particular function has * succeeded. */ fsRecPtr = FsGetFirstFilesystem(); while ((retVal == NULL) && (fsRecPtr != NULL)) { Tcl_FSGetCwdProc *proc = fsRecPtr->fsPtr->getCwdProc; if (proc != NULL) { retVal = (*proc)(interp); } fsRecPtr = fsRecPtr->nextPtr; } /* * Now the 'cwd' may NOT be normalized, at least on some * platforms. For the sake of efficiency, we want a completely * normalized cwd at all times. * * Finally, if retVal is NULL, we do not have a cwd, which * could be problematic. */ if (retVal != NULL) { Tcl_Obj *norm = TclFSNormalizeAbsolutePath(interp, retVal); if (norm != NULL) { /* * We found a cwd, which is now in our global storage. * We must make a copy. Norm already has a refCount of 1. * * Threading issue: note that multiple threads at system * startup could in principle call this procedure * simultaneously. They will therefore each set the * cwdPathPtr independently. That behaviour is a bit * peculiar, but should be fine. Once we have a cwd, * we'll always be in the 'else' branch below which * is simpler. */ FsUpdateCwd(norm); Tcl_DecrRefCount(norm); } Tcl_DecrRefCount(retVal); } } else { /* * We already have a cwd cached, but we want to give the * filesystem it is in a chance to check whether that cwd * has changed, or is perhaps no longer accessible. This * allows an error to be thrown if, say, the permissions on * that directory have changed. */ Tcl_Filesystem *fsPtr = Tcl_FSGetFileSystemForPath(tsdPtr->cwdPathPtr); /* * If the filesystem couldn't be found, or if no cwd function * exists for this filesystem, then we simply assume the cached * cwd is ok. If we do call a cwd, we must watch for errors * (if the cwd returns NULL). This ensures that, say, on Unix * if the permissions of the cwd change, 'pwd' does actually * throw the correct error in Tcl. (This is tested for in the * test suite on unix). */ if (fsPtr != NULL) { Tcl_FSGetCwdProc *proc = fsPtr->getCwdProc; if (proc != NULL) { Tcl_Obj *retVal = (*proc)(interp); if (retVal != NULL) { Tcl_Obj *norm = TclFSNormalizeAbsolutePath(interp, retVal); /* * Check whether cwd has changed from the value * previously stored in cwdPathPtr. Really 'norm' * shouldn't be null, but we are careful. */ if (norm == NULL) { /* Do nothing */ } else if (Tcl_FSEqualPaths(tsdPtr->cwdPathPtr, norm)) { /* * If the paths were equal, we can be more * efficient and retain the old path object * which will probably already be shared. In * this case we can simply free the normalized * path we just calculated. */ Tcl_DecrRefCount(norm); } else { FsUpdateCwd(norm); Tcl_DecrRefCount(norm); } Tcl_DecrRefCount(retVal); } else { /* The 'cwd' function returned an error; reset the cwd */ FsUpdateCwd(NULL); } } } } if (tsdPtr->cwdPathPtr != NULL) { Tcl_IncrRefCount(tsdPtr->cwdPathPtr); } return tsdPtr->cwdPathPtr; } /* *---------------------------------------------------------------------- * * Tcl_FSChdir -- * * This function replaces the library version of chdir(). * * The path is normalized and then passed to the filesystem * which claims it. * * Results: * See chdir() documentation. If successful, we keep a * record of the successful path in cwdPathPtr for subsequent * calls to getcwd. * * Side effects: * See chdir() documentation. The global cwdPathPtr may * change value. * *---------------------------------------------------------------------- */ int Tcl_FSChdir(pathPtr) Tcl_Obj *pathPtr; { Tcl_Filesystem *fsPtr; int retVal = -1; #ifdef WIN32 /* * This complete hack addresses the bug tested in winFCmd-16.12, * where having your HOME as "C:" (IOW, a seemingly path relative * dir) would cause a crash when you cd'd to it and requested 'pwd'. * The work-around is to force such a dir into an absolute path by * tacking on '/'. * * We check for '~' specifically because that's what Tcl_CdObjCmd * passes in that triggers the bug. A direct 'cd C:' call will not * because that gets the volumerelative pwd. * * This is not an issue for 8.5 as that has a more elaborate change * that requires the use of TCL_FILESYSTEM_VERSION_2. */ Tcl_Obj *objPtr = NULL; if (pathPtr->bytes && pathPtr->length == 1 && pathPtr->bytes[0] == '~') { int len; char *str; objPtr = Tcl_FSGetTranslatedPath(NULL, pathPtr); if (objPtr == NULL) { Tcl_SetErrno(ENOENT); return -1; } Tcl_IncrRefCount(objPtr); str = Tcl_GetStringFromObj(objPtr, &len); if (len == 2 && str[1] == ':') { pathPtr = Tcl_NewStringObj(str, len); Tcl_AppendToObj(pathPtr, "/", 1); Tcl_IncrRefCount(pathPtr); Tcl_DecrRefCount(objPtr); objPtr = pathPtr; } else { Tcl_DecrRefCount(objPtr); objPtr = NULL; } } #endif if (Tcl_FSGetNormalizedPath(NULL, pathPtr) == NULL) { #ifdef WIN32 if (objPtr) { Tcl_DecrRefCount(objPtr); } #endif Tcl_SetErrno(ENOENT); return -1; } fsPtr = Tcl_FSGetFileSystemForPath(pathPtr); if (fsPtr != NULL) { Tcl_FSChdirProc *proc = fsPtr->chdirProc; if (proc != NULL) { retVal = (*proc)(pathPtr); } else { /* Fallback on stat-based implementation */ Tcl_StatBuf buf; /* If the file can be stat'ed and is a directory and * is readable, then we can chdir. */ if ((Tcl_FSStat(pathPtr, &buf) == 0) && (S_ISDIR(buf.st_mode)) && (Tcl_FSAccess(pathPtr, R_OK) == 0)) { /* We allow the chdir */ retVal = 0; } } } if (retVal != -1) { /* * The cwd changed, or an error was thrown. If an error was * thrown, we can just continue (and that will report the error * to the user). If there was no error we must assume that the * cwd was actually changed to the normalized value we * calculated above, and we must therefore cache that * information. */ if (retVal == 0) { /* * Note that this normalized path may be different to what * we found above (or at least a different object), if the * filesystem epoch changed recently. This can actually * happen with scripted documents very easily. Therefore * we ask for the normalized path again (the correct value * will have been cached as a result of the * Tcl_FSGetFileSystemForPath call above anyway). */ Tcl_Obj *normDirName = Tcl_FSGetNormalizedPath(NULL, pathPtr); if (normDirName == NULL) { #ifdef WIN32 if (objPtr) { Tcl_DecrRefCount(objPtr); } #endif Tcl_SetErrno(ENOENT); return -1; } FsUpdateCwd(normDirName); } } else { Tcl_SetErrno(ENOENT); } #ifdef WIN32 if (objPtr) { Tcl_DecrRefCount(objPtr); } #endif return (retVal); } /* *---------------------------------------------------------------------- * * Tcl_FSLoadFile -- * * Dynamically loads a binary code file into memory and returns * the addresses of two procedures within that file, if they are * defined. The appropriate function for the filesystem to which * pathPtr belongs will be called. * * Note that the native filesystem doesn't actually assume * 'pathPtr' is a path. Rather it assumes filename is either * a path or just the name of a file which can be found somewhere * in the environment's loadable path. This behaviour is not * very compatible with virtual filesystems (and has other problems * documented in the load man-page), so it is advised that full * paths are always used. * * Results: * A standard Tcl completion code. If an error occurs, an error * message is left in the interp's result. * * Side effects: * New code suddenly appears in memory. This may later be * unloaded by passing the clientData to the unloadProc. * *---------------------------------------------------------------------- */ typedef int (Tcl_FSLoadFileProc2) (Tcl_Interp *interp, Tcl_Obj *pathPtr, Tcl_LoadHandle *handlePtr, Tcl_FSUnloadFileProc **unloadProcPtr, int flags); int Tcl_FSLoadFile(interp, pathPtr, sym1, sym2, proc1Ptr, proc2Ptr, handlePtr, unloadProcPtr) Tcl_Interp *interp; /* Used for error reporting. */ Tcl_Obj *pathPtr; /* Name of the file containing the desired * code. */ CONST char *sym1, *sym2; /* Names of two procedures to look up in * the file's symbol table. */ Tcl_PackageInitProc **proc1Ptr, **proc2Ptr; /* Where to return the addresses corresponding * to sym1 and sym2. */ Tcl_LoadHandle *handlePtr; /* Filled with token for dynamically loaded * file which will be passed back to * (*unloadProcPtr)() to unload the file. */ Tcl_FSUnloadFileProc **unloadProcPtr; /* Filled with address of Tcl_FSUnloadFileProc * function which should be used for * this file. */ { Tcl_Filesystem *fsPtr = Tcl_FSGetFileSystemForPath(pathPtr); if (fsPtr != NULL) { Tcl_FSLoadFileProc *proc = fsPtr->loadFileProc; if (proc != NULL) { int retVal = ((Tcl_FSLoadFileProc2 *)proc) (interp, pathPtr, handlePtr, unloadProcPtr, 0); if (retVal != TCL_OK) { return retVal; } if (*handlePtr == NULL) { return TCL_ERROR; } if (sym1 != NULL) { *proc1Ptr = TclpFindSymbol(interp, *handlePtr, sym1); } if (sym2 != NULL) { *proc2Ptr = TclpFindSymbol(interp, *handlePtr, sym2); } return retVal; } else { Tcl_Filesystem *copyFsPtr; Tcl_Obj *copyToPtr; /* First check if it is readable -- and exists! */ if (Tcl_FSAccess(pathPtr, R_OK) != 0) { Tcl_AppendResult(interp, "couldn't load library \"", Tcl_GetString(pathPtr), "\": ", Tcl_PosixError(interp), (char *) NULL); return TCL_ERROR; } #ifdef TCL_LOAD_FROM_MEMORY /* * The platform supports loading code from memory, so ask for a * buffer of the appropriate size, read the file into it and * load the code from the buffer: */ do { int ret, size; void *buffer; Tcl_StatBuf statBuf; Tcl_Channel data; ret = Tcl_FSStat(pathPtr, &statBuf); if (ret < 0) { break; } size = (int) statBuf.st_size; /* Tcl_Read takes an int: check that file size isn't wide */ if (size != (Tcl_WideInt)statBuf.st_size) { break; } data = Tcl_FSOpenFileChannel(interp, pathPtr, "r", 0666); if (!data) { break; } buffer = TclpLoadMemoryGetBuffer(interp, size); if (!buffer) { Tcl_Close(interp, data); break; } Tcl_SetChannelOption(interp, data, "-translation", "binary"); ret = Tcl_Read(data, buffer, size); Tcl_Close(interp, data); ret = TclpLoadMemory(interp, buffer, size, ret, handlePtr, unloadProcPtr); if (ret == TCL_OK) { if (*handlePtr == NULL) { break; } if (sym1 != NULL) { *proc1Ptr = TclpFindSymbol(interp, *handlePtr, sym1); } if (sym2 != NULL) { *proc2Ptr = TclpFindSymbol(interp, *handlePtr, sym2); } return TCL_OK; } } while (0); Tcl_ResetResult(interp); #endif /* * Get a temporary filename to use, first to * copy the file into, and then to load. */ copyToPtr = TclpTempFileName(); if (copyToPtr == NULL) { return -1; } Tcl_IncrRefCount(copyToPtr); copyFsPtr = Tcl_FSGetFileSystemForPath(copyToPtr); if ((copyFsPtr == NULL) || (copyFsPtr == fsPtr)) { /* * We already know we can't use Tcl_FSLoadFile from * this filesystem, and we must avoid a possible * infinite loop. Try to delete the file we * probably created, and then exit. */ Tcl_FSDeleteFile(copyToPtr); Tcl_DecrRefCount(copyToPtr); return -1; } if (TclCrossFilesystemCopy(interp, pathPtr, copyToPtr) == TCL_OK) { Tcl_LoadHandle newLoadHandle = NULL; Tcl_FSUnloadFileProc *newUnloadProcPtr = NULL; FsDivertLoad *tvdlPtr; int retVal; #if !defined(__WIN32__) /* * Do we need to set appropriate permissions * on the file? This may be required on some * systems. On Unix we could loop over * the file attributes, and set any that are * called "-permissions" to 0700. However, * we just do this directly, like this: */ Tcl_Obj* perm = Tcl_NewStringObj("0700",-1); Tcl_IncrRefCount(perm); Tcl_FSFileAttrsSet(NULL, 2, copyToPtr, perm); Tcl_DecrRefCount(perm); #endif /* * We need to reset the result now, because the cross- * filesystem copy may have stored the number of bytes * in the result */ Tcl_ResetResult(interp); retVal = Tcl_FSLoadFile(interp, copyToPtr, sym1, sym2, proc1Ptr, proc2Ptr, &newLoadHandle, &newUnloadProcPtr); if (retVal != TCL_OK) { /* The file didn't load successfully */ Tcl_FSDeleteFile(copyToPtr); Tcl_DecrRefCount(copyToPtr); return retVal; } /* * Try to delete the file immediately -- this is * possible in some OSes, and avoids any worries * about leaving the copy laying around on exit. */ if (Tcl_FSDeleteFile(copyToPtr) == TCL_OK) { Tcl_DecrRefCount(copyToPtr); /* * We tell our caller about the real shared * library which was loaded. Note that this * does mean that the package list maintained * by 'load' will store the original (vfs) * path alongside the temporary load handle * and unload proc ptr. */ (*handlePtr) = newLoadHandle; (*unloadProcPtr) = newUnloadProcPtr; return TCL_OK; } /* * When we unload this file, we need to divert the * unloading so we can unload and cleanup the * temporary file correctly. */ tvdlPtr = (FsDivertLoad*) ckalloc(sizeof(FsDivertLoad)); /* * Remember three pieces of information. This allows * us to cleanup the diverted load completely, on * platforms which allow proper unloading of code. */ tvdlPtr->loadHandle = newLoadHandle; tvdlPtr->unloadProcPtr = newUnloadProcPtr; if (copyFsPtr != &tclNativeFilesystem) { /* copyToPtr is already incremented for this reference */ tvdlPtr->divertedFile = copyToPtr; /* * This is the filesystem we loaded it into. Since * we have a reference to 'copyToPtr', we already * have a refCount on this filesystem, so we don't * need to worry about it disappearing on us. */ tvdlPtr->divertedFilesystem = copyFsPtr; tvdlPtr->divertedFileNativeRep = NULL; } else { /* We need the native rep */ tvdlPtr->divertedFileNativeRep = TclNativeDupInternalRep(Tcl_FSGetInternalRep(copyToPtr, copyFsPtr)); /* * We don't need or want references to the copied * Tcl_Obj or the filesystem if it is the native * one. */ tvdlPtr->divertedFile = NULL; tvdlPtr->divertedFilesystem = NULL; Tcl_DecrRefCount(copyToPtr); } copyToPtr = NULL; (*handlePtr) = (Tcl_LoadHandle) tvdlPtr; (*unloadProcPtr) = &FSUnloadTempFile; return retVal; } else { /* Cross-platform copy failed */ Tcl_FSDeleteFile(copyToPtr); Tcl_DecrRefCount(copyToPtr); return TCL_ERROR; } } } Tcl_SetErrno(ENOENT); return -1; } /* * This function used to be in the platform specific directories, but it * has now been made to work cross-platform */ int TclpLoadFile(interp, pathPtr, sym1, sym2, proc1Ptr, proc2Ptr, clientDataPtr, unloadProcPtr) Tcl_Interp *interp; /* Used for error reporting. */ Tcl_Obj *pathPtr; /* Name of the file containing the desired * code (UTF-8). */ CONST char *sym1, *sym2; /* Names of two procedures to look up in * the file's symbol table. */ Tcl_PackageInitProc **proc1Ptr, **proc2Ptr; /* Where to return the addresses corresponding * to sym1 and sym2. */ ClientData *clientDataPtr; /* Filled with token for dynamically loaded * file which will be passed back to * (*unloadProcPtr)() to unload the file. */ Tcl_FSUnloadFileProc **unloadProcPtr; /* Filled with address of Tcl_FSUnloadFileProc * function which should be used for * this file. */ { Tcl_LoadHandle handle = NULL; int res; res = TclpDlopen(interp, pathPtr, &handle, unloadProcPtr); if (res != TCL_OK) { return res; } if (handle == NULL) { return TCL_ERROR; } *clientDataPtr = (ClientData)handle; *proc1Ptr = TclpFindSymbol(interp, handle, sym1); *proc2Ptr = TclpFindSymbol(interp, handle, sym2); return TCL_OK; } /* *--------------------------------------------------------------------------- * * FSUnloadTempFile -- * * This function is called when we loaded a library of code via * an intermediate temporary file. This function ensures * the library is correctly unloaded and the temporary file * is correctly deleted. * * Results: * None. * * Side effects: * The effects of the 'unload' function called, and of course * the temporary file will be deleted. * *--------------------------------------------------------------------------- */ static void FSUnloadTempFile(loadHandle) Tcl_LoadHandle loadHandle; /* loadHandle returned by a previous call * to Tcl_FSLoadFile(). The loadHandle is * a token that represents the loaded * file. */ { FsDivertLoad *tvdlPtr = (FsDivertLoad*)loadHandle; /* * This test should never trigger, since we give * the client data in the function above. */ if (tvdlPtr == NULL) { return; } /* * Call the real 'unloadfile' proc we actually used. It is very * important that we call this first, so that the shared library * is actually unloaded by the OS. Otherwise, the following * 'delete' may well fail because the shared library is still in * use. */ if (tvdlPtr->unloadProcPtr != NULL) { (*tvdlPtr->unloadProcPtr)(tvdlPtr->loadHandle); } if (tvdlPtr->divertedFilesystem == NULL) { /* * It was the native filesystem, and we have a special * function available just for this purpose, which we * know works even at this late stage. */ TclpDeleteFile(tvdlPtr->divertedFileNativeRep); NativeFreeInternalRep(tvdlPtr->divertedFileNativeRep); } else { /* * Remove the temporary file we created. Note, we may crash * here because encodings have been taken down already. */ if (tvdlPtr->divertedFilesystem->deleteFileProc(tvdlPtr->divertedFile) != TCL_OK) { /* * The above may have failed because the filesystem, or something * it depends upon (e.g. encodings) have been taken down because * Tcl is exiting. * * We may need to work out how to delete this file more * robustly (or give the filesystem the information it needs * to delete the file more robustly). * * In particular, one problem might be that the filesystem * cannot extract the information it needs from the above * path object because Tcl's entire filesystem apparatus * (the code in this file) has been finalized, and it * refuses to pass the internal representation to the * filesystem. */ } /* * And free up the allocations. This will also of course remove * a refCount from the Tcl_Filesystem to which this file belongs, * which could then free up the filesystem if we are exiting. */ Tcl_DecrRefCount(tvdlPtr->divertedFile); } ckfree((char*)tvdlPtr); } /* *--------------------------------------------------------------------------- * * Tcl_FSLink -- * * This function replaces the library version of readlink() and * can also be used to make links. The appropriate function for * the filesystem to which pathPtr belongs will be called. * * Results: * If toPtr is NULL, then the result is a Tcl_Obj specifying the * contents of the symbolic link given by 'pathPtr', or NULL if * the symbolic link could not be read. The result is owned by * the caller, which should call Tcl_DecrRefCount when the result * is no longer needed. * * If toPtr is non-NULL, then the result is toPtr if the link action * was successful, or NULL if not. In this case the result has no * additional reference count, and need not be freed. The actual * action to perform is given by the 'linkAction' flags, which is * an or'd combination of: * * TCL_CREATE_SYMBOLIC_LINK * TCL_CREATE_HARD_LINK * * Note that most filesystems will not support linking across * to different filesystems, so this function will usually * fail unless toPtr is in the same FS as pathPtr. * * Side effects: * See readlink() documentation. A new filesystem link * object may appear * *--------------------------------------------------------------------------- */ Tcl_Obj * Tcl_FSLink(pathPtr, toPtr, linkAction) Tcl_Obj *pathPtr; /* Path of file to readlink or link */ Tcl_Obj *toPtr; /* NULL or path to be linked to */ int linkAction; /* Action to perform */ { Tcl_Filesystem *fsPtr = Tcl_FSGetFileSystemForPath(pathPtr); if (fsPtr != NULL) { Tcl_FSLinkProc *proc = fsPtr->linkProc; if (proc != NULL) { return (*proc)(pathPtr, toPtr, linkAction); } } /* * If S_IFLNK isn't defined it means that the machine doesn't * support symbolic links, so the file can't possibly be a * symbolic link. Generate an EINVAL error, which is what * happens on machines that do support symbolic links when * you invoke readlink on a file that isn't a symbolic link. */ #ifndef S_IFLNK errno = EINVAL; #else Tcl_SetErrno(ENOENT); #endif /* S_IFLNK */ return NULL; } /* *--------------------------------------------------------------------------- * * Tcl_FSListVolumes -- * * Lists the currently mounted volumes. The chain of functions * that have been "inserted" into the filesystem will be called in * succession; each may return a list of volumes, all of which are * added to the result until all mounted file systems are listed. * * Notice that we assume the lists returned by each filesystem * (if non NULL) have been given a refCount for us already. * However, we are NOT allowed to hang on to the list itself * (it belongs to the filesystem we called). Therefore we * quite naturally add its contents to the result we are * building, and then decrement the refCount. * * Results: * The list of volumes, in an object which has refCount 0. * * Side effects: * None * *--------------------------------------------------------------------------- */ Tcl_Obj* Tcl_FSListVolumes(void) { FilesystemRecord *fsRecPtr; Tcl_Obj *resultPtr = Tcl_NewObj(); /* * Call each of the "listVolumes" function in succession. * A non-NULL return value indicates the particular function has * succeeded. We call all the functions registered, since we want * a list of all drives from all filesystems. */ fsRecPtr = FsGetFirstFilesystem(); while (fsRecPtr != NULL) { Tcl_FSListVolumesProc *proc = fsRecPtr->fsPtr->listVolumesProc; if (proc != NULL) { Tcl_Obj *thisFsVolumes = (*proc)(); if (thisFsVolumes != NULL) { Tcl_ListObjAppendList(NULL, resultPtr, thisFsVolumes); Tcl_DecrRefCount(thisFsVolumes); } } fsRecPtr = fsRecPtr->nextPtr; } return resultPtr; } /* *--------------------------------------------------------------------------- * * FsListMounts -- * * List all mounts within the given directory, which match the * given pattern. * * Results: * The list of mounts, in a list object which has refCount 0, or * NULL if we didn't even find any filesystems to try to list * mounts. * * Side effects: * None * *--------------------------------------------------------------------------- */ static Tcl_Obj* FsListMounts(pathPtr, pattern) Tcl_Obj *pathPtr; /* Contains path to directory to search. */ CONST char *pattern; /* Pattern to match against. */ { FilesystemRecord *fsRecPtr; Tcl_GlobTypeData mountsOnly = { TCL_GLOB_TYPE_MOUNT, 0, NULL, NULL }; Tcl_Obj *resultPtr = NULL; /* * Call each of the "listMounts" functions in succession. * A non-NULL return value indicates the particular function has * succeeded. We call all the functions registered, since we want * a list from each filesystems. */ fsRecPtr = FsGetFirstFilesystem(); while (fsRecPtr != NULL) { if (fsRecPtr->fsPtr != &tclNativeFilesystem) { Tcl_FSMatchInDirectoryProc *proc = fsRecPtr->fsPtr->matchInDirectoryProc; if (proc != NULL) { if (resultPtr == NULL) { resultPtr = Tcl_NewObj(); } (*proc)(NULL, resultPtr, pathPtr, pattern, &mountsOnly); } } fsRecPtr = fsRecPtr->nextPtr; } return resultPtr; } /* *--------------------------------------------------------------------------- * * Tcl_FSSplitPath -- * * This function takes the given Tcl_Obj, which should be a valid * path, and returns a Tcl List object containing each segment of * that path as an element. * * Results: * Returns list object with refCount of zero. If the passed in * lenPtr is non-NULL, we use it to return the number of elements * in the returned list. * * Side effects: * None. * *--------------------------------------------------------------------------- */ Tcl_Obj* Tcl_FSSplitPath(pathPtr, lenPtr) Tcl_Obj *pathPtr; /* Path to split. */ int *lenPtr; /* int to store number of path elements. */ { Tcl_Obj *result = NULL; /* Needed only to prevent gcc warnings. */ Tcl_Filesystem *fsPtr; char separator = '/'; int driveNameLength; char *p; /* * Perform platform specific splitting. */ if (FSGetPathType(pathPtr, &fsPtr, &driveNameLength) == TCL_PATH_ABSOLUTE) { if (fsPtr == &tclNativeFilesystem) { return TclpNativeSplitPath(pathPtr, lenPtr); } } else { return TclpNativeSplitPath(pathPtr, lenPtr); } /* We assume separators are single characters */ if (fsPtr->filesystemSeparatorProc != NULL) { Tcl_Obj *sep = (*fsPtr->filesystemSeparatorProc)(pathPtr); if (sep != NULL) { separator = Tcl_GetString(sep)[0]; } } /* * Place the drive name as first element of the * result list. The drive name may contain strange * characters, like colons and multiple forward slashes * (for example 'ftp://' is a valid vfs drive name) */ result = Tcl_NewObj(); p = Tcl_GetString(pathPtr); Tcl_ListObjAppendElement(NULL, result, Tcl_NewStringObj(p, driveNameLength)); p+= driveNameLength; /* Add the remaining path elements to the list */ for (;;) { char *elementStart = p; int length; while ((*p != '\0') && (*p != separator)) { p++; } length = p - elementStart; if (length > 0) { Tcl_Obj *nextElt; if (elementStart[0] == '~') { nextElt = Tcl_NewStringObj("./",2); Tcl_AppendToObj(nextElt, elementStart, length); } else { nextElt = Tcl_NewStringObj(elementStart, length); } Tcl_ListObjAppendElement(NULL, result, nextElt); } if (*p++ == '\0') { break; } } /* * Compute the number of elements in the result. */ if (lenPtr != NULL) { Tcl_ListObjLength(NULL, result, lenPtr); } return result; } /* Simple helper function */ Tcl_Obj* TclFSInternalToNormalized(fromFilesystem, clientData, fsRecPtrPtr) Tcl_Filesystem *fromFilesystem; ClientData clientData; FilesystemRecord **fsRecPtrPtr; { FilesystemRecord *fsRecPtr = FsGetFirstFilesystem(); while (fsRecPtr != NULL) { if (fsRecPtr->fsPtr == fromFilesystem) { *fsRecPtrPtr = fsRecPtr; break; } fsRecPtr = fsRecPtr->nextPtr; } if ((fsRecPtr != NULL) && (fromFilesystem->internalToNormalizedProc != NULL)) { return (*fromFilesystem->internalToNormalizedProc)(clientData); } else { return NULL; } } /* *---------------------------------------------------------------------- * * GetPathType -- * * Helper function used by FSGetPathType. * * Results: * Returns one of TCL_PATH_ABSOLUTE, TCL_PATH_RELATIVE, or * TCL_PATH_VOLUME_RELATIVE. The filesystem reference will * be set if and only if it is non-NULL and the function's * return value is TCL_PATH_ABSOLUTE. * * Side effects: * None. * *---------------------------------------------------------------------- */ static Tcl_PathType GetPathType(pathObjPtr, filesystemPtrPtr, driveNameLengthPtr, driveNameRef) Tcl_Obj *pathObjPtr; Tcl_Filesystem **filesystemPtrPtr; int *driveNameLengthPtr; Tcl_Obj **driveNameRef; { FilesystemRecord *fsRecPtr; int pathLen; char *path; Tcl_PathType type = TCL_PATH_RELATIVE; path = Tcl_GetStringFromObj(pathObjPtr, &pathLen); /* * Call each of the "listVolumes" function in succession, checking * whether the given path is an absolute path on any of the volumes * returned (this is done by checking whether the path's prefix * matches). */ fsRecPtr = FsGetFirstFilesystem(); while (fsRecPtr != NULL) { Tcl_FSListVolumesProc *proc = fsRecPtr->fsPtr->listVolumesProc; /* * We want to skip the native filesystem in this loop because * otherwise we won't necessarily pass all the Tcl testsuite -- * this is because some of the tests artificially change the * current platform (between mac, win, unix) but the list * of volumes we get by calling (*proc) will reflect the current * (real) platform only and this may cause some tests to fail. * In particular, on unix '/' will match the beginning of * certain absolute Windows paths starting '//' and those tests * will go wrong. * * Besides these test-suite issues, there is one other reason * to skip the native filesystem --- since the tclFilename.c * code has nice fast 'absolute path' checkers, we don't want * to waste time repeating that effort here, and this * function is actually called quite often, so if we can * save the overhead of the native filesystem returning us * a list of volumes all the time, it is better. */ if ((fsRecPtr->fsPtr != &tclNativeFilesystem) && (proc != NULL)) { int numVolumes; Tcl_Obj *thisFsVolumes = (*proc)(); if (thisFsVolumes != NULL) { if (Tcl_ListObjLength(NULL, thisFsVolumes, &numVolumes) != TCL_OK) { /* * This is VERY bad; the Tcl_FSListVolumesProc * didn't return a valid list. Set numVolumes to * -1 so that we skip the while loop below and just * return with the current value of 'type'. * * It would be better if we could signal an error * here (but panic seems a bit excessive). */ numVolumes = -1; } while (numVolumes > 0) { Tcl_Obj *vol; int len; char *strVol; numVolumes--; Tcl_ListObjIndex(NULL, thisFsVolumes, numVolumes, &vol); strVol = Tcl_GetStringFromObj(vol,&len); if (pathLen < len) { continue; } if (strncmp(strVol, path, (size_t) len) == 0) { type = TCL_PATH_ABSOLUTE; if (filesystemPtrPtr != NULL) { *filesystemPtrPtr = fsRecPtr->fsPtr; } if (driveNameLengthPtr != NULL) { *driveNameLengthPtr = len; } if (driveNameRef != NULL) { *driveNameRef = vol; Tcl_IncrRefCount(vol); } break; } } Tcl_DecrRefCount(thisFsVolumes); if (type == TCL_PATH_ABSOLUTE) { /* We don't need to examine any more filesystems */ break; } } } fsRecPtr = fsRecPtr->nextPtr; } if (type != TCL_PATH_ABSOLUTE) { type = TclpGetNativePathType(pathObjPtr, driveNameLengthPtr, driveNameRef); if ((type == TCL_PATH_ABSOLUTE) && (filesystemPtrPtr != NULL)) { *filesystemPtrPtr = &tclNativeFilesystem; } } return type; } /* *--------------------------------------------------------------------------- * * Tcl_FSRenameFile -- * * If the two paths given belong to the same filesystem, we call * that filesystems rename function. Otherwise we simply * return the posix error 'EXDEV', and -1. * * Results: * Standard Tcl error code if a function was called. * * Side effects: * A file may be renamed. * *--------------------------------------------------------------------------- */ int Tcl_FSRenameFile(srcPathPtr, destPathPtr) Tcl_Obj* srcPathPtr; /* Pathname of file or dir to be renamed * (UTF-8). */ Tcl_Obj *destPathPtr; /* New pathname of file or directory * (UTF-8). */ { int retVal = -1; Tcl_Filesystem *fsPtr, *fsPtr2; fsPtr = Tcl_FSGetFileSystemForPath(srcPathPtr); fsPtr2 = Tcl_FSGetFileSystemForPath(destPathPtr); if (fsPtr == fsPtr2 && fsPtr != NULL) { Tcl_FSRenameFileProc *proc = fsPtr->renameFileProc; if (proc != NULL) { retVal = (*proc)(srcPathPtr, destPathPtr); } } if (retVal == -1) { Tcl_SetErrno(EXDEV); } return retVal; } /* *--------------------------------------------------------------------------- * * Tcl_FSCopyFile -- * * If the two paths given belong to the same filesystem, we call * that filesystem's copy function. Otherwise we simply * return the posix error 'EXDEV', and -1. * * Note that in the native filesystems, 'copyFileProc' is defined * to copy soft links (i.e. it copies the links themselves, not * the things they point to). * * Results: * Standard Tcl error code if a function was called. * * Side effects: * A file may be copied. * *--------------------------------------------------------------------------- */ int Tcl_FSCopyFile(srcPathPtr, destPathPtr) Tcl_Obj* srcPathPtr; /* Pathname of file to be copied (UTF-8). */ Tcl_Obj *destPathPtr; /* Pathname of file to copy to (UTF-8). */ { int retVal = -1; Tcl_Filesystem *fsPtr, *fsPtr2; fsPtr = Tcl_FSGetFileSystemForPath(srcPathPtr); fsPtr2 = Tcl_FSGetFileSystemForPath(destPathPtr); if (fsPtr == fsPtr2 && fsPtr != NULL) { Tcl_FSCopyFileProc *proc = fsPtr->copyFileProc; if (proc != NULL) { retVal = (*proc)(srcPathPtr, destPathPtr); } } if (retVal == -1) { Tcl_SetErrno(EXDEV); } return retVal; } /* *--------------------------------------------------------------------------- * * TclCrossFilesystemCopy -- * * Helper for above function, and for Tcl_FSLoadFile, to copy * files from one filesystem to another. This function will * overwrite the target file if it already exists. * * Results: * Standard Tcl error code. * * Side effects: * A file may be created. * *--------------------------------------------------------------------------- */ int TclCrossFilesystemCopy(interp, source, target) Tcl_Interp *interp; /* For error messages */ Tcl_Obj *source; /* Pathname of file to be copied (UTF-8). */ Tcl_Obj *target; /* Pathname of file to copy to (UTF-8). */ { int result = TCL_ERROR; int prot = 0666; Tcl_Channel out = Tcl_FSOpenFileChannel(interp, target, "w", prot); if (out != NULL) { /* It looks like we can copy it over */ Tcl_Channel in = Tcl_FSOpenFileChannel(interp, source, "r", prot); if (in == NULL) { /* This is very strange, we checked this above */ Tcl_Close(interp, out); } else { Tcl_StatBuf sourceStatBuf; struct utimbuf tval; /* * Copy it synchronously. We might wish to add an * asynchronous option to support vfs's which are * slow (e.g. network sockets). */ Tcl_SetChannelOption(interp, in, "-translation", "binary"); Tcl_SetChannelOption(interp, out, "-translation", "binary"); if (TclCopyChannel(interp, in, out, -1, NULL) == TCL_OK) { result = TCL_OK; } /* * If the copy failed, assume that copy channel left * a good error message. */ Tcl_Close(interp, in); Tcl_Close(interp, out); /* Set modification date of copied file */ if (Tcl_FSLstat(source, &sourceStatBuf) == 0) { tval.actime = sourceStatBuf.st_atime; tval.modtime = sourceStatBuf.st_mtime; Tcl_FSUtime(target, &tval); } } } return result; } /* *--------------------------------------------------------------------------- * * Tcl_FSDeleteFile -- * * The appropriate function for the filesystem to which pathPtr * belongs will be called. * * Results: * Standard Tcl error code. * * Side effects: * A file may be deleted. * *--------------------------------------------------------------------------- */ int Tcl_FSDeleteFile(pathPtr) Tcl_Obj *pathPtr; /* Pathname of file to be removed (UTF-8). */ { Tcl_Filesystem *fsPtr = Tcl_FSGetFileSystemForPath(pathPtr); if (fsPtr != NULL) { Tcl_FSDeleteFileProc *proc = fsPtr->deleteFileProc; if (proc != NULL) { return (*proc)(pathPtr); } } Tcl_SetErrno(ENOENT); return -1; } /* *--------------------------------------------------------------------------- * * Tcl_FSCreateDirectory -- * * The appropriate function for the filesystem to which pathPtr * belongs will be called. * * Results: * Standard Tcl error code. * * Side effects: * A directory may be created. * *--------------------------------------------------------------------------- */ int Tcl_FSCreateDirectory(pathPtr) Tcl_Obj *pathPtr; /* Pathname of directory to create (UTF-8). */ { Tcl_Filesystem *fsPtr = Tcl_FSGetFileSystemForPath(pathPtr); if (fsPtr != NULL) { Tcl_FSCreateDirectoryProc *proc = fsPtr->createDirectoryProc; if (proc != NULL) { return (*proc)(pathPtr); } } Tcl_SetErrno(ENOENT); return -1; } /* *--------------------------------------------------------------------------- * * Tcl_FSCopyDirectory -- * * If the two paths given belong to the same filesystem, we call * that filesystems copy-directory function. Otherwise we simply * return the posix error 'EXDEV', and -1. * * Results: * Standard Tcl error code if a function was called. * * Side effects: * A directory may be copied. * *--------------------------------------------------------------------------- */ int Tcl_FSCopyDirectory(srcPathPtr, destPathPtr, errorPtr) Tcl_Obj* srcPathPtr; /* Pathname of directory to be copied * (UTF-8). */ Tcl_Obj *destPathPtr; /* Pathname of target directory (UTF-8). */ Tcl_Obj **errorPtr; /* If non-NULL, then will be set to a * new object containing name of file * causing error, with refCount 1. */ { int retVal = -1; Tcl_Filesystem *fsPtr, *fsPtr2; fsPtr = Tcl_FSGetFileSystemForPath(srcPathPtr); fsPtr2 = Tcl_FSGetFileSystemForPath(destPathPtr); if (fsPtr == fsPtr2 && fsPtr != NULL) { Tcl_FSCopyDirectoryProc *proc = fsPtr->copyDirectoryProc; if (proc != NULL) { retVal = (*proc)(srcPathPtr, destPathPtr, errorPtr); } } if (retVal == -1) { Tcl_SetErrno(EXDEV); } return retVal; } /* *--------------------------------------------------------------------------- * * Tcl_FSRemoveDirectory -- * * The appropriate function for the filesystem to which pathPtr * belongs will be called. * * Results: * Standard Tcl error code. * * Side effects: * A directory may be deleted. * *--------------------------------------------------------------------------- */ int Tcl_FSRemoveDirectory(pathPtr, recursive, errorPtr) Tcl_Obj *pathPtr; /* Pathname of directory to be removed * (UTF-8). */ int recursive; /* If non-zero, removes directories that * are nonempty. Otherwise, will only remove * empty directories. */ Tcl_Obj **errorPtr; /* If non-NULL, then will be set to a * new object containing name of file * causing error, with refCount 1. */ { Tcl_Filesystem *fsPtr = Tcl_FSGetFileSystemForPath(pathPtr); if (fsPtr != NULL) { Tcl_FSRemoveDirectoryProc *proc = fsPtr->removeDirectoryProc; if (proc != NULL) { if (recursive) { /* * We check whether the cwd lies inside this directory * and move it if it does. */ Tcl_Obj *cwdPtr = Tcl_FSGetCwd(NULL); if (cwdPtr != NULL) { char *cwdStr, *normPathStr; int cwdLen, normLen; Tcl_Obj *normPath = Tcl_FSGetNormalizedPath(NULL, pathPtr); if (normPath != NULL) { normPathStr = Tcl_GetStringFromObj(normPath, &normLen); cwdStr = Tcl_GetStringFromObj(cwdPtr, &cwdLen); if ((cwdLen >= normLen) && (strncmp(normPathStr, cwdStr, (size_t) normLen) == 0)) { /* * the cwd is inside the directory, so we * perform a 'cd [file dirname $path]' */ Tcl_Obj *dirPtr = TclFileDirname(NULL, pathPtr); Tcl_FSChdir(dirPtr); Tcl_DecrRefCount(dirPtr); } } Tcl_DecrRefCount(cwdPtr); } } return (*proc)(pathPtr, recursive, errorPtr); } } Tcl_SetErrno(ENOENT); return -1; } /* *--------------------------------------------------------------------------- * * Tcl_FSGetFileSystemForPath -- * * This function determines which filesystem to use for a * particular path object, and returns the filesystem which * accepts this file. If no filesystem will accept this object * as a valid file path, then NULL is returned. * * Results: .* NULL or a filesystem which will accept this path. * * Side effects: * The object may be converted to a path type. * *--------------------------------------------------------------------------- */ Tcl_Filesystem* Tcl_FSGetFileSystemForPath(pathObjPtr) Tcl_Obj* pathObjPtr; { FilesystemRecord *fsRecPtr; Tcl_Filesystem* retVal = NULL; /* * If the object has a refCount of zero, we reject it. This * is to avoid possible segfaults or nondeterministic memory * leaks (i.e. the user doesn't know if they should decrement * the ref count on return or not). */ if (pathObjPtr->refCount == 0) { panic("Tcl_FSGetFileSystemForPath called with object with refCount == 0"); return NULL; } /* * Check if the filesystem has changed in some way since * this object's internal representation was calculated. * Before doing that, assure we have the most up-to-date * copy of the master filesystem. This is accomplished * by the FsGetFirstFilesystem() call. */ fsRecPtr = FsGetFirstFilesystem(); if (TclFSEnsureEpochOk(pathObjPtr, &retVal) != TCL_OK) { return NULL; } /* * Call each of the "pathInFilesystem" functions in succession. A * non-return value of -1 indicates the particular function has * succeeded. */ while ((retVal == NULL) && (fsRecPtr != NULL)) { Tcl_FSPathInFilesystemProc *proc = fsRecPtr->fsPtr->pathInFilesystemProc; if (proc != NULL) { ClientData clientData = NULL; int ret = (*proc)(pathObjPtr, &clientData); if (ret != -1) { /* * We assume the type of pathObjPtr hasn't been changed * by the above call to the pathInFilesystemProc. */ TclFSSetPathDetails(pathObjPtr, fsRecPtr, clientData); retVal = fsRecPtr->fsPtr; } } fsRecPtr = fsRecPtr->nextPtr; } return retVal; } /* *--------------------------------------------------------------------------- * * Tcl_FSGetNativePath -- * * This function is for use by the Win/Unix/MacOS native filesystems, * so that they can easily retrieve the native (char* or TCHAR*) * representation of a path. Other filesystems will probably * want to implement similar functions. They basically act as a * safety net around Tcl_FSGetInternalRep. Normally your file- * system procedures will always be called with path objects * already converted to the correct filesystem, but if for * some reason they are called directly (i.e. by procedures * not in this file), then one cannot necessarily guarantee that * the path object pointer is from the correct filesystem. * * Note: in the future it might be desireable to have separate * versions of this function with different signatures, for * example Tcl_FSGetNativeMacPath, Tcl_FSGetNativeUnixPath etc. * Right now, since native paths are all string based, we use just * one function. On MacOS we could possibly use an FSSpec or * FSRef as the native representation. * * Results: * NULL or a valid native path. * * Side effects: * See Tcl_FSGetInternalRep. * *--------------------------------------------------------------------------- */ CONST char * Tcl_FSGetNativePath(pathObjPtr) Tcl_Obj *pathObjPtr; { return (CONST char *)Tcl_FSGetInternalRep(pathObjPtr, &tclNativeFilesystem); } /* *--------------------------------------------------------------------------- * * NativeCreateNativeRep -- * * Create a native representation for the given path. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static ClientData NativeCreateNativeRep(pathObjPtr) Tcl_Obj* pathObjPtr; { char *nativePathPtr; Tcl_DString ds; Tcl_Obj* validPathObjPtr; int len; char *str; /* Make sure the normalized path is set */ validPathObjPtr = Tcl_FSGetNormalizedPath(NULL, pathObjPtr); if (validPathObjPtr == NULL) { return NULL; } str = Tcl_GetStringFromObj(validPathObjPtr, &len); #ifdef __WIN32__ Tcl_WinUtfToTChar(str, len, &ds); if (tclWinProcs->useWide) { len = Tcl_DStringLength(&ds) + sizeof(WCHAR); } else { len = Tcl_DStringLength(&ds) + sizeof(char); } #else Tcl_UtfToExternalDString(NULL, str, len, &ds); len = Tcl_DStringLength(&ds) + sizeof(char); #endif nativePathPtr = ckalloc((unsigned) len); memcpy((VOID*)nativePathPtr, (VOID*)Tcl_DStringValue(&ds), (size_t) len); Tcl_DStringFree(&ds); return (ClientData)nativePathPtr; } /* *--------------------------------------------------------------------------- * * TclpNativeToNormalized -- * * Convert native format to a normalized path object, with refCount * of zero. * * Results: * A valid normalized path. * * Side effects: * None. * *--------------------------------------------------------------------------- */ Tcl_Obj* TclpNativeToNormalized(clientData) ClientData clientData; { Tcl_DString ds; Tcl_Obj *objPtr; CONST char *copy; int len; #ifdef __WIN32__ Tcl_WinTCharToUtf((CONST char*)clientData, -1, &ds); #else Tcl_ExternalToUtfDString(NULL, (CONST char*)clientData, -1, &ds); #endif copy = Tcl_DStringValue(&ds); len = Tcl_DStringLength(&ds); #ifdef __WIN32__ /* * Certain native path representations on Windows have this special * prefix to indicate that they are to be treated specially. For * example extremely long paths, or symlinks */ if (*copy == '\\') { if (0 == strncmp(copy,"\\??\\",4)) { copy += 4; len -= 4; } else if (0 == strncmp(copy,"\\\\?\\",4)) { copy += 4; len -= 4; } } #endif objPtr = Tcl_NewStringObj(copy,len); Tcl_DStringFree(&ds); return objPtr; } /* *--------------------------------------------------------------------------- * * TclNativeDupInternalRep -- * * Duplicate the native representation. * * Results: * The copied native representation, or NULL if it is not possible * to copy the representation. * * Side effects: * None. * *--------------------------------------------------------------------------- */ ClientData TclNativeDupInternalRep(clientData) ClientData clientData; { ClientData copy; size_t len; if (clientData == NULL) { return NULL; } #ifdef __WIN32__ if (tclWinProcs->useWide) { /* unicode representation when running on NT/2K/XP */ len = sizeof(WCHAR) + (wcslen((CONST WCHAR*)clientData) * sizeof(WCHAR)); } else { /* ansi representation when running on 95/98/ME */ len = sizeof(char) + (strlen((CONST char*)clientData) * sizeof(char)); } #else /* ansi representation when running on Unix/MacOS */ len = sizeof(char) + (strlen((CONST char*)clientData) * sizeof(char)); #endif copy = (ClientData) ckalloc(len); memcpy((VOID*)copy, (VOID*)clientData, len); return copy; } /* *--------------------------------------------------------------------------- * * NativeFreeInternalRep -- * * Free a native internal representation, which will be non-NULL. * * Results: * None. * * Side effects: * Memory is released. * *--------------------------------------------------------------------------- */ static void NativeFreeInternalRep(clientData) ClientData clientData; { ckfree((char*)clientData); } /* *--------------------------------------------------------------------------- * * Tcl_FSFileSystemInfo -- * * This function returns a list of two elements. The first * element is the name of the filesystem (e.g. "native" or "vfs"), * and the second is the particular type of the given path within * that filesystem. * * Results: * A list of two elements. * * Side effects: * The object may be converted to a path type. * *--------------------------------------------------------------------------- */ Tcl_Obj* Tcl_FSFileSystemInfo(pathObjPtr) Tcl_Obj* pathObjPtr; { Tcl_Obj *resPtr; Tcl_FSFilesystemPathTypeProc *proc; Tcl_Filesystem *fsPtr = Tcl_FSGetFileSystemForPath(pathObjPtr); if (fsPtr == NULL) { return NULL; } resPtr = Tcl_NewListObj(0,NULL); Tcl_ListObjAppendElement(NULL, resPtr, Tcl_NewStringObj(fsPtr->typeName,-1)); proc = fsPtr->filesystemPathTypeProc; if (proc != NULL) { Tcl_Obj *typePtr = (*proc)(pathObjPtr); if (typePtr != NULL) { Tcl_ListObjAppendElement(NULL, resPtr, typePtr); } } return resPtr; } /* *--------------------------------------------------------------------------- * * Tcl_FSPathSeparator -- * * This function returns the separator to be used for a given * path. The object returned should have a refCount of zero * * Results: * A Tcl object, with a refCount of zero. If the caller * needs to retain a reference to the object, it should * call Tcl_IncrRefCount. * * Side effects: * The path object may be converted to a path type. * *--------------------------------------------------------------------------- */ Tcl_Obj* Tcl_FSPathSeparator(pathObjPtr) Tcl_Obj* pathObjPtr; { Tcl_Filesystem *fsPtr = Tcl_FSGetFileSystemForPath(pathObjPtr); if (fsPtr == NULL) { return NULL; } if (fsPtr->filesystemSeparatorProc != NULL) { return (*fsPtr->filesystemSeparatorProc)(pathObjPtr); } return NULL; } /* *--------------------------------------------------------------------------- * * NativeFilesystemSeparator -- * * This function is part of the native filesystem support, and * returns the separator for the given path. * * Results: * String object containing the separator character. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static Tcl_Obj* NativeFilesystemSeparator(pathObjPtr) Tcl_Obj* pathObjPtr; { char *separator = NULL; /* lint */ switch (tclPlatform) { case TCL_PLATFORM_UNIX: separator = "/"; break; case TCL_PLATFORM_WINDOWS: separator = "\\"; break; } return Tcl_NewStringObj(separator,1); } /* Everything from here on is contained in this obsolete ifdef */ #ifdef USE_OBSOLETE_FS_HOOKS /* *---------------------------------------------------------------------- * * TclStatInsertProc -- * * Insert the passed procedure pointer at the head of the list of * functions which are used during a call to 'TclStat(...)'. The * passed function should behave exactly like 'TclStat' when called * during that time (see 'TclStat(...)' for more information). * The function will be added even if it already in the list. * * Results: * Normally TCL_OK; TCL_ERROR if memory for a new node in the list * could not be allocated. * * Side effects: * Memory allocated and modifies the link list for 'TclStat' * functions. * *---------------------------------------------------------------------- */ int TclStatInsertProc (proc) TclStatProc_ *proc; { int retVal = TCL_ERROR; if (proc != NULL) { StatProc *newStatProcPtr; newStatProcPtr = (StatProc *)ckalloc(sizeof(StatProc)); if (newStatProcPtr != NULL) { newStatProcPtr->proc = proc; Tcl_MutexLock(&obsoleteFsHookMutex); newStatProcPtr->nextPtr = statProcList; statProcList = newStatProcPtr; Tcl_MutexUnlock(&obsoleteFsHookMutex); retVal = TCL_OK; } } return retVal; } /* *---------------------------------------------------------------------- * * TclStatDeleteProc -- * * Removed the passed function pointer from the list of 'TclStat' * functions. Ensures that the built-in stat function is not * removvable. * * Results: * TCL_OK if the procedure pointer was successfully removed, * TCL_ERROR otherwise. * * Side effects: * Memory is deallocated and the respective list updated. * *---------------------------------------------------------------------- */ int TclStatDeleteProc (proc) TclStatProc_ *proc; { int retVal = TCL_ERROR; StatProc *tmpStatProcPtr; StatProc *prevStatProcPtr = NULL; Tcl_MutexLock(&obsoleteFsHookMutex); tmpStatProcPtr = statProcList; /* * Traverse the 'statProcList' looking for the particular node * whose 'proc' member matches 'proc' and remove that one from * the list. Ensure that the "default" node cannot be removed. */ while ((retVal == TCL_ERROR) && (tmpStatProcPtr != NULL)) { if (tmpStatProcPtr->proc == proc) { if (prevStatProcPtr == NULL) { statProcList = tmpStatProcPtr->nextPtr; } else { prevStatProcPtr->nextPtr = tmpStatProcPtr->nextPtr; } ckfree((char *)tmpStatProcPtr); retVal = TCL_OK; } else { prevStatProcPtr = tmpStatProcPtr; tmpStatProcPtr = tmpStatProcPtr->nextPtr; } } Tcl_MutexUnlock(&obsoleteFsHookMutex); return retVal; } /* *---------------------------------------------------------------------- * * TclAccessInsertProc -- * * Insert the passed procedure pointer at the head of the list of * functions which are used during a call to 'TclAccess(...)'. * The passed function should behave exactly like 'TclAccess' when * called during that time (see 'TclAccess(...)' for more * information). The function will be added even if it already in * the list. * * Results: * Normally TCL_OK; TCL_ERROR if memory for a new node in the list * could not be allocated. * * Side effects: * Memory allocated and modifies the link list for 'TclAccess' * functions. * *---------------------------------------------------------------------- */ int TclAccessInsertProc(proc) TclAccessProc_ *proc; { int retVal = TCL_ERROR; if (proc != NULL) { AccessProc *newAccessProcPtr; newAccessProcPtr = (AccessProc *)ckalloc(sizeof(AccessProc)); if (newAccessProcPtr != NULL) { newAccessProcPtr->proc = proc; Tcl_MutexLock(&obsoleteFsHookMutex); newAccessProcPtr->nextPtr = accessProcList; accessProcList = newAccessProcPtr; Tcl_MutexUnlock(&obsoleteFsHookMutex); retVal = TCL_OK; } } return retVal; } /* *---------------------------------------------------------------------- * * TclAccessDeleteProc -- * * Removed the passed function pointer from the list of 'TclAccess' * functions. Ensures that the built-in access function is not * removvable. * * Results: * TCL_OK if the procedure pointer was successfully removed, * TCL_ERROR otherwise. * * Side effects: * Memory is deallocated and the respective list updated. * *---------------------------------------------------------------------- */ int TclAccessDeleteProc(proc) TclAccessProc_ *proc; { int retVal = TCL_ERROR; AccessProc *tmpAccessProcPtr; AccessProc *prevAccessProcPtr = NULL; /* * Traverse the 'accessProcList' looking for the particular node * whose 'proc' member matches 'proc' and remove that one from * the list. Ensure that the "default" node cannot be removed. */ Tcl_MutexLock(&obsoleteFsHookMutex); tmpAccessProcPtr = accessProcList; while ((retVal == TCL_ERROR) && (tmpAccessProcPtr != NULL)) { if (tmpAccessProcPtr->proc == proc) { if (prevAccessProcPtr == NULL) { accessProcList = tmpAccessProcPtr->nextPtr; } else { prevAccessProcPtr->nextPtr = tmpAccessProcPtr->nextPtr; } ckfree((char *)tmpAccessProcPtr); retVal = TCL_OK; } else { prevAccessProcPtr = tmpAccessProcPtr; tmpAccessProcPtr = tmpAccessProcPtr->nextPtr; } } Tcl_MutexUnlock(&obsoleteFsHookMutex); return retVal; } /* *---------------------------------------------------------------------- * * TclOpenFileChannelInsertProc -- * * Insert the passed procedure pointer at the head of the list of * functions which are used during a call to * 'Tcl_OpenFileChannel(...)'. The passed function should behave * exactly like 'Tcl_OpenFileChannel' when called during that time * (see 'Tcl_OpenFileChannel(...)' for more information). The * function will be added even if it already in the list. * * Results: * Normally TCL_OK; TCL_ERROR if memory for a new node in the list * could not be allocated. * * Side effects: * Memory allocated and modifies the link list for * 'Tcl_OpenFileChannel' functions. * *---------------------------------------------------------------------- */ int TclOpenFileChannelInsertProc(proc) TclOpenFileChannelProc_ *proc; { int retVal = TCL_ERROR; if (proc != NULL) { OpenFileChannelProc *newOpenFileChannelProcPtr; newOpenFileChannelProcPtr = (OpenFileChannelProc *)ckalloc(sizeof(OpenFileChannelProc)); if (newOpenFileChannelProcPtr != NULL) { newOpenFileChannelProcPtr->proc = proc; Tcl_MutexLock(&obsoleteFsHookMutex); newOpenFileChannelProcPtr->nextPtr = openFileChannelProcList; openFileChannelProcList = newOpenFileChannelProcPtr; Tcl_MutexUnlock(&obsoleteFsHookMutex); retVal = TCL_OK; } } return retVal; } /* *---------------------------------------------------------------------- * * TclOpenFileChannelDeleteProc -- * * Removed the passed function pointer from the list of * 'Tcl_OpenFileChannel' functions. Ensures that the built-in * open file channel function is not removable. * * Results: * TCL_OK if the procedure pointer was successfully removed, * TCL_ERROR otherwise. * * Side effects: * Memory is deallocated and the respective list updated. * *---------------------------------------------------------------------- */ int TclOpenFileChannelDeleteProc(proc) TclOpenFileChannelProc_ *proc; { int retVal = TCL_ERROR; OpenFileChannelProc *tmpOpenFileChannelProcPtr = openFileChannelProcList; OpenFileChannelProc *prevOpenFileChannelProcPtr = NULL; /* * Traverse the 'openFileChannelProcList' looking for the particular * node whose 'proc' member matches 'proc' and remove that one from * the list. */ Tcl_MutexLock(&obsoleteFsHookMutex); tmpOpenFileChannelProcPtr = openFileChannelProcList; while ((retVal == TCL_ERROR) && (tmpOpenFileChannelProcPtr != NULL)) { if (tmpOpenFileChannelProcPtr->proc == proc) { if (prevOpenFileChannelProcPtr == NULL) { openFileChannelProcList = tmpOpenFileChannelProcPtr->nextPtr; } else { prevOpenFileChannelProcPtr->nextPtr = tmpOpenFileChannelProcPtr->nextPtr; } ckfree((char *)tmpOpenFileChannelProcPtr); retVal = TCL_OK; } else { prevOpenFileChannelProcPtr = tmpOpenFileChannelProcPtr; tmpOpenFileChannelProcPtr = tmpOpenFileChannelProcPtr->nextPtr; } } Tcl_MutexUnlock(&obsoleteFsHookMutex); return retVal; } #endif /* USE_OBSOLETE_FS_HOOKS */ /* * Prototypes for procedures defined later in this file. */ static void DupFsPathInternalRep _ANSI_ARGS_((Tcl_Obj *srcPtr, Tcl_Obj *copyPtr)); static void FreeFsPathInternalRep _ANSI_ARGS_((Tcl_Obj *listPtr)); static void UpdateStringOfFsPath _ANSI_ARGS_((Tcl_Obj *objPtr)); static int SetFsPathFromAny _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr)); static int FindSplitPos _ANSI_ARGS_((char *path, char *separator)); /* * Define the 'path' object type, which Tcl uses to represent * file paths internally. */ static Tcl_ObjType tclFsPathType = { "path", /* name */ FreeFsPathInternalRep, /* freeIntRepProc */ DupFsPathInternalRep, /* dupIntRepProc */ UpdateStringOfFsPath, /* updateStringProc */ SetFsPathFromAny /* setFromAnyProc */ }; /* * struct FsPath -- * * Internal representation of a Tcl_Obj of "path" type. This * can be used to represent relative or absolute paths, and has * certain optimisations when used to represent paths which are * already normalized and absolute. * * Note that 'normPathPtr' can be a circular reference to the * container Tcl_Obj of this FsPath. */ typedef struct FsPath { Tcl_Obj *translatedPathPtr; /* Name without any ~user sequences. * If this is NULL, then this is a * pure normalized, absolute path * object, in which the parent Tcl_Obj's * string rep is already both translated * and normalized. */ Tcl_Obj *normPathPtr; /* Normalized absolute path, without * ., .. or ~user sequences. If the * Tcl_Obj containing * this FsPath is already normalized, * this may be a circular reference back * to the container. If that is NOT the * case, we have a refCount on the object. */ Tcl_Obj *cwdPtr; /* If null, path is absolute, else * this points to the cwd object used * for this path. We have a refCount * on the object. */ int flags; /* Flags to describe interpretation */ ClientData nativePathPtr; /* Native representation of this path, * which is filesystem dependent. */ int filesystemEpoch; /* Used to ensure the path representation * was generated during the correct * filesystem epoch. The epoch changes * when filesystem-mounts are changed. */ struct FilesystemRecord *fsRecPtr; /* Pointer to the filesystem record * entry to use for this path. */ } FsPath; /* * Define some macros to give us convenient access to path-object * specific fields. */ #define PATHOBJ(objPtr) (objPtr->internalRep.otherValuePtr) #define PATHFLAGS(objPtr) \ (((FsPath*)(objPtr->internalRep.otherValuePtr))->flags) #define TCLPATH_APPENDED 1 #define TCLPATH_RELATIVE 2 #define TCLPATH_NEEDNORM 4 /* *---------------------------------------------------------------------- * * Tcl_FSGetPathType -- * * Determines whether a given path is relative to the current * directory, relative to the current volume, or absolute. * * Results: * Returns one of TCL_PATH_ABSOLUTE, TCL_PATH_RELATIVE, or * TCL_PATH_VOLUME_RELATIVE. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_PathType Tcl_FSGetPathType(pathObjPtr) Tcl_Obj *pathObjPtr; { return FSGetPathType(pathObjPtr, NULL, NULL); } /* *---------------------------------------------------------------------- * * FSGetPathType -- * * Determines whether a given path is relative to the current * directory, relative to the current volume, or absolute. If the * caller wishes to know which filesystem claimed the path (in the * case for which the path is absolute), then a reference to a * filesystem pointer can be passed in (but passing NULL is * acceptable). * * Results: * Returns one of TCL_PATH_ABSOLUTE, TCL_PATH_RELATIVE, or * TCL_PATH_VOLUME_RELATIVE. The filesystem reference will * be set if and only if it is non-NULL and the function's * return value is TCL_PATH_ABSOLUTE. * * Side effects: * None. * *---------------------------------------------------------------------- */ static Tcl_PathType FSGetPathType(pathObjPtr, filesystemPtrPtr, driveNameLengthPtr) Tcl_Obj *pathObjPtr; Tcl_Filesystem **filesystemPtrPtr; int *driveNameLengthPtr; { if (Tcl_FSConvertToPathType(NULL, pathObjPtr) != TCL_OK) { return GetPathType(pathObjPtr, filesystemPtrPtr, driveNameLengthPtr, NULL); } else { FsPath *fsPathPtr = (FsPath*) PATHOBJ(pathObjPtr); if (fsPathPtr->cwdPtr != NULL) { if (PATHFLAGS(pathObjPtr) == 0) { /* The path is not absolute... */ #ifdef __WIN32__ /* ... on Windows we must make another call to determine * whether it's relative or volumerelative [Bug 2571597]. */ return GetPathType(pathObjPtr, filesystemPtrPtr, driveNameLengthPtr, NULL); #else /* On other systems, quickly deduce !absolute -> relative */ return TCL_PATH_RELATIVE; #endif } return FSGetPathType(fsPathPtr->cwdPtr, filesystemPtrPtr, driveNameLengthPtr); } else { return GetPathType(pathObjPtr, filesystemPtrPtr, driveNameLengthPtr, NULL); } } } /* *--------------------------------------------------------------------------- * * Tcl_FSJoinPath -- * * This function takes the given Tcl_Obj, which should be a valid * list, and returns the path object given by considering the * first 'elements' elements as valid path segments. If elements < 0, * we use the entire list. * * Results: * Returns object with refCount of zero, (or if non-zero, it has * references elsewhere in Tcl). Either way, the caller must * increment its refCount before use. * * Side effects: * None. * *--------------------------------------------------------------------------- */ Tcl_Obj* Tcl_FSJoinPath(listObj, elements) Tcl_Obj *listObj; int elements; { Tcl_Obj *res; int i; Tcl_Filesystem *fsPtr = NULL; if (elements < 0) { if (Tcl_ListObjLength(NULL, listObj, &elements) != TCL_OK) { return NULL; } } else { /* Just make sure it is a valid list */ int listTest; if (Tcl_ListObjLength(NULL, listObj, &listTest) != TCL_OK) { return NULL; } /* * Correct this if it is too large, otherwise we will * waste our time joining null elements to the path */ if (elements > listTest) { elements = listTest; } } res = Tcl_NewObj(); for (i = 0; i < elements; i++) { Tcl_Obj *elt; int driveNameLength; Tcl_PathType type; char *strElt; int strEltLen; int length; char *ptr; Tcl_Obj *driveName = NULL; Tcl_ListObjIndex(NULL, listObj, i, &elt); /* * This is a special case where we can be much more * efficient, where we are joining a single relative path * onto an object that is already of path type. The * 'TclNewFSPathObj' call below creates an object which * can be normalized more efficiently. Currently we only * use the special case when we have exactly two elements, * but we could expand that in the future. */ if ((i == (elements-2)) && (i == 0) && (elt->typePtr == &tclFsPathType) && !(elt->bytes != NULL && (elt->bytes[0] == '\0'))) { Tcl_Obj *tail; Tcl_PathType type; Tcl_ListObjIndex(NULL, listObj, i+1, &tail); type = GetPathType(tail, NULL, NULL, NULL); if (type == TCL_PATH_RELATIVE) { CONST char *str; int len; str = Tcl_GetStringFromObj(tail,&len); if (len == 0) { /* * This happens if we try to handle the root volume * '/'. There's no need to return a special path * object, when the base itself is just fine! */ Tcl_DecrRefCount(res); return elt; } /* * If it doesn't begin with '.' and is a mac or unix * path or it a windows path without backslashes, then we * can be very efficient here. (In fact even a windows * path with backslashes can be joined efficiently, but * the path object would not have forward slashes only, * and this would therefore contradict our 'file join' * documentation). */ if (str[0] != '.' && ((tclPlatform != TCL_PLATFORM_WINDOWS) || (strchr(str, '\\') == NULL))) { /* * Finally, on Windows, 'file join' is defined to * convert all backslashes to forward slashes, * so the base part cannot have backslashes either. */ if ((tclPlatform != TCL_PLATFORM_WINDOWS) || (strchr(Tcl_GetString(elt), '\\') == NULL)) { if (res != NULL) { TclDecrRefCount(res); } return TclNewFSPathObj(elt, str, len); } } /* * Otherwise we don't have an easy join, and * we must let the more general code below handle * things */ } else { if (tclPlatform == TCL_PLATFORM_UNIX) { Tcl_DecrRefCount(res); return tail; } else { CONST char *str; int len; str = Tcl_GetStringFromObj(tail,&len); if (tclPlatform == TCL_PLATFORM_WINDOWS) { if (strchr(str, '\\') == NULL) { Tcl_DecrRefCount(res); return tail; } } } } } strElt = Tcl_GetStringFromObj(elt, &strEltLen); type = GetPathType(elt, &fsPtr, &driveNameLength, &driveName); if (type != TCL_PATH_RELATIVE) { /* Zero out the current result */ Tcl_DecrRefCount(res); if (driveName != NULL) { res = Tcl_DuplicateObj(driveName); Tcl_DecrRefCount(driveName); } else { res = Tcl_NewStringObj(strElt, driveNameLength); } strElt += driveNameLength; } ptr = Tcl_GetStringFromObj(res, &length); /* * Strip off any './' before a tilde, unless this is the * beginning of the path. */ if (length > 0 && strEltLen > 0) { if ((strElt[0] == '.') && (strElt[1] == '/') && (strElt[2] == '~')) { strElt += 2; } } /* * A NULL value for fsPtr at this stage basically means * we're trying to join a relative path onto something * which is also relative (or empty). There's nothing * particularly wrong with that. */ if (*strElt == '\0') continue; if (fsPtr == &tclNativeFilesystem || fsPtr == NULL) { TclpNativeJoinPath(res, strElt); } else { char separator = '/'; int needsSep = 0; if (fsPtr->filesystemSeparatorProc != NULL) { Tcl_Obj *sep = (*fsPtr->filesystemSeparatorProc)(res); if (sep != NULL) { separator = Tcl_GetString(sep)[0]; } } if (length > 0 && ptr[length -1] != '/') { Tcl_AppendToObj(res, &separator, 1); Tcl_GetStringFromObj(res, &length); } Tcl_SetObjLength(res, length + (int) strlen(strElt)); ptr = Tcl_GetString(res) + length; for (; *strElt != '\0'; strElt++) { if (*strElt == separator) { while (strElt[1] == separator) { strElt++; } if (strElt[1] != '\0') { if (needsSep) { *ptr++ = separator; } } } else { *ptr++ = *strElt; needsSep = 1; } } length = ptr - Tcl_GetString(res); Tcl_SetObjLength(res, length); } } return res; } /* *--------------------------------------------------------------------------- * * Tcl_FSConvertToPathType -- * * This function tries to convert the given Tcl_Obj to a valid * Tcl path type, taking account of the fact that the cwd may * have changed even if this object is already supposedly of * the correct type. * * The filename may begin with "~" (to indicate current user's * home directory) or "~" (to indicate any user's home * directory). * * Results: * Standard Tcl error code. * * Side effects: * The old representation may be freed, and new memory allocated. * *--------------------------------------------------------------------------- */ int Tcl_FSConvertToPathType(interp, objPtr) Tcl_Interp *interp; /* Interpreter in which to store error * message (if necessary). */ Tcl_Obj *objPtr; /* Object to convert to a valid, current * path type. */ { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); /* * While it is bad practice to examine an object's type directly, * this is actually the best thing to do here. The reason is that * if we are converting this object to FsPath type for the first * time, we don't need to worry whether the 'cwd' has changed. * On the other hand, if this object is already of FsPath type, * and is a relative path, we do have to worry about the cwd. * If the cwd has changed, we must recompute the path. */ if (objPtr->typePtr == &tclFsPathType) { FsPath *fsPathPtr = (FsPath*) PATHOBJ(objPtr); if (fsPathPtr->filesystemEpoch != tsdPtr->filesystemEpoch) { if (objPtr->bytes == NULL) { UpdateStringOfFsPath(objPtr); } FreeFsPathInternalRep(objPtr); objPtr->typePtr = NULL; return Tcl_ConvertToType(interp, objPtr, &tclFsPathType); } return TCL_OK; } else { return Tcl_ConvertToType(interp, objPtr, &tclFsPathType); } } /* * Helper function for SetFsPathFromAny. Returns position of first * directory delimiter in the path. */ static int FindSplitPos(path, separator) char *path; char *separator; { int count = 0; switch (tclPlatform) { case TCL_PLATFORM_UNIX: while (path[count] != 0) { if (path[count] == *separator) { return count; } count++; } break; case TCL_PLATFORM_WINDOWS: while (path[count] != 0) { if (path[count] == *separator || path[count] == '\\') { return count; } count++; } break; } return count; } /* *--------------------------------------------------------------------------- * * TclNewFSPathObj -- * * Creates a path object whose string representation is * '[file join dirPtr addStrRep]', but does so in a way that * allows for more efficient caching of normalized paths. * * Assumptions: * 'dirPtr' must be an absolute path. * 'len' may not be zero. * * Results: * The new Tcl object, with refCount zero. * * Side effects: * Memory is allocated. 'dirPtr' gets an additional refCount. * *--------------------------------------------------------------------------- */ Tcl_Obj* TclNewFSPathObj(Tcl_Obj *dirPtr, CONST char *addStrRep, int len) { FsPath *fsPathPtr; Tcl_Obj *objPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); CONST char *p; int state = 0, count = 0; objPtr = Tcl_NewObj(); fsPathPtr = (FsPath*)ckalloc((unsigned)sizeof(FsPath)); /* Setup the path */ fsPathPtr->translatedPathPtr = NULL; fsPathPtr->normPathPtr = Tcl_NewStringObj(addStrRep, len); Tcl_IncrRefCount(fsPathPtr->normPathPtr); fsPathPtr->cwdPtr = dirPtr; Tcl_IncrRefCount(dirPtr); fsPathPtr->nativePathPtr = NULL; fsPathPtr->fsRecPtr = NULL; fsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch; PATHOBJ(objPtr) = (VOID *) fsPathPtr; PATHFLAGS(objPtr) = TCLPATH_RELATIVE | TCLPATH_APPENDED; objPtr->typePtr = &tclFsPathType; objPtr->bytes = NULL; objPtr->length = 0; /* * Look for path components made up of only "." * This is overly conservative analysis to keep simple. It may * mark some things as needing more aggressive normalization * that don't actually need it. No harm done. */ for (p = addStrRep; len > 0; p++, len--) { switch (state) { case 0: /* So far only "." since last dirsep or start */ switch (*p) { case '.': count++; break; case '/': case '\\': case ':': if (count) { PATHFLAGS(objPtr) |= TCLPATH_NEEDNORM; len = 0; } break; default: count = 0; state = 1; } case 1: /* Scanning for next dirsep */ switch (*p) { case '/': case '\\': case ':': state = 0; break; } } } if (len == 0 && count) { PATHFLAGS(objPtr) |= TCLPATH_NEEDNORM; } return objPtr; } /* *--------------------------------------------------------------------------- * * TclFSMakePathRelative -- * * Only for internal use. * * Takes a path and a directory, where we _assume_ both path and * directory are absolute, normalized and that the path lies * inside the directory. Returns a Tcl_Obj representing filename * of the path relative to the directory. * * In the case where the resulting path would start with a '~', we * take special care to return an ordinary string. This means to * use that path (and not have it interpreted as a user name), * one must prepend './'. This may seem strange, but that is how * 'glob' is currently defined. * * Results: * NULL on error, otherwise a valid object, typically with * refCount of zero, which it is assumed the caller will * increment. * * Side effects: * The old representation may be freed, and new memory allocated. * *--------------------------------------------------------------------------- */ Tcl_Obj* TclFSMakePathRelative(interp, objPtr, cwdPtr) Tcl_Interp *interp; /* Used for error reporting if not NULL. */ Tcl_Obj *objPtr; /* The object we have. */ Tcl_Obj *cwdPtr; /* Make it relative to this. */ { int cwdLen, len; CONST char *tempStr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (objPtr->typePtr == &tclFsPathType) { FsPath *fsPathPtr = (FsPath*) PATHOBJ(objPtr); if (PATHFLAGS(objPtr) != 0 && fsPathPtr->cwdPtr == cwdPtr) { objPtr = fsPathPtr->normPathPtr; /* Free old representation */ if (objPtr->typePtr != NULL) { if (objPtr->bytes == NULL) { if (objPtr->typePtr->updateStringProc == NULL) { if (interp != NULL) { Tcl_ResetResult(interp); Tcl_AppendResult(interp, "can't find object", "string representation", (char *) NULL); } return NULL; } objPtr->typePtr->updateStringProc(objPtr); } if ((objPtr->typePtr->freeIntRepProc) != NULL) { (*objPtr->typePtr->freeIntRepProc)(objPtr); } } /* Now objPtr is a string object */ if (Tcl_GetString(objPtr)[0] == '~') { /* * If the first character of the path is a tilde, * we must just return the path as is, to agree * with the defined behaviour of 'glob'. */ return objPtr; } fsPathPtr = (FsPath*)ckalloc((unsigned)sizeof(FsPath)); /* Circular reference, by design */ fsPathPtr->translatedPathPtr = objPtr; fsPathPtr->normPathPtr = NULL; fsPathPtr->cwdPtr = cwdPtr; Tcl_IncrRefCount(cwdPtr); fsPathPtr->nativePathPtr = NULL; fsPathPtr->fsRecPtr = NULL; fsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch; PATHOBJ(objPtr) = (VOID *) fsPathPtr; PATHFLAGS(objPtr) = 0; objPtr->typePtr = &tclFsPathType; return objPtr; } } /* * We know the cwd is a normalised object which does * not end in a directory delimiter, unless the cwd * is the name of a volume, in which case it will * end in a delimiter! We handle this situation here. * A better test than the '!= sep' might be to simply * check if 'cwd' is a root volume. * * Note that if we get this wrong, we will strip off * either too much or too little below, leading to * wrong answers returned by glob. */ tempStr = Tcl_GetStringFromObj(cwdPtr, &cwdLen); /* * Should we perhaps use 'Tcl_FSPathSeparator'? * But then what about the Windows special case? * Perhaps we should just check if cwd is a root * volume. */ switch (tclPlatform) { case TCL_PLATFORM_UNIX: if (tempStr[cwdLen-1] != '/') { cwdLen++; } break; case TCL_PLATFORM_WINDOWS: if (tempStr[cwdLen-1] != '/' && tempStr[cwdLen-1] != '\\') { cwdLen++; } break; } tempStr = Tcl_GetStringFromObj(objPtr, &len); return Tcl_NewStringObj(tempStr + cwdLen, len - cwdLen); } /* *--------------------------------------------------------------------------- * * TclFSMakePathFromNormalized -- * * Like SetFsPathFromAny, but assumes the given object is an * absolute normalized path. Only for internal use. * * Results: * Standard Tcl error code. * * Side effects: * The old representation may be freed, and new memory allocated. * *--------------------------------------------------------------------------- */ int TclFSMakePathFromNormalized(interp, objPtr) Tcl_Interp *interp; /* Used for error reporting if not NULL. */ Tcl_Obj *objPtr; /* The object to convert. */ { FsPath *fsPathPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (objPtr->typePtr == &tclFsPathType) { return TCL_OK; } /* Free old representation */ if (objPtr->typePtr != NULL) { if (objPtr->bytes == NULL) { if (objPtr->typePtr->updateStringProc == NULL) { if (interp != NULL) { Tcl_ResetResult(interp); Tcl_AppendResult(interp, "can't find object", "string representation", (char *) NULL); } return TCL_ERROR; } objPtr->typePtr->updateStringProc(objPtr); } if ((objPtr->typePtr->freeIntRepProc) != NULL) { (*objPtr->typePtr->freeIntRepProc)(objPtr); } } fsPathPtr = (FsPath*)ckalloc((unsigned)sizeof(FsPath)); /* It's a pure normalized absolute path */ fsPathPtr->translatedPathPtr = NULL; fsPathPtr->normPathPtr = objPtr; fsPathPtr->cwdPtr = NULL; fsPathPtr->nativePathPtr = NULL; fsPathPtr->fsRecPtr = NULL; fsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch; PATHOBJ(objPtr) = (VOID *) fsPathPtr; PATHFLAGS(objPtr) = 0; objPtr->typePtr = &tclFsPathType; return TCL_OK; } /* *--------------------------------------------------------------------------- * * Tcl_FSNewNativePath -- * * This function performs the something like that reverse of the * usual obj->path->nativerep conversions. If some code retrieves * a path in native form (from, e.g. readlink or a native dialog), * and that path is to be used at the Tcl level, then calling * this function is an efficient way of creating the appropriate * path object type. * * Any memory which is allocated for 'clientData' should be retained * until clientData is passed to the filesystem's freeInternalRepProc * when it can be freed. The built in platform-specific filesystems * use 'ckalloc' to allocate clientData, and ckfree to free it. * * Results: * NULL or a valid path object pointer, with refCount zero. * * Side effects: * New memory may be allocated. * *--------------------------------------------------------------------------- */ Tcl_Obj * Tcl_FSNewNativePath(fromFilesystem, clientData) Tcl_Filesystem* fromFilesystem; ClientData clientData; { Tcl_Obj *objPtr; FsPath *fsPathPtr; FilesystemRecord *fsFromPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); objPtr = TclFSInternalToNormalized(fromFilesystem, clientData, &fsFromPtr); if (objPtr == NULL) { return NULL; } /* * Free old representation; shouldn't normally be any, * but best to be safe. */ if (objPtr->typePtr != NULL) { if (objPtr->bytes == NULL) { if (objPtr->typePtr->updateStringProc == NULL) { return NULL; } objPtr->typePtr->updateStringProc(objPtr); } if ((objPtr->typePtr->freeIntRepProc) != NULL) { (*objPtr->typePtr->freeIntRepProc)(objPtr); } } fsPathPtr = (FsPath*)ckalloc((unsigned)sizeof(FsPath)); fsPathPtr->translatedPathPtr = NULL; /* Circular reference, by design */ fsPathPtr->normPathPtr = objPtr; fsPathPtr->cwdPtr = NULL; fsPathPtr->nativePathPtr = clientData; fsPathPtr->fsRecPtr = fsFromPtr; fsPathPtr->fsRecPtr->fileRefCount++; fsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch; PATHOBJ(objPtr) = (VOID *) fsPathPtr; PATHFLAGS(objPtr) = 0; objPtr->typePtr = &tclFsPathType; return objPtr; } /* *--------------------------------------------------------------------------- * * Tcl_FSGetTranslatedPath -- * * This function attempts to extract the translated path * from the given Tcl_Obj. If the translation succeeds (i.e. the * object is a valid path), then it is returned. Otherwise NULL * will be returned, and an error message may be left in the * interpreter (if it is non-NULL) * * Results: * NULL or a valid Tcl_Obj pointer. * * Side effects: * Only those of 'Tcl_FSConvertToPathType' * *--------------------------------------------------------------------------- */ Tcl_Obj* Tcl_FSGetTranslatedPath(interp, pathPtr) Tcl_Interp *interp; Tcl_Obj* pathPtr; { Tcl_Obj *retObj = NULL; FsPath *srcFsPathPtr; if (Tcl_FSConvertToPathType(interp, pathPtr) != TCL_OK) { return NULL; } srcFsPathPtr = (FsPath*) PATHOBJ(pathPtr); if (srcFsPathPtr->translatedPathPtr == NULL) { if (PATHFLAGS(pathPtr) != 0) { /* * We lack a translated path result, but we have a directory * (cwdPtr) and a tail (normPathPtr), and if we join the * translated version of cwdPtr to normPathPtr, we'll get the * translated result we need, and can store it for future use. */ Tcl_Obj *translatedCwdPtr = Tcl_FSGetTranslatedPath(interp, srcFsPathPtr->cwdPtr); retObj = Tcl_FSJoinToPath(translatedCwdPtr, 1, &(srcFsPathPtr->normPathPtr)); srcFsPathPtr->translatedPathPtr = retObj; Tcl_IncrRefCount(retObj); Tcl_DecrRefCount(translatedCwdPtr); } else { /* * It is a pure absolute, normalized path object. * This is something like being a 'pure list'. The * object's string, translatedPath and normalizedPath * are all identical. */ retObj = srcFsPathPtr->normPathPtr; } } else { /* It is an ordinary path object */ retObj = srcFsPathPtr->translatedPathPtr; } if (retObj) { Tcl_IncrRefCount(retObj); } return retObj; } /* *--------------------------------------------------------------------------- * * Tcl_FSGetTranslatedStringPath -- * * This function attempts to extract the translated path * from the given Tcl_Obj. If the translation succeeds (i.e. the * object is a valid path), then the path is returned. Otherwise NULL * will be returned, and an error message may be left in the * interpreter (if it is non-NULL) * * Results: * NULL or a valid string. * * Side effects: * Only those of 'Tcl_FSConvertToPathType' * *--------------------------------------------------------------------------- */ CONST char* Tcl_FSGetTranslatedStringPath(interp, pathPtr) Tcl_Interp *interp; Tcl_Obj* pathPtr; { Tcl_Obj *transPtr = Tcl_FSGetTranslatedPath(interp, pathPtr); if (transPtr != NULL) { int len; CONST char *result, *orig; orig = Tcl_GetStringFromObj(transPtr, &len); result = (char*) ckalloc((unsigned)(len+1)); memcpy((VOID*) result, (VOID*) orig, (size_t) (len+1)); Tcl_DecrRefCount(transPtr); return result; } return NULL; } /* *--------------------------------------------------------------------------- * * Tcl_FSGetNormalizedPath -- * * This important function attempts to extract from the given Tcl_Obj * a unique normalised path representation, whose string value can * be used as a unique identifier for the file. * * Results: * NULL or a valid path object pointer. * * Side effects: * New memory may be allocated. The Tcl 'errno' may be modified * in the process of trying to examine various path possibilities. * *--------------------------------------------------------------------------- */ Tcl_Obj* Tcl_FSGetNormalizedPath(interp, pathObjPtr) Tcl_Interp *interp; Tcl_Obj* pathObjPtr; { FsPath *fsPathPtr; if (Tcl_FSConvertToPathType(interp, pathObjPtr) != TCL_OK) { return NULL; } fsPathPtr = (FsPath*) PATHOBJ(pathObjPtr); if (PATHFLAGS(pathObjPtr) != 0) { /* * This is a special path object which is the result of * something like 'file join' */ Tcl_Obj *dir, *copy; int cwdLen; int pathType; CONST char *cwdStr; pathType = Tcl_FSGetPathType(fsPathPtr->cwdPtr); dir = Tcl_FSGetNormalizedPath(interp, fsPathPtr->cwdPtr); if (dir == NULL) { return NULL; } if (pathObjPtr->bytes == NULL) { UpdateStringOfFsPath(pathObjPtr); } copy = Tcl_DuplicateObj(dir); Tcl_IncrRefCount(copy); Tcl_IncrRefCount(dir); /* We now own a reference on both 'dir' and 'copy' */ cwdStr = Tcl_GetStringFromObj(copy, &cwdLen); /* * Should we perhaps use 'Tcl_FSPathSeparator'? * But then what about the Windows special case? * Perhaps we should just check if cwd is a root volume. * We should never get cwdLen == 0 in this code path. */ switch (tclPlatform) { case TCL_PLATFORM_UNIX: if (cwdStr[cwdLen-1] != '/') { Tcl_AppendToObj(copy, "/", 1); cwdLen++; } break; case TCL_PLATFORM_WINDOWS: if (cwdStr[cwdLen-1] != '/' && cwdStr[cwdLen-1] != '\\') { Tcl_AppendToObj(copy, "/", 1); cwdLen++; } break; } Tcl_AppendObjToObj(copy, fsPathPtr->normPathPtr); /* Normalize the combined string. */ if (PATHFLAGS(pathObjPtr) & TCLPATH_NEEDNORM) { /* * If the "tail" part has components (like /../) that cause * the combined path to need more complete normalizing, * call on the more powerful routine to accomplish that so * we avoid [Bug 2385549] ... */ Tcl_Obj *newCopy = TclFSNormalizeAbsolutePath(interp, copy); Tcl_DecrRefCount(copy); copy = newCopy; } else { /* * ... but in most cases where we join a trouble free tail * to a normalized head, we can more efficiently normalize the * combined path by passing over only the unnormalized tail * portion. When this is sufficient, prior developers claim * this should be much faster. We use 'cwdLen-1' so that we are * already pointing at the dir-separator that we know about. * The normalization code will actually start off directly * after that separator. */ TclFSNormalizeToUniquePath(interp, copy, cwdLen-1); } /* Now we need to construct the new path object */ if (pathType == TCL_PATH_RELATIVE) { FsPath* origDirFsPathPtr; Tcl_Obj *origDir = fsPathPtr->cwdPtr; origDirFsPathPtr = (FsPath*) PATHOBJ(origDir); fsPathPtr->cwdPtr = origDirFsPathPtr->cwdPtr; Tcl_IncrRefCount(fsPathPtr->cwdPtr); Tcl_DecrRefCount(fsPathPtr->normPathPtr); fsPathPtr->normPathPtr = copy; /* That's our reference to copy used */ Tcl_DecrRefCount(dir); Tcl_DecrRefCount(origDir); } else { Tcl_DecrRefCount(fsPathPtr->cwdPtr); fsPathPtr->cwdPtr = NULL; Tcl_DecrRefCount(fsPathPtr->normPathPtr); fsPathPtr->normPathPtr = copy; /* That's our reference to copy used */ Tcl_DecrRefCount(dir); } PATHFLAGS(pathObjPtr) = 0; } /* Ensure cwd hasn't changed */ if (fsPathPtr->cwdPtr != NULL) { if (!TclFSCwdPointerEquals(fsPathPtr->cwdPtr)) { if (pathObjPtr->bytes == NULL) { UpdateStringOfFsPath(pathObjPtr); } FreeFsPathInternalRep(pathObjPtr); pathObjPtr->typePtr = NULL; if (Tcl_ConvertToType(interp, pathObjPtr, &tclFsPathType) != TCL_OK) { return NULL; } fsPathPtr = (FsPath*) PATHOBJ(pathObjPtr); } else if (fsPathPtr->normPathPtr == NULL) { int cwdLen; Tcl_Obj *copy; CONST char *cwdStr; copy = Tcl_DuplicateObj(fsPathPtr->cwdPtr); Tcl_IncrRefCount(copy); cwdStr = Tcl_GetStringFromObj(copy, &cwdLen); /* * Should we perhaps use 'Tcl_FSPathSeparator'? * But then what about the Windows special case? * Perhaps we should just check if cwd is a root volume. * We should never get cwdLen == 0 in this code path. */ switch (tclPlatform) { case TCL_PLATFORM_UNIX: if (cwdStr[cwdLen-1] != '/') { Tcl_AppendToObj(copy, "/", 1); cwdLen++; } break; case TCL_PLATFORM_WINDOWS: if (cwdStr[cwdLen-1] != '/' && cwdStr[cwdLen-1] != '\\') { Tcl_AppendToObj(copy, "/", 1); cwdLen++; } break; } Tcl_AppendObjToObj(copy, pathObjPtr); /* * Normalize the combined string, but only starting after * the end of the previously normalized 'dir'. This should * be much faster! */ TclFSNormalizeToUniquePath(interp, copy, cwdLen-1); fsPathPtr->normPathPtr = copy; } } if (fsPathPtr->normPathPtr == NULL) { Tcl_Obj *useThisCwd = NULL; /* * Since normPathPtr is NULL, but this is a valid path * object, we know that the translatedPathPtr cannot be NULL. */ Tcl_Obj *absolutePath = fsPathPtr->translatedPathPtr; char *path = Tcl_GetString(absolutePath); /* * We have to be a little bit careful here to avoid infinite loops * we're asking Tcl_FSGetPathType to return the path's type, but * that call can actually result in a lot of other filesystem * action, which might loop back through here. */ if (path[0] != '\0') { Tcl_PathType type = Tcl_FSGetPathType(pathObjPtr); if (type == TCL_PATH_RELATIVE) { useThisCwd = Tcl_FSGetCwd(interp); if (useThisCwd == NULL) return NULL; absolutePath = Tcl_FSJoinToPath(useThisCwd, 1, &absolutePath); Tcl_IncrRefCount(absolutePath); /* We have a refCount on the cwd */ #ifdef __WIN32__ } else if (type == TCL_PATH_VOLUME_RELATIVE) { /* * Only Windows has volume-relative paths. These * paths are rather rare, but is is nice if Tcl can * handle them. It is much better if we can * handle them here, rather than in the native fs code, * because we really need to have a real absolute path * just below. * * We do not let this block compile on non-Windows * platforms because the test suite's manual forcing * of tclPlatform can otherwise cause this code path * to be executed, causing various errors because * volume-relative paths really do not exist. */ useThisCwd = Tcl_FSGetCwd(interp); if (useThisCwd == NULL) return NULL; if (path[0] == '/') { /* * Path of form /foo/bar which is a path in the * root directory of the current volume. */ CONST char *drive = Tcl_GetString(useThisCwd); absolutePath = Tcl_NewStringObj(drive,2); Tcl_AppendToObj(absolutePath, path, -1); Tcl_IncrRefCount(absolutePath); /* We have a refCount on the cwd */ } else { /* * Path of form C:foo/bar, but this only makes * sense if the cwd is also on drive C. */ CONST char *drive = Tcl_GetString(useThisCwd); char drive_c = path[0]; if (drive_c >= 'a') { drive_c -= ('a' - 'A'); } if (drive[0] == drive_c) { absolutePath = Tcl_DuplicateObj(useThisCwd); /* We have a refCount on the cwd */ } else { Tcl_DecrRefCount(useThisCwd); useThisCwd = NULL; /* * The path is not in the current drive, but * is volume-relative. The way Tcl 8.3 handles * this is that it treats such a path as * relative to the root of the drive. We * therefore behave the same here. */ absolutePath = Tcl_NewStringObj(path, 2); } Tcl_IncrRefCount(absolutePath); Tcl_AppendToObj(absolutePath, "/", 1); Tcl_AppendToObj(absolutePath, path+2, -1); } #endif /* __WIN32__ */ } } /* Already has refCount incremented */ fsPathPtr->normPathPtr = TclFSNormalizeAbsolutePath(interp, absolutePath); if (!strcmp(Tcl_GetString(fsPathPtr->normPathPtr), Tcl_GetString(pathObjPtr))) { /* * The path was already normalized. * Get rid of the duplicate. */ Tcl_DecrRefCount(fsPathPtr->normPathPtr); /* * We do *not* increment the refCount for * this circular reference */ fsPathPtr->normPathPtr = pathObjPtr; } if (useThisCwd != NULL) { /* This was returned by Tcl_FSJoinToPath above */ Tcl_DecrRefCount(absolutePath); fsPathPtr->cwdPtr = useThisCwd; } } return fsPathPtr->normPathPtr; } /* *--------------------------------------------------------------------------- * * Tcl_FSGetInternalRep -- * * Extract the internal representation of a given path object, * in the given filesystem. If the path object belongs to a * different filesystem, we return NULL. * * If the internal representation is currently NULL, we attempt * to generate it, by calling the filesystem's * 'Tcl_FSCreateInternalRepProc'. * * Results: * NULL or a valid internal representation. * * Side effects: * An attempt may be made to convert the object. * *--------------------------------------------------------------------------- */ ClientData Tcl_FSGetInternalRep(pathObjPtr, fsPtr) Tcl_Obj* pathObjPtr; Tcl_Filesystem *fsPtr; { FsPath *srcFsPathPtr; if (Tcl_FSConvertToPathType(NULL, pathObjPtr) != TCL_OK) { return NULL; } srcFsPathPtr = (FsPath*) PATHOBJ(pathObjPtr); /* * We will only return the native representation for the caller's * filesystem. Otherwise we will simply return NULL. This means * that there must be a unique bi-directional mapping between paths * and filesystems, and that this mapping will not allow 'remapped' * files -- files which are in one filesystem but mapped into * another. Another way of putting this is that 'stacked' * filesystems are not allowed. We recognise that this is a * potentially useful feature for the future. * * Even something simple like a 'pass through' filesystem which * logs all activity and passes the calls onto the native system * would be nice, but not easily achievable with the current * implementation. */ if (srcFsPathPtr->fsRecPtr == NULL) { /* * This only usually happens in wrappers like TclpStat which * create a string object and pass it to TclpObjStat. Code * which calls the Tcl_FS.. functions should always have a * filesystem already set. Whether this code path is legal or * not depends on whether we decide to allow external code to * call the native filesystem directly. It is at least safer * to allow this sub-optimal routing. */ Tcl_FSGetFileSystemForPath(pathObjPtr); /* * If we fail through here, then the path is probably not a * valid path in the filesystsem, and is most likely to be a * use of the empty path "" via a direct call to one of the * objectified interfaces (e.g. from the Tcl testsuite). */ srcFsPathPtr = (FsPath*) PATHOBJ(pathObjPtr); if (srcFsPathPtr->fsRecPtr == NULL) { return NULL; } } if (fsPtr != srcFsPathPtr->fsRecPtr->fsPtr) { /* * There is still one possibility we should consider; if the * file belongs to a different filesystem, perhaps it is * actually linked through to a file in our own filesystem * which we do care about. The way we can check for this * is we ask what filesystem this path belongs to. */ Tcl_Filesystem *actualFs = Tcl_FSGetFileSystemForPath(pathObjPtr); if (actualFs == fsPtr) { return Tcl_FSGetInternalRep(pathObjPtr, fsPtr); } return NULL; } if (srcFsPathPtr->nativePathPtr == NULL) { Tcl_FSCreateInternalRepProc *proc; char *nativePathPtr; proc = srcFsPathPtr->fsRecPtr->fsPtr->createInternalRepProc; if (proc == NULL) { return NULL; } nativePathPtr = (*proc)(pathObjPtr); srcFsPathPtr = (FsPath*) PATHOBJ(pathObjPtr); srcFsPathPtr->nativePathPtr = nativePathPtr; } return srcFsPathPtr->nativePathPtr; } /* *--------------------------------------------------------------------------- * * TclFSEnsureEpochOk -- * * This will ensure the pathObjPtr is up to date and can be * converted into a "path" type, and that we are able to generate a * complete normalized path which is used to determine the * filesystem match. * * Results: * Standard Tcl return code. * * Side effects: * An attempt may be made to convert the object. * *--------------------------------------------------------------------------- */ int TclFSEnsureEpochOk(pathObjPtr, fsPtrPtr) Tcl_Obj* pathObjPtr; Tcl_Filesystem **fsPtrPtr; { FsPath *srcFsPathPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); /* * SHOULD BE ABLE TO IMPROVE EFFICIENCY HERE. */ if (Tcl_FSGetNormalizedPath(NULL, pathObjPtr) == NULL) { return TCL_ERROR; } srcFsPathPtr = (FsPath*) PATHOBJ(pathObjPtr); /* * Check if the filesystem has changed in some way since * this object's internal representation was calculated. */ if (srcFsPathPtr->filesystemEpoch != tsdPtr->filesystemEpoch) { /* * We have to discard the stale representation and * recalculate it */ if (pathObjPtr->bytes == NULL) { UpdateStringOfFsPath(pathObjPtr); } FreeFsPathInternalRep(pathObjPtr); pathObjPtr->typePtr = NULL; if (SetFsPathFromAny(NULL, pathObjPtr) != TCL_OK) { return TCL_ERROR; } srcFsPathPtr = (FsPath*) PATHOBJ(pathObjPtr); } /* Check whether the object is already assigned to a fs */ if (srcFsPathPtr->fsRecPtr != NULL) { *fsPtrPtr = srcFsPathPtr->fsRecPtr->fsPtr; } return TCL_OK; } void TclFSSetPathDetails(pathObjPtr, fsRecPtr, clientData) Tcl_Obj *pathObjPtr; FilesystemRecord *fsRecPtr; ClientData clientData; { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); /* We assume pathObjPtr is already of the correct type */ FsPath *srcFsPathPtr; srcFsPathPtr = (FsPath*) PATHOBJ(pathObjPtr); srcFsPathPtr->fsRecPtr = fsRecPtr; srcFsPathPtr->nativePathPtr = clientData; srcFsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch; fsRecPtr->fileRefCount++; } /* *--------------------------------------------------------------------------- * * Tcl_FSEqualPaths -- * * This function tests whether the two paths given are equal path * objects. If either or both is NULL, 0 is always returned. * * Results: * 1 or 0. * * Side effects: * None. * *--------------------------------------------------------------------------- */ int Tcl_FSEqualPaths(firstPtr, secondPtr) Tcl_Obj* firstPtr; Tcl_Obj* secondPtr; { if (firstPtr == secondPtr) { return 1; } else { char *firstStr, *secondStr; int firstLen, secondLen, tempErrno; if (firstPtr == NULL || secondPtr == NULL) { return 0; } firstStr = Tcl_GetStringFromObj(firstPtr, &firstLen); secondStr = Tcl_GetStringFromObj(secondPtr, &secondLen); if ((firstLen == secondLen) && (strcmp(firstStr, secondStr) == 0)) { return 1; } /* * Try the most thorough, correct method of comparing fully * normalized paths */ tempErrno = Tcl_GetErrno(); firstPtr = Tcl_FSGetNormalizedPath(NULL, firstPtr); secondPtr = Tcl_FSGetNormalizedPath(NULL, secondPtr); Tcl_SetErrno(tempErrno); if (firstPtr == NULL || secondPtr == NULL) { return 0; } firstStr = Tcl_GetStringFromObj(firstPtr, &firstLen); secondStr = Tcl_GetStringFromObj(secondPtr, &secondLen); if ((firstLen == secondLen) && (strcmp(firstStr, secondStr) == 0)) { return 1; } } return 0; } /* *--------------------------------------------------------------------------- * * SetFsPathFromAny -- * * This function tries to convert the given Tcl_Obj to a valid * Tcl path type. * * The filename may begin with "~" (to indicate current user's * home directory) or "~" (to indicate any user's home * directory). * * Results: * Standard Tcl error code. * * Side effects: * The old representation may be freed, and new memory allocated. * *--------------------------------------------------------------------------- */ static int SetFsPathFromAny(interp, objPtr) Tcl_Interp *interp; /* Used for error reporting if not NULL. */ Tcl_Obj *objPtr; /* The object to convert. */ { int len; FsPath *fsPathPtr; Tcl_Obj *transPtr; char *name; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (objPtr->typePtr == &tclFsPathType) { return TCL_OK; } /* * First step is to translate the filename. This is similar to * Tcl_TranslateFilename, but shouldn't convert everything to * windows backslashes on that platform. The current * implementation of this piece is a slightly optimised version * of the various Tilde/Split/Join stuff to avoid multiple * split/join operations. * * We remove any trailing directory separator. * * However, the split/join routines are quite complex, and * one has to make sure not to break anything on Unix, Win * or MacOS (fCmd.test, fileName.test and cmdAH.test exercise * most of the code). */ name = Tcl_GetStringFromObj(objPtr,&len); /* * Handle tilde substitutions, if needed. */ if (name[0] == '~') { char *expandedUser; Tcl_DString temp; int split; char separator='/'; split = FindSplitPos(name, &separator); if (split != len) { /* We have multiple pieces '~user/foo/bar...' */ name[split] = '\0'; } /* Do some tilde substitution */ if (name[1] == '\0') { /* We have just '~' */ CONST char *dir; Tcl_DString dirString; if (split != len) { name[split] = separator; } dir = TclGetEnv("HOME", &dirString); if (dir == NULL) { if (interp) { Tcl_ResetResult(interp); Tcl_AppendResult(interp, "couldn't find HOME environment ", "variable to expand path", (char *) NULL); } return TCL_ERROR; } Tcl_DStringInit(&temp); Tcl_JoinPath(1, &dir, &temp); Tcl_DStringFree(&dirString); } else { /* We have a user name '~user' */ Tcl_DStringInit(&temp); if (TclpGetUserHome(name+1, &temp) == NULL) { if (interp != NULL) { Tcl_ResetResult(interp); Tcl_AppendResult(interp, "user \"", (name+1), "\" doesn't exist", (char *) NULL); } Tcl_DStringFree(&temp); if (split != len) { name[split] = separator; } return TCL_ERROR; } if (split != len) { name[split] = separator; } } expandedUser = Tcl_DStringValue(&temp); transPtr = Tcl_NewStringObj(expandedUser, Tcl_DStringLength(&temp)); if (split != len) { /* Join up the tilde substitution with the rest */ if (name[split+1] == separator) { /* * Somewhat tricky case like ~//foo/bar. * Make use of Split/Join machinery to get it right. * Assumes all paths beginning with ~ are part of the * native filesystem. */ int objc; Tcl_Obj **objv; Tcl_Obj *parts = TclpNativeSplitPath(objPtr, NULL); Tcl_ListObjGetElements(NULL, parts, &objc, &objv); /* Skip '~'. It's replaced by its expansion */ objc--; objv++; while (objc--) { TclpNativeJoinPath(transPtr, Tcl_GetString(*objv++)); } Tcl_DecrRefCount(parts); } else { /* Simple case. "rest" is relative path. Just join it. */ Tcl_Obj *rest = Tcl_NewStringObj(name+split+1,-1); transPtr = Tcl_FSJoinToPath(transPtr, 1, &rest); } } Tcl_DStringFree(&temp); } else { transPtr = Tcl_FSJoinToPath(objPtr,0,NULL); } /* * Now we have a translated filename in 'transPtr'. This will have * forward slashes on Windows, and will not contain any ~user * sequences. */ fsPathPtr = (FsPath*)ckalloc((unsigned)sizeof(FsPath)); fsPathPtr->translatedPathPtr = transPtr; Tcl_IncrRefCount(fsPathPtr->translatedPathPtr); fsPathPtr->normPathPtr = NULL; fsPathPtr->cwdPtr = NULL; fsPathPtr->nativePathPtr = NULL; fsPathPtr->fsRecPtr = NULL; fsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch; /* * Free old representation before installing our new one. */ if (objPtr->typePtr != NULL && objPtr->typePtr->freeIntRepProc != NULL) { (objPtr->typePtr->freeIntRepProc)(objPtr); } PATHOBJ(objPtr) = (VOID *) fsPathPtr; PATHFLAGS(objPtr) = 0; objPtr->typePtr = &tclFsPathType; return TCL_OK; } static void FreeFsPathInternalRep(pathObjPtr) Tcl_Obj *pathObjPtr; /* Path object with internal rep to free. */ { FsPath *fsPathPtr = (FsPath*) PATHOBJ(pathObjPtr); if (fsPathPtr->translatedPathPtr != NULL) { if (fsPathPtr->translatedPathPtr != pathObjPtr) { Tcl_DecrRefCount(fsPathPtr->translatedPathPtr); } } if (fsPathPtr->normPathPtr != NULL) { if (fsPathPtr->normPathPtr != pathObjPtr) { Tcl_DecrRefCount(fsPathPtr->normPathPtr); } fsPathPtr->normPathPtr = NULL; } if (fsPathPtr->cwdPtr != NULL) { Tcl_DecrRefCount(fsPathPtr->cwdPtr); } if (fsPathPtr->nativePathPtr != NULL) { if (fsPathPtr->fsRecPtr != NULL) { if (fsPathPtr->fsRecPtr->fsPtr->freeInternalRepProc != NULL) { (*fsPathPtr->fsRecPtr->fsPtr ->freeInternalRepProc)(fsPathPtr->nativePathPtr); fsPathPtr->nativePathPtr = NULL; } } } if (fsPathPtr->fsRecPtr != NULL) { fsPathPtr->fsRecPtr->fileRefCount--; if (fsPathPtr->fsRecPtr->fileRefCount <= 0) { /* It has been unregistered already, so simply free it */ ckfree((char *)fsPathPtr->fsRecPtr); } } ckfree((char*) fsPathPtr); } static void DupFsPathInternalRep(srcPtr, copyPtr) Tcl_Obj *srcPtr; /* Path obj with internal rep to copy. */ Tcl_Obj *copyPtr; /* Path obj with internal rep to set. */ { FsPath *srcFsPathPtr = (FsPath*) PATHOBJ(srcPtr); FsPath *copyFsPathPtr = (FsPath*) ckalloc((unsigned)sizeof(FsPath)); Tcl_FSDupInternalRepProc *dupProc; PATHOBJ(copyPtr) = (VOID *) copyFsPathPtr; if (srcFsPathPtr->translatedPathPtr != NULL) { copyFsPathPtr->translatedPathPtr = srcFsPathPtr->translatedPathPtr; if (copyFsPathPtr->translatedPathPtr != copyPtr) { Tcl_IncrRefCount(copyFsPathPtr->translatedPathPtr); } } else { copyFsPathPtr->translatedPathPtr = NULL; } if (srcFsPathPtr->normPathPtr != NULL) { copyFsPathPtr->normPathPtr = srcFsPathPtr->normPathPtr; if (copyFsPathPtr->normPathPtr != copyPtr) { Tcl_IncrRefCount(copyFsPathPtr->normPathPtr); } } else { copyFsPathPtr->normPathPtr = NULL; } if (srcFsPathPtr->cwdPtr != NULL) { copyFsPathPtr->cwdPtr = srcFsPathPtr->cwdPtr; Tcl_IncrRefCount(copyFsPathPtr->cwdPtr); } else { copyFsPathPtr->cwdPtr = NULL; } copyFsPathPtr->flags = srcFsPathPtr->flags; if (srcFsPathPtr->fsRecPtr != NULL && srcFsPathPtr->nativePathPtr != NULL) { dupProc = srcFsPathPtr->fsRecPtr->fsPtr->dupInternalRepProc; if (dupProc != NULL) { copyFsPathPtr->nativePathPtr = (*dupProc)(srcFsPathPtr->nativePathPtr); } else { copyFsPathPtr->nativePathPtr = NULL; } } else { copyFsPathPtr->nativePathPtr = NULL; } copyFsPathPtr->fsRecPtr = srcFsPathPtr->fsRecPtr; copyFsPathPtr->filesystemEpoch = srcFsPathPtr->filesystemEpoch; if (copyFsPathPtr->fsRecPtr != NULL) { copyFsPathPtr->fsRecPtr->fileRefCount++; } copyPtr->typePtr = &tclFsPathType; } /* *--------------------------------------------------------------------------- * * UpdateStringOfFsPath -- * * Gives an object a valid string rep. * * Results: * None. * * Side effects: * Memory may be allocated. * *--------------------------------------------------------------------------- */ static void UpdateStringOfFsPath(objPtr) register Tcl_Obj *objPtr; /* path obj with string rep to update. */ { FsPath *fsPathPtr = (FsPath*) PATHOBJ(objPtr); CONST char *cwdStr; int cwdLen; Tcl_Obj *copy; if (PATHFLAGS(objPtr) == 0 || fsPathPtr->cwdPtr == NULL) { panic("Called UpdateStringOfFsPath with invalid object"); } copy = Tcl_DuplicateObj(fsPathPtr->cwdPtr); Tcl_IncrRefCount(copy); cwdStr = Tcl_GetStringFromObj(copy, &cwdLen); /* * Should we perhaps use 'Tcl_FSPathSeparator'? * But then what about the Windows special case? * Perhaps we should just check if cwd is a root volume. * We should never get cwdLen == 0 in this code path. */ switch (tclPlatform) { case TCL_PLATFORM_UNIX: if (cwdStr[cwdLen-1] != '/') { Tcl_AppendToObj(copy, "/", 1); cwdLen++; } break; case TCL_PLATFORM_WINDOWS: /* * We need the extra 'cwdLen != 2', and ':' checks because * a volume relative path doesn't get a '/'. For example * 'glob C:*cat*.exe' will return 'C:cat32.exe' */ if (cwdStr[cwdLen-1] != '/' && cwdStr[cwdLen-1] != '\\') { if (cwdLen != 2 || cwdStr[1] != ':') { Tcl_AppendToObj(copy, "/", 1); cwdLen++; } } break; } Tcl_AppendObjToObj(copy, fsPathPtr->normPathPtr); objPtr->bytes = Tcl_GetStringFromObj(copy, &cwdLen); objPtr->length = cwdLen; copy->bytes = tclEmptyStringRep; copy->length = 0; Tcl_DecrRefCount(copy); } /* *--------------------------------------------------------------------------- * * NativePathInFilesystem -- * * Any path object is acceptable to the native filesystem, by * default (we will throw errors when illegal paths are actually * tried to be used). * * However, this behavior means the native filesystem must be * the last filesystem in the lookup list (otherwise it will * claim all files belong to it, and other filesystems will * never get a look in). * * Results: * TCL_OK, to indicate 'yes', -1 to indicate no. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int NativePathInFilesystem(pathPtr, clientDataPtr) Tcl_Obj *pathPtr; ClientData *clientDataPtr; { /* * A special case is required to handle the empty path "". * This is a valid path (i.e. the user should be able * to do 'file exists ""' without throwing an error), but * equally the path doesn't exist. Those are the semantics * of Tcl (at present anyway), so we have to abide by them * here. */ if (pathPtr->typePtr == &tclFsPathType) { if (pathPtr->bytes != NULL && pathPtr->bytes[0] == '\0') { /* We reject the empty path "" */ return -1; } /* Otherwise there is no way this path can be empty */ } else { /* * It is somewhat unusual to reach this code path without * the object being of tclFsPathType. However, we do * our best to deal with the situation. */ int len; Tcl_GetStringFromObj(pathPtr,&len); if (len == 0) { /* We reject the empty path "" */ return -1; } } /* * Path is of correct type, or is of non-zero length, * so we accept it. */ return TCL_OK; } tcl8.4.20/generic/tclBasic.c0000644003604700454610000061565012151137515014227 0ustar dgp771div/* * tclBasic.c -- * * Contains the basic facilities for TCL command interpretation, * including interpreter creation and deletion, command creation * and deletion, and command/script execution. * * Copyright (c) 1987-1994 The Regents of the University of California. * Copyright (c) 1994-1997 Sun Microsystems, Inc. * Copyright (c) 1998-1999 by Scriptics Corporation. * Copyright (c) 2001, 2002 by Kevin B. Kenny. All rights reserved. * Copyright (c) 2007 Daniel A. Steffen * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #if defined(_WIN32) && !defined(_WIN64) # define _USE_32BIT_TIME_T # include #endif #include "tclInt.h" #include "tclCompile.h" #ifndef TCL_GENERIC_ONLY # include "tclPort.h" #endif /* * Static procedures in this file: */ static char * CallCommandTraces _ANSI_ARGS_((Interp *iPtr, Command *cmdPtr, CONST char *oldName, CONST char* newName, int flags)); static void DeleteInterpProc _ANSI_ARGS_((Tcl_Interp *interp)); static void ProcessUnexpectedResult _ANSI_ARGS_(( Tcl_Interp *interp, int returnCode)); static int StringTraceProc _ANSI_ARGS_((ClientData clientData, Tcl_Interp* interp, int level, CONST char* command, Tcl_Command commandInfo, int objc, Tcl_Obj *CONST objv[])); static void StringTraceDeleteProc _ANSI_ARGS_((ClientData clientData)); #ifdef TCL_TIP280 /* TIP #280 - Modified token based evaluation, with line information */ static int EvalEx _ANSI_ARGS_((Tcl_Interp *interp, CONST char *script, int numBytes, int flags, int line, int* clNextOuter, CONST char* outerScript)); static int EvalTokensStandard _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Token *tokenPtr, int count, int line, int* clNextOuter, CONST char* outerScript)); #endif #ifdef USE_DTRACE static int DTraceObjCmd(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); #endif extern TclStubs tclStubs; /* * The following structure defines the commands in the Tcl core. */ typedef struct { CONST char *name; /* Name of object-based command. */ Tcl_CmdProc *proc; /* String-based procedure for command. */ Tcl_ObjCmdProc *objProc; /* Object-based procedure for command. */ CompileProc *compileProc; /* Procedure called to compile command. */ int isSafe; /* If non-zero, command will be present * in safe interpreter. Otherwise it will * be hidden. */ } CmdInfo; /* * The built-in commands, and the procedures that implement them: */ static CONST CmdInfo builtInCmds[] = { /* * Commands in the generic core. Note that at least one of the proc or * objProc members should be non-NULL. This avoids infinitely recursive * calls between TclInvokeObjectCommand and TclInvokeStringCommand if a * command name is computed at runtime and results in the name of a * compiled command. */ {"append", (Tcl_CmdProc *) NULL, Tcl_AppendObjCmd, TclCompileAppendCmd, 1}, {"array", (Tcl_CmdProc *) NULL, Tcl_ArrayObjCmd, (CompileProc *) NULL, 1}, {"binary", (Tcl_CmdProc *) NULL, Tcl_BinaryObjCmd, (CompileProc *) NULL, 1}, {"break", (Tcl_CmdProc *) NULL, Tcl_BreakObjCmd, TclCompileBreakCmd, 1}, {"case", (Tcl_CmdProc *) NULL, Tcl_CaseObjCmd, (CompileProc *) NULL, 1}, {"catch", (Tcl_CmdProc *) NULL, Tcl_CatchObjCmd, TclCompileCatchCmd, 1}, {"clock", (Tcl_CmdProc *) NULL, Tcl_ClockObjCmd, (CompileProc *) NULL, 1}, {"concat", (Tcl_CmdProc *) NULL, Tcl_ConcatObjCmd, (CompileProc *) NULL, 1}, {"continue", (Tcl_CmdProc *) NULL, Tcl_ContinueObjCmd, TclCompileContinueCmd, 1}, {"encoding", (Tcl_CmdProc *) NULL, Tcl_EncodingObjCmd, (CompileProc *) NULL, 0}, {"error", (Tcl_CmdProc *) NULL, Tcl_ErrorObjCmd, (CompileProc *) NULL, 1}, {"eval", (Tcl_CmdProc *) NULL, Tcl_EvalObjCmd, (CompileProc *) NULL, 1}, {"exit", (Tcl_CmdProc *) NULL, Tcl_ExitObjCmd, (CompileProc *) NULL, 0}, {"expr", (Tcl_CmdProc *) NULL, Tcl_ExprObjCmd, TclCompileExprCmd, 1}, {"fcopy", (Tcl_CmdProc *) NULL, Tcl_FcopyObjCmd, (CompileProc *) NULL, 1}, {"fileevent", (Tcl_CmdProc *) NULL, Tcl_FileEventObjCmd, (CompileProc *) NULL, 1}, {"for", (Tcl_CmdProc *) NULL, Tcl_ForObjCmd, TclCompileForCmd, 1}, {"foreach", (Tcl_CmdProc *) NULL, Tcl_ForeachObjCmd, TclCompileForeachCmd, 1}, {"format", (Tcl_CmdProc *) NULL, Tcl_FormatObjCmd, (CompileProc *) NULL, 1}, {"global", (Tcl_CmdProc *) NULL, Tcl_GlobalObjCmd, (CompileProc *) NULL, 1}, {"if", (Tcl_CmdProc *) NULL, Tcl_IfObjCmd, TclCompileIfCmd, 1}, {"incr", (Tcl_CmdProc *) NULL, Tcl_IncrObjCmd, TclCompileIncrCmd, 1}, {"info", (Tcl_CmdProc *) NULL, Tcl_InfoObjCmd, (CompileProc *) NULL, 1}, {"join", (Tcl_CmdProc *) NULL, Tcl_JoinObjCmd, (CompileProc *) NULL, 1}, {"lappend", (Tcl_CmdProc *) NULL, Tcl_LappendObjCmd, TclCompileLappendCmd, 1}, {"lindex", (Tcl_CmdProc *) NULL, Tcl_LindexObjCmd, TclCompileLindexCmd, 1}, {"linsert", (Tcl_CmdProc *) NULL, Tcl_LinsertObjCmd, (CompileProc *) NULL, 1}, {"list", (Tcl_CmdProc *) NULL, Tcl_ListObjCmd, TclCompileListCmd, 1}, {"llength", (Tcl_CmdProc *) NULL, Tcl_LlengthObjCmd, TclCompileLlengthCmd, 1}, {"load", (Tcl_CmdProc *) NULL, Tcl_LoadObjCmd, (CompileProc *) NULL, 0}, {"lrange", (Tcl_CmdProc *) NULL, Tcl_LrangeObjCmd, (CompileProc *) NULL, 1}, {"lreplace", (Tcl_CmdProc *) NULL, Tcl_LreplaceObjCmd, (CompileProc *) NULL, 1}, {"lsearch", (Tcl_CmdProc *) NULL, Tcl_LsearchObjCmd, (CompileProc *) NULL, 1}, {"lset", (Tcl_CmdProc *) NULL, Tcl_LsetObjCmd, TclCompileLsetCmd, 1}, {"lsort", (Tcl_CmdProc *) NULL, Tcl_LsortObjCmd, (CompileProc *) NULL, 1}, {"namespace", (Tcl_CmdProc *) NULL, Tcl_NamespaceObjCmd, (CompileProc *) NULL, 1}, {"package", (Tcl_CmdProc *) NULL, Tcl_PackageObjCmd, (CompileProc *) NULL, 1}, {"proc", (Tcl_CmdProc *) NULL, Tcl_ProcObjCmd, (CompileProc *) NULL, 1}, {"regexp", (Tcl_CmdProc *) NULL, Tcl_RegexpObjCmd, TclCompileRegexpCmd, 1}, {"regsub", (Tcl_CmdProc *) NULL, Tcl_RegsubObjCmd, (CompileProc *) NULL, 1}, {"rename", (Tcl_CmdProc *) NULL, Tcl_RenameObjCmd, (CompileProc *) NULL, 1}, {"return", (Tcl_CmdProc *) NULL, Tcl_ReturnObjCmd, TclCompileReturnCmd, 1}, {"scan", (Tcl_CmdProc *) NULL, Tcl_ScanObjCmd, (CompileProc *) NULL, 1}, {"set", (Tcl_CmdProc *) NULL, Tcl_SetObjCmd, TclCompileSetCmd, 1}, {"split", (Tcl_CmdProc *) NULL, Tcl_SplitObjCmd, (CompileProc *) NULL, 1}, {"string", (Tcl_CmdProc *) NULL, Tcl_StringObjCmd, TclCompileStringCmd, 1}, {"subst", (Tcl_CmdProc *) NULL, Tcl_SubstObjCmd, (CompileProc *) NULL, 1}, {"switch", (Tcl_CmdProc *) NULL, Tcl_SwitchObjCmd, (CompileProc *) NULL, 1}, {"trace", (Tcl_CmdProc *) NULL, Tcl_TraceObjCmd, (CompileProc *) NULL, 1}, {"unset", (Tcl_CmdProc *) NULL, Tcl_UnsetObjCmd, (CompileProc *) NULL, 1}, {"uplevel", (Tcl_CmdProc *) NULL, Tcl_UplevelObjCmd, (CompileProc *) NULL, 1}, {"upvar", (Tcl_CmdProc *) NULL, Tcl_UpvarObjCmd, (CompileProc *) NULL, 1}, {"variable", (Tcl_CmdProc *) NULL, Tcl_VariableObjCmd, (CompileProc *) NULL, 1}, {"while", (Tcl_CmdProc *) NULL, Tcl_WhileObjCmd, TclCompileWhileCmd, 1}, /* * Commands in the UNIX core: */ #ifndef TCL_GENERIC_ONLY {"after", (Tcl_CmdProc *) NULL, Tcl_AfterObjCmd, (CompileProc *) NULL, 1}, {"cd", (Tcl_CmdProc *) NULL, Tcl_CdObjCmd, (CompileProc *) NULL, 0}, {"close", (Tcl_CmdProc *) NULL, Tcl_CloseObjCmd, (CompileProc *) NULL, 1}, {"eof", (Tcl_CmdProc *) NULL, Tcl_EofObjCmd, (CompileProc *) NULL, 1}, {"fblocked", (Tcl_CmdProc *) NULL, Tcl_FblockedObjCmd, (CompileProc *) NULL, 1}, {"fconfigure", (Tcl_CmdProc *) NULL, Tcl_FconfigureObjCmd, (CompileProc *) NULL, 0}, {"file", (Tcl_CmdProc *) NULL, Tcl_FileObjCmd, (CompileProc *) NULL, 0}, {"flush", (Tcl_CmdProc *) NULL, Tcl_FlushObjCmd, (CompileProc *) NULL, 1}, {"gets", (Tcl_CmdProc *) NULL, Tcl_GetsObjCmd, (CompileProc *) NULL, 1}, {"glob", (Tcl_CmdProc *) NULL, Tcl_GlobObjCmd, (CompileProc *) NULL, 0}, {"open", (Tcl_CmdProc *) NULL, Tcl_OpenObjCmd, (CompileProc *) NULL, 0}, {"pid", (Tcl_CmdProc *) NULL, Tcl_PidObjCmd, (CompileProc *) NULL, 1}, {"puts", (Tcl_CmdProc *) NULL, Tcl_PutsObjCmd, (CompileProc *) NULL, 1}, {"pwd", (Tcl_CmdProc *) NULL, Tcl_PwdObjCmd, (CompileProc *) NULL, 0}, {"read", (Tcl_CmdProc *) NULL, Tcl_ReadObjCmd, (CompileProc *) NULL, 1}, {"seek", (Tcl_CmdProc *) NULL, Tcl_SeekObjCmd, (CompileProc *) NULL, 1}, {"socket", (Tcl_CmdProc *) NULL, Tcl_SocketObjCmd, (CompileProc *) NULL, 0}, {"tell", (Tcl_CmdProc *) NULL, Tcl_TellObjCmd, (CompileProc *) NULL, 1}, {"time", (Tcl_CmdProc *) NULL, Tcl_TimeObjCmd, (CompileProc *) NULL, 1}, {"update", (Tcl_CmdProc *) NULL, Tcl_UpdateObjCmd, (CompileProc *) NULL, 1}, {"vwait", (Tcl_CmdProc *) NULL, Tcl_VwaitObjCmd, (CompileProc *) NULL, 1}, {"exec", (Tcl_CmdProc *) NULL, Tcl_ExecObjCmd, (CompileProc *) NULL, 0}, {"source", (Tcl_CmdProc *) NULL, Tcl_SourceObjCmd, (CompileProc *) NULL, 0}, #endif /* TCL_GENERIC_ONLY */ {NULL, (Tcl_CmdProc *) NULL, (Tcl_ObjCmdProc *) NULL, (CompileProc *) NULL, 0} }; /* * The following structure holds the client data for string-based * trace procs */ typedef struct StringTraceData { ClientData clientData; /* Client data from Tcl_CreateTrace */ Tcl_CmdTraceProc* proc; /* Trace procedure from Tcl_CreateTrace */ } StringTraceData; /* *---------------------------------------------------------------------- * * Tcl_CreateInterp -- * * Create a new TCL command interpreter. * * Results: * The return value is a token for the interpreter, which may be * used in calls to procedures like Tcl_CreateCmd, Tcl_Eval, or * Tcl_DeleteInterp. * * Side effects: * The command interpreter is initialized with the built-in commands * and with the variables documented in tclvars(n). * *---------------------------------------------------------------------- */ Tcl_Interp * Tcl_CreateInterp() { Interp *iPtr; Tcl_Interp *interp; Command *cmdPtr; BuiltinFunc *builtinFuncPtr; MathFunc *mathFuncPtr; Tcl_HashEntry *hPtr; CONST CmdInfo *cmdInfoPtr; int i; union { char c[sizeof(short)]; short s; } order; #ifdef TCL_COMPILE_STATS ByteCodeStats *statsPtr; #endif /* TCL_COMPILE_STATS */ TclInitSubsystems(NULL); /* * Panic if someone updated the CallFrame structure without * also updating the Tcl_CallFrame structure (or vice versa). */ if (sizeof(Tcl_CallFrame) < sizeof(CallFrame)) { /*NOTREACHED*/ panic("Tcl_CallFrame must not be smaller than CallFrame"); } #if defined(_WIN32) && !defined(_WIN64) if (sizeof(time_t) != 4) { /*NOTREACHED*/ Tcl_Panic("sys/time.h is not compatible with MSVC"); } if (sizeof(Tcl_StatBuf) != 48) { /*NOTREACHED*/ Tcl_Panic("sys/stat.h is not compatible with MSVC"); } #endif /* * Initialize support for namespaces and create the global namespace * (whose name is ""; an alias is "::"). This also initializes the * Tcl object type table and other object management code. */ iPtr = (Interp *) ckalloc(sizeof(Interp)); interp = (Tcl_Interp *) iPtr; iPtr->result = iPtr->resultSpace; iPtr->freeProc = NULL; iPtr->errorLine = 0; iPtr->objResultPtr = Tcl_NewObj(); Tcl_IncrRefCount(iPtr->objResultPtr); iPtr->handle = TclHandleCreate(iPtr); iPtr->globalNsPtr = NULL; iPtr->hiddenCmdTablePtr = NULL; iPtr->interpInfo = NULL; Tcl_InitHashTable(&iPtr->mathFuncTable, TCL_STRING_KEYS); iPtr->numLevels = 0; iPtr->maxNestingDepth = MAX_NESTING_DEPTH; iPtr->framePtr = NULL; iPtr->varFramePtr = NULL; #ifdef TCL_TIP280 /* * TIP #280 - Initialize the arrays used to extend the ByteCode and * Proc structures. */ iPtr->cmdFramePtr = NULL; iPtr->linePBodyPtr = (Tcl_HashTable*) ckalloc (sizeof (Tcl_HashTable)); iPtr->lineBCPtr = (Tcl_HashTable*) ckalloc (sizeof (Tcl_HashTable)); iPtr->lineLAPtr = (Tcl_HashTable*) ckalloc (sizeof (Tcl_HashTable)); iPtr->lineLABCPtr = (Tcl_HashTable*) ckalloc (sizeof (Tcl_HashTable)); Tcl_InitHashTable(iPtr->linePBodyPtr, TCL_ONE_WORD_KEYS); Tcl_InitHashTable(iPtr->lineBCPtr, TCL_ONE_WORD_KEYS); Tcl_InitHashTable(iPtr->lineLAPtr, TCL_ONE_WORD_KEYS); Tcl_InitHashTable(iPtr->lineLABCPtr, TCL_ONE_WORD_KEYS); iPtr->scriptCLLocPtr = NULL; #endif iPtr->activeVarTracePtr = NULL; iPtr->returnCode = TCL_OK; iPtr->errorInfo = NULL; iPtr->errorCode = NULL; iPtr->appendResult = NULL; iPtr->appendAvl = 0; iPtr->appendUsed = 0; Tcl_InitHashTable(&iPtr->packageTable, TCL_STRING_KEYS); iPtr->packageUnknown = NULL; #ifdef TCL_TIP268 /* TIP #268 */ iPtr->packagePrefer = (getenv ("TCL_PKG_PREFER_LATEST") == NULL ? PKG_PREFER_STABLE : PKG_PREFER_LATEST); #endif iPtr->cmdCount = 0; iPtr->termOffset = 0; TclInitLiteralTable(&(iPtr->literalTable)); iPtr->compileEpoch = 0; iPtr->compiledProcPtr = NULL; iPtr->resolverPtr = NULL; iPtr->evalFlags = 0; iPtr->scriptFile = NULL; iPtr->flags = 0; iPtr->tracePtr = NULL; iPtr->tracesForbiddingInline = 0; iPtr->activeCmdTracePtr = NULL; iPtr->activeInterpTracePtr = NULL; iPtr->assocData = (Tcl_HashTable *) NULL; iPtr->execEnvPtr = NULL; /* set after namespaces initialized */ iPtr->emptyObjPtr = Tcl_NewObj(); /* another empty object */ Tcl_IncrRefCount(iPtr->emptyObjPtr); iPtr->resultSpace[0] = 0; iPtr->threadId = Tcl_GetCurrentThread(); iPtr->globalNsPtr = NULL; /* force creation of global ns below */ iPtr->globalNsPtr = (Namespace *) Tcl_CreateNamespace(interp, "", (ClientData) NULL, (Tcl_NamespaceDeleteProc *) NULL); if (iPtr->globalNsPtr == NULL) { panic("Tcl_CreateInterp: can't create global namespace"); } /* * Initialize support for code compilation and execution. We call * TclCreateExecEnv after initializing namespaces since it tries to * reference a Tcl variable (it links to the Tcl "tcl_traceExec" * variable). */ iPtr->execEnvPtr = TclCreateExecEnv(interp); /* * Initialize the compilation and execution statistics kept for this * interpreter. */ #ifdef TCL_COMPILE_STATS statsPtr = &(iPtr->stats); statsPtr->numExecutions = 0; statsPtr->numCompilations = 0; statsPtr->numByteCodesFreed = 0; (VOID *) memset(statsPtr->instructionCount, 0, sizeof(statsPtr->instructionCount)); statsPtr->totalSrcBytes = 0.0; statsPtr->totalByteCodeBytes = 0.0; statsPtr->currentSrcBytes = 0.0; statsPtr->currentByteCodeBytes = 0.0; (VOID *) memset(statsPtr->srcCount, 0, sizeof(statsPtr->srcCount)); (VOID *) memset(statsPtr->byteCodeCount, 0, sizeof(statsPtr->byteCodeCount)); (VOID *) memset(statsPtr->lifetimeCount, 0, sizeof(statsPtr->lifetimeCount)); statsPtr->currentInstBytes = 0.0; statsPtr->currentLitBytes = 0.0; statsPtr->currentExceptBytes = 0.0; statsPtr->currentAuxBytes = 0.0; statsPtr->currentCmdMapBytes = 0.0; statsPtr->numLiteralsCreated = 0; statsPtr->totalLitStringBytes = 0.0; statsPtr->currentLitStringBytes = 0.0; (VOID *) memset(statsPtr->literalCount, 0, sizeof(statsPtr->literalCount)); #endif /* TCL_COMPILE_STATS */ /* * Initialise the stub table pointer. */ iPtr->stubTable = &tclStubs; /* * Create the core commands. Do it here, rather than calling * Tcl_CreateCommand, because it's faster (there's no need to check for * a pre-existing command by the same name). If a command has a * Tcl_CmdProc but no Tcl_ObjCmdProc, set the Tcl_ObjCmdProc to * TclInvokeStringCommand. This is an object-based wrapper procedure * that extracts strings, calls the string procedure, and creates an * object for the result. Similarly, if a command has a Tcl_ObjCmdProc * but no Tcl_CmdProc, set the Tcl_CmdProc to TclInvokeObjectCommand. */ for (cmdInfoPtr = builtInCmds; cmdInfoPtr->name != NULL; cmdInfoPtr++) { int new; Tcl_HashEntry *hPtr; if ((cmdInfoPtr->proc == (Tcl_CmdProc *) NULL) && (cmdInfoPtr->objProc == (Tcl_ObjCmdProc *) NULL) && (cmdInfoPtr->compileProc == (CompileProc *) NULL)) { panic("Tcl_CreateInterp: builtin command with NULL string and object command procs and a NULL compile proc\n"); } hPtr = Tcl_CreateHashEntry(&iPtr->globalNsPtr->cmdTable, cmdInfoPtr->name, &new); if (new) { cmdPtr = (Command *) ckalloc(sizeof(Command)); cmdPtr->hPtr = hPtr; cmdPtr->nsPtr = iPtr->globalNsPtr; cmdPtr->refCount = 1; cmdPtr->cmdEpoch = 0; cmdPtr->compileProc = cmdInfoPtr->compileProc; if (cmdInfoPtr->proc == (Tcl_CmdProc *) NULL) { cmdPtr->proc = TclInvokeObjectCommand; cmdPtr->clientData = (ClientData) cmdPtr; } else { cmdPtr->proc = cmdInfoPtr->proc; cmdPtr->clientData = (ClientData) NULL; } if (cmdInfoPtr->objProc == (Tcl_ObjCmdProc *) NULL) { cmdPtr->objProc = TclInvokeStringCommand; cmdPtr->objClientData = (ClientData) cmdPtr; } else { cmdPtr->objProc = cmdInfoPtr->objProc; cmdPtr->objClientData = (ClientData) NULL; } cmdPtr->deleteProc = NULL; cmdPtr->deleteData = (ClientData) NULL; cmdPtr->flags = 0; cmdPtr->importRefPtr = NULL; cmdPtr->tracePtr = NULL; Tcl_SetHashValue(hPtr, cmdPtr); } } #ifdef USE_DTRACE /* * Register the tcl::dtrace command. */ Tcl_CreateObjCommand(interp, "::tcl::dtrace", DTraceObjCmd, NULL, NULL); #endif /* USE_DTRACE */ /* * Register the builtin math functions. */ i = 0; for (builtinFuncPtr = tclBuiltinFuncTable; builtinFuncPtr->name != NULL; builtinFuncPtr++) { Tcl_CreateMathFunc((Tcl_Interp *) iPtr, builtinFuncPtr->name, builtinFuncPtr->numArgs, builtinFuncPtr->argTypes, (Tcl_MathProc *) NULL, (ClientData) 0); hPtr = Tcl_FindHashEntry(&iPtr->mathFuncTable, builtinFuncPtr->name); if (hPtr == NULL) { panic("Tcl_CreateInterp: Tcl_CreateMathFunc incorrectly registered '%s'", builtinFuncPtr->name); return NULL; } mathFuncPtr = (MathFunc *) Tcl_GetHashValue(hPtr); mathFuncPtr->builtinFuncIndex = i; i++; } iPtr->flags |= EXPR_INITIALIZED; /* * Do Multiple/Safe Interps Tcl init stuff */ TclInterpInit(interp); /* * We used to create the "errorInfo" and "errorCode" global vars at this * point because so much of the Tcl implementation assumes they already * exist. This is not quite enough, however, since they can be unset * at any time. * * There are 2 choices: * + Check every place where a GetVar of those is used * and the NULL result is not checked (like in tclLoad.c) * + Make SetVar,... NULL friendly * We choose the second option because : * + It is easy and low cost to check for NULL pointer before * calling strlen() * + It can be helpfull to other people using those API * + Passing a NULL value to those closest 'meaning' is empty string * (specially with the new objects where 0 bytes strings are ok) * So the following init is commented out: -- dl * * (void) Tcl_SetVar2((Tcl_Interp *)iPtr, "errorInfo", (char *) NULL, * "", TCL_GLOBAL_ONLY); * (void) Tcl_SetVar2((Tcl_Interp *)iPtr, "errorCode", (char *) NULL, * "NONE", TCL_GLOBAL_ONLY); */ #ifndef TCL_GENERIC_ONLY TclSetupEnv(interp); #endif /* * Compute the byte order of this machine. */ order.s = 1; Tcl_SetVar2(interp, "tcl_platform", "byteOrder", ((order.c[0] == 1) ? "littleEndian" : "bigEndian"), TCL_GLOBAL_ONLY); Tcl_SetVar2Ex(interp, "tcl_platform", "wordSize", Tcl_NewLongObj((long) sizeof(long)), TCL_GLOBAL_ONLY); /* * Set up other variables such as tcl_version and tcl_library */ Tcl_SetVar(interp, "tcl_patchLevel", TCL_PATCH_LEVEL, TCL_GLOBAL_ONLY); Tcl_SetVar(interp, "tcl_version", TCL_VERSION, TCL_GLOBAL_ONLY); Tcl_TraceVar2(interp, "tcl_precision", (char *) NULL, TCL_GLOBAL_ONLY|TCL_TRACE_READS|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, TclPrecTraceProc, (ClientData) NULL); TclpSetVariables(interp); #ifdef TCL_THREADS /* * The existence of the "threaded" element of the tcl_platform array indicates * that this particular Tcl shell has been compiled with threads turned on. * Using "info exists tcl_platform(threaded)" a Tcl script can introspect on the * interpreter level of thread safety. */ Tcl_SetVar2(interp, "tcl_platform", "threaded", "1", TCL_GLOBAL_ONLY); #endif /* * Register Tcl's version number. * TIP#268: Expose information about its status, * for runtime switches in the core library * and tests. */ Tcl_PkgProvideEx(interp, "Tcl", TCL_VERSION, (ClientData) &tclStubs); #ifdef TCL_TIP268 Tcl_SetVar2(interp, "tcl_platform", "tip,268", "1", TCL_GLOBAL_ONLY); #endif #ifdef TCL_TIP280 Tcl_SetVar2(interp, "tcl_platform", "tip,280", "1", TCL_GLOBAL_ONLY); #endif #ifdef Tcl_InitStubs #undef Tcl_InitStubs #endif Tcl_InitStubs(interp, TCL_VERSION, 1); return interp; } /* *---------------------------------------------------------------------- * * TclHideUnsafeCommands -- * * Hides base commands that are not marked as safe from this * interpreter. * * Results: * TCL_OK if it succeeds, TCL_ERROR else. * * Side effects: * Hides functionality in an interpreter. * *---------------------------------------------------------------------- */ int TclHideUnsafeCommands(interp) Tcl_Interp *interp; /* Hide commands in this interpreter. */ { register CONST CmdInfo *cmdInfoPtr; if (interp == (Tcl_Interp *) NULL) { return TCL_ERROR; } for (cmdInfoPtr = builtInCmds; cmdInfoPtr->name != NULL; cmdInfoPtr++) { if (!cmdInfoPtr->isSafe) { Tcl_HideCommand(interp, cmdInfoPtr->name, cmdInfoPtr->name); } } return TCL_OK; } /* *-------------------------------------------------------------- * * Tcl_CallWhenDeleted -- * * Arrange for a procedure to be called before a given * interpreter is deleted. The procedure is called as soon * as Tcl_DeleteInterp is called; if Tcl_CallWhenDeleted is * called on an interpreter that has already been deleted, * the procedure will be called when the last Tcl_Release is * done on the interpreter. * * Results: * None. * * Side effects: * When Tcl_DeleteInterp is invoked to delete interp, * proc will be invoked. See the manual entry for * details. * *-------------------------------------------------------------- */ void Tcl_CallWhenDeleted(interp, proc, clientData) Tcl_Interp *interp; /* Interpreter to watch. */ Tcl_InterpDeleteProc *proc; /* Procedure to call when interpreter * is about to be deleted. */ ClientData clientData; /* One-word value to pass to proc. */ { Interp *iPtr = (Interp *) interp; static Tcl_ThreadDataKey assocDataCounterKey; int *assocDataCounterPtr = Tcl_GetThreadData(&assocDataCounterKey, (int)sizeof(int)); int new; char buffer[32 + TCL_INTEGER_SPACE]; AssocData *dPtr = (AssocData *) ckalloc(sizeof(AssocData)); Tcl_HashEntry *hPtr; sprintf(buffer, "Assoc Data Key #%d", *assocDataCounterPtr); (*assocDataCounterPtr)++; if (iPtr->assocData == (Tcl_HashTable *) NULL) { iPtr->assocData = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable)); Tcl_InitHashTable(iPtr->assocData, TCL_STRING_KEYS); } hPtr = Tcl_CreateHashEntry(iPtr->assocData, buffer, &new); dPtr->proc = proc; dPtr->clientData = clientData; Tcl_SetHashValue(hPtr, dPtr); } /* *-------------------------------------------------------------- * * Tcl_DontCallWhenDeleted -- * * Cancel the arrangement for a procedure to be called when * a given interpreter is deleted. * * Results: * None. * * Side effects: * If proc and clientData were previously registered as a * callback via Tcl_CallWhenDeleted, they are unregistered. * If they weren't previously registered then nothing * happens. * *-------------------------------------------------------------- */ void Tcl_DontCallWhenDeleted(interp, proc, clientData) Tcl_Interp *interp; /* Interpreter to watch. */ Tcl_InterpDeleteProc *proc; /* Procedure to call when interpreter * is about to be deleted. */ ClientData clientData; /* One-word value to pass to proc. */ { Interp *iPtr = (Interp *) interp; Tcl_HashTable *hTablePtr; Tcl_HashSearch hSearch; Tcl_HashEntry *hPtr; AssocData *dPtr; hTablePtr = iPtr->assocData; if (hTablePtr == (Tcl_HashTable *) NULL) { return; } for (hPtr = Tcl_FirstHashEntry(hTablePtr, &hSearch); hPtr != NULL; hPtr = Tcl_NextHashEntry(&hSearch)) { dPtr = (AssocData *) Tcl_GetHashValue(hPtr); if ((dPtr->proc == proc) && (dPtr->clientData == clientData)) { ckfree((char *) dPtr); Tcl_DeleteHashEntry(hPtr); return; } } } /* *---------------------------------------------------------------------- * * Tcl_SetAssocData -- * * Creates a named association between user-specified data, a delete * function and this interpreter. If the association already exists * the data is overwritten with the new data. The delete function will * be invoked when the interpreter is deleted. * * Results: * None. * * Side effects: * Sets the associated data, creates the association if needed. * *---------------------------------------------------------------------- */ void Tcl_SetAssocData(interp, name, proc, clientData) Tcl_Interp *interp; /* Interpreter to associate with. */ CONST char *name; /* Name for association. */ Tcl_InterpDeleteProc *proc; /* Proc to call when interpreter is * about to be deleted. */ ClientData clientData; /* One-word value to pass to proc. */ { Interp *iPtr = (Interp *) interp; AssocData *dPtr; Tcl_HashEntry *hPtr; int new; if (iPtr->assocData == (Tcl_HashTable *) NULL) { iPtr->assocData = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable)); Tcl_InitHashTable(iPtr->assocData, TCL_STRING_KEYS); } hPtr = Tcl_CreateHashEntry(iPtr->assocData, name, &new); if (new == 0) { dPtr = (AssocData *) Tcl_GetHashValue(hPtr); } else { dPtr = (AssocData *) ckalloc(sizeof(AssocData)); } dPtr->proc = proc; dPtr->clientData = clientData; Tcl_SetHashValue(hPtr, dPtr); } /* *---------------------------------------------------------------------- * * Tcl_DeleteAssocData -- * * Deletes a named association of user-specified data with * the specified interpreter. * * Results: * None. * * Side effects: * Deletes the association. * *---------------------------------------------------------------------- */ void Tcl_DeleteAssocData(interp, name) Tcl_Interp *interp; /* Interpreter to associate with. */ CONST char *name; /* Name of association. */ { Interp *iPtr = (Interp *) interp; AssocData *dPtr; Tcl_HashEntry *hPtr; if (iPtr->assocData == (Tcl_HashTable *) NULL) { return; } hPtr = Tcl_FindHashEntry(iPtr->assocData, name); if (hPtr == (Tcl_HashEntry *) NULL) { return; } dPtr = (AssocData *) Tcl_GetHashValue(hPtr); if (dPtr->proc != NULL) { (dPtr->proc) (dPtr->clientData, interp); } ckfree((char *) dPtr); Tcl_DeleteHashEntry(hPtr); } /* *---------------------------------------------------------------------- * * Tcl_GetAssocData -- * * Returns the client data associated with this name in the * specified interpreter. * * Results: * The client data in the AssocData record denoted by the named * association, or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ ClientData Tcl_GetAssocData(interp, name, procPtr) Tcl_Interp *interp; /* Interpreter associated with. */ CONST char *name; /* Name of association. */ Tcl_InterpDeleteProc **procPtr; /* Pointer to place to store address * of current deletion callback. */ { Interp *iPtr = (Interp *) interp; AssocData *dPtr; Tcl_HashEntry *hPtr; if (iPtr->assocData == (Tcl_HashTable *) NULL) { return (ClientData) NULL; } hPtr = Tcl_FindHashEntry(iPtr->assocData, name); if (hPtr == (Tcl_HashEntry *) NULL) { return (ClientData) NULL; } dPtr = (AssocData *) Tcl_GetHashValue(hPtr); if (procPtr != (Tcl_InterpDeleteProc **) NULL) { *procPtr = dPtr->proc; } return dPtr->clientData; } /* *---------------------------------------------------------------------- * * Tcl_InterpDeleted -- * * Returns nonzero if the interpreter has been deleted with a call * to Tcl_DeleteInterp. * * Results: * Nonzero if the interpreter is deleted, zero otherwise. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_InterpDeleted(interp) Tcl_Interp *interp; { return (((Interp *) interp)->flags & DELETED) ? 1 : 0; } /* *---------------------------------------------------------------------- * * Tcl_DeleteInterp -- * * Ensures that the interpreter will be deleted eventually. If there * are no Tcl_Preserve calls in effect for this interpreter, it is * deleted immediately, otherwise the interpreter is deleted when * the last Tcl_Preserve is matched by a call to Tcl_Release. In either * case, the procedure runs the currently registered deletion callbacks. * * Results: * None. * * Side effects: * The interpreter is marked as deleted. The caller may still use it * safely if there are calls to Tcl_Preserve in effect for the * interpreter, but further calls to Tcl_Eval etc in this interpreter * will fail. * *---------------------------------------------------------------------- */ void Tcl_DeleteInterp(interp) Tcl_Interp *interp; /* Token for command interpreter (returned * by a previous call to Tcl_CreateInterp). */ { Interp *iPtr = (Interp *) interp; /* * If the interpreter has already been marked deleted, just punt. */ if (iPtr->flags & DELETED) { return; } /* * Mark the interpreter as deleted. No further evals will be allowed. */ iPtr->flags |= DELETED; /* * Ensure that the interpreter is eventually deleted. */ Tcl_EventuallyFree((ClientData) interp, (Tcl_FreeProc *) DeleteInterpProc); } /* *---------------------------------------------------------------------- * * DeleteInterpProc -- * * Helper procedure to delete an interpreter. This procedure is * called when the last call to Tcl_Preserve on this interpreter * is matched by a call to Tcl_Release. The procedure cleans up * all resources used in the interpreter and calls all currently * registered interpreter deletion callbacks. * * Results: * None. * * Side effects: * Whatever the interpreter deletion callbacks do. Frees resources * used by the interpreter. * *---------------------------------------------------------------------- */ static void DeleteInterpProc(interp) Tcl_Interp *interp; /* Interpreter to delete. */ { Interp *iPtr = (Interp *) interp; Tcl_HashEntry *hPtr; Tcl_HashSearch search; Tcl_HashTable *hTablePtr; ResolverScheme *resPtr, *nextResPtr; /* * Punt if there is an error in the Tcl_Release/Tcl_Preserve matchup. */ if (iPtr->numLevels > 0) { panic("DeleteInterpProc called with active evals"); } /* * The interpreter should already be marked deleted; otherwise how * did we get here? */ if (!(iPtr->flags & DELETED)) { panic("DeleteInterpProc called on interpreter not marked deleted"); } TclHandleFree(iPtr->handle); /* * Dismantle everything in the global namespace except for the * "errorInfo" and "errorCode" variables. These remain until the * namespace is actually destroyed, in case any errors occur. * * Dismantle the namespace here, before we clear the assocData. If any * background errors occur here, they will be deleted below. */ TclTeardownNamespace(iPtr->globalNsPtr); /* * Delete all the hidden commands. */ hTablePtr = iPtr->hiddenCmdTablePtr; if (hTablePtr != NULL) { /* * Non-pernicious deletion. The deletion callbacks will not be * allowed to create any new hidden or non-hidden commands. * Tcl_DeleteCommandFromToken() will remove the entry from the * hiddenCmdTablePtr. */ hPtr = Tcl_FirstHashEntry(hTablePtr, &search); for ( ; hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { Tcl_DeleteCommandFromToken(interp, (Tcl_Command) Tcl_GetHashValue(hPtr)); } Tcl_DeleteHashTable(hTablePtr); ckfree((char *) hTablePtr); } /* * Tear down the math function table. */ for (hPtr = Tcl_FirstHashEntry(&iPtr->mathFuncTable, &search); hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { ckfree((char *) Tcl_GetHashValue(hPtr)); } Tcl_DeleteHashTable(&iPtr->mathFuncTable); /* * Invoke deletion callbacks; note that a callback can create new * callbacks, so we iterate. */ while (iPtr->assocData != (Tcl_HashTable *) NULL) { AssocData *dPtr; hTablePtr = iPtr->assocData; iPtr->assocData = (Tcl_HashTable *) NULL; for (hPtr = Tcl_FirstHashEntry(hTablePtr, &search); hPtr != NULL; hPtr = Tcl_FirstHashEntry(hTablePtr, &search)) { dPtr = (AssocData *) Tcl_GetHashValue(hPtr); Tcl_DeleteHashEntry(hPtr); if (dPtr->proc != NULL) { (*dPtr->proc)(dPtr->clientData, interp); } ckfree((char *) dPtr); } Tcl_DeleteHashTable(hTablePtr); ckfree((char *) hTablePtr); } /* * Finish deleting the global namespace. */ Tcl_DeleteNamespace((Tcl_Namespace *) iPtr->globalNsPtr); /* * Free up the result *after* deleting variables, since variable * deletion could have transferred ownership of the result string * to Tcl. */ Tcl_FreeResult(interp); interp->result = NULL; Tcl_DecrRefCount(iPtr->objResultPtr); iPtr->objResultPtr = NULL; if (iPtr->errorInfo != NULL) { ckfree(iPtr->errorInfo); iPtr->errorInfo = NULL; } if (iPtr->errorCode != NULL) { ckfree(iPtr->errorCode); iPtr->errorCode = NULL; } if (iPtr->appendResult != NULL) { ckfree(iPtr->appendResult); iPtr->appendResult = NULL; } TclFreePackageInfo(iPtr); while (iPtr->tracePtr != NULL) { Tcl_DeleteTrace((Tcl_Interp*) iPtr, (Tcl_Trace) iPtr->tracePtr); } if (iPtr->execEnvPtr != NULL) { TclDeleteExecEnv(iPtr->execEnvPtr); } if (iPtr->scriptFile) { Tcl_DecrRefCount(iPtr->scriptFile); iPtr->scriptFile = NULL; } Tcl_DecrRefCount(iPtr->emptyObjPtr); iPtr->emptyObjPtr = NULL; resPtr = iPtr->resolverPtr; while (resPtr) { nextResPtr = resPtr->nextPtr; ckfree(resPtr->name); ckfree((char *) resPtr); resPtr = nextResPtr; } /* * Free up literal objects created for scripts compiled by the * interpreter. */ TclDeleteLiteralTable(interp, &(iPtr->literalTable)); #ifdef TCL_TIP280 /* TIP #280 - Release the arrays for ByteCode/Proc extension, and contents. */ { Tcl_HashEntry *hPtr; Tcl_HashSearch hSearch; CmdFrame* cfPtr; ExtCmdLoc* eclPtr; int i; for (hPtr = Tcl_FirstHashEntry(iPtr->linePBodyPtr, &hSearch); hPtr != NULL; hPtr = Tcl_NextHashEntry(&hSearch)) { cfPtr = (CmdFrame*) Tcl_GetHashValue (hPtr); if (cfPtr->type == TCL_LOCATION_SOURCE) { Tcl_DecrRefCount (cfPtr->data.eval.path); } ckfree ((char*) cfPtr->line); ckfree ((char*) cfPtr); Tcl_DeleteHashEntry (hPtr); } Tcl_DeleteHashTable (iPtr->linePBodyPtr); ckfree ((char*) iPtr->linePBodyPtr); iPtr->linePBodyPtr = NULL; /* See also tclCompile.c, TclCleanupByteCode */ for (hPtr = Tcl_FirstHashEntry(iPtr->lineBCPtr, &hSearch); hPtr != NULL; hPtr = Tcl_NextHashEntry(&hSearch)) { eclPtr = (ExtCmdLoc*) Tcl_GetHashValue (hPtr); if (eclPtr->type == TCL_LOCATION_SOURCE) { Tcl_DecrRefCount (eclPtr->path); } for (i=0; i< eclPtr->nuloc; i++) { ckfree ((char*) eclPtr->loc[i].line); } if (eclPtr->loc != NULL) { ckfree ((char*) eclPtr->loc); } Tcl_DeleteHashTable (&eclPtr->litInfo); ckfree ((char*) eclPtr); Tcl_DeleteHashEntry (hPtr); } Tcl_DeleteHashTable (iPtr->lineBCPtr); ckfree((char*) iPtr->lineBCPtr); iPtr->lineBCPtr = NULL; /* * Location stack for uplevel/eval/... scripts which were passed * through proc arguments. Actually we track all arguments as we * don't, cannot know which arguments will be used as scripts and * which won't. */ if (iPtr->lineLAPtr->numEntries) { /* * When the interp goes away we have nothing on the stack, so * there are no arguments, so this table has to be empty. */ Tcl_Panic ("Argument location tracking table not empty"); } Tcl_DeleteHashTable (iPtr->lineLAPtr); ckfree((char*) iPtr->lineLAPtr); iPtr->lineLAPtr = NULL; if (iPtr->lineLABCPtr->numEntries) { /* * When the interp goes away we have nothing on the stack, so * there are no arguments, so this table has to be empty. */ Tcl_Panic ("Argument location tracking table not empty"); } Tcl_DeleteHashTable (iPtr->lineLABCPtr); ckfree((char*) iPtr->lineLABCPtr); iPtr->lineLABCPtr = NULL; } #endif ckfree((char *) iPtr); } /* *--------------------------------------------------------------------------- * * Tcl_HideCommand -- * * Makes a command hidden so that it cannot be invoked from within * an interpreter, only from within an ancestor. * * Results: * A standard Tcl result; also leaves a message in the interp's result * if an error occurs. * * Side effects: * Removes a command from the command table and create an entry * into the hidden command table under the specified token name. * *--------------------------------------------------------------------------- */ int Tcl_HideCommand(interp, cmdName, hiddenCmdToken) Tcl_Interp *interp; /* Interpreter in which to hide command. */ CONST char *cmdName; /* Name of command to hide. */ CONST char *hiddenCmdToken; /* Token name of the to-be-hidden command. */ { Interp *iPtr = (Interp *) interp; Tcl_Command cmd; Command *cmdPtr; Tcl_HashTable *hiddenCmdTablePtr; Tcl_HashEntry *hPtr; int new; if (iPtr->flags & DELETED) { /* * The interpreter is being deleted. Do not create any new * structures, because it is not safe to modify the interpreter. */ return TCL_ERROR; } /* * Disallow hiding of commands that are currently in a namespace or * renaming (as part of hiding) into a namespace. * * (because the current implementation with a single global table * and the needed uniqueness of names cause problems with namespaces) * * we don't need to check for "::" in cmdName because the real check is * on the nsPtr below. * * hiddenCmdToken is just a string which is not interpreted in any way. * It may contain :: but the string is not interpreted as a namespace * qualifier command name. Thus, hiding foo::bar to foo::bar and then * trying to expose or invoke ::foo::bar will NOT work; but if the * application always uses the same strings it will get consistent * behaviour. * * But as we currently limit ourselves to the global namespace only * for the source, in order to avoid potential confusion, * lets prevent "::" in the token too. --dl */ if (strstr(hiddenCmdToken, "::") != NULL) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "cannot use namespace qualifiers in hidden command", " token (rename)", (char *) NULL); return TCL_ERROR; } /* * Find the command to hide. An error is returned if cmdName can't * be found. Look up the command only from the global namespace. * Full path of the command must be given if using namespaces. */ cmd = Tcl_FindCommand(interp, cmdName, (Tcl_Namespace *) NULL, /*flags*/ TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY); if (cmd == (Tcl_Command) NULL) { return TCL_ERROR; } cmdPtr = (Command *) cmd; /* * Check that the command is really in global namespace */ if ( cmdPtr->nsPtr != iPtr->globalNsPtr ) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "can only hide global namespace commands", " (use rename then hide)", (char *) NULL); return TCL_ERROR; } /* * Initialize the hidden command table if necessary. */ hiddenCmdTablePtr = iPtr->hiddenCmdTablePtr; if (hiddenCmdTablePtr == NULL) { hiddenCmdTablePtr = (Tcl_HashTable *) ckalloc((unsigned) sizeof(Tcl_HashTable)); Tcl_InitHashTable(hiddenCmdTablePtr, TCL_STRING_KEYS); iPtr->hiddenCmdTablePtr = hiddenCmdTablePtr; } /* * It is an error to move an exposed command to a hidden command with * hiddenCmdToken if a hidden command with the name hiddenCmdToken already * exists. */ hPtr = Tcl_CreateHashEntry(hiddenCmdTablePtr, hiddenCmdToken, &new); if (!new) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "hidden command named \"", hiddenCmdToken, "\" already exists", (char *) NULL); return TCL_ERROR; } /* * Nb : This code is currently 'like' a rename to a specialy set apart * name table. Changes here and in TclRenameCommand must * be kept in synch untill the common parts are actually * factorized out. */ /* * Remove the hash entry for the command from the interpreter command * table. This is like deleting the command, so bump its command epoch; * this invalidates any cached references that point to the command. */ if (cmdPtr->hPtr != NULL) { Tcl_DeleteHashEntry(cmdPtr->hPtr); cmdPtr->hPtr = (Tcl_HashEntry *) NULL; cmdPtr->cmdEpoch++; } /* * Now link the hash table entry with the command structure. * We ensured above that the nsPtr was right. */ cmdPtr->hPtr = hPtr; Tcl_SetHashValue(hPtr, (ClientData) cmdPtr); /* * If the command being hidden has a compile procedure, increment the * interpreter's compileEpoch to invalidate its compiled code. This * makes sure that we don't later try to execute old code compiled with * command-specific (i.e., inline) bytecodes for the now-hidden * command. This field is checked in Tcl_EvalObj and ObjInterpProc, * and code whose compilation epoch doesn't match is recompiled. */ if (cmdPtr->compileProc != NULL) { iPtr->compileEpoch++; } return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_ExposeCommand -- * * Makes a previously hidden command callable from inside the * interpreter instead of only by its ancestors. * * Results: * A standard Tcl result. If an error occurs, a message is left * in the interp's result. * * Side effects: * Moves commands from one hash table to another. * *---------------------------------------------------------------------- */ int Tcl_ExposeCommand(interp, hiddenCmdToken, cmdName) Tcl_Interp *interp; /* Interpreter in which to make command * callable. */ CONST char *hiddenCmdToken; /* Name of hidden command. */ CONST char *cmdName; /* Name of to-be-exposed command. */ { Interp *iPtr = (Interp *) interp; Command *cmdPtr; Namespace *nsPtr; Tcl_HashEntry *hPtr; Tcl_HashTable *hiddenCmdTablePtr; int new; if (iPtr->flags & DELETED) { /* * The interpreter is being deleted. Do not create any new * structures, because it is not safe to modify the interpreter. */ return TCL_ERROR; } /* * Check that we have a regular name for the command * (that the user is not trying to do an expose and a rename * (to another namespace) at the same time) */ if (strstr(cmdName, "::") != NULL) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "can not expose to a namespace ", "(use expose to toplevel, then rename)", (char *) NULL); return TCL_ERROR; } /* * Get the command from the hidden command table: */ hPtr = NULL; hiddenCmdTablePtr = iPtr->hiddenCmdTablePtr; if (hiddenCmdTablePtr != NULL) { hPtr = Tcl_FindHashEntry(hiddenCmdTablePtr, hiddenCmdToken); } if (hPtr == (Tcl_HashEntry *) NULL) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "unknown hidden command \"", hiddenCmdToken, "\"", (char *) NULL); return TCL_ERROR; } cmdPtr = (Command *) Tcl_GetHashValue(hPtr); /* * Check that we have a true global namespace * command (enforced by Tcl_HideCommand() but let's double * check. (If it was not, we would not really know how to * handle it). */ if ( cmdPtr->nsPtr != iPtr->globalNsPtr ) { /* * This case is theoritically impossible, * we might rather panic() than 'nicely' erroring out ? */ Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "trying to expose a non global command name space command", (char *) NULL); return TCL_ERROR; } /* This is the global table */ nsPtr = cmdPtr->nsPtr; /* * It is an error to overwrite an existing exposed command as a result * of exposing a previously hidden command. */ hPtr = Tcl_CreateHashEntry(&nsPtr->cmdTable, cmdName, &new); if (!new) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "exposed command \"", cmdName, "\" already exists", (char *) NULL); return TCL_ERROR; } /* * Remove the hash entry for the command from the interpreter hidden * command table. */ if (cmdPtr->hPtr != NULL) { Tcl_DeleteHashEntry(cmdPtr->hPtr); cmdPtr->hPtr = NULL; } /* * Now link the hash table entry with the command structure. * This is like creating a new command, so deal with any shadowing * of commands in the global namespace. */ cmdPtr->hPtr = hPtr; Tcl_SetHashValue(hPtr, (ClientData) cmdPtr); /* * Not needed as we are only in the global namespace * (but would be needed again if we supported namespace command hiding) * * TclResetShadowedCmdRefs(interp, cmdPtr); */ /* * If the command being exposed has a compile procedure, increment * interpreter's compileEpoch to invalidate its compiled code. This * makes sure that we don't later try to execute old code compiled * assuming the command is hidden. This field is checked in Tcl_EvalObj * and ObjInterpProc, and code whose compilation epoch doesn't match is * recompiled. */ if (cmdPtr->compileProc != NULL) { iPtr->compileEpoch++; } return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_CreateCommand -- * * Define a new command in a command table. * * Results: * The return value is a token for the command, which can * be used in future calls to Tcl_GetCommandName. * * Side effects: * If a command named cmdName already exists for interp, it is deleted. * In the future, when cmdName is seen as the name of a command by * Tcl_Eval, proc will be called. To support the bytecode interpreter, * the command is created with a wrapper Tcl_ObjCmdProc * (TclInvokeStringCommand) that eventially calls proc. When the * command is deleted from the table, deleteProc will be called. * See the manual entry for details on the calling sequence. * *---------------------------------------------------------------------- */ Tcl_Command Tcl_CreateCommand(interp, cmdName, proc, clientData, deleteProc) Tcl_Interp *interp; /* Token for command interpreter returned by * a previous call to Tcl_CreateInterp. */ CONST char *cmdName; /* Name of command. If it contains namespace * qualifiers, the new command is put in the * specified namespace; otherwise it is put * in the global namespace. */ Tcl_CmdProc *proc; /* Procedure to associate with cmdName. */ ClientData clientData; /* Arbitrary value passed to string proc. */ Tcl_CmdDeleteProc *deleteProc; /* If not NULL, gives a procedure to call * when this command is deleted. */ { Interp *iPtr = (Interp *) interp; ImportRef *oldRefPtr = NULL; Namespace *nsPtr, *dummy1, *dummy2; Command *cmdPtr, *refCmdPtr; Tcl_HashEntry *hPtr; CONST char *tail; int new; ImportedCmdData *dataPtr; if (iPtr->flags & DELETED) { /* * The interpreter is being deleted. Don't create any new * commands; it's not safe to muck with the interpreter anymore. */ return (Tcl_Command) NULL; } /* * Determine where the command should reside. If its name contains * namespace qualifiers, we put it in the specified namespace; * otherwise, we always put it in the global namespace. */ if (strstr(cmdName, "::") != NULL) { TclGetNamespaceForQualName(interp, cmdName, (Namespace *) NULL, CREATE_NS_IF_UNKNOWN, &nsPtr, &dummy1, &dummy2, &tail); if ((nsPtr == NULL) || (tail == NULL)) { return (Tcl_Command) NULL; } } else { nsPtr = iPtr->globalNsPtr; tail = cmdName; } hPtr = Tcl_CreateHashEntry(&nsPtr->cmdTable, tail, &new); if (!new) { /* * Command already exists. Delete the old one. * Be careful to preserve any existing import links so we can * restore them down below. That way, you can redefine a * command and its import status will remain intact. */ cmdPtr = (Command *) Tcl_GetHashValue(hPtr); oldRefPtr = cmdPtr->importRefPtr; cmdPtr->importRefPtr = NULL; Tcl_DeleteCommandFromToken(interp, (Tcl_Command) cmdPtr); hPtr = Tcl_CreateHashEntry(&nsPtr->cmdTable, tail, &new); if (!new) { /* * If the deletion callback recreated the command, just throw * away the new command (if we try to delete it again, we * could get stuck in an infinite loop). */ ckfree((char*) Tcl_GetHashValue(hPtr)); } } cmdPtr = (Command *) ckalloc(sizeof(Command)); Tcl_SetHashValue(hPtr, cmdPtr); cmdPtr->hPtr = hPtr; cmdPtr->nsPtr = nsPtr; cmdPtr->refCount = 1; cmdPtr->cmdEpoch = 0; cmdPtr->compileProc = (CompileProc *) NULL; cmdPtr->objProc = TclInvokeStringCommand; cmdPtr->objClientData = (ClientData) cmdPtr; cmdPtr->proc = proc; cmdPtr->clientData = clientData; cmdPtr->deleteProc = deleteProc; cmdPtr->deleteData = clientData; cmdPtr->flags = 0; cmdPtr->importRefPtr = NULL; cmdPtr->tracePtr = NULL; /* * Plug in any existing import references found above. Be sure * to update all of these references to point to the new command. */ if (oldRefPtr != NULL) { cmdPtr->importRefPtr = oldRefPtr; while (oldRefPtr != NULL) { refCmdPtr = oldRefPtr->importedCmdPtr; dataPtr = (ImportedCmdData*)refCmdPtr->objClientData; dataPtr->realCmdPtr = cmdPtr; oldRefPtr = oldRefPtr->nextPtr; } } /* * We just created a command, so in its namespace and all of its parent * namespaces, it may shadow global commands with the same name. If any * shadowed commands are found, invalidate all cached command references * in the affected namespaces. */ TclResetShadowedCmdRefs(interp, cmdPtr); return (Tcl_Command) cmdPtr; } /* *---------------------------------------------------------------------- * * Tcl_CreateObjCommand -- * * Define a new object-based command in a command table. * * Results: * The return value is a token for the command, which can * be used in future calls to Tcl_GetCommandName. * * Side effects: * If no command named "cmdName" already exists for interp, one is * created. Otherwise, if a command does exist, then if the * object-based Tcl_ObjCmdProc is TclInvokeStringCommand, we assume * Tcl_CreateCommand was called previously for the same command and * just set its Tcl_ObjCmdProc to the argument "proc"; otherwise, we * delete the old command. * * In the future, during bytecode evaluation when "cmdName" is seen as * the name of a command by Tcl_EvalObj or Tcl_Eval, the object-based * Tcl_ObjCmdProc proc will be called. When the command is deleted from * the table, deleteProc will be called. See the manual entry for * details on the calling sequence. * *---------------------------------------------------------------------- */ Tcl_Command Tcl_CreateObjCommand(interp, cmdName, proc, clientData, deleteProc) Tcl_Interp *interp; /* Token for command interpreter (returned * by previous call to Tcl_CreateInterp). */ CONST char *cmdName; /* Name of command. If it contains namespace * qualifiers, the new command is put in the * specified namespace; otherwise it is put * in the global namespace. */ Tcl_ObjCmdProc *proc; /* Object-based procedure to associate with * name. */ ClientData clientData; /* Arbitrary value to pass to object * procedure. */ Tcl_CmdDeleteProc *deleteProc; /* If not NULL, gives a procedure to call * when this command is deleted. */ { Interp *iPtr = (Interp *) interp; ImportRef *oldRefPtr = NULL; Namespace *nsPtr, *dummy1, *dummy2; Command *cmdPtr, *refCmdPtr; Tcl_HashEntry *hPtr; CONST char *tail; int new; ImportedCmdData *dataPtr; if (iPtr->flags & DELETED) { /* * The interpreter is being deleted. Don't create any new * commands; it's not safe to muck with the interpreter anymore. */ return (Tcl_Command) NULL; } /* * Determine where the command should reside. If its name contains * namespace qualifiers, we put it in the specified namespace; * otherwise, we always put it in the global namespace. */ if (strstr(cmdName, "::") != NULL) { TclGetNamespaceForQualName(interp, cmdName, (Namespace *) NULL, CREATE_NS_IF_UNKNOWN, &nsPtr, &dummy1, &dummy2, &tail); if ((nsPtr == NULL) || (tail == NULL)) { return (Tcl_Command) NULL; } } else { nsPtr = iPtr->globalNsPtr; tail = cmdName; } hPtr = Tcl_CreateHashEntry(&nsPtr->cmdTable, tail, &new); if (!new) { cmdPtr = (Command *) Tcl_GetHashValue(hPtr); /* * Command already exists. If its object-based Tcl_ObjCmdProc is * TclInvokeStringCommand, we just set its Tcl_ObjCmdProc to the * argument "proc". Otherwise, we delete the old command. */ if (cmdPtr->objProc == TclInvokeStringCommand) { cmdPtr->objProc = proc; cmdPtr->objClientData = clientData; cmdPtr->deleteProc = deleteProc; cmdPtr->deleteData = clientData; return (Tcl_Command) cmdPtr; } /* * Otherwise, we delete the old command. Be careful to preserve * any existing import links so we can restore them down below. * That way, you can redefine a command and its import status * will remain intact. */ oldRefPtr = cmdPtr->importRefPtr; cmdPtr->importRefPtr = NULL; Tcl_DeleteCommandFromToken(interp, (Tcl_Command) cmdPtr); hPtr = Tcl_CreateHashEntry(&nsPtr->cmdTable, tail, &new); if (!new) { /* * If the deletion callback recreated the command, just throw * away the new command (if we try to delete it again, we * could get stuck in an infinite loop). */ ckfree((char *) Tcl_GetHashValue(hPtr)); } } cmdPtr = (Command *) ckalloc(sizeof(Command)); Tcl_SetHashValue(hPtr, cmdPtr); cmdPtr->hPtr = hPtr; cmdPtr->nsPtr = nsPtr; cmdPtr->refCount = 1; cmdPtr->cmdEpoch = 0; cmdPtr->compileProc = (CompileProc *) NULL; cmdPtr->objProc = proc; cmdPtr->objClientData = clientData; cmdPtr->proc = TclInvokeObjectCommand; cmdPtr->clientData = (ClientData) cmdPtr; cmdPtr->deleteProc = deleteProc; cmdPtr->deleteData = clientData; cmdPtr->flags = 0; cmdPtr->importRefPtr = NULL; cmdPtr->tracePtr = NULL; /* * Plug in any existing import references found above. Be sure * to update all of these references to point to the new command. */ if (oldRefPtr != NULL) { cmdPtr->importRefPtr = oldRefPtr; while (oldRefPtr != NULL) { refCmdPtr = oldRefPtr->importedCmdPtr; dataPtr = (ImportedCmdData*)refCmdPtr->objClientData; dataPtr->realCmdPtr = cmdPtr; oldRefPtr = oldRefPtr->nextPtr; } } /* * We just created a command, so in its namespace and all of its parent * namespaces, it may shadow global commands with the same name. If any * shadowed commands are found, invalidate all cached command references * in the affected namespaces. */ TclResetShadowedCmdRefs(interp, cmdPtr); return (Tcl_Command) cmdPtr; } /* *---------------------------------------------------------------------- * * TclInvokeStringCommand -- * * "Wrapper" Tcl_ObjCmdProc used to call an existing string-based * Tcl_CmdProc if no object-based procedure exists for a command. A * pointer to this procedure is stored as the Tcl_ObjCmdProc in a * Command structure. It simply turns around and calls the string * Tcl_CmdProc in the Command structure. * * Results: * A standard Tcl object result value. * * Side effects: * Besides those side effects of the called Tcl_CmdProc, * TclInvokeStringCommand allocates and frees storage. * *---------------------------------------------------------------------- */ int TclInvokeStringCommand(clientData, interp, objc, objv) ClientData clientData; /* Points to command's Command structure. */ Tcl_Interp *interp; /* Current interpreter. */ register int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { register Command *cmdPtr = (Command *) clientData; register int i; int result; /* * This procedure generates an argv array for the string arguments. It * starts out with stack-allocated space but uses dynamically-allocated * storage if needed. */ #define NUM_ARGS 20 CONST char *(argStorage[NUM_ARGS]); CONST char **argv = argStorage; /* * Create the string argument array "argv". Make sure argv is large * enough to hold the objc arguments plus 1 extra for the zero * end-of-argv word. */ if ((objc + 1) > NUM_ARGS) { argv = (CONST char **) ckalloc((unsigned)(objc + 1) * sizeof(char *)); } for (i = 0; i < objc; i++) { argv[i] = Tcl_GetString(objv[i]); } argv[objc] = 0; /* * Invoke the command's string-based Tcl_CmdProc. */ result = (*cmdPtr->proc)(cmdPtr->clientData, interp, objc, argv); /* * Free the argv array if malloc'ed storage was used. */ if (argv != argStorage) { ckfree((char *) argv); } return result; #undef NUM_ARGS } /* *---------------------------------------------------------------------- * * TclInvokeObjectCommand -- * * "Wrapper" Tcl_CmdProc used to call an existing object-based * Tcl_ObjCmdProc if no string-based procedure exists for a command. * A pointer to this procedure is stored as the Tcl_CmdProc in a * Command structure. It simply turns around and calls the object * Tcl_ObjCmdProc in the Command structure. * * Results: * A standard Tcl string result value. * * Side effects: * Besides those side effects of the called Tcl_CmdProc, * TclInvokeStringCommand allocates and frees storage. * *---------------------------------------------------------------------- */ int TclInvokeObjectCommand(clientData, interp, argc, argv) ClientData clientData; /* Points to command's Command structure. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ register CONST char **argv; /* Argument strings. */ { Command *cmdPtr = (Command *) clientData; register Tcl_Obj *objPtr; register int i; int length, result; /* * This procedure generates an objv array for object arguments that hold * the argv strings. It starts out with stack-allocated space but uses * dynamically-allocated storage if needed. */ #define NUM_ARGS 20 Tcl_Obj *(argStorage[NUM_ARGS]); register Tcl_Obj **objv = argStorage; /* * Create the object argument array "objv". Make sure objv is large * enough to hold the objc arguments plus 1 extra for the zero * end-of-objv word. */ if (argc > NUM_ARGS) { objv = (Tcl_Obj **) ckalloc((unsigned)(argc * sizeof(Tcl_Obj *))); } for (i = 0; i < argc; i++) { length = strlen(argv[i]); TclNewObj(objPtr); TclInitStringRep(objPtr, argv[i], length); Tcl_IncrRefCount(objPtr); objv[i] = objPtr; } /* * Invoke the command's object-based Tcl_ObjCmdProc. */ result = (*cmdPtr->objProc)(cmdPtr->objClientData, interp, argc, objv); /* * Move the interpreter's object result to the string result, * then reset the object result. */ Tcl_SetResult(interp, TclGetString(Tcl_GetObjResult(interp)), TCL_VOLATILE); /* * Decrement the ref counts for the argument objects created above, * then free the objv array if malloc'ed storage was used. */ for (i = 0; i < argc; i++) { objPtr = objv[i]; Tcl_DecrRefCount(objPtr); } if (objv != argStorage) { ckfree((char *) objv); } return result; #undef NUM_ARGS } /* *---------------------------------------------------------------------- * * TclRenameCommand -- * * Called to give an existing Tcl command a different name. Both the * old command name and the new command name can have "::" namespace * qualifiers. If the new command has a different namespace context, * the command will be moved to that namespace and will execute in * the context of that new namespace. * * If the new command name is NULL or the null string, the command is * deleted. * * Results: * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong. * * Side effects: * If anything goes wrong, an error message is returned in the * interpreter's result object. * *---------------------------------------------------------------------- */ int TclRenameCommand(interp, oldName, newName) Tcl_Interp *interp; /* Current interpreter. */ char *oldName; /* Existing command name. */ char *newName; /* New command name. */ { Interp *iPtr = (Interp *) interp; CONST char *newTail; Namespace *cmdNsPtr, *newNsPtr, *dummy1, *dummy2; Tcl_Command cmd; Command *cmdPtr; Tcl_HashEntry *hPtr, *oldHPtr; int new, result; Tcl_Obj* oldFullName; Tcl_DString newFullName; /* * Find the existing command. An error is returned if cmdName can't * be found. */ cmd = Tcl_FindCommand(interp, oldName, (Tcl_Namespace *) NULL, /*flags*/ 0); cmdPtr = (Command *) cmd; if (cmdPtr == NULL) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "can't ", ((newName == NULL)||(*newName == '\0'))? "delete":"rename", " \"", oldName, "\": command doesn't exist", (char *) NULL); return TCL_ERROR; } cmdNsPtr = cmdPtr->nsPtr; oldFullName = Tcl_NewObj(); Tcl_IncrRefCount( oldFullName ); Tcl_GetCommandFullName( interp, cmd, oldFullName ); /* * If the new command name is NULL or empty, delete the command. Do this * with Tcl_DeleteCommandFromToken, since we already have the command. */ if ((newName == NULL) || (*newName == '\0')) { Tcl_DeleteCommandFromToken(interp, cmd); result = TCL_OK; goto done; } /* * Make sure that the destination command does not already exist. * The rename operation is like creating a command, so we should * automatically create the containing namespaces just like * Tcl_CreateCommand would. */ TclGetNamespaceForQualName(interp, newName, (Namespace *) NULL, CREATE_NS_IF_UNKNOWN, &newNsPtr, &dummy1, &dummy2, &newTail); if ((newNsPtr == NULL) || (newTail == NULL)) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "can't rename to \"", newName, "\": bad command name", (char *) NULL); result = TCL_ERROR; goto done; } if (Tcl_FindHashEntry(&newNsPtr->cmdTable, newTail) != NULL) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "can't rename to \"", newName, "\": command already exists", (char *) NULL); result = TCL_ERROR; goto done; } /* * Warning: any changes done in the code here are likely * to be needed in Tcl_HideCommand() code too. * (until the common parts are extracted out) --dl */ /* * Put the command in the new namespace so we can check for an alias * loop. Since we are adding a new command to a namespace, we must * handle any shadowing of the global commands that this might create. */ oldHPtr = cmdPtr->hPtr; hPtr = Tcl_CreateHashEntry(&newNsPtr->cmdTable, newTail, &new); Tcl_SetHashValue(hPtr, (ClientData) cmdPtr); cmdPtr->hPtr = hPtr; cmdPtr->nsPtr = newNsPtr; TclResetShadowedCmdRefs(interp, cmdPtr); /* * Now check for an alias loop. If we detect one, put everything back * the way it was and report the error. */ result = TclPreventAliasLoop(interp, interp, (Tcl_Command) cmdPtr); if (result != TCL_OK) { Tcl_DeleteHashEntry(cmdPtr->hPtr); cmdPtr->hPtr = oldHPtr; cmdPtr->nsPtr = cmdNsPtr; goto done; } /* * Script for rename traces can delete the command "oldName". * Therefore increment the reference count for cmdPtr so that * it's Command structure is freed only towards the end of this * function by calling TclCleanupCommand. * * The trace procedure needs to get a fully qualified name for * old and new commands [Tcl bug #651271], or else there's no way * for the trace procedure to get the namespace from which the old * command is being renamed! */ Tcl_DStringInit( &newFullName ); Tcl_DStringAppend( &newFullName, newNsPtr->fullName, -1 ); if ( newNsPtr != iPtr->globalNsPtr ) { Tcl_DStringAppend( &newFullName, "::", 2 ); } Tcl_DStringAppend( &newFullName, newTail, -1 ); cmdPtr->refCount++; CallCommandTraces( iPtr, cmdPtr, Tcl_GetString( oldFullName ), Tcl_DStringValue( &newFullName ), TCL_TRACE_RENAME); Tcl_DStringFree( &newFullName ); /* * The new command name is okay, so remove the command from its * current namespace. This is like deleting the command, so bump * the cmdEpoch to invalidate any cached references to the command. */ Tcl_DeleteHashEntry(oldHPtr); cmdPtr->cmdEpoch++; /* * If the command being renamed has a compile procedure, increment the * interpreter's compileEpoch to invalidate its compiled code. This * makes sure that we don't later try to execute old code compiled for * the now-renamed command. */ if (cmdPtr->compileProc != NULL) { iPtr->compileEpoch++; } /* * Now free the Command structure, if the "oldName" command has * been deleted by invocation of rename traces. */ TclCleanupCommand(cmdPtr); result = TCL_OK; done: TclDecrRefCount( oldFullName ); return result; } /* *---------------------------------------------------------------------- * * Tcl_SetCommandInfo -- * * Modifies various information about a Tcl command. Note that * this procedure will not change a command's namespace; use * Tcl_RenameCommand to do that. Also, the isNativeObjectProc * member of *infoPtr is ignored. * * Results: * If cmdName exists in interp, then the information at *infoPtr * is stored with the command in place of the current information * and 1 is returned. If the command doesn't exist then 0 is * returned. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_SetCommandInfo(interp, cmdName, infoPtr) Tcl_Interp *interp; /* Interpreter in which to look * for command. */ CONST char *cmdName; /* Name of desired command. */ CONST Tcl_CmdInfo *infoPtr; /* Where to find information * to store in the command. */ { Tcl_Command cmd; cmd = Tcl_FindCommand(interp, cmdName, (Tcl_Namespace *) NULL, /*flags*/ 0); return Tcl_SetCommandInfoFromToken( cmd, infoPtr ); } /* *---------------------------------------------------------------------- * * Tcl_SetCommandInfoFromToken -- * * Modifies various information about a Tcl command. Note that * this procedure will not change a command's namespace; use * Tcl_RenameCommand to do that. Also, the isNativeObjectProc * member of *infoPtr is ignored. * * Results: * If cmdName exists in interp, then the information at *infoPtr * is stored with the command in place of the current information * and 1 is returned. If the command doesn't exist then 0 is * returned. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_SetCommandInfoFromToken( cmd, infoPtr ) Tcl_Command cmd; CONST Tcl_CmdInfo* infoPtr; { Command* cmdPtr; /* Internal representation of the command */ if (cmd == (Tcl_Command) NULL) { return 0; } /* * The isNativeObjectProc and nsPtr members of *infoPtr are ignored. */ cmdPtr = (Command *) cmd; cmdPtr->proc = infoPtr->proc; cmdPtr->clientData = infoPtr->clientData; if (infoPtr->objProc == (Tcl_ObjCmdProc *) NULL) { cmdPtr->objProc = TclInvokeStringCommand; cmdPtr->objClientData = (ClientData) cmdPtr; } else { cmdPtr->objProc = infoPtr->objProc; cmdPtr->objClientData = infoPtr->objClientData; } cmdPtr->deleteProc = infoPtr->deleteProc; cmdPtr->deleteData = infoPtr->deleteData; return 1; } /* *---------------------------------------------------------------------- * * Tcl_GetCommandInfo -- * * Returns various information about a Tcl command. * * Results: * If cmdName exists in interp, then *infoPtr is modified to * hold information about cmdName and 1 is returned. If the * command doesn't exist then 0 is returned and *infoPtr isn't * modified. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_GetCommandInfo(interp, cmdName, infoPtr) Tcl_Interp *interp; /* Interpreter in which to look * for command. */ CONST char *cmdName; /* Name of desired command. */ Tcl_CmdInfo *infoPtr; /* Where to store information about * command. */ { Tcl_Command cmd; cmd = Tcl_FindCommand(interp, cmdName, (Tcl_Namespace *) NULL, /*flags*/ 0); return Tcl_GetCommandInfoFromToken( cmd, infoPtr ); } /* *---------------------------------------------------------------------- * * Tcl_GetCommandInfoFromToken -- * * Returns various information about a Tcl command. * * Results: * Copies information from the command identified by 'cmd' into * a caller-supplied structure and returns 1. If the 'cmd' is * NULL, leaves the structure untouched and returns 0. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_GetCommandInfoFromToken( cmd, infoPtr ) Tcl_Command cmd; Tcl_CmdInfo* infoPtr; { Command* cmdPtr; /* Internal representation of the command */ if ( cmd == (Tcl_Command) NULL ) { return 0; } /* * Set isNativeObjectProc 1 if objProc was registered by a call to * Tcl_CreateObjCommand. Otherwise set it to 0. */ cmdPtr = (Command *) cmd; infoPtr->isNativeObjectProc = (cmdPtr->objProc != TclInvokeStringCommand); infoPtr->objProc = cmdPtr->objProc; infoPtr->objClientData = cmdPtr->objClientData; infoPtr->proc = cmdPtr->proc; infoPtr->clientData = cmdPtr->clientData; infoPtr->deleteProc = cmdPtr->deleteProc; infoPtr->deleteData = cmdPtr->deleteData; infoPtr->namespacePtr = (Tcl_Namespace *) cmdPtr->nsPtr; return 1; } /* *---------------------------------------------------------------------- * * Tcl_GetCommandName -- * * Given a token returned by Tcl_CreateCommand, this procedure * returns the current name of the command (which may have changed * due to renaming). * * Results: * The return value is the name of the given command. * * Side effects: * None. * *---------------------------------------------------------------------- */ CONST char * Tcl_GetCommandName(interp, command) Tcl_Interp *interp; /* Interpreter containing the command. */ Tcl_Command command; /* Token for command returned by a previous * call to Tcl_CreateCommand. The command * must not have been deleted. */ { Command *cmdPtr = (Command *) command; if ((cmdPtr == NULL) || (cmdPtr->hPtr == NULL)) { /* * This should only happen if command was "created" after the * interpreter began to be deleted, so there isn't really any * command. Just return an empty string. */ return ""; } return Tcl_GetHashKey(cmdPtr->hPtr->tablePtr, cmdPtr->hPtr); } /* *---------------------------------------------------------------------- * * Tcl_GetCommandFullName -- * * Given a token returned by, e.g., Tcl_CreateCommand or * Tcl_FindCommand, this procedure appends to an object the command's * full name, qualified by a sequence of parent namespace names. The * command's fully-qualified name may have changed due to renaming. * * Results: * None. * * Side effects: * The command's fully-qualified name is appended to the string * representation of objPtr. * *---------------------------------------------------------------------- */ void Tcl_GetCommandFullName(interp, command, objPtr) Tcl_Interp *interp; /* Interpreter containing the command. */ Tcl_Command command; /* Token for command returned by a previous * call to Tcl_CreateCommand. The command * must not have been deleted. */ Tcl_Obj *objPtr; /* Points to the object onto which the * command's full name is appended. */ { Interp *iPtr = (Interp *) interp; register Command *cmdPtr = (Command *) command; char *name; /* * Add the full name of the containing namespace, followed by the "::" * separator, and the command name. */ if (cmdPtr != NULL) { if (cmdPtr->nsPtr != NULL) { Tcl_AppendToObj(objPtr, cmdPtr->nsPtr->fullName, -1); if (cmdPtr->nsPtr != iPtr->globalNsPtr) { Tcl_AppendToObj(objPtr, "::", 2); } } if (cmdPtr->hPtr != NULL) { name = Tcl_GetHashKey(cmdPtr->hPtr->tablePtr, cmdPtr->hPtr); Tcl_AppendToObj(objPtr, name, -1); } } } /* *---------------------------------------------------------------------- * * Tcl_DeleteCommand -- * * Remove the given command from the given interpreter. * * Results: * 0 is returned if the command was deleted successfully. * -1 is returned if there didn't exist a command by that name. * * Side effects: * cmdName will no longer be recognized as a valid command for * interp. * *---------------------------------------------------------------------- */ int Tcl_DeleteCommand(interp, cmdName) Tcl_Interp *interp; /* Token for command interpreter (returned * by a previous Tcl_CreateInterp call). */ CONST char *cmdName; /* Name of command to remove. */ { Tcl_Command cmd; /* * Find the desired command and delete it. */ cmd = Tcl_FindCommand(interp, cmdName, (Tcl_Namespace *) NULL, /*flags*/ 0); if (cmd == (Tcl_Command) NULL) { return -1; } return Tcl_DeleteCommandFromToken(interp, cmd); } /* *---------------------------------------------------------------------- * * Tcl_DeleteCommandFromToken -- * * Removes the given command from the given interpreter. This procedure * resembles Tcl_DeleteCommand, but takes a Tcl_Command token instead * of a command name for efficiency. * * Results: * 0 is returned if the command was deleted successfully. * -1 is returned if there didn't exist a command by that name. * * Side effects: * The command specified by "cmd" will no longer be recognized as a * valid command for "interp". * *---------------------------------------------------------------------- */ int Tcl_DeleteCommandFromToken(interp, cmd) Tcl_Interp *interp; /* Token for command interpreter returned by * a previous call to Tcl_CreateInterp. */ Tcl_Command cmd; /* Token for command to delete. */ { Interp *iPtr = (Interp *) interp; Command *cmdPtr = (Command *) cmd; ImportRef *refPtr, *nextRefPtr; Tcl_Command importCmd; /* * The code here is tricky. We can't delete the hash table entry * before invoking the deletion callback because there are cases * where the deletion callback needs to invoke the command (e.g. * object systems such as OTcl). However, this means that the * callback could try to delete or rename the command. The deleted * flag allows us to detect these cases and skip nested deletes. */ if (cmdPtr->flags & CMD_IS_DELETED) { /* * Another deletion is already in progress. Remove the hash * table entry now, but don't invoke a callback or free the * command structure. */ Tcl_DeleteHashEntry(cmdPtr->hPtr); cmdPtr->hPtr = NULL; return 0; } /* * We must delete this command, even though both traces and * delete procs may try to avoid this (renaming the command etc). * Also traces and delete procs may try to delete the command * themsevles. This flag declares that a delete is in progress * and that recursive deletes should be ignored. */ cmdPtr->flags |= CMD_IS_DELETED; /* * Bump the command epoch counter. This will invalidate all cached * references that point to this command. */ cmdPtr->cmdEpoch++; /* * Call trace procedures for the command being deleted. Then delete * its traces. */ if (cmdPtr->tracePtr != NULL) { CommandTrace *tracePtr; CallCommandTraces(iPtr,cmdPtr,NULL,NULL,TCL_TRACE_DELETE); /* Now delete these traces */ tracePtr = cmdPtr->tracePtr; while (tracePtr != NULL) { CommandTrace *nextPtr = tracePtr->nextPtr; if ((--tracePtr->refCount) <= 0) { ckfree((char*)tracePtr); } tracePtr = nextPtr; } cmdPtr->tracePtr = NULL; } /* * If the command being deleted has a compile procedure, increment the * interpreter's compileEpoch to invalidate its compiled code. This * makes sure that we don't later try to execute old code compiled with * command-specific (i.e., inline) bytecodes for the now-deleted * command. This field is checked in Tcl_EvalObj and ObjInterpProc, and * code whose compilation epoch doesn't match is recompiled. */ if (cmdPtr->compileProc != NULL) { iPtr->compileEpoch++; } if (cmdPtr->deleteProc != NULL) { /* * Delete the command's client data. If this was an imported command * created when a command was imported into a namespace, this client * data will be a pointer to a ImportedCmdData structure describing * the "real" command that this imported command refers to. */ /* * If you are getting a crash during the call to deleteProc and * cmdPtr->deleteProc is a pointer to the function free(), the * most likely cause is that your extension allocated memory * for the clientData argument to Tcl_CreateObjCommand() with * the ckalloc() macro and you are now trying to deallocate * this memory with free() instead of ckfree(). You should * pass a pointer to your own method that calls ckfree(). */ (*cmdPtr->deleteProc)(cmdPtr->deleteData); } /* * If this command was imported into other namespaces, then imported * commands were created that refer back to this command. Delete these * imported commands now. */ for (refPtr = cmdPtr->importRefPtr; refPtr != NULL; refPtr = nextRefPtr) { nextRefPtr = refPtr->nextPtr; importCmd = (Tcl_Command) refPtr->importedCmdPtr; Tcl_DeleteCommandFromToken(interp, importCmd); } /* * Don't use hPtr to delete the hash entry here, because it's * possible that the deletion callback renamed the command. * Instead, use cmdPtr->hptr, and make sure that no-one else * has already deleted the hash entry. */ if (cmdPtr->hPtr != NULL) { Tcl_DeleteHashEntry(cmdPtr->hPtr); } /* * Mark the Command structure as no longer valid. This allows * TclExecuteByteCode to recognize when a Command has logically been * deleted and a pointer to this Command structure cached in a CmdName * object is invalid. TclExecuteByteCode will look up the command again * in the interpreter's command hashtable. */ cmdPtr->objProc = NULL; /* * Now free the Command structure, unless there is another reference to * it from a CmdName Tcl object in some ByteCode code sequence. In that * case, delay the cleanup until all references are either discarded * (when a ByteCode is freed) or replaced by a new reference (when a * cached CmdName Command reference is found to be invalid and * TclExecuteByteCode looks up the command in the command hashtable). */ TclCleanupCommand(cmdPtr); return 0; } static char * CallCommandTraces(iPtr, cmdPtr, oldName, newName, flags) Interp *iPtr; /* Interpreter containing command. */ Command *cmdPtr; /* Command whose traces are to be * invoked. */ CONST char *oldName; /* Command's old name, or NULL if we * must get the name from cmdPtr */ CONST char *newName; /* Command's new name, or NULL if * the command is not being renamed */ int flags; /* Flags indicating the type of traces * to trigger, either TCL_TRACE_DELETE * or TCL_TRACE_RENAME. */ { register CommandTrace *tracePtr; ActiveCommandTrace active; char *result; Tcl_Obj *oldNamePtr = NULL; int mask = (TCL_TRACE_DELETE | TCL_TRACE_RENAME); /* Safety */ flags &= mask; if (cmdPtr->flags & CMD_TRACE_ACTIVE) { /* * While a rename trace is active, we will not process any more * rename traces; while a delete trace is active we will never * reach here -- because Tcl_DeleteCommandFromToken checks for the * condition (cmdPtr->flags & CMD_IS_DELETED) and returns immediately * when a command deletion is in progress. For all other traces, * delete traces will not be invoked but a call to TraceCommandProc * will ensure that tracePtr->clientData is freed whenever the * command "oldName" is deleted. */ if (cmdPtr->flags & TCL_TRACE_RENAME) { flags &= ~TCL_TRACE_RENAME; } if (flags == 0) { return NULL; } } cmdPtr->flags |= CMD_TRACE_ACTIVE; cmdPtr->refCount++; result = NULL; active.nextPtr = iPtr->activeCmdTracePtr; active.reverseScan = 0; iPtr->activeCmdTracePtr = &active; if (flags & TCL_TRACE_DELETE) { flags |= TCL_TRACE_DESTROYED; } active.cmdPtr = cmdPtr; Tcl_Preserve((ClientData) iPtr); for (tracePtr = cmdPtr->tracePtr; tracePtr != NULL; tracePtr = active.nextTracePtr) { int traceFlags = (tracePtr->flags & mask); active.nextTracePtr = tracePtr->nextPtr; if (!(traceFlags & flags)) { continue; } cmdPtr->flags |= traceFlags; if (oldName == NULL) { TclNewObj(oldNamePtr); Tcl_IncrRefCount(oldNamePtr); Tcl_GetCommandFullName((Tcl_Interp *) iPtr, (Tcl_Command) cmdPtr, oldNamePtr); oldName = TclGetString(oldNamePtr); } tracePtr->refCount++; (*tracePtr->traceProc)(tracePtr->clientData, (Tcl_Interp *) iPtr, oldName, newName, flags); cmdPtr->flags &= ~traceFlags; if ((--tracePtr->refCount) <= 0) { ckfree((char*)tracePtr); } } /* * If a new object was created to hold the full oldName, * free it now. */ if (oldNamePtr != NULL) { TclDecrRefCount(oldNamePtr); } /* * Restore the variable's flags, remove the record of our active * traces, and then return. */ cmdPtr->flags &= ~CMD_TRACE_ACTIVE; cmdPtr->refCount--; iPtr->activeCmdTracePtr = active.nextPtr; Tcl_Release((ClientData) iPtr); return result; } /* *---------------------------------------------------------------------- * * TclCleanupCommand -- * * This procedure frees up a Command structure unless it is still * referenced from an interpreter's command hashtable or from a CmdName * Tcl object representing the name of a command in a ByteCode * instruction sequence. * * Results: * None. * * Side effects: * Memory gets freed unless a reference to the Command structure still * exists. In that case the cleanup is delayed until the command is * deleted or when the last ByteCode referring to it is freed. * *---------------------------------------------------------------------- */ void TclCleanupCommand(cmdPtr) register Command *cmdPtr; /* Points to the Command structure to * be freed. */ { cmdPtr->refCount--; if (cmdPtr->refCount <= 0) { ckfree((char *) cmdPtr); } } /* *---------------------------------------------------------------------- * * Tcl_CreateMathFunc -- * * Creates a new math function for expressions in a given * interpreter. * * Results: * None. * * Side effects: * The function defined by "name" is created or redefined. If the * function already exists then its definition is replaced; this * includes the builtin functions. Redefining a builtin function forces * all existing code to be invalidated since that code may be compiled * using an instruction specific to the replaced function. In addition, * redefioning a non-builtin function will force existing code to be * invalidated if the number of arguments has changed. * *---------------------------------------------------------------------- */ void Tcl_CreateMathFunc(interp, name, numArgs, argTypes, proc, clientData) Tcl_Interp *interp; /* Interpreter in which function is * to be available. */ CONST char *name; /* Name of function (e.g. "sin"). */ int numArgs; /* Nnumber of arguments required by * function. */ Tcl_ValueType *argTypes; /* Array of types acceptable for * each argument. */ Tcl_MathProc *proc; /* Procedure that implements the * math function. */ ClientData clientData; /* Additional value to pass to the * function. */ { Interp *iPtr = (Interp *) interp; Tcl_HashEntry *hPtr; MathFunc *mathFuncPtr; int new, i; hPtr = Tcl_CreateHashEntry(&iPtr->mathFuncTable, name, &new); if (new) { Tcl_SetHashValue(hPtr, ckalloc(sizeof(MathFunc))); } mathFuncPtr = (MathFunc *) Tcl_GetHashValue(hPtr); if (!new) { if (mathFuncPtr->builtinFuncIndex >= 0) { /* * We are redefining a builtin math function. Invalidate the * interpreter's existing code by incrementing its * compileEpoch member. This field is checked in Tcl_EvalObj * and ObjInterpProc, and code whose compilation epoch doesn't * match is recompiled. Newly compiled code will no longer * treat the function as builtin. */ iPtr->compileEpoch++; } else { /* * A non-builtin function is being redefined. We must invalidate * existing code if the number of arguments has changed. This * is because existing code was compiled assuming that number. */ if (numArgs != mathFuncPtr->numArgs) { iPtr->compileEpoch++; } } } mathFuncPtr->builtinFuncIndex = -1; /* can't be a builtin function */ if (numArgs > MAX_MATH_ARGS) { numArgs = MAX_MATH_ARGS; } mathFuncPtr->numArgs = numArgs; for (i = 0; i < numArgs; i++) { mathFuncPtr->argTypes[i] = argTypes[i]; } mathFuncPtr->proc = proc; mathFuncPtr->clientData = clientData; } /* *---------------------------------------------------------------------- * * Tcl_GetMathFuncInfo -- * * Discovers how a particular math function was created in a given * interpreter. * * Results: * TCL_OK if it succeeds, TCL_ERROR else (leaving an error message * in the interpreter result if that happens.) * * Side effects: * If this function succeeds, the variables pointed to by the * numArgsPtr and argTypePtr arguments will be updated to detail the * arguments allowed by the function. The variable pointed to by the * procPtr argument will be set to NULL if the function is a builtin * function, and will be set to the address of the C function used to * implement the math function otherwise (in which case the variable * pointed to by the clientDataPtr argument will also be updated.) * *---------------------------------------------------------------------- */ int Tcl_GetMathFuncInfo(interp, name, numArgsPtr, argTypesPtr, procPtr, clientDataPtr) Tcl_Interp *interp; CONST char *name; int *numArgsPtr; Tcl_ValueType **argTypesPtr; Tcl_MathProc **procPtr; ClientData *clientDataPtr; { Interp *iPtr = (Interp *) interp; Tcl_HashEntry *hPtr; MathFunc *mathFuncPtr; Tcl_ValueType *argTypes; int i,numArgs; hPtr = Tcl_FindHashEntry(&iPtr->mathFuncTable, name); if (hPtr == NULL) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "math function \"", name, "\" not known in this interpreter", (char *) NULL); return TCL_ERROR; } mathFuncPtr = (MathFunc *) Tcl_GetHashValue(hPtr); *numArgsPtr = numArgs = mathFuncPtr->numArgs; if (numArgs == 0) { /* Avoid doing zero-sized allocs... */ numArgs = 1; } *argTypesPtr = argTypes = (Tcl_ValueType *)ckalloc(numArgs * sizeof(Tcl_ValueType)); for (i = 0; i < mathFuncPtr->numArgs; i++) { argTypes[i] = mathFuncPtr->argTypes[i]; } if (mathFuncPtr->builtinFuncIndex == -1) { *procPtr = (Tcl_MathProc *) NULL; } else { *procPtr = mathFuncPtr->proc; *clientDataPtr = mathFuncPtr->clientData; } return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_ListMathFuncs -- * * Produces a list of all the math functions defined in a given * interpreter. * * Results: * A pointer to a Tcl_Obj structure with a reference count of zero, * or NULL in the case of an error (in which case a suitable error * message will be left in the interpreter result.) * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_Obj * Tcl_ListMathFuncs(interp, pattern) Tcl_Interp *interp; CONST char *pattern; { Interp *iPtr = (Interp *) interp; Tcl_Obj *resultList = Tcl_NewObj(); register Tcl_HashEntry *hPtr; Tcl_HashSearch hSearch; CONST char *name; for (hPtr = Tcl_FirstHashEntry(&iPtr->mathFuncTable, &hSearch); hPtr != NULL; hPtr = Tcl_NextHashEntry(&hSearch)) { name = Tcl_GetHashKey(&iPtr->mathFuncTable, hPtr); if ((pattern == NULL || Tcl_StringMatch(name, pattern)) && /* I don't expect this to fail, but... */ Tcl_ListObjAppendElement(interp, resultList, Tcl_NewStringObj(name,-1)) != TCL_OK) { Tcl_DecrRefCount(resultList); return NULL; } } return resultList; } /* *---------------------------------------------------------------------- * * TclInterpReady -- * * Check if an interpreter is ready to eval commands or scripts, * i.e., if it was not deleted and if the nesting level is not * too high. * * Results: * The return value is TCL_OK if it the interpreter is ready, * TCL_ERROR otherwise. * * Side effects: * The interpreters object and string results are cleared. * *---------------------------------------------------------------------- */ int TclInterpReady(interp) Tcl_Interp *interp; { register Interp *iPtr = (Interp *) interp; /* * Reset both the interpreter's string and object results and clear * out any previous error information. */ Tcl_ResetResult(interp); /* * If the interpreter has been deleted, return an error. */ if (iPtr->flags & DELETED) { Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "attempt to call eval in deleted interpreter", -1); Tcl_SetErrorCode(interp, "CORE", "IDELETE", "attempt to call eval in deleted interpreter", (char *) NULL); return TCL_ERROR; } /* * Check depth of nested calls to Tcl_Eval: if this gets too large, * it's probably because of an infinite loop somewhere. */ if (((iPtr->numLevels) > iPtr->maxNestingDepth) || (TclpCheckStackSpace() == 0)) { Tcl_AppendToObj(Tcl_GetObjResult(interp), "too many nested evaluations (infinite loop?)", -1); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * TclEvalObjvInternal -- * * This procedure evaluates a Tcl command that has already been * parsed into words, with one Tcl_Obj holding each word. The caller * is responsible for managing the iPtr->numLevels. * * Results: * The return value is a standard Tcl completion code such as * TCL_OK or TCL_ERROR. A result or error message is left in * interp's result. If an error occurs, this procedure does * NOT add any information to the errorInfo variable. * * Side effects: * Depends on the command. * *---------------------------------------------------------------------- */ int TclEvalObjvInternal(interp, objc, objv, command, length, flags) Tcl_Interp *interp; /* Interpreter in which to evaluate the * command. Also used for error * reporting. */ int objc; /* Number of words in command. */ Tcl_Obj *CONST objv[]; /* An array of pointers to objects that are * the words that make up the command. */ CONST char *command; /* Points to the beginning of the string * representation of the command; this * is used for traces. If the string * representation of the command is * unknown, an empty string should be * supplied. If it is NULL, no traces will * be called. */ int length; /* Number of bytes in command; if -1, all * characters up to the first null byte are * used. */ int flags; /* Collection of OR-ed bits that control * the evaluation of the script. Only * TCL_EVAL_GLOBAL and TCL_EVAL_INVOKE are * currently supported. */ { Command *cmdPtr; Interp *iPtr = (Interp *) interp; Tcl_Obj **newObjv; int i; CallFrame *savedVarFramePtr; /* Saves old copy of iPtr->varFramePtr * in case TCL_EVAL_GLOBAL was set. */ int code = TCL_OK; int traceCode = TCL_OK; int checkTraces = 1; Namespace *savedNsPtr = NULL; if (TclInterpReady(interp) == TCL_ERROR) { return TCL_ERROR; } if (objc == 0) { return TCL_OK; } /* * If any execution traces rename or delete the current command, * we may need (at most) two passes here. */ savedVarFramePtr = iPtr->varFramePtr; while (1) { /* Configure evaluation context to match the requested flags */ if (flags & TCL_EVAL_GLOBAL) { iPtr->varFramePtr = NULL; } else if ((flags & TCL_EVAL_INVOKE) && iPtr->varFramePtr) { savedNsPtr = iPtr->varFramePtr->nsPtr; iPtr->varFramePtr->nsPtr = iPtr->globalNsPtr; } /* * Find the procedure to execute this command. If there isn't one, * then see if there is a command "unknown". If so, create a new * word array with "unknown" as the first word and the original * command words as arguments. Then call ourselves recursively * to execute it. */ cmdPtr = (Command *) Tcl_GetCommandFromObj(interp, objv[0]); if (cmdPtr == NULL) { newObjv = (Tcl_Obj **) ckalloc((unsigned) ((objc + 1) * sizeof (Tcl_Obj *))); for (i = objc-1; i >= 0; i--) { newObjv[i+1] = objv[i]; } newObjv[0] = Tcl_NewStringObj("::unknown", -1); Tcl_IncrRefCount(newObjv[0]); cmdPtr = (Command *) Tcl_GetCommandFromObj(interp, newObjv[0]); if (cmdPtr == NULL) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "invalid command name \"", Tcl_GetString(objv[0]), "\"", (char *) NULL); code = TCL_ERROR; } else { iPtr->numLevels++; code = TclEvalObjvInternal(interp, objc+1, newObjv, command, length, 0); iPtr->numLevels--; } Tcl_DecrRefCount(newObjv[0]); ckfree((char *) newObjv); if (savedNsPtr) { iPtr->varFramePtr->nsPtr = savedNsPtr; } goto done; } if (savedNsPtr) { iPtr->varFramePtr->nsPtr = savedNsPtr; } /* * Call trace procedures if needed. */ if ((checkTraces) && (command != NULL)) { int cmdEpoch = cmdPtr->cmdEpoch; int newEpoch; cmdPtr->refCount++; /* * If the first set of traces modifies/deletes the command or * any existing traces, then the set checkTraces to 0 and * go through this while loop one more time. */ if (iPtr->tracePtr != NULL && traceCode == TCL_OK) { traceCode = TclCheckInterpTraces(interp, command, length, cmdPtr, code, TCL_TRACE_ENTER_EXEC, objc, objv); } if ((cmdPtr->flags & CMD_HAS_EXEC_TRACES) && (traceCode == TCL_OK)) { traceCode = TclCheckExecutionTraces(interp, command, length, cmdPtr, code, TCL_TRACE_ENTER_EXEC, objc, objv); } newEpoch = cmdPtr->cmdEpoch; TclCleanupCommand(cmdPtr); if (cmdEpoch != newEpoch) { /* The command has been modified in some way */ checkTraces = 0; continue; } } break; } #ifdef USE_DTRACE if (TCL_DTRACE_CMD_ARGS_ENABLED()) { char *a[10]; int i = 0; while (i < 10) { a[i] = i < objc ? TclGetString(objv[i]) : NULL; i++; } TCL_DTRACE_CMD_ARGS(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9]); } #endif /* USE_DTRACE */ /* * Finally, invoke the command's Tcl_ObjCmdProc. */ cmdPtr->refCount++; iPtr->cmdCount++; if ( code == TCL_OK && traceCode == TCL_OK) { if (TCL_DTRACE_CMD_ENTRY_ENABLED()) { TCL_DTRACE_CMD_ENTRY(TclGetString(objv[0]), objc - 1, (Tcl_Obj **)(objv + 1)); } code = (*cmdPtr->objProc)(cmdPtr->objClientData, interp, objc, objv); if (TCL_DTRACE_CMD_RETURN_ENABLED()) { TCL_DTRACE_CMD_RETURN(TclGetString(objv[0]), code); } } if (Tcl_AsyncReady()) { code = Tcl_AsyncInvoke(interp, code); } /* * Call 'leave' command traces */ if (!(cmdPtr->flags & CMD_IS_DELETED)) { int saveErrFlags = iPtr->flags & (ERR_IN_PROGRESS | ERR_ALREADY_LOGGED | ERROR_CODE_SET); if ((cmdPtr->flags & CMD_HAS_EXEC_TRACES) && (traceCode == TCL_OK)) { traceCode = TclCheckExecutionTraces (interp, command, length, cmdPtr, code, TCL_TRACE_LEAVE_EXEC, objc, objv); } if (iPtr->tracePtr != NULL && traceCode == TCL_OK) { traceCode = TclCheckInterpTraces(interp, command, length, cmdPtr, code, TCL_TRACE_LEAVE_EXEC, objc, objv); } if (traceCode == TCL_OK) { iPtr->flags |= saveErrFlags; } } TclCleanupCommand(cmdPtr); /* * If one of the trace invocation resulted in error, then * change the result code accordingly. Note, that the * interp->result should already be set correctly by the * call to TraceExecutionProc. */ if (traceCode != TCL_OK) { code = traceCode; } /* * If the interpreter has a non-empty string result, the result * object is either empty or stale because some procedure set * interp->result directly. If so, move the string result to the * result object, then reset the string result. */ if (*(iPtr->result) != 0) { (void) Tcl_GetObjResult(interp); } #ifdef USE_DTRACE if (TCL_DTRACE_CMD_RESULT_ENABLED()) { Tcl_Obj *r; r = Tcl_GetObjResult(interp); TCL_DTRACE_CMD_RESULT(TclGetString(objv[0]), code, TclGetString(r), r); } #endif /* USE_DTRACE */ done: iPtr->varFramePtr = savedVarFramePtr; return code; } /* *---------------------------------------------------------------------- * * Tcl_EvalObjv -- * * This procedure evaluates a Tcl command that has already been * parsed into words, with one Tcl_Obj holding each word. * * Results: * The return value is a standard Tcl completion code such as * TCL_OK or TCL_ERROR. A result or error message is left in * interp's result. * * Side effects: * Depends on the command. * *---------------------------------------------------------------------- */ int Tcl_EvalObjv(interp, objc, objv, flags) Tcl_Interp *interp; /* Interpreter in which to evaluate the * command. Also used for error * reporting. */ int objc; /* Number of words in command. */ Tcl_Obj *CONST objv[]; /* An array of pointers to objects that are * the words that make up the command. */ int flags; /* Collection of OR-ed bits that control * the evaluation of the script. Only * TCL_EVAL_GLOBAL and TCL_EVAL_INVOKE * are currently supported. */ { Interp *iPtr = (Interp *)interp; Trace *tracePtr; Tcl_DString cmdBuf; char *cmdString = ""; /* A command string is only necessary for * command traces or error logs; it will be * generated to replace this default value if * necessary. */ int cmdLen = 0; /* a non-zero value indicates that a command * string was generated. */ int code = TCL_OK; int i; int allowExceptions = (iPtr->evalFlags & TCL_ALLOW_EXCEPTIONS); for (tracePtr = iPtr->tracePtr; tracePtr; tracePtr = tracePtr->nextPtr) { if ((tracePtr->level == 0) || (iPtr->numLevels <= tracePtr->level)) { /* * The command may be needed for an execution trace. Generate a * command string. */ Tcl_DStringInit(&cmdBuf); for (i = 0; i < objc; i++) { Tcl_DStringAppendElement(&cmdBuf, Tcl_GetString(objv[i])); } cmdString = Tcl_DStringValue(&cmdBuf); cmdLen = Tcl_DStringLength(&cmdBuf); break; } } iPtr->numLevels++; code = TclEvalObjvInternal(interp, objc, objv, cmdString, cmdLen, flags); iPtr->numLevels--; /* * If we are again at the top level, process any unusual * return code returned by the evaluated code. */ if (iPtr->numLevels == 0) { if (code == TCL_RETURN) { code = TclUpdateReturnInfo(iPtr); } if ((code != TCL_OK) && (code != TCL_ERROR) && !allowExceptions) { ProcessUnexpectedResult(interp, code); code = TCL_ERROR; } } if ((code == TCL_ERROR) && !(flags & TCL_EVAL_INVOKE)) { /* * If there was an error, a command string will be needed for the * error log: generate it now if it was not done previously. */ if (cmdLen == 0) { Tcl_DStringInit(&cmdBuf); for (i = 0; i < objc; i++) { Tcl_DStringAppendElement(&cmdBuf, Tcl_GetString(objv[i])); } cmdString = Tcl_DStringValue(&cmdBuf); cmdLen = Tcl_DStringLength(&cmdBuf); } Tcl_LogCommandInfo(interp, cmdString, cmdString, cmdLen); } if (cmdLen != 0) { Tcl_DStringFree(&cmdBuf); } return code; } /* *---------------------------------------------------------------------- * * Tcl_LogCommandInfo -- * * This procedure is invoked after an error occurs in an interpreter. * It adds information to the "errorInfo" variable to describe the * command that was being executed when the error occurred. * * Results: * None. * * Side effects: * Information about the command is added to errorInfo and the * line number stored internally in the interpreter is set. If this * is the first call to this procedure or Tcl_AddObjErrorInfo since * an error occurred, then old information in errorInfo is * deleted. * *---------------------------------------------------------------------- */ void Tcl_LogCommandInfo(interp, script, command, length) Tcl_Interp *interp; /* Interpreter in which to log information. */ CONST char *script; /* First character in script containing * command (must be <= command). */ CONST char *command; /* First character in command that * generated the error. */ int length; /* Number of bytes in command (-1 means * use all bytes up to first null byte). */ { char buffer[200]; register CONST char *p; char *ellipsis = ""; Interp *iPtr = (Interp *) interp; if (iPtr->flags & ERR_ALREADY_LOGGED) { /* * Someone else has already logged error information for this * command; we shouldn't add anything more. */ return; } /* * Compute the line number where the error occurred. */ iPtr->errorLine = 1; for (p = script; p != command; p++) { if (*p == '\n') { iPtr->errorLine++; } } /* * Create an error message to add to errorInfo, including up to a * maximum number of characters of the command. */ if (length < 0) { length = strlen(command); } if (length > 150) { length = 150; ellipsis = "..."; } while ( (command[length] & 0xC0) == 0x80 ) { /* * Back up truncation point so that we don't truncate in the * middle of a multi-byte character (in UTF-8) */ length--; ellipsis = "..."; } if (!(iPtr->flags & ERR_IN_PROGRESS)) { sprintf(buffer, "\n while executing\n\"%.*s%s\"", length, command, ellipsis); } else { sprintf(buffer, "\n invoked from within\n\"%.*s%s\"", length, command, ellipsis); } Tcl_AddObjErrorInfo(interp, buffer, -1); iPtr->flags &= ~ERR_ALREADY_LOGGED; } /* *---------------------------------------------------------------------- * * Tcl_EvalTokensStandard, EvalTokensStandard -- * * Given an array of tokens parsed from a Tcl command (e.g., the * tokens that make up a word or the index for an array variable) * this procedure evaluates the tokens and concatenates their * values to form a single result value. * * Results: * The return value is a standard Tcl completion code such as * TCL_OK or TCL_ERROR. A result or error message is left in * interp's result. * * Side effects: * Depends on the array of tokens being evaled. * * TIP #280 : Keep public API, internally extended API. *---------------------------------------------------------------------- */ int Tcl_EvalTokensStandard(interp, tokenPtr, count) Tcl_Interp *interp; /* Interpreter in which to lookup * variables, execute nested commands, * and report errors. */ Tcl_Token *tokenPtr; /* Pointer to first in an array of tokens * to evaluate and concatenate. */ int count; /* Number of tokens to consider at tokenPtr. * Must be at least 1. */ { #ifdef TCL_TIP280 return EvalTokensStandard (interp, tokenPtr, count, 1, NULL, NULL); } static int EvalTokensStandard(interp, tokenPtr, count, line, clNextOuter, outerScript) Tcl_Interp *interp; /* Interpreter in which to lookup * variables, execute nested commands, * and report errors. */ Tcl_Token *tokenPtr; /* Pointer to first in an array of tokens * to evaluate and concatenate. */ int count; /* Number of tokens to consider at tokenPtr. * Must be at least 1. */ int line; /* The line the script starts on. */ int* clNextOuter; /* Information about an outer context for */ CONST char* outerScript; /* continuation line data. This is set by * EvalEx() to properly handle [...]-nested * commands. The 'outerScript' refers to the * most-outer script containing the embedded * command, which is refered to by 'script'. The * 'clNextOuter' refers to the current entry in * the table of continuation lines in this * "master script", and the character offsets are * relative to the 'outerScript' as well. * * If outerScript == script, then this call is for * words in the outer-most script/command. See * Tcl_EvalEx() and TclEvalObjEx() for the places * generating arguments for which this is true. */ { #endif Tcl_Obj *resultPtr, *indexPtr, *valuePtr; char buffer[TCL_UTF_MAX]; #ifdef TCL_MEM_DEBUG # define MAX_VAR_CHARS 5 #else # define MAX_VAR_CHARS 30 #endif char nameBuffer[MAX_VAR_CHARS+1]; char *varName, *index; CONST char *p = NULL; /* Initialized to avoid compiler warning. */ int length, code; #ifdef TCL_TIP280 #define NUM_STATIC_POS 20 int isLiteral, maxNumCL, numCL, i, adjust; int* clPosition = NULL; Interp* iPtr = (Interp*) interp; int inFile = iPtr->evalFlags & TCL_EVAL_FILE; #endif /* * The only tricky thing about this procedure is that it attempts to * avoid object creation and string copying whenever possible. For * example, if the value is just a nested command, then use the * command's result object directly. */ code = TCL_OK; resultPtr = NULL; Tcl_ResetResult(interp); #ifdef TCL_TIP280 /* * For the handling of continuation lines in literals we first check if * this is actually a literal. For if not we can forego the additional * processing. Otherwise we pre-allocate a small table to store the * locations of all continuation lines we find in this literal, if * any. The table is extended if needed. */ numCL = 0; maxNumCL = 0; isLiteral = 1; for (i=0 ; i < count; i++) { if ((tokenPtr[i].type != TCL_TOKEN_TEXT) && (tokenPtr[i].type != TCL_TOKEN_BS)) { isLiteral = 0; break; } } if (isLiteral) { maxNumCL = NUM_STATIC_POS; clPosition = (int*) ckalloc (maxNumCL*sizeof(int)); } adjust = 0; #endif for ( ; count > 0; count--, tokenPtr++) { valuePtr = NULL; /* * The switch statement below computes the next value to be * concat to the result, as either a range of text or an * object. */ switch (tokenPtr->type) { case TCL_TOKEN_TEXT: p = tokenPtr->start; length = tokenPtr->size; break; case TCL_TOKEN_BS: length = TclParseBackslash(tokenPtr->start, tokenPtr->size, (int *) NULL, buffer); p = buffer; #ifdef TCL_TIP280 /* * If the backslash sequence we found is in a literal, and * represented a continuation line, we compute and store its * location (as char offset to the beginning of the _result_ * script). We may have to extend the table of locations. * * Note that the continuation line information is relevant * even if the word we are processing is not a literal, as it * can affect nested commands. See the branch for * TCL_TOKEN_COMMAND below, where the adjustment we are * tracking here is taken into account. The good thing is that * we do not need a table of everything, just the number of * lines we have to add as correction. */ if ((length == 1) && (buffer[0] == ' ') && (tokenPtr->start[1] == '\n')) { if (isLiteral) { int clPos; if (resultPtr == 0) { clPos = 0; } else { Tcl_GetStringFromObj(resultPtr, &clPos); } if (numCL >= maxNumCL) { maxNumCL *= 2; clPosition = (int*) ckrealloc ((char*)clPosition, maxNumCL*sizeof(int)); } clPosition[numCL] = clPos; numCL ++; } adjust ++; } #endif break; case TCL_TOKEN_COMMAND: { Interp *iPtr = (Interp *) interp; iPtr->numLevels++; code = TclInterpReady(interp); if (code == TCL_OK) { #ifndef TCL_TIP280 code = Tcl_EvalEx(interp, tokenPtr->start+1, tokenPtr->size-2, 0); #else /* TIP #280: Transfer line information to nested command */ TclAdvanceContinuations (&line, &clNextOuter, tokenPtr->start - outerScript); code = EvalEx(interp, tokenPtr->start+1, tokenPtr->size-2, 0, line + adjust, clNextOuter, outerScript); /* * Restore flag reset by the nested eval for future * bracketed commands and their CmdFrame setup */ if (inFile) { iPtr->evalFlags |= TCL_EVAL_FILE; } #endif } iPtr->numLevels--; if (code != TCL_OK) { goto done; } valuePtr = Tcl_GetObjResult(interp); break; } case TCL_TOKEN_VARIABLE: if (tokenPtr->numComponents == 1) { indexPtr = NULL; index = NULL; } else { #ifndef TCL_TIP280 code = Tcl_EvalTokensStandard(interp, tokenPtr+2, tokenPtr->numComponents - 1); #else /* TIP #280: Transfer line information to nested command */ code = EvalTokensStandard(interp, tokenPtr+2, tokenPtr->numComponents - 1, line, NULL, NULL); #endif if (code != TCL_OK) { goto done; } indexPtr = Tcl_GetObjResult(interp); Tcl_IncrRefCount(indexPtr); index = Tcl_GetString(indexPtr); } /* * We have to make a copy of the variable name in order * to have a null-terminated string. We can't make a * temporary modification to the script to null-terminate * the name, because a trace callback might potentially * reuse the script and be affected by the null character. */ if (tokenPtr[1].size <= MAX_VAR_CHARS) { varName = nameBuffer; } else { varName = ckalloc((unsigned) (tokenPtr[1].size + 1)); } strncpy(varName, tokenPtr[1].start, (size_t) tokenPtr[1].size); varName[tokenPtr[1].size] = 0; valuePtr = Tcl_GetVar2Ex(interp, varName, index, TCL_LEAVE_ERR_MSG); if (varName != nameBuffer) { ckfree(varName); } if (indexPtr != NULL) { Tcl_DecrRefCount(indexPtr); } if (valuePtr == NULL) { code = TCL_ERROR; goto done; } count -= tokenPtr->numComponents; tokenPtr += tokenPtr->numComponents; break; default: panic("unexpected token type in Tcl_EvalTokensStandard"); } /* * If valuePtr isn't NULL, the next piece of text comes from that * object; otherwise, take length bytes starting at p. */ if (resultPtr == NULL) { if (valuePtr != NULL) { resultPtr = valuePtr; } else { resultPtr = Tcl_NewStringObj(p, length); } Tcl_IncrRefCount(resultPtr); } else { if (Tcl_IsShared(resultPtr)) { Tcl_DecrRefCount(resultPtr); resultPtr = Tcl_DuplicateObj(resultPtr); Tcl_IncrRefCount(resultPtr); } if (valuePtr != NULL) { p = Tcl_GetStringFromObj(valuePtr, &length); } Tcl_AppendToObj(resultPtr, p, length); } } if (resultPtr != NULL) { Tcl_SetObjResult(interp, resultPtr); #ifdef TCL_TIP280 /* * If the code found continuation lines (which implies that this word * is a literal), then we store the accumulated table of locations in * the thread-global data structure for the bytecode compiler to find * later, assuming that the literal is a script which will be * compiled. */ if (numCL) { TclContinuationsEnter(resultPtr, numCL, clPosition); } /* * Release the temp table we used to collect the locations of * continuation lines, if any. */ if (maxNumCL) { ckfree ((char*) clPosition); } #endif } else { code = TCL_ERROR; } done: if (resultPtr != NULL) { Tcl_DecrRefCount(resultPtr); } return code; } /* *---------------------------------------------------------------------- * * Tcl_EvalTokens -- * * Given an array of tokens parsed from a Tcl command (e.g., the * tokens that make up a word or the index for an array variable) * this procedure evaluates the tokens and concatenates their * values to form a single result value. * * Results: * The return value is a pointer to a newly allocated Tcl_Obj * containing the value of the array of tokens. The reference * count of the returned object has been incremented. If an error * occurs in evaluating the tokens then a NULL value is returned * and an error message is left in interp's result. * * Side effects: * A new object is allocated to hold the result. * *---------------------------------------------------------------------- * * This uses a non-standard return convention; its use is now deprecated. * It is a wrapper for the new function Tcl_EvalTokensStandard, and is not * used in the core any longer. It is only kept for backward compatibility. */ Tcl_Obj * Tcl_EvalTokens(interp, tokenPtr, count) Tcl_Interp *interp; /* Interpreter in which to lookup * variables, execute nested commands, * and report errors. */ Tcl_Token *tokenPtr; /* Pointer to first in an array of tokens * to evaluate and concatenate. */ int count; /* Number of tokens to consider at tokenPtr. * Must be at least 1. */ { int code; Tcl_Obj *resPtr; code = Tcl_EvalTokensStandard(interp, tokenPtr, count); if (code == TCL_OK) { resPtr = Tcl_GetObjResult(interp); Tcl_IncrRefCount(resPtr); Tcl_ResetResult(interp); return resPtr; } else { return NULL; } } /* *---------------------------------------------------------------------- * * Tcl_EvalEx, EvalEx -- * * This procedure evaluates a Tcl script without using the compiler * or byte-code interpreter. It just parses the script, creates * values for each word of each command, then calls EvalObjv * to execute each command. * * Results: * The return value is a standard Tcl completion code such as * TCL_OK or TCL_ERROR. A result or error message is left in * interp's result. * * Side effects: * Depends on the script. * * TIP #280 : Keep public API, internally extended API. *---------------------------------------------------------------------- */ int Tcl_EvalEx(interp, script, numBytes, flags) Tcl_Interp *interp; /* Interpreter in which to evaluate the * script. Also used for error reporting. */ CONST char *script; /* First character of script to evaluate. */ int numBytes; /* Number of bytes in script. If < 0, the * script consists of all bytes up to the * first null character. */ int flags; /* Collection of OR-ed bits that control * the evaluation of the script. Only * TCL_EVAL_GLOBAL is currently * supported. */ { #ifdef TCL_TIP280 return EvalEx (interp, script, numBytes, flags, 1, NULL, script); } static int EvalEx(interp, script, numBytes, flags, line, clNextOuter, outerScript) Tcl_Interp *interp; /* Interpreter in which to evaluate the * script. Also used for error reporting. */ CONST char *script; /* First character of script to evaluate. */ int numBytes; /* Number of bytes in script. If < 0, the * script consists of all bytes up to the * first null character. */ int flags; /* Collection of OR-ed bits that control * the evaluation of the script. Only * TCL_EVAL_GLOBAL is currently * supported. */ int line; /* The line the script starts on. */ int* clNextOuter; /* Information about an outer context for */ CONST char* outerScript; /* continuation line data. This is set only in * EvalTokensStandard(), to properly handle * [...]-nested commands. The 'outerScript' * refers to the most-outer script containing the * embedded command, which is refered to by * 'script'. The 'clNextOuter' refers to the * current entry in the table of continuation * lines in this "master script", and the * character offsets are relative to the * 'outerScript' as well. * * If outerScript == script, then this call is * for the outer-most script/command. See * Tcl_EvalEx() and TclEvalObjEx() for places * generating arguments for which this is true. */ { #endif Interp *iPtr = (Interp *) interp; CONST char *p, *next; Tcl_Parse parse; #define NUM_STATIC_OBJS 20 Tcl_Obj *staticObjArray[NUM_STATIC_OBJS], **objv; Tcl_Token *tokenPtr; int code = TCL_OK; int i, commandLength, bytesLeft, nested; CallFrame *savedVarFramePtr; /* Saves old copy of iPtr->varFramePtr * in case TCL_EVAL_GLOBAL was set. */ int allowExceptions = (iPtr->evalFlags & TCL_ALLOW_EXCEPTIONS); /* * The variables below keep track of how much state has been * allocated while evaluating the script, so that it can be freed * properly if an error occurs. */ int gotParse = 0, objectsUsed = 0; #ifdef TCL_TIP280 /* TIP #280 Structures for tracking of command locations. */ CmdFrame eeFrame; /* * Pointer for the tracking of invisible continuation lines. Initialized * only if the caller gave us a table of locations to track, via * scriptCLLocPtr. It always refers to the table entry holding the * location of the next invisible continuation line to look for, while * parsing the script. */ int* clNext = NULL; if (iPtr->scriptCLLocPtr) { if (clNextOuter) { clNext = clNextOuter; } else { clNext = &iPtr->scriptCLLocPtr->loc[0]; } } #endif if (numBytes < 0) { numBytes = strlen(script); } Tcl_ResetResult(interp); savedVarFramePtr = iPtr->varFramePtr; if (flags & TCL_EVAL_GLOBAL) { iPtr->varFramePtr = NULL; } /* * Each iteration through the following loop parses the next * command from the script and then executes it. */ objv = staticObjArray; p = script; bytesLeft = numBytes; if (iPtr->evalFlags & TCL_BRACKET_TERM) { nested = 1; } else { nested = 0; } #ifdef TCL_TIP280 /* TIP #280 Initialize tracking. Do not push on the frame stack yet. */ /* * We may cont. counting based on a specific context (CTX), or open a new * context, either for a sourced script, or 'eval'. For sourced files we * always have a path object, even if nothing was specified in the interp * itself. That makes code using it simpler as NULL checks can be left * out. Sourced file without path in the 'scriptFile' is possible during * Tcl initialization. */ if (iPtr->evalFlags & TCL_EVAL_CTX) { /* Path information comes out of the context. */ eeFrame.type = TCL_LOCATION_SOURCE; eeFrame.data.eval.path = iPtr->invokeCmdFramePtr->data.eval.path; Tcl_IncrRefCount (eeFrame.data.eval.path); } else if (iPtr->evalFlags & TCL_EVAL_FILE) { /* Set up for a sourced file */ eeFrame.type = TCL_LOCATION_SOURCE; if (iPtr->scriptFile) { /* Normalization here, to have the correct pwd. Should have * negligible impact on performance, as the norm should have been * done already by the 'source' invoking us, and it caches the * result */ Tcl_Obj* norm = Tcl_FSGetNormalizedPath (interp, iPtr->scriptFile); if (!norm) { /* Error message in the interp result */ return TCL_ERROR; } eeFrame.data.eval.path = norm; } else { eeFrame.data.eval.path = Tcl_NewStringObj ("",-1); } Tcl_IncrRefCount (eeFrame.data.eval.path); } else { /* Set up for plain eval */ eeFrame.type = TCL_LOCATION_EVAL; eeFrame.data.eval.path = NULL; } eeFrame.level = (iPtr->cmdFramePtr == NULL ? 1 : iPtr->cmdFramePtr->level + 1); eeFrame.framePtr = iPtr->framePtr; eeFrame.nextPtr = iPtr->cmdFramePtr; eeFrame.nline = 0; eeFrame.line = NULL; #endif iPtr->evalFlags = 0; do { if (Tcl_ParseCommand(interp, p, bytesLeft, nested, &parse) != TCL_OK) { code = TCL_ERROR; goto error; } gotParse = 1; if (nested && parse.term == (script + numBytes)) { /* * A nested script can only terminate in ']'. If * the parsing got terminated at the end of the script, * there was no closing ']'. Report the syntax error. */ code = TCL_ERROR; goto error; } #ifdef TCL_TIP280 /* * TIP #280 Track lines. The parser may have skipped text till it * found the command we are now at. We have count the lines in this * block, and do not forget invisible continuation lines. */ TclAdvanceLines (&line, p, parse.commandStart); TclAdvanceContinuations (&line, &clNext, parse.commandStart - outerScript); #endif if (parse.numWords > 0) { #ifdef TCL_TIP280 /* * TIP #280. Track lines within the words of the current * command. We use a separate pointer into the table of * continuation line locations to not lose our position for the * per-command parsing. */ int wordLine = line; CONST char* wordStart = parse.commandStart; int* wordCLNext = clNext; #endif /* * Generate an array of objects for the words of the command. */ if (parse.numWords <= NUM_STATIC_OBJS) { objv = staticObjArray; } else { objv = (Tcl_Obj **) ckalloc((unsigned) (parse.numWords * sizeof (Tcl_Obj *))); } #ifdef TCL_TIP280 eeFrame.nline = parse.numWords; eeFrame.line = (int*) ckalloc((unsigned) (parse.numWords * sizeof (int))); #endif for (objectsUsed = 0, tokenPtr = parse.tokenPtr; objectsUsed < parse.numWords; objectsUsed++, tokenPtr += (tokenPtr->numComponents + 1)) { #ifndef TCL_TIP280 code = Tcl_EvalTokensStandard(interp, tokenPtr+1, tokenPtr->numComponents); #else /* * TIP #280. Track lines to current word. Save the * information on a per-word basis, signaling dynamic words as * needed. Make the information available to the recursively * called evaluator as well, including the type of context * (source vs. eval). */ TclAdvanceLines (&wordLine, wordStart, tokenPtr->start); TclAdvanceContinuations (&wordLine, &wordCLNext, tokenPtr->start - outerScript); wordStart = tokenPtr->start; eeFrame.line [objectsUsed] = (TclWordKnownAtCompileTime (tokenPtr) ? wordLine : -1); if (eeFrame.type == TCL_LOCATION_SOURCE) { iPtr->evalFlags |= TCL_EVAL_FILE; } code = EvalTokensStandard(interp, tokenPtr+1, tokenPtr->numComponents, wordLine, wordCLNext, outerScript); iPtr->evalFlags = 0; #endif if (code == TCL_OK) { objv[objectsUsed] = Tcl_GetObjResult(interp); Tcl_IncrRefCount(objv[objectsUsed]); #ifdef TCL_TIP280 if (wordCLNext) { TclContinuationsEnterDerived (objv[objectsUsed], wordStart - outerScript, wordCLNext); } #endif } else { goto error; } } /* * Execute the command and free the objects for its words. * * TIP #280: Remember the command itself for 'info frame'. We * shorten the visible command by one char to exclude the * termination character, if necessary. Here is where we put our * frame on the stack of frames too. _After_ the nested commands * have been executed. */ #ifdef TCL_TIP280 eeFrame.cmd.str.cmd = parse.commandStart; eeFrame.cmd.str.len = parse.commandSize; if (parse.term == parse.commandStart + parse.commandSize - 1) { eeFrame.cmd.str.len --; } TclArgumentEnter (interp, objv, objectsUsed, &eeFrame); iPtr->cmdFramePtr = &eeFrame; #endif iPtr->numLevels++; code = TclEvalObjvInternal(interp, objectsUsed, objv, parse.commandStart, parse.commandSize, 0); iPtr->numLevels--; #ifdef TCL_TIP280 iPtr->cmdFramePtr = iPtr->cmdFramePtr->nextPtr; TclArgumentRelease (interp, objv, objectsUsed); ckfree ((char*) eeFrame.line); eeFrame.line = NULL; eeFrame.nline = 0; #endif if (code != TCL_OK) { goto error; } for (i = 0; i < objectsUsed; i++) { Tcl_DecrRefCount(objv[i]); } objectsUsed = 0; if (objv != staticObjArray) { ckfree((char *) objv); objv = staticObjArray; } } /* * Advance to the next command in the script. * * TIP #280 Track Lines. Now we track how many lines were in the * executed command. */ next = parse.commandStart + parse.commandSize; bytesLeft -= next - p; p = next; #ifdef TCL_TIP280 TclAdvanceLines (&line, parse.commandStart, p); #endif Tcl_FreeParse(&parse); gotParse = 0; if (nested && (*parse.term == ']')) { /* * We get here in the special case where the TCL_BRACKET_TERM * flag was set in the interpreter and the latest parsed command * was terminated by the matching close-bracket we seek. * Return immediately. */ iPtr->termOffset = (p - 1) - script; iPtr->varFramePtr = savedVarFramePtr; #ifndef TCL_TIP280 return TCL_OK; #else code = TCL_OK; goto cleanup_return; #endif } } while (bytesLeft > 0); if (nested) { /* * This nested script did not terminate in ']', it is an error. */ code = TCL_ERROR; goto error; } iPtr->termOffset = p - script; iPtr->varFramePtr = savedVarFramePtr; #ifndef TCL_TIP280 return TCL_OK; #else code = TCL_OK; goto cleanup_return; #endif error: /* * Generate various pieces of error information, such as the line * number where the error occurred and information to add to the * errorInfo variable. Then free resources that had been allocated * to the command. */ if (iPtr->numLevels == 0) { if (code == TCL_RETURN) { code = TclUpdateReturnInfo(iPtr); } if ((code != TCL_OK) && (code != TCL_ERROR) && !allowExceptions) { ProcessUnexpectedResult(interp, code); code = TCL_ERROR; } } if ((code == TCL_ERROR) && !(iPtr->flags & ERR_ALREADY_LOGGED)) { commandLength = parse.commandSize; if (parse.term == parse.commandStart + commandLength - 1) { /* * The terminator character (such as ; or ]) of the command where * the error occurred is the last character in the parsed command. * Reduce the length by one so that the error message doesn't * include the terminator character. */ commandLength -= 1; } Tcl_LogCommandInfo(interp, script, parse.commandStart, commandLength); } for (i = 0; i < objectsUsed; i++) { Tcl_DecrRefCount(objv[i]); } if (gotParse) { Tcl_FreeParse(&parse); } if (objv != staticObjArray) { ckfree((char *) objv); } iPtr->varFramePtr = savedVarFramePtr; /* * All that's left to do before returning is to set iPtr->termOffset * to point past the end of the script we just evaluated. */ next = parse.commandStart + parse.commandSize; bytesLeft -= next - p; p = next; if (!nested) { iPtr->termOffset = p - script; #ifndef TCL_TIP280 return code; #else goto cleanup_return; #endif } /* * When we are nested (the TCL_BRACKET_TERM flag was set in the * interpreter), we must find the matching close-bracket to * end the script we are evaluating. * * When our return code is TCL_CONTINUE or TCL_RETURN, we want * to correctly set iPtr->termOffset to point to that matching * close-bracket so our caller can move to the part of the * string beyond the script we were asked to evaluate. * So we try to parse past the rest of the commands. */ next = NULL; while (bytesLeft && (*parse.term != ']')) { if (TCL_OK != Tcl_ParseCommand(NULL, p, bytesLeft, 1, &parse)) { /* * Syntax error. Set the termOffset to the beginning of * the last command parsed. */ if (next == NULL) { iPtr->termOffset = (parse.commandStart - 1) - script; } else { iPtr->termOffset = (next - 1) - script; } #ifndef TCL_TIP280 return code; #else goto cleanup_return; #endif } next = parse.commandStart + parse.commandSize; bytesLeft -= next - p; p = next; next = parse.commandStart; Tcl_FreeParse(&parse); } if (bytesLeft) { /* * parse.term points to the close-bracket. */ iPtr->termOffset = parse.term - script; } else if (parse.term == script + numBytes) { /* * There was no close-bracket. Syntax error. */ iPtr->termOffset = parse.term - script; Tcl_SetObjResult(interp, Tcl_NewStringObj("missing close-bracket", -1)); #ifndef TCL_TIP280 return TCL_ERROR; #else code = TCL_ERROR; goto cleanup_return; #endif } else if (*parse.term != ']') { /* * There was no close-bracket. Syntax error. */ iPtr->termOffset = (parse.term + 1) - script; Tcl_SetObjResult(interp, Tcl_NewStringObj("missing close-bracket", -1)); #ifndef TCL_TIP280 return TCL_ERROR; #else code = TCL_ERROR; goto cleanup_return; #endif } else { /* * parse.term points to the close-bracket. */ iPtr->termOffset = parse.term - script; } #ifdef TCL_TIP280 cleanup_return: /* TIP #280. Release the local CmdFrame, and its contents. */ if (eeFrame.line != NULL) { ckfree ((char*) eeFrame.line); } if (eeFrame.type == TCL_LOCATION_SOURCE) { Tcl_DecrRefCount (eeFrame.data.eval.path); } #endif return code; } #ifdef TCL_TIP280 /* *---------------------------------------------------------------------- * * TclAdvanceLines -- * * This procedure is a helper which counts the number of lines * in a block of text and advances an external counter. * * Results: * None. * * Side effects: * The specified counter is advanced per the number of lines found. * * TIP #280 *---------------------------------------------------------------------- */ void TclAdvanceLines (line,start,end) int* line; CONST char* start; CONST char* end; { CONST char* p; for (p = start; p < end; p++) { if (*p == '\n') { (*line) ++; } } } /* *---------------------------------------------------------------------- * * TclAdvanceContinuations -- * * This procedure is a helper which counts the number of continuation * lines (CL) in a block of text using a table of CL locations and * advances an external counter, and the pointer into the table. * * Results: * None. * * Side effects: * The specified counter is advanced per the number of continuation lines * found. * * TIP #280 *---------------------------------------------------------------------- */ void TclAdvanceContinuations (line,clNextPtrPtr,loc) int* line; int** clNextPtrPtr; int loc; { /* * Track the invisible continuation lines embedded in a script, if * any. Here they are just spaces (already). They were removed by * EvalTokensStandard() via TclParseBackslash(). * * *clNextPtrPtr <=> We have continuation lines to track. * **clNextPtrPtr >= 0 <=> We are not beyond the last possible location. * loc >= **clNextPtrPtr <=> We stepped beyond the current cont. line. */ while (*clNextPtrPtr && (**clNextPtrPtr >= 0) && (loc >= **clNextPtrPtr)) { /* * We just stepped over an invisible continuation line. Adjust the * line counter and step to the table entry holding the location of * the next continuation line to track. */ (*line) ++; (*clNextPtrPtr) ++; } } /* *---------------------------------------------------------------------- * Note: The whole data structure access for argument location tracking is * hidden behind these three functions. The only parts open are the lineLAPtr * field in the Interp structure. The CFWord definition is internal to here. * Should make it easier to redo the data structures if we find something more * space/time efficient. */ /* *---------------------------------------------------------------------- * * TclArgumentEnter -- * * This procedure is a helper for the TIP #280 uplevel extension. * It enters location references for the arguments of a command to be * invoked. Only the first entry has the actual data, further entries * simply count the usage up. * * Results: * None. * * Side effects: * May allocate memory. * * TIP #280 *---------------------------------------------------------------------- */ void TclArgumentEnter(interp,objv,objc,cfPtr) Tcl_Interp* interp; Tcl_Obj** objv; int objc; CmdFrame* cfPtr; { Interp* iPtr = (Interp*) interp; int new, i; Tcl_HashEntry* hPtr; CFWord* cfwPtr; for (i=1; i < objc; i++) { /* * Ignore argument words without line information (= dynamic). If * they are variables they may have location information associated * with that, either through globally recorded 'set' invokations, or * literals in bytecode. Eitehr way there is no need to record * something here. */ if (cfPtr->line [i] < 0) continue; hPtr = Tcl_CreateHashEntry (iPtr->lineLAPtr, (char*) objv[i], &new); if (new) { /* * The word is not on the stack yet, remember the current location * and initialize references. */ cfwPtr = (CFWord*) ckalloc (sizeof (CFWord)); cfwPtr->framePtr = cfPtr; cfwPtr->word = i; cfwPtr->refCount = 1; Tcl_SetHashValue (hPtr, cfwPtr); } else { /* * The word is already on the stack, its current location is not * relevant. Just remember the reference to prevent early removal. */ cfwPtr = (CFWord*) Tcl_GetHashValue (hPtr); cfwPtr->refCount ++; } } } /* *---------------------------------------------------------------------- * * TclArgumentRelease -- * * This procedure is a helper for the TIP #280 uplevel extension. * It removes the location references for the arguments of a command * just done. Usage is counted down, the data is removed only when * no user is left over. * * Results: * None. * * Side effects: * May release memory. * * TIP #280 *---------------------------------------------------------------------- */ void TclArgumentRelease(interp,objv,objc) Tcl_Interp* interp; Tcl_Obj** objv; int objc; { Interp* iPtr = (Interp*) interp; Tcl_HashEntry* hPtr; CFWord* cfwPtr; int i; for (i=1; i < objc; i++) { hPtr = Tcl_FindHashEntry (iPtr->lineLAPtr, (char *) objv[i]); if (!hPtr) { continue; } cfwPtr = (CFWord*) Tcl_GetHashValue (hPtr); cfwPtr->refCount --; if (cfwPtr->refCount > 0) { continue; } ckfree ((char*) cfwPtr); Tcl_DeleteHashEntry (hPtr); } } /* *---------------------------------------------------------------------- * * TclArgumentBCEnter -- * * This procedure is a helper for the TIP #280 uplevel extension. * It enters location references for the literal arguments of commands * in bytecode about to be executed. Only the first entry has the actual * data, further entries simply count the usage up. * * Results: * None. * * Side effects: * May allocate memory. * * TIP #280 *---------------------------------------------------------------------- */ void TclArgumentBCEnter(interp, objv, objc, codePtr, cfPtr, pc) Tcl_Interp* interp; Tcl_Obj* objv[]; int objc; void* codePtr; CmdFrame* cfPtr; int pc; { Interp* iPtr = (Interp*) interp; Tcl_HashEntry* hePtr = Tcl_FindHashEntry (iPtr->lineBCPtr, (char *) codePtr); if (hePtr) { ExtCmdLoc* eclPtr = (ExtCmdLoc*) Tcl_GetHashValue (hePtr); hePtr = Tcl_FindHashEntry(&eclPtr->litInfo, (char*) pc); if (hePtr) { int word; int cmd = (int) Tcl_GetHashValue(hePtr); ECL* ePtr = &eclPtr->loc[cmd]; /* * A few truths ... * (1) ePtr->nline == objc * (2) (ePtr->line[word] < 0) => !literal, for all words * (3) (word == 0) => !literal * * Item (2) is why we can use objv to get the literals, and do not * have to save them at compile time. */ for (word = 1; word < objc; word++) { if (ePtr->line[word] >= 0) { int isnew; Tcl_HashEntry* hPtr = Tcl_CreateHashEntry (iPtr->lineLABCPtr, (char*) objv[word], &isnew); CFWordBC* cfwPtr = (CFWordBC*) ckalloc (sizeof (CFWordBC)); cfwPtr->framePtr = cfPtr; cfwPtr->pc = pc; cfwPtr->word = word; if (isnew) { /* * The word is not on the stack yet, remember the * current location and initialize references. */ cfwPtr->prevPtr = NULL; } else { /* * The object is already on the stack, however it may * have a different location now (literal sharing may * map multiple location to a single Tcl_Obj*. Save * the old information in the new structure. */ cfwPtr->prevPtr = (CFWordBC*) Tcl_GetHashValue(hPtr); } Tcl_SetHashValue (hPtr, cfwPtr); } } /* for */ } /* if */ } /* if */ } /* *---------------------------------------------------------------------- * * TclArgumentBCRelease -- * * This procedure is a helper for the TIP #280 uplevel extension. * It removes the location references for the literal arguments of * commands in bytecode just done. Usage is counted down, the data * is removed only when no user is left over. * * Results: * None. * * Side effects: * May release memory. * * TIP #280 *---------------------------------------------------------------------- */ void TclArgumentBCRelease(interp, objv, objc, codePtr, pc) Tcl_Interp* interp; Tcl_Obj* objv[]; int objc; void* codePtr; int pc; { Interp* iPtr = (Interp*) interp; Tcl_HashEntry* hePtr = Tcl_FindHashEntry (iPtr->lineBCPtr, (char *) codePtr); if (hePtr) { ExtCmdLoc* eclPtr = (ExtCmdLoc*) Tcl_GetHashValue (hePtr); hePtr = Tcl_FindHashEntry(&eclPtr->litInfo, (char*) pc); if (hePtr) { int cmd = (int) Tcl_GetHashValue(hePtr); ECL* ePtr = &eclPtr->loc[cmd]; int word; /* * Iterate in reverse order, to properly match our pop to the push * in TclArgumentBCEnter(). */ for (word = objc-1; word >= 1; word--) { if (ePtr->line[word] >= 0) { Tcl_HashEntry* hPtr = Tcl_FindHashEntry(iPtr->lineLABCPtr, (char *) objv[word]); if (hPtr) { CFWordBC* cfwPtr = (CFWordBC*) Tcl_GetHashValue (hPtr); if (cfwPtr->prevPtr) { Tcl_SetHashValue(hPtr, cfwPtr->prevPtr); } else { Tcl_DeleteHashEntry(hPtr); } ckfree((char *) cfwPtr); } } } } } } /* *---------------------------------------------------------------------- * * TclArgumentGet -- * * This procedure is a helper for the TIP #280 uplevel extension. * It find the location references for a Tcl_Obj, if any. * * Results: * None. * * Side effects: * Writes found location information into the result arguments. * * TIP #280 *---------------------------------------------------------------------- */ void TclArgumentGet(interp,obj,cfPtrPtr,wordPtr) Tcl_Interp* interp; Tcl_Obj* obj; CmdFrame** cfPtrPtr; int* wordPtr; { Interp* iPtr = (Interp*) interp; Tcl_HashEntry* hPtr; CmdFrame* framePtr; /* * An object which either has no string rep guaranteed to have been * generated dynamically: bail out, this cannot have a usable absolute * location. _Do not touch_ the information the set up by the caller. It * knows better than us. */ if (!obj->bytes) { return; } /* * First look for location information recorded in the argument * stack. That is nearest. */ hPtr = Tcl_FindHashEntry (iPtr->lineLAPtr, (char *) obj); if (hPtr) { CFWord* cfwPtr = (CFWord*) Tcl_GetHashValue (hPtr); *wordPtr = cfwPtr->word; *cfPtrPtr = cfwPtr->framePtr; return; } /* * Check if the Tcl_Obj has location information as a bytecode literal, in * that stack. */ hPtr = Tcl_FindHashEntry (iPtr->lineLABCPtr, (char *) obj); if (hPtr) { CFWordBC* cfwPtr = (CFWordBC*) Tcl_GetHashValue (hPtr); framePtr = cfwPtr->framePtr; framePtr->data.tebc.pc = (char*) ((ByteCode*) framePtr->data.tebc.codePtr)->codeStart + cfwPtr->pc; *cfPtrPtr = cfwPtr->framePtr; *wordPtr = cfwPtr->word; return; } } #endif /* *---------------------------------------------------------------------- * * Tcl_Eval -- * * Execute a Tcl command in a string. This procedure executes the * script directly, rather than compiling it to bytecodes. Before * the arrival of the bytecode compiler in Tcl 8.0 Tcl_Eval was * the main procedure used for executing Tcl commands, but nowadays * it isn't used much. * * Results: * The return value is one of the return codes defined in tcl.h * (such as TCL_OK), and interp's result contains a value * to supplement the return code. The value of the result * will persist only until the next call to Tcl_Eval or Tcl_EvalObj: * you must copy it or lose it! * * Side effects: * Can be almost arbitrary, depending on the commands in the script. * *---------------------------------------------------------------------- */ int Tcl_Eval(interp, string) Tcl_Interp *interp; /* Token for command interpreter (returned * by previous call to Tcl_CreateInterp). */ CONST char *string; /* Pointer to TCL command to execute. */ { int code = Tcl_EvalEx(interp, string, -1, 0); /* * For backwards compatibility with old C code that predates the * object system in Tcl 8.0, we have to mirror the object result * back into the string result (some callers may expect it there). */ Tcl_SetResult(interp, TclGetString(Tcl_GetObjResult(interp)), TCL_VOLATILE); return code; } /* *---------------------------------------------------------------------- * * Tcl_EvalObj, Tcl_GlobalEvalObj -- * * These functions are deprecated but we keep them around for backwards * compatibility reasons. * * Results: * See the functions they call. * * Side effects: * See the functions they call. * *---------------------------------------------------------------------- */ #undef Tcl_EvalObj int Tcl_EvalObj(interp, objPtr) Tcl_Interp * interp; Tcl_Obj * objPtr; { return Tcl_EvalObjEx(interp, objPtr, 0); } #undef Tcl_GlobalEvalObj int Tcl_GlobalEvalObj(interp, objPtr) Tcl_Interp * interp; Tcl_Obj * objPtr; { return Tcl_EvalObjEx(interp, objPtr, TCL_EVAL_GLOBAL); } /* *---------------------------------------------------------------------- * * Tcl_EvalObjEx, TclEvalObjEx -- * * Execute Tcl commands stored in a Tcl object. These commands are * compiled into bytecodes if necessary, unless TCL_EVAL_DIRECT * is specified. * * Results: * The return value is one of the return codes defined in tcl.h * (such as TCL_OK), and the interpreter's result contains a value * to supplement the return code. * * Side effects: * The object is converted, if necessary, to a ByteCode object that * holds the bytecode instructions for the commands. Executing the * commands will almost certainly have side effects that depend * on those commands. * * Just as in Tcl_Eval, interp->termOffset is set to the offset of the * last character executed in the objPtr's string. * * TIP #280 : Keep public API, internally extended API. *---------------------------------------------------------------------- */ int Tcl_EvalObjEx(interp, objPtr, flags) Tcl_Interp *interp; /* Token for command interpreter * (returned by a previous call to * Tcl_CreateInterp). */ register Tcl_Obj *objPtr; /* Pointer to object containing * commands to execute. */ int flags; /* Collection of OR-ed bits that * control the evaluation of the * script. Supported values are * TCL_EVAL_GLOBAL and * TCL_EVAL_DIRECT. */ { #ifdef TCL_TIP280 return TclEvalObjEx (interp, objPtr, flags, NULL, 0); } int TclEvalObjEx(interp, objPtr, flags, invoker, word) Tcl_Interp *interp; /* Token for command interpreter * (returned by a previous call to * Tcl_CreateInterp). */ register Tcl_Obj *objPtr; /* Pointer to object containing * commands to execute. */ int flags; /* Collection of OR-ed bits that * control the evaluation of the * script. Supported values are * TCL_EVAL_GLOBAL and * TCL_EVAL_DIRECT. */ CONST CmdFrame* invoker; /* Frame of the command doing the eval */ int word; /* Index of the word which is in objPtr */ { #endif register Interp *iPtr = (Interp *) interp; char *script; int numSrcBytes; int result; CallFrame *savedVarFramePtr; /* Saves old copy of iPtr->varFramePtr * in case TCL_EVAL_GLOBAL was set. */ int allowExceptions = (iPtr->evalFlags & TCL_ALLOW_EXCEPTIONS); Tcl_IncrRefCount(objPtr); if ((iPtr->flags & USE_EVAL_DIRECT) || (flags & TCL_EVAL_DIRECT)) { /* * We're not supposed to use the compiler or byte-code interpreter. * Let Tcl_EvalEx evaluate the command directly (and probably * more slowly). * * Pure List Optimization (no string representation). In this * case, we can safely use Tcl_EvalObjv instead and get an * appreciable improvement in execution speed. This is because it * allows us to avoid a setFromAny step that would just pack * everything into a string and back out again. * * USE_EVAL_DIRECT is a special flag used for testing purpose only * (ensure we go into the TCL_EVAL_DIRECT path, avoiding opt) */ if (!(iPtr->flags & USE_EVAL_DIRECT) && (objPtr->typePtr == &tclListType) && /* is a list... */ (objPtr->bytes == NULL) /* ...without a string rep */) { register List *listRepPtr = (List *) objPtr->internalRep.twoPtrValue.ptr1; int i, objc = listRepPtr->elemCount; #define TEOE_PREALLOC 10 Tcl_Obj *staticObjv[TEOE_PREALLOC], **objv = staticObjv; #ifdef TCL_TIP280 /* TIP #280 Structures for tracking lines. * As we know that this is dynamic execution we ignore the * invoker, even if known. */ CmdFrame eoFrame; eoFrame.type = TCL_LOCATION_EVAL_LIST; eoFrame.level = (iPtr->cmdFramePtr == NULL ? 1 : iPtr->cmdFramePtr->level + 1); eoFrame.framePtr = iPtr->framePtr; eoFrame.nextPtr = iPtr->cmdFramePtr; eoFrame.nline = 0; eoFrame.line = NULL; /* NOTE: Getting the string rep of the list to eval to fill the * command information required by 'info frame' implies that * further calls for the same list would not be optimized, as it * would not be 'pure' anymore. It would also be a waste of time * as most of the time this information is not needed at all. What * we do instead is to keep the list obj itself around and have * 'info frame' sort it out. */ eoFrame.cmd.listPtr = objPtr; Tcl_IncrRefCount (eoFrame.cmd.listPtr); eoFrame.data.eval.path = NULL; #endif if (objc > TEOE_PREALLOC) { objv = (Tcl_Obj **) ckalloc(objc*sizeof(Tcl_Obj *)); } #undef TEOE_PREALLOC /* * Copy the list elements here, to avoid a segfault if * objPtr loses its List internal rep [Bug 1119369]. * * TIP #280 We do _not_ compute all the line numbers for the words * in the command. For the eval of a pure list the most sensible * choice is to put all words on line 1. Given that we neither * need memory for them nor compute anything. 'line' is left * NULL. The two places using this information (TclInfoFrame, and * TclInitCompileEnv), are special-cased to use the proper line * number directly instead of accessing the 'line' array. */ for (i=0; i < objc; i++) { objv[i] = listRepPtr->elements[i]; Tcl_IncrRefCount(objv[i]); } #ifdef TCL_TIP280 iPtr->cmdFramePtr = &eoFrame; #endif result = Tcl_EvalObjv(interp, objc, objv, flags); #ifdef TCL_TIP280 iPtr->cmdFramePtr = iPtr->cmdFramePtr->nextPtr; Tcl_DecrRefCount (eoFrame.cmd.listPtr); #endif for (i=0; i < objc; i++) { TclDecrRefCount(objv[i]); } if (objv != staticObjv) { ckfree((char *) objv); } #ifdef TCL_TIP280 ckfree ((char*) eoFrame.line); eoFrame.line = NULL; eoFrame.nline = 0; #endif } else { #ifndef TCL_TIP280 script = Tcl_GetStringFromObj(objPtr, &numSrcBytes); result = Tcl_EvalEx(interp, script, numSrcBytes, flags); #else /* * TIP #280. Propagate context as much as we can. Especially if * the script to evaluate is a single literal it makes sense to * look if our context is one with absolute line numbers we can * then track into the literal itself too. * * See also tclCompile.c, TclInitCompileEnv, for the equivalent * code in the bytecode compiler. */ /* * Now we check if we have data about invisible continuation lines * for the script, and make it available to the direct script * parser and evaluator we are about to call, if so. * * It may be possible that the script Tcl_Obj* can be free'd while * the evaluator is using it, leading to the release of the * associated ContLineLoc structure as well. To ensure that the * latter doesn't happen we set a lock on it. We release this lock * later in this function, after the evaluator is done. The * relevant "lineCLPtr" hashtable is managed in the file * "tclObj.c". * * Another important action is to save (and later restore) the * continuation line information of the caller, in case we are * executing nested commands in the eval/direct path. */ ContLineLoc* saveCLLocPtr = iPtr->scriptCLLocPtr; ContLineLoc* clLocPtr = TclContinuationsGet (objPtr); if (clLocPtr) { iPtr->scriptCLLocPtr = clLocPtr; Tcl_Preserve (iPtr->scriptCLLocPtr); } else { iPtr->scriptCLLocPtr = NULL; } if (invoker == NULL) { /* No context, force opening of our own */ script = Tcl_GetStringFromObj(objPtr, &numSrcBytes); result = Tcl_EvalEx(interp, script, numSrcBytes, flags); } else { /* We have an invoker, describing the command asking for the * evaluation of a subordinate script. This script may * originate in a literal word, or from a variable, etc. Using * the line array we now check if we have good line * information for the relevant word. The type of context is * relevant as well. In a non-'source' context we don't have * to try tracking lines. * * First see if the word exists and is a literal. If not we go * through the easy dynamic branch. No need to perform more * complex invokations. */ CmdFrame ctx = *invoker; int pc = 0; if (invoker->type == TCL_LOCATION_BC) { /* Note: Type BC => ctx.data.eval.path is not used. * ctx.data.tebc.codePtr is used instead. */ TclGetSrcInfoForPc (&ctx); pc = 1; } script = Tcl_GetStringFromObj(objPtr, &numSrcBytes); if ((ctx.nline <= word) || (ctx.line[word] < 0) || (ctx.type != TCL_LOCATION_SOURCE)) { /* Dynamic script, or dynamic context, force our own * context */ result = Tcl_EvalEx(interp, script, numSrcBytes, flags); } else { /* Absolute context available to reuse. */ iPtr->invokeCmdFramePtr = &ctx; iPtr->evalFlags |= TCL_EVAL_CTX; result = EvalEx(interp, script, numSrcBytes, flags, ctx.line [word], NULL, script); } if (pc && (ctx.type == TCL_LOCATION_SOURCE)) { /* Death of SrcInfo reference. */ Tcl_DecrRefCount(ctx.data.eval.path); } } /* * Now release the lock on the continuation line information, if * any, and restore the caller's settings. */ if (iPtr->scriptCLLocPtr) { Tcl_Release (iPtr->scriptCLLocPtr); } iPtr->scriptCLLocPtr = saveCLLocPtr; #endif } } else { /* * Let the compiler/engine subsystem do the evaluation. * * TIP #280 The invoker provides us with the context for the * script. We transfer this to the byte code compiler. */ savedVarFramePtr = iPtr->varFramePtr; if (flags & TCL_EVAL_GLOBAL) { iPtr->varFramePtr = NULL; } #ifndef TCL_TIP280 result = TclCompEvalObj(interp, objPtr); #else result = TclCompEvalObj(interp, objPtr, invoker, word); #endif /* * If we are again at the top level, process any unusual * return code returned by the evaluated code. */ if (iPtr->numLevels == 0) { if (result == TCL_RETURN) { result = TclUpdateReturnInfo(iPtr); } if ((result != TCL_OK) && (result != TCL_ERROR) && !allowExceptions) { ProcessUnexpectedResult(interp, result); result = TCL_ERROR; /* * If an error was created here, record information about * what was being executed when the error occurred. Remove * the extra \n added by tclMain.c in the command sent to * Tcl_LogCommandInfo [Bug 833150]. */ if (!(iPtr->flags & ERR_ALREADY_LOGGED)) { script = Tcl_GetStringFromObj(objPtr, &numSrcBytes); Tcl_LogCommandInfo(interp, script, script, --numSrcBytes); iPtr->flags &= ~ERR_ALREADY_LOGGED; } } } iPtr->evalFlags = 0; iPtr->varFramePtr = savedVarFramePtr; } TclDecrRefCount(objPtr); return result; } /* *---------------------------------------------------------------------- * * ProcessUnexpectedResult -- * * Procedure called by Tcl_EvalObj to set the interpreter's result * value to an appropriate error message when the code it evaluates * returns an unexpected result code (not TCL_OK and not TCL_ERROR) to * the topmost evaluation level. * * Results: * None. * * Side effects: * The interpreter result is set to an error message appropriate to * the result code. * *---------------------------------------------------------------------- */ static void ProcessUnexpectedResult(interp, returnCode) Tcl_Interp *interp; /* The interpreter in which the unexpected * result code was returned. */ int returnCode; /* The unexpected result code. */ { Tcl_ResetResult(interp); if (returnCode == TCL_BREAK) { Tcl_AppendToObj(Tcl_GetObjResult(interp), "invoked \"break\" outside of a loop", -1); } else if (returnCode == TCL_CONTINUE) { Tcl_AppendToObj(Tcl_GetObjResult(interp), "invoked \"continue\" outside of a loop", -1); } else { char buf[30 + TCL_INTEGER_SPACE]; sprintf(buf, "command returned bad code: %d", returnCode); Tcl_SetResult(interp, buf, TCL_VOLATILE); } } /* *--------------------------------------------------------------------------- * * Tcl_ExprLong, Tcl_ExprDouble, Tcl_ExprBoolean -- * * Procedures to evaluate an expression and return its value in a * particular form. * * Results: * Each of the procedures below returns a standard Tcl result. If an * error occurs then an error message is left in the interp's result. * Otherwise the value of the expression, in the appropriate form, * is stored at *ptr. If the expression had a result that was * incompatible with the desired form then an error is returned. * * Side effects: * None. * *--------------------------------------------------------------------------- */ int Tcl_ExprLong(interp, string, ptr) Tcl_Interp *interp; /* Context in which to evaluate the * expression. */ CONST char *string; /* Expression to evaluate. */ long *ptr; /* Where to store result. */ { register Tcl_Obj *exprPtr; Tcl_Obj *resultPtr; int length = strlen(string); int result = TCL_OK; if (length > 0) { exprPtr = Tcl_NewStringObj(string, length); Tcl_IncrRefCount(exprPtr); result = Tcl_ExprObj(interp, exprPtr, &resultPtr); if (result == TCL_OK) { /* * Store an integer based on the expression result. */ if (resultPtr->typePtr == &tclIntType) { *ptr = resultPtr->internalRep.longValue; } else if (resultPtr->typePtr == &tclDoubleType) { *ptr = (long) resultPtr->internalRep.doubleValue; } else if (resultPtr->typePtr == &tclWideIntType) { #ifndef TCL_WIDE_INT_IS_LONG /* * See Tcl_GetIntFromObj for conversion comments. */ Tcl_WideInt w = resultPtr->internalRep.wideValue; if ((w >= -(Tcl_WideInt)(ULONG_MAX)) && (w <= (Tcl_WideInt)(ULONG_MAX))) { *ptr = Tcl_WideAsLong(w); } else { Tcl_SetResult(interp, "integer value too large to represent as non-long integer", TCL_STATIC); result = TCL_ERROR; } #else *ptr = resultPtr->internalRep.longValue; #endif } else { Tcl_SetResult(interp, "expression didn't have numeric value", TCL_STATIC); result = TCL_ERROR; } Tcl_DecrRefCount(resultPtr); /* discard the result object */ } else { /* * Move the interpreter's object result to the string result, * then reset the object result. */ Tcl_SetResult(interp, TclGetString(Tcl_GetObjResult(interp)), TCL_VOLATILE); } Tcl_DecrRefCount(exprPtr); /* discard the expression object */ } else { /* * An empty string. Just set the result integer to 0. */ *ptr = 0; } return result; } int Tcl_ExprDouble(interp, string, ptr) Tcl_Interp *interp; /* Context in which to evaluate the * expression. */ CONST char *string; /* Expression to evaluate. */ double *ptr; /* Where to store result. */ { register Tcl_Obj *exprPtr; Tcl_Obj *resultPtr; int length = strlen(string); int result = TCL_OK; if (length > 0) { exprPtr = Tcl_NewStringObj(string, length); Tcl_IncrRefCount(exprPtr); result = Tcl_ExprObj(interp, exprPtr, &resultPtr); if (result == TCL_OK) { /* * Store a double based on the expression result. */ if (resultPtr->typePtr == &tclIntType) { *ptr = (double) resultPtr->internalRep.longValue; } else if (resultPtr->typePtr == &tclDoubleType) { *ptr = resultPtr->internalRep.doubleValue; } else if (resultPtr->typePtr == &tclWideIntType) { #ifndef TCL_WIDE_INT_IS_LONG /* * See Tcl_GetIntFromObj for conversion comments. */ Tcl_WideInt w = resultPtr->internalRep.wideValue; if ((w >= -(Tcl_WideInt)(ULONG_MAX)) && (w <= (Tcl_WideInt)(ULONG_MAX))) { *ptr = (double) Tcl_WideAsLong(w); } else { Tcl_SetResult(interp, "integer value too large to represent as non-long integer", TCL_STATIC); result = TCL_ERROR; } #else *ptr = (double) resultPtr->internalRep.longValue; #endif } else { Tcl_SetResult(interp, "expression didn't have numeric value", TCL_STATIC); result = TCL_ERROR; } Tcl_DecrRefCount(resultPtr); /* discard the result object */ } else { /* * Move the interpreter's object result to the string result, * then reset the object result. */ Tcl_SetResult(interp, TclGetString(Tcl_GetObjResult(interp)), TCL_VOLATILE); } Tcl_DecrRefCount(exprPtr); /* discard the expression object */ } else { /* * An empty string. Just set the result double to 0.0. */ *ptr = 0.0; } return result; } int Tcl_ExprBoolean(interp, string, ptr) Tcl_Interp *interp; /* Context in which to evaluate the * expression. */ CONST char *string; /* Expression to evaluate. */ int *ptr; /* Where to store 0/1 result. */ { register Tcl_Obj *exprPtr; Tcl_Obj *resultPtr; int length = strlen(string); int result = TCL_OK; if (length > 0) { exprPtr = Tcl_NewStringObj(string, length); Tcl_IncrRefCount(exprPtr); result = Tcl_ExprObj(interp, exprPtr, &resultPtr); if (result == TCL_OK) { /* * Store a boolean based on the expression result. */ if (resultPtr->typePtr == &tclIntType) { *ptr = (resultPtr->internalRep.longValue != 0); } else if (resultPtr->typePtr == &tclDoubleType) { *ptr = (resultPtr->internalRep.doubleValue != 0.0); } else if (resultPtr->typePtr == &tclWideIntType) { #ifndef TCL_WIDE_INT_IS_LONG *ptr = (resultPtr->internalRep.wideValue != 0); #else *ptr = (resultPtr->internalRep.longValue != 0); #endif } else { result = Tcl_GetBooleanFromObj(interp, resultPtr, ptr); } Tcl_DecrRefCount(resultPtr); /* discard the result object */ } if (result != TCL_OK) { /* * Move the interpreter's object result to the string result, * then reset the object result. */ Tcl_SetResult(interp, TclGetString(Tcl_GetObjResult(interp)), TCL_VOLATILE); } Tcl_DecrRefCount(exprPtr); /* discard the expression object */ } else { /* * An empty string. Just set the result boolean to 0 (false). */ *ptr = 0; } return result; } /* *-------------------------------------------------------------- * * Tcl_ExprLongObj, Tcl_ExprDoubleObj, Tcl_ExprBooleanObj -- * * Procedures to evaluate an expression in an object and return its * value in a particular form. * * Results: * Each of the procedures below returns a standard Tcl result * object. If an error occurs then an error message is left in the * interpreter's result. Otherwise the value of the expression, in the * appropriate form, is stored at *ptr. If the expression had a result * that was incompatible with the desired form then an error is * returned. * * Side effects: * None. * *-------------------------------------------------------------- */ int Tcl_ExprLongObj(interp, objPtr, ptr) Tcl_Interp *interp; /* Context in which to evaluate the * expression. */ register Tcl_Obj *objPtr; /* Expression to evaluate. */ long *ptr; /* Where to store long result. */ { Tcl_Obj *resultPtr; int result; result = Tcl_ExprObj(interp, objPtr, &resultPtr); if (result == TCL_OK) { if (resultPtr->typePtr == &tclIntType) { *ptr = resultPtr->internalRep.longValue; } else if (resultPtr->typePtr == &tclDoubleType) { *ptr = (long) resultPtr->internalRep.doubleValue; } else { result = Tcl_GetLongFromObj(interp, resultPtr, ptr); if (result != TCL_OK) { return result; } } Tcl_DecrRefCount(resultPtr); /* discard the result object */ } return result; } int Tcl_ExprDoubleObj(interp, objPtr, ptr) Tcl_Interp *interp; /* Context in which to evaluate the * expression. */ register Tcl_Obj *objPtr; /* Expression to evaluate. */ double *ptr; /* Where to store double result. */ { Tcl_Obj *resultPtr; int result; result = Tcl_ExprObj(interp, objPtr, &resultPtr); if (result == TCL_OK) { if (resultPtr->typePtr == &tclIntType) { *ptr = (double) resultPtr->internalRep.longValue; } else if (resultPtr->typePtr == &tclDoubleType) { *ptr = resultPtr->internalRep.doubleValue; } else { result = Tcl_GetDoubleFromObj(interp, resultPtr, ptr); if (result != TCL_OK) { return result; } } Tcl_DecrRefCount(resultPtr); /* discard the result object */ } return result; } int Tcl_ExprBooleanObj(interp, objPtr, ptr) Tcl_Interp *interp; /* Context in which to evaluate the * expression. */ register Tcl_Obj *objPtr; /* Expression to evaluate. */ int *ptr; /* Where to store 0/1 result. */ { Tcl_Obj *resultPtr; int result; result = Tcl_ExprObj(interp, objPtr, &resultPtr); if (result == TCL_OK) { if (resultPtr->typePtr == &tclIntType) { *ptr = (resultPtr->internalRep.longValue != 0); } else if (resultPtr->typePtr == &tclDoubleType) { *ptr = (resultPtr->internalRep.doubleValue != 0.0); } else { result = Tcl_GetBooleanFromObj(interp, resultPtr, ptr); } Tcl_DecrRefCount(resultPtr); /* discard the result object */ } return result; } /* *---------------------------------------------------------------------- * * TclInvoke -- * * Invokes a Tcl command, given an argv/argc, from either the * exposed or the hidden sets of commands in the given interpreter. * NOTE: The command is invoked in the current stack frame of * the interpreter, thus it can modify local variables. * * Results: * A standard Tcl result. * * Side effects: * Whatever the command does. * *---------------------------------------------------------------------- */ int TclInvoke(interp, argc, argv, flags) Tcl_Interp *interp; /* Where to invoke the command. */ int argc; /* Count of args. */ register CONST char **argv; /* The arg strings; argv[0] is the name of * the command to invoke. */ int flags; /* Combination of flags controlling the * call: TCL_INVOKE_HIDDEN and * TCL_INVOKE_NO_UNKNOWN. */ { register Tcl_Obj *objPtr; register int i; int length, result; /* * This procedure generates an objv array for object arguments that hold * the argv strings. It starts out with stack-allocated space but uses * dynamically-allocated storage if needed. */ #define NUM_ARGS 20 Tcl_Obj *(objStorage[NUM_ARGS]); register Tcl_Obj **objv = objStorage; /* * Create the object argument array "objv". Make sure objv is large * enough to hold the objc arguments plus 1 extra for the zero * end-of-objv word. */ if ((argc + 1) > NUM_ARGS) { objv = (Tcl_Obj **) ckalloc((unsigned)(argc + 1) * sizeof(Tcl_Obj *)); } for (i = 0; i < argc; i++) { length = strlen(argv[i]); objv[i] = Tcl_NewStringObj(argv[i], length); Tcl_IncrRefCount(objv[i]); } objv[argc] = 0; /* * Use TclObjInterpProc to actually invoke the command. */ result = TclObjInvoke(interp, argc, objv, flags); /* * Move the interpreter's object result to the string result, * then reset the object result. */ Tcl_SetResult(interp, TclGetString(Tcl_GetObjResult(interp)), TCL_VOLATILE); /* * Decrement the ref counts on the objv elements since we are done * with them. */ for (i = 0; i < argc; i++) { objPtr = objv[i]; Tcl_DecrRefCount(objPtr); } /* * Free the objv array if malloc'ed storage was used. */ if (objv != objStorage) { ckfree((char *) objv); } return result; #undef NUM_ARGS } /* *---------------------------------------------------------------------- * * TclGlobalInvoke -- * * Invokes a Tcl command, given an argv/argc, from either the * exposed or hidden sets of commands in the given interpreter. * NOTE: The command is invoked in the global stack frame of * the interpreter, thus it cannot see any current state on * the stack for that interpreter. * * Results: * A standard Tcl result. * * Side effects: * Whatever the command does. * *---------------------------------------------------------------------- */ int TclGlobalInvoke(interp, argc, argv, flags) Tcl_Interp *interp; /* Where to invoke the command. */ int argc; /* Count of args. */ register CONST char **argv; /* The arg strings; argv[0] is the name of * the command to invoke. */ int flags; /* Combination of flags controlling the * call: TCL_INVOKE_HIDDEN and * TCL_INVOKE_NO_UNKNOWN. */ { register Interp *iPtr = (Interp *) interp; int result; CallFrame *savedVarFramePtr; savedVarFramePtr = iPtr->varFramePtr; iPtr->varFramePtr = NULL; result = TclInvoke(interp, argc, argv, flags); iPtr->varFramePtr = savedVarFramePtr; return result; } /* *---------------------------------------------------------------------- * * TclObjInvokeGlobal -- * * Object version: Invokes a Tcl command, given an objv/objc, from * either the exposed or hidden set of commands in the given * interpreter. * NOTE: The command is invoked in the global stack frame of the * interpreter, thus it cannot see any current state on the * stack of that interpreter. * * Results: * A standard Tcl result. * * Side effects: * Whatever the command does. * *---------------------------------------------------------------------- */ int TclObjInvokeGlobal(interp, objc, objv, flags) Tcl_Interp *interp; /* Interpreter in which command is to be * invoked. */ int objc; /* Count of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects; objv[0] points to the * name of the command to invoke. */ int flags; /* Combination of flags controlling the * call: TCL_INVOKE_HIDDEN, * TCL_INVOKE_NO_UNKNOWN, or * TCL_INVOKE_NO_TRACEBACK. */ { register Interp *iPtr = (Interp *) interp; int result; CallFrame *savedVarFramePtr; savedVarFramePtr = iPtr->varFramePtr; iPtr->varFramePtr = NULL; result = TclObjInvoke(interp, objc, objv, flags); iPtr->varFramePtr = savedVarFramePtr; return result; } /* *---------------------------------------------------------------------- * * TclObjInvoke -- * * Invokes a Tcl command, given an objv/objc, from either the * exposed or the hidden sets of commands in the given interpreter. * * Results: * A standard Tcl object result. * * Side effects: * Whatever the command does. * *---------------------------------------------------------------------- */ int TclObjInvoke(interp, objc, objv, flags) Tcl_Interp *interp; /* Interpreter in which command is to be * invoked. */ int objc; /* Count of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects; objv[0] points to the * name of the command to invoke. */ int flags; /* Combination of flags controlling the * call: TCL_INVOKE_HIDDEN, * TCL_INVOKE_NO_UNKNOWN, or * TCL_INVOKE_NO_TRACEBACK. */ { register Interp *iPtr = (Interp *) interp; Tcl_HashTable *hTblPtr; /* Table of hidden commands. */ char *cmdName; /* Name of the command from objv[0]. */ register Tcl_HashEntry *hPtr; Tcl_Command cmd; Command *cmdPtr; int localObjc; /* Used to invoke "unknown" if the */ Tcl_Obj **localObjv = NULL; /* command is not found. */ register int i; int result; if (interp == (Tcl_Interp *) NULL) { return TCL_ERROR; } if ((objc < 1) || (objv == (Tcl_Obj **) NULL)) { Tcl_AppendToObj(Tcl_GetObjResult(interp), "illegal argument vector", -1); return TCL_ERROR; } cmdName = Tcl_GetString(objv[0]); if (flags & TCL_INVOKE_HIDDEN) { /* * We never invoke "unknown" for hidden commands. */ hPtr = NULL; hTblPtr = ((Interp *) interp)->hiddenCmdTablePtr; if (hTblPtr != NULL) { hPtr = Tcl_FindHashEntry(hTblPtr, cmdName); } if (hPtr == NULL) { Tcl_ResetResult(interp); Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "invalid hidden command name \"", cmdName, "\"", (char *) NULL); return TCL_ERROR; } cmdPtr = (Command *) Tcl_GetHashValue(hPtr); } else { cmdPtr = NULL; cmd = Tcl_FindCommand(interp, cmdName, (Tcl_Namespace *) NULL, /*flags*/ TCL_GLOBAL_ONLY); if (cmd != (Tcl_Command) NULL) { cmdPtr = (Command *) cmd; } if (cmdPtr == NULL) { if (!(flags & TCL_INVOKE_NO_UNKNOWN)) { cmd = Tcl_FindCommand(interp, "unknown", (Tcl_Namespace *) NULL, /*flags*/ TCL_GLOBAL_ONLY); if (cmd != (Tcl_Command) NULL) { cmdPtr = (Command *) cmd; } if (cmdPtr != NULL) { localObjc = (objc + 1); localObjv = (Tcl_Obj **) ckalloc((unsigned) (sizeof(Tcl_Obj *) * localObjc)); localObjv[0] = Tcl_NewStringObj("unknown", -1); Tcl_IncrRefCount(localObjv[0]); for (i = 0; i < objc; i++) { localObjv[i+1] = objv[i]; } objc = localObjc; objv = localObjv; } } /* * Check again if we found the command. If not, "unknown" is * not present and we cannot help, or the caller said not to * call "unknown" (they specified TCL_INVOKE_NO_UNKNOWN). */ if (cmdPtr == NULL) { Tcl_ResetResult(interp); Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "invalid command name \"", cmdName, "\"", (char *) NULL); return TCL_ERROR; } } } /* * Invoke the command procedure. First reset the interpreter's string * and object results to their default empty values since they could * have gotten changed by earlier invocations. */ Tcl_ResetResult(interp); iPtr->cmdCount++; result = (*cmdPtr->objProc)(cmdPtr->objClientData, interp, objc, objv); /* * If an error occurred, record information about what was being * executed when the error occurred. */ if ((result == TCL_ERROR) && ((flags & TCL_INVOKE_NO_TRACEBACK) == 0) && ((iPtr->flags & ERR_ALREADY_LOGGED) == 0)) { Tcl_Obj *msg; if (!(iPtr->flags & ERR_IN_PROGRESS)) { msg = Tcl_NewStringObj("\n while invoking\n\"", -1); } else { msg = Tcl_NewStringObj("\n invoked from within\n\"", -1); } Tcl_IncrRefCount(msg); for (i = 0; i < objc; i++) { CONST char *bytes; int length; Tcl_AppendObjToObj(msg, objv[i]); bytes = Tcl_GetStringFromObj(msg, &length); if (length > 100) { /* * Back up truncation point so that we don't truncate * in the middle of a multi-byte character. */ length = 100; while ( (bytes[length] & 0xC0) == 0x80 ) { length--; } Tcl_SetObjLength(msg, length); Tcl_AppendToObj(msg, "...", -1); break; } if (i != (objc - 1)) { Tcl_AppendToObj(msg, " ", -1); } } Tcl_AppendToObj(msg, "\"", -1); Tcl_AddObjErrorInfo(interp, Tcl_GetString(msg), -1); Tcl_DecrRefCount(msg); iPtr->flags &= ~ERR_ALREADY_LOGGED; } /* * Free any locally allocated storage used to call "unknown". */ if (localObjv != (Tcl_Obj **) NULL) { Tcl_DecrRefCount(localObjv[0]); ckfree((char *) localObjv); } return result; } /* *--------------------------------------------------------------------------- * * Tcl_ExprString -- * * Evaluate an expression in a string and return its value in string * form. * * Results: * A standard Tcl result. If the result is TCL_OK, then the interp's * result is set to the string value of the expression. If the result * is TCL_ERROR, then the interp's result contains an error message. * * Side effects: * A Tcl object is allocated to hold a copy of the expression string. * This expression object is passed to Tcl_ExprObj and then * deallocated. * *--------------------------------------------------------------------------- */ int Tcl_ExprString(interp, string) Tcl_Interp *interp; /* Context in which to evaluate the * expression. */ CONST char *string; /* Expression to evaluate. */ { register Tcl_Obj *exprPtr; Tcl_Obj *resultPtr; int length = strlen(string); char buf[TCL_DOUBLE_SPACE]; int result = TCL_OK; if (length > 0) { TclNewObj(exprPtr); TclInitStringRep(exprPtr, string, length); Tcl_IncrRefCount(exprPtr); result = Tcl_ExprObj(interp, exprPtr, &resultPtr); if (result == TCL_OK) { /* * Set the interpreter's string result from the result object. */ if (resultPtr->typePtr == &tclIntType) { sprintf(buf, "%ld", resultPtr->internalRep.longValue); Tcl_SetResult(interp, buf, TCL_VOLATILE); } else if (resultPtr->typePtr == &tclDoubleType) { Tcl_PrintDouble((Tcl_Interp *) NULL, resultPtr->internalRep.doubleValue, buf); Tcl_SetResult(interp, buf, TCL_VOLATILE); } else { /* * Set interpreter's string result from the result object. */ Tcl_SetResult(interp, TclGetString(resultPtr), TCL_VOLATILE); } Tcl_DecrRefCount(resultPtr); /* discard the result object */ } else { /* * Move the interpreter's object result to the string result, * then reset the object result. */ Tcl_SetResult(interp, TclGetString(Tcl_GetObjResult(interp)), TCL_VOLATILE); } Tcl_DecrRefCount(exprPtr); /* discard the expression object */ } else { /* * An empty string. Just set the interpreter's result to 0. */ Tcl_SetResult(interp, "0", TCL_VOLATILE); } return result; } /* *---------------------------------------------------------------------- * * Tcl_CreateObjTrace -- * * Arrange for a procedure to be called to trace command execution. * * Results: * The return value is a token for the trace, which may be passed * to Tcl_DeleteTrace to eliminate the trace. * * Side effects: * From now on, proc will be called just before a command procedure * is called to execute a Tcl command. Calls to proc will have the * following form: * * void proc( ClientData clientData, * Tcl_Interp* interp, * int level, * CONST char* command, * Tcl_Command commandInfo, * int objc, * Tcl_Obj *CONST objv[] ); * * The 'clientData' and 'interp' arguments to 'proc' will be the * same as the arguments to Tcl_CreateObjTrace. The 'level' * argument gives the nesting depth of command interpretation within * the interpreter. The 'command' argument is the ASCII text of * the command being evaluated -- before any substitutions are * performed. The 'commandInfo' argument gives a handle to the * command procedure that will be evaluated. The 'objc' and 'objv' * parameters give the parameter vector that will be passed to the * command procedure. proc does not return a value. * * It is permissible for 'proc' to call Tcl_SetCommandTokenInfo * to change the command procedure or client data for the command * being evaluated, and these changes will take effect with the * current evaluation. * * The 'level' argument specifies the maximum nesting level of calls * to be traced. If the execution depth of the interpreter exceeds * 'level', the trace callback is not executed. * * The 'flags' argument is either zero or the value, * TCL_ALLOW_INLINE_COMPILATION. If the TCL_ALLOW_INLINE_COMPILATION * flag is not present, the bytecode compiler will not generate inline * code for Tcl's built-in commands. This behavior will have a significant * impact on performance, but will ensure that all command evaluations are * traced. If the TCL_ALLOW_INLINE_COMPILATION flag is present, the * bytecode compiler will have its normal behavior of compiling in-line * code for some of Tcl's built-in commands. In this case, the tracing * will be imprecise -- in-line code will not be traced -- but run-time * performance will be improved. The latter behavior is desired for * many applications such as profiling of run time. * * When the trace is deleted, the 'delProc' procedure will be invoked, * passing it the original client data. * *---------------------------------------------------------------------- */ Tcl_Trace Tcl_CreateObjTrace( interp, level, flags, proc, clientData, delProc ) Tcl_Interp* interp; /* Tcl interpreter */ int level; /* Maximum nesting level */ int flags; /* Flags, see above */ Tcl_CmdObjTraceProc* proc; /* Trace callback */ ClientData clientData; /* Client data for the callback */ Tcl_CmdObjTraceDeleteProc* delProc; /* Procedure to call when trace is deleted */ { register Trace *tracePtr; register Interp *iPtr = (Interp *) interp; /* Test if this trace allows inline compilation of commands */ if (!(flags & TCL_ALLOW_INLINE_COMPILATION)) { if (iPtr->tracesForbiddingInline == 0) { /* * When the first trace forbidding inline compilation is * created, invalidate existing compiled code for this * interpreter and arrange (by setting the * DONT_COMPILE_CMDS_INLINE flag) that when compiling new * code, no commands will be compiled inline (i.e., into * an inline sequence of instructions). We do this because * commands that were compiled inline will never result in * a command trace being called. */ iPtr->compileEpoch++; iPtr->flags |= DONT_COMPILE_CMDS_INLINE; } iPtr->tracesForbiddingInline++; } tracePtr = (Trace *) ckalloc(sizeof(Trace)); tracePtr->level = level; tracePtr->proc = proc; tracePtr->clientData = clientData; tracePtr->delProc = delProc; tracePtr->nextPtr = iPtr->tracePtr; tracePtr->flags = flags; iPtr->tracePtr = tracePtr; return (Tcl_Trace) tracePtr; } /* *---------------------------------------------------------------------- * * Tcl_CreateTrace -- * * Arrange for a procedure to be called to trace command execution. * * Results: * The return value is a token for the trace, which may be passed * to Tcl_DeleteTrace to eliminate the trace. * * Side effects: * From now on, proc will be called just before a command procedure * is called to execute a Tcl command. Calls to proc will have the * following form: * * void * proc(clientData, interp, level, command, cmdProc, cmdClientData, * argc, argv) * ClientData clientData; * Tcl_Interp *interp; * int level; * char *command; * int (*cmdProc)(); * ClientData cmdClientData; * int argc; * char **argv; * { * } * * The clientData and interp arguments to proc will be the same * as the corresponding arguments to this procedure. Level gives * the nesting level of command interpretation for this interpreter * (0 corresponds to top level). Command gives the ASCII text of * the raw command, cmdProc and cmdClientData give the procedure that * will be called to process the command and the ClientData value it * will receive, and argc and argv give the arguments to the * command, after any argument parsing and substitution. Proc * does not return a value. * *---------------------------------------------------------------------- */ Tcl_Trace Tcl_CreateTrace(interp, level, proc, clientData) Tcl_Interp *interp; /* Interpreter in which to create trace. */ int level; /* Only call proc for commands at nesting * level<=argument level (1=>top level). */ Tcl_CmdTraceProc *proc; /* Procedure to call before executing each * command. */ ClientData clientData; /* Arbitrary value word to pass to proc. */ { StringTraceData* data; data = (StringTraceData*) ckalloc( sizeof( *data )); data->clientData = clientData; data->proc = proc; return Tcl_CreateObjTrace( interp, level, 0, StringTraceProc, (ClientData) data, StringTraceDeleteProc ); } /* *---------------------------------------------------------------------- * * StringTraceProc -- * * Invoke a string-based trace procedure from an object-based * callback. * * Results: * None. * * Side effects: * Whatever the string-based trace procedure does. * *---------------------------------------------------------------------- */ static int StringTraceProc( clientData, interp, level, command, commandInfo, objc, objv ) ClientData clientData; Tcl_Interp* interp; int level; CONST char* command; Tcl_Command commandInfo; int objc; Tcl_Obj *CONST *objv; { StringTraceData* data = (StringTraceData*) clientData; Command* cmdPtr = (Command*) commandInfo; CONST char** argv; /* Args to pass to string trace proc */ int i; /* * This is a bit messy because we have to emulate the old trace * interface, which uses strings for everything. */ argv = (CONST char **) ckalloc((unsigned) ( (objc + 1) * sizeof(CONST char *) )); for (i = 0; i < objc; i++) { argv[i] = Tcl_GetString(objv[i]); } argv[objc] = 0; /* * Invoke the command procedure. Note that we cast away const-ness * on two parameters for compatibility with legacy code; the code * MUST NOT modify either command or argv. */ ( data->proc )( data->clientData, interp, level, (char*) command, cmdPtr->proc, cmdPtr->clientData, objc, argv ); ckfree( (char*) argv ); return TCL_OK; } /* *---------------------------------------------------------------------- * * StringTraceDeleteProc -- * * Clean up memory when a string-based trace is deleted. * * Results: * None. * * Side effects: * Allocated memory is returned to the system. * *---------------------------------------------------------------------- */ static void StringTraceDeleteProc( clientData ) ClientData clientData; { ckfree( (char*) clientData ); } /* *---------------------------------------------------------------------- * * Tcl_DeleteTrace -- * * Remove a trace. * * Results: * None. * * Side effects: * From now on there will be no more calls to the procedure given * in trace. * *---------------------------------------------------------------------- */ void Tcl_DeleteTrace(interp, trace) Tcl_Interp *interp; /* Interpreter that contains trace. */ Tcl_Trace trace; /* Token for trace (returned previously by * Tcl_CreateTrace). */ { Interp *iPtr = (Interp *) interp; Trace *prevPtr, *tracePtr = (Trace *) trace; register Trace **tracePtr2 = &(iPtr->tracePtr); ActiveInterpTrace *activePtr; /* * Locate the trace entry in the interpreter's trace list, * and remove it from the list. */ prevPtr = NULL; while ((*tracePtr2) != NULL && (*tracePtr2) != tracePtr) { prevPtr = *tracePtr2; tracePtr2 = &((*tracePtr2)->nextPtr); } if (*tracePtr2 == NULL) { return; } (*tracePtr2) = (*tracePtr2)->nextPtr; /* * The code below makes it possible to delete traces while traces * are active: it makes sure that the deleted trace won't be * processed by TclCheckInterpTraces. */ for (activePtr = iPtr->activeInterpTracePtr; activePtr != NULL; activePtr = activePtr->nextPtr) { if (activePtr->nextTracePtr == tracePtr) { if (activePtr->reverseScan) { activePtr->nextTracePtr = prevPtr; } else { activePtr->nextTracePtr = tracePtr->nextPtr; } } } /* * If the trace forbids bytecode compilation, change the interpreter's * state. If bytecode compilation is now permitted, flag the fact and * advance the compilation epoch so that procs will be recompiled to * take advantage of it. */ if (!(tracePtr->flags & TCL_ALLOW_INLINE_COMPILATION)) { iPtr->tracesForbiddingInline--; if (iPtr->tracesForbiddingInline == 0) { iPtr->flags &= ~DONT_COMPILE_CMDS_INLINE; iPtr->compileEpoch++; } } /* * Execute any delete callback. */ if (tracePtr->delProc != NULL) { (tracePtr->delProc)(tracePtr->clientData); } /* Delete the trace object */ Tcl_EventuallyFree((char*)tracePtr, TCL_DYNAMIC); } /* *---------------------------------------------------------------------- * * Tcl_AddErrorInfo -- * * Add information to the "errorInfo" variable that describes the * current error. * * Results: * None. * * Side effects: * The contents of message are added to the "errorInfo" variable. * If Tcl_Eval has been called since the current value of errorInfo * was set, errorInfo is cleared before adding the new message. * If we are just starting to log an error, errorInfo is initialized * from the error message in the interpreter's result. * *---------------------------------------------------------------------- */ void Tcl_AddErrorInfo(interp, message) Tcl_Interp *interp; /* Interpreter to which error information * pertains. */ CONST char *message; /* Message to record. */ { Tcl_AddObjErrorInfo(interp, message, -1); } /* *---------------------------------------------------------------------- * * Tcl_AddObjErrorInfo -- * * Add information to the "errorInfo" variable that describes the * current error. This routine differs from Tcl_AddErrorInfo by * taking a byte pointer and length. * * Results: * None. * * Side effects: * "length" bytes from "message" are added to the "errorInfo" variable. * If "length" is negative, use bytes up to the first NULL byte. * If Tcl_EvalObj has been called since the current value of errorInfo * was set, errorInfo is cleared before adding the new message. * If we are just starting to log an error, errorInfo is initialized * from the error message in the interpreter's result. * *---------------------------------------------------------------------- */ void Tcl_AddObjErrorInfo(interp, message, length) Tcl_Interp *interp; /* Interpreter to which error information * pertains. */ CONST char *message; /* Points to the first byte of an array of * bytes of the message. */ int length; /* The number of bytes in the message. * If < 0, then append all bytes up to a * NULL byte. */ { register Interp *iPtr = (Interp *) interp; Tcl_Obj *objPtr; /* * If we are just starting to log an error, errorInfo is initialized * from the error message in the interpreter's result. */ if (!(iPtr->flags & ERR_IN_PROGRESS)) { /* just starting to log error */ iPtr->flags |= ERR_IN_PROGRESS; if (iPtr->result[0] == 0) { Tcl_ObjSetVar2(interp, iPtr->execEnvPtr->errorInfo, NULL, iPtr->objResultPtr, TCL_GLOBAL_ONLY); } else { /* use the string result */ objPtr = Tcl_NewStringObj(interp->result, -1); Tcl_IncrRefCount(objPtr); Tcl_ObjSetVar2(interp, iPtr->execEnvPtr->errorInfo, NULL, objPtr, TCL_GLOBAL_ONLY); Tcl_DecrRefCount(objPtr); } /* * If the errorCode variable wasn't set by the code that generated * the error, set it to "NONE". */ if (!(iPtr->flags & ERROR_CODE_SET)) { objPtr = Tcl_NewStringObj("NONE", -1); Tcl_IncrRefCount(objPtr); Tcl_ObjSetVar2(interp, iPtr->execEnvPtr->errorCode, NULL, objPtr, TCL_GLOBAL_ONLY); Tcl_DecrRefCount(objPtr); } } /* * Now append "message" to the end of errorInfo. */ if (length != 0) { objPtr = Tcl_NewStringObj(message, length); Tcl_IncrRefCount(objPtr); Tcl_ObjSetVar2(interp, iPtr->execEnvPtr->errorInfo, NULL, objPtr, (TCL_GLOBAL_ONLY | TCL_APPEND_VALUE)); Tcl_DecrRefCount(objPtr); /* free msg object appended above */ } } /* *--------------------------------------------------------------------------- * * Tcl_VarEvalVA -- * * Given a variable number of string arguments, concatenate them * all together and execute the result as a Tcl command. * * Results: * A standard Tcl return result. An error message or other result may * be left in the interp's result. * * Side effects: * Depends on what was done by the command. * *--------------------------------------------------------------------------- */ int Tcl_VarEvalVA (interp, argList) Tcl_Interp *interp; /* Interpreter in which to evaluate command. */ va_list argList; /* Variable argument list. */ { Tcl_DString buf; char *string; int result; /* * Copy the strings one after the other into a single larger * string. Use stack-allocated space for small commands, but if * the command gets too large than call ckalloc to create the * space. */ Tcl_DStringInit(&buf); while (1) { string = va_arg(argList, char *); if (string == NULL) { break; } Tcl_DStringAppend(&buf, string, -1); } result = Tcl_Eval(interp, Tcl_DStringValue(&buf)); Tcl_DStringFree(&buf); return result; } /* *---------------------------------------------------------------------- * * Tcl_VarEval -- * * Given a variable number of string arguments, concatenate them * all together and execute the result as a Tcl command. * * Results: * A standard Tcl return result. An error message or other * result may be left in interp->result. * * Side effects: * Depends on what was done by the command. * *---------------------------------------------------------------------- */ /* VARARGS2 */ /* ARGSUSED */ int Tcl_VarEval TCL_VARARGS_DEF(Tcl_Interp *,arg1) { Tcl_Interp *interp; va_list argList; int result; interp = TCL_VARARGS_START(Tcl_Interp *,arg1,argList); result = Tcl_VarEvalVA(interp, argList); va_end(argList); return result; } /* *--------------------------------------------------------------------------- * * Tcl_GlobalEval -- * * Evaluate a command at global level in an interpreter. * * Results: * A standard Tcl result is returned, and the interp's result is * modified accordingly. * * Side effects: * The command string is executed in interp, and the execution * is carried out in the variable context of global level (no * procedures active), just as if an "uplevel #0" command were * being executed. * --------------------------------------------------------------------------- */ int Tcl_GlobalEval(interp, command) Tcl_Interp *interp; /* Interpreter in which to evaluate command. */ CONST char *command; /* Command to evaluate. */ { register Interp *iPtr = (Interp *) interp; int result; CallFrame *savedVarFramePtr; savedVarFramePtr = iPtr->varFramePtr; iPtr->varFramePtr = NULL; result = Tcl_Eval(interp, command); iPtr->varFramePtr = savedVarFramePtr; return result; } /* *---------------------------------------------------------------------- * * Tcl_SetRecursionLimit -- * * Set the maximum number of recursive calls that may be active * for an interpreter at once. * * Results: * The return value is the old limit on nesting for interp. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_SetRecursionLimit(interp, depth) Tcl_Interp *interp; /* Interpreter whose nesting limit * is to be set. */ int depth; /* New value for maximimum depth. */ { Interp *iPtr = (Interp *) interp; int old; old = iPtr->maxNestingDepth; if (depth > 0) { iPtr->maxNestingDepth = depth; } return old; } /* *---------------------------------------------------------------------- * * Tcl_AllowExceptions -- * * Sets a flag in an interpreter so that exceptions can occur * in the next call to Tcl_Eval without them being turned into * errors. * * Results: * None. * * Side effects: * The TCL_ALLOW_EXCEPTIONS flag gets set in the interpreter's * evalFlags structure. See the reference documentation for * more details. * *---------------------------------------------------------------------- */ void Tcl_AllowExceptions(interp) Tcl_Interp *interp; /* Interpreter in which to set flag. */ { Interp *iPtr = (Interp *) interp; iPtr->evalFlags |= TCL_ALLOW_EXCEPTIONS; } /* *---------------------------------------------------------------------- * * Tcl_GetVersion * * Get the Tcl major, minor, and patchlevel version numbers and * the release type. A patch is a release type TCL_FINAL_RELEASE * with a patchLevel > 0. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Tcl_GetVersion(majorV, minorV, patchLevelV, type) int *majorV; int *minorV; int *patchLevelV; int *type; { if (majorV != NULL) { *majorV = TCL_MAJOR_VERSION; } if (minorV != NULL) { *minorV = TCL_MINOR_VERSION; } if (patchLevelV != NULL) { *patchLevelV = TCL_RELEASE_SERIAL; } if (type != NULL) { *type = TCL_RELEASE_LEVEL; } } #ifdef USE_DTRACE /* *---------------------------------------------------------------------- * * DTraceObjCmd -- * * This function is invoked to process the "::tcl::dtrace" Tcl command. * * Results: * A standard Tcl object result. * * Side effects: * The 'tcl-probe' DTrace probe is triggered (if it is enabled). * *---------------------------------------------------------------------- */ static int DTraceObjCmd( ClientData dummy, /* Not used. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[]) /* Argument objects. */ { if (TCL_DTRACE_TCL_PROBE_ENABLED()) { char *a[10]; int i = 0; while (i++ < 10) { a[i-1] = i < objc ? TclGetString(objv[i]) : NULL; } TCL_DTRACE_TCL_PROBE(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9]); } return TCL_OK; } TCL_DTRACE_DEBUG_LOG() #endif /* USE_DTRACE */ /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ tcl8.4.20/generic/tclProc.c0000644003604700454610000016452311737050674014120 0ustar dgp771div/* * tclProc.c -- * * This file contains routines that implement Tcl procedures, * including the "proc" and "uplevel" commands. * * Copyright (c) 1987-1993 The Regents of the University of California. * Copyright (c) 1994-1998 Sun Microsystems, Inc. * Copyright (c) 2007 Daniel A. Steffen * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclCompile.h" /* * Prototypes for static functions in this file */ static void ProcBodyDup _ANSI_ARGS_((Tcl_Obj *srcPtr, Tcl_Obj *dupPtr)); static void ProcBodyFree _ANSI_ARGS_((Tcl_Obj *objPtr)); static int ProcBodySetFromAny _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr)); static void ProcBodyUpdateString _ANSI_ARGS_((Tcl_Obj *objPtr)); static int ProcCompileProc _ANSI_ARGS_((Tcl_Interp *interp, Proc *procPtr, Tcl_Obj *bodyPtr, Namespace *nsPtr, CONST char *description, CONST char *procName, Proc **procPtrPtr)); static int ProcessProcResultCode _ANSI_ARGS_((Tcl_Interp *interp, char *procName, int nameLen, int returnCode)); static int TclCompileNoOp _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Parse *parsePtr, struct CompileEnv *envPtr)); /* * The ProcBodyObjType type */ Tcl_ObjType tclProcBodyType = { "procbody", /* name for this type */ ProcBodyFree, /* FreeInternalRep procedure */ ProcBodyDup, /* DupInternalRep procedure */ ProcBodyUpdateString, /* UpdateString procedure */ ProcBodySetFromAny /* SetFromAny procedure */ }; /* *---------------------------------------------------------------------- * * Tcl_ProcObjCmd -- * * This object-based procedure is invoked to process the "proc" Tcl * command. See the user documentation for details on what it does. * * Results: * A standard Tcl object result value. * * Side effects: * A new procedure gets created. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_ProcObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { register Interp *iPtr = (Interp *) interp; Proc *procPtr; char *fullName; CONST char *procName, *procArgs, *procBody; Namespace *nsPtr, *altNsPtr, *cxtNsPtr; Tcl_Command cmd; Tcl_DString ds; if (objc != 4) { Tcl_WrongNumArgs(interp, 1, objv, "name args body"); return TCL_ERROR; } /* * Determine the namespace where the procedure should reside. Unless * the command name includes namespace qualifiers, this will be the * current namespace. */ fullName = TclGetString(objv[1]); TclGetNamespaceForQualName(interp, fullName, (Namespace *) NULL, 0, &nsPtr, &altNsPtr, &cxtNsPtr, &procName); if (nsPtr == NULL) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "can't create procedure \"", fullName, "\": unknown namespace", (char *) NULL); return TCL_ERROR; } if (procName == NULL) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "can't create procedure \"", fullName, "\": bad procedure name", (char *) NULL); return TCL_ERROR; } if ((nsPtr != iPtr->globalNsPtr) && (procName != NULL) && (procName[0] == ':')) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "can't create procedure \"", procName, "\" in non-global namespace with name starting with \":\"", (char *) NULL); return TCL_ERROR; } /* * Create the data structure to represent the procedure. */ if (TclCreateProc(interp, nsPtr, procName, objv[2], objv[3], &procPtr) != TCL_OK) { return TCL_ERROR; } /* * Now create a command for the procedure. This will initially be in * the current namespace unless the procedure's name included namespace * qualifiers. To create the new command in the right namespace, we * generate a fully qualified name for it. */ Tcl_DStringInit(&ds); if (nsPtr != iPtr->globalNsPtr) { Tcl_DStringAppend(&ds, nsPtr->fullName, -1); Tcl_DStringAppend(&ds, "::", 2); } Tcl_DStringAppend(&ds, procName, -1); Tcl_CreateCommand(interp, Tcl_DStringValue(&ds), TclProcInterpProc, (ClientData) procPtr, TclProcDeleteProc); cmd = Tcl_CreateObjCommand(interp, Tcl_DStringValue(&ds), TclObjInterpProc, (ClientData) procPtr, TclProcDeleteProc); Tcl_DStringFree(&ds); /* * Now initialize the new procedure's cmdPtr field. This will be used * later when the procedure is called to determine what namespace the * procedure will run in. This will be different than the current * namespace if the proc was renamed into a different namespace. */ procPtr->cmdPtr = (Command *) cmd; #ifdef TCL_TIP280 /* TIP #280 Remember the line the procedure body is starting on. In a * Byte code context we ask the engine to provide us with the necessary * information. This is for the initialization of the byte code compiler * when the body is used for the first time. */ if (iPtr->cmdFramePtr) { CmdFrame context = *iPtr->cmdFramePtr; if (context.type == TCL_LOCATION_BC) { TclGetSrcInfoForPc (&context); /* May get path in context */ } else if (context.type == TCL_LOCATION_SOURCE) { /* context now holds another reference */ Tcl_IncrRefCount (context.data.eval.path); } /* type == TCL_LOCATION_PREBC implies that 'line' is NULL here! We * cannot assume that 'line' is valid here, we have to check. If the * outer context is an eval (bc, prebc, eval) we do not save any * information. Counting relative to the beginning of the proc body is * more sensible than counting relative to the outer eval block. */ if ((context.type == TCL_LOCATION_SOURCE) && context.line && (context.nline >= 4) && (context.line [3] >= 0)) { int isNew; Tcl_HashEntry* hePtr; CmdFrame* cfPtr = (CmdFrame*) ckalloc (sizeof (CmdFrame)); cfPtr->level = -1; cfPtr->type = context.type; cfPtr->line = (int*) ckalloc (sizeof (int)); cfPtr->line [0] = context.line [3]; cfPtr->nline = 1; cfPtr->framePtr = NULL; cfPtr->nextPtr = NULL; if (context.type == TCL_LOCATION_SOURCE) { cfPtr->data.eval.path = context.data.eval.path; /* Transfer of reference. The reference going away (release of * the context) is replaced by the reference in the * constructed cmdframe */ } else { cfPtr->type = TCL_LOCATION_EVAL; cfPtr->data.eval.path = NULL; } cfPtr->cmd.str.cmd = NULL; cfPtr->cmd.str.len = 0; hePtr = Tcl_CreateHashEntry (iPtr->linePBodyPtr, (char*) procPtr, &isNew); if (!isNew) { /* * Get the old command frame and release it. See also * TclProcCleanupProc in this file. Currently it seems as if * only the procbodytest::proc command of the testsuite is * able to trigger this situation. */ CmdFrame* cfOldPtr = (CmdFrame *) Tcl_GetHashValue(hePtr); if (cfOldPtr->type == TCL_LOCATION_SOURCE) { Tcl_DecrRefCount(cfOldPtr->data.eval.path); cfOldPtr->data.eval.path = NULL; } ckfree((char *) cfOldPtr->line); cfOldPtr->line = NULL; ckfree((char *) cfOldPtr); } Tcl_SetHashValue (hePtr, cfPtr); } } #endif /* * Optimize for noop procs: if the body is not precompiled (like a TclPro * procbody), and the argument list is just "args" and the body is empty, * define a compileProc to compile a noop. * * Notes: * - cannot be done for any argument list without having different * compiled/not-compiled behaviour in the "wrong argument #" case, * or making this code much more complicated. In any case, it doesn't * seem to make a lot of sense to verify the number of arguments we * are about to ignore ... * - could be enhanced to handle also non-empty bodies that contain * only comments; however, parsing the body will slow down the * compilation of all procs whose argument list is just _args_ */ if (objv[3]->typePtr == &tclProcBodyType) { goto done; } procArgs = Tcl_GetString(objv[2]); while (*procArgs == ' ') { procArgs++; } if ((procArgs[0] == 'a') && (strncmp(procArgs, "args", 4) == 0)) { procArgs +=4; while(*procArgs != '\0') { if (*procArgs != ' ') { goto done; } procArgs++; } /* * The argument list is just "args"; check the body */ procBody = Tcl_GetString(objv[3]); while (*procBody != '\0') { if (!isspace(UCHAR(*procBody))) { goto done; } procBody++; } /* * The body is just spaces: link the compileProc */ ((Command *) cmd)->compileProc = TclCompileNoOp; } done: return TCL_OK; } /* *---------------------------------------------------------------------- * * TclCreateProc -- * * Creates the data associated with a Tcl procedure definition. * This procedure knows how to handle two types of body objects: * strings and procbody. Strings are the traditional (and common) value * for bodies, procbody are values created by extensions that have * loaded a previously compiled script. * * Results: * Returns TCL_OK on success, along with a pointer to a Tcl * procedure definition in procPtrPtr. This definition should * be freed by calling TclCleanupProc() when it is no longer * needed. Returns TCL_ERROR if anything goes wrong. * * Side effects: * If anything goes wrong, this procedure returns an error * message in the interpreter. * *---------------------------------------------------------------------- */ int TclCreateProc(interp, nsPtr, procName, argsPtr, bodyPtr, procPtrPtr) Tcl_Interp *interp; /* interpreter containing proc */ Namespace *nsPtr; /* namespace containing this proc */ CONST char *procName; /* unqualified name of this proc */ Tcl_Obj *argsPtr; /* description of arguments */ Tcl_Obj *bodyPtr; /* command body */ Proc **procPtrPtr; /* returns: pointer to proc data */ { Interp *iPtr = (Interp*)interp; CONST char **argArray = NULL; register Proc *procPtr; int i, length, result, numArgs; CONST char *args, *bytes, *p; register CompiledLocal *localPtr = NULL; Tcl_Obj *defPtr; int precompiled = 0; if (bodyPtr->typePtr == &tclProcBodyType) { /* * Because the body is a TclProProcBody, the actual body is already * compiled, and it is not shared with anyone else, so it's OK not to * unshare it (as a matter of fact, it is bad to unshare it, because * there may be no source code). * * We don't create and initialize a Proc structure for the procedure; * rather, we use what is in the body object. Note that * we initialize its cmdPtr field below after we've created the command * for the procedure. We increment the ref count of the Proc struct * since the command (soon to be created) will be holding a reference * to it. */ procPtr = (Proc *) bodyPtr->internalRep.otherValuePtr; procPtr->iPtr = iPtr; procPtr->refCount++; precompiled = 1; } else { /* * If the procedure's body object is shared because its string value is * identical to, e.g., the body of another procedure, we must create a * private copy for this procedure to use. Such sharing of procedure * bodies is rare but can cause problems. A procedure body is compiled * in a context that includes the number of compiler-allocated "slots" * for local variables. Each formal parameter is given a local variable * slot (the "procPtr->numCompiledLocals = numArgs" assignment * below). This means that the same code can not be shared by two * procedures that have a different number of arguments, even if their * bodies are identical. Note that we don't use Tcl_DuplicateObj since * we would not want any bytecode internal representation. */ if (Tcl_IsShared(bodyPtr)) { #ifdef TCL_TIP280 Tcl_Obj* sharedBodyPtr = bodyPtr; #endif bytes = Tcl_GetStringFromObj(bodyPtr, &length); bodyPtr = Tcl_NewStringObj(bytes, length); #ifdef TCL_TIP280 /* * TIP #280. * Ensure that the continuation line data for the original body is * not lost and applies to the new body as well. */ TclContinuationsCopy (bodyPtr, sharedBodyPtr); #endif } /* * Create and initialize a Proc structure for the procedure. Note that * we initialize its cmdPtr field below after we've created the command * for the procedure. We increment the ref count of the procedure's * body object since there will be a reference to it in the Proc * structure. */ Tcl_IncrRefCount(bodyPtr); procPtr = (Proc *) ckalloc(sizeof(Proc)); procPtr->iPtr = iPtr; procPtr->refCount = 1; procPtr->bodyPtr = bodyPtr; procPtr->numArgs = 0; /* actual argument count is set below. */ procPtr->numCompiledLocals = 0; procPtr->firstLocalPtr = NULL; procPtr->lastLocalPtr = NULL; } /* * Break up the argument list into argument specifiers, then process * each argument specifier. * If the body is precompiled, processing is limited to checking that * the the parsed argument is consistent with the one stored in the * Proc. * THIS FAILS IF THE ARG LIST OBJECT'S STRING REP CONTAINS NULLS. */ args = Tcl_GetStringFromObj(argsPtr, &length); result = Tcl_SplitList(interp, args, &numArgs, &argArray); if (result != TCL_OK) { goto procError; } if (precompiled) { if (numArgs > procPtr->numArgs) { char buf[64 + TCL_INTEGER_SPACE + TCL_INTEGER_SPACE]; sprintf(buf, "\": arg list contains %d entries, precompiled header expects %d", numArgs, procPtr->numArgs); Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "procedure \"", procName, buf, (char *) NULL); goto procError; } localPtr = procPtr->firstLocalPtr; } else { procPtr->numArgs = numArgs; procPtr->numCompiledLocals = numArgs; } for (i = 0; i < numArgs; i++) { int fieldCount, nameLength, valueLength; CONST char **fieldValues; /* * Now divide the specifier up into name and default. */ result = Tcl_SplitList(interp, argArray[i], &fieldCount, &fieldValues); if (result != TCL_OK) { goto procError; } if (fieldCount > 2) { ckfree((char *) fieldValues); Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "too many fields in argument specifier \"", argArray[i], "\"", (char *) NULL); goto procError; } if ((fieldCount == 0) || (*fieldValues[0] == 0)) { ckfree((char *) fieldValues); Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "procedure \"", procName, "\" has argument with no name", (char *) NULL); goto procError; } nameLength = strlen(fieldValues[0]); if (fieldCount == 2) { valueLength = strlen(fieldValues[1]); } else { valueLength = 0; } /* * Check that the formal parameter name is a scalar. */ p = fieldValues[0]; while (*p != '\0') { if (*p == '(') { CONST char *q = p; do { q++; } while (*q != '\0'); q--; if (*q == ')') { /* we have an array element */ Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "procedure \"", procName, "\" has formal parameter \"", fieldValues[0], "\" that is an array element", (char *) NULL); ckfree((char *) fieldValues); goto procError; } } else if ((*p == ':') && (*(p+1) == ':')) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "procedure \"", procName, "\" has formal parameter \"", fieldValues[0], "\" that is not a simple name", (char *) NULL); ckfree((char *) fieldValues); goto procError; } p++; } if (precompiled) { /* * Compare the parsed argument with the stored one. * For the flags, we and out VAR_UNDEFINED to support bridging * precompiled <= 8.3 code in 8.4 where this is now used as an * optimization indicator. Yes, this is a hack. -- hobbs */ if ((localPtr->nameLength != nameLength) || (strcmp(localPtr->name, fieldValues[0])) || (localPtr->frameIndex != i) || ((localPtr->flags & ~VAR_UNDEFINED) != (VAR_SCALAR | VAR_ARGUMENT)) || ((localPtr->defValuePtr == NULL) && (fieldCount == 2)) || ((localPtr->defValuePtr != NULL) && (fieldCount != 2))) { char buf[80 + TCL_INTEGER_SPACE]; sprintf(buf, "\": formal parameter %d is inconsistent with precompiled body", i); Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "procedure \"", procName, buf, (char *) NULL); ckfree((char *) fieldValues); goto procError; } /* * compare the default value if any */ if (localPtr->defValuePtr != NULL) { int tmpLength; char *tmpPtr = Tcl_GetStringFromObj(localPtr->defValuePtr, &tmpLength); if ((valueLength != tmpLength) || (strncmp(fieldValues[1], tmpPtr, (size_t) tmpLength))) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "procedure \"", procName, "\": formal parameter \"", fieldValues[0], "\" has default value inconsistent with precompiled body", (char *) NULL); ckfree((char *) fieldValues); goto procError; } } localPtr = localPtr->nextPtr; } else { /* * Allocate an entry in the runtime procedure frame's array of * local variables for the argument. */ localPtr = (CompiledLocal *) ckalloc((unsigned) (sizeof(CompiledLocal) - sizeof(localPtr->name) + nameLength+1)); if (procPtr->firstLocalPtr == NULL) { procPtr->firstLocalPtr = procPtr->lastLocalPtr = localPtr; } else { procPtr->lastLocalPtr->nextPtr = localPtr; procPtr->lastLocalPtr = localPtr; } localPtr->nextPtr = NULL; localPtr->nameLength = nameLength; localPtr->frameIndex = i; localPtr->flags = VAR_SCALAR | VAR_ARGUMENT; localPtr->resolveInfo = NULL; if (fieldCount == 2) { localPtr->defValuePtr = Tcl_NewStringObj(fieldValues[1], valueLength); Tcl_IncrRefCount(localPtr->defValuePtr); } else { localPtr->defValuePtr = NULL; } memcpy(localPtr->name, fieldValues[0], nameLength + 1); } ckfree((char *) fieldValues); } /* * Now initialize the new procedure's cmdPtr field. This will be used * later when the procedure is called to determine what namespace the * procedure will run in. This will be different than the current * namespace if the proc was renamed into a different namespace. */ *procPtrPtr = procPtr; ckfree((char *) argArray); return TCL_OK; procError: if (precompiled) { procPtr->refCount--; } else { Tcl_DecrRefCount(bodyPtr); while (procPtr->firstLocalPtr != NULL) { localPtr = procPtr->firstLocalPtr; procPtr->firstLocalPtr = localPtr->nextPtr; defPtr = localPtr->defValuePtr; if (defPtr != NULL) { Tcl_DecrRefCount(defPtr); } ckfree((char *) localPtr); } ckfree((char *) procPtr); } if (argArray != NULL) { ckfree((char *) argArray); } return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TclGetFrame -- * * Given a description of a procedure frame, such as the first * argument to an "uplevel" or "upvar" command, locate the * call frame for the appropriate level of procedure. * * Results: * The return value is -1 if an error occurred in finding the frame * (in this case an error message is left in the interp's result). * 1 is returned if string was either a number or a number preceded * by "#" and it specified a valid frame. 0 is returned if string * isn't one of the two things above (in this case, the lookup * acts as if string were "1"). The variable pointed to by * framePtrPtr is filled in with the address of the desired frame * (unless an error occurs, in which case it isn't modified). * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclGetFrame(interp, string, framePtrPtr) Tcl_Interp *interp; /* Interpreter in which to find frame. */ CONST char *string; /* String describing frame. */ CallFrame **framePtrPtr; /* Store pointer to frame here (or NULL * if global frame indicated). */ { register Interp *iPtr = (Interp *) interp; int curLevel, level, result; CallFrame *framePtr; /* * Parse string to figure out which level number to go to. */ result = 1; curLevel = (iPtr->varFramePtr == NULL) ? 0 : iPtr->varFramePtr->level; if (*string == '#') { if (Tcl_GetInt(interp, string+1, &level) != TCL_OK) { return -1; } if (level < 0) { levelError: Tcl_AppendResult(interp, "bad level \"", string, "\"", (char *) NULL); return -1; } } else if (isdigit(UCHAR(*string))) { /* INTL: digit */ if (Tcl_GetInt(interp, string, &level) != TCL_OK) { return -1; } level = curLevel - level; } else { level = curLevel - 1; result = 0; } /* * Figure out which frame to use, and modify the interpreter so * its variables come from that frame. */ if (level == 0) { framePtr = NULL; } else { for (framePtr = iPtr->varFramePtr; framePtr != NULL; framePtr = framePtr->callerVarPtr) { if (framePtr->level == level) { break; } } if (framePtr == NULL) { goto levelError; } } *framePtrPtr = framePtr; return result; } /* *---------------------------------------------------------------------- * * Tcl_UplevelObjCmd -- * * This object procedure is invoked to process the "uplevel" Tcl * command. See the user documentation for details on what it does. * * Results: * A standard Tcl object result value. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_UplevelObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { register Interp *iPtr = (Interp *) interp; char *optLevel; int result; CallFrame *savedVarFramePtr, *framePtr; if (objc < 2) { uplevelSyntax: Tcl_WrongNumArgs(interp, 1, objv, "?level? command ?arg ...?"); return TCL_ERROR; } /* * Find the level to use for executing the command. */ optLevel = TclGetString(objv[1]); result = TclGetFrame(interp, optLevel, &framePtr); if (result == -1) { return TCL_ERROR; } objc -= (result+1); if (objc == 0) { goto uplevelSyntax; } objv += (result+1); /* * Modify the interpreter state to execute in the given frame. */ savedVarFramePtr = iPtr->varFramePtr; iPtr->varFramePtr = framePtr; /* * Execute the residual arguments as a command. */ if (objc == 1) { #ifdef TCL_TIP280 /* TIP #280. Make argument location available to eval'd script */ CmdFrame* invoker = NULL; int word = 0; TclArgumentGet (interp, objv[0], &invoker, &word); result = TclEvalObjEx(interp, objv[0], TCL_EVAL_DIRECT, invoker, word); #else result = Tcl_EvalObjEx(interp, objv[0], TCL_EVAL_DIRECT); #endif } else { /* * More than one argument: concatenate them together with spaces * between, then evaluate the result. Tcl_EvalObjEx will delete * the object when it decrements its refcount after eval'ing it. */ Tcl_Obj *objPtr; objPtr = Tcl_ConcatObj(objc, objv); result = Tcl_EvalObjEx(interp, objPtr, TCL_EVAL_DIRECT); } if (result == TCL_ERROR) { char msg[32 + TCL_INTEGER_SPACE]; sprintf(msg, "\n (\"uplevel\" body line %d)", interp->errorLine); Tcl_AddObjErrorInfo(interp, msg, -1); } /* * Restore the variable frame, and return. */ iPtr->varFramePtr = savedVarFramePtr; return result; } /* *---------------------------------------------------------------------- * * TclFindProc -- * * Given the name of a procedure, return a pointer to the * record describing the procedure. The procedure will be * looked up using the usual rules: first in the current * namespace and then in the global namespace. * * Results: * NULL is returned if the name doesn't correspond to any * procedure. Otherwise, the return value is a pointer to * the procedure's record. If the name is found but refers * to an imported command that points to a "real" procedure * defined in another namespace, a pointer to that "real" * procedure's structure is returned. * * Side effects: * None. * *---------------------------------------------------------------------- */ Proc * TclFindProc(iPtr, procName) Interp *iPtr; /* Interpreter in which to look. */ CONST char *procName; /* Name of desired procedure. */ { Tcl_Command cmd; Tcl_Command origCmd; Command *cmdPtr; cmd = Tcl_FindCommand((Tcl_Interp *) iPtr, procName, (Tcl_Namespace *) NULL, /*flags*/ 0); if (cmd == (Tcl_Command) NULL) { return NULL; } cmdPtr = (Command *) cmd; origCmd = TclGetOriginalCommand(cmd); if (origCmd != NULL) { cmdPtr = (Command *) origCmd; } if (cmdPtr->proc != TclProcInterpProc) { return NULL; } return (Proc *) cmdPtr->clientData; } /* *---------------------------------------------------------------------- * * TclIsProc -- * * Tells whether a command is a Tcl procedure or not. * * Results: * If the given command is actually a Tcl procedure, the * return value is the address of the record describing * the procedure. Otherwise the return value is 0. * * Side effects: * None. * *---------------------------------------------------------------------- */ Proc * TclIsProc(cmdPtr) Command *cmdPtr; /* Command to test. */ { Tcl_Command origCmd; origCmd = TclGetOriginalCommand((Tcl_Command) cmdPtr); if (origCmd != NULL) { cmdPtr = (Command *) origCmd; } if (cmdPtr->proc == TclProcInterpProc) { return (Proc *) cmdPtr->clientData; } return (Proc *) 0; } /* *---------------------------------------------------------------------- * * TclProcInterpProc -- * * When a Tcl procedure gets invoked with an argc/argv array of * strings, this routine gets invoked to interpret the procedure. * * Results: * A standard Tcl result value, usually TCL_OK. * * Side effects: * Depends on the commands in the procedure. * *---------------------------------------------------------------------- */ int TclProcInterpProc(clientData, interp, argc, argv) ClientData clientData; /* Record describing procedure to be * interpreted. */ Tcl_Interp *interp; /* Interpreter in which procedure was * invoked. */ int argc; /* Count of number of arguments to this * procedure. */ register CONST char **argv; /* Argument values. */ { register Tcl_Obj *objPtr; register int i; int result; /* * This procedure generates an objv array for object arguments that hold * the argv strings. It starts out with stack-allocated space but uses * dynamically-allocated storage if needed. */ #define NUM_ARGS 20 Tcl_Obj *(objStorage[NUM_ARGS]); register Tcl_Obj **objv = objStorage; /* * Create the object argument array "objv". Make sure objv is large * enough to hold the objc arguments plus 1 extra for the zero * end-of-objv word. */ if ((argc + 1) > NUM_ARGS) { objv = (Tcl_Obj **) ckalloc((unsigned)(argc + 1) * sizeof(Tcl_Obj *)); } for (i = 0; i < argc; i++) { objv[i] = Tcl_NewStringObj(argv[i], -1); Tcl_IncrRefCount(objv[i]); } objv[argc] = 0; /* * Use TclObjInterpProc to actually interpret the procedure. */ result = TclObjInterpProc(clientData, interp, argc, objv); /* * Move the interpreter's object result to the string result, * then reset the object result. */ Tcl_SetResult(interp, TclGetString(Tcl_GetObjResult(interp)), TCL_VOLATILE); /* * Decrement the ref counts on the objv elements since we are done * with them. */ for (i = 0; i < argc; i++) { objPtr = objv[i]; TclDecrRefCount(objPtr); } /* * Free the objv array if malloc'ed storage was used. */ if (objv != objStorage) { ckfree((char *) objv); } return result; #undef NUM_ARGS } /* *---------------------------------------------------------------------- * * TclObjInterpProc -- * * When a Tcl procedure gets invoked during bytecode evaluation, this * object-based routine gets invoked to interpret the procedure. * * Results: * A standard Tcl object result value. * * Side effects: * Depends on the commands in the procedure. * *---------------------------------------------------------------------- */ int TclObjInterpProc(clientData, interp, objc, objv) ClientData clientData; /* Record describing procedure to be * interpreted. */ register Tcl_Interp *interp; /* Interpreter in which procedure was * invoked. */ int objc; /* Count of number of arguments to this * procedure. */ Tcl_Obj *CONST objv[]; /* Argument value objects. */ { Interp *iPtr = (Interp *) interp; Proc *procPtr = (Proc *) clientData; Namespace *nsPtr = procPtr->cmdPtr->nsPtr; CallFrame frame; register CallFrame *framePtr = &frame; register Var *varPtr; register CompiledLocal *localPtr; char *procName; int nameLen, localCt, numArgs, argCt, i, result; /* * This procedure generates an array "compiledLocals" that holds the * storage for local variables. It starts out with stack-allocated space * but uses dynamically-allocated storage if needed. */ #define NUM_LOCALS 20 Var localStorage[NUM_LOCALS]; Var *compiledLocals = localStorage; /* * Get the procedure's name. */ procName = Tcl_GetStringFromObj(objv[0], &nameLen); /* * If necessary, compile the procedure's body. The compiler will * allocate frame slots for the procedure's non-argument local * variables. Note that compiling the body might increase * procPtr->numCompiledLocals if new local variables are found * while compiling. */ result = ProcCompileProc(interp, procPtr, procPtr->bodyPtr, nsPtr, "body of proc", procName, &procPtr); if (result != TCL_OK) { return result; } /* * Create the "compiledLocals" array. Make sure it is large enough to * hold all the procedure's compiled local variables, including its * formal parameters. */ localCt = procPtr->numCompiledLocals; if (localCt > NUM_LOCALS) { compiledLocals = (Var *) ckalloc((unsigned) localCt * sizeof(Var)); } /* * Set up and push a new call frame for the new procedure invocation. * This call frame will execute in the proc's namespace, which might * be different than the current namespace. The proc's namespace is * that of its command, which can change if the command is renamed * from one namespace to another. */ result = Tcl_PushCallFrame(interp, (Tcl_CallFrame *) framePtr, (Tcl_Namespace *) nsPtr, /*isProcCallFrame*/ 1); if (result != TCL_OK) { return result; } framePtr->objc = objc; framePtr->objv = objv; /* ref counts for args are incremented below */ /* * Initialize and resolve compiled variable references. */ framePtr->procPtr = procPtr; framePtr->numCompiledLocals = localCt; framePtr->compiledLocals = compiledLocals; TclInitCompiledLocals(interp, framePtr, nsPtr); /* * Match and assign the call's actual parameters to the procedure's * formal arguments. The formal arguments are described by the first * numArgs entries in both the Proc structure's local variable list and * the call frame's local variable array. */ numArgs = procPtr->numArgs; varPtr = framePtr->compiledLocals; localPtr = procPtr->firstLocalPtr; argCt = objc; for (i = 1, argCt -= 1; i <= numArgs; i++, argCt--) { if (!TclIsVarArgument(localPtr)) { panic("TclObjInterpProc: local variable %s is not argument but should be", localPtr->name); return TCL_ERROR; } if (TclIsVarTemporary(localPtr)) { panic("TclObjInterpProc: local variable %d is temporary but should be an argument", i); return TCL_ERROR; } /* * Handle the special case of the last formal being "args". When * it occurs, assign it a list consisting of all the remaining * actual arguments. */ if ((i == numArgs) && ((localPtr->name[0] == 'a') && (strcmp(localPtr->name, "args") == 0))) { Tcl_Obj *listPtr = Tcl_NewListObj(argCt, &(objv[i])); varPtr->value.objPtr = listPtr; Tcl_IncrRefCount(listPtr); /* local var is a reference */ TclClearVarUndefined(varPtr); argCt = 0; break; /* done processing args */ } else if (argCt > 0) { Tcl_Obj *objPtr = objv[i]; varPtr->value.objPtr = objPtr; TclClearVarUndefined(varPtr); Tcl_IncrRefCount(objPtr); /* since the local variable now has * another reference to object. */ } else if (localPtr->defValuePtr != NULL) { Tcl_Obj *objPtr = localPtr->defValuePtr; varPtr->value.objPtr = objPtr; TclClearVarUndefined(varPtr); Tcl_IncrRefCount(objPtr); /* since the local variable now has * another reference to object. */ } else { goto incorrectArgs; } varPtr++; localPtr = localPtr->nextPtr; } if (argCt > 0) { Tcl_Obj *objResult; int len, flags; incorrectArgs: /* * Build up equivalent to Tcl_WrongNumArgs message for proc */ Tcl_ResetResult(interp); objResult = Tcl_GetObjResult(interp); Tcl_AppendToObj(objResult, "wrong # args: should be \"", -1); /* * Quote the proc name if it contains spaces (Bug 942757). */ len = Tcl_ScanCountedElement(procName, nameLen, &flags); if (len != nameLen) { char *procName1 = ckalloc((unsigned) len + 1); len = Tcl_ConvertCountedElement(procName, nameLen, procName1, flags); Tcl_AppendToObj(objResult, procName1, len); ckfree(procName1); } else { Tcl_AppendToObj(objResult, procName, len); } localPtr = procPtr->firstLocalPtr; for (i = 1; i <= numArgs; i++) { if (localPtr->defValuePtr != NULL) { Tcl_AppendStringsToObj(objResult, " ?", localPtr->name, "?", (char *) NULL); } else { Tcl_AppendStringsToObj(objResult, " ", localPtr->name, (char *) NULL); } localPtr = localPtr->nextPtr; } Tcl_AppendStringsToObj(objResult, "\"", (char *) NULL); result = TCL_ERROR; goto procDone; } /* * Invoke the commands in the procedure's body. */ #ifdef TCL_COMPILE_DEBUG if (tclTraceExec >= 1) { fprintf(stdout, "Calling proc "); for (i = 0; i < objc; i++) { TclPrintObject(stdout, objv[i], 15); fprintf(stdout, " "); } fprintf(stdout, "\n"); fflush(stdout); } #endif /*TCL_COMPILE_DEBUG*/ #ifdef USE_DTRACE if (TCL_DTRACE_PROC_ARGS_ENABLED()) { char *a[10]; int i = 0; while (i < 10) { a[i] = i < objc ? TclGetString(objv[i]) : NULL; i++; } TCL_DTRACE_PROC_ARGS(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9]); } #endif /* USE_DTRACE */ iPtr->returnCode = TCL_OK; procPtr->refCount++; if (TCL_DTRACE_PROC_ENTRY_ENABLED()) { TCL_DTRACE_PROC_ENTRY(TclGetString(objv[0]), objc - 1, (Tcl_Obj **)(objv + 1)); } #ifndef TCL_TIP280 result = TclCompEvalObj(interp, procPtr->bodyPtr); #else /* TIP #280: No need to set the invoking context here. The body has * already been compiled, so the part of CompEvalObj using it is bypassed. */ result = TclCompEvalObj(interp, procPtr->bodyPtr, NULL, 0); #endif if (TCL_DTRACE_PROC_RETURN_ENABLED()) { TCL_DTRACE_PROC_RETURN(TclGetString(objv[0]), result); } procPtr->refCount--; if (procPtr->refCount <= 0) { TclProcCleanupProc(procPtr); } if (result != TCL_OK) { result = ProcessProcResultCode(interp, procName, nameLen, result); } #ifdef USE_DTRACE if (TCL_DTRACE_PROC_RESULT_ENABLED()) { Tcl_Obj *r; r = Tcl_GetObjResult(interp); TCL_DTRACE_PROC_RESULT(TclGetString(objv[0]), result, TclGetString(r), r); } #endif /* USE_DTRACE */ /* * Pop and free the call frame for this procedure invocation, then * free the compiledLocals array if malloc'ed storage was used. */ procDone: Tcl_PopCallFrame(interp); if (compiledLocals != localStorage) { ckfree((char *) compiledLocals); } return result; #undef NUM_LOCALS } /* *---------------------------------------------------------------------- * * TclProcCompileProc -- * * Called just before a procedure is executed to compile the * body to byte codes. If the type of the body is not * "byte code" or if the compile conditions have changed * (namespace context, epoch counters, etc.) then the body * is recompiled. Otherwise, this procedure does nothing. * * Results: * None. * * Side effects: * May change the internal representation of the body object * to compiled code. * *---------------------------------------------------------------------- */ int TclProcCompileProc(interp, procPtr, bodyPtr, nsPtr, description, procName) Tcl_Interp *interp; /* Interpreter containing procedure. */ Proc *procPtr; /* Data associated with procedure. */ Tcl_Obj *bodyPtr; /* Body of proc. (Usually procPtr->bodyPtr, * but could be any code fragment compiled * in the context of this procedure.) */ Namespace *nsPtr; /* Namespace containing procedure. */ CONST char *description; /* string describing this body of code. */ CONST char *procName; /* Name of this procedure. */ { return ProcCompileProc(interp, procPtr, bodyPtr, nsPtr, description, procName, NULL); } static int ProcCompileProc(interp, procPtr, bodyPtr, nsPtr, description, procName, procPtrPtr) Tcl_Interp *interp; /* Interpreter containing procedure. */ Proc *procPtr; /* Data associated with procedure. */ Tcl_Obj *bodyPtr; /* Body of proc. (Usually procPtr->bodyPtr, * but could be any code fragment compiled * in the context of this procedure.) */ Namespace *nsPtr; /* Namespace containing procedure. */ CONST char *description; /* string describing this body of code. */ CONST char *procName; /* Name of this procedure. */ Proc **procPtrPtr; /* points to storage where a replacement * (Proc *) value may be written, when * appropriate */ { Interp *iPtr = (Interp*)interp; int i, result; Tcl_CallFrame frame; ByteCode *codePtr = (ByteCode *) bodyPtr->internalRep.otherValuePtr; CompiledLocal *localPtr; /* * If necessary, compile the procedure's body. The compiler will * allocate frame slots for the procedure's non-argument local * variables. If the ByteCode already exists, make sure it hasn't been * invalidated by someone redefining a core command (this might make the * compiled code wrong). Also, if the code was compiled in/for a * different interpreter, we recompile it. Note that compiling the body * might increase procPtr->numCompiledLocals if new local variables are * found while compiling. * * Precompiled procedure bodies, however, are immutable and therefore * they are not recompiled, even if things have changed. */ if (bodyPtr->typePtr == &tclByteCodeType) { if (((Interp *) *codePtr->interpHandle != iPtr) || (codePtr->compileEpoch != iPtr->compileEpoch) || (codePtr->nsPtr != nsPtr)) { if (codePtr->flags & TCL_BYTECODE_PRECOMPILED) { if ((Interp *) *codePtr->interpHandle != iPtr) { Tcl_AppendResult(interp, "a precompiled script jumped interps", NULL); return TCL_ERROR; } codePtr->compileEpoch = iPtr->compileEpoch; codePtr->nsPtr = nsPtr; } else { (*tclByteCodeType.freeIntRepProc)(bodyPtr); bodyPtr->typePtr = (Tcl_ObjType *) NULL; } } } if (bodyPtr->typePtr != &tclByteCodeType) { int numChars; char *ellipsis; #ifdef TCL_COMPILE_DEBUG if (tclTraceCompile >= 1) { /* * Display a line summarizing the top level command we * are about to compile. */ numChars = strlen(procName); ellipsis = ""; if (numChars > 50) { numChars = 50; ellipsis = "..."; } fprintf(stdout, "Compiling %s \"%.*s%s\"\n", description, numChars, procName, ellipsis); } #endif /* * Plug the current procPtr into the interpreter and coerce * the code body to byte codes. The interpreter needs to * know which proc it's compiling so that it can access its * list of compiled locals. * * TRICKY NOTE: Be careful to push a call frame with the * proper namespace context, so that the byte codes are * compiled in the appropriate class context. */ if (procPtrPtr != NULL && procPtr->refCount > 1) { Tcl_Command token; Tcl_CmdInfo info; Proc *new = (Proc *) ckalloc(sizeof(Proc)); new->iPtr = procPtr->iPtr; new->refCount = 1; new->cmdPtr = procPtr->cmdPtr; token = (Tcl_Command) new->cmdPtr; new->bodyPtr = Tcl_DuplicateObj(bodyPtr); bodyPtr = new->bodyPtr; Tcl_IncrRefCount(bodyPtr); new->numArgs = procPtr->numArgs; new->numCompiledLocals = new->numArgs; new->firstLocalPtr = NULL; new->lastLocalPtr = NULL; localPtr = procPtr->firstLocalPtr; for (i = 0; i < new->numArgs; i++, localPtr = localPtr->nextPtr) { CompiledLocal *copy = (CompiledLocal *) ckalloc((unsigned) (sizeof(CompiledLocal) -sizeof(localPtr->name) + localPtr->nameLength + 1)); if (new->firstLocalPtr == NULL) { new->firstLocalPtr = new->lastLocalPtr = copy; } else { new->lastLocalPtr->nextPtr = copy; new->lastLocalPtr = copy; } copy->nextPtr = NULL; copy->nameLength = localPtr->nameLength; copy->frameIndex = localPtr->frameIndex; copy->flags = localPtr->flags; copy->defValuePtr = localPtr->defValuePtr; if (copy->defValuePtr) { Tcl_IncrRefCount(copy->defValuePtr); } copy->resolveInfo = localPtr->resolveInfo; memcpy(copy->name, localPtr->name, localPtr->nameLength + 1); } /* Reset the ClientData */ Tcl_GetCommandInfoFromToken(token, &info); if (info.objClientData == (ClientData) procPtr) { info.objClientData = (ClientData) new; } if (info.clientData == (ClientData) procPtr) { info.clientData = (ClientData) new; } if (info.deleteData == (ClientData) procPtr) { info.deleteData = (ClientData) new; } Tcl_SetCommandInfoFromToken(token, &info); procPtr->refCount--; *procPtrPtr = procPtr = new; } iPtr->compiledProcPtr = procPtr; result = Tcl_PushCallFrame(interp, &frame, (Tcl_Namespace*)nsPtr, /* isProcCallFrame */ 0); if (result == TCL_OK) { #ifdef TCL_TIP280 /* TIP #280. We get the invoking context from the cmdFrame * which was saved by 'Tcl_ProcObjCmd' (using linePBodyPtr). */ Tcl_HashEntry* hePtr = Tcl_FindHashEntry (iPtr->linePBodyPtr, (char *) procPtr); /* Constructed saved frame has body as word 0. See Tcl_ProcObjCmd. */ iPtr->invokeWord = 0; iPtr->invokeCmdFramePtr = (hePtr ? (CmdFrame*) Tcl_GetHashValue (hePtr) : NULL); #endif result = tclByteCodeType.setFromAnyProc(interp, bodyPtr); #ifdef TCL_TIP280 iPtr->invokeCmdFramePtr = NULL; #endif Tcl_PopCallFrame(interp); } if (result != TCL_OK) { if (result == TCL_ERROR) { char buf[100 + TCL_INTEGER_SPACE]; numChars = strlen(procName); ellipsis = ""; if (numChars > 50) { numChars = 50; ellipsis = "..."; } while ( (procName[numChars] & 0xC0) == 0x80 ) { /* * Back up truncation point so that we don't truncate * in the middle of a multi-byte character (in UTF-8) */ numChars--; ellipsis = "..."; } sprintf(buf, "\n (compiling %s \"%.*s%s\", line %d)", description, numChars, procName, ellipsis, interp->errorLine); Tcl_AddObjErrorInfo(interp, buf, -1); } return result; } } else if (codePtr->nsEpoch != nsPtr->resolverEpoch) { /* * The resolver epoch has changed, but we only need to invalidate * the resolver cache. */ for (localPtr = procPtr->firstLocalPtr; localPtr != NULL; localPtr = localPtr->nextPtr) { localPtr->flags &= ~(VAR_RESOLVED); if (localPtr->resolveInfo) { if (localPtr->resolveInfo->deleteProc) { localPtr->resolveInfo->deleteProc(localPtr->resolveInfo); } else { ckfree((char*)localPtr->resolveInfo); } localPtr->resolveInfo = NULL; } } } return TCL_OK; } /* *---------------------------------------------------------------------- * * ProcessProcResultCode -- * * Procedure called by TclObjInterpProc to process a return code other * than TCL_OK returned by a Tcl procedure. * * Results: * Depending on the argument return code, the result returned is * another return code and the interpreter's result is set to a value * to supplement that return code. * * Side effects: * If the result returned is TCL_ERROR, traceback information about * the procedure just executed is appended to the interpreter's * "errorInfo" variable. * *---------------------------------------------------------------------- */ static int ProcessProcResultCode(interp, procName, nameLen, returnCode) Tcl_Interp *interp; /* The interpreter in which the procedure * was called and returned returnCode. */ char *procName; /* Name of the procedure. Used for error * messages and trace information. */ int nameLen; /* Number of bytes in procedure's name. */ int returnCode; /* The unexpected result code. */ { Interp *iPtr = (Interp *) interp; char msg[100 + TCL_INTEGER_SPACE]; char *ellipsis = ""; if (returnCode == TCL_OK) { return TCL_OK; } if ((returnCode > TCL_CONTINUE) || (returnCode < TCL_OK)) { return returnCode; } if (returnCode == TCL_RETURN) { return TclUpdateReturnInfo(iPtr); } if (returnCode != TCL_ERROR) { Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), ((returnCode == TCL_BREAK) ? "invoked \"break\" outside of a loop" : "invoked \"continue\" outside of a loop"), -1); } if (nameLen > 60) { nameLen = 60; ellipsis = "..."; } while ( (procName[nameLen] & 0xC0) == 0x80 ) { /* * Back up truncation point so that we don't truncate in the * middle of a multi-byte character (in UTF-8) */ nameLen--; ellipsis = "..."; } sprintf(msg, "\n (procedure \"%.*s%s\" line %d)", nameLen, procName, ellipsis, iPtr->errorLine); Tcl_AddObjErrorInfo(interp, msg, -1); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TclProcDeleteProc -- * * This procedure is invoked just before a command procedure is * removed from an interpreter. Its job is to release all the * resources allocated to the procedure. * * Results: * None. * * Side effects: * Memory gets freed, unless the procedure is actively being * executed. In this case the cleanup is delayed until the * last call to the current procedure completes. * *---------------------------------------------------------------------- */ void TclProcDeleteProc(clientData) ClientData clientData; /* Procedure to be deleted. */ { Proc *procPtr = (Proc *) clientData; procPtr->refCount--; if (procPtr->refCount <= 0) { TclProcCleanupProc(procPtr); } } /* *---------------------------------------------------------------------- * * TclProcCleanupProc -- * * This procedure does all the real work of freeing up a Proc * structure. It's called only when the structure's reference * count becomes zero. * * Results: * None. * * Side effects: * Memory gets freed. * *---------------------------------------------------------------------- */ void TclProcCleanupProc(procPtr) register Proc *procPtr; /* Procedure to be deleted. */ { register CompiledLocal *localPtr; Tcl_Obj *bodyPtr = procPtr->bodyPtr; Tcl_Obj *defPtr; Tcl_ResolvedVarInfo *resVarInfo; #ifdef TCL_TIP280 Tcl_HashEntry* hePtr = NULL; CmdFrame* cfPtr = NULL; Interp* iPtr = procPtr->iPtr; #endif if (bodyPtr != NULL) { Tcl_DecrRefCount(bodyPtr); } for (localPtr = procPtr->firstLocalPtr; localPtr != NULL; ) { CompiledLocal *nextPtr = localPtr->nextPtr; resVarInfo = localPtr->resolveInfo; if (resVarInfo) { if (resVarInfo->deleteProc) { (*resVarInfo->deleteProc)(resVarInfo); } else { ckfree((char *) resVarInfo); } } if (localPtr->defValuePtr != NULL) { defPtr = localPtr->defValuePtr; Tcl_DecrRefCount(defPtr); } ckfree((char *) localPtr); localPtr = nextPtr; } ckfree((char *) procPtr); #ifdef TCL_TIP280 /* TIP #280. Release the location data associated with this Proc * structure, if any. The interpreter may not exist (For example for * procbody structurues created by tbcload. */ if (!iPtr) return; hePtr = Tcl_FindHashEntry (iPtr->linePBodyPtr, (char *) procPtr); if (!hePtr) return; cfPtr = (CmdFrame*) Tcl_GetHashValue (hePtr); if (cfPtr->type == TCL_LOCATION_SOURCE) { Tcl_DecrRefCount (cfPtr->data.eval.path); cfPtr->data.eval.path = NULL; } ckfree ((char*) cfPtr->line); cfPtr->line = NULL; ckfree ((char*) cfPtr); Tcl_DeleteHashEntry (hePtr); #endif } /* *---------------------------------------------------------------------- * * TclUpdateReturnInfo -- * * This procedure is called when procedures return, and at other * points where the TCL_RETURN code is used. It examines fields * such as iPtr->returnCode and iPtr->errorCode and modifies * the real return status accordingly. * * Results: * The return value is the true completion code to use for * the procedure, instead of TCL_RETURN. * * Side effects: * The errorInfo and errorCode variables may get modified. * *---------------------------------------------------------------------- */ int TclUpdateReturnInfo(iPtr) Interp *iPtr; /* Interpreter for which TCL_RETURN * exception is being processed. */ { int code; char *errorCode; Tcl_Obj *objPtr; code = iPtr->returnCode; iPtr->returnCode = TCL_OK; if (code == TCL_ERROR) { errorCode = ((iPtr->errorCode != NULL) ? iPtr->errorCode : "NONE"); objPtr = Tcl_NewStringObj(errorCode, -1); Tcl_IncrRefCount(objPtr); Tcl_ObjSetVar2((Tcl_Interp *) iPtr, iPtr->execEnvPtr->errorCode, NULL, objPtr, TCL_GLOBAL_ONLY); Tcl_DecrRefCount(objPtr); iPtr->flags |= ERROR_CODE_SET; if (iPtr->errorInfo != NULL) { objPtr = Tcl_NewStringObj(iPtr->errorInfo, -1); Tcl_IncrRefCount(objPtr); Tcl_ObjSetVar2((Tcl_Interp *) iPtr, iPtr->execEnvPtr->errorInfo, NULL, objPtr, TCL_GLOBAL_ONLY); Tcl_DecrRefCount(objPtr); iPtr->flags |= ERR_IN_PROGRESS; } } return code; } /* *---------------------------------------------------------------------- * * TclGetInterpProc -- * * Returns a pointer to the TclProcInterpProc procedure; this is different * from the value obtained from the TclProcInterpProc reference on systems * like Windows where import and export versions of a procedure exported * by a DLL exist. * * Results: * Returns the internal address of the TclProcInterpProc procedure. * * Side effects: * None. * *---------------------------------------------------------------------- */ TclCmdProcType TclGetInterpProc() { return (TclCmdProcType) TclProcInterpProc; } /* *---------------------------------------------------------------------- * * TclGetObjInterpProc -- * * Returns a pointer to the TclObjInterpProc procedure; this is different * from the value obtained from the TclObjInterpProc reference on systems * like Windows where import and export versions of a procedure exported * by a DLL exist. * * Results: * Returns the internal address of the TclObjInterpProc procedure. * * Side effects: * None. * *---------------------------------------------------------------------- */ TclObjCmdProcType TclGetObjInterpProc() { return (TclObjCmdProcType) TclObjInterpProc; } /* *---------------------------------------------------------------------- * * TclNewProcBodyObj -- * * Creates a new object, of type "procbody", whose internal * representation is the given Proc struct. * The newly created object's reference count is 0. * * Results: * Returns a pointer to a newly allocated Tcl_Obj, 0 on error. * * Side effects: * The reference count in the ByteCode attached to the Proc is bumped up * by one, since the internal rep stores a pointer to it. * *---------------------------------------------------------------------- */ Tcl_Obj * TclNewProcBodyObj(procPtr) Proc *procPtr; /* the Proc struct to store as the internal * representation. */ { Tcl_Obj *objPtr; if (!procPtr) { return (Tcl_Obj *) NULL; } objPtr = Tcl_NewStringObj("", 0); if (objPtr) { objPtr->typePtr = &tclProcBodyType; objPtr->internalRep.otherValuePtr = (VOID *) procPtr; procPtr->refCount++; } return objPtr; } /* *---------------------------------------------------------------------- * * ProcBodyDup -- * * Tcl_ObjType's Dup function for the proc body object. * Bumps the reference count on the Proc stored in the internal * representation. * * Results: * None. * * Side effects: * Sets up the object in dupPtr to be a duplicate of the one in srcPtr. * *---------------------------------------------------------------------- */ static void ProcBodyDup(srcPtr, dupPtr) Tcl_Obj *srcPtr; /* object to copy */ Tcl_Obj *dupPtr; /* target object for the duplication */ { Proc *procPtr = (Proc *) srcPtr->internalRep.otherValuePtr; dupPtr->typePtr = &tclProcBodyType; dupPtr->internalRep.otherValuePtr = (VOID *) procPtr; procPtr->refCount++; } /* *---------------------------------------------------------------------- * * ProcBodyFree -- * * Tcl_ObjType's Free function for the proc body object. * The reference count on its Proc struct is decreased by 1; if the count * reaches 0, the proc is freed. * * Results: * None. * * Side effects: * If the reference count on the Proc struct reaches 0, the struct is freed. * *---------------------------------------------------------------------- */ static void ProcBodyFree(objPtr) Tcl_Obj *objPtr; /* the object to clean up */ { Proc *procPtr = (Proc *) objPtr->internalRep.otherValuePtr; procPtr->refCount--; if (procPtr->refCount <= 0) { TclProcCleanupProc(procPtr); } } /* *---------------------------------------------------------------------- * * ProcBodySetFromAny -- * * Tcl_ObjType's SetFromAny function for the proc body object. * Calls panic. * * Results: * Theoretically returns a TCL result code. * * Side effects: * Calls panic, since we can't set the value of the object from a string * representation (or any other internal ones). * *---------------------------------------------------------------------- */ static int ProcBodySetFromAny(interp, objPtr) Tcl_Interp *interp; /* current interpreter */ Tcl_Obj *objPtr; /* object pointer */ { panic("called ProcBodySetFromAny"); /* * this to keep compilers happy. */ return TCL_OK; } /* *---------------------------------------------------------------------- * * ProcBodyUpdateString -- * * Tcl_ObjType's UpdateString function for the proc body object. * Calls panic. * * Results: * None. * * Side effects: * Calls panic, since we this type has no string representation. * *---------------------------------------------------------------------- */ static void ProcBodyUpdateString(objPtr) Tcl_Obj *objPtr; /* the object to update */ { panic("called ProcBodyUpdateString"); } /* *---------------------------------------------------------------------- * * TclCompileNoOp -- * * Procedure called to compile noOp's * * Results: * The return value is TCL_OK, indicating successful compilation. * * Side effects: * Instructions are added to envPtr to execute a noOp at runtime. * *---------------------------------------------------------------------- */ static int TclCompileNoOp(interp, parsePtr, envPtr) Tcl_Interp *interp; /* Used for error reporting. */ Tcl_Parse *parsePtr; /* Points to a parse structure for the * command created by Tcl_ParseCommand. */ CompileEnv *envPtr; /* Holds resulting instructions. */ { Tcl_Token *tokenPtr; int i, code; int savedStackDepth = envPtr->currStackDepth; tokenPtr = parsePtr->tokenPtr; for(i = 1; i < parsePtr->numWords; i++) { tokenPtr = tokenPtr + tokenPtr->numComponents + 1; envPtr->currStackDepth = savedStackDepth; if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { code = TclCompileTokens(interp, tokenPtr+1, tokenPtr->numComponents, envPtr); if (code != TCL_OK) { return code; } TclEmitOpcode(INST_POP, envPtr); } } envPtr->currStackDepth = savedStackDepth; TclEmitPush(TclRegisterLiteral(envPtr, "", 0, /*onHeap*/ 0), envPtr); return TCL_OK; } /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ tcl8.4.20/generic/tclParse.c0000644003604700454610000015526011737050674014265 0ustar dgp771div/* * tclParse.c -- * * This file contains procedures that parse Tcl scripts. They * do so in a general-purpose fashion that can be used for many * different purposes, including compilation, direct execution, * code analysis, etc. * * Copyright (c) 1997 Sun Microsystems, Inc. * Copyright (c) 1998-2000 Ajuba Solutions. * Contributions from Don Porter, NIST, 2002. (not subject to US copyright) * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" /* * The following table provides parsing information about each possible * 8-bit character. The table is designed to be referenced with either * signed or unsigned characters, so it has 384 entries. The first 128 * entries correspond to negative character values, the next 256 correspond * to positive character values. The last 128 entries are identical to the * first 128. The table is always indexed with a 128-byte offset (the 128th * entry corresponds to a character value of 0). * * The macro CHAR_TYPE is used to index into the table and return * information about its character argument. The following return * values are defined. * * TYPE_NORMAL - All characters that don't have special significance * to the Tcl parser. * TYPE_SPACE - The character is a whitespace character other * than newline. * TYPE_COMMAND_END - Character is newline or semicolon. * TYPE_SUBS - Character begins a substitution or has other * special meaning in ParseTokens: backslash, dollar * sign, or open bracket. * TYPE_QUOTE - Character is a double quote. * TYPE_CLOSE_PAREN - Character is a right parenthesis. * TYPE_CLOSE_BRACK - Character is a right square bracket. * TYPE_BRACE - Character is a curly brace (either left or right). */ #define TYPE_NORMAL 0 #define TYPE_SPACE 0x1 #define TYPE_COMMAND_END 0x2 #define TYPE_SUBS 0x4 #define TYPE_QUOTE 0x8 #define TYPE_CLOSE_PAREN 0x10 #define TYPE_CLOSE_BRACK 0x20 #define TYPE_BRACE 0x40 #define CHAR_TYPE(c) (charTypeTable+128)[(int)(c)] static CONST char charTypeTable[] = { /* * Negative character values, from -128 to -1: */ TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, /* * Positive character values, from 0-127: */ TYPE_SUBS, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_SPACE, TYPE_COMMAND_END, TYPE_SPACE, TYPE_SPACE, TYPE_SPACE, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_SPACE, TYPE_NORMAL, TYPE_QUOTE, TYPE_NORMAL, TYPE_SUBS, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_CLOSE_PAREN, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_COMMAND_END, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_SUBS, TYPE_SUBS, TYPE_CLOSE_BRACK, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_BRACE, TYPE_NORMAL, TYPE_BRACE, TYPE_NORMAL, TYPE_NORMAL, /* * Large unsigned character values, from 128-255: */ TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, }; /* * Prototypes for local procedures defined in this file: */ static int CommandComplete _ANSI_ARGS_((CONST char *script, int numBytes)); static int ParseComment _ANSI_ARGS_((CONST char *src, int numBytes, Tcl_Parse *parsePtr)); static int ParseTokens _ANSI_ARGS_((CONST char *src, int numBytes, int mask, Tcl_Parse *parsePtr)); /* *---------------------------------------------------------------------- * * Tcl_ParseCommand -- * * Given a string, this procedure parses the first Tcl command * in the string and returns information about the structure of * the command. * * Results: * The return value is TCL_OK if the command was parsed * successfully and TCL_ERROR otherwise. If an error occurs * and interp isn't NULL then an error message is left in * its result. On a successful return, parsePtr is filled in * with information about the command that was parsed. * * Side effects: * If there is insufficient space in parsePtr to hold all the * information about the command, then additional space is * malloc-ed. If the procedure returns TCL_OK then the caller must * eventually invoke Tcl_FreeParse to release any additional space * that was allocated. * *---------------------------------------------------------------------- */ int Tcl_ParseCommand(interp, string, numBytes, nested, parsePtr) Tcl_Interp *interp; /* Interpreter to use for error reporting; * if NULL, then no error message is * provided. */ CONST char *string; /* First character of string containing * one or more Tcl commands. */ register int numBytes; /* Total number of bytes in string. If < 0, * the script consists of all bytes up to * the first null character. */ int nested; /* Non-zero means this is a nested command: * close bracket should be considered * a command terminator. If zero, then close * bracket has no special meaning. */ register Tcl_Parse *parsePtr; /* Structure to fill in with information * about the parsed command; any previous * information in the structure is * ignored. */ { register CONST char *src; /* Points to current character * in the command. */ char type; /* Result returned by CHAR_TYPE(*src). */ Tcl_Token *tokenPtr; /* Pointer to token being filled in. */ int wordIndex; /* Index of word token for current word. */ int terminators; /* CHAR_TYPE bits that indicate the end * of a command. */ CONST char *termPtr; /* Set by Tcl_ParseBraces/QuotedString to * point to char after terminating one. */ int scanned; if ((string == NULL) && (numBytes!=0)) { if (interp != NULL) { Tcl_SetResult(interp, "can't parse a NULL pointer", TCL_STATIC); } return TCL_ERROR; } if (numBytes < 0) { numBytes = strlen(string); } parsePtr->commentStart = NULL; parsePtr->commentSize = 0; parsePtr->commandStart = NULL; parsePtr->commandSize = 0; parsePtr->numWords = 0; parsePtr->tokenPtr = parsePtr->staticTokens; parsePtr->numTokens = 0; parsePtr->tokensAvailable = NUM_STATIC_TOKENS; parsePtr->string = string; parsePtr->end = string + numBytes; parsePtr->term = parsePtr->end; parsePtr->interp = interp; parsePtr->incomplete = 0; parsePtr->errorType = TCL_PARSE_SUCCESS; if (nested != 0) { terminators = TYPE_COMMAND_END | TYPE_CLOSE_BRACK; } else { terminators = TYPE_COMMAND_END; } /* * Parse any leading space and comments before the first word of the * command. */ scanned = ParseComment(string, numBytes, parsePtr); src = (string + scanned); numBytes -= scanned; if (numBytes == 0) { if (nested) { parsePtr->incomplete = nested; } } /* * The following loop parses the words of the command, one word * in each iteration through the loop. */ parsePtr->commandStart = src; while (1) { /* * Create the token for the word. */ if (parsePtr->numTokens == parsePtr->tokensAvailable) { TclExpandTokenArray(parsePtr); } wordIndex = parsePtr->numTokens; tokenPtr = &parsePtr->tokenPtr[wordIndex]; tokenPtr->type = TCL_TOKEN_WORD; /* * Skip white space before the word. Also skip a backslash-newline * sequence: it should be treated just like white space. */ scanned = TclParseWhiteSpace(src, numBytes, parsePtr, &type); src += scanned; numBytes -= scanned; if (numBytes == 0) { parsePtr->term = src; break; } if ((type & terminators) != 0) { parsePtr->term = src; src++; break; } tokenPtr->start = src; parsePtr->numTokens++; parsePtr->numWords++; /* * At this point the word can have one of three forms: something * enclosed in quotes, something enclosed in braces, or an * unquoted word (anything else). */ if (*src == '"') { if (Tcl_ParseQuotedString(interp, src, numBytes, parsePtr, 1, &termPtr) != TCL_OK) { goto error; } src = termPtr; numBytes = parsePtr->end - src; } else if (*src == '{') { if (Tcl_ParseBraces(interp, src, numBytes, parsePtr, 1, &termPtr) != TCL_OK) { goto error; } src = termPtr; numBytes = parsePtr->end - src; } else { /* * This is an unquoted word. Call ParseTokens and let it do * all of the work. */ if (ParseTokens(src, numBytes, TYPE_SPACE|terminators, parsePtr) != TCL_OK) { goto error; } src = parsePtr->term; numBytes = parsePtr->end - src; } /* * Finish filling in the token for the word and check for the * special case of a word consisting of a single range of * literal text. */ tokenPtr = &parsePtr->tokenPtr[wordIndex]; tokenPtr->size = src - tokenPtr->start; tokenPtr->numComponents = parsePtr->numTokens - (wordIndex + 1); if ((tokenPtr->numComponents == 1) && (tokenPtr[1].type == TCL_TOKEN_TEXT)) { tokenPtr->type = TCL_TOKEN_SIMPLE_WORD; } /* * Do two additional checks: (a) make sure we're really at the * end of a word (there might have been garbage left after a * quoted or braced word), and (b) check for the end of the * command. */ scanned = TclParseWhiteSpace(src, numBytes, parsePtr, &type); if (scanned) { src += scanned; numBytes -= scanned; continue; } if (numBytes == 0) { parsePtr->term = src; break; } if ((type & terminators) != 0) { parsePtr->term = src; src++; break; } if (src[-1] == '"') { if (interp != NULL) { Tcl_SetResult(interp, "extra characters after close-quote", TCL_STATIC); } parsePtr->errorType = TCL_PARSE_QUOTE_EXTRA; } else { if (interp != NULL) { Tcl_SetResult(interp, "extra characters after close-brace", TCL_STATIC); } parsePtr->errorType = TCL_PARSE_BRACE_EXTRA; } parsePtr->term = src; goto error; } parsePtr->commandSize = src - parsePtr->commandStart; return TCL_OK; error: Tcl_FreeParse(parsePtr); if (parsePtr->commandStart == NULL) { parsePtr->commandStart = string; } parsePtr->commandSize = parsePtr->end - parsePtr->commandStart; return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TclParseWhiteSpace -- * * Scans up to numBytes bytes starting at src, consuming white * space as defined by Tcl's parsing rules. * * Results: * Returns the number of bytes recognized as white space. Records * at parsePtr, information about the parse. Records at typePtr * the character type of the non-whitespace character that terminated * the scan. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclParseWhiteSpace(src, numBytes, parsePtr, typePtr) CONST char *src; /* First character to parse. */ register int numBytes; /* Max number of bytes to scan. */ Tcl_Parse *parsePtr; /* Information about parse in progress. * Updated if parsing indicates * an incomplete command. */ char *typePtr; /* Points to location to store character * type of character that ends run * of whitespace */ { register char type = TYPE_NORMAL; register CONST char *p = src; while (1) { while (numBytes && ((type = CHAR_TYPE(*p)) & TYPE_SPACE)) { numBytes--; p++; } if (numBytes && (type & TYPE_SUBS)) { if (*p != '\\') { break; } if (--numBytes == 0) { break; } if (p[1] != '\n') { break; } p+=2; if (--numBytes == 0) { parsePtr->incomplete = 1; break; } continue; } break; } *typePtr = type; return (p - src); } /* *---------------------------------------------------------------------- * * TclParseHex -- * * Scans a hexadecimal number as a Tcl_UniChar value. * (e.g., for parsing \x and \u escape sequences). * At most numBytes bytes are scanned. * * Results: * The numeric value is stored in *resultPtr. * Returns the number of bytes consumed. * * Notes: * Relies on the following properties of the ASCII * character set, with which UTF-8 is compatible: * * The digits '0' .. '9' and the letters 'A' .. 'Z' and 'a' .. 'z' * occupy consecutive code points, and '0' < 'A' < 'a'. * *---------------------------------------------------------------------- */ int TclParseHex(src, numBytes, resultPtr) CONST char *src; /* First character to parse. */ int numBytes; /* Max number of byes to scan */ Tcl_UniChar *resultPtr; /* Points to storage provided by * caller where the Tcl_UniChar * resulting from the conversion is * to be written. */ { Tcl_UniChar result = 0; register CONST char *p = src; while (numBytes--) { unsigned char digit = UCHAR(*p); if (!isxdigit(digit)) break; ++p; result <<= 4; if (digit >= 'a') { result |= (10 + digit - 'a'); } else if (digit >= 'A') { result |= (10 + digit - 'A'); } else { result |= (digit - '0'); } } *resultPtr = result; return (p - src); } /* *---------------------------------------------------------------------- * * TclParseBackslash -- * * Scans up to numBytes bytes starting at src, consuming a * backslash sequence as defined by Tcl's parsing rules. * * Results: * Records at readPtr the number of bytes making up the backslash * sequence. Records at dst the UTF-8 encoded equivalent of * that backslash sequence. Returns the number of bytes written * to dst, at most TCL_UTF_MAX. Either readPtr or dst may be * NULL, if the results are not needed, but the return value is * the same either way. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclParseBackslash(src, numBytes, readPtr, dst) CONST char * src; /* Points to the backslash character of a * a backslash sequence */ int numBytes; /* Max number of bytes to scan */ int *readPtr; /* NULL, or points to storage where the * number of bytes scanned should be written. */ char *dst; /* NULL, or points to buffer where the UTF-8 * encoding of the backslash sequence is to be * written. At most TCL_UTF_MAX bytes will be * written there. */ { register CONST char *p = src+1; Tcl_UniChar result; int count; char buf[TCL_UTF_MAX]; if (numBytes == 0) { if (readPtr != NULL) { *readPtr = 0; } return 0; } if (dst == NULL) { dst = buf; } if (numBytes == 1) { /* Can only scan the backslash. Return it. */ result = '\\'; count = 1; goto done; } count = 2; switch (*p) { /* * Note: in the conversions below, use absolute values (e.g., * 0xa) rather than symbolic values (e.g. \n) that get converted * by the compiler. It's possible that compilers on some * platforms will do the symbolic conversions differently, which * could result in non-portable Tcl scripts. */ case 'a': result = 0x7; break; case 'b': result = 0x8; break; case 'f': result = 0xc; break; case 'n': result = 0xa; break; case 'r': result = 0xd; break; case 't': result = 0x9; break; case 'v': result = 0xb; break; case 'x': count += TclParseHex(p+1, numBytes-2, &result); if (count == 2) { /* No hexadigits -> This is just "x". */ result = 'x'; } else { /* Keep only the last byte (2 hex digits) */ result = (unsigned char) result; } break; case 'u': count += TclParseHex(p+1, (numBytes > 5) ? 4 : numBytes-2, &result); if (count == 2) { /* No hexadigits -> This is just "u". */ result = 'u'; } break; case '\n': count--; do { p++; count++; } while ((count < numBytes) && ((*p == ' ') || (*p == '\t'))); result = ' '; break; case 0: result = '\\'; count = 1; break; default: /* * Check for an octal number \oo?o? */ if (isdigit(UCHAR(*p)) && (UCHAR(*p) < '8')) { /* INTL: digit */ result = (unsigned char)(*p - '0'); p++; if ((numBytes == 2) || !isdigit(UCHAR(*p)) /* INTL: digit */ || (UCHAR(*p) >= '8')) { break; } count = 3; result = (unsigned char)((result << 3) + (*p - '0')); p++; if ((numBytes == 3) || !isdigit(UCHAR(*p)) /* INTL: digit */ || (UCHAR(*p) >= '8')) { break; } count = 4; result = (unsigned char)((result << 3) + (*p - '0')); break; } /* * We have to convert here in case the user has put a * backslash in front of a multi-byte utf-8 character. * While this means nothing special, we shouldn't break up * a correct utf-8 character. [Bug #217987] test subst-3.2 */ if (Tcl_UtfCharComplete(p, numBytes - 1)) { count = Tcl_UtfToUniChar(p, &result) + 1; /* +1 for '\' */ } else { char utfBytes[TCL_UTF_MAX]; memcpy(utfBytes, p, (size_t) (numBytes - 1)); utfBytes[numBytes - 1] = '\0'; count = Tcl_UtfToUniChar(utfBytes, &result) + 1; } break; } done: if (readPtr != NULL) { *readPtr = count; } return Tcl_UniCharToUtf((int) result, dst); } /* *---------------------------------------------------------------------- * * ParseComment -- * * Scans up to numBytes bytes starting at src, consuming a * Tcl comment as defined by Tcl's parsing rules. * * Results: * Records in parsePtr information about the parse. Returns the * number of bytes consumed. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int ParseComment(src, numBytes, parsePtr) CONST char *src; /* First character to parse. */ register int numBytes; /* Max number of bytes to scan. */ Tcl_Parse *parsePtr; /* Information about parse in progress. * Updated if parsing indicates * an incomplete command. */ { register CONST char *p = src; while (numBytes) { char type; int scanned; do { scanned = TclParseWhiteSpace(p, numBytes, parsePtr, &type); p += scanned; numBytes -= scanned; } while (numBytes && (*p == '\n') && (p++,numBytes--)); if ((numBytes == 0) || (*p != '#')) { break; } if (parsePtr->commentStart == NULL) { parsePtr->commentStart = p; } while (numBytes) { if (*p == '\\') { scanned = TclParseWhiteSpace(p, numBytes, parsePtr, &type); if (scanned) { p += scanned; numBytes -= scanned; } else { /* * General backslash substitution in comments isn't * part of the formal spec, but test parse-15.47 * and history indicate that it has been the de facto * rule. Don't change it now. */ TclParseBackslash(p, numBytes, &scanned, NULL); p += scanned; numBytes -= scanned; } } else { p++; numBytes--; if (p[-1] == '\n') { break; } } } parsePtr->commentSize = p - parsePtr->commentStart; } return (p - src); } /* *---------------------------------------------------------------------- * * ParseTokens -- * * This procedure forms the heart of the Tcl parser. It parses one * or more tokens from a string, up to a termination point * specified by the caller. This procedure is used to parse * unquoted command words (those not in quotes or braces), words in * quotes, and array indices for variables. No more than numBytes * bytes will be scanned. * * Results: * Tokens are added to parsePtr and parsePtr->term is filled in * with the address of the character that terminated the parse (the * first one whose CHAR_TYPE matched mask or the character at * parsePtr->end). The return value is TCL_OK if the parse * completed successfully and TCL_ERROR otherwise. If a parse * error occurs and parsePtr->interp isn't NULL, then an error * message is left in the interpreter's result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int ParseTokens(src, numBytes, mask, parsePtr) register CONST char *src; /* First character to parse. */ register int numBytes; /* Max number of bytes to scan. */ int mask; /* Specifies when to stop parsing. The * parse stops at the first unquoted * character whose CHAR_TYPE contains * any of the bits in mask. */ Tcl_Parse *parsePtr; /* Information about parse in progress. * Updated with additional tokens and * termination information. */ { char type; int originalTokens, varToken; Tcl_Token *tokenPtr; Tcl_Parse nested; /* * Each iteration through the following loop adds one token of * type TCL_TOKEN_TEXT, TCL_TOKEN_BS, TCL_TOKEN_COMMAND, or * TCL_TOKEN_VARIABLE to parsePtr. For TCL_TOKEN_VARIABLE tokens, * additional tokens are added for the parsed variable name. */ originalTokens = parsePtr->numTokens; while (numBytes && !((type = CHAR_TYPE(*src)) & mask)) { if (parsePtr->numTokens == parsePtr->tokensAvailable) { TclExpandTokenArray(parsePtr); } tokenPtr = &parsePtr->tokenPtr[parsePtr->numTokens]; tokenPtr->start = src; tokenPtr->numComponents = 0; if ((type & TYPE_SUBS) == 0) { /* * This is a simple range of characters. Scan to find the end * of the range. */ while ((++src, --numBytes) && !(CHAR_TYPE(*src) & (mask | TYPE_SUBS))) { /* empty loop */ } tokenPtr->type = TCL_TOKEN_TEXT; tokenPtr->size = src - tokenPtr->start; parsePtr->numTokens++; } else if (*src == '$') { /* * This is a variable reference. Call Tcl_ParseVarName to do * all the dirty work of parsing the name. */ varToken = parsePtr->numTokens; if (Tcl_ParseVarName(parsePtr->interp, src, numBytes, parsePtr, 1) != TCL_OK) { return TCL_ERROR; } src += parsePtr->tokenPtr[varToken].size; numBytes -= parsePtr->tokenPtr[varToken].size; } else if (*src == '[') { /* * Command substitution. Call Tcl_ParseCommand recursively * (and repeatedly) to parse the nested command(s), then * throw away the parse information. */ src++; numBytes--; while (1) { if (Tcl_ParseCommand(parsePtr->interp, src, numBytes, 1, &nested) != TCL_OK) { parsePtr->errorType = nested.errorType; parsePtr->term = nested.term; parsePtr->incomplete = nested.incomplete; return TCL_ERROR; } src = nested.commandStart + nested.commandSize; numBytes = parsePtr->end - src; /* * This is equivalent to Tcl_FreeParse(&nested), but * presumably inlined here for sake of runtime optimization */ if (nested.tokenPtr != nested.staticTokens) { ckfree((char *) nested.tokenPtr); } /* * Check for the closing ']' that ends the command * substitution. It must have been the last character of * the parsed command. */ if ((nested.term < parsePtr->end) && (*nested.term == ']') && !nested.incomplete) { break; } if (numBytes == 0) { if (parsePtr->interp != NULL) { Tcl_SetResult(parsePtr->interp, "missing close-bracket", TCL_STATIC); } parsePtr->errorType = TCL_PARSE_MISSING_BRACKET; parsePtr->term = tokenPtr->start; parsePtr->incomplete = 1; return TCL_ERROR; } } tokenPtr->type = TCL_TOKEN_COMMAND; tokenPtr->size = src - tokenPtr->start; parsePtr->numTokens++; } else if (*src == '\\') { /* * Backslash substitution. */ TclParseBackslash(src, numBytes, &tokenPtr->size, NULL); if (tokenPtr->size == 1) { /* Just a backslash, due to end of string */ tokenPtr->type = TCL_TOKEN_TEXT; parsePtr->numTokens++; src++; numBytes--; continue; } if (src[1] == '\n') { if (numBytes == 2) { parsePtr->incomplete = 1; } /* * Note: backslash-newline is special in that it is * treated the same as a space character would be. This * means that it could terminate the token. */ if (mask & TYPE_SPACE) { if (parsePtr->numTokens == originalTokens) { goto finishToken; } break; } } tokenPtr->type = TCL_TOKEN_BS; parsePtr->numTokens++; src += tokenPtr->size; numBytes -= tokenPtr->size; } else if (*src == 0) { tokenPtr->type = TCL_TOKEN_TEXT; tokenPtr->size = 1; parsePtr->numTokens++; src++; numBytes--; } else { panic("ParseTokens encountered unknown character"); } } if (parsePtr->numTokens == originalTokens) { /* * There was nothing in this range of text. Add an empty token * for the empty range, so that there is always at least one * token added. */ if (parsePtr->numTokens == parsePtr->tokensAvailable) { TclExpandTokenArray(parsePtr); } tokenPtr = &parsePtr->tokenPtr[parsePtr->numTokens]; tokenPtr->start = src; tokenPtr->numComponents = 0; finishToken: tokenPtr->type = TCL_TOKEN_TEXT; tokenPtr->size = 0; parsePtr->numTokens++; } parsePtr->term = src; return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_FreeParse -- * * This procedure is invoked to free any dynamic storage that may * have been allocated by a previous call to Tcl_ParseCommand. * * Results: * None. * * Side effects: * If there is any dynamically allocated memory in *parsePtr, * it is freed. * *---------------------------------------------------------------------- */ void Tcl_FreeParse(parsePtr) Tcl_Parse *parsePtr; /* Structure that was filled in by a * previous call to Tcl_ParseCommand. */ { if (parsePtr->tokenPtr != parsePtr->staticTokens) { ckfree((char *) parsePtr->tokenPtr); parsePtr->tokenPtr = parsePtr->staticTokens; } } /* *---------------------------------------------------------------------- * * TclExpandTokenArray -- * * This procedure is invoked when the current space for tokens in * a Tcl_Parse structure fills up; it allocates memory to grow the * token array * * Results: * None. * * Side effects: * Memory is allocated for a new larger token array; the memory * for the old array is freed, if it had been dynamically allocated. * *---------------------------------------------------------------------- */ void TclExpandTokenArray(parsePtr) Tcl_Parse *parsePtr; /* Parse structure whose token space * has overflowed. */ { int newCount; Tcl_Token *newPtr; #define MAX_TOKENS (int)(UINT_MAX / sizeof(Tcl_Token)) if (parsePtr->tokensAvailable == MAX_TOKENS) { Tcl_Panic("max # of tokens for a Tcl parse (%d) exceeded", MAX_TOKENS); } newCount = parsePtr->tokensAvailable*2; if (newCount > MAX_TOKENS) { newCount = MAX_TOKENS; } newPtr = (Tcl_Token *) ckalloc((unsigned) (newCount * sizeof(Tcl_Token))); memcpy((VOID *) newPtr, (VOID *) parsePtr->tokenPtr, (size_t) (parsePtr->tokensAvailable * sizeof(Tcl_Token))); if (parsePtr->tokenPtr != parsePtr->staticTokens) { ckfree((char *) parsePtr->tokenPtr); } parsePtr->tokenPtr = newPtr; parsePtr->tokensAvailable = newCount; } /* *---------------------------------------------------------------------- * * Tcl_ParseVarName -- * * Given a string starting with a $ sign, parse off a variable * name and return information about the parse. No more than * numBytes bytes will be scanned. * * Results: * The return value is TCL_OK if the command was parsed * successfully and TCL_ERROR otherwise. If an error occurs and * interp isn't NULL then an error message is left in its result. * On a successful return, tokenPtr and numTokens fields of * parsePtr are filled in with information about the variable name * that was parsed. The "size" field of the first new token gives * the total number of bytes in the variable name. Other fields in * parsePtr are undefined. * * Side effects: * If there is insufficient space in parsePtr to hold all the * information about the command, then additional space is * malloc-ed. If the procedure returns TCL_OK then the caller must * eventually invoke Tcl_FreeParse to release any additional space * that was allocated. * *---------------------------------------------------------------------- */ int Tcl_ParseVarName(interp, string, numBytes, parsePtr, append) Tcl_Interp *interp; /* Interpreter to use for error reporting; * if NULL, then no error message is * provided. */ CONST char *string; /* String containing variable name. First * character must be "$". */ register int numBytes; /* Total number of bytes in string. If < 0, * the string consists of all bytes up to the * first null character. */ Tcl_Parse *parsePtr; /* Structure to fill in with information * about the variable name. */ int append; /* Non-zero means append tokens to existing * information in parsePtr; zero means ignore * existing tokens in parsePtr and reinitialize * it. */ { Tcl_Token *tokenPtr; register CONST char *src; unsigned char c; int varIndex, offset; Tcl_UniChar ch; unsigned array; if ((numBytes == 0) || (string == NULL)) { return TCL_ERROR; } if (numBytes < 0) { numBytes = strlen(string); } if (!append) { parsePtr->numWords = 0; parsePtr->tokenPtr = parsePtr->staticTokens; parsePtr->numTokens = 0; parsePtr->tokensAvailable = NUM_STATIC_TOKENS; parsePtr->string = string; parsePtr->end = (string + numBytes); parsePtr->interp = interp; parsePtr->errorType = TCL_PARSE_SUCCESS; parsePtr->incomplete = 0; } /* * Generate one token for the variable, an additional token for the * name, plus any number of additional tokens for the index, if * there is one. */ src = string; if ((parsePtr->numTokens + 2) > parsePtr->tokensAvailable) { TclExpandTokenArray(parsePtr); } tokenPtr = &parsePtr->tokenPtr[parsePtr->numTokens]; tokenPtr->type = TCL_TOKEN_VARIABLE; tokenPtr->start = src; varIndex = parsePtr->numTokens; parsePtr->numTokens++; tokenPtr++; src++; numBytes--; if (numBytes == 0) { goto justADollarSign; } tokenPtr->type = TCL_TOKEN_TEXT; tokenPtr->start = src; tokenPtr->numComponents = 0; /* * The name of the variable can have three forms: * 1. The $ sign is followed by an open curly brace. Then * the variable name is everything up to the next close * curly brace, and the variable is a scalar variable. * 2. The $ sign is not followed by an open curly brace. Then * the variable name is everything up to the next * character that isn't a letter, digit, or underscore. * :: sequences are also considered part of the variable * name, in order to support namespaces. If the following * character is an open parenthesis, then the information * between parentheses is the array element name. * 3. The $ sign is followed by something that isn't a letter, * digit, or underscore: in this case, there is no variable * name and the token is just "$". */ if (*src == '{') { src++; numBytes--; tokenPtr->type = TCL_TOKEN_TEXT; tokenPtr->start = src; tokenPtr->numComponents = 0; while (numBytes && (*src != '}')) { numBytes--; src++; } if (numBytes == 0) { if (parsePtr->interp != NULL) { Tcl_SetResult(parsePtr->interp, "missing close-brace for variable name", TCL_STATIC); } parsePtr->errorType = TCL_PARSE_MISSING_VAR_BRACE; parsePtr->term = tokenPtr->start-1; parsePtr->incomplete = 1; goto error; } tokenPtr->size = src - tokenPtr->start; tokenPtr[-1].size = src - tokenPtr[-1].start; parsePtr->numTokens++; src++; } else { tokenPtr->type = TCL_TOKEN_TEXT; tokenPtr->start = src; tokenPtr->numComponents = 0; while (numBytes) { if (Tcl_UtfCharComplete(src, numBytes)) { offset = Tcl_UtfToUniChar(src, &ch); } else { char utfBytes[TCL_UTF_MAX]; memcpy(utfBytes, src, (size_t) numBytes); utfBytes[numBytes] = '\0'; offset = Tcl_UtfToUniChar(utfBytes, &ch); } c = UCHAR(ch); if (isalnum(c) || (c == '_')) { /* INTL: ISO only, UCHAR. */ src += offset; numBytes -= offset; continue; } if ((c == ':') && (numBytes != 1) && (src[1] == ':')) { src += 2; numBytes -= 2; while (numBytes && (*src == ':')) { src++; numBytes--; } continue; } break; } /* * Support for empty array names here. */ array = (numBytes && (*src == '(')); tokenPtr->size = src - tokenPtr->start; if ((tokenPtr->size == 0) && !array) { goto justADollarSign; } parsePtr->numTokens++; if (array) { /* * This is a reference to an array element. Call * ParseTokens recursively to parse the element name, * since it could contain any number of substitutions. */ if (ParseTokens(src+1, numBytes-1, TYPE_CLOSE_PAREN, parsePtr) != TCL_OK) { goto error; } if ((parsePtr->term == (src + numBytes)) || (*parsePtr->term != ')')) { if (parsePtr->interp != NULL) { Tcl_SetResult(parsePtr->interp, "missing )", TCL_STATIC); } parsePtr->errorType = TCL_PARSE_MISSING_PAREN; parsePtr->term = src; parsePtr->incomplete = 1; goto error; } src = parsePtr->term + 1; } } tokenPtr = &parsePtr->tokenPtr[varIndex]; tokenPtr->size = src - tokenPtr->start; tokenPtr->numComponents = parsePtr->numTokens - (varIndex + 1); return TCL_OK; /* * The dollar sign isn't followed by a variable name. * replace the TCL_TOKEN_VARIABLE token with a * TCL_TOKEN_TEXT token for the dollar sign. */ justADollarSign: tokenPtr = &parsePtr->tokenPtr[varIndex]; tokenPtr->type = TCL_TOKEN_TEXT; tokenPtr->size = 1; tokenPtr->numComponents = 0; return TCL_OK; error: Tcl_FreeParse(parsePtr); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * Tcl_ParseVar -- * * Given a string starting with a $ sign, parse off a variable * name and return its value. * * Results: * The return value is the contents of the variable given by * the leading characters of string. If termPtr isn't NULL, * *termPtr gets filled in with the address of the character * just after the last one in the variable specifier. If the * variable doesn't exist, then the return value is NULL and * an error message will be left in interp's result. * * Side effects: * None. * *---------------------------------------------------------------------- */ CONST char * Tcl_ParseVar(interp, string, termPtr) Tcl_Interp *interp; /* Context for looking up variable. */ register CONST char *string; /* String containing variable name. * First character must be "$". */ CONST char **termPtr; /* If non-NULL, points to word to fill * in with character just after last * one in the variable specifier. */ { Tcl_Parse parse; register Tcl_Obj *objPtr; int code; if (Tcl_ParseVarName(interp, string, -1, &parse, 0) != TCL_OK) { return NULL; } if (termPtr != NULL) { *termPtr = string + parse.tokenPtr->size; } if (parse.numTokens == 1) { /* * There isn't a variable name after all: the $ is just a $. */ return "$"; } code = Tcl_EvalTokensStandard(interp, parse.tokenPtr, parse.numTokens); if (code != TCL_OK) { return NULL; } objPtr = Tcl_GetObjResult(interp); /* * At this point we should have an object containing the value of * a variable. Just return the string from that object. * * This should have returned the object for the user to manage, but * instead we have some weak reference to the string value in the * object, which is why we make sure the object exists after resetting * the result. This isn't ideal, but it's the best we can do with the * current documented interface. -- hobbs */ if (!Tcl_IsShared(objPtr)) { Tcl_IncrRefCount(objPtr); } Tcl_ResetResult(interp); return TclGetString(objPtr); } /* *---------------------------------------------------------------------- * * Tcl_ParseBraces -- * * Given a string in braces such as a Tcl command argument or a string * value in a Tcl expression, this procedure parses the string and * returns information about the parse. No more than numBytes bytes * will be scanned. * * Results: * The return value is TCL_OK if the string was parsed successfully and * TCL_ERROR otherwise. If an error occurs and interp isn't NULL then * an error message is left in its result. On a successful return, * tokenPtr and numTokens fields of parsePtr are filled in with * information about the string that was parsed. Other fields in * parsePtr are undefined. termPtr is set to point to the character * just after the last one in the braced string. * * Side effects: * If there is insufficient space in parsePtr to hold all the * information about the command, then additional space is * malloc-ed. If the procedure returns TCL_OK then the caller must * eventually invoke Tcl_FreeParse to release any additional space * that was allocated. * *---------------------------------------------------------------------- */ int Tcl_ParseBraces(interp, string, numBytes, parsePtr, append, termPtr) Tcl_Interp *interp; /* Interpreter to use for error reporting; * if NULL, then no error message is * provided. */ CONST char *string; /* String containing the string in braces. * The first character must be '{'. */ register int numBytes; /* Total number of bytes in string. If < 0, * the string consists of all bytes up to * the first null character. */ register Tcl_Parse *parsePtr; /* Structure to fill in with information * about the string. */ int append; /* Non-zero means append tokens to existing * information in parsePtr; zero means * ignore existing tokens in parsePtr and * reinitialize it. */ CONST char **termPtr; /* If non-NULL, points to word in which to * store a pointer to the character just * after the terminating '}' if the parse * was successful. */ { Tcl_Token *tokenPtr; register CONST char *src; int startIndex, level, length; if ((numBytes == 0) || (string == NULL)) { return TCL_ERROR; } if (numBytes < 0) { numBytes = strlen(string); } if (!append) { parsePtr->numWords = 0; parsePtr->tokenPtr = parsePtr->staticTokens; parsePtr->numTokens = 0; parsePtr->tokensAvailable = NUM_STATIC_TOKENS; parsePtr->string = string; parsePtr->end = (string + numBytes); parsePtr->interp = interp; parsePtr->errorType = TCL_PARSE_SUCCESS; } src = string; startIndex = parsePtr->numTokens; if (parsePtr->numTokens == parsePtr->tokensAvailable) { TclExpandTokenArray(parsePtr); } tokenPtr = &parsePtr->tokenPtr[startIndex]; tokenPtr->type = TCL_TOKEN_TEXT; tokenPtr->start = src+1; tokenPtr->numComponents = 0; level = 1; while (1) { while (++src, --numBytes) { if (CHAR_TYPE(*src) != TYPE_NORMAL) { break; } } if (numBytes == 0) { register int openBrace = 0; parsePtr->errorType = TCL_PARSE_MISSING_BRACE; parsePtr->term = string; parsePtr->incomplete = 1; if (parsePtr->interp == NULL) { /* * Skip straight to the exit code since we have no * interpreter to put error message in. */ goto error; } Tcl_SetResult(parsePtr->interp, "missing close-brace", TCL_STATIC); /* * Guess if the problem is due to comments by searching * the source string for a possible open brace within the * context of a comment. Since we aren't performing a * full Tcl parse, just look for an open brace preceded * by a '#' on the same line. */ while (--src > string) { switch (*src) { case '{': openBrace = 1; break; case '\n': openBrace = 0; break; case '#' : if (openBrace && (isspace(UCHAR(src[-1])))) { Tcl_AppendResult(parsePtr->interp, ": possible unbalanced brace in comment", (char *) NULL); goto error; } break; } } error: Tcl_FreeParse(parsePtr); return TCL_ERROR; } switch (*src) { case '{': level++; break; case '}': if (--level == 0) { /* * Decide if we need to finish emitting a * partially-finished token. There are 3 cases: * {abc \newline xyz} or {xyz} * - finish emitting "xyz" token * {abc \newline} * - don't emit token after \newline * {} - finish emitting zero-sized token * * The last case ensures that there is a token * (even if empty) that describes the braced string. */ if ((src != tokenPtr->start) || (parsePtr->numTokens == startIndex)) { tokenPtr->size = (src - tokenPtr->start); parsePtr->numTokens++; } if (termPtr != NULL) { *termPtr = src+1; } return TCL_OK; } break; case '\\': TclParseBackslash(src, numBytes, &length, NULL); if ((length > 1) && (src[1] == '\n')) { /* * A backslash-newline sequence must be collapsed, even * inside braces, so we have to split the word into * multiple tokens so that the backslash-newline can be * represented explicitly. */ if (numBytes == 2) { parsePtr->incomplete = 1; } tokenPtr->size = (src - tokenPtr->start); if (tokenPtr->size != 0) { parsePtr->numTokens++; } if ((parsePtr->numTokens+1) >= parsePtr->tokensAvailable) { TclExpandTokenArray(parsePtr); } tokenPtr = &parsePtr->tokenPtr[parsePtr->numTokens]; tokenPtr->type = TCL_TOKEN_BS; tokenPtr->start = src; tokenPtr->size = length; tokenPtr->numComponents = 0; parsePtr->numTokens++; src += length - 1; numBytes -= length - 1; tokenPtr++; tokenPtr->type = TCL_TOKEN_TEXT; tokenPtr->start = src + 1; tokenPtr->numComponents = 0; } else { src += length - 1; numBytes -= length - 1; } break; } } } /* *---------------------------------------------------------------------- * * Tcl_ParseQuotedString -- * * Given a double-quoted string such as a quoted Tcl command argument * or a quoted value in a Tcl expression, this procedure parses the * string and returns information about the parse. No more than * numBytes bytes will be scanned. * * Results: * The return value is TCL_OK if the string was parsed successfully and * TCL_ERROR otherwise. If an error occurs and interp isn't NULL then * an error message is left in its result. On a successful return, * tokenPtr and numTokens fields of parsePtr are filled in with * information about the string that was parsed. Other fields in * parsePtr are undefined. termPtr is set to point to the character * just after the quoted string's terminating close-quote. * * Side effects: * If there is insufficient space in parsePtr to hold all the * information about the command, then additional space is * malloc-ed. If the procedure returns TCL_OK then the caller must * eventually invoke Tcl_FreeParse to release any additional space * that was allocated. * *---------------------------------------------------------------------- */ int Tcl_ParseQuotedString(interp, string, numBytes, parsePtr, append, termPtr) Tcl_Interp *interp; /* Interpreter to use for error reporting; * if NULL, then no error message is * provided. */ CONST char *string; /* String containing the quoted string. * The first character must be '"'. */ register int numBytes; /* Total number of bytes in string. If < 0, * the string consists of all bytes up to * the first null character. */ register Tcl_Parse *parsePtr; /* Structure to fill in with information * about the string. */ int append; /* Non-zero means append tokens to existing * information in parsePtr; zero means * ignore existing tokens in parsePtr and * reinitialize it. */ CONST char **termPtr; /* If non-NULL, points to word in which to * store a pointer to the character just * after the quoted string's terminating * close-quote if the parse succeeds. */ { if ((numBytes == 0) || (string == NULL)) { return TCL_ERROR; } if (numBytes < 0) { numBytes = strlen(string); } if (!append) { parsePtr->numWords = 0; parsePtr->tokenPtr = parsePtr->staticTokens; parsePtr->numTokens = 0; parsePtr->tokensAvailable = NUM_STATIC_TOKENS; parsePtr->string = string; parsePtr->end = (string + numBytes); parsePtr->interp = interp; parsePtr->errorType = TCL_PARSE_SUCCESS; } if (ParseTokens(string+1, numBytes-1, TYPE_QUOTE, parsePtr) != TCL_OK) { goto error; } if (*parsePtr->term != '"') { if (parsePtr->interp != NULL) { Tcl_SetResult(parsePtr->interp, "missing \"", TCL_STATIC); } parsePtr->errorType = TCL_PARSE_MISSING_QUOTE; parsePtr->term = string; parsePtr->incomplete = 1; goto error; } if (termPtr != NULL) { *termPtr = (parsePtr->term + 1); } return TCL_OK; error: Tcl_FreeParse(parsePtr); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * CommandComplete -- * * This procedure is shared by TclCommandComplete and * Tcl_ObjCommandcoComplete; it does all the real work of seeing * whether a script is complete * * Results: * 1 is returned if the script is complete, 0 if there are open * delimiters such as " or (. 1 is also returned if there is a * parse error in the script other than unmatched delimiters. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int CommandComplete(script, numBytes) CONST char *script; /* Script to check. */ int numBytes; /* Number of bytes in script. */ { Tcl_Parse parse; CONST char *p, *end; int result; p = script; end = p + numBytes; while (Tcl_ParseCommand((Tcl_Interp *) NULL, p, end - p, 0, &parse) == TCL_OK) { p = parse.commandStart + parse.commandSize; if (p >= end) { break; } Tcl_FreeParse(&parse); } if (parse.incomplete) { result = 0; } else { result = 1; } Tcl_FreeParse(&parse); return result; } /* *---------------------------------------------------------------------- * * Tcl_CommandComplete -- * * Given a partial or complete Tcl script, this procedure * determines whether the script is complete in the sense * of having matched braces and quotes and brackets. * * Results: * 1 is returned if the script is complete, 0 otherwise. * 1 is also returned if there is a parse error in the script * other than unmatched delimiters. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_CommandComplete(script) CONST char *script; /* Script to check. */ { return CommandComplete(script, (int) strlen(script)); } /* *---------------------------------------------------------------------- * * TclObjCommandComplete -- * * Given a partial or complete Tcl command in a Tcl object, this * procedure determines whether the command is complete in the sense of * having matched braces and quotes and brackets. * * Results: * 1 is returned if the command is complete, 0 otherwise. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclObjCommandComplete(objPtr) Tcl_Obj *objPtr; /* Points to object holding script * to check. */ { CONST char *script; int length; script = Tcl_GetStringFromObj(objPtr, &length); return CommandComplete(script, length); } /* *---------------------------------------------------------------------- * * TclIsLocalScalar -- * * Check to see if a given string is a legal scalar variable * name with no namespace qualifiers or substitutions. * * Results: * Returns 1 if the variable is a local scalar. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclIsLocalScalar(src, len) CONST char *src; int len; { CONST char *p; CONST char *lastChar = src + (len - 1); for (p = src; p <= lastChar; p++) { if ((CHAR_TYPE(*p) != TYPE_NORMAL) && (CHAR_TYPE(*p) != TYPE_COMMAND_END)) { /* * TCL_COMMAND_END is returned for the last character * of the string. By this point we know it isn't * an array or namespace reference. */ return 0; } if (*p == '(') { if (*lastChar == ')') { /* we have an array element */ return 0; } } else if (*p == ':') { if ((p != lastChar) && *(p+1) == ':') { /* qualified name */ return 0; } } } return 1; } tcl8.4.20/generic/tclRegexp.h0000644003604700454610000000310311737050674014436 0ustar dgp771div/* * tclRegexp.h -- * * This file contains definitions used internally by Henry * Spencer's regular expression code. * * Copyright (c) 1998 by Sun Microsystems, Inc. * Copyright (c) 1998-1999 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef _TCLREGEXP #define _TCLREGEXP #include "regex.h" #ifdef BUILD_tcl # undef TCL_STORAGE_CLASS # define TCL_STORAGE_CLASS DLLEXPORT #endif /* * The TclRegexp structure encapsulates a compiled regex_t, * the flags that were used to compile it, and an array of pointers * that are used to indicate subexpressions after a call to Tcl_RegExpExec. * Note that the string and objPtr are mutually exclusive. These values * are needed by Tcl_RegExpRange in order to return pointers into the * original string. */ typedef struct TclRegexp { int flags; /* Regexp compile flags. */ regex_t re; /* Compiled re, includes number of * subexpressions. */ CONST char *string; /* Last string passed to Tcl_RegExpExec. */ Tcl_Obj *objPtr; /* Last object passed to Tcl_RegExpExecObj. */ regmatch_t *matches; /* Array of indices into the Tcl_UniChar * representation of the last string matched * with this regexp to indicate the location * of subexpressions. */ rm_detail_t details; /* Detailed information on match (currently * used only for REG_EXPECT). */ int refCount; /* Count of number of references to this * compiled regexp. */ } TclRegexp; #endif /* _TCLREGEXP */ tcl8.4.20/generic/tclObj.c0000644003604700454610000031741111737050674013723 0ustar dgp771div/* * tclObj.c -- * * This file contains Tcl object-related procedures that are used by * many Tcl commands. * * Copyright (c) 1995-1997 Sun Microsystems, Inc. * Copyright (c) 1999 by Scriptics Corporation. * Copyright (c) 2001 by ActiveState Corporation. * Copyright (c) 2007 Daniel A. Steffen * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclCompile.h" #include "tclPort.h" /* * Table of all object types. */ static Tcl_HashTable typeTable; static int typeTableInitialized = 0; /* 0 means not yet initialized. */ TCL_DECLARE_MUTEX(tableMutex) /* * Head of the list of free Tcl_Obj structs we maintain. */ Tcl_Obj *tclFreeObjList = NULL; /* * The object allocator is single threaded. This mutex is referenced * by the TclNewObj macro, however, so must be visible. */ #ifdef TCL_THREADS Tcl_Mutex tclObjMutex; #endif /* * Pointer to a heap-allocated string of length zero that the Tcl core uses * as the value of an empty string representation for an object. This value * is shared by all new objects allocated by Tcl_NewObj. */ char tclEmptyString = '\0'; char *tclEmptyStringRep = &tclEmptyString; #ifdef TCL_TIP280 /* * All static variables used in this file are collected into a single * instance of the following structure. For multi-threaded implementations, * there is one instance of this structure for each thread. * * Notice that different structures with the same name appear in other * files. The structure defined below is used in this file only. */ typedef struct ThreadSpecificData { Tcl_HashTable* lineCLPtr; /* This table remembers for each Tcl_Obj generated * by a call to the function EvalTokensStandard() * from a literal text where bs+nl sequences * occured in it, if any. I.e. this table keeps * track of invisible/stripped continuation * lines. Its keys are Tcl_Obj pointers, the * values are ContLineLoc pointers. See the file * tclCompile.h for the definition of this * structure, and for references to all related * places in the core. */ } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; static void ContLineLocFree _ANSI_ARGS_((char* clientData)); static void TclThreadFinalizeObjects _ANSI_ARGS_((ClientData clientData)); static ThreadSpecificData* TclGetContinuationTable _ANSI_ARGS_(()); #endif /* * Prototypes for procedures defined later in this file: */ static int SetBooleanFromAny _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr)); static int SetDoubleFromAny _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr)); static int SetIntFromAny _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr)); static int SetIntOrWideFromAny _ANSI_ARGS_((Tcl_Interp* interp, Tcl_Obj *objPtr)); static void UpdateStringOfBoolean _ANSI_ARGS_((Tcl_Obj *objPtr)); static void UpdateStringOfDouble _ANSI_ARGS_((Tcl_Obj *objPtr)); static void UpdateStringOfInt _ANSI_ARGS_((Tcl_Obj *objPtr)); static int SetWideIntFromAny _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr)); #ifndef TCL_WIDE_INT_IS_LONG static void UpdateStringOfWideInt _ANSI_ARGS_((Tcl_Obj *objPtr)); #endif /* * Prototypes for the array hash key methods. */ static Tcl_HashEntry * AllocObjEntry _ANSI_ARGS_(( Tcl_HashTable *tablePtr, VOID *keyPtr)); static int CompareObjKeys _ANSI_ARGS_(( VOID *keyPtr, Tcl_HashEntry *hPtr)); static void FreeObjEntry _ANSI_ARGS_(( Tcl_HashEntry *hPtr)); static unsigned int HashObjKey _ANSI_ARGS_(( Tcl_HashTable *tablePtr, VOID *keyPtr)); /* * Prototypes for the CommandName object type. */ static void DupCmdNameInternalRep _ANSI_ARGS_((Tcl_Obj *objPtr, Tcl_Obj *copyPtr)); static void FreeCmdNameInternalRep _ANSI_ARGS_(( Tcl_Obj *objPtr)); static int SetCmdNameFromAny _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr)); /* * The structures below defines the Tcl object types defined in this file by * means of procedures that can be invoked by generic object code. See also * tclStringObj.c, tclListObj.c, tclByteCode.c for other type manager * implementations. */ Tcl_ObjType tclBooleanType = { "boolean", /* name */ (Tcl_FreeInternalRepProc *) NULL, /* freeIntRepProc */ (Tcl_DupInternalRepProc *) NULL, /* dupIntRepProc */ UpdateStringOfBoolean, /* updateStringProc */ SetBooleanFromAny /* setFromAnyProc */ }; Tcl_ObjType tclDoubleType = { "double", /* name */ (Tcl_FreeInternalRepProc *) NULL, /* freeIntRepProc */ (Tcl_DupInternalRepProc *) NULL, /* dupIntRepProc */ UpdateStringOfDouble, /* updateStringProc */ SetDoubleFromAny /* setFromAnyProc */ }; Tcl_ObjType tclIntType = { "int", /* name */ (Tcl_FreeInternalRepProc *) NULL, /* freeIntRepProc */ (Tcl_DupInternalRepProc *) NULL, /* dupIntRepProc */ UpdateStringOfInt, /* updateStringProc */ SetIntFromAny /* setFromAnyProc */ }; Tcl_ObjType tclWideIntType = { "wideInt", /* name */ (Tcl_FreeInternalRepProc *) NULL, /* freeIntRepProc */ (Tcl_DupInternalRepProc *) NULL, /* dupIntRepProc */ #ifdef TCL_WIDE_INT_IS_LONG UpdateStringOfInt, /* updateStringProc */ #else /* !TCL_WIDE_INT_IS_LONG */ UpdateStringOfWideInt, /* updateStringProc */ #endif SetWideIntFromAny /* setFromAnyProc */ }; /* * The structure below defines the Tcl obj hash key type. */ Tcl_HashKeyType tclObjHashKeyType = { TCL_HASH_KEY_TYPE_VERSION, /* version */ 0, /* flags */ HashObjKey, /* hashKeyProc */ CompareObjKeys, /* compareKeysProc */ AllocObjEntry, /* allocEntryProc */ FreeObjEntry /* freeEntryProc */ }; /* * The structure below defines the command name Tcl object type by means of * procedures that can be invoked by generic object code. Objects of this * type cache the Command pointer that results from looking up command names * in the command hashtable. Such objects appear as the zeroth ("command * name") argument in a Tcl command. * * NOTE: the ResolvedCmdName that gets cached is stored in the * twoPtrValue.ptr1 field, and the twoPtrValue.ptr2 field is unused. * You might think you could use the simpler otherValuePtr field to * store the single ResolvedCmdName pointer, but DO NOT DO THIS. It * seems that some extensions use the second internal pointer field * of the twoPtrValue field for their own purposes. */ static Tcl_ObjType tclCmdNameType = { "cmdName", /* name */ FreeCmdNameInternalRep, /* freeIntRepProc */ DupCmdNameInternalRep, /* dupIntRepProc */ (Tcl_UpdateStringProc *) NULL, /* updateStringProc */ SetCmdNameFromAny /* setFromAnyProc */ }; /* * Structure containing a cached pointer to a command that is the result * of resolving the command's name in some namespace. It is the internal * representation for a cmdName object. It contains the pointer along * with some information that is used to check the pointer's validity. */ typedef struct ResolvedCmdName { Command *cmdPtr; /* A cached Command pointer. */ Namespace *refNsPtr; /* Points to the namespace containing the * reference (not the namespace that * contains the referenced command). */ long refNsId; /* refNsPtr's unique namespace id. Used to * verify that refNsPtr is still valid * (e.g., it's possible that the cmd's * containing namespace was deleted and a * new one created at the same address). */ int refNsCmdEpoch; /* Value of the referencing namespace's * cmdRefEpoch when the pointer was cached. * Before using the cached pointer, we check * if the namespace's epoch was incremented; * if so, this cached pointer is invalid. */ int cmdEpoch; /* Value of the command's cmdEpoch when this * pointer was cached. Before using the * cached pointer, we check if the cmd's * epoch was incremented; if so, the cmd was * renamed, deleted, hidden, or exposed, and * so the pointer is invalid. */ int refCount; /* Reference count: 1 for each cmdName * object that has a pointer to this * ResolvedCmdName structure as its internal * rep. This structure can be freed when * refCount becomes zero. */ } ResolvedCmdName; /* *------------------------------------------------------------------------- * * TclInitObjectSubsystem -- * * This procedure is invoked to perform once-only initialization of * the type table. It also registers the object types defined in * this file. * * Results: * None. * * Side effects: * Initializes the table of defined object types "typeTable" with * builtin object types defined in this file. * *------------------------------------------------------------------------- */ void TclInitObjSubsystem() { Tcl_MutexLock(&tableMutex); typeTableInitialized = 1; Tcl_InitHashTable(&typeTable, TCL_STRING_KEYS); Tcl_MutexUnlock(&tableMutex); Tcl_RegisterObjType(&tclBooleanType); Tcl_RegisterObjType(&tclByteArrayType); Tcl_RegisterObjType(&tclDoubleType); Tcl_RegisterObjType(&tclEndOffsetType); Tcl_RegisterObjType(&tclIntType); Tcl_RegisterObjType(&tclWideIntType); Tcl_RegisterObjType(&tclStringType); Tcl_RegisterObjType(&tclListType); Tcl_RegisterObjType(&tclByteCodeType); Tcl_RegisterObjType(&tclProcBodyType); Tcl_RegisterObjType(&tclArraySearchType); Tcl_RegisterObjType(&tclIndexType); Tcl_RegisterObjType(&tclNsNameType); Tcl_RegisterObjType(&tclCmdNameType); #ifdef TCL_COMPILE_STATS Tcl_MutexLock(&tclObjMutex); tclObjsAlloced = 0; tclObjsFreed = 0; { int i; for (i = 0; i < TCL_MAX_SHARED_OBJ_STATS; i++) { tclObjsShared[i] = 0; } } Tcl_MutexUnlock(&tclObjMutex); #endif } /* *---------------------------------------------------------------------- * * TclFinalizeObjects -- * * This procedure is called by Tcl_Finalize to clean up all * registered Tcl_ObjType's and to reset the tclFreeObjList. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TclFinalizeObjects() { Tcl_MutexLock(&tableMutex); if (typeTableInitialized) { Tcl_DeleteHashTable(&typeTable); typeTableInitialized = 0; } Tcl_MutexUnlock(&tableMutex); /* * All we do here is reset the head pointer of the linked list of * free Tcl_Obj's to NULL; the memory finalization will take care * of releasing memory for us. */ Tcl_MutexLock(&tclObjMutex); tclFreeObjList = NULL; Tcl_MutexUnlock(&tclObjMutex); } #ifdef TCL_TIP280 /* *---------------------------------------------------------------------- * * TclGetContinuationTable -- * * This procedure is a helper which returns the thread-specific * hash-table used to track continuation line information associated with * Tcl_Obj*. * * Results: * A reference to the continuation line thread-data. * * Side effects: * May allocate memory for the thread-data. * * TIP #280 *---------------------------------------------------------------------- */ static ThreadSpecificData* TclGetContinuationTable() { /* * Initialize the hashtable tracking invisible continuation lines. For * the release we use a thread exit handler to ensure that this is done * before TSD blocks are made invalid. The TclFinalizeObjects() which * would be the natural place for this is invoked afterwards, meaning that * we try to operate on a data structure already gone. */ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (!tsdPtr->lineCLPtr) { tsdPtr->lineCLPtr = (Tcl_HashTable*) ckalloc (sizeof (Tcl_HashTable)); Tcl_InitHashTable(tsdPtr->lineCLPtr, TCL_ONE_WORD_KEYS); Tcl_CreateThreadExitHandler (TclThreadFinalizeObjects,NULL); } return tsdPtr; } /* *---------------------------------------------------------------------- * * TclContinuationsEnter -- * * This procedure is a helper which saves the continuation line * information associated with a Tcl_Obj*. * * Results: * A reference to the newly created continuation line location table. * * Side effects: * Allocates memory for the table of continuation line locations. * * TIP #280 *---------------------------------------------------------------------- */ ContLineLoc* TclContinuationsEnter(objPtr,num,loc) Tcl_Obj* objPtr; int num; int* loc; { int newEntry; ThreadSpecificData *tsdPtr = TclGetContinuationTable(); Tcl_HashEntry* hPtr = Tcl_CreateHashEntry (tsdPtr->lineCLPtr, (char*) objPtr, &newEntry); ContLineLoc* clLocPtr = (ContLineLoc*) ckalloc (sizeof(ContLineLoc) + num*sizeof(int)); if (!newEntry) { /* * Somehow we're entering ContLineLoc data for the same value (objPtr) * more than one time. Not sure whether that's expected, or a sign of * trouble, but at a minimum, we should take care not to leak the old * entry. */ ckfree((char *) Tcl_GetHashValue(hPtr)); } clLocPtr->num = num; memcpy (&clLocPtr->loc, loc, num*sizeof(int)); clLocPtr->loc[num] = CLL_END; /* Sentinel */ Tcl_SetHashValue (hPtr, clLocPtr); return clLocPtr; } /* *---------------------------------------------------------------------- * * TclContinuationsEnterDerived -- * * This procedure is a helper which computes the continuation line * information associated with a Tcl_Obj* cut from the middle of a * script. * * Results: * None. * * Side effects: * Allocates memory for the table of continuation line locations. * * TIP #280 *---------------------------------------------------------------------- */ void TclContinuationsEnterDerived(objPtr, start, clNext) Tcl_Obj* objPtr; int start; int* clNext; { /* * We have to handle invisible continuations lines here as well, despite * the code we have in EvalTokensStandard (ETS) for that. Why ? * Nesting. If our script is the sole argument to an 'eval' command, for * example, the scriptCLLocPtr we are using here was generated by a * previous call to ETS, and while the words we have here may contain * continuation lines they are invisible already, and the call to ETS * above had no bs+nl sequences to trigger its code. * * Luckily for us, the table we have to create here for the current word * has to be a slice of the table currently in use, with the locations * suitably modified to be relative to the start of the word instead of * relative to the script. * * That is what we are doing now. Determine the slice we need, and if not * empty, wrap it into a new table, and save the result into our * thread-global hashtable, as usual. */ /* * First compute the range of the word within the script. */ int length, end, num; int* wordCLLast = clNext; Tcl_GetStringFromObj(objPtr, &length); /* Is there a better way which doesn't shimmer ? */ end = start + length; /* first char after the word */ /* * Then compute the table slice covering the range of * the word. */ while (*wordCLLast >= 0 && *wordCLLast < end) { wordCLLast++; } /* * And generate the table from the slice, if it was * not empty. */ num = wordCLLast - clNext; if (num) { int i; ContLineLoc* clLocPtr = TclContinuationsEnter(objPtr, num, clNext); /* * Re-base the locations. */ for (i=0;iloc[i] -= start; /* * Continuation lines coming before the string and affecting us * should not happen, due to the proper maintenance of clNext * during compilation. */ if (clLocPtr->loc[i] < 0) { Tcl_Panic("Derived ICL data for object using offsets from before the script"); } } } } /* *---------------------------------------------------------------------- * * TclContinuationsCopy -- * * This procedure is a helper which copies the continuation line * information associated with a Tcl_Obj* to another Tcl_Obj*. * It is assumed that both contain the same string/script. Use * this when a script is duplicated because it was shared. * * Results: * None. * * Side effects: * Allocates memory for the table of continuation line locations. * * TIP #280 *---------------------------------------------------------------------- */ void TclContinuationsCopy(Tcl_Obj* objPtr, Tcl_Obj* originObjPtr) { ThreadSpecificData *tsdPtr = TclGetContinuationTable(); Tcl_HashEntry* hPtr = Tcl_FindHashEntry (tsdPtr->lineCLPtr, (char*) originObjPtr); if (hPtr) { ContLineLoc* clLocPtr = (ContLineLoc*) Tcl_GetHashValue (hPtr); TclContinuationsEnter(objPtr, clLocPtr->num, clLocPtr->loc); } } /* *---------------------------------------------------------------------- * * TclContinuationsGet -- * * This procedure is a helper which retrieves the continuation line * information associated with a Tcl_Obj*, if it has any. * * Results: * A reference to the continuation line location table, or NULL * if the Tcl_Obj* has no such information associated with it. * * Side effects: * None. * * TIP #280 *---------------------------------------------------------------------- */ ContLineLoc* TclContinuationsGet(objPtr) Tcl_Obj* objPtr; { ThreadSpecificData *tsdPtr = TclGetContinuationTable(); Tcl_HashEntry* hPtr = Tcl_FindHashEntry (tsdPtr->lineCLPtr, (char*) objPtr); if (hPtr) { return (ContLineLoc*) Tcl_GetHashValue (hPtr); } else { return NULL; } } /* *---------------------------------------------------------------------- * * TclThreadFinalizeObjects -- * * This procedure is a helper which releases all continuation line * information currently known. It is run as a thread exit handler. * * Results: * None. * * Side effects: * Releases memory. * * TIP #280 *---------------------------------------------------------------------- */ static void TclThreadFinalizeObjects (clientData) ClientData clientData; { /* * Release the hashtable tracking invisible continuation lines. */ Tcl_HashEntry *hPtr; Tcl_HashSearch hSearch; ThreadSpecificData *tsdPtr = TclGetContinuationTable(); for (hPtr = Tcl_FirstHashEntry(tsdPtr->lineCLPtr, &hSearch); hPtr != NULL; hPtr = Tcl_NextHashEntry(&hSearch)) { /* * We are not using Tcl_EventuallyFree (as in * TclFreeObj()) because here we can be sure that the * compiler will not hold references to the data in the * hashtable, and using TEF might bork the finalization * sequence. */ ContLineLocFree (Tcl_GetHashValue (hPtr)); Tcl_DeleteHashEntry (hPtr); } Tcl_DeleteHashTable (tsdPtr->lineCLPtr); tsdPtr->lineCLPtr = NULL; } /* *---------------------------------------------------------------------- * * ContLineLocFree -- * * The freProc for continuation line location tables. * * Results: * None. * * Side effects: * Releases memory. * * TIP #280 *---------------------------------------------------------------------- */ static void ContLineLocFree (clientData) char* clientData; { ckfree (clientData); } #endif /* *-------------------------------------------------------------- * * Tcl_RegisterObjType -- * * This procedure is called to register a new Tcl object type * in the table of all object types supported by Tcl. * * Results: * None. * * Side effects: * The type is registered in the Tcl type table. If there was already * a type with the same name as in typePtr, it is replaced with the * new type. * *-------------------------------------------------------------- */ void Tcl_RegisterObjType(typePtr) Tcl_ObjType *typePtr; /* Information about object type; * storage must be statically * allocated (must live forever). */ { int new; Tcl_MutexLock(&tableMutex); Tcl_SetHashValue( Tcl_CreateHashEntry(&typeTable, typePtr->name, &new), typePtr); Tcl_MutexUnlock(&tableMutex); } /* *---------------------------------------------------------------------- * * Tcl_AppendAllObjTypes -- * * This procedure appends onto the argument object the name of each * object type as a list element. This includes the builtin object * types (e.g. int, list) as well as those added using * Tcl_NewObj. These names can be used, for example, with * Tcl_GetObjType to get pointers to the corresponding Tcl_ObjType * structures. * * Results: * The return value is normally TCL_OK; in this case the object * referenced by objPtr has each type name appended to it. If an * error occurs, TCL_ERROR is returned and the interpreter's result * holds an error message. * * Side effects: * If necessary, the object referenced by objPtr is converted into * a list object. * *---------------------------------------------------------------------- */ int Tcl_AppendAllObjTypes(interp, objPtr) Tcl_Interp *interp; /* Interpreter used for error reporting. */ Tcl_Obj *objPtr; /* Points to the Tcl object onto which the * name of each registered type is appended * as a list element. */ { register Tcl_HashEntry *hPtr; Tcl_HashSearch search; int objc; Tcl_Obj **objv; /* * Get the test for a valid list out of the way first. */ if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) { return TCL_ERROR; } /* * Type names are NUL-terminated, not counted strings. * This code relies on that. */ Tcl_MutexLock(&tableMutex); for (hPtr = Tcl_FirstHashEntry(&typeTable, &search); hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { Tcl_ListObjAppendElement(NULL, objPtr, Tcl_NewStringObj(Tcl_GetHashKey(&typeTable, hPtr), -1)); } Tcl_MutexUnlock(&tableMutex); return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_GetObjType -- * * This procedure looks up an object type by name. * * Results: * If an object type with name matching "typeName" is found, a pointer * to its Tcl_ObjType structure is returned; otherwise, NULL is * returned. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_ObjType * Tcl_GetObjType(typeName) CONST char *typeName; /* Name of Tcl object type to look up. */ { register Tcl_HashEntry *hPtr; Tcl_ObjType *typePtr = NULL; Tcl_MutexLock(&tableMutex); hPtr = Tcl_FindHashEntry(&typeTable, typeName); if (hPtr != (Tcl_HashEntry *) NULL) { typePtr = (Tcl_ObjType *) Tcl_GetHashValue(hPtr); } Tcl_MutexUnlock(&tableMutex); return typePtr; } /* *---------------------------------------------------------------------- * * Tcl_ConvertToType -- * * Convert the Tcl object "objPtr" to have type "typePtr" if possible. * * Results: * The return value is TCL_OK on success and TCL_ERROR on failure. If * TCL_ERROR is returned, then the interpreter's result contains an * error message unless "interp" is NULL. Passing a NULL "interp" * allows this procedure to be used as a test whether the conversion * could be done (and in fact was done). * * Side effects: * Any internal representation for the old type is freed. * *---------------------------------------------------------------------- */ int Tcl_ConvertToType(interp, objPtr, typePtr) Tcl_Interp *interp; /* Used for error reporting if not NULL. */ Tcl_Obj *objPtr; /* The object to convert. */ Tcl_ObjType *typePtr; /* The target type. */ { if (objPtr->typePtr == typePtr) { return TCL_OK; } /* * Use the target type's Tcl_SetFromAnyProc to set "objPtr"s internal * form as appropriate for the target type. This frees the old internal * representation. */ return typePtr->setFromAnyProc(interp, objPtr); } /* *---------------------------------------------------------------------- * * Tcl_NewObj -- * * This procedure is normally called when not debugging: i.e., when * TCL_MEM_DEBUG is not defined. It creates new Tcl objects that denote * the empty string. These objects have a NULL object type and NULL * string representation byte pointer. Type managers call this routine * to allocate new objects that they further initialize. * * When TCL_MEM_DEBUG is defined, this procedure just returns the * result of calling the debugging version Tcl_DbNewObj. * * Results: * The result is a newly allocated object that represents the empty * string. The new object's typePtr is set NULL and its ref count * is set to 0. * * Side effects: * If compiling with TCL_COMPILE_STATS, this procedure increments * the global count of allocated objects (tclObjsAlloced). * *---------------------------------------------------------------------- */ #ifdef TCL_MEM_DEBUG #undef Tcl_NewObj Tcl_Obj * Tcl_NewObj() { return Tcl_DbNewObj("unknown", 0); } #else /* if not TCL_MEM_DEBUG */ Tcl_Obj * Tcl_NewObj() { register Tcl_Obj *objPtr; /* * Use the macro defined in tclInt.h - it will use the * correct allocator. */ TclNewObj(objPtr); return objPtr; } #endif /* TCL_MEM_DEBUG */ /* *---------------------------------------------------------------------- * * Tcl_DbNewObj -- * * This procedure is normally called when debugging: i.e., when * TCL_MEM_DEBUG is defined. It creates new Tcl objects that denote the * empty string. It is the same as the Tcl_NewObj procedure above * except that it calls Tcl_DbCkalloc directly with the file name and * line number from its caller. This simplifies debugging since then * the [memory active] command will report the correct file name and line * number when reporting objects that haven't been freed. * * When TCL_MEM_DEBUG is not defined, this procedure just returns the * result of calling Tcl_NewObj. * * Results: * The result is a newly allocated that represents the empty string. * The new object's typePtr is set NULL and its ref count is set to 0. * * Side effects: * If compiling with TCL_COMPILE_STATS, this procedure increments * the global count of allocated objects (tclObjsAlloced). * *---------------------------------------------------------------------- */ #ifdef TCL_MEM_DEBUG Tcl_Obj * Tcl_DbNewObj(file, line) register CONST char *file; /* The name of the source file calling this * procedure; used for debugging. */ register int line; /* Line number in the source file; used * for debugging. */ { register Tcl_Obj *objPtr; /* * Use the macro defined in tclInt.h - it will use the * correct allocator. */ TclDbNewObj(objPtr, file, line); return objPtr; } #else /* if not TCL_MEM_DEBUG */ Tcl_Obj * Tcl_DbNewObj(file, line) CONST char *file; /* The name of the source file calling this * procedure; used for debugging. */ int line; /* Line number in the source file; used * for debugging. */ { return Tcl_NewObj(); } #endif /* TCL_MEM_DEBUG */ /* *---------------------------------------------------------------------- * * TclAllocateFreeObjects -- * * Procedure to allocate a number of free Tcl_Objs. This is done using * a single ckalloc to reduce the overhead for Tcl_Obj allocation. * * Assumes mutex is held. * * Results: * None. * * Side effects: * tclFreeObjList, the head of the list of free Tcl_Objs, is set to the * first of a number of free Tcl_Obj's linked together by their * internalRep.otherValuePtrs. * *---------------------------------------------------------------------- */ #define OBJS_TO_ALLOC_EACH_TIME 100 void TclAllocateFreeObjects() { size_t bytesToAlloc = (OBJS_TO_ALLOC_EACH_TIME * sizeof(Tcl_Obj)); char *basePtr; register Tcl_Obj *prevPtr, *objPtr; register int i; /* * This has been noted by Purify to be a potential leak. The problem is * that Tcl, when not TCL_MEM_DEBUG compiled, keeps around all allocated * Tcl_Obj's, pointed to by tclFreeObjList, when freed instead of * actually freeing the memory. TclFinalizeObjects() does not ckfree() * this memory, but leaves it to Tcl's memory subsystem finalziation to * release it. Purify apparently can't figure that out, and fires a * false alarm. */ basePtr = (char *) ckalloc(bytesToAlloc); memset(basePtr, 0, bytesToAlloc); prevPtr = NULL; objPtr = (Tcl_Obj *) basePtr; for (i = 0; i < OBJS_TO_ALLOC_EACH_TIME; i++) { objPtr->internalRep.otherValuePtr = (VOID *) prevPtr; prevPtr = objPtr; objPtr++; } tclFreeObjList = prevPtr; } #undef OBJS_TO_ALLOC_EACH_TIME /* *---------------------------------------------------------------------- * * TclFreeObj -- * * This procedure frees the memory associated with the argument * object. It is called by the tcl.h macro Tcl_DecrRefCount when an * object's ref count is zero. It is only "public" since it must * be callable by that macro wherever the macro is used. It should not * be directly called by clients. * * Results: * None. * * Side effects: * Deallocates the storage for the object's Tcl_Obj structure * after deallocating the string representation and calling the * type-specific Tcl_FreeInternalRepProc to deallocate the object's * internal representation. If compiling with TCL_COMPILE_STATS, * this procedure increments the global count of freed objects * (tclObjsFreed). * *---------------------------------------------------------------------- */ void TclFreeObj(objPtr) register Tcl_Obj *objPtr; /* The object to be freed. */ { register Tcl_ObjType *typePtr = objPtr->typePtr; #ifdef TCL_MEM_DEBUG if ((objPtr)->refCount < -1) { panic("Reference count for %lx was negative", objPtr); } #endif /* TCL_MEM_DEBUG */ TCL_DTRACE_OBJ_FREE(objPtr); if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) { typePtr->freeIntRepProc(objPtr); } Tcl_InvalidateStringRep(objPtr); /* * If debugging Tcl's memory usage, deallocate the object using ckfree. * Otherwise, deallocate it by adding it onto the list of free * Tcl_Obj structs we maintain. */ #if defined(TCL_MEM_DEBUG) || defined(PURIFY) Tcl_MutexLock(&tclObjMutex); ckfree((char *) objPtr); Tcl_MutexUnlock(&tclObjMutex); #elif defined(TCL_THREADS) && defined(USE_THREAD_ALLOC) TclThreadFreeObj(objPtr); #else Tcl_MutexLock(&tclObjMutex); objPtr->internalRep.otherValuePtr = (VOID *) tclFreeObjList; tclFreeObjList = objPtr; Tcl_MutexUnlock(&tclObjMutex); #endif /* TCL_MEM_DEBUG */ #ifdef TCL_TIP280 /* * We cannot use TclGetContinuationTable() here, because that may * re-initialize the thread-data for calls coming after the * finalization. We have to access it using the low-level call and then * check for validity. This function can be called after * TclFinalizeThreadData() has already killed the thread-global data * structures. Performing TCL_TSD_INIT will leave us with an * un-initialized memory block upon which we crash (if we where to access * the uninitialized hashtable). */ { ThreadSpecificData* tsdPtr = TCL_TSD_INIT(&dataKey); if (tsdPtr->lineCLPtr) { Tcl_HashEntry* hPtr = Tcl_FindHashEntry (tsdPtr->lineCLPtr, (char *) objPtr); if (hPtr) { Tcl_EventuallyFree (Tcl_GetHashValue (hPtr), ContLineLocFree); Tcl_DeleteHashEntry (hPtr); } } } #endif TclIncrObjsFreed(); } /* *---------------------------------------------------------------------- * * Tcl_DuplicateObj -- * * Create and return a new object that is a duplicate of the argument * object. * * Results: * The return value is a pointer to a newly created Tcl_Obj. This * object has reference count 0 and the same type, if any, as the * source object objPtr. Also: * 1) If the source object has a valid string rep, we copy it; * otherwise, the duplicate's string rep is set NULL to mark * it invalid. * 2) If the source object has an internal representation (i.e. its * typePtr is non-NULL), the new object's internal rep is set to * a copy; otherwise the new internal rep is marked invalid. * * Side effects: * What constitutes "copying" the internal representation depends on * the type. For example, if the argument object is a list, * the element objects it points to will not actually be copied but * will be shared with the duplicate list. That is, the ref counts of * the element objects will be incremented. * *---------------------------------------------------------------------- */ Tcl_Obj * Tcl_DuplicateObj(objPtr) register Tcl_Obj *objPtr; /* The object to duplicate. */ { register Tcl_ObjType *typePtr = objPtr->typePtr; register Tcl_Obj *dupPtr; TclNewObj(dupPtr); if (objPtr->bytes == NULL) { dupPtr->bytes = NULL; } else if (objPtr->bytes != tclEmptyStringRep) { TclInitStringRep(dupPtr, objPtr->bytes, objPtr->length); } if (typePtr != NULL) { if (typePtr->dupIntRepProc == NULL) { dupPtr->internalRep = objPtr->internalRep; dupPtr->typePtr = typePtr; } else { (*typePtr->dupIntRepProc)(objPtr, dupPtr); } } return dupPtr; } /* *---------------------------------------------------------------------- * * Tcl_GetString -- * * Returns the string representation byte array pointer for an object. * * Results: * Returns a pointer to the string representation of objPtr. The byte * array referenced by the returned pointer must not be modified by the * caller. Furthermore, the caller must copy the bytes if they need to * retain them since the object's string rep can change as a result of * other operations. * * Side effects: * May call the object's updateStringProc to update the string * representation from the internal representation. * *---------------------------------------------------------------------- */ char * Tcl_GetString(objPtr) register Tcl_Obj *objPtr; /* Object whose string rep byte pointer * should be returned. */ { if (objPtr->bytes != NULL) { return objPtr->bytes; } if (objPtr->typePtr->updateStringProc == NULL) { panic("UpdateStringProc should not be invoked for type %s", objPtr->typePtr->name); } (*objPtr->typePtr->updateStringProc)(objPtr); return objPtr->bytes; } /* *---------------------------------------------------------------------- * * Tcl_GetStringFromObj -- * * Returns the string representation's byte array pointer and length * for an object. * * Results: * Returns a pointer to the string representation of objPtr. If * lengthPtr isn't NULL, the length of the string representation is * stored at *lengthPtr. The byte array referenced by the returned * pointer must not be modified by the caller. Furthermore, the * caller must copy the bytes if they need to retain them since the * object's string rep can change as a result of other operations. * * Side effects: * May call the object's updateStringProc to update the string * representation from the internal representation. * *---------------------------------------------------------------------- */ char * Tcl_GetStringFromObj(objPtr, lengthPtr) register Tcl_Obj *objPtr; /* Object whose string rep byte pointer should * be returned. */ register int *lengthPtr; /* If non-NULL, the location where the string * rep's byte array length should * be stored. * If NULL, no length is stored. */ { if (objPtr->bytes == NULL) { if (objPtr->typePtr->updateStringProc == NULL) { panic("UpdateStringProc should not be invoked for type %s", objPtr->typePtr->name); } (*objPtr->typePtr->updateStringProc)(objPtr); } if (lengthPtr != NULL) { *lengthPtr = objPtr->length; } return objPtr->bytes; } /* *---------------------------------------------------------------------- * * Tcl_InvalidateStringRep -- * * This procedure is called to invalidate an object's string * representation. * * Results: * None. * * Side effects: * Deallocates the storage for any old string representation, then * sets the string representation NULL to mark it invalid. * *---------------------------------------------------------------------- */ void Tcl_InvalidateStringRep(objPtr) register Tcl_Obj *objPtr; /* Object whose string rep byte pointer * should be freed. */ { if (objPtr->bytes != NULL) { if (objPtr->bytes != tclEmptyStringRep) { ckfree((char *) objPtr->bytes); } objPtr->bytes = NULL; } } /* *---------------------------------------------------------------------- * * Tcl_NewBooleanObj -- * * This procedure is normally called when not debugging: i.e., when * TCL_MEM_DEBUG is not defined. It creates a new Tcl_Obj and * initializes it from the argument boolean value. A nonzero * "boolValue" is coerced to 1. * * When TCL_MEM_DEBUG is defined, this procedure just returns the * result of calling the debugging version Tcl_DbNewBooleanObj. * * Results: * The newly created object is returned. This object will have an * invalid string representation. The returned object has ref count 0. * * Side effects: * None. * *---------------------------------------------------------------------- */ #ifdef TCL_MEM_DEBUG #undef Tcl_NewBooleanObj Tcl_Obj * Tcl_NewBooleanObj(boolValue) register int boolValue; /* Boolean used to initialize new object. */ { return Tcl_DbNewBooleanObj(boolValue, "unknown", 0); } #else /* if not TCL_MEM_DEBUG */ Tcl_Obj * Tcl_NewBooleanObj(boolValue) register int boolValue; /* Boolean used to initialize new object. */ { register Tcl_Obj *objPtr; TclNewObj(objPtr); objPtr->bytes = NULL; objPtr->internalRep.longValue = (boolValue? 1 : 0); objPtr->typePtr = &tclBooleanType; return objPtr; } #endif /* TCL_MEM_DEBUG */ /* *---------------------------------------------------------------------- * * Tcl_DbNewBooleanObj -- * * This procedure is normally called when debugging: i.e., when * TCL_MEM_DEBUG is defined. It creates new boolean objects. It is the * same as the Tcl_NewBooleanObj procedure above except that it calls * Tcl_DbCkalloc directly with the file name and line number from its * caller. This simplifies debugging since then the [memory active] * command will report the correct file name and line number when * reporting objects that haven't been freed. * * When TCL_MEM_DEBUG is not defined, this procedure just returns the * result of calling Tcl_NewBooleanObj. * * Results: * The newly created object is returned. This object will have an * invalid string representation. The returned object has ref count 0. * * Side effects: * None. * *---------------------------------------------------------------------- */ #ifdef TCL_MEM_DEBUG Tcl_Obj * Tcl_DbNewBooleanObj(boolValue, file, line) register int boolValue; /* Boolean used to initialize new object. */ CONST char *file; /* The name of the source file calling this * procedure; used for debugging. */ int line; /* Line number in the source file; used * for debugging. */ { register Tcl_Obj *objPtr; TclDbNewObj(objPtr, file, line); objPtr->bytes = NULL; objPtr->internalRep.longValue = (boolValue? 1 : 0); objPtr->typePtr = &tclBooleanType; return objPtr; } #else /* if not TCL_MEM_DEBUG */ Tcl_Obj * Tcl_DbNewBooleanObj(boolValue, file, line) register int boolValue; /* Boolean used to initialize new object. */ CONST char *file; /* The name of the source file calling this * procedure; used for debugging. */ int line; /* Line number in the source file; used * for debugging. */ { return Tcl_NewBooleanObj(boolValue); } #endif /* TCL_MEM_DEBUG */ /* *---------------------------------------------------------------------- * * Tcl_SetBooleanObj -- * * Modify an object to be a boolean object and to have the specified * boolean value. A nonzero "boolValue" is coerced to 1. * * Results: * None. * * Side effects: * The object's old string rep, if any, is freed. Also, any old * internal rep is freed. * *---------------------------------------------------------------------- */ void Tcl_SetBooleanObj(objPtr, boolValue) register Tcl_Obj *objPtr; /* Object whose internal rep to init. */ register int boolValue; /* Boolean used to set object's value. */ { register Tcl_ObjType *oldTypePtr = objPtr->typePtr; if (Tcl_IsShared(objPtr)) { panic("Tcl_SetBooleanObj called with shared object"); } if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) { oldTypePtr->freeIntRepProc(objPtr); } objPtr->internalRep.longValue = (boolValue? 1 : 0); objPtr->typePtr = &tclBooleanType; Tcl_InvalidateStringRep(objPtr); } /* *---------------------------------------------------------------------- * * Tcl_GetBooleanFromObj -- * * Attempt to return a boolean from the Tcl object "objPtr". If the * object is not already a boolean, an attempt will be made to convert * it to one. * * Results: * The return value is a standard Tcl object result. If an error occurs * during conversion, an error message is left in the interpreter's * result unless "interp" is NULL. * * Side effects: * If the object is not already a boolean, the conversion will free * any old internal representation. * *---------------------------------------------------------------------- */ int Tcl_GetBooleanFromObj(interp, objPtr, boolPtr) Tcl_Interp *interp; /* Used for error reporting if not NULL. */ register Tcl_Obj *objPtr; /* The object from which to get boolean. */ register int *boolPtr; /* Place to store resulting boolean. */ { register int result; if (objPtr->typePtr == &tclBooleanType) { result = TCL_OK; } else { result = SetBooleanFromAny(interp, objPtr); } if (result == TCL_OK) { *boolPtr = (int) objPtr->internalRep.longValue; } return result; } /* *---------------------------------------------------------------------- * * SetBooleanFromAny -- * * Attempt to generate a boolean internal form for the Tcl object * "objPtr". * * Results: * The return value is a standard Tcl result. If an error occurs during * conversion, an error message is left in the interpreter's result * unless "interp" is NULL. * * Side effects: * If no error occurs, an integer 1 or 0 is stored as "objPtr"s * internal representation and the type of "objPtr" is set to boolean. * *---------------------------------------------------------------------- */ static int SetBooleanFromAny(interp, objPtr) Tcl_Interp *interp; /* Used for error reporting if not NULL. */ register Tcl_Obj *objPtr; /* The object to convert. */ { Tcl_ObjType *oldTypePtr = objPtr->typePtr; char *string, *end; register char c; char lowerCase[10]; int newBool, length; register int i; /* * Get the string representation. Make it up-to-date if necessary. */ string = Tcl_GetStringFromObj(objPtr, &length); /* * Use the obvious shortcuts for numerical values; if objPtr is not * of numerical type, parse its string rep. */ if (objPtr->typePtr == &tclIntType) { newBool = (objPtr->internalRep.longValue != 0); } else if (objPtr->typePtr == &tclDoubleType) { newBool = (objPtr->internalRep.doubleValue != 0.0); } else if (objPtr->typePtr == &tclWideIntType) { newBool = (objPtr->internalRep.wideValue != 0); } else { /* * Copy the string converting its characters to lower case. */ for (i = 0; (i < 9) && (i < length); i++) { c = string[i]; /* * Weed out international characters so we can safely operate * on single bytes. */ if (c & 0x80) { goto badBoolean; } if (Tcl_UniCharIsUpper(UCHAR(c))) { c = (char) Tcl_UniCharToLower(UCHAR(c)); } lowerCase[i] = c; } lowerCase[i] = 0; /* * Parse the string as a boolean. We use an implementation here that * doesn't report errors in interp if interp is NULL. */ c = lowerCase[0]; if ((c == '0') && (lowerCase[1] == '\0')) { newBool = 0; } else if ((c == '1') && (lowerCase[1] == '\0')) { newBool = 1; } else if ((c == 'y') && (strncmp(lowerCase, "yes", (size_t) length) == 0)) { newBool = 1; } else if ((c == 'n') && (strncmp(lowerCase, "no", (size_t) length) == 0)) { newBool = 0; } else if ((c == 't') && (strncmp(lowerCase, "true", (size_t) length) == 0)) { newBool = 1; } else if ((c == 'f') && (strncmp(lowerCase, "false", (size_t) length) == 0)) { newBool = 0; } else if ((c == 'o') && (length >= 2)) { if (strncmp(lowerCase, "on", (size_t) length) == 0) { newBool = 1; } else if (strncmp(lowerCase, "off", (size_t) length) == 0) { newBool = 0; } else { goto badBoolean; } } else { double dbl; /* * Boolean values can be extracted from ints or doubles. Note * that we don't use strtoul or strtoull here because we don't * care about what the value is, just whether it is equal to * zero or not. */ #ifdef TCL_WIDE_INT_IS_LONG newBool = strtol(string, &end, 0); if (end != string) { /* * Make sure the string has no garbage after the end of * the int. */ while ((end < (string+length)) && isspace(UCHAR(*end))) { /* INTL: ISO only */ end++; } if (end == (string+length)) { newBool = (newBool != 0); goto goodBoolean; } } #else /* !TCL_WIDE_INT_IS_LONG */ Tcl_WideInt wide = strtoll(string, &end, 0); if (end != string) { /* * Make sure the string has no garbage after the end of * the wide int. */ while ((end < (string+length)) && isspace(UCHAR(*end))) { /* INTL: ISO only */ end++; } if (end == (string+length)) { newBool = (wide != Tcl_LongAsWide(0)); goto goodBoolean; } } #endif /* TCL_WIDE_INT_IS_LONG */ /* * Still might be a string containing the characters representing an * int or double that wasn't handled above. This would be a string * like "27" or "1.0" that is non-zero and not "1". Such a string * would result in the boolean value true. We try converting to * double. If that succeeds and the resulting double is non-zero, we * have a "true". Note that numbers can't have embedded NULLs. */ dbl = strtod(string, &end); if (end == string) { goto badBoolean; } /* * Make sure the string has no garbage after the end of the double. */ while ((end < (string+length)) && isspace(UCHAR(*end))) { /* INTL: ISO only */ end++; } if (end != (string+length)) { goto badBoolean; } newBool = (dbl != 0.0); } } /* * Free the old internalRep before setting the new one. We do this as * late as possible to allow the conversion code, in particular * Tcl_GetStringFromObj, to use that old internalRep. */ goodBoolean: if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) { oldTypePtr->freeIntRepProc(objPtr); } objPtr->internalRep.longValue = newBool; objPtr->typePtr = &tclBooleanType; return TCL_OK; badBoolean: if (interp != NULL) { /* * Must copy string before resetting the result in case a caller * is trying to convert the interpreter's result to a boolean. */ char buf[100]; sprintf(buf, "expected boolean value but got \"%.50s\"", string); Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), buf, -1); } return TCL_ERROR; } /* *---------------------------------------------------------------------- * * UpdateStringOfBoolean -- * * Update the string representation for a boolean object. * Note: This procedure does not free an existing old string rep * so storage will be lost if this has not already been done. * * Results: * None. * * Side effects: * The object's string is set to a valid string that results from * the boolean-to-string conversion. * *---------------------------------------------------------------------- */ static void UpdateStringOfBoolean(objPtr) register Tcl_Obj *objPtr; /* Int object whose string rep to update. */ { char *s = ckalloc((unsigned) 2); s[0] = (char) (objPtr->internalRep.longValue? '1' : '0'); s[1] = '\0'; objPtr->bytes = s; objPtr->length = 1; } /* *---------------------------------------------------------------------- * * Tcl_NewDoubleObj -- * * This procedure is normally called when not debugging: i.e., when * TCL_MEM_DEBUG is not defined. It creates a new double object and * initializes it from the argument double value. * * When TCL_MEM_DEBUG is defined, this procedure just returns the * result of calling the debugging version Tcl_DbNewDoubleObj. * * Results: * The newly created object is returned. This object will have an * invalid string representation. The returned object has ref count 0. * * Side effects: * None. * *---------------------------------------------------------------------- */ #ifdef TCL_MEM_DEBUG #undef Tcl_NewDoubleObj Tcl_Obj * Tcl_NewDoubleObj(dblValue) register double dblValue; /* Double used to initialize the object. */ { return Tcl_DbNewDoubleObj(dblValue, "unknown", 0); } #else /* if not TCL_MEM_DEBUG */ Tcl_Obj * Tcl_NewDoubleObj(dblValue) register double dblValue; /* Double used to initialize the object. */ { register Tcl_Obj *objPtr; TclNewObj(objPtr); objPtr->bytes = NULL; objPtr->internalRep.doubleValue = dblValue; objPtr->typePtr = &tclDoubleType; return objPtr; } #endif /* if TCL_MEM_DEBUG */ /* *---------------------------------------------------------------------- * * Tcl_DbNewDoubleObj -- * * This procedure is normally called when debugging: i.e., when * TCL_MEM_DEBUG is defined. It creates new double objects. It is the * same as the Tcl_NewDoubleObj procedure above except that it calls * Tcl_DbCkalloc directly with the file name and line number from its * caller. This simplifies debugging since then the [memory active] * command will report the correct file name and line number when * reporting objects that haven't been freed. * * When TCL_MEM_DEBUG is not defined, this procedure just returns the * result of calling Tcl_NewDoubleObj. * * Results: * The newly created object is returned. This object will have an * invalid string representation. The returned object has ref count 0. * * Side effects: * None. * *---------------------------------------------------------------------- */ #ifdef TCL_MEM_DEBUG Tcl_Obj * Tcl_DbNewDoubleObj(dblValue, file, line) register double dblValue; /* Double used to initialize the object. */ CONST char *file; /* The name of the source file calling this * procedure; used for debugging. */ int line; /* Line number in the source file; used * for debugging. */ { register Tcl_Obj *objPtr; TclDbNewObj(objPtr, file, line); objPtr->bytes = NULL; objPtr->internalRep.doubleValue = dblValue; objPtr->typePtr = &tclDoubleType; return objPtr; } #else /* if not TCL_MEM_DEBUG */ Tcl_Obj * Tcl_DbNewDoubleObj(dblValue, file, line) register double dblValue; /* Double used to initialize the object. */ CONST char *file; /* The name of the source file calling this * procedure; used for debugging. */ int line; /* Line number in the source file; used * for debugging. */ { return Tcl_NewDoubleObj(dblValue); } #endif /* TCL_MEM_DEBUG */ /* *---------------------------------------------------------------------- * * Tcl_SetDoubleObj -- * * Modify an object to be a double object and to have the specified * double value. * * Results: * None. * * Side effects: * The object's old string rep, if any, is freed. Also, any old * internal rep is freed. * *---------------------------------------------------------------------- */ void Tcl_SetDoubleObj(objPtr, dblValue) register Tcl_Obj *objPtr; /* Object whose internal rep to init. */ register double dblValue; /* Double used to set the object's value. */ { register Tcl_ObjType *oldTypePtr = objPtr->typePtr; if (Tcl_IsShared(objPtr)) { panic("Tcl_SetDoubleObj called with shared object"); } if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) { oldTypePtr->freeIntRepProc(objPtr); } objPtr->internalRep.doubleValue = dblValue; objPtr->typePtr = &tclDoubleType; Tcl_InvalidateStringRep(objPtr); } /* *---------------------------------------------------------------------- * * Tcl_GetDoubleFromObj -- * * Attempt to return a double from the Tcl object "objPtr". If the * object is not already a double, an attempt will be made to convert * it to one. * * Results: * The return value is a standard Tcl object result. If an error occurs * during conversion, an error message is left in the interpreter's * result unless "interp" is NULL. * * Side effects: * If the object is not already a double, the conversion will free * any old internal representation. * *---------------------------------------------------------------------- */ int Tcl_GetDoubleFromObj(interp, objPtr, dblPtr) Tcl_Interp *interp; /* Used for error reporting if not NULL. */ register Tcl_Obj *objPtr; /* The object from which to get a double. */ register double *dblPtr; /* Place to store resulting double. */ { register int result; if (objPtr->typePtr == &tclDoubleType) { *dblPtr = objPtr->internalRep.doubleValue; return TCL_OK; } result = SetDoubleFromAny(interp, objPtr); if (result == TCL_OK) { *dblPtr = objPtr->internalRep.doubleValue; } return result; } /* *---------------------------------------------------------------------- * * SetDoubleFromAny -- * * Attempt to generate an double-precision floating point internal form * for the Tcl object "objPtr". * * Results: * The return value is a standard Tcl object result. If an error occurs * during conversion, an error message is left in the interpreter's * result unless "interp" is NULL. * * Side effects: * If no error occurs, a double is stored as "objPtr"s internal * representation. * *---------------------------------------------------------------------- */ static int SetDoubleFromAny(interp, objPtr) Tcl_Interp *interp; /* Used for error reporting if not NULL. */ register Tcl_Obj *objPtr; /* The object to convert. */ { Tcl_ObjType *oldTypePtr = objPtr->typePtr; char *string, *end; double newDouble; int length; /* * Get the string representation. Make it up-to-date if necessary. */ string = Tcl_GetStringFromObj(objPtr, &length); /* * Now parse "objPtr"s string as an double. Numbers can't have embedded * NULLs. We use an implementation here that doesn't report errors in * interp if interp is NULL. */ errno = 0; newDouble = strtod(string, &end); if (end == string) { badDouble: if (interp != NULL) { /* * Must copy string before resetting the result in case a caller * is trying to convert the interpreter's result to an int. */ char buf[100]; sprintf(buf, "expected floating-point number but got \"%.50s\"", string); Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), buf, -1); } return TCL_ERROR; } if (errno != 0) { if (interp != NULL) { TclExprFloatError(interp, newDouble); } return TCL_ERROR; } /* * Make sure that the string has no garbage after the end of the double. */ while ((end < (string+length)) && isspace(UCHAR(*end))) { /* INTL: ISO space. */ end++; } if (end != (string+length)) { goto badDouble; } /* * The conversion to double succeeded. Free the old internalRep before * setting the new one. We do this as late as possible to allow the * conversion code, in particular Tcl_GetStringFromObj, to use that old * internalRep. */ if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) { oldTypePtr->freeIntRepProc(objPtr); } objPtr->internalRep.doubleValue = newDouble; objPtr->typePtr = &tclDoubleType; return TCL_OK; } /* *---------------------------------------------------------------------- * * UpdateStringOfDouble -- * * Update the string representation for a double-precision floating * point object. This must obey the current tcl_precision value for * double-to-string conversions. Note: This procedure does not free an * existing old string rep so storage will be lost if this has not * already been done. * * Results: * None. * * Side effects: * The object's string is set to a valid string that results from * the double-to-string conversion. * *---------------------------------------------------------------------- */ static void UpdateStringOfDouble(objPtr) register Tcl_Obj *objPtr; /* Double obj with string rep to update. */ { char buffer[TCL_DOUBLE_SPACE]; register int len; Tcl_PrintDouble((Tcl_Interp *) NULL, objPtr->internalRep.doubleValue, buffer); len = strlen(buffer); objPtr->bytes = (char *) ckalloc((unsigned) len + 1); strcpy(objPtr->bytes, buffer); objPtr->length = len; } /* *---------------------------------------------------------------------- * * Tcl_NewIntObj -- * * If a client is compiled with TCL_MEM_DEBUG defined, calls to * Tcl_NewIntObj to create a new integer object end up calling the * debugging procedure Tcl_DbNewLongObj instead. * * Otherwise, if the client is compiled without TCL_MEM_DEBUG defined, * calls to Tcl_NewIntObj result in a call to one of the two * Tcl_NewIntObj implementations below. We provide two implementations * so that the Tcl core can be compiled to do memory debugging of the * core even if a client does not request it for itself. * * Integer and long integer objects share the same "integer" type * implementation. We store all integers as longs and Tcl_GetIntFromObj * checks whether the current value of the long can be represented by * an int. * * Results: * The newly created object is returned. This object will have an * invalid string representation. The returned object has ref count 0. * * Side effects: * None. * *---------------------------------------------------------------------- */ #ifdef TCL_MEM_DEBUG #undef Tcl_NewIntObj Tcl_Obj * Tcl_NewIntObj(intValue) register int intValue; /* Int used to initialize the new object. */ { return Tcl_DbNewLongObj((long)intValue, "unknown", 0); } #else /* if not TCL_MEM_DEBUG */ Tcl_Obj * Tcl_NewIntObj(intValue) register int intValue; /* Int used to initialize the new object. */ { register Tcl_Obj *objPtr; TclNewObj(objPtr); objPtr->bytes = NULL; objPtr->internalRep.longValue = (long)intValue; objPtr->typePtr = &tclIntType; return objPtr; } #endif /* if TCL_MEM_DEBUG */ /* *---------------------------------------------------------------------- * * Tcl_SetIntObj -- * * Modify an object to be an integer and to have the specified integer * value. * * Results: * None. * * Side effects: * The object's old string rep, if any, is freed. Also, any old * internal rep is freed. * *---------------------------------------------------------------------- */ void Tcl_SetIntObj(objPtr, intValue) register Tcl_Obj *objPtr; /* Object whose internal rep to init. */ register int intValue; /* Integer used to set object's value. */ { register Tcl_ObjType *oldTypePtr = objPtr->typePtr; if (Tcl_IsShared(objPtr)) { panic("Tcl_SetIntObj called with shared object"); } if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) { oldTypePtr->freeIntRepProc(objPtr); } objPtr->internalRep.longValue = (long) intValue; objPtr->typePtr = &tclIntType; Tcl_InvalidateStringRep(objPtr); } /* *---------------------------------------------------------------------- * * Tcl_GetIntFromObj -- * * Attempt to return an int from the Tcl object "objPtr". If the object * is not already an int, an attempt will be made to convert it to one. * * Integer and long integer objects share the same "integer" type * implementation. We store all integers as longs and Tcl_GetIntFromObj * checks whether the current value of the long can be represented by * an int. * * Results: * The return value is a standard Tcl object result. If an error occurs * during conversion or if the long integer held by the object * can not be represented by an int, an error message is left in * the interpreter's result unless "interp" is NULL. * * Side effects: * If the object is not already an int, the conversion will free * any old internal representation. * *---------------------------------------------------------------------- */ int Tcl_GetIntFromObj(interp, objPtr, intPtr) Tcl_Interp *interp; /* Used for error reporting if not NULL. */ register Tcl_Obj *objPtr; /* The object from which to get a int. */ register int *intPtr; /* Place to store resulting int. */ { int result; Tcl_WideInt w = 0; /* * If the object isn't already an integer of any width, try to * convert it to one. */ if (objPtr->typePtr != &tclIntType && objPtr->typePtr != &tclWideIntType) { result = SetIntOrWideFromAny(interp, objPtr); if (result != TCL_OK) { return result; } } /* * Object should now be either int or wide. Get its value. */ #ifndef TCL_WIDE_INT_IS_LONG if (objPtr->typePtr == &tclWideIntType) { w = objPtr->internalRep.wideValue; } else #endif { w = Tcl_LongAsWide(objPtr->internalRep.longValue); } if ((LLONG_MAX > UINT_MAX) && ((w > UINT_MAX) || (w < -(Tcl_WideInt)UINT_MAX))) { if (interp != NULL) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "integer value too large to represent as non-long integer", -1)); } return TCL_ERROR; } *intPtr = (int)w; return TCL_OK; } /* *---------------------------------------------------------------------- * * SetIntFromAny -- * * Attempts to force the internal representation for a Tcl object * to tclIntType, specifically. * * Results: * The return value is a standard object Tcl result. If an * error occurs during conversion, an error message is left in * the interpreter's result unless "interp" is NULL. * *---------------------------------------------------------------------- */ static int SetIntFromAny( Tcl_Interp* interp, /* Tcl interpreter */ Tcl_Obj* objPtr ) /* Pointer to the object to convert */ { int result; result = SetIntOrWideFromAny( interp, objPtr ); if ( result != TCL_OK ) { return result; } if ( objPtr->typePtr != &tclIntType ) { if ( interp != NULL ) { char *s = "integer value too large to represent"; Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), s, -1); Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW", s, (char *) NULL); } return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * SetIntOrWideFromAny -- * * Attempt to generate an integer internal form for the Tcl object * "objPtr". * * Results: * The return value is a standard object Tcl result. If an error occurs * during conversion, an error message is left in the interpreter's * result unless "interp" is NULL. * * Side effects: * If no error occurs, an int is stored as "objPtr"s internal * representation. * *---------------------------------------------------------------------- */ static int SetIntOrWideFromAny(interp, objPtr) Tcl_Interp *interp; /* Used for error reporting if not NULL. */ register Tcl_Obj *objPtr; /* The object to convert. */ { Tcl_ObjType *oldTypePtr = objPtr->typePtr; char *string, *end; int length; register char *p; unsigned long newLong; int isNegative = 0; int isWide = 0; /* * Get the string representation. Make it up-to-date if necessary. */ p = string = Tcl_GetStringFromObj(objPtr, &length); /* * Now parse "objPtr"s string as an int. We use an implementation here * that doesn't report errors in interp if interp is NULL. Note: use * strtoul instead of strtol for integer conversions to allow full-size * unsigned numbers, but don't depend on strtoul to handle sign * characters; it won't in some implementations. */ errno = 0; for ( ; isspace(UCHAR(*p)); p++) { /* INTL: ISO space. */ /* Empty loop body. */ } if (*p == '-') { p++; isNegative = 1; } else if (*p == '+') { p++; } if (!isdigit(UCHAR(*p))) { badInteger: if (interp != NULL) { /* * Must copy string before resetting the result in case a caller * is trying to convert the interpreter's result to an int. */ char buf[100]; sprintf(buf, "expected integer but got \"%.50s\"", string); Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), buf, -1); TclCheckBadOctal(interp, string); } return TCL_ERROR; } newLong = strtoul(p, &end, 0); if (end == p) { goto badInteger; } if (errno == ERANGE) { if (interp != NULL) { char *s = "integer value too large to represent"; Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), s, -1); Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW", s, (char *) NULL); } return TCL_ERROR; } /* * Make sure that the string has no garbage after the end of the int. */ while ((end < (string+length)) && isspace(UCHAR(*end))) { /* INTL: ISO space. */ end++; } if (end != (string+length)) { goto badInteger; } /* * If the resulting integer will exceed the range of a long, * put it into a wide instead. (Tcl Bug #868489) */ #ifndef TCL_WIDE_INT_IS_LONG if ((isNegative && newLong > (unsigned long) (LONG_MAX) + 1) || (!isNegative && newLong > LONG_MAX)) { isWide = 1; } #endif /* * The conversion to int succeeded. Free the old internalRep before * setting the new one. We do this as late as possible to allow the * conversion code, in particular Tcl_GetStringFromObj, to use that old * internalRep. */ if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) { oldTypePtr->freeIntRepProc(objPtr); } if (isWide) { objPtr->internalRep.wideValue = (isNegative ? -(Tcl_WideInt)newLong : (Tcl_WideInt)newLong); objPtr->typePtr = &tclWideIntType; } else { objPtr->internalRep.longValue = (isNegative ? -(long)newLong : (long)newLong); objPtr->typePtr = &tclIntType; } return TCL_OK; } /* *---------------------------------------------------------------------- * * UpdateStringOfInt -- * * Update the string representation for an integer object. * Note: This procedure does not free an existing old string rep * so storage will be lost if this has not already been done. * * Results: * None. * * Side effects: * The object's string is set to a valid string that results from * the int-to-string conversion. * *---------------------------------------------------------------------- */ static void UpdateStringOfInt(objPtr) register Tcl_Obj *objPtr; /* Int object whose string rep to update. */ { char buffer[TCL_INTEGER_SPACE]; register int len; len = TclFormatInt(buffer, objPtr->internalRep.longValue); objPtr->bytes = ckalloc((unsigned) len + 1); strcpy(objPtr->bytes, buffer); objPtr->length = len; } /* *---------------------------------------------------------------------- * * Tcl_NewLongObj -- * * If a client is compiled with TCL_MEM_DEBUG defined, calls to * Tcl_NewLongObj to create a new long integer object end up calling * the debugging procedure Tcl_DbNewLongObj instead. * * Otherwise, if the client is compiled without TCL_MEM_DEBUG defined, * calls to Tcl_NewLongObj result in a call to one of the two * Tcl_NewLongObj implementations below. We provide two implementations * so that the Tcl core can be compiled to do memory debugging of the * core even if a client does not request it for itself. * * Integer and long integer objects share the same "integer" type * implementation. We store all integers as longs and Tcl_GetIntFromObj * checks whether the current value of the long can be represented by * an int. * * Results: * The newly created object is returned. This object will have an * invalid string representation. The returned object has ref count 0. * * Side effects: * None. * *---------------------------------------------------------------------- */ #ifdef TCL_MEM_DEBUG #undef Tcl_NewLongObj Tcl_Obj * Tcl_NewLongObj(longValue) register long longValue; /* Long integer used to initialize the * new object. */ { return Tcl_DbNewLongObj(longValue, "unknown", 0); } #else /* if not TCL_MEM_DEBUG */ Tcl_Obj * Tcl_NewLongObj(longValue) register long longValue; /* Long integer used to initialize the * new object. */ { register Tcl_Obj *objPtr; TclNewObj(objPtr); objPtr->bytes = NULL; objPtr->internalRep.longValue = longValue; objPtr->typePtr = &tclIntType; return objPtr; } #endif /* if TCL_MEM_DEBUG */ /* *---------------------------------------------------------------------- * * Tcl_DbNewLongObj -- * * If a client is compiled with TCL_MEM_DEBUG defined, calls to * Tcl_NewIntObj and Tcl_NewLongObj to create new integer or * long integer objects end up calling the debugging procedure * Tcl_DbNewLongObj instead. We provide two implementations of * Tcl_DbNewLongObj so that whether the Tcl core is compiled to do * memory debugging of the core is independent of whether a client * requests debugging for itself. * * When the core is compiled with TCL_MEM_DEBUG defined, * Tcl_DbNewLongObj calls Tcl_DbCkalloc directly with the file name and * line number from its caller. This simplifies debugging since then * the [memory active] command will report the caller's file name and * line number when reporting objects that haven't been freed. * * Otherwise, when the core is compiled without TCL_MEM_DEBUG defined, * this procedure just returns the result of calling Tcl_NewLongObj. * * Results: * The newly created long integer object is returned. This object * will have an invalid string representation. The returned object has * ref count 0. * * Side effects: * Allocates memory. * *---------------------------------------------------------------------- */ #ifdef TCL_MEM_DEBUG Tcl_Obj * Tcl_DbNewLongObj(longValue, file, line) register long longValue; /* Long integer used to initialize the * new object. */ CONST char *file; /* The name of the source file calling this * procedure; used for debugging. */ int line; /* Line number in the source file; used * for debugging. */ { register Tcl_Obj *objPtr; TclDbNewObj(objPtr, file, line); objPtr->bytes = NULL; objPtr->internalRep.longValue = longValue; objPtr->typePtr = &tclIntType; return objPtr; } #else /* if not TCL_MEM_DEBUG */ Tcl_Obj * Tcl_DbNewLongObj(longValue, file, line) register long longValue; /* Long integer used to initialize the * new object. */ CONST char *file; /* The name of the source file calling this * procedure; used for debugging. */ int line; /* Line number in the source file; used * for debugging. */ { return Tcl_NewLongObj(longValue); } #endif /* TCL_MEM_DEBUG */ /* *---------------------------------------------------------------------- * * Tcl_SetLongObj -- * * Modify an object to be an integer object and to have the specified * long integer value. * * Results: * None. * * Side effects: * The object's old string rep, if any, is freed. Also, any old * internal rep is freed. * *---------------------------------------------------------------------- */ void Tcl_SetLongObj(objPtr, longValue) register Tcl_Obj *objPtr; /* Object whose internal rep to init. */ register long longValue; /* Long integer used to initialize the * object's value. */ { register Tcl_ObjType *oldTypePtr = objPtr->typePtr; if (Tcl_IsShared(objPtr)) { panic("Tcl_SetLongObj called with shared object"); } if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) { oldTypePtr->freeIntRepProc(objPtr); } objPtr->internalRep.longValue = longValue; objPtr->typePtr = &tclIntType; Tcl_InvalidateStringRep(objPtr); } /* *---------------------------------------------------------------------- * * Tcl_GetLongFromObj -- * * Attempt to return an long integer from the Tcl object "objPtr". If * the object is not already an int object, an attempt will be made to * convert it to one. * * Results: * The return value is a standard Tcl object result. If an error occurs * during conversion, an error message is left in the interpreter's * result unless "interp" is NULL. * * Side effects: * If the object is not already an int object, the conversion will free * any old internal representation. * *---------------------------------------------------------------------- */ int Tcl_GetLongFromObj(interp, objPtr, longPtr) Tcl_Interp *interp; /* Used for error reporting if not NULL. */ register Tcl_Obj *objPtr; /* The object from which to get a long. */ register long *longPtr; /* Place to store resulting long. */ { register int result; if (objPtr->typePtr != &tclIntType && objPtr->typePtr != &tclWideIntType) { result = SetIntOrWideFromAny(interp, objPtr); if (result != TCL_OK) { return result; } } #ifndef TCL_WIDE_INT_IS_LONG if (objPtr->typePtr == &tclWideIntType) { /* * If the object is already a wide integer, don't convert it. * This code allows for any integer in the range -ULONG_MAX to * ULONG_MAX to be converted to a long, ignoring overflow. * The rule preserves existing semantics for conversion of * integers on input, but avoids inadvertent demotion of * wide integers to 32-bit ones in the internal rep. */ Tcl_WideInt w = objPtr->internalRep.wideValue; if (w >= -(Tcl_WideInt)(ULONG_MAX) && w <= (Tcl_WideInt)(ULONG_MAX)) { *longPtr = Tcl_WideAsLong(w); return TCL_OK; } else { if (interp != NULL) { Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "integer value too large to represent", -1); } return TCL_ERROR; } } #endif *longPtr = objPtr->internalRep.longValue; return TCL_OK; } /* *---------------------------------------------------------------------- * * SetWideIntFromAny -- * * Attempt to generate an integer internal form for the Tcl object * "objPtr". * * Results: * The return value is a standard object Tcl result. If an error occurs * during conversion, an error message is left in the interpreter's * result unless "interp" is NULL. * * Side effects: * If no error occurs, an int is stored as "objPtr"s internal * representation. * *---------------------------------------------------------------------- */ static int SetWideIntFromAny(interp, objPtr) Tcl_Interp *interp; /* Used for error reporting if not NULL. */ register Tcl_Obj *objPtr; /* The object to convert. */ { #ifndef TCL_WIDE_INT_IS_LONG Tcl_ObjType *oldTypePtr = objPtr->typePtr; char *string, *end; int length; register char *p; Tcl_WideInt newWide; /* * Get the string representation. Make it up-to-date if necessary. */ p = string = Tcl_GetStringFromObj(objPtr, &length); /* * Now parse "objPtr"s string as an int. We use an implementation here * that doesn't report errors in interp if interp is NULL. Note: use * strtoull instead of strtoll for integer conversions to allow full-size * unsigned numbers, but don't depend on strtoull to handle sign * characters; it won't in some implementations. */ errno = 0; #ifdef TCL_STRTOUL_SIGN_CHECK for ( ; isspace(UCHAR(*p)); p++) { /* INTL: ISO space. */ /* Empty loop body. */ } if (*p == '-') { p++; newWide = -((Tcl_WideInt)strtoull(p, &end, 0)); } else if (*p == '+') { p++; newWide = strtoull(p, &end, 0); } else #else newWide = strtoull(p, &end, 0); #endif if (end == p) { badInteger: if (interp != NULL) { /* * Must copy string before resetting the result in case a caller * is trying to convert the interpreter's result to an int. */ char buf[100]; sprintf(buf, "expected integer but got \"%.50s\"", string); Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), buf, -1); TclCheckBadOctal(interp, string); } return TCL_ERROR; } if (errno == ERANGE) { if (interp != NULL) { char *s = "integer value too large to represent"; Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), s, -1); Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW", s, (char *) NULL); } return TCL_ERROR; } /* * Make sure that the string has no garbage after the end of the int. */ while ((end < (string+length)) && isspace(UCHAR(*end))) { /* INTL: ISO space. */ end++; } if (end != (string+length)) { goto badInteger; } /* * The conversion to int succeeded. Free the old internalRep before * setting the new one. We do this as late as possible to allow the * conversion code, in particular Tcl_GetStringFromObj, to use that old * internalRep. */ if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) { oldTypePtr->freeIntRepProc(objPtr); } objPtr->internalRep.wideValue = newWide; #else if (TCL_ERROR == SetIntFromAny(interp, objPtr)) { return TCL_ERROR; } #endif objPtr->typePtr = &tclWideIntType; return TCL_OK; } /* *---------------------------------------------------------------------- * * UpdateStringOfWideInt -- * * Update the string representation for a wide integer object. * Note: This procedure does not free an existing old string rep * so storage will be lost if this has not already been done. * * Results: * None. * * Side effects: * The object's string is set to a valid string that results from * the wideInt-to-string conversion. * *---------------------------------------------------------------------- */ #ifndef TCL_WIDE_INT_IS_LONG static void UpdateStringOfWideInt(objPtr) register Tcl_Obj *objPtr; /* Int object whose string rep to update. */ { char buffer[TCL_INTEGER_SPACE+2]; register unsigned len; register Tcl_WideInt wideVal = objPtr->internalRep.wideValue; /* * Note that sprintf will generate a compiler warning under * Mingw claiming %I64 is an unknown format specifier. * Just ignore this warning. We can't use %L as the format * specifier since that gets printed as a 32 bit value. */ sprintf(buffer, "%" TCL_LL_MODIFIER "d", wideVal); len = strlen(buffer); objPtr->bytes = ckalloc((unsigned) len + 1); memcpy(objPtr->bytes, buffer, len + 1); objPtr->length = len; } #endif /* TCL_WIDE_INT_IS_LONG */ /* *---------------------------------------------------------------------- * * Tcl_NewWideIntObj -- * * If a client is compiled with TCL_MEM_DEBUG defined, calls to * Tcl_NewWideIntObj to create a new 64-bit integer object end up calling * the debugging procedure Tcl_DbNewWideIntObj instead. * * Otherwise, if the client is compiled without TCL_MEM_DEBUG defined, * calls to Tcl_NewWideIntObj result in a call to one of the two * Tcl_NewWideIntObj implementations below. We provide two implementations * so that the Tcl core can be compiled to do memory debugging of the * core even if a client does not request it for itself. * * Results: * The newly created object is returned. This object will have an * invalid string representation. The returned object has ref count 0. * * Side effects: * None. * *---------------------------------------------------------------------- */ #ifdef TCL_MEM_DEBUG #undef Tcl_NewWideIntObj Tcl_Obj * Tcl_NewWideIntObj(wideValue) register Tcl_WideInt wideValue; /* Wide integer used to initialize * the new object. */ { return Tcl_DbNewWideIntObj(wideValue, "unknown", 0); } #else /* if not TCL_MEM_DEBUG */ Tcl_Obj * Tcl_NewWideIntObj(wideValue) register Tcl_WideInt wideValue; /* Wide integer used to initialize * the new object. */ { register Tcl_Obj *objPtr; TclNewObj(objPtr); objPtr->bytes = NULL; objPtr->internalRep.wideValue = wideValue; objPtr->typePtr = &tclWideIntType; return objPtr; } #endif /* if TCL_MEM_DEBUG */ /* *---------------------------------------------------------------------- * * Tcl_DbNewWideIntObj -- * * If a client is compiled with TCL_MEM_DEBUG defined, calls to * Tcl_NewWideIntObj to create new wide integer end up calling * the debugging procedure Tcl_DbNewWideIntObj instead. We * provide two implementations of Tcl_DbNewWideIntObj so that * whether the Tcl core is compiled to do memory debugging of the * core is independent of whether a client requests debugging for * itself. * * When the core is compiled with TCL_MEM_DEBUG defined, * Tcl_DbNewWideIntObj calls Tcl_DbCkalloc directly with the file * name and line number from its caller. This simplifies * debugging since then the checkmem command will report the * caller's file name and line number when reporting objects that * haven't been freed. * * Otherwise, when the core is compiled without TCL_MEM_DEBUG defined, * this procedure just returns the result of calling Tcl_NewWideIntObj. * * Results: * The newly created wide integer object is returned. This object * will have an invalid string representation. The returned object has * ref count 0. * * Side effects: * Allocates memory. * *---------------------------------------------------------------------- */ #ifdef TCL_MEM_DEBUG Tcl_Obj * Tcl_DbNewWideIntObj(wideValue, file, line) register Tcl_WideInt wideValue; /* Wide integer used to initialize * the new object. */ CONST char *file; /* The name of the source file * calling this procedure; used for * debugging. */ int line; /* Line number in the source file; * used for debugging. */ { register Tcl_Obj *objPtr; TclDbNewObj(objPtr, file, line); objPtr->bytes = NULL; objPtr->internalRep.wideValue = wideValue; objPtr->typePtr = &tclWideIntType; return objPtr; } #else /* if not TCL_MEM_DEBUG */ Tcl_Obj * Tcl_DbNewWideIntObj(wideValue, file, line) register Tcl_WideInt wideValue; /* Long integer used to initialize * the new object. */ CONST char *file; /* The name of the source file * calling this procedure; used for * debugging. */ int line; /* Line number in the source file; * used for debugging. */ { return Tcl_NewWideIntObj(wideValue); } #endif /* TCL_MEM_DEBUG */ /* *---------------------------------------------------------------------- * * Tcl_SetWideIntObj -- * * Modify an object to be a wide integer object and to have the * specified wide integer value. * * Results: * None. * * Side effects: * The object's old string rep, if any, is freed. Also, any old * internal rep is freed. * *---------------------------------------------------------------------- */ void Tcl_SetWideIntObj(objPtr, wideValue) register Tcl_Obj *objPtr; /* Object w. internal rep to init. */ register Tcl_WideInt wideValue; /* Wide integer used to initialize * the object's value. */ { register Tcl_ObjType *oldTypePtr = objPtr->typePtr; if (Tcl_IsShared(objPtr)) { panic("Tcl_SetWideIntObj called with shared object"); } if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) { oldTypePtr->freeIntRepProc(objPtr); } objPtr->internalRep.wideValue = wideValue; objPtr->typePtr = &tclWideIntType; Tcl_InvalidateStringRep(objPtr); } /* *---------------------------------------------------------------------- * * Tcl_GetWideIntFromObj -- * * Attempt to return a wide integer from the Tcl object "objPtr". If * the object is not already a wide int object, an attempt will be made * to convert it to one. * * Results: * The return value is a standard Tcl object result. If an error occurs * during conversion, an error message is left in the interpreter's * result unless "interp" is NULL. * * Side effects: * If the object is not already an int object, the conversion will free * any old internal representation. * *---------------------------------------------------------------------- */ int Tcl_GetWideIntFromObj(interp, objPtr, wideIntPtr) Tcl_Interp *interp; /* Used for error reporting if not NULL. */ register Tcl_Obj *objPtr; /* Object from which to get a wide int. */ register Tcl_WideInt *wideIntPtr; /* Place to store resulting long. */ { register int result; if (objPtr->typePtr == &tclWideIntType) { gotWide: *wideIntPtr = objPtr->internalRep.wideValue; return TCL_OK; } if (objPtr->typePtr == &tclIntType) { /* * This cast is safe; all valid ints/longs are wides. */ objPtr->internalRep.wideValue = Tcl_LongAsWide(objPtr->internalRep.longValue); objPtr->typePtr = &tclWideIntType; goto gotWide; } result = SetWideIntFromAny(interp, objPtr); if (result == TCL_OK) { *wideIntPtr = objPtr->internalRep.wideValue; } return result; } /* *---------------------------------------------------------------------- * * Tcl_DbIncrRefCount -- * * This procedure is normally called when debugging: i.e., when * TCL_MEM_DEBUG is defined. This checks to see whether or not * the memory has been freed before incrementing the ref count. * * When TCL_MEM_DEBUG is not defined, this procedure just increments * the reference count of the object. * * Results: * None. * * Side effects: * The object's ref count is incremented. * *---------------------------------------------------------------------- */ void Tcl_DbIncrRefCount(objPtr, file, line) register Tcl_Obj *objPtr; /* The object we are registering a * reference to. */ CONST char *file; /* The name of the source file calling this * procedure; used for debugging. */ int line; /* Line number in the source file; used * for debugging. */ { #ifdef TCL_MEM_DEBUG if (objPtr->refCount == 0x61616161) { fprintf(stderr, "file = %s, line = %d\n", file, line); fflush(stderr); panic("Trying to increment refCount of previously disposed object."); } #endif ++(objPtr)->refCount; } /* *---------------------------------------------------------------------- * * Tcl_DbDecrRefCount -- * * This procedure is normally called when debugging: i.e., when * TCL_MEM_DEBUG is defined. This checks to see whether or not * the memory has been freed before decrementing the ref count. * * When TCL_MEM_DEBUG is not defined, this procedure just decrements * the reference count of the object. * * Results: * None. * * Side effects: * The object's ref count is incremented. * *---------------------------------------------------------------------- */ void Tcl_DbDecrRefCount(objPtr, file, line) register Tcl_Obj *objPtr; /* The object we are releasing a reference * to. */ CONST char *file; /* The name of the source file calling this * procedure; used for debugging. */ int line; /* Line number in the source file; used * for debugging. */ { #ifdef TCL_MEM_DEBUG if (objPtr->refCount == 0x61616161) { fprintf(stderr, "file = %s, line = %d\n", file, line); fflush(stderr); panic("Trying to decrement refCount of previously disposed object."); } #endif if (--(objPtr)->refCount <= 0) { TclFreeObj(objPtr); } } /* *---------------------------------------------------------------------- * * Tcl_DbIsShared -- * * This procedure is normally called when debugging: i.e., when * TCL_MEM_DEBUG is defined. It tests whether the object has a ref * count greater than one. * * When TCL_MEM_DEBUG is not defined, this procedure just tests * if the object has a ref count greater than one. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_DbIsShared(objPtr, file, line) register Tcl_Obj *objPtr; /* The object to test for being shared. */ CONST char *file; /* The name of the source file calling this * procedure; used for debugging. */ int line; /* Line number in the source file; used * for debugging. */ { #ifdef TCL_MEM_DEBUG if (objPtr->refCount == 0x61616161) { fprintf(stderr, "file = %s, line = %d\n", file, line); fflush(stderr); panic("Trying to check whether previously disposed object is shared."); } #endif #ifdef TCL_COMPILE_STATS Tcl_MutexLock(&tclObjMutex); if ((objPtr)->refCount <= 1) { tclObjsShared[1]++; } else if ((objPtr)->refCount < TCL_MAX_SHARED_OBJ_STATS) { tclObjsShared[(objPtr)->refCount]++; } else { tclObjsShared[0]++; } Tcl_MutexUnlock(&tclObjMutex); #endif return ((objPtr)->refCount > 1); } /* *---------------------------------------------------------------------- * * Tcl_InitObjHashTable -- * * Given storage for a hash table, set up the fields to prepare * the hash table for use, the keys are Tcl_Obj *. * * Results: * None. * * Side effects: * TablePtr is now ready to be passed to Tcl_FindHashEntry and * Tcl_CreateHashEntry. * *---------------------------------------------------------------------- */ void Tcl_InitObjHashTable(tablePtr) register Tcl_HashTable *tablePtr; /* Pointer to table record, which * is supplied by the caller. */ { Tcl_InitCustomHashTable(tablePtr, TCL_CUSTOM_PTR_KEYS, &tclObjHashKeyType); } /* *---------------------------------------------------------------------- * * AllocObjEntry -- * * Allocate space for a Tcl_HashEntry containing the Tcl_Obj * key. * * Results: * The return value is a pointer to the created entry. * * Side effects: * Increments the reference count on the object. * *---------------------------------------------------------------------- */ static Tcl_HashEntry * AllocObjEntry(tablePtr, keyPtr) Tcl_HashTable *tablePtr; /* Hash table. */ VOID *keyPtr; /* Key to store in the hash table entry. */ { Tcl_Obj *objPtr = (Tcl_Obj *) keyPtr; Tcl_HashEntry *hPtr; hPtr = (Tcl_HashEntry *) ckalloc((unsigned) (sizeof(Tcl_HashEntry))); hPtr->key.oneWordValue = (char *) objPtr; Tcl_IncrRefCount (objPtr); return hPtr; } /* *---------------------------------------------------------------------- * * CompareObjKeys -- * * Compares two Tcl_Obj * keys. * * Results: * The return value is 0 if they are different and 1 if they are * the same. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int CompareObjKeys(keyPtr, hPtr) VOID *keyPtr; /* New key to compare. */ Tcl_HashEntry *hPtr; /* Existing key to compare. */ { Tcl_Obj *objPtr1 = (Tcl_Obj *) keyPtr; Tcl_Obj *objPtr2 = (Tcl_Obj *) hPtr->key.oneWordValue; register CONST char *p1, *p2; register int l1, l2; /* * If the object pointers are the same then they match. */ if (objPtr1 == objPtr2) { return 1; } /* * Don't use Tcl_GetStringFromObj as it would prevent l1 and l2 being * in a register. */ p1 = TclGetString(objPtr1); l1 = objPtr1->length; p2 = TclGetString(objPtr2); l2 = objPtr2->length; /* * Only compare if the string representations are of the same length. */ if (l1 == l2) { for (;; p1++, p2++, l1--) { if (*p1 != *p2) { break; } if (l1 == 0) { return 1; } } } return 0; } /* *---------------------------------------------------------------------- * * FreeObjEntry -- * * Frees space for a Tcl_HashEntry containing the Tcl_Obj * key. * * Results: * The return value is a pointer to the created entry. * * Side effects: * Decrements the reference count of the object. * *---------------------------------------------------------------------- */ static void FreeObjEntry(hPtr) Tcl_HashEntry *hPtr; /* Hash entry to free. */ { Tcl_Obj *objPtr = (Tcl_Obj *) hPtr->key.oneWordValue; Tcl_DecrRefCount (objPtr); ckfree ((char *) hPtr); } /* *---------------------------------------------------------------------- * * HashObjKey -- * * Compute a one-word summary of the string representation of the * Tcl_Obj, which can be used to generate a hash index. * * Results: * The return value is a one-word summary of the information in * the string representation of the Tcl_Obj. * * Side effects: * None. * *---------------------------------------------------------------------- */ static unsigned int HashObjKey(tablePtr, keyPtr) Tcl_HashTable *tablePtr; /* Hash table. */ VOID *keyPtr; /* Key from which to compute hash value. */ { Tcl_Obj *objPtr = (Tcl_Obj *) keyPtr; CONST char *string = TclGetString(objPtr); int length = objPtr->length; unsigned int result; int i; /* * I tried a zillion different hash functions and asked many other * people for advice. Many people had their own favorite functions, * all different, but no-one had much idea why they were good ones. * I chose the one below (multiply by 9 and add new character) * because of the following reasons: * * 1. Multiplying by 10 is perfect for keys that are decimal strings, * and multiplying by 9 is just about as good. * 2. Times-9 is (shift-left-3) plus (old). This means that each * character's bits hang around in the low-order bits of the * hash value for ever, plus they spread fairly rapidly up to * the high-order bits to fill out the hash value. This seems * works well both for decimal and non-decimal strings. */ result = 0; for (i=0 ; ivarFramePtr; name = Tcl_GetString(objPtr); if ((*name++ == ':') && (*name == ':')) { iPtr->varFramePtr = NULL; } /* * Get the internal representation, converting to a command type if * needed. The internal representation is a ResolvedCmdName that points * to the actual command. */ if (objPtr->typePtr != &tclCmdNameType) { result = tclCmdNameType.setFromAnyProc(interp, objPtr); if (result != TCL_OK) { iPtr->varFramePtr = savedFramePtr; return (Tcl_Command) NULL; } } resPtr = (ResolvedCmdName *) objPtr->internalRep.twoPtrValue.ptr1; /* * Get the current namespace. */ if (iPtr->varFramePtr != NULL) { currNsPtr = iPtr->varFramePtr->nsPtr; } else { currNsPtr = iPtr->globalNsPtr; } /* * Check the context namespace and the namespace epoch of the resolved * symbol to make sure that it is fresh. If not, then force another * conversion to the command type, to discard the old rep and create a * new one. Note that we verify that the namespace id of the context * namespace is the same as the one we cached; this insures that the * namespace wasn't deleted and a new one created at the same address * with the same command epoch. */ cmdPtr = NULL; if ((resPtr != NULL) && (resPtr->refNsPtr == currNsPtr) && (resPtr->refNsId == currNsPtr->nsId) && (resPtr->refNsCmdEpoch == currNsPtr->cmdRefEpoch)) { cmdPtr = resPtr->cmdPtr; if (cmdPtr->cmdEpoch != resPtr->cmdEpoch || (cmdPtr->flags & CMD_IS_DELETED)) { cmdPtr = NULL; } } if (cmdPtr == NULL) { result = tclCmdNameType.setFromAnyProc(interp, objPtr); if (result != TCL_OK) { iPtr->varFramePtr = savedFramePtr; return (Tcl_Command) NULL; } resPtr = (ResolvedCmdName *) objPtr->internalRep.twoPtrValue.ptr1; if (resPtr != NULL) { cmdPtr = resPtr->cmdPtr; } } iPtr->varFramePtr = savedFramePtr; return (Tcl_Command) cmdPtr; } /* *---------------------------------------------------------------------- * * TclSetCmdNameObj -- * * Modify an object to be an CmdName object that refers to the argument * Command structure. * * Results: * None. * * Side effects: * The object's old internal rep is freed. It's string rep is not * changed. The refcount in the Command structure is incremented to * keep it from being freed if the command is later deleted until * TclExecuteByteCode has a chance to recognize that it was deleted. * *---------------------------------------------------------------------- */ void TclSetCmdNameObj(interp, objPtr, cmdPtr) Tcl_Interp *interp; /* Points to interpreter containing command * that should be cached in objPtr. */ register Tcl_Obj *objPtr; /* Points to Tcl object to be changed to * a CmdName object. */ Command *cmdPtr; /* Points to Command structure that the * CmdName object should refer to. */ { Interp *iPtr = (Interp *) interp; register ResolvedCmdName *resPtr; Tcl_ObjType *oldTypePtr = objPtr->typePtr; register Namespace *currNsPtr; if (oldTypePtr == &tclCmdNameType) { return; } /* * Get the current namespace. */ if (iPtr->varFramePtr != NULL) { currNsPtr = iPtr->varFramePtr->nsPtr; } else { currNsPtr = iPtr->globalNsPtr; } cmdPtr->refCount++; resPtr = (ResolvedCmdName *) ckalloc(sizeof(ResolvedCmdName)); resPtr->cmdPtr = cmdPtr; resPtr->refNsPtr = currNsPtr; resPtr->refNsId = currNsPtr->nsId; resPtr->refNsCmdEpoch = currNsPtr->cmdRefEpoch; resPtr->cmdEpoch = cmdPtr->cmdEpoch; resPtr->refCount = 1; if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) { oldTypePtr->freeIntRepProc(objPtr); } objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) resPtr; objPtr->internalRep.twoPtrValue.ptr2 = NULL; objPtr->typePtr = &tclCmdNameType; } /* *---------------------------------------------------------------------- * * FreeCmdNameInternalRep -- * * Frees the resources associated with a cmdName object's internal * representation. * * Results: * None. * * Side effects: * Decrements the ref count of any cached ResolvedCmdName structure * pointed to by the cmdName's internal representation. If this is * the last use of the ResolvedCmdName, it is freed. This in turn * decrements the ref count of the Command structure pointed to by * the ResolvedSymbol, which may free the Command structure. * *---------------------------------------------------------------------- */ static void FreeCmdNameInternalRep(objPtr) register Tcl_Obj *objPtr; /* CmdName object with internal * representation to free. */ { register ResolvedCmdName *resPtr = (ResolvedCmdName *) objPtr->internalRep.twoPtrValue.ptr1; if (resPtr != NULL) { /* * Decrement the reference count of the ResolvedCmdName structure. * If there are no more uses, free the ResolvedCmdName structure. */ resPtr->refCount--; if (resPtr->refCount == 0) { /* * Now free the cached command, unless it is still in its * hash table or if there are other references to it * from other cmdName objects. */ Command *cmdPtr = resPtr->cmdPtr; TclCleanupCommand(cmdPtr); ckfree((char *) resPtr); } } } /* *---------------------------------------------------------------------- * * DupCmdNameInternalRep -- * * Initialize the internal representation of an cmdName Tcl_Obj to a * copy of the internal representation of an existing cmdName object. * * Results: * None. * * Side effects: * "copyPtr"s internal rep is set to point to the ResolvedCmdName * structure corresponding to "srcPtr"s internal rep. Increments the * ref count of the ResolvedCmdName structure pointed to by the * cmdName's internal representation. * *---------------------------------------------------------------------- */ static void DupCmdNameInternalRep(srcPtr, copyPtr) Tcl_Obj *srcPtr; /* Object with internal rep to copy. */ register Tcl_Obj *copyPtr; /* Object with internal rep to set. */ { register ResolvedCmdName *resPtr = (ResolvedCmdName *) srcPtr->internalRep.twoPtrValue.ptr1; copyPtr->internalRep.twoPtrValue.ptr1 = (VOID *) resPtr; copyPtr->internalRep.twoPtrValue.ptr2 = NULL; if (resPtr != NULL) { resPtr->refCount++; } copyPtr->typePtr = &tclCmdNameType; } /* *---------------------------------------------------------------------- * * SetCmdNameFromAny -- * * Generate an cmdName internal form for the Tcl object "objPtr". * * Results: * The return value is a standard Tcl result. The conversion always * succeeds and TCL_OK is returned. * * Side effects: * A pointer to a ResolvedCmdName structure that holds a cached pointer * to the command with a name that matches objPtr's string rep is * stored as objPtr's internal representation. This ResolvedCmdName * pointer will be NULL if no matching command was found. The ref count * of the cached Command's structure (if any) is also incremented. * *---------------------------------------------------------------------- */ static int SetCmdNameFromAny(interp, objPtr) Tcl_Interp *interp; /* Used for error reporting if not NULL. */ register Tcl_Obj *objPtr; /* The object to convert. */ { Interp *iPtr = (Interp *) interp; char *name; Tcl_Command cmd; register Command *cmdPtr; Namespace *currNsPtr; register ResolvedCmdName *resPtr; if (interp == NULL) { return TCL_ERROR; } /* * Get "objPtr"s string representation. Make it up-to-date if necessary. */ name = objPtr->bytes; if (name == NULL) { name = Tcl_GetString(objPtr); } /* * Find the Command structure, if any, that describes the command called * "name". Build a ResolvedCmdName that holds a cached pointer to this * Command, and bump the reference count in the referenced Command * structure. A Command structure will not be deleted as long as it is * referenced from a CmdName object. */ cmd = Tcl_FindCommand(interp, name, (Tcl_Namespace *) NULL, /*flags*/ 0); cmdPtr = (Command *) cmd; if (cmdPtr != NULL) { /* * Get the current namespace. */ if (iPtr->varFramePtr != NULL) { currNsPtr = iPtr->varFramePtr->nsPtr; } else { currNsPtr = iPtr->globalNsPtr; } cmdPtr->refCount++; resPtr = (ResolvedCmdName *) ckalloc(sizeof(ResolvedCmdName)); resPtr->cmdPtr = cmdPtr; resPtr->refNsPtr = currNsPtr; resPtr->refNsId = currNsPtr->nsId; resPtr->refNsCmdEpoch = currNsPtr->cmdRefEpoch; resPtr->cmdEpoch = cmdPtr->cmdEpoch; resPtr->refCount = 1; } else { resPtr = NULL; /* no command named "name" was found */ } /* * Free the old internalRep before setting the new one. We do this as * late as possible to allow the conversion code, in particular * GetStringFromObj, to use that old internalRep. If no Command * structure was found, leave NULL as the cached value. */ if ((objPtr->typePtr != NULL) && (objPtr->typePtr->freeIntRepProc != NULL)) { objPtr->typePtr->freeIntRepProc(objPtr); } objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) resPtr; objPtr->internalRep.twoPtrValue.ptr2 = NULL; objPtr->typePtr = &tclCmdNameType; return TCL_OK; } /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ tcl8.4.20/generic/tclCmdMZ.c0000644003604700454610000042754112052456743014167 0ustar dgp771div/* * tclCmdMZ.c -- * * This file contains the top-level command routines for most of * the Tcl built-in commands whose names begin with the letters * M to Z. It contains only commands in the generic core (i.e. * those that don't depend much upon UNIX facilities). * * Copyright (c) 1987-1993 The Regents of the University of California. * Copyright (c) 1994-1997 Sun Microsystems, Inc. * Copyright (c) 1998-2000 Scriptics Corporation. * Copyright (c) 2002 ActiveState Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" #include "tclRegexp.h" #include "tclCompile.h" /* * Structures used to hold information about variable traces: */ typedef struct { int flags; /* Operations for which Tcl command is * to be invoked. */ size_t length; /* Number of non-NULL chars. in command. */ char command[4]; /* Space for Tcl command to invoke. Actual * size will be as large as necessary to * hold command. This field must be the * last in the structure, so that it can * be larger than 4 bytes. */ } TraceVarInfo; typedef struct { VarTrace trace; TraceVarInfo tvar; } CompoundVarTrace; /* * Structure used to hold information about command traces: */ typedef struct { int flags; /* Operations for which Tcl command is * to be invoked. */ size_t length; /* Number of non-NULL chars. in command. */ Tcl_Trace stepTrace; /* Used for execution traces, when tracing * inside the given command */ int startLevel; /* Used for bookkeeping with step execution * traces, store the level at which the step * trace was invoked */ char *startCmd; /* Used for bookkeeping with step execution * traces, store the command name which invoked * step trace */ int curFlags; /* Trace flags for the current command */ int curCode; /* Return code for the current command */ int refCount; /* Used to ensure this structure is * not deleted too early. Keeps track * of how many pieces of code have * a pointer to this structure. */ char command[4]; /* Space for Tcl command to invoke. Actual * size will be as large as necessary to * hold command. This field must be the * last in the structure, so that it can * be larger than 4 bytes. */ } TraceCommandInfo; /* * Used by command execution traces. Note that we assume in the code * that the first two defines are exactly 4 times the * 'TCL_TRACE_ENTER_EXEC' and 'TCL_TRACE_LEAVE_EXEC' constants. * * TCL_TRACE_ENTER_DURING_EXEC - Trace each command inside the command * currently being traced, before execution. * TCL_TRACE_LEAVE_DURING_EXEC - Trace each command inside the command * currently being traced, after execution. * TCL_TRACE_ANY_EXEC - OR'd combination of all EXEC flags. * TCL_TRACE_EXEC_IN_PROGRESS - The callback procedure on this trace * is currently executing. Therefore we * don't let further traces execute. * TCL_TRACE_EXEC_DIRECT - This execution trace is triggered directly * by the command being traced, not because * of an internal trace. * The flags 'TCL_TRACE_DESTROYED' and 'TCL_INTERP_DESTROYED' may also * be used in command execution traces. */ #define TCL_TRACE_ENTER_DURING_EXEC 4 #define TCL_TRACE_LEAVE_DURING_EXEC 8 #define TCL_TRACE_ANY_EXEC 15 #define TCL_TRACE_EXEC_IN_PROGRESS 0x10 #define TCL_TRACE_EXEC_DIRECT 0x20 /* * Forward declarations for procedures defined in this file: */ typedef int (Tcl_TraceTypeObjCmd) _ANSI_ARGS_((Tcl_Interp *interp, int optionIndex, int objc, Tcl_Obj *CONST objv[])); Tcl_TraceTypeObjCmd TclTraceVariableObjCmd; Tcl_TraceTypeObjCmd TclTraceCommandObjCmd; Tcl_TraceTypeObjCmd TclTraceExecutionObjCmd; /* * Each subcommand has a number of 'types' to which it can apply. * Currently 'execution', 'command' and 'variable' are the only * types supported. These three arrays MUST be kept in sync! * In the future we may provide an API to add to the list of * supported trace types. */ static CONST char *traceTypeOptions[] = { "execution", "command", "variable", (char*) NULL }; static Tcl_TraceTypeObjCmd *CONST traceSubCmds[] = { TclTraceExecutionObjCmd, TclTraceCommandObjCmd, TclTraceVariableObjCmd }; /* * Declarations for local procedures to this file: */ static int CallTraceProcedure _ANSI_ARGS_((Tcl_Interp *interp, Trace *tracePtr, Command *cmdPtr, CONST char *command, int numChars, int objc, Tcl_Obj *CONST objv[])); static char * TraceVarProc _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, CONST char *name1, CONST char *name2, int flags)); static void TraceCommandProc _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, CONST char *oldName, CONST char *newName, int flags)); static Tcl_CmdObjTraceProc TraceExecutionProc; #ifdef TCL_TIP280 static void ListLines _ANSI_ARGS_((Tcl_Obj* listObj, int line, int n, int* lines, Tcl_Obj* const* elems)); #endif /* *---------------------------------------------------------------------- * * Tcl_PwdObjCmd -- * * This procedure is invoked to process the "pwd" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_PwdObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Tcl_Obj *retVal; if (objc != 1) { Tcl_WrongNumArgs(interp, 1, objv, NULL); return TCL_ERROR; } retVal = Tcl_FSGetCwd(interp); if (retVal == NULL) { return TCL_ERROR; } Tcl_SetObjResult(interp, retVal); Tcl_DecrRefCount(retVal); return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_RegexpObjCmd -- * * This procedure is invoked to process the "regexp" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_RegexpObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int i, indices, match, about, offset, all, doinline, numMatchesSaved; int cflags, eflags, stringLength; Tcl_RegExp regExpr; Tcl_Obj *objPtr, *resultPtr; Tcl_RegExpInfo info; static CONST char *options[] = { "-all", "-about", "-indices", "-inline", "-expanded", "-line", "-linestop", "-lineanchor", "-nocase", "-start", "--", (char *) NULL }; enum options { REGEXP_ALL, REGEXP_ABOUT, REGEXP_INDICES, REGEXP_INLINE, REGEXP_EXPANDED,REGEXP_LINE, REGEXP_LINESTOP,REGEXP_LINEANCHOR, REGEXP_NOCASE, REGEXP_START, REGEXP_LAST }; indices = 0; about = 0; cflags = TCL_REG_ADVANCED; eflags = 0; offset = 0; all = 0; doinline = 0; for (i = 1; i < objc; i++) { char *name; int index; name = Tcl_GetString(objv[i]); if (name[0] != '-') { break; } if (Tcl_GetIndexFromObj(interp, objv[i], options, "switch", TCL_EXACT, &index) != TCL_OK) { return TCL_ERROR; } switch ((enum options) index) { case REGEXP_ALL: { all = 1; break; } case REGEXP_INDICES: { indices = 1; break; } case REGEXP_INLINE: { doinline = 1; break; } case REGEXP_NOCASE: { cflags |= TCL_REG_NOCASE; break; } case REGEXP_ABOUT: { about = 1; break; } case REGEXP_EXPANDED: { cflags |= TCL_REG_EXPANDED; break; } case REGEXP_LINE: { cflags |= TCL_REG_NEWLINE; break; } case REGEXP_LINESTOP: { cflags |= TCL_REG_NLSTOP; break; } case REGEXP_LINEANCHOR: { cflags |= TCL_REG_NLANCH; break; } case REGEXP_START: { if (++i >= objc) { goto endOfForLoop; } if (Tcl_GetIntFromObj(interp, objv[i], &offset) != TCL_OK) { return TCL_ERROR; } if (offset < 0) { offset = 0; } break; } case REGEXP_LAST: { i++; goto endOfForLoop; } } } endOfForLoop: if ((objc - i) < (2 - about)) { Tcl_WrongNumArgs(interp, 1, objv, "?switches? exp string ?matchVar? ?subMatchVar subMatchVar ...?"); return TCL_ERROR; } objc -= i; objv += i; if (doinline && ((objc - 2) != 0)) { /* * User requested -inline, but specified match variables - a no-no. */ Tcl_AppendResult(interp, "regexp match variables not allowed", " when using -inline", (char *) NULL); return TCL_ERROR; } /* * Handle the odd about case separately. */ if (about) { regExpr = Tcl_GetRegExpFromObj(interp, objv[0], cflags); if ((regExpr == NULL) || (TclRegAbout(interp, regExpr) < 0)) { return TCL_ERROR; } return TCL_OK; } /* * Get the length of the string that we are matching against so * we can do the termination test for -all matches. Do this before * getting the regexp to avoid shimmering problems. */ objPtr = objv[1]; stringLength = Tcl_GetCharLength(objPtr); regExpr = Tcl_GetRegExpFromObj(interp, objv[0], cflags); if (regExpr == NULL) { return TCL_ERROR; } if (offset > 0) { /* * Add flag if using offset (string is part of a larger string), * so that "^" won't match. */ eflags |= TCL_REG_NOTBOL; } objc -= 2; objv += 2; resultPtr = Tcl_GetObjResult(interp); if (doinline) { /* * Save all the subexpressions, as we will return them as a list */ numMatchesSaved = -1; } else { /* * Save only enough subexpressions for matches we want to keep, * expect in the case of -all, where we need to keep at least * one to know where to move the offset. */ numMatchesSaved = (objc == 0) ? all : objc; } /* * The following loop is to handle multiple matches within the * same source string; each iteration handles one match. If "-all" * hasn't been specified then the loop body only gets executed once. * We terminate the loop when the starting offset is past the end of the * string. */ while (1) { match = Tcl_RegExpExecObj(interp, regExpr, objPtr, offset /* offset */, numMatchesSaved, eflags | ((offset > 0 && offset < stringLength && (Tcl_GetUniChar(objPtr,offset-1) != (Tcl_UniChar)'\n')) ? TCL_REG_NOTBOL : 0)); if (match < 0) { return TCL_ERROR; } if (match == 0) { /* * We want to set the value of the intepreter result only when * this is the first time through the loop. */ if (all <= 1) { /* * If inlining, set the interpreter's object result to an * empty list, otherwise set it to an integer object w/ * value 0. */ if (doinline) { Tcl_SetListObj(resultPtr, 0, NULL); } else { Tcl_SetIntObj(resultPtr, 0); } return TCL_OK; } break; } /* * If additional variable names have been specified, return * index information in those variables. */ Tcl_RegExpGetInfo(regExpr, &info); if (doinline) { /* * It's the number of substitutions, plus one for the matchVar * at index 0 */ objc = info.nsubs + 1; } for (i = 0; i < objc; i++) { Tcl_Obj *newPtr; if (indices) { int start, end; Tcl_Obj *objs[2]; /* * Only adjust the match area if there was a match for * that area. (Scriptics Bug 4391/SF Bug #219232) */ if (i <= info.nsubs && info.matches[i].start >= 0) { start = offset + info.matches[i].start; end = offset + info.matches[i].end; /* * Adjust index so it refers to the last character in the * match instead of the first character after the match. */ if (end >= offset) { end--; } } else { start = -1; end = -1; } objs[0] = Tcl_NewLongObj(start); objs[1] = Tcl_NewLongObj(end); newPtr = Tcl_NewListObj(2, objs); } else { if (i <= info.nsubs) { newPtr = Tcl_GetRange(objPtr, offset + info.matches[i].start, offset + info.matches[i].end - 1); } else { newPtr = Tcl_NewObj(); } } if (doinline) { if (Tcl_ListObjAppendElement(interp, resultPtr, newPtr) != TCL_OK) { Tcl_DecrRefCount(newPtr); return TCL_ERROR; } } else { Tcl_Obj *valuePtr; valuePtr = Tcl_ObjSetVar2(interp, objv[i], NULL, newPtr, 0); if (valuePtr == NULL) { Tcl_AppendResult(interp, "couldn't set variable \"", Tcl_GetString(objv[i]), "\"", (char *) NULL); Tcl_DecrRefCount(newPtr); return TCL_ERROR; } } } if (all == 0) { break; } /* * Adjust the offset to the character just after the last one * in the matchVar and increment all to count how many times * we are making a match. We always increment the offset by at least * one to prevent endless looping (as in the case: * regexp -all {a*} a). Otherwise, when we match the NULL string at * the end of the input string, we will loop indefinately (because the * length of the match is 0, so offset never changes). */ if (info.matches[0].end == 0) { offset++; } offset += info.matches[0].end; all++; eflags |= TCL_REG_NOTBOL; if (offset >= stringLength) { break; } } /* * Set the interpreter's object result to an integer object * with value 1 if -all wasn't specified, otherwise it's all-1 * (the number of times through the while - 1). * Get the resultPtr again as the Tcl_ObjSetVar2 above may have * cause the result to change. [Patch #558324] (watson). */ if (!doinline) { resultPtr = Tcl_GetObjResult(interp); Tcl_SetIntObj(resultPtr, (all ? all-1 : 1)); } return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_RegsubObjCmd -- * * This procedure is invoked to process the "regsub" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_RegsubObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int idx, result, cflags, all, wlen, wsublen, numMatches, offset; int start, end, subStart, subEnd, match; Tcl_RegExp regExpr; Tcl_RegExpInfo info; Tcl_Obj *resultPtr, *subPtr, *objPtr; Tcl_UniChar ch, *wsrc, *wfirstChar, *wstring, *wsubspec, *wend; static CONST char *options[] = { "-all", "-nocase", "-expanded", "-line", "-linestop", "-lineanchor", "-start", "--", NULL }; enum options { REGSUB_ALL, REGSUB_NOCASE, REGSUB_EXPANDED, REGSUB_LINE, REGSUB_LINESTOP, REGSUB_LINEANCHOR, REGSUB_START, REGSUB_LAST }; cflags = TCL_REG_ADVANCED; all = 0; offset = 0; resultPtr = NULL; for (idx = 1; idx < objc; idx++) { char *name; int index; name = Tcl_GetString(objv[idx]); if (name[0] != '-') { break; } if (Tcl_GetIndexFromObj(interp, objv[idx], options, "switch", TCL_EXACT, &index) != TCL_OK) { return TCL_ERROR; } switch ((enum options) index) { case REGSUB_ALL: { all = 1; break; } case REGSUB_NOCASE: { cflags |= TCL_REG_NOCASE; break; } case REGSUB_EXPANDED: { cflags |= TCL_REG_EXPANDED; break; } case REGSUB_LINE: { cflags |= TCL_REG_NEWLINE; break; } case REGSUB_LINESTOP: { cflags |= TCL_REG_NLSTOP; break; } case REGSUB_LINEANCHOR: { cflags |= TCL_REG_NLANCH; break; } case REGSUB_START: { if (++idx >= objc) { goto endOfForLoop; } if (Tcl_GetIntFromObj(interp, objv[idx], &offset) != TCL_OK) { return TCL_ERROR; } if (offset < 0) { offset = 0; } break; } case REGSUB_LAST: { idx++; goto endOfForLoop; } } } endOfForLoop: if (objc-idx < 3 || objc-idx > 4) { Tcl_WrongNumArgs(interp, 1, objv, "?switches? exp string subSpec ?varName?"); return TCL_ERROR; } objc -= idx; objv += idx; if (all && (offset == 0) && (strpbrk(Tcl_GetString(objv[2]), "&\\") == NULL) && (strpbrk(Tcl_GetString(objv[0]), "*+?{}()[].\\|^$") == NULL)) { /* * This is a simple one pair string map situation. We make use of * a slightly modified version of the one pair STR_MAP code. */ int slen, nocase; int (*strCmpFn)_ANSI_ARGS_((CONST Tcl_UniChar *, CONST Tcl_UniChar *, unsigned long)); Tcl_UniChar *p, wsrclc; numMatches = 0; nocase = (cflags & TCL_REG_NOCASE); strCmpFn = nocase ? Tcl_UniCharNcasecmp : Tcl_UniCharNcmp; wsrc = Tcl_GetUnicodeFromObj(objv[0], &slen); wstring = Tcl_GetUnicodeFromObj(objv[1], &wlen); wsubspec = Tcl_GetUnicodeFromObj(objv[2], &wsublen); wend = wstring + wlen - (slen ? slen - 1 : 0); result = TCL_OK; if (slen == 0) { /* * regsub behavior for "" matches between each character. * 'string map' skips the "" case. */ if (wstring < wend) { resultPtr = Tcl_NewUnicodeObj(wstring, 0); Tcl_IncrRefCount(resultPtr); for (; wstring < wend; wstring++) { Tcl_AppendUnicodeToObj(resultPtr, wsubspec, wsublen); Tcl_AppendUnicodeToObj(resultPtr, wstring, 1); numMatches++; } wlen = 0; } } else { wsrclc = Tcl_UniCharToLower(*wsrc); for (p = wfirstChar = wstring; wstring < wend; wstring++) { if (((*wstring == *wsrc) || (nocase && (Tcl_UniCharToLower(*wstring) == wsrclc))) && ((slen == 1) || (strCmpFn(wstring, wsrc, (unsigned long) slen) == 0))) { if (numMatches == 0) { resultPtr = Tcl_NewUnicodeObj(wstring, 0); Tcl_IncrRefCount(resultPtr); } if (p != wstring) { Tcl_AppendUnicodeToObj(resultPtr, p, wstring - p); p = wstring + slen; } else { p += slen; } wstring = p - 1; Tcl_AppendUnicodeToObj(resultPtr, wsubspec, wsublen); numMatches++; } } if (numMatches) { wlen = wfirstChar + wlen - p; wstring = p; } } objPtr = NULL; subPtr = NULL; goto regsubDone; } regExpr = Tcl_GetRegExpFromObj(interp, objv[0], cflags); if (regExpr == NULL) { return TCL_ERROR; } /* * Make sure to avoid problems where the objects are shared. This * can cause RegExpObj <> UnicodeObj shimmering that causes data * corruption. [Bug #461322] */ if (objv[1] == objv[0]) { objPtr = Tcl_DuplicateObj(objv[1]); } else { objPtr = objv[1]; } wstring = Tcl_GetUnicodeFromObj(objPtr, &wlen); if (objv[2] == objv[0]) { subPtr = Tcl_DuplicateObj(objv[2]); } else { subPtr = objv[2]; } wsubspec = Tcl_GetUnicodeFromObj(subPtr, &wsublen); result = TCL_OK; /* * The following loop is to handle multiple matches within the * same source string; each iteration handles one match and its * corresponding substitution. If "-all" hasn't been specified * then the loop body only gets executed once. We must use * 'offset <= wlen' in particular for the case where the regexp * pattern can match the empty string - this is useful when * doing, say, 'regsub -- ^ $str ...' when $str might be empty. */ numMatches = 0; for ( ; offset <= wlen; ) { /* * The flags argument is set if string is part of a larger string, * so that "^" won't match. */ match = Tcl_RegExpExecObj(interp, regExpr, objPtr, offset, 10 /* matches */, ((offset > 0 && (wstring[offset-1] != (Tcl_UniChar)'\n')) ? TCL_REG_NOTBOL : 0)); if (match < 0) { result = TCL_ERROR; goto done; } if (match == 0) { break; } if (numMatches == 0) { resultPtr = Tcl_NewUnicodeObj(wstring, 0); Tcl_IncrRefCount(resultPtr); if (offset > 0) { /* * Copy the initial portion of the string in if an offset * was specified. */ Tcl_AppendUnicodeToObj(resultPtr, wstring, offset); } } numMatches++; /* * Copy the portion of the source string before the match to the * result variable. */ Tcl_RegExpGetInfo(regExpr, &info); start = info.matches[0].start; end = info.matches[0].end; Tcl_AppendUnicodeToObj(resultPtr, wstring + offset, start); /* * Append the subSpec argument to the variable, making appropriate * substitutions. This code is a bit hairy because of the backslash * conventions and because the code saves up ranges of characters in * subSpec to reduce the number of calls to Tcl_SetVar. */ wsrc = wfirstChar = wsubspec; wend = wsubspec + wsublen; for (ch = *wsrc; wsrc != wend; wsrc++, ch = *wsrc) { if (ch == '&') { idx = 0; } else if (ch == '\\') { ch = wsrc[1]; if ((ch >= '0') && (ch <= '9')) { idx = ch - '0'; } else if ((ch == '\\') || (ch == '&')) { *wsrc = ch; Tcl_AppendUnicodeToObj(resultPtr, wfirstChar, wsrc - wfirstChar + 1); *wsrc = '\\'; wfirstChar = wsrc + 2; wsrc++; continue; } else { continue; } } else { continue; } if (wfirstChar != wsrc) { Tcl_AppendUnicodeToObj(resultPtr, wfirstChar, wsrc - wfirstChar); } if (idx <= info.nsubs) { subStart = info.matches[idx].start; subEnd = info.matches[idx].end; if ((subStart >= 0) && (subEnd >= 0)) { Tcl_AppendUnicodeToObj(resultPtr, wstring + offset + subStart, subEnd - subStart); } } if (*wsrc == '\\') { wsrc++; } wfirstChar = wsrc + 1; } if (wfirstChar != wsrc) { Tcl_AppendUnicodeToObj(resultPtr, wfirstChar, wsrc - wfirstChar); } if (end == 0) { /* * Always consume at least one character of the input string * in order to prevent infinite loops. */ if (offset < wlen) { Tcl_AppendUnicodeToObj(resultPtr, wstring + offset, 1); } offset++; } else { offset += end; if (start == end) { /* * We matched an empty string, which means we must go * forward one more step so we don't match again at the * same spot. */ if (offset < wlen) { Tcl_AppendUnicodeToObj(resultPtr, wstring + offset, 1); } offset++; } } if (!all) { break; } } /* * Copy the portion of the source string after the last match to the * result variable. */ regsubDone: if (numMatches == 0) { /* * On zero matches, just ignore the offset, since it shouldn't * matter to us in this case, and the user may have skewed it. */ resultPtr = objv[1]; Tcl_IncrRefCount(resultPtr); } else if (offset < wlen) { Tcl_AppendUnicodeToObj(resultPtr, wstring + offset, wlen - offset); } if (objc == 4) { if (Tcl_ObjSetVar2(interp, objv[3], NULL, resultPtr, 0) == NULL) { Tcl_AppendResult(interp, "couldn't set variable \"", Tcl_GetString(objv[3]), "\"", (char *) NULL); result = TCL_ERROR; } else { /* * Set the interpreter's object result to an integer object * holding the number of matches. */ Tcl_SetIntObj(Tcl_GetObjResult(interp), numMatches); } } else { /* * No varname supplied, so just return the modified string. */ Tcl_SetObjResult(interp, resultPtr); } done: if (objPtr && (objv[1] == objv[0])) { Tcl_DecrRefCount(objPtr); } if (subPtr && (objv[2] == objv[0])) { Tcl_DecrRefCount(subPtr); } if (resultPtr) { Tcl_DecrRefCount(resultPtr); } return result; } /* *---------------------------------------------------------------------- * * Tcl_RenameObjCmd -- * * This procedure is invoked to process the "rename" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl object result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_RenameObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Arbitrary value passed to the command. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { char *oldName, *newName; if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "oldName newName"); return TCL_ERROR; } oldName = Tcl_GetString(objv[1]); newName = Tcl_GetString(objv[2]); return TclRenameCommand(interp, oldName, newName); } /* *---------------------------------------------------------------------- * * Tcl_ReturnObjCmd -- * * This object-based procedure is invoked to process the "return" Tcl * command. See the user documentation for details on what it does. * * Results: * A standard Tcl object result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_ReturnObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Interp *iPtr = (Interp *) interp; int optionLen, argLen, code, result; if (iPtr->errorInfo != NULL) { ckfree(iPtr->errorInfo); iPtr->errorInfo = NULL; } if (iPtr->errorCode != NULL) { ckfree(iPtr->errorCode); iPtr->errorCode = NULL; } code = TCL_OK; for (objv++, objc--; objc > 1; objv += 2, objc -= 2) { char *option = Tcl_GetStringFromObj(objv[0], &optionLen); char *arg = Tcl_GetStringFromObj(objv[1], &argLen); if (strcmp(option, "-code") == 0) { register int c = arg[0]; if ((c == 'o') && (strcmp(arg, "ok") == 0)) { code = TCL_OK; } else if ((c == 'e') && (strcmp(arg, "error") == 0)) { code = TCL_ERROR; } else if ((c == 'r') && (strcmp(arg, "return") == 0)) { code = TCL_RETURN; } else if ((c == 'b') && (strcmp(arg, "break") == 0)) { code = TCL_BREAK; } else if ((c == 'c') && (strcmp(arg, "continue") == 0)) { code = TCL_CONTINUE; } else { result = Tcl_GetIntFromObj((Tcl_Interp *) NULL, objv[1], &code); if (result != TCL_OK) { Tcl_ResetResult(interp); Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "bad completion code \"", Tcl_GetString(objv[1]), "\": must be ok, error, return, break, ", "continue, or an integer", (char *) NULL); return result; } } } else if (strcmp(option, "-errorinfo") == 0) { iPtr->errorInfo = (char *) ckalloc((unsigned) (strlen(arg) + 1)); strcpy(iPtr->errorInfo, arg); } else if (strcmp(option, "-errorcode") == 0) { iPtr->errorCode = (char *) ckalloc((unsigned) (strlen(arg) + 1)); strcpy(iPtr->errorCode, arg); } else { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "bad option \"", option, "\": must be -code, -errorcode, or -errorinfo", (char *) NULL); return TCL_ERROR; } } if (objc == 1) { /* * Set the interpreter's object result. An inline version of * Tcl_SetObjResult. */ Tcl_SetObjResult(interp, objv[0]); } iPtr->returnCode = code; return TCL_RETURN; } /* *---------------------------------------------------------------------- * * Tcl_SourceObjCmd -- * * This procedure is invoked to process the "source" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl object result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_SourceObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "fileName"); return TCL_ERROR; } return Tcl_FSEvalFile(interp, objv[1]); } /* *---------------------------------------------------------------------- * * Tcl_SplitObjCmd -- * * This procedure is invoked to process the "split" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_SplitObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Tcl_UniChar ch; int len; char *splitChars, *string, *end; int splitCharLen, stringLen; Tcl_Obj *listPtr, *objPtr; if (objc == 2) { splitChars = " \n\t\r"; splitCharLen = 4; } else if (objc == 3) { splitChars = Tcl_GetStringFromObj(objv[2], &splitCharLen); } else { Tcl_WrongNumArgs(interp, 1, objv, "string ?splitChars?"); return TCL_ERROR; } string = Tcl_GetStringFromObj(objv[1], &stringLen); end = string + stringLen; listPtr = Tcl_GetObjResult(interp); if (stringLen == 0) { /* * Do nothing. */ } else if (splitCharLen == 0) { Tcl_HashTable charReuseTable; Tcl_HashEntry *hPtr; int isNew; /* * Handle the special case of splitting on every character. * * Uses a hash table to ensure that each kind of character has * only one Tcl_Obj instance (multiply-referenced) in the * final list. This is a *major* win when splitting on a long * string (especially in the megabyte range!) - DKF */ Tcl_InitHashTable(&charReuseTable, TCL_ONE_WORD_KEYS); for ( ; string < end; string += len) { len = TclUtfToUniChar(string, &ch); /* Assume Tcl_UniChar is an integral type... */ hPtr = Tcl_CreateHashEntry(&charReuseTable, (char*)0 + ch, &isNew); if (isNew) { objPtr = Tcl_NewStringObj(string, len); /* Don't need to fiddle with refcount... */ Tcl_SetHashValue(hPtr, (ClientData) objPtr); } else { objPtr = (Tcl_Obj*) Tcl_GetHashValue(hPtr); } Tcl_ListObjAppendElement(NULL, listPtr, objPtr); } Tcl_DeleteHashTable(&charReuseTable); } else if (splitCharLen == 1) { char *p; /* * Handle the special case of splitting on a single character. * This is only true for the one-char ASCII case, as one unicode * char is > 1 byte in length. */ while (*string && (p = strchr(string, (int) *splitChars)) != NULL) { objPtr = Tcl_NewStringObj(string, p - string); Tcl_ListObjAppendElement(NULL, listPtr, objPtr); string = p + 1; } objPtr = Tcl_NewStringObj(string, end - string); Tcl_ListObjAppendElement(NULL, listPtr, objPtr); } else { char *element, *p, *splitEnd; int splitLen; Tcl_UniChar splitChar; /* * Normal case: split on any of a given set of characters. * Discard instances of the split characters. */ splitEnd = splitChars + splitCharLen; for (element = string; string < end; string += len) { len = TclUtfToUniChar(string, &ch); for (p = splitChars; p < splitEnd; p += splitLen) { splitLen = TclUtfToUniChar(p, &splitChar); if (ch == splitChar) { objPtr = Tcl_NewStringObj(element, string - element); Tcl_ListObjAppendElement(NULL, listPtr, objPtr); element = string + len; break; } } } objPtr = Tcl_NewStringObj(element, string - element); Tcl_ListObjAppendElement(NULL, listPtr, objPtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_StringObjCmd -- * * This procedure is invoked to process the "string" Tcl command. * See the user documentation for details on what it does. Note * that this command only functions correctly on properly formed * Tcl UTF strings. * * Note that the primary methods here (equal, compare, match, ...) * have bytecode equivalents. You will find the code for those in * tclExecute.c. The code here will only be used in the non-bc * case (like in an 'eval'). * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_StringObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int index, left, right; Tcl_Obj *resultPtr; char *string1, *string2; int length1, length2; static CONST char *options[] = { "bytelength", "compare", "equal", "first", "index", "is", "last", "length", "map", "match", "range", "repeat", "replace", "tolower", "toupper", "totitle", "trim", "trimleft", "trimright", "wordend", "wordstart", (char *) NULL }; enum options { STR_BYTELENGTH, STR_COMPARE, STR_EQUAL, STR_FIRST, STR_INDEX, STR_IS, STR_LAST, STR_LENGTH, STR_MAP, STR_MATCH, STR_RANGE, STR_REPEAT, STR_REPLACE, STR_TOLOWER, STR_TOUPPER, STR_TOTITLE, STR_TRIM, STR_TRIMLEFT, STR_TRIMRIGHT, STR_WORDEND, STR_WORDSTART }; if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[1], options, "option", 0, &index) != TCL_OK) { return TCL_ERROR; } resultPtr = Tcl_GetObjResult(interp); switch ((enum options) index) { case STR_EQUAL: case STR_COMPARE: { /* * Remember to keep code here in some sync with the * byte-compiled versions in tclExecute.c (INST_STR_EQ, * INST_STR_NEQ and INST_STR_CMP as well as the expr string * comparison in INST_EQ/INST_NEQ/INST_LT/...). */ int i, match, length, nocase = 0, reqlength = -1; int (*strCmpFn)(); if (objc < 4 || objc > 7) { str_cmp_args: Tcl_WrongNumArgs(interp, 2, objv, "?-nocase? ?-length int? string1 string2"); return TCL_ERROR; } for (i = 2; i < objc-2; i++) { string2 = Tcl_GetStringFromObj(objv[i], &length2); if ((length2 > 1) && strncmp(string2, "-nocase", (size_t)length2) == 0) { nocase = 1; } else if ((length2 > 1) && strncmp(string2, "-length", (size_t)length2) == 0) { if (i+1 >= objc-2) { goto str_cmp_args; } if (Tcl_GetIntFromObj(interp, objv[++i], &reqlength) != TCL_OK) { return TCL_ERROR; } } else { Tcl_AppendStringsToObj(resultPtr, "bad option \"", string2, "\": must be -nocase or -length", (char *) NULL); return TCL_ERROR; } } /* * From now on, we only access the two objects at the end * of the argument array. */ objv += objc-2; if ((reqlength == 0) || (objv[0] == objv[1])) { /* * Alway match at 0 chars of if it is the same obj. */ Tcl_SetBooleanObj(resultPtr, ((enum options) index == STR_EQUAL)); break; } else if (!nocase && objv[0]->typePtr == &tclByteArrayType && objv[1]->typePtr == &tclByteArrayType) { /* * Use binary versions of comparisons since that won't * cause undue type conversions and it is much faster. * Only do this if we're case-sensitive (which is all * that really makes sense with byte arrays anyway, and * we have no memcasecmp() for some reason... :^) */ string1 = (char*) Tcl_GetByteArrayFromObj(objv[0], &length1); string2 = (char*) Tcl_GetByteArrayFromObj(objv[1], &length2); strCmpFn = memcmp; } else if ((objv[0]->typePtr == &tclStringType) && (objv[1]->typePtr == &tclStringType)) { /* * Do a unicode-specific comparison if both of the args * are of String type. In benchmark testing this proved * the most efficient check between the unicode and * string comparison operations. */ string1 = (char*) Tcl_GetUnicodeFromObj(objv[0], &length1); string2 = (char*) Tcl_GetUnicodeFromObj(objv[1], &length2); strCmpFn = nocase ? Tcl_UniCharNcasecmp : Tcl_UniCharNcmp; } else { /* * As a catch-all we will work with UTF-8. We cannot use * memcmp() as that is unsafe with any string containing * NULL (\xC0\x80 in Tcl's utf rep). We can use the more * efficient TclpUtfNcmp2 if we are case-sensitive and no * specific length was requested. */ string1 = (char*) Tcl_GetStringFromObj(objv[0], &length1); string2 = (char*) Tcl_GetStringFromObj(objv[1], &length2); if ((reqlength < 0) && !nocase) { strCmpFn = TclpUtfNcmp2; } else { length1 = Tcl_NumUtfChars(string1, length1); length2 = Tcl_NumUtfChars(string2, length2); strCmpFn = nocase ? Tcl_UtfNcasecmp : Tcl_UtfNcmp; } } if (((enum options) index == STR_EQUAL) && (reqlength < 0) && (length1 != length2)) { match = 1; /* this will be reversed below */ } else { length = (length1 < length2) ? length1 : length2; if (reqlength > 0 && reqlength < length) { length = reqlength; } else if (reqlength < 0) { /* * The requested length is negative, so we ignore it by * setting it to length + 1 so we correct the match var. */ reqlength = length + 1; } match = strCmpFn(string1, string2, (unsigned) length); if ((match == 0) && (reqlength > length)) { match = length1 - length2; } } if ((enum options) index == STR_EQUAL) { Tcl_SetBooleanObj(resultPtr, (match) ? 0 : 1); } else { Tcl_SetIntObj(resultPtr, ((match > 0) ? 1 : (match < 0) ? -1 : 0)); } break; } case STR_FIRST: { Tcl_UniChar *ustring1, *ustring2; int match, start; if (objc < 4 || objc > 5) { Tcl_WrongNumArgs(interp, 2, objv, "subString string ?startIndex?"); return TCL_ERROR; } /* * We are searching string2 for the sequence string1. */ match = -1; start = 0; length2 = -1; ustring1 = Tcl_GetUnicodeFromObj(objv[2], &length1); ustring2 = Tcl_GetUnicodeFromObj(objv[3], &length2); if (objc == 5) { /* * If a startIndex is specified, we will need to fast * forward to that point in the string before we think * about a match */ if (TclGetIntForIndex(interp, objv[4], length2 - 1, &start) != TCL_OK) { return TCL_ERROR; } if (start >= length2) { goto str_first_done; } else if (start > 0) { ustring2 += start; length2 -= start; } else if (start < 0) { /* * Invalid start index mapped to string start; * Bug #423581 */ start = 0; } } if (length1 > 0) { register Tcl_UniChar *p, *end; end = ustring2 + length2 - length1 + 1; for (p = ustring2; p < end; p++) { /* * Scan forward to find the first character. */ if ((*p == *ustring1) && (TclUniCharNcmp(ustring1, p, (unsigned long) length1) == 0)) { match = p - ustring2; break; } } } /* * Compute the character index of the matching string by * counting the number of characters before the match. */ if ((match != -1) && (objc == 5)) { match += start; } str_first_done: Tcl_SetIntObj(resultPtr, match); break; } case STR_INDEX: { if (objc != 4) { Tcl_WrongNumArgs(interp, 2, objv, "string charIndex"); return TCL_ERROR; } /* * If we have a ByteArray object, avoid indexing in the * Utf string since the byte array contains one byte per * character. Otherwise, use the Unicode string rep to * get the index'th char. */ if (objv[2]->typePtr == &tclByteArrayType) { string1 = (char *) Tcl_GetByteArrayFromObj(objv[2], &length1); if (TclGetIntForIndex(interp, objv[3], length1 - 1, &index) != TCL_OK) { return TCL_ERROR; } if ((index >= 0) && (index < length1)) { Tcl_SetByteArrayObj(resultPtr, (unsigned char *)(&string1[index]), 1); } } else { /* * Get Unicode char length to calulate what 'end' means. */ length1 = Tcl_GetCharLength(objv[2]); if (TclGetIntForIndex(interp, objv[3], length1 - 1, &index) != TCL_OK) { return TCL_ERROR; } if ((index >= 0) && (index < length1)) { char buf[TCL_UTF_MAX]; Tcl_UniChar ch; ch = Tcl_GetUniChar(objv[2], index); length1 = Tcl_UniCharToUtf(ch, buf); Tcl_SetStringObj(resultPtr, buf, length1); } } break; } case STR_IS: { char *end; Tcl_UniChar ch; /* * The UniChar comparison function */ int (*chcomp)_ANSI_ARGS_((int)) = NULL; int i, failat = 0, result = 1, strict = 0; Tcl_Obj *objPtr, *failVarObj = NULL; static CONST char *isOptions[] = { "alnum", "alpha", "ascii", "control", "boolean", "digit", "double", "false", "graph", "integer", "lower", "print", "punct", "space", "true", "upper", "wordchar", "xdigit", (char *) NULL }; enum isOptions { STR_IS_ALNUM, STR_IS_ALPHA, STR_IS_ASCII, STR_IS_CONTROL, STR_IS_BOOL, STR_IS_DIGIT, STR_IS_DOUBLE, STR_IS_FALSE, STR_IS_GRAPH, STR_IS_INT, STR_IS_LOWER, STR_IS_PRINT, STR_IS_PUNCT, STR_IS_SPACE, STR_IS_TRUE, STR_IS_UPPER, STR_IS_WORD, STR_IS_XDIGIT }; if (objc < 4 || objc > 7) { Tcl_WrongNumArgs(interp, 2, objv, "class ?-strict? ?-failindex var? str"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[2], isOptions, "class", 0, &index) != TCL_OK) { return TCL_ERROR; } if (objc != 4) { for (i = 3; i < objc-1; i++) { string2 = Tcl_GetStringFromObj(objv[i], &length2); if ((length2 > 1) && strncmp(string2, "-strict", (size_t) length2) == 0) { strict = 1; } else if ((length2 > 1) && strncmp(string2, "-failindex", (size_t) length2) == 0) { if (i+1 >= objc-1) { Tcl_WrongNumArgs(interp, 3, objv, "?-strict? ?-failindex var? str"); return TCL_ERROR; } failVarObj = objv[++i]; } else { Tcl_AppendStringsToObj(resultPtr, "bad option \"", string2, "\": must be -strict or -failindex", (char *) NULL); return TCL_ERROR; } } } /* * We get the objPtr so that we can short-cut for some classes * by checking the object type (int and double), but we need * the string otherwise, because we don't want any conversion * of type occuring (as, for example, Tcl_Get*FromObj would do */ objPtr = objv[objc-1]; string1 = Tcl_GetStringFromObj(objPtr, &length1); if (length1 == 0) { if (strict) { result = 0; } goto str_is_done; } end = string1 + length1; /* * When entering here, result == 1 and failat == 0 */ switch ((enum isOptions) index) { case STR_IS_ALNUM: chcomp = Tcl_UniCharIsAlnum; break; case STR_IS_ALPHA: chcomp = Tcl_UniCharIsAlpha; break; case STR_IS_ASCII: for (; string1 < end; string1++, failat++) { /* * This is a valid check in unicode, because all * bytes < 0xC0 are single byte chars (but isascii * limits that def'n to 0x80). */ if (*((unsigned char *)string1) >= 0x80) { result = 0; break; } } break; case STR_IS_BOOL: case STR_IS_TRUE: case STR_IS_FALSE: /* Optimizers, beware Bug 1187123 ! */ if ((Tcl_GetBoolean(NULL, string1, &i) == TCL_ERROR) || (((enum isOptions) index == STR_IS_TRUE) && i == 0) || (((enum isOptions) index == STR_IS_FALSE) && i != 0)) { result = 0; } break; case STR_IS_CONTROL: chcomp = Tcl_UniCharIsControl; break; case STR_IS_DIGIT: chcomp = Tcl_UniCharIsDigit; break; case STR_IS_DOUBLE: { char *stop; if ((objPtr->typePtr == &tclDoubleType) || (objPtr->typePtr == &tclIntType)) { break; } /* * This is adapted from Tcl_GetDouble * * The danger in this function is that * "12345678901234567890" is an acceptable 'double', * but will later be interp'd as an int by something * like [expr]. Therefore, we check to see if it looks * like an int, and if so we do a range check on it. * If strtoul gets to the end, we know we either * received an acceptable int, or over/underflow */ if (TclLooksLikeInt(string1, length1)) { errno = 0; #ifdef TCL_WIDE_INT_IS_LONG strtoul(string1, &stop, 0); /* INTL: Tcl source. */ #else strtoull(string1, &stop, 0); /* INTL: Tcl source. */ #endif if (stop == end) { if (errno == ERANGE) { result = 0; failat = -1; } break; } } errno = 0; strtod(string1, &stop); /* INTL: Tcl source. */ if (errno == ERANGE) { /* * if (errno == ERANGE), then it was an over/underflow * problem, but in this method, we only want to know * yes or no, so bad flow returns 0 (false) and sets * the failVarObj to the string length. */ result = 0; failat = -1; } else if (stop == string1) { /* * In this case, nothing like a number was found */ result = 0; failat = 0; } else { /* * Assume we sucked up one char per byte * and then we go onto SPACE, since we are * allowed trailing whitespace */ failat = stop - string1; string1 = stop; chcomp = Tcl_UniCharIsSpace; } break; } case STR_IS_GRAPH: chcomp = Tcl_UniCharIsGraph; break; case STR_IS_INT: { char *stop; long int l = 0; if (TCL_OK == Tcl_GetIntFromObj(NULL, objPtr, &i)) { break; } /* * Like STR_IS_DOUBLE, but we use strtoul. * Since Tcl_GetIntFromObj already failed, * we set result to 0. */ result = 0; errno = 0; l = strtol(string1, &stop, 0); /* INTL: Tcl source. */ if ((errno == ERANGE) || (l > INT_MAX) || (l < INT_MIN)) { /* * if (errno == ERANGE), then it was an over/underflow * problem, but in this method, we only want to know * yes or no, so bad flow returns 0 (false) and sets * the failVarObj to the string length. */ failat = -1; } else if (stop == string1) { /* * In this case, nothing like a number was found */ failat = 0; } else { /* * Assume we sucked up one char per byte * and then we go onto SPACE, since we are * allowed trailing whitespace */ failat = stop - string1; string1 = stop; chcomp = Tcl_UniCharIsSpace; } break; } case STR_IS_LOWER: chcomp = Tcl_UniCharIsLower; break; case STR_IS_PRINT: chcomp = Tcl_UniCharIsPrint; break; case STR_IS_PUNCT: chcomp = Tcl_UniCharIsPunct; break; case STR_IS_SPACE: chcomp = Tcl_UniCharIsSpace; break; case STR_IS_UPPER: chcomp = Tcl_UniCharIsUpper; break; case STR_IS_WORD: chcomp = Tcl_UniCharIsWordChar; break; case STR_IS_XDIGIT: { for (; string1 < end; string1++, failat++) { /* INTL: We assume unicode is bad for this class */ if ((*((unsigned char *)string1) >= 0xC0) || !isxdigit(*(unsigned char *)string1)) { result = 0; break; } } break; } } if (chcomp != NULL) { for (; string1 < end; string1 += length2, failat++) { length2 = TclUtfToUniChar(string1, &ch); if (!chcomp(ch)) { result = 0; break; } } } str_is_done: /* * Only set the failVarObj when we will return 0 * and we have indicated a valid fail index (>= 0) */ if ((result == 0) && (failVarObj != NULL)) { Tcl_Obj *resPtr, *tmpPtr = Tcl_NewIntObj(failat); Tcl_IncrRefCount(tmpPtr); resPtr = Tcl_ObjSetVar2(interp, failVarObj, NULL, tmpPtr, TCL_LEAVE_ERR_MSG); Tcl_DecrRefCount(tmpPtr); if (resPtr == NULL) { return TCL_ERROR; } } Tcl_SetBooleanObj(resultPtr, result); break; } case STR_LAST: { Tcl_UniChar *ustring1, *ustring2, *p; int match, start; if (objc < 4 || objc > 5) { Tcl_WrongNumArgs(interp, 2, objv, "subString string ?startIndex?"); return TCL_ERROR; } /* * We are searching string2 for the sequence string1. */ match = -1; start = 0; length2 = -1; ustring1 = Tcl_GetUnicodeFromObj(objv[2], &length1); ustring2 = Tcl_GetUnicodeFromObj(objv[3], &length2); if (objc == 5) { /* * If a startIndex is specified, we will need to restrict * the string range to that char index in the string */ if (TclGetIntForIndex(interp, objv[4], length2 - 1, &start) != TCL_OK) { return TCL_ERROR; } if (start < 0) { goto str_last_done; } else if (start < length2) { p = ustring2 + start + 1 - length1; } else { p = ustring2 + length2 - length1; } } else { p = ustring2 + length2 - length1; } if (length1 > 0) { for (; p >= ustring2; p--) { /* * Scan backwards to find the first character. */ if ((*p == *ustring1) && (memcmp((char *) ustring1, (char *) p, (size_t) (length1 * sizeof(Tcl_UniChar))) == 0)) { match = p - ustring2; break; } } } str_last_done: Tcl_SetIntObj(resultPtr, match); break; } case STR_BYTELENGTH: case STR_LENGTH: { if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "string"); return TCL_ERROR; } if ((enum options) index == STR_BYTELENGTH) { (void) Tcl_GetStringFromObj(objv[2], &length1); } else { /* * If we have a ByteArray object, avoid recomputing the * string since the byte array contains one byte per * character. Otherwise, use the Unicode string rep to * calculate the length. */ if (objv[2]->typePtr == &tclByteArrayType) { (void) Tcl_GetByteArrayFromObj(objv[2], &length1); } else { length1 = Tcl_GetCharLength(objv[2]); } } Tcl_SetIntObj(resultPtr, length1); break; } case STR_MAP: { int mapElemc, nocase = 0, copySource = 0; Tcl_Obj **mapElemv, *sourceObj; Tcl_UniChar *ustring1, *ustring2, *p, *end; int (*strCmpFn)_ANSI_ARGS_((CONST Tcl_UniChar*, CONST Tcl_UniChar*, unsigned long)); if (objc < 4 || objc > 5) { Tcl_WrongNumArgs(interp, 2, objv, "?-nocase? charMap string"); return TCL_ERROR; } if (objc == 5) { string2 = Tcl_GetStringFromObj(objv[2], &length2); if ((length2 > 1) && strncmp(string2, "-nocase", (size_t) length2) == 0) { nocase = 1; } else { Tcl_AppendStringsToObj(resultPtr, "bad option \"", string2, "\": must be -nocase", (char *) NULL); return TCL_ERROR; } } if (Tcl_ListObjGetElements(interp, objv[objc-2], &mapElemc, &mapElemv) != TCL_OK) { return TCL_ERROR; } if (mapElemc == 0) { /* * empty charMap, just return whatever string was given */ Tcl_SetObjResult(interp, objv[objc-1]); return TCL_OK; } else if (mapElemc & 1) { /* * The charMap must be an even number of key/value items */ Tcl_SetStringObj(resultPtr, "char map list unbalanced", -1); return TCL_ERROR; } /* * Take a copy of the source string object if it is the * same as the map string to cut out nasty sharing * crashes. [Bug 1018562] */ if (objv[objc-2] == objv[objc-1]) { sourceObj = Tcl_DuplicateObj(objv[objc-1]); copySource = 1; } else { sourceObj = objv[objc-1]; } ustring1 = Tcl_GetUnicodeFromObj(sourceObj, &length1); if (length1 == 0) { /* * Empty input string, just stop now */ if (copySource) { Tcl_DecrRefCount(sourceObj); } break; } end = ustring1 + length1; strCmpFn = nocase ? Tcl_UniCharNcasecmp : Tcl_UniCharNcmp; /* * Force result to be Unicode */ Tcl_SetUnicodeObj(resultPtr, ustring1, 0); if (mapElemc == 2) { /* * Special case for one map pair which avoids the extra * for loop and extra calls to get Unicode data. The * algorithm is otherwise identical to the multi-pair case. * This will be >30% faster on larger strings. */ int mapLen; Tcl_UniChar *mapString, u2lc; ustring2 = Tcl_GetUnicodeFromObj(mapElemv[0], &length2); p = ustring1; if ((length2 > length1) || (length2 == 0)) { /* match string is either longer than input or empty */ ustring1 = end; } else { mapString = Tcl_GetUnicodeFromObj(mapElemv[1], &mapLen); u2lc = (nocase ? Tcl_UniCharToLower(*ustring2) : 0); for (; ustring1 < end; ustring1++) { if (((*ustring1 == *ustring2) || (nocase && (Tcl_UniCharToLower(*ustring1) == u2lc))) && ((length2 == 1) || strCmpFn(ustring1, ustring2, (unsigned long) length2) == 0)) { if (p != ustring1) { Tcl_AppendUnicodeToObj(resultPtr, p, ustring1 - p); p = ustring1 + length2; } else { p += length2; } ustring1 = p - 1; Tcl_AppendUnicodeToObj(resultPtr, mapString, mapLen); } } } } else { Tcl_UniChar **mapStrings, *u2lc = NULL; int *mapLens; /* * Precompute pointers to the unicode string and length. * This saves us repeated function calls later, * significantly speeding up the algorithm. We only need * the lowercase first char in the nocase case. */ mapStrings = (Tcl_UniChar **) ckalloc((mapElemc * 2) * sizeof(Tcl_UniChar *)); mapLens = (int *) ckalloc((mapElemc * 2) * sizeof(int)); if (nocase) { u2lc = (Tcl_UniChar *) ckalloc((mapElemc) * sizeof(Tcl_UniChar)); } for (index = 0; index < mapElemc; index++) { mapStrings[index] = Tcl_GetUnicodeFromObj(mapElemv[index], &(mapLens[index])); if (nocase && ((index % 2) == 0)) { u2lc[index/2] = Tcl_UniCharToLower(*mapStrings[index]); } } for (p = ustring1; ustring1 < end; ustring1++) { for (index = 0; index < mapElemc; index += 2) { /* * Get the key string to match on. */ ustring2 = mapStrings[index]; length2 = mapLens[index]; if ((length2 > 0) && ((*ustring1 == *ustring2) || (nocase && (Tcl_UniCharToLower(*ustring1) == u2lc[index/2]))) && /* restrict max compare length */ ((end - ustring1) >= length2) && ((length2 == 1) || strCmpFn(ustring2, ustring1, (unsigned long) length2) == 0)) { if (p != ustring1) { /* * Put the skipped chars onto the result first */ Tcl_AppendUnicodeToObj(resultPtr, p, ustring1 - p); p = ustring1 + length2; } else { p += length2; } /* * Adjust len to be full length of matched string */ ustring1 = p - 1; /* * Append the map value to the unicode string */ Tcl_AppendUnicodeToObj(resultPtr, mapStrings[index+1], mapLens[index+1]); break; } } } ckfree((char *) mapStrings); ckfree((char *) mapLens); if (nocase) { ckfree((char *) u2lc); } } if (p != ustring1) { /* * Put the rest of the unmapped chars onto result */ Tcl_AppendUnicodeToObj(resultPtr, p, ustring1 - p); } if (copySource) { Tcl_DecrRefCount(sourceObj); } break; } case STR_MATCH: { Tcl_UniChar *ustring1, *ustring2; int nocase = 0; if (objc < 4 || objc > 5) { Tcl_WrongNumArgs(interp, 2, objv, "?-nocase? pattern string"); return TCL_ERROR; } if (objc == 5) { string2 = Tcl_GetStringFromObj(objv[2], &length2); if ((length2 > 1) && strncmp(string2, "-nocase", (size_t) length2) == 0) { nocase = 1; } else { Tcl_AppendStringsToObj(resultPtr, "bad option \"", string2, "\": must be -nocase", (char *) NULL); return TCL_ERROR; } } ustring1 = Tcl_GetUnicodeFromObj(objv[objc-1], &length1); ustring2 = Tcl_GetUnicodeFromObj(objv[objc-2], &length2); Tcl_SetBooleanObj(resultPtr, TclUniCharMatch(ustring1, length1, ustring2, length2, nocase)); break; } case STR_RANGE: { int first, last; if (objc != 5) { Tcl_WrongNumArgs(interp, 2, objv, "string first last"); return TCL_ERROR; } /* * If we have a ByteArray object, avoid indexing in the * Utf string since the byte array contains one byte per * character. Otherwise, use the Unicode string rep to * get the range. */ if (objv[2]->typePtr == &tclByteArrayType) { string1 = (char *)Tcl_GetByteArrayFromObj(objv[2], &length1); length1--; } else { /* * Get the length in actual characters. */ string1 = NULL; length1 = Tcl_GetCharLength(objv[2]) - 1; } if ((TclGetIntForIndex(interp, objv[3], length1, &first) != TCL_OK) || (TclGetIntForIndex(interp, objv[4], length1, &last) != TCL_OK)) { return TCL_ERROR; } if (first < 0) { first = 0; } if (last >= length1) { last = length1; } if (last >= first) { if (string1 != NULL) { int numBytes = last - first + 1; resultPtr = Tcl_NewByteArrayObj( (unsigned char *) &string1[first], numBytes); Tcl_SetObjResult(interp, resultPtr); } else { Tcl_SetObjResult(interp, Tcl_GetRange(objv[2], first, last)); } } break; } case STR_REPEAT: { int count; if (objc != 4) { Tcl_WrongNumArgs(interp, 2, objv, "string count"); return TCL_ERROR; } if (Tcl_GetIntFromObj(interp, objv[3], &count) != TCL_OK) { return TCL_ERROR; } if (count == 1) { Tcl_SetObjResult(interp, objv[2]); } else if (count > 1) { string1 = Tcl_GetStringFromObj(objv[2], &length1); if (length1 > 0) { /* * Only build up a string that has data. Instead of * building it up with repeated appends, we just allocate * the necessary space once and copy the string value in. * Check for overflow with back-division. [Bug #714106] */ length2 = length1 * count; if ((length2 / count) != length1) { char buf[TCL_INTEGER_SPACE+1]; sprintf(buf, "%d", INT_MAX); Tcl_AppendStringsToObj(resultPtr, "string size overflow, must be less than ", buf, (char *) NULL); return TCL_ERROR; } /* * Include space for the NULL */ string2 = (char *) ckalloc((size_t) length2+1); for (index = 0; index < count; index++) { memcpy(string2 + (length1 * index), string1, (size_t) length1); } string2[length2] = '\0'; /* * We have to directly assign this instead of using * Tcl_SetStringObj (and indirectly TclInitStringRep) * because that makes another copy of the data. */ resultPtr = Tcl_NewObj(); resultPtr->bytes = string2; resultPtr->length = length2; Tcl_SetObjResult(interp, resultPtr); } } break; } case STR_REPLACE: { Tcl_UniChar *ustring1; int first, last; if (objc < 5 || objc > 6) { Tcl_WrongNumArgs(interp, 2, objv, "string first last ?string?"); return TCL_ERROR; } ustring1 = Tcl_GetUnicodeFromObj(objv[2], &length1); length1--; if ((TclGetIntForIndex(interp, objv[3], length1, &first) != TCL_OK) || (TclGetIntForIndex(interp, objv[4], length1, &last) != TCL_OK)) { return TCL_ERROR; } if ((last < first) || (last < 0) || (first > length1)) { Tcl_SetObjResult(interp, objv[2]); } else { if (first < 0) { first = 0; } Tcl_SetUnicodeObj(resultPtr, ustring1, first); if (objc == 6) { Tcl_AppendObjToObj(resultPtr, objv[5]); } if (last < length1) { Tcl_AppendUnicodeToObj(resultPtr, ustring1 + last + 1, length1 - last); } } break; } case STR_TOLOWER: case STR_TOUPPER: case STR_TOTITLE: if (objc < 3 || objc > 5) { Tcl_WrongNumArgs(interp, 2, objv, "string ?first? ?last?"); return TCL_ERROR; } string1 = Tcl_GetStringFromObj(objv[2], &length1); if (objc == 3) { /* * Since the result object is not a shared object, it is * safe to copy the string into the result and do the * conversion in place. The conversion may change the length * of the string, so reset the length after conversion. */ Tcl_SetStringObj(resultPtr, string1, length1); if ((enum options) index == STR_TOLOWER) { length1 = Tcl_UtfToLower(Tcl_GetString(resultPtr)); } else if ((enum options) index == STR_TOUPPER) { length1 = Tcl_UtfToUpper(Tcl_GetString(resultPtr)); } else { length1 = Tcl_UtfToTitle(Tcl_GetString(resultPtr)); } Tcl_SetObjLength(resultPtr, length1); } else { int first, last; CONST char *start, *end; length1 = Tcl_NumUtfChars(string1, length1) - 1; if (TclGetIntForIndex(interp, objv[3], length1, &first) != TCL_OK) { return TCL_ERROR; } if (first < 0) { first = 0; } last = first; if ((objc == 5) && (TclGetIntForIndex(interp, objv[4], length1, &last) != TCL_OK)) { return TCL_ERROR; } if (last >= length1) { last = length1; } if (last < first) { Tcl_SetObjResult(interp, objv[2]); break; } start = Tcl_UtfAtIndex(string1, first); end = Tcl_UtfAtIndex(start, last - first + 1); length2 = end-start; string2 = ckalloc((size_t) length2+1); memcpy(string2, start, (size_t) length2); string2[length2] = '\0'; if ((enum options) index == STR_TOLOWER) { length2 = Tcl_UtfToLower(string2); } else if ((enum options) index == STR_TOUPPER) { length2 = Tcl_UtfToUpper(string2); } else { length2 = Tcl_UtfToTitle(string2); } Tcl_SetStringObj(resultPtr, string1, start - string1); Tcl_AppendToObj(resultPtr, string2, length2); Tcl_AppendToObj(resultPtr, end, -1); ckfree(string2); } break; case STR_TRIM: { Tcl_UniChar ch, trim; register CONST char *p, *end; char *check, *checkEnd; int offset; left = 1; right = 1; dotrim: if (objc == 4) { string2 = Tcl_GetStringFromObj(objv[3], &length2); } else if (objc == 3) { string2 = " \t\n\r"; length2 = strlen(string2); } else { Tcl_WrongNumArgs(interp, 2, objv, "string ?chars?"); return TCL_ERROR; } string1 = Tcl_GetStringFromObj(objv[2], &length1); checkEnd = string2 + length2; if (left) { end = string1 + length1; /* * The outer loop iterates over the string. The inner * loop iterates over the trim characters. The loops * terminate as soon as a non-trim character is discovered * and string1 is left pointing at the first non-trim * character. */ for (p = string1; p < end; p += offset) { offset = TclUtfToUniChar(p, &ch); for (check = string2; ; ) { if (check >= checkEnd) { p = end; break; } check += TclUtfToUniChar(check, &trim); if (ch == trim) { length1 -= offset; string1 += offset; break; } } } } if (right) { end = string1; /* * The outer loop iterates over the string. The inner * loop iterates over the trim characters. The loops * terminate as soon as a non-trim character is discovered * and length1 marks the last non-trim character. */ for (p = string1 + length1; p > end; ) { p = Tcl_UtfPrev(p, string1); offset = TclUtfToUniChar(p, &ch); for (check = string2; ; ) { if (check >= checkEnd) { p = end; break; } check += TclUtfToUniChar(check, &trim); if (ch == trim) { length1 -= offset; break; } } } } Tcl_SetStringObj(resultPtr, string1, length1); break; } case STR_TRIMLEFT: { left = 1; right = 0; goto dotrim; } case STR_TRIMRIGHT: { left = 0; right = 1; goto dotrim; } case STR_WORDEND: { int cur; Tcl_UniChar ch; CONST char *p, *end; int numChars; if (objc != 4) { Tcl_WrongNumArgs(interp, 2, objv, "string index"); return TCL_ERROR; } string1 = Tcl_GetStringFromObj(objv[2], &length1); numChars = Tcl_NumUtfChars(string1, length1); if (TclGetIntForIndex(interp, objv[3], numChars-1, &index) != TCL_OK) { return TCL_ERROR; } if (index < 0) { index = 0; } if (index < numChars) { p = Tcl_UtfAtIndex(string1, index); end = string1+length1; for (cur = index; p < end; cur++) { p += TclUtfToUniChar(p, &ch); if (!Tcl_UniCharIsWordChar(ch)) { break; } } if (cur == index) { cur++; } } else { cur = numChars; } Tcl_SetIntObj(resultPtr, cur); break; } case STR_WORDSTART: { int cur; Tcl_UniChar ch; CONST char *p; int numChars; if (objc != 4) { Tcl_WrongNumArgs(interp, 2, objv, "string index"); return TCL_ERROR; } string1 = Tcl_GetStringFromObj(objv[2], &length1); numChars = Tcl_NumUtfChars(string1, length1); if (TclGetIntForIndex(interp, objv[3], numChars-1, &index) != TCL_OK) { return TCL_ERROR; } if (index >= numChars) { index = numChars - 1; } cur = 0; if (index > 0) { p = Tcl_UtfAtIndex(string1, index); for (cur = index; cur >= 0; cur--) { TclUtfToUniChar(p, &ch); if (!Tcl_UniCharIsWordChar(ch)) { break; } p = Tcl_UtfPrev(p, string1); } if (cur != index) { cur += 1; } } Tcl_SetIntObj(resultPtr, cur); break; } } return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_SubstObjCmd -- * * This procedure is invoked to process the "subst" Tcl command. * See the user documentation for details on what it does. This * command relies on Tcl_SubstObj() for its implementation. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_SubstObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { static CONST char *substOptions[] = { "-nobackslashes", "-nocommands", "-novariables", (char *) NULL }; enum substOptions { SUBST_NOBACKSLASHES, SUBST_NOCOMMANDS, SUBST_NOVARS }; Tcl_Obj *resultPtr; int optionIndex, flags, i; /* * Parse command-line options. */ flags = TCL_SUBST_ALL; for (i = 1; i < (objc-1); i++) { if (Tcl_GetIndexFromObj(interp, objv[i], substOptions, "switch", 0, &optionIndex) != TCL_OK) { return TCL_ERROR; } switch (optionIndex) { case SUBST_NOBACKSLASHES: { flags &= ~TCL_SUBST_BACKSLASHES; break; } case SUBST_NOCOMMANDS: { flags &= ~TCL_SUBST_COMMANDS; break; } case SUBST_NOVARS: { flags &= ~TCL_SUBST_VARIABLES; break; } default: { panic("Tcl_SubstObjCmd: bad option index to SubstOptions"); } } } if (i != (objc-1)) { Tcl_WrongNumArgs(interp, 1, objv, "?-nobackslashes? ?-nocommands? ?-novariables? string"); return TCL_ERROR; } /* * Perform the substitution. */ resultPtr = Tcl_SubstObj(interp, objv[i], flags); if (resultPtr == NULL) { return TCL_ERROR; } Tcl_SetObjResult(interp, resultPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_SubstObj -- * * This function performs the substitutions specified on the * given string as described in the user documentation for the * "subst" Tcl command. This code is heavily based on an * implementation by Andrew Payne. Note that if a command * substitution returns TCL_CONTINUE or TCL_RETURN from its * evaluation and is not completely well-formed, the results are * not defined (or at least hard to characterise.) This fault * will be fixed at some point, but the cost of the only sane * fix (well-formedness check first) is such that you need to * "precompile and cache" to stop everyone from being hit with * the consequences every time through. Note that the current * behaviour is not a security hole; it just restarts parsing * the string following the substitution in a mildly surprising * place, and it is a very bad idea to count on this remaining * the same in future... * * Results: * A Tcl_Obj* containing the substituted string, or NULL to * indicate that an error occurred. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ Tcl_Obj * Tcl_SubstObj(interp, objPtr, flags) Tcl_Interp *interp; Tcl_Obj *objPtr; int flags; { Tcl_Obj *resultObj; char *p, *old; int length; old = p = Tcl_GetStringFromObj(objPtr, &length); resultObj = Tcl_NewStringObj("", 0); while (length) { switch (*p) { case '\\': if (flags & TCL_SUBST_BACKSLASHES) { char buf[TCL_UTF_MAX]; int count; if (p != old) { Tcl_AppendToObj(resultObj, old, p-old); } Tcl_AppendToObj(resultObj, buf, TclParseBackslash(p, length, &count, buf)); p += count; length -= count; old = p; } else { p++; length--; } break; case '$': if (flags & TCL_SUBST_VARIABLES) { Tcl_Parse parse; int code; /* * Code is simpler overall if we (effectively) inline * Tcl_ParseVar, particularly as that allows us to use * a non-string interface when we come to appending * the variable contents to the result object. There * are a few other optimisations that doing this * enables (like being able to continue the run of * unsubstituted characters straight through if a '$' * does not precede a variable name.) */ if (Tcl_ParseVarName(interp, p, length, &parse, 0) != TCL_OK) { goto errorResult; } if (parse.numTokens == 1) { /* * There isn't a variable name after all: the $ is * just a $. */ p++; length--; break; } if (p != old) { Tcl_AppendToObj(resultObj, old, p-old); } p += parse.tokenPtr->size; length -= parse.tokenPtr->size; code = Tcl_EvalTokensStandard(interp, parse.tokenPtr, parse.numTokens); if (code == TCL_ERROR) { goto errorResult; } if (code == TCL_BREAK) { Tcl_ResetResult(interp); return resultObj; } if (code != TCL_CONTINUE) { Tcl_AppendObjToObj(resultObj, Tcl_GetObjResult(interp)); } Tcl_ResetResult(interp); old = p; } else { p++; length--; } break; case '[': if (flags & TCL_SUBST_COMMANDS) { Interp *iPtr = (Interp *) interp; int code; if (p != old) { Tcl_AppendToObj(resultObj, old, p-old); } iPtr->evalFlags = TCL_BRACKET_TERM; iPtr->numLevels++; code = TclInterpReady(interp); if (code == TCL_OK) { code = Tcl_EvalEx(interp, p+1, length-1, 0); } iPtr->numLevels--; switch (code) { case TCL_ERROR: goto errorResult; case TCL_BREAK: Tcl_ResetResult(interp); return resultObj; default: Tcl_AppendObjToObj(resultObj, Tcl_GetObjResult(interp)); case TCL_CONTINUE: Tcl_ResetResult(interp); old = p = (p+1 + iPtr->termOffset + 1); length -= (iPtr->termOffset + 2); } } else { p++; length--; } break; default: p++; length--; break; } } if (p != old) { Tcl_AppendToObj(resultObj, old, p-old); } return resultObj; errorResult: Tcl_DecrRefCount(resultObj); return NULL; } /* *---------------------------------------------------------------------- * * Tcl_SwitchObjCmd -- * * This object-based procedure is invoked to process the "switch" Tcl * command. See the user documentation for details on what it does. * * Results: * A standard Tcl object result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_SwitchObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int i, j, index, mode, matched, result, splitObjs; char *string, *pattern; Tcl_Obj *stringObj; Tcl_Obj *CONST *savedObjv = objv; #ifdef TCL_TIP280 Interp* iPtr = (Interp*) interp; int pc = 0; int bidx = 0; /* Index of body argument */ Tcl_Obj* blist = NULL; /* List obj which is the body */ CmdFrame ctx; /* Copy of the topmost cmdframe, * to allow us to mess with the * line information */ #endif static CONST char *options[] = { "-exact", "-glob", "-regexp", "--", NULL }; enum options { OPT_EXACT, OPT_GLOB, OPT_REGEXP, OPT_LAST }; mode = OPT_EXACT; for (i = 1; i < objc; i++) { string = Tcl_GetString(objv[i]); if (string[0] != '-') { break; } if (Tcl_GetIndexFromObj(interp, objv[i], options, "option", 0, &index) != TCL_OK) { return TCL_ERROR; } if (index == OPT_LAST) { i++; break; } mode = index; } if (objc - i < 2) { Tcl_WrongNumArgs(interp, 1, objv, "?switches? string pattern body ... ?default body?"); return TCL_ERROR; } stringObj = objv[i]; objc -= i + 1; objv += i + 1; #ifdef TCL_TIP280 bidx = i+1; /* First after the match string */ #endif /* * If all of the pattern/command pairs are lumped into a single * argument, split them out again. * * TIP #280: Determine the lines the words in the list start at, based on * the same data for the list word itself. The cmdFramePtr line information * is manipulated directly. */ splitObjs = 0; if (objc == 1) { Tcl_Obj **listv; #ifdef TCL_TIP280 blist = objv[0]; #endif if (Tcl_ListObjGetElements(interp, objv[0], &objc, &listv) != TCL_OK) { return TCL_ERROR; } /* * Ensure that the list is non-empty. */ if (objc < 1) { Tcl_WrongNumArgs(interp, 1, savedObjv, "?switches? string {pattern body ... ?default body?}"); return TCL_ERROR; } objv = listv; splitObjs = 1; } /* * Complain if there is an odd number of words in the list of * patterns and bodies. */ if (objc % 2) { Tcl_ResetResult(interp); Tcl_AppendResult(interp, "extra switch pattern with no body", NULL); /* * Check if this can be due to a badly placed comment * in the switch block. * * The following is an heuristic to detect the infamous * "comment in switch" error: just check if a pattern * begins with '#'. */ if (splitObjs) { for (i=0 ; icmdFramePtr; if (splitObjs) { /* We have to perform the GetSrc and other type dependent handling * of the frame here because we are munging with the line numbers, * something the other commands like if, etc. are not doing. Them * are fine with simply passing the CmdFrame through and having * the special handling done in 'info frame', or the bc compiler */ if (ctx.type == TCL_LOCATION_BC) { /* Note: Type BC => ctx.data.eval.path is not used. * ctx.data.tebc.codePtr is used instead. */ TclGetSrcInfoForPc (&ctx); pc = 1; /* The line information in the cmdFrame is now a copy we do * not own */ } if (ctx.type == TCL_LOCATION_SOURCE) { int bline = ctx.line [bidx]; if (bline >= 0) { ctx.line = (int*) ckalloc (objc * sizeof(int)); ctx.nline = objc; ListLines (blist, bline, objc, ctx.line, objv); } else { int k; /* Dynamic code word ... All elements are relative to themselves */ ctx.line = (int*) ckalloc (objc * sizeof(int)); ctx.nline = objc; for (k=0; k < objc; k++) {ctx.line[k] = -1;} } } else { int k; /* Anything else ... No information, or dynamic ... */ ctx.line = (int*) ckalloc (objc * sizeof(int)); ctx.nline = objc; for (k=0; k < objc; k++) {ctx.line[k] = -1;} } } #endif for (j = i + 1; ; j += 2) { if (j >= objc) { /* * This shouldn't happen since we've checked that the * last body is not a continuation... */ panic("fall-out when searching for body to match pattern"); } if (strcmp(Tcl_GetString(objv[j]), "-") != 0) { break; } } #ifndef TCL_TIP280 result = Tcl_EvalObjEx(interp, objv[j], 0); #else /* TIP #280. Make invoking context available to switch branch */ result = TclEvalObjEx(interp, objv[j], 0, &ctx, splitObjs ? j : bidx+j); if (splitObjs) { ckfree ((char*) ctx.line); if (pc && (ctx.type == TCL_LOCATION_SOURCE)) { /* Death of SrcInfo reference */ Tcl_DecrRefCount (ctx.data.eval.path); } } #endif if (result == TCL_ERROR) { char msg[100 + TCL_INTEGER_SPACE]; sprintf(msg, "\n (\"%.50s\" arm line %d)", pattern, interp->errorLine); Tcl_AddObjErrorInfo(interp, msg, -1); } return result; } return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_TimeObjCmd -- * * This object-based procedure is invoked to process the "time" Tcl * command. See the user documentation for details on what it does. * * Results: * A standard Tcl object result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_TimeObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { register Tcl_Obj *objPtr; Tcl_Obj *objs[4]; register int i, result; int count; double totalMicroSec; Tcl_Time start, stop; if (objc == 2) { count = 1; } else if (objc == 3) { result = Tcl_GetIntFromObj(interp, objv[2], &count); if (result != TCL_OK) { return result; } } else { Tcl_WrongNumArgs(interp, 1, objv, "command ?count?"); return TCL_ERROR; } objPtr = objv[1]; i = count; Tcl_GetTime(&start); while (i-- > 0) { result = Tcl_EvalObjEx(interp, objPtr, 0); if (result != TCL_OK) { return result; } } Tcl_GetTime(&stop); totalMicroSec = ( ( (double) ( stop.sec - start.sec ) ) * 1.0e6 + ( stop.usec - start.usec ) ); if (count <= 1) { /* Use int obj since we know time is not fractional [Bug 1202178] */ objs[0] = Tcl_NewIntObj((count <= 0) ? 0 : (int) totalMicroSec); } else { objs[0] = Tcl_NewDoubleObj(totalMicroSec/count); } objs[1] = Tcl_NewStringObj("microseconds", -1); objs[2] = Tcl_NewStringObj("per", -1); objs[3] = Tcl_NewStringObj("iteration", -1); Tcl_SetObjResult(interp, Tcl_NewListObj(4, objs)); return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_TraceObjCmd -- * * This procedure is invoked to process the "trace" Tcl command. * See the user documentation for details on what it does. * * Standard syntax as of Tcl 8.4 is * * trace {add|info|remove} {command|variable} name ops cmd * * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_TraceObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int optionIndex; char *name, *flagOps, *p; /* Main sub commands to 'trace' */ static CONST char *traceOptions[] = { "add", "info", "remove", #ifndef TCL_REMOVE_OBSOLETE_TRACES "variable", "vdelete", "vinfo", #endif (char *) NULL }; /* 'OLD' options are pre-Tcl-8.4 style */ enum traceOptions { TRACE_ADD, TRACE_INFO, TRACE_REMOVE, #ifndef TCL_REMOVE_OBSOLETE_TRACES TRACE_OLD_VARIABLE, TRACE_OLD_VDELETE, TRACE_OLD_VINFO #endif }; if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[1], traceOptions, "option", 0, &optionIndex) != TCL_OK) { return TCL_ERROR; } switch ((enum traceOptions) optionIndex) { case TRACE_ADD: case TRACE_REMOVE: case TRACE_INFO: { /* * All sub commands of trace add/remove must take at least * one more argument. Beyond that we let the subcommand itself * control the argument structure. */ int typeIndex; if (objc < 3) { Tcl_WrongNumArgs(interp, 2, objv, "type ?arg arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[2], traceTypeOptions, "option", 0, &typeIndex) != TCL_OK) { return TCL_ERROR; } return (traceSubCmds[typeIndex])(interp, optionIndex, objc, objv); } #ifndef TCL_REMOVE_OBSOLETE_TRACES case TRACE_OLD_VARIABLE: case TRACE_OLD_VDELETE: { Tcl_Obj *copyObjv[6]; Tcl_Obj *opsList; int code, numFlags; if (objc != 5) { Tcl_WrongNumArgs(interp, 2, objv, "name ops command"); return TCL_ERROR; } opsList = Tcl_NewObj(); Tcl_IncrRefCount(opsList); flagOps = Tcl_GetStringFromObj(objv[3], &numFlags); if (numFlags == 0) { Tcl_DecrRefCount(opsList); goto badVarOps; } for (p = flagOps; *p != 0; p++) { if (*p == 'r') { Tcl_ListObjAppendElement(NULL, opsList, Tcl_NewStringObj("read", -1)); } else if (*p == 'w') { Tcl_ListObjAppendElement(NULL, opsList, Tcl_NewStringObj("write", -1)); } else if (*p == 'u') { Tcl_ListObjAppendElement(NULL, opsList, Tcl_NewStringObj("unset", -1)); } else if (*p == 'a') { Tcl_ListObjAppendElement(NULL, opsList, Tcl_NewStringObj("array", -1)); } else { Tcl_DecrRefCount(opsList); goto badVarOps; } } copyObjv[0] = NULL; memcpy(copyObjv+1, objv, objc*sizeof(Tcl_Obj *)); copyObjv[4] = opsList; if (optionIndex == TRACE_OLD_VARIABLE) { code = (traceSubCmds[2])(interp,TRACE_ADD,objc+1,copyObjv); } else { code = (traceSubCmds[2])(interp,TRACE_REMOVE,objc+1,copyObjv); } Tcl_DecrRefCount(opsList); return code; } case TRACE_OLD_VINFO: { ClientData clientData; char ops[5]; Tcl_Obj *resultListPtr, *pairObjPtr, *elemObjPtr; if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "name"); return TCL_ERROR; } resultListPtr = Tcl_GetObjResult(interp); clientData = 0; name = Tcl_GetString(objv[2]); while ((clientData = Tcl_VarTraceInfo(interp, name, 0, TraceVarProc, clientData)) != 0) { TraceVarInfo *tvarPtr = (TraceVarInfo *) clientData; pairObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); p = ops; if (tvarPtr->flags & TCL_TRACE_READS) { *p = 'r'; p++; } if (tvarPtr->flags & TCL_TRACE_WRITES) { *p = 'w'; p++; } if (tvarPtr->flags & TCL_TRACE_UNSETS) { *p = 'u'; p++; } if (tvarPtr->flags & TCL_TRACE_ARRAY) { *p = 'a'; p++; } *p = '\0'; /* * Build a pair (2-item list) with the ops string as * the first obj element and the tvarPtr->command string * as the second obj element. Append the pair (as an * element) to the end of the result object list. */ elemObjPtr = Tcl_NewStringObj(ops, -1); Tcl_ListObjAppendElement(NULL, pairObjPtr, elemObjPtr); elemObjPtr = Tcl_NewStringObj(tvarPtr->command, -1); Tcl_ListObjAppendElement(NULL, pairObjPtr, elemObjPtr); Tcl_ListObjAppendElement(interp, resultListPtr, pairObjPtr); } Tcl_SetObjResult(interp, resultListPtr); break; } #endif /* TCL_REMOVE_OBSOLETE_TRACES */ } return TCL_OK; badVarOps: Tcl_AppendResult(interp, "bad operations \"", flagOps, "\": should be one or more of rwua", (char *) NULL); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TclTraceExecutionObjCmd -- * * Helper function for Tcl_TraceObjCmd; implements the * [trace {add|remove|info} execution ...] subcommands. * See the user documentation for details on what these do. * * Results: * Standard Tcl result. * * Side effects: * Depends on the operation (add, remove, or info) being performed; * may add or remove command traces on a command. * *---------------------------------------------------------------------- */ int TclTraceExecutionObjCmd(interp, optionIndex, objc, objv) Tcl_Interp *interp; /* Current interpreter. */ int optionIndex; /* Add, info or remove */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int commandLength, index; char *name, *command; size_t length; enum traceOptions { TRACE_ADD, TRACE_INFO, TRACE_REMOVE }; static CONST char *opStrings[] = { "enter", "leave", "enterstep", "leavestep", (char *) NULL }; enum operations { TRACE_EXEC_ENTER, TRACE_EXEC_LEAVE, TRACE_EXEC_ENTER_STEP, TRACE_EXEC_LEAVE_STEP }; switch ((enum traceOptions) optionIndex) { case TRACE_ADD: case TRACE_REMOVE: { int flags = 0; int i, listLen, result; Tcl_Obj **elemPtrs; if (objc != 6) { Tcl_WrongNumArgs(interp, 3, objv, "name opList command"); return TCL_ERROR; } /* * Make sure the ops argument is a list object; get its length and * a pointer to its array of element pointers. */ result = Tcl_ListObjGetElements(interp, objv[4], &listLen, &elemPtrs); if (result != TCL_OK) { return result; } if (listLen == 0) { Tcl_SetResult(interp, "bad operation list \"\": must be " "one or more of enter, leave, enterstep, or leavestep", TCL_STATIC); return TCL_ERROR; } for (i = 0; i < listLen; i++) { if (Tcl_GetIndexFromObj(interp, elemPtrs[i], opStrings, "operation", TCL_EXACT, &index) != TCL_OK) { return TCL_ERROR; } switch ((enum operations) index) { case TRACE_EXEC_ENTER: flags |= TCL_TRACE_ENTER_EXEC; break; case TRACE_EXEC_LEAVE: flags |= TCL_TRACE_LEAVE_EXEC; break; case TRACE_EXEC_ENTER_STEP: flags |= TCL_TRACE_ENTER_DURING_EXEC; break; case TRACE_EXEC_LEAVE_STEP: flags |= TCL_TRACE_LEAVE_DURING_EXEC; break; } } command = Tcl_GetStringFromObj(objv[5], &commandLength); length = (size_t) commandLength; if ((enum traceOptions) optionIndex == TRACE_ADD) { TraceCommandInfo *tcmdPtr; tcmdPtr = (TraceCommandInfo *) ckalloc((unsigned) (sizeof(TraceCommandInfo) - sizeof(tcmdPtr->command) + length + 1)); tcmdPtr->flags = flags; tcmdPtr->stepTrace = NULL; tcmdPtr->startLevel = 0; tcmdPtr->startCmd = NULL; tcmdPtr->length = length; tcmdPtr->refCount = 1; flags |= TCL_TRACE_DELETE; if (flags & (TCL_TRACE_ENTER_DURING_EXEC | TCL_TRACE_LEAVE_DURING_EXEC)) { flags |= (TCL_TRACE_ENTER_EXEC | TCL_TRACE_LEAVE_EXEC); } memcpy(tcmdPtr->command, command, length + 1); name = Tcl_GetString(objv[3]); if (Tcl_TraceCommand(interp, name, flags, TraceCommandProc, (ClientData) tcmdPtr) != TCL_OK) { ckfree((char *) tcmdPtr); return TCL_ERROR; } } else { /* * Search through all of our traces on this command to * see if there's one with the given command. If so, then * delete the first one that matches. */ TraceCommandInfo *tcmdPtr; ClientData clientData = NULL; name = Tcl_GetString(objv[3]); /* First ensure the name given is valid */ if (Tcl_FindCommand(interp, name, NULL, TCL_LEAVE_ERR_MSG) == NULL) { return TCL_ERROR; } while ((clientData = Tcl_CommandTraceInfo(interp, name, 0, TraceCommandProc, clientData)) != NULL) { tcmdPtr = (TraceCommandInfo *) clientData; /* * In checking the 'flags' field we must remove any * extraneous flags which may have been temporarily * added by various pieces of the trace mechanism. */ if ((tcmdPtr->length == length) && ((tcmdPtr->flags & (TCL_TRACE_ANY_EXEC | TCL_TRACE_RENAME | TCL_TRACE_DELETE)) == flags) && (strncmp(command, tcmdPtr->command, (size_t) length) == 0)) { flags |= TCL_TRACE_DELETE; if (flags & (TCL_TRACE_ENTER_DURING_EXEC | TCL_TRACE_LEAVE_DURING_EXEC)) { flags |= (TCL_TRACE_ENTER_EXEC | TCL_TRACE_LEAVE_EXEC); } Tcl_UntraceCommand(interp, name, flags, TraceCommandProc, clientData); if (tcmdPtr->stepTrace != NULL) { /* * We need to remove the interpreter-wide trace * which we created to allow 'step' traces. */ Tcl_DeleteTrace(interp, tcmdPtr->stepTrace); tcmdPtr->stepTrace = NULL; if (tcmdPtr->startCmd != NULL) { ckfree((char *)tcmdPtr->startCmd); } } if (tcmdPtr->flags & TCL_TRACE_EXEC_IN_PROGRESS) { /* Postpone deletion */ tcmdPtr->flags = 0; } tcmdPtr->refCount--; if (tcmdPtr->refCount < 0) { Tcl_Panic("TclTraceExecutionObjCmd: negative TraceCommandInfo refCount"); } if (tcmdPtr->refCount == 0) { ckfree((char*)tcmdPtr); } break; } } } break; } case TRACE_INFO: { ClientData clientData; Tcl_Obj *resultListPtr, *eachTraceObjPtr, *elemObjPtr; if (objc != 4) { Tcl_WrongNumArgs(interp, 3, objv, "name"); return TCL_ERROR; } clientData = NULL; name = Tcl_GetString(objv[3]); /* First ensure the name given is valid */ if (Tcl_FindCommand(interp, name, NULL, TCL_LEAVE_ERR_MSG) == NULL) { return TCL_ERROR; } resultListPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); while ((clientData = Tcl_CommandTraceInfo(interp, name, 0, TraceCommandProc, clientData)) != NULL) { int numOps = 0; TraceCommandInfo *tcmdPtr = (TraceCommandInfo *) clientData; /* * Build a list with the ops list as the first obj * element and the tcmdPtr->command string as the * second obj element. Append this list (as an * element) to the end of the result object list. */ elemObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); Tcl_IncrRefCount(elemObjPtr); if (tcmdPtr->flags & TCL_TRACE_ENTER_EXEC) { Tcl_ListObjAppendElement(NULL, elemObjPtr, Tcl_NewStringObj("enter",5)); } if (tcmdPtr->flags & TCL_TRACE_LEAVE_EXEC) { Tcl_ListObjAppendElement(NULL, elemObjPtr, Tcl_NewStringObj("leave",5)); } if (tcmdPtr->flags & TCL_TRACE_ENTER_DURING_EXEC) { Tcl_ListObjAppendElement(NULL, elemObjPtr, Tcl_NewStringObj("enterstep",9)); } if (tcmdPtr->flags & TCL_TRACE_LEAVE_DURING_EXEC) { Tcl_ListObjAppendElement(NULL, elemObjPtr, Tcl_NewStringObj("leavestep",9)); } Tcl_ListObjLength(NULL, elemObjPtr, &numOps); if (0 == numOps) { Tcl_DecrRefCount(elemObjPtr); continue; } eachTraceObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); Tcl_ListObjAppendElement(NULL, eachTraceObjPtr, elemObjPtr); Tcl_DecrRefCount(elemObjPtr); elemObjPtr = NULL; Tcl_ListObjAppendElement(NULL, eachTraceObjPtr, Tcl_NewStringObj(tcmdPtr->command, -1)); Tcl_ListObjAppendElement(interp, resultListPtr, eachTraceObjPtr); } Tcl_SetObjResult(interp, resultListPtr); break; } } return TCL_OK; } /* *---------------------------------------------------------------------- * * TclTraceCommandObjCmd -- * * Helper function for Tcl_TraceObjCmd; implements the * [trace {add|info|remove} command ...] subcommands. * See the user documentation for details on what these do. * * Results: * Standard Tcl result. * * Side effects: * Depends on the operation (add, remove, or info) being performed; * may add or remove command traces on a command. * *---------------------------------------------------------------------- */ int TclTraceCommandObjCmd(interp, optionIndex, objc, objv) Tcl_Interp *interp; /* Current interpreter. */ int optionIndex; /* Add, info or remove */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int commandLength, index; char *name, *command; size_t length; enum traceOptions { TRACE_ADD, TRACE_INFO, TRACE_REMOVE }; static CONST char *opStrings[] = { "delete", "rename", (char *) NULL }; enum operations { TRACE_CMD_DELETE, TRACE_CMD_RENAME }; switch ((enum traceOptions) optionIndex) { case TRACE_ADD: case TRACE_REMOVE: { int flags = 0; int i, listLen, result; Tcl_Obj **elemPtrs; if (objc != 6) { Tcl_WrongNumArgs(interp, 3, objv, "name opList command"); return TCL_ERROR; } /* * Make sure the ops argument is a list object; get its length and * a pointer to its array of element pointers. */ result = Tcl_ListObjGetElements(interp, objv[4], &listLen, &elemPtrs); if (result != TCL_OK) { return result; } if (listLen == 0) { Tcl_SetResult(interp, "bad operation list \"\": must be " "one or more of delete or rename", TCL_STATIC); return TCL_ERROR; } for (i = 0; i < listLen; i++) { if (Tcl_GetIndexFromObj(interp, elemPtrs[i], opStrings, "operation", TCL_EXACT, &index) != TCL_OK) { return TCL_ERROR; } switch ((enum operations) index) { case TRACE_CMD_RENAME: flags |= TCL_TRACE_RENAME; break; case TRACE_CMD_DELETE: flags |= TCL_TRACE_DELETE; break; } } command = Tcl_GetStringFromObj(objv[5], &commandLength); length = (size_t) commandLength; if ((enum traceOptions) optionIndex == TRACE_ADD) { TraceCommandInfo *tcmdPtr; tcmdPtr = (TraceCommandInfo *) ckalloc((unsigned) (sizeof(TraceCommandInfo) - sizeof(tcmdPtr->command) + length + 1)); tcmdPtr->flags = flags; tcmdPtr->stepTrace = NULL; tcmdPtr->startLevel = 0; tcmdPtr->startCmd = NULL; tcmdPtr->length = length; tcmdPtr->refCount = 1; flags |= TCL_TRACE_DELETE; memcpy(tcmdPtr->command, command, length + 1); name = Tcl_GetString(objv[3]); if (Tcl_TraceCommand(interp, name, flags, TraceCommandProc, (ClientData) tcmdPtr) != TCL_OK) { ckfree((char *) tcmdPtr); return TCL_ERROR; } } else { /* * Search through all of our traces on this command to * see if there's one with the given command. If so, then * delete the first one that matches. */ TraceCommandInfo *tcmdPtr; ClientData clientData = NULL; name = Tcl_GetString(objv[3]); /* First ensure the name given is valid */ if (Tcl_FindCommand(interp, name, NULL, TCL_LEAVE_ERR_MSG) == NULL) { return TCL_ERROR; } while ((clientData = Tcl_CommandTraceInfo(interp, name, 0, TraceCommandProc, clientData)) != NULL) { tcmdPtr = (TraceCommandInfo *) clientData; if ((tcmdPtr->length == length) && (tcmdPtr->flags == flags) && (strncmp(command, tcmdPtr->command, (size_t) length) == 0)) { Tcl_UntraceCommand(interp, name, flags | TCL_TRACE_DELETE, TraceCommandProc, clientData); tcmdPtr->flags |= TCL_TRACE_DESTROYED; tcmdPtr->refCount--; if (tcmdPtr->refCount < 0) { Tcl_Panic("TclTraceCommandObjCmd: negative TraceCommandInfo refCount"); } if (tcmdPtr->refCount == 0) { ckfree((char *) tcmdPtr); } break; } } } break; } case TRACE_INFO: { ClientData clientData; Tcl_Obj *resultListPtr, *eachTraceObjPtr, *elemObjPtr; if (objc != 4) { Tcl_WrongNumArgs(interp, 3, objv, "name"); return TCL_ERROR; } clientData = NULL; name = Tcl_GetString(objv[3]); /* First ensure the name given is valid */ if (Tcl_FindCommand(interp, name, NULL, TCL_LEAVE_ERR_MSG) == NULL) { return TCL_ERROR; } resultListPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); while ((clientData = Tcl_CommandTraceInfo(interp, name, 0, TraceCommandProc, clientData)) != NULL) { int numOps = 0; TraceCommandInfo *tcmdPtr = (TraceCommandInfo *) clientData; /* * Build a list with the ops list as * the first obj element and the tcmdPtr->command string * as the second obj element. Append this list (as an * element) to the end of the result object list. */ elemObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); Tcl_IncrRefCount(elemObjPtr); if (tcmdPtr->flags & TCL_TRACE_RENAME) { Tcl_ListObjAppendElement(NULL, elemObjPtr, Tcl_NewStringObj("rename",6)); } if (tcmdPtr->flags & TCL_TRACE_DELETE) { Tcl_ListObjAppendElement(NULL, elemObjPtr, Tcl_NewStringObj("delete",6)); } Tcl_ListObjLength(NULL, elemObjPtr, &numOps); if (0 == numOps) { Tcl_DecrRefCount(elemObjPtr); continue; } eachTraceObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); Tcl_ListObjAppendElement(NULL, eachTraceObjPtr, elemObjPtr); Tcl_DecrRefCount(elemObjPtr); elemObjPtr = Tcl_NewStringObj(tcmdPtr->command, -1); Tcl_ListObjAppendElement(NULL, eachTraceObjPtr, elemObjPtr); Tcl_ListObjAppendElement(interp, resultListPtr, eachTraceObjPtr); } Tcl_SetObjResult(interp, resultListPtr); break; } } return TCL_OK; } /* *---------------------------------------------------------------------- * * TclTraceVariableObjCmd -- * * Helper function for Tcl_TraceObjCmd; implements the * [trace {add|info|remove} variable ...] subcommands. * See the user documentation for details on what these do. * * Results: * Standard Tcl result. * * Side effects: * Depends on the operation (add, remove, or info) being performed; * may add or remove variable traces on a variable. * *---------------------------------------------------------------------- */ int TclTraceVariableObjCmd(interp, optionIndex, objc, objv) Tcl_Interp *interp; /* Current interpreter. */ int optionIndex; /* Add, info or remove */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int commandLength, index; char *name, *command; size_t length; enum traceOptions { TRACE_ADD, TRACE_INFO, TRACE_REMOVE }; static CONST char *opStrings[] = { "array", "read", "unset", "write", (char *) NULL }; enum operations { TRACE_VAR_ARRAY, TRACE_VAR_READ, TRACE_VAR_UNSET, TRACE_VAR_WRITE }; switch ((enum traceOptions) optionIndex) { case TRACE_ADD: case TRACE_REMOVE: { int flags = 0; int i, listLen, result; Tcl_Obj **elemPtrs; if (objc != 6) { Tcl_WrongNumArgs(interp, 3, objv, "name opList command"); return TCL_ERROR; } /* * Make sure the ops argument is a list object; get its length and * a pointer to its array of element pointers. */ result = Tcl_ListObjGetElements(interp, objv[4], &listLen, &elemPtrs); if (result != TCL_OK) { return result; } if (listLen == 0) { Tcl_SetResult(interp, "bad operation list \"\": must be " "one or more of array, read, unset, or write", TCL_STATIC); return TCL_ERROR; } for (i = 0; i < listLen ; i++) { if (Tcl_GetIndexFromObj(interp, elemPtrs[i], opStrings, "operation", TCL_EXACT, &index) != TCL_OK) { return TCL_ERROR; } switch ((enum operations) index) { case TRACE_VAR_ARRAY: flags |= TCL_TRACE_ARRAY; break; case TRACE_VAR_READ: flags |= TCL_TRACE_READS; break; case TRACE_VAR_UNSET: flags |= TCL_TRACE_UNSETS; break; case TRACE_VAR_WRITE: flags |= TCL_TRACE_WRITES; break; } } command = Tcl_GetStringFromObj(objv[5], &commandLength); length = (size_t) commandLength; if ((enum traceOptions) optionIndex == TRACE_ADD) { /* * This code essentially mallocs together the VarTrace and the * TraceVarInfo, then inlines the Tcl_TraceVar(). This is * necessary in order to have the TraceVarInfo to be freed * automatically when the VarTrace is freed [Bug 1348775] */ CompoundVarTrace *compTracePtr; TraceVarInfo *tvarPtr; Var *varPtr, *arrayPtr; VarTrace *tracePtr; int flagMask; compTracePtr = (CompoundVarTrace *) ckalloc((unsigned) (sizeof(CompoundVarTrace) - sizeof(tvarPtr->command) + length + 1)); tracePtr = &(compTracePtr->trace); tvarPtr = &(compTracePtr->tvar); tvarPtr->flags = flags; if (objv[0] == NULL) { tvarPtr->flags |= TCL_TRACE_OLD_STYLE; } tvarPtr->length = length; flags |= TCL_TRACE_UNSETS | TCL_TRACE_RESULT_OBJECT; memcpy(tvarPtr->command, command, length + 1); name = Tcl_GetString(objv[3]); flagMask = TCL_GLOBAL_ONLY | TCL_NAMESPACE_ONLY; varPtr = TclLookupVar(interp, name, NULL, (flags & flagMask) | TCL_LEAVE_ERR_MSG, "trace", /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr); if (varPtr == NULL) { ckfree((char *) tracePtr); return TCL_ERROR; } flagMask = TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS | TCL_TRACE_ARRAY | TCL_TRACE_RESULT_DYNAMIC | TCL_TRACE_RESULT_OBJECT; #ifndef TCL_REMOVE_OBSOLETE_TRACES flagMask |= TCL_TRACE_OLD_STYLE; #endif tracePtr->traceProc = TraceVarProc; tracePtr->clientData = (ClientData) tvarPtr; tracePtr->flags = flags & flagMask; tracePtr->nextPtr = varPtr->tracePtr; varPtr->tracePtr = tracePtr; } else { /* * Search through all of our traces on this variable to * see if there's one with the given command. If so, then * delete the first one that matches. */ TraceVarInfo *tvarPtr; ClientData clientData = 0; name = Tcl_GetString(objv[3]); while ((clientData = Tcl_VarTraceInfo(interp, name, 0, TraceVarProc, clientData)) != 0) { tvarPtr = (TraceVarInfo *) clientData; if ((tvarPtr->length == length) && ((tvarPtr->flags & ~TCL_TRACE_OLD_STYLE)==flags) && (strncmp(command, tvarPtr->command, (size_t) length) == 0)) { Tcl_UntraceVar2(interp, name, NULL, flags | TCL_TRACE_UNSETS | TCL_TRACE_RESULT_OBJECT, TraceVarProc, clientData); break; } } } break; } case TRACE_INFO: { ClientData clientData; Tcl_Obj *resultListPtr, *eachTraceObjPtr, *elemObjPtr; if (objc != 4) { Tcl_WrongNumArgs(interp, 3, objv, "name"); return TCL_ERROR; } resultListPtr = Tcl_GetObjResult(interp); clientData = 0; name = Tcl_GetString(objv[3]); while ((clientData = Tcl_VarTraceInfo(interp, name, 0, TraceVarProc, clientData)) != 0) { TraceVarInfo *tvarPtr = (TraceVarInfo *) clientData; /* * Build a list with the ops list as * the first obj element and the tcmdPtr->command string * as the second obj element. Append this list (as an * element) to the end of the result object list. */ elemObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); if (tvarPtr->flags & TCL_TRACE_ARRAY) { Tcl_ListObjAppendElement(NULL, elemObjPtr, Tcl_NewStringObj("array", 5)); } if (tvarPtr->flags & TCL_TRACE_READS) { Tcl_ListObjAppendElement(NULL, elemObjPtr, Tcl_NewStringObj("read", 4)); } if (tvarPtr->flags & TCL_TRACE_WRITES) { Tcl_ListObjAppendElement(NULL, elemObjPtr, Tcl_NewStringObj("write", 5)); } if (tvarPtr->flags & TCL_TRACE_UNSETS) { Tcl_ListObjAppendElement(NULL, elemObjPtr, Tcl_NewStringObj("unset", 5)); } eachTraceObjPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); Tcl_ListObjAppendElement(NULL, eachTraceObjPtr, elemObjPtr); elemObjPtr = Tcl_NewStringObj(tvarPtr->command, -1); Tcl_ListObjAppendElement(NULL, eachTraceObjPtr, elemObjPtr); Tcl_ListObjAppendElement(interp, resultListPtr, eachTraceObjPtr); } Tcl_SetObjResult(interp, resultListPtr); break; } } return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_CommandTraceInfo -- * * Return the clientData value associated with a trace on a * command. This procedure can also be used to step through * all of the traces on a particular command that have the * same trace procedure. * * Results: * The return value is the clientData value associated with * a trace on the given command. Information will only be * returned for a trace with proc as trace procedure. If * the clientData argument is NULL then the first such trace is * returned; otherwise, the next relevant one after the one * given by clientData will be returned. If the command * doesn't exist then an error message is left in the interpreter * and NULL is returned. Also, if there are no (more) traces for * the given command, NULL is returned. * * Side effects: * None. * *---------------------------------------------------------------------- */ ClientData Tcl_CommandTraceInfo(interp, cmdName, flags, proc, prevClientData) Tcl_Interp *interp; /* Interpreter containing command. */ CONST char *cmdName; /* Name of command. */ int flags; /* OR-ed combo or TCL_GLOBAL_ONLY, * TCL_NAMESPACE_ONLY (can be 0). */ Tcl_CommandTraceProc *proc; /* Procedure assocated with trace. */ ClientData prevClientData; /* If non-NULL, gives last value returned * by this procedure, so this call will * return the next trace after that one. * If NULL, this call will return the * first trace. */ { Command *cmdPtr; register CommandTrace *tracePtr; cmdPtr = (Command*)Tcl_FindCommand(interp, cmdName, NULL, TCL_LEAVE_ERR_MSG); if (cmdPtr == NULL) { return NULL; } /* * Find the relevant trace, if any, and return its clientData. */ tracePtr = cmdPtr->tracePtr; if (prevClientData != NULL) { for ( ; tracePtr != NULL; tracePtr = tracePtr->nextPtr) { if ((tracePtr->clientData == prevClientData) && (tracePtr->traceProc == proc)) { tracePtr = tracePtr->nextPtr; break; } } } for ( ; tracePtr != NULL; tracePtr = tracePtr->nextPtr) { if (tracePtr->traceProc == proc) { return tracePtr->clientData; } } return NULL; } /* *---------------------------------------------------------------------- * * Tcl_TraceCommand -- * * Arrange for rename/deletes to a command to cause a * procedure to be invoked, which can monitor the operations. * * Also optionally arrange for execution of that command * to cause a procedure to be invoked. * * Results: * A standard Tcl return value. * * Side effects: * A trace is set up on the command given by cmdName, such that * future changes to the command will be intermediated by * proc. See the manual entry for complete details on the calling * sequence for proc. * *---------------------------------------------------------------------- */ int Tcl_TraceCommand(interp, cmdName, flags, proc, clientData) Tcl_Interp *interp; /* Interpreter in which command is * to be traced. */ CONST char *cmdName; /* Name of command. */ int flags; /* OR-ed collection of bits, including any * of TCL_TRACE_RENAME, TCL_TRACE_DELETE, * and any of the TRACE_*_EXEC flags */ Tcl_CommandTraceProc *proc; /* Procedure to call when specified ops are * invoked upon varName. */ ClientData clientData; /* Arbitrary argument to pass to proc. */ { Command *cmdPtr; register CommandTrace *tracePtr; cmdPtr = (Command*)Tcl_FindCommand(interp, cmdName, NULL, TCL_LEAVE_ERR_MSG); if (cmdPtr == NULL) { return TCL_ERROR; } /* * Set up trace information. */ tracePtr = (CommandTrace *) ckalloc(sizeof(CommandTrace)); tracePtr->traceProc = proc; tracePtr->clientData = clientData; tracePtr->flags = flags & (TCL_TRACE_RENAME | TCL_TRACE_DELETE | TCL_TRACE_ANY_EXEC); tracePtr->nextPtr = cmdPtr->tracePtr; tracePtr->refCount = 1; cmdPtr->tracePtr = tracePtr; if ((tracePtr->flags & TCL_TRACE_ANY_EXEC) && !(cmdPtr->flags & CMD_HAS_EXEC_TRACES)) { cmdPtr->flags |= CMD_HAS_EXEC_TRACES; /* * Bug 3484621: New execution trace means we no longer compile * this command if we normally would. Invalidate bytecode. */ if (cmdPtr->compileProc != NULL) { ((Interp *)interp)->compileEpoch++; } } return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_UntraceCommand -- * * Remove a previously-created trace for a command. * * Results: * None. * * Side effects: * If there exists a trace for the command given by cmdName * with the given flags, proc, and clientData, then that trace * is removed. * *---------------------------------------------------------------------- */ void Tcl_UntraceCommand(interp, cmdName, flags, proc, clientData) Tcl_Interp *interp; /* Interpreter containing command. */ CONST char *cmdName; /* Name of command. */ int flags; /* OR-ed collection of bits, including any * of TCL_TRACE_RENAME, TCL_TRACE_DELETE, * and any of the TRACE_*_EXEC flags */ Tcl_CommandTraceProc *proc; /* Procedure assocated with trace. */ ClientData clientData; /* Arbitrary argument to pass to proc. */ { register CommandTrace *tracePtr; CommandTrace *prevPtr; Command *cmdPtr; Interp *iPtr = (Interp *) interp; ActiveCommandTrace *activePtr; int hasExecTraces = 0; cmdPtr = (Command*)Tcl_FindCommand(interp, cmdName, NULL, TCL_LEAVE_ERR_MSG); if (cmdPtr == NULL) { return; } flags &= (TCL_TRACE_RENAME | TCL_TRACE_DELETE | TCL_TRACE_ANY_EXEC); for (tracePtr = cmdPtr->tracePtr, prevPtr = NULL; ; prevPtr = tracePtr, tracePtr = tracePtr->nextPtr) { if (tracePtr == NULL) { return; } if ((tracePtr->traceProc == proc) && ((tracePtr->flags & (TCL_TRACE_RENAME | TCL_TRACE_DELETE | TCL_TRACE_ANY_EXEC)) == flags) && (tracePtr->clientData == clientData)) { if (tracePtr->flags & TCL_TRACE_ANY_EXEC) { hasExecTraces = 1; } break; } } /* * The code below makes it possible to delete traces while traces * are active: it makes sure that the deleted trace won't be * processed by CallCommandTraces. */ for (activePtr = iPtr->activeCmdTracePtr; activePtr != NULL; activePtr = activePtr->nextPtr) { if (activePtr->nextTracePtr == tracePtr) { if (activePtr->reverseScan) { activePtr->nextTracePtr = prevPtr; } else { activePtr->nextTracePtr = tracePtr->nextPtr; } } } if (prevPtr == NULL) { cmdPtr->tracePtr = tracePtr->nextPtr; } else { prevPtr->nextPtr = tracePtr->nextPtr; } tracePtr->flags = 0; if ((--tracePtr->refCount) <= 0) { ckfree((char*)tracePtr); } if (hasExecTraces) { for (tracePtr = cmdPtr->tracePtr, prevPtr = NULL; tracePtr != NULL ; prevPtr = tracePtr, tracePtr = tracePtr->nextPtr) { if (tracePtr->flags & TCL_TRACE_ANY_EXEC) { return; } } /* * None of the remaining traces on this command are execution * traces. We therefore remove this flag: */ cmdPtr->flags &= ~CMD_HAS_EXEC_TRACES; /* * Bug 3484621: No more execution trace means we can compile * the command again. If we will, invalidate bytecode. */ if (cmdPtr->compileProc != NULL) { ((Interp *)interp)->compileEpoch++; } } } /* *---------------------------------------------------------------------- * * TraceCommandProc -- * * This procedure is called to handle command changes that have * been traced using the "trace" command, when using the * 'rename' or 'delete' options. * * Results: * None. * * Side effects: * Depends on the command associated with the trace. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static void TraceCommandProc(clientData, interp, oldName, newName, flags) ClientData clientData; /* Information about the command trace. */ Tcl_Interp *interp; /* Interpreter containing command. */ CONST char *oldName; /* Name of command being changed. */ CONST char *newName; /* New name of command. Empty string * or NULL means command is being deleted * (renamed to ""). */ int flags; /* OR-ed bits giving operation and other * information. */ { Interp *iPtr = (Interp *) interp; int stateCode; Tcl_SavedResult state; TraceCommandInfo *tcmdPtr = (TraceCommandInfo *) clientData; int code; Tcl_DString cmd; tcmdPtr->refCount++; if ((tcmdPtr->flags & flags) && !Tcl_InterpDeleted(interp)) { /* * Generate a command to execute by appending list elements * for the old and new command name and the operation. */ Tcl_DStringInit(&cmd); Tcl_DStringAppend(&cmd, tcmdPtr->command, (int) tcmdPtr->length); Tcl_DStringAppendElement(&cmd, oldName); Tcl_DStringAppendElement(&cmd, (newName ? newName : "")); if (flags & TCL_TRACE_RENAME) { Tcl_DStringAppend(&cmd, " rename", 7); } else if (flags & TCL_TRACE_DELETE) { Tcl_DStringAppend(&cmd, " delete", 7); } /* * Execute the command. Save the interp's result used for the * command, including the value of iPtr->returnCode which may be * modified when Tcl_Eval is invoked. We discard any object * result the command returns. * * Add the TCL_TRACE_DESTROYED flag to tcmdPtr to indicate to * other areas that this will be destroyed by us, otherwise a * double-free might occur depending on what the eval does. */ Tcl_SaveResult(interp, &state); stateCode = iPtr->returnCode; if (flags & TCL_TRACE_DESTROYED) { tcmdPtr->flags |= TCL_TRACE_DESTROYED; } code = Tcl_EvalEx(interp, Tcl_DStringValue(&cmd), Tcl_DStringLength(&cmd), 0); if (code != TCL_OK) { /* We ignore errors in these traced commands */ } Tcl_RestoreResult(interp, &state); iPtr->returnCode = stateCode; Tcl_DStringFree(&cmd); } /* * We delete when the trace was destroyed or if this is a delete trace, * because command deletes are unconditional, so the trace must go away. */ if (flags & (TCL_TRACE_DESTROYED | TCL_TRACE_DELETE)) { int untraceFlags = tcmdPtr->flags; if (tcmdPtr->stepTrace != NULL) { Tcl_DeleteTrace(interp, tcmdPtr->stepTrace); tcmdPtr->stepTrace = NULL; if (tcmdPtr->startCmd != NULL) { ckfree((char *)tcmdPtr->startCmd); } } if (tcmdPtr->flags & TCL_TRACE_EXEC_IN_PROGRESS) { /* Postpone deletion, until exec trace returns */ tcmdPtr->flags = 0; } /* * We need to construct the same flags for Tcl_UntraceCommand * as were passed to Tcl_TraceCommand. Reproduce the processing * of [trace add execution/command]. Be careful to keep this * code in sync with that. */ if (untraceFlags & TCL_TRACE_ANY_EXEC) { untraceFlags |= TCL_TRACE_DELETE; if (untraceFlags & (TCL_TRACE_ENTER_DURING_EXEC | TCL_TRACE_LEAVE_DURING_EXEC)) { untraceFlags |= (TCL_TRACE_ENTER_EXEC | TCL_TRACE_LEAVE_EXEC); } } else if (untraceFlags & TCL_TRACE_RENAME) { untraceFlags |= TCL_TRACE_DELETE; } /* * Remove the trace since TCL_TRACE_DESTROYED tells us to, or the * command we're tracing has just gone away. Then decrement the * clientData refCount that was set up by trace creation. * * Note that we save the (return) state of the interpreter to prevent * bizarre error messages. */ Tcl_SaveResult(interp, &state); stateCode = iPtr->returnCode; Tcl_UntraceCommand(interp, oldName, untraceFlags, TraceCommandProc, clientData); Tcl_RestoreResult(interp, &state); iPtr->returnCode = stateCode; tcmdPtr->refCount--; } tcmdPtr->refCount--; if (tcmdPtr->refCount < 0) { Tcl_Panic("TraceCommandProc: negative TraceCommandInfo refCount"); } if (tcmdPtr->refCount == 0) { ckfree((char*)tcmdPtr); } return; } /* *---------------------------------------------------------------------- * * TclCheckExecutionTraces -- * * Checks on all current command execution traces, and invokes * procedures which have been registered. This procedure can be * used by other code which performs execution to unify the * tracing system, so that execution traces will function for that * other code. * * For instance extensions like [incr Tcl] which use their * own execution technique can make use of Tcl's tracing. * * This procedure is called by 'TclEvalObjvInternal' * * Results: * The return value is a standard Tcl completion code such as * TCL_OK or TCL_ERROR, etc. * * Side effects: * Those side effects made by any trace procedures called. * *---------------------------------------------------------------------- */ int TclCheckExecutionTraces(interp, command, numChars, cmdPtr, code, traceFlags, objc, objv) Tcl_Interp *interp; /* The current interpreter. */ CONST char *command; /* Pointer to beginning of the current * command string. */ int numChars; /* The number of characters in 'command' * which are part of the command string. */ Command *cmdPtr; /* Points to command's Command struct. */ int code; /* The current result code. */ int traceFlags; /* Current tracing situation. */ int objc; /* Number of arguments for the command. */ Tcl_Obj *CONST objv[]; /* Pointers to Tcl_Obj of each argument. */ { Interp *iPtr = (Interp *) interp; CommandTrace *tracePtr, *lastTracePtr; ActiveCommandTrace active; int curLevel; int traceCode = TCL_OK; TraceCommandInfo* tcmdPtr; if (command == NULL || cmdPtr->tracePtr == NULL) { return traceCode; } curLevel = ((iPtr->varFramePtr == NULL) ? 0 : iPtr->varFramePtr->level); active.nextPtr = iPtr->activeCmdTracePtr; iPtr->activeCmdTracePtr = &active; active.cmdPtr = cmdPtr; lastTracePtr = NULL; for (tracePtr = cmdPtr->tracePtr; (traceCode == TCL_OK) && (tracePtr != NULL); tracePtr = active.nextTracePtr) { if (traceFlags & TCL_TRACE_LEAVE_EXEC) { /* execute the trace command in order of creation for "leave" */ active.reverseScan = 1; active.nextTracePtr = NULL; tracePtr = cmdPtr->tracePtr; while (tracePtr->nextPtr != lastTracePtr) { active.nextTracePtr = tracePtr; tracePtr = tracePtr->nextPtr; } } else { active.reverseScan = 0; active.nextTracePtr = tracePtr->nextPtr; } if (tracePtr->traceProc == TraceCommandProc) { tcmdPtr = (TraceCommandInfo*)tracePtr->clientData; if (tcmdPtr->flags != 0) { tcmdPtr->curFlags = traceFlags | TCL_TRACE_EXEC_DIRECT; tcmdPtr->curCode = code; tcmdPtr->refCount++; traceCode = TraceExecutionProc((ClientData)tcmdPtr, interp, curLevel, command, (Tcl_Command)cmdPtr, objc, objv); tcmdPtr->refCount--; if (tcmdPtr->refCount < 0) { Tcl_Panic("TclCheckExecutionTraces: negative TraceCommandInfo refCount"); } if (tcmdPtr->refCount == 0) { ckfree((char*)tcmdPtr); } } } if (active.nextTracePtr) { lastTracePtr = active.nextTracePtr->nextPtr; } } iPtr->activeCmdTracePtr = active.nextPtr; return(traceCode); } /* *---------------------------------------------------------------------- * * TclCheckInterpTraces -- * * Checks on all current traces, and invokes procedures which * have been registered. This procedure can be used by other * code which performs execution to unify the tracing system. * For instance extensions like [incr Tcl] which use their * own execution technique can make use of Tcl's tracing. * * This procedure is called by 'TclEvalObjvInternal' * * Results: * The return value is a standard Tcl completion code such as * TCL_OK or TCL_ERROR, etc. * * Side effects: * Those side effects made by any trace procedures called. * *---------------------------------------------------------------------- */ int TclCheckInterpTraces(interp, command, numChars, cmdPtr, code, traceFlags, objc, objv) Tcl_Interp *interp; /* The current interpreter. */ CONST char *command; /* Pointer to beginning of the current * command string. */ int numChars; /* The number of characters in 'command' * which are part of the command string. */ Command *cmdPtr; /* Points to command's Command struct. */ int code; /* The current result code. */ int traceFlags; /* Current tracing situation. */ int objc; /* Number of arguments for the command. */ Tcl_Obj *CONST objv[]; /* Pointers to Tcl_Obj of each argument. */ { Interp *iPtr = (Interp *) interp; Trace *tracePtr, *lastTracePtr; ActiveInterpTrace active; int curLevel; int traceCode = TCL_OK; if (command == NULL || iPtr->tracePtr == NULL || (iPtr->flags & INTERP_TRACE_IN_PROGRESS)) { return(traceCode); } curLevel = iPtr->numLevels; active.nextPtr = iPtr->activeInterpTracePtr; iPtr->activeInterpTracePtr = &active; lastTracePtr = NULL; for ( tracePtr = iPtr->tracePtr; (traceCode == TCL_OK) && (tracePtr != NULL); tracePtr = active.nextTracePtr) { if (traceFlags & TCL_TRACE_ENTER_EXEC) { /* * Execute the trace command in reverse order of creation * for "enterstep" operation. The order is changed for * "enterstep" instead of for "leavestep" as was done in * TclCheckExecutionTraces because for step traces, * Tcl_CreateObjTrace creates one more linked list of traces * which results in one more reversal of trace invocation. */ active.reverseScan = 1; active.nextTracePtr = NULL; tracePtr = iPtr->tracePtr; while (tracePtr->nextPtr != lastTracePtr) { active.nextTracePtr = tracePtr; tracePtr = tracePtr->nextPtr; } if (active.nextTracePtr) { lastTracePtr = active.nextTracePtr->nextPtr; } } else { active.reverseScan = 0; active.nextTracePtr = tracePtr->nextPtr; } if (tracePtr->level > 0 && curLevel > tracePtr->level) { continue; } if (!(tracePtr->flags & TCL_TRACE_EXEC_IN_PROGRESS)) { /* * The proc invoked might delete the traced command which * which might try to free tracePtr. We want to use tracePtr * until the end of this if section, so we use * Tcl_Preserve() and Tcl_Release() to be sure it is not * freed while we still need it. */ Tcl_Preserve((ClientData) tracePtr); tracePtr->flags |= TCL_TRACE_EXEC_IN_PROGRESS; if (tracePtr->flags & (TCL_TRACE_ENTER_EXEC | TCL_TRACE_LEAVE_EXEC)) { /* New style trace */ if (tracePtr->flags & traceFlags) { if (tracePtr->proc == TraceExecutionProc) { TraceCommandInfo *tcmdPtr = (TraceCommandInfo *) tracePtr->clientData; tcmdPtr->curFlags = traceFlags; tcmdPtr->curCode = code; } traceCode = (tracePtr->proc)(tracePtr->clientData, interp, curLevel, command, (Tcl_Command)cmdPtr, objc, objv); } } else { /* Old-style trace */ if (traceFlags & TCL_TRACE_ENTER_EXEC) { /* * Old-style interpreter-wide traces only trigger * before the command is executed. */ traceCode = CallTraceProcedure(interp, tracePtr, cmdPtr, command, numChars, objc, objv); } } tracePtr->flags &= ~TCL_TRACE_EXEC_IN_PROGRESS; Tcl_Release((ClientData) tracePtr); } } iPtr->activeInterpTracePtr = active.nextPtr; return(traceCode); } /* *---------------------------------------------------------------------- * * CallTraceProcedure -- * * Invokes a trace procedure registered with an interpreter. These * procedures trace command execution. Currently this trace procedure * is called with the address of the string-based Tcl_CmdProc for the * command, not the Tcl_ObjCmdProc. * * Results: * None. * * Side effects: * Those side effects made by the trace procedure. * *---------------------------------------------------------------------- */ static int CallTraceProcedure(interp, tracePtr, cmdPtr, command, numChars, objc, objv) Tcl_Interp *interp; /* The current interpreter. */ register Trace *tracePtr; /* Describes the trace procedure to call. */ Command *cmdPtr; /* Points to command's Command struct. */ CONST char *command; /* Points to the first character of the * command's source before substitutions. */ int numChars; /* The number of characters in the * command's source. */ register int objc; /* Number of arguments for the command. */ Tcl_Obj *CONST objv[]; /* Pointers to Tcl_Obj of each argument. */ { Interp *iPtr = (Interp *) interp; char *commandCopy; int traceCode; /* * Copy the command characters into a new string. */ commandCopy = (char *) ckalloc((unsigned) (numChars + 1)); memcpy((VOID *) commandCopy, (VOID *) command, (size_t) numChars); commandCopy[numChars] = '\0'; /* * Call the trace procedure then free allocated storage. */ traceCode = (tracePtr->proc)( tracePtr->clientData, (Tcl_Interp*) iPtr, iPtr->numLevels, commandCopy, (Tcl_Command) cmdPtr, objc, objv ); ckfree((char *) commandCopy); return(traceCode); } /* *---------------------------------------------------------------------- * * CommandObjTraceDeleted -- * * Ensure the trace is correctly deleted by decrementing its * refCount and only deleting if no other references exist. * * Results: * None. * * Side effects: * May release memory. * *---------------------------------------------------------------------- */ static void CommandObjTraceDeleted(ClientData clientData) { TraceCommandInfo* tcmdPtr = (TraceCommandInfo*)clientData; tcmdPtr->refCount--; if (tcmdPtr->refCount < 0) { Tcl_Panic("CommandObjTraceDeleted: negative TraceCommandInfo refCount"); } if (tcmdPtr->refCount == 0) { ckfree((char*)tcmdPtr); } } /* *---------------------------------------------------------------------- * * TraceExecutionProc -- * * This procedure is invoked whenever code relevant to a * 'trace execution' command is executed. It is called in one * of two ways in Tcl's core: * * (i) by the TclCheckExecutionTraces, when an execution trace * has been triggered. * (ii) by TclCheckInterpTraces, when a prior execution trace has * created a trace of the internals of a procedure, passing in * this procedure as the one to be called. * * Results: * The return value is a standard Tcl completion code such as * TCL_OK or TCL_ERROR, etc. * * Side effects: * May invoke an arbitrary Tcl procedure, and may create or * delete an interpreter-wide trace. * *---------------------------------------------------------------------- */ static int TraceExecutionProc(ClientData clientData, Tcl_Interp *interp, int level, CONST char* command, Tcl_Command cmdInfo, int objc, struct Tcl_Obj *CONST objv[]) { int call = 0; Interp *iPtr = (Interp *) interp; TraceCommandInfo* tcmdPtr = (TraceCommandInfo*)clientData; int flags = tcmdPtr->curFlags; int code = tcmdPtr->curCode; int traceCode = TCL_OK; if (tcmdPtr->flags & TCL_TRACE_EXEC_IN_PROGRESS) { /* * Inside any kind of execution trace callback, we do * not allow any further execution trace callbacks to * be called for the same trace. */ return traceCode; } if (!Tcl_InterpDeleted(interp)) { /* * Check whether the current call is going to eval arbitrary * Tcl code with a generated trace, or whether we are only * going to setup interpreter-wide traces to implement the * 'step' traces. This latter situation can happen if * we create a command trace without either before or after * operations, but with either of the step operations. */ if (flags & TCL_TRACE_EXEC_DIRECT) { call = flags & tcmdPtr->flags & (TCL_TRACE_ENTER_EXEC | TCL_TRACE_LEAVE_EXEC); } else { call = 1; } /* * First, if we have returned back to the level at which we * created an interpreter trace for enterstep and/or leavestep * execution traces, we remove it here. */ if (flags & TCL_TRACE_LEAVE_EXEC) { if ((tcmdPtr->stepTrace != NULL) && (level == tcmdPtr->startLevel) && (strcmp(command, tcmdPtr->startCmd) == 0)) { Tcl_DeleteTrace(interp, tcmdPtr->stepTrace); tcmdPtr->stepTrace = NULL; if (tcmdPtr->startCmd != NULL) { ckfree((char *)tcmdPtr->startCmd); } } } /* * Second, create the tcl callback, if required. */ if (call) { Tcl_SavedResult state; int stateCode, i, saveInterpFlags; Tcl_DString cmd; Tcl_DString sub; Tcl_DStringInit(&cmd); Tcl_DStringAppend(&cmd, tcmdPtr->command, (int)tcmdPtr->length); /* Append command with arguments */ Tcl_DStringInit(&sub); for (i = 0; i < objc; i++) { char* str; int len; str = Tcl_GetStringFromObj(objv[i],&len); Tcl_DStringAppendElement(&sub, str); } Tcl_DStringAppendElement(&cmd, Tcl_DStringValue(&sub)); Tcl_DStringFree(&sub); if (flags & TCL_TRACE_ENTER_EXEC) { /* Append trace operation */ if (flags & TCL_TRACE_EXEC_DIRECT) { Tcl_DStringAppendElement(&cmd, "enter"); } else { Tcl_DStringAppendElement(&cmd, "enterstep"); } } else if (flags & TCL_TRACE_LEAVE_EXEC) { Tcl_Obj* resultCode; char* resultCodeStr; /* Append result code */ resultCode = Tcl_NewIntObj(code); resultCodeStr = Tcl_GetString(resultCode); Tcl_DStringAppendElement(&cmd, resultCodeStr); Tcl_DecrRefCount(resultCode); /* Append result string */ Tcl_DStringAppendElement(&cmd, Tcl_GetStringResult(interp)); /* Append trace operation */ if (flags & TCL_TRACE_EXEC_DIRECT) { Tcl_DStringAppendElement(&cmd, "leave"); } else { Tcl_DStringAppendElement(&cmd, "leavestep"); } } else { panic("TraceExecutionProc: bad flag combination"); } /* * Execute the command. Save the interp's result used for * the command, including the value of iPtr->returnCode which * may be modified when Tcl_Eval is invoked. We discard any * object result the command returns. */ Tcl_SaveResult(interp, &state); stateCode = iPtr->returnCode; saveInterpFlags = iPtr->flags; iPtr->flags |= INTERP_TRACE_IN_PROGRESS; tcmdPtr->flags |= TCL_TRACE_EXEC_IN_PROGRESS; tcmdPtr->refCount++; /* * This line can have quite arbitrary side-effects, * including deleting the trace, the command being * traced, or even the interpreter. */ traceCode = Tcl_Eval(interp, Tcl_DStringValue(&cmd)); tcmdPtr->flags &= ~TCL_TRACE_EXEC_IN_PROGRESS; /* * Restore the interp tracing flag to prevent cmd traces * from affecting interp traces */ iPtr->flags = saveInterpFlags;; if (tcmdPtr->flags == 0) { flags |= TCL_TRACE_DESTROYED; } if (traceCode == TCL_OK) { /* Restore result if trace execution was successful */ Tcl_RestoreResult(interp, &state); iPtr->returnCode = stateCode; } else { Tcl_DiscardResult(&state); } Tcl_DStringFree(&cmd); } /* * Third, if there are any step execution traces for this proc, * we register an interpreter trace to invoke enterstep and/or * leavestep traces. * We also need to save the current stack level and the proc * string in startLevel and startCmd so that we can delete this * interpreter trace when it reaches the end of this proc. */ if ((flags & TCL_TRACE_ENTER_EXEC) && (tcmdPtr->stepTrace == NULL) && (tcmdPtr->flags & (TCL_TRACE_ENTER_DURING_EXEC | TCL_TRACE_LEAVE_DURING_EXEC))) { tcmdPtr->startLevel = level; tcmdPtr->startCmd = (char *) ckalloc((unsigned) (strlen(command) + 1)); strcpy(tcmdPtr->startCmd, command); tcmdPtr->refCount++; tcmdPtr->stepTrace = Tcl_CreateObjTrace(interp, 0, (tcmdPtr->flags & TCL_TRACE_ANY_EXEC) >> 2, TraceExecutionProc, (ClientData)tcmdPtr, CommandObjTraceDeleted); } } if (flags & TCL_TRACE_DESTROYED) { if (tcmdPtr->stepTrace != NULL) { Tcl_DeleteTrace(interp, tcmdPtr->stepTrace); tcmdPtr->stepTrace = NULL; if (tcmdPtr->startCmd != NULL) { ckfree((char *)tcmdPtr->startCmd); } } } if (call) { tcmdPtr->refCount--; if (tcmdPtr->refCount < 0) { Tcl_Panic("TraceExecutionProc: negative TraceCommandInfo refCount"); } if (tcmdPtr->refCount == 0) { ckfree((char*)tcmdPtr); } } return traceCode; } /* *---------------------------------------------------------------------- * * TraceVarProc -- * * This procedure is called to handle variable accesses that have * been traced using the "trace" command. * * Results: * Normally returns NULL. If the trace command returns an error, * then this procedure returns an error string. * * Side effects: * Depends on the command associated with the trace. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static char * TraceVarProc(clientData, interp, name1, name2, flags) ClientData clientData; /* Information about the variable trace. */ Tcl_Interp *interp; /* Interpreter containing variable. */ CONST char *name1; /* Name of variable or array. */ CONST char *name2; /* Name of element within array; NULL means * scalar variable is being referenced. */ int flags; /* OR-ed bits giving operation and other * information. */ { Tcl_SavedResult state; TraceVarInfo *tvarPtr = (TraceVarInfo *) clientData; char *result; int code, destroy = 0; Tcl_DString cmd; /* * We might call Tcl_Eval() below, and that might evaluate [trace * vdelete] which might try to free tvarPtr. However we do not * need to protect anything here; it's done by our caller because * the TraceVarInfo is really part of a CompoundVarTrace. [Bug 1348775] */ result = NULL; if ((tvarPtr->flags & flags) && !Tcl_InterpDeleted(interp)) { if (tvarPtr->length != (size_t) 0) { /* * Generate a command to execute by appending list elements * for the two variable names and the operation. */ Tcl_DStringInit(&cmd); Tcl_DStringAppend(&cmd, tvarPtr->command, (int) tvarPtr->length); Tcl_DStringAppendElement(&cmd, name1); Tcl_DStringAppendElement(&cmd, (name2 ? name2 : "")); #ifndef TCL_REMOVE_OBSOLETE_TRACES if (tvarPtr->flags & TCL_TRACE_OLD_STYLE) { if (flags & TCL_TRACE_ARRAY) { Tcl_DStringAppend(&cmd, " a", 2); } else if (flags & TCL_TRACE_READS) { Tcl_DStringAppend(&cmd, " r", 2); } else if (flags & TCL_TRACE_WRITES) { Tcl_DStringAppend(&cmd, " w", 2); } else if (flags & TCL_TRACE_UNSETS) { Tcl_DStringAppend(&cmd, " u", 2); } } else { #endif if (flags & TCL_TRACE_ARRAY) { Tcl_DStringAppend(&cmd, " array", 6); } else if (flags & TCL_TRACE_READS) { Tcl_DStringAppend(&cmd, " read", 5); } else if (flags & TCL_TRACE_WRITES) { Tcl_DStringAppend(&cmd, " write", 6); } else if (flags & TCL_TRACE_UNSETS) { Tcl_DStringAppend(&cmd, " unset", 6); } #ifndef TCL_REMOVE_OBSOLETE_TRACES } #endif /* * Execute the command. Save the interp's result used for * the command. We discard any object result the command returns. * * Add the TCL_TRACE_DESTROYED flag to tvarPtr to indicate to * other areas that this will be destroyed by us, otherwise a * double-free might occur depending on what the eval does. */ Tcl_SaveResult(interp, &state); if ((flags & TCL_TRACE_DESTROYED) && !(tvarPtr->flags & TCL_TRACE_DESTROYED)) { destroy = 1; tvarPtr->flags |= TCL_TRACE_DESTROYED; } code = Tcl_EvalEx(interp, Tcl_DStringValue(&cmd), Tcl_DStringLength(&cmd), 0); if (code != TCL_OK) { /* copy error msg to result */ register Tcl_Obj *errMsgObj = Tcl_GetObjResult(interp); Tcl_IncrRefCount(errMsgObj); result = (char *) errMsgObj; } Tcl_RestoreResult(interp, &state); Tcl_DStringFree(&cmd); } } if (destroy) { if (result != NULL) { register Tcl_Obj *errMsgObj = (Tcl_Obj *) result; Tcl_DecrRefCount(errMsgObj); result = NULL; } } return result; } /* *---------------------------------------------------------------------- * * Tcl_WhileObjCmd -- * * This procedure is invoked to process the "while" Tcl command. * See the user documentation for details on what it does. * * With the bytecode compiler, this procedure is only called when * a command name is computed at runtime, and is "while" or the name * to which "while" was renamed: e.g., "set z while; $z {$i<100} {}" * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_WhileObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int result, value; #ifdef TCL_TIP280 Interp* iPtr = (Interp*) interp; #endif if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "test command"); return TCL_ERROR; } while (1) { result = Tcl_ExprBooleanObj(interp, objv[1], &value); if (result != TCL_OK) { return result; } if (!value) { break; } #ifndef TCL_TIP280 result = Tcl_EvalObjEx(interp, objv[2], 0); #else /* TIP #280. */ result = TclEvalObjEx(interp, objv[2], 0, iPtr->cmdFramePtr,2); #endif if ((result != TCL_OK) && (result != TCL_CONTINUE)) { if (result == TCL_ERROR) { char msg[32 + TCL_INTEGER_SPACE]; sprintf(msg, "\n (\"while\" body line %d)", interp->errorLine); Tcl_AddErrorInfo(interp, msg); } break; } } if (result == TCL_BREAK) { result = TCL_OK; } if (result == TCL_OK) { Tcl_ResetResult(interp); } return result; } #ifdef TCL_TIP280 static void ListLines(listObj, line, n, lines, elems) Tcl_Obj* listObj; /* Pointer to obj holding a string with list structure. * Assumed to be valid. Assumed to contain n elements. */ int line; /* line the list as a whole starts on */ int n; /* #elements in lines */ int* lines; /* Array of line numbers, to fill */ Tcl_Obj* const* elems; /* The list elems as Tcl_Obj*, in need of derived * continuation data */ { int i; CONST char* listStr = Tcl_GetString (listObj); CONST char* listHead = listStr; int length = strlen( listStr); CONST char* element = NULL; CONST char* next = NULL; ContLineLoc* clLocPtr = TclContinuationsGet(listObj); int* clNext = (clLocPtr ? &clLocPtr->loc[0] : NULL); for (i = 0; i < n; i++) { TclFindElement(NULL, listStr, length, &element, &next, NULL, NULL); TclAdvanceLines (&line, listStr, element); /* Leading whitespace */ TclAdvanceContinuations (&line, &clNext, element - listHead); if (clNext) { TclContinuationsEnterDerived (elems[i], element - listHead, clNext); } lines [i] = line; length -= (next - listStr); TclAdvanceLines (&line, element, next); /* Element */ listStr = next; if (*element == 0) { /* ASSERT i == n */ break; } } } #endif /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ tcl8.4.20/generic/tclThreadAlloc.c0000755003604700454610000005710711737050674015401 0ustar dgp771div/* * tclThreadAlloc.c -- * * This is a very fast storage allocator for used with threads (designed * avoid lock contention). The basic strategy is to allocate memory in * fixed size blocks from block caches. * * The Initial Developer of the Original Code is America Online, Inc. * Portions created by AOL are Copyright (C) 1999 America Online, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #if defined(TCL_THREADS) && defined(USE_THREAD_ALLOC) && !defined(TCL_MEM_DEBUG) #ifdef WIN32 #include "tclWinInt.h" #else extern Tcl_Mutex *TclpNewAllocMutex(void); extern void *TclpGetAllocCache(void); extern void TclpSetAllocCache(void *); #endif /* * If range checking is enabled, an additional byte will be allocated * to store the magic number at the end of the requested memory. */ #ifndef RCHECK #ifdef NDEBUG #define RCHECK 0 #else #define RCHECK 1 #endif #endif /* * The following define the number of Tcl_Obj's to allocate/move * at a time and the high water mark to prune a per-thread cache. * On a 32 bit system, sizeof(Tcl_Obj) = 24 so 800 * 24 = ~16k. * */ #define NOBJALLOC 800 #define NOBJHIGH 1200 /* * Alignment for allocated memory. */ #if defined(__APPLE__) #define ALLOCALIGN 16 #else #define ALLOCALIGN 8 #endif /* * The following union stores accounting information for * each block including two small magic numbers and * a bucket number when in use or a next pointer when * free. The original requested size (not including * the Block overhead) is also maintained. */ typedef union Block { struct { union { union Block *next; /* Next in free list. */ struct { unsigned char magic1; /* First magic number. */ unsigned char bucket; /* Bucket block allocated from. */ unsigned char unused; /* Padding. */ unsigned char magic2; /* Second magic number. */ } s; } u; size_t reqSize; /* Requested allocation size. */ } b; unsigned char padding[ALLOCALIGN]; } Block; #define b_next b.u.next #define b_bucket b.u.s.bucket #define b_magic1 b.u.s.magic1 #define b_magic2 b.u.s.magic2 #define MAGIC 0xef #define b_reqsize b.reqSize /* * The following defines the minimum and and maximum block sizes and the number * of buckets in the bucket cache. */ #define MINALLOC ((sizeof(Block) + 8 + (ALLOCALIGN-1)) & ~(ALLOCALIGN-1)) #define NBUCKETS (11 - (MINALLOC >> 5)) #define MAXALLOC (MINALLOC << (NBUCKETS - 1)) /* * The following structure defines a bucket of blocks with * various accounting and statistics information. */ typedef struct Bucket { Block *firstPtr; long nfree; long nget; long nput; long nwait; long nlock; long nrequest; } Bucket; /* * The following structure defines a cache of buckets and objs. */ typedef struct Cache { struct Cache *nextPtr; Tcl_ThreadId owner; Tcl_Obj *firstObjPtr; int nobjs; int nsysalloc; Bucket buckets[NBUCKETS]; } Cache; /* * The following array specifies various per-bucket * limits and locks. The values are statically initialized * to avoid calculating them repeatedly. */ struct binfo { size_t blocksize; /* Bucket blocksize. */ int maxblocks; /* Max blocks before move to share. */ int nmove; /* Num blocks to move to share. */ Tcl_Mutex *lockPtr; /* Share bucket lock. */ } binfo[NBUCKETS]; /* * Static functions defined in this file. */ static void LockBucket(Cache *cachePtr, int bucket); static void UnlockBucket(Cache *cachePtr, int bucket); static void PutBlocks(Cache *cachePtr, int bucket, int nmove); static int GetBlocks(Cache *cachePtr, int bucket); static Block *Ptr2Block(char *ptr); static char *Block2Ptr(Block *blockPtr, int bucket, unsigned int reqsize); static void MoveObjs(Cache *fromPtr, Cache *toPtr, int nmove); /* * Local variables defined in this file and initialized at * startup. */ static Tcl_Mutex *listLockPtr; static Tcl_Mutex *objLockPtr; static Cache sharedCache; static Cache *sharedPtr = &sharedCache; static Cache *firstCachePtr = &sharedCache; /* *---------------------------------------------------------------------- * * GetCache --- * * Gets per-thread memory cache, allocating it if necessary. * * Results: * Pointer to cache. * * Side effects: * None. * *---------------------------------------------------------------------- */ static Cache * GetCache(void) { Cache *cachePtr; /* * Check for first-time initialization. */ if (listLockPtr == NULL) { Tcl_Mutex *initLockPtr; unsigned int i; initLockPtr = Tcl_GetAllocMutex(); Tcl_MutexLock(initLockPtr); if (listLockPtr == NULL) { listLockPtr = TclpNewAllocMutex(); objLockPtr = TclpNewAllocMutex(); for (i = 0; i < NBUCKETS; ++i) { binfo[i].blocksize = MINALLOC << i; binfo[i].maxblocks = 1 << (NBUCKETS - 1 - i); binfo[i].nmove = i < NBUCKETS-1 ? 1 << (NBUCKETS - 2 - i) : 1; binfo[i].lockPtr = TclpNewAllocMutex(); } } Tcl_MutexUnlock(initLockPtr); } /* * Get this thread's cache, allocating if necessary. */ cachePtr = TclpGetAllocCache(); if (cachePtr == NULL) { cachePtr = calloc(1, sizeof(Cache)); if (cachePtr == NULL) { panic("alloc: could not allocate new cache"); } Tcl_MutexLock(listLockPtr); cachePtr->nextPtr = firstCachePtr; firstCachePtr = cachePtr; Tcl_MutexUnlock(listLockPtr); cachePtr->owner = Tcl_GetCurrentThread(); TclpSetAllocCache(cachePtr); } return cachePtr; } /* *---------------------------------------------------------------------- * * TclFreeAllocCache -- * * Flush and delete a cache, removing from list of caches. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TclFreeAllocCache(void *arg) { Cache *cachePtr = arg; Cache **nextPtrPtr; register unsigned int bucket; /* * Flush blocks. */ for (bucket = 0; bucket < NBUCKETS; ++bucket) { if (cachePtr->buckets[bucket].nfree > 0) { PutBlocks(cachePtr, bucket, cachePtr->buckets[bucket].nfree); } } /* * Flush objs. */ if (cachePtr->nobjs > 0) { Tcl_MutexLock(objLockPtr); MoveObjs(cachePtr, sharedPtr, cachePtr->nobjs); Tcl_MutexUnlock(objLockPtr); } /* * Remove from pool list. */ Tcl_MutexLock(listLockPtr); nextPtrPtr = &firstCachePtr; while (*nextPtrPtr != cachePtr) { nextPtrPtr = &(*nextPtrPtr)->nextPtr; } *nextPtrPtr = cachePtr->nextPtr; cachePtr->nextPtr = NULL; Tcl_MutexUnlock(listLockPtr); free(cachePtr); } /* *---------------------------------------------------------------------- * * TclpAlloc -- * * Allocate memory. * * Results: * Pointer to memory just beyond Block pointer. * * Side effects: * May allocate more blocks for a bucket. * *---------------------------------------------------------------------- */ char * TclpAlloc(unsigned int reqsize) { Cache *cachePtr; Block *blockPtr; register int bucket; size_t size; if (sizeof(int) >= sizeof(size_t)) { /* An unsigned int overflow can also be a size_t overflow */ const size_t zero = 0; const size_t max = ~zero; if (((size_t) reqsize) > max - sizeof(Block) - RCHECK) { /* Requested allocation exceeds memory */ return NULL; } } cachePtr = TclpGetAllocCache(); if (cachePtr == NULL) { cachePtr = GetCache(); } /* * Increment the requested size to include room for * the Block structure. Call malloc() directly if the * required amount is greater than the largest block, * otherwise pop the smallest block large enough, * allocating more blocks if necessary. */ blockPtr = NULL; size = reqsize + sizeof(Block); #if RCHECK ++size; #endif if (size > MAXALLOC) { bucket = NBUCKETS; blockPtr = malloc(size); if (blockPtr != NULL) { cachePtr->nsysalloc += reqsize; } } else { bucket = 0; while (binfo[bucket].blocksize < size) { ++bucket; } if (cachePtr->buckets[bucket].nfree || GetBlocks(cachePtr, bucket)) { blockPtr = cachePtr->buckets[bucket].firstPtr; cachePtr->buckets[bucket].firstPtr = blockPtr->b_next; --cachePtr->buckets[bucket].nfree; ++cachePtr->buckets[bucket].nget; cachePtr->buckets[bucket].nrequest += reqsize; } } if (blockPtr == NULL) { return NULL; } return Block2Ptr(blockPtr, bucket, reqsize); } /* *---------------------------------------------------------------------- * * TclpFree -- * * Return blocks to the thread block cache. * * Results: * None. * * Side effects: * May move blocks to shared cache. * *---------------------------------------------------------------------- */ void TclpFree(char *ptr) { if (ptr != NULL) { Cache *cachePtr = TclpGetAllocCache(); Block *blockPtr; int bucket; if (cachePtr == NULL) { cachePtr = GetCache(); } /* * Get the block back from the user pointer and * call system free directly for large blocks. * Otherwise, push the block back on the bucket and * move blocks to the shared cache if there are now * too many free. */ blockPtr = Ptr2Block(ptr); bucket = blockPtr->b_bucket; if (bucket == NBUCKETS) { cachePtr->nsysalloc -= blockPtr->b_reqsize; free(blockPtr); } else { cachePtr->buckets[bucket].nrequest -= blockPtr->b_reqsize; blockPtr->b_next = cachePtr->buckets[bucket].firstPtr; cachePtr->buckets[bucket].firstPtr = blockPtr; ++cachePtr->buckets[bucket].nfree; ++cachePtr->buckets[bucket].nput; if (cachePtr != sharedPtr && cachePtr->buckets[bucket].nfree > binfo[bucket].maxblocks) { PutBlocks(cachePtr, bucket, binfo[bucket].nmove); } } } } /* *---------------------------------------------------------------------- * * TclpRealloc -- * * Re-allocate memory to a larger or smaller size. * * Results: * Pointer to memory just beyond Block pointer. * * Side effects: * Previous memory, if any, may be freed. * *---------------------------------------------------------------------- */ char * TclpRealloc(char *ptr, unsigned int reqsize) { Cache *cachePtr; Block *blockPtr; void *new; size_t size, min; int bucket; if (ptr == NULL) { return TclpAlloc(reqsize); } if (sizeof(int) >= sizeof(size_t)) { /* An unsigned int overflow can also be a size_t overflow */ const size_t zero = 0; const size_t max = ~zero; if (((size_t) reqsize) > max - sizeof(Block) - RCHECK) { /* Requested allocation exceeds memory */ return NULL; } } cachePtr = TclpGetAllocCache(); if (cachePtr == NULL) { cachePtr = GetCache(); } /* * If the block is not a system block and fits in place, * simply return the existing pointer. Otherwise, if the block * is a system block and the new size would also require a system * block, call realloc() directly. */ blockPtr = Ptr2Block(ptr); size = reqsize + sizeof(Block); #if RCHECK ++size; #endif bucket = blockPtr->b_bucket; if (bucket != NBUCKETS) { if (bucket > 0) { min = binfo[bucket-1].blocksize; } else { min = 0; } if (size > min && size <= binfo[bucket].blocksize) { cachePtr->buckets[bucket].nrequest -= blockPtr->b_reqsize; cachePtr->buckets[bucket].nrequest += reqsize; return Block2Ptr(blockPtr, bucket, reqsize); } } else if (size > MAXALLOC) { cachePtr->nsysalloc -= blockPtr->b_reqsize; cachePtr->nsysalloc += reqsize; blockPtr = realloc(blockPtr, size); if (blockPtr == NULL) { return NULL; } return Block2Ptr(blockPtr, NBUCKETS, reqsize); } /* * Finally, perform an expensive malloc/copy/free. */ new = TclpAlloc(reqsize); if (new != NULL) { if (reqsize > blockPtr->b_reqsize) { reqsize = blockPtr->b_reqsize; } memcpy(new, ptr, reqsize); TclpFree(ptr); } return new; } /* *---------------------------------------------------------------------- * * TclThreadAllocObj -- * * Allocate a Tcl_Obj from the per-thread cache. * * Results: * Pointer to uninitialized Tcl_Obj. * * Side effects: * May move Tcl_Obj's from shared cached or allocate new Tcl_Obj's * if list is empty. * *---------------------------------------------------------------------- */ Tcl_Obj * TclThreadAllocObj(void) { register Cache *cachePtr = TclpGetAllocCache(); register int nmove; register Tcl_Obj *objPtr; Tcl_Obj *newObjsPtr; if (cachePtr == NULL) { cachePtr = GetCache(); } /* * Get this thread's obj list structure and move * or allocate new objs if necessary. */ if (cachePtr->nobjs == 0) { Tcl_MutexLock(objLockPtr); nmove = sharedPtr->nobjs; if (nmove > 0) { if (nmove > NOBJALLOC) { nmove = NOBJALLOC; } MoveObjs(sharedPtr, cachePtr, nmove); } Tcl_MutexUnlock(objLockPtr); if (cachePtr->nobjs == 0) { cachePtr->nobjs = nmove = NOBJALLOC; newObjsPtr = malloc(sizeof(Tcl_Obj) * nmove); if (newObjsPtr == NULL) { panic("alloc: could not allocate %d new objects", nmove); } while (--nmove >= 0) { objPtr = &newObjsPtr[nmove]; objPtr->internalRep.otherValuePtr = cachePtr->firstObjPtr; cachePtr->firstObjPtr = objPtr; } } } /* * Pop the first object. */ objPtr = cachePtr->firstObjPtr; cachePtr->firstObjPtr = objPtr->internalRep.otherValuePtr; --cachePtr->nobjs; return objPtr; } /* *---------------------------------------------------------------------- * * TclThreadFreeObj -- * * Return a free Tcl_Obj to the per-thread cache. * * Results: * None. * * Side effects: * May move free Tcl_Obj's to shared list upon hitting high * water mark. * *---------------------------------------------------------------------- */ void TclThreadFreeObj(Tcl_Obj *objPtr) { Cache *cachePtr = TclpGetAllocCache(); if (cachePtr == NULL) { cachePtr = GetCache(); } /* * Get this thread's list and push on the free Tcl_Obj. */ objPtr->internalRep.otherValuePtr = cachePtr->firstObjPtr; cachePtr->firstObjPtr = objPtr; ++cachePtr->nobjs; /* * If the number of free objects has exceeded the high * water mark, move some blocks to the shared list. */ if (cachePtr->nobjs > NOBJHIGH) { Tcl_MutexLock(objLockPtr); MoveObjs(cachePtr, sharedPtr, NOBJALLOC); Tcl_MutexUnlock(objLockPtr); } } /* *---------------------------------------------------------------------- * * Tcl_GetMemoryInfo -- * * Return a list-of-lists of memory stats. * * Results: * None. * * Side effects: * List appended to given dstring. * *---------------------------------------------------------------------- */ void Tcl_GetMemoryInfo(Tcl_DString *dsPtr) { Cache *cachePtr; char buf[200]; unsigned int n; Tcl_MutexLock(listLockPtr); cachePtr = firstCachePtr; while (cachePtr != NULL) { Tcl_DStringStartSublist(dsPtr); if (cachePtr == sharedPtr) { Tcl_DStringAppendElement(dsPtr, "shared"); } else { sprintf(buf, "thread%d", (int) cachePtr->owner); Tcl_DStringAppendElement(dsPtr, buf); } for (n = 0; n < NBUCKETS; ++n) { sprintf(buf, "%lu %ld %ld %ld %ld %ld %ld", (unsigned long) binfo[n].blocksize, cachePtr->buckets[n].nfree, cachePtr->buckets[n].nget, cachePtr->buckets[n].nput, cachePtr->buckets[n].nrequest, cachePtr->buckets[n].nlock, cachePtr->buckets[n].nwait); Tcl_DStringAppendElement(dsPtr, buf); } Tcl_DStringEndSublist(dsPtr); cachePtr = cachePtr->nextPtr; } Tcl_MutexUnlock(listLockPtr); } /* *---------------------------------------------------------------------- * * MoveObjs -- * * Move Tcl_Obj's between caches. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void MoveObjs(Cache *fromPtr, Cache *toPtr, int nmove) { register Tcl_Obj *objPtr = fromPtr->firstObjPtr; Tcl_Obj *fromFirstObjPtr = objPtr; toPtr->nobjs += nmove; fromPtr->nobjs -= nmove; /* * Find the last object to be moved; set the next one * (the first one not to be moved) as the first object * in the 'from' cache. */ while (--nmove) { objPtr = objPtr->internalRep.otherValuePtr; } fromPtr->firstObjPtr = objPtr->internalRep.otherValuePtr; /* * Move all objects as a block - they are already linked to * each other, we just have to update the first and last. */ objPtr->internalRep.otherValuePtr = toPtr->firstObjPtr; toPtr->firstObjPtr = fromFirstObjPtr; } /* *---------------------------------------------------------------------- * * Block2Ptr, Ptr2Block -- * * Convert between internal blocks and user pointers. * * Results: * User pointer or internal block. * * Side effects: * Invalid blocks will abort the server. * *---------------------------------------------------------------------- */ static char * Block2Ptr(Block *blockPtr, int bucket, unsigned int reqsize) { register void *ptr; blockPtr->b_magic1 = blockPtr->b_magic2 = MAGIC; blockPtr->b_bucket = bucket; blockPtr->b_reqsize = reqsize; ptr = ((void *) (blockPtr + 1)); #if RCHECK ((unsigned char *)(ptr))[reqsize] = MAGIC; #endif return (char *) ptr; } static Block * Ptr2Block(char *ptr) { register Block *blockPtr; blockPtr = (((Block *) ptr) - 1); if (blockPtr->b_magic1 != MAGIC #if RCHECK || ((unsigned char *) ptr)[blockPtr->b_reqsize] != MAGIC #endif || blockPtr->b_magic2 != MAGIC) { panic("alloc: invalid block: %p: %x %x %x\n", blockPtr, blockPtr->b_magic1, blockPtr->b_magic2, ((unsigned char *) ptr)[blockPtr->b_reqsize]); } return blockPtr; } /* *---------------------------------------------------------------------- * * LockBucket, UnlockBucket -- * * Set/unset the lock to access a bucket in the shared cache. * * Results: * None. * * Side effects: * Lock activity and contention are monitored globally and on * a per-cache basis. * *---------------------------------------------------------------------- */ static void LockBucket(Cache *cachePtr, int bucket) { #if 0 if (Tcl_MutexTryLock(binfo[bucket].lockPtr) != TCL_OK) { Tcl_MutexLock(binfo[bucket].lockPtr); ++cachePtr->buckets[bucket].nwait; ++sharedPtr->buckets[bucket].nwait; } #else Tcl_MutexLock(binfo[bucket].lockPtr); #endif ++cachePtr->buckets[bucket].nlock; ++sharedPtr->buckets[bucket].nlock; } static void UnlockBucket(Cache *cachePtr, int bucket) { Tcl_MutexUnlock(binfo[bucket].lockPtr); } /* *---------------------------------------------------------------------- * * PutBlocks -- * * Return unused blocks to the shared cache. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void PutBlocks(Cache *cachePtr, int bucket, int nmove) { register Block *lastPtr, *firstPtr; register int n = nmove; /* * Before acquiring the lock, walk the block list to find * the last block to be moved. */ firstPtr = lastPtr = cachePtr->buckets[bucket].firstPtr; while (--n > 0) { lastPtr = lastPtr->b_next; } cachePtr->buckets[bucket].firstPtr = lastPtr->b_next; cachePtr->buckets[bucket].nfree -= nmove; /* * Aquire the lock and place the list of blocks at the front * of the shared cache bucket. */ LockBucket(cachePtr, bucket); lastPtr->b_next = sharedPtr->buckets[bucket].firstPtr; sharedPtr->buckets[bucket].firstPtr = firstPtr; sharedPtr->buckets[bucket].nfree += nmove; UnlockBucket(cachePtr, bucket); } /* *---------------------------------------------------------------------- * * GetBlocks -- * * Get more blocks for a bucket. * * Results: * 1 if blocks where allocated, 0 otherwise. * * Side effects: * Cache may be filled with available blocks. * *---------------------------------------------------------------------- */ static int GetBlocks(Cache *cachePtr, int bucket) { register Block *blockPtr; register int n; register size_t size; /* * First, atttempt to move blocks from the shared cache. Note * the potentially dirty read of nfree before acquiring the lock * which is a slight performance enhancement. The value is * verified after the lock is actually acquired. */ if (cachePtr != sharedPtr && sharedPtr->buckets[bucket].nfree > 0) { LockBucket(cachePtr, bucket); if (sharedPtr->buckets[bucket].nfree > 0) { /* * Either move the entire list or walk the list to find * the last block to move. */ n = binfo[bucket].nmove; if (n >= sharedPtr->buckets[bucket].nfree) { cachePtr->buckets[bucket].firstPtr = sharedPtr->buckets[bucket].firstPtr; cachePtr->buckets[bucket].nfree = sharedPtr->buckets[bucket].nfree; sharedPtr->buckets[bucket].firstPtr = NULL; sharedPtr->buckets[bucket].nfree = 0; } else { blockPtr = sharedPtr->buckets[bucket].firstPtr; cachePtr->buckets[bucket].firstPtr = blockPtr; sharedPtr->buckets[bucket].nfree -= n; cachePtr->buckets[bucket].nfree = n; while (--n > 0) { blockPtr = blockPtr->b_next; } sharedPtr->buckets[bucket].firstPtr = blockPtr->b_next; blockPtr->b_next = NULL; } } UnlockBucket(cachePtr, bucket); } if (cachePtr->buckets[bucket].nfree == 0) { /* * If no blocks could be moved from shared, first look for a * larger block in this cache to split up. */ blockPtr = NULL; n = NBUCKETS; size = 0; /* lint */ while (--n > bucket) { if (cachePtr->buckets[n].nfree > 0) { size = binfo[n].blocksize; blockPtr = cachePtr->buckets[n].firstPtr; cachePtr->buckets[n].firstPtr = blockPtr->b_next; --cachePtr->buckets[n].nfree; break; } } /* * Otherwise, allocate a big new block directly. */ if (blockPtr == NULL) { size = MAXALLOC; blockPtr = malloc(size); if (blockPtr == NULL) { return 0; } } /* * Split the larger block into smaller blocks for this bucket. */ n = size / binfo[bucket].blocksize; cachePtr->buckets[bucket].nfree = n; cachePtr->buckets[bucket].firstPtr = blockPtr; while (--n > 0) { blockPtr->b_next = (Block *) ((char *) blockPtr + binfo[bucket].blocksize); blockPtr = blockPtr->b_next; } blockPtr->b_next = NULL; } return 1; } /* *---------------------------------------------------------------------- * * TclFinalizeThreadAlloc -- * * This procedure is used to destroy all private resources used in * this file. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TclFinalizeThreadAlloc() { unsigned int i; for (i = 0; i < NBUCKETS; ++i) { TclpFreeAllocMutex(binfo[i].lockPtr); binfo[i].lockPtr = NULL; } TclpFreeAllocMutex(objLockPtr); objLockPtr = NULL; TclpFreeAllocMutex(listLockPtr); listLockPtr = NULL; TclpFreeAllocCache(NULL); } #else /* ! defined(TCL_THREADS) && ! defined(USE_THREAD_ALLOC) */ /* *---------------------------------------------------------------------- * * TclFinalizeThreadAlloc -- * * This procedure is used to destroy all private resources used in * this file. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TclFinalizeThreadAlloc() { Tcl_Panic("TclFinalizeThreadAlloc called when threaded memory allocator not in use."); } #endif /* TCL_THREADS */ tcl8.4.20/generic/tclIOGT.c0000644003604700454610000011604112052456744013746 0ustar dgp771div/* * tclIOGT.c -- * * Implements a generic transformation exposing the underlying API * at the script level. Contributed by Andreas Kupries. * * Copyright (c) 2000 Ajuba Solutions * Copyright (c) 1999-2000 Andreas Kupries (a.kupries@westend.com) * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" #include "tclIO.h" /* * Forward declarations of internal procedures. * First the driver procedures of the transformation. */ static int TransformBlockModeProc _ANSI_ARGS_ (( ClientData instanceData, int mode)); static int TransformCloseProc _ANSI_ARGS_ (( ClientData instanceData, Tcl_Interp* interp)); static int TransformInputProc _ANSI_ARGS_ (( ClientData instanceData, char* buf, int toRead, int* errorCodePtr)); static int TransformOutputProc _ANSI_ARGS_ (( ClientData instanceData, CONST char *buf, int toWrite, int* errorCodePtr)); static int TransformSeekProc _ANSI_ARGS_ (( ClientData instanceData, long offset, int mode, int* errorCodePtr)); static int TransformSetOptionProc _ANSI_ARGS_(( ClientData instanceData, Tcl_Interp *interp, CONST char *optionName, CONST char *value)); static int TransformGetOptionProc _ANSI_ARGS_(( ClientData instanceData, Tcl_Interp *interp, CONST char *optionName, Tcl_DString *dsPtr)); static void TransformWatchProc _ANSI_ARGS_ (( ClientData instanceData, int mask)); static int TransformGetFileHandleProc _ANSI_ARGS_ (( ClientData instanceData, int direction, ClientData* handlePtr)); static int TransformNotifyProc _ANSI_ARGS_ (( ClientData instanceData, int mask)); static Tcl_WideInt TransformWideSeekProc _ANSI_ARGS_ (( ClientData instanceData, Tcl_WideInt offset, int mode, int* errorCodePtr)); /* * Forward declarations of internal procedures. * Secondly the procedures for handling and generating fileeevents. */ static void TransformChannelHandlerTimer _ANSI_ARGS_ (( ClientData clientData)); /* * Forward declarations of internal procedures. * Third, helper procedures encapsulating essential tasks. */ typedef struct TransformChannelData TransformChannelData; static int ExecuteCallback _ANSI_ARGS_ (( TransformChannelData* ctrl, Tcl_Interp* interp, unsigned char* op, unsigned char* buf, int bufLen, int transmit, int preserve)); /* * Action codes to give to 'ExecuteCallback' (argument 'transmit') * confering to the procedure what to do with the result of the script * it calls. */ #define TRANSMIT_DONT (0) /* No transfer to do */ #define TRANSMIT_DOWN (1) /* Transfer to the underlying channel */ #define TRANSMIT_SELF (2) /* Transfer into our channel. */ #define TRANSMIT_IBUF (3) /* Transfer to internal input buffer */ #define TRANSMIT_NUM (4) /* Transfer number to 'maxRead' */ /* * Codes for 'preserve' of 'ExecuteCallback' */ #define P_PRESERVE (1) #define P_NO_PRESERVE (0) /* * Strings for the action codes delivered to the script implementing * a transformation. Argument 'op' of 'ExecuteCallback'. */ #define A_CREATE_WRITE (UCHARP ("create/write")) #define A_DELETE_WRITE (UCHARP ("delete/write")) #define A_FLUSH_WRITE (UCHARP ("flush/write")) #define A_WRITE (UCHARP ("write")) #define A_CREATE_READ (UCHARP ("create/read")) #define A_DELETE_READ (UCHARP ("delete/read")) #define A_FLUSH_READ (UCHARP ("flush/read")) #define A_READ (UCHARP ("read")) #define A_QUERY_MAXREAD (UCHARP ("query/maxRead")) #define A_CLEAR_READ (UCHARP ("clear/read")) /* * Management of a simple buffer. */ typedef struct ResultBuffer ResultBuffer; static void ResultClear _ANSI_ARGS_ ((ResultBuffer* r)); static void ResultInit _ANSI_ARGS_ ((ResultBuffer* r)); static int ResultLength _ANSI_ARGS_ ((ResultBuffer* r)); static int ResultCopy _ANSI_ARGS_ ((ResultBuffer* r, unsigned char* buf, int toRead)); static void ResultAdd _ANSI_ARGS_ ((ResultBuffer* r, unsigned char* buf, int toWrite)); /* * This structure describes the channel type structure for tcl based * transformations. */ static Tcl_ChannelType transformChannelType = { "transform", /* Type name. */ TCL_CHANNEL_VERSION_3, TransformCloseProc, /* Close proc. */ TransformInputProc, /* Input proc. */ TransformOutputProc, /* Output proc. */ TransformSeekProc, /* Seek proc. */ TransformSetOptionProc, /* Set option proc. */ TransformGetOptionProc, /* Get option proc. */ TransformWatchProc, /* Initialize notifier. */ TransformGetFileHandleProc, /* Get OS handles out of channel. */ NULL, /* close2proc */ TransformBlockModeProc, /* Set blocking/nonblocking mode.*/ NULL, /* Flush proc. */ TransformNotifyProc, /* Handling of events bubbling up */ TransformWideSeekProc, /* Wide seek proc */ NULL }; /* * Possible values for 'flags' field in control structure, see below. */ #define CHANNEL_ASYNC (1<<0) /* non-blocking mode */ /* * Definition of the structure containing the information about the * internal input buffer. */ struct ResultBuffer { unsigned char* buf; /* Reference to the buffer area */ int allocated; /* Allocated size of the buffer area */ int used; /* Number of bytes in the buffer, <= allocated */ }; /* * Additional bytes to allocate during buffer expansion */ #define INCREMENT (512) /* * Number of milliseconds to wait before firing an event to flush * out information waiting in buffers (fileevent support). */ #define FLUSH_DELAY (5) /* * Convenience macro to make some casts easier to use. */ #define UCHARP(x) ((unsigned char*) (x)) #define NO_INTERP ((Tcl_Interp*) NULL) /* * Definition of a structure used by all transformations generated here to * maintain their local state. */ struct TransformChannelData { /* * General section. Data to integrate the transformation into the channel * system. */ Tcl_Channel self; /* Our own Channel handle */ int readIsFlushed; /* Flag to note wether in.flushProc was called or not */ int flags; /* Currently CHANNEL_ASYNC or zero */ int watchMask; /* Current watch/event/interest mask */ int mode; /* mode of parent channel, OR'ed combination of * TCL_READABLE, TCL_WRITABLE */ Tcl_TimerToken timer; /* Timer for automatic flushing of information * sitting in an internal buffer. Required for full * fileevent support */ /* * Transformation specific data. */ int maxRead; /* Maximum allowed number of bytes to read, as * given to us by the tcl script implementing the * transformation. */ Tcl_Interp* interp; /* Reference to the interpreter which created the * transformation. Used to execute the code * below. */ Tcl_Obj* command; /* Tcl code to execute for a buffer */ ResultBuffer result; /* Internal buffer used to store the result of a * transformation of incoming data. Additionally * serves as buffer of all data not yet consumed by * the reader. */ }; /* *---------------------------------------------------------------------- * * TclChannelTransform -- * * Implements the Tcl "testchannel transform" debugging command. * This is part of the testing environment. This sets up a tcl * script (cmdObjPtr) to be used as a transform on the channel. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int TclChannelTransform(interp, chan, cmdObjPtr) Tcl_Interp *interp; /* Interpreter for result. */ Tcl_Channel chan; /* Channel to transform. */ Tcl_Obj *cmdObjPtr; /* Script to use for transform. */ { Channel *chanPtr; /* The actual channel. */ ChannelState *statePtr; /* state info for channel */ int mode; /* rw mode of the channel */ TransformChannelData *dataPtr; int res; Tcl_DString ds; if (chan == (Tcl_Channel) NULL) { return TCL_ERROR; } chanPtr = (Channel *) chan; statePtr = chanPtr->state; chanPtr = statePtr->topChanPtr; chan = (Tcl_Channel) chanPtr; mode = (statePtr->flags & (TCL_READABLE|TCL_WRITABLE)); /* * Now initialize the transformation state and stack it upon the * specified channel. One of the necessary things to do is to * retrieve the blocking regime of the underlying channel and to * use the same for us too. */ dataPtr = (TransformChannelData*) ckalloc(sizeof(TransformChannelData)); Tcl_DStringInit (&ds); Tcl_GetChannelOption(interp, chan, "-blocking", &ds); dataPtr->readIsFlushed = 0; dataPtr->flags = 0; if (ds.string[0] == '0') { dataPtr->flags |= CHANNEL_ASYNC; } Tcl_DStringFree (&ds); dataPtr->self = chan; dataPtr->watchMask = 0; dataPtr->mode = mode; dataPtr->timer = (Tcl_TimerToken) NULL; dataPtr->maxRead = 4096; /* Initial value not relevant */ dataPtr->interp = interp; dataPtr->command = cmdObjPtr; Tcl_IncrRefCount(dataPtr->command); ResultInit(&dataPtr->result); dataPtr->self = Tcl_StackChannel(interp, &transformChannelType, (ClientData) dataPtr, mode, chan); if (dataPtr->self == (Tcl_Channel) NULL) { Tcl_AppendResult(interp, "\nfailed to stack channel \"", Tcl_GetChannelName(chan), "\"", (char *) NULL); Tcl_DecrRefCount(dataPtr->command); ResultClear(&dataPtr->result); ckfree((VOID *) dataPtr); return TCL_ERROR; } /* * At last initialize the transformation at the script level. */ if (dataPtr->mode & TCL_WRITABLE) { res = ExecuteCallback (dataPtr, NO_INTERP, A_CREATE_WRITE, NULL, 0, TRANSMIT_DONT, P_NO_PRESERVE); if (res != TCL_OK) { Tcl_UnstackChannel(interp, chan); return TCL_ERROR; } } if (dataPtr->mode & TCL_READABLE) { res = ExecuteCallback (dataPtr, NO_INTERP, A_CREATE_READ, NULL, 0, TRANSMIT_DONT, P_NO_PRESERVE); if (res != TCL_OK) { ExecuteCallback (dataPtr, NO_INTERP, A_DELETE_WRITE, NULL, 0, TRANSMIT_DONT, P_NO_PRESERVE); Tcl_UnstackChannel(interp, chan); return TCL_ERROR; } } return TCL_OK; } /* *------------------------------------------------------* * * ExecuteCallback -- * * Executes the defined callback for buffer and * operation. * * Sideeffects: * As of the executed tcl script. * * Result: * A standard TCL error code. In case of an * error a message is left in the result area * of the specified interpreter. * *------------------------------------------------------* */ static int ExecuteCallback (dataPtr, interp, op, buf, bufLen, transmit, preserve) TransformChannelData* dataPtr; /* Transformation with the callback */ Tcl_Interp* interp; /* Current interpreter, possibly NULL */ unsigned char* op; /* Operation invoking the callback */ unsigned char* buf; /* Buffer to give to the script. */ int bufLen; /* Ands its length */ int transmit; /* Flag, determines whether the result * of the callback is sent to the * underlying channel or not. */ int preserve; /* Flag. If true the procedure will * preserver the result state of all * accessed interpreters. */ { /* * Step 1, create the complete command to execute. Do this by appending * operation and buffer to operate upon to a copy of the callback * definition. We *cannot* create a list containing 3 objects and then use * 'Tcl_EvalObjv', because the command may contain additional prefixed * arguments. Feather's curried commands would come in handy here. */ Tcl_Obj* resObj; /* See below, switch (transmit) */ int resLen; unsigned char* resBuf; Tcl_SavedResult ciSave; int res = TCL_OK; Tcl_Obj* command = Tcl_DuplicateObj (dataPtr->command); Tcl_Obj* temp; if (preserve) { Tcl_SaveResult (dataPtr->interp, &ciSave); } if (command == (Tcl_Obj*) NULL) { /* Memory allocation problem */ res = TCL_ERROR; goto cleanup; } Tcl_IncrRefCount(command); temp = Tcl_NewStringObj((char*) op, -1); if (temp == (Tcl_Obj*) NULL) { /* Memory allocation problem */ res = TCL_ERROR; goto cleanup; } res = Tcl_ListObjAppendElement(dataPtr->interp, command, temp); if (res != TCL_OK) goto cleanup; /* * Use a byte-array to prevent the misinterpretation of binary data * coming through as UTF while at the tcl level. */ temp = Tcl_NewByteArrayObj(buf, bufLen); if (temp == (Tcl_Obj*) NULL) { /* Memory allocation problem */ res = TCL_ERROR; goto cleanup; } res = Tcl_ListObjAppendElement (dataPtr->interp, command, temp); if (res != TCL_OK) goto cleanup; /* * Step 2, execute the command at the global level of the interpreter * used to create the transformation. Destroy the command afterward. * If an error occured and the current interpreter is defined and not * equal to the interpreter for the callback, then copy the error * message into current interpreter. Don't copy if in preservation mode. */ res = Tcl_EvalObjEx(dataPtr->interp, command, TCL_EVAL_GLOBAL); Tcl_DecrRefCount (command); command = (Tcl_Obj*) NULL; if ((res != TCL_OK) && (interp != NO_INTERP) && (dataPtr->interp != interp) && !preserve) { Tcl_SetObjResult(interp, Tcl_GetObjResult(dataPtr->interp)); return res; } /* * Step 3, transmit a possible conversion result to the underlying * channel, or ourselves. */ switch (transmit) { case TRANSMIT_DONT: /* nothing to do */ break; case TRANSMIT_DOWN: resObj = Tcl_GetObjResult(dataPtr->interp); resBuf = (unsigned char*) Tcl_GetByteArrayFromObj(resObj, &resLen); Tcl_WriteRaw(Tcl_GetStackedChannel(dataPtr->self), (char*) resBuf, resLen); break; case TRANSMIT_SELF: resObj = Tcl_GetObjResult (dataPtr->interp); resBuf = (unsigned char*) Tcl_GetByteArrayFromObj(resObj, &resLen); Tcl_WriteRaw(dataPtr->self, (char*) resBuf, resLen); break; case TRANSMIT_IBUF: resObj = Tcl_GetObjResult (dataPtr->interp); resBuf = (unsigned char*) Tcl_GetByteArrayFromObj(resObj, &resLen); ResultAdd(&dataPtr->result, resBuf, resLen); break; case TRANSMIT_NUM: /* Interpret result as integer number */ resObj = Tcl_GetObjResult (dataPtr->interp); Tcl_GetIntFromObj(dataPtr->interp, resObj, &dataPtr->maxRead); break; } Tcl_ResetResult(dataPtr->interp); if (preserve) { Tcl_RestoreResult(dataPtr->interp, &ciSave); } return res; cleanup: if (preserve) { Tcl_RestoreResult(dataPtr->interp, &ciSave); } if (command != (Tcl_Obj*) NULL) { Tcl_DecrRefCount(command); } return res; } /* *------------------------------------------------------* * * TransformBlockModeProc -- * * Trap handler. Called by the generic IO system * during option processing to change the blocking * mode of the channel. * * Sideeffects: * Forwards the request to the underlying * channel. * * Result: * 0 if successful, errno when failed. * *------------------------------------------------------* */ static int TransformBlockModeProc (instanceData, mode) ClientData instanceData; /* State of transformation */ int mode; /* New blocking mode */ { TransformChannelData* dataPtr = (TransformChannelData*) instanceData; if (mode == TCL_MODE_NONBLOCKING) { dataPtr->flags |= CHANNEL_ASYNC; } else { dataPtr->flags &= ~(CHANNEL_ASYNC); } return 0; } /* *------------------------------------------------------* * * TransformCloseProc -- * * Trap handler. Called by the generic IO system * during destruction of the transformation channel. * * Sideeffects: * Releases the memory allocated in * 'Tcl_TransformObjCmd'. * * Result: * None. * *------------------------------------------------------* */ static int TransformCloseProc (instanceData, interp) ClientData instanceData; Tcl_Interp* interp; { TransformChannelData* dataPtr = (TransformChannelData*) instanceData; /* * Important: In this procedure 'dataPtr->self' already points to * the underlying channel. */ /* * There is no need to cancel an existing channel handler, this is already * done. Either by 'Tcl_UnstackChannel' or by the general cleanup in * 'Tcl_Close'. * * But we have to cancel an active timer to prevent it from firing on the * removed channel. */ if (dataPtr->timer != (Tcl_TimerToken) NULL) { Tcl_DeleteTimerHandler (dataPtr->timer); dataPtr->timer = (Tcl_TimerToken) NULL; } /* * Now flush data waiting in internal buffers to output and input. The * input must be done despite the fact that there is no real receiver * for it anymore. But the scripts might have sideeffects other parts * of the system rely on (f.e. signaling the close to interested parties). */ if (dataPtr->mode & TCL_WRITABLE) { ExecuteCallback (dataPtr, interp, A_FLUSH_WRITE, NULL, 0, TRANSMIT_DOWN, 1); } if ((dataPtr->mode & TCL_READABLE) && !dataPtr->readIsFlushed) { dataPtr->readIsFlushed = 1; ExecuteCallback (dataPtr, interp, A_FLUSH_READ, NULL, 0, TRANSMIT_IBUF, 1); } if (dataPtr->mode & TCL_WRITABLE) { ExecuteCallback (dataPtr, interp, A_DELETE_WRITE, NULL, 0, TRANSMIT_DONT, 1); } if (dataPtr->mode & TCL_READABLE) { ExecuteCallback (dataPtr, interp, A_DELETE_READ, NULL, 0, TRANSMIT_DONT, 1); } /* * General cleanup */ ResultClear(&dataPtr->result); Tcl_DecrRefCount(dataPtr->command); ckfree((VOID*) dataPtr); return TCL_OK; } /* *------------------------------------------------------* * * TransformInputProc -- * * Called by the generic IO system to convert read data. * * Sideeffects: * As defined by the conversion. * * Result: * A transformed buffer. * *------------------------------------------------------* */ static int TransformInputProc (instanceData, buf, toRead, errorCodePtr) ClientData instanceData; char* buf; int toRead; int* errorCodePtr; { TransformChannelData* dataPtr = (TransformChannelData*) instanceData; int gotBytes, read, res, copied; Tcl_Channel downChan; /* should assert (dataPtr->mode & TCL_READABLE) */ if (toRead == 0) { /* Catch a no-op. */ return 0; } gotBytes = 0; downChan = Tcl_GetStackedChannel(dataPtr->self); while (toRead > 0) { /* * Loop until the request is satisfied (or no data is available from * below, possibly EOF). */ copied = ResultCopy (&dataPtr->result, UCHARP (buf), toRead); toRead -= copied; buf += copied; gotBytes += copied; if (toRead == 0) { /* The request was completely satisfied from our buffers. * We can break out of the loop and return to the caller. */ return gotBytes; } /* * Length (dataPtr->result) == 0, toRead > 0 here . Use the incoming * 'buf'! as target to store the intermediary information read * from the underlying channel. * * Ask the tcl level how much data it allows us to read from * the underlying channel. This feature allows the transform to * signal EOF upstream although there is none downstream. Useful * to control an unbounded 'fcopy', either through counting bytes, * or by pattern matching. */ ExecuteCallback (dataPtr, NO_INTERP, A_QUERY_MAXREAD, NULL, 0, TRANSMIT_NUM /* -> maxRead */, 1); if (dataPtr->maxRead >= 0) { if (dataPtr->maxRead < toRead) { toRead = dataPtr->maxRead; } } /* else: 'maxRead < 0' == Accept the current value of toRead */ if (toRead <= 0) { return gotBytes; } read = Tcl_ReadRaw(downChan, buf, toRead); if (read < 0) { /* Report errors to caller. EAGAIN is a special situation. * If we had some data before we report that instead of the * request to re-try. */ if ((Tcl_GetErrno() == EAGAIN) && (gotBytes > 0)) { return gotBytes; } *errorCodePtr = Tcl_GetErrno(); return -1; } if (read == 0) { /* * Check wether we hit on EOF in the underlying channel or * not. If not differentiate between blocking and * non-blocking modes. In non-blocking mode we ran * temporarily out of data. Signal this to the caller via * EWOULDBLOCK and error return (-1). In the other cases * we simply return what we got and let the caller wait * for more. On the other hand, if we got an EOF we have * to convert and flush all waiting partial data. */ if (! Tcl_Eof (downChan)) { if ((gotBytes == 0) && (dataPtr->flags & CHANNEL_ASYNC)) { *errorCodePtr = EWOULDBLOCK; return -1; } else { return gotBytes; } } else { if (dataPtr->readIsFlushed) { /* Already flushed, nothing to do anymore */ return gotBytes; } dataPtr->readIsFlushed = 1; ExecuteCallback (dataPtr, NO_INTERP, A_FLUSH_READ, NULL, 0, TRANSMIT_IBUF, P_PRESERVE); if (ResultLength (&dataPtr->result) == 0) { /* we had nothing to flush */ return gotBytes; } continue; /* at: while (toRead > 0) */ } } /* read == 0 */ /* Transform the read chunk and add the result to our * read buffer (dataPtr->result) */ res = ExecuteCallback (dataPtr, NO_INTERP, A_READ, UCHARP (buf), read, TRANSMIT_IBUF, P_PRESERVE); if (res != TCL_OK) { *errorCodePtr = EINVAL; return -1; } } /* while toRead > 0 */ return gotBytes; } /* *------------------------------------------------------* * * TransformOutputProc -- * * Called by the generic IO system to convert data * waiting to be written. * * Sideeffects: * As defined by the transformation. * * Result: * A transformed buffer. * *------------------------------------------------------* */ static int TransformOutputProc (instanceData, buf, toWrite, errorCodePtr) ClientData instanceData; CONST char* buf; int toWrite; int* errorCodePtr; { TransformChannelData* dataPtr = (TransformChannelData*) instanceData; int res; /* should assert (dataPtr->mode & TCL_WRITABLE) */ if (toWrite == 0) { /* Catch a no-op. */ return 0; } res = ExecuteCallback (dataPtr, NO_INTERP, A_WRITE, UCHARP (buf), toWrite, TRANSMIT_DOWN, P_NO_PRESERVE); if (res != TCL_OK) { *errorCodePtr = EINVAL; return -1; } return toWrite; } /* *------------------------------------------------------* * * TransformSeekProc -- * * This procedure is called by the generic IO level * to move the access point in a channel. * * Sideeffects: * Moves the location at which the channel * will be accessed in future operations. * Flushes all transformation buffers, then * forwards it to the underlying channel. * * Result: * -1 if failed, the new position if * successful. An output argument contains * the POSIX error code if an error * occurred, or zero. * *------------------------------------------------------* */ static int TransformSeekProc (instanceData, offset, mode, errorCodePtr) ClientData instanceData; /* The channel to manipulate */ long offset; /* Size of movement. */ int mode; /* How to move */ int* errorCodePtr; /* Location of error flag. */ { TransformChannelData* dataPtr = (TransformChannelData*) instanceData; Tcl_Channel parent = Tcl_GetStackedChannel(dataPtr->self); Tcl_ChannelType* parentType = Tcl_GetChannelType(parent); Tcl_DriverSeekProc* parentSeekProc = Tcl_ChannelSeekProc(parentType); if ((offset == 0) && (mode == SEEK_CUR)) { /* This is no seek but a request to tell the caller the current * location. Simply pass the request down. */ return (*parentSeekProc) (Tcl_GetChannelInstanceData(parent), offset, mode, errorCodePtr); } /* * It is a real request to change the position. Flush all data waiting * for output and discard everything in the input buffers. Then pass * the request down, unchanged. */ if (dataPtr->mode & TCL_WRITABLE) { ExecuteCallback (dataPtr, NO_INTERP, A_FLUSH_WRITE, NULL, 0, TRANSMIT_DOWN, P_NO_PRESERVE); } if (dataPtr->mode & TCL_READABLE) { ExecuteCallback (dataPtr, NO_INTERP, A_CLEAR_READ, NULL, 0, TRANSMIT_DONT, P_NO_PRESERVE); ResultClear(&dataPtr->result); dataPtr->readIsFlushed = 0; } return (*parentSeekProc) (Tcl_GetChannelInstanceData(parent), offset, mode, errorCodePtr); } /* *---------------------------------------------------------------------- * * TransformWideSeekProc -- * * This procedure is called by the generic IO level to move the * access point in a channel, with a (potentially) 64-bit offset. * * Side effects: * Moves the location at which the channel will be accessed in * future operations. Flushes all transformation buffers, then * forwards it to the underlying channel. * * Result: * -1 if failed, the new position if successful. An output * argument contains the POSIX error code if an error occurred, * or zero. * *---------------------------------------------------------------------- */ static Tcl_WideInt TransformWideSeekProc (instanceData, offset, mode, errorCodePtr) ClientData instanceData; /* The channel to manipulate */ Tcl_WideInt offset; /* Size of movement. */ int mode; /* How to move */ int* errorCodePtr; /* Location of error flag. */ { TransformChannelData* dataPtr = (TransformChannelData*) instanceData; Tcl_Channel parent = Tcl_GetStackedChannel(dataPtr->self); Tcl_ChannelType* parentType = Tcl_GetChannelType(parent); Tcl_DriverSeekProc* parentSeekProc = Tcl_ChannelSeekProc(parentType); Tcl_DriverWideSeekProc* parentWideSeekProc = Tcl_ChannelWideSeekProc(parentType); ClientData parentData = Tcl_GetChannelInstanceData(parent); if ((offset == Tcl_LongAsWide(0)) && (mode == SEEK_CUR)) { /* * This is no seek but a request to tell the caller the current * location. Simply pass the request down. */ if (parentWideSeekProc != NULL) { return (*parentWideSeekProc) (parentData, offset, mode, errorCodePtr); } return Tcl_LongAsWide((*parentSeekProc) (parentData, 0, mode, errorCodePtr)); } /* * It is a real request to change the position. Flush all data waiting * for output and discard everything in the input buffers. Then pass * the request down, unchanged. */ if (dataPtr->mode & TCL_WRITABLE) { ExecuteCallback (dataPtr, NO_INTERP, A_FLUSH_WRITE, NULL, 0, TRANSMIT_DOWN, P_NO_PRESERVE); } if (dataPtr->mode & TCL_READABLE) { ExecuteCallback (dataPtr, NO_INTERP, A_CLEAR_READ, NULL, 0, TRANSMIT_DONT, P_NO_PRESERVE); ResultClear(&dataPtr->result); dataPtr->readIsFlushed = 0; } /* * If we have a wide seek capability, we should stick with that. */ if (parentWideSeekProc != NULL) { return (*parentWideSeekProc) (parentData, offset, mode, errorCodePtr); } /* * We're transferring to narrow seeks at this point; this is a bit * complex because we have to check whether the seek is possible * first (i.e. whether we are losing information in truncating the * bits of the offset.) Luckily, there's a defined error for what * happens when trying to go out of the representable range. */ if (offsetTcl_LongAsWide(LONG_MAX)) { *errorCodePtr = EOVERFLOW; return Tcl_LongAsWide(-1); } return Tcl_LongAsWide((*parentSeekProc) (parentData, Tcl_WideAsLong(offset), mode, errorCodePtr)); } /* *------------------------------------------------------* * * TransformSetOptionProc -- * * Called by generic layer to handle the reconfi- * guration of channel specific options. As this * channel type does not have such, it simply passes * all requests downstream. * * Sideeffects: * As defined by the channel downstream. * * Result: * A standard TCL error code. * *------------------------------------------------------* */ static int TransformSetOptionProc (instanceData, interp, optionName, value) ClientData instanceData; Tcl_Interp *interp; CONST char *optionName; CONST char *value; { TransformChannelData* dataPtr = (TransformChannelData*) instanceData; Tcl_Channel downChan = Tcl_GetStackedChannel(dataPtr->self); Tcl_DriverSetOptionProc *setOptionProc; setOptionProc = Tcl_ChannelSetOptionProc(Tcl_GetChannelType(downChan)); if (setOptionProc != NULL) { return (*setOptionProc)(Tcl_GetChannelInstanceData(downChan), interp, optionName, value); } return TCL_ERROR; } /* *------------------------------------------------------* * * TransformGetOptionProc -- * * Called by generic layer to handle requests for * the values of channel specific options. As this * channel type does not have such, it simply passes * all requests downstream. * * Sideeffects: * As defined by the channel downstream. * * Result: * A standard TCL error code. * *------------------------------------------------------* */ static int TransformGetOptionProc (instanceData, interp, optionName, dsPtr) ClientData instanceData; Tcl_Interp* interp; CONST char* optionName; Tcl_DString* dsPtr; { TransformChannelData* dataPtr = (TransformChannelData*) instanceData; Tcl_Channel downChan = Tcl_GetStackedChannel(dataPtr->self); Tcl_DriverGetOptionProc *getOptionProc; getOptionProc = Tcl_ChannelGetOptionProc(Tcl_GetChannelType(downChan)); if (getOptionProc != NULL) { return (*getOptionProc)(Tcl_GetChannelInstanceData(downChan), interp, optionName, dsPtr); } else if (optionName == (CONST char*) NULL) { /* * Request is query for all options, this is ok. */ return TCL_OK; } /* * Request for a specific option has to fail, we don't have any. */ return TCL_ERROR; } /* *------------------------------------------------------* * * TransformWatchProc -- * * Initialize the notifier to watch for events from * this channel. * * Sideeffects: * Sets up the notifier so that a future * event on the channel will be seen by Tcl. * * Result: * None. * *------------------------------------------------------* */ /* ARGSUSED */ static void TransformWatchProc (instanceData, mask) ClientData instanceData; /* Channel to watch */ int mask; /* Events of interest */ { /* The caller expressed interest in events occuring for this * channel. We are forwarding the call to the underlying * channel now. */ TransformChannelData* dataPtr = (TransformChannelData*) instanceData; Tcl_Channel downChan; dataPtr->watchMask = mask; /* No channel handlers any more. We will be notified automatically * about events on the channel below via a call to our * 'TransformNotifyProc'. But we have to pass the interest down now. * We are allowed to add additional 'interest' to the mask if we want * to. But this transformation has no such interest. It just passes * the request down, unchanged. */ downChan = Tcl_GetStackedChannel(dataPtr->self); (Tcl_GetChannelType(downChan)) ->watchProc(Tcl_GetChannelInstanceData(downChan), mask); /* * Management of the internal timer. */ if ((dataPtr->timer != (Tcl_TimerToken) NULL) && (!(mask & TCL_READABLE) || (ResultLength(&dataPtr->result) == 0))) { /* A pending timer exists, but either is there no (more) * interest in the events it generates or nothing is availablee * for reading, so remove it. */ Tcl_DeleteTimerHandler (dataPtr->timer); dataPtr->timer = (Tcl_TimerToken) NULL; } if ((dataPtr->timer == (Tcl_TimerToken) NULL) && (mask & TCL_READABLE) && (ResultLength (&dataPtr->result) > 0)) { /* There is no pending timer, but there is interest in readable * events and we actually have data waiting, so generate a timer * to flush that. */ dataPtr->timer = Tcl_CreateTimerHandler (FLUSH_DELAY, TransformChannelHandlerTimer, (ClientData) dataPtr); } } /* *------------------------------------------------------* * * TransformGetFileHandleProc -- * * Called from Tcl_GetChannelHandle to retrieve * OS specific file handle from inside this channel. * * Sideeffects: * None. * * Result: * The appropriate Tcl_File or NULL if not * present. * *------------------------------------------------------* */ static int TransformGetFileHandleProc (instanceData, direction, handlePtr) ClientData instanceData; /* Channel to query */ int direction; /* Direction of interest */ ClientData* handlePtr; /* Place to store the handle into */ { /* * Return the handle belonging to parent channel. * IOW, pass the request down and the result up. */ TransformChannelData* dataPtr = (TransformChannelData*) instanceData; return Tcl_GetChannelHandle(Tcl_GetStackedChannel(dataPtr->self), direction, handlePtr); } /* *------------------------------------------------------* * * TransformNotifyProc -- * * ------------------------------------------------* * Handler called by Tcl to inform us of activity * on the underlying channel. * ------------------------------------------------* * * Sideeffects: * May process the incoming event by itself. * * Result: * None. * *------------------------------------------------------* */ static int TransformNotifyProc (clientData, mask) ClientData clientData; /* The state of the notified transformation */ int mask; /* The mask of occuring events */ { TransformChannelData* dataPtr = (TransformChannelData*) clientData; /* * An event occured in the underlying channel. This * transformation doesn't process such events thus returns the * incoming mask unchanged. */ if (dataPtr->timer != (Tcl_TimerToken) NULL) { /* * Delete an existing timer. It was not fired, yet we are * here, so the channel below generated such an event and we * don't have to. The renewal of the interest after the * execution of channel handlers will eventually cause us to * recreate the timer (in TransformWatchProc). */ Tcl_DeleteTimerHandler (dataPtr->timer); dataPtr->timer = (Tcl_TimerToken) NULL; } return mask; } /* *------------------------------------------------------* * * TransformChannelHandlerTimer -- * * Called by the notifier (-> timer) to flush out * information waiting in the input buffer. * * Sideeffects: * As of 'Tcl_NotifyChannel'. * * Result: * None. * *------------------------------------------------------* */ static void TransformChannelHandlerTimer (clientData) ClientData clientData; /* Transformation to query */ { TransformChannelData* dataPtr = (TransformChannelData*) clientData; dataPtr->timer = (Tcl_TimerToken) NULL; if (!(dataPtr->watchMask & TCL_READABLE) || (ResultLength (&dataPtr->result) == 0)) { /* The timer fired, but either is there no (more) * interest in the events it generates or nothing is available * for reading, so ignore it and don't recreate it. */ return; } Tcl_NotifyChannel(dataPtr->self, TCL_READABLE); } /* *------------------------------------------------------* * * ResultClear -- * * Deallocates any memory allocated by 'ResultAdd'. * * Sideeffects: * See above. * * Result: * None. * *------------------------------------------------------* */ static void ResultClear (r) ResultBuffer* r; /* Reference to the buffer to clear out */ { r->used = 0; if (r->allocated) { ckfree((char*) r->buf); r->buf = UCHARP (NULL); r->allocated = 0; } } /* *------------------------------------------------------* * * ResultInit -- * * Initializes the specified buffer structure. The * structure will contain valid information for an * emtpy buffer. * * Sideeffects: * See above. * * Result: * None. * *------------------------------------------------------* */ static void ResultInit (r) ResultBuffer* r; /* Reference to the structure to initialize */ { r->used = 0; r->allocated = 0; r->buf = UCHARP (NULL); } /* *------------------------------------------------------* * * ResultLength -- * * Returns the number of bytes stored in the buffer. * * Sideeffects: * None. * * Result: * An integer, see above too. * *------------------------------------------------------* */ static int ResultLength (r) ResultBuffer* r; /* The structure to query */ { return r->used; } /* *------------------------------------------------------* * * ResultCopy -- * * Copies the requested number of bytes from the * buffer into the specified array and removes them * from the buffer afterward. Copies less if there * is not enough data in the buffer. * * Sideeffects: * See above. * * Result: * The number of actually copied bytes, * possibly less than 'toRead'. * *------------------------------------------------------* */ static int ResultCopy (r, buf, toRead) ResultBuffer* r; /* The buffer to read from */ unsigned char* buf; /* The buffer to copy into */ int toRead; /* Number of requested bytes */ { if (r->used == 0) { /* Nothing to copy in the case of an empty buffer. */ return 0; } if (r->used == toRead) { /* We have just enough. Copy everything to the caller. */ memcpy ((VOID*) buf, (VOID*) r->buf, (size_t) toRead); r->used = 0; return toRead; } if (r->used > toRead) { /* The internal buffer contains more than requested. * Copy the requested subset to the caller, and shift * the remaining bytes down. */ memcpy ((VOID*) buf, (VOID*) r->buf, (size_t) toRead); memmove ((VOID*) r->buf, (VOID*) (r->buf + toRead), (size_t) r->used - toRead); r->used -= toRead; return toRead; } /* There is not enough in the buffer to satisfy the caller, so * take everything. */ memcpy((VOID*) buf, (VOID*) r->buf, (size_t) r->used); toRead = r->used; r->used = 0; return toRead; } /* *------------------------------------------------------* * * ResultAdd -- * * Adds the bytes in the specified array to the * buffer, by appending it. * * Sideeffects: * See above. * * Result: * None. * *------------------------------------------------------* */ static void ResultAdd (r, buf, toWrite) ResultBuffer* r; /* The buffer to extend */ unsigned char* buf; /* The buffer to read from */ int toWrite; /* The number of bytes in 'buf' */ { if ((r->used + toWrite) > r->allocated) { /* Extension of the internal buffer is required. */ if (r->allocated == 0) { r->allocated = toWrite + INCREMENT; r->buf = UCHARP (ckalloc((unsigned) r->allocated)); } else { r->allocated += toWrite + INCREMENT; r->buf = UCHARP (ckrealloc((char*) r->buf, (unsigned) r->allocated)); } } /* now copy data */ memcpy(r->buf + r->used, buf, (size_t) toWrite); r->used += toWrite; } tcl8.4.20/generic/tclTimer.c0000644003604700454610000010024611737050674014265 0ustar dgp771div/* * tclTimer.c -- * * This file provides timer event management facilities for Tcl, * including the "after" command. * * Copyright (c) 1997 by Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" /* * For each timer callback that's pending there is one record of the following * type. The normal handlers (created by Tcl_CreateTimerHandler) are chained * together in a list sorted by time (earliest event first). */ typedef struct TimerHandler { Tcl_Time time; /* When timer is to fire. */ Tcl_TimerProc *proc; /* Procedure to call. */ ClientData clientData; /* Argument to pass to proc. */ Tcl_TimerToken token; /* Identifies handler so it can be * deleted. */ struct TimerHandler *nextPtr; /* Next event in queue, or NULL for * end of queue. */ } TimerHandler; /* * The data structure below is used by the "after" command to remember * the command to be executed later. All of the pending "after" commands * for an interpreter are linked together in a list. */ typedef struct AfterInfo { struct AfterAssocData *assocPtr; /* Pointer to the "tclAfter" assocData for * the interp in which command will be * executed. */ Tcl_Obj *commandPtr; /* Command to execute. */ int id; /* Integer identifier for command; used to * cancel it. */ Tcl_TimerToken token; /* Used to cancel the "after" command. NULL * means that the command is run as an * idle handler rather than as a timer * handler. NULL means this is an "after * idle" handler rather than a * timer handler. */ struct AfterInfo *nextPtr; /* Next in list of all "after" commands for * this interpreter. */ } AfterInfo; /* * One of the following structures is associated with each interpreter * for which an "after" command has ever been invoked. A pointer to * this structure is stored in the AssocData for the "tclAfter" key. */ typedef struct AfterAssocData { Tcl_Interp *interp; /* The interpreter for which this data is * registered. */ AfterInfo *firstAfterPtr; /* First in list of all "after" commands * still pending for this interpreter, or * NULL if none. */ } AfterAssocData; /* * There is one of the following structures for each of the * handlers declared in a call to Tcl_DoWhenIdle. All of the * currently-active handlers are linked together into a list. */ typedef struct IdleHandler { Tcl_IdleProc (*proc); /* Procedure to call. */ ClientData clientData; /* Value to pass to proc. */ int generation; /* Used to distinguish older handlers from * recently-created ones. */ struct IdleHandler *nextPtr;/* Next in list of active handlers. */ } IdleHandler; /* * The timer and idle queues are per-thread because they are associated * with the notifier, which is also per-thread. * * All static variables used in this file are collected into a single * instance of the following structure. For multi-threaded implementations, * there is one instance of this structure for each thread. * * Notice that different structures with the same name appear in other * files. The structure defined below is used in this file only. */ typedef struct ThreadSpecificData { TimerHandler *firstTimerHandlerPtr; /* First event in queue. */ int lastTimerId; /* Timer identifier of most recently * created timer. */ int timerPending; /* 1 if a timer event is in the queue. */ IdleHandler *idleList; /* First in list of all idle handlers. */ IdleHandler *lastIdlePtr; /* Last in list (or NULL for empty list). */ int idleGeneration; /* Used to fill in the "generation" fields * of IdleHandler structures. Increments * each time Tcl_DoOneEvent starts calling * idle handlers, so that all old handlers * can be called without calling any of the * new ones created by old ones. */ int afterId; /* For unique identifiers of after events. */ } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; /* * Prototypes for procedures referenced only in this file: */ static void AfterCleanupProc _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp)); static void AfterProc _ANSI_ARGS_((ClientData clientData)); static void FreeAfterPtr _ANSI_ARGS_((AfterInfo *afterPtr)); static AfterInfo * GetAfterEvent _ANSI_ARGS_((AfterAssocData *assocPtr, Tcl_Obj *commandPtr)); static ThreadSpecificData *InitTimer _ANSI_ARGS_((void)); static void TimerExitProc _ANSI_ARGS_((ClientData clientData)); static int TimerHandlerEventProc _ANSI_ARGS_((Tcl_Event *evPtr, int flags)); static void TimerCheckProc _ANSI_ARGS_((ClientData clientData, int flags)); static void TimerSetupProc _ANSI_ARGS_((ClientData clientData, int flags)); /* *---------------------------------------------------------------------- * * InitTimer -- * * This function initializes the timer module. * * Results: * A pointer to the thread specific data. * * Side effects: * Registers the idle and timer event sources. * *---------------------------------------------------------------------- */ static ThreadSpecificData * InitTimer() { ThreadSpecificData *tsdPtr = (ThreadSpecificData *) TclThreadDataKeyGet(&dataKey); if (tsdPtr == NULL) { tsdPtr = TCL_TSD_INIT(&dataKey); Tcl_CreateEventSource(TimerSetupProc, TimerCheckProc, NULL); Tcl_CreateThreadExitHandler(TimerExitProc, NULL); } return tsdPtr; } /* *---------------------------------------------------------------------- * * TimerExitProc -- * * This function is call at exit or unload time to remove the * timer and idle event sources. * * Results: * None. * * Side effects: * Removes the timer and idle event sources and remaining events. * *---------------------------------------------------------------------- */ static void TimerExitProc(clientData) ClientData clientData; /* Not used. */ { ThreadSpecificData *tsdPtr = (ThreadSpecificData *) TclThreadDataKeyGet(&dataKey); Tcl_DeleteEventSource(TimerSetupProc, TimerCheckProc, NULL); if (tsdPtr != NULL) { register TimerHandler *timerHandlerPtr; timerHandlerPtr = tsdPtr->firstTimerHandlerPtr; while (timerHandlerPtr != NULL) { tsdPtr->firstTimerHandlerPtr = timerHandlerPtr->nextPtr; ckfree((char *) timerHandlerPtr); timerHandlerPtr = tsdPtr->firstTimerHandlerPtr; } } } /* *-------------------------------------------------------------- * * Tcl_CreateTimerHandler -- * * Arrange for a given procedure to be invoked at a particular * time in the future. * * Results: * The return value is a token for the timer event, which * may be used to delete the event before it fires. * * Side effects: * When milliseconds have elapsed, proc will be invoked * exactly once. * *-------------------------------------------------------------- */ Tcl_TimerToken Tcl_CreateTimerHandler(milliseconds, proc, clientData) int milliseconds; /* How many milliseconds to wait * before invoking proc. */ Tcl_TimerProc *proc; /* Procedure to invoke. */ ClientData clientData; /* Arbitrary data to pass to proc. */ { register TimerHandler *timerHandlerPtr, *tPtr2, *prevPtr; Tcl_Time time; ThreadSpecificData *tsdPtr; tsdPtr = InitTimer(); timerHandlerPtr = (TimerHandler *) ckalloc(sizeof(TimerHandler)); /* * Compute when the event should fire. */ Tcl_GetTime(&time); timerHandlerPtr->time.sec = time.sec + milliseconds/1000; timerHandlerPtr->time.usec = time.usec + (milliseconds%1000)*1000; if (timerHandlerPtr->time.usec >= 1000000) { timerHandlerPtr->time.usec -= 1000000; timerHandlerPtr->time.sec += 1; } /* * Fill in other fields for the event. */ timerHandlerPtr->proc = proc; timerHandlerPtr->clientData = clientData; tsdPtr->lastTimerId++; timerHandlerPtr->token = (Tcl_TimerToken) tsdPtr->lastTimerId; /* * Add the event to the queue in the correct position * (ordered by event firing time). */ for (tPtr2 = tsdPtr->firstTimerHandlerPtr, prevPtr = NULL; tPtr2 != NULL; prevPtr = tPtr2, tPtr2 = tPtr2->nextPtr) { if ((tPtr2->time.sec > timerHandlerPtr->time.sec) || ((tPtr2->time.sec == timerHandlerPtr->time.sec) && (tPtr2->time.usec > timerHandlerPtr->time.usec))) { break; } } timerHandlerPtr->nextPtr = tPtr2; if (prevPtr == NULL) { tsdPtr->firstTimerHandlerPtr = timerHandlerPtr; } else { prevPtr->nextPtr = timerHandlerPtr; } TimerSetupProc(NULL, TCL_ALL_EVENTS); return timerHandlerPtr->token; } /* *-------------------------------------------------------------- * * Tcl_DeleteTimerHandler -- * * Delete a previously-registered timer handler. * * Results: * None. * * Side effects: * Destroy the timer callback identified by TimerToken, * so that its associated procedure will not be called. * If the callback has already fired, or if the given * token doesn't exist, then nothing happens. * *-------------------------------------------------------------- */ void Tcl_DeleteTimerHandler(token) Tcl_TimerToken token; /* Result previously returned by * Tcl_DeleteTimerHandler. */ { register TimerHandler *timerHandlerPtr, *prevPtr; ThreadSpecificData *tsdPtr = InitTimer(); if (token == NULL) { return; } for (timerHandlerPtr = tsdPtr->firstTimerHandlerPtr, prevPtr = NULL; timerHandlerPtr != NULL; prevPtr = timerHandlerPtr, timerHandlerPtr = timerHandlerPtr->nextPtr) { if (timerHandlerPtr->token != token) { continue; } if (prevPtr == NULL) { tsdPtr->firstTimerHandlerPtr = timerHandlerPtr->nextPtr; } else { prevPtr->nextPtr = timerHandlerPtr->nextPtr; } ckfree((char *) timerHandlerPtr); return; } } /* *---------------------------------------------------------------------- * * TimerSetupProc -- * * This function is called by Tcl_DoOneEvent to setup the timer * event source for before blocking. This routine checks both the * idle and after timer lists. * * Results: * None. * * Side effects: * May update the maximum notifier block time. * *---------------------------------------------------------------------- */ static void TimerSetupProc(data, flags) ClientData data; /* Not used. */ int flags; /* Event flags as passed to Tcl_DoOneEvent. */ { Tcl_Time blockTime; ThreadSpecificData *tsdPtr = InitTimer(); if (((flags & TCL_IDLE_EVENTS) && tsdPtr->idleList) || ((flags & TCL_TIMER_EVENTS) && tsdPtr->timerPending)) { /* * There is an idle handler or a pending timer event, so just poll. */ blockTime.sec = 0; blockTime.usec = 0; } else if ((flags & TCL_TIMER_EVENTS) && tsdPtr->firstTimerHandlerPtr) { /* * Compute the timeout for the next timer on the list. */ Tcl_GetTime(&blockTime); blockTime.sec = tsdPtr->firstTimerHandlerPtr->time.sec - blockTime.sec; blockTime.usec = tsdPtr->firstTimerHandlerPtr->time.usec - blockTime.usec; if (blockTime.usec < 0) { blockTime.sec -= 1; blockTime.usec += 1000000; } if (blockTime.sec < 0) { blockTime.sec = 0; blockTime.usec = 0; } } else { return; } Tcl_SetMaxBlockTime(&blockTime); } /* *---------------------------------------------------------------------- * * TimerCheckProc -- * * This function is called by Tcl_DoOneEvent to check the timer * event source for events. This routine checks both the * idle and after timer lists. * * Results: * None. * * Side effects: * May queue an event and update the maximum notifier block time. * *---------------------------------------------------------------------- */ static void TimerCheckProc(data, flags) ClientData data; /* Not used. */ int flags; /* Event flags as passed to Tcl_DoOneEvent. */ { Tcl_Event *timerEvPtr; Tcl_Time blockTime; ThreadSpecificData *tsdPtr = InitTimer(); if ((flags & TCL_TIMER_EVENTS) && tsdPtr->firstTimerHandlerPtr) { /* * Compute the timeout for the next timer on the list. */ Tcl_GetTime(&blockTime); blockTime.sec = tsdPtr->firstTimerHandlerPtr->time.sec - blockTime.sec; blockTime.usec = tsdPtr->firstTimerHandlerPtr->time.usec - blockTime.usec; if (blockTime.usec < 0) { blockTime.sec -= 1; blockTime.usec += 1000000; } if (blockTime.sec < 0) { blockTime.sec = 0; blockTime.usec = 0; } /* * If the first timer has expired, stick an event on the queue. */ if (blockTime.sec == 0 && blockTime.usec == 0 && !tsdPtr->timerPending) { tsdPtr->timerPending = 1; timerEvPtr = (Tcl_Event *) ckalloc(sizeof(Tcl_Event)); timerEvPtr->proc = TimerHandlerEventProc; Tcl_QueueEvent(timerEvPtr, TCL_QUEUE_TAIL); } } } /* *---------------------------------------------------------------------- * * TimerHandlerEventProc -- * * This procedure is called by Tcl_ServiceEvent when a timer event * reaches the front of the event queue. This procedure handles * the event by invoking the callbacks for all timers that are * ready. * * Results: * Returns 1 if the event was handled, meaning it should be removed * from the queue. Returns 0 if the event was not handled, meaning * it should stay on the queue. The only time the event isn't * handled is if the TCL_TIMER_EVENTS flag bit isn't set. * * Side effects: * Whatever the timer handler callback procedures do. * *---------------------------------------------------------------------- */ static int TimerHandlerEventProc(evPtr, flags) Tcl_Event *evPtr; /* Event to service. */ int flags; /* Flags that indicate what events to * handle, such as TCL_FILE_EVENTS. */ { TimerHandler *timerHandlerPtr, **nextPtrPtr; Tcl_Time time; int currentTimerId; ThreadSpecificData *tsdPtr = InitTimer(); /* * Do nothing if timers aren't enabled. This leaves the event on the * queue, so we will get to it as soon as ServiceEvents() is called * with timers enabled. */ if (!(flags & TCL_TIMER_EVENTS)) { return 0; } /* * The code below is trickier than it may look, for the following * reasons: * * 1. New handlers can get added to the list while the current * one is being processed. If new ones get added, we don't * want to process them during this pass through the list to avoid * starving other event sources. This is implemented using the * token number in the handler: new handlers will have a * newer token than any of the ones currently on the list. * 2. The handler can call Tcl_DoOneEvent, so we have to remove * the handler from the list before calling it. Otherwise an * infinite loop could result. * 3. Tcl_DeleteTimerHandler can be called to remove an element from * the list while a handler is executing, so the list could * change structure during the call. * 4. Because we only fetch the current time before entering the loop, * the only way a new timer will even be considered runnable is if * its expiration time is within the same millisecond as the * current time. This is fairly likely on Windows, since it has * a course granularity clock. Since timers are placed * on the queue in time order with the most recently created * handler appearing after earlier ones with the same expiration * time, we don't have to worry about newer generation timers * appearing before later ones. */ tsdPtr->timerPending = 0; currentTimerId = tsdPtr->lastTimerId; Tcl_GetTime(&time); while (1) { nextPtrPtr = &tsdPtr->firstTimerHandlerPtr; timerHandlerPtr = tsdPtr->firstTimerHandlerPtr; if (timerHandlerPtr == NULL) { break; } if ((timerHandlerPtr->time.sec > time.sec) || ((timerHandlerPtr->time.sec == time.sec) && (timerHandlerPtr->time.usec > time.usec))) { break; } /* * Bail out if the next timer is of a newer generation. */ if ((currentTimerId - (int)timerHandlerPtr->token) < 0) { break; } /* * Remove the handler from the queue before invoking it, * to avoid potential reentrancy problems. */ (*nextPtrPtr) = timerHandlerPtr->nextPtr; (*timerHandlerPtr->proc)(timerHandlerPtr->clientData); ckfree((char *) timerHandlerPtr); } TimerSetupProc(NULL, TCL_TIMER_EVENTS); return 1; } /* *-------------------------------------------------------------- * * Tcl_DoWhenIdle -- * * Arrange for proc to be invoked the next time the system is * idle (i.e., just before the next time that Tcl_DoOneEvent * would have to wait for something to happen). * * Results: * None. * * Side effects: * Proc will eventually be called, with clientData as argument. * See the manual entry for details. * *-------------------------------------------------------------- */ void Tcl_DoWhenIdle(proc, clientData) Tcl_IdleProc *proc; /* Procedure to invoke. */ ClientData clientData; /* Arbitrary value to pass to proc. */ { register IdleHandler *idlePtr; Tcl_Time blockTime; ThreadSpecificData *tsdPtr = InitTimer(); idlePtr = (IdleHandler *) ckalloc(sizeof(IdleHandler)); idlePtr->proc = proc; idlePtr->clientData = clientData; idlePtr->generation = tsdPtr->idleGeneration; idlePtr->nextPtr = NULL; if (tsdPtr->lastIdlePtr == NULL) { tsdPtr->idleList = idlePtr; } else { tsdPtr->lastIdlePtr->nextPtr = idlePtr; } tsdPtr->lastIdlePtr = idlePtr; blockTime.sec = 0; blockTime.usec = 0; Tcl_SetMaxBlockTime(&blockTime); } /* *---------------------------------------------------------------------- * * Tcl_CancelIdleCall -- * * If there are any when-idle calls requested to a given procedure * with given clientData, cancel all of them. * * Results: * None. * * Side effects: * If the proc/clientData combination were on the when-idle list, * they are removed so that they will never be called. * *---------------------------------------------------------------------- */ void Tcl_CancelIdleCall(proc, clientData) Tcl_IdleProc *proc; /* Procedure that was previously registered. */ ClientData clientData; /* Arbitrary value to pass to proc. */ { register IdleHandler *idlePtr, *prevPtr; IdleHandler *nextPtr; ThreadSpecificData *tsdPtr = InitTimer(); for (prevPtr = NULL, idlePtr = tsdPtr->idleList; idlePtr != NULL; prevPtr = idlePtr, idlePtr = idlePtr->nextPtr) { while ((idlePtr->proc == proc) && (idlePtr->clientData == clientData)) { nextPtr = idlePtr->nextPtr; ckfree((char *) idlePtr); idlePtr = nextPtr; if (prevPtr == NULL) { tsdPtr->idleList = idlePtr; } else { prevPtr->nextPtr = idlePtr; } if (idlePtr == NULL) { tsdPtr->lastIdlePtr = prevPtr; return; } } } } /* *---------------------------------------------------------------------- * * TclServiceIdle -- * * This procedure is invoked by the notifier when it becomes * idle. It will invoke all idle handlers that are present at * the time the call is invoked, but not those added during idle * processing. * * Results: * The return value is 1 if TclServiceIdle found something to * do, otherwise return value is 0. * * Side effects: * Invokes all pending idle handlers. * *---------------------------------------------------------------------- */ int TclServiceIdle() { IdleHandler *idlePtr; int oldGeneration; Tcl_Time blockTime; ThreadSpecificData *tsdPtr = InitTimer(); if (tsdPtr->idleList == NULL) { return 0; } oldGeneration = tsdPtr->idleGeneration; tsdPtr->idleGeneration++; /* * The code below is trickier than it may look, for the following * reasons: * * 1. New handlers can get added to the list while the current * one is being processed. If new ones get added, we don't * want to process them during this pass through the list (want * to check for other work to do first). This is implemented * using the generation number in the handler: new handlers * will have a different generation than any of the ones currently * on the list. * 2. The handler can call Tcl_DoOneEvent, so we have to remove * the handler from the list before calling it. Otherwise an * infinite loop could result. * 3. Tcl_CancelIdleCall can be called to remove an element from * the list while a handler is executing, so the list could * change structure during the call. */ for (idlePtr = tsdPtr->idleList; ((idlePtr != NULL) && ((oldGeneration - idlePtr->generation) >= 0)); idlePtr = tsdPtr->idleList) { tsdPtr->idleList = idlePtr->nextPtr; if (tsdPtr->idleList == NULL) { tsdPtr->lastIdlePtr = NULL; } (*idlePtr->proc)(idlePtr->clientData); ckfree((char *) idlePtr); } if (tsdPtr->idleList) { blockTime.sec = 0; blockTime.usec = 0; Tcl_SetMaxBlockTime(&blockTime); } return 1; } /* *---------------------------------------------------------------------- * * Tcl_AfterObjCmd -- * * This procedure is invoked to process the "after" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_AfterObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Unused */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int ms; AfterInfo *afterPtr; AfterAssocData *assocPtr; int length; char *argString; int index; char buf[16 + TCL_INTEGER_SPACE]; static CONST char *afterSubCmds[] = { "cancel", "idle", "info", (char *) NULL }; enum afterSubCmds {AFTER_CANCEL, AFTER_IDLE, AFTER_INFO}; ThreadSpecificData *tsdPtr = InitTimer(); if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?"); return TCL_ERROR; } /* * Create the "after" information associated for this interpreter, * if it doesn't already exist. */ assocPtr = Tcl_GetAssocData( interp, "tclAfter", NULL ); if (assocPtr == NULL) { assocPtr = (AfterAssocData *) ckalloc(sizeof(AfterAssocData)); assocPtr->interp = interp; assocPtr->firstAfterPtr = NULL; Tcl_SetAssocData(interp, "tclAfter", AfterCleanupProc, (ClientData) assocPtr); } /* * First lets see if the command was passed a number as the first argument. */ if (objv[1]->typePtr == &tclIntType) { ms = (int) objv[1]->internalRep.longValue; goto processInteger; } argString = Tcl_GetStringFromObj(objv[1], &length); if (argString[0] == '+' || argString[0] == '-' || isdigit(UCHAR(argString[0]))) { /* INTL: digit */ if (Tcl_GetIntFromObj(interp, objv[1], &ms) != TCL_OK) { return TCL_ERROR; } processInteger: if (ms < 0) { ms = 0; } if (objc == 2) { Tcl_Sleep(ms); return TCL_OK; } afterPtr = (AfterInfo *) ckalloc((unsigned) (sizeof(AfterInfo))); afterPtr->assocPtr = assocPtr; if (objc == 3) { afterPtr->commandPtr = objv[2]; } else { afterPtr->commandPtr = Tcl_ConcatObj(objc-2, objv+2); } Tcl_IncrRefCount(afterPtr->commandPtr); /* * The variable below is used to generate unique identifiers for * after commands. This id can wrap around, which can potentially * cause problems. However, there are not likely to be problems * in practice, because after commands can only be requested to * about a month in the future, and wrap-around is unlikely to * occur in less than about 1-10 years. Thus it's unlikely that * any old ids will still be around when wrap-around occurs. */ afterPtr->id = tsdPtr->afterId; tsdPtr->afterId += 1; afterPtr->token = Tcl_CreateTimerHandler(ms, AfterProc, (ClientData) afterPtr); afterPtr->nextPtr = assocPtr->firstAfterPtr; assocPtr->firstAfterPtr = afterPtr; sprintf(buf, "after#%d", afterPtr->id); Tcl_AppendResult(interp, buf, (char *) NULL); return TCL_OK; } /* * If it's not a number it must be a subcommand. */ if (Tcl_GetIndexFromObj(NULL, objv[1], afterSubCmds, "argument", 0, &index) != TCL_OK) { Tcl_AppendResult(interp, "bad argument \"", argString, "\": must be cancel, idle, info, or a number", (char *) NULL); return TCL_ERROR; } switch ((enum afterSubCmds) index) { case AFTER_CANCEL: { Tcl_Obj *commandPtr; char *command, *tempCommand; int tempLength; if (objc < 3) { Tcl_WrongNumArgs(interp, 2, objv, "id|command"); return TCL_ERROR; } if (objc == 3) { commandPtr = objv[2]; } else { commandPtr = Tcl_ConcatObj(objc-2, objv+2);; } command = Tcl_GetStringFromObj(commandPtr, &length); for (afterPtr = assocPtr->firstAfterPtr; afterPtr != NULL; afterPtr = afterPtr->nextPtr) { tempCommand = Tcl_GetStringFromObj(afterPtr->commandPtr, &tempLength); if ((length == tempLength) && (memcmp((void*) command, (void*) tempCommand, (unsigned) length) == 0)) { break; } } if (afterPtr == NULL) { afterPtr = GetAfterEvent(assocPtr, commandPtr); } if (objc != 3) { Tcl_DecrRefCount(commandPtr); } if (afterPtr != NULL) { if (afterPtr->token != NULL) { Tcl_DeleteTimerHandler(afterPtr->token); } else { Tcl_CancelIdleCall(AfterProc, (ClientData) afterPtr); } FreeAfterPtr(afterPtr); } break; } case AFTER_IDLE: if (objc < 3) { Tcl_WrongNumArgs(interp, 2, objv, "script script ..."); return TCL_ERROR; } afterPtr = (AfterInfo *) ckalloc((unsigned) (sizeof(AfterInfo))); afterPtr->assocPtr = assocPtr; if (objc == 3) { afterPtr->commandPtr = objv[2]; } else { afterPtr->commandPtr = Tcl_ConcatObj(objc-2, objv+2); } Tcl_IncrRefCount(afterPtr->commandPtr); afterPtr->id = tsdPtr->afterId; tsdPtr->afterId += 1; afterPtr->token = NULL; afterPtr->nextPtr = assocPtr->firstAfterPtr; assocPtr->firstAfterPtr = afterPtr; Tcl_DoWhenIdle(AfterProc, (ClientData) afterPtr); sprintf(buf, "after#%d", afterPtr->id); Tcl_AppendResult(interp, buf, (char *) NULL); break; case AFTER_INFO: { Tcl_Obj *resultListPtr; if (objc == 2) { for (afterPtr = assocPtr->firstAfterPtr; afterPtr != NULL; afterPtr = afterPtr->nextPtr) { if (assocPtr->interp == interp) { sprintf(buf, "after#%d", afterPtr->id); Tcl_AppendElement(interp, buf); } } return TCL_OK; } if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "?id?"); return TCL_ERROR; } afterPtr = GetAfterEvent(assocPtr, objv[2]); if (afterPtr == NULL) { Tcl_AppendResult(interp, "event \"", Tcl_GetString(objv[2]), "\" doesn't exist", (char *) NULL); return TCL_ERROR; } resultListPtr = Tcl_GetObjResult(interp); Tcl_ListObjAppendElement(interp, resultListPtr, afterPtr->commandPtr); Tcl_ListObjAppendElement(interp, resultListPtr, Tcl_NewStringObj( (afterPtr->token == NULL) ? "idle" : "timer", -1)); Tcl_SetObjResult(interp, resultListPtr); break; } default: { panic("Tcl_AfterObjCmd: bad subcommand index to afterSubCmds"); } } return TCL_OK; } /* *---------------------------------------------------------------------- * * GetAfterEvent -- * * This procedure parses an "after" id such as "after#4" and * returns a pointer to the AfterInfo structure. * * Results: * The return value is either a pointer to an AfterInfo structure, * if one is found that corresponds to "cmdString" and is for interp, * or NULL if no corresponding after event can be found. * * Side effects: * None. * *---------------------------------------------------------------------- */ static AfterInfo * GetAfterEvent(assocPtr, commandPtr) AfterAssocData *assocPtr; /* Points to "after"-related information for * this interpreter. */ Tcl_Obj *commandPtr; { char *cmdString; /* Textual identifier for after event, such * as "after#6". */ AfterInfo *afterPtr; int id; char *end; cmdString = Tcl_GetString(commandPtr); if (strncmp(cmdString, "after#", 6) != 0) { return NULL; } cmdString += 6; id = strtoul(cmdString, &end, 10); if ((end == cmdString) || (*end != 0)) { return NULL; } for (afterPtr = assocPtr->firstAfterPtr; afterPtr != NULL; afterPtr = afterPtr->nextPtr) { if (afterPtr->id == id) { return afterPtr; } } return NULL; } /* *---------------------------------------------------------------------- * * AfterProc -- * * Timer callback to execute commands registered with the * "after" command. * * Results: * None. * * Side effects: * Executes whatever command was specified. If the command * returns an error, then the command "bgerror" is invoked * to process the error; if bgerror fails then information * about the error is output on stderr. * *---------------------------------------------------------------------- */ static void AfterProc(clientData) ClientData clientData; /* Describes command to execute. */ { AfterInfo *afterPtr = (AfterInfo *) clientData; AfterAssocData *assocPtr = afterPtr->assocPtr; AfterInfo *prevPtr; int result; Tcl_Interp *interp; char *script; int numBytes; /* * First remove the callback from our list of callbacks; otherwise * someone could delete the callback while it's being executed, which * could cause a core dump. */ if (assocPtr->firstAfterPtr == afterPtr) { assocPtr->firstAfterPtr = afterPtr->nextPtr; } else { for (prevPtr = assocPtr->firstAfterPtr; prevPtr->nextPtr != afterPtr; prevPtr = prevPtr->nextPtr) { /* Empty loop body. */ } prevPtr->nextPtr = afterPtr->nextPtr; } /* * Execute the callback. */ interp = assocPtr->interp; Tcl_Preserve((ClientData) interp); script = Tcl_GetStringFromObj(afterPtr->commandPtr, &numBytes); result = Tcl_EvalEx(interp, script, numBytes, TCL_EVAL_GLOBAL); if (result != TCL_OK) { Tcl_AddErrorInfo(interp, "\n (\"after\" script)"); Tcl_BackgroundError(interp); } Tcl_Release((ClientData) interp); /* * Free the memory for the callback. */ Tcl_DecrRefCount(afterPtr->commandPtr); ckfree((char *) afterPtr); } /* *---------------------------------------------------------------------- * * FreeAfterPtr -- * * This procedure removes an "after" command from the list of * those that are pending and frees its resources. This procedure * does *not* cancel the timer handler; if that's needed, the * caller must do it. * * Results: * None. * * Side effects: * The memory associated with afterPtr is released. * *---------------------------------------------------------------------- */ static void FreeAfterPtr(afterPtr) AfterInfo *afterPtr; /* Command to be deleted. */ { AfterInfo *prevPtr; AfterAssocData *assocPtr = afterPtr->assocPtr; if (assocPtr->firstAfterPtr == afterPtr) { assocPtr->firstAfterPtr = afterPtr->nextPtr; } else { for (prevPtr = assocPtr->firstAfterPtr; prevPtr->nextPtr != afterPtr; prevPtr = prevPtr->nextPtr) { /* Empty loop body. */ } prevPtr->nextPtr = afterPtr->nextPtr; } Tcl_DecrRefCount(afterPtr->commandPtr); ckfree((char *) afterPtr); } /* *---------------------------------------------------------------------- * * AfterCleanupProc -- * * This procedure is invoked whenever an interpreter is deleted * to cleanup the AssocData for "tclAfter". * * Results: * None. * * Side effects: * After commands are removed. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static void AfterCleanupProc(clientData, interp) ClientData clientData; /* Points to AfterAssocData for the * interpreter. */ Tcl_Interp *interp; /* Interpreter that is being deleted. */ { AfterAssocData *assocPtr = (AfterAssocData *) clientData; AfterInfo *afterPtr; while (assocPtr->firstAfterPtr != NULL) { afterPtr = assocPtr->firstAfterPtr; assocPtr->firstAfterPtr = afterPtr->nextPtr; if (afterPtr->token != NULL) { Tcl_DeleteTimerHandler(afterPtr->token); } else { Tcl_CancelIdleCall(AfterProc, (ClientData) afterPtr); } Tcl_DecrRefCount(afterPtr->commandPtr); ckfree((char *) afterPtr); } ckfree((char *) assocPtr); } tcl8.4.20/generic/tclDecls.h0000644003604700454610000051650612144442333014244 0ustar dgp771div/* * tclDecls.h -- * * Declarations of functions in the platform independent public Tcl API. * * Copyright (c) 1998-1999 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef _TCLDECLS #define _TCLDECLS /* * WARNING: This file is automatically generated by the tools/genStubs.tcl * script. Any modifications to the function declarations below should be made * in the generic/tcl.decls script. */ /* !BEGIN!: Do not edit below this line. */ /* * Exported function declarations: */ /* 0 */ EXTERN int Tcl_PkgProvideEx _ANSI_ARGS_((Tcl_Interp *interp, CONST char *name, CONST char *version, ClientData clientData)); /* 1 */ EXTERN CONST84_RETURN char * Tcl_PkgRequireEx _ANSI_ARGS_(( Tcl_Interp *interp, CONST char *name, CONST char *version, int exact, ClientData *clientDataPtr)); /* 2 */ EXTERN void Tcl_Panic _ANSI_ARGS_(TCL_VARARGS(CONST char *,format)); /* 3 */ EXTERN char * Tcl_Alloc _ANSI_ARGS_((unsigned int size)); /* 4 */ EXTERN void Tcl_Free _ANSI_ARGS_((char *ptr)); /* 5 */ EXTERN char * Tcl_Realloc _ANSI_ARGS_((char *ptr, unsigned int size)); /* 6 */ EXTERN char * Tcl_DbCkalloc _ANSI_ARGS_((unsigned int size, CONST char *file, int line)); /* 7 */ EXTERN void Tcl_DbCkfree _ANSI_ARGS_((char *ptr, CONST char *file, int line)); /* 8 */ EXTERN char * Tcl_DbCkrealloc _ANSI_ARGS_((char *ptr, unsigned int size, CONST char *file, int line)); #if !defined(__WIN32__) && !defined(MAC_OSX_TCL) /* UNIX */ /* 9 */ EXTERN void Tcl_CreateFileHandler _ANSI_ARGS_((int fd, int mask, Tcl_FileProc *proc, ClientData clientData)); #endif /* UNIX */ #ifdef MAC_OSX_TCL /* MACOSX */ /* 9 */ EXTERN void Tcl_CreateFileHandler _ANSI_ARGS_((int fd, int mask, Tcl_FileProc *proc, ClientData clientData)); #endif /* MACOSX */ #if !defined(__WIN32__) && !defined(MAC_OSX_TCL) /* UNIX */ /* 10 */ EXTERN void Tcl_DeleteFileHandler _ANSI_ARGS_((int fd)); #endif /* UNIX */ #ifdef MAC_OSX_TCL /* MACOSX */ /* 10 */ EXTERN void Tcl_DeleteFileHandler _ANSI_ARGS_((int fd)); #endif /* MACOSX */ /* 11 */ EXTERN void Tcl_SetTimer _ANSI_ARGS_((Tcl_Time *timePtr)); /* 12 */ EXTERN void Tcl_Sleep _ANSI_ARGS_((int ms)); /* 13 */ EXTERN int Tcl_WaitForEvent _ANSI_ARGS_((Tcl_Time *timePtr)); /* 14 */ EXTERN int Tcl_AppendAllObjTypes _ANSI_ARGS_(( Tcl_Interp *interp, Tcl_Obj *objPtr)); /* 15 */ EXTERN void Tcl_AppendStringsToObj _ANSI_ARGS_(TCL_VARARGS(Tcl_Obj *,objPtr)); /* 16 */ EXTERN void Tcl_AppendToObj _ANSI_ARGS_((Tcl_Obj *objPtr, CONST char *bytes, int length)); /* 17 */ EXTERN Tcl_Obj * Tcl_ConcatObj _ANSI_ARGS_((int objc, Tcl_Obj *CONST objv[])); /* 18 */ EXTERN int Tcl_ConvertToType _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_ObjType *typePtr)); /* 19 */ EXTERN void Tcl_DbDecrRefCount _ANSI_ARGS_((Tcl_Obj *objPtr, CONST char *file, int line)); /* 20 */ EXTERN void Tcl_DbIncrRefCount _ANSI_ARGS_((Tcl_Obj *objPtr, CONST char *file, int line)); /* 21 */ EXTERN int Tcl_DbIsShared _ANSI_ARGS_((Tcl_Obj *objPtr, CONST char *file, int line)); /* 22 */ EXTERN Tcl_Obj * Tcl_DbNewBooleanObj _ANSI_ARGS_((int boolValue, CONST char *file, int line)); /* 23 */ EXTERN Tcl_Obj * Tcl_DbNewByteArrayObj _ANSI_ARGS_(( CONST unsigned char *bytes, int length, CONST char *file, int line)); /* 24 */ EXTERN Tcl_Obj * Tcl_DbNewDoubleObj _ANSI_ARGS_((double doubleValue, CONST char *file, int line)); /* 25 */ EXTERN Tcl_Obj * Tcl_DbNewListObj _ANSI_ARGS_((int objc, Tcl_Obj *CONST *objv, CONST char *file, int line)); /* 26 */ EXTERN Tcl_Obj * Tcl_DbNewLongObj _ANSI_ARGS_((long longValue, CONST char *file, int line)); /* 27 */ EXTERN Tcl_Obj * Tcl_DbNewObj _ANSI_ARGS_((CONST char *file, int line)); /* 28 */ EXTERN Tcl_Obj * Tcl_DbNewStringObj _ANSI_ARGS_((CONST char *bytes, int length, CONST char *file, int line)); /* 29 */ EXTERN Tcl_Obj * Tcl_DuplicateObj _ANSI_ARGS_((Tcl_Obj *objPtr)); /* 30 */ EXTERN void TclFreeObj _ANSI_ARGS_((Tcl_Obj *objPtr)); /* 31 */ EXTERN int Tcl_GetBoolean _ANSI_ARGS_((Tcl_Interp *interp, CONST char *src, int *boolPtr)); /* 32 */ EXTERN int Tcl_GetBooleanFromObj _ANSI_ARGS_(( Tcl_Interp *interp, Tcl_Obj *objPtr, int *boolPtr)); /* 33 */ EXTERN unsigned char * Tcl_GetByteArrayFromObj _ANSI_ARGS_((Tcl_Obj *objPtr, int *lengthPtr)); /* 34 */ EXTERN int Tcl_GetDouble _ANSI_ARGS_((Tcl_Interp *interp, CONST char *src, double *doublePtr)); /* 35 */ EXTERN int Tcl_GetDoubleFromObj _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr, double *doublePtr)); /* 36 */ EXTERN int Tcl_GetIndexFromObj _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr, CONST84 char **tablePtr, CONST char *msg, int flags, int *indexPtr)); /* 37 */ EXTERN int Tcl_GetInt _ANSI_ARGS_((Tcl_Interp *interp, CONST char *src, int *intPtr)); /* 38 */ EXTERN int Tcl_GetIntFromObj _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr, int *intPtr)); /* 39 */ EXTERN int Tcl_GetLongFromObj _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr, long *longPtr)); /* 40 */ EXTERN Tcl_ObjType * Tcl_GetObjType _ANSI_ARGS_((CONST char *typeName)); /* 41 */ EXTERN char * Tcl_GetStringFromObj _ANSI_ARGS_((Tcl_Obj *objPtr, int *lengthPtr)); /* 42 */ EXTERN void Tcl_InvalidateStringRep _ANSI_ARGS_((Tcl_Obj *objPtr)); /* 43 */ EXTERN int Tcl_ListObjAppendList _ANSI_ARGS_(( Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Obj *elemListPtr)); /* 44 */ EXTERN int Tcl_ListObjAppendElement _ANSI_ARGS_(( Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Obj *objPtr)); /* 45 */ EXTERN int Tcl_ListObjGetElements _ANSI_ARGS_(( Tcl_Interp *interp, Tcl_Obj *listPtr, int *objcPtr, Tcl_Obj ***objvPtr)); /* 46 */ EXTERN int Tcl_ListObjIndex _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *listPtr, int index, Tcl_Obj **objPtrPtr)); /* 47 */ EXTERN int Tcl_ListObjLength _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *listPtr, int *lengthPtr)); /* 48 */ EXTERN int Tcl_ListObjReplace _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *listPtr, int first, int count, int objc, Tcl_Obj *CONST objv[])); /* 49 */ EXTERN Tcl_Obj * Tcl_NewBooleanObj _ANSI_ARGS_((int boolValue)); /* 50 */ EXTERN Tcl_Obj * Tcl_NewByteArrayObj _ANSI_ARGS_(( CONST unsigned char *bytes, int length)); /* 51 */ EXTERN Tcl_Obj * Tcl_NewDoubleObj _ANSI_ARGS_((double doubleValue)); /* 52 */ EXTERN Tcl_Obj * Tcl_NewIntObj _ANSI_ARGS_((int intValue)); /* 53 */ EXTERN Tcl_Obj * Tcl_NewListObj _ANSI_ARGS_((int objc, Tcl_Obj *CONST objv[])); /* 54 */ EXTERN Tcl_Obj * Tcl_NewLongObj _ANSI_ARGS_((long longValue)); /* 55 */ EXTERN Tcl_Obj * Tcl_NewObj _ANSI_ARGS_((void)); /* 56 */ EXTERN Tcl_Obj * Tcl_NewStringObj _ANSI_ARGS_((CONST char *bytes, int length)); /* 57 */ EXTERN void Tcl_SetBooleanObj _ANSI_ARGS_((Tcl_Obj *objPtr, int boolValue)); /* 58 */ EXTERN unsigned char * Tcl_SetByteArrayLength _ANSI_ARGS_((Tcl_Obj *objPtr, int length)); /* 59 */ EXTERN void Tcl_SetByteArrayObj _ANSI_ARGS_((Tcl_Obj *objPtr, CONST unsigned char *bytes, int length)); /* 60 */ EXTERN void Tcl_SetDoubleObj _ANSI_ARGS_((Tcl_Obj *objPtr, double doubleValue)); /* 61 */ EXTERN void Tcl_SetIntObj _ANSI_ARGS_((Tcl_Obj *objPtr, int intValue)); /* 62 */ EXTERN void Tcl_SetListObj _ANSI_ARGS_((Tcl_Obj *objPtr, int objc, Tcl_Obj *CONST objv[])); /* 63 */ EXTERN void Tcl_SetLongObj _ANSI_ARGS_((Tcl_Obj *objPtr, long longValue)); /* 64 */ EXTERN void Tcl_SetObjLength _ANSI_ARGS_((Tcl_Obj *objPtr, int length)); /* 65 */ EXTERN void Tcl_SetStringObj _ANSI_ARGS_((Tcl_Obj *objPtr, CONST char *bytes, int length)); /* 66 */ EXTERN void Tcl_AddErrorInfo _ANSI_ARGS_((Tcl_Interp *interp, CONST char *message)); /* 67 */ EXTERN void Tcl_AddObjErrorInfo _ANSI_ARGS_((Tcl_Interp *interp, CONST char *message, int length)); /* 68 */ EXTERN void Tcl_AllowExceptions _ANSI_ARGS_((Tcl_Interp *interp)); /* 69 */ EXTERN void Tcl_AppendElement _ANSI_ARGS_((Tcl_Interp *interp, CONST char *element)); /* 70 */ EXTERN void Tcl_AppendResult _ANSI_ARGS_(TCL_VARARGS(Tcl_Interp *,interp)); /* 71 */ EXTERN Tcl_AsyncHandler Tcl_AsyncCreate _ANSI_ARGS_((Tcl_AsyncProc *proc, ClientData clientData)); /* 72 */ EXTERN void Tcl_AsyncDelete _ANSI_ARGS_((Tcl_AsyncHandler async)); /* 73 */ EXTERN int Tcl_AsyncInvoke _ANSI_ARGS_((Tcl_Interp *interp, int code)); /* 74 */ EXTERN void Tcl_AsyncMark _ANSI_ARGS_((Tcl_AsyncHandler async)); /* 75 */ EXTERN int Tcl_AsyncReady _ANSI_ARGS_((void)); /* 76 */ EXTERN void Tcl_BackgroundError _ANSI_ARGS_((Tcl_Interp *interp)); /* 77 */ EXTERN char Tcl_Backslash _ANSI_ARGS_((CONST char *src, int *readPtr)); /* 78 */ EXTERN int Tcl_BadChannelOption _ANSI_ARGS_((Tcl_Interp *interp, CONST char *optionName, CONST char *optionList)); /* 79 */ EXTERN void Tcl_CallWhenDeleted _ANSI_ARGS_((Tcl_Interp *interp, Tcl_InterpDeleteProc *proc, ClientData clientData)); /* 80 */ EXTERN void Tcl_CancelIdleCall _ANSI_ARGS_(( Tcl_IdleProc *idleProc, ClientData clientData)); /* 81 */ EXTERN int Tcl_Close _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Channel chan)); /* 82 */ EXTERN int Tcl_CommandComplete _ANSI_ARGS_((CONST char *cmd)); /* 83 */ EXTERN char * Tcl_Concat _ANSI_ARGS_((int argc, CONST84 char *CONST *argv)); /* 84 */ EXTERN int Tcl_ConvertElement _ANSI_ARGS_((CONST char *src, char *dst, int flags)); /* 85 */ EXTERN int Tcl_ConvertCountedElement _ANSI_ARGS_(( CONST char *src, int length, char *dst, int flags)); /* 86 */ EXTERN int Tcl_CreateAlias _ANSI_ARGS_((Tcl_Interp *slave, CONST char *slaveCmd, Tcl_Interp *target, CONST char *targetCmd, int argc, CONST84 char *CONST *argv)); /* 87 */ EXTERN int Tcl_CreateAliasObj _ANSI_ARGS_((Tcl_Interp *slave, CONST char *slaveCmd, Tcl_Interp *target, CONST char *targetCmd, int objc, Tcl_Obj *CONST objv[])); /* 88 */ EXTERN Tcl_Channel Tcl_CreateChannel _ANSI_ARGS_(( Tcl_ChannelType *typePtr, CONST char *chanName, ClientData instanceData, int mask)); /* 89 */ EXTERN void Tcl_CreateChannelHandler _ANSI_ARGS_(( Tcl_Channel chan, int mask, Tcl_ChannelProc *proc, ClientData clientData)); /* 90 */ EXTERN void Tcl_CreateCloseHandler _ANSI_ARGS_((Tcl_Channel chan, Tcl_CloseProc *proc, ClientData clientData)); /* 91 */ EXTERN Tcl_Command Tcl_CreateCommand _ANSI_ARGS_((Tcl_Interp *interp, CONST char *cmdName, Tcl_CmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *deleteProc)); /* 92 */ EXTERN void Tcl_CreateEventSource _ANSI_ARGS_(( Tcl_EventSetupProc *setupProc, Tcl_EventCheckProc *checkProc, ClientData clientData)); /* 93 */ EXTERN void Tcl_CreateExitHandler _ANSI_ARGS_(( Tcl_ExitProc *proc, ClientData clientData)); /* 94 */ EXTERN Tcl_Interp * Tcl_CreateInterp _ANSI_ARGS_((void)); /* 95 */ EXTERN void Tcl_CreateMathFunc _ANSI_ARGS_((Tcl_Interp *interp, CONST char *name, int numArgs, Tcl_ValueType *argTypes, Tcl_MathProc *proc, ClientData clientData)); /* 96 */ EXTERN Tcl_Command Tcl_CreateObjCommand _ANSI_ARGS_((Tcl_Interp *interp, CONST char *cmdName, Tcl_ObjCmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *deleteProc)); /* 97 */ EXTERN Tcl_Interp * Tcl_CreateSlave _ANSI_ARGS_((Tcl_Interp *interp, CONST char *slaveName, int isSafe)); /* 98 */ EXTERN Tcl_TimerToken Tcl_CreateTimerHandler _ANSI_ARGS_((int milliseconds, Tcl_TimerProc *proc, ClientData clientData)); /* 99 */ EXTERN Tcl_Trace Tcl_CreateTrace _ANSI_ARGS_((Tcl_Interp *interp, int level, Tcl_CmdTraceProc *proc, ClientData clientData)); /* 100 */ EXTERN void Tcl_DeleteAssocData _ANSI_ARGS_((Tcl_Interp *interp, CONST char *name)); /* 101 */ EXTERN void Tcl_DeleteChannelHandler _ANSI_ARGS_(( Tcl_Channel chan, Tcl_ChannelProc *proc, ClientData clientData)); /* 102 */ EXTERN void Tcl_DeleteCloseHandler _ANSI_ARGS_((Tcl_Channel chan, Tcl_CloseProc *proc, ClientData clientData)); /* 103 */ EXTERN int Tcl_DeleteCommand _ANSI_ARGS_((Tcl_Interp *interp, CONST char *cmdName)); /* 104 */ EXTERN int Tcl_DeleteCommandFromToken _ANSI_ARGS_(( Tcl_Interp *interp, Tcl_Command command)); /* 105 */ EXTERN void Tcl_DeleteEvents _ANSI_ARGS_(( Tcl_EventDeleteProc *proc, ClientData clientData)); /* 106 */ EXTERN void Tcl_DeleteEventSource _ANSI_ARGS_(( Tcl_EventSetupProc *setupProc, Tcl_EventCheckProc *checkProc, ClientData clientData)); /* 107 */ EXTERN void Tcl_DeleteExitHandler _ANSI_ARGS_(( Tcl_ExitProc *proc, ClientData clientData)); /* 108 */ EXTERN void Tcl_DeleteHashEntry _ANSI_ARGS_(( Tcl_HashEntry *entryPtr)); /* 109 */ EXTERN void Tcl_DeleteHashTable _ANSI_ARGS_(( Tcl_HashTable *tablePtr)); /* 110 */ EXTERN void Tcl_DeleteInterp _ANSI_ARGS_((Tcl_Interp *interp)); /* 111 */ EXTERN void Tcl_DetachPids _ANSI_ARGS_((int numPids, Tcl_Pid *pidPtr)); /* 112 */ EXTERN void Tcl_DeleteTimerHandler _ANSI_ARGS_(( Tcl_TimerToken token)); /* 113 */ EXTERN void Tcl_DeleteTrace _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Trace trace)); /* 114 */ EXTERN void Tcl_DontCallWhenDeleted _ANSI_ARGS_(( Tcl_Interp *interp, Tcl_InterpDeleteProc *proc, ClientData clientData)); /* 115 */ EXTERN int Tcl_DoOneEvent _ANSI_ARGS_((int flags)); /* 116 */ EXTERN void Tcl_DoWhenIdle _ANSI_ARGS_((Tcl_IdleProc *proc, ClientData clientData)); /* 117 */ EXTERN char * Tcl_DStringAppend _ANSI_ARGS_((Tcl_DString *dsPtr, CONST char *bytes, int length)); /* 118 */ EXTERN char * Tcl_DStringAppendElement _ANSI_ARGS_(( Tcl_DString *dsPtr, CONST char *element)); /* 119 */ EXTERN void Tcl_DStringEndSublist _ANSI_ARGS_(( Tcl_DString *dsPtr)); /* 120 */ EXTERN void Tcl_DStringFree _ANSI_ARGS_((Tcl_DString *dsPtr)); /* 121 */ EXTERN void Tcl_DStringGetResult _ANSI_ARGS_((Tcl_Interp *interp, Tcl_DString *dsPtr)); /* 122 */ EXTERN void Tcl_DStringInit _ANSI_ARGS_((Tcl_DString *dsPtr)); /* 123 */ EXTERN void Tcl_DStringResult _ANSI_ARGS_((Tcl_Interp *interp, Tcl_DString *dsPtr)); /* 124 */ EXTERN void Tcl_DStringSetLength _ANSI_ARGS_((Tcl_DString *dsPtr, int length)); /* 125 */ EXTERN void Tcl_DStringStartSublist _ANSI_ARGS_(( Tcl_DString *dsPtr)); /* 126 */ EXTERN int Tcl_Eof _ANSI_ARGS_((Tcl_Channel chan)); /* 127 */ EXTERN CONST84_RETURN char * Tcl_ErrnoId _ANSI_ARGS_((void)); /* 128 */ EXTERN CONST84_RETURN char * Tcl_ErrnoMsg _ANSI_ARGS_((int err)); /* 129 */ EXTERN int Tcl_Eval _ANSI_ARGS_((Tcl_Interp *interp, CONST char *script)); /* 130 */ EXTERN int Tcl_EvalFile _ANSI_ARGS_((Tcl_Interp *interp, CONST char *fileName)); /* 131 */ EXTERN int Tcl_EvalObj _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr)); /* 132 */ EXTERN void Tcl_EventuallyFree _ANSI_ARGS_(( ClientData clientData, Tcl_FreeProc *freeProc)); /* 133 */ EXTERN void Tcl_Exit _ANSI_ARGS_((int status)); /* 134 */ EXTERN int Tcl_ExposeCommand _ANSI_ARGS_((Tcl_Interp *interp, CONST char *hiddenCmdToken, CONST char *cmdName)); /* 135 */ EXTERN int Tcl_ExprBoolean _ANSI_ARGS_((Tcl_Interp *interp, CONST char *expr, int *ptr)); /* 136 */ EXTERN int Tcl_ExprBooleanObj _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr, int *ptr)); /* 137 */ EXTERN int Tcl_ExprDouble _ANSI_ARGS_((Tcl_Interp *interp, CONST char *expr, double *ptr)); /* 138 */ EXTERN int Tcl_ExprDoubleObj _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr, double *ptr)); /* 139 */ EXTERN int Tcl_ExprLong _ANSI_ARGS_((Tcl_Interp *interp, CONST char *expr, long *ptr)); /* 140 */ EXTERN int Tcl_ExprLongObj _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr, long *ptr)); /* 141 */ EXTERN int Tcl_ExprObj _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Obj **resultPtrPtr)); /* 142 */ EXTERN int Tcl_ExprString _ANSI_ARGS_((Tcl_Interp *interp, CONST char *expr)); /* 143 */ EXTERN void Tcl_Finalize _ANSI_ARGS_((void)); /* 144 */ EXTERN void Tcl_FindExecutable _ANSI_ARGS_((CONST char *argv0)); /* 145 */ EXTERN Tcl_HashEntry * Tcl_FirstHashEntry _ANSI_ARGS_(( Tcl_HashTable *tablePtr, Tcl_HashSearch *searchPtr)); /* 146 */ EXTERN int Tcl_Flush _ANSI_ARGS_((Tcl_Channel chan)); /* 147 */ EXTERN void Tcl_FreeResult _ANSI_ARGS_((Tcl_Interp *interp)); /* 148 */ EXTERN int Tcl_GetAlias _ANSI_ARGS_((Tcl_Interp *interp, CONST char *slaveCmd, Tcl_Interp **targetInterpPtr, CONST84 char **targetCmdPtr, int *argcPtr, CONST84 char ***argvPtr)); /* 149 */ EXTERN int Tcl_GetAliasObj _ANSI_ARGS_((Tcl_Interp *interp, CONST char *slaveCmd, Tcl_Interp **targetInterpPtr, CONST84 char **targetCmdPtr, int *objcPtr, Tcl_Obj ***objv)); /* 150 */ EXTERN ClientData Tcl_GetAssocData _ANSI_ARGS_((Tcl_Interp *interp, CONST char *name, Tcl_InterpDeleteProc **procPtr)); /* 151 */ EXTERN Tcl_Channel Tcl_GetChannel _ANSI_ARGS_((Tcl_Interp *interp, CONST char *chanName, int *modePtr)); /* 152 */ EXTERN int Tcl_GetChannelBufferSize _ANSI_ARGS_(( Tcl_Channel chan)); /* 153 */ EXTERN int Tcl_GetChannelHandle _ANSI_ARGS_((Tcl_Channel chan, int direction, ClientData *handlePtr)); /* 154 */ EXTERN ClientData Tcl_GetChannelInstanceData _ANSI_ARGS_(( Tcl_Channel chan)); /* 155 */ EXTERN int Tcl_GetChannelMode _ANSI_ARGS_((Tcl_Channel chan)); /* 156 */ EXTERN CONST84_RETURN char * Tcl_GetChannelName _ANSI_ARGS_(( Tcl_Channel chan)); /* 157 */ EXTERN int Tcl_GetChannelOption _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Channel chan, CONST char *optionName, Tcl_DString *dsPtr)); /* 158 */ EXTERN Tcl_ChannelType * Tcl_GetChannelType _ANSI_ARGS_((Tcl_Channel chan)); /* 159 */ EXTERN int Tcl_GetCommandInfo _ANSI_ARGS_((Tcl_Interp *interp, CONST char *cmdName, Tcl_CmdInfo *infoPtr)); /* 160 */ EXTERN CONST84_RETURN char * Tcl_GetCommandName _ANSI_ARGS_(( Tcl_Interp *interp, Tcl_Command command)); /* 161 */ EXTERN int Tcl_GetErrno _ANSI_ARGS_((void)); /* 162 */ EXTERN CONST84_RETURN char * Tcl_GetHostName _ANSI_ARGS_((void)); /* 163 */ EXTERN int Tcl_GetInterpPath _ANSI_ARGS_((Tcl_Interp *askInterp, Tcl_Interp *slaveInterp)); /* 164 */ EXTERN Tcl_Interp * Tcl_GetMaster _ANSI_ARGS_((Tcl_Interp *interp)); /* 165 */ EXTERN CONST char * Tcl_GetNameOfExecutable _ANSI_ARGS_((void)); /* 166 */ EXTERN Tcl_Obj * Tcl_GetObjResult _ANSI_ARGS_((Tcl_Interp *interp)); #if !defined(__WIN32__) && !defined(MAC_OSX_TCL) /* UNIX */ /* 167 */ EXTERN int Tcl_GetOpenFile _ANSI_ARGS_((Tcl_Interp *interp, CONST char *chanID, int forWriting, int checkUsage, ClientData *filePtr)); #endif /* UNIX */ #ifdef MAC_OSX_TCL /* MACOSX */ /* 167 */ EXTERN int Tcl_GetOpenFile _ANSI_ARGS_((Tcl_Interp *interp, CONST char *chanID, int forWriting, int checkUsage, ClientData *filePtr)); #endif /* MACOSX */ /* 168 */ EXTERN Tcl_PathType Tcl_GetPathType _ANSI_ARGS_((CONST char *path)); /* 169 */ EXTERN int Tcl_Gets _ANSI_ARGS_((Tcl_Channel chan, Tcl_DString *dsPtr)); /* 170 */ EXTERN int Tcl_GetsObj _ANSI_ARGS_((Tcl_Channel chan, Tcl_Obj *objPtr)); /* 171 */ EXTERN int Tcl_GetServiceMode _ANSI_ARGS_((void)); /* 172 */ EXTERN Tcl_Interp * Tcl_GetSlave _ANSI_ARGS_((Tcl_Interp *interp, CONST char *slaveName)); /* 173 */ EXTERN Tcl_Channel Tcl_GetStdChannel _ANSI_ARGS_((int type)); /* 174 */ EXTERN CONST84_RETURN char * Tcl_GetStringResult _ANSI_ARGS_(( Tcl_Interp *interp)); /* 175 */ EXTERN CONST84_RETURN char * Tcl_GetVar _ANSI_ARGS_((Tcl_Interp *interp, CONST char *varName, int flags)); /* 176 */ EXTERN CONST84_RETURN char * Tcl_GetVar2 _ANSI_ARGS_((Tcl_Interp *interp, CONST char *part1, CONST char *part2, int flags)); /* 177 */ EXTERN int Tcl_GlobalEval _ANSI_ARGS_((Tcl_Interp *interp, CONST char *command)); /* 178 */ EXTERN int Tcl_GlobalEvalObj _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr)); /* 179 */ EXTERN int Tcl_HideCommand _ANSI_ARGS_((Tcl_Interp *interp, CONST char *cmdName, CONST char *hiddenCmdToken)); /* 180 */ EXTERN int Tcl_Init _ANSI_ARGS_((Tcl_Interp *interp)); /* 181 */ EXTERN void Tcl_InitHashTable _ANSI_ARGS_(( Tcl_HashTable *tablePtr, int keyType)); /* 182 */ EXTERN int Tcl_InputBlocked _ANSI_ARGS_((Tcl_Channel chan)); /* 183 */ EXTERN int Tcl_InputBuffered _ANSI_ARGS_((Tcl_Channel chan)); /* 184 */ EXTERN int Tcl_InterpDeleted _ANSI_ARGS_((Tcl_Interp *interp)); /* 185 */ EXTERN int Tcl_IsSafe _ANSI_ARGS_((Tcl_Interp *interp)); /* 186 */ EXTERN char * Tcl_JoinPath _ANSI_ARGS_((int argc, CONST84 char *CONST *argv, Tcl_DString *resultPtr)); /* 187 */ EXTERN int Tcl_LinkVar _ANSI_ARGS_((Tcl_Interp *interp, CONST char *varName, char *addr, int type)); /* Slot 188 is reserved */ /* 189 */ EXTERN Tcl_Channel Tcl_MakeFileChannel _ANSI_ARGS_((ClientData handle, int mode)); /* 190 */ EXTERN int Tcl_MakeSafe _ANSI_ARGS_((Tcl_Interp *interp)); /* 191 */ EXTERN Tcl_Channel Tcl_MakeTcpClientChannel _ANSI_ARGS_(( ClientData tcpSocket)); /* 192 */ EXTERN char * Tcl_Merge _ANSI_ARGS_((int argc, CONST84 char *CONST *argv)); /* 193 */ EXTERN Tcl_HashEntry * Tcl_NextHashEntry _ANSI_ARGS_(( Tcl_HashSearch *searchPtr)); /* 194 */ EXTERN void Tcl_NotifyChannel _ANSI_ARGS_((Tcl_Channel channel, int mask)); /* 195 */ EXTERN Tcl_Obj * Tcl_ObjGetVar2 _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, int flags)); /* 196 */ EXTERN Tcl_Obj * Tcl_ObjSetVar2 _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, Tcl_Obj *newValuePtr, int flags)); /* 197 */ EXTERN Tcl_Channel Tcl_OpenCommandChannel _ANSI_ARGS_(( Tcl_Interp *interp, int argc, CONST84 char **argv, int flags)); /* 198 */ EXTERN Tcl_Channel Tcl_OpenFileChannel _ANSI_ARGS_((Tcl_Interp *interp, CONST char *fileName, CONST char *modeString, int permissions)); /* 199 */ EXTERN Tcl_Channel Tcl_OpenTcpClient _ANSI_ARGS_((Tcl_Interp *interp, int port, CONST char *address, CONST char *myaddr, int myport, int async)); /* 200 */ EXTERN Tcl_Channel Tcl_OpenTcpServer _ANSI_ARGS_((Tcl_Interp *interp, int port, CONST char *host, Tcl_TcpAcceptProc *acceptProc, ClientData callbackData)); /* 201 */ EXTERN void Tcl_Preserve _ANSI_ARGS_((ClientData data)); /* 202 */ EXTERN void Tcl_PrintDouble _ANSI_ARGS_((Tcl_Interp *interp, double value, char *dst)); /* 203 */ EXTERN int Tcl_PutEnv _ANSI_ARGS_((CONST char *assignment)); /* 204 */ EXTERN CONST84_RETURN char * Tcl_PosixError _ANSI_ARGS_((Tcl_Interp *interp)); /* 205 */ EXTERN void Tcl_QueueEvent _ANSI_ARGS_((Tcl_Event *evPtr, Tcl_QueuePosition position)); /* 206 */ EXTERN int Tcl_Read _ANSI_ARGS_((Tcl_Channel chan, char *bufPtr, int toRead)); /* 207 */ EXTERN void Tcl_ReapDetachedProcs _ANSI_ARGS_((void)); /* 208 */ EXTERN int Tcl_RecordAndEval _ANSI_ARGS_((Tcl_Interp *interp, CONST char *cmd, int flags)); /* 209 */ EXTERN int Tcl_RecordAndEvalObj _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *cmdPtr, int flags)); /* 210 */ EXTERN void Tcl_RegisterChannel _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Channel chan)); /* 211 */ EXTERN void Tcl_RegisterObjType _ANSI_ARGS_(( Tcl_ObjType *typePtr)); /* 212 */ EXTERN Tcl_RegExp Tcl_RegExpCompile _ANSI_ARGS_((Tcl_Interp *interp, CONST char *pattern)); /* 213 */ EXTERN int Tcl_RegExpExec _ANSI_ARGS_((Tcl_Interp *interp, Tcl_RegExp regexp, CONST char *text, CONST char *start)); /* 214 */ EXTERN int Tcl_RegExpMatch _ANSI_ARGS_((Tcl_Interp *interp, CONST char *text, CONST char *pattern)); /* 215 */ EXTERN void Tcl_RegExpRange _ANSI_ARGS_((Tcl_RegExp regexp, int index, CONST84 char **startPtr, CONST84 char **endPtr)); /* 216 */ EXTERN void Tcl_Release _ANSI_ARGS_((ClientData clientData)); /* 217 */ EXTERN void Tcl_ResetResult _ANSI_ARGS_((Tcl_Interp *interp)); /* 218 */ EXTERN int Tcl_ScanElement _ANSI_ARGS_((CONST char *src, int *flagPtr)); /* 219 */ EXTERN int Tcl_ScanCountedElement _ANSI_ARGS_((CONST char *src, int length, int *flagPtr)); /* 220 */ EXTERN int Tcl_SeekOld _ANSI_ARGS_((Tcl_Channel chan, int offset, int mode)); /* 221 */ EXTERN int Tcl_ServiceAll _ANSI_ARGS_((void)); /* 222 */ EXTERN int Tcl_ServiceEvent _ANSI_ARGS_((int flags)); /* 223 */ EXTERN void Tcl_SetAssocData _ANSI_ARGS_((Tcl_Interp *interp, CONST char *name, Tcl_InterpDeleteProc *proc, ClientData clientData)); /* 224 */ EXTERN void Tcl_SetChannelBufferSize _ANSI_ARGS_(( Tcl_Channel chan, int sz)); /* 225 */ EXTERN int Tcl_SetChannelOption _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Channel chan, CONST char *optionName, CONST char *newValue)); /* 226 */ EXTERN int Tcl_SetCommandInfo _ANSI_ARGS_((Tcl_Interp *interp, CONST char *cmdName, CONST Tcl_CmdInfo *infoPtr)); /* 227 */ EXTERN void Tcl_SetErrno _ANSI_ARGS_((int err)); /* 228 */ EXTERN void Tcl_SetErrorCode _ANSI_ARGS_(TCL_VARARGS(Tcl_Interp *,interp)); /* 229 */ EXTERN void Tcl_SetMaxBlockTime _ANSI_ARGS_((Tcl_Time *timePtr)); /* 230 */ EXTERN void Tcl_SetPanicProc _ANSI_ARGS_(( Tcl_PanicProc *panicProc)); /* 231 */ EXTERN int Tcl_SetRecursionLimit _ANSI_ARGS_(( Tcl_Interp *interp, int depth)); /* 232 */ EXTERN void Tcl_SetResult _ANSI_ARGS_((Tcl_Interp *interp, char *result, Tcl_FreeProc *freeProc)); /* 233 */ EXTERN int Tcl_SetServiceMode _ANSI_ARGS_((int mode)); /* 234 */ EXTERN void Tcl_SetObjErrorCode _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *errorObjPtr)); /* 235 */ EXTERN void Tcl_SetObjResult _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *resultObjPtr)); /* 236 */ EXTERN void Tcl_SetStdChannel _ANSI_ARGS_((Tcl_Channel channel, int type)); /* 237 */ EXTERN CONST84_RETURN char * Tcl_SetVar _ANSI_ARGS_((Tcl_Interp *interp, CONST char *varName, CONST char *newValue, int flags)); /* 238 */ EXTERN CONST84_RETURN char * Tcl_SetVar2 _ANSI_ARGS_((Tcl_Interp *interp, CONST char *part1, CONST char *part2, CONST char *newValue, int flags)); /* 239 */ EXTERN CONST84_RETURN char * Tcl_SignalId _ANSI_ARGS_((int sig)); /* 240 */ EXTERN CONST84_RETURN char * Tcl_SignalMsg _ANSI_ARGS_((int sig)); /* 241 */ EXTERN void Tcl_SourceRCFile _ANSI_ARGS_((Tcl_Interp *interp)); /* 242 */ EXTERN int Tcl_SplitList _ANSI_ARGS_((Tcl_Interp *interp, CONST char *listStr, int *argcPtr, CONST84 char ***argvPtr)); /* 243 */ EXTERN void Tcl_SplitPath _ANSI_ARGS_((CONST char *path, int *argcPtr, CONST84 char ***argvPtr)); /* 244 */ EXTERN void Tcl_StaticPackage _ANSI_ARGS_((Tcl_Interp *interp, CONST char *pkgName, Tcl_PackageInitProc *initProc, Tcl_PackageInitProc *safeInitProc)); /* 245 */ EXTERN int Tcl_StringMatch _ANSI_ARGS_((CONST char *str, CONST char *pattern)); /* 246 */ EXTERN int Tcl_TellOld _ANSI_ARGS_((Tcl_Channel chan)); /* 247 */ EXTERN int Tcl_TraceVar _ANSI_ARGS_((Tcl_Interp *interp, CONST char *varName, int flags, Tcl_VarTraceProc *proc, ClientData clientData)); /* 248 */ EXTERN int Tcl_TraceVar2 _ANSI_ARGS_((Tcl_Interp *interp, CONST char *part1, CONST char *part2, int flags, Tcl_VarTraceProc *proc, ClientData clientData)); /* 249 */ EXTERN char * Tcl_TranslateFileName _ANSI_ARGS_(( Tcl_Interp *interp, CONST char *name, Tcl_DString *bufferPtr)); /* 250 */ EXTERN int Tcl_Ungets _ANSI_ARGS_((Tcl_Channel chan, CONST char *str, int len, int atHead)); /* 251 */ EXTERN void Tcl_UnlinkVar _ANSI_ARGS_((Tcl_Interp *interp, CONST char *varName)); /* 252 */ EXTERN int Tcl_UnregisterChannel _ANSI_ARGS_(( Tcl_Interp *interp, Tcl_Channel chan)); /* 253 */ EXTERN int Tcl_UnsetVar _ANSI_ARGS_((Tcl_Interp *interp, CONST char *varName, int flags)); /* 254 */ EXTERN int Tcl_UnsetVar2 _ANSI_ARGS_((Tcl_Interp *interp, CONST char *part1, CONST char *part2, int flags)); /* 255 */ EXTERN void Tcl_UntraceVar _ANSI_ARGS_((Tcl_Interp *interp, CONST char *varName, int flags, Tcl_VarTraceProc *proc, ClientData clientData)); /* 256 */ EXTERN void Tcl_UntraceVar2 _ANSI_ARGS_((Tcl_Interp *interp, CONST char *part1, CONST char *part2, int flags, Tcl_VarTraceProc *proc, ClientData clientData)); /* 257 */ EXTERN void Tcl_UpdateLinkedVar _ANSI_ARGS_((Tcl_Interp *interp, CONST char *varName)); /* 258 */ EXTERN int Tcl_UpVar _ANSI_ARGS_((Tcl_Interp *interp, CONST char *frameName, CONST char *varName, CONST char *localName, int flags)); /* 259 */ EXTERN int Tcl_UpVar2 _ANSI_ARGS_((Tcl_Interp *interp, CONST char *frameName, CONST char *part1, CONST char *part2, CONST char *localName, int flags)); /* 260 */ EXTERN int Tcl_VarEval _ANSI_ARGS_(TCL_VARARGS(Tcl_Interp *,interp)); /* 261 */ EXTERN ClientData Tcl_VarTraceInfo _ANSI_ARGS_((Tcl_Interp *interp, CONST char *varName, int flags, Tcl_VarTraceProc *procPtr, ClientData prevClientData)); /* 262 */ EXTERN ClientData Tcl_VarTraceInfo2 _ANSI_ARGS_((Tcl_Interp *interp, CONST char *part1, CONST char *part2, int flags, Tcl_VarTraceProc *procPtr, ClientData prevClientData)); /* 263 */ EXTERN int Tcl_Write _ANSI_ARGS_((Tcl_Channel chan, CONST char *s, int slen)); /* 264 */ EXTERN void Tcl_WrongNumArgs _ANSI_ARGS_((Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], CONST char *message)); /* 265 */ EXTERN int Tcl_DumpActiveMemory _ANSI_ARGS_(( CONST char *fileName)); /* 266 */ EXTERN void Tcl_ValidateAllMemory _ANSI_ARGS_((CONST char *file, int line)); /* 267 */ EXTERN void Tcl_AppendResultVA _ANSI_ARGS_((Tcl_Interp *interp, va_list argList)); /* 268 */ EXTERN void Tcl_AppendStringsToObjVA _ANSI_ARGS_(( Tcl_Obj *objPtr, va_list argList)); /* 269 */ EXTERN char * Tcl_HashStats _ANSI_ARGS_((Tcl_HashTable *tablePtr)); /* 270 */ EXTERN CONST84_RETURN char * Tcl_ParseVar _ANSI_ARGS_((Tcl_Interp *interp, CONST char *start, CONST84 char **termPtr)); /* 271 */ EXTERN CONST84_RETURN char * Tcl_PkgPresent _ANSI_ARGS_((Tcl_Interp *interp, CONST char *name, CONST char *version, int exact)); /* 272 */ EXTERN CONST84_RETURN char * Tcl_PkgPresentEx _ANSI_ARGS_(( Tcl_Interp *interp, CONST char *name, CONST char *version, int exact, ClientData *clientDataPtr)); /* 273 */ EXTERN int Tcl_PkgProvide _ANSI_ARGS_((Tcl_Interp *interp, CONST char *name, CONST char *version)); /* 274 */ EXTERN CONST84_RETURN char * Tcl_PkgRequire _ANSI_ARGS_((Tcl_Interp *interp, CONST char *name, CONST char *version, int exact)); /* 275 */ EXTERN void Tcl_SetErrorCodeVA _ANSI_ARGS_((Tcl_Interp *interp, va_list argList)); /* 276 */ EXTERN int Tcl_VarEvalVA _ANSI_ARGS_((Tcl_Interp *interp, va_list argList)); /* 277 */ EXTERN Tcl_Pid Tcl_WaitPid _ANSI_ARGS_((Tcl_Pid pid, int *statPtr, int options)); /* 278 */ EXTERN void Tcl_PanicVA _ANSI_ARGS_((CONST char *format, va_list argList)); /* 279 */ EXTERN void Tcl_GetVersion _ANSI_ARGS_((int *major, int *minor, int *patchLevel, int *type)); /* 280 */ EXTERN void Tcl_InitMemory _ANSI_ARGS_((Tcl_Interp *interp)); /* 281 */ EXTERN Tcl_Channel Tcl_StackChannel _ANSI_ARGS_((Tcl_Interp *interp, Tcl_ChannelType *typePtr, ClientData instanceData, int mask, Tcl_Channel prevChan)); /* 282 */ EXTERN int Tcl_UnstackChannel _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Channel chan)); /* 283 */ EXTERN Tcl_Channel Tcl_GetStackedChannel _ANSI_ARGS_((Tcl_Channel chan)); /* 284 */ EXTERN void Tcl_SetMainLoop _ANSI_ARGS_((Tcl_MainLoopProc *proc)); /* Slot 285 is reserved */ /* 286 */ EXTERN void Tcl_AppendObjToObj _ANSI_ARGS_((Tcl_Obj *objPtr, Tcl_Obj *appendObjPtr)); /* 287 */ EXTERN Tcl_Encoding Tcl_CreateEncoding _ANSI_ARGS_(( Tcl_EncodingType *typePtr)); /* 288 */ EXTERN void Tcl_CreateThreadExitHandler _ANSI_ARGS_(( Tcl_ExitProc *proc, ClientData clientData)); /* 289 */ EXTERN void Tcl_DeleteThreadExitHandler _ANSI_ARGS_(( Tcl_ExitProc *proc, ClientData clientData)); /* 290 */ EXTERN void Tcl_DiscardResult _ANSI_ARGS_(( Tcl_SavedResult *statePtr)); /* 291 */ EXTERN int Tcl_EvalEx _ANSI_ARGS_((Tcl_Interp *interp, CONST char *script, int numBytes, int flags)); /* 292 */ EXTERN int Tcl_EvalObjv _ANSI_ARGS_((Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], int flags)); /* 293 */ EXTERN int Tcl_EvalObjEx _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr, int flags)); /* 294 */ EXTERN void Tcl_ExitThread _ANSI_ARGS_((int status)); /* 295 */ EXTERN int Tcl_ExternalToUtf _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Encoding encoding, CONST char *src, int srcLen, int flags, Tcl_EncodingState *statePtr, char *dst, int dstLen, int *srcReadPtr, int *dstWrotePtr, int *dstCharsPtr)); /* 296 */ EXTERN char * Tcl_ExternalToUtfDString _ANSI_ARGS_(( Tcl_Encoding encoding, CONST char *src, int srcLen, Tcl_DString *dsPtr)); /* 297 */ EXTERN void Tcl_FinalizeThread _ANSI_ARGS_((void)); /* 298 */ EXTERN void Tcl_FinalizeNotifier _ANSI_ARGS_(( ClientData clientData)); /* 299 */ EXTERN void Tcl_FreeEncoding _ANSI_ARGS_((Tcl_Encoding encoding)); /* 300 */ EXTERN Tcl_ThreadId Tcl_GetCurrentThread _ANSI_ARGS_((void)); /* 301 */ EXTERN Tcl_Encoding Tcl_GetEncoding _ANSI_ARGS_((Tcl_Interp *interp, CONST char *name)); /* 302 */ EXTERN CONST84_RETURN char * Tcl_GetEncodingName _ANSI_ARGS_(( Tcl_Encoding encoding)); /* 303 */ EXTERN void Tcl_GetEncodingNames _ANSI_ARGS_((Tcl_Interp *interp)); /* 304 */ EXTERN int Tcl_GetIndexFromObjStruct _ANSI_ARGS_(( Tcl_Interp *interp, Tcl_Obj *objPtr, CONST VOID *tablePtr, int offset, CONST char *msg, int flags, int *indexPtr)); /* 305 */ EXTERN VOID * Tcl_GetThreadData _ANSI_ARGS_(( Tcl_ThreadDataKey *keyPtr, int size)); /* 306 */ EXTERN Tcl_Obj * Tcl_GetVar2Ex _ANSI_ARGS_((Tcl_Interp *interp, CONST char *part1, CONST char *part2, int flags)); /* 307 */ EXTERN ClientData Tcl_InitNotifier _ANSI_ARGS_((void)); /* 308 */ EXTERN void Tcl_MutexLock _ANSI_ARGS_((Tcl_Mutex *mutexPtr)); /* 309 */ EXTERN void Tcl_MutexUnlock _ANSI_ARGS_((Tcl_Mutex *mutexPtr)); /* 310 */ EXTERN void Tcl_ConditionNotify _ANSI_ARGS_(( Tcl_Condition *condPtr)); /* 311 */ EXTERN void Tcl_ConditionWait _ANSI_ARGS_(( Tcl_Condition *condPtr, Tcl_Mutex *mutexPtr, Tcl_Time *timePtr)); /* 312 */ EXTERN int Tcl_NumUtfChars _ANSI_ARGS_((CONST char *src, int length)); /* 313 */ EXTERN int Tcl_ReadChars _ANSI_ARGS_((Tcl_Channel channel, Tcl_Obj *objPtr, int charsToRead, int appendFlag)); /* 314 */ EXTERN void Tcl_RestoreResult _ANSI_ARGS_((Tcl_Interp *interp, Tcl_SavedResult *statePtr)); /* 315 */ EXTERN void Tcl_SaveResult _ANSI_ARGS_((Tcl_Interp *interp, Tcl_SavedResult *statePtr)); /* 316 */ EXTERN int Tcl_SetSystemEncoding _ANSI_ARGS_(( Tcl_Interp *interp, CONST char *name)); /* 317 */ EXTERN Tcl_Obj * Tcl_SetVar2Ex _ANSI_ARGS_((Tcl_Interp *interp, CONST char *part1, CONST char *part2, Tcl_Obj *newValuePtr, int flags)); /* 318 */ EXTERN void Tcl_ThreadAlert _ANSI_ARGS_((Tcl_ThreadId threadId)); /* 319 */ EXTERN void Tcl_ThreadQueueEvent _ANSI_ARGS_(( Tcl_ThreadId threadId, Tcl_Event *evPtr, Tcl_QueuePosition position)); /* 320 */ EXTERN Tcl_UniChar Tcl_UniCharAtIndex _ANSI_ARGS_((CONST char *src, int index)); /* 321 */ EXTERN Tcl_UniChar Tcl_UniCharToLower _ANSI_ARGS_((int ch)); /* 322 */ EXTERN Tcl_UniChar Tcl_UniCharToTitle _ANSI_ARGS_((int ch)); /* 323 */ EXTERN Tcl_UniChar Tcl_UniCharToUpper _ANSI_ARGS_((int ch)); /* 324 */ EXTERN int Tcl_UniCharToUtf _ANSI_ARGS_((int ch, char *buf)); /* 325 */ EXTERN CONST84_RETURN char * Tcl_UtfAtIndex _ANSI_ARGS_((CONST char *src, int index)); /* 326 */ EXTERN int Tcl_UtfCharComplete _ANSI_ARGS_((CONST char *src, int length)); /* 327 */ EXTERN int Tcl_UtfBackslash _ANSI_ARGS_((CONST char *src, int *readPtr, char *dst)); /* 328 */ EXTERN CONST84_RETURN char * Tcl_UtfFindFirst _ANSI_ARGS_((CONST char *src, int ch)); /* 329 */ EXTERN CONST84_RETURN char * Tcl_UtfFindLast _ANSI_ARGS_((CONST char *src, int ch)); /* 330 */ EXTERN CONST84_RETURN char * Tcl_UtfNext _ANSI_ARGS_((CONST char *src)); /* 331 */ EXTERN CONST84_RETURN char * Tcl_UtfPrev _ANSI_ARGS_((CONST char *src, CONST char *start)); /* 332 */ EXTERN int Tcl_UtfToExternal _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Encoding encoding, CONST char *src, int srcLen, int flags, Tcl_EncodingState *statePtr, char *dst, int dstLen, int *srcReadPtr, int *dstWrotePtr, int *dstCharsPtr)); /* 333 */ EXTERN char * Tcl_UtfToExternalDString _ANSI_ARGS_(( Tcl_Encoding encoding, CONST char *src, int srcLen, Tcl_DString *dsPtr)); /* 334 */ EXTERN int Tcl_UtfToLower _ANSI_ARGS_((char *src)); /* 335 */ EXTERN int Tcl_UtfToTitle _ANSI_ARGS_((char *src)); /* 336 */ EXTERN int Tcl_UtfToUniChar _ANSI_ARGS_((CONST char *src, Tcl_UniChar *chPtr)); /* 337 */ EXTERN int Tcl_UtfToUpper _ANSI_ARGS_((char *src)); /* 338 */ EXTERN int Tcl_WriteChars _ANSI_ARGS_((Tcl_Channel chan, CONST char *src, int srcLen)); /* 339 */ EXTERN int Tcl_WriteObj _ANSI_ARGS_((Tcl_Channel chan, Tcl_Obj *objPtr)); /* 340 */ EXTERN char * Tcl_GetString _ANSI_ARGS_((Tcl_Obj *objPtr)); /* 341 */ EXTERN CONST84_RETURN char * Tcl_GetDefaultEncodingDir _ANSI_ARGS_((void)); /* 342 */ EXTERN void Tcl_SetDefaultEncodingDir _ANSI_ARGS_(( CONST char *path)); /* 343 */ EXTERN void Tcl_AlertNotifier _ANSI_ARGS_((ClientData clientData)); /* 344 */ EXTERN void Tcl_ServiceModeHook _ANSI_ARGS_((int mode)); /* 345 */ EXTERN int Tcl_UniCharIsAlnum _ANSI_ARGS_((int ch)); /* 346 */ EXTERN int Tcl_UniCharIsAlpha _ANSI_ARGS_((int ch)); /* 347 */ EXTERN int Tcl_UniCharIsDigit _ANSI_ARGS_((int ch)); /* 348 */ EXTERN int Tcl_UniCharIsLower _ANSI_ARGS_((int ch)); /* 349 */ EXTERN int Tcl_UniCharIsSpace _ANSI_ARGS_((int ch)); /* 350 */ EXTERN int Tcl_UniCharIsUpper _ANSI_ARGS_((int ch)); /* 351 */ EXTERN int Tcl_UniCharIsWordChar _ANSI_ARGS_((int ch)); /* 352 */ EXTERN int Tcl_UniCharLen _ANSI_ARGS_(( CONST Tcl_UniChar *uniStr)); /* 353 */ EXTERN int Tcl_UniCharNcmp _ANSI_ARGS_((CONST Tcl_UniChar *ucs, CONST Tcl_UniChar *uct, unsigned long numChars)); /* 354 */ EXTERN char * Tcl_UniCharToUtfDString _ANSI_ARGS_(( CONST Tcl_UniChar *uniStr, int uniLength, Tcl_DString *dsPtr)); /* 355 */ EXTERN Tcl_UniChar * Tcl_UtfToUniCharDString _ANSI_ARGS_((CONST char *src, int length, Tcl_DString *dsPtr)); /* 356 */ EXTERN Tcl_RegExp Tcl_GetRegExpFromObj _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *patObj, int flags)); /* 357 */ EXTERN Tcl_Obj * Tcl_EvalTokens _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Token *tokenPtr, int count)); /* 358 */ EXTERN void Tcl_FreeParse _ANSI_ARGS_((Tcl_Parse *parsePtr)); /* 359 */ EXTERN void Tcl_LogCommandInfo _ANSI_ARGS_((Tcl_Interp *interp, CONST char *script, CONST char *command, int length)); /* 360 */ EXTERN int Tcl_ParseBraces _ANSI_ARGS_((Tcl_Interp *interp, CONST char *start, int numBytes, Tcl_Parse *parsePtr, int append, CONST84 char **termPtr)); /* 361 */ EXTERN int Tcl_ParseCommand _ANSI_ARGS_((Tcl_Interp *interp, CONST char *start, int numBytes, int nested, Tcl_Parse *parsePtr)); /* 362 */ EXTERN int Tcl_ParseExpr _ANSI_ARGS_((Tcl_Interp *interp, CONST char *start, int numBytes, Tcl_Parse *parsePtr)); /* 363 */ EXTERN int Tcl_ParseQuotedString _ANSI_ARGS_(( Tcl_Interp *interp, CONST char *start, int numBytes, Tcl_Parse *parsePtr, int append, CONST84 char **termPtr)); /* 364 */ EXTERN int Tcl_ParseVarName _ANSI_ARGS_((Tcl_Interp *interp, CONST char *start, int numBytes, Tcl_Parse *parsePtr, int append)); /* 365 */ EXTERN char * Tcl_GetCwd _ANSI_ARGS_((Tcl_Interp *interp, Tcl_DString *cwdPtr)); /* 366 */ EXTERN int Tcl_Chdir _ANSI_ARGS_((CONST char *dirName)); /* 367 */ EXTERN int Tcl_Access _ANSI_ARGS_((CONST char *path, int mode)); /* 368 */ EXTERN int Tcl_Stat _ANSI_ARGS_((CONST char *path, struct stat *bufPtr)); /* 369 */ EXTERN int Tcl_UtfNcmp _ANSI_ARGS_((CONST char *s1, CONST char *s2, unsigned long n)); /* 370 */ EXTERN int Tcl_UtfNcasecmp _ANSI_ARGS_((CONST char *s1, CONST char *s2, unsigned long n)); /* 371 */ EXTERN int Tcl_StringCaseMatch _ANSI_ARGS_((CONST char *str, CONST char *pattern, int nocase)); /* 372 */ EXTERN int Tcl_UniCharIsControl _ANSI_ARGS_((int ch)); /* 373 */ EXTERN int Tcl_UniCharIsGraph _ANSI_ARGS_((int ch)); /* 374 */ EXTERN int Tcl_UniCharIsPrint _ANSI_ARGS_((int ch)); /* 375 */ EXTERN int Tcl_UniCharIsPunct _ANSI_ARGS_((int ch)); /* 376 */ EXTERN int Tcl_RegExpExecObj _ANSI_ARGS_((Tcl_Interp *interp, Tcl_RegExp regexp, Tcl_Obj *textObj, int offset, int nmatches, int flags)); /* 377 */ EXTERN void Tcl_RegExpGetInfo _ANSI_ARGS_((Tcl_RegExp regexp, Tcl_RegExpInfo *infoPtr)); /* 378 */ EXTERN Tcl_Obj * Tcl_NewUnicodeObj _ANSI_ARGS_(( CONST Tcl_UniChar *unicode, int numChars)); /* 379 */ EXTERN void Tcl_SetUnicodeObj _ANSI_ARGS_((Tcl_Obj *objPtr, CONST Tcl_UniChar *unicode, int numChars)); /* 380 */ EXTERN int Tcl_GetCharLength _ANSI_ARGS_((Tcl_Obj *objPtr)); /* 381 */ EXTERN Tcl_UniChar Tcl_GetUniChar _ANSI_ARGS_((Tcl_Obj *objPtr, int index)); /* 382 */ EXTERN Tcl_UniChar * Tcl_GetUnicode _ANSI_ARGS_((Tcl_Obj *objPtr)); /* 383 */ EXTERN Tcl_Obj * Tcl_GetRange _ANSI_ARGS_((Tcl_Obj *objPtr, int first, int last)); /* 384 */ EXTERN void Tcl_AppendUnicodeToObj _ANSI_ARGS_((Tcl_Obj *objPtr, CONST Tcl_UniChar *unicode, int length)); /* 385 */ EXTERN int Tcl_RegExpMatchObj _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *textObj, Tcl_Obj *patternObj)); /* 386 */ EXTERN void Tcl_SetNotifier _ANSI_ARGS_(( Tcl_NotifierProcs *notifierProcPtr)); /* 387 */ EXTERN Tcl_Mutex * Tcl_GetAllocMutex _ANSI_ARGS_((void)); /* 388 */ EXTERN int Tcl_GetChannelNames _ANSI_ARGS_((Tcl_Interp *interp)); /* 389 */ EXTERN int Tcl_GetChannelNamesEx _ANSI_ARGS_(( Tcl_Interp *interp, CONST char *pattern)); /* 390 */ EXTERN int Tcl_ProcObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); /* 391 */ EXTERN void Tcl_ConditionFinalize _ANSI_ARGS_(( Tcl_Condition *condPtr)); /* 392 */ EXTERN void Tcl_MutexFinalize _ANSI_ARGS_((Tcl_Mutex *mutex)); /* 393 */ EXTERN int Tcl_CreateThread _ANSI_ARGS_((Tcl_ThreadId *idPtr, Tcl_ThreadCreateProc proc, ClientData clientData, int stackSize, int flags)); /* 394 */ EXTERN int Tcl_ReadRaw _ANSI_ARGS_((Tcl_Channel chan, char *dst, int bytesToRead)); /* 395 */ EXTERN int Tcl_WriteRaw _ANSI_ARGS_((Tcl_Channel chan, CONST char *src, int srcLen)); /* 396 */ EXTERN Tcl_Channel Tcl_GetTopChannel _ANSI_ARGS_((Tcl_Channel chan)); /* 397 */ EXTERN int Tcl_ChannelBuffered _ANSI_ARGS_((Tcl_Channel chan)); /* 398 */ EXTERN CONST84_RETURN char * Tcl_ChannelName _ANSI_ARGS_(( Tcl_ChannelType *chanTypePtr)); /* 399 */ EXTERN Tcl_ChannelTypeVersion Tcl_ChannelVersion _ANSI_ARGS_(( Tcl_ChannelType *chanTypePtr)); /* 400 */ EXTERN Tcl_DriverBlockModeProc * Tcl_ChannelBlockModeProc _ANSI_ARGS_(( Tcl_ChannelType *chanTypePtr)); /* 401 */ EXTERN Tcl_DriverCloseProc * Tcl_ChannelCloseProc _ANSI_ARGS_(( Tcl_ChannelType *chanTypePtr)); /* 402 */ EXTERN Tcl_DriverClose2Proc * Tcl_ChannelClose2Proc _ANSI_ARGS_(( Tcl_ChannelType *chanTypePtr)); /* 403 */ EXTERN Tcl_DriverInputProc * Tcl_ChannelInputProc _ANSI_ARGS_(( Tcl_ChannelType *chanTypePtr)); /* 404 */ EXTERN Tcl_DriverOutputProc * Tcl_ChannelOutputProc _ANSI_ARGS_(( Tcl_ChannelType *chanTypePtr)); /* 405 */ EXTERN Tcl_DriverSeekProc * Tcl_ChannelSeekProc _ANSI_ARGS_(( Tcl_ChannelType *chanTypePtr)); /* 406 */ EXTERN Tcl_DriverSetOptionProc * Tcl_ChannelSetOptionProc _ANSI_ARGS_(( Tcl_ChannelType *chanTypePtr)); /* 407 */ EXTERN Tcl_DriverGetOptionProc * Tcl_ChannelGetOptionProc _ANSI_ARGS_(( Tcl_ChannelType *chanTypePtr)); /* 408 */ EXTERN Tcl_DriverWatchProc * Tcl_ChannelWatchProc _ANSI_ARGS_(( Tcl_ChannelType *chanTypePtr)); /* 409 */ EXTERN Tcl_DriverGetHandleProc * Tcl_ChannelGetHandleProc _ANSI_ARGS_(( Tcl_ChannelType *chanTypePtr)); /* 410 */ EXTERN Tcl_DriverFlushProc * Tcl_ChannelFlushProc _ANSI_ARGS_(( Tcl_ChannelType *chanTypePtr)); /* 411 */ EXTERN Tcl_DriverHandlerProc * Tcl_ChannelHandlerProc _ANSI_ARGS_(( Tcl_ChannelType *chanTypePtr)); /* 412 */ EXTERN int Tcl_JoinThread _ANSI_ARGS_((Tcl_ThreadId threadId, int *result)); /* 413 */ EXTERN int Tcl_IsChannelShared _ANSI_ARGS_((Tcl_Channel channel)); /* 414 */ EXTERN int Tcl_IsChannelRegistered _ANSI_ARGS_(( Tcl_Interp *interp, Tcl_Channel channel)); /* 415 */ EXTERN void Tcl_CutChannel _ANSI_ARGS_((Tcl_Channel channel)); /* 416 */ EXTERN void Tcl_SpliceChannel _ANSI_ARGS_((Tcl_Channel channel)); /* 417 */ EXTERN void Tcl_ClearChannelHandlers _ANSI_ARGS_(( Tcl_Channel channel)); /* 418 */ EXTERN int Tcl_IsChannelExisting _ANSI_ARGS_(( CONST char *channelName)); /* 419 */ EXTERN int Tcl_UniCharNcasecmp _ANSI_ARGS_(( CONST Tcl_UniChar *ucs, CONST Tcl_UniChar *uct, unsigned long numChars)); /* 420 */ EXTERN int Tcl_UniCharCaseMatch _ANSI_ARGS_(( CONST Tcl_UniChar *uniStr, CONST Tcl_UniChar *uniPattern, int nocase)); /* 421 */ EXTERN Tcl_HashEntry * Tcl_FindHashEntry _ANSI_ARGS_(( Tcl_HashTable *tablePtr, CONST char *key)); /* 422 */ EXTERN Tcl_HashEntry * Tcl_CreateHashEntry _ANSI_ARGS_(( Tcl_HashTable *tablePtr, CONST char *key, int *newPtr)); /* 423 */ EXTERN void Tcl_InitCustomHashTable _ANSI_ARGS_(( Tcl_HashTable *tablePtr, int keyType, Tcl_HashKeyType *typePtr)); /* 424 */ EXTERN void Tcl_InitObjHashTable _ANSI_ARGS_(( Tcl_HashTable *tablePtr)); /* 425 */ EXTERN ClientData Tcl_CommandTraceInfo _ANSI_ARGS_((Tcl_Interp *interp, CONST char *varName, int flags, Tcl_CommandTraceProc *procPtr, ClientData prevClientData)); /* 426 */ EXTERN int Tcl_TraceCommand _ANSI_ARGS_((Tcl_Interp *interp, CONST char *varName, int flags, Tcl_CommandTraceProc *proc, ClientData clientData)); /* 427 */ EXTERN void Tcl_UntraceCommand _ANSI_ARGS_((Tcl_Interp *interp, CONST char *varName, int flags, Tcl_CommandTraceProc *proc, ClientData clientData)); /* 428 */ EXTERN char * Tcl_AttemptAlloc _ANSI_ARGS_((unsigned int size)); /* 429 */ EXTERN char * Tcl_AttemptDbCkalloc _ANSI_ARGS_((unsigned int size, CONST char *file, int line)); /* 430 */ EXTERN char * Tcl_AttemptRealloc _ANSI_ARGS_((char *ptr, unsigned int size)); /* 431 */ EXTERN char * Tcl_AttemptDbCkrealloc _ANSI_ARGS_((char *ptr, unsigned int size, CONST char *file, int line)); /* 432 */ EXTERN int Tcl_AttemptSetObjLength _ANSI_ARGS_((Tcl_Obj *objPtr, int length)); /* 433 */ EXTERN Tcl_ThreadId Tcl_GetChannelThread _ANSI_ARGS_(( Tcl_Channel channel)); /* 434 */ EXTERN Tcl_UniChar * Tcl_GetUnicodeFromObj _ANSI_ARGS_((Tcl_Obj *objPtr, int *lengthPtr)); /* 435 */ EXTERN int Tcl_GetMathFuncInfo _ANSI_ARGS_((Tcl_Interp *interp, CONST char *name, int *numArgsPtr, Tcl_ValueType **argTypesPtr, Tcl_MathProc **procPtr, ClientData *clientDataPtr)); /* 436 */ EXTERN Tcl_Obj * Tcl_ListMathFuncs _ANSI_ARGS_((Tcl_Interp *interp, CONST char *pattern)); /* 437 */ EXTERN Tcl_Obj * Tcl_SubstObj _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr, int flags)); /* 438 */ EXTERN int Tcl_DetachChannel _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Channel channel)); /* 439 */ EXTERN int Tcl_IsStandardChannel _ANSI_ARGS_(( Tcl_Channel channel)); /* 440 */ EXTERN int Tcl_FSCopyFile _ANSI_ARGS_((Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr)); /* 441 */ EXTERN int Tcl_FSCopyDirectory _ANSI_ARGS_((Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr, Tcl_Obj **errorPtr)); /* 442 */ EXTERN int Tcl_FSCreateDirectory _ANSI_ARGS_((Tcl_Obj *pathPtr)); /* 443 */ EXTERN int Tcl_FSDeleteFile _ANSI_ARGS_((Tcl_Obj *pathPtr)); /* 444 */ EXTERN int Tcl_FSLoadFile _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *pathPtr, CONST char *sym1, CONST char *sym2, Tcl_PackageInitProc **proc1Ptr, Tcl_PackageInitProc **proc2Ptr, Tcl_LoadHandle *handlePtr, Tcl_FSUnloadFileProc **unloadProcPtr)); /* 445 */ EXTERN int Tcl_FSMatchInDirectory _ANSI_ARGS_(( Tcl_Interp *interp, Tcl_Obj *result, Tcl_Obj *pathPtr, CONST char *pattern, Tcl_GlobTypeData *types)); /* 446 */ EXTERN Tcl_Obj * Tcl_FSLink _ANSI_ARGS_((Tcl_Obj *pathPtr, Tcl_Obj *toPtr, int linkAction)); /* 447 */ EXTERN int Tcl_FSRemoveDirectory _ANSI_ARGS_((Tcl_Obj *pathPtr, int recursive, Tcl_Obj **errorPtr)); /* 448 */ EXTERN int Tcl_FSRenameFile _ANSI_ARGS_((Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr)); /* 449 */ EXTERN int Tcl_FSLstat _ANSI_ARGS_((Tcl_Obj *pathPtr, Tcl_StatBuf *buf)); /* 450 */ EXTERN int Tcl_FSUtime _ANSI_ARGS_((Tcl_Obj *pathPtr, struct utimbuf *tval)); /* 451 */ EXTERN int Tcl_FSFileAttrsGet _ANSI_ARGS_((Tcl_Interp *interp, int index, Tcl_Obj *pathPtr, Tcl_Obj **objPtrRef)); /* 452 */ EXTERN int Tcl_FSFileAttrsSet _ANSI_ARGS_((Tcl_Interp *interp, int index, Tcl_Obj *pathPtr, Tcl_Obj *objPtr)); /* 453 */ EXTERN CONST char ** Tcl_FSFileAttrStrings _ANSI_ARGS_((Tcl_Obj *pathPtr, Tcl_Obj **objPtrRef)); /* 454 */ EXTERN int Tcl_FSStat _ANSI_ARGS_((Tcl_Obj *pathPtr, Tcl_StatBuf *buf)); /* 455 */ EXTERN int Tcl_FSAccess _ANSI_ARGS_((Tcl_Obj *pathPtr, int mode)); /* 456 */ EXTERN Tcl_Channel Tcl_FSOpenFileChannel _ANSI_ARGS_(( Tcl_Interp *interp, Tcl_Obj *pathPtr, CONST char *modeString, int permissions)); /* 457 */ EXTERN Tcl_Obj * Tcl_FSGetCwd _ANSI_ARGS_((Tcl_Interp *interp)); /* 458 */ EXTERN int Tcl_FSChdir _ANSI_ARGS_((Tcl_Obj *pathPtr)); /* 459 */ EXTERN int Tcl_FSConvertToPathType _ANSI_ARGS_(( Tcl_Interp *interp, Tcl_Obj *pathPtr)); /* 460 */ EXTERN Tcl_Obj * Tcl_FSJoinPath _ANSI_ARGS_((Tcl_Obj *listObj, int elements)); /* 461 */ EXTERN Tcl_Obj * Tcl_FSSplitPath _ANSI_ARGS_((Tcl_Obj *pathPtr, int *lenPtr)); /* 462 */ EXTERN int Tcl_FSEqualPaths _ANSI_ARGS_((Tcl_Obj *firstPtr, Tcl_Obj *secondPtr)); /* 463 */ EXTERN Tcl_Obj * Tcl_FSGetNormalizedPath _ANSI_ARGS_(( Tcl_Interp *interp, Tcl_Obj *pathPtr)); /* 464 */ EXTERN Tcl_Obj * Tcl_FSJoinToPath _ANSI_ARGS_((Tcl_Obj *pathPtr, int objc, Tcl_Obj *CONST objv[])); /* 465 */ EXTERN ClientData Tcl_FSGetInternalRep _ANSI_ARGS_((Tcl_Obj *pathPtr, Tcl_Filesystem *fsPtr)); /* 466 */ EXTERN Tcl_Obj * Tcl_FSGetTranslatedPath _ANSI_ARGS_(( Tcl_Interp *interp, Tcl_Obj *pathPtr)); /* 467 */ EXTERN int Tcl_FSEvalFile _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *fileName)); /* 468 */ EXTERN Tcl_Obj * Tcl_FSNewNativePath _ANSI_ARGS_(( Tcl_Filesystem *fromFilesystem, ClientData clientData)); /* 469 */ EXTERN CONST char * Tcl_FSGetNativePath _ANSI_ARGS_((Tcl_Obj *pathPtr)); /* 470 */ EXTERN Tcl_Obj * Tcl_FSFileSystemInfo _ANSI_ARGS_((Tcl_Obj *pathPtr)); /* 471 */ EXTERN Tcl_Obj * Tcl_FSPathSeparator _ANSI_ARGS_((Tcl_Obj *pathPtr)); /* 472 */ EXTERN Tcl_Obj * Tcl_FSListVolumes _ANSI_ARGS_((void)); /* 473 */ EXTERN int Tcl_FSRegister _ANSI_ARGS_((ClientData clientData, Tcl_Filesystem *fsPtr)); /* 474 */ EXTERN int Tcl_FSUnregister _ANSI_ARGS_((Tcl_Filesystem *fsPtr)); /* 475 */ EXTERN ClientData Tcl_FSData _ANSI_ARGS_((Tcl_Filesystem *fsPtr)); /* 476 */ EXTERN CONST char * Tcl_FSGetTranslatedStringPath _ANSI_ARGS_(( Tcl_Interp *interp, Tcl_Obj *pathPtr)); /* 477 */ EXTERN Tcl_Filesystem * Tcl_FSGetFileSystemForPath _ANSI_ARGS_(( Tcl_Obj *pathPtr)); /* 478 */ EXTERN Tcl_PathType Tcl_FSGetPathType _ANSI_ARGS_((Tcl_Obj *pathPtr)); /* 479 */ EXTERN int Tcl_OutputBuffered _ANSI_ARGS_((Tcl_Channel chan)); /* 480 */ EXTERN void Tcl_FSMountsChanged _ANSI_ARGS_(( Tcl_Filesystem *fsPtr)); /* 481 */ EXTERN int Tcl_EvalTokensStandard _ANSI_ARGS_(( Tcl_Interp *interp, Tcl_Token *tokenPtr, int count)); /* 482 */ EXTERN void Tcl_GetTime _ANSI_ARGS_((Tcl_Time *timeBuf)); /* 483 */ EXTERN Tcl_Trace Tcl_CreateObjTrace _ANSI_ARGS_((Tcl_Interp *interp, int level, int flags, Tcl_CmdObjTraceProc *objProc, ClientData clientData, Tcl_CmdObjTraceDeleteProc *delProc)); /* 484 */ EXTERN int Tcl_GetCommandInfoFromToken _ANSI_ARGS_(( Tcl_Command token, Tcl_CmdInfo *infoPtr)); /* 485 */ EXTERN int Tcl_SetCommandInfoFromToken _ANSI_ARGS_(( Tcl_Command token, CONST Tcl_CmdInfo *infoPtr)); /* 486 */ EXTERN Tcl_Obj * Tcl_DbNewWideIntObj _ANSI_ARGS_(( Tcl_WideInt wideValue, CONST char *file, int line)); /* 487 */ EXTERN int Tcl_GetWideIntFromObj _ANSI_ARGS_(( Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_WideInt *widePtr)); /* 488 */ EXTERN Tcl_Obj * Tcl_NewWideIntObj _ANSI_ARGS_((Tcl_WideInt wideValue)); /* 489 */ EXTERN void Tcl_SetWideIntObj _ANSI_ARGS_((Tcl_Obj *objPtr, Tcl_WideInt wideValue)); /* 490 */ EXTERN Tcl_StatBuf * Tcl_AllocStatBuf _ANSI_ARGS_((void)); /* 491 */ EXTERN Tcl_WideInt Tcl_Seek _ANSI_ARGS_((Tcl_Channel chan, Tcl_WideInt offset, int mode)); /* 492 */ EXTERN Tcl_WideInt Tcl_Tell _ANSI_ARGS_((Tcl_Channel chan)); /* 493 */ EXTERN Tcl_DriverWideSeekProc * Tcl_ChannelWideSeekProc _ANSI_ARGS_(( Tcl_ChannelType *chanTypePtr)); /* Slot 494 is reserved */ /* Slot 495 is reserved */ /* Slot 496 is reserved */ /* Slot 497 is reserved */ /* Slot 498 is reserved */ /* Slot 499 is reserved */ /* Slot 500 is reserved */ /* Slot 501 is reserved */ /* Slot 502 is reserved */ /* Slot 503 is reserved */ /* Slot 504 is reserved */ /* Slot 505 is reserved */ /* Slot 506 is reserved */ /* Slot 507 is reserved */ /* Slot 508 is reserved */ /* Slot 509 is reserved */ /* Slot 510 is reserved */ /* Slot 511 is reserved */ /* Slot 512 is reserved */ /* Slot 513 is reserved */ /* Slot 514 is reserved */ /* Slot 515 is reserved */ /* Slot 516 is reserved */ /* Slot 517 is reserved */ /* Slot 518 is reserved */ /* Slot 519 is reserved */ /* Slot 520 is reserved */ /* Slot 521 is reserved */ /* Slot 522 is reserved */ /* Slot 523 is reserved */ /* Slot 524 is reserved */ /* Slot 525 is reserved */ /* Slot 526 is reserved */ /* Slot 527 is reserved */ /* Slot 528 is reserved */ /* Slot 529 is reserved */ /* Slot 530 is reserved */ /* Slot 531 is reserved */ /* Slot 532 is reserved */ /* Slot 533 is reserved */ /* Slot 534 is reserved */ /* Slot 535 is reserved */ /* Slot 536 is reserved */ /* Slot 537 is reserved */ /* Slot 538 is reserved */ /* Slot 539 is reserved */ /* Slot 540 is reserved */ /* Slot 541 is reserved */ /* Slot 542 is reserved */ /* Slot 543 is reserved */ /* Slot 544 is reserved */ /* Slot 545 is reserved */ /* Slot 546 is reserved */ /* Slot 547 is reserved */ /* Slot 548 is reserved */ /* Slot 549 is reserved */ /* Slot 550 is reserved */ /* Slot 551 is reserved */ /* Slot 552 is reserved */ /* Slot 553 is reserved */ /* 554 */ EXTERN Tcl_DriverThreadActionProc * Tcl_ChannelThreadActionProc _ANSI_ARGS_(( Tcl_ChannelType *chanTypePtr)); /* Slot 555 is reserved */ /* Slot 556 is reserved */ /* Slot 557 is reserved */ /* Slot 558 is reserved */ /* Slot 559 is reserved */ /* Slot 560 is reserved */ /* Slot 561 is reserved */ /* Slot 562 is reserved */ /* Slot 563 is reserved */ /* Slot 564 is reserved */ /* Slot 565 is reserved */ /* Slot 566 is reserved */ /* Slot 567 is reserved */ /* Slot 568 is reserved */ /* Slot 569 is reserved */ /* Slot 570 is reserved */ /* Slot 571 is reserved */ /* Slot 572 is reserved */ /* 573 */ EXTERN int Tcl_PkgRequireProc _ANSI_ARGS_((Tcl_Interp *interp, CONST char *name, int objc, Tcl_Obj *CONST objv[], ClientData *clientDataPtr)); /* Slot 574 is reserved */ /* Slot 575 is reserved */ /* Slot 576 is reserved */ /* Slot 577 is reserved */ /* Slot 578 is reserved */ /* Slot 579 is reserved */ /* Slot 580 is reserved */ /* Slot 581 is reserved */ /* Slot 582 is reserved */ /* Slot 583 is reserved */ /* Slot 584 is reserved */ /* Slot 585 is reserved */ /* Slot 586 is reserved */ /* Slot 587 is reserved */ /* Slot 588 is reserved */ /* Slot 589 is reserved */ /* Slot 590 is reserved */ /* Slot 591 is reserved */ /* Slot 592 is reserved */ /* Slot 593 is reserved */ /* Slot 594 is reserved */ /* Slot 595 is reserved */ /* Slot 596 is reserved */ /* Slot 597 is reserved */ /* Slot 598 is reserved */ /* Slot 599 is reserved */ /* Slot 600 is reserved */ /* Slot 601 is reserved */ /* Slot 602 is reserved */ /* Slot 603 is reserved */ /* Slot 604 is reserved */ /* Slot 605 is reserved */ /* Slot 606 is reserved */ /* Slot 607 is reserved */ /* Slot 608 is reserved */ /* Slot 609 is reserved */ /* Slot 610 is reserved */ /* Slot 611 is reserved */ /* Slot 612 is reserved */ /* Slot 613 is reserved */ /* Slot 614 is reserved */ /* Slot 615 is reserved */ /* Slot 616 is reserved */ /* Slot 617 is reserved */ /* Slot 618 is reserved */ /* Slot 619 is reserved */ /* Slot 620 is reserved */ /* Slot 621 is reserved */ /* Slot 622 is reserved */ /* Slot 623 is reserved */ /* Slot 624 is reserved */ /* Slot 625 is reserved */ /* Slot 626 is reserved */ /* Slot 627 is reserved */ /* Slot 628 is reserved */ /* Slot 629 is reserved */ /* 630 */ EXTERN void TclUnusedStubEntry _ANSI_ARGS_((void)); typedef struct TclStubHooks { struct TclPlatStubs *tclPlatStubs; struct TclIntStubs *tclIntStubs; struct TclIntPlatStubs *tclIntPlatStubs; } TclStubHooks; typedef struct TclStubs { int magic; struct TclStubHooks *hooks; int (*tcl_PkgProvideEx) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *name, CONST char *version, ClientData clientData)); /* 0 */ CONST84_RETURN char * (*tcl_PkgRequireEx) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *name, CONST char *version, int exact, ClientData *clientDataPtr)); /* 1 */ void (*tcl_Panic) _ANSI_ARGS_((CONST char *format, ...)); /* 2 */ char * (*tcl_Alloc) _ANSI_ARGS_((unsigned int size)); /* 3 */ void (*tcl_Free) _ANSI_ARGS_((char *ptr)); /* 4 */ char * (*tcl_Realloc) _ANSI_ARGS_((char *ptr, unsigned int size)); /* 5 */ char * (*tcl_DbCkalloc) _ANSI_ARGS_((unsigned int size, CONST char *file, int line)); /* 6 */ void (*tcl_DbCkfree) _ANSI_ARGS_((char *ptr, CONST char *file, int line)); /* 7 */ char * (*tcl_DbCkrealloc) _ANSI_ARGS_((char *ptr, unsigned int size, CONST char *file, int line)); /* 8 */ #if !defined(__WIN32__) && !defined(MAC_OSX_TCL) /* UNIX */ void (*tcl_CreateFileHandler) _ANSI_ARGS_((int fd, int mask, Tcl_FileProc *proc, ClientData clientData)); /* 9 */ #endif /* UNIX */ #if defined(__WIN32__) /* WIN */ VOID *reserved9; #endif /* WIN */ #ifdef MAC_OSX_TCL /* MACOSX */ void (*tcl_CreateFileHandler) _ANSI_ARGS_((int fd, int mask, Tcl_FileProc *proc, ClientData clientData)); /* 9 */ #endif /* MACOSX */ #if !defined(__WIN32__) && !defined(MAC_OSX_TCL) /* UNIX */ void (*tcl_DeleteFileHandler) _ANSI_ARGS_((int fd)); /* 10 */ #endif /* UNIX */ #if defined(__WIN32__) /* WIN */ VOID *reserved10; #endif /* WIN */ #ifdef MAC_OSX_TCL /* MACOSX */ void (*tcl_DeleteFileHandler) _ANSI_ARGS_((int fd)); /* 10 */ #endif /* MACOSX */ void (*tcl_SetTimer) _ANSI_ARGS_((Tcl_Time *timePtr)); /* 11 */ void (*tcl_Sleep) _ANSI_ARGS_((int ms)); /* 12 */ int (*tcl_WaitForEvent) _ANSI_ARGS_((Tcl_Time *timePtr)); /* 13 */ int (*tcl_AppendAllObjTypes) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr)); /* 14 */ void (*tcl_AppendStringsToObj) _ANSI_ARGS_((Tcl_Obj *objPtr, ...)); /* 15 */ void (*tcl_AppendToObj) _ANSI_ARGS_((Tcl_Obj *objPtr, CONST char *bytes, int length)); /* 16 */ Tcl_Obj * (*tcl_ConcatObj) _ANSI_ARGS_((int objc, Tcl_Obj *CONST objv[])); /* 17 */ int (*tcl_ConvertToType) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_ObjType *typePtr)); /* 18 */ void (*tcl_DbDecrRefCount) _ANSI_ARGS_((Tcl_Obj *objPtr, CONST char *file, int line)); /* 19 */ void (*tcl_DbIncrRefCount) _ANSI_ARGS_((Tcl_Obj *objPtr, CONST char *file, int line)); /* 20 */ int (*tcl_DbIsShared) _ANSI_ARGS_((Tcl_Obj *objPtr, CONST char *file, int line)); /* 21 */ Tcl_Obj * (*tcl_DbNewBooleanObj) _ANSI_ARGS_((int boolValue, CONST char *file, int line)); /* 22 */ Tcl_Obj * (*tcl_DbNewByteArrayObj) _ANSI_ARGS_((CONST unsigned char *bytes, int length, CONST char *file, int line)); /* 23 */ Tcl_Obj * (*tcl_DbNewDoubleObj) _ANSI_ARGS_((double doubleValue, CONST char *file, int line)); /* 24 */ Tcl_Obj * (*tcl_DbNewListObj) _ANSI_ARGS_((int objc, Tcl_Obj *CONST *objv, CONST char *file, int line)); /* 25 */ Tcl_Obj * (*tcl_DbNewLongObj) _ANSI_ARGS_((long longValue, CONST char *file, int line)); /* 26 */ Tcl_Obj * (*tcl_DbNewObj) _ANSI_ARGS_((CONST char *file, int line)); /* 27 */ Tcl_Obj * (*tcl_DbNewStringObj) _ANSI_ARGS_((CONST char *bytes, int length, CONST char *file, int line)); /* 28 */ Tcl_Obj * (*tcl_DuplicateObj) _ANSI_ARGS_((Tcl_Obj *objPtr)); /* 29 */ void (*tclFreeObj) _ANSI_ARGS_((Tcl_Obj *objPtr)); /* 30 */ int (*tcl_GetBoolean) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *src, int *boolPtr)); /* 31 */ int (*tcl_GetBooleanFromObj) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr, int *boolPtr)); /* 32 */ unsigned char * (*tcl_GetByteArrayFromObj) _ANSI_ARGS_((Tcl_Obj *objPtr, int *lengthPtr)); /* 33 */ int (*tcl_GetDouble) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *src, double *doublePtr)); /* 34 */ int (*tcl_GetDoubleFromObj) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr, double *doublePtr)); /* 35 */ int (*tcl_GetIndexFromObj) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr, CONST84 char **tablePtr, CONST char *msg, int flags, int *indexPtr)); /* 36 */ int (*tcl_GetInt) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *src, int *intPtr)); /* 37 */ int (*tcl_GetIntFromObj) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr, int *intPtr)); /* 38 */ int (*tcl_GetLongFromObj) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr, long *longPtr)); /* 39 */ Tcl_ObjType * (*tcl_GetObjType) _ANSI_ARGS_((CONST char *typeName)); /* 40 */ char * (*tcl_GetStringFromObj) _ANSI_ARGS_((Tcl_Obj *objPtr, int *lengthPtr)); /* 41 */ void (*tcl_InvalidateStringRep) _ANSI_ARGS_((Tcl_Obj *objPtr)); /* 42 */ int (*tcl_ListObjAppendList) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Obj *elemListPtr)); /* 43 */ int (*tcl_ListObjAppendElement) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Obj *objPtr)); /* 44 */ int (*tcl_ListObjGetElements) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *listPtr, int *objcPtr, Tcl_Obj ***objvPtr)); /* 45 */ int (*tcl_ListObjIndex) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *listPtr, int index, Tcl_Obj **objPtrPtr)); /* 46 */ int (*tcl_ListObjLength) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *listPtr, int *lengthPtr)); /* 47 */ int (*tcl_ListObjReplace) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *listPtr, int first, int count, int objc, Tcl_Obj *CONST objv[])); /* 48 */ Tcl_Obj * (*tcl_NewBooleanObj) _ANSI_ARGS_((int boolValue)); /* 49 */ Tcl_Obj * (*tcl_NewByteArrayObj) _ANSI_ARGS_((CONST unsigned char *bytes, int length)); /* 50 */ Tcl_Obj * (*tcl_NewDoubleObj) _ANSI_ARGS_((double doubleValue)); /* 51 */ Tcl_Obj * (*tcl_NewIntObj) _ANSI_ARGS_((int intValue)); /* 52 */ Tcl_Obj * (*tcl_NewListObj) _ANSI_ARGS_((int objc, Tcl_Obj *CONST objv[])); /* 53 */ Tcl_Obj * (*tcl_NewLongObj) _ANSI_ARGS_((long longValue)); /* 54 */ Tcl_Obj * (*tcl_NewObj) _ANSI_ARGS_((void)); /* 55 */ Tcl_Obj * (*tcl_NewStringObj) _ANSI_ARGS_((CONST char *bytes, int length)); /* 56 */ void (*tcl_SetBooleanObj) _ANSI_ARGS_((Tcl_Obj *objPtr, int boolValue)); /* 57 */ unsigned char * (*tcl_SetByteArrayLength) _ANSI_ARGS_((Tcl_Obj *objPtr, int length)); /* 58 */ void (*tcl_SetByteArrayObj) _ANSI_ARGS_((Tcl_Obj *objPtr, CONST unsigned char *bytes, int length)); /* 59 */ void (*tcl_SetDoubleObj) _ANSI_ARGS_((Tcl_Obj *objPtr, double doubleValue)); /* 60 */ void (*tcl_SetIntObj) _ANSI_ARGS_((Tcl_Obj *objPtr, int intValue)); /* 61 */ void (*tcl_SetListObj) _ANSI_ARGS_((Tcl_Obj *objPtr, int objc, Tcl_Obj *CONST objv[])); /* 62 */ void (*tcl_SetLongObj) _ANSI_ARGS_((Tcl_Obj *objPtr, long longValue)); /* 63 */ void (*tcl_SetObjLength) _ANSI_ARGS_((Tcl_Obj *objPtr, int length)); /* 64 */ void (*tcl_SetStringObj) _ANSI_ARGS_((Tcl_Obj *objPtr, CONST char *bytes, int length)); /* 65 */ void (*tcl_AddErrorInfo) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *message)); /* 66 */ void (*tcl_AddObjErrorInfo) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *message, int length)); /* 67 */ void (*tcl_AllowExceptions) _ANSI_ARGS_((Tcl_Interp *interp)); /* 68 */ void (*tcl_AppendElement) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *element)); /* 69 */ void (*tcl_AppendResult) _ANSI_ARGS_((Tcl_Interp *interp, ...)); /* 70 */ Tcl_AsyncHandler (*tcl_AsyncCreate) _ANSI_ARGS_((Tcl_AsyncProc *proc, ClientData clientData)); /* 71 */ void (*tcl_AsyncDelete) _ANSI_ARGS_((Tcl_AsyncHandler async)); /* 72 */ int (*tcl_AsyncInvoke) _ANSI_ARGS_((Tcl_Interp *interp, int code)); /* 73 */ void (*tcl_AsyncMark) _ANSI_ARGS_((Tcl_AsyncHandler async)); /* 74 */ int (*tcl_AsyncReady) _ANSI_ARGS_((void)); /* 75 */ void (*tcl_BackgroundError) _ANSI_ARGS_((Tcl_Interp *interp)); /* 76 */ char (*tcl_Backslash) _ANSI_ARGS_((CONST char *src, int *readPtr)); /* 77 */ int (*tcl_BadChannelOption) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *optionName, CONST char *optionList)); /* 78 */ void (*tcl_CallWhenDeleted) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_InterpDeleteProc *proc, ClientData clientData)); /* 79 */ void (*tcl_CancelIdleCall) _ANSI_ARGS_((Tcl_IdleProc *idleProc, ClientData clientData)); /* 80 */ int (*tcl_Close) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Channel chan)); /* 81 */ int (*tcl_CommandComplete) _ANSI_ARGS_((CONST char *cmd)); /* 82 */ char * (*tcl_Concat) _ANSI_ARGS_((int argc, CONST84 char *CONST *argv)); /* 83 */ int (*tcl_ConvertElement) _ANSI_ARGS_((CONST char *src, char *dst, int flags)); /* 84 */ int (*tcl_ConvertCountedElement) _ANSI_ARGS_((CONST char *src, int length, char *dst, int flags)); /* 85 */ int (*tcl_CreateAlias) _ANSI_ARGS_((Tcl_Interp *slave, CONST char *slaveCmd, Tcl_Interp *target, CONST char *targetCmd, int argc, CONST84 char *CONST *argv)); /* 86 */ int (*tcl_CreateAliasObj) _ANSI_ARGS_((Tcl_Interp *slave, CONST char *slaveCmd, Tcl_Interp *target, CONST char *targetCmd, int objc, Tcl_Obj *CONST objv[])); /* 87 */ Tcl_Channel (*tcl_CreateChannel) _ANSI_ARGS_((Tcl_ChannelType *typePtr, CONST char *chanName, ClientData instanceData, int mask)); /* 88 */ void (*tcl_CreateChannelHandler) _ANSI_ARGS_((Tcl_Channel chan, int mask, Tcl_ChannelProc *proc, ClientData clientData)); /* 89 */ void (*tcl_CreateCloseHandler) _ANSI_ARGS_((Tcl_Channel chan, Tcl_CloseProc *proc, ClientData clientData)); /* 90 */ Tcl_Command (*tcl_CreateCommand) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *cmdName, Tcl_CmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *deleteProc)); /* 91 */ void (*tcl_CreateEventSource) _ANSI_ARGS_((Tcl_EventSetupProc *setupProc, Tcl_EventCheckProc *checkProc, ClientData clientData)); /* 92 */ void (*tcl_CreateExitHandler) _ANSI_ARGS_((Tcl_ExitProc *proc, ClientData clientData)); /* 93 */ Tcl_Interp * (*tcl_CreateInterp) _ANSI_ARGS_((void)); /* 94 */ void (*tcl_CreateMathFunc) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *name, int numArgs, Tcl_ValueType *argTypes, Tcl_MathProc *proc, ClientData clientData)); /* 95 */ Tcl_Command (*tcl_CreateObjCommand) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *cmdName, Tcl_ObjCmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *deleteProc)); /* 96 */ Tcl_Interp * (*tcl_CreateSlave) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *slaveName, int isSafe)); /* 97 */ Tcl_TimerToken (*tcl_CreateTimerHandler) _ANSI_ARGS_((int milliseconds, Tcl_TimerProc *proc, ClientData clientData)); /* 98 */ Tcl_Trace (*tcl_CreateTrace) _ANSI_ARGS_((Tcl_Interp *interp, int level, Tcl_CmdTraceProc *proc, ClientData clientData)); /* 99 */ void (*tcl_DeleteAssocData) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *name)); /* 100 */ void (*tcl_DeleteChannelHandler) _ANSI_ARGS_((Tcl_Channel chan, Tcl_ChannelProc *proc, ClientData clientData)); /* 101 */ void (*tcl_DeleteCloseHandler) _ANSI_ARGS_((Tcl_Channel chan, Tcl_CloseProc *proc, ClientData clientData)); /* 102 */ int (*tcl_DeleteCommand) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *cmdName)); /* 103 */ int (*tcl_DeleteCommandFromToken) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Command command)); /* 104 */ void (*tcl_DeleteEvents) _ANSI_ARGS_((Tcl_EventDeleteProc *proc, ClientData clientData)); /* 105 */ void (*tcl_DeleteEventSource) _ANSI_ARGS_((Tcl_EventSetupProc *setupProc, Tcl_EventCheckProc *checkProc, ClientData clientData)); /* 106 */ void (*tcl_DeleteExitHandler) _ANSI_ARGS_((Tcl_ExitProc *proc, ClientData clientData)); /* 107 */ void (*tcl_DeleteHashEntry) _ANSI_ARGS_((Tcl_HashEntry *entryPtr)); /* 108 */ void (*tcl_DeleteHashTable) _ANSI_ARGS_((Tcl_HashTable *tablePtr)); /* 109 */ void (*tcl_DeleteInterp) _ANSI_ARGS_((Tcl_Interp *interp)); /* 110 */ void (*tcl_DetachPids) _ANSI_ARGS_((int numPids, Tcl_Pid *pidPtr)); /* 111 */ void (*tcl_DeleteTimerHandler) _ANSI_ARGS_((Tcl_TimerToken token)); /* 112 */ void (*tcl_DeleteTrace) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Trace trace)); /* 113 */ void (*tcl_DontCallWhenDeleted) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_InterpDeleteProc *proc, ClientData clientData)); /* 114 */ int (*tcl_DoOneEvent) _ANSI_ARGS_((int flags)); /* 115 */ void (*tcl_DoWhenIdle) _ANSI_ARGS_((Tcl_IdleProc *proc, ClientData clientData)); /* 116 */ char * (*tcl_DStringAppend) _ANSI_ARGS_((Tcl_DString *dsPtr, CONST char *bytes, int length)); /* 117 */ char * (*tcl_DStringAppendElement) _ANSI_ARGS_((Tcl_DString *dsPtr, CONST char *element)); /* 118 */ void (*tcl_DStringEndSublist) _ANSI_ARGS_((Tcl_DString *dsPtr)); /* 119 */ void (*tcl_DStringFree) _ANSI_ARGS_((Tcl_DString *dsPtr)); /* 120 */ void (*tcl_DStringGetResult) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_DString *dsPtr)); /* 121 */ void (*tcl_DStringInit) _ANSI_ARGS_((Tcl_DString *dsPtr)); /* 122 */ void (*tcl_DStringResult) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_DString *dsPtr)); /* 123 */ void (*tcl_DStringSetLength) _ANSI_ARGS_((Tcl_DString *dsPtr, int length)); /* 124 */ void (*tcl_DStringStartSublist) _ANSI_ARGS_((Tcl_DString *dsPtr)); /* 125 */ int (*tcl_Eof) _ANSI_ARGS_((Tcl_Channel chan)); /* 126 */ CONST84_RETURN char * (*tcl_ErrnoId) _ANSI_ARGS_((void)); /* 127 */ CONST84_RETURN char * (*tcl_ErrnoMsg) _ANSI_ARGS_((int err)); /* 128 */ int (*tcl_Eval) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *script)); /* 129 */ int (*tcl_EvalFile) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *fileName)); /* 130 */ int (*tcl_EvalObj) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr)); /* 131 */ void (*tcl_EventuallyFree) _ANSI_ARGS_((ClientData clientData, Tcl_FreeProc *freeProc)); /* 132 */ void (*tcl_Exit) _ANSI_ARGS_((int status)); /* 133 */ int (*tcl_ExposeCommand) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *hiddenCmdToken, CONST char *cmdName)); /* 134 */ int (*tcl_ExprBoolean) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *expr, int *ptr)); /* 135 */ int (*tcl_ExprBooleanObj) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr, int *ptr)); /* 136 */ int (*tcl_ExprDouble) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *expr, double *ptr)); /* 137 */ int (*tcl_ExprDoubleObj) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr, double *ptr)); /* 138 */ int (*tcl_ExprLong) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *expr, long *ptr)); /* 139 */ int (*tcl_ExprLongObj) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr, long *ptr)); /* 140 */ int (*tcl_ExprObj) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Obj **resultPtrPtr)); /* 141 */ int (*tcl_ExprString) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *expr)); /* 142 */ void (*tcl_Finalize) _ANSI_ARGS_((void)); /* 143 */ void (*tcl_FindExecutable) _ANSI_ARGS_((CONST char *argv0)); /* 144 */ Tcl_HashEntry * (*tcl_FirstHashEntry) _ANSI_ARGS_((Tcl_HashTable *tablePtr, Tcl_HashSearch *searchPtr)); /* 145 */ int (*tcl_Flush) _ANSI_ARGS_((Tcl_Channel chan)); /* 146 */ void (*tcl_FreeResult) _ANSI_ARGS_((Tcl_Interp *interp)); /* 147 */ int (*tcl_GetAlias) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *slaveCmd, Tcl_Interp **targetInterpPtr, CONST84 char **targetCmdPtr, int *argcPtr, CONST84 char ***argvPtr)); /* 148 */ int (*tcl_GetAliasObj) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *slaveCmd, Tcl_Interp **targetInterpPtr, CONST84 char **targetCmdPtr, int *objcPtr, Tcl_Obj ***objv)); /* 149 */ ClientData (*tcl_GetAssocData) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *name, Tcl_InterpDeleteProc **procPtr)); /* 150 */ Tcl_Channel (*tcl_GetChannel) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *chanName, int *modePtr)); /* 151 */ int (*tcl_GetChannelBufferSize) _ANSI_ARGS_((Tcl_Channel chan)); /* 152 */ int (*tcl_GetChannelHandle) _ANSI_ARGS_((Tcl_Channel chan, int direction, ClientData *handlePtr)); /* 153 */ ClientData (*tcl_GetChannelInstanceData) _ANSI_ARGS_((Tcl_Channel chan)); /* 154 */ int (*tcl_GetChannelMode) _ANSI_ARGS_((Tcl_Channel chan)); /* 155 */ CONST84_RETURN char * (*tcl_GetChannelName) _ANSI_ARGS_((Tcl_Channel chan)); /* 156 */ int (*tcl_GetChannelOption) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Channel chan, CONST char *optionName, Tcl_DString *dsPtr)); /* 157 */ Tcl_ChannelType * (*tcl_GetChannelType) _ANSI_ARGS_((Tcl_Channel chan)); /* 158 */ int (*tcl_GetCommandInfo) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *cmdName, Tcl_CmdInfo *infoPtr)); /* 159 */ CONST84_RETURN char * (*tcl_GetCommandName) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Command command)); /* 160 */ int (*tcl_GetErrno) _ANSI_ARGS_((void)); /* 161 */ CONST84_RETURN char * (*tcl_GetHostName) _ANSI_ARGS_((void)); /* 162 */ int (*tcl_GetInterpPath) _ANSI_ARGS_((Tcl_Interp *askInterp, Tcl_Interp *slaveInterp)); /* 163 */ Tcl_Interp * (*tcl_GetMaster) _ANSI_ARGS_((Tcl_Interp *interp)); /* 164 */ CONST char * (*tcl_GetNameOfExecutable) _ANSI_ARGS_((void)); /* 165 */ Tcl_Obj * (*tcl_GetObjResult) _ANSI_ARGS_((Tcl_Interp *interp)); /* 166 */ #if !defined(__WIN32__) && !defined(MAC_OSX_TCL) /* UNIX */ int (*tcl_GetOpenFile) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *chanID, int forWriting, int checkUsage, ClientData *filePtr)); /* 167 */ #endif /* UNIX */ #if defined(__WIN32__) /* WIN */ VOID *reserved167; #endif /* WIN */ #ifdef MAC_OSX_TCL /* MACOSX */ int (*tcl_GetOpenFile) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *chanID, int forWriting, int checkUsage, ClientData *filePtr)); /* 167 */ #endif /* MACOSX */ Tcl_PathType (*tcl_GetPathType) _ANSI_ARGS_((CONST char *path)); /* 168 */ int (*tcl_Gets) _ANSI_ARGS_((Tcl_Channel chan, Tcl_DString *dsPtr)); /* 169 */ int (*tcl_GetsObj) _ANSI_ARGS_((Tcl_Channel chan, Tcl_Obj *objPtr)); /* 170 */ int (*tcl_GetServiceMode) _ANSI_ARGS_((void)); /* 171 */ Tcl_Interp * (*tcl_GetSlave) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *slaveName)); /* 172 */ Tcl_Channel (*tcl_GetStdChannel) _ANSI_ARGS_((int type)); /* 173 */ CONST84_RETURN char * (*tcl_GetStringResult) _ANSI_ARGS_((Tcl_Interp *interp)); /* 174 */ CONST84_RETURN char * (*tcl_GetVar) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *varName, int flags)); /* 175 */ CONST84_RETURN char * (*tcl_GetVar2) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *part1, CONST char *part2, int flags)); /* 176 */ int (*tcl_GlobalEval) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *command)); /* 177 */ int (*tcl_GlobalEvalObj) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr)); /* 178 */ int (*tcl_HideCommand) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *cmdName, CONST char *hiddenCmdToken)); /* 179 */ int (*tcl_Init) _ANSI_ARGS_((Tcl_Interp *interp)); /* 180 */ void (*tcl_InitHashTable) _ANSI_ARGS_((Tcl_HashTable *tablePtr, int keyType)); /* 181 */ int (*tcl_InputBlocked) _ANSI_ARGS_((Tcl_Channel chan)); /* 182 */ int (*tcl_InputBuffered) _ANSI_ARGS_((Tcl_Channel chan)); /* 183 */ int (*tcl_InterpDeleted) _ANSI_ARGS_((Tcl_Interp *interp)); /* 184 */ int (*tcl_IsSafe) _ANSI_ARGS_((Tcl_Interp *interp)); /* 185 */ char * (*tcl_JoinPath) _ANSI_ARGS_((int argc, CONST84 char *CONST *argv, Tcl_DString *resultPtr)); /* 186 */ int (*tcl_LinkVar) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *varName, char *addr, int type)); /* 187 */ VOID *reserved188; Tcl_Channel (*tcl_MakeFileChannel) _ANSI_ARGS_((ClientData handle, int mode)); /* 189 */ int (*tcl_MakeSafe) _ANSI_ARGS_((Tcl_Interp *interp)); /* 190 */ Tcl_Channel (*tcl_MakeTcpClientChannel) _ANSI_ARGS_((ClientData tcpSocket)); /* 191 */ char * (*tcl_Merge) _ANSI_ARGS_((int argc, CONST84 char *CONST *argv)); /* 192 */ Tcl_HashEntry * (*tcl_NextHashEntry) _ANSI_ARGS_((Tcl_HashSearch *searchPtr)); /* 193 */ void (*tcl_NotifyChannel) _ANSI_ARGS_((Tcl_Channel channel, int mask)); /* 194 */ Tcl_Obj * (*tcl_ObjGetVar2) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, int flags)); /* 195 */ Tcl_Obj * (*tcl_ObjSetVar2) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, Tcl_Obj *newValuePtr, int flags)); /* 196 */ Tcl_Channel (*tcl_OpenCommandChannel) _ANSI_ARGS_((Tcl_Interp *interp, int argc, CONST84 char **argv, int flags)); /* 197 */ Tcl_Channel (*tcl_OpenFileChannel) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *fileName, CONST char *modeString, int permissions)); /* 198 */ Tcl_Channel (*tcl_OpenTcpClient) _ANSI_ARGS_((Tcl_Interp *interp, int port, CONST char *address, CONST char *myaddr, int myport, int async)); /* 199 */ Tcl_Channel (*tcl_OpenTcpServer) _ANSI_ARGS_((Tcl_Interp *interp, int port, CONST char *host, Tcl_TcpAcceptProc *acceptProc, ClientData callbackData)); /* 200 */ void (*tcl_Preserve) _ANSI_ARGS_((ClientData data)); /* 201 */ void (*tcl_PrintDouble) _ANSI_ARGS_((Tcl_Interp *interp, double value, char *dst)); /* 202 */ int (*tcl_PutEnv) _ANSI_ARGS_((CONST char *assignment)); /* 203 */ CONST84_RETURN char * (*tcl_PosixError) _ANSI_ARGS_((Tcl_Interp *interp)); /* 204 */ void (*tcl_QueueEvent) _ANSI_ARGS_((Tcl_Event *evPtr, Tcl_QueuePosition position)); /* 205 */ int (*tcl_Read) _ANSI_ARGS_((Tcl_Channel chan, char *bufPtr, int toRead)); /* 206 */ void (*tcl_ReapDetachedProcs) _ANSI_ARGS_((void)); /* 207 */ int (*tcl_RecordAndEval) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *cmd, int flags)); /* 208 */ int (*tcl_RecordAndEvalObj) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *cmdPtr, int flags)); /* 209 */ void (*tcl_RegisterChannel) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Channel chan)); /* 210 */ void (*tcl_RegisterObjType) _ANSI_ARGS_((Tcl_ObjType *typePtr)); /* 211 */ Tcl_RegExp (*tcl_RegExpCompile) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *pattern)); /* 212 */ int (*tcl_RegExpExec) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_RegExp regexp, CONST char *text, CONST char *start)); /* 213 */ int (*tcl_RegExpMatch) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *text, CONST char *pattern)); /* 214 */ void (*tcl_RegExpRange) _ANSI_ARGS_((Tcl_RegExp regexp, int index, CONST84 char **startPtr, CONST84 char **endPtr)); /* 215 */ void (*tcl_Release) _ANSI_ARGS_((ClientData clientData)); /* 216 */ void (*tcl_ResetResult) _ANSI_ARGS_((Tcl_Interp *interp)); /* 217 */ int (*tcl_ScanElement) _ANSI_ARGS_((CONST char *src, int *flagPtr)); /* 218 */ int (*tcl_ScanCountedElement) _ANSI_ARGS_((CONST char *src, int length, int *flagPtr)); /* 219 */ int (*tcl_SeekOld) _ANSI_ARGS_((Tcl_Channel chan, int offset, int mode)); /* 220 */ int (*tcl_ServiceAll) _ANSI_ARGS_((void)); /* 221 */ int (*tcl_ServiceEvent) _ANSI_ARGS_((int flags)); /* 222 */ void (*tcl_SetAssocData) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *name, Tcl_InterpDeleteProc *proc, ClientData clientData)); /* 223 */ void (*tcl_SetChannelBufferSize) _ANSI_ARGS_((Tcl_Channel chan, int sz)); /* 224 */ int (*tcl_SetChannelOption) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Channel chan, CONST char *optionName, CONST char *newValue)); /* 225 */ int (*tcl_SetCommandInfo) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *cmdName, CONST Tcl_CmdInfo *infoPtr)); /* 226 */ void (*tcl_SetErrno) _ANSI_ARGS_((int err)); /* 227 */ void (*tcl_SetErrorCode) _ANSI_ARGS_((Tcl_Interp *interp, ...)); /* 228 */ void (*tcl_SetMaxBlockTime) _ANSI_ARGS_((Tcl_Time *timePtr)); /* 229 */ void (*tcl_SetPanicProc) _ANSI_ARGS_((Tcl_PanicProc *panicProc)); /* 230 */ int (*tcl_SetRecursionLimit) _ANSI_ARGS_((Tcl_Interp *interp, int depth)); /* 231 */ void (*tcl_SetResult) _ANSI_ARGS_((Tcl_Interp *interp, char *result, Tcl_FreeProc *freeProc)); /* 232 */ int (*tcl_SetServiceMode) _ANSI_ARGS_((int mode)); /* 233 */ void (*tcl_SetObjErrorCode) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *errorObjPtr)); /* 234 */ void (*tcl_SetObjResult) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *resultObjPtr)); /* 235 */ void (*tcl_SetStdChannel) _ANSI_ARGS_((Tcl_Channel channel, int type)); /* 236 */ CONST84_RETURN char * (*tcl_SetVar) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *varName, CONST char *newValue, int flags)); /* 237 */ CONST84_RETURN char * (*tcl_SetVar2) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *part1, CONST char *part2, CONST char *newValue, int flags)); /* 238 */ CONST84_RETURN char * (*tcl_SignalId) _ANSI_ARGS_((int sig)); /* 239 */ CONST84_RETURN char * (*tcl_SignalMsg) _ANSI_ARGS_((int sig)); /* 240 */ void (*tcl_SourceRCFile) _ANSI_ARGS_((Tcl_Interp *interp)); /* 241 */ int (*tcl_SplitList) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *listStr, int *argcPtr, CONST84 char ***argvPtr)); /* 242 */ void (*tcl_SplitPath) _ANSI_ARGS_((CONST char *path, int *argcPtr, CONST84 char ***argvPtr)); /* 243 */ void (*tcl_StaticPackage) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *pkgName, Tcl_PackageInitProc *initProc, Tcl_PackageInitProc *safeInitProc)); /* 244 */ int (*tcl_StringMatch) _ANSI_ARGS_((CONST char *str, CONST char *pattern)); /* 245 */ int (*tcl_TellOld) _ANSI_ARGS_((Tcl_Channel chan)); /* 246 */ int (*tcl_TraceVar) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *varName, int flags, Tcl_VarTraceProc *proc, ClientData clientData)); /* 247 */ int (*tcl_TraceVar2) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *part1, CONST char *part2, int flags, Tcl_VarTraceProc *proc, ClientData clientData)); /* 248 */ char * (*tcl_TranslateFileName) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *name, Tcl_DString *bufferPtr)); /* 249 */ int (*tcl_Ungets) _ANSI_ARGS_((Tcl_Channel chan, CONST char *str, int len, int atHead)); /* 250 */ void (*tcl_UnlinkVar) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *varName)); /* 251 */ int (*tcl_UnregisterChannel) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Channel chan)); /* 252 */ int (*tcl_UnsetVar) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *varName, int flags)); /* 253 */ int (*tcl_UnsetVar2) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *part1, CONST char *part2, int flags)); /* 254 */ void (*tcl_UntraceVar) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *varName, int flags, Tcl_VarTraceProc *proc, ClientData clientData)); /* 255 */ void (*tcl_UntraceVar2) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *part1, CONST char *part2, int flags, Tcl_VarTraceProc *proc, ClientData clientData)); /* 256 */ void (*tcl_UpdateLinkedVar) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *varName)); /* 257 */ int (*tcl_UpVar) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *frameName, CONST char *varName, CONST char *localName, int flags)); /* 258 */ int (*tcl_UpVar2) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *frameName, CONST char *part1, CONST char *part2, CONST char *localName, int flags)); /* 259 */ int (*tcl_VarEval) _ANSI_ARGS_((Tcl_Interp *interp, ...)); /* 260 */ ClientData (*tcl_VarTraceInfo) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *varName, int flags, Tcl_VarTraceProc *procPtr, ClientData prevClientData)); /* 261 */ ClientData (*tcl_VarTraceInfo2) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *part1, CONST char *part2, int flags, Tcl_VarTraceProc *procPtr, ClientData prevClientData)); /* 262 */ int (*tcl_Write) _ANSI_ARGS_((Tcl_Channel chan, CONST char *s, int slen)); /* 263 */ void (*tcl_WrongNumArgs) _ANSI_ARGS_((Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], CONST char *message)); /* 264 */ int (*tcl_DumpActiveMemory) _ANSI_ARGS_((CONST char *fileName)); /* 265 */ void (*tcl_ValidateAllMemory) _ANSI_ARGS_((CONST char *file, int line)); /* 266 */ void (*tcl_AppendResultVA) _ANSI_ARGS_((Tcl_Interp *interp, va_list argList)); /* 267 */ void (*tcl_AppendStringsToObjVA) _ANSI_ARGS_((Tcl_Obj *objPtr, va_list argList)); /* 268 */ char * (*tcl_HashStats) _ANSI_ARGS_((Tcl_HashTable *tablePtr)); /* 269 */ CONST84_RETURN char * (*tcl_ParseVar) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *start, CONST84 char **termPtr)); /* 270 */ CONST84_RETURN char * (*tcl_PkgPresent) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *name, CONST char *version, int exact)); /* 271 */ CONST84_RETURN char * (*tcl_PkgPresentEx) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *name, CONST char *version, int exact, ClientData *clientDataPtr)); /* 272 */ int (*tcl_PkgProvide) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *name, CONST char *version)); /* 273 */ CONST84_RETURN char * (*tcl_PkgRequire) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *name, CONST char *version, int exact)); /* 274 */ void (*tcl_SetErrorCodeVA) _ANSI_ARGS_((Tcl_Interp *interp, va_list argList)); /* 275 */ int (*tcl_VarEvalVA) _ANSI_ARGS_((Tcl_Interp *interp, va_list argList)); /* 276 */ Tcl_Pid (*tcl_WaitPid) _ANSI_ARGS_((Tcl_Pid pid, int *statPtr, int options)); /* 277 */ void (*tcl_PanicVA) _ANSI_ARGS_((CONST char *format, va_list argList)); /* 278 */ void (*tcl_GetVersion) _ANSI_ARGS_((int *major, int *minor, int *patchLevel, int *type)); /* 279 */ void (*tcl_InitMemory) _ANSI_ARGS_((Tcl_Interp *interp)); /* 280 */ Tcl_Channel (*tcl_StackChannel) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_ChannelType *typePtr, ClientData instanceData, int mask, Tcl_Channel prevChan)); /* 281 */ int (*tcl_UnstackChannel) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Channel chan)); /* 282 */ Tcl_Channel (*tcl_GetStackedChannel) _ANSI_ARGS_((Tcl_Channel chan)); /* 283 */ void (*tcl_SetMainLoop) _ANSI_ARGS_((Tcl_MainLoopProc *proc)); /* 284 */ VOID *reserved285; void (*tcl_AppendObjToObj) _ANSI_ARGS_((Tcl_Obj *objPtr, Tcl_Obj *appendObjPtr)); /* 286 */ Tcl_Encoding (*tcl_CreateEncoding) _ANSI_ARGS_((Tcl_EncodingType *typePtr)); /* 287 */ void (*tcl_CreateThreadExitHandler) _ANSI_ARGS_((Tcl_ExitProc *proc, ClientData clientData)); /* 288 */ void (*tcl_DeleteThreadExitHandler) _ANSI_ARGS_((Tcl_ExitProc *proc, ClientData clientData)); /* 289 */ void (*tcl_DiscardResult) _ANSI_ARGS_((Tcl_SavedResult *statePtr)); /* 290 */ int (*tcl_EvalEx) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *script, int numBytes, int flags)); /* 291 */ int (*tcl_EvalObjv) _ANSI_ARGS_((Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], int flags)); /* 292 */ int (*tcl_EvalObjEx) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr, int flags)); /* 293 */ void (*tcl_ExitThread) _ANSI_ARGS_((int status)); /* 294 */ int (*tcl_ExternalToUtf) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Encoding encoding, CONST char *src, int srcLen, int flags, Tcl_EncodingState *statePtr, char *dst, int dstLen, int *srcReadPtr, int *dstWrotePtr, int *dstCharsPtr)); /* 295 */ char * (*tcl_ExternalToUtfDString) _ANSI_ARGS_((Tcl_Encoding encoding, CONST char *src, int srcLen, Tcl_DString *dsPtr)); /* 296 */ void (*tcl_FinalizeThread) _ANSI_ARGS_((void)); /* 297 */ void (*tcl_FinalizeNotifier) _ANSI_ARGS_((ClientData clientData)); /* 298 */ void (*tcl_FreeEncoding) _ANSI_ARGS_((Tcl_Encoding encoding)); /* 299 */ Tcl_ThreadId (*tcl_GetCurrentThread) _ANSI_ARGS_((void)); /* 300 */ Tcl_Encoding (*tcl_GetEncoding) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *name)); /* 301 */ CONST84_RETURN char * (*tcl_GetEncodingName) _ANSI_ARGS_((Tcl_Encoding encoding)); /* 302 */ void (*tcl_GetEncodingNames) _ANSI_ARGS_((Tcl_Interp *interp)); /* 303 */ int (*tcl_GetIndexFromObjStruct) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr, CONST VOID *tablePtr, int offset, CONST char *msg, int flags, int *indexPtr)); /* 304 */ VOID * (*tcl_GetThreadData) _ANSI_ARGS_((Tcl_ThreadDataKey *keyPtr, int size)); /* 305 */ Tcl_Obj * (*tcl_GetVar2Ex) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *part1, CONST char *part2, int flags)); /* 306 */ ClientData (*tcl_InitNotifier) _ANSI_ARGS_((void)); /* 307 */ void (*tcl_MutexLock) _ANSI_ARGS_((Tcl_Mutex *mutexPtr)); /* 308 */ void (*tcl_MutexUnlock) _ANSI_ARGS_((Tcl_Mutex *mutexPtr)); /* 309 */ void (*tcl_ConditionNotify) _ANSI_ARGS_((Tcl_Condition *condPtr)); /* 310 */ void (*tcl_ConditionWait) _ANSI_ARGS_((Tcl_Condition *condPtr, Tcl_Mutex *mutexPtr, Tcl_Time *timePtr)); /* 311 */ int (*tcl_NumUtfChars) _ANSI_ARGS_((CONST char *src, int length)); /* 312 */ int (*tcl_ReadChars) _ANSI_ARGS_((Tcl_Channel channel, Tcl_Obj *objPtr, int charsToRead, int appendFlag)); /* 313 */ void (*tcl_RestoreResult) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_SavedResult *statePtr)); /* 314 */ void (*tcl_SaveResult) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_SavedResult *statePtr)); /* 315 */ int (*tcl_SetSystemEncoding) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *name)); /* 316 */ Tcl_Obj * (*tcl_SetVar2Ex) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *part1, CONST char *part2, Tcl_Obj *newValuePtr, int flags)); /* 317 */ void (*tcl_ThreadAlert) _ANSI_ARGS_((Tcl_ThreadId threadId)); /* 318 */ void (*tcl_ThreadQueueEvent) _ANSI_ARGS_((Tcl_ThreadId threadId, Tcl_Event *evPtr, Tcl_QueuePosition position)); /* 319 */ Tcl_UniChar (*tcl_UniCharAtIndex) _ANSI_ARGS_((CONST char *src, int index)); /* 320 */ Tcl_UniChar (*tcl_UniCharToLower) _ANSI_ARGS_((int ch)); /* 321 */ Tcl_UniChar (*tcl_UniCharToTitle) _ANSI_ARGS_((int ch)); /* 322 */ Tcl_UniChar (*tcl_UniCharToUpper) _ANSI_ARGS_((int ch)); /* 323 */ int (*tcl_UniCharToUtf) _ANSI_ARGS_((int ch, char *buf)); /* 324 */ CONST84_RETURN char * (*tcl_UtfAtIndex) _ANSI_ARGS_((CONST char *src, int index)); /* 325 */ int (*tcl_UtfCharComplete) _ANSI_ARGS_((CONST char *src, int length)); /* 326 */ int (*tcl_UtfBackslash) _ANSI_ARGS_((CONST char *src, int *readPtr, char *dst)); /* 327 */ CONST84_RETURN char * (*tcl_UtfFindFirst) _ANSI_ARGS_((CONST char *src, int ch)); /* 328 */ CONST84_RETURN char * (*tcl_UtfFindLast) _ANSI_ARGS_((CONST char *src, int ch)); /* 329 */ CONST84_RETURN char * (*tcl_UtfNext) _ANSI_ARGS_((CONST char *src)); /* 330 */ CONST84_RETURN char * (*tcl_UtfPrev) _ANSI_ARGS_((CONST char *src, CONST char *start)); /* 331 */ int (*tcl_UtfToExternal) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Encoding encoding, CONST char *src, int srcLen, int flags, Tcl_EncodingState *statePtr, char *dst, int dstLen, int *srcReadPtr, int *dstWrotePtr, int *dstCharsPtr)); /* 332 */ char * (*tcl_UtfToExternalDString) _ANSI_ARGS_((Tcl_Encoding encoding, CONST char *src, int srcLen, Tcl_DString *dsPtr)); /* 333 */ int (*tcl_UtfToLower) _ANSI_ARGS_((char *src)); /* 334 */ int (*tcl_UtfToTitle) _ANSI_ARGS_((char *src)); /* 335 */ int (*tcl_UtfToUniChar) _ANSI_ARGS_((CONST char *src, Tcl_UniChar *chPtr)); /* 336 */ int (*tcl_UtfToUpper) _ANSI_ARGS_((char *src)); /* 337 */ int (*tcl_WriteChars) _ANSI_ARGS_((Tcl_Channel chan, CONST char *src, int srcLen)); /* 338 */ int (*tcl_WriteObj) _ANSI_ARGS_((Tcl_Channel chan, Tcl_Obj *objPtr)); /* 339 */ char * (*tcl_GetString) _ANSI_ARGS_((Tcl_Obj *objPtr)); /* 340 */ CONST84_RETURN char * (*tcl_GetDefaultEncodingDir) _ANSI_ARGS_((void)); /* 341 */ void (*tcl_SetDefaultEncodingDir) _ANSI_ARGS_((CONST char *path)); /* 342 */ void (*tcl_AlertNotifier) _ANSI_ARGS_((ClientData clientData)); /* 343 */ void (*tcl_ServiceModeHook) _ANSI_ARGS_((int mode)); /* 344 */ int (*tcl_UniCharIsAlnum) _ANSI_ARGS_((int ch)); /* 345 */ int (*tcl_UniCharIsAlpha) _ANSI_ARGS_((int ch)); /* 346 */ int (*tcl_UniCharIsDigit) _ANSI_ARGS_((int ch)); /* 347 */ int (*tcl_UniCharIsLower) _ANSI_ARGS_((int ch)); /* 348 */ int (*tcl_UniCharIsSpace) _ANSI_ARGS_((int ch)); /* 349 */ int (*tcl_UniCharIsUpper) _ANSI_ARGS_((int ch)); /* 350 */ int (*tcl_UniCharIsWordChar) _ANSI_ARGS_((int ch)); /* 351 */ int (*tcl_UniCharLen) _ANSI_ARGS_((CONST Tcl_UniChar *uniStr)); /* 352 */ int (*tcl_UniCharNcmp) _ANSI_ARGS_((CONST Tcl_UniChar *ucs, CONST Tcl_UniChar *uct, unsigned long numChars)); /* 353 */ char * (*tcl_UniCharToUtfDString) _ANSI_ARGS_((CONST Tcl_UniChar *uniStr, int uniLength, Tcl_DString *dsPtr)); /* 354 */ Tcl_UniChar * (*tcl_UtfToUniCharDString) _ANSI_ARGS_((CONST char *src, int length, Tcl_DString *dsPtr)); /* 355 */ Tcl_RegExp (*tcl_GetRegExpFromObj) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *patObj, int flags)); /* 356 */ Tcl_Obj * (*tcl_EvalTokens) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Token *tokenPtr, int count)); /* 357 */ void (*tcl_FreeParse) _ANSI_ARGS_((Tcl_Parse *parsePtr)); /* 358 */ void (*tcl_LogCommandInfo) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *script, CONST char *command, int length)); /* 359 */ int (*tcl_ParseBraces) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *start, int numBytes, Tcl_Parse *parsePtr, int append, CONST84 char **termPtr)); /* 360 */ int (*tcl_ParseCommand) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *start, int numBytes, int nested, Tcl_Parse *parsePtr)); /* 361 */ int (*tcl_ParseExpr) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *start, int numBytes, Tcl_Parse *parsePtr)); /* 362 */ int (*tcl_ParseQuotedString) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *start, int numBytes, Tcl_Parse *parsePtr, int append, CONST84 char **termPtr)); /* 363 */ int (*tcl_ParseVarName) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *start, int numBytes, Tcl_Parse *parsePtr, int append)); /* 364 */ char * (*tcl_GetCwd) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_DString *cwdPtr)); /* 365 */ int (*tcl_Chdir) _ANSI_ARGS_((CONST char *dirName)); /* 366 */ int (*tcl_Access) _ANSI_ARGS_((CONST char *path, int mode)); /* 367 */ int (*tcl_Stat) _ANSI_ARGS_((CONST char *path, struct stat *bufPtr)); /* 368 */ int (*tcl_UtfNcmp) _ANSI_ARGS_((CONST char *s1, CONST char *s2, unsigned long n)); /* 369 */ int (*tcl_UtfNcasecmp) _ANSI_ARGS_((CONST char *s1, CONST char *s2, unsigned long n)); /* 370 */ int (*tcl_StringCaseMatch) _ANSI_ARGS_((CONST char *str, CONST char *pattern, int nocase)); /* 371 */ int (*tcl_UniCharIsControl) _ANSI_ARGS_((int ch)); /* 372 */ int (*tcl_UniCharIsGraph) _ANSI_ARGS_((int ch)); /* 373 */ int (*tcl_UniCharIsPrint) _ANSI_ARGS_((int ch)); /* 374 */ int (*tcl_UniCharIsPunct) _ANSI_ARGS_((int ch)); /* 375 */ int (*tcl_RegExpExecObj) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_RegExp regexp, Tcl_Obj *textObj, int offset, int nmatches, int flags)); /* 376 */ void (*tcl_RegExpGetInfo) _ANSI_ARGS_((Tcl_RegExp regexp, Tcl_RegExpInfo *infoPtr)); /* 377 */ Tcl_Obj * (*tcl_NewUnicodeObj) _ANSI_ARGS_((CONST Tcl_UniChar *unicode, int numChars)); /* 378 */ void (*tcl_SetUnicodeObj) _ANSI_ARGS_((Tcl_Obj *objPtr, CONST Tcl_UniChar *unicode, int numChars)); /* 379 */ int (*tcl_GetCharLength) _ANSI_ARGS_((Tcl_Obj *objPtr)); /* 380 */ Tcl_UniChar (*tcl_GetUniChar) _ANSI_ARGS_((Tcl_Obj *objPtr, int index)); /* 381 */ Tcl_UniChar * (*tcl_GetUnicode) _ANSI_ARGS_((Tcl_Obj *objPtr)); /* 382 */ Tcl_Obj * (*tcl_GetRange) _ANSI_ARGS_((Tcl_Obj *objPtr, int first, int last)); /* 383 */ void (*tcl_AppendUnicodeToObj) _ANSI_ARGS_((Tcl_Obj *objPtr, CONST Tcl_UniChar *unicode, int length)); /* 384 */ int (*tcl_RegExpMatchObj) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *textObj, Tcl_Obj *patternObj)); /* 385 */ void (*tcl_SetNotifier) _ANSI_ARGS_((Tcl_NotifierProcs *notifierProcPtr)); /* 386 */ Tcl_Mutex * (*tcl_GetAllocMutex) _ANSI_ARGS_((void)); /* 387 */ int (*tcl_GetChannelNames) _ANSI_ARGS_((Tcl_Interp *interp)); /* 388 */ int (*tcl_GetChannelNamesEx) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *pattern)); /* 389 */ int (*tcl_ProcObjCmd) _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); /* 390 */ void (*tcl_ConditionFinalize) _ANSI_ARGS_((Tcl_Condition *condPtr)); /* 391 */ void (*tcl_MutexFinalize) _ANSI_ARGS_((Tcl_Mutex *mutex)); /* 392 */ int (*tcl_CreateThread) _ANSI_ARGS_((Tcl_ThreadId *idPtr, Tcl_ThreadCreateProc proc, ClientData clientData, int stackSize, int flags)); /* 393 */ int (*tcl_ReadRaw) _ANSI_ARGS_((Tcl_Channel chan, char *dst, int bytesToRead)); /* 394 */ int (*tcl_WriteRaw) _ANSI_ARGS_((Tcl_Channel chan, CONST char *src, int srcLen)); /* 395 */ Tcl_Channel (*tcl_GetTopChannel) _ANSI_ARGS_((Tcl_Channel chan)); /* 396 */ int (*tcl_ChannelBuffered) _ANSI_ARGS_((Tcl_Channel chan)); /* 397 */ CONST84_RETURN char * (*tcl_ChannelName) _ANSI_ARGS_((Tcl_ChannelType *chanTypePtr)); /* 398 */ Tcl_ChannelTypeVersion (*tcl_ChannelVersion) _ANSI_ARGS_((Tcl_ChannelType *chanTypePtr)); /* 399 */ Tcl_DriverBlockModeProc * (*tcl_ChannelBlockModeProc) _ANSI_ARGS_((Tcl_ChannelType *chanTypePtr)); /* 400 */ Tcl_DriverCloseProc * (*tcl_ChannelCloseProc) _ANSI_ARGS_((Tcl_ChannelType *chanTypePtr)); /* 401 */ Tcl_DriverClose2Proc * (*tcl_ChannelClose2Proc) _ANSI_ARGS_((Tcl_ChannelType *chanTypePtr)); /* 402 */ Tcl_DriverInputProc * (*tcl_ChannelInputProc) _ANSI_ARGS_((Tcl_ChannelType *chanTypePtr)); /* 403 */ Tcl_DriverOutputProc * (*tcl_ChannelOutputProc) _ANSI_ARGS_((Tcl_ChannelType *chanTypePtr)); /* 404 */ Tcl_DriverSeekProc * (*tcl_ChannelSeekProc) _ANSI_ARGS_((Tcl_ChannelType *chanTypePtr)); /* 405 */ Tcl_DriverSetOptionProc * (*tcl_ChannelSetOptionProc) _ANSI_ARGS_((Tcl_ChannelType *chanTypePtr)); /* 406 */ Tcl_DriverGetOptionProc * (*tcl_ChannelGetOptionProc) _ANSI_ARGS_((Tcl_ChannelType *chanTypePtr)); /* 407 */ Tcl_DriverWatchProc * (*tcl_ChannelWatchProc) _ANSI_ARGS_((Tcl_ChannelType *chanTypePtr)); /* 408 */ Tcl_DriverGetHandleProc * (*tcl_ChannelGetHandleProc) _ANSI_ARGS_((Tcl_ChannelType *chanTypePtr)); /* 409 */ Tcl_DriverFlushProc * (*tcl_ChannelFlushProc) _ANSI_ARGS_((Tcl_ChannelType *chanTypePtr)); /* 410 */ Tcl_DriverHandlerProc * (*tcl_ChannelHandlerProc) _ANSI_ARGS_((Tcl_ChannelType *chanTypePtr)); /* 411 */ int (*tcl_JoinThread) _ANSI_ARGS_((Tcl_ThreadId threadId, int *result)); /* 412 */ int (*tcl_IsChannelShared) _ANSI_ARGS_((Tcl_Channel channel)); /* 413 */ int (*tcl_IsChannelRegistered) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Channel channel)); /* 414 */ void (*tcl_CutChannel) _ANSI_ARGS_((Tcl_Channel channel)); /* 415 */ void (*tcl_SpliceChannel) _ANSI_ARGS_((Tcl_Channel channel)); /* 416 */ void (*tcl_ClearChannelHandlers) _ANSI_ARGS_((Tcl_Channel channel)); /* 417 */ int (*tcl_IsChannelExisting) _ANSI_ARGS_((CONST char *channelName)); /* 418 */ int (*tcl_UniCharNcasecmp) _ANSI_ARGS_((CONST Tcl_UniChar *ucs, CONST Tcl_UniChar *uct, unsigned long numChars)); /* 419 */ int (*tcl_UniCharCaseMatch) _ANSI_ARGS_((CONST Tcl_UniChar *uniStr, CONST Tcl_UniChar *uniPattern, int nocase)); /* 420 */ Tcl_HashEntry * (*tcl_FindHashEntry) _ANSI_ARGS_((Tcl_HashTable *tablePtr, CONST char *key)); /* 421 */ Tcl_HashEntry * (*tcl_CreateHashEntry) _ANSI_ARGS_((Tcl_HashTable *tablePtr, CONST char *key, int *newPtr)); /* 422 */ void (*tcl_InitCustomHashTable) _ANSI_ARGS_((Tcl_HashTable *tablePtr, int keyType, Tcl_HashKeyType *typePtr)); /* 423 */ void (*tcl_InitObjHashTable) _ANSI_ARGS_((Tcl_HashTable *tablePtr)); /* 424 */ ClientData (*tcl_CommandTraceInfo) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *varName, int flags, Tcl_CommandTraceProc *procPtr, ClientData prevClientData)); /* 425 */ int (*tcl_TraceCommand) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *varName, int flags, Tcl_CommandTraceProc *proc, ClientData clientData)); /* 426 */ void (*tcl_UntraceCommand) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *varName, int flags, Tcl_CommandTraceProc *proc, ClientData clientData)); /* 427 */ char * (*tcl_AttemptAlloc) _ANSI_ARGS_((unsigned int size)); /* 428 */ char * (*tcl_AttemptDbCkalloc) _ANSI_ARGS_((unsigned int size, CONST char *file, int line)); /* 429 */ char * (*tcl_AttemptRealloc) _ANSI_ARGS_((char *ptr, unsigned int size)); /* 430 */ char * (*tcl_AttemptDbCkrealloc) _ANSI_ARGS_((char *ptr, unsigned int size, CONST char *file, int line)); /* 431 */ int (*tcl_AttemptSetObjLength) _ANSI_ARGS_((Tcl_Obj *objPtr, int length)); /* 432 */ Tcl_ThreadId (*tcl_GetChannelThread) _ANSI_ARGS_((Tcl_Channel channel)); /* 433 */ Tcl_UniChar * (*tcl_GetUnicodeFromObj) _ANSI_ARGS_((Tcl_Obj *objPtr, int *lengthPtr)); /* 434 */ int (*tcl_GetMathFuncInfo) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *name, int *numArgsPtr, Tcl_ValueType **argTypesPtr, Tcl_MathProc **procPtr, ClientData *clientDataPtr)); /* 435 */ Tcl_Obj * (*tcl_ListMathFuncs) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *pattern)); /* 436 */ Tcl_Obj * (*tcl_SubstObj) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr, int flags)); /* 437 */ int (*tcl_DetachChannel) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Channel channel)); /* 438 */ int (*tcl_IsStandardChannel) _ANSI_ARGS_((Tcl_Channel channel)); /* 439 */ int (*tcl_FSCopyFile) _ANSI_ARGS_((Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr)); /* 440 */ int (*tcl_FSCopyDirectory) _ANSI_ARGS_((Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr, Tcl_Obj **errorPtr)); /* 441 */ int (*tcl_FSCreateDirectory) _ANSI_ARGS_((Tcl_Obj *pathPtr)); /* 442 */ int (*tcl_FSDeleteFile) _ANSI_ARGS_((Tcl_Obj *pathPtr)); /* 443 */ int (*tcl_FSLoadFile) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *pathPtr, CONST char *sym1, CONST char *sym2, Tcl_PackageInitProc **proc1Ptr, Tcl_PackageInitProc **proc2Ptr, Tcl_LoadHandle *handlePtr, Tcl_FSUnloadFileProc **unloadProcPtr)); /* 444 */ int (*tcl_FSMatchInDirectory) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *result, Tcl_Obj *pathPtr, CONST char *pattern, Tcl_GlobTypeData *types)); /* 445 */ Tcl_Obj * (*tcl_FSLink) _ANSI_ARGS_((Tcl_Obj *pathPtr, Tcl_Obj *toPtr, int linkAction)); /* 446 */ int (*tcl_FSRemoveDirectory) _ANSI_ARGS_((Tcl_Obj *pathPtr, int recursive, Tcl_Obj **errorPtr)); /* 447 */ int (*tcl_FSRenameFile) _ANSI_ARGS_((Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr)); /* 448 */ int (*tcl_FSLstat) _ANSI_ARGS_((Tcl_Obj *pathPtr, Tcl_StatBuf *buf)); /* 449 */ int (*tcl_FSUtime) _ANSI_ARGS_((Tcl_Obj *pathPtr, struct utimbuf *tval)); /* 450 */ int (*tcl_FSFileAttrsGet) _ANSI_ARGS_((Tcl_Interp *interp, int index, Tcl_Obj *pathPtr, Tcl_Obj **objPtrRef)); /* 451 */ int (*tcl_FSFileAttrsSet) _ANSI_ARGS_((Tcl_Interp *interp, int index, Tcl_Obj *pathPtr, Tcl_Obj *objPtr)); /* 452 */ CONST char ** (*tcl_FSFileAttrStrings) _ANSI_ARGS_((Tcl_Obj *pathPtr, Tcl_Obj **objPtrRef)); /* 453 */ int (*tcl_FSStat) _ANSI_ARGS_((Tcl_Obj *pathPtr, Tcl_StatBuf *buf)); /* 454 */ int (*tcl_FSAccess) _ANSI_ARGS_((Tcl_Obj *pathPtr, int mode)); /* 455 */ Tcl_Channel (*tcl_FSOpenFileChannel) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *pathPtr, CONST char *modeString, int permissions)); /* 456 */ Tcl_Obj * (*tcl_FSGetCwd) _ANSI_ARGS_((Tcl_Interp *interp)); /* 457 */ int (*tcl_FSChdir) _ANSI_ARGS_((Tcl_Obj *pathPtr)); /* 458 */ int (*tcl_FSConvertToPathType) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *pathPtr)); /* 459 */ Tcl_Obj * (*tcl_FSJoinPath) _ANSI_ARGS_((Tcl_Obj *listObj, int elements)); /* 460 */ Tcl_Obj * (*tcl_FSSplitPath) _ANSI_ARGS_((Tcl_Obj *pathPtr, int *lenPtr)); /* 461 */ int (*tcl_FSEqualPaths) _ANSI_ARGS_((Tcl_Obj *firstPtr, Tcl_Obj *secondPtr)); /* 462 */ Tcl_Obj * (*tcl_FSGetNormalizedPath) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *pathPtr)); /* 463 */ Tcl_Obj * (*tcl_FSJoinToPath) _ANSI_ARGS_((Tcl_Obj *pathPtr, int objc, Tcl_Obj *CONST objv[])); /* 464 */ ClientData (*tcl_FSGetInternalRep) _ANSI_ARGS_((Tcl_Obj *pathPtr, Tcl_Filesystem *fsPtr)); /* 465 */ Tcl_Obj * (*tcl_FSGetTranslatedPath) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *pathPtr)); /* 466 */ int (*tcl_FSEvalFile) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *fileName)); /* 467 */ Tcl_Obj * (*tcl_FSNewNativePath) _ANSI_ARGS_((Tcl_Filesystem *fromFilesystem, ClientData clientData)); /* 468 */ CONST char * (*tcl_FSGetNativePath) _ANSI_ARGS_((Tcl_Obj *pathPtr)); /* 469 */ Tcl_Obj * (*tcl_FSFileSystemInfo) _ANSI_ARGS_((Tcl_Obj *pathPtr)); /* 470 */ Tcl_Obj * (*tcl_FSPathSeparator) _ANSI_ARGS_((Tcl_Obj *pathPtr)); /* 471 */ Tcl_Obj * (*tcl_FSListVolumes) _ANSI_ARGS_((void)); /* 472 */ int (*tcl_FSRegister) _ANSI_ARGS_((ClientData clientData, Tcl_Filesystem *fsPtr)); /* 473 */ int (*tcl_FSUnregister) _ANSI_ARGS_((Tcl_Filesystem *fsPtr)); /* 474 */ ClientData (*tcl_FSData) _ANSI_ARGS_((Tcl_Filesystem *fsPtr)); /* 475 */ CONST char * (*tcl_FSGetTranslatedStringPath) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *pathPtr)); /* 476 */ Tcl_Filesystem * (*tcl_FSGetFileSystemForPath) _ANSI_ARGS_((Tcl_Obj *pathPtr)); /* 477 */ Tcl_PathType (*tcl_FSGetPathType) _ANSI_ARGS_((Tcl_Obj *pathPtr)); /* 478 */ int (*tcl_OutputBuffered) _ANSI_ARGS_((Tcl_Channel chan)); /* 479 */ void (*tcl_FSMountsChanged) _ANSI_ARGS_((Tcl_Filesystem *fsPtr)); /* 480 */ int (*tcl_EvalTokensStandard) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Token *tokenPtr, int count)); /* 481 */ void (*tcl_GetTime) _ANSI_ARGS_((Tcl_Time *timeBuf)); /* 482 */ Tcl_Trace (*tcl_CreateObjTrace) _ANSI_ARGS_((Tcl_Interp *interp, int level, int flags, Tcl_CmdObjTraceProc *objProc, ClientData clientData, Tcl_CmdObjTraceDeleteProc *delProc)); /* 483 */ int (*tcl_GetCommandInfoFromToken) _ANSI_ARGS_((Tcl_Command token, Tcl_CmdInfo *infoPtr)); /* 484 */ int (*tcl_SetCommandInfoFromToken) _ANSI_ARGS_((Tcl_Command token, CONST Tcl_CmdInfo *infoPtr)); /* 485 */ Tcl_Obj * (*tcl_DbNewWideIntObj) _ANSI_ARGS_((Tcl_WideInt wideValue, CONST char *file, int line)); /* 486 */ int (*tcl_GetWideIntFromObj) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_WideInt *widePtr)); /* 487 */ Tcl_Obj * (*tcl_NewWideIntObj) _ANSI_ARGS_((Tcl_WideInt wideValue)); /* 488 */ void (*tcl_SetWideIntObj) _ANSI_ARGS_((Tcl_Obj *objPtr, Tcl_WideInt wideValue)); /* 489 */ Tcl_StatBuf * (*tcl_AllocStatBuf) _ANSI_ARGS_((void)); /* 490 */ Tcl_WideInt (*tcl_Seek) _ANSI_ARGS_((Tcl_Channel chan, Tcl_WideInt offset, int mode)); /* 491 */ Tcl_WideInt (*tcl_Tell) _ANSI_ARGS_((Tcl_Channel chan)); /* 492 */ Tcl_DriverWideSeekProc * (*tcl_ChannelWideSeekProc) _ANSI_ARGS_((Tcl_ChannelType *chanTypePtr)); /* 493 */ VOID *reserved494; VOID *reserved495; VOID *reserved496; VOID *reserved497; VOID *reserved498; VOID *reserved499; VOID *reserved500; VOID *reserved501; VOID *reserved502; VOID *reserved503; VOID *reserved504; VOID *reserved505; VOID *reserved506; VOID *reserved507; VOID *reserved508; VOID *reserved509; VOID *reserved510; VOID *reserved511; VOID *reserved512; VOID *reserved513; VOID *reserved514; VOID *reserved515; VOID *reserved516; VOID *reserved517; VOID *reserved518; VOID *reserved519; VOID *reserved520; VOID *reserved521; VOID *reserved522; VOID *reserved523; VOID *reserved524; VOID *reserved525; VOID *reserved526; VOID *reserved527; VOID *reserved528; VOID *reserved529; VOID *reserved530; VOID *reserved531; VOID *reserved532; VOID *reserved533; VOID *reserved534; VOID *reserved535; VOID *reserved536; VOID *reserved537; VOID *reserved538; VOID *reserved539; VOID *reserved540; VOID *reserved541; VOID *reserved542; VOID *reserved543; VOID *reserved544; VOID *reserved545; VOID *reserved546; VOID *reserved547; VOID *reserved548; VOID *reserved549; VOID *reserved550; VOID *reserved551; VOID *reserved552; VOID *reserved553; Tcl_DriverThreadActionProc * (*tcl_ChannelThreadActionProc) _ANSI_ARGS_((Tcl_ChannelType *chanTypePtr)); /* 554 */ VOID *reserved555; VOID *reserved556; VOID *reserved557; VOID *reserved558; VOID *reserved559; VOID *reserved560; VOID *reserved561; VOID *reserved562; VOID *reserved563; VOID *reserved564; VOID *reserved565; VOID *reserved566; VOID *reserved567; VOID *reserved568; VOID *reserved569; VOID *reserved570; VOID *reserved571; VOID *reserved572; int (*tcl_PkgRequireProc) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *name, int objc, Tcl_Obj *CONST objv[], ClientData *clientDataPtr)); /* 573 */ VOID *reserved574; VOID *reserved575; VOID *reserved576; VOID *reserved577; VOID *reserved578; VOID *reserved579; VOID *reserved580; VOID *reserved581; VOID *reserved582; VOID *reserved583; VOID *reserved584; VOID *reserved585; VOID *reserved586; VOID *reserved587; VOID *reserved588; VOID *reserved589; VOID *reserved590; VOID *reserved591; VOID *reserved592; VOID *reserved593; VOID *reserved594; VOID *reserved595; VOID *reserved596; VOID *reserved597; VOID *reserved598; VOID *reserved599; VOID *reserved600; VOID *reserved601; VOID *reserved602; VOID *reserved603; VOID *reserved604; VOID *reserved605; VOID *reserved606; VOID *reserved607; VOID *reserved608; VOID *reserved609; VOID *reserved610; VOID *reserved611; VOID *reserved612; VOID *reserved613; VOID *reserved614; VOID *reserved615; VOID *reserved616; VOID *reserved617; VOID *reserved618; VOID *reserved619; VOID *reserved620; VOID *reserved621; VOID *reserved622; VOID *reserved623; VOID *reserved624; VOID *reserved625; VOID *reserved626; VOID *reserved627; VOID *reserved628; VOID *reserved629; void (*tclUnusedStubEntry) _ANSI_ARGS_((void)); /* 630 */ } TclStubs; #ifdef __cplusplus extern "C" { #endif extern TclStubs *tclStubsPtr; #ifdef __cplusplus } #endif #if defined(USE_TCL_STUBS) && !defined(USE_TCL_STUB_PROCS) /* * Inline function declarations: */ #ifndef Tcl_PkgProvideEx #define Tcl_PkgProvideEx \ (tclStubsPtr->tcl_PkgProvideEx) /* 0 */ #endif #ifndef Tcl_PkgRequireEx #define Tcl_PkgRequireEx \ (tclStubsPtr->tcl_PkgRequireEx) /* 1 */ #endif #ifndef Tcl_Panic #define Tcl_Panic \ (tclStubsPtr->tcl_Panic) /* 2 */ #endif #ifndef Tcl_Alloc #define Tcl_Alloc \ (tclStubsPtr->tcl_Alloc) /* 3 */ #endif #ifndef Tcl_Free #define Tcl_Free \ (tclStubsPtr->tcl_Free) /* 4 */ #endif #ifndef Tcl_Realloc #define Tcl_Realloc \ (tclStubsPtr->tcl_Realloc) /* 5 */ #endif #ifndef Tcl_DbCkalloc #define Tcl_DbCkalloc \ (tclStubsPtr->tcl_DbCkalloc) /* 6 */ #endif #ifndef Tcl_DbCkfree #define Tcl_DbCkfree \ (tclStubsPtr->tcl_DbCkfree) /* 7 */ #endif #ifndef Tcl_DbCkrealloc #define Tcl_DbCkrealloc \ (tclStubsPtr->tcl_DbCkrealloc) /* 8 */ #endif #if !defined(__WIN32__) && !defined(MAC_OSX_TCL) /* UNIX */ #ifndef Tcl_CreateFileHandler #define Tcl_CreateFileHandler \ (tclStubsPtr->tcl_CreateFileHandler) /* 9 */ #endif #endif /* UNIX */ #ifdef MAC_OSX_TCL /* MACOSX */ #ifndef Tcl_CreateFileHandler #define Tcl_CreateFileHandler \ (tclStubsPtr->tcl_CreateFileHandler) /* 9 */ #endif #endif /* MACOSX */ #if !defined(__WIN32__) && !defined(MAC_OSX_TCL) /* UNIX */ #ifndef Tcl_DeleteFileHandler #define Tcl_DeleteFileHandler \ (tclStubsPtr->tcl_DeleteFileHandler) /* 10 */ #endif #endif /* UNIX */ #ifdef MAC_OSX_TCL /* MACOSX */ #ifndef Tcl_DeleteFileHandler #define Tcl_DeleteFileHandler \ (tclStubsPtr->tcl_DeleteFileHandler) /* 10 */ #endif #endif /* MACOSX */ #ifndef Tcl_SetTimer #define Tcl_SetTimer \ (tclStubsPtr->tcl_SetTimer) /* 11 */ #endif #ifndef Tcl_Sleep #define Tcl_Sleep \ (tclStubsPtr->tcl_Sleep) /* 12 */ #endif #ifndef Tcl_WaitForEvent #define Tcl_WaitForEvent \ (tclStubsPtr->tcl_WaitForEvent) /* 13 */ #endif #ifndef Tcl_AppendAllObjTypes #define Tcl_AppendAllObjTypes \ (tclStubsPtr->tcl_AppendAllObjTypes) /* 14 */ #endif #ifndef Tcl_AppendStringsToObj #define Tcl_AppendStringsToObj \ (tclStubsPtr->tcl_AppendStringsToObj) /* 15 */ #endif #ifndef Tcl_AppendToObj #define Tcl_AppendToObj \ (tclStubsPtr->tcl_AppendToObj) /* 16 */ #endif #ifndef Tcl_ConcatObj #define Tcl_ConcatObj \ (tclStubsPtr->tcl_ConcatObj) /* 17 */ #endif #ifndef Tcl_ConvertToType #define Tcl_ConvertToType \ (tclStubsPtr->tcl_ConvertToType) /* 18 */ #endif #ifndef Tcl_DbDecrRefCount #define Tcl_DbDecrRefCount \ (tclStubsPtr->tcl_DbDecrRefCount) /* 19 */ #endif #ifndef Tcl_DbIncrRefCount #define Tcl_DbIncrRefCount \ (tclStubsPtr->tcl_DbIncrRefCount) /* 20 */ #endif #ifndef Tcl_DbIsShared #define Tcl_DbIsShared \ (tclStubsPtr->tcl_DbIsShared) /* 21 */ #endif #ifndef Tcl_DbNewBooleanObj #define Tcl_DbNewBooleanObj \ (tclStubsPtr->tcl_DbNewBooleanObj) /* 22 */ #endif #ifndef Tcl_DbNewByteArrayObj #define Tcl_DbNewByteArrayObj \ (tclStubsPtr->tcl_DbNewByteArrayObj) /* 23 */ #endif #ifndef Tcl_DbNewDoubleObj #define Tcl_DbNewDoubleObj \ (tclStubsPtr->tcl_DbNewDoubleObj) /* 24 */ #endif #ifndef Tcl_DbNewListObj #define Tcl_DbNewListObj \ (tclStubsPtr->tcl_DbNewListObj) /* 25 */ #endif #ifndef Tcl_DbNewLongObj #define Tcl_DbNewLongObj \ (tclStubsPtr->tcl_DbNewLongObj) /* 26 */ #endif #ifndef Tcl_DbNewObj #define Tcl_DbNewObj \ (tclStubsPtr->tcl_DbNewObj) /* 27 */ #endif #ifndef Tcl_DbNewStringObj #define Tcl_DbNewStringObj \ (tclStubsPtr->tcl_DbNewStringObj) /* 28 */ #endif #ifndef Tcl_DuplicateObj #define Tcl_DuplicateObj \ (tclStubsPtr->tcl_DuplicateObj) /* 29 */ #endif #ifndef TclFreeObj #define TclFreeObj \ (tclStubsPtr->tclFreeObj) /* 30 */ #endif #ifndef Tcl_GetBoolean #define Tcl_GetBoolean \ (tclStubsPtr->tcl_GetBoolean) /* 31 */ #endif #ifndef Tcl_GetBooleanFromObj #define Tcl_GetBooleanFromObj \ (tclStubsPtr->tcl_GetBooleanFromObj) /* 32 */ #endif #ifndef Tcl_GetByteArrayFromObj #define Tcl_GetByteArrayFromObj \ (tclStubsPtr->tcl_GetByteArrayFromObj) /* 33 */ #endif #ifndef Tcl_GetDouble #define Tcl_GetDouble \ (tclStubsPtr->tcl_GetDouble) /* 34 */ #endif #ifndef Tcl_GetDoubleFromObj #define Tcl_GetDoubleFromObj \ (tclStubsPtr->tcl_GetDoubleFromObj) /* 35 */ #endif #ifndef Tcl_GetIndexFromObj #define Tcl_GetIndexFromObj \ (tclStubsPtr->tcl_GetIndexFromObj) /* 36 */ #endif #ifndef Tcl_GetInt #define Tcl_GetInt \ (tclStubsPtr->tcl_GetInt) /* 37 */ #endif #ifndef Tcl_GetIntFromObj #define Tcl_GetIntFromObj \ (tclStubsPtr->tcl_GetIntFromObj) /* 38 */ #endif #ifndef Tcl_GetLongFromObj #define Tcl_GetLongFromObj \ (tclStubsPtr->tcl_GetLongFromObj) /* 39 */ #endif #ifndef Tcl_GetObjType #define Tcl_GetObjType \ (tclStubsPtr->tcl_GetObjType) /* 40 */ #endif #ifndef Tcl_GetStringFromObj #define Tcl_GetStringFromObj \ (tclStubsPtr->tcl_GetStringFromObj) /* 41 */ #endif #ifndef Tcl_InvalidateStringRep #define Tcl_InvalidateStringRep \ (tclStubsPtr->tcl_InvalidateStringRep) /* 42 */ #endif #ifndef Tcl_ListObjAppendList #define Tcl_ListObjAppendList \ (tclStubsPtr->tcl_ListObjAppendList) /* 43 */ #endif #ifndef Tcl_ListObjAppendElement #define Tcl_ListObjAppendElement \ (tclStubsPtr->tcl_ListObjAppendElement) /* 44 */ #endif #ifndef Tcl_ListObjGetElements #define Tcl_ListObjGetElements \ (tclStubsPtr->tcl_ListObjGetElements) /* 45 */ #endif #ifndef Tcl_ListObjIndex #define Tcl_ListObjIndex \ (tclStubsPtr->tcl_ListObjIndex) /* 46 */ #endif #ifndef Tcl_ListObjLength #define Tcl_ListObjLength \ (tclStubsPtr->tcl_ListObjLength) /* 47 */ #endif #ifndef Tcl_ListObjReplace #define Tcl_ListObjReplace \ (tclStubsPtr->tcl_ListObjReplace) /* 48 */ #endif #ifndef Tcl_NewBooleanObj #define Tcl_NewBooleanObj \ (tclStubsPtr->tcl_NewBooleanObj) /* 49 */ #endif #ifndef Tcl_NewByteArrayObj #define Tcl_NewByteArrayObj \ (tclStubsPtr->tcl_NewByteArrayObj) /* 50 */ #endif #ifndef Tcl_NewDoubleObj #define Tcl_NewDoubleObj \ (tclStubsPtr->tcl_NewDoubleObj) /* 51 */ #endif #ifndef Tcl_NewIntObj #define Tcl_NewIntObj \ (tclStubsPtr->tcl_NewIntObj) /* 52 */ #endif #ifndef Tcl_NewListObj #define Tcl_NewListObj \ (tclStubsPtr->tcl_NewListObj) /* 53 */ #endif #ifndef Tcl_NewLongObj #define Tcl_NewLongObj \ (tclStubsPtr->tcl_NewLongObj) /* 54 */ #endif #ifndef Tcl_NewObj #define Tcl_NewObj \ (tclStubsPtr->tcl_NewObj) /* 55 */ #endif #ifndef Tcl_NewStringObj #define Tcl_NewStringObj \ (tclStubsPtr->tcl_NewStringObj) /* 56 */ #endif #ifndef Tcl_SetBooleanObj #define Tcl_SetBooleanObj \ (tclStubsPtr->tcl_SetBooleanObj) /* 57 */ #endif #ifndef Tcl_SetByteArrayLength #define Tcl_SetByteArrayLength \ (tclStubsPtr->tcl_SetByteArrayLength) /* 58 */ #endif #ifndef Tcl_SetByteArrayObj #define Tcl_SetByteArrayObj \ (tclStubsPtr->tcl_SetByteArrayObj) /* 59 */ #endif #ifndef Tcl_SetDoubleObj #define Tcl_SetDoubleObj \ (tclStubsPtr->tcl_SetDoubleObj) /* 60 */ #endif #ifndef Tcl_SetIntObj #define Tcl_SetIntObj \ (tclStubsPtr->tcl_SetIntObj) /* 61 */ #endif #ifndef Tcl_SetListObj #define Tcl_SetListObj \ (tclStubsPtr->tcl_SetListObj) /* 62 */ #endif #ifndef Tcl_SetLongObj #define Tcl_SetLongObj \ (tclStubsPtr->tcl_SetLongObj) /* 63 */ #endif #ifndef Tcl_SetObjLength #define Tcl_SetObjLength \ (tclStubsPtr->tcl_SetObjLength) /* 64 */ #endif #ifndef Tcl_SetStringObj #define Tcl_SetStringObj \ (tclStubsPtr->tcl_SetStringObj) /* 65 */ #endif #ifndef Tcl_AddErrorInfo #define Tcl_AddErrorInfo \ (tclStubsPtr->tcl_AddErrorInfo) /* 66 */ #endif #ifndef Tcl_AddObjErrorInfo #define Tcl_AddObjErrorInfo \ (tclStubsPtr->tcl_AddObjErrorInfo) /* 67 */ #endif #ifndef Tcl_AllowExceptions #define Tcl_AllowExceptions \ (tclStubsPtr->tcl_AllowExceptions) /* 68 */ #endif #ifndef Tcl_AppendElement #define Tcl_AppendElement \ (tclStubsPtr->tcl_AppendElement) /* 69 */ #endif #ifndef Tcl_AppendResult #define Tcl_AppendResult \ (tclStubsPtr->tcl_AppendResult) /* 70 */ #endif #ifndef Tcl_AsyncCreate #define Tcl_AsyncCreate \ (tclStubsPtr->tcl_AsyncCreate) /* 71 */ #endif #ifndef Tcl_AsyncDelete #define Tcl_AsyncDelete \ (tclStubsPtr->tcl_AsyncDelete) /* 72 */ #endif #ifndef Tcl_AsyncInvoke #define Tcl_AsyncInvoke \ (tclStubsPtr->tcl_AsyncInvoke) /* 73 */ #endif #ifndef Tcl_AsyncMark #define Tcl_AsyncMark \ (tclStubsPtr->tcl_AsyncMark) /* 74 */ #endif #ifndef Tcl_AsyncReady #define Tcl_AsyncReady \ (tclStubsPtr->tcl_AsyncReady) /* 75 */ #endif #ifndef Tcl_BackgroundError #define Tcl_BackgroundError \ (tclStubsPtr->tcl_BackgroundError) /* 76 */ #endif #ifndef Tcl_Backslash #define Tcl_Backslash \ (tclStubsPtr->tcl_Backslash) /* 77 */ #endif #ifndef Tcl_BadChannelOption #define Tcl_BadChannelOption \ (tclStubsPtr->tcl_BadChannelOption) /* 78 */ #endif #ifndef Tcl_CallWhenDeleted #define Tcl_CallWhenDeleted \ (tclStubsPtr->tcl_CallWhenDeleted) /* 79 */ #endif #ifndef Tcl_CancelIdleCall #define Tcl_CancelIdleCall \ (tclStubsPtr->tcl_CancelIdleCall) /* 80 */ #endif #ifndef Tcl_Close #define Tcl_Close \ (tclStubsPtr->tcl_Close) /* 81 */ #endif #ifndef Tcl_CommandComplete #define Tcl_CommandComplete \ (tclStubsPtr->tcl_CommandComplete) /* 82 */ #endif #ifndef Tcl_Concat #define Tcl_Concat \ (tclStubsPtr->tcl_Concat) /* 83 */ #endif #ifndef Tcl_ConvertElement #define Tcl_ConvertElement \ (tclStubsPtr->tcl_ConvertElement) /* 84 */ #endif #ifndef Tcl_ConvertCountedElement #define Tcl_ConvertCountedElement \ (tclStubsPtr->tcl_ConvertCountedElement) /* 85 */ #endif #ifndef Tcl_CreateAlias #define Tcl_CreateAlias \ (tclStubsPtr->tcl_CreateAlias) /* 86 */ #endif #ifndef Tcl_CreateAliasObj #define Tcl_CreateAliasObj \ (tclStubsPtr->tcl_CreateAliasObj) /* 87 */ #endif #ifndef Tcl_CreateChannel #define Tcl_CreateChannel \ (tclStubsPtr->tcl_CreateChannel) /* 88 */ #endif #ifndef Tcl_CreateChannelHandler #define Tcl_CreateChannelHandler \ (tclStubsPtr->tcl_CreateChannelHandler) /* 89 */ #endif #ifndef Tcl_CreateCloseHandler #define Tcl_CreateCloseHandler \ (tclStubsPtr->tcl_CreateCloseHandler) /* 90 */ #endif #ifndef Tcl_CreateCommand #define Tcl_CreateCommand \ (tclStubsPtr->tcl_CreateCommand) /* 91 */ #endif #ifndef Tcl_CreateEventSource #define Tcl_CreateEventSource \ (tclStubsPtr->tcl_CreateEventSource) /* 92 */ #endif #ifndef Tcl_CreateExitHandler #define Tcl_CreateExitHandler \ (tclStubsPtr->tcl_CreateExitHandler) /* 93 */ #endif #ifndef Tcl_CreateInterp #define Tcl_CreateInterp \ (tclStubsPtr->tcl_CreateInterp) /* 94 */ #endif #ifndef Tcl_CreateMathFunc #define Tcl_CreateMathFunc \ (tclStubsPtr->tcl_CreateMathFunc) /* 95 */ #endif #ifndef Tcl_CreateObjCommand #define Tcl_CreateObjCommand \ (tclStubsPtr->tcl_CreateObjCommand) /* 96 */ #endif #ifndef Tcl_CreateSlave #define Tcl_CreateSlave \ (tclStubsPtr->tcl_CreateSlave) /* 97 */ #endif #ifndef Tcl_CreateTimerHandler #define Tcl_CreateTimerHandler \ (tclStubsPtr->tcl_CreateTimerHandler) /* 98 */ #endif #ifndef Tcl_CreateTrace #define Tcl_CreateTrace \ (tclStubsPtr->tcl_CreateTrace) /* 99 */ #endif #ifndef Tcl_DeleteAssocData #define Tcl_DeleteAssocData \ (tclStubsPtr->tcl_DeleteAssocData) /* 100 */ #endif #ifndef Tcl_DeleteChannelHandler #define Tcl_DeleteChannelHandler \ (tclStubsPtr->tcl_DeleteChannelHandler) /* 101 */ #endif #ifndef Tcl_DeleteCloseHandler #define Tcl_DeleteCloseHandler \ (tclStubsPtr->tcl_DeleteCloseHandler) /* 102 */ #endif #ifndef Tcl_DeleteCommand #define Tcl_DeleteCommand \ (tclStubsPtr->tcl_DeleteCommand) /* 103 */ #endif #ifndef Tcl_DeleteCommandFromToken #define Tcl_DeleteCommandFromToken \ (tclStubsPtr->tcl_DeleteCommandFromToken) /* 104 */ #endif #ifndef Tcl_DeleteEvents #define Tcl_DeleteEvents \ (tclStubsPtr->tcl_DeleteEvents) /* 105 */ #endif #ifndef Tcl_DeleteEventSource #define Tcl_DeleteEventSource \ (tclStubsPtr->tcl_DeleteEventSource) /* 106 */ #endif #ifndef Tcl_DeleteExitHandler #define Tcl_DeleteExitHandler \ (tclStubsPtr->tcl_DeleteExitHandler) /* 107 */ #endif #ifndef Tcl_DeleteHashEntry #define Tcl_DeleteHashEntry \ (tclStubsPtr->tcl_DeleteHashEntry) /* 108 */ #endif #ifndef Tcl_DeleteHashTable #define Tcl_DeleteHashTable \ (tclStubsPtr->tcl_DeleteHashTable) /* 109 */ #endif #ifndef Tcl_DeleteInterp #define Tcl_DeleteInterp \ (tclStubsPtr->tcl_DeleteInterp) /* 110 */ #endif #ifndef Tcl_DetachPids #define Tcl_DetachPids \ (tclStubsPtr->tcl_DetachPids) /* 111 */ #endif #ifndef Tcl_DeleteTimerHandler #define Tcl_DeleteTimerHandler \ (tclStubsPtr->tcl_DeleteTimerHandler) /* 112 */ #endif #ifndef Tcl_DeleteTrace #define Tcl_DeleteTrace \ (tclStubsPtr->tcl_DeleteTrace) /* 113 */ #endif #ifndef Tcl_DontCallWhenDeleted #define Tcl_DontCallWhenDeleted \ (tclStubsPtr->tcl_DontCallWhenDeleted) /* 114 */ #endif #ifndef Tcl_DoOneEvent #define Tcl_DoOneEvent \ (tclStubsPtr->tcl_DoOneEvent) /* 115 */ #endif #ifndef Tcl_DoWhenIdle #define Tcl_DoWhenIdle \ (tclStubsPtr->tcl_DoWhenIdle) /* 116 */ #endif #ifndef Tcl_DStringAppend #define Tcl_DStringAppend \ (tclStubsPtr->tcl_DStringAppend) /* 117 */ #endif #ifndef Tcl_DStringAppendElement #define Tcl_DStringAppendElement \ (tclStubsPtr->tcl_DStringAppendElement) /* 118 */ #endif #ifndef Tcl_DStringEndSublist #define Tcl_DStringEndSublist \ (tclStubsPtr->tcl_DStringEndSublist) /* 119 */ #endif #ifndef Tcl_DStringFree #define Tcl_DStringFree \ (tclStubsPtr->tcl_DStringFree) /* 120 */ #endif #ifndef Tcl_DStringGetResult #define Tcl_DStringGetResult \ (tclStubsPtr->tcl_DStringGetResult) /* 121 */ #endif #ifndef Tcl_DStringInit #define Tcl_DStringInit \ (tclStubsPtr->tcl_DStringInit) /* 122 */ #endif #ifndef Tcl_DStringResult #define Tcl_DStringResult \ (tclStubsPtr->tcl_DStringResult) /* 123 */ #endif #ifndef Tcl_DStringSetLength #define Tcl_DStringSetLength \ (tclStubsPtr->tcl_DStringSetLength) /* 124 */ #endif #ifndef Tcl_DStringStartSublist #define Tcl_DStringStartSublist \ (tclStubsPtr->tcl_DStringStartSublist) /* 125 */ #endif #ifndef Tcl_Eof #define Tcl_Eof \ (tclStubsPtr->tcl_Eof) /* 126 */ #endif #ifndef Tcl_ErrnoId #define Tcl_ErrnoId \ (tclStubsPtr->tcl_ErrnoId) /* 127 */ #endif #ifndef Tcl_ErrnoMsg #define Tcl_ErrnoMsg \ (tclStubsPtr->tcl_ErrnoMsg) /* 128 */ #endif #ifndef Tcl_Eval #define Tcl_Eval \ (tclStubsPtr->tcl_Eval) /* 129 */ #endif #ifndef Tcl_EvalFile #define Tcl_EvalFile \ (tclStubsPtr->tcl_EvalFile) /* 130 */ #endif #ifndef Tcl_EvalObj #define Tcl_EvalObj \ (tclStubsPtr->tcl_EvalObj) /* 131 */ #endif #ifndef Tcl_EventuallyFree #define Tcl_EventuallyFree \ (tclStubsPtr->tcl_EventuallyFree) /* 132 */ #endif #ifndef Tcl_Exit #define Tcl_Exit \ (tclStubsPtr->tcl_Exit) /* 133 */ #endif #ifndef Tcl_ExposeCommand #define Tcl_ExposeCommand \ (tclStubsPtr->tcl_ExposeCommand) /* 134 */ #endif #ifndef Tcl_ExprBoolean #define Tcl_ExprBoolean \ (tclStubsPtr->tcl_ExprBoolean) /* 135 */ #endif #ifndef Tcl_ExprBooleanObj #define Tcl_ExprBooleanObj \ (tclStubsPtr->tcl_ExprBooleanObj) /* 136 */ #endif #ifndef Tcl_ExprDouble #define Tcl_ExprDouble \ (tclStubsPtr->tcl_ExprDouble) /* 137 */ #endif #ifndef Tcl_ExprDoubleObj #define Tcl_ExprDoubleObj \ (tclStubsPtr->tcl_ExprDoubleObj) /* 138 */ #endif #ifndef Tcl_ExprLong #define Tcl_ExprLong \ (tclStubsPtr->tcl_ExprLong) /* 139 */ #endif #ifndef Tcl_ExprLongObj #define Tcl_ExprLongObj \ (tclStubsPtr->tcl_ExprLongObj) /* 140 */ #endif #ifndef Tcl_ExprObj #define Tcl_ExprObj \ (tclStubsPtr->tcl_ExprObj) /* 141 */ #endif #ifndef Tcl_ExprString #define Tcl_ExprString \ (tclStubsPtr->tcl_ExprString) /* 142 */ #endif #ifndef Tcl_Finalize #define Tcl_Finalize \ (tclStubsPtr->tcl_Finalize) /* 143 */ #endif #ifndef Tcl_FindExecutable #define Tcl_FindExecutable \ (tclStubsPtr->tcl_FindExecutable) /* 144 */ #endif #ifndef Tcl_FirstHashEntry #define Tcl_FirstHashEntry \ (tclStubsPtr->tcl_FirstHashEntry) /* 145 */ #endif #ifndef Tcl_Flush #define Tcl_Flush \ (tclStubsPtr->tcl_Flush) /* 146 */ #endif #ifndef Tcl_FreeResult #define Tcl_FreeResult \ (tclStubsPtr->tcl_FreeResult) /* 147 */ #endif #ifndef Tcl_GetAlias #define Tcl_GetAlias \ (tclStubsPtr->tcl_GetAlias) /* 148 */ #endif #ifndef Tcl_GetAliasObj #define Tcl_GetAliasObj \ (tclStubsPtr->tcl_GetAliasObj) /* 149 */ #endif #ifndef Tcl_GetAssocData #define Tcl_GetAssocData \ (tclStubsPtr->tcl_GetAssocData) /* 150 */ #endif #ifndef Tcl_GetChannel #define Tcl_GetChannel \ (tclStubsPtr->tcl_GetChannel) /* 151 */ #endif #ifndef Tcl_GetChannelBufferSize #define Tcl_GetChannelBufferSize \ (tclStubsPtr->tcl_GetChannelBufferSize) /* 152 */ #endif #ifndef Tcl_GetChannelHandle #define Tcl_GetChannelHandle \ (tclStubsPtr->tcl_GetChannelHandle) /* 153 */ #endif #ifndef Tcl_GetChannelInstanceData #define Tcl_GetChannelInstanceData \ (tclStubsPtr->tcl_GetChannelInstanceData) /* 154 */ #endif #ifndef Tcl_GetChannelMode #define Tcl_GetChannelMode \ (tclStubsPtr->tcl_GetChannelMode) /* 155 */ #endif #ifndef Tcl_GetChannelName #define Tcl_GetChannelName \ (tclStubsPtr->tcl_GetChannelName) /* 156 */ #endif #ifndef Tcl_GetChannelOption #define Tcl_GetChannelOption \ (tclStubsPtr->tcl_GetChannelOption) /* 157 */ #endif #ifndef Tcl_GetChannelType #define Tcl_GetChannelType \ (tclStubsPtr->tcl_GetChannelType) /* 158 */ #endif #ifndef Tcl_GetCommandInfo #define Tcl_GetCommandInfo \ (tclStubsPtr->tcl_GetCommandInfo) /* 159 */ #endif #ifndef Tcl_GetCommandName #define Tcl_GetCommandName \ (tclStubsPtr->tcl_GetCommandName) /* 160 */ #endif #ifndef Tcl_GetErrno #define Tcl_GetErrno \ (tclStubsPtr->tcl_GetErrno) /* 161 */ #endif #ifndef Tcl_GetHostName #define Tcl_GetHostName \ (tclStubsPtr->tcl_GetHostName) /* 162 */ #endif #ifndef Tcl_GetInterpPath #define Tcl_GetInterpPath \ (tclStubsPtr->tcl_GetInterpPath) /* 163 */ #endif #ifndef Tcl_GetMaster #define Tcl_GetMaster \ (tclStubsPtr->tcl_GetMaster) /* 164 */ #endif #ifndef Tcl_GetNameOfExecutable #define Tcl_GetNameOfExecutable \ (tclStubsPtr->tcl_GetNameOfExecutable) /* 165 */ #endif #ifndef Tcl_GetObjResult #define Tcl_GetObjResult \ (tclStubsPtr->tcl_GetObjResult) /* 166 */ #endif #if !defined(__WIN32__) && !defined(MAC_OSX_TCL) /* UNIX */ #ifndef Tcl_GetOpenFile #define Tcl_GetOpenFile \ (tclStubsPtr->tcl_GetOpenFile) /* 167 */ #endif #endif /* UNIX */ #ifdef MAC_OSX_TCL /* MACOSX */ #ifndef Tcl_GetOpenFile #define Tcl_GetOpenFile \ (tclStubsPtr->tcl_GetOpenFile) /* 167 */ #endif #endif /* MACOSX */ #ifndef Tcl_GetPathType #define Tcl_GetPathType \ (tclStubsPtr->tcl_GetPathType) /* 168 */ #endif #ifndef Tcl_Gets #define Tcl_Gets \ (tclStubsPtr->tcl_Gets) /* 169 */ #endif #ifndef Tcl_GetsObj #define Tcl_GetsObj \ (tclStubsPtr->tcl_GetsObj) /* 170 */ #endif #ifndef Tcl_GetServiceMode #define Tcl_GetServiceMode \ (tclStubsPtr->tcl_GetServiceMode) /* 171 */ #endif #ifndef Tcl_GetSlave #define Tcl_GetSlave \ (tclStubsPtr->tcl_GetSlave) /* 172 */ #endif #ifndef Tcl_GetStdChannel #define Tcl_GetStdChannel \ (tclStubsPtr->tcl_GetStdChannel) /* 173 */ #endif #ifndef Tcl_GetStringResult #define Tcl_GetStringResult \ (tclStubsPtr->tcl_GetStringResult) /* 174 */ #endif #ifndef Tcl_GetVar #define Tcl_GetVar \ (tclStubsPtr->tcl_GetVar) /* 175 */ #endif #ifndef Tcl_GetVar2 #define Tcl_GetVar2 \ (tclStubsPtr->tcl_GetVar2) /* 176 */ #endif #ifndef Tcl_GlobalEval #define Tcl_GlobalEval \ (tclStubsPtr->tcl_GlobalEval) /* 177 */ #endif #ifndef Tcl_GlobalEvalObj #define Tcl_GlobalEvalObj \ (tclStubsPtr->tcl_GlobalEvalObj) /* 178 */ #endif #ifndef Tcl_HideCommand #define Tcl_HideCommand \ (tclStubsPtr->tcl_HideCommand) /* 179 */ #endif #ifndef Tcl_Init #define Tcl_Init \ (tclStubsPtr->tcl_Init) /* 180 */ #endif #ifndef Tcl_InitHashTable #define Tcl_InitHashTable \ (tclStubsPtr->tcl_InitHashTable) /* 181 */ #endif #ifndef Tcl_InputBlocked #define Tcl_InputBlocked \ (tclStubsPtr->tcl_InputBlocked) /* 182 */ #endif #ifndef Tcl_InputBuffered #define Tcl_InputBuffered \ (tclStubsPtr->tcl_InputBuffered) /* 183 */ #endif #ifndef Tcl_InterpDeleted #define Tcl_InterpDeleted \ (tclStubsPtr->tcl_InterpDeleted) /* 184 */ #endif #ifndef Tcl_IsSafe #define Tcl_IsSafe \ (tclStubsPtr->tcl_IsSafe) /* 185 */ #endif #ifndef Tcl_JoinPath #define Tcl_JoinPath \ (tclStubsPtr->tcl_JoinPath) /* 186 */ #endif #ifndef Tcl_LinkVar #define Tcl_LinkVar \ (tclStubsPtr->tcl_LinkVar) /* 187 */ #endif /* Slot 188 is reserved */ #ifndef Tcl_MakeFileChannel #define Tcl_MakeFileChannel \ (tclStubsPtr->tcl_MakeFileChannel) /* 189 */ #endif #ifndef Tcl_MakeSafe #define Tcl_MakeSafe \ (tclStubsPtr->tcl_MakeSafe) /* 190 */ #endif #ifndef Tcl_MakeTcpClientChannel #define Tcl_MakeTcpClientChannel \ (tclStubsPtr->tcl_MakeTcpClientChannel) /* 191 */ #endif #ifndef Tcl_Merge #define Tcl_Merge \ (tclStubsPtr->tcl_Merge) /* 192 */ #endif #ifndef Tcl_NextHashEntry #define Tcl_NextHashEntry \ (tclStubsPtr->tcl_NextHashEntry) /* 193 */ #endif #ifndef Tcl_NotifyChannel #define Tcl_NotifyChannel \ (tclStubsPtr->tcl_NotifyChannel) /* 194 */ #endif #ifndef Tcl_ObjGetVar2 #define Tcl_ObjGetVar2 \ (tclStubsPtr->tcl_ObjGetVar2) /* 195 */ #endif #ifndef Tcl_ObjSetVar2 #define Tcl_ObjSetVar2 \ (tclStubsPtr->tcl_ObjSetVar2) /* 196 */ #endif #ifndef Tcl_OpenCommandChannel #define Tcl_OpenCommandChannel \ (tclStubsPtr->tcl_OpenCommandChannel) /* 197 */ #endif #ifndef Tcl_OpenFileChannel #define Tcl_OpenFileChannel \ (tclStubsPtr->tcl_OpenFileChannel) /* 198 */ #endif #ifndef Tcl_OpenTcpClient #define Tcl_OpenTcpClient \ (tclStubsPtr->tcl_OpenTcpClient) /* 199 */ #endif #ifndef Tcl_OpenTcpServer #define Tcl_OpenTcpServer \ (tclStubsPtr->tcl_OpenTcpServer) /* 200 */ #endif #ifndef Tcl_Preserve #define Tcl_Preserve \ (tclStubsPtr->tcl_Preserve) /* 201 */ #endif #ifndef Tcl_PrintDouble #define Tcl_PrintDouble \ (tclStubsPtr->tcl_PrintDouble) /* 202 */ #endif #ifndef Tcl_PutEnv #define Tcl_PutEnv \ (tclStubsPtr->tcl_PutEnv) /* 203 */ #endif #ifndef Tcl_PosixError #define Tcl_PosixError \ (tclStubsPtr->tcl_PosixError) /* 204 */ #endif #ifndef Tcl_QueueEvent #define Tcl_QueueEvent \ (tclStubsPtr->tcl_QueueEvent) /* 205 */ #endif #ifndef Tcl_Read #define Tcl_Read \ (tclStubsPtr->tcl_Read) /* 206 */ #endif #ifndef Tcl_ReapDetachedProcs #define Tcl_ReapDetachedProcs \ (tclStubsPtr->tcl_ReapDetachedProcs) /* 207 */ #endif #ifndef Tcl_RecordAndEval #define Tcl_RecordAndEval \ (tclStubsPtr->tcl_RecordAndEval) /* 208 */ #endif #ifndef Tcl_RecordAndEvalObj #define Tcl_RecordAndEvalObj \ (tclStubsPtr->tcl_RecordAndEvalObj) /* 209 */ #endif #ifndef Tcl_RegisterChannel #define Tcl_RegisterChannel \ (tclStubsPtr->tcl_RegisterChannel) /* 210 */ #endif #ifndef Tcl_RegisterObjType #define Tcl_RegisterObjType \ (tclStubsPtr->tcl_RegisterObjType) /* 211 */ #endif #ifndef Tcl_RegExpCompile #define Tcl_RegExpCompile \ (tclStubsPtr->tcl_RegExpCompile) /* 212 */ #endif #ifndef Tcl_RegExpExec #define Tcl_RegExpExec \ (tclStubsPtr->tcl_RegExpExec) /* 213 */ #endif #ifndef Tcl_RegExpMatch #define Tcl_RegExpMatch \ (tclStubsPtr->tcl_RegExpMatch) /* 214 */ #endif #ifndef Tcl_RegExpRange #define Tcl_RegExpRange \ (tclStubsPtr->tcl_RegExpRange) /* 215 */ #endif #ifndef Tcl_Release #define Tcl_Release \ (tclStubsPtr->tcl_Release) /* 216 */ #endif #ifndef Tcl_ResetResult #define Tcl_ResetResult \ (tclStubsPtr->tcl_ResetResult) /* 217 */ #endif #ifndef Tcl_ScanElement #define Tcl_ScanElement \ (tclStubsPtr->tcl_ScanElement) /* 218 */ #endif #ifndef Tcl_ScanCountedElement #define Tcl_ScanCountedElement \ (tclStubsPtr->tcl_ScanCountedElement) /* 219 */ #endif #ifndef Tcl_SeekOld #define Tcl_SeekOld \ (tclStubsPtr->tcl_SeekOld) /* 220 */ #endif #ifndef Tcl_ServiceAll #define Tcl_ServiceAll \ (tclStubsPtr->tcl_ServiceAll) /* 221 */ #endif #ifndef Tcl_ServiceEvent #define Tcl_ServiceEvent \ (tclStubsPtr->tcl_ServiceEvent) /* 222 */ #endif #ifndef Tcl_SetAssocData #define Tcl_SetAssocData \ (tclStubsPtr->tcl_SetAssocData) /* 223 */ #endif #ifndef Tcl_SetChannelBufferSize #define Tcl_SetChannelBufferSize \ (tclStubsPtr->tcl_SetChannelBufferSize) /* 224 */ #endif #ifndef Tcl_SetChannelOption #define Tcl_SetChannelOption \ (tclStubsPtr->tcl_SetChannelOption) /* 225 */ #endif #ifndef Tcl_SetCommandInfo #define Tcl_SetCommandInfo \ (tclStubsPtr->tcl_SetCommandInfo) /* 226 */ #endif #ifndef Tcl_SetErrno #define Tcl_SetErrno \ (tclStubsPtr->tcl_SetErrno) /* 227 */ #endif #ifndef Tcl_SetErrorCode #define Tcl_SetErrorCode \ (tclStubsPtr->tcl_SetErrorCode) /* 228 */ #endif #ifndef Tcl_SetMaxBlockTime #define Tcl_SetMaxBlockTime \ (tclStubsPtr->tcl_SetMaxBlockTime) /* 229 */ #endif #ifndef Tcl_SetPanicProc #define Tcl_SetPanicProc \ (tclStubsPtr->tcl_SetPanicProc) /* 230 */ #endif #ifndef Tcl_SetRecursionLimit #define Tcl_SetRecursionLimit \ (tclStubsPtr->tcl_SetRecursionLimit) /* 231 */ #endif #ifndef Tcl_SetResult #define Tcl_SetResult \ (tclStubsPtr->tcl_SetResult) /* 232 */ #endif #ifndef Tcl_SetServiceMode #define Tcl_SetServiceMode \ (tclStubsPtr->tcl_SetServiceMode) /* 233 */ #endif #ifndef Tcl_SetObjErrorCode #define Tcl_SetObjErrorCode \ (tclStubsPtr->tcl_SetObjErrorCode) /* 234 */ #endif #ifndef Tcl_SetObjResult #define Tcl_SetObjResult \ (tclStubsPtr->tcl_SetObjResult) /* 235 */ #endif #ifndef Tcl_SetStdChannel #define Tcl_SetStdChannel \ (tclStubsPtr->tcl_SetStdChannel) /* 236 */ #endif #ifndef Tcl_SetVar #define Tcl_SetVar \ (tclStubsPtr->tcl_SetVar) /* 237 */ #endif #ifndef Tcl_SetVar2 #define Tcl_SetVar2 \ (tclStubsPtr->tcl_SetVar2) /* 238 */ #endif #ifndef Tcl_SignalId #define Tcl_SignalId \ (tclStubsPtr->tcl_SignalId) /* 239 */ #endif #ifndef Tcl_SignalMsg #define Tcl_SignalMsg \ (tclStubsPtr->tcl_SignalMsg) /* 240 */ #endif #ifndef Tcl_SourceRCFile #define Tcl_SourceRCFile \ (tclStubsPtr->tcl_SourceRCFile) /* 241 */ #endif #ifndef Tcl_SplitList #define Tcl_SplitList \ (tclStubsPtr->tcl_SplitList) /* 242 */ #endif #ifndef Tcl_SplitPath #define Tcl_SplitPath \ (tclStubsPtr->tcl_SplitPath) /* 243 */ #endif #ifndef Tcl_StaticPackage #define Tcl_StaticPackage \ (tclStubsPtr->tcl_StaticPackage) /* 244 */ #endif #ifndef Tcl_StringMatch #define Tcl_StringMatch \ (tclStubsPtr->tcl_StringMatch) /* 245 */ #endif #ifndef Tcl_TellOld #define Tcl_TellOld \ (tclStubsPtr->tcl_TellOld) /* 246 */ #endif #ifndef Tcl_TraceVar #define Tcl_TraceVar \ (tclStubsPtr->tcl_TraceVar) /* 247 */ #endif #ifndef Tcl_TraceVar2 #define Tcl_TraceVar2 \ (tclStubsPtr->tcl_TraceVar2) /* 248 */ #endif #ifndef Tcl_TranslateFileName #define Tcl_TranslateFileName \ (tclStubsPtr->tcl_TranslateFileName) /* 249 */ #endif #ifndef Tcl_Ungets #define Tcl_Ungets \ (tclStubsPtr->tcl_Ungets) /* 250 */ #endif #ifndef Tcl_UnlinkVar #define Tcl_UnlinkVar \ (tclStubsPtr->tcl_UnlinkVar) /* 251 */ #endif #ifndef Tcl_UnregisterChannel #define Tcl_UnregisterChannel \ (tclStubsPtr->tcl_UnregisterChannel) /* 252 */ #endif #ifndef Tcl_UnsetVar #define Tcl_UnsetVar \ (tclStubsPtr->tcl_UnsetVar) /* 253 */ #endif #ifndef Tcl_UnsetVar2 #define Tcl_UnsetVar2 \ (tclStubsPtr->tcl_UnsetVar2) /* 254 */ #endif #ifndef Tcl_UntraceVar #define Tcl_UntraceVar \ (tclStubsPtr->tcl_UntraceVar) /* 255 */ #endif #ifndef Tcl_UntraceVar2 #define Tcl_UntraceVar2 \ (tclStubsPtr->tcl_UntraceVar2) /* 256 */ #endif #ifndef Tcl_UpdateLinkedVar #define Tcl_UpdateLinkedVar \ (tclStubsPtr->tcl_UpdateLinkedVar) /* 257 */ #endif #ifndef Tcl_UpVar #define Tcl_UpVar \ (tclStubsPtr->tcl_UpVar) /* 258 */ #endif #ifndef Tcl_UpVar2 #define Tcl_UpVar2 \ (tclStubsPtr->tcl_UpVar2) /* 259 */ #endif #ifndef Tcl_VarEval #define Tcl_VarEval \ (tclStubsPtr->tcl_VarEval) /* 260 */ #endif #ifndef Tcl_VarTraceInfo #define Tcl_VarTraceInfo \ (tclStubsPtr->tcl_VarTraceInfo) /* 261 */ #endif #ifndef Tcl_VarTraceInfo2 #define Tcl_VarTraceInfo2 \ (tclStubsPtr->tcl_VarTraceInfo2) /* 262 */ #endif #ifndef Tcl_Write #define Tcl_Write \ (tclStubsPtr->tcl_Write) /* 263 */ #endif #ifndef Tcl_WrongNumArgs #define Tcl_WrongNumArgs \ (tclStubsPtr->tcl_WrongNumArgs) /* 264 */ #endif #ifndef Tcl_DumpActiveMemory #define Tcl_DumpActiveMemory \ (tclStubsPtr->tcl_DumpActiveMemory) /* 265 */ #endif #ifndef Tcl_ValidateAllMemory #define Tcl_ValidateAllMemory \ (tclStubsPtr->tcl_ValidateAllMemory) /* 266 */ #endif #ifndef Tcl_AppendResultVA #define Tcl_AppendResultVA \ (tclStubsPtr->tcl_AppendResultVA) /* 267 */ #endif #ifndef Tcl_AppendStringsToObjVA #define Tcl_AppendStringsToObjVA \ (tclStubsPtr->tcl_AppendStringsToObjVA) /* 268 */ #endif #ifndef Tcl_HashStats #define Tcl_HashStats \ (tclStubsPtr->tcl_HashStats) /* 269 */ #endif #ifndef Tcl_ParseVar #define Tcl_ParseVar \ (tclStubsPtr->tcl_ParseVar) /* 270 */ #endif #ifndef Tcl_PkgPresent #define Tcl_PkgPresent \ (tclStubsPtr->tcl_PkgPresent) /* 271 */ #endif #ifndef Tcl_PkgPresentEx #define Tcl_PkgPresentEx \ (tclStubsPtr->tcl_PkgPresentEx) /* 272 */ #endif #ifndef Tcl_PkgProvide #define Tcl_PkgProvide \ (tclStubsPtr->tcl_PkgProvide) /* 273 */ #endif #ifndef Tcl_PkgRequire #define Tcl_PkgRequire \ (tclStubsPtr->tcl_PkgRequire) /* 274 */ #endif #ifndef Tcl_SetErrorCodeVA #define Tcl_SetErrorCodeVA \ (tclStubsPtr->tcl_SetErrorCodeVA) /* 275 */ #endif #ifndef Tcl_VarEvalVA #define Tcl_VarEvalVA \ (tclStubsPtr->tcl_VarEvalVA) /* 276 */ #endif #ifndef Tcl_WaitPid #define Tcl_WaitPid \ (tclStubsPtr->tcl_WaitPid) /* 277 */ #endif #ifndef Tcl_PanicVA #define Tcl_PanicVA \ (tclStubsPtr->tcl_PanicVA) /* 278 */ #endif #ifndef Tcl_GetVersion #define Tcl_GetVersion \ (tclStubsPtr->tcl_GetVersion) /* 279 */ #endif #ifndef Tcl_InitMemory #define Tcl_InitMemory \ (tclStubsPtr->tcl_InitMemory) /* 280 */ #endif #ifndef Tcl_StackChannel #define Tcl_StackChannel \ (tclStubsPtr->tcl_StackChannel) /* 281 */ #endif #ifndef Tcl_UnstackChannel #define Tcl_UnstackChannel \ (tclStubsPtr->tcl_UnstackChannel) /* 282 */ #endif #ifndef Tcl_GetStackedChannel #define Tcl_GetStackedChannel \ (tclStubsPtr->tcl_GetStackedChannel) /* 283 */ #endif #ifndef Tcl_SetMainLoop #define Tcl_SetMainLoop \ (tclStubsPtr->tcl_SetMainLoop) /* 284 */ #endif /* Slot 285 is reserved */ #ifndef Tcl_AppendObjToObj #define Tcl_AppendObjToObj \ (tclStubsPtr->tcl_AppendObjToObj) /* 286 */ #endif #ifndef Tcl_CreateEncoding #define Tcl_CreateEncoding \ (tclStubsPtr->tcl_CreateEncoding) /* 287 */ #endif #ifndef Tcl_CreateThreadExitHandler #define Tcl_CreateThreadExitHandler \ (tclStubsPtr->tcl_CreateThreadExitHandler) /* 288 */ #endif #ifndef Tcl_DeleteThreadExitHandler #define Tcl_DeleteThreadExitHandler \ (tclStubsPtr->tcl_DeleteThreadExitHandler) /* 289 */ #endif #ifndef Tcl_DiscardResult #define Tcl_DiscardResult \ (tclStubsPtr->tcl_DiscardResult) /* 290 */ #endif #ifndef Tcl_EvalEx #define Tcl_EvalEx \ (tclStubsPtr->tcl_EvalEx) /* 291 */ #endif #ifndef Tcl_EvalObjv #define Tcl_EvalObjv \ (tclStubsPtr->tcl_EvalObjv) /* 292 */ #endif #ifndef Tcl_EvalObjEx #define Tcl_EvalObjEx \ (tclStubsPtr->tcl_EvalObjEx) /* 293 */ #endif #ifndef Tcl_ExitThread #define Tcl_ExitThread \ (tclStubsPtr->tcl_ExitThread) /* 294 */ #endif #ifndef Tcl_ExternalToUtf #define Tcl_ExternalToUtf \ (tclStubsPtr->tcl_ExternalToUtf) /* 295 */ #endif #ifndef Tcl_ExternalToUtfDString #define Tcl_ExternalToUtfDString \ (tclStubsPtr->tcl_ExternalToUtfDString) /* 296 */ #endif #ifndef Tcl_FinalizeThread #define Tcl_FinalizeThread \ (tclStubsPtr->tcl_FinalizeThread) /* 297 */ #endif #ifndef Tcl_FinalizeNotifier #define Tcl_FinalizeNotifier \ (tclStubsPtr->tcl_FinalizeNotifier) /* 298 */ #endif #ifndef Tcl_FreeEncoding #define Tcl_FreeEncoding \ (tclStubsPtr->tcl_FreeEncoding) /* 299 */ #endif #ifndef Tcl_GetCurrentThread #define Tcl_GetCurrentThread \ (tclStubsPtr->tcl_GetCurrentThread) /* 300 */ #endif #ifndef Tcl_GetEncoding #define Tcl_GetEncoding \ (tclStubsPtr->tcl_GetEncoding) /* 301 */ #endif #ifndef Tcl_GetEncodingName #define Tcl_GetEncodingName \ (tclStubsPtr->tcl_GetEncodingName) /* 302 */ #endif #ifndef Tcl_GetEncodingNames #define Tcl_GetEncodingNames \ (tclStubsPtr->tcl_GetEncodingNames) /* 303 */ #endif #ifndef Tcl_GetIndexFromObjStruct #define Tcl_GetIndexFromObjStruct \ (tclStubsPtr->tcl_GetIndexFromObjStruct) /* 304 */ #endif #ifndef Tcl_GetThreadData #define Tcl_GetThreadData \ (tclStubsPtr->tcl_GetThreadData) /* 305 */ #endif #ifndef Tcl_GetVar2Ex #define Tcl_GetVar2Ex \ (tclStubsPtr->tcl_GetVar2Ex) /* 306 */ #endif #ifndef Tcl_InitNotifier #define Tcl_InitNotifier \ (tclStubsPtr->tcl_InitNotifier) /* 307 */ #endif #ifndef Tcl_MutexLock #define Tcl_MutexLock \ (tclStubsPtr->tcl_MutexLock) /* 308 */ #endif #ifndef Tcl_MutexUnlock #define Tcl_MutexUnlock \ (tclStubsPtr->tcl_MutexUnlock) /* 309 */ #endif #ifndef Tcl_ConditionNotify #define Tcl_ConditionNotify \ (tclStubsPtr->tcl_ConditionNotify) /* 310 */ #endif #ifndef Tcl_ConditionWait #define Tcl_ConditionWait \ (tclStubsPtr->tcl_ConditionWait) /* 311 */ #endif #ifndef Tcl_NumUtfChars #define Tcl_NumUtfChars \ (tclStubsPtr->tcl_NumUtfChars) /* 312 */ #endif #ifndef Tcl_ReadChars #define Tcl_ReadChars \ (tclStubsPtr->tcl_ReadChars) /* 313 */ #endif #ifndef Tcl_RestoreResult #define Tcl_RestoreResult \ (tclStubsPtr->tcl_RestoreResult) /* 314 */ #endif #ifndef Tcl_SaveResult #define Tcl_SaveResult \ (tclStubsPtr->tcl_SaveResult) /* 315 */ #endif #ifndef Tcl_SetSystemEncoding #define Tcl_SetSystemEncoding \ (tclStubsPtr->tcl_SetSystemEncoding) /* 316 */ #endif #ifndef Tcl_SetVar2Ex #define Tcl_SetVar2Ex \ (tclStubsPtr->tcl_SetVar2Ex) /* 317 */ #endif #ifndef Tcl_ThreadAlert #define Tcl_ThreadAlert \ (tclStubsPtr->tcl_ThreadAlert) /* 318 */ #endif #ifndef Tcl_ThreadQueueEvent #define Tcl_ThreadQueueEvent \ (tclStubsPtr->tcl_ThreadQueueEvent) /* 319 */ #endif #ifndef Tcl_UniCharAtIndex #define Tcl_UniCharAtIndex \ (tclStubsPtr->tcl_UniCharAtIndex) /* 320 */ #endif #ifndef Tcl_UniCharToLower #define Tcl_UniCharToLower \ (tclStubsPtr->tcl_UniCharToLower) /* 321 */ #endif #ifndef Tcl_UniCharToTitle #define Tcl_UniCharToTitle \ (tclStubsPtr->tcl_UniCharToTitle) /* 322 */ #endif #ifndef Tcl_UniCharToUpper #define Tcl_UniCharToUpper \ (tclStubsPtr->tcl_UniCharToUpper) /* 323 */ #endif #ifndef Tcl_UniCharToUtf #define Tcl_UniCharToUtf \ (tclStubsPtr->tcl_UniCharToUtf) /* 324 */ #endif #ifndef Tcl_UtfAtIndex #define Tcl_UtfAtIndex \ (tclStubsPtr->tcl_UtfAtIndex) /* 325 */ #endif #ifndef Tcl_UtfCharComplete #define Tcl_UtfCharComplete \ (tclStubsPtr->tcl_UtfCharComplete) /* 326 */ #endif #ifndef Tcl_UtfBackslash #define Tcl_UtfBackslash \ (tclStubsPtr->tcl_UtfBackslash) /* 327 */ #endif #ifndef Tcl_UtfFindFirst #define Tcl_UtfFindFirst \ (tclStubsPtr->tcl_UtfFindFirst) /* 328 */ #endif #ifndef Tcl_UtfFindLast #define Tcl_UtfFindLast \ (tclStubsPtr->tcl_UtfFindLast) /* 329 */ #endif #ifndef Tcl_UtfNext #define Tcl_UtfNext \ (tclStubsPtr->tcl_UtfNext) /* 330 */ #endif #ifndef Tcl_UtfPrev #define Tcl_UtfPrev \ (tclStubsPtr->tcl_UtfPrev) /* 331 */ #endif #ifndef Tcl_UtfToExternal #define Tcl_UtfToExternal \ (tclStubsPtr->tcl_UtfToExternal) /* 332 */ #endif #ifndef Tcl_UtfToExternalDString #define Tcl_UtfToExternalDString \ (tclStubsPtr->tcl_UtfToExternalDString) /* 333 */ #endif #ifndef Tcl_UtfToLower #define Tcl_UtfToLower \ (tclStubsPtr->tcl_UtfToLower) /* 334 */ #endif #ifndef Tcl_UtfToTitle #define Tcl_UtfToTitle \ (tclStubsPtr->tcl_UtfToTitle) /* 335 */ #endif #ifndef Tcl_UtfToUniChar #define Tcl_UtfToUniChar \ (tclStubsPtr->tcl_UtfToUniChar) /* 336 */ #endif #ifndef Tcl_UtfToUpper #define Tcl_UtfToUpper \ (tclStubsPtr->tcl_UtfToUpper) /* 337 */ #endif #ifndef Tcl_WriteChars #define Tcl_WriteChars \ (tclStubsPtr->tcl_WriteChars) /* 338 */ #endif #ifndef Tcl_WriteObj #define Tcl_WriteObj \ (tclStubsPtr->tcl_WriteObj) /* 339 */ #endif #ifndef Tcl_GetString #define Tcl_GetString \ (tclStubsPtr->tcl_GetString) /* 340 */ #endif #ifndef Tcl_GetDefaultEncodingDir #define Tcl_GetDefaultEncodingDir \ (tclStubsPtr->tcl_GetDefaultEncodingDir) /* 341 */ #endif #ifndef Tcl_SetDefaultEncodingDir #define Tcl_SetDefaultEncodingDir \ (tclStubsPtr->tcl_SetDefaultEncodingDir) /* 342 */ #endif #ifndef Tcl_AlertNotifier #define Tcl_AlertNotifier \ (tclStubsPtr->tcl_AlertNotifier) /* 343 */ #endif #ifndef Tcl_ServiceModeHook #define Tcl_ServiceModeHook \ (tclStubsPtr->tcl_ServiceModeHook) /* 344 */ #endif #ifndef Tcl_UniCharIsAlnum #define Tcl_UniCharIsAlnum \ (tclStubsPtr->tcl_UniCharIsAlnum) /* 345 */ #endif #ifndef Tcl_UniCharIsAlpha #define Tcl_UniCharIsAlpha \ (tclStubsPtr->tcl_UniCharIsAlpha) /* 346 */ #endif #ifndef Tcl_UniCharIsDigit #define Tcl_UniCharIsDigit \ (tclStubsPtr->tcl_UniCharIsDigit) /* 347 */ #endif #ifndef Tcl_UniCharIsLower #define Tcl_UniCharIsLower \ (tclStubsPtr->tcl_UniCharIsLower) /* 348 */ #endif #ifndef Tcl_UniCharIsSpace #define Tcl_UniCharIsSpace \ (tclStubsPtr->tcl_UniCharIsSpace) /* 349 */ #endif #ifndef Tcl_UniCharIsUpper #define Tcl_UniCharIsUpper \ (tclStubsPtr->tcl_UniCharIsUpper) /* 350 */ #endif #ifndef Tcl_UniCharIsWordChar #define Tcl_UniCharIsWordChar \ (tclStubsPtr->tcl_UniCharIsWordChar) /* 351 */ #endif #ifndef Tcl_UniCharLen #define Tcl_UniCharLen \ (tclStubsPtr->tcl_UniCharLen) /* 352 */ #endif #ifndef Tcl_UniCharNcmp #define Tcl_UniCharNcmp \ (tclStubsPtr->tcl_UniCharNcmp) /* 353 */ #endif #ifndef Tcl_UniCharToUtfDString #define Tcl_UniCharToUtfDString \ (tclStubsPtr->tcl_UniCharToUtfDString) /* 354 */ #endif #ifndef Tcl_UtfToUniCharDString #define Tcl_UtfToUniCharDString \ (tclStubsPtr->tcl_UtfToUniCharDString) /* 355 */ #endif #ifndef Tcl_GetRegExpFromObj #define Tcl_GetRegExpFromObj \ (tclStubsPtr->tcl_GetRegExpFromObj) /* 356 */ #endif #ifndef Tcl_EvalTokens #define Tcl_EvalTokens \ (tclStubsPtr->tcl_EvalTokens) /* 357 */ #endif #ifndef Tcl_FreeParse #define Tcl_FreeParse \ (tclStubsPtr->tcl_FreeParse) /* 358 */ #endif #ifndef Tcl_LogCommandInfo #define Tcl_LogCommandInfo \ (tclStubsPtr->tcl_LogCommandInfo) /* 359 */ #endif #ifndef Tcl_ParseBraces #define Tcl_ParseBraces \ (tclStubsPtr->tcl_ParseBraces) /* 360 */ #endif #ifndef Tcl_ParseCommand #define Tcl_ParseCommand \ (tclStubsPtr->tcl_ParseCommand) /* 361 */ #endif #ifndef Tcl_ParseExpr #define Tcl_ParseExpr \ (tclStubsPtr->tcl_ParseExpr) /* 362 */ #endif #ifndef Tcl_ParseQuotedString #define Tcl_ParseQuotedString \ (tclStubsPtr->tcl_ParseQuotedString) /* 363 */ #endif #ifndef Tcl_ParseVarName #define Tcl_ParseVarName \ (tclStubsPtr->tcl_ParseVarName) /* 364 */ #endif #ifndef Tcl_GetCwd #define Tcl_GetCwd \ (tclStubsPtr->tcl_GetCwd) /* 365 */ #endif #ifndef Tcl_Chdir #define Tcl_Chdir \ (tclStubsPtr->tcl_Chdir) /* 366 */ #endif #ifndef Tcl_Access #define Tcl_Access \ (tclStubsPtr->tcl_Access) /* 367 */ #endif #ifndef Tcl_Stat #define Tcl_Stat \ (tclStubsPtr->tcl_Stat) /* 368 */ #endif #ifndef Tcl_UtfNcmp #define Tcl_UtfNcmp \ (tclStubsPtr->tcl_UtfNcmp) /* 369 */ #endif #ifndef Tcl_UtfNcasecmp #define Tcl_UtfNcasecmp \ (tclStubsPtr->tcl_UtfNcasecmp) /* 370 */ #endif #ifndef Tcl_StringCaseMatch #define Tcl_StringCaseMatch \ (tclStubsPtr->tcl_StringCaseMatch) /* 371 */ #endif #ifndef Tcl_UniCharIsControl #define Tcl_UniCharIsControl \ (tclStubsPtr->tcl_UniCharIsControl) /* 372 */ #endif #ifndef Tcl_UniCharIsGraph #define Tcl_UniCharIsGraph \ (tclStubsPtr->tcl_UniCharIsGraph) /* 373 */ #endif #ifndef Tcl_UniCharIsPrint #define Tcl_UniCharIsPrint \ (tclStubsPtr->tcl_UniCharIsPrint) /* 374 */ #endif #ifndef Tcl_UniCharIsPunct #define Tcl_UniCharIsPunct \ (tclStubsPtr->tcl_UniCharIsPunct) /* 375 */ #endif #ifndef Tcl_RegExpExecObj #define Tcl_RegExpExecObj \ (tclStubsPtr->tcl_RegExpExecObj) /* 376 */ #endif #ifndef Tcl_RegExpGetInfo #define Tcl_RegExpGetInfo \ (tclStubsPtr->tcl_RegExpGetInfo) /* 377 */ #endif #ifndef Tcl_NewUnicodeObj #define Tcl_NewUnicodeObj \ (tclStubsPtr->tcl_NewUnicodeObj) /* 378 */ #endif #ifndef Tcl_SetUnicodeObj #define Tcl_SetUnicodeObj \ (tclStubsPtr->tcl_SetUnicodeObj) /* 379 */ #endif #ifndef Tcl_GetCharLength #define Tcl_GetCharLength \ (tclStubsPtr->tcl_GetCharLength) /* 380 */ #endif #ifndef Tcl_GetUniChar #define Tcl_GetUniChar \ (tclStubsPtr->tcl_GetUniChar) /* 381 */ #endif #ifndef Tcl_GetUnicode #define Tcl_GetUnicode \ (tclStubsPtr->tcl_GetUnicode) /* 382 */ #endif #ifndef Tcl_GetRange #define Tcl_GetRange \ (tclStubsPtr->tcl_GetRange) /* 383 */ #endif #ifndef Tcl_AppendUnicodeToObj #define Tcl_AppendUnicodeToObj \ (tclStubsPtr->tcl_AppendUnicodeToObj) /* 384 */ #endif #ifndef Tcl_RegExpMatchObj #define Tcl_RegExpMatchObj \ (tclStubsPtr->tcl_RegExpMatchObj) /* 385 */ #endif #ifndef Tcl_SetNotifier #define Tcl_SetNotifier \ (tclStubsPtr->tcl_SetNotifier) /* 386 */ #endif #ifndef Tcl_GetAllocMutex #define Tcl_GetAllocMutex \ (tclStubsPtr->tcl_GetAllocMutex) /* 387 */ #endif #ifndef Tcl_GetChannelNames #define Tcl_GetChannelNames \ (tclStubsPtr->tcl_GetChannelNames) /* 388 */ #endif #ifndef Tcl_GetChannelNamesEx #define Tcl_GetChannelNamesEx \ (tclStubsPtr->tcl_GetChannelNamesEx) /* 389 */ #endif #ifndef Tcl_ProcObjCmd #define Tcl_ProcObjCmd \ (tclStubsPtr->tcl_ProcObjCmd) /* 390 */ #endif #ifndef Tcl_ConditionFinalize #define Tcl_ConditionFinalize \ (tclStubsPtr->tcl_ConditionFinalize) /* 391 */ #endif #ifndef Tcl_MutexFinalize #define Tcl_MutexFinalize \ (tclStubsPtr->tcl_MutexFinalize) /* 392 */ #endif #ifndef Tcl_CreateThread #define Tcl_CreateThread \ (tclStubsPtr->tcl_CreateThread) /* 393 */ #endif #ifndef Tcl_ReadRaw #define Tcl_ReadRaw \ (tclStubsPtr->tcl_ReadRaw) /* 394 */ #endif #ifndef Tcl_WriteRaw #define Tcl_WriteRaw \ (tclStubsPtr->tcl_WriteRaw) /* 395 */ #endif #ifndef Tcl_GetTopChannel #define Tcl_GetTopChannel \ (tclStubsPtr->tcl_GetTopChannel) /* 396 */ #endif #ifndef Tcl_ChannelBuffered #define Tcl_ChannelBuffered \ (tclStubsPtr->tcl_ChannelBuffered) /* 397 */ #endif #ifndef Tcl_ChannelName #define Tcl_ChannelName \ (tclStubsPtr->tcl_ChannelName) /* 398 */ #endif #ifndef Tcl_ChannelVersion #define Tcl_ChannelVersion \ (tclStubsPtr->tcl_ChannelVersion) /* 399 */ #endif #ifndef Tcl_ChannelBlockModeProc #define Tcl_ChannelBlockModeProc \ (tclStubsPtr->tcl_ChannelBlockModeProc) /* 400 */ #endif #ifndef Tcl_ChannelCloseProc #define Tcl_ChannelCloseProc \ (tclStubsPtr->tcl_ChannelCloseProc) /* 401 */ #endif #ifndef Tcl_ChannelClose2Proc #define Tcl_ChannelClose2Proc \ (tclStubsPtr->tcl_ChannelClose2Proc) /* 402 */ #endif #ifndef Tcl_ChannelInputProc #define Tcl_ChannelInputProc \ (tclStubsPtr->tcl_ChannelInputProc) /* 403 */ #endif #ifndef Tcl_ChannelOutputProc #define Tcl_ChannelOutputProc \ (tclStubsPtr->tcl_ChannelOutputProc) /* 404 */ #endif #ifndef Tcl_ChannelSeekProc #define Tcl_ChannelSeekProc \ (tclStubsPtr->tcl_ChannelSeekProc) /* 405 */ #endif #ifndef Tcl_ChannelSetOptionProc #define Tcl_ChannelSetOptionProc \ (tclStubsPtr->tcl_ChannelSetOptionProc) /* 406 */ #endif #ifndef Tcl_ChannelGetOptionProc #define Tcl_ChannelGetOptionProc \ (tclStubsPtr->tcl_ChannelGetOptionProc) /* 407 */ #endif #ifndef Tcl_ChannelWatchProc #define Tcl_ChannelWatchProc \ (tclStubsPtr->tcl_ChannelWatchProc) /* 408 */ #endif #ifndef Tcl_ChannelGetHandleProc #define Tcl_ChannelGetHandleProc \ (tclStubsPtr->tcl_ChannelGetHandleProc) /* 409 */ #endif #ifndef Tcl_ChannelFlushProc #define Tcl_ChannelFlushProc \ (tclStubsPtr->tcl_ChannelFlushProc) /* 410 */ #endif #ifndef Tcl_ChannelHandlerProc #define Tcl_ChannelHandlerProc \ (tclStubsPtr->tcl_ChannelHandlerProc) /* 411 */ #endif #ifndef Tcl_JoinThread #define Tcl_JoinThread \ (tclStubsPtr->tcl_JoinThread) /* 412 */ #endif #ifndef Tcl_IsChannelShared #define Tcl_IsChannelShared \ (tclStubsPtr->tcl_IsChannelShared) /* 413 */ #endif #ifndef Tcl_IsChannelRegistered #define Tcl_IsChannelRegistered \ (tclStubsPtr->tcl_IsChannelRegistered) /* 414 */ #endif #ifndef Tcl_CutChannel #define Tcl_CutChannel \ (tclStubsPtr->tcl_CutChannel) /* 415 */ #endif #ifndef Tcl_SpliceChannel #define Tcl_SpliceChannel \ (tclStubsPtr->tcl_SpliceChannel) /* 416 */ #endif #ifndef Tcl_ClearChannelHandlers #define Tcl_ClearChannelHandlers \ (tclStubsPtr->tcl_ClearChannelHandlers) /* 417 */ #endif #ifndef Tcl_IsChannelExisting #define Tcl_IsChannelExisting \ (tclStubsPtr->tcl_IsChannelExisting) /* 418 */ #endif #ifndef Tcl_UniCharNcasecmp #define Tcl_UniCharNcasecmp \ (tclStubsPtr->tcl_UniCharNcasecmp) /* 419 */ #endif #ifndef Tcl_UniCharCaseMatch #define Tcl_UniCharCaseMatch \ (tclStubsPtr->tcl_UniCharCaseMatch) /* 420 */ #endif #ifndef Tcl_FindHashEntry #define Tcl_FindHashEntry \ (tclStubsPtr->tcl_FindHashEntry) /* 421 */ #endif #ifndef Tcl_CreateHashEntry #define Tcl_CreateHashEntry \ (tclStubsPtr->tcl_CreateHashEntry) /* 422 */ #endif #ifndef Tcl_InitCustomHashTable #define Tcl_InitCustomHashTable \ (tclStubsPtr->tcl_InitCustomHashTable) /* 423 */ #endif #ifndef Tcl_InitObjHashTable #define Tcl_InitObjHashTable \ (tclStubsPtr->tcl_InitObjHashTable) /* 424 */ #endif #ifndef Tcl_CommandTraceInfo #define Tcl_CommandTraceInfo \ (tclStubsPtr->tcl_CommandTraceInfo) /* 425 */ #endif #ifndef Tcl_TraceCommand #define Tcl_TraceCommand \ (tclStubsPtr->tcl_TraceCommand) /* 426 */ #endif #ifndef Tcl_UntraceCommand #define Tcl_UntraceCommand \ (tclStubsPtr->tcl_UntraceCommand) /* 427 */ #endif #ifndef Tcl_AttemptAlloc #define Tcl_AttemptAlloc \ (tclStubsPtr->tcl_AttemptAlloc) /* 428 */ #endif #ifndef Tcl_AttemptDbCkalloc #define Tcl_AttemptDbCkalloc \ (tclStubsPtr->tcl_AttemptDbCkalloc) /* 429 */ #endif #ifndef Tcl_AttemptRealloc #define Tcl_AttemptRealloc \ (tclStubsPtr->tcl_AttemptRealloc) /* 430 */ #endif #ifndef Tcl_AttemptDbCkrealloc #define Tcl_AttemptDbCkrealloc \ (tclStubsPtr->tcl_AttemptDbCkrealloc) /* 431 */ #endif #ifndef Tcl_AttemptSetObjLength #define Tcl_AttemptSetObjLength \ (tclStubsPtr->tcl_AttemptSetObjLength) /* 432 */ #endif #ifndef Tcl_GetChannelThread #define Tcl_GetChannelThread \ (tclStubsPtr->tcl_GetChannelThread) /* 433 */ #endif #ifndef Tcl_GetUnicodeFromObj #define Tcl_GetUnicodeFromObj \ (tclStubsPtr->tcl_GetUnicodeFromObj) /* 434 */ #endif #ifndef Tcl_GetMathFuncInfo #define Tcl_GetMathFuncInfo \ (tclStubsPtr->tcl_GetMathFuncInfo) /* 435 */ #endif #ifndef Tcl_ListMathFuncs #define Tcl_ListMathFuncs \ (tclStubsPtr->tcl_ListMathFuncs) /* 436 */ #endif #ifndef Tcl_SubstObj #define Tcl_SubstObj \ (tclStubsPtr->tcl_SubstObj) /* 437 */ #endif #ifndef Tcl_DetachChannel #define Tcl_DetachChannel \ (tclStubsPtr->tcl_DetachChannel) /* 438 */ #endif #ifndef Tcl_IsStandardChannel #define Tcl_IsStandardChannel \ (tclStubsPtr->tcl_IsStandardChannel) /* 439 */ #endif #ifndef Tcl_FSCopyFile #define Tcl_FSCopyFile \ (tclStubsPtr->tcl_FSCopyFile) /* 440 */ #endif #ifndef Tcl_FSCopyDirectory #define Tcl_FSCopyDirectory \ (tclStubsPtr->tcl_FSCopyDirectory) /* 441 */ #endif #ifndef Tcl_FSCreateDirectory #define Tcl_FSCreateDirectory \ (tclStubsPtr->tcl_FSCreateDirectory) /* 442 */ #endif #ifndef Tcl_FSDeleteFile #define Tcl_FSDeleteFile \ (tclStubsPtr->tcl_FSDeleteFile) /* 443 */ #endif #ifndef Tcl_FSLoadFile #define Tcl_FSLoadFile \ (tclStubsPtr->tcl_FSLoadFile) /* 444 */ #endif #ifndef Tcl_FSMatchInDirectory #define Tcl_FSMatchInDirectory \ (tclStubsPtr->tcl_FSMatchInDirectory) /* 445 */ #endif #ifndef Tcl_FSLink #define Tcl_FSLink \ (tclStubsPtr->tcl_FSLink) /* 446 */ #endif #ifndef Tcl_FSRemoveDirectory #define Tcl_FSRemoveDirectory \ (tclStubsPtr->tcl_FSRemoveDirectory) /* 447 */ #endif #ifndef Tcl_FSRenameFile #define Tcl_FSRenameFile \ (tclStubsPtr->tcl_FSRenameFile) /* 448 */ #endif #ifndef Tcl_FSLstat #define Tcl_FSLstat \ (tclStubsPtr->tcl_FSLstat) /* 449 */ #endif #ifndef Tcl_FSUtime #define Tcl_FSUtime \ (tclStubsPtr->tcl_FSUtime) /* 450 */ #endif #ifndef Tcl_FSFileAttrsGet #define Tcl_FSFileAttrsGet \ (tclStubsPtr->tcl_FSFileAttrsGet) /* 451 */ #endif #ifndef Tcl_FSFileAttrsSet #define Tcl_FSFileAttrsSet \ (tclStubsPtr->tcl_FSFileAttrsSet) /* 452 */ #endif #ifndef Tcl_FSFileAttrStrings #define Tcl_FSFileAttrStrings \ (tclStubsPtr->tcl_FSFileAttrStrings) /* 453 */ #endif #ifndef Tcl_FSStat #define Tcl_FSStat \ (tclStubsPtr->tcl_FSStat) /* 454 */ #endif #ifndef Tcl_FSAccess #define Tcl_FSAccess \ (tclStubsPtr->tcl_FSAccess) /* 455 */ #endif #ifndef Tcl_FSOpenFileChannel #define Tcl_FSOpenFileChannel \ (tclStubsPtr->tcl_FSOpenFileChannel) /* 456 */ #endif #ifndef Tcl_FSGetCwd #define Tcl_FSGetCwd \ (tclStubsPtr->tcl_FSGetCwd) /* 457 */ #endif #ifndef Tcl_FSChdir #define Tcl_FSChdir \ (tclStubsPtr->tcl_FSChdir) /* 458 */ #endif #ifndef Tcl_FSConvertToPathType #define Tcl_FSConvertToPathType \ (tclStubsPtr->tcl_FSConvertToPathType) /* 459 */ #endif #ifndef Tcl_FSJoinPath #define Tcl_FSJoinPath \ (tclStubsPtr->tcl_FSJoinPath) /* 460 */ #endif #ifndef Tcl_FSSplitPath #define Tcl_FSSplitPath \ (tclStubsPtr->tcl_FSSplitPath) /* 461 */ #endif #ifndef Tcl_FSEqualPaths #define Tcl_FSEqualPaths \ (tclStubsPtr->tcl_FSEqualPaths) /* 462 */ #endif #ifndef Tcl_FSGetNormalizedPath #define Tcl_FSGetNormalizedPath \ (tclStubsPtr->tcl_FSGetNormalizedPath) /* 463 */ #endif #ifndef Tcl_FSJoinToPath #define Tcl_FSJoinToPath \ (tclStubsPtr->tcl_FSJoinToPath) /* 464 */ #endif #ifndef Tcl_FSGetInternalRep #define Tcl_FSGetInternalRep \ (tclStubsPtr->tcl_FSGetInternalRep) /* 465 */ #endif #ifndef Tcl_FSGetTranslatedPath #define Tcl_FSGetTranslatedPath \ (tclStubsPtr->tcl_FSGetTranslatedPath) /* 466 */ #endif #ifndef Tcl_FSEvalFile #define Tcl_FSEvalFile \ (tclStubsPtr->tcl_FSEvalFile) /* 467 */ #endif #ifndef Tcl_FSNewNativePath #define Tcl_FSNewNativePath \ (tclStubsPtr->tcl_FSNewNativePath) /* 468 */ #endif #ifndef Tcl_FSGetNativePath #define Tcl_FSGetNativePath \ (tclStubsPtr->tcl_FSGetNativePath) /* 469 */ #endif #ifndef Tcl_FSFileSystemInfo #define Tcl_FSFileSystemInfo \ (tclStubsPtr->tcl_FSFileSystemInfo) /* 470 */ #endif #ifndef Tcl_FSPathSeparator #define Tcl_FSPathSeparator \ (tclStubsPtr->tcl_FSPathSeparator) /* 471 */ #endif #ifndef Tcl_FSListVolumes #define Tcl_FSListVolumes \ (tclStubsPtr->tcl_FSListVolumes) /* 472 */ #endif #ifndef Tcl_FSRegister #define Tcl_FSRegister \ (tclStubsPtr->tcl_FSRegister) /* 473 */ #endif #ifndef Tcl_FSUnregister #define Tcl_FSUnregister \ (tclStubsPtr->tcl_FSUnregister) /* 474 */ #endif #ifndef Tcl_FSData #define Tcl_FSData \ (tclStubsPtr->tcl_FSData) /* 475 */ #endif #ifndef Tcl_FSGetTranslatedStringPath #define Tcl_FSGetTranslatedStringPath \ (tclStubsPtr->tcl_FSGetTranslatedStringPath) /* 476 */ #endif #ifndef Tcl_FSGetFileSystemForPath #define Tcl_FSGetFileSystemForPath \ (tclStubsPtr->tcl_FSGetFileSystemForPath) /* 477 */ #endif #ifndef Tcl_FSGetPathType #define Tcl_FSGetPathType \ (tclStubsPtr->tcl_FSGetPathType) /* 478 */ #endif #ifndef Tcl_OutputBuffered #define Tcl_OutputBuffered \ (tclStubsPtr->tcl_OutputBuffered) /* 479 */ #endif #ifndef Tcl_FSMountsChanged #define Tcl_FSMountsChanged \ (tclStubsPtr->tcl_FSMountsChanged) /* 480 */ #endif #ifndef Tcl_EvalTokensStandard #define Tcl_EvalTokensStandard \ (tclStubsPtr->tcl_EvalTokensStandard) /* 481 */ #endif #ifndef Tcl_GetTime #define Tcl_GetTime \ (tclStubsPtr->tcl_GetTime) /* 482 */ #endif #ifndef Tcl_CreateObjTrace #define Tcl_CreateObjTrace \ (tclStubsPtr->tcl_CreateObjTrace) /* 483 */ #endif #ifndef Tcl_GetCommandInfoFromToken #define Tcl_GetCommandInfoFromToken \ (tclStubsPtr->tcl_GetCommandInfoFromToken) /* 484 */ #endif #ifndef Tcl_SetCommandInfoFromToken #define Tcl_SetCommandInfoFromToken \ (tclStubsPtr->tcl_SetCommandInfoFromToken) /* 485 */ #endif #ifndef Tcl_DbNewWideIntObj #define Tcl_DbNewWideIntObj \ (tclStubsPtr->tcl_DbNewWideIntObj) /* 486 */ #endif #ifndef Tcl_GetWideIntFromObj #define Tcl_GetWideIntFromObj \ (tclStubsPtr->tcl_GetWideIntFromObj) /* 487 */ #endif #ifndef Tcl_NewWideIntObj #define Tcl_NewWideIntObj \ (tclStubsPtr->tcl_NewWideIntObj) /* 488 */ #endif #ifndef Tcl_SetWideIntObj #define Tcl_SetWideIntObj \ (tclStubsPtr->tcl_SetWideIntObj) /* 489 */ #endif #ifndef Tcl_AllocStatBuf #define Tcl_AllocStatBuf \ (tclStubsPtr->tcl_AllocStatBuf) /* 490 */ #endif #ifndef Tcl_Seek #define Tcl_Seek \ (tclStubsPtr->tcl_Seek) /* 491 */ #endif #ifndef Tcl_Tell #define Tcl_Tell \ (tclStubsPtr->tcl_Tell) /* 492 */ #endif #ifndef Tcl_ChannelWideSeekProc #define Tcl_ChannelWideSeekProc \ (tclStubsPtr->tcl_ChannelWideSeekProc) /* 493 */ #endif /* Slot 494 is reserved */ /* Slot 495 is reserved */ /* Slot 496 is reserved */ /* Slot 497 is reserved */ /* Slot 498 is reserved */ /* Slot 499 is reserved */ /* Slot 500 is reserved */ /* Slot 501 is reserved */ /* Slot 502 is reserved */ /* Slot 503 is reserved */ /* Slot 504 is reserved */ /* Slot 505 is reserved */ /* Slot 506 is reserved */ /* Slot 507 is reserved */ /* Slot 508 is reserved */ /* Slot 509 is reserved */ /* Slot 510 is reserved */ /* Slot 511 is reserved */ /* Slot 512 is reserved */ /* Slot 513 is reserved */ /* Slot 514 is reserved */ /* Slot 515 is reserved */ /* Slot 516 is reserved */ /* Slot 517 is reserved */ /* Slot 518 is reserved */ /* Slot 519 is reserved */ /* Slot 520 is reserved */ /* Slot 521 is reserved */ /* Slot 522 is reserved */ /* Slot 523 is reserved */ /* Slot 524 is reserved */ /* Slot 525 is reserved */ /* Slot 526 is reserved */ /* Slot 527 is reserved */ /* Slot 528 is reserved */ /* Slot 529 is reserved */ /* Slot 530 is reserved */ /* Slot 531 is reserved */ /* Slot 532 is reserved */ /* Slot 533 is reserved */ /* Slot 534 is reserved */ /* Slot 535 is reserved */ /* Slot 536 is reserved */ /* Slot 537 is reserved */ /* Slot 538 is reserved */ /* Slot 539 is reserved */ /* Slot 540 is reserved */ /* Slot 541 is reserved */ /* Slot 542 is reserved */ /* Slot 543 is reserved */ /* Slot 544 is reserved */ /* Slot 545 is reserved */ /* Slot 546 is reserved */ /* Slot 547 is reserved */ /* Slot 548 is reserved */ /* Slot 549 is reserved */ /* Slot 550 is reserved */ /* Slot 551 is reserved */ /* Slot 552 is reserved */ /* Slot 553 is reserved */ #ifndef Tcl_ChannelThreadActionProc #define Tcl_ChannelThreadActionProc \ (tclStubsPtr->tcl_ChannelThreadActionProc) /* 554 */ #endif /* Slot 555 is reserved */ /* Slot 556 is reserved */ /* Slot 557 is reserved */ /* Slot 558 is reserved */ /* Slot 559 is reserved */ /* Slot 560 is reserved */ /* Slot 561 is reserved */ /* Slot 562 is reserved */ /* Slot 563 is reserved */ /* Slot 564 is reserved */ /* Slot 565 is reserved */ /* Slot 566 is reserved */ /* Slot 567 is reserved */ /* Slot 568 is reserved */ /* Slot 569 is reserved */ /* Slot 570 is reserved */ /* Slot 571 is reserved */ /* Slot 572 is reserved */ #ifndef Tcl_PkgRequireProc #define Tcl_PkgRequireProc \ (tclStubsPtr->tcl_PkgRequireProc) /* 573 */ #endif /* Slot 574 is reserved */ /* Slot 575 is reserved */ /* Slot 576 is reserved */ /* Slot 577 is reserved */ /* Slot 578 is reserved */ /* Slot 579 is reserved */ /* Slot 580 is reserved */ /* Slot 581 is reserved */ /* Slot 582 is reserved */ /* Slot 583 is reserved */ /* Slot 584 is reserved */ /* Slot 585 is reserved */ /* Slot 586 is reserved */ /* Slot 587 is reserved */ /* Slot 588 is reserved */ /* Slot 589 is reserved */ /* Slot 590 is reserved */ /* Slot 591 is reserved */ /* Slot 592 is reserved */ /* Slot 593 is reserved */ /* Slot 594 is reserved */ /* Slot 595 is reserved */ /* Slot 596 is reserved */ /* Slot 597 is reserved */ /* Slot 598 is reserved */ /* Slot 599 is reserved */ /* Slot 600 is reserved */ /* Slot 601 is reserved */ /* Slot 602 is reserved */ /* Slot 603 is reserved */ /* Slot 604 is reserved */ /* Slot 605 is reserved */ /* Slot 606 is reserved */ /* Slot 607 is reserved */ /* Slot 608 is reserved */ /* Slot 609 is reserved */ /* Slot 610 is reserved */ /* Slot 611 is reserved */ /* Slot 612 is reserved */ /* Slot 613 is reserved */ /* Slot 614 is reserved */ /* Slot 615 is reserved */ /* Slot 616 is reserved */ /* Slot 617 is reserved */ /* Slot 618 is reserved */ /* Slot 619 is reserved */ /* Slot 620 is reserved */ /* Slot 621 is reserved */ /* Slot 622 is reserved */ /* Slot 623 is reserved */ /* Slot 624 is reserved */ /* Slot 625 is reserved */ /* Slot 626 is reserved */ /* Slot 627 is reserved */ /* Slot 628 is reserved */ /* Slot 629 is reserved */ #ifndef TclUnusedStubEntry #define TclUnusedStubEntry \ (tclStubsPtr->tclUnusedStubEntry) /* 630 */ #endif #endif /* defined(USE_TCL_STUBS) && !defined(USE_TCL_STUB_PROCS) */ /* !END!: Do not edit above this line. */ #undef TclUnusedStubEntry #undef Tcl_PkgPresent #define Tcl_PkgPresent(interp, name, version, exact) \ Tcl_PkgPresentEx(interp, name, version, exact, NULL) #undef Tcl_PkgProvide #define Tcl_PkgProvide(interp, name, version) \ Tcl_PkgProvideEx(interp, name, version, NULL) #undef Tcl_PkgRequire #define Tcl_PkgRequire(interp, name, version, exact) \ Tcl_PkgRequireEx(interp, name, version, exact, NULL) #undef Tcl_GetIndexFromObj #define Tcl_GetIndexFromObj(interp, objPtr, tablePtr, msg, flags, indexPtr) \ Tcl_GetIndexFromObjStruct(interp, objPtr, tablePtr, \ sizeof(char *), msg, flags, indexPtr) #undef Tcl_SetVar #define Tcl_SetVar(interp, varName, newValue, flags) \ Tcl_SetVar2(interp, varName, NULL, newValue, flags) #undef Tcl_UnsetVar #define Tcl_UnsetVar(interp, varName, flags) \ Tcl_UnsetVar2(interp, varName, NULL, flags) #undef Tcl_GetVar #define Tcl_GetVar(interp, varName, flags) \ Tcl_GetVar2(interp, varName, NULL, flags) #undef Tcl_TraceVar #define Tcl_TraceVar(interp, varName, flags, proc, clientData) \ Tcl_TraceVar2(interp, varName, NULL, flags, proc, clientData) #undef Tcl_UntraceVar #define Tcl_UntraceVar(interp, varName, flags, proc, clientData) \ Tcl_UntraceVar2(interp, varName, NULL, flags, proc, clientData) #undef Tcl_VarTraceInfo #define Tcl_VarTraceInfo(interp, varName, flags, proc, prevClientData) \ Tcl_VarTraceInfo2(interp, varName, NULL, flags, proc, prevClientData) #undef Tcl_UpVar #define Tcl_UpVar(interp, frameName, varName, localName, flags) \ Tcl_UpVar2(interp, frameName, varName, NULL, localName, flags) #if defined(USE_TCL_STUBS) && !defined(USE_TCL_STUB_PROCS) # if defined(__CYGWIN__) && defined(TCL_WIDE_INT_IS_LONG) /* On Cygwin64, long is 64-bit while on Win64 long is 32-bit. Therefore * we have to make sure that all stub entries on Cygwin64 follow the * Win64 signature. Cygwin64 stubbed extensions cannot use those stub * entries any more, they should use the 64-bit alternatives where * possible. Tcl 9 must find a better solution, but that cannot be done * without introducing a binary incompatibility. */ # undef Tcl_DbNewLongObj # undef Tcl_GetLongFromObj # undef Tcl_NewLongObj # undef Tcl_SetLongObj # undef Tcl_ExprLong # undef Tcl_ExprLongObj # undef Tcl_UniCharNcmp # undef Tcl_UtfNcmp # undef Tcl_UtfNcasecmp # undef Tcl_UniCharNcasecmp # define Tcl_DbNewLongObj ((Tcl_Obj*(*)(long,const char*,int))Tcl_DbNewWideIntObj) # define Tcl_GetLongFromObj ((int(*)(Tcl_Interp*,Tcl_Obj*,long*))Tcl_GetWideIntFromObj) # define Tcl_NewLongObj ((Tcl_Obj*(*)(long))Tcl_NewWideIntObj) # define Tcl_SetLongObj ((void(*)(Tcl_Obj*,long))Tcl_SetWideIntObj) # define Tcl_ExprLong TclExprLong static inline int TclExprLong(Tcl_Interp *interp, const char *string, long *ptr){ int intValue; int result = tclStubsPtr->tcl_ExprLong(interp, string, (long *)&intValue); if (result == TCL_OK) *ptr = (long)intValue; return result; } # define Tcl_ExprLongObj TclExprLongObj static inline int TclExprLongObj(Tcl_Interp *interp, Tcl_Obj *obj, long *ptr){ int intValue; int result = tclStubsPtr->tcl_ExprLongObj(interp, obj, (long *)&intValue); if (result == TCL_OK) *ptr = (long)intValue; return result; } # define Tcl_UniCharNcmp(ucs,uct,n) \ ((int(*)(const Tcl_UniChar*,const Tcl_UniChar*,unsigned int))tclStubsPtr->tcl_UniCharNcmp)(ucs,uct,(unsigned int)(n)) # define Tcl_UtfNcmp(s1,s2,n) \ ((int(*)(const char*,const char*,unsigned int))tclStubsPtr->tcl_UtfNcmp)(s1,s2,(unsigned int)(n)) # define Tcl_UtfNcasecmp(s1,s2,n) \ ((int(*)(const char*,const char*,unsigned int))tclStubsPtr->tcl_UtfNcasecmp)(s1,s2,(unsigned int)(n)) # define Tcl_UniCharNcasecmp(ucs,uct,n) \ ((int(*)(const Tcl_UniChar*,const Tcl_UniChar*,unsigned int))tclStubsPtr->tcl_UniCharNcasecmp)(ucs,uct,(unsigned int)(n)) # endif #endif /* * Deprecated Tcl procedures: */ #undef Tcl_EvalObj #define Tcl_EvalObj(interp,objPtr) \ Tcl_EvalObjEx((interp),(objPtr),0) #undef Tcl_GlobalEvalObj #define Tcl_GlobalEvalObj(interp,objPtr) \ Tcl_EvalObjEx((interp),(objPtr),TCL_EVAL_GLOBAL) #endif /* _TCLDECLS */ tcl8.4.20/generic/tclScan.c0000644003604700454610000006456211737050674014103 0ustar dgp771div/* * tclScan.c -- * * This file contains the implementation of the "scan" command. * * Copyright (c) 1998 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" /* * For strtoll() and strtoull() declarations on some platforms... */ #include "tclPort.h" /* * Flag values used by Tcl_ScanObjCmd. */ #define SCAN_NOSKIP 0x1 /* Don't skip blanks. */ #define SCAN_SUPPRESS 0x2 /* Suppress assignment. */ #define SCAN_UNSIGNED 0x4 /* Read an unsigned value. */ #define SCAN_WIDTH 0x8 /* A width value was supplied. */ #define SCAN_SIGNOK 0x10 /* A +/- character is allowed. */ #define SCAN_NODIGITS 0x20 /* No digits have been scanned. */ #define SCAN_NOZERO 0x40 /* No zero digits have been scanned. */ #define SCAN_XOK 0x80 /* An 'x' is allowed. */ #define SCAN_PTOK 0x100 /* Decimal point is allowed. */ #define SCAN_EXPOK 0x200 /* An exponent is allowed. */ #define SCAN_LONGER 0x400 /* Asked for a wide value. */ /* * The following structure contains the information associated with * a character set. */ typedef struct CharSet { int exclude; /* 1 if this is an exclusion set. */ int nchars; Tcl_UniChar *chars; int nranges; struct Range { Tcl_UniChar start; Tcl_UniChar end; } *ranges; } CharSet; /* * Declarations for functions used only in this file. */ static char * BuildCharSet _ANSI_ARGS_((CharSet *cset, char *format)); static int CharInSet _ANSI_ARGS_((CharSet *cset, int ch)); static void ReleaseCharSet _ANSI_ARGS_((CharSet *cset)); static int ValidateFormat _ANSI_ARGS_((Tcl_Interp *interp, char *format, int numVars, int *totalVars)); /* *---------------------------------------------------------------------- * * BuildCharSet -- * * This function examines a character set format specification * and builds a CharSet containing the individual characters and * character ranges specified. * * Results: * Returns the next format position. * * Side effects: * Initializes the charset. * *---------------------------------------------------------------------- */ static char * BuildCharSet(cset, format) CharSet *cset; char *format; /* Points to first char of set. */ { Tcl_UniChar ch, start; int offset, nranges; char *end; memset(cset, 0, sizeof(CharSet)); offset = Tcl_UtfToUniChar(format, &ch); if (ch == '^') { cset->exclude = 1; format += offset; offset = Tcl_UtfToUniChar(format, &ch); } end = format + offset; /* * Find the close bracket so we can overallocate the set. */ if (ch == ']') { end += Tcl_UtfToUniChar(end, &ch); } nranges = 0; while (ch != ']') { if (ch == '-') { nranges++; } end += Tcl_UtfToUniChar(end, &ch); } cset->chars = (Tcl_UniChar *) ckalloc(sizeof(Tcl_UniChar) * (end - format - 1)); if (nranges > 0) { cset->ranges = (struct Range *) ckalloc(sizeof(struct Range)*nranges); } else { cset->ranges = NULL; } /* * Now build the character set. */ cset->nchars = cset->nranges = 0; format += Tcl_UtfToUniChar(format, &ch); start = ch; if (ch == ']' || ch == '-') { cset->chars[cset->nchars++] = ch; format += Tcl_UtfToUniChar(format, &ch); } while (ch != ']') { if (*format == '-') { /* * This may be the first character of a range, so don't add * it yet. */ start = ch; } else if (ch == '-') { /* * Check to see if this is the last character in the set, in which * case it is not a range and we should add the previous character * as well as the dash. */ if (*format == ']') { cset->chars[cset->nchars++] = start; cset->chars[cset->nchars++] = ch; } else { format += Tcl_UtfToUniChar(format, &ch); /* * Check to see if the range is in reverse order. */ if (start < ch) { cset->ranges[cset->nranges].start = start; cset->ranges[cset->nranges].end = ch; } else { cset->ranges[cset->nranges].start = ch; cset->ranges[cset->nranges].end = start; } cset->nranges++; } } else { cset->chars[cset->nchars++] = ch; } format += Tcl_UtfToUniChar(format, &ch); } return format; } /* *---------------------------------------------------------------------- * * CharInSet -- * * Check to see if a character matches the given set. * * Results: * Returns non-zero if the character matches the given set. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int CharInSet(cset, c) CharSet *cset; int c; /* Character to test, passed as int because * of non-ANSI prototypes. */ { Tcl_UniChar ch = (Tcl_UniChar) c; int i, match = 0; for (i = 0; i < cset->nchars; i++) { if (cset->chars[i] == ch) { match = 1; break; } } if (!match) { for (i = 0; i < cset->nranges; i++) { if ((cset->ranges[i].start <= ch) && (ch <= cset->ranges[i].end)) { match = 1; break; } } } return (cset->exclude ? !match : match); } /* *---------------------------------------------------------------------- * * ReleaseCharSet -- * * Free the storage associated with a character set. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void ReleaseCharSet(cset) CharSet *cset; { ckfree((char *)cset->chars); if (cset->ranges) { ckfree((char *)cset->ranges); } } /* *---------------------------------------------------------------------- * * ValidateFormat -- * * Parse the format string and verify that it is properly formed * and that there are exactly enough variables on the command line. * * Results: * A standard Tcl result. * * Side effects: * May place an error in the interpreter result. * *---------------------------------------------------------------------- */ static int ValidateFormat(interp, format, numVars, totalSubs) Tcl_Interp *interp; /* Current interpreter. */ char *format; /* The format string. */ int numVars; /* The number of variables passed to the * scan command. */ int *totalSubs; /* The number of variables that will be * required. */ { #define STATIC_LIST_SIZE 16 int gotXpg, gotSequential, value, i, flags; char *end; Tcl_UniChar ch; int staticAssign[STATIC_LIST_SIZE]; int *nassign = staticAssign; int objIndex, xpgSize, nspace = STATIC_LIST_SIZE; char buf[TCL_UTF_MAX+1]; /* * Initialize an array that records the number of times a variable * is assigned to by the format string. We use this to detect if * a variable is multiply assigned or left unassigned. */ if (numVars > nspace) { nassign = (int*)ckalloc(sizeof(int) * numVars); nspace = numVars; } for (i = 0; i < nspace; i++) { nassign[i] = 0; } xpgSize = objIndex = gotXpg = gotSequential = 0; while (*format != '\0') { format += Tcl_UtfToUniChar(format, &ch); flags = 0; if (ch != '%') { continue; } format += Tcl_UtfToUniChar(format, &ch); if (ch == '%') { continue; } if (ch == '*') { flags |= SCAN_SUPPRESS; format += Tcl_UtfToUniChar(format, &ch); goto xpgCheckDone; } if ((ch < 0x80) && isdigit(UCHAR(ch))) { /* INTL: "C" locale. */ /* * Check for an XPG3-style %n$ specification. Note: there * must not be a mixture of XPG3 specs and non-XPG3 specs * in the same format string. */ value = strtoul(format-1, &end, 10); /* INTL: "C" locale. */ if (*end != '$') { goto notXpg; } format = end+1; format += Tcl_UtfToUniChar(format, &ch); gotXpg = 1; if (gotSequential) { goto mixedXPG; } objIndex = value - 1; if ((objIndex < 0) || (numVars && (objIndex >= numVars))) { goto badIndex; } else if (numVars == 0) { /* * In the case where no vars are specified, the user can * specify %9999$ legally, so we have to consider special * rules for growing the assign array. 'value' is * guaranteed to be > 0. */ xpgSize = (xpgSize > value) ? xpgSize : value; } goto xpgCheckDone; } notXpg: gotSequential = 1; if (gotXpg) { mixedXPG: Tcl_SetResult(interp, "cannot mix \"%\" and \"%n$\" conversion specifiers", TCL_STATIC); goto error; } xpgCheckDone: /* * Parse any width specifier. */ if ((ch < 0x80) && isdigit(UCHAR(ch))) { /* INTL: "C" locale. */ value = strtoul(format-1, &format, 10); /* INTL: "C" locale. */ flags |= SCAN_WIDTH; format += Tcl_UtfToUniChar(format, &ch); } /* * Handle any size specifier. */ switch (ch) { case 'l': case 'L': flags |= SCAN_LONGER; case 'h': format += Tcl_UtfToUniChar(format, &ch); } if (!(flags & SCAN_SUPPRESS) && numVars && (objIndex >= numVars)) { goto badIndex; } /* * Handle the various field types. */ switch (ch) { case 'c': if (flags & SCAN_WIDTH) { Tcl_SetResult(interp, "field width may not be specified in %c conversion", TCL_STATIC); goto error; } /* * Fall through! */ case 'n': case 's': if (flags & SCAN_LONGER) { invalidLonger: buf[Tcl_UniCharToUtf(ch, buf)] = '\0'; Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "'l' modifier may not be specified in %", buf, " conversion", NULL); goto error; } /* * Fall through! */ case 'd': case 'e': case 'f': case 'g': case 'i': case 'o': case 'u': case 'x': break; /* * Bracket terms need special checking */ case '[': if (flags & SCAN_LONGER) { goto invalidLonger; } if (*format == '\0') { goto badSet; } format += Tcl_UtfToUniChar(format, &ch); if (ch == '^') { if (*format == '\0') { goto badSet; } format += Tcl_UtfToUniChar(format, &ch); } if (ch == ']') { if (*format == '\0') { goto badSet; } format += Tcl_UtfToUniChar(format, &ch); } while (ch != ']') { if (*format == '\0') { goto badSet; } format += Tcl_UtfToUniChar(format, &ch); } break; badSet: Tcl_SetResult(interp, "unmatched [ in format string", TCL_STATIC); goto error; default: { char buf[TCL_UTF_MAX+1]; buf[Tcl_UniCharToUtf(ch, buf)] = '\0'; Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "bad scan conversion character \"", buf, "\"", NULL); goto error; } } if (!(flags & SCAN_SUPPRESS)) { if (objIndex >= nspace) { /* * Expand the nassign buffer. If we are using XPG specifiers, * make sure that we grow to a large enough size. xpgSize is * guaranteed to be at least one larger than objIndex. */ value = nspace; if (xpgSize) { nspace = xpgSize; } else { nspace += STATIC_LIST_SIZE; } if (nassign == staticAssign) { nassign = (void *)ckalloc(nspace * sizeof(int)); for (i = 0; i < STATIC_LIST_SIZE; ++i) { nassign[i] = staticAssign[i]; } } else { nassign = (void *)ckrealloc((void *)nassign, nspace * sizeof(int)); } for (i = value; i < nspace; i++) { nassign[i] = 0; } } nassign[objIndex]++; objIndex++; } } /* * Verify that all of the variable were assigned exactly once. */ if (numVars == 0) { if (xpgSize) { numVars = xpgSize; } else { numVars = objIndex; } } if (totalSubs) { *totalSubs = numVars; } for (i = 0; i < numVars; i++) { if (nassign[i] > 1) { Tcl_SetResult(interp, "variable is assigned by multiple \"%n$\" conversion specifiers", TCL_STATIC); goto error; } else if (!xpgSize && (nassign[i] == 0)) { /* * If the space is empty, and xpgSize is 0 (means XPG wasn't * used, and/or numVars != 0), then too many vars were given */ Tcl_SetResult(interp, "variable is not assigned by any conversion specifiers", TCL_STATIC); goto error; } } if (nassign != staticAssign) { ckfree((char *)nassign); } return TCL_OK; badIndex: if (gotXpg) { Tcl_SetResult(interp, "\"%n$\" argument index out of range", TCL_STATIC); } else { Tcl_SetResult(interp, "different numbers of variable names and field specifiers", TCL_STATIC); } error: if (nassign != staticAssign) { ckfree((char *)nassign); } return TCL_ERROR; #undef STATIC_LIST_SIZE } /* *---------------------------------------------------------------------- * * Tcl_ScanObjCmd -- * * This procedure is invoked to process the "scan" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_ScanObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { char *format; int numVars, nconversions, totalVars = -1; int objIndex, offset, i, result, code; long value; char *string, *end, *baseString; char op = 0; int base = 0; int underflow = 0; size_t width; long (*fn)() = NULL; #ifndef TCL_WIDE_INT_IS_LONG Tcl_WideInt (*lfn)() = NULL; Tcl_WideInt wideValue; #endif Tcl_UniChar ch, sch; Tcl_Obj **objs = NULL, *objPtr = NULL; int flags; char buf[513]; /* Temporary buffer to hold scanned * number strings before they are * passed to strtoul. */ if (objc < 3) { Tcl_WrongNumArgs(interp, 1, objv, "string format ?varName varName ...?"); return TCL_ERROR; } format = Tcl_GetStringFromObj(objv[2], NULL); numVars = objc-3; /* * Check for errors in the format string. */ if (ValidateFormat(interp, format, numVars, &totalVars) == TCL_ERROR) { return TCL_ERROR; } /* * Allocate space for the result objects. */ if (totalVars > 0) { objs = (Tcl_Obj **) ckalloc(sizeof(Tcl_Obj*) * totalVars); for (i = 0; i < totalVars; i++) { objs[i] = NULL; } } string = Tcl_GetStringFromObj(objv[1], NULL); baseString = string; /* * Iterate over the format string filling in the result objects until * we reach the end of input, the end of the format string, or there * is a mismatch. */ objIndex = 0; nconversions = 0; while (*format != '\0') { format += Tcl_UtfToUniChar(format, &ch); flags = 0; /* * If we see whitespace in the format, skip whitespace in the string. */ if (Tcl_UniCharIsSpace(ch)) { offset = Tcl_UtfToUniChar(string, &sch); while (Tcl_UniCharIsSpace(sch)) { if (*string == '\0') { goto done; } string += offset; offset = Tcl_UtfToUniChar(string, &sch); } continue; } if (ch != '%') { literal: if (*string == '\0') { underflow = 1; goto done; } string += Tcl_UtfToUniChar(string, &sch); if (ch != sch) { goto done; } continue; } format += Tcl_UtfToUniChar(format, &ch); if (ch == '%') { goto literal; } /* * Check for assignment suppression ('*') or an XPG3-style * assignment ('%n$'). */ if (ch == '*') { flags |= SCAN_SUPPRESS; format += Tcl_UtfToUniChar(format, &ch); } else if ((ch < 0x80) && isdigit(UCHAR(ch))) { /* INTL: "C" locale. */ value = strtoul(format-1, &end, 10); /* INTL: "C" locale. */ if (*end == '$') { format = end+1; format += Tcl_UtfToUniChar(format, &ch); objIndex = (int) value - 1; } } /* * Parse any width specifier. */ if ((ch < 0x80) && isdigit(UCHAR(ch))) { /* INTL: "C" locale. */ width = strtoul(format-1, &format, 10); /* INTL: "C" locale. */ format += Tcl_UtfToUniChar(format, &ch); } else { width = 0; } /* * Handle any size specifier. */ switch (ch) { case 'l': case 'L': flags |= SCAN_LONGER; /* * Fall through so we skip to the next character. */ case 'h': format += Tcl_UtfToUniChar(format, &ch); } /* * Handle the various field types. */ switch (ch) { case 'n': if (!(flags & SCAN_SUPPRESS)) { objPtr = Tcl_NewIntObj(string - baseString); Tcl_IncrRefCount(objPtr); objs[objIndex++] = objPtr; } nconversions++; continue; case 'd': op = 'i'; base = 10; fn = (long (*)())strtol; #ifndef TCL_WIDE_INT_IS_LONG lfn = (Tcl_WideInt (*)())strtoll; #endif break; case 'i': op = 'i'; base = 0; fn = (long (*)())strtol; #ifndef TCL_WIDE_INT_IS_LONG lfn = (Tcl_WideInt (*)())strtoll; #endif break; case 'o': op = 'i'; base = 8; fn = (long (*)())strtoul; #ifndef TCL_WIDE_INT_IS_LONG lfn = (Tcl_WideInt (*)())strtoull; #endif break; case 'x': op = 'i'; base = 16; fn = (long (*)())strtoul; #ifndef TCL_WIDE_INT_IS_LONG lfn = (Tcl_WideInt (*)())strtoull; #endif break; case 'u': op = 'i'; base = 10; flags |= SCAN_UNSIGNED; fn = (long (*)())strtoul; #ifndef TCL_WIDE_INT_IS_LONG lfn = (Tcl_WideInt (*)())strtoull; #endif break; case 'f': case 'e': case 'g': op = 'f'; break; case 's': op = 's'; break; case 'c': op = 'c'; flags |= SCAN_NOSKIP; break; case '[': op = '['; flags |= SCAN_NOSKIP; break; } /* * At this point, we will need additional characters from the * string to proceed. */ if (*string == '\0') { underflow = 1; goto done; } /* * Skip any leading whitespace at the beginning of a field unless * the format suppresses this behavior. */ if (!(flags & SCAN_NOSKIP)) { while (*string != '\0') { offset = Tcl_UtfToUniChar(string, &sch); if (!Tcl_UniCharIsSpace(sch)) { break; } string += offset; } if (*string == '\0') { underflow = 1; goto done; } } /* * Perform the requested scanning operation. */ switch (op) { case 's': /* * Scan a string up to width characters or whitespace. */ if (width == 0) { width = (size_t) ~0; } end = string; while (*end != '\0') { offset = Tcl_UtfToUniChar(end, &sch); if (Tcl_UniCharIsSpace(sch)) { break; } end += offset; if (--width == 0) { break; } } if (!(flags & SCAN_SUPPRESS)) { objPtr = Tcl_NewStringObj(string, end-string); Tcl_IncrRefCount(objPtr); objs[objIndex++] = objPtr; } string = end; break; case '[': { CharSet cset; if (width == 0) { width = (size_t) ~0; } end = string; format = BuildCharSet(&cset, format); while (*end != '\0') { offset = Tcl_UtfToUniChar(end, &sch); if (!CharInSet(&cset, (int)sch)) { break; } end += offset; if (--width == 0) { break; } } ReleaseCharSet(&cset); if (string == end) { /* * Nothing matched the range, stop processing */ goto done; } if (!(flags & SCAN_SUPPRESS)) { objPtr = Tcl_NewStringObj(string, end-string); Tcl_IncrRefCount(objPtr); objs[objIndex++] = objPtr; } string = end; break; } case 'c': /* * Scan a single Unicode character. */ string += Tcl_UtfToUniChar(string, &sch); if (!(flags & SCAN_SUPPRESS)) { objPtr = Tcl_NewIntObj((int)sch); Tcl_IncrRefCount(objPtr); objs[objIndex++] = objPtr; } break; case 'i': /* * Scan an unsigned or signed integer. */ if ((width == 0) || (width > sizeof(buf) - 1)) { width = sizeof(buf) - 1; } flags |= SCAN_SIGNOK | SCAN_NODIGITS | SCAN_NOZERO; for (end = buf; width > 0; width--) { switch (*string) { /* * The 0 digit has special meaning at the beginning of * a number. If we are unsure of the base, it * indicates that we are in base 8 or base 16 (if it is * followed by an 'x'). * * 8.1 - 8.3.4 incorrectly handled 0x... base-16 * cases for %x by not reading the 0x as the * auto-prelude for base-16. [Bug #495213] */ case '0': if (base == 0) { base = 8; flags |= SCAN_XOK; } if (base == 16) { flags |= SCAN_XOK; } if (flags & SCAN_NOZERO) { flags &= ~(SCAN_SIGNOK | SCAN_NODIGITS | SCAN_NOZERO); } else { flags &= ~(SCAN_SIGNOK | SCAN_XOK | SCAN_NODIGITS); } goto addToInt; case '1': case '2': case '3': case '4': case '5': case '6': case '7': if (base == 0) { base = 10; } flags &= ~(SCAN_SIGNOK | SCAN_XOK | SCAN_NODIGITS); goto addToInt; case '8': case '9': if (base == 0) { base = 10; } if (base <= 8) { break; } flags &= ~(SCAN_SIGNOK | SCAN_XOK | SCAN_NODIGITS); goto addToInt; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': if (base <= 10) { break; } flags &= ~(SCAN_SIGNOK | SCAN_XOK | SCAN_NODIGITS); goto addToInt; case '+': case '-': if (flags & SCAN_SIGNOK) { flags &= ~SCAN_SIGNOK; goto addToInt; } break; case 'x': case 'X': if ((flags & SCAN_XOK) && (end == buf+1)) { base = 16; flags &= ~SCAN_XOK; goto addToInt; } break; } /* * We got an illegal character so we are done accumulating. */ break; addToInt: /* * Add the character to the temporary buffer. */ *end++ = *string++; if (*string == '\0') { break; } } /* * Check to see if we need to back up because we only got a * sign or a trailing x after a 0. */ if (flags & SCAN_NODIGITS) { if (*string == '\0') { underflow = 1; } goto done; } else if (end[-1] == 'x' || end[-1] == 'X') { end--; string--; } /* * Scan the value from the temporary buffer. If we are * returning a large unsigned value, we have to convert it back * to a string since Tcl only supports signed values. */ if (!(flags & SCAN_SUPPRESS)) { *end = '\0'; #ifndef TCL_WIDE_INT_IS_LONG if (flags & SCAN_LONGER) { wideValue = (Tcl_WideInt) (*lfn)(buf, NULL, base); if ((flags & SCAN_UNSIGNED) && (wideValue < 0)) { /* INTL: ISO digit */ sprintf(buf, "%" TCL_LL_MODIFIER "u", (Tcl_WideUInt)wideValue); objPtr = Tcl_NewStringObj(buf, -1); } else { objPtr = Tcl_NewWideIntObj(wideValue); } } else { #endif /* !TCL_WIDE_INT_IS_LONG */ value = (long) (*fn)(buf, NULL, base); if ((flags & SCAN_UNSIGNED) && (value < 0)) { sprintf(buf, "%lu", value); /* INTL: ISO digit */ objPtr = Tcl_NewStringObj(buf, -1); } else if ((flags & SCAN_LONGER) || (unsigned long) value > UINT_MAX) { objPtr = Tcl_NewLongObj(value); } else { objPtr = Tcl_NewIntObj(value); } #ifndef TCL_WIDE_INT_IS_LONG } #endif Tcl_IncrRefCount(objPtr); objs[objIndex++] = objPtr; } break; case 'f': /* * Scan a floating point number */ if ((width == 0) || (width > sizeof(buf) - 1)) { width = sizeof(buf) - 1; } flags &= ~SCAN_LONGER; flags |= SCAN_SIGNOK | SCAN_NODIGITS | SCAN_PTOK | SCAN_EXPOK; for (end = buf; width > 0; width--) { switch (*string) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': flags &= ~(SCAN_SIGNOK | SCAN_NODIGITS); goto addToFloat; case '+': case '-': if (flags & SCAN_SIGNOK) { flags &= ~SCAN_SIGNOK; goto addToFloat; } break; case '.': if (flags & SCAN_PTOK) { flags &= ~(SCAN_SIGNOK | SCAN_PTOK); goto addToFloat; } break; case 'e': case 'E': /* * An exponent is not allowed until there has * been at least one digit. */ if ((flags & (SCAN_NODIGITS | SCAN_EXPOK)) == SCAN_EXPOK) { flags = (flags & ~(SCAN_EXPOK|SCAN_PTOK)) | SCAN_SIGNOK | SCAN_NODIGITS; goto addToFloat; } break; } /* * We got an illegal character so we are done accumulating. */ break; addToFloat: /* * Add the character to the temporary buffer. */ *end++ = *string++; if (*string == '\0') { break; } } /* * Check to see if we need to back up because we saw a * trailing 'e' or sign. */ if (flags & SCAN_NODIGITS) { if (flags & SCAN_EXPOK) { /* * There were no digits at all so scanning has * failed and we are done. */ if (*string == '\0') { underflow = 1; } goto done; } /* * We got a bad exponent ('e' and maybe a sign). */ end--; string--; if (*end != 'e' && *end != 'E') { end--; string--; } } /* * Scan the value from the temporary buffer. */ if (!(flags & SCAN_SUPPRESS)) { double dvalue; *end = '\0'; dvalue = strtod(buf, NULL); objPtr = Tcl_NewDoubleObj(dvalue); Tcl_IncrRefCount(objPtr); objs[objIndex++] = objPtr; } break; } nconversions++; } done: result = 0; code = TCL_OK; if (numVars) { /* * In this case, variables were specified (classic scan) */ for (i = 0; i < totalVars; i++) { if (objs[i] != NULL) { Tcl_Obj *tmpPtr; result++; tmpPtr = Tcl_ObjSetVar2(interp, objv[i+3], NULL, objs[i], 0); Tcl_DecrRefCount(objs[i]); if (tmpPtr == NULL) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "couldn't set variable \"", Tcl_GetString(objv[i+3]), "\"", (char *) NULL); code = TCL_ERROR; } } } } else { /* * Here no vars were specified, we want a list returned (inline scan) */ objPtr = Tcl_NewObj(); for (i = 0; i < totalVars; i++) { if (objs[i] != NULL) { Tcl_ListObjAppendElement(NULL, objPtr, objs[i]); Tcl_DecrRefCount(objs[i]); } else { /* * More %-specifiers than matching chars, so we * just spit out empty strings for these */ Tcl_ListObjAppendElement(NULL, objPtr, Tcl_NewObj()); } } } if (objs != NULL) { ckfree((char*) objs); } if (code == TCL_OK) { if (underflow && (nconversions == 0)) { if (numVars) { objPtr = Tcl_NewIntObj(-1); } else { if (objPtr) { Tcl_SetListObj(objPtr, 0, NULL); } else { objPtr = Tcl_NewObj(); } } } else if (numVars) { objPtr = Tcl_NewIntObj(result); } Tcl_SetObjResult(interp, objPtr); } return code; } tcl8.4.20/generic/tclInt.h0000644003604700454610000032130312052456744013742 0ustar dgp771div/* * tclInt.h -- * * Declarations of things used internally by the Tcl interpreter. * * Copyright (c) 1987-1993 The Regents of the University of California. * Copyright (c) 1993-1997 Lucent Technologies. * Copyright (c) 1994-1998 Sun Microsystems, Inc. * Copyright (c) 1998-1999 by Scriptics Corporation. * Copyright (c) 2001, 2002 by Kevin B. Kenny. All rights reserved. * Copyright (c) 2007 Daniel A. Steffen * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef _TCLINT #define _TCLINT /* * Common include files needed by most of the Tcl source files are * included here, so that system-dependent personalizations for the * include files only have to be made in once place. This results * in a few extra includes, but greater modularity. The order of * the three groups of #includes is important. For example, stdio.h * is needed by tcl.h, and the _ANSI_ARGS_ declaration in tcl.h is * needed by stdlib.h in some configurations. */ #ifndef _TCL #include "tcl.h" #endif #include #include #ifdef NO_LIMITS_H # include "../compat/limits.h" #else # include #endif #ifdef NO_STDLIB_H # include "../compat/stdlib.h" #else # include #endif #ifdef NO_STRING_H #include "../compat/string.h" #else #include #endif /* * Ensure WORDS_BIGENDIAN is defined correcly: * Needs to happen here in addition to configure to work with fat compiles on * Darwin (where configure runs only once for multiple architectures). */ #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_PARAM_H # include #endif #ifdef BYTE_ORDER # ifdef BIG_ENDIAN # if BYTE_ORDER == BIG_ENDIAN # undef WORDS_BIGENDIAN # define WORDS_BIGENDIAN 1 # endif # endif # ifdef LITTLE_ENDIAN # if BYTE_ORDER == LITTLE_ENDIAN # undef WORDS_BIGENDIAN # endif # endif #endif /* * Used to tag functions that are only to be visible within the module being * built and not outside it (where this is supported by the linker). */ #ifndef MODULE_SCOPE # ifdef __cplusplus # define MODULE_SCOPE extern "C" # else # define MODULE_SCOPE extern # endif #endif #undef TCL_STORAGE_CLASS #ifdef BUILD_tcl # define TCL_STORAGE_CLASS DLLEXPORT #else # ifdef USE_TCL_STUBS # define TCL_STORAGE_CLASS # else # define TCL_STORAGE_CLASS DLLIMPORT # endif #endif /* * The following procedures allow namespaces to be customized to * support special name resolution rules for commands/variables. * */ struct Tcl_ResolvedVarInfo; typedef Tcl_Var (Tcl_ResolveRuntimeVarProc) _ANSI_ARGS_(( Tcl_Interp* interp, struct Tcl_ResolvedVarInfo *vinfoPtr)); typedef void (Tcl_ResolveVarDeleteProc) _ANSI_ARGS_(( struct Tcl_ResolvedVarInfo *vinfoPtr)); /* * The following structure encapsulates the routines needed to resolve a * variable reference at runtime. Any variable specific state will typically * be appended to this structure. */ typedef struct Tcl_ResolvedVarInfo { Tcl_ResolveRuntimeVarProc *fetchProc; Tcl_ResolveVarDeleteProc *deleteProc; } Tcl_ResolvedVarInfo; typedef int (Tcl_ResolveCompiledVarProc) _ANSI_ARGS_(( Tcl_Interp* interp, CONST84 char* name, int length, Tcl_Namespace *context, Tcl_ResolvedVarInfo **rPtr)); typedef int (Tcl_ResolveVarProc) _ANSI_ARGS_(( Tcl_Interp* interp, CONST84 char* name, Tcl_Namespace *context, int flags, Tcl_Var *rPtr)); typedef int (Tcl_ResolveCmdProc) _ANSI_ARGS_((Tcl_Interp* interp, CONST84 char* name, Tcl_Namespace *context, int flags, Tcl_Command *rPtr)); typedef struct Tcl_ResolverInfo { Tcl_ResolveCmdProc *cmdResProc; /* Procedure handling command name * resolution. */ Tcl_ResolveVarProc *varResProc; /* Procedure handling variable name * resolution for variables that * can only be handled at runtime. */ Tcl_ResolveCompiledVarProc *compiledVarResProc; /* Procedure handling variable name * resolution at compile time. */ } Tcl_ResolverInfo; /* *---------------------------------------------------------------- * Data structures related to namespaces. *---------------------------------------------------------------- */ /* * The structure below defines a namespace. * Note: the first five fields must match exactly the fields in a * Tcl_Namespace structure (see tcl.h). If you change one, be sure to * change the other. */ typedef struct Namespace { char *name; /* The namespace's simple (unqualified) * name. This contains no ::'s. The name of * the global namespace is "" although "::" * is an synonym. */ char *fullName; /* The namespace's fully qualified name. * This starts with ::. */ ClientData clientData; /* An arbitrary value associated with this * namespace. */ Tcl_NamespaceDeleteProc *deleteProc; /* Procedure invoked when deleting the * namespace to, e.g., free clientData. */ struct Namespace *parentPtr; /* Points to the namespace that contains * this one. NULL if this is the global * namespace. */ Tcl_HashTable childTable; /* Contains any child namespaces. Indexed * by strings; values have type * (Namespace *). */ long nsId; /* Unique id for the namespace. */ Tcl_Interp *interp; /* The interpreter containing this * namespace. */ int flags; /* OR-ed combination of the namespace * status flags NS_DYING and NS_DEAD * listed below. */ int activationCount; /* Number of "activations" or active call * frames for this namespace that are on * the Tcl call stack. The namespace won't * be freed until activationCount becomes * zero. */ int refCount; /* Count of references by namespaceName * * objects. The namespace can't be freed * until refCount becomes zero. */ Tcl_HashTable cmdTable; /* Contains all the commands currently * registered in the namespace. Indexed by * strings; values have type (Command *). * Commands imported by Tcl_Import have * Command structures that point (via an * ImportedCmdRef structure) to the * Command structure in the source * namespace's command table. */ Tcl_HashTable varTable; /* Contains all the (global) variables * currently in this namespace. Indexed * by strings; values have type (Var *). */ char **exportArrayPtr; /* Points to an array of string patterns * specifying which commands are exported. * A pattern may include "string match" * style wildcard characters to specify * multiple commands; however, no namespace * qualifiers are allowed. NULL if no * export patterns are registered. */ int numExportPatterns; /* Number of export patterns currently * registered using "namespace export". */ int maxExportPatterns; /* Mumber of export patterns for which * space is currently allocated. */ int cmdRefEpoch; /* Incremented if a newly added command * shadows a command for which this * namespace has already cached a Command * * pointer; this causes all its cached * Command* pointers to be invalidated. */ int resolverEpoch; /* Incremented whenever (a) the name resolution * rules change for this namespace or (b) a * newly added command shadows a command that * is compiled to bytecodes. * This invalidates all byte codes compiled * in the namespace, causing the code to be * recompiled under the new rules.*/ Tcl_ResolveCmdProc *cmdResProc; /* If non-null, this procedure overrides * the usual command resolution mechanism * in Tcl. This procedure is invoked * within Tcl_FindCommand to resolve all * command references within the namespace. */ Tcl_ResolveVarProc *varResProc; /* If non-null, this procedure overrides * the usual variable resolution mechanism * in Tcl. This procedure is invoked * within Tcl_FindNamespaceVar to resolve all * variable references within the namespace * at runtime. */ Tcl_ResolveCompiledVarProc *compiledVarResProc; /* If non-null, this procedure overrides * the usual variable resolution mechanism * in Tcl. This procedure is invoked * within LookupCompiledLocal to resolve * variable references within the namespace * at compile time. */ } Namespace; /* * Flags used to represent the status of a namespace: * * NS_DYING - 1 means Tcl_DeleteNamespace has been called to delete the * namespace but there are still active call frames on the Tcl * stack that refer to the namespace. When the last call frame * referring to it has been popped, it's variables and command * will be destroyed and it will be marked "dead" (NS_DEAD). * The namespace can no longer be looked up by name. * NS_DEAD - 1 means Tcl_DeleteNamespace has been called to delete the * namespace and no call frames still refer to it. Its * variables and command have already been destroyed. This bit * allows the namespace resolution code to recognize that the * namespace is "deleted". When the last namespaceName object * in any byte code code unit that refers to the namespace has * been freed (i.e., when the namespace's refCount is 0), the * namespace's storage will be freed. * NS_KILLED 1 means that TclTeardownNamespace has already been called on * this namespace and it should not be called again [Bug 1355942] */ #define NS_DYING 0x01 #define NS_DEAD 0x02 #define NS_KILLED 0x04 /* * Flag passed to TclGetNamespaceForQualName to have it create all namespace * components of a namespace-qualified name that cannot be found. The new * namespaces are created within their specified parent. Note that this * flag's value must not conflict with the values of the flags * TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY, and FIND_ONLY_NS (defined in * tclNamesp.c). */ #define CREATE_NS_IF_UNKNOWN 0x800 /* *---------------------------------------------------------------- * Data structures related to variables. These are used primarily * in tclVar.c *---------------------------------------------------------------- */ /* * The following structure defines a variable trace, which is used to * invoke a specific C procedure whenever certain operations are performed * on a variable. */ typedef struct VarTrace { Tcl_VarTraceProc *traceProc;/* Procedure to call when operations given * by flags are performed on variable. */ ClientData clientData; /* Argument to pass to proc. */ int flags; /* What events the trace procedure is * interested in: OR-ed combination of * TCL_TRACE_READS, TCL_TRACE_WRITES, * TCL_TRACE_UNSETS and TCL_TRACE_ARRAY. */ struct VarTrace *nextPtr; /* Next in list of traces associated with * a particular variable. */ } VarTrace; /* * The following structure defines a command trace, which is used to * invoke a specific C procedure whenever certain operations are performed * on a command. */ typedef struct CommandTrace { Tcl_CommandTraceProc *traceProc;/* Procedure to call when operations given * by flags are performed on command. */ ClientData clientData; /* Argument to pass to proc. */ int flags; /* What events the trace procedure is * interested in: OR-ed combination of * TCL_TRACE_RENAME, TCL_TRACE_DELETE. */ struct CommandTrace *nextPtr; /* Next in list of traces associated with * a particular command. */ int refCount; /* Used to ensure this structure is * not deleted too early. Keeps track * of how many pieces of code have * a pointer to this structure. */ } CommandTrace; /* * When a command trace is active (i.e. its associated procedure is * executing), one of the following structures is linked into a list * associated with the command's interpreter. The information in * the structure is needed in order for Tcl to behave reasonably * if traces are deleted while traces are active. */ typedef struct ActiveCommandTrace { struct Command *cmdPtr; /* Command that's being traced. */ struct ActiveCommandTrace *nextPtr; /* Next in list of all active command * traces for the interpreter, or NULL * if no more. */ CommandTrace *nextTracePtr; /* Next trace to check after current * trace procedure returns; if this * trace gets deleted, must update pointer * to avoid using free'd memory. */ int reverseScan; /* Boolean set true when the traces * are scanning in reverse order. */ } ActiveCommandTrace; /* * When a variable trace is active (i.e. its associated procedure is * executing), one of the following structures is linked into a list * associated with the variable's interpreter. The information in * the structure is needed in order for Tcl to behave reasonably * if traces are deleted while traces are active. */ typedef struct ActiveVarTrace { struct Var *varPtr; /* Variable that's being traced. */ struct ActiveVarTrace *nextPtr; /* Next in list of all active variable * traces for the interpreter, or NULL * if no more. */ VarTrace *nextTracePtr; /* Next trace to check after current * trace procedure returns; if this * trace gets deleted, must update pointer * to avoid using free'd memory. */ } ActiveVarTrace; /* * The following structure describes an enumerative search in progress on * an array variable; this are invoked with options to the "array" * command. */ typedef struct ArraySearch { int id; /* Integer id used to distinguish among * multiple concurrent searches for the * same array. */ struct Var *varPtr; /* Pointer to array variable that's being * searched. */ Tcl_HashSearch search; /* Info kept by the hash module about * progress through the array. */ Tcl_HashEntry *nextEntry; /* Non-null means this is the next element * to be enumerated (it's leftover from * the Tcl_FirstHashEntry call or from * an "array anymore" command). NULL * means must call Tcl_NextHashEntry * to get value to return. */ struct ArraySearch *nextPtr;/* Next in list of all active searches * for this variable, or NULL if this is * the last one. */ } ArraySearch; /* * The structure below defines a variable, which associates a string name * with a Tcl_Obj value. These structures are kept in procedure call frames * (for local variables recognized by the compiler) or in the heap (for * global variables and any variable not known to the compiler). For each * Var structure in the heap, a hash table entry holds the variable name and * a pointer to the Var structure. */ typedef struct Var { union { Tcl_Obj *objPtr; /* The variable's object value. Used for * scalar variables and array elements. */ Tcl_HashTable *tablePtr;/* For array variables, this points to * information about the hash table used * to implement the associative array. * Points to malloc-ed data. */ struct Var *linkPtr; /* If this is a global variable being * referred to in a procedure, or a variable * created by "upvar", this field points to * the referenced variable's Var struct. */ } value; char *name; /* NULL if the variable is in a hashtable, * otherwise points to the variable's * name. It is used, e.g., by TclLookupVar * and "info locals". The storage for the * characters of the name is not owned by * the Var and must not be freed when * freeing the Var. */ Namespace *nsPtr; /* Points to the namespace that contains * this variable or NULL if the variable is * a local variable in a Tcl procedure. */ Tcl_HashEntry *hPtr; /* If variable is in a hashtable, either the * hash table entry that refers to this * variable or NULL if the variable has been * detached from its hash table (e.g. an * array is deleted, but some of its * elements are still referred to in * upvars). NULL if the variable is not in a * hashtable. This is used to delete an * variable from its hashtable if it is no * longer needed. */ int refCount; /* Counts number of active uses of this * variable, not including its entry in the * call frame or the hash table: 1 for each * additional variable whose linkPtr points * here, 1 for each nested trace active on * variable, and 1 if the variable is a * namespace variable. This record can't be * deleted until refCount becomes 0. */ VarTrace *tracePtr; /* First in list of all traces set for this * variable. */ ArraySearch *searchPtr; /* First in list of all searches active * for this variable, or NULL if none. */ int flags; /* Miscellaneous bits of information about * variable. See below for definitions. */ } Var; /* * Flag bits for variables. The first three (VAR_SCALAR, VAR_ARRAY, and * VAR_LINK) are mutually exclusive and give the "type" of the variable. * VAR_UNDEFINED is independent of the variable's type. * * VAR_SCALAR - 1 means this is a scalar variable and not * an array or link. The "objPtr" field points * to the variable's value, a Tcl object. * VAR_ARRAY - 1 means this is an array variable rather * than a scalar variable or link. The * "tablePtr" field points to the array's * hashtable for its elements. * VAR_LINK - 1 means this Var structure contains a * pointer to another Var structure that * either has the real value or is itself * another VAR_LINK pointer. Variables like * this come about through "upvar" and "global" * commands, or through references to variables * in enclosing namespaces. * VAR_UNDEFINED - 1 means that the variable is in the process * of being deleted. An undefined variable * logically does not exist and survives only * while it has a trace, or if it is a global * variable currently being used by some * procedure. * VAR_IN_HASHTABLE - 1 means this variable is in a hashtable and * the Var structure is malloced. 0 if it is * a local variable that was assigned a slot * in a procedure frame by the compiler so the * Var storage is part of the call frame. * VAR_TRACE_ACTIVE - 1 means that trace processing is currently * underway for a read or write access, so * new read or write accesses should not cause * trace procedures to be called and the * variable can't be deleted. * VAR_ARRAY_ELEMENT - 1 means that this variable is an array * element, so it is not legal for it to be * an array itself (the VAR_ARRAY flag had * better not be set). * VAR_NAMESPACE_VAR - 1 means that this variable was declared * as a namespace variable. This flag ensures * it persists until its namespace is * destroyed or until the variable is unset; * it will persist even if it has not been * initialized and is marked undefined. * The variable's refCount is incremented to * reflect the "reference" from its namespace. * * The following additional flags are used with the CompiledLocal type * defined below: * * VAR_ARGUMENT - 1 means that this variable holds a procedure * argument. * VAR_TEMPORARY - 1 if the local variable is an anonymous * temporary variable. Temporaries have a NULL * name. * VAR_RESOLVED - 1 if name resolution has been done for this * variable. */ #define VAR_SCALAR 0x1 #define VAR_ARRAY 0x2 #define VAR_LINK 0x4 #define VAR_UNDEFINED 0x8 #define VAR_IN_HASHTABLE 0x10 #define VAR_TRACE_ACTIVE 0x20 #define VAR_ARRAY_ELEMENT 0x40 #define VAR_NAMESPACE_VAR 0x80 #define VAR_ARGUMENT 0x100 #define VAR_TEMPORARY 0x200 #define VAR_RESOLVED 0x400 /* * Macros to ensure that various flag bits are set properly for variables. * The ANSI C "prototypes" for these macros are: * * EXTERN void TclSetVarScalar _ANSI_ARGS_((Var *varPtr)); * EXTERN void TclSetVarArray _ANSI_ARGS_((Var *varPtr)); * EXTERN void TclSetVarLink _ANSI_ARGS_((Var *varPtr)); * EXTERN void TclSetVarArrayElement _ANSI_ARGS_((Var *varPtr)); * EXTERN void TclSetVarUndefined _ANSI_ARGS_((Var *varPtr)); * EXTERN void TclClearVarUndefined _ANSI_ARGS_((Var *varPtr)); */ #define TclSetVarScalar(varPtr) \ (varPtr)->flags = ((varPtr)->flags & ~(VAR_ARRAY|VAR_LINK)) | VAR_SCALAR #define TclSetVarArray(varPtr) \ (varPtr)->flags = ((varPtr)->flags & ~(VAR_SCALAR|VAR_LINK)) | VAR_ARRAY #define TclSetVarLink(varPtr) \ (varPtr)->flags = ((varPtr)->flags & ~(VAR_SCALAR|VAR_ARRAY)) | VAR_LINK #define TclSetVarArrayElement(varPtr) \ (varPtr)->flags = ((varPtr)->flags & ~VAR_ARRAY) | VAR_ARRAY_ELEMENT #define TclSetVarUndefined(varPtr) \ (varPtr)->flags |= VAR_UNDEFINED #define TclClearVarUndefined(varPtr) \ (varPtr)->flags &= ~VAR_UNDEFINED /* * Macros to read various flag bits of variables. * The ANSI C "prototypes" for these macros are: * * EXTERN int TclIsVarScalar _ANSI_ARGS_((Var *varPtr)); * EXTERN int TclIsVarLink _ANSI_ARGS_((Var *varPtr)); * EXTERN int TclIsVarArray _ANSI_ARGS_((Var *varPtr)); * EXTERN int TclIsVarUndefined _ANSI_ARGS_((Var *varPtr)); * EXTERN int TclIsVarArrayElement _ANSI_ARGS_((Var *varPtr)); * EXTERN int TclIsVarTemporary _ANSI_ARGS_((Var *varPtr)); * EXTERN int TclIsVarArgument _ANSI_ARGS_((Var *varPtr)); * EXTERN int TclIsVarResolved _ANSI_ARGS_((Var *varPtr)); */ #define TclIsVarScalar(varPtr) \ ((varPtr)->flags & VAR_SCALAR) #define TclIsVarLink(varPtr) \ ((varPtr)->flags & VAR_LINK) #define TclIsVarArray(varPtr) \ ((varPtr)->flags & VAR_ARRAY) #define TclIsVarUndefined(varPtr) \ ((varPtr)->flags & VAR_UNDEFINED) #define TclIsVarArrayElement(varPtr) \ ((varPtr)->flags & VAR_ARRAY_ELEMENT) #define TclIsVarTemporary(varPtr) \ ((varPtr)->flags & VAR_TEMPORARY) #define TclIsVarArgument(varPtr) \ ((varPtr)->flags & VAR_ARGUMENT) #define TclIsVarResolved(varPtr) \ ((varPtr)->flags & VAR_RESOLVED) /* *---------------------------------------------------------------- * Data structures related to procedures. These are used primarily * in tclProc.c, tclCompile.c, and tclExecute.c. *---------------------------------------------------------------- */ /* * Forward declaration to prevent an error when the forward reference to * Command is encountered in the Proc and ImportRef types declared below. */ struct Command; /* * The variable-length structure below describes a local variable of a * procedure that was recognized by the compiler. These variables have a * name, an element in the array of compiler-assigned local variables in the * procedure's call frame, and various other items of information. If the * local variable is a formal argument, it may also have a default value. * The compiler can't recognize local variables whose names are * expressions (these names are only known at runtime when the expressions * are evaluated) or local variables that are created as a result of an * "upvar" or "uplevel" command. These other local variables are kept * separately in a hash table in the call frame. */ typedef struct CompiledLocal { struct CompiledLocal *nextPtr; /* Next compiler-recognized local variable * for this procedure, or NULL if this is * the last local. */ int nameLength; /* The number of characters in local * variable's name. Used to speed up * variable lookups. */ int frameIndex; /* Index in the array of compiler-assigned * variables in the procedure call frame. */ int flags; /* Flag bits for the local variable. Same as * the flags for the Var structure above, * although only VAR_SCALAR, VAR_ARRAY, * VAR_LINK, VAR_ARGUMENT, VAR_TEMPORARY, and * VAR_RESOLVED make sense. */ Tcl_Obj *defValuePtr; /* Pointer to the default value of an * argument, if any. NULL if not an argument * or, if an argument, no default value. */ Tcl_ResolvedVarInfo *resolveInfo; /* Customized variable resolution info * supplied by the Tcl_ResolveCompiledVarProc * associated with a namespace. Each variable * is marked by a unique ClientData tag * during compilation, and that same tag * is used to find the variable at runtime. */ char name[4]; /* Name of the local variable starts here. * If the name is NULL, this will just be * '\0'. The actual size of this field will * be large enough to hold the name. MUST * BE THE LAST FIELD IN THE STRUCTURE! */ } CompiledLocal; /* * The structure below defines a command procedure, which consists of a * collection of Tcl commands plus information about arguments and other * local variables recognized at compile time. */ typedef struct Proc { struct Interp *iPtr; /* Interpreter for which this command * is defined. */ int refCount; /* Reference count: 1 if still present * in command table plus 1 for each call * to the procedure that is currently * active. This structure can be freed * when refCount becomes zero. */ struct Command *cmdPtr; /* Points to the Command structure for * this procedure. This is used to get * the namespace in which to execute * the procedure. */ Tcl_Obj *bodyPtr; /* Points to the ByteCode object for * procedure's body command. */ int numArgs; /* Number of formal parameters. */ int numCompiledLocals; /* Count of local variables recognized by * the compiler including arguments and * temporaries. */ CompiledLocal *firstLocalPtr; /* Pointer to first of the procedure's * compiler-allocated local variables, or * NULL if none. The first numArgs entries * in this list describe the procedure's * formal arguments. */ CompiledLocal *lastLocalPtr; /* Pointer to the last allocated local * variable or NULL if none. This has * frame index (numCompiledLocals-1). */ } Proc; /* * The structure below defines a command trace. This is used to allow Tcl * clients to find out whenever a command is about to be executed. */ typedef struct Trace { int level; /* Only trace commands at nesting level * less than or equal to this. */ Tcl_CmdObjTraceProc *proc; /* Procedure to call to trace command. */ ClientData clientData; /* Arbitrary value to pass to proc. */ struct Trace *nextPtr; /* Next in list of traces for this interp. */ int flags; /* Flags governing the trace - see * Tcl_CreateObjTrace for details */ Tcl_CmdObjTraceDeleteProc* delProc; /* Procedure to call when trace is deleted */ } Trace; /* * When an interpreter trace is active (i.e. its associated procedure * is executing), one of the following structures is linked into a list * associated with the interpreter. The information in the structure * is needed in order for Tcl to behave reasonably if traces are * deleted while traces are active. */ typedef struct ActiveInterpTrace { struct ActiveInterpTrace *nextPtr; /* Next in list of all active command * traces for the interpreter, or NULL * if no more. */ Trace *nextTracePtr; /* Next trace to check after current * trace procedure returns; if this * trace gets deleted, must update pointer * to avoid using free'd memory. */ int reverseScan; /* Boolean set true when the traces * are scanning in reverse order. */ } ActiveInterpTrace; /* * The structure below defines an entry in the assocData hash table which * is associated with an interpreter. The entry contains a pointer to a * function to call when the interpreter is deleted, and a pointer to * a user-defined piece of data. */ typedef struct AssocData { Tcl_InterpDeleteProc *proc; /* Proc to call when deleting. */ ClientData clientData; /* Value to pass to proc. */ } AssocData; /* * The structure below defines a call frame. A call frame defines a naming * context for a procedure call: its local naming scope (for local * variables) and its global naming scope (a namespace, perhaps the global * :: namespace). A call frame can also define the naming context for a * namespace eval or namespace inscope command: the namespace in which the * command's code should execute. The Tcl_CallFrame structures exist only * while procedures or namespace eval/inscope's are being executed, and * provide a kind of Tcl call stack. * * WARNING!! The structure definition must be kept consistent with the * Tcl_CallFrame structure in tcl.h. If you change one, change the other. */ typedef struct CallFrame { Namespace *nsPtr; /* Points to the namespace used to resolve * commands and global variables. */ int isProcCallFrame; /* If nonzero, the frame was pushed to * execute a Tcl procedure and may have * local vars. If 0, the frame was pushed * to execute a namespace command and var * references are treated as references to * namespace vars; varTablePtr and * compiledLocals are ignored. */ int objc; /* This and objv below describe the * arguments for this procedure call. */ Tcl_Obj *CONST *objv; /* Array of argument objects. */ struct CallFrame *callerPtr; /* Value of interp->framePtr when this * procedure was invoked (i.e. next higher * in stack of all active procedures). */ struct CallFrame *callerVarPtr; /* Value of interp->varFramePtr when this * procedure was invoked (i.e. determines * variable scoping within caller). Same * as callerPtr unless an "uplevel" command * or something equivalent was active in * the caller). */ int level; /* Level of this procedure, for "uplevel" * purposes (i.e. corresponds to nesting of * callerVarPtr's, not callerPtr's). 1 for * outermost procedure, 0 for top-level. */ Proc *procPtr; /* Points to the structure defining the * called procedure. Used to get information * such as the number of compiled local * variables (local variables assigned * entries ["slots"] in the compiledLocals * array below). */ Tcl_HashTable *varTablePtr; /* Hash table containing local variables not * recognized by the compiler, or created at * execution time through, e.g., upvar. * Initially NULL and created if needed. */ int numCompiledLocals; /* Count of local variables recognized by * the compiler including arguments. */ Var* compiledLocals; /* Points to the array of local variables * recognized by the compiler. The compiler * emits code that refers to these variables * using an index into this array. */ } CallFrame; #ifdef TCL_TIP280 /* * TIP #280 * The structure below defines a command frame. A command frame * provides location information for all commands executing a tcl * script (source, eval, uplevel, procedure bodies, ...). The runtime * structure essentially contains the stack trace as it would be if * the currently executing command were to throw an error. * * For commands where it makes sense it refers to the associated * CallFrame as well. * * The structures are chained in a single list, with the top of the * stack anchored in the Interp structure. * * Instances can be allocated on the C stack, or the heap, the former * making cleanup a bit simpler. */ typedef struct CmdFrame { /* General data. Always available. */ int type; /* Values see below */ int level; /* #Frames in stack, prevent O(n) scan of list */ int* line; /* Lines the words of the command start on */ int nline; CallFrame* framePtr; /* Procedure activation record, may be NULL */ struct CmdFrame* nextPtr; /* Link to calling frame */ /* Data needed for Eval vs TEBC * * EXECUTION CONTEXTS and usage of CmdFrame * * Field TEBC EvalEx EvalObjEx * ======= ==== ====== ========= * level yes yes yes * type BC/PREBC SRC/EVAL EVAL_LIST * line0 yes yes yes * framePtr yes yes yes * ======= ==== ====== ========= * * ======= ==== ====== ========= union data * line1 - yes - * line3 - yes - * path - yes - * ------- ---- ------ --------- * codePtr yes - - * pc yes - - * ======= ==== ====== ========= * * ======= ==== ====== ========= | union cmd * listPtr - - yes | * ------- ---- ------ --------- | * cmd yes yes - | * cmdlen yes yes - | * ------- ---- ------ --------- | */ union { struct { Tcl_Obj* path; /* Path of the sourced file the command * is in. */ } eval; struct { CONST void* codePtr; /* Byte code currently executed */ CONST char* pc; /* and instruction pointer. */ } tebc; } data; union { struct { CONST char* cmd; /* The executed command, if possible */ int len; /* And its length */ } str; Tcl_Obj* listPtr; /* Tcl_EvalObjEx, cmd list */ } cmd; } CmdFrame; /* The following macros define the allowed values for the type field * of the CmdFrame structure above. Some of the values occur only in * the extended location data referenced via the 'baseLocPtr'. * * TCL_LOCATION_EVAL : Frame is for a script evaluated by EvalEx. * TCL_LOCATION_EVAL_LIST : Frame is for a script evaluated by the list * optimization path of EvalObjEx. * TCL_LOCATION_BC : Frame is for bytecode. * TCL_LOCATION_PREBC : Frame is for precompiled bytecode. * TCL_LOCATION_SOURCE : Frame is for a script evaluated by EvalEx, * from a sourced file. * TCL_LOCATION_PROC : Frame is for bytecode of a procedure. * * A TCL_LOCATION_BC type in a frame can be overridden by _SOURCE and * _PROC types, per the context of the byte code in execution. */ #define TCL_LOCATION_EVAL (0) /* Location in a dynamic eval script */ #define TCL_LOCATION_EVAL_LIST (1) /* Location in a dynamic eval script, list-path */ #define TCL_LOCATION_BC (2) /* Location in byte code */ #define TCL_LOCATION_PREBC (3) /* Location in precompiled byte code, no location */ #define TCL_LOCATION_SOURCE (4) /* Location in a file */ #define TCL_LOCATION_PROC (5) /* Location in a dynamic proc */ #define TCL_LOCATION_LAST (6) /* Number of values in the enum */ typedef struct CFWord { CmdFrame* framePtr; /* CmdFrame to acess */ int word; /* Index of the word in the command */ int refCount; /* #times the word is on the stack */ } CFWord; typedef struct CFWordBC { CmdFrame* framePtr; /* CmdFrame to acess */ int pc; /* Instruction pointer of a command in ExtCmdLoc.loc[.] */ int word; /* Index of word in ExtCmdLoc.loc[cmd]->{line,literal}[.] */ struct CFWordBC* prevPtr; } CFWordBC; /* * Structure to record the locations of invisible continuation lines in * literal scripts, as character offset from the beginning of the script. Both * compiler and direct evaluator use this information to adjust their line * counters when tracking through the script, because when it is invoked the * continuation line marker as a whole has been removed already, meaning that * the \n which was part of it is gone as well, breaking regular line * tracking. * * These structures are allocated and filled by both the function * EvalTokensStandard() in the file "tclBasic.c" and its caller EvalEx(), and * stored in the thread-global hashtable "lineCLPtr" in file "tclObj.c". They * are used by the functions TclSetByteCodeFromAny() and TclCompileScript(), * both found in the file "tclCompile.c". Their memory is released by the * function TclFreeObj(), in the file "tclObj.c", and also by the function * TclThreadFinalizeObjects(), in the same file. */ #define CLL_END (-1) typedef struct ContLineLoc { int num; /* Number of entries in loc, not counting the final -1 * marker entry */ int loc[1]; /* Table of locations, as character offsets. The table is * allocated as part of the structure, i.e. the loc array * extends behind the nominal end of the structure. An entry * containing the value CLL_END is put after the last * location, as end-marker/sentinel. */ } ContLineLoc; #endif /* TCL_TIP280 */ /* *---------------------------------------------------------------- * Data structures and procedures related to TclHandles, which * are a very lightweight method of preserving enough information * to determine if an arbitrary malloc'd block has been deleted. *---------------------------------------------------------------- */ typedef VOID **TclHandle; /* *---------------------------------------------------------------- * Data structures related to expressions. These are used only in * tclExpr.c. *---------------------------------------------------------------- */ /* * The data structure below defines a math function (e.g. sin or hypot) * for use in Tcl expressions. */ #define MAX_MATH_ARGS 5 typedef struct MathFunc { int builtinFuncIndex; /* If this is a builtin math function, its * index in the array of builtin functions. * (tclCompilation.h lists these indices.) * The value is -1 if this is a new function * defined by Tcl_CreateMathFunc. The value * is also -1 if a builtin function is * replaced by a Tcl_CreateMathFunc call. */ int numArgs; /* Number of arguments for function. */ Tcl_ValueType argTypes[MAX_MATH_ARGS]; /* Acceptable types for each argument. */ Tcl_MathProc *proc; /* Procedure that implements this function. * NULL if isBuiltinFunc is 1. */ ClientData clientData; /* Additional argument to pass to the * function when invoking it. NULL if * isBuiltinFunc is 1. */ } MathFunc; /* * These are a thin layer over TclpThreadKeyDataGet and TclpThreadKeyDataSet * when threads are used, or an emulation if there are no threads. These * are really internal and Tcl clients should use Tcl_GetThreadData. */ EXTERN VOID *TclThreadDataKeyGet _ANSI_ARGS_((Tcl_ThreadDataKey *keyPtr)); EXTERN void TclThreadDataKeySet _ANSI_ARGS_((Tcl_ThreadDataKey *keyPtr, VOID *data)); /* * This is a convenience macro used to initialize a thread local storage ptr. */ #define TCL_TSD_INIT(keyPtr) (ThreadSpecificData *)Tcl_GetThreadData((keyPtr), sizeof(ThreadSpecificData)) /* *---------------------------------------------------------------- * Data structures related to bytecode compilation and execution. * These are used primarily in tclCompile.c, tclExecute.c, and * tclBasic.c. *---------------------------------------------------------------- */ /* * Forward declaration to prevent errors when the forward references to * Tcl_Parse and CompileEnv are encountered in the procedure type * CompileProc declared below. */ struct CompileEnv; /* * The type of procedures called by the Tcl bytecode compiler to compile * commands. Pointers to these procedures are kept in the Command structure * describing each command. When a CompileProc returns, the interpreter's * result is set to error information, if any. In addition, the CompileProc * returns an integer value, which is one of the following: * * TCL_OK Compilation completed normally. * TCL_ERROR Compilation failed because of an error; * the interpreter's result describes what went wrong. * TCL_OUT_LINE_COMPILE Compilation failed because, e.g., the command is * too complex for effective inline compilation. The * CompileProc believes the command is legal but * should be compiled "out of line" by emitting code * to invoke its command procedure at runtime. */ #define TCL_OUT_LINE_COMPILE (TCL_CONTINUE + 1) typedef int (CompileProc) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Parse *parsePtr, struct CompileEnv *compEnvPtr)); /* * The type of procedure called from the compilation hook point in * SetByteCodeFromAny. */ typedef int (CompileHookProc) _ANSI_ARGS_((Tcl_Interp *interp, struct CompileEnv *compEnvPtr, ClientData clientData)); /* * The data structure defining the execution environment for ByteCode's. * There is one ExecEnv structure per Tcl interpreter. It holds the * evaluation stack that holds command operands and results. The stack grows * towards increasing addresses. The "stackTop" member is cached by * TclExecuteByteCode in a local variable: it must be set before calling * TclExecuteByteCode and will be restored by TclExecuteByteCode before it * returns. */ typedef struct ExecEnv { Tcl_Obj **stackPtr; /* Points to the first item in the * evaluation stack on the heap. */ int stackTop; /* Index of current top of stack; -1 when * the stack is empty. */ int stackEnd; /* Index of last usable item in stack. */ Tcl_Obj *errorInfo; Tcl_Obj *errorCode; } ExecEnv; /* * The definitions for the LiteralTable and LiteralEntry structures. Each * interpreter contains a LiteralTable. It is used to reduce the storage * needed for all the Tcl objects that hold the literals of scripts compiled * by the interpreter. A literal's object is shared by all the ByteCodes * that refer to the literal. Each distinct literal has one LiteralEntry * entry in the LiteralTable. A literal table is a specialized hash table * that is indexed by the literal's string representation, which may contain * null characters. * * Note that we reduce the space needed for literals by sharing literal * objects both within a ByteCode (each ByteCode contains a local * LiteralTable) and across all an interpreter's ByteCodes (with the * interpreter's global LiteralTable). */ typedef struct LiteralEntry { struct LiteralEntry *nextPtr; /* Points to next entry in this * hash bucket or NULL if end of * chain. */ Tcl_Obj *objPtr; /* Points to Tcl object that * holds the literal's bytes and * length. */ int refCount; /* If in an interpreter's global * literal table, the number of * ByteCode structures that share * the literal object; the literal * entry can be freed when refCount * drops to 0. If in a local literal * table, -1. */ } LiteralEntry; typedef struct LiteralTable { LiteralEntry **buckets; /* Pointer to bucket array. Each * element points to first entry in * bucket's hash chain, or NULL. */ LiteralEntry *staticBuckets[TCL_SMALL_HASH_TABLE]; /* Bucket array used for small * tables to avoid mallocs and * frees. */ int numBuckets; /* Total number of buckets allocated * at **buckets. */ int numEntries; /* Total number of entries present * in table. */ int rebuildSize; /* Enlarge table when numEntries * gets to be this large. */ int mask; /* Mask value used in hashing * function. */ } LiteralTable; /* * The following structure defines for each Tcl interpreter various * statistics-related information about the bytecode compiler and * interpreter's operation in that interpreter. */ #ifdef TCL_COMPILE_STATS typedef struct ByteCodeStats { long numExecutions; /* Number of ByteCodes executed. */ long numCompilations; /* Number of ByteCodes created. */ long numByteCodesFreed; /* Number of ByteCodes destroyed. */ long instructionCount[256]; /* Number of times each instruction was * executed. */ double totalSrcBytes; /* Total source bytes ever compiled. */ double totalByteCodeBytes; /* Total bytes for all ByteCodes. */ double currentSrcBytes; /* Src bytes for all current ByteCodes. */ double currentByteCodeBytes; /* Code bytes in all current ByteCodes. */ long srcCount[32]; /* Source size distribution: # of srcs of * size [2**(n-1)..2**n), n in [0..32). */ long byteCodeCount[32]; /* ByteCode size distribution. */ long lifetimeCount[32]; /* ByteCode lifetime distribution (ms). */ double currentInstBytes; /* Instruction bytes-current ByteCodes. */ double currentLitBytes; /* Current literal bytes. */ double currentExceptBytes; /* Current exception table bytes. */ double currentAuxBytes; /* Current auxiliary information bytes. */ double currentCmdMapBytes; /* Current src<->code map bytes. */ long numLiteralsCreated; /* Total literal objects ever compiled. */ double totalLitStringBytes; /* Total string bytes in all literals. */ double currentLitStringBytes; /* String bytes in current literals. */ long literalCount[32]; /* Distribution of literal string sizes. */ } ByteCodeStats; #endif /* TCL_COMPILE_STATS */ /* *---------------------------------------------------------------- * Data structures related to commands. *---------------------------------------------------------------- */ /* * An imported command is created in an namespace when it imports a "real" * command from another namespace. An imported command has a Command * structure that points (via its ClientData value) to the "real" Command * structure in the source namespace's command table. The real command * records all the imported commands that refer to it in a list of ImportRef * structures so that they can be deleted when the real command is deleted. */ typedef struct ImportRef { struct Command *importedCmdPtr; /* Points to the imported command created in * an importing namespace; this command * redirects its invocations to the "real" * command. */ struct ImportRef *nextPtr; /* Next element on the linked list of * imported commands that refer to the * "real" command. The real command deletes * these imported commands on this list when * it is deleted. */ } ImportRef; /* * Data structure used as the ClientData of imported commands: commands * created in an namespace when it imports a "real" command from another * namespace. */ typedef struct ImportedCmdData { struct Command *realCmdPtr; /* "Real" command that this imported command * refers to. */ struct Command *selfPtr; /* Pointer to this imported command. Needed * only when deleting it in order to remove * it from the real command's linked list of * imported commands that refer to it. */ } ImportedCmdData; /* * A Command structure exists for each command in a namespace. The * Tcl_Command opaque type actually refers to these structures. */ typedef struct Command { Tcl_HashEntry *hPtr; /* Pointer to the hash table entry that * refers to this command. The hash table is * either a namespace's command table or an * interpreter's hidden command table. This * pointer is used to get a command's name * from its Tcl_Command handle. NULL means * that the hash table entry has been * removed already (this can happen if * deleteProc causes the command to be * deleted or recreated). */ Namespace *nsPtr; /* Points to the namespace containing this * command. */ int refCount; /* 1 if in command hashtable plus 1 for each * reference from a CmdName Tcl object * representing a command's name in a * ByteCode instruction sequence. This * structure can be freed when refCount * becomes zero. */ int cmdEpoch; /* Incremented to invalidate any references * that point to this command when it is * renamed, deleted, hidden, or exposed. */ CompileProc *compileProc; /* Procedure called to compile command. NULL * if no compile proc exists for command. */ Tcl_ObjCmdProc *objProc; /* Object-based command procedure. */ ClientData objClientData; /* Arbitrary value passed to object proc. */ Tcl_CmdProc *proc; /* String-based command procedure. */ ClientData clientData; /* Arbitrary value passed to string proc. */ Tcl_CmdDeleteProc *deleteProc; /* Procedure invoked when deleting command * to, e.g., free all client data. */ ClientData deleteData; /* Arbitrary value passed to deleteProc. */ int flags; /* Miscellaneous bits of information about * command. See below for definitions. */ ImportRef *importRefPtr; /* List of each imported Command created in * another namespace when this command is * imported. These imported commands * redirect invocations back to this * command. The list is used to remove all * those imported commands when deleting * this "real" command. */ CommandTrace *tracePtr; /* First in list of all traces set for this * command. */ } Command; /* * Flag bits for commands. * * CMD_IS_DELETED - Means that the command is in the process * of being deleted (its deleteProc is * currently executing). Other attempts to * delete the command should be ignored. * CMD_TRACE_ACTIVE - 1 means that trace processing is currently * underway for a rename/delete change. * See the two flags below for which is * currently being processed. * CMD_HAS_EXEC_TRACES - 1 means that this command has at least * one execution trace (as opposed to simple * delete/rename traces) in its tracePtr list. * TCL_TRACE_RENAME - A rename trace is in progress. Further * recursive renames will not be traced. * TCL_TRACE_DELETE - A delete trace is in progress. Further * recursive deletes will not be traced. * (these last two flags are defined in tcl.h) */ #define CMD_IS_DELETED 0x1 #define CMD_TRACE_ACTIVE 0x2 #define CMD_HAS_EXEC_TRACES 0x4 /* *---------------------------------------------------------------- * Data structures related to name resolution procedures. *---------------------------------------------------------------- */ /* * The interpreter keeps a linked list of name resolution schemes. * The scheme for a namespace is consulted first, followed by the * list of schemes in an interpreter, followed by the default * name resolution in Tcl. Schemes are added/removed from the * interpreter's list by calling Tcl_AddInterpResolver and * Tcl_RemoveInterpResolver. */ typedef struct ResolverScheme { char *name; /* Name identifying this scheme. */ Tcl_ResolveCmdProc *cmdResProc; /* Procedure handling command name * resolution. */ Tcl_ResolveVarProc *varResProc; /* Procedure handling variable name * resolution for variables that * can only be handled at runtime. */ Tcl_ResolveCompiledVarProc *compiledVarResProc; /* Procedure handling variable name * resolution at compile time. */ struct ResolverScheme *nextPtr; /* Pointer to next record in linked list. */ } ResolverScheme; #ifdef TCL_TIP268 /* * TIP #268. * Values for the selection mode, i.e the package require preferences. */ enum PkgPreferOptions { PKG_PREFER_LATEST, PKG_PREFER_STABLE }; #endif /* *---------------------------------------------------------------- * This structure defines an interpreter, which is a collection of * commands plus other state information related to interpreting * commands, such as variable storage. Primary responsibility for * this data structure is in tclBasic.c, but almost every Tcl * source file uses something in here. *---------------------------------------------------------------- */ typedef struct Interp { /* * Note: the first three fields must match exactly the fields in * a Tcl_Interp struct (see tcl.h). If you change one, be sure to * change the other. * * The interpreter's result is held in both the string and the * objResultPtr fields. These fields hold, respectively, the result's * string or object value. The interpreter's result is always in the * result field if that is non-empty, otherwise it is in objResultPtr. * The two fields are kept consistent unless some C code sets * interp->result directly. Programs should not access result and * objResultPtr directly; instead, they should always get and set the * result using procedures such as Tcl_SetObjResult, Tcl_GetObjResult, * and Tcl_GetStringResult. See the SetResult man page for details. */ char *result; /* If the last command returned a string * result, this points to it. Should not be * accessed directly; see comment above. */ Tcl_FreeProc *freeProc; /* Zero means a string result is statically * allocated. TCL_DYNAMIC means string * result was allocated with ckalloc and * should be freed with ckfree. Other values * give address of procedure to invoke to * free the string result. Tcl_Eval must * free it before executing next command. */ int errorLine; /* When TCL_ERROR is returned, this gives * the line number in the command where the * error occurred (1 means first line). */ struct TclStubs *stubTable; /* Pointer to the exported Tcl stub table. * On previous versions of Tcl this is a * pointer to the objResultPtr or a pointer * to a buckets array in a hash table. We * therefore have to do some careful checking * before we can use this. */ TclHandle handle; /* Handle used to keep track of when this * interp is deleted. */ Namespace *globalNsPtr; /* The interpreter's global namespace. */ Tcl_HashTable *hiddenCmdTablePtr; /* Hash table used by tclBasic.c to keep * track of hidden commands on a per-interp * basis. */ ClientData interpInfo; /* Information used by tclInterp.c to keep * track of master/slave interps on * a per-interp basis. */ Tcl_HashTable mathFuncTable;/* Contains all the math functions currently * defined for the interpreter. Indexed by * strings (function names); values have * type (MathFunc *). */ /* * Information related to procedures and variables. See tclProc.c * and tclVar.c for usage. */ int numLevels; /* Keeps track of how many nested calls to * Tcl_Eval are in progress for this * interpreter. It's used to delay deletion * of the table until all Tcl_Eval * invocations are completed. */ int maxNestingDepth; /* If numLevels exceeds this value then Tcl * assumes that infinite recursion has * occurred and it generates an error. */ CallFrame *framePtr; /* Points to top-most in stack of all nested * procedure invocations. NULL means there * are no active procedures. */ CallFrame *varFramePtr; /* Points to the call frame whose variables * are currently in use (same as framePtr * unless an "uplevel" command is * executing). NULL means no procedure is * active or "uplevel 0" is executing. */ ActiveVarTrace *activeVarTracePtr; /* First in list of active traces for * interp, or NULL if no active traces. */ int returnCode; /* Completion code to return if current * procedure exits with TCL_RETURN code. */ char *errorInfo; /* Value to store in errorInfo if returnCode * is TCL_ERROR. Malloc'ed, may be NULL */ char *errorCode; /* Value to store in errorCode if returnCode * is TCL_ERROR. Malloc'ed, may be NULL */ /* * Information used by Tcl_AppendResult to keep track of partial * results. See Tcl_AppendResult code for details. */ char *appendResult; /* Storage space for results generated * by Tcl_AppendResult. Malloc-ed. NULL * means not yet allocated. */ int appendAvl; /* Total amount of space available at * partialResult. */ int appendUsed; /* Number of non-null bytes currently * stored at partialResult. */ /* * Information about packages. Used only in tclPkg.c. */ Tcl_HashTable packageTable; /* Describes all of the packages loaded * in or available to this interpreter. * Keys are package names, values are * (Package *) pointers. */ char *packageUnknown; /* Command to invoke during "package * require" commands for packages that * aren't described in packageTable. * Malloc'ed, may be NULL. */ /* * Miscellaneous information: */ int cmdCount; /* Total number of times a command procedure * has been called for this interpreter. */ int evalFlags; /* Flags to control next call to Tcl_Eval. * Normally zero, but may be set before * calling Tcl_Eval. See below for valid * values. */ int termOffset; /* Offset of character just after last one * compiled or executed by Tcl_EvalObj. */ LiteralTable literalTable; /* Contains LiteralEntry's describing all * Tcl objects holding literals of scripts * compiled by the interpreter. Indexed by * the string representations of literals. * Used to avoid creating duplicate * objects. */ int compileEpoch; /* Holds the current "compilation epoch" * for this interpreter. This is * incremented to invalidate existing * ByteCodes when, e.g., a command with a * compile procedure is redefined. */ Proc *compiledProcPtr; /* If a procedure is being compiled, a * pointer to its Proc structure; otherwise, * this is NULL. Set by ObjInterpProc in * tclProc.c and used by tclCompile.c to * process local variables appropriately. */ ResolverScheme *resolverPtr; /* Linked list of name resolution schemes * added to this interpreter. Schemes * are added/removed by calling * Tcl_AddInterpResolvers and * Tcl_RemoveInterpResolver. */ Tcl_Obj *scriptFile; /* NULL means there is no nested source * command active; otherwise this points to * pathPtr of the file being sourced. */ int flags; /* Various flag bits. See below. */ long randSeed; /* Seed used for rand() function. */ Trace *tracePtr; /* List of traces for this interpreter. */ Tcl_HashTable *assocData; /* Hash table for associating data with * this interpreter. Cleaned up when * this interpreter is deleted. */ struct ExecEnv *execEnvPtr; /* Execution environment for Tcl bytecode * execution. Contains a pointer to the * Tcl evaluation stack. */ Tcl_Obj *emptyObjPtr; /* Points to an object holding an empty * string. Returned by Tcl_ObjSetVar2 when * variable traces change a variable in a * gross way. */ char resultSpace[TCL_RESULT_SIZE+1]; /* Static space holding small results. */ Tcl_Obj *objResultPtr; /* If the last command returned an object * result, this points to it. Should not be * accessed directly; see comment above. */ Tcl_ThreadId threadId; /* ID of thread that owns the interpreter */ ActiveCommandTrace *activeCmdTracePtr; /* First in list of active command traces for * interp, or NULL if no active traces. */ ActiveInterpTrace *activeInterpTracePtr; /* First in list of active traces for * interp, or NULL if no active traces. */ int tracesForbiddingInline; /* Count of traces (in the list headed by * tracePtr) that forbid inline bytecode * compilation */ #ifdef TCL_TIP280 /* TIP #280 */ CmdFrame* cmdFramePtr; /* Points to the command frame containing * the location information for the current * command. */ CONST CmdFrame* invokeCmdFramePtr; /* Points to the command frame which is the * invoking context of the bytecode compiler. * NULL when the byte code compiler is not * active */ int invokeWord; /* Index of the word in the command which * is getting compiled. */ Tcl_HashTable* linePBodyPtr; /* This table remembers for each * statically defined procedure the * location information for its * body. It is keyed by the address of * the Proc structure for a procedure. * The values are "struct CmdFrame*". */ Tcl_HashTable* lineBCPtr; /* This table remembers for each * ByteCode object the location * information for its body. It is * keyed by the address of the Proc * structure for a procedure. The * values are "struct ExtCmdLoc*" (See * tclCompile.h). */ Tcl_HashTable* lineLABCPtr; Tcl_HashTable* lineLAPtr; /* This table remembers for each * argument of a command on the * execution stack the index of the * argument in the command, and the * location data of the command. It is * keyed by the address of the Tcl_Obj * containing the argument. The values * are "struct CFWord*" (See * tclBasic.c). This allows commands * like uplevel, eval, etc. to find * location information for their * arguments, if they are a proper * literal argument to an invoking * command. Alt view: An index to the * CmdFrame stack keyed by command * argument holders. */ ContLineLoc* scriptCLLocPtr; /* This table points to the location data for * invisible continuation lines in the script, * if any. This pointer is set by the function * TclEvalObjEx() in file "tclBasic.c", and * used by function ...() in the same file. * It does for the eval/direct path of script * execution what CompileEnv.clLoc does for * the bytecode compiler. */ #endif #ifdef TCL_TIP268 /* * TIP #268. * The currently active selection mode, * i.e the package require preferences. */ int packagePrefer; /* Current package selection mode. */ #endif /* * Statistical information about the bytecode compiler and interpreter's * operation. */ #ifdef TCL_COMPILE_STATS ByteCodeStats stats; /* Holds compilation and execution * statistics for this interpreter. */ #endif /* TCL_COMPILE_STATS */ } Interp; /* * EvalFlag bits for Interp structures: * * TCL_BRACKET_TERM 1 means that the current script is terminated by * a close bracket rather than the end of the string. * TCL_ALLOW_EXCEPTIONS 1 means it's OK for the script to terminate with * a code other than TCL_OK or TCL_ERROR; 0 means * codes other than these should be turned into errors. */ #define TCL_BRACKET_TERM 1 #define TCL_ALLOW_EXCEPTIONS 4 #ifdef TCL_TIP280 #define TCL_EVAL_FILE 2 #define TCL_EVAL_CTX 8 #endif /* * Flag bits for Interp structures: * * DELETED: Non-zero means the interpreter has been deleted: * don't process any more commands for it, and destroy * the structure as soon as all nested invocations of * Tcl_Eval are done. * ERR_IN_PROGRESS: Non-zero means an error unwind is already in * progress. Zero means a command proc has been * invoked since last error occured. * ERR_ALREADY_LOGGED: Non-zero means information has already been logged * in $errorInfo for the current Tcl_Eval instance, * so Tcl_Eval needn't log it (used to implement the * "error message log" command). * ERROR_CODE_SET: Non-zero means that Tcl_SetErrorCode has been * called to record information for the current * error. Zero means Tcl_Eval must clear the * errorCode variable if an error is returned. * EXPR_INITIALIZED: Non-zero means initialization specific to * expressions has been carried out. * DONT_COMPILE_CMDS_INLINE: Non-zero means that the bytecode compiler * should not compile any commands into an inline * sequence of instructions. This is set 1, for * example, when command traces are requested. * RAND_SEED_INITIALIZED: Non-zero means that the randSeed value of the * interp has not be initialized. This is set 1 * when we first use the rand() or srand() functions. * SAFE_INTERP: Non zero means that the current interp is a * safe interp (ie it has only the safe commands * installed, less priviledge than a regular interp). * USE_EVAL_DIRECT: Non-zero means don't use the compiler or byte-code * interpreter; instead, have Tcl_EvalObj call * Tcl_EvalEx. Used primarily for testing the * new parser. * INTERP_TRACE_IN_PROGRESS: Non-zero means that an interp trace is currently * active; so no further trace callbacks should be * invoked. */ #define DELETED 1 #define ERR_IN_PROGRESS 2 #define ERR_ALREADY_LOGGED 4 #define ERROR_CODE_SET 8 #define EXPR_INITIALIZED 0x10 #define DONT_COMPILE_CMDS_INLINE 0x20 #define RAND_SEED_INITIALIZED 0x40 #define SAFE_INTERP 0x80 #define USE_EVAL_DIRECT 0x100 #define INTERP_TRACE_IN_PROGRESS 0x200 /* * Maximum number of levels of nesting permitted in Tcl commands (used * to catch infinite recursion). */ #define MAX_NESTING_DEPTH 1000 /* * The macro below is used to modify a "char" value (e.g. by casting * it to an unsigned character) so that it can be used safely with * macros such as isspace. */ #define UCHAR(c) ((unsigned char) (c)) /* * This macro is used to determine the offset needed to safely allocate any * data structure in memory. Given a starting offset or size, it "rounds up" * or "aligns" the offset to the next 8-byte boundary so that any data * structure can be placed at the resulting offset without fear of an * alignment error. * * WARNING!! DO NOT USE THIS MACRO TO ALIGN POINTERS: it will produce * the wrong result on platforms that allocate addresses that are divisible * by 4 or 2. Only use it for offsets or sizes. */ #define TCL_ALIGN(x) (((int)(x) + 7) & ~7) /* * The following enum values are used to specify the runtime platform * setting of the tclPlatform variable. */ typedef enum { TCL_PLATFORM_UNIX, /* Any Unix-like OS. */ TCL_PLATFORM_WINDOWS=2 /* Any Microsoft Windows OS. */ } TclPlatformType; /* * The following enum values are used to indicate the translation * of a Tcl channel. Declared here so that each platform can define * TCL_PLATFORM_TRANSLATION to the native translation on that platform */ typedef enum TclEolTranslation { TCL_TRANSLATE_AUTO, /* Eol == \r, \n and \r\n. */ TCL_TRANSLATE_CR, /* Eol == \r. */ TCL_TRANSLATE_LF, /* Eol == \n. */ TCL_TRANSLATE_CRLF /* Eol == \r\n. */ } TclEolTranslation; /* * Flags for TclInvoke: * * TCL_INVOKE_HIDDEN Invoke a hidden command; if not set, * invokes an exposed command. * TCL_INVOKE_NO_UNKNOWN If set, "unknown" is not invoked if * the command to be invoked is not found. * Only has an effect if invoking an exposed * command, i.e. if TCL_INVOKE_HIDDEN is not * also set. * TCL_INVOKE_NO_TRACEBACK Does not record traceback information if * the invoked command returns an error. Used * if the caller plans on recording its own * traceback information. */ #define TCL_INVOKE_HIDDEN (1<<0) #define TCL_INVOKE_NO_UNKNOWN (1<<1) #define TCL_INVOKE_NO_TRACEBACK (1<<2) /* * The structure used as the internal representation of Tcl list * objects. This is an array of pointers to the element objects. This array * is grown (reallocated and copied) as necessary to hold all the list's * element pointers. The array might contain more slots than currently used * to hold all element pointers. This is done to make append operations * faster. */ typedef struct List { int maxElemCount; /* Total number of element array slots. */ int elemCount; /* Current number of list elements. */ Tcl_Obj **elements; /* Array of pointers to element objects. */ } List; /* * The following types are used for getting and storing platform-specific * file attributes in tclFCmd.c and the various platform-versions of * that file. This is done to have as much common code as possible * in the file attributes code. For more information about the callbacks, * see TclFileAttrsCmd in tclFCmd.c. */ typedef int (TclGetFileAttrProc) _ANSI_ARGS_((Tcl_Interp *interp, int objIndex, Tcl_Obj *fileName, Tcl_Obj **attrObjPtrPtr)); typedef int (TclSetFileAttrProc) _ANSI_ARGS_((Tcl_Interp *interp, int objIndex, Tcl_Obj *fileName, Tcl_Obj *attrObjPtr)); typedef struct TclFileAttrProcs { TclGetFileAttrProc *getProc; /* The procedure for getting attrs. */ TclSetFileAttrProc *setProc; /* The procedure for setting attrs. */ } TclFileAttrProcs; /* * Opaque handle used in pipeline routines to encapsulate platform-dependent * state. */ typedef struct TclFile_ *TclFile; /* * Opaque names for platform specific types. */ typedef struct TclpTime_t_ *TclpTime_t; typedef struct TclpTime_t_ *CONST TclpTime_t_CONST; /* * The "globParameters" argument of the function TclGlob is an * or'ed combination of the following values: */ #define TCL_GLOBMODE_NO_COMPLAIN 1 #define TCL_GLOBMODE_JOIN 2 #define TCL_GLOBMODE_DIR 4 #define TCL_GLOBMODE_TAILS 8 /* *---------------------------------------------------------------- * Data structures related to obsolete filesystem hooks *---------------------------------------------------------------- */ typedef int (TclStatProc_) _ANSI_ARGS_((CONST char *path, Tcl_StatBuf *buf)); typedef int (TclAccessProc_) _ANSI_ARGS_((CONST char *path, int mode)); typedef Tcl_Channel (TclOpenFileChannelProc_) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *fileName, CONST char *modeString, int permissions)); /* *---------------------------------------------------------------- * Data structures related to procedures *---------------------------------------------------------------- */ typedef Tcl_CmdProc *TclCmdProcType; typedef Tcl_ObjCmdProc *TclObjCmdProcType; /* *---------------------------------------------------------------- * Variables shared among Tcl modules but not used by the outside world. *---------------------------------------------------------------- */ extern Tcl_Time tclBlockTime; extern int tclBlockTimeSet; extern char * tclExecutableName; extern char * tclNativeExecutableName; extern char * tclDefaultEncodingDir; extern Tcl_ChannelType tclFileChannelType; extern char * tclMemDumpFileName; extern TclPlatformType tclPlatform; extern Tcl_NotifierProcs tclOriginalNotifier; /* * Variables denoting the Tcl object types defined in the core. */ extern Tcl_ObjType tclBooleanType; extern Tcl_ObjType tclByteArrayType; extern Tcl_ObjType tclByteCodeType; extern Tcl_ObjType tclDoubleType; extern Tcl_ObjType tclEndOffsetType; extern Tcl_ObjType tclIntType; extern Tcl_ObjType tclListType; extern Tcl_ObjType tclProcBodyType; extern Tcl_ObjType tclStringType; extern Tcl_ObjType tclArraySearchType; extern Tcl_ObjType tclIndexType; extern Tcl_ObjType tclNsNameType; extern Tcl_ObjType tclWideIntType; /* * Variables denoting the hash key types defined in the core. */ extern Tcl_HashKeyType tclArrayHashKeyType; extern Tcl_HashKeyType tclOneWordHashKeyType; extern Tcl_HashKeyType tclStringHashKeyType; extern Tcl_HashKeyType tclObjHashKeyType; /* * The head of the list of free Tcl objects, and the total number of Tcl * objects ever allocated and freed. */ extern Tcl_Obj * tclFreeObjList; #ifdef TCL_COMPILE_STATS extern long tclObjsAlloced; extern long tclObjsFreed; #define TCL_MAX_SHARED_OBJ_STATS 5 extern long tclObjsShared[TCL_MAX_SHARED_OBJ_STATS]; #endif /* TCL_COMPILE_STATS */ /* * Pointer to a heap-allocated string of length zero that the Tcl core uses * as the value of an empty string representation for an object. This value * is shared by all new objects allocated by Tcl_NewObj. */ extern char * tclEmptyStringRep; extern char tclEmptyString; /* *---------------------------------------------------------------- * Procedures shared among Tcl modules but not used by the outside * world: *---------------------------------------------------------------- */ #ifdef TCL_TIP280 EXTERN void TclAdvanceLines _ANSI_ARGS_((int* line, CONST char* start, CONST char* end)); EXTERN void TclAdvanceContinuations _ANSI_ARGS_((int* line, int** next, int loc)); EXTERN ContLineLoc* TclContinuationsEnter _ANSI_ARGS_((Tcl_Obj* objPtr, int num, int* loc)); EXTERN void TclContinuationsEnterDerived _ANSI_ARGS_((Tcl_Obj* objPtr, int start, int* clNext)); EXTERN ContLineLoc* TclContinuationsGet _ANSI_ARGS_((Tcl_Obj* objPtr)); EXTERN void TclContinuationsCopy _ANSI_ARGS_((Tcl_Obj* objPtr, Tcl_Obj* originObjPtr)); #endif EXTERN int TclArraySet _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *arrayNameObj, Tcl_Obj *arrayElemObj)); EXTERN int TclCheckBadOctal _ANSI_ARGS_((Tcl_Interp *interp, CONST char *value)); EXTERN void TclDeleteNamespaceVars _ANSI_ARGS_((Namespace *nsPtr)); #ifdef TCL_TIP280 EXTERN int TclEvalObjEx _ANSI_ARGS_((Tcl_Interp *interp, register Tcl_Obj *objPtr, int flags, CONST CmdFrame* invoker, int word)); EXTERN void TclArgumentEnter _ANSI_ARGS_((Tcl_Interp* interp, Tcl_Obj* objv[], int objc, CmdFrame* cf)); EXTERN void TclArgumentRelease _ANSI_ARGS_((Tcl_Interp* interp, Tcl_Obj* objv[], int objc)); EXTERN void TclArgumentBCEnter _ANSI_ARGS_((Tcl_Interp* interp, Tcl_Obj* objv[], int objc, void* codePtr, CmdFrame* cfPtr, int pc)); EXTERN void TclArgumentBCRelease _ANSI_ARGS_((Tcl_Interp* interp, Tcl_Obj* objv[], int objc, void* codePtr, int pc)); EXTERN void TclArgumentGet _ANSI_ARGS_((Tcl_Interp* interp, Tcl_Obj* obj, CmdFrame** cfPtrPtr, int* wordPtr)); #endif EXTERN void TclExpandTokenArray _ANSI_ARGS_(( Tcl_Parse *parsePtr)); EXTERN int TclFileAttrsCmd _ANSI_ARGS_((Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int TclFileCopyCmd _ANSI_ARGS_((Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) ; EXTERN int TclFileDeleteCmd _ANSI_ARGS_((Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int TclFileMakeDirsCmd _ANSI_ARGS_((Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) ; EXTERN int TclFileRenameCmd _ANSI_ARGS_((Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])) ; EXTERN void TclCreateLateExitHandler (Tcl_ExitProc * proc, ClientData clientData); EXTERN void TclDeleteLateExitHandler (Tcl_ExitProc * proc, ClientData clientData); EXTERN void TclFinalizeAllocSubsystem _ANSI_ARGS_((void)); EXTERN void TclFinalizeAsync _ANSI_ARGS_((void)); EXTERN void TclFinalizeCompilation _ANSI_ARGS_((void)); EXTERN void TclFinalizeEncodingSubsystem _ANSI_ARGS_((void)); EXTERN void TclFinalizeEnvironment _ANSI_ARGS_((void)); EXTERN void TclFinalizeExecution _ANSI_ARGS_((void)); EXTERN void TclFinalizeIOSubsystem _ANSI_ARGS_((void)); EXTERN void TclFinalizeFilesystem _ANSI_ARGS_((void)); EXTERN void TclResetFilesystem _ANSI_ARGS_((void)); EXTERN void TclFinalizeLoad _ANSI_ARGS_((void)); EXTERN void TclFinalizeLock _ANSI_ARGS_((void)); EXTERN void TclFinalizeMemorySubsystem _ANSI_ARGS_((void)); EXTERN void TclFinalizeNotifier _ANSI_ARGS_((void)); EXTERN void TclFinalizeObjects _ANSI_ARGS_((void)); EXTERN void TclFinalizePreserve _ANSI_ARGS_((void)); EXTERN void TclFinalizeSynchronization _ANSI_ARGS_((void)); EXTERN void TclFinalizeThreadAlloc _ANSI_ARGS_((void)); EXTERN void TclFinalizeThreadData _ANSI_ARGS_((void)); EXTERN int TclGetEncodingFromObj _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Encoding *encodingPtr)); #ifdef TCL_TIP280 EXTERN void TclGetSrcInfoForPc _ANSI_ARGS_((CmdFrame* cfPtr)); #endif EXTERN int TclGlob _ANSI_ARGS_((Tcl_Interp *interp, char *pattern, Tcl_Obj *unquotedPrefix, int globFlags, Tcl_GlobTypeData* types)); EXTERN void TclInitAlloc _ANSI_ARGS_((void)); EXTERN void TclInitDbCkalloc _ANSI_ARGS_((void)); EXTERN void TclInitEncodingSubsystem _ANSI_ARGS_((void)); EXTERN void TclInitIOSubsystem _ANSI_ARGS_((void)); EXTERN void TclInitNamespaceSubsystem _ANSI_ARGS_((void)); EXTERN void TclInitNotifier _ANSI_ARGS_((void)); EXTERN void TclInitObjSubsystem _ANSI_ARGS_((void)); EXTERN void TclInitSubsystems _ANSI_ARGS_((CONST char *argv0)); EXTERN int TclIsLocalScalar _ANSI_ARGS_((CONST char *src, int len)); EXTERN int TclJoinThread _ANSI_ARGS_((Tcl_ThreadId id, int* result)); EXTERN Tcl_Obj * TclLindexList _ANSI_ARGS_((Tcl_Interp* interp, Tcl_Obj* listPtr, Tcl_Obj* argPtr )); EXTERN Tcl_Obj * TclLindexFlat _ANSI_ARGS_((Tcl_Interp* interp, Tcl_Obj* listPtr, int indexCount, Tcl_Obj *CONST indexArray[] )); EXTERN Tcl_Obj * TclLsetList _ANSI_ARGS_((Tcl_Interp* interp, Tcl_Obj* listPtr, Tcl_Obj* indexPtr, Tcl_Obj* valuePtr )); EXTERN Tcl_Obj * TclLsetFlat _ANSI_ARGS_((Tcl_Interp* interp, Tcl_Obj* listPtr, int indexCount, Tcl_Obj *CONST indexArray[], Tcl_Obj* valuePtr )); EXTERN int TclParseBackslash _ANSI_ARGS_((CONST char *src, int numBytes, int *readPtr, char *dst)); EXTERN int TclParseHex _ANSI_ARGS_((CONST char *src, int numBytes, Tcl_UniChar *resultPtr)); EXTERN int TclParseInteger _ANSI_ARGS_((CONST char *string, int numBytes)); EXTERN int TclParseWhiteSpace _ANSI_ARGS_((CONST char *src, int numBytes, Tcl_Parse *parsePtr, char *typePtr)); #ifdef TCL_TIP280 EXTERN int TclWordKnownAtCompileTime _ANSI_ARGS_((Tcl_Token* token)); #endif EXTERN int TclpObjAccess _ANSI_ARGS_((Tcl_Obj *filename, int mode)); EXTERN int TclpObjLstat _ANSI_ARGS_((Tcl_Obj *pathPtr, Tcl_StatBuf *buf)); EXTERN int TclpCheckStackSpace _ANSI_ARGS_((void)); EXTERN Tcl_Obj* TclpTempFileName _ANSI_ARGS_((void)); EXTERN Tcl_Obj* TclNewFSPathObj _ANSI_ARGS_((Tcl_Obj *dirPtr, CONST char *addStrRep, int len)); EXTERN int TclpDeleteFile _ANSI_ARGS_((CONST char *path)); EXTERN void TclpFinalizeCondition _ANSI_ARGS_(( Tcl_Condition *condPtr)); EXTERN void TclpFinalizeMutex _ANSI_ARGS_((Tcl_Mutex *mutexPtr)); EXTERN void TclpFinalizePipes _ANSI_ARGS_((void)); EXTERN void TclpFinalizeSockets _ANSI_ARGS_((void)); EXTERN void TclpFinalizeThreadData _ANSI_ARGS_(( Tcl_ThreadDataKey *keyPtr)); EXTERN void TclpFinalizeThreadDataKey _ANSI_ARGS_(( Tcl_ThreadDataKey *keyPtr)); EXTERN char * TclpFindExecutable _ANSI_ARGS_(( CONST char *argv0)); EXTERN int TclpFindVariable _ANSI_ARGS_((CONST char *name, int *lengthPtr)); EXTERN int TclpInitLibraryPath _ANSI_ARGS_((CONST char *argv0)); EXTERN void TclpInitLock _ANSI_ARGS_((void)); EXTERN void TclpInitPlatform _ANSI_ARGS_((void)); EXTERN void TclpInitUnlock _ANSI_ARGS_((void)); EXTERN int TclpLoadFile _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *pathPtr, CONST char *sym1, CONST char *sym2, Tcl_PackageInitProc **proc1Ptr, Tcl_PackageInitProc **proc2Ptr, ClientData *clientDataPtr, Tcl_FSUnloadFileProc **unloadProcPtr)); EXTERN Tcl_Obj* TclpObjListVolumes _ANSI_ARGS_((void)); EXTERN void TclpMasterLock _ANSI_ARGS_((void)); EXTERN void TclpMasterUnlock _ANSI_ARGS_((void)); EXTERN int TclpMatchFiles _ANSI_ARGS_((Tcl_Interp *interp, char *separators, Tcl_DString *dirPtr, char *pattern, char *tail)); EXTERN int TclpObjNormalizePath _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *pathPtr, int nextCheckpoint)); EXTERN int TclpObjCreateDirectory _ANSI_ARGS_((Tcl_Obj *pathPtr)); EXTERN void TclpNativeJoinPath _ANSI_ARGS_((Tcl_Obj *prefix, char *joining)); EXTERN Tcl_Obj* TclpNativeSplitPath _ANSI_ARGS_((Tcl_Obj *pathPtr, int *lenPtr)); EXTERN Tcl_PathType TclpGetNativePathType _ANSI_ARGS_((Tcl_Obj *pathObjPtr, int *driveNameLengthPtr, Tcl_Obj **driveNameRef)); EXTERN int TclCrossFilesystemCopy _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *source, Tcl_Obj *target)); EXTERN int TclpObjDeleteFile _ANSI_ARGS_((Tcl_Obj *pathPtr)); EXTERN int TclpObjCopyDirectory _ANSI_ARGS_((Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr, Tcl_Obj **errorPtr)); EXTERN int TclpObjCopyFile _ANSI_ARGS_((Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr)); EXTERN int TclpObjRemoveDirectory _ANSI_ARGS_((Tcl_Obj *pathPtr, int recursive, Tcl_Obj **errorPtr)); EXTERN int TclpObjRenameFile _ANSI_ARGS_((Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr)); EXTERN int TclpMatchInDirectory _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *resultPtr, Tcl_Obj *pathPtr, CONST char *pattern, Tcl_GlobTypeData *types)); EXTERN Tcl_Obj* TclpObjGetCwd _ANSI_ARGS_((Tcl_Interp *interp)); EXTERN Tcl_FSDupInternalRepProc TclNativeDupInternalRep; EXTERN Tcl_Obj* TclpObjLink _ANSI_ARGS_((Tcl_Obj *pathPtr, Tcl_Obj *toPtr, int linkType)); EXTERN int TclpObjChdir _ANSI_ARGS_((Tcl_Obj *pathPtr)); EXTERN Tcl_Obj* TclFileDirname _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj*pathPtr)); EXTERN int TclpObjStat _ANSI_ARGS_((Tcl_Obj *pathPtr, Tcl_StatBuf *buf)); EXTERN Tcl_Channel TclpOpenFileChannel _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *pathPtr, int mode, int permissions)); EXTERN void TclpPanic _ANSI_ARGS_(TCL_VARARGS(CONST char *, format)); EXTERN char * TclpReadlink _ANSI_ARGS_((CONST char *fileName, Tcl_DString *linkPtr)); EXTERN void TclpReleaseFile _ANSI_ARGS_((TclFile file)); EXTERN void TclpSetVariables _ANSI_ARGS_((Tcl_Interp *interp)); EXTERN void TclpUnloadFile _ANSI_ARGS_((Tcl_LoadHandle loadHandle)); EXTERN VOID * TclpThreadDataKeyGet _ANSI_ARGS_(( Tcl_ThreadDataKey *keyPtr)); EXTERN void TclpThreadDataKeyInit _ANSI_ARGS_(( Tcl_ThreadDataKey *keyPtr)); EXTERN void TclpThreadDataKeySet _ANSI_ARGS_(( Tcl_ThreadDataKey *keyPtr, VOID *data)); EXTERN int TclpThreadCreate _ANSI_ARGS_(( Tcl_ThreadId *idPtr, Tcl_ThreadCreateProc proc, ClientData clientData, int stackSize, int flags)); EXTERN void TclpThreadExit _ANSI_ARGS_((int status)); EXTERN void TclRememberCondition _ANSI_ARGS_((Tcl_Condition *mutex)); EXTERN void TclRememberDataKey _ANSI_ARGS_((Tcl_ThreadDataKey *mutex)); EXTERN VOID TclRememberJoinableThread _ANSI_ARGS_((Tcl_ThreadId id)); EXTERN void TclRememberMutex _ANSI_ARGS_((Tcl_Mutex *mutex)); EXTERN VOID TclSignalExitThread _ANSI_ARGS_((Tcl_ThreadId id, int result)); EXTERN void TclTransferResult _ANSI_ARGS_((Tcl_Interp *sourceInterp, int result, Tcl_Interp *targetInterp)); EXTERN Tcl_Obj* TclpNativeToNormalized _ANSI_ARGS_((ClientData clientData)); EXTERN Tcl_Obj* TclpFilesystemPathType _ANSI_ARGS_((Tcl_Obj* pathObjPtr)); EXTERN Tcl_PackageInitProc* TclpFindSymbol _ANSI_ARGS_((Tcl_Interp *interp, Tcl_LoadHandle loadHandle, CONST char *symbol)); EXTERN int TclpDlopen _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *pathPtr, Tcl_LoadHandle *loadHandle, Tcl_FSUnloadFileProc **unloadProcPtr)); EXTERN int TclpUtime _ANSI_ARGS_((Tcl_Obj *pathPtr, struct utimbuf *tval)); #ifdef TCL_LOAD_FROM_MEMORY EXTERN void* TclpLoadMemoryGetBuffer _ANSI_ARGS_(( Tcl_Interp *interp, int size)); EXTERN int TclpLoadMemory _ANSI_ARGS_((Tcl_Interp *interp, void *buffer, int size, int codeSize, Tcl_LoadHandle *loadHandle, Tcl_FSUnloadFileProc **unloadProcPtr)); #endif /* *---------------------------------------------------------------- * Command procedures in the generic core: *---------------------------------------------------------------- */ EXTERN int Tcl_AfterObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_AppendObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_ArrayObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_BinaryObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_BreakObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_CaseObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_CatchObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_CdObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_ClockObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_CloseObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_ConcatObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_ContinueObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_EncodingObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_EofObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_ErrorObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_EvalObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_ExecObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_ExitObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_ExprObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_FblockedObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_FconfigureObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_FcopyObjCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_FileObjCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_FileEventObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_FlushObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_ForObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_ForeachObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_FormatObjCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_GetsObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_GlobalObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_GlobObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_IfObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_IncrObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_InfoObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_InterpObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int argc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_JoinObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_LappendObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_LindexObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_LinsertObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_LlengthObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_ListObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_LoadObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_LrangeObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_LreplaceObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_LsearchObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_LsetObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_LsortObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_NamespaceObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_OpenObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_PackageObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_PidObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_PutsObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_PwdObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_ReadObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_RegexpObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_RegsubObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_RenameObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_ReturnObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_ScanObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_SeekObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_SetObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_SplitObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_SocketObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_SourceObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_StringObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_SubstObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_SwitchObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_TellObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_TimeObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_TraceObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_UnsetObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_UpdateObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_UplevelObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_UpvarObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_VariableObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_VwaitObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int Tcl_WhileObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); /* *---------------------------------------------------------------- * Compilation procedures for commands in the generic core: *---------------------------------------------------------------- */ EXTERN int TclCompileAppendCmd _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Parse *parsePtr, struct CompileEnv *envPtr)); EXTERN int TclCompileBreakCmd _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Parse *parsePtr, struct CompileEnv *envPtr)); EXTERN int TclCompileCatchCmd _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Parse *parsePtr, struct CompileEnv *envPtr)); EXTERN int TclCompileContinueCmd _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Parse *parsePtr, struct CompileEnv *envPtr)); EXTERN int TclCompileExprCmd _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Parse *parsePtr, struct CompileEnv *envPtr)); EXTERN int TclCompileForCmd _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Parse *parsePtr, struct CompileEnv *envPtr)); EXTERN int TclCompileForeachCmd _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Parse *parsePtr, struct CompileEnv *envPtr)); EXTERN int TclCompileIfCmd _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Parse *parsePtr, struct CompileEnv *envPtr)); EXTERN int TclCompileIncrCmd _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Parse *parsePtr, struct CompileEnv *envPtr)); EXTERN int TclCompileLappendCmd _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Parse *parsePtr, struct CompileEnv *envPtr)); EXTERN int TclCompileLindexCmd _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Parse *parsePtr, struct CompileEnv *envPtr)); EXTERN int TclCompileListCmd _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Parse *parsePtr, struct CompileEnv *envPtr)); EXTERN int TclCompileLlengthCmd _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Parse *parsePtr, struct CompileEnv *envPtr)); EXTERN int TclCompileLsetCmd _ANSI_ARGS_((Tcl_Interp* interp, Tcl_Parse* parsePtr, struct CompileEnv* envPtr)); EXTERN int TclCompileRegexpCmd _ANSI_ARGS_((Tcl_Interp* interp, Tcl_Parse* parsePtr, struct CompileEnv* envPtr)); EXTERN int TclCompileReturnCmd _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Parse *parsePtr, struct CompileEnv *envPtr)); EXTERN int TclCompileSetCmd _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Parse *parsePtr, struct CompileEnv *envPtr)); EXTERN int TclCompileStringCmd _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Parse *parsePtr, struct CompileEnv *envPtr)); EXTERN int TclCompileWhileCmd _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Parse *parsePtr, struct CompileEnv *envPtr)); /* * Functions defined in generic/tclVar.c and currenttly exported only * for use by the bytecode compiler and engine. Some of these could later * be placed in the public interface. */ EXTERN Var * TclLookupArrayElement _ANSI_ARGS_((Tcl_Interp *interp, CONST char *arrayName, CONST char *elName, CONST int flags, CONST char *msg, CONST int createPart1, CONST int createPart2, Var *arrayPtr)); EXTERN Var * TclObjLookupVar _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *part1Ptr, CONST char *part2, int flags, CONST char *msg, CONST int createPart1, CONST int createPart2, Var **arrayPtrPtr)); EXTERN Tcl_Obj *TclPtrGetVar _ANSI_ARGS_((Tcl_Interp *interp, Var *varPtr, Var *arrayPtr, CONST char *part1, CONST char *part2, CONST int flags)); EXTERN Tcl_Obj *TclPtrSetVar _ANSI_ARGS_((Tcl_Interp *interp, Var *varPtr, Var *arrayPtr, CONST char *part1, CONST char *part2, Tcl_Obj *newValuePtr, CONST int flags)); EXTERN Tcl_Obj *TclPtrIncrVar _ANSI_ARGS_((Tcl_Interp *interp, Var *varPtr, Var *arrayPtr, CONST char *part1, CONST char *part2, CONST long i, CONST int flags)); /* *---------------------------------------------------------------- * Macros used by the Tcl core to create and release Tcl objects. * TclNewObj(objPtr) creates a new object denoting an empty string. * TclDecrRefCount(objPtr) decrements the object's reference count, * and frees the object if its reference count is zero. * These macros are inline versions of Tcl_NewObj() and * Tcl_DecrRefCount(). Notice that the names differ in not having * a "_" after the "Tcl". Notice also that these macros reference * their argument more than once, so you should avoid calling them * with an expression that is expensive to compute or has * side effects. The ANSI C "prototypes" for these macros are: * * EXTERN void TclNewObj _ANSI_ARGS_((Tcl_Obj *objPtr)); * EXTERN void TclDecrRefCount _ANSI_ARGS_((Tcl_Obj *objPtr)); * * These macros are defined in terms of two macros that depend on * memory allocator in use: TclAllocObjStorage, TclFreeObjStorage. * They are defined below. *---------------------------------------------------------------- */ /* * DTrace object allocation probe macros. */ #ifdef USE_DTRACE #include "tclDTrace.h" #define TCL_DTRACE_OBJ_CREATE(objPtr) TCL_OBJ_CREATE(objPtr) #define TCL_DTRACE_OBJ_FREE(objPtr) TCL_OBJ_FREE(objPtr) #else /* USE_DTRACE */ #define TCL_DTRACE_OBJ_CREATE(objPtr) {} #define TCL_DTRACE_OBJ_FREE(objPtr) {} #endif /* USE_DTRACE */ #ifdef TCL_COMPILE_STATS # define TclIncrObjsAllocated() \ tclObjsAlloced++ # define TclIncrObjsFreed() \ tclObjsFreed++ #else # define TclIncrObjsAllocated() # define TclIncrObjsFreed() #endif /* TCL_COMPILE_STATS */ #define TclNewObj(objPtr) \ TclAllocObjStorage(objPtr); \ TclIncrObjsAllocated(); \ (objPtr)->refCount = 0; \ (objPtr)->bytes = tclEmptyStringRep; \ (objPtr)->length = 0; \ (objPtr)->typePtr = NULL; \ TCL_DTRACE_OBJ_CREATE(objPtr) #ifdef TCL_MEM_DEBUG # define TclDecrRefCount(objPtr) \ Tcl_DbDecrRefCount(objPtr, __FILE__, __LINE__) #else # define TclDecrRefCount(objPtr) \ if (--(objPtr)->refCount <= 0) { \ TCL_DTRACE_OBJ_FREE(objPtr); \ if (((objPtr)->typePtr != NULL) \ && ((objPtr)->typePtr->freeIntRepProc != NULL)) { \ (objPtr)->typePtr->freeIntRepProc(objPtr); \ } \ if (((objPtr)->bytes != NULL) \ && ((objPtr)->bytes != tclEmptyStringRep)) { \ ckfree((char *) (objPtr)->bytes); \ } \ TclFreeObjStorage(objPtr); \ TclIncrObjsFreed(); \ } #endif #ifdef TCL_MEM_DEBUG # define TclAllocObjStorage(objPtr) \ (objPtr) = (Tcl_Obj *) \ Tcl_DbCkalloc(sizeof(Tcl_Obj), __FILE__, __LINE__) # define TclFreeObjStorage(objPtr) \ if ((objPtr)->refCount < -1) { \ panic("Reference count for %lx was negative: %s line %d", \ (objPtr), __FILE__, __LINE__); \ } \ ckfree((char *) (objPtr)) # define TclDbNewObj(objPtr, file, line) \ (objPtr) = (Tcl_Obj *) Tcl_DbCkalloc(sizeof(Tcl_Obj), (file), (line)); \ (objPtr)->refCount = 0; \ (objPtr)->bytes = tclEmptyStringRep; \ (objPtr)->length = 0; \ (objPtr)->typePtr = NULL; \ TclIncrObjsAllocated(); \ TCL_DTRACE_OBJ_CREATE(objPtr) #elif defined(PURIFY) /* * The PURIFY mode is like the regular mode, but instead of doing block * Tcl_Obj allocation and keeping a freed list for efficiency, it always * allocates and frees a single Tcl_Obj so that tools like Purify can * better track memory leaks */ # define TclAllocObjStorage(objPtr) \ (objPtr) = (Tcl_Obj *) Tcl_Ckalloc(sizeof(Tcl_Obj)) # define TclFreeObjStorage(objPtr) \ ckfree((char *) (objPtr)) #elif defined(TCL_THREADS) && defined(USE_THREAD_ALLOC) /* * The TCL_THREADS mode is like the regular mode but allocates Tcl_Obj's * from per-thread caches. */ EXTERN Tcl_Obj *TclThreadAllocObj _ANSI_ARGS_((void)); EXTERN void TclThreadFreeObj _ANSI_ARGS_((Tcl_Obj *)); EXTERN void TclFreeAllocCache _ANSI_ARGS_((void *)); EXTERN void TclpFreeAllocMutex _ANSI_ARGS_((Tcl_Mutex* mutex)); EXTERN void TclpFreeAllocCache _ANSI_ARGS_((void *)); # define TclAllocObjStorage(objPtr) \ (objPtr) = TclThreadAllocObj() # define TclFreeObjStorage(objPtr) \ TclThreadFreeObj((objPtr)) #else /* not TCL_MEM_DEBUG */ #if defined(USE_TCLALLOC) && USE_TCLALLOC MODULE_SCOPE void TclFinalizeAllocSubsystem(); MODULE_SCOPE void TclInitAlloc(); #else # define USE_TCLALLOC 0 #endif #ifdef TCL_THREADS /* declared in tclObj.c */ extern Tcl_Mutex tclObjMutex; #endif # define TclAllocObjStorage(objPtr) \ Tcl_MutexLock(&tclObjMutex); \ if (tclFreeObjList == NULL) { \ TclAllocateFreeObjects(); \ } \ (objPtr) = tclFreeObjList; \ tclFreeObjList = (Tcl_Obj *) \ tclFreeObjList->internalRep.otherValuePtr; \ Tcl_MutexUnlock(&tclObjMutex) # define TclFreeObjStorage(objPtr) \ Tcl_MutexLock(&tclObjMutex); \ (objPtr)->internalRep.otherValuePtr = (VOID *) tclFreeObjList; \ tclFreeObjList = (objPtr); \ Tcl_MutexUnlock(&tclObjMutex) #endif /* TCL_MEM_DEBUG */ /* *---------------------------------------------------------------- * Macro used by the Tcl core to set a Tcl_Obj's string representation * to a copy of the "len" bytes starting at "bytePtr". This code * works even if the byte array contains NULLs as long as the length * is correct. Because "len" is referenced multiple times, it should * be as simple an expression as possible. The ANSI C "prototype" for * this macro is: * * EXTERN void TclInitStringRep _ANSI_ARGS_((Tcl_Obj *objPtr, * char *bytePtr, int len)); *---------------------------------------------------------------- */ #define TclInitStringRep(objPtr, bytePtr, len) \ if ((len) == 0) { \ (objPtr)->bytes = tclEmptyStringRep; \ (objPtr)->length = 0; \ } else { \ (objPtr)->bytes = (char *) ckalloc((unsigned) ((len) + 1)); \ memcpy((VOID *) (objPtr)->bytes, (VOID *) (bytePtr), \ (unsigned) (len)); \ (objPtr)->bytes[len] = '\0'; \ (objPtr)->length = (len); \ } /* *---------------------------------------------------------------- * Macro used by the Tcl core to get the string representation's * byte array pointer from a Tcl_Obj. This is an inline version * of Tcl_GetString(). The macro's expression result is the string * rep's byte pointer which might be NULL. The bytes referenced by * this pointer must not be modified by the caller. * The ANSI C "prototype" for this macro is: * * EXTERN char * TclGetString _ANSI_ARGS_((Tcl_Obj *objPtr)); *---------------------------------------------------------------- */ #define TclGetString(objPtr) \ ((objPtr)->bytes? (objPtr)->bytes : Tcl_GetString((objPtr))) /* *---------------------------------------------------------------- * Macro used by the Tcl core to get a Tcl_WideInt value out of * a Tcl_Obj of the "wideInt" type. Different implementation on * different platforms depending whether TCL_WIDE_INT_IS_LONG. *---------------------------------------------------------------- */ #ifdef TCL_WIDE_INT_IS_LONG # define TclGetWide(resultVar, objPtr) \ (resultVar) = (objPtr)->internalRep.longValue # define TclGetLongFromWide(resultVar, objPtr) \ (resultVar) = (objPtr)->internalRep.longValue #else # define TclGetWide(resultVar, objPtr) \ (resultVar) = (objPtr)->internalRep.wideValue # define TclGetLongFromWide(resultVar, objPtr) \ (resultVar) = Tcl_WideAsLong((objPtr)->internalRep.wideValue) #endif /* *---------------------------------------------------------------- * Macro used by the Tcl core get a unicode char from a utf string. * It checks to see if we have a one-byte utf char before calling * the real Tcl_UtfToUniChar, as this will save a lot of time for * primarily ascii string handling. The macro's expression result * is 1 for the 1-byte case or the result of Tcl_UtfToUniChar. * The ANSI C "prototype" for this macro is: * * EXTERN int TclUtfToUniChar _ANSI_ARGS_((CONST char *string, * Tcl_UniChar *ch)); *---------------------------------------------------------------- */ #define TclUtfToUniChar(str, chPtr) \ ((((unsigned char) *(str)) < 0xC0) ? \ ((*(chPtr) = (Tcl_UniChar) *(str)), 1) \ : Tcl_UtfToUniChar(str, chPtr)) /* *---------------------------------------------------------------- * Macro used by the Tcl core to compare Unicode strings. On * big-endian systems we can use the more efficient memcmp, but * this would not be lexically correct on little-endian systems. * The ANSI C "prototype" for this macro is: * * EXTERN int TclUniCharNcmp _ANSI_ARGS_((CONST Tcl_UniChar *cs, * CONST Tcl_UniChar *ct, unsigned long n)); *---------------------------------------------------------------- */ #ifdef WORDS_BIGENDIAN # define TclUniCharNcmp(cs,ct,n) memcmp((cs),(ct),(n)*sizeof(Tcl_UniChar)) #else /* !WORDS_BIGENDIAN */ # define TclUniCharNcmp Tcl_UniCharNcmp #endif /* WORDS_BIGENDIAN */ #include "tclIntDecls.h" # undef TCL_STORAGE_CLASS # define TCL_STORAGE_CLASS DLLIMPORT #endif /* _TCLINT */ /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ tcl8.4.20/generic/tclPlatDecls.h0000644003604700454610000000614012052456744015062 0ustar dgp771div/* * tclPlatDecls.h -- * * Declarations of platform specific Tcl APIs. * * Copyright (c) 1998-1999 by Scriptics Corporation. * All rights reserved. */ #ifndef _TCLPLATDECLS #define _TCLPLATDECLS /* * TCHAR is needed here for win32, so if it is not defined yet do it here. * This way, we don't need to include just for one define. */ #if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(_TCHAR_DEFINED) # if defined(_UNICODE) typedef wchar_t TCHAR; # else typedef char TCHAR; # endif # define _TCHAR_DEFINED #endif /* !BEGIN!: Do not edit below this line. */ /* * Exported function declarations: */ #if defined(__WIN32__) || defined(__CYGWIN__) /* WIN */ /* 0 */ EXTERN TCHAR * Tcl_WinUtfToTChar _ANSI_ARGS_((CONST char *str, int len, Tcl_DString *dsPtr)); /* 1 */ EXTERN char * Tcl_WinTCharToUtf _ANSI_ARGS_((CONST TCHAR *str, int len, Tcl_DString *dsPtr)); #endif /* WIN */ #ifdef MAC_OSX_TCL /* MACOSX */ /* 0 */ EXTERN int Tcl_MacOSXOpenBundleResources _ANSI_ARGS_(( Tcl_Interp *interp, CONST char *bundleName, int hasResourceFile, int maxPathLen, char *libraryPath)); /* 1 */ EXTERN int Tcl_MacOSXOpenVersionedBundleResources _ANSI_ARGS_(( Tcl_Interp *interp, CONST char *bundleName, CONST char *bundleVersion, int hasResourceFile, int maxPathLen, char *libraryPath)); #endif /* MACOSX */ typedef struct TclPlatStubs { int magic; struct TclPlatStubHooks *hooks; #if defined(__WIN32__) || defined(__CYGWIN__) /* WIN */ TCHAR * (*tcl_WinUtfToTChar) _ANSI_ARGS_((CONST char *str, int len, Tcl_DString *dsPtr)); /* 0 */ char * (*tcl_WinTCharToUtf) _ANSI_ARGS_((CONST TCHAR *str, int len, Tcl_DString *dsPtr)); /* 1 */ #endif /* WIN */ #ifdef MAC_OSX_TCL /* MACOSX */ int (*tcl_MacOSXOpenBundleResources) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *bundleName, int hasResourceFile, int maxPathLen, char *libraryPath)); /* 0 */ int (*tcl_MacOSXOpenVersionedBundleResources) _ANSI_ARGS_((Tcl_Interp *interp, CONST char *bundleName, CONST char *bundleVersion, int hasResourceFile, int maxPathLen, char *libraryPath)); /* 1 */ #endif /* MACOSX */ } TclPlatStubs; #ifdef __cplusplus extern "C" { #endif extern TclPlatStubs *tclPlatStubsPtr; #ifdef __cplusplus } #endif #if defined(USE_TCL_STUBS) && !defined(USE_TCL_STUB_PROCS) /* * Inline function declarations: */ #if defined(__WIN32__) || defined(__CYGWIN__) /* WIN */ #ifndef Tcl_WinUtfToTChar #define Tcl_WinUtfToTChar \ (tclPlatStubsPtr->tcl_WinUtfToTChar) /* 0 */ #endif #ifndef Tcl_WinTCharToUtf #define Tcl_WinTCharToUtf \ (tclPlatStubsPtr->tcl_WinTCharToUtf) /* 1 */ #endif #endif /* WIN */ #ifdef MAC_OSX_TCL /* MACOSX */ #ifndef Tcl_MacOSXOpenBundleResources #define Tcl_MacOSXOpenBundleResources \ (tclPlatStubsPtr->tcl_MacOSXOpenBundleResources) /* 0 */ #endif #ifndef Tcl_MacOSXOpenVersionedBundleResources #define Tcl_MacOSXOpenVersionedBundleResources \ (tclPlatStubsPtr->tcl_MacOSXOpenVersionedBundleResources) /* 1 */ #endif #endif /* MACOSX */ #endif /* defined(USE_TCL_STUBS) && !defined(USE_TCL_STUB_PROCS) */ /* !END!: Do not edit above this line. */ #endif /* _TCLPLATDECLS */ tcl8.4.20/generic/tclTestProcBodyObj.c0000644003604700454610000002107312052456744016220 0ustar dgp771div/* * tclTestProcBodyObj.c -- * * Implements the "procbodytest" package, which contains commands * to test creation of Tcl procedures whose body argument is a * Tcl_Obj of type "procbody" rather than a string. * * Copyright (c) 1998 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" /* * name and version of this package */ static CONST char packageName[] = "procbodytest"; static CONST char packageVersion[] = "1.0"; /* * Name of the commands exported by this package */ static CONST char procCommand[] = "proc"; /* * this struct describes an entry in the table of command names and command * procs */ typedef struct CmdTable { CONST char *cmdName; /* command name */ Tcl_ObjCmdProc *proc; /* command proc */ int exportIt; /* if 1, export the command */ } CmdTable; /* * Declarations for functions defined in this file. */ static int ProcBodyTestProcObjCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int ProcBodyTestInitInternal _ANSI_ARGS_((Tcl_Interp *interp, int isSafe)); static int RegisterCommand _ANSI_ARGS_((Tcl_Interp* interp, CONST char *namespace, CONST CmdTable *cmdTablePtr)); int Procbodytest_Init _ANSI_ARGS_((Tcl_Interp * interp)); int Procbodytest_SafeInit _ANSI_ARGS_((Tcl_Interp * interp)); /* * List of commands to create when the package is loaded; must go after the * declarations of the enable command procedure. */ static CONST CmdTable commands[] = { { procCommand, ProcBodyTestProcObjCmd, 1 }, { 0, 0, 0 } }; static CONST CmdTable safeCommands[] = { { procCommand, ProcBodyTestProcObjCmd, 1 }, { 0, 0, 0 } }; /* *---------------------------------------------------------------------- * * Procbodytest_Init -- * * This procedure initializes the "procbodytest" package. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Procbodytest_Init(interp) Tcl_Interp *interp; /* the Tcl interpreter for which the package * is initialized */ { return ProcBodyTestInitInternal(interp, 0); } /* *---------------------------------------------------------------------- * * Procbodytest_SafeInit -- * * This procedure initializes the "procbodytest" package. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Procbodytest_SafeInit(interp) Tcl_Interp *interp; /* the Tcl interpreter for which the package * is initialized */ { return ProcBodyTestInitInternal(interp, 1); } /* *---------------------------------------------------------------------- * * RegisterCommand -- * * This procedure registers a command in the context of the given namespace. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int RegisterCommand(interp, namespace, cmdTablePtr) Tcl_Interp* interp; /* the Tcl interpreter for which the * operation is performed */ CONST char *namespace; /* the namespace in which the command * is registered */ CONST CmdTable *cmdTablePtr; /* the command to register */ { char buf[128]; if (cmdTablePtr->exportIt) { sprintf(buf, "namespace eval %s { namespace export %s }", namespace, cmdTablePtr->cmdName); if (Tcl_Eval(interp, buf) != TCL_OK) return TCL_ERROR; } sprintf(buf, "%s::%s", namespace, cmdTablePtr->cmdName); Tcl_CreateObjCommand(interp, buf, cmdTablePtr->proc, 0, 0); return TCL_OK; } /* *---------------------------------------------------------------------- * * ProcBodyTestInitInternal -- * * This procedure initializes the Loader package. * The isSafe flag is 1 if the interpreter is safe, 0 otherwise. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int ProcBodyTestInitInternal(interp, isSafe) Tcl_Interp *interp; /* the Tcl interpreter for which the package * is initialized */ int isSafe; /* 1 if this is a safe interpreter */ { CONST CmdTable *cmdTablePtr; cmdTablePtr = (isSafe) ? &safeCommands[0] : &commands[0]; for ( ; cmdTablePtr->cmdName ; cmdTablePtr++) { if (RegisterCommand(interp, packageName, cmdTablePtr) != TCL_OK) { return TCL_ERROR; } } return Tcl_PkgProvide(interp, packageName, packageVersion); } /* *---------------------------------------------------------------------- * * ProcBodyTestProcObjCmd -- * * Implements the "procbodytest::proc" command. Here is the command * description: * procbodytest::proc newName argList bodyName * Looks up a procedure called $bodyName and, if the procedure exists, * constructs a Tcl_Obj of type "procbody" and calls Tcl_ProcObjCmd. * Arguments: * newName the name of the procedure to be created * argList the argument list for the procedure * bodyName the name of an existing procedure from which the * body is to be copied. * This command can be used to trigger the branches in Tcl_ProcObjCmd that * construct a proc from a "procbody", for example: * proc a {x} {return $x} * a 123 * procbodytest::proc b {x} a * Note the call to "a 123", which is necessary so that the Proc pointer * for "a" is filled in by the internal compiler; this is a hack. * * Results: * Returns a standard Tcl code. * * Side effects: * A new procedure is created. * Leaves an error message in the interp's result on error. * *---------------------------------------------------------------------- */ static int ProcBodyTestProcObjCmd (dummy, interp, objc, objv) ClientData dummy; /* context; not used */ Tcl_Interp *interp; /* the current interpreter */ int objc; /* argument count */ Tcl_Obj *CONST objv[]; /* arguments */ { char *fullName; Tcl_Command procCmd; Command *cmdPtr; Proc *procPtr = (Proc *) NULL; Tcl_Obj *bodyObjPtr; Tcl_Obj *myobjv[5]; int result; if (objc != 4) { Tcl_WrongNumArgs(interp, 1, objv, "newName argsList bodyName"); return TCL_ERROR; } /* * Find the Command pointer to this procedure */ fullName = Tcl_GetStringFromObj(objv[3], (int *) NULL); procCmd = Tcl_FindCommand(interp, fullName, (Tcl_Namespace *) NULL, TCL_LEAVE_ERR_MSG); if (procCmd == NULL) { return TCL_ERROR; } cmdPtr = (Command *) procCmd; /* * check that this is a procedure and not a builtin command: * If a procedure, cmdPtr->objProc is either 0 or TclObjInterpProc, * and cmdPtr->proc is either 0 or TclProcInterpProc. * Also, the compile proc should be 0, but we don't check for that. */ if (((cmdPtr->objProc != NULL) && (cmdPtr->objProc != TclGetObjInterpProc())) || ((cmdPtr->proc != NULL) && (cmdPtr->proc != TclGetInterpProc()))) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "command \"", fullName, "\" is not a Tcl procedure", (char *) NULL); return TCL_ERROR; } /* * it is a Tcl procedure: the client data is the Proc structure */ if (cmdPtr->objProc != NULL) { procPtr = (Proc *) cmdPtr->objClientData; } else if (cmdPtr->proc != NULL) { procPtr = (Proc *) cmdPtr->clientData; } if (procPtr == NULL) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "procedure \"", fullName, "\" does not have a Proc struct!", (char *) NULL); return TCL_ERROR; } /* * create a new object, initialize our argument vector, call into Tcl */ bodyObjPtr = TclNewProcBodyObj(procPtr); if (bodyObjPtr == NULL) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "failed to create a procbody object for procedure \"", fullName, "\"", (char *) NULL); return TCL_ERROR; } Tcl_IncrRefCount(bodyObjPtr); myobjv[0] = objv[0]; myobjv[1] = objv[1]; myobjv[2] = objv[2]; myobjv[3] = bodyObjPtr; myobjv[4] = (Tcl_Obj *) NULL; result = Tcl_ProcObjCmd((ClientData) NULL, interp, objc, myobjv); Tcl_DecrRefCount(bodyObjPtr); return result; } tcl8.4.20/generic/regfree.c0000644003604700454610000000404611737050674014122 0ustar dgp771div/* * regfree - free an RE * * Copyright (c) 1998, 1999 Henry Spencer. All rights reserved. * * Development of this software was funded, in part, by Cray Research Inc., * UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics * Corporation, none of whom are responsible for the results. The author * thanks all of them. * * Redistribution and use in source and binary forms -- with or without * modification -- are permitted for any purpose, provided that * redistributions in source form retain this entire copyright notice and * indicate the origin and nature of any modifications. * * I'd appreciate being given credit for this package in the documentation * of software which uses it, but that is not a requirement. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * HENRY SPENCER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * * * You might think that this could be incorporated into regcomp.c, and * that would be a reasonable idea... except that this is a generic * function (with a generic name), applicable to all compiled REs * regardless of the size of their characters, whereas the stuff in * regcomp.c gets compiled once per character size. */ #include "regguts.h" /* - regfree - free an RE (generic function, punts to RE-specific function) * * Ignoring invocation with NULL is a convenience. */ VOID regfree(re) regex_t *re; { if (re == NULL) return; (*((struct fns *)re->re_fns)->free)(re); } tcl8.4.20/generic/tclThread.c0000644003604700454610000003104211737050674014411 0ustar dgp771div/* * tclThread.c -- * * This file implements Platform independent thread operations. * Most of the real work is done in the platform dependent files. * * Copyright (c) 1998 by Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" /* * There are three classes of synchronization objects: * mutexes, thread data keys, and condition variables. * The following are used to record the memory used for these * objects so they can be finalized. * * These statics are guarded by the mutex in the caller of * TclRememberThreadData, e.g., TclpThreadDataKeyInit */ typedef struct { int num; /* Number of objects remembered */ int max; /* Max size of the array */ char **list; /* List of pointers */ } SyncObjRecord; static SyncObjRecord keyRecord = {0, 0, NULL}; static SyncObjRecord mutexRecord = {0, 0, NULL}; static SyncObjRecord condRecord = {0, 0, NULL}; /* * Prototypes of functions used only in this file */ static void RememberSyncObject _ANSI_ARGS_((char *objPtr, SyncObjRecord *recPtr)); static void ForgetSyncObject _ANSI_ARGS_((char *objPtr, SyncObjRecord *recPtr)); /* * Several functions are #defined to nothing in tcl.h if TCL_THREADS is not * specified. Here we undo that so the procedures are defined in the * stubs table. */ #ifndef TCL_THREADS #undef Tcl_MutexLock #undef Tcl_MutexUnlock #undef Tcl_MutexFinalize #undef Tcl_ConditionNotify #undef Tcl_ConditionWait #undef Tcl_ConditionFinalize #endif /* *---------------------------------------------------------------------- * * Tcl_GetThreadData -- * * This procedure allocates and initializes a chunk of thread * local storage. * * Results: * A thread-specific pointer to the data structure. * * Side effects: * Will allocate memory the first time this thread calls for * this chunk of storage. * *---------------------------------------------------------------------- */ VOID * Tcl_GetThreadData(keyPtr, size) Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk */ int size; /* Size of storage block */ { VOID *result; #ifdef TCL_THREADS /* * See if this is the first thread to init this key. */ if (*keyPtr == NULL) { TclpThreadDataKeyInit(keyPtr); } /* * Initialize the key for this thread. */ result = TclpThreadDataKeyGet(keyPtr); if (result == NULL) { result = (VOID *)ckalloc((size_t)size); memset(result, 0, (size_t)size); TclpThreadDataKeySet(keyPtr, result); } #else if (*keyPtr == NULL) { result = (VOID *)ckalloc((size_t)size); memset((char *)result, 0, (size_t)size); *keyPtr = (Tcl_ThreadDataKey)result; TclRememberDataKey(keyPtr); } result = *(VOID **)keyPtr; #endif return result; } /* *---------------------------------------------------------------------- * * TclThreadDataKeyGet -- * * This procedure returns a pointer to a block of thread local storage. * * Results: * A thread-specific pointer to the data structure, or NULL * if the memory has not been assigned to this key for this thread. * * Side effects: * None. * *---------------------------------------------------------------------- */ VOID * TclThreadDataKeyGet(keyPtr) Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk, * really (pthread_key_t **) */ { #ifdef TCL_THREADS return (VOID *)TclpThreadDataKeyGet(keyPtr); #else char *result = *(char **)keyPtr; return (VOID *)result; #endif /* TCL_THREADS */ } /* *---------------------------------------------------------------------- * * TclThreadDataKeySet -- * * This procedure sets a thread local storage pointer. * * Results: * None. * * Side effects: * The assigned value will be returned by TclpThreadDataKeyGet. * *---------------------------------------------------------------------- */ void TclThreadDataKeySet(keyPtr, data) Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk, * really (pthread_key_t **) */ VOID *data; /* Thread local storage */ { #ifdef TCL_THREADS if (*keyPtr == NULL) { TclpThreadDataKeyInit(keyPtr); } TclpThreadDataKeySet(keyPtr, data); #else *keyPtr = (Tcl_ThreadDataKey)data; #endif /* TCL_THREADS */ } /* *---------------------------------------------------------------------- * * RememberSyncObject * * Keep a list of (mutexes/condition variable/data key) * used during finalization. * * Assume master lock is held. * * Results: * None. * * Side effects: * Add to the appropriate list. * *---------------------------------------------------------------------- */ static void RememberSyncObject(objPtr, recPtr) char *objPtr; /* Pointer to sync object */ SyncObjRecord *recPtr; /* Record of sync objects */ { char **newList; int i, j; /* * Reuse any free slot in the list. */ for (i=0 ; i < recPtr->num ; ++i) { if (recPtr->list[i] == NULL) { recPtr->list[i] = objPtr; return; } } /* * Grow the list of pointers if necessary, copying only non-NULL * pointers to the new list. */ if (recPtr->num >= recPtr->max) { recPtr->max += 8; newList = (char **)ckalloc(recPtr->max * sizeof(char *)); for (i=0, j=0 ; i < recPtr->num ; i++) { if (recPtr->list[i] != NULL) { newList[j++] = recPtr->list[i]; } } if (recPtr->list != NULL) { ckfree((char *)recPtr->list); } recPtr->list = newList; recPtr->num = j; } recPtr->list[recPtr->num] = objPtr; recPtr->num++; } /* *---------------------------------------------------------------------- * * ForgetSyncObject * * Remove a single object from the list. * Assume master lock is held. * * Results: * None. * * Side effects: * Remove from the appropriate list. * *---------------------------------------------------------------------- */ static void ForgetSyncObject(objPtr, recPtr) char *objPtr; /* Pointer to sync object */ SyncObjRecord *recPtr; /* Record of sync objects */ { int i; for (i=0 ; inum ; i++) { if (objPtr == recPtr->list[i]) { recPtr->list[i] = NULL; return; } } } /* *---------------------------------------------------------------------- * * TclRememberMutex * * Keep a list of mutexes used during finalization. * Assume master lock is held. * * Results: * None. * * Side effects: * Add to the mutex list. * *---------------------------------------------------------------------- */ void TclRememberMutex(mutexPtr) Tcl_Mutex *mutexPtr; { RememberSyncObject((char *)mutexPtr, &mutexRecord); } /* *---------------------------------------------------------------------- * * Tcl_MutexFinalize * * Finalize a single mutex and remove it from the * list of remembered objects. * * Results: * None. * * Side effects: * Remove the mutex from the list. * *---------------------------------------------------------------------- */ void Tcl_MutexFinalize(mutexPtr) Tcl_Mutex *mutexPtr; { #ifdef TCL_THREADS TclpFinalizeMutex(mutexPtr); #endif TclpMasterLock(); ForgetSyncObject((char *)mutexPtr, &mutexRecord); TclpMasterUnlock(); } /* *---------------------------------------------------------------------- * * TclRememberDataKey * * Keep a list of thread data keys used during finalization. * Assume master lock is held. * * Results: * None. * * Side effects: * Add to the key list. * *---------------------------------------------------------------------- */ void TclRememberDataKey(keyPtr) Tcl_ThreadDataKey *keyPtr; { RememberSyncObject((char *)keyPtr, &keyRecord); } /* *---------------------------------------------------------------------- * * TclRememberCondition * * Keep a list of condition variables used during finalization. * Assume master lock is held. * * Results: * None. * * Side effects: * Add to the condition variable list. * *---------------------------------------------------------------------- */ void TclRememberCondition(condPtr) Tcl_Condition *condPtr; { RememberSyncObject((char *)condPtr, &condRecord); } /* *---------------------------------------------------------------------- * * Tcl_ConditionFinalize * * Finalize a single condition variable and remove it from the * list of remembered objects. * * Results: * None. * * Side effects: * Remove the condition variable from the list. * *---------------------------------------------------------------------- */ void Tcl_ConditionFinalize(condPtr) Tcl_Condition *condPtr; { #ifdef TCL_THREADS TclpFinalizeCondition(condPtr); #endif TclpMasterLock(); ForgetSyncObject((char *)condPtr, &condRecord); TclpMasterUnlock(); } /* *---------------------------------------------------------------------- * * TclFinalizeThreadData -- * * This procedure cleans up the thread-local storage. This is * called once for each thread. * * Results: * None. * * Side effects: * Frees up all thread local storage. * *---------------------------------------------------------------------- */ void TclFinalizeThreadData() { int i; Tcl_ThreadDataKey *keyPtr; TclpMasterLock(); for (i=0 ; itclAccessDeleteProc) /* 1 */ #endif #ifndef TclAccessInsertProc #define TclAccessInsertProc \ (tclIntStubsPtr->tclAccessInsertProc) /* 2 */ #endif #ifndef TclAllocateFreeObjects #define TclAllocateFreeObjects \ (tclIntStubsPtr->tclAllocateFreeObjects) /* 3 */ #endif /* Slot 4 is reserved */ #ifndef TclCleanupChildren #define TclCleanupChildren \ (tclIntStubsPtr->tclCleanupChildren) /* 5 */ #endif #ifndef TclCleanupCommand #define TclCleanupCommand \ (tclIntStubsPtr->tclCleanupCommand) /* 6 */ #endif #ifndef TclCopyAndCollapse #define TclCopyAndCollapse \ (tclIntStubsPtr->tclCopyAndCollapse) /* 7 */ #endif #ifndef TclCopyChannel #define TclCopyChannel \ (tclIntStubsPtr->tclCopyChannel) /* 8 */ #endif #ifndef TclCreatePipeline #define TclCreatePipeline \ (tclIntStubsPtr->tclCreatePipeline) /* 9 */ #endif #ifndef TclCreateProc #define TclCreateProc \ (tclIntStubsPtr->tclCreateProc) /* 10 */ #endif #ifndef TclDeleteCompiledLocalVars #define TclDeleteCompiledLocalVars \ (tclIntStubsPtr->tclDeleteCompiledLocalVars) /* 11 */ #endif #ifndef TclDeleteVars #define TclDeleteVars \ (tclIntStubsPtr->tclDeleteVars) /* 12 */ #endif #ifndef TclDoGlob #define TclDoGlob \ (tclIntStubsPtr->tclDoGlob) /* 13 */ #endif #ifndef TclDumpMemoryInfo #define TclDumpMemoryInfo \ (tclIntStubsPtr->tclDumpMemoryInfo) /* 14 */ #endif /* Slot 15 is reserved */ #ifndef TclExprFloatError #define TclExprFloatError \ (tclIntStubsPtr->tclExprFloatError) /* 16 */ #endif /* Slot 17 is reserved */ /* Slot 18 is reserved */ /* Slot 19 is reserved */ /* Slot 20 is reserved */ /* Slot 21 is reserved */ #ifndef TclFindElement #define TclFindElement \ (tclIntStubsPtr->tclFindElement) /* 22 */ #endif #ifndef TclFindProc #define TclFindProc \ (tclIntStubsPtr->tclFindProc) /* 23 */ #endif #ifndef TclFormatInt #define TclFormatInt \ (tclIntStubsPtr->tclFormatInt) /* 24 */ #endif #ifndef TclFreePackageInfo #define TclFreePackageInfo \ (tclIntStubsPtr->tclFreePackageInfo) /* 25 */ #endif /* Slot 26 is reserved */ #ifndef TclGetDate #define TclGetDate \ (tclIntStubsPtr->tclGetDate) /* 27 */ #endif #ifndef TclpGetDefaultStdChannel #define TclpGetDefaultStdChannel \ (tclIntStubsPtr->tclpGetDefaultStdChannel) /* 28 */ #endif /* Slot 29 is reserved */ /* Slot 30 is reserved */ #ifndef TclGetExtension #define TclGetExtension \ (tclIntStubsPtr->tclGetExtension) /* 31 */ #endif #ifndef TclGetFrame #define TclGetFrame \ (tclIntStubsPtr->tclGetFrame) /* 32 */ #endif #ifndef TclGetInterpProc #define TclGetInterpProc \ (tclIntStubsPtr->tclGetInterpProc) /* 33 */ #endif #ifndef TclGetIntForIndex #define TclGetIntForIndex \ (tclIntStubsPtr->tclGetIntForIndex) /* 34 */ #endif /* Slot 35 is reserved */ #ifndef TclGetLong #define TclGetLong \ (tclIntStubsPtr->tclGetLong) /* 36 */ #endif #ifndef TclGetLoadedPackages #define TclGetLoadedPackages \ (tclIntStubsPtr->tclGetLoadedPackages) /* 37 */ #endif #ifndef TclGetNamespaceForQualName #define TclGetNamespaceForQualName \ (tclIntStubsPtr->tclGetNamespaceForQualName) /* 38 */ #endif #ifndef TclGetObjInterpProc #define TclGetObjInterpProc \ (tclIntStubsPtr->tclGetObjInterpProc) /* 39 */ #endif #ifndef TclGetOpenMode #define TclGetOpenMode \ (tclIntStubsPtr->tclGetOpenMode) /* 40 */ #endif #ifndef TclGetOriginalCommand #define TclGetOriginalCommand \ (tclIntStubsPtr->tclGetOriginalCommand) /* 41 */ #endif #ifndef TclpGetUserHome #define TclpGetUserHome \ (tclIntStubsPtr->tclpGetUserHome) /* 42 */ #endif #ifndef TclGlobalInvoke #define TclGlobalInvoke \ (tclIntStubsPtr->tclGlobalInvoke) /* 43 */ #endif #ifndef TclGuessPackageName #define TclGuessPackageName \ (tclIntStubsPtr->tclGuessPackageName) /* 44 */ #endif #ifndef TclHideUnsafeCommands #define TclHideUnsafeCommands \ (tclIntStubsPtr->tclHideUnsafeCommands) /* 45 */ #endif #ifndef TclInExit #define TclInExit \ (tclIntStubsPtr->tclInExit) /* 46 */ #endif /* Slot 47 is reserved */ /* Slot 48 is reserved */ #ifndef TclIncrVar2 #define TclIncrVar2 \ (tclIntStubsPtr->tclIncrVar2) /* 49 */ #endif #ifndef TclInitCompiledLocals #define TclInitCompiledLocals \ (tclIntStubsPtr->tclInitCompiledLocals) /* 50 */ #endif #ifndef TclInterpInit #define TclInterpInit \ (tclIntStubsPtr->tclInterpInit) /* 51 */ #endif #ifndef TclInvoke #define TclInvoke \ (tclIntStubsPtr->tclInvoke) /* 52 */ #endif #ifndef TclInvokeObjectCommand #define TclInvokeObjectCommand \ (tclIntStubsPtr->tclInvokeObjectCommand) /* 53 */ #endif #ifndef TclInvokeStringCommand #define TclInvokeStringCommand \ (tclIntStubsPtr->tclInvokeStringCommand) /* 54 */ #endif #ifndef TclIsProc #define TclIsProc \ (tclIntStubsPtr->tclIsProc) /* 55 */ #endif /* Slot 56 is reserved */ /* Slot 57 is reserved */ #ifndef TclLookupVar #define TclLookupVar \ (tclIntStubsPtr->tclLookupVar) /* 58 */ #endif /* Slot 59 is reserved */ #ifndef TclNeedSpace #define TclNeedSpace \ (tclIntStubsPtr->tclNeedSpace) /* 60 */ #endif #ifndef TclNewProcBodyObj #define TclNewProcBodyObj \ (tclIntStubsPtr->tclNewProcBodyObj) /* 61 */ #endif #ifndef TclObjCommandComplete #define TclObjCommandComplete \ (tclIntStubsPtr->tclObjCommandComplete) /* 62 */ #endif #ifndef TclObjInterpProc #define TclObjInterpProc \ (tclIntStubsPtr->tclObjInterpProc) /* 63 */ #endif #ifndef TclObjInvoke #define TclObjInvoke \ (tclIntStubsPtr->tclObjInvoke) /* 64 */ #endif #ifndef TclObjInvokeGlobal #define TclObjInvokeGlobal \ (tclIntStubsPtr->tclObjInvokeGlobal) /* 65 */ #endif #ifndef TclOpenFileChannelDeleteProc #define TclOpenFileChannelDeleteProc \ (tclIntStubsPtr->tclOpenFileChannelDeleteProc) /* 66 */ #endif #ifndef TclOpenFileChannelInsertProc #define TclOpenFileChannelInsertProc \ (tclIntStubsPtr->tclOpenFileChannelInsertProc) /* 67 */ #endif /* Slot 68 is reserved */ #ifndef TclpAlloc #define TclpAlloc \ (tclIntStubsPtr->tclpAlloc) /* 69 */ #endif /* Slot 70 is reserved */ /* Slot 71 is reserved */ /* Slot 72 is reserved */ /* Slot 73 is reserved */ #ifndef TclpFree #define TclpFree \ (tclIntStubsPtr->tclpFree) /* 74 */ #endif #ifndef TclpGetClicks #define TclpGetClicks \ (tclIntStubsPtr->tclpGetClicks) /* 75 */ #endif #ifndef TclpGetSeconds #define TclpGetSeconds \ (tclIntStubsPtr->tclpGetSeconds) /* 76 */ #endif #ifndef TclpGetTime #define TclpGetTime \ (tclIntStubsPtr->tclpGetTime) /* 77 */ #endif #ifndef TclpGetTimeZone #define TclpGetTimeZone \ (tclIntStubsPtr->tclpGetTimeZone) /* 78 */ #endif /* Slot 79 is reserved */ /* Slot 80 is reserved */ #ifndef TclpRealloc #define TclpRealloc \ (tclIntStubsPtr->tclpRealloc) /* 81 */ #endif /* Slot 82 is reserved */ /* Slot 83 is reserved */ /* Slot 84 is reserved */ /* Slot 85 is reserved */ /* Slot 86 is reserved */ /* Slot 87 is reserved */ #ifndef TclPrecTraceProc #define TclPrecTraceProc \ (tclIntStubsPtr->tclPrecTraceProc) /* 88 */ #endif #ifndef TclPreventAliasLoop #define TclPreventAliasLoop \ (tclIntStubsPtr->tclPreventAliasLoop) /* 89 */ #endif /* Slot 90 is reserved */ #ifndef TclProcCleanupProc #define TclProcCleanupProc \ (tclIntStubsPtr->tclProcCleanupProc) /* 91 */ #endif #ifndef TclProcCompileProc #define TclProcCompileProc \ (tclIntStubsPtr->tclProcCompileProc) /* 92 */ #endif #ifndef TclProcDeleteProc #define TclProcDeleteProc \ (tclIntStubsPtr->tclProcDeleteProc) /* 93 */ #endif #ifndef TclProcInterpProc #define TclProcInterpProc \ (tclIntStubsPtr->tclProcInterpProc) /* 94 */ #endif /* Slot 95 is reserved */ #ifndef TclRenameCommand #define TclRenameCommand \ (tclIntStubsPtr->tclRenameCommand) /* 96 */ #endif #ifndef TclResetShadowedCmdRefs #define TclResetShadowedCmdRefs \ (tclIntStubsPtr->tclResetShadowedCmdRefs) /* 97 */ #endif #ifndef TclServiceIdle #define TclServiceIdle \ (tclIntStubsPtr->tclServiceIdle) /* 98 */ #endif /* Slot 99 is reserved */ /* Slot 100 is reserved */ #ifndef TclSetPreInitScript #define TclSetPreInitScript \ (tclIntStubsPtr->tclSetPreInitScript) /* 101 */ #endif #ifndef TclSetupEnv #define TclSetupEnv \ (tclIntStubsPtr->tclSetupEnv) /* 102 */ #endif #ifndef TclSockGetPort #define TclSockGetPort \ (tclIntStubsPtr->tclSockGetPort) /* 103 */ #endif #ifndef TclSockMinimumBuffersOld #define TclSockMinimumBuffersOld \ (tclIntStubsPtr->tclSockMinimumBuffersOld) /* 104 */ #endif /* Slot 105 is reserved */ #ifndef TclStatDeleteProc #define TclStatDeleteProc \ (tclIntStubsPtr->tclStatDeleteProc) /* 106 */ #endif #ifndef TclStatInsertProc #define TclStatInsertProc \ (tclIntStubsPtr->tclStatInsertProc) /* 107 */ #endif #ifndef TclTeardownNamespace #define TclTeardownNamespace \ (tclIntStubsPtr->tclTeardownNamespace) /* 108 */ #endif #ifndef TclUpdateReturnInfo #define TclUpdateReturnInfo \ (tclIntStubsPtr->tclUpdateReturnInfo) /* 109 */ #endif #ifndef TclSockMinimumBuffers #define TclSockMinimumBuffers \ (tclIntStubsPtr->tclSockMinimumBuffers) /* 110 */ #endif #ifndef Tcl_AddInterpResolvers #define Tcl_AddInterpResolvers \ (tclIntStubsPtr->tcl_AddInterpResolvers) /* 111 */ #endif #ifndef Tcl_AppendExportList #define Tcl_AppendExportList \ (tclIntStubsPtr->tcl_AppendExportList) /* 112 */ #endif #ifndef Tcl_CreateNamespace #define Tcl_CreateNamespace \ (tclIntStubsPtr->tcl_CreateNamespace) /* 113 */ #endif #ifndef Tcl_DeleteNamespace #define Tcl_DeleteNamespace \ (tclIntStubsPtr->tcl_DeleteNamespace) /* 114 */ #endif #ifndef Tcl_Export #define Tcl_Export \ (tclIntStubsPtr->tcl_Export) /* 115 */ #endif #ifndef Tcl_FindCommand #define Tcl_FindCommand \ (tclIntStubsPtr->tcl_FindCommand) /* 116 */ #endif #ifndef Tcl_FindNamespace #define Tcl_FindNamespace \ (tclIntStubsPtr->tcl_FindNamespace) /* 117 */ #endif #ifndef Tcl_GetInterpResolvers #define Tcl_GetInterpResolvers \ (tclIntStubsPtr->tcl_GetInterpResolvers) /* 118 */ #endif #ifndef Tcl_GetNamespaceResolvers #define Tcl_GetNamespaceResolvers \ (tclIntStubsPtr->tcl_GetNamespaceResolvers) /* 119 */ #endif #ifndef Tcl_FindNamespaceVar #define Tcl_FindNamespaceVar \ (tclIntStubsPtr->tcl_FindNamespaceVar) /* 120 */ #endif #ifndef Tcl_ForgetImport #define Tcl_ForgetImport \ (tclIntStubsPtr->tcl_ForgetImport) /* 121 */ #endif #ifndef Tcl_GetCommandFromObj #define Tcl_GetCommandFromObj \ (tclIntStubsPtr->tcl_GetCommandFromObj) /* 122 */ #endif #ifndef Tcl_GetCommandFullName #define Tcl_GetCommandFullName \ (tclIntStubsPtr->tcl_GetCommandFullName) /* 123 */ #endif #ifndef Tcl_GetCurrentNamespace #define Tcl_GetCurrentNamespace \ (tclIntStubsPtr->tcl_GetCurrentNamespace) /* 124 */ #endif #ifndef Tcl_GetGlobalNamespace #define Tcl_GetGlobalNamespace \ (tclIntStubsPtr->tcl_GetGlobalNamespace) /* 125 */ #endif #ifndef Tcl_GetVariableFullName #define Tcl_GetVariableFullName \ (tclIntStubsPtr->tcl_GetVariableFullName) /* 126 */ #endif #ifndef Tcl_Import #define Tcl_Import \ (tclIntStubsPtr->tcl_Import) /* 127 */ #endif #ifndef Tcl_PopCallFrame #define Tcl_PopCallFrame \ (tclIntStubsPtr->tcl_PopCallFrame) /* 128 */ #endif #ifndef Tcl_PushCallFrame #define Tcl_PushCallFrame \ (tclIntStubsPtr->tcl_PushCallFrame) /* 129 */ #endif #ifndef Tcl_RemoveInterpResolvers #define Tcl_RemoveInterpResolvers \ (tclIntStubsPtr->tcl_RemoveInterpResolvers) /* 130 */ #endif #ifndef Tcl_SetNamespaceResolvers #define Tcl_SetNamespaceResolvers \ (tclIntStubsPtr->tcl_SetNamespaceResolvers) /* 131 */ #endif #ifndef TclpHasSockets #define TclpHasSockets \ (tclIntStubsPtr->tclpHasSockets) /* 132 */ #endif #ifndef TclpGetDate #define TclpGetDate \ (tclIntStubsPtr->tclpGetDate) /* 133 */ #endif #ifndef TclpStrftime #define TclpStrftime \ (tclIntStubsPtr->tclpStrftime) /* 134 */ #endif #ifndef TclpCheckStackSpace #define TclpCheckStackSpace \ (tclIntStubsPtr->tclpCheckStackSpace) /* 135 */ #endif /* Slot 136 is reserved */ /* Slot 137 is reserved */ #ifndef TclGetEnv #define TclGetEnv \ (tclIntStubsPtr->tclGetEnv) /* 138 */ #endif /* Slot 139 is reserved */ #ifndef TclLooksLikeInt #define TclLooksLikeInt \ (tclIntStubsPtr->tclLooksLikeInt) /* 140 */ #endif #ifndef TclpGetCwd #define TclpGetCwd \ (tclIntStubsPtr->tclpGetCwd) /* 141 */ #endif #ifndef TclSetByteCodeFromAny #define TclSetByteCodeFromAny \ (tclIntStubsPtr->tclSetByteCodeFromAny) /* 142 */ #endif #ifndef TclAddLiteralObj #define TclAddLiteralObj \ (tclIntStubsPtr->tclAddLiteralObj) /* 143 */ #endif #ifndef TclHideLiteral #define TclHideLiteral \ (tclIntStubsPtr->tclHideLiteral) /* 144 */ #endif #ifndef TclGetAuxDataType #define TclGetAuxDataType \ (tclIntStubsPtr->tclGetAuxDataType) /* 145 */ #endif #ifndef TclHandleCreate #define TclHandleCreate \ (tclIntStubsPtr->tclHandleCreate) /* 146 */ #endif #ifndef TclHandleFree #define TclHandleFree \ (tclIntStubsPtr->tclHandleFree) /* 147 */ #endif #ifndef TclHandlePreserve #define TclHandlePreserve \ (tclIntStubsPtr->tclHandlePreserve) /* 148 */ #endif #ifndef TclHandleRelease #define TclHandleRelease \ (tclIntStubsPtr->tclHandleRelease) /* 149 */ #endif #ifndef TclRegAbout #define TclRegAbout \ (tclIntStubsPtr->tclRegAbout) /* 150 */ #endif #ifndef TclRegExpRangeUniChar #define TclRegExpRangeUniChar \ (tclIntStubsPtr->tclRegExpRangeUniChar) /* 151 */ #endif #ifndef TclSetLibraryPath #define TclSetLibraryPath \ (tclIntStubsPtr->tclSetLibraryPath) /* 152 */ #endif #ifndef TclGetLibraryPath #define TclGetLibraryPath \ (tclIntStubsPtr->tclGetLibraryPath) /* 153 */ #endif /* Slot 154 is reserved */ /* Slot 155 is reserved */ #ifndef TclRegError #define TclRegError \ (tclIntStubsPtr->tclRegError) /* 156 */ #endif #ifndef TclVarTraceExists #define TclVarTraceExists \ (tclIntStubsPtr->tclVarTraceExists) /* 157 */ #endif #ifndef TclSetStartupScriptFileName #define TclSetStartupScriptFileName \ (tclIntStubsPtr->tclSetStartupScriptFileName) /* 158 */ #endif #ifndef TclGetStartupScriptFileName #define TclGetStartupScriptFileName \ (tclIntStubsPtr->tclGetStartupScriptFileName) /* 159 */ #endif /* Slot 160 is reserved */ #ifndef TclChannelTransform #define TclChannelTransform \ (tclIntStubsPtr->tclChannelTransform) /* 161 */ #endif #ifndef TclChannelEventScriptInvoker #define TclChannelEventScriptInvoker \ (tclIntStubsPtr->tclChannelEventScriptInvoker) /* 162 */ #endif #ifndef TclGetInstructionTable #define TclGetInstructionTable \ (tclIntStubsPtr->tclGetInstructionTable) /* 163 */ #endif #ifndef TclExpandCodeArray #define TclExpandCodeArray \ (tclIntStubsPtr->tclExpandCodeArray) /* 164 */ #endif #ifndef TclpSetInitialEncodings #define TclpSetInitialEncodings \ (tclIntStubsPtr->tclpSetInitialEncodings) /* 165 */ #endif #ifndef TclListObjSetElement #define TclListObjSetElement \ (tclIntStubsPtr->tclListObjSetElement) /* 166 */ #endif #ifndef TclSetStartupScriptPath #define TclSetStartupScriptPath \ (tclIntStubsPtr->tclSetStartupScriptPath) /* 167 */ #endif #ifndef TclGetStartupScriptPath #define TclGetStartupScriptPath \ (tclIntStubsPtr->tclGetStartupScriptPath) /* 168 */ #endif #ifndef TclpUtfNcmp2 #define TclpUtfNcmp2 \ (tclIntStubsPtr->tclpUtfNcmp2) /* 169 */ #endif #ifndef TclCheckInterpTraces #define TclCheckInterpTraces \ (tclIntStubsPtr->tclCheckInterpTraces) /* 170 */ #endif #ifndef TclCheckExecutionTraces #define TclCheckExecutionTraces \ (tclIntStubsPtr->tclCheckExecutionTraces) /* 171 */ #endif #ifndef TclInThreadExit #define TclInThreadExit \ (tclIntStubsPtr->tclInThreadExit) /* 172 */ #endif #ifndef TclUniCharMatch #define TclUniCharMatch \ (tclIntStubsPtr->tclUniCharMatch) /* 173 */ #endif /* Slot 174 is reserved */ /* Slot 175 is reserved */ /* Slot 176 is reserved */ /* Slot 177 is reserved */ /* Slot 178 is reserved */ /* Slot 179 is reserved */ /* Slot 180 is reserved */ /* Slot 181 is reserved */ #ifndef TclpLocaltime #define TclpLocaltime \ (tclIntStubsPtr->tclpLocaltime) /* 182 */ #endif #ifndef TclpGmtime #define TclpGmtime \ (tclIntStubsPtr->tclpGmtime) /* 183 */ #endif /* Slot 184 is reserved */ /* Slot 185 is reserved */ /* Slot 186 is reserved */ /* Slot 187 is reserved */ /* Slot 188 is reserved */ /* Slot 189 is reserved */ /* Slot 190 is reserved */ /* Slot 191 is reserved */ /* Slot 192 is reserved */ /* Slot 193 is reserved */ /* Slot 194 is reserved */ /* Slot 195 is reserved */ /* Slot 196 is reserved */ /* Slot 197 is reserved */ /* Slot 198 is reserved */ #ifndef TclMatchIsTrivial #define TclMatchIsTrivial \ (tclIntStubsPtr->tclMatchIsTrivial) /* 199 */ #endif /* Slot 200 is reserved */ /* Slot 201 is reserved */ /* Slot 202 is reserved */ /* Slot 203 is reserved */ /* Slot 204 is reserved */ /* Slot 205 is reserved */ /* Slot 206 is reserved */ /* Slot 207 is reserved */ /* Slot 208 is reserved */ /* Slot 209 is reserved */ /* Slot 210 is reserved */ /* Slot 211 is reserved */ /* Slot 212 is reserved */ /* Slot 213 is reserved */ /* Slot 214 is reserved */ /* Slot 215 is reserved */ /* Slot 216 is reserved */ /* Slot 217 is reserved */ /* Slot 218 is reserved */ /* Slot 219 is reserved */ /* Slot 220 is reserved */ /* Slot 221 is reserved */ /* Slot 222 is reserved */ /* Slot 223 is reserved */ /* Slot 224 is reserved */ /* Slot 225 is reserved */ /* Slot 226 is reserved */ /* Slot 227 is reserved */ /* Slot 228 is reserved */ /* Slot 229 is reserved */ /* Slot 230 is reserved */ /* Slot 231 is reserved */ /* Slot 232 is reserved */ /* Slot 233 is reserved */ /* Slot 234 is reserved */ /* Slot 235 is reserved */ /* Slot 236 is reserved */ /* Slot 237 is reserved */ /* Slot 238 is reserved */ /* Slot 239 is reserved */ /* Slot 240 is reserved */ /* Slot 241 is reserved */ /* Slot 242 is reserved */ /* Slot 243 is reserved */ /* Slot 244 is reserved */ /* Slot 245 is reserved */ /* Slot 246 is reserved */ /* Slot 247 is reserved */ /* Slot 248 is reserved */ #ifndef TclUnusedStubEntry #define TclUnusedStubEntry \ (tclIntStubsPtr->tclUnusedStubEntry) /* 249 */ #endif #endif /* defined(USE_TCL_STUBS) && !defined(USE_TCL_STUB_PROCS) */ /* !END!: Do not edit above this line. */ #if !defined(_WIN64) /* See bug 510001: TclSockMinimumBuffers needs plat imp */ # undef TclSockMinimumBuffers # define TclSockMinimumBuffers(a,b) TclSockMinimumBuffersOld((int)(a),b) #endif #undef TclUnusedStubEntry #endif /* _TCLINTDECLS */ tcl8.4.20/generic/tclAsync.c0000644003604700454610000002341511737050674014264 0ustar dgp771div/* * tclAsync.c -- * * This file provides low-level support needed to invoke signal * handlers in a safe way. The code here doesn't actually handle * signals, though. This code is based on proposals made by * Mark Diekhans and Don Libes. * * Copyright (c) 1993 The Regents of the University of California. * Copyright (c) 1994 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" /* Forward declaration */ struct ThreadSpecificData; /* * One of the following structures exists for each asynchronous * handler: */ typedef struct AsyncHandler { int ready; /* Non-zero means this handler should * be invoked in the next call to * Tcl_AsyncInvoke. */ struct AsyncHandler *nextPtr; /* Next in list of all handlers for * the process. */ Tcl_AsyncProc *proc; /* Procedure to call when handler * is invoked. */ ClientData clientData; /* Value to pass to handler when it * is invoked. */ struct ThreadSpecificData *originTsd; /* Used in Tcl_AsyncMark to modify thread- * specific data from outside the thread * it is associated to. */ Tcl_ThreadId originThrdId; /* Origin thread where this token was * created and where it will be * yielded. */ } AsyncHandler; typedef struct ThreadSpecificData { /* * The variables below maintain a list of all existing handlers * specific to the calling thread. */ AsyncHandler *firstHandler; /* First handler defined for process, * or NULL if none. */ AsyncHandler *lastHandler; /* Last handler or NULL. */ /* * The variable below is set to 1 whenever a handler becomes ready and * it is cleared to zero whenever Tcl_AsyncInvoke is called. It can be * checked elsewhere in the application by calling Tcl_AsyncReady to see * if Tcl_AsyncInvoke should be invoked. */ int asyncReady; /* * The variable below indicates whether Tcl_AsyncInvoke is currently * working. If so then we won't set asyncReady again until * Tcl_AsyncInvoke returns. */ int asyncActive; Tcl_Mutex asyncMutex; /* Thread-specific AsyncHandler linked-list lock */ } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; /* *---------------------------------------------------------------------- * * TclFinalizeAsync -- * * Finalizes the mutex in the thread local data structure for the * async subsystem. * * Results: * None. * * Side effects: * Forgets knowledge of the mutex should it have been created. * *---------------------------------------------------------------------- */ void TclFinalizeAsync() { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (tsdPtr->asyncMutex != NULL) { Tcl_MutexFinalize(&tsdPtr->asyncMutex); } } /* *---------------------------------------------------------------------- * * Tcl_AsyncCreate -- * * This procedure creates the data structures for an asynchronous * handler, so that no memory has to be allocated when the handler * is activated. * * Results: * The return value is a token for the handler, which can be used * to activate it later on. * * Side effects: * Information about the handler is recorded. * *---------------------------------------------------------------------- */ Tcl_AsyncHandler Tcl_AsyncCreate(proc, clientData) Tcl_AsyncProc *proc; /* Procedure to call when handler * is invoked. */ ClientData clientData; /* Argument to pass to handler. */ { AsyncHandler *asyncPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); asyncPtr = (AsyncHandler *) ckalloc(sizeof(AsyncHandler)); asyncPtr->ready = 0; asyncPtr->nextPtr = NULL; asyncPtr->proc = proc; asyncPtr->clientData = clientData; asyncPtr->originTsd = tsdPtr; asyncPtr->originThrdId = Tcl_GetCurrentThread(); Tcl_MutexLock(&tsdPtr->asyncMutex); if (tsdPtr->firstHandler == NULL) { tsdPtr->firstHandler = asyncPtr; } else { tsdPtr->lastHandler->nextPtr = asyncPtr; } tsdPtr->lastHandler = asyncPtr; Tcl_MutexUnlock(&tsdPtr->asyncMutex); return (Tcl_AsyncHandler) asyncPtr; } /* *---------------------------------------------------------------------- * * Tcl_AsyncMark -- * * This procedure is called to request that an asynchronous handler * be invoked as soon as possible. It's typically called from * an interrupt handler, where it isn't safe to do anything that * depends on or modifies application state. * * Results: * None. * * Side effects: * The handler gets marked for invocation later. * *---------------------------------------------------------------------- */ void Tcl_AsyncMark(async) Tcl_AsyncHandler async; /* Token for handler. */ { AsyncHandler *token = (AsyncHandler *) async; Tcl_MutexLock(&token->originTsd->asyncMutex); token->ready = 1; if (!token->originTsd->asyncActive) { token->originTsd->asyncReady = 1; Tcl_ThreadAlert(token->originThrdId); } Tcl_MutexUnlock(&token->originTsd->asyncMutex); } /* *---------------------------------------------------------------------- * * Tcl_AsyncInvoke -- * * This procedure is called at a "safe" time at background level * to invoke any active asynchronous handlers. * * Results: * The return value is a normal Tcl result, which is intended to * replace the code argument as the current completion code for * interp. * * Side effects: * Depends on the handlers that are active. * *---------------------------------------------------------------------- */ int Tcl_AsyncInvoke(interp, code) Tcl_Interp *interp; /* If invoked from Tcl_Eval just after * completing a command, points to * interpreter. Otherwise it is * NULL. */ int code; /* If interp is non-NULL, this gives * completion code from command that * just completed. */ { AsyncHandler *asyncPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); Tcl_MutexLock(&tsdPtr->asyncMutex); if (tsdPtr->asyncReady == 0) { Tcl_MutexUnlock(&tsdPtr->asyncMutex); return code; } tsdPtr->asyncReady = 0; tsdPtr->asyncActive = 1; if (interp == NULL) { code = 0; } /* * Make one or more passes over the list of handlers, invoking * at most one handler in each pass. After invoking a handler, * go back to the start of the list again so that (a) if a new * higher-priority handler gets marked while executing a lower * priority handler, we execute the higher-priority handler * next, and (b) if a handler gets deleted during the execution * of a handler, then the list structure may change so it isn't * safe to continue down the list anyway. */ while (1) { for (asyncPtr = tsdPtr->firstHandler; asyncPtr != NULL; asyncPtr = asyncPtr->nextPtr) { if (asyncPtr->ready) { break; } } if (asyncPtr == NULL) { break; } asyncPtr->ready = 0; Tcl_MutexUnlock(&tsdPtr->asyncMutex); code = (*asyncPtr->proc)(asyncPtr->clientData, interp, code); Tcl_MutexLock(&tsdPtr->asyncMutex); } tsdPtr->asyncActive = 0; Tcl_MutexUnlock(&tsdPtr->asyncMutex); return code; } /* *---------------------------------------------------------------------- * * Tcl_AsyncDelete -- * * Frees up all the state for an asynchronous handler. The handler * should never be used again. * * Results: * None. * * Side effects: * The state associated with the handler is deleted. * * Failure to locate the handler in current thread private list * of async handlers will result in panic; exception: the list * is already empty (potential trouble?). * Consequently, threads should create and delete handlers * themselves. I.e. a handler created by one should not be * deleted by some other thread. * *---------------------------------------------------------------------- */ void Tcl_AsyncDelete(async) Tcl_AsyncHandler async; /* Token for handler to delete. */ { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); AsyncHandler *asyncPtr = (AsyncHandler *) async; AsyncHandler *prevPtr, *thisPtr; /* * Assure early handling of the constraint */ if (asyncPtr->originThrdId != Tcl_GetCurrentThread()) { panic("Tcl_AsyncDelete: async handler deleted by the wrong thread"); } /* * If we come to this point when TSD's for the current * thread have already been garbage-collected, we are * in the _serious_ trouble. OTOH, we tolerate calling * with already cleaned-up handler list (should we?). */ Tcl_MutexLock(&tsdPtr->asyncMutex); if (tsdPtr->firstHandler != NULL) { prevPtr = thisPtr = tsdPtr->firstHandler; while (thisPtr != NULL && thisPtr != asyncPtr) { prevPtr = thisPtr; thisPtr = thisPtr->nextPtr; } if (thisPtr == NULL) { panic("Tcl_AsyncDelete: cannot find async handler"); } if (asyncPtr == tsdPtr->firstHandler) { tsdPtr->firstHandler = asyncPtr->nextPtr; } else { prevPtr->nextPtr = asyncPtr->nextPtr; } if (asyncPtr == tsdPtr->lastHandler) { tsdPtr->lastHandler = prevPtr; } } Tcl_MutexUnlock(&tsdPtr->asyncMutex); ckfree((char *) asyncPtr); } /* *---------------------------------------------------------------------- * * Tcl_AsyncReady -- * * This procedure can be used to tell whether Tcl_AsyncInvoke * needs to be called. This procedure is the external interface * for checking the thread-specific asyncReady variable. * * Results: * The return value is 1 whenever a handler is ready and is 0 * when no handlers are ready. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_AsyncReady() { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); return tsdPtr->asyncReady; } tcl8.4.20/generic/tclCompile.c0000644003604700454610000037142312133546537014603 0ustar dgp771div/* * tclCompile.c -- * * This file contains procedures that compile Tcl commands or parts * of commands (like quoted strings or nested sub-commands) into a * sequence of instructions ("bytecodes"). * * Copyright (c) 1996-1998 Sun Microsystems, Inc. * Copyright (c) 2001 by Kevin B. Kenny. All rights reserved. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclCompile.h" /* * Table of all AuxData types. */ static Tcl_HashTable auxDataTypeTable; static int auxDataTypeTableInitialized; /* 0 means not yet initialized. */ TCL_DECLARE_MUTEX(tableMutex) /* * Variable that controls whether compilation tracing is enabled and, if so, * what level of tracing is desired: * 0: no compilation tracing * 1: summarize compilation of top level cmds and proc bodies * 2: display all instructions of each ByteCode compiled * This variable is linked to the Tcl variable "tcl_traceCompile". */ #ifdef TCL_COMPILE_DEBUG int tclTraceCompile = 0; static int traceInitialized = 0; #endif /* * A table describing the Tcl bytecode instructions. Entries in this table * must correspond to the instruction opcode definitions in tclCompile.h. * The names "op1" and "op4" refer to an instruction's one or four byte * first operand. Similarly, "stktop" and "stknext" refer to the topmost * and next to topmost stack elements. * * Note that the load, store, and incr instructions do not distinguish local * from global variables; the bytecode interpreter at runtime uses the * existence of a procedure call frame to distinguish these. */ InstructionDesc tclInstructionTable[] = { /* Name Bytes stackEffect #Opnds Operand types Stack top, next */ {"done", 1, -1, 0, {OPERAND_NONE}}, /* Finish ByteCode execution and return stktop (top stack item) */ {"push1", 2, +1, 1, {OPERAND_UINT1}}, /* Push object at ByteCode objArray[op1] */ {"push4", 5, +1, 1, {OPERAND_UINT4}}, /* Push object at ByteCode objArray[op4] */ {"pop", 1, -1, 0, {OPERAND_NONE}}, /* Pop the topmost stack object */ {"dup", 1, +1, 0, {OPERAND_NONE}}, /* Duplicate the topmost stack object and push the result */ {"concat1", 2, INT_MIN, 1, {OPERAND_UINT1}}, /* Concatenate the top op1 items and push result */ {"invokeStk1", 2, INT_MIN, 1, {OPERAND_UINT1}}, /* Invoke command named objv[0]; = */ {"invokeStk4", 5, INT_MIN, 1, {OPERAND_UINT4}}, /* Invoke command named objv[0]; = */ {"evalStk", 1, 0, 0, {OPERAND_NONE}}, /* Evaluate command in stktop using Tcl_EvalObj. */ {"exprStk", 1, 0, 0, {OPERAND_NONE}}, /* Execute expression in stktop using Tcl_ExprStringObj. */ {"loadScalar1", 2, 1, 1, {OPERAND_UINT1}}, /* Load scalar variable at index op1 <= 255 in call frame */ {"loadScalar4", 5, 1, 1, {OPERAND_UINT4}}, /* Load scalar variable at index op1 >= 256 in call frame */ {"loadScalarStk", 1, 0, 0, {OPERAND_NONE}}, /* Load scalar variable; scalar's name is stktop */ {"loadArray1", 2, 0, 1, {OPERAND_UINT1}}, /* Load array element; array at slot op1<=255, element is stktop */ {"loadArray4", 5, 0, 1, {OPERAND_UINT4}}, /* Load array element; array at slot op1 > 255, element is stktop */ {"loadArrayStk", 1, -1, 0, {OPERAND_NONE}}, /* Load array element; element is stktop, array name is stknext */ {"loadStk", 1, 0, 0, {OPERAND_NONE}}, /* Load general variable; unparsed variable name is stktop */ {"storeScalar1", 2, 0, 1, {OPERAND_UINT1}}, /* Store scalar variable at op1<=255 in frame; value is stktop */ {"storeScalar4", 5, 0, 1, {OPERAND_UINT4}}, /* Store scalar variable at op1 > 255 in frame; value is stktop */ {"storeScalarStk", 1, -1, 0, {OPERAND_NONE}}, /* Store scalar; value is stktop, scalar name is stknext */ {"storeArray1", 2, -1, 1, {OPERAND_UINT1}}, /* Store array element; array at op1<=255, value is top then elem */ {"storeArray4", 5, -1, 1, {OPERAND_UINT4}}, /* Store array element; array at op1>=256, value is top then elem */ {"storeArrayStk", 1, -2, 0, {OPERAND_NONE}}, /* Store array element; value is stktop, then elem, array names */ {"storeStk", 1, -1, 0, {OPERAND_NONE}}, /* Store general variable; value is stktop, then unparsed name */ {"incrScalar1", 2, 0, 1, {OPERAND_UINT1}}, /* Incr scalar at index op1<=255 in frame; incr amount is stktop */ {"incrScalarStk", 1, -1, 0, {OPERAND_NONE}}, /* Incr scalar; incr amount is stktop, scalar's name is stknext */ {"incrArray1", 2, -1, 1, {OPERAND_UINT1}}, /* Incr array elem; arr at slot op1<=255, amount is top then elem */ {"incrArrayStk", 1, -2, 0, {OPERAND_NONE}}, /* Incr array element; amount is top then elem then array names */ {"incrStk", 1, -1, 0, {OPERAND_NONE}}, /* Incr general variable; amount is stktop then unparsed var name */ {"incrScalar1Imm", 3, +1, 2, {OPERAND_UINT1, OPERAND_INT1}}, /* Incr scalar at slot op1 <= 255; amount is 2nd operand byte */ {"incrScalarStkImm", 2, 0, 1, {OPERAND_INT1}}, /* Incr scalar; scalar name is stktop; incr amount is op1 */ {"incrArray1Imm", 3, 0, 2, {OPERAND_UINT1, OPERAND_INT1}}, /* Incr array elem; array at slot op1 <= 255, elem is stktop, * amount is 2nd operand byte */ {"incrArrayStkImm", 2, -1, 1, {OPERAND_INT1}}, /* Incr array element; elem is top then array name, amount is op1 */ {"incrStkImm", 2, 0, 1, {OPERAND_INT1}}, /* Incr general variable; unparsed name is top, amount is op1 */ {"jump1", 2, 0, 1, {OPERAND_INT1}}, /* Jump relative to (pc + op1) */ {"jump4", 5, 0, 1, {OPERAND_INT4}}, /* Jump relative to (pc + op4) */ {"jumpTrue1", 2, -1, 1, {OPERAND_INT1}}, /* Jump relative to (pc + op1) if stktop expr object is true */ {"jumpTrue4", 5, -1, 1, {OPERAND_INT4}}, /* Jump relative to (pc + op4) if stktop expr object is true */ {"jumpFalse1", 2, -1, 1, {OPERAND_INT1}}, /* Jump relative to (pc + op1) if stktop expr object is false */ {"jumpFalse4", 5, -1, 1, {OPERAND_INT4}}, /* Jump relative to (pc + op4) if stktop expr object is false */ {"lor", 1, -1, 0, {OPERAND_NONE}}, /* Logical or: push (stknext || stktop) */ {"land", 1, -1, 0, {OPERAND_NONE}}, /* Logical and: push (stknext && stktop) */ {"bitor", 1, -1, 0, {OPERAND_NONE}}, /* Bitwise or: push (stknext | stktop) */ {"bitxor", 1, -1, 0, {OPERAND_NONE}}, /* Bitwise xor push (stknext ^ stktop) */ {"bitand", 1, -1, 0, {OPERAND_NONE}}, /* Bitwise and: push (stknext & stktop) */ {"eq", 1, -1, 0, {OPERAND_NONE}}, /* Equal: push (stknext == stktop) */ {"neq", 1, -1, 0, {OPERAND_NONE}}, /* Not equal: push (stknext != stktop) */ {"lt", 1, -1, 0, {OPERAND_NONE}}, /* Less: push (stknext < stktop) */ {"gt", 1, -1, 0, {OPERAND_NONE}}, /* Greater: push (stknext || stktop) */ {"le", 1, -1, 0, {OPERAND_NONE}}, /* Logical or: push (stknext || stktop) */ {"ge", 1, -1, 0, {OPERAND_NONE}}, /* Logical or: push (stknext || stktop) */ {"lshift", 1, -1, 0, {OPERAND_NONE}}, /* Left shift: push (stknext << stktop) */ {"rshift", 1, -1, 0, {OPERAND_NONE}}, /* Right shift: push (stknext >> stktop) */ {"add", 1, -1, 0, {OPERAND_NONE}}, /* Add: push (stknext + stktop) */ {"sub", 1, -1, 0, {OPERAND_NONE}}, /* Sub: push (stkext - stktop) */ {"mult", 1, -1, 0, {OPERAND_NONE}}, /* Multiply: push (stknext * stktop) */ {"div", 1, -1, 0, {OPERAND_NONE}}, /* Divide: push (stknext / stktop) */ {"mod", 1, -1, 0, {OPERAND_NONE}}, /* Mod: push (stknext % stktop) */ {"uplus", 1, 0, 0, {OPERAND_NONE}}, /* Unary plus: push +stktop */ {"uminus", 1, 0, 0, {OPERAND_NONE}}, /* Unary minus: push -stktop */ {"bitnot", 1, 0, 0, {OPERAND_NONE}}, /* Bitwise not: push ~stktop */ {"not", 1, 0, 0, {OPERAND_NONE}}, /* Logical not: push !stktop */ {"callBuiltinFunc1", 2, 1, 1, {OPERAND_UINT1}}, /* Call builtin math function with index op1; any args are on stk */ {"callFunc1", 2, INT_MIN, 1, {OPERAND_UINT1}}, /* Call non-builtin func objv[0]; = */ {"tryCvtToNumeric", 1, 0, 0, {OPERAND_NONE}}, /* Try converting stktop to first int then double if possible. */ {"break", 1, 0, 0, {OPERAND_NONE}}, /* Abort closest enclosing loop; if none, return TCL_BREAK code. */ {"continue", 1, 0, 0, {OPERAND_NONE}}, /* Skip to next iteration of closest enclosing loop; if none, * return TCL_CONTINUE code. */ {"foreach_start4", 5, 0, 1, {OPERAND_UINT4}}, /* Initialize execution of a foreach loop. Operand is aux data index * of the ForeachInfo structure for the foreach command. */ {"foreach_step4", 5, +1, 1, {OPERAND_UINT4}}, /* "Step" or begin next iteration of foreach loop. Push 0 if to * terminate loop, else push 1. */ {"beginCatch4", 5, 0, 1, {OPERAND_UINT4}}, /* Record start of catch with the operand's exception index. * Push the current stack depth onto a special catch stack. */ {"endCatch", 1, 0, 0, {OPERAND_NONE}}, /* End of last catch. Pop the bytecode interpreter's catch stack. */ {"pushResult", 1, +1, 0, {OPERAND_NONE}}, /* Push the interpreter's object result onto the stack. */ {"pushReturnCode", 1, +1, 0, {OPERAND_NONE}}, /* Push interpreter's return code (e.g. TCL_OK or TCL_ERROR) as * a new object onto the stack. */ {"streq", 1, -1, 0, {OPERAND_NONE}}, /* Str Equal: push (stknext eq stktop) */ {"strneq", 1, -1, 0, {OPERAND_NONE}}, /* Str !Equal: push (stknext neq stktop) */ {"strcmp", 1, -1, 0, {OPERAND_NONE}}, /* Str Compare: push (stknext cmp stktop) */ {"strlen", 1, 0, 0, {OPERAND_NONE}}, /* Str Length: push (strlen stktop) */ {"strindex", 1, -1, 0, {OPERAND_NONE}}, /* Str Index: push (strindex stknext stktop) */ {"strmatch", 2, -1, 1, {OPERAND_INT1}}, /* Str Match: push (strmatch stknext stktop) opnd == nocase */ {"list", 5, INT_MIN, 1, {OPERAND_UINT4}}, /* List: push (stk1 stk2 ... stktop) */ {"listindex", 1, -1, 0, {OPERAND_NONE}}, /* List Index: push (listindex stknext stktop) */ {"listlength", 1, 0, 0, {OPERAND_NONE}}, /* List Len: push (listlength stktop) */ {"appendScalar1", 2, 0, 1, {OPERAND_UINT1}}, /* Append scalar variable at op1<=255 in frame; value is stktop */ {"appendScalar4", 5, 0, 1, {OPERAND_UINT4}}, /* Append scalar variable at op1 > 255 in frame; value is stktop */ {"appendArray1", 2, -1, 1, {OPERAND_UINT1}}, /* Append array element; array at op1<=255, value is top then elem */ {"appendArray4", 5, -1, 1, {OPERAND_UINT4}}, /* Append array element; array at op1>=256, value is top then elem */ {"appendArrayStk", 1, -2, 0, {OPERAND_NONE}}, /* Append array element; value is stktop, then elem, array names */ {"appendStk", 1, -1, 0, {OPERAND_NONE}}, /* Append general variable; value is stktop, then unparsed name */ {"lappendScalar1", 2, 0, 1, {OPERAND_UINT1}}, /* Lappend scalar variable at op1<=255 in frame; value is stktop */ {"lappendScalar4", 5, 0, 1, {OPERAND_UINT4}}, /* Lappend scalar variable at op1 > 255 in frame; value is stktop */ {"lappendArray1", 2, -1, 1, {OPERAND_UINT1}}, /* Lappend array element; array at op1<=255, value is top then elem */ {"lappendArray4", 5, -1, 1, {OPERAND_UINT4}}, /* Lappend array element; array at op1>=256, value is top then elem */ {"lappendArrayStk", 1, -2, 0, {OPERAND_NONE}}, /* Lappend array element; value is stktop, then elem, array names */ {"lappendStk", 1, -1, 0, {OPERAND_NONE}}, /* Lappend general variable; value is stktop, then unparsed name */ {"lindexMulti", 5, INT_MIN, 1, {OPERAND_UINT4}}, /* Lindex with generalized args, operand is number of stacked objs * used: (operand-1) entries from stktop are the indices; then list * to process. */ {"over", 5, +1, 1, {OPERAND_UINT4}}, /* Duplicate the arg-th element from top of stack (TOS=0) */ {"lsetList", 1, -2, 0, {OPERAND_NONE}}, /* Four-arg version of 'lset'. stktop is old value; next is * new element value, next is the index list; pushes new value */ {"lsetFlat", 5, INT_MIN, 1, {OPERAND_UINT4}}, /* Three- or >=5-arg version of 'lset', operand is number of * stacked objs: stktop is old value, next is new element value, next * come (operand-2) indices; pushes the new value. */ {0, 0, 0, 0, {OPERAND_NONE}} }; /* * Prototypes for procedures defined later in this file: */ static void DupByteCodeInternalRep _ANSI_ARGS_((Tcl_Obj *srcPtr, Tcl_Obj *copyPtr)); static unsigned char * EncodeCmdLocMap _ANSI_ARGS_(( CompileEnv *envPtr, ByteCode *codePtr, unsigned char *startPtr)); static void EnterCmdExtentData _ANSI_ARGS_(( CompileEnv *envPtr, int cmdNumber, int numSrcBytes, int numCodeBytes)); static void EnterCmdStartData _ANSI_ARGS_(( CompileEnv *envPtr, int cmdNumber, int srcOffset, int codeOffset)); static void FreeByteCodeInternalRep _ANSI_ARGS_(( Tcl_Obj *objPtr)); static int GetCmdLocEncodingSize _ANSI_ARGS_(( CompileEnv *envPtr)); static void LogCompilationInfo _ANSI_ARGS_((Tcl_Interp *interp, CONST char *script, CONST char *command, int length)); #ifdef TCL_COMPILE_STATS static void RecordByteCodeStats _ANSI_ARGS_(( ByteCode *codePtr)); #endif /* TCL_COMPILE_STATS */ static int SetByteCodeFromAny _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr)); #ifdef TCL_TIP280 /* TIP #280 : Helper for building the per-word line information of all * compiled commands */ static void EnterCmdWordData _ANSI_ARGS_(( ExtCmdLoc *eclPtr, int srcOffset, Tcl_Token* tokenPtr, CONST char* cmd, int len, int numWords, int line, int* clNext, int** lines, CompileEnv* envPtr)); static void ReleaseCmdWordData _ANSI_ARGS_((ExtCmdLoc* eclPtr)); #endif /* * The structure below defines the bytecode Tcl object type by * means of procedures that can be invoked by generic object code. */ Tcl_ObjType tclByteCodeType = { "bytecode", /* name */ FreeByteCodeInternalRep, /* freeIntRepProc */ DupByteCodeInternalRep, /* dupIntRepProc */ (Tcl_UpdateStringProc *) NULL, /* updateStringProc */ SetByteCodeFromAny /* setFromAnyProc */ }; /* *---------------------------------------------------------------------- * * TclSetByteCodeFromAny -- * * Part of the bytecode Tcl object type implementation. Attempts to * generate an byte code internal form for the Tcl object "objPtr" by * compiling its string representation. This function also takes * a hook procedure that will be invoked to perform any needed post * processing on the compilation results before generating byte * codes. interp is compilation context and may not be NULL. * * Results: * The return value is a standard Tcl object result. If an error occurs * during compilation, an error message is left in the interpreter's * result. * * Side effects: * Frees the old internal representation. If no error occurs, then the * compiled code is stored as "objPtr"s bytecode representation. * Also, if debugging, initializes the "tcl_traceCompile" Tcl variable * used to trace compilations. * *---------------------------------------------------------------------- */ int TclSetByteCodeFromAny(interp, objPtr, hookProc, clientData) Tcl_Interp *interp; /* The interpreter for which the code is * being compiled. Must not be NULL. */ Tcl_Obj *objPtr; /* The object to make a ByteCode object. */ CompileHookProc *hookProc; /* Procedure to invoke after compilation. */ ClientData clientData; /* Hook procedure private data. */ { Interp *iPtr = (Interp *) interp; CompileEnv compEnv; /* Compilation environment structure * allocated in frame. */ LiteralTable *localTablePtr = &(compEnv.localLitTable); int length, nested, result; char *string; #ifdef TCL_TIP280 ContLineLoc* clLocPtr; #endif #ifdef TCL_COMPILE_DEBUG if (!traceInitialized) { if (Tcl_LinkVar(interp, "tcl_traceCompile", (char *) &tclTraceCompile, TCL_LINK_INT) != TCL_OK) { panic("SetByteCodeFromAny: unable to create link for tcl_traceCompile variable"); } traceInitialized = 1; } #endif if (iPtr->evalFlags & TCL_BRACKET_TERM) { nested = 1; } else { nested = 0; } string = Tcl_GetStringFromObj(objPtr, &length); #ifndef TCL_TIP280 TclInitCompileEnv(interp, &compEnv, string, length); #else /* * TIP #280. Pick up the CmdFrame in which the BC compiler was invoked * and use to initialize the tracking in the compiler. This information * was stored by TclCompEvalObj (tclExecute.c), and ProcCompileProc * (tclProc.c). */ TclInitCompileEnv(interp, &compEnv, string, length, iPtr->invokeCmdFramePtr, iPtr->invokeWord); /* * Now we check if we have data about invisible continuation lines for the * script, and make it available to the compile environment, if so. * * It is not clear if the script Tcl_Obj* can be free'd while the compiler * is using it, leading to the release of the associated ContLineLoc * structure as well. To ensure that the latter doesn't happen we set a * lock on it. We release this lock in the function TclFreeCompileEnv (), * found in this file. The "lineCLPtr" hashtable is managed in the file * "tclObj.c". */ clLocPtr = TclContinuationsGet (objPtr); if (clLocPtr) { compEnv.clLoc = clLocPtr; compEnv.clNext = &compEnv.clLoc->loc[0]; Tcl_Preserve (compEnv.clLoc); } #endif result = TclCompileScript(interp, string, length, nested, &compEnv); if (result == TCL_OK) { /* * Successful compilation. Add a "done" instruction at the end. */ compEnv.numSrcBytes = iPtr->termOffset; TclEmitOpcode(INST_DONE, &compEnv); /* * Invoke the compilation hook procedure if one exists. */ if (hookProc) { result = (*hookProc)(interp, &compEnv, clientData); } /* * Change the object into a ByteCode object. Ownership of the literal * objects and aux data items is given to the ByteCode object. */ #ifdef TCL_COMPILE_DEBUG TclVerifyLocalLiteralTable(&compEnv); #endif /*TCL_COMPILE_DEBUG*/ if (result == TCL_OK) { TclInitByteCodeObj(objPtr, &compEnv); #ifdef TCL_COMPILE_DEBUG if (tclTraceCompile >= 2) { TclPrintByteCodeObj(interp, objPtr); } #endif /* TCL_COMPILE_DEBUG */ } } /* * Free storage allocated during compilation. */ if (localTablePtr->buckets != localTablePtr->staticBuckets) { ckfree((char *) localTablePtr->buckets); } TclFreeCompileEnv(&compEnv); return result; } /* *----------------------------------------------------------------------- * * SetByteCodeFromAny -- * * Part of the bytecode Tcl object type implementation. Attempts to * generate an byte code internal form for the Tcl object "objPtr" by * compiling its string representation. * * Results: * The return value is a standard Tcl object result. If an error occurs * during compilation, an error message is left in the interpreter's * result unless "interp" is NULL. * * Side effects: * Frees the old internal representation. If no error occurs, then the * compiled code is stored as "objPtr"s bytecode representation. * Also, if debugging, initializes the "tcl_traceCompile" Tcl variable * used to trace compilations. * *---------------------------------------------------------------------- */ static int SetByteCodeFromAny(interp, objPtr) Tcl_Interp *interp; /* The interpreter for which the code is * being compiled. Must not be NULL. */ Tcl_Obj *objPtr; /* The object to make a ByteCode object. */ { if (interp == NULL) { return TCL_ERROR; } return TclSetByteCodeFromAny(interp, objPtr, (CompileHookProc *) NULL, (ClientData) NULL); } /* *---------------------------------------------------------------------- * * DupByteCodeInternalRep -- * * Part of the bytecode Tcl object type implementation. However, it * does not copy the internal representation of a bytecode Tcl_Obj, but * instead leaves the new object untyped (with a NULL type pointer). * Code will be compiled for the new object only if necessary. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void DupByteCodeInternalRep(srcPtr, copyPtr) Tcl_Obj *srcPtr; /* Object with internal rep to copy. */ Tcl_Obj *copyPtr; /* Object with internal rep to set. */ { return; } /* *---------------------------------------------------------------------- * * FreeByteCodeInternalRep -- * * Part of the bytecode Tcl object type implementation. Frees the * storage associated with a bytecode object's internal representation * unless its code is actively being executed. * * Results: * None. * * Side effects: * The bytecode object's internal rep is marked invalid and its * code gets freed unless the code is actively being executed. * In that case the cleanup is delayed until the last execution * of the code completes. * *---------------------------------------------------------------------- */ static void FreeByteCodeInternalRep(objPtr) register Tcl_Obj *objPtr; /* Object whose internal rep to free. */ { register ByteCode *codePtr = (ByteCode *) objPtr->internalRep.otherValuePtr; codePtr->refCount--; if (codePtr->refCount <= 0) { TclCleanupByteCode(codePtr); } objPtr->typePtr = NULL; objPtr->internalRep.otherValuePtr = NULL; } /* *---------------------------------------------------------------------- * * TclCleanupByteCode -- * * This procedure does all the real work of freeing up a bytecode * object's ByteCode structure. It's called only when the structure's * reference count becomes zero. * * Results: * None. * * Side effects: * Frees objPtr's bytecode internal representation and sets its type * and objPtr->internalRep.otherValuePtr NULL. Also releases its * literals and frees its auxiliary data items. * *---------------------------------------------------------------------- */ void TclCleanupByteCode(codePtr) register ByteCode *codePtr; /* Points to the ByteCode to free. */ { Tcl_Interp *interp = (Tcl_Interp *) *codePtr->interpHandle; #ifdef TCL_TIP280 Interp* iPtr = (Interp*) interp; #endif int numLitObjects = codePtr->numLitObjects; int numAuxDataItems = codePtr->numAuxDataItems; register Tcl_Obj **objArrayPtr; register AuxData *auxDataPtr; int i; #ifdef TCL_COMPILE_STATS if (interp != NULL) { ByteCodeStats *statsPtr; Tcl_Time destroyTime; int lifetimeSec, lifetimeMicroSec, log2; statsPtr = &((Interp *) interp)->stats; statsPtr->numByteCodesFreed++; statsPtr->currentSrcBytes -= (double) codePtr->numSrcBytes; statsPtr->currentByteCodeBytes -= (double) codePtr->structureSize; statsPtr->currentInstBytes -= (double) codePtr->numCodeBytes; statsPtr->currentLitBytes -= (double) (codePtr->numLitObjects * sizeof(Tcl_Obj *)); statsPtr->currentExceptBytes -= (double) (codePtr->numExceptRanges * sizeof(ExceptionRange)); statsPtr->currentAuxBytes -= (double) (codePtr->numAuxDataItems * sizeof(AuxData)); statsPtr->currentCmdMapBytes -= (double) codePtr->numCmdLocBytes; Tcl_GetTime(&destroyTime); lifetimeSec = destroyTime.sec - codePtr->createTime.sec; if (lifetimeSec > 2000) { /* avoid overflow */ lifetimeSec = 2000; } lifetimeMicroSec = 1000000*lifetimeSec + (destroyTime.usec - codePtr->createTime.usec); log2 = TclLog2(lifetimeMicroSec); if (log2 > 31) { log2 = 31; } statsPtr->lifetimeCount[log2]++; } #endif /* TCL_COMPILE_STATS */ /* * A single heap object holds the ByteCode structure and its code, * object, command location, and auxiliary data arrays. This means we * only need to 1) decrement the ref counts of the LiteralEntry's in * its literal array, 2) call the free procs for the auxiliary data * items, and 3) free the ByteCode structure's heap object. * * The case for TCL_BYTECODE_PRECOMPILED (precompiled ByteCodes, * like those generated from tbcload) is special, as they doesn't * make use of the global literal table. They instead maintain * private references to their literals which must be decremented. */ if (codePtr->flags & TCL_BYTECODE_PRECOMPILED) { register Tcl_Obj *objPtr; objArrayPtr = codePtr->objArrayPtr; for (i = 0; i < numLitObjects; i++) { objPtr = *objArrayPtr; if (objPtr) { Tcl_DecrRefCount(objPtr); } objArrayPtr++; } codePtr->numLitObjects = 0; } else if (interp != NULL) { /* * If the interp has already been freed, then Tcl will have already * forcefully released all the literals used by ByteCodes compiled * with respect to that interp. */ objArrayPtr = codePtr->objArrayPtr; for (i = 0; i < numLitObjects; i++) { /* * TclReleaseLiteral sets a ByteCode's object array entry NULL to * indicate that it has already freed the literal. */ if (*objArrayPtr != NULL) { TclReleaseLiteral(interp, *objArrayPtr); } objArrayPtr++; } } auxDataPtr = codePtr->auxDataArrayPtr; for (i = 0; i < numAuxDataItems; i++) { if (auxDataPtr->type->freeProc != NULL) { (*auxDataPtr->type->freeProc)(auxDataPtr->clientData); } auxDataPtr++; } #ifdef TCL_TIP280 /* * TIP #280. Release the location data associated with this byte code * structure, if any. NOTE: The interp we belong to may be gone already, * and the data with it. * * See also tclBasic.c, DeleteInterpProc */ if (iPtr) { Tcl_HashEntry* hePtr = Tcl_FindHashEntry (iPtr->lineBCPtr, (char *) codePtr); if (hePtr) { ExtCmdLoc* eclPtr = (ExtCmdLoc*) Tcl_GetHashValue (hePtr); ReleaseCmdWordData (eclPtr); Tcl_DeleteHashEntry (hePtr); } } #endif TclHandleRelease(codePtr->interpHandle); ckfree((char *) codePtr); } #ifdef TCL_TIP280 static void ReleaseCmdWordData (eclPtr) ExtCmdLoc* eclPtr; { int i; if (eclPtr->type == TCL_LOCATION_SOURCE) { Tcl_DecrRefCount (eclPtr->path); } for (i=0; i < eclPtr->nuloc; i++) { ckfree ((char*) eclPtr->loc[i].line); } if (eclPtr->loc != NULL) { ckfree ((char*) eclPtr->loc); } Tcl_DeleteHashTable (&eclPtr->litInfo); ckfree ((char*) eclPtr); } #endif /* *---------------------------------------------------------------------- * * TclInitCompileEnv -- * * Initializes a CompileEnv compilation environment structure for the * compilation of a string in an interpreter. * * Results: * None. * * Side effects: * The CompileEnv structure is initialized. * *---------------------------------------------------------------------- */ void #ifndef TCL_TIP280 TclInitCompileEnv(interp, envPtr, string, numBytes) #else TclInitCompileEnv(interp, envPtr, string, numBytes, invoker, word) #endif Tcl_Interp *interp; /* The interpreter for which a CompileEnv * structure is initialized. */ register CompileEnv *envPtr; /* Points to the CompileEnv structure to * initialize. */ char *string; /* The source string to be compiled. */ int numBytes; /* Number of bytes in source string. */ #ifdef TCL_TIP280 CONST CmdFrame* invoker; /* Location context invoking the bcc */ int word; /* Index of the word in that context * getting compiled */ #endif { Interp *iPtr = (Interp *) interp; envPtr->iPtr = iPtr; envPtr->source = string; envPtr->numSrcBytes = numBytes; envPtr->procPtr = iPtr->compiledProcPtr; iPtr->compiledProcPtr = NULL; envPtr->numCommands = 0; envPtr->exceptDepth = 0; envPtr->maxExceptDepth = 0; envPtr->maxStackDepth = 0; envPtr->currStackDepth = 0; TclInitLiteralTable(&(envPtr->localLitTable)); envPtr->codeStart = envPtr->staticCodeSpace; envPtr->codeNext = envPtr->codeStart; envPtr->codeEnd = (envPtr->codeStart + COMPILEENV_INIT_CODE_BYTES); envPtr->mallocedCodeArray = 0; envPtr->literalArrayPtr = envPtr->staticLiteralSpace; envPtr->literalArrayNext = 0; envPtr->literalArrayEnd = COMPILEENV_INIT_NUM_OBJECTS; envPtr->mallocedLiteralArray = 0; envPtr->exceptArrayPtr = envPtr->staticExceptArraySpace; envPtr->exceptArrayNext = 0; envPtr->exceptArrayEnd = COMPILEENV_INIT_EXCEPT_RANGES; envPtr->mallocedExceptArray = 0; envPtr->cmdMapPtr = envPtr->staticCmdMapSpace; envPtr->cmdMapEnd = COMPILEENV_INIT_CMD_MAP_SIZE; envPtr->mallocedCmdMap = 0; #ifdef TCL_TIP280 /* * TIP #280: Set up the extended command location information, based on * the context invoking the byte code compiler. This structure is used to * keep the per-word line information for all compiled commands. * * See also tclBasic.c, TclEvalObjEx, for the equivalent code in the * non-compiling evaluator */ envPtr->extCmdMapPtr = (ExtCmdLoc*) ckalloc (sizeof (ExtCmdLoc)); envPtr->extCmdMapPtr->loc = NULL; envPtr->extCmdMapPtr->nloc = 0; envPtr->extCmdMapPtr->nuloc = 0; envPtr->extCmdMapPtr->path = NULL; Tcl_InitHashTable(&envPtr->extCmdMapPtr->litInfo, TCL_ONE_WORD_KEYS); if (invoker == NULL || (invoker->type == TCL_LOCATION_EVAL_LIST)) { /* * Initialize the compiler for relative counting in case of a * dynamic context. */ envPtr->line = 1; envPtr->extCmdMapPtr->type = (envPtr->procPtr ? TCL_LOCATION_PROC : TCL_LOCATION_BC); } else { /* Initialize the compiler using the context, making counting absolute * to that context. Note that the context can be byte code * execution. In that case we have to fill out the missing pieces * (line, path, ...). Which may make change the type as well. */ CmdFrame ctx = *invoker; int pc = 0; if (invoker->type == TCL_LOCATION_BC) { /* Note: Type BC => ctx.data.eval.path is not used. * ctx.data.tebc.codePtr is used instead. */ TclGetSrcInfoForPc (&ctx); pc = 1; } if ((ctx.nline <= word) || (ctx.line[word] < 0)) { /* Word is not a literal, relative counting */ envPtr->line = 1; envPtr->extCmdMapPtr->type = (envPtr->procPtr ? TCL_LOCATION_PROC : TCL_LOCATION_BC); if (pc && (ctx.type == TCL_LOCATION_SOURCE)) { /* * The reference made by 'TclGetSrcInfoForPc' is dead. */ Tcl_DecrRefCount(ctx.data.eval.path); } } else { envPtr->line = ctx.line [word]; envPtr->extCmdMapPtr->type = ctx.type; envPtr->extCmdMapPtr->path = ctx.data.eval.path; if (ctx.type == TCL_LOCATION_SOURCE) { if (pc) { /* The reference 'TclGetSrcInfoForPc' made is transfered */ ctx.data.eval.path = NULL; } else { /* We have a new reference here */ Tcl_IncrRefCount (ctx.data.eval.path); } } } /* ctx going out of scope */ } /* * Initialize the data about invisible continuation lines as empty, * i.e. not used. The caller (TclSetByteCodeFromAny) will set this up, if * such data is available. */ envPtr->clLoc = NULL; envPtr->clNext = NULL; #endif envPtr->auxDataArrayPtr = envPtr->staticAuxDataArraySpace; envPtr->auxDataArrayNext = 0; envPtr->auxDataArrayEnd = COMPILEENV_INIT_AUX_DATA_SIZE; envPtr->mallocedAuxDataArray = 0; } /* *---------------------------------------------------------------------- * * TclFreeCompileEnv -- * * Free the storage allocated in a CompileEnv compilation environment * structure. * * Results: * None. * * Side effects: * Allocated storage in the CompileEnv structure is freed. Note that * its local literal table is not deleted and its literal objects are * not released. In addition, storage referenced by its auxiliary data * items is not freed. This is done so that, when compilation is * successful, "ownership" of these objects and aux data items is * handed over to the corresponding ByteCode structure. * *---------------------------------------------------------------------- */ void TclFreeCompileEnv(envPtr) register CompileEnv *envPtr; /* Points to the CompileEnv structure. */ { if (envPtr->iPtr) { /* * We never converted to Bytecode, so free the things we would * have transferred to it. */ int i; LiteralEntry *entryPtr = envPtr->literalArrayPtr; AuxData *auxDataPtr = envPtr->auxDataArrayPtr; for (i = 0; i < envPtr->literalArrayNext; i++) { TclReleaseLiteral((Tcl_Interp *)envPtr->iPtr, entryPtr->objPtr); entryPtr++; } #ifdef TCL_COMPILE_DEBUG TclVerifyGlobalLiteralTable(envPtr->iPtr); #endif /*TCL_COMPILE_DEBUG*/ for (i = 0; i < envPtr->auxDataArrayNext; i++) { if (auxDataPtr->type->freeProc != NULL) { auxDataPtr->type->freeProc(auxDataPtr->clientData); } auxDataPtr++; } } if (envPtr->mallocedCodeArray) { ckfree((char *) envPtr->codeStart); } if (envPtr->mallocedLiteralArray) { ckfree((char *) envPtr->literalArrayPtr); } if (envPtr->mallocedExceptArray) { ckfree((char *) envPtr->exceptArrayPtr); } if (envPtr->mallocedCmdMap) { ckfree((char *) envPtr->cmdMapPtr); } if (envPtr->mallocedAuxDataArray) { ckfree((char *) envPtr->auxDataArrayPtr); } #ifdef TCL_TIP280 /* * If we used data about invisible continuation lines, then now is the * time to release on our hold on it. The lock was set in function * TclSetByteCodeFromAny(), found in this file. */ if (envPtr->clLoc) { Tcl_Release (envPtr->clLoc); } if (envPtr->extCmdMapPtr) { ReleaseCmdWordData (envPtr->extCmdMapPtr); } #endif } #ifdef TCL_TIP280 /* *---------------------------------------------------------------------- * * TclWordKnownAtCompileTime -- * * Test whether the value of a token is completely known at compile time. * * Results: * Returns true if the tokenPtr argument points to a word value that is * completely known at compile time. Generally, values that are known at * compile time can be compiled to their values, while values that cannot * be known until substitution at runtime must be compiled to bytecode * instructions that perform that substitution. For several commands, * whether or not arguments are known at compile time determine whether * it is worthwhile to compile at all. * * Side effects: * None. * * TIP #280 *---------------------------------------------------------------------- */ int TclWordKnownAtCompileTime (tokenPtr) Tcl_Token* tokenPtr; { int i; Tcl_Token* sub; if (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {return 1;}; if (tokenPtr->type != TCL_TOKEN_WORD) {return 0;}; /* Check the sub tokens of the word. It is a literal if we find * only BS and TEXT tokens */ for (i=0, sub = tokenPtr + 1; i < tokenPtr->numComponents; i++, sub ++) { if (sub->type == TCL_TOKEN_TEXT) continue; if (sub->type == TCL_TOKEN_BS) continue; return 0; } return 1; } #endif /* *---------------------------------------------------------------------- * * TclCompileScript -- * * Compile a Tcl script in a string. * * Results: * The return value is TCL_OK on a successful compilation and TCL_ERROR * on failure. If TCL_ERROR is returned, then the interpreter's result * contains an error message. * * interp->termOffset is set to the offset of the character in the * script just after the last one successfully processed; this will be * the offset of the ']' if (flags & TCL_BRACKET_TERM). * * Side effects: * Adds instructions to envPtr to evaluate the script at runtime. * *---------------------------------------------------------------------- */ int TclCompileScript(interp, script, numBytes, nested, envPtr) Tcl_Interp *interp; /* Used for error and status reporting. * Also serves as context for finding and * compiling commands. May not be NULL. */ CONST char *script; /* The source script to compile. */ int numBytes; /* Number of bytes in script. If < 0, the * script consists of all bytes up to the * first null character. */ int nested; /* Non-zero means this is a nested command: * close bracket ']' should be considered a * command terminator. If zero, close * bracket has no special meaning. */ CompileEnv *envPtr; /* Holds resulting instructions. */ { Interp *iPtr = (Interp *) interp; Tcl_Parse parse; int lastTopLevelCmdIndex = -1; /* Index of most recent toplevel command in * the command location table. Initialized * to avoid compiler warning. */ int startCodeOffset = -1; /* Offset of first byte of current command's * code. Init. to avoid compiler warning. */ unsigned char *entryCodeNext = envPtr->codeNext; CONST char *p, *next; Namespace *cmdNsPtr; Command *cmdPtr; Tcl_Token *tokenPtr; int bytesLeft, isFirstCmd, gotParse, wordIdx, currCmdIndex; int commandLength, objIndex, code; Tcl_DString ds; #ifdef TCL_TIP280 /* TIP #280 */ ExtCmdLoc* eclPtr = envPtr->extCmdMapPtr; int* wlines = NULL; int wlineat, cmdLine; int* clNext; #endif if (envPtr->iPtr == NULL) { Tcl_Panic("TclCompileScript() called on uninitialized CompileEnv"); } Tcl_DStringInit(&ds); if (numBytes < 0) { numBytes = strlen(script); } Tcl_ResetResult(interp); isFirstCmd = 1; /* * Each iteration through the following loop compiles the next * command from the script. */ p = script; bytesLeft = numBytes; gotParse = 0; #ifdef TCL_TIP280 cmdLine = envPtr->line; clNext = envPtr->clNext; #endif do { if (Tcl_ParseCommand(interp, p, bytesLeft, nested, &parse) != TCL_OK) { code = TCL_ERROR; goto error; } gotParse = 1; if (nested) { /* * This is an unusual situation where the caller has passed us * a non-zero value for "nested". How unusual? Well, this * procedure, TclCompileScript, is internal to Tcl, so all * callers should be within Tcl itself. All but one of those * callers explicitly pass in (nested = 0). The exceptional * caller is TclSetByteCodeFromAny, which will pass in * (nested = 1) if and only if the flag TCL_BRACKET_TERM * is set in the evalFlags field of interp. * * It appears that the TCL_BRACKET_TERM flag is only ever set * by Tcl_SubstObj, and it immediately calls Tcl_EvalEx * which clears the flag before passing the interp along. * So, I don't think this procedure, TclCompileScript, is * **ever** called with (nested != 0). * (The testsuite indeed doesn't exercise this code. MS) * * This means that the branches in this procedure that are * only active when (nested != 0) are probably never exercised. * This means that any bugs in them go unnoticed, and any bug * fixes in them have a semi-theoretical nature. * * All that said, the spec for this procedure says it should * handle the (nested != 0) case, so here's an attempt to fix * bugs (Tcl Bug 681841) in that case. Just in case some * callers eventually come along and expect it to work... */ if (parse.term == (script + numBytes)) { /* * The (nested != 0) case is meant to indicate that the * caller found an open bracket ([) and asked us to * parse and compile Tcl commands up to the matching * close bracket (]). We have to detect and handle * the case where the close bracket is missing. */ Tcl_SetObjResult(interp, Tcl_NewStringObj("missing close-bracket", -1)); code = TCL_ERROR; goto error; } } if (parse.numWords > 0) { /* * If not the first command, pop the previous command's result * and, if we're compiling a top level command, update the last * command's code size to account for the pop instruction. */ if (!isFirstCmd) { TclEmitOpcode(INST_POP, envPtr); if (!nested) { envPtr->cmdMapPtr[lastTopLevelCmdIndex].numCodeBytes = (envPtr->codeNext - envPtr->codeStart) - startCodeOffset; } } /* * Determine the actual length of the command. */ commandLength = parse.commandSize; if (parse.term == parse.commandStart + commandLength - 1) { /* * The command terminator character (such as ; or ]) is * the last character in the parsed command. Reduce the * length by one so that the trace message doesn't include * the terminator character. */ commandLength -= 1; } #ifdef TCL_COMPILE_DEBUG /* * If tracing, print a line for each top level command compiled. */ if ((tclTraceCompile >= 1) && !nested && (envPtr->procPtr == NULL)) { fprintf(stdout, " Compiling: "); TclPrintSource(stdout, parse.commandStart, TclMin(commandLength, 55)); fprintf(stdout, "\n"); } #endif /* * Each iteration of the following loop compiles one word * from the command. */ envPtr->numCommands++; currCmdIndex = (envPtr->numCommands - 1); if (!nested) { lastTopLevelCmdIndex = currCmdIndex; } startCodeOffset = (envPtr->codeNext - envPtr->codeStart); EnterCmdStartData(envPtr, currCmdIndex, (parse.commandStart - envPtr->source), startCodeOffset); #ifdef TCL_TIP280 /* TIP #280. Scan the words and compute the extended location * information. The map first contain full per-word line * information for use by the compiler. This is later replaced by * a reduced form which signals non-literal words, stored in * 'wlines'. */ TclAdvanceLines (&cmdLine, p, parse.commandStart); TclAdvanceContinuations (&cmdLine, &clNext, parse.commandStart - envPtr->source); EnterCmdWordData (eclPtr, (parse.commandStart - envPtr->source), parse.tokenPtr, parse.commandStart, parse.commandSize, parse.numWords, cmdLine, clNext, &wlines, envPtr); wlineat = eclPtr->nuloc - 1; #endif for (wordIdx = 0, tokenPtr = parse.tokenPtr; wordIdx < parse.numWords; wordIdx++, tokenPtr += (tokenPtr->numComponents + 1)) { #ifdef TCL_TIP280 envPtr->line = eclPtr->loc [wlineat].line [wordIdx]; envPtr->clNext = eclPtr->loc [wlineat].next [wordIdx]; #endif if (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD) { /* * If this is the first word and the command has a * compile procedure, let it compile the command. */ if (wordIdx == 0) { if (envPtr->procPtr != NULL) { cmdNsPtr = envPtr->procPtr->cmdPtr->nsPtr; } else { cmdNsPtr = NULL; /* use current NS */ } /* * We copy the string before trying to find the command * by name. We used to modify the string in place, but * this is not safe because the name resolution * handlers could have side effects that rely on the * unmodified string. */ Tcl_DStringSetLength(&ds, 0); Tcl_DStringAppend(&ds, tokenPtr[1].start, tokenPtr[1].size); cmdPtr = (Command *) Tcl_FindCommand(interp, Tcl_DStringValue(&ds), (Tcl_Namespace *) cmdNsPtr, /*flags*/ 0); if ((cmdPtr != NULL) && (cmdPtr->compileProc != NULL) && !(cmdPtr->flags & CMD_HAS_EXEC_TRACES) && !(iPtr->flags & DONT_COMPILE_CMDS_INLINE)) { int savedNumCmds = envPtr->numCommands; unsigned int savedCodeNext = envPtr->codeNext - envPtr->codeStart; code = (*(cmdPtr->compileProc))(interp, &parse, envPtr); if (code == TCL_OK) { goto finishCommand; } else if (code == TCL_OUT_LINE_COMPILE) { /* * Restore numCommands and codeNext to their correct * values, removing any commands compiled before * TCL_OUT_LINE_COMPILE [Bugs 705406 and 735055] */ envPtr->numCommands = savedNumCmds; envPtr->codeNext = envPtr->codeStart + savedCodeNext; } else { /* an error */ /* * There was a compilation error, the last * command did not get compiled into (*envPtr). * Decrement the number of commands * claimed to be in (*envPtr). */ envPtr->numCommands--; goto log; } } /* * No compile procedure so push the word. If the * command was found, push a CmdName object to * reduce runtime lookups. */ objIndex = TclRegisterNewLiteral(envPtr, tokenPtr[1].start, tokenPtr[1].size); if (cmdPtr != NULL) { TclSetCmdNameObj(interp, envPtr->literalArrayPtr[objIndex].objPtr, cmdPtr); } } else { /* Simple argument word of a command. We reach this if * and only if the command word was not compiled for * whatever reason. Register the literal's location * for use by uplevel, etc. commands, should they * encounter it unmodified. We care only if the we are * in a context which already allows absolute * counting. */ objIndex = TclRegisterNewLiteral(envPtr, tokenPtr[1].start, tokenPtr[1].size); #ifdef TCL_TIP280 if (envPtr->clNext) { TclContinuationsEnterDerived (envPtr->literalArrayPtr[objIndex].objPtr, tokenPtr[1].start - envPtr->source, eclPtr->loc [wlineat].next [wordIdx]); } #endif } TclEmitPush(objIndex, envPtr); } else { /* * The word is not a simple string of characters. */ code = TclCompileTokens(interp, tokenPtr+1, tokenPtr->numComponents, envPtr); if (code != TCL_OK) { goto log; } } } /* * Emit an invoke instruction for the command. We skip this * if a compile procedure was found for the command. */ if (wordIdx > 0) { #ifdef TCL_TIP280 /* * Save PC -> command map for the TclArgumentBC* functions. */ int isnew; Tcl_HashEntry* hePtr = Tcl_CreateHashEntry(&eclPtr->litInfo, (char*) (envPtr->codeNext - envPtr->codeStart), &isnew); Tcl_SetHashValue(hePtr, (char*) wlineat); #endif if (wordIdx <= 255) { TclEmitInstInt1(INST_INVOKE_STK1, wordIdx, envPtr); } else { TclEmitInstInt4(INST_INVOKE_STK4, wordIdx, envPtr); } } /* * Update the compilation environment structure and record the * offsets of the source and code for the command. */ finishCommand: EnterCmdExtentData(envPtr, currCmdIndex, commandLength, (envPtr->codeNext-envPtr->codeStart) - startCodeOffset); isFirstCmd = 0; #ifdef TCL_TIP280 /* TIP #280: Free full form of per-word line data and insert * the reduced form now */ ckfree ((char*) eclPtr->loc [wlineat].line); ckfree ((char*) eclPtr->loc [wlineat].next); eclPtr->loc [wlineat].line = wlines; eclPtr->loc [wlineat].next = NULL; wlines = NULL; #endif } /* end if parse.numWords > 0 */ /* * Advance to the next command in the script. */ next = parse.commandStart + parse.commandSize; bytesLeft -= (next - p); p = next; #ifdef TCL_TIP280 /* TIP #280 : Track lines in the just compiled command */ TclAdvanceLines (&cmdLine, parse.commandStart, p); TclAdvanceContinuations (&cmdLine, &clNext, p - envPtr->source); #endif Tcl_FreeParse(&parse); gotParse = 0; if (nested && (*parse.term == ']')) { /* * We get here in the special case where TCL_BRACKET_TERM was * set in the interpreter and the latest parsed command was * terminated by the matching close-bracket we were looking for. * Stop compilation. */ break; } } while (bytesLeft > 0); /* * If the source script yielded no instructions (e.g., if it was empty), * push an empty string as the command's result. */ if (envPtr->codeNext == entryCodeNext) { TclEmitPush(TclRegisterLiteral(envPtr, "", 0, /*onHeap*/ 0), envPtr); } if (nested) { /* * When (nested != 0) back up 1 character to have * iPtr->termOffset indicate the offset to the matching * close-bracket. */ iPtr->termOffset = (p - 1) - script; } else { iPtr->termOffset = (p - script); } Tcl_DStringFree(&ds); return TCL_OK; error: /* * Generate various pieces of error information, such as the line * number where the error occurred and information to add to the * errorInfo variable. Then free resources that had been allocated * to the command. */ commandLength = parse.commandSize; if (parse.term == parse.commandStart + commandLength - 1) { /* * The terminator character (such as ; or ]) of the command where * the error occurred is the last character in the parsed command. * Reduce the length by one so that the error message doesn't * include the terminator character. */ commandLength -= 1; } log: #ifdef TCL_TIP280 /* TIP #280: Free the per-word line data left over from parsing an * erroneous command, if any. */ if (wlines) { ckfree ((char*) eclPtr->loc [wlineat].line); ckfree ((char*) eclPtr->loc [wlineat].next); ckfree ((char*) wlines); eclPtr->loc [wlineat].line = NULL; eclPtr->loc [wlineat].next = NULL; wlines = NULL; } #endif LogCompilationInfo(interp, script, parse.commandStart, commandLength); if (gotParse) { Tcl_FreeParse(&parse); } iPtr->termOffset = (p - script); Tcl_DStringFree(&ds); return code; } /* *---------------------------------------------------------------------- * * TclCompileTokens -- * * Given an array of tokens parsed from a Tcl command (e.g., the tokens * that make up a word) this procedure emits instructions to evaluate * the tokens and concatenate their values to form a single result * value on the interpreter's runtime evaluation stack. * * Results: * The return value is a standard Tcl result. If an error occurs, an * error message is left in the interpreter's result. * * Side effects: * Instructions are added to envPtr to push and evaluate the tokens * at runtime. * *---------------------------------------------------------------------- */ int TclCompileTokens(interp, tokenPtr, count, envPtr) Tcl_Interp *interp; /* Used for error and status reporting. */ Tcl_Token *tokenPtr; /* Pointer to first in an array of tokens * to compile. */ int count; /* Number of tokens to consider at tokenPtr. * Must be at least 1. */ CompileEnv *envPtr; /* Holds the resulting instructions. */ { Tcl_DString textBuffer; /* Holds concatenated chars from adjacent * TCL_TOKEN_TEXT, TCL_TOKEN_BS tokens. */ char buffer[TCL_UTF_MAX]; CONST char *name, *p; int numObjsToConcat, nameBytes, localVarName, localVar; int length, i, code; unsigned char *entryCodeNext = envPtr->codeNext; #ifdef TCL_TIP280 #define NUM_STATIC_POS 20 int isLiteral, maxNumCL, numCL; int* clPosition = NULL; /* * For the handling of continuation lines in literals we first check if * this is actually a literal. For if not we can forego the additional * processing. Otherwise we pre-allocate a small table to store the * locations of all continuation lines we find in this literal, if * any. The table is extended if needed. * * Note: Different to the equivalent code in function * 'EvalTokensStandard()' (see file "tclBasic.c") we do not seem to need * the 'adjust' variable. We also do not seem to need code which merges * continuation line information of multiple words which concat'd at * runtime. Either that or I have not managed to find a test case for * these two possibilities yet. It might be a difference between compile- * versus runtime processing. */ numCL = 0; maxNumCL = 0; isLiteral = 1; for (i=0 ; i < count; i++) { if ((tokenPtr[i].type != TCL_TOKEN_TEXT) && (tokenPtr[i].type != TCL_TOKEN_BS)) { isLiteral = 0; break; } } if (isLiteral) { maxNumCL = NUM_STATIC_POS; clPosition = (int*) ckalloc (maxNumCL*sizeof(int)); } #endif Tcl_DStringInit(&textBuffer); numObjsToConcat = 0; for ( ; count > 0; count--, tokenPtr++) { switch (tokenPtr->type) { case TCL_TOKEN_TEXT: Tcl_DStringAppend(&textBuffer, tokenPtr->start, tokenPtr->size); break; case TCL_TOKEN_BS: length = TclParseBackslash(tokenPtr->start, tokenPtr->size, (int *) NULL, buffer); Tcl_DStringAppend(&textBuffer, buffer, length); #ifdef TCL_TIP280 /* * If the backslash sequence we found is in a literal, and * represented a continuation line, we compute and store its * location (as char offset to the beginning of the _result_ * script). We may have to extend the table of locations. * * Note that the continuation line information is relevant * even if the word we are processing is not a literal, as it * can affect nested commands. See the branch for * TCL_TOKEN_COMMAND below, where the adjustment we are * tracking here is taken into account. The good thing is that * we do not need a table of everything, just the number of * lines we have to add as correction. */ if ((length == 1) && (buffer[0] == ' ') && (tokenPtr->start[1] == '\n')) { if (isLiteral) { int clPos = Tcl_DStringLength (&textBuffer); if (numCL >= maxNumCL) { maxNumCL *= 2; clPosition = (int*) ckrealloc ((char*)clPosition, maxNumCL*sizeof(int)); } clPosition[numCL] = clPos; numCL ++; } } #endif break; case TCL_TOKEN_COMMAND: /* * Push any accumulated chars appearing before the command. */ if (Tcl_DStringLength(&textBuffer) > 0) { int literal; literal = TclRegisterLiteral(envPtr, Tcl_DStringValue(&textBuffer), Tcl_DStringLength(&textBuffer), /*onHeap*/ 0); TclEmitPush(literal, envPtr); numObjsToConcat++; Tcl_DStringFree(&textBuffer); #ifdef TCL_TIP280 if (numCL) { TclContinuationsEnter(envPtr->literalArrayPtr[literal].objPtr, numCL, clPosition); } numCL = 0; #endif } code = TclCompileScript(interp, tokenPtr->start+1, tokenPtr->size-2, /*nested*/ 0, envPtr); if (code != TCL_OK) { goto error; } numObjsToConcat++; break; case TCL_TOKEN_VARIABLE: /* * Push any accumulated chars appearing before the $. */ if (Tcl_DStringLength(&textBuffer) > 0) { int literal; literal = TclRegisterLiteral(envPtr, Tcl_DStringValue(&textBuffer), Tcl_DStringLength(&textBuffer), /*onHeap*/ 0); TclEmitPush(literal, envPtr); numObjsToConcat++; Tcl_DStringFree(&textBuffer); } /* * Determine how the variable name should be handled: if it contains * any namespace qualifiers it is not a local variable (localVarName=-1); * if it looks like an array element and the token has a single component, * it should not be created here [Bug 569438] (localVarName=0); otherwise, * the local variable can safely be created (localVarName=1). */ name = tokenPtr[1].start; nameBytes = tokenPtr[1].size; localVarName = -1; if (envPtr->procPtr != NULL) { localVarName = 1; for (i = 0, p = name; i < nameBytes; i++, p++) { if ((*p == ':') && (i < (nameBytes-1)) && (*(p+1) == ':')) { localVarName = -1; break; } else if ((*p == '(') && (tokenPtr->numComponents == 1) && (*(name + nameBytes - 1) == ')')) { localVarName = 0; break; } } } /* * Either push the variable's name, or find its index in * the array of local variables in a procedure frame. */ localVar = -1; if (localVarName != -1) { localVar = TclFindCompiledLocal(name, nameBytes, localVarName, /*flags*/ 0, envPtr->procPtr); } if (localVar < 0) { TclEmitPush(TclRegisterNewLiteral(envPtr, name, nameBytes), envPtr); } /* * Emit instructions to load the variable. */ if (tokenPtr->numComponents == 1) { if (localVar < 0) { TclEmitOpcode(INST_LOAD_SCALAR_STK, envPtr); } else if (localVar <= 255) { TclEmitInstInt1(INST_LOAD_SCALAR1, localVar, envPtr); } else { TclEmitInstInt4(INST_LOAD_SCALAR4, localVar, envPtr); } } else { code = TclCompileTokens(interp, tokenPtr+2, tokenPtr->numComponents-1, envPtr); if (code != TCL_OK) { char errorBuffer[150]; sprintf(errorBuffer, "\n (parsing index for array \"%.*s\")", ((nameBytes > 100)? 100 : nameBytes), name); Tcl_AddObjErrorInfo(interp, errorBuffer, -1); goto error; } if (localVar < 0) { TclEmitOpcode(INST_LOAD_ARRAY_STK, envPtr); } else if (localVar <= 255) { TclEmitInstInt1(INST_LOAD_ARRAY1, localVar, envPtr); } else { TclEmitInstInt4(INST_LOAD_ARRAY4, localVar, envPtr); } } numObjsToConcat++; count -= tokenPtr->numComponents; tokenPtr += tokenPtr->numComponents; break; default: panic("Unexpected token type in TclCompileTokens"); } } /* * Push any accumulated characters appearing at the end. */ if (Tcl_DStringLength(&textBuffer) > 0) { int literal; literal = TclRegisterLiteral(envPtr, Tcl_DStringValue(&textBuffer), Tcl_DStringLength(&textBuffer), /*onHeap*/ 0); TclEmitPush(literal, envPtr); numObjsToConcat++; #ifdef TCL_TIP280 if (numCL) { TclContinuationsEnter(envPtr->literalArrayPtr[literal].objPtr, numCL, clPosition); } numCL = 0; #endif } /* * If necessary, concatenate the parts of the word. */ while (numObjsToConcat > 255) { TclEmitInstInt1(INST_CONCAT1, 255, envPtr); numObjsToConcat -= 254; /* concat pushes 1 obj, the result */ } if (numObjsToConcat > 1) { TclEmitInstInt1(INST_CONCAT1, numObjsToConcat, envPtr); } /* * If the tokens yielded no instructions, push an empty string. */ if (envPtr->codeNext == entryCodeNext) { TclEmitPush(TclRegisterLiteral(envPtr, "", 0, /*onHeap*/ 0), envPtr); } code = TCL_OK; error: Tcl_DStringFree(&textBuffer); #ifdef TCL_TIP280 /* * Release the temp table we used to collect the locations of * continuation lines, if any. */ if (maxNumCL) { ckfree ((char*) clPosition); } #endif return code; } /* *---------------------------------------------------------------------- * * TclCompileCmdWord -- * * Given an array of parse tokens for a word containing one or more Tcl * commands, emit inline instructions to execute them. This procedure * differs from TclCompileTokens in that a simple word such as a loop * body enclosed in braces is not just pushed as a string, but is * itself parsed into tokens and compiled. * * Results: * The return value is a standard Tcl result. If an error occurs, an * error message is left in the interpreter's result. * * Side effects: * Instructions are added to envPtr to execute the tokens at runtime. * *---------------------------------------------------------------------- */ int TclCompileCmdWord(interp, tokenPtr, count, envPtr) Tcl_Interp *interp; /* Used for error and status reporting. */ Tcl_Token *tokenPtr; /* Pointer to first in an array of tokens * for a command word to compile inline. */ int count; /* Number of tokens to consider at tokenPtr. * Must be at least 1. */ CompileEnv *envPtr; /* Holds the resulting instructions. */ { int code; /* * Handle the common case: if there is a single text token, compile it * into an inline sequence of instructions. */ if ((count == 1) && (tokenPtr->type == TCL_TOKEN_TEXT)) { code = TclCompileScript(interp, tokenPtr->start, tokenPtr->size, /*nested*/ 0, envPtr); return code; } /* * Multiple tokens or the single token involves substitutions. Emit * instructions to invoke the eval command procedure at runtime on the * result of evaluating the tokens. */ code = TclCompileTokens(interp, tokenPtr, count, envPtr); if (code != TCL_OK) { return code; } TclEmitOpcode(INST_EVAL_STK, envPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * TclCompileExprWords -- * * Given an array of parse tokens representing one or more words that * contain a Tcl expression, emit inline instructions to execute the * expression. This procedure differs from TclCompileExpr in that it * supports Tcl's two-level substitution semantics for expressions that * appear as command words. * * Results: * The return value is a standard Tcl result. If an error occurs, an * error message is left in the interpreter's result. * * Side effects: * Instructions are added to envPtr to execute the expression. * *---------------------------------------------------------------------- */ int TclCompileExprWords(interp, tokenPtr, numWords, envPtr) Tcl_Interp *interp; /* Used for error and status reporting. */ Tcl_Token *tokenPtr; /* Points to first in an array of word * tokens tokens for the expression to * compile inline. */ int numWords; /* Number of word tokens starting at * tokenPtr. Must be at least 1. Each word * token contains one or more subtokens. */ CompileEnv *envPtr; /* Holds the resulting instructions. */ { Tcl_Token *wordPtr; int numBytes, i, code; CONST char *script; code = TCL_OK; /* * If the expression is a single word that doesn't require * substitutions, just compile its string into inline instructions. */ if ((numWords == 1) && (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD)) { script = tokenPtr[1].start; numBytes = tokenPtr[1].size; code = TclCompileExpr(interp, script, numBytes, envPtr); return code; } /* * Emit code to call the expr command proc at runtime. Concatenate the * (already substituted once) expr tokens with a space between each. */ wordPtr = tokenPtr; for (i = 0; i < numWords; i++) { code = TclCompileTokens(interp, wordPtr+1, wordPtr->numComponents, envPtr); if (code != TCL_OK) { break; } if (i < (numWords - 1)) { TclEmitPush(TclRegisterLiteral(envPtr, " ", 1, /*onHeap*/ 0), envPtr); } wordPtr += (wordPtr->numComponents + 1); } if (code == TCL_OK) { int concatItems = 2*numWords - 1; while (concatItems > 255) { TclEmitInstInt1(INST_CONCAT1, 255, envPtr); concatItems -= 254; } if (concatItems > 1) { TclEmitInstInt1(INST_CONCAT1, concatItems, envPtr); } TclEmitOpcode(INST_EXPR_STK, envPtr); } return code; } /* *---------------------------------------------------------------------- * * TclInitByteCodeObj -- * * Create a ByteCode structure and initialize it from a CompileEnv * compilation environment structure. The ByteCode structure is * smaller and contains just that information needed to execute * the bytecode instructions resulting from compiling a Tcl script. * The resulting structure is placed in the specified object. * * Results: * A newly constructed ByteCode object is stored in the internal * representation of the objPtr. * * Side effects: * A single heap object is allocated to hold the new ByteCode structure * and its code, object, command location, and aux data arrays. Note * that "ownership" (i.e., the pointers to) the Tcl objects and aux * data items will be handed over to the new ByteCode structure from * the CompileEnv structure. * *---------------------------------------------------------------------- */ void TclInitByteCodeObj(objPtr, envPtr) Tcl_Obj *objPtr; /* Points object that should be * initialized, and whose string rep * contains the source code. */ register CompileEnv *envPtr; /* Points to the CompileEnv structure from * which to create a ByteCode structure. */ { register ByteCode *codePtr; size_t codeBytes, objArrayBytes, exceptArrayBytes, cmdLocBytes; size_t auxDataArrayBytes, structureSize; register unsigned char *p; #ifdef TCL_COMPILE_DEBUG unsigned char *nextPtr; #endif int numLitObjects = envPtr->literalArrayNext; Namespace *namespacePtr; int i; #ifdef TCL_TIP280 int new; #endif Interp *iPtr; if (envPtr->iPtr == NULL) { Tcl_Panic("TclInitByteCodeObj() called on uninitialized CompileEnv"); } iPtr = envPtr->iPtr; codeBytes = (envPtr->codeNext - envPtr->codeStart); objArrayBytes = (envPtr->literalArrayNext * sizeof(Tcl_Obj *)); exceptArrayBytes = (envPtr->exceptArrayNext * sizeof(ExceptionRange)); auxDataArrayBytes = (envPtr->auxDataArrayNext * sizeof(AuxData)); cmdLocBytes = GetCmdLocEncodingSize(envPtr); /* * Compute the total number of bytes needed for this bytecode. */ structureSize = sizeof(ByteCode); structureSize += TCL_ALIGN(codeBytes); /* align object array */ structureSize += TCL_ALIGN(objArrayBytes); /* align exc range arr */ structureSize += TCL_ALIGN(exceptArrayBytes); /* align AuxData array */ structureSize += auxDataArrayBytes; structureSize += cmdLocBytes; if (envPtr->iPtr->varFramePtr != NULL) { namespacePtr = envPtr->iPtr->varFramePtr->nsPtr; } else { namespacePtr = envPtr->iPtr->globalNsPtr; } p = (unsigned char *) ckalloc((size_t) structureSize); codePtr = (ByteCode *) p; codePtr->interpHandle = TclHandlePreserve(iPtr->handle); codePtr->compileEpoch = iPtr->compileEpoch; codePtr->nsPtr = namespacePtr; codePtr->nsEpoch = namespacePtr->resolverEpoch; codePtr->refCount = 1; codePtr->flags = 0; codePtr->source = envPtr->source; codePtr->procPtr = envPtr->procPtr; codePtr->numCommands = envPtr->numCommands; codePtr->numSrcBytes = envPtr->numSrcBytes; codePtr->numCodeBytes = codeBytes; codePtr->numLitObjects = numLitObjects; codePtr->numExceptRanges = envPtr->exceptArrayNext; codePtr->numAuxDataItems = envPtr->auxDataArrayNext; codePtr->numCmdLocBytes = cmdLocBytes; codePtr->maxExceptDepth = envPtr->maxExceptDepth; codePtr->maxStackDepth = envPtr->maxStackDepth; p += sizeof(ByteCode); codePtr->codeStart = p; memcpy((VOID *) p, (VOID *) envPtr->codeStart, (size_t) codeBytes); p += TCL_ALIGN(codeBytes); /* align object array */ codePtr->objArrayPtr = (Tcl_Obj **) p; for (i = 0; i < numLitObjects; i++) { codePtr->objArrayPtr[i] = envPtr->literalArrayPtr[i].objPtr; } p += TCL_ALIGN(objArrayBytes); /* align exception range array */ if (exceptArrayBytes > 0) { codePtr->exceptArrayPtr = (ExceptionRange *) p; memcpy((VOID *) p, (VOID *) envPtr->exceptArrayPtr, (size_t) exceptArrayBytes); } else { codePtr->exceptArrayPtr = NULL; } p += TCL_ALIGN(exceptArrayBytes); /* align AuxData array */ if (auxDataArrayBytes > 0) { codePtr->auxDataArrayPtr = (AuxData *) p; memcpy((VOID *) p, (VOID *) envPtr->auxDataArrayPtr, (size_t) auxDataArrayBytes); } else { codePtr->auxDataArrayPtr = NULL; } p += auxDataArrayBytes; #ifndef TCL_COMPILE_DEBUG EncodeCmdLocMap(envPtr, codePtr, (unsigned char *) p); #else nextPtr = EncodeCmdLocMap(envPtr, codePtr, (unsigned char *) p); if (((size_t)(nextPtr - p)) != cmdLocBytes) { panic("TclInitByteCodeObj: encoded cmd location bytes %ld != expected size %ld\n", (nextPtr - p), cmdLocBytes); } #endif /* * Record various compilation-related statistics about the new ByteCode * structure. Don't include overhead for statistics-related fields. */ #ifdef TCL_COMPILE_STATS codePtr->structureSize = structureSize - (sizeof(size_t) + sizeof(Tcl_Time)); Tcl_GetTime(&(codePtr->createTime)); RecordByteCodeStats(codePtr); #endif /* TCL_COMPILE_STATS */ /* * Free the old internal rep then convert the object to a * bytecode object by making its internal rep point to the just * compiled ByteCode. */ if ((objPtr->typePtr != NULL) && (objPtr->typePtr->freeIntRepProc != NULL)) { (*objPtr->typePtr->freeIntRepProc)(objPtr); } objPtr->internalRep.otherValuePtr = (VOID *) codePtr; objPtr->typePtr = &tclByteCodeType; #ifdef TCL_TIP280 /* TIP #280. Associate the extended per-word line information with the * byte code object (internal rep), for use with the bc compiler. */ Tcl_SetHashValue (Tcl_CreateHashEntry (iPtr->lineBCPtr, (char*) codePtr, &new), envPtr->extCmdMapPtr); envPtr->extCmdMapPtr = NULL; #endif /* We've used up the CompileEnv. Mark as uninitialized. */ envPtr->iPtr = NULL; } /* *---------------------------------------------------------------------- * * LogCompilationInfo -- * * This procedure is invoked after an error occurs during compilation. * It adds information to the "errorInfo" variable to describe the * command that was being compiled when the error occurred. * * Results: * None. * * Side effects: * Information about the command is added to errorInfo and the * line number stored internally in the interpreter is set. If this * is the first call to this procedure or Tcl_AddObjErrorInfo since * an error occurred, then old information in errorInfo is * deleted. * *---------------------------------------------------------------------- */ static void LogCompilationInfo(interp, script, command, length) Tcl_Interp *interp; /* Interpreter in which to log the * information. */ CONST char *script; /* First character in script containing * command (must be <= command). */ CONST char *command; /* First character in command that * generated the error. */ int length; /* Number of bytes in command (-1 means * use all bytes up to first null byte). */ { char buffer[200]; register CONST char *p; char *ellipsis = ""; Interp *iPtr = (Interp *) interp; if (iPtr->flags & ERR_ALREADY_LOGGED) { /* * Someone else has already logged error information for this * command; we shouldn't add anything more. */ return; } /* * Compute the line number where the error occurred. */ iPtr->errorLine = 1; for (p = script; p != command; p++) { if (*p == '\n') { iPtr->errorLine++; } } /* * Create an error message to add to errorInfo, including up to a * maximum number of characters of the command. */ if (length < 0) { length = strlen(command); } if (length > 150) { length = 150; ellipsis = "..."; } while ( (command[length] & 0xC0) == 0x80 ) { /* * Back up truncation point so that we don't truncate in the * middle of a multi-byte character (in UTF-8) */ length--; ellipsis = "..."; } sprintf(buffer, "\n while compiling\n\"%.*s%s\"", length, command, ellipsis); Tcl_AddObjErrorInfo(interp, buffer, -1); } /* *---------------------------------------------------------------------- * * TclFindCompiledLocal -- * * This procedure is called at compile time to look up and optionally * allocate an entry ("slot") for a variable in a procedure's array of * local variables. If the variable's name is NULL, a new temporary * variable is always created. (Such temporary variables can only be * referenced using their slot index.) * * Results: * If create is 0 and the name is non-NULL, then if the variable is * found, the index of its entry in the procedure's array of local * variables is returned; otherwise -1 is returned. If name is NULL, * the index of a new temporary variable is returned. Finally, if * create is 1 and name is non-NULL, the index of a new entry is * returned. * * Side effects: * Creates and registers a new local variable if create is 1 and * the variable is unknown, or if the name is NULL. * *---------------------------------------------------------------------- */ int TclFindCompiledLocal(name, nameBytes, create, flags, procPtr) register CONST char *name; /* Points to first character of the name of * a scalar or array variable. If NULL, a * temporary var should be created. */ int nameBytes; /* Number of bytes in the name. */ int create; /* If 1, allocate a local frame entry for * the variable if it is new. */ int flags; /* Flag bits for the compiled local if * created. Only VAR_SCALAR, VAR_ARRAY, and * VAR_LINK make sense. */ register Proc *procPtr; /* Points to structure describing procedure * containing the variable reference. */ { register CompiledLocal *localPtr; int localVar = -1; register int i; /* * If not creating a temporary, does a local variable of the specified * name already exist? */ if (name != NULL) { int localCt = procPtr->numCompiledLocals; localPtr = procPtr->firstLocalPtr; for (i = 0; i < localCt; i++) { if (!TclIsVarTemporary(localPtr)) { char *localName = localPtr->name; if ((nameBytes == localPtr->nameLength) && (strncmp(name, localName, (unsigned) nameBytes) == 0)) { return i; } } localPtr = localPtr->nextPtr; } } /* * Create a new variable if appropriate. */ if (create || (name == NULL)) { localVar = procPtr->numCompiledLocals; localPtr = (CompiledLocal *) ckalloc((unsigned) (sizeof(CompiledLocal) - sizeof(localPtr->name) + nameBytes+1)); if (procPtr->firstLocalPtr == NULL) { procPtr->firstLocalPtr = procPtr->lastLocalPtr = localPtr; } else { procPtr->lastLocalPtr->nextPtr = localPtr; procPtr->lastLocalPtr = localPtr; } localPtr->nextPtr = NULL; localPtr->nameLength = nameBytes; localPtr->frameIndex = localVar; localPtr->flags = flags | VAR_UNDEFINED; if (name == NULL) { localPtr->flags |= VAR_TEMPORARY; } localPtr->defValuePtr = NULL; localPtr->resolveInfo = NULL; if (name != NULL) { memcpy((VOID *) localPtr->name, (VOID *) name, (size_t) nameBytes); } localPtr->name[nameBytes] = '\0'; procPtr->numCompiledLocals++; } return localVar; } /* *---------------------------------------------------------------------- * * TclInitCompiledLocals -- * * This routine is invoked in order to initialize the compiled * locals table for a new call frame. * * Results: * None. * * Side effects: * May invoke various name resolvers in order to determine which * variables are being referenced at runtime. * *---------------------------------------------------------------------- */ void TclInitCompiledLocals(interp, framePtr, nsPtr) Tcl_Interp *interp; /* Current interpreter. */ CallFrame *framePtr; /* Call frame to initialize. */ Namespace *nsPtr; /* Pointer to current namespace. */ { register CompiledLocal *localPtr; Interp *iPtr = (Interp*) interp; Tcl_ResolvedVarInfo *vinfo, *resVarInfo; Var *varPtr = framePtr->compiledLocals; Var *resolvedVarPtr; ResolverScheme *resPtr; int result; /* * Initialize the array of local variables stored in the call frame. * Some variables may have special resolution rules. In that case, * we call their "resolver" procs to get our hands on the variable, * and we make the compiled local a link to the real variable. */ for (localPtr = framePtr->procPtr->firstLocalPtr; localPtr != NULL; localPtr = localPtr->nextPtr) { /* * Check to see if this local is affected by namespace or * interp resolvers. The resolver to use is cached for the * next invocation of the procedure. */ if (!(localPtr->flags & (VAR_ARGUMENT|VAR_TEMPORARY|VAR_RESOLVED)) && (nsPtr->compiledVarResProc || iPtr->resolverPtr)) { resPtr = iPtr->resolverPtr; if (nsPtr->compiledVarResProc) { result = (*nsPtr->compiledVarResProc)(nsPtr->interp, localPtr->name, localPtr->nameLength, (Tcl_Namespace *) nsPtr, &vinfo); } else { result = TCL_CONTINUE; } while ((result == TCL_CONTINUE) && resPtr) { if (resPtr->compiledVarResProc) { result = (*resPtr->compiledVarResProc)(nsPtr->interp, localPtr->name, localPtr->nameLength, (Tcl_Namespace *) nsPtr, &vinfo); } resPtr = resPtr->nextPtr; } if (result == TCL_OK) { localPtr->resolveInfo = vinfo; localPtr->flags |= VAR_RESOLVED; } } /* * Now invoke the resolvers to determine the exact variables that * should be used. */ resVarInfo = localPtr->resolveInfo; resolvedVarPtr = NULL; if (resVarInfo && resVarInfo->fetchProc) { resolvedVarPtr = (Var*) (*resVarInfo->fetchProc)(interp, resVarInfo); } if (resolvedVarPtr) { varPtr->name = localPtr->name; /* will be just '\0' if temp var */ varPtr->nsPtr = NULL; varPtr->hPtr = NULL; varPtr->refCount = 0; varPtr->tracePtr = NULL; varPtr->searchPtr = NULL; varPtr->flags = 0; TclSetVarLink(varPtr); varPtr->value.linkPtr = resolvedVarPtr; resolvedVarPtr->refCount++; } else { varPtr->value.objPtr = NULL; varPtr->name = localPtr->name; /* will be just '\0' if temp var */ varPtr->nsPtr = NULL; varPtr->hPtr = NULL; varPtr->refCount = 0; varPtr->tracePtr = NULL; varPtr->searchPtr = NULL; varPtr->flags = localPtr->flags; } varPtr++; } } /* *---------------------------------------------------------------------- * * TclExpandCodeArray -- * * Procedure that uses malloc to allocate more storage for a * CompileEnv's code array. * * Results: * None. * * Side effects: * The byte code array in *envPtr is reallocated to a new array of * double the size, and if envPtr->mallocedCodeArray is non-zero the * old array is freed. Byte codes are copied from the old array to the * new one. * *---------------------------------------------------------------------- */ void TclExpandCodeArray(envArgPtr) void *envArgPtr; /* Points to the CompileEnv whose code array * must be enlarged. */ { CompileEnv *envPtr = (CompileEnv*) envArgPtr; /* Points to the CompileEnv whose code array * must be enlarged. */ /* * envPtr->codeNext is equal to envPtr->codeEnd. The currently defined * code bytes are stored between envPtr->codeStart and * (envPtr->codeNext - 1) [inclusive]. */ size_t currBytes = (envPtr->codeNext - envPtr->codeStart); size_t newBytes = 2*(envPtr->codeEnd - envPtr->codeStart); unsigned char *newPtr = (unsigned char *) ckalloc((unsigned) newBytes); /* * Copy from old code array to new, free old code array if needed, and * mark new code array as malloced. */ memcpy((VOID *) newPtr, (VOID *) envPtr->codeStart, currBytes); if (envPtr->mallocedCodeArray) { ckfree((char *) envPtr->codeStart); } envPtr->codeStart = newPtr; envPtr->codeNext = (newPtr + currBytes); envPtr->codeEnd = (newPtr + newBytes); envPtr->mallocedCodeArray = 1; } /* *---------------------------------------------------------------------- * * EnterCmdStartData -- * * Registers the starting source and bytecode location of a * command. This information is used at runtime to map between * instruction pc and source locations. * * Results: * None. * * Side effects: * Inserts source and code location information into the compilation * environment envPtr for the command at index cmdIndex. The * compilation environment's CmdLocation array is grown if necessary. * *---------------------------------------------------------------------- */ static void EnterCmdStartData(envPtr, cmdIndex, srcOffset, codeOffset) CompileEnv *envPtr; /* Points to the compilation environment * structure in which to enter command * location information. */ int cmdIndex; /* Index of the command whose start data * is being set. */ int srcOffset; /* Offset of first char of the command. */ int codeOffset; /* Offset of first byte of command code. */ { CmdLocation *cmdLocPtr; if ((cmdIndex < 0) || (cmdIndex >= envPtr->numCommands)) { panic("EnterCmdStartData: bad command index %d\n", cmdIndex); } if (cmdIndex >= envPtr->cmdMapEnd) { /* * Expand the command location array by allocating more storage from * the heap. The currently allocated CmdLocation entries are stored * from cmdMapPtr[0] up to cmdMapPtr[envPtr->cmdMapEnd] (inclusive). */ size_t currElems = envPtr->cmdMapEnd; size_t newElems = 2*currElems; size_t currBytes = currElems * sizeof(CmdLocation); size_t newBytes = newElems * sizeof(CmdLocation); CmdLocation *newPtr = (CmdLocation *) ckalloc((unsigned) newBytes); /* * Copy from old command location array to new, free old command * location array if needed, and mark new array as malloced. */ memcpy((VOID *) newPtr, (VOID *) envPtr->cmdMapPtr, currBytes); if (envPtr->mallocedCmdMap) { ckfree((char *) envPtr->cmdMapPtr); } envPtr->cmdMapPtr = (CmdLocation *) newPtr; envPtr->cmdMapEnd = newElems; envPtr->mallocedCmdMap = 1; } if (cmdIndex > 0) { if (codeOffset < envPtr->cmdMapPtr[cmdIndex-1].codeOffset) { panic("EnterCmdStartData: cmd map not sorted by code offset"); } } cmdLocPtr = &(envPtr->cmdMapPtr[cmdIndex]); cmdLocPtr->codeOffset = codeOffset; cmdLocPtr->srcOffset = srcOffset; cmdLocPtr->numSrcBytes = -1; cmdLocPtr->numCodeBytes = -1; } /* *---------------------------------------------------------------------- * * EnterCmdExtentData -- * * Registers the source and bytecode length for a command. This * information is used at runtime to map between instruction pc and * source locations. * * Results: * None. * * Side effects: * Inserts source and code length information into the compilation * environment envPtr for the command at index cmdIndex. Starting * source and bytecode information for the command must already * have been registered. * *---------------------------------------------------------------------- */ static void EnterCmdExtentData(envPtr, cmdIndex, numSrcBytes, numCodeBytes) CompileEnv *envPtr; /* Points to the compilation environment * structure in which to enter command * location information. */ int cmdIndex; /* Index of the command whose source and * code length data is being set. */ int numSrcBytes; /* Number of command source chars. */ int numCodeBytes; /* Offset of last byte of command code. */ { CmdLocation *cmdLocPtr; if ((cmdIndex < 0) || (cmdIndex >= envPtr->numCommands)) { panic("EnterCmdExtentData: bad command index %d\n", cmdIndex); } if (cmdIndex > envPtr->cmdMapEnd) { panic("EnterCmdExtentData: missing start data for command %d\n", cmdIndex); } cmdLocPtr = &(envPtr->cmdMapPtr[cmdIndex]); cmdLocPtr->numSrcBytes = numSrcBytes; cmdLocPtr->numCodeBytes = numCodeBytes; } #ifdef TCL_TIP280 /* *---------------------------------------------------------------------- * TIP #280 * * EnterCmdWordData -- * * Registers the lines for the words of a command. This information * is used at runtime by 'info frame'. * * Results: * None. * * Side effects: * Inserts word location information into the compilation * environment envPtr for the command at index cmdIndex. The * compilation environment's ExtCmdLoc.ECL array is grown if necessary. * *---------------------------------------------------------------------- */ static void EnterCmdWordData(eclPtr, srcOffset, tokenPtr, cmd, len, numWords, line, clNext, wlines, envPtr) ExtCmdLoc *eclPtr; /* Points to the map environment * structure in which to enter command * location information. */ int srcOffset; /* Offset of first char of the command. */ Tcl_Token* tokenPtr; CONST char* cmd; int len; int numWords; int line; int* clNext; int** wlines; CompileEnv* envPtr; { ECL* ePtr; int wordIdx; CONST char* last; int wordLine; int* wordNext; int* wwlines; if (eclPtr->nuloc >= eclPtr->nloc) { /* * Expand the ECL array by allocating more storage from the * heap. The currently allocated ECL entries are stored from * eclPtr->loc[0] up to eclPtr->loc[eclPtr->nuloc-1] (inclusive). */ size_t currElems = eclPtr->nloc; size_t newElems = (currElems ? 2*currElems : 1); size_t currBytes = currElems * sizeof(ECL); size_t newBytes = newElems * sizeof(ECL); ECL * newPtr = (ECL *) ckalloc((unsigned) newBytes); /* * Copy from old ECL array to new, free old ECL array if * needed. */ if (currBytes) { memcpy((VOID *) newPtr, (VOID *) eclPtr->loc, currBytes); } if (eclPtr->loc != NULL) { ckfree((char *) eclPtr->loc); } eclPtr->loc = (ECL *) newPtr; eclPtr->nloc = newElems; } ePtr = &eclPtr->loc [eclPtr->nuloc]; ePtr->srcOffset = srcOffset; ePtr->line = (int*) ckalloc (numWords * sizeof (int)); ePtr->next = (int**) ckalloc (numWords * sizeof (int*)); ePtr->nline = numWords; wwlines = (int*) ckalloc (numWords * sizeof (int)); last = cmd; wordLine = line; wordNext = clNext; for (wordIdx = 0; wordIdx < numWords; wordIdx++, tokenPtr += (tokenPtr->numComponents + 1)) { TclAdvanceLines (&wordLine, last, tokenPtr->start); TclAdvanceContinuations (&wordLine, &wordNext, tokenPtr->start - envPtr->source); wwlines [wordIdx] = (TclWordKnownAtCompileTime (tokenPtr) ? wordLine : -1); ePtr->line [wordIdx] = wordLine; ePtr->next [wordIdx] = wordNext; last = tokenPtr->start; } *wlines = wwlines; eclPtr->nuloc ++; } #endif /* *---------------------------------------------------------------------- * * TclCreateExceptRange -- * * Procedure that allocates and initializes a new ExceptionRange * structure of the specified kind in a CompileEnv. * * Results: * Returns the index for the newly created ExceptionRange. * * Side effects: * If there is not enough room in the CompileEnv's ExceptionRange * array, the array in expanded: a new array of double the size is * allocated, if envPtr->mallocedExceptArray is non-zero the old * array is freed, and ExceptionRange entries are copied from the old * array to the new one. * *---------------------------------------------------------------------- */ int TclCreateExceptRange(type, envPtr) ExceptionRangeType type; /* The kind of ExceptionRange desired. */ register CompileEnv *envPtr;/* Points to CompileEnv for which to * create a new ExceptionRange structure. */ { register ExceptionRange *rangePtr; int index = envPtr->exceptArrayNext; if (index >= envPtr->exceptArrayEnd) { /* * Expand the ExceptionRange array. The currently allocated entries * are stored between elements 0 and (envPtr->exceptArrayNext - 1) * [inclusive]. */ size_t currBytes = envPtr->exceptArrayNext * sizeof(ExceptionRange); int newElems = 2*envPtr->exceptArrayEnd; size_t newBytes = newElems * sizeof(ExceptionRange); ExceptionRange *newPtr = (ExceptionRange *) ckalloc((unsigned) newBytes); /* * Copy from old ExceptionRange array to new, free old * ExceptionRange array if needed, and mark the new ExceptionRange * array as malloced. */ memcpy((VOID *) newPtr, (VOID *) envPtr->exceptArrayPtr, currBytes); if (envPtr->mallocedExceptArray) { ckfree((char *) envPtr->exceptArrayPtr); } envPtr->exceptArrayPtr = (ExceptionRange *) newPtr; envPtr->exceptArrayEnd = newElems; envPtr->mallocedExceptArray = 1; } envPtr->exceptArrayNext++; rangePtr = &(envPtr->exceptArrayPtr[index]); rangePtr->type = type; rangePtr->nestingLevel = envPtr->exceptDepth; rangePtr->codeOffset = -1; rangePtr->numCodeBytes = -1; rangePtr->breakOffset = -1; rangePtr->continueOffset = -1; rangePtr->catchOffset = -1; return index; } /* *---------------------------------------------------------------------- * * TclCreateAuxData -- * * Procedure that allocates and initializes a new AuxData structure in * a CompileEnv's array of compilation auxiliary data records. These * AuxData records hold information created during compilation by * CompileProcs and used by instructions during execution. * * Results: * Returns the index for the newly created AuxData structure. * * Side effects: * If there is not enough room in the CompileEnv's AuxData array, * the AuxData array in expanded: a new array of double the size * is allocated, if envPtr->mallocedAuxDataArray is non-zero * the old array is freed, and AuxData entries are copied from * the old array to the new one. * *---------------------------------------------------------------------- */ int TclCreateAuxData(clientData, typePtr, envPtr) ClientData clientData; /* The compilation auxiliary data to store * in the new aux data record. */ AuxDataType *typePtr; /* Pointer to the type to attach to this AuxData */ register CompileEnv *envPtr;/* Points to the CompileEnv for which a new * aux data structure is to be allocated. */ { int index; /* Index for the new AuxData structure. */ register AuxData *auxDataPtr; /* Points to the new AuxData structure */ index = envPtr->auxDataArrayNext; if (index >= envPtr->auxDataArrayEnd) { /* * Expand the AuxData array. The currently allocated entries are * stored between elements 0 and (envPtr->auxDataArrayNext - 1) * [inclusive]. */ size_t currBytes = envPtr->auxDataArrayNext * sizeof(AuxData); int newElems = 2*envPtr->auxDataArrayEnd; size_t newBytes = newElems * sizeof(AuxData); AuxData *newPtr = (AuxData *) ckalloc((unsigned) newBytes); /* * Copy from old AuxData array to new, free old AuxData array if * needed, and mark the new AuxData array as malloced. */ memcpy((VOID *) newPtr, (VOID *) envPtr->auxDataArrayPtr, currBytes); if (envPtr->mallocedAuxDataArray) { ckfree((char *) envPtr->auxDataArrayPtr); } envPtr->auxDataArrayPtr = newPtr; envPtr->auxDataArrayEnd = newElems; envPtr->mallocedAuxDataArray = 1; } envPtr->auxDataArrayNext++; auxDataPtr = &(envPtr->auxDataArrayPtr[index]); auxDataPtr->clientData = clientData; auxDataPtr->type = typePtr; return index; } /* *---------------------------------------------------------------------- * * TclInitJumpFixupArray -- * * Initializes a JumpFixupArray structure to hold some number of * jump fixup entries. * * Results: * None. * * Side effects: * The JumpFixupArray structure is initialized. * *---------------------------------------------------------------------- */ void TclInitJumpFixupArray(fixupArrayPtr) register JumpFixupArray *fixupArrayPtr; /* Points to the JumpFixupArray structure * to initialize. */ { fixupArrayPtr->fixup = fixupArrayPtr->staticFixupSpace; fixupArrayPtr->next = 0; fixupArrayPtr->end = (JUMPFIXUP_INIT_ENTRIES - 1); fixupArrayPtr->mallocedArray = 0; } /* *---------------------------------------------------------------------- * * TclExpandJumpFixupArray -- * * Procedure that uses malloc to allocate more storage for a * jump fixup array. * * Results: * None. * * Side effects: * The jump fixup array in *fixupArrayPtr is reallocated to a new array * of double the size, and if fixupArrayPtr->mallocedArray is non-zero * the old array is freed. Jump fixup structures are copied from the * old array to the new one. * *---------------------------------------------------------------------- */ void TclExpandJumpFixupArray(fixupArrayPtr) register JumpFixupArray *fixupArrayPtr; /* Points to the JumpFixupArray structure * to enlarge. */ { /* * The currently allocated jump fixup entries are stored from fixup[0] * up to fixup[fixupArrayPtr->fixupNext] (*not* inclusive). We assume * fixupArrayPtr->fixupNext is equal to fixupArrayPtr->fixupEnd. */ size_t currBytes = fixupArrayPtr->next * sizeof(JumpFixup); int newElems = 2*(fixupArrayPtr->end + 1); size_t newBytes = newElems * sizeof(JumpFixup); JumpFixup *newPtr = (JumpFixup *) ckalloc((unsigned) newBytes); /* * Copy from the old array to new, free the old array if needed, * and mark the new array as malloced. */ memcpy((VOID *) newPtr, (VOID *) fixupArrayPtr->fixup, currBytes); if (fixupArrayPtr->mallocedArray) { ckfree((char *) fixupArrayPtr->fixup); } fixupArrayPtr->fixup = (JumpFixup *) newPtr; fixupArrayPtr->end = newElems; fixupArrayPtr->mallocedArray = 1; } /* *---------------------------------------------------------------------- * * TclFreeJumpFixupArray -- * * Free any storage allocated in a jump fixup array structure. * * Results: * None. * * Side effects: * Allocated storage in the JumpFixupArray structure is freed. * *---------------------------------------------------------------------- */ void TclFreeJumpFixupArray(fixupArrayPtr) register JumpFixupArray *fixupArrayPtr; /* Points to the JumpFixupArray structure * to free. */ { if (fixupArrayPtr->mallocedArray) { ckfree((char *) fixupArrayPtr->fixup); } } /* *---------------------------------------------------------------------- * * TclEmitForwardJump -- * * Procedure to emit a two-byte forward jump of kind "jumpType". Since * the jump may later have to be grown to five bytes if the jump target * is more than, say, 127 bytes away, this procedure also initializes a * JumpFixup record with information about the jump. * * Results: * None. * * Side effects: * The JumpFixup record pointed to by "jumpFixupPtr" is initialized * with information needed later if the jump is to be grown. Also, * a two byte jump of the designated type is emitted at the current * point in the bytecode stream. * *---------------------------------------------------------------------- */ void TclEmitForwardJump(envPtr, jumpType, jumpFixupPtr) CompileEnv *envPtr; /* Points to the CompileEnv structure that * holds the resulting instruction. */ TclJumpType jumpType; /* Indicates the kind of jump: if true or * false or unconditional. */ JumpFixup *jumpFixupPtr; /* Points to the JumpFixup structure to * initialize with information about this * forward jump. */ { /* * Initialize the JumpFixup structure: * - codeOffset is offset of first byte of jump below * - cmdIndex is index of the command after the current one * - exceptIndex is the index of the first ExceptionRange after * the current one. */ jumpFixupPtr->jumpType = jumpType; jumpFixupPtr->codeOffset = (envPtr->codeNext - envPtr->codeStart); jumpFixupPtr->cmdIndex = envPtr->numCommands; jumpFixupPtr->exceptIndex = envPtr->exceptArrayNext; switch (jumpType) { case TCL_UNCONDITIONAL_JUMP: TclEmitInstInt1(INST_JUMP1, 0, envPtr); break; case TCL_TRUE_JUMP: TclEmitInstInt1(INST_JUMP_TRUE1, 0, envPtr); break; default: TclEmitInstInt1(INST_JUMP_FALSE1, 0, envPtr); break; } } /* *---------------------------------------------------------------------- * * TclFixupForwardJump -- * * Procedure that updates a previously-emitted forward jump to jump * a specified number of bytes, "jumpDist". If necessary, the jump is * grown from two to five bytes; this is done if the jump distance is * greater than "distThreshold" (normally 127 bytes). The jump is * described by a JumpFixup record previously initialized by * TclEmitForwardJump. * * Results: * 1 if the jump was grown and subsequent instructions had to be moved; * otherwise 0. This result is returned to allow callers to update * any additional code offsets they may hold. * * Side effects: * The jump may be grown and subsequent instructions moved. If this * happens, the code offsets for any commands and any ExceptionRange * records between the jump and the current code address will be * updated to reflect the moved code. Also, the bytecode instruction * array in the CompileEnv structure may be grown and reallocated. * *---------------------------------------------------------------------- */ int TclFixupForwardJump(envPtr, jumpFixupPtr, jumpDist, distThreshold) CompileEnv *envPtr; /* Points to the CompileEnv structure that * holds the resulting instruction. */ JumpFixup *jumpFixupPtr; /* Points to the JumpFixup structure that * describes the forward jump. */ int jumpDist; /* Jump distance to set in jump * instruction. */ int distThreshold; /* Maximum distance before the two byte * jump is grown to five bytes. */ { unsigned char *jumpPc, *p; int firstCmd, lastCmd, firstRange, lastRange, k; unsigned int numBytes; if (jumpDist <= distThreshold) { jumpPc = (envPtr->codeStart + jumpFixupPtr->codeOffset); switch (jumpFixupPtr->jumpType) { case TCL_UNCONDITIONAL_JUMP: TclUpdateInstInt1AtPc(INST_JUMP1, jumpDist, jumpPc); break; case TCL_TRUE_JUMP: TclUpdateInstInt1AtPc(INST_JUMP_TRUE1, jumpDist, jumpPc); break; default: TclUpdateInstInt1AtPc(INST_JUMP_FALSE1, jumpDist, jumpPc); break; } return 0; } /* * We must grow the jump then move subsequent instructions down. * Note that if we expand the space for generated instructions, * code addresses might change; be careful about updating any of * these addresses held in variables. */ if ((envPtr->codeNext + 3) > envPtr->codeEnd) { TclExpandCodeArray(envPtr); } jumpPc = (envPtr->codeStart + jumpFixupPtr->codeOffset); numBytes = envPtr->codeNext-jumpPc-2; p = jumpPc+2; memmove(p+3, p, numBytes); envPtr->codeNext += 3; jumpDist += 3; switch (jumpFixupPtr->jumpType) { case TCL_UNCONDITIONAL_JUMP: TclUpdateInstInt4AtPc(INST_JUMP4, jumpDist, jumpPc); break; case TCL_TRUE_JUMP: TclUpdateInstInt4AtPc(INST_JUMP_TRUE4, jumpDist, jumpPc); break; default: TclUpdateInstInt4AtPc(INST_JUMP_FALSE4, jumpDist, jumpPc); break; } /* * Adjust the code offsets for any commands and any ExceptionRange * records between the jump and the current code address. */ firstCmd = jumpFixupPtr->cmdIndex; lastCmd = (envPtr->numCommands - 1); if (firstCmd < lastCmd) { for (k = firstCmd; k <= lastCmd; k++) { (envPtr->cmdMapPtr[k]).codeOffset += 3; } } firstRange = jumpFixupPtr->exceptIndex; lastRange = (envPtr->exceptArrayNext - 1); for (k = firstRange; k <= lastRange; k++) { ExceptionRange *rangePtr = &(envPtr->exceptArrayPtr[k]); rangePtr->codeOffset += 3; switch (rangePtr->type) { case LOOP_EXCEPTION_RANGE: rangePtr->breakOffset += 3; if (rangePtr->continueOffset != -1) { rangePtr->continueOffset += 3; } break; case CATCH_EXCEPTION_RANGE: rangePtr->catchOffset += 3; break; default: panic("TclFixupForwardJump: bad ExceptionRange type %d\n", rangePtr->type); } } return 1; /* the jump was grown */ } /* *---------------------------------------------------------------------- * * TclGetInstructionTable -- * * Returns a pointer to the table describing Tcl bytecode instructions. * This procedure is defined so that clients can access the pointer from * outside the TCL DLLs. * * Results: * Returns a pointer to the global instruction table, same as the * expression (&tclInstructionTable[0]). * * Side effects: * None. * *---------------------------------------------------------------------- */ void * /* == InstructionDesc* == */ TclGetInstructionTable() { return &tclInstructionTable[0]; } /* *-------------------------------------------------------------- * * TclRegisterAuxDataType -- * * This procedure is called to register a new AuxData type * in the table of all AuxData types supported by Tcl. * * Results: * None. * * Side effects: * The type is registered in the AuxData type table. If there was already * a type with the same name as in typePtr, it is replaced with the * new type. * *-------------------------------------------------------------- */ void TclRegisterAuxDataType(typePtr) AuxDataType *typePtr; /* Information about object type; * storage must be statically * allocated (must live forever). */ { register Tcl_HashEntry *hPtr; int new; Tcl_MutexLock(&tableMutex); if (!auxDataTypeTableInitialized) { TclInitAuxDataTypeTable(); } /* * If there's already a type with the given name, remove it. */ hPtr = Tcl_FindHashEntry(&auxDataTypeTable, typePtr->name); if (hPtr != (Tcl_HashEntry *) NULL) { Tcl_DeleteHashEntry(hPtr); } /* * Now insert the new object type. */ hPtr = Tcl_CreateHashEntry(&auxDataTypeTable, typePtr->name, &new); if (new) { Tcl_SetHashValue(hPtr, typePtr); } Tcl_MutexUnlock(&tableMutex); } /* *---------------------------------------------------------------------- * * TclGetAuxDataType -- * * This procedure looks up an Auxdata type by name. * * Results: * If an AuxData type with name matching "typeName" is found, a pointer * to its AuxDataType structure is returned; otherwise, NULL is returned. * * Side effects: * None. * *---------------------------------------------------------------------- */ AuxDataType * TclGetAuxDataType(typeName) char *typeName; /* Name of AuxData type to look up. */ { register Tcl_HashEntry *hPtr; AuxDataType *typePtr = NULL; Tcl_MutexLock(&tableMutex); if (!auxDataTypeTableInitialized) { TclInitAuxDataTypeTable(); } hPtr = Tcl_FindHashEntry(&auxDataTypeTable, typeName); if (hPtr != (Tcl_HashEntry *) NULL) { typePtr = (AuxDataType *) Tcl_GetHashValue(hPtr); } Tcl_MutexUnlock(&tableMutex); return typePtr; } /* *-------------------------------------------------------------- * * TclInitAuxDataTypeTable -- * * This procedure is invoked to perform once-only initialization of * the AuxData type table. It also registers the AuxData types defined in * this file. * * Results: * None. * * Side effects: * Initializes the table of defined AuxData types "auxDataTypeTable" with * builtin AuxData types defined in this file. * *-------------------------------------------------------------- */ void TclInitAuxDataTypeTable() { /* * The table mutex must already be held before this routine is invoked. */ auxDataTypeTableInitialized = 1; Tcl_InitHashTable(&auxDataTypeTable, TCL_STRING_KEYS); /* * There is only one AuxData type at this time, so register it here. */ TclRegisterAuxDataType(&tclForeachInfoType); } /* *---------------------------------------------------------------------- * * TclFinalizeAuxDataTypeTable -- * * This procedure is called by Tcl_Finalize after all exit handlers * have been run to free up storage associated with the table of AuxData * types. This procedure is called by TclFinalizeExecution() which * is called by Tcl_Finalize(). * * Results: * None. * * Side effects: * Deletes all entries in the hash table of AuxData types. * *---------------------------------------------------------------------- */ void TclFinalizeAuxDataTypeTable() { Tcl_MutexLock(&tableMutex); if (auxDataTypeTableInitialized) { Tcl_DeleteHashTable(&auxDataTypeTable); auxDataTypeTableInitialized = 0; } Tcl_MutexUnlock(&tableMutex); } /* *---------------------------------------------------------------------- * * GetCmdLocEncodingSize -- * * Computes the total number of bytes needed to encode the command * location information for some compiled code. * * Results: * The byte count needed to encode the compiled location information. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int GetCmdLocEncodingSize(envPtr) CompileEnv *envPtr; /* Points to compilation environment * structure containing the CmdLocation * structure to encode. */ { register CmdLocation *mapPtr = envPtr->cmdMapPtr; int numCmds = envPtr->numCommands; int codeDelta, codeLen, srcDelta, srcLen; int codeDeltaNext, codeLengthNext, srcDeltaNext, srcLengthNext; /* The offsets in their respective byte * sequences where the next encoded offset * or length should go. */ int prevCodeOffset, prevSrcOffset, i; codeDeltaNext = codeLengthNext = srcDeltaNext = srcLengthNext = 0; prevCodeOffset = prevSrcOffset = 0; for (i = 0; i < numCmds; i++) { codeDelta = (mapPtr[i].codeOffset - prevCodeOffset); if (codeDelta < 0) { panic("GetCmdLocEncodingSize: bad code offset"); } else if (codeDelta <= 127) { codeDeltaNext++; } else { codeDeltaNext += 5; /* 1 byte for 0xFF, 4 for positive delta */ } prevCodeOffset = mapPtr[i].codeOffset; codeLen = mapPtr[i].numCodeBytes; if (codeLen < 0) { panic("GetCmdLocEncodingSize: bad code length"); } else if (codeLen <= 127) { codeLengthNext++; } else { codeLengthNext += 5; /* 1 byte for 0xFF, 4 for length */ } srcDelta = (mapPtr[i].srcOffset - prevSrcOffset); if ((-127 <= srcDelta) && (srcDelta <= 127)) { srcDeltaNext++; } else { srcDeltaNext += 5; /* 1 byte for 0xFF, 4 for delta */ } prevSrcOffset = mapPtr[i].srcOffset; srcLen = mapPtr[i].numSrcBytes; if (srcLen < 0) { panic("GetCmdLocEncodingSize: bad source length"); } else if (srcLen <= 127) { srcLengthNext++; } else { srcLengthNext += 5; /* 1 byte for 0xFF, 4 for length */ } } return (codeDeltaNext + codeLengthNext + srcDeltaNext + srcLengthNext); } /* *---------------------------------------------------------------------- * * EncodeCmdLocMap -- * * Encode the command location information for some compiled code into * a ByteCode structure. The encoded command location map is stored as * three adjacent byte sequences. * * Results: * Pointer to the first byte after the encoded command location * information. * * Side effects: * The encoded information is stored into the block of memory headed * by codePtr. Also records pointers to the start of the four byte * sequences in fields in codePtr's ByteCode header structure. * *---------------------------------------------------------------------- */ static unsigned char * EncodeCmdLocMap(envPtr, codePtr, startPtr) CompileEnv *envPtr; /* Points to compilation environment * structure containing the CmdLocation * structure to encode. */ ByteCode *codePtr; /* ByteCode in which to encode envPtr's * command location information. */ unsigned char *startPtr; /* Points to the first byte in codePtr's * memory block where the location * information is to be stored. */ { register CmdLocation *mapPtr = envPtr->cmdMapPtr; int numCmds = envPtr->numCommands; register unsigned char *p = startPtr; int codeDelta, codeLen, srcDelta, srcLen, prevOffset; register int i; /* * Encode the code offset for each command as a sequence of deltas. */ codePtr->codeDeltaStart = p; prevOffset = 0; for (i = 0; i < numCmds; i++) { codeDelta = (mapPtr[i].codeOffset - prevOffset); if (codeDelta < 0) { panic("EncodeCmdLocMap: bad code offset"); } else if (codeDelta <= 127) { TclStoreInt1AtPtr(codeDelta, p); p++; } else { TclStoreInt1AtPtr(0xFF, p); p++; TclStoreInt4AtPtr(codeDelta, p); p += 4; } prevOffset = mapPtr[i].codeOffset; } /* * Encode the code length for each command. */ codePtr->codeLengthStart = p; for (i = 0; i < numCmds; i++) { codeLen = mapPtr[i].numCodeBytes; if (codeLen < 0) { panic("EncodeCmdLocMap: bad code length"); } else if (codeLen <= 127) { TclStoreInt1AtPtr(codeLen, p); p++; } else { TclStoreInt1AtPtr(0xFF, p); p++; TclStoreInt4AtPtr(codeLen, p); p += 4; } } /* * Encode the source offset for each command as a sequence of deltas. */ codePtr->srcDeltaStart = p; prevOffset = 0; for (i = 0; i < numCmds; i++) { srcDelta = (mapPtr[i].srcOffset - prevOffset); if ((-127 <= srcDelta) && (srcDelta <= 127)) { TclStoreInt1AtPtr(srcDelta, p); p++; } else { TclStoreInt1AtPtr(0xFF, p); p++; TclStoreInt4AtPtr(srcDelta, p); p += 4; } prevOffset = mapPtr[i].srcOffset; } /* * Encode the source length for each command. */ codePtr->srcLengthStart = p; for (i = 0; i < numCmds; i++) { srcLen = mapPtr[i].numSrcBytes; if (srcLen < 0) { panic("EncodeCmdLocMap: bad source length"); } else if (srcLen <= 127) { TclStoreInt1AtPtr(srcLen, p); p++; } else { TclStoreInt1AtPtr(0xFF, p); p++; TclStoreInt4AtPtr(srcLen, p); p += 4; } } return p; } #ifdef TCL_COMPILE_DEBUG /* *---------------------------------------------------------------------- * * TclPrintByteCodeObj -- * * This procedure prints ("disassembles") the instructions of a * bytecode object to stdout. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TclPrintByteCodeObj(interp, objPtr) Tcl_Interp *interp; /* Used only for Tcl_GetStringFromObj. */ Tcl_Obj *objPtr; /* The bytecode object to disassemble. */ { ByteCode* codePtr = (ByteCode *) objPtr->internalRep.otherValuePtr; unsigned char *codeStart, *codeLimit, *pc; unsigned char *codeDeltaNext, *codeLengthNext; unsigned char *srcDeltaNext, *srcLengthNext; int codeOffset, codeLen, srcOffset, srcLen, numCmds, delta, i; Interp *iPtr = (Interp *) *codePtr->interpHandle; if (codePtr->refCount <= 0) { return; /* already freed */ } codeStart = codePtr->codeStart; codeLimit = (codeStart + codePtr->numCodeBytes); numCmds = codePtr->numCommands; /* * Print header lines describing the ByteCode. */ fprintf(stdout, "\nByteCode 0x%x, refCt %u, epoch %u, interp 0x%x (epoch %u)\n", (unsigned int) codePtr, codePtr->refCount, codePtr->compileEpoch, (unsigned int) iPtr, iPtr->compileEpoch); fprintf(stdout, " Source "); TclPrintSource(stdout, codePtr->source, TclMin(codePtr->numSrcBytes, 55)); fprintf(stdout, "\n Cmds %d, src %d, inst %d, litObjs %u, aux %d, stkDepth %u, code/src %.2f\n", numCmds, codePtr->numSrcBytes, codePtr->numCodeBytes, codePtr->numLitObjects, codePtr->numAuxDataItems, codePtr->maxStackDepth, #ifdef TCL_COMPILE_STATS (codePtr->numSrcBytes? ((float)codePtr->structureSize)/((float)codePtr->numSrcBytes) : 0.0)); #else 0.0); #endif #ifdef TCL_COMPILE_STATS fprintf(stdout, " Code %u = header %u+inst %d+litObj %lu+exc %lu+aux %lu+cmdMap %d\n", (unsigned int)codePtr->structureSize, (unsigned int)(sizeof(ByteCode) - (sizeof(size_t) + sizeof(Tcl_Time))), codePtr->numCodeBytes, (unsigned long)(codePtr->numLitObjects * sizeof(Tcl_Obj *)), (unsigned long)(codePtr->numExceptRanges * sizeof(ExceptionRange)), (unsigned long)(codePtr->numAuxDataItems * sizeof(AuxData)), codePtr->numCmdLocBytes); #endif /* TCL_COMPILE_STATS */ /* * If the ByteCode is the compiled body of a Tcl procedure, print * information about that procedure. Note that we don't know the * procedure's name since ByteCode's can be shared among procedures. */ if (codePtr->procPtr != NULL) { Proc *procPtr = codePtr->procPtr; int numCompiledLocals = procPtr->numCompiledLocals; fprintf(stdout, " Proc 0x%x, refCt %d, args %d, compiled locals %d\n", (unsigned int) procPtr, procPtr->refCount, procPtr->numArgs, numCompiledLocals); if (numCompiledLocals > 0) { CompiledLocal *localPtr = procPtr->firstLocalPtr; for (i = 0; i < numCompiledLocals; i++) { fprintf(stdout, " slot %d%s%s%s%s%s%s", i, ((localPtr->flags & VAR_SCALAR)? ", scalar" : ""), ((localPtr->flags & VAR_ARRAY)? ", array" : ""), ((localPtr->flags & VAR_LINK)? ", link" : ""), ((localPtr->flags & VAR_ARGUMENT)? ", arg" : ""), ((localPtr->flags & VAR_TEMPORARY)? ", temp" : ""), ((localPtr->flags & VAR_RESOLVED)? ", resolved" : "")); if (TclIsVarTemporary(localPtr)) { fprintf(stdout, "\n"); } else { fprintf(stdout, ", \"%s\"\n", localPtr->name); } localPtr = localPtr->nextPtr; } } } /* * Print the ExceptionRange array. */ if (codePtr->numExceptRanges > 0) { fprintf(stdout, " Exception ranges %d, depth %d:\n", codePtr->numExceptRanges, codePtr->maxExceptDepth); for (i = 0; i < codePtr->numExceptRanges; i++) { ExceptionRange *rangePtr = &(codePtr->exceptArrayPtr[i]); fprintf(stdout, " %d: level %d, %s, pc %d-%d, ", i, rangePtr->nestingLevel, ((rangePtr->type == LOOP_EXCEPTION_RANGE) ? "loop" : "catch"), rangePtr->codeOffset, (rangePtr->codeOffset + rangePtr->numCodeBytes - 1)); switch (rangePtr->type) { case LOOP_EXCEPTION_RANGE: fprintf(stdout, "continue %d, break %d\n", rangePtr->continueOffset, rangePtr->breakOffset); break; case CATCH_EXCEPTION_RANGE: fprintf(stdout, "catch %d\n", rangePtr->catchOffset); break; default: panic("TclPrintByteCodeObj: bad ExceptionRange type %d\n", rangePtr->type); } } } /* * If there were no commands (e.g., an expression or an empty string * was compiled), just print all instructions and return. */ if (numCmds == 0) { pc = codeStart; while (pc < codeLimit) { fprintf(stdout, " "); pc += TclPrintInstruction(codePtr, pc); } return; } /* * Print table showing the code offset, source offset, and source * length for each command. These are encoded as a sequence of bytes. */ fprintf(stdout, " Commands %d:", numCmds); codeDeltaNext = codePtr->codeDeltaStart; codeLengthNext = codePtr->codeLengthStart; srcDeltaNext = codePtr->srcDeltaStart; srcLengthNext = codePtr->srcLengthStart; codeOffset = srcOffset = 0; for (i = 0; i < numCmds; i++) { if ((unsigned int) (*codeDeltaNext) == (unsigned int) 0xFF) { codeDeltaNext++; delta = TclGetInt4AtPtr(codeDeltaNext); codeDeltaNext += 4; } else { delta = TclGetInt1AtPtr(codeDeltaNext); codeDeltaNext++; } codeOffset += delta; if ((unsigned int) (*codeLengthNext) == (unsigned int) 0xFF) { codeLengthNext++; codeLen = TclGetInt4AtPtr(codeLengthNext); codeLengthNext += 4; } else { codeLen = TclGetInt1AtPtr(codeLengthNext); codeLengthNext++; } if ((unsigned int) (*srcDeltaNext) == (unsigned int) 0xFF) { srcDeltaNext++; delta = TclGetInt4AtPtr(srcDeltaNext); srcDeltaNext += 4; } else { delta = TclGetInt1AtPtr(srcDeltaNext); srcDeltaNext++; } srcOffset += delta; if ((unsigned int) (*srcLengthNext) == (unsigned int) 0xFF) { srcLengthNext++; srcLen = TclGetInt4AtPtr(srcLengthNext); srcLengthNext += 4; } else { srcLen = TclGetInt1AtPtr(srcLengthNext); srcLengthNext++; } fprintf(stdout, "%s%4d: pc %d-%d, src %d-%d", ((i % 2)? " " : "\n "), (i+1), codeOffset, (codeOffset + codeLen - 1), srcOffset, (srcOffset + srcLen - 1)); } if (numCmds > 0) { fprintf(stdout, "\n"); } /* * Print each instruction. If the instruction corresponds to the start * of a command, print the command's source. Note that we don't need * the code length here. */ codeDeltaNext = codePtr->codeDeltaStart; srcDeltaNext = codePtr->srcDeltaStart; srcLengthNext = codePtr->srcLengthStart; codeOffset = srcOffset = 0; pc = codeStart; for (i = 0; i < numCmds; i++) { if ((unsigned int) (*codeDeltaNext) == (unsigned int) 0xFF) { codeDeltaNext++; delta = TclGetInt4AtPtr(codeDeltaNext); codeDeltaNext += 4; } else { delta = TclGetInt1AtPtr(codeDeltaNext); codeDeltaNext++; } codeOffset += delta; if ((unsigned int) (*srcDeltaNext) == (unsigned int) 0xFF) { srcDeltaNext++; delta = TclGetInt4AtPtr(srcDeltaNext); srcDeltaNext += 4; } else { delta = TclGetInt1AtPtr(srcDeltaNext); srcDeltaNext++; } srcOffset += delta; if ((unsigned int) (*srcLengthNext) == (unsigned int) 0xFF) { srcLengthNext++; srcLen = TclGetInt4AtPtr(srcLengthNext); srcLengthNext += 4; } else { srcLen = TclGetInt1AtPtr(srcLengthNext); srcLengthNext++; } /* * Print instructions before command i. */ while ((pc-codeStart) < codeOffset) { fprintf(stdout, " "); pc += TclPrintInstruction(codePtr, pc); } fprintf(stdout, " Command %d: ", (i+1)); TclPrintSource(stdout, (codePtr->source + srcOffset), TclMin(srcLen, 55)); fprintf(stdout, "\n"); } if (pc < codeLimit) { /* * Print instructions after the last command. */ while (pc < codeLimit) { fprintf(stdout, " "); pc += TclPrintInstruction(codePtr, pc); } } } #endif /* TCL_COMPILE_DEBUG */ /* *---------------------------------------------------------------------- * * TclPrintInstruction -- * * This procedure prints ("disassembles") one instruction from a * bytecode object to stdout. * * Results: * Returns the length in bytes of the current instruiction. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclPrintInstruction(codePtr, pc) ByteCode* codePtr; /* Bytecode containing the instruction. */ unsigned char *pc; /* Points to first byte of instruction. */ { Proc *procPtr = codePtr->procPtr; unsigned char opCode = *pc; register InstructionDesc *instDesc = &tclInstructionTable[opCode]; unsigned char *codeStart = codePtr->codeStart; unsigned int pcOffset = (pc - codeStart); int opnd, i, j; fprintf(stdout, "(%u) %s ", pcOffset, instDesc->name); for (i = 0; i < instDesc->numOperands; i++) { switch (instDesc->opTypes[i]) { case OPERAND_INT1: opnd = TclGetInt1AtPtr(pc+1+i); if ((i == 0) && ((opCode == INST_JUMP1) || (opCode == INST_JUMP_TRUE1) || (opCode == INST_JUMP_FALSE1))) { fprintf(stdout, "%d # pc %u", opnd, (pcOffset + opnd)); } else { fprintf(stdout, "%d", opnd); } break; case OPERAND_INT4: opnd = TclGetInt4AtPtr(pc+1+i); if ((i == 0) && ((opCode == INST_JUMP4) || (opCode == INST_JUMP_TRUE4) || (opCode == INST_JUMP_FALSE4))) { fprintf(stdout, "%d # pc %u", opnd, (pcOffset + opnd)); } else { fprintf(stdout, "%d", opnd); } break; case OPERAND_UINT1: opnd = TclGetUInt1AtPtr(pc+1+i); if ((i == 0) && (opCode == INST_PUSH1)) { fprintf(stdout, "%u # ", (unsigned int) opnd); TclPrintObject(stdout, codePtr->objArrayPtr[opnd], 40); } else if ((i == 0) && ((opCode == INST_LOAD_SCALAR1) || (opCode == INST_LOAD_ARRAY1) || (opCode == INST_STORE_SCALAR1) || (opCode == INST_STORE_ARRAY1))) { int localCt = procPtr->numCompiledLocals; CompiledLocal *localPtr = procPtr->firstLocalPtr; if (opnd >= localCt) { panic("TclPrintInstruction: bad local var index %u (%u locals)\n", (unsigned int) opnd, localCt); return instDesc->numBytes; } for (j = 0; j < opnd; j++) { localPtr = localPtr->nextPtr; } if (TclIsVarTemporary(localPtr)) { fprintf(stdout, "%u # temp var %u", (unsigned int) opnd, (unsigned int) opnd); } else { fprintf(stdout, "%u # var ", (unsigned int) opnd); TclPrintSource(stdout, localPtr->name, 40); } } else { fprintf(stdout, "%u ", (unsigned int) opnd); } break; case OPERAND_UINT4: opnd = TclGetUInt4AtPtr(pc+1+i); if (opCode == INST_PUSH4) { fprintf(stdout, "%u # ", opnd); TclPrintObject(stdout, codePtr->objArrayPtr[opnd], 40); } else if ((i == 0) && ((opCode == INST_LOAD_SCALAR4) || (opCode == INST_LOAD_ARRAY4) || (opCode == INST_STORE_SCALAR4) || (opCode == INST_STORE_ARRAY4))) { int localCt = procPtr->numCompiledLocals; CompiledLocal *localPtr = procPtr->firstLocalPtr; if (opnd >= localCt) { panic("TclPrintInstruction: bad local var index %u (%u locals)\n", (unsigned int) opnd, localCt); return instDesc->numBytes; } for (j = 0; j < opnd; j++) { localPtr = localPtr->nextPtr; } if (TclIsVarTemporary(localPtr)) { fprintf(stdout, "%u # temp var %u", (unsigned int) opnd, (unsigned int) opnd); } else { fprintf(stdout, "%u # var ", (unsigned int) opnd); TclPrintSource(stdout, localPtr->name, 40); } } else { fprintf(stdout, "%u ", (unsigned int) opnd); } break; case OPERAND_NONE: default: break; } } fprintf(stdout, "\n"); return instDesc->numBytes; } /* *---------------------------------------------------------------------- * * TclPrintObject -- * * This procedure prints up to a specified number of characters from * the argument Tcl object's string representation to a specified file. * * Results: * None. * * Side effects: * Outputs characters to the specified file. * *---------------------------------------------------------------------- */ void TclPrintObject(outFile, objPtr, maxChars) FILE *outFile; /* The file to print the source to. */ Tcl_Obj *objPtr; /* Points to the Tcl object whose string * representation should be printed. */ int maxChars; /* Maximum number of chars to print. */ { char *bytes; int length; bytes = Tcl_GetStringFromObj(objPtr, &length); TclPrintSource(outFile, bytes, TclMin(length, maxChars)); } /* *---------------------------------------------------------------------- * * TclPrintSource -- * * This procedure prints up to a specified number of characters from * the argument string to a specified file. It tries to produce legible * output by adding backslashes as necessary. * * Results: * None. * * Side effects: * Outputs characters to the specified file. * *---------------------------------------------------------------------- */ void TclPrintSource(outFile, string, maxChars) FILE *outFile; /* The file to print the source to. */ CONST char *string; /* The string to print. */ int maxChars; /* Maximum number of chars to print. */ { register CONST char *p; register int i = 0; if (string == NULL) { fprintf(outFile, "\"\""); return; } fprintf(outFile, "\""); p = string; for (; (*p != '\0') && (i < maxChars); p++, i++) { switch (*p) { case '"': fprintf(outFile, "\\\""); continue; case '\f': fprintf(outFile, "\\f"); continue; case '\n': fprintf(outFile, "\\n"); continue; case '\r': fprintf(outFile, "\\r"); continue; case '\t': fprintf(outFile, "\\t"); continue; case '\v': fprintf(outFile, "\\v"); continue; default: fprintf(outFile, "%c", *p); continue; } } fprintf(outFile, "\""); } #ifdef TCL_COMPILE_STATS /* *---------------------------------------------------------------------- * * RecordByteCodeStats -- * * Accumulates various compilation-related statistics for each newly * compiled ByteCode. Called by the TclInitByteCodeObj when Tcl is * compiled with the -DTCL_COMPILE_STATS flag * * Results: * None. * * Side effects: * Accumulates aggregate code-related statistics in the interpreter's * ByteCodeStats structure. Records statistics specific to a ByteCode * in its ByteCode structure. * *---------------------------------------------------------------------- */ void RecordByteCodeStats(codePtr) ByteCode *codePtr; /* Points to ByteCode structure with info * to add to accumulated statistics. */ { Interp *iPtr = (Interp *) *codePtr->interpHandle; register ByteCodeStats *statsPtr = &(iPtr->stats); if (iPtr == NULL) { /* Avoid segfaulting in case we're called in a deleted interp */ return; } statsPtr->numCompilations++; statsPtr->totalSrcBytes += (double) codePtr->numSrcBytes; statsPtr->totalByteCodeBytes += (double) codePtr->structureSize; statsPtr->currentSrcBytes += (double) codePtr->numSrcBytes; statsPtr->currentByteCodeBytes += (double) codePtr->structureSize; statsPtr->srcCount[TclLog2(codePtr->numSrcBytes)]++; statsPtr->byteCodeCount[TclLog2((int)(codePtr->structureSize))]++; statsPtr->currentInstBytes += (double) codePtr->numCodeBytes; statsPtr->currentLitBytes += (double) (codePtr->numLitObjects * sizeof(Tcl_Obj *)); statsPtr->currentExceptBytes += (double) (codePtr->numExceptRanges * sizeof(ExceptionRange)); statsPtr->currentAuxBytes += (double) (codePtr->numAuxDataItems * sizeof(AuxData)); statsPtr->currentCmdMapBytes += (double) codePtr->numCmdLocBytes; } #endif /* TCL_COMPILE_STATS */ /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ tcl8.4.20/generic/tclRegexp.c0000644003604700454610000007271611737050674014451 0ustar dgp771div/* * tclRegexp.c -- * * This file contains the public interfaces to the Tcl regular * expression mechanism. * * Copyright (c) 1998 by Sun Microsystems, Inc. * Copyright (c) 1998-1999 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" #include "tclRegexp.h" /* *---------------------------------------------------------------------- * The routines in this file use Henry Spencer's regular expression * package contained in the following additional source files: * * regc_color.c regc_cvec.c regc_lex.c * regc_nfa.c regcomp.c regcustom.h * rege_dfa.c regerror.c regerrs.h * regex.h regexec.c regfree.c * regfronts.c regguts.h * * Copyright (c) 1998 Henry Spencer. All rights reserved. * * Development of this software was funded, in part, by Cray Research Inc., * UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics * Corporation, none of whom are responsible for the results. The author * thanks all of them. * * Redistribution and use in source and binary forms -- with or without * modification -- are permitted for any purpose, provided that * redistributions in source form retain this entire copyright notice and * indicate the origin and nature of any modifications. * * I'd appreciate being given credit for this package in the documentation * of software which uses it, but that is not a requirement. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * HENRY SPENCER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * *** NOTE: this code has been altered slightly for use in Tcl: *** * *** 1. Names have been changed, e.g. from re_comp to *** * *** TclRegComp, to avoid clashes with other *** * *** regexp implementations used by applications. *** */ /* * Thread local storage used to maintain a per-thread cache of compiled * regular expressions. */ #define NUM_REGEXPS 30 typedef struct ThreadSpecificData { int initialized; /* Set to 1 when the module is initialized. */ char *patterns[NUM_REGEXPS];/* Strings corresponding to compiled * regular expression patterns. NULL * means that this slot isn't used. * Malloc-ed. */ int patLengths[NUM_REGEXPS];/* Number of non-null characters in * corresponding entry in patterns. * -1 means entry isn't used. */ struct TclRegexp *regexps[NUM_REGEXPS]; /* Compiled forms of above strings. Also * malloc-ed, or NULL if not in use yet. */ } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; /* * Declarations for functions used only in this file. */ static TclRegexp * CompileRegexp _ANSI_ARGS_((Tcl_Interp *interp, CONST char *pattern, int length, int flags)); static void DupRegexpInternalRep _ANSI_ARGS_((Tcl_Obj *srcPtr, Tcl_Obj *copyPtr)); static void FinalizeRegexp _ANSI_ARGS_((ClientData clientData)); static void FreeRegexp _ANSI_ARGS_((TclRegexp *regexpPtr)); static void FreeRegexpInternalRep _ANSI_ARGS_((Tcl_Obj *objPtr)); static int RegExpExecUniChar _ANSI_ARGS_((Tcl_Interp *interp, Tcl_RegExp re, CONST Tcl_UniChar *uniString, int numChars, int nmatches, int flags)); static int SetRegexpFromAny _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr)); /* * The regular expression Tcl object type. This serves as a cache * of the compiled form of the regular expression. */ static Tcl_ObjType tclRegexpType = { "regexp", /* name */ FreeRegexpInternalRep, /* freeIntRepProc */ DupRegexpInternalRep, /* dupIntRepProc */ NULL, /* updateStringProc */ SetRegexpFromAny /* setFromAnyProc */ }; /* *---------------------------------------------------------------------- * * Tcl_RegExpCompile -- * * Compile a regular expression into a form suitable for fast * matching. This procedure is DEPRECATED in favor of the * object version of the command. * * Results: * The return value is a pointer to the compiled form of string, * suitable for passing to Tcl_RegExpExec. This compiled form * is only valid up until the next call to this procedure, so * don't keep these around for a long time! If an error occurred * while compiling the pattern, then NULL is returned and an error * message is left in the interp's result. * * Side effects: * Updates the cache of compiled regexps. * *---------------------------------------------------------------------- */ Tcl_RegExp Tcl_RegExpCompile(interp, string) Tcl_Interp *interp; /* For use in error reporting and * to access the interp regexp cache. */ CONST char *string; /* String for which to produce * compiled regular expression. */ { return (Tcl_RegExp) CompileRegexp(interp, string, (int) strlen(string), REG_ADVANCED); } /* *---------------------------------------------------------------------- * * Tcl_RegExpExec -- * * Execute the regular expression matcher using a compiled form * of a regular expression and save information about any match * that is found. * * Results: * If an error occurs during the matching operation then -1 * is returned and the interp's result contains an error message. * Otherwise the return value is 1 if a matching range is * found and 0 if there is no matching range. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_RegExpExec(interp, re, string, start) Tcl_Interp *interp; /* Interpreter to use for error reporting. */ Tcl_RegExp re; /* Compiled regular expression; must have * been returned by previous call to * Tcl_GetRegExpFromObj. */ CONST char *string; /* String against which to match re. */ CONST char *start; /* If string is part of a larger string, * this identifies beginning of larger * string, so that "^" won't match. */ { int flags, result, numChars; TclRegexp *regexp = (TclRegexp *)re; Tcl_DString ds; CONST Tcl_UniChar *ustr; /* * If the starting point is offset from the beginning of the buffer, * then we need to tell the regexp engine not to match "^". */ if (string > start) { flags = REG_NOTBOL; } else { flags = 0; } /* * Remember the string for use by Tcl_RegExpRange(). */ regexp->string = string; regexp->objPtr = NULL; /* * Convert the string to Unicode and perform the match. */ Tcl_DStringInit(&ds); ustr = Tcl_UtfToUniCharDString(string, -1, &ds); numChars = Tcl_DStringLength(&ds) / sizeof(Tcl_UniChar); result = RegExpExecUniChar(interp, re, ustr, numChars, -1 /* nmatches */, flags); Tcl_DStringFree(&ds); return result; } /* *--------------------------------------------------------------------------- * * Tcl_RegExpRange -- * * Returns pointers describing the range of a regular expression match, * or one of the subranges within the match. * * Results: * The variables at *startPtr and *endPtr are modified to hold the * addresses of the endpoints of the range given by index. If the * specified range doesn't exist then NULLs are returned. * * Side effects: * None. * *--------------------------------------------------------------------------- */ void Tcl_RegExpRange(re, index, startPtr, endPtr) Tcl_RegExp re; /* Compiled regular expression that has * been passed to Tcl_RegExpExec. */ int index; /* 0 means give the range of the entire * match, > 0 means give the range of * a matching subrange. */ CONST char **startPtr; /* Store address of first character in * (sub-) range here. */ CONST char **endPtr; /* Store address of character just after last * in (sub-) range here. */ { TclRegexp *regexpPtr = (TclRegexp *) re; CONST char *string; if ((size_t) index > regexpPtr->re.re_nsub) { *startPtr = *endPtr = NULL; } else if (regexpPtr->matches[index].rm_so < 0) { *startPtr = *endPtr = NULL; } else { if (regexpPtr->objPtr) { string = Tcl_GetString(regexpPtr->objPtr); } else { string = regexpPtr->string; } *startPtr = Tcl_UtfAtIndex(string, regexpPtr->matches[index].rm_so); *endPtr = Tcl_UtfAtIndex(string, regexpPtr->matches[index].rm_eo); } } /* *--------------------------------------------------------------------------- * * RegExpExecUniChar -- * * Execute the regular expression matcher using a compiled form of a * regular expression and save information about any match that is * found. * * Results: * If an error occurs during the matching operation then -1 is * returned and an error message is left in interp's result. * Otherwise the return value is 1 if a matching range was found or * 0 if there was no matching range. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int RegExpExecUniChar(interp, re, wString, numChars, nmatches, flags) Tcl_Interp *interp; /* Interpreter to use for error reporting. */ Tcl_RegExp re; /* Compiled regular expression; returned by * a previous call to Tcl_GetRegExpFromObj */ CONST Tcl_UniChar *wString; /* String against which to match re. */ int numChars; /* Length of Tcl_UniChar string (must * be >= 0). */ int nmatches; /* How many subexpression matches (counting * the whole match as subexpression 0) are * of interest. -1 means "don't know". */ int flags; /* Regular expression flags. */ { int status; TclRegexp *regexpPtr = (TclRegexp *) re; size_t last = regexpPtr->re.re_nsub + 1; size_t nm = last; if (nmatches >= 0 && (size_t) nmatches < nm) { nm = (size_t) nmatches; } status = TclReExec(®expPtr->re, wString, (size_t) numChars, ®expPtr->details, nm, regexpPtr->matches, flags); /* * Check for errors. */ if (status != REG_OKAY) { if (status == REG_NOMATCH) { return 0; } if (interp != NULL) { TclRegError(interp, "error while matching regular expression: ", status); } return -1; } return 1; } /* *--------------------------------------------------------------------------- * * TclRegExpRangeUniChar -- * * Returns pointers describing the range of a regular expression match, * or one of the subranges within the match, or the hypothetical range * represented by the rm_extend field of the rm_detail_t. * * Results: * The variables at *startPtr and *endPtr are modified to hold the * offsets of the endpoints of the range given by index. If the * specified range doesn't exist then -1s are supplied. * * Side effects: * None. * *--------------------------------------------------------------------------- */ void TclRegExpRangeUniChar(re, index, startPtr, endPtr) Tcl_RegExp re; /* Compiled regular expression that has * been passed to Tcl_RegExpExec. */ int index; /* 0 means give the range of the entire * match, > 0 means give the range of * a matching subrange, -1 means the * range of the rm_extend field. */ int *startPtr; /* Store address of first character in * (sub-) range here. */ int *endPtr; /* Store address of character just after last * in (sub-) range here. */ { TclRegexp *regexpPtr = (TclRegexp *) re; if ((regexpPtr->flags®_EXPECT) && index == -1) { *startPtr = regexpPtr->details.rm_extend.rm_so; *endPtr = regexpPtr->details.rm_extend.rm_eo; } else if ((size_t) index > regexpPtr->re.re_nsub) { *startPtr = -1; *endPtr = -1; } else { *startPtr = regexpPtr->matches[index].rm_so; *endPtr = regexpPtr->matches[index].rm_eo; } } /* *---------------------------------------------------------------------- * * Tcl_RegExpMatch -- * * See if a string matches a regular expression. * * Results: * If an error occurs during the matching operation then -1 * is returned and the interp's result contains an error message. * Otherwise the return value is 1 if "string" matches "pattern" * and 0 otherwise. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_RegExpMatch(interp, string, pattern) Tcl_Interp *interp; /* Used for error reporting. May be NULL. */ CONST char *string; /* String. */ CONST char *pattern; /* Regular expression to match against * string. */ { Tcl_RegExp re; re = Tcl_RegExpCompile(interp, pattern); if (re == NULL) { return -1; } return Tcl_RegExpExec(interp, re, string, string); } /* *---------------------------------------------------------------------- * * Tcl_RegExpExecObj -- * * Execute a precompiled regexp against the given object. * * Results: * If an error occurs during the matching operation then -1 * is returned and the interp's result contains an error message. * Otherwise the return value is 1 if "string" matches "pattern" * and 0 otherwise. * * Side effects: * Converts the object to a Unicode object. * *---------------------------------------------------------------------- */ int Tcl_RegExpExecObj(interp, re, objPtr, offset, nmatches, flags) Tcl_Interp *interp; /* Interpreter to use for error reporting. */ Tcl_RegExp re; /* Compiled regular expression; must have * been returned by previous call to * Tcl_GetRegExpFromObj. */ Tcl_Obj *objPtr; /* String against which to match re. */ int offset; /* Character index that marks where matching * should begin. */ int nmatches; /* How many subexpression matches (counting * the whole match as subexpression 0) are * of interest. -1 means all of them. */ int flags; /* Regular expression execution flags. */ { TclRegexp *regexpPtr = (TclRegexp *) re; Tcl_UniChar *udata; int length; /* * Save the target object so we can extract strings from it later. */ regexpPtr->string = NULL; regexpPtr->objPtr = objPtr; udata = Tcl_GetUnicodeFromObj(objPtr, &length); if (offset > length) { offset = length; } udata += offset; length -= offset; return RegExpExecUniChar(interp, re, udata, length, nmatches, flags); } /* *---------------------------------------------------------------------- * * Tcl_RegExpMatchObj -- * * See if an object matches a regular expression. * * Results: * If an error occurs during the matching operation then -1 * is returned and the interp's result contains an error message. * Otherwise the return value is 1 if "string" matches "pattern" * and 0 otherwise. * * Side effects: * Changes the internal rep of the pattern and string objects. * *---------------------------------------------------------------------- */ int Tcl_RegExpMatchObj(interp, stringObj, patternObj) Tcl_Interp *interp; /* Used for error reporting. May be NULL. */ Tcl_Obj *stringObj; /* Object containing the String to search. */ Tcl_Obj *patternObj; /* Regular expression to match against * string. */ { Tcl_RegExp re; re = Tcl_GetRegExpFromObj(interp, patternObj, TCL_REG_ADVANCED | TCL_REG_NOSUB); if (re == NULL) { return -1; } return Tcl_RegExpExecObj(interp, re, stringObj, 0 /* offset */, 0 /* nmatches */, 0 /* flags */); } /* *---------------------------------------------------------------------- * * Tcl_RegExpGetInfo -- * * Retrieve information about the current match. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Tcl_RegExpGetInfo(regexp, infoPtr) Tcl_RegExp regexp; /* Pattern from which to get subexpressions. */ Tcl_RegExpInfo *infoPtr; /* Match information is stored here. */ { TclRegexp *regexpPtr = (TclRegexp *) regexp; infoPtr->nsubs = regexpPtr->re.re_nsub; infoPtr->matches = (Tcl_RegExpIndices *) regexpPtr->matches; infoPtr->extendStart = regexpPtr->details.rm_extend.rm_so; } /* *---------------------------------------------------------------------- * * Tcl_GetRegExpFromObj -- * * Compile a regular expression into a form suitable for fast * matching. This procedure caches the result in a Tcl_Obj. * * Results: * The return value is a pointer to the compiled form of string, * suitable for passing to Tcl_RegExpExec. If an error occurred * while compiling the pattern, then NULL is returned and an error * message is left in the interp's result. * * Side effects: * Updates the native rep of the Tcl_Obj. * *---------------------------------------------------------------------- */ Tcl_RegExp Tcl_GetRegExpFromObj(interp, objPtr, flags) Tcl_Interp *interp; /* For use in error reporting, and to access * the interp regexp cache. */ Tcl_Obj *objPtr; /* Object whose string rep contains regular * expression pattern. Internal rep will be * changed to compiled form of this regular * expression. */ int flags; /* Regular expression compilation flags. */ { int length; Tcl_ObjType *typePtr; TclRegexp *regexpPtr; char *pattern; typePtr = objPtr->typePtr; regexpPtr = (TclRegexp *) objPtr->internalRep.otherValuePtr; if ((typePtr != &tclRegexpType) || (regexpPtr->flags != flags)) { pattern = Tcl_GetStringFromObj(objPtr, &length); regexpPtr = CompileRegexp(interp, pattern, length, flags); if (regexpPtr == NULL) { return NULL; } /* * Add a reference to the regexp so it will persist even if it is * pushed out of the current thread's regexp cache. This reference * will be removed when the object's internal rep is freed. */ regexpPtr->refCount++; /* * Free the old representation and set our type. */ if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) { (*typePtr->freeIntRepProc)(objPtr); } objPtr->internalRep.otherValuePtr = (VOID *) regexpPtr; objPtr->typePtr = &tclRegexpType; } return (Tcl_RegExp) regexpPtr; } /* *---------------------------------------------------------------------- * * TclRegAbout -- * * Return information about a compiled regular expression. * * Results: * The return value is -1 for failure, 0 for success, although at * the moment there's nothing that could fail. On success, a list * is left in the interp's result: first element is the subexpression * count, second is a list of re_info bit names. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclRegAbout(interp, re) Tcl_Interp *interp; /* For use in variable assignment. */ Tcl_RegExp re; /* The compiled regular expression. */ { TclRegexp *regexpPtr = (TclRegexp *)re; char buf[TCL_INTEGER_SPACE]; static struct infoname { int bit; char *text; } infonames[] = { {REG_UBACKREF, "REG_UBACKREF"}, {REG_ULOOKAHEAD, "REG_ULOOKAHEAD"}, {REG_UBOUNDS, "REG_UBOUNDS"}, {REG_UBRACES, "REG_UBRACES"}, {REG_UBSALNUM, "REG_UBSALNUM"}, {REG_UPBOTCH, "REG_UPBOTCH"}, {REG_UBBS, "REG_UBBS"}, {REG_UNONPOSIX, "REG_UNONPOSIX"}, {REG_UUNSPEC, "REG_UUNSPEC"}, {REG_UUNPORT, "REG_UUNPORT"}, {REG_ULOCALE, "REG_ULOCALE"}, {REG_UEMPTYMATCH, "REG_UEMPTYMATCH"}, {REG_UIMPOSSIBLE, "REG_UIMPOSSIBLE"}, {REG_USHORTEST, "REG_USHORTEST"}, {0, ""} }; struct infoname *inf; int n; Tcl_ResetResult(interp); sprintf(buf, "%u", (unsigned)(regexpPtr->re.re_nsub)); Tcl_AppendElement(interp, buf); /* * Must count bits before generating list, because we must know * whether {} are needed before we start appending names. */ n = 0; for (inf = infonames; inf->bit != 0; inf++) { if (regexpPtr->re.re_info&inf->bit) { n++; } } if (n != 1) { Tcl_AppendResult(interp, " {", NULL); } for (inf = infonames; inf->bit != 0; inf++) { if (regexpPtr->re.re_info&inf->bit) { Tcl_AppendElement(interp, inf->text); } } if (n != 1) { Tcl_AppendResult(interp, "}", NULL); } return 0; } /* *---------------------------------------------------------------------- * * TclRegError -- * * Generate an error message based on the regexp status code. * * Results: * Places an error in the interpreter. * * Side effects: * Sets errorCode as well. * *---------------------------------------------------------------------- */ void TclRegError(interp, msg, status) Tcl_Interp *interp; /* Interpreter for error reporting. */ CONST char *msg; /* Message to prepend to error. */ int status; /* Status code to report. */ { char buf[100]; /* ample in practice */ char cbuf[100]; /* lots in practice */ size_t n; char *p; Tcl_ResetResult(interp); n = TclReError(status, (regex_t *)NULL, buf, sizeof(buf)); p = (n > sizeof(buf)) ? "..." : ""; Tcl_AppendResult(interp, msg, buf, p, NULL); sprintf(cbuf, "%d", status); (VOID) TclReError(REG_ITOA, (regex_t *)NULL, cbuf, sizeof(cbuf)); Tcl_SetErrorCode(interp, "REGEXP", cbuf, buf, NULL); } /* *---------------------------------------------------------------------- * * FreeRegexpInternalRep -- * * Deallocate the storage associated with a regexp object's internal * representation. * * Results: * None. * * Side effects: * Frees the compiled regular expression. * *---------------------------------------------------------------------- */ static void FreeRegexpInternalRep(objPtr) Tcl_Obj *objPtr; /* Regexp object with internal rep to free. */ { TclRegexp *regexpRepPtr = (TclRegexp *) objPtr->internalRep.otherValuePtr; /* * If this is the last reference to the regexp, free it. */ if (--(regexpRepPtr->refCount) <= 0) { FreeRegexp(regexpRepPtr); } } /* *---------------------------------------------------------------------- * * DupRegexpInternalRep -- * * We copy the reference to the compiled regexp and bump its * reference count. * * Results: * None. * * Side effects: * Increments the reference count of the regexp. * *---------------------------------------------------------------------- */ static void DupRegexpInternalRep(srcPtr, copyPtr) Tcl_Obj *srcPtr; /* Object with internal rep to copy. */ Tcl_Obj *copyPtr; /* Object with internal rep to set. */ { TclRegexp *regexpPtr = (TclRegexp *) srcPtr->internalRep.otherValuePtr; regexpPtr->refCount++; copyPtr->internalRep.otherValuePtr = srcPtr->internalRep.otherValuePtr; copyPtr->typePtr = &tclRegexpType; } /* *---------------------------------------------------------------------- * * SetRegexpFromAny -- * * Attempt to generate a compiled regular expression for the Tcl object * "objPtr". * * Results: * The return value is TCL_OK or TCL_ERROR. If an error occurs during * conversion, an error message is left in the interpreter's result * unless "interp" is NULL. * * Side effects: * If no error occurs, a regular expression is stored as "objPtr"s * internal representation. * *---------------------------------------------------------------------- */ static int SetRegexpFromAny(interp, objPtr) Tcl_Interp *interp; /* Used for error reporting if not NULL. */ Tcl_Obj *objPtr; /* The object to convert. */ { if (Tcl_GetRegExpFromObj(interp, objPtr, REG_ADVANCED) == NULL) { return TCL_ERROR; } return TCL_OK; } /* *--------------------------------------------------------------------------- * * CompileRegexp -- * * Attempt to compile the given regexp pattern. If the compiled * regular expression can be found in the per-thread cache, it * will be used instead of compiling a new copy. * * Results: * The return value is a pointer to a newly allocated TclRegexp * that represents the compiled pattern, or NULL if the pattern * could not be compiled. If NULL is returned, an error message is * left in the interp's result. * * Side effects: * The thread-local regexp cache is updated and a new TclRegexp may * be allocated. * *---------------------------------------------------------------------- */ static TclRegexp * CompileRegexp(interp, string, length, flags) Tcl_Interp *interp; /* Used for error reporting if not NULL. */ CONST char *string; /* The regexp to compile (UTF-8). */ int length; /* The length of the string in bytes. */ int flags; /* Compilation flags. */ { TclRegexp *regexpPtr; CONST Tcl_UniChar *uniString; int numChars; Tcl_DString stringBuf; int status, i; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (!tsdPtr->initialized) { tsdPtr->initialized = 1; Tcl_CreateThreadExitHandler(FinalizeRegexp, NULL); } /* * This routine maintains a second-level regular expression cache in * addition to the per-object regexp cache. The per-thread cache is needed * to handle the case where for various reasons the object is lost between * invocations of the regexp command, but the literal pattern is the same. */ /* * Check the per-thread compiled regexp cache. We can only reuse * a regexp if it has the same pattern and the same flags. */ for (i = 0; (i < NUM_REGEXPS) && (tsdPtr->patterns[i] != NULL); i++) { if ((length == tsdPtr->patLengths[i]) && (tsdPtr->regexps[i]->flags == flags) && (strcmp(string, tsdPtr->patterns[i]) == 0)) { /* * Move the matched pattern to the first slot in the * cache and shift the other patterns down one position. */ if (i != 0) { int j; char *cachedString; cachedString = tsdPtr->patterns[i]; regexpPtr = tsdPtr->regexps[i]; for (j = i-1; j >= 0; j--) { tsdPtr->patterns[j+1] = tsdPtr->patterns[j]; tsdPtr->patLengths[j+1] = tsdPtr->patLengths[j]; tsdPtr->regexps[j+1] = tsdPtr->regexps[j]; } tsdPtr->patterns[0] = cachedString; tsdPtr->patLengths[0] = length; tsdPtr->regexps[0] = regexpPtr; } return tsdPtr->regexps[0]; } } /* * This is a new expression, so compile it and add it to the cache. */ regexpPtr = (TclRegexp *) ckalloc(sizeof(TclRegexp)); regexpPtr->objPtr = NULL; regexpPtr->string = NULL; regexpPtr->details.rm_extend.rm_so = -1; regexpPtr->details.rm_extend.rm_eo = -1; /* * Get the up-to-date string representation and map to unicode. */ Tcl_DStringInit(&stringBuf); uniString = Tcl_UtfToUniCharDString(string, length, &stringBuf); numChars = Tcl_DStringLength(&stringBuf) / sizeof(Tcl_UniChar); /* * Compile the string and check for errors. */ regexpPtr->flags = flags; status = TclReComp(®expPtr->re, uniString, (size_t) numChars, flags); Tcl_DStringFree(&stringBuf); if (status != REG_OKAY) { /* * Clean up and report errors in the interpreter, if possible. */ ckfree((char *)regexpPtr); if (interp) { TclRegError(interp, "couldn't compile regular expression pattern: ", status); } return NULL; } /* * Allocate enough space for all of the subexpressions, plus one * extra for the entire pattern. */ regexpPtr->matches = (regmatch_t *) ckalloc( sizeof(regmatch_t) * (regexpPtr->re.re_nsub + 1)); /* * Initialize the refcount to one initially, since it is in the cache. */ regexpPtr->refCount = 1; /* * Free the last regexp, if necessary, and make room at the head of the * list for the new regexp. */ if (tsdPtr->patterns[NUM_REGEXPS-1] != NULL) { TclRegexp *oldRegexpPtr = tsdPtr->regexps[NUM_REGEXPS-1]; if (--(oldRegexpPtr->refCount) <= 0) { FreeRegexp(oldRegexpPtr); } ckfree(tsdPtr->patterns[NUM_REGEXPS-1]); } for (i = NUM_REGEXPS - 2; i >= 0; i--) { tsdPtr->patterns[i+1] = tsdPtr->patterns[i]; tsdPtr->patLengths[i+1] = tsdPtr->patLengths[i]; tsdPtr->regexps[i+1] = tsdPtr->regexps[i]; } tsdPtr->patterns[0] = (char *) ckalloc((unsigned) (length+1)); strcpy(tsdPtr->patterns[0], string); tsdPtr->patLengths[0] = length; tsdPtr->regexps[0] = regexpPtr; return regexpPtr; } /* *---------------------------------------------------------------------- * * FreeRegexp -- * * Release the storage associated with a TclRegexp. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void FreeRegexp(regexpPtr) TclRegexp *regexpPtr; /* Compiled regular expression to free. */ { TclReFree(®expPtr->re); if (regexpPtr->matches) { ckfree((char *) regexpPtr->matches); } ckfree((char *) regexpPtr); } /* *---------------------------------------------------------------------- * * FinalizeRegexp -- * * Release the storage associated with the per-thread regexp * cache. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void FinalizeRegexp(clientData) ClientData clientData; /* Not used. */ { int i; TclRegexp *regexpPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); for (i = 0; (i < NUM_REGEXPS) && (tsdPtr->patterns[i] != NULL); i++) { regexpPtr = tsdPtr->regexps[i]; if (--(regexpPtr->refCount) <= 0) { FreeRegexp(regexpPtr); } ckfree(tsdPtr->patterns[i]); tsdPtr->patterns[i] = NULL; } /* * We may find ourselves reinitialized if another finalization routine * invokes regexps. */ tsdPtr->initialized = 0; } tcl8.4.20/generic/tclDate.c0000644003604700454610000015622012052456743014063 0ustar dgp771div/* * tclDate.c -- * * This file is generated from a yacc grammar defined in * the file tclGetDate.y. It should not be edited directly. * * Copyright (c) 1992-1995 Karl Lehenbauer and Mark Diekhans. * Copyright (c) 1995-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" #define EPOCH 1970 #define START_OF_TIME 1902 #define END_OF_TIME 2037 /* * The offset of tm_year of struct tm returned by localtime, gmtime, etc. * I don't know how universal this is; K&R II, the NetBSD manpages, and * ../compat/strftime.c all agree that tm_year is the year-1900. However, * some systems may have a different value. This #define should be the * same as in ../compat/strftime.c. */ #define TM_YEAR_BASE 1900 #define HOUR(x) ((int) (60 * x)) #define SECSPERDAY (24L * 60L * 60L) #define IsLeapYear(x) ((x % 4 == 0) && (x % 100 != 0 || x % 400 == 0)) /* * An entry in the lexical lookup table. */ typedef struct _TABLE { char *name; int type; time_t value; } TABLE; /* * Daylight-savings mode: on, off, or not yet known. */ typedef enum _DSTMODE { DSTon, DSToff, DSTmaybe } DSTMODE; /* * Meridian: am, pm, or 24-hour style. */ typedef enum _MERIDIAN { MERam, MERpm, MER24 } MERIDIAN; /* * Global variables. We could get rid of most of these by using a good * union as the yacc stack. (This routine was originally written before * yacc had the %union construct.) Maybe someday; right now we only use * the %union very rarely. */ static char *TclDateInput; static DSTMODE TclDateDSTmode; static time_t TclDateDayOrdinal; static time_t TclDateDayNumber; static time_t TclDateMonthOrdinal; static int TclDateHaveDate; static int TclDateHaveDay; static int TclDateHaveOrdinalMonth; static int TclDateHaveRel; static int TclDateHaveTime; static int TclDateHaveZone; static time_t TclDateTimezone; static time_t TclDateDay; static time_t TclDateHour; static time_t TclDateMinutes; static time_t TclDateMonth; static time_t TclDateSeconds; static time_t TclDateYear; static MERIDIAN TclDateMeridian; static time_t TclDateRelMonth; static time_t TclDateRelDay; static time_t TclDateRelSeconds; static time_t *TclDateRelPointer; /* * Prototypes of internal functions. */ static void TclDateerror _ANSI_ARGS_((char *s)); static time_t ToSeconds _ANSI_ARGS_((time_t Hours, time_t Minutes, time_t Seconds, MERIDIAN Meridian)); static int Convert _ANSI_ARGS_((time_t Month, time_t Day, time_t Year, time_t Hours, time_t Minutes, time_t Seconds, MERIDIAN Meridia, DSTMODE DSTmode, time_t *TimePtr)); static time_t DSTcorrect _ANSI_ARGS_((time_t Start, time_t Future)); static time_t NamedDay _ANSI_ARGS_((time_t Start, time_t DayOrdinal, time_t DayNumber)); static time_t NamedMonth _ANSI_ARGS_((time_t Start, time_t MonthOrdinal, time_t MonthNumber)); static int RelativeMonth _ANSI_ARGS_((time_t Start, time_t RelMonth, time_t *TimePtr)); static int RelativeDay _ANSI_ARGS_((time_t Start, time_t RelDay, time_t *TimePtr)); static int LookupWord _ANSI_ARGS_((char *buff)); static int TclDatelex _ANSI_ARGS_((void)); int TclDateparse _ANSI_ARGS_((void)); typedef union #ifdef __cplusplus YYSTYPE #endif { time_t Number; enum _MERIDIAN Meridian; } YYSTYPE; # define tAGO 257 # define tDAY 258 # define tDAYZONE 259 # define tID 260 # define tMERIDIAN 261 # define tMINUTE_UNIT 262 # define tMONTH 263 # define tMONTH_UNIT 264 # define tSTARDATE 265 # define tSEC_UNIT 266 # define tSNUMBER 267 # define tUNUMBER 268 # define tZONE 269 # define tEPOCH 270 # define tDST 271 # define tISOBASE 272 # define tDAY_UNIT 273 # define tNEXT 274 #if defined(__cplusplus) || defined(__STDC__) #if defined(__cplusplus) && defined(__EXTERN_C__) extern "C" { #endif #ifndef TclDateerror #if defined(__cplusplus) void TclDateerror(CONST char *); #endif #endif #ifndef TclDatelex int TclDatelex(void); #endif int TclDateparse(void); #if defined(__cplusplus) && defined(__EXTERN_C__) } #endif #endif #define TclDateclearin TclDatechar = -1 #define TclDateerrok TclDateerrflag = 0 extern int TclDatechar; extern int TclDateerrflag; YYSTYPE TclDatelval; YYSTYPE TclDateval; typedef int TclDatetabelem; #ifndef YYMAXDEPTH #define YYMAXDEPTH 150 #endif #if YYMAXDEPTH > 0 int TclDate_TclDates[YYMAXDEPTH], *TclDates = TclDate_TclDates; YYSTYPE TclDate_TclDatev[YYMAXDEPTH], *TclDatev = TclDate_TclDatev; #else /* user does initial allocation */ int *TclDates; YYSTYPE *TclDatev; #endif static int TclDatemaxdepth = YYMAXDEPTH; # define YYERRCODE 256 /* * Month and day table. */ static CONST TABLE MonthDayTable[] = { { "january", tMONTH, 1 }, { "february", tMONTH, 2 }, { "march", tMONTH, 3 }, { "april", tMONTH, 4 }, { "may", tMONTH, 5 }, { "june", tMONTH, 6 }, { "july", tMONTH, 7 }, { "august", tMONTH, 8 }, { "september", tMONTH, 9 }, { "sept", tMONTH, 9 }, { "october", tMONTH, 10 }, { "november", tMONTH, 11 }, { "december", tMONTH, 12 }, { "sunday", tDAY, 0 }, { "monday", tDAY, 1 }, { "tuesday", tDAY, 2 }, { "tues", tDAY, 2 }, { "wednesday", tDAY, 3 }, { "wednes", tDAY, 3 }, { "thursday", tDAY, 4 }, { "thur", tDAY, 4 }, { "thurs", tDAY, 4 }, { "friday", tDAY, 5 }, { "saturday", tDAY, 6 }, { NULL } }; /* * Time units table. */ static CONST TABLE UnitsTable[] = { { "year", tMONTH_UNIT, 12 }, { "month", tMONTH_UNIT, 1 }, { "fortnight", tDAY_UNIT, 14 }, { "week", tDAY_UNIT, 7 }, { "day", tDAY_UNIT, 1 }, { "hour", tSEC_UNIT, 60 * 60 }, { "minute", tSEC_UNIT, 60 }, { "min", tSEC_UNIT, 60 }, { "second", tSEC_UNIT, 1 }, { "sec", tSEC_UNIT, 1 }, { NULL } }; /* * Assorted relative-time words. */ static CONST TABLE OtherTable[] = { { "tomorrow", tDAY_UNIT, 1 }, { "yesterday", tDAY_UNIT, -1 }, { "today", tDAY_UNIT, 0 }, { "now", tSEC_UNIT, 0 }, { "last", tUNUMBER, -1 }, { "this", tSEC_UNIT, 0 }, { "next", tNEXT, 1 }, #if 0 { "first", tUNUMBER, 1 }, { "second", tUNUMBER, 2 }, { "third", tUNUMBER, 3 }, { "fourth", tUNUMBER, 4 }, { "fifth", tUNUMBER, 5 }, { "sixth", tUNUMBER, 6 }, { "seventh", tUNUMBER, 7 }, { "eighth", tUNUMBER, 8 }, { "ninth", tUNUMBER, 9 }, { "tenth", tUNUMBER, 10 }, { "eleventh", tUNUMBER, 11 }, { "twelfth", tUNUMBER, 12 }, #endif { "ago", tAGO, 1 }, { "epoch", tEPOCH, 0 }, { "stardate", tSTARDATE, 0}, { NULL } }; /* * The timezone table. (Note: This table was modified to not use any floating * point constants to work around an SGI compiler bug). */ static CONST TABLE TimezoneTable[] = { { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */ { "ut", tZONE, HOUR( 0) }, /* Universal (Coordinated) */ { "utc", tZONE, HOUR( 0) }, { "uct", tZONE, HOUR( 0) }, /* Universal Coordinated Time */ { "wet", tZONE, HOUR( 0) }, /* Western European */ { "bst", tDAYZONE, HOUR( 0) }, /* British Summer */ { "wat", tZONE, HOUR( 1) }, /* West Africa */ { "at", tZONE, HOUR( 2) }, /* Azores */ #if 0 /* For completeness. BST is also British Summer, and GST is * also Guam Standard. */ { "bst", tZONE, HOUR( 3) }, /* Brazil Standard */ { "gst", tZONE, HOUR( 3) }, /* Greenland Standard */ #endif { "nft", tZONE, HOUR( 7/2) }, /* Newfoundland */ { "nst", tZONE, HOUR( 7/2) }, /* Newfoundland Standard */ { "ndt", tDAYZONE, HOUR( 7/2) }, /* Newfoundland Daylight */ { "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */ { "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */ { "est", tZONE, HOUR( 5) }, /* Eastern Standard */ { "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */ { "cst", tZONE, HOUR( 6) }, /* Central Standard */ { "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */ { "mst", tZONE, HOUR( 7) }, /* Mountain Standard */ { "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */ { "pst", tZONE, HOUR( 8) }, /* Pacific Standard */ { "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */ { "yst", tZONE, HOUR( 9) }, /* Yukon Standard */ { "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */ { "hst", tZONE, HOUR(10) }, /* Hawaii Standard */ { "hdt", tDAYZONE, HOUR(10) }, /* Hawaii Daylight */ { "cat", tZONE, HOUR(10) }, /* Central Alaska */ { "ahst", tZONE, HOUR(10) }, /* Alaska-Hawaii Standard */ { "nt", tZONE, HOUR(11) }, /* Nome */ { "idlw", tZONE, HOUR(12) }, /* International Date Line West */ { "cet", tZONE, -HOUR( 1) }, /* Central European */ { "cest", tDAYZONE, -HOUR( 1) }, /* Central European Summer */ { "met", tZONE, -HOUR( 1) }, /* Middle European */ { "mewt", tZONE, -HOUR( 1) }, /* Middle European Winter */ { "mest", tDAYZONE, -HOUR( 1) }, /* Middle European Summer */ { "swt", tZONE, -HOUR( 1) }, /* Swedish Winter */ { "sst", tDAYZONE, -HOUR( 1) }, /* Swedish Summer */ { "fwt", tZONE, -HOUR( 1) }, /* French Winter */ { "fst", tDAYZONE, -HOUR( 1) }, /* French Summer */ { "eet", tZONE, -HOUR( 2) }, /* Eastern Europe, USSR Zone 1 */ { "bt", tZONE, -HOUR( 3) }, /* Baghdad, USSR Zone 2 */ { "it", tZONE, -HOUR( 7/2) }, /* Iran */ { "zp4", tZONE, -HOUR( 4) }, /* USSR Zone 3 */ { "zp5", tZONE, -HOUR( 5) }, /* USSR Zone 4 */ { "ist", tZONE, -HOUR(11/2) }, /* Indian Standard */ { "zp6", tZONE, -HOUR( 6) }, /* USSR Zone 5 */ #if 0 /* For completeness. NST is also Newfoundland Stanard, nad SST is * also Swedish Summer. */ { "nst", tZONE, -HOUR(13/2) }, /* North Sumatra */ { "sst", tZONE, -HOUR( 7) }, /* South Sumatra, USSR Zone 6 */ #endif /* 0 */ { "wast", tZONE, -HOUR( 7) }, /* West Australian Standard */ { "wadt", tDAYZONE, -HOUR( 7) }, /* West Australian Daylight */ { "jt", tZONE, -HOUR(15/2) }, /* Java (3pm in Cronusland!) */ { "cct", tZONE, -HOUR( 8) }, /* China Coast, USSR Zone 7 */ { "jst", tZONE, -HOUR( 9) }, /* Japan Standard, USSR Zone 8 */ { "jdt", tDAYZONE, -HOUR( 9) }, /* Japan Daylight */ { "kst", tZONE, -HOUR( 9) }, /* Korea Standard */ { "kdt", tDAYZONE, -HOUR( 9) }, /* Korea Daylight */ { "cast", tZONE, -HOUR(19/2) }, /* Central Australian Standard */ { "cadt", tDAYZONE, -HOUR(19/2) }, /* Central Australian Daylight */ { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */ { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */ { "gst", tZONE, -HOUR(10) }, /* Guam Standard, USSR Zone 9 */ { "nzt", tZONE, -HOUR(12) }, /* New Zealand */ { "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */ { "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */ { "idle", tZONE, -HOUR(12) }, /* International Date Line East */ /* ADDED BY Marco Nijdam */ { "dst", tDST, HOUR( 0) }, /* DST on (hour is ignored) */ /* End ADDED */ { NULL } }; /* * Military timezone table. */ static CONST TABLE MilitaryTable[] = { { "a", tZONE, HOUR( 1) }, { "b", tZONE, HOUR( 2) }, { "c", tZONE, HOUR( 3) }, { "d", tZONE, HOUR( 4) }, { "e", tZONE, HOUR( 5) }, { "f", tZONE, HOUR( 6) }, { "g", tZONE, HOUR( 7) }, { "h", tZONE, HOUR( 8) }, { "i", tZONE, HOUR( 9) }, { "k", tZONE, HOUR( 10) }, { "l", tZONE, HOUR( 11) }, { "m", tZONE, HOUR( 12) }, { "n", tZONE, HOUR(- 1) }, { "o", tZONE, HOUR(- 2) }, { "p", tZONE, HOUR(- 3) }, { "q", tZONE, HOUR(- 4) }, { "r", tZONE, HOUR(- 5) }, { "s", tZONE, HOUR(- 6) }, { "t", tZONE, HOUR(- 7) }, { "u", tZONE, HOUR(- 8) }, { "v", tZONE, HOUR(- 9) }, { "w", tZONE, HOUR(-10) }, { "x", tZONE, HOUR(-11) }, { "y", tZONE, HOUR(-12) }, { "z", tZONE, HOUR( 0) }, { NULL } }; /* * Dump error messages in the bit bucket. */ static void TclDateerror(s) char *s; { } static time_t ToSeconds(Hours, Minutes, Seconds, Meridian) time_t Hours; time_t Minutes; time_t Seconds; MERIDIAN Meridian; { if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59) return -1; switch (Meridian) { case MER24: if (Hours < 0 || Hours > 23) return -1; return (Hours * 60L + Minutes) * 60L + Seconds; case MERam: if (Hours < 1 || Hours > 12) return -1; return ((Hours % 12) * 60L + Minutes) * 60L + Seconds; case MERpm: if (Hours < 1 || Hours > 12) return -1; return (((Hours % 12) + 12) * 60L + Minutes) * 60L + Seconds; } return -1; /* Should never be reached */ } /* *----------------------------------------------------------------------------- * * Convert -- * * Convert a {month, day, year, hours, minutes, seconds, meridian, dst} * tuple into a clock seconds value. * * Results: * 0 or -1 indicating success or failure. * * Side effects: * Fills TimePtr with the computed value. * *----------------------------------------------------------------------------- */ static int Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode, TimePtr) time_t Month; time_t Day; time_t Year; time_t Hours; time_t Minutes; time_t Seconds; MERIDIAN Meridian; DSTMODE DSTmode; time_t *TimePtr; { static int DaysInMonth[12] = { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; time_t tod; time_t Julian; int i; /* Figure out how many days are in February for the given year. * Every year divisible by 4 is a leap year. * But, every year divisible by 100 is not a leap year. * But, every year divisible by 400 is a leap year after all. */ DaysInMonth[1] = IsLeapYear(Year) ? 29 : 28; /* Check the inputs for validity */ if (Month < 1 || Month > 12 || Year < START_OF_TIME || Year > END_OF_TIME || Day < 1 || Day > DaysInMonth[(int)--Month]) return -1; /* Start computing the value. First determine the number of days * represented by the date, then multiply by the number of seconds/day. */ for (Julian = Day - 1, i = 0; i < Month; i++) Julian += DaysInMonth[i]; if (Year >= EPOCH) { for (i = EPOCH; i < Year; i++) Julian += 365 + IsLeapYear(i); } else { for (i = (int)Year; i < EPOCH; i++) Julian -= 365 + IsLeapYear(i); } Julian *= SECSPERDAY; /* Add the timezone offset ?? */ Julian += TclDateTimezone * 60L; /* Add the number of seconds represented by the time component */ if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0) return -1; Julian += tod; /* Perform a preliminary DST compensation ?? */ if (DSTmode == DSTon || (DSTmode == DSTmaybe && TclpGetDate((TclpTime_t)&Julian, 0)->tm_isdst)) Julian -= 60 * 60; *TimePtr = Julian; return 0; } static time_t DSTcorrect(Start, Future) time_t Start; time_t Future; { time_t StartDay; time_t FutureDay; StartDay = (TclpGetDate((TclpTime_t)&Start, 0)->tm_hour + 1) % 24; FutureDay = (TclpGetDate((TclpTime_t)&Future, 0)->tm_hour + 1) % 24; return (Future - Start) + (StartDay - FutureDay) * 60L * 60L; } static time_t NamedDay(Start, DayOrdinal, DayNumber) time_t Start; time_t DayOrdinal; time_t DayNumber; { struct tm *tm; time_t now; now = Start; tm = TclpGetDate((TclpTime_t)&now, 0); now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7); now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1); return DSTcorrect(Start, now); } static time_t NamedMonth(Start, MonthOrdinal, MonthNumber) time_t Start; time_t MonthOrdinal; time_t MonthNumber; { struct tm *tm; time_t now; int result; now = Start; tm = TclpGetDate((TclpTime_t)&now, 0); /* To compute the next n'th month, we use this alg: * add n to year value * if currentMonth < requestedMonth decrement year value by 1 (so that * doing next february from january gives us february of the current year) * set day to 1, time to 0 */ tm->tm_year += (int)MonthOrdinal; if (tm->tm_mon < MonthNumber - 1) { tm->tm_year--; } result = Convert(MonthNumber, (time_t) 1, tm->tm_year + TM_YEAR_BASE, (time_t) 0, (time_t) 0, (time_t) 0, MER24, DSTmaybe, &now); if (result < 0) { return 0; } return DSTcorrect(Start, now); } static int RelativeMonth(Start, RelMonth, TimePtr) time_t Start; time_t RelMonth; time_t *TimePtr; { struct tm *tm; time_t Month; time_t Year; time_t Julian; int result; if (RelMonth == 0) { *TimePtr = 0; return 0; } tm = TclpGetDate((TclpTime_t)&Start, 0); Month = 12 * (tm->tm_year + TM_YEAR_BASE) + tm->tm_mon + RelMonth; Year = Month / 12; Month = Month % 12 + 1; result = Convert(Month, (time_t) tm->tm_mday, Year, (time_t) tm->tm_hour, (time_t) tm->tm_min, (time_t) tm->tm_sec, MER24, DSTmaybe, &Julian); /* * The Julian time returned above is behind by one day, if "month" * or "year" is used to specify relative time and the GMT flag is true. * This problem occurs only when the current time is closer to * midnight, the difference being not more than its time difference * with GMT. For example, in US/Pacific time zone, the problem occurs * whenever the current time is between midnight to 8:00am or 7:00amDST. * See Bug# 413397 for more details and sample script. * To resolve this bug, we simply add the number of seconds corresponding * to timezone difference with GMT to Julian time, if GMT flag is true. */ if (TclDateTimezone == 0) { Julian += TclpGetTimeZone((unsigned long) Start) * 60L; } /* * The following iteration takes into account the case were we jump * into a "short month". Far example, "one month from Jan 31" will * fail because there is no Feb 31. The code below will reduce the * day and try converting the date until we succed or the date equals * 28 (which always works unless the date is bad in another way). */ while ((result != 0) && (tm->tm_mday > 28)) { tm->tm_mday--; result = Convert(Month, (time_t) tm->tm_mday, Year, (time_t) tm->tm_hour, (time_t) tm->tm_min, (time_t) tm->tm_sec, MER24, DSTmaybe, &Julian); } if (result != 0) { return -1; } *TimePtr = DSTcorrect(Start, Julian); return 0; } /* *----------------------------------------------------------------------------- * * RelativeDay -- * * Given a starting time and a number of days before or after, compute the * DST corrected difference between those dates. * * Results: * 1 or -1 indicating success or failure. * * Side effects: * Fills TimePtr with the computed value. * *----------------------------------------------------------------------------- */ static int RelativeDay(Start, RelDay, TimePtr) time_t Start; time_t RelDay; time_t *TimePtr; { time_t new; new = Start + (RelDay * 60 * 60 * 24); *TimePtr = DSTcorrect(Start, new); return 1; } static int LookupWord(buff) char *buff; { register char *p; register char *q; register CONST TABLE *tp; int i; int abbrev; /* * Make it lowercase. */ Tcl_UtfToLower(buff); if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) { TclDatelval.Meridian = MERam; return tMERIDIAN; } if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) { TclDatelval.Meridian = MERpm; return tMERIDIAN; } /* * See if we have an abbreviation for a month. */ if (strlen(buff) == 3) { abbrev = 1; } else if (strlen(buff) == 4 && buff[3] == '.') { abbrev = 1; buff[3] = '\0'; } else { abbrev = 0; } for (tp = MonthDayTable; tp->name; tp++) { if (abbrev) { if (strncmp(buff, tp->name, 3) == 0) { TclDatelval.Number = tp->value; return tp->type; } } else if (strcmp(buff, tp->name) == 0) { TclDatelval.Number = tp->value; return tp->type; } } for (tp = TimezoneTable; tp->name; tp++) { if (strcmp(buff, tp->name) == 0) { TclDatelval.Number = tp->value; return tp->type; } } for (tp = UnitsTable; tp->name; tp++) { if (strcmp(buff, tp->name) == 0) { TclDatelval.Number = tp->value; return tp->type; } } /* * Strip off any plural and try the units table again. */ i = strlen(buff) - 1; if (buff[i] == 's') { buff[i] = '\0'; for (tp = UnitsTable; tp->name; tp++) { if (strcmp(buff, tp->name) == 0) { TclDatelval.Number = tp->value; return tp->type; } } } for (tp = OtherTable; tp->name; tp++) { if (strcmp(buff, tp->name) == 0) { TclDatelval.Number = tp->value; return tp->type; } } /* * Military timezones. */ if (buff[1] == '\0' && !(*buff & 0x80) && isalpha(UCHAR(*buff))) { /* INTL: ISO only */ for (tp = MilitaryTable; tp->name; tp++) { if (strcmp(buff, tp->name) == 0) { TclDatelval.Number = tp->value; return tp->type; } } } /* * Drop out any periods and try the timezone table again. */ for (i = 0, p = q = buff; *q; q++) if (*q != '.') { *p++ = *q; } else { i++; } *p = '\0'; if (i) { for (tp = TimezoneTable; tp->name; tp++) { if (strcmp(buff, tp->name) == 0) { TclDatelval.Number = tp->value; return tp->type; } } } return tID; } static int TclDatelex() { register char c; register char *p; char buff[20]; int Count; for ( ; ; ) { while (isspace(UCHAR(*TclDateInput))) { TclDateInput++; } if (isdigit(UCHAR(c = *TclDateInput))) { /* INTL: digit */ /* convert the string into a number; count the number of digits */ Count = 0; for (TclDatelval.Number = 0; isdigit(UCHAR(c = *TclDateInput++)); ) { /* INTL: digit */ TclDatelval.Number = 10 * TclDatelval.Number + c - '0'; Count++; } TclDateInput--; /* A number with 6 or more digits is considered an ISO 8601 base */ if (Count >= 6) { return tISOBASE; } else { return tUNUMBER; } } if (!(c & 0x80) && isalpha(UCHAR(c))) { /* INTL: ISO only. */ for (p = buff; isalpha(UCHAR(c = *TclDateInput++)) /* INTL: ISO only. */ || c == '.'; ) { if (p < &buff[sizeof buff - 1]) { *p++ = c; } } *p = '\0'; TclDateInput--; return LookupWord(buff); } if (c != '(') { return *TclDateInput++; } Count = 0; do { c = *TclDateInput++; if (c == '\0') { return c; } else if (c == '(') { Count++; } else if (c == ')') { Count--; } } while (Count > 0); } } /* * Specify zone is of -50000 to force GMT. (This allows BST to work). */ int TclGetDate(p, now, zone, timePtr) char *p; Tcl_WideInt now; long zone; Tcl_WideInt *timePtr; { struct tm *tm; time_t Start; time_t Time; time_t tod; int thisyear; TclDateInput = p; /* now has to be cast to a time_t for 64bit compliance */ Start = (time_t) now; tm = TclpGetDate((TclpTime_t) &Start, (zone == -50000)); thisyear = tm->tm_year + TM_YEAR_BASE; TclDateYear = thisyear; TclDateMonth = tm->tm_mon + 1; TclDateDay = tm->tm_mday; TclDateTimezone = zone; if (zone == -50000) { TclDateDSTmode = DSToff; /* assume GMT */ TclDateTimezone = 0; } else { TclDateDSTmode = DSTmaybe; } TclDateHour = 0; TclDateMinutes = 0; TclDateSeconds = 0; TclDateMeridian = MER24; TclDateRelSeconds = 0; TclDateRelMonth = 0; TclDateRelDay = 0; TclDateRelPointer = NULL; TclDateHaveDate = 0; TclDateHaveDay = 0; TclDateHaveOrdinalMonth = 0; TclDateHaveRel = 0; TclDateHaveTime = 0; TclDateHaveZone = 0; if (TclDateparse() || TclDateHaveTime > 1 || TclDateHaveZone > 1 || TclDateHaveDate > 1 || TclDateHaveDay > 1 || TclDateHaveOrdinalMonth > 1) { return -1; } if (TclDateHaveDate || TclDateHaveTime || TclDateHaveDay) { if (TclDateYear < 0) { TclDateYear = -TclDateYear; } /* * The following line handles years that are specified using * only two digits. The line of code below implements a policy * defined by the X/Open workgroup on the millinium rollover. * Note: some of those dates may not actually be valid on some * platforms. The POSIX standard startes that the dates 70-99 * shall refer to 1970-1999 and 00-38 shall refer to 2000-2038. * This later definition should work on all platforms. */ if (TclDateYear < 100) { if (TclDateYear >= 69) { TclDateYear += 1900; } else { TclDateYear += 2000; } } if (Convert(TclDateMonth, TclDateDay, TclDateYear, TclDateHour, TclDateMinutes, TclDateSeconds, TclDateMeridian, TclDateDSTmode, &Start) < 0) { return -1; } } else { Start = (time_t) now; if (!TclDateHaveRel) { Start -= ((tm->tm_hour * 60L * 60L) + tm->tm_min * 60L) + tm->tm_sec; } } Start += TclDateRelSeconds; if (RelativeMonth(Start, TclDateRelMonth, &Time) < 0) { return -1; } Start += Time; if (RelativeDay(Start, TclDateRelDay, &Time) < 0) { return -1; } Start += Time; if (TclDateHaveDay && !TclDateHaveDate) { tod = NamedDay(Start, TclDateDayOrdinal, TclDateDayNumber); Start += tod; } if (TclDateHaveOrdinalMonth) { tod = NamedMonth(Start, TclDateMonthOrdinal, TclDateMonth); Start += tod; } *timePtr = Start; return 0; } static CONST TclDatetabelem TclDateexca[] ={ -1, 1, 0, -1, -2, 0, }; # define YYNPROD 56 # define YYLAST 261 static CONST TclDatetabelem TclDateact[]={ 24, 40, 23, 36, 54, 81, 41, 28, 53, 26, 37, 42, 58, 38, 56, 28, 27, 26, 28, 33, 26, 32, 61, 50, 27, 80, 76, 27, 51, 75, 74, 73, 30, 72, 71, 70, 69, 52, 49, 48, 47, 45, 39, 62, 78, 46, 79, 68, 25, 65, 60, 67, 66, 55, 44, 21, 63, 11, 10, 9, 8, 35, 7, 6, 5, 4, 3, 43, 2, 1, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57, 0, 0, 59, 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 14, 0, 0, 0, 16, 28, 22, 26, 0, 12, 13, 17, 0, 15, 27, 18, 31, 0, 0, 29, 0, 34, 28, 0, 26, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 64 }; static CONST TclDatetabelem TclDatepact[]={ -10000000, -43,-10000000,-10000000,-10000000,-10000000,-10000000,-10000000,-10000000,-10000000, -10000000,-10000000, -26, -268,-10000000, -259, -226,-10000000, -257, 10, -227, -212, -228,-10000000,-10000000,-10000000,-10000000,-10000000,-10000000,-10000000, -229,-10000000, -230, -240, -231,-10000000,-10000000, -264,-10000000, 9, -10000000,-10000000, -249,-10000000,-10000000, -246,-10000000, 4, -2, 2, 7, 6,-10000000,-10000000, -11, -232,-10000000,-10000000,-10000000,-10000000, -233,-10000000, -234, -235,-10000000, -237, -238, -239, -242,-10000000, -10000000,-10000000, -1,-10000000,-10000000,-10000000, -12,-10000000, -243, -263, -10000000,-10000000 }; static CONST TclDatetabelem TclDatepgo[]={ 0, 48, 70, 22, 69, 68, 66, 65, 64, 63, 62, 60, 59, 58, 57, 55 }; static CONST TclDatetabelem TclDater1[]={ 0, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 7, 7, 7, 10, 10, 10, 10, 10, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 12, 12, 12, 13, 11, 11, 15, 15, 15, 15, 15, 2, 2, 1, 1, 1, 14, 3, 3 }; static CONST TclDatetabelem TclDater2[]={ 0, 0, 4, 3, 3, 3, 3, 3, 3, 3, 3, 2, 5, 9, 11, 13, 15, 5, 3, 3, 3, 5, 5, 7, 5, 7, 11, 3, 11, 11, 5, 9, 5, 3, 7, 5, 7, 7, 15, 5, 9, 5, 2, 7, 5, 5, 7, 3, 3, 3, 3, 3, 3, 3, 1, 3 }; static CONST TclDatetabelem TclDatechk[]={ -10000000, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13, -14, 268, 269, 259, 272, 263, 270, 274, 258, -2, -15, 265, 45, 43, -1, 266, 273, 264, 261, 58, 258, 47, 45, 263, -1, 271, 269, 272, 268, 258, 263, 268, -1, 44, 268, 257, 268, 268, 268, 263, 268, 268, 272, 268, 44, 263, -1, 258, -1, 46, -3, 45, 58, 261, 47, 45, 45, 58, 268, 268, 268, 268, 268, 268, 268, 268, -3, 45, 58, 268, 268 }; static CONST TclDatetabelem TclDatedef[]={ 1, -2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 53, 18, 19, 27, 0, 33, 0, 20, 0, 42, 0, 48, 49, 47, 50, 51, 52, 12, 0, 22, 0, 0, 32, 44, 17, 0, 39, 30, 24, 35, 0, 45, 21, 0, 41, 0, 54, 25, 0, 0, 34, 37, 0, 0, 36, 46, 23, 43, 0, 13, 0, 0, 55, 0, 0, 0, 0, 31, 40, 14, 54, 26, 28, 29, 0, 15, 0, 0, 16, 38 }; typedef struct #ifdef __cplusplus TclDatetoktype #endif { char *t_name; int t_val; } TclDatetoktype; #ifndef YYDEBUG # define YYDEBUG 0 /* don't allow debugging */ #endif #if YYDEBUG TclDatetoktype TclDatetoks[] = { "tAGO", 257, "tDAY", 258, "tDAYZONE", 259, "tID", 260, "tMERIDIAN", 261, "tMINUTE_UNIT", 262, "tMONTH", 263, "tMONTH_UNIT", 264, "tSTARDATE", 265, "tSEC_UNIT", 266, "tSNUMBER", 267, "tUNUMBER", 268, "tZONE", 269, "tEPOCH", 270, "tDST", 271, "tISOBASE", 272, "tDAY_UNIT", 273, "tNEXT", 274, "-unknown-", -1 /* ends search */ }; char * TclDatereds[] = { "-no such reduction-", "spec : /* empty */", "spec : spec item", "item : time", "item : zone", "item : date", "item : ordMonth", "item : day", "item : relspec", "item : iso", "item : trek", "item : number", "time : tUNUMBER tMERIDIAN", "time : tUNUMBER ':' tUNUMBER o_merid", "time : tUNUMBER ':' tUNUMBER '-' tUNUMBER", "time : tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid", "time : tUNUMBER ':' tUNUMBER ':' tUNUMBER '-' tUNUMBER", "zone : tZONE tDST", "zone : tZONE", "zone : tDAYZONE", "day : tDAY", "day : tDAY ','", "day : tUNUMBER tDAY", "day : sign tUNUMBER tDAY", "day : tNEXT tDAY", "date : tUNUMBER '/' tUNUMBER", "date : tUNUMBER '/' tUNUMBER '/' tUNUMBER", "date : tISOBASE", "date : tUNUMBER '-' tMONTH '-' tUNUMBER", "date : tUNUMBER '-' tUNUMBER '-' tUNUMBER", "date : tMONTH tUNUMBER", "date : tMONTH tUNUMBER ',' tUNUMBER", "date : tUNUMBER tMONTH", "date : tEPOCH", "date : tUNUMBER tMONTH tUNUMBER", "ordMonth : tNEXT tMONTH", "ordMonth : tNEXT tUNUMBER tMONTH", "iso : tISOBASE tZONE tISOBASE", "iso : tISOBASE tZONE tUNUMBER ':' tUNUMBER ':' tUNUMBER", "iso : tISOBASE tISOBASE", "trek : tSTARDATE tUNUMBER '.' tUNUMBER", "relspec : relunits tAGO", "relspec : relunits", "relunits : sign tUNUMBER unit", "relunits : tUNUMBER unit", "relunits : tNEXT unit", "relunits : tNEXT tUNUMBER unit", "relunits : unit", "sign : '-'", "sign : '+'", "unit : tSEC_UNIT", "unit : tDAY_UNIT", "unit : tMONTH_UNIT", "number : tUNUMBER", "o_merid : /* empty */", "o_merid : tMERIDIAN", }; #endif /* YYDEBUG */ /* * Copyright (c) 1993 by Sun Microsystems, Inc. */ /* ** Skeleton parser driver for yacc output */ /* ** yacc user known macros and defines */ #define YYERROR goto TclDateerrlab #define YYACCEPT return(0) #define YYABORT return(1) #define YYBACKUP( newtoken, newvalue )\ {\ if ( TclDatechar >= 0 || ( TclDater2[ TclDatetmp ] >> 1 ) != 1 )\ {\ TclDateerror( "syntax error - cannot backup" );\ goto TclDateerrlab;\ }\ TclDatechar = newtoken;\ TclDatestate = *TclDateps;\ TclDatelval = newvalue;\ goto TclDatenewstate;\ } #define YYRECOVERING() (!!TclDateerrflag) #define YYNEW(type) malloc(sizeof(type) * TclDatenewmax) #define YYCOPY(to, from, type) \ (type *) memcpy(to, (char *) from, TclDatemaxdepth * sizeof (type)) #define YYENLARGE( from, type) \ (type *) realloc((char *) from, TclDatenewmax * sizeof(type)) #ifndef YYDEBUG # define YYDEBUG 1 /* make debugging available */ #endif /* ** user known globals */ int TclDatedebug; /* set to 1 to get debugging */ /* ** driver internal defines */ #define YYFLAG (-10000000) /* ** global variables used by the parser */ YYSTYPE *TclDatepv; /* top of value stack */ int *TclDateps; /* top of state stack */ int TclDatestate; /* current state */ int TclDatetmp; /* extra var (lasts between blocks) */ int TclDatenerrs; /* number of errors */ int TclDateerrflag; /* error recovery flag */ int TclDatechar; /* current input token number */ #ifdef YYNMBCHARS #define YYLEX() TclDatecvtok(TclDatelex()) /* ** TclDatecvtok - return a token if i is a wchar_t value that exceeds 255. ** If i<255, i itself is the token. If i>255 but the neither ** of the 30th or 31st bit is on, i is already a token. */ #if defined(__STDC__) || defined(__cplusplus) int TclDatecvtok(int i) #else int TclDatecvtok(i) int i; #endif { int first = 0; int last = YYNMBCHARS - 1; int mid; wchar_t j; if(i&0x60000000){/*Must convert to a token. */ if( TclDatembchars[last].character < i ){ return i;/*Giving up*/ } while ((last>=first)&&(first>=0)) {/*Binary search loop*/ mid = (first+last)/2; j = TclDatembchars[mid].character; if( j==i ){/*Found*/ return TclDatembchars[mid].tvalue; }else if( j= 0; TclDate_i++ ) { if ( TclDatetoks[TclDate_i].t_val == TclDatechar ) break; } printf( "%s\n", TclDatetoks[TclDate_i].t_name ); } } #endif /* YYDEBUG */ if ( ++TclDate_ps >= &TclDates[ TclDatemaxdepth ] ) /* room on stack? */ { /* ** reallocate and recover. Note that pointers ** have to be reset, or bad things will happen */ long TclDateps_index = (TclDate_ps - TclDates); long TclDatepv_index = (TclDate_pv - TclDatev); long TclDatepvt_index = (TclDatepvt - TclDatev); int TclDatenewmax; #ifdef YYEXPAND TclDatenewmax = YYEXPAND(TclDatemaxdepth); #else TclDatenewmax = 2 * TclDatemaxdepth; /* double table size */ if (TclDatemaxdepth == YYMAXDEPTH) /* first time growth */ { char *newTclDates = (char *)YYNEW(int); char *newTclDatev = (char *)YYNEW(YYSTYPE); if (newTclDates != 0 && newTclDatev != 0) { TclDates = YYCOPY(newTclDates, TclDates, int); TclDatev = YYCOPY(newTclDatev, TclDatev, YYSTYPE); } else TclDatenewmax = 0; /* failed */ } else /* not first time */ { TclDates = YYENLARGE(TclDates, int); TclDatev = YYENLARGE(TclDatev, YYSTYPE); if (TclDates == 0 || TclDatev == 0) TclDatenewmax = 0; /* failed */ } #endif if (TclDatenewmax <= TclDatemaxdepth) /* tables not expanded */ { TclDateerror( "yacc stack overflow" ); YYABORT; } TclDatemaxdepth = TclDatenewmax; TclDate_ps = TclDates + TclDateps_index; TclDate_pv = TclDatev + TclDatepv_index; TclDatepvt = TclDatev + TclDatepvt_index; } *TclDate_ps = TclDate_state; *++TclDate_pv = TclDateval; /* ** we have a new state - find out what to do */ TclDate_newstate: if ( ( TclDate_n = TclDatepact[ TclDate_state ] ) <= YYFLAG ) goto TclDatedefault; /* simple state */ #if YYDEBUG /* ** if debugging, need to mark whether new token grabbed */ TclDatetmp = TclDatechar < 0; #endif if ( ( TclDatechar < 0 ) && ( ( TclDatechar = YYLEX() ) < 0 ) ) TclDatechar = 0; /* reached EOF */ #if YYDEBUG if ( TclDatedebug && TclDatetmp ) { register int TclDate_i; printf( "Received token " ); if ( TclDatechar == 0 ) printf( "end-of-file\n" ); else if ( TclDatechar < 0 ) printf( "-none-\n" ); else { for ( TclDate_i = 0; TclDatetoks[TclDate_i].t_val >= 0; TclDate_i++ ) { if ( TclDatetoks[TclDate_i].t_val == TclDatechar ) break; } printf( "%s\n", TclDatetoks[TclDate_i].t_name ); } } #endif /* YYDEBUG */ if ( ( ( TclDate_n += TclDatechar ) < 0 ) || ( TclDate_n >= YYLAST ) ) goto TclDatedefault; if ( TclDatechk[ TclDate_n = TclDateact[ TclDate_n ] ] == TclDatechar ) /*valid shift*/ { TclDatechar = -1; TclDateval = TclDatelval; TclDate_state = TclDate_n; if ( TclDateerrflag > 0 ) TclDateerrflag--; goto TclDate_stack; } TclDatedefault: if ( ( TclDate_n = TclDatedef[ TclDate_state ] ) == -2 ) { #if YYDEBUG TclDatetmp = TclDatechar < 0; #endif if ( ( TclDatechar < 0 ) && ( ( TclDatechar = YYLEX() ) < 0 ) ) TclDatechar = 0; /* reached EOF */ #if YYDEBUG if ( TclDatedebug && TclDatetmp ) { register int TclDate_i; printf( "Received token " ); if ( TclDatechar == 0 ) printf( "end-of-file\n" ); else if ( TclDatechar < 0 ) printf( "-none-\n" ); else { for ( TclDate_i = 0; TclDatetoks[TclDate_i].t_val >= 0; TclDate_i++ ) { if ( TclDatetoks[TclDate_i].t_val == TclDatechar ) { break; } } printf( "%s\n", TclDatetoks[TclDate_i].t_name ); } } #endif /* YYDEBUG */ /* ** look through exception table */ { register CONST int *TclDatexi = TclDateexca; while ( ( *TclDatexi != -1 ) || ( TclDatexi[1] != TclDate_state ) ) { TclDatexi += 2; } while ( ( *(TclDatexi += 2) >= 0 ) && ( *TclDatexi != TclDatechar ) ) ; if ( ( TclDate_n = TclDatexi[1] ) < 0 ) YYACCEPT; } } /* ** check for syntax error */ if ( TclDate_n == 0 ) /* have an error */ { /* no worry about speed here! */ switch ( TclDateerrflag ) { case 0: /* new error */ TclDateerror( "syntax error" ); goto skip_init; /* ** get globals into registers. ** we have a user generated syntax type error */ TclDate_pv = TclDatepv; TclDate_ps = TclDateps; TclDate_state = TclDatestate; skip_init: TclDatenerrs++; /* FALLTHRU */ case 1: case 2: /* incompletely recovered error */ /* try again... */ TclDateerrflag = 3; /* ** find state where "error" is a legal ** shift action */ while ( TclDate_ps >= TclDates ) { TclDate_n = TclDatepact[ *TclDate_ps ] + YYERRCODE; if ( TclDate_n >= 0 && TclDate_n < YYLAST && TclDatechk[TclDateact[TclDate_n]] == YYERRCODE) { /* ** simulate shift of "error" */ TclDate_state = TclDateact[ TclDate_n ]; goto TclDate_stack; } /* ** current state has no shift on ** "error", pop stack */ #if YYDEBUG # define _POP_ "Error recovery pops state %d, uncovers state %d\n" if ( TclDatedebug ) printf( _POP_, *TclDate_ps, TclDate_ps[-1] ); # undef _POP_ #endif TclDate_ps--; TclDate_pv--; } /* ** there is no state on stack with "error" as ** a valid shift. give up. */ YYABORT; case 3: /* no shift yet; eat a token */ #if YYDEBUG /* ** if debugging, look up token in list of ** pairs. 0 and negative shouldn't occur, ** but since timing doesn't matter when ** debugging, it doesn't hurt to leave the ** tests here. */ if ( TclDatedebug ) { register int TclDate_i; printf( "Error recovery discards " ); if ( TclDatechar == 0 ) printf( "token end-of-file\n" ); else if ( TclDatechar < 0 ) printf( "token -none-\n" ); else { for ( TclDate_i = 0; TclDatetoks[TclDate_i].t_val >= 0; TclDate_i++ ) { if ( TclDatetoks[TclDate_i].t_val == TclDatechar ) { break; } } printf( "token %s\n", TclDatetoks[TclDate_i].t_name ); } } #endif /* YYDEBUG */ if ( TclDatechar == 0 ) /* reached EOF. quit */ YYABORT; TclDatechar = -1; goto TclDate_newstate; } }/* end if ( TclDate_n == 0 ) */ /* ** reduction by production TclDate_n ** put stack tops, etc. so things right after switch */ #if YYDEBUG /* ** if debugging, print the string that is the user's ** specification of the reduction which is just about ** to be done. */ if ( TclDatedebug ) printf( "Reduce by (%d) \"%s\"\n", TclDate_n, TclDatereds[ TclDate_n ] ); #endif TclDatetmp = TclDate_n; /* value to switch over */ TclDatepvt = TclDate_pv; /* $vars top of value stack */ /* ** Look in goto table for next state ** Sorry about using TclDate_state here as temporary ** register variable, but why not, if it works... ** If TclDater2[ TclDate_n ] doesn't have the low order bit ** set, then there is no action to be done for ** this reduction. So, no saving & unsaving of ** registers done. The only difference between the ** code just after the if and the body of the if is ** the goto TclDate_stack in the body. This way the test ** can be made before the choice of what to do is needed. */ { /* length of production doubled with extra bit */ register int TclDate_len = TclDater2[ TclDate_n ]; if ( !( TclDate_len & 01 ) ) { TclDate_len >>= 1; TclDateval = ( TclDate_pv -= TclDate_len )[1]; /* $$ = $1 */ TclDate_state = TclDatepgo[ TclDate_n = TclDater1[ TclDate_n ] ] + *( TclDate_ps -= TclDate_len ) + 1; if ( TclDate_state >= YYLAST || TclDatechk[ TclDate_state = TclDateact[ TclDate_state ] ] != -TclDate_n ) { TclDate_state = TclDateact[ TclDatepgo[ TclDate_n ] ]; } goto TclDate_stack; } TclDate_len >>= 1; TclDateval = ( TclDate_pv -= TclDate_len )[1]; /* $$ = $1 */ TclDate_state = TclDatepgo[ TclDate_n = TclDater1[ TclDate_n ] ] + *( TclDate_ps -= TclDate_len ) + 1; if ( TclDate_state >= YYLAST || TclDatechk[ TclDate_state = TclDateact[ TclDate_state ] ] != -TclDate_n ) { TclDate_state = TclDateact[ TclDatepgo[ TclDate_n ] ]; } } /* save until reenter driver code */ TclDatestate = TclDate_state; TclDateps = TclDate_ps; TclDatepv = TclDate_pv; } /* ** code supplied by user is placed in this switch */ switch( TclDatetmp ) { case 3:{ TclDateHaveTime++; } break; case 4:{ TclDateHaveZone++; } break; case 5:{ TclDateHaveDate++; } break; case 6:{ TclDateHaveOrdinalMonth++; } break; case 7:{ TclDateHaveDay++; } break; case 8:{ TclDateHaveRel++; } break; case 9:{ TclDateHaveTime++; TclDateHaveDate++; } break; case 10:{ TclDateHaveTime++; TclDateHaveDate++; TclDateHaveRel++; } break; case 12:{ TclDateHour = TclDatepvt[-1].Number; TclDateMinutes = 0; TclDateSeconds = 0; TclDateMeridian = TclDatepvt[-0].Meridian; } break; case 13:{ TclDateHour = TclDatepvt[-3].Number; TclDateMinutes = TclDatepvt[-1].Number; TclDateSeconds = 0; TclDateMeridian = TclDatepvt[-0].Meridian; } break; case 14:{ TclDateHour = TclDatepvt[-4].Number; TclDateMinutes = TclDatepvt[-2].Number; TclDateMeridian = MER24; TclDateDSTmode = DSToff; TclDateTimezone = (TclDatepvt[-0].Number % 100 + (TclDatepvt[-0].Number / 100) * 60); } break; case 15:{ TclDateHour = TclDatepvt[-5].Number; TclDateMinutes = TclDatepvt[-3].Number; TclDateSeconds = TclDatepvt[-1].Number; TclDateMeridian = TclDatepvt[-0].Meridian; } break; case 16:{ TclDateHour = TclDatepvt[-6].Number; TclDateMinutes = TclDatepvt[-4].Number; TclDateSeconds = TclDatepvt[-2].Number; TclDateMeridian = MER24; TclDateDSTmode = DSToff; TclDateTimezone = (TclDatepvt[-0].Number % 100 + (TclDatepvt[-0].Number / 100) * 60); } break; case 17:{ TclDateTimezone = TclDatepvt[-1].Number; TclDateDSTmode = DSTon; } break; case 18:{ TclDateTimezone = TclDatepvt[-0].Number; TclDateDSTmode = DSToff; } break; case 19:{ TclDateTimezone = TclDatepvt[-0].Number; TclDateDSTmode = DSTon; } break; case 20:{ TclDateDayOrdinal = 1; TclDateDayNumber = TclDatepvt[-0].Number; } break; case 21:{ TclDateDayOrdinal = 1; TclDateDayNumber = TclDatepvt[-1].Number; } break; case 22:{ TclDateDayOrdinal = TclDatepvt[-1].Number; TclDateDayNumber = TclDatepvt[-0].Number; } break; case 23:{ TclDateDayOrdinal = TclDatepvt[-2].Number * TclDatepvt[-1].Number; TclDateDayNumber = TclDatepvt[-0].Number; } break; case 24:{ TclDateDayOrdinal = 2; TclDateDayNumber = TclDatepvt[-0].Number; } break; case 25:{ TclDateMonth = TclDatepvt[-2].Number; TclDateDay = TclDatepvt[-0].Number; } break; case 26:{ TclDateMonth = TclDatepvt[-4].Number; TclDateDay = TclDatepvt[-2].Number; TclDateYear = TclDatepvt[-0].Number; } break; case 27:{ TclDateYear = TclDatepvt[-0].Number / 10000; TclDateMonth = (TclDatepvt[-0].Number % 10000)/100; TclDateDay = TclDatepvt[-0].Number % 100; } break; case 28:{ TclDateDay = TclDatepvt[-4].Number; TclDateMonth = TclDatepvt[-2].Number; TclDateYear = TclDatepvt[-0].Number; } break; case 29:{ TclDateMonth = TclDatepvt[-2].Number; TclDateDay = TclDatepvt[-0].Number; TclDateYear = TclDatepvt[-4].Number; } break; case 30:{ TclDateMonth = TclDatepvt[-1].Number; TclDateDay = TclDatepvt[-0].Number; } break; case 31:{ TclDateMonth = TclDatepvt[-3].Number; TclDateDay = TclDatepvt[-2].Number; TclDateYear = TclDatepvt[-0].Number; } break; case 32:{ TclDateMonth = TclDatepvt[-0].Number; TclDateDay = TclDatepvt[-1].Number; } break; case 33:{ TclDateMonth = 1; TclDateDay = 1; TclDateYear = EPOCH; } break; case 34:{ TclDateMonth = TclDatepvt[-1].Number; TclDateDay = TclDatepvt[-2].Number; TclDateYear = TclDatepvt[-0].Number; } break; case 35:{ TclDateMonthOrdinal = 1; TclDateMonth = TclDatepvt[-0].Number; } break; case 36:{ TclDateMonthOrdinal = TclDatepvt[-1].Number; TclDateMonth = TclDatepvt[-0].Number; } break; case 37:{ if (TclDatepvt[-1].Number != HOUR(- 7)) YYABORT; TclDateYear = TclDatepvt[-2].Number / 10000; TclDateMonth = (TclDatepvt[-2].Number % 10000)/100; TclDateDay = TclDatepvt[-2].Number % 100; TclDateHour = TclDatepvt[-0].Number / 10000; TclDateMinutes = (TclDatepvt[-0].Number % 10000)/100; TclDateSeconds = TclDatepvt[-0].Number % 100; } break; case 38:{ if (TclDatepvt[-5].Number != HOUR(- 7)) YYABORT; TclDateYear = TclDatepvt[-6].Number / 10000; TclDateMonth = (TclDatepvt[-6].Number % 10000)/100; TclDateDay = TclDatepvt[-6].Number % 100; TclDateHour = TclDatepvt[-4].Number; TclDateMinutes = TclDatepvt[-2].Number; TclDateSeconds = TclDatepvt[-0].Number; } break; case 39:{ TclDateYear = TclDatepvt[-1].Number / 10000; TclDateMonth = (TclDatepvt[-1].Number % 10000)/100; TclDateDay = TclDatepvt[-1].Number % 100; TclDateHour = TclDatepvt[-0].Number / 10000; TclDateMinutes = (TclDatepvt[-0].Number % 10000)/100; TclDateSeconds = TclDatepvt[-0].Number % 100; } break; case 40:{ /* * Offset computed year by -377 so that the returned years will * be in a range accessible with a 32 bit clock seconds value */ TclDateYear = TclDatepvt[-2].Number/1000 + 2323 - 377; TclDateDay = 1; TclDateMonth = 1; TclDateRelDay += ((TclDatepvt[-2].Number%1000)*(365 + IsLeapYear(TclDateYear)))/1000; TclDateRelSeconds += TclDatepvt[-0].Number * 144 * 60; } break; case 41:{ TclDateRelSeconds *= -1; TclDateRelMonth *= -1; TclDateRelDay *= -1; } break; case 43:{ *TclDateRelPointer += TclDatepvt[-2].Number * TclDatepvt[-1].Number * TclDatepvt[-0].Number; } break; case 44:{ *TclDateRelPointer += TclDatepvt[-1].Number * TclDatepvt[-0].Number; } break; case 45:{ *TclDateRelPointer += TclDatepvt[-0].Number; } break; case 46:{ *TclDateRelPointer += TclDatepvt[-1].Number * TclDatepvt[-0].Number; } break; case 47:{ *TclDateRelPointer += TclDatepvt[-0].Number; } break; case 48:{ TclDateval.Number = -1; } break; case 49:{ TclDateval.Number = 1; } break; case 50:{ TclDateval.Number = TclDatepvt[-0].Number; TclDateRelPointer = &TclDateRelSeconds; } break; case 51:{ TclDateval.Number = TclDatepvt[-0].Number; TclDateRelPointer = &TclDateRelDay; } break; case 52:{ TclDateval.Number = TclDatepvt[-0].Number; TclDateRelPointer = &TclDateRelMonth; } break; case 53:{ if (TclDateHaveTime && TclDateHaveDate && !TclDateHaveRel) { TclDateYear = TclDatepvt[-0].Number; } else { TclDateHaveTime++; if (TclDatepvt[-0].Number < 100) { TclDateHour = TclDatepvt[-0].Number; TclDateMinutes = 0; } else { TclDateHour = TclDatepvt[-0].Number / 100; TclDateMinutes = TclDatepvt[-0].Number % 100; } TclDateSeconds = 0; TclDateMeridian = MER24; } } break; case 54:{ TclDateval.Meridian = MER24; } break; case 55:{ TclDateval.Meridian = TclDatepvt[-0].Meridian; } break; } goto TclDatestack; /* reset registers in driver code */ } tcl8.4.20/generic/tclStubLib.c0000644003604700454610000000551512133546540014545 0ustar dgp771div/* * tclStubLib.c -- * * Stub object that will be statically linked into extensions that want * to access Tcl. * * Copyright (c) 1998-1999 by Scriptics Corporation. * Copyright (c) 1998 Paul Duffin. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" TclStubs *tclStubsPtr = NULL; TclPlatStubs *tclPlatStubsPtr = NULL; TclIntStubs *tclIntStubsPtr = NULL; TclIntPlatStubs *tclIntPlatStubsPtr = NULL; /* * Use our own ISDIGIT to avoid linking to libc on windows */ #define ISDIGIT(c) (((unsigned)((c)-'0')) <= 9) /* *---------------------------------------------------------------------- * * Tcl_InitStubs -- * * Tries to initialise the stub table pointers and ensures that the * correct version of Tcl is loaded. * * Results: * The actual version of Tcl that satisfies the request, or NULL to * indicate that an error occurred. * * Side effects: * Sets the stub table pointers. * *---------------------------------------------------------------------- */ #undef Tcl_InitStubs CONST char * Tcl_InitStubs(interp, version, exact) Tcl_Interp *interp; CONST char *version; int exact; { Interp *iPtr = (Interp *) interp; CONST char *actualVersion = NULL; ClientData pkgData = NULL; TclStubs *stubsPtr = iPtr->stubTable; /* * We can't optimize this check by caching tclStubsPtr because that * prevents apps from being able to load/unload Tcl dynamically multiple * times. [Bug 615304] */ if (!stubsPtr || (stubsPtr->magic != TCL_STUB_MAGIC)) { iPtr->result = "interpreter uses an incompatible stubs mechanism"; iPtr->freeProc = TCL_STATIC; return NULL; } actualVersion = stubsPtr->tcl_PkgRequireEx(interp, "Tcl", version, 0, &pkgData); if (actualVersion == NULL) { return NULL; } if (exact) { CONST char *p = version; int count = 0; while (*p) { count += !ISDIGIT(*p++); } if (count == 1) { CONST char *q = actualVersion; p = version; while (*p && (*p == *q)) { p++; q++; } if (*p || ISDIGIT(*q)) { /* Construct error message */ stubsPtr->tcl_PkgRequireEx(interp, "Tcl", version, 1, NULL); return NULL; } } else { actualVersion = stubsPtr->tcl_PkgRequireEx(interp, "Tcl", version, 1, NULL); if (actualVersion == NULL) { return NULL; } } } tclStubsPtr = (TclStubs *)pkgData; if (tclStubsPtr->hooks) { tclPlatStubsPtr = tclStubsPtr->hooks->tclPlatStubs; tclIntStubsPtr = tclStubsPtr->hooks->tclIntStubs; tclIntPlatStubsPtr = tclStubsPtr->hooks->tclIntPlatStubs; } else { tclPlatStubsPtr = NULL; tclIntStubsPtr = NULL; tclIntPlatStubsPtr = NULL; } return actualVersion; } /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ tcl8.4.20/generic/tclFileName.c0000644003604700454610000016410612133546540014663 0ustar dgp771div/* * tclFileName.c -- * * This file contains routines for converting file names betwen * native and network form. * * Copyright (c) 1995-1998 Sun Microsystems, Inc. * Copyright (c) 1998-1999 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include #include "tclInt.h" #include "tclPort.h" #include "tclRegexp.h" /* * The following variable is set in the TclPlatformInit call to one * of: TCL_PLATFORM_UNIX, or TCL_PLATFORM_WINDOWS. */ TclPlatformType tclPlatform = TCL_PLATFORM_UNIX; /* * Prototypes for local procedures defined in this file: */ static CONST char * DoTildeSubst _ANSI_ARGS_((Tcl_Interp *interp, CONST char *user, Tcl_DString *resultPtr)); static CONST char * ExtractWinRoot _ANSI_ARGS_((CONST char *path, Tcl_DString *resultPtr, int offset, Tcl_PathType *typePtr)); static int SkipToChar _ANSI_ARGS_((char **stringPtr, char *match)); static Tcl_Obj* SplitWinPath _ANSI_ARGS_((CONST char *path)); static Tcl_Obj* SplitUnixPath _ANSI_ARGS_((CONST char *path)); /* *---------------------------------------------------------------------- * * ExtractWinRoot -- * * Matches the root portion of a Windows path and appends it * to the specified Tcl_DString. * * Results: * Returns the position in the path immediately after the root * including any trailing slashes. * Appends a cleaned up version of the root to the Tcl_DString * at the specified offest. * * Side effects: * Modifies the specified Tcl_DString. * *---------------------------------------------------------------------- */ static CONST char * ExtractWinRoot(path, resultPtr, offset, typePtr) CONST char *path; /* Path to parse. */ Tcl_DString *resultPtr; /* Buffer to hold result. */ int offset; /* Offset in buffer where result should be * stored. */ Tcl_PathType *typePtr; /* Where to store pathType result */ { if (path[0] == '/' || path[0] == '\\') { /* Might be a UNC or Vol-Relative path */ CONST char *host, *share, *tail; int hlen, slen; if (path[1] != '/' && path[1] != '\\') { Tcl_DStringSetLength(resultPtr, offset); *typePtr = TCL_PATH_VOLUME_RELATIVE; Tcl_DStringAppend(resultPtr, "/", 1); return &path[1]; } host = &path[2]; /* Skip separators */ while (host[0] == '/' || host[0] == '\\') host++; for (hlen = 0; host[hlen];hlen++) { if (host[hlen] == '/' || host[hlen] == '\\') break; } if (host[hlen] == 0 || host[hlen+1] == 0) { /* * The path given is simply of the form * '/foo', '//foo', '/////foo' or the same * with backslashes. If there is exactly * one leading '/' the path is volume relative * (see filename man page). If there are more * than one, we are simply assuming they * are superfluous and we trim them away. * (An alternative interpretation would * be that it is a host name, but we have * been documented that that is not the case). */ *typePtr = TCL_PATH_VOLUME_RELATIVE; Tcl_DStringAppend(resultPtr, "/", 1); return &path[2]; } Tcl_DStringSetLength(resultPtr, offset); share = &host[hlen]; /* Skip separators */ while (share[0] == '/' || share[0] == '\\') share++; for (slen = 0; share[slen];slen++) { if (share[slen] == '/' || share[slen] == '\\') break; } Tcl_DStringAppend(resultPtr, "//", 2); Tcl_DStringAppend(resultPtr, host, hlen); Tcl_DStringAppend(resultPtr, "/", 1); Tcl_DStringAppend(resultPtr, share, slen); tail = &share[slen]; /* Skip separators */ while (tail[0] == '/' || tail[0] == '\\') tail++; *typePtr = TCL_PATH_ABSOLUTE; return tail; } else if (*path && path[1] == ':') { /* Might be a drive sep */ Tcl_DStringSetLength(resultPtr, offset); if (path[2] != '/' && path[2] != '\\') { *typePtr = TCL_PATH_VOLUME_RELATIVE; Tcl_DStringAppend(resultPtr, path, 2); return &path[2]; } else { char *tail = (char*)&path[3]; /* Skip separators */ while (*tail && (tail[0] == '/' || tail[0] == '\\')) tail++; *typePtr = TCL_PATH_ABSOLUTE; Tcl_DStringAppend(resultPtr, path, 2); Tcl_DStringAppend(resultPtr, "/", 1); return tail; } } else { int abs = 0; if ((path[0] == 'c' || path[0] == 'C') && (path[1] == 'o' || path[1] == 'O')) { if ((path[2] == 'm' || path[2] == 'M') && path[3] >= '1' && path[3] <= '4') { /* May have match for 'com[1-4]:?', which is a serial port */ if (path[4] == '\0') { abs = 4; } else if (path [4] == ':' && path[5] == '\0') { abs = 5; } } else if ((path[2] == 'n' || path[2] == 'N') && path[3] == '\0') { /* Have match for 'con' */ abs = 3; } } else if ((path[0] == 'l' || path[0] == 'L') && (path[1] == 'p' || path[1] == 'P') && (path[2] == 't' || path[2] == 'T')) { if (path[3] >= '1' && path[3] <= '3') { /* May have match for 'lpt[1-3]:?' */ if (path[4] == '\0') { abs = 4; } else if (path [4] == ':' && path[5] == '\0') { abs = 5; } } } else if ((path[0] == 'p' || path[0] == 'P') && (path[1] == 'r' || path[1] == 'R') && (path[2] == 'n' || path[2] == 'N') && path[3] == '\0') { /* Have match for 'prn' */ abs = 3; } else if ((path[0] == 'n' || path[0] == 'N') && (path[1] == 'u' || path[1] == 'U') && (path[2] == 'l' || path[2] == 'L') && path[3] == '\0') { /* Have match for 'nul' */ abs = 3; } else if ((path[0] == 'a' || path[0] == 'A') && (path[1] == 'u' || path[1] == 'U') && (path[2] == 'x' || path[2] == 'X') && path[3] == '\0') { /* Have match for 'aux' */ abs = 3; } if (abs != 0) { *typePtr = TCL_PATH_ABSOLUTE; Tcl_DStringSetLength(resultPtr, offset); Tcl_DStringAppend(resultPtr, path, abs); return path + abs; } } /* Anything else is treated as relative */ *typePtr = TCL_PATH_RELATIVE; return path; } /* *---------------------------------------------------------------------- * * Tcl_GetPathType -- * * Determines whether a given path is relative to the current * directory, relative to the current volume, or absolute. * * The objectified Tcl_FSGetPathType should be used in * preference to this function (as you can see below, this * is just a wrapper around that other function). * * Results: * Returns one of TCL_PATH_ABSOLUTE, TCL_PATH_RELATIVE, or * TCL_PATH_VOLUME_RELATIVE. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_PathType Tcl_GetPathType(path) CONST char *path; { Tcl_PathType type; Tcl_Obj *tempObj = Tcl_NewStringObj(path,-1); Tcl_IncrRefCount(tempObj); type = Tcl_FSGetPathType(tempObj); Tcl_DecrRefCount(tempObj); return type; } /* *---------------------------------------------------------------------- * * TclpGetNativePathType -- * * Determines whether a given path is relative to the current * directory, relative to the current volume, or absolute, but * ONLY FOR THE NATIVE FILESYSTEM. This function is called from * tclIOUtil.c (but needs to be here due to its dependence on * static variables/functions in this file). The exported * function Tcl_FSGetPathType should be used by extensions. * * Results: * Returns one of TCL_PATH_ABSOLUTE, TCL_PATH_RELATIVE, or * TCL_PATH_VOLUME_RELATIVE. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_PathType TclpGetNativePathType(pathObjPtr, driveNameLengthPtr, driveNameRef) Tcl_Obj *pathObjPtr; int *driveNameLengthPtr; Tcl_Obj **driveNameRef; { Tcl_PathType type = TCL_PATH_ABSOLUTE; int pathLen; char *path = Tcl_GetStringFromObj(pathObjPtr, &pathLen); if (path[0] == '~') { /* * This case is common to all platforms. * Paths that begin with ~ are absolute. */ if (driveNameLengthPtr != NULL) { char *end = path + 1; while ((*end != '\0') && (*end != '/')) { end++; } *driveNameLengthPtr = end - path; } } else { switch (tclPlatform) { case TCL_PLATFORM_UNIX: { char *origPath = path; /* * Paths that begin with / are absolute. */ #ifdef __QNX__ /* * Check for QNX // prefix */ if (*path && (pathLen > 3) && (path[0] == '/') && (path[1] == '/') && isdigit(UCHAR(path[2]))) { path += 3; while (isdigit(UCHAR(*path))) { ++path; } } #endif if (path[0] == '/') { if (driveNameLengthPtr != NULL) { /* * We need this addition in case the QNX code * was used */ *driveNameLengthPtr = (1 + path - origPath); } } else { type = TCL_PATH_RELATIVE; } break; } case TCL_PLATFORM_WINDOWS: { Tcl_DString ds; CONST char *rootEnd; Tcl_DStringInit(&ds); rootEnd = ExtractWinRoot(path, &ds, 0, &type); if ((rootEnd != path) && (driveNameLengthPtr != NULL)) { *driveNameLengthPtr = rootEnd - path; if (driveNameRef != NULL) { *driveNameRef = Tcl_NewStringObj(Tcl_DStringValue(&ds), Tcl_DStringLength(&ds)); Tcl_IncrRefCount(*driveNameRef); } } Tcl_DStringFree(&ds); break; } } } return type; } /* *--------------------------------------------------------------------------- * * TclpNativeSplitPath -- * * This function takes the given Tcl_Obj, which should be a valid * path, and returns a Tcl List object containing each segment * of that path as an element. * * Note this function currently calls the older Split(Plat)Path * functions, which require more memory allocation than is * desirable. * * Results: * Returns list object with refCount of zero. If the passed in * lenPtr is non-NULL, we use it to return the number of elements * in the returned list. * * Side effects: * None. * *--------------------------------------------------------------------------- */ Tcl_Obj* TclpNativeSplitPath(pathPtr, lenPtr) Tcl_Obj *pathPtr; /* Path to split. */ int *lenPtr; /* int to store number of path elements. */ { Tcl_Obj *resultPtr = NULL; /* Needed only to prevent gcc warnings. */ /* * Perform platform specific splitting. */ switch (tclPlatform) { case TCL_PLATFORM_UNIX: resultPtr = SplitUnixPath(Tcl_GetString(pathPtr)); break; case TCL_PLATFORM_WINDOWS: resultPtr = SplitWinPath(Tcl_GetString(pathPtr)); break; } /* * Compute the number of elements in the result. */ if (lenPtr != NULL) { Tcl_ListObjLength(NULL, resultPtr, lenPtr); } return resultPtr; } /* *---------------------------------------------------------------------- * * Tcl_SplitPath -- * * Split a path into a list of path components. The first element * of the list will have the same path type as the original path. * * Results: * Returns a standard Tcl result. The interpreter result contains * a list of path components. * *argvPtr will be filled in with the address of an array * whose elements point to the elements of path, in order. * *argcPtr will get filled in with the number of valid elements * in the array. A single block of memory is dynamically allocated * to hold both the argv array and a copy of the path elements. * The caller must eventually free this memory by calling ckfree() * on *argvPtr. Note: *argvPtr and *argcPtr are only modified * if the procedure returns normally. * * Side effects: * Allocates memory. * *---------------------------------------------------------------------- */ void Tcl_SplitPath(path, argcPtr, argvPtr) CONST char *path; /* Pointer to string containing a path. */ int *argcPtr; /* Pointer to location to fill in with * the number of elements in the path. */ CONST char ***argvPtr; /* Pointer to place to store pointer to array * of pointers to path elements. */ { Tcl_Obj *resultPtr = NULL; /* Needed only to prevent gcc warnings. */ Tcl_Obj *tmpPtr, *eltPtr; int i, size, len; char *p, *str; /* * Perform the splitting, using objectified, vfs-aware code. */ tmpPtr = Tcl_NewStringObj(path, -1); Tcl_IncrRefCount(tmpPtr); resultPtr = Tcl_FSSplitPath(tmpPtr, argcPtr); Tcl_DecrRefCount(tmpPtr); /* Calculate space required for the result */ size = 1; for (i = 0; i < *argcPtr; i++) { Tcl_ListObjIndex(NULL, resultPtr, i, &eltPtr); Tcl_GetStringFromObj(eltPtr, &len); size += len + 1; } /* * Allocate a buffer large enough to hold the contents of all of * the list plus the argv pointers and the terminating NULL pointer. */ *argvPtr = (CONST char **) ckalloc((unsigned) ((((*argcPtr) + 1) * sizeof(char *)) + size)); /* * Position p after the last argv pointer and copy the contents of * the list in, piece by piece. */ p = (char *) &(*argvPtr)[(*argcPtr) + 1]; for (i = 0; i < *argcPtr; i++) { Tcl_ListObjIndex(NULL, resultPtr, i, &eltPtr); str = Tcl_GetStringFromObj(eltPtr, &len); memcpy((VOID *) p, (VOID *) str, (size_t) len+1); p += len+1; } /* * Now set up the argv pointers. */ p = (char *) &(*argvPtr)[(*argcPtr) + 1]; for (i = 0; i < *argcPtr; i++) { (*argvPtr)[i] = p; while ((*p++) != '\0') {} } (*argvPtr)[i] = NULL; /* * Free the result ptr given to us by Tcl_FSSplitPath */ Tcl_DecrRefCount(resultPtr); } /* *---------------------------------------------------------------------- * * SplitUnixPath -- * * This routine is used by Tcl_(FS)SplitPath to handle splitting * Unix paths. * * Results: * Returns a newly allocated Tcl list object. * * Side effects: * None. * *---------------------------------------------------------------------- */ static Tcl_Obj* SplitUnixPath(path) CONST char *path; /* Pointer to string containing a path. */ { int length; CONST char *p, *elementStart; Tcl_Obj *result = Tcl_NewObj(); /* * Deal with the root directory as a special case. */ #ifdef __QNX__ /* * Check for QNX // prefix */ if ((path[0] == '/') && (path[1] == '/') && isdigit(UCHAR(path[2]))) { /* INTL: digit */ path += 3; while (isdigit(UCHAR(*path))) { /* INTL: digit */ ++path; } } #endif if (path[0] == '/') { Tcl_ListObjAppendElement(NULL, result, Tcl_NewStringObj("/",1)); p = path+1; } else { p = path; } /* * Split on slashes. Embedded elements that start with tilde will be * prefixed with "./" so they are not affected by tilde substitution. */ for (;;) { elementStart = p; while ((*p != '\0') && (*p != '/')) { p++; } length = p - elementStart; if (length > 0) { Tcl_Obj *nextElt; if ((elementStart[0] == '~') && (elementStart != path)) { nextElt = Tcl_NewStringObj("./",2); Tcl_AppendToObj(nextElt, elementStart, length); } else { nextElt = Tcl_NewStringObj(elementStart, length); } Tcl_ListObjAppendElement(NULL, result, nextElt); } if (*p++ == '\0') { break; } } return result; } /* *---------------------------------------------------------------------- * * SplitWinPath -- * * This routine is used by Tcl_(FS)SplitPath to handle splitting * Windows paths. * * Results: * Returns a newly allocated Tcl list object. * * Side effects: * None. * *---------------------------------------------------------------------- */ static Tcl_Obj* SplitWinPath(path) CONST char *path; /* Pointer to string containing a path. */ { int length; CONST char *p, *elementStart; Tcl_PathType type = TCL_PATH_ABSOLUTE; Tcl_DString buf; Tcl_Obj *result = Tcl_NewObj(); Tcl_DStringInit(&buf); p = ExtractWinRoot(path, &buf, 0, &type); /* * Terminate the root portion, if we matched something. */ if (p != path) { Tcl_ListObjAppendElement(NULL, result, Tcl_NewStringObj(Tcl_DStringValue(&buf), Tcl_DStringLength(&buf))); } Tcl_DStringFree(&buf); /* * Split on slashes. Embedded elements that start with tilde * or a drive letter will be prefixed with "./" so they are not * affected by tilde substitution. */ do { elementStart = p; while ((*p != '\0') && (*p != '/') && (*p != '\\')) { p++; } length = p - elementStart; if (length > 0) { Tcl_Obj *nextElt; if ((elementStart != path) && ((elementStart[0] == '~') || (isalpha(UCHAR(elementStart[0])) && elementStart[1] == ':'))) { nextElt = Tcl_NewStringObj("./",2); Tcl_AppendToObj(nextElt, elementStart, length); } else { nextElt = Tcl_NewStringObj(elementStart, length); } Tcl_ListObjAppendElement(NULL, result, nextElt); } } while (*p++ != '\0'); return result; } /* *--------------------------------------------------------------------------- * * Tcl_FSJoinToPath -- * * This function takes the given object, which should usually be a * valid path or NULL, and joins onto it the array of paths * segments given. * * Results: * Returns object with refCount of zero * * Side effects: * None. * *--------------------------------------------------------------------------- */ Tcl_Obj* Tcl_FSJoinToPath(basePtr, objc, objv) Tcl_Obj *basePtr; int objc; Tcl_Obj *CONST objv[]; { int i; Tcl_Obj *lobj, *ret; if (basePtr == NULL) { lobj = Tcl_NewListObj(0, NULL); } else { lobj = Tcl_NewListObj(1, &basePtr); } for (i = 0; i 0 && (start[length-1] != '/')) { Tcl_AppendToObj(prefix, "/", 1); Tcl_GetStringFromObj(prefix, &length); } needsSep = 0; /* * Append the element, eliminating duplicate and trailing * slashes. */ Tcl_SetObjLength(prefix, length + (int) strlen(p)); dest = Tcl_GetString(prefix) + length; for (; *p != '\0'; p++) { if (*p == '/') { while (p[1] == '/') { p++; } if (p[1] != '\0') { if (needsSep) { *dest++ = '/'; } } } else { *dest++ = *p; needsSep = 1; } } length = dest - Tcl_GetString(prefix); Tcl_SetObjLength(prefix, length); break; case TCL_PLATFORM_WINDOWS: /* * Check to see if we need to append a separator. */ if ((length > 0) && (start[length-1] != '/') && (start[length-1] != ':')) { Tcl_AppendToObj(prefix, "/", 1); Tcl_GetStringFromObj(prefix, &length); } needsSep = 0; /* * Append the element, eliminating duplicate and * trailing slashes. */ Tcl_SetObjLength(prefix, length + (int) strlen(p)); dest = Tcl_GetString(prefix) + length; for (; *p != '\0'; p++) { if ((*p == '/') || (*p == '\\')) { while ((p[1] == '/') || (p[1] == '\\')) { p++; } if ((p[1] != '\0') && needsSep) { *dest++ = '/'; } } else { *dest++ = *p; needsSep = 1; } } length = dest - Tcl_GetString(prefix); Tcl_SetObjLength(prefix, length); break; } return; } /* *---------------------------------------------------------------------- * * Tcl_JoinPath -- * * Combine a list of paths in a platform specific manner. The * function 'Tcl_FSJoinPath' should be used in preference where * possible. * * Results: * Appends the joined path to the end of the specified * Tcl_DString returning a pointer to the resulting string. Note * that the Tcl_DString must already be initialized. * * Side effects: * Modifies the Tcl_DString. * *---------------------------------------------------------------------- */ char * Tcl_JoinPath(argc, argv, resultPtr) int argc; CONST char * CONST *argv; Tcl_DString *resultPtr; /* Pointer to previously initialized DString */ { int i, len; Tcl_Obj *listObj = Tcl_NewObj(); Tcl_Obj *resultObj; char *resultStr; /* Build the list of paths */ for (i = 0; i < argc; i++) { Tcl_ListObjAppendElement(NULL, listObj, Tcl_NewStringObj(argv[i], -1)); } /* Ask the objectified code to join the paths */ Tcl_IncrRefCount(listObj); resultObj = Tcl_FSJoinPath(listObj, argc); Tcl_IncrRefCount(resultObj); Tcl_DecrRefCount(listObj); /* Store the result */ resultStr = Tcl_GetStringFromObj(resultObj, &len); Tcl_DStringAppend(resultPtr, resultStr, len); Tcl_DecrRefCount(resultObj); /* Return a pointer to the result */ return Tcl_DStringValue(resultPtr); } /* *--------------------------------------------------------------------------- * * Tcl_TranslateFileName -- * * Converts a file name into a form usable by the native system * interfaces. If the name starts with a tilde, it will produce a * name where the tilde and following characters have been replaced * by the home directory location for the named user. * * Results: * The return value is a pointer to a string containing the name * after tilde substitution. If there was no tilde substitution, * the return value is a pointer to a copy of the original string. * If there was an error in processing the name, then an error * message is left in the interp's result (if interp was not NULL) * and the return value is NULL. Space for the return value is * allocated in bufferPtr; the caller must call Tcl_DStringFree() * to free the space if the return value was not NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ char * Tcl_TranslateFileName(interp, name, bufferPtr) Tcl_Interp *interp; /* Interpreter in which to store error * message (if necessary). */ CONST char *name; /* File name, which may begin with "~" (to * indicate current user's home directory) or * "~" (to indicate any user's home * directory). */ Tcl_DString *bufferPtr; /* Uninitialized or free DString filled * with name after tilde substitution. */ { Tcl_Obj *path = Tcl_NewStringObj(name, -1); Tcl_Obj *transPtr; Tcl_IncrRefCount(path); transPtr = Tcl_FSGetTranslatedPath(interp, path); if (transPtr == NULL) { Tcl_DecrRefCount(path); return NULL; } Tcl_DStringInit(bufferPtr); Tcl_DStringAppend(bufferPtr, Tcl_GetString(transPtr), -1); Tcl_DecrRefCount(path); Tcl_DecrRefCount(transPtr); /* * Convert forward slashes to backslashes in Windows paths because * some system interfaces don't accept forward slashes. */ if (tclPlatform == TCL_PLATFORM_WINDOWS) { register char *p; for (p = Tcl_DStringValue(bufferPtr); *p != '\0'; p++) { if (*p == '/') { *p = '\\'; } } } return Tcl_DStringValue(bufferPtr); } /* *---------------------------------------------------------------------- * * TclGetExtension -- * * This function returns a pointer to the beginning of the * extension part of a file name. * * Results: * Returns a pointer into name which indicates where the extension * starts. If there is no extension, returns NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ char * TclGetExtension(name) char *name; /* File name to parse. */ { char *p, *lastSep; /* * First find the last directory separator. */ lastSep = NULL; /* Needed only to prevent gcc warnings. */ switch (tclPlatform) { case TCL_PLATFORM_UNIX: lastSep = strrchr(name, '/'); break; case TCL_PLATFORM_WINDOWS: lastSep = NULL; for (p = name; *p != '\0'; p++) { if (strchr("/\\:", *p) != NULL) { lastSep = p; } } break; } p = strrchr(name, '.'); if ((p != NULL) && (lastSep != NULL) && (lastSep > p)) { p = NULL; } /* * In earlier versions, we used to back up to the first period in a series * so that "foo..o" would be split into "foo" and "..o". This is a * confusing and usually incorrect behavior, so now we split at the last * period in the name. */ return p; } /* *---------------------------------------------------------------------- * * DoTildeSubst -- * * Given a string following a tilde, this routine returns the * corresponding home directory. * * Results: * The result is a pointer to a static string containing the home * directory in native format. If there was an error in processing * the substitution, then an error message is left in the interp's * result and the return value is NULL. On success, the results * are appended to resultPtr, and the contents of resultPtr are * returned. * * Side effects: * Information may be left in resultPtr. * *---------------------------------------------------------------------- */ static CONST char * DoTildeSubst(interp, user, resultPtr) Tcl_Interp *interp; /* Interpreter in which to store error * message (if necessary). */ CONST char *user; /* Name of user whose home directory should be * substituted, or "" for current user. */ Tcl_DString *resultPtr; /* Initialized DString filled with name * after tilde substitution. */ { CONST char *dir; if (*user == '\0') { Tcl_DString dirString; dir = TclGetEnv("HOME", &dirString); if (dir == NULL) { if (interp) { Tcl_ResetResult(interp); Tcl_AppendResult(interp, "couldn't find HOME environment ", "variable to expand path", (char *) NULL); } return NULL; } Tcl_JoinPath(1, &dir, resultPtr); Tcl_DStringFree(&dirString); } else { if (TclpGetUserHome(user, resultPtr) == NULL) { if (interp) { Tcl_ResetResult(interp); Tcl_AppendResult(interp, "user \"", user, "\" doesn't exist", (char *) NULL); } return NULL; } } return Tcl_DStringValue(resultPtr); } /* *---------------------------------------------------------------------- * * Tcl_GlobObjCmd -- * * This procedure is invoked to process the "glob" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_GlobObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int index, i, globFlags, length, join, dir, result; char *string, *separators; Tcl_Obj *typePtr, *resultPtr, *look; Tcl_Obj *pathOrDir = NULL; Tcl_DString prefix; static CONST char *options[] = { "-directory", "-join", "-nocomplain", "-path", "-tails", "-types", "--", NULL }; enum options { GLOB_DIR, GLOB_JOIN, GLOB_NOCOMPLAIN, GLOB_PATH, GLOB_TAILS, GLOB_TYPE, GLOB_LAST }; enum pathDirOptions {PATH_NONE = -1 , PATH_GENERAL = 0, PATH_DIR = 1}; Tcl_GlobTypeData *globTypes = NULL; globFlags = 0; join = 0; dir = PATH_NONE; typePtr = NULL; for (i = 1; i < objc; i++) { if (Tcl_GetIndexFromObj(interp, objv[i], options, "option", 0, &index) != TCL_OK) { string = Tcl_GetStringFromObj(objv[i], &length); if (string[0] == '-') { /* * It looks like the command contains an option so signal * an error */ return TCL_ERROR; } else { /* * This clearly isn't an option; assume it's the first * glob pattern. We must clear the error */ Tcl_ResetResult(interp); break; } } switch (index) { case GLOB_NOCOMPLAIN: /* -nocomplain */ globFlags |= TCL_GLOBMODE_NO_COMPLAIN; break; case GLOB_DIR: /* -dir */ if (i == (objc-1)) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "missing argument to \"-directory\"", -1)); return TCL_ERROR; } if (dir != PATH_NONE) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "\"-directory\" cannot be used with \"-path\"", -1)); return TCL_ERROR; } dir = PATH_DIR; globFlags |= TCL_GLOBMODE_DIR; pathOrDir = objv[i+1]; i++; break; case GLOB_JOIN: /* -join */ join = 1; break; case GLOB_TAILS: /* -tails */ globFlags |= TCL_GLOBMODE_TAILS; break; case GLOB_PATH: /* -path */ if (i == (objc-1)) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "missing argument to \"-path\"", -1)); return TCL_ERROR; } if (dir != PATH_NONE) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "\"-path\" cannot be used with \"-directory\"", -1)); return TCL_ERROR; } dir = PATH_GENERAL; pathOrDir = objv[i+1]; i++; break; case GLOB_TYPE: /* -types */ if (i == (objc-1)) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "missing argument to \"-types\"", -1)); return TCL_ERROR; } typePtr = objv[i+1]; if (Tcl_ListObjLength(interp, typePtr, &length) != TCL_OK) { return TCL_ERROR; } i++; break; case GLOB_LAST: /* -- */ i++; goto endOfForLoop; } } endOfForLoop: if (objc - i < 1) { Tcl_WrongNumArgs(interp, 1, objv, "?switches? name ?name ...?"); return TCL_ERROR; } if ((globFlags & TCL_GLOBMODE_TAILS) && (pathOrDir == NULL)) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "\"-tails\" must be used with either \"-directory\" or \"-path\"", -1)); return TCL_ERROR; } separators = NULL; /* lint. */ switch (tclPlatform) { case TCL_PLATFORM_UNIX: separators = "/"; break; case TCL_PLATFORM_WINDOWS: separators = "/\\:"; break; } if (dir == PATH_GENERAL) { int pathlength; char *last; char *first = Tcl_GetStringFromObj(pathOrDir,&pathlength); /* * Find the last path separator in the path */ last = first + pathlength; for (; last != first; last--) { if (strchr(separators, *(last-1)) != NULL) { break; } } if (last == first + pathlength) { /* It's really a directory */ dir = PATH_DIR; } else { Tcl_DString pref; char *search, *find; Tcl_DStringInit(&pref); if (last == first) { /* The whole thing is a prefix */ Tcl_DStringAppend(&pref, first, -1); pathOrDir = NULL; } else { /* Have to split off the end */ Tcl_DStringAppend(&pref, last, first+pathlength-last); pathOrDir = Tcl_NewStringObj(first, last-first-1); /* * We must ensure that we haven't cut off too much, * and turned a valid path like '/' or 'C:/' into * an incorrect path like '' or 'C:'. The way we * do this is to add a separator if there are none * presently in the prefix. */ if (strpbrk(Tcl_GetString(pathOrDir), "\\/") == NULL) { Tcl_AppendToObj(pathOrDir, last-1, 1); } } /* Need to quote 'prefix' */ Tcl_DStringInit(&prefix); search = Tcl_DStringValue(&pref); while ((find = (strpbrk(search, "\\[]*?{}"))) != NULL) { Tcl_DStringAppend(&prefix, search, find-search); Tcl_DStringAppend(&prefix, "\\", 1); Tcl_DStringAppend(&prefix, find, 1); search = find+1; if (*search == '\0') { break; } } if (*search != '\0') { Tcl_DStringAppend(&prefix, search, -1); } Tcl_DStringFree(&pref); } } if (pathOrDir != NULL) { Tcl_IncrRefCount(pathOrDir); } if (typePtr != NULL) { /* * The rest of the possible type arguments (except 'd') are * platform specific. We don't complain when they are used * on an incompatible platform. */ Tcl_ListObjLength(interp, typePtr, &length); if (length <= 0) { goto skipTypes; } globTypes = (Tcl_GlobTypeData*) ckalloc(sizeof(Tcl_GlobTypeData)); globTypes->type = 0; globTypes->perm = 0; globTypes->macType = NULL; globTypes->macCreator = NULL; while(--length >= 0) { int len; char *str; Tcl_ListObjIndex(interp, typePtr, length, &look); str = Tcl_GetStringFromObj(look, &len); if (strcmp("readonly", str) == 0) { globTypes->perm |= TCL_GLOB_PERM_RONLY; } else if (strcmp("hidden", str) == 0) { globTypes->perm |= TCL_GLOB_PERM_HIDDEN; } else if (len == 1) { switch (str[0]) { case 'r': globTypes->perm |= TCL_GLOB_PERM_R; break; case 'w': globTypes->perm |= TCL_GLOB_PERM_W; break; case 'x': globTypes->perm |= TCL_GLOB_PERM_X; break; case 'b': globTypes->type |= TCL_GLOB_TYPE_BLOCK; break; case 'c': globTypes->type |= TCL_GLOB_TYPE_CHAR; break; case 'd': globTypes->type |= TCL_GLOB_TYPE_DIR; break; case 'p': globTypes->type |= TCL_GLOB_TYPE_PIPE; break; case 'f': globTypes->type |= TCL_GLOB_TYPE_FILE; break; case 'l': globTypes->type |= TCL_GLOB_TYPE_LINK; break; case 's': globTypes->type |= TCL_GLOB_TYPE_SOCK; break; default: goto badTypesArg; } } else if (len == 4) { /* This is assumed to be a MacOS file type */ if (globTypes->macType != NULL) { goto badMacTypesArg; } globTypes->macType = look; Tcl_IncrRefCount(look); } else { Tcl_Obj* item; if ((Tcl_ListObjLength(NULL, look, &len) == TCL_OK) && (len == 3)) { Tcl_ListObjIndex(interp, look, 0, &item); if (!strcmp("macintosh", Tcl_GetString(item))) { Tcl_ListObjIndex(interp, look, 1, &item); if (!strcmp("type", Tcl_GetString(item))) { Tcl_ListObjIndex(interp, look, 2, &item); if (globTypes->macType != NULL) { goto badMacTypesArg; } globTypes->macType = item; Tcl_IncrRefCount(item); continue; } else if (!strcmp("creator", Tcl_GetString(item))) { Tcl_ListObjIndex(interp, look, 2, &item); if (globTypes->macCreator != NULL) { goto badMacTypesArg; } globTypes->macCreator = item; Tcl_IncrRefCount(item); continue; } } } /* * Error cases. We reset * the 'join' flag to zero, since we haven't yet * made use of it. */ badTypesArg: resultPtr = Tcl_GetObjResult(interp); Tcl_AppendToObj(resultPtr, "bad argument to \"-types\": ", -1); Tcl_AppendObjToObj(resultPtr, look); result = TCL_ERROR; join = 0; goto endOfGlob; badMacTypesArg: Tcl_SetObjResult(interp, Tcl_NewStringObj( "only one MacOS type or creator argument" " to \"-types\" allowed", -1)); result = TCL_ERROR; join = 0; goto endOfGlob; } } } skipTypes: /* * Now we perform the actual glob below. This may involve joining * together the pattern arguments, dealing with particular file types * etc. We use a 'goto' to ensure we free any memory allocated along * the way. */ objc -= i; objv += i; result = TCL_OK; if (join) { if (dir != PATH_GENERAL) { Tcl_DStringInit(&prefix); } for (i = 0; i < objc; i++) { string = Tcl_GetStringFromObj(objv[i], &length); Tcl_DStringAppend(&prefix, string, length); if (i != objc -1) { Tcl_DStringAppend(&prefix, separators, 1); } } if (TclGlob(interp, Tcl_DStringValue(&prefix), pathOrDir, globFlags, globTypes) != TCL_OK) { result = TCL_ERROR; goto endOfGlob; } } else { if (dir == PATH_GENERAL) { Tcl_DString str; for (i = 0; i < objc; i++) { Tcl_DStringInit(&str); if (dir == PATH_GENERAL) { Tcl_DStringAppend(&str, Tcl_DStringValue(&prefix), Tcl_DStringLength(&prefix)); } string = Tcl_GetStringFromObj(objv[i], &length); Tcl_DStringAppend(&str, string, length); if (TclGlob(interp, Tcl_DStringValue(&str), pathOrDir, globFlags, globTypes) != TCL_OK) { result = TCL_ERROR; Tcl_DStringFree(&str); goto endOfGlob; } } Tcl_DStringFree(&str); } else { for (i = 0; i < objc; i++) { string = Tcl_GetString(objv[i]); if (TclGlob(interp, string, pathOrDir, globFlags, globTypes) != TCL_OK) { result = TCL_ERROR; goto endOfGlob; } } } } if ((globFlags & TCL_GLOBMODE_NO_COMPLAIN) == 0) { if (Tcl_ListObjLength(interp, Tcl_GetObjResult(interp), &length) != TCL_OK) { /* This should never happen. Maybe we should be more dramatic */ result = TCL_ERROR; goto endOfGlob; } if (length == 0) { Tcl_AppendResult(interp, "no files matched glob pattern", (join || (objc == 1)) ? " \"" : "s \"", (char *) NULL); if (join) { Tcl_AppendResult(interp, Tcl_DStringValue(&prefix), (char *) NULL); } else { char *sep = ""; for (i = 0; i < objc; i++) { string = Tcl_GetString(objv[i]); Tcl_AppendResult(interp, sep, string, (char *) NULL); sep = " "; } } Tcl_AppendResult(interp, "\"", (char *) NULL); result = TCL_ERROR; } } endOfGlob: if (join || (dir == PATH_GENERAL)) { Tcl_DStringFree(&prefix); } if (pathOrDir != NULL) { Tcl_DecrRefCount(pathOrDir); } if (globTypes != NULL) { if (globTypes->macType != NULL) { Tcl_DecrRefCount(globTypes->macType); } if (globTypes->macCreator != NULL) { Tcl_DecrRefCount(globTypes->macCreator); } ckfree((char *) globTypes); } return result; } /* *---------------------------------------------------------------------- * * TclGlob -- * * This procedure prepares arguments for the TclDoGlob call. * It sets the separator string based on the platform, performs * tilde substitution, and calls TclDoGlob. * * The interpreter's result, on entry to this function, must * be a valid Tcl list (e.g. it could be empty), since we will * lappend any new results to that list. If it is not a valid * list, this function will fail to do anything very meaningful. * * Results: * The return value is a standard Tcl result indicating whether * an error occurred in globbing. After a normal return the * result in interp (set by TclDoGlob) holds all of the file names * given by the pattern and unquotedPrefix arguments. After an * error the result in interp will hold an error message, unless * the 'TCL_GLOBMODE_NO_COMPLAIN' flag was given, in which case * an error results in a TCL_OK return leaving the interpreter's * result unmodified. * * Side effects: * The 'pattern' is written to. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int TclGlob(interp, pattern, unquotedPrefix, globFlags, types) Tcl_Interp *interp; /* Interpreter for returning error message * or appending list of matching file names. */ char *pattern; /* Glob pattern to match. Must not refer * to a static string. */ Tcl_Obj *unquotedPrefix; /* Prefix to glob pattern, if non-null, which * is considered literally. */ int globFlags; /* Stores or'ed combination of flags */ Tcl_GlobTypeData *types; /* Struct containing acceptable types. * May be NULL. */ { char *separators; CONST char *head; char *tail, *start; char c; int result, prefixLen; Tcl_DString buffer; Tcl_Obj *oldResult; separators = NULL; /* lint. */ switch (tclPlatform) { case TCL_PLATFORM_UNIX: separators = "/"; break; case TCL_PLATFORM_WINDOWS: separators = "/\\:"; break; } Tcl_DStringInit(&buffer); if (unquotedPrefix != NULL) { start = Tcl_GetString(unquotedPrefix); } else { start = pattern; } /* * Perform tilde substitution, if needed. */ if (start[0] == '~') { /* * Find the first path separator after the tilde. */ for (tail = start; *tail != '\0'; tail++) { if (*tail == '\\') { if (strchr(separators, tail[1]) != NULL) { break; } } else if (strchr(separators, *tail) != NULL) { break; } } /* * Determine the home directory for the specified user. */ c = *tail; *tail = '\0'; if (globFlags & TCL_GLOBMODE_NO_COMPLAIN) { /* * We will ignore any error message here, and we * don't want to mess up the interpreter's result. */ head = DoTildeSubst(NULL, start+1, &buffer); } else { head = DoTildeSubst(interp, start+1, &buffer); } *tail = c; if (head == NULL) { if (globFlags & TCL_GLOBMODE_NO_COMPLAIN) { return TCL_OK; } else { return TCL_ERROR; } } if (head != Tcl_DStringValue(&buffer)) { Tcl_DStringAppend(&buffer, head, -1); } if (unquotedPrefix != NULL) { Tcl_DStringAppend(&buffer, tail, -1); tail = pattern; } } else { tail = pattern; if (unquotedPrefix != NULL) { Tcl_DStringAppend(&buffer,Tcl_GetString(unquotedPrefix),-1); } } /* * We want to remember the length of the current prefix, * in case we are using TCL_GLOBMODE_TAILS. Also if we * are using TCL_GLOBMODE_DIR, we must make sure the * prefix ends in a directory separator. */ prefixLen = Tcl_DStringLength(&buffer); if (prefixLen > 0) { c = Tcl_DStringValue(&buffer)[prefixLen-1]; if (strchr(separators, c) == NULL) { /* * If the prefix is a directory, make sure it ends in a * directory separator. */ if (globFlags & TCL_GLOBMODE_DIR) { Tcl_DStringAppend(&buffer,separators,1); /* Try to borrow that separator from the tail */ if (*tail == *separators) { tail++; } } prefixLen++; } } /* * We need to get the old result, in case it is over-written * below when we still need it. */ oldResult = Tcl_GetObjResult(interp); Tcl_IncrRefCount(oldResult); Tcl_ResetResult(interp); result = TclDoGlob(interp, separators, &buffer, tail, types); if (result != TCL_OK) { if (globFlags & TCL_GLOBMODE_NO_COMPLAIN) { /* Put back the old result and reset the return code */ Tcl_SetObjResult(interp, oldResult); result = TCL_OK; } } else { /* * Now we must concatenate the 'oldResult' and the current * result, and then place that into the interpreter. * * If we only want the tails, we must strip off the prefix now. * It may seem more efficient to pass the tails flag down into * TclDoGlob, Tcl_FSMatchInDirectory, but those functions are * continually adjusting the prefix as the various pieces of * the pattern are assimilated, so that would add a lot of * complexity to the code. This way is a little slower (when * the -tails flag is given), but much simpler to code. */ int objc, i; Tcl_Obj **objv; /* Ensure sole ownership */ if (Tcl_IsShared(oldResult)) { Tcl_DecrRefCount(oldResult); oldResult = Tcl_DuplicateObj(oldResult); Tcl_IncrRefCount(oldResult); } Tcl_ListObjGetElements(NULL, Tcl_GetObjResult(interp), &objc, &objv); for (i = 0; i< objc; i++) { Tcl_Obj* elt; if (globFlags & TCL_GLOBMODE_TAILS) { int len; char *oldStr = Tcl_GetStringFromObj(objv[i],&len); if (len == prefixLen) { if ((pattern[0] == '\0') || (strchr(separators, pattern[0]) == NULL)) { elt = Tcl_NewStringObj(".",1); } else { elt = Tcl_NewStringObj("/",1); } } else { elt = Tcl_NewStringObj(oldStr + prefixLen, len - prefixLen); } } else { elt = objv[i]; } /* Assumption that 'oldResult' is a valid list */ Tcl_ListObjAppendElement(interp, oldResult, elt); } Tcl_SetObjResult(interp, oldResult); } /* * Release our temporary copy. All code paths above must * end here so we free our reference. */ Tcl_DecrRefCount(oldResult); Tcl_DStringFree(&buffer); return result; } /* *---------------------------------------------------------------------- * * SkipToChar -- * * This function traverses a glob pattern looking for the next * unquoted occurance of the specified character at the same braces * nesting level. * * Results: * Updates stringPtr to point to the matching character, or to * the end of the string if nothing matched. The return value * is 1 if a match was found at the top level, otherwise it is 0. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int SkipToChar(stringPtr, match) char **stringPtr; /* Pointer string to check. */ char *match; /* Pointer to character to find. */ { int quoted, level; register char *p; quoted = 0; level = 0; for (p = *stringPtr; *p != '\0'; p++) { if (quoted) { quoted = 0; continue; } if ((level == 0) && (*p == *match)) { *stringPtr = p; return 1; } if (*p == '{') { level++; } else if (*p == '}') { level--; } else if (*p == '\\') { quoted = 1; } } *stringPtr = p; return 0; } /* *---------------------------------------------------------------------- * * TclDoGlob -- * * This recursive procedure forms the heart of the globbing * code. It performs a depth-first traversal of the tree * given by the path name to be globbed. The directory and * remainder are assumed to be native format paths. The prefix * contained in 'headPtr' is not used as a glob pattern, simply * as a path specifier, so it can contain unquoted glob-sensitive * characters (if the directories to which it points contain * such strange characters). * * Results: * The return value is a standard Tcl result indicating whether * an error occurred in globbing. After a normal return the * result in interp will be set to hold all of the file names * given by the dir and rem arguments. After an error the * result in interp will hold an error message. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclDoGlob(interp, separators, headPtr, tail, types) Tcl_Interp *interp; /* Interpreter to use for error reporting * (e.g. unmatched brace). */ char *separators; /* String containing separator characters * that should be used to identify globbing * boundaries. */ Tcl_DString *headPtr; /* Completely expanded prefix. */ char *tail; /* The unexpanded remainder of the path. * Must not be a pointer to a static string. */ Tcl_GlobTypeData *types; /* List object containing list of acceptable * types. May be NULL. */ { int baseLength, quoted, count; int result = TCL_OK; char *name, *p, *openBrace, *closeBrace, *firstSpecialChar, savedChar; /* char lastChar = 0; */ int length = Tcl_DStringLength(headPtr); /* if (length > 0) { lastChar = Tcl_DStringValue(headPtr)[length-1]; } */ /* * Consume any leading directory separators, leaving tail pointing * just past the last initial separator. */ count = 0; name = tail; for (; *tail != '\0'; tail++) { if (*tail == '\\') { /* * If the first character is escaped, either we have a directory * separator, or we have any other character. In the latter case * the rest of tail is a pattern, and we must break from the loop. * This is particularly important on Windows where '\' is both * the escaping character and a directory separator. */ if (strchr(separators, tail[1]) != NULL) { tail++; } else { break; } } else if (strchr(separators, *tail) == NULL) { break; } if (*tail == '\\') { Tcl_DStringAppend(headPtr, separators, 1); } else { Tcl_DStringAppend(headPtr, tail, 1); } count++; } /* * Deal with path separators. On the Mac, we have to watch out * for multiple separators, since they are special in Mac-style * paths. */ switch (tclPlatform) { case TCL_PLATFORM_WINDOWS: /* * If this is a drive relative path, add the colon and the * trailing slash if needed. Otherwise add the slash if * this is the first absolute element, or a later relative * element. Add an extra slash if this is a UNC path. if (*name == ':') { Tcl_DStringAppend(headPtr, ":", 1); if (count > 1) { Tcl_DStringAppend(headPtr, "/", 1); } } else if ((*tail != '\0') && (((length > 0) && (strchr(separators, lastChar) == NULL)) || ((length == 0) && (count > 0)))) { Tcl_DStringAppend(headPtr, "/", 1); if ((length == 0) && (count > 1)) { Tcl_DStringAppend(headPtr, "/", 1); } } */ break; case TCL_PLATFORM_UNIX: { /* * Add a separator if this is the first absolute element, or * a later relative element. if ((*tail != '\0') && (((length > 0) && (strchr(separators, lastChar) == NULL)) || ((length == 0) && (count > 0)))) { Tcl_DStringAppend(headPtr, "/", 1); } */ break; } } /* * Look for the first matching pair of braces or the first * directory separator that is not inside a pair of braces. */ openBrace = closeBrace = NULL; quoted = 0; for (p = tail; *p != '\0'; p++) { if (quoted) { quoted = 0; } else if (*p == '\\') { quoted = 1; if (strchr(separators, p[1]) != NULL) { break; /* Quoted directory separator. */ } } else if (strchr(separators, *p) != NULL) { break; /* Unquoted directory separator. */ } else if (*p == '{') { openBrace = p; p++; if (SkipToChar(&p, "}")) { closeBrace = p; /* Balanced braces. */ break; } Tcl_SetResult(interp, "unmatched open-brace in file name", TCL_STATIC); return TCL_ERROR; } else if (*p == '}') { Tcl_SetResult(interp, "unmatched close-brace in file name", TCL_STATIC); return TCL_ERROR; } } /* * Substitute the alternate patterns from the braces and recurse. */ if (openBrace != NULL) { char *element; Tcl_DString newName; Tcl_DStringInit(&newName); /* * For each element within in the outermost pair of braces, * append the element and the remainder to the fixed portion * before the first brace and recursively call TclDoGlob. */ Tcl_DStringAppend(&newName, tail, openBrace-tail); baseLength = Tcl_DStringLength(&newName); length = Tcl_DStringLength(headPtr); *closeBrace = '\0'; for (p = openBrace; p != closeBrace; ) { p++; element = p; SkipToChar(&p, ","); Tcl_DStringSetLength(headPtr, length); Tcl_DStringSetLength(&newName, baseLength); Tcl_DStringAppend(&newName, element, p-element); Tcl_DStringAppend(&newName, closeBrace+1, -1); result = TclDoGlob(interp, separators, headPtr, Tcl_DStringValue(&newName), types); if (result != TCL_OK) { break; } } *closeBrace = '}'; Tcl_DStringFree(&newName); return result; } /* * At this point, there are no more brace substitutions to perform on * this path component. The variable p is pointing at a quoted or * unquoted directory separator or the end of the string. So we need * to check for special globbing characters in the current pattern. * We avoid modifying tail if p is pointing at the end of the string. */ if (*p != '\0') { /* * Note that we are modifying the string in place. This won't work * if the string is a static. */ savedChar = *p; *p = '\0'; firstSpecialChar = strpbrk(tail, "*[]?\\"); *p = savedChar; } else { firstSpecialChar = strpbrk(tail, "*[]?\\"); } if (firstSpecialChar != NULL) { int ret; Tcl_Obj *head = Tcl_NewStringObj(Tcl_DStringValue(headPtr),-1); Tcl_IncrRefCount(head); /* * Look for matching files in the given directory. The * implementation of this function is platform specific. For * each file that matches, it will add the match onto the * resultPtr given. */ if (*p == '\0') { ret = Tcl_FSMatchInDirectory(interp, Tcl_GetObjResult(interp), head, tail, types); } else { /* * We do the recursion ourselves. This makes implementing * Tcl_FSMatchInDirectory for each filesystem much easier. */ Tcl_GlobTypeData dirOnly = { TCL_GLOB_TYPE_DIR, 0, NULL, NULL }; char save = *p; Tcl_Obj *resultPtr; resultPtr = Tcl_NewListObj(0, NULL); Tcl_IncrRefCount(resultPtr); *p = '\0'; ret = Tcl_FSMatchInDirectory(interp, resultPtr, head, tail, &dirOnly); *p = save; if (ret == TCL_OK) { int resLength, repair = -1; ret = Tcl_ListObjLength(interp, resultPtr, &resLength); if (ret == TCL_OK) { int i; for (i =0; i< resLength; i++) { Tcl_Obj *elt; Tcl_DString ds; Tcl_ListObjIndex(NULL, resultPtr, i, &elt); Tcl_DStringInit(&ds); if (Tcl_GetString(elt)[0] == '~') { Tcl_Obj *paths = Tcl_GetObjResult(interp); Tcl_ListObjLength(NULL, paths, &repair); Tcl_DStringAppend(&ds, "./", 2); } Tcl_DStringAppend(&ds, Tcl_GetString(elt), -1); Tcl_DStringAppend(&ds, "/",1); ret = TclDoGlob(interp, separators, &ds, p+1, types); Tcl_DStringFree(&ds); if (ret != TCL_OK) { break; } if (repair >= 0) { Tcl_Obj *paths = Tcl_GetObjResult(interp); int end; Tcl_ListObjLength(NULL, paths, &end); while (repair < end) { CONST char *bytes; int numBytes; Tcl_Obj *fixme, *newObj; Tcl_ListObjIndex(NULL, paths, repair, &fixme); bytes = Tcl_GetStringFromObj(fixme, &numBytes); newObj = Tcl_NewStringObj(bytes+2, numBytes-2); Tcl_ListObjReplace(NULL, paths, repair, 1, 1, &newObj); repair++; } repair = -1; } } } } Tcl_DecrRefCount(resultPtr); } Tcl_DecrRefCount(head); return ret; } Tcl_DStringAppend(headPtr, tail, p-tail); if (*p != '\0') { return TclDoGlob(interp, separators, headPtr, p, types); } else { /* * This is the code path reached by a command like 'glob foo'. * * There are no more wildcards in the pattern and no more * unprocessed characters in the tail, so now we can construct * the path, and pass it to Tcl_FSMatchInDirectory with an * empty pattern to verify the existence of the file and check * it is of the correct type (if a 'types' flag it given -- if * no such flag was given, we could just use 'Tcl_FSLStat', but * for simplicity we keep to a common approach). */ Tcl_Obj *nameObj; switch (tclPlatform) { case TCL_PLATFORM_WINDOWS: { if (Tcl_DStringLength(headPtr) == 0) { if (((*name == '\\') && (name[1] == '/' || name[1] == '\\')) || (*name == '/')) { Tcl_DStringAppend(headPtr, "/", 1); } else { Tcl_DStringAppend(headPtr, ".", 1); } } /* * Convert to forward slashes. This is required to pass * some Tcl tests. We should probably remove the conversions * here and in tclWinFile.c, since they aren't needed since * the dropping of support for Win32s. */ for (p = Tcl_DStringValue(headPtr); *p != '\0'; p++) { if (*p == '\\') { *p = '/'; } } break; } case TCL_PLATFORM_UNIX: { if (Tcl_DStringLength(headPtr) == 0) { if ((*name == '\\' && name[1] == '/') || (*name == '/')) { Tcl_DStringAppend(headPtr, "/", 1); } else { Tcl_DStringAppend(headPtr, ".", 1); } } break; } } /* Common for all platforms */ name = Tcl_DStringValue(headPtr); nameObj = Tcl_NewStringObj(name, Tcl_DStringLength(headPtr)); Tcl_IncrRefCount(nameObj); result = Tcl_FSMatchInDirectory(interp, Tcl_GetObjResult(interp), nameObj, NULL, types); Tcl_DecrRefCount(nameObj); return result; } } /* *--------------------------------------------------------------------------- * * TclFileDirname * * This procedure calculates the directory above a given * path: basically 'file dirname'. It is used both by * the 'dirname' subcommand of file and by code in tclIOUtil.c. * * Results: * NULL if an error occurred, otherwise a Tcl_Obj owned by * the caller (i.e. most likely with refCount 1). * * Side effects: * None. * *--------------------------------------------------------------------------- */ Tcl_Obj* TclFileDirname(interp, pathPtr) Tcl_Interp *interp; /* Used for error reporting */ Tcl_Obj *pathPtr; /* Path to take dirname of */ { int splitElements; Tcl_Obj *splitPtr; Tcl_Obj *splitResultPtr = NULL; /* * The behaviour we want here is slightly different to * the standard Tcl_FSSplitPath in the handling of home * directories; Tcl_FSSplitPath preserves the "~" while * this code computes the actual full path name, if we * had just a single component. */ splitPtr = Tcl_FSSplitPath(pathPtr, &splitElements); if ((splitElements == 1) && (Tcl_GetString(pathPtr)[0] == '~')) { Tcl_DecrRefCount(splitPtr); splitPtr = Tcl_FSGetNormalizedPath(interp, pathPtr); if (splitPtr == NULL) { return NULL; } splitPtr = Tcl_FSSplitPath(splitPtr, &splitElements); } /* * Return all but the last component. If there is only one * component, return it if the path was non-relative, otherwise * return the current directory. */ if (splitElements > 1) { splitResultPtr = Tcl_FSJoinPath(splitPtr, splitElements - 1); } else if (splitElements == 0 || (Tcl_FSGetPathType(pathPtr) == TCL_PATH_RELATIVE)) { splitResultPtr = Tcl_NewStringObj(".", 1); } else { Tcl_ListObjIndex(NULL, splitPtr, 0, &splitResultPtr); } Tcl_IncrRefCount(splitResultPtr); Tcl_DecrRefCount(splitPtr); return splitResultPtr; } /* *--------------------------------------------------------------------------- * * Tcl_AllocStatBuf * * This procedure allocates a Tcl_StatBuf on the heap. It exists * so that extensions may be used unchanged on systems where * largefile support is optional. * * Results: * A pointer to a Tcl_StatBuf which may be deallocated by being * passed to ckfree(). * * Side effects: * None. * *--------------------------------------------------------------------------- */ Tcl_StatBuf * Tcl_AllocStatBuf() { return (Tcl_StatBuf *) ckalloc(sizeof(Tcl_StatBuf)); } tcl8.4.20/generic/tclLoad.c0000644003604700454610000004767211737050674014101 0ustar dgp771div/* * tclLoad.c -- * * This file provides the generic portion (those that are the same * on all platforms) of Tcl's dynamic loading facilities. * * Copyright (c) 1995-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" /* * The following structure describes a package that has been loaded * either dynamically (with the "load" command) or statically (as * indicated by a call to TclGetLoadedPackages). All such packages * are linked together into a single list for the process. Packages * are never unloaded, until the application exits, when * TclFinalizeLoad is called, and these structures are freed. */ typedef struct LoadedPackage { char *fileName; /* Name of the file from which the * package was loaded. An empty string * means the package is loaded statically. * Malloc-ed. */ char *packageName; /* Name of package prefix for the package, * properly capitalized (first letter UC, * others LC), no "_", as in "Net". * Malloc-ed. */ Tcl_LoadHandle loadHandle; /* Token for the loaded file which should be * passed to (*unLoadProcPtr)() when the file * is no longer needed. If fileName is NULL, * then this field is irrelevant. */ Tcl_PackageInitProc *initProc; /* Initialization procedure to call to * incorporate this package into a trusted * interpreter. */ Tcl_PackageInitProc *safeInitProc; /* Initialization procedure to call to * incorporate this package into a safe * interpreter (one that will execute * untrusted scripts). NULL means the * package can't be used in unsafe * interpreters. */ Tcl_FSUnloadFileProc *unLoadProcPtr; /* Procedure to use to unload this package. * If NULL, then we do not attempt to unload * the package. If fileName is NULL, then * this field is irrelevant. */ struct LoadedPackage *nextPtr; /* Next in list of all packages loaded into * this application process. NULL means * end of list. */ } LoadedPackage; /* * TCL_THREADS * There is a global list of packages that is anchored at firstPackagePtr. * Access to this list is governed by a mutex. */ static LoadedPackage *firstPackagePtr = NULL; /* First in list of all packages loaded into * this process. */ TCL_DECLARE_MUTEX(packageMutex) /* * The following structure represents a particular package that has * been incorporated into a particular interpreter (by calling its * initialization procedure). There is a list of these structures for * each interpreter, with an AssocData value (key "load") for the * interpreter that points to the first package (if any). */ typedef struct InterpPackage { LoadedPackage *pkgPtr; /* Points to detailed information about * package. */ struct InterpPackage *nextPtr; /* Next package in this interpreter, or * NULL for end of list. */ } InterpPackage; /* * Prototypes for procedures that are private to this file: */ static void LoadCleanupProc _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp)); /* *---------------------------------------------------------------------- * * Tcl_LoadObjCmd -- * * This procedure is invoked to process the "load" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ int Tcl_LoadObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Tcl_Interp *target; LoadedPackage *pkgPtr, *defaultPtr; Tcl_DString pkgName, tmp, initName, safeInitName; Tcl_PackageInitProc *initProc, *safeInitProc; InterpPackage *ipFirstPtr, *ipPtr; int code, namesMatch, filesMatch; char *p, *fullFileName, *packageName; Tcl_LoadHandle loadHandle; Tcl_FSUnloadFileProc *unLoadProcPtr = NULL; Tcl_UniChar ch; int offset; if ((objc < 2) || (objc > 4)) { Tcl_WrongNumArgs(interp, 1, objv, "fileName ?packageName? ?interp?"); return TCL_ERROR; } if (Tcl_FSConvertToPathType(interp, objv[1]) != TCL_OK) { return TCL_ERROR; } fullFileName = Tcl_GetString(objv[1]); Tcl_DStringInit(&pkgName); Tcl_DStringInit(&initName); Tcl_DStringInit(&safeInitName); Tcl_DStringInit(&tmp); packageName = NULL; if (objc >= 3) { packageName = Tcl_GetString(objv[2]); if (packageName[0] == '\0') { packageName = NULL; } } if ((fullFileName[0] == 0) && (packageName == NULL)) { Tcl_SetResult(interp, "must specify either file name or package name", TCL_STATIC); code = TCL_ERROR; goto done; } /* * Figure out which interpreter we're going to load the package into. */ target = interp; if (objc == 4) { char *slaveIntName; slaveIntName = Tcl_GetString(objv[3]); target = Tcl_GetSlave(interp, slaveIntName); if (target == NULL) { return TCL_ERROR; } } /* * Scan through the packages that are currently loaded to see if the * package we want is already loaded. We'll use a loaded package if * it meets any of the following conditions: * - Its name and file match the once we're looking for. * - Its file matches, and we weren't given a name. * - Its name matches, the file name was specified as empty, and there * is only no statically loaded package with the same name. */ Tcl_MutexLock(&packageMutex); defaultPtr = NULL; for (pkgPtr = firstPackagePtr; pkgPtr != NULL; pkgPtr = pkgPtr->nextPtr) { if (packageName == NULL) { namesMatch = 0; } else { Tcl_DStringSetLength(&pkgName, 0); Tcl_DStringAppend(&pkgName, packageName, -1); Tcl_DStringSetLength(&tmp, 0); Tcl_DStringAppend(&tmp, pkgPtr->packageName, -1); Tcl_UtfToLower(Tcl_DStringValue(&pkgName)); Tcl_UtfToLower(Tcl_DStringValue(&tmp)); if (strcmp(Tcl_DStringValue(&tmp), Tcl_DStringValue(&pkgName)) == 0) { namesMatch = 1; } else { namesMatch = 0; } } Tcl_DStringSetLength(&pkgName, 0); filesMatch = (strcmp(pkgPtr->fileName, fullFileName) == 0); if (filesMatch && (namesMatch || (packageName == NULL))) { break; } if (namesMatch && (fullFileName[0] == 0)) { defaultPtr = pkgPtr; } if (filesMatch && !namesMatch && (fullFileName[0] != 0)) { /* * Can't have two different packages loaded from the same * file. */ Tcl_AppendResult(interp, "file \"", fullFileName, "\" is already loaded for package \"", pkgPtr->packageName, "\"", (char *) NULL); code = TCL_ERROR; Tcl_MutexUnlock(&packageMutex); goto done; } } Tcl_MutexUnlock(&packageMutex); if (pkgPtr == NULL) { pkgPtr = defaultPtr; } /* * Scan through the list of packages already loaded in the target * interpreter. If the package we want is already loaded there, * then there's nothing for us to to. */ if (pkgPtr != NULL) { ipFirstPtr = (InterpPackage *) Tcl_GetAssocData(target, "tclLoad", (Tcl_InterpDeleteProc **) NULL); for (ipPtr = ipFirstPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) { if (ipPtr->pkgPtr == pkgPtr) { code = TCL_OK; goto done; } } } if (pkgPtr == NULL) { /* * The desired file isn't currently loaded, so load it. It's an * error if the desired package is a static one. */ if (fullFileName[0] == 0) { Tcl_AppendResult(interp, "package \"", packageName, "\" isn't loaded statically", (char *) NULL); code = TCL_ERROR; goto done; } /* * Figure out the module name if it wasn't provided explicitly. */ if (packageName != NULL) { Tcl_DStringAppend(&pkgName, packageName, -1); } else { int retc; /* * Threading note - this call used to be protected by a mutex. */ retc = TclGuessPackageName(fullFileName, &pkgName); if (!retc) { Tcl_Obj *splitPtr; Tcl_Obj *pkgGuessPtr; int pElements; char *pkgGuess; /* * The platform-specific code couldn't figure out the * module name. Make a guess by taking the last element * of the file name, stripping off any leading "lib", * and then using all of the alphabetic and underline * characters that follow that. */ splitPtr = Tcl_FSSplitPath(objv[1], &pElements); Tcl_ListObjIndex(NULL, splitPtr, pElements -1, &pkgGuessPtr); pkgGuess = Tcl_GetString(pkgGuessPtr); if ((pkgGuess[0] == 'l') && (pkgGuess[1] == 'i') && (pkgGuess[2] == 'b')) { pkgGuess += 3; } #ifdef __CYGWIN__ if ((pkgGuess[0] == 'c') && (pkgGuess[1] == 'y') && (pkgGuess[2] == 'g')) { pkgGuess += 3; } #endif /* __CYGWIN__ */ for (p = pkgGuess; *p != 0; p += offset) { offset = Tcl_UtfToUniChar(p, &ch); if ((ch > 0x100) || !(isalpha(UCHAR(ch)) /* INTL: ISO only */ || (UCHAR(ch) == '_'))) { break; } } if (p == pkgGuess) { Tcl_DecrRefCount(splitPtr); Tcl_AppendResult(interp, "couldn't figure out package name for ", fullFileName, (char *) NULL); code = TCL_ERROR; goto done; } Tcl_DStringAppend(&pkgName, pkgGuess, (p - pkgGuess)); Tcl_DecrRefCount(splitPtr); } } /* * Fix the capitalization in the package name so that the first * character is in caps (or title case) but the others are all * lower-case. */ Tcl_DStringSetLength(&pkgName, Tcl_UtfToTitle(Tcl_DStringValue(&pkgName))); /* * Compute the names of the two initialization procedures, * based on the package name. */ Tcl_DStringAppend(&initName, Tcl_DStringValue(&pkgName), -1); Tcl_DStringAppend(&initName, "_Init", 5); Tcl_DStringAppend(&safeInitName, Tcl_DStringValue(&pkgName), -1); Tcl_DStringAppend(&safeInitName, "_SafeInit", 9); /* * Call platform-specific code to load the package and find the * two initialization procedures. */ Tcl_MutexLock(&packageMutex); code = Tcl_FSLoadFile(interp, objv[1], Tcl_DStringValue(&initName), Tcl_DStringValue(&safeInitName), &initProc, &safeInitProc, &loadHandle,&unLoadProcPtr); Tcl_MutexUnlock(&packageMutex); if (code != TCL_OK) { goto done; } if (initProc == NULL) { Tcl_AppendResult(interp, "couldn't find procedure ", Tcl_DStringValue(&initName), (char *) NULL); if (unLoadProcPtr != NULL) { (*unLoadProcPtr)(loadHandle); } code = TCL_ERROR; goto done; } /* * Create a new record to describe this package. */ pkgPtr = (LoadedPackage *) ckalloc(sizeof(LoadedPackage)); pkgPtr->fileName = (char *) ckalloc((unsigned) (strlen(fullFileName) + 1)); strcpy(pkgPtr->fileName, fullFileName); pkgPtr->packageName = (char *) ckalloc((unsigned) (Tcl_DStringLength(&pkgName) + 1)); strcpy(pkgPtr->packageName, Tcl_DStringValue(&pkgName)); pkgPtr->loadHandle = loadHandle; pkgPtr->unLoadProcPtr = unLoadProcPtr; pkgPtr->initProc = initProc; pkgPtr->safeInitProc = safeInitProc; Tcl_MutexLock(&packageMutex); pkgPtr->nextPtr = firstPackagePtr; firstPackagePtr = pkgPtr; Tcl_MutexUnlock(&packageMutex); } /* * Invoke the package's initialization procedure (either the * normal one or the safe one, depending on whether or not the * interpreter is safe). */ if (Tcl_IsSafe(target)) { if (pkgPtr->safeInitProc != NULL) { code = (*pkgPtr->safeInitProc)(target); } else { Tcl_AppendResult(interp, "can't use package in a safe interpreter: ", "no ", pkgPtr->packageName, "_SafeInit procedure", (char *) NULL); code = TCL_ERROR; goto done; } } else { code = (*pkgPtr->initProc)(target); } /* * Record the fact that the package has been loaded in the * target interpreter. */ if (code == TCL_OK) { /* * Refetch ipFirstPtr: loading the package may have introduced * additional static packages at the head of the linked list! */ ipFirstPtr = (InterpPackage *) Tcl_GetAssocData(target, "tclLoad", (Tcl_InterpDeleteProc **) NULL); ipPtr = (InterpPackage *) ckalloc(sizeof(InterpPackage)); ipPtr->pkgPtr = pkgPtr; ipPtr->nextPtr = ipFirstPtr; Tcl_SetAssocData(target, "tclLoad", LoadCleanupProc, (ClientData) ipPtr); } else { TclTransferResult(target, code, interp); } done: Tcl_DStringFree(&pkgName); Tcl_DStringFree(&initName); Tcl_DStringFree(&safeInitName); Tcl_DStringFree(&tmp); return code; } /* *---------------------------------------------------------------------- * * Tcl_StaticPackage -- * * This procedure is invoked to indicate that a particular * package has been linked statically with an application. * * Results: * None. * * Side effects: * Once this procedure completes, the package becomes loadable * via the "load" command with an empty file name. * *---------------------------------------------------------------------- */ void Tcl_StaticPackage(interp, pkgName, initProc, safeInitProc) Tcl_Interp *interp; /* If not NULL, it means that the * package has already been loaded * into the given interpreter by * calling the appropriate init proc. */ CONST char *pkgName; /* Name of package (must be properly * capitalized: first letter upper * case, others lower case). */ Tcl_PackageInitProc *initProc; /* Procedure to call to incorporate * this package into a trusted * interpreter. */ Tcl_PackageInitProc *safeInitProc; /* Procedure to call to incorporate * this package into a safe interpreter * (one that will execute untrusted * scripts). NULL means the package * can't be used in safe * interpreters. */ { LoadedPackage *pkgPtr; InterpPackage *ipPtr, *ipFirstPtr; /* * Check to see if someone else has already reported this package as * statically loaded in the process. */ Tcl_MutexLock(&packageMutex); for (pkgPtr = firstPackagePtr; pkgPtr != NULL; pkgPtr = pkgPtr->nextPtr) { if ((pkgPtr->initProc == initProc) && (pkgPtr->safeInitProc == safeInitProc) && (strcmp(pkgPtr->packageName, pkgName) == 0)) { break; } } Tcl_MutexUnlock(&packageMutex); /* * If the package is not yet recorded as being loaded statically, * add it to the list now. */ if ( pkgPtr == NULL ) { pkgPtr = (LoadedPackage *) ckalloc(sizeof(LoadedPackage)); pkgPtr->fileName = (char *) ckalloc((unsigned) 1); pkgPtr->fileName[0] = 0; pkgPtr->packageName = (char *) ckalloc((unsigned) (strlen(pkgName) + 1)); strcpy(pkgPtr->packageName, pkgName); pkgPtr->loadHandle = NULL; pkgPtr->initProc = initProc; pkgPtr->safeInitProc = safeInitProc; Tcl_MutexLock(&packageMutex); pkgPtr->nextPtr = firstPackagePtr; firstPackagePtr = pkgPtr; Tcl_MutexUnlock(&packageMutex); } if (interp != NULL) { /* * If we're loading the package into an interpreter, * determine whether it's already loaded. */ ipFirstPtr = (InterpPackage *) Tcl_GetAssocData(interp, "tclLoad", (Tcl_InterpDeleteProc **) NULL); for ( ipPtr = ipFirstPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr ) { if ( ipPtr->pkgPtr == pkgPtr ) { return; } } /* * Package isn't loade in the current interp yet. Mark it as * now being loaded. */ ipPtr = (InterpPackage *) ckalloc(sizeof(InterpPackage)); ipPtr->pkgPtr = pkgPtr; ipPtr->nextPtr = ipFirstPtr; Tcl_SetAssocData(interp, "tclLoad", LoadCleanupProc, (ClientData) ipPtr); } } /* *---------------------------------------------------------------------- * * TclGetLoadedPackages -- * * This procedure returns information about all of the files * that are loaded (either in a particular intepreter, or * for all interpreters). * * Results: * The return value is a standard Tcl completion code. If * successful, a list of lists is placed in the interp's result. * Each sublist corresponds to one loaded file; its first * element is the name of the file (or an empty string for * something that's statically loaded) and the second element * is the name of the package in that file. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclGetLoadedPackages(interp, targetName) Tcl_Interp *interp; /* Interpreter in which to return * information or error message. */ char *targetName; /* Name of target interpreter or NULL. * If NULL, return info about all interps; * otherwise, just return info about this * interpreter. */ { Tcl_Interp *target; LoadedPackage *pkgPtr; InterpPackage *ipPtr; char *prefix; if (targetName == NULL) { /* * Return information about all of the available packages. */ prefix = "{"; Tcl_MutexLock(&packageMutex); for (pkgPtr = firstPackagePtr; pkgPtr != NULL; pkgPtr = pkgPtr->nextPtr) { Tcl_AppendResult(interp, prefix, (char *) NULL); Tcl_AppendElement(interp, pkgPtr->fileName); Tcl_AppendElement(interp, pkgPtr->packageName); Tcl_AppendResult(interp, "}", (char *) NULL); prefix = " {"; } Tcl_MutexUnlock(&packageMutex); return TCL_OK; } /* * Return information about only the packages that are loaded in * a given interpreter. */ target = Tcl_GetSlave(interp, targetName); if (target == NULL) { return TCL_ERROR; } ipPtr = (InterpPackage *) Tcl_GetAssocData(target, "tclLoad", (Tcl_InterpDeleteProc **) NULL); prefix = "{"; for ( ; ipPtr != NULL; ipPtr = ipPtr->nextPtr) { pkgPtr = ipPtr->pkgPtr; Tcl_AppendResult(interp, prefix, (char *) NULL); Tcl_AppendElement(interp, pkgPtr->fileName); Tcl_AppendElement(interp, pkgPtr->packageName); Tcl_AppendResult(interp, "}", (char *) NULL); prefix = " {"; } return TCL_OK; } /* *---------------------------------------------------------------------- * * LoadCleanupProc -- * * This procedure is called to delete all of the InterpPackage * structures for an interpreter when the interpreter is deleted. * It gets invoked via the Tcl AssocData mechanism. * * Results: * None. * * Side effects: * Storage for all of the InterpPackage procedures for interp * get deleted. * *---------------------------------------------------------------------- */ static void LoadCleanupProc(clientData, interp) ClientData clientData; /* Pointer to first InterpPackage structure * for interp. */ Tcl_Interp *interp; /* Interpreter that is being deleted. */ { InterpPackage *ipPtr, *nextPtr; ipPtr = (InterpPackage *) clientData; while (ipPtr != NULL) { nextPtr = ipPtr->nextPtr; ckfree((char *) ipPtr); ipPtr = nextPtr; } } /* *---------------------------------------------------------------------- * * TclFinalizeLoad -- * * This procedure is invoked just before the application exits. * It frees all of the LoadedPackage structures. * * Results: * None. * * Side effects: * Memory is freed. * *---------------------------------------------------------------------- */ void TclFinalizeLoad() { LoadedPackage *pkgPtr; /* * No synchronization here because there should just be * one thread alive at this point. Logically, * packageMutex should be grabbed at this point, but * the Mutexes get finalized before the call to this routine. * The only subsystem left alive at this point is the * memory allocator. */ while (firstPackagePtr != NULL) { pkgPtr = firstPackagePtr; firstPackagePtr = pkgPtr->nextPtr; #if defined(TCL_UNLOAD_DLLS) || defined(__WIN32__) /* * Some Unix dlls are poorly behaved - registering things like * atexit calls that can't be unregistered. If you unload * such dlls, you get a core on exit because it wants to * call a function in the dll after it's been unloaded. */ if (pkgPtr->fileName[0] != '\0') { Tcl_FSUnloadFileProc *unLoadProcPtr = pkgPtr->unLoadProcPtr; if (unLoadProcPtr != NULL) { (*unLoadProcPtr)(pkgPtr->loadHandle); } } #endif ckfree(pkgPtr->fileName); ckfree(pkgPtr->packageName); ckfree((char *) pkgPtr); } } tcl8.4.20/generic/regc_locale.c0000644003604700454610000014000112052456743014730 0ustar dgp771div/* * regc_locale.c -- * * This file contains the Unicode locale specific regexp routines. * This file is #included by regcomp.c. * * Copyright (c) 1998 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ /* ASCII character-name table */ static CONST struct cname { CONST char *name; CONST char code; } cnames[] = { {"NUL", '\0'}, {"SOH", '\001'}, {"STX", '\002'}, {"ETX", '\003'}, {"EOT", '\004'}, {"ENQ", '\005'}, {"ACK", '\006'}, {"BEL", '\007'}, {"alert", '\007'}, {"BS", '\010'}, {"backspace", '\b'}, {"HT", '\011'}, {"tab", '\t'}, {"LF", '\012'}, {"newline", '\n'}, {"VT", '\013'}, {"vertical-tab", '\v'}, {"FF", '\014'}, {"form-feed", '\f'}, {"CR", '\015'}, {"carriage-return", '\r'}, {"SO", '\016'}, {"SI", '\017'}, {"DLE", '\020'}, {"DC1", '\021'}, {"DC2", '\022'}, {"DC3", '\023'}, {"DC4", '\024'}, {"NAK", '\025'}, {"SYN", '\026'}, {"ETB", '\027'}, {"CAN", '\030'}, {"EM", '\031'}, {"SUB", '\032'}, {"ESC", '\033'}, {"IS4", '\034'}, {"FS", '\034'}, {"IS3", '\035'}, {"GS", '\035'}, {"IS2", '\036'}, {"RS", '\036'}, {"IS1", '\037'}, {"US", '\037'}, {"space", ' '}, {"exclamation-mark",'!'}, {"quotation-mark", '"'}, {"number-sign", '#'}, {"dollar-sign", '$'}, {"percent-sign", '%'}, {"ampersand", '&'}, {"apostrophe", '\''}, {"left-parenthesis",'('}, {"right-parenthesis", ')'}, {"asterisk", '*'}, {"plus-sign", '+'}, {"comma", ','}, {"hyphen", '-'}, {"hyphen-minus", '-'}, {"period", '.'}, {"full-stop", '.'}, {"slash", '/'}, {"solidus", '/'}, {"zero", '0'}, {"one", '1'}, {"two", '2'}, {"three", '3'}, {"four", '4'}, {"five", '5'}, {"six", '6'}, {"seven", '7'}, {"eight", '8'}, {"nine", '9'}, {"colon", ':'}, {"semicolon", ';'}, {"less-than-sign", '<'}, {"equals-sign", '='}, {"greater-than-sign", '>'}, {"question-mark", '?'}, {"commercial-at", '@'}, {"left-square-bracket", '['}, {"backslash", '\\'}, {"reverse-solidus", '\\'}, {"right-square-bracket", ']'}, {"circumflex", '^'}, {"circumflex-accent", '^'}, {"underscore", '_'}, {"low-line", '_'}, {"grave-accent", '`'}, {"left-brace", '{'}, {"left-curly-bracket", '{'}, {"vertical-line", '|'}, {"right-brace", '}'}, {"right-curly-bracket", '}'}, {"tilde", '~'}, {"DEL", '\177'}, {NULL, 0} }; /* * Unicode character-class tables. */ typedef struct crange { chr start; chr end; } crange; /* * Declarations of Unicode character ranges. This code * is automatically generated by the tools/uniClass.tcl script * and used in generic/regc_locale.c. Do not modify by hand. */ /* * Unicode: alphabetic characters. */ static CONST crange alphaRangeTable[] = { {0x41, 0x5a}, {0x61, 0x7a}, {0xc0, 0xd6}, {0xd8, 0xf6}, {0xf8, 0x2c1}, {0x2c6, 0x2d1}, {0x2e0, 0x2e4}, {0x370, 0x374}, {0x37a, 0x37d}, {0x388, 0x38a}, {0x38e, 0x3a1}, {0x3a3, 0x3f5}, {0x3f7, 0x481}, {0x48a, 0x527}, {0x531, 0x556}, {0x561, 0x587}, {0x5d0, 0x5ea}, {0x5f0, 0x5f2}, {0x620, 0x64a}, {0x671, 0x6d3}, {0x6fa, 0x6fc}, {0x712, 0x72f}, {0x74d, 0x7a5}, {0x7ca, 0x7ea}, {0x800, 0x815}, {0x840, 0x858}, {0x8a2, 0x8ac}, {0x904, 0x939}, {0x958, 0x961}, {0x971, 0x977}, {0x979, 0x97f}, {0x985, 0x98c}, {0x993, 0x9a8}, {0x9aa, 0x9b0}, {0x9b6, 0x9b9}, {0x9df, 0x9e1}, {0xa05, 0xa0a}, {0xa13, 0xa28}, {0xa2a, 0xa30}, {0xa59, 0xa5c}, {0xa72, 0xa74}, {0xa85, 0xa8d}, {0xa8f, 0xa91}, {0xa93, 0xaa8}, {0xaaa, 0xab0}, {0xab5, 0xab9}, {0xb05, 0xb0c}, {0xb13, 0xb28}, {0xb2a, 0xb30}, {0xb35, 0xb39}, {0xb5f, 0xb61}, {0xb85, 0xb8a}, {0xb8e, 0xb90}, {0xb92, 0xb95}, {0xba8, 0xbaa}, {0xbae, 0xbb9}, {0xc05, 0xc0c}, {0xc0e, 0xc10}, {0xc12, 0xc28}, {0xc2a, 0xc33}, {0xc35, 0xc39}, {0xc85, 0xc8c}, {0xc8e, 0xc90}, {0xc92, 0xca8}, {0xcaa, 0xcb3}, {0xcb5, 0xcb9}, {0xd05, 0xd0c}, {0xd0e, 0xd10}, {0xd12, 0xd3a}, {0xd7a, 0xd7f}, {0xd85, 0xd96}, {0xd9a, 0xdb1}, {0xdb3, 0xdbb}, {0xdc0, 0xdc6}, {0xe01, 0xe30}, {0xe40, 0xe46}, {0xe94, 0xe97}, {0xe99, 0xe9f}, {0xea1, 0xea3}, {0xead, 0xeb0}, {0xec0, 0xec4}, {0xedc, 0xedf}, {0xf40, 0xf47}, {0xf49, 0xf6c}, {0xf88, 0xf8c}, {0x1000, 0x102a}, {0x1050, 0x1055}, {0x105a, 0x105d}, {0x106e, 0x1070}, {0x1075, 0x1081}, {0x10a0, 0x10c5}, {0x10d0, 0x10fa}, {0x10fc, 0x1248}, {0x124a, 0x124d}, {0x1250, 0x1256}, {0x125a, 0x125d}, {0x1260, 0x1288}, {0x128a, 0x128d}, {0x1290, 0x12b0}, {0x12b2, 0x12b5}, {0x12b8, 0x12be}, {0x12c2, 0x12c5}, {0x12c8, 0x12d6}, {0x12d8, 0x1310}, {0x1312, 0x1315}, {0x1318, 0x135a}, {0x1380, 0x138f}, {0x13a0, 0x13f4}, {0x1401, 0x166c}, {0x166f, 0x167f}, {0x1681, 0x169a}, {0x16a0, 0x16ea}, {0x1700, 0x170c}, {0x170e, 0x1711}, {0x1720, 0x1731}, {0x1740, 0x1751}, {0x1760, 0x176c}, {0x176e, 0x1770}, {0x1780, 0x17b3}, {0x1820, 0x1877}, {0x1880, 0x18a8}, {0x18b0, 0x18f5}, {0x1900, 0x191c}, {0x1950, 0x196d}, {0x1970, 0x1974}, {0x1980, 0x19ab}, {0x19c1, 0x19c7}, {0x1a00, 0x1a16}, {0x1a20, 0x1a54}, {0x1b05, 0x1b33}, {0x1b45, 0x1b4b}, {0x1b83, 0x1ba0}, {0x1bba, 0x1be5}, {0x1c00, 0x1c23}, {0x1c4d, 0x1c4f}, {0x1c5a, 0x1c7d}, {0x1ce9, 0x1cec}, {0x1cee, 0x1cf1}, {0x1d00, 0x1dbf}, {0x1e00, 0x1f15}, {0x1f18, 0x1f1d}, {0x1f20, 0x1f45}, {0x1f48, 0x1f4d}, {0x1f50, 0x1f57}, {0x1f5f, 0x1f7d}, {0x1f80, 0x1fb4}, {0x1fb6, 0x1fbc}, {0x1fc2, 0x1fc4}, {0x1fc6, 0x1fcc}, {0x1fd0, 0x1fd3}, {0x1fd6, 0x1fdb}, {0x1fe0, 0x1fec}, {0x1ff2, 0x1ff4}, {0x1ff6, 0x1ffc}, {0x2090, 0x209c}, {0x210a, 0x2113}, {0x2119, 0x211d}, {0x212a, 0x212d}, {0x212f, 0x2139}, {0x213c, 0x213f}, {0x2145, 0x2149}, {0x2c00, 0x2c2e}, {0x2c30, 0x2c5e}, {0x2c60, 0x2ce4}, {0x2ceb, 0x2cee}, {0x2d00, 0x2d25}, {0x2d30, 0x2d67}, {0x2d80, 0x2d96}, {0x2da0, 0x2da6}, {0x2da8, 0x2dae}, {0x2db0, 0x2db6}, {0x2db8, 0x2dbe}, {0x2dc0, 0x2dc6}, {0x2dc8, 0x2dce}, {0x2dd0, 0x2dd6}, {0x2dd8, 0x2dde}, {0x3031, 0x3035}, {0x3041, 0x3096}, {0x309d, 0x309f}, {0x30a1, 0x30fa}, {0x30fc, 0x30ff}, {0x3105, 0x312d}, {0x3131, 0x318e}, {0x31a0, 0x31ba}, {0x31f0, 0x31ff}, {0x3400, 0x4db5}, {0x4e00, 0x9fcc}, {0xa000, 0xa48c}, {0xa4d0, 0xa4fd}, {0xa500, 0xa60c}, {0xa610, 0xa61f}, {0xa640, 0xa66e}, {0xa67f, 0xa697}, {0xa6a0, 0xa6e5}, {0xa717, 0xa71f}, {0xa722, 0xa788}, {0xa78b, 0xa78e}, {0xa790, 0xa793}, {0xa7a0, 0xa7aa}, {0xa7f8, 0xa801}, {0xa803, 0xa805}, {0xa807, 0xa80a}, {0xa80c, 0xa822}, {0xa840, 0xa873}, {0xa882, 0xa8b3}, {0xa8f2, 0xa8f7}, {0xa90a, 0xa925}, {0xa930, 0xa946}, {0xa960, 0xa97c}, {0xa984, 0xa9b2}, {0xaa00, 0xaa28}, {0xaa40, 0xaa42}, {0xaa44, 0xaa4b}, {0xaa60, 0xaa76}, {0xaa80, 0xaaaf}, {0xaab9, 0xaabd}, {0xaadb, 0xaadd}, {0xaae0, 0xaaea}, {0xaaf2, 0xaaf4}, {0xab01, 0xab06}, {0xab09, 0xab0e}, {0xab11, 0xab16}, {0xab20, 0xab26}, {0xab28, 0xab2e}, {0xabc0, 0xabe2}, {0xac00, 0xd7a3}, {0xd7b0, 0xd7c6}, {0xd7cb, 0xd7fb}, {0xf900, 0xfa6d}, {0xfa70, 0xfad9}, {0xfb00, 0xfb06}, {0xfb13, 0xfb17}, {0xfb1f, 0xfb28}, {0xfb2a, 0xfb36}, {0xfb38, 0xfb3c}, {0xfb46, 0xfbb1}, {0xfbd3, 0xfd3d}, {0xfd50, 0xfd8f}, {0xfd92, 0xfdc7}, {0xfdf0, 0xfdfb}, {0xfe70, 0xfe74}, {0xfe76, 0xfefc}, {0xff21, 0xff3a}, {0xff41, 0xff5a}, {0xff66, 0xffbe}, {0xffc2, 0xffc7}, {0xffca, 0xffcf}, {0xffd2, 0xffd7}, {0xffda, 0xffdc} #if TCL_UTF_MAX > 4 ,{0x10000, 0x1000b}, {0x1000d, 0x10026}, {0x10028, 0x1003a}, {0x1003f, 0x1004d}, {0x10050, 0x1005d}, {0x10080, 0x100fa}, {0x10280, 0x1029c}, {0x102a0, 0x102d0}, {0x10300, 0x1031e}, {0x10330, 0x10340}, {0x10342, 0x10349}, {0x10380, 0x1039d}, {0x103a0, 0x103c3}, {0x103c8, 0x103cf}, {0x10400, 0x1049d}, {0x10800, 0x10805}, {0x1080a, 0x10835}, {0x1083f, 0x10855}, {0x10900, 0x10915}, {0x10920, 0x10939}, {0x10980, 0x109b7}, {0x10a10, 0x10a13}, {0x10a15, 0x10a17}, {0x10a19, 0x10a33}, {0x10a60, 0x10a7c}, {0x10b00, 0x10b35}, {0x10b40, 0x10b55}, {0x10b60, 0x10b72}, {0x10c00, 0x10c48}, {0x11003, 0x11037}, {0x11083, 0x110af}, {0x110d0, 0x110e8}, {0x11103, 0x11126}, {0x11183, 0x111b2}, {0x111c1, 0x111c4}, {0x11680, 0x116aa}, {0x12000, 0x1236e}, {0x13000, 0x1342e}, {0x16800, 0x16a38}, {0x16f00, 0x16f44}, {0x16f93, 0x16f9f}, {0x1d400, 0x1d454}, {0x1d456, 0x1d49c}, {0x1d4a9, 0x1d4ac}, {0x1d4ae, 0x1d4b9}, {0x1d4bd, 0x1d4c3}, {0x1d4c5, 0x1d505}, {0x1d507, 0x1d50a}, {0x1d50d, 0x1d514}, {0x1d516, 0x1d51c}, {0x1d51e, 0x1d539}, {0x1d53b, 0x1d53e}, {0x1d540, 0x1d544}, {0x1d54a, 0x1d550}, {0x1d552, 0x1d6a5}, {0x1d6a8, 0x1d6c0}, {0x1d6c2, 0x1d6da}, {0x1d6dc, 0x1d6fa}, {0x1d6fc, 0x1d714}, {0x1d716, 0x1d734}, {0x1d736, 0x1d74e}, {0x1d750, 0x1d76e}, {0x1d770, 0x1d788}, {0x1d78a, 0x1d7a8}, {0x1d7aa, 0x1d7c2}, {0x1d7c4, 0x1d7cb}, {0x1ee00, 0x1ee03}, {0x1ee05, 0x1ee1f}, {0x1ee29, 0x1ee32}, {0x1ee34, 0x1ee37}, {0x1ee4d, 0x1ee4f}, {0x1ee67, 0x1ee6a}, {0x1ee6c, 0x1ee72}, {0x1ee74, 0x1ee77}, {0x1ee79, 0x1ee7c}, {0x1ee80, 0x1ee89}, {0x1ee8b, 0x1ee9b}, {0x1eea1, 0x1eea3}, {0x1eea5, 0x1eea9}, {0x1eeab, 0x1eebb}, {0x20000, 0x2a6d6}, {0x2a700, 0x2b734}, {0x2b740, 0x2b81d}, {0x2f800, 0x2fa1d} #endif }; #define NUM_ALPHA_RANGE (sizeof(alphaRangeTable)/sizeof(crange)) static CONST chr alphaCharTable[] = { 0xaa, 0xb5, 0xba, 0x2ec, 0x2ee, 0x376, 0x377, 0x386, 0x38c, 0x559, 0x66e, 0x66f, 0x6d5, 0x6e5, 0x6e6, 0x6ee, 0x6ef, 0x6ff, 0x710, 0x7b1, 0x7f4, 0x7f5, 0x7fa, 0x81a, 0x824, 0x828, 0x8a0, 0x93d, 0x950, 0x98f, 0x990, 0x9b2, 0x9bd, 0x9ce, 0x9dc, 0x9dd, 0x9f0, 0x9f1, 0xa0f, 0xa10, 0xa32, 0xa33, 0xa35, 0xa36, 0xa38, 0xa39, 0xa5e, 0xab2, 0xab3, 0xabd, 0xad0, 0xae0, 0xae1, 0xb0f, 0xb10, 0xb32, 0xb33, 0xb3d, 0xb5c, 0xb5d, 0xb71, 0xb83, 0xb99, 0xb9a, 0xb9c, 0xb9e, 0xb9f, 0xba3, 0xba4, 0xbd0, 0xc3d, 0xc58, 0xc59, 0xc60, 0xc61, 0xcbd, 0xcde, 0xce0, 0xce1, 0xcf1, 0xcf2, 0xd3d, 0xd4e, 0xd60, 0xd61, 0xdbd, 0xe32, 0xe33, 0xe81, 0xe82, 0xe84, 0xe87, 0xe88, 0xe8a, 0xe8d, 0xea5, 0xea7, 0xeaa, 0xeab, 0xeb2, 0xeb3, 0xebd, 0xec6, 0xf00, 0x103f, 0x1061, 0x1065, 0x1066, 0x108e, 0x10c7, 0x10cd, 0x1258, 0x12c0, 0x17d7, 0x17dc, 0x18aa, 0x1aa7, 0x1bae, 0x1baf, 0x1cf5, 0x1cf6, 0x1f59, 0x1f5b, 0x1f5d, 0x1fbe, 0x2071, 0x207f, 0x2102, 0x2107, 0x2115, 0x2124, 0x2126, 0x2128, 0x214e, 0x2183, 0x2184, 0x2cf2, 0x2cf3, 0x2d27, 0x2d2d, 0x2d6f, 0x2e2f, 0x3005, 0x3006, 0x303b, 0x303c, 0xa62a, 0xa62b, 0xa8fb, 0xa9cf, 0xaa7a, 0xaab1, 0xaab5, 0xaab6, 0xaac0, 0xaac2, 0xfb1d, 0xfb3e, 0xfb40, 0xfb41, 0xfb43, 0xfb44 #if TCL_UTF_MAX > 4 ,0x1003c, 0x1003d, 0x10808, 0x10837, 0x10838, 0x1083c, 0x109be, 0x109bf, 0x10a00, 0x16f50, 0x1b000, 0x1b001, 0x1d49e, 0x1d49f, 0x1d4a2, 0x1d4a5, 0x1d4a6, 0x1d4bb, 0x1d546, 0x1ee21, 0x1ee22, 0x1ee24, 0x1ee27, 0x1ee39, 0x1ee3b, 0x1ee42, 0x1ee47, 0x1ee49, 0x1ee4b, 0x1ee51, 0x1ee52, 0x1ee54, 0x1ee57, 0x1ee59, 0x1ee5b, 0x1ee5d, 0x1ee5f, 0x1ee61, 0x1ee62, 0x1ee64, 0x1ee7e #endif }; #define NUM_ALPHA_CHAR (sizeof(alphaCharTable)/sizeof(chr)) /* * Unicode: control characters. */ static CONST crange controlRangeTable[] = { {0x7f, 0x9f}, {0x600, 0x604}, {0x200b, 0x200f}, {0x202a, 0x202e}, {0x2060, 0x2064}, {0x206a, 0x206f}, {0xe000, 0xf8ff}, {0xfff9, 0xfffb} #if TCL_UTF_MAX > 4 ,{0x1d173, 0x1d17a}, {0xe0020, 0xe007f}, {0xf0000, 0xffffd}, {0x100000, 0x10fffd} #endif }; #define NUM_CONTROL_RANGE (sizeof(controlRangeTable)/sizeof(crange)) static CONST chr controlCharTable[] = { 0xad, 0x6dd, 0x70f, 0xfeff #if TCL_UTF_MAX > 4 ,0x110bd, 0xe0001 #endif }; #define NUM_CONTROL_CHAR (sizeof(controlCharTable)/sizeof(chr)) /* * Unicode: decimal digit characters. */ static CONST crange digitRangeTable[] = { {0x30, 0x39}, {0x660, 0x669}, {0x6f0, 0x6f9}, {0x7c0, 0x7c9}, {0x966, 0x96f}, {0x9e6, 0x9ef}, {0xa66, 0xa6f}, {0xae6, 0xaef}, {0xb66, 0xb6f}, {0xbe6, 0xbef}, {0xc66, 0xc6f}, {0xce6, 0xcef}, {0xd66, 0xd6f}, {0xe50, 0xe59}, {0xed0, 0xed9}, {0xf20, 0xf29}, {0x1040, 0x1049}, {0x1090, 0x1099}, {0x17e0, 0x17e9}, {0x1810, 0x1819}, {0x1946, 0x194f}, {0x19d0, 0x19d9}, {0x1a80, 0x1a89}, {0x1a90, 0x1a99}, {0x1b50, 0x1b59}, {0x1bb0, 0x1bb9}, {0x1c40, 0x1c49}, {0x1c50, 0x1c59}, {0xa620, 0xa629}, {0xa8d0, 0xa8d9}, {0xa900, 0xa909}, {0xa9d0, 0xa9d9}, {0xaa50, 0xaa59}, {0xabf0, 0xabf9}, {0xff10, 0xff19} #if TCL_UTF_MAX > 4 ,{0x104a0, 0x104a9}, {0x11066, 0x1106f}, {0x110f0, 0x110f9}, {0x11136, 0x1113f}, {0x111d0, 0x111d9}, {0x116c0, 0x116c9}, {0x1d7ce, 0x1d7ff} #endif }; #define NUM_DIGIT_RANGE (sizeof(digitRangeTable)/sizeof(crange)) /* * no singletons of digit characters. */ /* * Unicode: punctuation characters. */ static CONST crange punctRangeTable[] = { {0x21, 0x23}, {0x25, 0x2a}, {0x2c, 0x2f}, {0x5b, 0x5d}, {0x55a, 0x55f}, {0x66a, 0x66d}, {0x700, 0x70d}, {0x7f7, 0x7f9}, {0x830, 0x83e}, {0xf04, 0xf12}, {0xf3a, 0xf3d}, {0xfd0, 0xfd4}, {0x104a, 0x104f}, {0x1360, 0x1368}, {0x16eb, 0x16ed}, {0x17d4, 0x17d6}, {0x17d8, 0x17da}, {0x1800, 0x180a}, {0x1aa0, 0x1aa6}, {0x1aa8, 0x1aad}, {0x1b5a, 0x1b60}, {0x1bfc, 0x1bff}, {0x1c3b, 0x1c3f}, {0x1cc0, 0x1cc7}, {0x2010, 0x2027}, {0x2030, 0x2043}, {0x2045, 0x2051}, {0x2053, 0x205e}, {0x2768, 0x2775}, {0x27e6, 0x27ef}, {0x2983, 0x2998}, {0x29d8, 0x29db}, {0x2cf9, 0x2cfc}, {0x2e00, 0x2e2e}, {0x2e30, 0x2e3b}, {0x3001, 0x3003}, {0x3008, 0x3011}, {0x3014, 0x301f}, {0xa60d, 0xa60f}, {0xa6f2, 0xa6f7}, {0xa874, 0xa877}, {0xa8f8, 0xa8fa}, {0xa9c1, 0xa9cd}, {0xaa5c, 0xaa5f}, {0xfe10, 0xfe19}, {0xfe30, 0xfe52}, {0xfe54, 0xfe61}, {0xff01, 0xff03}, {0xff05, 0xff0a}, {0xff0c, 0xff0f}, {0xff3b, 0xff3d}, {0xff5f, 0xff65} #if TCL_UTF_MAX > 4 ,{0x10100, 0x10102}, {0x10a50, 0x10a58}, {0x10b39, 0x10b3f}, {0x11047, 0x1104d}, {0x110be, 0x110c1}, {0x11140, 0x11143}, {0x111c5, 0x111c8}, {0x12470, 0x12473} #endif }; #define NUM_PUNCT_RANGE (sizeof(punctRangeTable)/sizeof(crange)) static CONST chr punctCharTable[] = { 0x3a, 0x3b, 0x3f, 0x40, 0x5f, 0x7b, 0x7d, 0xa1, 0xa7, 0xab, 0xb6, 0xb7, 0xbb, 0xbf, 0x37e, 0x387, 0x589, 0x58a, 0x5be, 0x5c0, 0x5c3, 0x5c6, 0x5f3, 0x5f4, 0x609, 0x60a, 0x60c, 0x60d, 0x61b, 0x61e, 0x61f, 0x6d4, 0x85e, 0x964, 0x965, 0x970, 0xaf0, 0xdf4, 0xe4f, 0xe5a, 0xe5b, 0xf14, 0xf85, 0xfd9, 0xfda, 0x10fb, 0x1400, 0x166d, 0x166e, 0x169b, 0x169c, 0x1735, 0x1736, 0x1944, 0x1945, 0x1a1e, 0x1a1f, 0x1c7e, 0x1c7f, 0x1cd3, 0x207d, 0x207e, 0x208d, 0x208e, 0x2329, 0x232a, 0x27c5, 0x27c6, 0x29fc, 0x29fd, 0x2cfe, 0x2cff, 0x2d70, 0x3030, 0x303d, 0x30a0, 0x30fb, 0xa4fe, 0xa4ff, 0xa673, 0xa67e, 0xa8ce, 0xa8cf, 0xa92e, 0xa92f, 0xa95f, 0xa9de, 0xa9df, 0xaade, 0xaadf, 0xaaf0, 0xaaf1, 0xabeb, 0xfd3e, 0xfd3f, 0xfe63, 0xfe68, 0xfe6a, 0xfe6b, 0xff1a, 0xff1b, 0xff1f, 0xff20, 0xff3f, 0xff5b, 0xff5d #if TCL_UTF_MAX > 4 ,0x1039f, 0x103d0, 0x10857, 0x1091f, 0x1093f, 0x10a7f, 0x110bb, 0x110bc #endif }; #define NUM_PUNCT_CHAR (sizeof(punctCharTable)/sizeof(chr)) /* * Unicode: white space characters. */ static CONST crange spaceRangeTable[] = { {0x9, 0xd}, {0x2000, 0x200a} }; #define NUM_SPACE_RANGE (sizeof(spaceRangeTable)/sizeof(crange)) static CONST chr spaceCharTable[] = { 0x20, 0xa0, 0x1680, 0x180e, 0x2028, 0x2029, 0x202f, 0x205f, 0x3000 }; #define NUM_SPACE_CHAR (sizeof(spaceCharTable)/sizeof(chr)) /* * Unicode: lowercase characters. */ static CONST crange lowerRangeTable[] = { {0x61, 0x7a}, {0xdf, 0xf6}, {0xf8, 0xff}, {0x17e, 0x180}, {0x199, 0x19b}, {0x1bd, 0x1bf}, {0x233, 0x239}, {0x24f, 0x293}, {0x295, 0x2af}, {0x37b, 0x37d}, {0x3ac, 0x3ce}, {0x3d5, 0x3d7}, {0x3ef, 0x3f3}, {0x430, 0x45f}, {0x561, 0x587}, {0x1d00, 0x1d2b}, {0x1d6b, 0x1d77}, {0x1d79, 0x1d9a}, {0x1e95, 0x1e9d}, {0x1eff, 0x1f07}, {0x1f10, 0x1f15}, {0x1f20, 0x1f27}, {0x1f30, 0x1f37}, {0x1f40, 0x1f45}, {0x1f50, 0x1f57}, {0x1f60, 0x1f67}, {0x1f70, 0x1f7d}, {0x1f80, 0x1f87}, {0x1f90, 0x1f97}, {0x1fa0, 0x1fa7}, {0x1fb0, 0x1fb4}, {0x1fc2, 0x1fc4}, {0x1fd0, 0x1fd3}, {0x1fe0, 0x1fe7}, {0x1ff2, 0x1ff4}, {0x2146, 0x2149}, {0x2c30, 0x2c5e}, {0x2c76, 0x2c7b}, {0x2d00, 0x2d25}, {0xa72f, 0xa731}, {0xa771, 0xa778}, {0xfb00, 0xfb06}, {0xfb13, 0xfb17}, {0xff41, 0xff5a} #if TCL_UTF_MAX > 4 ,{0x10428, 0x1044f}, {0x1d41a, 0x1d433}, {0x1d44e, 0x1d454}, {0x1d456, 0x1d467}, {0x1d482, 0x1d49b}, {0x1d4b6, 0x1d4b9}, {0x1d4bd, 0x1d4c3}, {0x1d4c5, 0x1d4cf}, {0x1d4ea, 0x1d503}, {0x1d51e, 0x1d537}, {0x1d552, 0x1d56b}, {0x1d586, 0x1d59f}, {0x1d5ba, 0x1d5d3}, {0x1d5ee, 0x1d607}, {0x1d622, 0x1d63b}, {0x1d656, 0x1d66f}, {0x1d68a, 0x1d6a5}, {0x1d6c2, 0x1d6da}, {0x1d6dc, 0x1d6e1}, {0x1d6fc, 0x1d714}, {0x1d716, 0x1d71b}, {0x1d736, 0x1d74e}, {0x1d750, 0x1d755}, {0x1d770, 0x1d788}, {0x1d78a, 0x1d78f}, {0x1d7aa, 0x1d7c2}, {0x1d7c4, 0x1d7c9} #endif }; #define NUM_LOWER_RANGE (sizeof(lowerRangeTable)/sizeof(crange)) static CONST chr lowerCharTable[] = { 0xb5, 0x101, 0x103, 0x105, 0x107, 0x109, 0x10b, 0x10d, 0x10f, 0x111, 0x113, 0x115, 0x117, 0x119, 0x11b, 0x11d, 0x11f, 0x121, 0x123, 0x125, 0x127, 0x129, 0x12b, 0x12d, 0x12f, 0x131, 0x133, 0x135, 0x137, 0x138, 0x13a, 0x13c, 0x13e, 0x140, 0x142, 0x144, 0x146, 0x148, 0x149, 0x14b, 0x14d, 0x14f, 0x151, 0x153, 0x155, 0x157, 0x159, 0x15b, 0x15d, 0x15f, 0x161, 0x163, 0x165, 0x167, 0x169, 0x16b, 0x16d, 0x16f, 0x171, 0x173, 0x175, 0x177, 0x17a, 0x17c, 0x183, 0x185, 0x188, 0x18c, 0x18d, 0x192, 0x195, 0x19e, 0x1a1, 0x1a3, 0x1a5, 0x1a8, 0x1aa, 0x1ab, 0x1ad, 0x1b0, 0x1b4, 0x1b6, 0x1b9, 0x1ba, 0x1c6, 0x1c9, 0x1cc, 0x1ce, 0x1d0, 0x1d2, 0x1d4, 0x1d6, 0x1d8, 0x1da, 0x1dc, 0x1dd, 0x1df, 0x1e1, 0x1e3, 0x1e5, 0x1e7, 0x1e9, 0x1eb, 0x1ed, 0x1ef, 0x1f0, 0x1f3, 0x1f5, 0x1f9, 0x1fb, 0x1fd, 0x1ff, 0x201, 0x203, 0x205, 0x207, 0x209, 0x20b, 0x20d, 0x20f, 0x211, 0x213, 0x215, 0x217, 0x219, 0x21b, 0x21d, 0x21f, 0x221, 0x223, 0x225, 0x227, 0x229, 0x22b, 0x22d, 0x22f, 0x231, 0x23c, 0x23f, 0x240, 0x242, 0x247, 0x249, 0x24b, 0x24d, 0x371, 0x373, 0x377, 0x390, 0x3d0, 0x3d1, 0x3d9, 0x3db, 0x3dd, 0x3df, 0x3e1, 0x3e3, 0x3e5, 0x3e7, 0x3e9, 0x3eb, 0x3ed, 0x3f5, 0x3f8, 0x3fb, 0x3fc, 0x461, 0x463, 0x465, 0x467, 0x469, 0x46b, 0x46d, 0x46f, 0x471, 0x473, 0x475, 0x477, 0x479, 0x47b, 0x47d, 0x47f, 0x481, 0x48b, 0x48d, 0x48f, 0x491, 0x493, 0x495, 0x497, 0x499, 0x49b, 0x49d, 0x49f, 0x4a1, 0x4a3, 0x4a5, 0x4a7, 0x4a9, 0x4ab, 0x4ad, 0x4af, 0x4b1, 0x4b3, 0x4b5, 0x4b7, 0x4b9, 0x4bb, 0x4bd, 0x4bf, 0x4c2, 0x4c4, 0x4c6, 0x4c8, 0x4ca, 0x4cc, 0x4ce, 0x4cf, 0x4d1, 0x4d3, 0x4d5, 0x4d7, 0x4d9, 0x4db, 0x4dd, 0x4df, 0x4e1, 0x4e3, 0x4e5, 0x4e7, 0x4e9, 0x4eb, 0x4ed, 0x4ef, 0x4f1, 0x4f3, 0x4f5, 0x4f7, 0x4f9, 0x4fb, 0x4fd, 0x4ff, 0x501, 0x503, 0x505, 0x507, 0x509, 0x50b, 0x50d, 0x50f, 0x511, 0x513, 0x515, 0x517, 0x519, 0x51b, 0x51d, 0x51f, 0x521, 0x523, 0x525, 0x527, 0x1e01, 0x1e03, 0x1e05, 0x1e07, 0x1e09, 0x1e0b, 0x1e0d, 0x1e0f, 0x1e11, 0x1e13, 0x1e15, 0x1e17, 0x1e19, 0x1e1b, 0x1e1d, 0x1e1f, 0x1e21, 0x1e23, 0x1e25, 0x1e27, 0x1e29, 0x1e2b, 0x1e2d, 0x1e2f, 0x1e31, 0x1e33, 0x1e35, 0x1e37, 0x1e39, 0x1e3b, 0x1e3d, 0x1e3f, 0x1e41, 0x1e43, 0x1e45, 0x1e47, 0x1e49, 0x1e4b, 0x1e4d, 0x1e4f, 0x1e51, 0x1e53, 0x1e55, 0x1e57, 0x1e59, 0x1e5b, 0x1e5d, 0x1e5f, 0x1e61, 0x1e63, 0x1e65, 0x1e67, 0x1e69, 0x1e6b, 0x1e6d, 0x1e6f, 0x1e71, 0x1e73, 0x1e75, 0x1e77, 0x1e79, 0x1e7b, 0x1e7d, 0x1e7f, 0x1e81, 0x1e83, 0x1e85, 0x1e87, 0x1e89, 0x1e8b, 0x1e8d, 0x1e8f, 0x1e91, 0x1e93, 0x1e9f, 0x1ea1, 0x1ea3, 0x1ea5, 0x1ea7, 0x1ea9, 0x1eab, 0x1ead, 0x1eaf, 0x1eb1, 0x1eb3, 0x1eb5, 0x1eb7, 0x1eb9, 0x1ebb, 0x1ebd, 0x1ebf, 0x1ec1, 0x1ec3, 0x1ec5, 0x1ec7, 0x1ec9, 0x1ecb, 0x1ecd, 0x1ecf, 0x1ed1, 0x1ed3, 0x1ed5, 0x1ed7, 0x1ed9, 0x1edb, 0x1edd, 0x1edf, 0x1ee1, 0x1ee3, 0x1ee5, 0x1ee7, 0x1ee9, 0x1eeb, 0x1eed, 0x1eef, 0x1ef1, 0x1ef3, 0x1ef5, 0x1ef7, 0x1ef9, 0x1efb, 0x1efd, 0x1fb6, 0x1fb7, 0x1fbe, 0x1fc6, 0x1fc7, 0x1fd6, 0x1fd7, 0x1ff6, 0x1ff7, 0x210a, 0x210e, 0x210f, 0x2113, 0x212f, 0x2134, 0x2139, 0x213c, 0x213d, 0x214e, 0x2184, 0x2c61, 0x2c65, 0x2c66, 0x2c68, 0x2c6a, 0x2c6c, 0x2c71, 0x2c73, 0x2c74, 0x2c81, 0x2c83, 0x2c85, 0x2c87, 0x2c89, 0x2c8b, 0x2c8d, 0x2c8f, 0x2c91, 0x2c93, 0x2c95, 0x2c97, 0x2c99, 0x2c9b, 0x2c9d, 0x2c9f, 0x2ca1, 0x2ca3, 0x2ca5, 0x2ca7, 0x2ca9, 0x2cab, 0x2cad, 0x2caf, 0x2cb1, 0x2cb3, 0x2cb5, 0x2cb7, 0x2cb9, 0x2cbb, 0x2cbd, 0x2cbf, 0x2cc1, 0x2cc3, 0x2cc5, 0x2cc7, 0x2cc9, 0x2ccb, 0x2ccd, 0x2ccf, 0x2cd1, 0x2cd3, 0x2cd5, 0x2cd7, 0x2cd9, 0x2cdb, 0x2cdd, 0x2cdf, 0x2ce1, 0x2ce3, 0x2ce4, 0x2cec, 0x2cee, 0x2cf3, 0x2d27, 0x2d2d, 0xa641, 0xa643, 0xa645, 0xa647, 0xa649, 0xa64b, 0xa64d, 0xa64f, 0xa651, 0xa653, 0xa655, 0xa657, 0xa659, 0xa65b, 0xa65d, 0xa65f, 0xa661, 0xa663, 0xa665, 0xa667, 0xa669, 0xa66b, 0xa66d, 0xa681, 0xa683, 0xa685, 0xa687, 0xa689, 0xa68b, 0xa68d, 0xa68f, 0xa691, 0xa693, 0xa695, 0xa697, 0xa723, 0xa725, 0xa727, 0xa729, 0xa72b, 0xa72d, 0xa733, 0xa735, 0xa737, 0xa739, 0xa73b, 0xa73d, 0xa73f, 0xa741, 0xa743, 0xa745, 0xa747, 0xa749, 0xa74b, 0xa74d, 0xa74f, 0xa751, 0xa753, 0xa755, 0xa757, 0xa759, 0xa75b, 0xa75d, 0xa75f, 0xa761, 0xa763, 0xa765, 0xa767, 0xa769, 0xa76b, 0xa76d, 0xa76f, 0xa77a, 0xa77c, 0xa77f, 0xa781, 0xa783, 0xa785, 0xa787, 0xa78c, 0xa78e, 0xa791, 0xa793, 0xa7a1, 0xa7a3, 0xa7a5, 0xa7a7, 0xa7a9, 0xa7fa #if TCL_UTF_MAX > 4 ,0x1d4bb, 0x1d7cb #endif }; #define NUM_LOWER_CHAR (sizeof(lowerCharTable)/sizeof(chr)) /* * Unicode: uppercase characters. */ static CONST crange upperRangeTable[] = { {0x41, 0x5a}, {0xc0, 0xd6}, {0xd8, 0xde}, {0x189, 0x18b}, {0x18e, 0x191}, {0x196, 0x198}, {0x1b1, 0x1b3}, {0x1f6, 0x1f8}, {0x243, 0x246}, {0x388, 0x38a}, {0x391, 0x3a1}, {0x3a3, 0x3ab}, {0x3d2, 0x3d4}, {0x3fd, 0x42f}, {0x531, 0x556}, {0x10a0, 0x10c5}, {0x1f08, 0x1f0f}, {0x1f18, 0x1f1d}, {0x1f28, 0x1f2f}, {0x1f38, 0x1f3f}, {0x1f48, 0x1f4d}, {0x1f68, 0x1f6f}, {0x1fb8, 0x1fbb}, {0x1fc8, 0x1fcb}, {0x1fd8, 0x1fdb}, {0x1fe8, 0x1fec}, {0x1ff8, 0x1ffb}, {0x210b, 0x210d}, {0x2110, 0x2112}, {0x2119, 0x211d}, {0x212a, 0x212d}, {0x2130, 0x2133}, {0x2c00, 0x2c2e}, {0x2c62, 0x2c64}, {0x2c6d, 0x2c70}, {0x2c7e, 0x2c80}, {0xff21, 0xff3a} #if TCL_UTF_MAX > 4 ,{0x10400, 0x10427}, {0x1d400, 0x1d419}, {0x1d434, 0x1d44d}, {0x1d468, 0x1d481}, {0x1d4a9, 0x1d4ac}, {0x1d4ae, 0x1d4b5}, {0x1d4d0, 0x1d4e9}, {0x1d507, 0x1d50a}, {0x1d50d, 0x1d514}, {0x1d516, 0x1d51c}, {0x1d53b, 0x1d53e}, {0x1d540, 0x1d544}, {0x1d54a, 0x1d550}, {0x1d56c, 0x1d585}, {0x1d5a0, 0x1d5b9}, {0x1d5d4, 0x1d5ed}, {0x1d608, 0x1d621}, {0x1d63c, 0x1d655}, {0x1d670, 0x1d689}, {0x1d6a8, 0x1d6c0}, {0x1d6e2, 0x1d6fa}, {0x1d71c, 0x1d734}, {0x1d756, 0x1d76e}, {0x1d790, 0x1d7a8} #endif }; #define NUM_UPPER_RANGE (sizeof(upperRangeTable)/sizeof(crange)) static CONST chr upperCharTable[] = { 0x100, 0x102, 0x104, 0x106, 0x108, 0x10a, 0x10c, 0x10e, 0x110, 0x112, 0x114, 0x116, 0x118, 0x11a, 0x11c, 0x11e, 0x120, 0x122, 0x124, 0x126, 0x128, 0x12a, 0x12c, 0x12e, 0x130, 0x132, 0x134, 0x136, 0x139, 0x13b, 0x13d, 0x13f, 0x141, 0x143, 0x145, 0x147, 0x14a, 0x14c, 0x14e, 0x150, 0x152, 0x154, 0x156, 0x158, 0x15a, 0x15c, 0x15e, 0x160, 0x162, 0x164, 0x166, 0x168, 0x16a, 0x16c, 0x16e, 0x170, 0x172, 0x174, 0x176, 0x178, 0x179, 0x17b, 0x17d, 0x181, 0x182, 0x184, 0x186, 0x187, 0x193, 0x194, 0x19c, 0x19d, 0x19f, 0x1a0, 0x1a2, 0x1a4, 0x1a6, 0x1a7, 0x1a9, 0x1ac, 0x1ae, 0x1af, 0x1b5, 0x1b7, 0x1b8, 0x1bc, 0x1c4, 0x1c7, 0x1ca, 0x1cd, 0x1cf, 0x1d1, 0x1d3, 0x1d5, 0x1d7, 0x1d9, 0x1db, 0x1de, 0x1e0, 0x1e2, 0x1e4, 0x1e6, 0x1e8, 0x1ea, 0x1ec, 0x1ee, 0x1f1, 0x1f4, 0x1fa, 0x1fc, 0x1fe, 0x200, 0x202, 0x204, 0x206, 0x208, 0x20a, 0x20c, 0x20e, 0x210, 0x212, 0x214, 0x216, 0x218, 0x21a, 0x21c, 0x21e, 0x220, 0x222, 0x224, 0x226, 0x228, 0x22a, 0x22c, 0x22e, 0x230, 0x232, 0x23a, 0x23b, 0x23d, 0x23e, 0x241, 0x248, 0x24a, 0x24c, 0x24e, 0x370, 0x372, 0x376, 0x386, 0x38c, 0x38e, 0x38f, 0x3cf, 0x3d8, 0x3da, 0x3dc, 0x3de, 0x3e0, 0x3e2, 0x3e4, 0x3e6, 0x3e8, 0x3ea, 0x3ec, 0x3ee, 0x3f4, 0x3f7, 0x3f9, 0x3fa, 0x460, 0x462, 0x464, 0x466, 0x468, 0x46a, 0x46c, 0x46e, 0x470, 0x472, 0x474, 0x476, 0x478, 0x47a, 0x47c, 0x47e, 0x480, 0x48a, 0x48c, 0x48e, 0x490, 0x492, 0x494, 0x496, 0x498, 0x49a, 0x49c, 0x49e, 0x4a0, 0x4a2, 0x4a4, 0x4a6, 0x4a8, 0x4aa, 0x4ac, 0x4ae, 0x4b0, 0x4b2, 0x4b4, 0x4b6, 0x4b8, 0x4ba, 0x4bc, 0x4be, 0x4c0, 0x4c1, 0x4c3, 0x4c5, 0x4c7, 0x4c9, 0x4cb, 0x4cd, 0x4d0, 0x4d2, 0x4d4, 0x4d6, 0x4d8, 0x4da, 0x4dc, 0x4de, 0x4e0, 0x4e2, 0x4e4, 0x4e6, 0x4e8, 0x4ea, 0x4ec, 0x4ee, 0x4f0, 0x4f2, 0x4f4, 0x4f6, 0x4f8, 0x4fa, 0x4fc, 0x4fe, 0x500, 0x502, 0x504, 0x506, 0x508, 0x50a, 0x50c, 0x50e, 0x510, 0x512, 0x514, 0x516, 0x518, 0x51a, 0x51c, 0x51e, 0x520, 0x522, 0x524, 0x526, 0x10c7, 0x10cd, 0x1e00, 0x1e02, 0x1e04, 0x1e06, 0x1e08, 0x1e0a, 0x1e0c, 0x1e0e, 0x1e10, 0x1e12, 0x1e14, 0x1e16, 0x1e18, 0x1e1a, 0x1e1c, 0x1e1e, 0x1e20, 0x1e22, 0x1e24, 0x1e26, 0x1e28, 0x1e2a, 0x1e2c, 0x1e2e, 0x1e30, 0x1e32, 0x1e34, 0x1e36, 0x1e38, 0x1e3a, 0x1e3c, 0x1e3e, 0x1e40, 0x1e42, 0x1e44, 0x1e46, 0x1e48, 0x1e4a, 0x1e4c, 0x1e4e, 0x1e50, 0x1e52, 0x1e54, 0x1e56, 0x1e58, 0x1e5a, 0x1e5c, 0x1e5e, 0x1e60, 0x1e62, 0x1e64, 0x1e66, 0x1e68, 0x1e6a, 0x1e6c, 0x1e6e, 0x1e70, 0x1e72, 0x1e74, 0x1e76, 0x1e78, 0x1e7a, 0x1e7c, 0x1e7e, 0x1e80, 0x1e82, 0x1e84, 0x1e86, 0x1e88, 0x1e8a, 0x1e8c, 0x1e8e, 0x1e90, 0x1e92, 0x1e94, 0x1e9e, 0x1ea0, 0x1ea2, 0x1ea4, 0x1ea6, 0x1ea8, 0x1eaa, 0x1eac, 0x1eae, 0x1eb0, 0x1eb2, 0x1eb4, 0x1eb6, 0x1eb8, 0x1eba, 0x1ebc, 0x1ebe, 0x1ec0, 0x1ec2, 0x1ec4, 0x1ec6, 0x1ec8, 0x1eca, 0x1ecc, 0x1ece, 0x1ed0, 0x1ed2, 0x1ed4, 0x1ed6, 0x1ed8, 0x1eda, 0x1edc, 0x1ede, 0x1ee0, 0x1ee2, 0x1ee4, 0x1ee6, 0x1ee8, 0x1eea, 0x1eec, 0x1eee, 0x1ef0, 0x1ef2, 0x1ef4, 0x1ef6, 0x1ef8, 0x1efa, 0x1efc, 0x1efe, 0x1f59, 0x1f5b, 0x1f5d, 0x1f5f, 0x2102, 0x2107, 0x2115, 0x2124, 0x2126, 0x2128, 0x213e, 0x213f, 0x2145, 0x2183, 0x2c60, 0x2c67, 0x2c69, 0x2c6b, 0x2c72, 0x2c75, 0x2c82, 0x2c84, 0x2c86, 0x2c88, 0x2c8a, 0x2c8c, 0x2c8e, 0x2c90, 0x2c92, 0x2c94, 0x2c96, 0x2c98, 0x2c9a, 0x2c9c, 0x2c9e, 0x2ca0, 0x2ca2, 0x2ca4, 0x2ca6, 0x2ca8, 0x2caa, 0x2cac, 0x2cae, 0x2cb0, 0x2cb2, 0x2cb4, 0x2cb6, 0x2cb8, 0x2cba, 0x2cbc, 0x2cbe, 0x2cc0, 0x2cc2, 0x2cc4, 0x2cc6, 0x2cc8, 0x2cca, 0x2ccc, 0x2cce, 0x2cd0, 0x2cd2, 0x2cd4, 0x2cd6, 0x2cd8, 0x2cda, 0x2cdc, 0x2cde, 0x2ce0, 0x2ce2, 0x2ceb, 0x2ced, 0x2cf2, 0xa640, 0xa642, 0xa644, 0xa646, 0xa648, 0xa64a, 0xa64c, 0xa64e, 0xa650, 0xa652, 0xa654, 0xa656, 0xa658, 0xa65a, 0xa65c, 0xa65e, 0xa660, 0xa662, 0xa664, 0xa666, 0xa668, 0xa66a, 0xa66c, 0xa680, 0xa682, 0xa684, 0xa686, 0xa688, 0xa68a, 0xa68c, 0xa68e, 0xa690, 0xa692, 0xa694, 0xa696, 0xa722, 0xa724, 0xa726, 0xa728, 0xa72a, 0xa72c, 0xa72e, 0xa732, 0xa734, 0xa736, 0xa738, 0xa73a, 0xa73c, 0xa73e, 0xa740, 0xa742, 0xa744, 0xa746, 0xa748, 0xa74a, 0xa74c, 0xa74e, 0xa750, 0xa752, 0xa754, 0xa756, 0xa758, 0xa75a, 0xa75c, 0xa75e, 0xa760, 0xa762, 0xa764, 0xa766, 0xa768, 0xa76a, 0xa76c, 0xa76e, 0xa779, 0xa77b, 0xa77d, 0xa77e, 0xa780, 0xa782, 0xa784, 0xa786, 0xa78b, 0xa78d, 0xa790, 0xa792, 0xa7a0, 0xa7a2, 0xa7a4, 0xa7a6, 0xa7a8, 0xa7aa #if TCL_UTF_MAX > 4 ,0x1d49c, 0x1d49e, 0x1d49f, 0x1d4a2, 0x1d4a5, 0x1d4a6, 0x1d504, 0x1d505, 0x1d538, 0x1d539, 0x1d546, 0x1d7ca #endif }; #define NUM_UPPER_CHAR (sizeof(upperCharTable)/sizeof(chr)) /* * Unicode: unicode print characters excluding space. */ static CONST crange graphRangeTable[] = { {0x21, 0x7e}, {0xa1, 0xac}, {0xae, 0x377}, {0x37a, 0x37e}, {0x384, 0x38a}, {0x38e, 0x3a1}, {0x3a3, 0x527}, {0x531, 0x556}, {0x559, 0x55f}, {0x561, 0x587}, {0x591, 0x5c7}, {0x5d0, 0x5ea}, {0x5f0, 0x5f4}, {0x606, 0x61b}, {0x61e, 0x6dc}, {0x6de, 0x70d}, {0x710, 0x74a}, {0x74d, 0x7b1}, {0x7c0, 0x7fa}, {0x800, 0x82d}, {0x830, 0x83e}, {0x840, 0x85b}, {0x8a2, 0x8ac}, {0x8e4, 0x8fe}, {0x900, 0x977}, {0x979, 0x97f}, {0x981, 0x983}, {0x985, 0x98c}, {0x993, 0x9a8}, {0x9aa, 0x9b0}, {0x9b6, 0x9b9}, {0x9bc, 0x9c4}, {0x9cb, 0x9ce}, {0x9df, 0x9e3}, {0x9e6, 0x9fb}, {0xa01, 0xa03}, {0xa05, 0xa0a}, {0xa13, 0xa28}, {0xa2a, 0xa30}, {0xa3e, 0xa42}, {0xa4b, 0xa4d}, {0xa59, 0xa5c}, {0xa66, 0xa75}, {0xa81, 0xa83}, {0xa85, 0xa8d}, {0xa8f, 0xa91}, {0xa93, 0xaa8}, {0xaaa, 0xab0}, {0xab5, 0xab9}, {0xabc, 0xac5}, {0xac7, 0xac9}, {0xacb, 0xacd}, {0xae0, 0xae3}, {0xae6, 0xaf1}, {0xb01, 0xb03}, {0xb05, 0xb0c}, {0xb13, 0xb28}, {0xb2a, 0xb30}, {0xb35, 0xb39}, {0xb3c, 0xb44}, {0xb4b, 0xb4d}, {0xb5f, 0xb63}, {0xb66, 0xb77}, {0xb85, 0xb8a}, {0xb8e, 0xb90}, {0xb92, 0xb95}, {0xba8, 0xbaa}, {0xbae, 0xbb9}, {0xbbe, 0xbc2}, {0xbc6, 0xbc8}, {0xbca, 0xbcd}, {0xbe6, 0xbfa}, {0xc01, 0xc03}, {0xc05, 0xc0c}, {0xc0e, 0xc10}, {0xc12, 0xc28}, {0xc2a, 0xc33}, {0xc35, 0xc39}, {0xc3d, 0xc44}, {0xc46, 0xc48}, {0xc4a, 0xc4d}, {0xc60, 0xc63}, {0xc66, 0xc6f}, {0xc78, 0xc7f}, {0xc85, 0xc8c}, {0xc8e, 0xc90}, {0xc92, 0xca8}, {0xcaa, 0xcb3}, {0xcb5, 0xcb9}, {0xcbc, 0xcc4}, {0xcc6, 0xcc8}, {0xcca, 0xccd}, {0xce0, 0xce3}, {0xce6, 0xcef}, {0xd05, 0xd0c}, {0xd0e, 0xd10}, {0xd12, 0xd3a}, {0xd3d, 0xd44}, {0xd46, 0xd48}, {0xd4a, 0xd4e}, {0xd60, 0xd63}, {0xd66, 0xd75}, {0xd79, 0xd7f}, {0xd85, 0xd96}, {0xd9a, 0xdb1}, {0xdb3, 0xdbb}, {0xdc0, 0xdc6}, {0xdcf, 0xdd4}, {0xdd8, 0xddf}, {0xdf2, 0xdf4}, {0xe01, 0xe3a}, {0xe3f, 0xe5b}, {0xe94, 0xe97}, {0xe99, 0xe9f}, {0xea1, 0xea3}, {0xead, 0xeb9}, {0xebb, 0xebd}, {0xec0, 0xec4}, {0xec8, 0xecd}, {0xed0, 0xed9}, {0xedc, 0xedf}, {0xf00, 0xf47}, {0xf49, 0xf6c}, {0xf71, 0xf97}, {0xf99, 0xfbc}, {0xfbe, 0xfcc}, {0xfce, 0xfda}, {0x1000, 0x10c5}, {0x10d0, 0x1248}, {0x124a, 0x124d}, {0x1250, 0x1256}, {0x125a, 0x125d}, {0x1260, 0x1288}, {0x128a, 0x128d}, {0x1290, 0x12b0}, {0x12b2, 0x12b5}, {0x12b8, 0x12be}, {0x12c2, 0x12c5}, {0x12c8, 0x12d6}, {0x12d8, 0x1310}, {0x1312, 0x1315}, {0x1318, 0x135a}, {0x135d, 0x137c}, {0x1380, 0x1399}, {0x13a0, 0x13f4}, {0x1400, 0x167f}, {0x1681, 0x169c}, {0x16a0, 0x16f0}, {0x1700, 0x170c}, {0x170e, 0x1714}, {0x1720, 0x1736}, {0x1740, 0x1753}, {0x1760, 0x176c}, {0x176e, 0x1770}, {0x1780, 0x17dd}, {0x17e0, 0x17e9}, {0x17f0, 0x17f9}, {0x1800, 0x180d}, {0x1810, 0x1819}, {0x1820, 0x1877}, {0x1880, 0x18aa}, {0x18b0, 0x18f5}, {0x1900, 0x191c}, {0x1920, 0x192b}, {0x1930, 0x193b}, {0x1944, 0x196d}, {0x1970, 0x1974}, {0x1980, 0x19ab}, {0x19b0, 0x19c9}, {0x19d0, 0x19da}, {0x19de, 0x1a1b}, {0x1a1e, 0x1a5e}, {0x1a60, 0x1a7c}, {0x1a7f, 0x1a89}, {0x1a90, 0x1a99}, {0x1aa0, 0x1aad}, {0x1b00, 0x1b4b}, {0x1b50, 0x1b7c}, {0x1b80, 0x1bf3}, {0x1bfc, 0x1c37}, {0x1c3b, 0x1c49}, {0x1c4d, 0x1c7f}, {0x1cc0, 0x1cc7}, {0x1cd0, 0x1cf6}, {0x1d00, 0x1de6}, {0x1dfc, 0x1f15}, {0x1f18, 0x1f1d}, {0x1f20, 0x1f45}, {0x1f48, 0x1f4d}, {0x1f50, 0x1f57}, {0x1f5f, 0x1f7d}, {0x1f80, 0x1fb4}, {0x1fb6, 0x1fc4}, {0x1fc6, 0x1fd3}, {0x1fd6, 0x1fdb}, {0x1fdd, 0x1fef}, {0x1ff2, 0x1ff4}, {0x1ff6, 0x1ffe}, {0x2010, 0x2027}, {0x2030, 0x205e}, {0x2074, 0x208e}, {0x2090, 0x209c}, {0x20a0, 0x20ba}, {0x20d0, 0x20f0}, {0x2100, 0x2189}, {0x2190, 0x23f3}, {0x2400, 0x2426}, {0x2440, 0x244a}, {0x2460, 0x26ff}, {0x2701, 0x2b4c}, {0x2b50, 0x2b59}, {0x2c00, 0x2c2e}, {0x2c30, 0x2c5e}, {0x2c60, 0x2cf3}, {0x2cf9, 0x2d25}, {0x2d30, 0x2d67}, {0x2d7f, 0x2d96}, {0x2da0, 0x2da6}, {0x2da8, 0x2dae}, {0x2db0, 0x2db6}, {0x2db8, 0x2dbe}, {0x2dc0, 0x2dc6}, {0x2dc8, 0x2dce}, {0x2dd0, 0x2dd6}, {0x2dd8, 0x2dde}, {0x2de0, 0x2e3b}, {0x2e80, 0x2e99}, {0x2e9b, 0x2ef3}, {0x2f00, 0x2fd5}, {0x2ff0, 0x2ffb}, {0x3001, 0x303f}, {0x3041, 0x3096}, {0x3099, 0x30ff}, {0x3105, 0x312d}, {0x3131, 0x318e}, {0x3190, 0x31ba}, {0x31c0, 0x31e3}, {0x31f0, 0x321e}, {0x3220, 0x32fe}, {0x3300, 0x4db5}, {0x4dc0, 0x9fcc}, {0xa000, 0xa48c}, {0xa490, 0xa4c6}, {0xa4d0, 0xa62b}, {0xa640, 0xa697}, {0xa69f, 0xa6f7}, {0xa700, 0xa78e}, {0xa790, 0xa793}, {0xa7a0, 0xa7aa}, {0xa7f8, 0xa82b}, {0xa830, 0xa839}, {0xa840, 0xa877}, {0xa880, 0xa8c4}, {0xa8ce, 0xa8d9}, {0xa8e0, 0xa8fb}, {0xa900, 0xa953}, {0xa95f, 0xa97c}, {0xa980, 0xa9cd}, {0xa9cf, 0xa9d9}, {0xaa00, 0xaa36}, {0xaa40, 0xaa4d}, {0xaa50, 0xaa59}, {0xaa5c, 0xaa7b}, {0xaa80, 0xaac2}, {0xaadb, 0xaaf6}, {0xab01, 0xab06}, {0xab09, 0xab0e}, {0xab11, 0xab16}, {0xab20, 0xab26}, {0xab28, 0xab2e}, {0xabc0, 0xabed}, {0xabf0, 0xabf9}, {0xac00, 0xd7a3}, {0xd7b0, 0xd7c6}, {0xd7cb, 0xd7fb}, {0xf900, 0xfa6d}, {0xfa70, 0xfad9}, {0xfb00, 0xfb06}, {0xfb13, 0xfb17}, {0xfb1d, 0xfb36}, {0xfb38, 0xfb3c}, {0xfb46, 0xfbc1}, {0xfbd3, 0xfd3f}, {0xfd50, 0xfd8f}, {0xfd92, 0xfdc7}, {0xfdf0, 0xfdfd}, {0xfe00, 0xfe19}, {0xfe20, 0xfe26}, {0xfe30, 0xfe52}, {0xfe54, 0xfe66}, {0xfe68, 0xfe6b}, {0xfe70, 0xfe74}, {0xfe76, 0xfefc}, {0xff01, 0xffbe}, {0xffc2, 0xffc7}, {0xffca, 0xffcf}, {0xffd2, 0xffd7}, {0xffda, 0xffdc}, {0xffe0, 0xffe6}, {0xffe8, 0xffee} #if TCL_UTF_MAX > 4 ,{0x10000, 0x1000b}, {0x1000d, 0x10026}, {0x10028, 0x1003a}, {0x1003f, 0x1004d}, {0x10050, 0x1005d}, {0x10080, 0x100fa}, {0x10100, 0x10102}, {0x10107, 0x10133}, {0x10137, 0x1018a}, {0x10190, 0x1019b}, {0x101d0, 0x101fd}, {0x10280, 0x1029c}, {0x102a0, 0x102d0}, {0x10300, 0x1031e}, {0x10320, 0x10323}, {0x10330, 0x1034a}, {0x10380, 0x1039d}, {0x1039f, 0x103c3}, {0x103c8, 0x103d5}, {0x10400, 0x1049d}, {0x104a0, 0x104a9}, {0x10800, 0x10805}, {0x1080a, 0x10835}, {0x1083f, 0x10855}, {0x10857, 0x1085f}, {0x10900, 0x1091b}, {0x1091f, 0x10939}, {0x10980, 0x109b7}, {0x10a00, 0x10a03}, {0x10a0c, 0x10a13}, {0x10a15, 0x10a17}, {0x10a19, 0x10a33}, {0x10a38, 0x10a3a}, {0x10a3f, 0x10a47}, {0x10a50, 0x10a58}, {0x10a60, 0x10a7f}, {0x10b00, 0x10b35}, {0x10b39, 0x10b55}, {0x10b58, 0x10b72}, {0x10b78, 0x10b7f}, {0x10c00, 0x10c48}, {0x10e60, 0x10e7e}, {0x11000, 0x1104d}, {0x11052, 0x1106f}, {0x11080, 0x110bc}, {0x110be, 0x110c1}, {0x110d0, 0x110e8}, {0x110f0, 0x110f9}, {0x11100, 0x11134}, {0x11136, 0x11143}, {0x11180, 0x111c8}, {0x111d0, 0x111d9}, {0x11680, 0x116b7}, {0x116c0, 0x116c9}, {0x12000, 0x1236e}, {0x12400, 0x12462}, {0x12470, 0x12473}, {0x13000, 0x1342e}, {0x16800, 0x16a38}, {0x16f00, 0x16f44}, {0x16f50, 0x16f7e}, {0x16f8f, 0x16f9f}, {0x1d000, 0x1d0f5}, {0x1d100, 0x1d126}, {0x1d129, 0x1d172}, {0x1d17b, 0x1d1dd}, {0x1d200, 0x1d245}, {0x1d300, 0x1d356}, {0x1d360, 0x1d371}, {0x1d400, 0x1d454}, {0x1d456, 0x1d49c}, {0x1d4a9, 0x1d4ac}, {0x1d4ae, 0x1d4b9}, {0x1d4bd, 0x1d4c3}, {0x1d4c5, 0x1d505}, {0x1d507, 0x1d50a}, {0x1d50d, 0x1d514}, {0x1d516, 0x1d51c}, {0x1d51e, 0x1d539}, {0x1d53b, 0x1d53e}, {0x1d540, 0x1d544}, {0x1d54a, 0x1d550}, {0x1d552, 0x1d6a5}, {0x1d6a8, 0x1d7cb}, {0x1d7ce, 0x1d7ff}, {0x1ee00, 0x1ee03}, {0x1ee05, 0x1ee1f}, {0x1ee29, 0x1ee32}, {0x1ee34, 0x1ee37}, {0x1ee4d, 0x1ee4f}, {0x1ee67, 0x1ee6a}, {0x1ee6c, 0x1ee72}, {0x1ee74, 0x1ee77}, {0x1ee79, 0x1ee7c}, {0x1ee80, 0x1ee89}, {0x1ee8b, 0x1ee9b}, {0x1eea1, 0x1eea3}, {0x1eea5, 0x1eea9}, {0x1eeab, 0x1eebb}, {0x1f000, 0x1f02b}, {0x1f030, 0x1f093}, {0x1f0a0, 0x1f0ae}, {0x1f0b1, 0x1f0be}, {0x1f0c1, 0x1f0cf}, {0x1f0d1, 0x1f0df}, {0x1f100, 0x1f10a}, {0x1f110, 0x1f12e}, {0x1f130, 0x1f16b}, {0x1f170, 0x1f19a}, {0x1f1e6, 0x1f202}, {0x1f210, 0x1f23a}, {0x1f240, 0x1f248}, {0x1f300, 0x1f320}, {0x1f330, 0x1f335}, {0x1f337, 0x1f37c}, {0x1f380, 0x1f393}, {0x1f3a0, 0x1f3c4}, {0x1f3c6, 0x1f3ca}, {0x1f3e0, 0x1f3f0}, {0x1f400, 0x1f43e}, {0x1f442, 0x1f4f7}, {0x1f4f9, 0x1f4fc}, {0x1f500, 0x1f53d}, {0x1f540, 0x1f543}, {0x1f550, 0x1f567}, {0x1f5fb, 0x1f640}, {0x1f645, 0x1f64f}, {0x1f680, 0x1f6c5}, {0x1f700, 0x1f773}, {0x20000, 0x2a6d6}, {0x2a700, 0x2b734}, {0x2b740, 0x2b81d}, {0x2f800, 0x2fa1d}, {0xe0100, 0xe01ef} #endif }; #define NUM_GRAPH_RANGE (sizeof(graphRangeTable)/sizeof(crange)) static CONST chr graphCharTable[] = { 0x38c, 0x589, 0x58a, 0x58f, 0x85e, 0x8a0, 0x98f, 0x990, 0x9b2, 0x9c7, 0x9c8, 0x9d7, 0x9dc, 0x9dd, 0xa0f, 0xa10, 0xa32, 0xa33, 0xa35, 0xa36, 0xa38, 0xa39, 0xa3c, 0xa47, 0xa48, 0xa51, 0xa5e, 0xab2, 0xab3, 0xad0, 0xb0f, 0xb10, 0xb32, 0xb33, 0xb47, 0xb48, 0xb56, 0xb57, 0xb5c, 0xb5d, 0xb82, 0xb83, 0xb99, 0xb9a, 0xb9c, 0xb9e, 0xb9f, 0xba3, 0xba4, 0xbd0, 0xbd7, 0xc55, 0xc56, 0xc58, 0xc59, 0xc82, 0xc83, 0xcd5, 0xcd6, 0xcde, 0xcf1, 0xcf2, 0xd02, 0xd03, 0xd57, 0xd82, 0xd83, 0xdbd, 0xdca, 0xdd6, 0xe81, 0xe82, 0xe84, 0xe87, 0xe88, 0xe8a, 0xe8d, 0xea5, 0xea7, 0xeaa, 0xeab, 0xec6, 0x10c7, 0x10cd, 0x1258, 0x12c0, 0x1772, 0x1773, 0x1940, 0x1f59, 0x1f5b, 0x1f5d, 0x2070, 0x2071, 0x2d27, 0x2d2d, 0x2d6f, 0x2d70, 0xa9de, 0xa9df, 0xfb3e, 0xfb40, 0xfb41, 0xfb43, 0xfb44, 0xfffc, 0xfffd #if TCL_UTF_MAX > 4 ,0x1003c, 0x1003d, 0x10808, 0x10837, 0x10838, 0x1083c, 0x1093f, 0x109be, 0x109bf, 0x10a05, 0x10a06, 0x1b000, 0x1b001, 0x1d49e, 0x1d49f, 0x1d4a2, 0x1d4a5, 0x1d4a6, 0x1d4bb, 0x1d546, 0x1ee21, 0x1ee22, 0x1ee24, 0x1ee27, 0x1ee39, 0x1ee3b, 0x1ee42, 0x1ee47, 0x1ee49, 0x1ee4b, 0x1ee51, 0x1ee52, 0x1ee54, 0x1ee57, 0x1ee59, 0x1ee5b, 0x1ee5d, 0x1ee5f, 0x1ee61, 0x1ee62, 0x1ee64, 0x1ee7e, 0x1eef0, 0x1eef1, 0x1f250, 0x1f251, 0x1f440 #endif }; #define NUM_GRAPH_CHAR (sizeof(graphCharTable)/sizeof(chr)) /* * End of auto-generated Unicode character ranges declarations. */ #define CH NOCELT /* - element - map collating-element name to celt ^ static celt element(struct vars *, CONST chr *, CONST chr *); */ static celt element(v, startp, endp) struct vars *v; /* context */ CONST chr *startp; /* points to start of name */ CONST chr *endp; /* points just past end of name */ { CONST struct cname *cn; size_t len; Tcl_DString ds; CONST char *np; /* * Generic: one-chr names stand for themselves. */ assert(startp < endp); len = endp - startp; if (len == 1) { return *startp; } NOTE(REG_ULOCALE); /* * Search table. */ Tcl_DStringInit(&ds); np = Tcl_UniCharToUtfDString(startp, (int)len, &ds); for (cn=cnames; cn->name!=NULL; cn++) { if (strlen(cn->name)==len && strncmp(cn->name, np, len)==0) { break; /* NOTE BREAK OUT */ } } Tcl_DStringFree(&ds); if (cn->name != NULL) { return CHR(cn->code); } /* * Couldn't find it. */ ERR(REG_ECOLLATE); return 0; } /* - range - supply cvec for a range, including legality check ^ static struct cvec *range(struct vars *, celt, celt, int); */ static struct cvec * range(v, a, b, cases) struct vars *v; /* context */ celt a; /* range start */ celt b; /* range end, might equal a */ int cases; /* case-independent? */ { int nchrs; struct cvec *cv; celt c, lc, uc, tc; if (a != b && !before(a, b)) { ERR(REG_ERANGE); return NULL; } if (!cases) { /* easy version */ cv = getcvec(v, 0, 1); NOERRN(); addrange(cv, a, b); return cv; } /* * When case-independent, it's hard to decide when cvec ranges are usable, * so for now at least, we won't try. We allocate enough space for two * case variants plus a little extra for the two title case variants. */ nchrs = (b - a + 1)*2 + 4; cv = getcvec(v, nchrs, 0); NOERRN(); for (c=a; c<=b; c++) { addchr(cv, c); lc = Tcl_UniCharToLower((chr)c); uc = Tcl_UniCharToUpper((chr)c); tc = Tcl_UniCharToTitle((chr)c); if (c != lc) { addchr(cv, lc); } if (c != uc) { addchr(cv, uc); } if (c != tc && tc != uc) { addchr(cv, tc); } } return cv; } /* - before - is celt x before celt y, for purposes of range legality? ^ static int before(celt, celt); */ static int /* predicate */ before(x, y) celt x, y; /* collating elements */ { if (x < y) { return 1; } return 0; } /* - eclass - supply cvec for an equivalence class * Must include case counterparts on request. ^ static struct cvec *eclass(struct vars *, celt, int); */ static struct cvec * eclass(v, c, cases) struct vars *v; /* context */ celt c; /* Collating element representing * the equivalence class. */ int cases; /* all cases? */ { struct cvec *cv; /* * Crude fake equivalence class for testing. */ if ((v->cflags®_FAKE) && c == 'x') { cv = getcvec(v, 4, 0); addchr(cv, (chr)'x'); addchr(cv, (chr)'y'); if (cases) { addchr(cv, (chr)'X'); addchr(cv, (chr)'Y'); } return cv; } /* * Otherwise, none. */ if (cases) { return allcases(v, c); } cv = getcvec(v, 1, 0); assert(cv != NULL); addchr(cv, (chr)c); return cv; } /* - cclass - supply cvec for a character class * Must include case counterparts on request. ^ static struct cvec *cclass(struct vars *, CONST chr *, CONST chr *, int); */ static struct cvec * cclass(v, startp, endp, cases) struct vars *v; /* context */ CONST chr *startp; /* where the name starts */ CONST chr *endp; /* just past the end of the name */ int cases; /* case-independent? */ { size_t len; struct cvec *cv = NULL; Tcl_DString ds; CONST char *np; CONST char *CONST *namePtr; int i, index; /* * The following arrays define the valid character class names. */ static CONST char *CONST classNames[] = { "alnum", "alpha", "ascii", "blank", "cntrl", "digit", "graph", "lower", "print", "punct", "space", "upper", "xdigit", NULL }; enum classes { CC_ALNUM, CC_ALPHA, CC_ASCII, CC_BLANK, CC_CNTRL, CC_DIGIT, CC_GRAPH, CC_LOWER, CC_PRINT, CC_PUNCT, CC_SPACE, CC_UPPER, CC_XDIGIT }; /* * Extract the class name */ len = endp - startp; Tcl_DStringInit(&ds); np = Tcl_UniCharToUtfDString(startp, (int)len, &ds); /* * Map the name to the corresponding enumerated value. */ index = -1; for (namePtr=classNames,i=0 ; *namePtr!=NULL ; namePtr++,i++) { if ((strlen(*namePtr) == len) && (strncmp(*namePtr, np, len) == 0)) { index = i; break; } } Tcl_DStringFree(&ds); if (index == -1) { ERR(REG_ECTYPE); return NULL; } /* * Remap lower and upper to alpha if the match is case insensitive. */ if (cases && ((index == CC_LOWER) || (index == CC_UPPER))) { index = CC_ALNUM; } /* * Now compute the character class contents. */ switch((enum classes) index) { case CC_ALNUM: cv = getcvec(v, NUM_ALPHA_CHAR, NUM_DIGIT_RANGE + NUM_ALPHA_RANGE); if (cv) { for (i=0 ; (size_t)i 0; len--, x++, y++) { if ((*x!=*y) && (Tcl_UniCharToLower(*x) != Tcl_UniCharToLower(*y))) { return 1; } } return 0; } /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ tcl8.4.20/generic/tclUniData.c0000644003604700454610000030325412052456744014535 0ustar dgp771div/* * tclUniData.c -- * * Declarations of Unicode character information tables. This file is * automatically generated by the tools/uniParse.tcl script. Do not * modify this file by hand. * * Copyright (c) 1998 by Scriptics Corporation. * All rights reserved. */ /* * A 16-bit Unicode character is split into two parts in order to index * into the following tables. The lower OFFSET_BITS comprise an offset * into a page of characters. The upper bits comprise the page number. */ #define OFFSET_BITS 5 /* * The pageMap is indexed by page number and returns an alternate page number * that identifies a unique page of characters. Many Unicode characters map * to the same alternate page number. */ static CONST unsigned short pageMap[] = { 0, 32, 64, 96, 0, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 224, 480, 512, 544, 576, 608, 640, 672, 704, 704, 736, 768, 800, 832, 864, 896, 928, 960, 992, 224, 1024, 224, 1056, 224, 224, 1088, 1120, 1152, 1184, 1216, 1248, 1280, 1312, 1344, 1376, 1408, 1344, 1344, 1440, 1472, 1504, 1536, 1568, 1344, 1344, 1600, 1632, 1664, 1696, 1728, 1760, 1792, 1792, 1824, 1792, 1856, 1888, 1920, 1952, 1984, 2016, 2048, 2080, 2112, 2144, 2176, 2208, 2240, 2272, 2304, 2336, 2368, 2016, 2400, 2432, 2464, 2496, 2528, 2560, 2592, 2624, 2656, 2688, 2720, 2752, 2784, 2816, 2848, 2752, 2880, 2912, 2944, 2976, 3008, 3040, 3072, 3104, 3136, 3168, 1792, 3200, 3232, 3264, 1792, 3296, 3328, 3360, 3392, 3424, 3456, 3488, 1792, 1344, 3520, 3552, 3584, 3616, 3648, 3680, 3712, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 3744, 1344, 3776, 3808, 3840, 1344, 3872, 1344, 3904, 3936, 3968, 1344, 1344, 4000, 4032, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 4064, 4096, 1344, 1344, 4128, 4160, 4192, 4224, 4256, 1344, 4288, 4320, 4352, 4384, 1344, 4416, 4448, 1344, 4480, 1344, 4512, 4544, 4576, 4608, 4640, 1344, 4672, 4704, 4736, 4768, 1344, 4800, 4832, 4864, 4896, 1792, 1792, 4928, 4960, 4992, 5024, 5056, 5088, 1344, 5120, 1344, 5152, 5184, 5216, 1792, 1792, 5248, 5280, 5312, 5344, 5376, 5408, 5440, 5376, 704, 5472, 224, 224, 224, 224, 5504, 224, 224, 224, 5536, 5568, 5600, 5632, 5664, 5696, 5728, 5760, 5792, 5824, 5856, 5888, 5920, 5952, 5984, 6016, 6048, 6080, 6112, 6144, 6176, 6208, 6240, 6272, 6304, 6304, 6304, 6304, 6304, 6304, 6304, 6304, 6336, 6368, 4736, 6400, 6432, 6464, 6496, 6528, 4736, 6560, 6592, 6624, 6656, 6688, 6720, 6752, 4736, 4736, 4736, 4736, 4736, 6784, 6816, 6848, 4736, 4736, 4736, 6880, 4736, 4736, 4736, 4736, 6912, 4736, 4736, 6944, 6976, 4736, 7008, 7040, 4736, 4736, 4736, 4736, 4736, 4736, 4736, 4736, 6304, 6304, 6304, 6304, 7072, 6304, 7104, 7136, 6304, 6304, 6304, 6304, 6304, 6304, 6304, 6304, 4736, 7168, 7200, 1792, 1792, 1792, 1792, 1792, 7232, 7264, 7296, 7328, 224, 224, 224, 7360, 7392, 7424, 1344, 7456, 7488, 7520, 7520, 704, 7552, 7584, 1792, 1792, 7616, 4736, 4736, 7648, 4736, 4736, 4736, 4736, 4736, 4736, 7680, 7712, 7744, 7776, 3104, 1344, 7808, 4032, 1344, 7840, 7872, 7904, 1344, 1344, 7936, 7968, 4736, 8000, 8032, 8064, 8096, 4736, 8064, 8128, 4736, 8032, 4736, 4736, 4736, 4736, 4736, 4736, 4736, 4736, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 4512, 4736, 4736, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 8160, 1792, 8192, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 8224, 4736, 8256, 5216, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 8288, 8320, 224, 8352, 8384, 1344, 1344, 8416, 8448, 8480, 224, 8512, 8544, 8576, 1792, 8608, 8640, 8672, 1344, 8704, 8736, 8768, 8800, 8832, 1632, 8864, 8896, 4544, 1888, 8928, 8960, 1792, 1344, 8992, 9024, 9056, 1344, 9088, 9120, 9152, 9184, 9216, 1792, 1792, 1792, 1792, 1344, 9248, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 9280, 9312, 9344, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9376, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 9408, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 9440, 1344, 1344, 9472, 1792, 9504, 9536, 9568, 1344, 1344, 9600, 9632, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 9664, 9696, 1344, 9728, 1344, 9760, 9792, 9824, 9856, 9888, 9920, 1344, 1344, 1344, 9952, 9984, 64, 10016, 10048, 10080, 10112, 10144, 10176 #if TCL_UTF_MAX > 3 ,10208, 10240, 10272, 1792, 1344, 1344, 1344, 7968, 10304, 10336, 10368, 10400, 10432, 1792, 10464, 10496, 1792, 1792, 1792, 1792, 4544, 1344, 10528, 1792, 10112, 10560, 10592, 1792, 10624, 1344, 10656, 1792, 10688, 10720, 10752, 1344, 10784, 10816, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 10848, 10880, 10912, 1792, 1792, 1792, 1792, 1792, 10944, 10976, 1792, 1792, 1344, 11008, 1792, 1792, 11040, 11072, 11104, 11136, 1792, 1792, 1792, 1792, 1344, 11168, 11200, 11232, 1792, 1792, 1792, 1792, 1344, 1344, 11264, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 11296, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 11328, 11360, 11392, 11424, 5056, 11456, 11488, 11520, 11552, 11584, 11616, 1792, 5056, 11648, 11680, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1344, 11712, 10816, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 11744, 1792, 1792, 1792, 1792, 10368, 10368, 10368, 11776, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 11744, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 11808, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1344, 1344, 11840, 11872, 11904, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 11936, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 4736, 4736, 4736, 4736, 4736, 4736, 4736, 7680, 4736, 11968, 4736, 12000, 12032, 12064, 12096, 1792, 4736, 4736, 12128, 1792, 1792, 1792, 1792, 1792, 4736, 4736, 12160, 12192, 1792, 1792, 1792, 1792, 12224, 12256, 12288, 12320, 12352, 12384, 12416, 12448, 12480, 12512, 12544, 12576, 12608, 12224, 12256, 12640, 12320, 12672, 12704, 12736, 12448, 12768, 12800, 12832, 12864, 12896, 12928, 12960, 12992, 13024, 13056, 13088, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 13120, 13152, 13184, 13216, 13248, 13280, 1792, 13312, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 4736, 13344, 4736, 4736, 7648, 13376, 13408, 1792, 13440, 13472, 4736, 13344, 13504, 1792, 1792, 13536, 13568, 13504, 13600, 1792, 1792, 1792, 1792, 1792, 4736, 13632, 4736, 13664, 7648, 4736, 13696, 13728, 4736, 8032, 13760, 4736, 4736, 4736, 4736, 13792, 4736, 12096, 13824, 13856, 1792, 1792, 1792, 13888, 4736, 4736, 13920, 1792, 4736, 4736, 13952, 1792, 4736, 4736, 4736, 7648, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 7488, 1792, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 4000, 1344, 1344, 1344, 1344, 1344, 1344, 10784, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 10784 #endif /* TCL_UTF_MAX > 3 */ }; /* * The groupMap is indexed by combining the alternate page number with * the page offset and returns a group number that identifies a unique * set of character attributes. */ static CONST unsigned char groupMap[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 3, 3, 4, 3, 3, 3, 5, 6, 3, 7, 3, 8, 3, 3, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 3, 3, 7, 7, 7, 3, 3, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 5, 3, 6, 11, 12, 11, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 5, 7, 6, 7, 1, 2, 3, 4, 4, 4, 4, 14, 3, 11, 14, 15, 16, 7, 17, 14, 11, 14, 7, 18, 18, 11, 19, 3, 3, 11, 18, 15, 20, 18, 18, 18, 3, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 7, 10, 10, 10, 10, 10, 10, 10, 21, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 7, 13, 13, 13, 13, 13, 13, 13, 22, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 25, 26, 23, 24, 23, 24, 23, 24, 21, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 21, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 27, 23, 24, 23, 24, 23, 24, 28, 29, 30, 23, 24, 23, 24, 31, 23, 24, 32, 32, 23, 24, 21, 33, 34, 35, 23, 24, 32, 36, 37, 38, 39, 23, 24, 40, 21, 38, 41, 42, 43, 23, 24, 23, 24, 23, 24, 44, 23, 24, 44, 21, 21, 23, 24, 44, 23, 24, 45, 45, 23, 24, 23, 24, 46, 23, 24, 21, 15, 23, 24, 21, 47, 15, 15, 15, 15, 48, 49, 50, 48, 49, 50, 48, 49, 50, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 51, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 21, 48, 49, 50, 23, 24, 52, 53, 23, 24, 23, 24, 23, 24, 23, 24, 54, 21, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 21, 21, 21, 21, 21, 21, 55, 23, 24, 56, 57, 58, 58, 23, 24, 59, 60, 61, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 62, 63, 64, 65, 66, 21, 67, 67, 21, 68, 21, 69, 21, 21, 21, 21, 67, 21, 21, 70, 21, 71, 72, 21, 73, 74, 21, 75, 21, 21, 21, 74, 21, 76, 77, 21, 21, 78, 21, 21, 21, 21, 21, 21, 21, 79, 21, 21, 80, 21, 21, 80, 21, 21, 21, 21, 80, 81, 82, 82, 83, 21, 21, 21, 21, 21, 84, 21, 15, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 11, 11, 11, 11, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 85, 85, 85, 85, 85, 11, 11, 11, 11, 11, 11, 11, 85, 11, 85, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 87, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 23, 24, 23, 24, 85, 11, 23, 24, 0, 0, 85, 42, 42, 42, 3, 0, 0, 0, 0, 0, 11, 11, 88, 3, 89, 89, 89, 0, 90, 0, 91, 91, 21, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 10, 10, 10, 10, 92, 93, 93, 93, 21, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 94, 13, 13, 13, 13, 13, 13, 13, 13, 13, 95, 96, 96, 97, 98, 99, 100, 100, 100, 101, 102, 103, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 104, 105, 106, 21, 107, 108, 7, 23, 24, 109, 23, 24, 21, 54, 54, 54, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 23, 24, 14, 86, 86, 86, 86, 86, 111, 111, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 112, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 113, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 0, 0, 85, 3, 3, 3, 3, 3, 3, 0, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 21, 0, 3, 8, 0, 0, 0, 0, 4, 0, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 8, 86, 3, 86, 86, 3, 86, 86, 3, 86, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 15, 15, 15, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 17, 17, 0, 7, 7, 7, 3, 3, 4, 3, 3, 14, 14, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 3, 0, 0, 3, 3, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 85, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 3, 3, 3, 3, 15, 15, 86, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 3, 15, 86, 86, 86, 86, 86, 86, 86, 17, 14, 86, 86, 86, 86, 86, 86, 85, 85, 86, 86, 14, 86, 86, 86, 86, 15, 15, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 15, 15, 15, 14, 14, 15, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 17, 15, 86, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 86, 86, 86, 86, 86, 86, 86, 86, 86, 85, 85, 14, 3, 3, 3, 85, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 86, 86, 86, 86, 85, 86, 86, 86, 86, 86, 86, 86, 86, 86, 85, 86, 86, 86, 85, 86, 86, 86, 86, 86, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 86, 86, 86, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 0, 86, 86, 86, 116, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 86, 116, 86, 15, 116, 116, 116, 86, 86, 86, 86, 86, 86, 86, 86, 116, 116, 116, 116, 86, 116, 116, 15, 86, 86, 86, 86, 86, 86, 86, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 86, 86, 3, 3, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 3, 85, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 0, 86, 116, 116, 0, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 15, 15, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 0, 15, 0, 0, 0, 15, 15, 15, 15, 0, 0, 86, 15, 116, 116, 116, 86, 86, 86, 86, 0, 0, 116, 116, 0, 0, 116, 116, 86, 15, 0, 0, 0, 0, 0, 0, 0, 0, 116, 0, 0, 0, 0, 15, 15, 0, 15, 15, 15, 86, 86, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 15, 15, 4, 4, 18, 18, 18, 18, 18, 18, 14, 4, 0, 0, 0, 0, 0, 86, 86, 116, 0, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 15, 15, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 0, 15, 15, 0, 15, 15, 0, 0, 86, 0, 116, 116, 116, 86, 86, 0, 0, 0, 0, 86, 86, 0, 0, 86, 86, 86, 0, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 0, 15, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 86, 86, 15, 15, 15, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 86, 86, 116, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 0, 15, 15, 15, 15, 15, 0, 0, 86, 15, 116, 116, 116, 86, 86, 86, 86, 86, 0, 86, 86, 116, 0, 116, 116, 86, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 86, 86, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 0, 15, 15, 15, 15, 15, 0, 0, 86, 15, 116, 86, 116, 86, 86, 86, 86, 0, 0, 116, 116, 0, 0, 116, 116, 86, 0, 0, 0, 0, 0, 0, 0, 0, 86, 116, 0, 0, 0, 0, 15, 15, 0, 15, 15, 15, 86, 86, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 14, 15, 18, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 86, 15, 0, 15, 15, 15, 15, 15, 15, 0, 0, 0, 15, 15, 15, 0, 15, 15, 15, 15, 0, 0, 0, 15, 15, 0, 15, 0, 15, 15, 0, 0, 0, 15, 15, 0, 0, 0, 15, 15, 15, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 116, 116, 86, 116, 116, 0, 0, 0, 116, 116, 116, 0, 116, 116, 116, 86, 0, 0, 15, 0, 0, 0, 0, 0, 0, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 18, 18, 18, 14, 14, 14, 14, 14, 14, 4, 14, 0, 0, 0, 0, 0, 0, 116, 116, 116, 0, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 0, 0, 0, 15, 86, 86, 86, 116, 116, 116, 116, 0, 86, 86, 86, 0, 86, 86, 86, 86, 0, 0, 0, 0, 0, 0, 0, 86, 86, 0, 15, 15, 0, 0, 0, 0, 0, 0, 15, 15, 86, 86, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 18, 18, 18, 18, 14, 0, 0, 116, 116, 0, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 0, 0, 86, 15, 116, 86, 116, 116, 116, 116, 116, 0, 86, 116, 116, 0, 116, 116, 86, 86, 0, 0, 0, 0, 0, 0, 0, 116, 116, 0, 0, 0, 0, 0, 0, 0, 15, 0, 15, 15, 86, 86, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 15, 116, 116, 116, 86, 86, 86, 86, 0, 116, 116, 116, 0, 116, 116, 116, 86, 15, 0, 0, 0, 0, 0, 0, 0, 0, 116, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 86, 86, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 18, 18, 18, 18, 18, 18, 0, 0, 0, 14, 15, 15, 15, 15, 15, 15, 0, 0, 116, 116, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 0, 0, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 86, 0, 0, 0, 0, 116, 116, 116, 86, 86, 86, 0, 86, 0, 116, 116, 116, 116, 116, 116, 116, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 116, 116, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 86, 15, 15, 86, 86, 86, 86, 86, 86, 86, 0, 0, 0, 0, 4, 15, 15, 15, 15, 15, 15, 85, 86, 86, 86, 86, 86, 86, 86, 86, 3, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 3, 3, 0, 0, 0, 0, 0, 15, 15, 0, 15, 0, 0, 15, 15, 0, 15, 0, 0, 15, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 0, 15, 0, 15, 0, 0, 15, 15, 0, 15, 15, 15, 15, 86, 15, 15, 86, 86, 86, 86, 86, 86, 0, 86, 86, 15, 0, 0, 15, 15, 15, 15, 15, 0, 85, 0, 86, 86, 86, 86, 86, 86, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 15, 15, 15, 15, 15, 14, 14, 14, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 14, 3, 14, 14, 14, 86, 86, 14, 14, 14, 14, 14, 14, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 14, 86, 14, 86, 14, 86, 5, 6, 5, 6, 116, 116, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 116, 86, 86, 86, 86, 86, 3, 86, 86, 15, 15, 15, 15, 15, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 0, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 0, 14, 14, 14, 14, 14, 14, 14, 14, 86, 14, 14, 14, 14, 14, 14, 0, 14, 14, 3, 3, 3, 3, 3, 14, 14, 14, 14, 3, 3, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 116, 116, 86, 86, 86, 86, 116, 86, 86, 86, 86, 86, 86, 116, 86, 86, 116, 116, 86, 86, 15, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 3, 3, 3, 3, 3, 3, 15, 15, 15, 15, 15, 15, 116, 116, 86, 86, 15, 15, 15, 15, 86, 86, 86, 15, 116, 116, 116, 15, 15, 116, 116, 116, 116, 116, 116, 116, 15, 15, 15, 86, 86, 86, 86, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 86, 116, 116, 86, 86, 116, 116, 116, 116, 116, 116, 86, 15, 116, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 116, 116, 116, 86, 14, 14, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 0, 117, 0, 0, 0, 0, 0, 117, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 3, 85, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 0, 0, 15, 15, 15, 15, 15, 15, 15, 0, 15, 0, 15, 15, 15, 15, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 0, 0, 15, 15, 15, 15, 15, 15, 15, 0, 15, 0, 15, 15, 15, 15, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 86, 86, 86, 3, 3, 3, 3, 3, 3, 3, 3, 3, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 3, 3, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 2, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 5, 6, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 3, 3, 3, 118, 118, 118, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 86, 86, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 86, 86, 86, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 86, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 0, 86, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 86, 86, 116, 86, 86, 86, 86, 86, 86, 86, 116, 116, 116, 116, 116, 116, 116, 116, 86, 116, 116, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 3, 3, 3, 85, 3, 3, 3, 4, 15, 86, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 8, 3, 3, 3, 3, 86, 86, 86, 2, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 15, 15, 15, 85, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 86, 15, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 86, 86, 86, 116, 116, 116, 116, 86, 86, 116, 116, 116, 0, 0, 0, 0, 116, 116, 86, 116, 116, 116, 116, 116, 116, 86, 86, 86, 0, 0, 0, 0, 14, 0, 0, 0, 3, 3, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 15, 15, 15, 15, 15, 15, 15, 116, 116, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 18, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 86, 86, 116, 116, 116, 0, 0, 3, 3, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 116, 86, 116, 86, 86, 86, 86, 86, 86, 86, 0, 86, 116, 86, 116, 116, 86, 86, 86, 86, 86, 86, 86, 86, 116, 116, 116, 116, 116, 116, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 0, 0, 86, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 85, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 86, 86, 86, 86, 116, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 86, 116, 86, 86, 86, 86, 86, 116, 86, 116, 116, 116, 116, 116, 86, 116, 116, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 3, 3, 3, 3, 3, 3, 3, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 86, 86, 86, 86, 86, 86, 86, 86, 86, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 86, 86, 116, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 116, 86, 86, 86, 86, 116, 116, 86, 86, 116, 86, 116, 116, 15, 15, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 86, 116, 86, 86, 116, 116, 116, 86, 116, 86, 86, 86, 116, 116, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 15, 15, 15, 15, 116, 116, 116, 116, 116, 116, 116, 116, 86, 86, 86, 86, 86, 86, 86, 86, 116, 116, 86, 86, 0, 0, 0, 3, 3, 3, 3, 3, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 15, 15, 15, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 85, 85, 85, 85, 85, 85, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 86, 86, 86, 3, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 116, 86, 86, 86, 86, 86, 86, 86, 15, 15, 15, 15, 86, 15, 15, 15, 15, 116, 116, 86, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 85, 119, 21, 21, 21, 120, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 85, 85, 85, 85, 85, 86, 86, 86, 86, 86, 86, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 86, 86, 86, 86, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 21, 21, 21, 21, 21, 121, 21, 21, 122, 21, 123, 123, 123, 123, 123, 123, 123, 123, 124, 124, 124, 124, 124, 124, 124, 124, 123, 123, 123, 123, 123, 123, 0, 0, 124, 124, 124, 124, 124, 124, 0, 0, 123, 123, 123, 123, 123, 123, 123, 123, 124, 124, 124, 124, 124, 124, 124, 124, 123, 123, 123, 123, 123, 123, 123, 123, 124, 124, 124, 124, 124, 124, 124, 124, 123, 123, 123, 123, 123, 123, 0, 0, 124, 124, 124, 124, 124, 124, 0, 0, 21, 123, 21, 123, 21, 123, 21, 123, 0, 124, 0, 124, 0, 124, 0, 124, 123, 123, 123, 123, 123, 123, 123, 123, 124, 124, 124, 124, 124, 124, 124, 124, 125, 125, 126, 126, 126, 126, 127, 127, 128, 128, 129, 129, 130, 130, 0, 0, 123, 123, 123, 123, 123, 123, 123, 123, 131, 131, 131, 131, 131, 131, 131, 131, 123, 123, 123, 123, 123, 123, 123, 123, 131, 131, 131, 131, 131, 131, 131, 131, 123, 123, 123, 123, 123, 123, 123, 123, 131, 131, 131, 131, 131, 131, 131, 131, 123, 123, 21, 132, 21, 0, 21, 21, 124, 124, 133, 133, 134, 11, 135, 11, 11, 11, 21, 132, 21, 0, 21, 21, 136, 136, 136, 136, 134, 11, 11, 11, 123, 123, 21, 21, 0, 0, 21, 21, 124, 124, 137, 137, 0, 11, 11, 11, 123, 123, 21, 21, 21, 106, 21, 21, 124, 124, 138, 138, 109, 11, 11, 11, 0, 0, 21, 132, 21, 0, 21, 21, 139, 139, 140, 140, 134, 11, 11, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 17, 17, 17, 17, 17, 8, 8, 8, 8, 8, 8, 3, 3, 16, 20, 5, 16, 16, 20, 5, 16, 3, 3, 3, 3, 3, 3, 3, 3, 141, 142, 17, 17, 17, 17, 17, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 16, 20, 3, 3, 3, 3, 12, 12, 3, 3, 3, 7, 5, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 3, 12, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 17, 17, 17, 17, 17, 0, 0, 0, 0, 0, 17, 17, 17, 17, 17, 17, 18, 85, 0, 0, 18, 18, 18, 18, 18, 18, 7, 7, 7, 5, 6, 85, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 7, 7, 7, 5, 6, 0, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 111, 111, 111, 111, 86, 111, 111, 111, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 100, 14, 14, 14, 14, 100, 14, 14, 21, 100, 100, 100, 21, 21, 100, 100, 100, 21, 14, 100, 14, 14, 7, 100, 100, 100, 100, 100, 14, 14, 14, 14, 14, 14, 100, 14, 143, 14, 100, 14, 144, 145, 100, 100, 14, 21, 100, 100, 146, 100, 21, 15, 15, 15, 15, 21, 14, 14, 21, 21, 100, 100, 7, 7, 7, 7, 7, 100, 21, 21, 21, 21, 14, 7, 14, 14, 147, 14, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 118, 118, 118, 23, 24, 118, 118, 118, 118, 18, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 14, 14, 14, 14, 14, 7, 7, 14, 14, 14, 14, 7, 14, 14, 7, 14, 14, 7, 14, 14, 14, 14, 14, 14, 14, 7, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 7, 7, 14, 14, 7, 14, 7, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 14, 14, 14, 14, 14, 14, 14, 14, 7, 7, 7, 7, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 7, 7, 14, 14, 14, 14, 14, 14, 14, 5, 6, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 7, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 7, 7, 7, 7, 7, 7, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 7, 14, 14, 14, 14, 14, 14, 14, 14, 14, 7, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 7, 7, 7, 7, 7, 7, 7, 7, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 7, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 7, 7, 7, 7, 7, 5, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 5, 6, 5, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 5, 6, 7, 7, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 14, 14, 7, 7, 7, 7, 7, 7, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 0, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 0, 23, 24, 152, 153, 154, 155, 156, 23, 24, 23, 24, 23, 24, 157, 158, 159, 160, 21, 23, 24, 21, 23, 24, 21, 21, 21, 21, 21, 85, 85, 161, 161, 23, 24, 23, 24, 21, 14, 14, 14, 14, 14, 14, 23, 24, 23, 24, 86, 86, 86, 23, 24, 0, 0, 0, 0, 0, 3, 3, 3, 3, 18, 3, 3, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 0, 162, 0, 0, 0, 0, 0, 162, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 85, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 86, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 0, 3, 3, 16, 20, 16, 20, 3, 3, 3, 16, 20, 3, 16, 20, 3, 3, 3, 3, 3, 3, 3, 3, 3, 8, 3, 3, 8, 3, 16, 20, 3, 3, 16, 20, 5, 6, 5, 6, 5, 6, 5, 6, 3, 3, 3, 3, 3, 85, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 8, 8, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 2, 3, 3, 3, 14, 85, 15, 118, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 14, 14, 5, 6, 5, 6, 5, 6, 5, 6, 8, 5, 6, 6, 14, 118, 118, 118, 118, 118, 118, 118, 118, 118, 86, 86, 86, 86, 116, 116, 8, 85, 85, 85, 85, 85, 14, 14, 118, 118, 118, 85, 15, 3, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 86, 86, 11, 11, 85, 85, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 3, 85, 85, 85, 15, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 14, 14, 18, 18, 18, 18, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 18, 18, 18, 18, 18, 18, 18, 18, 14, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 85, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 85, 3, 3, 3, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 15, 86, 111, 111, 111, 3, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 3, 85, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 0, 0, 0, 0, 0, 0, 0, 86, 15, 15, 15, 15, 15, 15, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 86, 86, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 85, 85, 85, 85, 85, 85, 85, 85, 85, 11, 11, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 21, 21, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 85, 21, 21, 21, 21, 21, 21, 21, 21, 23, 24, 23, 24, 163, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 85, 11, 11, 23, 24, 164, 21, 0, 23, 24, 23, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 21, 15, 15, 15, 15, 15, 15, 15, 86, 15, 15, 15, 86, 15, 15, 15, 15, 86, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 116, 116, 86, 86, 116, 14, 14, 14, 14, 0, 0, 0, 0, 18, 18, 18, 18, 18, 18, 14, 14, 4, 14, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 116, 116, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 15, 15, 15, 15, 15, 15, 3, 3, 3, 15, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 86, 86, 86, 86, 86, 86, 86, 86, 3, 3, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 116, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 86, 116, 116, 86, 86, 86, 86, 116, 116, 86, 116, 116, 116, 116, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 85, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 3, 3, 15, 15, 15, 15, 15, 15, 15, 15, 15, 86, 86, 86, 86, 86, 86, 116, 116, 86, 86, 116, 116, 86, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 86, 15, 15, 15, 15, 15, 15, 15, 15, 86, 116, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 3, 3, 3, 3, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 85, 15, 15, 15, 15, 15, 15, 14, 14, 14, 15, 116, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 86, 15, 86, 86, 86, 15, 15, 86, 86, 15, 15, 15, 15, 15, 86, 86, 15, 86, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 85, 3, 3, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 116, 86, 86, 116, 116, 3, 3, 15, 85, 85, 116, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 0, 0, 15, 15, 15, 15, 15, 15, 0, 0, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 116, 116, 86, 116, 116, 86, 116, 116, 3, 116, 86, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 21, 21, 21, 21, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21, 21, 21, 21, 0, 0, 0, 0, 0, 15, 86, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 7, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 0, 15, 0, 15, 15, 0, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 4, 14, 0, 0, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 3, 3, 3, 3, 3, 3, 3, 5, 6, 3, 0, 0, 0, 0, 0, 0, 86, 86, 86, 86, 86, 86, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 8, 8, 12, 12, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 3, 3, 5, 6, 3, 3, 3, 3, 12, 12, 12, 3, 3, 3, 0, 3, 3, 3, 3, 8, 5, 6, 5, 6, 5, 6, 3, 3, 3, 7, 8, 7, 7, 7, 0, 3, 4, 3, 3, 0, 0, 0, 0, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 17, 0, 3, 3, 3, 4, 3, 3, 3, 5, 6, 3, 7, 3, 8, 3, 3, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 3, 3, 7, 7, 7, 3, 11, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 5, 7, 6, 7, 5, 6, 3, 5, 6, 3, 3, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 85, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 85, 85, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 15, 15, 15, 15, 15, 15, 0, 0, 15, 15, 15, 15, 15, 15, 0, 0, 15, 15, 15, 15, 15, 15, 0, 0, 15, 15, 15, 0, 0, 0, 4, 4, 7, 11, 14, 4, 4, 0, 14, 7, 7, 7, 7, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 14, 14, 0, 0 #if TCL_UTF_MAX > 3 ,15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 3, 3, 3, 0, 0, 0, 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 18, 18, 18, 18, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 18, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 86, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 118, 15, 15, 15, 15, 15, 15, 15, 15, 118, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 3, 15, 15, 15, 15, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 3, 118, 118, 118, 118, 118, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 0, 0, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 0, 0, 0, 15, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 3, 18, 18, 18, 18, 18, 18, 18, 18, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 18, 18, 18, 18, 18, 18, 0, 0, 0, 3, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 3, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 15, 15, 15, 86, 86, 86, 0, 86, 86, 0, 0, 0, 0, 0, 86, 86, 86, 86, 15, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 86, 86, 86, 0, 0, 0, 0, 86, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 18, 18, 3, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 18, 18, 18, 18, 18, 18, 18, 18, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 18, 18, 18, 18, 18, 18, 18, 18, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 116, 86, 116, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 116, 116, 116, 86, 86, 86, 86, 116, 116, 86, 86, 3, 3, 17, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 86, 86, 86, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 86, 86, 86, 86, 86, 116, 86, 86, 86, 86, 86, 86, 86, 86, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 116, 116, 116, 86, 86, 86, 86, 86, 86, 86, 86, 86, 116, 116, 15, 15, 15, 15, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 86, 116, 86, 116, 116, 86, 86, 86, 86, 86, 86, 116, 86, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 118, 118, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 86, 86, 86, 86, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 116, 116, 86, 86, 86, 14, 14, 14, 116, 116, 116, 116, 116, 116, 17, 17, 17, 17, 17, 17, 17, 17, 86, 86, 86, 86, 86, 86, 86, 86, 14, 14, 86, 86, 86, 86, 86, 86, 86, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 86, 86, 86, 86, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 14, 14, 86, 86, 86, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 21, 21, 21, 21, 21, 21, 21, 0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 100, 0, 100, 100, 0, 0, 100, 0, 0, 100, 100, 0, 0, 100, 100, 100, 100, 0, 100, 100, 100, 100, 100, 100, 100, 100, 21, 21, 21, 21, 0, 21, 0, 21, 21, 21, 21, 21, 21, 21, 0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 100, 100, 0, 100, 100, 100, 100, 0, 0, 100, 100, 100, 100, 100, 100, 100, 100, 0, 100, 100, 100, 100, 100, 100, 100, 0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 100, 100, 0, 100, 100, 100, 100, 0, 100, 100, 100, 100, 100, 0, 100, 0, 0, 0, 100, 100, 100, 100, 100, 100, 100, 0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 100, 100, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 21, 21, 21, 21, 21, 21, 0, 0, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 7, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 7, 21, 21, 21, 21, 21, 21, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 7, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 7, 21, 21, 21, 21, 21, 21, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 7, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 7, 21, 21, 21, 21, 21, 21, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 7, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 7, 21, 21, 21, 21, 21, 21, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 7, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 7, 21, 21, 21, 21, 21, 21, 100, 21, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 0, 15, 0, 0, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 0, 15, 0, 15, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 15, 0, 15, 0, 15, 0, 15, 15, 15, 0, 15, 15, 0, 15, 0, 0, 15, 0, 15, 0, 15, 0, 15, 0, 15, 0, 15, 15, 0, 15, 0, 0, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 0, 15, 15, 15, 15, 0, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 15, 15, 15, 0, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 14, 14, 14, 14, 14, 0, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 14, 14, 14, 14, 0, 0, 0, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 #endif /* TCL_UTF_MAX > 3 */ }; /* * Each group represents a unique set of character attributes. The attributes * are encoded into a 32-bit value as follows: * * Bits 0-4 Character category: see the constants listed below. * * Bits 5-7 Case delta type: 000 = identity * 010 = add delta for lower * 011 = add delta for lower, add 1 for title * 100 = subtract delta for title/upper * 101 = sub delta for upper, sub 1 for title * 110 = sub delta for upper, add delta for lower * * Bits 8-31 Case delta: delta for case conversions. This should be the * highest field so we can easily sign extend. */ static CONST int groups[] = { 0, 15, 12, 25, 27, 21, 22, 26, 20, 9, 8257, 28, 19, 8322, 29, 5, 23, 16, 11, -190078, 24, 2, -30846, 321, 386, -50879, 59522, -30911, 76930, -49790, 53825, 52801, 52545, 20289, 51777, 52033, 53057, -24702, 54081, 53569, -41598, 54593, -33150, 54849, 55873, 55617, 56129, -14206, 609, 451, 674, 20354, -24767, -14271, -33215, 2763585, -41663, 2762817, -2768510, -49855, 17729, 18241, -2760318, -2759550, -2760062, 53890, 52866, 52610, 51842, 52098, 53122, -10823550, -10830718, 53634, 54146, -2750078, -2751614, 54658, 54914, -2745982, 55938, 17794, 55682, 18306, 56194, 4, 6, -21370, 9793, 9537, 16449, 16193, 9858, 9602, 8066, 16514, 16258, 2113, 16002, 14722, 1, 12162, 13954, 2178, 22146, 20610, -1662, -15295, 24706, -1727, 20545, 7, 3905, 3970, 12353, 12418, 8, 1859649, 10, -9044862, -976254, 15234, -1949375, -1918, -1983, -18814, -21886, -25470, -32638, -28542, -32126, -1981, -2174, -18879, -2237, 1844610, -21951, -25535, -28607, -32703, -32191, 13, 14, -1924287, -2145983, -2115007, 7233, 7298, 4170, 4234, 6749, 6813, -2750143, -976319, -2746047, 2763650, 2762882, -2759615, -2751679, -2760383, -2760127, -2768575, 1859714, -9044927, -10823615, -10830783, 18, 17, 10305, 10370 }; #if TCL_UTF_MAX > 3 # define UNICODE_OUT_OF_RANGE(ch) (((ch) & 0x1fffff) >= 0x2fa20) #else # define UNICODE_OUT_OF_RANGE(ch) (((ch) & 0x1f0000) != 0) #endif /* * The following constants are used to determine the category of a * Unicode character. */ enum { UNASSIGNED, UPPERCASE_LETTER, LOWERCASE_LETTER, TITLECASE_LETTER, MODIFIER_LETTER, OTHER_LETTER, NON_SPACING_MARK, ENCLOSING_MARK, COMBINING_SPACING_MARK, DECIMAL_DIGIT_NUMBER, LETTER_NUMBER, OTHER_NUMBER, SPACE_SEPARATOR, LINE_SEPARATOR, PARAGRAPH_SEPARATOR, CONTROL, FORMAT, PRIVATE_USE, SURROGATE, CONNECTOR_PUNCTUATION, DASH_PUNCTUATION, OPEN_PUNCTUATION, CLOSE_PUNCTUATION, INITIAL_QUOTE_PUNCTUATION, FINAL_QUOTE_PUNCTUATION, OTHER_PUNCTUATION, MATH_SYMBOL, CURRENCY_SYMBOL, MODIFIER_SYMBOL, OTHER_SYMBOL }; /* * The following macros extract the fields of the character info. The * GetDelta() macro is complicated because we can't rely on the C compiler * to do sign extension on right shifts. */ #define GetCaseType(info) (((info) & 0xe0) >> 5) #define GetCategory(ch) (GetUniCharInfo(ch) & 0x1f) #define GetDelta(info) ((info) >> 8) /* * This macro extracts the information about a character from the * Unicode character tables. */ #define GetUniCharInfo(ch) (groups[groupMap[pageMap[((ch) & 0xffff) >> OFFSET_BITS] | ((ch) & ((1 << OFFSET_BITS)-1))]]) tcl8.4.20/generic/tclInitScript.h0000644003604700454610000000621311737050674015301 0ustar dgp771div/* * tclInitScript.h -- * * This file contains Unix & Windows common init script * It is not used on the Mac. (the mac init script is in tclMacInit.c) * * Copyright (c) 1998 Sun Microsystems, Inc. * Copyright (c) 1999 by Scriptics Corporation. * All rights reserved. */ /* * In order to find init.tcl during initialization, the following script * is invoked by Tcl_Init(). It looks in several different directories: * * $tcl_library - can specify a primary location, if set * no other locations will be checked * * $env(TCL_LIBRARY) - highest priority so user can always override * the search path unless the application has * specified an exact directory above * * $tclDefaultLibrary - this value is initialized by TclPlatformInit * from a static C variable that was set at * compile time * * $tcl_libPath - this value is initialized by a call to * TclGetLibraryPath called from Tcl_Init. * * The first directory on this path that contains a valid init.tcl script * will be set as the value of tcl_library. * * Note that this entire search mechanism can be bypassed by defining an * alternate tclInit procedure before calling Tcl_Init(). */ static char initScript[] = "if {[info proc tclInit]==\"\"} {\n\ proc tclInit {} {\n\ global tcl_libPath tcl_library errorInfo\n\ global env tclDefaultLibrary\n\ rename tclInit {}\n\ set errors {}\n\ set dirs {}\n\ if {[info exists tcl_library]} {\n\ lappend dirs $tcl_library\n\ } else {\n\ if {[info exists env(TCL_LIBRARY)]} {\n\ lappend dirs $env(TCL_LIBRARY)\n\ }\n\ catch {\n\ lappend dirs $tclDefaultLibrary\n\ unset tclDefaultLibrary\n\ }\n\ set dirs [concat $dirs $tcl_libPath]\n\ }\n\ foreach i $dirs {\n\ set tcl_library $i\n\ set tclfile [file join $i init.tcl]\n\ if {[file exists $tclfile]} {\n\ if {![catch {uplevel #0 [list source $tclfile]} msg]} {\n\ return\n\ } else {\n\ append errors \"$tclfile: $msg\n$errorInfo\n\"\n\ }\n\ }\n\ }\n\ set msg \"Can't find a usable init.tcl in the following directories: \n\"\n\ append msg \" $dirs\n\n\"\n\ append msg \"$errors\n\n\"\n\ append msg \"This probably means that Tcl wasn't installed properly.\n\"\n\ error $msg\n\ }\n\ }\n\ tclInit"; /* * A pointer to a string that holds an initialization script that if non-NULL * is evaluated in Tcl_Init() prior to the the built-in initialization script * above. This variable can be modified by the procedure below. */ static char * tclPreInitScript = NULL; /* *---------------------------------------------------------------------- * * TclSetPreInitScript -- * * This routine is used to change the value of the internal * variable, tclPreInitScript. * * Results: * Returns the current value of tclPreInitScript. * * Side effects: * Changes the way Tcl_Init() routine behaves. * *---------------------------------------------------------------------- */ char * TclSetPreInitScript (string) char *string; /* Pointer to a script. */ { char *prevString = tclPreInitScript; tclPreInitScript = string; return(prevString); } tcl8.4.20/generic/tclInterp.c0000644003604700454610000021502511737050674014450 0ustar dgp771div/* * tclInterp.c -- * * This file implements the "interp" command which allows creation * and manipulation of Tcl interpreters from within Tcl scripts. * * Copyright (c) 1995-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" #include /* * Counter for how many aliases were created (global) */ static int aliasCounter = 0; TCL_DECLARE_MUTEX(cntMutex) /* * struct Alias: * * Stores information about an alias. Is stored in the slave interpreter * and used by the source command to find the target command in the master * when the source command is invoked. */ typedef struct Alias { Tcl_Obj *namePtr; /* Name of alias command in slave interp. */ Tcl_Interp *targetInterp; /* Interp in which target command will be * invoked. */ Tcl_Command slaveCmd; /* Source command in slave interpreter, * bound to command that invokes the target * command in the target interpreter. */ Tcl_HashEntry *aliasEntryPtr; /* Entry for the alias hash table in slave. * This is used by alias deletion to remove * the alias from the slave interpreter * alias table. */ Tcl_HashEntry *targetEntryPtr; /* Entry for target command in master. * This is used in the master interpreter to * map back from the target command to aliases * redirecting to it. Random access to this * hash table is never required - we are using * a hash table only for convenience. */ int objc; /* Count of Tcl_Obj in the prefix of the * target command to be invoked in the * target interpreter. Additional arguments * specified when calling the alias in the * slave interp will be appended to the prefix * before the command is invoked. */ Tcl_Obj *objPtr; /* The first actual prefix object - the target * command name; this has to be at the end of the * structure, which will be extended to accomodate * the remaining objects in the prefix. */ } Alias; /* * * struct Slave: * * Used by the "interp" command to record and find information about slave * interpreters. Maps from a command name in the master to information about * a slave interpreter, e.g. what aliases are defined in it. */ typedef struct Slave { Tcl_Interp *masterInterp; /* Master interpreter for this slave. */ Tcl_HashEntry *slaveEntryPtr; /* Hash entry in masters slave table for * this slave interpreter. Used to find * this record, and used when deleting the * slave interpreter to delete it from the * master's table. */ Tcl_Interp *slaveInterp; /* The slave interpreter. */ Tcl_Command interpCmd; /* Interpreter object command. */ Tcl_HashTable aliasTable; /* Table which maps from names of commands * in slave interpreter to struct Alias * defined below. */ } Slave; /* * struct Target: * * Maps from master interpreter commands back to the source commands in slave * interpreters. This is needed because aliases can be created between sibling * interpreters and must be deleted when the target interpreter is deleted. In * case they would not be deleted the source interpreter would be left with a * "dangling pointer". One such record is stored in the Master record of the * master interpreter (in the targetTable hashtable, see below) with the * master for each alias which directs to a command in the master. These * records are used to remove the source command for an from a slave if/when * the master is deleted. */ typedef struct Target { Tcl_Command slaveCmd; /* Command for alias in slave interp. */ Tcl_Interp *slaveInterp; /* Slave Interpreter. */ } Target; /* * struct Master: * * This record is used for two purposes: First, slaveTable (a hashtable) * maps from names of commands to slave interpreters. This hashtable is * used to store information about slave interpreters of this interpreter, * to map over all slaves, etc. The second purpose is to store information * about all aliases in slaves (or siblings) which direct to target commands * in this interpreter (using the targetTable hashtable). * * NB: the flags field in the interp structure, used with SAFE_INTERP * mask denotes whether the interpreter is safe or not. Safe * interpreters have restricted functionality, can only create safe slave * interpreters and can only load safe extensions. */ typedef struct Master { Tcl_HashTable slaveTable; /* Hash table for slave interpreters. * Maps from command names to Slave records. */ Tcl_HashTable targetTable; /* Hash table for Target Records. Contains * all Target records which denote aliases * from slaves or sibling interpreters that * direct to commands in this interpreter. This * table is used to remove dangling pointers * from the slave (or sibling) interpreters * when this interpreter is deleted. */ } Master; /* * The following structure keeps track of all the Master and Slave information * on a per-interp basis. */ typedef struct InterpInfo { Master master; /* Keeps track of all interps for which this * interp is the Master. */ Slave slave; /* Information necessary for this interp to * function as a slave. */ } InterpInfo; /* * Prototypes for local static procedures: */ static int AliasCreate _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Interp *slaveInterp, Tcl_Interp *masterInterp, Tcl_Obj *namePtr, Tcl_Obj *targetPtr, int objc, Tcl_Obj *CONST objv[])); static int AliasDelete _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Interp *slaveInterp, Tcl_Obj *namePtr)); static int AliasDescribe _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Interp *slaveInterp, Tcl_Obj *objPtr)); static int AliasList _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Interp *slaveInterp)); static int AliasObjCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *currentInterp, int objc, Tcl_Obj *CONST objv[])); static void AliasObjCmdDeleteProc _ANSI_ARGS_(( ClientData clientData)); static Tcl_Interp * GetInterp _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *pathPtr)); static Tcl_Interp * GetInterp2 _ANSI_ARGS_((Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static void InterpInfoDeleteProc _ANSI_ARGS_(( ClientData clientData, Tcl_Interp *interp)); static Tcl_Interp * SlaveCreate _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *pathPtr, int safe)); static int SlaveEval _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Interp *slaveInterp, int objc, Tcl_Obj *CONST objv[])); static int SlaveExpose _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Interp *slaveInterp, int objc, Tcl_Obj *CONST objv[])); static int SlaveHide _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Interp *slaveInterp, int objc, Tcl_Obj *CONST objv[])); static int SlaveHidden _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Interp *slaveInterp)); static int SlaveInvokeHidden _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Interp *slaveInterp, int global, int objc, Tcl_Obj *CONST objv[])); static int SlaveMarkTrusted _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Interp *slaveInterp)); static int SlaveObjCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static void SlaveObjCmdDeleteProc _ANSI_ARGS_(( ClientData clientData)); static int SlaveRecursionLimit _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Interp *slaveInterp, int objc, Tcl_Obj *CONST objv[])); /* *--------------------------------------------------------------------------- * * TclInterpInit -- * * Initializes the invoking interpreter for using the master, slave * and safe interp facilities. This is called from inside * Tcl_CreateInterp(). * * Results: * Always returns TCL_OK for backwards compatibility. * * Side effects: * Adds the "interp" command to an interpreter and initializes the * interpInfoPtr field of the invoking interpreter. * *--------------------------------------------------------------------------- */ int TclInterpInit(interp) Tcl_Interp *interp; /* Interpreter to initialize. */ { InterpInfo *interpInfoPtr; Master *masterPtr; Slave *slavePtr; interpInfoPtr = (InterpInfo *) ckalloc(sizeof(InterpInfo)); ((Interp *) interp)->interpInfo = (ClientData) interpInfoPtr; masterPtr = &interpInfoPtr->master; Tcl_InitHashTable(&masterPtr->slaveTable, TCL_STRING_KEYS); Tcl_InitHashTable(&masterPtr->targetTable, TCL_ONE_WORD_KEYS); slavePtr = &interpInfoPtr->slave; slavePtr->masterInterp = NULL; slavePtr->slaveEntryPtr = NULL; slavePtr->slaveInterp = interp; slavePtr->interpCmd = NULL; Tcl_InitHashTable(&slavePtr->aliasTable, TCL_STRING_KEYS); Tcl_CreateObjCommand(interp, "interp", Tcl_InterpObjCmd, NULL, NULL); Tcl_CallWhenDeleted(interp, InterpInfoDeleteProc, NULL); return TCL_OK; } /* *--------------------------------------------------------------------------- * * InterpInfoDeleteProc -- * * Invoked when an interpreter is being deleted. It releases all * storage used by the master/slave/safe interpreter facilities. * * Results: * None. * * Side effects: * Cleans up storage. Sets the interpInfoPtr field of the interp * to NULL. * *--------------------------------------------------------------------------- */ static void InterpInfoDeleteProc(clientData, interp) ClientData clientData; /* Ignored. */ Tcl_Interp *interp; /* Interp being deleted. All commands for * slave interps should already be deleted. */ { InterpInfo *interpInfoPtr; Slave *slavePtr; Master *masterPtr; Tcl_HashSearch hSearch; Tcl_HashEntry *hPtr; Target *targetPtr; interpInfoPtr = (InterpInfo *) ((Interp *) interp)->interpInfo; /* * There shouldn't be any commands left. */ masterPtr = &interpInfoPtr->master; if (masterPtr->slaveTable.numEntries != 0) { panic("InterpInfoDeleteProc: still exist commands"); } Tcl_DeleteHashTable(&masterPtr->slaveTable); /* * Tell any interps that have aliases to this interp that they should * delete those aliases. If the other interp was already dead, it * would have removed the target record already. */ hPtr = Tcl_FirstHashEntry(&masterPtr->targetTable, &hSearch); while (hPtr != NULL) { targetPtr = (Target *) Tcl_GetHashValue(hPtr); Tcl_DeleteCommandFromToken(targetPtr->slaveInterp, targetPtr->slaveCmd); hPtr = Tcl_NextHashEntry(&hSearch); } Tcl_DeleteHashTable(&masterPtr->targetTable); slavePtr = &interpInfoPtr->slave; if (slavePtr->interpCmd != NULL) { /* * Tcl_DeleteInterp() was called on this interpreter, rather * "interp delete" or the equivalent deletion of the command in the * master. First ensure that the cleanup callback doesn't try to * delete the interp again. */ slavePtr->slaveInterp = NULL; Tcl_DeleteCommandFromToken(slavePtr->masterInterp, slavePtr->interpCmd); } /* * There shouldn't be any aliases left. */ if (slavePtr->aliasTable.numEntries != 0) { panic("InterpInfoDeleteProc: still exist aliases"); } Tcl_DeleteHashTable(&slavePtr->aliasTable); ckfree((char *) interpInfoPtr); } /* *---------------------------------------------------------------------- * * Tcl_InterpObjCmd -- * * This procedure is invoked to process the "interp" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_InterpObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Unused. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int index; static CONST char *options[] = { "alias", "aliases", "create", "delete", "eval", "exists", "expose", "hide", "hidden", "issafe", "invokehidden", "marktrusted", "recursionlimit", "slaves", "share", "target", "transfer", NULL }; enum option { OPT_ALIAS, OPT_ALIASES, OPT_CREATE, OPT_DELETE, OPT_EVAL, OPT_EXISTS, OPT_EXPOSE, OPT_HIDE, OPT_HIDDEN, OPT_ISSAFE, OPT_INVOKEHID, OPT_MARKTRUSTED, OPT_RECLIMIT, OPT_SLAVES, OPT_SHARE, OPT_TARGET, OPT_TRANSFER }; if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "cmd ?arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[1], options, "option", 0, &index) != TCL_OK) { return TCL_ERROR; } switch ((enum option) index) { case OPT_ALIAS: { Tcl_Interp *slaveInterp, *masterInterp; if (objc < 4) { aliasArgs: Tcl_WrongNumArgs(interp, 2, objv, "slavePath slaveCmd ?masterPath masterCmd? ?args ..?"); return TCL_ERROR; } slaveInterp = GetInterp(interp, objv[2]); if (slaveInterp == (Tcl_Interp *) NULL) { return TCL_ERROR; } if (objc == 4) { return AliasDescribe(interp, slaveInterp, objv[3]); } if ((objc == 5) && (Tcl_GetString(objv[4])[0] == '\0')) { return AliasDelete(interp, slaveInterp, objv[3]); } if (objc > 5) { masterInterp = GetInterp(interp, objv[4]); if (masterInterp == (Tcl_Interp *) NULL) { return TCL_ERROR; } if (Tcl_GetString(objv[5])[0] == '\0') { if (objc == 6) { return AliasDelete(interp, slaveInterp, objv[3]); } } else { return AliasCreate(interp, slaveInterp, masterInterp, objv[3], objv[5], objc - 6, objv + 6); } } goto aliasArgs; } case OPT_ALIASES: { Tcl_Interp *slaveInterp; slaveInterp = GetInterp2(interp, objc, objv); if (slaveInterp == NULL) { return TCL_ERROR; } return AliasList(interp, slaveInterp); } case OPT_CREATE: { int i, last, safe; Tcl_Obj *slavePtr; char buf[16 + TCL_INTEGER_SPACE]; static CONST char *options[] = { "-safe", "--", NULL }; enum option { OPT_SAFE, OPT_LAST }; safe = Tcl_IsSafe(interp); /* * Weird historical rules: "-safe" is accepted at the end, too. */ slavePtr = NULL; last = 0; for (i = 2; i < objc; i++) { if ((last == 0) && (Tcl_GetString(objv[i])[0] == '-')) { if (Tcl_GetIndexFromObj(interp, objv[i], options, "option", 0, &index) != TCL_OK) { return TCL_ERROR; } if (index == OPT_SAFE) { safe = 1; continue; } i++; last = 1; } if (slavePtr != NULL) { Tcl_WrongNumArgs(interp, 2, objv, "?-safe? ?--? ?path?"); return TCL_ERROR; } if (i < objc) { slavePtr = objv[i]; } } buf[0] = '\0'; if (slavePtr == NULL) { /* * Create an anonymous interpreter -- we choose its name and * the name of the command. We check that the command name * that we use for the interpreter does not collide with an * existing command in the master interpreter. */ for (i = 0; ; i++) { Tcl_CmdInfo cmdInfo; sprintf(buf, "interp%d", i); if (Tcl_GetCommandInfo(interp, buf, &cmdInfo) == 0) { break; } } slavePtr = Tcl_NewStringObj(buf, -1); } if (SlaveCreate(interp, slavePtr, safe) == NULL) { if (buf[0] != '\0') { Tcl_DecrRefCount(slavePtr); } return TCL_ERROR; } Tcl_SetObjResult(interp, slavePtr); return TCL_OK; } case OPT_DELETE: { int i; InterpInfo *iiPtr; Tcl_Interp *slaveInterp; for (i = 2; i < objc; i++) { slaveInterp = GetInterp(interp, objv[i]); if (slaveInterp == NULL) { return TCL_ERROR; } else if (slaveInterp == interp) { Tcl_ResetResult(interp); Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "cannot delete the current interpreter", (char *) NULL); return TCL_ERROR; } iiPtr = (InterpInfo *) ((Interp *) slaveInterp)->interpInfo; Tcl_DeleteCommandFromToken(iiPtr->slave.masterInterp, iiPtr->slave.interpCmd); } return TCL_OK; } case OPT_EVAL: { Tcl_Interp *slaveInterp; if (objc < 4) { Tcl_WrongNumArgs(interp, 2, objv, "path arg ?arg ...?"); return TCL_ERROR; } slaveInterp = GetInterp(interp, objv[2]); if (slaveInterp == NULL) { return TCL_ERROR; } return SlaveEval(interp, slaveInterp, objc - 3, objv + 3); } case OPT_EXISTS: { int exists; Tcl_Interp *slaveInterp; exists = 1; slaveInterp = GetInterp2(interp, objc, objv); if (slaveInterp == NULL) { if (objc > 3) { return TCL_ERROR; } Tcl_ResetResult(interp); exists = 0; } Tcl_SetIntObj(Tcl_GetObjResult(interp), exists); return TCL_OK; } case OPT_EXPOSE: { Tcl_Interp *slaveInterp; if ((objc < 4) || (objc > 5)) { Tcl_WrongNumArgs(interp, 2, objv, "path hiddenCmdName ?cmdName?"); return TCL_ERROR; } slaveInterp = GetInterp(interp, objv[2]); if (slaveInterp == NULL) { return TCL_ERROR; } return SlaveExpose(interp, slaveInterp, objc - 3, objv + 3); } case OPT_HIDE: { Tcl_Interp *slaveInterp; /* A slave. */ if ((objc < 4) || (objc > 5)) { Tcl_WrongNumArgs(interp, 2, objv, "path cmdName ?hiddenCmdName?"); return TCL_ERROR; } slaveInterp = GetInterp(interp, objv[2]); if (slaveInterp == (Tcl_Interp *) NULL) { return TCL_ERROR; } return SlaveHide(interp, slaveInterp, objc - 3, objv + 3); } case OPT_HIDDEN: { Tcl_Interp *slaveInterp; /* A slave. */ slaveInterp = GetInterp2(interp, objc, objv); if (slaveInterp == NULL) { return TCL_ERROR; } return SlaveHidden(interp, slaveInterp); } case OPT_ISSAFE: { Tcl_Interp *slaveInterp; slaveInterp = GetInterp2(interp, objc, objv); if (slaveInterp == NULL) { return TCL_ERROR; } Tcl_SetIntObj(Tcl_GetObjResult(interp), Tcl_IsSafe(slaveInterp)); return TCL_OK; } case OPT_INVOKEHID: { int i, index, global; Tcl_Interp *slaveInterp; static CONST char *hiddenOptions[] = { "-global", "--", NULL }; enum hiddenOption { OPT_GLOBAL, OPT_LAST }; global = 0; for (i = 3; i < objc; i++) { if (Tcl_GetString(objv[i])[0] != '-') { break; } if (Tcl_GetIndexFromObj(interp, objv[i], hiddenOptions, "option", 0, &index) != TCL_OK) { return TCL_ERROR; } if (index == OPT_GLOBAL) { global = 1; } else { i++; break; } } if (objc - i < 1) { Tcl_WrongNumArgs(interp, 2, objv, "path ?-global? ?--? cmd ?arg ..?"); return TCL_ERROR; } slaveInterp = GetInterp(interp, objv[2]); if (slaveInterp == (Tcl_Interp *) NULL) { return TCL_ERROR; } return SlaveInvokeHidden(interp, slaveInterp, global, objc - i, objv + i); } case OPT_MARKTRUSTED: { Tcl_Interp *slaveInterp; if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "path"); return TCL_ERROR; } slaveInterp = GetInterp(interp, objv[2]); if (slaveInterp == NULL) { return TCL_ERROR; } return SlaveMarkTrusted(interp, slaveInterp); } case OPT_RECLIMIT: { Tcl_Interp *slaveInterp; if (objc != 3 && objc != 4) { Tcl_WrongNumArgs(interp, 2, objv, "path ?newlimit?"); return TCL_ERROR; } slaveInterp = GetInterp(interp, objv[2]); if (slaveInterp == NULL) { return TCL_ERROR; } return SlaveRecursionLimit(interp, slaveInterp, objc - 3, objv + 3); } case OPT_SLAVES: { Tcl_Interp *slaveInterp; InterpInfo *iiPtr; Tcl_Obj *resultPtr; Tcl_HashEntry *hPtr; Tcl_HashSearch hashSearch; char *string; slaveInterp = GetInterp2(interp, objc, objv); if (slaveInterp == NULL) { return TCL_ERROR; } iiPtr = (InterpInfo *) ((Interp *) slaveInterp)->interpInfo; resultPtr = Tcl_GetObjResult(interp); hPtr = Tcl_FirstHashEntry(&iiPtr->master.slaveTable, &hashSearch); for ( ; hPtr != NULL; hPtr = Tcl_NextHashEntry(&hashSearch)) { string = Tcl_GetHashKey(&iiPtr->master.slaveTable, hPtr); Tcl_ListObjAppendElement(NULL, resultPtr, Tcl_NewStringObj(string, -1)); } return TCL_OK; } case OPT_SHARE: { Tcl_Interp *slaveInterp; /* A slave. */ Tcl_Interp *masterInterp; /* Its master. */ Tcl_Channel chan; if (objc != 5) { Tcl_WrongNumArgs(interp, 2, objv, "srcPath channelId destPath"); return TCL_ERROR; } masterInterp = GetInterp(interp, objv[2]); if (masterInterp == NULL) { return TCL_ERROR; } chan = Tcl_GetChannel(masterInterp, Tcl_GetString(objv[3]), NULL); if (chan == NULL) { TclTransferResult(masterInterp, TCL_OK, interp); return TCL_ERROR; } slaveInterp = GetInterp(interp, objv[4]); if (slaveInterp == NULL) { return TCL_ERROR; } Tcl_RegisterChannel(slaveInterp, chan); return TCL_OK; } case OPT_TARGET: { Tcl_Interp *slaveInterp; InterpInfo *iiPtr; Tcl_HashEntry *hPtr; Alias *aliasPtr; char *aliasName; if (objc != 4) { Tcl_WrongNumArgs(interp, 2, objv, "path alias"); return TCL_ERROR; } slaveInterp = GetInterp(interp, objv[2]); if (slaveInterp == NULL) { return TCL_ERROR; } aliasName = Tcl_GetString(objv[3]); iiPtr = (InterpInfo *) ((Interp *) slaveInterp)->interpInfo; hPtr = Tcl_FindHashEntry(&iiPtr->slave.aliasTable, aliasName); if (hPtr == NULL) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "alias \"", aliasName, "\" in path \"", Tcl_GetString(objv[2]), "\" not found", (char *) NULL); return TCL_ERROR; } aliasPtr = (Alias *) Tcl_GetHashValue(hPtr); if (Tcl_GetInterpPath(interp, aliasPtr->targetInterp) != TCL_OK) { Tcl_ResetResult(interp); Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "target interpreter for alias \"", aliasName, "\" in path \"", Tcl_GetString(objv[2]), "\" is not my descendant", (char *) NULL); return TCL_ERROR; } return TCL_OK; } case OPT_TRANSFER: { Tcl_Interp *slaveInterp; /* A slave. */ Tcl_Interp *masterInterp; /* Its master. */ Tcl_Channel chan; if (objc != 5) { Tcl_WrongNumArgs(interp, 2, objv, "srcPath channelId destPath"); return TCL_ERROR; } masterInterp = GetInterp(interp, objv[2]); if (masterInterp == NULL) { return TCL_ERROR; } chan = Tcl_GetChannel(masterInterp, Tcl_GetString(objv[3]), NULL); if (chan == NULL) { TclTransferResult(masterInterp, TCL_OK, interp); return TCL_ERROR; } slaveInterp = GetInterp(interp, objv[4]); if (slaveInterp == NULL) { return TCL_ERROR; } Tcl_RegisterChannel(slaveInterp, chan); if (Tcl_UnregisterChannel(masterInterp, chan) != TCL_OK) { TclTransferResult(masterInterp, TCL_OK, interp); return TCL_ERROR; } return TCL_OK; } } return TCL_OK; } /* *--------------------------------------------------------------------------- * * GetInterp2 -- * * Helper function for Tcl_InterpObjCmd() to convert the interp name * potentially specified on the command line to an Tcl_Interp. * * Results: * The return value is the interp specified on the command line, * or the interp argument itself if no interp was specified on the * command line. If the interp could not be found or the wrong * number of arguments was specified on the command line, the return * value is NULL and an error message is left in the interp's result. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static Tcl_Interp * GetInterp2(interp, objc, objv) Tcl_Interp *interp; /* Default interp if no interp was specified * on the command line. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { if (objc == 2) { return interp; } else if (objc == 3) { return GetInterp(interp, objv[2]); } else { Tcl_WrongNumArgs(interp, 2, objv, "?path?"); return NULL; } } /* *---------------------------------------------------------------------- * * Tcl_CreateAlias -- * * Creates an alias between two interpreters. * * Results: * A standard Tcl result. * * Side effects: * Creates a new alias, manipulates the result field of slaveInterp. * *---------------------------------------------------------------------- */ int Tcl_CreateAlias(slaveInterp, slaveCmd, targetInterp, targetCmd, argc, argv) Tcl_Interp *slaveInterp; /* Interpreter for source command. */ CONST char *slaveCmd; /* Command to install in slave. */ Tcl_Interp *targetInterp; /* Interpreter for target command. */ CONST char *targetCmd; /* Name of target command. */ int argc; /* How many additional arguments? */ CONST char * CONST *argv; /* These are the additional args. */ { Tcl_Obj *slaveObjPtr, *targetObjPtr; Tcl_Obj **objv; int i; int result; objv = (Tcl_Obj **) ckalloc((unsigned) sizeof(Tcl_Obj *) * argc); for (i = 0; i < argc; i++) { objv[i] = Tcl_NewStringObj(argv[i], -1); Tcl_IncrRefCount(objv[i]); } slaveObjPtr = Tcl_NewStringObj(slaveCmd, -1); Tcl_IncrRefCount(slaveObjPtr); targetObjPtr = Tcl_NewStringObj(targetCmd, -1); Tcl_IncrRefCount(targetObjPtr); result = AliasCreate(slaveInterp, slaveInterp, targetInterp, slaveObjPtr, targetObjPtr, argc, objv); for (i = 0; i < argc; i++) { Tcl_DecrRefCount(objv[i]); } ckfree((char *) objv); Tcl_DecrRefCount(targetObjPtr); Tcl_DecrRefCount(slaveObjPtr); return result; } /* *---------------------------------------------------------------------- * * Tcl_CreateAliasObj -- * * Object version: Creates an alias between two interpreters. * * Results: * A standard Tcl result. * * Side effects: * Creates a new alias. * *---------------------------------------------------------------------- */ int Tcl_CreateAliasObj(slaveInterp, slaveCmd, targetInterp, targetCmd, objc, objv) Tcl_Interp *slaveInterp; /* Interpreter for source command. */ CONST char *slaveCmd; /* Command to install in slave. */ Tcl_Interp *targetInterp; /* Interpreter for target command. */ CONST char *targetCmd; /* Name of target command. */ int objc; /* How many additional arguments? */ Tcl_Obj *CONST objv[]; /* Argument vector. */ { Tcl_Obj *slaveObjPtr, *targetObjPtr; int result; slaveObjPtr = Tcl_NewStringObj(slaveCmd, -1); Tcl_IncrRefCount(slaveObjPtr); targetObjPtr = Tcl_NewStringObj(targetCmd, -1); Tcl_IncrRefCount(targetObjPtr); result = AliasCreate(slaveInterp, slaveInterp, targetInterp, slaveObjPtr, targetObjPtr, objc, objv); Tcl_DecrRefCount(slaveObjPtr); Tcl_DecrRefCount(targetObjPtr); return result; } /* *---------------------------------------------------------------------- * * Tcl_GetAlias -- * * Gets information about an alias. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_GetAlias(interp, aliasName, targetInterpPtr, targetNamePtr, argcPtr, argvPtr) Tcl_Interp *interp; /* Interp to start search from. */ CONST char *aliasName; /* Name of alias to find. */ Tcl_Interp **targetInterpPtr; /* (Return) target interpreter. */ CONST char **targetNamePtr; /* (Return) name of target command. */ int *argcPtr; /* (Return) count of addnl args. */ CONST char ***argvPtr; /* (Return) additional arguments. */ { InterpInfo *iiPtr; Tcl_HashEntry *hPtr; Alias *aliasPtr; int i, objc; Tcl_Obj **objv; iiPtr = (InterpInfo *) ((Interp *) interp)->interpInfo; hPtr = Tcl_FindHashEntry(&iiPtr->slave.aliasTable, aliasName); if (hPtr == NULL) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "alias \"", aliasName, "\" not found", (char *) NULL); return TCL_ERROR; } aliasPtr = (Alias *) Tcl_GetHashValue(hPtr); objc = aliasPtr->objc; objv = &aliasPtr->objPtr; if (targetInterpPtr != NULL) { *targetInterpPtr = aliasPtr->targetInterp; } if (targetNamePtr != NULL) { *targetNamePtr = Tcl_GetString(objv[0]); } if (argcPtr != NULL) { *argcPtr = objc - 1; } if (argvPtr != NULL) { *argvPtr = (CONST char **) ckalloc((unsigned) sizeof(CONST char *) * (objc - 1)); for (i = 1; i < objc; i++) { (*argvPtr)[i - 1] = Tcl_GetString(objv[i]); } } return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_GetAliasObj -- * * Object version: Gets information about an alias. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_GetAliasObj(interp, aliasName, targetInterpPtr, targetNamePtr, objcPtr, objvPtr) Tcl_Interp *interp; /* Interp to start search from. */ CONST char *aliasName; /* Name of alias to find. */ Tcl_Interp **targetInterpPtr; /* (Return) target interpreter. */ CONST char **targetNamePtr; /* (Return) name of target command. */ int *objcPtr; /* (Return) count of addnl args. */ Tcl_Obj ***objvPtr; /* (Return) additional args. */ { InterpInfo *iiPtr; Tcl_HashEntry *hPtr; Alias *aliasPtr; int objc; Tcl_Obj **objv; iiPtr = (InterpInfo *) ((Interp *) interp)->interpInfo; hPtr = Tcl_FindHashEntry(&iiPtr->slave.aliasTable, aliasName); if (hPtr == (Tcl_HashEntry *) NULL) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "alias \"", aliasName, "\" not found", (char *) NULL); return TCL_ERROR; } aliasPtr = (Alias *) Tcl_GetHashValue(hPtr); objc = aliasPtr->objc; objv = &aliasPtr->objPtr; if (targetInterpPtr != (Tcl_Interp **) NULL) { *targetInterpPtr = aliasPtr->targetInterp; } if (targetNamePtr != (CONST char **) NULL) { *targetNamePtr = Tcl_GetString(objv[0]); } if (objcPtr != (int *) NULL) { *objcPtr = objc - 1; } if (objvPtr != (Tcl_Obj ***) NULL) { *objvPtr = objv + 1; } return TCL_OK; } /* *---------------------------------------------------------------------- * * TclPreventAliasLoop -- * * When defining an alias or renaming a command, prevent an alias * loop from being formed. * * Results: * A standard Tcl object result. * * Side effects: * If TCL_ERROR is returned, the function also stores an error message * in the interpreter's result object. * * NOTE: * This function is public internal (instead of being static to * this file) because it is also used from TclRenameCommand. * *---------------------------------------------------------------------- */ int TclPreventAliasLoop(interp, cmdInterp, cmd) Tcl_Interp *interp; /* Interp in which to report errors. */ Tcl_Interp *cmdInterp; /* Interp in which the command is * being defined. */ Tcl_Command cmd; /* Tcl command we are attempting * to define. */ { Command *cmdPtr = (Command *) cmd; Alias *aliasPtr, *nextAliasPtr; Tcl_Command aliasCmd; Command *aliasCmdPtr; /* * If we are not creating or renaming an alias, then it is * always OK to create or rename the command. */ if (cmdPtr->objProc != AliasObjCmd) { return TCL_OK; } /* * OK, we are dealing with an alias, so traverse the chain of aliases. * If we encounter the alias we are defining (or renaming to) any in * the chain then we have a loop. */ aliasPtr = (Alias *) cmdPtr->objClientData; nextAliasPtr = aliasPtr; while (1) { Tcl_Obj *cmdNamePtr; /* * If the target of the next alias in the chain is the same as * the source alias, we have a loop. */ if (Tcl_InterpDeleted(nextAliasPtr->targetInterp)) { /* * The slave interpreter can be deleted while creating the alias. * [Bug #641195] */ Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "cannot define or rename alias \"", Tcl_GetString(aliasPtr->namePtr), "\": interpreter deleted", (char *) NULL); return TCL_ERROR; } cmdNamePtr = nextAliasPtr->objPtr; aliasCmd = Tcl_FindCommand(nextAliasPtr->targetInterp, Tcl_GetString(cmdNamePtr), Tcl_GetGlobalNamespace(nextAliasPtr->targetInterp), /*flags*/ 0); if (aliasCmd == (Tcl_Command) NULL) { return TCL_OK; } aliasCmdPtr = (Command *) aliasCmd; if (aliasCmdPtr == cmdPtr) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "cannot define or rename alias \"", Tcl_GetString(aliasPtr->namePtr), "\": would create a loop", (char *) NULL); return TCL_ERROR; } /* * Otherwise, follow the chain one step further. See if the target * command is an alias - if so, follow the loop to its target * command. Otherwise we do not have a loop. */ if (aliasCmdPtr->objProc != AliasObjCmd) { return TCL_OK; } nextAliasPtr = (Alias *) aliasCmdPtr->objClientData; } /* NOTREACHED */ } /* *---------------------------------------------------------------------- * * AliasCreate -- * * Helper function to do the work to actually create an alias. * * Results: * A standard Tcl result. * * Side effects: * An alias command is created and entered into the alias table * for the slave interpreter. * *---------------------------------------------------------------------- */ static int AliasCreate(interp, slaveInterp, masterInterp, namePtr, targetNamePtr, objc, objv) Tcl_Interp *interp; /* Interp for error reporting. */ Tcl_Interp *slaveInterp; /* Interp where alias cmd will live or from * which alias will be deleted. */ Tcl_Interp *masterInterp; /* Interp in which target command will be * invoked. */ Tcl_Obj *namePtr; /* Name of alias cmd. */ Tcl_Obj *targetNamePtr; /* Name of target cmd. */ int objc; /* Additional arguments to store */ Tcl_Obj *CONST objv[]; /* with alias. */ { Alias *aliasPtr; Tcl_HashEntry *hPtr; Target *targetPtr; Slave *slavePtr; Master *masterPtr; Tcl_Obj **prefv; int new, i; aliasPtr = (Alias *) ckalloc((unsigned) (sizeof(Alias) + objc * sizeof(Tcl_Obj *))); aliasPtr->namePtr = namePtr; Tcl_IncrRefCount(aliasPtr->namePtr); aliasPtr->targetInterp = masterInterp; aliasPtr->objc = objc + 1; prefv = &aliasPtr->objPtr; *prefv = targetNamePtr; Tcl_IncrRefCount(targetNamePtr); for (i = 0; i < objc; i++) { *(++prefv) = objv[i]; Tcl_IncrRefCount(objv[i]); } Tcl_Preserve(slaveInterp); Tcl_Preserve(masterInterp); aliasPtr->slaveCmd = Tcl_CreateObjCommand(slaveInterp, Tcl_GetString(namePtr), AliasObjCmd, (ClientData) aliasPtr, AliasObjCmdDeleteProc); if (TclPreventAliasLoop(interp, slaveInterp, aliasPtr->slaveCmd) != TCL_OK) { /* * Found an alias loop! The last call to Tcl_CreateObjCommand made * the alias point to itself. Delete the command and its alias * record. Be careful to wipe out its client data first, so the * command doesn't try to delete itself. */ Command *cmdPtr; Tcl_DecrRefCount(aliasPtr->namePtr); Tcl_DecrRefCount(targetNamePtr); for (i = 0; i < objc; i++) { Tcl_DecrRefCount(objv[i]); } cmdPtr = (Command *) aliasPtr->slaveCmd; cmdPtr->clientData = NULL; cmdPtr->deleteProc = NULL; cmdPtr->deleteData = NULL; Tcl_DeleteCommandFromToken(slaveInterp, aliasPtr->slaveCmd); ckfree((char *) aliasPtr); /* * The result was already set by TclPreventAliasLoop. */ Tcl_Release(slaveInterp); Tcl_Release(masterInterp); return TCL_ERROR; } /* * Make an entry in the alias table. If it already exists delete * the alias command. Then retry. */ slavePtr = &((InterpInfo *) ((Interp *) slaveInterp)->interpInfo)->slave; while (1) { Alias *oldAliasPtr; char *string; string = Tcl_GetString(namePtr); hPtr = Tcl_CreateHashEntry(&slavePtr->aliasTable, string, &new); if (new != 0) { break; } oldAliasPtr = (Alias *) Tcl_GetHashValue(hPtr); Tcl_DeleteCommandFromToken(slaveInterp, oldAliasPtr->slaveCmd); } aliasPtr->aliasEntryPtr = hPtr; Tcl_SetHashValue(hPtr, (ClientData) aliasPtr); /* * Create the new command. We must do it after deleting any old command, * because the alias may be pointing at a renamed alias, as in: * * interp alias {} foo {} bar # Create an alias "foo" * rename foo zop # Now rename the alias * interp alias {} foo {} zop # Now recreate "foo"... */ targetPtr = (Target *) ckalloc((unsigned) sizeof(Target)); targetPtr->slaveCmd = aliasPtr->slaveCmd; targetPtr->slaveInterp = slaveInterp; Tcl_MutexLock(&cntMutex); masterPtr = &((InterpInfo *) ((Interp *) masterInterp)->interpInfo)->master; do { hPtr = Tcl_CreateHashEntry(&masterPtr->targetTable, (char *) aliasCounter, &new); aliasCounter++; } while (new == 0); Tcl_MutexUnlock(&cntMutex); Tcl_SetHashValue(hPtr, (ClientData) targetPtr); aliasPtr->targetEntryPtr = hPtr; Tcl_SetObjResult(interp, namePtr); Tcl_Release(slaveInterp); Tcl_Release(masterInterp); return TCL_OK; } /* *---------------------------------------------------------------------- * * AliasDelete -- * * Deletes the given alias from the slave interpreter given. * * Results: * A standard Tcl result. * * Side effects: * Deletes the alias from the slave interpreter. * *---------------------------------------------------------------------- */ static int AliasDelete(interp, slaveInterp, namePtr) Tcl_Interp *interp; /* Interpreter for result & errors. */ Tcl_Interp *slaveInterp; /* Interpreter containing alias. */ Tcl_Obj *namePtr; /* Name of alias to delete. */ { Slave *slavePtr; Alias *aliasPtr; Tcl_HashEntry *hPtr; /* * If the alias has been renamed in the slave, the master can still use * the original name (with which it was created) to find the alias to * delete it. */ slavePtr = &((InterpInfo *) ((Interp *) slaveInterp)->interpInfo)->slave; hPtr = Tcl_FindHashEntry(&slavePtr->aliasTable, Tcl_GetString(namePtr)); if (hPtr == NULL) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "alias \"", Tcl_GetString(namePtr), "\" not found", NULL); return TCL_ERROR; } aliasPtr = (Alias *) Tcl_GetHashValue(hPtr); Tcl_DeleteCommandFromToken(slaveInterp, aliasPtr->slaveCmd); return TCL_OK; } /* *---------------------------------------------------------------------- * * AliasDescribe -- * * Sets the interpreter's result object to a Tcl list describing * the given alias in the given interpreter: its target command * and the additional arguments to prepend to any invocation * of the alias. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int AliasDescribe(interp, slaveInterp, namePtr) Tcl_Interp *interp; /* Interpreter for result & errors. */ Tcl_Interp *slaveInterp; /* Interpreter containing alias. */ Tcl_Obj *namePtr; /* Name of alias to describe. */ { Slave *slavePtr; Tcl_HashEntry *hPtr; Alias *aliasPtr; Tcl_Obj *prefixPtr; /* * If the alias has been renamed in the slave, the master can still use * the original name (with which it was created) to find the alias to * describe it. */ slavePtr = &((InterpInfo *) ((Interp *) slaveInterp)->interpInfo)->slave; hPtr = Tcl_FindHashEntry(&slavePtr->aliasTable, Tcl_GetString(namePtr)); if (hPtr == NULL) { return TCL_OK; } aliasPtr = (Alias *) Tcl_GetHashValue(hPtr); prefixPtr = Tcl_NewListObj(aliasPtr->objc, &aliasPtr->objPtr); Tcl_SetObjResult(interp, prefixPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * AliasList -- * * Computes a list of aliases defined in a slave interpreter. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int AliasList(interp, slaveInterp) Tcl_Interp *interp; /* Interp for data return. */ Tcl_Interp *slaveInterp; /* Interp whose aliases to compute. */ { Tcl_HashEntry *entryPtr; Tcl_HashSearch hashSearch; Tcl_Obj *resultPtr; Alias *aliasPtr; Slave *slavePtr; slavePtr = &((InterpInfo *) ((Interp *) slaveInterp)->interpInfo)->slave; resultPtr = Tcl_GetObjResult(interp); entryPtr = Tcl_FirstHashEntry(&slavePtr->aliasTable, &hashSearch); for ( ; entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&hashSearch)) { aliasPtr = (Alias *) Tcl_GetHashValue(entryPtr); Tcl_ListObjAppendElement(NULL, resultPtr, aliasPtr->namePtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * AliasObjCmd -- * * This is the procedure that services invocations of aliases in a * slave interpreter. One such command exists for each alias. When * invoked, this procedure redirects the invocation to the target * command in the master interpreter as designated by the Alias * record associated with this command. * * Results: * A standard Tcl result. * * Side effects: * Causes forwarding of the invocation; all possible side effects * may occur as a result of invoking the command to which the * invocation is forwarded. * *---------------------------------------------------------------------- */ static int AliasObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Alias record. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument vector. */ { #define ALIAS_CMDV_PREALLOC 10 Tcl_Interp *targetInterp; Alias *aliasPtr; int result, prefc, cmdc, i; Tcl_Obj **prefv, **cmdv; Tcl_Obj *cmdArr[ALIAS_CMDV_PREALLOC]; aliasPtr = (Alias *) clientData; targetInterp = aliasPtr->targetInterp; /* * Append the arguments to the command prefix and invoke the command * in the target interp's global namespace. */ prefc = aliasPtr->objc; prefv = &aliasPtr->objPtr; cmdc = prefc + objc - 1; if (cmdc <= ALIAS_CMDV_PREALLOC) { cmdv = cmdArr; } else { cmdv = (Tcl_Obj **) ckalloc((unsigned) (cmdc * sizeof(Tcl_Obj *))); } prefv = &aliasPtr->objPtr; memcpy((VOID *) cmdv, (VOID *) prefv, (size_t) (prefc * sizeof(Tcl_Obj *))); memcpy((VOID *) (cmdv+prefc), (VOID *) (objv+1), (size_t) ((objc-1) * sizeof(Tcl_Obj *))); Tcl_ResetResult(targetInterp); for (i=0; inamePtr); objv = &aliasPtr->objPtr; for (i = 0; i < aliasPtr->objc; i++) { Tcl_DecrRefCount(objv[i]); } Tcl_DeleteHashEntry(aliasPtr->aliasEntryPtr); targetPtr = (Target *) Tcl_GetHashValue(aliasPtr->targetEntryPtr); ckfree((char *) targetPtr); Tcl_DeleteHashEntry(aliasPtr->targetEntryPtr); ckfree((char *) aliasPtr); } /* *---------------------------------------------------------------------- * * Tcl_CreateSlave -- * * Creates a slave interpreter. The slavePath argument denotes the * name of the new slave relative to the current interpreter; the * slave is a direct descendant of the one-before-last component of * the path, e.g. it is a descendant of the current interpreter if * the slavePath argument contains only one component. Optionally makes * the slave interpreter safe. * * Results: * Returns the interpreter structure created, or NULL if an error * occurred. * * Side effects: * Creates a new interpreter and a new interpreter object command in * the interpreter indicated by the slavePath argument. * *---------------------------------------------------------------------- */ Tcl_Interp * Tcl_CreateSlave(interp, slavePath, isSafe) Tcl_Interp *interp; /* Interpreter to start search at. */ CONST char *slavePath; /* Name of slave to create. */ int isSafe; /* Should new slave be "safe" ? */ { Tcl_Obj *pathPtr; Tcl_Interp *slaveInterp; pathPtr = Tcl_NewStringObj(slavePath, -1); slaveInterp = SlaveCreate(interp, pathPtr, isSafe); Tcl_DecrRefCount(pathPtr); return slaveInterp; } /* *---------------------------------------------------------------------- * * Tcl_GetSlave -- * * Finds a slave interpreter by its path name. * * Results: * Returns a Tcl_Interp * for the named interpreter or NULL if not * found. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_Interp * Tcl_GetSlave(interp, slavePath) Tcl_Interp *interp; /* Interpreter to start search from. */ CONST char *slavePath; /* Path of slave to find. */ { Tcl_Obj *pathPtr; Tcl_Interp *slaveInterp; pathPtr = Tcl_NewStringObj(slavePath, -1); slaveInterp = GetInterp(interp, pathPtr); Tcl_DecrRefCount(pathPtr); return slaveInterp; } /* *---------------------------------------------------------------------- * * Tcl_GetMaster -- * * Finds the master interpreter of a slave interpreter. * * Results: * Returns a Tcl_Interp * for the master interpreter or NULL if none. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_Interp * Tcl_GetMaster(interp) Tcl_Interp *interp; /* Get the master of this interpreter. */ { Slave *slavePtr; /* Slave record of this interpreter. */ if (interp == (Tcl_Interp *) NULL) { return NULL; } slavePtr = &((InterpInfo *) ((Interp *) interp)->interpInfo)->slave; return slavePtr->masterInterp; } /* *---------------------------------------------------------------------- * * Tcl_GetInterpPath -- * * Sets the result of the asking interpreter to a proper Tcl list * containing the names of interpreters between the asking and * target interpreters. The target interpreter must be either the * same as the asking interpreter or one of its slaves (including * recursively). * * Results: * TCL_OK if the target interpreter is the same as, or a descendant * of, the asking interpreter; TCL_ERROR else. This way one can * distinguish between the case where the asking and target interps * are the same (an empty list is the result, and TCL_OK is returned) * and when the target is not a descendant of the asking interpreter * (in which case the Tcl result is an error message and the function * returns TCL_ERROR). * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_GetInterpPath(askingInterp, targetInterp) Tcl_Interp *askingInterp; /* Interpreter to start search from. */ Tcl_Interp *targetInterp; /* Interpreter to find. */ { InterpInfo *iiPtr; if (targetInterp == askingInterp) { return TCL_OK; } if (targetInterp == NULL) { return TCL_ERROR; } iiPtr = (InterpInfo *) ((Interp *) targetInterp)->interpInfo; if (Tcl_GetInterpPath(askingInterp, iiPtr->slave.masterInterp) != TCL_OK) { return TCL_ERROR; } Tcl_AppendElement(askingInterp, Tcl_GetHashKey(&iiPtr->master.slaveTable, iiPtr->slave.slaveEntryPtr)); return TCL_OK; } /* *---------------------------------------------------------------------- * * GetInterp -- * * Helper function to find a slave interpreter given a pathname. * * Results: * Returns the slave interpreter known by that name in the calling * interpreter, or NULL if no interpreter known by that name exists. * * Side effects: * Assigns to the pointer variable passed in, if not NULL. * *---------------------------------------------------------------------- */ static Tcl_Interp * GetInterp(interp, pathPtr) Tcl_Interp *interp; /* Interp. to start search from. */ Tcl_Obj *pathPtr; /* List object containing name of interp. to * be found. */ { Tcl_HashEntry *hPtr; /* Search element. */ Slave *slavePtr; /* Interim slave record. */ Tcl_Obj **objv; int objc, i; Tcl_Interp *searchInterp; /* Interim storage for interp. to find. */ InterpInfo *masterInfoPtr; if (Tcl_ListObjGetElements(interp, pathPtr, &objc, &objv) != TCL_OK) { return NULL; } searchInterp = interp; for (i = 0; i < objc; i++) { masterInfoPtr = (InterpInfo *) ((Interp *) searchInterp)->interpInfo; hPtr = Tcl_FindHashEntry(&masterInfoPtr->master.slaveTable, Tcl_GetString(objv[i])); if (hPtr == NULL) { searchInterp = NULL; break; } slavePtr = (Slave *) Tcl_GetHashValue(hPtr); searchInterp = slavePtr->slaveInterp; if (searchInterp == NULL) { break; } } if (searchInterp == NULL) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "could not find interpreter \"", Tcl_GetString(pathPtr), "\"", (char *) NULL); } return searchInterp; } /* *---------------------------------------------------------------------- * * SlaveCreate -- * * Helper function to do the actual work of creating a slave interp * and new object command. Also optionally makes the new slave * interpreter "safe". * * Results: * Returns the new Tcl_Interp * if successful or NULL if not. If failed, * the result of the invoking interpreter contains an error message. * * Side effects: * Creates a new slave interpreter and a new object command. * *---------------------------------------------------------------------- */ static Tcl_Interp * SlaveCreate(interp, pathPtr, safe) Tcl_Interp *interp; /* Interp. to start search from. */ Tcl_Obj *pathPtr; /* Path (name) of slave to create. */ int safe; /* Should we make it "safe"? */ { Tcl_Interp *masterInterp, *slaveInterp; Slave *slavePtr; InterpInfo *masterInfoPtr; Tcl_HashEntry *hPtr; char *path; int new, objc; Tcl_Obj **objv; if (Tcl_ListObjGetElements(interp, pathPtr, &objc, &objv) != TCL_OK) { return NULL; } if (objc < 2) { masterInterp = interp; path = Tcl_GetString(pathPtr); } else { Tcl_Obj *objPtr; objPtr = Tcl_NewListObj(objc - 1, objv); masterInterp = GetInterp(interp, objPtr); Tcl_DecrRefCount(objPtr); if (masterInterp == NULL) { return NULL; } path = Tcl_GetString(objv[objc - 1]); } if (safe == 0) { safe = Tcl_IsSafe(masterInterp); } masterInfoPtr = (InterpInfo *) ((Interp *) masterInterp)->interpInfo; hPtr = Tcl_CreateHashEntry(&masterInfoPtr->master.slaveTable, path, &new); if (new == 0) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "interpreter named \"", path, "\" already exists, cannot create", (char *) NULL); return NULL; } slaveInterp = Tcl_CreateInterp(); slavePtr = &((InterpInfo *) ((Interp *) slaveInterp)->interpInfo)->slave; slavePtr->masterInterp = masterInterp; slavePtr->slaveEntryPtr = hPtr; slavePtr->slaveInterp = slaveInterp; slavePtr->interpCmd = Tcl_CreateObjCommand(masterInterp, path, SlaveObjCmd, (ClientData) slaveInterp, SlaveObjCmdDeleteProc); Tcl_InitHashTable(&slavePtr->aliasTable, TCL_STRING_KEYS); Tcl_SetHashValue(hPtr, (ClientData) slavePtr); Tcl_SetVar(slaveInterp, "tcl_interactive", "0", TCL_GLOBAL_ONLY); /* * Inherit the recursion limit. */ ((Interp *) slaveInterp)->maxNestingDepth = ((Interp *) masterInterp)->maxNestingDepth ; if (safe) { if (Tcl_MakeSafe(slaveInterp) == TCL_ERROR) { goto error; } } else { if (Tcl_Init(slaveInterp) == TCL_ERROR) { goto error; } /* * This will create the "memory" command in slave interpreters * if we compiled with TCL_MEM_DEBUG, otherwise it does nothing. */ Tcl_InitMemory(slaveInterp); } return slaveInterp; error: TclTransferResult(slaveInterp, TCL_ERROR, interp); Tcl_DeleteInterp(slaveInterp); return NULL; } /* *---------------------------------------------------------------------- * * SlaveObjCmd -- * * Command to manipulate an interpreter, e.g. to send commands to it * to be evaluated. One such command exists for each slave interpreter. * * Results: * A standard Tcl result. * * Side effects: * See user documentation for details. * *---------------------------------------------------------------------- */ static int SlaveObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Slave interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Tcl_Interp *slaveInterp; int index; static CONST char *options[] = { "alias", "aliases", "eval", "expose", "hide", "hidden", "issafe", "invokehidden", "marktrusted", "recursionlimit", NULL }; enum options { OPT_ALIAS, OPT_ALIASES, OPT_EVAL, OPT_EXPOSE, OPT_HIDE, OPT_HIDDEN, OPT_ISSAFE, OPT_INVOKEHIDDEN, OPT_MARKTRUSTED, OPT_RECLIMIT }; slaveInterp = (Tcl_Interp *) clientData; if (slaveInterp == NULL) { panic("SlaveObjCmd: interpreter has been deleted"); } if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "cmd ?arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[1], options, "option", 0, &index) != TCL_OK) { return TCL_ERROR; } switch ((enum options) index) { case OPT_ALIAS: { if (objc > 2) { if (objc == 3) { return AliasDescribe(interp, slaveInterp, objv[2]); } if (Tcl_GetString(objv[3])[0] == '\0') { if (objc == 4) { return AliasDelete(interp, slaveInterp, objv[2]); } } else { return AliasCreate(interp, slaveInterp, interp, objv[2], objv[3], objc - 4, objv + 4); } } Tcl_WrongNumArgs(interp, 2, objv, "aliasName ?targetName? ?args..?"); return TCL_ERROR; } case OPT_ALIASES: { if (objc != 2) { Tcl_WrongNumArgs(interp, 2, objv, (char *) NULL); return TCL_ERROR; } return AliasList(interp, slaveInterp); } case OPT_EVAL: { if (objc < 3) { Tcl_WrongNumArgs(interp, 2, objv, "arg ?arg ...?"); return TCL_ERROR; } return SlaveEval(interp, slaveInterp, objc - 2, objv + 2); } case OPT_EXPOSE: { if ((objc < 3) || (objc > 4)) { Tcl_WrongNumArgs(interp, 2, objv, "hiddenCmdName ?cmdName?"); return TCL_ERROR; } return SlaveExpose(interp, slaveInterp, objc - 2, objv + 2); } case OPT_HIDE: { if ((objc < 3) || (objc > 4)) { Tcl_WrongNumArgs(interp, 2, objv, "cmdName ?hiddenCmdName?"); return TCL_ERROR; } return SlaveHide(interp, slaveInterp, objc - 2, objv + 2); } case OPT_HIDDEN: { if (objc != 2) { Tcl_WrongNumArgs(interp, 2, objv, NULL); return TCL_ERROR; } return SlaveHidden(interp, slaveInterp); } case OPT_ISSAFE: { if (objc != 2) { Tcl_WrongNumArgs(interp, 2, objv, (char *) NULL); return TCL_ERROR; } Tcl_SetIntObj(Tcl_GetObjResult(interp), Tcl_IsSafe(slaveInterp)); return TCL_OK; } case OPT_INVOKEHIDDEN: { int global, i, index; static CONST char *hiddenOptions[] = { "-global", "--", NULL }; enum hiddenOption { OPT_GLOBAL, OPT_LAST }; global = 0; for (i = 2; i < objc; i++) { if (Tcl_GetString(objv[i])[0] != '-') { break; } if (Tcl_GetIndexFromObj(interp, objv[i], hiddenOptions, "option", 0, &index) != TCL_OK) { return TCL_ERROR; } if (index == OPT_GLOBAL) { global = 1; } else { i++; break; } } if (objc - i < 1) { Tcl_WrongNumArgs(interp, 2, objv, "?-global? ?--? cmd ?arg ..?"); return TCL_ERROR; } return SlaveInvokeHidden(interp, slaveInterp, global, objc - i, objv + i); } case OPT_MARKTRUSTED: { if (objc != 2) { Tcl_WrongNumArgs(interp, 2, objv, NULL); return TCL_ERROR; } return SlaveMarkTrusted(interp, slaveInterp); } case OPT_RECLIMIT: { if (objc != 2 && objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "?newlimit?"); return TCL_ERROR; } return SlaveRecursionLimit(interp, slaveInterp, objc - 2, objv + 2); } } return TCL_ERROR; } /* *---------------------------------------------------------------------- * * SlaveObjCmdDeleteProc -- * * Invoked when an object command for a slave interpreter is deleted; * cleans up all state associated with the slave interpreter and destroys * the slave interpreter. * * Results: * None. * * Side effects: * Cleans up all state associated with the slave interpreter and * destroys the slave interpreter. * *---------------------------------------------------------------------- */ static void SlaveObjCmdDeleteProc(clientData) ClientData clientData; /* The SlaveRecord for the command. */ { Slave *slavePtr; /* Interim storage for Slave record. */ Tcl_Interp *slaveInterp; /* And for a slave interp. */ slaveInterp = (Tcl_Interp *) clientData; slavePtr = &((InterpInfo *) ((Interp *) slaveInterp)->interpInfo)->slave; /* * Unlink the slave from its master interpreter. */ Tcl_DeleteHashEntry(slavePtr->slaveEntryPtr); /* * Set to NULL so that when the InterpInfo is cleaned up in the slave * it does not try to delete the command causing all sorts of grief. * See SlaveRecordDeleteProc(). */ slavePtr->interpCmd = NULL; if (slavePtr->slaveInterp != NULL) { Tcl_DeleteInterp(slavePtr->slaveInterp); } } /* *---------------------------------------------------------------------- * * SlaveEval -- * * Helper function to evaluate a command in a slave interpreter. * * Results: * A standard Tcl result. * * Side effects: * Whatever the command does. * *---------------------------------------------------------------------- */ static int SlaveEval(interp, slaveInterp, objc, objv) Tcl_Interp *interp; /* Interp for error return. */ Tcl_Interp *slaveInterp; /* The slave interpreter in which command * will be evaluated. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int result; Tcl_Obj *objPtr; Tcl_Preserve((ClientData) slaveInterp); Tcl_AllowExceptions(slaveInterp); if (objc == 1) { #ifndef TCL_TIP280 result = Tcl_EvalObjEx(slaveInterp, objv[0], 0); #else /* TIP #280 : Make actual argument location available to eval'd script */ Interp* iPtr = (Interp*) interp; CmdFrame* invoker = iPtr->cmdFramePtr; int word = 0; TclArgumentGet (interp, objv[0], &invoker, &word); result = TclEvalObjEx(slaveInterp, objv[0], 0, invoker, word); #endif } else { objPtr = Tcl_ConcatObj(objc, objv); Tcl_IncrRefCount(objPtr); result = Tcl_EvalObjEx(slaveInterp, objPtr, 0); Tcl_DecrRefCount(objPtr); } TclTransferResult(slaveInterp, result, interp); Tcl_Release((ClientData) slaveInterp); return result; } /* *---------------------------------------------------------------------- * * SlaveExpose -- * * Helper function to expose a command in a slave interpreter. * * Results: * A standard Tcl result. * * Side effects: * After this call scripts in the slave will be able to invoke * the newly exposed command. * *---------------------------------------------------------------------- */ static int SlaveExpose(interp, slaveInterp, objc, objv) Tcl_Interp *interp; /* Interp for error return. */ Tcl_Interp *slaveInterp; /* Interp in which command will be exposed. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { char *name; if (Tcl_IsSafe(interp)) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "permission denied: safe interpreter cannot expose commands", (char *) NULL); return TCL_ERROR; } name = Tcl_GetString(objv[(objc == 1) ? 0 : 1]); if (Tcl_ExposeCommand(slaveInterp, Tcl_GetString(objv[0]), name) != TCL_OK) { TclTransferResult(slaveInterp, TCL_ERROR, interp); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * SlaveRecursionLimit -- * * Helper function to set/query the Recursion limit of an interp * * Results: * A standard Tcl result. * * Side effects: * When (objc == 1), slaveInterp will be set to a new recursion * limit of objv[0]. * *---------------------------------------------------------------------- */ static int SlaveRecursionLimit(interp, slaveInterp, objc, objv) Tcl_Interp *interp; /* Interp for error return. */ Tcl_Interp *slaveInterp; /* Interp in which limit is set/queried. */ int objc; /* Set or Query. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { Interp *iPtr; int limit; if (objc) { if (Tcl_IsSafe(interp)) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "permission denied: ", "safe interpreters cannot change recursion limit", (char *) NULL); return TCL_ERROR; } if (Tcl_GetIntFromObj(interp, objv[0], &limit) == TCL_ERROR) { return TCL_ERROR; } if (limit <= 0) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "recursion limit must be > 0", -1)); return TCL_ERROR; } Tcl_SetRecursionLimit(slaveInterp, limit); iPtr = (Interp *) slaveInterp; if (interp == slaveInterp && iPtr->numLevels > limit) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "falling back due to new recursion limit", -1)); return TCL_ERROR; } Tcl_SetObjResult(interp, objv[0]); return TCL_OK; } else { limit = Tcl_SetRecursionLimit(slaveInterp, 0); Tcl_SetObjResult(interp, Tcl_NewIntObj(limit)); return TCL_OK; } } /* *---------------------------------------------------------------------- * * SlaveHide -- * * Helper function to hide a command in a slave interpreter. * * Results: * A standard Tcl result. * * Side effects: * After this call scripts in the slave will no longer be able * to invoke the named command. * *---------------------------------------------------------------------- */ static int SlaveHide(interp, slaveInterp, objc, objv) Tcl_Interp *interp; /* Interp for error return. */ Tcl_Interp *slaveInterp; /* Interp in which command will be exposed. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { char *name; if (Tcl_IsSafe(interp)) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "permission denied: safe interpreter cannot hide commands", (char *) NULL); return TCL_ERROR; } name = Tcl_GetString(objv[(objc == 1) ? 0 : 1]); if (Tcl_HideCommand(slaveInterp, Tcl_GetString(objv[0]), name) != TCL_OK) { TclTransferResult(slaveInterp, TCL_ERROR, interp); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * SlaveHidden -- * * Helper function to compute list of hidden commands in a slave * interpreter. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int SlaveHidden(interp, slaveInterp) Tcl_Interp *interp; /* Interp for data return. */ Tcl_Interp *slaveInterp; /* Interp whose hidden commands to query. */ { Tcl_Obj *listObjPtr; /* Local object pointer. */ Tcl_HashTable *hTblPtr; /* For local searches. */ Tcl_HashEntry *hPtr; /* For local searches. */ Tcl_HashSearch hSearch; /* For local searches. */ listObjPtr = Tcl_GetObjResult(interp); hTblPtr = ((Interp *) slaveInterp)->hiddenCmdTablePtr; if (hTblPtr != (Tcl_HashTable *) NULL) { for (hPtr = Tcl_FirstHashEntry(hTblPtr, &hSearch); hPtr != (Tcl_HashEntry *) NULL; hPtr = Tcl_NextHashEntry(&hSearch)) { Tcl_ListObjAppendElement(NULL, listObjPtr, Tcl_NewStringObj(Tcl_GetHashKey(hTblPtr, hPtr), -1)); } } return TCL_OK; } /* *---------------------------------------------------------------------- * * SlaveInvokeHidden -- * * Helper function to invoke a hidden command in a slave interpreter. * * Results: * A standard Tcl result. * * Side effects: * Whatever the hidden command does. * *---------------------------------------------------------------------- */ static int SlaveInvokeHidden(interp, slaveInterp, global, objc, objv) Tcl_Interp *interp; /* Interp for error return. */ Tcl_Interp *slaveInterp; /* The slave interpreter in which command * will be invoked. */ int global; /* Non-zero to invoke in global namespace. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int result; if (Tcl_IsSafe(interp)) { Tcl_SetStringObj(Tcl_GetObjResult(interp), "not allowed to invoke hidden commands from safe interpreter", -1); return TCL_ERROR; } Tcl_Preserve((ClientData) slaveInterp); Tcl_AllowExceptions(slaveInterp); if (global) { result = TclObjInvokeGlobal(slaveInterp, objc, objv, TCL_INVOKE_HIDDEN); } else { result = TclObjInvoke(slaveInterp, objc, objv, TCL_INVOKE_HIDDEN); } TclTransferResult(slaveInterp, result, interp); Tcl_Release((ClientData) slaveInterp); return result; } /* *---------------------------------------------------------------------- * * SlaveMarkTrusted -- * * Helper function to mark a slave interpreter as trusted (unsafe). * * Results: * A standard Tcl result. * * Side effects: * After this call the hard-wired security checks in the core no * longer prevent the slave from performing certain operations. * *---------------------------------------------------------------------- */ static int SlaveMarkTrusted(interp, slaveInterp) Tcl_Interp *interp; /* Interp for error return. */ Tcl_Interp *slaveInterp; /* The slave interpreter which will be * marked trusted. */ { if (Tcl_IsSafe(interp)) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "permission denied: safe interpreter cannot mark trusted", (char *) NULL); return TCL_ERROR; } ((Interp *) slaveInterp)->flags &= ~SAFE_INTERP; return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_IsSafe -- * * Determines whether an interpreter is safe * * Results: * 1 if it is safe, 0 if it is not. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_IsSafe(interp) Tcl_Interp *interp; /* Is this interpreter "safe" ? */ { Interp *iPtr; if (interp == (Tcl_Interp *) NULL) { return 0; } iPtr = (Interp *) interp; return ( (iPtr->flags) & SAFE_INTERP ) ? 1 : 0 ; } /* *---------------------------------------------------------------------- * * Tcl_MakeSafe -- * * Makes its argument interpreter contain only functionality that is * defined to be part of Safe Tcl. Unsafe commands are hidden, the * env array is unset, and the standard channels are removed. * * Results: * None. * * Side effects: * Hides commands in its argument interpreter, and removes settings * and channels. * *---------------------------------------------------------------------- */ int Tcl_MakeSafe(interp) Tcl_Interp *interp; /* Interpreter to be made safe. */ { Tcl_Channel chan; /* Channel to remove from * safe interpreter. */ Interp *iPtr = (Interp *) interp; TclHideUnsafeCommands(interp); iPtr->flags |= SAFE_INTERP; /* * Unsetting variables : (which should not have been set * in the first place, but...) */ /* * No env array in a safe slave. */ Tcl_UnsetVar(interp, "env", TCL_GLOBAL_ONLY); /* * Remove unsafe parts of tcl_platform */ Tcl_UnsetVar2(interp, "tcl_platform", "os", TCL_GLOBAL_ONLY); Tcl_UnsetVar2(interp, "tcl_platform", "osVersion", TCL_GLOBAL_ONLY); Tcl_UnsetVar2(interp, "tcl_platform", "machine", TCL_GLOBAL_ONLY); Tcl_UnsetVar2(interp, "tcl_platform", "user", TCL_GLOBAL_ONLY); /* * Unset path informations variables * (the only one remaining is [info nameofexecutable]) */ Tcl_UnsetVar(interp, "tclDefaultLibrary", TCL_GLOBAL_ONLY); Tcl_UnsetVar(interp, "tcl_library", TCL_GLOBAL_ONLY); Tcl_UnsetVar(interp, "tcl_pkgPath", TCL_GLOBAL_ONLY); /* * Remove the standard channels from the interpreter; safe interpreters * do not ordinarily have access to stdin, stdout and stderr. * * NOTE: These channels are not added to the interpreter by the * Tcl_CreateInterp call, but may be added later, by another I/O * operation. We want to ensure that the interpreter does not have * these channels even if it is being made safe after being used for * some time.. */ chan = Tcl_GetStdChannel(TCL_STDIN); if (chan != (Tcl_Channel) NULL) { Tcl_UnregisterChannel(interp, chan); } chan = Tcl_GetStdChannel(TCL_STDOUT); if (chan != (Tcl_Channel) NULL) { Tcl_UnregisterChannel(interp, chan); } chan = Tcl_GetStdChannel(TCL_STDERR); if (chan != (Tcl_Channel) NULL) { Tcl_UnregisterChannel(interp, chan); } return TCL_OK; } tcl8.4.20/generic/tclGet.c0000644003604700454610000002222212052456743013717 0ustar dgp771div/* * tclGet.c -- * * This file contains procedures to convert strings into * other forms, like integers or floating-point numbers or * booleans, doing syntax checking along the way. * * Copyright (c) 1990-1993 The Regents of the University of California. * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" #include /* *---------------------------------------------------------------------- * * Tcl_GetInt -- * * Given a string, produce the corresponding integer value. * * Results: * The return value is normally TCL_OK; in this case *intPtr * will be set to the integer value equivalent to string. If * string is improperly formed then TCL_ERROR is returned and * an error message will be left in the interp's result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_GetInt(interp, string, intPtr) Tcl_Interp *interp; /* Interpreter to use for error reporting. */ CONST char *string; /* String containing a (possibly signed) * integer in a form acceptable to strtol. */ int *intPtr; /* Place to store converted result. */ { char *end; CONST char *p = string; long i; /* * Note: use strtoul instead of strtol for integer conversions * to allow full-size unsigned numbers, but don't depend on strtoul * to handle sign characters; it won't in some implementations. */ errno = 0; #ifdef TCL_STRTOUL_SIGN_CHECK /* * This special sign check actually causes bad numbers to be allowed * when strtoul. I can't find a strtoul that doesn't validly handle * signed characters, and the C standard implies that this is all * unnecessary. [Bug #634856] */ for ( ; isspace(UCHAR(*p)); p++) { /* INTL: ISO space. */ /* Empty loop body. */ } if (*p == '-') { p++; i = -((long)strtoul(p, &end, 0)); /* INTL: Tcl source. */ } else if (*p == '+') { p++; i = strtoul(p, &end, 0); /* INTL: Tcl source. */ } else #else i = strtoul(p, &end, 0); /* INTL: Tcl source. */ #endif if (end == p) { badInteger: if (interp != (Tcl_Interp *) NULL) { Tcl_AppendResult(interp, "expected integer but got \"", string, "\"", (char *) NULL); TclCheckBadOctal(interp, string); } return TCL_ERROR; } /* * The second test below is needed on platforms where "long" is * larger than "int" to detect values that fit in a long but not in * an int. */ if ((errno == ERANGE) #if (LONG_MAX > INT_MAX) || (i > UINT_MAX) || (i < -(long)UINT_MAX) #endif ) { if (interp != (Tcl_Interp *) NULL) { Tcl_SetResult(interp, "integer value too large to represent", TCL_STATIC); Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW", Tcl_GetStringResult(interp), (char *) NULL); } return TCL_ERROR; } while ((*end != '\0') && isspace(UCHAR(*end))) { /* INTL: ISO space. */ end++; } if (*end != 0) { goto badInteger; } *intPtr = (int) i; return TCL_OK; } /* *---------------------------------------------------------------------- * * TclGetLong -- * * Given a string, produce the corresponding long integer value. * This routine is a version of Tcl_GetInt but returns a "long" * instead of an "int". * * Results: * The return value is normally TCL_OK; in this case *longPtr * will be set to the long integer value equivalent to string. If * string is improperly formed then TCL_ERROR is returned and * an error message will be left in the interp's result if interp * is non-NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclGetLong(interp, string, longPtr) Tcl_Interp *interp; /* Interpreter used for error reporting * if not NULL. */ CONST char *string; /* String containing a (possibly signed) * long integer in a form acceptable to * strtoul. */ long *longPtr; /* Place to store converted long result. */ { char *end; CONST char *p = string; long i; /* * Note: don't depend on strtoul to handle sign characters; it won't * in some implementations. */ errno = 0; #ifdef TCL_STRTOUL_SIGN_CHECK for ( ; isspace(UCHAR(*p)); p++) { /* INTL: ISO space. */ /* Empty loop body. */ } if (*p == '-') { p++; i = -(int)strtoul(p, &end, 0); /* INTL: Tcl source. */ } else if (*p == '+') { p++; i = strtoul(p, &end, 0); /* INTL: Tcl source. */ } else #else i = strtoul(p, &end, 0); /* INTL: Tcl source. */ #endif if (end == p) { badInteger: if (interp != (Tcl_Interp *) NULL) { Tcl_AppendResult(interp, "expected integer but got \"", string, "\"", (char *) NULL); TclCheckBadOctal(interp, string); } return TCL_ERROR; } if (errno == ERANGE) { if (interp != (Tcl_Interp *) NULL) { Tcl_SetResult(interp, "integer value too large to represent", TCL_STATIC); Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW", Tcl_GetStringResult(interp), (char *) NULL); } return TCL_ERROR; } while ((*end != '\0') && isspace(UCHAR(*end))) { /* INTL: ISO space. */ end++; } if (*end != 0) { goto badInteger; } *longPtr = i; return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_GetDouble -- * * Given a string, produce the corresponding double-precision * floating-point value. * * Results: * The return value is normally TCL_OK; in this case *doublePtr * will be set to the double-precision value equivalent to string. * If string is improperly formed then TCL_ERROR is returned and * an error message will be left in the interp's result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_GetDouble(interp, string, doublePtr) Tcl_Interp *interp; /* Interpreter used for error reporting. */ CONST char *string; /* String containing a floating-point number * in a form acceptable to strtod. */ double *doublePtr; /* Place to store converted result. */ { char *end; double d; errno = 0; d = strtod(string, &end); /* INTL: Tcl source. */ if (end == string) { badDouble: if (interp != (Tcl_Interp *) NULL) { Tcl_AppendResult(interp, "expected floating-point number but got \"", string, "\"", (char *) NULL); } return TCL_ERROR; } if (errno != 0 && (d == HUGE_VAL || d == -HUGE_VAL || d == 0)) { if (interp != (Tcl_Interp *) NULL) { TclExprFloatError(interp, d); } return TCL_ERROR; } while ((*end != 0) && isspace(UCHAR(*end))) { /* INTL: ISO space. */ end++; } if (*end != 0) { goto badDouble; } *doublePtr = d; return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_GetBoolean -- * * Given a string, return a 0/1 boolean value corresponding * to the string. * * Results: * The return value is normally TCL_OK; in this case *boolPtr * will be set to the 0/1 value equivalent to string. If * string is improperly formed then TCL_ERROR is returned and * an error message will be left in the interp's result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_GetBoolean(interp, string, boolPtr) Tcl_Interp *interp; /* Interpreter used for error reporting. */ CONST char *string; /* String containing a boolean number * specified either as 1/0 or true/false or * yes/no. */ int *boolPtr; /* Place to store converted result, which * will be 0 or 1. */ { int i; char lowerCase[10], c; size_t length; /* * Convert the input string to all lower-case. * INTL: This code will work on UTF strings. */ for (i = 0; i < 9; i++) { c = string[i]; if (c == 0) { break; } if ((c >= 'A') && (c <= 'Z')) { c += (char) ('a' - 'A'); } lowerCase[i] = c; } lowerCase[i] = 0; length = strlen(lowerCase); c = lowerCase[0]; if ((c == '0') && (lowerCase[1] == '\0')) { *boolPtr = 0; } else if ((c == '1') && (lowerCase[1] == '\0')) { *boolPtr = 1; } else if ((c == 'y') && (strncmp(lowerCase, "yes", length) == 0)) { *boolPtr = 1; } else if ((c == 'n') && (strncmp(lowerCase, "no", length) == 0)) { *boolPtr = 0; } else if ((c == 't') && (strncmp(lowerCase, "true", length) == 0)) { *boolPtr = 1; } else if ((c == 'f') && (strncmp(lowerCase, "false", length) == 0)) { *boolPtr = 0; } else if ((c == 'o') && (length >= 2)) { if (strncmp(lowerCase, "on", length) == 0) { *boolPtr = 1; } else if (strncmp(lowerCase, "off", length) == 0) { *boolPtr = 0; } else { goto badBoolean; } } else { badBoolean: if (interp != (Tcl_Interp *) NULL) { Tcl_AppendResult(interp, "expected boolean value but got \"", string, "\"", (char *) NULL); } return TCL_ERROR; } return TCL_OK; } tcl8.4.20/generic/tclTest.c0000644003604700454610000057775012052456744014145 0ustar dgp771div/* * tclTest.c -- * * This file contains C command procedures for a bunch of additional * Tcl commands that are used for testing out Tcl's C interfaces. * These commands are not normally included in Tcl applications; * they're only used for testing. * * Copyright (c) 1993-1994 The Regents of the University of California. * Copyright (c) 1994-1997 Sun Microsystems, Inc. * Copyright (c) 1998-2000 Ajuba Solutions. * Copyright (c) 2003 by Kevin B. Kenny. All rights reserved. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef _WIN64 /* See [Bug 3354324]: file mtime sets wrong time */ # define _USE_32BIT_TIME_T #endif #define TCL_TEST #include #include "tclInt.h" #include "tclPort.h" /* * Required for Testregexp*Cmd */ #include "tclRegexp.h" /* * Required for TestlocaleCmd */ #include /* * Required for the TestChannelCmd and TestChannelEventCmd */ #include "tclIO.h" /* * Declare external functions used in Windows tests. */ /* * Dynamic string shared by TestdcallCmd and DelCallbackProc; used * to collect the results of the various deletion callbacks. */ static Tcl_DString delString; static Tcl_Interp *delInterp; /* * One of the following structures exists for each asynchronous * handler created by the "testasync" command". */ typedef struct TestAsyncHandler { int id; /* Identifier for this handler. */ Tcl_AsyncHandler handler; /* Tcl's token for the handler. */ char *command; /* Command to invoke when the * handler is invoked. */ struct TestAsyncHandler *nextPtr; /* Next is list of handlers. */ } TestAsyncHandler; TCL_DECLARE_MUTEX(asyncTestMutex); static TestAsyncHandler *firstHandler = NULL; /* * The dynamic string below is used by the "testdstring" command * to test the dynamic string facilities. */ static Tcl_DString dstring; /* * The command trace below is used by the "testcmdtraceCmd" command * to test the command tracing facilities. */ static Tcl_Trace cmdTrace; /* * One of the following structures exists for each command created * by TestdelCmd: */ typedef struct DelCmd { Tcl_Interp *interp; /* Interpreter in which command exists. */ char *deleteCmd; /* Script to execute when command is * deleted. Malloc'ed. */ } DelCmd; /* * The following is used to keep track of an encoding that invokes a Tcl * command. */ typedef struct TclEncoding { Tcl_Interp *interp; char *toUtfCmd; char *fromUtfCmd; } TclEncoding; /* * The counter below is used to determine if the TestsaveresultFree * routine was called for a result. */ static int freeCount; /* * Boolean flag used by the "testsetmainloop" and "testexitmainloop" * commands. */ static int exitMainLoop = 0; /* * Event structure used in testing the event queue management procedures. */ typedef struct TestEvent { Tcl_Event header; /* Header common to all events */ Tcl_Interp* interp; /* Interpreter that will handle the event */ Tcl_Obj* command; /* Command to evaluate when the event occurs */ Tcl_Obj* tag; /* Tag for this event used to delete it */ } TestEvent; /* * Forward declarations for procedures defined later in this file: */ int Tcltest_Init _ANSI_ARGS_((Tcl_Interp *interp)); static int AsyncHandlerProc _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int code)); static void CleanupTestSetassocdataTests _ANSI_ARGS_(( ClientData clientData, Tcl_Interp *interp)); static void CmdDelProc1 _ANSI_ARGS_((ClientData clientData)); static void CmdDelProc2 _ANSI_ARGS_((ClientData clientData)); static int CmdProc1 _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int argc, CONST char **argv)); static int CmdProc2 _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int argc, CONST char **argv)); static void CmdTraceDeleteProc _ANSI_ARGS_(( ClientData clientData, Tcl_Interp *interp, int level, char *command, Tcl_CmdProc *cmdProc, ClientData cmdClientData, int argc, char **argv)); static void CmdTraceProc _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int level, char *command, Tcl_CmdProc *cmdProc, ClientData cmdClientData, int argc, char **argv)); static int CreatedCommandProc _ANSI_ARGS_(( ClientData clientData, Tcl_Interp *interp, int argc, CONST char **argv)); static int CreatedCommandProc2 _ANSI_ARGS_(( ClientData clientData, Tcl_Interp *interp, int argc, CONST char **argv)); static void DelCallbackProc _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp)); static int DelCmdProc _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int argc, CONST char **argv)); static void DelDeleteProc _ANSI_ARGS_((ClientData clientData)); static void EncodingFreeProc _ANSI_ARGS_((ClientData clientData)); static int EncodingToUtfProc _ANSI_ARGS_((ClientData clientData, CONST char *src, int srcLen, int flags, Tcl_EncodingState *statePtr, char *dst, int dstLen, int *srcReadPtr, int *dstWrotePtr, int *dstCharsPtr)); static int EncodingFromUtfProc _ANSI_ARGS_((ClientData clientData, CONST char *src, int srcLen, int flags, Tcl_EncodingState *statePtr, char *dst, int dstLen, int *srcReadPtr, int *dstWrotePtr, int *dstCharsPtr)); static void ExitProcEven _ANSI_ARGS_((ClientData clientData)); static void ExitProcOdd _ANSI_ARGS_((ClientData clientData)); static int GetTimesCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int argc, CONST char **argv)); static void MainLoop _ANSI_ARGS_((void)); static int NoopCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int argc, CONST char **argv)); static int NoopObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int ObjTraceProc _ANSI_ARGS_(( ClientData clientData, Tcl_Interp* interp, int level, CONST char* command, Tcl_Command commandToken, int objc, Tcl_Obj *CONST objv[] )); static void ObjTraceDeleteProc _ANSI_ARGS_(( ClientData )); static void PrintParse _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Parse *parsePtr)); static void SpecialFree _ANSI_ARGS_((char *blockPtr)); static int StaticInitProc _ANSI_ARGS_((Tcl_Interp *interp)); static int TestaccessprocCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int PretendTclpAccess _ANSI_ARGS_((CONST char *path, int mode)); static int TestAccessProc1 _ANSI_ARGS_((CONST char *path, int mode)); static int TestAccessProc2 _ANSI_ARGS_((CONST char *path, int mode)); static int TestAccessProc3 _ANSI_ARGS_((CONST char *path, int mode)); static int TestasyncCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int TestcmdinfoCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int TestcmdtokenCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int TestcmdtraceCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int TestcreatecommandCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int TestdcallCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int TestdelCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int TestdelassocdataCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int TestdstringCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int TestencodingObjCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int TestevalexObjCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int TestevalobjvObjCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int TesteventObjCmd _ANSI_ARGS_((ClientData unused, Tcl_Interp* interp, int argc, Tcl_Obj *CONST objv[])); static int TesteventProc _ANSI_ARGS_((Tcl_Event* event, int flags)); static int TesteventDeleteProc _ANSI_ARGS_(( Tcl_Event* event, ClientData clientData)); static int TestexithandlerCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int TestexprlongCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int TestexprlongobjCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int TestexprparserObjCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int TestexprstringCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int TestfileCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int TestfilelinkCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int TestfeventCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int TestgetassocdataCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int TestgetplatformCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int TestgetvarfullnameCmd _ANSI_ARGS_(( ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int TestinterpdeleteCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int TestlinkCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int TestlocaleCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int TestMathFunc _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, Tcl_Value *args, Tcl_Value *resultPtr)); static int TestMathFunc2 _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, Tcl_Value *args, Tcl_Value *resultPtr)); static int TestmainthreadCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int TestsetmainloopCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int TestexitmainloopCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static Tcl_Channel PretendTclpOpenFileChannel _ANSI_ARGS_(( Tcl_Interp *interp, CONST char *fileName, CONST char *modeString, int permissions)); static Tcl_Channel TestOpenFileChannelProc1 _ANSI_ARGS_(( Tcl_Interp *interp, CONST char *fileName, CONST char *modeString, int permissions)); static Tcl_Channel TestOpenFileChannelProc2 _ANSI_ARGS_(( Tcl_Interp *interp, CONST char *fileName, CONST char *modeString, int permissions)); static Tcl_Channel TestOpenFileChannelProc3 _ANSI_ARGS_(( Tcl_Interp *interp, CONST char *fileName, CONST char *modeString, int permissions)); static int TestpanicCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int TestparserObjCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int TestparsevarObjCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int TestparsevarnameObjCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int TestregexpObjCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static void TestregexpXflags _ANSI_ARGS_((char *string, int length, int *cflagsPtr, int *eflagsPtr)); static int TestsaveresultCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static void TestsaveresultFree _ANSI_ARGS_((char *blockPtr)); static int TestsetassocdataCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int TestsetCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int TestseterrorcodeCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int TestsetobjerrorcodeCmd _ANSI_ARGS_(( ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int TestopenfilechannelprocCmd _ANSI_ARGS_(( ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int TestsetplatformCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int TeststaticpkgCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int PretendTclpStat _ANSI_ARGS_((CONST char *path, Tcl_StatBuf *buf)); static int TestStatProc1 _ANSI_ARGS_((CONST char *path, Tcl_StatBuf *buf)); static int TestStatProc2 _ANSI_ARGS_((CONST char *path, Tcl_StatBuf *buf)); static int TestStatProc3 _ANSI_ARGS_((CONST char *path, Tcl_StatBuf *buf)); static int TeststatprocCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int TesttranslatefilenameCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int TestupvarCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int TestWrongNumArgsObjCmd _ANSI_ARGS_(( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int TestGetIndexFromObjStructObjCmd _ANSI_ARGS_(( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int TestChannelCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int argc, CONST char **argv)); static int TestChannelEventCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int argc, CONST char **argv)); /* Filesystem testing */ static int TestFilesystemObjCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int TestSimpleFilesystemObjCmd _ANSI_ARGS_(( ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static void TestReport _ANSI_ARGS_ ((CONST char* cmd, Tcl_Obj* arg1, Tcl_Obj* arg2)); static Tcl_Obj* TestReportGetNativePath _ANSI_ARGS_ (( Tcl_Obj* pathObjPtr)); static int TestReportStat _ANSI_ARGS_ ((Tcl_Obj *path, Tcl_StatBuf *buf)); static int TestReportAccess _ANSI_ARGS_ ((Tcl_Obj *path, int mode)); static Tcl_Channel TestReportOpenFileChannel _ANSI_ARGS_ (( Tcl_Interp *interp, Tcl_Obj *fileName, int mode, int permissions)); static int TestReportMatchInDirectory _ANSI_ARGS_ (( Tcl_Interp *interp, Tcl_Obj *resultPtr, Tcl_Obj *dirPtr, CONST char *pattern, Tcl_GlobTypeData *types)); static int TestReportChdir _ANSI_ARGS_ ((Tcl_Obj *dirName)); static int TestReportLstat _ANSI_ARGS_ ((Tcl_Obj *path, Tcl_StatBuf *buf)); static int TestReportCopyFile _ANSI_ARGS_ ((Tcl_Obj *src, Tcl_Obj *dst)); static int TestReportDeleteFile _ANSI_ARGS_ ((Tcl_Obj *path)); static int TestReportRenameFile _ANSI_ARGS_ ((Tcl_Obj *src, Tcl_Obj *dst)); static int TestReportCreateDirectory _ANSI_ARGS_ ((Tcl_Obj *path)); static int TestReportCopyDirectory _ANSI_ARGS_ ((Tcl_Obj *src, Tcl_Obj *dst, Tcl_Obj **errorPtr)); static int TestReportRemoveDirectory _ANSI_ARGS_ ((Tcl_Obj *path, int recursive, Tcl_Obj **errorPtr)); static int TestReportLoadFile _ANSI_ARGS_ ((Tcl_Interp *interp, Tcl_Obj *fileName, Tcl_LoadHandle *handlePtr, Tcl_FSUnloadFileProc **unloadProcPtr)); static Tcl_Obj * TestReportLink _ANSI_ARGS_ ((Tcl_Obj *path, Tcl_Obj *to, int linkType)); static CONST char** TestReportFileAttrStrings _ANSI_ARGS_ (( Tcl_Obj *fileName, Tcl_Obj **objPtrRef)); static int TestReportFileAttrsGet _ANSI_ARGS_ ((Tcl_Interp *interp, int index, Tcl_Obj *fileName, Tcl_Obj **objPtrRef)); static int TestReportFileAttrsSet _ANSI_ARGS_ ((Tcl_Interp *interp, int index, Tcl_Obj *fileName, Tcl_Obj *objPtr)); static int TestReportUtime _ANSI_ARGS_ ((Tcl_Obj *fileName, struct utimbuf *tval)); static int TestReportNormalizePath _ANSI_ARGS_ (( Tcl_Interp *interp, Tcl_Obj *pathPtr, int nextCheckpoint)); static int TestReportInFilesystem _ANSI_ARGS_ ((Tcl_Obj *pathPtr, ClientData *clientDataPtr)); static void TestReportFreeInternalRep _ANSI_ARGS_ ((ClientData clientData)); static ClientData TestReportDupInternalRep _ANSI_ARGS_ ((ClientData clientData)); static int SimpleStat _ANSI_ARGS_ ((Tcl_Obj *path, Tcl_StatBuf *buf)); static int SimpleAccess _ANSI_ARGS_ ((Tcl_Obj *path, int mode)); static Tcl_Channel SimpleOpenFileChannel _ANSI_ARGS_ (( Tcl_Interp *interp, Tcl_Obj *fileName, int mode, int permissions)); static Tcl_Obj* SimpleListVolumes _ANSI_ARGS_ ((void)); static int SimplePathInFilesystem _ANSI_ARGS_ (( Tcl_Obj *pathPtr, ClientData *clientDataPtr)); static Tcl_Obj* SimpleCopy _ANSI_ARGS_ ((Tcl_Obj *pathPtr)); static int TestNumUtfCharsCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); #if defined(HAVE_CPUID) || defined(__WIN32__) static int TestcpuidCmd _ANSI_ARGS_(( ClientData dummy, Tcl_Interp* interp, int objc, Tcl_Obj *CONST objv[] )); #endif static Tcl_Filesystem testReportingFilesystem = { "reporting", sizeof(Tcl_Filesystem), TCL_FILESYSTEM_VERSION_1, &TestReportInFilesystem, /* path in */ &TestReportDupInternalRep, &TestReportFreeInternalRep, NULL, /* native to norm */ NULL, /* convert to native */ &TestReportNormalizePath, NULL, /* path type */ NULL, /* separator */ &TestReportStat, &TestReportAccess, &TestReportOpenFileChannel, &TestReportMatchInDirectory, &TestReportUtime, &TestReportLink, NULL /* list volumes */, &TestReportFileAttrStrings, &TestReportFileAttrsGet, &TestReportFileAttrsSet, &TestReportCreateDirectory, &TestReportRemoveDirectory, &TestReportDeleteFile, &TestReportCopyFile, &TestReportRenameFile, &TestReportCopyDirectory, &TestReportLstat, (Tcl_FSLoadFileProc *) &TestReportLoadFile, NULL /* cwd */, &TestReportChdir }; static Tcl_Filesystem simpleFilesystem = { "simple", sizeof(Tcl_Filesystem), TCL_FILESYSTEM_VERSION_1, &SimplePathInFilesystem, NULL, NULL, /* No internal to normalized, since we don't create any * pure 'internal' Tcl_Obj path representations */ NULL, /* No create native rep function, since we don't use it * or 'Tcl_FSNewNativePath' */ NULL, /* Normalize path isn't needed - we assume paths only have * one representation */ NULL, NULL, NULL, &SimpleStat, &SimpleAccess, &SimpleOpenFileChannel, NULL, NULL, /* We choose not to support symbolic links inside our vfs's */ NULL, &SimpleListVolumes, NULL, NULL, NULL, NULL, NULL, NULL, /* No copy file - fallback will occur at Tcl level */ NULL, /* No rename file - fallback will occur at Tcl level */ NULL, /* No copy directory - fallback will occur at Tcl level */ NULL, /* Use stat for lstat */ NULL, /* No load - fallback on core implementation */ NULL, /* We don't need a getcwd or chdir - fallback on Tcl's versions */ NULL, NULL }; /* * External (platform specific) initialization routine, these declarations * explicitly don't use EXTERN since this code does not get compiled * into the library: */ extern int TclplatformtestInit _ANSI_ARGS_((Tcl_Interp *interp)); extern int TclThread_Init _ANSI_ARGS_((Tcl_Interp *interp)); /* *---------------------------------------------------------------------- * * Tcltest_Init -- * * This procedure performs application-specific initialization. * Most applications, especially those that incorporate additional * packages, will have their own version of this procedure. * * Results: * Returns a standard Tcl completion code, and leaves an error * message in the interp's result if an error occurs. * * Side effects: * Depends on the startup script. * *---------------------------------------------------------------------- */ int Tcltest_Init(interp) Tcl_Interp *interp; /* Interpreter for application. */ { Tcl_ValueType t3ArgTypes[2]; Tcl_Obj *listPtr; Tcl_Obj **objv; int objc, index; static CONST char *specialOptions[] = { "-appinitprocerror", "-appinitprocdeleteinterp", "-appinitprocclosestderr", "-appinitprocsetrcfile", (char *) NULL }; #ifndef TCL_TIP268 if (Tcl_PkgProvide(interp, "Tcltest", TCL_VERSION) == TCL_ERROR) { #else /* TIP #268: Full patchlevel instead of just major.minor */ if (Tcl_PkgProvide(interp, "Tcltest", TCL_PATCH_LEVEL) == TCL_ERROR) { #endif return TCL_ERROR; } /* * Create additional commands and math functions for testing Tcl. */ Tcl_CreateCommand(interp, "gettimes", GetTimesCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "noop", NoopCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "noop", NoopObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "testwrongnumargs", TestWrongNumArgsObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "testfilesystem", TestFilesystemObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "testsimplefilesystem", TestSimpleFilesystemObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "testgetindexfromobjstruct", TestGetIndexFromObjStructObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testaccessproc", TestaccessprocCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testasync", TestasyncCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testchannel", TestChannelCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testchannelevent", TestChannelEventCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testcmdtoken", TestcmdtokenCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testcmdinfo", TestcmdinfoCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testcmdtrace", TestcmdtraceCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testcreatecommand", TestcreatecommandCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testdcall", TestdcallCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testdel", TestdelCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testdelassocdata", TestdelassocdataCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_DStringInit(&dstring); Tcl_CreateCommand(interp, "testdstring", TestdstringCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "testencoding", TestencodingObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "testevalex", TestevalexObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "testevalobjv", TestevalobjvObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand( interp, "testevent", TesteventObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc*) NULL ); Tcl_CreateCommand(interp, "testexithandler", TestexithandlerCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testexprlong", TestexprlongCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "testexprlongobj", TestexprlongobjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "testexprparser", TestexprparserObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testexprstring", TestexprstringCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testfevent", TestfeventCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "testfilelink", TestfilelinkCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "testfile", TestfileCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testgetassocdata", TestgetassocdataCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testgetplatform", TestgetplatformCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "testgetvarfullname", TestgetvarfullnameCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testinterpdelete", TestinterpdeleteCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testlink", TestlinkCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "testlocale", TestlocaleCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testopenfilechannelproc", TestopenfilechannelprocCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testpanic", TestpanicCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "testparser", TestparserObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "testparsevar", TestparsevarObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "testparsevarname", TestparsevarnameObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "testregexp", TestregexpObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "testsaveresult", TestsaveresultCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testsetassocdata", TestsetassocdataCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testsetnoerr", TestsetCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testseterr", TestsetCmd, (ClientData) TCL_LEAVE_ERR_MSG, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testseterrorcode", TestseterrorcodeCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "testsetobjerrorcode", TestsetobjerrorcodeCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "testnumutfchars", TestNumUtfCharsCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testsetplatform", TestsetplatformCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "teststaticpkg", TeststaticpkgCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testtranslatefilename", TesttranslatefilenameCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testupvar", TestupvarCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateMathFunc(interp, "T1", 0, (Tcl_ValueType *) NULL, TestMathFunc, (ClientData) 123); Tcl_CreateMathFunc(interp, "T2", 0, (Tcl_ValueType *) NULL, TestMathFunc, (ClientData) 345); Tcl_CreateCommand(interp, "teststatproc", TeststatprocCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testmainthread", TestmainthreadCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testsetmainloop", TestsetmainloopCmd, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testexitmainloop", TestexitmainloopCmd, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); #if defined(HAVE_CPUID) || defined(__WIN32__) Tcl_CreateObjCommand(interp, "testcpuid", TestcpuidCmd, (ClientData) 0, (Tcl_CmdDeleteProc*) NULL ); #endif t3ArgTypes[0] = TCL_EITHER; t3ArgTypes[1] = TCL_EITHER; Tcl_CreateMathFunc(interp, "T3", 2, t3ArgTypes, TestMathFunc2, (ClientData) 0); #ifdef TCL_THREADS if (TclThread_Init(interp) != TCL_OK) { return TCL_ERROR; } #endif /* * Check for special options used in ../tests/main.test */ listPtr = Tcl_GetVar2Ex(interp, "argv", NULL, TCL_GLOBAL_ONLY); if (listPtr != NULL) { if (Tcl_ListObjGetElements(interp, listPtr, &objc, &objv) != TCL_OK) { return TCL_ERROR; } if (objc && (Tcl_GetIndexFromObj(NULL, objv[0], specialOptions, NULL, TCL_EXACT, &index) == TCL_OK)) { switch (index) { case 0: { return TCL_ERROR; } case 1: { Tcl_DeleteInterp(interp); return TCL_ERROR; } case 2: { int mode; Tcl_UnregisterChannel(interp, Tcl_GetChannel(interp, "stderr", &mode)); return TCL_ERROR; } case 3: { if (objc-1) { Tcl_SetVar2Ex(interp, "tcl_rcFileName", NULL, objv[1], TCL_GLOBAL_ONLY); } return TCL_ERROR; } } } } /* * And finally add any platform specific test commands. */ return TclplatformtestInit(interp); } /* *---------------------------------------------------------------------- * * TestasyncCmd -- * * This procedure implements the "testasync" command. It is used * to test the asynchronous handler facilities of Tcl. * * Results: * A standard Tcl result. * * Side effects: * Creates, deletes, and invokes handlers. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int TestasyncCmd(dummy, interp, argc, argv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { TestAsyncHandler *asyncPtr, *prevPtr; int id, code; static int nextId = 1; char buf[TCL_INTEGER_SPACE]; if (argc < 2) { wrongNumArgs: Tcl_SetResult(interp, "wrong # args", TCL_STATIC); return TCL_ERROR; } if (strcmp(argv[1], "create") == 0) { if (argc != 3) { goto wrongNumArgs; } asyncPtr = (TestAsyncHandler *) ckalloc(sizeof(TestAsyncHandler)); asyncPtr->command = (char *) ckalloc((unsigned) (strlen(argv[2]) + 1)); strcpy(asyncPtr->command, argv[2]); Tcl_MutexLock(&asyncTestMutex); asyncPtr->id = nextId; nextId++; asyncPtr->handler = Tcl_AsyncCreate(AsyncHandlerProc, (ClientData) asyncPtr->id); asyncPtr->nextPtr = firstHandler; firstHandler = asyncPtr; TclFormatInt(buf, asyncPtr->id); Tcl_MutexUnlock(&asyncTestMutex); Tcl_SetResult(interp, buf, TCL_VOLATILE); } else if (strcmp(argv[1], "delete") == 0) { if (argc == 2) { Tcl_MutexLock(&asyncTestMutex); while (firstHandler != NULL) { asyncPtr = firstHandler; firstHandler = asyncPtr->nextPtr; Tcl_AsyncDelete(asyncPtr->handler); ckfree(asyncPtr->command); ckfree((char *) asyncPtr); } Tcl_MutexUnlock(&asyncTestMutex); return TCL_OK; } if (argc != 3) { goto wrongNumArgs; } if (Tcl_GetInt(interp, argv[2], &id) != TCL_OK) { return TCL_ERROR; } Tcl_MutexLock(&asyncTestMutex); for (prevPtr = NULL, asyncPtr = firstHandler; asyncPtr != NULL; prevPtr = asyncPtr, asyncPtr = asyncPtr->nextPtr) { if (asyncPtr->id != id) { continue; } if (prevPtr == NULL) { firstHandler = asyncPtr->nextPtr; } else { prevPtr->nextPtr = asyncPtr->nextPtr; } Tcl_AsyncDelete(asyncPtr->handler); ckfree(asyncPtr->command); ckfree((char *) asyncPtr); break; } Tcl_MutexUnlock(&asyncTestMutex); } else if (strcmp(argv[1], "mark") == 0) { if (argc != 5) { goto wrongNumArgs; } if ((Tcl_GetInt(interp, argv[2], &id) != TCL_OK) || (Tcl_GetInt(interp, argv[4], &code) != TCL_OK)) { return TCL_ERROR; } Tcl_MutexLock(&asyncTestMutex); for (asyncPtr = firstHandler; asyncPtr != NULL; asyncPtr = asyncPtr->nextPtr) { if (asyncPtr->id == id) { Tcl_AsyncMark(asyncPtr->handler); break; } } Tcl_MutexUnlock(&asyncTestMutex); Tcl_SetResult(interp, (char *)argv[3], TCL_VOLATILE); return code; } else { Tcl_AppendResult(interp, "bad option \"", argv[1], "\": must be create, delete, int, or mark", (char *) NULL); return TCL_ERROR; } return TCL_OK; } static int AsyncHandlerProc(clientData, interp, code) ClientData clientData; /* Id of TestAsyncHandler structure. * in global list. */ Tcl_Interp *interp; /* Interpreter in which command was * executed, or NULL. */ int code; /* Current return code from command. */ { TestAsyncHandler *asyncPtr; int id = (int)clientData; CONST char *listArgv[4], *cmd; char string[TCL_INTEGER_SPACE]; Tcl_MutexLock(&asyncTestMutex); for (asyncPtr = firstHandler; asyncPtr != NULL; asyncPtr = asyncPtr->nextPtr) { if (asyncPtr->id == id) break; } Tcl_MutexUnlock(&asyncTestMutex); if (!asyncPtr) { /* Woops - this one was deleted between the AsyncMark and now */ return TCL_OK; } TclFormatInt(string, code); listArgv[0] = asyncPtr->command; listArgv[1] = Tcl_GetString(Tcl_GetObjResult(interp)); listArgv[2] = string; listArgv[3] = NULL; cmd = Tcl_Merge(3, listArgv); if (interp != NULL) { code = Tcl_Eval(interp, cmd); } else { /* * this should not happen, but by definition of how async * handlers are invoked, it's possible. Better error * checking is needed here. */ } ckfree((char *)cmd); return code; } /* *---------------------------------------------------------------------- * * TestcmdinfoCmd -- * * This procedure implements the "testcmdinfo" command. It is used * to test Tcl_GetCommandInfo, Tcl_SetCommandInfo, and command creation * and deletion. * * Results: * A standard Tcl result. * * Side effects: * Creates and deletes various commands and modifies their data. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int TestcmdinfoCmd(dummy, interp, argc, argv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { Tcl_CmdInfo info; if (argc != 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " option cmdName\"", (char *) NULL); return TCL_ERROR; } if (strcmp(argv[1], "create") == 0) { Tcl_CreateCommand(interp, argv[2], CmdProc1, (ClientData) "original", CmdDelProc1); } else if (strcmp(argv[1], "delete") == 0) { Tcl_DStringInit(&delString); Tcl_DeleteCommand(interp, argv[2]); Tcl_DStringResult(interp, &delString); } else if (strcmp(argv[1], "get") == 0) { if (Tcl_GetCommandInfo(interp, argv[2], &info) ==0) { Tcl_SetResult(interp, "??", TCL_STATIC); return TCL_OK; } if (info.proc == CmdProc1) { Tcl_AppendResult(interp, "CmdProc1", " ", (char *) info.clientData, (char *) NULL); } else if (info.proc == CmdProc2) { Tcl_AppendResult(interp, "CmdProc2", " ", (char *) info.clientData, (char *) NULL); } else { Tcl_AppendResult(interp, "unknown", (char *) NULL); } if (info.deleteProc == CmdDelProc1) { Tcl_AppendResult(interp, " CmdDelProc1", " ", (char *) info.deleteData, (char *) NULL); } else if (info.deleteProc == CmdDelProc2) { Tcl_AppendResult(interp, " CmdDelProc2", " ", (char *) info.deleteData, (char *) NULL); } else { Tcl_AppendResult(interp, " unknown", (char *) NULL); } Tcl_AppendResult(interp, " ", info.namespacePtr->fullName, (char *) NULL); if (info.isNativeObjectProc) { Tcl_AppendResult(interp, " nativeObjectProc", (char *) NULL); } else { Tcl_AppendResult(interp, " stringProc", (char *) NULL); } } else if (strcmp(argv[1], "modify") == 0) { info.proc = CmdProc2; info.clientData = (ClientData) "new_command_data"; info.objProc = NULL; info.objClientData = (ClientData) NULL; info.deleteProc = CmdDelProc2; info.deleteData = (ClientData) "new_delete_data"; if (Tcl_SetCommandInfo(interp, argv[2], &info) == 0) { Tcl_SetResult(interp, "0", TCL_STATIC); } else { Tcl_SetResult(interp, "1", TCL_STATIC); } } else { Tcl_AppendResult(interp, "bad option \"", argv[1], "\": must be create, delete, get, or modify", (char *) NULL); return TCL_ERROR; } return TCL_OK; } /*ARGSUSED*/ static int CmdProc1(clientData, interp, argc, argv) ClientData clientData; /* String to return. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { Tcl_AppendResult(interp, "CmdProc1 ", (char *) clientData, (char *) NULL); return TCL_OK; } /*ARGSUSED*/ static int CmdProc2(clientData, interp, argc, argv) ClientData clientData; /* String to return. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { Tcl_AppendResult(interp, "CmdProc2 ", (char *) clientData, (char *) NULL); return TCL_OK; } static void CmdDelProc1(clientData) ClientData clientData; /* String to save. */ { Tcl_DStringInit(&delString); Tcl_DStringAppend(&delString, "CmdDelProc1 ", -1); Tcl_DStringAppend(&delString, (char *) clientData, -1); } static void CmdDelProc2(clientData) ClientData clientData; /* String to save. */ { Tcl_DStringInit(&delString); Tcl_DStringAppend(&delString, "CmdDelProc2 ", -1); Tcl_DStringAppend(&delString, (char *) clientData, -1); } /* *---------------------------------------------------------------------- * * TestcmdtokenCmd -- * * This procedure implements the "testcmdtoken" command. It is used * to test Tcl_Command tokens and procedures such as * Tcl_GetCommandFullName. * * Results: * A standard Tcl result. * * Side effects: * Creates and deletes various commands and modifies their data. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int TestcmdtokenCmd(dummy, interp, argc, argv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { Tcl_Command token; int *l; char buf[30]; if (argc != 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " option arg\"", (char *) NULL); return TCL_ERROR; } if (strcmp(argv[1], "create") == 0) { token = Tcl_CreateCommand(interp, argv[2], CmdProc1, (ClientData) "original", (Tcl_CmdDeleteProc *) NULL); sprintf(buf, "%p", (VOID *)token); Tcl_SetResult(interp, buf, TCL_VOLATILE); } else if (strcmp(argv[1], "name") == 0) { Tcl_Obj *objPtr; if (sscanf(argv[2], "%p", &l) != 1) { Tcl_AppendResult(interp, "bad command token \"", argv[2], "\"", (char *) NULL); return TCL_ERROR; } objPtr = Tcl_NewObj(); Tcl_GetCommandFullName(interp, (Tcl_Command) l, objPtr); Tcl_AppendElement(interp, Tcl_GetCommandName(interp, (Tcl_Command) l)); Tcl_AppendElement(interp, Tcl_GetString(objPtr)); Tcl_DecrRefCount(objPtr); } else { Tcl_AppendResult(interp, "bad option \"", argv[1], "\": must be create or name", (char *) NULL); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * TestcmdtraceCmd -- * * This procedure implements the "testcmdtrace" command. It is used * to test Tcl_CreateTrace and Tcl_DeleteTrace. * * Results: * A standard Tcl result. * * Side effects: * Creates and deletes a command trace, and tests the invocation of * a procedure by the command trace. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int TestcmdtraceCmd(dummy, interp, argc, argv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { Tcl_DString buffer; int result; if (argc != 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " option script\"", (char *) NULL); return TCL_ERROR; } if (strcmp(argv[1], "tracetest") == 0) { Tcl_DStringInit(&buffer); cmdTrace = Tcl_CreateTrace(interp, 50000, (Tcl_CmdTraceProc *) CmdTraceProc, (ClientData) &buffer); result = Tcl_Eval(interp, argv[2]); if (result == TCL_OK) { Tcl_ResetResult(interp); Tcl_AppendResult(interp, Tcl_DStringValue(&buffer), NULL); } Tcl_DeleteTrace(interp, cmdTrace); Tcl_DStringFree(&buffer); } else if (strcmp(argv[1], "deletetest") == 0) { /* * Create a command trace then eval a script to check whether it is * called. Note that this trace procedure removes itself as a * further check of the robustness of the trace proc calling code in * TclExecuteByteCode. */ cmdTrace = Tcl_CreateTrace(interp, 50000, (Tcl_CmdTraceProc *) CmdTraceDeleteProc, (ClientData) NULL); Tcl_Eval(interp, argv[2]); } else if (strcmp(argv[1], "leveltest") == 0) { Interp *iPtr = (Interp *) interp; Tcl_DStringInit(&buffer); cmdTrace = Tcl_CreateTrace(interp, iPtr->numLevels + 4, (Tcl_CmdTraceProc *) CmdTraceProc, (ClientData) &buffer); result = Tcl_Eval(interp, argv[2]); if (result == TCL_OK) { Tcl_ResetResult(interp); Tcl_AppendResult(interp, Tcl_DStringValue(&buffer), NULL); } Tcl_DeleteTrace(interp, cmdTrace); Tcl_DStringFree(&buffer); } else if ( strcmp(argv[1], "resulttest" ) == 0 ) { /* Create an object-based trace, then eval a script. This is used * to test return codes other than TCL_OK from the trace engine. */ static int deleteCalled; deleteCalled = 0; cmdTrace = Tcl_CreateObjTrace( interp, 50000, TCL_ALLOW_INLINE_COMPILATION, ObjTraceProc, (ClientData) &deleteCalled, ObjTraceDeleteProc ); result = Tcl_Eval( interp, argv[ 2 ] ); Tcl_DeleteTrace( interp, cmdTrace ); if ( !deleteCalled ) { Tcl_SetResult( interp, "Delete wasn't called", TCL_STATIC ); return TCL_ERROR; } else { return result; } } else if ( strcmp(argv[1], "doubletest" ) == 0 ) { Tcl_Trace t1, t2; Tcl_DStringInit(&buffer); t1 = Tcl_CreateTrace(interp, 1, (Tcl_CmdTraceProc *) CmdTraceProc, (ClientData) &buffer); t2 = Tcl_CreateTrace(interp, 50000, (Tcl_CmdTraceProc *) CmdTraceProc, (ClientData) &buffer); result = Tcl_Eval(interp, argv[2]); if (result == TCL_OK) { Tcl_ResetResult(interp); Tcl_AppendResult(interp, Tcl_DStringValue(&buffer), NULL); } Tcl_DeleteTrace(interp, t2); Tcl_DeleteTrace(interp, t1); Tcl_DStringFree(&buffer); } else { Tcl_AppendResult(interp, "bad option \"", argv[1], "\": must be tracetest, deletetest, doubletest or resulttest", (char *) NULL); return TCL_ERROR; } return TCL_OK; } static void CmdTraceProc(clientData, interp, level, command, cmdProc, cmdClientData, argc, argv) ClientData clientData; /* Pointer to buffer in which the * command and arguments are appended. * Accumulates test result. */ Tcl_Interp *interp; /* Current interpreter. */ int level; /* Current trace level. */ char *command; /* The command being traced (after * substitutions). */ Tcl_CmdProc *cmdProc; /* Points to command's command procedure. */ ClientData cmdClientData; /* Client data associated with command * procedure. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { Tcl_DString *bufPtr = (Tcl_DString *) clientData; int i; Tcl_DStringAppendElement(bufPtr, command); Tcl_DStringStartSublist(bufPtr); for (i = 0; i < argc; i++) { Tcl_DStringAppendElement(bufPtr, argv[i]); } Tcl_DStringEndSublist(bufPtr); } static void CmdTraceDeleteProc(clientData, interp, level, command, cmdProc, cmdClientData, argc, argv) ClientData clientData; /* Unused. */ Tcl_Interp *interp; /* Current interpreter. */ int level; /* Current trace level. */ char *command; /* The command being traced (after * substitutions). */ Tcl_CmdProc *cmdProc; /* Points to command's command procedure. */ ClientData cmdClientData; /* Client data associated with command * procedure. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { /* * Remove ourselves to test whether calling Tcl_DeleteTrace within * a trace callback causes the for loop in TclExecuteByteCode that * calls traces to reference freed memory. */ Tcl_DeleteTrace(interp, cmdTrace); } static int ObjTraceProc( clientData, interp, level, command, token, objc, objv ) ClientData clientData; /* unused */ Tcl_Interp* interp; /* Tcl interpreter */ int level; /* Execution level */ CONST char* command; /* Command being executed */ Tcl_Command token; /* Command information */ int objc; /* Parameter count */ Tcl_Obj *CONST objv[]; /* Parameter list */ { CONST char* word = Tcl_GetString( objv[ 0 ] ); if ( !strcmp( word, "Error" ) ) { Tcl_SetObjResult( interp, Tcl_NewStringObj( command, -1 ) ); return TCL_ERROR; } else if ( !strcmp( word, "Break" ) ) { return TCL_BREAK; } else if ( !strcmp( word, "Continue" ) ) { return TCL_CONTINUE; } else if ( !strcmp( word, "Return" ) ) { return TCL_RETURN; } else if ( !strcmp( word, "OtherStatus" ) ) { return 6; } else { return TCL_OK; } } static void ObjTraceDeleteProc( clientData ) ClientData clientData; { int * intPtr = (int *) clientData; *intPtr = 1; /* Record that the trace was deleted */ } /* *---------------------------------------------------------------------- * * TestcreatecommandCmd -- * * This procedure implements the "testcreatecommand" command. It is * used to test that the Tcl_CreateCommand creates a new command in * the namespace specified as part of its name, if any. It also * checks that the namespace code ignore single ":"s in the middle * or end of a command name. * * Results: * A standard Tcl result. * * Side effects: * Creates and deletes two commands ("test_ns_basic::createdcommand" * and "value:at:"). * *---------------------------------------------------------------------- */ static int TestcreatecommandCmd(dummy, interp, argc, argv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { if (argc != 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " option\"", (char *) NULL); return TCL_ERROR; } if (strcmp(argv[1], "create") == 0) { Tcl_CreateCommand(interp, "test_ns_basic::createdcommand", CreatedCommandProc, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); } else if (strcmp(argv[1], "delete") == 0) { Tcl_DeleteCommand(interp, "test_ns_basic::createdcommand"); } else if (strcmp(argv[1], "create2") == 0) { Tcl_CreateCommand(interp, "value:at:", CreatedCommandProc2, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); } else if (strcmp(argv[1], "delete2") == 0) { Tcl_DeleteCommand(interp, "value:at:"); } else { Tcl_AppendResult(interp, "bad option \"", argv[1], "\": must be create, delete, create2, or delete2", (char *) NULL); return TCL_ERROR; } return TCL_OK; } static int CreatedCommandProc(clientData, interp, argc, argv) ClientData clientData; /* String to return. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { Tcl_CmdInfo info; int found; found = Tcl_GetCommandInfo(interp, "test_ns_basic::createdcommand", &info); if (!found) { Tcl_AppendResult(interp, "CreatedCommandProc could not get command info for test_ns_basic::createdcommand", (char *) NULL); return TCL_ERROR; } Tcl_AppendResult(interp, "CreatedCommandProc in ", info.namespacePtr->fullName, (char *) NULL); return TCL_OK; } static int CreatedCommandProc2(clientData, interp, argc, argv) ClientData clientData; /* String to return. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { Tcl_CmdInfo info; int found; found = Tcl_GetCommandInfo(interp, "value:at:", &info); if (!found) { Tcl_AppendResult(interp, "CreatedCommandProc2 could not get command info for test_ns_basic::createdcommand", (char *) NULL); return TCL_ERROR; } Tcl_AppendResult(interp, "CreatedCommandProc2 in ", info.namespacePtr->fullName, (char *) NULL); return TCL_OK; } /* *---------------------------------------------------------------------- * * TestdcallCmd -- * * This procedure implements the "testdcall" command. It is used * to test Tcl_CallWhenDeleted. * * Results: * A standard Tcl result. * * Side effects: * Creates and deletes interpreters. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int TestdcallCmd(dummy, interp, argc, argv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { int i, id; delInterp = Tcl_CreateInterp(); Tcl_DStringInit(&delString); for (i = 1; i < argc; i++) { if (Tcl_GetInt(interp, argv[i], &id) != TCL_OK) { return TCL_ERROR; } if (id < 0) { Tcl_DontCallWhenDeleted(delInterp, DelCallbackProc, (ClientData) (-id)); } else { Tcl_CallWhenDeleted(delInterp, DelCallbackProc, (ClientData) id); } } Tcl_DeleteInterp(delInterp); Tcl_DStringResult(interp, &delString); return TCL_OK; } /* * The deletion callback used by TestdcallCmd: */ static void DelCallbackProc(clientData, interp) ClientData clientData; /* Numerical value to append to * delString. */ Tcl_Interp *interp; /* Interpreter being deleted. */ { int id = (int) clientData; char buffer[TCL_INTEGER_SPACE]; TclFormatInt(buffer, id); Tcl_DStringAppendElement(&delString, buffer); if (interp != delInterp) { Tcl_DStringAppendElement(&delString, "bogus interpreter argument!"); } } /* *---------------------------------------------------------------------- * * TestdelCmd -- * * This procedure implements the "testdcall" command. It is used * to test Tcl_CallWhenDeleted. * * Results: * A standard Tcl result. * * Side effects: * Creates and deletes interpreters. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int TestdelCmd(dummy, interp, argc, argv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { DelCmd *dPtr; Tcl_Interp *slave; if (argc != 4) { Tcl_SetResult(interp, "wrong # args", TCL_STATIC); return TCL_ERROR; } slave = Tcl_GetSlave(interp, argv[1]); if (slave == NULL) { return TCL_ERROR; } dPtr = (DelCmd *) ckalloc(sizeof(DelCmd)); dPtr->interp = interp; dPtr->deleteCmd = (char *) ckalloc((unsigned) (strlen(argv[3]) + 1)); strcpy(dPtr->deleteCmd, argv[3]); Tcl_CreateCommand(slave, argv[2], DelCmdProc, (ClientData) dPtr, DelDeleteProc); return TCL_OK; } static int DelCmdProc(clientData, interp, argc, argv) ClientData clientData; /* String result to return. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { DelCmd *dPtr = (DelCmd *) clientData; Tcl_AppendResult(interp, dPtr->deleteCmd, (char *) NULL); ckfree(dPtr->deleteCmd); ckfree((char *) dPtr); return TCL_OK; } static void DelDeleteProc(clientData) ClientData clientData; /* String command to evaluate. */ { DelCmd *dPtr = (DelCmd *) clientData; Tcl_Eval(dPtr->interp, dPtr->deleteCmd); Tcl_ResetResult(dPtr->interp); ckfree(dPtr->deleteCmd); ckfree((char *) dPtr); } /* *---------------------------------------------------------------------- * * TestdelassocdataCmd -- * * This procedure implements the "testdelassocdata" command. It is used * to test Tcl_DeleteAssocData. * * Results: * A standard Tcl result. * * Side effects: * Deletes an association between a key and associated data from an * interpreter. * *---------------------------------------------------------------------- */ static int TestdelassocdataCmd(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { if (argc != 2) { Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0], " data_key\"", (char *) NULL); return TCL_ERROR; } Tcl_DeleteAssocData(interp, argv[1]); return TCL_OK; } /* *---------------------------------------------------------------------- * * TestdstringCmd -- * * This procedure implements the "testdstring" command. It is used * to test the dynamic string facilities of Tcl. * * Results: * A standard Tcl result. * * Side effects: * Creates, deletes, and invokes handlers. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int TestdstringCmd(dummy, interp, argc, argv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { int count; if (argc < 2) { wrongNumArgs: Tcl_SetResult(interp, "wrong # args", TCL_STATIC); return TCL_ERROR; } if (strcmp(argv[1], "append") == 0) { if (argc != 4) { goto wrongNumArgs; } if (Tcl_GetInt(interp, argv[3], &count) != TCL_OK) { return TCL_ERROR; } Tcl_DStringAppend(&dstring, argv[2], count); } else if (strcmp(argv[1], "element") == 0) { if (argc != 3) { goto wrongNumArgs; } Tcl_DStringAppendElement(&dstring, argv[2]); } else if (strcmp(argv[1], "end") == 0) { if (argc != 2) { goto wrongNumArgs; } Tcl_DStringEndSublist(&dstring); } else if (strcmp(argv[1], "free") == 0) { if (argc != 2) { goto wrongNumArgs; } Tcl_DStringFree(&dstring); } else if (strcmp(argv[1], "get") == 0) { if (argc != 2) { goto wrongNumArgs; } Tcl_SetResult(interp, Tcl_DStringValue(&dstring), TCL_VOLATILE); } else if (strcmp(argv[1], "gresult") == 0) { if (argc != 3) { goto wrongNumArgs; } if (strcmp(argv[2], "staticsmall") == 0) { Tcl_SetResult(interp, "short", TCL_STATIC); } else if (strcmp(argv[2], "staticlarge") == 0) { Tcl_SetResult(interp, "first0 first1 first2 first3 first4 first5 first6 first7 first8 first9\nsecond0 second1 second2 second3 second4 second5 second6 second7 second8 second9\nthird0 third1 third2 third3 third4 third5 third6 third7 third8 third9\nfourth0 fourth1 fourth2 fourth3 fourth4 fourth5 fourth6 fourth7 fourth8 fourth9\nfifth0 fifth1 fifth2 fifth3 fifth4 fifth5 fifth6 fifth7 fifth8 fifth9\nsixth0 sixth1 sixth2 sixth3 sixth4 sixth5 sixth6 sixth7 sixth8 sixth9\nseventh0 seventh1 seventh2 seventh3 seventh4 seventh5 seventh6 seventh7 seventh8 seventh9\n", TCL_STATIC); } else if (strcmp(argv[2], "free") == 0) { Tcl_SetResult(interp, (char *) ckalloc(100), TCL_DYNAMIC); strcpy(interp->result, "This is a malloc-ed string"); } else if (strcmp(argv[2], "special") == 0) { interp->result = (char *) ckalloc(100); interp->result += 4; interp->freeProc = SpecialFree; strcpy(interp->result, "This is a specially-allocated string"); } else { Tcl_AppendResult(interp, "bad gresult option \"", argv[2], "\": must be staticsmall, staticlarge, free, or special", (char *) NULL); return TCL_ERROR; } Tcl_DStringGetResult(interp, &dstring); } else if (strcmp(argv[1], "length") == 0) { char buf[TCL_INTEGER_SPACE]; if (argc != 2) { goto wrongNumArgs; } TclFormatInt(buf, Tcl_DStringLength(&dstring)); Tcl_SetResult(interp, buf, TCL_VOLATILE); } else if (strcmp(argv[1], "result") == 0) { if (argc != 2) { goto wrongNumArgs; } Tcl_DStringResult(interp, &dstring); } else if (strcmp(argv[1], "trunc") == 0) { if (argc != 3) { goto wrongNumArgs; } if (Tcl_GetInt(interp, argv[2], &count) != TCL_OK) { return TCL_ERROR; } Tcl_DStringTrunc(&dstring, count); } else if (strcmp(argv[1], "start") == 0) { if (argc != 2) { goto wrongNumArgs; } Tcl_DStringStartSublist(&dstring); } else { Tcl_AppendResult(interp, "bad option \"", argv[1], "\": must be append, element, end, free, get, length, ", "result, trunc, or start", (char *) NULL); return TCL_ERROR; } return TCL_OK; } /* * The procedure below is used as a special freeProc to test how well * Tcl_DStringGetResult handles freeProc's other than free. */ static void SpecialFree(blockPtr) char *blockPtr; /* Block to free. */ { ckfree(blockPtr - 4); } /* *---------------------------------------------------------------------- * * TestencodingCmd -- * * This procedure implements the "testencoding" command. It is used * to test the encoding package. * * Results: * A standard Tcl result. * * Side effects: * Load encodings. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int TestencodingObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Tcl_Encoding encoding; int index, length; char *string; TclEncoding *encodingPtr; static CONST char *optionStrings[] = { "create", "delete", "path", NULL }; enum options { ENC_CREATE, ENC_DELETE, ENC_PATH }; if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0, &index) != TCL_OK) { return TCL_ERROR; } switch ((enum options) index) { case ENC_CREATE: { Tcl_EncodingType type; if (objc != 5) { return TCL_ERROR; } encodingPtr = (TclEncoding *) ckalloc(sizeof(TclEncoding)); encodingPtr->interp = interp; string = Tcl_GetStringFromObj(objv[3], &length); encodingPtr->toUtfCmd = (char *) ckalloc((unsigned) (length + 1)); memcpy(encodingPtr->toUtfCmd, string, (unsigned) length + 1); string = Tcl_GetStringFromObj(objv[4], &length); encodingPtr->fromUtfCmd = (char *) ckalloc((unsigned) (length + 1)); memcpy(encodingPtr->fromUtfCmd, string, (unsigned) (length + 1)); string = Tcl_GetStringFromObj(objv[2], &length); type.encodingName = string; type.toUtfProc = EncodingToUtfProc; type.fromUtfProc = EncodingFromUtfProc; type.freeProc = EncodingFreeProc; type.clientData = (ClientData) encodingPtr; type.nullSize = 1; Tcl_CreateEncoding(&type); break; } case ENC_DELETE: { if (objc != 3) { return TCL_ERROR; } encoding = Tcl_GetEncoding(NULL, Tcl_GetString(objv[2])); Tcl_FreeEncoding(encoding); Tcl_FreeEncoding(encoding); break; } case ENC_PATH: { if (objc == 2) { Tcl_SetObjResult(interp, TclGetLibraryPath()); } else { TclSetLibraryPath(objv[2]); } break; } } return TCL_OK; } static int EncodingToUtfProc(clientData, src, srcLen, flags, statePtr, dst, dstLen, srcReadPtr, dstWrotePtr, dstCharsPtr) ClientData clientData; /* TclEncoding structure. */ CONST char *src; /* Source string in specified encoding. */ int srcLen; /* Source string length in bytes. */ int flags; /* Conversion control flags. */ Tcl_EncodingState *statePtr;/* Current state. */ char *dst; /* Output buffer. */ int dstLen; /* The maximum length of output buffer. */ int *srcReadPtr; /* Filled with number of bytes read. */ int *dstWrotePtr; /* Filled with number of bytes stored. */ int *dstCharsPtr; /* Filled with number of chars stored. */ { int len; TclEncoding *encodingPtr; encodingPtr = (TclEncoding *) clientData; Tcl_GlobalEval(encodingPtr->interp, encodingPtr->toUtfCmd); len = strlen(Tcl_GetStringResult(encodingPtr->interp)); if (len > dstLen) { len = dstLen; } memcpy(dst, Tcl_GetStringResult(encodingPtr->interp), (unsigned) len); Tcl_ResetResult(encodingPtr->interp); *srcReadPtr = srcLen; *dstWrotePtr = len; *dstCharsPtr = len; return TCL_OK; } static int EncodingFromUtfProc(clientData, src, srcLen, flags, statePtr, dst, dstLen, srcReadPtr, dstWrotePtr, dstCharsPtr) ClientData clientData; /* TclEncoding structure. */ CONST char *src; /* Source string in specified encoding. */ int srcLen; /* Source string length in bytes. */ int flags; /* Conversion control flags. */ Tcl_EncodingState *statePtr;/* Current state. */ char *dst; /* Output buffer. */ int dstLen; /* The maximum length of output buffer. */ int *srcReadPtr; /* Filled with number of bytes read. */ int *dstWrotePtr; /* Filled with number of bytes stored. */ int *dstCharsPtr; /* Filled with number of chars stored. */ { int len; TclEncoding *encodingPtr; encodingPtr = (TclEncoding *) clientData; Tcl_GlobalEval(encodingPtr->interp, encodingPtr->fromUtfCmd); len = strlen(Tcl_GetStringResult(encodingPtr->interp)); if (len > dstLen) { len = dstLen; } memcpy(dst, Tcl_GetStringResult(encodingPtr->interp), (unsigned) len); Tcl_ResetResult(encodingPtr->interp); *srcReadPtr = srcLen; *dstWrotePtr = len; *dstCharsPtr = len; return TCL_OK; } static void EncodingFreeProc(clientData) ClientData clientData; /* ClientData associated with type. */ { TclEncoding *encodingPtr; encodingPtr = (TclEncoding *) clientData; ckfree((char *) encodingPtr->toUtfCmd); ckfree((char *) encodingPtr->fromUtfCmd); ckfree((char *) encodingPtr); } /* *---------------------------------------------------------------------- * * TestevalexObjCmd -- * * This procedure implements the "testevalex" command. It is * used to test Tcl_EvalEx. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TestevalexObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Interp *iPtr = (Interp *) interp; int code, oldFlags, length, flags; char *string; if (objc == 1) { /* * The command was invoked with no arguments, so just toggle * the flag that determines whether we use Tcl_EvalEx. */ if (iPtr->flags & USE_EVAL_DIRECT) { iPtr->flags &= ~USE_EVAL_DIRECT; Tcl_SetResult(interp, "disabling direct evaluation", TCL_STATIC); } else { iPtr->flags |= USE_EVAL_DIRECT; Tcl_SetResult(interp, "enabling direct evaluation", TCL_STATIC); } return TCL_OK; } flags = 0; if (objc == 3) { string = Tcl_GetStringFromObj(objv[2], &length); if (strcmp(string, "global") != 0) { Tcl_AppendResult(interp, "bad value \"", string, "\": must be global", (char *) NULL); return TCL_ERROR; } flags = TCL_EVAL_GLOBAL; } else if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "script ?global?"); return TCL_ERROR; } Tcl_SetResult(interp, "xxx", TCL_STATIC); /* * Note, we have to set the USE_EVAL_DIRECT flag in the interpreter * in addition to calling Tcl_EvalEx. This is needed so that even nested * commands are evaluated directly. */ oldFlags = iPtr->flags; iPtr->flags |= USE_EVAL_DIRECT; string = Tcl_GetStringFromObj(objv[1], &length); code = Tcl_EvalEx(interp, string, length, flags); iPtr->flags = (iPtr->flags & ~USE_EVAL_DIRECT) | (oldFlags & USE_EVAL_DIRECT); return code; } /* *---------------------------------------------------------------------- * * TestevalobjvObjCmd -- * * This procedure implements the "testevalobjv" command. It is * used to test Tcl_EvalObjv. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TestevalobjvObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int evalGlobal; if (objc < 3) { Tcl_WrongNumArgs(interp, 1, objv, "global word ?word ...?"); return TCL_ERROR; } if (Tcl_GetIntFromObj(interp, objv[1], &evalGlobal) != TCL_OK) { return TCL_ERROR; } return Tcl_EvalObjv(interp, objc-2, objv+2, (evalGlobal) ? TCL_EVAL_GLOBAL : 0); } /* *---------------------------------------------------------------------- * * TesteventObjCmd -- * * This procedure implements a 'testevent' command. The command * is used to test event queue management. * * The command takes two forms: * - testevent queue name position script * Queues an event at the given position in the queue, and * associates a given name with it (the same name may be * associated with multiple events). When the event comes * to the head of the queue, executes the given script at * global level in the current interp. The position may be * one of 'head', 'tail' or 'mark'. * - testevent delete name * Deletes any events associated with the given name from * the queue. * * Return value: * Returns a standard Tcl result. * * Side effects: * Manipulates the event queue as directed. * *---------------------------------------------------------------------- */ static int TesteventObjCmd( ClientData unused, /* Not used */ Tcl_Interp* interp, /* Tcl interpreter */ int objc, /* Parameter count */ Tcl_Obj *CONST objv[] ) /* Parameter vector */ { static CONST char* subcommands[] = { /* Possible subcommands */ "queue", "delete", NULL }; int subCmdIndex; /* Index of the chosen subcommand */ static CONST char* positions[] = { /* Possible queue positions */ "head", "tail", "mark", NULL }; int posIndex; /* Index of the chosen position */ static CONST Tcl_QueuePosition posNum[] = { /* Interpretation of the chosen position */ TCL_QUEUE_HEAD, TCL_QUEUE_TAIL, TCL_QUEUE_MARK }; TestEvent* ev; /* Event to be queued */ if ( objc < 2 ) { Tcl_WrongNumArgs( interp, 1, objv, "subcommand ?args?" ); return TCL_ERROR; } if ( Tcl_GetIndexFromObj( interp, objv[1], subcommands, "subcommand", TCL_EXACT, &subCmdIndex ) != TCL_OK ) { return TCL_ERROR; } switch ( subCmdIndex ) { case 0: /* queue */ if ( objc != 5 ) { Tcl_WrongNumArgs( interp, 2, objv, "name position script" ); return TCL_ERROR; } if ( Tcl_GetIndexFromObj( interp, objv[3], positions, "position specifier", TCL_EXACT, &posIndex ) != TCL_OK ) { return TCL_ERROR; } ev = (TestEvent*) ckalloc( sizeof( TestEvent ) ); ev->header.proc = TesteventProc; ev->header.nextPtr = NULL; ev->interp = interp; ev->command = objv[ 4 ]; Tcl_IncrRefCount( ev->command ); ev->tag = objv[ 2 ]; Tcl_IncrRefCount( ev->tag ); Tcl_QueueEvent( (Tcl_Event*) ev, posNum[ posIndex ] ); break; case 1: /* delete */ if ( objc != 3 ) { Tcl_WrongNumArgs( interp, 2, objv, "name" ); return TCL_ERROR; } Tcl_DeleteEvents( TesteventDeleteProc, objv[ 2 ] ); break; } return TCL_OK; } /* *---------------------------------------------------------------------- * * TesteventProc -- * * Delivers a test event to the Tcl interpreter as part of event * queue testing. * * Results: * Returns 1 if the event has been serviced, 0 otherwise. * * Side effects: * Evaluates the event's callback script, so has whatever * side effects the callback has. The return value of the * callback script becomes the return value of this function. * If the callback script reports an error, it is reported as * a background error. * *---------------------------------------------------------------------- */ static int TesteventProc( Tcl_Event* event, /* Event to deliver */ int flags ) /* Current flags for Tcl_ServiceEvent */ { TestEvent * ev = (TestEvent *) event; Tcl_Interp* interp = ev->interp; Tcl_Obj* command = ev->command; int result = Tcl_EvalObjEx( interp, command, TCL_EVAL_GLOBAL | TCL_EVAL_DIRECT ); int retval; if ( result != TCL_OK ) { Tcl_AddErrorInfo( interp, " (command bound to \"testevent\" callback)" ); Tcl_BackgroundError( interp ); return 1; /* Avoid looping on errors */ } if ( Tcl_GetBooleanFromObj( interp, Tcl_GetObjResult( interp ), &retval ) != TCL_OK ) { Tcl_AddErrorInfo( interp, " (return value from \"testevent\" callback)" ); Tcl_BackgroundError( interp ); return 1; } if ( retval ) { Tcl_DecrRefCount( ev->tag ); Tcl_DecrRefCount( ev->command ); } return retval; } /* *---------------------------------------------------------------------- * * TesteventDeleteProc -- * * Removes some set of events from the queue. * * This procedure is used as part of testing event queue management. * * Results: * Returns 1 if a given event should be deleted, 0 otherwise. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TesteventDeleteProc( Tcl_Event* event, /* Event to examine */ ClientData clientData ) /* Tcl_Obj containing the name * of the event(s) to remove */ { TestEvent* ev; /* Event to examine */ char* evNameStr; Tcl_Obj* targetName; /* Name of the event(s) to delete */ char* targetNameStr; if ( event->proc != TesteventProc ) { return 0; } targetName = (Tcl_Obj*) clientData; targetNameStr = (char*) Tcl_GetStringFromObj( targetName, NULL ); ev = (TestEvent*) event; evNameStr = Tcl_GetStringFromObj( ev->tag, NULL ); if ( strcmp( evNameStr, targetNameStr ) == 0 ) { Tcl_DecrRefCount( ev->tag ); Tcl_DecrRefCount( ev->command ); return 1; } else { return 0; } } /* *---------------------------------------------------------------------- * * TestexithandlerCmd -- * * This procedure implements the "testexithandler" command. It is * used to test Tcl_CreateExitHandler and Tcl_DeleteExitHandler. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TestexithandlerCmd(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { int value; if (argc != 3) { Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0], " create|delete value\"", (char *) NULL); return TCL_ERROR; } if (Tcl_GetInt(interp, argv[2], &value) != TCL_OK) { return TCL_ERROR; } if (strcmp(argv[1], "create") == 0) { Tcl_CreateExitHandler((value & 1) ? ExitProcOdd : ExitProcEven, (ClientData) value); } else if (strcmp(argv[1], "delete") == 0) { Tcl_DeleteExitHandler((value & 1) ? ExitProcOdd : ExitProcEven, (ClientData) value); } else { Tcl_AppendResult(interp, "bad option \"", argv[1], "\": must be create or delete", (char *) NULL); return TCL_ERROR; } return TCL_OK; } static void ExitProcOdd(clientData) ClientData clientData; /* Integer value to print. */ { char buf[16 + TCL_INTEGER_SPACE]; sprintf(buf, "odd %d\n", (int) clientData); write(1, buf, strlen(buf)); } static void ExitProcEven(clientData) ClientData clientData; /* Integer value to print. */ { char buf[16 + TCL_INTEGER_SPACE]; sprintf(buf, "even %d\n", (int) clientData); write(1, buf, strlen(buf)); } /* *---------------------------------------------------------------------- * * TestexprlongCmd -- * * This procedure verifies that Tcl_ExprLong does not modify the * interpreter result if there is no error. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TestexprlongCmd(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { long exprResult; char buf[4 + TCL_INTEGER_SPACE]; int result; Tcl_SetResult(interp, "This is a result", TCL_STATIC); result = Tcl_ExprLong(interp, "4+1", &exprResult); if (result != TCL_OK) { return result; } sprintf(buf, ": %ld", exprResult); Tcl_AppendResult(interp, buf, NULL); return TCL_OK; } /* *---------------------------------------------------------------------- * * TestexprlongobjCmd -- * * This procedure verifies that Tcl_ExprLongObj does not modify the * interpreter result if there is no error. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TestexprlongobjCmd(clientData, interp, objc, objv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST *objv; /* Argument objects. */ { long exprResult; char buf[4 + TCL_INTEGER_SPACE]; int result; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "expression"); return TCL_ERROR; } Tcl_SetResult(interp, "This is a result", TCL_STATIC); result = Tcl_ExprLongObj(interp, objv[1], &exprResult); if (result != TCL_OK) { return result; } sprintf(buf, ": %ld", exprResult); Tcl_AppendResult(interp, buf, NULL); return TCL_OK; } /* *---------------------------------------------------------------------- * * TestexprstringCmd -- * * This procedure tests the basic operation of Tcl_ExprString. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TestexprstringCmd(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { if (argc != 2) { Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0], " expression\"", (char *) NULL); return TCL_ERROR; } return Tcl_ExprString(interp, argv[1]); } /* *---------------------------------------------------------------------- * * TestfilelinkCmd -- * * This procedure implements the "testfilelink" command. It is used * to test the effects of creating and manipulating filesystem links * in Tcl. * * Results: * A standard Tcl result. * * Side effects: * May create a link on disk. * *---------------------------------------------------------------------- */ static int TestfilelinkCmd(clientData, interp, objc, objv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* The argument objects. */ { Tcl_Obj *contents; if (objc < 2 || objc > 3) { Tcl_WrongNumArgs(interp, 1, objv, "source ?target?"); return TCL_ERROR; } if (Tcl_FSConvertToPathType(interp, objv[1]) != TCL_OK) { return TCL_ERROR; } if (objc == 3) { /* Create link from source to target */ contents = Tcl_FSLink(objv[1], objv[2], TCL_CREATE_SYMBOLIC_LINK|TCL_CREATE_HARD_LINK); if (contents == NULL) { Tcl_AppendResult(interp, "could not create link from \"", Tcl_GetString(objv[1]), "\" to \"", Tcl_GetString(objv[2]), "\": ", Tcl_PosixError(interp), (char *) NULL); return TCL_ERROR; } } else { /* Read link */ contents = Tcl_FSLink(objv[1], NULL, 0); if (contents == NULL) { Tcl_AppendResult(interp, "could not read link \"", Tcl_GetString(objv[1]), "\": ", Tcl_PosixError(interp), (char *) NULL); return TCL_ERROR; } } Tcl_SetObjResult(interp, contents); if (objc == 2) { /* * If we are creating a link, this will actually just * be objv[3], and we don't own it */ Tcl_DecrRefCount(contents); } return TCL_OK; } /* *---------------------------------------------------------------------- * * TestgetassocdataCmd -- * * This procedure implements the "testgetassocdata" command. It is * used to test Tcl_GetAssocData. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TestgetassocdataCmd(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { char *res; if (argc != 2) { Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0], " data_key\"", (char *) NULL); return TCL_ERROR; } res = (char *) Tcl_GetAssocData(interp, argv[1], NULL); if (res != NULL) { Tcl_AppendResult(interp, res, NULL); } return TCL_OK; } /* *---------------------------------------------------------------------- * * TestgetplatformCmd -- * * This procedure implements the "testgetplatform" command. It is * used to retrievel the value of the tclPlatform global variable. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TestgetplatformCmd(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { static CONST char *platformStrings[] = { "unix", "mac", "windows" }; TclPlatformType *platform; #if defined(__WIN32__) || defined(__CYGWIN__) platform = TclWinGetPlatform(); #else platform = &tclPlatform; #endif if (argc != 1) { Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0], (char *) NULL); return TCL_ERROR; } Tcl_AppendResult(interp, platformStrings[*platform], NULL); return TCL_OK; } /* *---------------------------------------------------------------------- * * TestinterpdeleteCmd -- * * This procedure tests the code in tclInterp.c that deals with * interpreter deletion. It deletes a user-specified interpreter * from the hierarchy, and subsequent code checks integrity. * * Results: * A standard Tcl result. * * Side effects: * Deletes one or more interpreters. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int TestinterpdeleteCmd(dummy, interp, argc, argv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { Tcl_Interp *slaveToDelete; if (argc != 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " path\"", (char *) NULL); return TCL_ERROR; } slaveToDelete = Tcl_GetSlave(interp, argv[1]); if (slaveToDelete == (Tcl_Interp *) NULL) { return TCL_ERROR; } Tcl_DeleteInterp(slaveToDelete); return TCL_OK; } /* *---------------------------------------------------------------------- * * TestlinkCmd -- * * This procedure implements the "testlink" command. It is used * to test Tcl_LinkVar and related library procedures. * * Results: * A standard Tcl result. * * Side effects: * Creates and deletes various variable links, plus returns * values of the linked variables. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int TestlinkCmd(dummy, interp, argc, argv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { static int intVar = 43; static int boolVar = 4; static double realVar = 1.23; static Tcl_WideInt wideVar = Tcl_LongAsWide(79); static char *stringVar = NULL; static int created = 0; char buffer[2*TCL_DOUBLE_SPACE]; int writable, flag; Tcl_Obj *tmp; if (argc < 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " option ?arg arg arg arg arg?\"", (char *) NULL); return TCL_ERROR; } if (strcmp(argv[1], "create") == 0) { if (argc != 7) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ", argv[1], " intRO realRO boolRO stringRO wideRO\"", (char *) NULL); return TCL_ERROR; } if (created) { Tcl_UnlinkVar(interp, "int"); Tcl_UnlinkVar(interp, "real"); Tcl_UnlinkVar(interp, "bool"); Tcl_UnlinkVar(interp, "string"); Tcl_UnlinkVar(interp, "wide"); } created = 1; if (Tcl_GetBoolean(interp, argv[2], &writable) != TCL_OK) { return TCL_ERROR; } flag = (writable != 0) ? 0 : TCL_LINK_READ_ONLY; if (Tcl_LinkVar(interp, "int", (char *) &intVar, TCL_LINK_INT | flag) != TCL_OK) { return TCL_ERROR; } if (Tcl_GetBoolean(interp, argv[3], &writable) != TCL_OK) { return TCL_ERROR; } flag = (writable != 0) ? 0 : TCL_LINK_READ_ONLY; if (Tcl_LinkVar(interp, "real", (char *) &realVar, TCL_LINK_DOUBLE | flag) != TCL_OK) { return TCL_ERROR; } if (Tcl_GetBoolean(interp, argv[4], &writable) != TCL_OK) { return TCL_ERROR; } flag = (writable != 0) ? 0 : TCL_LINK_READ_ONLY; if (Tcl_LinkVar(interp, "bool", (char *) &boolVar, TCL_LINK_BOOLEAN | flag) != TCL_OK) { return TCL_ERROR; } if (Tcl_GetBoolean(interp, argv[5], &writable) != TCL_OK) { return TCL_ERROR; } flag = (writable != 0) ? 0 : TCL_LINK_READ_ONLY; if (Tcl_LinkVar(interp, "string", (char *) &stringVar, TCL_LINK_STRING | flag) != TCL_OK) { return TCL_ERROR; } if (Tcl_GetBoolean(interp, argv[6], &writable) != TCL_OK) { return TCL_ERROR; } flag = (writable != 0) ? 0 : TCL_LINK_READ_ONLY; if (Tcl_LinkVar(interp, "wide", (char *) &wideVar, TCL_LINK_WIDE_INT | flag) != TCL_OK) { return TCL_ERROR; } } else if (strcmp(argv[1], "delete") == 0) { Tcl_UnlinkVar(interp, "int"); Tcl_UnlinkVar(interp, "real"); Tcl_UnlinkVar(interp, "bool"); Tcl_UnlinkVar(interp, "string"); Tcl_UnlinkVar(interp, "wide"); created = 0; } else if (strcmp(argv[1], "get") == 0) { TclFormatInt(buffer, intVar); Tcl_AppendElement(interp, buffer); Tcl_PrintDouble((Tcl_Interp *) NULL, realVar, buffer); Tcl_AppendElement(interp, buffer); TclFormatInt(buffer, boolVar); Tcl_AppendElement(interp, buffer); Tcl_AppendElement(interp, (stringVar == NULL) ? "-" : stringVar); /* * Wide ints only have an object-based interface. */ tmp = Tcl_NewWideIntObj(wideVar); Tcl_AppendElement(interp, Tcl_GetString(tmp)); Tcl_DecrRefCount(tmp); } else if (strcmp(argv[1], "set") == 0) { if (argc != 7) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ", argv[1], " intValue realValue boolValue stringValue wideValue\"", (char *) NULL); return TCL_ERROR; } if (argv[2][0] != 0) { if (Tcl_GetInt(interp, argv[2], &intVar) != TCL_OK) { return TCL_ERROR; } } if (argv[3][0] != 0) { if (Tcl_GetDouble(interp, argv[3], &realVar) != TCL_OK) { return TCL_ERROR; } } if (argv[4][0] != 0) { if (Tcl_GetInt(interp, argv[4], &boolVar) != TCL_OK) { return TCL_ERROR; } } if (argv[5][0] != 0) { if (stringVar != NULL) { ckfree(stringVar); } if (strcmp(argv[5], "-") == 0) { stringVar = NULL; } else { stringVar = (char *) ckalloc((unsigned) (strlen(argv[5]) + 1)); strcpy(stringVar, argv[5]); } } if (argv[6][0] != 0) { tmp = Tcl_NewStringObj(argv[6], -1); if (Tcl_GetWideIntFromObj(interp, tmp, &wideVar) != TCL_OK) { Tcl_DecrRefCount(tmp); return TCL_ERROR; } Tcl_DecrRefCount(tmp); } } else if (strcmp(argv[1], "update") == 0) { if (argc != 7) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ", argv[1], "intValue realValue boolValue stringValue wideValue\"", (char *) NULL); return TCL_ERROR; } if (argv[2][0] != 0) { if (Tcl_GetInt(interp, argv[2], &intVar) != TCL_OK) { return TCL_ERROR; } Tcl_UpdateLinkedVar(interp, "int"); } if (argv[3][0] != 0) { if (Tcl_GetDouble(interp, argv[3], &realVar) != TCL_OK) { return TCL_ERROR; } Tcl_UpdateLinkedVar(interp, "real"); } if (argv[4][0] != 0) { if (Tcl_GetInt(interp, argv[4], &boolVar) != TCL_OK) { return TCL_ERROR; } Tcl_UpdateLinkedVar(interp, "bool"); } if (argv[5][0] != 0) { if (stringVar != NULL) { ckfree(stringVar); } if (strcmp(argv[5], "-") == 0) { stringVar = NULL; } else { stringVar = (char *) ckalloc((unsigned) (strlen(argv[5]) + 1)); strcpy(stringVar, argv[5]); } Tcl_UpdateLinkedVar(interp, "string"); } if (argv[6][0] != 0) { tmp = Tcl_NewStringObj(argv[6], -1); if (Tcl_GetWideIntFromObj(interp, tmp, &wideVar) != TCL_OK) { Tcl_DecrRefCount(tmp); return TCL_ERROR; } Tcl_DecrRefCount(tmp); Tcl_UpdateLinkedVar(interp, "wide"); } } else { Tcl_AppendResult(interp, "bad option \"", argv[1], "\": should be create, delete, get, set, or update", (char *) NULL); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * TestlocaleCmd -- * * This procedure implements the "testlocale" command. It is used * to test the effects of setting different locales in Tcl. * * Results: * A standard Tcl result. * * Side effects: * Modifies the current C locale. * *---------------------------------------------------------------------- */ static int TestlocaleCmd(clientData, interp, objc, objv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* The argument objects. */ { int index; char *locale; static CONST char *optionStrings[] = { "ctype", "numeric", "time", "collate", "monetary", "all", NULL }; static CONST int lcTypes[] = { LC_CTYPE, LC_NUMERIC, LC_TIME, LC_COLLATE, LC_MONETARY, LC_ALL }; /* * LC_CTYPE, etc. correspond to the indices for the strings. */ if (objc < 2 || objc > 3) { Tcl_WrongNumArgs(interp, 1, objv, "category ?locale?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0, &index) != TCL_OK) { return TCL_ERROR; } if (objc == 3) { locale = Tcl_GetString(objv[2]); } else { locale = NULL; } locale = setlocale(lcTypes[index], locale); if (locale) { Tcl_SetStringObj(Tcl_GetObjResult(interp), locale, -1); } return TCL_OK; } /* *---------------------------------------------------------------------- * * TestMathFunc -- * * This is a user-defined math procedure to test out math procedures * with no arguments. * * Results: * A normal Tcl completion code. * * Side effects: * None. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int TestMathFunc(clientData, interp, args, resultPtr) ClientData clientData; /* Integer value to return. */ Tcl_Interp *interp; /* Not used. */ Tcl_Value *args; /* Not used. */ Tcl_Value *resultPtr; /* Where to store result. */ { resultPtr->type = TCL_INT; resultPtr->intValue = (int) clientData; return TCL_OK; } /* *---------------------------------------------------------------------- * * TestMathFunc2 -- * * This is a user-defined math procedure to test out math procedures * that do have arguments, in this case 2. * * Results: * A normal Tcl completion code. * * Side effects: * None. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int TestMathFunc2(clientData, interp, args, resultPtr) ClientData clientData; /* Integer value to return. */ Tcl_Interp *interp; /* Used to report errors. */ Tcl_Value *args; /* Points to an array of two * Tcl_Value structs for the * two arguments. */ Tcl_Value *resultPtr; /* Where to store the result. */ { int result = TCL_OK; /* * Return the maximum of the two arguments with the correct type. */ if (args[0].type == TCL_INT) { int i0 = args[0].intValue; if (args[1].type == TCL_INT) { int i1 = args[1].intValue; resultPtr->type = TCL_INT; resultPtr->intValue = ((i0 > i1)? i0 : i1); } else if (args[1].type == TCL_DOUBLE) { double d0 = i0; double d1 = args[1].doubleValue; resultPtr->type = TCL_DOUBLE; resultPtr->doubleValue = ((d0 > d1)? d0 : d1); } else if (args[1].type == TCL_WIDE_INT) { Tcl_WideInt w0 = Tcl_LongAsWide(i0); Tcl_WideInt w1 = args[1].wideValue; resultPtr->type = TCL_WIDE_INT; resultPtr->wideValue = ((w0 > w1)? w0 : w1); } else { Tcl_SetResult(interp, "T3: wrong type for arg 2", TCL_STATIC); result = TCL_ERROR; } } else if (args[0].type == TCL_DOUBLE) { double d0 = args[0].doubleValue; if (args[1].type == TCL_INT) { double d1 = args[1].intValue; resultPtr->type = TCL_DOUBLE; resultPtr->doubleValue = ((d0 > d1)? d0 : d1); } else if (args[1].type == TCL_DOUBLE) { double d1 = args[1].doubleValue; resultPtr->type = TCL_DOUBLE; resultPtr->doubleValue = ((d0 > d1)? d0 : d1); } else if (args[1].type == TCL_WIDE_INT) { double d1 = Tcl_WideAsDouble(args[1].wideValue); resultPtr->type = TCL_DOUBLE; resultPtr->doubleValue = ((d0 > d1)? d0 : d1); } else { Tcl_SetResult(interp, "T3: wrong type for arg 2", TCL_STATIC); result = TCL_ERROR; } } else if (args[0].type == TCL_WIDE_INT) { Tcl_WideInt w0 = args[0].wideValue; if (args[1].type == TCL_INT) { Tcl_WideInt w1 = Tcl_LongAsWide(args[1].intValue); resultPtr->type = TCL_WIDE_INT; resultPtr->wideValue = ((w0 > w1)? w0 : w1); } else if (args[1].type == TCL_DOUBLE) { double d0 = Tcl_WideAsDouble(w0); double d1 = args[1].doubleValue; resultPtr->type = TCL_DOUBLE; resultPtr->doubleValue = ((d0 > d1)? d0 : d1); } else if (args[1].type == TCL_WIDE_INT) { Tcl_WideInt w1 = args[1].wideValue; resultPtr->type = TCL_WIDE_INT; resultPtr->wideValue = ((w0 > w1)? w0 : w1); } else { Tcl_SetResult(interp, "T3: wrong type for arg 2", TCL_STATIC); result = TCL_ERROR; } } else { Tcl_SetResult(interp, "T3: wrong type for arg 1", TCL_STATIC); result = TCL_ERROR; } return result; } /* *---------------------------------------------------------------------- * * CleanupTestSetassocdataTests -- * * This function is called when an interpreter is deleted to clean * up any data left over from running the testsetassocdata command. * * Results: * None. * * Side effects: * Releases storage. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static void CleanupTestSetassocdataTests(clientData, interp) ClientData clientData; /* Data to be released. */ Tcl_Interp *interp; /* Interpreter being deleted. */ { ckfree((char *) clientData); } /* *---------------------------------------------------------------------- * * TestparserObjCmd -- * * This procedure implements the "testparser" command. It is * used for testing the new Tcl script parser in Tcl 8.1. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TestparserObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* The argument objects. */ { char *script; int length, dummy; Tcl_Parse parse; if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "script length"); return TCL_ERROR; } script = Tcl_GetStringFromObj(objv[1], &dummy); if (Tcl_GetIntFromObj(interp, objv[2], &length)) { return TCL_ERROR; } if (length == 0) { length = dummy; } if (Tcl_ParseCommand(interp, script, length, 0, &parse) != TCL_OK) { Tcl_AddErrorInfo(interp, "\n (remainder of script: \""); Tcl_AddErrorInfo(interp, parse.term); Tcl_AddErrorInfo(interp, "\")"); return TCL_ERROR; } /* * The parse completed successfully. Just print out the contents * of the parse structure into the interpreter's result. */ PrintParse(interp, &parse); Tcl_FreeParse(&parse); return TCL_OK; } /* *---------------------------------------------------------------------- * * TestexprparserObjCmd -- * * This procedure implements the "testexprparser" command. It is * used for testing the new Tcl expression parser in Tcl 8.1. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TestexprparserObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* The argument objects. */ { char *script; int length, dummy; Tcl_Parse parse; if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "expr length"); return TCL_ERROR; } script = Tcl_GetStringFromObj(objv[1], &dummy); if (Tcl_GetIntFromObj(interp, objv[2], &length)) { return TCL_ERROR; } if (length == 0) { length = dummy; } if (Tcl_ParseExpr(interp, script, length, &parse) != TCL_OK) { Tcl_AddErrorInfo(interp, "\n (remainder of expr: \""); Tcl_AddErrorInfo(interp, parse.term); Tcl_AddErrorInfo(interp, "\")"); return TCL_ERROR; } /* * The parse completed successfully. Just print out the contents * of the parse structure into the interpreter's result. */ PrintParse(interp, &parse); Tcl_FreeParse(&parse); return TCL_OK; } /* *---------------------------------------------------------------------- * * PrintParse -- * * This procedure prints out the contents of a Tcl_Parse structure * in the result of an interpreter. * * Results: * Interp's result is set to a prettily formatted version of the * contents of parsePtr. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void PrintParse(interp, parsePtr) Tcl_Interp *interp; /* Interpreter whose result is to be set to * the contents of a parse structure. */ Tcl_Parse *parsePtr; /* Parse structure to print out. */ { Tcl_Obj *objPtr; char *typeString; Tcl_Token *tokenPtr; int i; objPtr = Tcl_GetObjResult(interp); if (parsePtr->commentSize > 0) { Tcl_ListObjAppendElement((Tcl_Interp *) NULL, objPtr, Tcl_NewStringObj(parsePtr->commentStart, parsePtr->commentSize)); } else { Tcl_ListObjAppendElement((Tcl_Interp *) NULL, objPtr, Tcl_NewStringObj("-", 1)); } Tcl_ListObjAppendElement((Tcl_Interp *) NULL, objPtr, Tcl_NewStringObj(parsePtr->commandStart, parsePtr->commandSize)); Tcl_ListObjAppendElement((Tcl_Interp *) NULL, objPtr, Tcl_NewIntObj(parsePtr->numWords)); for (i = 0; i < parsePtr->numTokens; i++) { tokenPtr = &parsePtr->tokenPtr[i]; switch (tokenPtr->type) { case TCL_TOKEN_WORD: typeString = "word"; break; case TCL_TOKEN_SIMPLE_WORD: typeString = "simple"; break; case TCL_TOKEN_TEXT: typeString = "text"; break; case TCL_TOKEN_BS: typeString = "backslash"; break; case TCL_TOKEN_COMMAND: typeString = "command"; break; case TCL_TOKEN_VARIABLE: typeString = "variable"; break; case TCL_TOKEN_SUB_EXPR: typeString = "subexpr"; break; case TCL_TOKEN_OPERATOR: typeString = "operator"; break; default: typeString = "??"; break; } Tcl_ListObjAppendElement((Tcl_Interp *) NULL, objPtr, Tcl_NewStringObj(typeString, -1)); Tcl_ListObjAppendElement((Tcl_Interp *) NULL, objPtr, Tcl_NewStringObj(tokenPtr->start, tokenPtr->size)); Tcl_ListObjAppendElement((Tcl_Interp *) NULL, objPtr, Tcl_NewIntObj(tokenPtr->numComponents)); } Tcl_ListObjAppendElement((Tcl_Interp *) NULL, objPtr, Tcl_NewStringObj(parsePtr->commandStart + parsePtr->commandSize, -1)); } /* *---------------------------------------------------------------------- * * TestparsevarObjCmd -- * * This procedure implements the "testparsevar" command. It is * used for testing Tcl_ParseVar. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TestparsevarObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* The argument objects. */ { CONST char *value; CONST char *name, *termPtr; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "varName"); return TCL_ERROR; } name = Tcl_GetString(objv[1]); value = Tcl_ParseVar(interp, name, &termPtr); if (value == NULL) { return TCL_ERROR; } Tcl_AppendElement(interp, value); Tcl_AppendElement(interp, termPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * TestparsevarnameObjCmd -- * * This procedure implements the "testparsevarname" command. It is * used for testing the new Tcl script parser in Tcl 8.1. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TestparsevarnameObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* The argument objects. */ { char *script; int append, length, dummy; Tcl_Parse parse; if (objc != 4) { Tcl_WrongNumArgs(interp, 1, objv, "script length append"); return TCL_ERROR; } script = Tcl_GetStringFromObj(objv[1], &dummy); if (Tcl_GetIntFromObj(interp, objv[2], &length)) { return TCL_ERROR; } if (length == 0) { length = dummy; } if (Tcl_GetIntFromObj(interp, objv[3], &append)) { return TCL_ERROR; } if (Tcl_ParseVarName(interp, script, length, &parse, append) != TCL_OK) { Tcl_AddErrorInfo(interp, "\n (remainder of script: \""); Tcl_AddErrorInfo(interp, parse.term); Tcl_AddErrorInfo(interp, "\")"); return TCL_ERROR; } /* * The parse completed successfully. Just print out the contents * of the parse structure into the interpreter's result. */ parse.commentSize = 0; parse.commandStart = script + parse.tokenPtr->size; parse.commandSize = 0; PrintParse(interp, &parse); Tcl_FreeParse(&parse); return TCL_OK; } /* *---------------------------------------------------------------------- * * TestregexpObjCmd -- * * This procedure implements the "testregexp" command. It is * used to give a direct interface for regexp flags. It's identical * to Tcl_RegexpObjCmd except for the -xflags option, and the * consequences thereof (including the REG_EXPECT kludge). * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int TestregexpObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int i, ii, indices, stringLength, match, about; int hasxflags, cflags, eflags; Tcl_RegExp regExpr; char *string; Tcl_Obj *objPtr; Tcl_RegExpInfo info; static CONST char *options[] = { "-indices", "-nocase", "-about", "-expanded", "-line", "-linestop", "-lineanchor", "-xflags", "--", (char *) NULL }; enum options { REGEXP_INDICES, REGEXP_NOCASE, REGEXP_ABOUT, REGEXP_EXPANDED, REGEXP_MULTI, REGEXP_NOCROSS, REGEXP_NEWL, REGEXP_XFLAGS, REGEXP_LAST }; indices = 0; about = 0; cflags = REG_ADVANCED; eflags = 0; hasxflags = 0; for (i = 1; i < objc; i++) { char *name; int index; name = Tcl_GetString(objv[i]); if (name[0] != '-') { break; } if (Tcl_GetIndexFromObj(interp, objv[i], options, "switch", TCL_EXACT, &index) != TCL_OK) { return TCL_ERROR; } switch ((enum options) index) { case REGEXP_INDICES: { indices = 1; break; } case REGEXP_NOCASE: { cflags |= REG_ICASE; break; } case REGEXP_ABOUT: { about = 1; break; } case REGEXP_EXPANDED: { cflags |= REG_EXPANDED; break; } case REGEXP_MULTI: { cflags |= REG_NEWLINE; break; } case REGEXP_NOCROSS: { cflags |= REG_NLSTOP; break; } case REGEXP_NEWL: { cflags |= REG_NLANCH; break; } case REGEXP_XFLAGS: { hasxflags = 1; break; } case REGEXP_LAST: { i++; goto endOfForLoop; } } } endOfForLoop: if (objc - i < hasxflags + 2 - about) { Tcl_WrongNumArgs(interp, 1, objv, "?switches? exp string ?matchVar? ?subMatchVar subMatchVar ...?"); return TCL_ERROR; } objc -= i; objv += i; if (hasxflags) { string = Tcl_GetStringFromObj(objv[0], &stringLength); TestregexpXflags(string, stringLength, &cflags, &eflags); objc--; objv++; } regExpr = Tcl_GetRegExpFromObj(interp, objv[0], cflags); if (regExpr == NULL) { return TCL_ERROR; } objPtr = objv[1]; if (about) { if (TclRegAbout(interp, regExpr) < 0) { return TCL_ERROR; } return TCL_OK; } match = Tcl_RegExpExecObj(interp, regExpr, objPtr, 0 /* offset */, objc-2 /* nmatches */, eflags); if (match < 0) { return TCL_ERROR; } if (match == 0) { /* * Set the interpreter's object result to an integer object w/ * value 0. */ Tcl_SetIntObj(Tcl_GetObjResult(interp), 0); if (objc > 2 && (cflags®_EXPECT) && indices) { char *varName; CONST char *value; int start, end; char resinfo[TCL_INTEGER_SPACE * 2]; varName = Tcl_GetString(objv[2]); TclRegExpRangeUniChar(regExpr, -1, &start, &end); sprintf(resinfo, "%d %d", start, end-1); value = Tcl_SetVar(interp, varName, resinfo, 0); if (value == NULL) { Tcl_AppendResult(interp, "couldn't set variable \"", varName, "\"", (char *) NULL); return TCL_ERROR; } } else if (cflags & TCL_REG_CANMATCH) { char *varName; CONST char *value; char resinfo[TCL_INTEGER_SPACE * 2]; Tcl_RegExpGetInfo(regExpr, &info); varName = Tcl_GetString(objv[2]); sprintf(resinfo, "%ld", info.extendStart); value = Tcl_SetVar(interp, varName, resinfo, 0); if (value == NULL) { Tcl_AppendResult(interp, "couldn't set variable \"", varName, "\"", (char *) NULL); return TCL_ERROR; } } return TCL_OK; } /* * If additional variable names have been specified, return * index information in those variables. */ objc -= 2; objv += 2; Tcl_RegExpGetInfo(regExpr, &info); for (i = 0; i < objc; i++) { int start, end; Tcl_Obj *newPtr, *varPtr, *valuePtr; varPtr = objv[i]; ii = ((cflags®_EXPECT) && i == objc-1) ? -1 : i; if (indices) { Tcl_Obj *objs[2]; if (ii == -1) { TclRegExpRangeUniChar(regExpr, ii, &start, &end); } else if (ii > info.nsubs) { start = -1; end = -1; } else { start = info.matches[ii].start; end = info.matches[ii].end; } /* * Adjust index so it refers to the last character in the * match instead of the first character after the match. */ if (end >= 0) { end--; } objs[0] = Tcl_NewLongObj(start); objs[1] = Tcl_NewLongObj(end); newPtr = Tcl_NewListObj(2, objs); } else { if (ii == -1) { TclRegExpRangeUniChar(regExpr, ii, &start, &end); newPtr = Tcl_GetRange(objPtr, start, end); } else if (ii > info.nsubs) { newPtr = Tcl_NewObj(); } else { newPtr = Tcl_GetRange(objPtr, info.matches[ii].start, info.matches[ii].end - 1); } } Tcl_IncrRefCount(newPtr); valuePtr = Tcl_ObjSetVar2(interp, varPtr, NULL, newPtr, 0); Tcl_DecrRefCount(newPtr); if (valuePtr == NULL) { Tcl_AppendResult(interp, "couldn't set variable \"", Tcl_GetString(varPtr), "\"", (char *) NULL); return TCL_ERROR; } } /* * Set the interpreter's object result to an integer object w/ value 1. */ Tcl_SetIntObj(Tcl_GetObjResult(interp), 1); return TCL_OK; } /* *--------------------------------------------------------------------------- * * TestregexpXflags -- * * Parse a string of extended regexp flag letters, for testing. * * Results: * No return value (you're on your own for errors here). * * Side effects: * Modifies *cflagsPtr, a regcomp flags word, and *eflagsPtr, a * regexec flags word, as appropriate. * *---------------------------------------------------------------------- */ static void TestregexpXflags(string, length, cflagsPtr, eflagsPtr) char *string; /* The string of flags. */ int length; /* The length of the string in bytes. */ int *cflagsPtr; /* compile flags word */ int *eflagsPtr; /* exec flags word */ { int i; int cflags; int eflags; cflags = *cflagsPtr; eflags = *eflagsPtr; for (i = 0; i < length; i++) { switch (string[i]) { case 'a': { cflags |= REG_ADVF; break; } case 'b': { cflags &= ~REG_ADVANCED; break; } case 'c': { cflags |= TCL_REG_CANMATCH; break; } case 'e': { cflags &= ~REG_ADVANCED; cflags |= REG_EXTENDED; break; } case 'q': { cflags &= ~REG_ADVANCED; cflags |= REG_QUOTE; break; } case 'o': { /* o for opaque */ cflags |= REG_NOSUB; break; } case 's': { /* s for start */ cflags |= REG_BOSONLY; break; } case '+': { cflags |= REG_FAKE; break; } case ',': { cflags |= REG_PROGRESS; break; } case '.': { cflags |= REG_DUMP; break; } case ':': { eflags |= REG_MTRACE; break; } case ';': { eflags |= REG_FTRACE; break; } case '^': { eflags |= REG_NOTBOL; break; } case '$': { eflags |= REG_NOTEOL; break; } case 't': { cflags |= REG_EXPECT; break; } case '%': { eflags |= REG_SMALL; break; } } } *cflagsPtr = cflags; *eflagsPtr = eflags; } /* *---------------------------------------------------------------------- * * TestsetassocdataCmd -- * * This procedure implements the "testsetassocdata" command. It is used * to test Tcl_SetAssocData. * * Results: * A standard Tcl result. * * Side effects: * Modifies or creates an association between a key and associated * data for this interpreter. * *---------------------------------------------------------------------- */ static int TestsetassocdataCmd(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { char *buf; char *oldData; Tcl_InterpDeleteProc *procPtr; if (argc != 3) { Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0], " data_key data_item\"", (char *) NULL); return TCL_ERROR; } buf = ckalloc((unsigned) strlen(argv[2]) + 1); strcpy(buf, argv[2]); /* * If we previously associated a malloced value with the variable, * free it before associating a new value. */ oldData = (char *) Tcl_GetAssocData(interp, argv[1], &procPtr); if ((oldData != NULL) && (procPtr == CleanupTestSetassocdataTests)) { ckfree(oldData); } Tcl_SetAssocData(interp, argv[1], CleanupTestSetassocdataTests, (ClientData) buf); return TCL_OK; } /* *---------------------------------------------------------------------- * * TestsetplatformCmd -- * * This procedure implements the "testsetplatform" command. It is * used to change the tclPlatform global variable so all file * name conversions can be tested on a single platform. * * Results: * A standard Tcl result. * * Side effects: * Sets the tclPlatform global variable. * *---------------------------------------------------------------------- */ static int TestsetplatformCmd(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { size_t length; TclPlatformType *platform; #if defined(__WIN32__) || defined(__CYGWIN__) platform = TclWinGetPlatform(); #else platform = &tclPlatform; #endif if (argc != 2) { Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0], " platform\"", (char *) NULL); return TCL_ERROR; } length = strlen(argv[1]); if (strncmp(argv[1], "unix", length) == 0) { *platform = TCL_PLATFORM_UNIX; } else if (strncmp(argv[1], "windows", length) == 0) { *platform = TCL_PLATFORM_WINDOWS; } else { Tcl_AppendResult(interp, "unsupported platform: should be one of ", "unix, mac, or windows", (char *) NULL); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * TeststaticpkgCmd -- * * This procedure implements the "teststaticpkg" command. * It is used to test the procedure Tcl_StaticPackage. * * Results: * A standard Tcl result. * * Side effects: * When the packge given by argv[1] is loaded into an interpeter, * variable "x" in that interpreter is set to "loaded". * *---------------------------------------------------------------------- */ static int TeststaticpkgCmd(dummy, interp, argc, argv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { int safe, loaded; if (argc != 4) { Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0], " pkgName safe loaded\"", (char *) NULL); return TCL_ERROR; } if (Tcl_GetInt(interp, argv[2], &safe) != TCL_OK) { return TCL_ERROR; } if (Tcl_GetInt(interp, argv[3], &loaded) != TCL_OK) { return TCL_ERROR; } Tcl_StaticPackage((loaded) ? interp : NULL, argv[1], StaticInitProc, (safe) ? StaticInitProc : NULL); return TCL_OK; } static int StaticInitProc(interp) Tcl_Interp *interp; /* Interpreter in which package * is supposedly being loaded. */ { Tcl_SetVar(interp, "x", "loaded", TCL_GLOBAL_ONLY); return TCL_OK; } /* *---------------------------------------------------------------------- * * TesttranslatefilenameCmd -- * * This procedure implements the "testtranslatefilename" command. * It is used to test the Tcl_TranslateFileName command. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TesttranslatefilenameCmd(dummy, interp, argc, argv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { Tcl_DString buffer; CONST char *result; if (argc != 2) { Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0], " path\"", (char *) NULL); return TCL_ERROR; } result = Tcl_TranslateFileName(interp, argv[1], &buffer); if (result == NULL) { return TCL_ERROR; } Tcl_AppendResult(interp, result, NULL); Tcl_DStringFree(&buffer); return TCL_OK; } /* *---------------------------------------------------------------------- * * TestupvarCmd -- * * This procedure implements the "testupvar2" command. It is used * to test Tcl_UpVar and Tcl_UpVar2. * * Results: * A standard Tcl result. * * Side effects: * Creates or modifies an "upvar" reference. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int TestupvarCmd(dummy, interp, argc, argv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { int flags = 0; if ((argc != 5) && (argc != 6)) { Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0], " level name ?name2? dest global\"", (char *) NULL); return TCL_ERROR; } if (argc == 5) { if (strcmp(argv[4], "global") == 0) { flags = TCL_GLOBAL_ONLY; } else if (strcmp(argv[4], "namespace") == 0) { flags = TCL_NAMESPACE_ONLY; } return Tcl_UpVar(interp, argv[1], argv[2], argv[3], flags); } else { if (strcmp(argv[5], "global") == 0) { flags = TCL_GLOBAL_ONLY; } else if (strcmp(argv[5], "namespace") == 0) { flags = TCL_NAMESPACE_ONLY; } return Tcl_UpVar2(interp, argv[1], argv[2], (argv[3][0] == 0) ? (char *) NULL : argv[3], argv[4], flags); } } /* *---------------------------------------------------------------------- * * TestseterrorcodeCmd -- * * This procedure implements the "testseterrorcodeCmd". * This tests up to five elements passed to the * Tcl_SetErrorCode command. * * Results: * A standard Tcl result. Always returns TCL_ERROR so that * the error code can be tested. * * Side effects: * None. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int TestseterrorcodeCmd(dummy, interp, argc, argv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { if (argc > 6) { Tcl_SetResult(interp, "too many args", TCL_STATIC); return TCL_ERROR; } Tcl_SetErrorCode(interp, argv[1], argv[2], argv[3], argv[4], argv[5], NULL); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TestsetobjerrorcodeCmd -- * * This procedure implements the "testsetobjerrorcodeCmd". * This tests the Tcl_SetObjErrorCode function. * * Results: * A standard Tcl result. Always returns TCL_ERROR so that * the error code can be tested. * * Side effects: * None. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int TestsetobjerrorcodeCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* The argument objects. */ { Tcl_Obj *listObjPtr; if (objc > 1) { listObjPtr = Tcl_ConcatObj(objc - 1, objv + 1); } else { listObjPtr = Tcl_NewObj(); } Tcl_IncrRefCount(listObjPtr); Tcl_SetObjErrorCode(interp, listObjPtr); Tcl_DecrRefCount(listObjPtr); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TestfeventCmd -- * * This procedure implements the "testfevent" command. It is * used for testing the "fileevent" command. * * Results: * A standard Tcl result. * * Side effects: * Creates and deletes interpreters. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int TestfeventCmd(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { static Tcl_Interp *interp2 = NULL; int code; Tcl_Channel chan; if (argc < 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " option ?arg arg ...?", (char *) NULL); return TCL_ERROR; } if (strcmp(argv[1], "cmd") == 0) { if (argc != 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " cmd script", (char *) NULL); return TCL_ERROR; } if (interp2 != (Tcl_Interp *) NULL) { code = Tcl_GlobalEval(interp2, argv[2]); Tcl_SetObjResult(interp, Tcl_GetObjResult(interp2)); return code; } else { Tcl_AppendResult(interp, "called \"testfevent code\" before \"testfevent create\"", (char *) NULL); return TCL_ERROR; } } else if (strcmp(argv[1], "create") == 0) { if (interp2 != NULL) { Tcl_DeleteInterp(interp2); } interp2 = Tcl_CreateInterp(); return Tcl_Init(interp2); } else if (strcmp(argv[1], "delete") == 0) { if (interp2 != NULL) { Tcl_DeleteInterp(interp2); } interp2 = NULL; } else if (strcmp(argv[1], "share") == 0) { if (interp2 != NULL) { chan = Tcl_GetChannel(interp, argv[2], NULL); if (chan == (Tcl_Channel) NULL) { return TCL_ERROR; } Tcl_RegisterChannel(interp2, chan); } } return TCL_OK; } /* *---------------------------------------------------------------------- * * TestpanicCmd -- * * Calls the panic routine. * * Results: * Always returns TCL_OK. * * Side effects: * May exit application. * *---------------------------------------------------------------------- */ static int TestpanicCmd(dummy, interp, argc, argv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { CONST char *argString; /* * Put the arguments into a var args structure * Append all of the arguments together separated by spaces */ argString = Tcl_Merge(argc-1, argv+1); panic(argString); ckfree((char *)argString); return TCL_OK; } static int TestfileCmd(dummy, interp, argc, argv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ Tcl_Obj *CONST argv[]; /* The argument objects. */ { int force, i, j, result; Tcl_Obj *error = NULL; char *subcmd; if (argc < 3) { return TCL_ERROR; } force = 0; i = 2; if (strcmp(Tcl_GetString(argv[2]), "-force") == 0) { force = 1; i = 3; } if (argc - i > 2) { return TCL_ERROR; } for (j = i; j < argc; j++) { if (Tcl_FSGetNormalizedPath(interp, argv[j]) == NULL) { return TCL_ERROR; } } subcmd = Tcl_GetString(argv[1]); if (strcmp(subcmd, "mv") == 0) { result = TclpObjRenameFile(argv[i], argv[i + 1]); } else if (strcmp(subcmd, "cp") == 0) { result = TclpObjCopyFile(argv[i], argv[i + 1]); } else if (strcmp(subcmd, "rm") == 0) { result = TclpObjDeleteFile(argv[i]); } else if (strcmp(subcmd, "mkdir") == 0) { result = TclpObjCreateDirectory(argv[i]); } else if (strcmp(subcmd, "cpdir") == 0) { result = TclpObjCopyDirectory(argv[i], argv[i + 1], &error); } else if (strcmp(subcmd, "rmdir") == 0) { result = TclpObjRemoveDirectory(argv[i], force, &error); } else { result = TCL_ERROR; goto end; } if (result != TCL_OK) { if (error != NULL) { if (Tcl_GetString(error)[0] != '\0') { Tcl_AppendResult(interp, Tcl_GetString(error), " ", NULL); } Tcl_DecrRefCount(error); } Tcl_AppendResult(interp, Tcl_ErrnoId(), (char *) NULL); } end: return result; } /* *---------------------------------------------------------------------- * * TestgetvarfullnameCmd -- * * Implements the "testgetvarfullname" cmd that is used when testing * the Tcl_GetVariableFullName procedure. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TestgetvarfullnameCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* The argument objects. */ { char *name, *arg; int flags = 0; Tcl_Namespace *namespacePtr; Tcl_CallFrame frame; Tcl_Var variable; int result; if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "name scope"); return TCL_ERROR; } name = Tcl_GetString(objv[1]); arg = Tcl_GetString(objv[2]); if (strcmp(arg, "global") == 0) { flags = TCL_GLOBAL_ONLY; } else if (strcmp(arg, "namespace") == 0) { flags = TCL_NAMESPACE_ONLY; } /* * This command, like any other created with Tcl_Create[Obj]Command, * runs in the global namespace. As a "namespace-aware" command that * needs to run in a particular namespace, it must activate that * namespace itself. */ if (flags == TCL_NAMESPACE_ONLY) { namespacePtr = Tcl_FindNamespace(interp, "::test_ns_var", (Tcl_Namespace *) NULL, TCL_LEAVE_ERR_MSG); if (namespacePtr == NULL) { return TCL_ERROR; } result = Tcl_PushCallFrame(interp, &frame, namespacePtr, /*isProcCallFrame*/ 0); if (result != TCL_OK) { return result; } } variable = Tcl_FindNamespaceVar(interp, name, (Tcl_Namespace *) NULL, (flags | TCL_LEAVE_ERR_MSG)); if (flags == TCL_NAMESPACE_ONLY) { Tcl_PopCallFrame(interp); } if (variable == (Tcl_Var) NULL) { return TCL_ERROR; } Tcl_GetVariableFullName(interp, variable, Tcl_GetObjResult(interp)); return TCL_OK; } /* *---------------------------------------------------------------------- * * GetTimesCmd -- * * This procedure implements the "gettimes" command. It is * used for computing the time needed for various basic operations * such as reading variables, allocating memory, sprintf, converting * variables, etc. * * Results: * A standard Tcl result. * * Side effects: * Allocates and frees memory, sets a variable "a" in the interpreter. * *---------------------------------------------------------------------- */ static int GetTimesCmd(unused, interp, argc, argv) ClientData unused; /* Unused. */ Tcl_Interp *interp; /* The current interpreter. */ int argc; /* The number of arguments. */ CONST char **argv; /* The argument strings. */ { Interp *iPtr = (Interp *) interp; int i, n; double timePer; Tcl_Time start, stop; Tcl_Obj *objPtr; Tcl_Obj **objv; CONST char *s; char newString[TCL_INTEGER_SPACE]; /* alloc & free 100000 times */ fprintf(stderr, "alloc & free 100000 6 word items\n"); Tcl_GetTime(&start); for (i = 0; i < 100000; i++) { objPtr = (Tcl_Obj *) ckalloc(sizeof(Tcl_Obj)); ckfree((char *) objPtr); } Tcl_GetTime(&stop); timePer = (stop.sec - start.sec)*1000000 + (stop.usec - start.usec); fprintf(stderr, " %.3f usec per alloc+free\n", timePer/100000); /* alloc 5000 times */ fprintf(stderr, "alloc 5000 6 word items\n"); objv = (Tcl_Obj **) ckalloc(5000 * sizeof(Tcl_Obj *)); Tcl_GetTime(&start); for (i = 0; i < 5000; i++) { objv[i] = (Tcl_Obj *) ckalloc(sizeof(Tcl_Obj)); } Tcl_GetTime(&stop); timePer = (stop.sec - start.sec)*1000000 + (stop.usec - start.usec); fprintf(stderr, " %.3f usec per alloc\n", timePer/5000); /* free 5000 times */ fprintf(stderr, "free 5000 6 word items\n"); Tcl_GetTime(&start); for (i = 0; i < 5000; i++) { ckfree((char *) objv[i]); } Tcl_GetTime(&stop); timePer = (stop.sec - start.sec)*1000000 + (stop.usec - start.usec); fprintf(stderr, " %.3f usec per free\n", timePer/5000); /* Tcl_NewObj 5000 times */ fprintf(stderr, "Tcl_NewObj 5000 times\n"); Tcl_GetTime(&start); for (i = 0; i < 5000; i++) { objv[i] = Tcl_NewObj(); } Tcl_GetTime(&stop); timePer = (stop.sec - start.sec)*1000000 + (stop.usec - start.usec); fprintf(stderr, " %.3f usec per Tcl_NewObj\n", timePer/5000); /* Tcl_DecrRefCount 5000 times */ fprintf(stderr, "Tcl_DecrRefCount 5000 times\n"); Tcl_GetTime(&start); for (i = 0; i < 5000; i++) { objPtr = objv[i]; Tcl_DecrRefCount(objPtr); } Tcl_GetTime(&stop); timePer = (stop.sec - start.sec)*1000000 + (stop.usec - start.usec); fprintf(stderr, " %.3f usec per Tcl_DecrRefCount\n", timePer/5000); ckfree((char *) objv); /* TclGetString 100000 times */ fprintf(stderr, "TclGetStringFromObj of \"12345\" 100000 times\n"); objPtr = Tcl_NewStringObj("12345", -1); Tcl_GetTime(&start); for (i = 0; i < 100000; i++) { (void) TclGetString(objPtr); } Tcl_GetTime(&stop); timePer = (stop.sec - start.sec)*1000000 + (stop.usec - start.usec); fprintf(stderr, " %.3f usec per TclGetStringFromObj of \"12345\"\n", timePer/100000); /* Tcl_GetIntFromObj 100000 times */ fprintf(stderr, "Tcl_GetIntFromObj of \"12345\" 100000 times\n"); Tcl_GetTime(&start); for (i = 0; i < 100000; i++) { if (Tcl_GetIntFromObj(interp, objPtr, &n) != TCL_OK) { return TCL_ERROR; } } Tcl_GetTime(&stop); timePer = (stop.sec - start.sec)*1000000 + (stop.usec - start.usec); fprintf(stderr, " %.3f usec per Tcl_GetIntFromObj of \"12345\"\n", timePer/100000); Tcl_DecrRefCount(objPtr); /* Tcl_GetInt 100000 times */ fprintf(stderr, "Tcl_GetInt of \"12345\" 100000 times\n"); Tcl_GetTime(&start); for (i = 0; i < 100000; i++) { if (Tcl_GetInt(interp, "12345", &n) != TCL_OK) { return TCL_ERROR; } } Tcl_GetTime(&stop); timePer = (stop.sec - start.sec)*1000000 + (stop.usec - start.usec); fprintf(stderr, " %.3f usec per Tcl_GetInt of \"12345\"\n", timePer/100000); /* sprintf 100000 times */ fprintf(stderr, "sprintf of 12345 100000 times\n"); Tcl_GetTime(&start); for (i = 0; i < 100000; i++) { sprintf(newString, "%d", 12345); } Tcl_GetTime(&stop); timePer = (stop.sec - start.sec)*1000000 + (stop.usec - start.usec); fprintf(stderr, " %.3f usec per sprintf of 12345\n", timePer/100000); /* hashtable lookup 100000 times */ fprintf(stderr, "hashtable lookup of \"gettimes\" 100000 times\n"); Tcl_GetTime(&start); for (i = 0; i < 100000; i++) { (void) Tcl_FindHashEntry(&iPtr->globalNsPtr->cmdTable, "gettimes"); } Tcl_GetTime(&stop); timePer = (stop.sec - start.sec)*1000000 + (stop.usec - start.usec); fprintf(stderr, " %.3f usec per hashtable lookup of \"gettimes\"\n", timePer/100000); /* Tcl_SetVar 100000 times */ fprintf(stderr, "Tcl_SetVar of \"12345\" 100000 times\n"); Tcl_GetTime(&start); for (i = 0; i < 100000; i++) { s = Tcl_SetVar(interp, "a", "12345", TCL_LEAVE_ERR_MSG); if (s == NULL) { return TCL_ERROR; } } Tcl_GetTime(&stop); timePer = (stop.sec - start.sec)*1000000 + (stop.usec - start.usec); fprintf(stderr, " %.3f usec per Tcl_SetVar of a to \"12345\"\n", timePer/100000); /* Tcl_GetVar 100000 times */ fprintf(stderr, "Tcl_GetVar of a==\"12345\" 100000 times\n"); Tcl_GetTime(&start); for (i = 0; i < 100000; i++) { s = Tcl_GetVar(interp, "a", TCL_LEAVE_ERR_MSG); if (s == NULL) { return TCL_ERROR; } } Tcl_GetTime(&stop); timePer = (stop.sec - start.sec)*1000000 + (stop.usec - start.usec); fprintf(stderr, " %.3f usec per Tcl_GetVar of a==\"12345\"\n", timePer/100000); Tcl_ResetResult(interp); return TCL_OK; } /* *---------------------------------------------------------------------- * * NoopCmd -- * * This procedure is just used to time the overhead involved in * parsing and invoking a command. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int NoopCmd(unused, interp, argc, argv) ClientData unused; /* Unused. */ Tcl_Interp *interp; /* The current interpreter. */ int argc; /* The number of arguments. */ CONST char **argv; /* The argument strings. */ { return TCL_OK; } /* *---------------------------------------------------------------------- * * NoopObjCmd -- * * This object-based procedure is just used to time the overhead * involved in parsing and invoking a command. * * Results: * Returns the TCL_OK result code. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int NoopObjCmd(unused, interp, objc, objv) ClientData unused; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* The argument objects. */ { return TCL_OK; } /* *---------------------------------------------------------------------- * * TestsetCmd -- * * Implements the "testset{err,noerr}" cmds that are used when testing * Tcl_Set/GetVar C Api with/without TCL_LEAVE_ERR_MSG flag * * Results: * A standard Tcl result. * * Side effects: * Variables may be set. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int TestsetCmd(data, interp, argc, argv) ClientData data; /* Additional flags for Get/SetVar2. */ register Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { int flags = (int) data; CONST char *value; if (argc == 2) { Tcl_SetResult(interp, "before get", TCL_STATIC); value = Tcl_GetVar2(interp, argv[1], (char *) NULL, flags); if (value == NULL) { return TCL_ERROR; } Tcl_AppendElement(interp, value); return TCL_OK; } else if (argc == 3) { Tcl_SetResult(interp, "before set", TCL_STATIC); value = Tcl_SetVar2(interp, argv[1], (char *) NULL, argv[2], flags); if (value == NULL) { return TCL_ERROR; } Tcl_AppendElement(interp, value); return TCL_OK; } else { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " varName ?newValue?\"", (char *) NULL); return TCL_ERROR; } } /* *---------------------------------------------------------------------- * * TestsaveresultCmd -- * * Implements the "testsaveresult" cmd that is used when testing * the Tcl_SaveResult, Tcl_RestoreResult, and * Tcl_DiscardResult interfaces. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int TestsaveresultCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ register Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* The argument objects. */ { int discard, result, index; Tcl_SavedResult state; Tcl_Obj *objPtr; static CONST char *optionStrings[] = { "append", "dynamic", "free", "object", "small", NULL }; enum options { RESULT_APPEND, RESULT_DYNAMIC, RESULT_FREE, RESULT_OBJECT, RESULT_SMALL }; /* * Parse arguments */ if (objc != 4) { Tcl_WrongNumArgs(interp, 1, objv, "type script discard"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0, &index) != TCL_OK) { return TCL_ERROR; } if (Tcl_GetBooleanFromObj(interp, objv[3], &discard) != TCL_OK) { return TCL_ERROR; } objPtr = NULL; /* Lint. */ switch ((enum options) index) { case RESULT_SMALL: Tcl_SetResult(interp, "small result", TCL_VOLATILE); break; case RESULT_APPEND: Tcl_AppendResult(interp, "append result", NULL); break; case RESULT_FREE: { char *buf = ckalloc(200); strcpy(buf, "free result"); Tcl_SetResult(interp, buf, TCL_DYNAMIC); break; } case RESULT_DYNAMIC: Tcl_SetResult(interp, "dynamic result", TestsaveresultFree); break; case RESULT_OBJECT: objPtr = Tcl_NewStringObj("object result", -1); Tcl_SetObjResult(interp, objPtr); break; } freeCount = 0; Tcl_SaveResult(interp, &state); if (((enum options) index) == RESULT_OBJECT) { result = Tcl_EvalObjEx(interp, objv[2], 0); } else { result = Tcl_Eval(interp, Tcl_GetString(objv[2])); } if (discard) { Tcl_DiscardResult(&state); } else { Tcl_RestoreResult(interp, &state); result = TCL_OK; } switch ((enum options) index) { case RESULT_DYNAMIC: { int present = interp->freeProc == TestsaveresultFree; int called = freeCount; Tcl_AppendElement(interp, called ? "called" : "notCalled"); Tcl_AppendElement(interp, present ? "present" : "missing"); break; } case RESULT_OBJECT: Tcl_AppendElement(interp, Tcl_GetObjResult(interp) == objPtr ? "same" : "different"); break; default: break; } return result; } /* *---------------------------------------------------------------------- * * TestsaveresultFree -- * * Special purpose freeProc used by TestsaveresultCmd. * * Results: * None. * * Side effects: * Increments the freeCount. * *---------------------------------------------------------------------- */ static void TestsaveresultFree(blockPtr) char *blockPtr; { freeCount++; } /* *---------------------------------------------------------------------- * * TeststatprocCmd -- * * Implements the "testTclStatProc" cmd that is used to test the * 'TclStatInsertProc' & 'TclStatDeleteProc' C Apis. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TeststatprocCmd (dummy, interp, argc, argv) ClientData dummy; /* Not used. */ register Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { TclStatProc_ *proc; int retVal; if (argc != 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " option arg\"", (char *) NULL); return TCL_ERROR; } if (strcmp(argv[2], "TclpStat") == 0) { proc = PretendTclpStat; } else if (strcmp(argv[2], "TestStatProc1") == 0) { proc = TestStatProc1; } else if (strcmp(argv[2], "TestStatProc2") == 0) { proc = TestStatProc2; } else if (strcmp(argv[2], "TestStatProc3") == 0) { proc = TestStatProc3; } else { Tcl_AppendResult(interp, "bad arg \"", argv[1], "\": ", "must be TclpStat, ", "TestStatProc1, TestStatProc2, or TestStatProc3", (char *) NULL); return TCL_ERROR; } if (strcmp(argv[1], "insert") == 0) { if (proc == PretendTclpStat) { Tcl_AppendResult(interp, "bad arg \"", argv[1], "\": ", "must be ", "TestStatProc1, TestStatProc2, or TestStatProc3", (char *) NULL); return TCL_ERROR; } retVal = TclStatInsertProc(proc); } else if (strcmp(argv[1], "delete") == 0) { retVal = TclStatDeleteProc(proc); } else { Tcl_AppendResult(interp, "bad option \"", argv[1], "\": ", "must be insert or delete", (char *) NULL); return TCL_ERROR; } if (retVal == TCL_ERROR) { Tcl_AppendResult(interp, "\"", argv[2], "\": ", "could not be ", argv[1], "ed", (char *) NULL); } return retVal; } static int PretendTclpStat(path, buf) CONST char *path; Tcl_StatBuf *buf; { int ret; Tcl_Obj *pathPtr = Tcl_NewStringObj(path, -1); #ifdef TCL_WIDE_INT_IS_LONG Tcl_IncrRefCount(pathPtr); ret = TclpObjStat(pathPtr, buf); Tcl_DecrRefCount(pathPtr); return ret; #else /* TCL_WIDE_INT_IS_LONG */ Tcl_StatBuf realBuf; Tcl_IncrRefCount(pathPtr); ret = TclpObjStat(pathPtr, &realBuf); Tcl_DecrRefCount(pathPtr); if (ret != -1) { # define OUT_OF_RANGE(x) \ (((Tcl_WideInt)(x)) < Tcl_LongAsWide(LONG_MIN) || \ ((Tcl_WideInt)(x)) > Tcl_LongAsWide(LONG_MAX)) #if defined(__GNUC__) && __GNUC__ >= 2 /* * Workaround gcc warning of "comparison is always false due to limited range of * data type" in this macro by checking max type size, and when necessary ANDing * with the complement of ULONG_MAX instead of the comparison: */ # define OUT_OF_URANGE(x) \ ((((Tcl_WideUInt)(~ (__typeof__(x)) 0)) > (Tcl_WideUInt)ULONG_MAX) && \ (((Tcl_WideUInt)(x)) & ~(Tcl_WideUInt)ULONG_MAX)) #else # define OUT_OF_URANGE(x) \ (((Tcl_WideUInt)(x)) > (Tcl_WideUInt)ULONG_MAX) #endif /* * Perform the result-buffer overflow check manually. * * Note that ino_t/ino64_t is unsigned... */ if (OUT_OF_URANGE(realBuf.st_ino) || OUT_OF_RANGE(realBuf.st_size) # ifdef HAVE_ST_BLOCKS || OUT_OF_RANGE(realBuf.st_blocks) # endif ) { # ifdef EOVERFLOW errno = EOVERFLOW; # else # ifdef EFBIG errno = EFBIG; # else # error "what error should be returned for a value out of range?" # endif # endif return -1; } # undef OUT_OF_RANGE # undef OUT_OF_URANGE /* * Copy across all supported fields, with possible type * coercions on those fields that change between the normal * and lf64 versions of the stat structure (on Solaris at * least.) This is slow when the structure sizes coincide, * but that's what you get for mixing interfaces... */ buf->st_mode = realBuf.st_mode; buf->st_ino = (ino_t) realBuf.st_ino; buf->st_dev = realBuf.st_dev; buf->st_rdev = realBuf.st_rdev; buf->st_nlink = realBuf.st_nlink; buf->st_uid = realBuf.st_uid; buf->st_gid = realBuf.st_gid; buf->st_size = (off_t) realBuf.st_size; buf->st_atime = realBuf.st_atime; buf->st_mtime = realBuf.st_mtime; buf->st_ctime = realBuf.st_ctime; # ifdef HAVE_ST_BLOCKS buf->st_blksize = realBuf.st_blksize; buf->st_blocks = (blkcnt_t) realBuf.st_blocks; # endif } return ret; #endif /* TCL_WIDE_INT_IS_LONG */ } static int TestStatProc1(path, buf) CONST char *path; Tcl_StatBuf *buf; { memset(buf, 0, sizeof(Tcl_StatBuf)); buf->st_size = 1234; return ((strstr(path, "testStat1%.fil") == NULL) ? -1 : 0); } static int TestStatProc2(path, buf) CONST char *path; Tcl_StatBuf *buf; { memset(buf, 0, sizeof(Tcl_StatBuf)); buf->st_size = 2345; return ((strstr(path, "testStat2%.fil") == NULL) ? -1 : 0); } static int TestStatProc3(path, buf) CONST char *path; Tcl_StatBuf *buf; { memset(buf, 0, sizeof(Tcl_StatBuf)); buf->st_size = 3456; return ((strstr(path, "testStat3%.fil") == NULL) ? -1 : 0); } /* *---------------------------------------------------------------------- * * TestmainthreadCmd -- * * Implements the "testmainthread" cmd that is used to test the * 'Tcl_GetCurrentThread' API. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TestmainthreadCmd (dummy, interp, argc, argv) ClientData dummy; /* Not used. */ register Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { if (argc == 1) { Tcl_Obj *idObj = Tcl_NewLongObj((long)Tcl_GetCurrentThread()); Tcl_SetObjResult(interp, idObj); return TCL_OK; } else { Tcl_SetResult(interp, "wrong # args", TCL_STATIC); return TCL_ERROR; } } /* *---------------------------------------------------------------------- * * MainLoop -- * * A main loop set by TestsetmainloopCmd below. * * Results: * None. * * Side effects: * Event handlers could do anything. * *---------------------------------------------------------------------- */ static void MainLoop(void) { while (!exitMainLoop) { Tcl_DoOneEvent(0); } fprintf(stdout,"Exit MainLoop\n"); fflush(stdout); } /* *---------------------------------------------------------------------- * * TestsetmainloopCmd -- * * Implements the "testsetmainloop" cmd that is used to test the * 'Tcl_SetMainLoop' API. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TestsetmainloopCmd (dummy, interp, argc, argv) ClientData dummy; /* Not used. */ register Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { exitMainLoop = 0; Tcl_SetMainLoop(MainLoop); return TCL_OK; } /* *---------------------------------------------------------------------- * * TestexitmainloopCmd -- * * Implements the "testexitmainloop" cmd that is used to test the * 'Tcl_SetMainLoop' API. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TestexitmainloopCmd (dummy, interp, argc, argv) ClientData dummy; /* Not used. */ register Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { exitMainLoop = 1; return TCL_OK; } /* *---------------------------------------------------------------------- * * TestaccessprocCmd -- * * Implements the "testTclAccessProc" cmd that is used to test the * 'TclAccessInsertProc' & 'TclAccessDeleteProc' C Apis. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TestaccessprocCmd (dummy, interp, argc, argv) ClientData dummy; /* Not used. */ register Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { TclAccessProc_ *proc; int retVal; if (argc != 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " option arg\"", (char *) NULL); return TCL_ERROR; } if (strcmp(argv[2], "TclpAccess") == 0) { proc = PretendTclpAccess; } else if (strcmp(argv[2], "TestAccessProc1") == 0) { proc = TestAccessProc1; } else if (strcmp(argv[2], "TestAccessProc2") == 0) { proc = TestAccessProc2; } else if (strcmp(argv[2], "TestAccessProc3") == 0) { proc = TestAccessProc3; } else { Tcl_AppendResult(interp, "bad arg \"", argv[1], "\": ", "must be TclpAccess, ", "TestAccessProc1, TestAccessProc2, or TestAccessProc3", (char *) NULL); return TCL_ERROR; } if (strcmp(argv[1], "insert") == 0) { if (proc == PretendTclpAccess) { Tcl_AppendResult(interp, "bad arg \"", argv[1], "\": ", "must be ", "TestAccessProc1, TestAccessProc2, or TestAccessProc3", (char *) NULL); return TCL_ERROR; } retVal = TclAccessInsertProc(proc); } else if (strcmp(argv[1], "delete") == 0) { retVal = TclAccessDeleteProc(proc); } else { Tcl_AppendResult(interp, "bad option \"", argv[1], "\": ", "must be insert or delete", (char *) NULL); return TCL_ERROR; } if (retVal == TCL_ERROR) { Tcl_AppendResult(interp, "\"", argv[2], "\": ", "could not be ", argv[1], "ed", (char *) NULL); } return retVal; } static int PretendTclpAccess(path, mode) CONST char *path; int mode; { int ret; Tcl_Obj *pathPtr = Tcl_NewStringObj(path, -1); Tcl_IncrRefCount(pathPtr); ret = TclpObjAccess(pathPtr, mode); Tcl_DecrRefCount(pathPtr); return ret; } static int TestAccessProc1(path, mode) CONST char *path; int mode; { return ((strstr(path, "testAccess1%.fil") == NULL) ? -1 : 0); } static int TestAccessProc2(path, mode) CONST char *path; int mode; { return ((strstr(path, "testAccess2%.fil") == NULL) ? -1 : 0); } static int TestAccessProc3(path, mode) CONST char *path; int mode; { return ((strstr(path, "testAccess3%.fil") == NULL) ? -1 : 0); } /* *---------------------------------------------------------------------- * * TestopenfilechannelprocCmd -- * * Implements the "testTclOpenFileChannelProc" cmd that is used to test the * 'TclOpenFileChannelInsertProc' & 'TclOpenFileChannelDeleteProc' C Apis. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TestopenfilechannelprocCmd (dummy, interp, argc, argv) ClientData dummy; /* Not used. */ register Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { TclOpenFileChannelProc_ *proc; int retVal; if (argc != 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " option arg\"", (char *) NULL); return TCL_ERROR; } if (strcmp(argv[2], "TclpOpenFileChannel") == 0) { proc = PretendTclpOpenFileChannel; } else if (strcmp(argv[2], "TestOpenFileChannelProc1") == 0) { proc = TestOpenFileChannelProc1; } else if (strcmp(argv[2], "TestOpenFileChannelProc2") == 0) { proc = TestOpenFileChannelProc2; } else if (strcmp(argv[2], "TestOpenFileChannelProc3") == 0) { proc = TestOpenFileChannelProc3; } else { Tcl_AppendResult(interp, "bad arg \"", argv[1], "\": ", "must be TclpOpenFileChannel, ", "TestOpenFileChannelProc1, TestOpenFileChannelProc2, or ", "TestOpenFileChannelProc3", (char *) NULL); return TCL_ERROR; } if (strcmp(argv[1], "insert") == 0) { if (proc == PretendTclpOpenFileChannel) { Tcl_AppendResult(interp, "bad arg \"", argv[1], "\": ", "must be ", "TestOpenFileChannelProc1, TestOpenFileChannelProc2, or ", "TestOpenFileChannelProc3", (char *) NULL); return TCL_ERROR; } retVal = TclOpenFileChannelInsertProc(proc); } else if (strcmp(argv[1], "delete") == 0) { retVal = TclOpenFileChannelDeleteProc(proc); } else { Tcl_AppendResult(interp, "bad option \"", argv[1], "\": ", "must be insert or delete", (char *) NULL); return TCL_ERROR; } if (retVal == TCL_ERROR) { Tcl_AppendResult(interp, "\"", argv[2], "\": ", "could not be ", argv[1], "ed", (char *) NULL); } return retVal; } static Tcl_Channel PretendTclpOpenFileChannel(interp, fileName, modeString, permissions) Tcl_Interp *interp; /* Interpreter for error reporting; * can be NULL. */ CONST char *fileName; /* Name of file to open. */ CONST char *modeString; /* A list of POSIX open modes or * a string such as "rw". */ int permissions; /* If the open involves creating a * file, with what modes to create * it? */ { Tcl_Channel ret; int mode, seekFlag; Tcl_Obj *pathPtr; mode = TclGetOpenMode(interp, modeString, &seekFlag); if (mode == -1) { return NULL; } pathPtr = Tcl_NewStringObj(fileName, -1); Tcl_IncrRefCount(pathPtr); ret = TclpOpenFileChannel(interp, pathPtr, mode, permissions); Tcl_DecrRefCount(pathPtr); if (ret != NULL) { if (seekFlag) { if (Tcl_Seek(ret, (Tcl_WideInt)0, SEEK_END) < (Tcl_WideInt)0) { if (interp != (Tcl_Interp *) NULL) { Tcl_AppendResult(interp, "could not seek to end of file while opening \"", fileName, "\": ", Tcl_PosixError(interp), (char *) NULL); } Tcl_Close(NULL, ret); return NULL; } } } return ret; } static Tcl_Channel TestOpenFileChannelProc1(interp, fileName, modeString, permissions) Tcl_Interp *interp; /* Interpreter for error reporting; * can be NULL. */ CONST char *fileName; /* Name of file to open. */ CONST char *modeString; /* A list of POSIX open modes or * a string such as "rw". */ int permissions; /* If the open involves creating a * file, with what modes to create * it? */ { CONST char *expectname="testOpenFileChannel1%.fil"; Tcl_DString ds; Tcl_DStringInit(&ds); Tcl_JoinPath(1, &expectname, &ds); if (!strcmp(Tcl_DStringValue(&ds), fileName)) { Tcl_DStringFree(&ds); return (PretendTclpOpenFileChannel(interp, "__testOpenFileChannel1%__.fil", modeString, permissions)); } else { Tcl_DStringFree(&ds); return (NULL); } } static Tcl_Channel TestOpenFileChannelProc2(interp, fileName, modeString, permissions) Tcl_Interp *interp; /* Interpreter for error reporting; * can be NULL. */ CONST char *fileName; /* Name of file to open. */ CONST char *modeString; /* A list of POSIX open modes or * a string such as "rw". */ int permissions; /* If the open involves creating a * file, with what modes to create * it? */ { CONST char *expectname="testOpenFileChannel2%.fil"; Tcl_DString ds; Tcl_DStringInit(&ds); Tcl_JoinPath(1, &expectname, &ds); if (!strcmp(Tcl_DStringValue(&ds), fileName)) { Tcl_DStringFree(&ds); return (PretendTclpOpenFileChannel(interp, "__testOpenFileChannel2%__.fil", modeString, permissions)); } else { Tcl_DStringFree(&ds); return (NULL); } } static Tcl_Channel TestOpenFileChannelProc3(interp, fileName, modeString, permissions) Tcl_Interp *interp; /* Interpreter for error reporting; * can be NULL. */ CONST char *fileName; /* Name of file to open. */ CONST char *modeString; /* A list of POSIX open modes or * a string such as "rw". */ int permissions; /* If the open involves creating a * file, with what modes to create * it? */ { CONST char *expectname="testOpenFileChannel3%.fil"; Tcl_DString ds; Tcl_DStringInit(&ds); Tcl_JoinPath(1, &expectname, &ds); if (!strcmp(Tcl_DStringValue(&ds), fileName)) { Tcl_DStringFree(&ds); return (PretendTclpOpenFileChannel(interp, "__testOpenFileChannel3%__.fil", modeString, permissions)); } else { Tcl_DStringFree(&ds); return (NULL); } } /* *---------------------------------------------------------------------- * * TestChannelCmd -- * * Implements the Tcl "testchannel" debugging command and its * subcommands. This is part of the testing environment. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int TestChannelCmd(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Interpreter for result. */ int argc; /* Count of additional args. */ CONST char **argv; /* Additional arg strings. */ { CONST char *cmdName; /* Sub command. */ Tcl_HashTable *hTblPtr; /* Hash table of channels. */ Tcl_HashSearch hSearch; /* Search variable. */ Tcl_HashEntry *hPtr; /* Search variable. */ Channel *chanPtr; /* The actual channel. */ ChannelState *statePtr; /* state info for channel */ Tcl_Channel chan; /* The opaque type. */ size_t len; /* Length of subcommand string. */ int IOQueued; /* How much IO is queued inside channel? */ ChannelBuffer *bufPtr; /* For iterating over queued IO. */ char buf[TCL_INTEGER_SPACE];/* For sprintf. */ int mode; /* rw mode of the channel */ if (argc < 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " subcommand ?additional args..?\"", (char *) NULL); return TCL_ERROR; } cmdName = argv[1]; len = strlen(cmdName); chanPtr = (Channel *) NULL; if (argc > 2) { chan = Tcl_GetChannel(interp, argv[2], &mode); if (chan == (Tcl_Channel) NULL) { return TCL_ERROR; } chanPtr = (Channel *) chan; statePtr = chanPtr->state; chanPtr = statePtr->topChanPtr; chan = (Tcl_Channel) chanPtr; } else { /* lint */ statePtr = NULL; chan = NULL; } if ((cmdName[0] == 'c') && (strncmp(cmdName, "cut", len) == 0)) { if (argc != 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " cut channelName\"", (char *) NULL); return TCL_ERROR; } Tcl_CutChannel(chan); return TCL_OK; } if ((cmdName[0] == 'c') && (strncmp(cmdName, "clearchannelhandlers", len) == 0)) { if (argc != 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " clearchannelhandlers channelName\"", (char *) NULL); return TCL_ERROR; } Tcl_ClearChannelHandlers(chan); return TCL_OK; } if ((cmdName[0] == 'i') && (strncmp(cmdName, "info", len) == 0)) { if (argc != 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " info channelName\"", (char *) NULL); return TCL_ERROR; } Tcl_AppendElement(interp, argv[2]); Tcl_AppendElement(interp, Tcl_ChannelName(chanPtr->typePtr)); if (statePtr->flags & TCL_READABLE) { Tcl_AppendElement(interp, "read"); } else { Tcl_AppendElement(interp, ""); } if (statePtr->flags & TCL_WRITABLE) { Tcl_AppendElement(interp, "write"); } else { Tcl_AppendElement(interp, ""); } if (statePtr->flags & CHANNEL_NONBLOCKING) { Tcl_AppendElement(interp, "nonblocking"); } else { Tcl_AppendElement(interp, "blocking"); } if (statePtr->flags & CHANNEL_LINEBUFFERED) { Tcl_AppendElement(interp, "line"); } else if (statePtr->flags & CHANNEL_UNBUFFERED) { Tcl_AppendElement(interp, "none"); } else { Tcl_AppendElement(interp, "full"); } if (statePtr->flags & BG_FLUSH_SCHEDULED) { Tcl_AppendElement(interp, "async_flush"); } else { Tcl_AppendElement(interp, ""); } if (statePtr->flags & CHANNEL_EOF) { Tcl_AppendElement(interp, "eof"); } else { Tcl_AppendElement(interp, ""); } if (statePtr->flags & CHANNEL_BLOCKED) { Tcl_AppendElement(interp, "blocked"); } else { Tcl_AppendElement(interp, "unblocked"); } if (statePtr->inputTranslation == TCL_TRANSLATE_AUTO) { Tcl_AppendElement(interp, "auto"); if (statePtr->flags & INPUT_SAW_CR) { Tcl_AppendElement(interp, "saw_cr"); } else { Tcl_AppendElement(interp, ""); } } else if (statePtr->inputTranslation == TCL_TRANSLATE_LF) { Tcl_AppendElement(interp, "lf"); Tcl_AppendElement(interp, ""); } else if (statePtr->inputTranslation == TCL_TRANSLATE_CR) { Tcl_AppendElement(interp, "cr"); Tcl_AppendElement(interp, ""); } else if (statePtr->inputTranslation == TCL_TRANSLATE_CRLF) { Tcl_AppendElement(interp, "crlf"); if (statePtr->flags & INPUT_SAW_CR) { Tcl_AppendElement(interp, "queued_cr"); } else { Tcl_AppendElement(interp, ""); } } if (statePtr->outputTranslation == TCL_TRANSLATE_AUTO) { Tcl_AppendElement(interp, "auto"); } else if (statePtr->outputTranslation == TCL_TRANSLATE_LF) { Tcl_AppendElement(interp, "lf"); } else if (statePtr->outputTranslation == TCL_TRANSLATE_CR) { Tcl_AppendElement(interp, "cr"); } else if (statePtr->outputTranslation == TCL_TRANSLATE_CRLF) { Tcl_AppendElement(interp, "crlf"); } for (IOQueued = 0, bufPtr = statePtr->inQueueHead; bufPtr != (ChannelBuffer *) NULL; bufPtr = bufPtr->nextPtr) { IOQueued += bufPtr->nextAdded - bufPtr->nextRemoved; } TclFormatInt(buf, IOQueued); Tcl_AppendElement(interp, buf); IOQueued = 0; if (statePtr->curOutPtr != (ChannelBuffer *) NULL) { IOQueued = statePtr->curOutPtr->nextAdded - statePtr->curOutPtr->nextRemoved; } for (bufPtr = statePtr->outQueueHead; bufPtr != (ChannelBuffer *) NULL; bufPtr = bufPtr->nextPtr) { IOQueued += (bufPtr->nextAdded - bufPtr->nextRemoved); } TclFormatInt(buf, IOQueued); Tcl_AppendElement(interp, buf); TclFormatInt(buf, (int)Tcl_Tell((Tcl_Channel) chanPtr)); Tcl_AppendElement(interp, buf); TclFormatInt(buf, statePtr->refCount); Tcl_AppendElement(interp, buf); return TCL_OK; } if ((cmdName[0] == 'i') && (strncmp(cmdName, "inputbuffered", len) == 0)) { if (argc != 3) { Tcl_AppendResult(interp, "channel name required", (char *) NULL); return TCL_ERROR; } for (IOQueued = 0, bufPtr = statePtr->inQueueHead; bufPtr != (ChannelBuffer *) NULL; bufPtr = bufPtr->nextPtr) { IOQueued += bufPtr->nextAdded - bufPtr->nextRemoved; } TclFormatInt(buf, IOQueued); Tcl_AppendResult(interp, buf, (char *) NULL); return TCL_OK; } if ((cmdName[0] == 'i') && (strncmp(cmdName, "isshared", len) == 0)) { if (argc != 3) { Tcl_AppendResult(interp, "channel name required", (char *) NULL); return TCL_ERROR; } TclFormatInt(buf, Tcl_IsChannelShared(chan)); Tcl_AppendResult(interp, buf, (char *) NULL); return TCL_OK; } if ((cmdName[0] == 'i') && (strncmp(cmdName, "isstandard", len) == 0)) { if (argc != 3) { Tcl_AppendResult(interp, "channel name required", (char *) NULL); return TCL_ERROR; } TclFormatInt(buf, Tcl_IsStandardChannel(chan)); Tcl_AppendResult(interp, buf, (char *) NULL); return TCL_OK; } if ((cmdName[0] == 'm') && (strncmp(cmdName, "mode", len) == 0)) { if (argc != 3) { Tcl_AppendResult(interp, "channel name required", (char *) NULL); return TCL_ERROR; } if (statePtr->flags & TCL_READABLE) { Tcl_AppendElement(interp, "read"); } else { Tcl_AppendElement(interp, ""); } if (statePtr->flags & TCL_WRITABLE) { Tcl_AppendElement(interp, "write"); } else { Tcl_AppendElement(interp, ""); } return TCL_OK; } if ((cmdName[0] == 'm') && (strncmp(cmdName, "mthread", len) == 0)) { if (argc != 3) { Tcl_AppendResult(interp, "channel name required", (char *) NULL); return TCL_ERROR; } TclFormatInt(buf, (long) Tcl_GetChannelThread(chan)); Tcl_AppendResult(interp, buf, (char *) NULL); return TCL_OK; } if ((cmdName[0] == 'n') && (strncmp(cmdName, "name", len) == 0)) { if (argc != 3) { Tcl_AppendResult(interp, "channel name required", (char *) NULL); return TCL_ERROR; } Tcl_AppendResult(interp, statePtr->channelName, (char *) NULL); return TCL_OK; } if ((cmdName[0] == 'o') && (strncmp(cmdName, "open", len) == 0)) { hTblPtr = (Tcl_HashTable *) Tcl_GetAssocData(interp, "tclIO", NULL); if (hTblPtr == (Tcl_HashTable *) NULL) { return TCL_OK; } for (hPtr = Tcl_FirstHashEntry(hTblPtr, &hSearch); hPtr != (Tcl_HashEntry *) NULL; hPtr = Tcl_NextHashEntry(&hSearch)) { Tcl_AppendElement(interp, Tcl_GetHashKey(hTblPtr, hPtr)); } return TCL_OK; } if ((cmdName[0] == 'o') && (strncmp(cmdName, "outputbuffered", len) == 0)) { if (argc != 3) { Tcl_AppendResult(interp, "channel name required", (char *) NULL); return TCL_ERROR; } IOQueued = 0; if (statePtr->curOutPtr != (ChannelBuffer *) NULL) { IOQueued = statePtr->curOutPtr->nextAdded - statePtr->curOutPtr->nextRemoved; } for (bufPtr = statePtr->outQueueHead; bufPtr != (ChannelBuffer *) NULL; bufPtr = bufPtr->nextPtr) { IOQueued += (bufPtr->nextAdded - bufPtr->nextRemoved); } TclFormatInt(buf, IOQueued); Tcl_AppendResult(interp, buf, (char *) NULL); return TCL_OK; } if ((cmdName[0] == 'q') && (strncmp(cmdName, "queuedcr", len) == 0)) { if (argc != 3) { Tcl_AppendResult(interp, "channel name required", (char *) NULL); return TCL_ERROR; } Tcl_AppendResult(interp, (statePtr->flags & INPUT_SAW_CR) ? "1" : "0", (char *) NULL); return TCL_OK; } if ((cmdName[0] == 'r') && (strncmp(cmdName, "readable", len) == 0)) { hTblPtr = (Tcl_HashTable *) Tcl_GetAssocData(interp, "tclIO", NULL); if (hTblPtr == (Tcl_HashTable *) NULL) { return TCL_OK; } for (hPtr = Tcl_FirstHashEntry(hTblPtr, &hSearch); hPtr != (Tcl_HashEntry *) NULL; hPtr = Tcl_NextHashEntry(&hSearch)) { chanPtr = (Channel *) Tcl_GetHashValue(hPtr); statePtr = chanPtr->state; if (statePtr->flags & TCL_READABLE) { Tcl_AppendElement(interp, Tcl_GetHashKey(hTblPtr, hPtr)); } } return TCL_OK; } if ((cmdName[0] == 'r') && (strncmp(cmdName, "refcount", len) == 0)) { if (argc != 3) { Tcl_AppendResult(interp, "channel name required", (char *) NULL); return TCL_ERROR; } TclFormatInt(buf, statePtr->refCount); Tcl_AppendResult(interp, buf, (char *) NULL); return TCL_OK; } if ((cmdName[0] == 's') && (strncmp(cmdName, "splice", len) == 0)) { if (argc != 3) { Tcl_AppendResult(interp, "channel name required", (char *) NULL); return TCL_ERROR; } Tcl_SpliceChannel(chan); return TCL_OK; } if ((cmdName[0] == 't') && (strncmp(cmdName, "type", len) == 0)) { if (argc != 3) { Tcl_AppendResult(interp, "channel name required", (char *) NULL); return TCL_ERROR; } Tcl_AppendResult(interp, Tcl_ChannelName(chanPtr->typePtr), (char *) NULL); return TCL_OK; } if ((cmdName[0] == 'w') && (strncmp(cmdName, "writable", len) == 0)) { hTblPtr = (Tcl_HashTable *) Tcl_GetAssocData(interp, "tclIO", NULL); if (hTblPtr == (Tcl_HashTable *) NULL) { return TCL_OK; } for (hPtr = Tcl_FirstHashEntry(hTblPtr, &hSearch); hPtr != (Tcl_HashEntry *) NULL; hPtr = Tcl_NextHashEntry(&hSearch)) { chanPtr = (Channel *) Tcl_GetHashValue(hPtr); statePtr = chanPtr->state; if (statePtr->flags & TCL_WRITABLE) { Tcl_AppendElement(interp, Tcl_GetHashKey(hTblPtr, hPtr)); } } return TCL_OK; } if ((cmdName[0] == 't') && (strncmp(cmdName, "transform", len) == 0)) { /* * Syntax: transform channel -command command */ if (argc != 5) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " transform channelId -command cmd\"", (char *) NULL); return TCL_ERROR; } if (strcmp(argv[3], "-command") != 0) { Tcl_AppendResult(interp, "bad argument \"", argv[3], "\": should be \"-command\"", (char *) NULL); return TCL_ERROR; } return TclChannelTransform(interp, chan, Tcl_NewStringObj(argv[4], -1)); } if ((cmdName[0] == 'u') && (strncmp(cmdName, "unstack", len) == 0)) { /* * Syntax: unstack channel */ if (argc != 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " unstack channel\"", (char *) NULL); return TCL_ERROR; } return Tcl_UnstackChannel(interp, chan); } Tcl_AppendResult(interp, "bad option \"", cmdName, "\": should be ", "cut, clearchannelhandlers, info, isshared, mode, open, " "readable, splice, writable, transform, unstack", (char *) NULL); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TestChannelEventCmd -- * * This procedure implements the "testchannelevent" command. It is * used to test the Tcl channel event mechanism. * * Results: * A standard Tcl result. * * Side effects: * Creates, deletes and returns channel event handlers. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int TestChannelEventCmd(dummy, interp, argc, argv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { Tcl_Obj *resultListPtr; Channel *chanPtr; ChannelState *statePtr; /* state info for channel */ EventScriptRecord *esPtr, *prevEsPtr, *nextEsPtr; CONST char *cmd; int index, i, mask, len; if ((argc < 3) || (argc > 5)) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " channelName cmd ?arg1? ?arg2?\"", (char *) NULL); return TCL_ERROR; } chanPtr = (Channel *) Tcl_GetChannel(interp, argv[1], NULL); if (chanPtr == (Channel *) NULL) { return TCL_ERROR; } statePtr = chanPtr->state; cmd = argv[2]; len = strlen(cmd); if ((cmd[0] == 'a') && (strncmp(cmd, "add", (unsigned) len) == 0)) { if (argc != 5) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " channelName add eventSpec script\"", (char *) NULL); return TCL_ERROR; } if (strcmp(argv[3], "readable") == 0) { mask = TCL_READABLE; } else if (strcmp(argv[3], "writable") == 0) { mask = TCL_WRITABLE; } else if (strcmp(argv[3], "none") == 0) { mask = 0; } else { Tcl_AppendResult(interp, "bad event name \"", argv[3], "\": must be readable, writable, or none", (char *) NULL); return TCL_ERROR; } esPtr = (EventScriptRecord *) ckalloc((unsigned) sizeof(EventScriptRecord)); esPtr->nextPtr = statePtr->scriptRecordPtr; statePtr->scriptRecordPtr = esPtr; esPtr->chanPtr = chanPtr; esPtr->interp = interp; esPtr->mask = mask; esPtr->scriptPtr = Tcl_NewStringObj(argv[4], -1); Tcl_IncrRefCount(esPtr->scriptPtr); Tcl_CreateChannelHandler((Tcl_Channel) chanPtr, mask, TclChannelEventScriptInvoker, (ClientData) esPtr); return TCL_OK; } if ((cmd[0] == 'd') && (strncmp(cmd, "delete", (unsigned) len) == 0)) { if (argc != 4) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " channelName delete index\"", (char *) NULL); return TCL_ERROR; } if (Tcl_GetInt(interp, argv[3], &index) == TCL_ERROR) { return TCL_ERROR; } if (index < 0) { Tcl_AppendResult(interp, "bad event index: ", argv[3], ": must be nonnegative", (char *) NULL); return TCL_ERROR; } for (i = 0, esPtr = statePtr->scriptRecordPtr; (i < index) && (esPtr != (EventScriptRecord *) NULL); i++, esPtr = esPtr->nextPtr) { /* Empty loop body. */ } if (esPtr == (EventScriptRecord *) NULL) { Tcl_AppendResult(interp, "bad event index ", argv[3], ": out of range", (char *) NULL); return TCL_ERROR; } if (esPtr == statePtr->scriptRecordPtr) { statePtr->scriptRecordPtr = esPtr->nextPtr; } else { for (prevEsPtr = statePtr->scriptRecordPtr; (prevEsPtr != (EventScriptRecord *) NULL) && (prevEsPtr->nextPtr != esPtr); prevEsPtr = prevEsPtr->nextPtr) { /* Empty loop body. */ } if (prevEsPtr == (EventScriptRecord *) NULL) { panic("TestChannelEventCmd: damaged event script list"); } prevEsPtr->nextPtr = esPtr->nextPtr; } Tcl_DeleteChannelHandler((Tcl_Channel) chanPtr, TclChannelEventScriptInvoker, (ClientData) esPtr); Tcl_DecrRefCount(esPtr->scriptPtr); ckfree((char *) esPtr); return TCL_OK; } if ((cmd[0] == 'l') && (strncmp(cmd, "list", (unsigned) len) == 0)) { if (argc != 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " channelName list\"", (char *) NULL); return TCL_ERROR; } resultListPtr = Tcl_GetObjResult(interp); for (esPtr = statePtr->scriptRecordPtr; esPtr != (EventScriptRecord *) NULL; esPtr = esPtr->nextPtr) { if (esPtr->mask) { Tcl_ListObjAppendElement(interp, resultListPtr, Tcl_NewStringObj( (esPtr->mask == TCL_READABLE) ? "readable" : "writable", -1)); } else { Tcl_ListObjAppendElement(interp, resultListPtr, Tcl_NewStringObj("none", -1)); } Tcl_ListObjAppendElement(interp, resultListPtr, esPtr->scriptPtr); } Tcl_SetObjResult(interp, resultListPtr); return TCL_OK; } if ((cmd[0] == 'r') && (strncmp(cmd, "removeall", (unsigned) len) == 0)) { if (argc != 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " channelName removeall\"", (char *) NULL); return TCL_ERROR; } for (esPtr = statePtr->scriptRecordPtr; esPtr != (EventScriptRecord *) NULL; esPtr = nextEsPtr) { nextEsPtr = esPtr->nextPtr; Tcl_DeleteChannelHandler((Tcl_Channel) chanPtr, TclChannelEventScriptInvoker, (ClientData) esPtr); Tcl_DecrRefCount(esPtr->scriptPtr); ckfree((char *) esPtr); } statePtr->scriptRecordPtr = (EventScriptRecord *) NULL; return TCL_OK; } if ((cmd[0] == 's') && (strncmp(cmd, "set", (unsigned) len) == 0)) { if (argc != 5) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " channelName delete index event\"", (char *) NULL); return TCL_ERROR; } if (Tcl_GetInt(interp, argv[3], &index) == TCL_ERROR) { return TCL_ERROR; } if (index < 0) { Tcl_AppendResult(interp, "bad event index: ", argv[3], ": must be nonnegative", (char *) NULL); return TCL_ERROR; } for (i = 0, esPtr = statePtr->scriptRecordPtr; (i < index) && (esPtr != (EventScriptRecord *) NULL); i++, esPtr = esPtr->nextPtr) { /* Empty loop body. */ } if (esPtr == (EventScriptRecord *) NULL) { Tcl_AppendResult(interp, "bad event index ", argv[3], ": out of range", (char *) NULL); return TCL_ERROR; } if (strcmp(argv[4], "readable") == 0) { mask = TCL_READABLE; } else if (strcmp(argv[4], "writable") == 0) { mask = TCL_WRITABLE; } else if (strcmp(argv[4], "none") == 0) { mask = 0; } else { Tcl_AppendResult(interp, "bad event name \"", argv[4], "\": must be readable, writable, or none", (char *) NULL); return TCL_ERROR; } esPtr->mask = mask; Tcl_CreateChannelHandler((Tcl_Channel) chanPtr, mask, TclChannelEventScriptInvoker, (ClientData) esPtr); return TCL_OK; } Tcl_AppendResult(interp, "bad command ", cmd, ", must be one of ", "add, delete, list, set, or removeall", (char *) NULL); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TestWrongNumArgsObjCmd -- * * Test the Tcl_WrongNumArgs function. * * Results: * Standard Tcl result. * * Side effects: * Sets interpreter result. * *---------------------------------------------------------------------- */ static int TestWrongNumArgsObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int i, length; char *msg; if (objc < 3) { /* * Don't use Tcl_WrongNumArgs here, as that is the function * we want to test! */ Tcl_SetResult(interp, "insufficient arguments", TCL_STATIC); return TCL_ERROR; } if (Tcl_GetIntFromObj(interp, objv[1], &i) != TCL_OK) { return TCL_ERROR; } msg = Tcl_GetStringFromObj(objv[2], &length); if (length == 0) { msg = NULL; } if (i > objc - 3) { /* * Asked for more arguments than were given. */ Tcl_SetResult(interp, "insufficient arguments", TCL_STATIC); return TCL_ERROR; } Tcl_WrongNumArgs(interp, i, &(objv[3]), msg); return TCL_OK; } /* *---------------------------------------------------------------------- * * TestGetIndexFromObjStructObjCmd -- * * Test the Tcl_GetIndexFromObjStruct function. * * Results: * Standard Tcl result. * * Side effects: * Sets interpreter result. * *---------------------------------------------------------------------- */ static int TestGetIndexFromObjStructObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { char *ary[] = { "a", "b", "c", "d", "e", "f", (char *)NULL,(char *)NULL }; int idx,target; if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "argument targetvalue"); return TCL_ERROR; } if (Tcl_GetIndexFromObjStruct(interp, objv[1], ary, 2*sizeof(char *), "dummy", 0, &idx) != TCL_OK) { return TCL_ERROR; } if (Tcl_GetIntFromObj(interp, objv[2], &target) != TCL_OK) { return TCL_ERROR; } if (idx != target) { char buffer[64]; sprintf(buffer, "%d", idx); Tcl_AppendResult(interp, "index value comparison failed: got ", buffer, NULL); sprintf(buffer, "%d", target); Tcl_AppendResult(interp, " when ", buffer, " expected", NULL); return TCL_ERROR; } Tcl_WrongNumArgs(interp, 3, objv, NULL); return TCL_OK; } /* *---------------------------------------------------------------------- * * TestFilesystemObjCmd -- * * This procedure implements the "testfilesystem" command. It is * used to test Tcl_FSRegister, Tcl_FSUnregister, and can be used * to test that the pluggable filesystem works. * * Results: * A standard Tcl result. * * Side effects: * Inserts or removes a filesystem from Tcl's stack. * *---------------------------------------------------------------------- */ static int TestFilesystemObjCmd(dummy, interp, objc, objv) ClientData dummy; Tcl_Interp *interp; int objc; Tcl_Obj *CONST objv[]; { int res, boolVal; char *msg; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "boolean"); return TCL_ERROR; } if (Tcl_GetBooleanFromObj(interp, objv[1], &boolVal) != TCL_OK) { return TCL_ERROR; } if (boolVal) { res = Tcl_FSRegister((ClientData)interp, &testReportingFilesystem); msg = (res == TCL_OK) ? "registered" : "failed"; } else { res = Tcl_FSUnregister(&testReportingFilesystem); msg = (res == TCL_OK) ? "unregistered" : "failed"; } Tcl_SetResult(interp, msg, TCL_VOLATILE); return res; } static int TestReportInFilesystem(Tcl_Obj *pathPtr, ClientData *clientDataPtr) { static Tcl_Obj* lastPathPtr = NULL; if (pathPtr == lastPathPtr) { /* Reject all files second time around */ return -1; } else { Tcl_Obj * newPathPtr; /* Try to claim all files first time around */ newPathPtr = Tcl_DuplicateObj(pathPtr); lastPathPtr = newPathPtr; Tcl_IncrRefCount(newPathPtr); if (Tcl_FSGetFileSystemForPath(newPathPtr) == NULL) { /* Nothing claimed it. Therefore we don't either */ Tcl_DecrRefCount(newPathPtr); lastPathPtr = NULL; return -1; } else { lastPathPtr = NULL; *clientDataPtr = (ClientData) newPathPtr; return TCL_OK; } } } /* * Simple helper function to extract the native vfs representation of a * path object, or NULL if no such representation exists. */ static Tcl_Obj* TestReportGetNativePath(Tcl_Obj* pathObjPtr) { return (Tcl_Obj*) Tcl_FSGetInternalRep(pathObjPtr, &testReportingFilesystem); } static void TestReportFreeInternalRep(ClientData clientData) { Tcl_Obj *nativeRep = (Tcl_Obj*)clientData; if (nativeRep != NULL) { /* Free the path */ Tcl_DecrRefCount(nativeRep); } } static ClientData TestReportDupInternalRep(ClientData clientData) { Tcl_Obj *original = (Tcl_Obj*)clientData; Tcl_IncrRefCount(original); return clientData; } static void TestReport(cmd, path, arg2) CONST char* cmd; Tcl_Obj* path; Tcl_Obj* arg2; { Tcl_Interp* interp = (Tcl_Interp*) Tcl_FSData(&testReportingFilesystem); if (interp == NULL) { /* This is bad, but not much we can do about it */ } else { /* * No idea why I decided to program this up using the * old string-based API, but there you go. We should * convert it to objects. */ Tcl_SavedResult savedResult; Tcl_DString ds; Tcl_DStringInit(&ds); Tcl_DStringAppend(&ds, "lappend filesystemReport ",-1); Tcl_DStringStartSublist(&ds); Tcl_DStringAppendElement(&ds, cmd); if (path != NULL) { Tcl_DStringAppendElement(&ds, Tcl_GetString(path)); } if (arg2 != NULL) { Tcl_DStringAppendElement(&ds, Tcl_GetString(arg2)); } Tcl_DStringEndSublist(&ds); Tcl_SaveResult(interp, &savedResult); Tcl_Eval(interp, Tcl_DStringValue(&ds)); Tcl_DStringFree(&ds); Tcl_RestoreResult(interp, &savedResult); } } static int TestReportStat(path, buf) Tcl_Obj *path; /* Path of file to stat (in current CP). */ Tcl_StatBuf *buf; /* Filled with results of stat call. */ { TestReport("stat",path, NULL); return Tcl_FSStat(TestReportGetNativePath(path),buf); } static int TestReportLstat(path, buf) Tcl_Obj *path; /* Path of file to stat (in current CP). */ Tcl_StatBuf *buf; /* Filled with results of stat call. */ { TestReport("lstat",path, NULL); return Tcl_FSLstat(TestReportGetNativePath(path),buf); } static int TestReportAccess(path, mode) Tcl_Obj *path; /* Path of file to access (in current CP). */ int mode; /* Permission setting. */ { TestReport("access",path,NULL); return Tcl_FSAccess(TestReportGetNativePath(path),mode); } static Tcl_Channel TestReportOpenFileChannel(interp, fileName, mode, permissions) Tcl_Interp *interp; /* Interpreter for error reporting; * can be NULL. */ Tcl_Obj *fileName; /* Name of file to open. */ int mode; /* POSIX open mode. */ int permissions; /* If the open involves creating a * file, with what modes to create * it? */ { TestReport("open",fileName, NULL); return TclpOpenFileChannel(interp, TestReportGetNativePath(fileName), mode, permissions); } static int TestReportMatchInDirectory(interp, resultPtr, dirPtr, pattern, types) Tcl_Interp *interp; /* Interpreter to receive results. */ Tcl_Obj *resultPtr; /* Object to lappend results. */ Tcl_Obj *dirPtr; /* Contains path to directory to search. */ CONST char *pattern; /* Pattern to match against. */ Tcl_GlobTypeData *types; /* Object containing list of acceptable types. * May be NULL. */ { if (types != NULL && types->type & TCL_GLOB_TYPE_MOUNT) { TestReport("matchmounts",dirPtr, NULL); return TCL_OK; } else { TestReport("matchindirectory",dirPtr, NULL); return Tcl_FSMatchInDirectory(interp, resultPtr, TestReportGetNativePath(dirPtr), pattern, types); } } static int TestReportChdir(dirName) Tcl_Obj *dirName; { TestReport("chdir",dirName,NULL); return Tcl_FSChdir(TestReportGetNativePath(dirName)); } static int TestReportLoadFile(interp, fileName, handlePtr, unloadProcPtr) Tcl_Interp *interp; /* Used for error reporting. */ Tcl_Obj *fileName; /* Name of the file containing the desired * code. */ Tcl_LoadHandle *handlePtr; /* Filled with token for dynamically loaded * file which will be passed back to * (*unloadProcPtr)() to unload the file. */ Tcl_FSUnloadFileProc **unloadProcPtr; /* Filled with address of Tcl_FSUnloadFileProc * function which should be used for * this file. */ { TestReport("loadfile",fileName,NULL); return Tcl_FSLoadFile(interp, TestReportGetNativePath(fileName), NULL, NULL, NULL, NULL, handlePtr, unloadProcPtr); } static Tcl_Obj * TestReportLink(path, to, linkType) Tcl_Obj *path; /* Path of file to readlink or link */ Tcl_Obj *to; /* Path of file to link to, or NULL */ int linkType; { TestReport("link",path,to); return Tcl_FSLink(TestReportGetNativePath(path), to, linkType); } static int TestReportRenameFile(src, dst) Tcl_Obj *src; /* Pathname of file or dir to be renamed * (UTF-8). */ Tcl_Obj *dst; /* New pathname of file or directory * (UTF-8). */ { TestReport("renamefile",src,dst); return Tcl_FSRenameFile(TestReportGetNativePath(src), TestReportGetNativePath(dst)); } static int TestReportCopyFile(src, dst) Tcl_Obj *src; /* Pathname of file to be copied (UTF-8). */ Tcl_Obj *dst; /* Pathname of file to copy to (UTF-8). */ { TestReport("copyfile",src,dst); return Tcl_FSCopyFile(TestReportGetNativePath(src), TestReportGetNativePath(dst)); } static int TestReportDeleteFile(path) Tcl_Obj *path; /* Pathname of file to be removed (UTF-8). */ { TestReport("deletefile",path,NULL); return Tcl_FSDeleteFile(TestReportGetNativePath(path)); } static int TestReportCreateDirectory(path) Tcl_Obj *path; /* Pathname of directory to create (UTF-8). */ { TestReport("createdirectory",path,NULL); return Tcl_FSCreateDirectory(TestReportGetNativePath(path)); } static int TestReportCopyDirectory(src, dst, errorPtr) Tcl_Obj *src; /* Pathname of directory to be copied * (UTF-8). */ Tcl_Obj *dst; /* Pathname of target directory (UTF-8). */ Tcl_Obj **errorPtr; /* If non-NULL, to be filled with UTF-8 name * of file causing error. */ { TestReport("copydirectory",src,dst); return Tcl_FSCopyDirectory(TestReportGetNativePath(src), TestReportGetNativePath(dst), errorPtr); } static int TestReportRemoveDirectory(path, recursive, errorPtr) Tcl_Obj *path; /* Pathname of directory to be removed * (UTF-8). */ int recursive; /* If non-zero, removes directories that * are nonempty. Otherwise, will only remove * empty directories. */ Tcl_Obj **errorPtr; /* If non-NULL, to be filled with UTF-8 name * of file causing error. */ { TestReport("removedirectory",path,NULL); return Tcl_FSRemoveDirectory(TestReportGetNativePath(path), recursive, errorPtr); } static CONST char** TestReportFileAttrStrings(fileName, objPtrRef) Tcl_Obj* fileName; Tcl_Obj** objPtrRef; { TestReport("fileattributestrings",fileName,NULL); return Tcl_FSFileAttrStrings(TestReportGetNativePath(fileName), objPtrRef); } static int TestReportFileAttrsGet(interp, index, fileName, objPtrRef) Tcl_Interp *interp; /* The interpreter for error reporting. */ int index; /* index of the attribute command. */ Tcl_Obj *fileName; /* filename we are operating on. */ Tcl_Obj **objPtrRef; /* for output. */ { TestReport("fileattributesget",fileName,NULL); return Tcl_FSFileAttrsGet(interp, index, TestReportGetNativePath(fileName), objPtrRef); } static int TestReportFileAttrsSet(interp, index, fileName, objPtr) Tcl_Interp *interp; /* The interpreter for error reporting. */ int index; /* index of the attribute command. */ Tcl_Obj *fileName; /* filename we are operating on. */ Tcl_Obj *objPtr; /* for input. */ { TestReport("fileattributesset",fileName,objPtr); return Tcl_FSFileAttrsSet(interp, index, TestReportGetNativePath(fileName), objPtr); } static int TestReportUtime (fileName, tval) Tcl_Obj* fileName; struct utimbuf *tval; { TestReport("utime",fileName,NULL); return Tcl_FSUtime(TestReportGetNativePath(fileName), tval); } static int TestReportNormalizePath(interp, pathPtr, nextCheckpoint) Tcl_Interp *interp; Tcl_Obj *pathPtr; int nextCheckpoint; { TestReport("normalizepath",pathPtr,NULL); return nextCheckpoint; } static int SimplePathInFilesystem(Tcl_Obj *pathPtr, ClientData *clientDataPtr) { CONST char *str = Tcl_GetString(pathPtr); if (strncmp(str,"simplefs:/",10)) { return -1; } return TCL_OK; } /* * Since TclCopyChannel insists on an interpreter, we use this * to simplify our test scripts. Would be better if it could * copy without an interp */ static Tcl_Interp *simpleInterpPtr = NULL; /* We use this to ensure we clean up after ourselves */ static Tcl_Obj *tempFile = NULL; /* * This is a very 'hacky' filesystem which is used just to * test two important features of the vfs code: (1) that * you can load a shared library from a vfs, (2) that when * copying files from one fs to another, the 'mtime' is * preserved. * * It treats any file in 'simplefs:/' as a file, and * artificially creates a real file on the fly which it uses * to extract information from. The real file it uses is * whatever follows the trailing '/' (e.g. 'foo' in 'simplefs:/foo'), * and that file is assumed to exist in the native pwd, and is * copied over to the native temporary directory where it is * accessed. * * Please do not consider this filesystem a model of how * things are to be done. It is quite the opposite! But, it * does allow us to test two important features. * * Finally: this fs can only be used from one interpreter. */ static int TestSimpleFilesystemObjCmd(dummy, interp, objc, objv) ClientData dummy; Tcl_Interp *interp; int objc; Tcl_Obj *CONST objv[]; { int res, boolVal; char *msg; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "boolean"); return TCL_ERROR; } if (Tcl_GetBooleanFromObj(interp, objv[1], &boolVal) != TCL_OK) { return TCL_ERROR; } if (boolVal) { res = Tcl_FSRegister((ClientData)interp, &simpleFilesystem); msg = (res == TCL_OK) ? "registered" : "failed"; simpleInterpPtr = interp; } else { if (tempFile != NULL) { Tcl_FSDeleteFile(tempFile); Tcl_DecrRefCount(tempFile); tempFile = NULL; } res = Tcl_FSUnregister(&simpleFilesystem); msg = (res == TCL_OK) ? "unregistered" : "failed"; simpleInterpPtr = NULL; } Tcl_SetResult(interp, msg, TCL_VOLATILE); return res; } /* * Treats a file name 'simplefs:/foo' by copying the file 'foo' * in the current (native) directory to a temporary native file, * and then returns that native file. */ static Tcl_Obj* SimpleCopy(pathPtr) Tcl_Obj *pathPtr; /* Name of file to copy. */ { int res; CONST char *str; Tcl_Obj *origPtr; Tcl_Obj *tempPtr; tempPtr = TclpTempFileName(); Tcl_IncrRefCount(tempPtr); /* * We assume the same name in the current directory is ok. */ str = Tcl_GetString(pathPtr); origPtr = Tcl_NewStringObj(str+10,-1); Tcl_IncrRefCount(origPtr); res = TclCrossFilesystemCopy(simpleInterpPtr, origPtr, tempPtr); Tcl_DecrRefCount(origPtr); if (res != TCL_OK) { Tcl_FSDeleteFile(tempPtr); Tcl_DecrRefCount(tempPtr); return NULL; } return tempPtr; } static Tcl_Channel SimpleOpenFileChannel(interp, pathPtr, mode, permissions) Tcl_Interp *interp; /* Interpreter for error reporting; * can be NULL. */ Tcl_Obj *pathPtr; /* Name of file to open. */ int mode; /* POSIX open mode. */ int permissions; /* If the open involves creating a * file, with what modes to create * it? */ { Tcl_Obj *tempPtr; Tcl_Channel chan; if ((mode != 0) && !(mode & O_RDONLY)) { Tcl_AppendResult(interp, "read-only", (char *) NULL); return NULL; } tempPtr = SimpleCopy(pathPtr); if (tempPtr == NULL) { return NULL; } chan = Tcl_FSOpenFileChannel(interp, tempPtr, "r", permissions); if (tempFile != NULL) { Tcl_FSDeleteFile(tempFile); Tcl_DecrRefCount(tempFile); tempFile = NULL; } /* * Store file pointer in this global variable so we can delete * it later */ tempFile = tempPtr; return chan; } static int SimpleAccess(pathPtr, mode) Tcl_Obj *pathPtr; /* Path of file to access (in current CP). */ int mode; /* Permission setting. */ { /* All files exist */ return TCL_OK; } static int SimpleStat(pathPtr, bufPtr) Tcl_Obj *pathPtr; /* Path of file to stat (in current CP). */ Tcl_StatBuf *bufPtr; /* Filled with results of stat call. */ { Tcl_Obj *tempPtr = SimpleCopy(pathPtr); if (tempPtr == NULL) { /* We just pretend the file exists anyway */ return TCL_OK; } else { int res = Tcl_FSStat(tempPtr, bufPtr); Tcl_FSDeleteFile(tempPtr); Tcl_DecrRefCount(tempPtr); return res; } } static Tcl_Obj* SimpleListVolumes(void) { /* Add one new volume */ Tcl_Obj *retVal; retVal = Tcl_NewStringObj("simplefs:/",-1); Tcl_IncrRefCount(retVal); return retVal; } /* * Used to check correct string-length determining in Tcl_NumUtfChars */ static int TestNumUtfCharsCmd(clientData, interp, objc, objv) ClientData clientData; Tcl_Interp *interp; int objc; Tcl_Obj *CONST objv[]; { if (objc > 1) { int len = -1; if (objc > 2) { (void) Tcl_GetStringFromObj(objv[1], &len); } len = Tcl_NumUtfChars(Tcl_GetString(objv[1]), len); Tcl_SetObjResult(interp, Tcl_NewIntObj(len)); } return TCL_OK; } #if defined(HAVE_CPUID) || defined(__WIN32__) /* *---------------------------------------------------------------------- * * TestcpuidCmd -- * * Retrieves CPU ID information. * * Usage: * testcpuid * * Parameters: * eax - The value to pass in the EAX register to a CPUID instruction. * * Results: * Returns a four-element list containing the values from the * EAX, EBX, ECX and EDX registers returned from the CPUID instruction. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TestcpuidCmd( ClientData dummy, Tcl_Interp* interp, /* Tcl interpreter */ int objc, /* Parameter count */ Tcl_Obj *CONST * objv ) /* Parameter vector */ { int status; int index; unsigned int regs[4]; Tcl_Obj * regsObjs[4]; int i; if ( objc != 2 ) { Tcl_WrongNumArgs( interp, 1, objv, "eax" ); return TCL_ERROR; } if ( Tcl_GetIntFromObj( interp, objv[1], &index ) != TCL_OK ) { return TCL_ERROR; } status = TclWinCPUID( (unsigned int) index, regs ); if ( status != TCL_OK ) { Tcl_SetObjResult( interp, Tcl_NewStringObj( "operation not available", -1 ) ); return status; } for ( i = 0; i < 4; ++i ) { regsObjs[i] = Tcl_NewIntObj( (int) regs[i] ); } Tcl_SetObjResult( interp, Tcl_NewListObj( 4, regsObjs ) ); return TCL_OK; } #endif tcl8.4.20/generic/tclEvent.c0000644003604700454610000011172311737050674014270 0ustar dgp771div/* * tclEvent.c -- * * This file implements some general event related interfaces including * background errors, exit handlers, and the "vwait" and "update" * command procedures. * * Copyright (c) 1990-1994 The Regents of the University of California. * Copyright (c) 1994-1998 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" /* * The data structure below is used to report background errors. One * such structure is allocated for each error; it holds information * about the interpreter and the error until bgerror can be invoked * later as an idle handler. */ typedef struct BgError { Tcl_Interp *interp; /* Interpreter in which error occurred. NULL * means this error report has been cancelled * (a previous report generated a break). */ char *errorMsg; /* Copy of the error message (the interp's * result when the error occurred). * Malloc-ed. */ char *errorInfo; /* Value of the errorInfo variable * (malloc-ed). */ char *errorCode; /* Value of the errorCode variable * (malloc-ed). */ struct BgError *nextPtr; /* Next in list of all pending error * reports for this interpreter, or NULL * for end of list. */ } BgError; /* * One of the structures below is associated with the "tclBgError" * assoc data for each interpreter. It keeps track of the head and * tail of the list of pending background errors for the interpreter. */ typedef struct ErrAssocData { BgError *firstBgPtr; /* First in list of all background errors * waiting to be processed for this * interpreter (NULL if none). */ BgError *lastBgPtr; /* Last in list of all background errors * waiting to be processed for this * interpreter (NULL if none). */ } ErrAssocData; /* * For each exit handler created with a call to Tcl_Create(Late)ExitHandler there is * a structure of the following type: */ typedef struct ExitHandler { Tcl_ExitProc *proc; /* Procedure to call when process exits. */ ClientData clientData; /* One word of information to pass to proc. */ struct ExitHandler *nextPtr;/* Next in list of all exit handlers for * this application, or NULL for end of list. */ } ExitHandler; /* * There is both per-process and per-thread exit handlers. * The first list is controlled by a mutex. The other is in * thread local storage. */ static ExitHandler *firstExitPtr = NULL; /* First in list of all exit handlers for * application. */ static ExitHandler *firstLateExitPtr = NULL; /* First in list of all late exit handlers for * application. */ TCL_DECLARE_MUTEX(exitMutex) /* * This variable is set to 1 when Tcl_Finalize is called, and at the end of * its work, it is reset to 0. The variable is checked by TclInExit() to * allow different behavior for exit-time processing, e.g. in closing of * files and pipes. */ static int inFinalize = 0; static int subsystemsInitialized = 0; typedef struct ThreadSpecificData { ExitHandler *firstExitPtr; /* First in list of all exit handlers for * this thread. */ int inExit; /* True when this thread is exiting. This * is used as a hack to decide to close * the standard channels. */ Tcl_Obj *tclLibraryPath; /* Path(s) to the Tcl library */ } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; /* * Common string for the library path for sharing across threads. * This is ckalloc'd and cleared in Tcl_Finalize. */ static char *tclLibraryPathStr = NULL; #ifdef TCL_THREADS typedef struct { Tcl_ThreadCreateProc *proc; /* Main() function of the thread */ ClientData clientData; /* The one argument to Main() */ } ThreadClientData; static Tcl_ThreadCreateType NewThreadProc _ANSI_ARGS_(( ClientData clientData)); #endif /* * Prototypes for procedures referenced only in this file: */ static void BgErrorDeleteProc _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp)); static void HandleBgErrors _ANSI_ARGS_((ClientData clientData)); static char * VwaitVarProc _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, CONST char *name1, CONST char *name2, int flags)); /* *---------------------------------------------------------------------- * * Tcl_BackgroundError -- * * This procedure is invoked to handle errors that occur in Tcl * commands that are invoked in "background" (e.g. from event or * timer bindings). * * Results: * None. * * Side effects: * The command "bgerror" is invoked later as an idle handler to * process the error, passing it the error message. If that fails, * then an error message is output on stderr. * *---------------------------------------------------------------------- */ void Tcl_BackgroundError(interp) Tcl_Interp *interp; /* Interpreter in which an error has * occurred. */ { BgError *errPtr; CONST char *errResult, *varValue; ErrAssocData *assocPtr; int length; /* * The Tcl_AddErrorInfo call below (with an empty string) ensures that * errorInfo gets properly set. It's needed in cases where the error * came from a utility procedure like Tcl_GetVar instead of Tcl_Eval; * in these cases errorInfo still won't have been set when this * procedure is called. */ Tcl_AddErrorInfo(interp, ""); errResult = Tcl_GetStringFromObj(Tcl_GetObjResult(interp), &length); errPtr = (BgError *) ckalloc(sizeof(BgError)); errPtr->interp = interp; errPtr->errorMsg = (char *) ckalloc((unsigned) (length + 1)); memcpy(errPtr->errorMsg, errResult, (size_t) (length + 1)); varValue = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY); if (varValue == NULL) { varValue = errPtr->errorMsg; } errPtr->errorInfo = (char *) ckalloc((unsigned) (strlen(varValue) + 1)); strcpy(errPtr->errorInfo, varValue); varValue = Tcl_GetVar(interp, "errorCode", TCL_GLOBAL_ONLY); if (varValue == NULL) { varValue = ""; } errPtr->errorCode = (char *) ckalloc((unsigned) (strlen(varValue) + 1)); strcpy(errPtr->errorCode, varValue); errPtr->nextPtr = NULL; assocPtr = (ErrAssocData *) Tcl_GetAssocData(interp, "tclBgError", (Tcl_InterpDeleteProc **) NULL); if (assocPtr == NULL) { /* * This is the first time a background error has occurred in * this interpreter. Create associated data to keep track of * pending error reports. */ assocPtr = (ErrAssocData *) ckalloc(sizeof(ErrAssocData)); assocPtr->firstBgPtr = NULL; assocPtr->lastBgPtr = NULL; Tcl_SetAssocData(interp, "tclBgError", BgErrorDeleteProc, (ClientData) assocPtr); } if (assocPtr->firstBgPtr == NULL) { assocPtr->firstBgPtr = errPtr; Tcl_DoWhenIdle(HandleBgErrors, (ClientData) assocPtr); } else { assocPtr->lastBgPtr->nextPtr = errPtr; } assocPtr->lastBgPtr = errPtr; Tcl_ResetResult(interp); } /* *---------------------------------------------------------------------- * * HandleBgErrors -- * * This procedure is invoked as an idle handler to process all of * the accumulated background errors. * * Results: * None. * * Side effects: * Depends on what actions "bgerror" takes for the errors. * *---------------------------------------------------------------------- */ static void HandleBgErrors(clientData) ClientData clientData; /* Pointer to ErrAssocData structure. */ { Tcl_Interp *interp; CONST char *argv[2]; int code; BgError *errPtr; ErrAssocData *assocPtr = (ErrAssocData *) clientData; Tcl_Channel errChannel; Tcl_Preserve((ClientData) assocPtr); while (assocPtr->firstBgPtr != NULL) { interp = assocPtr->firstBgPtr->interp; if (interp == NULL) { goto doneWithInterp; } /* * Restore important state variables to what they were at * the time the error occurred. */ Tcl_SetVar(interp, "errorInfo", assocPtr->firstBgPtr->errorInfo, TCL_GLOBAL_ONLY); Tcl_SetVar(interp, "errorCode", assocPtr->firstBgPtr->errorCode, TCL_GLOBAL_ONLY); /* * Create and invoke the bgerror command. */ argv[0] = "bgerror"; argv[1] = assocPtr->firstBgPtr->errorMsg; Tcl_AllowExceptions(interp); Tcl_Preserve((ClientData) interp); code = TclGlobalInvoke(interp, 2, argv, 0); if (code == TCL_ERROR) { /* * If the interpreter is safe, we look for a hidden command * named "bgerror" and call that with the error information. * Otherwise, simply ignore the error. The rationale is that * this could be an error caused by a malicious applet trying * to cause an infinite barrage of error messages. The hidden * "bgerror" command can be used by a security policy to * interpose on such attacks and e.g. kill the applet after a * few attempts. */ if (Tcl_IsSafe(interp)) { Tcl_SavedResult save; Tcl_SaveResult(interp, &save); TclGlobalInvoke(interp, 2, argv, TCL_INVOKE_HIDDEN); Tcl_RestoreResult(interp, &save); goto doneWithInterp; } /* * We have to get the error output channel at the latest possible * time, because the eval (above) might have changed the channel. */ errChannel = Tcl_GetStdChannel(TCL_STDERR); if (errChannel != (Tcl_Channel) NULL) { char *string; int len; string = Tcl_GetStringFromObj(Tcl_GetObjResult(interp), &len); if (Tcl_FindCommand(interp, "bgerror", NULL, TCL_GLOBAL_ONLY) == NULL) { Tcl_WriteChars(errChannel, assocPtr->firstBgPtr->errorInfo, -1); Tcl_WriteChars(errChannel, "\n", -1); } else { Tcl_WriteChars(errChannel, "bgerror failed to handle background error.\n", -1); Tcl_WriteChars(errChannel, " Original error: ", -1); Tcl_WriteChars(errChannel, assocPtr->firstBgPtr->errorMsg, -1); Tcl_WriteChars(errChannel, "\n", -1); Tcl_WriteChars(errChannel, " Error in bgerror: ", -1); Tcl_WriteChars(errChannel, string, len); Tcl_WriteChars(errChannel, "\n", -1); } Tcl_Flush(errChannel); } } else if (code == TCL_BREAK) { /* * Break means cancel any remaining error reports for this * interpreter. */ for (errPtr = assocPtr->firstBgPtr; errPtr != NULL; errPtr = errPtr->nextPtr) { if (errPtr->interp == interp) { errPtr->interp = NULL; } } } /* * Discard the command and the information about the error report. */ doneWithInterp: if (assocPtr->firstBgPtr) { ckfree(assocPtr->firstBgPtr->errorMsg); ckfree(assocPtr->firstBgPtr->errorInfo); ckfree(assocPtr->firstBgPtr->errorCode); errPtr = assocPtr->firstBgPtr->nextPtr; ckfree((char *) assocPtr->firstBgPtr); assocPtr->firstBgPtr = errPtr; } if (interp != NULL) { Tcl_Release((ClientData) interp); } } assocPtr->lastBgPtr = NULL; Tcl_Release((ClientData) assocPtr); } /* *---------------------------------------------------------------------- * * BgErrorDeleteProc -- * * This procedure is associated with the "tclBgError" assoc data * for an interpreter; it is invoked when the interpreter is * deleted in order to free the information assoicated with any * pending error reports. * * Results: * None. * * Side effects: * Background error information is freed: if there were any * pending error reports, they are cancelled. * *---------------------------------------------------------------------- */ static void BgErrorDeleteProc(clientData, interp) ClientData clientData; /* Pointer to ErrAssocData structure. */ Tcl_Interp *interp; /* Interpreter being deleted. */ { ErrAssocData *assocPtr = (ErrAssocData *) clientData; BgError *errPtr; while (assocPtr->firstBgPtr != NULL) { errPtr = assocPtr->firstBgPtr; assocPtr->firstBgPtr = errPtr->nextPtr; ckfree(errPtr->errorMsg); ckfree(errPtr->errorInfo); ckfree(errPtr->errorCode); ckfree((char *) errPtr); } Tcl_CancelIdleCall(HandleBgErrors, (ClientData) assocPtr); Tcl_EventuallyFree((ClientData) assocPtr, TCL_DYNAMIC); } /* *---------------------------------------------------------------------- * * Tcl_CreateExitHandler -- * * Arrange for a given procedure to be invoked just before the * application exits. * * Results: * None. * * Side effects: * Proc will be invoked with clientData as argument when the * application exits. * *---------------------------------------------------------------------- */ void Tcl_CreateExitHandler(proc, clientData) Tcl_ExitProc *proc; /* Procedure to invoke. */ ClientData clientData; /* Arbitrary value to pass to proc. */ { ExitHandler *exitPtr; exitPtr = (ExitHandler *) ckalloc(sizeof(ExitHandler)); exitPtr->proc = proc; exitPtr->clientData = clientData; Tcl_MutexLock(&exitMutex); exitPtr->nextPtr = firstExitPtr; firstExitPtr = exitPtr; Tcl_MutexUnlock(&exitMutex); } /* *---------------------------------------------------------------------- * * TclCreateLateExitHandler -- * * Arrange for a given function to be invoked after all pre-thread cleanups * * Results: * None. * * Side effects: * Proc will be invoked with clientData as argument when the application * exits. * *---------------------------------------------------------------------- */ void TclCreateLateExitHandler( Tcl_ExitProc *proc, /* Function to invoke. */ ClientData clientData) /* Arbitrary value to pass to proc. */ { ExitHandler *exitPtr; exitPtr = (ExitHandler *) ckalloc(sizeof(ExitHandler)); exitPtr->proc = proc; exitPtr->clientData = clientData; Tcl_MutexLock(&exitMutex); exitPtr->nextPtr = firstLateExitPtr; firstLateExitPtr = exitPtr; Tcl_MutexUnlock(&exitMutex); } /* *---------------------------------------------------------------------- * * Tcl_DeleteExitHandler -- * * This procedure cancels an existing exit handler matching proc * and clientData, if such a handler exits. * * Results: * None. * * Side effects: * If there is an exit handler corresponding to proc and clientData * then it is cancelled; if no such handler exists then nothing * happens. * *---------------------------------------------------------------------- */ void Tcl_DeleteExitHandler(proc, clientData) Tcl_ExitProc *proc; /* Procedure that was previously registered. */ ClientData clientData; /* Arbitrary value to pass to proc. */ { ExitHandler *exitPtr, *prevPtr; Tcl_MutexLock(&exitMutex); for (prevPtr = NULL, exitPtr = firstExitPtr; exitPtr != NULL; prevPtr = exitPtr, exitPtr = exitPtr->nextPtr) { if ((exitPtr->proc == proc) && (exitPtr->clientData == clientData)) { if (prevPtr == NULL) { firstExitPtr = exitPtr->nextPtr; } else { prevPtr->nextPtr = exitPtr->nextPtr; } ckfree((char *) exitPtr); break; } } Tcl_MutexUnlock(&exitMutex); return; } /* *---------------------------------------------------------------------- * * TclDeleteLateExitHandler -- * * This function cancels an existing late exit handler matching proc and * clientData, if such a handler exits. * * Results: * None. * * Side effects: * If there is a late exit handler corresponding to proc and clientData then * it is canceled; if no such handler exists then nothing happens. * *---------------------------------------------------------------------- */ void TclDeleteLateExitHandler( Tcl_ExitProc *proc, /* Function that was previously registered. */ ClientData clientData) /* Arbitrary value to pass to proc. */ { ExitHandler *exitPtr, *prevPtr; Tcl_MutexLock(&exitMutex); for (prevPtr = NULL, exitPtr = firstLateExitPtr; exitPtr != NULL; prevPtr = exitPtr, exitPtr = exitPtr->nextPtr) { if ((exitPtr->proc == proc) && (exitPtr->clientData == clientData)) { if (prevPtr == NULL) { firstLateExitPtr = exitPtr->nextPtr; } else { prevPtr->nextPtr = exitPtr->nextPtr; } ckfree((char *) exitPtr); break; } } Tcl_MutexUnlock(&exitMutex); return; } /* *---------------------------------------------------------------------- * * Tcl_CreateThreadExitHandler -- * * Arrange for a given procedure to be invoked just before the * current thread exits. * * Results: * None. * * Side effects: * Proc will be invoked with clientData as argument when the * application exits. * *---------------------------------------------------------------------- */ void Tcl_CreateThreadExitHandler(proc, clientData) Tcl_ExitProc *proc; /* Procedure to invoke. */ ClientData clientData; /* Arbitrary value to pass to proc. */ { ExitHandler *exitPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); exitPtr = (ExitHandler *) ckalloc(sizeof(ExitHandler)); exitPtr->proc = proc; exitPtr->clientData = clientData; exitPtr->nextPtr = tsdPtr->firstExitPtr; tsdPtr->firstExitPtr = exitPtr; } /* *---------------------------------------------------------------------- * * Tcl_DeleteThreadExitHandler -- * * This procedure cancels an existing exit handler matching proc * and clientData, if such a handler exits. * * Results: * None. * * Side effects: * If there is an exit handler corresponding to proc and clientData * then it is cancelled; if no such handler exists then nothing * happens. * *---------------------------------------------------------------------- */ void Tcl_DeleteThreadExitHandler(proc, clientData) Tcl_ExitProc *proc; /* Procedure that was previously registered. */ ClientData clientData; /* Arbitrary value to pass to proc. */ { ExitHandler *exitPtr, *prevPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); for (prevPtr = NULL, exitPtr = tsdPtr->firstExitPtr; exitPtr != NULL; prevPtr = exitPtr, exitPtr = exitPtr->nextPtr) { if ((exitPtr->proc == proc) && (exitPtr->clientData == clientData)) { if (prevPtr == NULL) { tsdPtr->firstExitPtr = exitPtr->nextPtr; } else { prevPtr->nextPtr = exitPtr->nextPtr; } ckfree((char *) exitPtr); return; } } } /* *---------------------------------------------------------------------- * * Tcl_Exit -- * * This procedure is called to terminate the application. * * Results: * None. * * Side effects: * All existing exit handlers are invoked, then the application * ends. * *---------------------------------------------------------------------- */ void Tcl_Exit(status) int status; /* Exit status for application; typically * 0 for normal return, 1 for error return. */ { Tcl_Finalize(); TclpExit(status); } /* *------------------------------------------------------------------------- * * TclSetLibraryPath -- * * Set the path that will be used for searching for init.tcl and * encodings when an interp is being created. * * Results: * None. * * Side effects: * Changing the library path will affect what directories are * examined when looking for encodings for all interps from that * point forward. * * The refcount of the new library path is incremented and the * refcount of the old path is decremented. * *------------------------------------------------------------------------- */ void TclSetLibraryPath(pathPtr) Tcl_Obj *pathPtr; /* A Tcl list object whose elements are * the new library path. */ { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); const char *toDupe; int size; if (pathPtr != NULL) { Tcl_IncrRefCount(pathPtr); } if (tsdPtr->tclLibraryPath != NULL) { Tcl_DecrRefCount(tsdPtr->tclLibraryPath); } tsdPtr->tclLibraryPath = pathPtr; /* * No mutex locking is needed here as up the stack we're within * TclpInitLock(). */ if (tclLibraryPathStr != NULL) { ckfree(tclLibraryPathStr); } toDupe = Tcl_GetStringFromObj(pathPtr, &size); tclLibraryPathStr = ckalloc((unsigned)size+1); memcpy(tclLibraryPathStr, toDupe, (unsigned)size+1); } /* *------------------------------------------------------------------------- * * TclGetLibraryPath -- * * Return a Tcl list object whose elements are the library path. * The caller should not modify the contents of the returned object. * * Results: * As above. * * Side effects: * None. * *------------------------------------------------------------------------- */ Tcl_Obj * TclGetLibraryPath() { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (tsdPtr->tclLibraryPath == NULL) { /* * Grab the shared string and place it into a new thread specific * Tcl_Obj. */ tsdPtr->tclLibraryPath = Tcl_NewStringObj(tclLibraryPathStr, -1); /* take ownership */ Tcl_IncrRefCount(tsdPtr->tclLibraryPath); } return tsdPtr->tclLibraryPath; } /* *------------------------------------------------------------------------- * * TclInitSubsystems -- * * Initialize various subsytems in Tcl. This should be called the * first time an interp is created, or before any of the subsystems * are used. This function ensures an order for the initialization * of subsystems: * * 1. that cannot be initialized in lazy order because they are * mutually dependent. * * 2. so that they can be finalized in a known order w/o causing * the subsequent re-initialization of a subsystem in the act of * shutting down another. * * Results: * None. * * Side effects: * Varied, see the respective initialization routines. * *------------------------------------------------------------------------- */ void TclInitSubsystems(argv0) CONST char *argv0; /* Name of executable from argv[0] to main() * in native multi-byte encoding. */ { ThreadSpecificData *tsdPtr; if (inFinalize != 0) { panic("TclInitSubsystems called while finalizing"); } /* * Grab the thread local storage pointer before doing anything because * the initialization routines will be registering exit handlers. * We use this pointer to detect if this is the first time this * thread has created an interpreter. */ tsdPtr = (ThreadSpecificData *) TclThreadDataKeyGet(&dataKey); if (subsystemsInitialized == 0) { /* * Double check inside the mutex. There are definitly calls * back into this routine from some of the procedures below. */ TclpInitLock(); if (subsystemsInitialized == 0) { /* * Have to set this bit here to avoid deadlock with the * routines below us that call into TclInitSubsystems. */ subsystemsInitialized = 1; tclExecutableName = NULL; /* * Initialize locks used by the memory allocators before anything * interesting happens so we can use the allocators in the * implementation of self-initializing locks. */ #if USE_TCLALLOC TclInitAlloc(); /* process wide mutex init */ #endif #ifdef TCL_MEM_DEBUG TclInitDbCkalloc(); /* process wide mutex init */ #endif TclpInitPlatform(); /* creates signal handler(s) */ TclInitObjSubsystem(); /* register obj types, create mutexes */ TclInitIOSubsystem(); /* inits a tsd key (noop) */ TclInitEncodingSubsystem(); /* process wide encoding init */ TclInitNamespaceSubsystem(); /* register ns obj type (mutexed) */ } TclpInitUnlock(); } if (tsdPtr == NULL) { /* * First time this thread has created an interpreter. * We fetch the key again just in case no exit handlers were * registered by this point. */ (void) TCL_TSD_INIT(&dataKey); TclInitNotifier(); } } /* *---------------------------------------------------------------------- * * Tcl_Finalize -- * * Shut down Tcl. First calls registered exit handlers, then * carefully shuts down various subsystems. * Called by Tcl_Exit or when the Tcl shared library is being * unloaded. * * Results: * None. * * Side effects: * Varied, see the respective finalization routines. * *---------------------------------------------------------------------- */ void Tcl_Finalize() { ExitHandler *exitPtr; /* * Invoke exit handlers first. */ Tcl_MutexLock(&exitMutex); inFinalize = 1; for (exitPtr = firstExitPtr; exitPtr != NULL; exitPtr = firstExitPtr) { /* * Be careful to remove the handler from the list before * invoking its callback. This protects us against * double-freeing if the callback should call * Tcl_DeleteExitHandler on itself. */ firstExitPtr = exitPtr->nextPtr; Tcl_MutexUnlock(&exitMutex); (*exitPtr->proc)(exitPtr->clientData); ckfree((char *) exitPtr); Tcl_MutexLock(&exitMutex); } firstExitPtr = NULL; Tcl_MutexUnlock(&exitMutex); TclpInitLock(); if (subsystemsInitialized != 0) { subsystemsInitialized = 0; /* * Ensure the thread-specific data is initialised as it is * used in Tcl_FinalizeThread() */ (void) TCL_TSD_INIT(&dataKey); /* * Clean up after the current thread now, after exit handlers. * In particular, the testexithandler command sets up something * that writes to standard output, which gets closed. * Note that there is no thread-local storage after this call. */ Tcl_FinalizeThread(); /* * Now invoke late (process-wide) exit handlers. */ Tcl_MutexLock(&exitMutex); for (exitPtr = firstLateExitPtr; exitPtr != NULL; exitPtr = firstLateExitPtr) { /* * Be careful to remove the handler from the list before invoking its * callback. This protects us against double-freeing if the callback * should call Tcl_DeleteLateExitHandler on itself. */ firstLateExitPtr = exitPtr->nextPtr; Tcl_MutexUnlock(&exitMutex); exitPtr->proc(exitPtr->clientData); ckfree((char *) exitPtr); Tcl_MutexLock(&exitMutex); } firstLateExitPtr = NULL; Tcl_MutexUnlock(&exitMutex); /* * Now finalize the Tcl execution environment. Note that this must be done * after the exit handlers, because there are order dependencies. */ TclFinalizeCompilation(); TclFinalizeExecution(); TclFinalizeEnvironment(); /* * Finalizing the filesystem must come after anything which * might conceivably interact with the 'Tcl_FS' API. */ TclFinalizeFilesystem(); /* * Undo all the Tcl_ObjType registrations, and reset the master list * of free Tcl_Obj's. After this returns, no more Tcl_Obj's should * be allocated or freed. * * Note in particular that TclFinalizeObjects() must follow * TclFinalizeFilesystem() because TclFinalizeFilesystem free's * the Tcl_Obj that holds the path of the current working directory. */ TclFinalizeObjects(); /* * We must be sure the encoding finalization doesn't need * to examine the filesystem in any way. Since it only * needs to clean up internal data structures, this is * fine. */ TclFinalizeEncodingSubsystem(); if (tclExecutableName != NULL) { ckfree(tclExecutableName); tclExecutableName = NULL; } if (tclNativeExecutableName != NULL) { ckfree(tclNativeExecutableName); tclNativeExecutableName = NULL; } if (tclDefaultEncodingDir != NULL) { ckfree(tclDefaultEncodingDir); tclDefaultEncodingDir = NULL; } if (tclLibraryPathStr != NULL) { ckfree(tclLibraryPathStr); tclLibraryPathStr = NULL; } Tcl_SetPanicProc(NULL); /* * There have been several bugs in the past that cause * exit handlers to be established during Tcl_Finalize * processing. Such exit handlers leave malloc'ed memory, * and Tcl_FinalizeThreadAlloc or Tcl_FinalizeMemorySubsystem * will result in a corrupted heap. The result can be a * mysterious crash on process exit. Check here that * nobody's done this. */ #ifdef TCL_MEM_DEBUG if ( firstExitPtr != NULL ) { Tcl_Panic( "exit handlers were created during Tcl_Finalize" ); } #endif TclFinalizePreserve(); /* * Free synchronization objects. There really should only be one * thread alive at this moment. */ TclFinalizeSynchronization(); #if defined(TCL_THREADS) && defined(USE_THREAD_ALLOC) && !defined(TCL_MEM_DEBUG) && !defined(PURIFY) TclFinalizeThreadAlloc(); #endif /* * We defer unloading of packages until very late * to avoid memory access issues. Both exit callbacks and * synchronization variables may be stored in packages. * * Note that TclFinalizeLoad unloads packages in the reverse * of the order they were loaded in (i.e. last to be loaded * is the first to be unloaded). This can be important for * correct unloading when dependencies exist. * * Once load has been finalized, we will have deleted any * temporary copies of shared libraries and can therefore * reset the filesystem to its original state. */ TclFinalizeLoad(); TclResetFilesystem(); /* * At this point, there should no longer be any ckalloc'ed memory. */ TclFinalizeMemorySubsystem(); inFinalize = 0; } TclFinalizeLock(); } /* *---------------------------------------------------------------------- * * Tcl_FinalizeThread -- * * Runs the exit handlers to allow Tcl to clean up its state * about a particular thread. * * Results: * None. * * Side effects: * Varied, see the respective finalization routines. * *---------------------------------------------------------------------- */ void Tcl_FinalizeThread() { ExitHandler *exitPtr; ThreadSpecificData *tsdPtr; tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); if (tsdPtr != NULL) { tsdPtr->inExit = 1; /* * Clean up the library path now, before we invalidate thread-local * storage or calling thread exit handlers. */ if (tsdPtr->tclLibraryPath != NULL) { Tcl_DecrRefCount(tsdPtr->tclLibraryPath); tsdPtr->tclLibraryPath = NULL; } for (exitPtr = tsdPtr->firstExitPtr; exitPtr != NULL; exitPtr = tsdPtr->firstExitPtr) { /* * Be careful to remove the handler from the list before invoking * its callback. This protects us against double-freeing if the * callback should call Tcl_DeleteThreadExitHandler on itself. */ tsdPtr->firstExitPtr = exitPtr->nextPtr; (*exitPtr->proc)(exitPtr->clientData); ckfree((char *) exitPtr); } TclFinalizeIOSubsystem(); TclFinalizeNotifier(); TclFinalizeAsync(); } /* * Blow away all thread local storage blocks. * * Note that Tcl API allows creation of threads which do not use any * Tcl interp or other Tcl subsytems. Those threads might, however, * use thread local storage, so we must unconditionally finalize it. * * Fix [Bug #571002] */ TclFinalizeThreadData(); } /* *---------------------------------------------------------------------- * * TclInExit -- * * Determines if we are in the middle of exit-time cleanup. * * Results: * If we are in the middle of exiting, 1, otherwise 0. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclInExit() { return inFinalize; } /* *---------------------------------------------------------------------- * * TclInThreadExit -- * * Determines if we are in the middle of thread exit-time cleanup. * * Results: * If we are in the middle of exiting this thread, 1, otherwise 0. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclInThreadExit() { ThreadSpecificData *tsdPtr = (ThreadSpecificData *) TclThreadDataKeyGet(&dataKey); if (tsdPtr == NULL) { return 0; } else { return tsdPtr->inExit; } } /* *---------------------------------------------------------------------- * * Tcl_VwaitObjCmd -- * * This procedure is invoked to process the "vwait" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_VwaitObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int done, foundEvent; char *nameString; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "name"); return TCL_ERROR; } nameString = Tcl_GetString(objv[1]); if (Tcl_TraceVar(interp, nameString, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, VwaitVarProc, (ClientData) &done) != TCL_OK) { return TCL_ERROR; }; done = 0; foundEvent = 1; while (!done && foundEvent) { foundEvent = Tcl_DoOneEvent(TCL_ALL_EVENTS); } Tcl_UntraceVar(interp, nameString, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, VwaitVarProc, (ClientData) &done); /* * Clear out the interpreter's result, since it may have been set * by event handlers. */ Tcl_ResetResult(interp); if (!foundEvent) { Tcl_AppendResult(interp, "can't wait for variable \"", nameString, "\": would wait forever", (char *) NULL); return TCL_ERROR; } return TCL_OK; } /* ARGSUSED */ static char * VwaitVarProc(clientData, interp, name1, name2, flags) ClientData clientData; /* Pointer to integer to set to 1. */ Tcl_Interp *interp; /* Interpreter containing variable. */ CONST char *name1; /* Name of variable. */ CONST char *name2; /* Second part of variable name. */ int flags; /* Information about what happened. */ { int *donePtr = (int *) clientData; *donePtr = 1; return (char *) NULL; } /* *---------------------------------------------------------------------- * * Tcl_UpdateObjCmd -- * * This procedure is invoked to process the "update" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_UpdateObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int optionIndex; int flags = 0; /* Initialized to avoid compiler warning. */ static CONST char *updateOptions[] = {"idletasks", (char *) NULL}; enum updateOptions {REGEXP_IDLETASKS}; if (objc == 1) { flags = TCL_ALL_EVENTS|TCL_DONT_WAIT; } else if (objc == 2) { if (Tcl_GetIndexFromObj(interp, objv[1], updateOptions, "option", 0, &optionIndex) != TCL_OK) { return TCL_ERROR; } switch ((enum updateOptions) optionIndex) { case REGEXP_IDLETASKS: { flags = TCL_WINDOW_EVENTS|TCL_IDLE_EVENTS|TCL_DONT_WAIT; break; } default: { panic("Tcl_UpdateObjCmd: bad option index to UpdateOptions"); } } } else { Tcl_WrongNumArgs(interp, 1, objv, "?idletasks?"); return TCL_ERROR; } while (Tcl_DoOneEvent(flags) != 0) { /* Empty loop body */ } /* * Must clear the interpreter's result because event handlers could * have executed commands. */ Tcl_ResetResult(interp); return TCL_OK; } #ifdef TCL_THREADS /* *----------------------------------------------------------------------------- * * NewThreadProc -- * * Bootstrap function of a new Tcl thread. * * Results: * None. * * Side Effects: * Initializes Tcl notifier for the current thread. * *----------------------------------------------------------------------------- */ static Tcl_ThreadCreateType NewThreadProc(ClientData clientData) { ThreadClientData *cdPtr; ClientData threadClientData; Tcl_ThreadCreateProc *threadProc; cdPtr = (ThreadClientData*)clientData; threadProc = cdPtr->proc; threadClientData = cdPtr->clientData; ckfree((char*)clientData); /* Allocated in Tcl_CreateThread() */ (*threadProc)(threadClientData); TCL_THREAD_CREATE_RETURN; } #endif /* *---------------------------------------------------------------------- * * Tcl_CreateThread -- * * This procedure creates a new thread. This actually belongs * to the tclThread.c file but since we use some private * data structures local to this file, it is placed here. * * Results: * TCL_OK if the thread could be created. The thread ID is * returned in a parameter. * * Side effects: * A new thread is created. * *---------------------------------------------------------------------- */ int Tcl_CreateThread(idPtr, proc, clientData, stackSize, flags) Tcl_ThreadId *idPtr; /* Return, the ID of the thread */ Tcl_ThreadCreateProc proc; /* Main() function of the thread */ ClientData clientData; /* The one argument to Main() */ int stackSize; /* Size of stack for the new thread */ int flags; /* Flags controlling behaviour of * the new thread */ { #ifdef TCL_THREADS ThreadClientData *cdPtr; cdPtr = (ThreadClientData*)ckalloc(sizeof(ThreadClientData)); cdPtr->proc = proc; cdPtr->clientData = clientData; return TclpThreadCreate(idPtr, NewThreadProc, (ClientData)cdPtr, stackSize, flags); #else return TCL_ERROR; #endif /* TCL_THREADS */ } tcl8.4.20/generic/tclStubInit.c0000644003604700454610000010765112144442333014743 0ustar dgp771div/* * tclStubInit.c -- * * This file contains the initializers for the Tcl stub vectors. * * Copyright (c) 1998-1999 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" /* * Remove macros that will interfere with the definitions below. */ #undef Tcl_Alloc #undef Tcl_Free #undef Tcl_Realloc #undef Tcl_NewBooleanObj #undef Tcl_NewByteArrayObj #undef Tcl_NewDoubleObj #undef Tcl_NewIntObj #undef Tcl_NewListObj #undef Tcl_NewLongObj #undef Tcl_NewObj #undef Tcl_NewStringObj #undef Tcl_DumpActiveMemory #undef Tcl_ValidateAllMemory #undef Tcl_FindHashEntry #undef Tcl_CreateHashEntry #undef TclpGetPid #undef TclSockMinimumBuffers #define TclUnusedStubEntry NULL /* * Keep a record of the original Notifier procedures, created in the * same compilation unit as the stub tables so we can later do reliable, * portable comparisons to see whether a Tcl_SetNotifier() call swapped * new routines into the stub table. */ Tcl_NotifierProcs tclOriginalNotifier = { Tcl_SetTimer, Tcl_WaitForEvent, #if !defined(__WIN32__) /* UNIX */ Tcl_CreateFileHandler, Tcl_DeleteFileHandler, #else NULL, NULL, #endif NULL, NULL, NULL, NULL }; /* See bug 510001: TclSockMinimumBuffers needs plat imp */ #ifdef _WIN64 # define TclSockMinimumBuffersOld 0 #else int TclSockMinimumBuffersOld(sock, size) int sock; int size; { return TclSockMinimumBuffers((void *) (size_t) sock, size); } #endif #ifdef __WIN32__ # define TclUnixWaitForFile 0 # define TclpReaddir 0 # define TclpIsAtty 0 #elif defined(__CYGWIN__) # define TclpIsAtty TclPlatIsAtty # define TclWinSetInterfaces (void (*) (int)) doNothing # define TclWinAddProcess (void (*) (void *, unsigned int)) doNothing # define TclWinFlushDirtyChannels doNothing # define TclWinResetInterfaces doNothing # define TclpGetTZName 0 static Tcl_Encoding winTCharEncoding; static int TclpIsAtty(int fd) { return isatty(fd); } int TclWinGetPlatformId() { /* Don't bother to determine the real platform on cygwin, * because VER_PLATFORM_WIN32_NT is the only supported platform */ return 2; /* VER_PLATFORM_WIN32_NT */; } TclPlatformType * TclWinGetPlatform() { return &tclPlatform; } void *TclWinGetTclInstance() { void *hInstance = NULL; GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char *)&winTCharEncoding, &hInstance); return hInstance; } unsigned short TclWinNToHS(unsigned short ns) { return ntohs(ns); } int TclWinSetSockOpt(SOCKET s, int level, int optname, const char *optval, int optlen) { return setsockopt((int) s, level, optname, optval, optlen); } int TclWinGetSockOpt(SOCKET s, int level, int optname, char *optval, int *optlen) { return getsockopt((int) s, level, optname, optval, optlen); } struct servent * TclWinGetServByName(const char *name, const char *proto) { return getservbyname(name, proto); } char * TclWinNoBackslash(char *path) { char *p; for (p = path; *p != '\0'; p++) { if (*p == '\\') { *p = '/'; } } return path; } int TclpGetPid(Tcl_Pid pid) { return (int) (size_t) pid; } static void doNothing(void) { /* dummy implementation, no need to do anything */ } char * Tcl_WinUtfToTChar( const char *string, int len, Tcl_DString *dsPtr) { if (!winTCharEncoding) { winTCharEncoding = Tcl_GetEncoding(0, "unicode"); } return Tcl_UtfToExternalDString(winTCharEncoding, string, len, dsPtr); } char * Tcl_WinTCharToUtf( const char *string, int len, Tcl_DString *dsPtr) { if (!winTCharEncoding) { winTCharEncoding = Tcl_GetEncoding(0, "unicode"); } return Tcl_ExternalToUtfDString(winTCharEncoding, string, len, dsPtr); } #if defined(TCL_WIDE_INT_IS_LONG) /* On Cygwin64, long is 64-bit while on Win64 long is 32-bit. Therefore * we have to make sure that all stub entries on Cygwin64 follow the Win64 * signature. Tcl 9 must find a better solution, but that cannot be done * without introducing a binary incompatibility. */ #define Tcl_DbNewLongObj ((Tcl_Obj*(*)(long,const char*,int))dbNewLongObj) static Tcl_Obj *dbNewLongObj( int intValue, const char *file, int line ) { #ifdef TCL_MEM_DEBUG register Tcl_Obj *objPtr; TclDbNewObj(objPtr, file, line); objPtr->bytes = NULL; objPtr->internalRep.longValue = (long) intValue; objPtr->typePtr = &tclIntType; return objPtr; #else return Tcl_NewIntObj(intValue); #endif } #define Tcl_GetLongFromObj (int(*)(Tcl_Interp*,Tcl_Obj*,long*))Tcl_GetIntFromObj #define Tcl_NewLongObj (Tcl_Obj*(*)(long))Tcl_NewIntObj #define Tcl_SetLongObj (void(*)(Tcl_Obj*,long))Tcl_SetIntObj static int exprInt(Tcl_Interp *interp, const char *expr, int *ptr){ long longValue; int result = Tcl_ExprLong(interp, expr, &longValue); if (result == TCL_OK) { if ((longValue >= -(long)(UINT_MAX)) && (longValue <= (long)(UINT_MAX))) { *ptr = (int)longValue; } else { Tcl_SetResult(interp, "integer value too large to represent as non-long integer", TCL_STATIC); result = TCL_ERROR; } } return result; } #define Tcl_ExprLong (int(*)(Tcl_Interp*,const char*,long*))exprInt static int exprIntObj(Tcl_Interp *interp, Tcl_Obj*expr, int *ptr){ long longValue; int result = Tcl_ExprLongObj(interp, expr, &longValue); if (result == TCL_OK) { if ((longValue >= -(long)(UINT_MAX)) && (longValue <= (long)(UINT_MAX))) { *ptr = (int)longValue; } else { Tcl_SetResult(interp, "integer value too large to represent as non-long integer", TCL_STATIC); result = TCL_ERROR; } } return result; } #define Tcl_ExprLongObj (int(*)(Tcl_Interp*,Tcl_Obj*,long*))exprIntObj static int uniCharNcmp(const Tcl_UniChar *ucs, const Tcl_UniChar *uct, unsigned int n){ return Tcl_UniCharNcmp(ucs, uct, (unsigned long)n); } #define Tcl_UniCharNcmp (int(*)(const Tcl_UniChar*,const Tcl_UniChar*,unsigned long))uniCharNcmp static int utfNcmp(const char *s1, const char *s2, unsigned int n){ return Tcl_UtfNcmp(s1, s2, (unsigned long)n); } #define Tcl_UtfNcmp (int(*)(const char*,const char*,unsigned long))utfNcmp static int utfNcasecmp(const char *s1, const char *s2, unsigned int n){ return Tcl_UtfNcasecmp(s1, s2, (unsigned long)n); } #define Tcl_UtfNcasecmp (int(*)(const char*,const char*,unsigned long))utfNcasecmp static int uniCharNcasecmp(const Tcl_UniChar *ucs, const Tcl_UniChar *uct, unsigned int n){ return Tcl_UniCharNcasecmp(ucs, uct, (unsigned long)n); } #define Tcl_UniCharNcasecmp (int(*)(const Tcl_UniChar*,const Tcl_UniChar*,unsigned long))uniCharNcasecmp static int formatInt(char *buffer, int n){ return TclFormatInt(buffer, (long)n); } #define TclFormatInt (int(*)(char *, long))formatInt #endif #else /* UNIX and MAC */ # define TclpGetPid 0 # define TclpLocaltime_unix TclpLocaltime # define TclpGmtime_unix TclpGmtime #endif /* * WARNING: The contents of this file is automatically generated by the * tools/genStubs.tcl script. Any modifications to the function declarations * below should be made in the generic/tcl.decls script. */ /* !BEGIN!: Do not edit below this line. */ TclIntStubs tclIntStubs = { TCL_STUB_MAGIC, NULL, NULL, /* 0 */ TclAccessDeleteProc, /* 1 */ TclAccessInsertProc, /* 2 */ TclAllocateFreeObjects, /* 3 */ NULL, /* 4 */ TclCleanupChildren, /* 5 */ TclCleanupCommand, /* 6 */ TclCopyAndCollapse, /* 7 */ TclCopyChannel, /* 8 */ TclCreatePipeline, /* 9 */ TclCreateProc, /* 10 */ TclDeleteCompiledLocalVars, /* 11 */ TclDeleteVars, /* 12 */ TclDoGlob, /* 13 */ TclDumpMemoryInfo, /* 14 */ NULL, /* 15 */ TclExprFloatError, /* 16 */ NULL, /* 17 */ NULL, /* 18 */ NULL, /* 19 */ NULL, /* 20 */ NULL, /* 21 */ TclFindElement, /* 22 */ TclFindProc, /* 23 */ TclFormatInt, /* 24 */ TclFreePackageInfo, /* 25 */ NULL, /* 26 */ TclGetDate, /* 27 */ TclpGetDefaultStdChannel, /* 28 */ NULL, /* 29 */ NULL, /* 30 */ TclGetExtension, /* 31 */ TclGetFrame, /* 32 */ TclGetInterpProc, /* 33 */ TclGetIntForIndex, /* 34 */ NULL, /* 35 */ TclGetLong, /* 36 */ TclGetLoadedPackages, /* 37 */ TclGetNamespaceForQualName, /* 38 */ TclGetObjInterpProc, /* 39 */ TclGetOpenMode, /* 40 */ TclGetOriginalCommand, /* 41 */ TclpGetUserHome, /* 42 */ TclGlobalInvoke, /* 43 */ TclGuessPackageName, /* 44 */ TclHideUnsafeCommands, /* 45 */ TclInExit, /* 46 */ NULL, /* 47 */ NULL, /* 48 */ TclIncrVar2, /* 49 */ TclInitCompiledLocals, /* 50 */ TclInterpInit, /* 51 */ TclInvoke, /* 52 */ TclInvokeObjectCommand, /* 53 */ TclInvokeStringCommand, /* 54 */ TclIsProc, /* 55 */ NULL, /* 56 */ NULL, /* 57 */ TclLookupVar, /* 58 */ NULL, /* 59 */ TclNeedSpace, /* 60 */ TclNewProcBodyObj, /* 61 */ TclObjCommandComplete, /* 62 */ TclObjInterpProc, /* 63 */ TclObjInvoke, /* 64 */ TclObjInvokeGlobal, /* 65 */ TclOpenFileChannelDeleteProc, /* 66 */ TclOpenFileChannelInsertProc, /* 67 */ NULL, /* 68 */ TclpAlloc, /* 69 */ NULL, /* 70 */ NULL, /* 71 */ NULL, /* 72 */ NULL, /* 73 */ TclpFree, /* 74 */ TclpGetClicks, /* 75 */ TclpGetSeconds, /* 76 */ TclpGetTime, /* 77 */ TclpGetTimeZone, /* 78 */ NULL, /* 79 */ NULL, /* 80 */ TclpRealloc, /* 81 */ NULL, /* 82 */ NULL, /* 83 */ NULL, /* 84 */ NULL, /* 85 */ NULL, /* 86 */ NULL, /* 87 */ TclPrecTraceProc, /* 88 */ TclPreventAliasLoop, /* 89 */ NULL, /* 90 */ TclProcCleanupProc, /* 91 */ TclProcCompileProc, /* 92 */ TclProcDeleteProc, /* 93 */ TclProcInterpProc, /* 94 */ NULL, /* 95 */ TclRenameCommand, /* 96 */ TclResetShadowedCmdRefs, /* 97 */ TclServiceIdle, /* 98 */ NULL, /* 99 */ NULL, /* 100 */ TclSetPreInitScript, /* 101 */ TclSetupEnv, /* 102 */ TclSockGetPort, /* 103 */ TclSockMinimumBuffersOld, /* 104 */ NULL, /* 105 */ TclStatDeleteProc, /* 106 */ TclStatInsertProc, /* 107 */ TclTeardownNamespace, /* 108 */ TclUpdateReturnInfo, /* 109 */ TclSockMinimumBuffers, /* 110 */ Tcl_AddInterpResolvers, /* 111 */ Tcl_AppendExportList, /* 112 */ Tcl_CreateNamespace, /* 113 */ Tcl_DeleteNamespace, /* 114 */ Tcl_Export, /* 115 */ Tcl_FindCommand, /* 116 */ Tcl_FindNamespace, /* 117 */ Tcl_GetInterpResolvers, /* 118 */ Tcl_GetNamespaceResolvers, /* 119 */ Tcl_FindNamespaceVar, /* 120 */ Tcl_ForgetImport, /* 121 */ Tcl_GetCommandFromObj, /* 122 */ Tcl_GetCommandFullName, /* 123 */ Tcl_GetCurrentNamespace, /* 124 */ Tcl_GetGlobalNamespace, /* 125 */ Tcl_GetVariableFullName, /* 126 */ Tcl_Import, /* 127 */ Tcl_PopCallFrame, /* 128 */ Tcl_PushCallFrame, /* 129 */ Tcl_RemoveInterpResolvers, /* 130 */ Tcl_SetNamespaceResolvers, /* 131 */ TclpHasSockets, /* 132 */ TclpGetDate, /* 133 */ TclpStrftime, /* 134 */ TclpCheckStackSpace, /* 135 */ NULL, /* 136 */ NULL, /* 137 */ TclGetEnv, /* 138 */ NULL, /* 139 */ TclLooksLikeInt, /* 140 */ TclpGetCwd, /* 141 */ TclSetByteCodeFromAny, /* 142 */ TclAddLiteralObj, /* 143 */ TclHideLiteral, /* 144 */ TclGetAuxDataType, /* 145 */ TclHandleCreate, /* 146 */ TclHandleFree, /* 147 */ TclHandlePreserve, /* 148 */ TclHandleRelease, /* 149 */ TclRegAbout, /* 150 */ TclRegExpRangeUniChar, /* 151 */ TclSetLibraryPath, /* 152 */ TclGetLibraryPath, /* 153 */ NULL, /* 154 */ NULL, /* 155 */ TclRegError, /* 156 */ TclVarTraceExists, /* 157 */ TclSetStartupScriptFileName, /* 158 */ TclGetStartupScriptFileName, /* 159 */ NULL, /* 160 */ TclChannelTransform, /* 161 */ TclChannelEventScriptInvoker, /* 162 */ TclGetInstructionTable, /* 163 */ TclExpandCodeArray, /* 164 */ TclpSetInitialEncodings, /* 165 */ TclListObjSetElement, /* 166 */ TclSetStartupScriptPath, /* 167 */ TclGetStartupScriptPath, /* 168 */ TclpUtfNcmp2, /* 169 */ TclCheckInterpTraces, /* 170 */ TclCheckExecutionTraces, /* 171 */ TclInThreadExit, /* 172 */ TclUniCharMatch, /* 173 */ NULL, /* 174 */ NULL, /* 175 */ NULL, /* 176 */ NULL, /* 177 */ NULL, /* 178 */ NULL, /* 179 */ NULL, /* 180 */ NULL, /* 181 */ TclpLocaltime, /* 182 */ TclpGmtime, /* 183 */ NULL, /* 184 */ NULL, /* 185 */ NULL, /* 186 */ NULL, /* 187 */ NULL, /* 188 */ NULL, /* 189 */ NULL, /* 190 */ NULL, /* 191 */ NULL, /* 192 */ NULL, /* 193 */ NULL, /* 194 */ NULL, /* 195 */ NULL, /* 196 */ NULL, /* 197 */ NULL, /* 198 */ TclMatchIsTrivial, /* 199 */ NULL, /* 200 */ NULL, /* 201 */ NULL, /* 202 */ NULL, /* 203 */ NULL, /* 204 */ NULL, /* 205 */ NULL, /* 206 */ NULL, /* 207 */ NULL, /* 208 */ NULL, /* 209 */ NULL, /* 210 */ NULL, /* 211 */ NULL, /* 212 */ NULL, /* 213 */ NULL, /* 214 */ NULL, /* 215 */ NULL, /* 216 */ NULL, /* 217 */ NULL, /* 218 */ NULL, /* 219 */ NULL, /* 220 */ NULL, /* 221 */ NULL, /* 222 */ NULL, /* 223 */ NULL, /* 224 */ NULL, /* 225 */ NULL, /* 226 */ NULL, /* 227 */ NULL, /* 228 */ NULL, /* 229 */ NULL, /* 230 */ NULL, /* 231 */ NULL, /* 232 */ NULL, /* 233 */ NULL, /* 234 */ NULL, /* 235 */ NULL, /* 236 */ NULL, /* 237 */ NULL, /* 238 */ NULL, /* 239 */ NULL, /* 240 */ NULL, /* 241 */ NULL, /* 242 */ NULL, /* 243 */ NULL, /* 244 */ NULL, /* 245 */ NULL, /* 246 */ NULL, /* 247 */ NULL, /* 248 */ TclUnusedStubEntry, /* 249 */ }; TclIntPlatStubs tclIntPlatStubs = { TCL_STUB_MAGIC, NULL, #if !defined(__WIN32__) && !defined(__CYGWIN__) && !defined(MAC_OSX_TCL) /* UNIX */ TclGetAndDetachPids, /* 0 */ TclpCloseFile, /* 1 */ TclpCreateCommandChannel, /* 2 */ TclpCreatePipe, /* 3 */ TclpCreateProcess, /* 4 */ NULL, /* 5 */ TclpMakeFile, /* 6 */ TclpOpenFile, /* 7 */ TclUnixWaitForFile, /* 8 */ TclpCreateTempFile, /* 9 */ TclpReaddir, /* 10 */ TclpLocaltime_unix, /* 11 */ TclpGmtime_unix, /* 12 */ TclpInetNtoa, /* 13 */ NULL, /* 14 */ NULL, /* 15 */ NULL, /* 16 */ NULL, /* 17 */ NULL, /* 18 */ NULL, /* 19 */ NULL, /* 20 */ NULL, /* 21 */ NULL, /* 22 */ NULL, /* 23 */ NULL, /* 24 */ NULL, /* 25 */ NULL, /* 26 */ NULL, /* 27 */ NULL, /* 28 */ TclWinCPUID, /* 29 */ #endif /* UNIX */ #if defined(__WIN32__) || defined(__CYGWIN__) /* WIN */ TclWinConvertError, /* 0 */ TclWinConvertWSAError, /* 1 */ TclWinGetServByName, /* 2 */ TclWinGetSockOpt, /* 3 */ TclWinGetTclInstance, /* 4 */ TclUnixWaitForFile, /* 5 */ TclWinNToHS, /* 6 */ TclWinSetSockOpt, /* 7 */ TclpGetPid, /* 8 */ TclWinGetPlatformId, /* 9 */ TclpReaddir, /* 10 */ TclGetAndDetachPids, /* 11 */ TclpCloseFile, /* 12 */ TclpCreateCommandChannel, /* 13 */ TclpCreatePipe, /* 14 */ TclpCreateProcess, /* 15 */ TclpIsAtty, /* 16 */ NULL, /* 17 */ TclpMakeFile, /* 18 */ TclpOpenFile, /* 19 */ TclWinAddProcess, /* 20 */ TclpInetNtoa, /* 21 */ TclpCreateTempFile, /* 22 */ TclpGetTZName, /* 23 */ TclWinNoBackslash, /* 24 */ TclWinGetPlatform, /* 25 */ TclWinSetInterfaces, /* 26 */ TclWinFlushDirtyChannels, /* 27 */ TclWinResetInterfaces, /* 28 */ TclWinCPUID, /* 29 */ #endif /* WIN */ #ifdef MAC_OSX_TCL /* MACOSX */ TclGetAndDetachPids, /* 0 */ TclpCloseFile, /* 1 */ TclpCreateCommandChannel, /* 2 */ TclpCreatePipe, /* 3 */ TclpCreateProcess, /* 4 */ NULL, /* 5 */ TclpMakeFile, /* 6 */ TclpOpenFile, /* 7 */ TclUnixWaitForFile, /* 8 */ TclpCreateTempFile, /* 9 */ TclpReaddir, /* 10 */ TclpLocaltime_unix, /* 11 */ TclpGmtime_unix, /* 12 */ TclpInetNtoa, /* 13 */ NULL, /* 14 */ NULL, /* 15 */ NULL, /* 16 */ NULL, /* 17 */ NULL, /* 18 */ NULL, /* 19 */ NULL, /* 20 */ NULL, /* 21 */ NULL, /* 22 */ NULL, /* 23 */ NULL, /* 24 */ NULL, /* 25 */ NULL, /* 26 */ NULL, /* 27 */ NULL, /* 28 */ TclWinCPUID, /* 29 */ #endif /* MACOSX */ }; TclPlatStubs tclPlatStubs = { TCL_STUB_MAGIC, NULL, #if defined(__WIN32__) || defined(__CYGWIN__) /* WIN */ Tcl_WinUtfToTChar, /* 0 */ Tcl_WinTCharToUtf, /* 1 */ #endif /* WIN */ #ifdef MAC_OSX_TCL /* MACOSX */ Tcl_MacOSXOpenBundleResources, /* 0 */ Tcl_MacOSXOpenVersionedBundleResources, /* 1 */ #endif /* MACOSX */ }; static TclStubHooks tclStubHooks = { &tclPlatStubs, &tclIntStubs, &tclIntPlatStubs }; TclStubs tclStubs = { TCL_STUB_MAGIC, &tclStubHooks, Tcl_PkgProvideEx, /* 0 */ Tcl_PkgRequireEx, /* 1 */ Tcl_Panic, /* 2 */ Tcl_Alloc, /* 3 */ Tcl_Free, /* 4 */ Tcl_Realloc, /* 5 */ Tcl_DbCkalloc, /* 6 */ Tcl_DbCkfree, /* 7 */ Tcl_DbCkrealloc, /* 8 */ #if !defined(__WIN32__) && !defined(MAC_OSX_TCL) /* UNIX */ Tcl_CreateFileHandler, /* 9 */ #endif /* UNIX */ #if defined(__WIN32__) /* WIN */ NULL, /* 9 */ #endif /* WIN */ #ifdef MAC_OSX_TCL /* MACOSX */ Tcl_CreateFileHandler, /* 9 */ #endif /* MACOSX */ #if !defined(__WIN32__) && !defined(MAC_OSX_TCL) /* UNIX */ Tcl_DeleteFileHandler, /* 10 */ #endif /* UNIX */ #if defined(__WIN32__) /* WIN */ NULL, /* 10 */ #endif /* WIN */ #ifdef MAC_OSX_TCL /* MACOSX */ Tcl_DeleteFileHandler, /* 10 */ #endif /* MACOSX */ Tcl_SetTimer, /* 11 */ Tcl_Sleep, /* 12 */ Tcl_WaitForEvent, /* 13 */ Tcl_AppendAllObjTypes, /* 14 */ Tcl_AppendStringsToObj, /* 15 */ Tcl_AppendToObj, /* 16 */ Tcl_ConcatObj, /* 17 */ Tcl_ConvertToType, /* 18 */ Tcl_DbDecrRefCount, /* 19 */ Tcl_DbIncrRefCount, /* 20 */ Tcl_DbIsShared, /* 21 */ Tcl_DbNewBooleanObj, /* 22 */ Tcl_DbNewByteArrayObj, /* 23 */ Tcl_DbNewDoubleObj, /* 24 */ Tcl_DbNewListObj, /* 25 */ Tcl_DbNewLongObj, /* 26 */ Tcl_DbNewObj, /* 27 */ Tcl_DbNewStringObj, /* 28 */ Tcl_DuplicateObj, /* 29 */ TclFreeObj, /* 30 */ Tcl_GetBoolean, /* 31 */ Tcl_GetBooleanFromObj, /* 32 */ Tcl_GetByteArrayFromObj, /* 33 */ Tcl_GetDouble, /* 34 */ Tcl_GetDoubleFromObj, /* 35 */ Tcl_GetIndexFromObj, /* 36 */ Tcl_GetInt, /* 37 */ Tcl_GetIntFromObj, /* 38 */ Tcl_GetLongFromObj, /* 39 */ Tcl_GetObjType, /* 40 */ Tcl_GetStringFromObj, /* 41 */ Tcl_InvalidateStringRep, /* 42 */ Tcl_ListObjAppendList, /* 43 */ Tcl_ListObjAppendElement, /* 44 */ Tcl_ListObjGetElements, /* 45 */ Tcl_ListObjIndex, /* 46 */ Tcl_ListObjLength, /* 47 */ Tcl_ListObjReplace, /* 48 */ Tcl_NewBooleanObj, /* 49 */ Tcl_NewByteArrayObj, /* 50 */ Tcl_NewDoubleObj, /* 51 */ Tcl_NewIntObj, /* 52 */ Tcl_NewListObj, /* 53 */ Tcl_NewLongObj, /* 54 */ Tcl_NewObj, /* 55 */ Tcl_NewStringObj, /* 56 */ Tcl_SetBooleanObj, /* 57 */ Tcl_SetByteArrayLength, /* 58 */ Tcl_SetByteArrayObj, /* 59 */ Tcl_SetDoubleObj, /* 60 */ Tcl_SetIntObj, /* 61 */ Tcl_SetListObj, /* 62 */ Tcl_SetLongObj, /* 63 */ Tcl_SetObjLength, /* 64 */ Tcl_SetStringObj, /* 65 */ Tcl_AddErrorInfo, /* 66 */ Tcl_AddObjErrorInfo, /* 67 */ Tcl_AllowExceptions, /* 68 */ Tcl_AppendElement, /* 69 */ Tcl_AppendResult, /* 70 */ Tcl_AsyncCreate, /* 71 */ Tcl_AsyncDelete, /* 72 */ Tcl_AsyncInvoke, /* 73 */ Tcl_AsyncMark, /* 74 */ Tcl_AsyncReady, /* 75 */ Tcl_BackgroundError, /* 76 */ Tcl_Backslash, /* 77 */ Tcl_BadChannelOption, /* 78 */ Tcl_CallWhenDeleted, /* 79 */ Tcl_CancelIdleCall, /* 80 */ Tcl_Close, /* 81 */ Tcl_CommandComplete, /* 82 */ Tcl_Concat, /* 83 */ Tcl_ConvertElement, /* 84 */ Tcl_ConvertCountedElement, /* 85 */ Tcl_CreateAlias, /* 86 */ Tcl_CreateAliasObj, /* 87 */ Tcl_CreateChannel, /* 88 */ Tcl_CreateChannelHandler, /* 89 */ Tcl_CreateCloseHandler, /* 90 */ Tcl_CreateCommand, /* 91 */ Tcl_CreateEventSource, /* 92 */ Tcl_CreateExitHandler, /* 93 */ Tcl_CreateInterp, /* 94 */ Tcl_CreateMathFunc, /* 95 */ Tcl_CreateObjCommand, /* 96 */ Tcl_CreateSlave, /* 97 */ Tcl_CreateTimerHandler, /* 98 */ Tcl_CreateTrace, /* 99 */ Tcl_DeleteAssocData, /* 100 */ Tcl_DeleteChannelHandler, /* 101 */ Tcl_DeleteCloseHandler, /* 102 */ Tcl_DeleteCommand, /* 103 */ Tcl_DeleteCommandFromToken, /* 104 */ Tcl_DeleteEvents, /* 105 */ Tcl_DeleteEventSource, /* 106 */ Tcl_DeleteExitHandler, /* 107 */ Tcl_DeleteHashEntry, /* 108 */ Tcl_DeleteHashTable, /* 109 */ Tcl_DeleteInterp, /* 110 */ Tcl_DetachPids, /* 111 */ Tcl_DeleteTimerHandler, /* 112 */ Tcl_DeleteTrace, /* 113 */ Tcl_DontCallWhenDeleted, /* 114 */ Tcl_DoOneEvent, /* 115 */ Tcl_DoWhenIdle, /* 116 */ Tcl_DStringAppend, /* 117 */ Tcl_DStringAppendElement, /* 118 */ Tcl_DStringEndSublist, /* 119 */ Tcl_DStringFree, /* 120 */ Tcl_DStringGetResult, /* 121 */ Tcl_DStringInit, /* 122 */ Tcl_DStringResult, /* 123 */ Tcl_DStringSetLength, /* 124 */ Tcl_DStringStartSublist, /* 125 */ Tcl_Eof, /* 126 */ Tcl_ErrnoId, /* 127 */ Tcl_ErrnoMsg, /* 128 */ Tcl_Eval, /* 129 */ Tcl_EvalFile, /* 130 */ Tcl_EvalObj, /* 131 */ Tcl_EventuallyFree, /* 132 */ Tcl_Exit, /* 133 */ Tcl_ExposeCommand, /* 134 */ Tcl_ExprBoolean, /* 135 */ Tcl_ExprBooleanObj, /* 136 */ Tcl_ExprDouble, /* 137 */ Tcl_ExprDoubleObj, /* 138 */ Tcl_ExprLong, /* 139 */ Tcl_ExprLongObj, /* 140 */ Tcl_ExprObj, /* 141 */ Tcl_ExprString, /* 142 */ Tcl_Finalize, /* 143 */ Tcl_FindExecutable, /* 144 */ Tcl_FirstHashEntry, /* 145 */ Tcl_Flush, /* 146 */ Tcl_FreeResult, /* 147 */ Tcl_GetAlias, /* 148 */ Tcl_GetAliasObj, /* 149 */ Tcl_GetAssocData, /* 150 */ Tcl_GetChannel, /* 151 */ Tcl_GetChannelBufferSize, /* 152 */ Tcl_GetChannelHandle, /* 153 */ Tcl_GetChannelInstanceData, /* 154 */ Tcl_GetChannelMode, /* 155 */ Tcl_GetChannelName, /* 156 */ Tcl_GetChannelOption, /* 157 */ Tcl_GetChannelType, /* 158 */ Tcl_GetCommandInfo, /* 159 */ Tcl_GetCommandName, /* 160 */ Tcl_GetErrno, /* 161 */ Tcl_GetHostName, /* 162 */ Tcl_GetInterpPath, /* 163 */ Tcl_GetMaster, /* 164 */ Tcl_GetNameOfExecutable, /* 165 */ Tcl_GetObjResult, /* 166 */ #if !defined(__WIN32__) && !defined(MAC_OSX_TCL) /* UNIX */ Tcl_GetOpenFile, /* 167 */ #endif /* UNIX */ #if defined(__WIN32__) /* WIN */ NULL, /* 167 */ #endif /* WIN */ #ifdef MAC_OSX_TCL /* MACOSX */ Tcl_GetOpenFile, /* 167 */ #endif /* MACOSX */ Tcl_GetPathType, /* 168 */ Tcl_Gets, /* 169 */ Tcl_GetsObj, /* 170 */ Tcl_GetServiceMode, /* 171 */ Tcl_GetSlave, /* 172 */ Tcl_GetStdChannel, /* 173 */ Tcl_GetStringResult, /* 174 */ Tcl_GetVar, /* 175 */ Tcl_GetVar2, /* 176 */ Tcl_GlobalEval, /* 177 */ Tcl_GlobalEvalObj, /* 178 */ Tcl_HideCommand, /* 179 */ Tcl_Init, /* 180 */ Tcl_InitHashTable, /* 181 */ Tcl_InputBlocked, /* 182 */ Tcl_InputBuffered, /* 183 */ Tcl_InterpDeleted, /* 184 */ Tcl_IsSafe, /* 185 */ Tcl_JoinPath, /* 186 */ Tcl_LinkVar, /* 187 */ NULL, /* 188 */ Tcl_MakeFileChannel, /* 189 */ Tcl_MakeSafe, /* 190 */ Tcl_MakeTcpClientChannel, /* 191 */ Tcl_Merge, /* 192 */ Tcl_NextHashEntry, /* 193 */ Tcl_NotifyChannel, /* 194 */ Tcl_ObjGetVar2, /* 195 */ Tcl_ObjSetVar2, /* 196 */ Tcl_OpenCommandChannel, /* 197 */ Tcl_OpenFileChannel, /* 198 */ Tcl_OpenTcpClient, /* 199 */ Tcl_OpenTcpServer, /* 200 */ Tcl_Preserve, /* 201 */ Tcl_PrintDouble, /* 202 */ Tcl_PutEnv, /* 203 */ Tcl_PosixError, /* 204 */ Tcl_QueueEvent, /* 205 */ Tcl_Read, /* 206 */ Tcl_ReapDetachedProcs, /* 207 */ Tcl_RecordAndEval, /* 208 */ Tcl_RecordAndEvalObj, /* 209 */ Tcl_RegisterChannel, /* 210 */ Tcl_RegisterObjType, /* 211 */ Tcl_RegExpCompile, /* 212 */ Tcl_RegExpExec, /* 213 */ Tcl_RegExpMatch, /* 214 */ Tcl_RegExpRange, /* 215 */ Tcl_Release, /* 216 */ Tcl_ResetResult, /* 217 */ Tcl_ScanElement, /* 218 */ Tcl_ScanCountedElement, /* 219 */ Tcl_SeekOld, /* 220 */ Tcl_ServiceAll, /* 221 */ Tcl_ServiceEvent, /* 222 */ Tcl_SetAssocData, /* 223 */ Tcl_SetChannelBufferSize, /* 224 */ Tcl_SetChannelOption, /* 225 */ Tcl_SetCommandInfo, /* 226 */ Tcl_SetErrno, /* 227 */ Tcl_SetErrorCode, /* 228 */ Tcl_SetMaxBlockTime, /* 229 */ Tcl_SetPanicProc, /* 230 */ Tcl_SetRecursionLimit, /* 231 */ Tcl_SetResult, /* 232 */ Tcl_SetServiceMode, /* 233 */ Tcl_SetObjErrorCode, /* 234 */ Tcl_SetObjResult, /* 235 */ Tcl_SetStdChannel, /* 236 */ Tcl_SetVar, /* 237 */ Tcl_SetVar2, /* 238 */ Tcl_SignalId, /* 239 */ Tcl_SignalMsg, /* 240 */ Tcl_SourceRCFile, /* 241 */ Tcl_SplitList, /* 242 */ Tcl_SplitPath, /* 243 */ Tcl_StaticPackage, /* 244 */ Tcl_StringMatch, /* 245 */ Tcl_TellOld, /* 246 */ Tcl_TraceVar, /* 247 */ Tcl_TraceVar2, /* 248 */ Tcl_TranslateFileName, /* 249 */ Tcl_Ungets, /* 250 */ Tcl_UnlinkVar, /* 251 */ Tcl_UnregisterChannel, /* 252 */ Tcl_UnsetVar, /* 253 */ Tcl_UnsetVar2, /* 254 */ Tcl_UntraceVar, /* 255 */ Tcl_UntraceVar2, /* 256 */ Tcl_UpdateLinkedVar, /* 257 */ Tcl_UpVar, /* 258 */ Tcl_UpVar2, /* 259 */ Tcl_VarEval, /* 260 */ Tcl_VarTraceInfo, /* 261 */ Tcl_VarTraceInfo2, /* 262 */ Tcl_Write, /* 263 */ Tcl_WrongNumArgs, /* 264 */ Tcl_DumpActiveMemory, /* 265 */ Tcl_ValidateAllMemory, /* 266 */ Tcl_AppendResultVA, /* 267 */ Tcl_AppendStringsToObjVA, /* 268 */ Tcl_HashStats, /* 269 */ Tcl_ParseVar, /* 270 */ Tcl_PkgPresent, /* 271 */ Tcl_PkgPresentEx, /* 272 */ Tcl_PkgProvide, /* 273 */ Tcl_PkgRequire, /* 274 */ Tcl_SetErrorCodeVA, /* 275 */ Tcl_VarEvalVA, /* 276 */ Tcl_WaitPid, /* 277 */ Tcl_PanicVA, /* 278 */ Tcl_GetVersion, /* 279 */ Tcl_InitMemory, /* 280 */ Tcl_StackChannel, /* 281 */ Tcl_UnstackChannel, /* 282 */ Tcl_GetStackedChannel, /* 283 */ Tcl_SetMainLoop, /* 284 */ NULL, /* 285 */ Tcl_AppendObjToObj, /* 286 */ Tcl_CreateEncoding, /* 287 */ Tcl_CreateThreadExitHandler, /* 288 */ Tcl_DeleteThreadExitHandler, /* 289 */ Tcl_DiscardResult, /* 290 */ Tcl_EvalEx, /* 291 */ Tcl_EvalObjv, /* 292 */ Tcl_EvalObjEx, /* 293 */ Tcl_ExitThread, /* 294 */ Tcl_ExternalToUtf, /* 295 */ Tcl_ExternalToUtfDString, /* 296 */ Tcl_FinalizeThread, /* 297 */ Tcl_FinalizeNotifier, /* 298 */ Tcl_FreeEncoding, /* 299 */ Tcl_GetCurrentThread, /* 300 */ Tcl_GetEncoding, /* 301 */ Tcl_GetEncodingName, /* 302 */ Tcl_GetEncodingNames, /* 303 */ Tcl_GetIndexFromObjStruct, /* 304 */ Tcl_GetThreadData, /* 305 */ Tcl_GetVar2Ex, /* 306 */ Tcl_InitNotifier, /* 307 */ Tcl_MutexLock, /* 308 */ Tcl_MutexUnlock, /* 309 */ Tcl_ConditionNotify, /* 310 */ Tcl_ConditionWait, /* 311 */ Tcl_NumUtfChars, /* 312 */ Tcl_ReadChars, /* 313 */ Tcl_RestoreResult, /* 314 */ Tcl_SaveResult, /* 315 */ Tcl_SetSystemEncoding, /* 316 */ Tcl_SetVar2Ex, /* 317 */ Tcl_ThreadAlert, /* 318 */ Tcl_ThreadQueueEvent, /* 319 */ Tcl_UniCharAtIndex, /* 320 */ Tcl_UniCharToLower, /* 321 */ Tcl_UniCharToTitle, /* 322 */ Tcl_UniCharToUpper, /* 323 */ Tcl_UniCharToUtf, /* 324 */ Tcl_UtfAtIndex, /* 325 */ Tcl_UtfCharComplete, /* 326 */ Tcl_UtfBackslash, /* 327 */ Tcl_UtfFindFirst, /* 328 */ Tcl_UtfFindLast, /* 329 */ Tcl_UtfNext, /* 330 */ Tcl_UtfPrev, /* 331 */ Tcl_UtfToExternal, /* 332 */ Tcl_UtfToExternalDString, /* 333 */ Tcl_UtfToLower, /* 334 */ Tcl_UtfToTitle, /* 335 */ Tcl_UtfToUniChar, /* 336 */ Tcl_UtfToUpper, /* 337 */ Tcl_WriteChars, /* 338 */ Tcl_WriteObj, /* 339 */ Tcl_GetString, /* 340 */ Tcl_GetDefaultEncodingDir, /* 341 */ Tcl_SetDefaultEncodingDir, /* 342 */ Tcl_AlertNotifier, /* 343 */ Tcl_ServiceModeHook, /* 344 */ Tcl_UniCharIsAlnum, /* 345 */ Tcl_UniCharIsAlpha, /* 346 */ Tcl_UniCharIsDigit, /* 347 */ Tcl_UniCharIsLower, /* 348 */ Tcl_UniCharIsSpace, /* 349 */ Tcl_UniCharIsUpper, /* 350 */ Tcl_UniCharIsWordChar, /* 351 */ Tcl_UniCharLen, /* 352 */ Tcl_UniCharNcmp, /* 353 */ Tcl_UniCharToUtfDString, /* 354 */ Tcl_UtfToUniCharDString, /* 355 */ Tcl_GetRegExpFromObj, /* 356 */ Tcl_EvalTokens, /* 357 */ Tcl_FreeParse, /* 358 */ Tcl_LogCommandInfo, /* 359 */ Tcl_ParseBraces, /* 360 */ Tcl_ParseCommand, /* 361 */ Tcl_ParseExpr, /* 362 */ Tcl_ParseQuotedString, /* 363 */ Tcl_ParseVarName, /* 364 */ Tcl_GetCwd, /* 365 */ Tcl_Chdir, /* 366 */ Tcl_Access, /* 367 */ Tcl_Stat, /* 368 */ Tcl_UtfNcmp, /* 369 */ Tcl_UtfNcasecmp, /* 370 */ Tcl_StringCaseMatch, /* 371 */ Tcl_UniCharIsControl, /* 372 */ Tcl_UniCharIsGraph, /* 373 */ Tcl_UniCharIsPrint, /* 374 */ Tcl_UniCharIsPunct, /* 375 */ Tcl_RegExpExecObj, /* 376 */ Tcl_RegExpGetInfo, /* 377 */ Tcl_NewUnicodeObj, /* 378 */ Tcl_SetUnicodeObj, /* 379 */ Tcl_GetCharLength, /* 380 */ Tcl_GetUniChar, /* 381 */ Tcl_GetUnicode, /* 382 */ Tcl_GetRange, /* 383 */ Tcl_AppendUnicodeToObj, /* 384 */ Tcl_RegExpMatchObj, /* 385 */ Tcl_SetNotifier, /* 386 */ Tcl_GetAllocMutex, /* 387 */ Tcl_GetChannelNames, /* 388 */ Tcl_GetChannelNamesEx, /* 389 */ Tcl_ProcObjCmd, /* 390 */ Tcl_ConditionFinalize, /* 391 */ Tcl_MutexFinalize, /* 392 */ Tcl_CreateThread, /* 393 */ Tcl_ReadRaw, /* 394 */ Tcl_WriteRaw, /* 395 */ Tcl_GetTopChannel, /* 396 */ Tcl_ChannelBuffered, /* 397 */ Tcl_ChannelName, /* 398 */ Tcl_ChannelVersion, /* 399 */ Tcl_ChannelBlockModeProc, /* 400 */ Tcl_ChannelCloseProc, /* 401 */ Tcl_ChannelClose2Proc, /* 402 */ Tcl_ChannelInputProc, /* 403 */ Tcl_ChannelOutputProc, /* 404 */ Tcl_ChannelSeekProc, /* 405 */ Tcl_ChannelSetOptionProc, /* 406 */ Tcl_ChannelGetOptionProc, /* 407 */ Tcl_ChannelWatchProc, /* 408 */ Tcl_ChannelGetHandleProc, /* 409 */ Tcl_ChannelFlushProc, /* 410 */ Tcl_ChannelHandlerProc, /* 411 */ Tcl_JoinThread, /* 412 */ Tcl_IsChannelShared, /* 413 */ Tcl_IsChannelRegistered, /* 414 */ Tcl_CutChannel, /* 415 */ Tcl_SpliceChannel, /* 416 */ Tcl_ClearChannelHandlers, /* 417 */ Tcl_IsChannelExisting, /* 418 */ Tcl_UniCharNcasecmp, /* 419 */ Tcl_UniCharCaseMatch, /* 420 */ Tcl_FindHashEntry, /* 421 */ Tcl_CreateHashEntry, /* 422 */ Tcl_InitCustomHashTable, /* 423 */ Tcl_InitObjHashTable, /* 424 */ Tcl_CommandTraceInfo, /* 425 */ Tcl_TraceCommand, /* 426 */ Tcl_UntraceCommand, /* 427 */ Tcl_AttemptAlloc, /* 428 */ Tcl_AttemptDbCkalloc, /* 429 */ Tcl_AttemptRealloc, /* 430 */ Tcl_AttemptDbCkrealloc, /* 431 */ Tcl_AttemptSetObjLength, /* 432 */ Tcl_GetChannelThread, /* 433 */ Tcl_GetUnicodeFromObj, /* 434 */ Tcl_GetMathFuncInfo, /* 435 */ Tcl_ListMathFuncs, /* 436 */ Tcl_SubstObj, /* 437 */ Tcl_DetachChannel, /* 438 */ Tcl_IsStandardChannel, /* 439 */ Tcl_FSCopyFile, /* 440 */ Tcl_FSCopyDirectory, /* 441 */ Tcl_FSCreateDirectory, /* 442 */ Tcl_FSDeleteFile, /* 443 */ Tcl_FSLoadFile, /* 444 */ Tcl_FSMatchInDirectory, /* 445 */ Tcl_FSLink, /* 446 */ Tcl_FSRemoveDirectory, /* 447 */ Tcl_FSRenameFile, /* 448 */ Tcl_FSLstat, /* 449 */ Tcl_FSUtime, /* 450 */ Tcl_FSFileAttrsGet, /* 451 */ Tcl_FSFileAttrsSet, /* 452 */ Tcl_FSFileAttrStrings, /* 453 */ Tcl_FSStat, /* 454 */ Tcl_FSAccess, /* 455 */ Tcl_FSOpenFileChannel, /* 456 */ Tcl_FSGetCwd, /* 457 */ Tcl_FSChdir, /* 458 */ Tcl_FSConvertToPathType, /* 459 */ Tcl_FSJoinPath, /* 460 */ Tcl_FSSplitPath, /* 461 */ Tcl_FSEqualPaths, /* 462 */ Tcl_FSGetNormalizedPath, /* 463 */ Tcl_FSJoinToPath, /* 464 */ Tcl_FSGetInternalRep, /* 465 */ Tcl_FSGetTranslatedPath, /* 466 */ Tcl_FSEvalFile, /* 467 */ Tcl_FSNewNativePath, /* 468 */ Tcl_FSGetNativePath, /* 469 */ Tcl_FSFileSystemInfo, /* 470 */ Tcl_FSPathSeparator, /* 471 */ Tcl_FSListVolumes, /* 472 */ Tcl_FSRegister, /* 473 */ Tcl_FSUnregister, /* 474 */ Tcl_FSData, /* 475 */ Tcl_FSGetTranslatedStringPath, /* 476 */ Tcl_FSGetFileSystemForPath, /* 477 */ Tcl_FSGetPathType, /* 478 */ Tcl_OutputBuffered, /* 479 */ Tcl_FSMountsChanged, /* 480 */ Tcl_EvalTokensStandard, /* 481 */ Tcl_GetTime, /* 482 */ Tcl_CreateObjTrace, /* 483 */ Tcl_GetCommandInfoFromToken, /* 484 */ Tcl_SetCommandInfoFromToken, /* 485 */ Tcl_DbNewWideIntObj, /* 486 */ Tcl_GetWideIntFromObj, /* 487 */ Tcl_NewWideIntObj, /* 488 */ Tcl_SetWideIntObj, /* 489 */ Tcl_AllocStatBuf, /* 490 */ Tcl_Seek, /* 491 */ Tcl_Tell, /* 492 */ Tcl_ChannelWideSeekProc, /* 493 */ NULL, /* 494 */ NULL, /* 495 */ NULL, /* 496 */ NULL, /* 497 */ NULL, /* 498 */ NULL, /* 499 */ NULL, /* 500 */ NULL, /* 501 */ NULL, /* 502 */ NULL, /* 503 */ NULL, /* 504 */ NULL, /* 505 */ NULL, /* 506 */ NULL, /* 507 */ NULL, /* 508 */ NULL, /* 509 */ NULL, /* 510 */ NULL, /* 511 */ NULL, /* 512 */ NULL, /* 513 */ NULL, /* 514 */ NULL, /* 515 */ NULL, /* 516 */ NULL, /* 517 */ NULL, /* 518 */ NULL, /* 519 */ NULL, /* 520 */ NULL, /* 521 */ NULL, /* 522 */ NULL, /* 523 */ NULL, /* 524 */ NULL, /* 525 */ NULL, /* 526 */ NULL, /* 527 */ NULL, /* 528 */ NULL, /* 529 */ NULL, /* 530 */ NULL, /* 531 */ NULL, /* 532 */ NULL, /* 533 */ NULL, /* 534 */ NULL, /* 535 */ NULL, /* 536 */ NULL, /* 537 */ NULL, /* 538 */ NULL, /* 539 */ NULL, /* 540 */ NULL, /* 541 */ NULL, /* 542 */ NULL, /* 543 */ NULL, /* 544 */ NULL, /* 545 */ NULL, /* 546 */ NULL, /* 547 */ NULL, /* 548 */ NULL, /* 549 */ NULL, /* 550 */ NULL, /* 551 */ NULL, /* 552 */ NULL, /* 553 */ Tcl_ChannelThreadActionProc, /* 554 */ NULL, /* 555 */ NULL, /* 556 */ NULL, /* 557 */ NULL, /* 558 */ NULL, /* 559 */ NULL, /* 560 */ NULL, /* 561 */ NULL, /* 562 */ NULL, /* 563 */ NULL, /* 564 */ NULL, /* 565 */ NULL, /* 566 */ NULL, /* 567 */ NULL, /* 568 */ NULL, /* 569 */ NULL, /* 570 */ NULL, /* 571 */ NULL, /* 572 */ Tcl_PkgRequireProc, /* 573 */ NULL, /* 574 */ NULL, /* 575 */ NULL, /* 576 */ NULL, /* 577 */ NULL, /* 578 */ NULL, /* 579 */ NULL, /* 580 */ NULL, /* 581 */ NULL, /* 582 */ NULL, /* 583 */ NULL, /* 584 */ NULL, /* 585 */ NULL, /* 586 */ NULL, /* 587 */ NULL, /* 588 */ NULL, /* 589 */ NULL, /* 590 */ NULL, /* 591 */ NULL, /* 592 */ NULL, /* 593 */ NULL, /* 594 */ NULL, /* 595 */ NULL, /* 596 */ NULL, /* 597 */ NULL, /* 598 */ NULL, /* 599 */ NULL, /* 600 */ NULL, /* 601 */ NULL, /* 602 */ NULL, /* 603 */ NULL, /* 604 */ NULL, /* 605 */ NULL, /* 606 */ NULL, /* 607 */ NULL, /* 608 */ NULL, /* 609 */ NULL, /* 610 */ NULL, /* 611 */ NULL, /* 612 */ NULL, /* 613 */ NULL, /* 614 */ NULL, /* 615 */ NULL, /* 616 */ NULL, /* 617 */ NULL, /* 618 */ NULL, /* 619 */ NULL, /* 620 */ NULL, /* 621 */ NULL, /* 622 */ NULL, /* 623 */ NULL, /* 624 */ NULL, /* 625 */ NULL, /* 626 */ NULL, /* 627 */ NULL, /* 628 */ NULL, /* 629 */ TclUnusedStubEntry, /* 630 */ }; /* !END!: Do not edit above this line. */ tcl8.4.20/generic/tclPosixStr.c0000644003604700454610000006761411737050674015013 0ustar dgp771div/* * tclPosixStr.c -- * * This file contains procedures that generate strings * corresponding to various POSIX-related codes, such * as errno and signals. * * Copyright (c) 1991-1994 The Regents of the University of California. * Copyright (c) 1994-1996 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" /* *---------------------------------------------------------------------- * * Tcl_ErrnoId -- * * Return a textual identifier for the current errno value. * * Results: * This procedure returns a machine-readable textual identifier * that corresponds to the current errno value (e.g. "EPERM"). * The identifier is the same as the #define name in errno.h. * * Side effects: * None. * *---------------------------------------------------------------------- */ CONST char * Tcl_ErrnoId() { switch (errno) { #if defined(E2BIG) && (!defined(EOVERFLOW) || (E2BIG != EOVERFLOW)) case E2BIG: return "E2BIG"; #endif #ifdef EACCES case EACCES: return "EACCES"; #endif #ifdef EADDRINUSE case EADDRINUSE: return "EADDRINUSE"; #endif #ifdef EADDRNOTAVAIL case EADDRNOTAVAIL: return "EADDRNOTAVAIL"; #endif #ifdef EADV case EADV: return "EADV"; #endif #ifdef EAFNOSUPPORT case EAFNOSUPPORT: return "EAFNOSUPPORT"; #endif #ifdef EAGAIN case EAGAIN: return "EAGAIN"; #endif #ifdef EALIGN case EALIGN: return "EALIGN"; #endif #if defined(EALREADY) && (!defined(EBUSY) || (EALREADY != EBUSY)) case EALREADY: return "EALREADY"; #endif #ifdef EBADE case EBADE: return "EBADE"; #endif #ifdef EBADF case EBADF: return "EBADF"; #endif #ifdef EBADFD case EBADFD: return "EBADFD"; #endif #ifdef EBADMSG case EBADMSG: return "EBADMSG"; #endif #ifdef EBADR case EBADR: return "EBADR"; #endif #ifdef EBADRPC case EBADRPC: return "EBADRPC"; #endif #ifdef EBADRQC case EBADRQC: return "EBADRQC"; #endif #ifdef EBADSLT case EBADSLT: return "EBADSLT"; #endif #ifdef EBFONT case EBFONT: return "EBFONT"; #endif #ifdef EBUSY case EBUSY: return "EBUSY"; #endif #ifdef ECHILD case ECHILD: return "ECHILD"; #endif #ifdef ECHRNG case ECHRNG: return "ECHRNG"; #endif #ifdef ECOMM case ECOMM: return "ECOMM"; #endif #ifdef ECONNABORTED case ECONNABORTED: return "ECONNABORTED"; #endif #ifdef ECONNREFUSED case ECONNREFUSED: return "ECONNREFUSED"; #endif #ifdef ECONNRESET case ECONNRESET: return "ECONNRESET"; #endif #if defined(EDEADLK) && (!defined(EWOULDBLOCK) || (EDEADLK != EWOULDBLOCK)) case EDEADLK: return "EDEADLK"; #endif #if defined(EDEADLOCK) && (!defined(EDEADLK) || (EDEADLOCK != EDEADLK)) case EDEADLOCK: return "EDEADLOCK"; #endif #ifdef EDESTADDRREQ case EDESTADDRREQ: return "EDESTADDRREQ"; #endif #ifdef EDIRTY case EDIRTY: return "EDIRTY"; #endif #ifdef EDOM case EDOM: return "EDOM"; #endif #ifdef EDOTDOT case EDOTDOT: return "EDOTDOT"; #endif #ifdef EDQUOT case EDQUOT: return "EDQUOT"; #endif #ifdef EDUPPKG case EDUPPKG: return "EDUPPKG"; #endif #ifdef EEXIST case EEXIST: return "EEXIST"; #endif #ifdef EFAULT case EFAULT: return "EFAULT"; #endif #ifdef EFBIG case EFBIG: return "EFBIG"; #endif #ifdef EHOSTDOWN case EHOSTDOWN: return "EHOSTDOWN"; #endif #ifdef EHOSTUNREACH case EHOSTUNREACH: return "EHOSTUNREACH"; #endif #if defined(EIDRM) && (!defined(EINPROGRESS) || (EIDRM != EINPROGRESS)) case EIDRM: return "EIDRM"; #endif #ifdef EINIT case EINIT: return "EINIT"; #endif #ifdef EINPROGRESS case EINPROGRESS: return "EINPROGRESS"; #endif #ifdef EINTR case EINTR: return "EINTR"; #endif #ifdef EINVAL case EINVAL: return "EINVAL"; #endif #ifdef EIO case EIO: return "EIO"; #endif #ifdef EISCONN case EISCONN: return "EISCONN"; #endif #ifdef EISDIR case EISDIR: return "EISDIR"; #endif #ifdef EISNAME case EISNAM: return "EISNAM"; #endif #ifdef ELBIN case ELBIN: return "ELBIN"; #endif #ifdef EL2HLT case EL2HLT: return "EL2HLT"; #endif #ifdef EL2NSYNC case EL2NSYNC: return "EL2NSYNC"; #endif #ifdef EL3HLT case EL3HLT: return "EL3HLT"; #endif #ifdef EL3RST case EL3RST: return "EL3RST"; #endif #ifdef ELIBACC case ELIBACC: return "ELIBACC"; #endif #ifdef ELIBBAD case ELIBBAD: return "ELIBBAD"; #endif #ifdef ELIBEXEC case ELIBEXEC: return "ELIBEXEC"; #endif #ifdef ELIBMAX case ELIBMAX: return "ELIBMAX"; #endif #ifdef ELIBSCN case ELIBSCN: return "ELIBSCN"; #endif #ifdef ELNRNG case ELNRNG: return "ELNRNG"; #endif #if defined(ELOOP) && (!defined(ENOENT) || (ELOOP != ENOENT)) case ELOOP: return "ELOOP"; #endif #ifdef EMFILE case EMFILE: return "EMFILE"; #endif #ifdef EMLINK case EMLINK: return "EMLINK"; #endif #ifdef EMSGSIZE case EMSGSIZE: return "EMSGSIZE"; #endif #ifdef EMULTIHOP case EMULTIHOP: return "EMULTIHOP"; #endif #ifdef ENAMETOOLONG case ENAMETOOLONG: return "ENAMETOOLONG"; #endif #ifdef ENAVAIL case ENAVAIL: return "ENAVAIL"; #endif #ifdef ENET case ENET: return "ENET"; #endif #ifdef ENETDOWN case ENETDOWN: return "ENETDOWN"; #endif #ifdef ENETRESET case ENETRESET: return "ENETRESET"; #endif #ifdef ENETUNREACH case ENETUNREACH: return "ENETUNREACH"; #endif #ifdef ENFILE case ENFILE: return "ENFILE"; #endif #ifdef ENOANO case ENOANO: return "ENOANO"; #endif #if defined(ENOBUFS) && (!defined(ENOSR) || (ENOBUFS != ENOSR)) case ENOBUFS: return "ENOBUFS"; #endif #ifdef ENOCSI case ENOCSI: return "ENOCSI"; #endif #if defined(ENODATA) && (!defined(ECONNREFUSED) || (ENODATA != ECONNREFUSED)) case ENODATA: return "ENODATA"; #endif #ifdef ENODEV case ENODEV: return "ENODEV"; #endif #ifdef ENOENT case ENOENT: return "ENOENT"; #endif #ifdef ENOEXEC case ENOEXEC: return "ENOEXEC"; #endif #ifdef ENOLCK case ENOLCK: return "ENOLCK"; #endif #if defined(ENOLINK) && (!defined(ESOCKTNOSUPPORT) || (ESOCKTNOSUPPORT != ENOLINK)) case ENOLINK: return "ENOLINK"; #endif #ifdef ENOMEM case ENOMEM: return "ENOMEM"; #endif #ifdef ENOMSG case ENOMSG: return "ENOMSG"; #endif #ifdef ENONET case ENONET: return "ENONET"; #endif #ifdef ENOPKG case ENOPKG: return "ENOPKG"; #endif #if defined(ENOPROTOOPT) && (!defined(EPFNOSUPPORT) || (EPFNOSUPPORT != ENOPROTOOPT)) case ENOPROTOOPT: return "ENOPROTOOPT"; #endif #ifdef ENOSPC case ENOSPC: return "ENOSPC"; #endif #if defined(ENOSR) && (!defined(ENAMETOOLONG) || (ENAMETOOLONG != ENOSR)) case ENOSR: return "ENOSR"; #endif #if defined(ENOSTR) && (!defined(ENOTTY) || (ENOTTY != ENOSTR)) case ENOSTR: return "ENOSTR"; #endif #ifdef ENOSYM case ENOSYM: return "ENOSYM"; #endif #ifdef ENOSYS case ENOSYS: return "ENOSYS"; #endif #ifdef ENOTBLK case ENOTBLK: return "ENOTBLK"; #endif #ifdef ENOTCONN case ENOTCONN: return "ENOTCONN"; #endif #ifdef ENOTDIR case ENOTDIR: return "ENOTDIR"; #endif #if defined(ENOTEMPTY) && (!defined(EEXIST) || (ENOTEMPTY != EEXIST)) case ENOTEMPTY: return "ENOTEMPTY"; #endif #ifdef ENOTNAM case ENOTNAM: return "ENOTNAM"; #endif #ifdef ENOTSOCK case ENOTSOCK: return "ENOTSOCK"; #endif #ifdef ENOTSUP case ENOTSUP: return "ENOTSUP"; #endif #ifdef ENOTTY case ENOTTY: return "ENOTTY"; #endif #ifdef ENOTUNIQ case ENOTUNIQ: return "ENOTUNIQ"; #endif #ifdef ENXIO case ENXIO: return "ENXIO"; #endif #if defined(EOPNOTSUPP) && (!defined(ENOTSUP) || (ENOTSUP != EOPNOTSUPP)) case EOPNOTSUPP: return "EOPNOTSUPP"; #endif #if defined(EOVERFLOW) && (!defined(EFBIG) || (EOVERFLOW != EFBIG)) && (!defined(EINVAL) || (EOVERFLOW != EINVAL)) case EOVERFLOW: return "EOVERFLOW"; #endif #ifdef EPERM case EPERM: return "EPERM"; #endif #if defined(EPFNOSUPPORT) && (!defined(ENOLCK) || (ENOLCK != EPFNOSUPPORT)) case EPFNOSUPPORT: return "EPFNOSUPPORT"; #endif #ifdef EPIPE case EPIPE: return "EPIPE"; #endif #ifdef EPROCLIM case EPROCLIM: return "EPROCLIM"; #endif #ifdef EPROCUNAVAIL case EPROCUNAVAIL: return "EPROCUNAVAIL"; #endif #ifdef EPROGMISMATCH case EPROGMISMATCH: return "EPROGMISMATCH"; #endif #ifdef EPROGUNAVAIL case EPROGUNAVAIL: return "EPROGUNAVAIL"; #endif #ifdef EPROTO case EPROTO: return "EPROTO"; #endif #ifdef EPROTONOSUPPORT case EPROTONOSUPPORT: return "EPROTONOSUPPORT"; #endif #ifdef EPROTOTYPE case EPROTOTYPE: return "EPROTOTYPE"; #endif #ifdef ERANGE case ERANGE: return "ERANGE"; #endif #if defined(EREFUSED) && (!defined(ECONNREFUSED) || (EREFUSED != ECONNREFUSED)) case EREFUSED: return "EREFUSED"; #endif #ifdef EREMCHG case EREMCHG: return "EREMCHG"; #endif #ifdef EREMDEV case EREMDEV: return "EREMDEV"; #endif #ifdef EREMOTE case EREMOTE: return "EREMOTE"; #endif #ifdef EREMOTEIO case EREMOTEIO: return "EREMOTEIO"; #endif #ifdef EREMOTERELEASE case EREMOTERELEASE: return "EREMOTERELEASE"; #endif #ifdef EROFS case EROFS: return "EROFS"; #endif #ifdef ERPCMISMATCH case ERPCMISMATCH: return "ERPCMISMATCH"; #endif #ifdef ERREMOTE case ERREMOTE: return "ERREMOTE"; #endif #ifdef ESHUTDOWN case ESHUTDOWN: return "ESHUTDOWN"; #endif #ifdef ESOCKTNOSUPPORT case ESOCKTNOSUPPORT: return "ESOCKTNOSUPPORT"; #endif #ifdef ESPIPE case ESPIPE: return "ESPIPE"; #endif #ifdef ESRCH case ESRCH: return "ESRCH"; #endif #ifdef ESRMNT case ESRMNT: return "ESRMNT"; #endif #ifdef ESTALE case ESTALE: return "ESTALE"; #endif #ifdef ESUCCESS case ESUCCESS: return "ESUCCESS"; #endif #if defined(ETIME) && (!defined(ELOOP) || (ETIME != ELOOP)) case ETIME: return "ETIME"; #endif #if defined(ETIMEDOUT) && (!defined(ENOSTR) || (ETIMEDOUT != ENOSTR)) case ETIMEDOUT: return "ETIMEDOUT"; #endif #ifdef ETOOMANYREFS case ETOOMANYREFS: return "ETOOMANYREFS"; #endif #ifdef ETXTBSY case ETXTBSY: return "ETXTBSY"; #endif #ifdef EUCLEAN case EUCLEAN: return "EUCLEAN"; #endif #ifdef EUNATCH case EUNATCH: return "EUNATCH"; #endif #ifdef EUSERS case EUSERS: return "EUSERS"; #endif #ifdef EVERSION case EVERSION: return "EVERSION"; #endif #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) case EWOULDBLOCK: return "EWOULDBLOCK"; #endif #ifdef EXDEV case EXDEV: return "EXDEV"; #endif #ifdef EXFULL case EXFULL: return "EXFULL"; #endif } return "unknown error"; } /* *---------------------------------------------------------------------- * * Tcl_ErrnoMsg -- * * Return a human-readable message corresponding to a given * errno value. * * Results: * The return value is the standard POSIX error message for * errno. This procedure is used instead of strerror because * strerror returns slightly different values on different * machines (e.g. different capitalizations), which cause * problems for things such as regression tests. This procedure * provides messages for most standard errors, then it calls * strerror for things it doesn't understand. * * Side effects: * None. * *---------------------------------------------------------------------- */ CONST char * Tcl_ErrnoMsg(err) int err; /* Error number (such as in errno variable). */ { switch (err) { #if defined(E2BIG) && (!defined(EOVERFLOW) || (E2BIG != EOVERFLOW)) case E2BIG: return "argument list too long"; #endif #ifdef EACCES case EACCES: return "permission denied"; #endif #ifdef EADDRINUSE case EADDRINUSE: return "address already in use"; #endif #ifdef EADDRNOTAVAIL case EADDRNOTAVAIL: return "can't assign requested address"; #endif #ifdef EADV case EADV: return "advertise error"; #endif #ifdef EAFNOSUPPORT case EAFNOSUPPORT: return "address family not supported by protocol family"; #endif #ifdef EAGAIN case EAGAIN: return "resource temporarily unavailable"; #endif #ifdef EALIGN case EALIGN: return "EALIGN"; #endif #if defined(EALREADY) && (!defined(EBUSY) || (EALREADY != EBUSY)) case EALREADY: return "operation already in progress"; #endif #ifdef EBADE case EBADE: return "bad exchange descriptor"; #endif #ifdef EBADF case EBADF: return "bad file number"; #endif #ifdef EBADFD case EBADFD: return "file descriptor in bad state"; #endif #ifdef EBADMSG case EBADMSG: return "not a data message"; #endif #ifdef EBADR case EBADR: return "bad request descriptor"; #endif #ifdef EBADRPC case EBADRPC: return "RPC structure is bad"; #endif #ifdef EBADRQC case EBADRQC: return "bad request code"; #endif #ifdef EBADSLT case EBADSLT: return "invalid slot"; #endif #ifdef EBFONT case EBFONT: return "bad font file format"; #endif #ifdef EBUSY case EBUSY: return "file busy"; #endif #ifdef ECHILD case ECHILD: return "no children"; #endif #ifdef ECHRNG case ECHRNG: return "channel number out of range"; #endif #ifdef ECOMM case ECOMM: return "communication error on send"; #endif #ifdef ECONNABORTED case ECONNABORTED: return "software caused connection abort"; #endif #ifdef ECONNREFUSED case ECONNREFUSED: return "connection refused"; #endif #ifdef ECONNRESET case ECONNRESET: return "connection reset by peer"; #endif #if defined(EDEADLK) && (!defined(EWOULDBLOCK) || (EDEADLK != EWOULDBLOCK)) case EDEADLK: return "resource deadlock avoided"; #endif #if defined(EDEADLOCK) && (!defined(EDEADLK) || (EDEADLOCK != EDEADLK)) case EDEADLOCK: return "resource deadlock avoided"; #endif #ifdef EDESTADDRREQ case EDESTADDRREQ: return "destination address required"; #endif #ifdef EDIRTY case EDIRTY: return "mounting a dirty fs w/o force"; #endif #ifdef EDOM case EDOM: return "math argument out of range"; #endif #ifdef EDOTDOT case EDOTDOT: return "cross mount point"; #endif #ifdef EDQUOT case EDQUOT: return "disk quota exceeded"; #endif #ifdef EDUPPKG case EDUPPKG: return "duplicate package name"; #endif #ifdef EEXIST case EEXIST: return "file already exists"; #endif #ifdef EFAULT case EFAULT: return "bad address in system call argument"; #endif #ifdef EFBIG case EFBIG: return "file too large"; #endif #ifdef EHOSTDOWN case EHOSTDOWN: return "host is down"; #endif #ifdef EHOSTUNREACH case EHOSTUNREACH: return "host is unreachable"; #endif #if defined(EIDRM) && (!defined(EINPROGRESS) || (EIDRM != EINPROGRESS)) case EIDRM: return "identifier removed"; #endif #ifdef EINIT case EINIT: return "initialization error"; #endif #ifdef EINPROGRESS case EINPROGRESS: return "operation now in progress"; #endif #ifdef EINTR case EINTR: return "interrupted system call"; #endif #ifdef EINVAL case EINVAL: return "invalid argument"; #endif #ifdef EIO case EIO: return "I/O error"; #endif #ifdef EISCONN case EISCONN: return "socket is already connected"; #endif #ifdef EISDIR case EISDIR: return "illegal operation on a directory"; #endif #ifdef EISNAME case EISNAM: return "is a name file"; #endif #ifdef ELBIN case ELBIN: return "ELBIN"; #endif #ifdef EL2HLT case EL2HLT: return "level 2 halted"; #endif #ifdef EL2NSYNC case EL2NSYNC: return "level 2 not synchronized"; #endif #ifdef EL3HLT case EL3HLT: return "level 3 halted"; #endif #ifdef EL3RST case EL3RST: return "level 3 reset"; #endif #ifdef ELIBACC case ELIBACC: return "can not access a needed shared library"; #endif #ifdef ELIBBAD case ELIBBAD: return "accessing a corrupted shared library"; #endif #ifdef ELIBEXEC case ELIBEXEC: return "can not exec a shared library directly"; #endif #ifdef ELIBMAX case ELIBMAX: return "attempting to link in more shared libraries than system limit"; #endif #ifdef ELIBSCN case ELIBSCN: return ".lib section in a.out corrupted"; #endif #ifdef ELNRNG case ELNRNG: return "link number out of range"; #endif #if defined(ELOOP) && (!defined(ENOENT) || (ELOOP != ENOENT)) case ELOOP: return "too many levels of symbolic links"; #endif #ifdef EMFILE case EMFILE: return "too many open files"; #endif #ifdef EMLINK case EMLINK: return "too many links"; #endif #ifdef EMSGSIZE case EMSGSIZE: return "message too long"; #endif #ifdef EMULTIHOP case EMULTIHOP: return "multihop attempted"; #endif #ifdef ENAMETOOLONG case ENAMETOOLONG: return "file name too long"; #endif #ifdef ENAVAIL case ENAVAIL: return "not available"; #endif #ifdef ENET case ENET: return "ENET"; #endif #ifdef ENETDOWN case ENETDOWN: return "network is down"; #endif #ifdef ENETRESET case ENETRESET: return "network dropped connection on reset"; #endif #ifdef ENETUNREACH case ENETUNREACH: return "network is unreachable"; #endif #ifdef ENFILE case ENFILE: return "file table overflow"; #endif #ifdef ENOANO case ENOANO: return "anode table overflow"; #endif #if defined(ENOBUFS) && (!defined(ENOSR) || (ENOBUFS != ENOSR)) case ENOBUFS: return "no buffer space available"; #endif #ifdef ENOCSI case ENOCSI: return "no CSI structure available"; #endif #if defined(ENODATA) && (!defined(ECONNREFUSED) || (ENODATA != ECONNREFUSED)) case ENODATA: return "no data available"; #endif #ifdef ENODEV case ENODEV: return "no such device"; #endif #ifdef ENOENT case ENOENT: return "no such file or directory"; #endif #ifdef ENOEXEC case ENOEXEC: return "exec format error"; #endif #ifdef ENOLCK case ENOLCK: return "no locks available"; #endif #if defined(ENOLINK) && (!defined(ESOCKTNOSUPPORT) || (ESOCKTNOSUPPORT != ENOLINK)) case ENOLINK: return "link has been severed"; #endif #ifdef ENOMEM case ENOMEM: return "not enough memory"; #endif #ifdef ENOMSG case ENOMSG: return "no message of desired type"; #endif #ifdef ENONET case ENONET: return "machine is not on the network"; #endif #ifdef ENOPKG case ENOPKG: return "package not installed"; #endif #if defined(ENOPROTOOPT) && (!defined(EPFNOSUPPORT) || (EPFNOSUPPORT != ENOPROTOOPT)) case ENOPROTOOPT: return "bad protocol option"; #endif #ifdef ENOSPC case ENOSPC: return "no space left on device"; #endif #if defined(ENOSR) && (!defined(ENAMETOOLONG) || (ENAMETOOLONG != ENOSR)) case ENOSR: return "out of stream resources"; #endif #if defined(ENOSTR) && (!defined(ENOTTY) || (ENOTTY != ENOSTR)) case ENOSTR: return "not a stream device"; #endif #ifdef ENOSYM case ENOSYM: return "unresolved symbol name"; #endif #ifdef ENOSYS case ENOSYS: return "function not implemented"; #endif #ifdef ENOTBLK case ENOTBLK: return "block device required"; #endif #ifdef ENOTCONN case ENOTCONN: return "socket is not connected"; #endif #ifdef ENOTDIR case ENOTDIR: return "not a directory"; #endif #if defined(ENOTEMPTY) && (!defined(EEXIST) || (ENOTEMPTY != EEXIST)) case ENOTEMPTY: return "directory not empty"; #endif #ifdef ENOTNAM case ENOTNAM: return "not a name file"; #endif #ifdef ENOTSOCK case ENOTSOCK: return "socket operation on non-socket"; #endif #ifdef ENOTSUP case ENOTSUP: return "operation not supported"; #endif #ifdef ENOTTY case ENOTTY: return "inappropriate device for ioctl"; #endif #ifdef ENOTUNIQ case ENOTUNIQ: return "name not unique on network"; #endif #ifdef ENXIO case ENXIO: return "no such device or address"; #endif #if defined(EOPNOTSUPP) && (!defined(ENOTSUP) || (ENOTSUP != EOPNOTSUPP)) case EOPNOTSUPP: return "operation not supported on socket"; #endif #if defined(EOVERFLOW) && (!defined(EFBIG) || (EOVERFLOW != EFBIG)) && (!defined(EINVAL) || (EOVERFLOW != EINVAL)) case EOVERFLOW: return "file too big"; #endif #ifdef EPERM case EPERM: return "not owner"; #endif #if defined(EPFNOSUPPORT) && (!defined(ENOLCK) || (ENOLCK != EPFNOSUPPORT)) case EPFNOSUPPORT: return "protocol family not supported"; #endif #ifdef EPIPE case EPIPE: return "broken pipe"; #endif #ifdef EPROCLIM case EPROCLIM: return "too many processes"; #endif #ifdef EPROCUNAVAIL case EPROCUNAVAIL: return "bad procedure for program"; #endif #ifdef EPROGMISMATCH case EPROGMISMATCH: return "program version wrong"; #endif #ifdef EPROGUNAVAIL case EPROGUNAVAIL: return "RPC program not available"; #endif #ifdef EPROTO case EPROTO: return "protocol error"; #endif #ifdef EPROTONOSUPPORT case EPROTONOSUPPORT: return "protocol not supported"; #endif #ifdef EPROTOTYPE case EPROTOTYPE: return "protocol wrong type for socket"; #endif #ifdef ERANGE case ERANGE: return "math result unrepresentable"; #endif #if defined(EREFUSED) && (!defined(ECONNREFUSED) || (EREFUSED != ECONNREFUSED)) case EREFUSED: return "EREFUSED"; #endif #ifdef EREMCHG case EREMCHG: return "remote address changed"; #endif #ifdef EREMDEV case EREMDEV: return "remote device"; #endif #ifdef EREMOTE case EREMOTE: return "pathname hit remote file system"; #endif #ifdef EREMOTEIO case EREMOTEIO: return "remote i/o error"; #endif #ifdef EREMOTERELEASE case EREMOTERELEASE: return "EREMOTERELEASE"; #endif #ifdef EROFS case EROFS: return "read-only file system"; #endif #ifdef ERPCMISMATCH case ERPCMISMATCH: return "RPC version is wrong"; #endif #ifdef ERREMOTE case ERREMOTE: return "object is remote"; #endif #ifdef ESHUTDOWN case ESHUTDOWN: return "can't send after socket shutdown"; #endif #ifdef ESOCKTNOSUPPORT case ESOCKTNOSUPPORT: return "socket type not supported"; #endif #ifdef ESPIPE case ESPIPE: return "invalid seek"; #endif #ifdef ESRCH case ESRCH: return "no such process"; #endif #ifdef ESRMNT case ESRMNT: return "srmount error"; #endif #ifdef ESTALE case ESTALE: return "stale remote file handle"; #endif #ifdef ESUCCESS case ESUCCESS: return "Error 0"; #endif #if defined(ETIME) && (!defined(ELOOP) || (ETIME != ELOOP)) case ETIME: return "timer expired"; #endif #if defined(ETIMEDOUT) && (!defined(ENOSTR) || (ETIMEDOUT != ENOSTR)) case ETIMEDOUT: return "connection timed out"; #endif #ifdef ETOOMANYREFS case ETOOMANYREFS: return "too many references: can't splice"; #endif #ifdef ETXTBSY case ETXTBSY: return "text file or pseudo-device busy"; #endif #ifdef EUCLEAN case EUCLEAN: return "structure needs cleaning"; #endif #ifdef EUNATCH case EUNATCH: return "protocol driver not attached"; #endif #ifdef EUSERS case EUSERS: return "too many users"; #endif #ifdef EVERSION case EVERSION: return "version mismatch"; #endif #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) case EWOULDBLOCK: return "operation would block"; #endif #ifdef EXDEV case EXDEV: return "cross-domain link"; #endif #ifdef EXFULL case EXFULL: return "message tables full"; #endif default: #ifdef NO_STRERROR return "unknown POSIX error"; #else return strerror(err); #endif } } /* *---------------------------------------------------------------------- * * Tcl_SignalId -- * * Return a textual identifier for a signal number. * * Results: * This procedure returns a machine-readable textual identifier * that corresponds to sig. The identifier is the same as the * #define name in signal.h. * * Side effects: * None. * *---------------------------------------------------------------------- */ CONST char * Tcl_SignalId(sig) int sig; /* Number of signal. */ { switch (sig) { #ifdef SIGABRT case SIGABRT: return "SIGABRT"; #endif #ifdef SIGALRM case SIGALRM: return "SIGALRM"; #endif #ifdef SIGBUS case SIGBUS: return "SIGBUS"; #endif #ifdef SIGCHLD case SIGCHLD: return "SIGCHLD"; #endif #if defined(SIGCLD) && (!defined(SIGCHLD) || (SIGCLD != SIGCHLD)) case SIGCLD: return "SIGCLD"; #endif #ifdef SIGCONT case SIGCONT: return "SIGCONT"; #endif #if defined(SIGEMT) && (!defined(SIGXCPU) || (SIGEMT != SIGXCPU)) case SIGEMT: return "SIGEMT"; #endif #ifdef SIGFPE case SIGFPE: return "SIGFPE"; #endif #ifdef SIGHUP case SIGHUP: return "SIGHUP"; #endif #ifdef SIGILL case SIGILL: return "SIGILL"; #endif #ifdef SIGINT case SIGINT: return "SIGINT"; #endif #ifdef SIGIO case SIGIO: return "SIGIO"; #endif #if defined(SIGIOT) && (!defined(SIGABRT) || (SIGIOT != SIGABRT)) case SIGIOT: return "SIGIOT"; #endif #ifdef SIGKILL case SIGKILL: return "SIGKILL"; #endif #if defined(SIGLOST) && (!defined(SIGIOT) || (SIGLOST != SIGIOT)) && (!defined(SIGURG) || (SIGLOST != SIGURG)) && (!defined(SIGPROF) || (SIGLOST != SIGPROF)) && (!defined(SIGIO) || (SIGLOST != SIGIO)) case SIGLOST: return "SIGLOST"; #endif #ifdef SIGPIPE case SIGPIPE: return "SIGPIPE"; #endif #if defined(SIGPOLL) && (!defined(SIGIO) || (SIGPOLL != SIGIO)) case SIGPOLL: return "SIGPOLL"; #endif #ifdef SIGPROF case SIGPROF: return "SIGPROF"; #endif #if defined(SIGPWR) && (!defined(SIGXFSZ) || (SIGPWR != SIGXFSZ)) && (!defined(SIGLOST) || (SIGPWR != SIGLOST)) case SIGPWR: return "SIGPWR"; #endif #ifdef SIGQUIT case SIGQUIT: return "SIGQUIT"; #endif #if defined(SIGSEGV) && (!defined(SIGBUS) || (SIGSEGV != SIGBUS)) case SIGSEGV: return "SIGSEGV"; #endif #ifdef SIGSTOP case SIGSTOP: return "SIGSTOP"; #endif #ifdef SIGSYS case SIGSYS: return "SIGSYS"; #endif #ifdef SIGTERM case SIGTERM: return "SIGTERM"; #endif #ifdef SIGTRAP case SIGTRAP: return "SIGTRAP"; #endif #ifdef SIGTSTP case SIGTSTP: return "SIGTSTP"; #endif #ifdef SIGTTIN case SIGTTIN: return "SIGTTIN"; #endif #ifdef SIGTTOU case SIGTTOU: return "SIGTTOU"; #endif #if defined(SIGURG) && (!defined(SIGIO) || (SIGURG != SIGIO)) case SIGURG: return "SIGURG"; #endif #if defined(SIGUSR1) && (!defined(SIGIO) || (SIGUSR1 != SIGIO)) case SIGUSR1: return "SIGUSR1"; #endif #if defined(SIGUSR2) && (!defined(SIGURG) || (SIGUSR2 != SIGURG)) case SIGUSR2: return "SIGUSR2"; #endif #ifdef SIGVTALRM case SIGVTALRM: return "SIGVTALRM"; #endif #ifdef SIGWINCH case SIGWINCH: return "SIGWINCH"; #endif #ifdef SIGXCPU case SIGXCPU: return "SIGXCPU"; #endif #ifdef SIGXFSZ case SIGXFSZ: return "SIGXFSZ"; #endif } return "unknown signal"; } /* *---------------------------------------------------------------------- * * Tcl_SignalMsg -- * * Return a human-readable message describing a signal. * * Results: * This procedure returns a string describing sig that should * make sense to a human. It may not be easy for a machine * to parse. * * Side effects: * None. * *---------------------------------------------------------------------- */ CONST char * Tcl_SignalMsg(sig) int sig; /* Number of signal. */ { switch (sig) { #ifdef SIGABRT case SIGABRT: return "SIGABRT"; #endif #ifdef SIGALRM case SIGALRM: return "alarm clock"; #endif #ifdef SIGBUS case SIGBUS: return "bus error"; #endif #ifdef SIGCHLD case SIGCHLD: return "child status changed"; #endif #if defined(SIGCLD) && (!defined(SIGCHLD) || (SIGCLD != SIGCHLD)) case SIGCLD: return "child status changed"; #endif #ifdef SIGCONT case SIGCONT: return "continue after stop"; #endif #if defined(SIGEMT) && (!defined(SIGXCPU) || (SIGEMT != SIGXCPU)) case SIGEMT: return "EMT instruction"; #endif #ifdef SIGFPE case SIGFPE: return "floating-point exception"; #endif #ifdef SIGHUP case SIGHUP: return "hangup"; #endif #ifdef SIGILL case SIGILL: return "illegal instruction"; #endif #ifdef SIGINT case SIGINT: return "interrupt"; #endif #ifdef SIGIO case SIGIO: return "input/output possible on file"; #endif #if defined(SIGIOT) && (!defined(SIGABRT) || (SIGABRT != SIGIOT)) case SIGIOT: return "IOT instruction"; #endif #ifdef SIGKILL case SIGKILL: return "kill signal"; #endif #if defined(SIGLOST) && (!defined(SIGIOT) || (SIGLOST != SIGIOT)) && (!defined(SIGURG) || (SIGLOST != SIGURG)) && (!defined(SIGPROF) || (SIGLOST != SIGPROF)) && (!defined(SIGIO) || (SIGLOST != SIGIO)) case SIGLOST: return "resource lost"; #endif #ifdef SIGPIPE case SIGPIPE: return "write on pipe with no readers"; #endif #if defined(SIGPOLL) && (!defined(SIGIO) || (SIGPOLL != SIGIO)) case SIGPOLL: return "input/output possible on file"; #endif #ifdef SIGPROF case SIGPROF: return "profiling alarm"; #endif #if defined(SIGPWR) && (!defined(SIGXFSZ) || (SIGPWR != SIGXFSZ)) && (!defined(SIGLOST) || (SIGPWR != SIGLOST)) case SIGPWR: return "power-fail restart"; #endif #ifdef SIGQUIT case SIGQUIT: return "quit signal"; #endif #if defined(SIGSEGV) && (!defined(SIGBUS) || (SIGSEGV != SIGBUS)) case SIGSEGV: return "segmentation violation"; #endif #ifdef SIGSTOP case SIGSTOP: return "stop"; #endif #ifdef SIGSYS case SIGSYS: return "bad argument to system call"; #endif #ifdef SIGTERM case SIGTERM: return "software termination signal"; #endif #ifdef SIGTRAP case SIGTRAP: return "trace trap"; #endif #ifdef SIGTSTP case SIGTSTP: return "stop signal from tty"; #endif #ifdef SIGTTIN case SIGTTIN: return "background tty read"; #endif #ifdef SIGTTOU case SIGTTOU: return "background tty write"; #endif #if defined(SIGURG) && (!defined(SIGIO) || (SIGURG != SIGIO)) case SIGURG: return "urgent I/O condition"; #endif #if defined(SIGUSR1) && (!defined(SIGIO) || (SIGUSR1 != SIGIO)) case SIGUSR1: return "user-defined signal 1"; #endif #if defined(SIGUSR2) && (!defined(SIGURG) || (SIGUSR2 != SIGURG)) case SIGUSR2: return "user-defined signal 2"; #endif #ifdef SIGVTALRM case SIGVTALRM: return "virtual time alarm"; #endif #ifdef SIGWINCH case SIGWINCH: return "window changed"; #endif #ifdef SIGXCPU case SIGXCPU: return "exceeded CPU time limit"; #endif #ifdef SIGXFSZ case SIGXFSZ: return "exceeded file size limit"; #endif } return "unknown signal"; } tcl8.4.20/generic/tclCompCmds.c0000644003604700454610000031033711737050674014716 0ustar dgp771div/* * tclCompCmds.c -- * * This file contains compilation procedures that compile various * Tcl commands into a sequence of instructions ("bytecodes"). * * Copyright (c) 1997-1998 Sun Microsystems, Inc. * Copyright (c) 2001 by Kevin B. Kenny. All rights reserved. * Copyright (c) 2002 ActiveState Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclCompile.h" /* * Prototypes for procedures defined later in this file: */ static ClientData DupForeachInfo _ANSI_ARGS_((ClientData clientData)); static void FreeForeachInfo _ANSI_ARGS_((ClientData clientData)); #ifndef TCL_TIP280 static int TclPushVarName _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Token *varTokenPtr, CompileEnv *envPtr, int flags, int *localIndexPtr, int *simpleVarNamePtr, int *isScalarPtr)); #define TclPushVarNameWord(i,v,e,f,l,s,sc,word) \ TclPushVarName (i,v,e,f,l,s,sc) /* ignoring word */ #define DefineLineInformation /**/ #define SetLineInformation(word) /**/ #else static int TclPushVarName _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Token *varTokenPtr, CompileEnv *envPtr, int flags, int *localIndexPtr, int *simpleVarNamePtr, int *isScalarPtr, int line, int* clNext)); #define TclPushVarNameWord(i,v,e,f,l,s,sc,word) \ TclPushVarName (i,v,e,f,l,s,sc, \ mapPtr->loc [eclIndex].line [(word)], \ mapPtr->loc [eclIndex].next [(word)]) /* TIP #280 : Remember the per-word line information of the current * command. An index is used instead of a pointer as recursive compilation may * reallocate, i.e. move, the array. This is also the reason to save the nuloc * now, it may change during the course of the function. * * Macros to encapsulate the variable definition and setup, and their use. */ #define DefineLineInformation \ ExtCmdLoc *mapPtr = envPtr->extCmdMapPtr; \ int eclIndex = mapPtr->nuloc - 1 #define SetLineInformation(word) \ envPtr->line = mapPtr->loc [eclIndex].line [(word)]; \ envPtr->clNext = mapPtr->loc [eclIndex].next [(word)] #endif /* * Flags bits used by TclPushVarName. */ #define TCL_CREATE_VAR 1 /* Create a compiled local if none is found */ #define TCL_NO_LARGE_INDEX 2 /* Do not return localIndex value > 255 */ /* * The structures below define the AuxData types defined in this file. */ AuxDataType tclForeachInfoType = { "ForeachInfo", /* name */ DupForeachInfo, /* dupProc */ FreeForeachInfo /* freeProc */ }; /* *---------------------------------------------------------------------- * * TclCompileAppendCmd -- * * Procedure called to compile the "append" command. * * Results: * The return value is a standard Tcl result, which is normally TCL_OK * unless there was an error while parsing string. If an error occurs * then the interpreter's result contains a standard error message. If * compilation fails because the command requires a second level of * substitutions, TCL_OUT_LINE_COMPILE is returned indicating that the * command should be compiled "out of line" by emitting code to * invoke its command procedure (Tcl_AppendObjCmd) at runtime. * * Side effects: * Instructions are added to envPtr to execute the "append" command * at runtime. * *---------------------------------------------------------------------- */ int TclCompileAppendCmd(interp, parsePtr, envPtr) Tcl_Interp *interp; /* Used for error reporting. */ Tcl_Parse *parsePtr; /* Points to a parse structure for the * command created by Tcl_ParseCommand. */ CompileEnv *envPtr; /* Holds resulting instructions. */ { Tcl_Token *varTokenPtr, *valueTokenPtr; int simpleVarName, isScalar, localIndex, numWords; int code = TCL_OK; DefineLineInformation; numWords = parsePtr->numWords; if (numWords == 1) { Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "wrong # args: should be \"append varName ?value value ...?\"", -1); return TCL_ERROR; } else if (numWords == 2) { /* * append varName === set varName */ return TclCompileSetCmd(interp, parsePtr, envPtr); } else if (numWords > 3) { /* * APPEND instructions currently only handle one value */ return TCL_OUT_LINE_COMPILE; } /* * Decide if we can use a frame slot for the var/array name or if we * need to emit code to compute and push the name at runtime. We use a * frame slot (entry in the array of local vars) if we are compiling a * procedure body and if the name is simple text that does not include * namespace qualifiers. */ varTokenPtr = parsePtr->tokenPtr + (parsePtr->tokenPtr->numComponents + 1); code = TclPushVarNameWord(interp, varTokenPtr, envPtr, TCL_CREATE_VAR, &localIndex, &simpleVarName, &isScalar, 1); if (code != TCL_OK) { goto done; } /* * We are doing an assignment, otherwise TclCompileSetCmd was called, * so push the new value. This will need to be extended to push a * value for each argument. */ if (numWords > 2) { valueTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1); if (valueTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) { TclEmitPush(TclRegisterNewLiteral(envPtr, valueTokenPtr[1].start, valueTokenPtr[1].size), envPtr); } else { SetLineInformation (2); code = TclCompileTokens(interp, valueTokenPtr+1, valueTokenPtr->numComponents, envPtr); if (code != TCL_OK) { goto done; } } } /* * Emit instructions to set/get the variable. */ if (simpleVarName) { if (isScalar) { if (localIndex >= 0) { if (localIndex <= 255) { TclEmitInstInt1(INST_APPEND_SCALAR1, localIndex, envPtr); } else { TclEmitInstInt4(INST_APPEND_SCALAR4, localIndex, envPtr); } } else { TclEmitOpcode(INST_APPEND_STK, envPtr); } } else { if (localIndex >= 0) { if (localIndex <= 255) { TclEmitInstInt1(INST_APPEND_ARRAY1, localIndex, envPtr); } else { TclEmitInstInt4(INST_APPEND_ARRAY4, localIndex, envPtr); } } else { TclEmitOpcode(INST_APPEND_ARRAY_STK, envPtr); } } } else { TclEmitOpcode(INST_APPEND_STK, envPtr); } done: return code; } /* *---------------------------------------------------------------------- * * TclCompileBreakCmd -- * * Procedure called to compile the "break" command. * * Results: * The return value is a standard Tcl result, which is TCL_OK unless * there was an error during compilation. If an error occurs then * the interpreter's result contains a standard error message. * * Side effects: * Instructions are added to envPtr to execute the "break" command * at runtime. * *---------------------------------------------------------------------- */ int TclCompileBreakCmd(interp, parsePtr, envPtr) Tcl_Interp *interp; /* Used for error reporting. */ Tcl_Parse *parsePtr; /* Points to a parse structure for the * command created by Tcl_ParseCommand. */ CompileEnv *envPtr; /* Holds resulting instructions. */ { if (parsePtr->numWords != 1) { Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "wrong # args: should be \"break\"", -1); return TCL_ERROR; } /* * Emit a break instruction. */ TclEmitOpcode(INST_BREAK, envPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * TclCompileCatchCmd -- * * Procedure called to compile the "catch" command. * * Results: * The return value is a standard Tcl result, which is TCL_OK if * compilation was successful. If an error occurs then the * interpreter's result contains a standard error message and TCL_ERROR * is returned. If the command is too complex for TclCompileCatchCmd, * TCL_OUT_LINE_COMPILE is returned indicating that the catch command * should be compiled "out of line" by emitting code to invoke its * command procedure at runtime. * * Side effects: * Instructions are added to envPtr to execute the "catch" command * at runtime. * *---------------------------------------------------------------------- */ int TclCompileCatchCmd(interp, parsePtr, envPtr) Tcl_Interp *interp; /* Used for error reporting. */ Tcl_Parse *parsePtr; /* Points to a parse structure for the * command created by Tcl_ParseCommand. */ CompileEnv *envPtr; /* Holds resulting instructions. */ { JumpFixup jumpFixup; Tcl_Token *cmdTokenPtr, *nameTokenPtr; CONST char *name; int localIndex, nameChars, range, startOffset, jumpDist; int code; int savedStackDepth = envPtr->currStackDepth; DefineLineInformation; if ((parsePtr->numWords != 2) && (parsePtr->numWords != 3)) { Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "wrong # args: should be \"catch command ?varName?\"", -1); return TCL_ERROR; } /* * If a variable was specified and the catch command is at global level * (not in a procedure), don't compile it inline: the payoff is * too small. */ if ((parsePtr->numWords == 3) && (envPtr->procPtr == NULL)) { return TCL_OUT_LINE_COMPILE; } /* * Make sure the variable name, if any, has no substitutions and just * refers to a local scaler. */ localIndex = -1; cmdTokenPtr = parsePtr->tokenPtr + (parsePtr->tokenPtr->numComponents + 1); if (parsePtr->numWords == 3) { nameTokenPtr = cmdTokenPtr + (cmdTokenPtr->numComponents + 1); if (nameTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) { name = nameTokenPtr[1].start; nameChars = nameTokenPtr[1].size; if (!TclIsLocalScalar(name, nameChars)) { return TCL_OUT_LINE_COMPILE; } localIndex = TclFindCompiledLocal(nameTokenPtr[1].start, nameTokenPtr[1].size, /*create*/ 1, /*flags*/ VAR_SCALAR, envPtr->procPtr); } else { return TCL_OUT_LINE_COMPILE; } } /* * We will compile the catch command. Emit a beginCatch instruction at * the start of the catch body: the subcommand it controls. */ envPtr->exceptDepth++; envPtr->maxExceptDepth = TclMax(envPtr->exceptDepth, envPtr->maxExceptDepth); range = TclCreateExceptRange(CATCH_EXCEPTION_RANGE, envPtr); TclEmitInstInt4(INST_BEGIN_CATCH4, range, envPtr); /* * If the body is a simple word, compile the instructions to * eval it. Otherwise, compile instructions to substitute its * text without catching, a catch instruction that resets the * stack to what it was before substituting the body, and then * an instruction to eval the body. Care has to be taken to * register the correct startOffset for the catch range so that * errors in the substitution are not catched [Bug 219184] */ SetLineInformation (1); if (cmdTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) { startOffset = (envPtr->codeNext - envPtr->codeStart); code = TclCompileCmdWord(interp, cmdTokenPtr+1, 1, envPtr); } else { code = TclCompileTokens(interp, cmdTokenPtr+1, cmdTokenPtr->numComponents, envPtr); startOffset = (envPtr->codeNext - envPtr->codeStart); TclEmitOpcode(INST_EVAL_STK, envPtr); } envPtr->exceptArrayPtr[range].codeOffset = startOffset; if (code != TCL_OK) { code = TCL_OUT_LINE_COMPILE; goto done; } envPtr->exceptArrayPtr[range].numCodeBytes = (envPtr->codeNext - envPtr->codeStart) - startOffset; /* * The "no errors" epilogue code: store the body's result into the * variable (if any), push "0" (TCL_OK) as the catch's "no error" * result, and jump around the "error case" code. */ if (localIndex != -1) { if (localIndex <= 255) { TclEmitInstInt1(INST_STORE_SCALAR1, localIndex, envPtr); } else { TclEmitInstInt4(INST_STORE_SCALAR4, localIndex, envPtr); } } TclEmitOpcode(INST_POP, envPtr); TclEmitPush(TclRegisterNewLiteral(envPtr, "0", 1), envPtr); TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &jumpFixup); /* * The "error case" code: store the body's result into the variable (if * any), then push the error result code. The initial PC offset here is * the catch's error target. */ envPtr->currStackDepth = savedStackDepth; envPtr->exceptArrayPtr[range].catchOffset = (envPtr->codeNext - envPtr->codeStart); if (localIndex != -1) { TclEmitOpcode(INST_PUSH_RESULT, envPtr); if (localIndex <= 255) { TclEmitInstInt1(INST_STORE_SCALAR1, localIndex, envPtr); } else { TclEmitInstInt4(INST_STORE_SCALAR4, localIndex, envPtr); } TclEmitOpcode(INST_POP, envPtr); } TclEmitOpcode(INST_PUSH_RETURN_CODE, envPtr); /* * Update the target of the jump after the "no errors" code, then emit * an endCatch instruction at the end of the catch command. */ jumpDist = (envPtr->codeNext - envPtr->codeStart) - jumpFixup.codeOffset; if (TclFixupForwardJump(envPtr, &jumpFixup, jumpDist, 127)) { panic("TclCompileCatchCmd: bad jump distance %d\n", jumpDist); } TclEmitOpcode(INST_END_CATCH, envPtr); done: envPtr->currStackDepth = savedStackDepth + 1; envPtr->exceptDepth--; return code; } /* *---------------------------------------------------------------------- * * TclCompileContinueCmd -- * * Procedure called to compile the "continue" command. * * Results: * The return value is a standard Tcl result, which is TCL_OK unless * there was an error while parsing string. If an error occurs then * the interpreter's result contains a standard error message. * * Side effects: * Instructions are added to envPtr to execute the "continue" command * at runtime. * *---------------------------------------------------------------------- */ int TclCompileContinueCmd(interp, parsePtr, envPtr) Tcl_Interp *interp; /* Used for error reporting. */ Tcl_Parse *parsePtr; /* Points to a parse structure for the * command created by Tcl_ParseCommand. */ CompileEnv *envPtr; /* Holds resulting instructions. */ { /* * There should be no argument after the "continue". */ if (parsePtr->numWords != 1) { Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "wrong # args: should be \"continue\"", -1); return TCL_ERROR; } /* * Emit a continue instruction. */ TclEmitOpcode(INST_CONTINUE, envPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * TclCompileExprCmd -- * * Procedure called to compile the "expr" command. * * Results: * The return value is a standard Tcl result, which is TCL_OK * unless there was an error while parsing string. If an error occurs * then the interpreter's result contains a standard error message. * * Side effects: * Instructions are added to envPtr to execute the "expr" command * at runtime. * *---------------------------------------------------------------------- */ int TclCompileExprCmd(interp, parsePtr, envPtr) Tcl_Interp *interp; /* Used for error reporting. */ Tcl_Parse *parsePtr; /* Points to a parse structure for the * command created by Tcl_ParseCommand. */ CompileEnv *envPtr; /* Holds resulting instructions. */ { Tcl_Token *firstWordPtr; DefineLineInformation; if (parsePtr->numWords == 1) { Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "wrong # args: should be \"expr arg ?arg ...?\"", -1); return TCL_ERROR; } SetLineInformation (1); firstWordPtr = parsePtr->tokenPtr + (parsePtr->tokenPtr->numComponents + 1); return TclCompileExprWords(interp, firstWordPtr, (parsePtr->numWords-1), envPtr); } /* *---------------------------------------------------------------------- * * TclCompileForCmd -- * * Procedure called to compile the "for" command. * * Results: * The return value is a standard Tcl result, which is TCL_OK unless * there was an error while parsing string. If an error occurs then * the interpreter's result contains a standard error message. * * Side effects: * Instructions are added to envPtr to execute the "for" command * at runtime. * *---------------------------------------------------------------------- */ int TclCompileForCmd(interp, parsePtr, envPtr) Tcl_Interp *interp; /* Used for error reporting. */ Tcl_Parse *parsePtr; /* Points to a parse structure for the * command created by Tcl_ParseCommand. */ CompileEnv *envPtr; /* Holds resulting instructions. */ { Tcl_Token *startTokenPtr, *testTokenPtr, *nextTokenPtr, *bodyTokenPtr; JumpFixup jumpEvalCondFixup; int testCodeOffset, bodyCodeOffset, nextCodeOffset, jumpDist; int bodyRange, nextRange, code; char buffer[32 + TCL_INTEGER_SPACE]; int savedStackDepth = envPtr->currStackDepth; DefineLineInformation; if (parsePtr->numWords != 5) { Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "wrong # args: should be \"for start test next command\"", -1); return TCL_ERROR; } /* * If the test expression requires substitutions, don't compile the for * command inline. E.g., the expression might cause the loop to never * execute or execute forever, as in "for {} "$x > 5" {incr x} {}". */ startTokenPtr = parsePtr->tokenPtr + (parsePtr->tokenPtr->numComponents + 1); testTokenPtr = startTokenPtr + (startTokenPtr->numComponents + 1); if (testTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { return TCL_OUT_LINE_COMPILE; } /* * Bail out also if the body or the next expression require substitutions * in order to insure correct behaviour [Bug 219166] */ nextTokenPtr = testTokenPtr + (testTokenPtr->numComponents + 1); bodyTokenPtr = nextTokenPtr + (nextTokenPtr->numComponents + 1); if ((nextTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) || (bodyTokenPtr->type != TCL_TOKEN_SIMPLE_WORD)) { return TCL_OUT_LINE_COMPILE; } /* * Create ExceptionRange records for the body and the "next" command. * The "next" command's ExceptionRange supports break but not continue * (and has a -1 continueOffset). */ envPtr->exceptDepth++; envPtr->maxExceptDepth = TclMax(envPtr->exceptDepth, envPtr->maxExceptDepth); bodyRange = TclCreateExceptRange(LOOP_EXCEPTION_RANGE, envPtr); nextRange = TclCreateExceptRange(LOOP_EXCEPTION_RANGE, envPtr); /* * Inline compile the initial command. */ SetLineInformation (1); code = TclCompileCmdWord(interp, startTokenPtr+1, startTokenPtr->numComponents, envPtr); if (code != TCL_OK) { if (code == TCL_ERROR) { Tcl_AddObjErrorInfo(interp, "\n (\"for\" initial command)", -1); } goto done; } TclEmitOpcode(INST_POP, envPtr); /* * Jump to the evaluation of the condition. This code uses the "loop * rotation" optimisation (which eliminates one branch from the loop). * "for start cond next body" produces then: * start * goto A * B: body : bodyCodeOffset * next : nextCodeOffset, continueOffset * A: cond -> result : testCodeOffset * if (result) goto B */ TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &jumpEvalCondFixup); /* * Compile the loop body. */ bodyCodeOffset = (envPtr->codeNext - envPtr->codeStart); SetLineInformation (4); code = TclCompileCmdWord(interp, bodyTokenPtr+1, bodyTokenPtr->numComponents, envPtr); envPtr->currStackDepth = savedStackDepth + 1; if (code != TCL_OK) { if (code == TCL_ERROR) { sprintf(buffer, "\n (\"for\" body line %d)", interp->errorLine); Tcl_AddObjErrorInfo(interp, buffer, -1); } goto done; } envPtr->exceptArrayPtr[bodyRange].numCodeBytes = (envPtr->codeNext - envPtr->codeStart) - bodyCodeOffset; TclEmitOpcode(INST_POP, envPtr); /* * Compile the "next" subcommand. */ nextCodeOffset = (envPtr->codeNext - envPtr->codeStart); SetLineInformation (3); envPtr->currStackDepth = savedStackDepth; code = TclCompileCmdWord(interp, nextTokenPtr+1, nextTokenPtr->numComponents, envPtr); envPtr->currStackDepth = savedStackDepth + 1; if (code != TCL_OK) { if (code == TCL_ERROR) { Tcl_AddObjErrorInfo(interp, "\n (\"for\" loop-end command)", -1); } goto done; } envPtr->exceptArrayPtr[nextRange].numCodeBytes = (envPtr->codeNext - envPtr->codeStart) - nextCodeOffset; TclEmitOpcode(INST_POP, envPtr); envPtr->currStackDepth = savedStackDepth; /* * Compile the test expression then emit the conditional jump that * terminates the for. */ testCodeOffset = (envPtr->codeNext - envPtr->codeStart); jumpDist = testCodeOffset - jumpEvalCondFixup.codeOffset; if (TclFixupForwardJump(envPtr, &jumpEvalCondFixup, jumpDist, 127)) { bodyCodeOffset += 3; nextCodeOffset += 3; testCodeOffset += 3; } SetLineInformation (2); envPtr->currStackDepth = savedStackDepth; code = TclCompileExprWords(interp, testTokenPtr, 1, envPtr); if (code != TCL_OK) { if (code == TCL_ERROR) { Tcl_AddObjErrorInfo(interp, "\n (\"for\" test expression)", -1); } goto done; } envPtr->currStackDepth = savedStackDepth + 1; jumpDist = (envPtr->codeNext - envPtr->codeStart) - bodyCodeOffset; if (jumpDist > 127) { TclEmitInstInt4(INST_JUMP_TRUE4, -jumpDist, envPtr); } else { TclEmitInstInt1(INST_JUMP_TRUE1, -jumpDist, envPtr); } /* * Set the loop's offsets and break target. */ envPtr->exceptArrayPtr[bodyRange].codeOffset = bodyCodeOffset; envPtr->exceptArrayPtr[bodyRange].continueOffset = nextCodeOffset; envPtr->exceptArrayPtr[nextRange].codeOffset = nextCodeOffset; envPtr->exceptArrayPtr[bodyRange].breakOffset = envPtr->exceptArrayPtr[nextRange].breakOffset = (envPtr->codeNext - envPtr->codeStart); /* * The for command's result is an empty string. */ envPtr->currStackDepth = savedStackDepth; TclEmitPush(TclRegisterNewLiteral(envPtr, "", 0), envPtr); code = TCL_OK; done: envPtr->exceptDepth--; return code; } /* *---------------------------------------------------------------------- * * TclCompileForeachCmd -- * * Procedure called to compile the "foreach" command. * * Results: * The return value is a standard Tcl result, which is TCL_OK if * compilation was successful. If an error occurs then the * interpreter's result contains a standard error message and TCL_ERROR * is returned. If the command is too complex for TclCompileForeachCmd, * TCL_OUT_LINE_COMPILE is returned indicating that the foreach command * should be compiled "out of line" by emitting code to invoke its * command procedure at runtime. * * Side effects: * Instructions are added to envPtr to execute the "foreach" command * at runtime. * n*---------------------------------------------------------------------- */ int TclCompileForeachCmd(interp, parsePtr, envPtr) Tcl_Interp *interp; /* Used for error reporting. */ Tcl_Parse *parsePtr; /* Points to a parse structure for the * command created by Tcl_ParseCommand. */ CompileEnv *envPtr; /* Holds resulting instructions. */ { Proc *procPtr = envPtr->procPtr; ForeachInfo *infoPtr; /* Points to the structure describing this * foreach command. Stored in a AuxData * record in the ByteCode. */ int firstValueTemp; /* Index of the first temp var in the frame * used to point to a value list. */ int loopCtTemp; /* Index of temp var holding the loop's * iteration count. */ Tcl_Token *tokenPtr, *bodyTokenPtr; unsigned char *jumpPc; JumpFixup jumpFalseFixup; int jumpDist, jumpBackDist, jumpBackOffset, infoIndex, range; int numWords, numLists, numVars, loopIndex, tempVar, i, j, code; char buffer[32 + TCL_INTEGER_SPACE]; int savedStackDepth = envPtr->currStackDepth; #ifdef TCL_TIP280 int bodyIndex; #endif /* * We parse the variable list argument words and create two arrays: * varcList[i] is number of variables in i-th var list * varvList[i] points to array of var names in i-th var list */ #define STATIC_VAR_LIST_SIZE 5 int varcListStaticSpace[STATIC_VAR_LIST_SIZE]; CONST char **varvListStaticSpace[STATIC_VAR_LIST_SIZE]; int *varcList = varcListStaticSpace; CONST char ***varvList = varvListStaticSpace; DefineLineInformation; /* * If the foreach command isn't in a procedure, don't compile it inline: * the payoff is too small. */ if (procPtr == NULL) { return TCL_OUT_LINE_COMPILE; } numWords = parsePtr->numWords; if ((numWords < 4) || (numWords%2 != 0)) { Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "wrong # args: should be \"foreach varList list ?varList list ...? command\"", -1); return TCL_ERROR; } /* * Bail out if the body requires substitutions * in order to insure correct behaviour [Bug 219166] */ for (i = 0, tokenPtr = parsePtr->tokenPtr; i < numWords-1; i++, tokenPtr += (tokenPtr->numComponents + 1)) { } bodyTokenPtr = tokenPtr; if (bodyTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { return TCL_OUT_LINE_COMPILE; } #ifdef TCL_TIP280 bodyIndex = i-1; #endif /* * Allocate storage for the varcList and varvList arrays if necessary. */ numLists = (numWords - 2)/2; if (numLists > STATIC_VAR_LIST_SIZE) { varcList = (int *) ckalloc(numLists * sizeof(int)); varvList = (CONST char ***) ckalloc(numLists * sizeof(CONST char **)); } for (loopIndex = 0; loopIndex < numLists; loopIndex++) { varcList[loopIndex] = 0; varvList[loopIndex] = NULL; } /* * Set the exception stack depth. */ envPtr->exceptDepth++; envPtr->maxExceptDepth = TclMax(envPtr->exceptDepth, envPtr->maxExceptDepth); /* * Break up each var list and set the varcList and varvList arrays. * Don't compile the foreach inline if any var name needs substitutions * or isn't a scalar, or if any var list needs substitutions. */ loopIndex = 0; for (i = 0, tokenPtr = parsePtr->tokenPtr; i < numWords-1; i++, tokenPtr += (tokenPtr->numComponents + 1)) { if (i%2 == 1) { if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { code = TCL_OUT_LINE_COMPILE; goto done; } else { /* Lots of copying going on here. Need a ListObj wizard * to show a better way. */ Tcl_DString varList; Tcl_DStringInit(&varList); Tcl_DStringAppend(&varList, tokenPtr[1].start, tokenPtr[1].size); code = Tcl_SplitList(interp, Tcl_DStringValue(&varList), &varcList[loopIndex], &varvList[loopIndex]); Tcl_DStringFree(&varList); if (code != TCL_OK) { goto done; } numVars = varcList[loopIndex]; /* * If the variable list is empty, we can enter an infinite * loop when the interpreted version would not. Take care to * ensure this does not happen. [Bug 1671138] */ if (numVars == 0) { code = TCL_OUT_LINE_COMPILE; goto done; } for (j = 0; j < numVars; j++) { CONST char *varName = varvList[loopIndex][j]; if (!TclIsLocalScalar(varName, (int) strlen(varName))) { code = TCL_OUT_LINE_COMPILE; goto done; } } } loopIndex++; } } /* * We will compile the foreach command. * Reserve (numLists + 1) temporary variables: * - numLists temps to hold each value list * - 1 temp for the loop counter (index of next element in each list) * At this time we don't try to reuse temporaries; if there are two * nonoverlapping foreach loops, they don't share any temps. */ firstValueTemp = -1; for (loopIndex = 0; loopIndex < numLists; loopIndex++) { tempVar = TclFindCompiledLocal(NULL, /*nameChars*/ 0, /*create*/ 1, /*flags*/ VAR_SCALAR, procPtr); if (loopIndex == 0) { firstValueTemp = tempVar; } } loopCtTemp = TclFindCompiledLocal(NULL, /*nameChars*/ 0, /*create*/ 1, /*flags*/ VAR_SCALAR, procPtr); /* * Create and initialize the ForeachInfo and ForeachVarList data * structures describing this command. Then create a AuxData record * pointing to the ForeachInfo structure. */ infoPtr = (ForeachInfo *) ckalloc((unsigned) (sizeof(ForeachInfo) + (numLists * sizeof(ForeachVarList *)))); infoPtr->numLists = numLists; infoPtr->firstValueTemp = firstValueTemp; infoPtr->loopCtTemp = loopCtTemp; for (loopIndex = 0; loopIndex < numLists; loopIndex++) { ForeachVarList *varListPtr; numVars = varcList[loopIndex]; varListPtr = (ForeachVarList *) ckalloc((unsigned) sizeof(ForeachVarList) + (numVars * sizeof(int))); varListPtr->numVars = numVars; for (j = 0; j < numVars; j++) { CONST char *varName = varvList[loopIndex][j]; int nameChars = strlen(varName); varListPtr->varIndexes[j] = TclFindCompiledLocal(varName, nameChars, /*create*/ 1, /*flags*/ VAR_SCALAR, procPtr); } infoPtr->varLists[loopIndex] = varListPtr; } infoIndex = TclCreateAuxData((ClientData) infoPtr, &tclForeachInfoType, envPtr); /* * Evaluate then store each value list in the associated temporary. */ range = TclCreateExceptRange(LOOP_EXCEPTION_RANGE, envPtr); loopIndex = 0; for (i = 0, tokenPtr = parsePtr->tokenPtr; i < numWords-1; i++, tokenPtr += (tokenPtr->numComponents + 1)) { if ((i%2 == 0) && (i > 0)) { SetLineInformation (i); code = TclCompileTokens(interp, tokenPtr+1, tokenPtr->numComponents, envPtr); if (code != TCL_OK) { goto done; } tempVar = (firstValueTemp + loopIndex); if (tempVar <= 255) { TclEmitInstInt1(INST_STORE_SCALAR1, tempVar, envPtr); } else { TclEmitInstInt4(INST_STORE_SCALAR4, tempVar, envPtr); } TclEmitOpcode(INST_POP, envPtr); loopIndex++; } } /* * Initialize the temporary var that holds the count of loop iterations. */ TclEmitInstInt4(INST_FOREACH_START4, infoIndex, envPtr); /* * Top of loop code: assign each loop variable and check whether * to terminate the loop. */ envPtr->exceptArrayPtr[range].continueOffset = (envPtr->codeNext - envPtr->codeStart); TclEmitInstInt4(INST_FOREACH_STEP4, infoIndex, envPtr); TclEmitForwardJump(envPtr, TCL_FALSE_JUMP, &jumpFalseFixup); /* * Inline compile the loop body. */ SetLineInformation (bodyIndex); envPtr->exceptArrayPtr[range].codeOffset = (envPtr->codeNext - envPtr->codeStart); code = TclCompileCmdWord(interp, bodyTokenPtr+1, bodyTokenPtr->numComponents, envPtr); envPtr->currStackDepth = savedStackDepth + 1; if (code != TCL_OK) { if (code == TCL_ERROR) { sprintf(buffer, "\n (\"foreach\" body line %d)", interp->errorLine); Tcl_AddObjErrorInfo(interp, buffer, -1); } goto done; } envPtr->exceptArrayPtr[range].numCodeBytes = (envPtr->codeNext - envPtr->codeStart) - envPtr->exceptArrayPtr[range].codeOffset; TclEmitOpcode(INST_POP, envPtr); /* * Jump back to the test at the top of the loop. Generate a 4 byte jump * if the distance to the test is > 120 bytes. This is conservative and * ensures that we won't have to replace this jump if we later need to * replace the ifFalse jump with a 4 byte jump. */ jumpBackOffset = (envPtr->codeNext - envPtr->codeStart); jumpBackDist = (jumpBackOffset - envPtr->exceptArrayPtr[range].continueOffset); if (jumpBackDist > 120) { TclEmitInstInt4(INST_JUMP4, -jumpBackDist, envPtr); } else { TclEmitInstInt1(INST_JUMP1, -jumpBackDist, envPtr); } /* * Fix the target of the jump after the foreach_step test. */ jumpDist = (envPtr->codeNext - envPtr->codeStart) - jumpFalseFixup.codeOffset; if (TclFixupForwardJump(envPtr, &jumpFalseFixup, jumpDist, 127)) { /* * Update the loop body's starting PC offset since it moved down. */ envPtr->exceptArrayPtr[range].codeOffset += 3; /* * Update the jump back to the test at the top of the loop since it * also moved down 3 bytes. */ jumpBackOffset += 3; jumpPc = (envPtr->codeStart + jumpBackOffset); jumpBackDist += 3; if (jumpBackDist > 120) { TclUpdateInstInt4AtPc(INST_JUMP4, -jumpBackDist, jumpPc); } else { TclUpdateInstInt1AtPc(INST_JUMP1, -jumpBackDist, jumpPc); } } /* * Set the loop's break target. */ envPtr->exceptArrayPtr[range].breakOffset = (envPtr->codeNext - envPtr->codeStart); /* * The foreach command's result is an empty string. */ envPtr->currStackDepth = savedStackDepth; TclEmitPush(TclRegisterNewLiteral(envPtr, "", 0), envPtr); envPtr->currStackDepth = savedStackDepth + 1; done: for (loopIndex = 0; loopIndex < numLists; loopIndex++) { if (varvList[loopIndex] != (CONST char **) NULL) { ckfree((char *) varvList[loopIndex]); } } if (varcList != varcListStaticSpace) { ckfree((char *) varcList); ckfree((char *) varvList); } envPtr->exceptDepth--; return code; } /* *---------------------------------------------------------------------- * * DupForeachInfo -- * * This procedure duplicates a ForeachInfo structure created as * auxiliary data during the compilation of a foreach command. * * Results: * A pointer to a newly allocated copy of the existing ForeachInfo * structure is returned. * * Side effects: * Storage for the copied ForeachInfo record is allocated. If the * original ForeachInfo structure pointed to any ForeachVarList * records, these structures are also copied and pointers to them * are stored in the new ForeachInfo record. * *---------------------------------------------------------------------- */ static ClientData DupForeachInfo(clientData) ClientData clientData; /* The foreach command's compilation * auxiliary data to duplicate. */ { register ForeachInfo *srcPtr = (ForeachInfo *) clientData; ForeachInfo *dupPtr; register ForeachVarList *srcListPtr, *dupListPtr; int numLists = srcPtr->numLists; int numVars, i, j; dupPtr = (ForeachInfo *) ckalloc((unsigned) (sizeof(ForeachInfo) + (numLists * sizeof(ForeachVarList *)))); dupPtr->numLists = numLists; dupPtr->firstValueTemp = srcPtr->firstValueTemp; dupPtr->loopCtTemp = srcPtr->loopCtTemp; for (i = 0; i < numLists; i++) { srcListPtr = srcPtr->varLists[i]; numVars = srcListPtr->numVars; dupListPtr = (ForeachVarList *) ckalloc((unsigned) sizeof(ForeachVarList) + numVars*sizeof(int)); dupListPtr->numVars = numVars; for (j = 0; j < numVars; j++) { dupListPtr->varIndexes[j] = srcListPtr->varIndexes[j]; } dupPtr->varLists[i] = dupListPtr; } return (ClientData) dupPtr; } /* *---------------------------------------------------------------------- * * FreeForeachInfo -- * * Procedure to free a ForeachInfo structure created as auxiliary data * during the compilation of a foreach command. * * Results: * None. * * Side effects: * Storage for the ForeachInfo structure pointed to by the ClientData * argument is freed as is any ForeachVarList record pointed to by the * ForeachInfo structure. * *---------------------------------------------------------------------- */ static void FreeForeachInfo(clientData) ClientData clientData; /* The foreach command's compilation * auxiliary data to free. */ { register ForeachInfo *infoPtr = (ForeachInfo *) clientData; register ForeachVarList *listPtr; int numLists = infoPtr->numLists; register int i; for (i = 0; i < numLists; i++) { listPtr = infoPtr->varLists[i]; ckfree((char *) listPtr); } ckfree((char *) infoPtr); } /* *---------------------------------------------------------------------- * * TclCompileIfCmd -- * * Procedure called to compile the "if" command. * * Results: * The return value is a standard Tcl result, which is TCL_OK if * compilation was successful. If an error occurs then the * interpreter's result contains a standard error message and TCL_ERROR * is returned. If the command is too complex for TclCompileIfCmd, * TCL_OUT_LINE_COMPILE is returned indicating that the if command * should be compiled "out of line" by emitting code to invoke its * command procedure at runtime. * * Side effects: * Instructions are added to envPtr to execute the "if" command * at runtime. * *---------------------------------------------------------------------- */ int TclCompileIfCmd(interp, parsePtr, envPtr) Tcl_Interp *interp; /* Used for error reporting. */ Tcl_Parse *parsePtr; /* Points to a parse structure for the * command created by Tcl_ParseCommand. */ CompileEnv *envPtr; /* Holds resulting instructions. */ { JumpFixupArray jumpFalseFixupArray; /* Used to fix the ifFalse jump after each * test when its target PC is determined. */ JumpFixupArray jumpEndFixupArray; /* Used to fix the jump after each "then" * body to the end of the "if" when that PC * is determined. */ Tcl_Token *tokenPtr, *testTokenPtr; int jumpDist, jumpFalseDist; int jumpIndex = 0; /* avoid compiler warning. */ int numWords, wordIdx, numBytes, j, code; CONST char *word; char buffer[100]; int savedStackDepth = envPtr->currStackDepth; /* Saved stack depth at the start of the first * test; the envPtr current depth is restored * to this value at the start of each test. */ int realCond = 1; /* set to 0 for static conditions: "if 0 {..}" */ int boolVal; /* value of static condition */ int compileScripts = 1; DefineLineInformation; /* * Only compile the "if" command if all arguments are simple * words, in order to insure correct substitution [Bug 219166] */ tokenPtr = parsePtr->tokenPtr; wordIdx = 0; numWords = parsePtr->numWords; for (wordIdx = 0; wordIdx < numWords; wordIdx++) { if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { return TCL_OUT_LINE_COMPILE; } tokenPtr += 2; } TclInitJumpFixupArray(&jumpFalseFixupArray); TclInitJumpFixupArray(&jumpEndFixupArray); code = TCL_OK; /* * Each iteration of this loop compiles one "if expr ?then? body" * or "elseif expr ?then? body" clause. */ tokenPtr = parsePtr->tokenPtr; wordIdx = 0; while (wordIdx < numWords) { /* * Stop looping if the token isn't "if" or "elseif". */ word = tokenPtr[1].start; numBytes = tokenPtr[1].size; if ((tokenPtr == parsePtr->tokenPtr) || ((numBytes == 6) && (strncmp(word, "elseif", 6) == 0))) { tokenPtr += (tokenPtr->numComponents + 1); wordIdx++; } else { break; } if (wordIdx >= numWords) { sprintf(buffer, "wrong # args: no expression after \"%.*s\" argument", (numBytes > 50 ? 50 : numBytes), word); Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), buffer, -1); code = TCL_ERROR; goto done; } /* * Compile the test expression then emit the conditional jump * around the "then" part. */ envPtr->currStackDepth = savedStackDepth; testTokenPtr = tokenPtr; if (realCond) { /* * Find out if the condition is a constant. */ Tcl_Obj *boolObj = Tcl_NewStringObj(testTokenPtr[1].start, testTokenPtr[1].size); Tcl_IncrRefCount(boolObj); code = Tcl_GetBooleanFromObj(NULL, boolObj, &boolVal); Tcl_DecrRefCount(boolObj); if (code == TCL_OK) { /* * A static condition */ realCond = 0; if (!boolVal) { compileScripts = 0; } } else { Tcl_ResetResult(interp); SetLineInformation (wordIdx); code = TclCompileExprWords(interp, testTokenPtr, 1, envPtr); if (code != TCL_OK) { if (code == TCL_ERROR) { Tcl_AddObjErrorInfo(interp, "\n (\"if\" test expression)", -1); } goto done; } if (jumpFalseFixupArray.next >= jumpFalseFixupArray.end) { TclExpandJumpFixupArray(&jumpFalseFixupArray); } jumpIndex = jumpFalseFixupArray.next; jumpFalseFixupArray.next++; TclEmitForwardJump(envPtr, TCL_FALSE_JUMP, &(jumpFalseFixupArray.fixup[jumpIndex])); } } /* * Skip over the optional "then" before the then clause. */ tokenPtr = testTokenPtr + (testTokenPtr->numComponents + 1); wordIdx++; if (wordIdx >= numWords) { sprintf(buffer, "wrong # args: no script following \"%.*s\" argument", (testTokenPtr->size > 50 ? 50 : testTokenPtr->size), testTokenPtr->start); Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), buffer, -1); code = TCL_ERROR; goto done; } if (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD) { word = tokenPtr[1].start; numBytes = tokenPtr[1].size; if ((numBytes == 4) && (strncmp(word, "then", 4) == 0)) { tokenPtr += (tokenPtr->numComponents + 1); wordIdx++; if (wordIdx >= numWords) { Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "wrong # args: no script following \"then\" argument", -1); code = TCL_ERROR; goto done; } } } /* * Compile the "then" command body. */ if (compileScripts) { SetLineInformation (wordIdx); envPtr->currStackDepth = savedStackDepth; code = TclCompileCmdWord(interp, tokenPtr+1, tokenPtr->numComponents, envPtr); if (code != TCL_OK) { if (code == TCL_ERROR) { sprintf(buffer, "\n (\"if\" then script line %d)", interp->errorLine); Tcl_AddObjErrorInfo(interp, buffer, -1); } goto done; } } if (realCond) { /* * Jump to the end of the "if" command. Both jumpFalseFixupArray and * jumpEndFixupArray are indexed by "jumpIndex". */ if (jumpEndFixupArray.next >= jumpEndFixupArray.end) { TclExpandJumpFixupArray(&jumpEndFixupArray); } jumpEndFixupArray.next++; TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &(jumpEndFixupArray.fixup[jumpIndex])); /* * Fix the target of the jumpFalse after the test. Generate a 4 byte * jump if the distance is > 120 bytes. This is conservative, and * ensures that we won't have to replace this jump if we later also * need to replace the proceeding jump to the end of the "if" with a * 4 byte jump. */ jumpDist = (envPtr->codeNext - envPtr->codeStart) - jumpFalseFixupArray.fixup[jumpIndex].codeOffset; if (TclFixupForwardJump(envPtr, &(jumpFalseFixupArray.fixup[jumpIndex]), jumpDist, 120)) { /* * Adjust the code offset for the proceeding jump to the end * of the "if" command. */ jumpEndFixupArray.fixup[jumpIndex].codeOffset += 3; } } else if (boolVal) { /* *We were processing an "if 1 {...}"; stop compiling * scripts */ compileScripts = 0; } else { /* *We were processing an "if 0 {...}"; reset so that * the rest (elseif, else) is compiled correctly */ realCond = 1; compileScripts = 1; } tokenPtr += (tokenPtr->numComponents + 1); wordIdx++; } /* * Restore the current stack depth in the environment; the * "else" clause (or its default) will add 1 to this. */ envPtr->currStackDepth = savedStackDepth; /* * Check for the optional else clause. Do not compile * anything if this was an "if 1 {...}" case. */ if ((wordIdx < numWords) && (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD)) { /* * There is an else clause. Skip over the optional "else" word. */ word = tokenPtr[1].start; numBytes = tokenPtr[1].size; if ((numBytes == 4) && (strncmp(word, "else", 4) == 0)) { tokenPtr += (tokenPtr->numComponents + 1); wordIdx++; if (wordIdx >= numWords) { Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "wrong # args: no script following \"else\" argument", -1); code = TCL_ERROR; goto done; } } if (compileScripts) { /* * Compile the else command body. */ SetLineInformation (wordIdx); code = TclCompileCmdWord(interp, tokenPtr+1, tokenPtr->numComponents, envPtr); if (code != TCL_OK) { if (code == TCL_ERROR) { sprintf(buffer, "\n (\"if\" else script line %d)", interp->errorLine); Tcl_AddObjErrorInfo(interp, buffer, -1); } goto done; } } /* * Make sure there are no words after the else clause. */ wordIdx++; if (wordIdx < numWords) { Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "wrong # args: extra words after \"else\" clause in \"if\" command", -1); code = TCL_ERROR; goto done; } } else { /* * No else clause: the "if" command's result is an empty string. */ if (compileScripts) { TclEmitPush(TclRegisterNewLiteral(envPtr, "", 0), envPtr); } } /* * Fix the unconditional jumps to the end of the "if" command. */ for (j = jumpEndFixupArray.next; j > 0; j--) { jumpIndex = (j - 1); /* i.e. process the closest jump first */ jumpDist = (envPtr->codeNext - envPtr->codeStart) - jumpEndFixupArray.fixup[jumpIndex].codeOffset; if (TclFixupForwardJump(envPtr, &(jumpEndFixupArray.fixup[jumpIndex]), jumpDist, 127)) { /* * Adjust the immediately preceeding "ifFalse" jump. We moved * it's target (just after this jump) down three bytes. */ unsigned char *ifFalsePc = envPtr->codeStart + jumpFalseFixupArray.fixup[jumpIndex].codeOffset; unsigned char opCode = *ifFalsePc; if (opCode == INST_JUMP_FALSE1) { jumpFalseDist = TclGetInt1AtPtr(ifFalsePc + 1); jumpFalseDist += 3; TclStoreInt1AtPtr(jumpFalseDist, (ifFalsePc + 1)); } else if (opCode == INST_JUMP_FALSE4) { jumpFalseDist = TclGetInt4AtPtr(ifFalsePc + 1); jumpFalseDist += 3; TclStoreInt4AtPtr(jumpFalseDist, (ifFalsePc + 1)); } else { panic("TclCompileIfCmd: unexpected opcode updating ifFalse jump"); } } } /* * Free the jumpFixupArray array if malloc'ed storage was used. */ done: envPtr->currStackDepth = savedStackDepth + 1; TclFreeJumpFixupArray(&jumpFalseFixupArray); TclFreeJumpFixupArray(&jumpEndFixupArray); return code; } /* *---------------------------------------------------------------------- * * TclCompileIncrCmd -- * * Procedure called to compile the "incr" command. * * Results: * The return value is a standard Tcl result, which is TCL_OK if * compilation was successful. If an error occurs then the * interpreter's result contains a standard error message and TCL_ERROR * is returned. If the command is too complex for TclCompileIncrCmd, * TCL_OUT_LINE_COMPILE is returned indicating that the incr command * should be compiled "out of line" by emitting code to invoke its * command procedure at runtime. * * Side effects: * Instructions are added to envPtr to execute the "incr" command * at runtime. * *---------------------------------------------------------------------- */ int TclCompileIncrCmd(interp, parsePtr, envPtr) Tcl_Interp *interp; /* Used for error reporting. */ Tcl_Parse *parsePtr; /* Points to a parse structure for the * command created by Tcl_ParseCommand. */ CompileEnv *envPtr; /* Holds resulting instructions. */ { Tcl_Token *varTokenPtr, *incrTokenPtr; int simpleVarName, isScalar, localIndex, haveImmValue, immValue; int code = TCL_OK; DefineLineInformation; if ((parsePtr->numWords != 2) && (parsePtr->numWords != 3)) { Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "wrong # args: should be \"incr varName ?increment?\"", -1); return TCL_ERROR; } varTokenPtr = parsePtr->tokenPtr + (parsePtr->tokenPtr->numComponents + 1); code = TclPushVarNameWord(interp, varTokenPtr, envPtr, (TCL_NO_LARGE_INDEX | TCL_CREATE_VAR), &localIndex, &simpleVarName, &isScalar, 1); if (code != TCL_OK) { goto done; } /* * If an increment is given, push it, but see first if it's a small * integer. */ haveImmValue = 0; immValue = 1; if (parsePtr->numWords == 3) { incrTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1); if (incrTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) { CONST char *word = incrTokenPtr[1].start; int numBytes = incrTokenPtr[1].size; /* * Note there is a danger that modifying the string could have * undesirable side effects. In this case, TclLooksLikeInt has * no dependencies on shared strings so we should be safe. */ if (TclLooksLikeInt(word, numBytes)) { int code; Tcl_Obj *intObj = Tcl_NewStringObj(word, numBytes); Tcl_IncrRefCount(intObj); code = Tcl_GetIntFromObj(NULL, intObj, &immValue); Tcl_DecrRefCount(intObj); if ((code == TCL_OK) && (-127 <= immValue) && (immValue <= 127)) { haveImmValue = 1; } } if (!haveImmValue) { TclEmitPush( TclRegisterNewLiteral(envPtr, word, numBytes), envPtr); } } else { SetLineInformation (2); code = TclCompileTokens(interp, incrTokenPtr+1, incrTokenPtr->numComponents, envPtr); if (code != TCL_OK) { goto done; } } } else { /* no incr amount given so use 1 */ haveImmValue = 1; } /* * Emit the instruction to increment the variable. */ if (simpleVarName) { if (isScalar) { if (localIndex >= 0) { if (haveImmValue) { TclEmitInstInt1(INST_INCR_SCALAR1_IMM, localIndex, envPtr); TclEmitInt1(immValue, envPtr); } else { TclEmitInstInt1(INST_INCR_SCALAR1, localIndex, envPtr); } } else { if (haveImmValue) { TclEmitInstInt1(INST_INCR_SCALAR_STK_IMM, immValue, envPtr); } else { TclEmitOpcode(INST_INCR_SCALAR_STK, envPtr); } } } else { if (localIndex >= 0) { if (haveImmValue) { TclEmitInstInt1(INST_INCR_ARRAY1_IMM, localIndex, envPtr); TclEmitInt1(immValue, envPtr); } else { TclEmitInstInt1(INST_INCR_ARRAY1, localIndex, envPtr); } } else { if (haveImmValue) { TclEmitInstInt1(INST_INCR_ARRAY_STK_IMM, immValue, envPtr); } else { TclEmitOpcode(INST_INCR_ARRAY_STK, envPtr); } } } } else { /* non-simple variable name */ if (haveImmValue) { TclEmitInstInt1(INST_INCR_STK_IMM, immValue, envPtr); } else { TclEmitOpcode(INST_INCR_STK, envPtr); } } done: return code; } /* *---------------------------------------------------------------------- * * TclCompileLappendCmd -- * * Procedure called to compile the "lappend" command. * * Results: * The return value is a standard Tcl result, which is normally TCL_OK * unless there was an error while parsing string. If an error occurs * then the interpreter's result contains a standard error message. If * compilation fails because the command requires a second level of * substitutions, TCL_OUT_LINE_COMPILE is returned indicating that the * command should be compiled "out of line" by emitting code to * invoke its command procedure (Tcl_LappendObjCmd) at runtime. * * Side effects: * Instructions are added to envPtr to execute the "lappend" command * at runtime. * *---------------------------------------------------------------------- */ int TclCompileLappendCmd(interp, parsePtr, envPtr) Tcl_Interp *interp; /* Used for error reporting. */ Tcl_Parse *parsePtr; /* Points to a parse structure for the * command created by Tcl_ParseCommand. */ CompileEnv *envPtr; /* Holds resulting instructions. */ { Tcl_Token *varTokenPtr, *valueTokenPtr; int simpleVarName, isScalar, localIndex, numWords; int code = TCL_OK; DefineLineInformation; /* * If we're not in a procedure, don't compile. */ if (envPtr->procPtr == NULL) { return TCL_OUT_LINE_COMPILE; } numWords = parsePtr->numWords; if (numWords == 1) { Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "wrong # args: should be \"lappend varName ?value value ...?\"", -1); return TCL_ERROR; } if (numWords != 3) { /* * LAPPEND instructions currently only handle one value appends */ return TCL_OUT_LINE_COMPILE; } /* * Decide if we can use a frame slot for the var/array name or if we * need to emit code to compute and push the name at runtime. We use a * frame slot (entry in the array of local vars) if we are compiling a * procedure body and if the name is simple text that does not include * namespace qualifiers. */ varTokenPtr = parsePtr->tokenPtr + (parsePtr->tokenPtr->numComponents + 1); code = TclPushVarNameWord(interp, varTokenPtr, envPtr, TCL_CREATE_VAR, &localIndex, &simpleVarName, &isScalar, 1); if (code != TCL_OK) { goto done; } /* * If we are doing an assignment, push the new value. * In the no values case, create an empty object. */ if (numWords > 2) { valueTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1); if (valueTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) { TclEmitPush(TclRegisterNewLiteral(envPtr, valueTokenPtr[1].start, valueTokenPtr[1].size), envPtr); } else { SetLineInformation (2); code = TclCompileTokens(interp, valueTokenPtr+1, valueTokenPtr->numComponents, envPtr); if (code != TCL_OK) { goto done; } } } /* * Emit instructions to set/get the variable. */ /* * The *_STK opcodes should be refactored to make better use of existing * LOAD/STORE instructions. */ if (simpleVarName) { if (isScalar) { if (localIndex >= 0) { if (localIndex <= 255) { TclEmitInstInt1(INST_LAPPEND_SCALAR1, localIndex, envPtr); } else { TclEmitInstInt4(INST_LAPPEND_SCALAR4, localIndex, envPtr); } } else { TclEmitOpcode(INST_LAPPEND_STK, envPtr); } } else { if (localIndex >= 0) { if (localIndex <= 255) { TclEmitInstInt1(INST_LAPPEND_ARRAY1, localIndex, envPtr); } else { TclEmitInstInt4(INST_LAPPEND_ARRAY4, localIndex, envPtr); } } else { TclEmitOpcode(INST_LAPPEND_ARRAY_STK, envPtr); } } } else { TclEmitOpcode(INST_LAPPEND_STK, envPtr); } done: return code; } /* *---------------------------------------------------------------------- * * TclCompileLindexCmd -- * * Procedure called to compile the "lindex" command. * * Results: * The return value is a standard Tcl result, which is TCL_OK if the * compilation was successful. If the command cannot be byte-compiled, * TCL_OUT_LINE_COMPILE is returned. If an error occurs then the * interpreter's result contains an error message, and TCL_ERROR is * returned. * * Side effects: * Instructions are added to envPtr to execute the "lindex" command * at runtime. * *---------------------------------------------------------------------- */ int TclCompileLindexCmd(interp, parsePtr, envPtr) Tcl_Interp *interp; /* Used for error reporting. */ Tcl_Parse *parsePtr; /* Points to a parse structure for the * command created by Tcl_ParseCommand. */ CompileEnv *envPtr; /* Holds resulting instructions. */ { Tcl_Token *varTokenPtr; int code, i; int numWords; DefineLineInformation; numWords = parsePtr->numWords; /* * Quit if too few args */ if ( numWords <= 1 ) { return TCL_OUT_LINE_COMPILE; } varTokenPtr = parsePtr->tokenPtr + (parsePtr->tokenPtr->numComponents + 1); /* * Push the operands onto the stack. */ for ( i = 1 ; i < numWords ; i++ ) { if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) { TclEmitPush( TclRegisterNewLiteral( envPtr, varTokenPtr[1].start, varTokenPtr[1].size), envPtr); } else { SetLineInformation (i); code = TclCompileTokens(interp, varTokenPtr+1, varTokenPtr->numComponents, envPtr); if (code != TCL_OK) { return code; } } varTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1); } /* * Emit INST_LIST_INDEX if objc==3, or INST_LIST_INDEX_MULTI * if there are multiple index args. */ if ( numWords == 3 ) { TclEmitOpcode( INST_LIST_INDEX, envPtr ); } else { TclEmitInstInt4( INST_LIST_INDEX_MULTI, numWords-1, envPtr ); } return TCL_OK; } /* *---------------------------------------------------------------------- * * TclCompileListCmd -- * * Procedure called to compile the "list" command. * * Results: * The return value is a standard Tcl result, which is normally TCL_OK * unless there was an error while parsing string. If an error occurs * then the interpreter's result contains a standard error message. If * compilation fails because the command requires a second level of * substitutions, TCL_OUT_LINE_COMPILE is returned indicating that the * command should be compiled "out of line" by emitting code to * invoke its command procedure (Tcl_ListObjCmd) at runtime. * * Side effects: * Instructions are added to envPtr to execute the "list" command * at runtime. * *---------------------------------------------------------------------- */ int TclCompileListCmd(interp, parsePtr, envPtr) Tcl_Interp *interp; /* Used for error reporting. */ Tcl_Parse *parsePtr; /* Points to a parse structure for the * command created by Tcl_ParseCommand. */ CompileEnv *envPtr; /* Holds resulting instructions. */ { DefineLineInformation; /* * If we're not in a procedure, don't compile. */ if (envPtr->procPtr == NULL) { return TCL_OUT_LINE_COMPILE; } if (parsePtr->numWords == 1) { /* * Empty args case */ TclEmitPush(TclRegisterNewLiteral(envPtr, "", 0), envPtr); } else { /* * Push the all values onto the stack. */ Tcl_Token *valueTokenPtr; int i, code, numWords; numWords = parsePtr->numWords; valueTokenPtr = parsePtr->tokenPtr + (parsePtr->tokenPtr->numComponents + 1); for (i = 1; i < numWords; i++) { if (valueTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) { TclEmitPush(TclRegisterNewLiteral(envPtr, valueTokenPtr[1].start, valueTokenPtr[1].size), envPtr); } else { SetLineInformation (i); code = TclCompileTokens(interp, valueTokenPtr+1, valueTokenPtr->numComponents, envPtr); if (code != TCL_OK) { return code; } } valueTokenPtr = valueTokenPtr + (valueTokenPtr->numComponents + 1); } TclEmitInstInt4(INST_LIST, numWords - 1, envPtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * TclCompileLlengthCmd -- * * Procedure called to compile the "llength" command. * * Results: * The return value is a standard Tcl result, which is TCL_OK if the * compilation was successful. If the command cannot be byte-compiled, * TCL_OUT_LINE_COMPILE is returned. If an error occurs then the * interpreter's result contains an error message, and TCL_ERROR is * returned. * * Side effects: * Instructions are added to envPtr to execute the "llength" command * at runtime. * *---------------------------------------------------------------------- */ int TclCompileLlengthCmd(interp, parsePtr, envPtr) Tcl_Interp *interp; /* Used for error reporting. */ Tcl_Parse *parsePtr; /* Points to a parse structure for the * command created by Tcl_ParseCommand. */ CompileEnv *envPtr; /* Holds resulting instructions. */ { Tcl_Token *varTokenPtr; int code; DefineLineInformation; if (parsePtr->numWords != 2) { Tcl_SetResult(interp, "wrong # args: should be \"llength list\"", TCL_STATIC); return TCL_ERROR; } varTokenPtr = parsePtr->tokenPtr + (parsePtr->tokenPtr->numComponents + 1); if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) { /* * We could simply count the number of elements here and push * that value, but that is too rare a case to waste the code space. */ TclEmitPush(TclRegisterNewLiteral(envPtr, varTokenPtr[1].start, varTokenPtr[1].size), envPtr); } else { SetLineInformation (1); code = TclCompileTokens(interp, varTokenPtr+1, varTokenPtr->numComponents, envPtr); if (code != TCL_OK) { return code; } } TclEmitOpcode(INST_LIST_LENGTH, envPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * TclCompileLsetCmd -- * * Procedure called to compile the "lset" command. * * Results: * The return value is a standard Tcl result, which is TCL_OK if * the compilation was successful. If the "lset" command is too * complex for this function, then TCL_OUT_LINE_COMPILE is returned, * indicating that the command should be compiled "out of line" * (that is, not byte-compiled). If an error occurs, TCL_ERROR is * returned, and the interpreter result contains an error message. * * Side effects: * Instructions are added to envPtr to execute the "lset" command * at runtime. * * The general template for execution of the "lset" command is: * (1) Instructions to push the variable name, unless the * variable is local to the stack frame. * (2) If the variable is an array element, instructions * to push the array element name. * (3) Instructions to push each of zero or more "index" arguments * to the stack, followed with the "newValue" element. * (4) Instructions to duplicate the variable name and/or array * element name onto the top of the stack, if either was * pushed at steps (1) and (2). * (5) The appropriate INST_LOAD_* instruction to place the * original value of the list variable at top of stack. * (6) At this point, the stack contains: * varName? arrayElementName? index1 index2 ... newValue oldList * The compiler emits one of INST_LSET_FLAT or INST_LSET_LIST * according as whether there is exactly one index element (LIST) * or either zero or else two or more (FLAT). This instruction * removes everything from the stack except for the two names * and pushes the new value of the variable. * (7) Finally, INST_STORE_* stores the new value in the variable * and cleans up the stack. * *---------------------------------------------------------------------- */ int TclCompileLsetCmd( interp, parsePtr, envPtr ) Tcl_Interp* interp; /* Tcl interpreter for error reporting */ Tcl_Parse* parsePtr; /* Points to a parse structure for * the command */ CompileEnv* envPtr; /* Holds the resulting instructions */ { int tempDepth; /* Depth used for emitting one part * of the code burst. */ Tcl_Token* varTokenPtr; /* Pointer to the Tcl_Token representing * the parse of the variable name */ int result; /* Status return from library calls */ int localIndex; /* Index of var in local var table */ int simpleVarName; /* Flag == 1 if var name is simple */ int isScalar; /* Flag == 1 if scalar, 0 if array */ int i; DefineLineInformation; /* Check argument count */ if ( parsePtr->numWords < 3 ) { /* Fail at run time, not in compilation */ return TCL_OUT_LINE_COMPILE; } /* * Decide if we can use a frame slot for the var/array name or if we * need to emit code to compute and push the name at runtime. We use a * frame slot (entry in the array of local vars) if we are compiling a * procedure body and if the name is simple text that does not include * namespace qualifiers. */ varTokenPtr = parsePtr->tokenPtr + (parsePtr->tokenPtr->numComponents + 1); result = TclPushVarNameWord( interp, varTokenPtr, envPtr, TCL_CREATE_VAR, &localIndex, &simpleVarName, &isScalar, 1); if (result != TCL_OK) { return result; } /* Push the "index" args and the new element value. */ for ( i = 2; i < parsePtr->numWords; ++i ) { /* Advance to next arg */ varTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1); /* Push an arg */ if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) { TclEmitPush(TclRegisterNewLiteral( envPtr, varTokenPtr[1].start, varTokenPtr[1].size), envPtr); } else { SetLineInformation (i); result = TclCompileTokens(interp, varTokenPtr+1, varTokenPtr->numComponents, envPtr); if ( result != TCL_OK ) { return result; } } } /* * Duplicate the variable name if it's been pushed. */ if ( !simpleVarName || localIndex < 0 ) { if ( !simpleVarName || isScalar ) { tempDepth = parsePtr->numWords - 2; } else { tempDepth = parsePtr->numWords - 1; } TclEmitInstInt4( INST_OVER, tempDepth, envPtr ); } /* * Duplicate an array index if one's been pushed */ if ( simpleVarName && !isScalar ) { if ( localIndex < 0 ) { tempDepth = parsePtr->numWords - 1; } else { tempDepth = parsePtr->numWords - 2; } TclEmitInstInt4( INST_OVER, tempDepth, envPtr ); } /* * Emit code to load the variable's value. */ if ( !simpleVarName ) { TclEmitOpcode( INST_LOAD_STK, envPtr ); } else if ( isScalar ) { if ( localIndex < 0 ) { TclEmitOpcode( INST_LOAD_SCALAR_STK, envPtr ); } else if ( localIndex < 0x100 ) { TclEmitInstInt1( INST_LOAD_SCALAR1, localIndex, envPtr ); } else { TclEmitInstInt4( INST_LOAD_SCALAR4, localIndex, envPtr ); } } else { if ( localIndex < 0 ) { TclEmitOpcode( INST_LOAD_ARRAY_STK, envPtr ); } else if ( localIndex < 0x100 ) { TclEmitInstInt1( INST_LOAD_ARRAY1, localIndex, envPtr ); } else { TclEmitInstInt4( INST_LOAD_ARRAY4, localIndex, envPtr ); } } /* * Emit the correct variety of 'lset' instruction */ if ( parsePtr->numWords == 4 ) { TclEmitOpcode( INST_LSET_LIST, envPtr ); } else { TclEmitInstInt4( INST_LSET_FLAT, (parsePtr->numWords - 1), envPtr ); } /* * Emit code to put the value back in the variable */ if ( !simpleVarName ) { TclEmitOpcode( INST_STORE_STK, envPtr ); } else if ( isScalar ) { if ( localIndex < 0 ) { TclEmitOpcode( INST_STORE_SCALAR_STK, envPtr ); } else if ( localIndex < 0x100 ) { TclEmitInstInt1( INST_STORE_SCALAR1, localIndex, envPtr ); } else { TclEmitInstInt4( INST_STORE_SCALAR4, localIndex, envPtr ); } } else { if ( localIndex < 0 ) { TclEmitOpcode( INST_STORE_ARRAY_STK, envPtr ); } else if ( localIndex < 0x100 ) { TclEmitInstInt1( INST_STORE_ARRAY1, localIndex, envPtr ); } else { TclEmitInstInt4( INST_STORE_ARRAY4, localIndex, envPtr ); } } return TCL_OK; } /* *---------------------------------------------------------------------- * * TclCompileRegexpCmd -- * * Procedure called to compile the "regexp" command. * * Results: * The return value is a standard Tcl result, which is TCL_OK if * the compilation was successful. If the "regexp" command is too * complex for this function, then TCL_OUT_LINE_COMPILE is returned, * indicating that the command should be compiled "out of line" * (that is, not byte-compiled). If an error occurs, TCL_ERROR is * returned, and the interpreter result contains an error message. * * Side effects: * Instructions are added to envPtr to execute the "regexp" command * at runtime. * *---------------------------------------------------------------------- */ int TclCompileRegexpCmd(interp, parsePtr, envPtr) Tcl_Interp* interp; /* Tcl interpreter for error reporting */ Tcl_Parse* parsePtr; /* Points to a parse structure for * the command */ CompileEnv* envPtr; /* Holds the resulting instructions */ { Tcl_Token *varTokenPtr; /* Pointer to the Tcl_Token representing * the parse of the RE or string */ int i, len, code, nocase, anchorLeft, anchorRight, start; char *str; DefineLineInformation; /* * We are only interested in compiling simple regexp cases. * Currently supported compile cases are: * regexp ?-nocase? ?--? staticString $var * regexp ?-nocase? ?--? {^staticString$} $var */ if (parsePtr->numWords < 3) { return TCL_OUT_LINE_COMPILE; } nocase = 0; varTokenPtr = parsePtr->tokenPtr; /* * We only look for -nocase and -- as options. Everything else * gets pushed to runtime execution. This is different than regexp's * runtime option handling, but satisfies our stricter needs. */ for (i = 1; i < parsePtr->numWords - 2; i++) { varTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1); if (varTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { /* Not a simple string - punt to runtime. */ return TCL_OUT_LINE_COMPILE; } str = (char *) varTokenPtr[1].start; len = varTokenPtr[1].size; if ((len == 2) && (str[0] == '-') && (str[1] == '-')) { i++; break; } else if ((len > 1) && (strncmp(str, "-nocase", (unsigned) len) == 0)) { nocase = 1; } else { /* Not an option we recognize. */ return TCL_OUT_LINE_COMPILE; } } if ((parsePtr->numWords - i) != 2) { /* We don't support capturing to variables */ return TCL_OUT_LINE_COMPILE; } /* * Get the regexp string. If it is not a simple string, punt to runtime. * If it has a '-', it could be an incorrectly formed regexp command. */ varTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1); str = (char *) varTokenPtr[1].start; len = varTokenPtr[1].size; if ((varTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) || (*str == '-')) { return TCL_OUT_LINE_COMPILE; } if (len == 0) { /* * The semantics of regexp are always match on re == "". */ TclEmitPush(TclRegisterNewLiteral(envPtr, "1", 1), envPtr); return TCL_OK; } /* * Make a copy of the string that is null-terminated for checks which * require such. */ str = (char *) ckalloc((unsigned) len + 1); strncpy(str, varTokenPtr[1].start, (size_t) len); str[len] = '\0'; start = 0; /* * Check for anchored REs (ie ^foo$), so we can use string equal if * possible. Do not alter the start of str so we can free it correctly. */ if (str[0] == '^') { start++; anchorLeft = 1; } else { anchorLeft = 0; } if ((str[len-1] == '$') && ((len == 1) || (str[len-2] != '\\'))) { anchorRight = 1; str[--len] = '\0'; } else { anchorRight = 0; } /* * On the first (pattern) arg, check to see if any RE special characters * are in the word. If not, this is the same as 'string equal'. */ if ((len > (1+start)) && (str[start] == '.') && (str[start+1] == '*')) { start += 2; anchorLeft = 0; } if ((len > (2+start)) && (str[len-3] != '\\') && (str[len-2] == '.') && (str[len-1] == '*')) { len -= 2; str[len] = '\0'; anchorRight = 0; } /* * Don't do anything with REs with other special chars. Also check if * this is a bad RE (do this at the end because it can be expensive). * If so, let it complain at runtime. */ if ((strpbrk(str + start, "*+?{}()[].\\|^$") != NULL) || (Tcl_RegExpCompile(NULL, str) == NULL)) { ckfree((char *) str); return TCL_OUT_LINE_COMPILE; } if (anchorLeft && anchorRight) { TclEmitPush(TclRegisterNewLiteral(envPtr, str+start, len-start), envPtr); } else { /* * This needs to find the substring anywhere in the string, so * use string match and *foo*, with appropriate anchoring. */ char *newStr = ckalloc((unsigned) len + 3); len -= start; if (anchorLeft) { strncpy(newStr, str + start, (size_t) len); } else { newStr[0] = '*'; strncpy(newStr + 1, str + start, (size_t) len++); } if (!anchorRight) { newStr[len++] = '*'; } newStr[len] = '\0'; TclEmitPush(TclRegisterNewLiteral(envPtr, newStr, len), envPtr); ckfree((char *) newStr); } ckfree((char *) str); /* * Push the string arg */ varTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1); if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) { TclEmitPush(TclRegisterNewLiteral(envPtr, varTokenPtr[1].start, varTokenPtr[1].size), envPtr); } else { SetLineInformation (parsePtr->numWords-1); code = TclCompileTokens(interp, varTokenPtr+1, varTokenPtr->numComponents, envPtr); if (code != TCL_OK) { return code; } } if (anchorLeft && anchorRight && !nocase) { TclEmitOpcode(INST_STR_EQ, envPtr); } else { TclEmitInstInt1(INST_STR_MATCH, nocase, envPtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * TclCompileReturnCmd -- * * Procedure called to compile the "return" command. * * Results: * The return value is a standard Tcl result, which is TCL_OK if the * compilation was successful. If the particular return command is * too complex for this function (ie, return with any flags like "-code" * or "-errorinfo"), TCL_OUT_LINE_COMPILE is returned, indicating that * the command should be compiled "out of line" (eg, not byte compiled). * If an error occurs then the interpreter's result contains a standard * error message. * * Side effects: * Instructions are added to envPtr to execute the "return" command * at runtime. * *---------------------------------------------------------------------- */ int TclCompileReturnCmd(interp, parsePtr, envPtr) Tcl_Interp *interp; /* Used for error reporting. */ Tcl_Parse *parsePtr; /* Points to a parse structure for the * command created by Tcl_ParseCommand. */ CompileEnv *envPtr; /* Holds resulting instructions. */ { Tcl_Token *varTokenPtr; int code; int index = envPtr->exceptArrayNext - 1; DefineLineInformation; /* * If we're not in a procedure, don't compile. */ if (envPtr->procPtr == NULL) { return TCL_OUT_LINE_COMPILE; } /* * Look back through the ExceptionRanges of the current CompileEnv, * from exceptArrayPtr[(exceptArrayNext - 1)] down to * exceptArrayPtr[0] to see if any of them is an enclosing [catch]. * If there's an enclosing [catch], don't compile. */ while (index >= 0) { ExceptionRange range = envPtr->exceptArrayPtr[index]; if ((range.type == CATCH_EXCEPTION_RANGE) && (range.catchOffset == -1)) { return TCL_OUT_LINE_COMPILE; } index--; } switch (parsePtr->numWords) { case 1: { /* * Simple case: [return] * Just push the literal string "". */ TclEmitPush(TclRegisterNewLiteral(envPtr, "", 0), envPtr); break; } case 2: { /* * More complex cases: * [return "foo"] * [return $value] * [return [otherCmd]] */ varTokenPtr = parsePtr->tokenPtr + (parsePtr->tokenPtr->numComponents + 1); if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) { /* * [return "foo"] case: the parse token is a simple word, * so just push it. */ TclEmitPush(TclRegisterNewLiteral(envPtr, varTokenPtr[1].start, varTokenPtr[1].size), envPtr); } else { /* * Parse token is more complex, so compile it; this handles the * variable reference and nested command cases. If the * parse token can be byte-compiled, then this instance of * "return" will be byte-compiled; otherwise it will be * out line compiled. */ SetLineInformation (1); code = TclCompileTokens(interp, varTokenPtr+1, varTokenPtr->numComponents, envPtr); if (code != TCL_OK) { return code; } } break; } default: { /* * Most complex return cases: everything else, including * [return -code error], etc. */ return TCL_OUT_LINE_COMPILE; } } /* * The INST_DONE opcode actually causes the branching out of the * subroutine, and takes the top stack item as the return result * (which is why we pushed the value above). */ TclEmitOpcode(INST_DONE, envPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * TclCompileSetCmd -- * * Procedure called to compile the "set" command. * * Results: * The return value is a standard Tcl result, which is normally TCL_OK * unless there was an error while parsing string. If an error occurs * then the interpreter's result contains a standard error message. If * compilation fails because the set command requires a second level of * substitutions, TCL_OUT_LINE_COMPILE is returned indicating that the * set command should be compiled "out of line" by emitting code to * invoke its command procedure (Tcl_SetCmd) at runtime. * * Side effects: * Instructions are added to envPtr to execute the "set" command * at runtime. * *---------------------------------------------------------------------- */ int TclCompileSetCmd(interp, parsePtr, envPtr) Tcl_Interp *interp; /* Used for error reporting. */ Tcl_Parse *parsePtr; /* Points to a parse structure for the * command created by Tcl_ParseCommand. */ CompileEnv *envPtr; /* Holds resulting instructions. */ { Tcl_Token *varTokenPtr, *valueTokenPtr; int isAssignment, isScalar, simpleVarName, localIndex, numWords; int code = TCL_OK; DefineLineInformation; numWords = parsePtr->numWords; if ((numWords != 2) && (numWords != 3)) { Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "wrong # args: should be \"set varName ?newValue?\"", -1); return TCL_ERROR; } isAssignment = (numWords == 3); /* * Decide if we can use a frame slot for the var/array name or if we * need to emit code to compute and push the name at runtime. We use a * frame slot (entry in the array of local vars) if we are compiling a * procedure body and if the name is simple text that does not include * namespace qualifiers. */ varTokenPtr = parsePtr->tokenPtr + (parsePtr->tokenPtr->numComponents + 1); code = TclPushVarNameWord(interp, varTokenPtr, envPtr, TCL_CREATE_VAR, &localIndex, &simpleVarName, &isScalar, 1); if (code != TCL_OK) { goto done; } /* * If we are doing an assignment, push the new value. */ if (isAssignment) { valueTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1); if (valueTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) { TclEmitPush(TclRegisterNewLiteral(envPtr, valueTokenPtr[1].start, valueTokenPtr[1].size), envPtr); } else { SetLineInformation (2); code = TclCompileTokens(interp, valueTokenPtr+1, valueTokenPtr->numComponents, envPtr); if (code != TCL_OK) { goto done; } } } /* * Emit instructions to set/get the variable. */ if (simpleVarName) { if (isScalar) { if (localIndex >= 0) { if (localIndex <= 255) { TclEmitInstInt1((isAssignment? INST_STORE_SCALAR1 : INST_LOAD_SCALAR1), localIndex, envPtr); } else { TclEmitInstInt4((isAssignment? INST_STORE_SCALAR4 : INST_LOAD_SCALAR4), localIndex, envPtr); } } else { TclEmitOpcode((isAssignment? INST_STORE_SCALAR_STK : INST_LOAD_SCALAR_STK), envPtr); } } else { if (localIndex >= 0) { if (localIndex <= 255) { TclEmitInstInt1((isAssignment? INST_STORE_ARRAY1 : INST_LOAD_ARRAY1), localIndex, envPtr); } else { TclEmitInstInt4((isAssignment? INST_STORE_ARRAY4 : INST_LOAD_ARRAY4), localIndex, envPtr); } } else { TclEmitOpcode((isAssignment? INST_STORE_ARRAY_STK : INST_LOAD_ARRAY_STK), envPtr); } } } else { TclEmitOpcode((isAssignment? INST_STORE_STK : INST_LOAD_STK), envPtr); } done: return code; } /* *---------------------------------------------------------------------- * * TclCompileStringCmd -- * * Procedure called to compile the "string" command. * * Results: * The return value is a standard Tcl result, which is TCL_OK if the * compilation was successful. If the command cannot be byte-compiled, * TCL_OUT_LINE_COMPILE is returned. If an error occurs then the * interpreter's result contains an error message, and TCL_ERROR is * returned. * * Side effects: * Instructions are added to envPtr to execute the "string" command * at runtime. * *---------------------------------------------------------------------- */ int TclCompileStringCmd(interp, parsePtr, envPtr) Tcl_Interp *interp; /* Used for error reporting. */ Tcl_Parse *parsePtr; /* Points to a parse structure for the * command created by Tcl_ParseCommand. */ CompileEnv *envPtr; /* Holds resulting instructions. */ { Tcl_Token *opTokenPtr, *varTokenPtr; Tcl_Obj *opObj; int index; int code; static CONST char *options[] = { "bytelength", "compare", "equal", "first", "index", "is", "last", "length", "map", "match", "range", "repeat", "replace", "tolower", "toupper", "totitle", "trim", "trimleft", "trimright", "wordend", "wordstart", (char *) NULL }; enum options { STR_BYTELENGTH, STR_COMPARE, STR_EQUAL, STR_FIRST, STR_INDEX, STR_IS, STR_LAST, STR_LENGTH, STR_MAP, STR_MATCH, STR_RANGE, STR_REPEAT, STR_REPLACE, STR_TOLOWER, STR_TOUPPER, STR_TOTITLE, STR_TRIM, STR_TRIMLEFT, STR_TRIMRIGHT, STR_WORDEND, STR_WORDSTART }; DefineLineInformation; if (parsePtr->numWords < 2) { /* Fail at run time, not in compilation */ return TCL_OUT_LINE_COMPILE; } opTokenPtr = parsePtr->tokenPtr + (parsePtr->tokenPtr->numComponents + 1); opObj = Tcl_NewStringObj(opTokenPtr->start, opTokenPtr->size); if (Tcl_GetIndexFromObj(interp, opObj, options, "option", 0, &index) != TCL_OK) { Tcl_DecrRefCount(opObj); Tcl_ResetResult(interp); return TCL_OUT_LINE_COMPILE; } Tcl_DecrRefCount(opObj); varTokenPtr = opTokenPtr + (opTokenPtr->numComponents + 1); switch ((enum options) index) { case STR_BYTELENGTH: case STR_FIRST: case STR_IS: case STR_LAST: case STR_MAP: case STR_RANGE: case STR_REPEAT: case STR_REPLACE: case STR_TOLOWER: case STR_TOUPPER: case STR_TOTITLE: case STR_TRIM: case STR_TRIMLEFT: case STR_TRIMRIGHT: case STR_WORDEND: case STR_WORDSTART: /* * All other cases: compile out of line. */ return TCL_OUT_LINE_COMPILE; case STR_COMPARE: case STR_EQUAL: { int i; /* * If there are any flags to the command, we can't byte compile it * because the INST_STR_EQ bytecode doesn't support flags. */ if (parsePtr->numWords != 4) { return TCL_OUT_LINE_COMPILE; } /* * Push the two operands onto the stack. */ for (i = 0; i < 2; i++) { if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) { TclEmitPush(TclRegisterNewLiteral(envPtr, varTokenPtr[1].start, varTokenPtr[1].size), envPtr); } else { SetLineInformation (i); code = TclCompileTokens(interp, varTokenPtr+1, varTokenPtr->numComponents, envPtr); if (code != TCL_OK) { return code; } } varTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1); } TclEmitOpcode(((((enum options) index) == STR_COMPARE) ? INST_STR_CMP : INST_STR_EQ), envPtr); return TCL_OK; } case STR_INDEX: { int i; if (parsePtr->numWords != 4) { /* Fail at run time, not in compilation */ return TCL_OUT_LINE_COMPILE; } /* * Push the two operands onto the stack. */ for (i = 0; i < 2; i++) { if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) { TclEmitPush(TclRegisterNewLiteral(envPtr, varTokenPtr[1].start, varTokenPtr[1].size), envPtr); } else { SetLineInformation (i); code = TclCompileTokens(interp, varTokenPtr+1, varTokenPtr->numComponents, envPtr); if (code != TCL_OK) { return code; } } varTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1); } TclEmitOpcode(INST_STR_INDEX, envPtr); return TCL_OK; } case STR_LENGTH: { if (parsePtr->numWords != 3) { /* Fail at run time, not in compilation */ return TCL_OUT_LINE_COMPILE; } if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) { /* * Here someone is asking for the length of a static string. * Just push the actual character (not byte) length. */ char buf[TCL_INTEGER_SPACE]; int len = Tcl_NumUtfChars(varTokenPtr[1].start, varTokenPtr[1].size); len = sprintf(buf, "%d", len); TclEmitPush(TclRegisterNewLiteral(envPtr, buf, len), envPtr); return TCL_OK; } else { SetLineInformation (2); code = TclCompileTokens(interp, varTokenPtr+1, varTokenPtr->numComponents, envPtr); if (code != TCL_OK) { return code; } } TclEmitOpcode(INST_STR_LEN, envPtr); return TCL_OK; } case STR_MATCH: { int i, length, exactMatch = 0, nocase = 0; CONST char *str; if (parsePtr->numWords < 4 || parsePtr->numWords > 5) { /* Fail at run time, not in compilation */ return TCL_OUT_LINE_COMPILE; } if (parsePtr->numWords == 5) { if (varTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { return TCL_OUT_LINE_COMPILE; } str = varTokenPtr[1].start; length = varTokenPtr[1].size; if ((length > 1) && strncmp(str, "-nocase", (size_t) length) == 0) { nocase = 1; } else { /* Fail at run time, not in compilation */ return TCL_OUT_LINE_COMPILE; } varTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1); } for (i = 0; i < 2; i++) { if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) { str = varTokenPtr[1].start; length = varTokenPtr[1].size; if (!nocase && (i == 0)) { /* * On the first (pattern) arg, check to see if any * glob special characters are in the word '*[]?\\'. * If not, this is the same as 'string equal'. We * can use strpbrk here because the glob chars are all * in the ascii-7 range. If -nocase was specified, * we can't do this because INST_STR_EQ has no support * for nocase. */ Tcl_Obj *copy = Tcl_NewStringObj(str, length); Tcl_IncrRefCount(copy); exactMatch = (strpbrk(Tcl_GetString(copy), "*[]?\\") == NULL); Tcl_DecrRefCount(copy); } TclEmitPush( TclRegisterNewLiteral(envPtr, str, length), envPtr); } else { SetLineInformation (i); code = TclCompileTokens(interp, varTokenPtr+1, varTokenPtr->numComponents, envPtr); if (code != TCL_OK) { return code; } } varTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1); } if (exactMatch) { TclEmitOpcode(INST_STR_EQ, envPtr); } else { TclEmitInstInt1(INST_STR_MATCH, nocase, envPtr); } return TCL_OK; } } return TCL_OK; } /* *---------------------------------------------------------------------- * * TclCompileVariableCmd -- * * Procedure called to reserve the local variables for the * "variable" command. The command itself is *not* compiled. * * Results: * Always returns TCL_OUT_LINE_COMPILE. * * Side effects: * Indexed local variables are added to the environment. * *---------------------------------------------------------------------- */ int TclCompileVariableCmd(interp, parsePtr, envPtr) Tcl_Interp *interp; /* Used for error reporting. */ Tcl_Parse *parsePtr; /* Points to a parse structure for the * command created by Tcl_ParseCommand. */ CompileEnv *envPtr; /* Holds resulting instructions. */ { Tcl_Token *varTokenPtr; int i, numWords; CONST char *varName, *tail; if (envPtr->procPtr == NULL) { return TCL_OUT_LINE_COMPILE; } numWords = parsePtr->numWords; varTokenPtr = parsePtr->tokenPtr + (parsePtr->tokenPtr->numComponents + 1); for (i = 1; i < numWords; i += 2) { if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) { varName = varTokenPtr[1].start; tail = varName + varTokenPtr[1].size - 1; if ((*tail == ')') || (tail < varName)) continue; while ((tail > varName) && ((*tail != ':') || (*(tail-1) != ':'))) { tail--; } if ((*tail == ':') && (tail > varName)) { tail++; } (void) TclFindCompiledLocal(tail, (tail-varName+1), /*create*/ 1, /*flags*/ 0, envPtr->procPtr); varTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1); } } return TCL_OUT_LINE_COMPILE; } /* *---------------------------------------------------------------------- * * TclCompileWhileCmd -- * * Procedure called to compile the "while" command. * * Results: * The return value is a standard Tcl result, which is TCL_OK if * compilation was successful. If an error occurs then the * interpreter's result contains a standard error message and TCL_ERROR * is returned. If compilation failed because the command is too * complex for TclCompileWhileCmd, TCL_OUT_LINE_COMPILE is returned * indicating that the while command should be compiled "out of line" * by emitting code to invoke its command procedure at runtime. * * Side effects: * Instructions are added to envPtr to execute the "while" command * at runtime. * *---------------------------------------------------------------------- */ int TclCompileWhileCmd(interp, parsePtr, envPtr) Tcl_Interp *interp; /* Used for error reporting. */ Tcl_Parse *parsePtr; /* Points to a parse structure for the * command created by Tcl_ParseCommand. */ CompileEnv *envPtr; /* Holds resulting instructions. */ { Tcl_Token *testTokenPtr, *bodyTokenPtr; JumpFixup jumpEvalCondFixup; int testCodeOffset, bodyCodeOffset, jumpDist; int range, code; char buffer[32 + TCL_INTEGER_SPACE]; int savedStackDepth = envPtr->currStackDepth; int loopMayEnd = 1; /* This is set to 0 if it is recognized as * an infinite loop. */ Tcl_Obj *boolObj; int boolVal; DefineLineInformation; if (parsePtr->numWords != 3) { Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "wrong # args: should be \"while test command\"", -1); return TCL_ERROR; } /* * If the test expression requires substitutions, don't compile the * while command inline. E.g., the expression might cause the loop to * never execute or execute forever, as in "while "$x < 5" {}". * * Bail out also if the body expression requires substitutions * in order to insure correct behaviour [Bug 219166] */ testTokenPtr = parsePtr->tokenPtr + (parsePtr->tokenPtr->numComponents + 1); bodyTokenPtr = testTokenPtr + (testTokenPtr->numComponents + 1); if ((testTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) || (bodyTokenPtr->type != TCL_TOKEN_SIMPLE_WORD)) { return TCL_OUT_LINE_COMPILE; } /* * Find out if the condition is a constant. */ boolObj = Tcl_NewStringObj(testTokenPtr[1].start, testTokenPtr[1].size); Tcl_IncrRefCount(boolObj); code = Tcl_GetBooleanFromObj(NULL, boolObj, &boolVal); Tcl_DecrRefCount(boolObj); if (code == TCL_OK) { if (boolVal) { /* * it is an infinite loop */ loopMayEnd = 0; } else { /* * This is an empty loop: "while 0 {...}" or such. * Compile no bytecodes. */ goto pushResult; } } /* * Create a ExceptionRange record for the loop body. This is used to * implement break and continue. */ envPtr->exceptDepth++; envPtr->maxExceptDepth = TclMax(envPtr->exceptDepth, envPtr->maxExceptDepth); range = TclCreateExceptRange(LOOP_EXCEPTION_RANGE, envPtr); /* * Jump to the evaluation of the condition. This code uses the "loop * rotation" optimisation (which eliminates one branch from the loop). * "while cond body" produces then: * goto A * B: body : bodyCodeOffset * A: cond -> result : testCodeOffset, continueOffset * if (result) goto B * * The infinite loop "while 1 body" produces: * B: body : all three offsets here * goto B */ if (loopMayEnd) { TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &jumpEvalCondFixup); testCodeOffset = 0; /* avoid compiler warning */ } else { testCodeOffset = (envPtr->codeNext - envPtr->codeStart); } /* * Compile the loop body. */ SetLineInformation (2); bodyCodeOffset = (envPtr->codeNext - envPtr->codeStart); code = TclCompileCmdWord(interp, bodyTokenPtr+1, bodyTokenPtr->numComponents, envPtr); envPtr->currStackDepth = savedStackDepth + 1; if (code != TCL_OK) { if (code == TCL_ERROR) { sprintf(buffer, "\n (\"while\" body line %d)", interp->errorLine); Tcl_AddObjErrorInfo(interp, buffer, -1); } goto error; } envPtr->exceptArrayPtr[range].numCodeBytes = (envPtr->codeNext - envPtr->codeStart) - bodyCodeOffset; TclEmitOpcode(INST_POP, envPtr); /* * Compile the test expression then emit the conditional jump that * terminates the while. We already know it's a simple word. */ if (loopMayEnd) { testCodeOffset = (envPtr->codeNext - envPtr->codeStart); jumpDist = testCodeOffset - jumpEvalCondFixup.codeOffset; if (TclFixupForwardJump(envPtr, &jumpEvalCondFixup, jumpDist, 127)) { bodyCodeOffset += 3; testCodeOffset += 3; } envPtr->currStackDepth = savedStackDepth; SetLineInformation (1); code = TclCompileExprWords(interp, testTokenPtr, 1, envPtr); if (code != TCL_OK) { if (code == TCL_ERROR) { Tcl_AddObjErrorInfo(interp, "\n (\"while\" test expression)", -1); } goto error; } envPtr->currStackDepth = savedStackDepth + 1; jumpDist = (envPtr->codeNext - envPtr->codeStart) - bodyCodeOffset; if (jumpDist > 127) { TclEmitInstInt4(INST_JUMP_TRUE4, -jumpDist, envPtr); } else { TclEmitInstInt1(INST_JUMP_TRUE1, -jumpDist, envPtr); } } else { jumpDist = (envPtr->codeNext - envPtr->codeStart) - bodyCodeOffset; if (jumpDist > 127) { TclEmitInstInt4(INST_JUMP4, -jumpDist, envPtr); } else { TclEmitInstInt1(INST_JUMP1, -jumpDist, envPtr); } } /* * Set the loop's body, continue and break offsets. */ envPtr->exceptArrayPtr[range].continueOffset = testCodeOffset; envPtr->exceptArrayPtr[range].codeOffset = bodyCodeOffset; envPtr->exceptArrayPtr[range].breakOffset = (envPtr->codeNext - envPtr->codeStart); /* * The while command's result is an empty string. */ pushResult: envPtr->currStackDepth = savedStackDepth; TclEmitPush(TclRegisterNewLiteral(envPtr, "", 0), envPtr); envPtr->exceptDepth--; return TCL_OK; error: envPtr->exceptDepth--; return code; } /* *---------------------------------------------------------------------- * * TclPushVarName -- * * Procedure used in the compiling where pushing a variable name * is necessary (append, lappend, set). * * Results: * The return value is a standard Tcl result, which is normally TCL_OK * unless there was an error while parsing string. If an error occurs * then the interpreter's result contains a standard error message. * * Side effects: * Instructions are added to envPtr to execute the "set" command * at runtime. * *---------------------------------------------------------------------- */ static int TclPushVarName(interp, varTokenPtr, envPtr, flags, localIndexPtr, #ifndef TCL_TIP280 simpleVarNamePtr, isScalarPtr) #else simpleVarNamePtr, isScalarPtr, line, clNext) #endif Tcl_Interp *interp; /* Used for error reporting. */ Tcl_Token *varTokenPtr; /* Points to a variable token. */ CompileEnv *envPtr; /* Holds resulting instructions. */ int flags; /* takes TCL_CREATE_VAR or * TCL_NO_LARGE_INDEX */ int *localIndexPtr; /* must not be NULL */ int *simpleVarNamePtr; /* must not be NULL */ int *isScalarPtr; /* must not be NULL */ #ifdef TCL_TIP280 int line; /* line the token starts on */ int* clNext; #endif { register CONST char *p; CONST char *name, *elName; register int i, n; int nameChars, elNameChars, simpleVarName, localIndex; int code = TCL_OK; Tcl_Token *elemTokenPtr = NULL; int elemTokenCount = 0; int allocedTokens = 0; int removedParen = 0; /* * Decide if we can use a frame slot for the var/array name or if we * need to emit code to compute and push the name at runtime. We use a * frame slot (entry in the array of local vars) if we are compiling a * procedure body and if the name is simple text that does not include * namespace qualifiers. */ simpleVarName = 0; name = elName = NULL; nameChars = elNameChars = 0; localIndex = -1; /* * Check not only that the type is TCL_TOKEN_SIMPLE_WORD, but whether * curly braces surround the variable name. * This really matters for array elements to handle things like * set {x($foo)} 5 * which raises an undefined var error if we are not careful here. */ if ((varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) && (varTokenPtr->start[0] != '{')) { /* * A simple variable name. Divide it up into "name" and "elName" * strings. If it is not a local variable, look it up at runtime. */ simpleVarName = 1; name = varTokenPtr[1].start; nameChars = varTokenPtr[1].size; if ( *(name + nameChars - 1) == ')') { /* * last char is ')' => potential array reference. */ for (i = 0, p = name; i < nameChars; i++, p++) { if (*p == '(') { elName = p + 1; elNameChars = nameChars - i - 2; nameChars = i ; break; } } if ((elName != NULL) && elNameChars) { /* * An array element, the element name is a simple * string: assemble the corresponding token. */ elemTokenPtr = (Tcl_Token *) ckalloc(sizeof(Tcl_Token)); allocedTokens = 1; elemTokenPtr->type = TCL_TOKEN_TEXT; elemTokenPtr->start = elName; elemTokenPtr->size = elNameChars; elemTokenPtr->numComponents = 0; elemTokenCount = 1; } } } else if (((n = varTokenPtr->numComponents) > 1) && (varTokenPtr[1].type == TCL_TOKEN_TEXT) && (varTokenPtr[n].type == TCL_TOKEN_TEXT) && (varTokenPtr[n].start[varTokenPtr[n].size - 1] == ')')) { /* * Check for parentheses inside first token */ simpleVarName = 0; for (i = 0, p = varTokenPtr[1].start; i < varTokenPtr[1].size; i++, p++) { if (*p == '(') { simpleVarName = 1; break; } } if (simpleVarName) { int remainingChars; /* * Check the last token: if it is just ')', do not count * it. Otherwise, remove the ')' and flag so that it is * restored at the end. */ if (varTokenPtr[n].size == 1) { --n; } else { --varTokenPtr[n].size; removedParen = n; } name = varTokenPtr[1].start; nameChars = p - varTokenPtr[1].start; elName = p + 1; remainingChars = (varTokenPtr[2].start - p) - 1; elNameChars = (varTokenPtr[n].start - p) + varTokenPtr[n].size - 2; if (remainingChars) { /* * Make a first token with the extra characters in the first * token. */ elemTokenPtr = (Tcl_Token *) ckalloc(n * sizeof(Tcl_Token)); allocedTokens = 1; elemTokenPtr->type = TCL_TOKEN_TEXT; elemTokenPtr->start = elName; elemTokenPtr->size = remainingChars; elemTokenPtr->numComponents = 0; elemTokenCount = n; /* * Copy the remaining tokens. */ memcpy((void *) (elemTokenPtr+1), (void *) (&varTokenPtr[2]), ((n-1) * sizeof(Tcl_Token))); } else { /* * Use the already available tokens. */ elemTokenPtr = &varTokenPtr[2]; elemTokenCount = n - 1; } } } if (simpleVarName) { /* * See whether name has any namespace separators (::'s). */ int hasNsQualifiers = 0; for (i = 0, p = name; i < nameChars; i++, p++) { if ((*p == ':') && ((i+1) < nameChars) && (*(p+1) == ':')) { hasNsQualifiers = 1; break; } } /* * Look up the var name's index in the array of local vars in the * proc frame. If retrieving the var's value and it doesn't already * exist, push its name and look it up at runtime. */ if ((envPtr->procPtr != NULL) && !hasNsQualifiers) { localIndex = TclFindCompiledLocal(name, nameChars, /*create*/ (flags & TCL_CREATE_VAR), /*flags*/ ((elName==NULL)? VAR_SCALAR : VAR_ARRAY), envPtr->procPtr); if ((flags & TCL_NO_LARGE_INDEX) && (localIndex > 255)) { /* we'll push the name */ localIndex = -1; } } if (localIndex < 0) { TclEmitPush(TclRegisterNewLiteral(envPtr, name, nameChars), envPtr); } /* * Compile the element script, if any. */ if (elName != NULL) { if (elNameChars) { #ifdef TCL_TIP280 envPtr->line = line; envPtr->clNext = clNext; #endif code = TclCompileTokens(interp, elemTokenPtr, elemTokenCount, envPtr); if (code != TCL_OK) { goto done; } } else { TclEmitPush(TclRegisterNewLiteral(envPtr, "", 0), envPtr); } } } else { /* * The var name isn't simple: compile and push it. */ #ifdef TCL_TIP280 envPtr->line = line; envPtr->clNext = clNext; #endif code = TclCompileTokens(interp, varTokenPtr+1, varTokenPtr->numComponents, envPtr); if (code != TCL_OK) { goto done; } } done: if (removedParen) { ++varTokenPtr[removedParen].size; } if (allocedTokens) { ckfree((char *) elemTokenPtr); } *localIndexPtr = localIndex; *simpleVarNamePtr = simpleVarName; *isScalarPtr = (elName == NULL); return code; } /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ tcl8.4.20/generic/tclResolve.c0000644003604700454610000003320611737050674014625 0ustar dgp771div/* * tclResolve.c -- * * Contains hooks for customized command/variable name resolution * schemes. These hooks allow extensions like [incr Tcl] to add * their own name resolution rules to the Tcl language. Rules can * be applied to a particular namespace, to the interpreter as a * whole, or both. * * Copyright (c) 1998 Lucent Technologies, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" /* * Declarations for procedures local to this file: */ static void BumpCmdRefEpochs _ANSI_ARGS_((Namespace *nsPtr)); /* *---------------------------------------------------------------------- * * Tcl_AddInterpResolvers -- * * Adds a set of command/variable resolution procedures to an * interpreter. These procedures are consulted when commands * are resolved in Tcl_FindCommand, and when variables are * resolved in TclLookupVar and LookupCompiledLocal. Each * namespace may also have its own set of resolution procedures * which take precedence over those for the interpreter. * * When a name is resolved, it is handled as follows. First, * the name is passed to the resolution procedures for the * namespace. If not resolved, the name is passed to each of * the resolution procedures added to the interpreter. Finally, * if still not resolved, the name is handled using the default * Tcl rules for name resolution. * * Results: * Returns pointers to the current name resolution procedures * in the cmdProcPtr, varProcPtr and compiledVarProcPtr * arguments. * * Side effects: * If a compiledVarProc is specified, this procedure bumps the * compileEpoch for the interpreter, forcing all code to be * recompiled. If a cmdProc is specified, this procedure bumps * the cmdRefEpoch in all namespaces, forcing commands to be * resolved again using the new rules. * *---------------------------------------------------------------------- */ void Tcl_AddInterpResolvers(interp, name, cmdProc, varProc, compiledVarProc) Tcl_Interp *interp; /* Interpreter whose name resolution * rules are being modified. */ CONST char *name; /* Name of this resolution scheme. */ Tcl_ResolveCmdProc *cmdProc; /* New procedure for command * resolution */ Tcl_ResolveVarProc *varProc; /* Procedure for variable resolution * at runtime */ Tcl_ResolveCompiledVarProc *compiledVarProc; /* Procedure for variable resolution * at compile time. */ { Interp *iPtr = (Interp*)interp; ResolverScheme *resPtr; /* * Since we're adding a new name resolution scheme, we must force * all code to be recompiled to use the new scheme. If there * are new compiled variable resolution rules, bump the compiler * epoch to invalidate compiled code. If there are new command * resolution rules, bump the cmdRefEpoch in all namespaces. */ if (compiledVarProc) { iPtr->compileEpoch++; } if (cmdProc) { BumpCmdRefEpochs(iPtr->globalNsPtr); } /* * Look for an existing scheme with the given name. If found, * then replace its rules. */ for (resPtr = iPtr->resolverPtr; resPtr != NULL; resPtr = resPtr->nextPtr) { if (*name == *resPtr->name && strcmp(name, resPtr->name) == 0) { resPtr->cmdResProc = cmdProc; resPtr->varResProc = varProc; resPtr->compiledVarResProc = compiledVarProc; return; } } /* * Otherwise, this is a new scheme. Add it to the FRONT * of the linked list, so that it overrides existing schemes. */ resPtr = (ResolverScheme *) ckalloc(sizeof(ResolverScheme)); resPtr->name = (char*)ckalloc((unsigned)(strlen(name)+1)); strcpy(resPtr->name, name); resPtr->cmdResProc = cmdProc; resPtr->varResProc = varProc; resPtr->compiledVarResProc = compiledVarProc; resPtr->nextPtr = iPtr->resolverPtr; iPtr->resolverPtr = resPtr; } /* *---------------------------------------------------------------------- * * Tcl_GetInterpResolvers -- * * Looks for a set of command/variable resolution procedures with * the given name in an interpreter. These procedures are * registered by calling Tcl_AddInterpResolvers. * * Results: * If the name is recognized, this procedure returns non-zero, * along with pointers to the name resolution procedures in * the Tcl_ResolverInfo structure. If the name is not recognized, * this procedure returns zero. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_GetInterpResolvers(interp, name, resInfoPtr) Tcl_Interp *interp; /* Interpreter whose name resolution * rules are being queried. */ CONST char *name; /* Look for a scheme with this name. */ Tcl_ResolverInfo *resInfoPtr; /* Returns pointers to the procedures, * if found */ { Interp *iPtr = (Interp*)interp; ResolverScheme *resPtr; /* * Look for an existing scheme with the given name. If found, * then return pointers to its procedures. */ for (resPtr = iPtr->resolverPtr; resPtr != NULL; resPtr = resPtr->nextPtr) { if (*name == *resPtr->name && strcmp(name, resPtr->name) == 0) { resInfoPtr->cmdResProc = resPtr->cmdResProc; resInfoPtr->varResProc = resPtr->varResProc; resInfoPtr->compiledVarResProc = resPtr->compiledVarResProc; return 1; } } return 0; } /* *---------------------------------------------------------------------- * * Tcl_RemoveInterpResolvers -- * * Removes a set of command/variable resolution procedures * previously added by Tcl_AddInterpResolvers. The next time * a command/variable name is resolved, these procedures * won't be consulted. * * Results: * Returns non-zero if the name was recognized and the * resolution scheme was deleted. Returns zero otherwise. * * Side effects: * If a scheme with a compiledVarProc was deleted, this procedure * bumps the compileEpoch for the interpreter, forcing all code * to be recompiled. If a scheme with a cmdProc was deleted, * this procedure bumps the cmdRefEpoch in all namespaces, * forcing commands to be resolved again using the new rules. * *---------------------------------------------------------------------- */ int Tcl_RemoveInterpResolvers(interp, name) Tcl_Interp *interp; /* Interpreter whose name resolution * rules are being modified. */ CONST char *name; /* Name of the scheme to be removed. */ { Interp *iPtr = (Interp*)interp; ResolverScheme **prevPtrPtr, *resPtr; /* * Look for an existing scheme with the given name. */ prevPtrPtr = &iPtr->resolverPtr; for (resPtr = iPtr->resolverPtr; resPtr != NULL; resPtr = resPtr->nextPtr) { if (*name == *resPtr->name && strcmp(name, resPtr->name) == 0) { break; } prevPtrPtr = &resPtr->nextPtr; } /* * If we found the scheme, delete it. */ if (resPtr) { /* * If we're deleting a scheme with compiled variable resolution * rules, bump the compiler epoch to invalidate compiled code. * If we're deleting a scheme with command resolution rules, * bump the cmdRefEpoch in all namespaces. */ if (resPtr->compiledVarResProc) { iPtr->compileEpoch++; } if (resPtr->cmdResProc) { BumpCmdRefEpochs(iPtr->globalNsPtr); } *prevPtrPtr = resPtr->nextPtr; ckfree(resPtr->name); ckfree((char *) resPtr); return 1; } return 0; } /* *---------------------------------------------------------------------- * * BumpCmdRefEpochs -- * * This procedure is used to bump the cmdRefEpoch counters in * the specified namespace and all of its child namespaces. * It is used whenever name resolution schemes are added/removed * from an interpreter, to invalidate all command references. * * Results: * None. * * Side effects: * Bumps the cmdRefEpoch in the specified namespace and its * children, recursively. * *---------------------------------------------------------------------- */ static void BumpCmdRefEpochs(nsPtr) Namespace *nsPtr; /* Namespace being modified. */ { Tcl_HashEntry *entry; Tcl_HashSearch search; Namespace *childNsPtr; nsPtr->cmdRefEpoch++; for (entry = Tcl_FirstHashEntry(&nsPtr->childTable, &search); entry != NULL; entry = Tcl_NextHashEntry(&search)) { childNsPtr = (Namespace *) Tcl_GetHashValue(entry); BumpCmdRefEpochs(childNsPtr); } } /* *---------------------------------------------------------------------- * * Tcl_SetNamespaceResolvers -- * * Sets the command/variable resolution procedures for a namespace, * thereby changing the way that command/variable names are * interpreted. This allows extension writers to support different * name resolution schemes, such as those for object-oriented * packages. * * Command resolution is handled by a procedure of the following * type: * * typedef int (Tcl_ResolveCmdProc) _ANSI_ARGS_(( * Tcl_Interp* interp, CONST char* name, Tcl_Namespace *context, * int flags, Tcl_Command *rPtr)); * * Whenever a command is executed or Tcl_FindCommand is invoked * within the namespace, this procedure is called to resolve the * command name. If this procedure is able to resolve the name, * it should return the status code TCL_OK, along with the * corresponding Tcl_Command in the rPtr argument. Otherwise, * the procedure can return TCL_CONTINUE, and the command will * be treated under the usual name resolution rules. Or, it can * return TCL_ERROR, and the command will be considered invalid. * * Variable resolution is handled by two procedures. The first * is called whenever a variable needs to be resolved at compile * time: * * typedef int (Tcl_ResolveCompiledVarProc) _ANSI_ARGS_(( * Tcl_Interp* interp, CONST char* name, Tcl_Namespace *context, * Tcl_ResolvedVarInfo *rPtr)); * * If this procedure is able to resolve the name, it should return * the status code TCL_OK, along with variable resolution info in * the rPtr argument; this info will be used to set up compiled * locals in the call frame at runtime. The procedure may also * return TCL_CONTINUE, and the variable will be treated under * the usual name resolution rules. Or, it can return TCL_ERROR, * and the variable will be considered invalid. * * Another procedure is used whenever a variable needs to be * resolved at runtime but it is not recognized as a compiled local. * (For example, the variable may be requested via * Tcl_FindNamespaceVar.) This procedure has the following type: * * typedef int (Tcl_ResolveVarProc) _ANSI_ARGS_(( * Tcl_Interp* interp, CONST char* name, Tcl_Namespace *context, * int flags, Tcl_Var *rPtr)); * * This procedure is quite similar to the compile-time version. * It returns the same status codes, but if variable resolution * succeeds, this procedure returns a Tcl_Var directly via the * rPtr argument. * * Results: * Nothing. * * Side effects: * Bumps the command epoch counter for the namespace, invalidating * all command references in that namespace. Also bumps the * resolver epoch counter for the namespace, forcing all code * in the namespace to be recompiled. * *---------------------------------------------------------------------- */ void Tcl_SetNamespaceResolvers(namespacePtr, cmdProc, varProc, compiledVarProc) Tcl_Namespace *namespacePtr; /* Namespace whose resolution rules * are being modified. */ Tcl_ResolveCmdProc *cmdProc; /* Procedure for command resolution */ Tcl_ResolveVarProc *varProc; /* Procedure for variable resolution * at runtime */ Tcl_ResolveCompiledVarProc *compiledVarProc; /* Procedure for variable resolution * at compile time. */ { Namespace *nsPtr = (Namespace*)namespacePtr; /* * Plug in the new command resolver, and bump the epoch counters * so that all code will have to be recompiled and all commands * will have to be resolved again using the new policy. */ nsPtr->cmdResProc = cmdProc; nsPtr->varResProc = varProc; nsPtr->compiledVarResProc = compiledVarProc; nsPtr->cmdRefEpoch++; nsPtr->resolverEpoch++; } /* *---------------------------------------------------------------------- * * Tcl_GetNamespaceResolvers -- * * Returns the current command/variable resolution procedures * for a namespace. By default, these procedures are NULL. * New procedures can be installed by calling * Tcl_SetNamespaceResolvers, to provide new name resolution * rules. * * Results: * Returns non-zero if any name resolution procedures have been * assigned to this namespace; also returns pointers to the * procedures in the Tcl_ResolverInfo structure. Returns zero * otherwise. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tcl_GetNamespaceResolvers(namespacePtr, resInfoPtr) Tcl_Namespace *namespacePtr; /* Namespace whose resolution rules * are being modified. */ Tcl_ResolverInfo *resInfoPtr; /* Returns: pointers for all * name resolution procedures * assigned to this namespace. */ { Namespace *nsPtr = (Namespace*)namespacePtr; resInfoPtr->cmdResProc = nsPtr->cmdResProc; resInfoPtr->varResProc = nsPtr->varResProc; resInfoPtr->compiledVarResProc = nsPtr->compiledVarResProc; if (nsPtr->cmdResProc != NULL || nsPtr->varResProc != NULL || nsPtr->compiledVarResProc != NULL) { return 1; } return 0; } tcl8.4.20/generic/tclGetDate.y0000644003604700454610000010051612052456743014546 0ustar dgp771div/* * tclGetDate.y -- * * Contains yacc grammar for parsing date and time strings. * The output of this file should be the file tclDate.c which * is used directly in the Tcl sources. * * Copyright (c) 1992-1995 Karl Lehenbauer and Mark Diekhans. * Copyright (c) 1995-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ %{ /* * tclDate.c -- * * This file is generated from a yacc grammar defined in * the file tclGetDate.y. It should not be edited directly. * * Copyright (c) 1992-1995 Karl Lehenbauer and Mark Diekhans. * Copyright (c) 1995-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * SCCSID */ #include "tclInt.h" #include "tclPort.h" #define EPOCH 1970 #define START_OF_TIME 1902 #define END_OF_TIME 2037 /* * The offset of tm_year of struct tm returned by localtime, gmtime, etc. * I don't know how universal this is; K&R II, the NetBSD manpages, and * ../compat/strftime.c all agree that tm_year is the year-1900. However, * some systems may have a different value. This #define should be the * same as in ../compat/strftime.c. */ #define TM_YEAR_BASE 1900 #define HOUR(x) ((int) (60 * x)) #define SECSPERDAY (24L * 60L * 60L) #define IsLeapYear(x) ((x % 4 == 0) && (x % 100 != 0 || x % 400 == 0)) /* * An entry in the lexical lookup table. */ typedef struct _TABLE { char *name; int type; time_t value; } TABLE; /* * Daylight-savings mode: on, off, or not yet known. */ typedef enum _DSTMODE { DSTon, DSToff, DSTmaybe } DSTMODE; /* * Meridian: am, pm, or 24-hour style. */ typedef enum _MERIDIAN { MERam, MERpm, MER24 } MERIDIAN; /* * Global variables. We could get rid of most of these by using a good * union as the yacc stack. (This routine was originally written before * yacc had the %union construct.) Maybe someday; right now we only use * the %union very rarely. */ static char *yyInput; static DSTMODE yyDSTmode; static time_t yyDayOrdinal; static time_t yyDayNumber; static time_t yyMonthOrdinal; static int yyHaveDate; static int yyHaveDay; static int yyHaveOrdinalMonth; static int yyHaveRel; static int yyHaveTime; static int yyHaveZone; static time_t yyTimezone; static time_t yyDay; static time_t yyHour; static time_t yyMinutes; static time_t yyMonth; static time_t yySeconds; static time_t yyYear; static MERIDIAN yyMeridian; static time_t yyRelMonth; static time_t yyRelDay; static time_t yyRelSeconds; static time_t *yyRelPointer; /* * Prototypes of internal functions. */ static void yyerror _ANSI_ARGS_((char *s)); static time_t ToSeconds _ANSI_ARGS_((time_t Hours, time_t Minutes, time_t Seconds, MERIDIAN Meridian)); static int Convert _ANSI_ARGS_((time_t Month, time_t Day, time_t Year, time_t Hours, time_t Minutes, time_t Seconds, MERIDIAN Meridia, DSTMODE DSTmode, time_t *TimePtr)); static time_t DSTcorrect _ANSI_ARGS_((time_t Start, time_t Future)); static time_t NamedDay _ANSI_ARGS_((time_t Start, time_t DayOrdinal, time_t DayNumber)); static time_t NamedMonth _ANSI_ARGS_((time_t Start, time_t MonthOrdinal, time_t MonthNumber)); static int RelativeMonth _ANSI_ARGS_((time_t Start, time_t RelMonth, time_t *TimePtr)); static int RelativeDay _ANSI_ARGS_((time_t Start, time_t RelDay, time_t *TimePtr)); static int LookupWord _ANSI_ARGS_((char *buff)); static int yylex _ANSI_ARGS_((void)); int yyparse _ANSI_ARGS_((void)); %} %union { time_t Number; enum _MERIDIAN Meridian; } %token tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT %token tSTARDATE tSEC_UNIT tSNUMBER tUNUMBER tZONE tEPOCH tDST tISOBASE %token tDAY_UNIT tNEXT %type tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT tDST %type tSEC_UNIT tSNUMBER tUNUMBER tZONE tISOBASE tDAY_UNIT %type unit sign tNEXT tSTARDATE %type tMERIDIAN o_merid %% spec : /* NULL */ | spec item ; item : time { yyHaveTime++; } | zone { yyHaveZone++; } | date { yyHaveDate++; } | ordMonth { yyHaveOrdinalMonth++; } | day { yyHaveDay++; } | relspec { yyHaveRel++; } | iso { yyHaveTime++; yyHaveDate++; } | trek { yyHaveTime++; yyHaveDate++; yyHaveRel++; } | number ; time : tUNUMBER tMERIDIAN { yyHour = $1; yyMinutes = 0; yySeconds = 0; yyMeridian = $2; } | tUNUMBER ':' tUNUMBER o_merid { yyHour = $1; yyMinutes = $3; yySeconds = 0; yyMeridian = $4; } | tUNUMBER ':' tUNUMBER '-' tUNUMBER { yyHour = $1; yyMinutes = $3; yyMeridian = MER24; yyDSTmode = DSToff; yyTimezone = ($5 % 100 + ($5 / 100) * 60); } | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid { yyHour = $1; yyMinutes = $3; yySeconds = $5; yyMeridian = $6; } | tUNUMBER ':' tUNUMBER ':' tUNUMBER '-' tUNUMBER { yyHour = $1; yyMinutes = $3; yySeconds = $5; yyMeridian = MER24; yyDSTmode = DSToff; yyTimezone = ($7 % 100 + ($7 / 100) * 60); } ; zone : tZONE tDST { yyTimezone = $1; yyDSTmode = DSTon; } | tZONE { yyTimezone = $1; yyDSTmode = DSToff; } | tDAYZONE { yyTimezone = $1; yyDSTmode = DSTon; } ; day : tDAY { yyDayOrdinal = 1; yyDayNumber = $1; } | tDAY ',' { yyDayOrdinal = 1; yyDayNumber = $1; } | tUNUMBER tDAY { yyDayOrdinal = $1; yyDayNumber = $2; } | sign tUNUMBER tDAY { yyDayOrdinal = $1 * $2; yyDayNumber = $3; } | tNEXT tDAY { yyDayOrdinal = 2; yyDayNumber = $2; } ; date : tUNUMBER '/' tUNUMBER { yyMonth = $1; yyDay = $3; } | tUNUMBER '/' tUNUMBER '/' tUNUMBER { yyMonth = $1; yyDay = $3; yyYear = $5; } | tISOBASE { yyYear = $1 / 10000; yyMonth = ($1 % 10000)/100; yyDay = $1 % 100; } | tUNUMBER '-' tMONTH '-' tUNUMBER { yyDay = $1; yyMonth = $3; yyYear = $5; } | tUNUMBER '-' tUNUMBER '-' tUNUMBER { yyMonth = $3; yyDay = $5; yyYear = $1; } | tMONTH tUNUMBER { yyMonth = $1; yyDay = $2; } | tMONTH tUNUMBER ',' tUNUMBER { yyMonth = $1; yyDay = $2; yyYear = $4; } | tUNUMBER tMONTH { yyMonth = $2; yyDay = $1; } | tEPOCH { yyMonth = 1; yyDay = 1; yyYear = EPOCH; } | tUNUMBER tMONTH tUNUMBER { yyMonth = $2; yyDay = $1; yyYear = $3; } ; ordMonth: tNEXT tMONTH { yyMonthOrdinal = 1; yyMonth = $2; } | tNEXT tUNUMBER tMONTH { yyMonthOrdinal = $2; yyMonth = $3; } ; iso : tISOBASE tZONE tISOBASE { if ($2 != HOUR(- 7)) YYABORT; yyYear = $1 / 10000; yyMonth = ($1 % 10000)/100; yyDay = $1 % 100; yyHour = $3 / 10000; yyMinutes = ($3 % 10000)/100; yySeconds = $3 % 100; } | tISOBASE tZONE tUNUMBER ':' tUNUMBER ':' tUNUMBER { if ($2 != HOUR(- 7)) YYABORT; yyYear = $1 / 10000; yyMonth = ($1 % 10000)/100; yyDay = $1 % 100; yyHour = $3; yyMinutes = $5; yySeconds = $7; } | tISOBASE tISOBASE { yyYear = $1 / 10000; yyMonth = ($1 % 10000)/100; yyDay = $1 % 100; yyHour = $2 / 10000; yyMinutes = ($2 % 10000)/100; yySeconds = $2 % 100; } ; trek : tSTARDATE tUNUMBER '.' tUNUMBER { /* * Offset computed year by -377 so that the returned years will * be in a range accessible with a 32 bit clock seconds value */ yyYear = $2/1000 + 2323 - 377; yyDay = 1; yyMonth = 1; yyRelDay += (($2%1000)*(365 + IsLeapYear(yyYear)))/1000; yyRelSeconds += $4 * 144 * 60; } ; relspec : relunits tAGO { yyRelSeconds *= -1; yyRelMonth *= -1; yyRelDay *= -1; } | relunits ; relunits : sign tUNUMBER unit { *yyRelPointer += $1 * $2 * $3; } | tUNUMBER unit { *yyRelPointer += $1 * $2; } | tNEXT unit { *yyRelPointer += $2; } | tNEXT tUNUMBER unit { *yyRelPointer += $2 * $3; } | unit { *yyRelPointer += $1; } ; sign : '-' { $$ = -1; } | '+' { $$ = 1; } ; unit : tSEC_UNIT { $$ = $1; yyRelPointer = &yyRelSeconds; } | tDAY_UNIT { $$ = $1; yyRelPointer = &yyRelDay; } | tMONTH_UNIT { $$ = $1; yyRelPointer = &yyRelMonth; } ; number : tUNUMBER { if (yyHaveTime && yyHaveDate && !yyHaveRel) { yyYear = $1; } else { yyHaveTime++; if ($1 < 100) { yyHour = $1; yyMinutes = 0; } else { yyHour = $1 / 100; yyMinutes = $1 % 100; } yySeconds = 0; yyMeridian = MER24; } } ; o_merid : /* NULL */ { $$ = MER24; } | tMERIDIAN { $$ = $1; } ; %% /* * Month and day table. */ static CONST TABLE MonthDayTable[] = { { "january", tMONTH, 1 }, { "february", tMONTH, 2 }, { "march", tMONTH, 3 }, { "april", tMONTH, 4 }, { "may", tMONTH, 5 }, { "june", tMONTH, 6 }, { "july", tMONTH, 7 }, { "august", tMONTH, 8 }, { "september", tMONTH, 9 }, { "sept", tMONTH, 9 }, { "october", tMONTH, 10 }, { "november", tMONTH, 11 }, { "december", tMONTH, 12 }, { "sunday", tDAY, 0 }, { "monday", tDAY, 1 }, { "tuesday", tDAY, 2 }, { "tues", tDAY, 2 }, { "wednesday", tDAY, 3 }, { "wednes", tDAY, 3 }, { "thursday", tDAY, 4 }, { "thur", tDAY, 4 }, { "thurs", tDAY, 4 }, { "friday", tDAY, 5 }, { "saturday", tDAY, 6 }, { NULL } }; /* * Time units table. */ static CONST TABLE UnitsTable[] = { { "year", tMONTH_UNIT, 12 }, { "month", tMONTH_UNIT, 1 }, { "fortnight", tDAY_UNIT, 14 }, { "week", tDAY_UNIT, 7 }, { "day", tDAY_UNIT, 1 }, { "hour", tSEC_UNIT, 60 * 60 }, { "minute", tSEC_UNIT, 60 }, { "min", tSEC_UNIT, 60 }, { "second", tSEC_UNIT, 1 }, { "sec", tSEC_UNIT, 1 }, { NULL } }; /* * Assorted relative-time words. */ static CONST TABLE OtherTable[] = { { "tomorrow", tDAY_UNIT, 1 }, { "yesterday", tDAY_UNIT, -1 }, { "today", tDAY_UNIT, 0 }, { "now", tSEC_UNIT, 0 }, { "last", tUNUMBER, -1 }, { "this", tSEC_UNIT, 0 }, { "next", tNEXT, 1 }, #if 0 { "first", tUNUMBER, 1 }, { "second", tUNUMBER, 2 }, { "third", tUNUMBER, 3 }, { "fourth", tUNUMBER, 4 }, { "fifth", tUNUMBER, 5 }, { "sixth", tUNUMBER, 6 }, { "seventh", tUNUMBER, 7 }, { "eighth", tUNUMBER, 8 }, { "ninth", tUNUMBER, 9 }, { "tenth", tUNUMBER, 10 }, { "eleventh", tUNUMBER, 11 }, { "twelfth", tUNUMBER, 12 }, #endif { "ago", tAGO, 1 }, { "epoch", tEPOCH, 0 }, { "stardate", tSTARDATE, 0}, { NULL } }; /* * The timezone table. (Note: This table was modified to not use any floating * point constants to work around an SGI compiler bug). */ static CONST TABLE TimezoneTable[] = { { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */ { "ut", tZONE, HOUR( 0) }, /* Universal (Coordinated) */ { "utc", tZONE, HOUR( 0) }, { "uct", tZONE, HOUR( 0) }, /* Universal Coordinated Time */ { "wet", tZONE, HOUR( 0) }, /* Western European */ { "bst", tDAYZONE, HOUR( 0) }, /* British Summer */ { "wat", tZONE, HOUR( 1) }, /* West Africa */ { "at", tZONE, HOUR( 2) }, /* Azores */ #if 0 /* For completeness. BST is also British Summer, and GST is * also Guam Standard. */ { "bst", tZONE, HOUR( 3) }, /* Brazil Standard */ { "gst", tZONE, HOUR( 3) }, /* Greenland Standard */ #endif { "nft", tZONE, HOUR( 7/2) }, /* Newfoundland */ { "nst", tZONE, HOUR( 7/2) }, /* Newfoundland Standard */ { "ndt", tDAYZONE, HOUR( 7/2) }, /* Newfoundland Daylight */ { "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */ { "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */ { "est", tZONE, HOUR( 5) }, /* Eastern Standard */ { "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */ { "cst", tZONE, HOUR( 6) }, /* Central Standard */ { "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */ { "mst", tZONE, HOUR( 7) }, /* Mountain Standard */ { "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */ { "pst", tZONE, HOUR( 8) }, /* Pacific Standard */ { "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */ { "yst", tZONE, HOUR( 9) }, /* Yukon Standard */ { "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */ { "hst", tZONE, HOUR(10) }, /* Hawaii Standard */ { "hdt", tDAYZONE, HOUR(10) }, /* Hawaii Daylight */ { "cat", tZONE, HOUR(10) }, /* Central Alaska */ { "ahst", tZONE, HOUR(10) }, /* Alaska-Hawaii Standard */ { "nt", tZONE, HOUR(11) }, /* Nome */ { "idlw", tZONE, HOUR(12) }, /* International Date Line West */ { "cet", tZONE, -HOUR( 1) }, /* Central European */ { "cest", tDAYZONE, -HOUR( 1) }, /* Central European Summer */ { "met", tZONE, -HOUR( 1) }, /* Middle European */ { "mewt", tZONE, -HOUR( 1) }, /* Middle European Winter */ { "mest", tDAYZONE, -HOUR( 1) }, /* Middle European Summer */ { "swt", tZONE, -HOUR( 1) }, /* Swedish Winter */ { "sst", tDAYZONE, -HOUR( 1) }, /* Swedish Summer */ { "fwt", tZONE, -HOUR( 1) }, /* French Winter */ { "fst", tDAYZONE, -HOUR( 1) }, /* French Summer */ { "eet", tZONE, -HOUR( 2) }, /* Eastern Europe, USSR Zone 1 */ { "bt", tZONE, -HOUR( 3) }, /* Baghdad, USSR Zone 2 */ { "it", tZONE, -HOUR( 7/2) }, /* Iran */ { "zp4", tZONE, -HOUR( 4) }, /* USSR Zone 3 */ { "zp5", tZONE, -HOUR( 5) }, /* USSR Zone 4 */ { "ist", tZONE, -HOUR(11/2) }, /* Indian Standard */ { "zp6", tZONE, -HOUR( 6) }, /* USSR Zone 5 */ #if 0 /* For completeness. NST is also Newfoundland Stanard, nad SST is * also Swedish Summer. */ { "nst", tZONE, -HOUR(13/2) }, /* North Sumatra */ { "sst", tZONE, -HOUR( 7) }, /* South Sumatra, USSR Zone 6 */ #endif /* 0 */ { "wast", tZONE, -HOUR( 7) }, /* West Australian Standard */ { "wadt", tDAYZONE, -HOUR( 7) }, /* West Australian Daylight */ { "jt", tZONE, -HOUR(15/2) }, /* Java (3pm in Cronusland!) */ { "cct", tZONE, -HOUR( 8) }, /* China Coast, USSR Zone 7 */ { "jst", tZONE, -HOUR( 9) }, /* Japan Standard, USSR Zone 8 */ { "jdt", tDAYZONE, -HOUR( 9) }, /* Japan Daylight */ { "kst", tZONE, -HOUR( 9) }, /* Korea Standard */ { "kdt", tDAYZONE, -HOUR( 9) }, /* Korea Daylight */ { "cast", tZONE, -HOUR(19/2) }, /* Central Australian Standard */ { "cadt", tDAYZONE, -HOUR(19/2) }, /* Central Australian Daylight */ { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */ { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */ { "gst", tZONE, -HOUR(10) }, /* Guam Standard, USSR Zone 9 */ { "nzt", tZONE, -HOUR(12) }, /* New Zealand */ { "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */ { "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */ { "idle", tZONE, -HOUR(12) }, /* International Date Line East */ /* ADDED BY Marco Nijdam */ { "dst", tDST, HOUR( 0) }, /* DST on (hour is ignored) */ /* End ADDED */ { NULL } }; /* * Military timezone table. */ static CONST TABLE MilitaryTable[] = { { "a", tZONE, HOUR( 1) }, { "b", tZONE, HOUR( 2) }, { "c", tZONE, HOUR( 3) }, { "d", tZONE, HOUR( 4) }, { "e", tZONE, HOUR( 5) }, { "f", tZONE, HOUR( 6) }, { "g", tZONE, HOUR( 7) }, { "h", tZONE, HOUR( 8) }, { "i", tZONE, HOUR( 9) }, { "k", tZONE, HOUR( 10) }, { "l", tZONE, HOUR( 11) }, { "m", tZONE, HOUR( 12) }, { "n", tZONE, HOUR(- 1) }, { "o", tZONE, HOUR(- 2) }, { "p", tZONE, HOUR(- 3) }, { "q", tZONE, HOUR(- 4) }, { "r", tZONE, HOUR(- 5) }, { "s", tZONE, HOUR(- 6) }, { "t", tZONE, HOUR(- 7) }, { "u", tZONE, HOUR(- 8) }, { "v", tZONE, HOUR(- 9) }, { "w", tZONE, HOUR(-10) }, { "x", tZONE, HOUR(-11) }, { "y", tZONE, HOUR(-12) }, { "z", tZONE, HOUR( 0) }, { NULL } }; /* * Dump error messages in the bit bucket. */ static void yyerror(s) char *s; { } static time_t ToSeconds(Hours, Minutes, Seconds, Meridian) time_t Hours; time_t Minutes; time_t Seconds; MERIDIAN Meridian; { if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59) return -1; switch (Meridian) { case MER24: if (Hours < 0 || Hours > 23) return -1; return (Hours * 60L + Minutes) * 60L + Seconds; case MERam: if (Hours < 1 || Hours > 12) return -1; return ((Hours % 12) * 60L + Minutes) * 60L + Seconds; case MERpm: if (Hours < 1 || Hours > 12) return -1; return (((Hours % 12) + 12) * 60L + Minutes) * 60L + Seconds; } return -1; /* Should never be reached */ } /* *----------------------------------------------------------------------------- * * Convert -- * * Convert a {month, day, year, hours, minutes, seconds, meridian, dst} * tuple into a clock seconds value. * * Results: * 0 or -1 indicating success or failure. * * Side effects: * Fills TimePtr with the computed value. * *----------------------------------------------------------------------------- */ static int Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode, TimePtr) time_t Month; time_t Day; time_t Year; time_t Hours; time_t Minutes; time_t Seconds; MERIDIAN Meridian; DSTMODE DSTmode; time_t *TimePtr; { static int DaysInMonth[12] = { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; time_t tod; time_t Julian; int i; /* Figure out how many days are in February for the given year. * Every year divisible by 4 is a leap year. * But, every year divisible by 100 is not a leap year. * But, every year divisible by 400 is a leap year after all. */ DaysInMonth[1] = IsLeapYear(Year) ? 29 : 28; /* Check the inputs for validity */ if (Month < 1 || Month > 12 || Year < START_OF_TIME || Year > END_OF_TIME || Day < 1 || Day > DaysInMonth[(int)--Month]) return -1; /* Start computing the value. First determine the number of days * represented by the date, then multiply by the number of seconds/day. */ for (Julian = Day - 1, i = 0; i < Month; i++) Julian += DaysInMonth[i]; if (Year >= EPOCH) { for (i = EPOCH; i < Year; i++) Julian += 365 + IsLeapYear(i); } else { for (i = Year; i < EPOCH; i++) Julian -= 365 + IsLeapYear(i); } Julian *= SECSPERDAY; /* Add the timezone offset ?? */ Julian += yyTimezone * 60L; /* Add the number of seconds represented by the time component */ if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0) return -1; Julian += tod; /* Perform a preliminary DST compensation ?? */ if (DSTmode == DSTon || (DSTmode == DSTmaybe && TclpGetDate((TclpTime_t)&Julian, 0)->tm_isdst)) Julian -= 60 * 60; *TimePtr = Julian; return 0; } static time_t DSTcorrect(Start, Future) time_t Start; time_t Future; { time_t StartDay; time_t FutureDay; StartDay = (TclpGetDate((TclpTime_t)&Start, 0)->tm_hour + 1) % 24; FutureDay = (TclpGetDate((TclpTime_t)&Future, 0)->tm_hour + 1) % 24; return (Future - Start) + (StartDay - FutureDay) * 60L * 60L; } static time_t NamedDay(Start, DayOrdinal, DayNumber) time_t Start; time_t DayOrdinal; time_t DayNumber; { struct tm *tm; time_t now; now = Start; tm = TclpGetDate((TclpTime_t)&now, 0); now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7); now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1); return DSTcorrect(Start, now); } static time_t NamedMonth(Start, MonthOrdinal, MonthNumber) time_t Start; time_t MonthOrdinal; time_t MonthNumber; { struct tm *tm; time_t now; int result; now = Start; tm = TclpGetDate((TclpTime_t)&now, 0); /* To compute the next n'th month, we use this alg: * add n to year value * if currentMonth < requestedMonth decrement year value by 1 (so that * doing next february from january gives us february of the current year) * set day to 1, time to 0 */ tm->tm_year += MonthOrdinal; if (tm->tm_mon < MonthNumber - 1) { tm->tm_year--; } result = Convert(MonthNumber, (time_t) 1, tm->tm_year + TM_YEAR_BASE, (time_t) 0, (time_t) 0, (time_t) 0, MER24, DSTmaybe, &now); if (result < 0) { return 0; } return DSTcorrect(Start, now); } static int RelativeMonth(Start, RelMonth, TimePtr) time_t Start; time_t RelMonth; time_t *TimePtr; { struct tm *tm; time_t Month; time_t Year; time_t Julian; int result; if (RelMonth == 0) { *TimePtr = 0; return 0; } tm = TclpGetDate((TclpTime_t)&Start, 0); Month = 12 * (tm->tm_year + TM_YEAR_BASE) + tm->tm_mon + RelMonth; Year = Month / 12; Month = Month % 12 + 1; result = Convert(Month, (time_t) tm->tm_mday, Year, (time_t) tm->tm_hour, (time_t) tm->tm_min, (time_t) tm->tm_sec, MER24, DSTmaybe, &Julian); /* * The Julian time returned above is behind by one day, if "month" * or "year" is used to specify relative time and the GMT flag is true. * This problem occurs only when the current time is closer to * midnight, the difference being not more than its time difference * with GMT. For example, in US/Pacific time zone, the problem occurs * whenever the current time is between midnight to 8:00am or 7:00amDST. * See Bug# 413397 for more details and sample script. * To resolve this bug, we simply add the number of seconds corresponding * to timezone difference with GMT to Julian time, if GMT flag is true. */ if (TclDateTimezone == 0) { Julian += TclpGetTimeZone((unsigned long) Start) * 60L; } /* * The following iteration takes into account the case were we jump * into a "short month". Far example, "one month from Jan 31" will * fail because there is no Feb 31. The code below will reduce the * day and try converting the date until we succed or the date equals * 28 (which always works unless the date is bad in another way). */ while ((result != 0) && (tm->tm_mday > 28)) { tm->tm_mday--; result = Convert(Month, (time_t) tm->tm_mday, Year, (time_t) tm->tm_hour, (time_t) tm->tm_min, (time_t) tm->tm_sec, MER24, DSTmaybe, &Julian); } if (result != 0) { return -1; } *TimePtr = DSTcorrect(Start, Julian); return 0; } /* *----------------------------------------------------------------------------- * * RelativeDay -- * * Given a starting time and a number of days before or after, compute the * DST corrected difference between those dates. * * Results: * 1 or -1 indicating success or failure. * * Side effects: * Fills TimePtr with the computed value. * *----------------------------------------------------------------------------- */ static int RelativeDay(Start, RelDay, TimePtr) time_t Start; time_t RelDay; time_t *TimePtr; { time_t new; new = Start + (RelDay * 60 * 60 * 24); *TimePtr = DSTcorrect(Start, new); return 1; } static int LookupWord(buff) char *buff; { register char *p; register char *q; register CONST TABLE *tp; int i; int abbrev; /* * Make it lowercase. */ Tcl_UtfToLower(buff); if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) { yylval.Meridian = MERam; return tMERIDIAN; } if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) { yylval.Meridian = MERpm; return tMERIDIAN; } /* * See if we have an abbreviation for a month. */ if (strlen(buff) == 3) { abbrev = 1; } else if (strlen(buff) == 4 && buff[3] == '.') { abbrev = 1; buff[3] = '\0'; } else { abbrev = 0; } for (tp = MonthDayTable; tp->name; tp++) { if (abbrev) { if (strncmp(buff, tp->name, 3) == 0) { yylval.Number = tp->value; return tp->type; } } else if (strcmp(buff, tp->name) == 0) { yylval.Number = tp->value; return tp->type; } } for (tp = TimezoneTable; tp->name; tp++) { if (strcmp(buff, tp->name) == 0) { yylval.Number = tp->value; return tp->type; } } for (tp = UnitsTable; tp->name; tp++) { if (strcmp(buff, tp->name) == 0) { yylval.Number = tp->value; return tp->type; } } /* * Strip off any plural and try the units table again. */ i = strlen(buff) - 1; if (buff[i] == 's') { buff[i] = '\0'; for (tp = UnitsTable; tp->name; tp++) { if (strcmp(buff, tp->name) == 0) { yylval.Number = tp->value; return tp->type; } } } for (tp = OtherTable; tp->name; tp++) { if (strcmp(buff, tp->name) == 0) { yylval.Number = tp->value; return tp->type; } } /* * Military timezones. */ if (buff[1] == '\0' && !(*buff & 0x80) && isalpha(UCHAR(*buff))) { /* INTL: ISO only */ for (tp = MilitaryTable; tp->name; tp++) { if (strcmp(buff, tp->name) == 0) { yylval.Number = tp->value; return tp->type; } } } /* * Drop out any periods and try the timezone table again. */ for (i = 0, p = q = buff; *q; q++) if (*q != '.') { *p++ = *q; } else { i++; } *p = '\0'; if (i) { for (tp = TimezoneTable; tp->name; tp++) { if (strcmp(buff, tp->name) == 0) { yylval.Number = tp->value; return tp->type; } } } return tID; } static int yylex() { register char c; register char *p; char buff[20]; int Count; for ( ; ; ) { while (isspace(UCHAR(*yyInput))) { yyInput++; } if (isdigit(UCHAR(c = *yyInput))) { /* INTL: digit */ /* convert the string into a number; count the number of digits */ Count = 0; for (yylval.Number = 0; isdigit(UCHAR(c = *yyInput++)); ) { /* INTL: digit */ yylval.Number = 10 * yylval.Number + c - '0'; Count++; } yyInput--; /* A number with 6 or more digits is considered an ISO 8601 base */ if (Count >= 6) { return tISOBASE; } else { return tUNUMBER; } } if (!(c & 0x80) && isalpha(UCHAR(c))) { /* INTL: ISO only. */ for (p = buff; isalpha(UCHAR(c = *yyInput++)) /* INTL: ISO only. */ || c == '.'; ) { if (p < &buff[sizeof buff - 1]) { *p++ = c; } } *p = '\0'; yyInput--; return LookupWord(buff); } if (c != '(') { return *yyInput++; } Count = 0; do { c = *yyInput++; if (c == '\0') { return c; } else if (c == '(') { Count++; } else if (c == ')') { Count--; } } while (Count > 0); } } /* * Specify zone is of -50000 to force GMT. (This allows BST to work). */ int TclGetDate(p, now, zone, timePtr) char *p; Tcl_WideInt now; long zone; Tcl_WideInt *timePtr; { struct tm *tm; time_t Start; time_t Time; time_t tod; int thisyear; yyInput = p; /* now has to be cast to a time_t for 64bit compliance */ Start = (time_t) now; tm = TclpGetDate((TclpTime_t) &Start, (zone == -50000)); thisyear = tm->tm_year + TM_YEAR_BASE; yyYear = thisyear; yyMonth = tm->tm_mon + 1; yyDay = tm->tm_mday; yyTimezone = zone; if (zone == -50000) { yyDSTmode = DSToff; /* assume GMT */ yyTimezone = 0; } else { yyDSTmode = DSTmaybe; } yyHour = 0; yyMinutes = 0; yySeconds = 0; yyMeridian = MER24; yyRelSeconds = 0; yyRelMonth = 0; yyRelDay = 0; yyRelPointer = NULL; yyHaveDate = 0; yyHaveDay = 0; yyHaveOrdinalMonth = 0; yyHaveRel = 0; yyHaveTime = 0; yyHaveZone = 0; if (yyparse() || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1 || yyHaveOrdinalMonth > 1) { return -1; } if (yyHaveDate || yyHaveTime || yyHaveDay) { if (TclDateYear < 0) { TclDateYear = -TclDateYear; } /* * The following line handles years that are specified using * only two digits. The line of code below implements a policy * defined by the X/Open workgroup on the millinium rollover. * Note: some of those dates may not actually be valid on some * platforms. The POSIX standard startes that the dates 70-99 * shall refer to 1970-1999 and 00-38 shall refer to 2000-2038. * This later definition should work on all platforms. */ if (TclDateYear < 100) { if (TclDateYear >= 69) { TclDateYear += 1900; } else { TclDateYear += 2000; } } if (Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds, yyMeridian, yyDSTmode, &Start) < 0) { return -1; } } else { Start = (time_t) now; if (!yyHaveRel) { Start -= ((tm->tm_hour * 60L * 60L) + tm->tm_min * 60L) + tm->tm_sec; } } Start += yyRelSeconds; if (RelativeMonth(Start, yyRelMonth, &Time) < 0) { return -1; } Start += Time; if (RelativeDay(Start, yyRelDay, &Time) < 0) { return -1; } Start += Time; if (yyHaveDay && !yyHaveDate) { tod = NamedDay(Start, yyDayOrdinal, yyDayNumber); Start += tod; } if (yyHaveOrdinalMonth) { tod = NamedMonth(Start, yyMonthOrdinal, yyMonth); Start += tod; } *timePtr = Start; return 0; } tcl8.4.20/generic/tclAlloc.c0000644003604700454610000004226212052456743014240 0ustar dgp771div/* * tclAlloc.c -- * * This is a very fast storage allocator. It allocates blocks of a * small number of different sizes, and keeps free lists of each size. * Blocks that don't exactly fit are passed up to the next larger size. * Blocks over a certain size are directly allocated from the system. * * Copyright (c) 1983 Regents of the University of California. * Copyright (c) 1996-1997 Sun Microsystems, Inc. * Copyright (c) 1998-1999 by Scriptics Corporation. * * Portions contributed by Chris Kingsley, Jack Jansen and Ray Johnson. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ /* * Windows and Unix use an alternative allocator when building with threads * that has significantly reduced lock contention. */ #if !defined(TCL_THREADS) || !defined(USE_THREAD_ALLOC) || defined(TCL_MEM_DEBUG) #include "tclInt.h" #include "tclPort.h" #if USE_TCLALLOC /* * We should really make use of AC_CHECK_TYPE(caddr_t) * here, but it can wait until Tcl uses config.h properly. */ #if defined(_MSC_VER) || defined(__MINGW32__) || defined(__BORLANDC__) typedef unsigned long caddr_t; #endif /* * Alignment for allocated memory. */ #if defined(__APPLE__) #define ALLOCALIGN 16 #else #define ALLOCALIGN 8 #endif /* * The overhead on a block is at least 8 bytes. When free, this space * contains a pointer to the next free block, and the bottom two bits must * be zero. When in use, the first byte is set to MAGIC, and the second * byte is the size index. The remaining bytes are for alignment. * If range checking is enabled then a second word holds the size of the * requested block, less 1, rounded up to a multiple of sizeof(RMAGIC). * The order of elements is critical: ov_magic must overlay the low order * bits of ov_next, and ov_magic can not be a valid ov_next bit pattern. */ union overhead { union overhead *ov_next; /* when free */ unsigned char ov_padding[ALLOCALIGN];/* align struct to ALLOCALIGN bytes */ struct { unsigned char ovu_magic0; /* magic number */ unsigned char ovu_index; /* bucket # */ unsigned char ovu_unused; /* unused */ unsigned char ovu_magic1; /* other magic number */ #ifndef NDEBUG unsigned short ovu_rmagic; /* range magic number */ unsigned long ovu_size; /* actual block size */ unsigned short ovu_unused2; /* padding to 8-byte align */ #endif } ovu; #define ov_magic0 ovu.ovu_magic0 #define ov_magic1 ovu.ovu_magic1 #define ov_index ovu.ovu_index #define ov_rmagic ovu.ovu_rmagic #define ov_size ovu.ovu_size }; #define MAGIC 0xef /* magic # on accounting info */ #define RMAGIC 0x5555 /* magic # on range info */ #ifndef NDEBUG #define RSLOP sizeof (unsigned short) #else #define RSLOP 0 #endif #define OVERHEAD (sizeof(union overhead) + RSLOP) /* * nextf[i] is the pointer to the next free block of size 2^(i+3). The * smallest allocatable block is MINBLOCK bytes. The overhead information * precedes the data area returned to the user. */ #define MINBLOCK ((sizeof(union overhead) + (ALLOCALIGN-1)) & ~(ALLOCALIGN-1)) #define NBUCKETS (13 - (MINBLOCK >> 4)) #define MAXMALLOC (1<<(NBUCKETS+2)) static union overhead *nextf[NBUCKETS]; /* * The following structure is used to keep track of all system memory * currently owned by Tcl. When finalizing, all this memory will * be returned to the system. */ struct block { struct block *nextPtr; /* Linked list. */ struct block *prevPtr; /* Linked list for big blocks, ensures 8-byte * alignment for suballocated blocks. */ }; static struct block *blockList; /* Tracks the suballocated blocks. */ static struct block bigBlocks = { /* Big blocks aren't suballocated. */ &bigBlocks, &bigBlocks }; /* * The allocator is protected by a special mutex that must be * explicitly initialized. Futhermore, because Tcl_Alloc may be * used before anything else in Tcl, we make this module self-initializing * after all with the allocInit variable. */ #ifdef TCL_THREADS static Tcl_Mutex *allocMutexPtr; #endif static int allocInit = 0; #ifdef MSTATS /* * nmalloc[i] is the difference between the number of mallocs and frees * for a given block size. */ static unsigned int nmalloc[NBUCKETS+1]; #include #endif #if !defined(NDEBUG) #define ASSERT(p) if (!(p)) panic(# p) #define RANGE_ASSERT(p) if (!(p)) panic(# p) #else #define ASSERT(p) #define RANGE_ASSERT(p) #endif /* * Prototypes for functions used only in this file. */ static void MoreCore _ANSI_ARGS_((int bucket)); /* *------------------------------------------------------------------------- * * TclInitAlloc -- * * Initialize the memory system. * * Results: * None. * * Side effects: * Initialize the mutex used to serialize allocations. * *------------------------------------------------------------------------- */ void TclInitAlloc() { if (!allocInit) { allocInit = 1; #ifdef TCL_THREADS allocMutexPtr = Tcl_GetAllocMutex(); #endif } } /* *------------------------------------------------------------------------- * * TclFinalizeAllocSubsystem -- * * Release all resources being used by this subsystem, including * aggressively freeing all memory allocated by TclpAlloc() that * has not yet been released with TclpFree(). * * After this function is called, all memory allocated with * TclpAlloc() should be considered unusable. * * Results: * None. * * Side effects: * This subsystem is self-initializing, since memory can be * allocated before Tcl is formally initialized. After this call, * this subsystem has been reset to its initial state and is * usable again. * *------------------------------------------------------------------------- */ void TclFinalizeAllocSubsystem() { unsigned int i; struct block *blockPtr, *nextPtr; Tcl_MutexLock(allocMutexPtr); for (blockPtr = blockList; blockPtr != NULL; blockPtr = nextPtr) { nextPtr = blockPtr->nextPtr; TclpSysFree(blockPtr); } blockList = NULL; for (blockPtr = bigBlocks.nextPtr; blockPtr != &bigBlocks; ) { nextPtr = blockPtr->nextPtr; TclpSysFree(blockPtr); blockPtr = nextPtr; } bigBlocks.nextPtr = &bigBlocks; bigBlocks.prevPtr = &bigBlocks; for (i = 0; i < NBUCKETS; i++) { nextf[i] = NULL; #ifdef MSTATS nmalloc[i] = 0; #endif } #ifdef MSTATS nmalloc[i] = 0; #endif Tcl_MutexUnlock(allocMutexPtr); } /* *---------------------------------------------------------------------- * * TclpAlloc -- * * Allocate more memory. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ char * TclpAlloc(nbytes) unsigned int nbytes; /* Number of bytes to allocate. */ { register union overhead *op; register long bucket; register unsigned amt; struct block *bigBlockPtr = NULL; if (!allocInit) { /* * We have to make the "self initializing" because Tcl_Alloc * may be used before any other part of Tcl. E.g., see * main() for tclsh! */ TclInitAlloc(); } Tcl_MutexLock(allocMutexPtr); /* * First the simple case: we simple allocate big blocks directly */ if (nbytes >= MAXMALLOC - OVERHEAD) { if (nbytes <= UINT_MAX - OVERHEAD - sizeof(struct block)) { bigBlockPtr = (struct block *) TclpSysAlloc((unsigned) (sizeof(struct block) + OVERHEAD + nbytes), 0); } if (bigBlockPtr == NULL) { Tcl_MutexUnlock(allocMutexPtr); return NULL; } bigBlockPtr->nextPtr = bigBlocks.nextPtr; bigBlocks.nextPtr = bigBlockPtr; bigBlockPtr->prevPtr = &bigBlocks; bigBlockPtr->nextPtr->prevPtr = bigBlockPtr; op = (union overhead *) (bigBlockPtr + 1); op->ov_magic0 = op->ov_magic1 = MAGIC; op->ov_index = 0xff; #ifdef MSTATS nmalloc[NBUCKETS]++; #endif #ifndef NDEBUG /* * Record allocated size of block and * bound space with magic numbers. */ op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1); op->ov_rmagic = RMAGIC; *(unsigned short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC; #endif Tcl_MutexUnlock(allocMutexPtr); return (void *)(op+1); } /* * Convert amount of memory requested into closest block size * stored in hash buckets which satisfies request. * Account for space used per block for accounting. */ amt = MINBLOCK; /* size of first bucket */ bucket = MINBLOCK >> 4; while (nbytes + OVERHEAD > amt) { amt <<= 1; if (amt == 0) { Tcl_MutexUnlock(allocMutexPtr); return (NULL); } bucket++; } ASSERT( bucket < NBUCKETS ); /* * If nothing in hash bucket right now, * request more memory from the system. */ if ((op = nextf[bucket]) == NULL) { MoreCore(bucket); if ((op = nextf[bucket]) == NULL) { Tcl_MutexUnlock(allocMutexPtr); return (NULL); } } /* * Remove from linked list */ nextf[bucket] = op->ov_next; op->ov_magic0 = op->ov_magic1 = MAGIC; op->ov_index = (unsigned char) bucket; #ifdef MSTATS nmalloc[bucket]++; #endif #ifndef NDEBUG /* * Record allocated size of block and * bound space with magic numbers. */ op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1); op->ov_rmagic = RMAGIC; *(unsigned short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC; #endif Tcl_MutexUnlock(allocMutexPtr); return ((char *)(op + 1)); } /* *---------------------------------------------------------------------- * * MoreCore -- * * Allocate more memory to the indicated bucket. * * Assumes Mutex is already held. * * Results: * None. * * Side effects: * Attempts to get more memory from the system. * *---------------------------------------------------------------------- */ static void MoreCore(bucket) int bucket; /* What bucket to allocat to. */ { register union overhead *op; register long sz; /* size of desired block */ long amt; /* amount to allocate */ int nblks; /* how many blocks we get */ struct block *blockPtr; /* * sbrk_size <= 0 only for big, FLUFFY, requests (about * 2^30 bytes on a VAX, I think) or for a negative arg. */ sz = 1 << (bucket + 3); ASSERT(sz > 0); amt = MAXMALLOC; nblks = amt / sz; ASSERT(nblks*sz == amt); blockPtr = (struct block *) TclpSysAlloc((unsigned) (sizeof(struct block) + amt), 1); /* no more room! */ if (blockPtr == NULL) { return; } blockPtr->nextPtr = blockList; blockList = blockPtr; op = (union overhead *) (blockPtr + 1); /* * Add new memory allocated to that on * free list for this hash bucket. */ nextf[bucket] = op; while (--nblks > 0) { op->ov_next = (union overhead *)((caddr_t)op + sz); op = (union overhead *)((caddr_t)op + sz); } op->ov_next = (union overhead *)NULL; } /* *---------------------------------------------------------------------- * * TclpFree -- * * Free memory. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TclpFree(cp) char *cp; /* Pointer to memory to free. */ { register long size; register union overhead *op; struct block *bigBlockPtr; if (cp == NULL) { return; } Tcl_MutexLock(allocMutexPtr); op = (union overhead *)((caddr_t)cp - sizeof (union overhead)); ASSERT(op->ov_magic0 == MAGIC); /* make sure it was in use */ ASSERT(op->ov_magic1 == MAGIC); if (op->ov_magic0 != MAGIC || op->ov_magic1 != MAGIC) { Tcl_MutexUnlock(allocMutexPtr); return; } RANGE_ASSERT(op->ov_rmagic == RMAGIC); RANGE_ASSERT(*(unsigned short *)((caddr_t)(op + 1) + op->ov_size) == RMAGIC); size = op->ov_index; if ( size == 0xff ) { #ifdef MSTATS nmalloc[NBUCKETS]--; #endif bigBlockPtr = (struct block *) op - 1; bigBlockPtr->prevPtr->nextPtr = bigBlockPtr->nextPtr; bigBlockPtr->nextPtr->prevPtr = bigBlockPtr->prevPtr; TclpSysFree(bigBlockPtr); Tcl_MutexUnlock(allocMutexPtr); return; } ASSERT(size < NBUCKETS); op->ov_next = nextf[size]; /* also clobbers ov_magic */ nextf[size] = op; #ifdef MSTATS nmalloc[size]--; #endif Tcl_MutexUnlock(allocMutexPtr); } /* *---------------------------------------------------------------------- * * TclpRealloc -- * * Reallocate memory. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ char * TclpRealloc(cp, nbytes) char *cp; /* Pointer to alloced block. */ unsigned int nbytes; /* New size of memory. */ { int i; union overhead *op; struct block *bigBlockPtr; int expensive; unsigned long maxsize; if (cp == NULL) { return (TclpAlloc(nbytes)); } Tcl_MutexLock(allocMutexPtr); op = (union overhead *)((caddr_t)cp - sizeof (union overhead)); ASSERT(op->ov_magic0 == MAGIC); /* make sure it was in use */ ASSERT(op->ov_magic1 == MAGIC); if (op->ov_magic0 != MAGIC || op->ov_magic1 != MAGIC) { Tcl_MutexUnlock(allocMutexPtr); return NULL; } RANGE_ASSERT(op->ov_rmagic == RMAGIC); RANGE_ASSERT(*(unsigned short *)((caddr_t)(op + 1) + op->ov_size) == RMAGIC); i = op->ov_index; /* * If the block isn't in a bin, just realloc it. */ if (i == 0xff) { struct block *prevPtr, *nextPtr; bigBlockPtr = (struct block *) op - 1; prevPtr = bigBlockPtr->prevPtr; nextPtr = bigBlockPtr->nextPtr; bigBlockPtr = (struct block *) TclpSysRealloc(bigBlockPtr, sizeof(struct block) + OVERHEAD + nbytes); if (bigBlockPtr == NULL) { Tcl_MutexUnlock(allocMutexPtr); return NULL; } if (prevPtr->nextPtr != bigBlockPtr) { /* * If the block has moved, splice the new block into the list where * the old block used to be. */ prevPtr->nextPtr = bigBlockPtr; nextPtr->prevPtr = bigBlockPtr; } op = (union overhead *) (bigBlockPtr + 1); #ifdef MSTATS nmalloc[NBUCKETS]++; #endif #ifndef NDEBUG /* * Record allocated size of block and update magic number bounds. */ op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1); *(unsigned short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC; #endif Tcl_MutexUnlock(allocMutexPtr); return (char *)(op+1); } maxsize = 1 << (i+3); expensive = 0; if ( nbytes + OVERHEAD > maxsize ) { expensive = 1; } else if ( i > 0 && nbytes + OVERHEAD < (maxsize/2) ) { expensive = 1; } if (expensive) { void *newp; Tcl_MutexUnlock(allocMutexPtr); newp = TclpAlloc(nbytes); if ( newp == NULL ) { return NULL; } maxsize -= OVERHEAD; if ( maxsize < nbytes ) nbytes = maxsize; memcpy((VOID *) newp, (VOID *) cp, (size_t) nbytes); TclpFree(cp); return newp; } /* * Ok, we don't have to copy, it fits as-is */ #ifndef NDEBUG op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1); *(unsigned short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC; #endif Tcl_MutexUnlock(allocMutexPtr); return(cp); } /* *---------------------------------------------------------------------- * * mstats -- * * Prints two lines of numbers, one showing the length of the * free list for each size category, the second showing the * number of mallocs - frees for each size category. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ #ifdef MSTATS void mstats(s) char *s; /* Where to write info. */ { register int i, j; register union overhead *p; int totfree = 0, totused = 0; Tcl_MutexLock(allocMutexPtr); fprintf(stderr, "Memory allocation statistics %s\nTclpFree:\t", s); for (i = 0; i < NBUCKETS; i++) { for (j = 0, p = nextf[i]; p; p = p->ov_next, j++) fprintf(stderr, " %d", j); totfree += j * (1 << (i + 3)); } fprintf(stderr, "\nused:\t"); for (i = 0; i < NBUCKETS; i++) { fprintf(stderr, " %d", nmalloc[i]); totused += nmalloc[i] * (1 << (i + 3)); } fprintf(stderr, "\n\tTotal small in use: %d, total free: %d\n", totused, totfree); fprintf(stderr, "\n\tNumber of big (>%d) blocks in use: %d\n", MAXMALLOC, nmalloc[NBUCKETS]); Tcl_MutexUnlock(allocMutexPtr); } #endif #else /* !USE_TCLALLOC */ /* *---------------------------------------------------------------------- * * TclpAlloc -- * * Allocate more memory. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ char * TclpAlloc(nbytes) unsigned int nbytes; /* Number of bytes to allocate. */ { return (char*) malloc(nbytes); } /* *---------------------------------------------------------------------- * * TclpFree -- * * Free memory. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TclpFree(cp) char *cp; /* Pointer to memory to free. */ { free(cp); return; } /* *---------------------------------------------------------------------- * * TclpRealloc -- * * Reallocate memory. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ char * TclpRealloc(cp, nbytes) char *cp; /* Pointer to alloced block. */ unsigned int nbytes; /* New size of memory. */ { return (char*) realloc(cp, nbytes); } #endif /* !USE_TCLALLOC */ #endif /* !TCL_THREADS */ tcl8.4.20/generic/tclNamesp.c0000644003604700454610000037275212133546540014436 0ustar dgp771div/* * tclNamesp.c -- * * Contains support for namespaces, which provide a separate context of * commands and global variables. The global :: namespace is the * traditional Tcl "global" scope. Other namespaces are created as * children of the global namespace. These other namespaces contain * special-purpose commands and variables for packages. * * Copyright (c) 1993-1997 Lucent Technologies. * Copyright (c) 1997 Sun Microsystems, Inc. * Copyright (c) 1998-1999 by Scriptics Corporation. * * Originally implemented by * Michael J. McLennan * Bell Labs Innovations for Lucent Technologies * mmclennan@lucent.com * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" /* * Flag passed to TclGetNamespaceForQualName to indicate that it should * search for a namespace rather than a command or variable inside a * namespace. Note that this flag's value must not conflict with the values * of TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY, or CREATE_NS_IF_UNKNOWN. */ #define FIND_ONLY_NS 0x1000 /* * Initial size of stack allocated space for tail list - used when resetting * shadowed command references in the functin: TclResetShadowedCmdRefs. */ #define NUM_TRAIL_ELEMS 5 /* * Count of the number of namespaces created. This value is used as a * unique id for each namespace. */ static long numNsCreated = 0; TCL_DECLARE_MUTEX(nsMutex) /* * This structure contains a cached pointer to a namespace that is the * result of resolving the namespace's name in some other namespace. It is * the internal representation for a nsName object. It contains the * pointer along with some information that is used to check the cached * pointer's validity. */ typedef struct ResolvedNsName { Namespace *nsPtr; /* A cached namespace pointer. */ long nsId; /* nsPtr's unique namespace id. Used to * verify that nsPtr is still valid * (e.g., it's possible that the namespace * was deleted and a new one created at * the same address). */ Namespace *refNsPtr; /* Points to the namespace containing the * reference (not the namespace that * contains the referenced namespace). */ int refCount; /* Reference count: 1 for each nsName * object that has a pointer to this * ResolvedNsName structure as its internal * rep. This structure can be freed when * refCount becomes zero. */ } ResolvedNsName; /* * Declarations for procedures local to this file: */ static void DeleteImportedCmd _ANSI_ARGS_(( ClientData clientData)); static void DupNsNameInternalRep _ANSI_ARGS_((Tcl_Obj *objPtr, Tcl_Obj *copyPtr)); static void FreeNsNameInternalRep _ANSI_ARGS_(( Tcl_Obj *objPtr)); static int GetNamespaceFromObj _ANSI_ARGS_(( Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Namespace **nsPtrPtr)); static int InvokeImportedCmd _ANSI_ARGS_(( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int NamespaceChildrenCmd _ANSI_ARGS_(( ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int NamespaceCodeCmd _ANSI_ARGS_(( ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int NamespaceCurrentCmd _ANSI_ARGS_(( ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int NamespaceDeleteCmd _ANSI_ARGS_(( ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int NamespaceEvalCmd _ANSI_ARGS_(( ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int NamespaceExistsCmd _ANSI_ARGS_(( ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int NamespaceExportCmd _ANSI_ARGS_(( ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int NamespaceForgetCmd _ANSI_ARGS_(( ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static void NamespaceFree _ANSI_ARGS_((Namespace *nsPtr)); static int NamespaceImportCmd _ANSI_ARGS_(( ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int NamespaceInscopeCmd _ANSI_ARGS_(( ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int NamespaceOriginCmd _ANSI_ARGS_(( ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int NamespaceParentCmd _ANSI_ARGS_(( ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int NamespaceQualifiersCmd _ANSI_ARGS_(( ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int NamespaceTailCmd _ANSI_ARGS_(( ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int NamespaceWhichCmd _ANSI_ARGS_(( ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int SetNsNameFromAny _ANSI_ARGS_(( Tcl_Interp *interp, Tcl_Obj *objPtr)); static void UpdateStringOfNsName _ANSI_ARGS_((Tcl_Obj *objPtr)); /* * This structure defines a Tcl object type that contains a * namespace reference. It is used in commands that take the * name of a namespace as an argument. The namespace reference * is resolved, and the result in cached in the object. */ Tcl_ObjType tclNsNameType = { "nsName", /* the type's name */ FreeNsNameInternalRep, /* freeIntRepProc */ DupNsNameInternalRep, /* dupIntRepProc */ UpdateStringOfNsName, /* updateStringProc */ SetNsNameFromAny /* setFromAnyProc */ }; /* *---------------------------------------------------------------------- * * TclInitNamespaceSubsystem -- * * This procedure is called to initialize all the structures that * are used by namespaces on a per-process basis. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TclInitNamespaceSubsystem() { /* * Does nothing for now. */ } /* *---------------------------------------------------------------------- * * Tcl_GetCurrentNamespace -- * * Returns a pointer to an interpreter's currently active namespace. * * Results: * Returns a pointer to the interpreter's current namespace. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_Namespace * Tcl_GetCurrentNamespace(interp) register Tcl_Interp *interp; /* Interpreter whose current namespace is * being queried. */ { register Interp *iPtr = (Interp *) interp; register Namespace *nsPtr; if (iPtr->varFramePtr != NULL) { nsPtr = iPtr->varFramePtr->nsPtr; } else { nsPtr = iPtr->globalNsPtr; } return (Tcl_Namespace *) nsPtr; } /* *---------------------------------------------------------------------- * * Tcl_GetGlobalNamespace -- * * Returns a pointer to an interpreter's global :: namespace. * * Results: * Returns a pointer to the specified interpreter's global namespace. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_Namespace * Tcl_GetGlobalNamespace(interp) register Tcl_Interp *interp; /* Interpreter whose global namespace * should be returned. */ { register Interp *iPtr = (Interp *) interp; return (Tcl_Namespace *) iPtr->globalNsPtr; } /* *---------------------------------------------------------------------- * * Tcl_PushCallFrame -- * * Pushes a new call frame onto the interpreter's Tcl call stack. * Called when executing a Tcl procedure or a "namespace eval" or * "namespace inscope" command. * * Results: * Returns TCL_OK if successful, or TCL_ERROR (along with an error * message in the interpreter's result object) if something goes wrong. * * Side effects: * Modifies the interpreter's Tcl call stack. * *---------------------------------------------------------------------- */ int Tcl_PushCallFrame(interp, callFramePtr, namespacePtr, isProcCallFrame) Tcl_Interp *interp; /* Interpreter in which the new call frame * is to be pushed. */ Tcl_CallFrame *callFramePtr; /* Points to a call frame structure to * push. Storage for this has already been * allocated by the caller; typically this * is the address of a CallFrame structure * allocated on the caller's C stack. The * call frame will be initialized by this * procedure. The caller can pop the frame * later with Tcl_PopCallFrame, and it is * responsible for freeing the frame's * storage. */ Tcl_Namespace *namespacePtr; /* Points to the namespace in which the * frame will execute. If NULL, the * interpreter's current namespace will * be used. */ int isProcCallFrame; /* If nonzero, the frame represents a * called Tcl procedure and may have local * vars. Vars will ordinarily be looked up * in the frame. If new variables are * created, they will be created in the * frame. If 0, the frame is for a * "namespace eval" or "namespace inscope" * command and var references are treated * as references to namespace variables. */ { Interp *iPtr = (Interp *) interp; register CallFrame *framePtr = (CallFrame *) callFramePtr; register Namespace *nsPtr; if (namespacePtr == NULL) { nsPtr = (Namespace *) Tcl_GetCurrentNamespace(interp); } else { nsPtr = (Namespace *) namespacePtr; if (nsPtr->flags & NS_DEAD) { panic("Trying to push call frame for dead namespace"); /*NOTREACHED*/ } } nsPtr->activationCount++; framePtr->nsPtr = nsPtr; framePtr->isProcCallFrame = isProcCallFrame; framePtr->objc = 0; framePtr->objv = NULL; framePtr->callerPtr = iPtr->framePtr; framePtr->callerVarPtr = iPtr->varFramePtr; if (iPtr->varFramePtr != NULL) { framePtr->level = (iPtr->varFramePtr->level + 1); } else { framePtr->level = 1; } framePtr->procPtr = NULL; /* no called procedure */ framePtr->varTablePtr = NULL; /* and no local variables */ framePtr->numCompiledLocals = 0; framePtr->compiledLocals = NULL; /* * Push the new call frame onto the interpreter's stack of procedure * call frames making it the current frame. */ iPtr->framePtr = framePtr; iPtr->varFramePtr = framePtr; return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_PopCallFrame -- * * Removes a call frame from the Tcl call stack for the interpreter. * Called to remove a frame previously pushed by Tcl_PushCallFrame. * * Results: * None. * * Side effects: * Modifies the call stack of the interpreter. Resets various fields of * the popped call frame. If a namespace has been deleted and * has no more activations on the call stack, the namespace is * destroyed. * *---------------------------------------------------------------------- */ void Tcl_PopCallFrame(interp) Tcl_Interp* interp; /* Interpreter with call frame to pop. */ { register Interp *iPtr = (Interp *) interp; register CallFrame *framePtr = iPtr->framePtr; Namespace *nsPtr; /* * It's important to remove the call frame from the interpreter's stack * of call frames before deleting local variables, so that traces * invoked by the variable deletion don't see the partially-deleted * frame. */ iPtr->framePtr = framePtr->callerPtr; iPtr->varFramePtr = framePtr->callerVarPtr; if (framePtr->varTablePtr != NULL) { TclDeleteVars(iPtr, framePtr->varTablePtr); ckfree((char *) framePtr->varTablePtr); framePtr->varTablePtr = NULL; } if (framePtr->numCompiledLocals > 0) { TclDeleteCompiledLocalVars(iPtr, framePtr); } /* * Decrement the namespace's count of active call frames. If the * namespace is "dying" and there are no more active call frames, * call Tcl_DeleteNamespace to destroy it. */ nsPtr = framePtr->nsPtr; nsPtr->activationCount--; if ((nsPtr->flags & NS_DYING) && (nsPtr->activationCount == 0)) { Tcl_DeleteNamespace((Tcl_Namespace *) nsPtr); } framePtr->nsPtr = NULL; } /* *---------------------------------------------------------------------- * * Tcl_CreateNamespace -- * * Creates a new namespace with the given name. If there is no * active namespace (i.e., the interpreter is being initialized), * the global :: namespace is created and returned. * * Results: * Returns a pointer to the new namespace if successful. If the * namespace already exists or if another error occurs, this routine * returns NULL, along with an error message in the interpreter's * result object. * * Side effects: * If the name contains "::" qualifiers and a parent namespace does * not already exist, it is automatically created. * *---------------------------------------------------------------------- */ Tcl_Namespace * Tcl_CreateNamespace(interp, name, clientData, deleteProc) Tcl_Interp *interp; /* Interpreter in which a new namespace * is being created. Also used for * error reporting. */ CONST char *name; /* Name for the new namespace. May be a * qualified name with names of ancestor * namespaces separated by "::"s. */ ClientData clientData; /* One-word value to store with * namespace. */ Tcl_NamespaceDeleteProc *deleteProc; /* Procedure called to delete client * data when the namespace is deleted. * NULL if no procedure should be * called. */ { Interp *iPtr = (Interp *) interp; register Namespace *nsPtr, *ancestorPtr; Namespace *parentPtr, *dummy1Ptr, *dummy2Ptr; Namespace *globalNsPtr = iPtr->globalNsPtr; CONST char *simpleName; Tcl_HashEntry *entryPtr; Tcl_DString buffer1, buffer2; int newEntry; /* * If there is no active namespace, the interpreter is being * initialized. */ if ((globalNsPtr == NULL) && (iPtr->varFramePtr == NULL)) { /* * Treat this namespace as the global namespace, and avoid * looking for a parent. */ parentPtr = NULL; simpleName = ""; } else if (*name == '\0') { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "can't create namespace \"\": only global namespace can have empty name", (char *) NULL); return NULL; } else { /* * Find the parent for the new namespace. */ TclGetNamespaceForQualName(interp, name, NULL, CREATE_NS_IF_UNKNOWN, &parentPtr, &dummy1Ptr, &dummy2Ptr, &simpleName); /* * If the unqualified name at the end is empty, there were trailing * "::"s after the namespace's name which we ignore. The new * namespace was already (recursively) created and is pointed to * by parentPtr. */ if (*simpleName == '\0') { return (Tcl_Namespace *) parentPtr; } /* * Check for a bad namespace name and make sure that the name * does not already exist in the parent namespace. */ if (Tcl_FindHashEntry(&parentPtr->childTable, simpleName) != NULL) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "can't create namespace \"", name, "\": already exists", (char *) NULL); return NULL; } } /* * Create the new namespace and root it in its parent. Increment the * count of namespaces created. */ nsPtr = (Namespace *) ckalloc(sizeof(Namespace)); nsPtr->name = (char *) ckalloc((unsigned) (strlen(simpleName)+1)); strcpy(nsPtr->name, simpleName); nsPtr->fullName = NULL; /* set below */ nsPtr->clientData = clientData; nsPtr->deleteProc = deleteProc; nsPtr->parentPtr = parentPtr; Tcl_InitHashTable(&nsPtr->childTable, TCL_STRING_KEYS); Tcl_MutexLock(&nsMutex); numNsCreated++; nsPtr->nsId = numNsCreated; Tcl_MutexUnlock(&nsMutex); nsPtr->interp = interp; nsPtr->flags = 0; nsPtr->activationCount = 0; nsPtr->refCount = 0; Tcl_InitHashTable(&nsPtr->cmdTable, TCL_STRING_KEYS); Tcl_InitHashTable(&nsPtr->varTable, TCL_STRING_KEYS); nsPtr->exportArrayPtr = NULL; nsPtr->numExportPatterns = 0; nsPtr->maxExportPatterns = 0; nsPtr->cmdRefEpoch = 0; nsPtr->resolverEpoch = 0; nsPtr->cmdResProc = NULL; nsPtr->varResProc = NULL; nsPtr->compiledVarResProc = NULL; if (parentPtr != NULL) { entryPtr = Tcl_CreateHashEntry(&parentPtr->childTable, simpleName, &newEntry); Tcl_SetHashValue(entryPtr, (ClientData) nsPtr); } /* * Build the fully qualified name for this namespace. */ Tcl_DStringInit(&buffer1); Tcl_DStringInit(&buffer2); for (ancestorPtr = nsPtr; ancestorPtr != NULL; ancestorPtr = ancestorPtr->parentPtr) { if (ancestorPtr != globalNsPtr) { Tcl_DStringAppend(&buffer1, "::", 2); Tcl_DStringAppend(&buffer1, ancestorPtr->name, -1); } Tcl_DStringAppend(&buffer1, Tcl_DStringValue(&buffer2), -1); Tcl_DStringSetLength(&buffer2, 0); Tcl_DStringAppend(&buffer2, Tcl_DStringValue(&buffer1), -1); Tcl_DStringSetLength(&buffer1, 0); } name = Tcl_DStringValue(&buffer2); nsPtr->fullName = (char *) ckalloc((unsigned) (strlen(name)+1)); strcpy(nsPtr->fullName, name); Tcl_DStringFree(&buffer1); Tcl_DStringFree(&buffer2); /* * Return a pointer to the new namespace. */ return (Tcl_Namespace *) nsPtr; } /* *---------------------------------------------------------------------- * * Tcl_DeleteNamespace -- * * Deletes a namespace and all of the commands, variables, and other * namespaces within it. * * Results: * None. * * Side effects: * When a namespace is deleted, it is automatically removed as a * child of its parent namespace. Also, all its commands, variables * and child namespaces are deleted. * *---------------------------------------------------------------------- */ void Tcl_DeleteNamespace(namespacePtr) Tcl_Namespace *namespacePtr; /* Points to the namespace to delete. */ { register Namespace *nsPtr = (Namespace *) namespacePtr; Interp *iPtr = (Interp *) nsPtr->interp; Namespace *globalNsPtr = (Namespace *) Tcl_GetGlobalNamespace((Tcl_Interp *) iPtr); Tcl_HashEntry *entryPtr; /* * If the namespace is on the call frame stack, it is marked as "dying" * (NS_DYING is OR'd into its flags): the namespace can't be looked up * by name but its commands and variables are still usable by those * active call frames. When all active call frames referring to the * namespace have been popped from the Tcl stack, Tcl_PopCallFrame will * call this procedure again to delete everything in the namespace. * If no nsName objects refer to the namespace (i.e., if its refCount * is zero), its commands and variables are deleted and the storage for * its namespace structure is freed. Otherwise, if its refCount is * nonzero, the namespace's commands and variables are deleted but the * structure isn't freed. Instead, NS_DEAD is OR'd into the structure's * flags to allow the namespace resolution code to recognize that the * namespace is "deleted". The structure's storage is freed by * FreeNsNameInternalRep when its refCount reaches 0. */ if (nsPtr->activationCount > 0) { nsPtr->flags |= NS_DYING; if (nsPtr->parentPtr != NULL) { entryPtr = Tcl_FindHashEntry(&nsPtr->parentPtr->childTable, nsPtr->name); if (entryPtr != NULL) { Tcl_DeleteHashEntry(entryPtr); } } nsPtr->parentPtr = NULL; } else if (!(nsPtr->flags & NS_KILLED)) { /* * Delete the namespace and everything in it. If this is the global * namespace, then clear it but don't free its storage unless the * interpreter is being torn down. Set the NS_KILLED flag to avoid * recursive calls here - if the namespace is really in the process of * being deleted, ignore any second call. */ nsPtr->flags |= (NS_DYING|NS_KILLED); TclTeardownNamespace(nsPtr); if ((nsPtr != globalNsPtr) || (iPtr->flags & DELETED)) { /* * If this is the global namespace, then it may have residual * "errorInfo" and "errorCode" variables for errors that * occurred while it was being torn down. Try to clear the * variable list one last time. */ TclDeleteNamespaceVars(nsPtr); Tcl_DeleteHashTable(&nsPtr->childTable); Tcl_DeleteHashTable(&nsPtr->cmdTable); /* * If the reference count is 0, then discard the namespace. * Otherwise, mark it as "dead" so that it can't be used. */ if (nsPtr->refCount == 0) { NamespaceFree(nsPtr); } else { nsPtr->flags |= NS_DEAD; } } else { /* * We didn't really kill it, so remove the KILLED marks, so * it can get killed later, avoiding mem leaks */ nsPtr->flags &= ~(NS_DYING|NS_KILLED); } } } /* *---------------------------------------------------------------------- * * TclTeardownNamespace -- * * Used internally to dismantle and unlink a namespace when it is * deleted. Divorces the namespace from its parent, and deletes all * commands, variables, and child namespaces. * * This is kept separate from Tcl_DeleteNamespace so that the global * namespace can be handled specially. Global variables like * "errorInfo" and "errorCode" need to remain intact while other * namespaces and commands are torn down, in case any errors occur. * * Results: * None. * * Side effects: * Removes this namespace from its parent's child namespace hashtable. * Deletes all commands, variables and namespaces in this namespace. * If this is the global namespace, the "errorInfo" and "errorCode" * variables are left alone and deleted later. * *---------------------------------------------------------------------- */ void TclTeardownNamespace(nsPtr) register Namespace *nsPtr; /* Points to the namespace to be dismantled * and unlinked from its parent. */ { Interp *iPtr = (Interp *) nsPtr->interp; register Tcl_HashEntry *entryPtr; Tcl_HashSearch search; Tcl_Namespace *childNsPtr; Tcl_Command cmd; Namespace *globalNsPtr = (Namespace *) Tcl_GetGlobalNamespace((Tcl_Interp *) iPtr); int i; /* * Start by destroying the namespace's variable table, * since variables might trigger traces. */ if (nsPtr == globalNsPtr) { /* * This is the global namespace. Tearing it down will destroy the * ::errorInfo and ::errorCode variables. We save and restore them * in case there are any errors in progress, so the error details * they contain will not be lost. See test namespace-8.5 */ Tcl_Obj *errorInfo = Tcl_GetVar2Ex(nsPtr->interp, "errorInfo", NULL, TCL_GLOBAL_ONLY); Tcl_Obj *errorCode = Tcl_GetVar2Ex(nsPtr->interp, "errorCode", NULL, TCL_GLOBAL_ONLY); if (errorInfo) { Tcl_IncrRefCount(errorInfo); } if (errorCode) { Tcl_IncrRefCount(errorCode); } TclDeleteNamespaceVars(nsPtr); Tcl_InitHashTable(&nsPtr->varTable, TCL_STRING_KEYS); if (errorInfo) { Tcl_SetVar2Ex(nsPtr->interp, "errorInfo", NULL, errorInfo, TCL_GLOBAL_ONLY); Tcl_DecrRefCount(errorInfo); } if (errorCode) { Tcl_SetVar2Ex(nsPtr->interp, "errorCode", NULL, errorCode, TCL_GLOBAL_ONLY); Tcl_DecrRefCount(errorCode); } } else { /* * Variable table should be cleared but not freed! TclDeleteVars * frees it, so we reinitialize it afterwards. */ TclDeleteNamespaceVars(nsPtr); Tcl_InitHashTable(&nsPtr->varTable, TCL_STRING_KEYS); } /* * Delete all commands in this namespace. Be careful when traversing the * hash table: when each command is deleted, it removes itself from the * command table. */ for (entryPtr = Tcl_FirstHashEntry(&nsPtr->cmdTable, &search); entryPtr != NULL; entryPtr = Tcl_FirstHashEntry(&nsPtr->cmdTable, &search)) { cmd = (Tcl_Command) Tcl_GetHashValue(entryPtr); Tcl_DeleteCommandFromToken((Tcl_Interp *) iPtr, cmd); } Tcl_DeleteHashTable(&nsPtr->cmdTable); Tcl_InitHashTable(&nsPtr->cmdTable, TCL_STRING_KEYS); /* * Remove the namespace from its parent's child hashtable. */ if (nsPtr->parentPtr != NULL) { entryPtr = Tcl_FindHashEntry(&nsPtr->parentPtr->childTable, nsPtr->name); if (entryPtr != NULL) { Tcl_DeleteHashEntry(entryPtr); } } nsPtr->parentPtr = NULL; /* * Delete all the child namespaces. * * BE CAREFUL: When each child is deleted, it will divorce * itself from its parent. You can't traverse a hash table * properly if its elements are being deleted. We use only * the Tcl_FirstHashEntry function to be safe. */ for (entryPtr = Tcl_FirstHashEntry(&nsPtr->childTable, &search); entryPtr != NULL; entryPtr = Tcl_FirstHashEntry(&nsPtr->childTable, &search)) { childNsPtr = (Tcl_Namespace *) Tcl_GetHashValue(entryPtr); Tcl_DeleteNamespace(childNsPtr); } /* * Free the namespace's export pattern array. */ if (nsPtr->exportArrayPtr != NULL) { for (i = 0; i < nsPtr->numExportPatterns; i++) { ckfree(nsPtr->exportArrayPtr[i]); } ckfree((char *) nsPtr->exportArrayPtr); nsPtr->exportArrayPtr = NULL; nsPtr->numExportPatterns = 0; nsPtr->maxExportPatterns = 0; } /* * Free any client data associated with the namespace. */ if (nsPtr->deleteProc != NULL) { (*nsPtr->deleteProc)(nsPtr->clientData); } nsPtr->deleteProc = NULL; nsPtr->clientData = NULL; /* * Reset the namespace's id field to ensure that this namespace won't * be interpreted as valid by, e.g., the cache validation code for * cached command references in Tcl_GetCommandFromObj. */ nsPtr->nsId = 0; } /* *---------------------------------------------------------------------- * * NamespaceFree -- * * Called after a namespace has been deleted, when its * reference count reaches 0. Frees the data structure * representing the namespace. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void NamespaceFree(nsPtr) register Namespace *nsPtr; /* Points to the namespace to free. */ { /* * Most of the namespace's contents are freed when the namespace is * deleted by Tcl_DeleteNamespace. All that remains is to free its names * (for error messages), and the structure itself. */ ckfree(nsPtr->name); ckfree(nsPtr->fullName); ckfree((char *) nsPtr); } /* *---------------------------------------------------------------------- * * Tcl_Export -- * * Makes all the commands matching a pattern available to later be * imported from the namespace specified by namespacePtr (or the * current namespace if namespacePtr is NULL). The specified pattern is * appended onto the namespace's export pattern list, which is * optionally cleared beforehand. * * Results: * Returns TCL_OK if successful, or TCL_ERROR (along with an error * message in the interpreter's result) if something goes wrong. * * Side effects: * Appends the export pattern onto the namespace's export list. * Optionally reset the namespace's export pattern list. * *---------------------------------------------------------------------- */ int Tcl_Export(interp, namespacePtr, pattern, resetListFirst) Tcl_Interp *interp; /* Current interpreter. */ Tcl_Namespace *namespacePtr; /* Points to the namespace from which * commands are to be exported. NULL for * the current namespace. */ CONST char *pattern; /* String pattern indicating which commands * to export. This pattern may not include * any namespace qualifiers; only commands * in the specified namespace may be * exported. */ int resetListFirst; /* If nonzero, resets the namespace's * export list before appending. */ { #define INIT_EXPORT_PATTERNS 5 Namespace *nsPtr, *exportNsPtr, *dummyPtr; Namespace *currNsPtr = (Namespace *) Tcl_GetCurrentNamespace(interp); CONST char *simplePattern; char *patternCpy; int neededElems, len, i; /* * If the specified namespace is NULL, use the current namespace. */ if (namespacePtr == NULL) { nsPtr = (Namespace *) currNsPtr; } else { nsPtr = (Namespace *) namespacePtr; } /* * If resetListFirst is true (nonzero), clear the namespace's export * pattern list. */ if (resetListFirst) { if (nsPtr->exportArrayPtr != NULL) { for (i = 0; i < nsPtr->numExportPatterns; i++) { ckfree(nsPtr->exportArrayPtr[i]); } ckfree((char *) nsPtr->exportArrayPtr); nsPtr->exportArrayPtr = NULL; nsPtr->numExportPatterns = 0; nsPtr->maxExportPatterns = 0; } } /* * Check that the pattern doesn't have namespace qualifiers. */ TclGetNamespaceForQualName(interp, pattern, nsPtr, TCL_NAMESPACE_ONLY, &exportNsPtr, &dummyPtr, &dummyPtr, &simplePattern); if ((exportNsPtr != nsPtr) || (strcmp(pattern, simplePattern) != 0)) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "invalid export pattern \"", pattern, "\": pattern can't specify a namespace", (char *) NULL); return TCL_ERROR; } /* * Make sure that we don't already have the pattern in the array */ if (nsPtr->exportArrayPtr != NULL) { for (i = 0; i < nsPtr->numExportPatterns; i++) { if (strcmp(pattern, nsPtr->exportArrayPtr[i]) == 0) { /* * The pattern already exists in the list */ return TCL_OK; } } } /* * Make sure there is room in the namespace's pattern array for the * new pattern. */ neededElems = nsPtr->numExportPatterns + 1; if (nsPtr->exportArrayPtr == NULL) { nsPtr->exportArrayPtr = (char **) ckalloc((unsigned) (INIT_EXPORT_PATTERNS * sizeof(char *))); nsPtr->numExportPatterns = 0; nsPtr->maxExportPatterns = INIT_EXPORT_PATTERNS; } else if (neededElems > nsPtr->maxExportPatterns) { int numNewElems = 2 * nsPtr->maxExportPatterns; size_t currBytes = nsPtr->numExportPatterns * sizeof(char *); size_t newBytes = numNewElems * sizeof(char *); char **newPtr = (char **) ckalloc((unsigned) newBytes); memcpy((VOID *) newPtr, (VOID *) nsPtr->exportArrayPtr, currBytes); ckfree((char *) nsPtr->exportArrayPtr); nsPtr->exportArrayPtr = (char **) newPtr; nsPtr->maxExportPatterns = numNewElems; } /* * Add the pattern to the namespace's array of export patterns. */ len = strlen(pattern); patternCpy = (char *) ckalloc((unsigned) (len + 1)); strcpy(patternCpy, pattern); nsPtr->exportArrayPtr[nsPtr->numExportPatterns] = patternCpy; nsPtr->numExportPatterns++; return TCL_OK; #undef INIT_EXPORT_PATTERNS } /* *---------------------------------------------------------------------- * * Tcl_AppendExportList -- * * Appends onto the argument object the list of export patterns for the * specified namespace. * * Results: * The return value is normally TCL_OK; in this case the object * referenced by objPtr has each export pattern appended to it. If an * error occurs, TCL_ERROR is returned and the interpreter's result * holds an error message. * * Side effects: * If necessary, the object referenced by objPtr is converted into * a list object. * *---------------------------------------------------------------------- */ int Tcl_AppendExportList(interp, namespacePtr, objPtr) Tcl_Interp *interp; /* Interpreter used for error reporting. */ Tcl_Namespace *namespacePtr; /* Points to the namespace whose export * pattern list is appended onto objPtr. * NULL for the current namespace. */ Tcl_Obj *objPtr; /* Points to the Tcl object onto which the * export pattern list is appended. */ { Namespace *nsPtr; int i, result; /* * If the specified namespace is NULL, use the current namespace. */ if (namespacePtr == NULL) { nsPtr = (Namespace *) Tcl_GetCurrentNamespace(interp); } else { nsPtr = (Namespace *) namespacePtr; } /* * Append the export pattern list onto objPtr. */ for (i = 0; i < nsPtr->numExportPatterns; i++) { result = Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj(nsPtr->exportArrayPtr[i], -1)); if (result != TCL_OK) { return result; } } return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_Import -- * * Imports all of the commands matching a pattern into the namespace * specified by namespacePtr (or the current namespace if contextNsPtr * is NULL). This is done by creating a new command (the "imported * command") that points to the real command in its original namespace. * * If matching commands are on the autoload path but haven't been * loaded yet, this command forces them to be loaded, then creates * the links to them. * * Results: * Returns TCL_OK if successful, or TCL_ERROR (along with an error * message in the interpreter's result) if something goes wrong. * * Side effects: * Creates new commands in the importing namespace. These indirect * calls back to the real command and are deleted if the real commands * are deleted. * *---------------------------------------------------------------------- */ int Tcl_Import(interp, namespacePtr, pattern, allowOverwrite) Tcl_Interp *interp; /* Current interpreter. */ Tcl_Namespace *namespacePtr; /* Points to the namespace into which the * commands are to be imported. NULL for * the current namespace. */ CONST char *pattern; /* String pattern indicating which commands * to import. This pattern should be * qualified by the name of the namespace * from which to import the command(s). */ int allowOverwrite; /* If nonzero, allow existing commands to * be overwritten by imported commands. * If 0, return an error if an imported * cmd conflicts with an existing one. */ { Interp *iPtr = (Interp *) interp; Namespace *nsPtr, *importNsPtr, *dummyPtr; Namespace *currNsPtr = (Namespace *) Tcl_GetCurrentNamespace(interp); CONST char *simplePattern; char *cmdName; register Tcl_HashEntry *hPtr; Tcl_HashSearch search; Command *cmdPtr; ImportRef *refPtr; Tcl_Command autoCmd, importedCmd; ImportedCmdData *dataPtr; int wasExported, i, result; /* * If the specified namespace is NULL, use the current namespace. */ if (namespacePtr == NULL) { nsPtr = (Namespace *) currNsPtr; } else { nsPtr = (Namespace *) namespacePtr; } /* * First, invoke the "auto_import" command with the pattern * being imported. This command is part of the Tcl library. * It looks for imported commands in autoloaded libraries and * loads them in. That way, they will be found when we try * to create links below. */ autoCmd = Tcl_FindCommand(interp, "auto_import", (Tcl_Namespace *) NULL, /*flags*/ TCL_GLOBAL_ONLY); if (autoCmd != NULL) { Tcl_Obj *objv[2]; objv[0] = Tcl_NewStringObj("auto_import", -1); Tcl_IncrRefCount(objv[0]); objv[1] = Tcl_NewStringObj(pattern, -1); Tcl_IncrRefCount(objv[1]); cmdPtr = (Command *) autoCmd; result = (*cmdPtr->objProc)(cmdPtr->objClientData, interp, 2, objv); Tcl_DecrRefCount(objv[0]); Tcl_DecrRefCount(objv[1]); if (result != TCL_OK) { return TCL_ERROR; } Tcl_ResetResult(interp); } /* * From the pattern, find the namespace from which we are importing * and get the simple pattern (no namespace qualifiers or ::'s) at * the end. */ if (strlen(pattern) == 0) { Tcl_SetStringObj(Tcl_GetObjResult(interp), "empty import pattern", -1); return TCL_ERROR; } TclGetNamespaceForQualName(interp, pattern, nsPtr, TCL_NAMESPACE_ONLY, &importNsPtr, &dummyPtr, &dummyPtr, &simplePattern); if (importNsPtr == NULL) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "unknown namespace in import pattern \"", pattern, "\"", (char *) NULL); return TCL_ERROR; } if (importNsPtr == nsPtr) { if (pattern == simplePattern) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "no namespace specified in import pattern \"", pattern, "\"", (char *) NULL); } else { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "import pattern \"", pattern, "\" tries to import from namespace \"", importNsPtr->name, "\" into itself", (char *) NULL); } return TCL_ERROR; } /* * Scan through the command table in the source namespace and look for * exported commands that match the string pattern. Create an "imported * command" in the current namespace for each imported command; these * commands redirect their invocations to the "real" command. */ for (hPtr = Tcl_FirstHashEntry(&importNsPtr->cmdTable, &search); (hPtr != NULL); hPtr = Tcl_NextHashEntry(&search)) { cmdName = Tcl_GetHashKey(&importNsPtr->cmdTable, hPtr); if (Tcl_StringMatch(cmdName, simplePattern)) { /* * The command cmdName in the source namespace matches the * pattern. Check whether it was exported. If it wasn't, * we ignore it. */ Tcl_HashEntry *found; wasExported = 0; for (i = 0; i < importNsPtr->numExportPatterns; i++) { if (Tcl_StringMatch(cmdName, importNsPtr->exportArrayPtr[i])) { wasExported = 1; break; } } if (!wasExported) { continue; } /* * Unless there is a name clash, create an imported command * in the current namespace that refers to cmdPtr. */ found = Tcl_FindHashEntry(&nsPtr->cmdTable, cmdName); if ((found == NULL) || allowOverwrite) { /* * Create the imported command and its client data. * To create the new command in the current namespace, * generate a fully qualified name for it. */ Tcl_DString ds; Tcl_DStringInit(&ds); Tcl_DStringAppend(&ds, nsPtr->fullName, -1); if (nsPtr != iPtr->globalNsPtr) { Tcl_DStringAppend(&ds, "::", 2); } Tcl_DStringAppend(&ds, cmdName, -1); /* * Check whether creating the new imported command in the * current namespace would create a cycle of imported * command references. */ cmdPtr = (Command *) Tcl_GetHashValue(hPtr); if ((found != NULL) && cmdPtr->deleteProc == DeleteImportedCmd) { Command *overwrite = (Command *) Tcl_GetHashValue(found); Command *link = cmdPtr; while (link->deleteProc == DeleteImportedCmd) { ImportedCmdData *dataPtr; dataPtr = (ImportedCmdData *) link->objClientData; link = dataPtr->realCmdPtr; if (overwrite == link) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "import pattern \"", pattern, "\" would create a loop containing ", "command \"", Tcl_DStringValue(&ds), "\"", (char *) NULL); Tcl_DStringFree(&ds); return TCL_ERROR; } } } dataPtr = (ImportedCmdData *) ckalloc(sizeof(ImportedCmdData)); importedCmd = Tcl_CreateObjCommand(interp, Tcl_DStringValue(&ds), InvokeImportedCmd, (ClientData) dataPtr, DeleteImportedCmd); dataPtr->realCmdPtr = cmdPtr; dataPtr->selfPtr = (Command *) importedCmd; dataPtr->selfPtr->compileProc = cmdPtr->compileProc; Tcl_DStringFree(&ds); /* * Create an ImportRef structure describing this new import * command and add it to the import ref list in the "real" * command. */ refPtr = (ImportRef *) ckalloc(sizeof(ImportRef)); refPtr->importedCmdPtr = (Command *) importedCmd; refPtr->nextPtr = cmdPtr->importRefPtr; cmdPtr->importRefPtr = refPtr; } else { Command *overwrite = (Command *) Tcl_GetHashValue(found); if (overwrite->deleteProc == DeleteImportedCmd) { ImportedCmdData *dataPtr = (ImportedCmdData *) overwrite->objClientData; if (dataPtr->realCmdPtr == (Command *) Tcl_GetHashValue(hPtr)) { /* Repeated import of same command -- acceptable */ return TCL_OK; } } Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "can't import command \"", cmdName, "\": already exists", (char *) NULL); return TCL_ERROR; } } } return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_ForgetImport -- * * Deletes commands previously imported into the namespace indicated. The * by namespacePtr, or the current namespace of interp, when * namespacePtr is NULL. The pattern controls which imported commands * are deleted. A simple pattern, one without namespace separators, * matches the current command names of imported commands in the * namespace. Matching imported commands are deleted. A qualified * pattern is interpreted as deletion selection on the basis of where * the command is imported from. The original command and "first link" * command for each imported command are determined, and they are matched * against the pattern. A match leads to deletion of the imported * command. * * Results: * Returns TCL_ERROR and records an error message in the interp * result if a namespace qualified pattern refers to a namespace * that does not exist. Otherwise, returns TCL_OK. * * Side effects: * May delete commands. * *---------------------------------------------------------------------- */ int Tcl_ForgetImport(interp, namespacePtr, pattern) Tcl_Interp *interp; /* Current interpreter. */ Tcl_Namespace *namespacePtr; /* Points to the namespace from which * previously imported commands should be * removed. NULL for current namespace. */ CONST char *pattern; /* String pattern indicating which imported * commands to remove. */ { Namespace *nsPtr, *sourceNsPtr, *dummyPtr; CONST char *simplePattern; char *cmdName; register Tcl_HashEntry *hPtr; Tcl_HashSearch search; /* * If the specified namespace is NULL, use the current namespace. */ if (namespacePtr == NULL) { nsPtr = (Namespace *) Tcl_GetCurrentNamespace(interp); } else { nsPtr = (Namespace *) namespacePtr; } /* * Parse the pattern into its namespace-qualification (if any) * and the simple pattern. */ TclGetNamespaceForQualName(interp, pattern, nsPtr, TCL_NAMESPACE_ONLY, &sourceNsPtr, &dummyPtr, &dummyPtr, &simplePattern); if (sourceNsPtr == NULL) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "unknown namespace in namespace forget pattern \"", pattern, "\"", (char *) NULL); return TCL_ERROR; } if (strcmp(pattern, simplePattern) == 0) { /* * The pattern is simple. * Delete any imported commands that match it. */ for (hPtr = Tcl_FirstHashEntry(&nsPtr->cmdTable, &search); (hPtr != NULL); hPtr = Tcl_NextHashEntry(&search)) { Command *cmdPtr = (Command *) Tcl_GetHashValue(hPtr); if (cmdPtr->deleteProc != DeleteImportedCmd) { continue; } cmdName = Tcl_GetHashKey(&nsPtr->cmdTable, hPtr); if (Tcl_StringMatch(cmdName, simplePattern)) { Tcl_DeleteCommandFromToken(interp, (Tcl_Command) cmdPtr); } } return TCL_OK; } /* The pattern was namespace-qualified */ for (hPtr = Tcl_FirstHashEntry(&nsPtr->cmdTable, &search); (hPtr != NULL); hPtr = Tcl_NextHashEntry(&search)) { Tcl_CmdInfo info; Tcl_Command token = (Tcl_Command) Tcl_GetHashValue(hPtr); Tcl_Command origin = TclGetOriginalCommand(token); if (Tcl_GetCommandInfoFromToken(origin, &info) == 0) { continue; /* Not an imported command */ } if (info.namespacePtr != (Tcl_Namespace *) sourceNsPtr) { /* * Original not in namespace we're matching. * Check the first link in the import chain. */ Command *cmdPtr = (Command *) token; ImportedCmdData *dataPtr = (ImportedCmdData *) cmdPtr->objClientData; Tcl_Command firstToken = (Tcl_Command) dataPtr->realCmdPtr; if (firstToken == origin) { continue; } Tcl_GetCommandInfoFromToken(firstToken, &info); if (info.namespacePtr != (Tcl_Namespace *) sourceNsPtr) { continue; } origin = firstToken; } if (Tcl_StringMatch(Tcl_GetCommandName(NULL, origin), simplePattern)) { Tcl_DeleteCommandFromToken(interp, token); } } return TCL_OK; } /* *---------------------------------------------------------------------- * * TclGetOriginalCommand -- * * An imported command is created in an namespace when a "real" command * is imported from another namespace. If the specified command is an * imported command, this procedure returns the original command it * refers to. * * Results: * If the command was imported into a sequence of namespaces a, b,...,n * where each successive namespace just imports the command from the * previous namespace, this procedure returns the Tcl_Command token in * the first namespace, a. Otherwise, if the specified command is not * an imported command, the procedure returns NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_Command TclGetOriginalCommand(command) Tcl_Command command; /* The imported command for which the * original command should be returned. */ { register Command *cmdPtr = (Command *) command; ImportedCmdData *dataPtr; if (cmdPtr->deleteProc != DeleteImportedCmd) { return (Tcl_Command) NULL; } while (cmdPtr->deleteProc == DeleteImportedCmd) { dataPtr = (ImportedCmdData *) cmdPtr->objClientData; cmdPtr = dataPtr->realCmdPtr; } return (Tcl_Command) cmdPtr; } /* *---------------------------------------------------------------------- * * InvokeImportedCmd -- * * Invoked by Tcl whenever the user calls an imported command that * was created by Tcl_Import. Finds the "real" command (in another * namespace), and passes control to it. * * Results: * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong. * * Side effects: * Returns a result in the interpreter's result object. If anything * goes wrong, the result object is set to an error message. * *---------------------------------------------------------------------- */ static int InvokeImportedCmd(clientData, interp, objc, objv) ClientData clientData; /* Points to the imported command's * ImportedCmdData structure. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* The argument objects. */ { register ImportedCmdData *dataPtr = (ImportedCmdData *) clientData; register Command *realCmdPtr = dataPtr->realCmdPtr; return (*realCmdPtr->objProc)(realCmdPtr->objClientData, interp, objc, objv); } /* *---------------------------------------------------------------------- * * DeleteImportedCmd -- * * Invoked by Tcl whenever an imported command is deleted. The "real" * command keeps a list of all the imported commands that refer to it, * so those imported commands can be deleted when the real command is * deleted. This procedure removes the imported command reference from * the real command's list, and frees up the memory associated with * the imported command. * * Results: * None. * * Side effects: * Removes the imported command from the real command's import list. * *---------------------------------------------------------------------- */ static void DeleteImportedCmd(clientData) ClientData clientData; /* Points to the imported command's * ImportedCmdData structure. */ { ImportedCmdData *dataPtr = (ImportedCmdData *) clientData; Command *realCmdPtr = dataPtr->realCmdPtr; Command *selfPtr = dataPtr->selfPtr; register ImportRef *refPtr, *prevPtr; prevPtr = NULL; for (refPtr = realCmdPtr->importRefPtr; refPtr != NULL; refPtr = refPtr->nextPtr) { if (refPtr->importedCmdPtr == selfPtr) { /* * Remove *refPtr from real command's list of imported commands * that refer to it. */ if (prevPtr == NULL) { /* refPtr is first in list */ realCmdPtr->importRefPtr = refPtr->nextPtr; } else { prevPtr->nextPtr = refPtr->nextPtr; } ckfree((char *) refPtr); ckfree((char *) dataPtr); return; } prevPtr = refPtr; } panic("DeleteImportedCmd: did not find cmd in real cmd's list of import references"); } /* *---------------------------------------------------------------------- * * TclGetNamespaceForQualName -- * * Given a qualified name specifying a command, variable, or namespace, * and a namespace in which to resolve the name, this procedure returns * a pointer to the namespace that contains the item. A qualified name * consists of the "simple" name of an item qualified by the names of * an arbitrary number of containing namespace separated by "::"s. If * the qualified name starts with "::", it is interpreted absolutely * from the global namespace. Otherwise, it is interpreted relative to * the namespace specified by cxtNsPtr if it is non-NULL. If cxtNsPtr * is NULL, the name is interpreted relative to the current namespace. * * A relative name like "foo::bar::x" can be found starting in either * the current namespace or in the global namespace. So each search * usually follows two tracks, and two possible namespaces are * returned. If the procedure sets either *nsPtrPtr or *altNsPtrPtr to * NULL, then that path failed. * * If "flags" contains TCL_GLOBAL_ONLY, the relative qualified name is * sought only in the global :: namespace. The alternate search * (also) starting from the global namespace is ignored and * *altNsPtrPtr is set NULL. * * If "flags" contains TCL_NAMESPACE_ONLY, the relative qualified * name is sought only in the namespace specified by cxtNsPtr. The * alternate search starting from the global namespace is ignored and * *altNsPtrPtr is set NULL. If both TCL_GLOBAL_ONLY and * TCL_NAMESPACE_ONLY are specified, TCL_GLOBAL_ONLY is ignored and * the search starts from the namespace specified by cxtNsPtr. * * If "flags" contains CREATE_NS_IF_UNKNOWN, all namespace * components of the qualified name that cannot be found are * automatically created within their specified parent. This makes sure * that functions like Tcl_CreateCommand always succeed. There is no * alternate search path, so *altNsPtrPtr is set NULL. * * If "flags" contains FIND_ONLY_NS, the qualified name is treated as a * reference to a namespace, and the entire qualified name is * followed. If the name is relative, the namespace is looked up only * in the current namespace. A pointer to the namespace is stored in * *nsPtrPtr and NULL is stored in *simpleNamePtr. Otherwise, if * FIND_ONLY_NS is not specified, only the leading components are * treated as namespace names, and a pointer to the simple name of the * final component is stored in *simpleNamePtr. * * Results: * It sets *nsPtrPtr and *altNsPtrPtr to point to the two possible * namespaces which represent the last (containing) namespace in the * qualified name. If the procedure sets either *nsPtrPtr or *altNsPtrPtr * to NULL, then the search along that path failed. The procedure also * stores a pointer to the simple name of the final component in * *simpleNamePtr. If the qualified name is "::" or was treated as a * namespace reference (FIND_ONLY_NS), the procedure stores a pointer * to the namespace in *nsPtrPtr, NULL in *altNsPtrPtr, and sets * *simpleNamePtr to point to an empty string. * * If there is an error, this procedure returns TCL_ERROR. If "flags" * contains TCL_LEAVE_ERR_MSG, an error message is returned in the * interpreter's result object. Otherwise, the interpreter's result * object is left unchanged. * * *actualCxtPtrPtr is set to the actual context namespace. It is * set to the input context namespace pointer in cxtNsPtr. If cxtNsPtr * is NULL, it is set to the current namespace context. * * For backwards compatibility with the TclPro byte code loader, * this function always returns TCL_OK. * * Side effects: * If "flags" contains CREATE_NS_IF_UNKNOWN, new namespaces may be * created. * *---------------------------------------------------------------------- */ int TclGetNamespaceForQualName(interp, qualName, cxtNsPtr, flags, nsPtrPtr, altNsPtrPtr, actualCxtPtrPtr, simpleNamePtr) Tcl_Interp *interp; /* Interpreter in which to find the * namespace containing qualName. */ CONST char *qualName; /* A namespace-qualified name of an * command, variable, or namespace. */ Namespace *cxtNsPtr; /* The namespace in which to start the * search for qualName's namespace. If NULL * start from the current namespace. * Ignored if TCL_GLOBAL_ONLY is set. */ int flags; /* Flags controlling the search: an OR'd * combination of TCL_GLOBAL_ONLY, * TCL_NAMESPACE_ONLY, * CREATE_NS_IF_UNKNOWN, and * FIND_ONLY_NS. */ Namespace **nsPtrPtr; /* Address where procedure stores a pointer * to containing namespace if qualName is * found starting from *cxtNsPtr or, if * TCL_GLOBAL_ONLY is set, if qualName is * found in the global :: namespace. NULL * is stored otherwise. */ Namespace **altNsPtrPtr; /* Address where procedure stores a pointer * to containing namespace if qualName is * found starting from the global :: * namespace. NULL is stored if qualName * isn't found starting from :: or if the * TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY, * CREATE_NS_IF_UNKNOWN, FIND_ONLY_NS flag * is set. */ Namespace **actualCxtPtrPtr; /* Address where procedure stores a pointer * to the actual namespace from which the * search started. This is either cxtNsPtr, * the :: namespace if TCL_GLOBAL_ONLY was * specified, or the current namespace if * cxtNsPtr was NULL. */ CONST char **simpleNamePtr; /* Address where procedure stores the * simple name at end of the qualName, or * NULL if qualName is "::" or the flag * FIND_ONLY_NS was specified. */ { Interp *iPtr = (Interp *) interp; Namespace *nsPtr = cxtNsPtr; Namespace *altNsPtr; Namespace *globalNsPtr = iPtr->globalNsPtr; CONST char *start, *end; CONST char *nsName; Tcl_HashEntry *entryPtr; Tcl_DString buffer; int len; /* * Determine the context namespace nsPtr in which to start the primary * search. If the qualName name starts with a "::" or TCL_GLOBAL_ONLY * was specified, search from the global namespace. Otherwise, use the * namespace given in cxtNsPtr, or if that is NULL, use the current * namespace context. Note that we always treat two or more * adjacent ":"s as a namespace separator. */ if (flags & TCL_GLOBAL_ONLY) { nsPtr = globalNsPtr; } else if (nsPtr == NULL) { if (iPtr->varFramePtr != NULL) { nsPtr = iPtr->varFramePtr->nsPtr; } else { nsPtr = iPtr->globalNsPtr; } } start = qualName; /* pts to start of qualifying namespace */ if ((*qualName == ':') && (*(qualName+1) == ':')) { start = qualName+2; /* skip over the initial :: */ while (*start == ':') { start++; /* skip over a subsequent : */ } nsPtr = globalNsPtr; if (*start == '\0') { /* qualName is just two or more ":"s */ *nsPtrPtr = globalNsPtr; *altNsPtrPtr = NULL; *actualCxtPtrPtr = globalNsPtr; *simpleNamePtr = start; /* points to empty string */ return TCL_OK; } } *actualCxtPtrPtr = nsPtr; /* * Start an alternate search path starting with the global namespace. * However, if the starting context is the global namespace, or if the * flag is set to search only the namespace *cxtNsPtr, ignore the * alternate search path. */ altNsPtr = globalNsPtr; if ((nsPtr == globalNsPtr) || (flags & (TCL_NAMESPACE_ONLY | FIND_ONLY_NS))) { altNsPtr = NULL; } /* * Loop to resolve each namespace qualifier in qualName. */ Tcl_DStringInit(&buffer); end = start; while (*start != '\0') { /* * Find the next namespace qualifier (i.e., a name ending in "::") * or the end of the qualified name (i.e., a name ending in "\0"). * Set len to the number of characters, starting from start, * in the name; set end to point after the "::"s or at the "\0". */ len = 0; for (end = start; *end != '\0'; end++) { if ((*end == ':') && (*(end+1) == ':')) { end += 2; /* skip over the initial :: */ while (*end == ':') { end++; /* skip over the subsequent : */ } break; /* exit for loop; end is after ::'s */ } len++; } if ((*end == '\0') && !((end-start >= 2) && (*(end-1) == ':') && (*(end-2) == ':'))) { /* * qualName ended with a simple name at start. If FIND_ONLY_NS * was specified, look this up as a namespace. Otherwise, * start is the name of a cmd or var and we are done. */ if (flags & FIND_ONLY_NS) { nsName = start; } else { *nsPtrPtr = nsPtr; *altNsPtrPtr = altNsPtr; *simpleNamePtr = start; Tcl_DStringFree(&buffer); return TCL_OK; } } else { /* * start points to the beginning of a namespace qualifier ending * in "::". end points to the start of a name in that namespace * that might be empty. Copy the namespace qualifier to a * buffer so it can be null terminated. We can't modify the * incoming qualName since it may be a string constant. */ Tcl_DStringSetLength(&buffer, 0); Tcl_DStringAppend(&buffer, start, len); nsName = Tcl_DStringValue(&buffer); } /* * Look up the namespace qualifier nsName in the current namespace * context. If it isn't found but CREATE_NS_IF_UNKNOWN is set, * create that qualifying namespace. This is needed for procedures * like Tcl_CreateCommand that cannot fail. */ if (nsPtr != NULL) { entryPtr = Tcl_FindHashEntry(&nsPtr->childTable, nsName); if (entryPtr != NULL) { nsPtr = (Namespace *) Tcl_GetHashValue(entryPtr); } else if (flags & CREATE_NS_IF_UNKNOWN) { Tcl_CallFrame frame; (void) Tcl_PushCallFrame(interp, &frame, (Tcl_Namespace *) nsPtr, /*isProcCallFrame*/ 0); nsPtr = (Namespace *) Tcl_CreateNamespace(interp, nsName, (ClientData) NULL, (Tcl_NamespaceDeleteProc *) NULL); Tcl_PopCallFrame(interp); if (nsPtr == NULL) { panic("Could not create namespace '%s'", nsName); } } else { /* namespace not found and wasn't created */ nsPtr = NULL; } } /* * Look up the namespace qualifier in the alternate search path too. */ if (altNsPtr != NULL) { entryPtr = Tcl_FindHashEntry(&altNsPtr->childTable, nsName); if (entryPtr != NULL) { altNsPtr = (Namespace *) Tcl_GetHashValue(entryPtr); } else { altNsPtr = NULL; } } /* * If both search paths have failed, return NULL results. */ if ((nsPtr == NULL) && (altNsPtr == NULL)) { *nsPtrPtr = NULL; *altNsPtrPtr = NULL; *simpleNamePtr = NULL; Tcl_DStringFree(&buffer); return TCL_OK; } start = end; } /* * We ignore trailing "::"s in a namespace name, but in a command or * variable name, trailing "::"s refer to the cmd or var named {}. */ if ((flags & FIND_ONLY_NS) || ((end > start ) && (*(end-1) != ':'))) { *simpleNamePtr = NULL; /* found namespace name */ } else { *simpleNamePtr = end; /* found cmd/var: points to empty string */ } /* * As a special case, if we are looking for a namespace and qualName * is "" and the current active namespace (nsPtr) is not the global * namespace, return NULL (no namespace was found). This is because * namespaces can not have empty names except for the global namespace. */ if ((flags & FIND_ONLY_NS) && (*qualName == '\0') && (nsPtr != globalNsPtr)) { nsPtr = NULL; } *nsPtrPtr = nsPtr; *altNsPtrPtr = altNsPtr; Tcl_DStringFree(&buffer); return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_FindNamespace -- * * Searches for a namespace. * * Results: * Returns a pointer to the namespace if it is found. Otherwise, * returns NULL and leaves an error message in the interpreter's * result object if "flags" contains TCL_LEAVE_ERR_MSG. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_Namespace * Tcl_FindNamespace(interp, name, contextNsPtr, flags) Tcl_Interp *interp; /* The interpreter in which to find the * namespace. */ CONST char *name; /* Namespace name. If it starts with "::", * will be looked up in global namespace. * Else, looked up first in contextNsPtr * (current namespace if contextNsPtr is * NULL), then in global namespace. */ Tcl_Namespace *contextNsPtr; /* Ignored if TCL_GLOBAL_ONLY flag is set * or if the name starts with "::". * Otherwise, points to namespace in which * to resolve name; if NULL, look up name * in the current namespace. */ register int flags; /* Flags controlling namespace lookup: an * OR'd combination of TCL_GLOBAL_ONLY and * TCL_LEAVE_ERR_MSG flags. */ { Namespace *nsPtr, *dummy1Ptr, *dummy2Ptr; CONST char *dummy; /* * Find the namespace(s) that contain the specified namespace name. * Add the FIND_ONLY_NS flag to resolve the name all the way down * to its last component, a namespace. */ TclGetNamespaceForQualName(interp, name, (Namespace *) contextNsPtr, (flags | FIND_ONLY_NS), &nsPtr, &dummy1Ptr, &dummy2Ptr, &dummy); if (nsPtr != NULL) { return (Tcl_Namespace *) nsPtr; } else if (flags & TCL_LEAVE_ERR_MSG) { Tcl_ResetResult(interp); Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "unknown namespace \"", name, "\"", (char *) NULL); } return NULL; } /* *---------------------------------------------------------------------- * * Tcl_FindCommand -- * * Searches for a command. * * Results: * Returns a token for the command if it is found. Otherwise, if it * can't be found or there is an error, returns NULL and leaves an * error message in the interpreter's result object if "flags" * contains TCL_LEAVE_ERR_MSG. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_Command Tcl_FindCommand(interp, name, contextNsPtr, flags) Tcl_Interp *interp; /* The interpreter in which to find the * command and to report errors. */ CONST char *name; /* Command's name. If it starts with "::", * will be looked up in global namespace. * Else, looked up first in contextNsPtr * (current namespace if contextNsPtr is * NULL), then in global namespace. */ Tcl_Namespace *contextNsPtr; /* Ignored if TCL_GLOBAL_ONLY flag set. * Otherwise, points to namespace in which * to resolve name. If NULL, look up name * in the current namespace. */ int flags; /* An OR'd combination of flags: * TCL_GLOBAL_ONLY (look up name only in * global namespace), TCL_NAMESPACE_ONLY * (look up only in contextNsPtr, or the * current namespace if contextNsPtr is * NULL), and TCL_LEAVE_ERR_MSG. If both * TCL_GLOBAL_ONLY and TCL_NAMESPACE_ONLY * are given, TCL_GLOBAL_ONLY is * ignored. */ { Interp *iPtr = (Interp*)interp; ResolverScheme *resPtr; Namespace *nsPtr[2], *cxtNsPtr; CONST char *simpleName; register Tcl_HashEntry *entryPtr; register Command *cmdPtr; register int search; int result; Tcl_Command cmd; /* * If this namespace has a command resolver, then give it first * crack at the command resolution. If the interpreter has any * command resolvers, consult them next. The command resolver * procedures may return a Tcl_Command value, they may signal * to continue onward, or they may signal an error. */ if ((flags & TCL_GLOBAL_ONLY) != 0) { cxtNsPtr = (Namespace *) Tcl_GetGlobalNamespace(interp); } else if (contextNsPtr != NULL) { cxtNsPtr = (Namespace *) contextNsPtr; } else { cxtNsPtr = (Namespace *) Tcl_GetCurrentNamespace(interp); } if (cxtNsPtr->cmdResProc != NULL || iPtr->resolverPtr != NULL) { resPtr = iPtr->resolverPtr; if (cxtNsPtr->cmdResProc) { result = (*cxtNsPtr->cmdResProc)(interp, name, (Tcl_Namespace *) cxtNsPtr, flags, &cmd); } else { result = TCL_CONTINUE; } while (result == TCL_CONTINUE && resPtr) { if (resPtr->cmdResProc) { result = (*resPtr->cmdResProc)(interp, name, (Tcl_Namespace *) cxtNsPtr, flags, &cmd); } resPtr = resPtr->nextPtr; } if (result == TCL_OK) { return cmd; } else if (result != TCL_CONTINUE) { return (Tcl_Command) NULL; } } /* * Find the namespace(s) that contain the command. */ TclGetNamespaceForQualName(interp, name, (Namespace *) contextNsPtr, flags, &nsPtr[0], &nsPtr[1], &cxtNsPtr, &simpleName); /* * Look for the command in the command table of its namespace. * Be sure to check both possible search paths: from the specified * namespace context and from the global namespace. */ cmdPtr = NULL; for (search = 0; (search < 2) && (cmdPtr == NULL); search++) { if ((nsPtr[search] != NULL) && (simpleName != NULL)) { entryPtr = Tcl_FindHashEntry(&nsPtr[search]->cmdTable, simpleName); if (entryPtr != NULL) { cmdPtr = (Command *) Tcl_GetHashValue(entryPtr); } } } if (cmdPtr != NULL) { return (Tcl_Command) cmdPtr; } else if (flags & TCL_LEAVE_ERR_MSG) { Tcl_ResetResult(interp); Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "unknown command \"", name, "\"", (char *) NULL); } return (Tcl_Command) NULL; } /* *---------------------------------------------------------------------- * * Tcl_FindNamespaceVar -- * * Searches for a namespace variable, a variable not local to a * procedure. The variable can be either a scalar or an array, but * may not be an element of an array. * * Results: * Returns a token for the variable if it is found. Otherwise, if it * can't be found or there is an error, returns NULL and leaves an * error message in the interpreter's result object if "flags" * contains TCL_LEAVE_ERR_MSG. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_Var Tcl_FindNamespaceVar(interp, name, contextNsPtr, flags) Tcl_Interp *interp; /* The interpreter in which to find the * variable. */ CONST char *name; /* Variable's name. If it starts with "::", * will be looked up in global namespace. * Else, looked up first in contextNsPtr * (current namespace if contextNsPtr is * NULL), then in global namespace. */ Tcl_Namespace *contextNsPtr; /* Ignored if TCL_GLOBAL_ONLY flag set. * Otherwise, points to namespace in which * to resolve name. If NULL, look up name * in the current namespace. */ int flags; /* An OR'd combination of flags: * TCL_GLOBAL_ONLY (look up name only in * global namespace), TCL_NAMESPACE_ONLY * (look up only in contextNsPtr, or the * current namespace if contextNsPtr is * NULL), and TCL_LEAVE_ERR_MSG. If both * TCL_GLOBAL_ONLY and TCL_NAMESPACE_ONLY * are given, TCL_GLOBAL_ONLY is * ignored. */ { Interp *iPtr = (Interp*)interp; ResolverScheme *resPtr; Namespace *nsPtr[2], *cxtNsPtr; CONST char *simpleName; Tcl_HashEntry *entryPtr; Var *varPtr; register int search; int result; Tcl_Var var; /* * If this namespace has a variable resolver, then give it first * crack at the variable resolution. It may return a Tcl_Var * value, it may signal to continue onward, or it may signal * an error. */ if ((flags & TCL_GLOBAL_ONLY) != 0) { cxtNsPtr = (Namespace *) Tcl_GetGlobalNamespace(interp); } else if (contextNsPtr != NULL) { cxtNsPtr = (Namespace *) contextNsPtr; } else { cxtNsPtr = (Namespace *) Tcl_GetCurrentNamespace(interp); } if (cxtNsPtr->varResProc != NULL || iPtr->resolverPtr != NULL) { resPtr = iPtr->resolverPtr; if (cxtNsPtr->varResProc) { result = (*cxtNsPtr->varResProc)(interp, name, (Tcl_Namespace *) cxtNsPtr, flags, &var); } else { result = TCL_CONTINUE; } while (result == TCL_CONTINUE && resPtr) { if (resPtr->varResProc) { result = (*resPtr->varResProc)(interp, name, (Tcl_Namespace *) cxtNsPtr, flags, &var); } resPtr = resPtr->nextPtr; } if (result == TCL_OK) { return var; } else if (result != TCL_CONTINUE) { return (Tcl_Var) NULL; } } /* * Find the namespace(s) that contain the variable. */ TclGetNamespaceForQualName(interp, name, (Namespace *) contextNsPtr, flags, &nsPtr[0], &nsPtr[1], &cxtNsPtr, &simpleName); /* * Look for the variable in the variable table of its namespace. * Be sure to check both possible search paths: from the specified * namespace context and from the global namespace. */ varPtr = NULL; for (search = 0; (search < 2) && (varPtr == NULL); search++) { if ((nsPtr[search] != NULL) && (simpleName != NULL)) { entryPtr = Tcl_FindHashEntry(&nsPtr[search]->varTable, simpleName); if (entryPtr != NULL) { varPtr = (Var *) Tcl_GetHashValue(entryPtr); } } } if (varPtr != NULL) { return (Tcl_Var) varPtr; } else if (flags & TCL_LEAVE_ERR_MSG) { Tcl_ResetResult(interp); Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "unknown variable \"", name, "\"", (char *) NULL); } return (Tcl_Var) NULL; } /* *---------------------------------------------------------------------- * * TclResetShadowedCmdRefs -- * * Called when a command is added to a namespace to check for existing * command references that the new command may invalidate. Consider the * following cases that could happen when you add a command "foo" to a * namespace "b": * 1. It could shadow a command named "foo" at the global scope. * If it does, all command references in the namespace "b" are * suspect. * 2. Suppose the namespace "b" resides in a namespace "a". * Then to "a" the new command "b::foo" could shadow another * command "b::foo" in the global namespace. If so, then all * command references in "a" are suspect. * The same checks are applied to all parent namespaces, until we * reach the global :: namespace. * * Results: * None. * * Side effects: * If the new command shadows an existing command, the cmdRefEpoch * counter is incremented in each namespace that sees the shadow. * This invalidates all command references that were previously cached * in that namespace. The next time the commands are used, they are * resolved from scratch. * *---------------------------------------------------------------------- */ void TclResetShadowedCmdRefs(interp, newCmdPtr) Tcl_Interp *interp; /* Interpreter containing the new command. */ Command *newCmdPtr; /* Points to the new command. */ { char *cmdName; Tcl_HashEntry *hPtr; register Namespace *nsPtr; Namespace *trailNsPtr, *shadowNsPtr; Namespace *globalNsPtr = (Namespace *) Tcl_GetGlobalNamespace(interp); int found, i; /* * This procedure generates an array used to hold the trail list. This * starts out with stack-allocated space but uses dynamically-allocated * storage if needed. */ Namespace *(trailStorage[NUM_TRAIL_ELEMS]); Namespace **trailPtr = trailStorage; int trailFront = -1; int trailSize = NUM_TRAIL_ELEMS; /* * Start at the namespace containing the new command, and work up * through the list of parents. Stop just before the global namespace, * since the global namespace can't "shadow" its own entries. * * The namespace "trail" list we build consists of the names of each * namespace that encloses the new command, in order from outermost to * innermost: for example, "a" then "b". Each iteration of this loop * eventually extends the trail upwards by one namespace, nsPtr. We use * this trail list to see if nsPtr (e.g. "a" in 2. above) could have * now-invalid cached command references. This will happen if nsPtr * (e.g. "a") contains a sequence of child namespaces (e.g. "b") * such that there is a identically-named sequence of child namespaces * starting from :: (e.g. "::b") whose tail namespace contains a command * also named cmdName. */ cmdName = Tcl_GetHashKey(newCmdPtr->hPtr->tablePtr, newCmdPtr->hPtr); for (nsPtr = newCmdPtr->nsPtr; (nsPtr != NULL) && (nsPtr != globalNsPtr); nsPtr = nsPtr->parentPtr) { /* * Find the maximal sequence of child namespaces contained in nsPtr * such that there is a identically-named sequence of child * namespaces starting from ::. shadowNsPtr will be the tail of this * sequence, or the deepest namespace under :: that might contain a * command now shadowed by cmdName. We check below if shadowNsPtr * actually contains a command cmdName. */ found = 1; shadowNsPtr = globalNsPtr; for (i = trailFront; i >= 0; i--) { trailNsPtr = trailPtr[i]; hPtr = Tcl_FindHashEntry(&shadowNsPtr->childTable, trailNsPtr->name); if (hPtr != NULL) { shadowNsPtr = (Namespace *) Tcl_GetHashValue(hPtr); } else { found = 0; break; } } /* * If shadowNsPtr contains a command named cmdName, we invalidate * all of the command refs cached in nsPtr. As a boundary case, * shadowNsPtr is initially :: and we check for case 1. above. */ if (found) { hPtr = Tcl_FindHashEntry(&shadowNsPtr->cmdTable, cmdName); if (hPtr != NULL) { nsPtr->cmdRefEpoch++; /* * If the shadowed command was compiled to bytecodes, we * invalidate all the bytecodes in nsPtr, to force a new * compilation. We use the resolverEpoch to signal the need * for a fresh compilation of every bytecode. */ if ((((Command *) Tcl_GetHashValue(hPtr))->compileProc) != NULL) { nsPtr->resolverEpoch++; } } } /* * Insert nsPtr at the front of the trail list: i.e., at the end * of the trailPtr array. */ trailFront++; if (trailFront == trailSize) { size_t currBytes = trailSize * sizeof(Namespace *); int newSize = 2*trailSize; size_t newBytes = newSize * sizeof(Namespace *); Namespace **newPtr = (Namespace **) ckalloc((unsigned) newBytes); memcpy((VOID *) newPtr, (VOID *) trailPtr, currBytes); if (trailPtr != trailStorage) { ckfree((char *) trailPtr); } trailPtr = newPtr; trailSize = newSize; } trailPtr[trailFront] = nsPtr; } /* * Free any allocated storage. */ if (trailPtr != trailStorage) { ckfree((char *) trailPtr); } } /* *---------------------------------------------------------------------- * * GetNamespaceFromObj -- * * Gets the namespace specified by the name in a Tcl_Obj. * * Results: * Returns TCL_OK if the namespace was resolved successfully, and * stores a pointer to the namespace in the location specified by * nsPtrPtr. If the namespace can't be found, the procedure stores * NULL in *nsPtrPtr and returns TCL_OK. If anything else goes wrong, * this procedure returns TCL_ERROR. * * Side effects: * May update the internal representation for the object, caching the * namespace reference. The next time this procedure is called, the * namespace value can be found quickly. * * If anything goes wrong, an error message is left in the * interpreter's result object. * *---------------------------------------------------------------------- */ static int GetNamespaceFromObj(interp, objPtr, nsPtrPtr) Tcl_Interp *interp; /* The current interpreter. */ Tcl_Obj *objPtr; /* The object to be resolved as the name * of a namespace. */ Tcl_Namespace **nsPtrPtr; /* Result namespace pointer goes here. */ { Interp *iPtr = (Interp *) interp; register ResolvedNsName *resNamePtr; register Namespace *nsPtr; Namespace *currNsPtr; CallFrame *savedFramePtr; int result = TCL_OK; char *name; /* * If the namespace name is fully qualified, do as if the lookup were * done from the global namespace; this helps avoid repeated lookups * of fully qualified names. */ savedFramePtr = iPtr->varFramePtr; name = Tcl_GetString(objPtr); if ((*name++ == ':') && (*name == ':')) { iPtr->varFramePtr = NULL; } currNsPtr = (Namespace *) Tcl_GetCurrentNamespace(interp); /* * Get the internal representation, converting to a namespace type if * needed. The internal representation is a ResolvedNsName that points * to the actual namespace. */ if (objPtr->typePtr != &tclNsNameType) { result = tclNsNameType.setFromAnyProc(interp, objPtr); if (result != TCL_OK) { goto done; } } resNamePtr = (ResolvedNsName *) objPtr->internalRep.otherValuePtr; /* * Check the context namespace of the resolved symbol to make sure that * it is fresh. If not, then force another conversion to the namespace * type, to discard the old rep and create a new one. Note that we * verify that the namespace id of the cached namespace is the same as * the id when we cached it; this insures that the namespace wasn't * deleted and a new one created at the same address. */ nsPtr = NULL; if ((resNamePtr != NULL) && (resNamePtr->refNsPtr == currNsPtr) && (resNamePtr->nsId == resNamePtr->nsPtr->nsId)) { nsPtr = resNamePtr->nsPtr; if (nsPtr->flags & NS_DEAD) { nsPtr = NULL; } } if (nsPtr == NULL) { /* try again */ result = tclNsNameType.setFromAnyProc(interp, objPtr); if (result != TCL_OK) { goto done; } resNamePtr = (ResolvedNsName *) objPtr->internalRep.otherValuePtr; if (resNamePtr != NULL) { nsPtr = resNamePtr->nsPtr; if (nsPtr->flags & NS_DEAD) { nsPtr = NULL; } } } *nsPtrPtr = (Tcl_Namespace *) nsPtr; done: iPtr->varFramePtr = savedFramePtr; return result; } /* *---------------------------------------------------------------------- * * Tcl_NamespaceObjCmd -- * * Invoked to implement the "namespace" command that creates, deletes, * or manipulates Tcl namespaces. Handles the following syntax: * * namespace children ?name? ?pattern? * namespace code arg * namespace current * namespace delete ?name name...? * namespace eval name arg ?arg...? * namespace exists name * namespace export ?-clear? ?pattern pattern...? * namespace forget ?pattern pattern...? * namespace import ?-force? ?pattern pattern...? * namespace inscope name arg ?arg...? * namespace origin name * namespace parent ?name? * namespace qualifiers string * namespace tail string * namespace which ?-command? ?-variable? name * * Results: * Returns TCL_OK if the command is successful. Returns TCL_ERROR if * anything goes wrong. * * Side effects: * Based on the subcommand name (e.g., "import"), this procedure * dispatches to a corresponding procedure NamespaceXXXCmd defined * statically in this file. This procedure's side effects depend on * whatever that subcommand procedure does. If there is an error, this * procedure returns an error message in the interpreter's result * object. Otherwise it may return a result in the interpreter's result * object. * *---------------------------------------------------------------------- */ int Tcl_NamespaceObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Arbitrary value passed to cmd. */ Tcl_Interp *interp; /* Current interpreter. */ register int objc; /* Number of arguments. */ register Tcl_Obj *CONST objv[]; /* Argument objects. */ { static CONST char *subCmds[] = { "children", "code", "current", "delete", "eval", "exists", "export", "forget", "import", "inscope", "origin", "parent", "qualifiers", "tail", "which", (char *) NULL }; enum NSSubCmdIdx { NSChildrenIdx, NSCodeIdx, NSCurrentIdx, NSDeleteIdx, NSEvalIdx, NSExistsIdx, NSExportIdx, NSForgetIdx, NSImportIdx, NSInscopeIdx, NSOriginIdx, NSParentIdx, NSQualifiersIdx, NSTailIdx, NSWhichIdx }; int index, result; if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "subcommand ?arg ...?"); return TCL_ERROR; } /* * Return an index reflecting the particular subcommand. */ result = Tcl_GetIndexFromObj((Tcl_Interp *) interp, objv[1], subCmds, "option", /*flags*/ 0, (int *) &index); if (result != TCL_OK) { return result; } switch (index) { case NSChildrenIdx: result = NamespaceChildrenCmd(clientData, interp, objc, objv); break; case NSCodeIdx: result = NamespaceCodeCmd(clientData, interp, objc, objv); break; case NSCurrentIdx: result = NamespaceCurrentCmd(clientData, interp, objc, objv); break; case NSDeleteIdx: result = NamespaceDeleteCmd(clientData, interp, objc, objv); break; case NSEvalIdx: result = NamespaceEvalCmd(clientData, interp, objc, objv); break; case NSExistsIdx: result = NamespaceExistsCmd(clientData, interp, objc, objv); break; case NSExportIdx: result = NamespaceExportCmd(clientData, interp, objc, objv); break; case NSForgetIdx: result = NamespaceForgetCmd(clientData, interp, objc, objv); break; case NSImportIdx: result = NamespaceImportCmd(clientData, interp, objc, objv); break; case NSInscopeIdx: result = NamespaceInscopeCmd(clientData, interp, objc, objv); break; case NSOriginIdx: result = NamespaceOriginCmd(clientData, interp, objc, objv); break; case NSParentIdx: result = NamespaceParentCmd(clientData, interp, objc, objv); break; case NSQualifiersIdx: result = NamespaceQualifiersCmd(clientData, interp, objc, objv); break; case NSTailIdx: result = NamespaceTailCmd(clientData, interp, objc, objv); break; case NSWhichIdx: result = NamespaceWhichCmd(clientData, interp, objc, objv); break; } return result; } /* *---------------------------------------------------------------------- * * NamespaceChildrenCmd -- * * Invoked to implement the "namespace children" command that returns a * list containing the fully-qualified names of the child namespaces of * a given namespace. Handles the following syntax: * * namespace children ?name? ?pattern? * * Results: * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong. * * Side effects: * Returns a result in the interpreter's result object. If anything * goes wrong, the result is an error message. * *---------------------------------------------------------------------- */ static int NamespaceChildrenCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Tcl_Namespace *namespacePtr; Namespace *nsPtr, *childNsPtr; Namespace *globalNsPtr = (Namespace *) Tcl_GetGlobalNamespace(interp); char *pattern = NULL; Tcl_DString buffer; register Tcl_HashEntry *entryPtr; Tcl_HashSearch search; Tcl_Obj *listPtr, *elemPtr; /* * Get a pointer to the specified namespace, or the current namespace. */ if (objc == 2) { nsPtr = (Namespace *) Tcl_GetCurrentNamespace(interp); } else if ((objc == 3) || (objc == 4)) { if (GetNamespaceFromObj(interp, objv[2], &namespacePtr) != TCL_OK) { return TCL_ERROR; } if (namespacePtr == NULL) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "unknown namespace \"", Tcl_GetString(objv[2]), "\" in namespace children command", (char *) NULL); return TCL_ERROR; } nsPtr = (Namespace *) namespacePtr; } else { Tcl_WrongNumArgs(interp, 2, objv, "?name? ?pattern?"); return TCL_ERROR; } /* * Get the glob-style pattern, if any, used to narrow the search. */ Tcl_DStringInit(&buffer); if (objc == 4) { char *name = Tcl_GetString(objv[3]); if ((*name == ':') && (*(name+1) == ':')) { pattern = name; } else { Tcl_DStringAppend(&buffer, nsPtr->fullName, -1); if (nsPtr != globalNsPtr) { Tcl_DStringAppend(&buffer, "::", 2); } Tcl_DStringAppend(&buffer, name, -1); pattern = Tcl_DStringValue(&buffer); } } /* * Create a list containing the full names of all child namespaces * whose names match the specified pattern, if any. */ listPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); entryPtr = Tcl_FirstHashEntry(&nsPtr->childTable, &search); while (entryPtr != NULL) { childNsPtr = (Namespace *) Tcl_GetHashValue(entryPtr); if ((pattern == NULL) || Tcl_StringMatch(childNsPtr->fullName, pattern)) { elemPtr = Tcl_NewStringObj(childNsPtr->fullName, -1); Tcl_ListObjAppendElement(interp, listPtr, elemPtr); } entryPtr = Tcl_NextHashEntry(&search); } Tcl_SetObjResult(interp, listPtr); Tcl_DStringFree(&buffer); return TCL_OK; } /* *---------------------------------------------------------------------- * * NamespaceCodeCmd -- * * Invoked to implement the "namespace code" command to capture the * namespace context of a command. Handles the following syntax: * * namespace code arg * * Here "arg" can be a list. "namespace code arg" produces a result * equivalent to that produced by the command * * list ::namespace inscope [namespace current] $arg * * However, if "arg" is itself a scoped value starting with * "::namespace inscope", then the result is just "arg". * * Results: * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong. * * Side effects: * If anything goes wrong, this procedure returns an error * message as the result in the interpreter's result object. * *---------------------------------------------------------------------- */ static int NamespaceCodeCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Namespace *currNsPtr; Tcl_Obj *listPtr, *objPtr; register char *arg, *p; int length; if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "arg"); return TCL_ERROR; } /* * If "arg" is already a scoped value, then return it directly. */ arg = Tcl_GetStringFromObj(objv[2], &length); while (*arg == ':') { arg++; length--; } if ((*arg == 'n') && (length > 17) && (strncmp(arg, "namespace", 9) == 0)) { for (p = (arg + 9); (*p == ' '); p++) { /* empty body: skip over spaces */ } if ((*p == 'i') && ((p + 7) <= (arg + length)) && (strncmp(p, "inscope", 7) == 0)) { Tcl_SetObjResult(interp, objv[2]); return TCL_OK; } } /* * Otherwise, construct a scoped command by building a list with * "namespace inscope", the full name of the current namespace, and * the argument "arg". By constructing a list, we ensure that scoped * commands are interpreted properly when they are executed later, * by the "namespace inscope" command. */ listPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewStringObj("::namespace", -1)); Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewStringObj("inscope", -1)); currNsPtr = (Namespace *) Tcl_GetCurrentNamespace(interp); if (currNsPtr == (Namespace *) Tcl_GetGlobalNamespace(interp)) { objPtr = Tcl_NewStringObj("::", -1); } else { objPtr = Tcl_NewStringObj(currNsPtr->fullName, -1); } Tcl_ListObjAppendElement(interp, listPtr, objPtr); Tcl_ListObjAppendElement(interp, listPtr, objv[2]); Tcl_SetObjResult(interp, listPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * NamespaceCurrentCmd -- * * Invoked to implement the "namespace current" command which returns * the fully-qualified name of the current namespace. Handles the * following syntax: * * namespace current * * Results: * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong. * * Side effects: * Returns a result in the interpreter's result object. If anything * goes wrong, the result is an error message. * *---------------------------------------------------------------------- */ static int NamespaceCurrentCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { register Namespace *currNsPtr; if (objc != 2) { Tcl_WrongNumArgs(interp, 2, objv, NULL); return TCL_ERROR; } /* * The "real" name of the global namespace ("::") is the null string, * but we return "::" for it as a convenience to programmers. Note that * "" and "::" are treated as synonyms by the namespace code so that it * is still easy to do things like: * * namespace [namespace current]::bar { ... } */ currNsPtr = (Namespace *) Tcl_GetCurrentNamespace(interp); if (currNsPtr == (Namespace *) Tcl_GetGlobalNamespace(interp)) { Tcl_AppendToObj(Tcl_GetObjResult(interp), "::", -1); } else { Tcl_AppendToObj(Tcl_GetObjResult(interp), currNsPtr->fullName, -1); } return TCL_OK; } /* *---------------------------------------------------------------------- * * NamespaceDeleteCmd -- * * Invoked to implement the "namespace delete" command to delete * namespace(s). Handles the following syntax: * * namespace delete ?name name...? * * Each name identifies a namespace. It may include a sequence of * namespace qualifiers separated by "::"s. If a namespace is found, it * is deleted: all variables and procedures contained in that namespace * are deleted. If that namespace is being used on the call stack, it * is kept alive (but logically deleted) until it is removed from the * call stack: that is, it can no longer be referenced by name but any * currently executing procedure that refers to it is allowed to do so * until the procedure returns. If the namespace can't be found, this * procedure returns an error. If no namespaces are specified, this * command does nothing. * * Results: * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong. * * Side effects: * Deletes the specified namespaces. If anything goes wrong, this * procedure returns an error message in the interpreter's * result object. * *---------------------------------------------------------------------- */ static int NamespaceDeleteCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Tcl_Namespace *namespacePtr; char *name; register int i; if (objc < 2) { Tcl_WrongNumArgs(interp, 2, objv, "?name name...?"); return TCL_ERROR; } /* * Destroying one namespace may cause another to be destroyed. Break * this into two passes: first check to make sure that all namespaces on * the command line are valid, and report any errors. */ for (i = 2; i < objc; i++) { name = Tcl_GetString(objv[i]); namespacePtr = Tcl_FindNamespace(interp, name, (Tcl_Namespace *) NULL, /*flags*/ 0); if (namespacePtr == NULL) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "unknown namespace \"", Tcl_GetString(objv[i]), "\" in namespace delete command", (char *) NULL); return TCL_ERROR; } } /* * Okay, now delete each namespace. */ for (i = 2; i < objc; i++) { name = Tcl_GetString(objv[i]); namespacePtr = Tcl_FindNamespace(interp, name, (Tcl_Namespace *) NULL, /* flags */ 0); if (namespacePtr) { Tcl_DeleteNamespace(namespacePtr); } } return TCL_OK; } /* *---------------------------------------------------------------------- * * NamespaceEvalCmd -- * * Invoked to implement the "namespace eval" command. Executes * commands in a namespace. If the namespace does not already exist, * it is created. Handles the following syntax: * * namespace eval name arg ?arg...? * * If more than one arg argument is specified, the command that is * executed is the result of concatenating the arguments together with * a space between each argument. * * Results: * Returns TCL_OK if the namespace is found and the commands are * executed successfully. Returns TCL_ERROR if anything goes wrong. * * Side effects: * Returns the result of the command in the interpreter's result * object. If anything goes wrong, this procedure returns an error * message as the result. * *---------------------------------------------------------------------- */ static int NamespaceEvalCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Tcl_Namespace *namespacePtr; CallFrame frame; Tcl_Obj *objPtr; char *name; int length, result; if (objc < 4) { Tcl_WrongNumArgs(interp, 2, objv, "name arg ?arg...?"); return TCL_ERROR; } /* * Try to resolve the namespace reference, caching the result in the * namespace object along the way. */ result = GetNamespaceFromObj(interp, objv[2], &namespacePtr); if (result != TCL_OK) { return result; } /* * If the namespace wasn't found, try to create it. */ if (namespacePtr == NULL) { name = Tcl_GetStringFromObj(objv[2], &length); namespacePtr = Tcl_CreateNamespace(interp, name, (ClientData) NULL, (Tcl_NamespaceDeleteProc *) NULL); if (namespacePtr == NULL) { return TCL_ERROR; } } /* * Make the specified namespace the current namespace and evaluate * the command(s). */ result = Tcl_PushCallFrame(interp, (Tcl_CallFrame *) &frame, namespacePtr, /*isProcCallFrame*/ 0); if (result != TCL_OK) { return TCL_ERROR; } frame.objc = objc; frame.objv = objv; /* ref counts do not need to be incremented here */ if (objc == 4) { #ifndef TCL_TIP280 result = Tcl_EvalObjEx(interp, objv[3], 0); #else /* TIP #280 : Make actual argument location available to eval'd script */ Interp* iPtr = (Interp*) interp; CmdFrame* invoker = iPtr->cmdFramePtr; int word = 3; TclArgumentGet (interp, objv[3], &invoker, &word); result = TclEvalObjEx(interp, objv[3], 0, invoker, word); #endif } else { /* * More than one argument: concatenate them together with spaces * between, then evaluate the result. Tcl_EvalObjEx will delete * the object when it decrements its refcount after eval'ing it. */ objPtr = Tcl_ConcatObj(objc-3, objv+3); #ifndef TCL_TIP280 result = Tcl_EvalObjEx(interp, objPtr, TCL_EVAL_DIRECT); #else /* TIP #280. Make invoking context available to eval'd script */ result = TclEvalObjEx(interp, objPtr, TCL_EVAL_DIRECT, NULL, 0); #endif } if (result == TCL_ERROR) { char msg[256 + TCL_INTEGER_SPACE]; sprintf(msg, "\n (in namespace eval \"%.200s\" script line %d)", namespacePtr->fullName, interp->errorLine); Tcl_AddObjErrorInfo(interp, msg, -1); } /* * Restore the previous "current" namespace. */ Tcl_PopCallFrame(interp); return result; } /* *---------------------------------------------------------------------- * * NamespaceExistsCmd -- * * Invoked to implement the "namespace exists" command that returns * true if the given namespace currently exists, and false otherwise. * Handles the following syntax: * * namespace exists name * * Results: * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong. * * Side effects: * Returns a result in the interpreter's result object. If anything * goes wrong, the result is an error message. * *---------------------------------------------------------------------- */ static int NamespaceExistsCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Tcl_Namespace *namespacePtr; if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "name"); return TCL_ERROR; } /* * Check whether the given namespace exists */ if (GetNamespaceFromObj(interp, objv[2], &namespacePtr) != TCL_OK) { return TCL_ERROR; } Tcl_SetBooleanObj(Tcl_GetObjResult(interp), (namespacePtr != NULL)); return TCL_OK; } /* *---------------------------------------------------------------------- * * NamespaceExportCmd -- * * Invoked to implement the "namespace export" command that specifies * which commands are exported from a namespace. The exported commands * are those that can be imported into another namespace using * "namespace import". Both commands defined in a namespace and * commands the namespace has imported can be exported by a * namespace. This command has the following syntax: * * namespace export ?-clear? ?pattern pattern...? * * Each pattern may contain "string match"-style pattern matching * special characters, but the pattern may not include any namespace * qualifiers: that is, the pattern must specify commands in the * current (exporting) namespace. The specified patterns are appended * onto the namespace's list of export patterns. * * To reset the namespace's export pattern list, specify the "-clear" * flag. * * If there are no export patterns and the "-clear" flag isn't given, * this command returns the namespace's current export list. * * Results: * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong. * * Side effects: * Returns a result in the interpreter's result object. If anything * goes wrong, the result is an error message. * *---------------------------------------------------------------------- */ static int NamespaceExportCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int firstArg, i; if (objc < 2) { Tcl_WrongNumArgs(interp, 2, objv, "?-clear? ?pattern pattern...?"); return TCL_ERROR; } /* * If no pattern arguments are given, and "-clear" isn't specified, * return the namespace's current export pattern list. */ if (objc == 2) { Tcl_Obj *listPtr = Tcl_NewObj(); (void) Tcl_AppendExportList(interp, NULL, listPtr); Tcl_SetObjResult(interp, listPtr); return TCL_OK; } /* * Process the optional "-clear" argument. */ firstArg = 2; if (strcmp("-clear", Tcl_GetString(objv[firstArg])) == 0) { Tcl_Export(interp, NULL, "::", 1); Tcl_ResetResult(interp); firstArg++; } /* * Add each pattern to the namespace's export pattern list. */ for (i = firstArg; i < objc; i++) { int result = Tcl_Export(interp, NULL, Tcl_GetString(objv[i]), 0); if (result != TCL_OK) { return result; } } return TCL_OK; } /* *---------------------------------------------------------------------- * * NamespaceForgetCmd -- * * Invoked to implement the "namespace forget" command to remove * imported commands from a namespace. Handles the following syntax: * * namespace forget ?pattern pattern...? * * Each pattern is a name like "foo::*" or "a::b::x*". That is, the * pattern may include the special pattern matching characters * recognized by the "string match" command, but only in the command * name at the end of the qualified name; the special pattern * characters may not appear in a namespace name. All of the commands * that match that pattern are checked to see if they have an imported * command in the current namespace that refers to the matched * command. If there is an alias, it is removed. * * Results: * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong. * * Side effects: * Imported commands are removed from the current namespace. If * anything goes wrong, this procedure returns an error message in the * interpreter's result object. * *---------------------------------------------------------------------- */ static int NamespaceForgetCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { char *pattern; register int i, result; if (objc < 2) { Tcl_WrongNumArgs(interp, 2, objv, "?pattern pattern...?"); return TCL_ERROR; } for (i = 2; i < objc; i++) { pattern = Tcl_GetString(objv[i]); result = Tcl_ForgetImport(interp, (Tcl_Namespace *) NULL, pattern); if (result != TCL_OK) { return result; } } return TCL_OK; } /* *---------------------------------------------------------------------- * * NamespaceImportCmd -- * * Invoked to implement the "namespace import" command that imports * commands into a namespace. Handles the following syntax: * * namespace import ?-force? ?pattern pattern...? * * Each pattern is a namespace-qualified name like "foo::*", * "a::b::x*", or "bar::p". That is, the pattern may include the * special pattern matching characters recognized by the "string match" * command, but only in the command name at the end of the qualified * name; the special pattern characters may not appear in a namespace * name. All of the commands that match the pattern and which are * exported from their namespace are made accessible from the current * namespace context. This is done by creating a new "imported command" * in the current namespace that points to the real command in its * original namespace; when the imported command is called, it invokes * the real command. * * If an imported command conflicts with an existing command, it is * treated as an error. But if the "-force" option is included, then * existing commands are overwritten by the imported commands. * * Results: * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong. * * Side effects: * Adds imported commands to the current namespace. If anything goes * wrong, this procedure returns an error message in the interpreter's * result object. * *---------------------------------------------------------------------- */ static int NamespaceImportCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int allowOverwrite = 0; char *string, *pattern; register int i, result; int firstArg; if (objc < 2) { Tcl_WrongNumArgs(interp, 2, objv, "?-force? ?pattern pattern...?"); return TCL_ERROR; } /* * Skip over the optional "-force" as the first argument. */ firstArg = 2; if (firstArg < objc) { string = Tcl_GetString(objv[firstArg]); if ((*string == '-') && (strcmp(string, "-force") == 0)) { allowOverwrite = 1; firstArg++; } } /* * Handle the imports for each of the patterns. */ for (i = firstArg; i < objc; i++) { pattern = Tcl_GetString(objv[i]); result = Tcl_Import(interp, (Tcl_Namespace *) NULL, pattern, allowOverwrite); if (result != TCL_OK) { return result; } } return TCL_OK; } /* *---------------------------------------------------------------------- * * NamespaceInscopeCmd -- * * Invoked to implement the "namespace inscope" command that executes a * script in the context of a particular namespace. This command is not * expected to be used directly by programmers; calls to it are * generated implicitly when programs use "namespace code" commands * to register callback scripts. Handles the following syntax: * * namespace inscope name arg ?arg...? * * The "namespace inscope" command is much like the "namespace eval" * command except that it has lappend semantics and the namespace must * already exist. It treats the first argument as a list, and appends * any arguments after the first onto the end as proper list elements. * For example, * * namespace inscope ::foo a b c d * * is equivalent to * * namespace eval ::foo [concat a [list b c d]] * * This lappend semantics is important because many callback scripts * are actually prefixes. * * Results: * Returns TCL_OK to indicate success, or TCL_ERROR to indicate * failure. * * Side effects: * Returns a result in the Tcl interpreter's result object. * *---------------------------------------------------------------------- */ static int NamespaceInscopeCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Tcl_Namespace *namespacePtr; Tcl_CallFrame frame; int i, result; if (objc < 4) { Tcl_WrongNumArgs(interp, 2, objv, "name arg ?arg...?"); return TCL_ERROR; } /* * Resolve the namespace reference. */ result = GetNamespaceFromObj(interp, objv[2], &namespacePtr); if (result != TCL_OK) { return result; } if (namespacePtr == NULL) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "unknown namespace \"", Tcl_GetString(objv[2]), "\" in inscope namespace command", (char *) NULL); return TCL_ERROR; } /* * Make the specified namespace the current namespace. */ result = Tcl_PushCallFrame(interp, &frame, namespacePtr, /*isProcCallFrame*/ 0); if (result != TCL_OK) { return result; } /* * Execute the command. If there is just one argument, just treat it as * a script and evaluate it. Otherwise, create a list from the arguments * after the first one, then concatenate the first argument and the list * of extra arguments to form the command to evaluate. */ if (objc == 4) { result = Tcl_EvalObjEx(interp, objv[3], 0); } else { Tcl_Obj *concatObjv[2]; register Tcl_Obj *listPtr, *cmdObjPtr; listPtr = Tcl_NewListObj(0, (Tcl_Obj **) NULL); for (i = 4; i < objc; i++) { result = Tcl_ListObjAppendElement(interp, listPtr, objv[i]); if (result != TCL_OK) { Tcl_DecrRefCount(listPtr); /* free unneeded obj */ return result; } } concatObjv[0] = objv[3]; concatObjv[1] = listPtr; cmdObjPtr = Tcl_ConcatObj(2, concatObjv); result = Tcl_EvalObjEx(interp, cmdObjPtr, TCL_EVAL_DIRECT); Tcl_DecrRefCount(listPtr); /* we're done with the list object */ } if (result == TCL_ERROR) { char msg[256 + TCL_INTEGER_SPACE]; sprintf(msg, "\n (in namespace inscope \"%.200s\" script line %d)", namespacePtr->fullName, interp->errorLine); Tcl_AddObjErrorInfo(interp, msg, -1); } /* * Restore the previous "current" namespace. */ Tcl_PopCallFrame(interp); return result; } /* *---------------------------------------------------------------------- * * NamespaceOriginCmd -- * * Invoked to implement the "namespace origin" command to return the * fully-qualified name of the "real" command to which the specified * "imported command" refers. Handles the following syntax: * * namespace origin name * * Results: * An imported command is created in an namespace when that namespace * imports a command from another namespace. If a command is imported * into a sequence of namespaces a, b,...,n where each successive * namespace just imports the command from the previous namespace, this * command returns the fully-qualified name of the original command in * the first namespace, a. If "name" does not refer to an alias, its * fully-qualified name is returned. The returned name is stored in the * interpreter's result object. This procedure returns TCL_OK if * successful, and TCL_ERROR if anything goes wrong. * * Side effects: * If anything goes wrong, this procedure returns an error message in * the interpreter's result object. * *---------------------------------------------------------------------- */ static int NamespaceOriginCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Tcl_Command command, origCommand; if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "name"); return TCL_ERROR; } command = Tcl_GetCommandFromObj(interp, objv[2]); if (command == (Tcl_Command) NULL) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "invalid command name \"", Tcl_GetString(objv[2]), "\"", (char *) NULL); return TCL_ERROR; } origCommand = TclGetOriginalCommand(command); if (origCommand == (Tcl_Command) NULL) { /* * The specified command isn't an imported command. Return the * command's name qualified by the full name of the namespace it * was defined in. */ Tcl_GetCommandFullName(interp, command, Tcl_GetObjResult(interp)); } else { Tcl_GetCommandFullName(interp, origCommand, Tcl_GetObjResult(interp)); } return TCL_OK; } /* *---------------------------------------------------------------------- * * NamespaceParentCmd -- * * Invoked to implement the "namespace parent" command that returns the * fully-qualified name of the parent namespace for a specified * namespace. Handles the following syntax: * * namespace parent ?name? * * Results: * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong. * * Side effects: * Returns a result in the interpreter's result object. If anything * goes wrong, the result is an error message. * *---------------------------------------------------------------------- */ static int NamespaceParentCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Tcl_Namespace *nsPtr; int result; if (objc == 2) { nsPtr = Tcl_GetCurrentNamespace(interp); } else if (objc == 3) { result = GetNamespaceFromObj(interp, objv[2], &nsPtr); if (result != TCL_OK) { return result; } if (nsPtr == NULL) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "unknown namespace \"", Tcl_GetString(objv[2]), "\" in namespace parent command", (char *) NULL); return TCL_ERROR; } } else { Tcl_WrongNumArgs(interp, 2, objv, "?name?"); return TCL_ERROR; } /* * Report the parent of the specified namespace. */ if (nsPtr->parentPtr != NULL) { Tcl_SetStringObj(Tcl_GetObjResult(interp), nsPtr->parentPtr->fullName, -1); } return TCL_OK; } /* *---------------------------------------------------------------------- * * NamespaceQualifiersCmd -- * * Invoked to implement the "namespace qualifiers" command that returns * any leading namespace qualifiers in a string. These qualifiers are * namespace names separated by "::"s. For example, for "::foo::p" this * command returns "::foo", and for "::" it returns "". This command * is the complement of the "namespace tail" command. Note that this * command does not check whether the "namespace" names are, in fact, * the names of currently defined namespaces. Handles the following * syntax: * * namespace qualifiers string * * Results: * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong. * * Side effects: * Returns a result in the interpreter's result object. If anything * goes wrong, the result is an error message. * *---------------------------------------------------------------------- */ static int NamespaceQualifiersCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { register char *name, *p; int length; if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "string"); return TCL_ERROR; } /* * Find the end of the string, then work backward and find * the start of the last "::" qualifier. */ name = Tcl_GetString(objv[2]); for (p = name; *p != '\0'; p++) { /* empty body */ } while (--p >= name) { if ((*p == ':') && (p > name) && (*(p-1) == ':')) { p -= 2; /* back up over the :: */ while ((p >= name) && (*p == ':')) { p--; /* back up over the preceeding : */ } break; } } if (p >= name) { length = p-name+1; Tcl_AppendToObj(Tcl_GetObjResult(interp), name, length); } return TCL_OK; } /* *---------------------------------------------------------------------- * * NamespaceTailCmd -- * * Invoked to implement the "namespace tail" command that returns the * trailing name at the end of a string with "::" namespace * qualifiers. These qualifiers are namespace names separated by * "::"s. For example, for "::foo::p" this command returns "p", and for * "::" it returns "". This command is the complement of the "namespace * qualifiers" command. Note that this command does not check whether * the "namespace" names are, in fact, the names of currently defined * namespaces. Handles the following syntax: * * namespace tail string * * Results: * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong. * * Side effects: * Returns a result in the interpreter's result object. If anything * goes wrong, the result is an error message. * *---------------------------------------------------------------------- */ static int NamespaceTailCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { register char *name, *p; if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "string"); return TCL_ERROR; } /* * Find the end of the string, then work backward and find the * last "::" qualifier. */ name = Tcl_GetString(objv[2]); for (p = name; *p != '\0'; p++) { /* empty body */ } while (--p > name) { if ((*p == ':') && (*(p-1) == ':')) { p++; /* just after the last "::" */ break; } } if (p >= name) { Tcl_AppendToObj(Tcl_GetObjResult(interp), p, -1); } return TCL_OK; } /* *---------------------------------------------------------------------- * * NamespaceWhichCmd -- * * Invoked to implement the "namespace which" command that returns the * fully-qualified name of a command or variable. If the specified * command or variable does not exist, it returns "". Handles the * following syntax: * * namespace which ?-command? ?-variable? name * * Results: * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong. * * Side effects: * Returns a result in the interpreter's result object. If anything * goes wrong, the result is an error message. * *---------------------------------------------------------------------- */ static int NamespaceWhichCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { register char *arg; Tcl_Command cmd; Tcl_Var variable; int argIndex, lookup; if (objc < 3) { badArgs: Tcl_WrongNumArgs(interp, 2, objv, "?-command? ?-variable? name"); return TCL_ERROR; } /* * Look for a flag controlling the lookup. */ argIndex = 2; lookup = 0; /* assume command lookup by default */ arg = Tcl_GetString(objv[2]); if (*arg == '-') { if (strncmp(arg, "-command", 8) == 0) { lookup = 0; } else if (strncmp(arg, "-variable", 9) == 0) { lookup = 1; } else { goto badArgs; } argIndex = 3; } if (objc != (argIndex + 1)) { goto badArgs; } switch (lookup) { case 0: /* -command */ cmd = Tcl_GetCommandFromObj(interp, objv[argIndex]); if (cmd == (Tcl_Command) NULL) { return TCL_OK; /* cmd not found, just return (no error) */ } Tcl_GetCommandFullName(interp, cmd, Tcl_GetObjResult(interp)); break; case 1: /* -variable */ arg = Tcl_GetString(objv[argIndex]); variable = Tcl_FindNamespaceVar(interp, arg, (Tcl_Namespace *) NULL, /*flags*/ 0); if (variable != (Tcl_Var) NULL) { Tcl_GetVariableFullName(interp, variable, Tcl_GetObjResult(interp)); } break; } return TCL_OK; } /* *---------------------------------------------------------------------- * * FreeNsNameInternalRep -- * * Frees the resources associated with a nsName object's internal * representation. * * Results: * None. * * Side effects: * Decrements the ref count of any Namespace structure pointed * to by the nsName's internal representation. If there are no more * references to the namespace, it's structure will be freed. * *---------------------------------------------------------------------- */ static void FreeNsNameInternalRep(objPtr) register Tcl_Obj *objPtr; /* nsName object with internal * representation to free */ { register ResolvedNsName *resNamePtr = (ResolvedNsName *) objPtr->internalRep.otherValuePtr; Namespace *nsPtr; /* * Decrement the reference count of the namespace. If there are no * more references, free it up. */ if (resNamePtr != NULL) { resNamePtr->refCount--; if (resNamePtr->refCount == 0) { /* * Decrement the reference count for the cached namespace. If * the namespace is dead, and there are no more references to * it, free it. */ nsPtr = resNamePtr->nsPtr; nsPtr->refCount--; if ((nsPtr->refCount == 0) && (nsPtr->flags & NS_DEAD)) { NamespaceFree(nsPtr); } ckfree((char *) resNamePtr); } } } /* *---------------------------------------------------------------------- * * DupNsNameInternalRep -- * * Initializes the internal representation of a nsName object to a copy * of the internal representation of another nsName object. * * Results: * None. * * Side effects: * copyPtr's internal rep is set to refer to the same namespace * referenced by srcPtr's internal rep. Increments the ref count of * the ResolvedNsName structure used to hold the namespace reference. * *---------------------------------------------------------------------- */ static void DupNsNameInternalRep(srcPtr, copyPtr) Tcl_Obj *srcPtr; /* Object with internal rep to copy. */ register Tcl_Obj *copyPtr; /* Object with internal rep to set. */ { register ResolvedNsName *resNamePtr = (ResolvedNsName *) srcPtr->internalRep.otherValuePtr; copyPtr->internalRep.otherValuePtr = (VOID *) resNamePtr; if (resNamePtr != NULL) { resNamePtr->refCount++; } copyPtr->typePtr = &tclNsNameType; } /* *---------------------------------------------------------------------- * * SetNsNameFromAny -- * * Attempt to generate a nsName internal representation for a * Tcl object. * * Results: * Returns TCL_OK if the value could be converted to a proper * namespace reference. Otherwise, it returns TCL_ERROR, along * with an error message in the interpreter's result object. * * Side effects: * If successful, the object is made a nsName object. Its internal rep * is set to point to a ResolvedNsName, which contains a cached pointer * to the Namespace. Reference counts are kept on both the * ResolvedNsName and the Namespace, so we can keep track of their * usage and free them when appropriate. * *---------------------------------------------------------------------- */ static int SetNsNameFromAny(interp, objPtr) Tcl_Interp *interp; /* Points to the namespace in which to * resolve name. Also used for error * reporting if not NULL. */ register Tcl_Obj *objPtr; /* The object to convert. */ { register Tcl_ObjType *oldTypePtr = objPtr->typePtr; char *name; CONST char *dummy; Namespace *nsPtr, *dummy1Ptr, *dummy2Ptr; register ResolvedNsName *resNamePtr; if (interp == NULL) { return TCL_ERROR; } /* * Get the string representation. Make it up-to-date if necessary. */ name = objPtr->bytes; if (name == NULL) { name = Tcl_GetString(objPtr); } /* * Look for the namespace "name" in the current namespace. If there is * an error parsing the (possibly qualified) name, return an error. * If the namespace isn't found, we convert the object to an nsName * object with a NULL ResolvedNsName* internal rep. */ TclGetNamespaceForQualName(interp, name, (Namespace *) NULL, FIND_ONLY_NS, &nsPtr, &dummy1Ptr, &dummy2Ptr, &dummy); /* * If we found a namespace, then create a new ResolvedNsName structure * that holds a reference to it. */ if (nsPtr != NULL) { Namespace *currNsPtr = (Namespace *) Tcl_GetCurrentNamespace(interp); nsPtr->refCount++; resNamePtr = (ResolvedNsName *) ckalloc(sizeof(ResolvedNsName)); resNamePtr->nsPtr = nsPtr; resNamePtr->nsId = nsPtr->nsId; resNamePtr->refNsPtr = currNsPtr; resNamePtr->refCount = 1; } else { resNamePtr = NULL; } /* * Free the old internalRep before setting the new one. * We do this as late as possible to allow the conversion code * (in particular, Tcl_GetStringFromObj) to use that old internalRep. */ if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) { oldTypePtr->freeIntRepProc(objPtr); } objPtr->internalRep.otherValuePtr = (VOID *) resNamePtr; objPtr->typePtr = &tclNsNameType; return TCL_OK; } /* *---------------------------------------------------------------------- * * UpdateStringOfNsName -- * * Updates the string representation for a nsName object. * Note: This procedure does not free an existing old string rep * so storage will be lost if this has not already been done. * * Results: * None. * * Side effects: * The object's string is set to a copy of the fully qualified * namespace name. * *---------------------------------------------------------------------- */ static void UpdateStringOfNsName(objPtr) register Tcl_Obj *objPtr; /* nsName object with string rep to update. */ { ResolvedNsName *resNamePtr = (ResolvedNsName *) objPtr->internalRep.otherValuePtr; register Namespace *nsPtr; char *name = ""; int length; if ((resNamePtr != NULL) && (resNamePtr->nsId == resNamePtr->nsPtr->nsId)) { nsPtr = resNamePtr->nsPtr; if (nsPtr->flags & NS_DEAD) { nsPtr = NULL; } if (nsPtr != NULL) { name = nsPtr->fullName; } } /* * The following sets the string rep to an empty string on the heap * if the internal rep is NULL. */ length = strlen(name); if (length == 0) { objPtr->bytes = tclEmptyStringRep; } else { objPtr->bytes = (char *) ckalloc((unsigned) (length + 1)); memcpy((VOID *) objPtr->bytes, (VOID *) name, (unsigned) length); objPtr->bytes[length] = '\0'; } objPtr->length = length; } tcl8.4.20/generic/tclPipe.c0000644003604700454610000007645312052456744014115 0ustar dgp771div/* * tclPipe.c -- * * This file contains the generic portion of the command channel * driver as well as various utility routines used in managing * subprocesses. * * Copyright (c) 1997 by Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" /* * A linked list of the following structures is used to keep track * of child processes that have been detached but haven't exited * yet, so we can make sure that they're properly "reaped" (officially * waited for) and don't lie around as zombies cluttering the * system. */ typedef struct Detached { Tcl_Pid pid; /* Id of process that's been detached * but isn't known to have exited. */ struct Detached *nextPtr; /* Next in list of all detached * processes. */ } Detached; static Detached *detList = NULL; /* List of all detached proceses. */ TCL_DECLARE_MUTEX(pipeMutex) /* Guard access to detList. */ /* * Declarations for local procedures defined in this file: */ static TclFile FileForRedirect _ANSI_ARGS_((Tcl_Interp *interp, CONST char *spec, int atOk, CONST char *arg, CONST char *nextArg, int flags, int *skipPtr, int *closePtr, int *releasePtr)); /* *---------------------------------------------------------------------- * * FileForRedirect -- * * This procedure does much of the work of parsing redirection * operators. It handles "@" if specified and allowed, and a file * name, and opens the file if necessary. * * Results: * The return value is the descriptor number for the file. If an * error occurs then NULL is returned and an error message is left * in the interp's result. Several arguments are side-effected; see * the argument list below for details. * * Side effects: * None. * *---------------------------------------------------------------------- */ static TclFile FileForRedirect(interp, spec, atOK, arg, nextArg, flags, skipPtr, closePtr, releasePtr) Tcl_Interp *interp; /* Intepreter to use for error reporting. */ CONST char *spec; /* Points to character just after * redirection character. */ int atOK; /* Non-zero means that '@' notation can be * used to specify a channel, zero means that * it isn't. */ CONST char *arg; /* Pointer to entire argument containing * spec: used for error reporting. */ CONST char *nextArg; /* Next argument in argc/argv array, if needed * for file name or channel name. May be * NULL. */ int flags; /* Flags to use for opening file or to * specify mode for channel. */ int *skipPtr; /* Filled with 1 if redirection target was * in spec, 2 if it was in nextArg. */ int *closePtr; /* Filled with one if the caller should * close the file when done with it, zero * otherwise. */ int *releasePtr; { int writing = (flags & O_WRONLY); Tcl_Channel chan; TclFile file; *skipPtr = 1; if ((atOK != 0) && (*spec == '@')) { spec++; if (*spec == '\0') { spec = nextArg; if (spec == NULL) { goto badLastArg; } *skipPtr = 2; } chan = Tcl_GetChannel(interp, spec, NULL); if (chan == (Tcl_Channel) NULL) { return NULL; } file = TclpMakeFile(chan, writing ? TCL_WRITABLE : TCL_READABLE); if (file == NULL) { Tcl_AppendResult(interp, "channel \"", Tcl_GetChannelName(chan), "\" wasn't opened for ", ((writing) ? "writing" : "reading"), (char *) NULL); return NULL; } *releasePtr = 1; if (writing) { /* * Be sure to flush output to the file, so that anything * written by the child appears after stuff we've already * written. */ Tcl_Flush(chan); } } else { CONST char *name; Tcl_DString nameString; if (*spec == '\0') { spec = nextArg; if (spec == NULL) { goto badLastArg; } *skipPtr = 2; } name = Tcl_TranslateFileName(interp, spec, &nameString); if (name == NULL) { return NULL; } file = TclpOpenFile(name, flags); Tcl_DStringFree(&nameString); if (file == NULL) { Tcl_AppendResult(interp, "couldn't ", ((writing) ? "write" : "read"), " file \"", spec, "\": ", Tcl_PosixError(interp), (char *) NULL); return NULL; } *closePtr = 1; } return file; badLastArg: Tcl_AppendResult(interp, "can't specify \"", arg, "\" as last word in command", (char *) NULL); return NULL; } /* *---------------------------------------------------------------------- * * Tcl_DetachPids -- * * This procedure is called to indicate that one or more child * processes have been placed in background and will never be * waited for; they should eventually be reaped by * Tcl_ReapDetachedProcs. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Tcl_DetachPids(numPids, pidPtr) int numPids; /* Number of pids to detach: gives size * of array pointed to by pidPtr. */ Tcl_Pid *pidPtr; /* Array of pids to detach. */ { register Detached *detPtr; int i; Tcl_MutexLock(&pipeMutex); for (i = 0; i < numPids; i++) { detPtr = (Detached *) ckalloc(sizeof(Detached)); detPtr->pid = pidPtr[i]; detPtr->nextPtr = detList; detList = detPtr; } Tcl_MutexUnlock(&pipeMutex); } /* *---------------------------------------------------------------------- * * Tcl_ReapDetachedProcs -- * * This procedure checks to see if any detached processes have * exited and, if so, it "reaps" them by officially waiting on * them. It should be called "occasionally" to make sure that * all detached processes are eventually reaped. * * Results: * None. * * Side effects: * Processes are waited on, so that they can be reaped by the * system. * *---------------------------------------------------------------------- */ void Tcl_ReapDetachedProcs() { register Detached *detPtr; Detached *nextPtr, *prevPtr; int status; Tcl_Pid pid; Tcl_MutexLock(&pipeMutex); for (detPtr = detList, prevPtr = NULL; detPtr != NULL; ) { pid = Tcl_WaitPid(detPtr->pid, &status, WNOHANG); if ((pid == 0) || ((pid == (Tcl_Pid) -1) && (errno != ECHILD))) { prevPtr = detPtr; detPtr = detPtr->nextPtr; continue; } nextPtr = detPtr->nextPtr; if (prevPtr == NULL) { detList = detPtr->nextPtr; } else { prevPtr->nextPtr = detPtr->nextPtr; } ckfree((char *) detPtr); detPtr = nextPtr; } Tcl_MutexUnlock(&pipeMutex); } /* *---------------------------------------------------------------------- * * TclCleanupChildren -- * * This is a utility procedure used to wait for child processes * to exit, record information about abnormal exits, and then * collect any stderr output generated by them. * * Results: * The return value is a standard Tcl result. If anything at * weird happened with the child processes, TCL_ERROR is returned * and a message is left in the interp's result. * * Side effects: * If the last character of the interp's result is a newline, then it * is removed unless keepNewline is non-zero. File errorId gets * closed, and pidPtr is freed back to the storage allocator. * *---------------------------------------------------------------------- */ int TclCleanupChildren(interp, numPids, pidPtr, errorChan) Tcl_Interp *interp; /* Used for error messages. */ int numPids; /* Number of entries in pidPtr array. */ Tcl_Pid *pidPtr; /* Array of process ids of children. */ Tcl_Channel errorChan; /* Channel for file containing stderr output * from pipeline. NULL means there isn't any * stderr output. */ { int result = TCL_OK; int i, abnormalExit, anyErrorInfo; Tcl_Pid pid; WAIT_STATUS_TYPE waitStatus; CONST char *msg; unsigned long resolvedPid; abnormalExit = 0; for (i = 0; i < numPids; i++) { /* * We need to get the resolved pid before we wait on it as * the windows implementation of Tcl_WaitPid deletes the * information such that any following calls to TclpGetPid * fail. */ resolvedPid = TclpGetPid(pidPtr[i]); pid = Tcl_WaitPid(pidPtr[i], (int *) &waitStatus, 0); if (pid == (Tcl_Pid) -1) { result = TCL_ERROR; if (interp != (Tcl_Interp *) NULL) { msg = Tcl_PosixError(interp); if (errno == ECHILD) { /* * This changeup in message suggested by Mark Diekhans * to remind people that ECHILD errors can occur on * some systems if SIGCHLD isn't in its default state. */ msg = "child process lost (is SIGCHLD ignored or trapped?)"; } Tcl_AppendResult(interp, "error waiting for process to exit: ", msg, (char *) NULL); } continue; } /* * Create error messages for unusual process exits. An * extra newline gets appended to each error message, but * it gets removed below (in the same fashion that an * extra newline in the command's output is removed). */ if (!WIFEXITED(waitStatus) || (WEXITSTATUS(waitStatus) != 0)) { char msg1[TCL_INTEGER_SPACE], msg2[TCL_INTEGER_SPACE]; result = TCL_ERROR; TclFormatInt(msg1, (long) resolvedPid); if (WIFEXITED(waitStatus)) { if (interp != (Tcl_Interp *) NULL) { TclFormatInt(msg2, WEXITSTATUS(waitStatus)); Tcl_SetErrorCode(interp, "CHILDSTATUS", msg1, msg2, (char *) NULL); } abnormalExit = 1; } else if (WIFSIGNALED(waitStatus)) { if (interp != (Tcl_Interp *) NULL) { CONST char *p; p = Tcl_SignalMsg((int) (WTERMSIG(waitStatus))); Tcl_SetErrorCode(interp, "CHILDKILLED", msg1, Tcl_SignalId((int) (WTERMSIG(waitStatus))), p, (char *) NULL); Tcl_AppendResult(interp, "child killed: ", p, "\n", (char *) NULL); } } else if (WIFSTOPPED(waitStatus)) { if (interp != (Tcl_Interp *) NULL) { CONST char *p; p = Tcl_SignalMsg((int) (WSTOPSIG(waitStatus))); Tcl_SetErrorCode(interp, "CHILDSUSP", msg1, Tcl_SignalId((int) (WSTOPSIG(waitStatus))), p, (char *) NULL); Tcl_AppendResult(interp, "child suspended: ", p, "\n", (char *) NULL); } } else { if (interp != (Tcl_Interp *) NULL) { Tcl_AppendResult(interp, "child wait status didn't make sense\n", (char *) NULL); } } } } /* * Read the standard error file. If there's anything there, * then return an error and add the file's contents to the result * string. */ anyErrorInfo = 0; if (errorChan != NULL) { /* * Make sure we start at the beginning of the file. */ if (interp != NULL) { int count; Tcl_Obj *objPtr; Tcl_Seek(errorChan, (Tcl_WideInt)0, SEEK_SET); objPtr = Tcl_NewObj(); count = Tcl_ReadChars(errorChan, objPtr, -1, 0); if (count < 0) { result = TCL_ERROR; Tcl_DecrRefCount(objPtr); Tcl_ResetResult(interp); Tcl_AppendResult(interp, "error reading stderr output file: ", Tcl_PosixError(interp), NULL); } else if (count > 0) { anyErrorInfo = 1; Tcl_SetObjResult(interp, objPtr); result = TCL_ERROR; } else { Tcl_DecrRefCount(objPtr); } } Tcl_Close(NULL, errorChan); } /* * If a child exited abnormally but didn't output any error information * at all, generate an error message here. */ if ((abnormalExit != 0) && (anyErrorInfo == 0) && (interp != NULL)) { Tcl_AppendResult(interp, "child process exited abnormally", (char *) NULL); } return result; } /* *---------------------------------------------------------------------- * * TclCreatePipeline -- * * Given an argc/argv array, instantiate a pipeline of processes * as described by the argv. * * This procedure is unofficially exported for use by BLT. * * Results: * The return value is a count of the number of new processes * created, or -1 if an error occurred while creating the pipeline. * *pidArrayPtr is filled in with the address of a dynamically * allocated array giving the ids of all of the processes. It * is up to the caller to free this array when it isn't needed * anymore. If inPipePtr is non-NULL, *inPipePtr is filled in * with the file id for the input pipe for the pipeline (if any): * the caller must eventually close this file. If outPipePtr * isn't NULL, then *outPipePtr is filled in with the file id * for the output pipe from the pipeline: the caller must close * this file. If errFilePtr isn't NULL, then *errFilePtr is filled * with a file id that may be used to read error output after the * pipeline completes. * * Side effects: * Processes and pipes are created. * *---------------------------------------------------------------------- */ int TclCreatePipeline(interp, argc, argv, pidArrayPtr, inPipePtr, outPipePtr, errFilePtr) Tcl_Interp *interp; /* Interpreter to use for error reporting. */ int argc; /* Number of entries in argv. */ CONST char **argv; /* Array of strings describing commands in * pipeline plus I/O redirection with <, * <<, >, etc. Argv[argc] must be NULL. */ Tcl_Pid **pidArrayPtr; /* Word at *pidArrayPtr gets filled in with * address of array of pids for processes * in pipeline (first pid is first process * in pipeline). */ TclFile *inPipePtr; /* If non-NULL, input to the pipeline comes * from a pipe (unless overridden by * redirection in the command). The file * id with which to write to this pipe is * stored at *inPipePtr. NULL means command * specified its own input source. */ TclFile *outPipePtr; /* If non-NULL, output to the pipeline goes * to a pipe, unless overriden by redirection * in the command. The file id with which to * read frome this pipe is stored at * *outPipePtr. NULL means command specified * its own output sink. */ TclFile *errFilePtr; /* If non-NULL, all stderr output from the * pipeline will go to a temporary file * created here, and a descriptor to read * the file will be left at *errFilePtr. * The file will be removed already, so * closing this descriptor will be the end * of the file. If this is NULL, then * all stderr output goes to our stderr. * If the pipeline specifies redirection * then the file will still be created * but it will never get any data. */ { Tcl_Pid *pidPtr = NULL; /* Points to malloc-ed array holding all * the pids of child processes. */ int numPids; /* Actual number of processes that exist * at *pidPtr right now. */ int cmdCount; /* Count of number of distinct commands * found in argc/argv. */ CONST char *inputLiteral = NULL; /* If non-null, then this points to a * string containing input data (specified * via <<) to be piped to the first process * in the pipeline. */ TclFile inputFile = NULL; /* If != NULL, gives file to use as input for * first process in pipeline (specified via < * or <@). */ int inputClose = 0; /* If non-zero, then inputFile should be * closed when cleaning up. */ int inputRelease = 0; TclFile outputFile = NULL; /* Writable file for output from last command * in pipeline (could be file or pipe). NULL * means use stdout. */ int outputClose = 0; /* If non-zero, then outputFile should be * closed when cleaning up. */ int outputRelease = 0; TclFile errorFile = NULL; /* Writable file for error output from all * commands in pipeline. NULL means use * stderr. */ int errorClose = 0; /* If non-zero, then errorFile should be * closed when cleaning up. */ int errorRelease = 0; CONST char *p; CONST char *nextArg; int skip, lastBar, lastArg, i, j, atOK, flags, needCmd, errorToOutput = 0; Tcl_DString execBuffer; TclFile pipeIn; TclFile curInFile, curOutFile, curErrFile; Tcl_Channel channel; if (inPipePtr != NULL) { *inPipePtr = NULL; } if (outPipePtr != NULL) { *outPipePtr = NULL; } if (errFilePtr != NULL) { *errFilePtr = NULL; } Tcl_DStringInit(&execBuffer); pipeIn = NULL; curInFile = NULL; curOutFile = NULL; numPids = 0; /* * First, scan through all the arguments to figure out the structure * of the pipeline. Process all of the input and output redirection * arguments and remove them from the argument list in the pipeline. * Count the number of distinct processes (it's the number of "|" * arguments plus one) but don't remove the "|" arguments because * they'll be used in the second pass to seperate the individual * child processes. Cannot start the child processes in this pass * because the redirection symbols may appear anywhere in the * command line -- e.g., the '<' that specifies the input to the * entire pipe may appear at the very end of the argument list. */ lastBar = -1; cmdCount = 1; needCmd = 1; for (i = 0; i < argc; i++) { errorToOutput = 0; skip = 0; p = argv[i]; switch (*p++) { case '|': if (*p == '&') { p++; } if (*p == '\0') { if ((i == (lastBar + 1)) || (i == (argc - 1))) { Tcl_SetResult(interp, "illegal use of | or |& in command", TCL_STATIC); goto error; } } lastBar = i; cmdCount++; needCmd = 1; break; case '<': if (inputClose != 0) { inputClose = 0; TclpCloseFile(inputFile); } if (inputRelease != 0) { inputRelease = 0; TclpReleaseFile(inputFile); } if (*p == '<') { inputFile = NULL; inputLiteral = p + 1; skip = 1; if (*inputLiteral == '\0') { inputLiteral = ((i + 1) == argc) ? NULL : argv[i + 1]; if (inputLiteral == NULL) { Tcl_AppendResult(interp, "can't specify \"", argv[i], "\" as last word in command", (char *) NULL); goto error; } skip = 2; } } else { nextArg = ((i + 1) == argc) ? NULL : argv[i + 1]; inputLiteral = NULL; inputFile = FileForRedirect(interp, p, 1, argv[i], nextArg, O_RDONLY, &skip, &inputClose, &inputRelease); if (inputFile == NULL) { goto error; } } break; case '>': atOK = 1; flags = O_WRONLY | O_CREAT | O_TRUNC; if (*p == '>') { p++; atOK = 0; /* * Note that the O_APPEND flag only has an effect on POSIX * platforms. On Windows, we just have to carry on regardless. */ flags = O_WRONLY | O_CREAT | O_APPEND; } if (*p == '&') { if (errorClose != 0) { errorClose = 0; TclpCloseFile(errorFile); } errorToOutput = 1; p++; } /* * Close the old output file, but only if the error file is * not also using it. */ if (outputClose != 0) { outputClose = 0; if (errorFile == outputFile) { errorClose = 1; } else { TclpCloseFile(outputFile); } } if (outputRelease != 0) { outputRelease = 0; if (errorFile == outputFile) { errorRelease = 1; } else { TclpReleaseFile(outputFile); } } nextArg = ((i + 1) == argc) ? NULL : argv[i + 1]; outputFile = FileForRedirect(interp, p, atOK, argv[i], nextArg, flags, &skip, &outputClose, &outputRelease); if (outputFile == NULL) { goto error; } if (errorToOutput) { if (errorClose != 0) { errorClose = 0; TclpCloseFile(errorFile); } if (errorRelease != 0) { errorRelease = 0; TclpReleaseFile(errorFile); } errorFile = outputFile; } break; case '2': if (*p != '>') { break; } p++; atOK = 1; flags = O_WRONLY | O_CREAT | O_TRUNC; if (*p == '>') { p++; atOK = 0; flags = O_WRONLY | O_CREAT; } if (errorClose != 0) { errorClose = 0; TclpCloseFile(errorFile); } if (errorRelease != 0) { errorRelease = 0; TclpReleaseFile(errorFile); } if (atOK && p[0] == '@' && p[1] == '1' && p[2] == '\0') { /* * Special case handling of 2>@1 to redirect stderr to the * exec/open output pipe as well. This is meant for the end * of the command string, otherwise use |& between commands. */ if (i != argc - 1) { Tcl_AppendResult(interp, "must specify \"", argv[i], "\" as last word in command", (char *) NULL); goto error; } errorFile = outputFile; errorToOutput = 2; skip = 1; } else { nextArg = ((i + 1) == argc) ? NULL : argv[i + 1]; errorFile = FileForRedirect(interp, p, atOK, argv[i], nextArg, flags, &skip, &errorClose, &errorRelease); if (errorFile == NULL) { goto error; } } break; default: /* Got a command word, not a redirection */ needCmd = 0; break; } if (skip != 0) { for (j = i + skip; j < argc; j++) { argv[j - skip] = argv[j]; } argc -= skip; i -= 1; } } if (needCmd) { /* We had a bar followed only by redirections. */ Tcl_SetResult(interp, "illegal use of | or |& in command", TCL_STATIC); goto error; } if (inputFile == NULL) { if (inputLiteral != NULL) { /* * The input for the first process is immediate data coming from * Tcl. Create a temporary file for it and put the data into the * file. */ inputFile = TclpCreateTempFile(inputLiteral); if (inputFile == NULL) { Tcl_AppendResult(interp, "couldn't create input file for command: ", Tcl_PosixError(interp), (char *) NULL); goto error; } inputClose = 1; } else if (inPipePtr != NULL) { /* * The input for the first process in the pipeline is to * come from a pipe that can be written from by the caller. */ if (TclpCreatePipe(&inputFile, inPipePtr) == 0) { Tcl_AppendResult(interp, "couldn't create input pipe for command: ", Tcl_PosixError(interp), (char *) NULL); goto error; } inputClose = 1; } else { /* * The input for the first process comes from stdin. */ channel = Tcl_GetStdChannel(TCL_STDIN); if (channel != NULL) { inputFile = TclpMakeFile(channel, TCL_READABLE); if (inputFile != NULL) { inputRelease = 1; } } } } if (outputFile == NULL) { if (outPipePtr != NULL) { /* * Output from the last process in the pipeline is to go to a * pipe that can be read by the caller. */ if (TclpCreatePipe(outPipePtr, &outputFile) == 0) { Tcl_AppendResult(interp, "couldn't create output pipe for command: ", Tcl_PosixError(interp), (char *) NULL); goto error; } outputClose = 1; } else { /* * The output for the last process goes to stdout. */ channel = Tcl_GetStdChannel(TCL_STDOUT); if (channel) { outputFile = TclpMakeFile(channel, TCL_WRITABLE); if (outputFile != NULL) { outputRelease = 1; } } } } if (errorFile == NULL) { if (errorToOutput == 2) { /* * Handle 2>@1 special case at end of cmd line */ errorFile = outputFile; } else if (errFilePtr != NULL) { /* * Set up the standard error output sink for the pipeline, if * requested. Use a temporary file which is opened, then deleted. * Could potentially just use pipe, but if it filled up it could * cause the pipeline to deadlock: we'd be waiting for processes * to complete before reading stderr, and processes couldn't * complete because stderr was backed up. */ errorFile = TclpCreateTempFile(NULL); if (errorFile == NULL) { Tcl_AppendResult(interp, "couldn't create error file for command: ", Tcl_PosixError(interp), (char *) NULL); goto error; } *errFilePtr = errorFile; } else { /* * Errors from the pipeline go to stderr. */ channel = Tcl_GetStdChannel(TCL_STDERR); if (channel) { errorFile = TclpMakeFile(channel, TCL_WRITABLE); if (errorFile != NULL) { errorRelease = 1; } } } } /* * Scan through the argc array, creating a process for each * group of arguments between the "|" characters. */ Tcl_ReapDetachedProcs(); pidPtr = (Tcl_Pid *) ckalloc((unsigned) (cmdCount * sizeof(Tcl_Pid))); curInFile = inputFile; for (i = 0; i < argc; i = lastArg + 1) { int result, joinThisError; Tcl_Pid pid; CONST char *oldName; /* * Convert the program name into native form. */ if (Tcl_TranslateFileName(interp, argv[i], &execBuffer) == NULL) { goto error; } /* * Find the end of the current segment of the pipeline. */ joinThisError = 0; for (lastArg = i; lastArg < argc; lastArg++) { if (argv[lastArg][0] == '|') { if (argv[lastArg][1] == '\0') { break; } if ((argv[lastArg][1] == '&') && (argv[lastArg][2] == '\0')) { joinThisError = 1; break; } } } /* * If this is the last segment, use the specified outputFile. * Otherwise create an intermediate pipe. pipeIn will become the * curInFile for the next segment of the pipe. */ if (lastArg == argc) { curOutFile = outputFile; } else { argv[lastArg] = NULL; if (TclpCreatePipe(&pipeIn, &curOutFile) == 0) { Tcl_AppendResult(interp, "couldn't create pipe: ", Tcl_PosixError(interp), (char *) NULL); goto error; } } if (joinThisError != 0) { curErrFile = curOutFile; } else { curErrFile = errorFile; } /* * Restore argv[i], since a caller wouldn't expect the contents of * argv to be modified. */ oldName = argv[i]; argv[i] = Tcl_DStringValue(&execBuffer); result = TclpCreateProcess(interp, lastArg - i, argv + i, curInFile, curOutFile, curErrFile, &pid); argv[i] = oldName; if (result != TCL_OK) { goto error; } Tcl_DStringFree(&execBuffer); pidPtr[numPids] = pid; numPids++; /* * Close off our copies of file descriptors that were set up for * this child, then set up the input for the next child. */ if ((curInFile != NULL) && (curInFile != inputFile)) { TclpCloseFile(curInFile); } curInFile = pipeIn; pipeIn = NULL; if ((curOutFile != NULL) && (curOutFile != outputFile)) { TclpCloseFile(curOutFile); } curOutFile = NULL; } *pidArrayPtr = pidPtr; /* * All done. Cleanup open files lying around and then return. */ cleanup: Tcl_DStringFree(&execBuffer); if (inputClose) { TclpCloseFile(inputFile); } else if (inputRelease) { TclpReleaseFile(inputFile); } if (outputClose) { TclpCloseFile(outputFile); } else if (outputRelease) { TclpReleaseFile(outputFile); } if (errorClose) { TclpCloseFile(errorFile); } else if (errorRelease) { TclpReleaseFile(errorFile); } return numPids; /* * An error occurred. There could have been extra files open, such * as pipes between children. Clean them all up. Detach any child * processes that have been created. */ error: if (pipeIn != NULL) { TclpCloseFile(pipeIn); } if ((curOutFile != NULL) && (curOutFile != outputFile)) { TclpCloseFile(curOutFile); } if ((curInFile != NULL) && (curInFile != inputFile)) { TclpCloseFile(curInFile); } if ((inPipePtr != NULL) && (*inPipePtr != NULL)) { TclpCloseFile(*inPipePtr); *inPipePtr = NULL; } if ((outPipePtr != NULL) && (*outPipePtr != NULL)) { TclpCloseFile(*outPipePtr); *outPipePtr = NULL; } if ((errFilePtr != NULL) && (*errFilePtr != NULL)) { TclpCloseFile(*errFilePtr); *errFilePtr = NULL; } if (pidPtr != NULL) { for (i = 0; i < numPids; i++) { if (pidPtr[i] != (Tcl_Pid) -1) { Tcl_DetachPids(1, &pidPtr[i]); } } ckfree((char *) pidPtr); } numPids = -1; goto cleanup; } /* *---------------------------------------------------------------------- * * Tcl_OpenCommandChannel -- * * Opens an I/O channel to one or more subprocesses specified * by argc and argv. The flags argument determines the * disposition of the stdio handles. If the TCL_STDIN flag is * set then the standard input for the first subprocess will * be tied to the channel: writing to the channel will provide * input to the subprocess. If TCL_STDIN is not set, then * standard input for the first subprocess will be the same as * this application's standard input. If TCL_STDOUT is set then * standard output from the last subprocess can be read from the * channel; otherwise it goes to this application's standard * output. If TCL_STDERR is set, standard error output for all * subprocesses is returned to the channel and results in an error * when the channel is closed; otherwise it goes to this * application's standard error. If TCL_ENFORCE_MODE is not set, * then argc and argv can redirect the stdio handles to override * TCL_STDIN, TCL_STDOUT, and TCL_STDERR; if it is set, then it * is an error for argc and argv to override stdio channels for * which TCL_STDIN, TCL_STDOUT, and TCL_STDERR have been set. * * Results: * A new command channel, or NULL on failure with an error * message left in interp. * * Side effects: * Creates processes, opens pipes. * *---------------------------------------------------------------------- */ Tcl_Channel Tcl_OpenCommandChannel(interp, argc, argv, flags) Tcl_Interp *interp; /* Interpreter for error reporting. Can * NOT be NULL. */ int argc; /* How many arguments. */ CONST char **argv; /* Array of arguments for command pipe. */ int flags; /* Or'ed combination of TCL_STDIN, TCL_STDOUT, * TCL_STDERR, and TCL_ENFORCE_MODE. */ { TclFile *inPipePtr, *outPipePtr, *errFilePtr; TclFile inPipe, outPipe, errFile; int numPids; Tcl_Pid *pidPtr; Tcl_Channel channel; inPipe = outPipe = errFile = NULL; inPipePtr = (flags & TCL_STDIN) ? &inPipe : NULL; outPipePtr = (flags & TCL_STDOUT) ? &outPipe : NULL; errFilePtr = (flags & TCL_STDERR) ? &errFile : NULL; numPids = TclCreatePipeline(interp, argc, argv, &pidPtr, inPipePtr, outPipePtr, errFilePtr); if (numPids < 0) { goto error; } /* * Verify that the pipes that were created satisfy the * readable/writable constraints. */ if (flags & TCL_ENFORCE_MODE) { if ((flags & TCL_STDOUT) && (outPipe == NULL)) { Tcl_AppendResult(interp, "can't read output from command:", " standard output was redirected", (char *) NULL); goto error; } if ((flags & TCL_STDIN) && (inPipe == NULL)) { Tcl_AppendResult(interp, "can't write input to command:", " standard input was redirected", (char *) NULL); goto error; } } channel = TclpCreateCommandChannel(outPipe, inPipe, errFile, numPids, pidPtr); if (channel == (Tcl_Channel) NULL) { Tcl_AppendResult(interp, "pipe for command could not be created", (char *) NULL); goto error; } return channel; error: if (numPids > 0) { Tcl_DetachPids(numPids, pidPtr); ckfree((char *) pidPtr); } if (inPipe != NULL) { TclpCloseFile(inPipe); } if (outPipe != NULL) { TclpCloseFile(outPipe); } if (errFile != NULL) { TclpCloseFile(errFile); } return NULL; } tcl8.4.20/generic/tclMain.c0000644003604700454610000004622412052456744014075 0ustar dgp771div/* * tclMain.c -- * * Main program for Tcl shells and other Tcl-based applications. * * Copyright (c) 1988-1994 The Regents of the University of California. * Copyright (c) 1994-1997 Sun Microsystems, Inc. * Copyright (c) 2000 Ajuba Solutions. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tcl.h" #include "tclInt.h" # undef TCL_STORAGE_CLASS # define TCL_STORAGE_CLASS DLLEXPORT /* * Declarations for various library procedures and variables (don't want * to include tclPort.h here, because people might copy this file out of * the Tcl source directory to make their own modified versions). */ extern int isatty _ANSI_ARGS_((int fd)); static Tcl_Obj *tclStartupScriptPath = NULL; static Tcl_MainLoopProc *mainLoopProc = NULL; /* * Structure definition for information used to keep the state of * an interactive command processor that reads lines from standard * input and writes prompts and results to standard output. */ typedef enum { PROMPT_NONE, /* Print no prompt */ PROMPT_START, /* Print prompt for command start */ PROMPT_CONTINUE /* Print prompt for command continuation */ } PromptType; typedef struct InteractiveState { Tcl_Channel input; /* The standard input channel from which * lines are read. */ int tty; /* Non-zero means standard input is a * terminal-like device. Zero means it's * a file. */ Tcl_Obj *commandPtr; /* Used to assemble lines of input into * Tcl commands. */ PromptType prompt; /* Next prompt to print */ Tcl_Interp *interp; /* Interpreter that evaluates interactive * commands. */ } InteractiveState; /* * Forward declarations for procedures defined later in this file. */ static void Prompt _ANSI_ARGS_((Tcl_Interp *interp, PromptType *promptPtr)); static void StdinProc _ANSI_ARGS_((ClientData clientData, int mask)); /* *---------------------------------------------------------------------- * * TclSetStartupScriptPath -- * * Primes the startup script VFS path, used to override the * command line processing. * * Results: * None. * * Side effects: * This procedure initializes the VFS path of the Tcl script to * run at startup. * *---------------------------------------------------------------------- */ void TclSetStartupScriptPath(pathPtr) Tcl_Obj *pathPtr; { if (tclStartupScriptPath != NULL) { Tcl_DecrRefCount(tclStartupScriptPath); } tclStartupScriptPath = pathPtr; if (tclStartupScriptPath != NULL) { Tcl_IncrRefCount(tclStartupScriptPath); } } /* *---------------------------------------------------------------------- * * TclGetStartupScriptPath -- * * Gets the startup script VFS path, used to override the * command line processing. * * Results: * The startup script VFS path, NULL if none has been set. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_Obj *TclGetStartupScriptPath() { return tclStartupScriptPath; } /* *---------------------------------------------------------------------- * * TclSetStartupScriptFileName -- * * Primes the startup script file name, used to override the * command line processing. * * Results: * None. * * Side effects: * This procedure initializes the file name of the Tcl script to * run at startup. * *---------------------------------------------------------------------- */ void TclSetStartupScriptFileName(fileName) CONST char *fileName; { Tcl_Obj *pathPtr = Tcl_NewStringObj(fileName,-1); TclSetStartupScriptPath(pathPtr); } /* *---------------------------------------------------------------------- * * TclGetStartupScriptFileName -- * * Gets the startup script file name, used to override the * command line processing. * * Results: * The startup script file name, NULL if none has been set. * * Side effects: * None. * *---------------------------------------------------------------------- */ CONST char *TclGetStartupScriptFileName() { Tcl_Obj *pathPtr = TclGetStartupScriptPath(); if (pathPtr == NULL) { return NULL; } return Tcl_GetString(pathPtr); } /* *---------------------------------------------------------------------- * * Tcl_Main -- * * Main program for tclsh and most other Tcl-based applications. * * Results: * None. This procedure never returns (it exits the process when * it's done). * * Side effects: * This procedure initializes the Tcl world and then starts * interpreting commands; almost anything could happen, depending * on the script being interpreted. * *---------------------------------------------------------------------- */ void Tcl_Main(argc, argv, appInitProc) int argc; /* Number of arguments. */ char **argv; /* Array of argument strings. */ Tcl_AppInitProc *appInitProc; /* Application-specific initialization * procedure to call after most * initialization but before starting to * execute commands. */ { Tcl_Obj *resultPtr, *argvPtr, *commandPtr = NULL; PromptType prompt = PROMPT_START; int code, length, tty, exitCode = 0; Tcl_Channel inChannel, outChannel, errChannel; Tcl_Interp *interp; Tcl_DString appName; Tcl_Obj *objPtr; Tcl_FindExecutable(argv[0]); interp = Tcl_CreateInterp(); Tcl_InitMemory(interp); /* * Make command-line arguments available in the Tcl variables "argc" * and "argv". If the first argument doesn't start with a "-" then * strip it off and use it as the name of a script file to process. */ if (TclGetStartupScriptPath() == NULL) { if ((argc > 1) && (argv[1][0] != '-')) { TclSetStartupScriptFileName(argv[1]); argc--; argv++; } } if (TclGetStartupScriptPath() == NULL) { Tcl_ExternalToUtfDString(NULL, argv[0], -1, &appName); } else { TclSetStartupScriptFileName(Tcl_ExternalToUtfDString(NULL, TclGetStartupScriptFileName(), -1, &appName)); } Tcl_SetVar(interp, "argv0", Tcl_DStringValue(&appName), TCL_GLOBAL_ONLY); Tcl_DStringFree(&appName); argc--; argv++; objPtr = Tcl_NewIntObj(argc); Tcl_IncrRefCount(objPtr); Tcl_SetVar2Ex(interp, "argc", NULL, objPtr, TCL_GLOBAL_ONLY); Tcl_DecrRefCount(objPtr); argvPtr = Tcl_NewListObj(0, NULL); while (argc--) { Tcl_DString ds; Tcl_ExternalToUtfDString(NULL, *argv++, -1, &ds); Tcl_ListObjAppendElement(NULL, argvPtr, Tcl_NewStringObj( Tcl_DStringValue(&ds), Tcl_DStringLength(&ds))); Tcl_DStringFree(&ds); } Tcl_IncrRefCount(argvPtr); Tcl_SetVar2Ex(interp, "argv", NULL, argvPtr, TCL_GLOBAL_ONLY); Tcl_DecrRefCount(argvPtr); /* * Set the "tcl_interactive" variable. */ tty = isatty(0); Tcl_SetVar(interp, "tcl_interactive", ((TclGetStartupScriptPath() == NULL) && tty) ? "1" : "0", TCL_GLOBAL_ONLY); /* * Invoke application-specific initialization. */ Tcl_Preserve((ClientData) interp); if ((*appInitProc)(interp) != TCL_OK) { errChannel = Tcl_GetStdChannel(TCL_STDERR); if (errChannel) { Tcl_WriteChars(errChannel, "application-specific initialization failed: ", -1); Tcl_WriteObj(errChannel, Tcl_GetObjResult(interp)); Tcl_WriteChars(errChannel, "\n", 1); } } if (Tcl_InterpDeleted(interp)) { goto done; } /* * If a script file was specified then just source that file * and quit. */ if (TclGetStartupScriptPath() != NULL) { code = Tcl_FSEvalFile(interp, TclGetStartupScriptPath()); if (code != TCL_OK) { errChannel = Tcl_GetStdChannel(TCL_STDERR); if (errChannel) { /* * The following statement guarantees that the errorInfo * variable is set properly. */ Tcl_AddErrorInfo(interp, ""); Tcl_WriteObj(errChannel, Tcl_GetVar2Ex(interp, "errorInfo", NULL, TCL_GLOBAL_ONLY)); Tcl_WriteChars(errChannel, "\n", 1); } exitCode = 1; } goto done; } /* * We're running interactively. Source a user-specific startup * file if the application specified one and if the file exists. */ Tcl_SourceRCFile(interp); /* * Process commands from stdin until there's an end-of-file. Note * that we need to fetch the standard channels again after every * eval, since they may have been changed. */ commandPtr = Tcl_NewObj(); Tcl_IncrRefCount(commandPtr); /* * Get a new value for tty if anyone writes to ::tcl_interactive */ Tcl_LinkVar(interp, "tcl_interactive", (char *) &tty, TCL_LINK_BOOLEAN); inChannel = Tcl_GetStdChannel(TCL_STDIN); outChannel = Tcl_GetStdChannel(TCL_STDOUT); while ((inChannel != (Tcl_Channel) NULL) && !Tcl_InterpDeleted(interp)) { if (mainLoopProc == NULL) { if (tty) { Prompt(interp, &prompt); if (Tcl_InterpDeleted(interp)) { break; } inChannel = Tcl_GetStdChannel(TCL_STDIN); if (inChannel == (Tcl_Channel) NULL) { break; } } if (Tcl_IsShared(commandPtr)) { Tcl_DecrRefCount(commandPtr); commandPtr = Tcl_DuplicateObj(commandPtr); Tcl_IncrRefCount(commandPtr); } length = Tcl_GetsObj(inChannel, commandPtr); if (length < 0) { if (Tcl_InputBlocked(inChannel)) { /* * This can only happen if stdin has been set to * non-blocking. In that case cycle back and try * again. This sets up a tight polling loop (since * we have no event loop running). If this causes * bad CPU hogging, we might try toggling the blocking * on stdin instead. */ continue; } /* * Either EOF, or an error on stdin; we're done */ break; } /* * Add the newline removed by Tcl_GetsObj back to the string. */ if (Tcl_IsShared(commandPtr)) { Tcl_DecrRefCount(commandPtr); commandPtr = Tcl_DuplicateObj(commandPtr); Tcl_IncrRefCount(commandPtr); } Tcl_AppendToObj(commandPtr, "\n", 1); if (!TclObjCommandComplete(commandPtr)) { prompt = PROMPT_CONTINUE; continue; } prompt = PROMPT_START; code = Tcl_RecordAndEvalObj(interp, commandPtr, TCL_EVAL_GLOBAL); inChannel = Tcl_GetStdChannel(TCL_STDIN); outChannel = Tcl_GetStdChannel(TCL_STDOUT); errChannel = Tcl_GetStdChannel(TCL_STDERR); Tcl_DecrRefCount(commandPtr); commandPtr = Tcl_NewObj(); Tcl_IncrRefCount(commandPtr); if (code != TCL_OK) { if (errChannel) { Tcl_WriteObj(errChannel, Tcl_GetObjResult(interp)); Tcl_WriteChars(errChannel, "\n", 1); } } else if (tty) { resultPtr = Tcl_GetObjResult(interp); Tcl_IncrRefCount(resultPtr); Tcl_GetStringFromObj(resultPtr, &length); if ((length > 0) && outChannel) { Tcl_WriteObj(outChannel, resultPtr); Tcl_WriteChars(outChannel, "\n", 1); } Tcl_DecrRefCount(resultPtr); } } else { /* (mainLoopProc != NULL) */ /* * If a main loop has been defined while running interactively, * we want to start a fileevent based prompt by establishing a * channel handler for stdin. */ InteractiveState *isPtr = NULL; if (inChannel) { if (tty) { Prompt(interp, &prompt); } isPtr = (InteractiveState *) ckalloc((int) sizeof(InteractiveState)); isPtr->input = inChannel; isPtr->tty = tty; isPtr->commandPtr = commandPtr; isPtr->prompt = prompt; isPtr->interp = interp; Tcl_UnlinkVar(interp, "tcl_interactive"); Tcl_LinkVar(interp, "tcl_interactive", (char *) &(isPtr->tty), TCL_LINK_BOOLEAN); Tcl_CreateChannelHandler(inChannel, TCL_READABLE, StdinProc, (ClientData) isPtr); } (*mainLoopProc)(); mainLoopProc = NULL; if (inChannel) { tty = isPtr->tty; Tcl_UnlinkVar(interp, "tcl_interactive"); Tcl_LinkVar(interp, "tcl_interactive", (char *) &tty, TCL_LINK_BOOLEAN); prompt = isPtr->prompt; commandPtr = isPtr->commandPtr; if (isPtr->input != (Tcl_Channel) NULL) { Tcl_DeleteChannelHandler(isPtr->input, StdinProc, (ClientData) isPtr); } ckfree((char *)isPtr); } inChannel = Tcl_GetStdChannel(TCL_STDIN); outChannel = Tcl_GetStdChannel(TCL_STDOUT); errChannel = Tcl_GetStdChannel(TCL_STDERR); } #ifdef TCL_MEM_DEBUG /* * This code here only for the (unsupported and deprecated) * [checkmem] command. */ if (tclMemDumpFileName != NULL) { mainLoopProc = NULL; Tcl_DeleteInterp(interp); } #endif } done: if ((exitCode == 0) && (mainLoopProc != NULL)) { /* * If everything has gone OK so far, call the main loop proc, * if it exists. Packages (like Tk) can set it to start processing * events at this point. */ (*mainLoopProc)(); mainLoopProc = NULL; } if (commandPtr != NULL) { Tcl_DecrRefCount(commandPtr); } /* * Rather than calling exit, invoke the "exit" command so that * users can replace "exit" with some other command to do additional * cleanup on exit. The Tcl_Eval call should never return. */ if (!Tcl_InterpDeleted(interp)) { char buffer[TCL_INTEGER_SPACE + 5]; sprintf(buffer, "exit %d", exitCode); Tcl_Eval(interp, buffer); /* * If Tcl_Eval returns, trying to eval [exit], something * unusual is happening. Maybe interp has been deleted; * maybe [exit] was redefined. We still want to cleanup * and exit. */ if (!Tcl_InterpDeleted(interp)) { Tcl_DeleteInterp(interp); } } TclSetStartupScriptPath(NULL); /* * If we get here, the master interp has been deleted. Allow * its destruction with the last matching Tcl_Release. */ Tcl_Release((ClientData) interp); Tcl_Exit(exitCode); } /* *--------------------------------------------------------------- * * Tcl_SetMainLoop -- * * Sets an alternative main loop procedure. * * Results: * Returns the previously defined main loop procedure. * * Side effects: * This procedure will be called before Tcl exits, allowing for * the creation of an event loop. * *--------------------------------------------------------------- */ void Tcl_SetMainLoop(proc) Tcl_MainLoopProc *proc; { mainLoopProc = proc; } /* *---------------------------------------------------------------------- * * StdinProc -- * * This procedure is invoked by the event dispatcher whenever * standard input becomes readable. It grabs the next line of * input characters, adds them to a command being assembled, and * executes the command if it's complete. * * Results: * None. * * Side effects: * Could be almost arbitrary, depending on the command that's * typed. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static void StdinProc(clientData, mask) ClientData clientData; /* The state of interactive cmd line */ int mask; /* Not used. */ { InteractiveState *isPtr = (InteractiveState *) clientData; Tcl_Channel chan = isPtr->input; Tcl_Obj *commandPtr = isPtr->commandPtr; Tcl_Interp *interp = isPtr->interp; int code, length; if (Tcl_IsShared(commandPtr)) { Tcl_DecrRefCount(commandPtr); commandPtr = Tcl_DuplicateObj(commandPtr); Tcl_IncrRefCount(commandPtr); } length = Tcl_GetsObj(chan, commandPtr); if (length < 0) { if (Tcl_InputBlocked(chan)) { return; } if (isPtr->tty) { /* * Would be better to find a way to exit the mainLoop? * Or perhaps evaluate [exit]? Leaving as is for now due * to compatibility concerns. */ Tcl_Exit(0); } Tcl_DeleteChannelHandler(chan, StdinProc, (ClientData) isPtr); return; } if (Tcl_IsShared(commandPtr)) { Tcl_DecrRefCount(commandPtr); commandPtr = Tcl_DuplicateObj(commandPtr); Tcl_IncrRefCount(commandPtr); } Tcl_AppendToObj(commandPtr, "\n", 1); if (!TclObjCommandComplete(commandPtr)) { isPtr->prompt = PROMPT_CONTINUE; goto prompt; } isPtr->prompt = PROMPT_START; /* * Disable the stdin channel handler while evaluating the command; * otherwise if the command re-enters the event loop we might * process commands from stdin before the current command is * finished. Among other things, this will trash the text of the * command being evaluated. */ Tcl_CreateChannelHandler(chan, 0, StdinProc, (ClientData) isPtr); code = Tcl_RecordAndEvalObj(interp, commandPtr, TCL_EVAL_GLOBAL); isPtr->input = chan = Tcl_GetStdChannel(TCL_STDIN); Tcl_DecrRefCount(commandPtr); isPtr->commandPtr = commandPtr = Tcl_NewObj(); Tcl_IncrRefCount(commandPtr); if (chan != (Tcl_Channel) NULL) { Tcl_CreateChannelHandler(chan, TCL_READABLE, StdinProc, (ClientData) isPtr); } if (code != TCL_OK) { Tcl_Channel errChannel = Tcl_GetStdChannel(TCL_STDERR); if (errChannel != (Tcl_Channel) NULL) { Tcl_WriteObj(errChannel, Tcl_GetObjResult(interp)); Tcl_WriteChars(errChannel, "\n", 1); } } else if (isPtr->tty) { Tcl_Obj *resultPtr = Tcl_GetObjResult(interp); Tcl_Channel outChannel = Tcl_GetStdChannel(TCL_STDOUT); Tcl_IncrRefCount(resultPtr); Tcl_GetStringFromObj(resultPtr, &length); if ((length >0) && (outChannel != (Tcl_Channel) NULL)) { Tcl_WriteObj(outChannel, resultPtr); Tcl_WriteChars(outChannel, "\n", 1); } Tcl_DecrRefCount(resultPtr); } /* * If a tty stdin is still around, output a prompt. */ prompt: if (isPtr->tty && (isPtr->input != (Tcl_Channel) NULL)) { Prompt(interp, &(isPtr->prompt)); isPtr->input = Tcl_GetStdChannel(TCL_STDIN); } } /* *---------------------------------------------------------------------- * * Prompt -- * * Issue a prompt on standard output, or invoke a script * to issue the prompt. * * Results: * None. * * Side effects: * A prompt gets output, and a Tcl script may be evaluated * in interp. * *---------------------------------------------------------------------- */ static void Prompt(interp, promptPtr) Tcl_Interp *interp; /* Interpreter to use for prompting. */ PromptType *promptPtr; /* Points to type of prompt to print. * Filled with PROMPT_NONE after a * prompt is printed. */ { Tcl_Obj *promptCmdPtr; int code; Tcl_Channel outChannel, errChannel; if (*promptPtr == PROMPT_NONE) { return; } promptCmdPtr = Tcl_GetVar2Ex(interp, ((*promptPtr == PROMPT_CONTINUE) ? "tcl_prompt2" : "tcl_prompt1"), NULL, TCL_GLOBAL_ONLY); if (Tcl_InterpDeleted(interp)) { return; } if (promptCmdPtr == NULL) { defaultPrompt: outChannel = Tcl_GetStdChannel(TCL_STDOUT); if ((*promptPtr == PROMPT_START) && (outChannel != (Tcl_Channel) NULL)) { Tcl_WriteChars(outChannel, "% ", 2); } } else { code = Tcl_EvalObjEx(interp, promptCmdPtr, TCL_EVAL_GLOBAL); if (code != TCL_OK) { Tcl_AddErrorInfo(interp, "\n (script that generates prompt)"); errChannel = Tcl_GetStdChannel(TCL_STDERR); if (errChannel != (Tcl_Channel) NULL) { Tcl_WriteObj(errChannel, Tcl_GetObjResult(interp)); Tcl_WriteChars(errChannel, "\n", 1); } goto defaultPrompt; } } outChannel = Tcl_GetStdChannel(TCL_STDOUT); if (outChannel != (Tcl_Channel) NULL) { Tcl_Flush(outChannel); } *promptPtr = PROMPT_NONE; } tcl8.4.20/generic/tclMath.h0000644003604700454610000000115412052456744014100 0ustar dgp771div/* * tclMath.h -- * * This file is necessary because of Metrowerks CodeWarrior Pro 1 * on the Macintosh. With 8-byte doubles turned on, the definitions of * sin, cos, acos, etc., are screwed up. They are fine as long as * they are used as function calls, but if the function pointers * are passed around and used, they will crash hard on the 68K. * * Copyright (c) 1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef _TCLMATH #define _TCLMATH #include #endif /* _TCLMATH */ tcl8.4.20/generic/tclDTrace.d0000644003604700454610000001276511737050674014360 0ustar dgp771div/* * tclDTrace.d -- * * Tcl DTrace provider. * * Copyright (c) 2007 Daniel A. Steffen * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ typedef struct Tcl_Obj Tcl_Obj; /* * Tcl DTrace probes */ provider tcl { /***************************** proc probes *****************************/ /* * tcl*:::proc-entry probe * triggered immediately before proc bytecode execution * arg0: proc name (string) * arg1: number of arguments (int) * arg2: array of proc argument objects (Tcl_Obj**) */ probe proc__entry(char* name, int objc, struct Tcl_Obj **objv); /* * tcl*:::proc-return probe * triggered immediately after proc bytecode execution * arg0: proc name (string) * arg1: return code (int) */ probe proc__return(char* name, int code); /* * tcl*:::proc-result probe * triggered after proc-return probe and result processing * arg0: proc name (string) * arg1: return code (int) * arg2: proc result (string) * arg3: proc result object (Tcl_Obj*) */ probe proc__result(char* name, int code, char* result, struct Tcl_Obj *resultobj); /* * tcl*:::proc-args probe * triggered before proc-entry probe, gives access to string * representation of proc arguments * arg0: proc name (string) * arg1-arg9: proc arguments or NULL (strings) */ probe proc__args(char* name, char* arg1, char* arg2, char* arg3, char* arg4, char* arg5, char* arg6, char* arg7, char* arg8, char* arg9); /***************************** cmd probes ******************************/ /* * tcl*:::cmd-entry probe * triggered immediately before commmand execution * arg0: command name (string) * arg1: number of arguments (int) * arg2: array of command argument objects (Tcl_Obj**) */ probe cmd__entry(char* name, int objc, struct Tcl_Obj **objv); /* * tcl*:::cmd-return probe * triggered immediately after commmand execution * arg0: command name (string) * arg1: return code (int) */ probe cmd__return(char* name, int code); /* * tcl*:::cmd-result probe * triggered after cmd-return probe and result processing * arg0: command name (string) * arg1: return code (int) * arg2: command result (string) * arg3: command result object (Tcl_Obj*) */ probe cmd__result(char* name, int code, char* result, struct Tcl_Obj *resultobj); /* * tcl*:::cmd-args probe * triggered before cmd-entry probe, gives access to string * representation of command arguments * arg0: command name (string) * arg1-arg9: command arguments or NULL (strings) */ probe cmd__args(char* name, char* arg1, char* arg2, char* arg3, char* arg4, char* arg5, char* arg6, char* arg7, char* arg8, char* arg9); /***************************** inst probes *****************************/ /* * tcl*:::inst-start probe * triggered immediately before execution of a bytecode * arg0: bytecode name (string) * arg1: depth of stack (int) * arg2: top of stack (Tcl_Obj**) */ probe inst__start(char* name, int depth, struct Tcl_Obj **stack); /* * tcl*:::inst-done probe * triggered immediately after execution of a bytecode * arg0: bytecode name (string) * arg1: depth of stack (int) * arg2: top of stack (Tcl_Obj**) */ probe inst__done(char* name, int depth, struct Tcl_Obj **stack); /***************************** obj probes ******************************/ /* * tcl*:::obj-create probe * triggered immediately after a new Tcl_Obj has been created * arg0: object created (Tcl_Obj*) */ probe obj__create(struct Tcl_Obj* obj); /* * tcl*:::obj-free probe * triggered immediately before a Tcl_Obj is freed * arg0: object to be freed (Tcl_Obj*) */ probe obj__free(struct Tcl_Obj* obj); /***************************** tcl probes ******************************/ /* * tcl*:::tcl-probe probe * triggered when the ::tcl::dtrace command is called * arg0-arg9: command arguments (strings) */ probe tcl__probe(char* arg0, char* arg1, char* arg2, char* arg3, char* arg4, char* arg5, char* arg6, char* arg7, char* arg8, char* arg9); }; /* * Tcl types and constants for use in DTrace scripts */ typedef struct Tcl_ObjType { char *name; void *freeIntRepProc; void *dupIntRepProc; void *updateStringProc; void *setFromAnyProc; } Tcl_ObjType; struct Tcl_Obj { int refCount; char *bytes; int length; Tcl_ObjType *typePtr; union { long longValue; double doubleValue; void *otherValuePtr; int64_t wideValue; struct { void *ptr1; void *ptr2; } twoPtrValue; } internalRep; }; enum return_codes { TCL_OK = 0, TCL_ERROR, TCL_RETURN, TCL_BREAK, TCL_CONTINUE }; #pragma D attributes Evolving/Evolving/Common provider tcl provider #pragma D attributes Private/Private/Common provider tcl module #pragma D attributes Private/Private/Common provider tcl function #pragma D attributes Evolving/Evolving/Common provider tcl name #pragma D attributes Evolving/Evolving/Common provider tcl args /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ tcl8.4.20/generic/regex.h0000644003604700454610000002603612133546537013624 0ustar dgp771div#ifndef _REGEX_H_ #define _REGEX_H_ /* never again */ /* * regular expressions * * Copyright (c) 1998, 1999 Henry Spencer. All rights reserved. * * Development of this software was funded, in part, by Cray Research Inc., * UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics * Corporation, none of whom are responsible for the results. The author * thanks all of them. * * Redistribution and use in source and binary forms -- with or without * modification -- are permitted for any purpose, provided that * redistributions in source form retain this entire copyright notice and * indicate the origin and nature of any modifications. * * I'd appreciate being given credit for this package in the documentation * of software which uses it, but that is not a requirement. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * HENRY SPENCER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * * * Prototypes etc. marked with "^" within comments get gathered up (and * possibly edited) by the regfwd program and inserted near the bottom of * this file. * * We offer the option of declaring one wide-character version of the * RE functions as well as the char versions. To do that, define * __REG_WIDE_T to the type of wide characters (unfortunately, there * is no consensus that wchar_t is suitable) and __REG_WIDE_COMPILE and * __REG_WIDE_EXEC to the names to be used for the compile and execute * functions (suggestion: re_Xcomp and re_Xexec, where X is a letter * suggestive of the wide type, e.g. re_ucomp and re_uexec for Unicode). * For cranky old compilers, it may be necessary to do something like: * #define __REG_WIDE_COMPILE(a,b,c,d) re_Xcomp(a,b,c,d) * #define __REG_WIDE_EXEC(a,b,c,d,e,f,g) re_Xexec(a,b,c,d,e,f,g) * rather than just #defining the names as parameterless macros. * * For some specialized purposes, it may be desirable to suppress the * declarations of the "front end" functions, regcomp() and regexec(), * or of the char versions of the compile and execute functions. To * suppress the front-end functions, define __REG_NOFRONT. To suppress * the char versions, define __REG_NOCHAR. * * The right place to do those defines (and some others you may want, see * below) would be . If you don't have control of that file, * the right place to add your own defines to this file is marked below. * This is normally done automatically, by the makefile and regmkhdr, based * on the contents of regcustom.h. */ /* * voodoo for C++ */ #ifdef __cplusplus extern "C" { #endif /* * Add your own defines, if needed, here. */ /* * Location where a chunk of regcustom.h is automatically spliced into * this file (working from its prototype, regproto.h). */ /* --- begin --- */ /* ensure certain things don't sneak in from system headers */ #ifdef __REG_WIDE_T #undef __REG_WIDE_T #endif #ifdef __REG_WIDE_COMPILE #undef __REG_WIDE_COMPILE #endif #ifdef __REG_WIDE_EXEC #undef __REG_WIDE_EXEC #endif #ifdef __REG_REGOFF_T #undef __REG_REGOFF_T #endif #ifdef __REG_VOID_T #undef __REG_VOID_T #endif #ifdef __REG_CONST #undef __REG_CONST #endif #ifdef __REG_NOFRONT #undef __REG_NOFRONT #endif #ifdef __REG_NOCHAR #undef __REG_NOCHAR #endif /* interface types */ #define __REG_WIDE_T Tcl_UniChar #define __REG_REGOFF_T long /* not really right, but good enough... */ #define __REG_VOID_T VOID #define __REG_CONST CONST /* names and declarations */ #define __REG_WIDE_COMPILE TclReComp #define __REG_WIDE_EXEC TclReExec #define __REG_NOFRONT /* don't want regcomp() and regexec() */ #define __REG_NOCHAR /* or the char versions */ #define regfree TclReFree #define regerror TclReError /* --- end --- */ /* * interface types etc. */ /* * regoff_t has to be large enough to hold either off_t or ssize_t, * and must be signed; it's only a guess that long is suitable, so we * offer an override. */ #ifdef __REG_REGOFF_T typedef __REG_REGOFF_T regoff_t; #else typedef long regoff_t; #endif /* * For benefit of old compilers, we offer the option of * overriding the `void' type used to declare nonexistent return types. */ #ifdef __REG_VOID_T typedef __REG_VOID_T re_void; #else typedef void re_void; #endif /* * Also for benefit of old compilers, can supply a macro * which expands to a substitute for `const'. */ #ifndef __REG_CONST #define __REG_CONST const #endif /* * other interface types */ /* the biggie, a compiled RE (or rather, a front end to same) */ typedef struct { int re_magic; /* magic number */ size_t re_nsub; /* number of subexpressions */ long re_info; /* information about RE */ # define REG_UBACKREF 000001 # define REG_ULOOKAHEAD 000002 # define REG_UBOUNDS 000004 # define REG_UBRACES 000010 # define REG_UBSALNUM 000020 # define REG_UPBOTCH 000040 # define REG_UBBS 000100 # define REG_UNONPOSIX 000200 # define REG_UUNSPEC 000400 # define REG_UUNPORT 001000 # define REG_ULOCALE 002000 # define REG_UEMPTYMATCH 004000 # define REG_UIMPOSSIBLE 010000 # define REG_USHORTEST 020000 int re_csize; /* sizeof(character) */ char *re_endp; /* backward compatibility kludge */ /* the rest is opaque pointers to hidden innards */ char *re_guts; /* `char *' is more portable than `void *' */ char *re_fns; } regex_t; /* result reporting (may acquire more fields later) */ typedef struct { regoff_t rm_so; /* start of substring */ regoff_t rm_eo; /* end of substring */ } regmatch_t; /* supplementary control and reporting */ typedef struct { regmatch_t rm_extend; /* see REG_EXPECT */ } rm_detail_t; /* * compilation ^ #ifndef __REG_NOCHAR ^ int re_comp(regex_t *, __REG_CONST char *, size_t, int); ^ #endif ^ #ifndef __REG_NOFRONT ^ int regcomp(regex_t *, __REG_CONST char *, int); ^ #endif ^ #ifdef __REG_WIDE_T ^ int __REG_WIDE_COMPILE(regex_t *, __REG_CONST __REG_WIDE_T *, size_t, int); ^ #endif */ #define REG_BASIC 000000 /* BREs (convenience) */ #define REG_EXTENDED 000001 /* EREs */ #define REG_ADVF 000002 /* advanced features in EREs */ #define REG_ADVANCED 000003 /* AREs (which are also EREs) */ #define REG_QUOTE 000004 /* no special characters, none */ #define REG_NOSPEC REG_QUOTE /* historical synonym */ #define REG_ICASE 000010 /* ignore case */ #define REG_NOSUB 000020 /* don't care about subexpressions */ #define REG_EXPANDED 000040 /* expanded format, white space & comments */ #define REG_NLSTOP 000100 /* \n doesn't match . or [^ ] */ #define REG_NLANCH 000200 /* ^ matches after \n, $ before */ #define REG_NEWLINE 000300 /* newlines are line terminators */ #define REG_PEND 000400 /* ugh -- backward-compatibility hack */ #define REG_EXPECT 001000 /* report details on partial/limited matches */ #define REG_BOSONLY 002000 /* temporary kludge for BOS-only matches */ #define REG_DUMP 004000 /* none of your business :-) */ #define REG_FAKE 010000 /* none of your business :-) */ #define REG_PROGRESS 020000 /* none of your business :-) */ /* * execution ^ #ifndef __REG_NOCHAR ^ int re_exec(regex_t *, __REG_CONST char *, size_t, ^ rm_detail_t *, size_t, regmatch_t [], int); ^ #endif ^ #ifndef __REG_NOFRONT ^ int regexec(regex_t *, __REG_CONST char *, size_t, regmatch_t [], int); ^ #endif ^ #ifdef __REG_WIDE_T ^ int __REG_WIDE_EXEC(regex_t *, __REG_CONST __REG_WIDE_T *, size_t, ^ rm_detail_t *, size_t, regmatch_t [], int); ^ #endif */ #define REG_NOTBOL 0001 /* BOS is not BOL */ #define REG_NOTEOL 0002 /* EOS is not EOL */ #define REG_STARTEND 0004 /* backward compatibility kludge */ #define REG_FTRACE 0010 /* none of your business */ #define REG_MTRACE 0020 /* none of your business */ #define REG_SMALL 0040 /* none of your business */ /* * misc generics (may be more functions here eventually) ^ re_void regfree(regex_t *); */ /* * error reporting * Be careful if modifying the list of error codes -- the table used by * regerror() is generated automatically from this file! * * Note that there is no wide-char variant of regerror at this time; what * kind of character is used for error reports is independent of what kind * is used in matching. * ^ extern size_t regerror(int, __REG_CONST regex_t *, char *, size_t); */ #define REG_OKAY 0 /* no errors detected */ #define REG_NOMATCH 1 /* failed to match */ #define REG_BADPAT 2 /* invalid regexp */ #define REG_ECOLLATE 3 /* invalid collating element */ #define REG_ECTYPE 4 /* invalid character class */ #define REG_EESCAPE 5 /* invalid escape \ sequence */ #define REG_ESUBREG 6 /* invalid backreference number */ #define REG_EBRACK 7 /* brackets [] not balanced */ #define REG_EPAREN 8 /* parentheses () not balanced */ #define REG_EBRACE 9 /* braces {} not balanced */ #define REG_BADBR 10 /* invalid repetition count(s) */ #define REG_ERANGE 11 /* invalid character range */ #define REG_ESPACE 12 /* out of memory */ #define REG_BADRPT 13 /* quantifier operand invalid */ #define REG_ASSERT 15 /* "can't happen" -- you found a bug */ #define REG_INVARG 16 /* invalid argument to regex function */ #define REG_MIXED 17 /* character widths of regex and string differ */ #define REG_BADOPT 18 /* invalid embedded option */ #define REG_ETOOBIG 19 /* nfa has too many states */ #define REG_ECOLORS 20 /* too many colors */ /* two specials for debugging and testing */ #define REG_ATOI 101 /* convert error-code name to number */ #define REG_ITOA 102 /* convert error-code number to name */ /* * the prototypes, as possibly munched by regfwd */ /* =====^!^===== begin forwards =====^!^===== */ /* automatically gathered by fwd; do not hand-edit */ /* === regproto.h === */ #ifndef __REG_NOCHAR int re_comp _ANSI_ARGS_((regex_t *, __REG_CONST char *, size_t, int)); #endif #ifndef __REG_NOFRONT int regcomp _ANSI_ARGS_((regex_t *, __REG_CONST char *, int)); #endif #ifdef __REG_WIDE_T int __REG_WIDE_COMPILE _ANSI_ARGS_((regex_t *, __REG_CONST __REG_WIDE_T *, size_t, int)); #endif #ifndef __REG_NOCHAR int re_exec _ANSI_ARGS_((regex_t *, __REG_CONST char *, size_t, rm_detail_t *, size_t, regmatch_t [], int)); #endif #ifndef __REG_NOFRONT int regexec _ANSI_ARGS_((regex_t *, __REG_CONST char *, size_t, regmatch_t [], int)); #endif #ifdef __REG_WIDE_T int __REG_WIDE_EXEC _ANSI_ARGS_((regex_t *, __REG_CONST __REG_WIDE_T *, size_t, rm_detail_t *, size_t, regmatch_t [], int)); #endif re_void regfree _ANSI_ARGS_((regex_t *)); extern size_t regerror _ANSI_ARGS_((int, __REG_CONST regex_t *, char *, size_t)); /* automatically gathered by fwd; do not hand-edit */ /* =====^!^===== end forwards =====^!^===== */ /* * more C++ voodoo */ #ifdef __cplusplus } #endif #endif tcl8.4.20/generic/tclClock.c0000644003604700454610000002343411737050674014243 0ustar dgp771div/* * tclClock.c -- * * Contains the time and date related commands. This code * is derived from the time and date facilities of TclX, * by Mark Diekhans and Karl Lehenbauer. * * Copyright 1991-1995 Karl Lehenbauer and Mark Diekhans. * Copyright (c) 1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tcl.h" #include "tclInt.h" #include "tclPort.h" /* * The date parsing stuff uses lexx and has tons o statics. */ TCL_DECLARE_MUTEX(clockMutex) /* * Function prototypes for local procedures in this file: */ static int FormatClock _ANSI_ARGS_((Tcl_Interp *interp, Tcl_WideInt clockVal, int useGMT, char *format)); /* *------------------------------------------------------------------------- * * Tcl_ClockObjCmd -- * * This procedure is invoked to process the "clock" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *------------------------------------------------------------------------- */ int Tcl_ClockObjCmd (client, interp, objc, objv) ClientData client; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument values. */ { Tcl_Obj *resultPtr; int index; Tcl_Obj *CONST *objPtr; int useGMT = 0; char *format = "%a %b %d %X %Z %Y"; int dummy; Tcl_WideInt baseClock, clockVal; long zone; Tcl_Obj *baseObjPtr = NULL; char *scanStr; int n; static CONST char *switches[] = {"clicks", "format", "scan", "seconds", (char *) NULL}; enum command { COMMAND_CLICKS, COMMAND_FORMAT, COMMAND_SCAN, COMMAND_SECONDS }; static CONST char *formatSwitches[] = {"-format", "-gmt", (char *) NULL}; static CONST char *scanSwitches[] = {"-base", "-gmt", (char *) NULL}; resultPtr = Tcl_GetObjResult(interp); if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[1], switches, "option", 0, &index) != TCL_OK) { return TCL_ERROR; } switch ((enum command) index) { case COMMAND_CLICKS: { /* clicks */ int forceMilli = 0; if (objc == 3) { format = Tcl_GetStringFromObj(objv[2], &n); if ( ( n >= 2 ) && ( strncmp( format, "-milliseconds", (unsigned int) n) == 0 ) ) { forceMilli = 1; } else { Tcl_AppendStringsToObj(resultPtr, "bad switch \"", format, "\": must be -milliseconds", (char *) NULL); return TCL_ERROR; } } else if (objc != 2) { Tcl_WrongNumArgs(interp, 2, objv, "?-milliseconds?"); return TCL_ERROR; } if (forceMilli) { /* * We can enforce at least millisecond granularity */ Tcl_Time time; Tcl_GetTime(&time); Tcl_SetLongObj(resultPtr, (long) (time.sec*1000 + time.usec/1000)); } else { Tcl_SetLongObj(resultPtr, (long) TclpGetClicks()); } return TCL_OK; } case COMMAND_FORMAT: /* format */ if ((objc < 3) || (objc > 7)) { wrongFmtArgs: Tcl_WrongNumArgs(interp, 2, objv, "clockval ?-format string? ?-gmt boolean?"); return TCL_ERROR; } if (Tcl_GetWideIntFromObj(interp, objv[2], &clockVal) != TCL_OK) { return TCL_ERROR; } objPtr = objv+3; objc -= 3; while (objc > 1) { if (Tcl_GetIndexFromObj(interp, objPtr[0], formatSwitches, "switch", 0, &index) != TCL_OK) { return TCL_ERROR; } switch (index) { case 0: /* -format */ format = Tcl_GetStringFromObj(objPtr[1], &dummy); break; case 1: /* -gmt */ if (Tcl_GetBooleanFromObj(interp, objPtr[1], &useGMT) != TCL_OK) { return TCL_ERROR; } break; } objPtr += 2; objc -= 2; } if (objc != 0) { goto wrongFmtArgs; } return FormatClock(interp, clockVal, useGMT, format); case COMMAND_SCAN: /* scan */ if ((objc < 3) || (objc > 7)) { wrongScanArgs: Tcl_WrongNumArgs(interp, 2, objv, "dateString ?-base clockValue? ?-gmt boolean?"); return TCL_ERROR; } objPtr = objv+3; objc -= 3; while (objc > 1) { if (Tcl_GetIndexFromObj(interp, objPtr[0], scanSwitches, "switch", 0, &index) != TCL_OK) { return TCL_ERROR; } switch (index) { case 0: /* -base */ baseObjPtr = objPtr[1]; break; case 1: /* -gmt */ if (Tcl_GetBooleanFromObj(interp, objPtr[1], &useGMT) != TCL_OK) { return TCL_ERROR; } break; } objPtr += 2; objc -= 2; } if (objc != 0) { goto wrongScanArgs; } if (baseObjPtr != NULL) { if (Tcl_GetWideIntFromObj(interp, baseObjPtr, &baseClock) != TCL_OK) { return TCL_ERROR; } } else { baseClock = TclpGetSeconds(); } if (useGMT) { zone = -50000; /* Force GMT */ } else { zone = TclpGetTimeZone(baseClock); } scanStr = Tcl_GetStringFromObj(objv[2], &dummy); Tcl_MutexLock(&clockMutex); if (TclGetDate(scanStr, baseClock, zone, &clockVal) < 0) { Tcl_MutexUnlock(&clockMutex); Tcl_AppendStringsToObj(resultPtr, "unable to convert date-time string \"", scanStr, "\"", (char *) NULL); return TCL_ERROR; } Tcl_MutexUnlock(&clockMutex); Tcl_SetWideIntObj(resultPtr, clockVal); return TCL_OK; case COMMAND_SECONDS: /* seconds */ if (objc != 2) { Tcl_WrongNumArgs(interp, 2, objv, NULL); return TCL_ERROR; } Tcl_SetLongObj(resultPtr, (long) TclpGetSeconds()); return TCL_OK; default: return TCL_ERROR; /* Should never be reached. */ } } /* *----------------------------------------------------------------------------- * * FormatClock -- * * Formats a time value based on seconds into a human readable * string. * * Results: * Standard Tcl result. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static int FormatClock(interp, clockVal, useGMT, format) Tcl_Interp *interp; /* Current interpreter. */ Tcl_WideInt clockVal; /* Time in seconds. */ int useGMT; /* Boolean */ char *format; /* Format string */ { struct tm *timeDataPtr; Tcl_DString buffer, uniBuffer; int bufSize; char *p; int result; time_t tclockVal; #if !defined(HAVE_TM_ZONE) && !defined(WIN32) TIMEZONE_t savedTimeZone = 0; /* lint. */ char *savedTZEnv = NULL; /* lint. */ #endif #ifdef HAVE_TZSET /* * Some systems forgot to call tzset in localtime, make sure its done. */ static int calledTzset = 0; Tcl_MutexLock(&clockMutex); if (!calledTzset) { tzset(); calledTzset = 1; } Tcl_MutexUnlock(&clockMutex); #endif /* * If the user gave us -format "", just return now */ if (*format == '\0') { return TCL_OK; } #if !defined(HAVE_TM_ZONE) && !defined(WIN32) /* * This is a kludge for systems not having the timezone string in * struct tm. No matter what was specified, they use the local * timezone string. Since this kludge requires fiddling with the * TZ environment variable, it will mess up if done on multiple * threads at once. Protect it with a the clock mutex. */ Tcl_MutexLock( &clockMutex ); if (useGMT) { CONST char *varValue; varValue = Tcl_GetVar2(interp, "env", "TZ", TCL_GLOBAL_ONLY); if (varValue != NULL) { savedTZEnv = strcpy(ckalloc(strlen(varValue) + 1), varValue); } else { savedTZEnv = NULL; } Tcl_SetVar2(interp, "env", "TZ", "GMT0", TCL_GLOBAL_ONLY); savedTimeZone = timezone; timezone = 0; tzset(); } #endif tclockVal = (time_t) clockVal; timeDataPtr = TclpGetDate((TclpTime_t) &tclockVal, useGMT); /* * Make a guess at the upper limit on the substituted string size * based on the number of percents in the string. */ for (bufSize = 1, p = format; *p != '\0'; p++) { if (*p == '%') { bufSize += 40; if (p[1] == 'c') { bufSize += 226; } } else { bufSize++; } } Tcl_DStringInit(&uniBuffer); Tcl_UtfToExternalDString(NULL, format, -1, &uniBuffer); Tcl_DStringInit(&buffer); Tcl_DStringSetLength(&buffer, bufSize); /* If we haven't locked the clock mutex up above, lock it now. */ #if defined(HAVE_TM_ZONE) || defined(WIN32) Tcl_MutexLock(&clockMutex); #endif result = TclpStrftime(buffer.string, (unsigned int) bufSize, Tcl_DStringValue(&uniBuffer), timeDataPtr, useGMT); #if defined(HAVE_TM_ZONE) || defined(WIN32) Tcl_MutexUnlock(&clockMutex); #endif Tcl_DStringFree(&uniBuffer); #if !defined(HAVE_TM_ZONE) && !defined(WIN32) if (useGMT) { if (savedTZEnv != NULL) { Tcl_SetVar2(interp, "env", "TZ", savedTZEnv, TCL_GLOBAL_ONLY); ckfree(savedTZEnv); } else { Tcl_UnsetVar2(interp, "env", "TZ", TCL_GLOBAL_ONLY); } timezone = savedTimeZone; tzset(); } Tcl_MutexUnlock( &clockMutex ); #endif if (result == 0) { /* * A zero return is the error case (can also mean the strftime * didn't get enough space to write into). We know it doesn't * mean that we wrote zero chars because the check for an empty * format string is above. */ Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "bad format string \"", format, "\"", (char *) NULL); return TCL_ERROR; } /* * Convert the time to UTF from external encoding [Bug: 3345] */ Tcl_DStringInit(&uniBuffer); Tcl_ExternalToUtfDString(NULL, buffer.string, -1, &uniBuffer); Tcl_SetStringObj(Tcl_GetObjResult(interp), uniBuffer.string, -1); Tcl_DStringFree(&uniBuffer); Tcl_DStringFree(&buffer); return TCL_OK; } tcl8.4.20/generic/regguts.h0000644003604700454610000003067212151137515014163 0ustar dgp771div/* * Internal interface definitions, etc., for the reg package * * Copyright (c) 1998, 1999 Henry Spencer. All rights reserved. * * Development of this software was funded, in part, by Cray Research Inc., * UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics * Corporation, none of whom are responsible for the results. The author * thanks all of them. * * Redistribution and use in source and binary forms -- with or without * modification -- are permitted for any purpose, provided that * redistributions in source form retain this entire copyright notice and * indicate the origin and nature of any modifications. * * I'd appreciate being given credit for this package in the documentation * of software which uses it, but that is not a requirement. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * HENRY SPENCER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Environmental customization. It should not (I hope) be necessary to * alter the file you are now reading -- regcustom.h should handle it all, * given care here and elsewhere. */ #include "regcustom.h" /* * Things that regcustom.h might override. */ /* standard header files (NULL is a reasonable indicator for them) */ #ifndef NULL #include #include #include #include #include #endif /* assertions */ #ifndef assert # ifndef REG_DEBUG # ifndef NDEBUG # define NDEBUG /* no assertions */ # endif # endif #include #endif /* voids */ #ifndef VOID #define VOID void /* for function return values */ #endif #ifndef DISCARD #define DISCARD VOID /* for throwing values away */ #endif #ifndef PVOID #define PVOID VOID * /* generic pointer */ #endif #ifndef VS #define VS(x) ((PVOID)(x)) /* cast something to generic ptr */ #endif #ifndef NOPARMS #define NOPARMS VOID /* for empty parm lists */ #endif /* const */ #ifndef CONST #define CONST const /* for old compilers, might be empty */ #endif /* function-pointer declarator */ #ifndef FUNCPTR #if __STDC__ >= 1 #define FUNCPTR(name, args) (*name)args #else #define FUNCPTR(name, args) (*name)() #endif #endif /* memory allocation */ #ifndef MALLOC #define MALLOC(n) malloc(n) #endif #ifndef REALLOC #define REALLOC(p, n) realloc(VS(p), n) #endif #ifndef FREE #define FREE(p) free(VS(p)) #endif /* want size of a char in bits, and max value in bounded quantifiers */ #ifndef CHAR_BIT #include #endif #ifndef _POSIX2_RE_DUP_MAX #define _POSIX2_RE_DUP_MAX 255 /* normally from */ #endif /* * misc */ #define NOTREACHED 0 #define xxx 1 #define DUPMAX _POSIX2_RE_DUP_MAX #define INFINITY (DUPMAX+1) #define REMAGIC 0xfed7 /* magic number for main struct */ /* * debugging facilities */ #ifdef REG_DEBUG /* FDEBUG does finite-state tracing */ #define FDEBUG(arglist) { if (v->eflags®_FTRACE) printf arglist; } /* MDEBUG does higher-level tracing */ #define MDEBUG(arglist) { if (v->eflags®_MTRACE) printf arglist; } #else #define FDEBUG(arglist) {} #define MDEBUG(arglist) {} #endif /* * bitmap manipulation */ #define UBITS (CHAR_BIT * sizeof(unsigned)) #define BSET(uv, sn) ((uv)[(sn)/UBITS] |= (unsigned)1 << ((sn)%UBITS)) #define ISBSET(uv, sn) ((uv)[(sn)/UBITS] & ((unsigned)1 << ((sn)%UBITS))) /* * We dissect a chr into byts for colormap table indexing. Here we define * a byt, which will be the same as a byte on most machines... The exact * size of a byt is not critical, but about 8 bits is good, and extraction * of 8-bit chunks is sometimes especially fast. */ #ifndef BYTBITS #define BYTBITS 8 /* bits in a byt */ #endif #define BYTTAB (1<flags&FREECOL) union tree *block; /* block of solid color, if any */ }; /* the color map itself */ struct colormap { int magic; # define CMMAGIC 0x876 struct vars *v; /* for compile error reporting */ size_t ncds; /* number of colordescs */ size_t max; /* highest in use */ color free; /* beginning of free chain (if non-0) */ struct colordesc *cd; # define CDEND(cm) (&(cm)->cd[(cm)->max + 1]) # define NINLINECDS ((size_t)10) struct colordesc cdspace[NINLINECDS]; union tree tree[NBYTS]; /* tree top, plus fill blocks */ }; /* optimization magic to do fast chr->color mapping */ #define B0(c) ((c) & BYTMASK) #define B1(c) (((c)>>BYTBITS) & BYTMASK) #define B2(c) (((c)>>(2*BYTBITS)) & BYTMASK) #define B3(c) (((c)>>(3*BYTBITS)) & BYTMASK) #if NBYTS == 1 #define GETCOLOR(cm, c) ((cm)->tree->tcolor[B0(c)]) #endif /* beware, for NBYTS>1, GETCOLOR() is unsafe -- 2nd arg used repeatedly */ #if NBYTS == 2 #define GETCOLOR(cm, c) ((cm)->tree->tptr[B1(c)]->tcolor[B0(c)]) #endif #if NBYTS == 4 #define GETCOLOR(cm, c) ((cm)->tree->tptr[B3(c)]->tptr[B2(c)]->tptr[B1(c)]->tcolor[B0(c)]) #endif /* * Interface definitions for locale-interface functions in locale.c. * Multi-character collating elements (MCCEs) cause most of the trouble. */ struct cvec { int nchrs; /* number of chrs */ int chrspace; /* number of chrs possible */ chr *chrs; /* pointer to vector of chrs */ int nranges; /* number of ranges (chr pairs) */ int rangespace; /* number of chrs possible */ chr *ranges; /* pointer to vector of chr pairs */ int nmcces; /* number of MCCEs */ int mccespace; /* number of MCCEs possible */ int nmccechrs; /* number of chrs used for MCCEs */ chr *mcces[1]; /* pointers to 0-terminated MCCEs */ /* and both batches of chrs are on the end */ }; /* caution: this value cannot be changed easily */ #define MAXMCCE 2 /* length of longest MCCE */ /* * definitions for NFA internal representation * * Having a "from" pointer within each arc may seem redundant, but it * saves a lot of hassle. */ struct state; struct arc { int type; # define ARCFREE '\0' color co; struct state *from; /* where it's from (and contained within) */ struct state *to; /* where it's to */ struct arc *outchain; /* *from's outs chain or free chain */ # define freechain outchain struct arc *inchain; /* *to's ins chain */ struct arc *colorchain; /* color's arc chain */ struct arc *colorchain_rev; /* back-link in color's arc chain */ }; struct arcbatch { /* for bulk allocation of arcs */ struct arcbatch *next; # define ABSIZE 10 struct arc a[ABSIZE]; }; struct state { int no; # define FREESTATE (-1) char flag; /* marks special states */ int nins; /* number of inarcs */ struct arc *ins; /* chain of inarcs */ int nouts; /* number of outarcs */ struct arc *outs; /* chain of outarcs */ struct arc *free; /* chain of free arcs */ struct state *tmp; /* temporary for traversal algorithms */ struct state *next; /* chain for traversing all */ struct state *prev; /* back chain */ struct arcbatch oas; /* first arcbatch, avoid malloc in easy case */ int noas; /* number of arcs used in first arcbatch */ }; struct nfa { struct state *pre; /* pre-initial state */ struct state *init; /* initial state */ struct state *final; /* final state */ struct state *post; /* post-final state */ int nstates; /* for numbering states */ struct state *states; /* state-chain header */ struct state *slast; /* tail of the chain */ struct state *free; /* free list */ struct colormap *cm; /* the color map */ color bos[2]; /* colors, if any, assigned to BOS and BOL */ color eos[2]; /* colors, if any, assigned to EOS and EOL */ size_t size; /* current NFA size; differs from nstates as * it will be incremented by its children */ struct vars *v; /* simplifies compile error reporting */ struct nfa *parent; /* parent NFA, if any */ }; /* * definitions for compacted NFA */ struct carc { color co; /* COLORLESS is list terminator */ int to; /* state number */ }; struct cnfa { int nstates; /* number of states */ int ncolors; /* number of colors */ int flags; # define HASLACONS 01 /* uses lookahead constraints */ int pre; /* setup state number */ int post; /* teardown state number */ color bos[2]; /* colors, if any, assigned to BOS and BOL */ color eos[2]; /* colors, if any, assigned to EOS and EOL */ struct carc **states; /* vector of pointers to outarc lists */ struct carc *arcs; /* the area for the lists */ }; #define ZAPCNFA(cnfa) ((cnfa).nstates = 0) #define NULLCNFA(cnfa) ((cnfa).nstates == 0) /* Used to limit the maximum NFA size */ #ifndef REG_MAX_STATES #define REG_MAX_STATES 100000 #endif /* * subexpression tree */ struct subre { char op; /* '|', '.' (concat), 'b' (backref), '(', '=' */ char flags; # define LONGER 01 /* prefers longer match */ # define SHORTER 02 /* prefers shorter match */ # define MIXED 04 /* mixed preference below */ # define CAP 010 /* capturing parens below */ # define BACKR 020 /* back reference below */ # define INUSE 0100 /* in use in final tree */ # define NOPROP 03 /* bits which may not propagate up */ # define LMIX(f) ((f)<<2) /* LONGER -> MIXED */ # define SMIX(f) ((f)<<1) /* SHORTER -> MIXED */ # define UP(f) (((f)&~NOPROP) | (LMIX(f) & SMIX(f) & MIXED)) # define MESSY(f) ((f)&(MIXED|CAP|BACKR)) # define PREF(f) ((f)&NOPROP) # define PREF2(f1, f2) ((PREF(f1) != 0) ? PREF(f1) : PREF(f2)) # define COMBINE(f1, f2) (UP((f1)|(f2)) | PREF2(f1, f2)) short retry; /* index into retry memory */ int subno; /* subexpression number (for 'b' and '(') */ short min; /* min repetitions, for backref only */ short max; /* max repetitions, for backref only */ struct subre *left; /* left child, if any (also freelist chain) */ struct subre *right; /* right child, if any */ struct state *begin; /* outarcs from here... */ struct state *end; /* ...ending in inarcs here */ struct cnfa cnfa; /* compacted NFA, if any */ struct subre *chain; /* for bookkeeping and error cleanup */ }; /* * table of function pointers for generic manipulation functions * A regex_t's re_fns points to one of these. */ struct fns { VOID FUNCPTR(free, (regex_t *)); }; /* * the insides of a regex_t, hidden behind a void * */ struct guts { int magic; # define GUTSMAGIC 0xfed9 int cflags; /* copy of compile flags */ long info; /* copy of re_info */ size_t nsub; /* copy of re_nsub */ struct subre *tree; struct cnfa search; /* for fast preliminary search */ int ntree; struct colormap cmap; int FUNCPTR(compare, (CONST chr *, CONST chr *, size_t)); struct subre *lacons; /* lookahead-constraint vector */ int nlacons; /* size of lacons */ }; tcl8.4.20/generic/tclHash.c0000644003604700454610000007771611737050674014107 0ustar dgp771div/* * tclHash.c -- * * Implementation of in-memory hash tables for Tcl and Tcl-based * applications. * * Copyright (c) 1991-1993 The Regents of the University of California. * Copyright (c) 1994 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" /* * Prevent macros from clashing with function definitions. */ #if TCL_PRESERVE_BINARY_COMPATABILITY # undef Tcl_FindHashEntry # undef Tcl_CreateHashEntry #endif /* * When there are this many entries per bucket, on average, rebuild * the hash table to make it larger. */ #define REBUILD_MULTIPLIER 3 /* * The following macro takes a preliminary integer hash value and * produces an index into a hash tables bucket list. The idea is * to make it so that preliminary values that are arbitrarily similar * will end up in different buckets. The hash function was taken * from a random-number generator. */ #define RANDOM_INDEX(tablePtr, i) \ (((((long) (i))*1103515245) >> (tablePtr)->downShift) & (tablePtr)->mask) /* * Prototypes for the array hash key methods. */ static Tcl_HashEntry * AllocArrayEntry _ANSI_ARGS_(( Tcl_HashTable *tablePtr, VOID *keyPtr)); static int CompareArrayKeys _ANSI_ARGS_(( VOID *keyPtr, Tcl_HashEntry *hPtr)); static unsigned int HashArrayKey _ANSI_ARGS_(( Tcl_HashTable *tablePtr, VOID *keyPtr)); /* * Prototypes for the one word hash key methods. */ #if 0 static Tcl_HashEntry * AllocOneWordEntry _ANSI_ARGS_(( Tcl_HashTable *tablePtr, VOID *keyPtr)); static int CompareOneWordKeys _ANSI_ARGS_(( VOID *keyPtr, Tcl_HashEntry *hPtr)); static unsigned int HashOneWordKey _ANSI_ARGS_(( Tcl_HashTable *tablePtr, VOID *keyPtr)); #endif /* * Prototypes for the string hash key methods. */ static Tcl_HashEntry * AllocStringEntry _ANSI_ARGS_(( Tcl_HashTable *tablePtr, VOID *keyPtr)); static int CompareStringKeys _ANSI_ARGS_(( VOID *keyPtr, Tcl_HashEntry *hPtr)); static unsigned int HashStringKey _ANSI_ARGS_(( Tcl_HashTable *tablePtr, VOID *keyPtr)); /* * Procedure prototypes for static procedures in this file: */ #if TCL_PRESERVE_BINARY_COMPATABILITY static Tcl_HashEntry * BogusFind _ANSI_ARGS_((Tcl_HashTable *tablePtr, CONST char *key)); static Tcl_HashEntry * BogusCreate _ANSI_ARGS_((Tcl_HashTable *tablePtr, CONST char *key, int *newPtr)); static Tcl_HashEntry * FindHashEntry _ANSI_ARGS_((Tcl_HashTable *tablePtr, CONST char *key)); static Tcl_HashEntry * CreateHashEntry _ANSI_ARGS_((Tcl_HashTable *tablePtr, CONST char *key, int *newPtr)); #endif static void RebuildTable _ANSI_ARGS_((Tcl_HashTable *tablePtr)); Tcl_HashKeyType tclArrayHashKeyType = { TCL_HASH_KEY_TYPE_VERSION, /* version */ TCL_HASH_KEY_RANDOMIZE_HASH, /* flags */ HashArrayKey, /* hashKeyProc */ CompareArrayKeys, /* compareKeysProc */ AllocArrayEntry, /* allocEntryProc */ NULL /* freeEntryProc */ }; Tcl_HashKeyType tclOneWordHashKeyType = { TCL_HASH_KEY_TYPE_VERSION, /* version */ 0, /* flags */ NULL, /* HashOneWordKey, */ /* hashProc */ NULL, /* CompareOneWordKey, */ /* compareProc */ NULL, /* AllocOneWordKey, */ /* allocEntryProc */ NULL /* FreeOneWordKey, */ /* freeEntryProc */ }; Tcl_HashKeyType tclStringHashKeyType = { TCL_HASH_KEY_TYPE_VERSION, /* version */ 0, /* flags */ HashStringKey, /* hashKeyProc */ CompareStringKeys, /* compareKeysProc */ AllocStringEntry, /* allocEntryProc */ NULL /* freeEntryProc */ }; /* *---------------------------------------------------------------------- * * Tcl_InitHashTable -- * * Given storage for a hash table, set up the fields to prepare * the hash table for use. * * Results: * None. * * Side effects: * TablePtr is now ready to be passed to Tcl_FindHashEntry and * Tcl_CreateHashEntry. * *---------------------------------------------------------------------- */ #undef Tcl_InitHashTable void Tcl_InitHashTable(tablePtr, keyType) register Tcl_HashTable *tablePtr; /* Pointer to table record, which * is supplied by the caller. */ int keyType; /* Type of keys to use in table: * TCL_STRING_KEYS, TCL_ONE_WORD_KEYS, * or an integer >= 2. */ { /* * Use a special value to inform the extended version that it must * not access any of the new fields in the Tcl_HashTable. If an * extension is rebuilt then any calls to this function will be * redirected to the extended version by a macro. */ Tcl_InitCustomHashTable(tablePtr, keyType, (Tcl_HashKeyType *) -1); } /* *---------------------------------------------------------------------- * * Tcl_InitCustomHashTable -- * * Given storage for a hash table, set up the fields to prepare * the hash table for use. This is an extended version of * Tcl_InitHashTable which supports user defined keys. * * Results: * None. * * Side effects: * TablePtr is now ready to be passed to Tcl_FindHashEntry and * Tcl_CreateHashEntry. * *---------------------------------------------------------------------- */ void Tcl_InitCustomHashTable(tablePtr, keyType, typePtr) register Tcl_HashTable *tablePtr; /* Pointer to table record, which * is supplied by the caller. */ int keyType; /* Type of keys to use in table: * TCL_STRING_KEYS, TCL_ONE_WORD_KEYS, * TCL_CUSTOM_TYPE_KEYS, * TCL_CUSTOM_PTR_KEYS, or an * integer >= 2. */ Tcl_HashKeyType *typePtr; /* Pointer to structure which defines * the behaviour of this table. */ { #if (TCL_SMALL_HASH_TABLE != 4) panic("Tcl_InitCustomHashTable: TCL_SMALL_HASH_TABLE is %d, not 4\n", TCL_SMALL_HASH_TABLE); #endif tablePtr->buckets = tablePtr->staticBuckets; tablePtr->staticBuckets[0] = tablePtr->staticBuckets[1] = 0; tablePtr->staticBuckets[2] = tablePtr->staticBuckets[3] = 0; tablePtr->numBuckets = TCL_SMALL_HASH_TABLE; tablePtr->numEntries = 0; tablePtr->rebuildSize = TCL_SMALL_HASH_TABLE*REBUILD_MULTIPLIER; tablePtr->downShift = 28; tablePtr->mask = 3; tablePtr->keyType = keyType; #if TCL_PRESERVE_BINARY_COMPATABILITY tablePtr->findProc = FindHashEntry; tablePtr->createProc = CreateHashEntry; if (typePtr == NULL) { /* * The caller has been rebuilt so the hash table is an extended * version. */ } else if (typePtr != (Tcl_HashKeyType *) -1) { /* * The caller is requesting a customized hash table so it must be * an extended version. */ tablePtr->typePtr = typePtr; } else { /* * The caller has not been rebuilt so the hash table is not * extended. */ } #else if (typePtr == NULL) { /* * Use the key type to decide which key type is needed. */ if (keyType == TCL_STRING_KEYS) { typePtr = &tclStringHashKeyType; } else if (keyType == TCL_ONE_WORD_KEYS) { typePtr = &tclOneWordHashKeyType; } else if (keyType == TCL_CUSTOM_TYPE_KEYS) { Tcl_Panic ("No type structure specified for TCL_CUSTOM_TYPE_KEYS"); } else if (keyType == TCL_CUSTOM_PTR_KEYS) { Tcl_Panic ("No type structure specified for TCL_CUSTOM_PTR_KEYS"); } else { typePtr = &tclArrayHashKeyType; } } else if (typePtr == (Tcl_HashKeyType *) -1) { /* * If the caller has not been rebuilt then we cannot continue as * the hash table is not an extended version. */ Tcl_Panic ("Hash table is not compatible"); } tablePtr->typePtr = typePtr; #endif } /* *---------------------------------------------------------------------- * * Tcl_FindHashEntry -- * * Given a hash table find the entry with a matching key. * * Results: * The return value is a token for the matching entry in the * hash table, or NULL if there was no matching entry. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_HashEntry * Tcl_FindHashEntry(tablePtr, key) Tcl_HashTable *tablePtr; /* Table in which to lookup entry. */ CONST char *key; /* Key to use to find matching entry. */ #if TCL_PRESERVE_BINARY_COMPATABILITY { return tablePtr->findProc(tablePtr, key); } static Tcl_HashEntry * FindHashEntry(tablePtr, key) Tcl_HashTable *tablePtr; /* Table in which to lookup entry. */ CONST char *key; /* Key to use to find matching entry. */ #endif /* TCL_PRESERVE_BINARY_COMPATABILITY */ { register Tcl_HashEntry *hPtr; Tcl_HashKeyType *typePtr; unsigned int hash; int index; #if TCL_PRESERVE_BINARY_COMPATABILITY if (tablePtr->keyType == TCL_STRING_KEYS) { typePtr = &tclStringHashKeyType; } else if (tablePtr->keyType == TCL_ONE_WORD_KEYS) { typePtr = &tclOneWordHashKeyType; } else if (tablePtr->keyType == TCL_CUSTOM_TYPE_KEYS || tablePtr->keyType == TCL_CUSTOM_PTR_KEYS) { typePtr = tablePtr->typePtr; } else { typePtr = &tclArrayHashKeyType; } #else typePtr = tablePtr->typePtr; if (typePtr == NULL) { Tcl_Panic("called Tcl_FindHashEntry on deleted table"); return NULL; } #endif if (typePtr->hashKeyProc) { hash = typePtr->hashKeyProc (tablePtr, (VOID *) key); if (typePtr->flags & TCL_HASH_KEY_RANDOMIZE_HASH) { index = RANDOM_INDEX (tablePtr, hash); } else { index = hash & tablePtr->mask; } } else { hash = (unsigned int) key; index = RANDOM_INDEX (tablePtr, hash); } /* * Search all of the entries in the appropriate bucket. */ if (typePtr->compareKeysProc) { Tcl_CompareHashKeysProc *compareKeysProc = typePtr->compareKeysProc; for (hPtr = tablePtr->buckets[index]; hPtr != NULL; hPtr = hPtr->nextPtr) { #if TCL_HASH_KEY_STORE_HASH if (hash != (unsigned int) hPtr->hash) { continue; } #endif if (compareKeysProc ((VOID *) key, hPtr)) { return hPtr; } } } else { for (hPtr = tablePtr->buckets[index]; hPtr != NULL; hPtr = hPtr->nextPtr) { #if TCL_HASH_KEY_STORE_HASH if (hash != (unsigned int) hPtr->hash) { continue; } #endif if (key == hPtr->key.oneWordValue) { return hPtr; } } } return NULL; } /* *---------------------------------------------------------------------- * * Tcl_CreateHashEntry -- * * Given a hash table with string keys, and a string key, find * the entry with a matching key. If there is no matching entry, * then create a new entry that does match. * * Results: * The return value is a pointer to the matching entry. If this * is a newly-created entry, then *newPtr will be set to a non-zero * value; otherwise *newPtr will be set to 0. If this is a new * entry the value stored in the entry will initially be 0. * * Side effects: * A new entry may be added to the hash table. * *---------------------------------------------------------------------- */ Tcl_HashEntry * Tcl_CreateHashEntry(tablePtr, key, newPtr) Tcl_HashTable *tablePtr; /* Table in which to lookup entry. */ CONST char *key; /* Key to use to find or create matching * entry. */ int *newPtr; /* Store info here telling whether a new * entry was created. */ #if TCL_PRESERVE_BINARY_COMPATABILITY { return tablePtr->createProc(tablePtr, key, newPtr); } static Tcl_HashEntry * CreateHashEntry(tablePtr, key, newPtr) Tcl_HashTable *tablePtr; /* Table in which to lookup entry. */ CONST char *key; /* Key to use to find or create matching * entry. */ int *newPtr; /* Store info here telling whether a new * entry was created. */ #endif /* TCL_PRESERVE_BINARY_COMPATABILITY */ { register Tcl_HashEntry *hPtr; Tcl_HashKeyType *typePtr; unsigned int hash; int index; #if TCL_PRESERVE_BINARY_COMPATABILITY if (tablePtr->keyType == TCL_STRING_KEYS) { typePtr = &tclStringHashKeyType; } else if (tablePtr->keyType == TCL_ONE_WORD_KEYS) { typePtr = &tclOneWordHashKeyType; } else if (tablePtr->keyType == TCL_CUSTOM_TYPE_KEYS || tablePtr->keyType == TCL_CUSTOM_PTR_KEYS) { typePtr = tablePtr->typePtr; } else { typePtr = &tclArrayHashKeyType; } #else typePtr = tablePtr->typePtr; if (typePtr == NULL) { Tcl_Panic("called Tcl_CreateHashEntry on deleted table"); return NULL; } #endif if (typePtr->hashKeyProc) { hash = typePtr->hashKeyProc (tablePtr, (VOID *) key); if (typePtr->flags & TCL_HASH_KEY_RANDOMIZE_HASH) { index = RANDOM_INDEX (tablePtr, hash); } else { index = hash & tablePtr->mask; } } else { hash = (unsigned int) key; index = RANDOM_INDEX (tablePtr, hash); } /* * Search all of the entries in the appropriate bucket. */ if (typePtr->compareKeysProc) { Tcl_CompareHashKeysProc *compareKeysProc = typePtr->compareKeysProc; for (hPtr = tablePtr->buckets[index]; hPtr != NULL; hPtr = hPtr->nextPtr) { #if TCL_HASH_KEY_STORE_HASH if (hash != (unsigned int) hPtr->hash) { continue; } #endif if (compareKeysProc ((VOID *) key, hPtr)) { *newPtr = 0; return hPtr; } } } else { for (hPtr = tablePtr->buckets[index]; hPtr != NULL; hPtr = hPtr->nextPtr) { #if TCL_HASH_KEY_STORE_HASH if (hash != (unsigned int) hPtr->hash) { continue; } #endif if (key == hPtr->key.oneWordValue) { *newPtr = 0; return hPtr; } } } /* * Entry not found. Add a new one to the bucket. */ *newPtr = 1; if (typePtr->allocEntryProc) { hPtr = typePtr->allocEntryProc (tablePtr, (VOID *) key); } else { hPtr = (Tcl_HashEntry *) ckalloc((unsigned) sizeof(Tcl_HashEntry)); hPtr->key.oneWordValue = (char *) key; } hPtr->tablePtr = tablePtr; #if TCL_HASH_KEY_STORE_HASH # if TCL_PRESERVE_BINARY_COMPATABILITY hPtr->hash = (VOID *) hash; # else hPtr->hash = hash; # endif hPtr->nextPtr = tablePtr->buckets[index]; tablePtr->buckets[index] = hPtr; #else hPtr->bucketPtr = &(tablePtr->buckets[index]); hPtr->nextPtr = *hPtr->bucketPtr; *hPtr->bucketPtr = hPtr; #endif hPtr->clientData = 0; tablePtr->numEntries++; /* * If the table has exceeded a decent size, rebuild it with many * more buckets. */ if (tablePtr->numEntries >= tablePtr->rebuildSize) { RebuildTable(tablePtr); } return hPtr; } /* *---------------------------------------------------------------------- * * Tcl_DeleteHashEntry -- * * Remove a single entry from a hash table. * * Results: * None. * * Side effects: * The entry given by entryPtr is deleted from its table and * should never again be used by the caller. It is up to the * caller to free the clientData field of the entry, if that * is relevant. * *---------------------------------------------------------------------- */ void Tcl_DeleteHashEntry(entryPtr) Tcl_HashEntry *entryPtr; { register Tcl_HashEntry *prevPtr; Tcl_HashKeyType *typePtr; Tcl_HashTable *tablePtr; Tcl_HashEntry **bucketPtr; #if TCL_HASH_KEY_STORE_HASH int index; #endif tablePtr = entryPtr->tablePtr; #if TCL_PRESERVE_BINARY_COMPATABILITY if (tablePtr->keyType == TCL_STRING_KEYS) { typePtr = &tclStringHashKeyType; } else if (tablePtr->keyType == TCL_ONE_WORD_KEYS) { typePtr = &tclOneWordHashKeyType; } else if (tablePtr->keyType == TCL_CUSTOM_TYPE_KEYS || tablePtr->keyType == TCL_CUSTOM_PTR_KEYS) { typePtr = tablePtr->typePtr; } else { typePtr = &tclArrayHashKeyType; } #else typePtr = tablePtr->typePtr; #endif #if TCL_HASH_KEY_STORE_HASH if (typePtr->hashKeyProc == NULL || typePtr->flags & TCL_HASH_KEY_RANDOMIZE_HASH) { index = RANDOM_INDEX (tablePtr, entryPtr->hash); } else { index = ((unsigned int) entryPtr->hash) & tablePtr->mask; } bucketPtr = &(tablePtr->buckets[index]); #else bucketPtr = entryPtr->bucketPtr; #endif if (*bucketPtr == entryPtr) { *bucketPtr = entryPtr->nextPtr; } else { for (prevPtr = *bucketPtr; ; prevPtr = prevPtr->nextPtr) { if (prevPtr == NULL) { panic("malformed bucket chain in Tcl_DeleteHashEntry"); } if (prevPtr->nextPtr == entryPtr) { prevPtr->nextPtr = entryPtr->nextPtr; break; } } } tablePtr->numEntries--; if (typePtr->freeEntryProc) { typePtr->freeEntryProc (entryPtr); } else { ckfree((char *) entryPtr); } } /* *---------------------------------------------------------------------- * * Tcl_DeleteHashTable -- * * Free up everything associated with a hash table except for * the record for the table itself. * * Results: * None. * * Side effects: * The hash table is no longer useable. * *---------------------------------------------------------------------- */ void Tcl_DeleteHashTable(tablePtr) register Tcl_HashTable *tablePtr; /* Table to delete. */ { register Tcl_HashEntry *hPtr, *nextPtr; Tcl_HashKeyType *typePtr; int i; #if TCL_PRESERVE_BINARY_COMPATABILITY if (tablePtr->keyType == TCL_STRING_KEYS) { typePtr = &tclStringHashKeyType; } else if (tablePtr->keyType == TCL_ONE_WORD_KEYS) { typePtr = &tclOneWordHashKeyType; } else if (tablePtr->keyType == TCL_CUSTOM_TYPE_KEYS || tablePtr->keyType == TCL_CUSTOM_PTR_KEYS) { typePtr = tablePtr->typePtr; } else { typePtr = &tclArrayHashKeyType; } #else typePtr = tablePtr->typePtr; #endif /* * Free up all the entries in the table. */ for (i = 0; i < tablePtr->numBuckets; i++) { hPtr = tablePtr->buckets[i]; while (hPtr != NULL) { nextPtr = hPtr->nextPtr; if (typePtr->freeEntryProc) { typePtr->freeEntryProc (hPtr); } else { ckfree((char *) hPtr); } hPtr = nextPtr; } } /* * Free up the bucket array, if it was dynamically allocated. */ if (tablePtr->buckets != tablePtr->staticBuckets) { ckfree((char *) tablePtr->buckets); } /* * Arrange for panics if the table is used again without * re-initialization. */ #if TCL_PRESERVE_BINARY_COMPATABILITY tablePtr->findProc = BogusFind; tablePtr->createProc = BogusCreate; #else tablePtr->typePtr = NULL; #endif } /* *---------------------------------------------------------------------- * * Tcl_FirstHashEntry -- * * Locate the first entry in a hash table and set up a record * that can be used to step through all the remaining entries * of the table. * * Results: * The return value is a pointer to the first entry in tablePtr, * or NULL if tablePtr has no entries in it. The memory at * *searchPtr is initialized so that subsequent calls to * Tcl_NextHashEntry will return all of the entries in the table, * one at a time. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_HashEntry * Tcl_FirstHashEntry(tablePtr, searchPtr) Tcl_HashTable *tablePtr; /* Table to search. */ Tcl_HashSearch *searchPtr; /* Place to store information about * progress through the table. */ { searchPtr->tablePtr = tablePtr; searchPtr->nextIndex = 0; searchPtr->nextEntryPtr = NULL; return Tcl_NextHashEntry(searchPtr); } /* *---------------------------------------------------------------------- * * Tcl_NextHashEntry -- * * Once a hash table enumeration has been initiated by calling * Tcl_FirstHashEntry, this procedure may be called to return * successive elements of the table. * * Results: * The return value is the next entry in the hash table being * enumerated, or NULL if the end of the table is reached. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_HashEntry * Tcl_NextHashEntry(searchPtr) register Tcl_HashSearch *searchPtr; /* Place to store information about * progress through the table. Must * have been initialized by calling * Tcl_FirstHashEntry. */ { Tcl_HashEntry *hPtr; Tcl_HashTable *tablePtr = searchPtr->tablePtr; while (searchPtr->nextEntryPtr == NULL) { if (searchPtr->nextIndex >= tablePtr->numBuckets) { return NULL; } searchPtr->nextEntryPtr = tablePtr->buckets[searchPtr->nextIndex]; searchPtr->nextIndex++; } hPtr = searchPtr->nextEntryPtr; searchPtr->nextEntryPtr = hPtr->nextPtr; return hPtr; } /* *---------------------------------------------------------------------- * * Tcl_HashStats -- * * Return statistics describing the layout of the hash table * in its hash buckets. * * Results: * The return value is a malloc-ed string containing information * about tablePtr. It is the caller's responsibility to free * this string. * * Side effects: * None. * *---------------------------------------------------------------------- */ char * Tcl_HashStats(tablePtr) Tcl_HashTable *tablePtr; /* Table for which to produce stats. */ { #define NUM_COUNTERS 10 int count[NUM_COUNTERS], overflow, i, j; double average, tmp; register Tcl_HashEntry *hPtr; char *result, *p; /* * Compute a histogram of bucket usage. */ for (i = 0; i < NUM_COUNTERS; i++) { count[i] = 0; } overflow = 0; average = 0.0; for (i = 0; i < tablePtr->numBuckets; i++) { j = 0; for (hPtr = tablePtr->buckets[i]; hPtr != NULL; hPtr = hPtr->nextPtr) { j++; } if (j < NUM_COUNTERS) { count[j]++; } else { overflow++; } tmp = j; average += (tmp+1.0)*(tmp/tablePtr->numEntries)/2.0; } /* * Print out the histogram and a few other pieces of information. */ result = (char *) ckalloc((unsigned) ((NUM_COUNTERS*60) + 300)); sprintf(result, "%d entries in table, %d buckets\n", tablePtr->numEntries, tablePtr->numBuckets); p = result + strlen(result); for (i = 0; i < NUM_COUNTERS; i++) { sprintf(p, "number of buckets with %d entries: %d\n", i, count[i]); p += strlen(p); } sprintf(p, "number of buckets with %d or more entries: %d\n", NUM_COUNTERS, overflow); p += strlen(p); sprintf(p, "average search distance for entry: %.1f", average); return result; } /* *---------------------------------------------------------------------- * * AllocArrayEntry -- * * Allocate space for a Tcl_HashEntry containing the array key. * * Results: * The return value is a pointer to the created entry. * * Side effects: * None. * *---------------------------------------------------------------------- */ static Tcl_HashEntry * AllocArrayEntry(tablePtr, keyPtr) Tcl_HashTable *tablePtr; /* Hash table. */ VOID *keyPtr; /* Key to store in the hash table entry. */ { int *array = (int *) keyPtr; register int *iPtr1, *iPtr2; Tcl_HashEntry *hPtr; int count; unsigned int size; count = tablePtr->keyType; size = sizeof(Tcl_HashEntry) + (count*sizeof(int)) - sizeof(hPtr->key); if (size < sizeof(Tcl_HashEntry)) size = sizeof(Tcl_HashEntry); hPtr = (Tcl_HashEntry *) ckalloc(size); for (iPtr1 = array, iPtr2 = hPtr->key.words; count > 0; count--, iPtr1++, iPtr2++) { *iPtr2 = *iPtr1; } return hPtr; } /* *---------------------------------------------------------------------- * * CompareArrayKeys -- * * Compares two array keys. * * Results: * The return value is 0 if they are different and 1 if they are * the same. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int CompareArrayKeys(keyPtr, hPtr) VOID *keyPtr; /* New key to compare. */ Tcl_HashEntry *hPtr; /* Existing key to compare. */ { register CONST int *iPtr1 = (CONST int *) keyPtr; register CONST int *iPtr2 = (CONST int *) hPtr->key.words; Tcl_HashTable *tablePtr = hPtr->tablePtr; int count; for (count = tablePtr->keyType; ; count--, iPtr1++, iPtr2++) { if (count == 0) { return 1; } if (*iPtr1 != *iPtr2) { break; } } return 0; } /* *---------------------------------------------------------------------- * * HashArrayKey -- * * Compute a one-word summary of an array, which can be * used to generate a hash index. * * Results: * The return value is a one-word summary of the information in * string. * * Side effects: * None. * *---------------------------------------------------------------------- */ static unsigned int HashArrayKey(tablePtr, keyPtr) Tcl_HashTable *tablePtr; /* Hash table. */ VOID *keyPtr; /* Key from which to compute hash value. */ { register CONST int *array = (CONST int *) keyPtr; register unsigned int result; int count; for (result = 0, count = tablePtr->keyType; count > 0; count--, array++) { result += *array; } return result; } /* *---------------------------------------------------------------------- * * AllocStringEntry -- * * Allocate space for a Tcl_HashEntry containing the string key. * * Results: * The return value is a pointer to the created entry. * * Side effects: * None. * *---------------------------------------------------------------------- */ static Tcl_HashEntry * AllocStringEntry(tablePtr, keyPtr) Tcl_HashTable *tablePtr; /* Hash table. */ VOID *keyPtr; /* Key to store in the hash table entry. */ { CONST char *string = (CONST char *) keyPtr; Tcl_HashEntry *hPtr; unsigned int size, allocsize; allocsize = size = strlen(string) + 1; if (size < sizeof(hPtr->key)) { allocsize = sizeof(hPtr->key); } hPtr = (Tcl_HashEntry *) ckalloc(sizeof(Tcl_HashEntry) + allocsize - sizeof(hPtr->key)); memcpy(hPtr->key.string, string, size); return hPtr; } /* *---------------------------------------------------------------------- * * CompareStringKeys -- * * Compares two string keys. * * Results: * The return value is 0 if they are different and 1 if they are * the same. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int CompareStringKeys(keyPtr, hPtr) VOID *keyPtr; /* New key to compare. */ Tcl_HashEntry *hPtr; /* Existing key to compare. */ { register CONST char *p1 = (CONST char *) keyPtr; register CONST char *p2 = (CONST char *) hPtr->key.string; for (;; p1++, p2++) { if (*p1 != *p2) { break; } if (*p1 == '\0') { return 1; } } return 0; } /* *---------------------------------------------------------------------- * * HashStringKey -- * * Compute a one-word summary of a text string, which can be * used to generate a hash index. * * Results: * The return value is a one-word summary of the information in * string. * * Side effects: * None. * *---------------------------------------------------------------------- */ static unsigned int HashStringKey(tablePtr, keyPtr) Tcl_HashTable *tablePtr; /* Hash table. */ VOID *keyPtr; /* Key from which to compute hash value. */ { register CONST char *string = (CONST char *) keyPtr; register unsigned int result; register int c; /* * I tried a zillion different hash functions and asked many other * people for advice. Many people had their own favorite functions, * all different, but no-one had much idea why they were good ones. * I chose the one below (multiply by 9 and add new character) * because of the following reasons: * * 1. Multiplying by 10 is perfect for keys that are decimal strings, * and multiplying by 9 is just about as good. * 2. Times-9 is (shift-left-3) plus (old). This means that each * character's bits hang around in the low-order bits of the * hash value for ever, plus they spread fairly rapidly up to * the high-order bits to fill out the hash value. This seems * works well both for decimal and non-decimal strings. */ result = 0; while (1) { c = *string; if (c == 0) { break; } result += (result<<3) + c; string++; } return result; } #if TCL_PRESERVE_BINARY_COMPATABILITY /* *---------------------------------------------------------------------- * * BogusFind -- * * This procedure is invoked when an Tcl_FindHashEntry is called * on a table that has been deleted. * * Results: * If panic returns (which it shouldn't) this procedure returns * NULL. * * Side effects: * Generates a panic. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static Tcl_HashEntry * BogusFind(tablePtr, key) Tcl_HashTable *tablePtr; /* Table in which to lookup entry. */ CONST char *key; /* Key to use to find matching entry. */ { panic("called Tcl_FindHashEntry on deleted table"); return NULL; } /* *---------------------------------------------------------------------- * * BogusCreate -- * * This procedure is invoked when an Tcl_CreateHashEntry is called * on a table that has been deleted. * * Results: * If panic returns (which it shouldn't) this procedure returns * NULL. * * Side effects: * Generates a panic. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static Tcl_HashEntry * BogusCreate(tablePtr, key, newPtr) Tcl_HashTable *tablePtr; /* Table in which to lookup entry. */ CONST char *key; /* Key to use to find or create matching * entry. */ int *newPtr; /* Store info here telling whether a new * entry was created. */ { panic("called Tcl_CreateHashEntry on deleted table"); return NULL; } #endif /* *---------------------------------------------------------------------- * * RebuildTable -- * * This procedure is invoked when the ratio of entries to hash * buckets becomes too large. It creates a new table with a * larger bucket array and moves all of the entries into the * new table. * * Results: * None. * * Side effects: * Memory gets reallocated and entries get re-hashed to new * buckets. * *---------------------------------------------------------------------- */ static void RebuildTable(tablePtr) register Tcl_HashTable *tablePtr; /* Table to enlarge. */ { int oldSize, count, index; Tcl_HashEntry **oldBuckets; register Tcl_HashEntry **oldChainPtr, **newChainPtr; register Tcl_HashEntry *hPtr; Tcl_HashKeyType *typePtr; oldSize = tablePtr->numBuckets; oldBuckets = tablePtr->buckets; /* * Allocate and initialize the new bucket array, and set up * hashing constants for new array size. */ tablePtr->numBuckets *= 4; tablePtr->buckets = (Tcl_HashEntry **) ckalloc((unsigned) (tablePtr->numBuckets * sizeof(Tcl_HashEntry *))); for (count = tablePtr->numBuckets, newChainPtr = tablePtr->buckets; count > 0; count--, newChainPtr++) { *newChainPtr = NULL; } tablePtr->rebuildSize *= 4; tablePtr->downShift -= 2; tablePtr->mask = (tablePtr->mask << 2) + 3; #if TCL_PRESERVE_BINARY_COMPATABILITY if (tablePtr->keyType == TCL_STRING_KEYS) { typePtr = &tclStringHashKeyType; } else if (tablePtr->keyType == TCL_ONE_WORD_KEYS) { typePtr = &tclOneWordHashKeyType; } else if (tablePtr->keyType == TCL_CUSTOM_TYPE_KEYS || tablePtr->keyType == TCL_CUSTOM_PTR_KEYS) { typePtr = tablePtr->typePtr; } else { typePtr = &tclArrayHashKeyType; } #else typePtr = tablePtr->typePtr; #endif /* * Rehash all of the existing entries into the new bucket array. */ for (oldChainPtr = oldBuckets; oldSize > 0; oldSize--, oldChainPtr++) { for (hPtr = *oldChainPtr; hPtr != NULL; hPtr = *oldChainPtr) { *oldChainPtr = hPtr->nextPtr; #if TCL_HASH_KEY_STORE_HASH if (typePtr->hashKeyProc == NULL || typePtr->flags & TCL_HASH_KEY_RANDOMIZE_HASH) { index = RANDOM_INDEX (tablePtr, hPtr->hash); } else { index = ((unsigned int) hPtr->hash) & tablePtr->mask; } hPtr->nextPtr = tablePtr->buckets[index]; tablePtr->buckets[index] = hPtr; #else VOID *key = (VOID *) Tcl_GetHashKey (tablePtr, hPtr); if (typePtr->hashKeyProc) { unsigned int hash; hash = typePtr->hashKeyProc (tablePtr, (VOID *) key); if (typePtr->flags & TCL_HASH_KEY_RANDOMIZE_HASH) { index = RANDOM_INDEX (tablePtr, hash); } else { index = hash & tablePtr->mask; } } else { index = RANDOM_INDEX (tablePtr, key); } hPtr->bucketPtr = &(tablePtr->buckets[index]); hPtr->nextPtr = *hPtr->bucketPtr; *hPtr->bucketPtr = hPtr; #endif } } /* * Free up the old bucket array, if it was dynamically allocated. */ if (oldBuckets != tablePtr->staticBuckets) { ckfree((char *) oldBuckets); } } tcl8.4.20/generic/tclInt.decls0000644003604700454610000005642712133546540014613 0ustar dgp771div# tclInt.decls -- # # This file contains the declarations for all unsupported # functions that are exported by the Tcl library. This file # is used to generate the tclIntDecls.h, tclIntPlatDecls.h, # tclIntStub.c, tclPlatStub.c, tclCompileDecls.h and tclCompileStub.c # files # # Copyright (c) 1998-1999 by Scriptics Corporation. # Copyright (c) 2001 by Kevin B. Kenny. All rights reserved. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. library tcl # Define the unsupported generic interfaces. interface tclInt # Declare each of the functions in the unsupported internal Tcl # interface. These interfaces are allowed to changed between versions. # Use at your own risk. Note that the position of functions should not # be changed between versions to avoid gratuitous incompatibilities. # Replaced by Tcl_FSAccess in 8.4: #declare 0 { # int TclAccess(const char *path, int mode) #} declare 1 { int TclAccessDeleteProc(TclAccessProc_ *proc) } declare 2 { int TclAccessInsertProc(TclAccessProc_ *proc) } declare 3 { void TclAllocateFreeObjects(void) } # Replaced by TclpChdir in 8.1: # declare 4 { # int TclChdir(Tcl_Interp *interp, char *dirName) # } declare 5 { int TclCleanupChildren(Tcl_Interp *interp, int numPids, Tcl_Pid *pidPtr, Tcl_Channel errorChan) } declare 6 { void TclCleanupCommand(Command *cmdPtr) } declare 7 { int TclCopyAndCollapse(int count, const char *src, char *dst) } declare 8 { int TclCopyChannel(Tcl_Interp *interp, Tcl_Channel inChan, Tcl_Channel outChan, int toRead, Tcl_Obj *cmdPtr) } # TclCreatePipeline unofficially exported for use by BLT. declare 9 { int TclCreatePipeline(Tcl_Interp *interp, int argc, const char **argv, Tcl_Pid **pidArrayPtr, TclFile *inPipePtr, TclFile *outPipePtr, TclFile *errFilePtr) } declare 10 { int TclCreateProc(Tcl_Interp *interp, Namespace *nsPtr, const char *procName, Tcl_Obj *argsPtr, Tcl_Obj *bodyPtr, Proc **procPtrPtr) } declare 11 { void TclDeleteCompiledLocalVars(Interp *iPtr, CallFrame *framePtr) } declare 12 { void TclDeleteVars(Interp *iPtr, Tcl_HashTable *tablePtr) } declare 13 { int TclDoGlob(Tcl_Interp *interp, char *separators, Tcl_DString *headPtr, char *tail, Tcl_GlobTypeData *types) } declare 14 { void TclDumpMemoryInfo(FILE *outFile) } # Removed in 8.1: # declare 15 { # void TclExpandParseValue(ParseValue *pvPtr, int needed) # } declare 16 { void TclExprFloatError(Tcl_Interp *interp, double value) } # Removed in 8.4: #declare 17 { # int TclFileAttrsCmd(Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) #} #declare 18 { # int TclFileCopyCmd(Tcl_Interp *interp, int argc, char **argv) #} #declare 19 { # int TclFileDeleteCmd(Tcl_Interp *interp, int argc, char **argv) #} #declare 20 { # int TclFileMakeDirsCmd(Tcl_Interp *interp, int argc, char **argv) #} #declare 21 { # int TclFileRenameCmd(Tcl_Interp *interp, int argc, char **argv) #} declare 22 { int TclFindElement(Tcl_Interp *interp, const char *listStr, int listLength, const char **elementPtr, const char **nextPtr, int *sizePtr, int *bracePtr) } declare 23 { Proc *TclFindProc(Interp *iPtr, const char *procName) } declare 24 { int TclFormatInt(char *buffer, long n) } declare 25 { void TclFreePackageInfo(Interp *iPtr) } # Removed in 8.1: # declare 26 { # char *TclGetCwd(Tcl_Interp *interp) # } declare 27 { int TclGetDate(char *p, Tcl_WideInt now, long zone, Tcl_WideInt *timePtr) } declare 28 { Tcl_Channel TclpGetDefaultStdChannel(int type) } # Removed in 8.4b2: #declare 29 { # Tcl_Obj *TclGetElementOfIndexedArray(Tcl_Interp *interp, # int localIndex, Tcl_Obj *elemPtr, int flags) #} # Replaced by char *TclGetEnv(const char *name, Tcl_DString *valuePtr) in 8.1: # declare 30 { # char *TclGetEnv(const char *name) # } declare 31 { char *TclGetExtension(char *name) } declare 32 { int TclGetFrame(Tcl_Interp *interp, const char *str, CallFrame **framePtrPtr) } declare 33 { TclCmdProcType TclGetInterpProc(void) } declare 34 { int TclGetIntForIndex(Tcl_Interp *interp, Tcl_Obj *objPtr, int endValue, int *indexPtr) } # Removed in 8.4b2: #declare 35 { # Tcl_Obj *TclGetIndexedScalar(Tcl_Interp *interp, int localIndex, # int flags) #} declare 36 { int TclGetLong(Tcl_Interp *interp, const char *str, long *longPtr) } declare 37 { int TclGetLoadedPackages(Tcl_Interp *interp, char *targetName) } declare 38 { int TclGetNamespaceForQualName(Tcl_Interp *interp, const char *qualName, Namespace *cxtNsPtr, int flags, Namespace **nsPtrPtr, Namespace **altNsPtrPtr, Namespace **actualCxtPtrPtr, const char **simpleNamePtr) } declare 39 { TclObjCmdProcType TclGetObjInterpProc(void) } declare 40 { int TclGetOpenMode(Tcl_Interp *interp, const char *str, int *seekFlagPtr) } declare 41 { Tcl_Command TclGetOriginalCommand(Tcl_Command command) } declare 42 { char *TclpGetUserHome(const char *name, Tcl_DString *bufferPtr) } declare 43 { int TclGlobalInvoke(Tcl_Interp *interp, int argc, CONST84 char **argv, int flags) } declare 44 { int TclGuessPackageName(const char *fileName, Tcl_DString *bufPtr) } declare 45 { int TclHideUnsafeCommands(Tcl_Interp *interp) } declare 46 { int TclInExit(void) } # Removed in 8.4b2: #declare 47 { # Tcl_Obj *TclIncrElementOfIndexedArray(Tcl_Interp *interp, # int localIndex, Tcl_Obj *elemPtr, long incrAmount) #} # Removed in 8.4b2: #declare 48 { # Tcl_Obj *TclIncrIndexedScalar(Tcl_Interp *interp, int localIndex, # long incrAmount) #} declare 49 { Tcl_Obj *TclIncrVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, long incrAmount, int part1NotParsed) } declare 50 { void TclInitCompiledLocals(Tcl_Interp *interp, CallFrame *framePtr, Namespace *nsPtr) } declare 51 { int TclInterpInit(Tcl_Interp *interp) } declare 52 { int TclInvoke(Tcl_Interp *interp, int argc, CONST84 char **argv, int flags) } declare 53 { int TclInvokeObjectCommand(ClientData clientData, Tcl_Interp *interp, int argc, CONST84 char **argv) } declare 54 { int TclInvokeStringCommand(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) } declare 55 { Proc *TclIsProc(Command *cmdPtr) } # Replaced with TclpLoadFile in 8.1: # declare 56 { # int TclLoadFile(Tcl_Interp *interp, char *fileName, char *sym1, # char *sym2, Tcl_PackageInitProc **proc1Ptr, # Tcl_PackageInitProc **proc2Ptr) # } # Signature changed to take a length in 8.1: # declare 57 { # int TclLooksLikeInt(char *p) # } declare 58 { Var *TclLookupVar(Tcl_Interp *interp, const char *part1, const char *part2, int flags, const char *msg, int createPart1, int createPart2, Var **arrayPtrPtr) } # Replaced by Tcl_FSMatchInDirectory in 8.4 #declare 59 { # int TclpMatchFiles(Tcl_Interp *interp, char *separators, # Tcl_DString *dirPtr, char *pattern, char *tail) #} declare 60 { int TclNeedSpace(const char *start, const char *end) } declare 61 { Tcl_Obj *TclNewProcBodyObj(Proc *procPtr) } declare 62 { int TclObjCommandComplete(Tcl_Obj *cmdPtr) } declare 63 { int TclObjInterpProc(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) } declare 64 { int TclObjInvoke(Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], int flags) } declare 65 { int TclObjInvokeGlobal(Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], int flags) } declare 66 { int TclOpenFileChannelDeleteProc(TclOpenFileChannelProc_ *proc) } declare 67 { int TclOpenFileChannelInsertProc(TclOpenFileChannelProc_ *proc) } # Replaced by Tcl_FSAccess in 8.4: #declare 68 { # int TclpAccess(const char *path, int mode) #} declare 69 { char *TclpAlloc(unsigned int size) } #declare 70 { # int TclpCopyFile(const char *source, const char *dest) #} #declare 71 { # int TclpCopyDirectory(const char *source, const char *dest, # Tcl_DString *errorPtr) #} #declare 72 { # int TclpCreateDirectory(const char *path) #} #declare 73 { # int TclpDeleteFile(const char *path) #} declare 74 { void TclpFree(char *ptr) } declare 75 { unsigned long TclpGetClicks(void) } declare 76 { unsigned long TclpGetSeconds(void) } # deprecated declare 77 { void TclpGetTime(Tcl_Time *time) } declare 78 { int TclpGetTimeZone(Tcl_WideInt time) } # Replaced by Tcl_FSListVolumes in 8.4: #declare 79 { # int TclpListVolumes(Tcl_Interp *interp) #} # Replaced by Tcl_FSOpenFileChannel in 8.4: #declare 80 { # Tcl_Channel TclpOpenFileChannel(Tcl_Interp *interp, char *fileName, # char *modeString, int permissions) #} declare 81 { char *TclpRealloc(char *ptr, unsigned int size) } #declare 82 { # int TclpRemoveDirectory(const char *path, int recursive, # Tcl_DString *errorPtr) #} #declare 83 { # int TclpRenameFile(const char *source, const char *dest) #} # Removed in 8.1: # declare 84 { # int TclParseBraces(Tcl_Interp *interp, char *str, char **termPtr, # ParseValue *pvPtr) # } # declare 85 { # int TclParseNestedCmd(Tcl_Interp *interp, char *str, int flags, # char **termPtr, ParseValue *pvPtr) # } # declare 86 { # int TclParseQuotes(Tcl_Interp *interp, char *str, int termChar, # int flags, char **termPtr, ParseValue *pvPtr) # } # declare 87 { # void TclPlatformInit(Tcl_Interp *interp) # } declare 88 { char *TclPrecTraceProc(ClientData clientData, Tcl_Interp *interp, const char *name1, const char *name2, int flags) } declare 89 { int TclPreventAliasLoop(Tcl_Interp *interp, Tcl_Interp *cmdInterp, Tcl_Command cmd) } # Removed in 8.1 (only available if compiled with TCL_COMPILE_DEBUG): # declare 90 { # void TclPrintByteCodeObj(Tcl_Interp *interp, Tcl_Obj *objPtr) # } declare 91 { void TclProcCleanupProc(Proc *procPtr) } declare 92 { int TclProcCompileProc(Tcl_Interp *interp, Proc *procPtr, Tcl_Obj *bodyPtr, Namespace *nsPtr, const char *description, const char *procName) } declare 93 { void TclProcDeleteProc(ClientData clientData) } declare 94 { int TclProcInterpProc(ClientData clientData, Tcl_Interp *interp, int argc, CONST84 char **argv) } # Replaced by Tcl_FSStat in 8.4: #declare 95 { # int TclpStat(const char *path, Tcl_StatBuf *buf) #} declare 96 { int TclRenameCommand(Tcl_Interp *interp, char *oldName, char *newName) } declare 97 { void TclResetShadowedCmdRefs(Tcl_Interp *interp, Command *newCmdPtr) } declare 98 { int TclServiceIdle(void) } # Removed in 8.4b2: #declare 99 { # Tcl_Obj *TclSetElementOfIndexedArray(Tcl_Interp *interp, int localIndex, # Tcl_Obj *elemPtr, Tcl_Obj *objPtr, int flags) #} # Removed in 8.4b2: #declare 100 { # Tcl_Obj *TclSetIndexedScalar(Tcl_Interp *interp, int localIndex, # Tcl_Obj *objPtr, int flags) #} declare 101 { char *TclSetPreInitScript(char *string) } declare 102 { void TclSetupEnv(Tcl_Interp *interp) } declare 103 { int TclSockGetPort(Tcl_Interp *interp, char *str, char *proto, int *portPtr) } declare 104 { int TclSockMinimumBuffersOld(int sock, int size) } # Replaced by Tcl_FSStat in 8.4: #declare 105 { # int TclStat(const char *path, Tcl_StatBuf *buf) #} declare 106 { int TclStatDeleteProc(TclStatProc_ *proc) } declare 107 { int TclStatInsertProc(TclStatProc_ *proc) } declare 108 { void TclTeardownNamespace(Namespace *nsPtr) } declare 109 { int TclUpdateReturnInfo(Interp *iPtr) } declare 110 { int TclSockMinimumBuffers(void *sock, int size) } # Removed in 8.1: # declare 110 { # char *TclWordEnd(char *start, char *lastChar, int nested, int *semiPtr) # } # Procedures used in conjunction with Tcl namespaces. They are # defined here instead of in tcl.decls since they are not stable yet. declare 111 { void Tcl_AddInterpResolvers(Tcl_Interp *interp, const char *name, Tcl_ResolveCmdProc *cmdProc, Tcl_ResolveVarProc *varProc, Tcl_ResolveCompiledVarProc *compiledVarProc) } declare 112 { int Tcl_AppendExportList(Tcl_Interp *interp, Tcl_Namespace *nsPtr, Tcl_Obj *objPtr) } declare 113 { Tcl_Namespace *Tcl_CreateNamespace(Tcl_Interp *interp, const char *name, ClientData clientData, Tcl_NamespaceDeleteProc *deleteProc) } declare 114 { void Tcl_DeleteNamespace(Tcl_Namespace *nsPtr) } declare 115 { int Tcl_Export(Tcl_Interp *interp, Tcl_Namespace *nsPtr, const char *pattern, int resetListFirst) } declare 116 { Tcl_Command Tcl_FindCommand(Tcl_Interp *interp, const char *name, Tcl_Namespace *contextNsPtr, int flags) } declare 117 { Tcl_Namespace *Tcl_FindNamespace(Tcl_Interp *interp, const char *name, Tcl_Namespace *contextNsPtr, int flags) } declare 118 { int Tcl_GetInterpResolvers(Tcl_Interp *interp, const char *name, Tcl_ResolverInfo *resInfo) } declare 119 { int Tcl_GetNamespaceResolvers(Tcl_Namespace *namespacePtr, Tcl_ResolverInfo *resInfo) } declare 120 { Tcl_Var Tcl_FindNamespaceVar(Tcl_Interp *interp, const char *name, Tcl_Namespace *contextNsPtr, int flags) } declare 121 { int Tcl_ForgetImport(Tcl_Interp *interp, Tcl_Namespace *nsPtr, const char *pattern) } declare 122 { Tcl_Command Tcl_GetCommandFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr) } declare 123 { void Tcl_GetCommandFullName(Tcl_Interp *interp, Tcl_Command command, Tcl_Obj *objPtr) } declare 124 { Tcl_Namespace *Tcl_GetCurrentNamespace(Tcl_Interp *interp) } declare 125 { Tcl_Namespace *Tcl_GetGlobalNamespace(Tcl_Interp *interp) } declare 126 { void Tcl_GetVariableFullName(Tcl_Interp *interp, Tcl_Var variable, Tcl_Obj *objPtr) } declare 127 { int Tcl_Import(Tcl_Interp *interp, Tcl_Namespace *nsPtr, const char *pattern, int allowOverwrite) } declare 128 { void Tcl_PopCallFrame(Tcl_Interp *interp) } declare 129 { int Tcl_PushCallFrame(Tcl_Interp *interp, Tcl_CallFrame *framePtr, Tcl_Namespace *nsPtr, int isProcCallFrame) } declare 130 { int Tcl_RemoveInterpResolvers(Tcl_Interp *interp, const char *name) } declare 131 { void Tcl_SetNamespaceResolvers(Tcl_Namespace *namespacePtr, Tcl_ResolveCmdProc *cmdProc, Tcl_ResolveVarProc *varProc, Tcl_ResolveCompiledVarProc *compiledVarProc) } declare 132 { int TclpHasSockets(Tcl_Interp *interp) } declare 133 { struct tm *TclpGetDate(TclpTime_t time, int useGMT) } declare 134 { size_t TclpStrftime(char *s, size_t maxsize, const char *format, const struct tm *t, int useGMT) } declare 135 { int TclpCheckStackSpace(void) } declare 138 { CONST84_RETURN char *TclGetEnv(const char *name, Tcl_DString *valuePtr) } declare 140 { int TclLooksLikeInt(const char *bytes, int length) } # This is used by TclX, but should otherwise be considered private declare 141 { CONST84_RETURN char *TclpGetCwd(Tcl_Interp *interp, Tcl_DString *cwdPtr) } declare 142 { int TclSetByteCodeFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr, CompileHookProc *hookProc, ClientData clientData) } declare 143 { int TclAddLiteralObj(struct CompileEnv *envPtr, Tcl_Obj *objPtr, LiteralEntry **litPtrPtr) } declare 144 { void TclHideLiteral(Tcl_Interp *interp, struct CompileEnv *envPtr, int index) } declare 145 { struct AuxDataType *TclGetAuxDataType(char *typeName) } declare 146 { TclHandle TclHandleCreate(void *ptr) } declare 147 { void TclHandleFree(TclHandle handle) } declare 148 { TclHandle TclHandlePreserve(TclHandle handle) } declare 149 { void TclHandleRelease(TclHandle handle) } # Added in 8.2: declare 150 { int TclRegAbout(Tcl_Interp *interp, Tcl_RegExp re) } declare 151 { void TclRegExpRangeUniChar(Tcl_RegExp re, int index, int *startPtr, int *endPtr) } declare 152 { void TclSetLibraryPath(Tcl_Obj *pathPtr) } declare 153 { Tcl_Obj *TclGetLibraryPath(void) } # moved to tclTest.c (static) in 8.3.2: #declare 154 { # int TclTestChannelCmd(ClientData clientData, # Tcl_Interp *interp, int argc, char **argv) #} #declare 155 { # int TclTestChannelEventCmd(ClientData clientData, # Tcl_Interp *interp, int argc, char **argv) #} declare 156 { void TclRegError(Tcl_Interp *interp, const char *msg, int status) } declare 157 { Var *TclVarTraceExists(Tcl_Interp *interp, const char *varName) } declare 158 { void TclSetStartupScriptFileName(const char *filename) } declare 159 { CONST84_RETURN char *TclGetStartupScriptFileName(void) } #declare 160 { # int TclpMatchFilesTypes(Tcl_Interp *interp, char *separators, # Tcl_DString *dirPtr, char *pattern, char *tail, # GlobTypeData *types) #} # new in 8.3.2/8.4a2 declare 161 { int TclChannelTransform(Tcl_Interp *interp, Tcl_Channel chan, Tcl_Obj *cmdObjPtr) } declare 162 { void TclChannelEventScriptInvoker(ClientData clientData, int flags) } # ALERT: The result of 'TclGetInstructionTable' is actually a # "const InstructionDesc*" but we do not want to describe this structure in # "tclInt.h". It is described in "tclCompile.h". Use a cast to the # correct type when calling this procedure. declare 163 { void *TclGetInstructionTable(void) } # ALERT: The argument of 'TclExpandCodeArray' is actually a # "CompileEnv*" but we do not want to describe this structure in # "tclInt.h". It is described in "tclCompile.h". declare 164 { void TclExpandCodeArray(void *envPtr) } # These functions are vfs aware, but are generally only useful internally. declare 165 { void TclpSetInitialEncodings(void) } # New function due to TIP #33 declare 166 { int TclListObjSetElement(Tcl_Interp *interp, Tcl_Obj *listPtr, int index, Tcl_Obj *valuePtr) } # VFS-aware versions of Tcl*StartupScriptFileName (158 and 159 above) declare 167 { void TclSetStartupScriptPath(Tcl_Obj *pathPtr) } declare 168 { Tcl_Obj *TclGetStartupScriptPath(void) } # variant of Tcl_UtfNCmp that takes n as bytes, not chars declare 169 { int TclpUtfNcmp2(const char *s1, const char *s2, unsigned long n) } declare 170 { int TclCheckInterpTraces(Tcl_Interp *interp, const char *command, int numChars, Command *cmdPtr, int result, int traceFlags, int objc, Tcl_Obj *const objv[]) } declare 171 { int TclCheckExecutionTraces(Tcl_Interp *interp, const char *command, int numChars, Command *cmdPtr, int result, int traceFlags, int objc, Tcl_Obj *const objv[]) } declare 172 { int TclInThreadExit(void) } # Added in 8.4.2: declare 173 { int TclUniCharMatch(const Tcl_UniChar *string, int strLen, const Tcl_UniChar *pattern, int ptnLen, int nocase) } # TclpGmtime and TclpLocaltime promoted to the generic interface from unix declare 182 { struct tm *TclpLocaltime(TclpTime_t_CONST clock) } declare 183 { struct tm *TclpGmtime(TclpTime_t_CONST clock) } declare 199 { int TclMatchIsTrivial(const char *pattern) } declare 249 { void TclUnusedStubEntry(void) } ############################################################################## # Define the platform specific internal Tcl interface. These functions are # only available on the designated platform. interface tclIntPlat ################################ # Windows specific functions declare 0 win { void TclWinConvertError(DWORD errCode) } declare 1 win { void TclWinConvertWSAError(DWORD errCode) } declare 2 win { struct servent *TclWinGetServByName(const char *nm, const char *proto) } declare 3 win { int TclWinGetSockOpt(SOCKET s, int level, int optname, char *optval, int *optlen) } declare 4 win { HINSTANCE TclWinGetTclInstance(void) } # new for 8.4.20+/8.5.12+ Cygwin only declare 5 win { int TclUnixWaitForFile(int fd, int mask, int timeout) } # Removed in 8.1: # declare 5 win { # HINSTANCE TclWinLoadLibrary(char *name) # } declare 6 win { unsigned short TclWinNToHS(unsigned short ns) } declare 7 win { int TclWinSetSockOpt(SOCKET s, int level, int optname, const char *optval, int optlen) } declare 8 win { int TclpGetPid(Tcl_Pid pid) } declare 9 win { int TclWinGetPlatformId(void) } # new for 8.4.20+/8.5.12+ Cygwin only declare 10 win { Tcl_DirEntry *TclpReaddir(DIR *dir) } # Removed in 8.3.1 (for Win32s only): #declare 10 win { # int TclWinSynchSpawn(void *args, int type, void **trans, Tcl_Pid *pidPtr) #} # Pipe channel functions declare 11 win { void TclGetAndDetachPids(Tcl_Interp *interp, Tcl_Channel chan) } declare 12 win { int TclpCloseFile(TclFile file) } declare 13 win { Tcl_Channel TclpCreateCommandChannel(TclFile readFile, TclFile writeFile, TclFile errorFile, int numPids, Tcl_Pid *pidPtr) } declare 14 win { int TclpCreatePipe(TclFile *readPipe, TclFile *writePipe) } declare 15 win { int TclpCreateProcess(Tcl_Interp *interp, int argc, const char **argv, TclFile inputFile, TclFile outputFile, TclFile errorFile, Tcl_Pid *pidPtr) } # new for 8.4.20+/8.5.12+ Cygwin only declare 16 win { int TclpIsAtty(int fd) } # Signature changed in 8.1: # declare 16 win { # TclFile TclpCreateTempFile(char *contents, Tcl_DString *namePtr) # } # declare 17 win { # char *TclpGetTZName(void) # } declare 18 win { TclFile TclpMakeFile(Tcl_Channel channel, int direction) } declare 19 win { TclFile TclpOpenFile(const char *fname, int mode) } declare 20 win { void TclWinAddProcess(HANDLE hProcess, DWORD id) } # new for 8.4.20+/8.5.12+ declare 21 win { char *TclpInetNtoa(struct in_addr addr) } # Removed in 8.4: #declare 21 win { # void TclpAsyncMark(Tcl_AsyncHandler async) #} # Added in 8.1: declare 22 win { TclFile TclpCreateTempFile(const char *contents) } declare 23 win { char *TclpGetTZName(int isdst) } declare 24 win { char *TclWinNoBackslash(char *path) } declare 25 win { TclPlatformType *TclWinGetPlatform(void) } declare 26 win { void TclWinSetInterfaces(int wide) } # Added in 8.3.3: declare 27 win { void TclWinFlushDirtyChannels(void) } # Added in 8.4.2: declare 28 win { void TclWinResetInterfaces(void) } ################################ # Unix specific functions # Pipe channel functions declare 0 unix { void TclGetAndDetachPids(Tcl_Interp *interp, Tcl_Channel chan) } declare 1 unix { int TclpCloseFile(TclFile file) } declare 2 unix { Tcl_Channel TclpCreateCommandChannel(TclFile readFile, TclFile writeFile, TclFile errorFile, int numPids, Tcl_Pid *pidPtr) } declare 3 unix { int TclpCreatePipe(TclFile *readPipe, TclFile *writePipe) } declare 4 unix { int TclpCreateProcess(Tcl_Interp *interp, int argc, const char **argv, TclFile inputFile, TclFile outputFile, TclFile errorFile, Tcl_Pid *pidPtr) } # Signature changed in 8.1: # declare 5 unix { # TclFile TclpCreateTempFile(char *contents, Tcl_DString *namePtr) # } declare 6 unix { TclFile TclpMakeFile(Tcl_Channel channel, int direction) } declare 7 unix { TclFile TclpOpenFile(const char *fname, int mode) } declare 8 unix { int TclUnixWaitForFile(int fd, int mask, int timeout) } # Added in 8.1: declare 9 unix { TclFile TclpCreateTempFile(const char *contents) } # Added in 8.4: declare 10 unix { Tcl_DirEntry *TclpReaddir(DIR *dir) } # Slots 11 and 12 are forwarders for functions that were promoted to # generic Stubs declare 11 unix { struct tm *TclpLocaltime_unix(TclpTime_t_CONST clock) } declare 12 unix { struct tm *TclpGmtime_unix(TclpTime_t_CONST clock) } declare 13 unix { char *TclpInetNtoa(struct in_addr addr) } declare 29 {win unix} { int TclWinCPUID(unsigned int index, unsigned int *regs) } # Local Variables: # mode: tcl # End: tcl8.4.20/generic/regcomp.c0000644003604700454610000016164012133546537014142 0ustar dgp771div/* * re_*comp and friends - compile REs * This file #includes several others (see the bottom). * * Copyright (c) 1998, 1999 Henry Spencer. All rights reserved. * * Development of this software was funded, in part, by Cray Research Inc., * UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics * Corporation, none of whom are responsible for the results. The author * thanks all of them. * * Redistribution and use in source and binary forms -- with or without * modification -- are permitted for any purpose, provided that * redistributions in source form retain this entire copyright notice and * indicate the origin and nature of any modifications. * * I'd appreciate being given credit for this package in the documentation * of software which uses it, but that is not a requirement. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * HENRY SPENCER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include "regguts.h" /* * forward declarations, up here so forward datatypes etc. are defined early */ /* =====^!^===== begin forwards =====^!^===== */ /* automatically gathered by fwd; do not hand-edit */ /* === regcomp.c === */ int compile _ANSI_ARGS_((regex_t *, CONST chr *, size_t, int)); static VOID moresubs _ANSI_ARGS_((struct vars *, int)); static int freev _ANSI_ARGS_((struct vars *, int)); static VOID makesearch _ANSI_ARGS_((struct vars *, struct nfa *)); static struct subre *parse _ANSI_ARGS_((struct vars *, int, int, struct state *, struct state *)); static struct subre *parsebranch _ANSI_ARGS_((struct vars *, int, int, struct state *, struct state *, int)); static VOID parseqatom _ANSI_ARGS_((struct vars *, int, int, struct state *, struct state *, struct subre *)); static VOID nonword _ANSI_ARGS_((struct vars *, int, struct state *, struct state *)); static VOID word _ANSI_ARGS_((struct vars *, int, struct state *, struct state *)); static int scannum _ANSI_ARGS_((struct vars *)); static VOID repeat _ANSI_ARGS_((struct vars *, struct state *, struct state *, int, int)); static VOID bracket _ANSI_ARGS_((struct vars *, struct state *, struct state *)); static VOID cbracket _ANSI_ARGS_((struct vars *, struct state *, struct state *)); static VOID brackpart _ANSI_ARGS_((struct vars *, struct state *, struct state *)); static CONST chr *scanplain _ANSI_ARGS_((struct vars *)); static VOID onechr _ANSI_ARGS_((struct vars *, pchr, struct state *, struct state *)); static VOID dovec _ANSI_ARGS_((struct vars *, struct cvec *, struct state *, struct state *)); static celt nextleader _ANSI_ARGS_((struct vars *, pchr, pchr)); static VOID wordchrs _ANSI_ARGS_((struct vars *)); static struct subre *subre _ANSI_ARGS_((struct vars *, int, int, struct state *, struct state *)); static VOID freesubre _ANSI_ARGS_((struct vars *, struct subre *)); static VOID freesrnode _ANSI_ARGS_((struct vars *, struct subre *)); static VOID optst _ANSI_ARGS_((struct vars *, struct subre *)); static int numst _ANSI_ARGS_((struct subre *, int)); static VOID markst _ANSI_ARGS_((struct subre *)); static VOID cleanst _ANSI_ARGS_((struct vars *)); static long nfatree _ANSI_ARGS_((struct vars *, struct subre *, FILE *)); static long nfanode _ANSI_ARGS_((struct vars *, struct subre *, FILE *)); static int newlacon _ANSI_ARGS_((struct vars *, struct state *, struct state *, int)); static VOID freelacons _ANSI_ARGS_((struct subre *, int)); static VOID rfree _ANSI_ARGS_((regex_t *)); static VOID dump _ANSI_ARGS_((regex_t *, FILE *)); static VOID dumpst _ANSI_ARGS_((struct subre *, FILE *, int)); static VOID stdump _ANSI_ARGS_((struct subre *, FILE *, int)); static char *stid _ANSI_ARGS_((struct subre *, char *, size_t)); /* === regc_lex.c === */ static VOID lexstart _ANSI_ARGS_((struct vars *)); static VOID prefixes _ANSI_ARGS_((struct vars *)); static VOID lexnest _ANSI_ARGS_((struct vars *, CONST chr *, CONST chr *)); static VOID lexword _ANSI_ARGS_((struct vars *)); static int next _ANSI_ARGS_((struct vars *)); static int lexescape _ANSI_ARGS_((struct vars *)); static chr lexdigits _ANSI_ARGS_((struct vars *, int, int, int)); static int brenext _ANSI_ARGS_((struct vars *, pchr)); static VOID skip _ANSI_ARGS_((struct vars *)); static chr newline _ANSI_ARGS_((NOPARMS)); #ifdef REG_DEBUG static CONST chr *ch _ANSI_ARGS_((NOPARMS)); #endif static chr chrnamed _ANSI_ARGS_((struct vars *, CONST chr *, CONST chr *, pchr)); /* === regc_color.c === */ static VOID initcm _ANSI_ARGS_((struct vars *, struct colormap *)); static VOID freecm _ANSI_ARGS_((struct colormap *)); static VOID cmtreefree _ANSI_ARGS_((struct colormap *, union tree *, int)); static color setcolor _ANSI_ARGS_((struct colormap *, pchr, pcolor)); static color maxcolor _ANSI_ARGS_((struct colormap *)); static color newcolor _ANSI_ARGS_((struct colormap *)); static VOID freecolor _ANSI_ARGS_((struct colormap *, pcolor)); static color pseudocolor _ANSI_ARGS_((struct colormap *)); static color subcolor _ANSI_ARGS_((struct colormap *, pchr c)); static color newsub _ANSI_ARGS_((struct colormap *, pcolor)); static VOID subrange _ANSI_ARGS_((struct vars *, pchr, pchr, struct state *, struct state *)); static VOID subblock _ANSI_ARGS_((struct vars *, pchr, struct state *, struct state *)); static VOID okcolors _ANSI_ARGS_((struct nfa *, struct colormap *)); static VOID colorchain _ANSI_ARGS_((struct colormap *, struct arc *)); static VOID uncolorchain _ANSI_ARGS_((struct colormap *, struct arc *)); static int singleton _ANSI_ARGS_((struct colormap *, pchr c)); static VOID rainbow _ANSI_ARGS_((struct nfa *, struct colormap *, int, pcolor, struct state *, struct state *)); static VOID colorcomplement _ANSI_ARGS_((struct nfa *, struct colormap *, int, struct state *, struct state *, struct state *)); #ifdef REG_DEBUG static VOID dumpcolors _ANSI_ARGS_((struct colormap *, FILE *)); static VOID fillcheck _ANSI_ARGS_((struct colormap *, union tree *, int, FILE *)); static VOID dumpchr _ANSI_ARGS_((pchr, FILE *)); #endif /* === regc_nfa.c === */ static struct nfa *newnfa _ANSI_ARGS_((struct vars *, struct colormap *, struct nfa *)); static VOID freenfa _ANSI_ARGS_((struct nfa *)); static struct state *newstate _ANSI_ARGS_((struct nfa *)); static struct state *newfstate _ANSI_ARGS_((struct nfa *, int flag)); static VOID dropstate _ANSI_ARGS_((struct nfa *, struct state *)); static VOID freestate _ANSI_ARGS_((struct nfa *, struct state *)); static VOID destroystate _ANSI_ARGS_((struct nfa *, struct state *)); static VOID newarc _ANSI_ARGS_((struct nfa *, int, pcolor, struct state *, struct state *)); static struct arc *allocarc _ANSI_ARGS_((struct nfa *, struct state *)); static VOID freearc _ANSI_ARGS_((struct nfa *, struct arc *)); static int hasnonemptyout _ANSI_ARGS_((struct state *)); static int nonemptyouts _ANSI_ARGS_((struct state *)); static int nonemptyins _ANSI_ARGS_((struct state *)); static struct arc *findarc _ANSI_ARGS_((struct state *, int, pcolor)); static VOID cparc _ANSI_ARGS_((struct nfa *, struct arc *, struct state *, struct state *)); static VOID moveins _ANSI_ARGS_((struct nfa *, struct state *, struct state *)); static VOID copyins _ANSI_ARGS_((struct nfa *, struct state *, struct state *, int)); static VOID moveouts _ANSI_ARGS_((struct nfa *, struct state *, struct state *)); static VOID copyouts _ANSI_ARGS_((struct nfa *, struct state *, struct state *, int)); static VOID cloneouts _ANSI_ARGS_((struct nfa *, struct state *, struct state *, struct state *, int)); static VOID delsub _ANSI_ARGS_((struct nfa *, struct state *, struct state *)); static VOID deltraverse _ANSI_ARGS_((struct nfa *, struct state *, struct state *)); static VOID dupnfa _ANSI_ARGS_((struct nfa *, struct state *, struct state *, struct state *, struct state *)); static VOID duptraverse _ANSI_ARGS_((struct nfa *, struct state *, struct state *)); static VOID cleartraverse _ANSI_ARGS_((struct nfa *, struct state *)); static VOID specialcolors _ANSI_ARGS_((struct nfa *)); static long optimize _ANSI_ARGS_((struct nfa *, FILE *)); static VOID pullback _ANSI_ARGS_((struct nfa *, FILE *)); static int pull _ANSI_ARGS_((struct nfa *, struct arc *)); static VOID pushfwd _ANSI_ARGS_((struct nfa *, FILE *)); static int push _ANSI_ARGS_((struct nfa *, struct arc *)); #define INCOMPATIBLE 1 /* destroys arc */ #define SATISFIED 2 /* constraint satisfied */ #define COMPATIBLE 3 /* compatible but not satisfied yet */ static int combine _ANSI_ARGS_((struct arc *, struct arc *)); static VOID fixempties _ANSI_ARGS_((struct nfa *, FILE *)); static struct state *emptyreachable _ANSI_ARGS_((struct state *, struct state *)); static VOID replaceempty _ANSI_ARGS_((struct nfa *, struct state *, struct state *)); static VOID cleanup _ANSI_ARGS_((struct nfa *)); static VOID markreachable _ANSI_ARGS_((struct nfa *, struct state *, struct state *, struct state *)); static VOID markcanreach _ANSI_ARGS_((struct nfa *, struct state *, struct state *, struct state *)); static long analyze _ANSI_ARGS_((struct nfa *)); static VOID compact _ANSI_ARGS_((struct nfa *, struct cnfa *)); static VOID carcsort _ANSI_ARGS_((struct carc *, struct carc *)); static VOID freecnfa _ANSI_ARGS_((struct cnfa *)); static VOID dumpnfa _ANSI_ARGS_((struct nfa *, FILE *)); #ifdef REG_DEBUG static VOID dumpstate _ANSI_ARGS_((struct state *, FILE *)); static VOID dumparcs _ANSI_ARGS_((struct state *, FILE *)); static int dumprarcs _ANSI_ARGS_((struct arc *, struct state *, FILE *, int)); static VOID dumparc _ANSI_ARGS_((struct arc *, struct state *, FILE *)); #endif static VOID dumpcnfa _ANSI_ARGS_((struct cnfa *, FILE *)); #ifdef REG_DEBUG static VOID dumpcstate _ANSI_ARGS_((int, struct carc *, struct cnfa *, FILE *)); #endif /* === regc_cvec.c === */ static struct cvec *newcvec _ANSI_ARGS_((int, int, int)); static struct cvec *clearcvec _ANSI_ARGS_((struct cvec *)); static VOID addchr _ANSI_ARGS_((struct cvec *, pchr)); static VOID addrange _ANSI_ARGS_((struct cvec *, pchr, pchr)); static int haschr _ANSI_ARGS_((struct cvec *, pchr)); static struct cvec *getcvec _ANSI_ARGS_((struct vars *, int, int)); static VOID freecvec _ANSI_ARGS_((struct cvec *)); /* === regc_locale.c === */ static celt element _ANSI_ARGS_((struct vars *, CONST chr *, CONST chr *)); static struct cvec *range _ANSI_ARGS_((struct vars *, celt, celt, int)); static int before _ANSI_ARGS_((celt, celt)); static struct cvec *eclass _ANSI_ARGS_((struct vars *, celt, int)); static struct cvec *cclass _ANSI_ARGS_((struct vars *, CONST chr *, CONST chr *, int)); static struct cvec *allcases _ANSI_ARGS_((struct vars *, pchr)); static int cmp _ANSI_ARGS_((CONST chr *, CONST chr *, size_t)); static int casecmp _ANSI_ARGS_((CONST chr *, CONST chr *, size_t)); /* automatically gathered by fwd; do not hand-edit */ /* =====^!^===== end forwards =====^!^===== */ /* internal variables, bundled for easy passing around */ struct vars { regex_t *re; CONST chr *now; /* scan pointer into string */ CONST chr *stop; /* end of string */ CONST chr *savenow; /* saved now and stop for "subroutine call" */ CONST chr *savestop; int err; /* error code (0 if none) */ int cflags; /* copy of compile flags */ int lasttype; /* type of previous token */ int nexttype; /* type of next token */ chr nextvalue; /* value (if any) of next token */ int lexcon; /* lexical context type (see lex.c) */ int nsubexp; /* subexpression count */ struct subre **subs; /* subRE pointer vector */ size_t nsubs; /* length of vector */ struct subre *sub10[10]; /* initial vector, enough for most */ struct nfa *nfa; /* the NFA */ struct colormap *cm; /* character color map */ color nlcolor; /* color of newline */ struct state *wordchrs; /* state in nfa holding word-char outarcs */ struct subre *tree; /* subexpression tree */ struct subre *treechain; /* all tree nodes allocated */ struct subre *treefree; /* any free tree nodes */ int ntree; /* number of tree nodes */ struct cvec *cv; /* interface cvec */ struct cvec *cv2; /* utility cvec */ struct cvec *mcces; /* collating-element information */ # define ISCELEADER(v,c) (v->mcces != NULL && haschr(v->mcces, (c))) struct state *mccepbegin; /* in nfa, start of MCCE prototypes */ struct state *mccepend; /* in nfa, end of MCCE prototypes */ struct subre *lacons; /* lookahead-constraint vector */ int nlacons; /* size of lacons */ }; /* parsing macros; most know that `v' is the struct vars pointer */ #define NEXT() (next(v)) /* advance by one token */ #define SEE(t) (v->nexttype == (t)) /* is next token this? */ #define EAT(t) (SEE(t) && next(v)) /* if next is this, swallow it */ #define VISERR(vv) ((vv)->err != 0) /* have we seen an error yet? */ #define ISERR() VISERR(v) #define VERR(vv,e) ((vv)->nexttype = EOS, ((vv)->err) ? (vv)->err :\ ((vv)->err = (e))) #define ERR(e) VERR(v, e) /* record an error */ #define NOERR() {if (ISERR()) return;} /* if error seen, return */ #define NOERRN() {if (ISERR()) return NULL;} /* NOERR with retval */ #define NOERRZ() {if (ISERR()) return 0;} /* NOERR with retval */ #define INSIST(c, e) ((c) ? 0 : ERR(e)) /* if condition false, error */ #define NOTE(b) (v->re->re_info |= (b)) /* note visible condition */ #define EMPTYARC(x, y) newarc(v->nfa, EMPTY, 0, x, y) /* token type codes, some also used as NFA arc types */ #define EMPTY 'n' /* no token present */ #define EOS 'e' /* end of string */ #define PLAIN 'p' /* ordinary character */ #define DIGIT 'd' /* digit (in bound) */ #define BACKREF 'b' /* back reference */ #define COLLEL 'I' /* start of [. */ #define ECLASS 'E' /* start of [= */ #define CCLASS 'C' /* start of [: */ #define END 'X' /* end of [. [= [: */ #define RANGE 'R' /* - within [] which might be range delim. */ #define LACON 'L' /* lookahead constraint subRE */ #define AHEAD 'a' /* color-lookahead arc */ #define BEHIND 'r' /* color-lookbehind arc */ #define WBDRY 'w' /* word boundary constraint */ #define NWBDRY 'W' /* non-word-boundary constraint */ #define SBEGIN 'A' /* beginning of string (even if not BOL) */ #define SEND 'Z' /* end of string (even if not EOL) */ #define PREFER 'P' /* length preference */ /* is an arc colored, and hence on a color chain? */ #define COLORED(a) ((a)->type == PLAIN || (a)->type == AHEAD || \ (a)->type == BEHIND) /* static function list */ static struct fns functions = { rfree, /* regfree insides */ }; /* - compile - compile regular expression ^ int compile(regex_t *, CONST chr *, size_t, int); */ int compile(re, string, len, flags) regex_t *re; CONST chr *string; size_t len; int flags; { struct vars var; struct vars *v = &var; struct guts *g; int i; size_t j; FILE *debug = (flags®_PROGRESS) ? stdout : (FILE *)NULL; # define CNOERR() { if (ISERR()) return freev(v, v->err); } /* sanity checks */ if (re == NULL || string == NULL) return REG_INVARG; if ((flags®_QUOTE) && (flags&(REG_ADVANCED|REG_EXPANDED|REG_NEWLINE))) return REG_INVARG; if (!(flags®_EXTENDED) && (flags®_ADVF)) return REG_INVARG; /* initial setup (after which freev() is callable) */ v->re = re; v->now = (chr *)string; v->stop = v->now + len; v->savenow = v->savestop = NULL; v->err = 0; v->cflags = flags; v->nsubexp = 0; v->subs = v->sub10; v->nsubs = 10; for (j = 0; j < v->nsubs; j++) v->subs[j] = NULL; v->nfa = NULL; v->cm = NULL; v->nlcolor = COLORLESS; v->wordchrs = NULL; v->tree = NULL; v->treechain = NULL; v->treefree = NULL; v->cv = NULL; v->cv2 = NULL; v->mcces = NULL; v->lacons = NULL; v->nlacons = 0; re->re_magic = REMAGIC; re->re_info = 0; /* bits get set during parse */ re->re_csize = sizeof(chr); re->re_guts = NULL; re->re_fns = VS(&functions); /* more complex setup, malloced things */ re->re_guts = VS(MALLOC(sizeof(struct guts))); if (re->re_guts == NULL) return freev(v, REG_ESPACE); g = (struct guts *)re->re_guts; g->tree = NULL; initcm(v, &g->cmap); v->cm = &g->cmap; g->lacons = NULL; g->nlacons = 0; ZAPCNFA(g->search); v->nfa = newnfa(v, v->cm, (struct nfa *)NULL); CNOERR(); v->cv = newcvec(100, 20, 10); if (v->cv == NULL) return freev(v, REG_ESPACE); CNOERR(); /* parsing */ lexstart(v); /* also handles prefixes */ if ((v->cflags®_NLSTOP) || (v->cflags®_NLANCH)) { /* assign newline a unique color */ v->nlcolor = subcolor(v->cm, newline()); okcolors(v->nfa, v->cm); } CNOERR(); v->tree = parse(v, EOS, PLAIN, v->nfa->init, v->nfa->final); assert(SEE(EOS)); /* even if error; ISERR() => SEE(EOS) */ CNOERR(); assert(v->tree != NULL); /* finish setup of nfa and its subre tree */ specialcolors(v->nfa); CNOERR(); if (debug != NULL) { fprintf(debug, "\n\n\n========= RAW ==========\n"); dumpnfa(v->nfa, debug); dumpst(v->tree, debug, 1); } optst(v, v->tree); v->ntree = numst(v->tree, 1); markst(v->tree); cleanst(v); if (debug != NULL) { fprintf(debug, "\n\n\n========= TREE FIXED ==========\n"); dumpst(v->tree, debug, 1); } /* build compacted NFAs for tree and lacons */ re->re_info |= nfatree(v, v->tree, debug); CNOERR(); assert(v->nlacons == 0 || v->lacons != NULL); for (i = 1; i < v->nlacons; i++) { if (debug != NULL) fprintf(debug, "\n\n\n========= LA%d ==========\n", i); nfanode(v, &v->lacons[i], debug); } CNOERR(); if (v->tree->flags&SHORTER) NOTE(REG_USHORTEST); /* build compacted NFAs for tree, lacons, fast search */ if (debug != NULL) fprintf(debug, "\n\n\n========= SEARCH ==========\n"); /* can sacrifice main NFA now, so use it as work area */ (DISCARD)optimize(v->nfa, debug); CNOERR(); makesearch(v, v->nfa); CNOERR(); compact(v->nfa, &g->search); CNOERR(); /* looks okay, package it up */ re->re_nsub = v->nsubexp; v->re = NULL; /* freev no longer frees re */ g->magic = GUTSMAGIC; g->cflags = v->cflags; g->info = re->re_info; g->nsub = re->re_nsub; g->tree = v->tree; v->tree = NULL; g->ntree = v->ntree; g->compare = (v->cflags®_ICASE) ? casecmp : cmp; g->lacons = v->lacons; v->lacons = NULL; g->nlacons = v->nlacons; if (flags®_DUMP) dump(re, stdout); assert(v->err == 0); return freev(v, 0); } /* - moresubs - enlarge subRE vector ^ static VOID moresubs(struct vars *, int); */ static VOID moresubs(v, wanted) struct vars *v; int wanted; /* want enough room for this one */ { struct subre **p; size_t n; assert(wanted > 0 && (size_t)wanted >= v->nsubs); n = (size_t)wanted * 3 / 2 + 1; if (v->subs == v->sub10) { p = (struct subre **)MALLOC(n * sizeof(struct subre *)); if (p != NULL) memcpy(VS(p), VS(v->subs), v->nsubs * sizeof(struct subre *)); } else p = (struct subre **)REALLOC(v->subs, n*sizeof(struct subre *)); if (p == NULL) { ERR(REG_ESPACE); return; } v->subs = p; for (p = &v->subs[v->nsubs]; v->nsubs < n; p++, v->nsubs++) *p = NULL; assert(v->nsubs == n); assert((size_t)wanted < v->nsubs); } /* - freev - free vars struct's substructures where necessary * Optionally does error-number setting, and always returns error code * (if any), to make error-handling code terser. ^ static int freev(struct vars *, int); */ static int freev(v, err) struct vars *v; int err; { if (v->re != NULL) rfree(v->re); if (v->subs != v->sub10) FREE(v->subs); if (v->nfa != NULL) freenfa(v->nfa); if (v->tree != NULL) freesubre(v, v->tree); if (v->treechain != NULL) cleanst(v); if (v->cv != NULL) freecvec(v->cv); if (v->cv2 != NULL) freecvec(v->cv2); if (v->mcces != NULL) freecvec(v->mcces); if (v->lacons != NULL) freelacons(v->lacons, v->nlacons); ERR(err); /* nop if err==0 */ return v->err; } /* - makesearch - turn an NFA into a search NFA (implicit prepend of .*?) * NFA must have been optimize()d already. ^ static VOID makesearch(struct vars *, struct nfa *); */ static VOID makesearch(v, nfa) struct vars *v; struct nfa *nfa; { struct arc *a; struct arc *b; struct state *pre = nfa->pre; struct state *s; struct state *s2; struct state *slist; /* no loops are needed if it's anchored */ for (a = pre->outs; a != NULL; a = a->outchain) { assert(a->type == PLAIN); if (a->co != nfa->bos[0] && a->co != nfa->bos[1]) break; } if (a != NULL) { /* add implicit .* in front */ rainbow(nfa, v->cm, PLAIN, COLORLESS, pre, pre); /* and ^* and \A* too -- not always necessary, but harmless */ newarc(nfa, PLAIN, nfa->bos[0], pre, pre); newarc(nfa, PLAIN, nfa->bos[1], pre, pre); } /* * Now here's the subtle part. Because many REs have no lookback * constraints, often knowing when you were in the pre state tells * you little; it's the next state(s) that are informative. But * some of them may have other inarcs, i.e. it may be possible to * make actual progress and then return to one of them. We must * de-optimize such cases, splitting each such state into progress * and no-progress states. */ /* first, make a list of the states */ slist = NULL; for (a = pre->outs; a != NULL; a = a->outchain) { s = a->to; for (b = s->ins; b != NULL; b = b->inchain) if (b->from != pre) break; if (b != NULL) { /* must be split */ if (s->tmp == NULL) { /* if not already in the list */ /* (fixes bugs 505048, 230589, */ /* 840258, 504785) */ s->tmp = slist; slist = s; } } } /* do the splits */ for (s = slist; s != NULL; s = s2) { s2 = newstate(nfa); copyouts(nfa, s, s2, 1); for (a = s->ins; a != NULL; a = b) { b = a->inchain; if (a->from != pre) { cparc(nfa, a, a->from, s2); freearc(nfa, a); } } s2 = s->tmp; s->tmp = NULL; /* clean up while we're at it */ } } /* - parse - parse an RE * This is actually just the top level, which parses a bunch of branches * tied together with '|'. They appear in the tree as the left children * of a chain of '|' subres. ^ static struct subre *parse(struct vars *, int, int, struct state *, ^ struct state *); */ static struct subre * parse(v, stopper, type, init, final) struct vars *v; int stopper; /* EOS or ')' */ int type; /* LACON (lookahead subRE) or PLAIN */ struct state *init; /* initial state */ struct state *final; /* final state */ { struct state *left; /* scaffolding for branch */ struct state *right; struct subre *branches; /* top level */ struct subre *branch; /* current branch */ struct subre *t; /* temporary */ int firstbranch; /* is this the first branch? */ assert(stopper == ')' || stopper == EOS); branches = subre(v, '|', LONGER, init, final); NOERRN(); branch = branches; firstbranch = 1; do { /* a branch */ if (!firstbranch) { /* need a place to hang it */ branch->right = subre(v, '|', LONGER, init, final); NOERRN(); branch = branch->right; } firstbranch = 0; left = newstate(v->nfa); right = newstate(v->nfa); NOERRN(); EMPTYARC(init, left); EMPTYARC(right, final); NOERRN(); branch->left = parsebranch(v, stopper, type, left, right, 0); NOERRN(); branch->flags |= UP(branch->flags | branch->left->flags); if ((branch->flags &~ branches->flags) != 0) /* new flags */ for (t = branches; t != branch; t = t->right) t->flags |= branch->flags; } while (EAT('|')); assert(SEE(stopper) || SEE(EOS)); if (!SEE(stopper)) { assert(stopper == ')' && SEE(EOS)); ERR(REG_EPAREN); } /* optimize out simple cases */ if (branch == branches) { /* only one branch */ assert(branch->right == NULL); t = branch->left; branch->left = NULL; freesubre(v, branches); branches = t; } else if (!MESSY(branches->flags)) { /* no interesting innards */ freesubre(v, branches->left); branches->left = NULL; freesubre(v, branches->right); branches->right = NULL; branches->op = '='; } return branches; } /* - parsebranch - parse one branch of an RE * This mostly manages concatenation, working closely with parseqatom(). * Concatenated things are bundled up as much as possible, with separate * ',' nodes introduced only when necessary due to substructure. ^ static struct subre *parsebranch(struct vars *, int, int, struct state *, ^ struct state *, int); */ static struct subre * parsebranch(v, stopper, type, left, right, partial) struct vars *v; int stopper; /* EOS or ')' */ int type; /* LACON (lookahead subRE) or PLAIN */ struct state *left; /* leftmost state */ struct state *right; /* rightmost state */ int partial; /* is this only part of a branch? */ { struct state *lp; /* left end of current construct */ int seencontent; /* is there anything in this branch yet? */ struct subre *t; lp = left; seencontent = 0; t = subre(v, '=', 0, left, right); /* op '=' is tentative */ NOERRN(); while (!SEE('|') && !SEE(stopper) && !SEE(EOS)) { if (seencontent) { /* implicit concat operator */ lp = newstate(v->nfa); NOERRN(); moveins(v->nfa, right, lp); } seencontent = 1; /* NB, recursion in parseqatom() may swallow rest of branch */ parseqatom(v, stopper, type, lp, right, t); NOERRN(); } if (!seencontent) { /* empty branch */ if (!partial) NOTE(REG_UUNSPEC); assert(lp == left); EMPTYARC(left, right); } return t; } /* - parseqatom - parse one quantified atom or constraint of an RE * The bookkeeping near the end cooperates very closely with parsebranch(); * in particular, it contains a recursion that can involve parsing the rest * of the branch, making this function's name somewhat inaccurate. ^ static VOID parseqatom(struct vars *, int, int, struct state *, ^ struct state *, struct subre *); */ static VOID parseqatom(v, stopper, type, lp, rp, top) struct vars *v; int stopper; /* EOS or ')' */ int type; /* LACON (lookahead subRE) or PLAIN */ struct state *lp; /* left state to hang it on */ struct state *rp; /* right state to hang it on */ struct subre *top; /* subtree top */ { struct state *s; /* temporaries for new states */ struct state *s2; # define ARCV(t, val) newarc(v->nfa, t, val, lp, rp) int m, n; struct subre *atom; /* atom's subtree */ struct subre *t; int cap; /* capturing parens? */ int pos; /* positive lookahead? */ int subno; /* capturing-parens or backref number */ int atomtype; int qprefer; /* quantifier short/long preference */ int f; struct subre **atomp; /* where the pointer to atom is */ /* initial bookkeeping */ atom = NULL; assert(lp->nouts == 0); /* must string new code */ assert(rp->nins == 0); /* between lp and rp */ subno = 0; /* just to shut lint up */ /* an atom or constraint... */ atomtype = v->nexttype; switch (atomtype) { /* first, constraints, which end by returning */ case '^': ARCV('^', 1); if (v->cflags®_NLANCH) ARCV(BEHIND, v->nlcolor); NEXT(); return; break; case '$': ARCV('$', 1); if (v->cflags®_NLANCH) ARCV(AHEAD, v->nlcolor); NEXT(); return; break; case SBEGIN: ARCV('^', 1); /* BOL */ ARCV('^', 0); /* or BOS */ NEXT(); return; break; case SEND: ARCV('$', 1); /* EOL */ ARCV('$', 0); /* or EOS */ NEXT(); return; break; case '<': wordchrs(v); /* does NEXT() */ s = newstate(v->nfa); NOERR(); nonword(v, BEHIND, lp, s); word(v, AHEAD, s, rp); return; break; case '>': wordchrs(v); /* does NEXT() */ s = newstate(v->nfa); NOERR(); word(v, BEHIND, lp, s); nonword(v, AHEAD, s, rp); return; break; case WBDRY: wordchrs(v); /* does NEXT() */ s = newstate(v->nfa); NOERR(); nonword(v, BEHIND, lp, s); word(v, AHEAD, s, rp); s = newstate(v->nfa); NOERR(); word(v, BEHIND, lp, s); nonword(v, AHEAD, s, rp); return; break; case NWBDRY: wordchrs(v); /* does NEXT() */ s = newstate(v->nfa); NOERR(); word(v, BEHIND, lp, s); word(v, AHEAD, s, rp); s = newstate(v->nfa); NOERR(); nonword(v, BEHIND, lp, s); nonword(v, AHEAD, s, rp); return; break; case LACON: /* lookahead constraint */ pos = v->nextvalue; NEXT(); s = newstate(v->nfa); s2 = newstate(v->nfa); NOERR(); t = parse(v, ')', LACON, s, s2); freesubre(v, t); /* internal structure irrelevant */ assert(SEE(')') || ISERR()); NEXT(); n = newlacon(v, s, s2, pos); NOERR(); ARCV(LACON, n); return; break; /* then errors, to get them out of the way */ case '*': case '+': case '?': case '{': ERR(REG_BADRPT); return; break; default: ERR(REG_ASSERT); return; break; /* then plain characters, and minor variants on that theme */ case ')': /* unbalanced paren */ if ((v->cflags®_ADVANCED) != REG_EXTENDED) { ERR(REG_EPAREN); return; } /* legal in EREs due to specification botch */ NOTE(REG_UPBOTCH); /* fallthrough into case PLAIN */ case PLAIN: onechr(v, v->nextvalue, lp, rp); okcolors(v->nfa, v->cm); NOERR(); NEXT(); break; case '[': if (v->nextvalue == 1) bracket(v, lp, rp); else cbracket(v, lp, rp); assert(SEE(']') || ISERR()); NEXT(); break; case '.': rainbow(v->nfa, v->cm, PLAIN, (v->cflags®_NLSTOP) ? v->nlcolor : COLORLESS, lp, rp); NEXT(); break; /* and finally the ugly stuff */ case '(': /* value flags as capturing or non */ cap = (type == LACON) ? 0 : v->nextvalue; if (cap) { v->nsubexp++; subno = v->nsubexp; if ((size_t)subno >= v->nsubs) moresubs(v, subno); assert((size_t)subno < v->nsubs); } else atomtype = PLAIN; /* something that's not '(' */ NEXT(); /* need new endpoints because tree will contain pointers */ s = newstate(v->nfa); s2 = newstate(v->nfa); NOERR(); EMPTYARC(lp, s); EMPTYARC(s2, rp); NOERR(); atom = parse(v, ')', PLAIN, s, s2); assert(SEE(')') || ISERR()); NEXT(); NOERR(); if (cap) { v->subs[subno] = atom; t = subre(v, '(', atom->flags|CAP, lp, rp); NOERR(); t->subno = subno; t->left = atom; atom = t; } /* postpone everything else pending possible {0} */ break; case BACKREF: /* the Feature From The Black Lagoon */ INSIST(type != LACON, REG_ESUBREG); INSIST(v->nextvalue < v->nsubs, REG_ESUBREG); INSIST(v->subs[v->nextvalue] != NULL, REG_ESUBREG); NOERR(); assert(v->nextvalue > 0); atom = subre(v, 'b', BACKR, lp, rp); subno = v->nextvalue; atom->subno = subno; EMPTYARC(lp, rp); /* temporarily, so there's something */ NEXT(); break; } /* ...and an atom may be followed by a quantifier */ switch (v->nexttype) { case '*': m = 0; n = INFINITY; qprefer = (v->nextvalue) ? LONGER : SHORTER; NEXT(); break; case '+': m = 1; n = INFINITY; qprefer = (v->nextvalue) ? LONGER : SHORTER; NEXT(); break; case '?': m = 0; n = 1; qprefer = (v->nextvalue) ? LONGER : SHORTER; NEXT(); break; case '{': NEXT(); m = scannum(v); if (EAT(',')) { if (SEE(DIGIT)) n = scannum(v); else n = INFINITY; if (m > n) { ERR(REG_BADBR); return; } /* {m,n} exercises preference, even if it's {m,m} */ qprefer = (v->nextvalue) ? LONGER : SHORTER; } else { n = m; /* {m} passes operand's preference through */ qprefer = 0; } if (!SEE('}')) { /* catches errors too */ ERR(REG_BADBR); return; } NEXT(); break; default: /* no quantifier */ m = n = 1; qprefer = 0; break; } /* annoying special case: {0} or {0,0} cancels everything */ if (m == 0 && n == 0) { if (atom != NULL) freesubre(v, atom); if (atomtype == '(') v->subs[subno] = NULL; delsub(v->nfa, lp, rp); EMPTYARC(lp, rp); return; } /* if not a messy case, avoid hard part */ assert(!MESSY(top->flags)); f = top->flags | qprefer | ((atom != NULL) ? atom->flags : 0); if (atomtype != '(' && atomtype != BACKREF && !MESSY(UP(f))) { if (!(m == 1 && n == 1)) repeat(v, lp, rp, m, n); if (atom != NULL) freesubre(v, atom); top->flags = f; return; } /* * hard part: something messy * That is, capturing parens, back reference, short/long clash, or * an atom with substructure containing one of those. */ /* now we'll need a subre for the contents even if they're boring */ if (atom == NULL) { atom = subre(v, '=', 0, lp, rp); NOERR(); } /* * prepare a general-purpose state skeleton * * ---> [s] ---prefix---> [begin] ---atom---> [end] ----rest---> [rp] * / / * [lp] ----> [s2] ----bypass--------------------- * * where bypass is an empty, and prefix is some repetitions of atom */ s = newstate(v->nfa); /* first, new endpoints for the atom */ s2 = newstate(v->nfa); NOERR(); moveouts(v->nfa, lp, s); moveins(v->nfa, rp, s2); NOERR(); atom->begin = s; atom->end = s2; s = newstate(v->nfa); /* and spots for prefix and bypass */ s2 = newstate(v->nfa); NOERR(); EMPTYARC(lp, s); EMPTYARC(lp, s2); NOERR(); /* break remaining subRE into x{...} and what follows */ t = subre(v, '.', COMBINE(qprefer, atom->flags), lp, rp); t->left = atom; atomp = &t->left; /* here we should recurse... but we must postpone that to the end */ /* split top into prefix and remaining */ assert(top->op == '=' && top->left == NULL && top->right == NULL); top->left = subre(v, '=', top->flags, top->begin, lp); top->op = '.'; top->right = t; /* if it's a backref, now is the time to replicate the subNFA */ if (atomtype == BACKREF) { assert(atom->begin->nouts == 1); /* just the EMPTY */ delsub(v->nfa, atom->begin, atom->end); assert(v->subs[subno] != NULL); /* and here's why the recursion got postponed: it must */ /* wait until the skeleton is filled in, because it may */ /* hit a backref that wants to copy the filled-in skeleton */ dupnfa(v->nfa, v->subs[subno]->begin, v->subs[subno]->end, atom->begin, atom->end); NOERR(); } /* it's quantifier time; first, turn x{0,...} into x{1,...}|empty */ if (m == 0) { EMPTYARC(s2, atom->end); /* the bypass */ assert(PREF(qprefer) != 0); f = COMBINE(qprefer, atom->flags); t = subre(v, '|', f, lp, atom->end); NOERR(); t->left = atom; t->right = subre(v, '|', PREF(f), s2, atom->end); NOERR(); t->right->left = subre(v, '=', 0, s2, atom->end); NOERR(); *atomp = t; atomp = &t->left; m = 1; } /* deal with the rest of the quantifier */ if (atomtype == BACKREF) { /* special case: backrefs have internal quantifiers */ EMPTYARC(s, atom->begin); /* empty prefix */ /* just stuff everything into atom */ repeat(v, atom->begin, atom->end, m, n); atom->min = (short)m; atom->max = (short)n; atom->flags |= COMBINE(qprefer, atom->flags); } else if (m == 1 && n == 1) { /* no/vacuous quantifier: done */ EMPTYARC(s, atom->begin); /* empty prefix */ } else { /* turn x{m,n} into x{m-1,n-1}x, with capturing */ /* parens in only second x */ dupnfa(v->nfa, atom->begin, atom->end, s, atom->begin); assert(m >= 1 && m != INFINITY && n >= 1); repeat(v, s, atom->begin, m-1, (n == INFINITY) ? n : n-1); f = COMBINE(qprefer, atom->flags); t = subre(v, '.', f, s, atom->end); /* prefix and atom */ NOERR(); t->left = subre(v, '=', PREF(f), s, atom->begin); NOERR(); t->right = atom; *atomp = t; } /* and finally, look after that postponed recursion */ t = top->right; if (!(SEE('|') || SEE(stopper) || SEE(EOS))) t->right = parsebranch(v, stopper, type, atom->end, rp, 1); else { EMPTYARC(atom->end, rp); t->right = subre(v, '=', 0, atom->end, rp); } NOERR(); assert(SEE('|') || SEE(stopper) || SEE(EOS)); t->flags |= COMBINE(t->flags, t->right->flags); top->flags |= COMBINE(top->flags, t->flags); } /* - nonword - generate arcs for non-word-character ahead or behind ^ static VOID nonword(struct vars *, int, struct state *, struct state *); */ static VOID nonword(v, dir, lp, rp) struct vars *v; int dir; /* AHEAD or BEHIND */ struct state *lp; struct state *rp; { int anchor = (dir == AHEAD) ? '$' : '^'; assert(dir == AHEAD || dir == BEHIND); newarc(v->nfa, anchor, 1, lp, rp); newarc(v->nfa, anchor, 0, lp, rp); colorcomplement(v->nfa, v->cm, dir, v->wordchrs, lp, rp); /* (no need for special attention to \n) */ } /* - word - generate arcs for word character ahead or behind ^ static VOID word(struct vars *, int, struct state *, struct state *); */ static VOID word(v, dir, lp, rp) struct vars *v; int dir; /* AHEAD or BEHIND */ struct state *lp; struct state *rp; { assert(dir == AHEAD || dir == BEHIND); cloneouts(v->nfa, v->wordchrs, lp, rp, dir); /* (no need for special attention to \n) */ } /* - scannum - scan a number ^ static int scannum(struct vars *); */ static int /* value, <= DUPMAX */ scannum(v) struct vars *v; { int n = 0; while (SEE(DIGIT) && n < DUPMAX) { n = n*10 + v->nextvalue; NEXT(); } if (SEE(DIGIT) || n > DUPMAX) { ERR(REG_BADBR); return 0; } return n; } /* - repeat - replicate subNFA for quantifiers * The duplication sequences used here are chosen carefully so that any * pointers starting out pointing into the subexpression end up pointing into * the last occurrence. (Note that it may not be strung between the same * left and right end states, however!) This used to be important for the * subRE tree, although the important bits are now handled by the in-line * code in parse(), and when this is called, it doesn't matter any more. ^ static VOID repeat(struct vars *, struct state *, struct state *, int, int); */ static VOID repeat(v, lp, rp, m, n) struct vars *v; struct state *lp; struct state *rp; int m; int n; { # define SOME 2 # define INF 3 # define PAIR(x, y) ((x)*4 + (y)) # define REDUCE(x) ( ((x) == INFINITY) ? INF : (((x) > 1) ? SOME : (x)) ) CONST int rm = REDUCE(m); CONST int rn = REDUCE(n); struct state *s; struct state *s2; switch (PAIR(rm, rn)) { case PAIR(0, 0): /* empty string */ delsub(v->nfa, lp, rp); EMPTYARC(lp, rp); break; case PAIR(0, 1): /* do as x| */ EMPTYARC(lp, rp); break; case PAIR(0, SOME): /* do as x{1,n}| */ repeat(v, lp, rp, 1, n); NOERR(); EMPTYARC(lp, rp); break; case PAIR(0, INF): /* loop x around */ s = newstate(v->nfa); NOERR(); moveouts(v->nfa, lp, s); moveins(v->nfa, rp, s); EMPTYARC(lp, s); EMPTYARC(s, rp); break; case PAIR(1, 1): /* no action required */ break; case PAIR(1, SOME): /* do as x{0,n-1}x = (x{1,n-1}|)x */ s = newstate(v->nfa); NOERR(); moveouts(v->nfa, lp, s); dupnfa(v->nfa, s, rp, lp, s); NOERR(); repeat(v, lp, s, 1, n-1); NOERR(); EMPTYARC(lp, s); break; case PAIR(1, INF): /* add loopback arc */ s = newstate(v->nfa); s2 = newstate(v->nfa); NOERR(); moveouts(v->nfa, lp, s); moveins(v->nfa, rp, s2); EMPTYARC(lp, s); EMPTYARC(s2, rp); EMPTYARC(s2, s); break; case PAIR(SOME, SOME): /* do as x{m-1,n-1}x */ s = newstate(v->nfa); NOERR(); moveouts(v->nfa, lp, s); dupnfa(v->nfa, s, rp, lp, s); NOERR(); repeat(v, lp, s, m-1, n-1); break; case PAIR(SOME, INF): /* do as x{m-1,}x */ s = newstate(v->nfa); NOERR(); moveouts(v->nfa, lp, s); dupnfa(v->nfa, s, rp, lp, s); NOERR(); repeat(v, lp, s, m-1, n); break; default: ERR(REG_ASSERT); break; } } /* - bracket - handle non-complemented bracket expression * Also called from cbracket for complemented bracket expressions. ^ static VOID bracket(struct vars *, struct state *, struct state *); */ static VOID bracket(v, lp, rp) struct vars *v; struct state *lp; struct state *rp; { assert(SEE('[')); NEXT(); while (!SEE(']') && !SEE(EOS)) brackpart(v, lp, rp); assert(SEE(']') || ISERR()); okcolors(v->nfa, v->cm); } /* - cbracket - handle complemented bracket expression * We do it by calling bracket() with dummy endpoints, and then complementing * the result. The alternative would be to invoke rainbow(), and then delete * arcs as the b.e. is seen... but that gets messy. ^ static VOID cbracket(struct vars *, struct state *, struct state *); */ static VOID cbracket(v, lp, rp) struct vars *v; struct state *lp; struct state *rp; { struct state *left = newstate(v->nfa); struct state *right = newstate(v->nfa); struct state *s; struct arc *a; /* arc from lp */ struct arc *ba; /* arc from left, from bracket() */ struct arc *pa; /* MCCE-prototype arc */ color co; chr *p; int i; NOERR(); bracket(v, left, right); if (v->cflags®_NLSTOP) newarc(v->nfa, PLAIN, v->nlcolor, left, right); NOERR(); assert(lp->nouts == 0); /* all outarcs will be ours */ /* easy part of complementing */ colorcomplement(v->nfa, v->cm, PLAIN, left, lp, rp); NOERR(); if (v->mcces == NULL) { /* no MCCEs -- we're done */ dropstate(v->nfa, left); assert(right->nins == 0); freestate(v->nfa, right); return; } /* but complementing gets messy in the presence of MCCEs... */ NOTE(REG_ULOCALE); for (p = v->mcces->chrs, i = v->mcces->nchrs; i > 0; p++, i--) { co = GETCOLOR(v->cm, *p); a = findarc(lp, PLAIN, co); ba = findarc(left, PLAIN, co); if (ba == NULL) { assert(a != NULL); freearc(v->nfa, a); } else { assert(a == NULL); } s = newstate(v->nfa); NOERR(); newarc(v->nfa, PLAIN, co, lp, s); NOERR(); pa = findarc(v->mccepbegin, PLAIN, co); assert(pa != NULL); if (ba == NULL) { /* easy case, need all of them */ cloneouts(v->nfa, pa->to, s, rp, PLAIN); newarc(v->nfa, '$', 1, s, rp); newarc(v->nfa, '$', 0, s, rp); colorcomplement(v->nfa, v->cm, AHEAD, pa->to, s, rp); } else { /* must be selective */ if (findarc(ba->to, '$', 1) == NULL) { newarc(v->nfa, '$', 1, s, rp); newarc(v->nfa, '$', 0, s, rp); colorcomplement(v->nfa, v->cm, AHEAD, pa->to, s, rp); } for (pa = pa->to->outs; pa != NULL; pa = pa->outchain) if (findarc(ba->to, PLAIN, pa->co) == NULL) newarc(v->nfa, PLAIN, pa->co, s, rp); if (s->nouts == 0) /* limit of selectivity: none */ dropstate(v->nfa, s); /* frees arc too */ } NOERR(); } delsub(v->nfa, left, right); assert(left->nouts == 0); freestate(v->nfa, left); assert(right->nins == 0); freestate(v->nfa, right); } /* - brackpart - handle one item (or range) within a bracket expression ^ static VOID brackpart(struct vars *, struct state *, struct state *); */ static VOID brackpart(v, lp, rp) struct vars *v; struct state *lp; struct state *rp; { celt startc; celt endc; struct cvec *cv; CONST chr *startp; CONST chr *endp; chr c[1]; /* parse something, get rid of special cases, take shortcuts */ switch (v->nexttype) { case RANGE: /* a-b-c or other botch */ ERR(REG_ERANGE); return; break; case PLAIN: c[0] = v->nextvalue; NEXT(); /* shortcut for ordinary chr (not range, not MCCE leader) */ if (!SEE(RANGE) && !ISCELEADER(v, c[0])) { onechr(v, c[0], lp, rp); return; } startc = element(v, c, c+1); NOERR(); break; case COLLEL: startp = v->now; endp = scanplain(v); INSIST(startp < endp, REG_ECOLLATE); NOERR(); startc = element(v, startp, endp); NOERR(); break; case ECLASS: startp = v->now; endp = scanplain(v); INSIST(startp < endp, REG_ECOLLATE); NOERR(); startc = element(v, startp, endp); NOERR(); cv = eclass(v, startc, (v->cflags®_ICASE)); NOERR(); dovec(v, cv, lp, rp); return; break; case CCLASS: startp = v->now; endp = scanplain(v); INSIST(startp < endp, REG_ECTYPE); NOERR(); cv = cclass(v, startp, endp, (v->cflags®_ICASE)); NOERR(); dovec(v, cv, lp, rp); return; break; default: ERR(REG_ASSERT); return; break; } if (SEE(RANGE)) { NEXT(); switch (v->nexttype) { case PLAIN: case RANGE: c[0] = v->nextvalue; NEXT(); endc = element(v, c, c+1); NOERR(); break; case COLLEL: startp = v->now; endp = scanplain(v); INSIST(startp < endp, REG_ECOLLATE); NOERR(); endc = element(v, startp, endp); NOERR(); break; default: ERR(REG_ERANGE); return; break; } } else endc = startc; /* * Ranges are unportable. Actually, standard C does * guarantee that digits are contiguous, but making * that an exception is just too complicated. */ if (startc != endc) NOTE(REG_UUNPORT); cv = range(v, startc, endc, (v->cflags®_ICASE)); NOERR(); dovec(v, cv, lp, rp); } /* - scanplain - scan PLAIN contents of [. etc. * Certain bits of trickery in lex.c know that this code does not try * to look past the final bracket of the [. etc. ^ static chr *scanplain(struct vars *); */ static CONST chr * /* just after end of sequence */ scanplain(v) struct vars *v; { CONST chr *endp; assert(SEE(COLLEL) || SEE(ECLASS) || SEE(CCLASS)); NEXT(); endp = v->now; while (SEE(PLAIN)) { endp = v->now; NEXT(); } assert(SEE(END) || ISERR()); NEXT(); return endp; } /* - onechr - fill in arcs for a plain character, and possible case complements * This is mostly a shortcut for efficient handling of the common case. ^ static VOID onechr(struct vars *, pchr, struct state *, struct state *); */ static VOID onechr(v, c, lp, rp) struct vars *v; pchr c; struct state *lp; struct state *rp; { if (!(v->cflags®_ICASE)) { newarc(v->nfa, PLAIN, subcolor(v->cm, c), lp, rp); return; } /* rats, need general case anyway... */ dovec(v, allcases(v, c), lp, rp); } /* - dovec - fill in arcs for each element of a cvec * This one has to handle the messy cases, like MCCEs and MCCE leaders. ^ static VOID dovec(struct vars *, struct cvec *, struct state *, ^ struct state *); */ static VOID dovec(v, cv, lp, rp) struct vars *v; struct cvec *cv; struct state *lp; struct state *rp; { chr ch, from, to; celt ce; chr *p; int i; color co; struct cvec *leads; struct arc *a; struct arc *pa; /* arc in prototype */ struct state *s; struct state *ps; /* state in prototype */ leads = NULL; /* first, get the ordinary characters out of the way */ for (p = cv->chrs, i = cv->nchrs; i > 0; p++, i--) { ch = *p; if (!ISCELEADER(v, ch)) newarc(v->nfa, PLAIN, subcolor(v->cm, ch), lp, rp); else { assert(singleton(v->cm, ch)); assert(leads != NULL); if (!haschr(leads, ch)) addchr(leads, ch); } } /* and the ranges */ for (p = cv->ranges, i = cv->nranges; i > 0; p += 2, i--) { from = *p; to = *(p+1); while (from <= to && (ce = nextleader(v, from, to)) != NOCELT) { if (from < ce) subrange(v, from, ce - 1, lp, rp); assert(singleton(v->cm, ce)); assert(leads != NULL); if (!haschr(leads, ce)) addchr(leads, ce); from = ce + 1; } if (from <= to) subrange(v, from, to, lp, rp); } if ((leads == NULL || leads->nchrs == 0) && cv->nmcces == 0) return; /* deal with the MCCE leaders */ NOTE(REG_ULOCALE); for (p = leads->chrs, i = leads->nchrs; i > 0; p++, i--) { co = GETCOLOR(v->cm, *p); a = findarc(lp, PLAIN, co); if (a != NULL) s = a->to; else { s = newstate(v->nfa); NOERR(); newarc(v->nfa, PLAIN, co, lp, s); NOERR(); } pa = findarc(v->mccepbegin, PLAIN, co); assert(pa != NULL); ps = pa->to; newarc(v->nfa, '$', 1, s, rp); newarc(v->nfa, '$', 0, s, rp); colorcomplement(v->nfa, v->cm, AHEAD, ps, s, rp); NOERR(); } /* and the MCCEs */ for (i = 0; i < cv->nmcces; i++) { p = cv->mcces[i]; assert(singleton(v->cm, *p)); if (!singleton(v->cm, *p)) { ERR(REG_ASSERT); return; } ch = *p++; co = GETCOLOR(v->cm, ch); a = findarc(lp, PLAIN, co); if (a != NULL) s = a->to; else { s = newstate(v->nfa); NOERR(); newarc(v->nfa, PLAIN, co, lp, s); NOERR(); } assert(*p != 0); /* at least two chars */ assert(singleton(v->cm, *p)); ch = *p++; co = GETCOLOR(v->cm, ch); assert(*p == 0); /* and only two, for now */ newarc(v->nfa, PLAIN, co, s, rp); NOERR(); } } /* - nextleader - find next MCCE leader within range ^ static celt nextleader(struct vars *, pchr, pchr); */ static celt /* NOCELT means none */ nextleader(v, from, to) struct vars *v; pchr from; pchr to; { int i; chr *p; chr ch; celt it = NOCELT; if (v->mcces == NULL) return it; for (i = v->mcces->nchrs, p = v->mcces->chrs; i > 0; i--, p++) { ch = *p; if (from <= ch && ch <= to) if (it == NOCELT || ch < it) it = ch; } return it; } /* - wordchrs - set up word-chr list for word-boundary stuff, if needed * The list is kept as a bunch of arcs between two dummy states; it's * disposed of by the unreachable-states sweep in NFA optimization. * Does NEXT(). Must not be called from any unusual lexical context. * This should be reconciled with the \w etc. handling in lex.c, and * should be cleaned up to reduce dependencies on input scanning. ^ static VOID wordchrs(struct vars *); */ static VOID wordchrs(v) struct vars *v; { struct state *left; struct state *right; if (v->wordchrs != NULL) { NEXT(); /* for consistency */ return; } left = newstate(v->nfa); right = newstate(v->nfa); NOERR(); /* fine point: implemented with [::], and lexer will set REG_ULOCALE */ lexword(v); NEXT(); assert(v->savenow != NULL && SEE('[')); bracket(v, left, right); assert((v->savenow != NULL && SEE(']')) || ISERR()); NEXT(); NOERR(); v->wordchrs = left; } /* - subre - allocate a subre ^ static struct subre *subre(struct vars *, int, int, struct state *, ^ struct state *); */ static struct subre * subre(v, op, flags, begin, end) struct vars *v; int op; int flags; struct state *begin; struct state *end; { struct subre *ret; ret = v->treefree; if (ret != NULL) v->treefree = ret->left; else { ret = (struct subre *)MALLOC(sizeof(struct subre)); if (ret == NULL) { ERR(REG_ESPACE); return NULL; } ret->chain = v->treechain; v->treechain = ret; } assert(strchr("|.b(=", op) != NULL); ret->op = op; ret->flags = flags; ret->retry = 0; ret->subno = 0; ret->min = ret->max = 1; ret->left = NULL; ret->right = NULL; ret->begin = begin; ret->end = end; ZAPCNFA(ret->cnfa); return ret; } /* - freesubre - free a subRE subtree ^ static VOID freesubre(struct vars *, struct subre *); */ static VOID freesubre(v, sr) struct vars *v; /* might be NULL */ struct subre *sr; { if (sr == NULL) return; if (sr->left != NULL) freesubre(v, sr->left); if (sr->right != NULL) freesubre(v, sr->right); freesrnode(v, sr); } /* - freesrnode - free one node in a subRE subtree ^ static VOID freesrnode(struct vars *, struct subre *); */ static VOID freesrnode(v, sr) struct vars *v; /* might be NULL */ struct subre *sr; { if (sr == NULL) return; if (!NULLCNFA(sr->cnfa)) freecnfa(&sr->cnfa); sr->flags = 0; if (v != NULL) { sr->left = v->treefree; v->treefree = sr; } else FREE(sr); } /* - optst - optimize a subRE subtree ^ static VOID optst(struct vars *, struct subre *); */ static VOID optst(v, t) struct vars *v; struct subre *t; { /* * DGP (2007-11-13): I assume it was the programmer's intent to eventually * come back and add code to optimize subRE trees, but the routine coded * just spent effort traversing the tree and doing nothing. We can do * nothing with less effort. */ return; } /* - numst - number tree nodes (assigning retry indexes) ^ static int numst(struct subre *, int); */ static int /* next number */ numst(t, start) struct subre *t; int start; /* starting point for subtree numbers */ { int i; assert(t != NULL); i = start; t->retry = (short)i++; if (t->left != NULL) i = numst(t->left, i); if (t->right != NULL) i = numst(t->right, i); return i; } /* - markst - mark tree nodes as INUSE ^ static VOID markst(struct subre *); */ static VOID markst(t) struct subre *t; { assert(t != NULL); t->flags |= INUSE; if (t->left != NULL) markst(t->left); if (t->right != NULL) markst(t->right); } /* - cleanst - free any tree nodes not marked INUSE ^ static VOID cleanst(struct vars *); */ static VOID cleanst(v) struct vars *v; { struct subre *t; struct subre *next; for (t = v->treechain; t != NULL; t = next) { next = t->chain; if (!(t->flags&INUSE)) FREE(t); } v->treechain = NULL; v->treefree = NULL; /* just on general principles */ } /* - nfatree - turn a subRE subtree into a tree of compacted NFAs ^ static long nfatree(struct vars *, struct subre *, FILE *); */ static long /* optimize results from top node */ nfatree(v, t, f) struct vars *v; struct subre *t; FILE *f; /* for debug output */ { assert(t != NULL && t->begin != NULL); if (t->left != NULL) (DISCARD)nfatree(v, t->left, f); if (t->right != NULL) (DISCARD)nfatree(v, t->right, f); return nfanode(v, t, f); } /* - nfanode - do one NFA for nfatree ^ static long nfanode(struct vars *, struct subre *, FILE *); */ static long /* optimize results */ nfanode(v, t, f) struct vars *v; struct subre *t; FILE *f; /* for debug output */ { struct nfa *nfa; long ret = 0; char idbuf[50]; assert(t->begin != NULL); if (f != NULL) fprintf(f, "\n\n\n========= TREE NODE %s ==========\n", stid(t, idbuf, sizeof(idbuf))); nfa = newnfa(v, v->cm, v->nfa); NOERRZ(); dupnfa(nfa, t->begin, t->end, nfa->init, nfa->final); if (!ISERR()) { specialcolors(nfa); ret = optimize(nfa, f); } if (!ISERR()) compact(nfa, &t->cnfa); freenfa(nfa); return ret; } /* - newlacon - allocate a lookahead-constraint subRE ^ static int newlacon(struct vars *, struct state *, struct state *, int); */ static int /* lacon number */ newlacon(v, begin, end, pos) struct vars *v; struct state *begin; struct state *end; int pos; { int n; struct subre *sub; if (v->nlacons == 0) { v->lacons = (struct subre *)MALLOC(2 * sizeof(struct subre)); n = 1; /* skip 0th */ v->nlacons = 2; } else { v->lacons = (struct subre *)REALLOC(v->lacons, (v->nlacons+1)*sizeof(struct subre)); n = v->nlacons++; } if (v->lacons == NULL) { ERR(REG_ESPACE); return 0; } sub = &v->lacons[n]; sub->begin = begin; sub->end = end; sub->subno = pos; ZAPCNFA(sub->cnfa); return n; } /* - freelacons - free lookahead-constraint subRE vector ^ static VOID freelacons(struct subre *, int); */ static VOID freelacons(subs, n) struct subre *subs; int n; { struct subre *sub; int i; assert(n > 0); for (sub = subs + 1, i = n - 1; i > 0; sub++, i--) /* no 0th */ if (!NULLCNFA(sub->cnfa)) freecnfa(&sub->cnfa); FREE(subs); } /* - rfree - free a whole RE (insides of regfree) ^ static VOID rfree(regex_t *); */ static VOID rfree(re) regex_t *re; { struct guts *g; if (re == NULL || re->re_magic != REMAGIC) return; re->re_magic = 0; /* invalidate RE */ g = (struct guts *)re->re_guts; re->re_guts = NULL; re->re_fns = NULL; g->magic = 0; freecm(&g->cmap); if (g->tree != NULL) freesubre((struct vars *)NULL, g->tree); if (g->lacons != NULL) freelacons(g->lacons, g->nlacons); if (!NULLCNFA(g->search)) freecnfa(&g->search); FREE(g); } /* - dump - dump an RE in human-readable form ^ static VOID dump(regex_t *, FILE *); */ static VOID dump(re, f) regex_t *re; FILE *f; { #ifdef REG_DEBUG struct guts *g; int i; if (re->re_magic != REMAGIC) fprintf(f, "bad magic number (0x%x not 0x%x)\n", re->re_magic, REMAGIC); if (re->re_guts == NULL) { fprintf(f, "NULL guts!!!\n"); return; } g = (struct guts *)re->re_guts; if (g->magic != GUTSMAGIC) fprintf(f, "bad guts magic number (0x%x not 0x%x)\n", g->magic, GUTSMAGIC); fprintf(f, "\n\n\n========= DUMP ==========\n"); fprintf(f, "nsub %d, info 0%lo, csize %d, ntree %d\n", re->re_nsub, re->re_info, re->re_csize, g->ntree); dumpcolors(&g->cmap, f); if (!NULLCNFA(g->search)) { printf("\nsearch:\n"); dumpcnfa(&g->search, f); } for (i = 1; i < g->nlacons; i++) { fprintf(f, "\nla%d (%s):\n", i, (g->lacons[i].subno) ? "positive" : "negative"); dumpcnfa(&g->lacons[i].cnfa, f); } fprintf(f, "\n"); dumpst(g->tree, f, 0); #endif } /* - dumpst - dump a subRE tree ^ static VOID dumpst(struct subre *, FILE *, int); */ static VOID dumpst(t, f, nfapresent) struct subre *t; FILE *f; int nfapresent; /* is the original NFA still around? */ { if (t == NULL) fprintf(f, "null tree\n"); else stdump(t, f, nfapresent); fflush(f); } /* - stdump - recursive guts of dumpst ^ static VOID stdump(struct subre *, FILE *, int); */ static VOID stdump(t, f, nfapresent) struct subre *t; FILE *f; int nfapresent; /* is the original NFA still around? */ { char idbuf[50]; fprintf(f, "%s. `%c'", stid(t, idbuf, sizeof(idbuf)), t->op); if (t->flags&LONGER) fprintf(f, " longest"); if (t->flags&SHORTER) fprintf(f, " shortest"); if (t->flags&MIXED) fprintf(f, " hasmixed"); if (t->flags&CAP) fprintf(f, " hascapture"); if (t->flags&BACKR) fprintf(f, " hasbackref"); if (!(t->flags&INUSE)) fprintf(f, " UNUSED"); if (t->subno != 0) fprintf(f, " (#%d)", t->subno); if (t->min != 1 || t->max != 1) { fprintf(f, " {%d,", t->min); if (t->max != INFINITY) fprintf(f, "%d", t->max); fprintf(f, "}"); } if (nfapresent) fprintf(f, " %ld-%ld", (long)t->begin->no, (long)t->end->no); if (t->left != NULL) fprintf(f, " L:%s", stid(t->left, idbuf, sizeof(idbuf))); if (t->right != NULL) fprintf(f, " R:%s", stid(t->right, idbuf, sizeof(idbuf))); if (!NULLCNFA(t->cnfa)) { fprintf(f, "\n"); dumpcnfa(&t->cnfa, f); } fprintf(f, "\n"); if (t->left != NULL) stdump(t->left, f, nfapresent); if (t->right != NULL) stdump(t->right, f, nfapresent); } /* - stid - identify a subtree node for dumping ^ static char *stid(struct subre *, char *, size_t); */ static char * /* points to buf or constant string */ stid(t, buf, bufsize) struct subre *t; char *buf; size_t bufsize; { /* big enough for hex int or decimal t->retry? */ if (bufsize < sizeof(void*)*2 + 3 || bufsize < sizeof(t->retry)*3 + 1) return "unable"; if (t->retry != 0) sprintf(buf, "%d", t->retry); else sprintf(buf, "%p", t); return buf; } #include "regc_lex.c" #include "regc_color.c" #include "regc_nfa.c" #include "regc_cvec.c" #include "regc_locale.c" tcl8.4.20/generic/tclExecute.c0000644003604700454610000056103612133546537014616 0ustar dgp771div/* * tclExecute.c -- * * This file contains procedures that execute byte-compiled Tcl * commands. * * Copyright (c) 1996-1997 Sun Microsystems, Inc. * Copyright (c) 1998-2000 by Scriptics Corporation. * Copyright (c) 2001 by Kevin B. Kenny. All rights reserved. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclCompile.h" #ifndef TCL_NO_MATH # include #endif /* * The stuff below is a bit of a hack so that this file can be used * in environments that include no UNIX, i.e. no errno. Just define * errno here. */ #ifndef TCL_GENERIC_ONLY # include "tclPort.h" #else /* TCL_GENERIC_ONLY */ # ifndef NO_FLOAT_H # include # else /* NO_FLOAT_H */ # ifndef NO_VALUES_H # include # endif /* !NO_VALUES_H */ # endif /* !NO_FLOAT_H */ # define NO_ERRNO_H #endif /* !TCL_GENERIC_ONLY */ #ifdef NO_ERRNO_H int errno; # define EDOM 33 # define ERANGE 34 #endif /* * Need DBL_MAX for IS_INF() macro... */ #ifndef DBL_MAX # ifdef MAXDOUBLE # define DBL_MAX MAXDOUBLE # else /* !MAXDOUBLE */ /* * This value is from the Solaris headers, but doubles seem to be the * same size everywhere. Long doubles aren't, but we don't use those. */ # define DBL_MAX 1.79769313486231570e+308 # endif /* MAXDOUBLE */ #endif /* !DBL_MAX */ /* * Boolean flag indicating whether the Tcl bytecode interpreter has been * initialized. */ static int execInitialized = 0; TCL_DECLARE_MUTEX(execMutex) #ifdef TCL_COMPILE_DEBUG /* * Variable that controls whether execution tracing is enabled and, if so, * what level of tracing is desired: * 0: no execution tracing * 1: trace invocations of Tcl procs only * 2: trace invocations of all (not compiled away) commands * 3: display each instruction executed * This variable is linked to the Tcl variable "tcl_traceExec". */ int tclTraceExec = 0; #endif /* * Mapping from expression instruction opcodes to strings; used for error * messages. Note that these entries must match the order and number of the * expression opcodes (e.g., INST_LOR) in tclCompile.h. */ static CONST char *CONST operatorStrings[] = { "||", "&&", "|", "^", "&", "==", "!=", "<", ">", "<=", ">=", "<<", ">>", "+", "-", "*", "/", "%", "+", "-", "~", "!", "BUILTIN FUNCTION", "FUNCTION", "", "", "", "", "", "", "", "", "eq", "ne", }; /* * Mapping from Tcl result codes to strings; used for error and debugging * messages. */ #ifdef TCL_COMPILE_DEBUG static CONST char *CONST resultStrings[] = { "TCL_OK", "TCL_ERROR", "TCL_RETURN", "TCL_BREAK", "TCL_CONTINUE" }; #endif /* * These are used by evalstats to monitor object usage in Tcl. */ #ifdef TCL_COMPILE_STATS long tclObjsAlloced = 0; long tclObjsFreed = 0; #define TCL_MAX_SHARED_OBJ_STATS 5 long tclObjsShared[TCL_MAX_SHARED_OBJ_STATS] = { 0, 0, 0, 0, 0 }; #endif /* TCL_COMPILE_STATS */ /* * Macros for testing floating-point values for certain special cases. Test * for not-a-number by comparing a value against itself; test for infinity * by comparing against the largest floating-point value. */ #define IS_NAN(v) ((v) != (v)) #define IS_INF(v) (((v) > DBL_MAX) || ((v) < -DBL_MAX)) /* * The new macro for ending an instruction; note that a * reasonable C-optimiser will resolve all branches * at compile time. (result) is always a constant; the macro * NEXT_INST_F handles constant (nCleanup), NEXT_INST_V is * resolved at runtime for variable (nCleanup). * * ARGUMENTS: * pcAdjustment: how much to increment pc * nCleanup: how many objects to remove from the stack * result: 0 indicates no object should be pushed on the * stack; otherwise, push objResultPtr. If (result < 0), * objResultPtr already has the correct reference count. */ #define NEXT_INST_F(pcAdjustment, nCleanup, result) \ if (nCleanup == 0) {\ if (result != 0) {\ if ((result) > 0) {\ PUSH_OBJECT(objResultPtr);\ } else {\ stackPtr[++stackTop] = objResultPtr;\ }\ } \ pc += (pcAdjustment);\ goto cleanup0;\ } else if (result != 0) {\ if ((result) > 0) {\ Tcl_IncrRefCount(objResultPtr);\ }\ pc += (pcAdjustment);\ switch (nCleanup) {\ case 1: goto cleanup1_pushObjResultPtr;\ case 2: goto cleanup2_pushObjResultPtr;\ default: panic("ERROR: bad usage of macro NEXT_INST_F");\ }\ } else {\ pc += (pcAdjustment);\ switch (nCleanup) {\ case 1: goto cleanup1;\ case 2: goto cleanup2;\ default: panic("ERROR: bad usage of macro NEXT_INST_F");\ }\ } #define NEXT_INST_V(pcAdjustment, nCleanup, result) \ pc += (pcAdjustment);\ cleanup = (nCleanup);\ if (result) {\ if ((result) > 0) {\ Tcl_IncrRefCount(objResultPtr);\ }\ goto cleanupV_pushObjResultPtr;\ } else {\ goto cleanupV;\ } /* * Macros used to cache often-referenced Tcl evaluation stack information * in local variables. Note that a DECACHE_STACK_INFO()-CACHE_STACK_INFO() * pair must surround any call inside TclExecuteByteCode (and a few other * procedures that use this scheme) that could result in a recursive call * to TclExecuteByteCode. */ #define CACHE_STACK_INFO() \ stackPtr = eePtr->stackPtr; \ stackTop = eePtr->stackTop #define DECACHE_STACK_INFO() \ eePtr->stackTop = stackTop /* * Macros used to access items on the Tcl evaluation stack. PUSH_OBJECT * increments the object's ref count since it makes the stack have another * reference pointing to the object. However, POP_OBJECT does not decrement * the ref count. This is because the stack may hold the only reference to * the object, so the object would be destroyed if its ref count were * decremented before the caller had a chance to, e.g., store it in a * variable. It is the caller's responsibility to decrement the ref count * when it is finished with an object. * * WARNING! It is essential that objPtr only appear once in the PUSH_OBJECT * macro. The actual parameter might be an expression with side effects, * and this ensures that it will be executed only once. */ #define PUSH_OBJECT(objPtr) \ Tcl_IncrRefCount(stackPtr[++stackTop] = (objPtr)) #define POP_OBJECT() \ (stackPtr[stackTop--]) /* * Macros used to trace instruction execution. The macros TRACE, * TRACE_WITH_OBJ, and O2S are only used inside TclExecuteByteCode. * O2S is only used in TRACE* calls to get a string from an object. */ #ifdef TCL_COMPILE_DEBUG # define TRACE(a) \ if (traceInstructions) { \ fprintf(stdout, "%2d: %2d (%u) %s ", iPtr->numLevels, stackTop, \ (unsigned int)(pc - codePtr->codeStart), \ GetOpcodeName(pc)); \ printf a; \ } # define TRACE_APPEND(a) \ if (traceInstructions) { \ printf a; \ } # define TRACE_WITH_OBJ(a, objPtr) \ if (traceInstructions) { \ fprintf(stdout, "%2d: %2d (%u) %s ", iPtr->numLevels, stackTop, \ (unsigned int)(pc - codePtr->codeStart), \ GetOpcodeName(pc)); \ printf a; \ TclPrintObject(stdout, objPtr, 30); \ fprintf(stdout, "\n"); \ } # define O2S(objPtr) \ (objPtr ? TclGetString(objPtr) : "") #else /* !TCL_COMPILE_DEBUG */ # define TRACE(a) # define TRACE_APPEND(a) # define TRACE_WITH_OBJ(a, objPtr) # define O2S(objPtr) #endif /* TCL_COMPILE_DEBUG */ /* * DTrace instruction probe macros. */ #define TCL_DTRACE_INST_NEXT() \ if (TCL_DTRACE_INST_DONE_ENABLED()) {\ if (curInstName) {\ TCL_DTRACE_INST_DONE(curInstName, stackTop - initStackTop,\ stackPtr + stackTop);\ }\ curInstName = tclInstructionTable[*pc].name;\ if (TCL_DTRACE_INST_START_ENABLED()) {\ TCL_DTRACE_INST_START(curInstName, stackTop - initStackTop,\ stackPtr + stackTop);\ }\ } else if (TCL_DTRACE_INST_START_ENABLED()) {\ TCL_DTRACE_INST_START(tclInstructionTable[*pc].name,\ stackTop - initStackTop, stackPtr + stackTop);\ } #define TCL_DTRACE_INST_LAST() \ if (TCL_DTRACE_INST_DONE_ENABLED() && curInstName) {\ TCL_DTRACE_INST_DONE(curInstName, stackTop - initStackTop,\ stackPtr + stackTop);\ } /* * Macro to read a string containing either a wide or an int and * decide which it is while decoding it at the same time. This * enforces the policy that integer constants between LONG_MIN and * LONG_MAX (inclusive) are represented by normal longs, and integer * constants outside that range are represented by wide ints. * * GET_WIDE_OR_INT is the same as REQUIRE_WIDE_OR_INT except it never * generates an error message. */ #define REQUIRE_WIDE_OR_INT(resultVar, objPtr, longVar, wideVar) \ (resultVar) = Tcl_GetWideIntFromObj(interp, (objPtr), &(wideVar)); \ if ((resultVar) == TCL_OK && (wideVar) >= Tcl_LongAsWide(LONG_MIN) \ && (wideVar) <= Tcl_LongAsWide(LONG_MAX)) { \ (objPtr)->typePtr = &tclIntType; \ (objPtr)->internalRep.longValue = (longVar) \ = Tcl_WideAsLong(wideVar); \ } #define GET_WIDE_OR_INT(resultVar, objPtr, longVar, wideVar) \ (resultVar) = Tcl_GetWideIntFromObj((Tcl_Interp *) NULL, (objPtr), \ &(wideVar)); \ if ((resultVar) == TCL_OK && (wideVar) >= Tcl_LongAsWide(LONG_MIN) \ && (wideVar) <= Tcl_LongAsWide(LONG_MAX)) { \ (objPtr)->typePtr = &tclIntType; \ (objPtr)->internalRep.longValue = (longVar) \ = Tcl_WideAsLong(wideVar); \ } /* * Combined with REQUIRE_WIDE_OR_INT, this gets a long value from * an obj. */ #define FORCE_LONG(objPtr, longVar, wideVar) \ if ((objPtr)->typePtr == &tclWideIntType) { \ (longVar) = Tcl_WideAsLong(wideVar); \ } #define IS_INTEGER_TYPE(typePtr) \ ((typePtr) == &tclIntType || (typePtr) == &tclWideIntType) #define IS_NUMERIC_TYPE(typePtr) \ (IS_INTEGER_TYPE(typePtr) || (typePtr) == &tclDoubleType) #define W0 Tcl_LongAsWide(0) /* * For tracing that uses wide values. */ #define LLD "%" TCL_LL_MODIFIER "d" #ifndef TCL_WIDE_INT_IS_LONG /* * Extract a double value from a general numeric object. */ #define GET_DOUBLE_VALUE(doubleVar, objPtr, typePtr) \ if ((typePtr) == &tclIntType) { \ (doubleVar) = (double) (objPtr)->internalRep.longValue; \ } else if ((typePtr) == &tclWideIntType) { \ (doubleVar) = Tcl_WideAsDouble((objPtr)->internalRep.wideValue);\ } else { \ (doubleVar) = (objPtr)->internalRep.doubleValue; \ } #else /* TCL_WIDE_INT_IS_LONG */ #define GET_DOUBLE_VALUE(doubleVar, objPtr, typePtr) \ if (((typePtr) == &tclIntType) || ((typePtr) == &tclWideIntType)) { \ (doubleVar) = (double) (objPtr)->internalRep.longValue; \ } else { \ (doubleVar) = (objPtr)->internalRep.doubleValue; \ } #endif /* TCL_WIDE_INT_IS_LONG */ /* * Declarations for local procedures to this file: */ static int TclExecuteByteCode _ANSI_ARGS_((Tcl_Interp *interp, ByteCode *codePtr)); static void DupExprCodeInternalRep _ANSI_ARGS_((Tcl_Obj *srcPtr, Tcl_Obj *copyPtr)); static int ExprAbsFunc _ANSI_ARGS_((Tcl_Interp *interp, ExecEnv *eePtr, ClientData clientData)); static int ExprBinaryFunc _ANSI_ARGS_((Tcl_Interp *interp, ExecEnv *eePtr, ClientData clientData)); static int ExprCallMathFunc _ANSI_ARGS_((Tcl_Interp *interp, ExecEnv *eePtr, int objc, Tcl_Obj **objv)); static int ExprDoubleFunc _ANSI_ARGS_((Tcl_Interp *interp, ExecEnv *eePtr, ClientData clientData)); static int ExprIntFunc _ANSI_ARGS_((Tcl_Interp *interp, ExecEnv *eePtr, ClientData clientData)); static int ExprRandFunc _ANSI_ARGS_((Tcl_Interp *interp, ExecEnv *eePtr, ClientData clientData)); static int ExprRoundFunc _ANSI_ARGS_((Tcl_Interp *interp, ExecEnv *eePtr, ClientData clientData)); static int ExprSrandFunc _ANSI_ARGS_((Tcl_Interp *interp, ExecEnv *eePtr, ClientData clientData)); static int ExprUnaryFunc _ANSI_ARGS_((Tcl_Interp *interp, ExecEnv *eePtr, ClientData clientData)); static int ExprWideFunc _ANSI_ARGS_((Tcl_Interp *interp, ExecEnv *eePtr, ClientData clientData)); #ifdef TCL_COMPILE_STATS static int EvalStatsCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); #endif /* TCL_COMPILE_STATS */ static void FreeExprCodeInternalRep _ANSI_ARGS_ ((Tcl_Obj *objPtr)); #ifdef TCL_COMPILE_DEBUG static char * GetOpcodeName _ANSI_ARGS_((unsigned char *pc)); #endif /* TCL_COMPILE_DEBUG */ static ExceptionRange * GetExceptRangeForPc _ANSI_ARGS_((unsigned char *pc, int catchOnly, ByteCode* codePtr)); static char * GetSrcInfoForPc _ANSI_ARGS_((unsigned char *pc, ByteCode* codePtr, int *lengthPtr)); static void GrowEvaluationStack _ANSI_ARGS_((ExecEnv *eePtr)); static void IllegalExprOperandType _ANSI_ARGS_(( Tcl_Interp *interp, unsigned char *pc, Tcl_Obj *opndPtr)); static void InitByteCodeExecution _ANSI_ARGS_(( Tcl_Interp *interp)); #ifdef TCL_COMPILE_DEBUG static void PrintByteCodeInfo _ANSI_ARGS_((ByteCode *codePtr)); static CONST char * StringForResultCode _ANSI_ARGS_((int result)); static void ValidatePcAndStackTop _ANSI_ARGS_(( ByteCode *codePtr, unsigned char *pc, int stackTop, int stackLowerBound)); #endif /* TCL_COMPILE_DEBUG */ static int VerifyExprObjType _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr)); /* * The structure below defines a bytecode Tcl object type to hold the * compiled bytecode for Tcl expressions. */ static Tcl_ObjType exprCodeType = { "exprcode", FreeExprCodeInternalRep, /* freeIntRepProc */ DupExprCodeInternalRep, /* dupIntRepProc */ NULL, /* updateStringProc */ NULL /* setFromAnyProc */ }; /* * Table describing the built-in math functions. Entries in this table are * indexed by the values of the INST_CALL_BUILTIN_FUNC instruction's * operand byte. */ BuiltinFunc tclBuiltinFuncTable[] = { #ifndef TCL_NO_MATH {"acos", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) acos}, {"asin", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) asin}, {"atan", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) atan}, {"atan2", 2, {TCL_DOUBLE, TCL_DOUBLE}, ExprBinaryFunc, (ClientData) atan2}, {"ceil", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) ceil}, {"cos", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) cos}, {"cosh", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) cosh}, {"exp", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) exp}, {"floor", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) floor}, {"fmod", 2, {TCL_DOUBLE, TCL_DOUBLE}, ExprBinaryFunc, (ClientData) fmod}, {"hypot", 2, {TCL_DOUBLE, TCL_DOUBLE}, ExprBinaryFunc, (ClientData) hypot}, {"log", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) log}, {"log10", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) log10}, {"pow", 2, {TCL_DOUBLE, TCL_DOUBLE}, ExprBinaryFunc, (ClientData) pow}, {"sin", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) sin}, {"sinh", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) sinh}, {"sqrt", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) sqrt}, {"tan", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) tan}, {"tanh", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) tanh}, #endif {"abs", 1, {TCL_EITHER}, ExprAbsFunc, 0}, {"double", 1, {TCL_EITHER}, ExprDoubleFunc, 0}, {"int", 1, {TCL_EITHER}, ExprIntFunc, 0}, {"rand", 0, {TCL_EITHER}, ExprRandFunc, 0}, /* NOTE: rand takes no args. */ {"round", 1, {TCL_EITHER}, ExprRoundFunc, 0}, {"srand", 1, {TCL_INT}, ExprSrandFunc, 0}, {"wide", 1, {TCL_EITHER}, ExprWideFunc, 0}, {0, 0, {TCL_INT}, 0, 0}, }; /* *---------------------------------------------------------------------- * * InitByteCodeExecution -- * * This procedure is called once to initialize the Tcl bytecode * interpreter. * * Results: * None. * * Side effects: * This procedure initializes the array of instruction names. If * compiling with the TCL_COMPILE_STATS flag, it initializes the * array that counts the executions of each instruction and it * creates the "evalstats" command. It also establishes the link * between the Tcl "tcl_traceExec" and C "tclTraceExec" variables. * *---------------------------------------------------------------------- */ static void InitByteCodeExecution(interp) Tcl_Interp *interp; /* Interpreter for which the Tcl variable * "tcl_traceExec" is linked to control * instruction tracing. */ { #ifdef TCL_COMPILE_DEBUG if (Tcl_LinkVar(interp, "tcl_traceExec", (char *) &tclTraceExec, TCL_LINK_INT) != TCL_OK) { panic("InitByteCodeExecution: can't create link for tcl_traceExec variable"); } #endif #ifdef TCL_COMPILE_STATS Tcl_CreateObjCommand(interp, "evalstats", EvalStatsCmd, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); #endif /* TCL_COMPILE_STATS */ } /* *---------------------------------------------------------------------- * * TclCreateExecEnv -- * * This procedure creates a new execution environment for Tcl bytecode * execution. An ExecEnv points to a Tcl evaluation stack. An ExecEnv * is typically created once for each Tcl interpreter (Interp * structure) and recursively passed to TclExecuteByteCode to execute * ByteCode sequences for nested commands. * * Results: * A newly allocated ExecEnv is returned. This points to an empty * evaluation stack of the standard initial size. * * Side effects: * The bytecode interpreter is also initialized here, as this * procedure will be called before any call to TclExecuteByteCode. * *---------------------------------------------------------------------- */ #define TCL_STACK_INITIAL_SIZE 2000 ExecEnv * TclCreateExecEnv(interp) Tcl_Interp *interp; /* Interpreter for which the execution * environment is being created. */ { ExecEnv *eePtr = (ExecEnv *) ckalloc(sizeof(ExecEnv)); Tcl_Obj **stackPtr; stackPtr = (Tcl_Obj **) ckalloc((size_t) (TCL_STACK_INITIAL_SIZE * sizeof(Tcl_Obj *))); /* * Use the bottom pointer to keep a reference count; the * execution environment holds a reference. */ stackPtr++; eePtr->stackPtr = stackPtr; stackPtr[-1] = (Tcl_Obj *) ((char *) 1); eePtr->stackTop = -1; eePtr->stackEnd = (TCL_STACK_INITIAL_SIZE - 2); eePtr->errorInfo = Tcl_NewStringObj("::errorInfo", -1); Tcl_IncrRefCount(eePtr->errorInfo); eePtr->errorCode = Tcl_NewStringObj("::errorCode", -1); Tcl_IncrRefCount(eePtr->errorCode); Tcl_MutexLock(&execMutex); if (!execInitialized) { TclInitAuxDataTypeTable(); InitByteCodeExecution(interp); execInitialized = 1; } Tcl_MutexUnlock(&execMutex); return eePtr; } #undef TCL_STACK_INITIAL_SIZE /* *---------------------------------------------------------------------- * * TclDeleteExecEnv -- * * Frees the storage for an ExecEnv. * * Results: * None. * * Side effects: * Storage for an ExecEnv and its contained storage (e.g. the * evaluation stack) is freed. * *---------------------------------------------------------------------- */ void TclDeleteExecEnv(eePtr) ExecEnv *eePtr; /* Execution environment to free. */ { if (eePtr->stackPtr[-1] == (Tcl_Obj *) ((char *) 1)) { ckfree((char *) (eePtr->stackPtr-1)); } else { panic("ERROR: freeing an execEnv whose stack is still in use.\n"); } TclDecrRefCount(eePtr->errorInfo); TclDecrRefCount(eePtr->errorCode); ckfree((char *) eePtr); } /* *---------------------------------------------------------------------- * * TclFinalizeExecution -- * * Finalizes the execution environment setup so that it can be * later reinitialized. * * Results: * None. * * Side effects: * After this call, the next time TclCreateExecEnv will be called * it will call InitByteCodeExecution. * *---------------------------------------------------------------------- */ void TclFinalizeExecution() { Tcl_MutexLock(&execMutex); execInitialized = 0; Tcl_MutexUnlock(&execMutex); TclFinalizeAuxDataTypeTable(); } /* *---------------------------------------------------------------------- * * GrowEvaluationStack -- * * This procedure grows a Tcl evaluation stack stored in an ExecEnv. * * Results: * None. * * Side effects: * The size of the evaluation stack is doubled. * *---------------------------------------------------------------------- */ static void GrowEvaluationStack(eePtr) register ExecEnv *eePtr; /* Points to the ExecEnv with an evaluation * stack to enlarge. */ { /* * The current Tcl stack elements are stored from eePtr->stackPtr[0] * to eePtr->stackPtr[eePtr->stackEnd] (inclusive). */ int currElems = (eePtr->stackEnd + 1); int newElems = 2*currElems; int currBytes = currElems * sizeof(Tcl_Obj *); int newBytes = 2*currBytes; Tcl_Obj **newStackPtr = (Tcl_Obj **) ckalloc((unsigned) newBytes); Tcl_Obj **oldStackPtr = eePtr->stackPtr; /* * We keep the stack reference count as a (char *), as that * works nicely as a portable pointer-sized counter. */ char *refCount = (char *) oldStackPtr[-1]; /* * Copy the existing stack items to the new stack space, free the old * storage if appropriate, and record the refCount of the new stack * held by the environment. */ newStackPtr++; memcpy((VOID *) newStackPtr, (VOID *) oldStackPtr, (size_t) currBytes); if (refCount == (char *) 1) { ckfree((VOID *) (oldStackPtr-1)); } else { /* * Remove the reference corresponding to the * environment pointer. */ oldStackPtr[-1] = (Tcl_Obj *) (refCount-1); } eePtr->stackPtr = newStackPtr; eePtr->stackEnd = (newElems - 2); /* index of last usable item */ newStackPtr[-1] = (Tcl_Obj *) ((char *) 1); } /* *-------------------------------------------------------------- * * Tcl_ExprObj -- * * Evaluate an expression in a Tcl_Obj. * * Results: * A standard Tcl object result. If the result is other than TCL_OK, * then the interpreter's result contains an error message. If the * result is TCL_OK, then a pointer to the expression's result value * object is stored in resultPtrPtr. In that case, the object's ref * count is incremented to reflect the reference returned to the * caller; the caller is then responsible for the resulting object * and must, for example, decrement the ref count when it is finished * with the object. * * Side effects: * Any side effects caused by subcommands in the expression, if any. * The interpreter result is not modified unless there is an error. * *-------------------------------------------------------------- */ int Tcl_ExprObj(interp, objPtr, resultPtrPtr) Tcl_Interp *interp; /* Context in which to evaluate the * expression. */ register Tcl_Obj *objPtr; /* Points to Tcl object containing * expression to evaluate. */ Tcl_Obj **resultPtrPtr; /* Where the Tcl_Obj* that is the expression * result is stored if no errors occur. */ { Interp *iPtr = (Interp *) interp; CompileEnv compEnv; /* Compilation environment structure * allocated in frame. */ LiteralTable *localTablePtr = &(compEnv.localLitTable); register ByteCode *codePtr = NULL; /* Tcl Internal type of bytecode. * Initialized to avoid compiler warning. */ Tcl_Obj *saveObjPtr; char *string; int length, result; /* * First handle some common expressions specially. */ string = Tcl_GetStringFromObj(objPtr, &length); if (length == 1) { if (*string == '0') { *resultPtrPtr = Tcl_NewLongObj(0); Tcl_IncrRefCount(*resultPtrPtr); return TCL_OK; } else if (*string == '1') { *resultPtrPtr = Tcl_NewLongObj(1); Tcl_IncrRefCount(*resultPtrPtr); return TCL_OK; } } else if ((length == 2) && (*string == '!')) { if (*(string+1) == '0') { *resultPtrPtr = Tcl_NewLongObj(1); Tcl_IncrRefCount(*resultPtrPtr); return TCL_OK; } else if (*(string+1) == '1') { *resultPtrPtr = Tcl_NewLongObj(0); Tcl_IncrRefCount(*resultPtrPtr); return TCL_OK; } } /* * Compile and execute the expression after saving the interp's result. */ saveObjPtr = Tcl_GetObjResult(interp); Tcl_IncrRefCount(saveObjPtr); /* * Get the expression ByteCode from the object. If it exists, make sure it * is valid in the current context. */ if (objPtr->typePtr == &exprCodeType) { Namespace *namespacePtr = iPtr->varFramePtr ? iPtr->varFramePtr->nsPtr : iPtr->globalNsPtr; codePtr = (ByteCode *) objPtr->internalRep.otherValuePtr; if (((Interp *) *codePtr->interpHandle != iPtr) || (codePtr->compileEpoch != iPtr->compileEpoch) || (codePtr->nsPtr != namespacePtr) || (codePtr->nsEpoch != namespacePtr->resolverEpoch)) { objPtr->typePtr->freeIntRepProc(objPtr); objPtr->typePtr = (Tcl_ObjType *) NULL; } } if (objPtr->typePtr != &exprCodeType) { #ifndef TCL_TIP280 TclInitCompileEnv(interp, &compEnv, string, length); #else /* TIP #280 : No invoker (yet) - Expression compilation */ TclInitCompileEnv(interp, &compEnv, string, length, NULL, 0); #endif result = TclCompileExpr(interp, string, length, &compEnv); /* * Free the compilation environment's literal table bucket array if * it was dynamically allocated. */ if (localTablePtr->buckets != localTablePtr->staticBuckets) { ckfree((char *) localTablePtr->buckets); } if (result != TCL_OK) { /* * Compilation errors. Free storage allocated for compilation. */ #ifdef TCL_COMPILE_DEBUG TclVerifyLocalLiteralTable(&compEnv); #endif /*TCL_COMPILE_DEBUG*/ TclFreeCompileEnv(&compEnv); goto done; } /* * Successful compilation. If the expression yielded no * instructions, push an zero object as the expression's result. */ if (compEnv.codeNext == compEnv.codeStart) { TclEmitPush(TclRegisterLiteral(&compEnv, "0", 1, /*onHeap*/ 0), &compEnv); } /* * Add a "done" instruction as the last instruction and change the * object into a ByteCode object. Ownership of the literal objects * and aux data items is given to the ByteCode object. */ compEnv.numSrcBytes = iPtr->termOffset; TclEmitOpcode(INST_DONE, &compEnv); TclInitByteCodeObj(objPtr, &compEnv); objPtr->typePtr = &exprCodeType; TclFreeCompileEnv(&compEnv); codePtr = (ByteCode *) objPtr->internalRep.otherValuePtr; #ifdef TCL_COMPILE_DEBUG if (tclTraceCompile == 2) { TclPrintByteCodeObj(interp, objPtr); } #endif /* TCL_COMPILE_DEBUG */ } Tcl_ResetResult(interp); /* * Increment the code's ref count while it is being executed. If * afterwards no references to it remain, free the code. */ codePtr->refCount++; result = TclExecuteByteCode(interp, codePtr); codePtr->refCount--; if (codePtr->refCount <= 0) { TclCleanupByteCode(codePtr); } /* * If the expression evaluated successfully, store a pointer to its * value object in resultPtrPtr then restore the old interpreter result. * We increment the object's ref count to reflect the reference that we * are returning to the caller. We also decrement the ref count of the * interpreter's result object after calling Tcl_SetResult since we * next store into that field directly. */ if (result == TCL_OK) { *resultPtrPtr = iPtr->objResultPtr; Tcl_IncrRefCount(iPtr->objResultPtr); Tcl_SetObjResult(interp, saveObjPtr); } done: TclDecrRefCount(saveObjPtr); return result; } /* *---------------------------------------------------------------------- * * DupExprCodeInternalRep -- * * Part of the Tcl object type implementation for Tcl expression * bytecode. We do not copy the bytecode intrep. Instead, we * return without setting copyPtr->typePtr, so the copy is a plain * string copy of the expression value, and if it is to be used * as a compiled expression, it will just need a recompile. * * This makes sense, because with Tcl's copy-on-write practices, * the usual (only?) time Tcl_DuplicateObj() will be called is * when the copy is about to be modified, which would invalidate * any copied bytecode anyway. The only reason it might make sense * to copy the bytecode is if we had some modifying routines that * operated directly on the intrep, like we do for lists and dicts. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void DupExprCodeInternalRep( Tcl_Obj *srcPtr, Tcl_Obj *copyPtr) { return; } /* *---------------------------------------------------------------------- * * FreeExprCodeInternalRep -- * * Part of the Tcl object type implementation for Tcl expression * bytecode. Frees the storage allocated to hold the internal rep, * unless ref counts indicate bytecode execution is still in progress. * * Results: * None. * * Side effects: * May free allocated memory. Leaves objPtr untyped. *---------------------------------------------------------------------- */ static void FreeExprCodeInternalRep( Tcl_Obj *objPtr) { ByteCode *codePtr = (ByteCode *) objPtr->internalRep.otherValuePtr; codePtr->refCount--; if (codePtr->refCount <= 0) { TclCleanupByteCode(codePtr); } objPtr->typePtr = NULL; objPtr->internalRep.otherValuePtr = NULL; } /* *---------------------------------------------------------------------- * * TclCompEvalObj -- * * This procedure evaluates the script contained in a Tcl_Obj by * first compiling it and then passing it to TclExecuteByteCode. * * Results: * The return value is one of the return codes defined in tcl.h * (such as TCL_OK), and interp->objResultPtr refers to a Tcl object * that either contains the result of executing the code or an * error message. * * Side effects: * Almost certainly, depending on the ByteCode's instructions. * *---------------------------------------------------------------------- */ int #ifndef TCL_TIP280 TclCompEvalObj(interp, objPtr) #else TclCompEvalObj(interp, objPtr, invoker, word) #endif Tcl_Interp *interp; Tcl_Obj *objPtr; #ifdef TCL_TIP280 CONST CmdFrame* invoker; /* Frame of the command doing the eval */ int word; /* Index of the word which is in objPtr */ #endif { register Interp *iPtr = (Interp *) interp; register ByteCode* codePtr; /* Tcl Internal type of bytecode. */ int oldCount = iPtr->cmdCount; /* Used to tell whether any commands * at all were executed. */ char *script; int numSrcBytes; int result; Namespace *namespacePtr; /* * Check that the interpreter is ready to execute scripts */ iPtr->numLevels++; if (TclInterpReady(interp) == TCL_ERROR) { iPtr->numLevels--; return TCL_ERROR; } if (iPtr->varFramePtr != NULL) { namespacePtr = iPtr->varFramePtr->nsPtr; } else { namespacePtr = iPtr->globalNsPtr; } /* * If the object is not already of tclByteCodeType, compile it (and * reset the compilation flags in the interpreter; this should be * done after any compilation). * Otherwise, check that it is "fresh" enough. */ if (objPtr->typePtr != &tclByteCodeType) { recompileObj: iPtr->errorLine = 1; #ifdef TCL_TIP280 /* TIP #280. Remember the invoker for a moment in the interpreter * structures so that the byte code compiler can pick it up when * initializing the compilation environment, i.e. the extended * location information. */ iPtr->invokeCmdFramePtr = invoker; iPtr->invokeWord = word; #endif result = tclByteCodeType.setFromAnyProc(interp, objPtr); #ifdef TCL_TIP280 iPtr->invokeCmdFramePtr = NULL; #endif if (result != TCL_OK) { iPtr->numLevels--; return result; } codePtr = (ByteCode *) objPtr->internalRep.otherValuePtr; } else { /* * Make sure the Bytecode hasn't been invalidated by, e.g., someone * redefining a command with a compile procedure (this might make the * compiled code wrong). * The object needs to be recompiled if it was compiled in/for a * different interpreter, or for a different namespace, or for the * same namespace but with different name resolution rules. * Precompiled objects, however, are immutable and therefore * they are not recompiled, even if the epoch has changed. * * To be pedantically correct, we should also check that the * originating procPtr is the same as the current context procPtr * (assuming one exists at all - none for global level). This * code is #def'ed out because [info body] was changed to never * return a bytecode type object, which should obviate us from * the extra checks here. */ codePtr = (ByteCode *) objPtr->internalRep.otherValuePtr; if (((Interp *) *codePtr->interpHandle != iPtr) || (codePtr->compileEpoch != iPtr->compileEpoch) #ifdef CHECK_PROC_ORIGINATION /* [Bug: 3412 Pedantic] */ || (codePtr->procPtr != NULL && !(iPtr->varFramePtr && iPtr->varFramePtr->procPtr == codePtr->procPtr)) #endif || (codePtr->nsPtr != namespacePtr) || (codePtr->nsEpoch != namespacePtr->resolverEpoch)) { if (codePtr->flags & TCL_BYTECODE_PRECOMPILED) { if ((Interp *) *codePtr->interpHandle != iPtr) { panic("Tcl_EvalObj: compiled script jumped interps"); } codePtr->compileEpoch = iPtr->compileEpoch; } else { /* * This byteCode is invalid: free it and recompile */ tclByteCodeType.freeIntRepProc(objPtr); goto recompileObj; } } } /* * Execute the commands. If the code was compiled from an empty string, * don't bother executing the code. */ numSrcBytes = codePtr->numSrcBytes; if ((numSrcBytes > 0) || (codePtr->flags & TCL_BYTECODE_PRECOMPILED)) { /* * Increment the code's ref count while it is being executed. If * afterwards no references to it remain, free the code. */ codePtr->refCount++; result = TclExecuteByteCode(interp, codePtr); codePtr->refCount--; if (codePtr->refCount <= 0) { TclCleanupByteCode(codePtr); } } else { result = TCL_OK; } iPtr->numLevels--; /* * If no commands at all were executed, check for asynchronous * handlers so that they at least get one change to execute. * This is needed to handle event loops written in Tcl with * empty bodies. */ if ((oldCount == iPtr->cmdCount) && Tcl_AsyncReady()) { result = Tcl_AsyncInvoke(interp, result); /* * If an error occurred, record information about what was being * executed when the error occurred. */ if ((result == TCL_ERROR) && !(iPtr->flags & ERR_ALREADY_LOGGED)) { script = Tcl_GetStringFromObj(objPtr, &numSrcBytes); Tcl_LogCommandInfo(interp, script, script, numSrcBytes); } } /* * Set the interpreter's termOffset member to the offset of the * character just after the last one executed. We approximate the offset * of the last character executed by using the number of characters * compiled. */ iPtr->termOffset = numSrcBytes; iPtr->flags &= ~ERR_ALREADY_LOGGED; return result; } /* *---------------------------------------------------------------------- * * TclExecuteByteCode -- * * This procedure executes the instructions of a ByteCode structure. * It returns when a "done" instruction is executed or an error occurs. * * Results: * The return value is one of the return codes defined in tcl.h * (such as TCL_OK), and interp->objResultPtr refers to a Tcl object * that either contains the result of executing the code or an * error message. * * Side effects: * Almost certainly, depending on the ByteCode's instructions. * *---------------------------------------------------------------------- */ static int TclExecuteByteCode(interp, codePtr) Tcl_Interp *interp; /* Token for command interpreter. */ ByteCode *codePtr; /* The bytecode sequence to interpret. */ { Interp *iPtr = (Interp *) interp; ExecEnv *eePtr = iPtr->execEnvPtr; /* Points to the execution environment. */ register Tcl_Obj **stackPtr = eePtr->stackPtr; /* Cached evaluation stack base pointer. */ register int stackTop = eePtr->stackTop; /* Cached top index of evaluation stack. */ register unsigned char *pc = codePtr->codeStart; /* The current program counter. */ int opnd; /* Current instruction's operand byte(s). */ int pcAdjustment; /* Hold pc adjustment after instruction. */ int initStackTop = stackTop;/* Stack top at start of execution. */ ExceptionRange *rangePtr; /* Points to closest loop or catch exception * range enclosing the pc. Used by various * instructions and processCatch to * process break, continue, and errors. */ int result = TCL_OK; /* Return code returned after execution. */ int storeFlags; Tcl_Obj *valuePtr, *value2Ptr, *objPtr; char *bytes; int length; long i = 0; /* Init. avoids compiler warning. */ Tcl_WideInt w; register int cleanup; Tcl_Obj *objResultPtr; char *part1, *part2; Var *varPtr, *arrayPtr; CallFrame *varFramePtr = iPtr->varFramePtr; #ifdef TCL_TIP280 /* TIP #280 : Structures for tracking lines */ CmdFrame bcFrame; #endif #ifdef TCL_COMPILE_DEBUG int traceInstructions = (tclTraceExec == 3); char cmdNameBuf[21]; #endif char *curInstName = NULL; /* * This procedure uses a stack to hold information about catch commands. * This information is the current operand stack top when starting to * execute the code for each catch command. It starts out with stack- * allocated space but uses dynamically-allocated storage if needed. */ #define STATIC_CATCH_STACK_SIZE 4 int (catchStackStorage[STATIC_CATCH_STACK_SIZE]); int *catchStackPtr = catchStackStorage; int catchTop = -1; #ifdef TCL_TIP280 /* TIP #280 : Initialize the frame. Do not push it yet. */ bcFrame.type = ((codePtr->flags & TCL_BYTECODE_PRECOMPILED) ? TCL_LOCATION_PREBC : TCL_LOCATION_BC); bcFrame.level = (iPtr->cmdFramePtr == NULL ? 1 : iPtr->cmdFramePtr->level + 1); bcFrame.framePtr = iPtr->framePtr; bcFrame.nextPtr = iPtr->cmdFramePtr; bcFrame.nline = 0; bcFrame.line = NULL; bcFrame.data.tebc.codePtr = codePtr; bcFrame.data.tebc.pc = NULL; bcFrame.cmd.str.cmd = NULL; bcFrame.cmd.str.len = 0; #endif #ifdef TCL_COMPILE_DEBUG if (tclTraceExec >= 2) { PrintByteCodeInfo(codePtr); fprintf(stdout, " Starting stack top=%d\n", eePtr->stackTop); fflush(stdout); } opnd = 0; /* Init. avoids compiler warning. */ #endif #ifdef TCL_COMPILE_STATS iPtr->stats.numExecutions++; #endif /* * Make sure the catch stack is large enough to hold the maximum number * of catch commands that could ever be executing at the same time. This * will be no more than the exception range array's depth. */ if (codePtr->maxExceptDepth > STATIC_CATCH_STACK_SIZE) { catchStackPtr = (int *) ckalloc(codePtr->maxExceptDepth * sizeof(int)); } /* * Make sure the stack has enough room to execute this ByteCode. */ while ((stackTop + codePtr->maxStackDepth) > eePtr->stackEnd) { GrowEvaluationStack(eePtr); stackPtr = eePtr->stackPtr; } /* * Loop executing instructions until a "done" instruction, a * TCL_RETURN, or some error. */ goto cleanup0; /* * Targets for standard instruction endings; unrolled * for speed in the most frequent cases (instructions that * consume up to two stack elements). * * This used to be a "for(;;)" loop, with each instruction doing * its own cleanup. */ cleanupV_pushObjResultPtr: switch (cleanup) { case 0: stackPtr[++stackTop] = (objResultPtr); goto cleanup0; default: cleanup -= 2; while (cleanup--) { valuePtr = POP_OBJECT(); TclDecrRefCount(valuePtr); } case 2: cleanup2_pushObjResultPtr: valuePtr = POP_OBJECT(); TclDecrRefCount(valuePtr); case 1: cleanup1_pushObjResultPtr: valuePtr = stackPtr[stackTop]; TclDecrRefCount(valuePtr); } stackPtr[stackTop] = objResultPtr; goto cleanup0; cleanupV: switch (cleanup) { default: cleanup -= 2; while (cleanup--) { valuePtr = POP_OBJECT(); TclDecrRefCount(valuePtr); } case 2: cleanup2: valuePtr = POP_OBJECT(); TclDecrRefCount(valuePtr); case 1: cleanup1: valuePtr = POP_OBJECT(); TclDecrRefCount(valuePtr); case 0: /* * We really want to do nothing now, but this is needed * for some compilers (SunPro CC) */ break; } cleanup0: #ifdef TCL_COMPILE_DEBUG ValidatePcAndStackTop(codePtr, pc, stackTop, initStackTop); if (traceInstructions) { fprintf(stdout, "%2d: %2d ", iPtr->numLevels, stackTop); TclPrintInstruction(codePtr, pc); fflush(stdout); } #endif /* TCL_COMPILE_DEBUG */ #ifdef TCL_COMPILE_STATS iPtr->stats.instructionCount[*pc]++; #endif TCL_DTRACE_INST_NEXT(); switch (*pc) { case INST_DONE: if (stackTop <= initStackTop) { stackTop--; goto abnormalReturn; } /* * Set the interpreter's object result to point to the * topmost object from the stack, and check for a possible * [catch]. The stackTop's level and refCount will be handled * by "processCatch" or "abnormalReturn". */ valuePtr = stackPtr[stackTop]; Tcl_SetObjResult(interp, valuePtr); #ifdef TCL_COMPILE_DEBUG TRACE_WITH_OBJ(("=> return code=%d, result=", result), iPtr->objResultPtr); if (traceInstructions) { fprintf(stdout, "\n"); } #endif goto checkForCatch; case INST_PUSH1: objResultPtr = codePtr->objArrayPtr[TclGetUInt1AtPtr(pc+1)]; TRACE_WITH_OBJ(("%u => ", TclGetInt1AtPtr(pc+1)), objResultPtr); NEXT_INST_F(2, 0, 1); case INST_PUSH4: objResultPtr = codePtr->objArrayPtr[TclGetUInt4AtPtr(pc+1)]; TRACE_WITH_OBJ(("%u => ", TclGetUInt4AtPtr(pc+1)), objResultPtr); NEXT_INST_F(5, 0, 1); case INST_POP: TRACE_WITH_OBJ(("=> discarding "), stackPtr[stackTop]); valuePtr = POP_OBJECT(); TclDecrRefCount(valuePtr); NEXT_INST_F(1, 0, 0); case INST_DUP: objResultPtr = stackPtr[stackTop]; TRACE_WITH_OBJ(("=> "), objResultPtr); NEXT_INST_F(1, 0, 1); case INST_OVER: opnd = TclGetUInt4AtPtr( pc+1 ); objResultPtr = stackPtr[ stackTop - opnd ]; TRACE_WITH_OBJ(("=> "), objResultPtr); NEXT_INST_F(5, 0, 1); case INST_CONCAT1: opnd = TclGetUInt1AtPtr(pc+1); { int totalLen = 0; /* * Peephole optimisation for appending an empty string. * This enables replacing 'K $x [set x{}]' by '$x[set x{}]' * for fastest execution. Avoid doing the optimisation for wide * ints - a case where equal strings may refer to different values * (see [Bug 1251791]). */ if ((opnd == 2) && (stackPtr[stackTop-1]->typePtr != &tclWideIntType)) { Tcl_GetStringFromObj(stackPtr[stackTop], &length); if (length == 0) { /* Just drop the top item from the stack */ NEXT_INST_F(2, 1, 0); } } /* * Concatenate strings (with no separators) from the top * opnd items on the stack starting with the deepest item. * First, determine how many characters are needed. */ for (i = (stackTop - (opnd-1)); totalLen >= 0 && i <= stackTop; i++) { bytes = Tcl_GetStringFromObj(stackPtr[i], &length); if (bytes != NULL) { totalLen += length; } } if (totalLen < 0) { Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX); } /* * Initialize the new append string object by appending the * strings of the opnd stack objects. Also pop the objects. */ TclNewObj(objResultPtr); if (totalLen > 0) { char *p = (char *) ckalloc((unsigned) (totalLen + 1)); objResultPtr->bytes = p; objResultPtr->length = totalLen; for (i = (stackTop - (opnd-1)); i <= stackTop; i++) { valuePtr = stackPtr[i]; bytes = Tcl_GetStringFromObj(valuePtr, &length); if (bytes != NULL) { memcpy((VOID *) p, (VOID *) bytes, (size_t) length); p += length; } } *p = '\0'; } TRACE_WITH_OBJ(("%u => ", opnd), objResultPtr); NEXT_INST_V(2, opnd, 1); } case INST_INVOKE_STK4: opnd = TclGetUInt4AtPtr(pc+1); pcAdjustment = 5; goto doInvocation; case INST_INVOKE_STK1: opnd = TclGetUInt1AtPtr(pc+1); pcAdjustment = 2; doInvocation: { int objc = opnd; /* The number of arguments. */ Tcl_Obj **objv; /* The array of argument objects. */ /* * We keep the stack reference count as a (char *), as that * works nicely as a portable pointer-sized counter. */ char **preservedStackRefCountPtr; /* * Reference to memory block containing * objv array (must be kept live throughout * trace and command invokations.) */ objv = &(stackPtr[stackTop - (objc-1)]); #ifdef TCL_COMPILE_DEBUG if (tclTraceExec >= 2) { if (traceInstructions) { strncpy(cmdNameBuf, TclGetString(objv[0]), 20); TRACE(("%u => call ", objc)); } else { fprintf(stdout, "%d: (%u) invoking ", iPtr->numLevels, (unsigned int)(pc - codePtr->codeStart)); } for (i = 0; i < objc; i++) { TclPrintObject(stdout, objv[i], 15); fprintf(stdout, " "); } fprintf(stdout, "\n"); fflush(stdout); } #endif /*TCL_COMPILE_DEBUG*/ /* * If trace procedures will be called, we need a * command string to pass to TclEvalObjvInternal; note * that a copy of the string will be made there to * include the ending \0. */ bytes = NULL; length = 0; if (iPtr->tracePtr != NULL) { Trace *tracePtr, *nextTracePtr; for (tracePtr = iPtr->tracePtr; tracePtr != NULL; tracePtr = nextTracePtr) { nextTracePtr = tracePtr->nextPtr; if (tracePtr->level == 0 || iPtr->numLevels <= tracePtr->level) { /* * Traces will be called: get command string */ bytes = GetSrcInfoForPc(pc, codePtr, &length); break; } } } else { Command *cmdPtr; cmdPtr = (Command *) Tcl_GetCommandFromObj(interp, objv[0]); if ((cmdPtr != NULL) && (cmdPtr->flags & CMD_HAS_EXEC_TRACES)) { bytes = GetSrcInfoForPc(pc, codePtr, &length); } } /* * A reference to part of the stack vector itself * escapes our control: increase its refCount * to stop it from being deallocated by a recursive * call to ourselves. The extra variable is needed * because all others are liable to change due to the * trace procedures. */ preservedStackRefCountPtr = (char **) (stackPtr-1); ++*preservedStackRefCountPtr; /* * Finally, let TclEvalObjvInternal handle the command. * * TIP #280 : Record the last piece of info needed by * 'TclGetSrcInfoForPc', and push the frame. */ #ifdef TCL_TIP280 bcFrame.data.tebc.pc = (char*) pc; iPtr->cmdFramePtr = &bcFrame; TclArgumentBCEnter((Tcl_Interp*) iPtr, objv, objc, codePtr, &bcFrame, pc - codePtr->codeStart); #endif DECACHE_STACK_INFO(); Tcl_ResetResult(interp); result = TclEvalObjvInternal(interp, objc, objv, bytes, length, 0); CACHE_STACK_INFO(); #ifdef TCL_TIP280 TclArgumentBCRelease((Tcl_Interp*) iPtr, objv, objc, codePtr, pc - codePtr->codeStart); iPtr->cmdFramePtr = iPtr->cmdFramePtr->nextPtr; #endif /* * If the old stack is going to be released, it is * safe to do so now, since no references to objv are * going to be used from now on. */ --*preservedStackRefCountPtr; if (*preservedStackRefCountPtr == (char *) 0) { ckfree((VOID *) preservedStackRefCountPtr); } if (result == TCL_OK) { /* * Push the call's object result and continue execution * with the next instruction. */ TRACE_WITH_OBJ(("%u => ... after \"%.20s\": TCL_OK, result=", objc, cmdNameBuf), Tcl_GetObjResult(interp)); objResultPtr = Tcl_GetObjResult(interp); /* * Reset the interp's result to avoid possible duplications * of large objects [Bug 781585]. We do not call * Tcl_ResetResult() to avoid any side effects caused by * the resetting of errorInfo and errorCode [Bug 804681], * which are not needed here. We chose instead to manipulate * the interp's object result directly. * * Note that the result object is now in objResultPtr, it * keeps the refCount it had in its role of iPtr->objResultPtr. */ { Tcl_Obj *newObjResultPtr; TclNewObj(newObjResultPtr); Tcl_IncrRefCount(newObjResultPtr); iPtr->objResultPtr = newObjResultPtr; } NEXT_INST_V(pcAdjustment, opnd, -1); } else { cleanup = opnd; goto processExceptionReturn; } } case INST_EVAL_STK: /* * Note to maintainers: it is important that INST_EVAL_STK * pop its argument from the stack before jumping to * checkForCatch! DO NOT OPTIMISE! */ objPtr = stackPtr[stackTop]; DECACHE_STACK_INFO(); #ifndef TCL_TIP280 result = TclCompEvalObj(interp, objPtr); #else /* TIP #280: The invoking context is left NULL for a dynamically * constructed command. We cannot match its lines to the outer * context. */ result = TclCompEvalObj(interp, objPtr, NULL,0); #endif CACHE_STACK_INFO(); if (result == TCL_OK) { /* * Normal return; push the eval's object result. */ objResultPtr = Tcl_GetObjResult(interp); TRACE_WITH_OBJ(("\"%.30s\" => ", O2S(objPtr)), Tcl_GetObjResult(interp)); /* * Reset the interp's result to avoid possible duplications * of large objects [Bug 781585]. We do not call * Tcl_ResetResult() to avoid any side effects caused by * the resetting of errorInfo and errorCode [Bug 804681], * which are not needed here. We chose instead to manipulate * the interp's object result directly. * * Note that the result object is now in objResultPtr, it * keeps the refCount it had in its role of iPtr->objResultPtr. */ { Tcl_Obj *newObjResultPtr; TclNewObj(newObjResultPtr); Tcl_IncrRefCount(newObjResultPtr); iPtr->objResultPtr = newObjResultPtr; } NEXT_INST_F(1, 1, -1); } else { cleanup = 1; goto processExceptionReturn; } case INST_EXPR_STK: objPtr = stackPtr[stackTop]; DECACHE_STACK_INFO(); Tcl_ResetResult(interp); result = Tcl_ExprObj(interp, objPtr, &valuePtr); CACHE_STACK_INFO(); if (result != TCL_OK) { TRACE_WITH_OBJ(("\"%.30s\" => ERROR: ", O2S(objPtr)), Tcl_GetObjResult(interp)); goto checkForCatch; } objResultPtr = valuePtr; TRACE_WITH_OBJ(("\"%.30s\" => ", O2S(objPtr)), valuePtr); NEXT_INST_F(1, 1, -1); /* already has right refct */ /* * --------------------------------------------------------- * Start of INST_LOAD instructions. * * WARNING: more 'goto' here than your doctor recommended! * The different instructions set the value of some variables * and then jump to somme common execution code. */ case INST_LOAD_SCALAR1: opnd = TclGetUInt1AtPtr(pc+1); varPtr = &(varFramePtr->compiledLocals[opnd]); part1 = varPtr->name; while (TclIsVarLink(varPtr)) { varPtr = varPtr->value.linkPtr; } TRACE(("%u => ", opnd)); if (TclIsVarScalar(varPtr) && !TclIsVarUndefined(varPtr) && (varPtr->tracePtr == NULL)) { /* * No errors, no traces: just get the value. */ objResultPtr = varPtr->value.objPtr; TRACE_APPEND(("%.30s\n", O2S(objResultPtr))); NEXT_INST_F(2, 0, 1); } pcAdjustment = 2; cleanup = 0; arrayPtr = NULL; part2 = NULL; goto doCallPtrGetVar; case INST_LOAD_SCALAR4: opnd = TclGetUInt4AtPtr(pc+1); varPtr = &(varFramePtr->compiledLocals[opnd]); part1 = varPtr->name; while (TclIsVarLink(varPtr)) { varPtr = varPtr->value.linkPtr; } TRACE(("%u => ", opnd)); if (TclIsVarScalar(varPtr) && !TclIsVarUndefined(varPtr) && (varPtr->tracePtr == NULL)) { /* * No errors, no traces: just get the value. */ objResultPtr = varPtr->value.objPtr; TRACE_APPEND(("%.30s\n", O2S(objResultPtr))); NEXT_INST_F(5, 0, 1); } pcAdjustment = 5; cleanup = 0; arrayPtr = NULL; part2 = NULL; goto doCallPtrGetVar; case INST_LOAD_ARRAY_STK: cleanup = 2; part2 = Tcl_GetString(stackPtr[stackTop]); /* element name */ objPtr = stackPtr[stackTop-1]; /* array name */ TRACE(("\"%.30s(%.30s)\" => ", O2S(objPtr), part2)); goto doLoadStk; case INST_LOAD_STK: case INST_LOAD_SCALAR_STK: cleanup = 1; part2 = NULL; objPtr = stackPtr[stackTop]; /* variable name */ TRACE(("\"%.30s\" => ", O2S(objPtr))); doLoadStk: part1 = TclGetString(objPtr); varPtr = TclObjLookupVar(interp, objPtr, part2, TCL_LEAVE_ERR_MSG, "read", /*createPart1*/ 0, /*createPart2*/ 1, &arrayPtr); if (varPtr == NULL) { TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp)))); result = TCL_ERROR; goto checkForCatch; } if (TclIsVarScalar(varPtr) && !TclIsVarUndefined(varPtr) && (varPtr->tracePtr == NULL) && ((arrayPtr == NULL) || (arrayPtr->tracePtr == NULL))) { /* * No errors, no traces: just get the value. */ objResultPtr = varPtr->value.objPtr; TRACE_APPEND(("%.30s\n", O2S(objResultPtr))); NEXT_INST_V(1, cleanup, 1); } pcAdjustment = 1; goto doCallPtrGetVar; case INST_LOAD_ARRAY4: opnd = TclGetUInt4AtPtr(pc+1); pcAdjustment = 5; goto doLoadArray; case INST_LOAD_ARRAY1: opnd = TclGetUInt1AtPtr(pc+1); pcAdjustment = 2; doLoadArray: part2 = TclGetString(stackPtr[stackTop]); arrayPtr = &(varFramePtr->compiledLocals[opnd]); part1 = arrayPtr->name; while (TclIsVarLink(arrayPtr)) { arrayPtr = arrayPtr->value.linkPtr; } TRACE(("%u \"%.30s\" => ", opnd, part2)); varPtr = TclLookupArrayElement(interp, part1, part2, TCL_LEAVE_ERR_MSG, "read", 0, 1, arrayPtr); if (varPtr == NULL) { TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp)))); result = TCL_ERROR; goto checkForCatch; } if (TclIsVarScalar(varPtr) && !TclIsVarUndefined(varPtr) && (varPtr->tracePtr == NULL) && ((arrayPtr == NULL) || (arrayPtr->tracePtr == NULL))) { /* * No errors, no traces: just get the value. */ objResultPtr = varPtr->value.objPtr; TRACE_APPEND(("%.30s\n", O2S(objResultPtr))); NEXT_INST_F(pcAdjustment, 1, 1); } cleanup = 1; goto doCallPtrGetVar; doCallPtrGetVar: /* * There are either errors or the variable is traced: * call TclPtrGetVar to process fully. */ DECACHE_STACK_INFO(); objResultPtr = TclPtrGetVar(interp, varPtr, arrayPtr, part1, part2, TCL_LEAVE_ERR_MSG); CACHE_STACK_INFO(); if (objResultPtr == NULL) { TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp)))); result = TCL_ERROR; goto checkForCatch; } TRACE_APPEND(("%.30s\n", O2S(objResultPtr))); NEXT_INST_V(pcAdjustment, cleanup, 1); /* * End of INST_LOAD instructions. * --------------------------------------------------------- */ /* * --------------------------------------------------------- * Start of INST_STORE and related instructions. * * WARNING: more 'goto' here than your doctor recommended! * The different instructions set the value of some variables * and then jump to somme common execution code. */ case INST_LAPPEND_STK: valuePtr = stackPtr[stackTop]; /* value to append */ part2 = NULL; storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE | TCL_LIST_ELEMENT); goto doStoreStk; case INST_LAPPEND_ARRAY_STK: valuePtr = stackPtr[stackTop]; /* value to append */ part2 = TclGetString(stackPtr[stackTop - 1]); storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE | TCL_LIST_ELEMENT); goto doStoreStk; case INST_APPEND_STK: valuePtr = stackPtr[stackTop]; /* value to append */ part2 = NULL; storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE); goto doStoreStk; case INST_APPEND_ARRAY_STK: valuePtr = stackPtr[stackTop]; /* value to append */ part2 = TclGetString(stackPtr[stackTop - 1]); storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE); goto doStoreStk; case INST_STORE_ARRAY_STK: valuePtr = stackPtr[stackTop]; part2 = TclGetString(stackPtr[stackTop - 1]); storeFlags = TCL_LEAVE_ERR_MSG; goto doStoreStk; case INST_STORE_STK: case INST_STORE_SCALAR_STK: valuePtr = stackPtr[stackTop]; part2 = NULL; storeFlags = TCL_LEAVE_ERR_MSG; doStoreStk: objPtr = stackPtr[stackTop - 1 - (part2 != NULL)]; /* variable name */ part1 = TclGetString(objPtr); #ifdef TCL_COMPILE_DEBUG if (part2 == NULL) { TRACE(("\"%.30s\" <- \"%.30s\" =>", part1, O2S(valuePtr))); } else { TRACE(("\"%.30s(%.30s)\" <- \"%.30s\" => ", part1, part2, O2S(valuePtr))); } #endif varPtr = TclObjLookupVar(interp, objPtr, part2, TCL_LEAVE_ERR_MSG, "set", /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr); if (varPtr == NULL) { TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp)))); result = TCL_ERROR; goto checkForCatch; } cleanup = ((part2 == NULL)? 2 : 3); pcAdjustment = 1; goto doCallPtrSetVar; case INST_LAPPEND_ARRAY4: opnd = TclGetUInt4AtPtr(pc+1); pcAdjustment = 5; storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE | TCL_LIST_ELEMENT); goto doStoreArray; case INST_LAPPEND_ARRAY1: opnd = TclGetUInt1AtPtr(pc+1); pcAdjustment = 2; storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE | TCL_LIST_ELEMENT); goto doStoreArray; case INST_APPEND_ARRAY4: opnd = TclGetUInt4AtPtr(pc+1); pcAdjustment = 5; storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE); goto doStoreArray; case INST_APPEND_ARRAY1: opnd = TclGetUInt1AtPtr(pc+1); pcAdjustment = 2; storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE); goto doStoreArray; case INST_STORE_ARRAY4: opnd = TclGetUInt4AtPtr(pc+1); pcAdjustment = 5; storeFlags = TCL_LEAVE_ERR_MSG; goto doStoreArray; case INST_STORE_ARRAY1: opnd = TclGetUInt1AtPtr(pc+1); pcAdjustment = 2; storeFlags = TCL_LEAVE_ERR_MSG; doStoreArray: valuePtr = stackPtr[stackTop]; part2 = TclGetString(stackPtr[stackTop - 1]); arrayPtr = &(varFramePtr->compiledLocals[opnd]); part1 = arrayPtr->name; TRACE(("%u \"%.30s\" <- \"%.30s\" => ", opnd, part2, O2S(valuePtr))); while (TclIsVarLink(arrayPtr)) { arrayPtr = arrayPtr->value.linkPtr; } varPtr = TclLookupArrayElement(interp, part1, part2, TCL_LEAVE_ERR_MSG, "set", 1, 1, arrayPtr); if (varPtr == NULL) { TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp)))); result = TCL_ERROR; goto checkForCatch; } cleanup = 2; goto doCallPtrSetVar; case INST_LAPPEND_SCALAR4: opnd = TclGetUInt4AtPtr(pc+1); pcAdjustment = 5; storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE | TCL_LIST_ELEMENT); goto doStoreScalar; case INST_LAPPEND_SCALAR1: opnd = TclGetUInt1AtPtr(pc+1); pcAdjustment = 2; storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE | TCL_LIST_ELEMENT); goto doStoreScalar; case INST_APPEND_SCALAR4: opnd = TclGetUInt4AtPtr(pc+1); pcAdjustment = 5; storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE); goto doStoreScalar; case INST_APPEND_SCALAR1: opnd = TclGetUInt1AtPtr(pc+1); pcAdjustment = 2; storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE); goto doStoreScalar; case INST_STORE_SCALAR4: opnd = TclGetUInt4AtPtr(pc+1); pcAdjustment = 5; storeFlags = TCL_LEAVE_ERR_MSG; goto doStoreScalar; case INST_STORE_SCALAR1: opnd = TclGetUInt1AtPtr(pc+1); pcAdjustment = 2; storeFlags = TCL_LEAVE_ERR_MSG; doStoreScalar: valuePtr = stackPtr[stackTop]; varPtr = &(varFramePtr->compiledLocals[opnd]); part1 = varPtr->name; TRACE(("%u <- \"%.30s\" => ", opnd, O2S(valuePtr))); while (TclIsVarLink(varPtr)) { varPtr = varPtr->value.linkPtr; } cleanup = 1; arrayPtr = NULL; part2 = NULL; doCallPtrSetVar: if ((storeFlags == TCL_LEAVE_ERR_MSG) && !((varPtr->flags & VAR_IN_HASHTABLE) && (varPtr->hPtr == NULL)) && (varPtr->tracePtr == NULL) && (TclIsVarScalar(varPtr) || TclIsVarUndefined(varPtr)) && ((arrayPtr == NULL) || (arrayPtr->tracePtr == NULL))) { /* * No traces, no errors, plain 'set': we can safely inline. * The value *will* be set to what's requested, so that * the stack top remains pointing to the same Tcl_Obj. */ valuePtr = varPtr->value.objPtr; objResultPtr = stackPtr[stackTop]; if (valuePtr != objResultPtr) { if (valuePtr != NULL) { TclDecrRefCount(valuePtr); } else { TclSetVarScalar(varPtr); TclClearVarUndefined(varPtr); } varPtr->value.objPtr = objResultPtr; Tcl_IncrRefCount(objResultPtr); } #ifndef TCL_COMPILE_DEBUG if (*(pc+pcAdjustment) == INST_POP) { NEXT_INST_V((pcAdjustment+1), cleanup, 0); } #else TRACE_APPEND(("%.30s\n", O2S(objResultPtr))); #endif NEXT_INST_V(pcAdjustment, cleanup, 1); } else { DECACHE_STACK_INFO(); objResultPtr = TclPtrSetVar(interp, varPtr, arrayPtr, part1, part2, valuePtr, storeFlags); CACHE_STACK_INFO(); if (objResultPtr == NULL) { TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp)))); result = TCL_ERROR; goto checkForCatch; } } #ifndef TCL_COMPILE_DEBUG if (*(pc+pcAdjustment) == INST_POP) { NEXT_INST_V((pcAdjustment+1), cleanup, 0); } #endif TRACE_APPEND(("%.30s\n", O2S(objResultPtr))); NEXT_INST_V(pcAdjustment, cleanup, 1); /* * End of INST_STORE and related instructions. * --------------------------------------------------------- */ /* * --------------------------------------------------------- * Start of INST_INCR instructions. * * WARNING: more 'goto' here than your doctor recommended! * The different instructions set the value of some variables * and then jump to somme common execution code. */ case INST_INCR_SCALAR1: case INST_INCR_ARRAY1: case INST_INCR_ARRAY_STK: case INST_INCR_SCALAR_STK: case INST_INCR_STK: opnd = TclGetUInt1AtPtr(pc+1); valuePtr = stackPtr[stackTop]; if (valuePtr->typePtr == &tclIntType) { i = valuePtr->internalRep.longValue; } else if (valuePtr->typePtr == &tclWideIntType) { TclGetLongFromWide(i,valuePtr); } else { REQUIRE_WIDE_OR_INT(result, valuePtr, i, w); if (result != TCL_OK) { TRACE_WITH_OBJ(("%u (by %s) => ERROR converting increment amount to int: ", opnd, O2S(valuePtr)), Tcl_GetObjResult(interp)); DECACHE_STACK_INFO(); Tcl_AddErrorInfo(interp, "\n (reading increment)"); CACHE_STACK_INFO(); goto checkForCatch; } FORCE_LONG(valuePtr, i, w); } stackTop--; TclDecrRefCount(valuePtr); switch (*pc) { case INST_INCR_SCALAR1: pcAdjustment = 2; goto doIncrScalar; case INST_INCR_ARRAY1: pcAdjustment = 2; goto doIncrArray; default: pcAdjustment = 1; goto doIncrStk; } case INST_INCR_ARRAY_STK_IMM: case INST_INCR_SCALAR_STK_IMM: case INST_INCR_STK_IMM: i = TclGetInt1AtPtr(pc+1); pcAdjustment = 2; doIncrStk: if ((*pc == INST_INCR_ARRAY_STK_IMM) || (*pc == INST_INCR_ARRAY_STK)) { part2 = TclGetString(stackPtr[stackTop]); objPtr = stackPtr[stackTop - 1]; TRACE(("\"%.30s(%.30s)\" (by %ld) => ", O2S(objPtr), part2, i)); } else { part2 = NULL; objPtr = stackPtr[stackTop]; TRACE(("\"%.30s\" (by %ld) => ", O2S(objPtr), i)); } part1 = TclGetString(objPtr); varPtr = TclObjLookupVar(interp, objPtr, part2, TCL_LEAVE_ERR_MSG, "read", 0, 1, &arrayPtr); if (varPtr == NULL) { DECACHE_STACK_INFO(); Tcl_AddObjErrorInfo(interp, "\n (reading value of variable to increment)", -1); CACHE_STACK_INFO(); TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp)))); result = TCL_ERROR; goto checkForCatch; } cleanup = ((part2 == NULL)? 1 : 2); goto doIncrVar; case INST_INCR_ARRAY1_IMM: opnd = TclGetUInt1AtPtr(pc+1); i = TclGetInt1AtPtr(pc+2); pcAdjustment = 3; doIncrArray: part2 = TclGetString(stackPtr[stackTop]); arrayPtr = &(varFramePtr->compiledLocals[opnd]); part1 = arrayPtr->name; while (TclIsVarLink(arrayPtr)) { arrayPtr = arrayPtr->value.linkPtr; } TRACE(("%u \"%.30s\" (by %ld) => ", opnd, part2, i)); varPtr = TclLookupArrayElement(interp, part1, part2, TCL_LEAVE_ERR_MSG, "read", 0, 1, arrayPtr); if (varPtr == NULL) { TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp)))); result = TCL_ERROR; goto checkForCatch; } cleanup = 1; goto doIncrVar; case INST_INCR_SCALAR1_IMM: opnd = TclGetUInt1AtPtr(pc+1); i = TclGetInt1AtPtr(pc+2); pcAdjustment = 3; doIncrScalar: varPtr = &(varFramePtr->compiledLocals[opnd]); part1 = varPtr->name; while (TclIsVarLink(varPtr)) { varPtr = varPtr->value.linkPtr; } arrayPtr = NULL; part2 = NULL; cleanup = 0; TRACE(("%u %ld => ", opnd, i)); doIncrVar: objPtr = varPtr->value.objPtr; if (TclIsVarScalar(varPtr) && !TclIsVarUndefined(varPtr) && (varPtr->tracePtr == NULL) && ((arrayPtr == NULL) || (arrayPtr->tracePtr == NULL)) && (objPtr->typePtr == &tclIntType)) { /* * No errors, no traces, the variable already has an * integer value: inline processing. */ i += objPtr->internalRep.longValue; if (Tcl_IsShared(objPtr)) { objResultPtr = Tcl_NewLongObj(i); TclDecrRefCount(objPtr); Tcl_IncrRefCount(objResultPtr); varPtr->value.objPtr = objResultPtr; } else { Tcl_SetLongObj(objPtr, i); objResultPtr = objPtr; } TRACE_APPEND(("%.30s\n", O2S(objResultPtr))); } else { DECACHE_STACK_INFO(); objResultPtr = TclPtrIncrVar(interp, varPtr, arrayPtr, part1, part2, i, TCL_LEAVE_ERR_MSG); CACHE_STACK_INFO(); if (objResultPtr == NULL) { TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp)))); result = TCL_ERROR; goto checkForCatch; } } TRACE_APPEND(("%.30s\n", O2S(objResultPtr))); #ifndef TCL_COMPILE_DEBUG if (*(pc+pcAdjustment) == INST_POP) { NEXT_INST_V((pcAdjustment+1), cleanup, 0); } #endif NEXT_INST_V(pcAdjustment, cleanup, 1); /* * End of INST_INCR instructions. * --------------------------------------------------------- */ case INST_JUMP1: opnd = TclGetInt1AtPtr(pc+1); TRACE(("%d => new pc %u\n", opnd, (unsigned int)(pc + opnd - codePtr->codeStart))); NEXT_INST_F(opnd, 0, 0); case INST_JUMP4: opnd = TclGetInt4AtPtr(pc+1); TRACE(("%d => new pc %u\n", opnd, (unsigned int)(pc + opnd - codePtr->codeStart))); NEXT_INST_F(opnd, 0, 0); case INST_JUMP_FALSE4: opnd = 5; /* TRUE */ pcAdjustment = TclGetInt4AtPtr(pc+1); /* FALSE */ goto doJumpTrue; case INST_JUMP_TRUE4: opnd = TclGetInt4AtPtr(pc+1); /* TRUE */ pcAdjustment = 5; /* FALSE */ goto doJumpTrue; case INST_JUMP_FALSE1: opnd = 2; /* TRUE */ pcAdjustment = TclGetInt1AtPtr(pc+1); /* FALSE */ goto doJumpTrue; case INST_JUMP_TRUE1: opnd = TclGetInt1AtPtr(pc+1); /* TRUE */ pcAdjustment = 2; /* FALSE */ doJumpTrue: { int b; valuePtr = stackPtr[stackTop]; if (valuePtr->typePtr == &tclIntType) { b = (valuePtr->internalRep.longValue != 0); } else if (valuePtr->typePtr == &tclDoubleType) { b = (valuePtr->internalRep.doubleValue != 0.0); } else if (valuePtr->typePtr == &tclWideIntType) { TclGetWide(w,valuePtr); b = (w != W0); } else { result = Tcl_GetBooleanFromObj(interp, valuePtr, &b); if (result != TCL_OK) { TRACE_WITH_OBJ(("%d => ERROR: ", opnd), Tcl_GetObjResult(interp)); goto checkForCatch; } } #ifndef TCL_COMPILE_DEBUG NEXT_INST_F((b? opnd : pcAdjustment), 1, 0); #else if (b) { if ((*pc == INST_JUMP_TRUE1) || (*pc == INST_JUMP_TRUE1)) { TRACE(("%d => %.20s true, new pc %u\n", opnd, O2S(valuePtr), (unsigned int)(pc+opnd - codePtr->codeStart))); } else { TRACE(("%d => %.20s true\n", pcAdjustment, O2S(valuePtr))); } NEXT_INST_F(opnd, 1, 0); } else { if ((*pc == INST_JUMP_TRUE1) || (*pc == INST_JUMP_TRUE1)) { TRACE(("%d => %.20s false\n", opnd, O2S(valuePtr))); } else { opnd = pcAdjustment; TRACE(("%d => %.20s false, new pc %u\n", opnd, O2S(valuePtr), (unsigned int)(pc + opnd - codePtr->codeStart))); } NEXT_INST_F(pcAdjustment, 1, 0); } #endif } case INST_LOR: case INST_LAND: { /* * Operands must be boolean or numeric. No int->double * conversions are performed. */ int i1, i2; int iResult; char *s; Tcl_ObjType *t1Ptr, *t2Ptr; value2Ptr = stackPtr[stackTop]; valuePtr = stackPtr[stackTop - 1];; t1Ptr = valuePtr->typePtr; t2Ptr = value2Ptr->typePtr; if ((t1Ptr == &tclIntType) || (t1Ptr == &tclBooleanType)) { i1 = (valuePtr->internalRep.longValue != 0); } else if (t1Ptr == &tclWideIntType) { TclGetWide(w,valuePtr); i1 = (w != W0); } else if (t1Ptr == &tclDoubleType) { i1 = (valuePtr->internalRep.doubleValue != 0.0); } else { s = Tcl_GetStringFromObj(valuePtr, &length); if (TclLooksLikeInt(s, length)) { GET_WIDE_OR_INT(result, valuePtr, i, w); if (valuePtr->typePtr == &tclIntType) { i1 = (i != 0); } else { i1 = (w != W0); } } else { result = Tcl_GetBooleanFromObj((Tcl_Interp *) NULL, valuePtr, &i1); i1 = (i1 != 0); } if (result != TCL_OK) { TRACE(("\"%.20s\" => ILLEGAL TYPE %s \n", O2S(valuePtr), (t1Ptr? t1Ptr->name : "null"))); DECACHE_STACK_INFO(); IllegalExprOperandType(interp, pc, valuePtr); CACHE_STACK_INFO(); goto checkForCatch; } } if ((t2Ptr == &tclIntType) || (t2Ptr == &tclBooleanType)) { i2 = (value2Ptr->internalRep.longValue != 0); } else if (t2Ptr == &tclWideIntType) { TclGetWide(w,value2Ptr); i2 = (w != W0); } else if (t2Ptr == &tclDoubleType) { i2 = (value2Ptr->internalRep.doubleValue != 0.0); } else { s = Tcl_GetStringFromObj(value2Ptr, &length); if (TclLooksLikeInt(s, length)) { GET_WIDE_OR_INT(result, value2Ptr, i, w); if (value2Ptr->typePtr == &tclIntType) { i2 = (i != 0); } else { i2 = (w != W0); } } else { result = Tcl_GetBooleanFromObj((Tcl_Interp *) NULL, value2Ptr, &i2); } if (result != TCL_OK) { TRACE(("\"%.20s\" => ILLEGAL TYPE %s \n", O2S(value2Ptr), (t2Ptr? t2Ptr->name : "null"))); DECACHE_STACK_INFO(); IllegalExprOperandType(interp, pc, value2Ptr); CACHE_STACK_INFO(); goto checkForCatch; } } /* * Reuse the valuePtr object already on stack if possible. */ if (*pc == INST_LOR) { iResult = (i1 || i2); } else { iResult = (i1 && i2); } if (Tcl_IsShared(valuePtr)) { objResultPtr = Tcl_NewLongObj(iResult); TRACE(("%.20s %.20s => %d\n", O2S(valuePtr), O2S(value2Ptr), iResult)); NEXT_INST_F(1, 2, 1); } else { /* reuse the valuePtr object */ TRACE(("%.20s %.20s => %d\n", O2S(valuePtr), O2S(value2Ptr), iResult)); Tcl_SetLongObj(valuePtr, iResult); NEXT_INST_F(1, 1, 0); } } /* * --------------------------------------------------------- * Start of INST_LIST and related instructions. */ case INST_LIST: /* * Pop the opnd (objc) top stack elements into a new list obj * and then decrement their ref counts. */ opnd = TclGetUInt4AtPtr(pc+1); objResultPtr = Tcl_NewListObj(opnd, &(stackPtr[stackTop - (opnd-1)])); TRACE_WITH_OBJ(("%u => ", opnd), objResultPtr); NEXT_INST_V(5, opnd, 1); case INST_LIST_LENGTH: valuePtr = stackPtr[stackTop]; result = Tcl_ListObjLength(interp, valuePtr, &length); if (result != TCL_OK) { TRACE_WITH_OBJ(("%.30s => ERROR: ", O2S(valuePtr)), Tcl_GetObjResult(interp)); goto checkForCatch; } objResultPtr = Tcl_NewIntObj(length); TRACE(("%.20s => %d\n", O2S(valuePtr), length)); NEXT_INST_F(1, 1, 1); case INST_LIST_INDEX: /*** lindex with objc == 3 ***/ /* * Pop the two operands */ value2Ptr = stackPtr[stackTop]; valuePtr = stackPtr[stackTop- 1]; /* * Extract the desired list element */ objResultPtr = TclLindexList(interp, valuePtr, value2Ptr); if (objResultPtr == NULL) { TRACE_WITH_OBJ(("%.30s %.30s => ERROR: ", O2S(valuePtr), O2S(value2Ptr)), Tcl_GetObjResult(interp)); result = TCL_ERROR; goto checkForCatch; } /* * Stash the list element on the stack */ TRACE(("%.20s %.20s => %s\n", O2S(valuePtr), O2S(value2Ptr), O2S(objResultPtr))); NEXT_INST_F(1, 2, -1); /* already has the correct refCount */ case INST_LIST_INDEX_MULTI: { /* * 'lindex' with multiple index args: * * Determine the count of index args. */ int numIdx; opnd = TclGetUInt4AtPtr(pc+1); numIdx = opnd-1; /* * Do the 'lindex' operation. */ objResultPtr = TclLindexFlat(interp, stackPtr[stackTop - numIdx], numIdx, stackPtr + stackTop - numIdx + 1); /* * Check for errors */ if (objResultPtr == NULL) { TRACE_WITH_OBJ(("%d => ERROR: ", opnd), Tcl_GetObjResult(interp)); result = TCL_ERROR; goto checkForCatch; } /* * Set result */ TRACE(("%d => %s\n", opnd, O2S(objResultPtr))); NEXT_INST_V(5, opnd, -1); } case INST_LSET_FLAT: { /* * Lset with 3, 5, or more args. Get the number * of index args. */ int numIdx; opnd = TclGetUInt4AtPtr( pc + 1 ); numIdx = opnd - 2; /* * Get the old value of variable, and remove the stack ref. * This is safe because the variable still references the * object; the ref count will never go zero here. */ value2Ptr = POP_OBJECT(); TclDecrRefCount(value2Ptr); /* This one should be done here */ /* * Get the new element value. */ valuePtr = stackPtr[stackTop]; /* * Compute the new variable value */ objResultPtr = TclLsetFlat(interp, value2Ptr, numIdx, stackPtr + stackTop - numIdx, valuePtr); /* * Check for errors */ if (objResultPtr == NULL) { TRACE_WITH_OBJ(("%d => ERROR: ", opnd), Tcl_GetObjResult(interp)); result = TCL_ERROR; goto checkForCatch; } /* * Set result */ TRACE(("%d => %s\n", opnd, O2S(objResultPtr))); NEXT_INST_V(5, (numIdx+1), -1); } case INST_LSET_LIST: /* * 'lset' with 4 args. * * Get the old value of variable, and remove the stack ref. * This is safe because the variable still references the * object; the ref count will never go zero here. */ objPtr = POP_OBJECT(); TclDecrRefCount(objPtr); /* This one should be done here */ /* * Get the new element value, and the index list */ valuePtr = stackPtr[stackTop]; value2Ptr = stackPtr[stackTop - 1]; /* * Compute the new variable value */ objResultPtr = TclLsetList(interp, objPtr, value2Ptr, valuePtr); /* * Check for errors */ if (objResultPtr == NULL) { TRACE_WITH_OBJ(("\"%.30s\" => ERROR: ", O2S(value2Ptr)), Tcl_GetObjResult(interp)); result = TCL_ERROR; goto checkForCatch; } /* * Set result */ TRACE(("=> %s\n", O2S(objResultPtr))); NEXT_INST_F(1, 2, -1); /* * End of INST_LIST and related instructions. * --------------------------------------------------------- */ case INST_STR_EQ: case INST_STR_NEQ: { /* * String (in)equality check */ int iResult; value2Ptr = stackPtr[stackTop]; valuePtr = stackPtr[stackTop - 1]; if (valuePtr == value2Ptr) { /* * On the off-chance that the objects are the same, * we don't really have to think hard about equality. */ iResult = (*pc == INST_STR_EQ); } else { char *s1, *s2; int s1len, s2len; s1 = Tcl_GetStringFromObj(valuePtr, &s1len); s2 = Tcl_GetStringFromObj(value2Ptr, &s2len); if (s1len == s2len) { /* * We only need to check (in)equality when * we have equal length strings. */ if (*pc == INST_STR_NEQ) { iResult = (strcmp(s1, s2) != 0); } else { /* INST_STR_EQ */ iResult = (strcmp(s1, s2) == 0); } } else { iResult = (*pc == INST_STR_NEQ); } } TRACE(("%.20s %.20s => %d\n", O2S(valuePtr), O2S(value2Ptr), iResult)); /* * Peep-hole optimisation: if you're about to jump, do jump * from here. */ pc++; #ifndef TCL_COMPILE_DEBUG switch (*pc) { case INST_JUMP_FALSE1: NEXT_INST_F((iResult? 2 : TclGetInt1AtPtr(pc+1)), 2, 0); case INST_JUMP_TRUE1: NEXT_INST_F((iResult? TclGetInt1AtPtr(pc+1) : 2), 2, 0); case INST_JUMP_FALSE4: NEXT_INST_F((iResult? 5 : TclGetInt4AtPtr(pc+1)), 2, 0); case INST_JUMP_TRUE4: NEXT_INST_F((iResult? TclGetInt4AtPtr(pc+1) : 5), 2, 0); } #endif objResultPtr = Tcl_NewIntObj(iResult); NEXT_INST_F(0, 2, 1); } case INST_STR_CMP: { /* * String compare */ CONST char *s1, *s2; int s1len, s2len, iResult; value2Ptr = stackPtr[stackTop]; valuePtr = stackPtr[stackTop - 1]; /* * The comparison function should compare up to the * minimum byte length only. */ if (valuePtr == value2Ptr) { /* * In the pure equality case, set lengths too for * the checks below (or we could goto beyond it). */ iResult = s1len = s2len = 0; } else if ((valuePtr->typePtr == &tclByteArrayType) && (value2Ptr->typePtr == &tclByteArrayType)) { s1 = (char *) Tcl_GetByteArrayFromObj(valuePtr, &s1len); s2 = (char *) Tcl_GetByteArrayFromObj(value2Ptr, &s2len); iResult = memcmp(s1, s2, (size_t) ((s1len < s2len) ? s1len : s2len)); } else if (((valuePtr->typePtr == &tclStringType) && (value2Ptr->typePtr == &tclStringType))) { /* * Do a unicode-specific comparison if both of the args are of * String type. If the char length == byte length, we can do a * memcmp. In benchmark testing this proved the most efficient * check between the unicode and string comparison operations. */ s1len = Tcl_GetCharLength(valuePtr); s2len = Tcl_GetCharLength(value2Ptr); if ((s1len == valuePtr->length) && (s2len == value2Ptr->length)) { iResult = memcmp(valuePtr->bytes, value2Ptr->bytes, (unsigned) ((s1len < s2len) ? s1len : s2len)); } else { iResult = TclUniCharNcmp(Tcl_GetUnicode(valuePtr), Tcl_GetUnicode(value2Ptr), (unsigned) ((s1len < s2len) ? s1len : s2len)); } } else { /* * We can't do a simple memcmp in order to handle the * special Tcl \xC0\x80 null encoding for utf-8. */ s1 = Tcl_GetStringFromObj(valuePtr, &s1len); s2 = Tcl_GetStringFromObj(value2Ptr, &s2len); iResult = TclpUtfNcmp2(s1, s2, (size_t) ((s1len < s2len) ? s1len : s2len)); } /* * Make sure only -1,0,1 is returned */ if (iResult == 0) { iResult = s1len - s2len; } if (iResult < 0) { iResult = -1; } else if (iResult > 0) { iResult = 1; } objResultPtr = Tcl_NewIntObj(iResult); TRACE(("%.20s %.20s => %d\n", O2S(valuePtr), O2S(value2Ptr), iResult)); NEXT_INST_F(1, 2, 1); } case INST_STR_LEN: { int length1; valuePtr = stackPtr[stackTop]; if (valuePtr->typePtr == &tclByteArrayType) { (void) Tcl_GetByteArrayFromObj(valuePtr, &length1); } else { length1 = Tcl_GetCharLength(valuePtr); } objResultPtr = Tcl_NewIntObj(length1); TRACE(("%.20s => %d\n", O2S(valuePtr), length1)); NEXT_INST_F(1, 1, 1); } case INST_STR_INDEX: { /* * String compare */ int index; bytes = NULL; /* lint */ value2Ptr = stackPtr[stackTop]; valuePtr = stackPtr[stackTop - 1]; /* * If we have a ByteArray object, avoid indexing in the * Utf string since the byte array contains one byte per * character. Otherwise, use the Unicode string rep to * get the index'th char. */ if (valuePtr->typePtr == &tclByteArrayType) { bytes = (char *)Tcl_GetByteArrayFromObj(valuePtr, &length); } else { /* * Get Unicode char length to calulate what 'end' means. */ length = Tcl_GetCharLength(valuePtr); } result = TclGetIntForIndex(interp, value2Ptr, length - 1, &index); if (result != TCL_OK) { goto checkForCatch; } if ((index >= 0) && (index < length)) { if (valuePtr->typePtr == &tclByteArrayType) { objResultPtr = Tcl_NewByteArrayObj((unsigned char *) (&bytes[index]), 1); } else if (valuePtr->bytes && length == valuePtr->length) { objResultPtr = Tcl_NewStringObj((CONST char *) (&valuePtr->bytes[index]), 1); } else { char buf[TCL_UTF_MAX]; Tcl_UniChar ch; ch = Tcl_GetUniChar(valuePtr, index); /* * This could be: * Tcl_NewUnicodeObj((CONST Tcl_UniChar *)&ch, 1) * but creating the object as a string seems to be * faster in practical use. */ length = Tcl_UniCharToUtf(ch, buf); objResultPtr = Tcl_NewStringObj(buf, length); } } else { TclNewObj(objResultPtr); } TRACE(("%.20s %.20s => %s\n", O2S(valuePtr), O2S(value2Ptr), O2S(objResultPtr))); NEXT_INST_F(1, 2, 1); } case INST_STR_MATCH: { int nocase, match; nocase = TclGetInt1AtPtr(pc+1); valuePtr = stackPtr[stackTop]; /* String */ value2Ptr = stackPtr[stackTop - 1]; /* Pattern */ /* * Check that at least one of the objects is Unicode before * promoting both. */ if ((valuePtr->typePtr == &tclStringType) || (value2Ptr->typePtr == &tclStringType)) { Tcl_UniChar *ustring1, *ustring2; int length1, length2; ustring1 = Tcl_GetUnicodeFromObj(valuePtr, &length1); ustring2 = Tcl_GetUnicodeFromObj(value2Ptr, &length2); match = TclUniCharMatch(ustring1, length1, ustring2, length2, nocase); } else { match = Tcl_StringCaseMatch(TclGetString(valuePtr), TclGetString(value2Ptr), nocase); } /* * Reuse value2Ptr object already on stack if possible. * Adjustment is 2 due to the nocase byte */ TRACE(("%.20s %.20s => %d\n", O2S(valuePtr), O2S(value2Ptr), match)); if (Tcl_IsShared(value2Ptr)) { objResultPtr = Tcl_NewIntObj(match); NEXT_INST_F(2, 2, 1); } else { /* reuse the valuePtr object */ Tcl_SetIntObj(value2Ptr, match); NEXT_INST_F(2, 1, 0); } } case INST_EQ: case INST_NEQ: case INST_LT: case INST_GT: case INST_LE: case INST_GE: { /* * Any type is allowed but the two operands must have the * same type. We will compute value op value2. */ Tcl_ObjType *t1Ptr, *t2Ptr; char *s1 = NULL; /* Init. avoids compiler warning. */ char *s2 = NULL; /* Init. avoids compiler warning. */ long i2 = 0; /* Init. avoids compiler warning. */ double d1 = 0.0; /* Init. avoids compiler warning. */ double d2 = 0.0; /* Init. avoids compiler warning. */ long iResult = 0; /* Init. avoids compiler warning. */ value2Ptr = stackPtr[stackTop]; valuePtr = stackPtr[stackTop - 1]; /* * Be careful in the equal-object case; 'NaN' isn't supposed * to be equal to even itself. [Bug 761471] */ t1Ptr = valuePtr->typePtr; if (valuePtr == value2Ptr) { /* * If we are numeric already, we can proceed to the main * equality check right now. Otherwise, we need to try to * coerce to a numeric type so we can see if we've got a * NaN but haven't parsed it as numeric. */ if (!IS_NUMERIC_TYPE(t1Ptr)) { if (t1Ptr == &tclListType) { int length; /* * Only a list of length 1 can be NaN or such * things. */ (void) Tcl_ListObjLength(NULL, valuePtr, &length); if (length == 1) { goto mustConvertForNaNCheck; } } else { /* * Too bad, we'll have to compute the string and * try the conversion */ mustConvertForNaNCheck: s1 = Tcl_GetStringFromObj(valuePtr, &length); if (TclLooksLikeInt(s1, length)) { GET_WIDE_OR_INT(iResult, valuePtr, i, w); } else { (void) Tcl_GetDoubleFromObj((Tcl_Interp *) NULL, valuePtr, &d1); } t1Ptr = valuePtr->typePtr; } } switch (*pc) { case INST_EQ: case INST_LE: case INST_GE: iResult = !((t1Ptr == &tclDoubleType) && IS_NAN(valuePtr->internalRep.doubleValue)); break; case INST_LT: case INST_GT: iResult = 0; break; case INST_NEQ: iResult = ((t1Ptr == &tclDoubleType) && IS_NAN(valuePtr->internalRep.doubleValue)); break; } goto foundResult; } t2Ptr = value2Ptr->typePtr; /* * We only want to coerce numeric validation if neither type * is NULL. A NULL type means the arg is essentially an empty * object ("", {} or [list]). */ if (!( (!t1Ptr && !valuePtr->bytes) || (valuePtr->bytes && !valuePtr->length) || (!t2Ptr && !value2Ptr->bytes) || (value2Ptr->bytes && !value2Ptr->length))) { if (!IS_NUMERIC_TYPE(t1Ptr)) { s1 = Tcl_GetStringFromObj(valuePtr, &length); if (TclLooksLikeInt(s1, length)) { GET_WIDE_OR_INT(iResult, valuePtr, i, w); } else { (void) Tcl_GetDoubleFromObj((Tcl_Interp *) NULL, valuePtr, &d1); } t1Ptr = valuePtr->typePtr; } if (!IS_NUMERIC_TYPE(t2Ptr)) { s2 = Tcl_GetStringFromObj(value2Ptr, &length); if (TclLooksLikeInt(s2, length)) { GET_WIDE_OR_INT(iResult, value2Ptr, i2, w); } else { (void) Tcl_GetDoubleFromObj((Tcl_Interp *) NULL, value2Ptr, &d2); } t2Ptr = value2Ptr->typePtr; } } if (!IS_NUMERIC_TYPE(t1Ptr) || !IS_NUMERIC_TYPE(t2Ptr)) { /* * One operand is not numeric. Compare as strings. NOTE: * strcmp is not correct for \x00 < \x01, but that is * unlikely to occur here. We could use the TclUtfNCmp2 * to handle this. */ int s1len, s2len; s1 = Tcl_GetStringFromObj(valuePtr, &s1len); s2 = Tcl_GetStringFromObj(value2Ptr, &s2len); switch (*pc) { case INST_EQ: if (s1len == s2len) { iResult = (strcmp(s1, s2) == 0); } else { iResult = 0; } break; case INST_NEQ: if (s1len == s2len) { iResult = (strcmp(s1, s2) != 0); } else { iResult = 1; } break; case INST_LT: iResult = (strcmp(s1, s2) < 0); break; case INST_GT: iResult = (strcmp(s1, s2) > 0); break; case INST_LE: iResult = (strcmp(s1, s2) <= 0); break; case INST_GE: iResult = (strcmp(s1, s2) >= 0); break; } } else if ((t1Ptr == &tclDoubleType) || (t2Ptr == &tclDoubleType)) { /* * Compare as doubles. */ if (t1Ptr == &tclDoubleType) { d1 = valuePtr->internalRep.doubleValue; GET_DOUBLE_VALUE(d2, value2Ptr, t2Ptr); } else { /* t1Ptr is integer, t2Ptr is double */ GET_DOUBLE_VALUE(d1, valuePtr, t1Ptr); d2 = value2Ptr->internalRep.doubleValue; } switch (*pc) { case INST_EQ: iResult = d1 == d2; break; case INST_NEQ: iResult = d1 != d2; break; case INST_LT: iResult = d1 < d2; break; case INST_GT: iResult = d1 > d2; break; case INST_LE: iResult = d1 <= d2; break; case INST_GE: iResult = d1 >= d2; break; } } else if ((t1Ptr == &tclWideIntType) || (t2Ptr == &tclWideIntType)) { Tcl_WideInt w2; /* * Compare as wide ints (neither are doubles) */ if (t1Ptr == &tclIntType) { w = Tcl_LongAsWide(valuePtr->internalRep.longValue); TclGetWide(w2,value2Ptr); } else if (t2Ptr == &tclIntType) { TclGetWide(w,valuePtr); w2 = Tcl_LongAsWide(value2Ptr->internalRep.longValue); } else { TclGetWide(w,valuePtr); TclGetWide(w2,value2Ptr); } switch (*pc) { case INST_EQ: iResult = w == w2; break; case INST_NEQ: iResult = w != w2; break; case INST_LT: iResult = w < w2; break; case INST_GT: iResult = w > w2; break; case INST_LE: iResult = w <= w2; break; case INST_GE: iResult = w >= w2; break; } } else { /* * Compare as ints. */ i = valuePtr->internalRep.longValue; i2 = value2Ptr->internalRep.longValue; switch (*pc) { case INST_EQ: iResult = i == i2; break; case INST_NEQ: iResult = i != i2; break; case INST_LT: iResult = i < i2; break; case INST_GT: iResult = i > i2; break; case INST_LE: iResult = i <= i2; break; case INST_GE: iResult = i >= i2; break; } } foundResult: TRACE(("%.20s %.20s => %ld\n", O2S(valuePtr), O2S(value2Ptr), iResult)); /* * Peep-hole optimisation: if you're about to jump, do jump * from here. */ pc++; #ifndef TCL_COMPILE_DEBUG switch (*pc) { case INST_JUMP_FALSE1: NEXT_INST_F((iResult? 2 : TclGetInt1AtPtr(pc+1)), 2, 0); case INST_JUMP_TRUE1: NEXT_INST_F((iResult? TclGetInt1AtPtr(pc+1) : 2), 2, 0); case INST_JUMP_FALSE4: NEXT_INST_F((iResult? 5 : TclGetInt4AtPtr(pc+1)), 2, 0); case INST_JUMP_TRUE4: NEXT_INST_F((iResult? TclGetInt4AtPtr(pc+1) : 5), 2, 0); } #endif objResultPtr = Tcl_NewIntObj(iResult); NEXT_INST_F(0, 2, 1); } case INST_MOD: case INST_LSHIFT: case INST_RSHIFT: case INST_BITOR: case INST_BITXOR: case INST_BITAND: { /* * Only integers are allowed. We compute value op value2. */ long i2 = 0, rem, negative; long iResult = 0; /* Init. avoids compiler warning. */ Tcl_WideInt w2, wResult = W0; int doWide = 0; value2Ptr = stackPtr[stackTop]; valuePtr = stackPtr[stackTop - 1]; if (valuePtr->typePtr == &tclIntType) { i = valuePtr->internalRep.longValue; } else if (valuePtr->typePtr == &tclWideIntType) { TclGetWide(w,valuePtr); } else { /* try to convert to int */ REQUIRE_WIDE_OR_INT(result, valuePtr, i, w); if (result != TCL_OK) { TRACE(("%.20s %.20s => ILLEGAL 1st TYPE %s\n", O2S(valuePtr), O2S(value2Ptr), (valuePtr->typePtr? valuePtr->typePtr->name : "null"))); DECACHE_STACK_INFO(); IllegalExprOperandType(interp, pc, valuePtr); CACHE_STACK_INFO(); goto checkForCatch; } } if (value2Ptr->typePtr == &tclIntType) { i2 = value2Ptr->internalRep.longValue; } else if (value2Ptr->typePtr == &tclWideIntType) { TclGetWide(w2,value2Ptr); } else { REQUIRE_WIDE_OR_INT(result, value2Ptr, i2, w2); if (result != TCL_OK) { TRACE(("%.20s %.20s => ILLEGAL 2nd TYPE %s\n", O2S(valuePtr), O2S(value2Ptr), (value2Ptr->typePtr? value2Ptr->typePtr->name : "null"))); DECACHE_STACK_INFO(); IllegalExprOperandType(interp, pc, value2Ptr); CACHE_STACK_INFO(); goto checkForCatch; } } switch (*pc) { case INST_MOD: /* * This code is tricky: C doesn't guarantee much about * the quotient or remainder, but Tcl does. The * remainder always has the same sign as the divisor and * a smaller absolute value. */ if (value2Ptr->typePtr == &tclWideIntType && w2 == W0) { if (valuePtr->typePtr == &tclIntType) { TRACE(("%ld "LLD" => DIVIDE BY ZERO\n", i, w2)); } else { TRACE((LLD" "LLD" => DIVIDE BY ZERO\n", w, w2)); } goto divideByZero; } if (value2Ptr->typePtr == &tclIntType && i2 == 0) { if (valuePtr->typePtr == &tclIntType) { TRACE(("%ld %ld => DIVIDE BY ZERO\n", i, i2)); } else { TRACE((LLD" %ld => DIVIDE BY ZERO\n", w, i2)); } goto divideByZero; } negative = 0; if (valuePtr->typePtr == &tclWideIntType || value2Ptr->typePtr == &tclWideIntType) { Tcl_WideInt wRemainder; /* * Promote to wide */ if (valuePtr->typePtr == &tclIntType) { w = Tcl_LongAsWide(i); } else if (value2Ptr->typePtr == &tclIntType) { w2 = Tcl_LongAsWide(i2); } if (w2 < 0) { w2 = -w2; w = -w; negative = 1; } wRemainder = w % w2; if (wRemainder < 0) { wRemainder += w2; } if (negative) { wRemainder = -wRemainder; } wResult = wRemainder; doWide = 1; break; } if (i2 < 0) { i2 = -i2; i = -i; negative = 1; } rem = i % i2; if (rem < 0) { rem += i2; } if (negative) { rem = -rem; } iResult = rem; break; case INST_LSHIFT: /* * Shifts are never usefully 64-bits wide! */ FORCE_LONG(value2Ptr, i2, w2); if (valuePtr->typePtr == &tclWideIntType) { #ifdef TCL_COMPILE_DEBUG w2 = Tcl_LongAsWide(i2); #endif /* TCL_COMPILE_DEBUG */ wResult = w; /* * Shift in steps when the shift gets large to prevent * annoying compiler/processor bugs. [Bug 868467] */ if (i2 >= 64) { wResult = Tcl_LongAsWide(0); } else if (i2 > 60) { wResult = w << 30; wResult <<= 30; wResult <<= i2-60; } else if (i2 > 30) { wResult = w << 30; wResult <<= i2-30; } else { wResult = w << i2; } doWide = 1; break; } /* * Shift in steps when the shift gets large to prevent * annoying compiler/processor bugs. [Bug 868467] */ if (i2 >= 64) { iResult = 0; } else if (i2 > 60) { iResult = i << 30; iResult <<= 30; iResult <<= i2-60; } else if (i2 > 30) { iResult = i << 30; iResult <<= i2-30; } else { iResult = i << i2; } break; case INST_RSHIFT: /* * The following code is a bit tricky: it ensures that * right shifts propagate the sign bit even on machines * where ">>" won't do it by default. */ /* * Shifts are never usefully 64-bits wide! */ FORCE_LONG(value2Ptr, i2, w2); if (valuePtr->typePtr == &tclWideIntType) { #ifdef TCL_COMPILE_DEBUG w2 = Tcl_LongAsWide(i2); #endif /* TCL_COMPILE_DEBUG */ if (w < 0) { wResult = ~w; } else { wResult = w; } /* * Shift in steps when the shift gets large to prevent * annoying compiler/processor bugs. [Bug 868467] */ if (i2 >= 64) { wResult = Tcl_LongAsWide(0); } else if (i2 > 60) { wResult >>= 30; wResult >>= 30; wResult >>= i2-60; } else if (i2 > 30) { wResult >>= 30; wResult >>= i2-30; } else { wResult >>= i2; } if (w < 0) { wResult = ~wResult; } doWide = 1; break; } if (i < 0) { iResult = ~i; } else { iResult = i; } /* * Shift in steps when the shift gets large to prevent * annoying compiler/processor bugs. [Bug 868467] */ if (i2 >= 64) { iResult = 0; } else if (i2 > 60) { iResult >>= 30; iResult >>= 30; iResult >>= i2-60; } else if (i2 > 30) { iResult >>= 30; iResult >>= i2-30; } else { iResult >>= i2; } if (i < 0) { iResult = ~iResult; } break; case INST_BITOR: if (valuePtr->typePtr == &tclWideIntType || value2Ptr->typePtr == &tclWideIntType) { /* * Promote to wide */ if (valuePtr->typePtr == &tclIntType) { w = Tcl_LongAsWide(i); } else if (value2Ptr->typePtr == &tclIntType) { w2 = Tcl_LongAsWide(i2); } wResult = w | w2; doWide = 1; break; } iResult = i | i2; break; case INST_BITXOR: if (valuePtr->typePtr == &tclWideIntType || value2Ptr->typePtr == &tclWideIntType) { /* * Promote to wide */ if (valuePtr->typePtr == &tclIntType) { w = Tcl_LongAsWide(i); } else if (value2Ptr->typePtr == &tclIntType) { w2 = Tcl_LongAsWide(i2); } wResult = w ^ w2; doWide = 1; break; } iResult = i ^ i2; break; case INST_BITAND: if (valuePtr->typePtr == &tclWideIntType || value2Ptr->typePtr == &tclWideIntType) { /* * Promote to wide */ if (valuePtr->typePtr == &tclIntType) { w = Tcl_LongAsWide(i); } else if (value2Ptr->typePtr == &tclIntType) { w2 = Tcl_LongAsWide(i2); } wResult = w & w2; doWide = 1; break; } iResult = i & i2; break; } /* * Reuse the valuePtr object already on stack if possible. */ if (Tcl_IsShared(valuePtr)) { if (doWide) { objResultPtr = Tcl_NewWideIntObj(wResult); TRACE((LLD" "LLD" => "LLD"\n", w, w2, wResult)); } else { objResultPtr = Tcl_NewLongObj(iResult); TRACE(("%ld %ld => %ld\n", i, i2, iResult)); } NEXT_INST_F(1, 2, 1); } else { /* reuse the valuePtr object */ if (doWide) { TRACE((LLD" "LLD" => "LLD"\n", w, w2, wResult)); Tcl_SetWideIntObj(valuePtr, wResult); } else { TRACE(("%ld %ld => %ld\n", i, i2, iResult)); Tcl_SetLongObj(valuePtr, iResult); } NEXT_INST_F(1, 1, 0); } } case INST_ADD: case INST_SUB: case INST_MULT: case INST_DIV: { /* * Operands must be numeric and ints get converted to floats * if necessary. We compute value op value2. */ Tcl_ObjType *t1Ptr, *t2Ptr; long i2 = 0, quot, rem; /* Init. avoids compiler warning. */ double d1, d2; long iResult = 0; /* Init. avoids compiler warning. */ double dResult = 0.0; /* Init. avoids compiler warning. */ int doDouble = 0; /* 1 if doing floating arithmetic */ Tcl_WideInt w2, wquot, wrem; Tcl_WideInt wResult = W0; /* Init. avoids compiler warning. */ int doWide = 0; /* 1 if doing wide arithmetic. */ value2Ptr = stackPtr[stackTop]; valuePtr = stackPtr[stackTop - 1]; t1Ptr = valuePtr->typePtr; t2Ptr = value2Ptr->typePtr; if (t1Ptr == &tclIntType) { i = valuePtr->internalRep.longValue; } else if (t1Ptr == &tclWideIntType) { TclGetWide(w,valuePtr); } else if ((t1Ptr == &tclDoubleType) && (valuePtr->bytes == NULL)) { /* * We can only use the internal rep directly if there is * no string rep. Otherwise the string rep might actually * look like an integer, which is preferred. */ d1 = valuePtr->internalRep.doubleValue; } else { char *s = Tcl_GetStringFromObj(valuePtr, &length); if (TclLooksLikeInt(s, length)) { GET_WIDE_OR_INT(result, valuePtr, i, w); } else { result = Tcl_GetDoubleFromObj((Tcl_Interp *) NULL, valuePtr, &d1); } if (result != TCL_OK) { TRACE(("%.20s %.20s => ILLEGAL 1st TYPE %s\n", s, O2S(valuePtr), (valuePtr->typePtr? valuePtr->typePtr->name : "null"))); DECACHE_STACK_INFO(); IllegalExprOperandType(interp, pc, valuePtr); CACHE_STACK_INFO(); goto checkForCatch; } t1Ptr = valuePtr->typePtr; } if (t2Ptr == &tclIntType) { i2 = value2Ptr->internalRep.longValue; } else if (t2Ptr == &tclWideIntType) { TclGetWide(w2,value2Ptr); } else if ((t2Ptr == &tclDoubleType) && (value2Ptr->bytes == NULL)) { /* * We can only use the internal rep directly if there is * no string rep. Otherwise the string rep might actually * look like an integer, which is preferred. */ d2 = value2Ptr->internalRep.doubleValue; } else { char *s = Tcl_GetStringFromObj(value2Ptr, &length); if (TclLooksLikeInt(s, length)) { GET_WIDE_OR_INT(result, value2Ptr, i2, w2); } else { result = Tcl_GetDoubleFromObj((Tcl_Interp *) NULL, value2Ptr, &d2); } if (result != TCL_OK) { TRACE(("%.20s %.20s => ILLEGAL 2nd TYPE %s\n", O2S(value2Ptr), s, (value2Ptr->typePtr? value2Ptr->typePtr->name : "null"))); DECACHE_STACK_INFO(); IllegalExprOperandType(interp, pc, value2Ptr); CACHE_STACK_INFO(); goto checkForCatch; } t2Ptr = value2Ptr->typePtr; } if ((t1Ptr == &tclDoubleType) || (t2Ptr == &tclDoubleType)) { /* * Do double arithmetic. */ doDouble = 1; if (t1Ptr == &tclIntType) { d1 = i; /* promote value 1 to double */ } else if (t2Ptr == &tclIntType) { d2 = i2; /* promote value 2 to double */ } else if (t1Ptr == &tclWideIntType) { d1 = Tcl_WideAsDouble(w); } else if (t2Ptr == &tclWideIntType) { d2 = Tcl_WideAsDouble(w2); } switch (*pc) { case INST_ADD: dResult = d1 + d2; break; case INST_SUB: dResult = d1 - d2; break; case INST_MULT: dResult = d1 * d2; break; case INST_DIV: if (d2 == 0.0) { TRACE(("%.6g %.6g => DIVIDE BY ZERO\n", d1, d2)); goto divideByZero; } dResult = d1 / d2; break; } /* * Check now for IEEE floating-point error. */ if (IS_NAN(dResult) || IS_INF(dResult)) { TRACE(("%.20s %.20s => IEEE FLOATING PT ERROR\n", O2S(valuePtr), O2S(value2Ptr))); DECACHE_STACK_INFO(); TclExprFloatError(interp, dResult); CACHE_STACK_INFO(); result = TCL_ERROR; goto checkForCatch; } } else if ((t1Ptr == &tclWideIntType) || (t2Ptr == &tclWideIntType)) { /* * Do wide integer arithmetic. */ doWide = 1; if (t1Ptr == &tclIntType) { w = Tcl_LongAsWide(i); } else if (t2Ptr == &tclIntType) { w2 = Tcl_LongAsWide(i2); } switch (*pc) { case INST_ADD: wResult = w + w2; break; case INST_SUB: wResult = w - w2; break; case INST_MULT: wResult = w * w2; break; case INST_DIV: /* * This code is tricky: C doesn't guarantee much * about the quotient or remainder, but Tcl does. * The remainder always has the same sign as the * divisor and a smaller absolute value. */ if (w2 == W0) { TRACE((LLD" "LLD" => DIVIDE BY ZERO\n", w, w2)); goto divideByZero; } if (w2 < 0) { w2 = -w2; w = -w; } wquot = w / w2; wrem = w % w2; if (wrem < W0) { wquot -= 1; } wResult = wquot; break; } } else { /* * Do integer arithmetic. */ switch (*pc) { case INST_ADD: iResult = i + i2; break; case INST_SUB: iResult = i - i2; break; case INST_MULT: iResult = i * i2; break; case INST_DIV: /* * This code is tricky: C doesn't guarantee much * about the quotient or remainder, but Tcl does. * The remainder always has the same sign as the * divisor and a smaller absolute value. */ if (i2 == 0) { TRACE(("%ld %ld => DIVIDE BY ZERO\n", i, i2)); goto divideByZero; } if (i2 < 0) { i2 = -i2; i = -i; } quot = i / i2; rem = i % i2; if (rem < 0) { quot -= 1; } iResult = quot; break; } } /* * Reuse the valuePtr object already on stack if possible. */ if (Tcl_IsShared(valuePtr)) { if (doDouble) { objResultPtr = Tcl_NewDoubleObj(dResult); TRACE(("%.6g %.6g => %.6g\n", d1, d2, dResult)); } else if (doWide) { objResultPtr = Tcl_NewWideIntObj(wResult); TRACE((LLD" "LLD" => "LLD"\n", w, w2, wResult)); } else { objResultPtr = Tcl_NewLongObj(iResult); TRACE(("%ld %ld => %ld\n", i, i2, iResult)); } NEXT_INST_F(1, 2, 1); } else { /* reuse the valuePtr object */ if (doDouble) { /* NB: stack top is off by 1 */ TRACE(("%.6g %.6g => %.6g\n", d1, d2, dResult)); Tcl_SetDoubleObj(valuePtr, dResult); } else if (doWide) { TRACE((LLD" "LLD" => "LLD"\n", w, w2, wResult)); Tcl_SetWideIntObj(valuePtr, wResult); } else { TRACE(("%ld %ld => %ld\n", i, i2, iResult)); Tcl_SetLongObj(valuePtr, iResult); } NEXT_INST_F(1, 1, 0); } } case INST_UPLUS: { /* * Operand must be numeric. */ double d; Tcl_ObjType *tPtr; valuePtr = stackPtr[stackTop]; tPtr = valuePtr->typePtr; if (!IS_INTEGER_TYPE(tPtr) && ((tPtr != &tclDoubleType) || (valuePtr->bytes != NULL))) { char *s = Tcl_GetStringFromObj(valuePtr, &length); if (TclLooksLikeInt(s, length)) { GET_WIDE_OR_INT(result, valuePtr, i, w); } else { result = Tcl_GetDoubleFromObj((Tcl_Interp *) NULL, valuePtr, &d); } if (result != TCL_OK) { TRACE(("\"%.20s\" => ILLEGAL TYPE %s \n", s, (tPtr? tPtr->name : "null"))); DECACHE_STACK_INFO(); IllegalExprOperandType(interp, pc, valuePtr); CACHE_STACK_INFO(); goto checkForCatch; } tPtr = valuePtr->typePtr; } /* * Ensure that the operand's string rep is the same as the * formatted version of its internal rep. This makes sure * that "expr +000123" yields "83", not "000123". We * implement this by _discarding_ the string rep since we * know it will be regenerated, if needed later, by * formatting the internal rep's value. */ if (Tcl_IsShared(valuePtr)) { if (tPtr == &tclIntType) { i = valuePtr->internalRep.longValue; objResultPtr = Tcl_NewLongObj(i); } else if (tPtr == &tclWideIntType) { TclGetWide(w,valuePtr); objResultPtr = Tcl_NewWideIntObj(w); } else { d = valuePtr->internalRep.doubleValue; objResultPtr = Tcl_NewDoubleObj(d); } TRACE_WITH_OBJ(("%s => ", O2S(objResultPtr)), objResultPtr); NEXT_INST_F(1, 1, 1); } else { Tcl_InvalidateStringRep(valuePtr); TRACE_WITH_OBJ(("%s => ", O2S(valuePtr)), valuePtr); NEXT_INST_F(1, 0, 0); } } case INST_UMINUS: case INST_LNOT: { /* * The operand must be numeric or a boolean string as * accepted by Tcl_GetBooleanFromObj(). If the operand * object is unshared modify it directly, otherwise * create a copy to modify: this is "copy on write". * Free any old string representation since it is now * invalid. */ double d; int boolvar; Tcl_ObjType *tPtr; valuePtr = stackPtr[stackTop]; tPtr = valuePtr->typePtr; if (!IS_INTEGER_TYPE(tPtr) && ((tPtr != &tclDoubleType) || (valuePtr->bytes != NULL))) { if ((tPtr == &tclBooleanType) && (valuePtr->bytes == NULL)) { valuePtr->typePtr = &tclIntType; } else { char *s = Tcl_GetStringFromObj(valuePtr, &length); if (TclLooksLikeInt(s, length)) { GET_WIDE_OR_INT(result, valuePtr, i, w); } else { result = Tcl_GetDoubleFromObj((Tcl_Interp *) NULL, valuePtr, &d); } if (result == TCL_ERROR && *pc == INST_LNOT) { result = Tcl_GetBooleanFromObj((Tcl_Interp *)NULL, valuePtr, &boolvar); i = (long)boolvar; /* i is long, not int! */ } if (result != TCL_OK) { TRACE(("\"%.20s\" => ILLEGAL TYPE %s\n", s, (tPtr? tPtr->name : "null"))); DECACHE_STACK_INFO(); IllegalExprOperandType(interp, pc, valuePtr); CACHE_STACK_INFO(); goto checkForCatch; } } tPtr = valuePtr->typePtr; } if (Tcl_IsShared(valuePtr)) { /* * Create a new object. */ if ((tPtr == &tclIntType) || (tPtr == &tclBooleanType)) { i = valuePtr->internalRep.longValue; objResultPtr = Tcl_NewLongObj( (*pc == INST_UMINUS)? -i : !i); TRACE_WITH_OBJ(("%ld => ", i), objResultPtr); } else if (tPtr == &tclWideIntType) { TclGetWide(w,valuePtr); if (*pc == INST_UMINUS) { objResultPtr = Tcl_NewWideIntObj(-w); } else { objResultPtr = Tcl_NewLongObj(w == W0); } TRACE_WITH_OBJ((LLD" => ", w), objResultPtr); } else { d = valuePtr->internalRep.doubleValue; if (*pc == INST_UMINUS) { objResultPtr = Tcl_NewDoubleObj(-d); } else { /* * Should be able to use "!d", but apparently * some compilers can't handle it. */ objResultPtr = Tcl_NewLongObj((d==0.0)? 1 : 0); } TRACE_WITH_OBJ(("%.6g => ", d), objResultPtr); } NEXT_INST_F(1, 1, 1); } else { /* * valuePtr is unshared. Modify it directly. */ if ((tPtr == &tclIntType) || (tPtr == &tclBooleanType)) { i = valuePtr->internalRep.longValue; Tcl_SetLongObj(valuePtr, (*pc == INST_UMINUS)? -i : !i); TRACE_WITH_OBJ(("%ld => ", i), valuePtr); } else if (tPtr == &tclWideIntType) { TclGetWide(w,valuePtr); if (*pc == INST_UMINUS) { Tcl_SetWideIntObj(valuePtr, -w); } else { Tcl_SetLongObj(valuePtr, w == W0); } TRACE_WITH_OBJ((LLD" => ", w), valuePtr); } else { d = valuePtr->internalRep.doubleValue; if (*pc == INST_UMINUS) { Tcl_SetDoubleObj(valuePtr, -d); } else { /* * Should be able to use "!d", but apparently * some compilers can't handle it. */ Tcl_SetLongObj(valuePtr, (d==0.0)? 1 : 0); } TRACE_WITH_OBJ(("%.6g => ", d), valuePtr); } NEXT_INST_F(1, 0, 0); } } case INST_BITNOT: { /* * The operand must be an integer. If the operand object is * unshared modify it directly, otherwise modify a copy. * Free any old string representation since it is now * invalid. */ Tcl_ObjType *tPtr; valuePtr = stackPtr[stackTop]; tPtr = valuePtr->typePtr; if (!IS_INTEGER_TYPE(tPtr)) { REQUIRE_WIDE_OR_INT(result, valuePtr, i, w); if (result != TCL_OK) { /* try to convert to double */ TRACE(("\"%.20s\" => ILLEGAL TYPE %s\n", O2S(valuePtr), (tPtr? tPtr->name : "null"))); DECACHE_STACK_INFO(); IllegalExprOperandType(interp, pc, valuePtr); CACHE_STACK_INFO(); goto checkForCatch; } } if (valuePtr->typePtr == &tclWideIntType) { TclGetWide(w,valuePtr); if (Tcl_IsShared(valuePtr)) { objResultPtr = Tcl_NewWideIntObj(~w); TRACE(("0x%" TCL_LL_MODIFIER "x => (%" TCL_LL_MODIFIER "u)\n", w, ~w)); NEXT_INST_F(1, 1, 1); } else { /* * valuePtr is unshared. Modify it directly. */ Tcl_SetWideIntObj(valuePtr, ~w); TRACE(("0x%" TCL_LL_MODIFIER "x => (%" TCL_LL_MODIFIER "u)\n", w, ~w)); NEXT_INST_F(1, 0, 0); } } else { i = valuePtr->internalRep.longValue; if (Tcl_IsShared(valuePtr)) { objResultPtr = Tcl_NewLongObj(~i); TRACE(("0x%lx => (%lu)\n", i, ~i)); NEXT_INST_F(1, 1, 1); } else { /* * valuePtr is unshared. Modify it directly. */ Tcl_SetLongObj(valuePtr, ~i); TRACE(("0x%lx => (%lu)\n", i, ~i)); NEXT_INST_F(1, 0, 0); } } } case INST_CALL_BUILTIN_FUNC1: opnd = TclGetUInt1AtPtr(pc+1); { /* * Call one of the built-in Tcl math functions. */ BuiltinFunc *mathFuncPtr; if ((opnd < 0) || (opnd > LAST_BUILTIN_FUNC)) { TRACE(("UNRECOGNIZED BUILTIN FUNC CODE %d\n", opnd)); panic("TclExecuteByteCode: unrecognized builtin function code %d", opnd); } mathFuncPtr = &(tclBuiltinFuncTable[opnd]); DECACHE_STACK_INFO(); result = (*mathFuncPtr->proc)(interp, eePtr, mathFuncPtr->clientData); CACHE_STACK_INFO(); if (result != TCL_OK) { goto checkForCatch; } TRACE_WITH_OBJ(("%d => ", opnd), stackPtr[stackTop]); } NEXT_INST_F(2, 0, 0); case INST_CALL_FUNC1: opnd = TclGetUInt1AtPtr(pc+1); { /* * Call a non-builtin Tcl math function previously * registered by a call to Tcl_CreateMathFunc. */ int objc = opnd; /* Number of arguments. The function name * is the 0-th argument. */ Tcl_Obj **objv; /* The array of arguments. The function * name is objv[0]. */ objv = &(stackPtr[stackTop - (objc-1)]); /* "objv[0]" */ DECACHE_STACK_INFO(); result = ExprCallMathFunc(interp, eePtr, objc, objv); CACHE_STACK_INFO(); if (result != TCL_OK) { goto checkForCatch; } TRACE_WITH_OBJ(("%d => ", objc), stackPtr[stackTop]); } NEXT_INST_F(2, 0, 0); case INST_TRY_CVT_TO_NUMERIC: { /* * Try to convert the topmost stack object to an int or * double object. This is done in order to support Tcl's * policy of interpreting operands if at all possible as * first integers, else floating-point numbers. */ double d; char *s; Tcl_ObjType *tPtr; int converted, needNew; valuePtr = stackPtr[stackTop]; tPtr = valuePtr->typePtr; converted = 0; if (!IS_INTEGER_TYPE(tPtr) && ((tPtr != &tclDoubleType) || (valuePtr->bytes != NULL))) { if ((tPtr == &tclBooleanType) && (valuePtr->bytes == NULL)) { valuePtr->typePtr = &tclIntType; converted = 1; } else { s = Tcl_GetStringFromObj(valuePtr, &length); if (TclLooksLikeInt(s, length)) { GET_WIDE_OR_INT(result, valuePtr, i, w); } else { result = Tcl_GetDoubleFromObj((Tcl_Interp *) NULL, valuePtr, &d); } if (result == TCL_OK) { converted = 1; } result = TCL_OK; /* reset the result variable */ } tPtr = valuePtr->typePtr; } /* * Ensure that the topmost stack object, if numeric, has a * string rep the same as the formatted version of its * internal rep. This is used, e.g., to make sure that "expr * {0001}" yields "1", not "0001". We implement this by * _discarding_ the string rep since we know it will be * regenerated, if needed later, by formatting the internal * rep's value. Also check if there has been an IEEE * floating point error. */ objResultPtr = valuePtr; needNew = 0; if (IS_NUMERIC_TYPE(tPtr)) { if (Tcl_IsShared(valuePtr)) { if (valuePtr->bytes != NULL) { /* * We only need to make a copy of the object * when it already had a string rep */ needNew = 1; if (tPtr == &tclIntType) { i = valuePtr->internalRep.longValue; objResultPtr = Tcl_NewLongObj(i); } else if (tPtr == &tclWideIntType) { TclGetWide(w,valuePtr); objResultPtr = Tcl_NewWideIntObj(w); } else { d = valuePtr->internalRep.doubleValue; objResultPtr = Tcl_NewDoubleObj(d); } tPtr = objResultPtr->typePtr; } } else { Tcl_InvalidateStringRep(valuePtr); } if (tPtr == &tclDoubleType) { d = objResultPtr->internalRep.doubleValue; if (IS_NAN(d) || IS_INF(d)) { TRACE(("\"%.20s\" => IEEE FLOATING PT ERROR\n", O2S(objResultPtr))); DECACHE_STACK_INFO(); TclExprFloatError(interp, d); CACHE_STACK_INFO(); result = TCL_ERROR; goto checkForCatch; } } converted = converted; /* lint, converted not used. */ TRACE(("\"%.20s\" => numeric, %s, %s\n", O2S(valuePtr), (converted? "converted" : "not converted"), (needNew? "new Tcl_Obj" : "same Tcl_Obj"))); } else { TRACE(("\"%.20s\" => not numeric\n", O2S(valuePtr))); } if (needNew) { NEXT_INST_F(1, 1, 1); } else { NEXT_INST_F(1, 0, 0); } } case INST_BREAK: DECACHE_STACK_INFO(); Tcl_ResetResult(interp); CACHE_STACK_INFO(); result = TCL_BREAK; cleanup = 0; goto processExceptionReturn; case INST_CONTINUE: DECACHE_STACK_INFO(); Tcl_ResetResult(interp); CACHE_STACK_INFO(); result = TCL_CONTINUE; cleanup = 0; goto processExceptionReturn; case INST_FOREACH_START4: opnd = TclGetUInt4AtPtr(pc+1); { /* * Initialize the temporary local var that holds the count * of the number of iterations of the loop body to -1. */ ForeachInfo *infoPtr = (ForeachInfo *) codePtr->auxDataArrayPtr[opnd].clientData; int iterTmpIndex = infoPtr->loopCtTemp; Var *compiledLocals = iPtr->varFramePtr->compiledLocals; Var *iterVarPtr = &(compiledLocals[iterTmpIndex]); Tcl_Obj *oldValuePtr = iterVarPtr->value.objPtr; if (oldValuePtr == NULL) { iterVarPtr->value.objPtr = Tcl_NewLongObj(-1); Tcl_IncrRefCount(iterVarPtr->value.objPtr); } else { Tcl_SetLongObj(oldValuePtr, -1); } TclSetVarScalar(iterVarPtr); TclClearVarUndefined(iterVarPtr); TRACE(("%u => loop iter count temp %d\n", opnd, iterTmpIndex)); } #ifndef TCL_COMPILE_DEBUG /* * Remark that the compiler ALWAYS sets INST_FOREACH_STEP4 * immediately after INST_FOREACH_START4 - let us just fall * through instead of jumping back to the top. */ pc += 5; TCL_DTRACE_INST_NEXT(); #else NEXT_INST_F(5, 0, 0); #endif case INST_FOREACH_STEP4: opnd = TclGetUInt4AtPtr(pc+1); { /* * "Step" a foreach loop (i.e., begin its next iteration) by * assigning the next value list element to each loop var. */ ForeachInfo *infoPtr = (ForeachInfo *) codePtr->auxDataArrayPtr[opnd].clientData; ForeachVarList *varListPtr; int numLists = infoPtr->numLists; Var *compiledLocals = iPtr->varFramePtr->compiledLocals; Tcl_Obj *listPtr; Var *iterVarPtr, *listVarPtr; int iterNum, listTmpIndex, listLen, numVars; int varIndex, valIndex, continueLoop, j; /* * Increment the temp holding the loop iteration number. */ iterVarPtr = &(compiledLocals[infoPtr->loopCtTemp]); valuePtr = iterVarPtr->value.objPtr; iterNum = (valuePtr->internalRep.longValue + 1); Tcl_SetLongObj(valuePtr, iterNum); /* * Check whether all value lists are exhausted and we should * stop the loop. */ continueLoop = 0; listTmpIndex = infoPtr->firstValueTemp; for (i = 0; i < numLists; i++) { varListPtr = infoPtr->varLists[i]; numVars = varListPtr->numVars; listVarPtr = &(compiledLocals[listTmpIndex]); listPtr = listVarPtr->value.objPtr; result = Tcl_ListObjLength(interp, listPtr, &listLen); if (result != TCL_OK) { TRACE_WITH_OBJ(("%u => ERROR converting list %ld, \"%s\": ", opnd, i, O2S(listPtr)), Tcl_GetObjResult(interp)); goto checkForCatch; } if (listLen > (iterNum * numVars)) { continueLoop = 1; } listTmpIndex++; } /* * If some var in some var list still has a remaining list * element iterate one more time. Assign to var the next * element from its value list. We already checked above * that each list temp holds a valid list object. */ if (continueLoop) { listTmpIndex = infoPtr->firstValueTemp; for (i = 0; i < numLists; i++) { varListPtr = infoPtr->varLists[i]; numVars = varListPtr->numVars; listVarPtr = &(compiledLocals[listTmpIndex]); listPtr = listVarPtr->value.objPtr; valIndex = (iterNum * numVars); for (j = 0; j < numVars; j++) { Tcl_Obj **elements; /* * The call to TclPtrSetVar might shimmer listPtr, * so re-fetch pointers every iteration for safety. * See test foreach-10.1. */ Tcl_ListObjGetElements(NULL, listPtr, &listLen, &elements); if (valIndex >= listLen) { TclNewObj(valuePtr); } else { valuePtr = elements[valIndex]; } varIndex = varListPtr->varIndexes[j]; varPtr = &(varFramePtr->compiledLocals[varIndex]); part1 = varPtr->name; while (TclIsVarLink(varPtr)) { varPtr = varPtr->value.linkPtr; } if (!((varPtr->flags & VAR_IN_HASHTABLE) && (varPtr->hPtr == NULL)) && (varPtr->tracePtr == NULL) && (TclIsVarScalar(varPtr) || TclIsVarUndefined(varPtr))) { value2Ptr = varPtr->value.objPtr; if (valuePtr != value2Ptr) { if (value2Ptr != NULL) { TclDecrRefCount(value2Ptr); } else { TclSetVarScalar(varPtr); TclClearVarUndefined(varPtr); } varPtr->value.objPtr = valuePtr; Tcl_IncrRefCount(valuePtr); } } else { DECACHE_STACK_INFO(); Tcl_IncrRefCount(valuePtr); value2Ptr = TclPtrSetVar(interp, varPtr, NULL, part1, NULL, valuePtr, TCL_LEAVE_ERR_MSG); TclDecrRefCount(valuePtr); CACHE_STACK_INFO(); if (value2Ptr == NULL) { TRACE_WITH_OBJ(("%u => ERROR init. index temp %d: ", opnd, varIndex), Tcl_GetObjResult(interp)); result = TCL_ERROR; goto checkForCatch; } } valIndex++; } listTmpIndex++; } } TRACE(("%u => %d lists, iter %d, %s loop\n", opnd, numLists, iterNum, (continueLoop? "continue" : "exit"))); /* * Run-time peep-hole optimisation: the compiler ALWAYS follows * INST_FOREACH_STEP4 with an INST_JUMP_FALSE. We just skip that * instruction and jump direct from here. */ pc += 5; if (*pc == INST_JUMP_FALSE1) { NEXT_INST_F((continueLoop? 2 : TclGetInt1AtPtr(pc+1)), 0, 0); } else { NEXT_INST_F((continueLoop? 5 : TclGetInt4AtPtr(pc+1)), 0, 0); } } case INST_BEGIN_CATCH4: /* * Record start of the catch command with exception range index * equal to the operand. Push the current stack depth onto the * special catch stack. */ catchStackPtr[++catchTop] = stackTop; TRACE(("%u => catchTop=%d, stackTop=%d\n", TclGetUInt4AtPtr(pc+1), catchTop, stackTop)); NEXT_INST_F(5, 0, 0); case INST_END_CATCH: catchTop--; result = TCL_OK; TRACE(("=> catchTop=%d\n", catchTop)); NEXT_INST_F(1, 0, 0); case INST_PUSH_RESULT: objResultPtr = Tcl_GetObjResult(interp); TRACE_WITH_OBJ(("=> "), Tcl_GetObjResult(interp)); /* * See the comments at INST_INVOKE_STK */ { Tcl_Obj *newObjResultPtr; TclNewObj(newObjResultPtr); Tcl_IncrRefCount(newObjResultPtr); iPtr->objResultPtr = newObjResultPtr; } NEXT_INST_F(1, 0, -1); case INST_PUSH_RETURN_CODE: objResultPtr = Tcl_NewLongObj(result); TRACE(("=> %u\n", result)); NEXT_INST_F(1, 0, 1); default: panic("TclExecuteByteCode: unrecognized opCode %u", *pc); } /* end of switch on opCode */ /* * Division by zero in an expression. Control only reaches this * point by "goto divideByZero". */ divideByZero: DECACHE_STACK_INFO(); Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "divide by zero", -1); Tcl_SetErrorCode(interp, "ARITH", "DIVZERO", "divide by zero", (char *) NULL); CACHE_STACK_INFO(); result = TCL_ERROR; goto checkForCatch; /* * An external evaluation (INST_INVOKE or INST_EVAL) returned * something different from TCL_OK, or else INST_BREAK or * INST_CONTINUE were called. */ processExceptionReturn: #if TCL_COMPILE_DEBUG switch (*pc) { case INST_INVOKE_STK1: case INST_INVOKE_STK4: TRACE(("%u => ... after \"%.20s\": ", opnd, cmdNameBuf)); break; case INST_EVAL_STK: /* * Note that the object at stacktop has to be used * before doing the cleanup. */ TRACE(("\"%.30s\" => ", O2S(stackPtr[stackTop]))); break; default: TRACE(("=> ")); } #endif if ((result == TCL_CONTINUE) || (result == TCL_BREAK)) { rangePtr = GetExceptRangeForPc(pc, /*catchOnly*/ 0, codePtr); if (rangePtr == NULL) { TRACE_APPEND(("no encl. loop or catch, returning %s\n", StringForResultCode(result))); goto abnormalReturn; } if (rangePtr->type == CATCH_EXCEPTION_RANGE) { TRACE_APPEND(("%s ...\n", StringForResultCode(result))); goto processCatch; } while (cleanup--) { valuePtr = POP_OBJECT(); TclDecrRefCount(valuePtr); } if (result == TCL_BREAK) { result = TCL_OK; pc = (codePtr->codeStart + rangePtr->breakOffset); TRACE_APPEND(("%s, range at %d, new pc %d\n", StringForResultCode(result), rangePtr->codeOffset, rangePtr->breakOffset)); NEXT_INST_F(0, 0, 0); } else { if (rangePtr->continueOffset == -1) { TRACE_APPEND(("%s, loop w/o continue, checking for catch\n", StringForResultCode(result))); goto checkForCatch; } result = TCL_OK; pc = (codePtr->codeStart + rangePtr->continueOffset); TRACE_APPEND(("%s, range at %d, new pc %d\n", StringForResultCode(result), rangePtr->codeOffset, rangePtr->continueOffset)); NEXT_INST_F(0, 0, 0); } #if TCL_COMPILE_DEBUG } else if (traceInstructions) { if ((result != TCL_ERROR) && (result != TCL_RETURN)) { objPtr = Tcl_GetObjResult(interp); TRACE_APPEND(("OTHER RETURN CODE %d, result= \"%s\"\n ", result, O2S(objPtr))); } else { objPtr = Tcl_GetObjResult(interp); TRACE_APPEND(("%s, result= \"%s\"\n", StringForResultCode(result), O2S(objPtr))); } #endif } /* * Execution has generated an "exception" such as TCL_ERROR. If the * exception is an error, record information about what was being * executed when the error occurred. Find the closest enclosing * catch range, if any. If no enclosing catch range is found, stop * execution and return the "exception" code. */ checkForCatch: if ((result == TCL_ERROR) && !(iPtr->flags & ERR_ALREADY_LOGGED)) { bytes = GetSrcInfoForPc(pc, codePtr, &length); if (bytes != NULL) { DECACHE_STACK_INFO(); Tcl_LogCommandInfo(interp, codePtr->source, bytes, length); CACHE_STACK_INFO(); iPtr->flags |= ERR_ALREADY_LOGGED; } } if (catchTop == -1) { #ifdef TCL_COMPILE_DEBUG if (traceInstructions) { fprintf(stdout, " ... no enclosing catch, returning %s\n", StringForResultCode(result)); } #endif goto abnormalReturn; } rangePtr = GetExceptRangeForPc(pc, /*catchOnly*/ 1, codePtr); if (rangePtr == NULL) { /* * This is only possible when compiling a [catch] that sends its * script to INST_EVAL. Cannot correct the compiler without * breakingcompat with previous .tbc compiled scripts. */ #ifdef TCL_COMPILE_DEBUG if (traceInstructions) { fprintf(stdout, " ... no enclosing catch, returning %s\n", StringForResultCode(result)); } #endif goto abnormalReturn; } /* * A catch exception range (rangePtr) was found to handle an * "exception". It was found either by checkForCatch just above or * by an instruction during break, continue, or error processing. * Jump to its catchOffset after unwinding the operand stack to * the depth it had when starting to execute the range's catch * command. */ processCatch: while (stackTop > catchStackPtr[catchTop]) { valuePtr = POP_OBJECT(); TclDecrRefCount(valuePtr); } #ifdef TCL_COMPILE_DEBUG if (traceInstructions) { fprintf(stdout, " ... found catch at %d, catchTop=%d, unwound to %d, new pc %u\n", rangePtr->codeOffset, catchTop, catchStackPtr[catchTop], (unsigned int)(rangePtr->catchOffset)); } #endif pc = (codePtr->codeStart + rangePtr->catchOffset); NEXT_INST_F(0, 0, 0); /* restart the execution loop at pc */ /* * end of infinite loop dispatching on instructions. */ /* * Abnormal return code. Restore the stack to state it had when starting * to execute the ByteCode. Panic if the stack is below the initial level. */ abnormalReturn: TCL_DTRACE_INST_LAST(); while (stackTop > initStackTop) { valuePtr = POP_OBJECT(); TclDecrRefCount(valuePtr); } if (stackTop < initStackTop) { fprintf(stderr, "\nTclExecuteByteCode: abnormal return at pc %u: stack top %d < entry stack top %d\n", (unsigned int)(pc - codePtr->codeStart), (unsigned int) stackTop, (unsigned int) initStackTop); panic("TclExecuteByteCode execution failure: end stack top < start stack top"); } /* * Free the catch stack array if malloc'ed storage was used. */ if (catchStackPtr != catchStackStorage) { ckfree((char *) catchStackPtr); } eePtr->stackTop = initStackTop; return result; #undef STATIC_CATCH_STACK_SIZE } #ifdef TCL_COMPILE_DEBUG /* *---------------------------------------------------------------------- * * PrintByteCodeInfo -- * * This procedure prints a summary about a bytecode object to stdout. * It is called by TclExecuteByteCode when starting to execute the * bytecode object if tclTraceExec has the value 2 or more. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void PrintByteCodeInfo(codePtr) register ByteCode *codePtr; /* The bytecode whose summary is printed * to stdout. */ { Proc *procPtr = codePtr->procPtr; Interp *iPtr = (Interp *) *codePtr->interpHandle; fprintf(stdout, "\nExecuting ByteCode 0x%x, refCt %u, epoch %u, interp 0x%x (epoch %u)\n", (unsigned int) codePtr, codePtr->refCount, codePtr->compileEpoch, (unsigned int) iPtr, iPtr->compileEpoch); fprintf(stdout, " Source: "); TclPrintSource(stdout, codePtr->source, 60); fprintf(stdout, "\n Cmds %d, src %d, inst %u, litObjs %u, aux %d, stkDepth %u, code/src %.2f\n", codePtr->numCommands, codePtr->numSrcBytes, codePtr->numCodeBytes, codePtr->numLitObjects, codePtr->numAuxDataItems, codePtr->maxStackDepth, #ifdef TCL_COMPILE_STATS (codePtr->numSrcBytes? ((float)codePtr->structureSize)/((float)codePtr->numSrcBytes) : 0.0)); #else 0.0); #endif #ifdef TCL_COMPILE_STATS fprintf(stdout, " Code %u = header %u+inst %d+litObj %lu+exc %lu+aux %lu+cmdMap %d\n", (unsigned int)codePtr->structureSize, (unsigned int)(sizeof(ByteCode) - (sizeof(size_t) + sizeof(Tcl_Time))), codePtr->numCodeBytes, (unsigned long)(codePtr->numLitObjects * sizeof(Tcl_Obj *)), (unsigned long)(codePtr->numExceptRanges * sizeof(ExceptionRange)), (unsigned long)(codePtr->numAuxDataItems * sizeof(AuxData)), codePtr->numCmdLocBytes); #endif /* TCL_COMPILE_STATS */ if (procPtr != NULL) { fprintf(stdout, " Proc 0x%x, refCt %d, args %d, compiled locals %d\n", (unsigned int) procPtr, procPtr->refCount, procPtr->numArgs, procPtr->numCompiledLocals); } } #endif /* TCL_COMPILE_DEBUG */ /* *---------------------------------------------------------------------- * * ValidatePcAndStackTop -- * * This procedure is called by TclExecuteByteCode when debugging to * verify that the program counter and stack top are valid during * execution. * * Results: * None. * * Side effects: * Prints a message to stderr and panics if either the pc or stack * top are invalid. * *---------------------------------------------------------------------- */ #ifdef TCL_COMPILE_DEBUG static void ValidatePcAndStackTop(codePtr, pc, stackTop, stackLowerBound) register ByteCode *codePtr; /* The bytecode whose summary is printed * to stdout. */ unsigned char *pc; /* Points to first byte of a bytecode * instruction. The program counter. */ int stackTop; /* Current stack top. Must be between * stackLowerBound and stackUpperBound * (inclusive). */ int stackLowerBound; /* Smallest legal value for stackTop. */ { int stackUpperBound = stackLowerBound + codePtr->maxStackDepth; /* Greatest legal value for stackTop. */ unsigned int relativePc = (unsigned int) (pc - codePtr->codeStart); unsigned int codeStart = (unsigned int) codePtr->codeStart; unsigned int codeEnd = (unsigned int) (codePtr->codeStart + codePtr->numCodeBytes); unsigned char opCode = *pc; if (((unsigned int) pc < codeStart) || ((unsigned int) pc > codeEnd)) { fprintf(stderr, "\nBad instruction pc 0x%x in TclExecuteByteCode\n", (unsigned int) pc); panic("TclExecuteByteCode execution failure: bad pc"); } if ((unsigned int) opCode > LAST_INST_OPCODE) { fprintf(stderr, "\nBad opcode %d at pc %u in TclExecuteByteCode\n", (unsigned int) opCode, relativePc); panic("TclExecuteByteCode execution failure: bad opcode"); } if ((stackTop < stackLowerBound) || (stackTop > stackUpperBound)) { int numChars; char *cmd = GetSrcInfoForPc(pc, codePtr, &numChars); char *ellipsis = ""; fprintf(stderr, "\nBad stack top %d at pc %u in TclExecuteByteCode (min %i, max %i)", stackTop, relativePc, stackLowerBound, stackUpperBound); if (cmd != NULL) { if (numChars > 100) { numChars = 100; ellipsis = "..."; } fprintf(stderr, "\n executing %.*s%s\n", numChars, cmd, ellipsis); } else { fprintf(stderr, "\n"); } panic("TclExecuteByteCode execution failure: bad stack top"); } } #endif /* TCL_COMPILE_DEBUG */ /* *---------------------------------------------------------------------- * * IllegalExprOperandType -- * * Used by TclExecuteByteCode to add an error message to errorInfo * when an illegal operand type is detected by an expression * instruction. The argument opndPtr holds the operand object in error. * * Results: * None. * * Side effects: * An error message is appended to errorInfo. * *---------------------------------------------------------------------- */ static void IllegalExprOperandType(interp, pc, opndPtr) Tcl_Interp *interp; /* Interpreter to which error information * pertains. */ unsigned char *pc; /* Points to the instruction being executed * when the illegal type was found. */ Tcl_Obj *opndPtr; /* Points to the operand holding the value * with the illegal type. */ { unsigned char opCode = *pc; Tcl_ResetResult(interp); if ((opndPtr->bytes == NULL) || (opndPtr->length == 0)) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "can't use empty string as operand of \"", operatorStrings[opCode - INST_LOR], "\"", (char *) NULL); } else { char *msg = "non-numeric string"; char *s, *p; int length; int looksLikeInt = 0; s = Tcl_GetStringFromObj(opndPtr, &length); p = s; /* * strtod() isn't at all consistent about detecting Inf and * NaN between platforms. */ if (length == 3) { if ((s[0]=='n' || s[0]=='N') && (s[1]=='a' || s[1]=='A') && (s[2]=='n' || s[2]=='N')) { msg = "non-numeric floating-point value"; goto makeErrorMessage; } if ((s[0]=='i' || s[0]=='I') && (s[1]=='n' || s[1]=='N') && (s[2]=='f' || s[2]=='F')) { msg = "infinite floating-point value"; goto makeErrorMessage; } } /* * We cannot use TclLooksLikeInt here because it passes strings * like "10;" [Bug 587140]. We'll accept as "looking like ints" * for the present purposes any string that looks formally like * a (decimal|octal|hex) integer. */ while (length && isspace(UCHAR(*p))) { length--; p++; } if (length && ((*p == '+') || (*p == '-'))) { length--; p++; } if (length) { if ((*p == '0') && ((*(p+1) == 'x') || (*(p+1) == 'X'))) { p += 2; length -= 2; looksLikeInt = ((length > 0) && isxdigit(UCHAR(*p))); if (looksLikeInt) { length--; p++; while (length && isxdigit(UCHAR(*p))) { length--; p++; } } } else { looksLikeInt = (length && isdigit(UCHAR(*p))); if (looksLikeInt) { length--; p++; while (length && isdigit(UCHAR(*p))) { length--; p++; } } } while (length && isspace(UCHAR(*p))) { length--; p++; } looksLikeInt = !length; } if (looksLikeInt) { /* * If something that looks like an integer could not be * converted, then it *must* be a bad octal or too large * to represent [Bug 542588]. */ if (TclCheckBadOctal(NULL, s)) { msg = "invalid octal number"; } else { msg = "integer value too large to represent"; Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW", "integer value too large to represent", (char *) NULL); } } else { /* * See if the operand can be interpreted as a double in * order to improve the error message. */ double d; if (Tcl_GetDouble((Tcl_Interp *) NULL, s, &d) == TCL_OK) { msg = "floating-point value"; } } makeErrorMessage: Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "can't use ", msg, " as operand of \"", operatorStrings[opCode - INST_LOR], "\"", (char *) NULL); } } /* *---------------------------------------------------------------------- * * TclGetSrcInfoForPc, GetSrcInfoForPc -- * * Given a program counter value, finds the closest command in the * bytecode code unit's CmdLocation array and returns information about * that command's source: a pointer to its first byte and the number of * characters. * * Results: * If a command is found that encloses the program counter value, a * pointer to the command's source is returned and the length of the * source is stored at *lengthPtr. If multiple commands resulted in * code at pc, information about the closest enclosing command is * returned. If no matching command is found, NULL is returned and * *lengthPtr is unchanged. * * Side effects: * None. * *---------------------------------------------------------------------- */ #ifdef TCL_TIP280 void TclGetSrcInfoForPc (cfPtr) CmdFrame* cfPtr; { ByteCode* codePtr = (ByteCode*) cfPtr->data.tebc.codePtr; if (cfPtr->cmd.str.cmd == NULL) { cfPtr->cmd.str.cmd = GetSrcInfoForPc((unsigned char*) cfPtr->data.tebc.pc, codePtr, &cfPtr->cmd.str.len); } if (cfPtr->cmd.str.cmd != NULL) { /* We now have the command. We can get the srcOffset back and * from there find the list of word locations for this command */ ExtCmdLoc* eclPtr; ECL* locPtr = NULL; int srcOffset; Interp* iPtr = (Interp*) *codePtr->interpHandle; Tcl_HashEntry* hePtr = Tcl_FindHashEntry (iPtr->lineBCPtr, (char *) codePtr); if (!hePtr) return; srcOffset = cfPtr->cmd.str.cmd - codePtr->source; eclPtr = (ExtCmdLoc*) Tcl_GetHashValue (hePtr); { int i; for (i=0; i < eclPtr->nuloc; i++) { if (eclPtr->loc [i].srcOffset == srcOffset) { locPtr = &(eclPtr->loc [i]); break; } } } if (locPtr == NULL) {Tcl_Panic ("LocSearch failure");} cfPtr->line = locPtr->line; cfPtr->nline = locPtr->nline; cfPtr->type = eclPtr->type; if (eclPtr->type == TCL_LOCATION_SOURCE) { cfPtr->data.eval.path = eclPtr->path; Tcl_IncrRefCount (cfPtr->data.eval.path); } /* Do not set cfPtr->data.eval.path NULL for non-SOURCE * Needed for cfPtr->data.tebc.codePtr. */ } } #endif static char * GetSrcInfoForPc(pc, codePtr, lengthPtr) unsigned char *pc; /* The program counter value for which to * return the closest command's source info. * This points to a bytecode instruction * in codePtr's code. */ ByteCode *codePtr; /* The bytecode sequence in which to look * up the command source for the pc. */ int *lengthPtr; /* If non-NULL, the location where the * length of the command's source should be * stored. If NULL, no length is stored. */ { register int pcOffset = (pc - codePtr->codeStart); int numCmds = codePtr->numCommands; unsigned char *codeDeltaNext, *codeLengthNext; unsigned char *srcDeltaNext, *srcLengthNext; int codeOffset, codeLen, codeEnd, srcOffset, srcLen, delta, i; int bestDist = INT_MAX; /* Distance of pc to best cmd's start pc. */ int bestSrcOffset = -1; /* Initialized to avoid compiler warning. */ int bestSrcLength = -1; /* Initialized to avoid compiler warning. */ if ((pcOffset < 0) || (pcOffset >= codePtr->numCodeBytes)) { return NULL; } /* * Decode the code and source offset and length for each command. The * closest enclosing command is the last one whose code started before * pcOffset. */ codeDeltaNext = codePtr->codeDeltaStart; codeLengthNext = codePtr->codeLengthStart; srcDeltaNext = codePtr->srcDeltaStart; srcLengthNext = codePtr->srcLengthStart; codeOffset = srcOffset = 0; for (i = 0; i < numCmds; i++) { if ((unsigned int) (*codeDeltaNext) == (unsigned int) 0xFF) { codeDeltaNext++; delta = TclGetInt4AtPtr(codeDeltaNext); codeDeltaNext += 4; } else { delta = TclGetInt1AtPtr(codeDeltaNext); codeDeltaNext++; } codeOffset += delta; if ((unsigned int) (*codeLengthNext) == (unsigned int) 0xFF) { codeLengthNext++; codeLen = TclGetInt4AtPtr(codeLengthNext); codeLengthNext += 4; } else { codeLen = TclGetInt1AtPtr(codeLengthNext); codeLengthNext++; } codeEnd = (codeOffset + codeLen - 1); if ((unsigned int) (*srcDeltaNext) == (unsigned int) 0xFF) { srcDeltaNext++; delta = TclGetInt4AtPtr(srcDeltaNext); srcDeltaNext += 4; } else { delta = TclGetInt1AtPtr(srcDeltaNext); srcDeltaNext++; } srcOffset += delta; if ((unsigned int) (*srcLengthNext) == (unsigned int) 0xFF) { srcLengthNext++; srcLen = TclGetInt4AtPtr(srcLengthNext); srcLengthNext += 4; } else { srcLen = TclGetInt1AtPtr(srcLengthNext); srcLengthNext++; } if (codeOffset > pcOffset) { /* best cmd already found */ break; } else if (pcOffset <= codeEnd) { /* this cmd's code encloses pc */ int dist = (pcOffset - codeOffset); if (dist <= bestDist) { bestDist = dist; bestSrcOffset = srcOffset; bestSrcLength = srcLen; } } } if (bestDist == INT_MAX) { return NULL; } if (lengthPtr != NULL) { *lengthPtr = bestSrcLength; } return (codePtr->source + bestSrcOffset); } /* *---------------------------------------------------------------------- * * GetExceptRangeForPc -- * * Given a program counter value, return the closest enclosing * ExceptionRange. * * Results: * In the normal case, catchOnly is 0 (false) and this procedure * returns a pointer to the most closely enclosing ExceptionRange * structure regardless of whether it is a loop or catch exception * range. This is appropriate when processing a TCL_BREAK or * TCL_CONTINUE, which will be "handled" either by a loop exception * range or a closer catch range. If catchOnly is nonzero, this * procedure ignores loop exception ranges and returns a pointer to the * closest catch range. If no matching ExceptionRange is found that * encloses pc, a NULL is returned. * * Side effects: * None. * *---------------------------------------------------------------------- */ static ExceptionRange * GetExceptRangeForPc(pc, catchOnly, codePtr) unsigned char *pc; /* The program counter value for which to * search for a closest enclosing exception * range. This points to a bytecode * instruction in codePtr's code. */ int catchOnly; /* If 0, consider either loop or catch * ExceptionRanges in search. If nonzero * consider only catch ranges (and ignore * any closer loop ranges). */ ByteCode* codePtr; /* Points to the ByteCode in which to search * for the enclosing ExceptionRange. */ { ExceptionRange *rangeArrayPtr; int numRanges = codePtr->numExceptRanges; register ExceptionRange *rangePtr; int pcOffset = (pc - codePtr->codeStart); register int start; if (numRanges == 0) { return NULL; } /* * This exploits peculiarities of our compiler: nested ranges * are always *after* their containing ranges, so that by scanning * backwards we are sure that the first matching range is indeed * the deepest. */ rangeArrayPtr = codePtr->exceptArrayPtr; rangePtr = rangeArrayPtr + numRanges; while (--rangePtr >= rangeArrayPtr) { start = rangePtr->codeOffset; if ((start <= pcOffset) && (pcOffset < (start + rangePtr->numCodeBytes))) { if ((!catchOnly) || (rangePtr->type == CATCH_EXCEPTION_RANGE)) { return rangePtr; } } } return NULL; } /* *---------------------------------------------------------------------- * * GetOpcodeName -- * * This procedure is called by the TRACE and TRACE_WITH_OBJ macros * used in TclExecuteByteCode when debugging. It returns the name of * the bytecode instruction at a specified instruction pc. * * Results: * A character string for the instruction. * * Side effects: * None. * *---------------------------------------------------------------------- */ #ifdef TCL_COMPILE_DEBUG static char * GetOpcodeName(pc) unsigned char *pc; /* Points to the instruction whose name * should be returned. */ { unsigned char opCode = *pc; return tclInstructionTable[opCode].name; } #endif /* TCL_COMPILE_DEBUG */ /* *---------------------------------------------------------------------- * * VerifyExprObjType -- * * This procedure is called by the math functions to verify that * the object is either an int or double, coercing it if necessary. * If an error occurs during conversion, an error message is left * in the interpreter's result unless "interp" is NULL. * * Results: * TCL_OK if it was int or double, TCL_ERROR otherwise * * Side effects: * objPtr is ensured to be of tclIntType, tclWideIntType or * tclDoubleType. * *---------------------------------------------------------------------- */ static int VerifyExprObjType(interp, objPtr) Tcl_Interp *interp; /* The interpreter in which to execute the * function. */ Tcl_Obj *objPtr; /* Points to the object to type check. */ { if (IS_NUMERIC_TYPE(objPtr->typePtr)) { return TCL_OK; } else { int length, result = TCL_OK; char *s = Tcl_GetStringFromObj(objPtr, &length); if (TclLooksLikeInt(s, length)) { long i; Tcl_WideInt w; GET_WIDE_OR_INT(result, objPtr, i, w); /* Quiet cranky old compilers that complain about * setting i, but not using it. */ (void)i; } else { double d; result = Tcl_GetDoubleFromObj((Tcl_Interp *) NULL, objPtr, &d); } if ((result != TCL_OK) && (interp != NULL)) { Tcl_ResetResult(interp); if (TclCheckBadOctal((Tcl_Interp *) NULL, s)) { Tcl_AppendToObj(Tcl_GetObjResult(interp), "argument to math function was an invalid octal number", -1); } else { Tcl_AppendToObj(Tcl_GetObjResult(interp), "argument to math function didn't have numeric value", -1); } } return result; } } /* *---------------------------------------------------------------------- * * Math Functions -- * * This page contains the procedures that implement all of the * built-in math functions for expressions. * * Results: * Each procedure returns TCL_OK if it succeeds and pushes an * Tcl object holding the result. If it fails it returns TCL_ERROR * and leaves an error message in the interpreter's result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int ExprUnaryFunc(interp, eePtr, clientData) Tcl_Interp *interp; /* The interpreter in which to execute the * function. */ ExecEnv *eePtr; /* Points to the environment for executing * the function. */ ClientData clientData; /* Contains the address of a procedure that * takes one double argument and returns a * double result. */ { Tcl_Obj **stackPtr; /* Cached evaluation stack base pointer. */ register int stackTop; /* Cached top index of evaluation stack. */ register Tcl_Obj *valuePtr; double d, dResult; int result; double (*func) _ANSI_ARGS_((double)) = (double (*)_ANSI_ARGS_((double))) clientData; /* * Set stackPtr and stackTop from eePtr. */ result = TCL_OK; CACHE_STACK_INFO(); /* * Pop the function's argument from the evaluation stack. Convert it * to a double if necessary. */ valuePtr = POP_OBJECT(); if (VerifyExprObjType(interp, valuePtr) != TCL_OK) { result = TCL_ERROR; goto done; } GET_DOUBLE_VALUE(d, valuePtr, valuePtr->typePtr); errno = 0; dResult = (*func)(d); if ((errno != 0) || IS_NAN(dResult) || IS_INF(dResult)) { TclExprFloatError(interp, dResult); result = TCL_ERROR; goto done; } /* * Push a Tcl object holding the result. */ PUSH_OBJECT(Tcl_NewDoubleObj(dResult)); /* * Reflect the change to stackTop back in eePtr. */ done: TclDecrRefCount(valuePtr); DECACHE_STACK_INFO(); return result; } static int ExprBinaryFunc(interp, eePtr, clientData) Tcl_Interp *interp; /* The interpreter in which to execute the * function. */ ExecEnv *eePtr; /* Points to the environment for executing * the function. */ ClientData clientData; /* Contains the address of a procedure that * takes two double arguments and * returns a double result. */ { Tcl_Obj **stackPtr; /* Cached evaluation stack base pointer. */ register int stackTop; /* Cached top index of evaluation stack. */ register Tcl_Obj *valuePtr, *value2Ptr; double d1, d2, dResult; int result; double (*func) _ANSI_ARGS_((double, double)) = (double (*)_ANSI_ARGS_((double, double))) clientData; /* * Set stackPtr and stackTop from eePtr. */ result = TCL_OK; CACHE_STACK_INFO(); /* * Pop the function's two arguments from the evaluation stack. Convert * them to doubles if necessary. */ value2Ptr = POP_OBJECT(); valuePtr = POP_OBJECT(); if ((VerifyExprObjType(interp, valuePtr) != TCL_OK) || (VerifyExprObjType(interp, value2Ptr) != TCL_OK)) { result = TCL_ERROR; goto done; } GET_DOUBLE_VALUE(d1, valuePtr, valuePtr->typePtr); GET_DOUBLE_VALUE(d2, value2Ptr, value2Ptr->typePtr); errno = 0; dResult = (*func)(d1, d2); if ((errno != 0) || IS_NAN(dResult) || IS_INF(dResult)) { TclExprFloatError(interp, dResult); result = TCL_ERROR; goto done; } /* * Push a Tcl object holding the result. */ PUSH_OBJECT(Tcl_NewDoubleObj(dResult)); /* * Reflect the change to stackTop back in eePtr. */ done: TclDecrRefCount(valuePtr); TclDecrRefCount(value2Ptr); DECACHE_STACK_INFO(); return result; } static int ExprAbsFunc(interp, eePtr, clientData) Tcl_Interp *interp; /* The interpreter in which to execute the * function. */ ExecEnv *eePtr; /* Points to the environment for executing * the function. */ ClientData clientData; /* Ignored. */ { Tcl_Obj **stackPtr; /* Cached evaluation stack base pointer. */ register int stackTop; /* Cached top index of evaluation stack. */ register Tcl_Obj *valuePtr; long i, iResult; double d, dResult; int result; /* * Set stackPtr and stackTop from eePtr. */ result = TCL_OK; CACHE_STACK_INFO(); /* * Pop the argument from the evaluation stack. */ valuePtr = POP_OBJECT(); if (VerifyExprObjType(interp, valuePtr) != TCL_OK) { result = TCL_ERROR; goto done; } /* * Push a Tcl object with the result. */ if (valuePtr->typePtr == &tclIntType) { i = valuePtr->internalRep.longValue; if (i < 0) { if (i == LONG_MIN) { #ifdef TCL_WIDE_INT_IS_LONG Tcl_SetObjResult(interp, Tcl_NewStringObj( "integer value too large to represent", -1)); Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW", "integer value too large to represent", (char *) NULL); result = TCL_ERROR; goto done; #else /* * Special case: abs(MIN_INT) must promote to wide. */ PUSH_OBJECT( Tcl_NewWideIntObj(-(Tcl_WideInt) i) ); result = TCL_OK; goto done; #endif } iResult = -i; } else { iResult = i; } PUSH_OBJECT(Tcl_NewLongObj(iResult)); } else if (valuePtr->typePtr == &tclWideIntType) { Tcl_WideInt wResult, w; TclGetWide(w,valuePtr); if (w < W0) { wResult = -w; if (wResult < 0) { Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "integer value too large to represent", -1); Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW", "integer value too large to represent", (char *) NULL); result = TCL_ERROR; goto done; } } else { wResult = w; } PUSH_OBJECT(Tcl_NewWideIntObj(wResult)); } else { d = valuePtr->internalRep.doubleValue; if (d < 0.0) { dResult = -d; } else if (d == -0.0) { /* We need to distinguish here between positive 0.0 and * negative -0.0, see Bug ID #2954959. */ static const double poszero = 0.0; if (memcmp(&d, &poszero, sizeof(double))) { dResult = -d; } else { dResult = d; } } else { dResult = d; } if (IS_NAN(dResult) || IS_INF(dResult)) { TclExprFloatError(interp, dResult); result = TCL_ERROR; goto done; } PUSH_OBJECT(Tcl_NewDoubleObj(dResult)); } /* * Reflect the change to stackTop back in eePtr. */ done: TclDecrRefCount(valuePtr); DECACHE_STACK_INFO(); return result; } static int ExprDoubleFunc(interp, eePtr, clientData) Tcl_Interp *interp; /* The interpreter in which to execute the * function. */ ExecEnv *eePtr; /* Points to the environment for executing * the function. */ ClientData clientData; /* Ignored. */ { Tcl_Obj **stackPtr; /* Cached evaluation stack base pointer. */ register int stackTop; /* Cached top index of evaluation stack. */ register Tcl_Obj *valuePtr; double dResult; int result; /* * Set stackPtr and stackTop from eePtr. */ result = TCL_OK; CACHE_STACK_INFO(); /* * Pop the argument from the evaluation stack. */ valuePtr = POP_OBJECT(); if (VerifyExprObjType(interp, valuePtr) != TCL_OK) { result = TCL_ERROR; goto done; } GET_DOUBLE_VALUE(dResult, valuePtr, valuePtr->typePtr); /* * Push a Tcl object with the result. */ PUSH_OBJECT(Tcl_NewDoubleObj(dResult)); /* * Reflect the change to stackTop back in eePtr. */ done: TclDecrRefCount(valuePtr); DECACHE_STACK_INFO(); return result; } static int ExprIntFunc(interp, eePtr, clientData) Tcl_Interp *interp; /* The interpreter in which to execute the * function. */ ExecEnv *eePtr; /* Points to the environment for executing * the function. */ ClientData clientData; /* Ignored. */ { Tcl_Obj **stackPtr; /* Cached evaluation stack base pointer. */ register int stackTop; /* Cached top index of evaluation stack. */ register Tcl_Obj *valuePtr; long iResult; double d; int result; /* * Set stackPtr and stackTop from eePtr. */ result = TCL_OK; CACHE_STACK_INFO(); /* * Pop the argument from the evaluation stack. */ valuePtr = POP_OBJECT(); if (VerifyExprObjType(interp, valuePtr) != TCL_OK) { result = TCL_ERROR; goto done; } if (valuePtr->typePtr == &tclIntType) { iResult = valuePtr->internalRep.longValue; } else if (valuePtr->typePtr == &tclWideIntType) { TclGetLongFromWide(iResult,valuePtr); } else { d = valuePtr->internalRep.doubleValue; if (d < 0.0) { if (d < (double) (long) LONG_MIN) { tooLarge: Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "integer value too large to represent", -1); Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW", "integer value too large to represent", (char *) NULL); result = TCL_ERROR; goto done; } } else { if (d > (double) LONG_MAX) { goto tooLarge; } } if (IS_NAN(d) || IS_INF(d)) { TclExprFloatError(interp, d); result = TCL_ERROR; goto done; } iResult = (long) d; } /* * Push a Tcl object with the result. */ PUSH_OBJECT(Tcl_NewLongObj(iResult)); /* * Reflect the change to stackTop back in eePtr. */ done: TclDecrRefCount(valuePtr); DECACHE_STACK_INFO(); return result; } static int ExprWideFunc(interp, eePtr, clientData) Tcl_Interp *interp; /* The interpreter in which to execute the * function. */ ExecEnv *eePtr; /* Points to the environment for executing * the function. */ ClientData clientData; /* Ignored. */ { Tcl_Obj **stackPtr; /* Cached evaluation stack base pointer. */ register int stackTop; /* Cached top index of evaluation stack. */ register Tcl_Obj *valuePtr; Tcl_WideInt wResult; double d; int result; /* * Set stackPtr and stackTop from eePtr. */ result = TCL_OK; CACHE_STACK_INFO(); /* * Pop the argument from the evaluation stack. */ valuePtr = POP_OBJECT(); if (VerifyExprObjType(interp, valuePtr) != TCL_OK) { result = TCL_ERROR; goto done; } if (valuePtr->typePtr == &tclWideIntType) { TclGetWide(wResult,valuePtr); } else if (valuePtr->typePtr == &tclIntType) { wResult = Tcl_LongAsWide(valuePtr->internalRep.longValue); } else { d = valuePtr->internalRep.doubleValue; if (d < 0.0) { if (d < Tcl_WideAsDouble(LLONG_MIN)) { tooLarge: Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "integer value too large to represent", -1); Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW", "integer value too large to represent", (char *) NULL); result = TCL_ERROR; goto done; } } else { if (d > Tcl_WideAsDouble(LLONG_MAX)) { goto tooLarge; } } if (IS_NAN(d) || IS_INF(d)) { TclExprFloatError(interp, d); result = TCL_ERROR; goto done; } wResult = Tcl_DoubleAsWide(d); } /* * Push a Tcl object with the result. */ PUSH_OBJECT(Tcl_NewWideIntObj(wResult)); /* * Reflect the change to stackTop back in eePtr. */ done: TclDecrRefCount(valuePtr); DECACHE_STACK_INFO(); return result; } static int ExprRandFunc(interp, eePtr, clientData) Tcl_Interp *interp; /* The interpreter in which to execute the * function. */ ExecEnv *eePtr; /* Points to the environment for executing * the function. */ ClientData clientData; /* Ignored. */ { Tcl_Obj **stackPtr; /* Cached evaluation stack base pointer. */ register int stackTop; /* Cached top index of evaluation stack. */ Interp *iPtr = (Interp *) interp; double dResult; long tmp; /* Algorithm assumes at least 32 bits. * Only long guarantees that. See below. */ if (!(iPtr->flags & RAND_SEED_INITIALIZED)) { iPtr->flags |= RAND_SEED_INITIALIZED; /* * Take into consideration the thread this interp is running in order * to insure different seeds in different threads (bug #416643) */ iPtr->randSeed = TclpGetClicks() + ((long)Tcl_GetCurrentThread()<<12); /* * Make sure 1 <= randSeed <= (2^31) - 2. See below. */ iPtr->randSeed &= (unsigned long) 0x7fffffff; if ((iPtr->randSeed == 0) || (iPtr->randSeed == 0x7fffffff)) { iPtr->randSeed ^= 123459876; } } /* * Set stackPtr and stackTop from eePtr. */ CACHE_STACK_INFO(); /* * Generate the random number using the linear congruential * generator defined by the following recurrence: * seed = ( IA * seed ) mod IM * where IA is 16807 and IM is (2^31) - 1. The recurrence maps * a seed in the range [1, IM - 1] to a new seed in that same range. * The recurrence maps IM to 0, and maps 0 back to 0, so those two * values must not be allowed as initial values of seed. * * In order to avoid potential problems with integer overflow, the * recurrence is implemented in terms of additional constants * IQ and IR such that * IM = IA*IQ + IR * None of the operations in the implementation overflows a 32-bit * signed integer, and the C type long is guaranteed to be at least * 32 bits wide. * * For more details on how this algorithm works, refer to the following * papers: * * S.K. Park & K.W. Miller, "Random number generators: good ones * are hard to find," Comm ACM 31(10):1192-1201, Oct 1988 * * W.H. Press & S.A. Teukolsky, "Portable random number * generators," Computers in Physics 6(5):522-524, Sep/Oct 1992. */ #define RAND_IA 16807 #define RAND_IM 2147483647 #define RAND_IQ 127773 #define RAND_IR 2836 #define RAND_MASK 123459876 tmp = iPtr->randSeed/RAND_IQ; iPtr->randSeed = RAND_IA*(iPtr->randSeed - tmp*RAND_IQ) - RAND_IR*tmp; if (iPtr->randSeed < 0) { iPtr->randSeed += RAND_IM; } /* * Since the recurrence keeps seed values in the range [1, RAND_IM - 1], * dividing by RAND_IM yields a double in the range (0, 1). */ dResult = iPtr->randSeed * (1.0/RAND_IM); /* * Push a Tcl object with the result. */ PUSH_OBJECT(Tcl_NewDoubleObj(dResult)); /* * Reflect the change to stackTop back in eePtr. */ DECACHE_STACK_INFO(); return TCL_OK; } static int ExprRoundFunc(interp, eePtr, clientData) Tcl_Interp *interp; /* The interpreter in which to execute the * function. */ ExecEnv *eePtr; /* Points to the environment for executing * the function. */ ClientData clientData; /* Ignored. */ { Tcl_Obj **stackPtr; /* Cached evaluation stack base pointer. */ register int stackTop; /* Cached top index of evaluation stack. */ Tcl_Obj *valuePtr, *resPtr; double d, f, i; int result; /* * Set stackPtr and stackTop from eePtr. */ result = TCL_OK; CACHE_STACK_INFO(); /* * Pop the argument from the evaluation stack. */ valuePtr = POP_OBJECT(); if (VerifyExprObjType(interp, valuePtr) != TCL_OK) { result = TCL_ERROR; goto done; } if ((valuePtr->typePtr == &tclIntType) || (valuePtr->typePtr == &tclWideIntType)) { result = TCL_OK; resPtr = valuePtr; } else { /* * Round the number to the nearest integer. I'd like to use round(), * but it's C99 (or BSD), and not yet universal. */ d = valuePtr->internalRep.doubleValue; f = modf(d, &i); if (d < 0.0) { if (f <= -0.5) { i += -1.0; } if (i <= Tcl_WideAsDouble(LLONG_MIN)) { goto tooLarge; } else if (i <= (double) LONG_MIN) { resPtr = Tcl_NewWideIntObj(Tcl_DoubleAsWide(i)); } else { resPtr = Tcl_NewLongObj((long) i); } } else { if (f >= 0.5) { i += 1.0; } if (i >= Tcl_WideAsDouble(LLONG_MAX)) { goto tooLarge; } else if (i >= (double) LONG_MAX) { resPtr = Tcl_NewWideIntObj(Tcl_DoubleAsWide(i)); } else { resPtr = Tcl_NewLongObj((long) i); } } } /* * Push the result object and free the argument Tcl_Obj. */ PUSH_OBJECT(resPtr); done: TclDecrRefCount(valuePtr); DECACHE_STACK_INFO(); return result; /* * Error return: result cannot be represented as an integer. */ tooLarge: Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "integer value too large to represent", -1); Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW", "integer value too large to represent", (char *) NULL); result = TCL_ERROR; goto done; } static int ExprSrandFunc(interp, eePtr, clientData) Tcl_Interp *interp; /* The interpreter in which to execute the * function. */ ExecEnv *eePtr; /* Points to the environment for executing * the function. */ ClientData clientData; /* Ignored. */ { Tcl_Obj **stackPtr; /* Cached evaluation stack base pointer. */ register int stackTop; /* Cached top index of evaluation stack. */ Interp *iPtr = (Interp *) interp; Tcl_Obj *valuePtr; long i = 0; /* Initialized to avoid compiler warning. */ /* * Set stackPtr and stackTop from eePtr. */ CACHE_STACK_INFO(); /* * Pop the argument from the evaluation stack. Use the value * to reset the random number seed. */ valuePtr = POP_OBJECT(); if (VerifyExprObjType(interp, valuePtr) != TCL_OK) { goto badValue; } if (Tcl_GetLongFromObj(NULL, valuePtr, &i) != TCL_OK) { Tcl_WideInt w; if (Tcl_GetWideIntFromObj(interp, valuePtr, &w) != TCL_OK) { badValue: Tcl_AddErrorInfo(interp, "\n (argument to \"srand()\")"); TclDecrRefCount(valuePtr); DECACHE_STACK_INFO(); return TCL_ERROR; } i = Tcl_WideAsLong(w); } /* * Reset the seed. Make sure 1 <= randSeed <= 2^31 - 2. * See comments in ExprRandFunc() for more details. */ iPtr->flags |= RAND_SEED_INITIALIZED; iPtr->randSeed = i; iPtr->randSeed &= (unsigned long) 0x7fffffff; if ((iPtr->randSeed == 0) || (iPtr->randSeed == 0x7fffffff)) { iPtr->randSeed ^= 123459876; } /* * To avoid duplicating the random number generation code we simply * clean up our state and call the real random number function. That * function will always succeed. */ TclDecrRefCount(valuePtr); DECACHE_STACK_INFO(); ExprRandFunc(interp, eePtr, clientData); return TCL_OK; } /* *---------------------------------------------------------------------- * * ExprCallMathFunc -- * * This procedure is invoked to call a non-builtin math function * during the execution of an expression. * * Results: * TCL_OK is returned if all went well and the function's value * was computed successfully. If an error occurred, TCL_ERROR * is returned and an error message is left in the interpreter's * result. After a successful return this procedure pushes a Tcl object * holding the result. * * Side effects: * None, unless the called math function has side effects. * *---------------------------------------------------------------------- */ static int ExprCallMathFunc(interp, eePtr, objc, objv) Tcl_Interp *interp; /* The interpreter in which to execute the * function. */ ExecEnv *eePtr; /* Points to the environment for executing * the function. */ int objc; /* Number of arguments. The function name is * the 0-th argument. */ Tcl_Obj **objv; /* The array of arguments. The function name * is objv[0]. */ { Interp *iPtr = (Interp *) interp; Tcl_Obj **stackPtr; /* Cached evaluation stack base pointer. */ register int stackTop; /* Cached top index of evaluation stack. */ char *funcName; Tcl_HashEntry *hPtr; MathFunc *mathFuncPtr; /* Information about math function. */ Tcl_Value args[MAX_MATH_ARGS]; /* Arguments for function call. */ Tcl_Value funcResult; /* Result of function call as Tcl_Value. */ register Tcl_Obj *valuePtr; long i; double d; int j, k, result; Tcl_ResetResult(interp); /* * Set stackPtr and stackTop from eePtr. */ CACHE_STACK_INFO(); /* * Look up the MathFunc record for the function. */ funcName = TclGetString(objv[0]); hPtr = Tcl_FindHashEntry(&iPtr->mathFuncTable, funcName); if (hPtr == NULL) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "unknown math function \"", funcName, "\"", (char *) NULL); result = TCL_ERROR; goto done; } mathFuncPtr = (MathFunc *) Tcl_GetHashValue(hPtr); if (mathFuncPtr->numArgs != (objc-1)) { panic("ExprCallMathFunc: expected number of args %d != actual number %d", mathFuncPtr->numArgs, objc); result = TCL_ERROR; goto done; } /* * Collect the arguments for the function, if there are any, into the * array "args". Note that args[0] will have the Tcl_Value that * corresponds to objv[1]. */ for (j = 1, k = 0; j < objc; j++, k++) { valuePtr = objv[j]; if (VerifyExprObjType(interp, valuePtr) != TCL_OK) { result = TCL_ERROR; goto done; } /* * Copy the object's numeric value to the argument record, * converting it if necessary. */ if (valuePtr->typePtr == &tclIntType) { i = valuePtr->internalRep.longValue; if (mathFuncPtr->argTypes[k] == TCL_DOUBLE) { args[k].type = TCL_DOUBLE; args[k].doubleValue = i; } else if (mathFuncPtr->argTypes[k] == TCL_WIDE_INT) { args[k].type = TCL_WIDE_INT; args[k].wideValue = Tcl_LongAsWide(i); } else { args[k].type = TCL_INT; args[k].intValue = i; } } else if (valuePtr->typePtr == &tclWideIntType) { Tcl_WideInt w; TclGetWide(w,valuePtr); if (mathFuncPtr->argTypes[k] == TCL_DOUBLE) { args[k].type = TCL_DOUBLE; args[k].doubleValue = Tcl_WideAsDouble(w); } else if (mathFuncPtr->argTypes[k] == TCL_INT) { args[k].type = TCL_INT; args[k].intValue = Tcl_WideAsLong(w); } else { args[k].type = TCL_WIDE_INT; args[k].wideValue = w; } } else { d = valuePtr->internalRep.doubleValue; if (mathFuncPtr->argTypes[k] == TCL_INT) { args[k].type = TCL_INT; args[k].intValue = (long) d; } else if (mathFuncPtr->argTypes[k] == TCL_WIDE_INT) { args[k].type = TCL_WIDE_INT; args[k].wideValue = Tcl_DoubleAsWide(d); } else { args[k].type = TCL_DOUBLE; args[k].doubleValue = d; } } } /* * Invoke the function and copy its result back into valuePtr. */ result = (*mathFuncPtr->proc)(mathFuncPtr->clientData, interp, args, &funcResult); if (result != TCL_OK) { goto done; } /* * Pop the objc top stack elements and decrement their ref counts. */ k = (stackTop - (objc-1)); while (stackTop >= k) { valuePtr = POP_OBJECT(); TclDecrRefCount(valuePtr); } /* * Push the call's object result. */ if (funcResult.type == TCL_INT) { PUSH_OBJECT(Tcl_NewLongObj(funcResult.intValue)); } else if (funcResult.type == TCL_WIDE_INT) { PUSH_OBJECT(Tcl_NewWideIntObj(funcResult.wideValue)); } else { d = funcResult.doubleValue; if (IS_NAN(d) || IS_INF(d)) { TclExprFloatError(interp, d); result = TCL_ERROR; goto done; } PUSH_OBJECT(Tcl_NewDoubleObj(d)); } /* * Reflect the change to stackTop back in eePtr. */ done: DECACHE_STACK_INFO(); return result; } /* *---------------------------------------------------------------------- * * TclExprFloatError -- * * This procedure is called when an error occurs during a * floating-point operation. It reads errno and sets * interp->objResultPtr accordingly. * * Results: * interp->objResultPtr is set to hold an error message. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TclExprFloatError(interp, value) Tcl_Interp *interp; /* Where to store error message. */ double value; /* Value returned after error; used to * distinguish underflows from overflows. */ { char *s; Tcl_ResetResult(interp); if ((errno == EDOM) || IS_NAN(value)) { s = "domain error: argument not in valid range"; Tcl_AppendToObj(Tcl_GetObjResult(interp), s, -1); Tcl_SetErrorCode(interp, "ARITH", "DOMAIN", s, (char *) NULL); } else if ((errno == ERANGE) || IS_INF(value)) { if (value == 0.0) { s = "floating-point value too small to represent"; Tcl_AppendToObj(Tcl_GetObjResult(interp), s, -1); Tcl_SetErrorCode(interp, "ARITH", "UNDERFLOW", s, (char *) NULL); } else { s = "floating-point value too large to represent"; Tcl_AppendToObj(Tcl_GetObjResult(interp), s, -1); Tcl_SetErrorCode(interp, "ARITH", "OVERFLOW", s, (char *) NULL); } } else { char msg[64 + TCL_INTEGER_SPACE]; sprintf(msg, "unknown floating-point error, errno = %d", errno); Tcl_AppendToObj(Tcl_GetObjResult(interp), msg, -1); Tcl_SetErrorCode(interp, "ARITH", "UNKNOWN", msg, (char *) NULL); } } #ifdef TCL_COMPILE_STATS /* *---------------------------------------------------------------------- * * TclLog2 -- * * Procedure used while collecting compilation statistics to determine * the log base 2 of an integer. * * Results: * Returns the log base 2 of the operand. If the argument is less * than or equal to zero, a zero is returned. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclLog2(value) register int value; /* The integer for which to compute the * log base 2. */ { register int n = value; register int result = 0; while (n > 1) { n = n >> 1; result++; } return result; } /* *---------------------------------------------------------------------- * * EvalStatsCmd -- * * Implements the "evalstats" command that prints instruction execution * counts to stdout. * * Results: * Standard Tcl results. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int EvalStatsCmd(unused, interp, objc, objv) ClientData unused; /* Unused. */ Tcl_Interp *interp; /* The current interpreter. */ int objc; /* The number of arguments. */ Tcl_Obj *CONST objv[]; /* The argument strings. */ { Interp *iPtr = (Interp *) interp; LiteralTable *globalTablePtr = &(iPtr->literalTable); ByteCodeStats *statsPtr = &(iPtr->stats); double totalCodeBytes, currentCodeBytes; double totalLiteralBytes, currentLiteralBytes; double objBytesIfUnshared, strBytesIfUnshared, sharingBytesSaved; double strBytesSharedMultX, strBytesSharedOnce; double numInstructions, currentHeaderBytes; long numCurrentByteCodes, numByteCodeLits; long refCountSum, literalMgmtBytes, sum; int numSharedMultX, numSharedOnce; int decadeHigh, minSizeDecade, maxSizeDecade, length, i; char *litTableStats; LiteralEntry *entryPtr; numInstructions = 0.0; for (i = 0; i < 256; i++) { if (statsPtr->instructionCount[i] != 0) { numInstructions += statsPtr->instructionCount[i]; } } totalLiteralBytes = sizeof(LiteralTable) + iPtr->literalTable.numBuckets * sizeof(LiteralEntry *) + (statsPtr->numLiteralsCreated * sizeof(LiteralEntry)) + (statsPtr->numLiteralsCreated * sizeof(Tcl_Obj)) + statsPtr->totalLitStringBytes; totalCodeBytes = statsPtr->totalByteCodeBytes + totalLiteralBytes; numCurrentByteCodes = statsPtr->numCompilations - statsPtr->numByteCodesFreed; currentHeaderBytes = numCurrentByteCodes * (sizeof(ByteCode) - (sizeof(size_t) + sizeof(Tcl_Time))); literalMgmtBytes = sizeof(LiteralTable) + (iPtr->literalTable.numBuckets * sizeof(LiteralEntry *)) + (iPtr->literalTable.numEntries * sizeof(LiteralEntry)); currentLiteralBytes = literalMgmtBytes + iPtr->literalTable.numEntries * sizeof(Tcl_Obj) + statsPtr->currentLitStringBytes; currentCodeBytes = statsPtr->currentByteCodeBytes + currentLiteralBytes; /* * Summary statistics, total and current source and ByteCode sizes. */ fprintf(stdout, "\n----------------------------------------------------------------\n"); fprintf(stdout, "Compilation and execution statistics for interpreter 0x%x\n", (unsigned int) iPtr); fprintf(stdout, "\nNumber ByteCodes executed %ld\n", statsPtr->numExecutions); fprintf(stdout, "Number ByteCodes compiled %ld\n", statsPtr->numCompilations); fprintf(stdout, " Mean executions/compile %.1f\n", ((float)statsPtr->numExecutions) / ((float)statsPtr->numCompilations)); fprintf(stdout, "\nInstructions executed %.0f\n", numInstructions); fprintf(stdout, " Mean inst/compile %.0f\n", numInstructions / statsPtr->numCompilations); fprintf(stdout, " Mean inst/execution %.0f\n", numInstructions / statsPtr->numExecutions); fprintf(stdout, "\nTotal ByteCodes %ld\n", statsPtr->numCompilations); fprintf(stdout, " Source bytes %.6g\n", statsPtr->totalSrcBytes); fprintf(stdout, " Code bytes %.6g\n", totalCodeBytes); fprintf(stdout, " ByteCode bytes %.6g\n", statsPtr->totalByteCodeBytes); fprintf(stdout, " Literal bytes %.6g\n", totalLiteralBytes); fprintf(stdout, " table %u + bkts %lu + entries %lu + objects %lu + strings %.6g\n", (unsigned int)sizeof(LiteralTable), (unsigned long)iPtr->literalTable.numBuckets * sizeof(LiteralEntry *), (unsigned long)statsPtr->numLiteralsCreated * sizeof(LiteralEntry), (unsigned long)statsPtr->numLiteralsCreated * sizeof(Tcl_Obj), statsPtr->totalLitStringBytes); fprintf(stdout, " Mean code/compile %.1f\n", totalCodeBytes / statsPtr->numCompilations); fprintf(stdout, " Mean code/source %.1f\n", totalCodeBytes / statsPtr->totalSrcBytes); fprintf(stdout, "\nCurrent (active) ByteCodes %ld\n", numCurrentByteCodes); fprintf(stdout, " Source bytes %.6g\n", statsPtr->currentSrcBytes); fprintf(stdout, " Code bytes %.6g\n", currentCodeBytes); fprintf(stdout, " ByteCode bytes %.6g\n", statsPtr->currentByteCodeBytes); fprintf(stdout, " Literal bytes %.6g\n", currentLiteralBytes); fprintf(stdout, " table %u + bkts %lu + entries %lu + objects %lu + strings %.6g\n", (unsigned int)sizeof(LiteralTable), (unsigned long)iPtr->literalTable.numBuckets * sizeof(LiteralEntry *), (unsigned long)iPtr->literalTable.numEntries * sizeof(LiteralEntry), (unsigned long)iPtr->literalTable.numEntries * sizeof(Tcl_Obj), statsPtr->currentLitStringBytes); fprintf(stdout, " Mean code/source %.1f\n", currentCodeBytes / statsPtr->currentSrcBytes); fprintf(stdout, " Code + source bytes %.6g (%0.1f mean code/src)\n", (currentCodeBytes + statsPtr->currentSrcBytes), (currentCodeBytes / statsPtr->currentSrcBytes) + 1.0); /* * Tcl_IsShared statistics check * * This gives the refcount of each obj as Tcl_IsShared was called * for it. Shared objects must be duplicated before they can be * modified. */ numSharedMultX = 0; fprintf(stdout, "\nTcl_IsShared object check (all objects):\n"); fprintf(stdout, " Object had refcount <=1 (not shared) %ld\n", tclObjsShared[1]); for (i = 2; i < TCL_MAX_SHARED_OBJ_STATS; i++) { fprintf(stdout, " refcount ==%d %ld\n", i, tclObjsShared[i]); numSharedMultX += tclObjsShared[i]; } fprintf(stdout, " refcount >=%d %ld\n", i, tclObjsShared[0]); numSharedMultX += tclObjsShared[0]; fprintf(stdout, " Total shared objects %d\n", numSharedMultX); /* * Literal table statistics. */ numByteCodeLits = 0; refCountSum = 0; numSharedMultX = 0; numSharedOnce = 0; objBytesIfUnshared = 0.0; strBytesIfUnshared = 0.0; strBytesSharedMultX = 0.0; strBytesSharedOnce = 0.0; for (i = 0; i < globalTablePtr->numBuckets; i++) { for (entryPtr = globalTablePtr->buckets[i]; entryPtr != NULL; entryPtr = entryPtr->nextPtr) { if (entryPtr->objPtr->typePtr == &tclByteCodeType) { numByteCodeLits++; } (void) Tcl_GetStringFromObj(entryPtr->objPtr, &length); refCountSum += entryPtr->refCount; objBytesIfUnshared += (entryPtr->refCount * sizeof(Tcl_Obj)); strBytesIfUnshared += (entryPtr->refCount * (length+1)); if (entryPtr->refCount > 1) { numSharedMultX++; strBytesSharedMultX += (length+1); } else { numSharedOnce++; strBytesSharedOnce += (length+1); } } } sharingBytesSaved = (objBytesIfUnshared + strBytesIfUnshared) - currentLiteralBytes; fprintf(stdout, "\nTotal objects (all interps) %ld\n", tclObjsAlloced); fprintf(stdout, "Current objects %ld\n", (tclObjsAlloced - tclObjsFreed)); fprintf(stdout, "Total literal objects %ld\n", statsPtr->numLiteralsCreated); fprintf(stdout, "\nCurrent literal objects %d (%0.1f%% of current objects)\n", globalTablePtr->numEntries, (globalTablePtr->numEntries * 100.0) / (tclObjsAlloced-tclObjsFreed)); fprintf(stdout, " ByteCode literals %ld (%0.1f%% of current literals)\n", numByteCodeLits, (numByteCodeLits * 100.0) / globalTablePtr->numEntries); fprintf(stdout, " Literals reused > 1x %d\n", numSharedMultX); fprintf(stdout, " Mean reference count %.2f\n", ((double) refCountSum) / globalTablePtr->numEntries); fprintf(stdout, " Mean len, str reused >1x %.2f\n", (numSharedMultX? (strBytesSharedMultX/numSharedMultX) : 0.0)); fprintf(stdout, " Mean len, str used 1x %.2f\n", (numSharedOnce? (strBytesSharedOnce/numSharedOnce) : 0.0)); fprintf(stdout, " Total sharing savings %.6g (%0.1f%% of bytes if no sharing)\n", sharingBytesSaved, (sharingBytesSaved * 100.0) / (objBytesIfUnshared + strBytesIfUnshared)); fprintf(stdout, " Bytes with sharing %.6g\n", currentLiteralBytes); fprintf(stdout, " table %u + bkts %lu + entries %lu + objects %lu + strings %.6g\n", (unsigned int)sizeof(LiteralTable), (unsigned long)iPtr->literalTable.numBuckets * sizeof(LiteralEntry *), (unsigned long)iPtr->literalTable.numEntries * sizeof(LiteralEntry), (unsigned long)iPtr->literalTable.numEntries * sizeof(Tcl_Obj), statsPtr->currentLitStringBytes); fprintf(stdout, " Bytes if no sharing %.6g = objects %.6g + strings %.6g\n", (objBytesIfUnshared + strBytesIfUnshared), objBytesIfUnshared, strBytesIfUnshared); fprintf(stdout, " String sharing savings %.6g = unshared %.6g - shared %.6g\n", (strBytesIfUnshared - statsPtr->currentLitStringBytes), strBytesIfUnshared, statsPtr->currentLitStringBytes); fprintf(stdout, " Literal mgmt overhead %ld (%0.1f%% of bytes with sharing)\n", literalMgmtBytes, (literalMgmtBytes * 100.0) / currentLiteralBytes); fprintf(stdout, " table %u + buckets %lu + entries %lu\n", (unsigned int)sizeof(LiteralTable), (unsigned long)iPtr->literalTable.numBuckets * sizeof(LiteralEntry *), (unsigned long)iPtr->literalTable.numEntries * sizeof(LiteralEntry)); /* * Breakdown of current ByteCode space requirements. */ fprintf(stdout, "\nBreakdown of current ByteCode requirements:\n"); fprintf(stdout, " Bytes Pct of Avg per\n"); fprintf(stdout, " total ByteCode\n"); fprintf(stdout, "Total %12.6g 100.00%% %8.1f\n", statsPtr->currentByteCodeBytes, statsPtr->currentByteCodeBytes / numCurrentByteCodes); fprintf(stdout, "Header %12.6g %8.1f%% %8.1f\n", currentHeaderBytes, ((currentHeaderBytes * 100.0) / statsPtr->currentByteCodeBytes), currentHeaderBytes / numCurrentByteCodes); fprintf(stdout, "Instructions %12.6g %8.1f%% %8.1f\n", statsPtr->currentInstBytes, ((statsPtr->currentInstBytes * 100.0) / statsPtr->currentByteCodeBytes), statsPtr->currentInstBytes / numCurrentByteCodes); fprintf(stdout, "Literal ptr array %12.6g %8.1f%% %8.1f\n", statsPtr->currentLitBytes, ((statsPtr->currentLitBytes * 100.0) / statsPtr->currentByteCodeBytes), statsPtr->currentLitBytes / numCurrentByteCodes); fprintf(stdout, "Exception table %12.6g %8.1f%% %8.1f\n", statsPtr->currentExceptBytes, ((statsPtr->currentExceptBytes * 100.0) / statsPtr->currentByteCodeBytes), statsPtr->currentExceptBytes / numCurrentByteCodes); fprintf(stdout, "Auxiliary data %12.6g %8.1f%% %8.1f\n", statsPtr->currentAuxBytes, ((statsPtr->currentAuxBytes * 100.0) / statsPtr->currentByteCodeBytes), statsPtr->currentAuxBytes / numCurrentByteCodes); fprintf(stdout, "Command map %12.6g %8.1f%% %8.1f\n", statsPtr->currentCmdMapBytes, ((statsPtr->currentCmdMapBytes * 100.0) / statsPtr->currentByteCodeBytes), statsPtr->currentCmdMapBytes / numCurrentByteCodes); /* * Detailed literal statistics. */ fprintf(stdout, "\nLiteral string sizes:\n"); fprintf(stdout, " Up to length Percentage\n"); maxSizeDecade = 0; for (i = 31; i >= 0; i--) { if (statsPtr->literalCount[i] > 0) { maxSizeDecade = i; break; } } sum = 0; for (i = 0; i <= maxSizeDecade; i++) { decadeHigh = (1 << (i+1)) - 1; sum += statsPtr->literalCount[i]; fprintf(stdout, " %10d %8.0f%%\n", decadeHigh, (sum * 100.0) / statsPtr->numLiteralsCreated); } litTableStats = TclLiteralStats(globalTablePtr); fprintf(stdout, "\nCurrent literal table statistics:\n%s\n", litTableStats); ckfree((char *) litTableStats); /* * Source and ByteCode size distributions. */ fprintf(stdout, "\nSource sizes:\n"); fprintf(stdout, " Up to size Percentage\n"); minSizeDecade = maxSizeDecade = 0; for (i = 0; i < 31; i++) { if (statsPtr->srcCount[i] > 0) { minSizeDecade = i; break; } } for (i = 31; i >= 0; i--) { if (statsPtr->srcCount[i] > 0) { maxSizeDecade = i; break; } } sum = 0; for (i = minSizeDecade; i <= maxSizeDecade; i++) { decadeHigh = (1 << (i+1)) - 1; sum += statsPtr->srcCount[i]; fprintf(stdout, " %10d %8.0f%%\n", decadeHigh, (sum * 100.0) / statsPtr->numCompilations); } fprintf(stdout, "\nByteCode sizes:\n"); fprintf(stdout, " Up to size Percentage\n"); minSizeDecade = maxSizeDecade = 0; for (i = 0; i < 31; i++) { if (statsPtr->byteCodeCount[i] > 0) { minSizeDecade = i; break; } } for (i = 31; i >= 0; i--) { if (statsPtr->byteCodeCount[i] > 0) { maxSizeDecade = i; break; } } sum = 0; for (i = minSizeDecade; i <= maxSizeDecade; i++) { decadeHigh = (1 << (i+1)) - 1; sum += statsPtr->byteCodeCount[i]; fprintf(stdout, " %10d %8.0f%%\n", decadeHigh, (sum * 100.0) / statsPtr->numCompilations); } fprintf(stdout, "\nByteCode longevity (excludes Current ByteCodes):\n"); fprintf(stdout, " Up to ms Percentage\n"); minSizeDecade = maxSizeDecade = 0; for (i = 0; i < 31; i++) { if (statsPtr->lifetimeCount[i] > 0) { minSizeDecade = i; break; } } for (i = 31; i >= 0; i--) { if (statsPtr->lifetimeCount[i] > 0) { maxSizeDecade = i; break; } } sum = 0; for (i = minSizeDecade; i <= maxSizeDecade; i++) { decadeHigh = (1 << (i+1)) - 1; sum += statsPtr->lifetimeCount[i]; fprintf(stdout, " %12.3f %8.0f%%\n", decadeHigh / 1000.0, (sum * 100.0) / statsPtr->numByteCodesFreed); } /* * Instruction counts. */ fprintf(stdout, "\nInstruction counts:\n"); for (i = 0; i <= LAST_INST_OPCODE; i++) { if (statsPtr->instructionCount[i]) { fprintf(stdout, "%20s %8ld %6.1f%%\n", tclInstructionTable[i].name, statsPtr->instructionCount[i], (statsPtr->instructionCount[i]*100.0) / numInstructions); } } fprintf(stdout, "\nInstructions NEVER executed:\n"); for (i = 0; i <= LAST_INST_OPCODE; i++) { if (statsPtr->instructionCount[i] == 0) { fprintf(stdout, "%20s\n", tclInstructionTable[i].name); } } #ifdef TCL_MEM_DEBUG fprintf(stdout, "\nHeap Statistics:\n"); TclDumpMemoryInfo(stdout); #endif fprintf(stdout, "\n----------------------------------------------------------------\n"); return TCL_OK; } #endif /* TCL_COMPILE_STATS */ #ifdef TCL_COMPILE_DEBUG /* *---------------------------------------------------------------------- * * StringForResultCode -- * * Procedure that returns a human-readable string representing a * Tcl result code such as TCL_ERROR. * * Results: * If the result code is one of the standard Tcl return codes, the * result is a string representing that code such as "TCL_ERROR". * Otherwise, the result string is that code formatted as a * sequence of decimal digit characters. Note that the resulting * string must not be modified by the caller. * * Side effects: * None. * *---------------------------------------------------------------------- */ static CONST char * StringForResultCode(result) int result; /* The Tcl result code for which to * generate a string. */ { static char buf[TCL_INTEGER_SPACE]; if ((result >= TCL_OK) && (result <= TCL_CONTINUE)) { return resultStrings[result]; } TclFormatInt(buf, result); return buf; } #endif /* TCL_COMPILE_DEBUG */ /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ tcl8.4.20/generic/tclPkg.c0000644003604700454610000016467112133546540013733 0ustar dgp771div/* * tclPkg.c -- * * This file implements package and version control for Tcl via * the "package" command and a few C APIs. * * Copyright (c) 1996 Sun Microsystems, Inc. * Copyright (c) 2006 Andreas Kupries * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * TIP #268. * Heavily rewritten to handle the extend version numbers, and extended * package requirements. */ #include "tclInt.h" /* * Each invocation of the "package ifneeded" command creates a structure * of the following type, which is used to load the package into the * interpreter if it is requested with a "package require" command. */ typedef struct PkgAvail { char *version; /* Version string; malloc'ed. */ char *script; /* Script to invoke to provide this version * of the package. Malloc'ed and protected * by Tcl_Preserve and Tcl_Release. */ struct PkgAvail *nextPtr; /* Next in list of available versions of * the same package. */ } PkgAvail; /* * For each package that is known in any way to an interpreter, there * is one record of the following type. These records are stored in * the "packageTable" hash table in the interpreter, keyed by * package name such as "Tk" (no version number). */ typedef struct Package { char *version; /* Version that has been supplied in this * interpreter via "package provide" * (malloc'ed). NULL means the package doesn't * exist in this interpreter yet. */ PkgAvail *availPtr; /* First in list of all available versions * of this package. */ ClientData clientData; /* Client data. */ } Package; /* * Prototypes for procedures defined in this file: */ #ifndef TCL_TIP268 static int CheckVersion _ANSI_ARGS_((Tcl_Interp *interp, CONST char *string)); static int ComparePkgVersions _ANSI_ARGS_((CONST char *v1, CONST char *v2, int *satPtr)); static Package * FindPackage _ANSI_ARGS_((Tcl_Interp *interp, CONST char *name)); #else static int CheckVersionAndConvert(Tcl_Interp *interp, CONST char *string, char** internal, int* stable); static int CompareVersions(CONST char *v1i, CONST char *v2i, int *isMajorPtr); static int CheckRequirement(Tcl_Interp *interp, CONST char *string); static int CheckAllRequirements(Tcl_Interp* interp, int reqc, Tcl_Obj *CONST reqv[]); static int RequirementSatisfied(char *havei, CONST char *req); static int SomeRequirementSatisfied(char *havei, int reqc, Tcl_Obj *CONST reqv[]); static void AddRequirementsToResult(Tcl_Interp* interp, int reqc, Tcl_Obj *CONST reqv[]); static void AddRequirementsToDString(Tcl_DString* dstring, int reqc, Tcl_Obj *CONST reqv[]); static Package * FindPackage(Tcl_Interp *interp, CONST char *name); static CONST char * PkgRequireCore(Tcl_Interp *interp, CONST char *name, int reqx, Tcl_Obj *CONST reqv[], ClientData *clientDataPtr); #endif /* * Helper macros. */ #define DupBlock(v,s,len) \ ((v) = ckalloc(len), memcpy((v),(s),(len))) #define DupString(v,s) \ do { \ unsigned local__len = (unsigned) (strlen(s) + 1); \ DupBlock((v),(s),local__len); \ } while (0) /* *---------------------------------------------------------------------- * * Tcl_PkgProvide / Tcl_PkgProvideEx -- * * This procedure is invoked to declare that a particular version * of a particular package is now present in an interpreter. There * must not be any other version of this package already * provided in the interpreter. * * Results: * Normally returns TCL_OK; if there is already another version * of the package loaded then TCL_ERROR is returned and an error * message is left in the interp's result. * * Side effects: * The interpreter remembers that this package is available, * so that no other version of the package may be provided for * the interpreter. * *---------------------------------------------------------------------- */ #undef Tcl_PkgProvide int Tcl_PkgProvide(interp, name, version) Tcl_Interp *interp; /* Interpreter in which package is now * available. */ CONST char *name; /* Name of package. */ CONST char *version; /* Version string for package. */ { return Tcl_PkgProvideEx(interp, name, version, (ClientData) NULL); } int Tcl_PkgProvideEx(interp, name, version, clientData) Tcl_Interp *interp; /* Interpreter in which package is now * available. */ CONST char *name; /* Name of package. */ CONST char *version; /* Version string for package. */ ClientData clientData; /* clientdata for this package (normally * used for C callback function table) */ { Package *pkgPtr; #ifdef TCL_TIP268 char* pvi; char* vi; int res; #endif pkgPtr = FindPackage(interp, name); if (pkgPtr->version == NULL) { DupString(pkgPtr->version, version); pkgPtr->clientData = clientData; return TCL_OK; } #ifndef TCL_TIP268 if (ComparePkgVersions(pkgPtr->version, version, (int *) NULL) == 0) { #else if (CheckVersionAndConvert (interp, pkgPtr->version, &pvi, NULL) != TCL_OK) { return TCL_ERROR; } else if (CheckVersionAndConvert (interp, version, &vi, NULL) != TCL_OK) { ckfree(pvi); return TCL_ERROR; } res = CompareVersions(pvi, vi, NULL); ckfree(pvi); ckfree(vi); if (res == 0) { #endif if (clientData != NULL) { pkgPtr->clientData = clientData; } return TCL_OK; } Tcl_AppendResult(interp, "conflicting versions provided for package \"", name, "\": ", pkgPtr->version, ", then ", version, (char *) NULL); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * Tcl_PkgRequire / Tcl_PkgRequireEx / Tcl_PkgRequireProc -- * * This procedure is called by code that depends on a particular * version of a particular package. If the package is not already * provided in the interpreter, this procedure invokes a Tcl script * to provide it. If the package is already provided, this * procedure makes sure that the caller's needs don't conflict with * the version that is present. * * Results: * If successful, returns the version string for the currently * provided version of the package, which may be different from * the "version" argument. If the caller's requirements * cannot be met (e.g. the version requested conflicts with * a currently provided version, or the required version cannot * be found, or the script to provide the required version * generates an error), NULL is returned and an error * message is left in the interp's result. * * Side effects: * The script from some previous "package ifneeded" command may * be invoked to provide the package. * *---------------------------------------------------------------------- */ #ifndef TCL_TIP268 /* * Empty definition for Stubs when TIP 268 is not activated. */ int Tcl_PkgRequireProc(interp,name,reqc,reqv,clientDataPtr) Tcl_Interp *interp; /* Interpreter in which package is now * available. */ CONST char *name; /* Name of desired package. */ int reqc; /* Requirements constraining the desired version. */ Tcl_Obj *CONST reqv[]; /* 0 means to use the latest version available. */ ClientData *clientDataPtr; { return TCL_ERROR; } #endif #undef Tcl_PkgRequire CONST char * Tcl_PkgRequire(interp, name, version, exact) Tcl_Interp *interp; /* Interpreter in which package is now * available. */ CONST char *name; /* Name of desired package. */ CONST char *version; /* Version string for desired version; NULL * means use the latest version available. */ int exact; /* Non-zero means that only the particular * version given is acceptable. Zero means use * the latest compatible version. */ { return Tcl_PkgRequireEx(interp, name, version, exact, (ClientData *) NULL); } CONST char * Tcl_PkgRequireEx(interp, name, version, exact, clientDataPtr) Tcl_Interp *interp; /* Interpreter in which package is now * available. */ CONST char *name; /* Name of desired package. */ CONST char *version; /* Version string for desired version; * NULL means use the latest version * available. */ int exact; /* Non-zero means that only the particular * version given is acceptable. Zero means * use the latest compatible version. */ ClientData *clientDataPtr; /* Used to return the client data for this * package. If it is NULL then the client * data is not returned. This is unchanged * if this call fails for any reason. */ { #ifndef TCL_TIP268 Package *pkgPtr; PkgAvail *availPtr, *bestPtr; char *script; int code, satisfies, result, pass; Tcl_DString command; #else Tcl_Obj *ov; CONST char *result = NULL; #endif /* * If an attempt is being made to load this into a standalone executable * on a platform where backlinking is not supported then this must be * a shared version of Tcl (Otherwise the load would have failed). * Detect this situation by checking that this library has been correctly * initialised. If it has not been then return immediately as nothing will * work. */ if (tclEmptyStringRep == NULL) { /* * OK, so what's going on here? * * First, what are we doing? We are performing a check on behalf of * one particular caller, Tcl_InitStubs(). When a package is * stub-enabled, it is statically linked to libtclstub.a, which * contains a copy of Tcl_InitStubs(). When a stub-enabled package * is loaded, its *_Init() function is supposed to call * Tcl_InitStubs() before calling any other functions in the Tcl * library. The first Tcl function called by Tcl_InitStubs() through * the stub table is Tcl_PkgRequireEx(), so this code right here is * the first code that is part of the original Tcl library in the * executable that gets executed on behalf of a newly loaded * stub-enabled package. * * One easy error for the developer/builder of a stub-enabled package * to make is to forget to define USE_TCL_STUBS when compiling the * package. When that happens, the package will contain symbols * that are references to the Tcl library, rather than function * pointers referencing the stub table. On platforms that lack * backlinking, those unresolved references may cause the loading * of the package to also load a second copy of the Tcl library, * leading to all kinds of trouble. We would like to catch that * error and report a useful message back to the user. That's * what we're doing. * * Second, how does this work? If we reach this point, then the * global variable tclEmptyStringRep has the value NULL. Compare * that with the definition of tclEmptyStringRep near the top of * the file generic/tclObj.c. It clearly should not have the value * NULL; it should point to the char tclEmptyString. If we see it * having the value NULL, then somehow we are seeing a Tcl library * that isn't completely initialized, and that's an indicator for the * error condition described above. (Further explanation is welcome.) * * Third, so what do we do about it? This situation indicates * the package we just loaded wasn't properly compiled to be * stub-enabled, yet it thinks it is stub-enabled (it called * Tcl_InitStubs()). We want to report that the package just * loaded is broken, so we want to place an error message in * the interpreter result and return NULL to indicate failure * to Tcl_InitStubs() so that it will also fail. (Further * explanation why we don't want to Tcl_Panic() is welcome. * After all, two Tcl libraries can't be a good thing!) * * Trouble is that's going to be tricky. We're now using a Tcl * library that's not fully initialized. In particular, it * doesn't have a proper value for tclEmptyStringRep. The * Tcl_Obj system heavily depends on the value of tclEmptyStringRep * and all of Tcl depends (increasingly) on the Tcl_Obj system, we * need to correct that flaw before making the calls to set the * interpreter result to the error message. That's the only flaw * corrected; other problems with initialization of the Tcl library * are not remedied, so be very careful about adding any other calls * here without checking how they behave when initialization is * incomplete. */ tclEmptyStringRep = &tclEmptyString; Tcl_AppendResult(interp, "Cannot load package \"", name, "\" in standalone executable: This package is not ", "compiled with stub support", NULL); return NULL; } #ifdef TCL_TIP268 /* Translate between old and new API, and defer to the new function. */ if (version == NULL) { result = PkgRequireCore(interp, name, 0, NULL, clientDataPtr); } else { if (exact && TCL_OK != CheckVersionAndConvert(interp, version, NULL, NULL)) { return NULL; } ov = Tcl_NewStringObj(version, -1); if (exact) { Tcl_AppendStringsToObj(ov, "-", version, NULL); } Tcl_IncrRefCount (ov); result = PkgRequireCore(interp, name, 1, &ov, clientDataPtr); Tcl_DecrRefCount (ov); } return result; } int Tcl_PkgRequireProc( Tcl_Interp *interp, /* Interpreter in which package is now * available. */ CONST char *name, /* Name of desired package. */ int reqc, /* Requirements constraining the desired * version. */ Tcl_Obj *CONST reqv[], /* 0 means to use the latest version * available. */ ClientData *clientDataPtr) { CONST char *result = PkgRequireCore(interp, name, reqc, reqv, clientDataPtr); if (result == NULL) { return TCL_ERROR; } Tcl_SetObjResult(interp, Tcl_NewStringObj(result, -1)); return TCL_OK; } static CONST char * PkgRequireCore( Tcl_Interp *interp, /* Interpreter in which package is now * available. */ CONST char *name, /* Name of desired package. */ int reqc, /* Requirements constraining the desired * version. */ Tcl_Obj *CONST reqv[], /* 0 means to use the latest version * available. */ ClientData *clientDataPtr) { Interp *iPtr = (Interp *) interp; Package *pkgPtr; PkgAvail *availPtr, *bestPtr, *bestStablePtr; char *availVersion, *bestVersion; /* Internal rep. of versions */ int availStable; char *script; int code, satisfies, pass; Tcl_DString command; char* pkgVersionI; #endif /* * It can take up to three passes to find the package: one pass to run the * "package unknown" script, one to run the "package ifneeded" script for * a specific version, and a final pass to lookup the package loaded by * the "package ifneeded" script. */ for (pass = 1; ; pass++) { pkgPtr = FindPackage(interp, name); if (pkgPtr->version != NULL) { break; } /* * Check whether we're already attempting to load some version * of this package (circular dependency detection). */ if (pkgPtr->clientData != NULL) { Tcl_AppendResult(interp, "circular package dependency: ", "attempt to provide ", name, " ", (char *)(pkgPtr->clientData), " requires ", name, NULL); #ifndef TCL_TIP268 if (version != NULL) { Tcl_AppendResult(interp, " ", version, NULL); } #else AddRequirementsToResult (interp, reqc, reqv); #endif return NULL; } /* * The package isn't yet present. Search the list of available * versions and invoke the script for the best available version. * * For TIP 268 we are actually locating the best, and the best stable * version. One of them is then chosen based on the selection mode. */ #ifndef TCL_TIP268 bestPtr = NULL; for (availPtr = pkgPtr->availPtr; availPtr != NULL; availPtr = availPtr->nextPtr) { if ((bestPtr != NULL) && (ComparePkgVersions(availPtr->version, bestPtr->version, (int *) NULL) <= 0)) { #else bestPtr = NULL; bestStablePtr = NULL; bestVersion = NULL; for (availPtr = pkgPtr->availPtr; availPtr != NULL; availPtr = availPtr->nextPtr) { if (CheckVersionAndConvert(interp, availPtr->version, &availVersion, &availStable) != TCL_OK) { /* The provided version number has invalid syntax. This * should not happen. This should have been caught by the * 'package ifneeded' registering the package. */ #endif continue; } #ifndef TCL_TIP268 if (version != NULL) { result = ComparePkgVersions(availPtr->version, version, &satisfies); if ((result != 0) && exact) { #else if (bestPtr != NULL) { int res = CompareVersions (availVersion, bestVersion, NULL); /* Note: Use internal reps! */ if (res <= 0) { /* * The version of the package sought is not as good as the * currently selected version. Ignore it. */ ckfree(availVersion); availVersion = NULL; #endif continue; } #ifdef TCL_TIP268 } /* We have found a version which is better than our max. */ if (reqc > 0) { /* Check satisfaction of requirements. */ satisfies = SomeRequirementSatisfied(availVersion, reqc, reqv); #endif if (!satisfies) { #ifdef TCL_TIP268 ckfree(availVersion); availVersion = NULL; #endif continue; } } bestPtr = availPtr; #ifdef TCL_TIP268 if (bestVersion != NULL) { ckfree(bestVersion); } bestVersion = availVersion; availVersion = NULL; /* * If this new best version is stable then it also has to be * better than the max stable version found so far. */ if (availStable) { bestStablePtr = availPtr; } } if (bestVersion != NULL) { ckfree(bestVersion); } /* Now choose a version among the two best. For 'latest' we simply * take (actually keep) the best. For 'stable' we take the best * stable, if there is any, or the best if there is nothing stable. */ if ((iPtr->packagePrefer == PKG_PREFER_STABLE) && (bestStablePtr != NULL)) { bestPtr = bestStablePtr; #endif } if (bestPtr != NULL) { /* * We found an ifneeded script for the package. Be careful while * executing it: this could cause reentrancy, so (a) protect the * script itself from deletion and (b) don't assume that bestPtr * will still exist when the script completes. */ CONST char *versionToProvide = bestPtr->version; script = bestPtr->script; pkgPtr->clientData = (ClientData) versionToProvide; Tcl_Preserve((ClientData) script); Tcl_Preserve((ClientData) versionToProvide); code = Tcl_EvalEx(interp, script, -1, TCL_EVAL_GLOBAL); Tcl_Release((ClientData) script); pkgPtr = FindPackage(interp, name); if (code == TCL_OK) { #ifdef TCL_TIP268 Tcl_ResetResult(interp); #endif if (pkgPtr->version == NULL) { #ifndef TCL_TIP268 Tcl_ResetResult(interp); #endif code = TCL_ERROR; Tcl_AppendResult(interp, "attempt to provide package ", name, " ", versionToProvide, " failed: no version of package ", name, " provided", NULL); #ifndef TCL_TIP268 } else if (0 != ComparePkgVersions( pkgPtr->version, versionToProvide, NULL)) { /* At this point, it is clear that a prior * [package ifneeded] command lied to us. It said * that to get a particular version of a particular * package, we needed to evaluate a particular script. * However, we evaluated that script and got a different * version than we were told. This is an error, and we * ought to report it. * * However, we've been letting this type of error slide * for a long time, and as a result, a lot of packages * suffer from them. * * It's a bit too harsh to make a large number of * existing packages start failing by releasing a * new patch release, so we forgive this type of error * for the rest of the Tcl 8.4 series. * * We considered reporting a warning, but in practice * even that appears too harsh a change for a patch release. * * We limit the error reporting to only * the situation where a broken ifneeded script leads * to a failure to satisfy the requirement. */ if (version) { result = ComparePkgVersions( pkgPtr->version, version, &satisfies); if (result && (exact || !satisfies)) { Tcl_ResetResult(interp); code = TCL_ERROR; Tcl_AppendResult(interp, "attempt to provide package ", name, " ", versionToProvide, " failed: package ", name, " ", pkgPtr->version, " provided instead", NULL); #else } else { char *pvi, *vi; int res; if (CheckVersionAndConvert(interp, pkgPtr->version, &pvi, NULL) != TCL_OK) { code = TCL_ERROR; } else if (CheckVersionAndConvert(interp, versionToProvide, &vi, NULL) != TCL_OK) { ckfree(pvi); code = TCL_ERROR; } else { res = CompareVersions(pvi, vi, NULL); ckfree(vi); if (res != 0) { /* At this point, it is clear that a prior * [package ifneeded] command lied to us. It said * that to get a particular version of a particular * package, we needed to evaluate a particular * script. However, we evaluated that script and * got a different version than we were told. * This is an error, and we ought to report it. * * However, we've been letting this type of error * slide for a long time, and as a result, a lot * of packages suffer from them. * * It's a bit too harsh to make a large number of * existing packages start failing by releasing a * new patch release, so we forgive this type of * error for the rest of the Tcl 8.4 series. * * We considered reporting a warning, but in * practice even that appears too harsh a change * for a patch release. * * We limit the error reporting to only the * situation where a broken ifneeded script leads * to a failure to satisfy the requirement. */ if (reqc > 0) { satisfies = SomeRequirementSatisfied(pvi, reqc, reqv); if (!satisfies) { code = TCL_ERROR; Tcl_AppendResult(interp, "attempt to provide package ", name, " ", versionToProvide, " failed: package ", name, " ", pkgPtr->version, " provided instead", NULL); } } #endif } #ifdef TCL_TIP268 ckfree(pvi); #endif } } } else if (code != TCL_ERROR) { Tcl_Obj *codePtr = Tcl_NewIntObj(code); Tcl_ResetResult(interp); Tcl_AppendResult(interp, "attempt to provide package ", name, " ", versionToProvide, " failed: ", "bad return code: ", Tcl_GetString(codePtr), NULL); Tcl_DecrRefCount(codePtr); code = TCL_ERROR; } Tcl_Release((ClientData) versionToProvide); if (code != TCL_OK) { /* * Take a non-TCL_OK code from the script as an indication the * package wasn't loaded properly, so the package system * should not remember an improper load. * * This is consistent with our returning NULL. If we're not * willing to tell our caller we got a particular version, we * shouldn't store that version for telling future callers * either. */ Tcl_AddErrorInfo(interp, "\n (\"package ifneeded\" script)"); if (pkgPtr->version != NULL) { ckfree(pkgPtr->version); pkgPtr->version = NULL; } pkgPtr->clientData = NULL; return NULL; } break; } /* * The package is not in the database. If there is a "package unknown" * command, invoke it (but only on the first pass; after that, we * should not get here in the first place). */ if (pass > 1) { break; } script = ((Interp *) interp)->packageUnknown; if (script != NULL) { Tcl_DStringInit(&command); Tcl_DStringAppend(&command, script, -1); Tcl_DStringAppendElement(&command, name); #ifndef TCL_TIP268 Tcl_DStringAppend(&command, " ", 1); Tcl_DStringAppend(&command, (version != NULL) ? version : "{}", -1); if (exact) { Tcl_DStringAppend(&command, " -exact", 7); } #else AddRequirementsToDString(&command, reqc, reqv); #endif code = Tcl_EvalEx(interp, Tcl_DStringValue(&command), Tcl_DStringLength(&command), TCL_EVAL_GLOBAL); Tcl_DStringFree(&command); if ((code != TCL_OK) && (code != TCL_ERROR)) { Tcl_Obj *codePtr = Tcl_NewIntObj(code); Tcl_ResetResult(interp); Tcl_AppendResult(interp, "bad return code: ", Tcl_GetString(codePtr), NULL); Tcl_DecrRefCount(codePtr); code = TCL_ERROR; } if (code == TCL_ERROR) { Tcl_AddErrorInfo(interp, "\n (\"package unknown\" script)"); return NULL; } Tcl_ResetResult(interp); } } if (pkgPtr->version == NULL) { Tcl_AppendResult(interp, "can't find package ", name, (char *) NULL); #ifndef TCL_TIP268 if (version != NULL) { Tcl_AppendResult(interp, " ", version, (char *) NULL); } #else AddRequirementsToResult(interp, reqc, reqv); #endif return NULL; } /* * At this point we know that the package is present. Make sure that the * provided version meets the current requirements. */ #ifndef TCL_TIP268 if (version == NULL) { if (clientDataPtr) { *clientDataPtr = pkgPtr->clientData; } return pkgPtr->version; #else if (reqc == 0) { satisfies = 1; } else { CheckVersionAndConvert(interp, pkgPtr->version, &pkgVersionI, NULL); satisfies = SomeRequirementSatisfied(pkgVersionI, reqc, reqv); ckfree(pkgVersionI); #endif } #ifndef TCL_TIP268 result = ComparePkgVersions(pkgPtr->version, version, &satisfies); if ((satisfies && !exact) || (result == 0)) { #else if (satisfies) { #endif if (clientDataPtr) { *clientDataPtr = pkgPtr->clientData; } return pkgPtr->version; } Tcl_AppendResult(interp, "version conflict for package \"", name, "\": have ", pkgPtr->version, #ifndef TCL_TIP268 ", need ", version, (char *) NULL); #else ", need", (char*) NULL); AddRequirementsToResult (interp, reqc, reqv); #endif return NULL; } /* *---------------------------------------------------------------------- * * Tcl_PkgPresent / Tcl_PkgPresentEx -- * * Checks to see whether the specified package is present. If it * is not then no additional action is taken. * * Results: * If successful, returns the version string for the currently * provided version of the package, which may be different from * the "version" argument. If the caller's requirements * cannot be met (e.g. the version requested conflicts with * a currently provided version), NULL is returned and an error * message is left in interp->result. * * Side effects: * None. * *---------------------------------------------------------------------- */ #undef Tcl_PkgPresent CONST char * Tcl_PkgPresent(interp, name, version, exact) Tcl_Interp *interp; /* Interpreter in which package is now * available. */ CONST char *name; /* Name of desired package. */ CONST char *version; /* Version string for desired version; * NULL means use the latest version * available. */ int exact; /* Non-zero means that only the particular * version given is acceptable. Zero means * use the latest compatible version. */ { return Tcl_PkgPresentEx(interp, name, version, exact, (ClientData *) NULL); } CONST char * Tcl_PkgPresentEx(interp, name, version, exact, clientDataPtr) Tcl_Interp *interp; /* Interpreter in which package is now * available. */ CONST char *name; /* Name of desired package. */ CONST char *version; /* Version string for desired version; * NULL means use the latest version * available. */ int exact; /* Non-zero means that only the particular * version given is acceptable. Zero means * use the latest compatible version. */ ClientData *clientDataPtr; /* Used to return the client data for this * package. If it is NULL then the client * data is not returned. This is unchanged * if this call fails for any reason. */ { Interp *iPtr = (Interp *) interp; Tcl_HashEntry *hPtr; Package *pkgPtr; hPtr = Tcl_FindHashEntry(&iPtr->packageTable, name); if (hPtr) { pkgPtr = (Package *) Tcl_GetHashValue(hPtr); if (pkgPtr->version != NULL) { /* * At this point we know that the package is present. Make sure * that the provided version meets the current requirement by * calling Tcl_PkgRequireEx() to check for us. */ return Tcl_PkgRequireEx(interp, name, version, exact, clientDataPtr); } } if (version != NULL) { Tcl_AppendResult(interp, "package ", name, " ", version, " is not present", NULL); } else { Tcl_AppendResult(interp, "package ", name, " is not present", NULL); } return NULL; } /* *---------------------------------------------------------------------- * * Tcl_PackageObjCmd -- * * This procedure is invoked to process the "package" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_PackageObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { static CONST char *pkgOptions[] = { "forget", "ifneeded", "names", #ifdef TCL_TIP268 "prefer", #endif "present", "provide", "require", "unknown", "vcompare", "versions", "vsatisfies", (char *) NULL }; enum pkgOptions { PKG_FORGET, PKG_IFNEEDED, PKG_NAMES, #ifdef TCL_TIP268 PKG_PREFER, #endif PKG_PRESENT, PKG_PROVIDE, PKG_REQUIRE, PKG_UNKNOWN, PKG_VCOMPARE, PKG_VERSIONS, PKG_VSATISFIES }; Interp *iPtr = (Interp *) interp; int optionIndex, exact, i, satisfies; PkgAvail *availPtr, *prevPtr; Package *pkgPtr; Tcl_HashEntry *hPtr; Tcl_HashSearch search; Tcl_HashTable *tablePtr; CONST char *version; char *argv2, *argv3, *argv4; #ifdef TCL_TIP268 char* iva = NULL; char* ivb = NULL; #endif if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[1], pkgOptions, "option", 0, &optionIndex) != TCL_OK) { return TCL_ERROR; } switch ((enum pkgOptions) optionIndex) { case PKG_FORGET: { char *keyString; for (i = 2; i < objc; i++) { keyString = Tcl_GetString(objv[i]); hPtr = Tcl_FindHashEntry(&iPtr->packageTable, keyString); if (hPtr == NULL) { continue; } pkgPtr = (Package *) Tcl_GetHashValue(hPtr); Tcl_DeleteHashEntry(hPtr); if (pkgPtr->version != NULL) { ckfree(pkgPtr->version); } while (pkgPtr->availPtr != NULL) { availPtr = pkgPtr->availPtr; pkgPtr->availPtr = availPtr->nextPtr; Tcl_EventuallyFree((ClientData)availPtr->version, TCL_DYNAMIC); Tcl_EventuallyFree((ClientData)availPtr->script, TCL_DYNAMIC); ckfree((char *) availPtr); } ckfree((char *) pkgPtr); } break; } case PKG_IFNEEDED: { int length; #ifdef TCL_TIP268 int res; char *argv3i, *avi; #endif if ((objc != 4) && (objc != 5)) { Tcl_WrongNumArgs(interp, 2, objv, "package version ?script?"); return TCL_ERROR; } argv3 = Tcl_GetString(objv[3]); #ifdef TCL_TIP268 if (CheckVersionAndConvert(interp, argv3, &argv3i, NULL) != TCL_OK) { #else if (CheckVersion(interp, argv3) != TCL_OK) { #endif return TCL_ERROR; } argv2 = Tcl_GetString(objv[2]); if (objc == 4) { hPtr = Tcl_FindHashEntry(&iPtr->packageTable, argv2); if (hPtr == NULL) { #ifdef TCL_TIP268 ckfree(argv3i); #endif return TCL_OK; } pkgPtr = (Package *) Tcl_GetHashValue(hPtr); } else { pkgPtr = FindPackage(interp, argv2); } argv3 = Tcl_GetStringFromObj(objv[3], &length); for (availPtr = pkgPtr->availPtr, prevPtr = NULL; availPtr != NULL; prevPtr = availPtr, availPtr = availPtr->nextPtr) { #ifdef TCL_TIP268 if (CheckVersionAndConvert(interp, availPtr->version, &avi, NULL) != TCL_OK) { ckfree(argv3i); return TCL_ERROR; } res = CompareVersions(avi, argv3i, NULL); ckfree(avi); if (res == 0){ #else if (ComparePkgVersions(availPtr->version, argv3, (int *) NULL) == 0) { #endif if (objc == 4) { #ifdef TCL_TIP268 ckfree(argv3i); #endif Tcl_SetResult(interp, availPtr->script, TCL_VOLATILE); return TCL_OK; } Tcl_EventuallyFree((ClientData)availPtr->script, TCL_DYNAMIC); break; } } #ifdef TCL_TIP268 ckfree(argv3i); #endif if (objc == 4) { return TCL_OK; } if (availPtr == NULL) { availPtr = (PkgAvail *) ckalloc(sizeof(PkgAvail)); DupBlock(availPtr->version, argv3, (unsigned) length + 1); if (prevPtr == NULL) { availPtr->nextPtr = pkgPtr->availPtr; pkgPtr->availPtr = availPtr; } else { availPtr->nextPtr = prevPtr->nextPtr; prevPtr->nextPtr = availPtr; } } argv4 = Tcl_GetStringFromObj(objv[4], &length); DupBlock(availPtr->script, argv4, (unsigned) length + 1); break; } case PKG_NAMES: { if (objc != 2) { Tcl_WrongNumArgs(interp, 2, objv, NULL); return TCL_ERROR; } tablePtr = &iPtr->packageTable; for (hPtr = Tcl_FirstHashEntry(tablePtr, &search); hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { pkgPtr = (Package *) Tcl_GetHashValue(hPtr); if ((pkgPtr->version != NULL) || (pkgPtr->availPtr != NULL)) { Tcl_AppendElement(interp, Tcl_GetHashKey(tablePtr, hPtr)); } } break; } case PKG_PRESENT: { CONST char *name; if (objc < 3) { goto require; } argv2 = Tcl_GetString(objv[2]); if ((argv2[0] == '-') && (strcmp(argv2, "-exact") == 0)) { if (objc != 5) { goto requireSyntax; } exact = 1; name = TclGetString(objv[3]); } else { exact = 0; name = argv2; } hPtr = Tcl_FindHashEntry(&iPtr->packageTable, name); if (hPtr != NULL) { pkgPtr = Tcl_GetHashValue(hPtr); if (pkgPtr->version != NULL) { goto require; } } #ifndef TCL_TIP268 version = NULL; if (objc == (4 + exact)) { version = Tcl_GetString(objv[3 + exact]); if (CheckVersion(interp, version) != TCL_OK) { return TCL_ERROR; } } else if ((objc != 3) || exact) { goto requireSyntax; } #else version = NULL; if (exact) { version = Tcl_GetString(objv[4]); if (CheckVersionAndConvert(interp, version, NULL, NULL) != TCL_OK) { return TCL_ERROR; } } else { if (CheckAllRequirements(interp, objc-3, objv+3) != TCL_OK) { return TCL_ERROR; } if ((objc > 3) && (CheckVersionAndConvert(interp, TclGetString(objv[3]), NULL, NULL) == TCL_OK)) { version = TclGetString(objv[3]); } } #endif Tcl_PkgPresentEx(interp, name, version, exact, NULL); return TCL_ERROR; break; } case PKG_PROVIDE: { if ((objc != 3) && (objc != 4)) { Tcl_WrongNumArgs(interp, 2, objv, "package ?version?"); return TCL_ERROR; } argv2 = Tcl_GetString(objv[2]); if (objc == 3) { hPtr = Tcl_FindHashEntry(&iPtr->packageTable, argv2); if (hPtr != NULL) { pkgPtr = (Package *) Tcl_GetHashValue(hPtr); if (pkgPtr->version != NULL) { Tcl_SetResult(interp, pkgPtr->version, TCL_VOLATILE); } } return TCL_OK; } argv3 = Tcl_GetString(objv[3]); #ifndef TCL_TIP268 if (CheckVersion(interp, argv3) != TCL_OK) { #else if (CheckVersionAndConvert(interp, argv3, NULL, NULL) != TCL_OK) { #endif return TCL_ERROR; } return Tcl_PkgProvideEx(interp, argv2, argv3, NULL); } case PKG_REQUIRE: { require: if (objc < 3) { requireSyntax: #ifndef TCL_TIP268 Tcl_WrongNumArgs(interp, 2, objv, "?-exact? package ?version?"); #else Tcl_WrongNumArgs(interp, 2, objv, "?-exact? package ?requirement...?"); #endif return TCL_ERROR; } #ifndef TCL_TIP268 argv2 = Tcl_GetString(objv[2]); if ((argv2[0] == '-') && (strcmp(argv2, "-exact") == 0)) { exact = 1; } else { exact = 0; } version = NULL; if (objc == (4 + exact)) { version = Tcl_GetString(objv[3 + exact]); if (CheckVersion(interp, version) != TCL_OK) { return TCL_ERROR; } } else if ((objc != 3) || exact) { goto requireSyntax; } if (exact) { argv3 = Tcl_GetString(objv[3]); version = Tcl_PkgRequireEx(interp, argv3, version, exact, NULL); } else { version = Tcl_PkgRequireEx(interp, argv2, version, exact, NULL); } if (version == NULL) { return TCL_ERROR; } Tcl_SetObjResult( interp, Tcl_NewStringObj( version, -1 ) ); #else version = NULL; argv2 = Tcl_GetString(objv[2]); if ((argv2[0] == '-') && (strcmp(argv2, "-exact") == 0)) { Tcl_Obj* ov; int res; if (objc != 5) { goto requireSyntax; } version = Tcl_GetString(objv[4]); if (CheckVersionAndConvert(interp, version, NULL, NULL) != TCL_OK) { return TCL_ERROR; } /* Create a new-style requirement for the exact version. */ ov = Tcl_NewStringObj(version, -1); Tcl_AppendStringsToObj(ov, "-", version, NULL); version = NULL; argv3 = Tcl_GetString(objv[3]); Tcl_IncrRefCount (ov); res = Tcl_PkgRequireProc(interp, argv3, 1, &ov, NULL); Tcl_DecrRefCount (ov); return res; } else { if (CheckAllRequirements (interp, objc-3, objv+3) != TCL_OK) { return TCL_ERROR; } return Tcl_PkgRequireProc(interp, argv2, objc-3, objv+3, NULL); } #endif break; } case PKG_UNKNOWN: { int length; if (objc == 2) { if (iPtr->packageUnknown != NULL) { Tcl_SetResult(interp, iPtr->packageUnknown, TCL_VOLATILE); } } else if (objc == 3) { if (iPtr->packageUnknown != NULL) { ckfree(iPtr->packageUnknown); } argv2 = Tcl_GetStringFromObj(objv[2], &length); if (argv2[0] == 0) { iPtr->packageUnknown = NULL; } else { DupBlock(iPtr->packageUnknown, argv2, (unsigned) length + 1); } } else { Tcl_WrongNumArgs(interp, 2, objv, "?command?"); return TCL_ERROR; } break; } #ifdef TCL_TIP268 case PKG_PREFER: { /* See tclInt.h for the enum, just before Interp */ static CONST char *pkgPreferOptions[] = { "latest", "stable", NULL }; if (objc > 3) { Tcl_WrongNumArgs(interp, 2, objv, "?latest|stable?"); return TCL_ERROR; } else if (objc == 3) { /* Set value. */ int new; if (Tcl_GetIndexFromObj(interp, objv[2], pkgPreferOptions, "preference", 0, &new) != TCL_OK) { return TCL_ERROR; } if (new < iPtr->packagePrefer) { iPtr->packagePrefer = new; } } /* Always return current value. */ Tcl_SetObjResult(interp, Tcl_NewStringObj(pkgPreferOptions[iPtr->packagePrefer], -1)); break; } #endif case PKG_VCOMPARE: { if (objc != 4) { Tcl_WrongNumArgs(interp, 2, objv, "version1 version2"); return TCL_ERROR; } argv3 = Tcl_GetString(objv[3]); argv2 = Tcl_GetString(objv[2]); #ifndef TCL_TIP268 if ((CheckVersion(interp, argv2) != TCL_OK) || (CheckVersion(interp, argv3) != TCL_OK)) { return TCL_ERROR; } Tcl_SetObjResult(interp, Tcl_NewIntObj( ComparePkgVersions(argv2, argv3, (int *) NULL))); #else if ((CheckVersionAndConvert (interp, argv2, &iva, NULL) != TCL_OK) || (CheckVersionAndConvert (interp, argv3, &ivb, NULL) != TCL_OK)) { if (iva != NULL) { ckfree(iva); } /* ivb cannot be set in this branch */ return TCL_ERROR; } /* Comparison is done on the internal representation */ Tcl_SetObjResult(interp, Tcl_NewIntObj(CompareVersions(iva, ivb, NULL))); ckfree(iva); ckfree(ivb); #endif break; } case PKG_VERSIONS: { if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "package"); return TCL_ERROR; } argv2 = Tcl_GetString(objv[2]); hPtr = Tcl_FindHashEntry(&iPtr->packageTable, argv2); if (hPtr != NULL) { pkgPtr = (Package *) Tcl_GetHashValue(hPtr); for (availPtr = pkgPtr->availPtr; availPtr != NULL; availPtr = availPtr->nextPtr) { Tcl_AppendElement(interp, availPtr->version); } } break; } case PKG_VSATISFIES: { #ifdef TCL_TIP268 char* argv2i = NULL; if (objc < 4) { Tcl_WrongNumArgs(interp, 2, objv, "version requirement requirement..."); return TCL_ERROR; } argv2 = Tcl_GetString(objv[2]); if ((CheckVersionAndConvert(interp, argv2, &argv2i, NULL) != TCL_OK)) { return TCL_ERROR; } else if (CheckAllRequirements(interp, objc-3, objv+3) != TCL_OK) { ckfree(argv2i); return TCL_ERROR; } satisfies = SomeRequirementSatisfied(argv2i, objc-3, objv+3); ckfree (argv2i); #else if (objc != 4) { Tcl_WrongNumArgs(interp, 2, objv, "version1 version2"); return TCL_ERROR; } argv3 = Tcl_GetString(objv[3]); argv2 = Tcl_GetString(objv[2]); if ((CheckVersion(interp, argv2) != TCL_OK) || (CheckVersion(interp, argv3) != TCL_OK)) { return TCL_ERROR; } ComparePkgVersions(argv2, argv3, &satisfies); #endif Tcl_SetObjResult(interp, Tcl_NewIntObj(satisfies)); break; } default: { panic("Tcl_PackageObjCmd: bad option index to pkgOptions"); } } return TCL_OK; } /* *---------------------------------------------------------------------- * * FindPackage -- * * This procedure finds the Package record for a particular package * in a particular interpreter, creating a record if one doesn't * already exist. * * Results: * The return value is a pointer to the Package record for the * package. * * Side effects: * A new Package record may be created. * *---------------------------------------------------------------------- */ static Package * FindPackage(interp, name) Tcl_Interp *interp; /* Interpreter to use for package lookup. */ CONST char *name; /* Name of package to fine. */ { Interp *iPtr = (Interp *) interp; Tcl_HashEntry *hPtr; int new; Package *pkgPtr; hPtr = Tcl_CreateHashEntry(&iPtr->packageTable, name, &new); if (new) { pkgPtr = (Package *) ckalloc(sizeof(Package)); pkgPtr->version = NULL; pkgPtr->availPtr = NULL; pkgPtr->clientData = NULL; Tcl_SetHashValue(hPtr, pkgPtr); } else { pkgPtr = (Package *) Tcl_GetHashValue(hPtr); } return pkgPtr; } /* *---------------------------------------------------------------------- * * TclFreePackageInfo -- * * This procedure is called during interpreter deletion to * free all of the package-related information for the * interpreter. * * Results: * None. * * Side effects: * Memory is freed. * *---------------------------------------------------------------------- */ void TclFreePackageInfo(iPtr) Interp *iPtr; /* Interpreter that is being deleted. */ { Package *pkgPtr; Tcl_HashSearch search; Tcl_HashEntry *hPtr; PkgAvail *availPtr; for (hPtr = Tcl_FirstHashEntry(&iPtr->packageTable, &search); hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { pkgPtr = (Package *) Tcl_GetHashValue(hPtr); if (pkgPtr->version != NULL) { ckfree(pkgPtr->version); } while (pkgPtr->availPtr != NULL) { availPtr = pkgPtr->availPtr; pkgPtr->availPtr = availPtr->nextPtr; Tcl_EventuallyFree((ClientData)availPtr->version, TCL_DYNAMIC); Tcl_EventuallyFree((ClientData)availPtr->script, TCL_DYNAMIC); ckfree((char *) availPtr); } ckfree((char *) pkgPtr); } Tcl_DeleteHashTable(&iPtr->packageTable); if (iPtr->packageUnknown != NULL) { ckfree(iPtr->packageUnknown); } } /* *---------------------------------------------------------------------- * * CheckVersion / CheckVersionAndConvert -- * * This procedure checks to see whether a version number has * valid syntax. * * Results: * If string is a properly formed version number the TCL_OK * is returned. Otherwise TCL_ERROR is returned and an error * message is left in the interp's result. * * Side effects: * None. * *---------------------------------------------------------------------- */ #ifndef TCL_TIP268 static int CheckVersion(interp, string) Tcl_Interp *interp; /* Used for error reporting. */ CONST char *string; /* Supposedly a version number, which is * groups of decimal digits separated * by dots. */ { CONST char *p = string; char prevChar; if (!isdigit(UCHAR(*p))) { /* INTL: digit */ goto error; } for (prevChar = *p, p++; *p != 0; p++) { if (!isdigit(UCHAR(*p)) && ((*p != '.') || (prevChar == '.'))) { /* INTL: digit */ goto error; } prevChar = *p; } if (prevChar != '.') { return TCL_OK; } error: Tcl_AppendResult(interp, "expected version number but got \"", string, "\"", (char *) NULL); return TCL_ERROR; } #else static int CheckVersionAndConvert(interp, string, internal, stable) Tcl_Interp *interp; /* Used for error reporting. */ CONST char *string; /* Supposedly a version number, which is * groups of decimal digits separated by * dots. */ char** internal; /* Internal normalized representation */ int* stable; /* Flag: Version is (un)stable. */ { CONST char *p = string; char prevChar; int hasunstable = 0; /* * 4* assuming that each char is a separator (a,b become ' -x '). * 4+ to have spce for an additional -2 at the end */ char* ibuf = ckalloc(4+4*strlen(string)); char* ip = ibuf; /* Basic rules * (1) First character has to be a digit. * (2) All other characters have to be a digit or '.' * (3) Two '.'s may not follow each other. * TIP 268, Modified rules * (1) s.a. * (2) All other characters have to be a digit, 'a', 'b', or '.' * (3) s.a. * (4) Only one of 'a' or 'b' may occur. * (5) Neither 'a', nor 'b' may occur before or after a '.' */ if (!isdigit(UCHAR(*p))) { /* INTL: digit */ goto error; } *ip++ = *p; for (prevChar = *p, p++; *p != 0; p++) { if ((!isdigit(UCHAR(*p))) && (((*p != '.') && (*p != 'a') && (*p != 'b')) || ((hasunstable && ((*p == 'a') || (*p == 'b'))) || (((prevChar == 'a') || (prevChar == 'b') || (prevChar == '.')) && (*p == '.')) || (((*p == 'a') || (*p == 'b') || (*p == '.')) && (prevChar == '.'))))) { /* INTL: digit */ goto error; } if ((*p == 'a') || (*p == 'b')) { hasunstable = 1; } /* * Translation to the internal rep. Regular version chars are copied * as is. The separators are translated to numerics. The new separator * for all parts is space. */ if (*p == '.') { *ip++ = ' '; *ip++ = '0'; *ip++ = ' '; } else if (*p == 'a') { *ip++ = ' '; *ip++ = '-'; *ip++ = '2'; *ip++ = ' '; } else if (*p == 'b') { *ip++ = ' '; *ip++ = '-'; *ip++ = '1'; *ip++ = ' '; } else { *ip++ = *p; } prevChar = *p; } if ((prevChar != '.') && (prevChar != 'a') && (prevChar != 'b')) { *ip = '\0'; if (internal != NULL) { *internal = ibuf; } else { ckfree(ibuf); } if (stable != NULL) { *stable = !hasunstable; } return TCL_OK; } error: ckfree(ibuf); Tcl_AppendResult(interp, "expected version number but got \"", string, "\"", (char *) NULL); return TCL_ERROR; } #endif /* *---------------------------------------------------------------------- * * ComparePkgVersions / CompareVersions -- * * This procedure compares two version numbers. (268: in internal rep). * * Results: * The return value is -1 if v1 is less than v2, 0 if the two * version numbers are the same, and 1 if v1 is greater than v2. * If *satPtr is non-NULL, the word it points to is filled in * with 1 if v2 >= v1 and both numbers have the same major number * or 0 otherwise. * * Side effects: * None. * *---------------------------------------------------------------------- */ #ifndef TCL_TIP268 static int ComparePkgVersions(v1, v2, satPtr) CONST char *v1; CONST char *v2; /* Versions strings, of form 2.1.3 (any * number of version numbers). */ int *satPtr; /* If non-null, the word pointed to is * filled in with a 0/1 value. 1 means * v1 "satisfies" v2: v1 is greater than * or equal to v2 and both version numbers * have the same major number. */ { int thisIsMajor, n1, n2; /* * Each iteration of the following loop processes one number from each * string, terminated by a " " (space). If those numbers don't match then * the comparison is over; otherwise, we loop back for the next number. */ thisIsMajor = 1; while (1) { /* Parse one decimal number from the front of each string. */ n1 = n2 = 0; while ((*v1 != 0) && (*v1 != '.')) { n1 = 10*n1 + (*v1 - '0'); v1++; } while ((*v2 != 0) && (*v2 != '.')) { n2 = 10*n2 + (*v2 - '0'); v2++; } /* * Compare and go on to the next version number if the current numbers * match. */ if (n1 != n2) { break; } if (*v1 != 0) { v1++; } else if (*v2 == 0) { break; } if (*v2 != 0) { v2++; } thisIsMajor = 0; } if (satPtr != NULL) { *satPtr = (n1 == n2) || ((n1 > n2) && !thisIsMajor); } if (n1 > n2) { return 1; } else if (n1 == n2) { return 0; } else { return -1; } } #else static int CompareVersions(v1, v2, isMajorPtr) CONST char *v1; /* Versions strings, of form 2.1.3 (any number */ CONST char *v2; /* of version numbers). */ int *isMajorPtr; /* If non-null, the word pointed to is filled * in with a 0/1 value. 1 means that the difference * occured in the first element. */ { int thisIsMajor, n1, n2; int res, flip; /* * Each iteration of the following loop processes one number from each * string, terminated by a " " (space). If those numbers don't match then * the comparison is over; otherwise, we loop back for the next number. * * TIP 268. * This is identical the function 'ComparePkgVersion', but using the new * space separator as used by the internal rep of version numbers. The * special separators 'a' and 'b' have already been dealt with in * 'CheckVersionAndConvert', they were translated into numbers as * well. This keeps the comparison sane. Otherwise we would have to * compare numerics, the separators, and also deal with the special case * of end-of-string compared to separators. The semi-list rep we get here * is much easier to handle, as it is still regular. */ thisIsMajor = 1; while (1) { /* Parse one decimal number from the front of each string. */ n1 = n2 = 0; flip = 0; while ((*v1 != 0) && (*v1 != ' ')) { if (*v1 == '-') {flip = 1 ; v1++ ; continue;} n1 = 10*n1 + (*v1 - '0'); v1++; } if (flip) n1 = -n1; flip = 0; while ((*v2 != 0) && (*v2 != ' ')) { if (*v2 == '-') {flip = 1; v2++ ; continue;} n2 = 10*n2 + (*v2 - '0'); v2++; } if (flip) n2 = -n2; /* * Compare and go on to the next version number if the current numbers * match. */ if (n1 != n2) { break; } if (*v1 != 0) { v1++; } else if (*v2 == 0) { break; } if (*v2 != 0) { v2++; } thisIsMajor = 0; } if (n1 > n2) { res = 1; } else if (n1 == n2) { res = 0; } else { res = -1; } if (isMajorPtr != NULL) { *isMajorPtr = thisIsMajor; } return res; } /* *---------------------------------------------------------------------- * * CheckAllRequirements -- * * This function checks to see whether all requirements in a set * have valid syntax. * * Results: * TCL_OK is returned if all requirements are valid. * Otherwise TCL_ERROR is returned and an error message * is left in the interp's result. * * Side effects: * May modify the interpreter result. * *---------------------------------------------------------------------- */ static int CheckAllRequirements(interp, reqc, reqv) Tcl_Interp* interp; int reqc; /* Requirements to check. */ Tcl_Obj *CONST reqv[]; { int i; for (i = 0; i < reqc; i++) { if ((CheckRequirement(interp, Tcl_GetString(reqv[i])) != TCL_OK)) { return TCL_ERROR; } } return TCL_OK; } /* *---------------------------------------------------------------------- * * CheckRequirement -- * * This function checks to see whether a requirement has valid syntax. * * Results: * If string is a properly formed requirement then TCL_OK is returned. * Otherwise TCL_ERROR is returned and an error message is left in the * interp's result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int CheckRequirement(interp, string) Tcl_Interp *interp; /* Used for error reporting. */ CONST char *string; /* Supposedly a requirement. */ { /* Syntax of requirement = version * = version-version * = version- */ char* dash = NULL; char* buf; dash = strchr (string, '-'); if (dash == NULL) { /* no dash found, has to be a simple version */ return CheckVersionAndConvert (interp, string, NULL, NULL); } if (strchr (dash+1, '-') != NULL) { /* More dashes found after the first. This is wrong. */ Tcl_AppendResult(interp, "expected versionMin-versionMax but got \"", string, "\"", NULL); return TCL_ERROR; } /* Exactly one dash is present. Copy the string, split at the location of * dash and check that both parts are versions. Note that the max part can * be empty. */ DupString(buf, string); dash = buf + (dash - string); *dash = '\0'; /* buf now <=> min part */ dash ++; /* dash now <=> max part */ if ((CheckVersionAndConvert(interp, buf, NULL, NULL) != TCL_OK) || ((*dash != '\0') && (CheckVersionAndConvert(interp, dash, NULL, NULL) != TCL_OK))) { ckfree(buf); return TCL_ERROR; } ckfree(buf); return TCL_OK; } /* *---------------------------------------------------------------------- * * AddRequirementsToResult -- * * This function accumulates requirements in the interpreter result. * * Results: * None. * * Side effects: * The interpreter result is extended. * *---------------------------------------------------------------------- */ static void AddRequirementsToResult(interp, reqc, reqv) Tcl_Interp* interp; int reqc; /* Requirements constraining the desired version. */ Tcl_Obj *CONST reqv[]; /* 0 means use the latest version available. */ { if (reqc > 0) { int i; for (i = 0; i < reqc; i++) { int length; char *v = Tcl_GetStringFromObj(reqv[i], &length); if ((length & 0x1) && (v[length/2] == '-') && (strncmp(v, v+((length+1)/2), length/2) == 0)) { Tcl_AppendResult(interp, " ", v+((length+1)/2), NULL); } else { Tcl_AppendResult(interp, " ", v, NULL); } } } } /* *---------------------------------------------------------------------- * * AddRequirementsToDString -- * * This function accumulates requirements in a DString. * * Results: * None. * * Side effects: * The DString argument is extended. * *---------------------------------------------------------------------- */ static void AddRequirementsToDString(dstring, reqc, reqv) Tcl_DString* dstring; int reqc; /* Requirements constraining the desired version. */ Tcl_Obj *CONST reqv[]; /* 0 means use the latest version available. */ { if (reqc > 0) { int i; for (i = 0; i < reqc; i++) { Tcl_DStringAppend(dstring, " ", 1); Tcl_DStringAppend(dstring, TclGetString(reqv[i]), -1); } } else { Tcl_DStringAppend(dstring, " 0-", -1); } } /* *---------------------------------------------------------------------- * * SomeRequirementSatisfied -- * * This function checks to see whether a version satisfies at * least one of a set of requirements. * * Results: * If the requirements are satisfied 1 is returned. * Otherwise 0 is returned. The function assumes * that all pieces have valid syntax. And is allowed * to make that assumption. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int SomeRequirementSatisfied(availVersionI, reqc, reqv) char *availVersionI; /* Candidate version to check against the * requirements. */ int reqc; /* Requirements constraining the desired * version. */ Tcl_Obj *CONST reqv[]; /* 0 means use the latest version available. */ { int i; for (i = 0; i < reqc; i++) { if (RequirementSatisfied(availVersionI, Tcl_GetString(reqv[i]))) { return 1; } } return 0; } /* *---------------------------------------------------------------------- * * RequirementSatisfied -- * * This function checks to see whether a version satisfies a requirement. * * Results: * If the requirement is satisfied 1 is returned. * Otherwise 0 is returned. The function assumes * that all pieces have valid syntax. And is allowed * to make that assumption. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int RequirementSatisfied(havei, req) char *havei; /* Version string, of candidate package we have */ CONST char *req; /* Requirement string the candidate has to satisfy */ { /* The have candidate is already in internal rep. */ int satisfied, res; char* dash = NULL; char* buf, *min, *max; dash = strchr (req, '-'); if (dash == NULL) { /* No dash found, is a simple version, fallback to regular check. * The 'CheckVersionAndConvert' cannot fail. We pad the requirement with * 'a0', i.e '-2' before doing the comparison to properly accept * unstables as well. */ char* reqi = NULL; int thisIsMajor; CheckVersionAndConvert (NULL, req, &reqi, NULL); strcat (reqi, " -2"); res = CompareVersions(havei, reqi, &thisIsMajor); satisfied = (res == 0) || ((res == 1) && !thisIsMajor); ckfree(reqi); return satisfied; } /* Exactly one dash is present (Assumption of valid syntax). Copy the req, * split at the location of dash and check that both parts are * versions. Note that the max part can be empty. */ DupString(buf, req); dash = buf + (dash - req); *dash = '\0'; /* buf now <=> min part */ dash ++; /* dash now <=> max part */ if (*dash == '\0') { /* We have a min, but no max. For the comparison we generate the * internal rep, padded with 'a0' i.e. '-2'. */ /* No max part, unbound */ CheckVersionAndConvert (NULL, buf, &min, NULL); strcat (min, " -2"); satisfied = (CompareVersions(havei, min, NULL) >= 0); ckfree(min); ckfree(buf); return satisfied; } /* We have both min and max, and generate their internal reps. * When identical we compare as is, otherwise we pad with 'a0' * to ove the range a bit. */ CheckVersionAndConvert (NULL, buf, &min, NULL); CheckVersionAndConvert (NULL, dash, &max, NULL); if (CompareVersions(min, max, NULL) == 0) { satisfied = (CompareVersions(min, havei, NULL) == 0); } else { strcat (min, " -2"); strcat (max, " -2"); satisfied = ((CompareVersions(min, havei, NULL) <= 0) && (CompareVersions(havei, max, NULL) < 0)); } ckfree(min); ckfree(max); ckfree(buf); return satisfied; } /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ #endif tcl8.4.20/generic/tcl.decls0000644003604700454610000014070612133546537014140 0ustar dgp771div# tcl.decls -- # # This file contains the declarations for all supported public # functions that are exported by the Tcl library via the stubs table. # This file is used to generate the tclDecls.h, tclPlatDecls.h, # tclStub.c, and tclPlatStub.c files. # # Copyright (c) 1998-1999 by Scriptics Corporation. # Copyright (c) 2001, 2002 by Kevin B. Kenny. All rights reserved. # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. library tcl # Define the tcl interface with several sub interfaces: # tclPlat - platform specific public # tclInt - generic private # tclPlatInt - platform specific private interface tcl hooks {tclPlat tclInt tclIntPlat} # Declare each of the functions in the public Tcl interface. Note that # the an index should never be reused for a different function in order # to preserve backwards compatibility. declare 0 { int Tcl_PkgProvideEx(Tcl_Interp *interp, const char *name, const char *version, ClientData clientData) } declare 1 { CONST84_RETURN char *Tcl_PkgRequireEx(Tcl_Interp *interp, const char *name, const char *version, int exact, ClientData *clientDataPtr) } declare 2 { void Tcl_Panic(const char *format, ...) } declare 3 { char *Tcl_Alloc(unsigned int size) } declare 4 { void Tcl_Free(char *ptr) } declare 5 { char *Tcl_Realloc(char *ptr, unsigned int size) } declare 6 { char *Tcl_DbCkalloc(unsigned int size, const char *file, int line) } declare 7 { void Tcl_DbCkfree(char *ptr, const char *file, int line) } declare 8 { char *Tcl_DbCkrealloc(char *ptr, unsigned int size, const char *file, int line) } # Tcl_CreateFileHandler and Tcl_DeleteFileHandler are only available on unix, # but they are part of the old generic interface, so we include them here for # compatibility reasons. declare 9 unix { void Tcl_CreateFileHandler(int fd, int mask, Tcl_FileProc *proc, ClientData clientData) } declare 10 unix { void Tcl_DeleteFileHandler(int fd) } declare 11 { void Tcl_SetTimer(Tcl_Time *timePtr) } declare 12 { void Tcl_Sleep(int ms) } declare 13 { int Tcl_WaitForEvent(Tcl_Time *timePtr) } declare 14 { int Tcl_AppendAllObjTypes(Tcl_Interp *interp, Tcl_Obj *objPtr) } declare 15 { void Tcl_AppendStringsToObj(Tcl_Obj *objPtr, ...) } declare 16 { void Tcl_AppendToObj(Tcl_Obj *objPtr, const char *bytes, int length) } declare 17 { Tcl_Obj *Tcl_ConcatObj(int objc, Tcl_Obj *const objv[]) } declare 18 { int Tcl_ConvertToType(Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_ObjType *typePtr) } declare 19 { void Tcl_DbDecrRefCount(Tcl_Obj *objPtr, const char *file, int line) } declare 20 { void Tcl_DbIncrRefCount(Tcl_Obj *objPtr, const char *file, int line) } declare 21 { int Tcl_DbIsShared(Tcl_Obj *objPtr, const char *file, int line) } declare 22 { Tcl_Obj *Tcl_DbNewBooleanObj(int boolValue, const char *file, int line) } declare 23 { Tcl_Obj *Tcl_DbNewByteArrayObj(const unsigned char *bytes, int length, const char *file, int line) } declare 24 { Tcl_Obj *Tcl_DbNewDoubleObj(double doubleValue, const char *file, int line) } declare 25 { Tcl_Obj *Tcl_DbNewListObj(int objc, Tcl_Obj *const *objv, const char *file, int line) } declare 26 { Tcl_Obj *Tcl_DbNewLongObj(long longValue, const char *file, int line) } declare 27 { Tcl_Obj *Tcl_DbNewObj(const char *file, int line) } declare 28 { Tcl_Obj *Tcl_DbNewStringObj(const char *bytes, int length, const char *file, int line) } declare 29 { Tcl_Obj *Tcl_DuplicateObj(Tcl_Obj *objPtr) } declare 30 { void TclFreeObj(Tcl_Obj *objPtr) } declare 31 { int Tcl_GetBoolean(Tcl_Interp *interp, const char *src, int *boolPtr) } declare 32 { int Tcl_GetBooleanFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, int *boolPtr) } declare 33 { unsigned char *Tcl_GetByteArrayFromObj(Tcl_Obj *objPtr, int *lengthPtr) } declare 34 { int Tcl_GetDouble(Tcl_Interp *interp, const char *src, double *doublePtr) } declare 35 { int Tcl_GetDoubleFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, double *doublePtr) } declare 36 { int Tcl_GetIndexFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, CONST84 char **tablePtr, const char *msg, int flags, int *indexPtr) } declare 37 { int Tcl_GetInt(Tcl_Interp *interp, const char *src, int *intPtr) } declare 38 { int Tcl_GetIntFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, int *intPtr) } declare 39 { int Tcl_GetLongFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, long *longPtr) } declare 40 { Tcl_ObjType *Tcl_GetObjType(const char *typeName) } declare 41 { char *Tcl_GetStringFromObj(Tcl_Obj *objPtr, int *lengthPtr) } declare 42 { void Tcl_InvalidateStringRep(Tcl_Obj *objPtr) } declare 43 { int Tcl_ListObjAppendList(Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Obj *elemListPtr) } declare 44 { int Tcl_ListObjAppendElement(Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Obj *objPtr) } declare 45 { int Tcl_ListObjGetElements(Tcl_Interp *interp, Tcl_Obj *listPtr, int *objcPtr, Tcl_Obj ***objvPtr) } declare 46 { int Tcl_ListObjIndex(Tcl_Interp *interp, Tcl_Obj *listPtr, int index, Tcl_Obj **objPtrPtr) } declare 47 { int Tcl_ListObjLength(Tcl_Interp *interp, Tcl_Obj *listPtr, int *lengthPtr) } declare 48 { int Tcl_ListObjReplace(Tcl_Interp *interp, Tcl_Obj *listPtr, int first, int count, int objc, Tcl_Obj *const objv[]) } declare 49 { Tcl_Obj *Tcl_NewBooleanObj(int boolValue) } declare 50 { Tcl_Obj *Tcl_NewByteArrayObj(const unsigned char *bytes, int length) } declare 51 { Tcl_Obj *Tcl_NewDoubleObj(double doubleValue) } declare 52 { Tcl_Obj *Tcl_NewIntObj(int intValue) } declare 53 { Tcl_Obj *Tcl_NewListObj(int objc, Tcl_Obj *const objv[]) } declare 54 { Tcl_Obj *Tcl_NewLongObj(long longValue) } declare 55 { Tcl_Obj *Tcl_NewObj(void) } declare 56 { Tcl_Obj *Tcl_NewStringObj(const char *bytes, int length) } declare 57 { void Tcl_SetBooleanObj(Tcl_Obj *objPtr, int boolValue) } declare 58 { unsigned char *Tcl_SetByteArrayLength(Tcl_Obj *objPtr, int length) } declare 59 { void Tcl_SetByteArrayObj(Tcl_Obj *objPtr, const unsigned char *bytes, int length) } declare 60 { void Tcl_SetDoubleObj(Tcl_Obj *objPtr, double doubleValue) } declare 61 { void Tcl_SetIntObj(Tcl_Obj *objPtr, int intValue) } declare 62 { void Tcl_SetListObj(Tcl_Obj *objPtr, int objc, Tcl_Obj *const objv[]) } declare 63 { void Tcl_SetLongObj(Tcl_Obj *objPtr, long longValue) } declare 64 { void Tcl_SetObjLength(Tcl_Obj *objPtr, int length) } declare 65 { void Tcl_SetStringObj(Tcl_Obj *objPtr, const char *bytes, int length) } declare 66 { void Tcl_AddErrorInfo(Tcl_Interp *interp, const char *message) } declare 67 { void Tcl_AddObjErrorInfo(Tcl_Interp *interp, const char *message, int length) } declare 68 { void Tcl_AllowExceptions(Tcl_Interp *interp) } declare 69 { void Tcl_AppendElement(Tcl_Interp *interp, const char *element) } declare 70 { void Tcl_AppendResult(Tcl_Interp *interp, ...) } declare 71 { Tcl_AsyncHandler Tcl_AsyncCreate(Tcl_AsyncProc *proc, ClientData clientData) } declare 72 { void Tcl_AsyncDelete(Tcl_AsyncHandler async) } declare 73 { int Tcl_AsyncInvoke(Tcl_Interp *interp, int code) } declare 74 { void Tcl_AsyncMark(Tcl_AsyncHandler async) } declare 75 { int Tcl_AsyncReady(void) } declare 76 { void Tcl_BackgroundError(Tcl_Interp *interp) } declare 77 { char Tcl_Backslash(const char *src, int *readPtr) } declare 78 { int Tcl_BadChannelOption(Tcl_Interp *interp, const char *optionName, const char *optionList) } declare 79 { void Tcl_CallWhenDeleted(Tcl_Interp *interp, Tcl_InterpDeleteProc *proc, ClientData clientData) } declare 80 { void Tcl_CancelIdleCall(Tcl_IdleProc *idleProc, ClientData clientData) } declare 81 { int Tcl_Close(Tcl_Interp *interp, Tcl_Channel chan) } declare 82 { int Tcl_CommandComplete(const char *cmd) } declare 83 { char *Tcl_Concat(int argc, CONST84 char *const *argv) } declare 84 { int Tcl_ConvertElement(const char *src, char *dst, int flags) } declare 85 { int Tcl_ConvertCountedElement(const char *src, int length, char *dst, int flags) } declare 86 { int Tcl_CreateAlias(Tcl_Interp *slave, const char *slaveCmd, Tcl_Interp *target, const char *targetCmd, int argc, CONST84 char *const *argv) } declare 87 { int Tcl_CreateAliasObj(Tcl_Interp *slave, const char *slaveCmd, Tcl_Interp *target, const char *targetCmd, int objc, Tcl_Obj *const objv[]) } declare 88 { Tcl_Channel Tcl_CreateChannel(Tcl_ChannelType *typePtr, const char *chanName, ClientData instanceData, int mask) } declare 89 { void Tcl_CreateChannelHandler(Tcl_Channel chan, int mask, Tcl_ChannelProc *proc, ClientData clientData) } declare 90 { void Tcl_CreateCloseHandler(Tcl_Channel chan, Tcl_CloseProc *proc, ClientData clientData) } declare 91 { Tcl_Command Tcl_CreateCommand(Tcl_Interp *interp, const char *cmdName, Tcl_CmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *deleteProc) } declare 92 { void Tcl_CreateEventSource(Tcl_EventSetupProc *setupProc, Tcl_EventCheckProc *checkProc, ClientData clientData) } declare 93 { void Tcl_CreateExitHandler(Tcl_ExitProc *proc, ClientData clientData) } declare 94 { Tcl_Interp *Tcl_CreateInterp(void) } declare 95 { void Tcl_CreateMathFunc(Tcl_Interp *interp, const char *name, int numArgs, Tcl_ValueType *argTypes, Tcl_MathProc *proc, ClientData clientData) } declare 96 { Tcl_Command Tcl_CreateObjCommand(Tcl_Interp *interp, const char *cmdName, Tcl_ObjCmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *deleteProc) } declare 97 { Tcl_Interp *Tcl_CreateSlave(Tcl_Interp *interp, const char *slaveName, int isSafe) } declare 98 { Tcl_TimerToken Tcl_CreateTimerHandler(int milliseconds, Tcl_TimerProc *proc, ClientData clientData) } declare 99 { Tcl_Trace Tcl_CreateTrace(Tcl_Interp *interp, int level, Tcl_CmdTraceProc *proc, ClientData clientData) } declare 100 { void Tcl_DeleteAssocData(Tcl_Interp *interp, const char *name) } declare 101 { void Tcl_DeleteChannelHandler(Tcl_Channel chan, Tcl_ChannelProc *proc, ClientData clientData) } declare 102 { void Tcl_DeleteCloseHandler(Tcl_Channel chan, Tcl_CloseProc *proc, ClientData clientData) } declare 103 { int Tcl_DeleteCommand(Tcl_Interp *interp, const char *cmdName) } declare 104 { int Tcl_DeleteCommandFromToken(Tcl_Interp *interp, Tcl_Command command) } declare 105 { void Tcl_DeleteEvents(Tcl_EventDeleteProc *proc, ClientData clientData) } declare 106 { void Tcl_DeleteEventSource(Tcl_EventSetupProc *setupProc, Tcl_EventCheckProc *checkProc, ClientData clientData) } declare 107 { void Tcl_DeleteExitHandler(Tcl_ExitProc *proc, ClientData clientData) } declare 108 { void Tcl_DeleteHashEntry(Tcl_HashEntry *entryPtr) } declare 109 { void Tcl_DeleteHashTable(Tcl_HashTable *tablePtr) } declare 110 { void Tcl_DeleteInterp(Tcl_Interp *interp) } declare 111 { void Tcl_DetachPids(int numPids, Tcl_Pid *pidPtr) } declare 112 { void Tcl_DeleteTimerHandler(Tcl_TimerToken token) } declare 113 { void Tcl_DeleteTrace(Tcl_Interp *interp, Tcl_Trace trace) } declare 114 { void Tcl_DontCallWhenDeleted(Tcl_Interp *interp, Tcl_InterpDeleteProc *proc, ClientData clientData) } declare 115 { int Tcl_DoOneEvent(int flags) } declare 116 { void Tcl_DoWhenIdle(Tcl_IdleProc *proc, ClientData clientData) } declare 117 { char *Tcl_DStringAppend(Tcl_DString *dsPtr, const char *bytes, int length) } declare 118 { char *Tcl_DStringAppendElement(Tcl_DString *dsPtr, const char *element) } declare 119 { void Tcl_DStringEndSublist(Tcl_DString *dsPtr) } declare 120 { void Tcl_DStringFree(Tcl_DString *dsPtr) } declare 121 { void Tcl_DStringGetResult(Tcl_Interp *interp, Tcl_DString *dsPtr) } declare 122 { void Tcl_DStringInit(Tcl_DString *dsPtr) } declare 123 { void Tcl_DStringResult(Tcl_Interp *interp, Tcl_DString *dsPtr) } declare 124 { void Tcl_DStringSetLength(Tcl_DString *dsPtr, int length) } declare 125 { void Tcl_DStringStartSublist(Tcl_DString *dsPtr) } declare 126 { int Tcl_Eof(Tcl_Channel chan) } declare 127 { CONST84_RETURN char *Tcl_ErrnoId(void) } declare 128 { CONST84_RETURN char *Tcl_ErrnoMsg(int err) } declare 129 { int Tcl_Eval(Tcl_Interp *interp, const char *script) } # This is obsolete, use Tcl_FSEvalFile declare 130 { int Tcl_EvalFile(Tcl_Interp *interp, const char *fileName) } declare 131 { int Tcl_EvalObj(Tcl_Interp *interp, Tcl_Obj *objPtr) } declare 132 { void Tcl_EventuallyFree(ClientData clientData, Tcl_FreeProc *freeProc) } declare 133 { void Tcl_Exit(int status) } declare 134 { int Tcl_ExposeCommand(Tcl_Interp *interp, const char *hiddenCmdToken, const char *cmdName) } declare 135 { int Tcl_ExprBoolean(Tcl_Interp *interp, const char *expr, int *ptr) } declare 136 { int Tcl_ExprBooleanObj(Tcl_Interp *interp, Tcl_Obj *objPtr, int *ptr) } declare 137 { int Tcl_ExprDouble(Tcl_Interp *interp, const char *expr, double *ptr) } declare 138 { int Tcl_ExprDoubleObj(Tcl_Interp *interp, Tcl_Obj *objPtr, double *ptr) } declare 139 { int Tcl_ExprLong(Tcl_Interp *interp, const char *expr, long *ptr) } declare 140 { int Tcl_ExprLongObj(Tcl_Interp *interp, Tcl_Obj *objPtr, long *ptr) } declare 141 { int Tcl_ExprObj(Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Obj **resultPtrPtr) } declare 142 { int Tcl_ExprString(Tcl_Interp *interp, const char *expr) } declare 143 { void Tcl_Finalize(void) } declare 144 { void Tcl_FindExecutable(const char *argv0) } declare 145 { Tcl_HashEntry *Tcl_FirstHashEntry(Tcl_HashTable *tablePtr, Tcl_HashSearch *searchPtr) } declare 146 { int Tcl_Flush(Tcl_Channel chan) } declare 147 { void Tcl_FreeResult(Tcl_Interp *interp) } declare 148 { int Tcl_GetAlias(Tcl_Interp *interp, const char *slaveCmd, Tcl_Interp **targetInterpPtr, CONST84 char **targetCmdPtr, int *argcPtr, CONST84 char ***argvPtr) } declare 149 { int Tcl_GetAliasObj(Tcl_Interp *interp, const char *slaveCmd, Tcl_Interp **targetInterpPtr, CONST84 char **targetCmdPtr, int *objcPtr, Tcl_Obj ***objv) } declare 150 { ClientData Tcl_GetAssocData(Tcl_Interp *interp, const char *name, Tcl_InterpDeleteProc **procPtr) } declare 151 { Tcl_Channel Tcl_GetChannel(Tcl_Interp *interp, const char *chanName, int *modePtr) } declare 152 { int Tcl_GetChannelBufferSize(Tcl_Channel chan) } declare 153 { int Tcl_GetChannelHandle(Tcl_Channel chan, int direction, ClientData *handlePtr) } declare 154 { ClientData Tcl_GetChannelInstanceData(Tcl_Channel chan) } declare 155 { int Tcl_GetChannelMode(Tcl_Channel chan) } declare 156 { CONST84_RETURN char *Tcl_GetChannelName(Tcl_Channel chan) } declare 157 { int Tcl_GetChannelOption(Tcl_Interp *interp, Tcl_Channel chan, const char *optionName, Tcl_DString *dsPtr) } declare 158 { Tcl_ChannelType *Tcl_GetChannelType(Tcl_Channel chan) } declare 159 { int Tcl_GetCommandInfo(Tcl_Interp *interp, const char *cmdName, Tcl_CmdInfo *infoPtr) } declare 160 { CONST84_RETURN char *Tcl_GetCommandName(Tcl_Interp *interp, Tcl_Command command) } declare 161 { int Tcl_GetErrno(void) } declare 162 { CONST84_RETURN char *Tcl_GetHostName(void) } declare 163 { int Tcl_GetInterpPath(Tcl_Interp *askInterp, Tcl_Interp *slaveInterp) } declare 164 { Tcl_Interp *Tcl_GetMaster(Tcl_Interp *interp) } declare 165 { const char *Tcl_GetNameOfExecutable(void) } declare 166 { Tcl_Obj *Tcl_GetObjResult(Tcl_Interp *interp) } # Tcl_GetOpenFile is only available on unix, but it is a part of the old # generic interface, so we inlcude it here for compatibility reasons. declare 167 unix { int Tcl_GetOpenFile(Tcl_Interp *interp, const char *chanID, int forWriting, int checkUsage, ClientData *filePtr) } # Obsolete. Should now use Tcl_FSGetPathType which is objectified # and therefore usually faster. declare 168 { Tcl_PathType Tcl_GetPathType(const char *path) } declare 169 { int Tcl_Gets(Tcl_Channel chan, Tcl_DString *dsPtr) } declare 170 { int Tcl_GetsObj(Tcl_Channel chan, Tcl_Obj *objPtr) } declare 171 { int Tcl_GetServiceMode(void) } declare 172 { Tcl_Interp *Tcl_GetSlave(Tcl_Interp *interp, const char *slaveName) } declare 173 { Tcl_Channel Tcl_GetStdChannel(int type) } declare 174 { CONST84_RETURN char *Tcl_GetStringResult(Tcl_Interp *interp) } declare 175 { CONST84_RETURN char *Tcl_GetVar(Tcl_Interp *interp, const char *varName, int flags) } declare 176 { CONST84_RETURN char *Tcl_GetVar2(Tcl_Interp *interp, const char *part1, const char *part2, int flags) } declare 177 { int Tcl_GlobalEval(Tcl_Interp *interp, const char *command) } declare 178 { int Tcl_GlobalEvalObj(Tcl_Interp *interp, Tcl_Obj *objPtr) } declare 179 { int Tcl_HideCommand(Tcl_Interp *interp, const char *cmdName, const char *hiddenCmdToken) } declare 180 { int Tcl_Init(Tcl_Interp *interp) } declare 181 { void Tcl_InitHashTable(Tcl_HashTable *tablePtr, int keyType) } declare 182 { int Tcl_InputBlocked(Tcl_Channel chan) } declare 183 { int Tcl_InputBuffered(Tcl_Channel chan) } declare 184 { int Tcl_InterpDeleted(Tcl_Interp *interp) } declare 185 { int Tcl_IsSafe(Tcl_Interp *interp) } # Obsolete, use Tcl_FSJoinPath declare 186 { char *Tcl_JoinPath(int argc, CONST84 char *const *argv, Tcl_DString *resultPtr) } declare 187 { int Tcl_LinkVar(Tcl_Interp *interp, const char *varName, char *addr, int type) } # This slot is reserved for use by the plus patch: # declare 188 { # Tcl_MainLoop # } declare 189 { Tcl_Channel Tcl_MakeFileChannel(ClientData handle, int mode) } declare 190 { int Tcl_MakeSafe(Tcl_Interp *interp) } declare 191 { Tcl_Channel Tcl_MakeTcpClientChannel(ClientData tcpSocket) } declare 192 { char *Tcl_Merge(int argc, CONST84 char *const *argv) } declare 193 { Tcl_HashEntry *Tcl_NextHashEntry(Tcl_HashSearch *searchPtr) } declare 194 { void Tcl_NotifyChannel(Tcl_Channel channel, int mask) } declare 195 { Tcl_Obj *Tcl_ObjGetVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, int flags) } declare 196 { Tcl_Obj *Tcl_ObjSetVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, Tcl_Obj *newValuePtr, int flags) } declare 197 { Tcl_Channel Tcl_OpenCommandChannel(Tcl_Interp *interp, int argc, CONST84 char **argv, int flags) } # This is obsolete, use Tcl_FSOpenFileChannel declare 198 { Tcl_Channel Tcl_OpenFileChannel(Tcl_Interp *interp, const char *fileName, const char *modeString, int permissions) } declare 199 { Tcl_Channel Tcl_OpenTcpClient(Tcl_Interp *interp, int port, const char *address, const char *myaddr, int myport, int async) } declare 200 { Tcl_Channel Tcl_OpenTcpServer(Tcl_Interp *interp, int port, const char *host, Tcl_TcpAcceptProc *acceptProc, ClientData callbackData) } declare 201 { void Tcl_Preserve(ClientData data) } declare 202 { void Tcl_PrintDouble(Tcl_Interp *interp, double value, char *dst) } declare 203 { int Tcl_PutEnv(const char *assignment) } declare 204 { CONST84_RETURN char *Tcl_PosixError(Tcl_Interp *interp) } declare 205 { void Tcl_QueueEvent(Tcl_Event *evPtr, Tcl_QueuePosition position) } declare 206 { int Tcl_Read(Tcl_Channel chan, char *bufPtr, int toRead) } declare 207 { void Tcl_ReapDetachedProcs(void) } declare 208 { int Tcl_RecordAndEval(Tcl_Interp *interp, const char *cmd, int flags) } declare 209 { int Tcl_RecordAndEvalObj(Tcl_Interp *interp, Tcl_Obj *cmdPtr, int flags) } declare 210 { void Tcl_RegisterChannel(Tcl_Interp *interp, Tcl_Channel chan) } declare 211 { void Tcl_RegisterObjType(Tcl_ObjType *typePtr) } declare 212 { Tcl_RegExp Tcl_RegExpCompile(Tcl_Interp *interp, const char *pattern) } declare 213 { int Tcl_RegExpExec(Tcl_Interp *interp, Tcl_RegExp regexp, const char *text, const char *start) } declare 214 { int Tcl_RegExpMatch(Tcl_Interp *interp, const char *text, const char *pattern) } declare 215 { void Tcl_RegExpRange(Tcl_RegExp regexp, int index, CONST84 char **startPtr, CONST84 char **endPtr) } declare 216 { void Tcl_Release(ClientData clientData) } declare 217 { void Tcl_ResetResult(Tcl_Interp *interp) } declare 218 { int Tcl_ScanElement(const char *src, int *flagPtr) } declare 219 { int Tcl_ScanCountedElement(const char *src, int length, int *flagPtr) } # Obsolete declare 220 { int Tcl_SeekOld(Tcl_Channel chan, int offset, int mode) } declare 221 { int Tcl_ServiceAll(void) } declare 222 { int Tcl_ServiceEvent(int flags) } declare 223 { void Tcl_SetAssocData(Tcl_Interp *interp, const char *name, Tcl_InterpDeleteProc *proc, ClientData clientData) } declare 224 { void Tcl_SetChannelBufferSize(Tcl_Channel chan, int sz) } declare 225 { int Tcl_SetChannelOption(Tcl_Interp *interp, Tcl_Channel chan, const char *optionName, const char *newValue) } declare 226 { int Tcl_SetCommandInfo(Tcl_Interp *interp, const char *cmdName, const Tcl_CmdInfo *infoPtr) } declare 227 { void Tcl_SetErrno(int err) } declare 228 { void Tcl_SetErrorCode(Tcl_Interp *interp, ...) } declare 229 { void Tcl_SetMaxBlockTime(Tcl_Time *timePtr) } declare 230 { void Tcl_SetPanicProc(Tcl_PanicProc *panicProc) } declare 231 { int Tcl_SetRecursionLimit(Tcl_Interp *interp, int depth) } declare 232 { void Tcl_SetResult(Tcl_Interp *interp, char *result, Tcl_FreeProc *freeProc) } declare 233 { int Tcl_SetServiceMode(int mode) } declare 234 { void Tcl_SetObjErrorCode(Tcl_Interp *interp, Tcl_Obj *errorObjPtr) } declare 235 { void Tcl_SetObjResult(Tcl_Interp *interp, Tcl_Obj *resultObjPtr) } declare 236 { void Tcl_SetStdChannel(Tcl_Channel channel, int type) } declare 237 { CONST84_RETURN char *Tcl_SetVar(Tcl_Interp *interp, const char *varName, const char *newValue, int flags) } declare 238 { CONST84_RETURN char *Tcl_SetVar2(Tcl_Interp *interp, const char *part1, const char *part2, const char *newValue, int flags) } declare 239 { CONST84_RETURN char *Tcl_SignalId(int sig) } declare 240 { CONST84_RETURN char *Tcl_SignalMsg(int sig) } declare 241 { void Tcl_SourceRCFile(Tcl_Interp *interp) } declare 242 { int Tcl_SplitList(Tcl_Interp *interp, const char *listStr, int *argcPtr, CONST84 char ***argvPtr) } # Obsolete, use Tcl_FSSplitPath declare 243 { void Tcl_SplitPath(const char *path, int *argcPtr, CONST84 char ***argvPtr) } declare 244 { void Tcl_StaticPackage(Tcl_Interp *interp, const char *pkgName, Tcl_PackageInitProc *initProc, Tcl_PackageInitProc *safeInitProc) } declare 245 { int Tcl_StringMatch(const char *str, const char *pattern) } # Obsolete declare 246 { int Tcl_TellOld(Tcl_Channel chan) } declare 247 { int Tcl_TraceVar(Tcl_Interp *interp, const char *varName, int flags, Tcl_VarTraceProc *proc, ClientData clientData) } declare 248 { int Tcl_TraceVar2(Tcl_Interp *interp, const char *part1, const char *part2, int flags, Tcl_VarTraceProc *proc, ClientData clientData) } declare 249 { char *Tcl_TranslateFileName(Tcl_Interp *interp, const char *name, Tcl_DString *bufferPtr) } declare 250 { int Tcl_Ungets(Tcl_Channel chan, const char *str, int len, int atHead) } declare 251 { void Tcl_UnlinkVar(Tcl_Interp *interp, const char *varName) } declare 252 { int Tcl_UnregisterChannel(Tcl_Interp *interp, Tcl_Channel chan) } declare 253 { int Tcl_UnsetVar(Tcl_Interp *interp, const char *varName, int flags) } declare 254 { int Tcl_UnsetVar2(Tcl_Interp *interp, const char *part1, const char *part2, int flags) } declare 255 { void Tcl_UntraceVar(Tcl_Interp *interp, const char *varName, int flags, Tcl_VarTraceProc *proc, ClientData clientData) } declare 256 { void Tcl_UntraceVar2(Tcl_Interp *interp, const char *part1, const char *part2, int flags, Tcl_VarTraceProc *proc, ClientData clientData) } declare 257 { void Tcl_UpdateLinkedVar(Tcl_Interp *interp, const char *varName) } declare 258 { int Tcl_UpVar(Tcl_Interp *interp, const char *frameName, const char *varName, const char *localName, int flags) } declare 259 { int Tcl_UpVar2(Tcl_Interp *interp, const char *frameName, const char *part1, const char *part2, const char *localName, int flags) } declare 260 { int Tcl_VarEval(Tcl_Interp *interp, ...) } declare 261 { ClientData Tcl_VarTraceInfo(Tcl_Interp *interp, const char *varName, int flags, Tcl_VarTraceProc *procPtr, ClientData prevClientData) } declare 262 { ClientData Tcl_VarTraceInfo2(Tcl_Interp *interp, const char *part1, const char *part2, int flags, Tcl_VarTraceProc *procPtr, ClientData prevClientData) } declare 263 { int Tcl_Write(Tcl_Channel chan, const char *s, int slen) } declare 264 { void Tcl_WrongNumArgs(Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], const char *message) } declare 265 { int Tcl_DumpActiveMemory(const char *fileName) } declare 266 { void Tcl_ValidateAllMemory(const char *file, int line) } declare 267 { void Tcl_AppendResultVA(Tcl_Interp *interp, va_list argList) } declare 268 { void Tcl_AppendStringsToObjVA(Tcl_Obj *objPtr, va_list argList) } declare 269 { char *Tcl_HashStats(Tcl_HashTable *tablePtr) } declare 270 { CONST84_RETURN char *Tcl_ParseVar(Tcl_Interp *interp, const char *start, CONST84 char **termPtr) } declare 271 { CONST84_RETURN char *Tcl_PkgPresent(Tcl_Interp *interp, const char *name, const char *version, int exact) } declare 272 { CONST84_RETURN char *Tcl_PkgPresentEx(Tcl_Interp *interp, const char *name, const char *version, int exact, ClientData *clientDataPtr) } declare 273 { int Tcl_PkgProvide(Tcl_Interp *interp, const char *name, const char *version) } # TIP #268: The internally used new Require function is in slot 573. declare 274 { CONST84_RETURN char *Tcl_PkgRequire(Tcl_Interp *interp, const char *name, const char *version, int exact) } declare 275 { void Tcl_SetErrorCodeVA(Tcl_Interp *interp, va_list argList) } declare 276 { int Tcl_VarEvalVA(Tcl_Interp *interp, va_list argList) } declare 277 { Tcl_Pid Tcl_WaitPid(Tcl_Pid pid, int *statPtr, int options) } declare 278 { void Tcl_PanicVA(const char *format, va_list argList) } declare 279 { void Tcl_GetVersion(int *major, int *minor, int *patchLevel, int *type) } declare 280 { void Tcl_InitMemory(Tcl_Interp *interp) } # Andreas Kupries , 03/21/1999 # "Trf-Patch for filtering channels" # # C-Level API for (un)stacking of channels. This allows the introduction # of filtering channels with relatively little changes to the core. # This patch was created in cooperation with Jan Nijtmans j.nijtmans@chello.nl # and is therefore part of his plus-patches too. # # It would have been possible to place the following definitions according # to the alphabetical order used elsewhere in this file, but I decided # against that to ease the maintenance of the patch across new tcl versions # (patch usually has no problems to integrate the patch file for the last # version into the new one). declare 281 { Tcl_Channel Tcl_StackChannel(Tcl_Interp *interp, Tcl_ChannelType *typePtr, ClientData instanceData, int mask, Tcl_Channel prevChan) } declare 282 { int Tcl_UnstackChannel(Tcl_Interp *interp, Tcl_Channel chan) } declare 283 { Tcl_Channel Tcl_GetStackedChannel(Tcl_Channel chan) } # 284 was reserved, but added in 8.4a2 declare 284 { void Tcl_SetMainLoop(Tcl_MainLoopProc *proc) } # Reserved for future use (8.0.x vs. 8.1) # declare 285 { # } # Added in 8.1: declare 286 { void Tcl_AppendObjToObj(Tcl_Obj *objPtr, Tcl_Obj *appendObjPtr) } declare 287 { Tcl_Encoding Tcl_CreateEncoding(Tcl_EncodingType *typePtr) } declare 288 { void Tcl_CreateThreadExitHandler(Tcl_ExitProc *proc, ClientData clientData) } declare 289 { void Tcl_DeleteThreadExitHandler(Tcl_ExitProc *proc, ClientData clientData) } declare 290 { void Tcl_DiscardResult(Tcl_SavedResult *statePtr) } declare 291 { int Tcl_EvalEx(Tcl_Interp *interp, const char *script, int numBytes, int flags) } declare 292 { int Tcl_EvalObjv(Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], int flags) } declare 293 { int Tcl_EvalObjEx(Tcl_Interp *interp, Tcl_Obj *objPtr, int flags) } declare 294 { void Tcl_ExitThread(int status) } declare 295 { int Tcl_ExternalToUtf(Tcl_Interp *interp, Tcl_Encoding encoding, const char *src, int srcLen, int flags, Tcl_EncodingState *statePtr, char *dst, int dstLen, int *srcReadPtr, int *dstWrotePtr, int *dstCharsPtr) } declare 296 { char *Tcl_ExternalToUtfDString(Tcl_Encoding encoding, const char *src, int srcLen, Tcl_DString *dsPtr) } declare 297 { void Tcl_FinalizeThread(void) } declare 298 { void Tcl_FinalizeNotifier(ClientData clientData) } declare 299 { void Tcl_FreeEncoding(Tcl_Encoding encoding) } declare 300 { Tcl_ThreadId Tcl_GetCurrentThread(void) } declare 301 { Tcl_Encoding Tcl_GetEncoding(Tcl_Interp *interp, const char *name) } declare 302 { CONST84_RETURN char *Tcl_GetEncodingName(Tcl_Encoding encoding) } declare 303 { void Tcl_GetEncodingNames(Tcl_Interp *interp) } declare 304 { int Tcl_GetIndexFromObjStruct(Tcl_Interp *interp, Tcl_Obj *objPtr, const void *tablePtr, int offset, const char *msg, int flags, int *indexPtr) } declare 305 { void *Tcl_GetThreadData(Tcl_ThreadDataKey *keyPtr, int size) } declare 306 { Tcl_Obj *Tcl_GetVar2Ex(Tcl_Interp *interp, const char *part1, const char *part2, int flags) } declare 307 { ClientData Tcl_InitNotifier(void) } declare 308 { void Tcl_MutexLock(Tcl_Mutex *mutexPtr) } declare 309 { void Tcl_MutexUnlock(Tcl_Mutex *mutexPtr) } declare 310 { void Tcl_ConditionNotify(Tcl_Condition *condPtr) } declare 311 { void Tcl_ConditionWait(Tcl_Condition *condPtr, Tcl_Mutex *mutexPtr, Tcl_Time *timePtr) } declare 312 { int Tcl_NumUtfChars(const char *src, int length) } declare 313 { int Tcl_ReadChars(Tcl_Channel channel, Tcl_Obj *objPtr, int charsToRead, int appendFlag) } declare 314 { void Tcl_RestoreResult(Tcl_Interp *interp, Tcl_SavedResult *statePtr) } declare 315 { void Tcl_SaveResult(Tcl_Interp *interp, Tcl_SavedResult *statePtr) } declare 316 { int Tcl_SetSystemEncoding(Tcl_Interp *interp, const char *name) } declare 317 { Tcl_Obj *Tcl_SetVar2Ex(Tcl_Interp *interp, const char *part1, const char *part2, Tcl_Obj *newValuePtr, int flags) } declare 318 { void Tcl_ThreadAlert(Tcl_ThreadId threadId) } declare 319 { void Tcl_ThreadQueueEvent(Tcl_ThreadId threadId, Tcl_Event *evPtr, Tcl_QueuePosition position) } declare 320 { Tcl_UniChar Tcl_UniCharAtIndex(const char *src, int index) } declare 321 { Tcl_UniChar Tcl_UniCharToLower(int ch) } declare 322 { Tcl_UniChar Tcl_UniCharToTitle(int ch) } declare 323 { Tcl_UniChar Tcl_UniCharToUpper(int ch) } declare 324 { int Tcl_UniCharToUtf(int ch, char *buf) } declare 325 { CONST84_RETURN char *Tcl_UtfAtIndex(const char *src, int index) } declare 326 { int Tcl_UtfCharComplete(const char *src, int length) } declare 327 { int Tcl_UtfBackslash(const char *src, int *readPtr, char *dst) } declare 328 { CONST84_RETURN char *Tcl_UtfFindFirst(const char *src, int ch) } declare 329 { CONST84_RETURN char *Tcl_UtfFindLast(const char *src, int ch) } declare 330 { CONST84_RETURN char *Tcl_UtfNext(const char *src) } declare 331 { CONST84_RETURN char *Tcl_UtfPrev(const char *src, const char *start) } declare 332 { int Tcl_UtfToExternal(Tcl_Interp *interp, Tcl_Encoding encoding, const char *src, int srcLen, int flags, Tcl_EncodingState *statePtr, char *dst, int dstLen, int *srcReadPtr, int *dstWrotePtr, int *dstCharsPtr) } declare 333 { char *Tcl_UtfToExternalDString(Tcl_Encoding encoding, const char *src, int srcLen, Tcl_DString *dsPtr) } declare 334 { int Tcl_UtfToLower(char *src) } declare 335 { int Tcl_UtfToTitle(char *src) } declare 336 { int Tcl_UtfToUniChar(const char *src, Tcl_UniChar *chPtr) } declare 337 { int Tcl_UtfToUpper(char *src) } declare 338 { int Tcl_WriteChars(Tcl_Channel chan, const char *src, int srcLen) } declare 339 { int Tcl_WriteObj(Tcl_Channel chan, Tcl_Obj *objPtr) } declare 340 { char *Tcl_GetString(Tcl_Obj *objPtr) } declare 341 { CONST84_RETURN char *Tcl_GetDefaultEncodingDir(void) } declare 342 { void Tcl_SetDefaultEncodingDir(const char *path) } declare 343 { void Tcl_AlertNotifier(ClientData clientData) } declare 344 { void Tcl_ServiceModeHook(int mode) } declare 345 { int Tcl_UniCharIsAlnum(int ch) } declare 346 { int Tcl_UniCharIsAlpha(int ch) } declare 347 { int Tcl_UniCharIsDigit(int ch) } declare 348 { int Tcl_UniCharIsLower(int ch) } declare 349 { int Tcl_UniCharIsSpace(int ch) } declare 350 { int Tcl_UniCharIsUpper(int ch) } declare 351 { int Tcl_UniCharIsWordChar(int ch) } declare 352 { int Tcl_UniCharLen(const Tcl_UniChar *uniStr) } declare 353 { int Tcl_UniCharNcmp(const Tcl_UniChar *ucs, const Tcl_UniChar *uct, unsigned long numChars) } declare 354 { char *Tcl_UniCharToUtfDString(const Tcl_UniChar *uniStr, int uniLength, Tcl_DString *dsPtr) } declare 355 { Tcl_UniChar *Tcl_UtfToUniCharDString(const char *src, int length, Tcl_DString *dsPtr) } declare 356 { Tcl_RegExp Tcl_GetRegExpFromObj(Tcl_Interp *interp, Tcl_Obj *patObj, int flags) } declare 357 { Tcl_Obj *Tcl_EvalTokens(Tcl_Interp *interp, Tcl_Token *tokenPtr, int count) } declare 358 { void Tcl_FreeParse(Tcl_Parse *parsePtr) } declare 359 { void Tcl_LogCommandInfo(Tcl_Interp *interp, const char *script, const char *command, int length) } declare 360 { int Tcl_ParseBraces(Tcl_Interp *interp, const char *start, int numBytes, Tcl_Parse *parsePtr, int append, CONST84 char **termPtr) } declare 361 { int Tcl_ParseCommand(Tcl_Interp *interp, const char *start, int numBytes, int nested, Tcl_Parse *parsePtr) } declare 362 { int Tcl_ParseExpr(Tcl_Interp *interp, const char *start, int numBytes, Tcl_Parse *parsePtr) } declare 363 { int Tcl_ParseQuotedString(Tcl_Interp *interp, const char *start, int numBytes, Tcl_Parse *parsePtr, int append, CONST84 char **termPtr) } declare 364 { int Tcl_ParseVarName(Tcl_Interp *interp, const char *start, int numBytes, Tcl_Parse *parsePtr, int append) } # These 4 functions are obsolete, use Tcl_FSGetCwd, Tcl_FSChdir, # Tcl_FSAccess and Tcl_FSStat declare 365 { char *Tcl_GetCwd(Tcl_Interp *interp, Tcl_DString *cwdPtr) } declare 366 { int Tcl_Chdir(const char *dirName) } declare 367 { int Tcl_Access(const char *path, int mode) } declare 368 { int Tcl_Stat(const char *path, struct stat *bufPtr) } declare 369 { int Tcl_UtfNcmp(const char *s1, const char *s2, unsigned long n) } declare 370 { int Tcl_UtfNcasecmp(const char *s1, const char *s2, unsigned long n) } declare 371 { int Tcl_StringCaseMatch(const char *str, const char *pattern, int nocase) } declare 372 { int Tcl_UniCharIsControl(int ch) } declare 373 { int Tcl_UniCharIsGraph(int ch) } declare 374 { int Tcl_UniCharIsPrint(int ch) } declare 375 { int Tcl_UniCharIsPunct(int ch) } declare 376 { int Tcl_RegExpExecObj(Tcl_Interp *interp, Tcl_RegExp regexp, Tcl_Obj *textObj, int offset, int nmatches, int flags) } declare 377 { void Tcl_RegExpGetInfo(Tcl_RegExp regexp, Tcl_RegExpInfo *infoPtr) } declare 378 { Tcl_Obj *Tcl_NewUnicodeObj(const Tcl_UniChar *unicode, int numChars) } declare 379 { void Tcl_SetUnicodeObj(Tcl_Obj *objPtr, const Tcl_UniChar *unicode, int numChars) } declare 380 { int Tcl_GetCharLength(Tcl_Obj *objPtr) } declare 381 { Tcl_UniChar Tcl_GetUniChar(Tcl_Obj *objPtr, int index) } declare 382 { Tcl_UniChar *Tcl_GetUnicode(Tcl_Obj *objPtr) } declare 383 { Tcl_Obj *Tcl_GetRange(Tcl_Obj *objPtr, int first, int last) } declare 384 { void Tcl_AppendUnicodeToObj(Tcl_Obj *objPtr, const Tcl_UniChar *unicode, int length) } declare 385 { int Tcl_RegExpMatchObj(Tcl_Interp *interp, Tcl_Obj *textObj, Tcl_Obj *patternObj) } declare 386 { void Tcl_SetNotifier(Tcl_NotifierProcs *notifierProcPtr) } declare 387 { Tcl_Mutex *Tcl_GetAllocMutex(void) } declare 388 { int Tcl_GetChannelNames(Tcl_Interp *interp) } declare 389 { int Tcl_GetChannelNamesEx(Tcl_Interp *interp, const char *pattern) } declare 390 { int Tcl_ProcObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) } declare 391 { void Tcl_ConditionFinalize(Tcl_Condition *condPtr) } declare 392 { void Tcl_MutexFinalize(Tcl_Mutex *mutex) } declare 393 { int Tcl_CreateThread(Tcl_ThreadId *idPtr, Tcl_ThreadCreateProc proc, ClientData clientData, int stackSize, int flags) } # Introduced in 8.3.2 declare 394 { int Tcl_ReadRaw(Tcl_Channel chan, char *dst, int bytesToRead) } declare 395 { int Tcl_WriteRaw(Tcl_Channel chan, const char *src, int srcLen) } declare 396 { Tcl_Channel Tcl_GetTopChannel(Tcl_Channel chan) } declare 397 { int Tcl_ChannelBuffered(Tcl_Channel chan) } declare 398 { CONST84_RETURN char *Tcl_ChannelName(Tcl_ChannelType *chanTypePtr) } declare 399 { Tcl_ChannelTypeVersion Tcl_ChannelVersion( Tcl_ChannelType *chanTypePtr) } declare 400 { Tcl_DriverBlockModeProc *Tcl_ChannelBlockModeProc( Tcl_ChannelType *chanTypePtr) } declare 401 { Tcl_DriverCloseProc *Tcl_ChannelCloseProc( Tcl_ChannelType *chanTypePtr) } declare 402 { Tcl_DriverClose2Proc *Tcl_ChannelClose2Proc( Tcl_ChannelType *chanTypePtr) } declare 403 { Tcl_DriverInputProc *Tcl_ChannelInputProc( Tcl_ChannelType *chanTypePtr) } declare 404 { Tcl_DriverOutputProc *Tcl_ChannelOutputProc( Tcl_ChannelType *chanTypePtr) } declare 405 { Tcl_DriverSeekProc *Tcl_ChannelSeekProc( Tcl_ChannelType *chanTypePtr) } declare 406 { Tcl_DriverSetOptionProc *Tcl_ChannelSetOptionProc( Tcl_ChannelType *chanTypePtr) } declare 407 { Tcl_DriverGetOptionProc *Tcl_ChannelGetOptionProc( Tcl_ChannelType *chanTypePtr) } declare 408 { Tcl_DriverWatchProc *Tcl_ChannelWatchProc( Tcl_ChannelType *chanTypePtr) } declare 409 { Tcl_DriverGetHandleProc *Tcl_ChannelGetHandleProc( Tcl_ChannelType *chanTypePtr) } declare 410 { Tcl_DriverFlushProc *Tcl_ChannelFlushProc( Tcl_ChannelType *chanTypePtr) } declare 411 { Tcl_DriverHandlerProc *Tcl_ChannelHandlerProc( Tcl_ChannelType *chanTypePtr) } # Introduced in 8.4a2 declare 412 { int Tcl_JoinThread(Tcl_ThreadId threadId, int *result) } declare 413 { int Tcl_IsChannelShared(Tcl_Channel channel) } declare 414 { int Tcl_IsChannelRegistered(Tcl_Interp *interp, Tcl_Channel channel) } declare 415 { void Tcl_CutChannel(Tcl_Channel channel) } declare 416 { void Tcl_SpliceChannel(Tcl_Channel channel) } declare 417 { void Tcl_ClearChannelHandlers(Tcl_Channel channel) } declare 418 { int Tcl_IsChannelExisting(const char *channelName) } declare 419 { int Tcl_UniCharNcasecmp(const Tcl_UniChar *ucs, const Tcl_UniChar *uct, unsigned long numChars) } declare 420 { int Tcl_UniCharCaseMatch(const Tcl_UniChar *uniStr, const Tcl_UniChar *uniPattern, int nocase) } declare 421 { Tcl_HashEntry *Tcl_FindHashEntry(Tcl_HashTable *tablePtr, const char *key) } declare 422 { Tcl_HashEntry *Tcl_CreateHashEntry(Tcl_HashTable *tablePtr, const char *key, int *newPtr) } declare 423 { void Tcl_InitCustomHashTable(Tcl_HashTable *tablePtr, int keyType, Tcl_HashKeyType *typePtr) } declare 424 { void Tcl_InitObjHashTable(Tcl_HashTable *tablePtr) } declare 425 { ClientData Tcl_CommandTraceInfo(Tcl_Interp *interp, const char *varName, int flags, Tcl_CommandTraceProc *procPtr, ClientData prevClientData) } declare 426 { int Tcl_TraceCommand(Tcl_Interp *interp, const char *varName, int flags, Tcl_CommandTraceProc *proc, ClientData clientData) } declare 427 { void Tcl_UntraceCommand(Tcl_Interp *interp, const char *varName, int flags, Tcl_CommandTraceProc *proc, ClientData clientData) } declare 428 { char *Tcl_AttemptAlloc(unsigned int size) } declare 429 { char *Tcl_AttemptDbCkalloc(unsigned int size, const char *file, int line) } declare 430 { char *Tcl_AttemptRealloc(char *ptr, unsigned int size) } declare 431 { char *Tcl_AttemptDbCkrealloc(char *ptr, unsigned int size, const char *file, int line) } declare 432 { int Tcl_AttemptSetObjLength(Tcl_Obj *objPtr, int length) } # TIP#10 (thread-aware channels) akupries declare 433 { Tcl_ThreadId Tcl_GetChannelThread(Tcl_Channel channel) } # introduced in 8.4a3 declare 434 { Tcl_UniChar *Tcl_GetUnicodeFromObj(Tcl_Obj *objPtr, int *lengthPtr) } # TIP#15 (math function introspection) dkf declare 435 { int Tcl_GetMathFuncInfo(Tcl_Interp *interp, const char *name, int *numArgsPtr, Tcl_ValueType **argTypesPtr, Tcl_MathProc **procPtr, ClientData *clientDataPtr) } declare 436 { Tcl_Obj *Tcl_ListMathFuncs(Tcl_Interp *interp, const char *pattern) } # TIP#36 (better access to 'subst') dkf declare 437 { Tcl_Obj *Tcl_SubstObj(Tcl_Interp *interp, Tcl_Obj *objPtr, int flags) } # TIP#17 (virtual filesystem layer) vdarley declare 438 { int Tcl_DetachChannel(Tcl_Interp *interp, Tcl_Channel channel) } declare 439 { int Tcl_IsStandardChannel(Tcl_Channel channel) } declare 440 { int Tcl_FSCopyFile(Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr) } declare 441 { int Tcl_FSCopyDirectory(Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr, Tcl_Obj **errorPtr) } declare 442 { int Tcl_FSCreateDirectory(Tcl_Obj *pathPtr) } declare 443 { int Tcl_FSDeleteFile(Tcl_Obj *pathPtr) } declare 444 { int Tcl_FSLoadFile(Tcl_Interp *interp, Tcl_Obj *pathPtr, const char *sym1, const char *sym2, Tcl_PackageInitProc **proc1Ptr, Tcl_PackageInitProc **proc2Ptr, Tcl_LoadHandle *handlePtr, Tcl_FSUnloadFileProc **unloadProcPtr) } declare 445 { int Tcl_FSMatchInDirectory(Tcl_Interp *interp, Tcl_Obj *result, Tcl_Obj *pathPtr, const char *pattern, Tcl_GlobTypeData *types) } declare 446 { Tcl_Obj *Tcl_FSLink(Tcl_Obj *pathPtr, Tcl_Obj *toPtr, int linkAction) } declare 447 { int Tcl_FSRemoveDirectory(Tcl_Obj *pathPtr, int recursive, Tcl_Obj **errorPtr) } declare 448 { int Tcl_FSRenameFile(Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr) } declare 449 { int Tcl_FSLstat(Tcl_Obj *pathPtr, Tcl_StatBuf *buf) } declare 450 { int Tcl_FSUtime(Tcl_Obj *pathPtr, struct utimbuf *tval) } declare 451 { int Tcl_FSFileAttrsGet(Tcl_Interp *interp, int index, Tcl_Obj *pathPtr, Tcl_Obj **objPtrRef) } declare 452 { int Tcl_FSFileAttrsSet(Tcl_Interp *interp, int index, Tcl_Obj *pathPtr, Tcl_Obj *objPtr) } declare 453 { const char **Tcl_FSFileAttrStrings(Tcl_Obj *pathPtr, Tcl_Obj **objPtrRef) } declare 454 { int Tcl_FSStat(Tcl_Obj *pathPtr, Tcl_StatBuf *buf) } declare 455 { int Tcl_FSAccess(Tcl_Obj *pathPtr, int mode) } declare 456 { Tcl_Channel Tcl_FSOpenFileChannel(Tcl_Interp *interp, Tcl_Obj *pathPtr, const char *modeString, int permissions) } declare 457 { Tcl_Obj *Tcl_FSGetCwd(Tcl_Interp *interp) } declare 458 { int Tcl_FSChdir(Tcl_Obj *pathPtr) } declare 459 { int Tcl_FSConvertToPathType(Tcl_Interp *interp, Tcl_Obj *pathPtr) } declare 460 { Tcl_Obj *Tcl_FSJoinPath(Tcl_Obj *listObj, int elements) } declare 461 { Tcl_Obj *Tcl_FSSplitPath(Tcl_Obj *pathPtr, int *lenPtr) } declare 462 { int Tcl_FSEqualPaths(Tcl_Obj *firstPtr, Tcl_Obj *secondPtr) } declare 463 { Tcl_Obj *Tcl_FSGetNormalizedPath(Tcl_Interp *interp, Tcl_Obj *pathPtr) } declare 464 { Tcl_Obj *Tcl_FSJoinToPath(Tcl_Obj *pathPtr, int objc, Tcl_Obj *const objv[]) } declare 465 { ClientData Tcl_FSGetInternalRep(Tcl_Obj *pathPtr, Tcl_Filesystem *fsPtr) } declare 466 { Tcl_Obj *Tcl_FSGetTranslatedPath(Tcl_Interp *interp, Tcl_Obj *pathPtr) } declare 467 { int Tcl_FSEvalFile(Tcl_Interp *interp, Tcl_Obj *fileName) } declare 468 { Tcl_Obj *Tcl_FSNewNativePath(Tcl_Filesystem *fromFilesystem, ClientData clientData) } declare 469 { const char *Tcl_FSGetNativePath(Tcl_Obj *pathPtr) } declare 470 { Tcl_Obj *Tcl_FSFileSystemInfo(Tcl_Obj *pathPtr) } declare 471 { Tcl_Obj *Tcl_FSPathSeparator(Tcl_Obj *pathPtr) } declare 472 { Tcl_Obj *Tcl_FSListVolumes(void) } declare 473 { int Tcl_FSRegister(ClientData clientData, Tcl_Filesystem *fsPtr) } declare 474 { int Tcl_FSUnregister(Tcl_Filesystem *fsPtr) } declare 475 { ClientData Tcl_FSData(Tcl_Filesystem *fsPtr) } declare 476 { const char *Tcl_FSGetTranslatedStringPath(Tcl_Interp *interp, Tcl_Obj *pathPtr) } declare 477 { Tcl_Filesystem *Tcl_FSGetFileSystemForPath(Tcl_Obj *pathPtr) } declare 478 { Tcl_PathType Tcl_FSGetPathType(Tcl_Obj *pathPtr) } # TIP#49 (detection of output buffering) akupries declare 479 { int Tcl_OutputBuffered(Tcl_Channel chan) } declare 480 { void Tcl_FSMountsChanged(Tcl_Filesystem *fsPtr) } # TIP#56 (evaluate a parsed script) msofer declare 481 { int Tcl_EvalTokensStandard(Tcl_Interp *interp, Tcl_Token *tokenPtr, int count) } # TIP#73 (access to current time) kbk declare 482 { void Tcl_GetTime(Tcl_Time *timeBuf) } # TIP#32 (object-enabled traces) kbk declare 483 { Tcl_Trace Tcl_CreateObjTrace(Tcl_Interp *interp, int level, int flags, Tcl_CmdObjTraceProc *objProc, ClientData clientData, Tcl_CmdObjTraceDeleteProc *delProc) } declare 484 { int Tcl_GetCommandInfoFromToken(Tcl_Command token, Tcl_CmdInfo *infoPtr) } declare 485 { int Tcl_SetCommandInfoFromToken(Tcl_Command token, const Tcl_CmdInfo *infoPtr) } ### New functions on 64-bit dev branch ### # TIP#72 (64-bit values) dkf declare 486 { Tcl_Obj *Tcl_DbNewWideIntObj(Tcl_WideInt wideValue, const char *file, int line) } declare 487 { int Tcl_GetWideIntFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_WideInt *widePtr) } declare 488 { Tcl_Obj *Tcl_NewWideIntObj(Tcl_WideInt wideValue) } declare 489 { void Tcl_SetWideIntObj(Tcl_Obj *objPtr, Tcl_WideInt wideValue) } declare 490 { Tcl_StatBuf *Tcl_AllocStatBuf(void) } declare 491 { Tcl_WideInt Tcl_Seek(Tcl_Channel chan, Tcl_WideInt offset, int mode) } declare 492 { Tcl_WideInt Tcl_Tell(Tcl_Channel chan) } # TIP#91 (back-compat enhancements for channels) dkf declare 493 { Tcl_DriverWideSeekProc *Tcl_ChannelWideSeekProc( Tcl_ChannelType *chanTypePtr) } # Slots 494 to 553 are taken already by 8.5 # #111 - Dicts (494 ... 504) # #59 - Config (505) # #139 - Namespace API (506 ... 517) # #137 - source -encoding (518) # #121 - ExitProc (519) # #121 - Resource Limits (520 ... 534) # #226 - S/R Interp State (535 ... 537) # #227 - S/G Return Opts (538 ... 539) # #235 - Ensemble C API (540 ... 551) # #233 - Virtualized Time (552 ... 553) # TIP#218 (driver thread actions) davygrvy/akupries ChannelType ver 4 declare 554 { Tcl_DriverThreadActionProc *Tcl_ChannelThreadActionProc( Tcl_ChannelType *chanTypePtr) } # Slots 555 to 572 are taken already by 8.5 # TIP #237: Arbitrary-prec Integers (555 ... 559) # TIP #208: 'chan' Command (560 ... 561) # TIP #219: Channel Reflection (562 ... 565) # TIP #237: Add. bignum support (566) # TIP #181: 'namespace unknown' Cmd (567 ... 568) # TIP #258: Enhanced Encodings API (569 ... 572) # TIP#268 (extended version numbers and requirements) akupries declare 573 { int Tcl_PkgRequireProc(Tcl_Interp *interp, const char *name, int objc, Tcl_Obj *const objv[], ClientData *clientDataPtr) } declare 630 { void TclUnusedStubEntry(void) } ############################################################################## # Define the platform specific public Tcl interface. These functions are only # available on the designated platform. interface tclPlat ################################ # Unix specific functions # (none) ################################ # Windows specific functions # Added in Tcl 8.1 declare 0 win { TCHAR *Tcl_WinUtfToTChar(const char *str, int len, Tcl_DString *dsPtr) } declare 1 win { char *Tcl_WinTCharToUtf(const TCHAR *str, int len, Tcl_DString *dsPtr) } ################################ # Mac OS X specific functions declare 0 macosx { int Tcl_MacOSXOpenBundleResources(Tcl_Interp *interp, const char *bundleName, int hasResourceFile, int maxPathLen, char *libraryPath) } declare 1 macosx { int Tcl_MacOSXOpenVersionedBundleResources(Tcl_Interp *interp, const char *bundleName, const char *bundleVersion, int hasResourceFile, int maxPathLen, char *libraryPath) } # Local Variables: # mode: tcl # End: tcl8.4.20/generic/regc_nfa.c0000644003604700454610000012527112133546537014252 0ustar dgp771div/* * NFA utilities. * This file is #included by regcomp.c. * * Copyright (c) 1998, 1999 Henry Spencer. All rights reserved. * * Development of this software was funded, in part, by Cray Research Inc., * UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics * Corporation, none of whom are responsible for the results. The author * thanks all of them. * * Redistribution and use in source and binary forms -- with or without * modification -- are permitted for any purpose, provided that * redistributions in source form retain this entire copyright notice and * indicate the origin and nature of any modifications. * * I'd appreciate being given credit for this package in the documentation * of software which uses it, but that is not a requirement. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * HENRY SPENCER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * * * One or two things that technically ought to be in here * are actually in color.c, thanks to some incestuous relationships in * the color chains. */ #define NISERR() VISERR(nfa->v) #define NERR(e) VERR(nfa->v, (e)) /* - newnfa - set up an NFA ^ static struct nfa *newnfa(struct vars *, struct colormap *, struct nfa *); */ static struct nfa * /* the NFA, or NULL */ newnfa(v, cm, parent) struct vars *v; struct colormap *cm; struct nfa *parent; /* NULL if primary NFA */ { struct nfa *nfa; nfa = (struct nfa *)MALLOC(sizeof(struct nfa)); if (nfa == NULL) return NULL; nfa->states = NULL; nfa->slast = NULL; nfa->free = NULL; nfa->nstates = 0; nfa->cm = cm; nfa->v = v; nfa->size = 0; nfa->bos[0] = nfa->bos[1] = COLORLESS; nfa->eos[0] = nfa->eos[1] = COLORLESS; nfa->parent = parent; nfa->post = newfstate(nfa, '@'); /* number 0 */ nfa->pre = newfstate(nfa, '>'); /* number 1 */ nfa->init = newstate(nfa); /* may become invalid later */ nfa->final = newstate(nfa); if (ISERR()) { freenfa(nfa); return NULL; } rainbow(nfa, nfa->cm, PLAIN, COLORLESS, nfa->pre, nfa->init); newarc(nfa, '^', 1, nfa->pre, nfa->init); newarc(nfa, '^', 0, nfa->pre, nfa->init); rainbow(nfa, nfa->cm, PLAIN, COLORLESS, nfa->final, nfa->post); newarc(nfa, '$', 1, nfa->final, nfa->post); newarc(nfa, '$', 0, nfa->final, nfa->post); if (ISERR()) { freenfa(nfa); return NULL; } return nfa; } /* - too_many_states - checks if the max states exceeds the compile-time value ^ static int too_many_states(struct nfa *); */ static int too_many_states(nfa) struct nfa *nfa; { struct nfa *parent = nfa->parent; size_t sz = nfa->size; while (parent != NULL) { sz = parent->size; parent = parent->parent; } if (sz > REG_MAX_STATES) return 1; return 0; } /* - increment_size - increases the tracked size of the NFA and its parents. ^ static void increment_size(struct nfa *); */ static void increment_size(nfa) struct nfa *nfa; { struct nfa *parent = nfa->parent; nfa->size++; while (parent != NULL) { parent->size++; parent = parent->parent; } } /* - decrement_size - increases the tracked size of the NFA and its parents. ^ static void decrement_size(struct nfa *); */ static void decrement_size(nfa) struct nfa *nfa; { struct nfa *parent = nfa->parent; nfa->size--; while (parent != NULL) { parent->size--; parent = parent->parent; } } /* - freenfa - free an entire NFA ^ static VOID freenfa(struct nfa *); */ static VOID freenfa(nfa) struct nfa *nfa; { struct state *s; while ((s = nfa->states) != NULL) { s->nins = s->nouts = 0; /* don't worry about arcs */ freestate(nfa, s); } while ((s = nfa->free) != NULL) { nfa->free = s->next; destroystate(nfa, s); } nfa->slast = NULL; nfa->nstates = -1; nfa->pre = NULL; nfa->post = NULL; FREE(nfa); } /* - newstate - allocate an NFA state, with zero flag value ^ static struct state *newstate(struct nfa *); */ static struct state * /* NULL on error */ newstate(nfa) struct nfa *nfa; { struct state *s; if (too_many_states(nfa)) { /* XXX: add specific error for this */ NERR(REG_ETOOBIG); return NULL; } if (nfa->free != NULL) { s = nfa->free; nfa->free = s->next; } else { s = (struct state *)MALLOC(sizeof(struct state)); if (s == NULL) { NERR(REG_ESPACE); return NULL; } s->oas.next = NULL; s->free = NULL; s->noas = 0; } assert(nfa->nstates >= 0); s->no = nfa->nstates++; s->flag = 0; if (nfa->states == NULL) nfa->states = s; s->nins = 0; s->ins = NULL; s->nouts = 0; s->outs = NULL; s->tmp = NULL; s->next = NULL; if (nfa->slast != NULL) { assert(nfa->slast->next == NULL); nfa->slast->next = s; } s->prev = nfa->slast; nfa->slast = s; /* Track the current size and the parent size */ increment_size(nfa); return s; } /* - newfstate - allocate an NFA state with a specified flag value ^ static struct state *newfstate(struct nfa *, int flag); */ static struct state * /* NULL on error */ newfstate(nfa, flag) struct nfa *nfa; int flag; { struct state *s; s = newstate(nfa); if (s != NULL) s->flag = (char)flag; return s; } /* - dropstate - delete a state's inarcs and outarcs and free it ^ static VOID dropstate(struct nfa *, struct state *); */ static VOID dropstate(nfa, s) struct nfa *nfa; struct state *s; { struct arc *a; while ((a = s->ins) != NULL) freearc(nfa, a); while ((a = s->outs) != NULL) freearc(nfa, a); freestate(nfa, s); } /* - freestate - free a state, which has no in-arcs or out-arcs ^ static VOID freestate(struct nfa *, struct state *); */ static VOID freestate(nfa, s) struct nfa *nfa; struct state *s; { assert(s != NULL); assert(s->nins == 0 && s->nouts == 0); s->no = FREESTATE; s->flag = 0; if (s->next != NULL) s->next->prev = s->prev; else { assert(s == nfa->slast); nfa->slast = s->prev; } if (s->prev != NULL) s->prev->next = s->next; else { assert(s == nfa->states); nfa->states = s->next; } s->prev = NULL; s->next = nfa->free; /* don't delete it, put it on the free list */ nfa->free = s; decrement_size(nfa); } /* - destroystate - really get rid of an already-freed state ^ static VOID destroystate(struct nfa *, struct state *); */ static VOID destroystate(nfa, s) struct nfa *nfa; struct state *s; { struct arcbatch *ab; struct arcbatch *abnext; assert(s->no == FREESTATE); for (ab = s->oas.next; ab != NULL; ab = abnext) { abnext = ab->next; FREE(ab); } s->ins = NULL; s->outs = NULL; s->next = NULL; FREE(s); } /* - newarc - set up a new arc within an NFA ^ static VOID newarc(struct nfa *, int, pcolor, struct state *, ^ struct state *); */ static VOID newarc(nfa, t, co, from, to) struct nfa *nfa; int t; pcolor co; struct state *from; struct state *to; { struct arc *a; assert(from != NULL && to != NULL); /* check for duplicates */ for (a = from->outs; a != NULL; a = a->outchain) if (a->to == to && a->co == co && a->type == t) return; a = allocarc(nfa, from); if (NISERR()) return; assert(a != NULL); a->type = t; a->co = (color)co; a->to = to; a->from = from; /* * Put the new arc on the beginning, not the end, of the chains. * Not only is this easier, it has the very useful side effect that * deleting the most-recently-added arc is the cheapest case rather * than the most expensive one. */ a->inchain = to->ins; to->ins = a; a->outchain = from->outs; from->outs = a; from->nouts++; to->nins++; if (COLORED(a) && nfa->parent == NULL) colorchain(nfa->cm, a); return; } /* - allocarc - allocate a new out-arc within a state ^ static struct arc *allocarc(struct nfa *, struct state *); */ static struct arc * /* NULL for failure */ allocarc(nfa, s) struct nfa *nfa; struct state *s; { struct arc *a; struct arcbatch *new; int i; /* shortcut */ if (s->free == NULL && s->noas < ABSIZE) { a = &s->oas.a[s->noas]; s->noas++; return a; } /* if none at hand, get more */ if (s->free == NULL) { new = (struct arcbatch *)MALLOC(sizeof(struct arcbatch)); if (new == NULL) { NERR(REG_ESPACE); return NULL; } new->next = s->oas.next; s->oas.next = new; for (i = 0; i < ABSIZE; i++) { new->a[i].type = 0; new->a[i].freechain = &new->a[i+1]; } new->a[ABSIZE-1].freechain = NULL; s->free = &new->a[0]; } assert(s->free != NULL); a = s->free; s->free = a->freechain; return a; } /* - freearc - free an arc ^ static VOID freearc(struct nfa *, struct arc *); */ static VOID freearc(nfa, victim) struct nfa *nfa; struct arc *victim; { struct state *from = victim->from; struct state *to = victim->to; struct arc *a; assert(victim->type != 0); /* take it off color chain if necessary */ if (COLORED(victim) && nfa->parent == NULL) uncolorchain(nfa->cm, victim); /* take it off source's out-chain */ assert(from != NULL); assert(from->outs != NULL); a = from->outs; if (a == victim) /* simple case: first in chain */ from->outs = victim->outchain; else { for (; a != NULL && a->outchain != victim; a = a->outchain) continue; assert(a != NULL); a->outchain = victim->outchain; } from->nouts--; /* take it off target's in-chain */ assert(to != NULL); assert(to->ins != NULL); a = to->ins; if (a == victim) /* simple case: first in chain */ to->ins = victim->inchain; else { for (; a != NULL && a->inchain != victim; a = a->inchain) continue; assert(a != NULL); a->inchain = victim->inchain; } to->nins--; /* clean up and place on free list */ victim->type = 0; victim->from = NULL; /* precautions... */ victim->to = NULL; victim->inchain = NULL; victim->outchain = NULL; victim->freechain = from->free; from->free = victim; } /* - hasnonemptyout - Does state have a non-EMPTY out arc? ^ static int hasnonemptyout(struct state *); */ static int hasnonemptyout(s) struct state *s; { struct arc *a; for (a = s->outs; a != NULL; a = a->outchain) if (a->type != EMPTY) return 1; return 0; } /* - nonemptyouts - count non-EMPTY out arcs of a state ^ static int nonemptyouts(struct state *); */ static int nonemptyouts(s) struct state *s; { int n = 0; struct arc *a; for (a = s->outs; a != NULL; a = a->outchain) if (a->type != EMPTY) n++; return n; } /* - nonemptyins - count non-EMPTY in arcs of a state ^ static int nonemptyins(struct state *); */ static int nonemptyins(s) struct state *s; { int n = 0; struct arc *a; for (a = s->ins; a != NULL; a = a->inchain) if (a->type != EMPTY) n++; return n; } /* - findarc - find arc, if any, from given source with given type and color * If there is more than one such arc, the result is random. ^ static struct arc *findarc(struct state *, int, pcolor); */ static struct arc * findarc(s, type, co) struct state *s; int type; pcolor co; { struct arc *a; for (a = s->outs; a != NULL; a = a->outchain) if (a->type == type && a->co == co) return a; return NULL; } /* - cparc - allocate a new arc within an NFA, copying details from old one ^ static VOID cparc(struct nfa *, struct arc *, struct state *, ^ struct state *); */ static VOID cparc(nfa, oa, from, to) struct nfa *nfa; struct arc *oa; struct state *from; struct state *to; { newarc(nfa, oa->type, oa->co, from, to); } /* - moveins - move all in arcs of a state to another state * You might think this could be done better by just updating the * existing arcs, and you would be right if it weren't for the desire * for duplicate suppression, which makes it easier to just make new * ones to exploit the suppression built into newarc. ^ static VOID moveins(struct nfa *, struct state *, struct state *); */ static VOID moveins(nfa, old, new) struct nfa *nfa; struct state *old; struct state *new; { struct arc *a; assert(old != new); while ((a = old->ins) != NULL) { cparc(nfa, a, a->from, new); freearc(nfa, a); } assert(old->nins == 0); assert(old->ins == NULL); } /* - copyins - copy in arcs of a state to another state * Either all arcs, or only non-empty ones as determined by all value. ^ static VOID copyins(struct nfa *, struct state *, struct state *, int); */ static VOID copyins(nfa, old, new, all) struct nfa *nfa; struct state *old; struct state *new; int all; { struct arc *a; assert(old != new); for (a = old->ins; a != NULL; a = a->inchain) if (all || a->type != EMPTY) cparc(nfa, a, a->from, new); } /* - moveouts - move all out arcs of a state to another state ^ static VOID moveouts(struct nfa *, struct state *, struct state *); */ static VOID moveouts(nfa, old, new) struct nfa *nfa; struct state *old; struct state *new; { struct arc *a; assert(old != new); while ((a = old->outs) != NULL) { cparc(nfa, a, new, a->to); freearc(nfa, a); } } /* - copyouts - copy out arcs of a state to another state * Either all arcs, or only non-empty ones as determined by all value. ^ static VOID copyouts(struct nfa *, struct state *, struct state *, int); */ static VOID copyouts(nfa, old, new, all) struct nfa *nfa; struct state *old; struct state *new; int all; { struct arc *a; assert(old != new); for (a = old->outs; a != NULL; a = a->outchain) if (all || a->type != EMPTY) cparc(nfa, a, new, a->to); } /* - cloneouts - copy out arcs of a state to another state pair, modifying type ^ static VOID cloneouts(struct nfa *, struct state *, struct state *, ^ struct state *, int); */ static VOID cloneouts(nfa, old, from, to, type) struct nfa *nfa; struct state *old; struct state *from; struct state *to; int type; { struct arc *a; assert(old != from); for (a = old->outs; a != NULL; a = a->outchain) newarc(nfa, type, a->co, from, to); } /* - delsub - delete a sub-NFA, updating subre pointers if necessary * This uses a recursive traversal of the sub-NFA, marking already-seen * states using their tmp pointer. ^ static VOID delsub(struct nfa *, struct state *, struct state *); */ static VOID delsub(nfa, lp, rp) struct nfa *nfa; struct state *lp; /* the sub-NFA goes from here... */ struct state *rp; /* ...to here, *not* inclusive */ { assert(lp != rp); rp->tmp = rp; /* mark end */ deltraverse(nfa, lp, lp); assert(lp->nouts == 0 && rp->nins == 0); /* did the job */ assert(lp->no != FREESTATE && rp->no != FREESTATE); /* no more */ rp->tmp = NULL; /* unmark end */ lp->tmp = NULL; /* and begin, marked by deltraverse */ } /* - deltraverse - the recursive heart of delsub * This routine's basic job is to destroy all out-arcs of the state. ^ static VOID deltraverse(struct nfa *, struct state *, struct state *); */ static VOID deltraverse(nfa, leftend, s) struct nfa *nfa; struct state *leftend; struct state *s; { struct arc *a; struct state *to; if (s->nouts == 0) return; /* nothing to do */ if (s->tmp != NULL) return; /* already in progress */ s->tmp = s; /* mark as in progress */ while ((a = s->outs) != NULL) { to = a->to; deltraverse(nfa, leftend, to); assert(to->nouts == 0 || to->tmp != NULL); freearc(nfa, a); if (to->nins == 0 && to->tmp == NULL) { assert(to->nouts == 0); freestate(nfa, to); } } assert(s->no != FREESTATE); /* we're still here */ assert(s == leftend || s->nins != 0); /* and still reachable */ assert(s->nouts == 0); /* but have no outarcs */ s->tmp = NULL; /* we're done here */ } /* - dupnfa - duplicate sub-NFA * Another recursive traversal, this time using tmp to point to duplicates * as well as mark already-seen states. (You knew there was a reason why * it's a state pointer, didn't you? :-)) ^ static VOID dupnfa(struct nfa *, struct state *, struct state *, ^ struct state *, struct state *); */ static VOID dupnfa(nfa, start, stop, from, to) struct nfa *nfa; struct state *start; /* duplicate of subNFA starting here */ struct state *stop; /* and stopping here */ struct state *from; /* stringing duplicate from here */ struct state *to; /* to here */ { if (start == stop) { newarc(nfa, EMPTY, 0, from, to); return; } stop->tmp = to; duptraverse(nfa, start, from); /* done, except for clearing out the tmp pointers */ stop->tmp = NULL; cleartraverse(nfa, start); } /* - duptraverse - recursive heart of dupnfa ^ static VOID duptraverse(struct nfa *, struct state *, struct state *); */ static VOID duptraverse(nfa, s, stmp) struct nfa *nfa; struct state *s; struct state *stmp; /* s's duplicate, or NULL */ { struct arc *a; if (s->tmp != NULL) return; /* already done */ s->tmp = (stmp == NULL) ? newstate(nfa) : stmp; if (s->tmp == NULL) { assert(NISERR()); return; } for (a = s->outs; a != NULL && !NISERR(); a = a->outchain) { duptraverse(nfa, a->to, (struct state *)NULL); if (NISERR()) break; assert(a->to->tmp != NULL); cparc(nfa, a, s->tmp, a->to->tmp); } } /* - cleartraverse - recursive cleanup for algorithms that leave tmp ptrs set ^ static VOID cleartraverse(struct nfa *, struct state *); */ static VOID cleartraverse(nfa, s) struct nfa *nfa; struct state *s; { struct arc *a; if (s->tmp == NULL) return; s->tmp = NULL; for (a = s->outs; a != NULL; a = a->outchain) cleartraverse(nfa, a->to); } /* - specialcolors - fill in special colors for an NFA ^ static VOID specialcolors(struct nfa *); */ static VOID specialcolors(nfa) struct nfa *nfa; { /* false colors for BOS, BOL, EOS, EOL */ if (nfa->parent == NULL) { nfa->bos[0] = pseudocolor(nfa->cm); nfa->bos[1] = pseudocolor(nfa->cm); nfa->eos[0] = pseudocolor(nfa->cm); nfa->eos[1] = pseudocolor(nfa->cm); } else { assert(nfa->parent->bos[0] != COLORLESS); nfa->bos[0] = nfa->parent->bos[0]; assert(nfa->parent->bos[1] != COLORLESS); nfa->bos[1] = nfa->parent->bos[1]; assert(nfa->parent->eos[0] != COLORLESS); nfa->eos[0] = nfa->parent->eos[0]; assert(nfa->parent->eos[1] != COLORLESS); nfa->eos[1] = nfa->parent->eos[1]; } } /* - optimize - optimize an NFA ^ static long optimize(struct nfa *, FILE *); */ static long /* re_info bits */ optimize(nfa, f) struct nfa *nfa; FILE *f; /* for debug output; NULL none */ { int verbose = (f != NULL) ? 1 : 0; if (verbose) fprintf(f, "\ninitial cleanup:\n"); cleanup(nfa); /* may simplify situation */ if (verbose) dumpnfa(nfa, f); if (verbose) fprintf(f, "\nempties:\n"); fixempties(nfa, f); /* get rid of EMPTY arcs */ if (verbose) fprintf(f, "\nconstraints:\n"); pullback(nfa, f); /* pull back constraints backward */ pushfwd(nfa, f); /* push fwd constraints forward */ if (verbose) fprintf(f, "\nfinal cleanup:\n"); cleanup(nfa); /* final tidying */ return analyze(nfa); /* and analysis */ } /* - pullback - pull back constraints backward to (with luck) eliminate them ^ static VOID pullback(struct nfa *, FILE *); */ static VOID pullback(nfa, f) struct nfa *nfa; FILE *f; /* for debug output; NULL none */ { struct state *s; struct state *nexts; struct arc *a; struct arc *nexta; int progress; /* find and pull until there are no more */ do { progress = 0; for (s = nfa->states; s != NULL && !NISERR(); s = nexts) { nexts = s->next; for (a = s->outs; a != NULL && !NISERR(); a = nexta) { nexta = a->outchain; if (a->type == '^' || a->type == BEHIND) if (pull(nfa, a)) progress = 1; assert(nexta == NULL || s->no != FREESTATE); } } if (progress && f != NULL) dumpnfa(nfa, f); } while (progress && !NISERR()); if (NISERR()) return; for (a = nfa->pre->outs; a != NULL; a = nexta) { nexta = a->outchain; if (a->type == '^') { assert(a->co == 0 || a->co == 1); newarc(nfa, PLAIN, nfa->bos[a->co], a->from, a->to); freearc(nfa, a); } } } /* - pull - pull a back constraint backward past its source state * A significant property of this function is that it deletes at most * one state -- the constraint's from state -- and only if the constraint * was that state's last outarc. ^ static int pull(struct nfa *, struct arc *); */ static int /* 0 couldn't, 1 could */ pull(nfa, con) struct nfa *nfa; struct arc *con; { struct state *from = con->from; struct state *to = con->to; struct arc *a; struct arc *nexta; struct state *s; if (from == to) { /* circular constraint is pointless */ freearc(nfa, con); return 1; } if (from->flag) /* can't pull back beyond start */ return 0; if (from->nins == 0) { /* unreachable */ freearc(nfa, con); return 1; } /* * DGP 2007-11-15: Cloning a state with a circular constraint on its * list of outs can lead to trouble [Bug 1810038], so get rid of them * first. */ for (a = from->outs; a != NULL; a = nexta) { nexta = a->outchain; switch (a->type) { case '^': case '$': case BEHIND: case AHEAD: if (from == a->to) { freearc(nfa, a); } break; } } /* first, clone from state if necessary to avoid other outarcs */ if (from->nouts > 1) { s = newstate(nfa); if (NISERR()) return 0; assert(to != from); /* con is not an inarc */ copyins(nfa, from, s, 1); /* duplicate inarcs */ cparc(nfa, con, s, to); /* move constraint arc */ freearc(nfa, con); from = s; con = from->outs; } assert(from->nouts == 1); /* propagate the constraint into the from state's inarcs */ for (a = from->ins; a != NULL; a = nexta) { nexta = a->inchain; switch (combine(con, a)) { case INCOMPATIBLE: /* destroy the arc */ freearc(nfa, a); break; case SATISFIED: /* no action needed */ break; case COMPATIBLE: /* swap the two arcs, more or less */ s = newstate(nfa); if (NISERR()) return 0; cparc(nfa, a, s, to); /* anticipate move */ cparc(nfa, con, a->from, s); if (NISERR()) return 0; freearc(nfa, a); break; default: assert(NOTREACHED); break; } } /* remaining inarcs, if any, incorporate the constraint */ moveins(nfa, from, to); dropstate(nfa, from); /* will free the constraint */ return 1; } /* - pushfwd - push forward constraints forward to (with luck) eliminate them ^ static VOID pushfwd(struct nfa *, FILE *); */ static VOID pushfwd(nfa, f) struct nfa *nfa; FILE *f; /* for debug output; NULL none */ { struct state *s; struct state *nexts; struct arc *a; struct arc *nexta; int progress; /* find and push until there are no more */ do { progress = 0; for (s = nfa->states; s != NULL && !NISERR(); s = nexts) { nexts = s->next; for (a = s->ins; a != NULL && !NISERR(); a = nexta) { nexta = a->inchain; if (a->type == '$' || a->type == AHEAD) if (push(nfa, a)) progress = 1; assert(nexta == NULL || s->no != FREESTATE); } } if (progress && f != NULL) dumpnfa(nfa, f); } while (progress && !NISERR()); if (NISERR()) return; for (a = nfa->post->ins; a != NULL; a = nexta) { nexta = a->inchain; if (a->type == '$') { assert(a->co == 0 || a->co == 1); newarc(nfa, PLAIN, nfa->eos[a->co], a->from, a->to); freearc(nfa, a); } } } /* - push - push a forward constraint forward past its destination state * A significant property of this function is that it deletes at most * one state -- the constraint's to state -- and only if the constraint * was that state's last inarc. ^ static int push(struct nfa *, struct arc *); */ static int /* 0 couldn't, 1 could */ push(nfa, con) struct nfa *nfa; struct arc *con; { struct state *from = con->from; struct state *to = con->to; struct arc *a; struct arc *nexta; struct state *s; if (to == from) { /* circular constraint is pointless */ freearc(nfa, con); return 1; } if (to->flag) /* can't push forward beyond end */ return 0; if (to->nouts == 0) { /* dead end */ freearc(nfa, con); return 1; } /* * DGP 2007-11-15: Here we duplicate the same protections as appear * in pull() above to avoid troubles with cloning a state with a * circular constraint on its list of ins. It is not clear whether * this is necessary, or is protecting against a "can't happen". * Any test case that actually leads to a freearc() call here would * be a welcome addition to the test suite. */ for (a = to->ins; a != NULL; a = nexta) { nexta = a->inchain; switch (a->type) { case '^': case '$': case BEHIND: case AHEAD: if (a->from == to) { freearc(nfa, a); } break; } } /* first, clone to state if necessary to avoid other inarcs */ if (to->nins > 1) { s = newstate(nfa); if (NISERR()) return 0; copyouts(nfa, to, s, 1); /* duplicate outarcs */ cparc(nfa, con, from, s); /* move constraint */ freearc(nfa, con); to = s; con = to->ins; } assert(to->nins == 1); /* propagate the constraint into the to state's outarcs */ for (a = to->outs; a != NULL; a = nexta) { nexta = a->outchain; switch (combine(con, a)) { case INCOMPATIBLE: /* destroy the arc */ freearc(nfa, a); break; case SATISFIED: /* no action needed */ break; case COMPATIBLE: /* swap the two arcs, more or less */ s = newstate(nfa); if (NISERR()) return 0; cparc(nfa, con, s, a->to); /* anticipate move */ cparc(nfa, a, from, s); if (NISERR()) return 0; freearc(nfa, a); break; default: assert(NOTREACHED); break; } } /* remaining outarcs, if any, incorporate the constraint */ moveouts(nfa, to, from); dropstate(nfa, to); /* will free the constraint */ return 1; } /* - combine - constraint lands on an arc, what happens? ^ #def INCOMPATIBLE 1 // destroys arc ^ #def SATISFIED 2 // constraint satisfied ^ #def COMPATIBLE 3 // compatible but not satisfied yet ^ static int combine(struct arc *, struct arc *); */ static int combine(con, a) struct arc *con; struct arc *a; { # define CA(ct,at) (((ct)<type, a->type)) { case CA('^', PLAIN): /* newlines are handled separately */ case CA('$', PLAIN): return INCOMPATIBLE; break; case CA(AHEAD, PLAIN): /* color constraints meet colors */ case CA(BEHIND, PLAIN): if (con->co == a->co) return SATISFIED; return INCOMPATIBLE; break; case CA('^', '^'): /* collision, similar constraints */ case CA('$', '$'): case CA(AHEAD, AHEAD): case CA(BEHIND, BEHIND): if (con->co == a->co) /* true duplication */ return SATISFIED; return INCOMPATIBLE; break; case CA('^', BEHIND): /* collision, dissimilar constraints */ case CA(BEHIND, '^'): case CA('$', AHEAD): case CA(AHEAD, '$'): return INCOMPATIBLE; break; case CA('^', '$'): /* constraints passing each other */ case CA('^', AHEAD): case CA(BEHIND, '$'): case CA(BEHIND, AHEAD): case CA('$', '^'): case CA('$', BEHIND): case CA(AHEAD, '^'): case CA(AHEAD, BEHIND): case CA('^', LACON): case CA(BEHIND, LACON): case CA('$', LACON): case CA(AHEAD, LACON): return COMPATIBLE; break; } assert(NOTREACHED); return INCOMPATIBLE; /* for benefit of blind compilers */ } /* - fixempties - get rid of EMPTY arcs ^ static VOID fixempties(struct nfa *, FILE *); */ static VOID fixempties(nfa, f) struct nfa *nfa; FILE *f; /* for debug output; NULL none */ { struct state *s; struct state *s2; struct state *nexts; struct arc *a; struct arc *nexta; /* * First, get rid of any states whose sole out-arc is an EMPTY, * since they're basically just aliases for their successor. * The parsing algorithm creates enough of these that it's worth * special-casing this. */ for (s = nfa->states; s != NULL && !NISERR(); s = nexts) { nexts = s->next; if (s->flag || s->nouts != 1) continue; a = s->outs; assert(a != NULL && a->outchain == NULL); if (a->type != EMPTY) continue; if (s != a->to) moveins(nfa, s, a->to); dropstate(nfa, s); } /* * Similarly, get rid of any state with a single EMPTY in-arc, * by folding it into its predecessor. */ for (s = nfa->states; s != NULL && !NISERR(); s = nexts) { nexts = s->next; /* Ensure tmp fields are clear for next step */ assert(s->tmp = NULL); if (s->flag || s->nins != 1) continue; a = s->ins; assert(a != NULL && a->inchain == NULL); if (a->type != EMPTY) continue; if (s != a->from) moveouts(nfa, s, a->from); dropstate(nfa, s); } /* * For each remaining NFA state, find all other states that are * reachable from it by a chain of one or more EMPTY arcs. Then * generate new arcs that eliminate the need for each such chain. * * If we just do this straightforwardly, the algorithm gets slow * in complex graphs, because the same arcs get copied to all * intermediate states of an EMPTY chain, and then uselessly * pushed repeatedly to the chain's final state; we waste a lot * of time in newarc's duplicate checking. To improve matters, * we decree that any state with only EMPTY out-arcs is "doomed" * and will not be part of the final NFA. That can be ensured by * not adding any new out-arcs to such a state. Having ensured * that, we need not update the state's in-arcs list either; all * arcs that might have gotten pushed forward to it will just get * pushed directly to successor states. This eliminates most of * the useless duplicate arcs. */ for (s = nfa->states; s != NULL && !NISERR(); s = s->next) { for (s2 = emptyreachable(s, s); s2 != s && !NISERR(); s2 = nexts) { /* * If s2 is doomed, we decide that (1) we will * always push arcs forward to it, not pull them * back to s; and (2) we can optimize away the * push-forward, per comment above. * So do nothing. */ if (s2->flag || hasnonemptyout(s2)) replaceempty(nfa, s, s2); /* Reset the tmp fields as we walk back */ nexts = s2->tmp; s2->tmp = NULL; } s->tmp = NULL; } if (NISERR()) return; /* * Remove all the EMPTY arcs, since we don't need them anymore. */ for (s = nfa->states; s != NULL; s = s->next) for (a = s->outs; a != NULL; a = nexta) { nexta = a->outchain; if (a->type == EMPTY) freearc(nfa, a); } /* * And remove any states that have become useless. (This * cleanup is not very thorough, and would be even less so if we * tried to combine it with the previous step; but cleanup() * will take care of anything we miss.) */ for (s = nfa->states; s != NULL; s = nexts) { nexts = s->next; if ((s->nins == 0 || s->nouts == 0) && !s->flag) dropstate(nfa, s); } if (f != NULL) dumpnfa(nfa, f); } /* - emptyreachable - recursively find all states reachable from s by EMPTY arcs * The return value is the last such state found. Its tmp field links back * to the next-to-last such state, and so on back to s, so that all these * states can be located without searching the whole NFA. * The maximum recursion depth here is equal to the length of the longest * loop-free chain of EMPTY arcs, which is surely no more than the size of * the NFA, and in practice will be a lot less than that. ^ static struct state *emptyreachable(struct state *, struct state *); */ static struct state * emptyreachable(s, lastfound) struct state *s; struct state *lastfound; { struct arc *a; s->tmp = lastfound; lastfound = s; for (a = s->outs; a != NULL; a = a->outchain) if (a->type == EMPTY && a->to->tmp == NULL) lastfound = emptyreachable(a->to, lastfound); return lastfound; } /* - replaceempty - replace an EMPTY arc chain with some non-empty arcs * The EMPTY arc(s) should be deleted later, but we can't do it here because * they may still be needed to identify other arc chains during fixempties(). ^ static void replaceempty(struct nfa *, struct state *, struct state *); */ static VOID replaceempty(nfa, from, to) struct nfa *nfa; struct state *from; struct state *to; { int fromouts; int toins; assert(from != to); /* * Create replacement arcs that bypass the need for the EMPTY * chain. We can do this either by pushing arcs forward * (linking directly from predecessors of "from" to "to") or by * pulling them back (linking directly from "from" to the * successors of "to"). In general, we choose whichever way * creates greater fan-out or fan-in, so as to improve the odds * of reducing the other state to zero in-arcs or out-arcs and * thereby being able to delete it. However, if "from" is * doomed (has no non-EMPTY out-arcs), we must keep it so, so * always push forward in that case. * * The fan-out/fan-in comparison should count only non-EMPTY * arcs. If "from" is doomed, we can skip counting "to"'s arcs, * since we want to force taking the copyins path in that case. */ fromouts = nonemptyouts(from); toins = (fromouts == 0) ? 1 : nonemptyins(to); if (fromouts > toins) { copyouts(nfa, to, from, 0); return; } if (fromouts < toins) { copyins(nfa, from, to, 0); return; } /* * fromouts == toins. Secondary decision: copy fewest arcs. * * Doesn't seem to be worth the trouble to exclude empties from * these comparisons; that takes extra time and doesn't seem to * improve the resulting graph much. */ if (from->nins > to->nouts) { copyouts(nfa, to, from, 0); return; } copyins(nfa, from, to, 0); } /* - cleanup - clean up NFA after optimizations ^ static VOID cleanup(struct nfa *); */ static VOID cleanup(nfa) struct nfa *nfa; { struct state *s; struct state *nexts; int n; /* clear out unreachable or dead-end states */ /* use pre to mark reachable, then post to mark can-reach-post */ markreachable(nfa, nfa->pre, (struct state *)NULL, nfa->pre); markcanreach(nfa, nfa->post, nfa->pre, nfa->post); for (s = nfa->states; s != NULL; s = nexts) { nexts = s->next; if (s->tmp != nfa->post && !s->flag) dropstate(nfa, s); } assert(nfa->post->nins == 0 || nfa->post->tmp == nfa->post); cleartraverse(nfa, nfa->pre); assert(nfa->post->nins == 0 || nfa->post->tmp == NULL); /* the nins==0 (final unreachable) case will be caught later */ /* renumber surviving states */ n = 0; for (s = nfa->states; s != NULL; s = s->next) s->no = n++; nfa->nstates = n; } /* - markreachable - recursive marking of reachable states ^ static VOID markreachable(struct nfa *, struct state *, struct state *, ^ struct state *); */ static VOID markreachable(nfa, s, okay, mark) struct nfa *nfa; struct state *s; struct state *okay; /* consider only states with this mark */ struct state *mark; /* the value to mark with */ { struct arc *a; if (s->tmp != okay) return; s->tmp = mark; for (a = s->outs; a != NULL; a = a->outchain) markreachable(nfa, a->to, okay, mark); } /* - markcanreach - recursive marking of states which can reach here ^ static VOID markcanreach(struct nfa *, struct state *, struct state *, ^ struct state *); */ static VOID markcanreach(nfa, s, okay, mark) struct nfa *nfa; struct state *s; struct state *okay; /* consider only states with this mark */ struct state *mark; /* the value to mark with */ { struct arc *a; if (s->tmp != okay) return; s->tmp = mark; for (a = s->ins; a != NULL; a = a->inchain) markcanreach(nfa, a->from, okay, mark); } /* - analyze - ascertain potentially-useful facts about an optimized NFA ^ static long analyze(struct nfa *); */ static long /* re_info bits to be ORed in */ analyze(nfa) struct nfa *nfa; { struct arc *a; struct arc *aa; if (nfa->pre->outs == NULL) return REG_UIMPOSSIBLE; for (a = nfa->pre->outs; a != NULL; a = a->outchain) for (aa = a->to->outs; aa != NULL; aa = aa->outchain) if (aa->to == nfa->post) return REG_UEMPTYMATCH; return 0; } /* - compact - compact an NFA ^ static VOID compact(struct nfa *, struct cnfa *); */ static VOID compact(nfa, cnfa) struct nfa *nfa; struct cnfa *cnfa; { struct state *s; struct arc *a; size_t nstates; size_t narcs; struct carc *ca; struct carc *first; assert (!NISERR()); nstates = 0; narcs = 0; for (s = nfa->states; s != NULL; s = s->next) { nstates++; narcs += 1 + s->nouts + 1; /* 1 as a fake for flags, nouts for arcs, 1 as endmarker */ } cnfa->states = (struct carc **)MALLOC(nstates * sizeof(struct carc *)); cnfa->arcs = (struct carc *)MALLOC(narcs * sizeof(struct carc)); if (cnfa->states == NULL || cnfa->arcs == NULL) { if (cnfa->states != NULL) FREE(cnfa->states); if (cnfa->arcs != NULL) FREE(cnfa->arcs); NERR(REG_ESPACE); return; } cnfa->nstates = nstates; cnfa->pre = nfa->pre->no; cnfa->post = nfa->post->no; cnfa->bos[0] = nfa->bos[0]; cnfa->bos[1] = nfa->bos[1]; cnfa->eos[0] = nfa->eos[0]; cnfa->eos[1] = nfa->eos[1]; cnfa->ncolors = maxcolor(nfa->cm) + 1; cnfa->flags = 0; ca = cnfa->arcs; for (s = nfa->states; s != NULL; s = s->next) { assert((size_t)s->no < nstates); cnfa->states[s->no] = ca; ca->co = 0; /* clear and skip flags "arc" */ ca++; first = ca; for (a = s->outs; a != NULL; a = a->outchain) switch (a->type) { case PLAIN: ca->co = a->co; ca->to = a->to->no; ca++; break; case LACON: assert(s->no != cnfa->pre); ca->co = (color)(cnfa->ncolors + a->co); ca->to = a->to->no; ca++; cnfa->flags |= HASLACONS; break; default: assert(NOTREACHED); break; } carcsort(first, ca-1); ca->co = COLORLESS; ca->to = 0; ca++; } assert(ca == &cnfa->arcs[narcs]); assert(cnfa->nstates != 0); /* mark no-progress states */ for (a = nfa->pre->outs; a != NULL; a = a->outchain) cnfa->states[a->to->no]->co = 1; cnfa->states[nfa->pre->no]->co = 1; } /* - carcsort - sort compacted-NFA arcs by color * Really dumb algorithm, but if the list is long enough for that to matter, * you're in real trouble anyway. ^ static VOID carcsort(struct carc *, struct carc *); */ static VOID carcsort(first, last) struct carc *first; struct carc *last; { struct carc *p; struct carc *q; struct carc tmp; if (last - first <= 1) return; for (p = first; p <= last; p++) for (q = p; q <= last; q++) if (p->co > q->co || (p->co == q->co && p->to > q->to)) { assert(p != q); tmp = *p; *p = *q; *q = tmp; } } /* - freecnfa - free a compacted NFA ^ static VOID freecnfa(struct cnfa *); */ static VOID freecnfa(cnfa) struct cnfa *cnfa; { assert(cnfa->nstates != 0); /* not empty already */ cnfa->nstates = 0; FREE(cnfa->states); FREE(cnfa->arcs); } /* - dumpnfa - dump an NFA in human-readable form ^ static VOID dumpnfa(struct nfa *, FILE *); */ static VOID dumpnfa(nfa, f) struct nfa *nfa; FILE *f; { #ifdef REG_DEBUG struct state *s; fprintf(f, "pre %d, post %d", nfa->pre->no, nfa->post->no); if (nfa->bos[0] != COLORLESS) fprintf(f, ", bos [%ld]", (long)nfa->bos[0]); if (nfa->bos[1] != COLORLESS) fprintf(f, ", bol [%ld]", (long)nfa->bos[1]); if (nfa->eos[0] != COLORLESS) fprintf(f, ", eos [%ld]", (long)nfa->eos[0]); if (nfa->eos[1] != COLORLESS) fprintf(f, ", eol [%ld]", (long)nfa->eos[1]); fprintf(f, "\n"); for (s = nfa->states; s != NULL; s = s->next) dumpstate(s, f); if (nfa->parent == NULL) dumpcolors(nfa->cm, f); fflush(f); #endif } #ifdef REG_DEBUG /* subordinates of dumpnfa */ /* ^ #ifdef REG_DEBUG */ /* - dumpstate - dump an NFA state in human-readable form ^ static VOID dumpstate(struct state *, FILE *); */ static VOID dumpstate(s, f) struct state *s; FILE *f; { struct arc *a; fprintf(f, "%d%s%c", s->no, (s->tmp != NULL) ? "T" : "", (s->flag) ? s->flag : '.'); if (s->prev != NULL && s->prev->next != s) fprintf(f, "\tstate chain bad\n"); if (s->nouts == 0) fprintf(f, "\tno out arcs\n"); else dumparcs(s, f); fflush(f); for (a = s->ins; a != NULL; a = a->inchain) { if (a->to != s) fprintf(f, "\tlink from %d to %d on %d's in-chain\n", a->from->no, a->to->no, s->no); } } /* - dumparcs - dump out-arcs in human-readable form ^ static VOID dumparcs(struct state *, FILE *); */ static VOID dumparcs(s, f) struct state *s; FILE *f; { int pos; assert(s->nouts > 0); /* printing arcs in reverse order is usually clearer */ pos = dumprarcs(s->outs, s, f, 1); if (pos != 1) fprintf(f, "\n"); } /* - dumprarcs - dump remaining outarcs, recursively, in reverse order ^ static int dumprarcs(struct arc *, struct state *, FILE *, int); */ static int /* resulting print position */ dumprarcs(a, s, f, pos) struct arc *a; struct state *s; FILE *f; int pos; /* initial print position */ { if (a->outchain != NULL) pos = dumprarcs(a->outchain, s, f, pos); dumparc(a, s, f); if (pos == 5) { fprintf(f, "\n"); pos = 1; } else pos++; return pos; } /* - dumparc - dump one outarc in readable form, including prefixing tab ^ static VOID dumparc(struct arc *, struct state *, FILE *); */ static VOID dumparc(a, s, f) struct arc *a; struct state *s; FILE *f; { struct arc *aa; struct arcbatch *ab; fprintf(f, "\t"); switch (a->type) { case PLAIN: fprintf(f, "[%ld]", (long)a->co); break; case AHEAD: fprintf(f, ">%ld>", (long)a->co); break; case BEHIND: fprintf(f, "<%ld<", (long)a->co); break; case LACON: fprintf(f, ":%ld:", (long)a->co); break; case '^': case '$': fprintf(f, "%c%d", a->type, (int)a->co); break; case EMPTY: break; default: fprintf(f, "0x%x/0%lo", a->type, (long)a->co); break; } if (a->from != s) fprintf(f, "?%d?", a->from->no); for (ab = &a->from->oas; ab != NULL; ab = ab->next) { for (aa = &ab->a[0]; aa < &ab->a[ABSIZE]; aa++) if (aa == a) break; /* NOTE BREAK OUT */ if (aa < &ab->a[ABSIZE]) /* propagate break */ break; /* NOTE BREAK OUT */ } if (ab == NULL) fprintf(f, "?!?"); /* not in allocated space */ fprintf(f, "->"); if (a->to == NULL) { fprintf(f, "NULL"); return; } fprintf(f, "%d", a->to->no); for (aa = a->to->ins; aa != NULL; aa = aa->inchain) if (aa == a) break; /* NOTE BREAK OUT */ if (aa == NULL) fprintf(f, "?!?"); /* missing from in-chain */ } /* ^ #endif */ #endif /* ifdef REG_DEBUG */ /* - dumpcnfa - dump a compacted NFA in human-readable form ^ static VOID dumpcnfa(struct cnfa *, FILE *); */ static VOID dumpcnfa(cnfa, f) struct cnfa *cnfa; FILE *f; { #ifdef REG_DEBUG int st; fprintf(f, "pre %d, post %d", cnfa->pre, cnfa->post); if (cnfa->bos[0] != COLORLESS) fprintf(f, ", bos [%ld]", (long)cnfa->bos[0]); if (cnfa->bos[1] != COLORLESS) fprintf(f, ", bol [%ld]", (long)cnfa->bos[1]); if (cnfa->eos[0] != COLORLESS) fprintf(f, ", eos [%ld]", (long)cnfa->eos[0]); if (cnfa->eos[1] != COLORLESS) fprintf(f, ", eol [%ld]", (long)cnfa->eos[1]); if (cnfa->flags&HASLACONS) fprintf(f, ", haslacons"); fprintf(f, "\n"); for (st = 0; st < cnfa->nstates; st++) dumpcstate(st, cnfa->states[st], cnfa, f); fflush(f); #endif } #ifdef REG_DEBUG /* subordinates of dumpcnfa */ /* ^ #ifdef REG_DEBUG */ /* - dumpcstate - dump a compacted-NFA state in human-readable form ^ static VOID dumpcstate(int, struct carc *, struct cnfa *, FILE *); */ static VOID dumpcstate(st, ca, cnfa, f) int st; struct carc *ca; struct cnfa *cnfa; FILE *f; { int i; int pos; fprintf(f, "%d%s", st, (ca[0].co) ? ":" : "."); pos = 1; for (i = 1; ca[i].co != COLORLESS; i++) { if (ca[i].co < cnfa->ncolors) fprintf(f, "\t[%ld]->%d", (long)ca[i].co, ca[i].to); else fprintf(f, "\t:%ld:->%d", (long)ca[i].co-cnfa->ncolors, ca[i].to); if (pos == 5) { fprintf(f, "\n"); pos = 1; } else pos++; } if (i == 1 || pos != 1) fprintf(f, "\n"); fflush(f); } /* ^ #endif */ #endif /* ifdef REG_DEBUG */ tcl8.4.20/generic/regc_color.c0000644003604700454610000004304312133546537014620 0ustar dgp771div/* * colorings of characters * This file is #included by regcomp.c. * * Copyright (c) 1998, 1999 Henry Spencer. All rights reserved. * * Development of this software was funded, in part, by Cray Research Inc., * UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics * Corporation, none of whom are responsible for the results. The author * thanks all of them. * * Redistribution and use in source and binary forms -- with or without * modification -- are permitted for any purpose, provided that * redistributions in source form retain this entire copyright notice and * indicate the origin and nature of any modifications. * * I'd appreciate being given credit for this package in the documentation * of software which uses it, but that is not a requirement. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * HENRY SPENCER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * * * Note that there are some incestuous relationships between this code and * NFA arc maintenance, which perhaps ought to be cleaned up sometime. */ #define CISERR() VISERR(cm->v) #define CERR(e) VERR(cm->v, (e)) /* - initcm - set up new colormap ^ static VOID initcm(struct vars *, struct colormap *); */ static VOID initcm(v, cm) struct vars *v; struct colormap *cm; { int i; int j; union tree *t; union tree *nextt; struct colordesc *cd; cm->magic = CMMAGIC; cm->v = v; cm->ncds = NINLINECDS; cm->cd = cm->cdspace; cm->max = 0; cm->free = 0; cd = cm->cd; /* cm->cd[WHITE] */ cd->sub = NOSUB; cd->arcs = NULL; cd->flags = 0; cd->nchrs = CHR_MAX - CHR_MIN + 1; /* upper levels of tree */ for (t = &cm->tree[0], j = NBYTS-1; j > 0; t = nextt, j--) { nextt = t + 1; for (i = BYTTAB-1; i >= 0; i--) t->tptr[i] = nextt; } /* bottom level is solid white */ t = &cm->tree[NBYTS-1]; for (i = BYTTAB-1; i >= 0; i--) t->tcolor[i] = WHITE; cd->block = t; } /* - freecm - free dynamically-allocated things in a colormap ^ static VOID freecm(struct colormap *); */ static VOID freecm(cm) struct colormap *cm; { size_t i; union tree *cb; cm->magic = 0; if (NBYTS > 1) cmtreefree(cm, cm->tree, 0); for (i = 1; i <= cm->max; i++) /* skip WHITE */ if (!UNUSEDCOLOR(&cm->cd[i])) { cb = cm->cd[i].block; if (cb != NULL) FREE(cb); } if (cm->cd != cm->cdspace) FREE(cm->cd); } /* - cmtreefree - free a non-terminal part of a colormap tree ^ static VOID cmtreefree(struct colormap *, union tree *, int); */ static VOID cmtreefree(cm, tree, level) struct colormap *cm; union tree *tree; int level; /* level number (top == 0) of this block */ { int i; union tree *t; union tree *fillt = &cm->tree[level+1]; union tree *cb; assert(level < NBYTS-1); /* this level has pointers */ for (i = BYTTAB-1; i >= 0; i--) { t = tree->tptr[i]; assert(t != NULL); if (t != fillt) { if (level < NBYTS-2) { /* more pointer blocks below */ cmtreefree(cm, t, level+1); FREE(t); } else { /* color block below */ cb = cm->cd[t->tcolor[0]].block; if (t != cb) /* not a solid block */ FREE(t); } } } } /* - setcolor - set the color of a character in a colormap ^ static color setcolor(struct colormap *, pchr, pcolor); */ static color /* previous color */ setcolor(cm, c, co) struct colormap *cm; pchr c; pcolor co; { uchr uc = c; int shift; int level; int b; int bottom; union tree *t; union tree *newt; union tree *fillt; union tree *lastt; union tree *cb; color prev; assert(cm->magic == CMMAGIC); if (CISERR() || co == COLORLESS) return COLORLESS; t = cm->tree; for (level = 0, shift = BYTBITS * (NBYTS - 1); shift > 0; level++, shift -= BYTBITS) { b = (uc >> shift) & BYTMASK; lastt = t; t = lastt->tptr[b]; assert(t != NULL); fillt = &cm->tree[level+1]; bottom = (shift <= BYTBITS) ? 1 : 0; cb = (bottom) ? cm->cd[t->tcolor[0]].block : fillt; if (t == fillt || t == cb) { /* must allocate a new block */ newt = (union tree *)MALLOC((bottom) ? sizeof(struct colors) : sizeof(struct ptrs)); if (newt == NULL) { CERR(REG_ESPACE); return COLORLESS; } if (bottom) memcpy(VS(newt->tcolor), VS(t->tcolor), BYTTAB*sizeof(color)); else memcpy(VS(newt->tptr), VS(t->tptr), BYTTAB*sizeof(union tree *)); t = newt; lastt->tptr[b] = t; } } b = uc & BYTMASK; prev = t->tcolor[b]; t->tcolor[b] = (color)co; return prev; } /* - maxcolor - report largest color number in use ^ static color maxcolor(struct colormap *); */ static color maxcolor(cm) struct colormap *cm; { if (CISERR()) return COLORLESS; return (color)cm->max; } /* - newcolor - find a new color (must be subject of setcolor at once) * Beware: may relocate the colordescs. ^ static color newcolor(struct colormap *); */ static color /* COLORLESS for error */ newcolor(cm) struct colormap *cm; { struct colordesc *cd; size_t n; if (CISERR()) return COLORLESS; if (cm->free != 0) { assert(cm->free > 0); assert((size_t)cm->free < cm->ncds); cd = &cm->cd[cm->free]; assert(UNUSEDCOLOR(cd)); assert(cd->arcs == NULL); cm->free = cd->sub; } else if (cm->max < cm->ncds - 1) { cm->max++; cd = &cm->cd[cm->max]; } else { /* oops, must allocate more */ struct colordesc *newCd; if (cm->max == MAX_COLOR) { CERR(REG_ECOLORS); return COLORLESS; /* too many colors */ } n = cm->ncds * 2; if (n < MAX_COLOR + 1) n = MAX_COLOR + 1; if (cm->cd == cm->cdspace) { newCd = (struct colordesc *)MALLOC(n * sizeof(struct colordesc)); if (newCd != NULL) memcpy(VS(newCd), VS(cm->cdspace), cm->ncds * sizeof(struct colordesc)); } else newCd = (struct colordesc *)REALLOC(cm->cd, n * sizeof(struct colordesc)); if (newCd == NULL) { CERR(REG_ESPACE); return COLORLESS; } cm->cd = newCd; cm->ncds = n; assert(cm->max < cm->ncds - 1); cm->max++; cd = &cm->cd[cm->max]; } cd->nchrs = 0; cd->sub = NOSUB; cd->arcs = NULL; cd->flags = 0; cd->block = NULL; return (color)(cd - cm->cd); } /* - freecolor - free a color (must have no arcs or subcolor) ^ static VOID freecolor(struct colormap *, pcolor); */ static VOID freecolor(cm, co) struct colormap *cm; pcolor co; { struct colordesc *cd = &cm->cd[co]; color pco, nco; /* for freelist scan */ assert(co >= 0); if (co == WHITE) return; assert(cd->arcs == NULL); assert(cd->sub == NOSUB); assert(cd->nchrs == 0); cd->flags = FREECOL; if (cd->block != NULL) { FREE(cd->block); cd->block = NULL; /* just paranoia */ } if ((size_t)co == cm->max) { while (cm->max > WHITE && UNUSEDCOLOR(&cm->cd[cm->max])) cm->max--; assert(cm->free >= 0); while ((size_t)cm->free > cm->max) cm->free = cm->cd[cm->free].sub; if (cm->free > 0) { assert(cm->free < cm->max); pco = cm->free; nco = cm->cd[pco].sub; while (nco > 0) if ((size_t)nco > cm->max) { /* take this one out of freelist */ nco = cm->cd[nco].sub; cm->cd[pco].sub = nco; } else { assert(nco < cm->max); pco = nco; nco = cm->cd[pco].sub; } } } else { cd->sub = cm->free; cm->free = (color)(cd - cm->cd); } } /* - pseudocolor - allocate a false color, to be managed by other means ^ static color pseudocolor(struct colormap *); */ static color pseudocolor(cm) struct colormap *cm; { color co; co = newcolor(cm); if (CISERR()) return COLORLESS; cm->cd[co].nchrs = 1; cm->cd[co].flags = PSEUDO; return co; } /* - subcolor - allocate a new subcolor (if necessary) to this chr ^ static color subcolor(struct colormap *, pchr c); */ static color subcolor(cm, c) struct colormap *cm; pchr c; { color co; /* current color of c */ color sco; /* new subcolor */ co = GETCOLOR(cm, c); sco = newsub(cm, co); if (CISERR()) return COLORLESS; assert(sco != COLORLESS); if (co == sco) /* already in an open subcolor */ return co; /* rest is redundant */ cm->cd[co].nchrs--; cm->cd[sco].nchrs++; setcolor(cm, c, sco); return sco; } /* - newsub - allocate a new subcolor (if necessary) for a color ^ static color newsub(struct colormap *, pcolor); */ static color newsub(cm, co) struct colormap *cm; pcolor co; { color sco; /* new subcolor */ sco = cm->cd[co].sub; if (sco == NOSUB) { /* color has no open subcolor */ if (cm->cd[co].nchrs == 1) /* optimization */ return co; sco = newcolor(cm); /* must create subcolor */ if (sco == COLORLESS) { assert(CISERR()); return COLORLESS; } cm->cd[co].sub = sco; cm->cd[sco].sub = sco; /* open subcolor points to self */ } assert(sco != NOSUB); return sco; } /* - subrange - allocate new subcolors to this range of chrs, fill in arcs ^ static VOID subrange(struct vars *, pchr, pchr, struct state *, ^ struct state *); */ static VOID subrange(v, from, to, lp, rp) struct vars *v; pchr from; pchr to; struct state *lp; struct state *rp; { uchr uf; int i; assert(from <= to); /* first, align "from" on a tree-block boundary */ uf = (uchr)from; i = (int)( ((uf + BYTTAB-1) & (uchr)~BYTMASK) - uf ); for (; from <= to && i > 0; i--, from++) newarc(v->nfa, PLAIN, subcolor(v->cm, from), lp, rp); if (from > to) /* didn't reach a boundary */ return; /* deal with whole blocks */ for (; to - from >= BYTTAB; from += BYTTAB) subblock(v, from, lp, rp); /* clean up any remaining partial table */ for (; from <= to; from++) newarc(v->nfa, PLAIN, subcolor(v->cm, from), lp, rp); } /* - subblock - allocate new subcolors for one tree block of chrs, fill in arcs ^ static VOID subblock(struct vars *, pchr, struct state *, struct state *); */ static VOID subblock(v, start, lp, rp) struct vars *v; pchr start; /* first of BYTTAB chrs */ struct state *lp; struct state *rp; { uchr uc = start; struct colormap *cm = v->cm; int shift; int level; int i; int b; union tree *t; union tree *cb; union tree *fillt; union tree *lastt; int previ; int ndone; color co; color sco; assert((uc % BYTTAB) == 0); /* find its color block, making new pointer blocks as needed */ t = cm->tree; fillt = NULL; for (level = 0, shift = BYTBITS * (NBYTS - 1); shift > 0; level++, shift -= BYTBITS) { b = (uc >> shift) & BYTMASK; lastt = t; t = lastt->tptr[b]; assert(t != NULL); fillt = &cm->tree[level+1]; if (t == fillt && shift > BYTBITS) { /* need new ptr block */ t = (union tree *)MALLOC(sizeof(struct ptrs)); if (t == NULL) { CERR(REG_ESPACE); return; } memcpy(VS(t->tptr), VS(fillt->tptr), BYTTAB*sizeof(union tree *)); lastt->tptr[b] = t; } } /* special cases: fill block or solid block */ co = t->tcolor[0]; cb = cm->cd[co].block; if (t == fillt || t == cb) { /* either way, we want a subcolor solid block */ sco = newsub(cm, co); t = cm->cd[sco].block; if (t == NULL) { /* must set it up */ t = (union tree *)MALLOC(sizeof(struct colors)); if (t == NULL) { CERR(REG_ESPACE); return; } for (i = 0; i < BYTTAB; i++) t->tcolor[i] = sco; cm->cd[sco].block = t; } /* find loop must have run at least once */ lastt->tptr[b] = t; newarc(v->nfa, PLAIN, sco, lp, rp); cm->cd[co].nchrs -= BYTTAB; cm->cd[sco].nchrs += BYTTAB; return; } /* general case, a mixed block to be altered */ i = 0; while (i < BYTTAB) { co = t->tcolor[i]; sco = newsub(cm, co); newarc(v->nfa, PLAIN, sco, lp, rp); previ = i; do { t->tcolor[i++] = sco; } while (i < BYTTAB && t->tcolor[i] == co); ndone = i - previ; cm->cd[co].nchrs -= ndone; cm->cd[sco].nchrs += ndone; } } /* - okcolors - promote subcolors to full colors ^ static VOID okcolors(struct nfa *, struct colormap *); */ static VOID okcolors(nfa, cm) struct nfa *nfa; struct colormap *cm; { struct colordesc *cd; struct colordesc *end = CDEND(cm); struct colordesc *scd; struct arc *a; color co; color sco; for (cd = cm->cd, co = 0; cd < end; cd++, co++) { sco = cd->sub; if (UNUSEDCOLOR(cd) || sco == NOSUB) { /* has no subcolor, no further action */ } else if (sco == co) { /* is subcolor, let parent deal with it */ } else if (cd->nchrs == 0) { /* parent empty, its arcs change color to subcolor */ cd->sub = NOSUB; scd = &cm->cd[sco]; assert(scd->nchrs > 0); assert(scd->sub == sco); scd->sub = NOSUB; while ((a = cd->arcs) != NULL) { assert(a->co == co); uncolorchain(cm, a); a->co = sco; colorchain(cm, a); } freecolor(cm, co); } else { /* parent's arcs must gain parallel subcolor arcs */ cd->sub = NOSUB; scd = &cm->cd[sco]; assert(scd->nchrs > 0); assert(scd->sub == sco); scd->sub = NOSUB; for (a = cd->arcs; a != NULL; a = a->colorchain) { assert(a->co == co); newarc(nfa, a->type, sco, a->from, a->to); } } } } /* - colorchain - add this arc to the color chain of its color ^ static VOID colorchain(struct colormap *, struct arc *); */ static VOID colorchain(cm, a) struct colormap *cm; struct arc *a; { struct colordesc *cd = &cm->cd[a->co]; if (cd->arcs) cd->arcs->colorchain_rev = a; a->colorchain = cd->arcs; a->colorchain_rev = NULL; cd->arcs = a; } /* - uncolorchain - delete this arc from the color chain of its color ^ static VOID uncolorchain(struct colormap *, struct arc *); */ static VOID uncolorchain(cm, a) struct colormap *cm; struct arc *a; { struct colordesc *cd = &cm->cd[a->co]; struct arc *aa = a->colorchain_rev; if (aa == NULL) { assert(cd->arcs == a); cd->arcs = a->colorchain; } else { assert(aa->colorchain == a); aa->colorchain = a->colorchain; } if (a->colorchain) a->colorchain->colorchain_rev = aa; a->colorchain = NULL; /* paranoia */ a->colorchain_rev = NULL; } /* - singleton - is this character in its own color? ^ static int singleton(struct colormap *, pchr c); */ static int /* predicate */ singleton(cm, c) struct colormap *cm; pchr c; { color co; /* color of c */ co = GETCOLOR(cm, c); if (cm->cd[co].nchrs == 1 && cm->cd[co].sub == NOSUB) return 1; return 0; } /* - rainbow - add arcs of all full colors (but one) between specified states ^ static VOID rainbow(struct nfa *, struct colormap *, int, pcolor, ^ struct state *, struct state *); */ static VOID rainbow(nfa, cm, type, but, from, to) struct nfa *nfa; struct colormap *cm; int type; pcolor but; /* COLORLESS if no exceptions */ struct state *from; struct state *to; { struct colordesc *cd; struct colordesc *end = CDEND(cm); color co; for (cd = cm->cd, co = 0; cd < end && !CISERR(); cd++, co++) if (!UNUSEDCOLOR(cd) && cd->sub != co && co != but && !(cd->flags&PSEUDO)) newarc(nfa, type, co, from, to); } /* - colorcomplement - add arcs of complementary colors * The calling sequence ought to be reconciled with cloneouts(). ^ static VOID colorcomplement(struct nfa *, struct colormap *, int, ^ struct state *, struct state *, struct state *); */ static VOID colorcomplement(nfa, cm, type, of, from, to) struct nfa *nfa; struct colormap *cm; int type; struct state *of; /* complements of this guy's PLAIN outarcs */ struct state *from; struct state *to; { struct colordesc *cd; struct colordesc *end = CDEND(cm); color co; assert(of != from); for (cd = cm->cd, co = 0; cd < end && !CISERR(); cd++, co++) if (!UNUSEDCOLOR(cd) && !(cd->flags&PSEUDO)) if (findarc(of, PLAIN, co) == NULL) newarc(nfa, type, co, from, to); } #ifdef REG_DEBUG /* ^ #ifdef REG_DEBUG */ /* - dumpcolors - debugging output ^ static VOID dumpcolors(struct colormap *, FILE *); */ static VOID dumpcolors(cm, f) struct colormap *cm; FILE *f; { struct colordesc *cd; struct colordesc *end; color co; chr c; char *has; fprintf(f, "max %ld\n", (long)cm->max); if (NBYTS > 1) fillcheck(cm, cm->tree, 0, f); end = CDEND(cm); for (cd = cm->cd + 1, co = 1; cd < end; cd++, co++) /* skip 0 */ if (!UNUSEDCOLOR(cd)) { assert(cd->nchrs > 0); has = (cd->block != NULL) ? "#" : ""; if (cd->flags&PSEUDO) fprintf(f, "#%2ld%s(ps): ", (long)co, has); else fprintf(f, "#%2ld%s(%2d): ", (long)co, has, cd->nchrs); /* it's hard to do this more efficiently */ for (c = CHR_MIN; c < CHR_MAX; c++) if (GETCOLOR(cm, c) == co) dumpchr(c, f); assert(c == CHR_MAX); if (GETCOLOR(cm, c) == co) dumpchr(c, f); fprintf(f, "\n"); } } /* - fillcheck - check proper filling of a tree ^ static VOID fillcheck(struct colormap *, union tree *, int, FILE *); */ static VOID fillcheck(cm, tree, level, f) struct colormap *cm; union tree *tree; int level; /* level number (top == 0) of this block */ FILE *f; { int i; union tree *t; union tree *fillt = &cm->tree[level+1]; assert(level < NBYTS-1); /* this level has pointers */ for (i = BYTTAB-1; i >= 0; i--) { t = tree->tptr[i]; if (t == NULL) fprintf(f, "NULL found in filled tree!\n"); else if (t == fillt) {} else if (level < NBYTS-2) /* more pointer blocks below */ fillcheck(cm, t, level+1, f); } } /* - dumpchr - print a chr * Kind of char-centric but works well enough for debug use. ^ static VOID dumpchr(pchr, FILE *); */ static VOID dumpchr(c, f) pchr c; FILE *f; { if (c == '\\') fprintf(f, "\\\\"); else if (c > ' ' && c <= '~') putc((char)c, f); else fprintf(f, "\\u%04lx", (long)c); } /* ^ #endif */ #endif /* ifdef REG_DEBUG */ tcl8.4.20/generic/tclIndexObj.c0000644003604700454610000003471412144442333014703 0ustar dgp771div/* * tclIndexObj.c -- * * This file implements objects of type "index". This object type * is used to lookup a keyword in a table of valid values and cache * the index of the matching entry. * * Copyright (c) 1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" /* * Prototypes for procedures defined later in this file: */ static int SetIndexFromAny _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr)); static void UpdateStringOfIndex _ANSI_ARGS_((Tcl_Obj *objPtr)); static void DupIndex _ANSI_ARGS_((Tcl_Obj *srcPtr, Tcl_Obj *dupPtr)); static void FreeIndex _ANSI_ARGS_((Tcl_Obj *objPtr)); /* * The structure below defines the index Tcl object type by means of * procedures that can be invoked by generic object code. */ Tcl_ObjType tclIndexType = { "index", /* name */ FreeIndex, /* freeIntRepProc */ DupIndex, /* dupIntRepProc */ UpdateStringOfIndex, /* updateStringProc */ SetIndexFromAny /* setFromAnyProc */ }; /* * The definition of the internal representation of the "index" * object; The internalRep.otherValuePtr field of an object of "index" * type will be a pointer to one of these structures. * * Keep this structure declaration in sync with tclTestObj.c */ typedef struct { VOID *tablePtr; /* Pointer to the table of strings */ int offset; /* Offset between table entries */ int index; /* Selected index into table. */ } IndexRep; /* * The following macros greatly simplify moving through a table... */ #define STRING_AT(table, offset, index) \ (*((CONST char * CONST *)(((char *)(table)) + ((offset) * (index))))) #define NEXT_ENTRY(table, offset) \ (&(STRING_AT(table, offset, 1))) #define EXPAND_OF(indexRep) \ STRING_AT((indexRep)->tablePtr, (indexRep)->offset, (indexRep)->index) /* *---------------------------------------------------------------------- * * Tcl_GetIndexFromObj -- * * This procedure looks up an object's value in a table of strings * and returns the index of the matching string, if any. * * Results: * * If the value of objPtr is identical to or a unique abbreviation * for one of the entries in objPtr, then the return value is * TCL_OK and the index of the matching entry is stored at * *indexPtr. If there isn't a proper match, then TCL_ERROR is * returned and an error message is left in interp's result (unless * interp is NULL). The msg argument is used in the error * message; for example, if msg has the value "option" then the * error message will say something flag 'bad option "foo": must be * ...' * * Side effects: * The result of the lookup is cached as the internal rep of * objPtr, so that repeated lookups can be done quickly. * *---------------------------------------------------------------------- */ #undef Tcl_GetIndexFromObj int Tcl_GetIndexFromObj(interp, objPtr, tablePtr, msg, flags, indexPtr) Tcl_Interp *interp; /* Used for error reporting if not NULL. */ Tcl_Obj *objPtr; /* Object containing the string to lookup. */ CONST char **tablePtr; /* Array of strings to compare against the * value of objPtr; last entry must be NULL * and there must not be duplicate entries. */ CONST char *msg; /* Identifying word to use in error messages. */ int flags; /* 0 or TCL_EXACT */ int *indexPtr; /* Place to store resulting integer index. */ { /* * See if there is a valid cached result from a previous lookup * (doing the check here saves the overhead of calling * Tcl_GetIndexFromObjStruct in the common case where the result * is cached). */ if (objPtr->typePtr == &tclIndexType) { IndexRep *indexRep = (IndexRep *) objPtr->internalRep.otherValuePtr; /* * Here's hoping we don't get hit by unfortunate packing * constraints on odd platforms like a Cray PVP... */ if (indexRep->tablePtr == (VOID *)tablePtr && indexRep->offset == sizeof(char *)) { *indexPtr = indexRep->index; return TCL_OK; } } return Tcl_GetIndexFromObjStruct(interp, objPtr, tablePtr, sizeof(char *), msg, flags, indexPtr); } /* *---------------------------------------------------------------------- * * Tcl_GetIndexFromObjStruct -- * * This procedure looks up an object's value given a starting * string and an offset for the amount of space between strings. * This is useful when the strings are embedded in some other * kind of array. * * Results: * * If the value of objPtr is identical to or a unique abbreviation * for one of the entries in objPtr, then the return value is * TCL_OK and the index of the matching entry is stored at * *indexPtr. If there isn't a proper match, then TCL_ERROR is * returned and an error message is left in interp's result (unless * interp is NULL). The msg argument is used in the error * message; for example, if msg has the value "option" then the * error message will say something like 'bad option "foo": must be * ...' * * Side effects: * The result of the lookup is cached as the internal rep of * objPtr, so that repeated lookups can be done quickly. * *---------------------------------------------------------------------- */ int Tcl_GetIndexFromObjStruct(interp, objPtr, tablePtr, offset, msg, flags, indexPtr) Tcl_Interp *interp; /* Used for error reporting if not NULL. */ Tcl_Obj *objPtr; /* Object containing the string to lookup. */ CONST VOID *tablePtr; /* The first string in the table. The second * string will be at this address plus the * offset, the third plus the offset again, * etc. The last entry must be NULL * and there must not be duplicate entries. */ int offset; /* The number of bytes between entries */ CONST char *msg; /* Identifying word to use in error messages. */ int flags; /* 0 or TCL_EXACT */ int *indexPtr; /* Place to store resulting integer index. */ { int index, i, numAbbrev; char *key, *p1; CONST char *p2; CONST char * CONST *entryPtr; Tcl_Obj *resultPtr; IndexRep *indexRep; /* Protect against invalid values, like -1 or 0. */ if (offset < (int)sizeof(char *)) { offset = (int)sizeof(char *); } /* * See if there is a valid cached result from a previous lookup. */ if (objPtr->typePtr == &tclIndexType) { indexRep = (IndexRep *) objPtr->internalRep.otherValuePtr; if (indexRep->tablePtr==tablePtr && indexRep->offset==offset) { *indexPtr = indexRep->index; return TCL_OK; } } /* * Lookup the value of the object in the table. Accept unique * abbreviations unless TCL_EXACT is set in flags. */ key = TclGetString(objPtr); index = -1; numAbbrev = 0; /* * Scan the table looking for one of: * - An exact match (always preferred) * - A single abbreviation (allowed depending on flags) * - Several abbreviations (never allowed, but overridden by exact match) */ for (entryPtr = tablePtr, i = 0; *entryPtr != NULL; entryPtr = NEXT_ENTRY(entryPtr, offset), i++) { for (p1 = key, p2 = *entryPtr; *p1 == *p2; p1++, p2++) { if (*p1 == '\0') { index = i; goto done; } } if (*p1 == '\0') { /* * The value is an abbreviation for this entry. Continue * checking other entries to make sure it's unique. If we * get more than one unique abbreviation, keep searching to * see if there is an exact match, but remember the number * of unique abbreviations and don't allow either. */ numAbbrev++; index = i; } } /* * Check if we were instructed to disallow abbreviations. */ if ((flags & TCL_EXACT) || (key[0] == '\0') || (numAbbrev != 1)) { goto error; } done: /* * Cache the found representation. Note that we want to avoid * allocating a new internal-rep if at all possible since that is * potentially a slow operation. */ if (objPtr->typePtr == &tclIndexType) { indexRep = (IndexRep *) objPtr->internalRep.otherValuePtr; } else { if ((objPtr->typePtr != NULL) && (objPtr->typePtr->freeIntRepProc != NULL)) { objPtr->typePtr->freeIntRepProc(objPtr); } indexRep = (IndexRep *) ckalloc(sizeof(IndexRep)); objPtr->internalRep.otherValuePtr = (VOID *) indexRep; objPtr->typePtr = &tclIndexType; } indexRep->tablePtr = (VOID*) tablePtr; indexRep->offset = offset; indexRep->index = index; *indexPtr = index; return TCL_OK; error: if (interp != NULL) { /* * Produce a fancy error message. */ int count = 0; TclNewObj(resultPtr); Tcl_SetObjResult(interp, resultPtr); entryPtr = tablePtr; while ((*entryPtr != NULL) && !**entryPtr) { entryPtr = NEXT_ENTRY(entryPtr, offset); } Tcl_AppendStringsToObj(resultPtr, (numAbbrev > 1) && !(flags & TCL_EXACT) ? "ambiguous " : "bad ", msg, " \"", key, "\": must be ", *entryPtr, (char*)NULL); entryPtr = NEXT_ENTRY(entryPtr, offset); while (*entryPtr != NULL) { if (*NEXT_ENTRY(entryPtr, offset) == NULL) { Tcl_AppendStringsToObj(resultPtr, (count > 0) ? ", or " : " or ", *entryPtr, (char *) NULL); } else if (**entryPtr) { Tcl_AppendStringsToObj(resultPtr, ", ", *entryPtr, (char *) NULL); count++; } entryPtr = NEXT_ENTRY(entryPtr, offset); } } return TCL_ERROR; } /* *---------------------------------------------------------------------- * * SetIndexFromAny -- * * This procedure is called to convert a Tcl object to index * internal form. However, this doesn't make sense (need to have a * table of keywords in order to do the conversion) so the * procedure always generates an error. * * Results: * The return value is always TCL_ERROR, and an error message is * left in interp's result if interp isn't NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int SetIndexFromAny(interp, objPtr) Tcl_Interp *interp; /* Used for error reporting if not NULL. */ register Tcl_Obj *objPtr; /* The object to convert. */ { if (interp) { Tcl_AppendToObj(Tcl_GetObjResult(interp), "can't convert value to index except via Tcl_GetIndexFromObj API", -1); } return TCL_ERROR; } /* *---------------------------------------------------------------------- * * UpdateStringOfIndex -- * * This procedure is called to convert a Tcl object from index * internal form to its string form. No abbreviation is ever * generated. * * Results: * None. * * Side effects: * The string representation of the object is updated. * *---------------------------------------------------------------------- */ static void UpdateStringOfIndex(objPtr) Tcl_Obj *objPtr; { IndexRep *indexRep = (IndexRep *) objPtr->internalRep.otherValuePtr; register char *buf; register unsigned len; register CONST char *indexStr = EXPAND_OF(indexRep); len = strlen(indexStr); buf = (char *) ckalloc(len + 1); memcpy(buf, indexStr, len+1); objPtr->bytes = buf; objPtr->length = len; } /* *---------------------------------------------------------------------- * * DupIndex -- * * This procedure is called to copy the internal rep of an index * Tcl object from to another object. * * Results: * None. * * Side effects: * The internal representation of the target object is updated * and the type is set. * *---------------------------------------------------------------------- */ static void DupIndex(srcPtr, dupPtr) Tcl_Obj *srcPtr, *dupPtr; { IndexRep *srcIndexRep = (IndexRep *) srcPtr->internalRep.otherValuePtr; IndexRep *dupIndexRep = (IndexRep *) ckalloc(sizeof(IndexRep)); memcpy(dupIndexRep, srcIndexRep, sizeof(IndexRep)); dupPtr->internalRep.otherValuePtr = (VOID *) dupIndexRep; dupPtr->typePtr = &tclIndexType; } /* *---------------------------------------------------------------------- * * FreeIndex -- * * This procedure is called to delete the internal rep of an index * Tcl object. * * Results: * None. * * Side effects: * The internal representation of the target object is deleted. * *---------------------------------------------------------------------- */ static void FreeIndex(objPtr) Tcl_Obj *objPtr; { ckfree((char *) objPtr->internalRep.otherValuePtr); } /* *---------------------------------------------------------------------- * * Tcl_WrongNumArgs -- * * This procedure generates a "wrong # args" error message in an * interpreter. It is used as a utility function by many command * procedures. * * Results: * None. * * Side effects: * An error message is generated in interp's result object to * indicate that a command was invoked with the wrong number of * arguments. The message has the form * wrong # args: should be "foo bar additional stuff" * where "foo" and "bar" are the initial objects in objv (objc * determines how many of these are printed) and "additional stuff" * is the contents of the message argument. * *---------------------------------------------------------------------- */ void Tcl_WrongNumArgs(interp, objc, objv, message) Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments to print * from objv. */ Tcl_Obj *CONST objv[]; /* Initial argument objects, which * should be included in the error * message. */ CONST char *message; /* Error message to print after the * leading objects in objv. The * message may be NULL. */ { Tcl_Obj *objPtr; int i; register IndexRep *indexRep; TclNewObj(objPtr); Tcl_SetObjResult(interp, objPtr); Tcl_AppendToObj(objPtr, "wrong # args: should be \"", -1); for (i = 0; i < objc; i++) { /* * If the object is an index type use the index table which allows * for the correct error message even if the subcommand was * abbreviated. Otherwise, just use the string rep. */ if (objv[i]->typePtr == &tclIndexType) { indexRep = (IndexRep *) objv[i]->internalRep.otherValuePtr; Tcl_AppendStringsToObj(objPtr, EXPAND_OF(indexRep), (char *) NULL); } else { Tcl_AppendStringsToObj(objPtr, Tcl_GetString(objv[i]), (char *) NULL); } /* * Append a space character (" ") if there is more text to follow * (either another element from objv, or the message string). */ if ((i < (objc - 1)) || message) { Tcl_AppendStringsToObj(objPtr, " ", (char *) NULL); } } if (message) { Tcl_AppendStringsToObj(objPtr, message, (char *) NULL); } Tcl_AppendStringsToObj(objPtr, "\"", (char *) NULL); } tcl8.4.20/generic/README0000644003604700454610000000027312052456743013213 0ustar dgp771divThis directory contains Tcl source files that work on all the platforms where Tcl runs (e.g. UNIX, PCs). Platform-specific sources are in the directories ../unix, ../win, and ../macosx. tcl8.4.20/generic/tclCmdAH.c0000644003604700454610000017671212052456743014132 0ustar dgp771div/* * tclCmdAH.c -- * * This file contains the top-level command routines for most of * the Tcl built-in commands whose names begin with the letters * A to H. * * Copyright (c) 1987-1993 The Regents of the University of California. * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef _WIN64 /* See [Bug 3354324]: file mtime sets wrong time */ # define _USE_32BIT_TIME_T #endif #include #include "tclInt.h" #include "tclPort.h" #include /* * Prototypes for local procedures defined in this file: */ static int CheckAccess _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr, int mode)); static int GetStatBuf _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_FSStatProc *statProc, Tcl_StatBuf *statPtr)); static char * GetTypeFromMode _ANSI_ARGS_((int mode)); static int StoreStatData _ANSI_ARGS_((Tcl_Interp *interp, char *varName, Tcl_StatBuf *statPtr)); /* *---------------------------------------------------------------------- * * Tcl_BreakObjCmd -- * * This procedure is invoked to process the "break" Tcl command. * See the user documentation for details on what it does. * * With the bytecode compiler, this procedure is only called when * a command name is computed at runtime, and is "break" or the name * to which "break" was renamed: e.g., "set z break; $z" * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_BreakObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { if (objc != 1) { Tcl_WrongNumArgs(interp, 1, objv, NULL); return TCL_ERROR; } return TCL_BREAK; } /* *---------------------------------------------------------------------- * * Tcl_CaseObjCmd -- * * This procedure is invoked to process the "case" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl object result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_CaseObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { register int i; int body, result, caseObjc; char *string, *arg; Tcl_Obj *CONST *caseObjv; Tcl_Obj *armPtr; if (objc < 3) { Tcl_WrongNumArgs(interp, 1, objv, "string ?in? patList body ... ?default body?"); return TCL_ERROR; } string = Tcl_GetString(objv[1]); body = -1; arg = Tcl_GetString(objv[2]); if (strcmp(arg, "in") == 0) { i = 3; } else { i = 2; } caseObjc = objc - i; caseObjv = objv + i; /* * If all of the pattern/command pairs are lumped into a single * argument, split them out again. */ if (caseObjc == 1) { Tcl_Obj **newObjv; Tcl_ListObjGetElements(interp, caseObjv[0], &caseObjc, &newObjv); caseObjv = newObjv; } for (i = 0; i < caseObjc; i += 2) { int patObjc, j; CONST char **patObjv; char *pat; unsigned char *p; if (i == (caseObjc - 1)) { Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "extra case pattern with no body", -1); return TCL_ERROR; } /* * Check for special case of single pattern (no list) with * no backslash sequences. */ pat = Tcl_GetString(caseObjv[i]); for (p = (unsigned char *) pat; *p != '\0'; p++) { if (isspace(*p) || (*p == '\\')) { /* INTL: ISO space, UCHAR */ break; } } if (*p == '\0') { if ((*pat == 'd') && (strcmp(pat, "default") == 0)) { body = i + 1; } if (Tcl_StringMatch(string, pat)) { body = i + 1; goto match; } continue; } /* * Break up pattern lists, then check each of the patterns * in the list. */ result = Tcl_SplitList(interp, pat, &patObjc, &patObjv); if (result != TCL_OK) { return result; } for (j = 0; j < patObjc; j++) { if (Tcl_StringMatch(string, patObjv[j])) { body = i + 1; break; } } ckfree((char *) patObjv); if (j < patObjc) { break; } } match: if (body != -1) { armPtr = caseObjv[body - 1]; result = Tcl_EvalObjEx(interp, caseObjv[body], 0); if (result == TCL_ERROR) { char msg[100 + TCL_INTEGER_SPACE]; arg = Tcl_GetString(armPtr); sprintf(msg, "\n (\"%.50s\" arm line %d)", arg, interp->errorLine); Tcl_AddObjErrorInfo(interp, msg, -1); } return result; } /* * Nothing matched: return nothing. */ return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_CatchObjCmd -- * * This object-based procedure is invoked to process the "catch" Tcl * command. See the user documentation for details on what it does. * * Results: * A standard Tcl object result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_CatchObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Tcl_Obj *varNamePtr = NULL; int result; #ifdef TCL_TIP280 Interp* iPtr = (Interp*) interp; #endif if ((objc != 2) && (objc != 3)) { Tcl_WrongNumArgs(interp, 1, objv, "command ?varName?"); return TCL_ERROR; } if (objc == 3) { varNamePtr = objv[2]; } #ifndef TCL_TIP280 result = Tcl_EvalObjEx(interp, objv[1], 0); #else /* TIP #280. Make invoking context available to caught script */ result = TclEvalObjEx(interp, objv[1], 0, iPtr->cmdFramePtr,1); #endif if (objc == 3) { if (Tcl_ObjSetVar2(interp, varNamePtr, NULL, Tcl_GetObjResult(interp), 0) == NULL) { Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "couldn't save command result in variable", -1); return TCL_ERROR; } } /* * Set the interpreter's object result to an integer object holding the * integer Tcl_EvalObj result. Note that we don't bother generating a * string representation. We reset the interpreter's object result * to an unshared empty object and then set it to be an integer object. */ Tcl_ResetResult(interp); Tcl_SetIntObj(Tcl_GetObjResult(interp), result); return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_CdObjCmd -- * * This procedure is invoked to process the "cd" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_CdObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Tcl_Obj *dir; int result; if (objc > 2) { Tcl_WrongNumArgs(interp, 1, objv, "?dirName?"); return TCL_ERROR; } if (objc == 2) { dir = objv[1]; } else { dir = Tcl_NewStringObj("~",1); Tcl_IncrRefCount(dir); } if (Tcl_FSConvertToPathType(interp, dir) != TCL_OK) { result = TCL_ERROR; } else { result = Tcl_FSChdir(dir); if (result != TCL_OK) { Tcl_AppendResult(interp, "couldn't change working directory to \"", Tcl_GetString(dir), "\": ", Tcl_PosixError(interp), (char *) NULL); result = TCL_ERROR; } } if (objc != 2) { Tcl_DecrRefCount(dir); } return result; } /* *---------------------------------------------------------------------- * * Tcl_ConcatObjCmd -- * * This object-based procedure is invoked to process the "concat" Tcl * command. See the user documentation for details on what it does. * * Results: * A standard Tcl object result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_ConcatObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { if (objc >= 2) { Tcl_SetObjResult(interp, Tcl_ConcatObj(objc-1, objv+1)); } return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_ContinueObjCmd - * * This procedure is invoked to process the "continue" Tcl command. * See the user documentation for details on what it does. * * With the bytecode compiler, this procedure is only called when * a command name is computed at runtime, and is "continue" or the name * to which "continue" was renamed: e.g., "set z continue; $z" * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_ContinueObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { if (objc != 1) { Tcl_WrongNumArgs(interp, 1, objv, NULL); return TCL_ERROR; } return TCL_CONTINUE; } /* *---------------------------------------------------------------------- * * Tcl_EncodingObjCmd -- * * This command manipulates encodings. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ int Tcl_EncodingObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int index, length; Tcl_Encoding encoding; char *string; Tcl_DString ds; Tcl_Obj *resultPtr; static CONST char *optionStrings[] = { "convertfrom", "convertto", "names", "system", NULL }; enum options { ENC_CONVERTFROM, ENC_CONVERTTO, ENC_NAMES, ENC_SYSTEM }; if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0, &index) != TCL_OK) { return TCL_ERROR; } switch ((enum options) index) { case ENC_CONVERTTO: case ENC_CONVERTFROM: { Tcl_Obj *data; if (objc == 3) { encoding = Tcl_GetEncoding(interp, NULL); data = objv[2]; } else if (objc == 4) { if (TclGetEncodingFromObj(interp, objv[2], &encoding) != TCL_OK) { return TCL_ERROR; } data = objv[3]; } else { Tcl_WrongNumArgs(interp, 2, objv, "?encoding? data"); return TCL_ERROR; } if ((enum options) index == ENC_CONVERTFROM) { /* * Treat the string as binary data. */ string = (char *) Tcl_GetByteArrayFromObj(data, &length); Tcl_ExternalToUtfDString(encoding, string, length, &ds); /* * Note that we cannot use Tcl_DStringResult here because * it will truncate the string at the first null byte. */ Tcl_SetStringObj(Tcl_GetObjResult(interp), Tcl_DStringValue(&ds), Tcl_DStringLength(&ds)); Tcl_DStringFree(&ds); } else { /* * Store the result as binary data. */ string = Tcl_GetStringFromObj(data, &length); Tcl_UtfToExternalDString(encoding, string, length, &ds); resultPtr = Tcl_GetObjResult(interp); Tcl_SetByteArrayObj(resultPtr, (unsigned char *) Tcl_DStringValue(&ds), Tcl_DStringLength(&ds)); Tcl_DStringFree(&ds); } Tcl_FreeEncoding(encoding); break; } case ENC_NAMES: { if (objc > 2) { Tcl_WrongNumArgs(interp, 2, objv, NULL); return TCL_ERROR; } Tcl_GetEncodingNames(interp); break; } case ENC_SYSTEM: { if (objc > 3) { Tcl_WrongNumArgs(interp, 2, objv, "?encoding?"); return TCL_ERROR; } if (objc == 2) { Tcl_SetStringObj(Tcl_GetObjResult(interp), Tcl_GetEncodingName(NULL), -1); } else { return Tcl_SetSystemEncoding(interp, Tcl_GetStringFromObj(objv[2], NULL)); } break; } } return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_ErrorObjCmd -- * * This procedure is invoked to process the "error" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl object result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_ErrorObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Interp *iPtr = (Interp *) interp; char *info; int infoLen; if ((objc < 2) || (objc > 4)) { Tcl_WrongNumArgs(interp, 1, objv, "message ?errorInfo? ?errorCode?"); return TCL_ERROR; } if (objc >= 3) { /* process the optional info argument */ info = Tcl_GetStringFromObj(objv[2], &infoLen); if (infoLen > 0) { Tcl_AddObjErrorInfo(interp, info, infoLen); iPtr->flags |= ERR_ALREADY_LOGGED; } } if (objc == 4) { Tcl_SetVar2Ex(interp, "errorCode", NULL, objv[3], TCL_GLOBAL_ONLY); iPtr->flags |= ERROR_CODE_SET; } Tcl_SetObjResult(interp, objv[1]); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * Tcl_EvalObjCmd -- * * This object-based procedure is invoked to process the "eval" Tcl * command. See the user documentation for details on what it does. * * Results: * A standard Tcl object result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_EvalObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int result; register Tcl_Obj *objPtr; #ifdef TCL_TIP280 Interp* iPtr = (Interp*) interp; #endif if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "arg ?arg ...?"); return TCL_ERROR; } if (objc == 2) { #ifndef TCL_TIP280 result = Tcl_EvalObjEx(interp, objv[1], TCL_EVAL_DIRECT); #else /* TIP #280. Make argument location available to eval'd script */ CmdFrame* invoker = iPtr->cmdFramePtr; int word = 1; TclArgumentGet (interp, objv[1], &invoker, &word); result = TclEvalObjEx(interp, objv[1], TCL_EVAL_DIRECT, invoker, word); #endif } else { /* * More than one argument: concatenate them together with spaces * between, then evaluate the result. Tcl_EvalObjEx will delete * the object when it decrements its refcount after eval'ing it. */ objPtr = Tcl_ConcatObj(objc-1, objv+1); #ifndef TCL_TIP280 result = Tcl_EvalObjEx(interp, objPtr, TCL_EVAL_DIRECT); #else /* TIP #280. Make invoking context available to eval'd script */ result = TclEvalObjEx(interp, objPtr, TCL_EVAL_DIRECT, NULL, 0); #endif } if (result == TCL_ERROR) { char msg[32 + TCL_INTEGER_SPACE]; sprintf(msg, "\n (\"eval\" body line %d)", interp->errorLine); Tcl_AddObjErrorInfo(interp, msg, -1); } return result; } /* *---------------------------------------------------------------------- * * Tcl_ExitObjCmd -- * * This procedure is invoked to process the "exit" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl object result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_ExitObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int value; if ((objc != 1) && (objc != 2)) { Tcl_WrongNumArgs(interp, 1, objv, "?returnCode?"); return TCL_ERROR; } if (objc == 1) { value = 0; } else if (Tcl_GetIntFromObj(interp, objv[1], &value) != TCL_OK) { return TCL_ERROR; } Tcl_Exit(value); /*NOTREACHED*/ return TCL_OK; /* Better not ever reach this! */ } /* *---------------------------------------------------------------------- * * Tcl_ExprObjCmd -- * * This object-based procedure is invoked to process the "expr" Tcl * command. See the user documentation for details on what it does. * * With the bytecode compiler, this procedure is called in two * circumstances: 1) to execute expr commands that are too complicated * or too unsafe to try compiling directly into an inline sequence of * instructions, and 2) to execute commands where the command name is * computed at runtime and is "expr" or the name to which "expr" was * renamed (e.g., "set z expr; $z 2+3") * * Results: * A standard Tcl object result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_ExprObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { register Tcl_Obj *objPtr; Tcl_Obj *resultPtr; register char *bytes; int length, i, result; if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "arg ?arg ...?"); return TCL_ERROR; } if (objc == 2) { result = Tcl_ExprObj(interp, objv[1], &resultPtr); if (result == TCL_OK) { Tcl_SetObjResult(interp, resultPtr); Tcl_DecrRefCount(resultPtr); /* done with the result object */ } return result; } /* * Create a new object holding the concatenated argument strings. */ /*** QUESTION: Do we need to copy the slow way? ***/ bytes = Tcl_GetStringFromObj(objv[1], &length); objPtr = Tcl_NewStringObj(bytes, length); Tcl_IncrRefCount(objPtr); for (i = 2; i < objc; i++) { Tcl_AppendToObj(objPtr, " ", 1); bytes = Tcl_GetStringFromObj(objv[i], &length); Tcl_AppendToObj(objPtr, bytes, length); } /* * Evaluate the concatenated string object. */ result = Tcl_ExprObj(interp, objPtr, &resultPtr); if (result == TCL_OK) { Tcl_SetObjResult(interp, resultPtr); Tcl_DecrRefCount(resultPtr); /* done with the result object */ } /* * Free allocated resources. */ Tcl_DecrRefCount(objPtr); return result; } /* *---------------------------------------------------------------------- * * Tcl_FileObjCmd -- * * This procedure is invoked to process the "file" Tcl command. * See the user documentation for details on what it does. * PLEASE NOTE THAT THIS FAILS WITH FILENAMES AND PATHS WITH * EMBEDDED NULLS, WHICH COULD THEORETICALLY HAPPEN ON A MAC. * With the object-based Tcl_FS APIs, the above NOTE may no * longer be true. In any case this assertion should be tested. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_FileObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int index; /* * This list of constants should match the fileOption string array below. */ static CONST char *fileOptions[] = { "atime", "attributes", "channels", "copy", "delete", "dirname", "executable", "exists", "extension", "isdirectory", "isfile", "join", "link", "lstat", "mtime", "mkdir", "nativename", "normalize", "owned", "pathtype", "readable", "readlink", "rename", "rootname", "separator", "size", "split", "stat", "system", "tail", "type", "volumes", "writable", (char *) NULL }; enum options { FCMD_ATIME, FCMD_ATTRIBUTES, FCMD_CHANNELS, FCMD_COPY, FCMD_DELETE, FCMD_DIRNAME, FCMD_EXECUTABLE, FCMD_EXISTS, FCMD_EXTENSION, FCMD_ISDIRECTORY, FCMD_ISFILE, FCMD_JOIN, FCMD_LINK, FCMD_LSTAT, FCMD_MTIME, FCMD_MKDIR, FCMD_NATIVENAME, FCMD_NORMALIZE, FCMD_OWNED, FCMD_PATHTYPE, FCMD_READABLE, FCMD_READLINK, FCMD_RENAME, FCMD_ROOTNAME, FCMD_SEPARATOR, FCMD_SIZE, FCMD_SPLIT, FCMD_STAT, FCMD_SYSTEM, FCMD_TAIL, FCMD_TYPE, FCMD_VOLUMES, FCMD_WRITABLE }; if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[1], fileOptions, "option", 0, &index) != TCL_OK) { return TCL_ERROR; } switch ((enum options) index) { case FCMD_ATIME: { Tcl_StatBuf buf; struct utimbuf tval; if ((objc < 3) || (objc > 4)) { Tcl_WrongNumArgs(interp, 2, objv, "name ?time?"); return TCL_ERROR; } if (GetStatBuf(interp, objv[2], Tcl_FSStat, &buf) != TCL_OK) { return TCL_ERROR; } if (objc == 4) { long newTime; if (Tcl_GetLongFromObj(interp, objv[3], &newTime) != TCL_OK) { return TCL_ERROR; } tval.actime = newTime; tval.modtime = buf.st_mtime; if (Tcl_FSUtime(objv[2], &tval) != 0) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "could not set access time for file \"", Tcl_GetString(objv[2]), "\": ", Tcl_PosixError(interp), (char *) NULL); return TCL_ERROR; } /* * Do another stat to ensure that the we return the * new recognized atime - hopefully the same as the * one we sent in. However, fs's like FAT don't * even know what atime is. */ if (GetStatBuf(interp, objv[2], Tcl_FSStat, &buf) != TCL_OK) { return TCL_ERROR; } } Tcl_SetLongObj(Tcl_GetObjResult(interp), (long) buf.st_atime); return TCL_OK; } case FCMD_ATTRIBUTES: { return TclFileAttrsCmd(interp, objc, objv); } case FCMD_CHANNELS: { if ((objc < 2) || (objc > 3)) { Tcl_WrongNumArgs(interp, 2, objv, "?pattern?"); return TCL_ERROR; } return Tcl_GetChannelNamesEx(interp, ((objc == 2) ? NULL : Tcl_GetString(objv[2]))); } case FCMD_COPY: { return TclFileCopyCmd(interp, objc, objv); } case FCMD_DELETE: { return TclFileDeleteCmd(interp, objc, objv); } case FCMD_DIRNAME: { Tcl_Obj *dirPtr; if (objc != 3) { goto only3Args; } dirPtr = TclFileDirname(interp, objv[2]); if (dirPtr == NULL) { return TCL_ERROR; } else { Tcl_SetObjResult(interp, dirPtr); Tcl_DecrRefCount(dirPtr); return TCL_OK; } } case FCMD_EXECUTABLE: { if (objc != 3) { goto only3Args; } return CheckAccess(interp, objv[2], X_OK); } case FCMD_EXISTS: { if (objc != 3) { goto only3Args; } return CheckAccess(interp, objv[2], F_OK); } case FCMD_EXTENSION: { char *fileName, *extension; if (objc != 3) { goto only3Args; } fileName = Tcl_GetString(objv[2]); extension = TclGetExtension(fileName); if (extension != NULL) { Tcl_SetStringObj(Tcl_GetObjResult(interp), extension, -1); } return TCL_OK; } case FCMD_ISDIRECTORY: { int value; Tcl_StatBuf buf; if (objc != 3) { goto only3Args; } value = 0; if (GetStatBuf(NULL, objv[2], Tcl_FSStat, &buf) == TCL_OK) { value = S_ISDIR(buf.st_mode); } Tcl_SetBooleanObj(Tcl_GetObjResult(interp), value); return TCL_OK; } case FCMD_ISFILE: { int value; Tcl_StatBuf buf; if (objc != 3) { goto only3Args; } value = 0; if (GetStatBuf(NULL, objv[2], Tcl_FSStat, &buf) == TCL_OK) { value = S_ISREG(buf.st_mode); } Tcl_SetBooleanObj(Tcl_GetObjResult(interp), value); return TCL_OK; } case FCMD_JOIN: { Tcl_Obj *resObj; if (objc < 3) { Tcl_WrongNumArgs(interp, 2, objv, "name ?name ...?"); return TCL_ERROR; } resObj = Tcl_FSJoinToPath(NULL, objc - 2, objv + 2); Tcl_SetObjResult(interp, resObj); return TCL_OK; } case FCMD_LINK: { Tcl_Obj *contents; int index; if (objc < 3 || objc > 5) { Tcl_WrongNumArgs(interp, 2, objv, "?-linktype? linkname ?target?"); return TCL_ERROR; } /* Index of the 'source' argument */ if (objc == 5) { index = 3; } else { index = 2; } if (objc > 3) { int linkAction; if (objc == 5) { /* We have a '-linktype' argument */ static CONST char *linkTypes[] = { "-symbolic", "-hard", NULL }; if (Tcl_GetIndexFromObj(interp, objv[2], linkTypes, "switch", 0, &linkAction) != TCL_OK) { return TCL_ERROR; } if (linkAction == 0) { linkAction = TCL_CREATE_SYMBOLIC_LINK; } else { linkAction = TCL_CREATE_HARD_LINK; } } else { linkAction = TCL_CREATE_SYMBOLIC_LINK|TCL_CREATE_HARD_LINK; } if (Tcl_FSConvertToPathType(interp, objv[index]) != TCL_OK) { return TCL_ERROR; } /* Create link from source to target */ contents = Tcl_FSLink(objv[index], objv[index+1], linkAction); if (contents == NULL) { /* * We handle two common error cases specially, and * for all other errors, we use the standard posix * error message. */ if (errno == EEXIST) { Tcl_AppendResult(interp, "could not create new link \"", Tcl_GetString(objv[index]), "\": that path already exists", (char *) NULL); } else if (errno == ENOENT) { Tcl_AppendResult(interp, "could not create new link \"", Tcl_GetString(objv[index]), "\" since target \"", Tcl_GetString(objv[index+1]), "\" doesn't exist", (char *) NULL); } else { Tcl_AppendResult(interp, "could not create new link \"", Tcl_GetString(objv[index]), "\" pointing to \"", Tcl_GetString(objv[index+1]), "\": ", Tcl_PosixError(interp), (char *) NULL); } return TCL_ERROR; } } else { if (Tcl_FSConvertToPathType(interp, objv[index]) != TCL_OK) { return TCL_ERROR; } /* Read link */ contents = Tcl_FSLink(objv[index], NULL, 0); if (contents == NULL) { Tcl_AppendResult(interp, "could not read link \"", Tcl_GetString(objv[index]), "\": ", Tcl_PosixError(interp), (char *) NULL); return TCL_ERROR; } } Tcl_SetObjResult(interp, contents); if (objc == 3) { /* * If we are reading a link, we need to free this * result refCount. If we are creating a link, this * will just be objv[index+1], and so we don't own it. */ Tcl_DecrRefCount(contents); } return TCL_OK; } case FCMD_LSTAT: { char *varName; Tcl_StatBuf buf; if (objc != 4) { Tcl_WrongNumArgs(interp, 2, objv, "name varName"); return TCL_ERROR; } if (GetStatBuf(interp, objv[2], Tcl_FSLstat, &buf) != TCL_OK) { return TCL_ERROR; } varName = Tcl_GetString(objv[3]); return StoreStatData(interp, varName, &buf); } case FCMD_MTIME: { Tcl_StatBuf buf; struct utimbuf tval; if ((objc < 3) || (objc > 4)) { Tcl_WrongNumArgs(interp, 2, objv, "name ?time?"); return TCL_ERROR; } if (GetStatBuf(interp, objv[2], Tcl_FSStat, &buf) != TCL_OK) { return TCL_ERROR; } if (objc == 4) { long newTime; if (Tcl_GetLongFromObj(interp, objv[3], &newTime) != TCL_OK) { return TCL_ERROR; } tval.actime = buf.st_atime; tval.modtime = newTime; if (Tcl_FSUtime(objv[2], &tval) != 0) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "could not set modification time for file \"", Tcl_GetString(objv[2]), "\": ", Tcl_PosixError(interp), (char *) NULL); return TCL_ERROR; } /* * Do another stat to ensure that the we return the * new recognized atime - hopefully the same as the * one we sent in. However, fs's like FAT don't * even know what atime is. */ if (GetStatBuf(interp, objv[2], Tcl_FSStat, &buf) != TCL_OK) { return TCL_ERROR; } } Tcl_SetLongObj(Tcl_GetObjResult(interp), (long) buf.st_mtime); return TCL_OK; } case FCMD_MKDIR: { if (objc < 3) { Tcl_WrongNumArgs(interp, 2, objv, "name ?name ...?"); return TCL_ERROR; } return TclFileMakeDirsCmd(interp, objc, objv); } case FCMD_NATIVENAME: { CONST char *fileName; Tcl_DString ds; if (objc != 3) { goto only3Args; } fileName = Tcl_GetString(objv[2]); fileName = Tcl_TranslateFileName(interp, fileName, &ds); if (fileName == NULL) { return TCL_ERROR; } Tcl_SetStringObj(Tcl_GetObjResult(interp), fileName, Tcl_DStringLength(&ds)); Tcl_DStringFree(&ds); return TCL_OK; } case FCMD_NORMALIZE: { Tcl_Obj *fileName; if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "filename"); return TCL_ERROR; } fileName = Tcl_FSGetNormalizedPath(interp, objv[2]); if (fileName == NULL) { return TCL_ERROR; } Tcl_SetObjResult(interp, fileName); return TCL_OK; } case FCMD_OWNED: { int value; Tcl_StatBuf buf; if (objc != 3) { goto only3Args; } value = 0; if (GetStatBuf(NULL, objv[2], Tcl_FSStat, &buf) == TCL_OK) { /* * For Windows there are no user ids * associated with a file, so we always return 1. */ #if defined(__WIN32__) || defined(__CYGWIN__) value = 1; #else value = (geteuid() == buf.st_uid); #endif } Tcl_SetBooleanObj(Tcl_GetObjResult(interp), value); return TCL_OK; } case FCMD_PATHTYPE: { if (objc != 3) { goto only3Args; } switch (Tcl_FSGetPathType(objv[2])) { case TCL_PATH_ABSOLUTE: Tcl_SetStringObj(Tcl_GetObjResult(interp), "absolute", -1); break; case TCL_PATH_RELATIVE: Tcl_SetStringObj(Tcl_GetObjResult(interp), "relative", -1); break; case TCL_PATH_VOLUME_RELATIVE: Tcl_SetStringObj(Tcl_GetObjResult(interp), "volumerelative", -1); break; } return TCL_OK; } case FCMD_READABLE: { if (objc != 3) { goto only3Args; } return CheckAccess(interp, objv[2], R_OK); } case FCMD_READLINK: { Tcl_Obj *contents; if (objc != 3) { goto only3Args; } if (Tcl_FSConvertToPathType(interp, objv[2]) != TCL_OK) { return TCL_ERROR; } contents = Tcl_FSLink(objv[2], NULL, 0); if (contents == NULL) { Tcl_AppendResult(interp, "could not readlink \"", Tcl_GetString(objv[2]), "\": ", Tcl_PosixError(interp), (char *) NULL); return TCL_ERROR; } Tcl_SetObjResult(interp, contents); Tcl_DecrRefCount(contents); return TCL_OK; } case FCMD_RENAME: { return TclFileRenameCmd(interp, objc, objv); } case FCMD_ROOTNAME: { int length; char *fileName, *extension; if (objc != 3) { goto only3Args; } fileName = Tcl_GetStringFromObj(objv[2], &length); extension = TclGetExtension(fileName); if (extension == NULL) { Tcl_SetObjResult(interp, objv[2]); } else { Tcl_SetStringObj(Tcl_GetObjResult(interp), fileName, (int) (length - strlen(extension))); } return TCL_OK; } case FCMD_SEPARATOR: { if ((objc < 2) || (objc > 3)) { Tcl_WrongNumArgs(interp, 2, objv, "?name?"); return TCL_ERROR; } if (objc == 2) { char *separator = NULL; /* lint */ switch (tclPlatform) { case TCL_PLATFORM_UNIX: separator = "/"; break; case TCL_PLATFORM_WINDOWS: separator = "\\"; break; } Tcl_SetObjResult(interp, Tcl_NewStringObj(separator,1)); } else { Tcl_Obj *separatorObj = Tcl_FSPathSeparator(objv[2]); if (separatorObj != NULL) { Tcl_SetObjResult(interp, separatorObj); } else { Tcl_SetObjResult(interp, Tcl_NewStringObj("Unrecognised path",-1)); return TCL_ERROR; } } return TCL_OK; } case FCMD_SIZE: { Tcl_StatBuf buf; if (objc != 3) { goto only3Args; } if (GetStatBuf(interp, objv[2], Tcl_FSStat, &buf) != TCL_OK) { return TCL_ERROR; } Tcl_SetWideIntObj(Tcl_GetObjResult(interp), (Tcl_WideInt) buf.st_size); return TCL_OK; } case FCMD_SPLIT: { if (objc != 3) { goto only3Args; } Tcl_SetObjResult(interp, Tcl_FSSplitPath(objv[2], NULL)); return TCL_OK; } case FCMD_STAT: { char *varName; Tcl_StatBuf buf; if (objc != 4) { Tcl_WrongNumArgs(interp, 1, objv, "stat name varName"); return TCL_ERROR; } if (GetStatBuf(interp, objv[2], Tcl_FSStat, &buf) != TCL_OK) { return TCL_ERROR; } varName = Tcl_GetString(objv[3]); return StoreStatData(interp, varName, &buf); } case FCMD_SYSTEM: { Tcl_Obj* fsInfo; if (objc != 3) { goto only3Args; } fsInfo = Tcl_FSFileSystemInfo(objv[2]); if (fsInfo != NULL) { Tcl_SetObjResult(interp, fsInfo); return TCL_OK; } else { Tcl_SetObjResult(interp, Tcl_NewStringObj("Unrecognised path",-1)); return TCL_ERROR; } } case FCMD_TAIL: { int splitElements; Tcl_Obj *splitPtr; if (objc != 3) { goto only3Args; } /* * The behaviour we want here is slightly different to * the standard Tcl_FSSplitPath in the handling of home * directories; Tcl_FSSplitPath preserves the "~" while * this code computes the actual full path name, if we * had just a single component. */ splitPtr = Tcl_FSSplitPath(objv[2], &splitElements); if ((splitElements == 1) && (Tcl_GetString(objv[2])[0] == '~')) { Tcl_DecrRefCount(splitPtr); splitPtr = Tcl_FSGetNormalizedPath(interp, objv[2]); if (splitPtr == NULL) { return TCL_ERROR; } splitPtr = Tcl_FSSplitPath(splitPtr, &splitElements); } /* * Return the last component, unless it is the only component, * and it is the root of an absolute path. */ if (splitElements > 0) { if ((splitElements > 1) || (Tcl_FSGetPathType(objv[2]) == TCL_PATH_RELATIVE)) { Tcl_Obj *tail = NULL; Tcl_ListObjIndex(NULL, splitPtr, splitElements-1, &tail); Tcl_SetObjResult(interp, tail); } } Tcl_DecrRefCount(splitPtr); return TCL_OK; } case FCMD_TYPE: { Tcl_StatBuf buf; if (objc != 3) { goto only3Args; } if (GetStatBuf(interp, objv[2], Tcl_FSLstat, &buf) != TCL_OK) { return TCL_ERROR; } Tcl_SetStringObj(Tcl_GetObjResult(interp), GetTypeFromMode((unsigned short) buf.st_mode), -1); return TCL_OK; } case FCMD_VOLUMES: { if (objc != 2) { Tcl_WrongNumArgs(interp, 2, objv, NULL); return TCL_ERROR; } Tcl_SetObjResult(interp, Tcl_FSListVolumes()); return TCL_OK; } case FCMD_WRITABLE: { if (objc != 3) { goto only3Args; } return CheckAccess(interp, objv[2], W_OK); } } only3Args: Tcl_WrongNumArgs(interp, 2, objv, "name"); return TCL_ERROR; } /* *--------------------------------------------------------------------------- * * CheckAccess -- * * Utility procedure used by Tcl_FileObjCmd() to query file * attributes available through the access() system call. * * Results: * Always returns TCL_OK. Sets interp's result to boolean true or * false depending on whether the file has the specified attribute. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int CheckAccess(interp, objPtr, mode) Tcl_Interp *interp; /* Interp for status return. Must not be * NULL. */ Tcl_Obj *objPtr; /* Name of file to check. */ int mode; /* Attribute to check; passed as argument to * access(). */ { int value; if (Tcl_FSConvertToPathType(interp, objPtr) != TCL_OK) { value = 0; } else { value = (Tcl_FSAccess(objPtr, mode) == 0); } Tcl_SetBooleanObj(Tcl_GetObjResult(interp), value); return TCL_OK; } /* *--------------------------------------------------------------------------- * * GetStatBuf -- * * Utility procedure used by Tcl_FileObjCmd() to query file * attributes available through the stat() or lstat() system call. * * Results: * The return value is TCL_OK if the specified file exists and can * be stat'ed, TCL_ERROR otherwise. If TCL_ERROR is returned, an * error message is left in interp's result. If TCL_OK is returned, * *statPtr is filled with information about the specified file. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int GetStatBuf(interp, objPtr, statProc, statPtr) Tcl_Interp *interp; /* Interp for error return. May be NULL. */ Tcl_Obj *objPtr; /* Path name to examine. */ Tcl_FSStatProc *statProc; /* Either stat() or lstat() depending on * desired behavior. */ Tcl_StatBuf *statPtr; /* Filled with info about file obtained by * calling (*statProc)(). */ { int status; if (Tcl_FSConvertToPathType(interp, objPtr) != TCL_OK) { return TCL_ERROR; } status = (*statProc)(objPtr, statPtr); if (status < 0) { if (interp != NULL) { Tcl_AppendResult(interp, "could not read \"", Tcl_GetString(objPtr), "\": ", Tcl_PosixError(interp), (char *) NULL); } return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * StoreStatData -- * * This is a utility procedure that breaks out the fields of a * "stat" structure and stores them in textual form into the * elements of an associative array. * * Results: * Returns a standard Tcl return value. If an error occurs then * a message is left in interp's result. * * Side effects: * Elements of the associative array given by "varName" are modified. * *---------------------------------------------------------------------- */ static int StoreStatData(interp, varName, statPtr) Tcl_Interp *interp; /* Interpreter for error reports. */ char *varName; /* Name of associative array variable * in which to store stat results. */ Tcl_StatBuf *statPtr; /* Pointer to buffer containing * stat data to store in varName. */ { Tcl_Obj *var = Tcl_NewStringObj(varName, -1); Tcl_Obj *field = Tcl_NewObj(); Tcl_Obj *value; register unsigned short mode; /* * Assume Tcl_ObjSetVar2() does not keep a copy of the field name! */ #define STORE_ARY(fieldName, object) \ Tcl_SetStringObj(field, (fieldName), -1); \ value = (object); \ if (Tcl_ObjSetVar2(interp,var,field,value,TCL_LEAVE_ERR_MSG) == NULL) { \ Tcl_DecrRefCount(var); \ Tcl_DecrRefCount(field); \ Tcl_DecrRefCount(value); \ return TCL_ERROR; \ } Tcl_IncrRefCount(var); Tcl_IncrRefCount(field); STORE_ARY("dev", Tcl_NewLongObj((long)statPtr->st_dev)); /* * Watch out porters; the inode is meant to be an *unsigned* value, * so the cast might fail when there isn't a real arithmentic 'long * long' type... */ STORE_ARY("ino", Tcl_NewWideIntObj((Tcl_WideInt)statPtr->st_ino)); STORE_ARY("nlink", Tcl_NewLongObj((long)statPtr->st_nlink)); STORE_ARY("uid", Tcl_NewLongObj((long)statPtr->st_uid)); STORE_ARY("gid", Tcl_NewLongObj((long)statPtr->st_gid)); STORE_ARY("size", Tcl_NewWideIntObj((Tcl_WideInt)statPtr->st_size)); #ifdef HAVE_ST_BLOCKS STORE_ARY("blocks",Tcl_NewWideIntObj((Tcl_WideInt)statPtr->st_blocks)); #endif STORE_ARY("atime", Tcl_NewLongObj((long)statPtr->st_atime)); STORE_ARY("mtime", Tcl_NewLongObj((long)statPtr->st_mtime)); STORE_ARY("ctime", Tcl_NewLongObj((long)statPtr->st_ctime)); mode = (unsigned short) statPtr->st_mode; STORE_ARY("mode", Tcl_NewIntObj(mode)); STORE_ARY("type", Tcl_NewStringObj(GetTypeFromMode(mode), -1)); #undef STORE_ARY Tcl_DecrRefCount(var); Tcl_DecrRefCount(field); return TCL_OK; } /* *---------------------------------------------------------------------- * * GetTypeFromMode -- * * Given a mode word, returns a string identifying the type of a * file. * * Results: * A static text string giving the file type from mode. * * Side effects: * None. * *---------------------------------------------------------------------- */ static char * GetTypeFromMode(mode) int mode; { if (S_ISREG(mode)) { return "file"; } else if (S_ISDIR(mode)) { return "directory"; } else if (S_ISCHR(mode)) { return "characterSpecial"; } else if (S_ISBLK(mode)) { return "blockSpecial"; } else if (S_ISFIFO(mode)) { return "fifo"; #ifdef S_ISLNK } else if (S_ISLNK(mode)) { return "link"; #endif #ifdef S_ISSOCK } else if (S_ISSOCK(mode)) { return "socket"; #endif } return "unknown"; } /* *---------------------------------------------------------------------- * * Tcl_ForObjCmd -- * * This procedure is invoked to process the "for" Tcl command. * See the user documentation for details on what it does. * * With the bytecode compiler, this procedure is only called when * a command name is computed at runtime, and is "for" or the name * to which "for" was renamed: e.g., * "set z for; $z {set i 0} {$i<100} {incr i} {puts $i}" * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_ForObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int result, value; #ifdef TCL_TIP280 Interp* iPtr = (Interp*) interp; #endif if (objc != 5) { Tcl_WrongNumArgs(interp, 1, objv, "start test next command"); return TCL_ERROR; } #ifndef TCL_TIP280 result = Tcl_EvalObjEx(interp, objv[1], 0); #else /* TIP #280. Make invoking context available to initial script */ result = TclEvalObjEx(interp, objv[1], 0, iPtr->cmdFramePtr,1); #endif if (result != TCL_OK) { if (result == TCL_ERROR) { Tcl_AddErrorInfo(interp, "\n (\"for\" initial command)"); } return result; } while (1) { /* * We need to reset the result before passing it off to * Tcl_ExprBooleanObj. Otherwise, any error message will be appended * to the result of the last evaluation. */ Tcl_ResetResult(interp); result = Tcl_ExprBooleanObj(interp, objv[2], &value); if (result != TCL_OK) { return result; } if (!value) { break; } #ifndef TCL_TIP280 result = Tcl_EvalObjEx(interp, objv[4], 0); #else /* TIP #280. Make invoking context available to loop body */ result = TclEvalObjEx(interp, objv[4], 0, iPtr->cmdFramePtr,4); #endif if ((result != TCL_OK) && (result != TCL_CONTINUE)) { if (result == TCL_ERROR) { char msg[32 + TCL_INTEGER_SPACE]; sprintf(msg, "\n (\"for\" body line %d)",interp->errorLine); Tcl_AddErrorInfo(interp, msg); } break; } #ifndef TCL_TIP280 result = Tcl_EvalObjEx(interp, objv[3], 0); #else /* TIP #280. Make invoking context available to next script */ result = TclEvalObjEx(interp, objv[3], 0, iPtr->cmdFramePtr,3); #endif if (result == TCL_BREAK) { break; } else if (result != TCL_OK) { if (result == TCL_ERROR) { Tcl_AddErrorInfo(interp, "\n (\"for\" loop-end command)"); } return result; } } if (result == TCL_BREAK) { result = TCL_OK; } if (result == TCL_OK) { Tcl_ResetResult(interp); } return result; } /* *---------------------------------------------------------------------- * * Tcl_ForeachObjCmd -- * * This object-based procedure is invoked to process the "foreach" Tcl * command. See the user documentation for details on what it does. * * Results: * A standard Tcl object result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_ForeachObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int result = TCL_OK; int i; /* i selects a value list */ int j, maxj; /* Number of loop iterations */ int v; /* v selects a loop variable */ int numLists; /* Count of value lists */ Tcl_Obj *bodyPtr; /* * We copy the argument object pointers into a local array to avoid * the problem that "objv" might become invalid. It is a pointer into * the evaluation stack and that stack might be grown and reallocated * if the loop body requires a large amount of stack space. */ #define NUM_ARGS 9 Tcl_Obj *(argObjStorage[NUM_ARGS]); Tcl_Obj **argObjv = argObjStorage; #define STATIC_LIST_SIZE 4 int indexArray[STATIC_LIST_SIZE]; int varcListArray[STATIC_LIST_SIZE]; Tcl_Obj **varvListArray[STATIC_LIST_SIZE]; int argcListArray[STATIC_LIST_SIZE]; Tcl_Obj **argvListArray[STATIC_LIST_SIZE]; int *index = indexArray; /* Array of value list indices */ int *varcList = varcListArray; /* # loop variables per list */ Tcl_Obj ***varvList = varvListArray; /* Array of var name lists */ int *argcList = argcListArray; /* Array of value list sizes */ Tcl_Obj ***argvList = argvListArray; /* Array of value lists */ #ifdef TCL_TIP280 Interp* iPtr = (Interp*) interp; #endif if (objc < 4 || (objc%2 != 0)) { Tcl_WrongNumArgs(interp, 1, objv, "varList list ?varList list ...? command"); return TCL_ERROR; } /* * Create the object argument array "argObjv". Make sure argObjv is * large enough to hold the objc arguments. */ if (objc > NUM_ARGS) { argObjv = (Tcl_Obj **) ckalloc(objc * sizeof(Tcl_Obj *)); } for (i = 0; i < objc; i++) { argObjv[i] = objv[i]; } /* * Manage numList parallel value lists. * argvList[i] is a value list counted by argcList[i] * varvList[i] is the list of variables associated with the value list * varcList[i] is the number of variables associated with the value list * index[i] is the current pointer into the value list argvList[i] */ numLists = (objc-2)/2; if (numLists > STATIC_LIST_SIZE) { index = (int *) ckalloc(numLists * sizeof(int)); varcList = (int *) ckalloc(numLists * sizeof(int)); varvList = (Tcl_Obj ***) ckalloc(numLists * sizeof(Tcl_Obj **)); argcList = (int *) ckalloc(numLists * sizeof(int)); argvList = (Tcl_Obj ***) ckalloc(numLists * sizeof(Tcl_Obj **)); } for (i = 0; i < numLists; i++) { index[i] = 0; varcList[i] = 0; varvList[i] = (Tcl_Obj **) NULL; argcList[i] = 0; argvList[i] = (Tcl_Obj **) NULL; } /* * Break up the value lists and variable lists into elements */ maxj = 0; for (i = 0; i < numLists; i++) { result = Tcl_ListObjGetElements(interp, argObjv[1+i*2], &varcList[i], &varvList[i]); if (result != TCL_OK) { goto done; } if (varcList[i] < 1) { Tcl_AppendToObj(Tcl_GetObjResult(interp), "foreach varlist is empty", -1); result = TCL_ERROR; goto done; } result = Tcl_ListObjGetElements(interp, argObjv[2+i*2], &argcList[i], &argvList[i]); if (result != TCL_OK) { goto done; } j = argcList[i] / varcList[i]; if ((argcList[i] % varcList[i]) != 0) { j++; } if (j > maxj) { maxj = j; } } /* * Iterate maxj times through the lists in parallel * If some value lists run out of values, set loop vars to "" */ bodyPtr = argObjv[objc-1]; for (j = 0; j < maxj; j++) { for (i = 0; i < numLists; i++) { /* * Refetch the list members; we assume that the sizes are * the same, but the array of elements might be different * if the internal rep of the objects has been lost and * recreated (it is too difficult to accurately tell when * this happens, which can lead to some wierd crashes, * like Bug #494348...) */ result = Tcl_ListObjGetElements(interp, argObjv[1+i*2], &varcList[i], &varvList[i]); if (result != TCL_OK) { panic("Tcl_ForeachObjCmd: could not reconvert variable list %d to a list object\n", i); } result = Tcl_ListObjGetElements(interp, argObjv[2+i*2], &argcList[i], &argvList[i]); if (result != TCL_OK) { panic("Tcl_ForeachObjCmd: could not reconvert value list %d to a list object\n", i); } for (v = 0; v < varcList[i]; v++) { int k = index[i]++; Tcl_Obj *valuePtr, *varValuePtr; if (k < argcList[i]) { valuePtr = argvList[i][k]; } else { valuePtr = Tcl_NewObj(); /* empty string */ } Tcl_IncrRefCount(valuePtr); varValuePtr = Tcl_ObjSetVar2(interp, varvList[i][v], NULL, valuePtr, 0); Tcl_DecrRefCount(valuePtr); if (varValuePtr == NULL) { Tcl_ResetResult(interp); Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "couldn't set loop variable: \"", Tcl_GetString(varvList[i][v]), "\"", (char *) NULL); result = TCL_ERROR; goto done; } } } #ifndef TCL_TIP280 result = Tcl_EvalObjEx(interp, bodyPtr, 0); #else /* TIP #280. Make invoking context available to loop body */ result = TclEvalObjEx(interp, bodyPtr, 0, iPtr->cmdFramePtr,objc-1); #endif if (result != TCL_OK) { if (result == TCL_CONTINUE) { result = TCL_OK; } else if (result == TCL_BREAK) { result = TCL_OK; break; } else if (result == TCL_ERROR) { char msg[32 + TCL_INTEGER_SPACE]; sprintf(msg, "\n (\"foreach\" body line %d)", interp->errorLine); Tcl_AddObjErrorInfo(interp, msg, -1); break; } else { break; } } } if (result == TCL_OK) { Tcl_ResetResult(interp); } done: if (numLists > STATIC_LIST_SIZE) { ckfree((char *) index); ckfree((char *) varcList); ckfree((char *) argcList); ckfree((char *) varvList); ckfree((char *) argvList); } if (argObjv != argObjStorage) { ckfree((char *) argObjv); } return result; #undef STATIC_LIST_SIZE #undef NUM_ARGS } /* *---------------------------------------------------------------------- * * Tcl_FormatObjCmd -- * * This procedure is invoked to process the "format" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_FormatObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { char *format; /* Used to read characters from the format * string. */ int formatLen; /* The length of the format string */ char *endPtr; /* Points to the last char in format array */ char newFormat[43]; /* A new format specifier is generated here. */ int width; /* Field width from field specifier, or 0 if * no width given. */ int precision; /* Field precision from field specifier, or 0 * if no precision given. */ int size; /* Number of bytes needed for result of * conversion, based on type of conversion * ("e", "s", etc.), width, and precision. */ long intValue; /* Used to hold value to pass to sprintf, if * it's a one-word integer or char value */ char *ptrValue = NULL; /* Used to hold value to pass to sprintf, if * it's a one-word value. */ double doubleValue; /* Used to hold value to pass to sprintf if * it's a double value. */ Tcl_WideInt wideValue; /* Used to hold value to pass to sprintf if * it's a 'long long' value. */ int whichValue; /* Indicates which of intValue, ptrValue, * or doubleValue has the value to pass to * sprintf, according to the following * definitions: */ # define INT_VALUE 0 # define CHAR_VALUE 1 # define PTR_VALUE 2 # define DOUBLE_VALUE 3 # define STRING_VALUE 4 # define WIDE_VALUE 5 # define MAX_FLOAT_SIZE 320 Tcl_Obj *resultPtr; /* Where result is stored finally. */ char staticBuf[MAX_FLOAT_SIZE + 1]; /* A static buffer to copy the format results * into */ char *dst = staticBuf; /* The buffer that sprintf writes into each * time the format processes a specifier */ int dstSize = MAX_FLOAT_SIZE; /* The size of the dst buffer */ int noPercent; /* Special case for speed: indicates there's * no field specifier, just a string to copy.*/ int objIndex; /* Index of argument to substitute next. */ int gotXpg = 0; /* Non-zero means that an XPG3 %n$-style * specifier has been seen. */ int gotSequential = 0; /* Non-zero means that a regular sequential * (non-XPG3) conversion specifier has been * seen. */ int useShort; /* Value to be printed is short (half word). */ char *end; /* Used to locate end of numerical fields. */ int stringLen = 0; /* Length of string in characters rather * than bytes. Used for %s substitution. */ int gotMinus; /* Non-zero indicates that a minus flag has * been seen in the current field. */ int gotPrecision; /* Non-zero indicates that a precision has * been set for the current field. */ int gotZero; /* Non-zero indicates that a zero flag has * been seen in the current field. */ int useWide; /* Value to be printed is Tcl_WideInt. */ /* * This procedure is a bit nasty. The goal is to use sprintf to * do most of the dirty work. There are several problems: * 1. this procedure can't trust its arguments. * 2. we must be able to provide a large enough result area to hold * whatever's generated. This is hard to estimate. * 3. there's no way to move the arguments from objv to the call * to sprintf in a reasonable way. This is particularly nasty * because some of the arguments may be two-word values (doubles * and wide-ints). * So, what happens here is to scan the format string one % group * at a time, making many individual calls to sprintf. */ if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "formatString ?arg arg ...?"); return TCL_ERROR; } format = Tcl_GetStringFromObj(objv[1], &formatLen); endPtr = format + formatLen; resultPtr = Tcl_NewObj(); objIndex = 2; while (format < endPtr) { register char *newPtr = newFormat; width = precision = noPercent = useShort = 0; gotZero = gotMinus = gotPrecision = 0; useWide = 0; whichValue = PTR_VALUE; /* * Get rid of any characters before the next field specifier. */ if (*format != '%') { ptrValue = format; while ((*format != '%') && (format < endPtr)) { format++; } size = format - ptrValue; noPercent = 1; goto doField; } if (format[1] == '%') { ptrValue = format; size = 1; noPercent = 1; format += 2; goto doField; } /* * Parse off a field specifier, compute how many characters * will be needed to store the result, and substitute for * "*" size specifiers. */ *newPtr = '%'; newPtr++; format++; if (isdigit(UCHAR(*format))) { /* INTL: Tcl source. */ int tmp; /* * Check for an XPG3-style %n$ specification. Note: there * must not be a mixture of XPG3 specs and non-XPG3 specs * in the same format string. */ tmp = strtoul(format, &end, 10); /* INTL: "C" locale. */ if (*end != '$') { goto notXpg; } format = end+1; gotXpg = 1; if (gotSequential) { goto mixedXPG; } objIndex = tmp+1; if ((objIndex < 2) || (objIndex >= objc)) { goto badIndex; } goto xpgCheckDone; } notXpg: gotSequential = 1; if (gotXpg) { goto mixedXPG; } xpgCheckDone: while ((*format == '-') || (*format == '#') || (*format == '0') || (*format == ' ') || (*format == '+')) { if (*format == '-') { gotMinus = 1; } if (*format == '0') { /* * This will be handled by sprintf for numbers, but we * need to do the char/string ones ourselves */ gotZero = 1; } *newPtr = *format; newPtr++; format++; } if (isdigit(UCHAR(*format))) { /* INTL: Tcl source. */ width = strtoul(format, &end, 10); /* INTL: Tcl source. */ format = end; } else if (*format == '*') { if (objIndex >= objc) { goto badIndex; } if (Tcl_GetIntFromObj(interp, /* INTL: Tcl source. */ objv[objIndex], &width) != TCL_OK) { goto fmtError; } if (width < 0) { width = -width; *newPtr = '-'; gotMinus = 1; newPtr++; } objIndex++; format++; } if (width > 100000) { /* * Don't allow arbitrarily large widths: could cause core * dump when we try to allocate a zillion bytes of memory * below. */ width = 100000; } else if (width < 0) { width = 0; } if (width != 0) { TclFormatInt(newPtr, width); /* INTL: printf format. */ while (*newPtr != 0) { newPtr++; } } if (*format == '.') { *newPtr = '.'; newPtr++; format++; gotPrecision = 1; } if (isdigit(UCHAR(*format))) { /* INTL: Tcl source. */ precision = strtoul(format, &end, 10); /* INTL: "C" locale. */ format = end; } else if (*format == '*') { if (objIndex >= objc) { goto badIndex; } if (Tcl_GetIntFromObj(interp, /* INTL: Tcl source. */ objv[objIndex], &precision) != TCL_OK) { goto fmtError; } objIndex++; format++; } if (gotPrecision) { TclFormatInt(newPtr, precision); /* INTL: printf format. */ while (*newPtr != 0) { newPtr++; } } if (*format == 'l') { useWide = 1; /* * Only add a 'll' modifier for integer values as it makes * some libc's go into spasm otherwise. [Bug #702622] */ switch (format[1]) { case 'i': case 'd': case 'o': case 'u': case 'x': case 'X': strcpy(newPtr, TCL_LL_MODIFIER); newPtr += TCL_LL_MODIFIER_SIZE; } format++; } else if (*format == 'h') { useShort = 1; *newPtr = 'h'; newPtr++; format++; } *newPtr = *format; newPtr++; *newPtr = 0; if (objIndex >= objc) { goto badIndex; } switch (*format) { case 'i': newPtr[-1] = 'd'; case 'd': case 'o': case 'u': case 'x': case 'X': if (useWide) { if (Tcl_GetWideIntFromObj(interp, /* INTL: Tcl source. */ objv[objIndex], &wideValue) != TCL_OK) { goto fmtError; } whichValue = WIDE_VALUE; size = 40 + precision; break; } if (Tcl_GetLongFromObj(interp, /* INTL: Tcl source. */ objv[objIndex], &intValue) != TCL_OK) { if (Tcl_GetWideIntFromObj(interp, /* INTL: Tcl source. */ objv[objIndex], &wideValue) != TCL_OK) { goto fmtError; } intValue = Tcl_WideAsLong(wideValue); } #if (LONG_MAX > INT_MAX) if (!useShort) { /* * Add the 'l' for long format type because we are on an * LP64 archtecture and we are really going to pass a long * argument to sprintf. * * Do not add this if we're going to pass in a short (i.e. * if we've got an 'h' modifier already in the string); some * libc implementations of sprintf() do not like it at all. * [Bug 1154163] */ newPtr++; *newPtr = 0; newPtr[-1] = newPtr[-2]; newPtr[-2] = 'l'; } #endif /* LONG_MAX > INT_MAX */ whichValue = INT_VALUE; size = 40 + precision; break; case 's': /* * Compute the length of the string in characters and add * any additional space required by the field width. All * of the extra characters will be spaces, so one byte per * character is adequate. */ whichValue = STRING_VALUE; ptrValue = Tcl_GetStringFromObj(objv[objIndex], &size); stringLen = Tcl_NumUtfChars(ptrValue, size); if (gotPrecision && (precision < stringLen)) { stringLen = precision; } size = Tcl_UtfAtIndex(ptrValue, stringLen) - ptrValue; if (width > stringLen) { size += (width - stringLen); } break; case 'c': if (Tcl_GetLongFromObj(interp, /* INTL: Tcl source. */ objv[objIndex], &intValue) != TCL_OK) { goto fmtError; } whichValue = CHAR_VALUE; size = width + TCL_UTF_MAX; break; case 'e': case 'E': case 'f': case 'g': case 'G': if (Tcl_GetDoubleFromObj(interp, /* INTL: Tcl source. */ objv[objIndex], &doubleValue) != TCL_OK) { goto fmtError; } whichValue = DOUBLE_VALUE; size = MAX_FLOAT_SIZE; if (precision > 10) { size += precision; } break; case 0: Tcl_SetResult(interp, "format string ended in middle of field specifier", TCL_STATIC); goto fmtError; default: { char buf[40]; sprintf(buf, "bad field specifier \"%c\"", *format); Tcl_SetResult(interp, buf, TCL_VOLATILE); goto fmtError; } } objIndex++; format++; /* * Make sure that there's enough space to hold the formatted * result, then format it. */ doField: if (width > size) { size = width; } if (noPercent) { Tcl_AppendToObj(resultPtr, ptrValue, size); } else { if (size > dstSize) { if (dst != staticBuf) { ckfree(dst); } dst = (char *) ckalloc((unsigned) (size + 1)); dstSize = size; } switch (whichValue) { case DOUBLE_VALUE: sprintf(dst, newFormat, doubleValue); /* INTL: user locale. */ break; case WIDE_VALUE: sprintf(dst, newFormat, wideValue); break; case INT_VALUE: if (useShort) { sprintf(dst, newFormat, (short) intValue); } else { sprintf(dst, newFormat, intValue); } break; case CHAR_VALUE: { char *ptr; char padChar = (gotZero ? '0' : ' '); ptr = dst; if (!gotMinus) { for ( ; --width > 0; ptr++) { *ptr = padChar; } } ptr += Tcl_UniCharToUtf(intValue, ptr); for ( ; --width > 0; ptr++) { *ptr = padChar; } *ptr = '\0'; break; } case STRING_VALUE: { char *ptr; char padChar = (gotZero ? '0' : ' '); int pad; ptr = dst; if (width > stringLen) { pad = width - stringLen; } else { pad = 0; } if (!gotMinus) { while (pad > 0) { *ptr++ = padChar; pad--; } } size = Tcl_UtfAtIndex(ptrValue, stringLen) - ptrValue; if (size) { memcpy(ptr, ptrValue, (size_t) size); ptr += size; } while (pad > 0) { *ptr++ = padChar; pad--; } *ptr = '\0'; break; } default: sprintf(dst, newFormat, ptrValue); break; } Tcl_AppendToObj(resultPtr, dst, -1); } } Tcl_SetObjResult(interp, resultPtr); if (dst != staticBuf) { ckfree(dst); } return TCL_OK; mixedXPG: Tcl_SetResult(interp, "cannot mix \"%\" and \"%n$\" conversion specifiers", TCL_STATIC); goto fmtError; badIndex: if (gotXpg) { Tcl_SetResult(interp, "\"%n$\" argument index out of range", TCL_STATIC); } else { Tcl_SetResult(interp, "not enough arguments for all format specifiers", TCL_STATIC); } fmtError: if (dst != staticBuf) { ckfree(dst); } Tcl_DecrRefCount(resultPtr); return TCL_ERROR; } /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ tcl8.4.20/generic/tclThreadJoin.c0000644003604700454610000002307012052456744015232 0ustar dgp771div/* * tclThreadJoin.c -- * * This file implements a platform independent emulation layer for * the handling of joinable threads. The Mac and Windows platforms * use this code to provide the functionality of joining threads. * This code is currently not necessary on Unix. * * Copyright (c) 2000 by Scriptics Corporation * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #if defined(WIN32) /* The information about each joinable thread is remembered in a * structure as defined below. */ typedef struct JoinableThread { Tcl_ThreadId id; /* The id of the joinable thread */ int result; /* A place for the result after the * demise of the thread */ int done; /* Boolean flag. Initialized to 0 * and set to 1 after the exit of * the thread. This allows a thread * requesting a join to detect when * waiting is not necessary. */ int waitedUpon; /* Boolean flag. Initialized to 0 * and set to 1 by the thread waiting * for this one via Tcl_JoinThread. * Used to lock any other thread * trying to wait on this one. */ Tcl_Mutex threadMutex; /* The mutex used to serialize access * to this structure. */ Tcl_Condition cond; /* This is the condition a thread has * to wait upon to get notified of the * end of the described thread. It is * signaled indirectly by * Tcl_ExitThread. */ struct JoinableThread* nextThreadPtr; /* Reference to the next thread in the * list of joinable threads */ } JoinableThread; /* The following variable is used to maintain the global list of all * joinable threads. Usage by a thread is allowed only if the * thread acquired the 'joinMutex'. */ TCL_DECLARE_MUTEX(joinMutex) static JoinableThread* firstThreadPtr; /* *---------------------------------------------------------------------- * * TclJoinThread -- * * This procedure waits for the exit of the thread with the specified * id and returns its result. * * Results: * A standard tcl result signaling the overall success/failure of the * operation and an integer result delivered by the thread which was * waited upon. * * Side effects: * Deallocates the memory allocated by TclRememberJoinableThread. * Removes the data associated to the thread waited upon from the * list of joinable threads. * *---------------------------------------------------------------------- */ int TclJoinThread(id, result) Tcl_ThreadId id; /* The id of the thread to wait upon. */ int* result; /* Reference to a location for the result * of the thread we are waiting upon. */ { /* Steps done here: * i. Acquire the joinMutex and search for the thread. * ii. Error out if it could not be found. * iii. If found, switch from exclusive access to the list to exclusive * access to the thread structure. * iv. Error out if some other is already waiting. * v. Skip the waiting part of the thread is already done. * vi. Wait for the thread to exit, mark it as waited upon too. * vii. Get the result form the structure, * viii. switch to exclusive access of the list, * ix. remove the structure from the list, * x. then switch back to exclusive access to the structure * xi. and delete it. */ JoinableThread* threadPtr; Tcl_MutexLock (&joinMutex); for (threadPtr = firstThreadPtr; (threadPtr != (JoinableThread*) NULL) && (threadPtr->id != id); threadPtr = threadPtr->nextThreadPtr) /* empty body */ ; if (threadPtr == (JoinableThread*) NULL) { /* Thread not found. Either not joinable, or already waited * upon and exited. Whatever, an error is in order. */ Tcl_MutexUnlock (&joinMutex); return TCL_ERROR; } /* [1] If we don't lock the structure before giving up exclusive access * to the list some other thread just completing its wait on the same * thread can delete the structure from under us, leaving us with a * dangling pointer. */ Tcl_MutexLock (&threadPtr->threadMutex); Tcl_MutexUnlock (&joinMutex); /* [2] Now that we have the structure mutex any other thread that just * tries to delete structure will wait at location [3] until we are * done with the structure. And in that case we are done with it * rather quickly as 'waitedUpon' will be set and we will have to * error out. */ if (threadPtr->waitedUpon) { Tcl_MutexUnlock (&threadPtr->threadMutex); return TCL_ERROR; } /* We are waiting now, let other threads recognize this */ threadPtr->waitedUpon = 1; while (!threadPtr->done) { Tcl_ConditionWait (&threadPtr->cond, &threadPtr->threadMutex, NULL); } /* We have to release the structure before trying to access the list * again or we can run into deadlock with a thread at [1] (see above) * because of us holding the structure and the other holding the list. * There is no problem with dangling pointers here as 'waitedUpon == 1' * is still valid and any other thread will error out and not come to * this place. IOW, the fact that we are here also means that no other * thread came here before us and is able to delete the structure. */ Tcl_MutexUnlock (&threadPtr->threadMutex); Tcl_MutexLock (&joinMutex); /* We have to search the list again as its structure may (may, almost * certainly) have changed while we were waiting. Especially now is the * time to compute the predecessor in the list. Any earlier result can * be dangling by now. */ if (firstThreadPtr == threadPtr) { firstThreadPtr = threadPtr->nextThreadPtr; } else { JoinableThread* prevThreadPtr; for (prevThreadPtr = firstThreadPtr; prevThreadPtr->nextThreadPtr != threadPtr; prevThreadPtr = prevThreadPtr->nextThreadPtr) /* empty body */ ; prevThreadPtr->nextThreadPtr = threadPtr->nextThreadPtr; } Tcl_MutexUnlock (&joinMutex); /* [3] Now that the structure is not part of the list anymore no other * thread can acquire its mutex from now on. But it is possible that * another thread is still holding the mutex though, see location [2]. * So we have to acquire the mutex one more time to wait for that thread * to finish. We can (and have to) release the mutex immediately. */ Tcl_MutexLock (&threadPtr->threadMutex); Tcl_MutexUnlock (&threadPtr->threadMutex); /* Copy the result to us, finalize the synchronisation objects, then * free the structure and return. */ *result = threadPtr->result; Tcl_ConditionFinalize (&threadPtr->cond); Tcl_MutexFinalize (&threadPtr->threadMutex); ckfree ((VOID*) threadPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * TclRememberJoinableThread -- * * This procedure remebers a thread as joinable. Only a call to * TclJoinThread will remove the structre created (and initialized) * here. IOW, not waiting upon a joinable thread will cause memory * leaks. * * Results: * None. * * Side effects: * Allocates memory, adds it to the global list of all joinable * threads. * *---------------------------------------------------------------------- */ VOID TclRememberJoinableThread(id) Tcl_ThreadId id; /* The thread to remember as joinable */ { JoinableThread* threadPtr; threadPtr = (JoinableThread*) ckalloc (sizeof (JoinableThread)); threadPtr->id = id; threadPtr->done = 0; threadPtr->waitedUpon = 0; threadPtr->threadMutex = (Tcl_Mutex) NULL; threadPtr->cond = (Tcl_Condition) NULL; Tcl_MutexLock (&joinMutex); threadPtr->nextThreadPtr = firstThreadPtr; firstThreadPtr = threadPtr; Tcl_MutexUnlock (&joinMutex); } /* *---------------------------------------------------------------------- * * TclSignalExitThread -- * * This procedure signals that the specified thread is done with * its work. If the thread is joinable this signal is propagated * to the thread waiting upon it. * * Results: * None. * * Side effects: * Modifies the associated structure to hold the result. * *---------------------------------------------------------------------- */ VOID TclSignalExitThread(id,result) Tcl_ThreadId id; /* Id of the thread signaling its exit */ int result; /* The result from the thread */ { JoinableThread* threadPtr; Tcl_MutexLock (&joinMutex); for (threadPtr = firstThreadPtr; (threadPtr != (JoinableThread*) NULL) && (threadPtr->id != id); threadPtr = threadPtr->nextThreadPtr) /* empty body */ ; if (threadPtr == (JoinableThread*) NULL) { /* Thread not found. Not joinable. No problem, nothing to do. */ Tcl_MutexUnlock (&joinMutex); return; } /* Switch over the exclusive access from the list to the structure, * then store the result, set the flag and notify the waiting thread, * provided that it exists. The order of lock/unlock ensures that a * thread entering 'TclJoinThread' will not interfere with us. */ Tcl_MutexLock (&threadPtr->threadMutex); Tcl_MutexUnlock (&joinMutex); threadPtr->done = 1; threadPtr->result = result; if (threadPtr->waitedUpon) { Tcl_ConditionNotify (&threadPtr->cond); } Tcl_MutexUnlock (&threadPtr->threadMutex); } #endif /* WIN32 */ tcl8.4.20/generic/tclEncoding.c0000644003604700454610000026773212052456743014747 0ustar dgp771div/* * tclEncoding.c -- * * Contains the implementation of the encoding conversion package. * * Copyright (c) 1996-1998 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" typedef size_t (LengthProc)_ANSI_ARGS_((CONST char *src)); /* * The following data structure represents an encoding, which describes how * to convert between various character sets and UTF-8. */ typedef struct Encoding { char *name; /* Name of encoding. Malloced because (1) * hash table entry that owns this encoding * may be freed prior to this encoding being * freed, (2) string passed in the * Tcl_EncodingType structure may not be * persistent. */ Tcl_EncodingConvertProc *toUtfProc; /* Procedure to convert from external * encoding into UTF-8. */ Tcl_EncodingConvertProc *fromUtfProc; /* Procedure to convert from UTF-8 into * external encoding. */ Tcl_EncodingFreeProc *freeProc; /* If non-NULL, procedure to call when this * encoding is deleted. */ int nullSize; /* Number of 0x00 bytes that signify * end-of-string in this encoding. This * number is used to determine the source * string length when the srcLen argument is * negative. This number can be 1 or 2. */ ClientData clientData; /* Arbitrary value associated with encoding * type. Passed to conversion procedures. */ LengthProc *lengthProc; /* Function to compute length of * null-terminated strings in this encoding. * If nullSize is 1, this is strlen; if * nullSize is 2, this is a function that * returns the number of bytes in a 0x0000 * terminated string. */ int refCount; /* Number of uses of this structure. */ Tcl_HashEntry *hPtr; /* Hash table entry that owns this encoding. */ } Encoding; /* * The following structure is the clientData for a dynamically-loaded, * table-driven encoding created by LoadTableEncoding(). It maps between * Unicode and a single-byte, double-byte, or multibyte (1 or 2 bytes only) * encoding. */ typedef struct TableEncodingData { int fallback; /* Character (in this encoding) to * substitute when this encoding cannot * represent a UTF-8 character. */ char prefixBytes[256]; /* If a byte in the input stream is a lead * byte for a 2-byte sequence, the * corresponding entry in this array is 1, * otherwise it is 0. */ unsigned short **toUnicode; /* Two dimensional sparse matrix to map * characters from the encoding to Unicode. * Each element of the toUnicode array points * to an array of 256 shorts. If there is no * corresponding character in Unicode, the * value in the matrix is 0x0000. malloc'd. */ unsigned short **fromUnicode; /* Two dimensional sparse matrix to map * characters from Unicode to the encoding. * Each element of the fromUnicode array * points to an array of 256 shorts. If there * is no corresponding character the encoding, * the value in the matrix is 0x0000. * malloc'd. */ } TableEncodingData; /* * The following structures is the clientData for a dynamically-loaded, * escape-driven encoding that is itself comprised of other simpler * encodings. An example is "iso-2022-jp", which uses escape sequences to * switch between ascii, jis0208, jis0212, gb2312, and ksc5601. Note that * "escape-driven" does not necessarily mean that the ESCAPE character is * the character used for switching character sets. */ typedef struct EscapeSubTable { unsigned int sequenceLen; /* Length of following string. */ char sequence[16]; /* Escape code that marks this encoding. */ char name[32]; /* Name for encoding. */ Encoding *encodingPtr; /* Encoding loaded using above name, or NULL * if this sub-encoding has not been needed * yet. */ } EscapeSubTable; typedef struct EscapeEncodingData { int fallback; /* Character (in this encoding) to * substitute when this encoding cannot * represent a UTF-8 character. */ unsigned int initLen; /* Length of following string. */ char init[16]; /* String to emit or expect before first char * in conversion. */ unsigned int finalLen; /* Length of following string. */ char final[16]; /* String to emit or expect after last char * in conversion. */ char prefixBytes[256]; /* If a byte in the input stream is the * first character of one of the escape * sequences in the following array, the * corresponding entry in this array is 1, * otherwise it is 0. */ int numSubTables; /* Length of following array. */ EscapeSubTable subTables[1];/* Information about each EscapeSubTable * used by this encoding type. The actual * size will be as large as necessary to * hold all EscapeSubTables. */ } EscapeEncodingData; /* * Constants used when loading an encoding file to identify the type of the * file. */ #define ENCODING_SINGLEBYTE 0 #define ENCODING_DOUBLEBYTE 1 #define ENCODING_MULTIBYTE 2 #define ENCODING_ESCAPE 3 /* * Initialize the default encoding directory. If this variable contains * a non NULL value, it will be the first path used to locate the * system encoding files. */ char *tclDefaultEncodingDir = NULL; static int encodingsInitialized = 0; /* * Hash table that keeps track of all loaded Encodings. Keys are * the string names that represent the encoding, values are (Encoding *). */ static Tcl_HashTable encodingTable; TCL_DECLARE_MUTEX(encodingMutex) /* * The following are used to hold the default and current system encodings. * If NULL is passed to one of the conversion routines, the current setting * of the system encoding will be used to perform the conversion. */ static Tcl_Encoding defaultEncoding; static Tcl_Encoding systemEncoding; /* * The following variable is used in the sparse matrix code for a * TableEncoding to represent a page in the table that has no entries. */ static unsigned short emptyPage[256]; /* * Procedures used only in this module. */ static int BinaryProc _ANSI_ARGS_((ClientData clientData, CONST char *src, int srcLen, int flags, Tcl_EncodingState *statePtr, char *dst, int dstLen, int *srcReadPtr, int *dstWrotePtr, int *dstCharsPtr)); static void DupEncodingIntRep _ANSI_ARGS_((Tcl_Obj *srcPtr, Tcl_Obj *dupPtr)); static void EscapeFreeProc _ANSI_ARGS_((ClientData clientData)); static int EscapeFromUtfProc _ANSI_ARGS_((ClientData clientData, CONST char *src, int srcLen, int flags, Tcl_EncodingState *statePtr, char *dst, int dstLen, int *srcReadPtr, int *dstWrotePtr, int *dstCharsPtr)); static int EscapeToUtfProc _ANSI_ARGS_((ClientData clientData, CONST char *src, int srcLen, int flags, Tcl_EncodingState *statePtr, char *dst, int dstLen, int *srcReadPtr, int *dstWrotePtr, int *dstCharsPtr)); static void FreeEncoding _ANSI_ARGS_((Tcl_Encoding encoding)); static void FreeEncodingIntRep _ANSI_ARGS_((Tcl_Obj *objPtr)); static Encoding * GetTableEncoding _ANSI_ARGS_(( EscapeEncodingData *dataPtr, int state)); static Tcl_Encoding LoadEncodingFile _ANSI_ARGS_((Tcl_Interp *interp, CONST char *name)); static Tcl_Encoding LoadTableEncoding _ANSI_ARGS_((Tcl_Interp *interp, CONST char *name, int type, Tcl_Channel chan)); static Tcl_Encoding LoadEscapeEncoding _ANSI_ARGS_((CONST char *name, Tcl_Channel chan)); static Tcl_Channel OpenEncodingFile _ANSI_ARGS_((CONST char *dir, CONST char *name)); static void TableFreeProc _ANSI_ARGS_((ClientData clientData)); static int TableFromUtfProc _ANSI_ARGS_((ClientData clientData, CONST char *src, int srcLen, int flags, Tcl_EncodingState *statePtr, char *dst, int dstLen, int *srcReadPtr, int *dstWrotePtr, int *dstCharsPtr)); static int TableToUtfProc _ANSI_ARGS_((ClientData clientData, CONST char *src, int srcLen, int flags, Tcl_EncodingState *statePtr, char *dst, int dstLen, int *srcReadPtr, int *dstWrotePtr, int *dstCharsPtr)); static size_t unilen _ANSI_ARGS_((CONST char *src)); static int UnicodeToUtfProc _ANSI_ARGS_((ClientData clientData, CONST char *src, int srcLen, int flags, Tcl_EncodingState *statePtr, char *dst, int dstLen, int *srcReadPtr, int *dstWrotePtr, int *dstCharsPtr)); static int UtfToUnicodeProc _ANSI_ARGS_((ClientData clientData, CONST char *src, int srcLen, int flags, Tcl_EncodingState *statePtr, char *dst, int dstLen, int *srcReadPtr, int *dstWrotePtr, int *dstCharsPtr)); static int UtfToUtfProc _ANSI_ARGS_((ClientData clientData, CONST char *src, int srcLen, int flags, Tcl_EncodingState *statePtr, char *dst, int dstLen, int *srcReadPtr, int *dstWrotePtr, int *dstCharsPtr, int pureNullMode)); static int UtfIntToUtfExtProc _ANSI_ARGS_((ClientData clientData, CONST char *src, int srcLen, int flags, Tcl_EncodingState *statePtr, char *dst, int dstLen, int *srcReadPtr, int *dstWrotePtr, int *dstCharsPtr)); static int UtfExtToUtfIntProc _ANSI_ARGS_((ClientData clientData, CONST char *src, int srcLen, int flags, Tcl_EncodingState *statePtr, char *dst, int dstLen, int *srcReadPtr, int *dstWrotePtr, int *dstCharsPtr)); static int TclFindEncodings _ANSI_ARGS_((CONST char *argv0)); /* * A Tcl_ObjType for holding a cached Tcl_Encoding as the intrep. * This should help the lifetime of encodings be more useful. * See concerns raised in [Bug 1077262]. */ static Tcl_ObjType EncodingType = { "encoding", FreeEncodingIntRep, DupEncodingIntRep, NULL, NULL }; /* *---------------------------------------------------------------------- * * TclGetEncodingFromObj -- * * Writes to (*encodingPtr) the Tcl_Encoding value of (*objPtr), * if possible, and returns TCL_OK. If no such encoding exists, * TCL_ERROR is returned, and if interp is non-NULL, an error message * is written there. * * Results: * Standard Tcl return code. * * Side effects: * Caches the Tcl_Encoding value as the internal rep of (*objPtr). * *---------------------------------------------------------------------- */ int TclGetEncodingFromObj(interp, objPtr, encodingPtr) Tcl_Interp *interp; Tcl_Obj *objPtr; Tcl_Encoding *encodingPtr; { CONST char *name = Tcl_GetString(objPtr); if (objPtr->typePtr != &EncodingType) { Tcl_Encoding encoding = Tcl_GetEncoding(interp, name); if (encoding == NULL) { return TCL_ERROR; } if (objPtr->typePtr && objPtr->typePtr->freeIntRepProc) { objPtr->typePtr->freeIntRepProc(objPtr); } objPtr->internalRep.otherValuePtr = (VOID *) encoding; objPtr->typePtr = &EncodingType; } *encodingPtr = Tcl_GetEncoding(NULL, name); return TCL_OK; } /* *---------------------------------------------------------------------- * * FreeEncodingIntRep -- * * The Tcl_FreeInternalRepProc for the "encoding" Tcl_ObjType. * *---------------------------------------------------------------------- */ static void FreeEncodingIntRep(objPtr) Tcl_Obj *objPtr; { Tcl_FreeEncoding((Tcl_Encoding) objPtr->internalRep.otherValuePtr); } /* *---------------------------------------------------------------------- * * DupEncodingIntRep -- * * The Tcl_DupInternalRepProc for the "encoding" Tcl_ObjType. * *---------------------------------------------------------------------- */ static void DupEncodingIntRep(srcPtr, dupPtr) Tcl_Obj *srcPtr; Tcl_Obj *dupPtr; { dupPtr->internalRep.otherValuePtr = (VOID *) Tcl_GetEncoding(NULL, srcPtr->bytes); } /* *--------------------------------------------------------------------------- * * TclInitEncodingSubsystem -- * * Initialize all resources used by this subsystem on a per-process * basis. * * Results: * None. * * Side effects: * Depends on the memory, object, and IO subsystems. * *--------------------------------------------------------------------------- */ void TclInitEncodingSubsystem() { Tcl_EncodingType type; Tcl_MutexLock(&encodingMutex); Tcl_InitHashTable(&encodingTable, TCL_STRING_KEYS); Tcl_MutexUnlock(&encodingMutex); /* * Create a few initial encodings. Note that the UTF-8 to UTF-8 * translation is not a no-op, because it will turn a stream of * improperly formed UTF-8 into a properly formed stream. */ type.encodingName = "identity"; type.toUtfProc = BinaryProc; type.fromUtfProc = BinaryProc; type.freeProc = NULL; type.nullSize = 1; type.clientData = NULL; defaultEncoding = Tcl_CreateEncoding(&type); systemEncoding = Tcl_GetEncoding(NULL, type.encodingName); type.encodingName = "utf-8"; type.toUtfProc = UtfExtToUtfIntProc; type.fromUtfProc = UtfIntToUtfExtProc; type.freeProc = NULL; type.nullSize = 1; type.clientData = NULL; Tcl_CreateEncoding(&type); type.encodingName = "unicode"; type.toUtfProc = UnicodeToUtfProc; type.fromUtfProc = UtfToUnicodeProc; type.freeProc = NULL; type.nullSize = 2; type.clientData = NULL; Tcl_CreateEncoding(&type); } /* *---------------------------------------------------------------------- * * TclFinalizeEncodingSubsystem -- * * Release the state associated with the encoding subsystem. * * Results: * None. * * Side effects: * Frees all of the encodings. * *---------------------------------------------------------------------- */ void TclFinalizeEncodingSubsystem() { Tcl_HashSearch search; Tcl_HashEntry *hPtr; Tcl_MutexLock(&encodingMutex); encodingsInitialized = 0; FreeEncoding(systemEncoding); hPtr = Tcl_FirstHashEntry(&encodingTable, &search); while (hPtr != NULL) { /* * Call FreeEncoding instead of doing it directly to handle refcounts * like escape encodings use. [Bug #524674] * Make sure to call Tcl_FirstHashEntry repeatedly so that all * encodings are eventually cleaned up. */ FreeEncoding((Tcl_Encoding) Tcl_GetHashValue(hPtr)); hPtr = Tcl_FirstHashEntry(&encodingTable, &search); } Tcl_DeleteHashTable(&encodingTable); Tcl_MutexUnlock(&encodingMutex); } /* *------------------------------------------------------------------------- * * Tcl_GetDefaultEncodingDir -- * * * Results: * * Side effects: * *------------------------------------------------------------------------- */ CONST char * Tcl_GetDefaultEncodingDir() { return tclDefaultEncodingDir; } /* *------------------------------------------------------------------------- * * Tcl_SetDefaultEncodingDir -- * * * Results: * * Side effects: * *------------------------------------------------------------------------- */ void Tcl_SetDefaultEncodingDir(path) CONST char *path; { tclDefaultEncodingDir = (char *)ckalloc((unsigned) strlen(path) + 1); strcpy(tclDefaultEncodingDir, path); } /* *------------------------------------------------------------------------- * * Tcl_GetEncoding -- * * Given the name of a encoding, find the corresponding Tcl_Encoding * token. If the encoding did not already exist, Tcl attempts to * dynamically load an encoding by that name. * * Results: * Returns a token that represents the encoding. If the name didn't * refer to any known or loadable encoding, NULL is returned. If * NULL was returned, an error message is left in interp's result * object, unless interp was NULL. * * Side effects: * The new encoding type is entered into a table visible to all * interpreters, keyed off the encoding's name. For each call to * this procedure, there should eventually be a call to * Tcl_FreeEncoding, so that the database can be cleaned up when * encodings aren't needed anymore. * *------------------------------------------------------------------------- */ Tcl_Encoding Tcl_GetEncoding(interp, name) Tcl_Interp *interp; /* Interp for error reporting, if not NULL. */ CONST char *name; /* The name of the desired encoding. */ { Tcl_HashEntry *hPtr; Encoding *encodingPtr; Tcl_MutexLock(&encodingMutex); if (name == NULL) { encodingPtr = (Encoding *) systemEncoding; encodingPtr->refCount++; Tcl_MutexUnlock(&encodingMutex); return systemEncoding; } hPtr = Tcl_FindHashEntry(&encodingTable, name); if (hPtr != NULL) { encodingPtr = (Encoding *) Tcl_GetHashValue(hPtr); encodingPtr->refCount++; Tcl_MutexUnlock(&encodingMutex); return (Tcl_Encoding) encodingPtr; } Tcl_MutexUnlock(&encodingMutex); return LoadEncodingFile(interp, name); } /* *--------------------------------------------------------------------------- * * Tcl_FreeEncoding -- * * This procedure is called to release an encoding allocated by * Tcl_CreateEncoding() or Tcl_GetEncoding(). * * Results: * None. * * Side effects: * The reference count associated with the encoding is decremented * and the encoding may be deleted if nothing is using it anymore. * *--------------------------------------------------------------------------- */ void Tcl_FreeEncoding(encoding) Tcl_Encoding encoding; { Tcl_MutexLock(&encodingMutex); FreeEncoding(encoding); Tcl_MutexUnlock(&encodingMutex); } /* *---------------------------------------------------------------------- * * FreeEncoding -- * * This procedure is called to release an encoding by procedures * that already have the encodingMutex. * * Results: * None. * * Side effects: * The reference count associated with the encoding is decremented * and the encoding may be deleted if nothing is using it anymore. * *---------------------------------------------------------------------- */ static void FreeEncoding(encoding) Tcl_Encoding encoding; { Encoding *encodingPtr; encodingPtr = (Encoding *) encoding; if (encodingPtr == NULL) { return; } if (encodingPtr->refCount<=0) { Tcl_Panic("FreeEncoding: refcount problem !!!"); } encodingPtr->refCount--; if (encodingPtr->refCount == 0) { if (encodingPtr->freeProc != NULL) { (*encodingPtr->freeProc)(encodingPtr->clientData); } if (encodingPtr->hPtr != NULL) { Tcl_DeleteHashEntry(encodingPtr->hPtr); } ckfree((char *) encodingPtr->name); ckfree((char *) encodingPtr); } } /* *------------------------------------------------------------------------- * * Tcl_GetEncodingName -- * * Given an encoding, return the name that was used to constuct * the encoding. * * Results: * The name of the encoding. * * Side effects: * None. * *--------------------------------------------------------------------------- */ CONST char * Tcl_GetEncodingName(encoding) Tcl_Encoding encoding; /* The encoding whose name to fetch. */ { Encoding *encodingPtr; if (encoding == NULL) { encoding = systemEncoding; } encodingPtr = (Encoding *) encoding; return encodingPtr->name; } /* *------------------------------------------------------------------------- * * Tcl_GetEncodingNames -- * * Get the list of all known encodings, including the ones stored * as files on disk in the encoding path. * * Results: * Modifies interp's result object to hold a list of all the available * encodings. * * Side effects: * None. * *------------------------------------------------------------------------- */ void Tcl_GetEncodingNames(interp) Tcl_Interp *interp; /* Interp to hold result. */ { Tcl_HashSearch search; Tcl_HashEntry *hPtr; Tcl_Obj *pathPtr, *resultPtr; int dummy; Tcl_HashTable table; Tcl_MutexLock(&encodingMutex); Tcl_InitHashTable(&table, TCL_STRING_KEYS); hPtr = Tcl_FirstHashEntry(&encodingTable, &search); while (hPtr != NULL) { Encoding *encodingPtr; encodingPtr = (Encoding *) Tcl_GetHashValue(hPtr); Tcl_CreateHashEntry(&table, encodingPtr->name, &dummy); hPtr = Tcl_NextHashEntry(&search); } Tcl_MutexUnlock(&encodingMutex); pathPtr = TclGetLibraryPath(); if (pathPtr != NULL) { int i, objc; Tcl_Obj **objv; char globArgString[10]; Tcl_Obj* encodingObj = Tcl_NewStringObj("encoding",-1); Tcl_IncrRefCount(encodingObj); objc = 0; Tcl_ListObjGetElements(NULL, pathPtr, &objc, &objv); for (i = 0; i < objc; i++) { Tcl_Obj *searchIn; /* * Construct the path from the element of pathPtr, * joined with 'encoding'. */ searchIn = Tcl_FSJoinToPath(objv[i],1,&encodingObj); Tcl_IncrRefCount(searchIn); Tcl_ResetResult(interp); /* * TclGlob() changes the contents of globArgString, which causes * a segfault if we pass in a pointer to non-writeable memory. * TclGlob() puts its results directly into interp. */ strcpy(globArgString, "*.enc"); /* * The GLOBMODE_TAILS flag returns just the tail of each file * which is the encoding name with a .enc extension */ if ((TclGlob(interp, globArgString, searchIn, TCL_GLOBMODE_TAILS, NULL) == TCL_OK)) { int objc2 = 0; Tcl_Obj **objv2; int j; Tcl_ListObjGetElements(NULL, Tcl_GetObjResult(interp), &objc2, &objv2); for (j = 0; j < objc2; j++) { int length; char *string; string = Tcl_GetStringFromObj(objv2[j], &length); length -= 4; if (length > 0) { string[length] = '\0'; Tcl_CreateHashEntry(&table, string, &dummy); string[length] = '.'; } } } Tcl_DecrRefCount(searchIn); } Tcl_DecrRefCount(encodingObj); } /* * Clear any values placed in the result by globbing. */ Tcl_ResetResult(interp); resultPtr = Tcl_GetObjResult(interp); hPtr = Tcl_FirstHashEntry(&table, &search); while (hPtr != NULL) { Tcl_Obj *strPtr; strPtr = Tcl_NewStringObj(Tcl_GetHashKey(&table, hPtr), -1); Tcl_ListObjAppendElement(NULL, resultPtr, strPtr); hPtr = Tcl_NextHashEntry(&search); } Tcl_DeleteHashTable(&table); } /* *------------------------------------------------------------------------ * * Tcl_SetSystemEncoding -- * * Sets the default encoding that should be used whenever the user * passes a NULL value in to one of the conversion routines. * If the supplied name is NULL, the system encoding is reset to the * default system encoding. * * Results: * The return value is TCL_OK if the system encoding was successfully * set to the encoding specified by name, TCL_ERROR otherwise. If * TCL_ERROR is returned, an error message is left in interp's result * object, unless interp was NULL. * * Side effects: * The reference count of the new system encoding is incremented. * The reference count of the old system encoding is decremented and * it may be freed. * *------------------------------------------------------------------------ */ int Tcl_SetSystemEncoding(interp, name) Tcl_Interp *interp; /* Interp for error reporting, if not NULL. */ CONST char *name; /* The name of the desired encoding, or NULL/"" * to reset to default encoding. */ { Tcl_Encoding encoding; Encoding *encodingPtr; if (!name || !*name) { Tcl_MutexLock(&encodingMutex); encoding = defaultEncoding; encodingPtr = (Encoding *) encoding; encodingPtr->refCount++; Tcl_MutexUnlock(&encodingMutex); } else { encoding = Tcl_GetEncoding(interp, name); if (encoding == NULL) { return TCL_ERROR; } } Tcl_MutexLock(&encodingMutex); FreeEncoding(systemEncoding); systemEncoding = encoding; Tcl_MutexUnlock(&encodingMutex); return TCL_OK; } /* *--------------------------------------------------------------------------- * * Tcl_CreateEncoding -- * * This procedure is called to define a new encoding and the procedures * that are used to convert between the specified encoding and Unicode. * * Results: * Returns a token that represents the encoding. If an encoding with * the same name already existed, the old encoding token remains * valid and continues to behave as it used to, and will eventually * be garbage collected when the last reference to it goes away. Any * subsequent calls to Tcl_GetEncoding with the specified name will * retrieve the most recent encoding token. * * Side effects: * The new encoding type is entered into a table visible to all * interpreters, keyed off the encoding's name. For each call to * this procedure, there should eventually be a call to * Tcl_FreeEncoding, so that the database can be cleaned up when * encodings aren't needed anymore. * *--------------------------------------------------------------------------- */ Tcl_Encoding Tcl_CreateEncoding(typePtr) Tcl_EncodingType *typePtr; /* The encoding type. */ { Tcl_HashEntry *hPtr; int new; Encoding *encodingPtr; char *name; Tcl_MutexLock(&encodingMutex); hPtr = Tcl_CreateHashEntry(&encodingTable, typePtr->encodingName, &new); if (new == 0) { /* * Remove old encoding from hash table, but don't delete it until * last reference goes away. */ encodingPtr = (Encoding *) Tcl_GetHashValue(hPtr); encodingPtr->hPtr = NULL; } name = ckalloc((unsigned) strlen(typePtr->encodingName) + 1); encodingPtr = (Encoding *) ckalloc(sizeof(Encoding)); encodingPtr->name = strcpy(name, typePtr->encodingName); encodingPtr->toUtfProc = typePtr->toUtfProc; encodingPtr->fromUtfProc = typePtr->fromUtfProc; encodingPtr->freeProc = typePtr->freeProc; encodingPtr->nullSize = typePtr->nullSize; encodingPtr->clientData = typePtr->clientData; if (typePtr->nullSize == 1) { encodingPtr->lengthProc = (LengthProc *) strlen; } else { encodingPtr->lengthProc = (LengthProc *) unilen; } encodingPtr->refCount = 1; encodingPtr->hPtr = hPtr; Tcl_SetHashValue(hPtr, encodingPtr); Tcl_MutexUnlock(&encodingMutex); return (Tcl_Encoding) encodingPtr; } /* *------------------------------------------------------------------------- * * Tcl_ExternalToUtfDString -- * * Convert a source buffer from the specified encoding into UTF-8. * If any of the bytes in the source buffer are invalid or cannot * be represented in the target encoding, a default fallback * character will be substituted. * * Results: * The converted bytes are stored in the DString, which is then NULL * terminated. The return value is a pointer to the value stored * in the DString. * * Side effects: * None. * *------------------------------------------------------------------------- */ char * Tcl_ExternalToUtfDString(encoding, src, srcLen, dstPtr) Tcl_Encoding encoding; /* The encoding for the source string, or * NULL for the default system encoding. */ CONST char *src; /* Source string in specified encoding. */ int srcLen; /* Source string length in bytes, or < 0 for * encoding-specific string length. */ Tcl_DString *dstPtr; /* Uninitialized or free DString in which * the converted string is stored. */ { char *dst; Tcl_EncodingState state; Encoding *encodingPtr; int flags, dstLen, result, soFar, srcRead, dstWrote, dstChars; Tcl_DStringInit(dstPtr); dst = Tcl_DStringValue(dstPtr); dstLen = dstPtr->spaceAvl - 1; if (encoding == NULL) { encoding = systemEncoding; } encodingPtr = (Encoding *) encoding; if (src == NULL) { srcLen = 0; } else if (srcLen < 0) { srcLen = (*encodingPtr->lengthProc)(src); } flags = TCL_ENCODING_START | TCL_ENCODING_END; while (1) { result = (*encodingPtr->toUtfProc)(encodingPtr->clientData, src, srcLen, flags, &state, dst, dstLen, &srcRead, &dstWrote, &dstChars); soFar = dst + dstWrote - Tcl_DStringValue(dstPtr); if (result != TCL_CONVERT_NOSPACE) { Tcl_DStringSetLength(dstPtr, soFar); return Tcl_DStringValue(dstPtr); } flags &= ~TCL_ENCODING_START; src += srcRead; srcLen -= srcRead; if (Tcl_DStringLength(dstPtr) == 0) { Tcl_DStringSetLength(dstPtr, dstLen); } Tcl_DStringSetLength(dstPtr, 2 * Tcl_DStringLength(dstPtr) + 1); dst = Tcl_DStringValue(dstPtr) + soFar; dstLen = Tcl_DStringLength(dstPtr) - soFar - 1; } } /* *------------------------------------------------------------------------- * * Tcl_ExternalToUtf -- * * Convert a source buffer from the specified encoding into UTF-8. * * Results: * The return value is one of TCL_OK, TCL_CONVERT_MULTIBYTE, * TCL_CONVERT_SYNTAX, TCL_CONVERT_UNKNOWN, or TCL_CONVERT_NOSPACE, * as documented in tcl.h. * * Side effects: * The converted bytes are stored in the output buffer. * *------------------------------------------------------------------------- */ int Tcl_ExternalToUtf(interp, encoding, src, srcLen, flags, statePtr, dst, dstLen, srcReadPtr, dstWrotePtr, dstCharsPtr) Tcl_Interp *interp; /* Interp for error return, if not NULL. */ Tcl_Encoding encoding; /* The encoding for the source string, or * NULL for the default system encoding. */ CONST char *src; /* Source string in specified encoding. */ int srcLen; /* Source string length in bytes, or < 0 for * encoding-specific string length. */ int flags; /* Conversion control flags. */ Tcl_EncodingState *statePtr;/* Place for conversion routine to store * state information used during a piecewise * conversion. Contents of statePtr are * initialized and/or reset by conversion * routine under control of flags argument. */ char *dst; /* Output buffer in which converted string * is stored. */ int dstLen; /* The maximum length of output buffer in * bytes. */ int *srcReadPtr; /* Filled with the number of bytes from the * source string that were converted. This * may be less than the original source length * if there was a problem converting some * source characters. */ int *dstWrotePtr; /* Filled with the number of bytes that were * stored in the output buffer as a result of * the conversion. */ int *dstCharsPtr; /* Filled with the number of characters that * correspond to the bytes stored in the * output buffer. */ { Encoding *encodingPtr; int result, srcRead, dstWrote, dstChars; Tcl_EncodingState state; if (encoding == NULL) { encoding = systemEncoding; } encodingPtr = (Encoding *) encoding; if (src == NULL) { srcLen = 0; } else if (srcLen < 0) { srcLen = (*encodingPtr->lengthProc)(src); } if (statePtr == NULL) { flags |= TCL_ENCODING_START | TCL_ENCODING_END; statePtr = &state; } if (srcReadPtr == NULL) { srcReadPtr = &srcRead; } if (dstWrotePtr == NULL) { dstWrotePtr = &dstWrote; } if (dstCharsPtr == NULL) { dstCharsPtr = &dstChars; } /* * If there are any null characters in the middle of the buffer, they will * converted to the UTF-8 null character (\xC080). To get the actual * \0 at the end of the destination buffer, we need to append it manually. */ dstLen--; result = (*encodingPtr->toUtfProc)(encodingPtr->clientData, src, srcLen, flags, statePtr, dst, dstLen, srcReadPtr, dstWrotePtr, dstCharsPtr); dst[*dstWrotePtr] = '\0'; return result; } /* *------------------------------------------------------------------------- * * Tcl_UtfToExternalDString -- * * Convert a source buffer from UTF-8 into the specified encoding. * If any of the bytes in the source buffer are invalid or cannot * be represented in the target encoding, a default fallback * character will be substituted. * * Results: * The converted bytes are stored in the DString, which is then * NULL terminated in an encoding-specific manner. The return value * is a pointer to the value stored in the DString. * * Side effects: * None. * *------------------------------------------------------------------------- */ char * Tcl_UtfToExternalDString(encoding, src, srcLen, dstPtr) Tcl_Encoding encoding; /* The encoding for the converted string, * or NULL for the default system encoding. */ CONST char *src; /* Source string in UTF-8. */ int srcLen; /* Source string length in bytes, or < 0 for * strlen(). */ Tcl_DString *dstPtr; /* Uninitialized or free DString in which * the converted string is stored. */ { char *dst; Tcl_EncodingState state; Encoding *encodingPtr; int flags, dstLen, result, soFar, srcRead, dstWrote, dstChars; Tcl_DStringInit(dstPtr); dst = Tcl_DStringValue(dstPtr); dstLen = dstPtr->spaceAvl - 1; if (encoding == NULL) { encoding = systemEncoding; } encodingPtr = (Encoding *) encoding; if (src == NULL) { srcLen = 0; } else if (srcLen < 0) { srcLen = strlen(src); } flags = TCL_ENCODING_START | TCL_ENCODING_END; while (1) { result = (*encodingPtr->fromUtfProc)(encodingPtr->clientData, src, srcLen, flags, &state, dst, dstLen, &srcRead, &dstWrote, &dstChars); soFar = dst + dstWrote - Tcl_DStringValue(dstPtr); if (result != TCL_CONVERT_NOSPACE) { if (encodingPtr->nullSize == 2) { Tcl_DStringSetLength(dstPtr, soFar + 1); } Tcl_DStringSetLength(dstPtr, soFar); return Tcl_DStringValue(dstPtr); } flags &= ~TCL_ENCODING_START; src += srcRead; srcLen -= srcRead; if (Tcl_DStringLength(dstPtr) == 0) { Tcl_DStringSetLength(dstPtr, dstLen); } Tcl_DStringSetLength(dstPtr, 2 * Tcl_DStringLength(dstPtr) + 1); dst = Tcl_DStringValue(dstPtr) + soFar; dstLen = Tcl_DStringLength(dstPtr) - soFar - 1; } } /* *------------------------------------------------------------------------- * * Tcl_UtfToExternal -- * * Convert a buffer from UTF-8 into the specified encoding. * * Results: * The return value is one of TCL_OK, TCL_CONVERT_MULTIBYTE, * TCL_CONVERT_SYNTAX, TCL_CONVERT_UNKNOWN, or TCL_CONVERT_NOSPACE, * as documented in tcl.h. * * Side effects: * The converted bytes are stored in the output buffer. * *------------------------------------------------------------------------- */ int Tcl_UtfToExternal(interp, encoding, src, srcLen, flags, statePtr, dst, dstLen, srcReadPtr, dstWrotePtr, dstCharsPtr) Tcl_Interp *interp; /* Interp for error return, if not NULL. */ Tcl_Encoding encoding; /* The encoding for the converted string, * or NULL for the default system encoding. */ CONST char *src; /* Source string in UTF-8. */ int srcLen; /* Source string length in bytes, or < 0 for * strlen(). */ int flags; /* Conversion control flags. */ Tcl_EncodingState *statePtr;/* Place for conversion routine to store * state information used during a piecewise * conversion. Contents of statePtr are * initialized and/or reset by conversion * routine under control of flags argument. */ char *dst; /* Output buffer in which converted string * is stored. */ int dstLen; /* The maximum length of output buffer in * bytes. */ int *srcReadPtr; /* Filled with the number of bytes from the * source string that were converted. This * may be less than the original source length * if there was a problem converting some * source characters. */ int *dstWrotePtr; /* Filled with the number of bytes that were * stored in the output buffer as a result of * the conversion. */ int *dstCharsPtr; /* Filled with the number of characters that * correspond to the bytes stored in the * output buffer. */ { Encoding *encodingPtr; int result, srcRead, dstWrote, dstChars; Tcl_EncodingState state; if (encoding == NULL) { encoding = systemEncoding; } encodingPtr = (Encoding *) encoding; if (src == NULL) { srcLen = 0; } else if (srcLen < 0) { srcLen = strlen(src); } if (statePtr == NULL) { flags |= TCL_ENCODING_START | TCL_ENCODING_END; statePtr = &state; } if (srcReadPtr == NULL) { srcReadPtr = &srcRead; } if (dstWrotePtr == NULL) { dstWrotePtr = &dstWrote; } if (dstCharsPtr == NULL) { dstCharsPtr = &dstChars; } dstLen -= encodingPtr->nullSize; result = (*encodingPtr->fromUtfProc)(encodingPtr->clientData, src, srcLen, flags, statePtr, dst, dstLen, srcReadPtr, dstWrotePtr, dstCharsPtr); if (encodingPtr->nullSize == 2) { dst[*dstWrotePtr + 1] = '\0'; } dst[*dstWrotePtr] = '\0'; return result; } /* *--------------------------------------------------------------------------- * * Tcl_FindExecutable -- * * This procedure computes the absolute path name of the current * application, given its argv[0] value. * * Results: * None. * * Side effects: * The variable tclExecutableName gets filled in with the file * name for the application, if we figured it out. If we couldn't * figure it out, tclExecutableName is set to NULL. * *--------------------------------------------------------------------------- */ void Tcl_FindExecutable(argv0) CONST char *argv0; /* The value of the application's argv[0] * (native). */ { int mustCleanUtf; CONST char *name; Tcl_DString buffer, nameString; TclInitSubsystems(argv0); if (argv0 == NULL) { goto done; } if (tclExecutableName != NULL) { ckfree(tclExecutableName); tclExecutableName = NULL; } if ((name = TclpFindExecutable(argv0)) == NULL) { goto done; } /* * The value returned from TclpNameOfExecutable is a UTF string that * is possibly dirty depending on when it was initialized. * TclFindEncodings will indicate whether we must "clean" the UTF (as * reported by the underlying system). To assure that the UTF string * is a properly encoded native string for this system, convert the * UTF string to the default native encoding before the default * encoding is initialized. Then, convert it back to UTF after the * system encoding is loaded. */ Tcl_UtfToExternalDString(NULL, name, -1, &buffer); mustCleanUtf = TclFindEncodings(argv0); /* * Now it is OK to convert the native string back to UTF and set * the value of the tclExecutableName. */ if (mustCleanUtf) { Tcl_ExternalToUtfDString(NULL, Tcl_DStringValue(&buffer), -1, &nameString); tclExecutableName = (char *) ckalloc((unsigned) (Tcl_DStringLength(&nameString) + 1)); strcpy(tclExecutableName, Tcl_DStringValue(&nameString)); Tcl_DStringFree(&nameString); } else { tclExecutableName = (char *) ckalloc((unsigned) (strlen(name) + 1)); strcpy(tclExecutableName, name); } Tcl_DStringFree(&buffer); return; done: (void) TclFindEncodings(argv0); } /* *--------------------------------------------------------------------------- * * LoadEncodingFile -- * * Read a file that describes an encoding and create a new Encoding * from the data. * * Results: * The return value is the newly loaded Encoding, or NULL if * the file didn't exist of was in the incorrect format. If NULL was * returned, an error message is left in interp's result object, * unless interp was NULL. * * Side effects: * File read from disk. * *--------------------------------------------------------------------------- */ static Tcl_Encoding LoadEncodingFile(interp, name) Tcl_Interp *interp; /* Interp for error reporting, if not NULL. */ CONST char *name; /* The name of the encoding file on disk * and also the name for new encoding. */ { int objc, i, ch; Tcl_Obj **objv; Tcl_Obj *pathPtr; Tcl_Channel chan; Tcl_Encoding encoding; pathPtr = TclGetLibraryPath(); if (pathPtr == NULL) { goto unknown; } objc = 0; Tcl_ListObjGetElements(NULL, pathPtr, &objc, &objv); chan = NULL; for (i = 0; i < objc; i++) { chan = OpenEncodingFile(Tcl_GetString(objv[i]), name); if (chan != NULL) { break; } } if (chan == NULL) { goto unknown; } Tcl_SetChannelOption(NULL, chan, "-encoding", "utf-8"); while (1) { Tcl_DString ds; Tcl_DStringInit(&ds); Tcl_Gets(chan, &ds); ch = Tcl_DStringValue(&ds)[0]; Tcl_DStringFree(&ds); if (ch != '#') { break; } } encoding = NULL; switch (ch) { case 'S': { encoding = LoadTableEncoding(interp, name, ENCODING_SINGLEBYTE, chan); break; } case 'D': { encoding = LoadTableEncoding(interp, name, ENCODING_DOUBLEBYTE, chan); break; } case 'M': { encoding = LoadTableEncoding(interp, name, ENCODING_MULTIBYTE, chan); break; } case 'E': { encoding = LoadEscapeEncoding(name, chan); break; } } if ((encoding == NULL) && (interp != NULL)) { Tcl_AppendResult(interp, "invalid encoding file \"", name, "\"", NULL); if (ch == 'E') { Tcl_AppendResult(interp, " or missing sub-encoding", NULL); } } Tcl_Close(NULL, chan); return encoding; unknown: if (interp != NULL) { Tcl_AppendResult(interp, "unknown encoding \"", name, "\"", NULL); } return NULL; } /* *---------------------------------------------------------------------- * * OpenEncodingFile -- * * Look for the file encoding/.enc in the specified * directory. * * Results: * Returns an open file channel if the file exists. * * Side effects: * None. * *---------------------------------------------------------------------- */ static Tcl_Channel OpenEncodingFile(dir, name) CONST char *dir; CONST char *name; { CONST char *argv[3]; Tcl_DString pathString; CONST char *path; Tcl_Channel chan; Tcl_Obj *pathPtr; argv[0] = dir; argv[1] = "encoding"; argv[2] = name; Tcl_DStringInit(&pathString); Tcl_JoinPath(3, argv, &pathString); path = Tcl_DStringAppend(&pathString, ".enc", -1); pathPtr = Tcl_NewStringObj(path,-1); Tcl_IncrRefCount(pathPtr); chan = Tcl_FSOpenFileChannel(NULL, pathPtr, "r", 0); Tcl_DecrRefCount(pathPtr); Tcl_DStringFree(&pathString); return chan; } /* *------------------------------------------------------------------------- * * LoadTableEncoding -- * * Helper function for LoadEncodingTable(). Loads a table to that * converts between Unicode and some other encoding and creates an * encoding (using a TableEncoding structure) from that information. * * File contains binary data, but begins with a marker to indicate * byte-ordering, so that same binary file can be read on either * endian platforms. * * Results: * The return value is the new encoding, or NULL if the encoding * could not be created (because the file contained invalid data). * * Side effects: * None. * *------------------------------------------------------------------------- */ static Tcl_Encoding LoadTableEncoding(interp, name, type, chan) Tcl_Interp *interp; /* Interp for temporary obj while reading. */ CONST char *name; /* Name for new encoding. */ int type; /* Type of encoding (ENCODING_?????). */ Tcl_Channel chan; /* File containing new encoding. */ { Tcl_DString lineString; Tcl_Obj *objPtr; char *line; int i, hi, lo, numPages, symbol, fallback; unsigned char used[256]; unsigned int size; TableEncodingData *dataPtr; unsigned short *pageMemPtr; Tcl_EncodingType encType; /* * Speed over memory. Use a full 256 character table to decode hex * sequences in the encoding files. */ static CONST char staticHex[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0 ... 15 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16 ... 31 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 32 ... 47 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 48 ... 63 */ 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 64 ... 79 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 ... 95 */ 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 96 ... 111 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 112 ... 127 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128 ... 143 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144 ... 159 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 160 ... 175 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 176 ... 191 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 192 ... 207 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 208 ... 223 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 224 ... 239 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 240 ... 255 */ }; Tcl_DStringInit(&lineString); Tcl_Gets(chan, &lineString); line = Tcl_DStringValue(&lineString); fallback = (int) strtol(line, &line, 16); symbol = (int) strtol(line, &line, 10); numPages = (int) strtol(line, &line, 10); Tcl_DStringFree(&lineString); if (numPages < 0) { numPages = 0; } else if (numPages > 256) { numPages = 256; } memset(used, 0, sizeof(used)); #undef PAGESIZE #define PAGESIZE (256 * sizeof(unsigned short)) dataPtr = (TableEncodingData *) ckalloc(sizeof(TableEncodingData)); memset(dataPtr, 0, sizeof(TableEncodingData)); dataPtr->fallback = fallback; /* * Read the table that maps characters to Unicode. Performs a single * malloc to get the memory for the array and all the pages needed by * the array. */ size = 256 * sizeof(unsigned short *) + numPages * PAGESIZE; dataPtr->toUnicode = (unsigned short **) ckalloc(size); memset(dataPtr->toUnicode, 0, size); pageMemPtr = (unsigned short *) (dataPtr->toUnicode + 256); if (interp == NULL) { objPtr = Tcl_NewObj(); } else { objPtr = Tcl_GetObjResult(interp); } for (i = 0; i < numPages; i++) { int ch; char *p; Tcl_ReadChars(chan, objPtr, 3 + 16 * (16 * 4 + 1), 0); p = Tcl_GetString(objPtr); hi = (staticHex[(unsigned int)p[0]] << 4) + staticHex[(unsigned int)p[1]]; dataPtr->toUnicode[hi] = pageMemPtr; p += 2; for (lo = 0; lo < 256; lo++) { if ((lo & 0x0f) == 0) { p++; } ch = (staticHex[(unsigned int)p[0]] << 12) + (staticHex[(unsigned int)p[1]] << 8) + (staticHex[(unsigned int)p[2]] << 4) + staticHex[(unsigned int)p[3]]; if (ch != 0) { used[ch >> 8] = 1; } *pageMemPtr = (unsigned short) ch; pageMemPtr++; p += 4; } } if (interp == NULL) { Tcl_DecrRefCount(objPtr); } else { Tcl_ResetResult(interp); } if (type == ENCODING_DOUBLEBYTE) { memset(dataPtr->prefixBytes, 1, sizeof(dataPtr->prefixBytes)); } else { for (hi = 1; hi < 256; hi++) { if (dataPtr->toUnicode[hi] != NULL) { dataPtr->prefixBytes[hi] = 1; } } } /* * Invert toUnicode array to produce the fromUnicode array. Performs a * single malloc to get the memory for the array and all the pages * needed by the array. While reading in the toUnicode array, we * remembered what pages that would be needed for the fromUnicode array. */ if (symbol) { used[0] = 1; } numPages = 0; for (hi = 0; hi < 256; hi++) { if (used[hi]) { numPages++; } } size = 256 * sizeof(unsigned short *) + numPages * PAGESIZE; dataPtr->fromUnicode = (unsigned short **) ckalloc(size); memset(dataPtr->fromUnicode, 0, size); pageMemPtr = (unsigned short *) (dataPtr->fromUnicode + 256); for (hi = 0; hi < 256; hi++) { if (dataPtr->toUnicode[hi] == NULL) { dataPtr->toUnicode[hi] = emptyPage; } else { for (lo = 0; lo < 256; lo++) { int ch; ch = dataPtr->toUnicode[hi][lo]; if (ch != 0) { unsigned short *page; page = dataPtr->fromUnicode[ch >> 8]; if (page == NULL) { page = pageMemPtr; pageMemPtr += 256; dataPtr->fromUnicode[ch >> 8] = page; } page[ch & 0xff] = (unsigned short) ((hi << 8) + lo); } } } } if (type == ENCODING_MULTIBYTE) { /* * If multibyte encodings don't have a backslash character, define * one. Otherwise, on Windows, native file names won't work because * the backslash in the file name will map to the unknown character * (question mark) when converting from UTF-8 to external encoding. */ if (dataPtr->fromUnicode[0] != NULL) { if (dataPtr->fromUnicode[0]['\\'] == '\0') { dataPtr->fromUnicode[0]['\\'] = '\\'; } } } if (symbol) { unsigned short *page; /* * Make a special symbol encoding that not only maps the symbol * characters from their Unicode code points down into page 0, but * also ensure that the characters on page 0 map to themselves. * This is so that a symbol font can be used to display a simple * string like "abcd" and have alpha, beta, chi, delta show up, * rather than have "unknown" chars show up because strictly * speaking the symbol font doesn't have glyphs for those low ascii * chars. */ page = dataPtr->fromUnicode[0]; if (page == NULL) { page = pageMemPtr; dataPtr->fromUnicode[0] = page; } for (lo = 0; lo < 256; lo++) { if (dataPtr->toUnicode[0][lo] != 0) { page[lo] = (unsigned short) lo; } } } for (hi = 0; hi < 256; hi++) { if (dataPtr->fromUnicode[hi] == NULL) { dataPtr->fromUnicode[hi] = emptyPage; } } /* * For trailing 'R'everse encoding, see [Patch #689341] */ Tcl_DStringInit(&lineString); do { int len; /* skip leading empty lines */ while ((len = Tcl_Gets(chan, &lineString)) == 0) ; if (len < 0) { break; } line = Tcl_DStringValue(&lineString); if (line[0] != 'R') { break; } for (Tcl_DStringSetLength(&lineString, 0); (len = Tcl_Gets(chan, &lineString)) >= 0; Tcl_DStringSetLength(&lineString, 0)) { unsigned char* p; int to, from; if (len < 5) { continue; } p = (unsigned char*) Tcl_DStringValue(&lineString); to = (staticHex[p[0]] << 12) + (staticHex[p[1]] << 8) + (staticHex[p[2]] << 4) + staticHex[p[3]]; if (to == 0) { continue; } for (p += 5, len -= 5; len >= 0 && *p; p += 5, len -= 5) { from = (staticHex[p[0]] << 12) + (staticHex[p[1]] << 8) + (staticHex[p[2]] << 4) + staticHex[p[3]]; if (from == 0) { continue; } dataPtr->fromUnicode[from >> 8][from & 0xff] = to; } } } while (0); Tcl_DStringFree(&lineString); encType.encodingName = name; encType.toUtfProc = TableToUtfProc; encType.fromUtfProc = TableFromUtfProc; encType.freeProc = TableFreeProc; encType.nullSize = (type == ENCODING_DOUBLEBYTE) ? 2 : 1; encType.clientData = (ClientData) dataPtr; return Tcl_CreateEncoding(&encType); } /* *------------------------------------------------------------------------- * * LoadEscapeEncoding -- * * Helper function for LoadEncodingTable(). Loads a state machine * that converts between Unicode and some other encoding. * * File contains text data that describes the escape sequences that * are used to choose an encoding and the associated names for the * sub-encodings. * * Results: * The return value is the new encoding, or NULL if the encoding * could not be created (because the file contained invalid data). * * Side effects: * None. * *------------------------------------------------------------------------- */ static Tcl_Encoding LoadEscapeEncoding(name, chan) CONST char *name; /* Name for new encoding. */ Tcl_Channel chan; /* File containing new encoding. */ { int i, missingSubEncoding = 0; unsigned int size; Tcl_DString escapeData; char init[16], final[16]; EscapeEncodingData *dataPtr; Tcl_EncodingType type; init[0] = '\0'; final[0] = '\0'; Tcl_DStringInit(&escapeData); while (1) { int argc; CONST char **argv; char *line; Tcl_DString lineString; Tcl_DStringInit(&lineString); if (Tcl_Gets(chan, &lineString) < 0) { break; } line = Tcl_DStringValue(&lineString); if (Tcl_SplitList(NULL, line, &argc, &argv) != TCL_OK) { continue; } if (argc >= 2) { if (strcmp(argv[0], "name") == 0) { ; } else if (strcmp(argv[0], "init") == 0) { strncpy(init, argv[1], sizeof(init)); init[sizeof(init) - 1] = '\0'; } else if (strcmp(argv[0], "final") == 0) { strncpy(final, argv[1], sizeof(final)); final[sizeof(final) - 1] = '\0'; } else { EscapeSubTable est; strncpy(est.sequence, argv[1], sizeof(est.sequence)); est.sequence[sizeof(est.sequence) - 1] = '\0'; est.sequenceLen = strlen(est.sequence); strncpy(est.name, argv[0], sizeof(est.name)); est.name[sizeof(est.name) - 1] = '\0'; /* * Load the subencodings first so we're never stuck * trying to use a half-loaded system encoding to * open/read a *.enc file. */ est.encodingPtr = (Encoding *) Tcl_GetEncoding(NULL, est.name); if ((est.encodingPtr == NULL) || (est.encodingPtr->toUtfProc != TableToUtfProc)) { missingSubEncoding = 1; } Tcl_DStringAppend(&escapeData, (char *) &est, sizeof(est)); } } ckfree((char *) argv); Tcl_DStringFree(&lineString); } if (missingSubEncoding) { Tcl_DStringFree(&escapeData); return NULL; } size = sizeof(EscapeEncodingData) - sizeof(EscapeSubTable) + Tcl_DStringLength(&escapeData); dataPtr = (EscapeEncodingData *) ckalloc(size); dataPtr->initLen = strlen(init); strcpy(dataPtr->init, init); dataPtr->finalLen = strlen(final); strcpy(dataPtr->final, final); dataPtr->numSubTables = Tcl_DStringLength(&escapeData) / sizeof(EscapeSubTable); memcpy((VOID *) dataPtr->subTables, (VOID *) Tcl_DStringValue(&escapeData), (size_t) Tcl_DStringLength(&escapeData)); Tcl_DStringFree(&escapeData); memset(dataPtr->prefixBytes, 0, sizeof(dataPtr->prefixBytes)); for (i = 0; i < dataPtr->numSubTables; i++) { dataPtr->prefixBytes[UCHAR(dataPtr->subTables[i].sequence[0])] = 1; } if (dataPtr->init[0] != '\0') { dataPtr->prefixBytes[UCHAR(dataPtr->init[0])] = 1; } if (dataPtr->final[0] != '\0') { dataPtr->prefixBytes[UCHAR(dataPtr->final[0])] = 1; } type.encodingName = name; type.toUtfProc = EscapeToUtfProc; type.fromUtfProc = EscapeFromUtfProc; type.freeProc = EscapeFreeProc; type.nullSize = 1; type.clientData = (ClientData) dataPtr; return Tcl_CreateEncoding(&type); } /* *------------------------------------------------------------------------- * * BinaryProc -- * * The default conversion when no other conversion is specified. * No translation is done; source bytes are copied directly to * destination bytes. * * Results: * Returns TCL_OK if conversion was successful. * * Side effects: * None. * *------------------------------------------------------------------------- */ static int BinaryProc(clientData, src, srcLen, flags, statePtr, dst, dstLen, srcReadPtr, dstWrotePtr, dstCharsPtr) ClientData clientData; /* Not used. */ CONST char *src; /* Source string (unknown encoding). */ int srcLen; /* Source string length in bytes. */ int flags; /* Conversion control flags. */ Tcl_EncodingState *statePtr;/* Place for conversion routine to store * state information used during a piecewise * conversion. Contents of statePtr are * initialized and/or reset by conversion * routine under control of flags argument. */ char *dst; /* Output buffer in which converted string * is stored. */ int dstLen; /* The maximum length of output buffer in * bytes. */ int *srcReadPtr; /* Filled with the number of bytes from the * source string that were converted. */ int *dstWrotePtr; /* Filled with the number of bytes that were * stored in the output buffer as a result of * the conversion. */ int *dstCharsPtr; /* Filled with the number of characters that * correspond to the bytes stored in the * output buffer. */ { int result; result = TCL_OK; dstLen -= TCL_UTF_MAX - 1; if (dstLen < 0) { dstLen = 0; } if (srcLen > dstLen) { srcLen = dstLen; result = TCL_CONVERT_NOSPACE; } *srcReadPtr = srcLen; *dstWrotePtr = srcLen; *dstCharsPtr = srcLen; memcpy((void *) dst, (void *) src, (size_t) srcLen); return result; } /* *------------------------------------------------------------------------- * * UtfExtToUtfIntProc -- * * Convert from UTF-8 to UTF-8. While converting null-bytes from * the Tcl's internal representation (0xc0, 0x80) to the official * representation (0x00). See UtfToUtfProc for details. * * Results: * Returns TCL_OK if conversion was successful. * * Side effects: * None. * *------------------------------------------------------------------------- */ static int UtfIntToUtfExtProc(clientData, src, srcLen, flags, statePtr, dst, dstLen, srcReadPtr, dstWrotePtr, dstCharsPtr) ClientData clientData; /* Not used. */ CONST char *src; /* Source string in UTF-8. */ int srcLen; /* Source string length in bytes. */ int flags; /* Conversion control flags. */ Tcl_EncodingState *statePtr;/* Place for conversion routine to store * state information used during a piecewise * conversion. Contents of statePtr are * initialized and/or reset by conversion * routine under control of flags argument. */ char *dst; /* Output buffer in which converted string * is stored. */ int dstLen; /* The maximum length of output buffer in * bytes. */ int *srcReadPtr; /* Filled with the number of bytes from the * source string that were converted. This * may be less than the original source length * if there was a problem converting some * source characters. */ int *dstWrotePtr; /* Filled with the number of bytes that were * stored in the output buffer as a result of * the conversion. */ int *dstCharsPtr; /* Filled with the number of characters that * correspond to the bytes stored in the * output buffer. */ { return UtfToUtfProc(clientData, src, srcLen, flags, statePtr, dst, dstLen, srcReadPtr, dstWrotePtr, dstCharsPtr, 1); } /* *------------------------------------------------------------------------- * * UtfExtToUtfIntProc -- * * Convert from UTF-8 to UTF-8 while converting null-bytes from * the official representation (0x00) to Tcl's internal * representation (0xc0, 0x80). See UtfToUtfProc for details. * * Results: * Returns TCL_OK if conversion was successful. * * Side effects: * None. * *------------------------------------------------------------------------- */ static int UtfExtToUtfIntProc(clientData, src, srcLen, flags, statePtr, dst, dstLen, srcReadPtr, dstWrotePtr, dstCharsPtr) ClientData clientData; /* Not used. */ CONST char *src; /* Source string in UTF-8. */ int srcLen; /* Source string length in bytes. */ int flags; /* Conversion control flags. */ Tcl_EncodingState *statePtr;/* Place for conversion routine to store * state information used during a piecewise * conversion. Contents of statePtr are * initialized and/or reset by conversion * routine under control of flags argument. */ char *dst; /* Output buffer in which converted string * is stored. */ int dstLen; /* The maximum length of output buffer in * bytes. */ int *srcReadPtr; /* Filled with the number of bytes from the * source string that were converted. This * may be less than the original source length * if there was a problem converting some * source characters. */ int *dstWrotePtr; /* Filled with the number of bytes that were * stored in the output buffer as a result of * the conversion. */ int *dstCharsPtr; /* Filled with the number of characters that * correspond to the bytes stored in the * output buffer. */ { return UtfToUtfProc(clientData, src, srcLen, flags, statePtr, dst, dstLen, srcReadPtr, dstWrotePtr, dstCharsPtr, 0); } /* *------------------------------------------------------------------------- * * UtfToUtfProc -- * * Convert from UTF-8 to UTF-8. Note that the UTF-8 to UTF-8 * translation is not a no-op, because it will turn a stream of * improperly formed UTF-8 into a properly formed stream. * * Results: * Returns TCL_OK if conversion was successful. * * Side effects: * None. * *------------------------------------------------------------------------- */ static int UtfToUtfProc(clientData, src, srcLen, flags, statePtr, dst, dstLen, srcReadPtr, dstWrotePtr, dstCharsPtr, pureNullMode) ClientData clientData; /* Not used. */ CONST char *src; /* Source string in UTF-8. */ int srcLen; /* Source string length in bytes. */ int flags; /* Conversion control flags. */ Tcl_EncodingState *statePtr;/* Place for conversion routine to store * state information used during a piecewise * conversion. Contents of statePtr are * initialized and/or reset by conversion * routine under control of flags argument. */ char *dst; /* Output buffer in which converted string * is stored. */ int dstLen; /* The maximum length of output buffer in * bytes. */ int *srcReadPtr; /* Filled with the number of bytes from the * source string that were converted. This * may be less than the original source length * if there was a problem converting some * source characters. */ int *dstWrotePtr; /* Filled with the number of bytes that were * stored in the output buffer as a result of * the conversion. */ int *dstCharsPtr; /* Filled with the number of characters that * correspond to the bytes stored in the * output buffer. */ int pureNullMode; /* Convert embedded nulls from * internal representation to real * null-bytes or vice versa */ { CONST char *srcStart, *srcEnd, *srcClose; char *dstStart, *dstEnd; int result, numChars; Tcl_UniChar ch; result = TCL_OK; srcStart = src; srcEnd = src + srcLen; srcClose = srcEnd; if ((flags & TCL_ENCODING_END) == 0) { srcClose -= TCL_UTF_MAX; } dstStart = dst; dstEnd = dst + dstLen - TCL_UTF_MAX; for (numChars = 0; src < srcEnd; numChars++) { if ((src > srcClose) && (!Tcl_UtfCharComplete(src, srcEnd - src))) { /* * If there is more string to follow, this will ensure that the * last UTF-8 character in the source buffer hasn't been cut off. */ result = TCL_CONVERT_MULTIBYTE; break; } if (dst > dstEnd) { result = TCL_CONVERT_NOSPACE; break; } if (UCHAR(*src) < 0x80 && !(UCHAR(*src) == 0 && pureNullMode == 0)) { /* * Copy 7bit chatacters, but skip null-bytes when we are * in input mode, so that they get converted to 0xc080. */ *dst++ = *src++; } else if (pureNullMode == 1 && UCHAR(*src) == 0xc0 && UCHAR(*(src+1)) == 0x80) { /* * Convert 0xc080 to real nulls when we are in output mode. */ *dst++ = 0; src += 2; } else if (!Tcl_UtfCharComplete(src, srcEnd - src)) { /* Always check before using Tcl_UtfToUniChar. Not doing * can so cause it run beyond the endof the buffer! If we * happen such an incomplete char its bytes are made to * represent themselves. */ ch = (unsigned char) *src; src += 1; dst += Tcl_UniCharToUtf(ch, dst); } else { src += Tcl_UtfToUniChar(src, &ch); dst += Tcl_UniCharToUtf(ch, dst); } } *srcReadPtr = src - srcStart; *dstWrotePtr = dst - dstStart; *dstCharsPtr = numChars; return result; } /* *------------------------------------------------------------------------- * * UnicodeToUtfProc -- * * Convert from Unicode to UTF-8. * * Results: * Returns TCL_OK if conversion was successful. * * Side effects: * None. * *------------------------------------------------------------------------- */ static int UnicodeToUtfProc(clientData, src, srcLen, flags, statePtr, dst, dstLen, srcReadPtr, dstWrotePtr, dstCharsPtr) ClientData clientData; /* Not used. */ CONST char *src; /* Source string in Unicode. */ int srcLen; /* Source string length in bytes. */ int flags; /* Conversion control flags. */ Tcl_EncodingState *statePtr;/* Place for conversion routine to store * state information used during a piecewise * conversion. Contents of statePtr are * initialized and/or reset by conversion * routine under control of flags argument. */ char *dst; /* Output buffer in which converted string * is stored. */ int dstLen; /* The maximum length of output buffer in * bytes. */ int *srcReadPtr; /* Filled with the number of bytes from the * source string that were converted. This * may be less than the original source length * if there was a problem converting some * source characters. */ int *dstWrotePtr; /* Filled with the number of bytes that were * stored in the output buffer as a result of * the conversion. */ int *dstCharsPtr; /* Filled with the number of characters that * correspond to the bytes stored in the * output buffer. */ { CONST char *srcStart, *srcEnd; char *dstEnd, *dstStart; int result, numChars; Tcl_UniChar ch; result = TCL_OK; if ((srcLen % sizeof(Tcl_UniChar)) != 0) { result = TCL_CONVERT_MULTIBYTE; srcLen /= sizeof(Tcl_UniChar); srcLen *= sizeof(Tcl_UniChar); } srcStart = src; srcEnd = src + srcLen; dstStart = dst; dstEnd = dst + dstLen - TCL_UTF_MAX; for (numChars = 0; src < srcEnd; numChars++) { if (dst > dstEnd) { result = TCL_CONVERT_NOSPACE; break; } /* * Special case for 1-byte utf chars for speed. Make sure we * work with Tcl_UniChar-size data. */ ch = *(Tcl_UniChar *)src; if (ch && ch < 0x80) { *dst++ = (ch & 0xFF); } else { dst += Tcl_UniCharToUtf(ch, dst); } src += sizeof(Tcl_UniChar); } *srcReadPtr = src - srcStart; *dstWrotePtr = dst - dstStart; *dstCharsPtr = numChars; return result; } /* *------------------------------------------------------------------------- * * UtfToUnicodeProc -- * * Convert from UTF-8 to Unicode. * * Results: * Returns TCL_OK if conversion was successful. * * Side effects: * None. * *------------------------------------------------------------------------- */ static int UtfToUnicodeProc(clientData, src, srcLen, flags, statePtr, dst, dstLen, srcReadPtr, dstWrotePtr, dstCharsPtr) ClientData clientData; /* TableEncodingData that specifies encoding. */ CONST char *src; /* Source string in UTF-8. */ int srcLen; /* Source string length in bytes. */ int flags; /* Conversion control flags. */ Tcl_EncodingState *statePtr;/* Place for conversion routine to store * state information used during a piecewise * conversion. Contents of statePtr are * initialized and/or reset by conversion * routine under control of flags argument. */ char *dst; /* Output buffer in which converted string * is stored. */ int dstLen; /* The maximum length of output buffer in * bytes. */ int *srcReadPtr; /* Filled with the number of bytes from the * source string that were converted. This * may be less than the original source length * if there was a problem converting some * source characters. */ int *dstWrotePtr; /* Filled with the number of bytes that were * stored in the output buffer as a result of * the conversion. */ int *dstCharsPtr; /* Filled with the number of characters that * correspond to the bytes stored in the * output buffer. */ { CONST char *srcStart, *srcEnd, *srcClose, *dstStart, *dstEnd; int result, numChars; Tcl_UniChar ch; srcStart = src; srcEnd = src + srcLen; srcClose = srcEnd; if ((flags & TCL_ENCODING_END) == 0) { srcClose -= TCL_UTF_MAX; } dstStart = dst; dstEnd = dst + dstLen - sizeof(Tcl_UniChar); result = TCL_OK; for (numChars = 0; src < srcEnd; numChars++) { if ((src > srcClose) && (!Tcl_UtfCharComplete(src, srcEnd - src))) { /* * If there is more string to follow, this will ensure that the * last UTF-8 character in the source buffer hasn't been cut off. */ result = TCL_CONVERT_MULTIBYTE; break; } if (dst > dstEnd) { result = TCL_CONVERT_NOSPACE; break; } src += TclUtfToUniChar(src, &ch); /* * Need to handle this in a way that won't cause misalignment * by casting dst to a Tcl_UniChar. [Bug 1122671] * XXX: This hard-codes the assumed size of Tcl_UniChar as 2. */ #ifdef WORDS_BIGENDIAN *dst++ = (ch >> 8); *dst++ = (ch & 0xFF); #else *dst++ = (ch & 0xFF); *dst++ = (ch >> 8); #endif } *srcReadPtr = src - srcStart; *dstWrotePtr = dst - dstStart; *dstCharsPtr = numChars; return result; } /* *------------------------------------------------------------------------- * * TableToUtfProc -- * * Convert from the encoding specified by the TableEncodingData into * UTF-8. * * Results: * Returns TCL_OK if conversion was successful. * * Side effects: * None. * *------------------------------------------------------------------------- */ static int TableToUtfProc(clientData, src, srcLen, flags, statePtr, dst, dstLen, srcReadPtr, dstWrotePtr, dstCharsPtr) ClientData clientData; /* TableEncodingData that specifies * encoding. */ CONST char *src; /* Source string in specified encoding. */ int srcLen; /* Source string length in bytes. */ int flags; /* Conversion control flags. */ Tcl_EncodingState *statePtr;/* Place for conversion routine to store * state information used during a piecewise * conversion. Contents of statePtr are * initialized and/or reset by conversion * routine under control of flags argument. */ char *dst; /* Output buffer in which converted string * is stored. */ int dstLen; /* The maximum length of output buffer in * bytes. */ int *srcReadPtr; /* Filled with the number of bytes from the * source string that were converted. This * may be less than the original source length * if there was a problem converting some * source characters. */ int *dstWrotePtr; /* Filled with the number of bytes that were * stored in the output buffer as a result of * the conversion. */ int *dstCharsPtr; /* Filled with the number of characters that * correspond to the bytes stored in the * output buffer. */ { CONST char *srcStart, *srcEnd; char *dstEnd, *dstStart, *prefixBytes; int result, byte, numChars; Tcl_UniChar ch; unsigned short **toUnicode; unsigned short *pageZero; TableEncodingData *dataPtr; srcStart = src; srcEnd = src + srcLen; dstStart = dst; dstEnd = dst + dstLen - TCL_UTF_MAX; dataPtr = (TableEncodingData *) clientData; toUnicode = dataPtr->toUnicode; prefixBytes = dataPtr->prefixBytes; pageZero = toUnicode[0]; result = TCL_OK; for (numChars = 0; src < srcEnd; numChars++) { if (dst > dstEnd) { result = TCL_CONVERT_NOSPACE; break; } byte = *((unsigned char *) src); if (prefixBytes[byte]) { src++; if (src >= srcEnd) { src--; result = TCL_CONVERT_MULTIBYTE; break; } ch = toUnicode[byte][*((unsigned char *) src)]; } else { ch = pageZero[byte]; } if ((ch == 0) && (byte != 0)) { if (flags & TCL_ENCODING_STOPONERROR) { result = TCL_CONVERT_SYNTAX; break; } if (prefixBytes[byte]) { src--; } ch = (Tcl_UniChar) byte; } /* * Special case for 1-byte utf chars for speed. */ if (ch && ch < 0x80) { *dst++ = (char) ch; } else { dst += Tcl_UniCharToUtf(ch, dst); } src++; } *srcReadPtr = src - srcStart; *dstWrotePtr = dst - dstStart; *dstCharsPtr = numChars; return result; } /* *------------------------------------------------------------------------- * * TableFromUtfProc -- * * Convert from UTF-8 into the encoding specified by the * TableEncodingData. * * Results: * Returns TCL_OK if conversion was successful. * * Side effects: * None. * *------------------------------------------------------------------------- */ static int TableFromUtfProc(clientData, src, srcLen, flags, statePtr, dst, dstLen, srcReadPtr, dstWrotePtr, dstCharsPtr) ClientData clientData; /* TableEncodingData that specifies * encoding. */ CONST char *src; /* Source string in UTF-8. */ int srcLen; /* Source string length in bytes. */ int flags; /* Conversion control flags. */ Tcl_EncodingState *statePtr;/* Place for conversion routine to store * state information used during a piecewise * conversion. Contents of statePtr are * initialized and/or reset by conversion * routine under control of flags argument. */ char *dst; /* Output buffer in which converted string * is stored. */ int dstLen; /* The maximum length of output buffer in * bytes. */ int *srcReadPtr; /* Filled with the number of bytes from the * source string that were converted. This * may be less than the original source length * if there was a problem converting some * source characters. */ int *dstWrotePtr; /* Filled with the number of bytes that were * stored in the output buffer as a result of * the conversion. */ int *dstCharsPtr; /* Filled with the number of characters that * correspond to the bytes stored in the * output buffer. */ { CONST char *srcStart, *srcEnd, *srcClose; char *dstStart, *dstEnd, *prefixBytes; Tcl_UniChar ch; int result, len, word, numChars; TableEncodingData *dataPtr; unsigned short **fromUnicode; result = TCL_OK; dataPtr = (TableEncodingData *) clientData; prefixBytes = dataPtr->prefixBytes; fromUnicode = dataPtr->fromUnicode; srcStart = src; srcEnd = src + srcLen; srcClose = srcEnd; if ((flags & TCL_ENCODING_END) == 0) { srcClose -= TCL_UTF_MAX; } dstStart = dst; dstEnd = dst + dstLen - 1; for (numChars = 0; src < srcEnd; numChars++) { if ((src > srcClose) && (!Tcl_UtfCharComplete(src, srcEnd - src))) { /* * If there is more string to follow, this will ensure that the * last UTF-8 character in the source buffer hasn't been cut off. */ result = TCL_CONVERT_MULTIBYTE; break; } len = TclUtfToUniChar(src, &ch); #if TCL_UTF_MAX > 3 /* * This prevents a crash condition. More evaluation is required * for full support of int Tcl_UniChar. [Bug 1004065] */ if (ch & 0xffff0000) { word = 0; } else #endif word = fromUnicode[(ch >> 8)][ch & 0xff]; if ((word == 0) && (ch != 0)) { if (flags & TCL_ENCODING_STOPONERROR) { result = TCL_CONVERT_UNKNOWN; break; } word = dataPtr->fallback; } if (prefixBytes[(word >> 8)] != 0) { if (dst + 1 > dstEnd) { result = TCL_CONVERT_NOSPACE; break; } dst[0] = (char) (word >> 8); dst[1] = (char) word; dst += 2; } else { if (dst > dstEnd) { result = TCL_CONVERT_NOSPACE; break; } dst[0] = (char) word; dst++; } src += len; } *srcReadPtr = src - srcStart; *dstWrotePtr = dst - dstStart; *dstCharsPtr = numChars; return result; } /* *--------------------------------------------------------------------------- * * TableFreeProc -- * * This procedure is invoked when an encoding is deleted. It deletes * the memory used by the TableEncodingData. * * Results: * None. * * Side effects: * Memory freed. * *--------------------------------------------------------------------------- */ static void TableFreeProc(clientData) ClientData clientData; /* TableEncodingData that specifies * encoding. */ { TableEncodingData *dataPtr; /* * Make sure we aren't freeing twice on shutdown. [Bug #219314] */ dataPtr = (TableEncodingData *) clientData; ckfree((char *) dataPtr->toUnicode); ckfree((char *) dataPtr->fromUnicode); ckfree((char *) dataPtr); } /* *------------------------------------------------------------------------- * * EscapeToUtfProc -- * * Convert from the encoding specified by the EscapeEncodingData into * UTF-8. * * Results: * Returns TCL_OK if conversion was successful. * * Side effects: * None. * *------------------------------------------------------------------------- */ static int EscapeToUtfProc(clientData, src, srcLen, flags, statePtr, dst, dstLen, srcReadPtr, dstWrotePtr, dstCharsPtr) ClientData clientData; /* EscapeEncodingData that specifies * encoding. */ CONST char *src; /* Source string in specified encoding. */ int srcLen; /* Source string length in bytes. */ int flags; /* Conversion control flags. */ Tcl_EncodingState *statePtr;/* Place for conversion routine to store * state information used during a piecewise * conversion. Contents of statePtr are * initialized and/or reset by conversion * routine under control of flags argument. */ char *dst; /* Output buffer in which converted string * is stored. */ int dstLen; /* The maximum length of output buffer in * bytes. */ int *srcReadPtr; /* Filled with the number of bytes from the * source string that were converted. This * may be less than the original source length * if there was a problem converting some * source characters. */ int *dstWrotePtr; /* Filled with the number of bytes that were * stored in the output buffer as a result of * the conversion. */ int *dstCharsPtr; /* Filled with the number of characters that * correspond to the bytes stored in the * output buffer. */ { EscapeEncodingData *dataPtr; char *prefixBytes, *tablePrefixBytes; unsigned short **tableToUnicode; Encoding *encodingPtr; int state, result, numChars; CONST char *srcStart, *srcEnd; char *dstStart, *dstEnd; result = TCL_OK; tablePrefixBytes = NULL; /* lint. */ tableToUnicode = NULL; /* lint. */ dataPtr = (EscapeEncodingData *) clientData; prefixBytes = dataPtr->prefixBytes; encodingPtr = NULL; srcStart = src; srcEnd = src + srcLen; dstStart = dst; dstEnd = dst + dstLen - TCL_UTF_MAX; state = (int) *statePtr; if (flags & TCL_ENCODING_START) { state = 0; } for (numChars = 0; src < srcEnd; ) { int byte, hi, lo, ch; if (dst > dstEnd) { result = TCL_CONVERT_NOSPACE; break; } byte = *((unsigned char *) src); if (prefixBytes[byte]) { unsigned int left, len, longest; int checked, i; EscapeSubTable *subTablePtr; /* * Saw the beginning of an escape sequence. */ left = srcEnd - src; len = dataPtr->initLen; longest = len; checked = 0; if (len <= left) { checked++; if ((len > 0) && (memcmp(src, dataPtr->init, len) == 0)) { /* * If we see initialization string, skip it, even if we're * not at the beginning of the buffer. */ src += len; continue; } } len = dataPtr->finalLen; if (len > longest) { longest = len; } if (len <= left) { checked++; if ((len > 0) && (memcmp(src, dataPtr->final, len) == 0)) { /* * If we see finalization string, skip it, even if we're * not at the end of the buffer. */ src += len; continue; } } subTablePtr = dataPtr->subTables; for (i = 0; i < dataPtr->numSubTables; i++) { len = subTablePtr->sequenceLen; if (len > longest) { longest = len; } if (len <= left) { checked++; if ((len > 0) && (memcmp(src, subTablePtr->sequence, len) == 0)) { state = i; encodingPtr = NULL; subTablePtr = NULL; src += len; break; } } subTablePtr++; } if (subTablePtr == NULL) { /* * A match was found, the escape sequence was consumed, and * the state was updated. */ continue; } /* * We have a split-up or unrecognized escape sequence. If we * checked all the sequences, then it's a syntax error, * otherwise we need more bytes to determine a match. */ if ((checked == dataPtr->numSubTables + 2) || (flags & TCL_ENCODING_END)) { if ((flags & TCL_ENCODING_STOPONERROR) == 0) { /* * Skip the unknown escape sequence. */ src += longest; continue; } result = TCL_CONVERT_SYNTAX; } else { result = TCL_CONVERT_MULTIBYTE; } break; } if (encodingPtr == NULL) { TableEncodingData *tableDataPtr; encodingPtr = GetTableEncoding(dataPtr, state); tableDataPtr = (TableEncodingData *) encodingPtr->clientData; tablePrefixBytes = tableDataPtr->prefixBytes; tableToUnicode = tableDataPtr->toUnicode; } if (tablePrefixBytes[byte]) { src++; if (src >= srcEnd) { src--; result = TCL_CONVERT_MULTIBYTE; break; } hi = byte; lo = *((unsigned char *) src); } else { hi = 0; lo = byte; } ch = tableToUnicode[hi][lo]; dst += Tcl_UniCharToUtf(ch, dst); src++; numChars++; } *statePtr = (Tcl_EncodingState) state; *srcReadPtr = src - srcStart; *dstWrotePtr = dst - dstStart; *dstCharsPtr = numChars; return result; } /* *------------------------------------------------------------------------- * * EscapeFromUtfProc -- * * Convert from UTF-8 into the encoding specified by the * EscapeEncodingData. * * Results: * Returns TCL_OK if conversion was successful. * * Side effects: * None. * *------------------------------------------------------------------------- */ static int EscapeFromUtfProc(clientData, src, srcLen, flags, statePtr, dst, dstLen, srcReadPtr, dstWrotePtr, dstCharsPtr) ClientData clientData; /* EscapeEncodingData that specifies * encoding. */ CONST char *src; /* Source string in UTF-8. */ int srcLen; /* Source string length in bytes. */ int flags; /* Conversion control flags. */ Tcl_EncodingState *statePtr;/* Place for conversion routine to store * state information used during a piecewise * conversion. Contents of statePtr are * initialized and/or reset by conversion * routine under control of flags argument. */ char *dst; /* Output buffer in which converted string * is stored. */ int dstLen; /* The maximum length of output buffer in * bytes. */ int *srcReadPtr; /* Filled with the number of bytes from the * source string that were converted. This * may be less than the original source length * if there was a problem converting some * source characters. */ int *dstWrotePtr; /* Filled with the number of bytes that were * stored in the output buffer as a result of * the conversion. */ int *dstCharsPtr; /* Filled with the number of characters that * correspond to the bytes stored in the * output buffer. */ { EscapeEncodingData *dataPtr; Encoding *encodingPtr; CONST char *srcStart, *srcEnd, *srcClose; char *dstStart, *dstEnd; int state, result, numChars; TableEncodingData *tableDataPtr; char *tablePrefixBytes; unsigned short **tableFromUnicode; result = TCL_OK; dataPtr = (EscapeEncodingData *) clientData; srcStart = src; srcEnd = src + srcLen; srcClose = srcEnd; if ((flags & TCL_ENCODING_END) == 0) { srcClose -= TCL_UTF_MAX; } dstStart = dst; dstEnd = dst + dstLen - 1; /* * RFC1468 states that the text starts in ASCII, and switches to Japanese * characters, and that the text must end in ASCII. [Patch #474358] */ if (flags & TCL_ENCODING_START) { state = 0; if ((dst + dataPtr->initLen) > dstEnd) { *srcReadPtr = 0; *dstWrotePtr = 0; return TCL_CONVERT_NOSPACE; } memcpy((VOID *) dst, (VOID *) dataPtr->init, (size_t) dataPtr->initLen); dst += dataPtr->initLen; } else { state = (int) *statePtr; } encodingPtr = GetTableEncoding(dataPtr, state); tableDataPtr = (TableEncodingData *) encodingPtr->clientData; tablePrefixBytes = tableDataPtr->prefixBytes; tableFromUnicode = tableDataPtr->fromUnicode; for (numChars = 0; src < srcEnd; numChars++) { unsigned int len; int word; Tcl_UniChar ch; if ((src > srcClose) && (!Tcl_UtfCharComplete(src, srcEnd - src))) { /* * If there is more string to follow, this will ensure that the * last UTF-8 character in the source buffer hasn't been cut off. */ result = TCL_CONVERT_MULTIBYTE; break; } len = TclUtfToUniChar(src, &ch); word = tableFromUnicode[(ch >> 8)][ch & 0xff]; if ((word == 0) && (ch != 0)) { int oldState; EscapeSubTable *subTablePtr; oldState = state; for (state = 0; state < dataPtr->numSubTables; state++) { encodingPtr = GetTableEncoding(dataPtr, state); tableDataPtr = (TableEncodingData *) encodingPtr->clientData; word = tableDataPtr->fromUnicode[(ch >> 8)][ch & 0xff]; if (word != 0) { break; } } if (word == 0) { state = oldState; if (flags & TCL_ENCODING_STOPONERROR) { result = TCL_CONVERT_UNKNOWN; break; } encodingPtr = GetTableEncoding(dataPtr, state); tableDataPtr = (TableEncodingData *) encodingPtr->clientData; word = tableDataPtr->fallback; } tablePrefixBytes = tableDataPtr->prefixBytes; tableFromUnicode = tableDataPtr->fromUnicode; /* * The state variable has the value of oldState when word is 0. * In this case, the escape sequense should not be copied to dst * because the current character set is not changed. */ if (state != oldState) { subTablePtr = &dataPtr->subTables[state]; if ((dst + subTablePtr->sequenceLen) > dstEnd) { /* * If there is no space to write the escape sequence, the * state variable must be changed to the value of oldState * variable because this escape sequence must be written * in the next conversion. */ state = oldState; result = TCL_CONVERT_NOSPACE; break; } memcpy((VOID *) dst, (VOID *) subTablePtr->sequence, (size_t) subTablePtr->sequenceLen); dst += subTablePtr->sequenceLen; } } if (tablePrefixBytes[(word >> 8)] != 0) { if (dst + 1 > dstEnd) { result = TCL_CONVERT_NOSPACE; break; } dst[0] = (char) (word >> 8); dst[1] = (char) word; dst += 2; } else { if (dst > dstEnd) { result = TCL_CONVERT_NOSPACE; break; } dst[0] = (char) word; dst++; } src += len; } if ((result == TCL_OK) && (flags & TCL_ENCODING_END)) { unsigned int len = dataPtr->subTables[0].sequenceLen; /* * [Bug 1516109]. * Certain encodings like iso2022-jp need to write * an escape sequence after all characters have * been converted. This logic checks that enough * room is available in the buffer for the escape bytes. * The TCL_ENCODING_END flag is cleared after a final * escape sequence has been added to the buffer so * that another call to this method does not attempt * to append escape bytes a second time. */ if ((dst + dataPtr->finalLen + (state?len:0)) > dstEnd) { result = TCL_CONVERT_NOSPACE; } else { if (state) { memcpy((VOID *) dst, (VOID *) dataPtr->subTables[0].sequence, (size_t) len); dst += len; } memcpy((VOID *) dst, (VOID *) dataPtr->final, (size_t) dataPtr->finalLen); dst += dataPtr->finalLen; state &= ~TCL_ENCODING_END; } } *statePtr = (Tcl_EncodingState) state; *srcReadPtr = src - srcStart; *dstWrotePtr = dst - dstStart; *dstCharsPtr = numChars; return result; } /* *--------------------------------------------------------------------------- * * EscapeFreeProc -- * * This procedure is invoked when an EscapeEncodingData encoding is * deleted. It deletes the memory used by the encoding. * * Results: * None. * * Side effects: * Memory freed. * *--------------------------------------------------------------------------- */ static void EscapeFreeProc(clientData) ClientData clientData; /* EscapeEncodingData that specifies encoding. */ { EscapeEncodingData *dataPtr; EscapeSubTable *subTablePtr; int i; dataPtr = (EscapeEncodingData *) clientData; if (dataPtr == NULL) { return; } /* * The subTables should be freed recursively in normal operation but not * during TclFinalizeEncodingSubsystem because they are also present as a * weak reference in the toplevel encodingTable (ie they don't have a +1 * refcount for this), and unpredictable nuking order could remove them * from under the following loop's feet [Bug 2891556]. * * The encodingsInitialized flag, being reset on entry to TFES, can serve * as a "not in finalization" test. */ if (encodingsInitialized) { subTablePtr = dataPtr->subTables; for (i = 0; i < dataPtr->numSubTables; i++) { FreeEncoding((Tcl_Encoding) subTablePtr->encodingPtr); subTablePtr++; } } ckfree((char *) dataPtr); } /* *--------------------------------------------------------------------------- * * GetTableEncoding -- * * Helper function for the EscapeEncodingData conversions. Gets the * encoding (of type TextEncodingData) that represents the specified * state. * * Results: * The return value is the encoding. * * Side effects: * If the encoding that represents the specified state has not * already been used by this EscapeEncoding, it will be loaded * and cached in the dataPtr. * *--------------------------------------------------------------------------- */ static Encoding * GetTableEncoding(dataPtr, state) EscapeEncodingData *dataPtr;/* Contains names of encodings. */ int state; /* Index in dataPtr of desired Encoding. */ { EscapeSubTable *subTablePtr; Encoding *encodingPtr; subTablePtr = &dataPtr->subTables[state]; encodingPtr = subTablePtr->encodingPtr; if (encodingPtr == NULL) { /* * Now that escape encodings load their sub-encodings first, and * fail to load if any sub-encodings are missing, this branch should * never happen. */ encodingPtr = (Encoding *) Tcl_GetEncoding(NULL, subTablePtr->name); if ((encodingPtr == NULL) || (encodingPtr->toUtfProc != TableToUtfProc)) { panic("EscapeToUtfProc: invalid sub table"); } subTablePtr->encodingPtr = encodingPtr; } return encodingPtr; } /* *--------------------------------------------------------------------------- * * unilen -- * * A helper function for the Tcl_ExternalToUtf functions. This * function is similar to strlen for double-byte characters: it * returns the number of bytes in a 0x0000 terminated string. * * Results: * As above. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static size_t unilen(src) CONST char *src; { unsigned short *p; p = (unsigned short *) src; while (*p != 0x0000) { p++; } return (char *) p - src; } /* *------------------------------------------------------------------------- * * TclFindEncodings -- * * Find and load the encoding file for this operating system. * Before this is called, Tcl makes assumptions about the * native string representation, but the true encoding is not * assured. * * Results: * Return result of TclpInitLibraryPath, which reports whether the * path is clean (0) or dirty (1) UTF. * * Side effects: * Varied, see the respective initialization routines. * *------------------------------------------------------------------------- */ static int TclFindEncodings(argv0) CONST char *argv0; /* Name of executable from argv[0] to main() * in native multi-byte encoding. */ { int mustCleanUtf = 0; if (encodingsInitialized == 0) { /* * Double check inside the mutex. There may be calls * back into this routine from some of the procedures below. */ TclpInitLock(); if (encodingsInitialized == 0) { char *native; Tcl_Obj *pathPtr; Tcl_DString libPath, buffer; /* * Have to set this bit here to avoid deadlock with the * routines below us that call into TclInitSubsystems. */ encodingsInitialized = 1; native = TclpFindExecutable(argv0); mustCleanUtf = TclpInitLibraryPath(native); /* * The library path was set in the TclpInitLibraryPath routine. * The string set is a dirty UTF string. To preserve the value * convert the UTF string back to native before setting the new * default encoding. */ pathPtr = TclGetLibraryPath(); if ((pathPtr != NULL) && mustCleanUtf) { Tcl_UtfToExternalDString(NULL, Tcl_GetString(pathPtr), -1, &libPath); } TclpSetInitialEncodings(); /* * Now convert the native string back to UTF. */ if ((pathPtr != NULL) && mustCleanUtf) { Tcl_ExternalToUtfDString(NULL, Tcl_DStringValue(&libPath), -1, &buffer); pathPtr = Tcl_NewStringObj(Tcl_DStringValue(&buffer), -1); TclSetLibraryPath(pathPtr); Tcl_DStringFree(&libPath); Tcl_DStringFree(&buffer); } } TclpInitUnlock(); } return mustCleanUtf; } tcl8.4.20/generic/tclLink.c0000644003604700454610000003375111737050674014110 0ustar dgp771div/* * tclLink.c -- * * This file implements linked variables (a C variable that is * tied to a Tcl variable). The idea of linked variables was * first suggested by Andreas Stolcke and this implementation is * based heavily on a prototype implementation provided by * him. * * Copyright (c) 1993 The Regents of the University of California. * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" /* * For each linked variable there is a data structure of the following * type, which describes the link and is the clientData for the trace * set on the Tcl variable. */ typedef struct Link { Tcl_Interp *interp; /* Interpreter containing Tcl variable. */ Tcl_Obj *varName; /* Name of variable (must be global). This * is needed during trace callbacks, since * the actual variable may be aliased at * that time via upvar. */ char *addr; /* Location of C variable. */ int type; /* Type of link (TCL_LINK_INT, etc.). */ union { int i; double d; Tcl_WideInt w; } lastValue; /* Last known value of C variable; used to * avoid string conversions. */ int flags; /* Miscellaneous one-bit values; see below * for definitions. */ } Link; /* * Definitions for flag bits: * LINK_READ_ONLY - 1 means errors should be generated if Tcl * script attempts to write variable. * LINK_BEING_UPDATED - 1 means that a call to Tcl_UpdateLinkedVar * is in progress for this variable, so * trace callbacks on the variable should * be ignored. */ #define LINK_READ_ONLY 1 #define LINK_BEING_UPDATED 2 /* * Forward references to procedures defined later in this file: */ static char * LinkTraceProc _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, CONST char *name1, CONST char *name2, int flags)); static Tcl_Obj * ObjValue _ANSI_ARGS_((Link *linkPtr)); /* *---------------------------------------------------------------------- * * Tcl_LinkVar -- * * Link a C variable to a Tcl variable so that changes to either * one causes the other to change. * * Results: * The return value is TCL_OK if everything went well or TCL_ERROR * if an error occurred (the interp's result is also set after * errors). * * Side effects: * The value at *addr is linked to the Tcl variable "varName", * using "type" to convert between string values for Tcl and * binary values for *addr. * *---------------------------------------------------------------------- */ int Tcl_LinkVar(interp, varName, addr, type) Tcl_Interp *interp; /* Interpreter in which varName exists. */ CONST char *varName; /* Name of a global variable in interp. */ char *addr; /* Address of a C variable to be linked * to varName. */ int type; /* Type of C variable: TCL_LINK_INT, etc. * Also may have TCL_LINK_READ_ONLY * OR'ed in. */ { Tcl_Obj *objPtr, *resPtr; Link *linkPtr; int code; linkPtr = (Link *) ckalloc(sizeof(Link)); linkPtr->interp = interp; linkPtr->varName = Tcl_NewStringObj(varName, -1); Tcl_IncrRefCount(linkPtr->varName); linkPtr->addr = addr; linkPtr->type = type & ~TCL_LINK_READ_ONLY; if (type & TCL_LINK_READ_ONLY) { linkPtr->flags = LINK_READ_ONLY; } else { linkPtr->flags = 0; } objPtr = ObjValue(linkPtr); Tcl_IncrRefCount(objPtr); resPtr = Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, objPtr, TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG); Tcl_DecrRefCount(objPtr); if (resPtr == NULL) { Tcl_DecrRefCount(linkPtr->varName); ckfree((char *) linkPtr); return TCL_ERROR; } code = Tcl_TraceVar(interp, varName, TCL_GLOBAL_ONLY|TCL_TRACE_READS |TCL_TRACE_WRITES|TCL_TRACE_UNSETS, LinkTraceProc, (ClientData) linkPtr); if (code != TCL_OK) { Tcl_DecrRefCount(linkPtr->varName); ckfree((char *) linkPtr); } return code; } /* *---------------------------------------------------------------------- * * Tcl_UnlinkVar -- * * Destroy the link between a Tcl variable and a C variable. * * Results: * None. * * Side effects: * If "varName" was previously linked to a C variable, the link * is broken to make the variable independent. If there was no * previous link for "varName" then nothing happens. * *---------------------------------------------------------------------- */ void Tcl_UnlinkVar(interp, varName) Tcl_Interp *interp; /* Interpreter containing variable to unlink. */ CONST char *varName; /* Global variable in interp to unlink. */ { Link *linkPtr; linkPtr = (Link *) Tcl_VarTraceInfo(interp, varName, TCL_GLOBAL_ONLY, LinkTraceProc, (ClientData) NULL); if (linkPtr == NULL) { return; } Tcl_UntraceVar(interp, varName, TCL_GLOBAL_ONLY|TCL_TRACE_READS|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, LinkTraceProc, (ClientData) linkPtr); Tcl_DecrRefCount(linkPtr->varName); ckfree((char *) linkPtr); } /* *---------------------------------------------------------------------- * * Tcl_UpdateLinkedVar -- * * This procedure is invoked after a linked variable has been * changed by C code. It updates the Tcl variable so that * traces on the variable will trigger. * * Results: * None. * * Side effects: * The Tcl variable "varName" is updated from its C value, * causing traces on the variable to trigger. * *---------------------------------------------------------------------- */ void Tcl_UpdateLinkedVar(interp, varName) Tcl_Interp *interp; /* Interpreter containing variable. */ CONST char *varName; /* Name of global variable that is linked. */ { Link *linkPtr; int savedFlag; Tcl_Obj *objPtr; linkPtr = (Link *) Tcl_VarTraceInfo(interp, varName, TCL_GLOBAL_ONLY, LinkTraceProc, (ClientData) NULL); if (linkPtr == NULL) { return; } savedFlag = linkPtr->flags & LINK_BEING_UPDATED; linkPtr->flags |= LINK_BEING_UPDATED; objPtr = ObjValue(linkPtr); Tcl_IncrRefCount(objPtr); Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, objPtr, TCL_GLOBAL_ONLY); Tcl_DecrRefCount(objPtr); /* * Callback may have unlinked the variable. [Bug 1740631] */ linkPtr = (Link *) Tcl_VarTraceInfo(interp, varName, TCL_GLOBAL_ONLY, LinkTraceProc, (ClientData) NULL); if (linkPtr != NULL) { linkPtr->flags = (linkPtr->flags & ~LINK_BEING_UPDATED) | savedFlag; } } /* *---------------------------------------------------------------------- * * LinkTraceProc -- * * This procedure is invoked when a linked Tcl variable is read, * written, or unset from Tcl. It's responsible for keeping the * C variable in sync with the Tcl variable. * * Results: * If all goes well, NULL is returned; otherwise an error message * is returned. * * Side effects: * The C variable may be updated to make it consistent with the * Tcl variable, or the Tcl variable may be overwritten to reject * a modification. * *---------------------------------------------------------------------- */ static char * LinkTraceProc(clientData, interp, name1, name2, flags) ClientData clientData; /* Contains information about the link. */ Tcl_Interp *interp; /* Interpreter containing Tcl variable. */ CONST char *name1; /* First part of variable name. */ CONST char *name2; /* Second part of variable name. */ int flags; /* Miscellaneous additional information. */ { Link *linkPtr = (Link *) clientData; int changed, valueLength; CONST char *value; char **pp, *result; Tcl_Obj *objPtr, *valueObj, *tmpPtr; /* * If the variable is being unset, then just re-create it (with a * trace) unless the whole interpreter is going away. */ if (flags & TCL_TRACE_UNSETS) { if (Tcl_InterpDeleted(interp)) { Tcl_DecrRefCount(linkPtr->varName); ckfree((char *) linkPtr); } else if (flags & TCL_TRACE_DESTROYED) { tmpPtr = ObjValue(linkPtr); Tcl_IncrRefCount(tmpPtr); Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, tmpPtr, TCL_GLOBAL_ONLY); Tcl_DecrRefCount(tmpPtr); Tcl_TraceVar(interp, Tcl_GetString(linkPtr->varName), TCL_GLOBAL_ONLY|TCL_TRACE_READS|TCL_TRACE_WRITES |TCL_TRACE_UNSETS, LinkTraceProc, (ClientData) linkPtr); } return NULL; } /* * If we were invoked because of a call to Tcl_UpdateLinkedVar, then * don't do anything at all. In particular, we don't want to get * upset that the variable is being modified, even if it is * supposed to be read-only. */ if (linkPtr->flags & LINK_BEING_UPDATED) { return NULL; } /* * For read accesses, update the Tcl variable if the C variable * has changed since the last time we updated the Tcl variable. */ if (flags & TCL_TRACE_READS) { switch (linkPtr->type) { case TCL_LINK_INT: case TCL_LINK_BOOLEAN: changed = *(int *)(linkPtr->addr) != linkPtr->lastValue.i; break; case TCL_LINK_DOUBLE: changed = *(double *)(linkPtr->addr) != linkPtr->lastValue.d; break; case TCL_LINK_WIDE_INT: changed = *(Tcl_WideInt *)(linkPtr->addr) != linkPtr->lastValue.w; break; case TCL_LINK_STRING: changed = 1; break; default: return "internal error: bad linked variable type"; } if (changed) { tmpPtr = ObjValue(linkPtr); Tcl_IncrRefCount(tmpPtr); Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, tmpPtr, TCL_GLOBAL_ONLY); Tcl_DecrRefCount(tmpPtr); } return NULL; } /* * For writes, first make sure that the variable is writable. Then * convert the Tcl value to C if possible. If the variable isn't * writable or can't be converted, then restore the varaible's old * value and return an error. Another tricky thing: we have to save * and restore the interpreter's result, since the variable access * could occur when the result has been partially set. */ if (linkPtr->flags & LINK_READ_ONLY) { tmpPtr = ObjValue(linkPtr); Tcl_IncrRefCount(tmpPtr); Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, tmpPtr, TCL_GLOBAL_ONLY); Tcl_DecrRefCount(tmpPtr); return "linked variable is read-only"; } valueObj = Tcl_ObjGetVar2(interp, linkPtr->varName,NULL, TCL_GLOBAL_ONLY); if (valueObj == NULL) { /* * This shouldn't ever happen. */ return "internal error: linked variable couldn't be read"; } objPtr = Tcl_GetObjResult(interp); Tcl_IncrRefCount(objPtr); Tcl_ResetResult(interp); result = NULL; switch (linkPtr->type) { case TCL_LINK_INT: if (Tcl_GetIntFromObj(interp, valueObj, &linkPtr->lastValue.i) != TCL_OK) { Tcl_SetObjResult(interp, objPtr); tmpPtr = ObjValue(linkPtr); Tcl_IncrRefCount(tmpPtr); Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, tmpPtr, TCL_GLOBAL_ONLY); Tcl_DecrRefCount(tmpPtr); result = "variable must have integer value"; goto end; } *(int *)(linkPtr->addr) = linkPtr->lastValue.i; break; case TCL_LINK_WIDE_INT: if (Tcl_GetWideIntFromObj(interp, valueObj, &linkPtr->lastValue.w) != TCL_OK) { Tcl_SetObjResult(interp, objPtr); tmpPtr = ObjValue(linkPtr); Tcl_IncrRefCount(tmpPtr); Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, tmpPtr, TCL_GLOBAL_ONLY); Tcl_DecrRefCount(tmpPtr); result = "variable must have integer value"; goto end; } *(Tcl_WideInt *)(linkPtr->addr) = linkPtr->lastValue.w; break; case TCL_LINK_DOUBLE: if (Tcl_GetDoubleFromObj(interp, valueObj, &linkPtr->lastValue.d) != TCL_OK) { Tcl_SetObjResult(interp, objPtr); tmpPtr = ObjValue(linkPtr); Tcl_IncrRefCount(tmpPtr); Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, tmpPtr, TCL_GLOBAL_ONLY); Tcl_DecrRefCount(tmpPtr); result = "variable must have real value"; goto end; } *(double *)(linkPtr->addr) = linkPtr->lastValue.d; break; case TCL_LINK_BOOLEAN: if (Tcl_GetBooleanFromObj(interp, valueObj, &linkPtr->lastValue.i) != TCL_OK) { Tcl_SetObjResult(interp, objPtr); tmpPtr = ObjValue(linkPtr); Tcl_IncrRefCount(tmpPtr); Tcl_ObjSetVar2(interp, linkPtr->varName, NULL, tmpPtr, TCL_GLOBAL_ONLY); Tcl_DecrRefCount(tmpPtr); result = "variable must have boolean value"; goto end; } *(int *)(linkPtr->addr) = linkPtr->lastValue.i; break; case TCL_LINK_STRING: value = Tcl_GetStringFromObj(valueObj, &valueLength); valueLength++; pp = (char **)(linkPtr->addr); if (*pp != NULL) { ckfree(*pp); } *pp = (char *) ckalloc((unsigned) valueLength); memcpy(*pp, value, (unsigned) valueLength); break; default: return "internal error: bad linked variable type"; } end: Tcl_DecrRefCount(objPtr); return result; } /* *---------------------------------------------------------------------- * * ObjValue -- * * Converts the value of a C variable to a Tcl_Obj* for use in a * Tcl variable to which it is linked. * * Results: * The return value is a pointer to a Tcl_Obj that represents * the value of the C variable given by linkPtr. * * Side effects: * None. * *---------------------------------------------------------------------- */ static Tcl_Obj * ObjValue(linkPtr) Link *linkPtr; /* Structure describing linked variable. */ { char *p; switch (linkPtr->type) { case TCL_LINK_INT: linkPtr->lastValue.i = *(int *)(linkPtr->addr); return Tcl_NewIntObj(linkPtr->lastValue.i); case TCL_LINK_WIDE_INT: linkPtr->lastValue.w = *(Tcl_WideInt *)(linkPtr->addr); return Tcl_NewWideIntObj(linkPtr->lastValue.w); case TCL_LINK_DOUBLE: linkPtr->lastValue.d = *(double *)(linkPtr->addr); return Tcl_NewDoubleObj(linkPtr->lastValue.d); case TCL_LINK_BOOLEAN: linkPtr->lastValue.i = *(int *)(linkPtr->addr); return Tcl_NewBooleanObj(linkPtr->lastValue.i != 0); case TCL_LINK_STRING: p = *(char **)(linkPtr->addr); if (p == NULL) { return Tcl_NewStringObj("NULL", 4); } return Tcl_NewStringObj(p, -1); /* * This code only gets executed if the link type is unknown * (shouldn't ever happen). */ default: return Tcl_NewStringObj("??", 2); } } tcl8.4.20/generic/tclStringObj.c0000644003604700454610000015773512052456744015124 0ustar dgp771div/* * tclStringObj.c -- * * This file contains procedures that implement string operations on Tcl * objects. Some string operations work with UTF strings and others * require Unicode format. Functions that require knowledge of the width * of each character, such as indexing, operate on Unicode data. * * A Unicode string is an internationalized string. Conceptually, a * Unicode string is an array of 16-bit quantities organized as a sequence * of properly formed UTF-8 characters. There is a one-to-one map between * Unicode and UTF characters. Because Unicode characters have a fixed * width, operations such as indexing operate on Unicode data. The String * object is optimized for the case where each UTF char in a string is * only one byte. In this case, we store the value of numChars, but we * don't store the Unicode data (unless Tcl_GetUnicode is explicitly * called). * * The String object type stores one or both formats. The default * behavior is to store UTF. Once Unicode is calculated by a function, it * is stored in the internal rep for future access (without an additional * O(n) cost). * * To allow many appends to be done to an object without constantly * reallocating the space for the string or Unicode representation, we * allocate double the space for the string or Unicode and use the * internal representation to keep track of how much space is used * vs. allocated. * * Copyright (c) 1995-1997 Sun Microsystems, Inc. * Copyright (c) 1999 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" /* * Prototypes for procedures defined later in this file: */ static void AppendUnicodeToUnicodeRep _ANSI_ARGS_(( Tcl_Obj *objPtr, CONST Tcl_UniChar *unicode, int appendNumChars)); static void AppendUnicodeToUtfRep _ANSI_ARGS_(( Tcl_Obj *objPtr, CONST Tcl_UniChar *unicode, int numChars)); static void AppendUtfToUnicodeRep _ANSI_ARGS_((Tcl_Obj *objPtr, CONST char *bytes, int numBytes)); static void AppendUtfToUtfRep _ANSI_ARGS_((Tcl_Obj *objPtr, CONST char *bytes, int numBytes)); static void DupStringInternalRep _ANSI_ARGS_((Tcl_Obj *objPtr, Tcl_Obj *copyPtr)); static void FillUnicodeRep _ANSI_ARGS_((Tcl_Obj *objPtr)); static void FreeStringInternalRep _ANSI_ARGS_((Tcl_Obj *objPtr)); static void GrowUnicodeBuffer _ANSI_ARGS_((Tcl_Obj *objPtr, int needed)); static int SetStringFromAny _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr)); static void SetUnicodeObj(Tcl_Obj *objPtr, CONST Tcl_UniChar *unicode, int numChars); static int UnicodeLength _ANSI_ARGS_((CONST Tcl_UniChar *unicode)); static void UpdateStringOfString _ANSI_ARGS_((Tcl_Obj *objPtr)); /* * The structure below defines the string Tcl object type by means of * procedures that can be invoked by generic object code. */ Tcl_ObjType tclStringType = { "string", /* name */ FreeStringInternalRep, /* freeIntRepPro */ DupStringInternalRep, /* dupIntRepProc */ UpdateStringOfString, /* updateStringProc */ SetStringFromAny /* setFromAnyProc */ }; /* * The following structure is the internal rep for a String object. * It keeps track of how much memory has been used and how much has been * allocated for the Unicode and UTF string to enable growing and * shrinking of the UTF and Unicode reps of the String object with fewer * mallocs. To optimize string length and indexing operations, this * structure also stores the number of characters (same of UTF and Unicode!) * once that value has been computed. */ typedef struct String { int numChars; /* The number of chars in the string. * -1 means this value has not been * calculated. >= 0 means that there is a * valid Unicode rep, or that the number * of UTF bytes == the number of chars. */ size_t allocated; /* The amount of space actually allocated * for the UTF string (minus 1 byte for * the termination char). */ size_t uallocated; /* The amount of space actually allocated * for the Unicode string (minus 2 bytes for * the termination char). */ int hasUnicode; /* Boolean determining whether the string * has a Unicode representation. */ Tcl_UniChar unicode[2]; /* The array of Unicode chars. The actual * size of this field depends on the * 'uallocated' field above. */ } String; #define STRING_MAXCHARS \ (1 + (int)(((size_t)UINT_MAX - sizeof(String))/sizeof(Tcl_UniChar))) #define STRING_UALLOC(numChars) \ ((numChars) * sizeof(Tcl_UniChar)) #define STRING_SIZE(ualloc) \ ((unsigned) ((ualloc) \ ? (sizeof(String) - sizeof(Tcl_UniChar) + (ualloc)) \ : sizeof(String))) #define stringCheckLimits(numChars) \ if ((unsigned)(numChars) > (unsigned)(STRING_MAXCHARS)) { \ Tcl_Panic("max length for a Tcl unicode value (%d chars) exceeded", \ STRING_MAXCHARS); \ } #define stringRealloc(ptr, numChars) \ (String *) ckrealloc((char *) ptr, \ (unsigned) STRING_SIZE(STRING_UALLOC(numChars)) ) #define stringAttemptRealloc(ptr, numChars) \ (String *) attemptckrealloc((char *) ptr, \ (unsigned) STRING_SIZE(STRING_UALLOC(numChars)) ) #define GET_STRING(objPtr) \ ((String *) (objPtr)->internalRep.otherValuePtr) #define SET_STRING(objPtr, stringPtr) \ (objPtr)->internalRep.otherValuePtr = (VOID *) (stringPtr) /* * TCL STRING GROWTH ALGORITHM * * When growing strings (during an append, for example), the following growth * algorithm is used: * * Attempt to allocate 2 * (originalLength + appendLength) * On failure: * attempt to allocate originalLength + 2*appendLength + * TCL_GROWTH_MIN_ALLOC * * This algorithm allows very good performance, as it rapidly increases the * memory allocated for a given string, which minimizes the number of * reallocations that must be performed. However, using only the doubling * algorithm can lead to a significant waste of memory. In particular, it * may fail even when there is sufficient memory available to complete the * append request (but there is not 2 * totalLength memory available). So when * the doubling fails (because there is not enough memory available), the * algorithm requests a smaller amount of memory, which is still enough to * cover the request, but which hopefully will be less than the total available * memory. * * The addition of TCL_GROWTH_MIN_ALLOC allows for efficient handling * of very small appends. Without this extra slush factor, a sequence * of several small appends would cause several memory allocations. * As long as TCL_GROWTH_MIN_ALLOC is a reasonable size, we can * avoid that behavior. * * The growth algorithm can be tuned by adjusting the following parameters: * * TCL_GROWTH_MIN_ALLOC Additional space, in bytes, to allocate when * the double allocation has failed. * Default is 1024 (1 kilobyte). */ #ifndef TCL_GROWTH_MIN_ALLOC #define TCL_GROWTH_MIN_ALLOC 1024 #endif static void GrowUnicodeBuffer( Tcl_Obj *objPtr, int needed) { /* Pre-conditions: * objPtr->typePtr == &tclStringType * STRING_UALLOC(needed) > stringPtr->uallocated * needed < STRING_MAXCHARS */ String *ptr = NULL, *stringPtr = GET_STRING(objPtr); int attempt; if (stringPtr->uallocated > 0) { /* Subsequent appends - apply the growth algorithm. */ attempt = 2 * needed; if (attempt >= 0 && attempt <= STRING_MAXCHARS) { ptr = stringAttemptRealloc(stringPtr, attempt); } if (ptr == NULL) { /* * Take care computing the amount of modest growth to avoid * overflow into invalid argument values for attempt. */ unsigned int limit = STRING_MAXCHARS - needed; unsigned int extra = needed - stringPtr->numChars + TCL_GROWTH_MIN_ALLOC/sizeof(Tcl_UniChar); int growth = (int) ((extra > limit) ? limit : extra); attempt = needed + growth; ptr = stringAttemptRealloc(stringPtr, attempt); } } if (ptr == NULL) { /* First allocation - just big enough; or last chance fallback. */ attempt = needed; ptr = stringRealloc(stringPtr, attempt); } stringPtr = ptr; stringPtr->uallocated = STRING_UALLOC(attempt); SET_STRING(objPtr, stringPtr); } /* *---------------------------------------------------------------------- * * Tcl_NewStringObj -- * * This procedure is normally called when not debugging: i.e., when * TCL_MEM_DEBUG is not defined. It creates a new string object and * initializes it from the byte pointer and length arguments. * * When TCL_MEM_DEBUG is defined, this procedure just returns the * result of calling the debugging version Tcl_DbNewStringObj. * * Results: * A newly created string object is returned that has ref count zero. * * Side effects: * The new object's internal string representation will be set to a * copy of the length bytes starting at "bytes". If "length" is * negative, use bytes up to the first NULL byte; i.e., assume "bytes" * points to a C-style NULL-terminated string. The object's type is set * to NULL. An extra NULL is added to the end of the new object's byte * array. * *---------------------------------------------------------------------- */ #ifdef TCL_MEM_DEBUG #undef Tcl_NewStringObj Tcl_Obj * Tcl_NewStringObj(bytes, length) CONST char *bytes; /* Points to the first of the length bytes * used to initialize the new object. */ int length; /* The number of bytes to copy from "bytes" * when initializing the new object. If * negative, use bytes up to the first * NULL byte. */ { return Tcl_DbNewStringObj(bytes, length, "unknown", 0); } #else /* if not TCL_MEM_DEBUG */ Tcl_Obj * Tcl_NewStringObj(bytes, length) CONST char *bytes; /* Points to the first of the length bytes * used to initialize the new object. */ int length; /* The number of bytes to copy from "bytes" * when initializing the new object. If * negative, use bytes up to the first * NULL byte. */ { register Tcl_Obj *objPtr; if (length < 0) { length = (bytes? strlen(bytes) : 0); } TclNewObj(objPtr); TclInitStringRep(objPtr, bytes, length); return objPtr; } #endif /* TCL_MEM_DEBUG */ /* *---------------------------------------------------------------------- * * Tcl_DbNewStringObj -- * * This procedure is normally called when debugging: i.e., when * TCL_MEM_DEBUG is defined. It creates new string objects. It is the * same as the Tcl_NewStringObj procedure above except that it calls * Tcl_DbCkalloc directly with the file name and line number from its * caller. This simplifies debugging since then the [memory active] * command will report the correct file name and line number when * reporting objects that haven't been freed. * * When TCL_MEM_DEBUG is not defined, this procedure just returns the * result of calling Tcl_NewStringObj. * * Results: * A newly created string object is returned that has ref count zero. * * Side effects: * The new object's internal string representation will be set to a * copy of the length bytes starting at "bytes". If "length" is * negative, use bytes up to the first NULL byte; i.e., assume "bytes" * points to a C-style NULL-terminated string. The object's type is set * to NULL. An extra NULL is added to the end of the new object's byte * array. * *---------------------------------------------------------------------- */ #ifdef TCL_MEM_DEBUG Tcl_Obj * Tcl_DbNewStringObj(bytes, length, file, line) CONST char *bytes; /* Points to the first of the length bytes * used to initialize the new object. */ int length; /* The number of bytes to copy from "bytes" * when initializing the new object. If * negative, use bytes up to the first * NULL byte. */ CONST char *file; /* The name of the source file calling this * procedure; used for debugging. */ int line; /* Line number in the source file; used * for debugging. */ { register Tcl_Obj *objPtr; if (length < 0) { length = (bytes? strlen(bytes) : 0); } TclDbNewObj(objPtr, file, line); TclInitStringRep(objPtr, bytes, length); return objPtr; } #else /* if not TCL_MEM_DEBUG */ Tcl_Obj * Tcl_DbNewStringObj(bytes, length, file, line) CONST char *bytes; /* Points to the first of the length bytes * used to initialize the new object. */ register int length; /* The number of bytes to copy from "bytes" * when initializing the new object. If * negative, use bytes up to the first * NULL byte. */ CONST char *file; /* The name of the source file calling this * procedure; used for debugging. */ int line; /* Line number in the source file; used * for debugging. */ { return Tcl_NewStringObj(bytes, length); } #endif /* TCL_MEM_DEBUG */ /* *--------------------------------------------------------------------------- * * Tcl_NewUnicodeObj -- * * This procedure is creates a new String object and initializes * it from the given Unicode String. If the Utf String is the same size * as the Unicode string, don't duplicate the data. * * Results: * The newly created object is returned. This object will have no * initial string representation. The returned object has a ref count * of 0. * * Side effects: * Memory allocated for new object and copy of Unicode argument. * *--------------------------------------------------------------------------- */ Tcl_Obj * Tcl_NewUnicodeObj(unicode, numChars) CONST Tcl_UniChar *unicode; /* The unicode string used to initialize * the new object. */ int numChars; /* Number of characters in the unicode * string. */ { Tcl_Obj *objPtr; TclNewObj(objPtr); SetUnicodeObj(objPtr, unicode, numChars); return objPtr; } /* *---------------------------------------------------------------------- * * Tcl_GetCharLength -- * * Get the length of the Unicode string from the Tcl object. * * Results: * Pointer to unicode string representing the unicode object. * * Side effects: * Frees old internal rep. Allocates memory for new "String" * internal rep. * *---------------------------------------------------------------------- */ int Tcl_GetCharLength(objPtr) Tcl_Obj *objPtr; /* The String object to get the num chars of. */ { String *stringPtr; SetStringFromAny(NULL, objPtr); stringPtr = GET_STRING(objPtr); /* * If numChars is unknown, then calculate the number of characaters * while populating the Unicode string. */ if (stringPtr->numChars == -1) { register int i = objPtr->length; register unsigned char *str = (unsigned char *) objPtr->bytes; /* * This is a speed sensitive function, so run specially over the * string to count continuous ascii characters before resorting * to the Tcl_NumUtfChars call. This is a long form of: stringPtr->numChars = Tcl_NumUtfChars(objPtr->bytes, objPtr->length); */ while (i && (*str < 0xC0)) { i--; str++; } stringPtr->numChars = objPtr->length - i; if (i) { stringPtr->numChars += Tcl_NumUtfChars(objPtr->bytes + (objPtr->length - i), i); } if (stringPtr->numChars == objPtr->length) { /* * Since we've just calculated the number of chars, and all * UTF chars are 1-byte long, we don't need to store the * unicode string. */ stringPtr->hasUnicode = 0; } else { /* * Since we've just calucalated the number of chars, and not * all UTF chars are 1-byte long, go ahead and populate the * unicode string. */ FillUnicodeRep(objPtr); /* * We need to fetch the pointer again because we have just * reallocated the structure to make room for the Unicode data. */ stringPtr = GET_STRING(objPtr); } } return stringPtr->numChars; } /* *---------------------------------------------------------------------- * * Tcl_GetUniChar -- * * Get the index'th Unicode character from the String object. The * index is assumed to be in the appropriate range. * * Results: * Returns the index'th Unicode character in the Object. * * Side effects: * Fills unichar with the index'th Unicode character. * *---------------------------------------------------------------------- */ Tcl_UniChar Tcl_GetUniChar(objPtr, index) Tcl_Obj *objPtr; /* The object to get the Unicode charater from. */ int index; /* Get the index'th Unicode character. */ { Tcl_UniChar unichar; String *stringPtr; SetStringFromAny(NULL, objPtr); stringPtr = GET_STRING(objPtr); if (stringPtr->numChars == -1) { /* * We haven't yet calculated the length, so we don't have the * Unicode str. We need to know the number of chars before we * can do indexing. */ Tcl_GetCharLength(objPtr); /* * We need to fetch the pointer again because we may have just * reallocated the structure. */ stringPtr = GET_STRING(objPtr); } if (stringPtr->hasUnicode == 0) { /* * All of the characters in the Utf string are 1 byte chars, * so we don't store the unicode char. We get the Utf string * and convert the index'th byte to a Unicode character. */ unichar = (Tcl_UniChar) objPtr->bytes[index]; } else { unichar = stringPtr->unicode[index]; } return unichar; } /* *---------------------------------------------------------------------- * * Tcl_GetUnicode -- * * Get the Unicode form of the String object. If * the object is not already a String object, it will be converted * to one. If the String object does not have a Unicode rep, then * one is create from the UTF string format. * * Results: * Returns a pointer to the object's internal Unicode string. * * Side effects: * Converts the object to have the String internal rep. * *---------------------------------------------------------------------- */ Tcl_UniChar * Tcl_GetUnicode(objPtr) Tcl_Obj *objPtr; /* The object to find the unicode string for. */ { String *stringPtr; SetStringFromAny(NULL, objPtr); stringPtr = GET_STRING(objPtr); if ((stringPtr->numChars == -1) || (stringPtr->hasUnicode == 0)) { /* * We haven't yet calculated the length, or all of the characters * in the Utf string are 1 byte chars (so we didn't store the * unicode str). Since this function must return a unicode string, * and one has not yet been stored, force the Unicode to be * calculated and stored now. */ FillUnicodeRep(objPtr); /* * We need to fetch the pointer again because we have just * reallocated the structure to make room for the Unicode data. */ stringPtr = GET_STRING(objPtr); } return stringPtr->unicode; } /* *---------------------------------------------------------------------- * * Tcl_GetUnicodeFromObj -- * * Get the Unicode form of the String object with length. If * the object is not already a String object, it will be converted * to one. If the String object does not have a Unicode rep, then * one is create from the UTF string format. * * Results: * Returns a pointer to the object's internal Unicode string. * * Side effects: * Converts the object to have the String internal rep. * *---------------------------------------------------------------------- */ Tcl_UniChar * Tcl_GetUnicodeFromObj(objPtr, lengthPtr) Tcl_Obj *objPtr; /* The object to find the unicode string for. */ int *lengthPtr; /* If non-NULL, the location where the * string rep's unichar length should be * stored. If NULL, no length is stored. */ { String *stringPtr; SetStringFromAny(NULL, objPtr); stringPtr = GET_STRING(objPtr); if ((stringPtr->numChars == -1) || (stringPtr->hasUnicode == 0)) { /* * We haven't yet calculated the length, or all of the characters * in the Utf string are 1 byte chars (so we didn't store the * unicode str). Since this function must return a unicode string, * and one has not yet been stored, force the Unicode to be * calculated and stored now. */ FillUnicodeRep(objPtr); /* * We need to fetch the pointer again because we have just * reallocated the structure to make room for the Unicode data. */ stringPtr = GET_STRING(objPtr); } if (lengthPtr != NULL) { *lengthPtr = stringPtr->numChars; } return stringPtr->unicode; } /* *---------------------------------------------------------------------- * * Tcl_GetRange -- * * Create a Tcl Object that contains the chars between first and last * of the object indicated by "objPtr". If the object is not already * a String object, convert it to one. The first and last indices * are assumed to be in the appropriate range. * * Results: * Returns a new Tcl Object of the String type. * * Side effects: * Changes the internal rep of "objPtr" to the String type. * *---------------------------------------------------------------------- */ Tcl_Obj * Tcl_GetRange(objPtr, first, last) Tcl_Obj *objPtr; /* The Tcl object to find the range of. */ int first; /* First index of the range. */ int last; /* Last index of the range. */ { Tcl_Obj *newObjPtr; /* The Tcl object to find the range of. */ String *stringPtr; SetStringFromAny(NULL, objPtr); stringPtr = GET_STRING(objPtr); if (stringPtr->numChars == -1) { /* * We haven't yet calculated the length, so we don't have the * Unicode str. We need to know the number of chars before we * can do indexing. */ Tcl_GetCharLength(objPtr); /* * We need to fetch the pointer again because we may have just * reallocated the structure. */ stringPtr = GET_STRING(objPtr); } if (objPtr->bytes && stringPtr->numChars == objPtr->length) { char *str = Tcl_GetString(objPtr); /* * All of the characters in the Utf string are 1 byte chars, * so we don't store the unicode char. Create a new string * object containing the specified range of chars. */ newObjPtr = Tcl_NewStringObj(&str[first], last-first+1); /* * Since we know the new string only has 1-byte chars, we * can set it's numChars field. */ SetStringFromAny(NULL, newObjPtr); stringPtr = GET_STRING(newObjPtr); stringPtr->numChars = last-first+1; } else { newObjPtr = Tcl_NewUnicodeObj(stringPtr->unicode + first, last-first+1); } return newObjPtr; } /* *---------------------------------------------------------------------- * * Tcl_SetStringObj -- * * Modify an object to hold a string that is a copy of the bytes * indicated by the byte pointer and length arguments. * * Results: * None. * * Side effects: * The object's string representation will be set to a copy of * the "length" bytes starting at "bytes". If "length" is negative, use * bytes up to the first NULL byte; i.e., assume "bytes" points to a * C-style NULL-terminated string. The object's old string and internal * representations are freed and the object's type is set NULL. * *---------------------------------------------------------------------- */ void Tcl_SetStringObj(objPtr, bytes, length) register Tcl_Obj *objPtr; /* Object whose internal rep to init. */ CONST char *bytes; /* Points to the first of the length bytes * used to initialize the object. */ register int length; /* The number of bytes to copy from "bytes" * when initializing the object. If * negative, use bytes up to the first * NULL byte.*/ { register Tcl_ObjType *oldTypePtr = objPtr->typePtr; if (Tcl_IsShared(objPtr)) { panic("Tcl_SetStringObj called with shared object"); } /* * Set the type to NULL and free any internal rep for the old type. */ if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) { oldTypePtr->freeIntRepProc(objPtr); } objPtr->typePtr = NULL; /* * Free any old string rep, then set the string rep to a copy of * the length bytes starting at "bytes". */ Tcl_InvalidateStringRep(objPtr); if (length < 0) { length = (bytes? strlen(bytes) : 0); } TclInitStringRep(objPtr, bytes, length); } /* *---------------------------------------------------------------------- * * Tcl_SetObjLength -- * * This procedure changes the length of the string representation * of an object. * * Results: * None. * * Side effects: * If the size of objPtr's string representation is greater than * length, then it is reduced to length and a new terminating null * byte is stored in the strength. If the length of the string * representation is greater than length, the storage space is * reallocated to the given length; a null byte is stored at the * end, but other bytes past the end of the original string * representation are undefined. The object's internal * representation is changed to "expendable string". * *---------------------------------------------------------------------- */ void Tcl_SetObjLength(objPtr, length) register Tcl_Obj *objPtr; /* Pointer to object. This object must * not currently be shared. */ register int length; /* Number of bytes desired for string * representation of object, not including * terminating null byte. */ { String *stringPtr; if (length < 0) { /* * Setting to a negative length is nonsense. This is probably the * result of overflowing the signed integer range. */ Tcl_Panic("Tcl_SetObjLength: negative length requested: " "%d (integer overflow?)", length); } if (Tcl_IsShared(objPtr)) { panic("Tcl_SetObjLength called with shared object"); } SetStringFromAny(NULL, objPtr); stringPtr = GET_STRING(objPtr); /* Check that we're not extending a pure unicode string */ if ((size_t)length > stringPtr->allocated && (objPtr->bytes != NULL || stringPtr->hasUnicode == 0)) { char *new; /* * Not enough space in current string. Reallocate the string * space and free the old string. */ if (objPtr->bytes != tclEmptyStringRep && objPtr->bytes != NULL) { new = (char *) ckrealloc((char *)objPtr->bytes, (unsigned)(length+1)); } else { new = (char *) ckalloc((unsigned) (length+1)); if (objPtr->bytes != NULL && objPtr->length != 0) { memcpy((VOID *) new, (VOID *) objPtr->bytes, (size_t) objPtr->length); Tcl_InvalidateStringRep(objPtr); } } objPtr->bytes = new; stringPtr->allocated = length; /* Invalidate the unicode data. */ stringPtr->hasUnicode = 0; } if (objPtr->bytes != NULL) { objPtr->length = length; if (objPtr->bytes != tclEmptyStringRep) { /* Ensure the string is NULL-terminated */ objPtr->bytes[length] = 0; } /* Invalidate the unicode data. */ stringPtr->numChars = -1; stringPtr->hasUnicode = 0; } else { /* Changing length of pure unicode string */ size_t uallocated = STRING_UALLOC(length); stringCheckLimits(length); if (uallocated > stringPtr->uallocated) { stringPtr = stringRealloc(stringPtr, length); SET_STRING(objPtr, stringPtr); stringPtr->uallocated = uallocated; } stringPtr->numChars = length; stringPtr->hasUnicode = (length > 0); /* Ensure the string is NULL-terminated */ stringPtr->unicode[length] = 0; stringPtr->allocated = 0; objPtr->length = 0; } } /* *---------------------------------------------------------------------- * * Tcl_AttemptSetObjLength -- * * This procedure changes the length of the string representation * of an object. It uses the attempt* (non-panic'ing) memory allocators. * * Results: * 1 if the requested memory was allocated, 0 otherwise. * * Side effects: * If the size of objPtr's string representation is greater than * length, then it is reduced to length and a new terminating null * byte is stored in the strength. If the length of the string * representation is greater than length, the storage space is * reallocated to the given length; a null byte is stored at the * end, but other bytes past the end of the original string * representation are undefined. The object's internal * representation is changed to "expendable string". * *---------------------------------------------------------------------- */ int Tcl_AttemptSetObjLength(objPtr, length) register Tcl_Obj *objPtr; /* Pointer to object. This object must * not currently be shared. */ register int length; /* Number of bytes desired for string * representation of object, not including * terminating null byte. */ { String *stringPtr; if (length < 0) { /* * Setting to a negative length is nonsense. This is probably the * result of overflowing the signed integer range. */ return 0; } if (Tcl_IsShared(objPtr)) { panic("Tcl_AttemptSetObjLength called with shared object"); } SetStringFromAny(NULL, objPtr); stringPtr = GET_STRING(objPtr); /* Check that we're not extending a pure unicode string */ if (length > (int) stringPtr->allocated && (objPtr->bytes != NULL || stringPtr->hasUnicode == 0)) { char *new; /* * Not enough space in current string. Reallocate the string * space and free the old string. */ if (objPtr->bytes != tclEmptyStringRep && objPtr->bytes != NULL) { new = (char *) attemptckrealloc((char *)objPtr->bytes, (unsigned)(length+1)); if (new == NULL) { return 0; } } else { new = (char *) attemptckalloc((unsigned) (length+1)); if (new == NULL) { return 0; } if (objPtr->bytes != NULL && objPtr->length != 0) { memcpy((VOID *) new, (VOID *) objPtr->bytes, (size_t) objPtr->length); Tcl_InvalidateStringRep(objPtr); } } objPtr->bytes = new; stringPtr->allocated = length; /* Invalidate the unicode data. */ stringPtr->hasUnicode = 0; } if (objPtr->bytes != NULL) { objPtr->length = length; if (objPtr->bytes != tclEmptyStringRep) { /* Ensure the string is NULL-terminated */ objPtr->bytes[length] = 0; } /* Invalidate the unicode data. */ stringPtr->numChars = -1; stringPtr->hasUnicode = 0; } else { /* Changing length of pure unicode string */ size_t uallocated = STRING_UALLOC(length); if (length > STRING_MAXCHARS) { return 0; } if (uallocated > stringPtr->uallocated) { stringPtr = stringAttemptRealloc(stringPtr, length); if (stringPtr == NULL) { return 0; } SET_STRING(objPtr, stringPtr); stringPtr->uallocated = uallocated; } stringPtr->numChars = length; stringPtr->hasUnicode = (length > 0); /* Ensure the string is NULL-terminated */ stringPtr->unicode[length] = 0; stringPtr->allocated = 0; objPtr->length = 0; } return 1; } /* *--------------------------------------------------------------------------- * * Tcl_SetUnicodeObj -- * * Modify an object to hold the Unicode string indicated by "unicode". * * Results: * None. * * Side effects: * Memory allocated for new "String" internal rep. * *--------------------------------------------------------------------------- */ void Tcl_SetUnicodeObj(objPtr, unicode, numChars) Tcl_Obj *objPtr; /* The object to set the string of. */ CONST Tcl_UniChar *unicode; /* The unicode string used to initialize * the object. */ int numChars; /* Number of characters in the unicode * string. */ { Tcl_ObjType *typePtr = objPtr->typePtr; if (Tcl_IsShared(objPtr)) { Tcl_Panic("%s called with shared object", "Tcl_SetUnicodeObj"); } if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) { typePtr->freeIntRepProc(objPtr); } SetUnicodeObj(objPtr, unicode, numChars); } static int UnicodeLength( CONST Tcl_UniChar *unicode) { int numChars = 0; if (unicode) { while (numChars >= 0 && unicode[numChars] != 0) { numChars++; } } stringCheckLimits(numChars); return numChars; } static void SetUnicodeObj(objPtr, unicode, numChars) Tcl_Obj *objPtr; /* The object to set the string of. */ CONST Tcl_UniChar *unicode; /* The unicode string used to initialize * the object. */ int numChars; /* Number of characters in the unicode * string. */ { String *stringPtr; size_t uallocated; if (numChars < 0) { numChars = UnicodeLength(unicode); } /* * Allocate enough space for the String structure + Unicode string. */ stringCheckLimits(numChars); uallocated = STRING_UALLOC(numChars); stringPtr = (String *) ckalloc(STRING_SIZE(uallocated)); stringPtr->numChars = numChars; stringPtr->uallocated = uallocated; stringPtr->hasUnicode = (numChars > 0); stringPtr->allocated = 0; memcpy((VOID *) stringPtr->unicode, (VOID *) unicode, uallocated); stringPtr->unicode[numChars] = 0; Tcl_InvalidateStringRep(objPtr); objPtr->typePtr = &tclStringType; SET_STRING(objPtr, stringPtr); } /* *---------------------------------------------------------------------- * * Tcl_AppendToObj -- * * This procedure appends a sequence of bytes to an object. * * Results: * None. * * Side effects: * The bytes at *bytes are appended to the string representation * of objPtr. * *---------------------------------------------------------------------- */ void Tcl_AppendToObj(objPtr, bytes, length) register Tcl_Obj *objPtr; /* Points to the object to append to. */ CONST char *bytes; /* Points to the bytes to append to the * object. */ register int length; /* The number of bytes to append from * "bytes". If < 0, then append all bytes * up to NULL byte. */ { String *stringPtr; if (Tcl_IsShared(objPtr)) { panic("Tcl_AppendToObj called with shared object"); } SetStringFromAny(NULL, objPtr); if (length < 0) { length = (bytes ? strlen(bytes) : 0); } if (length == 0) { return; } /* * If objPtr has a valid Unicode rep, then append the Unicode * conversion of "bytes" to the objPtr's Unicode rep, otherwise * append "bytes" to objPtr's string rep. */ stringPtr = GET_STRING(objPtr); if (stringPtr->hasUnicode != 0) { AppendUtfToUnicodeRep(objPtr, bytes, length); stringPtr = GET_STRING(objPtr); } else { AppendUtfToUtfRep(objPtr, bytes, length); } } /* *---------------------------------------------------------------------- * * Tcl_AppendUnicodeToObj -- * * This procedure appends a Unicode string to an object in the * most efficient manner possible. Length must be >= 0. * * Results: * None. * * Side effects: * Invalidates the string rep and creates a new Unicode string. * *---------------------------------------------------------------------- */ void Tcl_AppendUnicodeToObj(objPtr, unicode, length) register Tcl_Obj *objPtr; /* Points to the object to append to. */ CONST Tcl_UniChar *unicode; /* The unicode string to append to the * object. */ int length; /* Number of chars in "unicode". */ { String *stringPtr; if (Tcl_IsShared(objPtr)) { panic("Tcl_AppendUnicodeToObj called with shared object"); } if (length == 0) { return; } SetStringFromAny(NULL, objPtr); stringPtr = GET_STRING(objPtr); /* * If objPtr has a valid Unicode rep, then append the "unicode" * to the objPtr's Unicode rep, otherwise the UTF conversion of * "unicode" to objPtr's string rep. */ if (stringPtr->hasUnicode != 0) { AppendUnicodeToUnicodeRep(objPtr, unicode, length); } else { AppendUnicodeToUtfRep(objPtr, unicode, length); } } /* *---------------------------------------------------------------------- * * Tcl_AppendObjToObj -- * * This procedure appends the string rep of one object to another. * "objPtr" cannot be a shared object. * * Results: * None. * * Side effects: * The string rep of appendObjPtr is appended to the string * representation of objPtr. * *---------------------------------------------------------------------- */ void Tcl_AppendObjToObj(objPtr, appendObjPtr) Tcl_Obj *objPtr; /* Points to the object to append to. */ Tcl_Obj *appendObjPtr; /* Object to append. */ { String *stringPtr; int length, numChars, allOneByteChars; char *bytes; SetStringFromAny(NULL, objPtr); /* * If objPtr has a valid Unicode rep, then get a Unicode string * from appendObjPtr and append it. */ stringPtr = GET_STRING(objPtr); if (stringPtr->hasUnicode != 0) { /* * If appendObjPtr is not of the "String" type, don't convert it. */ if (appendObjPtr->typePtr == &tclStringType) { stringPtr = GET_STRING(appendObjPtr); if ((stringPtr->numChars == -1) || (stringPtr->hasUnicode == 0)) { /* * If appendObjPtr is a string obj with no valid Unicode * rep, then fill its unicode rep. */ FillUnicodeRep(appendObjPtr); stringPtr = GET_STRING(appendObjPtr); } AppendUnicodeToUnicodeRep(objPtr, stringPtr->unicode, stringPtr->numChars); } else { bytes = Tcl_GetStringFromObj(appendObjPtr, &length); AppendUtfToUnicodeRep(objPtr, bytes, length); } return; } /* * Append to objPtr's UTF string rep. If we know the number of * characters in both objects before appending, then set the combined * number of characters in the final (appended-to) object. */ bytes = Tcl_GetStringFromObj(appendObjPtr, &length); allOneByteChars = 0; numChars = stringPtr->numChars; if ((numChars >= 0) && (appendObjPtr->typePtr == &tclStringType)) { stringPtr = GET_STRING(appendObjPtr); if ((stringPtr->numChars >= 0) && (stringPtr->numChars == length)) { numChars += stringPtr->numChars; allOneByteChars = 1; } } AppendUtfToUtfRep(objPtr, bytes, length); if (allOneByteChars) { stringPtr = GET_STRING(objPtr); stringPtr->numChars = numChars; } } /* *---------------------------------------------------------------------- * * AppendUnicodeToUnicodeRep -- * * This procedure appends the contents of "unicode" to the Unicode * rep of "objPtr". objPtr must already have a valid Unicode rep. * * Results: * None. * * Side effects: * objPtr's internal rep is reallocated. * *---------------------------------------------------------------------- */ static void AppendUnicodeToUnicodeRep(objPtr, unicode, appendNumChars) Tcl_Obj *objPtr; /* Points to the object to append to. */ CONST Tcl_UniChar *unicode; /* String to append. */ int appendNumChars; /* Number of chars of "unicode" to append. */ { String *stringPtr; size_t numChars; if (appendNumChars < 0) { appendNumChars = UnicodeLength(unicode); } if (appendNumChars == 0) { return; } SetStringFromAny(NULL, objPtr); stringPtr = GET_STRING(objPtr); /* * If not enough space has been allocated for the unicode rep, * reallocate the internal rep object with additional space. First * try to double the required allocation; if that fails, try a more * modest increase. See the "TCL STRING GROWTH ALGORITHM" comment at * the top of this file for an explanation of this growth algorithm. */ numChars = stringPtr->numChars + appendNumChars; stringCheckLimits(numChars); if (STRING_UALLOC(numChars) > stringPtr->uallocated) { /* * Protect against case where unicode points into the existing * stringPtr->unicode array. Force it to follow any relocations * due to the reallocs below. */ int offset = -1; if (unicode >= stringPtr->unicode && unicode <= stringPtr->unicode + stringPtr->uallocated / sizeof(Tcl_UniChar)) { offset = unicode - stringPtr->unicode; } GrowUnicodeBuffer(objPtr, numChars); stringPtr = GET_STRING(objPtr); /* Relocate unicode if needed; see above. */ if (offset >= 0) { unicode = stringPtr->unicode + offset; } } /* * Copy the new string onto the end of the old string, then add the * trailing null. */ memcpy((VOID*) (stringPtr->unicode + stringPtr->numChars), unicode, appendNumChars * sizeof(Tcl_UniChar)); stringPtr->unicode[numChars] = 0; stringPtr->numChars = numChars; stringPtr->allocated = 0; Tcl_InvalidateStringRep(objPtr); } /* *---------------------------------------------------------------------- * * AppendUnicodeToUtfRep -- * * This procedure converts the contents of "unicode" to UTF and * appends the UTF to the string rep of "objPtr". * * Results: * None. * * Side effects: * objPtr's internal rep is reallocated. * *---------------------------------------------------------------------- */ static void AppendUnicodeToUtfRep(objPtr, unicode, numChars) Tcl_Obj *objPtr; /* Points to the object to append to. */ CONST Tcl_UniChar *unicode; /* String to convert to UTF. */ int numChars; /* Number of chars of "unicode" to convert. */ { Tcl_DString dsPtr; CONST char *bytes; if (numChars < 0) { numChars = UnicodeLength(unicode); } if (numChars == 0) { return; } Tcl_DStringInit(&dsPtr); bytes = Tcl_UniCharToUtfDString(unicode, numChars, &dsPtr); AppendUtfToUtfRep(objPtr, bytes, Tcl_DStringLength(&dsPtr)); Tcl_DStringFree(&dsPtr); } /* *---------------------------------------------------------------------- * * AppendUtfToUnicodeRep -- * * This procedure converts the contents of "bytes" to Unicode and * appends the Unicode to the Unicode rep of "objPtr". objPtr must * already have a valid Unicode rep. * * Results: * None. * * Side effects: * objPtr's internal rep is reallocated. * *---------------------------------------------------------------------- */ static void AppendUtfToUnicodeRep(objPtr, bytes, numBytes) Tcl_Obj *objPtr; /* Points to the object to append to. */ CONST char *bytes; /* String to convert to Unicode. */ int numBytes; /* Number of bytes of "bytes" to convert. */ { Tcl_DString dsPtr; int numChars; Tcl_UniChar *unicode; if (numBytes < 0) { numBytes = (bytes ? strlen(bytes) : 0); } if (numBytes == 0) { return; } Tcl_DStringInit(&dsPtr); numChars = Tcl_NumUtfChars(bytes, numBytes); unicode = (Tcl_UniChar *)Tcl_UtfToUniCharDString(bytes, numBytes, &dsPtr); AppendUnicodeToUnicodeRep(objPtr, unicode, numChars); Tcl_DStringFree(&dsPtr); } /* *---------------------------------------------------------------------- * * AppendUtfToUtfRep -- * * This procedure appends "numBytes" bytes of "bytes" to the UTF string * rep of "objPtr". objPtr must already have a valid String rep. * * Results: * None. * * Side effects: * objPtr's internal rep is reallocated. * *---------------------------------------------------------------------- */ static void AppendUtfToUtfRep(objPtr, bytes, numBytes) Tcl_Obj *objPtr; /* Points to the object to append to. */ CONST char *bytes; /* String to append. */ int numBytes; /* Number of bytes of "bytes" to append. */ { String *stringPtr; int newLength, oldLength; if (numBytes < 0) { numBytes = (bytes ? strlen(bytes) : 0); } if (numBytes == 0) { return; } /* * Copy the new string onto the end of the old string, then add the * trailing null. */ oldLength = objPtr->length; newLength = numBytes + oldLength; if (newLength < 0) { Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX); } stringPtr = GET_STRING(objPtr); if (newLength > (int) stringPtr->allocated) { /* * Protect against case where unicode points into the existing * stringPtr->unicode array. Force it to follow any relocations * due to the reallocs below. */ int offset = -1; if (bytes >= objPtr->bytes && bytes <= objPtr->bytes + objPtr->length) { offset = bytes - objPtr->bytes; } /* * There isn't currently enough space in the string representation * so allocate additional space. First, try to double the length * required. If that fails, try a more modest allocation. See the * "TCL STRING GROWTH ALGORITHM" comment at the top of this file for an * explanation of this growth algorithm. */ if (Tcl_AttemptSetObjLength(objPtr, 2 * newLength) == 0) { /* * Take care computing the amount of modest growth to avoid * overflow into invalid argument values for Tcl_SetObjLength. */ unsigned int limit = INT_MAX - newLength; unsigned int extra = numBytes + TCL_GROWTH_MIN_ALLOC; int growth = (int) ((extra > limit) ? limit : extra); Tcl_SetObjLength(objPtr, newLength + growth); } /* Relocate bytes if needed; see above. */ if (offset >=0) { bytes = objPtr->bytes + offset; } } /* * Invalidate the unicode data. */ stringPtr->numChars = -1; stringPtr->hasUnicode = 0; memcpy((VOID *) (objPtr->bytes + oldLength), (VOID *) bytes, (size_t) numBytes); objPtr->bytes[newLength] = 0; objPtr->length = newLength; } /* *---------------------------------------------------------------------- * * Tcl_AppendStringsToObjVA -- * * This procedure appends one or more null-terminated strings * to an object. * * Results: * None. * * Side effects: * The contents of all the string arguments are appended to the * string representation of objPtr. * *---------------------------------------------------------------------- */ void Tcl_AppendStringsToObjVA (objPtr, argList) Tcl_Obj *objPtr; /* Points to the object to append to. */ va_list argList; /* Variable argument list. */ { #define STATIC_LIST_SIZE 16 String *stringPtr; int newLength, oldLength, attemptLength; register char *string, *dst; char *static_list[STATIC_LIST_SIZE]; char **args = static_list; int nargs_space = STATIC_LIST_SIZE; int nargs, i; if (Tcl_IsShared(objPtr)) { panic("Tcl_AppendStringsToObj called with shared object"); } SetStringFromAny(NULL, objPtr); /* * Force the existence of a string rep. so we avoid crashes operating * on a pure unicode value. [Bug 2597185] */ (void) Tcl_GetStringFromObj(objPtr, &oldLength); /* * Figure out how much space is needed for all the strings, and * expand the string representation if it isn't big enough. If no * bytes would be appended, just return. Note that on some platforms * (notably OS/390) the argList is an array so we need to use memcpy. */ nargs = 0; newLength = 0; while (1) { string = va_arg(argList, char *); if (string == NULL) { break; } if (nargs >= nargs_space) { /* * Expand the args buffer */ nargs_space += STATIC_LIST_SIZE; if (args == static_list) { args = (void *)ckalloc(nargs_space * sizeof(char *)); for (i = 0; i < nargs; ++i) { args[i] = static_list[i]; } } else { args = (void *)ckrealloc((void *)args, nargs_space * sizeof(char *)); } } newLength += strlen(string); args[nargs++] = string; } if (newLength == 0) { goto done; } stringPtr = GET_STRING(objPtr); if (oldLength + newLength > (int) stringPtr->allocated) { /* * There isn't currently enough space in the string * representation, so allocate additional space. If the current * string representation isn't empty (i.e. it looks like we're * doing a series of appends) then try to allocate extra space to * accomodate future growth: first try to double the required memory; * if that fails, try a more modest allocation. See the "TCL STRING * GROWTH ALGORITHM" comment at the top of this file for an explanation * of this growth algorithm. Otherwise, if the current string * representation is empty, exactly enough memory is allocated. */ if (oldLength == 0) { Tcl_SetObjLength(objPtr, newLength); } else { attemptLength = 2 * (oldLength + newLength); if (Tcl_AttemptSetObjLength(objPtr, attemptLength) == 0) { attemptLength = oldLength + (2 * newLength) + TCL_GROWTH_MIN_ALLOC; Tcl_SetObjLength(objPtr, attemptLength); } } } /* * Make a second pass through the arguments, appending all the * strings to the object. */ dst = objPtr->bytes + oldLength; for (i = 0; i < nargs; ++i) { string = args[i]; if (string == NULL) { break; } while (*string != 0) { *dst = *string; dst++; string++; } } /* * Add a null byte to terminate the string. However, be careful: * it's possible that the object is totally empty (if it was empty * originally and there was nothing to append). In this case dst is * NULL; just leave everything alone. */ if (dst != NULL) { *dst = 0; } objPtr->length = oldLength + newLength; done: /* * If we had to allocate a buffer from the heap, * free it now. */ if (args != static_list) { ckfree((void *)args); } #undef STATIC_LIST_SIZE } /* *---------------------------------------------------------------------- * * Tcl_AppendStringsToObj -- * * This procedure appends one or more null-terminated strings * to an object. * * Results: * None. * * Side effects: * The contents of all the string arguments are appended to the * string representation of objPtr. * *---------------------------------------------------------------------- */ void Tcl_AppendStringsToObj TCL_VARARGS_DEF(Tcl_Obj *,arg1) { register Tcl_Obj *objPtr; va_list argList; objPtr = TCL_VARARGS_START(Tcl_Obj *,arg1,argList); Tcl_AppendStringsToObjVA(objPtr, argList); va_end(argList); } /* *--------------------------------------------------------------------------- * * FillUnicodeRep -- * * Populate the Unicode internal rep with the Unicode form of its string * rep. The object must alread have a "String" internal rep. * * Results: * None. * * Side effects: * Reallocates the String internal rep. * *--------------------------------------------------------------------------- */ static void FillUnicodeRep(objPtr) Tcl_Obj *objPtr; /* The object in which to fill the unicode rep. */ { String *stringPtr; size_t uallocated; char *src, *srcEnd; Tcl_UniChar *dst; src = objPtr->bytes; stringPtr = GET_STRING(objPtr); if (stringPtr->numChars == -1) { stringPtr->numChars = Tcl_NumUtfChars(src, objPtr->length); } stringPtr->hasUnicode = (stringPtr->numChars > 0); stringCheckLimits(stringPtr->numChars); uallocated = STRING_UALLOC(stringPtr->numChars); if (uallocated > stringPtr->uallocated) { GrowUnicodeBuffer(objPtr, stringPtr->numChars); stringPtr = GET_STRING(objPtr); } /* * Convert src to Unicode and store the coverted data in "unicode". */ srcEnd = src + objPtr->length; for (dst = stringPtr->unicode; src < srcEnd; dst++) { src += TclUtfToUniChar(src, dst); } *dst = 0; SET_STRING(objPtr, stringPtr); } /* *---------------------------------------------------------------------- * * DupStringInternalRep -- * * Initialize the internal representation of a new Tcl_Obj to a * copy of the internal representation of an existing string object. * * Results: * None. * * Side effects: * copyPtr's internal rep is set to a copy of srcPtr's internal * representation. * *---------------------------------------------------------------------- */ static void DupStringInternalRep(srcPtr, copyPtr) register Tcl_Obj *srcPtr; /* Object with internal rep to copy. Must * have an internal rep of type "String". */ register Tcl_Obj *copyPtr; /* Object with internal rep to set. Must * not currently have an internal rep.*/ { String *srcStringPtr = GET_STRING(srcPtr); String *copyStringPtr = NULL; /* * If the src obj is a string of 1-byte Utf chars, then copy the * string rep of the source object and create an "empty" Unicode * internal rep for the new object. Otherwise, copy Unicode * internal rep, and invalidate the string rep of the new object. */ if (srcStringPtr->hasUnicode == 0) { copyStringPtr = (String *) ckalloc(sizeof(String)); copyStringPtr->uallocated = 0; } else { copyStringPtr = (String *) ckalloc( STRING_SIZE(srcStringPtr->uallocated)); copyStringPtr->uallocated = srcStringPtr->uallocated; memcpy((VOID *) copyStringPtr->unicode, (VOID *) srcStringPtr->unicode, (size_t) srcStringPtr->numChars * sizeof(Tcl_UniChar)); copyStringPtr->unicode[srcStringPtr->numChars] = 0; } copyStringPtr->numChars = srcStringPtr->numChars; copyStringPtr->hasUnicode = srcStringPtr->hasUnicode; copyStringPtr->allocated = srcStringPtr->allocated; /* * Tricky point: the string value was copied by generic object * management code, so it doesn't contain any extra bytes that * might exist in the source object. */ copyStringPtr->allocated = copyPtr->length; SET_STRING(copyPtr, copyStringPtr); copyPtr->typePtr = &tclStringType; } /* *---------------------------------------------------------------------- * * SetStringFromAny -- * * Create an internal representation of type "String" for an object. * * Results: * This operation always succeeds and returns TCL_OK. * * Side effects: * Any old internal reputation for objPtr is freed and the * internal representation is set to "String". * *---------------------------------------------------------------------- */ static int SetStringFromAny(interp, objPtr) Tcl_Interp *interp; /* Used for error reporting if not NULL. */ register Tcl_Obj *objPtr; /* The object to convert. */ { /* * The Unicode object is optimized for the case where each UTF char * in a string is only one byte. In this case, we store the value of * numChars, but we don't copy the bytes to the unicodeObj->unicode. */ if (objPtr->typePtr != &tclStringType) { String *stringPtr; if (objPtr->typePtr != NULL) { if (objPtr->bytes == NULL) { objPtr->typePtr->updateStringProc(objPtr); } if ((objPtr->typePtr->freeIntRepProc) != NULL) { (*objPtr->typePtr->freeIntRepProc)(objPtr); } } objPtr->typePtr = &tclStringType; /* * Allocate enough space for the basic String structure. */ stringPtr = (String *) ckalloc(sizeof(String)); stringPtr->numChars = -1; stringPtr->uallocated = 0; stringPtr->hasUnicode = 0; if (objPtr->bytes != NULL) { stringPtr->allocated = objPtr->length; if (objPtr->bytes != tclEmptyStringRep) { objPtr->bytes[objPtr->length] = 0; } } else { objPtr->length = 0; } SET_STRING(objPtr, stringPtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * UpdateStringOfString -- * * Update the string representation for an object whose internal * representation is "String". * * Results: * None. * * Side effects: * The object's string may be set by converting its Unicode * represention to UTF format. * *---------------------------------------------------------------------- */ static void UpdateStringOfString(objPtr) Tcl_Obj *objPtr; /* Object with string rep to update. */ { int i, size; Tcl_UniChar *unicode; char dummy[TCL_UTF_MAX]; char *dst; String *stringPtr; stringPtr = GET_STRING(objPtr); if ((objPtr->bytes == NULL) || (stringPtr->allocated == 0)) { if (stringPtr->numChars <= 0) { /* * If there is no Unicode rep, or the string has 0 chars, * then set the string rep to an empty string. */ objPtr->bytes = tclEmptyStringRep; objPtr->length = 0; return; } unicode = stringPtr->unicode; /* * Translate the Unicode string to UTF. "size" will hold the * amount of space the UTF string needs. */ if (stringPtr->numChars <= INT_MAX/TCL_UTF_MAX && stringPtr->allocated >= (size_t) (stringPtr->numChars * TCL_UTF_MAX)) { goto copyBytes; } size = 0; for (i = 0; i < stringPtr->numChars && size >= 0; i++) { size += Tcl_UniCharToUtf((int) unicode[i], dummy); } if (size < 0) { Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX); } objPtr->bytes = (char *) ckalloc((unsigned) (size + 1)); objPtr->length = size; stringPtr->allocated = size; copyBytes: dst = objPtr->bytes; for (i = 0; i < stringPtr->numChars; i++) { dst += Tcl_UniCharToUtf(unicode[i], dst); } *dst = '\0'; } return; } /* *---------------------------------------------------------------------- * * FreeStringInternalRep -- * * Deallocate the storage associated with a String data object's * internal representation. * * Results: * None. * * Side effects: * Frees memory. * *---------------------------------------------------------------------- */ static void FreeStringInternalRep(objPtr) Tcl_Obj *objPtr; /* Object with internal rep to free. */ { ckfree((char *) GET_STRING(objPtr)); } tcl8.4.20/generic/tclLoadNone.c0000644003604700454610000000720611737050674014706 0ustar dgp771div/* * tclLoadNone.c -- * * This procedure provides a version of the TclLoadFile for use * in systems that don't support dynamic loading; it just returns * an error. * * Copyright (c) 1995-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" /* *---------------------------------------------------------------------- * * TclpDlopen -- * * This procedure is called to carry out dynamic loading of binary * code; it is intended for use only on systems that don't support * dynamic loading (it returns an error). * * Results: * The result is TCL_ERROR, and an error message is left in * the interp's result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclpDlopen(interp, pathPtr, loadHandle, unloadProcPtr) Tcl_Interp *interp; /* Used for error reporting. */ Tcl_Obj *pathPtr; /* Name of the file containing the desired * code (UTF-8). */ Tcl_LoadHandle *loadHandle; /* Filled with token for dynamically loaded * file which will be passed back to * (*unloadProcPtr)() to unload the file. */ Tcl_FSUnloadFileProc **unloadProcPtr; /* Filled with address of Tcl_FSUnloadFileProc * function which should be used for * this file. */ { Tcl_SetResult(interp, "dynamic loading is not currently available on this system", TCL_STATIC); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TclpFindSymbol -- * * Looks up a symbol, by name, through a handle associated with * a previously loaded piece of code (shared library). * * Results: * Returns a pointer to the function associated with 'symbol' if * it is found. Otherwise returns NULL and may leave an error * message in the interp's result. * *---------------------------------------------------------------------- */ Tcl_PackageInitProc* TclpFindSymbol(interp, loadHandle, symbol) Tcl_Interp *interp; Tcl_LoadHandle loadHandle; CONST char *symbol; { return NULL; } /* *---------------------------------------------------------------------- * * TclGuessPackageName -- * * If the "load" command is invoked without providing a package * name, this procedure is invoked to try to figure it out. * * Results: * Always returns 0 to indicate that we couldn't figure out a * package name; generic code will then try to guess the package * from the file name. A return value of 1 would have meant that * we figured out the package name and put it in bufPtr. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclGuessPackageName(fileName, bufPtr) CONST char *fileName; /* Name of file containing package (already * translated to local form if needed). */ Tcl_DString *bufPtr; /* Initialized empty dstring. Append * package name to this if possible. */ { return 0; } /* *---------------------------------------------------------------------- * * TclpUnloadFile -- * * This procedure is called to carry out dynamic unloading of binary * code; it is intended for use only on systems that don't support * dynamic loading (it does nothing). * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TclpUnloadFile(loadHandle) Tcl_LoadHandle loadHandle; /* loadHandle returned by a previous call * to TclpDlopen(). The loadHandle is * a token that represents the loaded * file. */ { } tcl8.4.20/generic/tclLiteral.c0000644003604700454610000007524111737050674014607 0ustar dgp771div/* * tclLiteral.c -- * * Implementation of the global and ByteCode-local literal tables * used to manage the Tcl objects created for literal values during * compilation of Tcl scripts. This implementation borrows heavily * from the more general hashtable implementation of Tcl hash tables * that appears in tclHash.c. * * Copyright (c) 1997-1998 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclCompile.h" #include "tclPort.h" /* * When there are this many entries per bucket, on average, rebuild * a literal's hash table to make it larger. */ #define REBUILD_MULTIPLIER 3 /* * Procedure prototypes for static procedures in this file: */ static int AddLocalLiteralEntry _ANSI_ARGS_(( CompileEnv *envPtr, LiteralEntry *globalPtr, int localHash)); static void ExpandLocalLiteralArray _ANSI_ARGS_(( CompileEnv *envPtr)); static unsigned int HashString _ANSI_ARGS_((CONST char *bytes, int length)); static void RebuildLiteralTable _ANSI_ARGS_(( LiteralTable *tablePtr)); /* *---------------------------------------------------------------------- * * TclInitLiteralTable -- * * This procedure is called to initialize the fields of a literal table * structure for either an interpreter or a compilation's CompileEnv * structure. * * Results: * None. * * Side effects: * The literal table is made ready for use. * *---------------------------------------------------------------------- */ void TclInitLiteralTable(tablePtr) register LiteralTable *tablePtr; /* Pointer to table structure, which * is supplied by the caller. */ { #if (TCL_SMALL_HASH_TABLE != 4) panic("TclInitLiteralTable: TCL_SMALL_HASH_TABLE is %d, not 4\n", TCL_SMALL_HASH_TABLE); #endif tablePtr->buckets = tablePtr->staticBuckets; tablePtr->staticBuckets[0] = tablePtr->staticBuckets[1] = 0; tablePtr->staticBuckets[2] = tablePtr->staticBuckets[3] = 0; tablePtr->numBuckets = TCL_SMALL_HASH_TABLE; tablePtr->numEntries = 0; tablePtr->rebuildSize = TCL_SMALL_HASH_TABLE*REBUILD_MULTIPLIER; tablePtr->mask = 3; } /* *---------------------------------------------------------------------- * * TclDeleteLiteralTable -- * * This procedure frees up everything associated with a literal table * except for the table's structure itself. * * Results: * None. * * Side effects: * Each literal in the table is released: i.e., its reference count * in the global literal table is decremented and, if it becomes zero, * the literal is freed. In addition, the table's bucket array is * freed. * *---------------------------------------------------------------------- */ void TclDeleteLiteralTable(interp, tablePtr) Tcl_Interp *interp; /* Interpreter containing shared literals * referenced by the table to delete. */ LiteralTable *tablePtr; /* Points to the literal table to delete. */ { LiteralEntry *entryPtr; int i, start; /* * Release remaining literals in the table. Note that releasing a * literal might release other literals, modifying the table, so we * restart the search from the bucket chain we last found an entry. */ #ifdef TCL_COMPILE_DEBUG TclVerifyGlobalLiteralTable((Interp *) interp); #endif /*TCL_COMPILE_DEBUG*/ start = 0; while (tablePtr->numEntries > 0) { for (i = start; i < tablePtr->numBuckets; i++) { entryPtr = tablePtr->buckets[i]; if (entryPtr != NULL) { TclReleaseLiteral(interp, entryPtr->objPtr); start = i; break; } } } /* * Free up the table's bucket array if it was dynamically allocated. */ if (tablePtr->buckets != tablePtr->staticBuckets) { ckfree((char *) tablePtr->buckets); } } /* *---------------------------------------------------------------------- * * TclRegisterLiteral -- * * Find, or if necessary create, an object in a CompileEnv literal * array that has a string representation matching the argument string. * * Results: * The index in the CompileEnv's literal array that references a * shared literal matching the string. The object is created if * necessary. * * Side effects: * To maximize sharing, we look up the string in the interpreter's * global literal table. If not found, we create a new shared literal * in the global table. We then add a reference to the shared * literal in the CompileEnv's literal array. * * If onHeap is 1, this procedure is given ownership of the string: if * an object is created then its string representation is set directly * from string, otherwise the string is freed. Typically, a caller sets * onHeap 1 if "string" is an already heap-allocated buffer holding the * result of backslash substitutions. * *---------------------------------------------------------------------- */ int TclRegisterLiteral(envPtr, bytes, length, onHeap) CompileEnv *envPtr; /* Points to the CompileEnv in whose object * array an object is found or created. */ register char *bytes; /* Points to string for which to find or * create an object in CompileEnv's object * array. */ int length; /* Number of bytes in the string. If < 0, * the string consists of all bytes up to * the first null character. */ int onHeap; /* If 1 then the caller already malloc'd * bytes and ownership is passed to this * procedure. */ { Interp *iPtr = envPtr->iPtr; LiteralTable *globalTablePtr = &(iPtr->literalTable); LiteralTable *localTablePtr = &(envPtr->localLitTable); register LiteralEntry *globalPtr, *localPtr; register Tcl_Obj *objPtr; unsigned int hash; int localHash, globalHash, objIndex; long n; char buf[TCL_INTEGER_SPACE]; if (length < 0) { length = (bytes? strlen(bytes) : 0); } hash = HashString(bytes, length); /* * Is the literal already in the CompileEnv's local literal array? * If so, just return its index. */ localHash = (hash & localTablePtr->mask); for (localPtr = localTablePtr->buckets[localHash]; localPtr != NULL; localPtr = localPtr->nextPtr) { objPtr = localPtr->objPtr; if ((objPtr->length == length) && ((length == 0) || ((objPtr->bytes[0] == bytes[0]) && (memcmp(objPtr->bytes, bytes, (unsigned) length) == 0)))) { if (onHeap) { ckfree(bytes); } objIndex = (localPtr - envPtr->literalArrayPtr); #ifdef TCL_COMPILE_DEBUG TclVerifyLocalLiteralTable(envPtr); #endif /*TCL_COMPILE_DEBUG*/ return objIndex; } } /* * The literal is new to this CompileEnv. Is it in the interpreter's * global literal table? */ globalHash = (hash & globalTablePtr->mask); for (globalPtr = globalTablePtr->buckets[globalHash]; globalPtr != NULL; globalPtr = globalPtr->nextPtr) { objPtr = globalPtr->objPtr; if ((objPtr->length == length) && ((length == 0) || ((objPtr->bytes[0] == bytes[0]) && (memcmp(objPtr->bytes, bytes, (unsigned) length) == 0)))) { /* * A global literal was found. Add an entry to the CompileEnv's * local literal array. */ if (onHeap) { ckfree(bytes); } objIndex = AddLocalLiteralEntry(envPtr, globalPtr, localHash); #ifdef TCL_COMPILE_DEBUG if (globalPtr->refCount < 1) { panic("TclRegisterLiteral: global literal \"%.*s\" had bad refCount %d", (length>60? 60 : length), bytes, globalPtr->refCount); } TclVerifyLocalLiteralTable(envPtr); #endif /*TCL_COMPILE_DEBUG*/ return objIndex; } } /* * The literal is new to the interpreter. Add it to the global literal * table then add an entry to the CompileEnv's local literal array. * Convert the object to an integer object if possible. */ TclNewObj(objPtr); Tcl_IncrRefCount(objPtr); if (onHeap) { objPtr->bytes = bytes; objPtr->length = length; } else { TclInitStringRep(objPtr, bytes, length); } if (TclLooksLikeInt(bytes, length)) { /* * From here we use the objPtr, because it is NULL terminated */ if (TclGetLong((Tcl_Interp *) NULL, objPtr->bytes, &n) == TCL_OK) { TclFormatInt(buf, n); if (strcmp(objPtr->bytes, buf) == 0) { objPtr->internalRep.longValue = n; objPtr->typePtr = &tclIntType; } } } #ifdef TCL_COMPILE_DEBUG if (TclLookupLiteralEntry((Tcl_Interp *) iPtr, objPtr) != NULL) { panic("TclRegisterLiteral: literal \"%.*s\" found globally but shouldn't be", (length>60? 60 : length), bytes); } #endif globalPtr = (LiteralEntry *) ckalloc((unsigned) sizeof(LiteralEntry)); globalPtr->objPtr = objPtr; globalPtr->refCount = 0; globalPtr->nextPtr = globalTablePtr->buckets[globalHash]; globalTablePtr->buckets[globalHash] = globalPtr; globalTablePtr->numEntries++; /* * If the global literal table has exceeded a decent size, rebuild it * with more buckets. */ if (globalTablePtr->numEntries >= globalTablePtr->rebuildSize) { RebuildLiteralTable(globalTablePtr); } objIndex = AddLocalLiteralEntry(envPtr, globalPtr, localHash); #ifdef TCL_COMPILE_DEBUG TclVerifyGlobalLiteralTable(iPtr); TclVerifyLocalLiteralTable(envPtr); { LiteralEntry *entryPtr; int found, i; found = 0; for (i = 0; i < globalTablePtr->numBuckets; i++) { for (entryPtr = globalTablePtr->buckets[i]; entryPtr != NULL; entryPtr = entryPtr->nextPtr) { if ((entryPtr == globalPtr) && (entryPtr->objPtr == objPtr)) { found = 1; } } } if (!found) { panic("TclRegisterLiteral: literal \"%.*s\" wasn't global", (length>60? 60 : length), bytes); } } #endif /*TCL_COMPILE_DEBUG*/ #ifdef TCL_COMPILE_STATS iPtr->stats.numLiteralsCreated++; iPtr->stats.totalLitStringBytes += (double) (length + 1); iPtr->stats.currentLitStringBytes += (double) (length + 1); iPtr->stats.literalCount[TclLog2(length)]++; #endif /*TCL_COMPILE_STATS*/ return objIndex; } /* *---------------------------------------------------------------------- * * TclLookupLiteralEntry -- * * Finds the LiteralEntry that corresponds to a literal Tcl object * holding a literal. * * Results: * Returns the matching LiteralEntry if found, otherwise NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ LiteralEntry * TclLookupLiteralEntry(interp, objPtr) Tcl_Interp *interp; /* Interpreter for which objPtr was created * to hold a literal. */ register Tcl_Obj *objPtr; /* Points to a Tcl object holding a * literal that was previously created by a * call to TclRegisterLiteral. */ { Interp *iPtr = (Interp *) interp; LiteralTable *globalTablePtr = &(iPtr->literalTable); register LiteralEntry *entryPtr; char *bytes; int length, globalHash; bytes = Tcl_GetStringFromObj(objPtr, &length); globalHash = (HashString(bytes, length) & globalTablePtr->mask); for (entryPtr = globalTablePtr->buckets[globalHash]; entryPtr != NULL; entryPtr = entryPtr->nextPtr) { if (entryPtr->objPtr == objPtr) { return entryPtr; } } return NULL; } /* *---------------------------------------------------------------------- * * TclHideLiteral -- * * Remove a literal entry from the literal hash tables, leaving it in * the literal array so existing references continue to function. * This makes it possible to turn a shared literal into a private * literal that cannot be shared. * * Results: * None. * * Side effects: * Removes the literal from the local hash table and decrements the * global hash entry's reference count. * *---------------------------------------------------------------------- */ void TclHideLiteral(interp, envPtr, index) Tcl_Interp *interp; /* Interpreter for which objPtr was created * to hold a literal. */ register CompileEnv *envPtr; /* Points to CompileEnv whose literal array * contains the entry being hidden. */ int index; /* The index of the entry in the literal * array. */ { LiteralEntry **nextPtrPtr, *entryPtr, *lPtr; LiteralTable *localTablePtr = &(envPtr->localLitTable); int localHash, length; char *bytes; Tcl_Obj *newObjPtr; lPtr = &(envPtr->literalArrayPtr[index]); /* * To avoid unwanted sharing we need to copy the object and remove it from * the local and global literal tables. It still has a slot in the literal * array so it can be referred to by byte codes, but it will not be matched * by literal searches. */ newObjPtr = Tcl_DuplicateObj(lPtr->objPtr); Tcl_IncrRefCount(newObjPtr); TclReleaseLiteral(interp, lPtr->objPtr); lPtr->objPtr = newObjPtr; bytes = Tcl_GetStringFromObj(newObjPtr, &length); localHash = (HashString(bytes, length) & localTablePtr->mask); nextPtrPtr = &localTablePtr->buckets[localHash]; for (entryPtr = *nextPtrPtr; entryPtr != NULL; entryPtr = *nextPtrPtr) { if (entryPtr == lPtr) { *nextPtrPtr = lPtr->nextPtr; lPtr->nextPtr = NULL; localTablePtr->numEntries--; break; } nextPtrPtr = &entryPtr->nextPtr; } } /* *---------------------------------------------------------------------- * * TclAddLiteralObj -- * * Add a single literal object to the literal array. This * function does not add the literal to the local or global * literal tables. The caller is expected to add the entry * to whatever tables are appropriate. * * Results: * The index in the CompileEnv's literal array that references the * literal. Stores the pointer to the new literal entry in the * location referenced by the localPtrPtr argument. * * Side effects: * Expands the literal array if necessary. Increments the refcount * on the literal object. * *---------------------------------------------------------------------- */ int TclAddLiteralObj(envPtr, objPtr, litPtrPtr) register CompileEnv *envPtr; /* Points to CompileEnv in whose literal * array the object is to be inserted. */ Tcl_Obj *objPtr; /* The object to insert into the array. */ LiteralEntry **litPtrPtr; /* The location where the pointer to the * new literal entry should be stored. * May be NULL. */ { register LiteralEntry *lPtr; int objIndex; if (envPtr->literalArrayNext >= envPtr->literalArrayEnd) { ExpandLocalLiteralArray(envPtr); } objIndex = envPtr->literalArrayNext; envPtr->literalArrayNext++; lPtr = &(envPtr->literalArrayPtr[objIndex]); lPtr->objPtr = objPtr; Tcl_IncrRefCount(objPtr); lPtr->refCount = -1; /* i.e., unused */ lPtr->nextPtr = NULL; if (litPtrPtr) { *litPtrPtr = lPtr; } return objIndex; } /* *---------------------------------------------------------------------- * * AddLocalLiteralEntry -- * * Insert a new literal into a CompileEnv's local literal array. * * Results: * The index in the CompileEnv's literal array that references the * literal. * * Side effects: * Increments the ref count of the global LiteralEntry since the * CompileEnv now refers to the literal. Expands the literal array * if necessary. May rebuild the hash bucket array of the CompileEnv's * literal array if it becomes too large. * *---------------------------------------------------------------------- */ static int AddLocalLiteralEntry(envPtr, globalPtr, localHash) register CompileEnv *envPtr; /* Points to CompileEnv in whose literal * array the object is to be inserted. */ LiteralEntry *globalPtr; /* Points to the global LiteralEntry for * the literal to add to the CompileEnv. */ int localHash; /* Hash value for the literal's string. */ { register LiteralTable *localTablePtr = &(envPtr->localLitTable); LiteralEntry *localPtr; int objIndex; objIndex = TclAddLiteralObj(envPtr, globalPtr->objPtr, &localPtr); /* * Add the literal to the local table. */ localPtr->nextPtr = localTablePtr->buckets[localHash]; localTablePtr->buckets[localHash] = localPtr; localTablePtr->numEntries++; globalPtr->refCount++; /* * If the CompileEnv's local literal table has exceeded a decent size, * rebuild it with more buckets. */ if (localTablePtr->numEntries >= localTablePtr->rebuildSize) { RebuildLiteralTable(localTablePtr); } #ifdef TCL_COMPILE_DEBUG TclVerifyLocalLiteralTable(envPtr); { char *bytes; int length, found, i; found = 0; for (i = 0; i < localTablePtr->numBuckets; i++) { for (localPtr = localTablePtr->buckets[i]; localPtr != NULL; localPtr = localPtr->nextPtr) { if (localPtr->objPtr == globalPtr->objPtr) { found = 1; } } } if (!found) { bytes = Tcl_GetStringFromObj(globalPtr->objPtr, &length); panic("AddLocalLiteralEntry: literal \"%.*s\" wasn't found locally", (length>60? 60 : length), bytes); } } #endif /*TCL_COMPILE_DEBUG*/ return objIndex; } /* *---------------------------------------------------------------------- * * ExpandLocalLiteralArray -- * * Procedure that uses malloc to allocate more storage for a * CompileEnv's local literal array. * * Results: * None. * * Side effects: * The literal array in *envPtr is reallocated to a new array of * double the size, and if envPtr->mallocedLiteralArray is non-zero * the old array is freed. Entries are copied from the old array * to the new one. The local literal table is updated to refer to * the new entries. * *---------------------------------------------------------------------- */ static void ExpandLocalLiteralArray(envPtr) register CompileEnv *envPtr; /* Points to the CompileEnv whose object * array must be enlarged. */ { /* * The current allocated local literal entries are stored between * elements 0 and (envPtr->literalArrayNext - 1) [inclusive]. */ LiteralTable *localTablePtr = &(envPtr->localLitTable); int currElems = envPtr->literalArrayNext; size_t currBytes = (currElems * sizeof(LiteralEntry)); register LiteralEntry *currArrayPtr = envPtr->literalArrayPtr; register LiteralEntry *newArrayPtr = (LiteralEntry *) ckalloc((unsigned) (2 * currBytes)); int i; /* * Copy from the old literal array to the new, then update the local * literal table's bucket array. */ memcpy((VOID *) newArrayPtr, (VOID *) currArrayPtr, currBytes); for (i = 0; i < currElems; i++) { if (currArrayPtr[i].nextPtr == NULL) { newArrayPtr[i].nextPtr = NULL; } else { newArrayPtr[i].nextPtr = newArrayPtr + (currArrayPtr[i].nextPtr - currArrayPtr); } } for (i = 0; i < localTablePtr->numBuckets; i++) { if (localTablePtr->buckets[i] != NULL) { localTablePtr->buckets[i] = newArrayPtr + (localTablePtr->buckets[i] - currArrayPtr); } } /* * Free the old literal array if needed, and mark the new literal * array as malloced. */ if (envPtr->mallocedLiteralArray) { ckfree((char *) currArrayPtr); } envPtr->literalArrayPtr = newArrayPtr; envPtr->literalArrayEnd = (2 * currElems); envPtr->mallocedLiteralArray = 1; } /* *---------------------------------------------------------------------- * * TclReleaseLiteral -- * * This procedure releases a reference to one of the shared Tcl objects * that hold literals. It is called to release the literals referenced * by a ByteCode that is being destroyed, and it is also called by * TclDeleteLiteralTable. * * Results: * None. * * Side effects: * The reference count for the global LiteralTable entry that * corresponds to the literal is decremented. If no other reference * to a global literal object remains, it is freed. * *---------------------------------------------------------------------- */ void TclReleaseLiteral(interp, objPtr) Tcl_Interp *interp; /* Interpreter for which objPtr was created * to hold a literal. */ register Tcl_Obj *objPtr; /* Points to a literal object that was * previously created by a call to * TclRegisterLiteral. */ { Interp *iPtr = (Interp *) interp; LiteralTable *globalTablePtr = &(iPtr->literalTable); register LiteralEntry *entryPtr, *prevPtr; ByteCode* codePtr; char *bytes; int length, index; bytes = Tcl_GetStringFromObj(objPtr, &length); index = (HashString(bytes, length) & globalTablePtr->mask); /* * Check to see if the object is in the global literal table and * remove this reference. The object may not be in the table if * it is a hidden local literal. */ for (prevPtr = NULL, entryPtr = globalTablePtr->buckets[index]; entryPtr != NULL; prevPtr = entryPtr, entryPtr = entryPtr->nextPtr) { if (entryPtr->objPtr == objPtr) { entryPtr->refCount--; /* * If the literal is no longer being used by any ByteCode, * delete the entry then remove the reference corresponding * to the global literal table entry (decrement the ref count * of the object). */ if (entryPtr->refCount == 0) { if (prevPtr == NULL) { globalTablePtr->buckets[index] = entryPtr->nextPtr; } else { prevPtr->nextPtr = entryPtr->nextPtr; } ckfree((char *) entryPtr); globalTablePtr->numEntries--; TclDecrRefCount(objPtr); /* * Check if the LiteralEntry is only being kept alive by * a circular reference from a ByteCode stored as its * internal rep. In that case, set the ByteCode object array * entry NULL to signal to TclCleanupByteCode to not try to * release this about to be freed literal again. */ if (objPtr->typePtr == &tclByteCodeType) { codePtr = (ByteCode *) objPtr->internalRep.otherValuePtr; if ((codePtr->numLitObjects == 1) && (codePtr->objArrayPtr[0] == objPtr)) { codePtr->objArrayPtr[0] = NULL; } } #ifdef TCL_COMPILE_STATS iPtr->stats.currentLitStringBytes -= (double) (length + 1); #endif /*TCL_COMPILE_STATS*/ } break; } } /* * Remove the reference corresponding to the local literal table * entry. */ Tcl_DecrRefCount(objPtr); } /* *---------------------------------------------------------------------- * * HashString -- * * Compute a one-word summary of a text string, which can be * used to generate a hash index. * * Results: * The return value is a one-word summary of the information in * string. * * Side effects: * None. * *---------------------------------------------------------------------- */ static unsigned int HashString(bytes, length) register CONST char *bytes; /* String for which to compute hash * value. */ int length; /* Number of bytes in the string. */ { register unsigned int result; register int i; /* * I tried a zillion different hash functions and asked many other * people for advice. Many people had their own favorite functions, * all different, but no-one had much idea why they were good ones. * I chose the one below (multiply by 9 and add new character) * because of the following reasons: * * 1. Multiplying by 10 is perfect for keys that are decimal strings, * and multiplying by 9 is just about as good. * 2. Times-9 is (shift-left-3) plus (old). This means that each * character's bits hang around in the low-order bits of the * hash value for ever, plus they spread fairly rapidly up to * the high-order bits to fill out the hash value. This seems * works well both for decimal and non-decimal strings. */ result = 0; for (i = 0; i < length; i++) { result += (result<<3) + *bytes++; } return result; } /* *---------------------------------------------------------------------- * * RebuildLiteralTable -- * * This procedure is invoked when the ratio of entries to hash buckets * becomes too large in a local or global literal table. It allocates * a larger bucket array and moves the entries into the new buckets. * * Results: * None. * * Side effects: * Memory gets reallocated and entries get rehashed into new buckets. * *---------------------------------------------------------------------- */ static void RebuildLiteralTable(tablePtr) register LiteralTable *tablePtr; /* Local or global table to enlarge. */ { LiteralEntry **oldBuckets; register LiteralEntry **oldChainPtr, **newChainPtr; register LiteralEntry *entryPtr; LiteralEntry **bucketPtr; char *bytes; int oldSize, count, index, length; oldSize = tablePtr->numBuckets; oldBuckets = tablePtr->buckets; /* * Allocate and initialize the new bucket array, and set up * hashing constants for new array size. */ tablePtr->numBuckets *= 4; tablePtr->buckets = (LiteralEntry **) ckalloc((unsigned) (tablePtr->numBuckets * sizeof(LiteralEntry *))); for (count = tablePtr->numBuckets, newChainPtr = tablePtr->buckets; count > 0; count--, newChainPtr++) { *newChainPtr = NULL; } tablePtr->rebuildSize *= 4; tablePtr->mask = (tablePtr->mask << 2) + 3; /* * Rehash all of the existing entries into the new bucket array. */ for (oldChainPtr = oldBuckets; oldSize > 0; oldSize--, oldChainPtr++) { for (entryPtr = *oldChainPtr; entryPtr != NULL; entryPtr = *oldChainPtr) { bytes = Tcl_GetStringFromObj(entryPtr->objPtr, &length); index = (HashString(bytes, length) & tablePtr->mask); *oldChainPtr = entryPtr->nextPtr; bucketPtr = &(tablePtr->buckets[index]); entryPtr->nextPtr = *bucketPtr; *bucketPtr = entryPtr; } } /* * Free up the old bucket array, if it was dynamically allocated. */ if (oldBuckets != tablePtr->staticBuckets) { ckfree((char *) oldBuckets); } } #ifdef TCL_COMPILE_STATS /* *---------------------------------------------------------------------- * * TclLiteralStats -- * * Return statistics describing the layout of the hash table * in its hash buckets. * * Results: * The return value is a malloc-ed string containing information * about tablePtr. It is the caller's responsibility to free * this string. * * Side effects: * None. * *---------------------------------------------------------------------- */ char * TclLiteralStats(tablePtr) LiteralTable *tablePtr; /* Table for which to produce stats. */ { #define NUM_COUNTERS 10 int count[NUM_COUNTERS], overflow, i, j; double average, tmp; register LiteralEntry *entryPtr; char *result, *p; /* * Compute a histogram of bucket usage. For each bucket chain i, * j is the number of entries in the chain. */ for (i = 0; i < NUM_COUNTERS; i++) { count[i] = 0; } overflow = 0; average = 0.0; for (i = 0; i < tablePtr->numBuckets; i++) { j = 0; for (entryPtr = tablePtr->buckets[i]; entryPtr != NULL; entryPtr = entryPtr->nextPtr) { j++; } if (j < NUM_COUNTERS) { count[j]++; } else { overflow++; } tmp = j; average += (tmp+1.0)*(tmp/tablePtr->numEntries)/2.0; } /* * Print out the histogram and a few other pieces of information. */ result = (char *) ckalloc((unsigned) ((NUM_COUNTERS*60) + 300)); sprintf(result, "%d entries in table, %d buckets\n", tablePtr->numEntries, tablePtr->numBuckets); p = result + strlen(result); for (i = 0; i < NUM_COUNTERS; i++) { sprintf(p, "number of buckets with %d entries: %d\n", i, count[i]); p += strlen(p); } sprintf(p, "number of buckets with %d or more entries: %d\n", NUM_COUNTERS, overflow); p += strlen(p); sprintf(p, "average search distance for entry: %.1f", average); return result; } #endif /*TCL_COMPILE_STATS*/ #ifdef TCL_COMPILE_DEBUG /* *---------------------------------------------------------------------- * * TclVerifyLocalLiteralTable -- * * Check a CompileEnv's local literal table for consistency. * * Results: * None. * * Side effects: * Panics if problems are found. * *---------------------------------------------------------------------- */ void TclVerifyLocalLiteralTable(envPtr) CompileEnv *envPtr; /* Points to CompileEnv whose literal * table is to be validated. */ { register LiteralTable *localTablePtr = &(envPtr->localLitTable); register LiteralEntry *localPtr; char *bytes; register int i; int length, count; count = 0; for (i = 0; i < localTablePtr->numBuckets; i++) { for (localPtr = localTablePtr->buckets[i]; localPtr != NULL; localPtr = localPtr->nextPtr) { count++; if (localPtr->refCount != -1) { bytes = Tcl_GetStringFromObj(localPtr->objPtr, &length); panic("TclVerifyLocalLiteralTable: local literal \"%.*s\" had bad refCount %d", (length>60? 60 : length), bytes, localPtr->refCount); } if (TclLookupLiteralEntry((Tcl_Interp *) envPtr->iPtr, localPtr->objPtr) == NULL) { bytes = Tcl_GetStringFromObj(localPtr->objPtr, &length); panic("TclVerifyLocalLiteralTable: local literal \"%.*s\" is not global", (length>60? 60 : length), bytes); } if (localPtr->objPtr->bytes == NULL) { panic("TclVerifyLocalLiteralTable: literal has NULL string rep"); } } } if (count != localTablePtr->numEntries) { panic("TclVerifyLocalLiteralTable: local literal table had %d entries, should be %d", count, localTablePtr->numEntries); } } /* *---------------------------------------------------------------------- * * TclVerifyGlobalLiteralTable -- * * Check an interpreter's global literal table literal for consistency. * * Results: * None. * * Side effects: * Panics if problems are found. * *---------------------------------------------------------------------- */ void TclVerifyGlobalLiteralTable(iPtr) Interp *iPtr; /* Points to interpreter whose global * literal table is to be validated. */ { register LiteralTable *globalTablePtr = &(iPtr->literalTable); register LiteralEntry *globalPtr; char *bytes; register int i; int length, count; count = 0; for (i = 0; i < globalTablePtr->numBuckets; i++) { for (globalPtr = globalTablePtr->buckets[i]; globalPtr != NULL; globalPtr = globalPtr->nextPtr) { count++; if (globalPtr->refCount < 1) { bytes = Tcl_GetStringFromObj(globalPtr->objPtr, &length); panic("TclVerifyGlobalLiteralTable: global literal \"%.*s\" had bad refCount %d", (length>60? 60 : length), bytes, globalPtr->refCount); } if (globalPtr->objPtr->bytes == NULL) { panic("TclVerifyGlobalLiteralTable: literal has NULL string rep"); } } } if (count != globalTablePtr->numEntries) { panic("TclVerifyGlobalLiteralTable: global literal table had %d entries, should be %d", count, globalTablePtr->numEntries); } } #endif /*TCL_COMPILE_DEBUG*/ tcl8.4.20/generic/tclIOSock.c0000644003604700454610000000556512052456744014343 0ustar dgp771div/* * tclIOSock.c -- * * Common routines used by all socket based channel types. * * Copyright (c) 1995-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" /* *--------------------------------------------------------------------------- * * TclSockGetPort -- * * Maps from a string, which could be a service name, to a port. * Used by socket creation code to get port numbers and resolve * registered service names to port numbers. * * Results: * A standard Tcl result. On success, the port number is returned * in portPtr. On failure, an error message is left in the interp's * result. * * Side effects: * None. * *--------------------------------------------------------------------------- */ int TclSockGetPort(interp, string, proto, portPtr) Tcl_Interp *interp; char *string; /* Integer or service name */ char *proto; /* "tcp" or "udp", typically */ int *portPtr; /* Return port number */ { struct servent *sp; /* Protocol info for named services */ Tcl_DString ds; CONST char *native; if (Tcl_GetInt(NULL, string, portPtr) != TCL_OK) { /* * Don't bother translating 'proto' to native. */ native = Tcl_UtfToExternalDString(NULL, string, -1, &ds); sp = getservbyname(native, proto); /* INTL: Native. */ Tcl_DStringFree(&ds); if (sp != NULL) { *portPtr = ntohs((unsigned short) sp->s_port); return TCL_OK; } } if (Tcl_GetInt(interp, string, portPtr) != TCL_OK) { return TCL_ERROR; } if (*portPtr > 0xFFFF) { Tcl_AppendResult(interp, "couldn't open socket: port number too high", (char *) NULL); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * TclSockMinimumBuffers -- * * Ensure minimum buffer sizes (non zero). * * Results: * A standard Tcl result. * * Side effects: * Sets SO_SNDBUF and SO_RCVBUF sizes. * *---------------------------------------------------------------------- */ #undef TclSockMinimumBuffers #if !defined(_WIN32) && !defined(__CYGWIN__) # define SOCKET int #endif int TclSockMinimumBuffers(sock, size) void *sock; /* Socket file descriptor */ int size; /* Minimum buffer size */ { int current; socklen_t len; len = sizeof(int); getsockopt((SOCKET)(size_t)sock, SOL_SOCKET, SO_SNDBUF, (char *)¤t, &len); if (current < size) { len = sizeof(int); setsockopt((SOCKET)(size_t)sock, SOL_SOCKET, SO_SNDBUF, (char *)&size, len); } len = sizeof(int); getsockopt((SOCKET)(size_t)sock, SOL_SOCKET, SO_RCVBUF, (char *)¤t, &len); if (current < size) { len = sizeof(int); setsockopt((SOCKET)(size_t)sock, SOL_SOCKET, SO_RCVBUF, (char *)&size, len); } return TCL_OK; } tcl8.4.20/generic/tclResult.c0000644003604700454610000006733411737050674014475 0ustar dgp771div/* * tclResult.c -- * * This file contains code to manage the interpreter result. * * Copyright (c) 1997 by Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" /* * Function prototypes for local procedures in this file: */ static void ResetObjResult _ANSI_ARGS_((Interp *iPtr)); static void SetupAppendBuffer _ANSI_ARGS_((Interp *iPtr, int newSpace)); /* *---------------------------------------------------------------------- * * Tcl_SaveResult -- * * Takes a snapshot of the current result state of the interpreter. * The snapshot can be restored at any point by * Tcl_RestoreResult. Note that this routine does not * preserve the errorCode, errorInfo, or flags fields so it * should not be used if an error is in progress. * * Once a snapshot is saved, it must be restored by calling * Tcl_RestoreResult, or discarded by calling * Tcl_DiscardResult. * * Results: * None. * * Side effects: * Resets the interpreter result. * *---------------------------------------------------------------------- */ void Tcl_SaveResult(interp, statePtr) Tcl_Interp *interp; /* Interpreter to save. */ Tcl_SavedResult *statePtr; /* Pointer to state structure. */ { Interp *iPtr = (Interp *) interp; /* * Move the result object into the save state. Note that we don't need * to change its refcount because we're moving it, not adding a new * reference. Put an empty object into the interpreter. */ statePtr->objResultPtr = iPtr->objResultPtr; iPtr->objResultPtr = Tcl_NewObj(); Tcl_IncrRefCount(iPtr->objResultPtr); /* * Save the string result. */ statePtr->freeProc = iPtr->freeProc; if (iPtr->result == iPtr->resultSpace) { /* * Copy the static string data out of the interp buffer. */ statePtr->result = statePtr->resultSpace; strcpy(statePtr->result, iPtr->result); statePtr->appendResult = NULL; } else if (iPtr->result == iPtr->appendResult) { /* * Move the append buffer out of the interp. */ statePtr->appendResult = iPtr->appendResult; statePtr->appendAvl = iPtr->appendAvl; statePtr->appendUsed = iPtr->appendUsed; statePtr->result = statePtr->appendResult; iPtr->appendResult = NULL; iPtr->appendAvl = 0; iPtr->appendUsed = 0; } else { /* * Move the dynamic or static string out of the interpreter. */ statePtr->result = iPtr->result; statePtr->appendResult = NULL; } iPtr->result = iPtr->resultSpace; iPtr->resultSpace[0] = 0; iPtr->freeProc = 0; } /* *---------------------------------------------------------------------- * * Tcl_RestoreResult -- * * Restores the state of the interpreter to a snapshot taken * by Tcl_SaveResult. After this call, the token for * the interpreter state is no longer valid. * * Results: * None. * * Side effects: * Restores the interpreter result. * *---------------------------------------------------------------------- */ void Tcl_RestoreResult(interp, statePtr) Tcl_Interp* interp; /* Interpreter being restored. */ Tcl_SavedResult *statePtr; /* State returned by Tcl_SaveResult. */ { Interp *iPtr = (Interp *) interp; Tcl_ResetResult(interp); /* * Restore the string result. */ iPtr->freeProc = statePtr->freeProc; if (statePtr->result == statePtr->resultSpace) { /* * Copy the static string data into the interp buffer. */ iPtr->result = iPtr->resultSpace; strcpy(iPtr->result, statePtr->result); } else if (statePtr->result == statePtr->appendResult) { /* * Move the append buffer back into the interp. */ if (iPtr->appendResult != NULL) { ckfree((char *)iPtr->appendResult); } iPtr->appendResult = statePtr->appendResult; iPtr->appendAvl = statePtr->appendAvl; iPtr->appendUsed = statePtr->appendUsed; iPtr->result = iPtr->appendResult; } else { /* * Move the dynamic or static string back into the interpreter. */ iPtr->result = statePtr->result; } /* * Restore the object result. */ Tcl_DecrRefCount(iPtr->objResultPtr); iPtr->objResultPtr = statePtr->objResultPtr; } /* *---------------------------------------------------------------------- * * Tcl_DiscardResult -- * * Frees the memory associated with an interpreter snapshot * taken by Tcl_SaveResult. If the snapshot is not * restored, this procedure must be called to discard it, * or the memory will be lost. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Tcl_DiscardResult(statePtr) Tcl_SavedResult *statePtr; /* State returned by Tcl_SaveResult. */ { TclDecrRefCount(statePtr->objResultPtr); if (statePtr->result == statePtr->appendResult) { ckfree(statePtr->appendResult); } else if (statePtr->freeProc) { if (statePtr->freeProc == TCL_DYNAMIC) { ckfree(statePtr->result); } else { (*statePtr->freeProc)(statePtr->result); } } } /* *---------------------------------------------------------------------- * * Tcl_SetResult -- * * Arrange for "string" to be the Tcl return value. * * Results: * None. * * Side effects: * interp->result is left pointing either to "string" (if "copy" is 0) * or to a copy of string. Also, the object result is reset. * *---------------------------------------------------------------------- */ void Tcl_SetResult(interp, string, freeProc) Tcl_Interp *interp; /* Interpreter with which to associate the * return value. */ register char *string; /* Value to be returned. If NULL, the * result is set to an empty string. */ Tcl_FreeProc *freeProc; /* Gives information about the string: * TCL_STATIC, TCL_VOLATILE, or the address * of a Tcl_FreeProc such as free. */ { Interp *iPtr = (Interp *) interp; int length; register Tcl_FreeProc *oldFreeProc = iPtr->freeProc; char *oldResult = iPtr->result; if (string == NULL) { iPtr->resultSpace[0] = 0; iPtr->result = iPtr->resultSpace; iPtr->freeProc = 0; } else if (freeProc == TCL_VOLATILE) { length = strlen(string); if (length > TCL_RESULT_SIZE) { iPtr->result = (char *) ckalloc((unsigned) length+1); iPtr->freeProc = TCL_DYNAMIC; } else { iPtr->result = iPtr->resultSpace; iPtr->freeProc = 0; } strcpy(iPtr->result, string); } else { iPtr->result = string; iPtr->freeProc = freeProc; } /* * If the old result was dynamically-allocated, free it up. Do it * here, rather than at the beginning, in case the new result value * was part of the old result value. */ if (oldFreeProc != 0) { if (oldFreeProc == TCL_DYNAMIC) { ckfree(oldResult); } else { (*oldFreeProc)(oldResult); } } /* * Reset the object result since we just set the string result. */ ResetObjResult(iPtr); } /* *---------------------------------------------------------------------- * * Tcl_GetStringResult -- * * Returns an interpreter's result value as a string. * * Results: * The interpreter's result as a string. * * Side effects: * If the string result is empty, the object result is moved to the * string result, then the object result is reset. * *---------------------------------------------------------------------- */ CONST char * Tcl_GetStringResult(interp) register Tcl_Interp *interp; /* Interpreter whose result to return. */ { /* * If the string result is empty, move the object result to the * string result, then reset the object result. */ if (*(interp->result) == 0) { Tcl_SetResult(interp, TclGetString(Tcl_GetObjResult(interp)), TCL_VOLATILE); } return interp->result; } /* *---------------------------------------------------------------------- * * Tcl_SetObjResult -- * * Arrange for objPtr to be an interpreter's result value. * * Results: * None. * * Side effects: * interp->objResultPtr is left pointing to the object referenced * by objPtr. The object's reference count is incremented since * there is now a new reference to it. The reference count for any * old objResultPtr value is decremented. Also, the string result * is reset. * *---------------------------------------------------------------------- */ void Tcl_SetObjResult(interp, objPtr) Tcl_Interp *interp; /* Interpreter with which to associate the * return object value. */ register Tcl_Obj *objPtr; /* Tcl object to be returned. If NULL, the * obj result is made an empty string * object. */ { register Interp *iPtr = (Interp *) interp; register Tcl_Obj *oldObjResult = iPtr->objResultPtr; iPtr->objResultPtr = objPtr; Tcl_IncrRefCount(objPtr); /* since interp result is a reference */ /* * We wait until the end to release the old object result, in case * we are setting the result to itself. */ TclDecrRefCount(oldObjResult); /* * Reset the string result since we just set the result object. */ if (iPtr->freeProc != NULL) { if (iPtr->freeProc == TCL_DYNAMIC) { ckfree(iPtr->result); } else { (*iPtr->freeProc)(iPtr->result); } iPtr->freeProc = 0; } iPtr->result = iPtr->resultSpace; iPtr->resultSpace[0] = 0; } /* *---------------------------------------------------------------------- * * Tcl_GetObjResult -- * * Returns an interpreter's result value as a Tcl object. The object's * reference count is not modified; the caller must do that if it * needs to hold on to a long-term reference to it. * * Results: * The interpreter's result as an object. * * Side effects: * If the interpreter has a non-empty string result, the result object * is either empty or stale because some procedure set interp->result * directly. If so, the string result is moved to the result object * then the string result is reset. * *---------------------------------------------------------------------- */ Tcl_Obj * Tcl_GetObjResult(interp) Tcl_Interp *interp; /* Interpreter whose result to return. */ { register Interp *iPtr = (Interp *) interp; Tcl_Obj *objResultPtr; int length; /* * If the string result is non-empty, move the string result to the * object result, then reset the string result. */ if (*(iPtr->result) != 0) { ResetObjResult(iPtr); objResultPtr = iPtr->objResultPtr; length = strlen(iPtr->result); TclInitStringRep(objResultPtr, iPtr->result, length); if (iPtr->freeProc != NULL) { if (iPtr->freeProc == TCL_DYNAMIC) { ckfree(iPtr->result); } else { (*iPtr->freeProc)(iPtr->result); } iPtr->freeProc = 0; } iPtr->result = iPtr->resultSpace; iPtr->resultSpace[0] = 0; } return iPtr->objResultPtr; } /* *---------------------------------------------------------------------- * * Tcl_AppendResultVA -- * * Append a variable number of strings onto the interpreter's string * result. * * Results: * None. * * Side effects: * The result of the interpreter given by the first argument is * extended by the strings in the va_list (up to a terminating NULL * argument). * * If the string result is empty, the object result is moved to the * string result, then the object result is reset. * *---------------------------------------------------------------------- */ void Tcl_AppendResultVA (interp, argList) Tcl_Interp *interp; /* Interpreter with which to associate the * return value. */ va_list argList; /* Variable argument list. */ { #define STATIC_LIST_SIZE 16 Interp *iPtr = (Interp *) interp; char *string, *static_list[STATIC_LIST_SIZE]; char **args = static_list; int nargs_space = STATIC_LIST_SIZE; int nargs, newSpace, i; /* * If the string result is empty, move the object result to the * string result, then reset the object result. */ if (*(iPtr->result) == 0) { Tcl_SetResult((Tcl_Interp *) iPtr, TclGetString(Tcl_GetObjResult((Tcl_Interp *) iPtr)), TCL_VOLATILE); } /* * Scan through all the arguments to see how much space is needed * and save pointers to the arguments in the args array, * reallocating as necessary. */ nargs = 0; newSpace = 0; while (1) { string = va_arg(argList, char *); if (string == NULL) { break; } if (nargs >= nargs_space) { /* * Expand the args buffer */ nargs_space += STATIC_LIST_SIZE; if (args == static_list) { args = (void *)ckalloc(nargs_space * sizeof(char *)); for (i = 0; i < nargs; ++i) { args[i] = static_list[i]; } } else { args = (void *)ckrealloc((void *)args, nargs_space * sizeof(char *)); } } newSpace += strlen(string); args[nargs++] = string; } /* * If the append buffer isn't already setup and large enough to hold * the new data, set it up. */ if ((iPtr->result != iPtr->appendResult) || (iPtr->appendResult[iPtr->appendUsed] != 0) || ((newSpace + iPtr->appendUsed) >= iPtr->appendAvl)) { SetupAppendBuffer(iPtr, newSpace); } /* * Now go through all the argument strings again, copying them into the * buffer. */ for (i = 0; i < nargs; ++i) { string = args[i]; strcpy(iPtr->appendResult + iPtr->appendUsed, string); iPtr->appendUsed += strlen(string); } /* * If we had to allocate a buffer from the heap, * free it now. */ if (args != static_list) { ckfree((void *)args); } #undef STATIC_LIST_SIZE } /* *---------------------------------------------------------------------- * * Tcl_AppendResult -- * * Append a variable number of strings onto the interpreter's string * result. * * Results: * None. * * Side effects: * The result of the interpreter given by the first argument is * extended by the strings given by the second and following arguments * (up to a terminating NULL argument). * * If the string result is empty, the object result is moved to the * string result, then the object result is reset. * *---------------------------------------------------------------------- */ void Tcl_AppendResult TCL_VARARGS_DEF(Tcl_Interp *,arg1) { Tcl_Interp *interp; va_list argList; interp = TCL_VARARGS_START(Tcl_Interp *,arg1,argList); Tcl_AppendResultVA(interp, argList); va_end(argList); } /* *---------------------------------------------------------------------- * * Tcl_AppendElement -- * * Convert a string to a valid Tcl list element and append it to the * result (which is ostensibly a list). * * Results: * None. * * Side effects: * The result in the interpreter given by the first argument is * extended with a list element converted from string. A separator * space is added before the converted list element unless the current * result is empty, contains the single character "{", or ends in " {". * * If the string result is empty, the object result is moved to the * string result, then the object result is reset. * *---------------------------------------------------------------------- */ void Tcl_AppendElement(interp, string) Tcl_Interp *interp; /* Interpreter whose result is to be * extended. */ CONST char *string; /* String to convert to list element and * add to result. */ { Interp *iPtr = (Interp *) interp; char *dst; int size; int flags; /* * If the string result is empty, move the object result to the * string result, then reset the object result. */ if (*(iPtr->result) == 0) { Tcl_SetResult(interp, TclGetString(Tcl_GetObjResult(interp)), TCL_VOLATILE); } /* * See how much space is needed, and grow the append buffer if * needed to accommodate the list element. */ size = Tcl_ScanElement(string, &flags) + 1; if ((iPtr->result != iPtr->appendResult) || (iPtr->appendResult[iPtr->appendUsed] != 0) || ((size + iPtr->appendUsed) >= iPtr->appendAvl)) { SetupAppendBuffer(iPtr, size+iPtr->appendUsed); } /* * Convert the string into a list element and copy it to the * buffer that's forming, with a space separator if needed. */ dst = iPtr->appendResult + iPtr->appendUsed; if (TclNeedSpace(iPtr->appendResult, dst)) { iPtr->appendUsed++; *dst = ' '; dst++; } iPtr->appendUsed += Tcl_ConvertElement(string, dst, flags); } /* *---------------------------------------------------------------------- * * SetupAppendBuffer -- * * This procedure makes sure that there is an append buffer properly * initialized, if necessary, from the interpreter's result, and * that it has at least enough room to accommodate newSpace new * bytes of information. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void SetupAppendBuffer(iPtr, newSpace) Interp *iPtr; /* Interpreter whose result is being set up. */ int newSpace; /* Make sure that at least this many bytes * of new information may be added. */ { int totalSpace; /* * Make the append buffer larger, if that's necessary, then copy the * result into the append buffer and make the append buffer the official * Tcl result. */ if (iPtr->result != iPtr->appendResult) { /* * If an oversized buffer was used recently, then free it up * so we go back to a smaller buffer. This avoids tying up * memory forever after a large operation. */ if (iPtr->appendAvl > 500) { ckfree(iPtr->appendResult); iPtr->appendResult = NULL; iPtr->appendAvl = 0; } iPtr->appendUsed = strlen(iPtr->result); } else if (iPtr->result[iPtr->appendUsed] != 0) { /* * Most likely someone has modified a result created by * Tcl_AppendResult et al. so that it has a different size. * Just recompute the size. */ iPtr->appendUsed = strlen(iPtr->result); } totalSpace = newSpace + iPtr->appendUsed; if (totalSpace >= iPtr->appendAvl) { char *new; if (totalSpace < 100) { totalSpace = 200; } else { totalSpace *= 2; } new = (char *) ckalloc((unsigned) totalSpace); strcpy(new, iPtr->result); if (iPtr->appendResult != NULL) { ckfree(iPtr->appendResult); } iPtr->appendResult = new; iPtr->appendAvl = totalSpace; } else if (iPtr->result != iPtr->appendResult) { strcpy(iPtr->appendResult, iPtr->result); } Tcl_FreeResult((Tcl_Interp *) iPtr); iPtr->result = iPtr->appendResult; } /* *---------------------------------------------------------------------- * * Tcl_FreeResult -- * * This procedure frees up the memory associated with an interpreter's * string result. It also resets the interpreter's result object. * Tcl_FreeResult is most commonly used when a procedure is about to * replace one result value with another. * * Results: * None. * * Side effects: * Frees the memory associated with interp's string result and sets * interp->freeProc to zero, but does not change interp->result or * clear error state. Resets interp's result object to an unshared * empty object. * *---------------------------------------------------------------------- */ void Tcl_FreeResult(interp) register Tcl_Interp *interp; /* Interpreter for which to free result. */ { register Interp *iPtr = (Interp *) interp; if (iPtr->freeProc != NULL) { if (iPtr->freeProc == TCL_DYNAMIC) { ckfree(iPtr->result); } else { (*iPtr->freeProc)(iPtr->result); } iPtr->freeProc = 0; } ResetObjResult(iPtr); } /* *---------------------------------------------------------------------- * * Tcl_ResetResult -- * * This procedure resets both the interpreter's string and object * results. * * Results: * None. * * Side effects: * It resets the result object to an unshared empty object. It * then restores the interpreter's string result area to its default * initialized state, freeing up any memory that may have been * allocated. It also clears any error information for the interpreter. * *---------------------------------------------------------------------- */ void Tcl_ResetResult(interp) register Tcl_Interp *interp; /* Interpreter for which to clear result. */ { register Interp *iPtr = (Interp *) interp; ResetObjResult(iPtr); if (iPtr->freeProc != NULL) { if (iPtr->freeProc == TCL_DYNAMIC) { ckfree(iPtr->result); } else { (*iPtr->freeProc)(iPtr->result); } iPtr->freeProc = 0; } iPtr->result = iPtr->resultSpace; iPtr->resultSpace[0] = 0; iPtr->flags &= ~(ERR_ALREADY_LOGGED | ERR_IN_PROGRESS | ERROR_CODE_SET); } /* *---------------------------------------------------------------------- * * ResetObjResult -- * * Procedure used to reset an interpreter's Tcl result object. * * Results: * None. * * Side effects: * Resets the interpreter's result object to an unshared empty string * object with ref count one. It does not clear any error information * in the interpreter. * *---------------------------------------------------------------------- */ static void ResetObjResult(iPtr) register Interp *iPtr; /* Points to the interpreter whose result * object should be reset. */ { register Tcl_Obj *objResultPtr = iPtr->objResultPtr; if (Tcl_IsShared(objResultPtr)) { TclDecrRefCount(objResultPtr); TclNewObj(objResultPtr); Tcl_IncrRefCount(objResultPtr); iPtr->objResultPtr = objResultPtr; } else { if ((objResultPtr->bytes != NULL) && (objResultPtr->bytes != tclEmptyStringRep)) { ckfree((char *) objResultPtr->bytes); } objResultPtr->bytes = tclEmptyStringRep; objResultPtr->length = 0; if ((objResultPtr->typePtr != NULL) && (objResultPtr->typePtr->freeIntRepProc != NULL)) { objResultPtr->typePtr->freeIntRepProc(objResultPtr); } objResultPtr->typePtr = (Tcl_ObjType *) NULL; } } /* *---------------------------------------------------------------------- * * Tcl_SetErrorCodeVA -- * * This procedure is called to record machine-readable information * about an error that is about to be returned. * * Results: * None. * * Side effects: * The errorCode global variable is modified to hold all of the * arguments to this procedure, in a list form with each argument * becoming one element of the list. A flag is set internally * to remember that errorCode has been set, so the variable doesn't * get set automatically when the error is returned. * *---------------------------------------------------------------------- */ void Tcl_SetErrorCodeVA (interp, argList) Tcl_Interp *interp; /* Interpreter in which to access the errorCode * variable. */ va_list argList; /* Variable argument list. */ { char *string; int flags; Interp *iPtr = (Interp *) interp; /* * Scan through the arguments one at a time, appending them to * $errorCode as list elements. */ flags = TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT; while (1) { string = va_arg(argList, char *); if (string == NULL) { break; } (void) Tcl_SetVar2((Tcl_Interp *) iPtr, "errorCode", (char *) NULL, string, flags); flags |= TCL_APPEND_VALUE; } iPtr->flags |= ERROR_CODE_SET; } /* *---------------------------------------------------------------------- * * Tcl_SetErrorCode -- * * This procedure is called to record machine-readable information * about an error that is about to be returned. * * Results: * None. * * Side effects: * The errorCode global variable is modified to hold all of the * arguments to this procedure, in a list form with each argument * becoming one element of the list. A flag is set internally * to remember that errorCode has been set, so the variable doesn't * get set automatically when the error is returned. * *---------------------------------------------------------------------- */ /* VARARGS2 */ void Tcl_SetErrorCode TCL_VARARGS_DEF(Tcl_Interp *,arg1) { Tcl_Interp *interp; va_list argList; /* * Scan through the arguments one at a time, appending them to * $errorCode as list elements. */ interp = TCL_VARARGS_START(Tcl_Interp *,arg1,argList); Tcl_SetErrorCodeVA(interp, argList); va_end(argList); } /* *---------------------------------------------------------------------- * * Tcl_SetObjErrorCode -- * * This procedure is called to record machine-readable information * about an error that is about to be returned. The caller should * build a list object up and pass it to this routine. * * Results: * None. * * Side effects: * The errorCode global variable is modified to be the new value. * A flag is set internally to remember that errorCode has been * set, so the variable doesn't get set automatically when the * error is returned. * *---------------------------------------------------------------------- */ void Tcl_SetObjErrorCode(interp, errorObjPtr) Tcl_Interp *interp; Tcl_Obj *errorObjPtr; { Interp *iPtr; iPtr = (Interp *) interp; Tcl_SetVar2Ex(interp, "errorCode", NULL, errorObjPtr, TCL_GLOBAL_ONLY); iPtr->flags |= ERROR_CODE_SET; } /* *------------------------------------------------------------------------- * * TclTransferResult -- * * Copy the result (and error information) from one interp to * another. Used when one interp has caused another interp to * evaluate a script and then wants to transfer the results back * to itself. * * This routine copies the string reps of the result and error * information. It does not simply increment the refcounts of the * result and error information objects themselves. * It is not legal to exchange objects between interps, because an * object may be kept alive by one interp, but have an internal rep * that is only valid while some other interp is alive. * * Results: * The target interp's result is set to a copy of the source interp's * result. The source's error information "$errorInfo" may be * appended to the target's error information and the source's error * code "$errorCode" may be stored in the target's error code. * * Side effects: * None. * *------------------------------------------------------------------------- */ void TclTransferResult(sourceInterp, result, targetInterp) Tcl_Interp *sourceInterp; /* Interp whose result and error information * should be moved to the target interp. * After moving result, this interp's result * is reset. */ int result; /* TCL_OK if just the result should be copied, * TCL_ERROR if both the result and error * information should be copied. */ Tcl_Interp *targetInterp; /* Interp where result and error information * should be stored. If source and target * are the same, nothing is done. */ { Interp *iPtr; Tcl_Obj *objPtr; if (sourceInterp == targetInterp) { return; } if (result == TCL_ERROR) { /* * An error occurred, so transfer error information from the source * interpreter to the target interpreter. Setting the flags tells * the target interp that it has inherited a partial traceback * chain, not just a simple error message. */ iPtr = (Interp *) sourceInterp; if ((iPtr->flags & ERR_ALREADY_LOGGED) == 0) { Tcl_AddErrorInfo(sourceInterp, ""); } iPtr->flags &= ~(ERR_ALREADY_LOGGED); Tcl_ResetResult(targetInterp); objPtr = Tcl_GetVar2Ex(sourceInterp, "errorInfo", NULL, TCL_GLOBAL_ONLY); if (objPtr) { Tcl_SetVar2Ex(targetInterp, "errorInfo", NULL, objPtr, TCL_GLOBAL_ONLY); ((Interp *) targetInterp)->flags |= ERR_IN_PROGRESS; } objPtr = Tcl_GetVar2Ex(sourceInterp, "errorCode", NULL, TCL_GLOBAL_ONLY); if (objPtr) { Tcl_SetObjErrorCode(targetInterp, objPtr); } } ((Interp *) targetInterp)->returnCode = ((Interp *) sourceInterp)->returnCode; Tcl_SetObjResult(targetInterp, Tcl_GetObjResult(sourceInterp)); Tcl_ResetResult(sourceInterp); } tcl8.4.20/generic/tclVar.c0000644003604700454610000050310412144442333013723 0ustar dgp771div/* * tclVar.c -- * * This file contains routines that implement Tcl variables * (both scalars and arrays). * * The implementation of arrays is modelled after an initial * implementation by Mark Diekhans and Karl Lehenbauer. * * Copyright (c) 1987-1994 The Regents of the University of California. * Copyright (c) 1994-1997 Sun Microsystems, Inc. * Copyright (c) 1998-1999 by Scriptics Corporation. * Copyright (c) 2001 by Kevin B. Kenny. All rights reserved. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" /* * The strings below are used to indicate what went wrong when a * variable access is denied. */ static CONST char *noSuchVar = "no such variable"; static CONST char *isArray = "variable is array"; static CONST char *needArray = "variable isn't array"; static CONST char *noSuchElement = "no such element in array"; static CONST char *danglingElement = "upvar refers to element in deleted array"; static CONST char *danglingVar = "upvar refers to variable in deleted namespace"; static CONST char *badNamespace = "parent namespace doesn't exist"; static CONST char *missingName = "missing variable name"; static CONST char *isArrayElement = "name refers to an element in an array"; /* * Forward references to procedures defined later in this file: */ static int CallVarTraces _ANSI_ARGS_((Interp *iPtr, Var *arrayPtr, Var *varPtr, CONST char *part1, CONST char *part2, int flags, CONST int leaveErrMsg)); static void CleanupVar _ANSI_ARGS_((Var *varPtr, Var *arrayPtr)); static void DeleteSearches _ANSI_ARGS_((Var *arrayVarPtr)); static void DeleteArray _ANSI_ARGS_((Interp *iPtr, CONST char *arrayName, Var *varPtr, int flags)); static void DisposeTraceResult _ANSI_ARGS_((int flags, char *result)); static int ObjMakeUpvar _ANSI_ARGS_((Tcl_Interp *interp, CallFrame *framePtr, Tcl_Obj *otherP1Ptr, CONST char *otherP2, CONST int otherFlags, CONST char *myName, int myFlags, int index)); static Var * NewVar _ANSI_ARGS_((void)); static ArraySearch * ParseSearchId _ANSI_ARGS_((Tcl_Interp *interp, CONST Var *varPtr, CONST char *varName, Tcl_Obj *handleObj)); static void VarErrMsg _ANSI_ARGS_((Tcl_Interp *interp, CONST char *part1, CONST char *part2, CONST char *operation, CONST char *reason)); static int SetArraySearchObj _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr)); static void UnsetVarStruct _ANSI_ARGS_((Var *varPtr, Var *arrayPtr, Interp *iPtr, CONST char *part1, CONST char *part2, int flags)); /* * Functions defined in this file that may be exported in the future * for use by the bytecode compiler and engine or to the public interface. */ Var * TclLookupSimpleVar _ANSI_ARGS_((Tcl_Interp *interp, CONST char *varName, int flags, CONST int create, CONST char **errMsgPtr, int *indexPtr)); int TclObjUnsetVar2 _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *part1Ptr, CONST char *part2, int flags)); static Tcl_FreeInternalRepProc FreeLocalVarName; static Tcl_DupInternalRepProc DupLocalVarName; static Tcl_UpdateStringProc UpdateLocalVarName; static Tcl_FreeInternalRepProc FreeNsVarName; static Tcl_DupInternalRepProc DupNsVarName; static Tcl_FreeInternalRepProc FreeParsedVarName; static Tcl_DupInternalRepProc DupParsedVarName; static Tcl_UpdateStringProc UpdateParsedVarName; /* * Types of Tcl_Objs used to cache variable lookups. * * * localVarName - INTERNALREP DEFINITION: * twoPtrValue.ptr1 = pointer to the corresponding Proc * twoPtrValue.ptr2 = index into locals table * * nsVarName - INTERNALREP DEFINITION: * twoPtrValue.ptr1: pointer to the namespace containing the * reference * twoPtrValue.ptr2: pointer to the corresponding Var * * parsedVarName - INTERNALREP DEFINITION: * twoPtrValue.ptr1 = pointer to the array name Tcl_Obj, * or NULL if it is a scalar variable * twoPtrValue.ptr2 = pointer to the element name string * (owned by this Tcl_Obj), or NULL if * it is a scalar variable */ static Tcl_ObjType tclLocalVarNameType = { "localVarName", FreeLocalVarName, DupLocalVarName, UpdateLocalVarName, NULL }; static Tcl_ObjType tclNsVarNameType = { "namespaceVarName", FreeNsVarName, DupNsVarName, NULL, NULL }; static Tcl_ObjType tclParsedVarNameType = { "parsedVarName", FreeParsedVarName, DupParsedVarName, UpdateParsedVarName, NULL }; /* * Type of Tcl_Objs used to speed up array searches. * * INTERNALREP DEFINITION: * twoPtrValue.ptr1 = searchIdNumber as offset from (char*)NULL * twoPtrValue.ptr2 = variableNameStartInString as offset from (char*)NULL * * Note that the value stored in ptr2 is the offset into the string of * the start of the variable name and not the address of the variable * name itself, as this can be safely copied. */ Tcl_ObjType tclArraySearchType = { "array search", NULL, NULL, NULL, SetArraySearchObj }; /* *---------------------------------------------------------------------- * * TclLookupVar -- * * This procedure is used to locate a variable given its name(s). It * has been mostly superseded by TclObjLookupVar, it is now only used * by the string-based interfaces. It is kept in tcl8.4 mainly because * it is in the internal stubs table, so that some extension may be * calling it. * * Results: * The return value is a pointer to the variable structure indicated by * part1 and part2, or NULL if the variable couldn't be found. If the * variable is found, *arrayPtrPtr is filled in with the address of the * variable structure for the array that contains the variable (or NULL * if the variable is a scalar). If the variable can't be found and * either createPart1 or createPart2 are 1, a new as-yet-undefined * (VAR_UNDEFINED) variable structure is created, entered into a hash * table, and returned. * * If the variable isn't found and creation wasn't specified, or some * other error occurs, NULL is returned and an error message is left in * the interp's result if TCL_LEAVE_ERR_MSG is set in flags. * * Note: it's possible for the variable returned to be VAR_UNDEFINED * even if createPart1 or createPart2 are 1 (these only cause the hash * table entry or array to be created). For example, the variable might * be a global that has been unset but is still referenced by a * procedure, or a variable that has been unset but it only being kept * in existence (if VAR_UNDEFINED) by a trace. * * Side effects: * New hashtable entries may be created if createPart1 or createPart2 * are 1. * *---------------------------------------------------------------------- */ Var * TclLookupVar(interp, part1, part2, flags, msg, createPart1, createPart2, arrayPtrPtr) Tcl_Interp *interp; /* Interpreter to use for lookup. */ CONST char *part1; /* If part2 isn't NULL, this is the name of * an array. Otherwise, this * is a full variable name that could * include a parenthesized array element. */ CONST char *part2; /* Name of element within array, or NULL. */ int flags; /* Only TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY, * and TCL_LEAVE_ERR_MSG bits matter. */ CONST char *msg; /* Verb to use in error messages, e.g. * "read" or "set". Only needed if * TCL_LEAVE_ERR_MSG is set in flags. */ int createPart1; /* If 1, create hash table entry for part 1 * of name, if it doesn't already exist. If * 0, return error if it doesn't exist. */ int createPart2; /* If 1, create hash table entry for part 2 * of name, if it doesn't already exist. If * 0, return error if it doesn't exist. */ Var **arrayPtrPtr; /* If the name refers to an element of an * array, *arrayPtrPtr gets filled in with * address of array variable. Otherwise * this is set to NULL. */ { Var *varPtr; CONST char *elName; /* Name of array element or NULL; may be * same as part2, or may be openParen+1. */ int openParen, closeParen; /* If this procedure parses a name into * array and index, these are the offsets to * the parens around the index. Otherwise * they are -1. */ register CONST char *p; CONST char *errMsg = NULL; int index; #define VAR_NAME_BUF_SIZE 26 char buffer[VAR_NAME_BUF_SIZE]; char *newVarName = buffer; varPtr = NULL; *arrayPtrPtr = NULL; openParen = closeParen = -1; /* * Parse part1 into array name and index. * Always check if part1 is an array element name and allow it only if * part2 is not given. * (if one does not care about creating array elements that can't be used * from tcl, and prefer slightly better performance, one can put * the following in an if (part2 == NULL) { ... } block and remove * the part2's test and error reporting or move that code in array set) */ elName = part2; for (p = part1; *p ; p++) { if (*p == '(') { openParen = p - part1; do { p++; } while (*p != '\0'); p--; if (*p == ')') { if (part2 != NULL) { if (flags & TCL_LEAVE_ERR_MSG) { VarErrMsg(interp, part1, part2, msg, needArray); } return NULL; } closeParen = p - part1; } else { openParen = -1; } break; } } if (openParen != -1) { if (closeParen >= VAR_NAME_BUF_SIZE) { newVarName = ckalloc((unsigned int) (closeParen+1)); } memcpy(newVarName, part1, (unsigned int) closeParen); newVarName[openParen] = '\0'; newVarName[closeParen] = '\0'; part1 = newVarName; elName = newVarName + openParen + 1; } varPtr = TclLookupSimpleVar(interp, part1, flags, createPart1, &errMsg, &index); if (varPtr == NULL) { if ((errMsg != NULL) && (flags & TCL_LEAVE_ERR_MSG)) { VarErrMsg(interp, part1, elName, msg, errMsg); } } else { while (TclIsVarLink(varPtr)) { varPtr = varPtr->value.linkPtr; } if (elName != NULL) { *arrayPtrPtr = varPtr; varPtr = TclLookupArrayElement(interp, part1, elName, flags, msg, createPart1, createPart2, varPtr); } } if (newVarName != buffer) { ckfree(newVarName); } return varPtr; #undef VAR_NAME_BUF_SIZE } /* *---------------------------------------------------------------------- * * TclObjLookupVar -- * * This procedure is used by virtually all of the variable code to * locate a variable given its name(s). The parsing into array/element * components and (if possible) the lookup results are cached in * part1Ptr, which is converted to one of the varNameTypes. * * Results: * The return value is a pointer to the variable structure indicated by * part1Ptr and part2, or NULL if the variable couldn't be found. If * the variable is found, *arrayPtrPtr is filled with the address of the * variable structure for the array that contains the variable (or NULL * if the variable is a scalar). If the variable can't be found and * either createPart1 or createPart2 are 1, a new as-yet-undefined * (VAR_UNDEFINED) variable structure is created, entered into a hash * table, and returned. * * If the variable isn't found and creation wasn't specified, or some * other error occurs, NULL is returned and an error message is left in * the interp's result if TCL_LEAVE_ERR_MSG is set in flags. * * Note: it's possible for the variable returned to be VAR_UNDEFINED * even if createPart1 or createPart2 are 1 (these only cause the hash * table entry or array to be created). For example, the variable might * be a global that has been unset but is still referenced by a * procedure, or a variable that has been unset but it only being kept * in existence (if VAR_UNDEFINED) by a trace. * * Side effects: * New hashtable entries may be created if createPart1 or createPart2 * are 1. * The object part1Ptr is converted to one of tclLocalVarNameType, * tclNsVarNameType or tclParsedVarNameType and caches as much of the * lookup as it can. * *---------------------------------------------------------------------- */ Var * TclObjLookupVar(interp, part1Ptr, part2, flags, msg, createPart1, createPart2, arrayPtrPtr) Tcl_Interp *interp; /* Interpreter to use for lookup. */ register Tcl_Obj *part1Ptr; /* If part2 isn't NULL, this is the name * of an array. Otherwise, this is a full * variable name that could include a parenthesized * array element. */ CONST char *part2; /* Name of element within array, or NULL. */ int flags; /* Only TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY, * and TCL_LEAVE_ERR_MSG bits matter. */ CONST char *msg; /* Verb to use in error messages, e.g. * "read" or "set". Only needed if * TCL_LEAVE_ERR_MSG is set in flags. */ CONST int createPart1; /* If 1, create hash table entry for part 1 * of name, if it doesn't already exist. If * 0, return error if it doesn't exist. */ CONST int createPart2; /* If 1, create hash table entry for part 2 * of name, if it doesn't already exist. If * 0, return error if it doesn't exist. */ Var **arrayPtrPtr; /* If the name refers to an element of an * array, *arrayPtrPtr gets filled in with * address of array variable. Otherwise * this is set to NULL. */ { Interp *iPtr = (Interp *) interp; register Var *varPtr; /* Points to the variable's in-frame Var * structure. */ char *part1; int index, len1, len2; int parsed = 0; Tcl_Obj *objPtr; Tcl_ObjType *typePtr = part1Ptr->typePtr; CONST char *errMsg = NULL; CallFrame *varFramePtr = iPtr->varFramePtr; Namespace *nsPtr; /* * If part1Ptr is a tclParsedVarNameType, separate it into the * pre-parsed parts. */ *arrayPtrPtr = NULL; if (typePtr == &tclParsedVarNameType) { if (part1Ptr->internalRep.twoPtrValue.ptr1 != NULL) { if (part2 != NULL) { /* * ERROR: part1Ptr is already an array element, cannot * specify a part2. */ if (flags & TCL_LEAVE_ERR_MSG) { part1 = TclGetString(part1Ptr); VarErrMsg(interp, part1, part2, msg, needArray); } return NULL; } part2 = (char *) part1Ptr->internalRep.twoPtrValue.ptr2; part1Ptr = (Tcl_Obj *) part1Ptr->internalRep.twoPtrValue.ptr1; typePtr = part1Ptr->typePtr; } parsed = 1; } part1 = Tcl_GetStringFromObj(part1Ptr, &len1); nsPtr = ((varFramePtr == NULL)? iPtr->globalNsPtr : varFramePtr->nsPtr); if (nsPtr->varResProc != NULL || iPtr->resolverPtr != NULL) { goto doParse; } if (typePtr == &tclLocalVarNameType) { Proc *procPtr = (Proc *) part1Ptr->internalRep.twoPtrValue.ptr1; int localIndex = (int) part1Ptr->internalRep.twoPtrValue.ptr2; int useLocal; useLocal = ((varFramePtr != NULL) && varFramePtr->isProcCallFrame && !(flags & (TCL_GLOBAL_ONLY | TCL_NAMESPACE_ONLY))); if (useLocal && (procPtr == varFramePtr->procPtr)) { /* * part1Ptr points to an indexed local variable of the * correct procedure: use the cached value. */ varPtr = &(varFramePtr->compiledLocals[localIndex]); goto donePart1; } goto doneParsing; } else if (typePtr == &tclNsVarNameType) { Namespace *cachedNsPtr; int useGlobal, useReference; varPtr = (Var *) part1Ptr->internalRep.twoPtrValue.ptr2; cachedNsPtr = (Namespace *) part1Ptr->internalRep.twoPtrValue.ptr1; useGlobal = (cachedNsPtr == iPtr->globalNsPtr) && ((flags & TCL_GLOBAL_ONLY) || ((*part1 == ':') && (*(part1+1) == ':')) || (varFramePtr == NULL) || (!varFramePtr->isProcCallFrame && (nsPtr == iPtr->globalNsPtr))); useReference = useGlobal || ((cachedNsPtr == nsPtr) && ((flags & TCL_NAMESPACE_ONLY) || (varFramePtr && !varFramePtr->isProcCallFrame && !(flags & TCL_GLOBAL_ONLY) /* careful: an undefined ns variable could * be hiding a valid global reference. */ && !(varPtr->flags & VAR_UNDEFINED)))); if (useReference && (varPtr->hPtr != NULL)) { /* * A straight global or namespace reference, use it. It isn't * so simple to deal with 'implicit' namespace references, i.e., * those where the reference could be to either a namespace * or a global variable. Those we lookup again. * * If (varPtr->hPtr == NULL), this might be a reference to a * variable in a deleted namespace, kept alive by e.g. part1Ptr. * We could conceivably be so unlucky that a new namespace was * created at the same address as the deleted one, so to be * safe we test for a valid hPtr. */ goto donePart1; } goto doneParsing; } doParse: if (!parsed && (*(part1 + len1 - 1) == ')')) { /* * part1Ptr is possibly an unparsed array element. */ register int i; char *newPart2; len2 = -1; for (i = 0; i < len1; i++) { if (*(part1 + i) == '(') { if (part2 != NULL) { if (flags & TCL_LEAVE_ERR_MSG) { VarErrMsg(interp, part1, part2, msg, needArray); } } /* * part1Ptr points to an array element; first copy * the element name to a new string part2. */ part2 = part1 + i + 1; len2 = len1 - i - 2; len1 = i; newPart2 = ckalloc((unsigned int) (len2+1)); memcpy(newPart2, part2, (unsigned int) len2); *(newPart2+len2) = '\0'; part2 = newPart2; /* * Free the internal rep of the original part1Ptr, now * renamed objPtr, and set it to tclParsedVarNameType. */ objPtr = part1Ptr; if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) { typePtr->freeIntRepProc(objPtr); } objPtr->typePtr = &tclParsedVarNameType; /* * Define a new string object to hold the new part1Ptr, i.e., * the array name. Set the internal rep of objPtr, reset * typePtr and part1 to contain the references to the * array name. */ part1Ptr = Tcl_NewStringObj(part1, len1); Tcl_IncrRefCount(part1Ptr); objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) part1Ptr; objPtr->internalRep.twoPtrValue.ptr2 = (VOID *) part2; typePtr = part1Ptr->typePtr; part1 = TclGetString(part1Ptr); break; } } } doneParsing: /* * part1Ptr is not an array element; look it up, and convert * it to one of the cached types if possible. */ if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) { typePtr->freeIntRepProc(part1Ptr); part1Ptr->typePtr = NULL; } varPtr = TclLookupSimpleVar(interp, part1, flags, createPart1, &errMsg, &index); if (varPtr == NULL) { if ((errMsg != NULL) && (flags & TCL_LEAVE_ERR_MSG)) { VarErrMsg(interp, part1, part2, msg, errMsg); } return NULL; } /* * Cache the newly found variable if possible. */ if (index >= 0) { /* * An indexed local variable. */ Proc *procPtr = ((Interp *) interp)->varFramePtr->procPtr; part1Ptr->typePtr = &tclLocalVarNameType; procPtr->refCount++; part1Ptr->internalRep.twoPtrValue.ptr1 = (VOID *) procPtr; part1Ptr->internalRep.twoPtrValue.ptr2 = (VOID *) index; #if 0 /* * TEMPORARYLY DISABLED tclNsVarNameType * * This optimisation will hopefully be turned back on soon. * Miguel Sofer, 2004-05-22 */ } else if (index > -3) { /* * A cacheable namespace or global variable. */ Namespace *nsPtr; nsPtr = ((index == -1)? iPtr->globalNsPtr : varFramePtr->nsPtr); varPtr->refCount++; part1Ptr->typePtr = &tclNsVarNameType; part1Ptr->internalRep.twoPtrValue.ptr1 = (VOID *) nsPtr; part1Ptr->internalRep.twoPtrValue.ptr2 = (VOID *) varPtr; #endif } else { /* * At least mark part1Ptr as already parsed. */ part1Ptr->typePtr = &tclParsedVarNameType; part1Ptr->internalRep.twoPtrValue.ptr1 = NULL; part1Ptr->internalRep.twoPtrValue.ptr2 = NULL; } donePart1: #if 0 if (varPtr == NULL) { if (flags & TCL_LEAVE_ERR_MSG) { part1 = TclGetString(part1Ptr); VarErrMsg(interp, part1, part2, msg, "Cached variable reference is NULL."); } return NULL; } #endif while (TclIsVarLink(varPtr)) { varPtr = varPtr->value.linkPtr; } if (part2 != NULL) { /* * Array element sought: look it up. */ part1 = TclGetString(part1Ptr); *arrayPtrPtr = varPtr; varPtr = TclLookupArrayElement(interp, part1, part2, flags, msg, createPart1, createPart2, varPtr); } return varPtr; } /* * This flag bit should not interfere with TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY, * or TCL_LEAVE_ERR_MSG; it signals that the variable lookup is performed for * upvar (or similar) purposes, with slightly different rules: * - Bug #696893 - variable is either proc-local or in the current * namespace; never follow the second (global) resolution path * - Bug #631741 - do not use special namespace or interp resolvers */ #define LOOKUP_FOR_UPVAR 0x40000 /* *---------------------------------------------------------------------- * * TclLookupSimpleVar -- * * This procedure is used by to locate a simple variable (i.e., not * an array element) given its name. * * Results: * The return value is a pointer to the variable structure indicated by * varName, or NULL if the variable couldn't be found. If the variable * can't be found and create is 1, a new as-yet-undefined (VAR_UNDEFINED) * variable structure is created, entered into a hash table, and returned. * * If the current CallFrame corresponds to a proc and the variable found is * one of the compiledLocals, its index is placed in *indexPtr. Otherwise, * *indexPtr will be set to (according to the needs of TclObjLookupVar): * -1 a global reference * -2 a reference to a namespace variable * -3 a non-cachable reference, i.e., one of: * . non-indexed local var * . a reference of unknown origin; * . resolution by a namespace or interp resolver * * If the variable isn't found and creation wasn't specified, or some * other error occurs, NULL is returned and the corresponding error * message is left in *errMsgPtr. * * Note: it's possible for the variable returned to be VAR_UNDEFINED * even if create is 1 (this only causes the hash table entry to be * created). For example, the variable might be a global that has been * unset but is still referenced by a procedure, or a variable that has * been unset but it only being kept in existence (if VAR_UNDEFINED) by * a trace. * * Side effects: * A new hashtable entry may be created if create is 1. * *---------------------------------------------------------------------- */ Var * TclLookupSimpleVar(interp, varName, flags, create, errMsgPtr, indexPtr) Tcl_Interp *interp; /* Interpreter to use for lookup. */ CONST char *varName; /* This is a simple variable name that could * representa scalar or an array. */ int flags; /* Only TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY, * LOOKUP_FOR_UPVAR and TCL_LEAVE_ERR_MSG bits * matter. */ CONST int create; /* If 1, create hash table entry for varname, * if it doesn't already exist. If 0, return * error if it doesn't exist. */ CONST char **errMsgPtr; int *indexPtr; { Interp *iPtr = (Interp *) interp; CallFrame *varFramePtr = iPtr->varFramePtr; /* Points to the procedure call frame whose * variables are currently in use. Same as * the current procedure's frame, if any, * unless an "uplevel" is executing. */ Tcl_HashTable *tablePtr; /* Points to the hashtable, if any, in which * to look up the variable. */ Tcl_Var var; /* Used to search for global names. */ Var *varPtr; /* Points to the Var structure returned for * the variable. */ Namespace *varNsPtr, *cxtNsPtr, *dummy1Ptr, *dummy2Ptr; ResolverScheme *resPtr; Tcl_HashEntry *hPtr; int new, i, result; varPtr = NULL; varNsPtr = NULL; /* set non-NULL if a nonlocal variable */ *indexPtr = -3; if ((flags & TCL_GLOBAL_ONLY) || iPtr->varFramePtr == NULL) { cxtNsPtr = iPtr->globalNsPtr; } else { cxtNsPtr = iPtr->varFramePtr->nsPtr; } /* * If this namespace has a variable resolver, then give it first * crack at the variable resolution. It may return a Tcl_Var * value, it may signal to continue onward, or it may signal * an error. */ if ((cxtNsPtr->varResProc != NULL || iPtr->resolverPtr != NULL) && !(flags & LOOKUP_FOR_UPVAR)) { resPtr = iPtr->resolverPtr; if (cxtNsPtr->varResProc) { result = (*cxtNsPtr->varResProc)(interp, varName, (Tcl_Namespace *) cxtNsPtr, flags, &var); } else { result = TCL_CONTINUE; } while (result == TCL_CONTINUE && resPtr) { if (resPtr->varResProc) { result = (*resPtr->varResProc)(interp, varName, (Tcl_Namespace *) cxtNsPtr, flags, &var); } resPtr = resPtr->nextPtr; } if (result == TCL_OK) { varPtr = (Var *) var; return varPtr; } else if (result != TCL_CONTINUE) { return NULL; } } /* * Look up varName. Look it up as either a namespace variable or as a * local variable in a procedure call frame (varFramePtr). * Interpret varName as a namespace variable if: * 1) so requested by a TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY flag, * 2) there is no active frame (we're at the global :: scope), * 3) the active frame was pushed to define the namespace context * for a "namespace eval" or "namespace inscope" command, * 4) the name has namespace qualifiers ("::"s). * Otherwise, if varName is a local variable, search first in the * frame's array of compiler-allocated local variables, then in its * hashtable for runtime-created local variables. * * If create and the variable isn't found, create the variable and, * if necessary, create varFramePtr's local var hashtable. */ if (((flags & (TCL_GLOBAL_ONLY | TCL_NAMESPACE_ONLY)) != 0) || (varFramePtr == NULL) || !varFramePtr->isProcCallFrame || (strstr(varName, "::") != NULL)) { CONST char *tail; int lookGlobal; lookGlobal = (flags & TCL_GLOBAL_ONLY) || (cxtNsPtr == iPtr->globalNsPtr) || ((*varName == ':') && (*(varName+1) == ':')); if (lookGlobal) { *indexPtr = -1; flags = (flags | TCL_GLOBAL_ONLY) & ~(TCL_NAMESPACE_ONLY|LOOKUP_FOR_UPVAR); } else { if (flags & LOOKUP_FOR_UPVAR) { flags = (flags | TCL_NAMESPACE_ONLY) & ~LOOKUP_FOR_UPVAR; } if (flags & TCL_NAMESPACE_ONLY) { *indexPtr = -2; } } /* * Don't pass TCL_LEAVE_ERR_MSG, we may yet create the variable, * or otherwise generate our own error! */ var = Tcl_FindNamespaceVar(interp, varName, (Tcl_Namespace *) cxtNsPtr, flags & ~TCL_LEAVE_ERR_MSG); if (var != (Tcl_Var) NULL) { varPtr = (Var *) var; } if (varPtr == NULL) { if (create) { /* var wasn't found so create it */ TclGetNamespaceForQualName(interp, varName, cxtNsPtr, flags, &varNsPtr, &dummy1Ptr, &dummy2Ptr, &tail); if (varNsPtr == NULL) { *errMsgPtr = badNamespace; return NULL; } if (tail == NULL) { *errMsgPtr = missingName; return NULL; } hPtr = Tcl_CreateHashEntry(&varNsPtr->varTable, tail, &new); varPtr = NewVar(); Tcl_SetHashValue(hPtr, varPtr); varPtr->hPtr = hPtr; varPtr->nsPtr = varNsPtr; if ((lookGlobal) || (varNsPtr == NULL)) { /* * The variable was created starting from the global * namespace: a global reference is returned even if * it wasn't explicitly requested. */ *indexPtr = -1; } else { *indexPtr = -2; } } else { /* var wasn't found and not to create it */ *errMsgPtr = noSuchVar; return NULL; } } } else { /* local var: look in frame varFramePtr */ Proc *procPtr = varFramePtr->procPtr; int localCt = procPtr->numCompiledLocals; CompiledLocal *localPtr = procPtr->firstLocalPtr; Var *localVarPtr = varFramePtr->compiledLocals; int varNameLen = strlen(varName); for (i = 0; i < localCt; i++) { if (!TclIsVarTemporary(localPtr)) { register char *localName = localVarPtr->name; if ((varName[0] == localName[0]) && (varNameLen == localPtr->nameLength) && (strcmp(varName, localName) == 0)) { *indexPtr = i; return localVarPtr; } } localVarPtr++; localPtr = localPtr->nextPtr; } tablePtr = varFramePtr->varTablePtr; if (create) { if (tablePtr == NULL) { tablePtr = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable)); Tcl_InitHashTable(tablePtr, TCL_STRING_KEYS); varFramePtr->varTablePtr = tablePtr; } hPtr = Tcl_CreateHashEntry(tablePtr, varName, &new); if (new) { varPtr = NewVar(); Tcl_SetHashValue(hPtr, varPtr); varPtr->hPtr = hPtr; varPtr->nsPtr = NULL; /* a local variable */ } else { varPtr = (Var *) Tcl_GetHashValue(hPtr); } } else { hPtr = NULL; if (tablePtr != NULL) { hPtr = Tcl_FindHashEntry(tablePtr, varName); } if (hPtr == NULL) { *errMsgPtr = noSuchVar; return NULL; } varPtr = (Var *) Tcl_GetHashValue(hPtr); } } return varPtr; } /* *---------------------------------------------------------------------- * * TclLookupArrayElement -- * * This procedure is used to locate a variable which is in an array's * hashtable given a pointer to the array's Var structure and the * element's name. * * Results: * The return value is a pointer to the variable structure , or NULL if * the variable couldn't be found. * * If arrayPtr points to a variable that isn't an array and createPart1 * is 1, the corresponding variable will be converted to an array. * Otherwise, NULL is returned and an error message is left in * the interp's result if TCL_LEAVE_ERR_MSG is set in flags. * * If the variable is not found and createPart2 is 1, the variable is * created. Otherwise, NULL is returned and an error message is left in * the interp's result if TCL_LEAVE_ERR_MSG is set in flags. * * Note: it's possible for the variable returned to be VAR_UNDEFINED * even if createPart1 or createPart2 are 1 (these only cause the hash * table entry or array to be created). For example, the variable might * be a global that has been unset but is still referenced by a * procedure, or a variable that has been unset but it only being kept * in existence (if VAR_UNDEFINED) by a trace. * * Side effects: * The variable at arrayPtr may be converted to be an array if * createPart1 is 1. A new hashtable entry may be created if createPart2 * is 1. * *---------------------------------------------------------------------- */ Var * TclLookupArrayElement(interp, arrayName, elName, flags, msg, createArray, createElem, arrayPtr) Tcl_Interp *interp; /* Interpreter to use for lookup. */ CONST char *arrayName; /* This is the name of the array. */ CONST char *elName; /* Name of element within array. */ CONST int flags; /* Only TCL_LEAVE_ERR_MSG bit matters. */ CONST char *msg; /* Verb to use in error messages, e.g. * "read" or "set". Only needed if * TCL_LEAVE_ERR_MSG is set in flags. */ CONST int createArray; /* If 1, transform arrayName to be an array * if it isn't one yet and the transformation * is possible. If 0, return error if it * isn't already an array. */ CONST int createElem; /* If 1, create hash table entry for the * element, if it doesn't already exist. If * 0, return error if it doesn't exist. */ Var *arrayPtr; /* Pointer to the array's Var structure. */ { Tcl_HashEntry *hPtr; int new; Var *varPtr; /* * We're dealing with an array element. Make sure the variable is an * array and look up the element (create the element if desired). */ if (TclIsVarUndefined(arrayPtr) && !TclIsVarArrayElement(arrayPtr)) { if (!createArray) { if (flags & TCL_LEAVE_ERR_MSG) { VarErrMsg(interp, arrayName, elName, msg, noSuchVar); } return NULL; } /* * Make sure we are not resurrecting a namespace variable from a * deleted namespace! */ if ((arrayPtr->flags & VAR_IN_HASHTABLE) && (arrayPtr->hPtr == NULL)) { if (flags & TCL_LEAVE_ERR_MSG) { VarErrMsg(interp, arrayName, elName, msg, danglingVar); } return NULL; } TclSetVarArray(arrayPtr); TclClearVarUndefined(arrayPtr); arrayPtr->value.tablePtr = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable)); Tcl_InitHashTable(arrayPtr->value.tablePtr, TCL_STRING_KEYS); } else if (!TclIsVarArray(arrayPtr)) { if (flags & TCL_LEAVE_ERR_MSG) { VarErrMsg(interp, arrayName, elName, msg, needArray); } return NULL; } if (createElem) { hPtr = Tcl_CreateHashEntry(arrayPtr->value.tablePtr, elName, &new); if (new) { if (arrayPtr->searchPtr != NULL) { DeleteSearches(arrayPtr); } varPtr = NewVar(); Tcl_SetHashValue(hPtr, varPtr); varPtr->hPtr = hPtr; varPtr->nsPtr = arrayPtr->nsPtr; TclSetVarArrayElement(varPtr); } } else { hPtr = Tcl_FindHashEntry(arrayPtr->value.tablePtr, elName); if (hPtr == NULL) { if (flags & TCL_LEAVE_ERR_MSG) { VarErrMsg(interp, arrayName, elName, msg, noSuchElement); } return NULL; } } return (Var *) Tcl_GetHashValue(hPtr); } /* *---------------------------------------------------------------------- * * Tcl_GetVar -- * * Return the value of a Tcl variable as a string. * * Results: * The return value points to the current value of varName as a string. * If the variable is not defined or can't be read because of a clash * in array usage then a NULL pointer is returned and an error message * is left in the interp's result if the TCL_LEAVE_ERR_MSG flag is set. * Note: the return value is only valid up until the next change to the * variable; if you depend on the value lasting longer than that, then * make yourself a private copy. * * Side effects: * None. * *---------------------------------------------------------------------- */ #undef Tcl_GetVar CONST char * Tcl_GetVar(interp, varName, flags) Tcl_Interp *interp; /* Command interpreter in which varName is * to be looked up. */ CONST char *varName; /* Name of a variable in interp. */ int flags; /* OR-ed combination of TCL_GLOBAL_ONLY, * TCL_NAMESPACE_ONLY or TCL_LEAVE_ERR_MSG * bits. */ { return Tcl_GetVar2(interp, varName, (char *) NULL, flags); } /* *---------------------------------------------------------------------- * * Tcl_GetVar2 -- * * Return the value of a Tcl variable as a string, given a two-part * name consisting of array name and element within array. * * Results: * The return value points to the current value of the variable given * by part1 and part2 as a string. If the specified variable doesn't * exist, or if there is a clash in array usage, then NULL is returned * and a message will be left in the interp's result if the * TCL_LEAVE_ERR_MSG flag is set. Note: the return value is only valid * up until the next change to the variable; if you depend on the value * lasting longer than that, then make yourself a private copy. * * Side effects: * None. * *---------------------------------------------------------------------- */ CONST char * Tcl_GetVar2(interp, part1, part2, flags) Tcl_Interp *interp; /* Command interpreter in which variable is * to be looked up. */ CONST char *part1; /* Name of an array (if part2 is non-NULL) * or the name of a variable. */ CONST char *part2; /* If non-NULL, gives the name of an element * in the array part1. */ int flags; /* OR-ed combination of TCL_GLOBAL_ONLY, * TCL_NAMESPACE_ONLY and TCL_LEAVE_ERR_MSG * bits. */ { Tcl_Obj *objPtr; objPtr = Tcl_GetVar2Ex(interp, part1, part2, flags); if (objPtr == NULL) { return NULL; } return TclGetString(objPtr); } /* *---------------------------------------------------------------------- * * Tcl_GetVar2Ex -- * * Return the value of a Tcl variable as a Tcl object, given a * two-part name consisting of array name and element within array. * * Results: * The return value points to the current object value of the variable * given by part1Ptr and part2Ptr. If the specified variable doesn't * exist, or if there is a clash in array usage, then NULL is returned * and a message will be left in the interpreter's result if the * TCL_LEAVE_ERR_MSG flag is set. * * Side effects: * The ref count for the returned object is _not_ incremented to * reflect the returned reference; if you want to keep a reference to * the object you must increment its ref count yourself. * *---------------------------------------------------------------------- */ Tcl_Obj * Tcl_GetVar2Ex(interp, part1, part2, flags) Tcl_Interp *interp; /* Command interpreter in which variable is * to be looked up. */ CONST char *part1; /* Name of an array (if part2 is non-NULL) * or the name of a variable. */ CONST char *part2; /* If non-NULL, gives the name of an element * in the array part1. */ int flags; /* OR-ed combination of TCL_GLOBAL_ONLY, * and TCL_LEAVE_ERR_MSG bits. */ { Var *varPtr, *arrayPtr; /* Filter to pass through only the flags this interface supports. */ flags &= (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY|TCL_LEAVE_ERR_MSG); varPtr = TclLookupVar(interp, part1, part2, flags, "read", /*createPart1*/ 0, /*createPart2*/ 1, &arrayPtr); if (varPtr == NULL) { return NULL; } return TclPtrGetVar(interp, varPtr, arrayPtr, part1, part2, flags); } /* *---------------------------------------------------------------------- * * Tcl_ObjGetVar2 -- * * Return the value of a Tcl variable as a Tcl object, given a * two-part name consisting of array name and element within array. * * Results: * The return value points to the current object value of the variable * given by part1Ptr and part2Ptr. If the specified variable doesn't * exist, or if there is a clash in array usage, then NULL is returned * and a message will be left in the interpreter's result if the * TCL_LEAVE_ERR_MSG flag is set. * * Side effects: * The ref count for the returned object is _not_ incremented to * reflect the returned reference; if you want to keep a reference to * the object you must increment its ref count yourself. * *---------------------------------------------------------------------- */ Tcl_Obj * Tcl_ObjGetVar2(interp, part1Ptr, part2Ptr, flags) Tcl_Interp *interp; /* Command interpreter in which variable is * to be looked up. */ register Tcl_Obj *part1Ptr; /* Points to an object holding the name of * an array (if part2 is non-NULL) or the * name of a variable. */ register Tcl_Obj *part2Ptr; /* If non-null, points to an object holding * the name of an element in the array * part1Ptr. */ int flags; /* OR-ed combination of TCL_GLOBAL_ONLY and * TCL_LEAVE_ERR_MSG bits. */ { Var *varPtr, *arrayPtr; char *part1, *part2; part1 = Tcl_GetString(part1Ptr); part2 = ((part2Ptr == NULL) ? NULL : Tcl_GetString(part2Ptr)); /* Filter to pass through only the flags this interface supports. */ flags &= (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY|TCL_LEAVE_ERR_MSG); varPtr = TclObjLookupVar(interp, part1Ptr, part2, flags, "read", /*createPart1*/ 0, /*createPart2*/ 1, &arrayPtr); if (varPtr == NULL) { return NULL; } return TclPtrGetVar(interp, varPtr, arrayPtr, part1, part2, flags); } /* *---------------------------------------------------------------------- * * TclPtrGetVar -- * * Return the value of a Tcl variable as a Tcl object, given the * pointers to the variable's (and possibly containing array's) * VAR structure. * * Results: * The return value points to the current object value of the variable * given by varPtr. If the specified variable doesn't exist, or if there * is a clash in array usage, then NULL is returned and a message will be * left in the interpreter's result if the TCL_LEAVE_ERR_MSG flag is set. * * Side effects: * The ref count for the returned object is _not_ incremented to * reflect the returned reference; if you want to keep a reference to * the object you must increment its ref count yourself. * *---------------------------------------------------------------------- */ Tcl_Obj * TclPtrGetVar(interp, varPtr, arrayPtr, part1, part2, flags) Tcl_Interp *interp; /* Command interpreter in which variable is * to be looked up. */ register Var *varPtr; /* The variable to be read.*/ Var *arrayPtr; /* NULL for scalar variables, pointer to * the containing array otherwise. */ CONST char *part1; /* Name of an array (if part2 is non-NULL) * or the name of a variable. */ CONST char *part2; /* If non-NULL, gives the name of an element * in the array part1. */ CONST int flags; /* OR-ed combination of TCL_GLOBAL_ONLY, * and TCL_LEAVE_ERR_MSG bits. */ { Interp *iPtr = (Interp *) interp; CONST char *msg; /* * Invoke any traces that have been set for the variable. */ if ((varPtr->tracePtr != NULL) || ((arrayPtr != NULL) && (arrayPtr->tracePtr != NULL))) { if (TCL_ERROR == CallVarTraces(iPtr, arrayPtr, varPtr, part1, part2, (flags & (TCL_NAMESPACE_ONLY|TCL_GLOBAL_ONLY)) | TCL_TRACE_READS, (flags & TCL_LEAVE_ERR_MSG))) { goto errorReturn; } } /* * Return the element if it's an existing scalar variable. */ if (TclIsVarScalar(varPtr) && !TclIsVarUndefined(varPtr)) { return varPtr->value.objPtr; } if (flags & TCL_LEAVE_ERR_MSG) { if (TclIsVarUndefined(varPtr) && (arrayPtr != NULL) && !TclIsVarUndefined(arrayPtr)) { msg = noSuchElement; } else if (TclIsVarArray(varPtr)) { msg = isArray; } else { msg = noSuchVar; } VarErrMsg(interp, part1, part2, "read", msg); } /* * An error. If the variable doesn't exist anymore and no-one's using * it, then free up the relevant structures and hash table entries. */ errorReturn: if (TclIsVarUndefined(varPtr)) { CleanupVar(varPtr, arrayPtr); } return NULL; } /* *---------------------------------------------------------------------- * * Tcl_SetObjCmd -- * * This procedure is invoked to process the "set" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result value. * * Side effects: * A variable's value may be changed. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_SetObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ register Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Tcl_Obj *varValueObj; if (objc == 2) { varValueObj = Tcl_ObjGetVar2(interp, objv[1], NULL, TCL_LEAVE_ERR_MSG); if (varValueObj == NULL) { return TCL_ERROR; } Tcl_SetObjResult(interp, varValueObj); return TCL_OK; } else if (objc == 3) { varValueObj = Tcl_ObjSetVar2(interp, objv[1], NULL, objv[2], TCL_LEAVE_ERR_MSG); if (varValueObj == NULL) { return TCL_ERROR; } Tcl_SetObjResult(interp, varValueObj); return TCL_OK; } else { Tcl_WrongNumArgs(interp, 1, objv, "varName ?newValue?"); return TCL_ERROR; } } /* *---------------------------------------------------------------------- * * Tcl_SetVar -- * * Change the value of a variable. * * Results: * Returns a pointer to the malloc'ed string which is the character * representation of the variable's new value. The caller must not * modify this string. If the write operation was disallowed then NULL * is returned; if the TCL_LEAVE_ERR_MSG flag is set, then an * explanatory message will be left in the interp's result. Note that the * returned string may not be the same as newValue; this is because * variable traces may modify the variable's value. * * Side effects: * If varName is defined as a local or global variable in interp, * its value is changed to newValue. If varName isn't currently * defined, then a new global variable by that name is created. * *---------------------------------------------------------------------- */ #undef Tcl_SetVar CONST char * Tcl_SetVar(interp, varName, newValue, flags) Tcl_Interp *interp; /* Command interpreter in which varName is * to be looked up. */ CONST char *varName; /* Name of a variable in interp. */ CONST char *newValue; /* New value for varName. */ int flags; /* Various flags that tell how to set value: * any of TCL_GLOBAL_ONLY, * TCL_NAMESPACE_ONLY, TCL_APPEND_VALUE, * TCL_LIST_ELEMENT, TCL_LEAVE_ERR_MSG. */ { return Tcl_SetVar2(interp, varName, (char *) NULL, newValue, flags); } /* *---------------------------------------------------------------------- * * Tcl_SetVar2 -- * * Given a two-part variable name, which may refer either to a * scalar variable or an element of an array, change the value * of the variable. If the named scalar or array or element * doesn't exist then create one. * * Results: * Returns a pointer to the malloc'ed string which is the character * representation of the variable's new value. The caller must not * modify this string. If the write operation was disallowed because an * array was expected but not found (or vice versa), then NULL is * returned; if the TCL_LEAVE_ERR_MSG flag is set, then an explanatory * message will be left in the interp's result. Note that the returned * string may not be the same as newValue; this is because variable * traces may modify the variable's value. * * Side effects: * The value of the given variable is set. If either the array * or the entry didn't exist then a new one is created. * *---------------------------------------------------------------------- */ CONST char * Tcl_SetVar2(interp, part1, part2, newValue, flags) Tcl_Interp *interp; /* Command interpreter in which variable is * to be looked up. */ CONST char *part1; /* If part2 is NULL, this is name of scalar * variable. Otherwise it is the name of * an array. */ CONST char *part2; /* Name of an element within an array, or * NULL. */ CONST char *newValue; /* New value for variable. */ int flags; /* Various flags that tell how to set value: * any of TCL_GLOBAL_ONLY, * TCL_NAMESPACE_ONLY, TCL_APPEND_VALUE, * TCL_LIST_ELEMENT, or TCL_LEAVE_ERR_MSG */ { register Tcl_Obj *valuePtr; Tcl_Obj *varValuePtr; /* * Create an object holding the variable's new value and use * Tcl_SetVar2Ex to actually set the variable. */ valuePtr = Tcl_NewStringObj(newValue, -1); Tcl_IncrRefCount(valuePtr); varValuePtr = Tcl_SetVar2Ex(interp, part1, part2, valuePtr, flags); Tcl_DecrRefCount(valuePtr); /* done with the object */ if (varValuePtr == NULL) { return NULL; } return TclGetString(varValuePtr); } /* *---------------------------------------------------------------------- * * Tcl_SetVar2Ex -- * * Given a two-part variable name, which may refer either to a scalar * variable or an element of an array, change the value of the variable * to a new Tcl object value. If the named scalar or array or element * doesn't exist then create one. * * Results: * Returns a pointer to the Tcl_Obj holding the new value of the * variable. If the write operation was disallowed because an array was * expected but not found (or vice versa), then NULL is returned; if * the TCL_LEAVE_ERR_MSG flag is set, then an explanatory message will * be left in the interpreter's result. Note that the returned object * may not be the same one referenced by newValuePtr; this is because * variable traces may modify the variable's value. * * Side effects: * The value of the given variable is set. If either the array or the * entry didn't exist then a new variable is created. * * The reference count is decremented for any old value of the variable * and incremented for its new value. If the new value for the variable * is not the same one referenced by newValuePtr (perhaps as a result * of a variable trace), then newValuePtr's ref count is left unchanged * by Tcl_SetVar2Ex. newValuePtr's ref count is also left unchanged if * we are appending it as a string value: that is, if "flags" includes * TCL_APPEND_VALUE but not TCL_LIST_ELEMENT. * * The reference count for the returned object is _not_ incremented: if * you want to keep a reference to the object you must increment its * ref count yourself. * *---------------------------------------------------------------------- */ Tcl_Obj * Tcl_SetVar2Ex(interp, part1, part2, newValuePtr, flags) Tcl_Interp *interp; /* Command interpreter in which variable is * to be found. */ CONST char *part1; /* Name of an array (if part2 is non-NULL) * or the name of a variable. */ CONST char *part2; /* If non-NULL, gives the name of an element * in the array part1. */ Tcl_Obj *newValuePtr; /* New value for variable. */ int flags; /* Various flags that tell how to set value: * any of TCL_GLOBAL_ONLY, * TCL_NAMESPACE_ONLY, TCL_APPEND_VALUE, * TCL_LIST_ELEMENT or TCL_LEAVE_ERR_MSG. */ { Var *varPtr, *arrayPtr; /* Filter to pass through only the flags this interface supports. */ flags &= (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY|TCL_LEAVE_ERR_MSG |TCL_APPEND_VALUE|TCL_LIST_ELEMENT); varPtr = TclLookupVar(interp, part1, part2, flags, "set", /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr); if (varPtr == NULL) { return NULL; } return TclPtrSetVar(interp, varPtr, arrayPtr, part1, part2, newValuePtr, flags); } /* *---------------------------------------------------------------------- * * Tcl_ObjSetVar2 -- * * This function is the same as Tcl_SetVar2Ex above, except the * variable names are passed in Tcl object instead of strings. * * Results: * Returns a pointer to the Tcl_Obj holding the new value of the * variable. If the write operation was disallowed because an array was * expected but not found (or vice versa), then NULL is returned; if * the TCL_LEAVE_ERR_MSG flag is set, then an explanatory message will * be left in the interpreter's result. Note that the returned object * may not be the same one referenced by newValuePtr; this is because * variable traces may modify the variable's value. * * Side effects: * The value of the given variable is set. If either the array or the * entry didn't exist then a new variable is created. * *---------------------------------------------------------------------- */ Tcl_Obj * Tcl_ObjSetVar2(interp, part1Ptr, part2Ptr, newValuePtr, flags) Tcl_Interp *interp; /* Command interpreter in which variable is * to be found. */ register Tcl_Obj *part1Ptr; /* Points to an object holding the name of * an array (if part2 is non-NULL) or the * name of a variable. */ register Tcl_Obj *part2Ptr; /* If non-null, points to an object holding * the name of an element in the array * part1Ptr. */ Tcl_Obj *newValuePtr; /* New value for variable. */ int flags; /* Various flags that tell how to set value: * any of TCL_GLOBAL_ONLY, * TCL_NAMESPACE_ONLY, TCL_APPEND_VALUE, * TCL_LIST_ELEMENT, or TCL_LEAVE_ERR_MSG. */ { Var *varPtr, *arrayPtr; char *part1, *part2; part1 = TclGetString(part1Ptr); part2 = ((part2Ptr == NULL) ? NULL : Tcl_GetString(part2Ptr)); /* Filter to pass through only the flags this interface supports. */ flags &= (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY|TCL_LEAVE_ERR_MSG |TCL_APPEND_VALUE|TCL_LIST_ELEMENT); varPtr = TclObjLookupVar(interp, part1Ptr, part2, flags, "set", /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr); if (varPtr == NULL) { return NULL; } return TclPtrSetVar(interp, varPtr, arrayPtr, part1, part2, newValuePtr, flags); } /* *---------------------------------------------------------------------- * * TclPtrSetVar -- * * This function is the same as Tcl_SetVar2Ex above, except that * it requires pointers to the variable's Var structs in addition * to the variable names. * * Results: * Returns a pointer to the Tcl_Obj holding the new value of the * variable. If the write operation was disallowed because an array was * expected but not found (or vice versa), then NULL is returned; if * the TCL_LEAVE_ERR_MSG flag is set, then an explanatory message will * be left in the interpreter's result. Note that the returned object * may not be the same one referenced by newValuePtr; this is because * variable traces may modify the variable's value. * * Side effects: * The value of the given variable is set. If either the array or the * entry didn't exist then a new variable is created. * *---------------------------------------------------------------------- */ Tcl_Obj * TclPtrSetVar(interp, varPtr, arrayPtr, part1, part2, newValuePtr, flags) Tcl_Interp *interp; /* Command interpreter in which variable is * to be looked up. */ register Var *varPtr; Var *arrayPtr; CONST char *part1; /* Name of an array (if part2 is non-NULL) * or the name of a variable. */ CONST char *part2; /* If non-NULL, gives the name of an element * in the array part1. */ Tcl_Obj *newValuePtr; /* New value for variable. */ CONST int flags; /* OR-ed combination of TCL_GLOBAL_ONLY, * and TCL_LEAVE_ERR_MSG bits. */ { Interp *iPtr = (Interp *) interp; Tcl_Obj *oldValuePtr; Tcl_Obj *resultPtr = NULL; int result; /* * If the variable is in a hashtable and its hPtr field is NULL, then we * may have an upvar to an array element where the array was deleted * or an upvar to a namespace variable whose namespace was deleted. * Generate an error (allowing the variable to be reset would screw up * our storage allocation and is meaningless anyway). */ if ((varPtr->flags & VAR_IN_HASHTABLE) && (varPtr->hPtr == NULL)) { if (flags & TCL_LEAVE_ERR_MSG) { if (TclIsVarArrayElement(varPtr)) { VarErrMsg(interp, part1, part2, "set", danglingElement); } else { VarErrMsg(interp, part1, part2, "set", danglingVar); } } return NULL; } /* * It's an error to try to set an array variable itself. */ if (TclIsVarArray(varPtr) && !TclIsVarUndefined(varPtr)) { if (flags & TCL_LEAVE_ERR_MSG) { VarErrMsg(interp, part1, part2, "set", isArray); } return NULL; } /* * Invoke any read traces that have been set for the variable if it * requested. This was done for INST_LAPPEND_* but that was inconsistent * with the non-bc instruction, and would cause failures trying to * lappend to any non-existing ::env var, which is inconsistent with * documented behavior. [Bug #3057639]. */ if ((flags & TCL_TRACE_READS) && ((varPtr->tracePtr != NULL) || ((arrayPtr != NULL) && (arrayPtr->tracePtr != NULL)))) { if (TCL_ERROR == CallVarTraces(iPtr, arrayPtr, varPtr, part1, part2, TCL_TRACE_READS, (flags & TCL_LEAVE_ERR_MSG))) { return NULL; } } /* * Set the variable's new value. If appending, append the new value to * the variable, either as a list element or as a string. Also, if * appending, then if the variable's old value is unshared we can modify * it directly, otherwise we must create a new copy to modify: this is * "copy on write". */ if (flags & TCL_LIST_ELEMENT && !(flags & TCL_APPEND_VALUE)) { TclSetVarUndefined(varPtr); } oldValuePtr = varPtr->value.objPtr; if (flags & (TCL_APPEND_VALUE|TCL_LIST_ELEMENT)) { if (TclIsVarUndefined(varPtr) && (oldValuePtr != NULL)) { Tcl_DecrRefCount(oldValuePtr); /* discard old value */ varPtr->value.objPtr = NULL; oldValuePtr = NULL; } if (flags & TCL_LIST_ELEMENT) { /* append list element */ if (oldValuePtr == NULL) { TclNewObj(oldValuePtr); varPtr->value.objPtr = oldValuePtr; Tcl_IncrRefCount(oldValuePtr); /* since var is referenced */ } else if (Tcl_IsShared(oldValuePtr)) { varPtr->value.objPtr = Tcl_DuplicateObj(oldValuePtr); Tcl_DecrRefCount(oldValuePtr); oldValuePtr = varPtr->value.objPtr; Tcl_IncrRefCount(oldValuePtr); /* since var is referenced */ } result = Tcl_ListObjAppendElement(interp, oldValuePtr, newValuePtr); if (result != TCL_OK) { return NULL; } } else { /* append string */ /* * We append newValuePtr's bytes but don't change its ref count. */ if (oldValuePtr == NULL) { varPtr->value.objPtr = newValuePtr; Tcl_IncrRefCount(newValuePtr); } else { if (Tcl_IsShared(oldValuePtr)) { /* append to copy */ varPtr->value.objPtr = Tcl_DuplicateObj(oldValuePtr); #ifdef TCL_TIP280 /* * TIP #280. * Ensure that the continuation line data for the * string is not lost and applies to the extended * script as well. */ TclContinuationsCopy (varPtr->value.objPtr, oldValuePtr); #endif TclDecrRefCount(oldValuePtr); oldValuePtr = varPtr->value.objPtr; Tcl_IncrRefCount(oldValuePtr); /* since var is ref */ } Tcl_AppendObjToObj(oldValuePtr, newValuePtr); } } } else if (newValuePtr != oldValuePtr) { /* * In this case we are replacing the value, so we don't need to * do more than swap the objects. */ varPtr->value.objPtr = newValuePtr; Tcl_IncrRefCount(newValuePtr); /* var is another ref */ if (oldValuePtr != NULL) { TclDecrRefCount(oldValuePtr); /* discard old value */ } } TclSetVarScalar(varPtr); TclClearVarUndefined(varPtr); if (arrayPtr != NULL) { TclClearVarUndefined(arrayPtr); } /* * Invoke any write traces for the variable. */ if ((varPtr->tracePtr != NULL) || ((arrayPtr != NULL) && (arrayPtr->tracePtr != NULL))) { if (TCL_ERROR == CallVarTraces(iPtr, arrayPtr, varPtr, part1, part2, (flags & (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY)) | TCL_TRACE_WRITES, (flags & TCL_LEAVE_ERR_MSG))) { goto cleanup; } } /* * Return the variable's value unless the variable was changed in some * gross way by a trace (e.g. it was unset and then recreated as an * array). */ if (TclIsVarScalar(varPtr) && !TclIsVarUndefined(varPtr)) { return varPtr->value.objPtr; } /* * A trace changed the value in some gross way. Return an empty string * object. */ resultPtr = iPtr->emptyObjPtr; /* * If the variable doesn't exist anymore and no-one's using it, then * free up the relevant structures and hash table entries. */ cleanup: if (TclIsVarUndefined(varPtr)) { CleanupVar(varPtr, arrayPtr); } return resultPtr; } /* *---------------------------------------------------------------------- * * TclIncrVar2 -- * * Given a two-part variable name, which may refer either to a scalar * variable or an element of an array, increment the Tcl object value * of the variable by a specified amount. * * Results: * Returns a pointer to the Tcl_Obj holding the new value of the * variable. If the specified variable doesn't exist, or there is a * clash in array usage, or an error occurs while executing variable * traces, then NULL is returned and a message will be left in * the interpreter's result. * * Side effects: * The value of the given variable is incremented by the specified * amount. If either the array or the entry didn't exist then a new * variable is created. The ref count for the returned object is _not_ * incremented to reflect the returned reference; if you want to keep a * reference to the object you must increment its ref count yourself. * *---------------------------------------------------------------------- */ Tcl_Obj * TclIncrVar2(interp, part1Ptr, part2Ptr, incrAmount, flags) Tcl_Interp *interp; /* Command interpreter in which variable is * to be found. */ Tcl_Obj *part1Ptr; /* Points to an object holding the name of * an array (if part2 is non-NULL) or the * name of a variable. */ Tcl_Obj *part2Ptr; /* If non-null, points to an object holding * the name of an element in the array * part1Ptr. */ long incrAmount; /* Amount to be added to variable. */ int flags; /* Various flags that tell how to incr value: * any of TCL_GLOBAL_ONLY, * TCL_NAMESPACE_ONLY, TCL_APPEND_VALUE, * TCL_LIST_ELEMENT, TCL_LEAVE_ERR_MSG. */ { Var *varPtr, *arrayPtr; char *part1, *part2; part1 = TclGetString(part1Ptr); part2 = ((part2Ptr == NULL)? NULL : TclGetString(part2Ptr)); varPtr = TclObjLookupVar(interp, part1Ptr, part2, flags, "read", 0, 1, &arrayPtr); if (varPtr == NULL) { Tcl_AddObjErrorInfo(interp, "\n (reading value of variable to increment)", -1); return NULL; } return TclPtrIncrVar(interp, varPtr, arrayPtr, part1, part2, incrAmount, flags); } /* *---------------------------------------------------------------------- * * TclPtrIncrVar -- * * Given the pointers to a variable and possible containing array, * increment the Tcl object value of the variable by a specified * amount. * * Results: * Returns a pointer to the Tcl_Obj holding the new value of the * variable. If the specified variable doesn't exist, or there is a * clash in array usage, or an error occurs while executing variable * traces, then NULL is returned and a message will be left in * the interpreter's result. * * Side effects: * The value of the given variable is incremented by the specified * amount. If either the array or the entry didn't exist then a new * variable is created. The ref count for the returned object is _not_ * incremented to reflect the returned reference; if you want to keep a * reference to the object you must increment its ref count yourself. * *---------------------------------------------------------------------- */ Tcl_Obj * TclPtrIncrVar(interp, varPtr, arrayPtr, part1, part2, incrAmount, flags) Tcl_Interp *interp; /* Command interpreter in which variable is * to be found. */ Var *varPtr; Var *arrayPtr; CONST char *part1; /* Points to an object holding the name of * an array (if part2 is non-NULL) or the * name of a variable. */ CONST char *part2; /* If non-null, points to an object holding * the name of an element in the array * part1Ptr. */ CONST long incrAmount; /* Amount to be added to variable. */ CONST int flags; /* Various flags that tell how to incr value: * any of TCL_GLOBAL_ONLY, * TCL_NAMESPACE_ONLY, TCL_APPEND_VALUE, * TCL_LIST_ELEMENT, TCL_LEAVE_ERR_MSG. */ { register Tcl_Obj *varValuePtr; int createdNewObj; /* Set 1 if var's value object is shared * so we must increment a copy (i.e. copy * on write). */ long i; varValuePtr = TclPtrGetVar(interp, varPtr, arrayPtr, part1, part2, flags); if (varValuePtr == NULL) { Tcl_AddObjErrorInfo(interp, "\n (reading value of variable to increment)", -1); return NULL; } /* * Increment the variable's value. If the object is unshared we can * modify it directly, otherwise we must create a new copy to modify: * this is "copy on write". Then free the variable's old string * representation, if any, since it will no longer be valid. */ createdNewObj = 0; if (Tcl_IsShared(varValuePtr)) { varValuePtr = Tcl_DuplicateObj(varValuePtr); createdNewObj = 1; } if (varValuePtr->typePtr == &tclWideIntType) { Tcl_WideInt wide; TclGetWide(wide,varValuePtr); Tcl_SetWideIntObj(varValuePtr, wide + Tcl_LongAsWide(incrAmount)); } else if (varValuePtr->typePtr == &tclIntType) { i = varValuePtr->internalRep.longValue; Tcl_SetIntObj(varValuePtr, i + incrAmount); } else { /* * Not an integer or wide internal-rep... */ Tcl_WideInt wide; if (Tcl_GetWideIntFromObj(interp, varValuePtr, &wide) != TCL_OK) { if (createdNewObj) { Tcl_DecrRefCount(varValuePtr); /* free unneeded copy */ } return NULL; } if (wide <= Tcl_LongAsWide(LONG_MAX) && wide >= Tcl_LongAsWide(LONG_MIN)) { Tcl_SetLongObj(varValuePtr, Tcl_WideAsLong(wide) + incrAmount); } else { Tcl_SetWideIntObj(varValuePtr, wide + Tcl_LongAsWide(incrAmount)); } } /* * Store the variable's new value and run any write traces. */ return TclPtrSetVar(interp, varPtr, arrayPtr, part1, part2, varValuePtr, flags); } /* *---------------------------------------------------------------------- * * Tcl_UnsetVar -- * * Delete a variable, so that it may not be accessed anymore. * * Results: * Returns TCL_OK if the variable was successfully deleted, TCL_ERROR * if the variable can't be unset. In the event of an error, * if the TCL_LEAVE_ERR_MSG flag is set then an error message * is left in the interp's result. * * Side effects: * If varName is defined as a local or global variable in interp, * it is deleted. * *---------------------------------------------------------------------- */ #undef Tcl_UnsetVar int Tcl_UnsetVar(interp, varName, flags) Tcl_Interp *interp; /* Command interpreter in which varName is * to be looked up. */ CONST char *varName; /* Name of a variable in interp. May be * either a scalar name or an array name * or an element in an array. */ int flags; /* OR-ed combination of any of * TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY or * TCL_LEAVE_ERR_MSG. */ { return Tcl_UnsetVar2(interp, varName, (char *) NULL, flags); } /* *---------------------------------------------------------------------- * * Tcl_UnsetVar2 -- * * Delete a variable, given a 2-part name. * * Results: * Returns TCL_OK if the variable was successfully deleted, TCL_ERROR * if the variable can't be unset. In the event of an error, * if the TCL_LEAVE_ERR_MSG flag is set then an error message * is left in the interp's result. * * Side effects: * If part1 and part2 indicate a local or global variable in interp, * it is deleted. If part1 is an array name and part2 is NULL, then * the whole array is deleted. * *---------------------------------------------------------------------- */ int Tcl_UnsetVar2(interp, part1, part2, flags) Tcl_Interp *interp; /* Command interpreter in which varName is * to be looked up. */ CONST char *part1; /* Name of variable or array. */ CONST char *part2; /* Name of element within array or NULL. */ int flags; /* OR-ed combination of any of * TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY, * TCL_LEAVE_ERR_MSG. */ { int result; Tcl_Obj *part1Ptr; part1Ptr = Tcl_NewStringObj(part1, -1); Tcl_IncrRefCount(part1Ptr); /* Filter to pass through only the flags this interface supports. */ flags &= (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY|TCL_LEAVE_ERR_MSG); result = TclObjUnsetVar2(interp, part1Ptr, part2, flags); TclDecrRefCount(part1Ptr); return result; } /* *---------------------------------------------------------------------- * * TclObjUnsetVar2 -- * * Delete a variable, given a 2-object name. * * Results: * Returns TCL_OK if the variable was successfully deleted, TCL_ERROR * if the variable can't be unset. In the event of an error, * if the TCL_LEAVE_ERR_MSG flag is set then an error message * is left in the interp's result. * * Side effects: * If part1ptr and part2Ptr indicate a local or global variable in interp, * it is deleted. If part1Ptr is an array name and part2Ptr is NULL, then * the whole array is deleted. * *---------------------------------------------------------------------- */ int TclObjUnsetVar2(interp, part1Ptr, part2, flags) Tcl_Interp *interp; /* Command interpreter in which varName is * to be looked up. */ Tcl_Obj *part1Ptr; /* Name of variable or array. */ CONST char *part2; /* Name of element within array or NULL. */ int flags; /* OR-ed combination of any of * TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY, * TCL_LEAVE_ERR_MSG. */ { Var *varPtr; Interp *iPtr = (Interp *) interp; Var *arrayPtr; int result; char *part1; part1 = TclGetString(part1Ptr); varPtr = TclObjLookupVar(interp, part1Ptr, part2, flags, "unset", /*createPart1*/ 0, /*createPart2*/ 0, &arrayPtr); if (varPtr == NULL) { return TCL_ERROR; } result = (TclIsVarUndefined(varPtr)? TCL_ERROR : TCL_OK); /* * Keep the variable alive until we're done with it. We used to * increase/decrease the refCount for each operation, making it * hard to find [Bug 735335] - caused by unsetting the variable * whose value was the variable's name. */ varPtr->refCount++; UnsetVarStruct(varPtr, arrayPtr, iPtr, part1, part2, flags); /* * It's an error to unset an undefined variable. */ if (result != TCL_OK) { if (flags & TCL_LEAVE_ERR_MSG) { VarErrMsg(interp, part1, part2, "unset", ((arrayPtr == NULL) ? noSuchVar : noSuchElement)); } } /* * Try to avoid keeping the Var struct allocated due to a tclNsVarNameType * keeping a reference. This removes some additional exteriorisations of * [Bug 736729], but may be a good thing independently of the bug. */ if (part1Ptr->typePtr == &tclNsVarNameType) { part1Ptr->typePtr->freeIntRepProc(part1Ptr); part1Ptr->typePtr = NULL; } /* * Finally, if the variable is truly not in use then free up its Var * structure and remove it from its hash table, if any. The ref count of * its value object, if any, was decremented above. */ varPtr->refCount--; CleanupVar(varPtr, arrayPtr); return result; } /* *---------------------------------------------------------------------- * * UnsetVarStruct -- * * Unset and delete a variable. This does the internal work for * TclObjUnsetVar2 and TclDeleteNamespaceVars, which call here for each * variable to be unset and deleted. * * Results: * None. * * Side effects: * If the arguments indicate a local or global variable in iPtr, it is * unset and deleted. * *---------------------------------------------------------------------- */ static void UnsetVarStruct(varPtr, arrayPtr, iPtr, part1, part2, flags) Var *varPtr; Var *arrayPtr; Interp *iPtr; CONST char *part1; CONST char *part2; int flags; { Var dummyVar; Var *dummyVarPtr; ActiveVarTrace *activePtr; if ((arrayPtr != NULL) && (arrayPtr->searchPtr != NULL)) { DeleteSearches(arrayPtr); } /* * For global/upvar variables referenced in procedures, decrement * the reference count on the variable referred to, and free * the referenced variable if it's no longer needed. */ if (TclIsVarLink(varPtr)) { Var *linkPtr = varPtr->value.linkPtr; linkPtr->refCount--; if ((linkPtr->refCount == 0) && TclIsVarUndefined(linkPtr) && (linkPtr->tracePtr == NULL) && (linkPtr->flags & VAR_IN_HASHTABLE)) { if (linkPtr->hPtr != NULL) { Tcl_DeleteHashEntry(linkPtr->hPtr); } ckfree((char *) linkPtr); } } /* * The code below is tricky, because of the possibility that * a trace procedure might try to access a variable being * deleted. To handle this situation gracefully, do things * in three steps: * 1. Copy the contents of the variable to a dummy variable * structure, and mark the original Var structure as undefined. * 2. Invoke traces and clean up the variable, using the dummy copy. * 3. If at the end of this the original variable is still * undefined and has no outstanding references, then delete * it (but it could have gotten recreated by a trace). */ dummyVar = *varPtr; TclSetVarUndefined(varPtr); TclSetVarScalar(varPtr); varPtr->value.objPtr = NULL; /* dummyVar points to any value object */ varPtr->tracePtr = NULL; varPtr->searchPtr = NULL; /* * Call trace procedures for the variable being deleted. Then delete * its traces. Be sure to abort any other traces for the variable * that are still pending. Special tricks: * 1. We need to increment varPtr's refCount around this: CallVarTraces * will use dummyVar so it won't increment varPtr's refCount itself. * 2. Turn off the VAR_TRACE_ACTIVE flag in dummyVar: we want to * call unset traces even if other traces are pending. */ if ((dummyVar.tracePtr != NULL) || ((arrayPtr != NULL) && (arrayPtr->tracePtr != NULL))) { dummyVar.flags &= ~VAR_TRACE_ACTIVE; CallVarTraces(iPtr, arrayPtr, &dummyVar, part1, part2, (flags & (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY)) | TCL_TRACE_UNSETS, /* leaveErrMsg */ 0); while (dummyVar.tracePtr != NULL) { VarTrace *tracePtr = dummyVar.tracePtr; dummyVar.tracePtr = tracePtr->nextPtr; Tcl_EventuallyFree((ClientData) tracePtr, TCL_DYNAMIC); } for (activePtr = iPtr->activeVarTracePtr; activePtr != NULL; activePtr = activePtr->nextPtr) { if (activePtr->varPtr == varPtr) { activePtr->nextTracePtr = NULL; } } } /* * If the variable is an array, delete all of its elements. This must be * done after calling the traces on the array, above (that's the way * traces are defined). If it is a scalar, "discard" its object * (decrement the ref count of its object, if any). */ dummyVarPtr = &dummyVar; if (TclIsVarArray(dummyVarPtr) && !TclIsVarUndefined(dummyVarPtr)) { DeleteArray(iPtr, part1, dummyVarPtr, (flags & (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY)) | TCL_TRACE_UNSETS); } if (TclIsVarScalar(dummyVarPtr) && (dummyVarPtr->value.objPtr != NULL)) { Tcl_Obj *objPtr = dummyVarPtr->value.objPtr; TclDecrRefCount(objPtr); dummyVarPtr->value.objPtr = NULL; } /* * If the variable was a namespace variable, decrement its reference count. */ if (varPtr->flags & VAR_NAMESPACE_VAR) { varPtr->flags &= ~VAR_NAMESPACE_VAR; varPtr->refCount--; } } /* *---------------------------------------------------------------------- * * Tcl_TraceVar -- * * Arrange for reads and/or writes to a variable to cause a * procedure to be invoked, which can monitor the operations * and/or change their actions. * * Results: * A standard Tcl return value. * * Side effects: * A trace is set up on the variable given by varName, such that * future references to the variable will be intermediated by * proc. See the manual entry for complete details on the calling * sequence for proc. * *---------------------------------------------------------------------- */ #undef Tcl_TraceVar int Tcl_TraceVar(interp, varName, flags, proc, clientData) Tcl_Interp *interp; /* Interpreter in which variable is * to be traced. */ CONST char *varName; /* Name of variable; may end with "(index)" * to signify an array reference. */ int flags; /* OR-ed collection of bits, including any * of TCL_TRACE_READS, TCL_TRACE_WRITES, * TCL_TRACE_UNSETS, TCL_GLOBAL_ONLY, and * TCL_NAMESPACE_ONLY. */ Tcl_VarTraceProc *proc; /* Procedure to call when specified ops are * invoked upon varName. */ ClientData clientData; /* Arbitrary argument to pass to proc. */ { return Tcl_TraceVar2(interp, varName, (char *) NULL, flags, proc, clientData); } /* *---------------------------------------------------------------------- * * Tcl_TraceVar2 -- * * Arrange for reads and/or writes to a variable to cause a * procedure to be invoked, which can monitor the operations * and/or change their actions. * * Results: * A standard Tcl return value. * * Side effects: * A trace is set up on the variable given by part1 and part2, such * that future references to the variable will be intermediated by * proc. See the manual entry for complete details on the calling * sequence for proc. * *---------------------------------------------------------------------- */ int Tcl_TraceVar2(interp, part1, part2, flags, proc, clientData) Tcl_Interp *interp; /* Interpreter in which variable is * to be traced. */ CONST char *part1; /* Name of scalar variable or array. */ CONST char *part2; /* Name of element within array; NULL means * trace applies to scalar variable or array * as-a-whole. */ int flags; /* OR-ed collection of bits, including any * of TCL_TRACE_READS, TCL_TRACE_WRITES, * TCL_TRACE_UNSETS, TCL_GLOBAL_ONLY, * and TCL_NAMESPACE_ONLY. */ Tcl_VarTraceProc *proc; /* Procedure to call when specified ops are * invoked upon varName. */ ClientData clientData; /* Arbitrary argument to pass to proc. */ { Var *varPtr, *arrayPtr; register VarTrace *tracePtr; int flagMask; /* * We strip 'flags' down to just the parts which are relevant to * TclLookupVar, to avoid conflicts between trace flags and * internal namespace flags such as 'FIND_ONLY_NS'. This can * now occur since we have trace flags with values 0x1000 and higher. */ flagMask = TCL_GLOBAL_ONLY | TCL_NAMESPACE_ONLY; varPtr = TclLookupVar(interp, part1, part2, (flags & flagMask) | TCL_LEAVE_ERR_MSG, "trace", /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr); if (varPtr == NULL) { return TCL_ERROR; } /* * Check for a nonsense flag combination. Note that this is a * panic() because there should be no code path that ever sets * both flags. */ if ((flags&TCL_TRACE_RESULT_DYNAMIC) && (flags&TCL_TRACE_RESULT_OBJECT)) { panic("bad result flag combination"); } /* * Set up trace information. */ flagMask = TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS | TCL_TRACE_ARRAY | TCL_TRACE_RESULT_DYNAMIC | TCL_TRACE_RESULT_OBJECT; #ifndef TCL_REMOVE_OBSOLETE_TRACES flagMask |= TCL_TRACE_OLD_STYLE; #endif tracePtr = (VarTrace *) ckalloc(sizeof(VarTrace)); tracePtr->traceProc = proc; tracePtr->clientData = clientData; tracePtr->flags = flags & flagMask; tracePtr->nextPtr = varPtr->tracePtr; varPtr->tracePtr = tracePtr; return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_UntraceVar -- * * Remove a previously-created trace for a variable. * * Results: * None. * * Side effects: * If there exists a trace for the variable given by varName * with the given flags, proc, and clientData, then that trace * is removed. * *---------------------------------------------------------------------- */ #undef Tcl_UntraceVar void Tcl_UntraceVar(interp, varName, flags, proc, clientData) Tcl_Interp *interp; /* Interpreter containing variable. */ CONST char *varName; /* Name of variable; may end with "(index)" * to signify an array reference. */ int flags; /* OR-ed collection of bits describing * current trace, including any of * TCL_TRACE_READS, TCL_TRACE_WRITES, * TCL_TRACE_UNSETS, TCL_GLOBAL_ONLY * and TCL_NAMESPACE_ONLY. */ Tcl_VarTraceProc *proc; /* Procedure assocated with trace. */ ClientData clientData; /* Arbitrary argument to pass to proc. */ { Tcl_UntraceVar2(interp, varName, (char *) NULL, flags, proc, clientData); } /* *---------------------------------------------------------------------- * * Tcl_UntraceVar2 -- * * Remove a previously-created trace for a variable. * * Results: * None. * * Side effects: * If there exists a trace for the variable given by part1 * and part2 with the given flags, proc, and clientData, then * that trace is removed. * *---------------------------------------------------------------------- */ void Tcl_UntraceVar2(interp, part1, part2, flags, proc, clientData) Tcl_Interp *interp; /* Interpreter containing variable. */ CONST char *part1; /* Name of variable or array. */ CONST char *part2; /* Name of element within array; NULL means * trace applies to scalar variable or array * as-a-whole. */ int flags; /* OR-ed collection of bits describing * current trace, including any of * TCL_TRACE_READS, TCL_TRACE_WRITES, * TCL_TRACE_UNSETS, TCL_GLOBAL_ONLY, * and TCL_NAMESPACE_ONLY. */ Tcl_VarTraceProc *proc; /* Procedure assocated with trace. */ ClientData clientData; /* Arbitrary argument to pass to proc. */ { register VarTrace *tracePtr; VarTrace *prevPtr; Var *varPtr, *arrayPtr; Interp *iPtr = (Interp *) interp; ActiveVarTrace *activePtr; int flagMask; /* * Set up a mask to mask out the parts of the flags that we are not * interested in now. */ flagMask = TCL_GLOBAL_ONLY | TCL_NAMESPACE_ONLY; varPtr = TclLookupVar(interp, part1, part2, flags & flagMask, /*msg*/ (char *) NULL, /*createPart1*/ 0, /*createPart2*/ 0, &arrayPtr); if (varPtr == NULL) { return; } /* * Set up a mask to mask out the parts of the flags that we are not * interested in now. */ flagMask = TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS | TCL_TRACE_ARRAY | TCL_TRACE_RESULT_DYNAMIC | TCL_TRACE_RESULT_OBJECT; #ifndef TCL_REMOVE_OBSOLETE_TRACES flagMask |= TCL_TRACE_OLD_STYLE; #endif flags &= flagMask; for (tracePtr = varPtr->tracePtr, prevPtr = NULL; ; prevPtr = tracePtr, tracePtr = tracePtr->nextPtr) { if (tracePtr == NULL) { return; } if ((tracePtr->traceProc == proc) && (tracePtr->flags == flags) && (tracePtr->clientData == clientData)) { break; } } /* * The code below makes it possible to delete traces while traces * are active: it makes sure that the deleted trace won't be * processed by CallVarTraces. */ for (activePtr = iPtr->activeVarTracePtr; activePtr != NULL; activePtr = activePtr->nextPtr) { if (activePtr->nextTracePtr == tracePtr) { activePtr->nextTracePtr = tracePtr->nextPtr; } } if (prevPtr == NULL) { varPtr->tracePtr = tracePtr->nextPtr; } else { prevPtr->nextPtr = tracePtr->nextPtr; } Tcl_EventuallyFree((ClientData) tracePtr, TCL_DYNAMIC); /* * If this is the last trace on the variable, and the variable is * unset and unused, then free up the variable. */ if (TclIsVarUndefined(varPtr)) { CleanupVar(varPtr, (Var *) NULL); } } /* *---------------------------------------------------------------------- * * Tcl_VarTraceInfo -- * * Return the clientData value associated with a trace on a * variable. This procedure can also be used to step through * all of the traces on a particular variable that have the * same trace procedure. * * Results: * The return value is the clientData value associated with * a trace on the given variable. Information will only be * returned for a trace with proc as trace procedure. If * the clientData argument is NULL then the first such trace is * returned; otherwise, the next relevant one after the one * given by clientData will be returned. If the variable * doesn't exist, or if there are no (more) traces for it, * then NULL is returned. * * Side effects: * None. * *---------------------------------------------------------------------- */ #undef Tcl_VarTraceInfo ClientData Tcl_VarTraceInfo(interp, varName, flags, proc, prevClientData) Tcl_Interp *interp; /* Interpreter containing variable. */ CONST char *varName; /* Name of variable; may end with "(index)" * to signify an array reference. */ int flags; /* OR-ed combo or TCL_GLOBAL_ONLY, * TCL_NAMESPACE_ONLY (can be 0). */ Tcl_VarTraceProc *proc; /* Procedure assocated with trace. */ ClientData prevClientData; /* If non-NULL, gives last value returned * by this procedure, so this call will * return the next trace after that one. * If NULL, this call will return the * first trace. */ { return Tcl_VarTraceInfo2(interp, varName, (char *) NULL, flags, proc, prevClientData); } /* *---------------------------------------------------------------------- * * Tcl_VarTraceInfo2 -- * * Same as Tcl_VarTraceInfo, except takes name in two pieces * instead of one. * * Results: * Same as Tcl_VarTraceInfo. * * Side effects: * None. * *---------------------------------------------------------------------- */ ClientData Tcl_VarTraceInfo2(interp, part1, part2, flags, proc, prevClientData) Tcl_Interp *interp; /* Interpreter containing variable. */ CONST char *part1; /* Name of variable or array. */ CONST char *part2; /* Name of element within array; NULL means * trace applies to scalar variable or array * as-a-whole. */ int flags; /* OR-ed combination of TCL_GLOBAL_ONLY, * TCL_NAMESPACE_ONLY. */ Tcl_VarTraceProc *proc; /* Procedure assocated with trace. */ ClientData prevClientData; /* If non-NULL, gives last value returned * by this procedure, so this call will * return the next trace after that one. * If NULL, this call will return the * first trace. */ { register VarTrace *tracePtr; Var *varPtr, *arrayPtr; varPtr = TclLookupVar(interp, part1, part2, flags & (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY), /*msg*/ (char *) NULL, /*createPart1*/ 0, /*createPart2*/ 0, &arrayPtr); if (varPtr == NULL) { return NULL; } /* * Find the relevant trace, if any, and return its clientData. */ tracePtr = varPtr->tracePtr; if (prevClientData != NULL) { for ( ; tracePtr != NULL; tracePtr = tracePtr->nextPtr) { if ((tracePtr->clientData == prevClientData) && (tracePtr->traceProc == proc)) { tracePtr = tracePtr->nextPtr; break; } } } for ( ; tracePtr != NULL; tracePtr = tracePtr->nextPtr) { if (tracePtr->traceProc == proc) { return tracePtr->clientData; } } return NULL; } /* *---------------------------------------------------------------------- * * Tcl_UnsetObjCmd -- * * This object-based procedure is invoked to process the "unset" Tcl * command. See the user documentation for details on what it does. * * Results: * A standard Tcl object result value. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_UnsetObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { register int i, flags = TCL_LEAVE_ERR_MSG; register char *name; if (objc < 1) { Tcl_WrongNumArgs(interp, 1, objv, "?-nocomplain? ?--? ?varName varName ...?"); return TCL_ERROR; } else if (objc == 1) { /* * Do nothing if no arguments supplied, so as to match * command documentation. */ return TCL_OK; } /* * Simple, restrictive argument parsing. The only options are -- * and -nocomplain (which must come first and be given exactly to * be an option). */ i = 1; name = TclGetString(objv[i]); if (name[0] == '-') { if (strcmp("-nocomplain", name) == 0) { i++; if (i == objc) { return TCL_OK; } flags = 0; name = TclGetString(objv[i]); } if (strcmp("--", name) == 0) { i++; } } for (; i < objc; i++) { if ((TclObjUnsetVar2(interp, objv[i], NULL, flags) != TCL_OK) && (flags == TCL_LEAVE_ERR_MSG)) { return TCL_ERROR; } } return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_AppendObjCmd -- * * This object-based procedure is invoked to process the "append" * Tcl command. See the user documentation for details on what it does. * * Results: * A standard Tcl object result value. * * Side effects: * A variable's value may be changed. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_AppendObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Var *varPtr, *arrayPtr; char *part1; register Tcl_Obj *varValuePtr = NULL; /* Initialized to avoid compiler * warning. */ int i; if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "varName ?value value ...?"); return TCL_ERROR; } if (objc == 2) { varValuePtr = Tcl_ObjGetVar2(interp, objv[1], NULL, TCL_LEAVE_ERR_MSG); if (varValuePtr == NULL) { return TCL_ERROR; } } else { varPtr = TclObjLookupVar(interp, objv[1], NULL, TCL_LEAVE_ERR_MSG, "set", /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr); part1 = TclGetString(objv[1]); if (varPtr == NULL) { return TCL_ERROR; } for (i = 2; i < objc; i++) { /* * Note that we do not need to increase the refCount of * the Var pointers: should a trace delete the variable, * the return value of TclPtrSetVar will be NULL, and we * will not access the variable again. */ varValuePtr = TclPtrSetVar(interp, varPtr, arrayPtr, part1, NULL, objv[i], (TCL_APPEND_VALUE | TCL_LEAVE_ERR_MSG)); if ((varValuePtr == NULL) || (varValuePtr == ((Interp *) interp)->emptyObjPtr)) { return TCL_ERROR; } } } Tcl_SetObjResult(interp, varValuePtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_LappendObjCmd -- * * This object-based procedure is invoked to process the "lappend" * Tcl command. See the user documentation for details on what it does. * * Results: * A standard Tcl object result value. * * Side effects: * A variable's value may be changed. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_LappendObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Tcl_Obj *varValuePtr, *newValuePtr; register List *listRepPtr; register Tcl_Obj **elemPtrs; int numElems, numRequired, createdNewObj, i, j; Var *varPtr, *arrayPtr; char *part1; if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "varName ?value value ...?"); return TCL_ERROR; } if (objc == 2) { newValuePtr = Tcl_ObjGetVar2(interp, objv[1], (Tcl_Obj *) NULL, 0); if (newValuePtr == NULL) { /* * The variable doesn't exist yet. Just create it with an empty * initial value. */ varValuePtr = Tcl_NewObj(); Tcl_IncrRefCount(varValuePtr); newValuePtr = Tcl_ObjSetVar2(interp, objv[1], NULL, varValuePtr, TCL_LEAVE_ERR_MSG); Tcl_DecrRefCount(varValuePtr); if (newValuePtr == NULL) { return TCL_ERROR; } } else { int result; result = Tcl_ListObjLength(interp, newValuePtr, &numElems); if (result != TCL_OK) { return result; } } } else { /* * We have arguments to append. We used to call Tcl_SetVar2 to * append each argument one at a time to ensure that traces were run * for each append step. We now append the arguments all at once * because it's faster. Note that a read trace and a write trace for * the variable will now each only be called once. Also, if the * variable's old value is unshared we modify it directly, otherwise * we create a new copy to modify: this is "copy on write". * * Note that you have to protect the variable pointers around * the TclPtrGetVar call to insure that they remain valid * even if the variable was undefined and unused. */ varPtr = TclObjLookupVar(interp, objv[1], NULL, TCL_LEAVE_ERR_MSG, "set", /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr); if (varPtr == NULL) { return TCL_ERROR; } varPtr->refCount++; if (arrayPtr != NULL) { arrayPtr->refCount++; } part1 = TclGetString(objv[1]); varValuePtr = TclPtrGetVar(interp, varPtr, arrayPtr, part1, NULL, TCL_LEAVE_ERR_MSG); varPtr->refCount--; if (arrayPtr != NULL) { arrayPtr->refCount--; } createdNewObj = 0; if (varValuePtr == NULL) { /* * We couldn't read the old value: either the var doesn't yet * exist or it's an array element. If it's new, we will try to * create it with Tcl_ObjSetVar2 below. */ varValuePtr = Tcl_NewObj(); createdNewObj = 1; } else if (Tcl_IsShared(varValuePtr)) { varValuePtr = Tcl_DuplicateObj(varValuePtr); createdNewObj = 1; } /* * Convert the variable's old value to a list object if necessary. */ if (varValuePtr->typePtr != &tclListType) { int result = tclListType.setFromAnyProc(interp, varValuePtr); if (result != TCL_OK) { if (createdNewObj) { Tcl_DecrRefCount(varValuePtr); /* free unneeded obj. */ } return result; } } listRepPtr = (List *) varValuePtr->internalRep.twoPtrValue.ptr1; elemPtrs = listRepPtr->elements; numElems = listRepPtr->elemCount; /* * If there is no room in the current array of element pointers, * allocate a new, larger array and copy the pointers to it. */ numRequired = numElems + (objc-2); if (numRequired > listRepPtr->maxElemCount) { int newMax = (2 * numRequired); Tcl_Obj **newElemPtrs = (Tcl_Obj **) ckalloc((unsigned) (newMax * sizeof(Tcl_Obj *))); memcpy((VOID *) newElemPtrs, (VOID *) elemPtrs, (size_t) (numElems * sizeof(Tcl_Obj *))); listRepPtr->maxElemCount = newMax; listRepPtr->elements = newElemPtrs; ckfree((char *) elemPtrs); elemPtrs = newElemPtrs; } /* * Insert the new elements at the end of the list. */ for (i = 2, j = numElems; i < objc; i++, j++) { elemPtrs[j] = objv[i]; Tcl_IncrRefCount(objv[i]); } listRepPtr->elemCount = numRequired; /* * Invalidate and free any old string representation since it no * longer reflects the list's internal representation. */ Tcl_InvalidateStringRep(varValuePtr); /* * Now store the list object back into the variable. If there is an * error setting the new value, decrement its ref count if it * was new and we didn't create the variable. */ Tcl_IncrRefCount(varValuePtr); newValuePtr = TclPtrSetVar(interp, varPtr, arrayPtr, part1, NULL, varValuePtr, TCL_LEAVE_ERR_MSG); Tcl_DecrRefCount(varValuePtr); if (newValuePtr == NULL) { return TCL_ERROR; } } /* * Set the interpreter's object result to refer to the variable's value * object. */ Tcl_SetObjResult(interp, newValuePtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_ArrayObjCmd -- * * This object-based procedure is invoked to process the "array" Tcl * command. See the user documentation for details on what it does. * * Results: * A standard Tcl result object. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_ArrayObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { /* * The list of constants below should match the arrayOptions string array * below. */ enum {ARRAY_ANYMORE, ARRAY_DONESEARCH, ARRAY_EXISTS, ARRAY_GET, ARRAY_NAMES, ARRAY_NEXTELEMENT, ARRAY_SET, ARRAY_SIZE, ARRAY_STARTSEARCH, ARRAY_STATISTICS, ARRAY_UNSET}; static CONST char *arrayOptions[] = { "anymore", "donesearch", "exists", "get", "names", "nextelement", "set", "size", "startsearch", "statistics", "unset", (char *) NULL }; Interp *iPtr = (Interp *) interp; Var *varPtr, *arrayPtr; Tcl_HashEntry *hPtr; Tcl_Obj *resultPtr, *varNamePtr; int notArray; char *varName; int index, result; if (objc < 3) { Tcl_WrongNumArgs(interp, 1, objv, "option arrayName ?arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[1], arrayOptions, "option", 0, &index) != TCL_OK) { return TCL_ERROR; } /* * Locate the array variable */ varNamePtr = objv[2]; varName = TclGetString(varNamePtr); varPtr = TclObjLookupVar(interp, varNamePtr, NULL, /*flags*/ 0, /*msg*/ 0, /*createPart1*/ 0, /*createPart2*/ 0, &arrayPtr); /* * Special array trace used to keep the env array in sync for * array names, array get, etc. */ if (varPtr != NULL && varPtr->tracePtr != NULL && (TclIsVarArray(varPtr) || TclIsVarUndefined(varPtr))) { if (TCL_ERROR == CallVarTraces(iPtr, arrayPtr, varPtr, varName, NULL, (TCL_LEAVE_ERR_MSG|TCL_NAMESPACE_ONLY|TCL_GLOBAL_ONLY| TCL_TRACE_ARRAY), /* leaveErrMsg */ 1)) { return TCL_ERROR; } } /* * Verify that it is indeed an array variable. This test comes after * the traces - the variable may actually become an array as an effect * of said traces. */ notArray = 0; if ((varPtr == NULL) || !TclIsVarArray(varPtr) || TclIsVarUndefined(varPtr)) { notArray = 1; } /* * We have to wait to get the resultPtr until here because * CallVarTraces can affect the result. */ resultPtr = Tcl_GetObjResult(interp); switch (index) { case ARRAY_ANYMORE: { ArraySearch *searchPtr; if (objc != 4) { Tcl_WrongNumArgs(interp, 2, objv, "arrayName searchId"); return TCL_ERROR; } if (notArray) { goto error; } searchPtr = ParseSearchId(interp, varPtr, varName, objv[3]); if (searchPtr == NULL) { return TCL_ERROR; } while (1) { Var *varPtr2; if (searchPtr->nextEntry != NULL) { varPtr2 = (Var *) Tcl_GetHashValue(searchPtr->nextEntry); if (!TclIsVarUndefined(varPtr2)) { break; } } searchPtr->nextEntry = Tcl_NextHashEntry(&searchPtr->search); if (searchPtr->nextEntry == NULL) { Tcl_SetIntObj(resultPtr, 0); return TCL_OK; } } Tcl_SetIntObj(resultPtr, 1); break; } case ARRAY_DONESEARCH: { ArraySearch *searchPtr, *prevPtr; if (objc != 4) { Tcl_WrongNumArgs(interp, 2, objv, "arrayName searchId"); return TCL_ERROR; } if (notArray) { goto error; } searchPtr = ParseSearchId(interp, varPtr, varName, objv[3]); if (searchPtr == NULL) { return TCL_ERROR; } if (varPtr->searchPtr == searchPtr) { varPtr->searchPtr = searchPtr->nextPtr; } else { for (prevPtr = varPtr->searchPtr; ; prevPtr = prevPtr->nextPtr) { if (prevPtr->nextPtr == searchPtr) { prevPtr->nextPtr = searchPtr->nextPtr; break; } } } ckfree((char *) searchPtr); break; } case ARRAY_EXISTS: { if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "arrayName"); return TCL_ERROR; } Tcl_SetIntObj(resultPtr, !notArray); break; } case ARRAY_GET: { Tcl_HashSearch search; Var *varPtr2; char *pattern = NULL; char *name; Tcl_Obj *namePtr, *valuePtr, *nameLstPtr, *tmpResPtr, **namePtrPtr; int i, count; if ((objc != 3) && (objc != 4)) { Tcl_WrongNumArgs(interp, 2, objv, "arrayName ?pattern?"); return TCL_ERROR; } if (notArray) { return TCL_OK; } if (objc == 4) { pattern = TclGetString(objv[3]); } /* * Store the array names in a new object. */ nameLstPtr = Tcl_NewObj(); Tcl_IncrRefCount(nameLstPtr); for (hPtr = Tcl_FirstHashEntry(varPtr->value.tablePtr, &search); hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { varPtr2 = (Var *) Tcl_GetHashValue(hPtr); if (TclIsVarUndefined(varPtr2)) { continue; } name = Tcl_GetHashKey(varPtr->value.tablePtr, hPtr); if ((objc == 4) && !Tcl_StringMatch(name, pattern)) { continue; /* element name doesn't match pattern */ } namePtr = Tcl_NewStringObj(name, -1); result = Tcl_ListObjAppendElement(interp, nameLstPtr, namePtr); if (result != TCL_OK) { Tcl_DecrRefCount(namePtr); /* free unneeded name obj */ Tcl_DecrRefCount(nameLstPtr); return result; } } /* * Make sure the Var structure of the array is not removed by * a trace while we're working. */ varPtr->refCount++; /* * Get the array values corresponding to each element name */ tmpResPtr = Tcl_NewObj(); result = Tcl_ListObjGetElements(interp, nameLstPtr, &count, &namePtrPtr); if (result != TCL_OK) { goto errorInArrayGet; } for (i = 0; i < count; i++) { namePtr = *namePtrPtr++; valuePtr = Tcl_ObjGetVar2(interp, objv[2], namePtr, TCL_LEAVE_ERR_MSG); if (valuePtr == NULL) { /* * Some trace played a trick on us; we need to diagnose to * adapt our behaviour: was the array element unset, or did * the modification modify the complete array? */ if (TclIsVarArray(varPtr) && !TclIsVarUndefined(varPtr)) { /* * The array itself looks OK, the variable was * undefined: forget it. */ continue; } else { result = TCL_ERROR; goto errorInArrayGet; } } result = Tcl_ListObjAppendElement(interp, tmpResPtr, namePtr); if (result != TCL_OK) { goto errorInArrayGet; } result = Tcl_ListObjAppendElement(interp, tmpResPtr, valuePtr); if (result != TCL_OK) { goto errorInArrayGet; } } varPtr->refCount--; Tcl_SetObjResult(interp, tmpResPtr); Tcl_DecrRefCount(nameLstPtr); break; errorInArrayGet: varPtr->refCount--; Tcl_DecrRefCount(nameLstPtr); Tcl_DecrRefCount(tmpResPtr); /* free unneeded temp result obj */ return result; } case ARRAY_NAMES: { Tcl_HashSearch search; Var *varPtr2; char *pattern = NULL; char *name; Tcl_Obj *namePtr; int mode, matched = 0; static CONST char *options[] = { "-exact", "-glob", "-regexp", (char *) NULL }; enum options { OPT_EXACT, OPT_GLOB, OPT_REGEXP }; mode = OPT_GLOB; if ((objc < 3) || (objc > 5)) { Tcl_WrongNumArgs(interp, 2, objv, "arrayName ?mode? ?pattern?"); return TCL_ERROR; } if (notArray) { return TCL_OK; } if (objc == 4) { pattern = Tcl_GetString(objv[3]); } else if (objc == 5) { pattern = Tcl_GetString(objv[4]); if (Tcl_GetIndexFromObj(interp, objv[3], options, "option", 0, &mode) != TCL_OK) { return TCL_ERROR; } } for (hPtr = Tcl_FirstHashEntry(varPtr->value.tablePtr, &search); hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { varPtr2 = (Var *) Tcl_GetHashValue(hPtr); if (TclIsVarUndefined(varPtr2)) { continue; } name = Tcl_GetHashKey(varPtr->value.tablePtr, hPtr); if (objc > 3) { switch ((enum options) mode) { case OPT_EXACT: matched = (strcmp(name, pattern) == 0); break; case OPT_GLOB: matched = Tcl_StringMatch(name, pattern); break; case OPT_REGEXP: matched = Tcl_RegExpMatch(interp, name, pattern); if (matched < 0) { return TCL_ERROR; } break; } if (matched == 0) { continue; } } namePtr = Tcl_NewStringObj(name, -1); result = Tcl_ListObjAppendElement(interp, resultPtr, namePtr); if (result != TCL_OK) { Tcl_DecrRefCount(namePtr); /* free unneeded name obj */ return result; } } break; } case ARRAY_NEXTELEMENT: { ArraySearch *searchPtr; Tcl_HashEntry *hPtr; if (objc != 4) { Tcl_WrongNumArgs(interp, 2, objv, "arrayName searchId"); return TCL_ERROR; } if (notArray) { goto error; } searchPtr = ParseSearchId(interp, varPtr, varName, objv[3]); if (searchPtr == NULL) { return TCL_ERROR; } while (1) { Var *varPtr2; hPtr = searchPtr->nextEntry; if (hPtr == NULL) { hPtr = Tcl_NextHashEntry(&searchPtr->search); if (hPtr == NULL) { return TCL_OK; } } else { searchPtr->nextEntry = NULL; } varPtr2 = (Var *) Tcl_GetHashValue(hPtr); if (!TclIsVarUndefined(varPtr2)) { break; } } Tcl_SetStringObj(resultPtr, Tcl_GetHashKey(varPtr->value.tablePtr, hPtr), -1); break; } case ARRAY_SET: { if (objc != 4) { Tcl_WrongNumArgs(interp, 2, objv, "arrayName list"); return TCL_ERROR; } return(TclArraySet(interp, objv[2], objv[3])); } case ARRAY_SIZE: { Tcl_HashSearch search; Var *varPtr2; int size; if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "arrayName"); return TCL_ERROR; } size = 0; if (!notArray) { for (hPtr = Tcl_FirstHashEntry(varPtr->value.tablePtr, &search); hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { varPtr2 = (Var *) Tcl_GetHashValue(hPtr); if (TclIsVarUndefined(varPtr2)) { continue; } size++; } } Tcl_SetIntObj(resultPtr, size); break; } case ARRAY_STARTSEARCH: { ArraySearch *searchPtr; if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "arrayName"); return TCL_ERROR; } if (notArray) { goto error; } searchPtr = (ArraySearch *) ckalloc(sizeof(ArraySearch)); if (varPtr->searchPtr == NULL) { searchPtr->id = 1; Tcl_AppendStringsToObj(resultPtr, "s-1-", varName, (char *) NULL); } else { char string[TCL_INTEGER_SPACE]; searchPtr->id = varPtr->searchPtr->id + 1; TclFormatInt(string, searchPtr->id); Tcl_AppendStringsToObj(resultPtr, "s-", string, "-", varName, (char *) NULL); } searchPtr->varPtr = varPtr; searchPtr->nextEntry = Tcl_FirstHashEntry(varPtr->value.tablePtr, &searchPtr->search); searchPtr->nextPtr = varPtr->searchPtr; varPtr->searchPtr = searchPtr; break; } case ARRAY_STATISTICS: { char *stats; if (notArray) { goto error; } stats = Tcl_HashStats(varPtr->value.tablePtr); if (stats != NULL) { Tcl_SetStringObj(Tcl_GetObjResult(interp), stats, -1); ckfree((void *)stats); } else { Tcl_SetResult(interp, "error reading array statistics", TCL_STATIC); return TCL_ERROR; } break; } case ARRAY_UNSET: { Tcl_HashSearch search; Var *varPtr2; char *pattern = NULL; char *name; if ((objc != 3) && (objc != 4)) { Tcl_WrongNumArgs(interp, 2, objv, "arrayName ?pattern?"); return TCL_ERROR; } if (notArray) { return TCL_OK; } if (objc == 3) { /* * When no pattern is given, just unset the whole array */ if (TclObjUnsetVar2(interp, varNamePtr, NULL, 0) != TCL_OK) { return TCL_ERROR; } } else { pattern = Tcl_GetString(objv[3]); for (hPtr = Tcl_FirstHashEntry(varPtr->value.tablePtr, &search); hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { varPtr2 = (Var *) Tcl_GetHashValue(hPtr); if (TclIsVarUndefined(varPtr2)) { continue; } name = Tcl_GetHashKey(varPtr->value.tablePtr, hPtr); if (Tcl_StringMatch(name, pattern) && (TclObjUnsetVar2(interp, varNamePtr, name, 0) != TCL_OK)) { return TCL_ERROR; } } } break; } } return TCL_OK; error: Tcl_AppendStringsToObj(resultPtr, "\"", varName, "\" isn't an array", (char *) NULL); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TclArraySet -- * * Set the elements of an array. If there are no elements to * set, create an empty array. This routine is used by the * Tcl_ArrayObjCmd and by the TclSetupEnv routine. * * Results: * A standard Tcl result object. * * Side effects: * A variable will be created if one does not already exist. * *---------------------------------------------------------------------- */ int TclArraySet(interp, arrayNameObj, arrayElemObj) Tcl_Interp *interp; /* Current interpreter. */ Tcl_Obj *arrayNameObj; /* The array name. */ Tcl_Obj *arrayElemObj; /* The array elements list. If this is * NULL, create an empty array. */ { Var *varPtr, *arrayPtr; Tcl_Obj **elemPtrs; int result, elemLen, i, nameLen; char *varName, *p; varName = Tcl_GetStringFromObj(arrayNameObj, &nameLen); p = varName + nameLen - 1; if (*p == ')') { while (--p >= varName) { if (*p == '(') { VarErrMsg(interp, varName, NULL, "set", needArray); return TCL_ERROR; } } } varPtr = TclObjLookupVar(interp, arrayNameObj, NULL, /*flags*/ TCL_LEAVE_ERR_MSG, /*msg*/ "set", /*createPart1*/ 1, /*createPart2*/ 0, &arrayPtr); if (varPtr == NULL) { return TCL_ERROR; } if (arrayElemObj != NULL) { result = Tcl_ListObjGetElements(interp, arrayElemObj, &elemLen, &elemPtrs); if (result != TCL_OK) { return result; } if (elemLen & 1) { Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "list must have an even number of elements", -1); return TCL_ERROR; } if (elemLen > 0) { /* * We needn't worry about traces invalidating arrayPtr: * should that be the case, TclPtrSetVar will return NULL * so that we break out of the loop and return an error. */ for (i = 0; i < elemLen; i += 2) { char *part2 = TclGetString(elemPtrs[i]); Var *elemVarPtr = TclLookupArrayElement(interp, varName, part2, TCL_LEAVE_ERR_MSG, "set", 1, 1, varPtr); if ((elemVarPtr == NULL) || (TclPtrSetVar(interp, elemVarPtr, varPtr, varName, part2, elemPtrs[i+1], TCL_LEAVE_ERR_MSG) == NULL)) { result = TCL_ERROR; break; } /* * The TclPtrSetVar call might have shimmered * arrayElemObj to another type, so re-fetch * the pointers for safety. */ Tcl_ListObjGetElements(NULL, arrayElemObj, &elemLen, &elemPtrs); } return result; } } /* * The list is empty make sure we have an array, or create * one if necessary. */ if (varPtr != NULL) { if (!TclIsVarUndefined(varPtr) && TclIsVarArray(varPtr)) { /* * Already an array, done. */ return TCL_OK; } if (TclIsVarArrayElement(varPtr) || !TclIsVarUndefined(varPtr)) { /* * Either an array element, or a scalar: lose! */ VarErrMsg(interp, varName, (char *)NULL, "array set", needArray); return TCL_ERROR; } } TclSetVarArray(varPtr); TclClearVarUndefined(varPtr); varPtr->value.tablePtr = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable)); Tcl_InitHashTable(varPtr->value.tablePtr, TCL_STRING_KEYS); return TCL_OK; } /* *---------------------------------------------------------------------- * * ObjMakeUpvar -- * * This procedure does all of the work of the "global" and "upvar" * commands. * * Results: * A standard Tcl completion code. If an error occurs then an * error message is left in iPtr->result. * * Side effects: * The variable given by myName is linked to the variable in framePtr * given by otherP1 and otherP2, so that references to myName are * redirected to the other variable like a symbolic link. * *---------------------------------------------------------------------- */ static int ObjMakeUpvar(interp, framePtr, otherP1Ptr, otherP2, otherFlags, myName, myFlags, index) Tcl_Interp *interp; /* Interpreter containing variables. Used * for error messages, too. */ CallFrame *framePtr; /* Call frame containing "other" variable. * NULL means use global :: context. */ Tcl_Obj *otherP1Ptr; CONST char *otherP2; /* Two-part name of variable in framePtr. */ CONST int otherFlags; /* 0, TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY: * indicates scope of "other" variable. */ CONST char *myName; /* Name of variable which will refer to * otherP1/otherP2. Must be a scalar. */ int myFlags; /* 0, TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY: * indicates scope of myName. */ int index; /* If the variable to be linked is an indexed * scalar, this is its index. Otherwise, -1. */ { Interp *iPtr = (Interp *) interp; Var *otherPtr, *varPtr, *arrayPtr; CallFrame *varFramePtr; CONST char *errMsg; /* * Find "other" in "framePtr". If not looking up other in just the * current namespace, temporarily replace the current var frame * pointer in the interpreter in order to use TclObjLookupVar. */ varFramePtr = iPtr->varFramePtr; if (!(otherFlags & TCL_NAMESPACE_ONLY)) { iPtr->varFramePtr = framePtr; } otherPtr = TclObjLookupVar(interp, otherP1Ptr, otherP2, (otherFlags | TCL_LEAVE_ERR_MSG), "access", /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr); if (!(otherFlags & TCL_NAMESPACE_ONLY)) { iPtr->varFramePtr = varFramePtr; } if (otherPtr == NULL) { return TCL_ERROR; } if (index >= 0) { if (!varFramePtr->isProcCallFrame) { panic("ObjMakeUpvar called with an index outside from a proc.\n"); } varPtr = &(varFramePtr->compiledLocals[index]); } else { /* * Check that we are not trying to create a namespace var linked to * a local variable in a procedure. If we allowed this, the local * variable in the shorter-lived procedure frame could go away * leaving the namespace var's reference invalid. */ if (((otherP2 ? arrayPtr->nsPtr : otherPtr->nsPtr) == NULL) && ((myFlags & (TCL_GLOBAL_ONLY | TCL_NAMESPACE_ONLY)) || (varFramePtr == NULL) || !varFramePtr->isProcCallFrame || (strstr(myName, "::") != NULL))) { Tcl_AppendResult((Tcl_Interp *) iPtr, "bad variable name \"", myName, "\": upvar won't create namespace variable that ", "refers to procedure variable", (char *) NULL); return TCL_ERROR; } /* * Lookup and eventually create the new variable. Set the flag bit * LOOKUP_FOR_UPVAR to indicate the special resolution rules for * upvar purposes: * - Bug #696893 - variable is either proc-local or in the current * namespace; never follow the second (global) resolution path * - Bug #631741 - do not use special namespace or interp resolvers */ varPtr = TclLookupSimpleVar(interp, myName, (myFlags | LOOKUP_FOR_UPVAR), /* create */ 1, &errMsg, &index); if (varPtr == NULL) { VarErrMsg(interp, myName, NULL, "create", errMsg); return TCL_ERROR; } } if (varPtr == otherPtr) { Tcl_SetResult((Tcl_Interp *) iPtr, "can't upvar from variable to itself", TCL_STATIC); return TCL_ERROR; } if (varPtr->tracePtr != NULL) { Tcl_AppendResult((Tcl_Interp *) iPtr, "variable \"", myName, "\" has traces: can't use for upvar", (char *) NULL); return TCL_ERROR; } else if (!TclIsVarUndefined(varPtr)) { /* * The variable already existed. Make sure this variable "varPtr" * isn't the same as "otherPtr" (avoid circular links). Also, if * it's not an upvar then it's an error. If it is an upvar, then * just disconnect it from the thing it currently refers to. */ if (TclIsVarLink(varPtr)) { Var *linkPtr = varPtr->value.linkPtr; if (linkPtr == otherPtr) { return TCL_OK; } linkPtr->refCount--; if (TclIsVarUndefined(linkPtr)) { CleanupVar(linkPtr, (Var *) NULL); } } else { Tcl_AppendResult((Tcl_Interp *) iPtr, "variable \"", myName, "\" already exists", (char *) NULL); return TCL_ERROR; } } TclSetVarLink(varPtr); TclClearVarUndefined(varPtr); varPtr->value.linkPtr = otherPtr; otherPtr->refCount++; return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_UpVar -- * * This procedure links one variable to another, just like * the "upvar" command. * * Results: * A standard Tcl completion code. If an error occurs then * an error message is left in the interp's result. * * Side effects: * The variable in frameName whose name is given by varName becomes * accessible under the name localName, so that references to * localName are redirected to the other variable like a symbolic * link. * *---------------------------------------------------------------------- */ #undef Tcl_UpVar int Tcl_UpVar(interp, frameName, varName, localName, flags) Tcl_Interp *interp; /* Command interpreter in which varName is * to be looked up. */ CONST char *frameName; /* Name of the frame containing the source * variable, such as "1" or "#0". */ CONST char *varName; /* Name of a variable in interp to link to. * May be either a scalar name or an * element in an array. */ CONST char *localName; /* Name of link variable. */ int flags; /* 0, TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY: * indicates scope of localName. */ { return Tcl_UpVar2(interp, frameName, varName, NULL, localName, flags); } /* *---------------------------------------------------------------------- * * Tcl_UpVar2 -- * * This procedure links one variable to another, just like * the "upvar" command. * * Results: * A standard Tcl completion code. If an error occurs then * an error message is left in the interp's result. * * Side effects: * The variable in frameName whose name is given by part1 and * part2 becomes accessible under the name localName, so that * references to localName are redirected to the other variable * like a symbolic link. * *---------------------------------------------------------------------- */ int Tcl_UpVar2(interp, frameName, part1, part2, localName, flags) Tcl_Interp *interp; /* Interpreter containing variables. Used * for error messages too. */ CONST char *frameName; /* Name of the frame containing the source * variable, such as "1" or "#0". */ CONST char *part1; CONST char *part2; /* Two parts of source variable name to * link to. */ CONST char *localName; /* Name of link variable. */ int flags; /* 0, TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY: * indicates scope of localName. */ { int result; CallFrame *framePtr; Tcl_Obj *part1Ptr; if (TclGetFrame(interp, frameName, &framePtr) == -1) { return TCL_ERROR; } part1Ptr = Tcl_NewStringObj(part1, -1); Tcl_IncrRefCount(part1Ptr); result = ObjMakeUpvar(interp, framePtr, part1Ptr, part2, 0, localName, flags, -1); TclDecrRefCount(part1Ptr); return result; } /* *---------------------------------------------------------------------- * * Tcl_GetVariableFullName -- * * Given a Tcl_Var token returned by Tcl_FindNamespaceVar, this * procedure appends to an object the namespace variable's full * name, qualified by a sequence of parent namespace names. * * Results: * None. * * Side effects: * The variable's fully-qualified name is appended to the string * representation of objPtr. * *---------------------------------------------------------------------- */ void Tcl_GetVariableFullName(interp, variable, objPtr) Tcl_Interp *interp; /* Interpreter containing the variable. */ Tcl_Var variable; /* Token for the variable returned by a * previous call to Tcl_FindNamespaceVar. */ Tcl_Obj *objPtr; /* Points to the object onto which the * variable's full name is appended. */ { Interp *iPtr = (Interp *) interp; register Var *varPtr = (Var *) variable; char *name; /* * Add the full name of the containing namespace (if any), followed by * the "::" separator, then the variable name. */ if (varPtr != NULL) { if (!TclIsVarArrayElement(varPtr)) { if (varPtr->nsPtr != NULL) { Tcl_AppendToObj(objPtr, varPtr->nsPtr->fullName, -1); if (varPtr->nsPtr != iPtr->globalNsPtr) { Tcl_AppendToObj(objPtr, "::", 2); } } if (varPtr->name != NULL) { Tcl_AppendToObj(objPtr, varPtr->name, -1); } else if (varPtr->hPtr != NULL) { name = Tcl_GetHashKey(varPtr->hPtr->tablePtr, varPtr->hPtr); Tcl_AppendToObj(objPtr, name, -1); } } } } /* *---------------------------------------------------------------------- * * Tcl_GlobalObjCmd -- * * This object-based procedure is invoked to process the "global" Tcl * command. See the user documentation for details on what it does. * * Results: * A standard Tcl object result value. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ int Tcl_GlobalObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Interp *iPtr = (Interp *) interp; register Tcl_Obj *objPtr; char *varName; register char *tail; int result, i; if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "varName ?varName ...?"); return TCL_ERROR; } /* * If we are not executing inside a Tcl procedure, just return. */ if ((iPtr->varFramePtr == NULL) || !iPtr->varFramePtr->isProcCallFrame) { return TCL_OK; } for (i = 1; i < objc; i++) { /* * Make a local variable linked to its counterpart in the global :: * namespace. */ objPtr = objv[i]; varName = TclGetString(objPtr); /* * The variable name might have a scope qualifier, but the name for * the local "link" variable must be the simple name at the tail. */ for (tail = varName; *tail != '\0'; tail++) { /* empty body */ } while ((tail > varName) && ((*tail != ':') || (*(tail-1) != ':'))) { tail--; } if ((*tail == ':') && (tail > varName)) { tail++; } /* * Link to the variable "varName" in the global :: namespace. */ result = ObjMakeUpvar(interp, (CallFrame *) NULL, objPtr, NULL, /*otherFlags*/ TCL_GLOBAL_ONLY, /*myName*/ tail, /*myFlags*/ 0, -1); if (result != TCL_OK) { return result; } } return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_VariableObjCmd -- * * Invoked to implement the "variable" command that creates one or more * global variables. Handles the following syntax: * * variable ?name value...? name ?value? * * One or more variables can be created. The variables are initialized * with the specified values. The value for the last variable is * optional. * * If the variable does not exist, it is created and given the optional * value. If it already exists, it is simply set to the optional * value. Normally, "name" is an unqualified name, so it is created in * the current namespace. If it includes namespace qualifiers, it can * be created in another namespace. * * If the variable command is executed inside a Tcl procedure, it * creates a local variable linked to the newly-created namespace * variable. * * Results: * Returns TCL_OK if the variable is found or created. Returns * TCL_ERROR if anything goes wrong. * * Side effects: * If anything goes wrong, this procedure returns an error message * as the result in the interpreter's result object. * *---------------------------------------------------------------------- */ int Tcl_VariableObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Interp *iPtr = (Interp *) interp; char *varName, *tail, *cp; Var *varPtr, *arrayPtr; Tcl_Obj *varValuePtr; int i, result; Tcl_Obj *varNamePtr; if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "?name value...? name ?value?"); return TCL_ERROR; } for (i = 1; i < objc; i = i+2) { /* * Look up each variable in the current namespace context, creating * it if necessary. */ varNamePtr = objv[i]; varName = TclGetString(varNamePtr); varPtr = TclObjLookupVar(interp, varNamePtr, NULL, (TCL_NAMESPACE_ONLY | TCL_LEAVE_ERR_MSG), "define", /*createPart1*/ 1, /*createPart2*/ 0, &arrayPtr); if (arrayPtr != NULL) { /* * Variable cannot be an element in an array. If arrayPtr is * non-null, it is, so throw up an error and return. */ VarErrMsg(interp, varName, NULL, "define", isArrayElement); return TCL_ERROR; } if (varPtr == NULL) { return TCL_ERROR; } /* * Mark the variable as a namespace variable and increment its * reference count so that it will persist until its namespace is * destroyed or until the variable is unset. */ if (!(varPtr->flags & VAR_NAMESPACE_VAR)) { varPtr->flags |= VAR_NAMESPACE_VAR; varPtr->refCount++; } /* * If a value was specified, set the variable to that value. * Otherwise, if the variable is new, leave it undefined. * (If the variable already exists and no value was specified, * leave its value unchanged; just create the local link if * we're in a Tcl procedure). */ if (i+1 < objc) { /* a value was specified */ varValuePtr = TclPtrSetVar(interp, varPtr, arrayPtr, varName, NULL, objv[i+1], (TCL_NAMESPACE_ONLY | TCL_LEAVE_ERR_MSG)); if (varValuePtr == NULL) { return TCL_ERROR; } } /* * If we are executing inside a Tcl procedure, create a local * variable linked to the new namespace variable "varName". */ if ((iPtr->varFramePtr != NULL) && iPtr->varFramePtr->isProcCallFrame) { /* * varName might have a scope qualifier, but the name for the * local "link" variable must be the simple name at the tail. * * Locate tail in one pass: drop any prefix after two *or more* * consecutive ":" characters). */ for (tail = cp = varName; *cp != '\0'; ) { if (*cp++ == ':') { while (*cp == ':') { tail = ++cp; } } } /* * Create a local link "tail" to the variable "varName" in the * current namespace. */ result = ObjMakeUpvar(interp, (CallFrame *) NULL, /*otherP1*/ varNamePtr, /*otherP2*/ NULL, /*otherFlags*/ TCL_NAMESPACE_ONLY, /*myName*/ tail, /*myFlags*/ 0, -1); if (result != TCL_OK) { return result; } } } return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_UpvarObjCmd -- * * This object-based procedure is invoked to process the "upvar" * Tcl command. See the user documentation for details on what it does. * * Results: * A standard Tcl object result value. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_UpvarObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { CallFrame *framePtr; char *frameSpec, *localName; int result; if (objc < 3) { upvarSyntax: Tcl_WrongNumArgs(interp, 1, objv, "?level? otherVar localVar ?otherVar localVar ...?"); return TCL_ERROR; } /* * Find the call frame containing each of the "other variables" to be * linked to. */ frameSpec = TclGetString(objv[1]); result = TclGetFrame(interp, frameSpec, &framePtr); if (result == -1) { return TCL_ERROR; } objc -= result+1; if ((objc & 1) != 0) { goto upvarSyntax; } objv += result+1; /* * Iterate over each (other variable, local variable) pair. * Divide the other variable name into two parts, then call * MakeUpvar to do all the work of linking it to the local variable. */ for ( ; objc > 0; objc -= 2, objv += 2) { localName = TclGetString(objv[1]); result = ObjMakeUpvar(interp, framePtr, /* othervarName */ objv[0], NULL, 0, /* myVarName */ localName, /*flags*/ 0, -1); if (result != TCL_OK) { return TCL_ERROR; } } return TCL_OK; } /* *---------------------------------------------------------------------- * * DisposeTraceResult-- * * This procedure is called to dispose of the result returned from * a trace procedure. The disposal method appropriate to the type * of result is determined by flags. * * Results: * None. * * Side effects: * The memory allocated for the trace result may be freed. * *---------------------------------------------------------------------- */ static void DisposeTraceResult(flags, result) int flags; /* Indicates type of result to determine * proper disposal method */ char *result; /* The result returned from a trace * procedure to be disposed */ { if (flags & TCL_TRACE_RESULT_DYNAMIC) { ckfree(result); } else if (flags & TCL_TRACE_RESULT_OBJECT) { Tcl_DecrRefCount((Tcl_Obj *) result); } } /* *---------------------------------------------------------------------- * * CallVarTraces -- * * This procedure is invoked to find and invoke relevant * trace procedures associated with a particular operation on * a variable. This procedure invokes traces both on the * variable and on its containing array (where relevant). * * Results: * Returns TCL_OK to indicate normal operation. Returns TCL_ERROR * if invocation of a trace procedure indicated an error. When * TCL_ERROR is returned and leaveErrMsg is true, then the * ::errorInfo variable of iPtr has information about the error * appended to it. * * Side effects: * Almost anything can happen, depending on trace; this procedure * itself doesn't have any side effects. * *---------------------------------------------------------------------- */ static int CallVarTraces(iPtr, arrayPtr, varPtr, part1, part2, flags, leaveErrMsg) Interp *iPtr; /* Interpreter containing variable. */ register Var *arrayPtr; /* Pointer to array variable that contains * the variable, or NULL if the variable * isn't an element of an array. */ Var *varPtr; /* Variable whose traces are to be * invoked. */ CONST char *part1; CONST char *part2; /* Variable's two-part name. */ int flags; /* Flags passed to trace procedures: * indicates what's happening to variable, * plus other stuff like TCL_GLOBAL_ONLY, * or TCL_NAMESPACE_ONLY. */ CONST int leaveErrMsg; /* If true, and one of the traces indicates an * error, then leave an error message and stack * trace information in *iPTr. */ { register VarTrace *tracePtr; ActiveVarTrace active; char *result; CONST char *openParen, *p; Tcl_DString nameCopy; int copiedName; int code = TCL_OK; int disposeFlags = 0; int saveErrFlags = iPtr->flags & (ERR_IN_PROGRESS | ERR_ALREADY_LOGGED | ERROR_CODE_SET); /* * If there are already similar trace procedures active for the * variable, don't call them again. */ if (varPtr->flags & VAR_TRACE_ACTIVE) { return code; } varPtr->flags |= VAR_TRACE_ACTIVE; varPtr->refCount++; if (arrayPtr != NULL) { arrayPtr->refCount++; } /* * If the variable name hasn't been parsed into array name and * element, do it here. If there really is an array element, * make a copy of the original name so that NULLs can be * inserted into it to separate the names (can't modify the name * string in place, because the string might get used by the * callbacks we invoke). */ copiedName = 0; if (part2 == NULL) { for (p = part1; *p ; p++) { if (*p == '(') { openParen = p; do { p++; } while (*p != '\0'); p--; if (*p == ')') { int offset = (openParen - part1); char *newPart1; Tcl_DStringInit(&nameCopy); Tcl_DStringAppend(&nameCopy, part1, (p-part1)); newPart1 = Tcl_DStringValue(&nameCopy); newPart1[offset] = 0; part1 = newPart1; part2 = newPart1 + offset + 1; copiedName = 1; } break; } } } /* * Invoke traces on the array containing the variable, if relevant. */ result = NULL; active.nextPtr = iPtr->activeVarTracePtr; iPtr->activeVarTracePtr = &active; Tcl_Preserve((ClientData) iPtr); if (arrayPtr != NULL && !(arrayPtr->flags & VAR_TRACE_ACTIVE)) { active.varPtr = arrayPtr; for (tracePtr = arrayPtr->tracePtr; tracePtr != NULL; tracePtr = active.nextTracePtr) { active.nextTracePtr = tracePtr->nextPtr; if (!(tracePtr->flags & flags)) { continue; } Tcl_Preserve((ClientData) tracePtr); if (Tcl_InterpDeleted((Tcl_Interp *)iPtr)) { flags |= TCL_INTERP_DESTROYED; } result = (*tracePtr->traceProc)(tracePtr->clientData, (Tcl_Interp *) iPtr, part1, part2, flags); if (result != NULL) { if (flags & TCL_TRACE_UNSETS) { /* Ignore errors in unset traces */ DisposeTraceResult(tracePtr->flags, result); } else { disposeFlags = tracePtr->flags; code = TCL_ERROR; } } Tcl_Release((ClientData) tracePtr); if (code == TCL_ERROR) { goto done; } } } /* * Invoke traces on the variable itself. */ if (flags & TCL_TRACE_UNSETS) { flags |= TCL_TRACE_DESTROYED; } active.varPtr = varPtr; for (tracePtr = varPtr->tracePtr; tracePtr != NULL; tracePtr = active.nextTracePtr) { active.nextTracePtr = tracePtr->nextPtr; if (!(tracePtr->flags & flags)) { continue; } Tcl_Preserve((ClientData) tracePtr); if (Tcl_InterpDeleted((Tcl_Interp *)iPtr)) { flags |= TCL_INTERP_DESTROYED; } result = (*tracePtr->traceProc)(tracePtr->clientData, (Tcl_Interp *) iPtr, part1, part2, flags); if (result != NULL) { if (flags & TCL_TRACE_UNSETS) { /* Ignore errors in unset traces */ DisposeTraceResult(tracePtr->flags, result); } else { disposeFlags = tracePtr->flags; code = TCL_ERROR; } } Tcl_Release((ClientData) tracePtr); if (code == TCL_ERROR) { goto done; } } /* * Restore the variable's flags, remove the record of our active * traces, and then return. */ done: if (code == TCL_OK) { iPtr->flags |= saveErrFlags; } if (code == TCL_ERROR) { if (leaveErrMsg) { CONST char *type = ""; switch (flags&(TCL_TRACE_READS|TCL_TRACE_WRITES|TCL_TRACE_ARRAY)) { case TCL_TRACE_READS: { type = "read"; break; } case TCL_TRACE_WRITES: { type = "set"; break; } case TCL_TRACE_ARRAY: { type = "trace array"; break; } } if (disposeFlags & TCL_TRACE_RESULT_OBJECT) { VarErrMsg((Tcl_Interp *) iPtr, part1, part2, type, Tcl_GetString((Tcl_Obj *) result)); } else { VarErrMsg((Tcl_Interp *) iPtr, part1, part2, type, result); } } DisposeTraceResult(disposeFlags,result); } if (arrayPtr != NULL) { arrayPtr->refCount--; } if (copiedName) { Tcl_DStringFree(&nameCopy); } varPtr->flags &= ~VAR_TRACE_ACTIVE; varPtr->refCount--; iPtr->activeVarTracePtr = active.nextPtr; Tcl_Release((ClientData) iPtr); return code; } /* *---------------------------------------------------------------------- * * NewVar -- * * Create a new heap-allocated variable that will eventually be * entered into a hashtable. * * Results: * The return value is a pointer to the new variable structure. It is * marked as a scalar variable (and not a link or array variable). Its * value initially is NULL. The variable is not part of any hash table * yet. Since it will be in a hashtable and not in a call frame, its * name field is set NULL. It is initially marked as undefined. * * Side effects: * Storage gets allocated. * *---------------------------------------------------------------------- */ static Var * NewVar() { register Var *varPtr; varPtr = (Var *) ckalloc(sizeof(Var)); varPtr->value.objPtr = NULL; varPtr->name = NULL; varPtr->nsPtr = NULL; varPtr->hPtr = NULL; varPtr->refCount = 0; varPtr->tracePtr = NULL; varPtr->searchPtr = NULL; varPtr->flags = (VAR_SCALAR | VAR_UNDEFINED | VAR_IN_HASHTABLE); return varPtr; } /* *---------------------------------------------------------------------- * * SetArraySearchObj -- * * This function converts the given tcl object into one that * has the "array search" internal type. * * Results: * TCL_OK if the conversion succeeded, and TCL_ERROR if it failed * (when an error message will be placed in the interpreter's * result.) * * Side effects: * Updates the internal type and representation of the object to * make this an array-search object. See the tclArraySearchType * declaration above for details of the internal representation. * *---------------------------------------------------------------------- */ static int SetArraySearchObj(interp, objPtr) Tcl_Interp *interp; Tcl_Obj *objPtr; { char *string; char *end; int id; size_t offset; /* * Get the string representation. Make it up-to-date if necessary. */ string = Tcl_GetString(objPtr); /* * Parse the id into the three parts separated by dashes. */ if ((string[0] != 's') || (string[1] != '-')) { syntax: Tcl_AppendResult(interp, "illegal search identifier \"", string, "\"", (char *) NULL); return TCL_ERROR; } id = strtoul(string+2, &end, 10); if ((end == (string+2)) || (*end != '-')) { goto syntax; } /* * Can't perform value check in this context, so place reference * to place in string to use for the check in the object instead. */ end++; offset = end - string; if (objPtr->typePtr != NULL && objPtr->typePtr->freeIntRepProc != NULL) { objPtr->typePtr->freeIntRepProc(objPtr); } objPtr->typePtr = &tclArraySearchType; objPtr->internalRep.twoPtrValue.ptr1 = (VOID *)(((char *)NULL)+id); objPtr->internalRep.twoPtrValue.ptr2 = (VOID *)(((char *)NULL)+offset); return TCL_OK; } /* *---------------------------------------------------------------------- * * ParseSearchId -- * * This procedure translates from a tcl object to a pointer to an * active array search (if there is one that matches the string). * * Results: * The return value is a pointer to the array search indicated * by string, or NULL if there isn't one. If NULL is returned, * the interp's result contains an error message. * * Side effects: * The tcl object might have its internal type and representation * modified. * *---------------------------------------------------------------------- */ static ArraySearch * ParseSearchId(interp, varPtr, varName, handleObj) Tcl_Interp *interp; /* Interpreter containing variable. */ CONST Var *varPtr; /* Array variable search is for. */ CONST char *varName; /* Name of array variable that search is * supposed to be for. */ Tcl_Obj *handleObj; /* Object containing id of search. Must have * form "search-num-var" where "num" is a * decimal number and "var" is a variable * name. */ { register char *string; register size_t offset; int id; ArraySearch *searchPtr; /* * Parse the id. */ if (Tcl_ConvertToType(interp, handleObj, &tclArraySearchType) != TCL_OK) { return NULL; } /* * Cast is safe, since always came from an int in the first place. */ id = (int)(((char*)handleObj->internalRep.twoPtrValue.ptr1) - ((char*)NULL)); string = Tcl_GetString(handleObj); offset = (((char*)handleObj->internalRep.twoPtrValue.ptr2) - ((char*)NULL)); /* * This test cannot be placed inside the Tcl_Obj machinery, since * it is dependent on the variable context. */ if (strcmp(string+offset, varName) != 0) { Tcl_AppendResult(interp, "search identifier \"", string, "\" isn't for variable \"", varName, "\"", (char *) NULL); return NULL; } /* * Search through the list of active searches on the interpreter * to see if the desired one exists. * * Note that we cannot store the searchPtr directly in the Tcl_Obj * as that would run into trouble when DeleteSearches() was called * so we must scan this list every time. */ for (searchPtr = varPtr->searchPtr; searchPtr != NULL; searchPtr = searchPtr->nextPtr) { if (searchPtr->id == id) { return searchPtr; } } Tcl_AppendResult(interp, "couldn't find search \"", string, "\"", (char *) NULL); return NULL; } /* *---------------------------------------------------------------------- * * DeleteSearches -- * * This procedure is called to free up all of the searches * associated with an array variable. * * Results: * None. * * Side effects: * Memory is released to the storage allocator. * *---------------------------------------------------------------------- */ static void DeleteSearches(arrayVarPtr) register Var *arrayVarPtr; /* Variable whose searches are * to be deleted. */ { ArraySearch *searchPtr; while (arrayVarPtr->searchPtr != NULL) { searchPtr = arrayVarPtr->searchPtr; arrayVarPtr->searchPtr = searchPtr->nextPtr; ckfree((char *) searchPtr); } } /* *---------------------------------------------------------------------- * * TclDeleteNamespaceVars -- * * This procedure is called to recycle all the storage space * associated with a namespace's table of variables. * * Results: * None. * * Side effects: * Variables are deleted and trace procedures are invoked, if * any are declared. * *---------------------------------------------------------------------- */ void TclDeleteNamespaceVars(nsPtr) Namespace *nsPtr; { Tcl_HashTable *tablePtr = &nsPtr->varTable; Tcl_Interp *interp = nsPtr->interp; Interp *iPtr = (Interp *)interp; Tcl_HashSearch search; Tcl_HashEntry *hPtr; int flags = 0; Namespace *currNsPtr = (Namespace *) Tcl_GetCurrentNamespace(interp); /* * Determine what flags to pass to the trace callback procedures. */ if (nsPtr == iPtr->globalNsPtr) { flags = TCL_GLOBAL_ONLY; } else if (nsPtr == currNsPtr) { flags = TCL_NAMESPACE_ONLY; } for (hPtr = Tcl_FirstHashEntry(tablePtr, &search); hPtr != NULL; hPtr = Tcl_FirstHashEntry(tablePtr, &search)) { register Var *varPtr = (Var *) Tcl_GetHashValue(hPtr); Tcl_Obj *objPtr = Tcl_NewObj(); varPtr->refCount++; /* Make sure we get to remove from hash */ Tcl_IncrRefCount(objPtr); Tcl_GetVariableFullName(interp, (Tcl_Var) varPtr, objPtr); UnsetVarStruct(varPtr, NULL, iPtr, Tcl_GetString(objPtr), NULL, flags); Tcl_DecrRefCount(objPtr); /* free no longer needed obj */ varPtr->refCount--; /* Remove the variable from the table and force it undefined * in case an unset trace brought it back from the dead */ Tcl_DeleteHashEntry(hPtr); varPtr->hPtr = NULL; TclSetVarUndefined(varPtr); TclSetVarScalar(varPtr); while (varPtr->tracePtr != NULL) { VarTrace *tracePtr = varPtr->tracePtr; varPtr->tracePtr = tracePtr->nextPtr; Tcl_EventuallyFree((ClientData) tracePtr, TCL_DYNAMIC); } CleanupVar(varPtr, NULL); } Tcl_DeleteHashTable(tablePtr); } /* *---------------------------------------------------------------------- * * TclDeleteVars -- * * This procedure is called to recycle all the storage space * associated with a table of variables. For this procedure * to work correctly, it must not be possible for any of the * variables in the table to be accessed from Tcl commands * (e.g. from trace procedures). * * Results: * None. * * Side effects: * Variables are deleted and trace procedures are invoked, if * any are declared. * *---------------------------------------------------------------------- */ void TclDeleteVars(iPtr, tablePtr) Interp *iPtr; /* Interpreter to which variables belong. */ Tcl_HashTable *tablePtr; /* Hash table containing variables to * delete. */ { Tcl_Interp *interp = (Tcl_Interp *) iPtr; Tcl_HashSearch search; Tcl_HashEntry *hPtr; register Var *varPtr; Var *linkPtr; int flags; ActiveVarTrace *activePtr; Tcl_Obj *objPtr; Namespace *currNsPtr = (Namespace *) Tcl_GetCurrentNamespace(interp); /* * Determine what flags to pass to the trace callback procedures. */ flags = TCL_TRACE_UNSETS; if (tablePtr == &iPtr->globalNsPtr->varTable) { flags |= TCL_GLOBAL_ONLY; } else if (tablePtr == &currNsPtr->varTable) { flags |= TCL_NAMESPACE_ONLY; } for (hPtr = Tcl_FirstHashEntry(tablePtr, &search); hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { varPtr = (Var *) Tcl_GetHashValue(hPtr); /* * For global/upvar variables referenced in procedures, decrement * the reference count on the variable referred to, and free * the referenced variable if it's no longer needed. Don't delete * the hash entry for the other variable if it's in the same table * as us: this will happen automatically later on. */ if (TclIsVarLink(varPtr)) { linkPtr = varPtr->value.linkPtr; linkPtr->refCount--; if ((linkPtr->refCount == 0) && TclIsVarUndefined(linkPtr) && (linkPtr->tracePtr == NULL) && (linkPtr->flags & VAR_IN_HASHTABLE)) { if (linkPtr->hPtr == NULL) { ckfree((char *) linkPtr); } else if (linkPtr->hPtr->tablePtr != tablePtr) { Tcl_DeleteHashEntry(linkPtr->hPtr); ckfree((char *) linkPtr); } } } /* * Invoke traces on the variable that is being deleted, then * free up the variable's space (no need to free the hash entry * here, unless we're dealing with a global variable: the * hash entries will be deleted automatically when the whole * table is deleted). Note that we give CallVarTraces the variable's * fully-qualified name so that any called trace procedures can * refer to these variables being deleted. */ if (varPtr->tracePtr != NULL) { objPtr = Tcl_NewObj(); Tcl_IncrRefCount(objPtr); /* until done with traces */ Tcl_GetVariableFullName(interp, (Tcl_Var) varPtr, objPtr); CallVarTraces(iPtr, (Var *) NULL, varPtr, Tcl_GetString(objPtr), NULL, flags, /* leaveErrMsg */ 0); Tcl_DecrRefCount(objPtr); /* free no longer needed obj */ while (varPtr->tracePtr != NULL) { VarTrace *tracePtr = varPtr->tracePtr; varPtr->tracePtr = tracePtr->nextPtr; Tcl_EventuallyFree((ClientData) tracePtr, TCL_DYNAMIC); } for (activePtr = iPtr->activeVarTracePtr; activePtr != NULL; activePtr = activePtr->nextPtr) { if (activePtr->varPtr == varPtr) { activePtr->nextTracePtr = NULL; } } } if (TclIsVarArray(varPtr)) { DeleteArray(iPtr, Tcl_GetHashKey(tablePtr, hPtr), varPtr, flags); varPtr->value.tablePtr = NULL; } if (TclIsVarScalar(varPtr) && (varPtr->value.objPtr != NULL)) { objPtr = varPtr->value.objPtr; TclDecrRefCount(objPtr); varPtr->value.objPtr = NULL; } varPtr->hPtr = NULL; varPtr->tracePtr = NULL; TclSetVarUndefined(varPtr); TclSetVarScalar(varPtr); /* * If the variable was a namespace variable, decrement its * reference count. We are in the process of destroying its * namespace so that namespace will no longer "refer" to the * variable. */ if (varPtr->flags & VAR_NAMESPACE_VAR) { varPtr->flags &= ~VAR_NAMESPACE_VAR; varPtr->refCount--; } /* * Recycle the variable's memory space if there aren't any upvar's * pointing to it. If there are upvars to this variable, then the * variable will get freed when the last upvar goes away. */ if (varPtr->refCount == 0) { ckfree((char *) varPtr); /* this Var must be VAR_IN_HASHTABLE */ } } Tcl_DeleteHashTable(tablePtr); } /* *---------------------------------------------------------------------- * * TclDeleteCompiledLocalVars -- * * This procedure is called to recycle storage space associated with * the compiler-allocated array of local variables in a procedure call * frame. This procedure resembles TclDeleteVars above except that each * variable is stored in a call frame and not a hash table. For this * procedure to work correctly, it must not be possible for any of the * variable in the table to be accessed from Tcl commands (e.g. from * trace procedures). * * Results: * None. * * Side effects: * Variables are deleted and trace procedures are invoked, if * any are declared. * *---------------------------------------------------------------------- */ void TclDeleteCompiledLocalVars(iPtr, framePtr) Interp *iPtr; /* Interpreter to which variables belong. */ CallFrame *framePtr; /* Procedure call frame containing * compiler-assigned local variables to * delete. */ { register Var *varPtr; int flags; /* Flags passed to trace procedures. */ Var *linkPtr; ActiveVarTrace *activePtr; int numLocals, i; flags = TCL_TRACE_UNSETS; numLocals = framePtr->numCompiledLocals; varPtr = framePtr->compiledLocals; for (i = 0; i < numLocals; i++) { /* * For global/upvar variables referenced in procedures, decrement * the reference count on the variable referred to, and free * the referenced variable if it's no longer needed. Don't delete * the hash entry for the other variable if it's in the same table * as us: this will happen automatically later on. */ if (TclIsVarLink(varPtr)) { linkPtr = varPtr->value.linkPtr; linkPtr->refCount--; if ((linkPtr->refCount == 0) && TclIsVarUndefined(linkPtr) && (linkPtr->tracePtr == NULL) && (linkPtr->flags & VAR_IN_HASHTABLE)) { if (linkPtr->hPtr == NULL) { ckfree((char *) linkPtr); } else { Tcl_DeleteHashEntry(linkPtr->hPtr); ckfree((char *) linkPtr); } } } /* * Invoke traces on the variable that is being deleted. Then delete * the variable's trace records. */ if (varPtr->tracePtr != NULL) { CallVarTraces(iPtr, (Var *) NULL, varPtr, varPtr->name, NULL, flags, /* leaveErrMsg */ 0); while (varPtr->tracePtr != NULL) { VarTrace *tracePtr = varPtr->tracePtr; varPtr->tracePtr = tracePtr->nextPtr; Tcl_EventuallyFree((ClientData) tracePtr, TCL_DYNAMIC); } for (activePtr = iPtr->activeVarTracePtr; activePtr != NULL; activePtr = activePtr->nextPtr) { if (activePtr->varPtr == varPtr) { activePtr->nextTracePtr = NULL; } } } /* * Now if the variable is an array, delete its element hash table. * Otherwise, if it's a scalar variable, decrement the ref count * of its value. */ if (TclIsVarArray(varPtr) && (varPtr->value.tablePtr != NULL)) { DeleteArray(iPtr, varPtr->name, varPtr, flags); } if (TclIsVarScalar(varPtr) && (varPtr->value.objPtr != NULL)) { TclDecrRefCount(varPtr->value.objPtr); varPtr->value.objPtr = NULL; } varPtr->hPtr = NULL; varPtr->tracePtr = NULL; TclSetVarUndefined(varPtr); TclSetVarScalar(varPtr); varPtr++; } } /* *---------------------------------------------------------------------- * * DeleteArray -- * * This procedure is called to free up everything in an array * variable. It's the caller's responsibility to make sure * that the array is no longer accessible before this procedure * is called. * * Results: * None. * * Side effects: * All storage associated with varPtr's array elements is deleted * (including the array's hash table). Deletion trace procedures for * array elements are invoked, then deleted. Any pending traces for * array elements are also deleted. * *---------------------------------------------------------------------- */ static void DeleteArray(iPtr, arrayName, varPtr, flags) Interp *iPtr; /* Interpreter containing array. */ CONST char *arrayName; /* Name of array (used for trace * callbacks). */ Var *varPtr; /* Pointer to variable structure. */ int flags; /* Flags to pass to CallVarTraces: * TCL_TRACE_UNSETS and sometimes * TCL_NAMESPACE_ONLY, or * TCL_GLOBAL_ONLY. */ { Tcl_HashSearch search; register Tcl_HashEntry *hPtr; register Var *elPtr; ActiveVarTrace *activePtr; Tcl_Obj *objPtr; DeleteSearches(varPtr); for (hPtr = Tcl_FirstHashEntry(varPtr->value.tablePtr, &search); hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { elPtr = (Var *) Tcl_GetHashValue(hPtr); if (TclIsVarScalar(elPtr) && (elPtr->value.objPtr != NULL)) { objPtr = elPtr->value.objPtr; TclDecrRefCount(objPtr); elPtr->value.objPtr = NULL; } elPtr->hPtr = NULL; if (elPtr->tracePtr != NULL) { elPtr->flags &= ~VAR_TRACE_ACTIVE; CallVarTraces(iPtr, (Var *) NULL, elPtr, arrayName, Tcl_GetHashKey(varPtr->value.tablePtr, hPtr), flags, /* leaveErrMsg */ 0); while (elPtr->tracePtr != NULL) { VarTrace *tracePtr = elPtr->tracePtr; elPtr->tracePtr = tracePtr->nextPtr; Tcl_EventuallyFree((ClientData) tracePtr,TCL_DYNAMIC); } for (activePtr = iPtr->activeVarTracePtr; activePtr != NULL; activePtr = activePtr->nextPtr) { if (activePtr->varPtr == elPtr) { activePtr->nextTracePtr = NULL; } } } TclSetVarUndefined(elPtr); TclSetVarScalar(elPtr); /* * Even though array elements are not supposed to be namespace * variables, some combinations of [upvar] and [variable] may * create such beasts - see [Bug 604239]. This is necessary to * avoid leaking the corresponding Var struct, and is otherwise * harmless. */ if (elPtr->flags & VAR_NAMESPACE_VAR) { elPtr->flags &= ~VAR_NAMESPACE_VAR; elPtr->refCount--; } if (elPtr->refCount == 0) { ckfree((char *) elPtr); /* element Vars are VAR_IN_HASHTABLE */ } } Tcl_DeleteHashTable(varPtr->value.tablePtr); ckfree((char *) varPtr->value.tablePtr); } /* *---------------------------------------------------------------------- * * CleanupVar -- * * This procedure is called when it looks like it may be OK to free up * a variable's storage. If the variable is in a hashtable, its Var * structure and hash table entry will be freed along with those of its * containing array, if any. This procedure is called, for example, * when a trace on a variable deletes a variable. * * Results: * None. * * Side effects: * If the variable (or its containing array) really is dead and in a * hashtable, then its Var structure, and possibly its hash table * entry, is freed up. * *---------------------------------------------------------------------- */ static void CleanupVar(varPtr, arrayPtr) Var *varPtr; /* Pointer to variable that may be a * candidate for being expunged. */ Var *arrayPtr; /* Array that contains the variable, or * NULL if this variable isn't an array * element. */ { if (TclIsVarUndefined(varPtr) && (varPtr->refCount == 0) && (varPtr->tracePtr == NULL) && (varPtr->flags & VAR_IN_HASHTABLE)) { if (varPtr->hPtr != NULL) { Tcl_DeleteHashEntry(varPtr->hPtr); } ckfree((char *) varPtr); } if (arrayPtr != NULL) { if (TclIsVarUndefined(arrayPtr) && (arrayPtr->refCount == 0) && (arrayPtr->tracePtr == NULL) && (arrayPtr->flags & VAR_IN_HASHTABLE)) { if (arrayPtr->hPtr != NULL) { Tcl_DeleteHashEntry(arrayPtr->hPtr); } ckfree((char *) arrayPtr); } } } /* *---------------------------------------------------------------------- * * VarErrMsg -- * * Generate a reasonable error message describing why a variable * operation failed. * * Results: * None. * * Side effects: * The interp's result is set to hold a message identifying the * variable given by part1 and part2 and describing why the * variable operation failed. * *---------------------------------------------------------------------- */ static void VarErrMsg(interp, part1, part2, operation, reason) Tcl_Interp *interp; /* Interpreter in which to record message. */ CONST char *part1; CONST char *part2; /* Variable's two-part name. */ CONST char *operation; /* String describing operation that failed, * e.g. "read", "set", or "unset". */ CONST char *reason; /* String describing why operation failed. */ { Tcl_ResetResult(interp); Tcl_AppendResult(interp, "can't ", operation, " \"", part1, (char *) NULL); if (part2 != NULL) { Tcl_AppendResult(interp, "(", part2, ")", (char *) NULL); } Tcl_AppendResult(interp, "\": ", reason, (char *) NULL); } /* *---------------------------------------------------------------------- * * TclTraceVarExists -- * * This is called from info exists. We need to trigger read * and/or array traces because they may end up creating a * variable that doesn't currently exist. * * Results: * A pointer to the Var structure, or NULL. * * Side effects: * May fill in error messages in the interp. * *---------------------------------------------------------------------- */ Var * TclVarTraceExists(interp, varName) Tcl_Interp *interp; /* The interpreter */ CONST char *varName; /* The variable name */ { Var *varPtr; Var *arrayPtr; /* * The choice of "create" flag values is delicate here, and * matches the semantics of GetVar. Things are still not perfect, * however, because if you do "info exists x" you get a varPtr * and therefore trigger traces. However, if you do * "info exists x(i)", then you only get a varPtr if x is already * known to be an array. Otherwise you get NULL, and no trace * is triggered. This matches Tcl 7.6 semantics. */ varPtr = TclLookupVar(interp, varName, (char *) NULL, 0, "access", /*createPart1*/ 0, /*createPart2*/ 1, &arrayPtr); if (varPtr == NULL) { return NULL; } if ((varPtr->tracePtr != NULL) || ((arrayPtr != NULL) && (arrayPtr->tracePtr != NULL))) { CallVarTraces((Interp *)interp, arrayPtr, varPtr, varName, NULL, TCL_TRACE_READS, /* leaveErrMsg */ 0); } /* * If the variable doesn't exist anymore and no-one's using * it, then free up the relevant structures and hash table entries. */ if (TclIsVarUndefined(varPtr)) { CleanupVar(varPtr, arrayPtr); return NULL; } return varPtr; } /* *---------------------------------------------------------------------- * * Internal functions for variable name object types -- * *---------------------------------------------------------------------- */ /* * localVarName - * * INTERNALREP DEFINITION: * twoPtrValue.ptr1 = pointer to the corresponding Proc * twoPtrValue.ptr2 = index into locals table */ static void FreeLocalVarName(objPtr) Tcl_Obj *objPtr; { register Proc *procPtr = (Proc *) objPtr->internalRep.twoPtrValue.ptr1; procPtr->refCount--; if (procPtr->refCount <= 0) { TclProcCleanupProc(procPtr); } } static void DupLocalVarName(srcPtr, dupPtr) Tcl_Obj *srcPtr; Tcl_Obj *dupPtr; { register Proc *procPtr = (Proc *) srcPtr->internalRep.twoPtrValue.ptr1; dupPtr->internalRep.twoPtrValue.ptr1 = (VOID *) procPtr; dupPtr->internalRep.twoPtrValue.ptr2 = srcPtr->internalRep.twoPtrValue.ptr2; procPtr->refCount++; dupPtr->typePtr = &tclLocalVarNameType; } static void UpdateLocalVarName(objPtr) Tcl_Obj *objPtr; { Proc *procPtr = (Proc *) objPtr->internalRep.twoPtrValue.ptr1; unsigned int index = (unsigned int) objPtr->internalRep.twoPtrValue.ptr2; CompiledLocal *localPtr = procPtr->firstLocalPtr; unsigned int nameLen; if (localPtr == NULL) { goto emptyName; } while (index--) { localPtr = localPtr->nextPtr; if (localPtr == NULL) { goto emptyName; } } nameLen = (unsigned int) localPtr->nameLength; objPtr->bytes = ckalloc(nameLen + 1); memcpy(objPtr->bytes, localPtr->name, nameLen + 1); objPtr->length = nameLen; return; emptyName: objPtr->bytes = ckalloc(1); *(objPtr->bytes) = '\0'; objPtr->length = 0; } /* * nsVarName - * * INTERNALREP DEFINITION: * twoPtrValue.ptr1: pointer to the namespace containing the * reference. * twoPtrValue.ptr2: pointer to the corresponding Var */ static void FreeNsVarName(objPtr) Tcl_Obj *objPtr; { register Var *varPtr = (Var *) objPtr->internalRep.twoPtrValue.ptr2; varPtr->refCount--; if (TclIsVarUndefined(varPtr) && (varPtr->refCount <= 0)) { if (TclIsVarLink(varPtr)) { Var *linkPtr = varPtr->value.linkPtr; linkPtr->refCount--; if (TclIsVarUndefined(linkPtr) && (linkPtr->refCount <= 0)) { CleanupVar(linkPtr, (Var *) NULL); } } CleanupVar(varPtr, NULL); } } static void DupNsVarName(srcPtr, dupPtr) Tcl_Obj *srcPtr; Tcl_Obj *dupPtr; { Namespace *nsPtr = (Namespace *) srcPtr->internalRep.twoPtrValue.ptr1; register Var *varPtr = (Var *) srcPtr->internalRep.twoPtrValue.ptr2; dupPtr->internalRep.twoPtrValue.ptr1 = (VOID *) nsPtr; dupPtr->internalRep.twoPtrValue.ptr2 = (VOID *) varPtr; varPtr->refCount++; dupPtr->typePtr = &tclNsVarNameType; } /* * parsedVarName - * * INTERNALREP DEFINITION: * twoPtrValue.ptr1 = pointer to the array name Tcl_Obj * (NULL if scalar) * twoPtrValue.ptr2 = pointer to the element name string * (owned by this Tcl_Obj), or NULL if * it is a scalar variable */ static void FreeParsedVarName(objPtr) Tcl_Obj *objPtr; { register Tcl_Obj *arrayPtr = (Tcl_Obj *) objPtr->internalRep.twoPtrValue.ptr1; register char *elem = (char *) objPtr->internalRep.twoPtrValue.ptr2; if (arrayPtr != NULL) { TclDecrRefCount(arrayPtr); ckfree(elem); } } static void DupParsedVarName(srcPtr, dupPtr) Tcl_Obj *srcPtr; Tcl_Obj *dupPtr; { register Tcl_Obj *arrayPtr = (Tcl_Obj *) srcPtr->internalRep.twoPtrValue.ptr1; register char *elem = (char *) srcPtr->internalRep.twoPtrValue.ptr2; char *elemCopy; unsigned int elemLen; if (arrayPtr != NULL) { Tcl_IncrRefCount(arrayPtr); elemLen = strlen(elem); elemCopy = ckalloc(elemLen+1); memcpy(elemCopy, elem, elemLen); *(elemCopy + elemLen) = '\0'; elem = elemCopy; } dupPtr->internalRep.twoPtrValue.ptr1 = (VOID *) arrayPtr; dupPtr->internalRep.twoPtrValue.ptr2 = (VOID *) elem; dupPtr->typePtr = &tclParsedVarNameType; } static void UpdateParsedVarName(objPtr) Tcl_Obj *objPtr; { Tcl_Obj *arrayPtr = (Tcl_Obj *) objPtr->internalRep.twoPtrValue.ptr1; char *part2 = (char *) objPtr->internalRep.twoPtrValue.ptr2; char *part1, *p; int len1, len2, totalLen; if (arrayPtr == NULL) { /* * This is a parsed scalar name: what is it * doing here? */ panic("ERROR: scalar parsedVarName without a string rep.\n"); } part1 = Tcl_GetStringFromObj(arrayPtr, &len1); len2 = strlen(part2); totalLen = len1 + len2 + 2; p = ckalloc((unsigned int) totalLen + 1); objPtr->bytes = p; objPtr->length = totalLen; memcpy(p, part1, (unsigned int) len1); p += len1; *p++ = '('; memcpy(p, part2, (unsigned int) len2); p += len2; *p++ = ')'; *p = '\0'; } tcl8.4.20/generic/tcl.h0000644003604700454610000024431112151137515013262 0ustar dgp771div/* * tcl.h -- * * This header file describes the externally-visible facilities * of the Tcl interpreter. * * Copyright (c) 1987-1994 The Regents of the University of California. * Copyright (c) 1993-1996 Lucent Technologies. * Copyright (c) 1994-1998 Sun Microsystems, Inc. * Copyright (c) 1998-2000 by Scriptics Corporation. * Copyright (c) 2002 by Kevin B. Kenny. All rights reserved. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef _TCL #define _TCL /* * For C++ compilers, use extern "C" */ #ifdef __cplusplus extern "C" { #endif /* * The following defines are used to indicate the various release levels. */ #define TCL_ALPHA_RELEASE 0 #define TCL_BETA_RELEASE 1 #define TCL_FINAL_RELEASE 2 /* * When version numbers change here, must also go into the following files * and update the version numbers: * * library/init.tcl (only if Major.minor changes, not patchlevel) 1 LOC * unix/configure.in (2 LOC Major, 2 LOC minor, 1 LOC patch) * win/configure.in (as above) * win/tcl.m4 (not patchlevel) * win/makefile.vc (not patchlevel) 2 LOC * README (sections 0 and 2) * mac/README (2 LOC, not patchlevel) * macosx/Tcl.pbproj/project.pbxproj (not patchlevel) 1 LOC * macosx/Tcl.pbproj/default.pbxuser (not patchlevel) 1 LOC * win/README.binary (sections 0-4) * win/README (not patchlevel) (sections 0 and 2) * unix/tcl.spec (2 LOC Major/Minor, 1 LOC patch) * tests/basic.test (1 LOC M/M, not patchlevel) * tools/tcl.hpj.in (not patchlevel, for windows installer) * tools/tcl.wse.in (for windows installer) * tools/tclSplash.bmp (not patchlevel) */ #define TCL_MAJOR_VERSION 8 #define TCL_MINOR_VERSION 4 #define TCL_RELEASE_LEVEL TCL_FINAL_RELEASE #define TCL_RELEASE_SERIAL 20 #define TCL_VERSION "8.4" #define TCL_PATCH_LEVEL "8.4.20" /* * The following definitions set up the proper options for Windows * compilers. We use this method because there is no autoconf equivalent. */ #ifndef __WIN32__ # if defined(_WIN32) || defined(WIN32) || defined(__MINGW32__) || defined(__BORLANDC__) || (defined(__WATCOMC__) && defined(__WINDOWS_386__)) # define __WIN32__ # ifndef WIN32 # define WIN32 # endif # ifndef _WIN32 # define _WIN32 # endif # endif #endif /* * STRICT: See MSDN Article Q83456 */ #ifdef __WIN32__ # ifndef STRICT # define STRICT # endif #endif /* __WIN32__ */ /* * Utility macros: STRINGIFY takes an argument and wraps it in "" (double * quotation marks), JOIN joins two arguments. */ #ifndef STRINGIFY # define STRINGIFY(x) STRINGIFY1(x) # define STRINGIFY1(x) #x #endif #ifndef JOIN # define JOIN(a,b) JOIN1(a,b) # define JOIN1(a,b) a##b #endif /* * A special definition used to allow this header file to be included * from windows resource files so that they can obtain version * information. RC_INVOKED is defined by default by the windows RC tool. * * Resource compilers don't like all the C stuff, like typedefs and * procedure declarations, that occur below, so block them out. */ #ifndef RC_INVOKED /* * Special macro to define mutexes, that doesn't do anything * if we are not using threads. */ #ifdef TCL_THREADS #define TCL_DECLARE_MUTEX(name) static Tcl_Mutex name; #else #define TCL_DECLARE_MUTEX(name) #endif /* * Macros that eliminate the overhead of the thread synchronization * functions when compiling without thread support. */ #ifndef TCL_THREADS #define Tcl_MutexLock(mutexPtr) #define Tcl_MutexUnlock(mutexPtr) #define Tcl_MutexFinalize(mutexPtr) #define Tcl_ConditionNotify(condPtr) #define Tcl_ConditionWait(condPtr, mutexPtr, timePtr) #define Tcl_ConditionFinalize(condPtr) #endif /* TCL_THREADS */ #ifndef BUFSIZ # include #endif /* * Definitions that allow Tcl functions with variable numbers of * arguments to be used with either varargs.h or stdarg.h. TCL_VARARGS * is used in procedure prototypes. TCL_VARARGS_DEF is used to declare * the arguments in a function definiton: it takes the type and name of * the first argument and supplies the appropriate argument declaration * string for use in the function definition. TCL_VARARGS_START * initializes the va_list data structure and returns the first argument. */ #if !defined(NO_STDARG) # include # define TCL_VARARGS(type, name) (type name, ...) # define TCL_VARARGS_DEF(type, name) (type name, ...) # define TCL_VARARGS_START(type, name, list) (va_start(list, name), name) #else # include # define TCL_VARARGS(type, name) () # define TCL_VARARGS_DEF(type, name) (va_alist) # define TCL_VARARGS_START(type, name, list) \ (va_start(list), va_arg(list, type)) #endif /* * Macros used to declare a function to be exported by a DLL. * Used by Windows, maps to no-op declarations on non-Windows systems. * The default build on windows is for a DLL, which causes the DLLIMPORT * and DLLEXPORT macros to be nonempty. To build a static library, the * macro STATIC_BUILD should be defined. */ #if (defined(__WIN32__) && (defined(_MSC_VER) || (__BORLANDC__ >= 0x0550) || defined(__LCC__) || defined(__WATCOMC__) || (defined(__GNUC__) && defined(__declspec)))) # ifdef STATIC_BUILD # define DLLIMPORT # define DLLEXPORT # else # define DLLIMPORT __declspec(dllimport) # define DLLEXPORT __declspec(dllexport) # endif #else # define DLLIMPORT # if defined(__GNUC__) && __GNUC__ > 3 # define DLLEXPORT __attribute__ ((visibility("default"))) # else # define DLLEXPORT # endif #endif /* * These macros are used to control whether functions are being declared for * import or export. If a function is being declared while it is being built * to be included in a shared library, then it should have the DLLEXPORT * storage class. If is being declared for use by a module that is going to * link against the shared library, then it should have the DLLIMPORT storage * class. If the symbol is beind declared for a static build or for use from a * stub library, then the storage class should be empty. * * The convention is that a macro called BUILD_xxxx, where xxxx is the * name of a library we are building, is set on the compile line for sources * that are to be placed in the library. When this macro is set, the * storage class will be set to DLLEXPORT. At the end of the header file, the * storage class will be reset to DLLIMPORT. */ #undef TCL_STORAGE_CLASS #ifdef BUILD_tcl # define TCL_STORAGE_CLASS DLLEXPORT #else # ifdef USE_TCL_STUBS # define TCL_STORAGE_CLASS # else # define TCL_STORAGE_CLASS DLLIMPORT # endif #endif /* * Definitions that allow this header file to be used either with or * without ANSI C features like function prototypes. */ #undef _ANSI_ARGS_ #undef CONST #ifndef INLINE # define INLINE #endif #ifndef NO_CONST # define CONST const #else # define CONST #endif #ifndef NO_PROTOTYPES # define _ANSI_ARGS_(x) x #else # define _ANSI_ARGS_(x) () #endif #ifdef USE_NON_CONST # ifdef USE_COMPAT_CONST # error define at most one of USE_NON_CONST and USE_COMPAT_CONST # endif # define CONST84 # define CONST84_RETURN #else # ifdef USE_COMPAT_CONST # define CONST84 # define CONST84_RETURN CONST # else # define CONST84 CONST # define CONST84_RETURN CONST # endif #endif /* * Make sure EXTERN isn't defined elsewhere */ #ifdef EXTERN # undef EXTERN #endif /* EXTERN */ #ifdef __cplusplus # define EXTERN extern "C" TCL_STORAGE_CLASS #else # define EXTERN extern TCL_STORAGE_CLASS #endif /* * The following code is copied from winnt.h. * If we don't replicate it here, then can't be included * after tcl.h, since tcl.h also defines VOID. * This block is skipped under Cygwin and Mingw. * * */ #if defined(__WIN32__) && !defined(HAVE_WINNT_IGNORE_VOID) #ifndef VOID #define VOID void typedef char CHAR; typedef short SHORT; typedef long LONG; #endif #endif /* __WIN32__ && !HAVE_WINNT_IGNORE_VOID */ /* * Macro to use instead of "void" for arguments that must have * type "void *" in ANSI C; maps them to type "char *" in * non-ANSI systems. */ #ifndef __VXWORKS__ # ifndef NO_VOID # define VOID void # else # define VOID char # endif #endif /* * Miscellaneous declarations. */ #ifndef _CLIENTDATA # ifndef NO_VOID typedef void *ClientData; # else typedef int *ClientData; # endif # define _CLIENTDATA #endif /* * Darwin specific configure overrides (to support fat compiles, where * configure runs only once for multiple architectures): */ #ifdef __APPLE__ # ifdef __LP64__ # undef TCL_WIDE_INT_TYPE # define TCL_WIDE_INT_IS_LONG 1 # else /* !__LP64__ */ # define TCL_WIDE_INT_TYPE long long # undef TCL_WIDE_INT_IS_LONG # endif /* __LP64__ */ # undef HAVE_STRUCT_STAT64 # include #endif /* __APPLE__ */ /* * Define Tcl_WideInt to be a type that is (at least) 64-bits wide, * and define Tcl_WideUInt to be the unsigned variant of that type * (assuming that where we have one, we can have the other.) * * Also defines the following macros: * TCL_WIDE_INT_IS_LONG - if wide ints are really longs (i.e. we're on * a real 64-bit system.) * Tcl_WideAsLong - forgetful converter from wideInt to long. * Tcl_LongAsWide - sign-extending converter from long to wideInt. * Tcl_WideAsDouble - converter from wideInt to double. * Tcl_DoubleAsWide - converter from double to wideInt. * * The following invariant should hold for any long value 'longVal': * longVal == Tcl_WideAsLong(Tcl_LongAsWide(longVal)) * * Note on converting between Tcl_WideInt and strings. This * implementation (in tclObj.c) depends on the functions strtoull() * and sprintf(...,"%" TCL_LL_MODIFIER "d",...). TCL_LL_MODIFIER_SIZE * is the length of the modifier string, which is "ll" on most 32-bit * Unix systems. It has to be split up like this to allow for the more * complex formats sometimes needed (e.g. in the format(n) command.) */ #if !defined(TCL_WIDE_INT_TYPE)&&!defined(TCL_WIDE_INT_IS_LONG) # if defined(__WIN32__) # define TCL_WIDE_INT_TYPE __int64 # ifdef __BORLANDC__ # define TCL_LL_MODIFIER "L" # define TCL_LL_MODIFIER_SIZE 1 # else /* __BORLANDC__ */ # define TCL_LL_MODIFIER "I64" # define TCL_LL_MODIFIER_SIZE 3 # endif /* __BORLANDC__ */ # elif defined(__GNUC__) # define TCL_WIDE_INT_TYPE long long # define TCL_LL_MODIFIER "ll" # define TCL_LL_MODIFIER_SIZE 2 # else /* ! __WIN32__ && ! __GNUC__ */ /* * Don't know what platform it is and configure hasn't discovered what * is going on for us. Try to guess... */ # ifdef NO_LIMITS_H # error please define either TCL_WIDE_INT_TYPE or TCL_WIDE_INT_IS_LONG # else /* !NO_LIMITS_H */ # include # if (INT_MAX < LONG_MAX) # define TCL_WIDE_INT_IS_LONG 1 # else # define TCL_WIDE_INT_TYPE long long # endif # endif /* NO_LIMITS_H */ # endif /* __WIN32__ */ #endif /* !TCL_WIDE_INT_TYPE & !TCL_WIDE_INT_IS_LONG */ #ifdef TCL_WIDE_INT_IS_LONG # undef TCL_WIDE_INT_TYPE # define TCL_WIDE_INT_TYPE long #endif /* TCL_WIDE_INT_IS_LONG */ typedef TCL_WIDE_INT_TYPE Tcl_WideInt; typedef unsigned TCL_WIDE_INT_TYPE Tcl_WideUInt; #ifdef TCL_WIDE_INT_IS_LONG # define Tcl_WideAsLong(val) ((long)(val)) # define Tcl_LongAsWide(val) ((long)(val)) # define Tcl_WideAsDouble(val) ((double)((long)(val))) # define Tcl_DoubleAsWide(val) ((long)((double)(val))) # ifndef TCL_LL_MODIFIER # define TCL_LL_MODIFIER "l" # define TCL_LL_MODIFIER_SIZE 1 # endif /* !TCL_LL_MODIFIER */ #else /* TCL_WIDE_INT_IS_LONG */ /* * The next short section of defines are only done when not running on * Windows or some other strange platform. */ # ifndef TCL_LL_MODIFIER # define TCL_LL_MODIFIER "ll" # define TCL_LL_MODIFIER_SIZE 2 # endif /* !TCL_LL_MODIFIER */ # define Tcl_WideAsLong(val) ((long)((Tcl_WideInt)(val))) # define Tcl_LongAsWide(val) ((Tcl_WideInt)((long)(val))) # define Tcl_WideAsDouble(val) ((double)((Tcl_WideInt)(val))) # define Tcl_DoubleAsWide(val) ((Tcl_WideInt)((double)(val))) #endif /* TCL_WIDE_INT_IS_LONG */ #if defined(__WIN32__) # ifdef __BORLANDC__ typedef struct stati64 Tcl_StatBuf; # elif defined(_WIN64) typedef struct __stat64 Tcl_StatBuf; # elif (defined(_MSC_VER) && (_MSC_VER < 1400)) || defined(_USE_32BIT_TIME_T) typedef struct _stati64 Tcl_StatBuf; # else typedef struct _stat32i64 Tcl_StatBuf; # endif /* _MSC_VER < 1400 */ #elif defined(__CYGWIN__) typedef struct _stat32i64 { dev_t st_dev; unsigned short st_ino; unsigned short st_mode; short st_nlink; short st_uid; short st_gid; /* Here is a 2-byte gap */ dev_t st_rdev; /* Here is a 4-byte gap */ long long st_size; struct {long tv_sec;} st_atim; struct {long tv_sec;} st_mtim; struct {long tv_sec;} st_ctim; /* Here is a 4-byte gap */ } Tcl_StatBuf; #elif defined(HAVE_STRUCT_STAT64) typedef struct stat64 Tcl_StatBuf; #else typedef struct stat Tcl_StatBuf; #endif /* * This flag controls whether binary compatability is maintained with * extensions built against a previous version of Tcl. This is true * by default. */ #ifndef TCL_PRESERVE_BINARY_COMPATABILITY # define TCL_PRESERVE_BINARY_COMPATABILITY 1 #endif /* * Data structures defined opaquely in this module. The definitions below * just provide dummy types. A few fields are made visible in Tcl_Interp * structures, namely those used for returning a string result from * commands. Direct access to the result field is discouraged in Tcl 8.0. * The interpreter result is either an object or a string, and the two * values are kept consistent unless some C code sets interp->result * directly. Programmers should use either the procedure Tcl_GetObjResult() * or Tcl_GetStringResult() to read the interpreter's result. See the * SetResult man page for details. * * Note: any change to the Tcl_Interp definition below must be mirrored * in the "real" definition in tclInt.h. * * Note: Tcl_ObjCmdProc procedures do not directly set result and freeProc. * Instead, they set a Tcl_Obj member in the "real" structure that can be * accessed with Tcl_GetObjResult() and Tcl_SetObjResult(). */ typedef struct Tcl_Interp { char *result; /* If the last command returned a string * result, this points to it. */ void (*freeProc) _ANSI_ARGS_((char *blockPtr)); /* Zero means the string result is * statically allocated. TCL_DYNAMIC means * it was allocated with ckalloc and should * be freed with ckfree. Other values give * the address of procedure to invoke to * free the result. Tcl_Eval must free it * before executing next command. */ int errorLine; /* When TCL_ERROR is returned, this gives * the line number within the command where * the error occurred (1 if first line). */ } Tcl_Interp; typedef struct Tcl_AsyncHandler_ *Tcl_AsyncHandler; typedef struct Tcl_Channel_ *Tcl_Channel; typedef struct Tcl_Command_ *Tcl_Command; typedef struct Tcl_Condition_ *Tcl_Condition; typedef struct Tcl_EncodingState_ *Tcl_EncodingState; typedef struct Tcl_Encoding_ *Tcl_Encoding; typedef struct Tcl_Event Tcl_Event; typedef struct Tcl_Mutex_ *Tcl_Mutex; typedef struct Tcl_Pid_ *Tcl_Pid; typedef struct Tcl_RegExp_ *Tcl_RegExp; typedef struct Tcl_ThreadDataKey_ *Tcl_ThreadDataKey; typedef struct Tcl_ThreadId_ *Tcl_ThreadId; typedef struct Tcl_TimerToken_ *Tcl_TimerToken; typedef struct Tcl_Trace_ *Tcl_Trace; typedef struct Tcl_Var_ *Tcl_Var; typedef struct Tcl_ChannelTypeVersion_ *Tcl_ChannelTypeVersion; typedef struct Tcl_LoadHandle_ *Tcl_LoadHandle; /* * Definition of the interface to procedures implementing threads. * A procedure following this definition is given to each call of * 'Tcl_CreateThread' and will be called as the main fuction of * the new thread created by that call. */ #if defined __WIN32__ typedef unsigned (__stdcall Tcl_ThreadCreateProc) _ANSI_ARGS_((ClientData clientData)); #else typedef void (Tcl_ThreadCreateProc) _ANSI_ARGS_((ClientData clientData)); #endif /* * Threading function return types used for abstracting away platform * differences when writing a Tcl_ThreadCreateProc. See the NewThread * function in generic/tclThreadTest.c for it's usage. */ #ifdef __WIN32__ # define Tcl_ThreadCreateType unsigned __stdcall # define TCL_THREAD_CREATE_RETURN return 0 #else # define Tcl_ThreadCreateType void # define TCL_THREAD_CREATE_RETURN #endif /* * Definition of values for default stacksize and the possible flags to be * given to Tcl_CreateThread. */ #define TCL_THREAD_STACK_DEFAULT (0) /* Use default size for stack */ #define TCL_THREAD_NOFLAGS (0000) /* Standard flags, default behaviour */ #define TCL_THREAD_JOINABLE (0001) /* Mark the thread as joinable */ /* * Flag values passed to Tcl_GetRegExpFromObj. */ #define TCL_REG_BASIC 000000 /* BREs (convenience) */ #define TCL_REG_EXTENDED 000001 /* EREs */ #define TCL_REG_ADVF 000002 /* advanced features in EREs */ #define TCL_REG_ADVANCED 000003 /* AREs (which are also EREs) */ #define TCL_REG_QUOTE 000004 /* no special characters, none */ #define TCL_REG_NOCASE 000010 /* ignore case */ #define TCL_REG_NOSUB 000020 /* don't care about subexpressions */ #define TCL_REG_EXPANDED 000040 /* expanded format, white space & * comments */ #define TCL_REG_NLSTOP 000100 /* \n doesn't match . or [^ ] */ #define TCL_REG_NLANCH 000200 /* ^ matches after \n, $ before */ #define TCL_REG_NEWLINE 000300 /* newlines are line terminators */ #define TCL_REG_CANMATCH 001000 /* report details on partial/limited * matches */ /* * The following flag is experimental and only intended for use by Expect. It * will probably go away in a later release. */ #define TCL_REG_BOSONLY 002000 /* prepend \A to pattern so it only * matches at the beginning of the * string. */ /* * Flags values passed to Tcl_RegExpExecObj. */ #define TCL_REG_NOTBOL 0001 /* Beginning of string does not match ^. */ #define TCL_REG_NOTEOL 0002 /* End of string does not match $. */ /* * Structures filled in by Tcl_RegExpInfo. Note that all offset values are * relative to the start of the match string, not the beginning of the * entire string. */ typedef struct Tcl_RegExpIndices { long start; /* character offset of first character in match */ long end; /* character offset of first character after the * match. */ } Tcl_RegExpIndices; typedef struct Tcl_RegExpInfo { int nsubs; /* number of subexpressions in the * compiled expression */ Tcl_RegExpIndices *matches; /* array of nsubs match offset * pairs */ long extendStart; /* The offset at which a subsequent * match might begin. */ long reserved; /* Reserved for later use. */ } Tcl_RegExpInfo; /* * Picky compilers complain if this typdef doesn't appear before the * struct's reference in tclDecls.h. */ typedef Tcl_StatBuf *Tcl_Stat_; typedef struct stat *Tcl_OldStat_; /* * When a TCL command returns, the interpreter contains a result from the * command. Programmers are strongly encouraged to use one of the * procedures Tcl_GetObjResult() or Tcl_GetStringResult() to read the * interpreter's result. See the SetResult man page for details. Besides * this result, the command procedure returns an integer code, which is * one of the following: * * TCL_OK Command completed normally; the interpreter's * result contains the command's result. * TCL_ERROR The command couldn't be completed successfully; * the interpreter's result describes what went wrong. * TCL_RETURN The command requests that the current procedure * return; the interpreter's result contains the * procedure's return value. * TCL_BREAK The command requests that the innermost loop * be exited; the interpreter's result is meaningless. * TCL_CONTINUE Go on to the next iteration of the current loop; * the interpreter's result is meaningless. */ #define TCL_OK 0 #define TCL_ERROR 1 #define TCL_RETURN 2 #define TCL_BREAK 3 #define TCL_CONTINUE 4 #define TCL_RESULT_SIZE 200 /* * Flags to control what substitutions are performed by Tcl_SubstObj(): */ #define TCL_SUBST_COMMANDS 001 #define TCL_SUBST_VARIABLES 002 #define TCL_SUBST_BACKSLASHES 004 #define TCL_SUBST_ALL 007 /* * Argument descriptors for math function callbacks in expressions: */ typedef enum { TCL_INT, TCL_DOUBLE, TCL_EITHER, TCL_WIDE_INT } Tcl_ValueType; typedef struct Tcl_Value { Tcl_ValueType type; /* Indicates intValue or doubleValue is * valid, or both. */ long intValue; /* Integer value. */ double doubleValue; /* Double-precision floating value. */ Tcl_WideInt wideValue; /* Wide (min. 64-bit) integer value. */ } Tcl_Value; /* * Forward declaration of Tcl_Obj to prevent an error when the forward * reference to Tcl_Obj is encountered in the procedure types declared * below. */ struct Tcl_Obj; /* * Procedure types defined by Tcl: */ typedef int (Tcl_AppInitProc) _ANSI_ARGS_((Tcl_Interp *interp)); typedef int (Tcl_AsyncProc) _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int code)); typedef void (Tcl_ChannelProc) _ANSI_ARGS_((ClientData clientData, int mask)); typedef void (Tcl_CloseProc) _ANSI_ARGS_((ClientData data)); typedef void (Tcl_CmdDeleteProc) _ANSI_ARGS_((ClientData clientData)); typedef int (Tcl_CmdProc) _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int argc, CONST84 char *argv[])); typedef void (Tcl_CmdTraceProc) _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int level, char *command, Tcl_CmdProc *proc, ClientData cmdClientData, int argc, CONST84 char *argv[])); typedef int (Tcl_CmdObjTraceProc) _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int level, CONST char *command, Tcl_Command commandInfo, int objc, struct Tcl_Obj * CONST * objv)); typedef void (Tcl_CmdObjTraceDeleteProc) _ANSI_ARGS_((ClientData clientData)); typedef void (Tcl_DupInternalRepProc) _ANSI_ARGS_((struct Tcl_Obj *srcPtr, struct Tcl_Obj *dupPtr)); typedef int (Tcl_EncodingConvertProc)_ANSI_ARGS_((ClientData clientData, CONST char *src, int srcLen, int flags, Tcl_EncodingState *statePtr, char *dst, int dstLen, int *srcReadPtr, int *dstWrotePtr, int *dstCharsPtr)); typedef void (Tcl_EncodingFreeProc)_ANSI_ARGS_((ClientData clientData)); typedef int (Tcl_EventProc) _ANSI_ARGS_((Tcl_Event *evPtr, int flags)); typedef void (Tcl_EventCheckProc) _ANSI_ARGS_((ClientData clientData, int flags)); typedef int (Tcl_EventDeleteProc) _ANSI_ARGS_((Tcl_Event *evPtr, ClientData clientData)); typedef void (Tcl_EventSetupProc) _ANSI_ARGS_((ClientData clientData, int flags)); typedef void (Tcl_ExitProc) _ANSI_ARGS_((ClientData clientData)); typedef void (Tcl_FileProc) _ANSI_ARGS_((ClientData clientData, int mask)); typedef void (Tcl_FileFreeProc) _ANSI_ARGS_((ClientData clientData)); typedef void (Tcl_FreeInternalRepProc) _ANSI_ARGS_((struct Tcl_Obj *objPtr)); typedef void (Tcl_FreeProc) _ANSI_ARGS_((char *blockPtr)); typedef void (Tcl_IdleProc) _ANSI_ARGS_((ClientData clientData)); typedef void (Tcl_InterpDeleteProc) _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp)); typedef int (Tcl_MathProc) _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, Tcl_Value *args, Tcl_Value *resultPtr)); typedef void (Tcl_NamespaceDeleteProc) _ANSI_ARGS_((ClientData clientData)); typedef int (Tcl_ObjCmdProc) _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, struct Tcl_Obj * CONST * objv)); typedef int (Tcl_PackageInitProc) _ANSI_ARGS_((Tcl_Interp *interp)); typedef void (Tcl_PanicProc) _ANSI_ARGS_(TCL_VARARGS(CONST char *, format)); typedef void (Tcl_TcpAcceptProc) _ANSI_ARGS_((ClientData callbackData, Tcl_Channel chan, char *address, int port)); typedef void (Tcl_TimerProc) _ANSI_ARGS_((ClientData clientData)); typedef int (Tcl_SetFromAnyProc) _ANSI_ARGS_((Tcl_Interp *interp, struct Tcl_Obj *objPtr)); typedef void (Tcl_UpdateStringProc) _ANSI_ARGS_((struct Tcl_Obj *objPtr)); typedef char *(Tcl_VarTraceProc) _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, CONST84 char *part1, CONST84 char *part2, int flags)); typedef void (Tcl_CommandTraceProc) _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, CONST char *oldName, CONST char *newName, int flags)); typedef void (Tcl_CreateFileHandlerProc) _ANSI_ARGS_((int fd, int mask, Tcl_FileProc *proc, ClientData clientData)); typedef void (Tcl_DeleteFileHandlerProc) _ANSI_ARGS_((int fd)); typedef void (Tcl_AlertNotifierProc) _ANSI_ARGS_((ClientData clientData)); typedef void (Tcl_ServiceModeHookProc) _ANSI_ARGS_((int mode)); typedef ClientData (Tcl_InitNotifierProc) _ANSI_ARGS_((VOID)); typedef void (Tcl_FinalizeNotifierProc) _ANSI_ARGS_((ClientData clientData)); typedef void (Tcl_MainLoopProc) _ANSI_ARGS_((void)); /* * The following structure represents a type of object, which is a * particular internal representation for an object plus a set of * procedures that provide standard operations on objects of that type. */ typedef struct Tcl_ObjType { char *name; /* Name of the type, e.g. "int". */ Tcl_FreeInternalRepProc *freeIntRepProc; /* Called to free any storage for the type's * internal rep. NULL if the internal rep * does not need freeing. */ Tcl_DupInternalRepProc *dupIntRepProc; /* Called to create a new object as a copy * of an existing object. */ Tcl_UpdateStringProc *updateStringProc; /* Called to update the string rep from the * type's internal representation. */ Tcl_SetFromAnyProc *setFromAnyProc; /* Called to convert the object's internal * rep to this type. Frees the internal rep * of the old type. Returns TCL_ERROR on * failure. */ } Tcl_ObjType; /* * One of the following structures exists for each object in the Tcl * system. An object stores a value as either a string, some internal * representation, or both. */ typedef struct Tcl_Obj { int refCount; /* When 0 the object will be freed. */ char *bytes; /* This points to the first byte of the * object's string representation. The array * must be followed by a null byte (i.e., at * offset length) but may also contain * embedded null characters. The array's * storage is allocated by ckalloc. NULL * means the string rep is invalid and must * be regenerated from the internal rep. * Clients should use Tcl_GetStringFromObj * or Tcl_GetString to get a pointer to the * byte array as a readonly value. */ int length; /* The number of bytes at *bytes, not * including the terminating null. */ Tcl_ObjType *typePtr; /* Denotes the object's type. Always * corresponds to the type of the object's * internal rep. NULL indicates the object * has no internal rep (has no type). */ union { /* The internal representation: */ long longValue; /* - an long integer value */ double doubleValue; /* - a double-precision floating value */ VOID *otherValuePtr; /* - another, type-specific value */ Tcl_WideInt wideValue; /* - a long long value */ struct { /* - internal rep as two pointers */ VOID *ptr1; VOID *ptr2; } twoPtrValue; } internalRep; } Tcl_Obj; /* * Macros to increment and decrement a Tcl_Obj's reference count, and to * test whether an object is shared (i.e. has reference count > 1). * Note: clients should use Tcl_DecrRefCount() when they are finished using * an object, and should never call TclFreeObj() directly. TclFreeObj() is * only defined and made public in tcl.h to support Tcl_DecrRefCount's macro * definition. */ void Tcl_IncrRefCount _ANSI_ARGS_((Tcl_Obj *objPtr)); void Tcl_DecrRefCount _ANSI_ARGS_((Tcl_Obj *objPtr)); int Tcl_IsShared _ANSI_ARGS_((Tcl_Obj *objPtr)); #ifdef TCL_MEM_DEBUG # define Tcl_IncrRefCount(objPtr) \ Tcl_DbIncrRefCount(objPtr, __FILE__, __LINE__) # define Tcl_DecrRefCount(objPtr) \ Tcl_DbDecrRefCount(objPtr, __FILE__, __LINE__) # define Tcl_IsShared(objPtr) \ Tcl_DbIsShared(objPtr, __FILE__, __LINE__) #else # define Tcl_IncrRefCount(objPtr) \ ++(objPtr)->refCount /* * Use do/while0 idiom for optimum correctness without compiler warnings * http://c2.com/cgi/wiki?TrivialDoWhileLoop */ # define Tcl_DecrRefCount(objPtr) \ do { \ Tcl_Obj *_objPtr = (objPtr); \ if (--(_objPtr)->refCount <= 0) { \ TclFreeObj(_objPtr); \ } \ } while(0) # define Tcl_IsShared(objPtr) \ ((objPtr)->refCount > 1) #endif /* * Macros and definitions that help to debug the use of Tcl objects. * When TCL_MEM_DEBUG is defined, the Tcl_New declarations are * overridden to call debugging versions of the object creation procedures. */ #ifdef TCL_MEM_DEBUG # define Tcl_NewBooleanObj(val) \ Tcl_DbNewBooleanObj(val, __FILE__, __LINE__) # define Tcl_NewByteArrayObj(bytes, len) \ Tcl_DbNewByteArrayObj(bytes, len, __FILE__, __LINE__) # define Tcl_NewDoubleObj(val) \ Tcl_DbNewDoubleObj(val, __FILE__, __LINE__) # define Tcl_NewIntObj(val) \ Tcl_DbNewLongObj(val, __FILE__, __LINE__) # define Tcl_NewListObj(objc, objv) \ Tcl_DbNewListObj(objc, objv, __FILE__, __LINE__) # define Tcl_NewLongObj(val) \ Tcl_DbNewLongObj(val, __FILE__, __LINE__) # define Tcl_NewObj() \ Tcl_DbNewObj(__FILE__, __LINE__) # define Tcl_NewStringObj(bytes, len) \ Tcl_DbNewStringObj(bytes, len, __FILE__, __LINE__) # define Tcl_NewWideIntObj(val) \ Tcl_DbNewWideIntObj(val, __FILE__, __LINE__) #endif /* TCL_MEM_DEBUG */ /* * The following structure contains the state needed by * Tcl_SaveResult. No-one outside of Tcl should access any of these * fields. This structure is typically allocated on the stack. */ typedef struct Tcl_SavedResult { char *result; Tcl_FreeProc *freeProc; Tcl_Obj *objResultPtr; char *appendResult; int appendAvl; int appendUsed; char resultSpace[TCL_RESULT_SIZE+1]; } Tcl_SavedResult; /* * The following definitions support Tcl's namespace facility. * Note: the first five fields must match exactly the fields in a * Namespace structure (see tclInt.h). */ typedef struct Tcl_Namespace { char *name; /* The namespace's name within its parent * namespace. This contains no ::'s. The * name of the global namespace is "" * although "::" is an synonym. */ char *fullName; /* The namespace's fully qualified name. * This starts with ::. */ ClientData clientData; /* Arbitrary value associated with this * namespace. */ Tcl_NamespaceDeleteProc* deleteProc; /* Procedure invoked when deleting the * namespace to, e.g., free clientData. */ struct Tcl_Namespace* parentPtr; /* Points to the namespace that contains * this one. NULL if this is the global * namespace. */ } Tcl_Namespace; /* * The following structure represents a call frame, or activation record. * A call frame defines a naming context for a procedure call: its local * scope (for local variables) and its namespace scope (used for non-local * variables; often the global :: namespace). A call frame can also define * the naming context for a namespace eval or namespace inscope command: * the namespace in which the command's code should execute. The * Tcl_CallFrame structures exist only while procedures or namespace * eval/inscope's are being executed, and provide a Tcl call stack. * * A call frame is initialized and pushed using Tcl_PushCallFrame and * popped using Tcl_PopCallFrame. Storage for a Tcl_CallFrame must be * provided by the Tcl_PushCallFrame caller, and callers typically allocate * them on the C call stack for efficiency. For this reason, Tcl_CallFrame * is defined as a structure and not as an opaque token. However, most * Tcl_CallFrame fields are hidden since applications should not access * them directly; others are declared as "dummyX". * * WARNING!! The structure definition must be kept consistent with the * CallFrame structure in tclInt.h. If you change one, change the other. */ typedef struct Tcl_CallFrame { Tcl_Namespace *nsPtr; int dummy1; int dummy2; VOID *dummy3; VOID *dummy4; VOID *dummy5; int dummy6; VOID *dummy7; VOID *dummy8; int dummy9; VOID *dummy10; VOID *dummy11; VOID *dummy12; VOID *dummy13; } Tcl_CallFrame; /* * Information about commands that is returned by Tcl_GetCommandInfo and * passed to Tcl_SetCommandInfo. objProc is an objc/objv object-based * command procedure while proc is a traditional Tcl argc/argv * string-based procedure. Tcl_CreateObjCommand and Tcl_CreateCommand * ensure that both objProc and proc are non-NULL and can be called to * execute the command. However, it may be faster to call one instead of * the other. The member isNativeObjectProc is set to 1 if an * object-based procedure was registered by Tcl_CreateObjCommand, and to * 0 if a string-based procedure was registered by Tcl_CreateCommand. * The other procedure is typically set to a compatibility wrapper that * does string-to-object or object-to-string argument conversions then * calls the other procedure. */ typedef struct Tcl_CmdInfo { int isNativeObjectProc; /* 1 if objProc was registered by a call to * Tcl_CreateObjCommand; 0 otherwise. * Tcl_SetCmdInfo does not modify this * field. */ Tcl_ObjCmdProc *objProc; /* Command's object-based procedure. */ ClientData objClientData; /* ClientData for object proc. */ Tcl_CmdProc *proc; /* Command's string-based procedure. */ ClientData clientData; /* ClientData for string proc. */ Tcl_CmdDeleteProc *deleteProc; /* Procedure to call when command is * deleted. */ ClientData deleteData; /* Value to pass to deleteProc (usually * the same as clientData). */ Tcl_Namespace *namespacePtr; /* Points to the namespace that contains * this command. Note that Tcl_SetCmdInfo * will not change a command's namespace; * use Tcl_RenameCommand to do that. */ } Tcl_CmdInfo; /* * The structure defined below is used to hold dynamic strings. The only * field that clients should use is the string field, accessible via the * macro Tcl_DStringValue. */ #define TCL_DSTRING_STATIC_SIZE 200 typedef struct Tcl_DString { char *string; /* Points to beginning of string: either * staticSpace below or a malloced array. */ int length; /* Number of non-NULL characters in the * string. */ int spaceAvl; /* Total number of bytes available for the * string and its terminating NULL char. */ char staticSpace[TCL_DSTRING_STATIC_SIZE]; /* Space to use in common case where string * is small. */ } Tcl_DString; #define Tcl_DStringLength(dsPtr) ((dsPtr)->length) #define Tcl_DStringValue(dsPtr) ((dsPtr)->string) #define Tcl_DStringTrunc Tcl_DStringSetLength /* * Definitions for the maximum number of digits of precision that may * be specified in the "tcl_precision" variable, and the number of * bytes of buffer space required by Tcl_PrintDouble. */ #define TCL_MAX_PREC 17 #define TCL_DOUBLE_SPACE (TCL_MAX_PREC+10) /* * Definition for a number of bytes of buffer space sufficient to hold the * string representation of an integer in base 10 (assuming the existence * of 64-bit integers). */ #define TCL_INTEGER_SPACE 24 /* * Flag that may be passed to Tcl_ConvertElement to force it not to * output braces (careful! if you change this flag be sure to change * the definitions at the front of tclUtil.c). */ #define TCL_DONT_USE_BRACES 1 /* * Flag that may be passed to Tcl_GetIndexFromObj to force it to disallow * abbreviated strings. */ #define TCL_EXACT 1 /* * Flag values passed to Tcl_RecordAndEval and/or Tcl_EvalObj. * WARNING: these bit choices must not conflict with the bit choices * for evalFlag bits in tclInt.h!! */ #define TCL_NO_EVAL 0x10000 #define TCL_EVAL_GLOBAL 0x20000 #define TCL_EVAL_DIRECT 0x40000 #define TCL_EVAL_INVOKE 0x80000 /* * Special freeProc values that may be passed to Tcl_SetResult (see * the man page for details): */ #define TCL_VOLATILE ((Tcl_FreeProc *) 1) #define TCL_STATIC ((Tcl_FreeProc *) 0) #define TCL_DYNAMIC ((Tcl_FreeProc *) 3) /* * Flag values passed to variable-related procedures. */ #define TCL_GLOBAL_ONLY 1 #define TCL_NAMESPACE_ONLY 2 #define TCL_APPEND_VALUE 4 #define TCL_LIST_ELEMENT 8 #define TCL_TRACE_READS 0x10 #define TCL_TRACE_WRITES 0x20 #define TCL_TRACE_UNSETS 0x40 #define TCL_TRACE_DESTROYED 0x80 #define TCL_INTERP_DESTROYED 0x100 #define TCL_LEAVE_ERR_MSG 0x200 #define TCL_TRACE_ARRAY 0x800 #ifndef TCL_REMOVE_OBSOLETE_TRACES /* Required to support old variable/vdelete/vinfo traces */ #define TCL_TRACE_OLD_STYLE 0x1000 #endif /* Indicate the semantics of the result of a trace */ #define TCL_TRACE_RESULT_DYNAMIC 0x8000 #define TCL_TRACE_RESULT_OBJECT 0x10000 /* * Flag values passed to command-related procedures. */ #define TCL_TRACE_RENAME 0x2000 #define TCL_TRACE_DELETE 0x4000 #define TCL_ALLOW_INLINE_COMPILATION 0x20000 /* * Flag values passed to Tcl_CreateObjTrace, and used internally * by command execution traces. Slots 4,8,16 and 32 are * used internally by execution traces (see tclCmdMZ.c) */ #define TCL_TRACE_ENTER_EXEC 1 #define TCL_TRACE_LEAVE_EXEC 2 /* * The TCL_PARSE_PART1 flag is deprecated and has no effect. * The part1 is now always parsed whenever the part2 is NULL. * (This is to avoid a common error when converting code to * use the new object based APIs and forgetting to give the * flag) */ #ifndef TCL_NO_DEPRECATED # define TCL_PARSE_PART1 0x400 #endif /* * Types for linked variables: */ #define TCL_LINK_INT 1 #define TCL_LINK_DOUBLE 2 #define TCL_LINK_BOOLEAN 3 #define TCL_LINK_STRING 4 #define TCL_LINK_WIDE_INT 5 #define TCL_LINK_READ_ONLY 0x80 /* * Forward declarations of Tcl_HashTable and related types. */ typedef struct Tcl_HashKeyType Tcl_HashKeyType; typedef struct Tcl_HashTable Tcl_HashTable; typedef struct Tcl_HashEntry Tcl_HashEntry; typedef unsigned int (Tcl_HashKeyProc) _ANSI_ARGS_((Tcl_HashTable *tablePtr, VOID *keyPtr)); typedef int (Tcl_CompareHashKeysProc) _ANSI_ARGS_((VOID *keyPtr, Tcl_HashEntry *hPtr)); typedef Tcl_HashEntry *(Tcl_AllocHashEntryProc) _ANSI_ARGS_(( Tcl_HashTable *tablePtr, VOID *keyPtr)); typedef void (Tcl_FreeHashEntryProc) _ANSI_ARGS_((Tcl_HashEntry *hPtr)); /* * This flag controls whether the hash table stores the hash of a key, or * recalculates it. There should be no reason for turning this flag off * as it is completely binary and source compatible unless you directly * access the bucketPtr member of the Tcl_HashTableEntry structure. This * member has been removed and the space used to store the hash value. */ #ifndef TCL_HASH_KEY_STORE_HASH # define TCL_HASH_KEY_STORE_HASH 1 #endif /* * Structure definition for an entry in a hash table. No-one outside * Tcl should access any of these fields directly; use the macros * defined below. */ struct Tcl_HashEntry { Tcl_HashEntry *nextPtr; /* Pointer to next entry in this * hash bucket, or NULL for end of * chain. */ Tcl_HashTable *tablePtr; /* Pointer to table containing entry. */ #if TCL_HASH_KEY_STORE_HASH # if TCL_PRESERVE_BINARY_COMPATABILITY VOID *hash; /* Hash value, stored as pointer to * ensure that the offsets of the * fields in this structure are not * changed. */ # else unsigned int hash; /* Hash value. */ # endif #else Tcl_HashEntry **bucketPtr; /* Pointer to bucket that points to * first entry in this entry's chain: * used for deleting the entry. */ #endif ClientData clientData; /* Application stores something here * with Tcl_SetHashValue. */ union { /* Key has one of these forms: */ char *oneWordValue; /* One-word value for key. */ Tcl_Obj *objPtr; /* Tcl_Obj * key value. */ int words[1]; /* Multiple integer words for key. * The actual size will be as large * as necessary for this table's * keys. */ char string[4]; /* String for key. The actual size * will be as large as needed to hold * the key. */ } key; /* MUST BE LAST FIELD IN RECORD!! */ }; /* * Flags used in Tcl_HashKeyType. * * TCL_HASH_KEY_RANDOMIZE_HASH: * There are some things, pointers for example * which don't hash well because they do not use * the lower bits. If this flag is set then the * hash table will attempt to rectify this by * randomising the bits and then using the upper * N bits as the index into the table. */ #define TCL_HASH_KEY_RANDOMIZE_HASH 0x1 /* * Structure definition for the methods associated with a hash table * key type. */ #define TCL_HASH_KEY_TYPE_VERSION 1 struct Tcl_HashKeyType { int version; /* Version of the table. If this structure is * extended in future then the version can be * used to distinguish between different * structures. */ int flags; /* Flags, see above for details. */ /* Calculates a hash value for the key. If this is NULL then the pointer * itself is used as a hash value. */ Tcl_HashKeyProc *hashKeyProc; /* Compares two keys and returns zero if they do not match, and non-zero * if they do. If this is NULL then the pointers are compared. */ Tcl_CompareHashKeysProc *compareKeysProc; /* Called to allocate memory for a new entry, i.e. if the key is a * string then this could allocate a single block which contains enough * space for both the entry and the string. Only the key field of the * allocated Tcl_HashEntry structure needs to be filled in. If something * else needs to be done to the key, i.e. incrementing a reference count * then that should be done by this function. If this is NULL then Tcl_Alloc * is used to allocate enough space for a Tcl_HashEntry and the key pointer * is assigned to key.oneWordValue. */ Tcl_AllocHashEntryProc *allocEntryProc; /* Called to free memory associated with an entry. If something else needs * to be done to the key, i.e. decrementing a reference count then that * should be done by this function. If this is NULL then Tcl_Free is used * to free the Tcl_HashEntry. */ Tcl_FreeHashEntryProc *freeEntryProc; }; /* * Structure definition for a hash table. Must be in tcl.h so clients * can allocate space for these structures, but clients should never * access any fields in this structure. */ #define TCL_SMALL_HASH_TABLE 4 struct Tcl_HashTable { Tcl_HashEntry **buckets; /* Pointer to bucket array. Each * element points to first entry in * bucket's hash chain, or NULL. */ Tcl_HashEntry *staticBuckets[TCL_SMALL_HASH_TABLE]; /* Bucket array used for small tables * (to avoid mallocs and frees). */ int numBuckets; /* Total number of buckets allocated * at **bucketPtr. */ int numEntries; /* Total number of entries present * in table. */ int rebuildSize; /* Enlarge table when numEntries gets * to be this large. */ int downShift; /* Shift count used in hashing * function. Designed to use high- * order bits of randomized keys. */ int mask; /* Mask value used in hashing * function. */ int keyType; /* Type of keys used in this table. * It's either TCL_CUSTOM_KEYS, * TCL_STRING_KEYS, TCL_ONE_WORD_KEYS, * or an integer giving the number of * ints that is the size of the key. */ #if TCL_PRESERVE_BINARY_COMPATABILITY Tcl_HashEntry *(*findProc) _ANSI_ARGS_((Tcl_HashTable *tablePtr, CONST char *key)); Tcl_HashEntry *(*createProc) _ANSI_ARGS_((Tcl_HashTable *tablePtr, CONST char *key, int *newPtr)); #endif Tcl_HashKeyType *typePtr; /* Type of the keys used in the * Tcl_HashTable. */ }; /* * Structure definition for information used to keep track of searches * through hash tables: */ typedef struct Tcl_HashSearch { Tcl_HashTable *tablePtr; /* Table being searched. */ int nextIndex; /* Index of next bucket to be * enumerated after present one. */ Tcl_HashEntry *nextEntryPtr; /* Next entry to be enumerated in the * the current bucket. */ } Tcl_HashSearch; /* * Acceptable key types for hash tables: * * TCL_STRING_KEYS: The keys are strings, they are copied into * the entry. * TCL_ONE_WORD_KEYS: The keys are pointers, the pointer is stored * in the entry. * TCL_CUSTOM_TYPE_KEYS: The keys are arbitrary types which are copied * into the entry. * TCL_CUSTOM_PTR_KEYS: The keys are pointers to arbitrary types, the * pointer is stored in the entry. * * While maintaining binary compatability the above have to be distinct * values as they are used to differentiate between old versions of the * hash table which don't have a typePtr and new ones which do. Once binary * compatability is discarded in favour of making more wide spread changes * TCL_STRING_KEYS can be the same as TCL_CUSTOM_TYPE_KEYS, and * TCL_ONE_WORD_KEYS can be the same as TCL_CUSTOM_PTR_KEYS because they * simply determine how the key is accessed from the entry and not the * behaviour. */ #define TCL_STRING_KEYS 0 #define TCL_ONE_WORD_KEYS 1 #if TCL_PRESERVE_BINARY_COMPATABILITY # define TCL_CUSTOM_TYPE_KEYS -2 # define TCL_CUSTOM_PTR_KEYS -1 #else # define TCL_CUSTOM_TYPE_KEYS TCL_STRING_KEYS # define TCL_CUSTOM_PTR_KEYS TCL_ONE_WORD_KEYS #endif /* * Macros for clients to use to access fields of hash entries: */ #define Tcl_GetHashValue(h) ((h)->clientData) #define Tcl_SetHashValue(h, value) ((h)->clientData = (ClientData) (value)) #if TCL_PRESERVE_BINARY_COMPATABILITY # define Tcl_GetHashKey(tablePtr, h) \ ((char *) (((tablePtr)->keyType == TCL_ONE_WORD_KEYS || \ (tablePtr)->keyType == TCL_CUSTOM_PTR_KEYS) \ ? (h)->key.oneWordValue \ : (h)->key.string)) #else # define Tcl_GetHashKey(tablePtr, h) \ ((char *) (((tablePtr)->keyType == TCL_ONE_WORD_KEYS) \ ? (h)->key.oneWordValue \ : (h)->key.string)) #endif /* * Macros to use for clients to use to invoke find and create procedures * for hash tables: */ #if TCL_PRESERVE_BINARY_COMPATABILITY # define Tcl_FindHashEntry(tablePtr, key) \ (*((tablePtr)->findProc))(tablePtr, key) # define Tcl_CreateHashEntry(tablePtr, key, newPtr) \ (*((tablePtr)->createProc))(tablePtr, key, newPtr) #else /* !TCL_PRESERVE_BINARY_COMPATABILITY */ /* * Macro to use new extended version of Tcl_InitHashTable. */ # define Tcl_InitHashTable(tablePtr, keyType) \ Tcl_InitHashTableEx(tablePtr, keyType, NULL) #endif /* TCL_PRESERVE_BINARY_COMPATABILITY */ /* * Flag values to pass to Tcl_DoOneEvent to disable searches * for some kinds of events: */ #define TCL_DONT_WAIT (1<<1) #define TCL_WINDOW_EVENTS (1<<2) #define TCL_FILE_EVENTS (1<<3) #define TCL_TIMER_EVENTS (1<<4) #define TCL_IDLE_EVENTS (1<<5) /* WAS 0x10 ???? */ #define TCL_ALL_EVENTS (~TCL_DONT_WAIT) /* * The following structure defines a generic event for the Tcl event * system. These are the things that are queued in calls to Tcl_QueueEvent * and serviced later by Tcl_DoOneEvent. There can be many different * kinds of events with different fields, corresponding to window events, * timer events, etc. The structure for a particular event consists of * a Tcl_Event header followed by additional information specific to that * event. */ struct Tcl_Event { Tcl_EventProc *proc; /* Procedure to call to service this event. */ struct Tcl_Event *nextPtr; /* Next in list of pending events, or NULL. */ }; /* * Positions to pass to Tcl_QueueEvent: */ typedef enum { TCL_QUEUE_TAIL, TCL_QUEUE_HEAD, TCL_QUEUE_MARK } Tcl_QueuePosition; /* * Values to pass to Tcl_SetServiceMode to specify the behavior of notifier * event routines. */ #define TCL_SERVICE_NONE 0 #define TCL_SERVICE_ALL 1 /* * The following structure keeps is used to hold a time value, either as * an absolute time (the number of seconds from the epoch) or as an * elapsed time. On Unix systems the epoch is Midnight Jan 1, 1970 GMT. */ typedef struct Tcl_Time { long sec; /* Seconds. */ long usec; /* Microseconds. */ } Tcl_Time; typedef void (Tcl_SetTimerProc) _ANSI_ARGS_((Tcl_Time *timePtr)); typedef int (Tcl_WaitForEventProc) _ANSI_ARGS_((Tcl_Time *timePtr)); /* * Bits to pass to Tcl_CreateFileHandler and Tcl_CreateChannelHandler * to indicate what sorts of events are of interest: */ #define TCL_READABLE (1<<1) #define TCL_WRITABLE (1<<2) #define TCL_EXCEPTION (1<<3) /* * Flag values to pass to Tcl_OpenCommandChannel to indicate the * disposition of the stdio handles. TCL_STDIN, TCL_STDOUT, TCL_STDERR, * are also used in Tcl_GetStdChannel. */ #define TCL_STDIN (1<<1) #define TCL_STDOUT (1<<2) #define TCL_STDERR (1<<3) #define TCL_ENFORCE_MODE (1<<4) /* * Bits passed to Tcl_DriverClose2Proc to indicate which side of a channel * should be closed. */ #define TCL_CLOSE_READ (1<<1) #define TCL_CLOSE_WRITE (1<<2) /* * Value to use as the closeProc for a channel that supports the * close2Proc interface. */ #define TCL_CLOSE2PROC ((Tcl_DriverCloseProc *)1) /* * Channel version tag. This was introduced in 8.3.2/8.4. */ #define TCL_CHANNEL_VERSION_1 ((Tcl_ChannelTypeVersion) 0x1) #define TCL_CHANNEL_VERSION_2 ((Tcl_ChannelTypeVersion) 0x2) #define TCL_CHANNEL_VERSION_3 ((Tcl_ChannelTypeVersion) 0x3) #define TCL_CHANNEL_VERSION_4 ((Tcl_ChannelTypeVersion) 0x4) /* * TIP #218: Channel Actions, Ids for Tcl_DriverThreadActionProc */ #define TCL_CHANNEL_THREAD_INSERT (0) #define TCL_CHANNEL_THREAD_REMOVE (1) /* * Typedefs for the various operations in a channel type: */ typedef int (Tcl_DriverBlockModeProc) _ANSI_ARGS_(( ClientData instanceData, int mode)); typedef int (Tcl_DriverCloseProc) _ANSI_ARGS_((ClientData instanceData, Tcl_Interp *interp)); typedef int (Tcl_DriverClose2Proc) _ANSI_ARGS_((ClientData instanceData, Tcl_Interp *interp, int flags)); typedef int (Tcl_DriverInputProc) _ANSI_ARGS_((ClientData instanceData, char *buf, int toRead, int *errorCodePtr)); typedef int (Tcl_DriverOutputProc) _ANSI_ARGS_((ClientData instanceData, CONST84 char *buf, int toWrite, int *errorCodePtr)); typedef int (Tcl_DriverSeekProc) _ANSI_ARGS_((ClientData instanceData, long offset, int mode, int *errorCodePtr)); typedef int (Tcl_DriverSetOptionProc) _ANSI_ARGS_(( ClientData instanceData, Tcl_Interp *interp, CONST char *optionName, CONST char *value)); typedef int (Tcl_DriverGetOptionProc) _ANSI_ARGS_(( ClientData instanceData, Tcl_Interp *interp, CONST84 char *optionName, Tcl_DString *dsPtr)); typedef void (Tcl_DriverWatchProc) _ANSI_ARGS_(( ClientData instanceData, int mask)); typedef int (Tcl_DriverGetHandleProc) _ANSI_ARGS_(( ClientData instanceData, int direction, ClientData *handlePtr)); typedef int (Tcl_DriverFlushProc) _ANSI_ARGS_(( ClientData instanceData)); typedef int (Tcl_DriverHandlerProc) _ANSI_ARGS_(( ClientData instanceData, int interestMask)); typedef Tcl_WideInt (Tcl_DriverWideSeekProc) _ANSI_ARGS_(( ClientData instanceData, Tcl_WideInt offset, int mode, int *errorCodePtr)); /* TIP #218, Channel Thread Actions */ typedef void (Tcl_DriverThreadActionProc) _ANSI_ARGS_ (( ClientData instanceData, int action)); /* * The following declarations either map ckalloc and ckfree to * malloc and free, or they map them to procedures with all sorts * of debugging hooks defined in tclCkalloc.c. */ #ifdef TCL_MEM_DEBUG # define ckalloc(x) Tcl_DbCkalloc(x, __FILE__, __LINE__) # define ckfree(x) Tcl_DbCkfree(x, __FILE__, __LINE__) # define ckrealloc(x,y) Tcl_DbCkrealloc((x), (y),__FILE__, __LINE__) # define attemptckalloc(x) Tcl_AttemptDbCkalloc(x, __FILE__, __LINE__) # define attemptckrealloc(x,y) Tcl_AttemptDbCkrealloc((x), (y), __FILE__, __LINE__) #else /* !TCL_MEM_DEBUG */ /* * If we are not using the debugging allocator, we should call the * Tcl_Alloc, et al. routines in order to guarantee that every module * is using the same memory allocator both inside and outside of the * Tcl library. */ # define ckalloc(x) Tcl_Alloc(x) # define ckfree(x) Tcl_Free(x) # define ckrealloc(x,y) Tcl_Realloc(x,y) # define attemptckalloc(x) Tcl_AttemptAlloc(x) # define attemptckrealloc(x,y) Tcl_AttemptRealloc(x,y) # define Tcl_InitMemory(x) # define Tcl_DumpActiveMemory(x) # define Tcl_ValidateAllMemory(x,y) #endif /* !TCL_MEM_DEBUG */ /* * struct Tcl_ChannelType: * * One such structure exists for each type (kind) of channel. * It collects together in one place all the functions that are * part of the specific channel type. * * It is recommend that the Tcl_Channel* functions are used to access * elements of this structure, instead of direct accessing. */ typedef struct Tcl_ChannelType { char *typeName; /* The name of the channel type in Tcl * commands. This storage is owned by * channel type. */ Tcl_ChannelTypeVersion version; /* Version of the channel type. */ Tcl_DriverCloseProc *closeProc; /* Procedure to call to close the * channel, or TCL_CLOSE2PROC if the * close2Proc should be used * instead. */ Tcl_DriverInputProc *inputProc; /* Procedure to call for input * on channel. */ Tcl_DriverOutputProc *outputProc; /* Procedure to call for output * on channel. */ Tcl_DriverSeekProc *seekProc; /* Procedure to call to seek * on the channel. May be NULL. */ Tcl_DriverSetOptionProc *setOptionProc; /* Set an option on a channel. */ Tcl_DriverGetOptionProc *getOptionProc; /* Get an option from a channel. */ Tcl_DriverWatchProc *watchProc; /* Set up the notifier to watch * for events on this channel. */ Tcl_DriverGetHandleProc *getHandleProc; /* Get an OS handle from the channel * or NULL if not supported. */ Tcl_DriverClose2Proc *close2Proc; /* Procedure to call to close the * channel if the device supports * closing the read & write sides * independently. */ Tcl_DriverBlockModeProc *blockModeProc; /* Set blocking mode for the * raw channel. May be NULL. */ /* * Only valid in TCL_CHANNEL_VERSION_2 channels or later */ Tcl_DriverFlushProc *flushProc; /* Procedure to call to flush a * channel. May be NULL. */ Tcl_DriverHandlerProc *handlerProc; /* Procedure to call to handle a * channel event. This will be passed * up the stacked channel chain. */ /* * Only valid in TCL_CHANNEL_VERSION_3 channels or later */ Tcl_DriverWideSeekProc *wideSeekProc; /* Procedure to call to seek * on the channel which can * handle 64-bit offsets. May be * NULL, and must be NULL if * seekProc is NULL. */ /* * Only valid in TCL_CHANNEL_VERSION_4 channels or later * TIP #218, Channel Thread Actions */ Tcl_DriverThreadActionProc *threadActionProc; /* Procedure to call to notify * the driver of thread specific * activity for a channel. * May be NULL. */ } Tcl_ChannelType; /* * The following flags determine whether the blockModeProc above should * set the channel into blocking or nonblocking mode. They are passed * as arguments to the blockModeProc procedure in the above structure. */ #define TCL_MODE_BLOCKING 0 /* Put channel into blocking mode. */ #define TCL_MODE_NONBLOCKING 1 /* Put channel into nonblocking * mode. */ /* * Enum for different types of file paths. */ typedef enum Tcl_PathType { TCL_PATH_ABSOLUTE, TCL_PATH_RELATIVE, TCL_PATH_VOLUME_RELATIVE } Tcl_PathType; /* * The following structure is used to pass glob type data amongst * the various glob routines and Tcl_FSMatchInDirectory. */ typedef struct Tcl_GlobTypeData { /* Corresponds to bcdpfls as in 'find -t' */ int type; /* Corresponds to file permissions */ int perm; /* Acceptable mac type */ Tcl_Obj* macType; /* Acceptable mac creator */ Tcl_Obj* macCreator; } Tcl_GlobTypeData; /* * type and permission definitions for glob command */ #define TCL_GLOB_TYPE_BLOCK (1<<0) #define TCL_GLOB_TYPE_CHAR (1<<1) #define TCL_GLOB_TYPE_DIR (1<<2) #define TCL_GLOB_TYPE_PIPE (1<<3) #define TCL_GLOB_TYPE_FILE (1<<4) #define TCL_GLOB_TYPE_LINK (1<<5) #define TCL_GLOB_TYPE_SOCK (1<<6) #define TCL_GLOB_TYPE_MOUNT (1<<7) #define TCL_GLOB_PERM_RONLY (1<<0) #define TCL_GLOB_PERM_HIDDEN (1<<1) #define TCL_GLOB_PERM_R (1<<2) #define TCL_GLOB_PERM_W (1<<3) #define TCL_GLOB_PERM_X (1<<4) /* * Typedefs for the various filesystem operations: */ typedef int (Tcl_FSStatProc) _ANSI_ARGS_((Tcl_Obj *pathPtr, Tcl_StatBuf *buf)); typedef int (Tcl_FSAccessProc) _ANSI_ARGS_((Tcl_Obj *pathPtr, int mode)); typedef Tcl_Channel (Tcl_FSOpenFileChannelProc) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *pathPtr, int mode, int permissions)); typedef int (Tcl_FSMatchInDirectoryProc) _ANSI_ARGS_((Tcl_Interp* interp, Tcl_Obj *result, Tcl_Obj *pathPtr, CONST char *pattern, Tcl_GlobTypeData * types)); typedef Tcl_Obj* (Tcl_FSGetCwdProc) _ANSI_ARGS_((Tcl_Interp *interp)); typedef int (Tcl_FSChdirProc) _ANSI_ARGS_((Tcl_Obj *pathPtr)); typedef int (Tcl_FSLstatProc) _ANSI_ARGS_((Tcl_Obj *pathPtr, Tcl_StatBuf *buf)); typedef int (Tcl_FSCreateDirectoryProc) _ANSI_ARGS_((Tcl_Obj *pathPtr)); typedef int (Tcl_FSDeleteFileProc) _ANSI_ARGS_((Tcl_Obj *pathPtr)); typedef int (Tcl_FSCopyDirectoryProc) _ANSI_ARGS_((Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr, Tcl_Obj **errorPtr)); typedef int (Tcl_FSCopyFileProc) _ANSI_ARGS_((Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr)); typedef int (Tcl_FSRemoveDirectoryProc) _ANSI_ARGS_((Tcl_Obj *pathPtr, int recursive, Tcl_Obj **errorPtr)); typedef int (Tcl_FSRenameFileProc) _ANSI_ARGS_((Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr)); typedef void (Tcl_FSUnloadFileProc) _ANSI_ARGS_((Tcl_LoadHandle loadHandle)); typedef Tcl_Obj* (Tcl_FSListVolumesProc) _ANSI_ARGS_((void)); /* We have to declare the utime structure here. */ struct utimbuf; typedef int (Tcl_FSUtimeProc) _ANSI_ARGS_((Tcl_Obj *pathPtr, struct utimbuf *tval)); typedef int (Tcl_FSNormalizePathProc) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *pathPtr, int nextCheckpoint)); typedef int (Tcl_FSFileAttrsGetProc) _ANSI_ARGS_((Tcl_Interp *interp, int index, Tcl_Obj *pathPtr, Tcl_Obj **objPtrRef)); typedef CONST char** (Tcl_FSFileAttrStringsProc) _ANSI_ARGS_((Tcl_Obj *pathPtr, Tcl_Obj** objPtrRef)); typedef int (Tcl_FSFileAttrsSetProc) _ANSI_ARGS_((Tcl_Interp *interp, int index, Tcl_Obj *pathPtr, Tcl_Obj *objPtr)); typedef Tcl_Obj* (Tcl_FSLinkProc) _ANSI_ARGS_((Tcl_Obj *pathPtr, Tcl_Obj *toPtr, int linkType)); typedef int (Tcl_FSLoadFileProc) _ANSI_ARGS_((Tcl_Interp * interp, Tcl_Obj *pathPtr, Tcl_LoadHandle *handlePtr, Tcl_FSUnloadFileProc **unloadProcPtr)); typedef int (Tcl_FSPathInFilesystemProc) _ANSI_ARGS_((Tcl_Obj *pathPtr, ClientData *clientDataPtr)); typedef Tcl_Obj* (Tcl_FSFilesystemPathTypeProc) _ANSI_ARGS_((Tcl_Obj *pathPtr)); typedef Tcl_Obj* (Tcl_FSFilesystemSeparatorProc) _ANSI_ARGS_((Tcl_Obj *pathPtr)); typedef void (Tcl_FSFreeInternalRepProc) _ANSI_ARGS_((ClientData clientData)); typedef ClientData (Tcl_FSDupInternalRepProc) _ANSI_ARGS_((ClientData clientData)); typedef Tcl_Obj* (Tcl_FSInternalToNormalizedProc) _ANSI_ARGS_((ClientData clientData)); typedef ClientData (Tcl_FSCreateInternalRepProc) _ANSI_ARGS_((Tcl_Obj *pathPtr)); typedef struct Tcl_FSVersion_ *Tcl_FSVersion; /* *---------------------------------------------------------------- * Data structures related to hooking into the filesystem *---------------------------------------------------------------- */ /* * Filesystem version tag. This was introduced in 8.4. */ #define TCL_FILESYSTEM_VERSION_1 ((Tcl_FSVersion) 0x1) /* * struct Tcl_Filesystem: * * One such structure exists for each type (kind) of filesystem. * It collects together in one place all the functions that are * part of the specific filesystem. Tcl always accesses the * filesystem through one of these structures. * * Not all entries need be non-NULL; any which are NULL are simply * ignored. However, a complete filesystem should provide all of * these functions. The explanations in the structure show * the importance of each function. */ typedef struct Tcl_Filesystem { CONST char *typeName; /* The name of the filesystem. */ int structureLength; /* Length of this structure, so future * binary compatibility can be assured. */ Tcl_FSVersion version; /* Version of the filesystem type. */ Tcl_FSPathInFilesystemProc *pathInFilesystemProc; /* Function to check whether a path is in * this filesystem. This is the most * important filesystem procedure. */ Tcl_FSDupInternalRepProc *dupInternalRepProc; /* Function to duplicate internal fs rep. May * be NULL (but then fs is less efficient). */ Tcl_FSFreeInternalRepProc *freeInternalRepProc; /* Function to free internal fs rep. Must * be implemented, if internal representations * need freeing, otherwise it can be NULL. */ Tcl_FSInternalToNormalizedProc *internalToNormalizedProc; /* Function to convert internal representation * to a normalized path. Only required if * the fs creates pure path objects with no * string/path representation. */ Tcl_FSCreateInternalRepProc *createInternalRepProc; /* Function to create a filesystem-specific * internal representation. May be NULL * if paths have no internal representation, * or if the Tcl_FSPathInFilesystemProc * for this filesystem always immediately * creates an internal representation for * paths it accepts. */ Tcl_FSNormalizePathProc *normalizePathProc; /* Function to normalize a path. Should * be implemented for all filesystems * which can have multiple string * representations for the same path * object. */ Tcl_FSFilesystemPathTypeProc *filesystemPathTypeProc; /* Function to determine the type of a * path in this filesystem. May be NULL. */ Tcl_FSFilesystemSeparatorProc *filesystemSeparatorProc; /* Function to return the separator * character(s) for this filesystem. Must * be implemented. */ Tcl_FSStatProc *statProc; /* * Function to process a 'Tcl_FSStat()' * call. Must be implemented for any * reasonable filesystem. */ Tcl_FSAccessProc *accessProc; /* * Function to process a 'Tcl_FSAccess()' * call. Must be implemented for any * reasonable filesystem. */ Tcl_FSOpenFileChannelProc *openFileChannelProc; /* * Function to process a * 'Tcl_FSOpenFileChannel()' call. Must be * implemented for any reasonable * filesystem. */ Tcl_FSMatchInDirectoryProc *matchInDirectoryProc; /* Function to process a * 'Tcl_FSMatchInDirectory()'. If not * implemented, then glob and recursive * copy functionality will be lacking in * the filesystem. */ Tcl_FSUtimeProc *utimeProc; /* Function to process a * 'Tcl_FSUtime()' call. Required to * allow setting (not reading) of times * with 'file mtime', 'file atime' and * the open-r/open-w/fcopy implementation * of 'file copy'. */ Tcl_FSLinkProc *linkProc; /* Function to process a * 'Tcl_FSLink()' call. Should be * implemented only if the filesystem supports * links (reading or creating). */ Tcl_FSListVolumesProc *listVolumesProc; /* Function to list any filesystem volumes * added by this filesystem. Should be * implemented only if the filesystem adds * volumes at the head of the filesystem. */ Tcl_FSFileAttrStringsProc *fileAttrStringsProc; /* Function to list all attributes strings * which are valid for this filesystem. * If not implemented the filesystem will * not support the 'file attributes' command. * This allows arbitrary additional information * to be attached to files in the filesystem. */ Tcl_FSFileAttrsGetProc *fileAttrsGetProc; /* Function to process a * 'Tcl_FSFileAttrsGet()' call, used by * 'file attributes'. */ Tcl_FSFileAttrsSetProc *fileAttrsSetProc; /* Function to process a * 'Tcl_FSFileAttrsSet()' call, used by * 'file attributes'. */ Tcl_FSCreateDirectoryProc *createDirectoryProc; /* Function to process a * 'Tcl_FSCreateDirectory()' call. Should * be implemented unless the FS is * read-only. */ Tcl_FSRemoveDirectoryProc *removeDirectoryProc; /* Function to process a * 'Tcl_FSRemoveDirectory()' call. Should * be implemented unless the FS is * read-only. */ Tcl_FSDeleteFileProc *deleteFileProc; /* Function to process a * 'Tcl_FSDeleteFile()' call. Should * be implemented unless the FS is * read-only. */ Tcl_FSCopyFileProc *copyFileProc; /* Function to process a * 'Tcl_FSCopyFile()' call. If not * implemented Tcl will fall back * on open-r, open-w and fcopy as * a copying mechanism, for copying * actions initiated in Tcl (not C). */ Tcl_FSRenameFileProc *renameFileProc; /* Function to process a * 'Tcl_FSRenameFile()' call. If not * implemented, Tcl will fall back on * a copy and delete mechanism, for * rename actions initiated in Tcl (not C). */ Tcl_FSCopyDirectoryProc *copyDirectoryProc; /* Function to process a * 'Tcl_FSCopyDirectory()' call. If * not implemented, Tcl will fall back * on a recursive create-dir, file copy * mechanism, for copying actions * initiated in Tcl (not C). */ Tcl_FSLstatProc *lstatProc; /* Function to process a * 'Tcl_FSLstat()' call. If not implemented, * Tcl will attempt to use the 'statProc' * defined above instead. */ Tcl_FSLoadFileProc *loadFileProc; /* Function to process a * 'Tcl_FSLoadFile()' call. If not * implemented, Tcl will fall back on * a copy to native-temp followed by a * Tcl_FSLoadFile on that temporary copy. */ Tcl_FSGetCwdProc *getCwdProc; /* * Function to process a 'Tcl_FSGetCwd()' * call. Most filesystems need not * implement this. It will usually only be * called once, if 'getcwd' is called * before 'chdir'. May be NULL. */ Tcl_FSChdirProc *chdirProc; /* * Function to process a 'Tcl_FSChdir()' * call. If filesystems do not implement * this, it will be emulated by a series of * directory access checks. Otherwise, * virtual filesystems which do implement * it need only respond with a positive * return result if the dirName is a valid * directory in their filesystem. They * need not remember the result, since that * will be automatically remembered for use * by GetCwd. Real filesystems should * carry out the correct action (i.e. call * the correct system 'chdir' api). If not * implemented, then 'cd' and 'pwd' will * fail inside the filesystem. */ } Tcl_Filesystem; /* * The following definitions are used as values for the 'linkAction' flag * to Tcl_FSLink, or the linkProc of any filesystem. Any combination * of flags can be given. For link creation, the linkProc should create * a link which matches any of the types given. * * TCL_CREATE_SYMBOLIC_LINK: Create a symbolic or soft link. * TCL_CREATE_HARD_LINK: Create a hard link. */ #define TCL_CREATE_SYMBOLIC_LINK 0x01 #define TCL_CREATE_HARD_LINK 0x02 /* * The following structure represents the Notifier functions that * you can override with the Tcl_SetNotifier call. */ typedef struct Tcl_NotifierProcs { Tcl_SetTimerProc *setTimerProc; Tcl_WaitForEventProc *waitForEventProc; Tcl_CreateFileHandlerProc *createFileHandlerProc; Tcl_DeleteFileHandlerProc *deleteFileHandlerProc; Tcl_InitNotifierProc *initNotifierProc; Tcl_FinalizeNotifierProc *finalizeNotifierProc; Tcl_AlertNotifierProc *alertNotifierProc; Tcl_ServiceModeHookProc *serviceModeHookProc; } Tcl_NotifierProcs; /* * The following structure represents a user-defined encoding. It collects * together all the functions that are used by the specific encoding. */ typedef struct Tcl_EncodingType { CONST char *encodingName; /* The name of the encoding, e.g. "euc-jp". * This name is the unique key for this * encoding type. */ Tcl_EncodingConvertProc *toUtfProc; /* Procedure to convert from external * encoding into UTF-8. */ Tcl_EncodingConvertProc *fromUtfProc; /* Procedure to convert from UTF-8 into * external encoding. */ Tcl_EncodingFreeProc *freeProc; /* If non-NULL, procedure to call when this * encoding is deleted. */ ClientData clientData; /* Arbitrary value associated with encoding * type. Passed to conversion procedures. */ int nullSize; /* Number of zero bytes that signify * end-of-string in this encoding. This * number is used to determine the source * string length when the srcLen argument is * negative. Must be 1 or 2. */ } Tcl_EncodingType; /* * The following definitions are used as values for the conversion control * flags argument when converting text from one character set to another: * * TCL_ENCODING_START: Signifies that the source buffer is the first * block in a (potentially multi-block) input * stream. Tells the conversion procedure to * reset to an initial state and perform any * initialization that needs to occur before the * first byte is converted. If the source * buffer contains the entire input stream to be * converted, this flag should be set. * * TCL_ENCODING_END: Signifies that the source buffer is the last * block in a (potentially multi-block) input * stream. Tells the conversion routine to * perform any finalization that needs to occur * after the last byte is converted and then to * reset to an initial state. If the source * buffer contains the entire input stream to be * converted, this flag should be set. * * TCL_ENCODING_STOPONERROR: If set, then the converter will return * immediately upon encountering an invalid * byte sequence or a source character that has * no mapping in the target encoding. If clear, * then the converter will skip the problem, * substituting one or more "close" characters * in the destination buffer and then continue * to sonvert the source. */ #define TCL_ENCODING_START 0x01 #define TCL_ENCODING_END 0x02 #define TCL_ENCODING_STOPONERROR 0x04 /* * The following data structures and declarations are for the new Tcl * parser. */ /* * For each word of a command, and for each piece of a word such as a * variable reference, one of the following structures is created to * describe the token. */ typedef struct Tcl_Token { int type; /* Type of token, such as TCL_TOKEN_WORD; * see below for valid types. */ CONST char *start; /* First character in token. */ int size; /* Number of bytes in token. */ int numComponents; /* If this token is composed of other * tokens, this field tells how many of * them there are (including components of * components, etc.). The component tokens * immediately follow this one. */ } Tcl_Token; /* * Type values defined for Tcl_Token structures. These values are * defined as mask bits so that it's easy to check for collections of * types. * * TCL_TOKEN_WORD - The token describes one word of a command, * from the first non-blank character of * the word (which may be " or {) up to but * not including the space, semicolon, or * bracket that terminates the word. * NumComponents counts the total number of * sub-tokens that make up the word. This * includes, for example, sub-tokens of * TCL_TOKEN_VARIABLE tokens. * TCL_TOKEN_SIMPLE_WORD - This token is just like TCL_TOKEN_WORD * except that the word is guaranteed to * consist of a single TCL_TOKEN_TEXT * sub-token. * TCL_TOKEN_TEXT - The token describes a range of literal * text that is part of a word. * NumComponents is always 0. * TCL_TOKEN_BS - The token describes a backslash sequence * that must be collapsed. NumComponents * is always 0. * TCL_TOKEN_COMMAND - The token describes a command whose result * must be substituted into the word. The * token includes the enclosing brackets. * NumComponents is always 0. * TCL_TOKEN_VARIABLE - The token describes a variable * substitution, including the dollar sign, * variable name, and array index (if there * is one) up through the right * parentheses. NumComponents tells how * many additional tokens follow to * represent the variable name. The first * token will be a TCL_TOKEN_TEXT token * that describes the variable name. If * the variable is an array reference then * there will be one or more additional * tokens, of type TCL_TOKEN_TEXT, * TCL_TOKEN_BS, TCL_TOKEN_COMMAND, and * TCL_TOKEN_VARIABLE, that describe the * array index; numComponents counts the * total number of nested tokens that make * up the variable reference, including * sub-tokens of TCL_TOKEN_VARIABLE tokens. * TCL_TOKEN_SUB_EXPR - The token describes one subexpression of a * expression, from the first non-blank * character of the subexpression up to but not * including the space, brace, or bracket * that terminates the subexpression. * NumComponents counts the total number of * following subtokens that make up the * subexpression; this includes all subtokens * for any nested TCL_TOKEN_SUB_EXPR tokens. * For example, a numeric value used as a * primitive operand is described by a * TCL_TOKEN_SUB_EXPR token followed by a * TCL_TOKEN_TEXT token. A binary subexpression * is described by a TCL_TOKEN_SUB_EXPR token * followed by the TCL_TOKEN_OPERATOR token * for the operator, then TCL_TOKEN_SUB_EXPR * tokens for the left then the right operands. * TCL_TOKEN_OPERATOR - The token describes one expression operator. * An operator might be the name of a math * function such as "abs". A TCL_TOKEN_OPERATOR * token is always preceeded by one * TCL_TOKEN_SUB_EXPR token for the operator's * subexpression, and is followed by zero or * more TCL_TOKEN_SUB_EXPR tokens for the * operator's operands. NumComponents is * always 0. */ #define TCL_TOKEN_WORD 1 #define TCL_TOKEN_SIMPLE_WORD 2 #define TCL_TOKEN_TEXT 4 #define TCL_TOKEN_BS 8 #define TCL_TOKEN_COMMAND 16 #define TCL_TOKEN_VARIABLE 32 #define TCL_TOKEN_SUB_EXPR 64 #define TCL_TOKEN_OPERATOR 128 /* * Parsing error types. On any parsing error, one of these values * will be stored in the error field of the Tcl_Parse structure * defined below. */ #define TCL_PARSE_SUCCESS 0 #define TCL_PARSE_QUOTE_EXTRA 1 #define TCL_PARSE_BRACE_EXTRA 2 #define TCL_PARSE_MISSING_BRACE 3 #define TCL_PARSE_MISSING_BRACKET 4 #define TCL_PARSE_MISSING_PAREN 5 #define TCL_PARSE_MISSING_QUOTE 6 #define TCL_PARSE_MISSING_VAR_BRACE 7 #define TCL_PARSE_SYNTAX 8 #define TCL_PARSE_BAD_NUMBER 9 /* * A structure of the following type is filled in by Tcl_ParseCommand. * It describes a single command parsed from an input string. */ #define NUM_STATIC_TOKENS 20 typedef struct Tcl_Parse { CONST char *commentStart; /* Pointer to # that begins the first of * one or more comments preceding the * command. */ int commentSize; /* Number of bytes in comments (up through * newline character that terminates the * last comment). If there were no * comments, this field is 0. */ CONST char *commandStart; /* First character in first word of command. */ int commandSize; /* Number of bytes in command, including * first character of first word, up * through the terminating newline, * close bracket, or semicolon. */ int numWords; /* Total number of words in command. May * be 0. */ Tcl_Token *tokenPtr; /* Pointer to first token representing * the words of the command. Initially * points to staticTokens, but may change * to point to malloc-ed space if command * exceeds space in staticTokens. */ int numTokens; /* Total number of tokens in command. */ int tokensAvailable; /* Total number of tokens available at * *tokenPtr. */ int errorType; /* One of the parsing error types defined * above. */ /* * The fields below are intended only for the private use of the * parser. They should not be used by procedures that invoke * Tcl_ParseCommand. */ CONST char *string; /* The original command string passed to * Tcl_ParseCommand. */ CONST char *end; /* Points to the character just after the * last one in the command string. */ Tcl_Interp *interp; /* Interpreter to use for error reporting, * or NULL. */ CONST char *term; /* Points to character in string that * terminated most recent token. Filled in * by ParseTokens. If an error occurs, * points to beginning of region where the * error occurred (e.g. the open brace if * the close brace is missing). */ int incomplete; /* This field is set to 1 by Tcl_ParseCommand * if the command appears to be incomplete. * This information is used by * Tcl_CommandComplete. */ Tcl_Token staticTokens[NUM_STATIC_TOKENS]; /* Initial space for tokens for command. * This space should be large enough to * accommodate most commands; dynamic * space is allocated for very large * commands that don't fit here. */ } Tcl_Parse; /* * The following definitions are the error codes returned by the conversion * routines: * * TCL_OK: All characters were converted. * * TCL_CONVERT_NOSPACE: The output buffer would not have been large * enough for all of the converted data; as many * characters as could fit were converted though. * * TCL_CONVERT_MULTIBYTE: The last few bytes in the source string were * the beginning of a multibyte sequence, but * more bytes were needed to complete this * sequence. A subsequent call to the conversion * routine should pass the beginning of this * unconverted sequence plus additional bytes * from the source stream to properly convert * the formerly split-up multibyte sequence. * * TCL_CONVERT_SYNTAX: The source stream contained an invalid * character sequence. This may occur if the * input stream has been damaged or if the input * encoding method was misidentified. This error * is reported only if TCL_ENCODING_STOPONERROR * was specified. * * TCL_CONVERT_UNKNOWN: The source string contained a character * that could not be represented in the target * encoding. This error is reported only if * TCL_ENCODING_STOPONERROR was specified. */ #define TCL_CONVERT_MULTIBYTE -1 #define TCL_CONVERT_SYNTAX -2 #define TCL_CONVERT_UNKNOWN -3 #define TCL_CONVERT_NOSPACE -4 /* * The maximum number of bytes that are necessary to represent a single * Unicode character in UTF-8. The valid values should be 3 or 6 (or * perhaps 1 if we want to support a non-unicode enabled core). * If 3, then Tcl_UniChar must be 2-bytes in size (UCS-2). (default) * If 6, then Tcl_UniChar must be 4-bytes in size (UCS-4). * At this time UCS-2 mode is the default and recommended mode. * UCS-4 is experimental and not recommended. It works for the core, * but most extensions expect UCS-2. */ #ifndef TCL_UTF_MAX #define TCL_UTF_MAX 3 #endif /* * This represents a Unicode character. Any changes to this should * also be reflected in regcustom.h. */ #if TCL_UTF_MAX > 4 /* * unsigned int isn't 100% accurate as it should be a strict 4-byte * value (perhaps wchar_t). 64-bit systems may have troubles. The * size of this value must be reflected correctly in regcustom.h and * in tclEncoding.c. * XXX: Tcl is currently UCS-2 and planning UTF-16 for the Unicode * XXX: string rep that Tcl_UniChar represents. Changing the size * XXX: of Tcl_UniChar is /not/ supported. */ typedef unsigned int Tcl_UniChar; #else typedef unsigned short Tcl_UniChar; #endif /* * These function have been renamed. The old names are deprecated, but we * define these macros for backwards compatibilty. */ #define Tcl_Ckalloc Tcl_Alloc #define Tcl_Ckfree Tcl_Free #define Tcl_Ckrealloc Tcl_Realloc #define Tcl_Return Tcl_SetResult #define Tcl_TildeSubst Tcl_TranslateFileName #define panic Tcl_Panic #define panicVA Tcl_PanicVA /* * The following constant is used to test for older versions of Tcl * in the stubs tables. * * Jan Nijtman's plus patch uses 0xFCA1BACF, so we need to pick a different * value since the stubs tables don't match. */ #define TCL_STUB_MAGIC ((int)0xFCA3BACF) /* * The following function is required to be defined in all stubs aware * extensions. The function is actually implemented in the stub * library, not the main Tcl library, although there is a trivial * implementation in the main library in case an extension is statically * linked into an application. */ EXTERN CONST char * Tcl_InitStubs _ANSI_ARGS_((Tcl_Interp *interp, CONST char *version, int exact)); #ifndef USE_TCL_STUBS /* * When not using stubs, make it a macro. */ #define Tcl_InitStubs(interp, version, exact) \ Tcl_PkgRequire(interp, "Tcl", version, exact) #endif /* * Include the public function declarations that are accessible via * the stubs table. */ #include "tclDecls.h" /* * Include platform specific public function declarations that are * accessible via the stubs table. */ #include "tclPlatDecls.h" /* * Public functions that are not accessible via the stubs table. */ EXTERN void Tcl_Main _ANSI_ARGS_((int argc, char **argv, Tcl_AppInitProc *appInitProc)); /* * Convenience declaration of Tcl_AppInit for backwards compatibility. * This function is not *implemented* by the tcl library, so the storage * class is neither DLLEXPORT nor DLLIMPORT */ #undef TCL_STORAGE_CLASS #define TCL_STORAGE_CLASS EXTERN int Tcl_AppInit _ANSI_ARGS_((Tcl_Interp *interp)); #undef TCL_STORAGE_CLASS #define TCL_STORAGE_CLASS DLLIMPORT #endif /* RC_INVOKED */ /* * end block for C++ */ #ifdef __cplusplus } #endif #endif /* _TCL */ /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ tcl8.4.20/generic/tclIOCmd.c0000644003604700454610000012503212052456744014137 0ustar dgp771div/* * tclIOCmd.c -- * * Contains the definitions of most of the Tcl commands relating to IO. * * Copyright (c) 1995-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" /* * Callback structure for accept callback in a TCP server. */ typedef struct AcceptCallback { char *script; /* Script to invoke. */ Tcl_Interp *interp; /* Interpreter in which to run it. */ } AcceptCallback; /* * Static functions for this file: */ static void AcceptCallbackProc _ANSI_ARGS_((ClientData callbackData, Tcl_Channel chan, char *address, int port)); static void RegisterTcpServerInterpCleanup _ANSI_ARGS_((Tcl_Interp *interp, AcceptCallback *acceptCallbackPtr)); static void TcpAcceptCallbacksDeleteProc _ANSI_ARGS_(( ClientData clientData, Tcl_Interp *interp)); static void TcpServerCloseProc _ANSI_ARGS_((ClientData callbackData)); static void UnregisterTcpServerInterpCleanupProc _ANSI_ARGS_(( Tcl_Interp *interp, AcceptCallback *acceptCallbackPtr)); /* *---------------------------------------------------------------------- * * Tcl_PutsObjCmd -- * * This procedure is invoked to process the "puts" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * Produces output on a channel. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_PutsObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Tcl_Channel chan; /* The channel to puts on. */ Tcl_Obj *string; /* String to write. */ int newline; /* Add a newline at end? */ char *channelId; /* Name of channel for puts. */ int result; /* Result of puts operation. */ int mode; /* Mode in which channel is opened. */ switch (objc) { case 2: /* puts $x */ string = objv[1]; newline = 1; channelId = "stdout"; break; case 3: /* puts -nonewline $x or puts $chan $x */ if (strcmp(Tcl_GetString(objv[1]), "-nonewline") == 0) { newline = 0; channelId = "stdout"; } else { newline = 1; channelId = Tcl_GetString(objv[1]); } string = objv[2]; break; case 4: /* puts -nonewline $chan $x or puts $chan $x nonewline */ if (strcmp(Tcl_GetString(objv[1]), "-nonewline") == 0) { channelId = Tcl_GetString(objv[2]); string = objv[3]; } else { /* * The code below provides backwards compatibility with an * old form of the command that is no longer recommended * or documented. */ char *arg; int length; arg = Tcl_GetStringFromObj(objv[3], &length); if ((length != 9) || (strncmp(arg, "nonewline", (size_t) length) != 0)) { Tcl_AppendResult(interp, "bad argument \"", arg, "\": should be \"nonewline\"", (char *) NULL); return TCL_ERROR; } channelId = Tcl_GetString(objv[1]); string = objv[2]; } newline = 0; break; default: /* puts or puts some bad number of arguments... */ Tcl_WrongNumArgs(interp, 1, objv, "?-nonewline? ?channelId? string"); return TCL_ERROR; } chan = Tcl_GetChannel(interp, channelId, &mode); if (chan == (Tcl_Channel) NULL) { return TCL_ERROR; } if ((mode & TCL_WRITABLE) == 0) { Tcl_AppendResult(interp, "channel \"", channelId, "\" wasn't opened for writing", (char *) NULL); return TCL_ERROR; } result = Tcl_WriteObj(chan, string); if (result < 0) { goto error; } if (newline != 0) { result = Tcl_WriteChars(chan, "\n", 1); if (result < 0) { goto error; } } return TCL_OK; error: Tcl_AppendResult(interp, "error writing \"", channelId, "\": ", Tcl_PosixError(interp), (char *) NULL); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * Tcl_FlushObjCmd -- * * This procedure is called to process the Tcl "flush" command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * May cause output to appear on the specified channel. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_FlushObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Tcl_Channel chan; /* The channel to flush on. */ char *channelId; int mode; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "channelId"); return TCL_ERROR; } channelId = Tcl_GetString(objv[1]); chan = Tcl_GetChannel(interp, channelId, &mode); if (chan == (Tcl_Channel) NULL) { return TCL_ERROR; } if ((mode & TCL_WRITABLE) == 0) { Tcl_AppendResult(interp, "channel \"", channelId, "\" wasn't opened for writing", (char *) NULL); return TCL_ERROR; } if (Tcl_Flush(chan) != TCL_OK) { Tcl_AppendResult(interp, "error flushing \"", channelId, "\": ", Tcl_PosixError(interp), (char *) NULL); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_GetsObjCmd -- * * This procedure is called to process the Tcl "gets" command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * May consume input from channel. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_GetsObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Tcl_Channel chan; /* The channel to read from. */ int lineLen; /* Length of line just read. */ int mode; /* Mode in which channel is opened. */ char *name; Tcl_Obj *linePtr; if ((objc != 2) && (objc != 3)) { Tcl_WrongNumArgs(interp, 1, objv, "channelId ?varName?"); return TCL_ERROR; } name = Tcl_GetString(objv[1]); chan = Tcl_GetChannel(interp, name, &mode); if (chan == (Tcl_Channel) NULL) { return TCL_ERROR; } if ((mode & TCL_READABLE) == 0) { Tcl_AppendResult(interp, "channel \"", name, "\" wasn't opened for reading", (char *) NULL); return TCL_ERROR; } linePtr = Tcl_NewObj(); lineLen = Tcl_GetsObj(chan, linePtr); if (lineLen < 0) { if (!Tcl_Eof(chan) && !Tcl_InputBlocked(chan)) { Tcl_DecrRefCount(linePtr); Tcl_ResetResult(interp); Tcl_AppendResult(interp, "error reading \"", name, "\": ", Tcl_PosixError(interp), (char *) NULL); return TCL_ERROR; } lineLen = -1; } if (objc == 3) { if (Tcl_ObjSetVar2(interp, objv[2], NULL, linePtr, TCL_LEAVE_ERR_MSG) == NULL) { Tcl_DecrRefCount(linePtr); return TCL_ERROR; } Tcl_SetObjResult(interp, Tcl_NewIntObj(lineLen)); return TCL_OK; } else { Tcl_SetObjResult(interp, linePtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_ReadObjCmd -- * * This procedure is invoked to process the Tcl "read" command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * May consume input from channel. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_ReadObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Tcl_Channel chan; /* The channel to read from. */ int newline, i; /* Discard newline at end? */ int toRead; /* How many bytes to read? */ int charactersRead; /* How many characters were read? */ int mode; /* Mode in which channel is opened. */ char *name; Tcl_Obj *resultPtr; if ((objc != 2) && (objc != 3)) { argerror: Tcl_WrongNumArgs(interp, 1, objv, "channelId ?numChars?"); Tcl_AppendResult(interp, " or \"", Tcl_GetString(objv[0]), " ?-nonewline? channelId\"", (char *) NULL); return TCL_ERROR; } i = 1; newline = 0; if (strcmp(Tcl_GetString(objv[1]), "-nonewline") == 0) { newline = 1; i++; } if (i == objc) { goto argerror; } name = Tcl_GetString(objv[i]); chan = Tcl_GetChannel(interp, name, &mode); if (chan == (Tcl_Channel) NULL) { return TCL_ERROR; } if ((mode & TCL_READABLE) == 0) { Tcl_AppendResult(interp, "channel \"", name, "\" wasn't opened for reading", (char *) NULL); return TCL_ERROR; } i++; /* Consumed channel name. */ /* * Compute how many bytes to read, and see whether the final * newline should be dropped. */ toRead = -1; if (i < objc) { char *arg; arg = Tcl_GetString(objv[i]); if (isdigit(UCHAR(arg[0]))) { /* INTL: digit */ if (Tcl_GetIntFromObj(interp, objv[i], &toRead) != TCL_OK) { return TCL_ERROR; } } else if (strcmp(arg, "nonewline") == 0) { newline = 1; } else { Tcl_AppendResult(interp, "bad argument \"", arg, "\": should be \"nonewline\"", (char *) NULL); return TCL_ERROR; } } resultPtr = Tcl_NewObj(); Tcl_IncrRefCount(resultPtr); charactersRead = Tcl_ReadChars(chan, resultPtr, toRead, 0); if (charactersRead < 0) { Tcl_ResetResult(interp); Tcl_AppendResult(interp, "error reading \"", name, "\": ", Tcl_PosixError(interp), (char *) NULL); Tcl_DecrRefCount(resultPtr); return TCL_ERROR; } /* * If requested, remove the last newline in the channel if at EOF. */ if ((charactersRead > 0) && (newline != 0)) { char *result; int length; result = Tcl_GetStringFromObj(resultPtr, &length); if (result[length - 1] == '\n') { Tcl_SetObjLength(resultPtr, length - 1); } } Tcl_SetObjResult(interp, resultPtr); Tcl_DecrRefCount(resultPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_SeekObjCmd -- * * This procedure is invoked to process the Tcl "seek" command. See * the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * Moves the position of the access point on the specified channel. * May flush queued output. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_SeekObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Tcl_Channel chan; /* The channel to tell on. */ Tcl_WideInt offset; /* Where to seek? */ int mode; /* How to seek? */ Tcl_WideInt result; /* Of calling Tcl_Seek. */ char *chanName; int optionIndex; static CONST char *originOptions[] = { "start", "current", "end", (char *) NULL }; static CONST int modeArray[] = {SEEK_SET, SEEK_CUR, SEEK_END}; if ((objc != 3) && (objc != 4)) { Tcl_WrongNumArgs(interp, 1, objv, "channelId offset ?origin?"); return TCL_ERROR; } chanName = Tcl_GetString(objv[1]); chan = Tcl_GetChannel(interp, chanName, NULL); if (chan == (Tcl_Channel) NULL) { return TCL_ERROR; } if (Tcl_GetWideIntFromObj(interp, objv[2], &offset) != TCL_OK) { return TCL_ERROR; } mode = SEEK_SET; if (objc == 4) { if (Tcl_GetIndexFromObj(interp, objv[3], originOptions, "origin", 0, &optionIndex) != TCL_OK) { return TCL_ERROR; } mode = modeArray[optionIndex]; } result = Tcl_Seek(chan, offset, mode); if (result == Tcl_LongAsWide(-1)) { Tcl_AppendResult(interp, "error during seek on \"", chanName, "\": ", Tcl_PosixError(interp), (char *) NULL); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_TellObjCmd -- * * This procedure is invoked to process the Tcl "tell" command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_TellObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Tcl_Channel chan; /* The channel to tell on. */ char *chanName; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "channelId"); return TCL_ERROR; } /* * Try to find a channel with the right name and permissions in * the IO channel table of this interpreter. */ chanName = Tcl_GetString(objv[1]); chan = Tcl_GetChannel(interp, chanName, NULL); if (chan == (Tcl_Channel) NULL) { return TCL_ERROR; } Tcl_SetWideIntObj(Tcl_GetObjResult(interp), Tcl_Tell(chan)); return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_CloseObjCmd -- * * This procedure is invoked to process the Tcl "close" command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * May discard queued input; may flush queued output. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_CloseObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Tcl_Channel chan; /* The channel to close. */ char *arg; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "channelId"); return TCL_ERROR; } arg = Tcl_GetString(objv[1]); chan = Tcl_GetChannel(interp, arg, NULL); if (chan == (Tcl_Channel) NULL) { return TCL_ERROR; } if (Tcl_UnregisterChannel(interp, chan) != TCL_OK) { /* * If there is an error message and it ends with a newline, remove * the newline. This is done for command pipeline channels where the * error output from the subprocesses is stored in interp's result. * * NOTE: This is likely to not have any effect on regular error * messages produced by drivers during the closing of a channel, * because the Tcl convention is that such error messages do not * have a terminating newline. */ Tcl_Obj *resultPtr; char *string; int len; resultPtr = Tcl_GetObjResult(interp); string = Tcl_GetStringFromObj(resultPtr, &len); if ((len > 0) && (string[len - 1] == '\n')) { Tcl_SetObjLength(resultPtr, len - 1); } return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_FconfigureObjCmd -- * * This procedure is invoked to process the Tcl "fconfigure" command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * May modify the behavior of an IO channel. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_FconfigureObjCmd(clientData, interp, objc, objv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { char *chanName, *optionName, *valueName; Tcl_Channel chan; /* The channel to set a mode on. */ int i; /* Iterate over arg-value pairs. */ Tcl_DString ds; /* DString to hold result of * calling Tcl_GetChannelOption. */ if ((objc < 2) || (((objc % 2) == 1) && (objc != 3))) { Tcl_WrongNumArgs(interp, 1, objv, "channelId ?optionName? ?value? ?optionName value?..."); return TCL_ERROR; } chanName = Tcl_GetString(objv[1]); chan = Tcl_GetChannel(interp, chanName, NULL); if (chan == (Tcl_Channel) NULL) { return TCL_ERROR; } if (objc == 2) { Tcl_DStringInit(&ds); if (Tcl_GetChannelOption(interp, chan, (char *) NULL, &ds) != TCL_OK) { Tcl_DStringFree(&ds); return TCL_ERROR; } Tcl_DStringResult(interp, &ds); return TCL_OK; } if (objc == 3) { Tcl_DStringInit(&ds); optionName = Tcl_GetString(objv[2]); if (Tcl_GetChannelOption(interp, chan, optionName, &ds) != TCL_OK) { Tcl_DStringFree(&ds); return TCL_ERROR; } Tcl_DStringResult(interp, &ds); return TCL_OK; } for (i = 3; i < objc; i += 2) { optionName = Tcl_GetString(objv[i-1]); valueName = Tcl_GetString(objv[i]); if (Tcl_SetChannelOption(interp, chan, optionName, valueName) != TCL_OK) { return TCL_ERROR; } } return TCL_OK; } /* *--------------------------------------------------------------------------- * * Tcl_EofObjCmd -- * * This procedure is invoked to process the Tcl "eof" command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * Sets interp's result to boolean true or false depending on whether * the specified channel has an EOF condition. * *--------------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_EofObjCmd(unused, interp, objc, objv) ClientData unused; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Tcl_Channel chan; int dummy; char *arg; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "channelId"); return TCL_ERROR; } arg = Tcl_GetString(objv[1]); chan = Tcl_GetChannel(interp, arg, &dummy); if (chan == NULL) { return TCL_ERROR; } Tcl_SetBooleanObj(Tcl_GetObjResult(interp), Tcl_Eof(chan)); return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_ExecObjCmd -- * * This procedure is invoked to process the "exec" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_ExecObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { /* * This procedure generates an argv array for the string arguments. It * starts out with stack-allocated space but uses dynamically-allocated * storage if needed. */ #define NUM_ARGS 20 Tcl_Obj *resultPtr; CONST char **argv; char *string; Tcl_Channel chan; CONST char *argStorage[NUM_ARGS]; int argc, background, i, index, keepNewline, result, skip, length; static CONST char *options[] = { "-keepnewline", "--", NULL }; enum options { EXEC_KEEPNEWLINE, EXEC_LAST }; /* * Check for a leading "-keepnewline" argument. */ keepNewline = 0; for (skip = 1; skip < objc; skip++) { string = Tcl_GetString(objv[skip]); if (string[0] != '-') { break; } if (Tcl_GetIndexFromObj(interp, objv[skip], options, "switch", TCL_EXACT, &index) != TCL_OK) { return TCL_ERROR; } if (index == EXEC_KEEPNEWLINE) { keepNewline = 1; } else { skip++; break; } } if (objc <= skip) { Tcl_WrongNumArgs(interp, 1, objv, "?switches? arg ?arg ...?"); return TCL_ERROR; } /* * See if the command is to be run in background. */ background = 0; string = Tcl_GetString(objv[objc - 1]); if ((string[0] == '&') && (string[1] == '\0')) { objc--; background = 1; } /* * Create the string argument array "argv". Make sure argv is large * enough to hold the argc arguments plus 1 extra for the zero * end-of-argv word. */ argv = argStorage; argc = objc - skip; if ((argc + 1) > (int)(sizeof(argv) / sizeof(argv[0]))) { argv = (CONST char **) ckalloc((unsigned)(argc + 1) * sizeof(char *)); } /* * Copy the string conversions of each (post option) object into the * argument vector. */ for (i = 0; i < argc; i++) { argv[i] = Tcl_GetString(objv[i + skip]); } argv[argc] = NULL; chan = Tcl_OpenCommandChannel(interp, argc, argv, (background ? 0 : TCL_STDOUT | TCL_STDERR)); /* * Free the argv array if malloc'ed storage was used. */ if (argv != argStorage) { ckfree((char *)argv); } if (chan == (Tcl_Channel) NULL) { return TCL_ERROR; } if (background) { /* * Store the list of PIDs from the pipeline in interp's result and * detach the PIDs (instead of waiting for them). */ TclGetAndDetachPids(interp, chan); if (Tcl_Close(interp, chan) != TCL_OK) { return TCL_ERROR; } return TCL_OK; } resultPtr = Tcl_NewObj(); if (Tcl_GetChannelHandle(chan, TCL_READABLE, NULL) == TCL_OK) { if (Tcl_ReadChars(chan, resultPtr, -1, 0) < 0) { Tcl_ResetResult(interp); Tcl_AppendResult(interp, "error reading output from command: ", Tcl_PosixError(interp), (char *) NULL); Tcl_DecrRefCount(resultPtr); return TCL_ERROR; } } /* * If the process produced anything on stderr, it will have been * returned in the interpreter result. It needs to be appended to * the result string. */ result = Tcl_Close(interp, chan); string = Tcl_GetStringFromObj(Tcl_GetObjResult(interp), &length); Tcl_AppendToObj(resultPtr, string, length); /* * If the last character of the result is a newline, then remove * the newline character. */ if (keepNewline == 0) { string = Tcl_GetStringFromObj(resultPtr, &length); if ((length > 0) && (string[length - 1] == '\n')) { Tcl_SetObjLength(resultPtr, length - 1); } } Tcl_SetObjResult(interp, resultPtr); return result; } /* *--------------------------------------------------------------------------- * * Tcl_FblockedObjCmd -- * * This procedure is invoked to process the Tcl "fblocked" command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * Sets interp's result to boolean true or false depending on whether * the preceeding input operation on the channel would have blocked. * *--------------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_FblockedObjCmd(unused, interp, objc, objv) ClientData unused; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Tcl_Channel chan; int mode; char *arg; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "channelId"); return TCL_ERROR; } arg = Tcl_GetString(objv[1]); chan = Tcl_GetChannel(interp, arg, &mode); if (chan == NULL) { return TCL_ERROR; } if ((mode & TCL_READABLE) == 0) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "channel \"", arg, "\" wasn't opened for reading", (char *) NULL); return TCL_ERROR; } Tcl_SetBooleanObj(Tcl_GetObjResult(interp), Tcl_InputBlocked(chan)); return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_OpenObjCmd -- * * This procedure is invoked to process the "open" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_OpenObjCmd(notUsed, interp, objc, objv) ClientData notUsed; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int pipeline, prot; char *modeString, *what; Tcl_Channel chan; if ((objc < 2) || (objc > 4)) { Tcl_WrongNumArgs(interp, 1, objv, "fileName ?access? ?permissions?"); return TCL_ERROR; } prot = 0666; if (objc == 2) { modeString = "r"; } else { modeString = Tcl_GetString(objv[2]); if (objc == 4) { if (Tcl_GetIntFromObj(interp, objv[3], &prot) != TCL_OK) { return TCL_ERROR; } } } pipeline = 0; what = Tcl_GetString(objv[1]); if (what[0] == '|') { pipeline = 1; } /* * Open the file or create a process pipeline. */ if (!pipeline) { chan = Tcl_FSOpenFileChannel(interp, objv[1], modeString, prot); } else { int mode, seekFlag, cmdObjc; CONST char **cmdArgv; if (Tcl_SplitList(interp, what+1, &cmdObjc, &cmdArgv) != TCL_OK) { return TCL_ERROR; } mode = TclGetOpenMode(interp, modeString, &seekFlag); if (mode == -1) { chan = NULL; } else { int flags = TCL_STDERR | TCL_ENFORCE_MODE; switch (mode & (O_RDONLY | O_WRONLY | O_RDWR)) { case O_RDONLY: flags |= TCL_STDOUT; break; case O_WRONLY: flags |= TCL_STDIN; break; case O_RDWR: flags |= (TCL_STDIN | TCL_STDOUT); break; default: panic("Tcl_OpenCmd: invalid mode value"); break; } chan = Tcl_OpenCommandChannel(interp, cmdObjc, cmdArgv, flags); } ckfree((char *) cmdArgv); } if (chan == (Tcl_Channel) NULL) { return TCL_ERROR; } Tcl_RegisterChannel(interp, chan); Tcl_AppendResult(interp, Tcl_GetChannelName(chan), (char *) NULL); return TCL_OK; } /* *---------------------------------------------------------------------- * * TcpAcceptCallbacksDeleteProc -- * * Assocdata cleanup routine called when an interpreter is being * deleted to set the interp field of all the accept callback records * registered with the interpreter to NULL. This will prevent the * interpreter from being used in the future to eval accept scripts. * * Results: * None. * * Side effects: * Deallocates memory and sets the interp field of all the accept * callback records to NULL to prevent this interpreter from being * used subsequently to eval accept scripts. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static void TcpAcceptCallbacksDeleteProc(clientData, interp) ClientData clientData; /* Data which was passed when the assocdata * was registered. */ Tcl_Interp *interp; /* Interpreter being deleted - not used. */ { Tcl_HashTable *hTblPtr; Tcl_HashEntry *hPtr; Tcl_HashSearch hSearch; AcceptCallback *acceptCallbackPtr; hTblPtr = (Tcl_HashTable *) clientData; for (hPtr = Tcl_FirstHashEntry(hTblPtr, &hSearch); hPtr != (Tcl_HashEntry *) NULL; hPtr = Tcl_NextHashEntry(&hSearch)) { acceptCallbackPtr = (AcceptCallback *) Tcl_GetHashValue(hPtr); acceptCallbackPtr->interp = (Tcl_Interp *) NULL; } Tcl_DeleteHashTable(hTblPtr); ckfree((char *) hTblPtr); } /* *---------------------------------------------------------------------- * * RegisterTcpServerInterpCleanup -- * * Registers an accept callback record to have its interp * field set to NULL when the interpreter is deleted. * * Results: * None. * * Side effects: * When, in the future, the interpreter is deleted, the interp * field of the accept callback data structure will be set to * NULL. This will prevent attempts to eval the accept script * in a deleted interpreter. * *---------------------------------------------------------------------- */ static void RegisterTcpServerInterpCleanup(interp, acceptCallbackPtr) Tcl_Interp *interp; /* Interpreter for which we want to be * informed of deletion. */ AcceptCallback *acceptCallbackPtr; /* The accept callback record whose * interp field we want set to NULL when * the interpreter is deleted. */ { Tcl_HashTable *hTblPtr; /* Hash table for accept callback * records to smash when the interpreter * will be deleted. */ Tcl_HashEntry *hPtr; /* Entry for this record. */ int new; /* Is the entry new? */ hTblPtr = (Tcl_HashTable *) Tcl_GetAssocData(interp, "tclTCPAcceptCallbacks", NULL); if (hTblPtr == (Tcl_HashTable *) NULL) { hTblPtr = (Tcl_HashTable *) ckalloc((unsigned) sizeof(Tcl_HashTable)); Tcl_InitHashTable(hTblPtr, TCL_ONE_WORD_KEYS); (void) Tcl_SetAssocData(interp, "tclTCPAcceptCallbacks", TcpAcceptCallbacksDeleteProc, (ClientData) hTblPtr); } hPtr = Tcl_CreateHashEntry(hTblPtr, (char *) acceptCallbackPtr, &new); if (!new) { panic("RegisterTcpServerCleanup: damaged accept record table"); } Tcl_SetHashValue(hPtr, (ClientData) acceptCallbackPtr); } /* *---------------------------------------------------------------------- * * UnregisterTcpServerInterpCleanupProc -- * * Unregister a previously registered accept callback record. The * interp field of this record will no longer be set to NULL in * the future when the interpreter is deleted. * * Results: * None. * * Side effects: * Prevents the interp field of the accept callback record from * being set to NULL in the future when the interpreter is deleted. * *---------------------------------------------------------------------- */ static void UnregisterTcpServerInterpCleanupProc(interp, acceptCallbackPtr) Tcl_Interp *interp; /* Interpreter in which the accept callback * record was registered. */ AcceptCallback *acceptCallbackPtr; /* The record for which to delete the * registration. */ { Tcl_HashTable *hTblPtr; Tcl_HashEntry *hPtr; hTblPtr = (Tcl_HashTable *) Tcl_GetAssocData(interp, "tclTCPAcceptCallbacks", NULL); if (hTblPtr == (Tcl_HashTable *) NULL) { return; } hPtr = Tcl_FindHashEntry(hTblPtr, (char *) acceptCallbackPtr); if (hPtr == (Tcl_HashEntry *) NULL) { return; } Tcl_DeleteHashEntry(hPtr); } /* *---------------------------------------------------------------------- * * AcceptCallbackProc -- * * This callback is invoked by the TCP channel driver when it * accepts a new connection from a client on a server socket. * * Results: * None. * * Side effects: * Whatever the script does. * *---------------------------------------------------------------------- */ static void AcceptCallbackProc(callbackData, chan, address, port) ClientData callbackData; /* The data stored when the callback * was created in the call to * Tcl_OpenTcpServer. */ Tcl_Channel chan; /* Channel for the newly accepted * connection. */ char *address; /* Address of client that was * accepted. */ int port; /* Port of client that was accepted. */ { AcceptCallback *acceptCallbackPtr; Tcl_Interp *interp; char *script; char portBuf[TCL_INTEGER_SPACE]; int result; acceptCallbackPtr = (AcceptCallback *) callbackData; /* * Check if the callback is still valid; the interpreter may have gone * away, this is signalled by setting the interp field of the callback * data to NULL. */ if (acceptCallbackPtr->interp != (Tcl_Interp *) NULL) { script = acceptCallbackPtr->script; interp = acceptCallbackPtr->interp; Tcl_Preserve((ClientData) script); Tcl_Preserve((ClientData) interp); TclFormatInt(portBuf, port); Tcl_RegisterChannel(interp, chan); /* * Artificially bump the refcount to protect the channel from * being deleted while the script is being evaluated. */ Tcl_RegisterChannel((Tcl_Interp *) NULL, chan); result = Tcl_VarEval(interp, script, " ", Tcl_GetChannelName(chan), " ", address, " ", portBuf, (char *) NULL); if (result != TCL_OK) { Tcl_BackgroundError(interp); Tcl_UnregisterChannel(interp, chan); } /* * Decrement the artificially bumped refcount. After this it is * not safe anymore to use "chan", because it may now be deleted. */ Tcl_UnregisterChannel((Tcl_Interp *) NULL, chan); Tcl_Release((ClientData) interp); Tcl_Release((ClientData) script); } else { /* * The interpreter has been deleted, so there is no useful * way to utilize the client socket - just close it. */ Tcl_Close((Tcl_Interp *) NULL, chan); } } /* *---------------------------------------------------------------------- * * TcpServerCloseProc -- * * This callback is called when the TCP server channel for which it * was registered is being closed. It informs the interpreter in * which the accept script is evaluated (if that interpreter still * exists) that this channel no longer needs to be informed if the * interpreter is deleted. * * Results: * None. * * Side effects: * In the future, if the interpreter is deleted this channel will * no longer be informed. * *---------------------------------------------------------------------- */ static void TcpServerCloseProc(callbackData) ClientData callbackData; /* The data passed in the call to * Tcl_CreateCloseHandler. */ { AcceptCallback *acceptCallbackPtr; /* The actual data. */ acceptCallbackPtr = (AcceptCallback *) callbackData; if (acceptCallbackPtr->interp != (Tcl_Interp *) NULL) { UnregisterTcpServerInterpCleanupProc(acceptCallbackPtr->interp, acceptCallbackPtr); } Tcl_EventuallyFree((ClientData) acceptCallbackPtr->script, TCL_DYNAMIC); ckfree((char *) acceptCallbackPtr); } /* *---------------------------------------------------------------------- * * Tcl_SocketObjCmd -- * * This procedure is invoked to process the "socket" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * Creates a socket based channel. * *---------------------------------------------------------------------- */ int Tcl_SocketObjCmd(notUsed, interp, objc, objv) ClientData notUsed; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { static CONST char *socketOptions[] = { "-async", "-myaddr", "-myport","-server", (char *) NULL }; enum socketOptions { SKT_ASYNC, SKT_MYADDR, SKT_MYPORT, SKT_SERVER }; int optionIndex, a, server, port; char *arg, *copyScript, *host, *script; char *myaddr = NULL; int myport = 0; int async = 0; Tcl_Channel chan; AcceptCallback *acceptCallbackPtr; server = 0; script = NULL; if (TclpHasSockets(interp) != TCL_OK) { return TCL_ERROR; } for (a = 1; a < objc; a++) { arg = Tcl_GetString(objv[a]); if (arg[0] != '-') { break; } if (Tcl_GetIndexFromObj(interp, objv[a], socketOptions, "option", TCL_EXACT, &optionIndex) != TCL_OK) { return TCL_ERROR; } switch ((enum socketOptions) optionIndex) { case SKT_ASYNC: { if (server == 1) { Tcl_AppendResult(interp, "cannot set -async option for server sockets", (char *) NULL); return TCL_ERROR; } async = 1; break; } case SKT_MYADDR: { a++; if (a >= objc) { Tcl_AppendResult(interp, "no argument given for -myaddr option", (char *) NULL); return TCL_ERROR; } myaddr = Tcl_GetString(objv[a]); break; } case SKT_MYPORT: { char *myPortName; a++; if (a >= objc) { Tcl_AppendResult(interp, "no argument given for -myport option", (char *) NULL); return TCL_ERROR; } myPortName = Tcl_GetString(objv[a]); if (TclSockGetPort(interp, myPortName, "tcp", &myport) != TCL_OK) { return TCL_ERROR; } break; } case SKT_SERVER: { if (async == 1) { Tcl_AppendResult(interp, "cannot set -async option for server sockets", (char *) NULL); return TCL_ERROR; } server = 1; a++; if (a >= objc) { Tcl_AppendResult(interp, "no argument given for -server option", (char *) NULL); return TCL_ERROR; } script = Tcl_GetString(objv[a]); break; } default: { panic("Tcl_SocketObjCmd: bad option index to SocketOptions"); } } } if (server) { host = myaddr; /* NULL implies INADDR_ANY */ if (myport != 0) { Tcl_AppendResult(interp, "Option -myport is not valid for servers", NULL); return TCL_ERROR; } } else if (a < objc) { host = Tcl_GetString(objv[a]); a++; } else { wrongNumArgs: Tcl_AppendResult(interp, "wrong # args: should be either:\n", Tcl_GetString(objv[0]), " ?-myaddr addr? ?-myport myport? ?-async? host port\n", Tcl_GetString(objv[0]), " -server command ?-myaddr addr? port", (char *) NULL); return TCL_ERROR; } if (a == objc-1) { if (TclSockGetPort(interp, Tcl_GetString(objv[a]), "tcp", &port) != TCL_OK) { return TCL_ERROR; } } else { goto wrongNumArgs; } if (server) { acceptCallbackPtr = (AcceptCallback *) ckalloc((unsigned) sizeof(AcceptCallback)); copyScript = ckalloc((unsigned) strlen(script) + 1); strcpy(copyScript, script); acceptCallbackPtr->script = copyScript; acceptCallbackPtr->interp = interp; chan = Tcl_OpenTcpServer(interp, port, host, AcceptCallbackProc, (ClientData) acceptCallbackPtr); if (chan == (Tcl_Channel) NULL) { ckfree(copyScript); ckfree((char *) acceptCallbackPtr); return TCL_ERROR; } /* * Register with the interpreter to let us know when the * interpreter is deleted (by having the callback set the * acceptCallbackPtr->interp field to NULL). This is to * avoid trying to eval the script in a deleted interpreter. */ RegisterTcpServerInterpCleanup(interp, acceptCallbackPtr); /* * Register a close callback. This callback will inform the * interpreter (if it still exists) that this channel does not * need to be informed when the interpreter is deleted. */ Tcl_CreateCloseHandler(chan, TcpServerCloseProc, (ClientData) acceptCallbackPtr); } else { chan = Tcl_OpenTcpClient(interp, port, host, myaddr, myport, async); if (chan == (Tcl_Channel) NULL) { return TCL_ERROR; } } Tcl_RegisterChannel(interp, chan); Tcl_AppendResult(interp, Tcl_GetChannelName(chan), (char *) NULL); return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_FcopyObjCmd -- * * This procedure is invoked to process the "fcopy" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * Moves data between two channels and possibly sets up a * background copy handler. * *---------------------------------------------------------------------- */ int Tcl_FcopyObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { Tcl_Channel inChan, outChan; char *arg; int mode, i; int toRead, index; Tcl_Obj *cmdPtr; static CONST char* switches[] = { "-size", "-command", NULL }; enum { FcopySize, FcopyCommand }; if ((objc < 3) || (objc > 7) || (objc == 4) || (objc == 6)) { Tcl_WrongNumArgs(interp, 1, objv, "input output ?-size size? ?-command callback?"); return TCL_ERROR; } /* * Parse the channel arguments and verify that they are readable * or writable, as appropriate. */ arg = Tcl_GetString(objv[1]); inChan = Tcl_GetChannel(interp, arg, &mode); if (inChan == (Tcl_Channel) NULL) { return TCL_ERROR; } if ((mode & TCL_READABLE) == 0) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "channel \"", arg, "\" wasn't opened for reading", (char *) NULL); return TCL_ERROR; } arg = Tcl_GetString(objv[2]); outChan = Tcl_GetChannel(interp, arg, &mode); if (outChan == (Tcl_Channel) NULL) { return TCL_ERROR; } if ((mode & TCL_WRITABLE) == 0) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "channel \"", arg, "\" wasn't opened for writing", (char *) NULL); return TCL_ERROR; } toRead = -1; cmdPtr = NULL; for (i = 3; i < objc; i += 2) { if (Tcl_GetIndexFromObj(interp, objv[i], switches, "switch", 0, (int *) &index) != TCL_OK) { return TCL_ERROR; } switch (index) { case FcopySize: if (Tcl_GetIntFromObj(interp, objv[i+1], &toRead) != TCL_OK) { return TCL_ERROR; } if (toRead<0) { /* * Handle all negative sizes like -1, meaning 'copy all'. * By resetting toRead we avoid changes in the * core copying functions (which explicitly check * for -1 and crash on any other negative value). */ toRead = -1; } break; case FcopyCommand: cmdPtr = objv[i+1]; break; } } return TclCopyChannel(interp, inChan, outChan, toRead, cmdPtr); } tcl8.4.20/generic/tclThreadTest.c0000644003604700454610000006605212133546540015253 0ustar dgp771div/* * tclThreadTest.c -- * * This file implements the testthread command. Eventually this * should be tclThreadCmd.c * Some of this code is based on work done by Richard Hipp on behalf of * Conservation Through Innovation, Limited, with their permission. * * Copyright (c) 1998 by Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #ifdef TCL_THREADS /* * Each thread has an single instance of the following structure. There * is one instance of this structure per thread even if that thread contains * multiple interpreters. The interpreter identified by this structure is * the main interpreter for the thread. * * The main interpreter is the one that will process any messages * received by a thread. Any thread can send messages but only the * main interpreter can receive them. */ typedef struct ThreadSpecificData { Tcl_ThreadId threadId; /* Tcl ID for this thread */ Tcl_Interp *interp; /* Main interpreter for this thread */ int flags; /* See the TP_ defines below... */ struct ThreadSpecificData *nextPtr; /* List for "thread names" */ struct ThreadSpecificData *prevPtr; /* List for "thread names" */ } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; /* * This list is used to list all threads that have interpreters. * This is protected by threadMutex. */ static struct ThreadSpecificData *threadList; /* * The following bit-values are legal for the "flags" field of the * ThreadSpecificData structure. */ #define TP_Dying 0x001 /* This thread is being cancelled */ /* * An instance of the following structure contains all information that is * passed into a new thread when the thread is created using either the * "thread create" Tcl command or the TclCreateThread() C function. */ typedef struct ThreadCtrl { char *script; /* The TCL command this thread should execute */ int flags; /* Initial value of the "flags" field in the * ThreadSpecificData structure for the new thread. * Might contain TP_Detached or TP_TclThread. */ Tcl_Condition condWait; /* This condition variable is used to synchronize * the parent and child threads. The child won't run * until it acquires threadMutex, and the parent function * won't complete until signaled on this condition * variable. */ } ThreadCtrl; /* * This is the event used to send scripts to other threads. */ typedef struct ThreadEvent { Tcl_Event event; /* Must be first */ char *script; /* The script to execute. */ struct ThreadEventResult *resultPtr; /* To communicate the result. This is * NULL if we don't care about it. */ } ThreadEvent; typedef struct ThreadEventResult { Tcl_Condition done; /* Signaled when the script completes */ int code; /* Return value of Tcl_Eval */ char *result; /* Result from the script */ char *errorInfo; /* Copy of errorInfo variable */ char *errorCode; /* Copy of errorCode variable */ Tcl_ThreadId srcThreadId; /* Id of sending thread, in case it dies */ Tcl_ThreadId dstThreadId; /* Id of target thread, in case it dies */ struct ThreadEvent *eventPtr; /* Back pointer */ struct ThreadEventResult *nextPtr; /* List for cleanup */ struct ThreadEventResult *prevPtr; } ThreadEventResult; static ThreadEventResult *resultList; /* * This is for simple error handling when a thread script exits badly. */ static Tcl_ThreadId errorThreadId; static char *errorProcString; /* * Access to the list of threads and to the thread send results is * guarded by this mutex. */ TCL_DECLARE_MUTEX(threadMutex) #undef TCL_STORAGE_CLASS #define TCL_STORAGE_CLASS DLLEXPORT EXTERN int TclThread_Init _ANSI_ARGS_((Tcl_Interp *interp)); EXTERN int Tcl_ThreadObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); EXTERN int TclCreateThread _ANSI_ARGS_((Tcl_Interp *interp, char *script, int joinable)); EXTERN int TclThreadList _ANSI_ARGS_((Tcl_Interp *interp)); EXTERN int TclThreadSend _ANSI_ARGS_((Tcl_Interp *interp, Tcl_ThreadId id, char *script, int wait)); #undef TCL_STORAGE_CLASS #define TCL_STORAGE_CLASS DLLIMPORT Tcl_ThreadCreateType NewTestThread _ANSI_ARGS_((ClientData clientData)); static void ListRemove _ANSI_ARGS_((ThreadSpecificData *tsdPtr)); static void ListUpdateInner _ANSI_ARGS_((ThreadSpecificData *tsdPtr)); static int ThreadEventProc _ANSI_ARGS_((Tcl_Event *evPtr, int mask)); static void ThreadErrorProc _ANSI_ARGS_((Tcl_Interp *interp)); static void ThreadFreeProc _ANSI_ARGS_((ClientData clientData)); static int ThreadDeleteEvent _ANSI_ARGS_((Tcl_Event *eventPtr, ClientData clientData)); static void ThreadExitProc _ANSI_ARGS_((ClientData clientData)); /* *---------------------------------------------------------------------- * * TclThread_Init -- * * Initialize the test thread command. * * Results: * TCL_OK if the package was properly initialized. * * Side effects: * Add the "testthread" command to the interp. * *---------------------------------------------------------------------- */ int TclThread_Init(interp) Tcl_Interp *interp; /* The current Tcl interpreter */ { Tcl_CreateObjCommand(interp,"testthread", Tcl_ThreadObjCmd, (ClientData)NULL ,NULL); if (Tcl_PkgProvide(interp, "Thread", "1.0" ) != TCL_OK) { return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_ThreadObjCmd -- * * This procedure is invoked to process the "testthread" Tcl command. * See the user documentation for details on what it does. * * thread create ?-joinable? ?script? * thread send id ?-async? script * thread exit * thread info id * thread names * thread wait * thread errorproc proc * thread join id * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_ThreadObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); int option; static CONST char *threadOptions[] = {"create", "exit", "id", "join", "names", "send", "wait", "errorproc", (char *) NULL}; enum options {THREAD_CREATE, THREAD_EXIT, THREAD_ID, THREAD_JOIN, THREAD_NAMES, THREAD_SEND, THREAD_WAIT, THREAD_ERRORPROC}; if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "option ?args?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[1], threadOptions, "option", 0, &option) != TCL_OK) { return TCL_ERROR; } /* * Make sure the initial thread is on the list before doing anything. */ if (tsdPtr->interp == NULL) { Tcl_MutexLock(&threadMutex); tsdPtr->interp = interp; ListUpdateInner(tsdPtr); Tcl_CreateThreadExitHandler(ThreadExitProc, NULL); Tcl_MutexUnlock(&threadMutex); } switch ((enum options)option) { case THREAD_CREATE: { char *script; int joinable, len; if (objc == 2) { /* Neither joinable nor special script */ joinable = 0; script = "testthread wait"; /* Just enter the event loop */ } else if (objc == 3) { /* Possibly -joinable, then no special script, * no joinable, then its a script. */ script = Tcl_GetString(objv[2]); len = strlen (script); if ((len > 1) && (script [0] == '-') && (script [1] == 'j') && (0 == strncmp (script, "-joinable", (size_t) len))) { joinable = 1; script = "testthread wait"; /* Just enter the event loop */ } else { /* Remember the script */ joinable = 0; } } else if (objc == 4) { /* Definitely a script available, but is the flag * -joinable ? */ script = Tcl_GetString(objv[2]); len = strlen (script); joinable = ((len > 1) && (script [0] == '-') && (script [1] == 'j') && (0 == strncmp (script, "-joinable", (size_t) len))); script = Tcl_GetString(objv[3]); } else { Tcl_WrongNumArgs(interp, 2, objv, "?-joinable? ?script?"); return TCL_ERROR; } return TclCreateThread(interp, script, joinable); } case THREAD_EXIT: { if (objc > 2) { Tcl_WrongNumArgs(interp, 1, objv, NULL); return TCL_ERROR; } ListRemove(NULL); Tcl_ExitThread(0); return TCL_OK; } case THREAD_ID: if (objc == 2) { Tcl_Obj *idObj = Tcl_NewLongObj((long)Tcl_GetCurrentThread()); Tcl_SetObjResult(interp, idObj); return TCL_OK; } else { Tcl_WrongNumArgs(interp, 2, objv, NULL); return TCL_ERROR; } case THREAD_JOIN: { long id; int result, status; if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "join id"); return TCL_ERROR; } if (Tcl_GetLongFromObj(interp, objv[2], &id) != TCL_OK) { return TCL_ERROR; } result = Tcl_JoinThread ((Tcl_ThreadId) id, &status); if (result == TCL_OK) { Tcl_SetIntObj (Tcl_GetObjResult (interp), status); } else { char buf [20]; sprintf (buf, "%ld", id); Tcl_AppendResult (interp, "cannot join thread ", buf, NULL); } return result; } case THREAD_NAMES: { if (objc > 2) { Tcl_WrongNumArgs(interp, 2, objv, NULL); return TCL_ERROR; } return TclThreadList(interp); } case THREAD_SEND: { long id; char *script; int wait, arg; if ((objc != 4) && (objc != 5)) { Tcl_WrongNumArgs(interp, 1, objv, "send ?-async? id script"); return TCL_ERROR; } if (objc == 5) { if (strcmp("-async", Tcl_GetString(objv[2])) != 0) { Tcl_WrongNumArgs(interp, 1, objv, "send ?-async? id script"); return TCL_ERROR; } wait = 0; arg = 3; } else { wait = 1; arg = 2; } if (Tcl_GetLongFromObj(interp, objv[arg], &id) != TCL_OK) { return TCL_ERROR; } arg++; script = Tcl_GetString(objv[arg]); return TclThreadSend(interp, (Tcl_ThreadId) id, script, wait); } case THREAD_WAIT: { while (1) { (void) Tcl_DoOneEvent(TCL_ALL_EVENTS); } } case THREAD_ERRORPROC: { /* * Arrange for this proc to handle thread death errors. */ char *proc; if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "errorproc proc"); return TCL_ERROR; } Tcl_MutexLock(&threadMutex); errorThreadId = Tcl_GetCurrentThread(); if (errorProcString) { ckfree(errorProcString); } proc = Tcl_GetString(objv[2]); errorProcString = ckalloc(strlen(proc)+1); strcpy(errorProcString, proc); Tcl_MutexUnlock(&threadMutex); return TCL_OK; } } return TCL_OK; } /* *---------------------------------------------------------------------- * * TclCreateThread -- * * This procedure is invoked to create a thread containing an interp to * run a script. This returns after the thread has started executing. * * Results: * A standard Tcl result, which is the thread ID. * * Side effects: * Create a thread. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int TclCreateThread(interp, script, joinable) Tcl_Interp *interp; /* Current interpreter. */ char *script; /* Script to execute */ int joinable; /* Flag, joinable thread or not */ { ThreadCtrl ctrl; Tcl_ThreadId id; ctrl.script = script; ctrl.condWait = NULL; ctrl.flags = 0; joinable = joinable ? TCL_THREAD_JOINABLE : TCL_THREAD_NOFLAGS; Tcl_MutexLock(&threadMutex); if (Tcl_CreateThread(&id, NewTestThread, (ClientData) &ctrl, TCL_THREAD_STACK_DEFAULT, joinable) != TCL_OK) { Tcl_MutexUnlock(&threadMutex); Tcl_AppendResult(interp,"can't create a new thread",NULL); return TCL_ERROR; } /* * Wait for the thread to start because it is using something on our stack! */ Tcl_ConditionWait(&ctrl.condWait, &threadMutex, NULL); Tcl_MutexUnlock(&threadMutex); Tcl_ConditionFinalize(&ctrl.condWait); Tcl_SetObjResult(interp, Tcl_NewLongObj((long)id)); return TCL_OK; } /* *------------------------------------------------------------------------ * * NewTestThread -- * * This routine is the "main()" for a new thread whose task is to * execute a single TCL script. The argument to this function is * a pointer to a structure that contains the text of the TCL script * to be executed. * * Space to hold the script field of the ThreadControl structure passed * in as the only argument was obtained from malloc() and must be freed * by this function before it exits. Space to hold the ThreadControl * structure itself is released by the calling function, and the * two condition variables in the ThreadControl structure are destroyed * by the calling function. The calling function will destroy the * ThreadControl structure and the condition variable as soon as * ctrlPtr->condWait is signaled, so this routine must make copies of * any data it might need after that point. * * Results: * none * * Side effects: * A TCL script is executed in a new thread. * *------------------------------------------------------------------------ */ Tcl_ThreadCreateType NewTestThread(clientData) ClientData clientData; { ThreadCtrl *ctrlPtr = (ThreadCtrl*)clientData; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); int result; char *threadEvalScript; /* * Initialize the interpreter. This should be more general. */ tsdPtr->interp = Tcl_CreateInterp(); result = Tcl_Init(tsdPtr->interp); result = TclThread_Init(tsdPtr->interp); /* * Update the list of threads. */ Tcl_MutexLock(&threadMutex); ListUpdateInner(tsdPtr); /* * We need to keep a pointer to the alloc'ed mem of the script * we are eval'ing, for the case that we exit during evaluation */ threadEvalScript = (char *) ckalloc(strlen(ctrlPtr->script)+1); strcpy(threadEvalScript, ctrlPtr->script); Tcl_CreateThreadExitHandler(ThreadExitProc, (ClientData) threadEvalScript); /* * Notify the parent we are alive. */ Tcl_ConditionNotify(&ctrlPtr->condWait); Tcl_MutexUnlock(&threadMutex); /* * Run the script. */ Tcl_Preserve((ClientData) tsdPtr->interp); result = Tcl_Eval(tsdPtr->interp, threadEvalScript); if (result != TCL_OK) { ThreadErrorProc(tsdPtr->interp); } /* * Clean up. */ ListRemove(tsdPtr); Tcl_Release((ClientData) tsdPtr->interp); Tcl_DeleteInterp(tsdPtr->interp); Tcl_ExitThread(result); TCL_THREAD_CREATE_RETURN; } /* *------------------------------------------------------------------------ * * ThreadErrorProc -- * * Send a message to the thread willing to hear about errors. * * Results: * none * * Side effects: * Send an event. * *------------------------------------------------------------------------ */ static void ThreadErrorProc(interp) Tcl_Interp *interp; /* Interp that failed */ { Tcl_Channel errChannel; CONST char *errorInfo, *argv[3]; char *script; char buf[TCL_DOUBLE_SPACE+1]; sprintf(buf, "%ld", (long) Tcl_GetCurrentThread()); errorInfo = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY); if (errorProcString == NULL) { errChannel = Tcl_GetStdChannel(TCL_STDERR); Tcl_WriteChars(errChannel, "Error from thread ", -1); Tcl_WriteChars(errChannel, buf, -1); Tcl_WriteChars(errChannel, "\n", 1); Tcl_WriteChars(errChannel, errorInfo, -1); Tcl_WriteChars(errChannel, "\n", 1); } else { argv[0] = errorProcString; argv[1] = buf; argv[2] = errorInfo; script = Tcl_Merge(3, argv); TclThreadSend(interp, errorThreadId, script, 0); ckfree(script); } } /* *------------------------------------------------------------------------ * * ListUpdateInner -- * * Add the thread local storage to the list. This assumes * the caller has obtained the mutex. * * Results: * none * * Side effects: * Add the thread local storage to its list. * *------------------------------------------------------------------------ */ static void ListUpdateInner(tsdPtr) ThreadSpecificData *tsdPtr; { if (tsdPtr == NULL) { tsdPtr = TCL_TSD_INIT(&dataKey); } tsdPtr->threadId = Tcl_GetCurrentThread(); tsdPtr->nextPtr = threadList; if (threadList) { threadList->prevPtr = tsdPtr; } tsdPtr->prevPtr = NULL; threadList = tsdPtr; } /* *------------------------------------------------------------------------ * * ListRemove -- * * Remove the thread local storage from its list. This grabs the * mutex to protect the list. * * Results: * none * * Side effects: * Remove the thread local storage from its list. * *------------------------------------------------------------------------ */ static void ListRemove(tsdPtr) ThreadSpecificData *tsdPtr; { if (tsdPtr == NULL) { tsdPtr = TCL_TSD_INIT(&dataKey); } Tcl_MutexLock(&threadMutex); if (tsdPtr->prevPtr) { tsdPtr->prevPtr->nextPtr = tsdPtr->nextPtr; } else { threadList = tsdPtr->nextPtr; } if (tsdPtr->nextPtr) { tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr; } tsdPtr->nextPtr = tsdPtr->prevPtr = 0; Tcl_MutexUnlock(&threadMutex); } /* *------------------------------------------------------------------------ * * TclThreadList -- * * Return a list of threads running Tcl interpreters. * * Results: * A standard Tcl result. * * Side effects: * None. * *------------------------------------------------------------------------ */ int TclThreadList(interp) Tcl_Interp *interp; { ThreadSpecificData *tsdPtr; Tcl_Obj *listPtr; listPtr = Tcl_NewListObj(0, NULL); Tcl_MutexLock(&threadMutex); for (tsdPtr = threadList ; tsdPtr ; tsdPtr = tsdPtr->nextPtr) { Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewLongObj((long)tsdPtr->threadId)); } Tcl_MutexUnlock(&threadMutex); Tcl_SetObjResult(interp, listPtr); return TCL_OK; } /* *------------------------------------------------------------------------ * * TclThreadSend -- * * Send a script to another thread. * * Results: * A standard Tcl result. * * Side effects: * None. * *------------------------------------------------------------------------ */ int TclThreadSend(interp, id, script, wait) Tcl_Interp *interp; /* The current interpreter. */ Tcl_ThreadId id; /* Thread Id of other interpreter. */ char *script; /* The script to evaluate. */ int wait; /* If 1, we block for the result. */ { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); ThreadEvent *threadEventPtr; ThreadEventResult *resultPtr; int found, code; Tcl_ThreadId threadId = (Tcl_ThreadId) id; /* * Verify the thread exists. */ Tcl_MutexLock(&threadMutex); found = 0; for (tsdPtr = threadList ; tsdPtr ; tsdPtr = tsdPtr->nextPtr) { if (tsdPtr->threadId == threadId) { found = 1; break; } } if (!found) { Tcl_MutexUnlock(&threadMutex); Tcl_AppendResult(interp, "invalid thread id", NULL); return TCL_ERROR; } /* * Short circut sends to ourself. Ought to do something with -async, * like run in an idle handler. */ if (threadId == Tcl_GetCurrentThread()) { Tcl_MutexUnlock(&threadMutex); return Tcl_GlobalEval(interp, script); } /* * Create the event for its event queue. */ threadEventPtr = (ThreadEvent *) ckalloc(sizeof(ThreadEvent)); threadEventPtr->script = ckalloc(strlen(script) + 1); strcpy(threadEventPtr->script, script); if (!wait) { resultPtr = threadEventPtr->resultPtr = NULL; } else { resultPtr = (ThreadEventResult *) ckalloc(sizeof(ThreadEventResult)); threadEventPtr->resultPtr = resultPtr; /* * Initialize the result fields. */ resultPtr->done = NULL; resultPtr->code = 0; resultPtr->result = NULL; resultPtr->errorInfo = NULL; resultPtr->errorCode = NULL; /* * Maintain the cleanup list. */ resultPtr->srcThreadId = Tcl_GetCurrentThread(); resultPtr->dstThreadId = threadId; resultPtr->eventPtr = threadEventPtr; resultPtr->nextPtr = resultList; if (resultList) { resultList->prevPtr = resultPtr; } resultPtr->prevPtr = NULL; resultList = resultPtr; } /* * Queue the event and poke the other thread's notifier. */ threadEventPtr->event.proc = ThreadEventProc; Tcl_ThreadQueueEvent(threadId, (Tcl_Event *)threadEventPtr, TCL_QUEUE_TAIL); Tcl_ThreadAlert(threadId); if (!wait) { Tcl_MutexUnlock(&threadMutex); return TCL_OK; } /* * Block on the results and then get them. */ Tcl_ResetResult(interp); while (resultPtr->result == NULL) { Tcl_ConditionWait(&resultPtr->done, &threadMutex, NULL); } /* * Unlink result from the result list. */ if (resultPtr->prevPtr) { resultPtr->prevPtr->nextPtr = resultPtr->nextPtr; } else { resultList = resultPtr->nextPtr; } if (resultPtr->nextPtr) { resultPtr->nextPtr->prevPtr = resultPtr->prevPtr; } resultPtr->eventPtr = NULL; resultPtr->nextPtr = NULL; resultPtr->prevPtr = NULL; Tcl_MutexUnlock(&threadMutex); if (resultPtr->code != TCL_OK) { if (resultPtr->errorCode) { Tcl_SetErrorCode(interp, resultPtr->errorCode, NULL); ckfree(resultPtr->errorCode); } if (resultPtr->errorInfo) { Tcl_AddErrorInfo(interp, resultPtr->errorInfo); ckfree(resultPtr->errorInfo); } } Tcl_SetResult(interp, resultPtr->result, TCL_DYNAMIC); Tcl_ConditionFinalize(&resultPtr->done); code = resultPtr->code; ckfree((char *) resultPtr); return code; } /* *------------------------------------------------------------------------ * * ThreadEventProc -- * * Handle the event in the target thread. * * Results: * Returns 1 to indicate that the event was processed. * * Side effects: * Fills out the ThreadEventResult struct. * *------------------------------------------------------------------------ */ static int ThreadEventProc(evPtr, mask) Tcl_Event *evPtr; /* Really ThreadEvent */ int mask; { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); ThreadEvent *threadEventPtr = (ThreadEvent *)evPtr; ThreadEventResult *resultPtr = threadEventPtr->resultPtr; Tcl_Interp *interp = tsdPtr->interp; int code; CONST char *result, *errorCode, *errorInfo; if (interp == NULL) { code = TCL_ERROR; result = "no target interp!"; errorCode = "THREAD"; errorInfo = ""; } else { Tcl_Preserve((ClientData) interp); Tcl_ResetResult(interp); Tcl_CreateThreadExitHandler(ThreadFreeProc, (ClientData) threadEventPtr->script); code = Tcl_GlobalEval(interp, threadEventPtr->script); Tcl_DeleteThreadExitHandler(ThreadFreeProc, (ClientData) threadEventPtr->script); if (code != TCL_OK) { errorCode = Tcl_GetVar(interp, "errorCode", TCL_GLOBAL_ONLY); errorInfo = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY); } else { errorCode = errorInfo = NULL; } result = Tcl_GetStringResult(interp); } ckfree(threadEventPtr->script); if (resultPtr) { Tcl_MutexLock(&threadMutex); resultPtr->code = code; resultPtr->result = ckalloc(strlen(result) + 1); strcpy(resultPtr->result, result); if (errorCode != NULL) { resultPtr->errorCode = ckalloc(strlen(errorCode) + 1); strcpy(resultPtr->errorCode, errorCode); } if (errorInfo != NULL) { resultPtr->errorInfo = ckalloc(strlen(errorInfo) + 1); strcpy(resultPtr->errorInfo, errorInfo); } Tcl_ConditionNotify(&resultPtr->done); Tcl_MutexUnlock(&threadMutex); } if (interp != NULL) { Tcl_Release((ClientData) interp); } return 1; } /* *------------------------------------------------------------------------ * * ThreadFreeProc -- * * This is called from when we are exiting and memory needs * to be freed. * * Results: * None. * * Side effects: * Clears up mem specified in ClientData * *------------------------------------------------------------------------ */ /* ARGSUSED */ static void ThreadFreeProc(clientData) ClientData clientData; { if (clientData) { ckfree((char *) clientData); } } /* *------------------------------------------------------------------------ * * ThreadDeleteEvent -- * * This is called from the ThreadExitProc to delete memory related * to events that we put on the queue. * * Results: * 1 it was our event and we want it removed, 0 otherwise. * * Side effects: * It cleans up our events in the event queue for this thread. * *------------------------------------------------------------------------ */ /* ARGSUSED */ static int ThreadDeleteEvent(eventPtr, clientData) Tcl_Event *eventPtr; /* Really ThreadEvent */ ClientData clientData; /* dummy */ { if (eventPtr->proc == ThreadEventProc) { ckfree((char *) ((ThreadEvent *) eventPtr)->script); return 1; } /* * If it was NULL, we were in the middle of servicing the event * and it should be removed */ return (eventPtr->proc == NULL); } /* *------------------------------------------------------------------------ * * ThreadExitProc -- * * This is called when the thread exits. * * Results: * None. * * Side effects: * It unblocks anyone that is waiting on a send to this thread. * It cleans up any events in the event queue for this thread. * *------------------------------------------------------------------------ */ /* ARGSUSED */ static void ThreadExitProc(clientData) ClientData clientData; { char *threadEvalScript = (char *) clientData; ThreadEventResult *resultPtr, *nextPtr; Tcl_ThreadId self = Tcl_GetCurrentThread(); Tcl_MutexLock(&threadMutex); if (threadEvalScript) { ckfree((char *) threadEvalScript); threadEvalScript = NULL; } Tcl_DeleteEvents((Tcl_EventDeleteProc *)ThreadDeleteEvent, NULL); for (resultPtr = resultList ; resultPtr ; resultPtr = nextPtr) { nextPtr = resultPtr->nextPtr; if (resultPtr->srcThreadId == self) { /* * We are going away. By freeing up the result we signal * to the other thread we don't care about the result. */ if (resultPtr->prevPtr) { resultPtr->prevPtr->nextPtr = resultPtr->nextPtr; } else { resultList = resultPtr->nextPtr; } if (resultPtr->nextPtr) { resultPtr->nextPtr->prevPtr = resultPtr->prevPtr; } resultPtr->nextPtr = resultPtr->prevPtr = 0; resultPtr->eventPtr->resultPtr = NULL; ckfree((char *)resultPtr); } else if (resultPtr->dstThreadId == self) { /* * Dang. The target is going away. Unblock the caller. * The result string must be dynamically allocated because * the main thread is going to call free on it. */ char *msg = "target thread died"; resultPtr->result = ckalloc(strlen(msg)+1); strcpy(resultPtr->result, msg); resultPtr->code = TCL_ERROR; Tcl_ConditionNotify(&resultPtr->done); } } Tcl_MutexUnlock(&threadMutex); } #endif /* TCL_THREADS */ tcl8.4.20/generic/tclBinary.c0000644003604700454610000013255512052456743014437 0ustar dgp771div/* * tclBinary.c -- * * This file contains the implementation of the "binary" Tcl built-in * command and the Tcl binary data object. * * Copyright (c) 1997 by Sun Microsystems, Inc. * Copyright (c) 1998-1999 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" #include /* * The following constants are used by GetFormatSpec to indicate various * special conditions in the parsing of a format specifier. */ #define BINARY_ALL -1 /* Use all elements in the argument. */ #define BINARY_NOCOUNT -2 /* No count was specified in format. */ /* * The following defines the maximum number of different (integer) * numbers placed in the object cache by 'binary scan' before it bails * out and switches back to Plan A (creating a new object for each * value.) Theoretically, it would be possible to keep the cache * about for the values that are already in it, but that makes the * code slower in practise when overflow happens, and makes little * odds the rest of the time (as measured on my machine.) It is also * slower (on the sample I tried at least) to grow the cache to hold * all items we might want to put in it; presumably the extra cost of * managing the memory for the enlarged table outweighs the benefit * from allocating fewer objects. This is probably because as the * number of objects increases, the likelihood of reuse of any * particular one drops, and there is very little gain from larger * maximum cache sizes (the value below is chosen to allow caching to * work in full with conversion of bytes.) - DKF */ #define BINARY_SCAN_MAX_CACHE 260 /* * Prototypes for local procedures defined in this file: */ static void DupByteArrayInternalRep _ANSI_ARGS_((Tcl_Obj *srcPtr, Tcl_Obj *copyPtr)); static int FormatNumber _ANSI_ARGS_((Tcl_Interp *interp, int type, Tcl_Obj *src, unsigned char **cursorPtr)); static void CopyNumber _ANSI_ARGS_((CONST VOID *from, VOID *to, unsigned int length)); static void FreeByteArrayInternalRep _ANSI_ARGS_((Tcl_Obj *objPtr)); static int GetFormatSpec _ANSI_ARGS_((char **formatPtr, char *cmdPtr, int *countPtr)); static Tcl_Obj * ScanNumber _ANSI_ARGS_((unsigned char *buffer, int type, Tcl_HashTable **numberCachePtr)); static int SetByteArrayFromAny _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr)); static void UpdateStringOfByteArray _ANSI_ARGS_((Tcl_Obj *listPtr)); static void DeleteScanNumberCache _ANSI_ARGS_(( Tcl_HashTable *numberCachePtr)); /* * The following object type represents an array of bytes. An array of * bytes is not equivalent to an internationalized string. Conceptually, a * string is an array of 16-bit quantities organized as a sequence of properly * formed UTF-8 characters, while a ByteArray is an array of 8-bit quantities. * Accessor functions are provided to convert a ByteArray to a String or a * String to a ByteArray. Two or more consecutive bytes in an array of bytes * may look like a single UTF-8 character if the array is casually treated as * a string. But obtaining the String from a ByteArray is guaranteed to * produced properly formed UTF-8 sequences so that there is a one-to-one * map between bytes and characters. * * Converting a ByteArray to a String proceeds by casting each byte in the * array to a 16-bit quantity, treating that number as a Unicode character, * and storing the UTF-8 version of that Unicode character in the String. * For ByteArrays consisting entirely of values 1..127, the corresponding * String representation is the same as the ByteArray representation. * * Converting a String to a ByteArray proceeds by getting the Unicode * representation of each character in the String, casting it to a * byte by truncating the upper 8 bits, and then storing the byte in the * ByteArray. Converting from ByteArray to String and back to ByteArray * is not lossy, but converting an arbitrary String to a ByteArray may be. */ Tcl_ObjType tclByteArrayType = { "bytearray", FreeByteArrayInternalRep, DupByteArrayInternalRep, UpdateStringOfByteArray, SetByteArrayFromAny }; /* * The following structure is the internal rep for a ByteArray object. * Keeps track of how much memory has been used and how much has been * allocated for the byte array to enable growing and shrinking of the * ByteArray object with fewer mallocs. */ typedef struct ByteArray { int used; /* The number of bytes used in the byte * array. */ int allocated; /* The amount of space actually allocated * minus 1 byte. */ unsigned char bytes[4]; /* The array of bytes. The actual size of * this field depends on the 'allocated' field * above. */ } ByteArray; #define BYTEARRAY_SIZE(len) \ ((unsigned) (sizeof(ByteArray) - 4 + (len))) #define GET_BYTEARRAY(objPtr) \ ((ByteArray *) (objPtr)->internalRep.otherValuePtr) #define SET_BYTEARRAY(objPtr, baPtr) \ (objPtr)->internalRep.otherValuePtr = (VOID *) (baPtr) /* *--------------------------------------------------------------------------- * * Tcl_NewByteArrayObj -- * * This procedure is creates a new ByteArray object and initializes * it from the given array of bytes. * * Results: * The newly create object is returned. This object will have no * initial string representation. The returned object has a ref count * of 0. * * Side effects: * Memory allocated for new object and copy of byte array argument. * *--------------------------------------------------------------------------- */ #ifdef TCL_MEM_DEBUG #undef Tcl_NewByteArrayObj Tcl_Obj * Tcl_NewByteArrayObj(bytes, length) CONST unsigned char *bytes; /* The array of bytes used to initialize * the new object. */ int length; /* Length of the array of bytes, which must * be >= 0. */ { return Tcl_DbNewByteArrayObj(bytes, length, "unknown", 0); } #else /* if not TCL_MEM_DEBUG */ Tcl_Obj * Tcl_NewByteArrayObj(bytes, length) CONST unsigned char *bytes; /* The array of bytes used to initialize * the new object. */ int length; /* Length of the array of bytes, which must * be >= 0. */ { Tcl_Obj *objPtr; TclNewObj(objPtr); Tcl_SetByteArrayObj(objPtr, bytes, length); return objPtr; } #endif /* TCL_MEM_DEBUG */ /* *--------------------------------------------------------------------------- * * Tcl_DbNewByteArrayObj -- * * This procedure is normally called when debugging: i.e., when * TCL_MEM_DEBUG is defined. It is the same as the Tcl_NewByteArrayObj * above except that it calls Tcl_DbCkalloc directly with the file name * and line number from its caller. This simplifies debugging since then * the [memory active] command will report the correct file name and line * number when reporting objects that haven't been freed. * * When TCL_MEM_DEBUG is not defined, this procedure just returns the * result of calling Tcl_NewByteArrayObj. * * Results: * The newly create object is returned. This object will have no * initial string representation. The returned object has a ref count * of 0. * * Side effects: * Memory allocated for new object and copy of byte array argument. * *--------------------------------------------------------------------------- */ #ifdef TCL_MEM_DEBUG Tcl_Obj * Tcl_DbNewByteArrayObj(bytes, length, file, line) CONST unsigned char *bytes; /* The array of bytes used to initialize * the new object. */ int length; /* Length of the array of bytes, which must * be >= 0. */ CONST char *file; /* The name of the source file calling this * procedure; used for debugging. */ int line; /* Line number in the source file; used * for debugging. */ { Tcl_Obj *objPtr; TclDbNewObj(objPtr, file, line); Tcl_SetByteArrayObj(objPtr, bytes, length); return objPtr; } #else /* if not TCL_MEM_DEBUG */ Tcl_Obj * Tcl_DbNewByteArrayObj(bytes, length, file, line) CONST unsigned char *bytes; /* The array of bytes used to initialize * the new object. */ int length; /* Length of the array of bytes, which must * be >= 0. */ CONST char *file; /* The name of the source file calling this * procedure; used for debugging. */ int line; /* Line number in the source file; used * for debugging. */ { return Tcl_NewByteArrayObj(bytes, length); } #endif /* TCL_MEM_DEBUG */ /* *--------------------------------------------------------------------------- * * Tcl_SetByteArrayObj -- * * Modify an object to be a ByteArray object and to have the specified * array of bytes as its value. * * Results: * None. * * Side effects: * The object's old string rep and internal rep is freed. * Memory allocated for copy of byte array argument. * *---------------------------------------------------------------------- */ void Tcl_SetByteArrayObj(objPtr, bytes, length) Tcl_Obj *objPtr; /* Object to initialize as a ByteArray. */ CONST unsigned char *bytes; /* The array of bytes to use as the new * value. */ int length; /* Length of the array of bytes, which must * be >= 0. */ { Tcl_ObjType *typePtr; ByteArray *byteArrayPtr; if (Tcl_IsShared(objPtr)) { panic("Tcl_SetByteArrayObj called with shared object"); } typePtr = objPtr->typePtr; if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) { (*typePtr->freeIntRepProc)(objPtr); } Tcl_InvalidateStringRep(objPtr); byteArrayPtr = (ByteArray *) ckalloc(BYTEARRAY_SIZE(length)); byteArrayPtr->used = length; byteArrayPtr->allocated = length; memcpy((VOID *) byteArrayPtr->bytes, (VOID *) bytes, (size_t) length); objPtr->typePtr = &tclByteArrayType; SET_BYTEARRAY(objPtr, byteArrayPtr); } /* *---------------------------------------------------------------------- * * Tcl_GetByteArrayFromObj -- * * Attempt to get the array of bytes from the Tcl object. If the * object is not already a ByteArray object, an attempt will be * made to convert it to one. * * Results: * Pointer to array of bytes representing the ByteArray object. * * Side effects: * Frees old internal rep. Allocates memory for new internal rep. * *---------------------------------------------------------------------- */ unsigned char * Tcl_GetByteArrayFromObj(objPtr, lengthPtr) Tcl_Obj *objPtr; /* The ByteArray object. */ int *lengthPtr; /* If non-NULL, filled with length of the * array of bytes in the ByteArray object. */ { ByteArray *baPtr; SetByteArrayFromAny(NULL, objPtr); baPtr = GET_BYTEARRAY(objPtr); if (lengthPtr != NULL) { *lengthPtr = baPtr->used; } return (unsigned char *) baPtr->bytes; } /* *---------------------------------------------------------------------- * * Tcl_SetByteArrayLength -- * * This procedure changes the length of the byte array for this * object. Once the caller has set the length of the array, it * is acceptable to directly modify the bytes in the array up until * Tcl_GetStringFromObj() has been called on this object. * * Results: * The new byte array of the specified length. * * Side effects: * Allocates enough memory for an array of bytes of the requested * size. When growing the array, the old array is copied to the * new array; new bytes are undefined. When shrinking, the * old array is truncated to the specified length. * *--------------------------------------------------------------------------- */ unsigned char * Tcl_SetByteArrayLength(objPtr, length) Tcl_Obj *objPtr; /* The ByteArray object. */ int length; /* New length for internal byte array. */ { ByteArray *byteArrayPtr, *newByteArrayPtr; if (Tcl_IsShared(objPtr)) { panic("Tcl_SetObjLength called with shared object"); } if (objPtr->typePtr != &tclByteArrayType) { SetByteArrayFromAny(NULL, objPtr); } byteArrayPtr = GET_BYTEARRAY(objPtr); if (length > byteArrayPtr->allocated) { newByteArrayPtr = (ByteArray *) ckalloc(BYTEARRAY_SIZE(length)); newByteArrayPtr->used = length; newByteArrayPtr->allocated = length; memcpy((VOID *) newByteArrayPtr->bytes, (VOID *) byteArrayPtr->bytes, (size_t) byteArrayPtr->used); ckfree((char *) byteArrayPtr); byteArrayPtr = newByteArrayPtr; SET_BYTEARRAY(objPtr, byteArrayPtr); } Tcl_InvalidateStringRep(objPtr); byteArrayPtr->used = length; return byteArrayPtr->bytes; } /* *--------------------------------------------------------------------------- * * SetByteArrayFromAny -- * * Generate the ByteArray internal rep from the string rep. * * Results: * The return value is always TCL_OK. * * Side effects: * A ByteArray object is stored as the internal rep of objPtr. * *--------------------------------------------------------------------------- */ static int SetByteArrayFromAny(interp, objPtr) Tcl_Interp *interp; /* Not used. */ Tcl_Obj *objPtr; /* The object to convert to type ByteArray. */ { Tcl_ObjType *typePtr; int length; char *src, *srcEnd; unsigned char *dst; ByteArray *byteArrayPtr; Tcl_UniChar ch; typePtr = objPtr->typePtr; if (typePtr != &tclByteArrayType) { src = Tcl_GetStringFromObj(objPtr, &length); srcEnd = src + length; byteArrayPtr = (ByteArray *) ckalloc(BYTEARRAY_SIZE(length)); for (dst = byteArrayPtr->bytes; src < srcEnd; ) { src += Tcl_UtfToUniChar(src, &ch); *dst++ = (unsigned char) ch; } byteArrayPtr->used = dst - byteArrayPtr->bytes; byteArrayPtr->allocated = length; if ((typePtr != NULL) && (typePtr->freeIntRepProc) != NULL) { (*typePtr->freeIntRepProc)(objPtr); } objPtr->typePtr = &tclByteArrayType; SET_BYTEARRAY(objPtr, byteArrayPtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * FreeByteArrayInternalRep -- * * Deallocate the storage associated with a ByteArray data object's * internal representation. * * Results: * None. * * Side effects: * Frees memory. * *---------------------------------------------------------------------- */ static void FreeByteArrayInternalRep(objPtr) Tcl_Obj *objPtr; /* Object with internal rep to free. */ { ckfree((char *) GET_BYTEARRAY(objPtr)); } /* *--------------------------------------------------------------------------- * * DupByteArrayInternalRep -- * * Initialize the internal representation of a ByteArray Tcl_Obj * to a copy of the internal representation of an existing ByteArray * object. * * Results: * None. * * Side effects: * Allocates memory. * *--------------------------------------------------------------------------- */ static void DupByteArrayInternalRep(srcPtr, copyPtr) Tcl_Obj *srcPtr; /* Object with internal rep to copy. */ Tcl_Obj *copyPtr; /* Object with internal rep to set. */ { int length; ByteArray *srcArrayPtr, *copyArrayPtr; srcArrayPtr = GET_BYTEARRAY(srcPtr); length = srcArrayPtr->used; copyArrayPtr = (ByteArray *) ckalloc(BYTEARRAY_SIZE(length)); copyArrayPtr->used = length; copyArrayPtr->allocated = length; memcpy((VOID *) copyArrayPtr->bytes, (VOID *) srcArrayPtr->bytes, (size_t) length); SET_BYTEARRAY(copyPtr, copyArrayPtr); copyPtr->typePtr = &tclByteArrayType; } /* *--------------------------------------------------------------------------- * * UpdateStringOfByteArray -- * * Update the string representation for a ByteArray data object. * Note: This procedure does not invalidate an existing old string rep * so storage will be lost if this has not already been done. * * Results: * None. * * Side effects: * The object's string is set to a valid string that results from * the ByteArray-to-string conversion. * * The object becomes a string object -- the internal rep is * discarded and the typePtr becomes NULL. * *--------------------------------------------------------------------------- */ static void UpdateStringOfByteArray(objPtr) Tcl_Obj *objPtr; /* ByteArray object whose string rep to * update. */ { int i, length, size; unsigned char *src; char *dst; ByteArray *byteArrayPtr; byteArrayPtr = GET_BYTEARRAY(objPtr); src = byteArrayPtr->bytes; length = byteArrayPtr->used; /* * How much space will string rep need? */ size = length; for (i = 0; i < length; i++) { if ((src[i] == 0) || (src[i] > 127)) { size++; } } dst = (char *) ckalloc((unsigned) (size + 1)); objPtr->bytes = dst; objPtr->length = size; if (size == length) { memcpy((VOID *) dst, (VOID *) src, (size_t) size); dst[size] = '\0'; } else { for (i = 0; i < length; i++) { dst += Tcl_UniCharToUtf(src[i], dst); } *dst = '\0'; } } /* *---------------------------------------------------------------------- * * Tcl_BinaryObjCmd -- * * This procedure implements the "binary" Tcl command. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ int Tcl_BinaryObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int arg; /* Index of next argument to consume. */ int value = 0; /* Current integer value to be packed. * Initialized to avoid compiler warning. */ char cmd; /* Current format character. */ int count; /* Count associated with current format * character. */ char *format; /* Pointer to current position in format * string. */ Tcl_Obj *resultPtr; /* Object holding result buffer. */ unsigned char *buffer; /* Start of result buffer. */ unsigned char *cursor; /* Current position within result buffer. */ unsigned char *maxPos; /* Greatest position within result buffer that * cursor has visited.*/ char *errorString, *errorValue, *str; int offset, size, length, index; static CONST char *options[] = { "format", "scan", NULL }; enum options { BINARY_FORMAT, BINARY_SCAN }; if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[1], options, "option", 0, &index) != TCL_OK) { return TCL_ERROR; } switch ((enum options) index) { case BINARY_FORMAT: { if (objc < 3) { Tcl_WrongNumArgs(interp, 2, objv, "formatString ?arg arg ...?"); return TCL_ERROR; } /* * To avoid copying the data, we format the string in two passes. * The first pass computes the size of the output buffer. The * second pass places the formatted data into the buffer. */ format = Tcl_GetString(objv[2]); arg = 3; offset = 0; length = 0; while (*format != '\0') { str = format; if (!GetFormatSpec(&format, &cmd, &count)) { break; } switch (cmd) { case 'a': case 'A': case 'b': case 'B': case 'h': case 'H': { /* * For string-type specifiers, the count corresponds * to the number of bytes in a single argument. */ if (arg >= objc) { goto badIndex; } if (count == BINARY_ALL) { Tcl_GetByteArrayFromObj(objv[arg], &count); } else if (count == BINARY_NOCOUNT) { count = 1; } arg++; if (cmd == 'a' || cmd == 'A') { offset += count; } else if (cmd == 'b' || cmd == 'B') { offset += (count + 7) / 8; } else { offset += (count + 1) / 2; } break; } case 'c': { size = 1; goto doNumbers; } case 's': case 'S': { size = 2; goto doNumbers; } case 'i': case 'I': { size = 4; goto doNumbers; } case 'w': case 'W': { size = 8; goto doNumbers; } case 'f': { size = sizeof(float); goto doNumbers; } case 'd': { size = sizeof(double); doNumbers: if (arg >= objc) { goto badIndex; } /* * For number-type specifiers, the count corresponds * to the number of elements in the list stored in * a single argument. If no count is specified, then * the argument is taken as a single non-list value. */ if (count == BINARY_NOCOUNT) { arg++; count = 1; } else { int listc; Tcl_Obj **listv; if (Tcl_ListObjGetElements(interp, objv[arg++], &listc, &listv) != TCL_OK) { return TCL_ERROR; } if (count == BINARY_ALL) { count = listc; } else if (count > listc) { Tcl_AppendResult(interp, "number of elements in list does not match count", (char *) NULL); return TCL_ERROR; } } offset += count*size; break; } case 'x': { if (count == BINARY_ALL) { Tcl_AppendResult(interp, "cannot use \"*\" in format string with \"x\"", (char *) NULL); return TCL_ERROR; } else if (count == BINARY_NOCOUNT) { count = 1; } offset += count; break; } case 'X': { if (count == BINARY_NOCOUNT) { count = 1; } if ((count > offset) || (count == BINARY_ALL)) { count = offset; } if (offset > length) { length = offset; } offset -= count; break; } case '@': { if (offset > length) { length = offset; } if (count == BINARY_ALL) { offset = length; } else if (count == BINARY_NOCOUNT) { goto badCount; } else { offset = count; } break; } default: { errorString = str; goto badField; } } } if (offset > length) { length = offset; } if (length == 0) { return TCL_OK; } /* * Prepare the result object by preallocating the caclulated * number of bytes and filling with nulls. */ resultPtr = Tcl_GetObjResult(interp); if (Tcl_IsShared(resultPtr)) { TclNewObj(resultPtr); Tcl_SetObjResult(interp, resultPtr); } buffer = Tcl_SetByteArrayLength(resultPtr, length); memset((VOID *) buffer, 0, (size_t) length); /* * Pack the data into the result object. Note that we can skip * the error checking during this pass, since we have already * parsed the string once. */ arg = 3; format = Tcl_GetString(objv[2]); cursor = buffer; maxPos = cursor; while (*format != 0) { if (!GetFormatSpec(&format, &cmd, &count)) { break; } if ((count == 0) && (cmd != '@')) { if (cmd != 'x') { arg++; } continue; } switch (cmd) { case 'a': case 'A': { char pad = (char) (cmd == 'a' ? '\0' : ' '); unsigned char *bytes; bytes = Tcl_GetByteArrayFromObj(objv[arg++], &length); if (count == BINARY_ALL) { count = length; } else if (count == BINARY_NOCOUNT) { count = 1; } if (length >= count) { memcpy((VOID *) cursor, (VOID *) bytes, (size_t) count); } else { memcpy((VOID *) cursor, (VOID *) bytes, (size_t) length); memset((VOID *) (cursor + length), pad, (size_t) (count - length)); } cursor += count; break; } case 'b': case 'B': { unsigned char *last; str = Tcl_GetStringFromObj(objv[arg++], &length); if (count == BINARY_ALL) { count = length; } else if (count == BINARY_NOCOUNT) { count = 1; } last = cursor + ((count + 7) / 8); if (count > length) { count = length; } value = 0; errorString = "binary"; if (cmd == 'B') { for (offset = 0; offset < count; offset++) { value <<= 1; if (str[offset] == '1') { value |= 1; } else if (str[offset] != '0') { errorValue = str; goto badValue; } if (((offset + 1) % 8) == 0) { *cursor++ = (unsigned char) value; value = 0; } } } else { for (offset = 0; offset < count; offset++) { value >>= 1; if (str[offset] == '1') { value |= 128; } else if (str[offset] != '0') { errorValue = str; goto badValue; } if (!((offset + 1) % 8)) { *cursor++ = (unsigned char) value; value = 0; } } } if ((offset % 8) != 0) { if (cmd == 'B') { value <<= 8 - (offset % 8); } else { value >>= 8 - (offset % 8); } *cursor++ = (unsigned char) value; } while (cursor < last) { *cursor++ = '\0'; } break; } case 'h': case 'H': { unsigned char *last; int c; str = Tcl_GetStringFromObj(objv[arg++], &length); if (count == BINARY_ALL) { count = length; } else if (count == BINARY_NOCOUNT) { count = 1; } last = cursor + ((count + 1) / 2); if (count > length) { count = length; } value = 0; errorString = "hexadecimal"; if (cmd == 'H') { for (offset = 0; offset < count; offset++) { value <<= 4; if (!isxdigit(UCHAR(str[offset]))) { /* INTL: digit */ errorValue = str; goto badValue; } c = str[offset] - '0'; if (c > 9) { c += ('0' - 'A') + 10; } if (c > 16) { c += ('A' - 'a'); } value |= (c & 0xf); if (offset % 2) { *cursor++ = (char) value; value = 0; } } } else { for (offset = 0; offset < count; offset++) { value >>= 4; if (!isxdigit(UCHAR(str[offset]))) { /* INTL: digit */ errorValue = str; goto badValue; } c = str[offset] - '0'; if (c > 9) { c += ('0' - 'A') + 10; } if (c > 16) { c += ('A' - 'a'); } value |= ((c << 4) & 0xf0); if (offset % 2) { *cursor++ = (unsigned char)(value & 0xff); value = 0; } } } if (offset % 2) { if (cmd == 'H') { value <<= 4; } else { value >>= 4; } *cursor++ = (unsigned char) value; } while (cursor < last) { *cursor++ = '\0'; } break; } case 'c': case 's': case 'S': case 'i': case 'I': case 'w': case 'W': case 'd': case 'f': { int listc, i; Tcl_Obj **listv; if (count == BINARY_NOCOUNT) { /* * Note that we are casting away the const-ness of * objv, but this is safe since we aren't going to * modify the array. */ listv = (Tcl_Obj**)(objv + arg); listc = 1; count = 1; } else { Tcl_ListObjGetElements(interp, objv[arg], &listc, &listv); if (count == BINARY_ALL) { count = listc; } } arg++; for (i = 0; i < count; i++) { if (FormatNumber(interp, cmd, listv[i], &cursor) != TCL_OK) { return TCL_ERROR; } } break; } case 'x': { if (count == BINARY_NOCOUNT) { count = 1; } memset(cursor, 0, (size_t) count); cursor += count; break; } case 'X': { if (cursor > maxPos) { maxPos = cursor; } if (count == BINARY_NOCOUNT) { count = 1; } if ((count == BINARY_ALL) || (count > (cursor - buffer))) { cursor = buffer; } else { cursor -= count; } break; } case '@': { if (cursor > maxPos) { maxPos = cursor; } if (count == BINARY_ALL) { cursor = maxPos; } else { cursor = buffer + count; } break; } } } break; } case BINARY_SCAN: { int i; Tcl_Obj *valuePtr, *elementPtr; Tcl_HashTable numberCacheHash; Tcl_HashTable *numberCachePtr; if (objc < 4) { Tcl_WrongNumArgs(interp, 2, objv, "value formatString ?varName varName ...?"); return TCL_ERROR; } numberCachePtr = &numberCacheHash; Tcl_InitHashTable(numberCachePtr, TCL_ONE_WORD_KEYS); buffer = Tcl_GetByteArrayFromObj(objv[2], &length); format = Tcl_GetString(objv[3]); cursor = buffer; arg = 4; offset = 0; while (*format != '\0') { str = format; if (!GetFormatSpec(&format, &cmd, &count)) { goto done; } switch (cmd) { case 'a': case 'A': { unsigned char *src; if (arg >= objc) { DeleteScanNumberCache(numberCachePtr); goto badIndex; } if (count == BINARY_ALL) { count = length - offset; } else { if (count == BINARY_NOCOUNT) { count = 1; } if (count > (length - offset)) { goto done; } } src = buffer + offset; size = count; /* * Trim trailing nulls and spaces, if necessary. */ if (cmd == 'A') { while (size > 0) { if (src[size-1] != '\0' && src[size-1] != ' ') { break; } size--; } } valuePtr = Tcl_NewByteArrayObj(src, size); Tcl_IncrRefCount(valuePtr); resultPtr = Tcl_ObjSetVar2(interp, objv[arg], NULL, valuePtr, TCL_LEAVE_ERR_MSG); Tcl_DecrRefCount(valuePtr); arg++; if (resultPtr == NULL) { DeleteScanNumberCache(numberCachePtr); return TCL_ERROR; } offset += count; break; } case 'b': case 'B': { unsigned char *src; char *dest; if (arg >= objc) { DeleteScanNumberCache(numberCachePtr); goto badIndex; } if (count == BINARY_ALL) { count = (length - offset) * 8; } else { if (count == BINARY_NOCOUNT) { count = 1; } if (count > (length - offset) * 8) { goto done; } } src = buffer + offset; valuePtr = Tcl_NewObj(); Tcl_SetObjLength(valuePtr, count); dest = Tcl_GetString(valuePtr); if (cmd == 'b') { for (i = 0; i < count; i++) { if (i % 8) { value >>= 1; } else { value = *src++; } *dest++ = (char) ((value & 1) ? '1' : '0'); } } else { for (i = 0; i < count; i++) { if (i % 8) { value <<= 1; } else { value = *src++; } *dest++ = (char) ((value & 0x80) ? '1' : '0'); } } Tcl_IncrRefCount(valuePtr); resultPtr = Tcl_ObjSetVar2(interp, objv[arg], NULL, valuePtr, TCL_LEAVE_ERR_MSG); Tcl_DecrRefCount(valuePtr); arg++; if (resultPtr == NULL) { DeleteScanNumberCache(numberCachePtr); return TCL_ERROR; } offset += (count + 7 ) / 8; break; } case 'h': case 'H': { char *dest; unsigned char *src; int i; static CONST char hexdigit[] = "0123456789abcdef"; if (arg >= objc) { DeleteScanNumberCache(numberCachePtr); goto badIndex; } if (count == BINARY_ALL) { count = (length - offset)*2; } else { if (count == BINARY_NOCOUNT) { count = 1; } if (count > (length - offset)*2) { goto done; } } src = buffer + offset; valuePtr = Tcl_NewObj(); Tcl_SetObjLength(valuePtr, count); dest = Tcl_GetString(valuePtr); if (cmd == 'h') { for (i = 0; i < count; i++) { if (i % 2) { value >>= 4; } else { value = *src++; } *dest++ = hexdigit[value & 0xf]; } } else { for (i = 0; i < count; i++) { if (i % 2) { value <<= 4; } else { value = *src++; } *dest++ = hexdigit[(value >> 4) & 0xf]; } } Tcl_IncrRefCount(valuePtr); resultPtr = Tcl_ObjSetVar2(interp, objv[arg], NULL, valuePtr, TCL_LEAVE_ERR_MSG); Tcl_DecrRefCount(valuePtr); arg++; if (resultPtr == NULL) { DeleteScanNumberCache(numberCachePtr); return TCL_ERROR; } offset += (count + 1) / 2; break; } case 'c': { size = 1; goto scanNumber; } case 's': case 'S': { size = 2; goto scanNumber; } case 'i': case 'I': { size = 4; goto scanNumber; } case 'w': case 'W': { size = 8; goto scanNumber; } case 'f': { size = sizeof(float); goto scanNumber; } case 'd': { unsigned char *src; size = sizeof(double); /* fall through */ scanNumber: if (arg >= objc) { DeleteScanNumberCache(numberCachePtr); goto badIndex; } if (count == BINARY_NOCOUNT) { if ((length - offset) < size) { goto done; } valuePtr = ScanNumber(buffer+offset, cmd, &numberCachePtr); offset += size; } else { if (count == BINARY_ALL) { count = (length - offset) / size; } if ((length - offset) < (count * size)) { goto done; } valuePtr = Tcl_NewObj(); src = buffer+offset; for (i = 0; i < count; i++) { elementPtr = ScanNumber(src, cmd, &numberCachePtr); src += size; Tcl_ListObjAppendElement(NULL, valuePtr, elementPtr); } offset += count*size; } Tcl_IncrRefCount(valuePtr); resultPtr = Tcl_ObjSetVar2(interp, objv[arg], NULL, valuePtr, TCL_LEAVE_ERR_MSG); Tcl_DecrRefCount(valuePtr); arg++; if (resultPtr == NULL) { DeleteScanNumberCache(numberCachePtr); return TCL_ERROR; } break; } case 'x': { if (count == BINARY_NOCOUNT) { count = 1; } if ((count == BINARY_ALL) || (count > (length - offset))) { offset = length; } else { offset += count; } break; } case 'X': { if (count == BINARY_NOCOUNT) { count = 1; } if ((count == BINARY_ALL) || (count > offset)) { offset = 0; } else { offset -= count; } break; } case '@': { if (count == BINARY_NOCOUNT) { DeleteScanNumberCache(numberCachePtr); goto badCount; } if ((count == BINARY_ALL) || (count > length)) { offset = length; } else { offset = count; } break; } default: { DeleteScanNumberCache(numberCachePtr); errorString = str; goto badField; } } } /* * Set the result to the last position of the cursor. */ done: Tcl_ResetResult(interp); Tcl_SetLongObj(Tcl_GetObjResult(interp), arg - 4); DeleteScanNumberCache(numberCachePtr); break; } } return TCL_OK; badValue: Tcl_ResetResult(interp); Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "expected ", errorString, " string but got \"", errorValue, "\" instead", NULL); return TCL_ERROR; badCount: errorString = "missing count for \"@\" field specifier"; goto error; badIndex: errorString = "not enough arguments for all format specifiers"; goto error; badField: { Tcl_UniChar ch; char buf[TCL_UTF_MAX + 1]; Tcl_UtfToUniChar(errorString, &ch); buf[Tcl_UniCharToUtf(ch, buf)] = '\0'; Tcl_AppendResult(interp, "bad field specifier \"", buf, "\"", NULL); return TCL_ERROR; } error: Tcl_AppendResult(interp, errorString, NULL); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * GetFormatSpec -- * * This function parses the format strings used in the binary * format and scan commands. * * Results: * Moves the formatPtr to the start of the next command. Returns * the current command character and count in cmdPtr and countPtr. * The count is set to BINARY_ALL if the count character was '*' * or BINARY_NOCOUNT if no count was specified. Returns 1 on * success, or 0 if the string did not have a format specifier. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int GetFormatSpec(formatPtr, cmdPtr, countPtr) char **formatPtr; /* Pointer to format string. */ char *cmdPtr; /* Pointer to location of command char. */ int *countPtr; /* Pointer to repeat count value. */ { /* * Skip any leading blanks. */ while (**formatPtr == ' ') { (*formatPtr)++; } /* * The string was empty, except for whitespace, so fail. */ if (!(**formatPtr)) { return 0; } /* * Extract the command character and any trailing digits or '*'. */ *cmdPtr = **formatPtr; (*formatPtr)++; if (**formatPtr == '*') { (*formatPtr)++; (*countPtr) = BINARY_ALL; } else if (isdigit(UCHAR(**formatPtr))) { /* INTL: digit */ (*countPtr) = strtoul(*formatPtr, formatPtr, 10); } else { (*countPtr) = BINARY_NOCOUNT; } return 1; } /* *---------------------------------------------------------------------- * * FormatNumber -- * * This routine is called by Tcl_BinaryObjCmd to format a number * into a location pointed at by cursor. * * Results: * A standard Tcl result. * * Side effects: * Moves the cursor to the next location to be written into. * *---------------------------------------------------------------------- */ static int FormatNumber(interp, type, src, cursorPtr) Tcl_Interp *interp; /* Current interpreter, used to report * errors. */ int type; /* Type of number to format. */ Tcl_Obj *src; /* Number to format. */ unsigned char **cursorPtr; /* Pointer to index into destination buffer. */ { long value; double dvalue; Tcl_WideInt wvalue; switch (type) { case 'd': case 'f': /* * For floating point types, we need to copy the data using * memcpy to avoid alignment issues. */ if (Tcl_GetDoubleFromObj(interp, src, &dvalue) != TCL_OK) { return TCL_ERROR; } if (type == 'd') { /* * Can't just memcpy() here. [Bug 1116542] */ CopyNumber(&dvalue, *cursorPtr, sizeof(double)); *cursorPtr += sizeof(double); } else { float fvalue; /* * Because some compilers will generate floating point exceptions * on an overflow cast (e.g. Borland), we restrict the values * to the valid range for float. */ if (fabs(dvalue) > (double)FLT_MAX) { fvalue = (dvalue >= 0.0) ? FLT_MAX : -FLT_MAX; } else { fvalue = (float) dvalue; } memcpy((VOID *) *cursorPtr, (VOID *) &fvalue, sizeof(float)); *cursorPtr += sizeof(float); } return TCL_OK; /* * Next cases separate from other integer cases because we * need a different API to get a wide. */ case 'w': case 'W': if (Tcl_GetWideIntFromObj(interp, src, &wvalue) != TCL_OK) { return TCL_ERROR; } if (type == 'w') { *(*cursorPtr)++ = (unsigned char) wvalue; *(*cursorPtr)++ = (unsigned char) (wvalue >> 8); *(*cursorPtr)++ = (unsigned char) (wvalue >> 16); *(*cursorPtr)++ = (unsigned char) (wvalue >> 24); *(*cursorPtr)++ = (unsigned char) (wvalue >> 32); *(*cursorPtr)++ = (unsigned char) (wvalue >> 40); *(*cursorPtr)++ = (unsigned char) (wvalue >> 48); *(*cursorPtr)++ = (unsigned char) (wvalue >> 56); } else { *(*cursorPtr)++ = (unsigned char) (wvalue >> 56); *(*cursorPtr)++ = (unsigned char) (wvalue >> 48); *(*cursorPtr)++ = (unsigned char) (wvalue >> 40); *(*cursorPtr)++ = (unsigned char) (wvalue >> 32); *(*cursorPtr)++ = (unsigned char) (wvalue >> 24); *(*cursorPtr)++ = (unsigned char) (wvalue >> 16); *(*cursorPtr)++ = (unsigned char) (wvalue >> 8); *(*cursorPtr)++ = (unsigned char) wvalue; } return TCL_OK; default: if (Tcl_GetLongFromObj(interp, src, &value) != TCL_OK) { return TCL_ERROR; } if (type == 'c') { *(*cursorPtr)++ = (unsigned char) value; } else if (type == 's') { *(*cursorPtr)++ = (unsigned char) value; *(*cursorPtr)++ = (unsigned char) (value >> 8); } else if (type == 'S') { *(*cursorPtr)++ = (unsigned char) (value >> 8); *(*cursorPtr)++ = (unsigned char) value; } else if (type == 'i') { *(*cursorPtr)++ = (unsigned char) value; *(*cursorPtr)++ = (unsigned char) (value >> 8); *(*cursorPtr)++ = (unsigned char) (value >> 16); *(*cursorPtr)++ = (unsigned char) (value >> 24); } else if (type == 'I') { *(*cursorPtr)++ = (unsigned char) (value >> 24); *(*cursorPtr)++ = (unsigned char) (value >> 16); *(*cursorPtr)++ = (unsigned char) (value >> 8); *(*cursorPtr)++ = (unsigned char) value; } return TCL_OK; } } /* Ugly workaround for old and broken compiler! */ static void CopyNumber(from, to, length) CONST VOID *from; VOID *to; unsigned int length; { memcpy(to, from, length); } /* *---------------------------------------------------------------------- * * ScanNumber -- * * This routine is called by Tcl_BinaryObjCmd to scan a number * out of a buffer. * * Results: * Returns a newly created object containing the scanned number. * This object has a ref count of zero. * * Side effects: * Might reuse an object in the number cache, place a new object * in the cache, or delete the cache and set the reference to * it (itself passed in by reference) to NULL. * *---------------------------------------------------------------------- */ static Tcl_Obj * ScanNumber(buffer, type, numberCachePtrPtr) unsigned char *buffer; /* Buffer to scan number from. */ int type; /* Format character from "binary scan" */ Tcl_HashTable **numberCachePtrPtr; /* Place to look for cache of scanned * value objects, or NULL if too many * different numbers have been scanned. */ { long value; Tcl_WideUInt uwvalue; /* * We cannot rely on the compiler to properly sign extend integer values * when we cast from smaller values to larger values because we don't know * the exact size of the integer types. So, we have to handle sign * extension explicitly by checking the high bit and padding with 1's as * needed. */ switch (type) { case 'c': /* * Characters need special handling. We want to produce a * signed result, but on some platforms (such as AIX) chars * are unsigned. To deal with this, check for a value that * should be negative but isn't. */ value = buffer[0]; if (value & 0x80) { value |= -0x100; } goto returnNumericObject; case 's': value = (long) (buffer[0] + (buffer[1] << 8)); goto shortValue; case 'S': value = (long) (buffer[1] + (buffer[0] << 8)); shortValue: if (value & 0x8000) { value |= -0x10000; } goto returnNumericObject; case 'i': value = (long) (buffer[0] + (buffer[1] << 8) + (buffer[2] << 16) + (buffer[3] << 24)); goto intValue; case 'I': value = (long) (buffer[3] + (buffer[2] << 8) + (buffer[1] << 16) + (buffer[0] << 24)); intValue: /* * Check to see if the value was sign extended properly on * systems where an int is more than 32-bits. */ if ((value & (((unsigned int)1)<<31)) && (value > 0)) { value -= (((unsigned int)1)<<31); value -= (((unsigned int)1)<<31); } returnNumericObject: if (*numberCachePtrPtr == NULL) { return Tcl_NewLongObj(value); } else { register Tcl_HashTable *tablePtr = *numberCachePtrPtr; register Tcl_HashEntry *hPtr; int isNew; hPtr = Tcl_CreateHashEntry(tablePtr, (char *)value, &isNew); if (!isNew) { return (Tcl_Obj *) Tcl_GetHashValue(hPtr); } if (tablePtr->numEntries > BINARY_SCAN_MAX_CACHE) { /* * We've overflowed the cache! Someone's parsing * a LOT of varied binary data in a single call! * Bail out by switching back to the old behaviour * for the rest of the scan. * * Note that anyone just using the 'c' conversion * (for bytes) cannot trigger this. */ DeleteScanNumberCache(tablePtr); *numberCachePtrPtr = NULL; return Tcl_NewLongObj(value); } else { register Tcl_Obj *objPtr = Tcl_NewLongObj(value); Tcl_IncrRefCount(objPtr); Tcl_SetHashValue(hPtr, (ClientData) objPtr); return objPtr; } } /* * Do not cache wide values; they are already too large to * use as keys. */ case 'w': uwvalue = ((Tcl_WideUInt) buffer[0]) | (((Tcl_WideUInt) buffer[1]) << 8) | (((Tcl_WideUInt) buffer[2]) << 16) | (((Tcl_WideUInt) buffer[3]) << 24) | (((Tcl_WideUInt) buffer[4]) << 32) | (((Tcl_WideUInt) buffer[5]) << 40) | (((Tcl_WideUInt) buffer[6]) << 48) | (((Tcl_WideUInt) buffer[7]) << 56); return Tcl_NewWideIntObj((Tcl_WideInt) uwvalue); case 'W': uwvalue = ((Tcl_WideUInt) buffer[7]) | (((Tcl_WideUInt) buffer[6]) << 8) | (((Tcl_WideUInt) buffer[5]) << 16) | (((Tcl_WideUInt) buffer[4]) << 24) | (((Tcl_WideUInt) buffer[3]) << 32) | (((Tcl_WideUInt) buffer[2]) << 40) | (((Tcl_WideUInt) buffer[1]) << 48) | (((Tcl_WideUInt) buffer[0]) << 56); return Tcl_NewWideIntObj((Tcl_WideInt) uwvalue); /* * Do not cache double values; they are already too large * to use as keys and the values stored are utterly * incompatible too. */ case 'f': { float fvalue; memcpy((VOID *) &fvalue, (VOID *) buffer, sizeof(float)); return Tcl_NewDoubleObj(fvalue); } case 'd': { double dvalue; memcpy((VOID *) &dvalue, (VOID *) buffer, sizeof(double)); return Tcl_NewDoubleObj(dvalue); } } return NULL; } /* *---------------------------------------------------------------------- * * DeleteScanNumberCache -- * * Deletes the hash table acting as a scan number cache. * * Results: * None * * Side effects: * Decrements the reference counts of the objects in the cache. * *---------------------------------------------------------------------- */ static void DeleteScanNumberCache(numberCachePtr) Tcl_HashTable *numberCachePtr; /* Pointer to the hash table, or * NULL (when the cache has already * been deleted due to overflow.) */ { Tcl_HashEntry *hEntry; Tcl_HashSearch search; if (numberCachePtr == NULL) { return; } hEntry = Tcl_FirstHashEntry(numberCachePtr, &search); while (hEntry != NULL) { register Tcl_Obj *value = (Tcl_Obj *) Tcl_GetHashValue(hEntry); if (value != NULL) { Tcl_DecrRefCount(value); } hEntry = Tcl_NextHashEntry(&search); } Tcl_DeleteHashTable(numberCachePtr); } tcl8.4.20/doc/0000755003604700454610000000000012153151142011445 5ustar dgp771divtcl8.4.20/doc/UpVar.30000644003604700454610000000537711737050674012621 0ustar dgp771div'\" '\" Copyright (c) 1994 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_UpVar 3 7.4 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_UpVar, Tcl_UpVar2 \- link one variable to another .SH SYNOPSIS .nf \fB#include \fR .sp int \fBTcl_UpVar(\fIinterp, frameName, sourceName, destName, flags\fB)\fR .sp int \fBTcl_UpVar2(\fIinterp, frameName, name1, name2, destName, flags\fB)\fR .SH ARGUMENTS .AS Tcl_VarTraceProc prevClientData .AP Tcl_Interp *interp in Interpreter containing variables; also used for error reporting. .AP "CONST char" *frameName in Identifies the stack frame containing source variable. May have any of the forms accepted by the \fBupvar\fR command, such as \fB#0\fR or \fB1\fR. .AP "CONST char" *sourceName in Name of source variable, in the frame given by \fIframeName\fR. May refer to a scalar variable or to an array variable with a parenthesized index. .AP "CONST char" *destName in Name of destination variable, which is to be linked to source variable so that references to \fIdestName\fR refer to the other variable. Must not currently exist except as an upvar-ed variable. .AP int flags in Either TCL_GLOBAL_ONLY or 0; if non-zero, then \fIdestName\fR is a global variable; otherwise it is a local to the current procedure (or global if no procedure is active). .AP "CONST char" *name1 in First part of source variable's name (scalar name, or name of array without array index). .AP "CONST char" *name2 in If source variable is an element of an array, gives the index of the element. For scalar source variables, is NULL. .BE .SH DESCRIPTION .PP \fBTcl_UpVar\fR and \fBTcl_UpVar2\fR provide the same functionality as the \fBupvar\fR command: they make a link from a source variable to a destination variable, so that references to the destination are passed transparently through to the source. The name of the source variable may be specified either as a single string such as \fBxyx\fR or \fBa(24)\fR (by calling \fBTcl_UpVar\fR) or in two parts where the array name has been separated from the element name (by calling \fBTcl_UpVar2\fR). The destination variable name is specified in a single string; it may not be an array element. .PP Both procedures return either TCL_OK or TCL_ERROR, and they leave an error message in the interpreter's result if an error occurs. .PP As with the \fBupvar\fR command, the source variable need not exist; if it does exist, unsetting it later does not destroy the link. The destination variable may exist at the time of the call, but if so it must exist as a linked variable. .SH KEYWORDS linked variable, upvar, variable tcl8.4.20/doc/tclsh.10000644003604700454610000001317011737050674012665 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH tclsh 1 "" Tcl "Tcl Applications" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME tclsh \- Simple shell containing Tcl interpreter .SH SYNOPSIS \fBtclsh\fR ?\fIfileName arg arg ...\fR? .BE .SH DESCRIPTION .PP \fBTclsh\fR is a shell-like application that reads Tcl commands from its standard input or from a file and evaluates them. If invoked with no arguments then it runs interactively, reading Tcl commands from standard input and printing command results and error messages to standard output. It runs until the \fBexit\fR command is invoked or until it reaches end-of-file on its standard input. If there exists a file \fB.tclshrc\fR (or \fBtclshrc.tcl\fR on the Windows platforms) in the home directory of the user, \fBtclsh\fR evaluates the file as a Tcl script just before reading the first command from standard input. .SH "SCRIPT FILES" .PP If \fBtclsh\fR is invoked with arguments then the first argument is the name of a script file and any additional arguments are made available to the script as variables (see below). Instead of reading commands from standard input \fBtclsh\fR will read Tcl commands from the named file; \fBtclsh\fR will exit when it reaches the end of the file. .VS 8.4 The end of the file may be marked either by the physical end of the medium, or by the character, '\\032' ('\\u001a', control-Z). If this character is present in the file, the \fBtclsh\fR application will read text up to but not including the character. An application that requires this character in the file may safely encode it as ``\\032'', ``\\x1a'', or ``\\u001a''; or may generate it by use of commands such as \fBformat\fR or \fBbinary\fR. .VE There is no automatic evaluation of \fB.tclshrc\fR when the name of a script file is presented on the \fBtclsh\fR command line, but the script file can always \fBsource\fR it if desired. .PP If you create a Tcl script in a file whose first line is .CS \fB#!/usr/local/bin/tclsh\fR .CE then you can invoke the script file directly from your shell if you mark the file as executable. This assumes that \fBtclsh\fR has been installed in the default location in /usr/local/bin; if it's installed somewhere else then you'll have to modify the above line to match. Many UNIX systems do not allow the \fB#!\fR line to exceed about 30 characters in length, so be sure that the \fBtclsh\fR executable can be accessed with a short file name. .PP An even better approach is to start your script files with the following three lines: .CS \fB#!/bin/sh # the next line restarts using tclsh \e exec tclsh "$0" ${1+"$@"}\fR .CE This approach has three advantages over the approach in the previous paragraph. First, the location of the \fBtclsh\fR binary doesn't have to be hard-wired into the script: it can be anywhere in your shell search path. Second, it gets around the 30-character file name limit in the previous approach. Third, this approach will work even if \fBtclsh\fR is itself a shell script (this is done on some systems in order to handle multiple architectures or operating systems: the \fBtclsh\fR script selects one of several binaries to run). The three lines cause both \fBsh\fR and \fBtclsh\fR to process the script, but the \fBexec\fR is only executed by \fBsh\fR. \fBsh\fR processes the script first; it treats the second line as a comment and executes the third line. The \fBexec\fR statement cause the shell to stop processing and instead to start up \fBtclsh\fR to reprocess the entire script. When \fBtclsh\fR starts up, it treats all three lines as comments, since the backslash at the end of the second line causes the third line to be treated as part of the comment on the second line. .PP .VS You should note that it is also common practise to install tclsh with its version number as part of the name. This has the advantage of allowing multiple versions of Tcl to exist on the same system at once, but also the disadvantage of making it harder to write scripts that start up uniformly across different versions of Tcl. .VE .SH "VARIABLES" .PP \fBTclsh\fR sets the following Tcl variables: .TP 15 \fBargc\fR Contains a count of the number of \fIarg\fR arguments (0 if none), not including the name of the script file. .TP 15 \fBargv\fR Contains a Tcl list whose elements are the \fIarg\fR arguments, in order, or an empty string if there are no \fIarg\fR arguments. .TP 15 \fBargv0\fR Contains \fIfileName\fR if it was specified. Otherwise, contains the name by which \fBtclsh\fR was invoked. .TP 15 \fBtcl_interactive\fR Contains 1 if \fBtclsh\fR is running interactively (no \fIfileName\fR was specified and standard input is a terminal-like device), 0 otherwise. .SH PROMPTS .PP When \fBtclsh\fR is invoked interactively it normally prompts for each command with ``\fB% \fR''. You can change the prompt by setting the variables \fBtcl_prompt1\fR and \fBtcl_prompt2\fR. If variable \fBtcl_prompt1\fR exists then it must consist of a Tcl script to output a prompt; instead of outputting a prompt \fBtclsh\fR will evaluate the script in \fBtcl_prompt1\fR. The variable \fBtcl_prompt2\fR is used in a similar way when a newline is typed but the current command isn't yet complete; if \fBtcl_prompt2\fR isn't set then no prompt is output for incomplete commands. .SH "STANDARD CHANNELS" .PP See \fBTcl_StandardChannels\fR for more explanations. .SH "SEE ALSO" fconfigure(n), tclvars(n) .SH KEYWORDS argument, interpreter, prompt, script file, shell tcl8.4.20/doc/global.n0000644003604700454610000000325011737050674013103 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH global n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME global \- Access global variables .SH SYNOPSIS \fBglobal \fIvarname \fR?\fIvarname ...\fR? .BE .SH DESCRIPTION .PP This command has no effect unless executed in the context of a proc body. If the \fBglobal\fR command is executed in the context of a proc body, it creates local variables linked to the corresponding global variables (though these linked variables, like those created by \fBupvar\fR, are not included in the list returned by \fBinfo locals\fR). .PP If \fIvarname\fR contains namespace qualifiers, the local variable's name is the unqualified name of the global variable, as determined by the \fBnamespace tail\fR command. .SH EXAMPLES This procedure sets the namespace variable \fI::a::x\fR .CS proc reset {} { \fBglobal\fR a::x set x 0 } .CE .PP This procedure accumulates the strings passed to it in a global buffer, separated by newlines. It is useful for situations when you want to build a message piece-by-piece (as if with \fBputs\fR) but send that full message in a single piece (e.g. over a connection opened with \fBsocket\fR or as part of a counted HTTP response). .CS proc accum {string} { \fBglobal\fR accumulator append accumulator $string \\n } .CE .SH "SEE ALSO" namespace(n), upvar(n), variable(n) .SH KEYWORDS global, namespace, procedure, variable tcl8.4.20/doc/tcltest.n0000644003604700454610000012760411737050674013337 0ustar dgp771div'\" '\" Copyright (c) 1990-1994 The Regents of the University of California '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" Copyright (c) 1998-1999 Scriptics Corporation '\" Copyright (c) 2000 Ajuba Solutions '\" Contributions from Don Porter, NIST, 2002. (not subject to US copyright) '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH "tcltest" n 2.2 tcltest "Tcl Bundled Packages" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME tcltest \- Test harness support code and utilities .SH SYNOPSIS .nf \fBpackage require tcltest ?2.2.5?\fR .sp \fBtcltest::test \fIname description ?option value ...?\fR \fBtcltest::test \fIname description ?constraints? body result\fR .sp \fBtcltest::loadTestedCommands\fR \fBtcltest::makeDirectory \fIname ?directory?\fR \fBtcltest::removeDirectory \fIname ?directory?\fR \fBtcltest::makeFile \fIcontents name ?directory?\fR \fBtcltest::removeFile \fIname ?directory?\fR \fBtcltest::viewFile \fIname ?directory?\fR \fBtcltest::cleanupTests \fI?runningMultipleTests?\fR \fBtcltest::runAllTests\fR .sp \fBtcltest::configure\fR \fBtcltest::configure \fIoption\fR \fBtcltest::configure \fIoption value ?option value ...?\fR \fBtcltest::customMatch \fImode command\fR \fBtcltest::testConstraint \fIconstraint ?value?\fR \fBtcltest::outputChannel \fI?channelID?\fR \fBtcltest::errorChannel \fI?channelID?\fR \fBtcltest::interpreter \fI?interp?\fR .sp \fBtcltest::debug \fI?level?\fR \fBtcltest::errorFile \fI?filename?\fR \fBtcltest::limitConstraints \fI?boolean?\fR \fBtcltest::loadFile \fI?filename?\fR \fBtcltest::loadScript \fI?script?\fR \fBtcltest::match \fI?patternList?\fR \fBtcltest::matchDirectories \fI?patternList?\fR \fBtcltest::matchFiles \fI?patternList?\fR \fBtcltest::outputFile \fI?filename?\fR \fBtcltest::preserveCore \fI?level?\fR \fBtcltest::singleProcess \fI?boolean?\fR \fBtcltest::skip \fI?patternList?\fR \fBtcltest::skipDirectories \fI?patternList?\fR \fBtcltest::skipFiles \fI?patternList?\fR \fBtcltest::temporaryDirectory \fI?directory?\fR \fBtcltest::testsDirectory \fI?directory?\fR \fBtcltest::verbose \fI?level?\fR .sp \fBtcltest::test \fIname description optionList\fR \fBtcltest::bytestring \fIstring\fR \fBtcltest::normalizeMsg \fImsg\fR \fBtcltest::normalizePath \fIpathVar\fR \fBtcltest::workingDirectory \fI?dir?\fR .fi .BE .SH DESCRIPTION .PP The \fBtcltest\fR package provides several utility commands useful in the construction of test suites for code instrumented to be run by evaluation of Tcl commands. Notably the built-in commands of the Tcl library itself are tested by a test suite using the tcltest package. .PP All the commands provided by the \fBtcltest\fR package are defined in and exported from the \fB::tcltest\fR namespace, as indicated in the \fBSYNOPSIS\fR above. In the following sections, all commands will be described by their simple names, in the interest of brevity. .PP The central command of \fBtcltest\fR is [\fBtest\fR] that defines and runs a test. Testing with [\fBtest\fR] involves evaluation of a Tcl script and comparing the result to an expected result, as configured and controlled by a number of options. Several other commands provided by \fBtcltest\fR govern the configuration of [\fBtest\fR] and the collection of many [\fBtest\fR] commands into test suites. .PP See \fBCREATING TEST SUITES WITH TCLTEST\fR below for an extended example of how to use the commands of \fBtcltest\fR to produce test suites for your Tcl-enabled code. .SH COMMANDS .TP \fBtest\fR \fIname description ?option value ...?\fR Defines and possibly runs a test with the name \fIname\fR and description \fIdescription\fR. The name and description of a test are used in messages reported by [\fBtest\fR] during the test, as configured by the options of \fBtcltest\fR. The remaining \fIoption value\fR arguments to [\fBtest\fR] define the test, including the scripts to run, the conditions under which to run them, the expected result, and the means by which the expected and actual results should be compared. See \fBTESTS\fR below for a complete description of the valid options and how they define a test. The [\fBtest\fR] command returns an empty string. .TP \fBtest\fR \fIname description ?constraints? body result\fR This form of [\fBtest\fR] is provided to support test suites written for version 1 of the \fBtcltest\fR package, and also a simpler interface for a common usage. It is the same as [\fBtest\fR \fIname description\fB -constraints \fIconstraints\fB -body \fIbody\fB -result \fIresult\fR]. All other options to [\fBtest\fR] take their default values. When \fIconstraints\fR is omitted, this form of [\fBtest\fR] can be distinguished from the first because all \fIoption\fRs begin with ``-''. .TP \fBloadTestedCommands\fR Evaluates in the caller's context the script specified by [\fBconfigure -load\fR] or [\fBconfigure -loadfile\fR]. Returns the result of that script evaluation, including any error raised by the script. Use this command and the related configuration options to provide the commands to be tested to the interpreter running the test suite. .TP \fBmakeFile\fR \fIcontents name ?directory?\fR Creates a file named \fIname\fR relative to directory \fIdirectory\fR and write \fIcontents\fR to that file using the encoding [\fBencoding system\fR]. If \fIcontents\fR does not end with a newline, a newline will be appended so that the file named \fIname\fR does end with a newline. Because the system encoding is used, this command is only suitable for making text files. The file will be removed by the next evaluation of [\fBcleanupTests\fR], unless it is removed by [\fBremoveFile\fR] first. The default value of \fIdirectory\fR is the directory [\fBconfigure -tmpdir\fR]. Returns the full path of the file created. Use this command to create any text file required by a test with contents as needed. .TP \fBremoveFile\fR \fIname ?directory?\fR Forces the file referenced by \fIname\fR to be removed. This file name should be relative to \fIdirectory\fR. The default value of \fIdirectory\fR is the directory [\fBconfigure -tmpdir\fR]. Returns an empty string. Use this command to delete files created by [\fBmakeFile\fR]. .TP \fBmakeDirectory\fR \fIname ?directory?\fR Creates a directory named \fIname\fR relative to directory \fIdirectory\fR. The directory will be removed by the next evaluation of [\fBcleanupTests\fR], unless it is removed by [\fBremoveDirectory\fR] first. The default value of \fIdirectory\fR is the directory [\fBconfigure -tmpdir\fR]. Returns the full path of the directory created. Use this command to create any directories that are required to exist by a test. .TP \fBremoveDirectory\fR \fIname ?directory?\fR Forces the directory referenced by \fIname\fR to be removed. This directory should be relative to \fIdirectory\fR. The default value of \fIdirectory\fR is the directory [\fBconfigure -tmpdir\fR]. Returns an empty string. Use this command to delete any directories created by [\fBmakeDirectory\fR]. .TP \fBviewFile\fR \fIfile ?directory?\fR Returns the contents of \fIfile\fR, except for any final newline, just as [\fBread -nonewline\fR] would return. This file name should be relative to \fIdirectory\fR. The default value of \fIdirectory\fR is the directory [\fBconfigure -tmpdir\fR]. Use this command as a convenient way to turn the contents of a file generated by a test into the result of that test for matching against an expected result. The contents of the file are read using the system encoding, so its usefulness is limited to text files. .TP \fBcleanupTests\fR Intended to clean up and summarize after several tests have been run. Typically called once per test file, at the end of the file after all tests have been completed. For best effectiveness, be sure that the [\fBcleanupTests\fR] is evaluated even if an error occurs earlier in the test file evaluation. .sp Prints statistics about the tests run and removes files that were created by [\fBmakeDirectory\fR] and [\fBmakeFile\fR] since the last [\fBcleanupTests\fR]. Names of files and directories in the directory [\fBconfigure -tmpdir\fR] created since the last [\fBcleanupTests\fR], but not created by [\fBmakeFile\fR] or [\fBmakeDirectory\fR] are printed to [\fBoutputChannel\fR]. This command also restores the original shell environment, as described by the ::env array. Returns an empty string. .TP \fBrunAllTests\fR This is a master command meant to run an entire suite of tests, spanning multiple files and/or directories, as governed by the configurable options of \fBtcltest\fR. See \fBRUNNING ALL TESTS\fR below for a complete description of the many variations possible with [\fBrunAllTests\fR]. .SH "CONFIGURATION COMMANDS" .TP \fBconfigure\fR Returns the list of configurable options supported by \fBtcltest\fR. See \fBCONFIGURABLE OPTIONS\fR below for the full list of options, their valid values, and their effect on \fBtcltest\fR operations. .TP \fBconfigure \fIoption\fR Returns the current value of the supported configurable option \fIoption\fR. Raises an error if \fIoption\fR is not a supported configurable option. .TP \fBconfigure \fIoption value ?option value ...?\fR Sets the value of each configurable option \fIoption\fR to the corresponding value \fIvalue\fR, in order. Raises an error if an \fIoption\fR is not a supported configurable option, or if \fIvalue\fR is not a valid value for the corresponding \fIoption\fR, or if a \fIvalue\fR is not provided. When an error is raised, the operation of [\fBconfigure\fR] is halted, and subsequent \fIoption value\fR arguments are not processed. .sp If the environment variable \fB::env(TCLTEST_OPTIONS)\fR exists when the \fBtcltest\fR package is loaded (by [\fBpackage require tcltest\fR]) then its value is taken as a list of arguments to pass to [\fBconfigure\fR]. This allows the default values of the configuration options to be set by the environment. .TP \fBcustomMatch \fImode script\fR Registers \fImode\fR as a new legal value of the \fB-match\fR option to [\fBtest\fR]. When the \fB-match \fImode\fR option is passed to [\fBtest\fR], the script \fIscript\fR will be evaluated to compare the actual result of evaluating the body of the test to the expected result. To perform the match, the \fIscript\fR is completed with two additional words, the expected result, and the actual result, and the completed script is evaluated in the global namespace. The completed script is expected to return a boolean value indicating whether or not the results match. The built-in matching modes of [\fBtest\fR] are \fBexact\fR, \fBglob\fR, and \fBregexp\fR. .TP \fBtestConstraint \fIconstraint ?boolean?\fR Sets or returns the boolean value associated with the named \fIconstraint\fR. See \fBTEST CONSTRAINTS\fR below for more information. .TP \fBinterpreter\fR \fI?executableName?\fR Sets or returns the name of the executable to be [\fBexec\fR]ed by [\fBrunAllTests\fR] to run each test file when [\fBconfigure -singleproc\fR] is false. The default value for [\fBinterpreter\fR] is the name of the currently running program as returned by [\fBinfo nameofexecutable\fR]. .TP \fBoutputChannel\fR \fI?channelID?\fR Sets or returns the output channel ID. This defaults to stdout. Any test that prints test related output should send that output to [\fBoutputChannel\fR] rather than letting that output default to stdout. .TP \fBerrorChannel\fR \fI?channelID?\fR Sets or returns the error channel ID. This defaults to stderr. Any test that prints error messages should send that output to [\fBerrorChannel\fR] rather than printing directly to stderr. .SH "SHORTCUT COMMANDS" .TP \fBdebug \fI?level?\fR Same as [\fBconfigure -debug \fI?level?\fR]. .TP \fBerrorFile \fI?filename?\fR Same as [\fBconfigure -errfile \fI?filename?\fR]. .TP \fBlimitConstraints \fI?boolean?\fR Same as [\fBconfigure -limitconstraints \fI?boolean?\fR]. .TP \fBloadFile \fI?filename?\fR Same as [\fBconfigure -loadfile \fI?filename?\fR]. .TP \fBloadScript \fI?script?\fR Same as [\fBconfigure -load \fI?script?\fR]. .TP \fBmatch \fI?patternList?\fR Same as [\fBconfigure -match \fI?patternList?\fR]. .TP \fBmatchDirectories \fI?patternList?\fR Same as [\fBconfigure -relateddir \fI?patternList?\fR]. .TP \fBmatchFiles \fI?patternList?\fR Same as [\fBconfigure -file \fI?patternList?\fR]. .TP \fBoutputFile \fI?filename?\fR Same as [\fBconfigure -outfile \fI?filename?\fR]. .TP \fBpreserveCore \fI?level?\fR Same as [\fBconfigure -preservecore \fI?level?\fR]. .TP \fBsingleProcess \fI?boolean?\fR Same as [\fBconfigure -singleproc \fI?boolean?\fR]. .TP \fBskip \fI?patternList?\fR Same as [\fBconfigure -skip \fI?patternList?\fR]. .TP \fBskipDirectories \fI?patternList?\fR Same as [\fBconfigure -asidefromdir \fI?patternList?\fR]. .TP \fBskipFiles \fI?patternList?\fR Same as [\fBconfigure -notfile \fI?patternList?\fR]. .TP \fBtemporaryDirectory \fI?directory?\fR Same as [\fBconfigure -tmpdir \fI?directory?\fR]. .TP \fBtestsDirectory \fI?directory?\fR Same as [\fBconfigure -testdir \fI?directory?\fR]. .TP \fBverbose \fI?level?\fR Same as [\fBconfigure -verbose \fI?level?\fR]. .SH "OTHER COMMANDS" .PP The remaining commands provided by \fBtcltest\fR have better alternatives provided by \fBtcltest\fR or \fBTcl\fR itself. They are retained to support existing test suites, but should be avoided in new code. .TP \fBtest\fR \fIname description optionList\fR This form of [\fBtest\fR] was provided to enable passing many options spanning several lines to [\fBtest\fR] as a single argument quoted by braces, rather than needing to backslash quote the newlines between arguments to [\fBtest\fR]. The \fIoptionList\fR argument is expected to be a list with an even number of elements representing \fIoption\fR and \fIvalue\fR arguments to pass to [\fBtest\fR]. However, these values are not passed directly, as in the alternate forms of [\fBswitch\fR]. Instead, this form makes an unfortunate attempt to overthrow Tcl's substitution rules by performing substitutions on some of the list elements as an attempt to implement a ``do what I mean'' interpretation of a brace-enclosed ``block''. The result is nearly impossible to document clearly, and for that reason this form is not recommended. See the examples in \fBCREATING TEST SUITES WITH TCLTEST\fR below to see that this form is really not necessary to avoid backslash-quoted newlines. If you insist on using this form, examine the source code of \fBtcltest\fR if you want to know the substitution details, or just enclose the third through last argument to [\fBtest\fR] in braces and hope for the best. .TP \fBworkingDirectory\fR \fI?directoryName?\fR Sets or returns the current working directory when the test suite is running. The default value for workingDirectory is the directory in which the test suite was launched. The Tcl commands [\fBcd\fR] and [\fBpwd\fR] are sufficient replacements. .TP \fBnormalizeMsg\fR \fImsg\fR Returns the result of removing the ``extra'' newlines from \fImsg\fR, where ``extra'' is rather imprecise. Tcl offers plenty of string processing commands to modify strings as you wish, and [\fBcustomMatch\fR] allows flexible matching of actual and expected results. .TP \fBnormalizePath\fR \fIpathVar\fR Resolves symlinks in a path, thus creating a path without internal redirection. It is assumed that \fIpathVar\fR is absolute. \fIpathVar\fR is modified in place. The Tcl command [\fBfile normalize\fR] is a sufficient replacement. .TP \fBbytestring\fR \fIstring\fR Construct a string that consists of the requested sequence of bytes, as opposed to a string of properly formed UTF-8 characters using the value supplied in \fIstring\fR. This allows the tester to create denormalized or improperly formed strings to pass to C procedures that are supposed to accept strings with embedded NULL types and confirm that a string result has a certain pattern of bytes. This is exactly equivalent to the Tcl command [\fBencoding convertfrom identity\fR]. .SH TESTS .PP The [\fBtest\fR] command is the heart of the \fBtcltest\fR package. Its essential function is to evaluate a Tcl script and compare the result with an expected result. The options of [\fBtest\fR] define the test script, the environment in which to evaluate it, the expected result, and how the compare the actual result to the expected result. Some configuration options of \fBtcltest\fR also influence how [\fBtest\fR] operates. .PP The valid options for [\fBtest\fR] are summarized: .CS .ta 0.8i \fBtest\fR \fIname\fR \fIdescription\fR ?-constraints \fIkeywordList|expression\fR? ?-setup \fIsetupScript\fR? ?-body \fItestScript\fR? ?-cleanup \fIcleanupScript\fR? ?-result \fIexpectedAnswer\fR? ?-output \fIexpectedOutput\fR? ?-errorOutput \fIexpectedError\fR? ?-returnCodes \fIcodeList\fR? ?-match \fImode\fR? .CE The \fIname\fR may be any string. It is conventional to choose a \fIname\fR according to the pattern: .CS \fItarget\fR-\fImajorNum\fR.\fIminorNum\fR .CE For white-box (regression) tests, the target should be the name of the C function or Tcl procedure being tested. For black-box tests, the target should be the name of the feature being tested. Some conventions call for the names of black-box tests to have the suffix \fB_bb\fR. Related tests should share a major number. As a test suite evolves, it is best to have the same test name continue to correspond to the same test, so that it remains meaningful to say things like ``Test foo-1.3 passed in all releases up to 3.4, but began failing in release 3.5.'' .PP During evaluation of [\fBtest\fR], the \fIname\fR will be compared to the lists of string matching patterns returned by [\fBconfigure -match\fR], and [\fBconfigure -skip\fR]. The test will be run only if \fIname\fR matches any of the patterns from [\fBconfigure -match\fR] and matches none of the patterns from [\fBconfigure -skip\fR]. .PP The \fIdescription\fR should be a short textual description of the test. The \fIdescription\fR is included in output produced by the test, typically test failure messages. Good \fIdescription\fR values should briefly explain the purpose of the test to users of a test suite. The name of a Tcl or C function being tested should be included in the description for regression tests. If the test case exists to reproduce a bug, include the bug ID in the description. .PP Valid attributes and associated values are: .TP \fB-constraints \fIkeywordList|expression\fR The optional \fB-constraints\fR attribute can be list of one or more keywords or an expression. If the \fB-constraints\fR value is a list of keywords, each of these keywords should be the name of a constraint defined by a call to [\fBtestConstraint\fR]. If any of the listed constraints is false or does not exist, the test is skipped. If the \fB-constraints\fR value is an expression, that expression is evaluated. If the expression evaluates to true, then the test is run. Note that the expression form of \fB-constraints\fR may interfere with the operation of [\fBconfigure -constraints\fR] and [\fBconfigure -limitconstraints\fR], and is not recommended. Appropriate constraints should be added to any tests that should not always be run. That is, conditional evaluation of a test should be accomplished by the \fB-constraints\fR option, not by conditional evaluation of [\fBtest\fR]. In that way, the same number of tests are always reported by the test suite, though the number skipped may change based on the testing environment. The default value is an empty list. See \fBTEST CONSTRAINTS\fR below for a list of built-in constraints and information on how to add your own constraints. .TP \fB-setup \fIscript\fR The optional \fB-setup\fR attribute indicates a \fIscript\fR that will be run before the script indicated by the \fB-body\fR attribute. If evaluation of \fIscript\fR raises an error, the test will fail. The default value is an empty script. .TP \fB-body \fIscript\fR The \fB-body\fR attribute indicates the \fIscript\fR to run to carry out the test. It must return a result that can be checked for correctness. If evaluation of \fIscript\fR raises an error, the test will fail. The default value is an empty script. .TP \fB-cleanup \fIscript\fR The optional \fB-cleanup\fR attribute indicates a \fIscript\fR that will be run after the script indicated by the \fB-body\fR attribute. If evaluation of \fIscript\fR raises an error, the test will fail. The default value is an empty script. .TP \fB-match \fImode\fR The \fB-match\fR attribute determines how expected answers supplied by \fB-result\fR, \fB-output\fR, and \fB-errorOutput\fR are compared. Valid values for \fImode\fR are \fBregexp\fR, \fBglob\fR, \fBexact\fR, and any value registered by a prior call to [\fBcustomMatch\fR]. The default value is \fBexact\fR. .TP \fB-result \fIexpectedValue\fR The \fB-result\fR attribute supplies the \fIexpectedValue\fR against which the return value from script will be compared. The default value is an empty string. .TP \fB-output \fIexpectedValue\fR The \fB-output\fR attribute supplies the \fIexpectedValue\fR against which any output sent to \fBstdout\fR or [\fBoutputChannel\fR] during evaluation of the script(s) will be compared. Note that only output printed using [\fB::puts\fR] is used for comparison. If \fB-output\fR is not specified, output sent to \fBstdout\fR and [\fBoutputChannel\fR] is not processed for comparison. .TP \fB-errorOutput \fIexpectedValue\fR The \fB-errorOutput\fR attribute supplies the \fIexpectedValue\fR against which any output sent to \fBstderr\fR or [\fBerrorChannel\fR] during evaluation of the script(s) will be compared. Note that only output printed using [\fB::puts\fR] is used for comparison. If \fB-errorOutput\fR is not specified, output sent to \fBstderr\fR and [\fBerrorChannel\fR] is not processed for comparison. .TP \fB-returnCodes \fIexpectedCodeList\fR The optional \fB-returnCodes\fR attribute supplies \fIexpectedCodeList\fR, a list of return codes that may be accepted from evaluation of the \fB-body\fR script. If evaluation of the \fB-body\fR script returns a code not in the \fIexpectedCodeList\fR, the test fails. All return codes known to [\fBreturn\fR], in both numeric and symbolic form, including extended return codes, are acceptable elements in the \fIexpectedCodeList\fR. Default value is \fB{ok return}\fR. .PP To pass, a test must successfully evaluate its \fB-setup\fR, \fB-body\fR, and \fB-cleanup\fR scripts. The return code of the \fB-body\fR script and its result must match expected values, and if specified, output and error data from the test must match expected \fB-output\fR and \fB-errorOutput\fR values. If any of these conditions are not met, then the test fails. Note that all scripts are evaluated in the context of the caller of [\fBtest\fR]. .PP As long as [\fBtest\fR] is called with valid syntax and legal values for all attributes, it will not raise an error. Test failures are instead reported as output written to [\fBoutputChannel\fR]. In default operation, a successful test produces no output. The output messages produced by [\fBtest\fR] are controlled by the [\fBconfigure -verbose\fR] option as described in \fBCONFIGURABLE OPTIONS\fR below. Any output produced by the test scripts themselves should be produced using [\fB::puts\fR] to [\fBoutputChannel\fR] or [\fBerrorChannel\fR], so that users of the test suite may easily capture output with the [\fBconfigure -outfile\fR] and [\fBconfigure -errfile\fR] options, and so that the \fB-output\fR and \fB-errorOutput\fR attributes work properly. .SH "TEST CONSTRAINTS" .PP Constraints are used to determine whether or not a test should be skipped. Each constraint has a name, which may be any string, and a boolean value. Each [\fBtest\fR] has a \fB-constraints\fR value which is a list of constraint names. There are two modes of constraint control. Most frequently, the default mode is used, indicated by a setting of [\fBconfigure -limitconstraints\fR] to false. The test will run only if all constraints in the list are true-valued. Thus, the \fB-constraints\fR option of [\fBtest\fR] is a convenient, symbolic way to define any conditions required for the test to be possible or meaningful. For example, a [\fBtest\fR] with \fB-constraints unix\fR will only be run if the constraint \fBunix\fR is true, which indicates the test suite is being run on a Unix platform. .PP Each [\fBtest\fR] should include whatever \fB-constraints\fR are required to constrain it to run only where appropriate. Several constraints are pre-defined in the \fBtcltest\fR package, listed below. The registration of user-defined constraints is performed by the [\fBtestConstraint\fR] command. User-defined constraints may appear within a test file, or within the script specified by the [\fBconfigure -load\fR] or [\fBconfigure -loadfile\fR] options. .PP The following is a list of constraints pre-defined by the \fBtcltest\fR package itself: .TP \fIsingleTestInterp\fR test can only be run if all test files are sourced into a single interpreter .TP \fIunix\fR test can only be run on any Unix platform .TP \fIwin\fR test can only be run on any Windows platform .TP \fInt\fR test can only be run on any Windows NT platform .TP \fI95\fR test can only be run on any Windows 95 platform .TP \fI98\fR test can only be run on any Windows 98 platform .TP \fImac\fR test can only be run on any Mac platform .TP \fIunixOrWin\fR test can only be run on a Unix or Windows platform .TP \fImacOrWin\fR test can only be run on a Mac or Windows platform .TP \fImacOrUnix\fR test can only be run on a Mac or Unix platform .TP \fItempNotWin\fR test can not be run on Windows. This flag is used to temporarily disable a test. .TP \fItempNotMac\fR test can not be run on a Mac. This flag is used to temporarily disable a test. .TP \fIunixCrash\fR test crashes if it's run on Unix. This flag is used to temporarily disable a test. .TP \fIwinCrash\fR test crashes if it's run on Windows. This flag is used to temporarily disable a test. .TP \fImacCrash\fR test crashes if it's run on a Mac. This flag is used to temporarily disable a test. .TP \fIemptyTest\fR test is empty, and so not worth running, but it remains as a place-holder for a test to be written in the future. This constraint has value false to cause tests to be skipped unless the user specifies otherwise. .TP \fIknownBug\fR test is known to fail and the bug is not yet fixed. This constraint has value false to cause tests to be skipped unless the user specifies otherwise. .TP \fInonPortable\fR test can only be run in some known development environment. Some tests are inherently non-portable because they depend on things like word length, file system configuration, window manager, etc. This constraint has value false to cause tests to be skipped unless the user specifies otherwise. .TP \fIuserInteraction\fR test requires interaction from the user. This constraint has value false to causes tests to be skipped unless the user specifies otherwise. .TP \fIinteractive\fR test can only be run in if the interpreter is in interactive mode (when the global tcl_interactive variable is set to 1). .TP \fInonBlockFiles\fR test can only be run if platform supports setting files into nonblocking mode .TP \fIasyncPipeClose\fR test can only be run if platform supports async flush and async close on a pipe .TP \fIunixExecs\fR test can only be run if this machine has Unix-style commands \fBcat\fR, \fBecho\fR, \fBsh\fR, \fBwc\fR, \fBrm\fR, \fBsleep\fR, \fBfgrep\fR, \fBps\fR, \fBchmod\fR, and \fBmkdir\fR available .TP \fIhasIsoLocale\fR test can only be run if can switch to an ISO locale .TP \fIroot\fR test can only run if Unix user is root .TP \fInotRoot\fR test can only run if Unix user is not root .TP \fIeformat\fR test can only run if app has a working version of sprintf with respect to the "e" format of floating-point numbers. .TP \fIstdio\fR test can only be run if [\fBinterpreter\fR] can be [\fBopen\fR]ed as a pipe. .PP The alternative mode of constraint control is enabled by setting [\fBconfigure -limitconstraints\fR] to true. With that configuration setting, all existing constraints other than those in the constraint list returned by [\fBconfigure -constraints\fR] are set to false. When the value of [\fBconfigure -constraints\fR] is set, all those constraints are set to true. The effect is that when both options [\fBconfigure -constraints\fR] and [\fBconfigure -limitconstraints\fR] are in use, only those tests including only constraints from the [\fBconfigure -constraints\fR] list are run; all others are skipped. For example, one might set up a configuration with .CS \fBconfigure\fR -constraints knownBug \e -limitconstraints true \e -verbose pass .CE to run exactly those tests that exercise known bugs, and discover whether any of them pass, indicating the bug had been fixed. .SH "RUNNING ALL TESTS" .PP The single command [\fBrunAllTests\fR] is evaluated to run an entire test suite, spanning many files and directories. The configuration options of \fBtcltest\fR control the precise operations. The [\fBrunAllTests\fR] command begins by printing a summary of its configuration to [\fBoutputChannel\fR]. .PP Test files to be evaluated are sought in the directory [\fBconfigure -testdir\fR]. The list of files in that directory that match any of the patterns in [\fBconfigure -file\fR] and match none of the patterns in [\fBconfigure -notfile\fR] is generated and sorted. Then each file will be evaluated in turn. If [\fBconfigure -singleproc\fR] is true, then each file will be [\fBsource\fR]d in the caller's context. If it is false, then a copy of [\fBinterpreter\fR] will be [\fBexec\fR]d to evaluate each file. The multi-process operation is useful when testing can cause errors so severe that a process terminates. Although such an error may terminate a child process evaluating one file, the master process can continue with the rest of the test suite. In multi-process operation, the configuration of \fBtcltest\fR in the master process is passed to the child processes as command line arguments, with the exception of [\fBconfigure -outfile\fR]. The [\fBrunAllTests\fR] command in the master process collects all output from the child processes and collates their results into one master report. Any reports of individual test failures, or messages requested by a [\fBconfigure -verbose\fR] setting are passed directly on to [\fBoutputChannel\fR] by the master process. .PP After evaluating all selected test files, a summary of the results is printed to [\fBoutputChannel\fR]. The summary includes the total number of [\fBtest\fR]s evaluated, broken down into those skipped, those passed, and those failed. The summary also notes the number of files evaluated, and the names of any files with failing tests or errors. A list of the constraints that caused tests to be skipped, and the number of tests skipped for each is also printed. Also, messages are printed if it appears that evaluation of a test file has caused any temporary files to be left behind in [\fBconfigure -tmpdir\fR]. .PP Having completed and summarized all selected test files, [\fBrunAllTests\fR] then recursively acts on subdirectories of [\fBconfigure -testdir\fR]. All subdirectories that match any of the patterns in [\fBconfigure -relateddir\fR] and do not match any of the patterns in [\fBconfigure -asidefromdir\fR] are examined. If a file named \fBall.tcl\fR is found in such a directory, it will be [\fBsource\fR]d in the caller's context. Whether or not an examined directory contains an \fBall.tcl\fR file, its subdirectories are also scanned against the [\fBconfigure -relateddir\fR] and [\fBconfigure -asidefromdir\fR] patterns. In this way, many directories in a directory tree can have all their test files evaluated by a single [\fBrunAllTests\fR] command. .SH "CONFIGURABLE OPTIONS" The [\fBconfigure\fR] command is used to set and query the configurable options of \fBtcltest\fR. The valid options are: .TP \fB-singleproc \fIboolean\fR Controls whether or not [\fBrunAllTests\fR] spawns a child process for each test file. No spawning when \fIboolean\fR is true. Default value is false. .TP \fB-debug \fIlevel\fR Sets the debug level to \fIlevel\fR, an integer value indicating how much debugging information should be printed to stdout. Note that debug messages always go to stdout, independent of the value of [\fBconfigure -outfile\fR]. Default value is 0. Levels are defined as: .RS .IP 0 Do not display any debug information. .IP 1 Display information regarding whether a test is skipped because it doesn't match any of the tests that were specified using by [\fBconfigure -match\fR] (userSpecifiedNonMatch) or matches any of the tests specified by [\fBconfigure -skip\fR] (userSpecifiedSkip). Also print warnings about possible lack of cleanup or balance in test files. Also print warnings about any re-use of test names. .IP 2 Display the flag array parsed by the command line processor, the contents of the ::env array, and all user-defined variables that exist in the current namespace as they are used. .IP 3 Display information regarding what individual procs in the test harness are doing. .RE .TP \fB-verbose \fIlevel\fR Sets the type of output verbosity desired to \fIlevel\fR, a list of zero or more of the elements \fBbody\fR, \fBpass\fR, \fBskip\fR, \fBstart\fR, and \fBerror\fR. Default value is \fB{body error}\fR. Levels are defined as: .RS .IP "body (b)" Display the body of failed tests .IP "pass (p)" Print output when a test passes .IP "skip (s)" Print output when a test is skipped .IP "start (t)" Print output whenever a test starts .IP "error (e)" Print errorInfo and errorCode, if they exist, when a test return code does not match its expected return code .RE The single letter abbreviations noted above are also recognized so that [\fBconfigure -verbose pt\fR] is the same as [\fBconfigure -verbose {pass start}\fR]. .TP \fB-preservecore \fIlevel\fR Sets the core preservation level to \fIlevel\fR. This level determines how stringent checks for core files are. Default value is 0. Levels are defined as: .RS .IP 0 No checking - do not check for core files at the end of each test command, but do check for them in [\fBrunAllTests\fR] after all test files have been evaluated. .IP 1 Also check for core files at the end of each [\fBtest\fR] command. .IP 2 Check for core files at all times described above, and save a copy of each core file produced in [\fBconfigure -tmpdir\fR]. .RE .TP \fB-limitconstraints \fIboolean\fR Sets the mode by which [\fBtest\fR] honors constraints as described in \fBTESTS\fR above. Default value is false. .TP \fB-constraints \fIlist\fR Sets all the constraints in \fIlist\fR to true. Also used in combination with [\fBconfigure -limitconstraints true\fR] to control an alternative constraint mode as described in \fBTESTS\fR above. Default value is an empty list. .TP \fB-tmpdir \fIdirectory\fR Sets the temporary directory to be used by [\fBmakeFile\fR], [\fBmakeDirectory\fR], [\fBviewFile\fR], [\fBremoveFile\fR], and [\fBremoveDirectory\fR] as the default directory where temporary files and directories created by test files should be created. Default value is [\fBworkingDirectory\fR]. .TP \fB-testdir \fIdirectory\fR Sets the directory searched by [\fBrunAllTests\fR] for test files and subdirectories. Default value is [\fBworkingDirectory\fR]. .TP \fB-file \fIpatternList\fR Sets the list of patterns used by [\fBrunAllTests\fR] to determine what test files to evaluate. Default value is \fB*.test\fR. .TP \fB-notfile \fIpatternList\fR Sets the list of patterns used by [\fBrunAllTests\fR] to determine what test files to skip. Default value is \fBl.*.test\fR, so that any SCCS lock files are skipped. .TP \fB-relateddir \fIpatternList\fR Sets the list of patterns used by [\fBrunAllTests\fR] to determine what subdirectories to search for an \fBall.tcl\fR file. Default value is \fB*\fR. .TP \fB-asidefromdir \fIpatternList\fR Sets the list of patterns used by [\fBrunAllTests\fR] to determine what subdirectories to skip when searching for an \fBall.tcl\fR file. Default value is an empty list. .TP \fB-match \fIpatternList\fR Set the list of patterns used by [\fBtest\fR] to determine whether a test should be run. Default value is \fB*\fR. .TP \fB-skip \fIpatternList\fR Set the list of patterns used by [\fBtest\fR] to determine whether a test should be skipped. Default value is an empty list. .TP \fB-load \fIscript\fR Sets a script to be evaluated by [\fBloadTestedCommands\fR]. Default value is an empty script. .TP \fB-loadfile \fIfilename\fR Sets the filename from which to read a script to be evaluated by [\fBloadTestedCommands\fR]. This is an alternative to \fB-load\fR. They cannot be used together. .TP \fB-outfile \fIfilename\fR Sets the file to which all output produced by tcltest should be written. A file named \fIfilename\fR will be [\fBopen\fR]ed for writing, and the resulting channel will be set as the value of [\fBoutputChannel\fR]. .TP \fB-errfile \fIfilename\fR Sets the file to which all error output produced by tcltest should be written. A file named \fIfilename\fR will be [\fBopen\fR]ed for writing, and the resulting channel will be set as the value of [\fBerrorChannel\fR]. .SH "CREATING TEST SUITES WITH TCLTEST" .PP The fundamental element of a test suite is the individual [\fBtest\fR] command. We begin with several examples. .IP [1] Test of a script that returns normally. .CS \fBtest\fR example-1.0 {normal return} { format %s value } value .CE .IP [2] Test of a script that requires context setup and cleanup. Note the bracing and indenting style that avoids any need for line continuation. .CS \fBtest\fR example-1.1 {test file existence} -setup { set file [makeFile {} test] } -body { file exists $file } -cleanup { removeFile test } -result 1 .CE .IP [3] Test of a script that raises an error. .CS \fBtest\fR example-1.2 {error return} -body { error message } -returnCodes error -result message .CE .IP [4] Test with a constraint. .CS \fBtest\fR example-1.3 {user owns created files} -constraints { unix } -setup { set file [makeFile {} test] } -body { file attributes $file -owner } -cleanup { removeFile test } -result $::tcl_platform(user) .CE .PP At the next higher layer of organization, several [\fBtest\fR] commands are gathered together into a single test file. Test files should have names with the \fB.test\fR extension, because that is the default pattern used by [\fBrunAllTests\fR] to find test files. It is a good rule of thumb to have one test file for each source code file of your project. It is good practice to edit the test file and the source code file together, keeping tests synchronized with code changes. .PP Most of the code in the test file should be the [\fBtest\fR] commands. Use constraints to skip tests, rather than conditional evaluation of [\fBtest\fR]. That is, do this: .IP [5] .CS \fBtestConstraint\fR X [expr $myRequirement] \fBtest\fR goodConditionalTest {} X { # body } result .CE and do not do this: .IP [6] .CS if $myRequirement { test badConditionalTest {} { #body } result } .CE .PP Use the \fB-setup\fR and \fB-cleanup\fR options to establish and release all context requirements of the test body. Do not make tests depend on prior tests in the file. Those prior tests might be skipped. If several consecutive tests require the same context, the appropriate setup and cleanup scripts may be stored in variable for passing to each tests \fB-setup\fR and \fB-cleanup\fR options. This is a better solution than performing setup outside of [\fBtest\fR] commands, because the setup will only be done if necessary, and any errors during setup will be reported, and not cause the test file to abort. .PP A test file should be able to be combined with other test files and not interfere with them, even when [\fBconfigure -singleproc 1\fR] causes all files to be evaluated in a common interpreter. A simple way to achieve this is to have your tests define all their commands and variables in a namespace that is deleted when the test file evaluation is complete. A good namespace to use is a child namespace \fBtest\fR of the namespace of the module you are testing. .PP A test file should also be able to be evaluated directly as a script, not depending on being called by a master [\fBrunAllTests\fR]. This means that each test file should process command line arguments to give the tester all the configuration control that \fBtcltest\fR provides. .PP After all [\fBtest\fR]s in a test file, the command [\fBcleanupTests\fR] should be called. .IP [7] Here is a sketch of a sample test file illustrating those points: .CS package require tcltest 2.2 eval \fB::tcltest::configure\fR $argv package require example namespace eval ::example::test { namespace import ::tcltest::* \fBtestConstraint\fR X [expr {...}] variable SETUP {#common setup code} variable CLEANUP {#common cleanup code} \fBtest\fR example-1 {} -setup $SETUP -body { # First test } -cleanup $CLEANUP -result {...} \fBtest\fR example-2 {} -constraints X -setup $SETUP -body { # Second test; constrained } -cleanup $CLEANUP -result {...} \fBtest\fR example-3 {} { # Third test; no context required } {...} \fBcleanupTests\fR } namespace delete ::example::test .CE .PP The next level of organization is a full test suite, made up of several test files. One script is used to control the entire suite. The basic function of this script is to call [\fBrunAllTests\fR] after doing any necessary setup. This script is usually named \fBall.tcl\fR because that's the default name used by [\fBrunAllTests\fR] when combining multiple test suites into one testing run. .IP [8] Here is a sketch of a sample test suite master script: .CS package require Tcl 8.4 package require tcltest 2.2 package require example \fB::tcltest::configure\fR -testdir \ [file dirname [file normalize [info script]]] eval \fB::tcltest::configure\fR $argv \fB::tcltest::runAllTests\fR .CE .SH COMPATIBILITY .PP A number of commands and variables in the \fB::tcltest\fR namespace provided by earlier releases of \fBtcltest\fR have not been documented here. They are no longer part of the supported public interface of \fBtcltest\fR and should not be used in new test suites. However, to continue to support existing test suites written to the older interface specifications, many of those deprecated commands and variables still work as before. For example, in many circumstances, [\fBconfigure\fR] will be automatically called shortly after [\fBpackage require tcltest 2.1\fR] succeeds with arguments from the variable \fB::argv\fR. This is to support test suites that depend on the old behavior that \fBtcltest\fR was automatically configured from command line arguments. New test files should not depend on this, but should explicitly include .CS eval \fB::tcltest::configure\fR $::argv .CE to establish a configuration from command line arguments. .SH "KNOWN ISSUES" There are two known issues related to nested evaluations of [\fBtest\fR]. The first issue relates to the stack level in which test scripts are executed. Tests nested within other tests may be executed at the same stack level as the outermost test. For example, in the following code: .CS \fBtest\fR level-1.1 {level 1} { -body { \fBtest\fR level-2.1 {level 2} { } } } .CE any script executed in level-2.1 may be executed at the same stack level as the script defined for level-1.1. .PP In addition, while two [\fBtest\fR]s have been run, results will only be reported by [\fBcleanupTests\fR] for tests at the same level as test level-1.1. However, test results for all tests run prior to level-1.1 will be available when test level-2.1 runs. What this means is that if you try to access the test results for test level-2.1, it will may say that 'm' tests have run, 'n' tests have been skipped, 'o' tests have passed and 'p' tests have failed, where 'm', 'n', 'o', and 'p' refer to tests that were run at the same test level as test level-1.1. .PP Implementation of output and error comparison in the test command depends on usage of ::puts in your application code. Output is intercepted by redefining the ::puts command while the defined test script is being run. Errors thrown by C procedures or printed directly from C applications will not be caught by the test command. Therefore, usage of the \fB-output\fR and \fB-errorOutput\fR options to [\fBtest\fR] is useful only for pure Tcl applications that use [\fB::puts\fR] to produce output. .SH KEYWORDS test, test harness, test suite tcl8.4.20/doc/foreach.n0000644003604700454610000000543011737050674013254 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH foreach n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME foreach \- Iterate over all elements in one or more lists .SH SYNOPSIS \fBforeach \fIvarname list body\fR .br \fBforeach \fIvarlist1 list1\fR ?\fIvarlist2 list2 ...\fR? \fIbody\fR .BE .SH DESCRIPTION .PP The \fBforeach\fR command implements a loop where the loop variable(s) take on values from one or more lists. In the simplest case there is one loop variable, \fIvarname\fR, and one list, \fIlist\fR, that is a list of values to assign to \fIvarname\fR. The \fIbody\fR argument is a Tcl script. For each element of \fIlist\fR (in order from first to last), \fBforeach\fR assigns the contents of the element to \fIvarname\fR as if the \fBlindex\fR command had been used to extract the element, then calls the Tcl interpreter to execute \fIbody\fR. .PP In the general case there can be more than one value list (e.g., \fIlist1\fR and \fIlist2\fR), and each value list can be associated with a list of loop variables (e.g., \fIvarlist1\fR and \fIvarlist2\fR). During each iteration of the loop the variables of each \fIvarlist\fP are assigned consecutive values from the corresponding \fIlist\fP. Values in each \fIlist\fP are used in order from first to last, and each value is used exactly once. The total number of loop iterations is large enough to use up all the values from all the value lists. If a value list does not contain enough elements for each of its loop variables in each iteration, empty values are used for the missing elements. .PP The \fBbreak\fR and \fBcontinue\fR statements may be invoked inside \fIbody\fR, with the same effect as in the \fBfor\fR command. \fBForeach\fR returns an empty string. .SH EXAMPLES .PP The following loop uses i and j as loop variables to iterate over pairs of elements of a single list. .DS set x {} \fBforeach\fR {i j} {a b c d e f} { lappend x $j $i } # The value of x is "b a d c f e" # There are 3 iterations of the loop. .DE .PP The next loop uses i and j to iterate over two lists in parallel. .DS set x {} \fBforeach\fR i {a b c} j {d e f g} { lappend x $i $j } # The value of x is "a d b e c f {} g" # There are 4 iterations of the loop. .DE .PP The two forms are combined in the following example. .DS set x {} \fBforeach\fR i {a b c} {j k} {d e f g} { lappend x $i $j $k } # The value of x is "a d e b f g c {} {}" # There are 3 iterations of the loop. .DE .SH "SEE ALSO" for(n), while(n), break(n), continue(n) .SH KEYWORDS foreach, iteration, list, looping tcl8.4.20/doc/GetTime.30000644003604700454610000000325511737050674013113 0ustar dgp771div'\" '\" Copyright (c) 2001 by Kevin B. Kenny. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_GetTime 3 8.4 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_GetTime \- get date and time .SH SYNOPSIS .nf \fB#include \fR .sp \fBTcl_GetTime\fR(\fI timePtr \fR) .SH ARGUMENTS .AS "Tcl_Time *" timePtr .AP "Tcl_Time *" timePtr out Points to memory in which to store the date and time information. .BE .SH DESCRIPTION .PP The \fBTcl_GetTime\fR function retrieves the current time as a \fITcl_Time\fR structure in memory the caller provides. This structure has the following definition: .CS typedef struct Tcl_Time { long sec; long usec; } Tcl_Time; .CE .PP On return, the \fIsec\fR member of the structure is filled in with the number of seconds that have elapsed since the \fIepoch:\fR the epoch is the point in time of 00:00 UTC, 1 January 1970. This number does \fInot\fR count leap seconds \- an interval of one day advances it by 86400 seconds regardless of whether a leap second has been inserted. .PP The \fIusec\fR member of the structure is filled in with the number of microseconds that have elapsed since the start of the second designated by \fIsec\fR. The Tcl library makes every effort to keep this number as precise as possible, subject to the limitations of the computer system. On multiprocessor variants of Windows, this number may be limited to the 10- or 20-ms granularity of the system clock. (On single-processor Windows systems, the \fIusec\fR field is derived from a performance counter and is highly precise.) .SH "SEE ALSO" clock .SH KEYWORDS date, time tcl8.4.20/doc/CrtMathFnc.30000644003604700454610000001373611737050674013553 0ustar dgp771div'\" '\" Copyright (c) 1989-1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_CreateMathFunc 3 8.4 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_CreateMathFunc, Tcl_GetMathFuncInfo, Tcl_ListMathFuncs \- Define, query and enumerate math functions for expressions .SH SYNOPSIS .nf \fB#include \fR .sp void \fBTcl_CreateMathFunc\fR(\fIinterp, name, numArgs, argTypes, proc, clientData\fR) .sp .VS 8.4 int \fBTcl_GetMathFuncInfo\fR(\fIinterp, name, numArgsPtr, argTypesPtr, procPtr, clientDataPtr\fR) .sp Tcl_Obj * \fBTcl_ListMathFuncs\fR(\fIinterp, pattern\fR) .VE .SH ARGUMENTS .AS Tcl_ValueType *clientDataPtr .AP Tcl_Interp *interp in Interpreter in which new function will be defined. .VS 8.4 .AP "CONST char" *name in .VE Name for new function. .AP int numArgs in Number of arguments to new function; also gives size of \fIargTypes\fR array. .AP Tcl_ValueType *argTypes in Points to an array giving the permissible types for each argument to function. .AP Tcl_MathProc *proc in Procedure that implements the function. .AP ClientData clientData in Arbitrary one-word value to pass to \fIproc\fR when it is invoked. .AP int *numArgsPtr out Points to a variable that will be set to contain the number of arguments to the function. .AP Tcl_ValueType **argTypesPtr out Points to a variable that will be set to contain a pointer to an array giving the permissible types for each argument to the function which will need to be freed up using \fITcl_Free\fR. .AP Tcl_MathProc **procPtr out Points to a variable that will be set to contain a pointer to the implementation code for the function (or NULL if the function is implemented directly in bytecode.) .AP ClientData *clientDataPtr out Points to a variable that will be set to contain the clientData argument passed to \fITcl_CreateMathFunc\fR when the function was created if the function is not implemented directly in bytecode. .AP "CONST char" *pattern in Pattern to match against function names so as to filter them (by passing to \fITcl_StringMatch\fR), or NULL to not apply any filter. .BE .SH DESCRIPTION .PP Tcl allows a number of mathematical functions to be used in expressions, such as \fBsin\fR, \fBcos\fR, and \fBhypot\fR. \fBTcl_CreateMathFunc\fR allows applications to add additional functions to those already provided by Tcl or to replace existing functions. \fIName\fR is the name of the function as it will appear in expressions. If \fIname\fR doesn't already exist as a function then a new function is created. If it does exist, then the existing function is replaced. \fINumArgs\fR and \fIargTypes\fR describe the arguments to the function. Each entry in the \fIargTypes\fR array must be .VS 8.4 one of TCL_INT, TCL_DOUBLE, TCL_WIDE_INT, or TCL_EITHER to indicate whether the corresponding argument must be an integer, a double-precision floating value, a wide (64-bit) integer, or any, respectively. .VE 8.4 .PP Whenever the function is invoked in an expression Tcl will invoke \fIproc\fR. \fIProc\fR should have arguments and result that match the type \fBTcl_MathProc\fR: .CS typedef int Tcl_MathProc( ClientData \fIclientData\fR, Tcl_Interp *\fIinterp\fR, Tcl_Value *\fIargs\fR, Tcl_Value *\fIresultPtr\fR); .CE .PP When \fIproc\fR is invoked the \fIclientData\fR and \fIinterp\fR arguments will be the same as those passed to \fBTcl_CreateMathFunc\fR. \fIArgs\fR will point to an array of \fInumArgs\fR Tcl_Value structures, which describe the actual arguments to the function: .VS 8.4 .CS typedef struct Tcl_Value { Tcl_ValueType \fItype\fR; long \fIintValue\fR; double \fIdoubleValue\fR; Tcl_WideInt \fIwideValue\fR; } Tcl_Value; .CE .PP The \fItype\fR field indicates the type of the argument and is one of TCL_INT, TCL_DOUBLE or TCL_WIDE_INT. .VE 8.4 It will match the \fIargTypes\fR value specified for the function unless the \fIargTypes\fR value was TCL_EITHER. Tcl converts the argument supplied in the expression to the type requested in \fIargTypes\fR, if that is necessary. Depending on the value of the \fItype\fR field, the \fIintValue\fR, .VS 8.4 \fIdoubleValue\fR or \fIwideValue\fR .VE 8.4 field will contain the actual value of the argument. .PP \fIProc\fR should compute its result and store it either as an integer in \fIresultPtr->intValue\fR or as a floating value in \fIresultPtr->doubleValue\fR. It should set also \fIresultPtr->type\fR to one of .VS 8.4 TCL_INT, TCL_DOUBLE or TCL_WIDE_INT .VE 8.4 to indicate which value was set. Under normal circumstances \fIproc\fR should return TCL_OK. If an error occurs while executing the function, \fIproc\fR should return TCL_ERROR and leave an error message in the interpreter's result. .PP .VS 8.4 \fBTcl_GetMathFuncInfo\fR retrieves the values associated with function \fIname\fR that were passed to a preceding \fBTcl_CreateMathFunc\fR call. Normally, the return code is \fBTCL_OK\fR but if the named function does not exist, \fBTCL_ERROR\fR is returned and an error message is placed in the interpreter's result. .PP If an error did not occur, the array reference placed in the variable pointed to by \fIargTypesPtr\fR is newly allocated, and should be released by passing it to \fBTcl_Free\fR. Some functions (the standard set implemented in the core) are implemented directly at the bytecode level; attempting to retrieve values for them causes a NULL to be stored in the variable pointed to by \fIprocPtr\fR and the variable pointed to by \fIclientDataPtr\fR will not be modified. .PP \fBTcl_ListMathFuncs\fR returns a Tcl object containing a list of all the math functions defined in the interpreter whose name matches \fIpattern\fR. In the case of an error, NULL is returned and an error message is left in the interpreter result, and otherwise the returned object will have a reference count of zero. .VE .SH KEYWORDS expression, mathematical function .SH "SEE ALSO" expr(n), info(n), Tcl_Free(3), Tcl_NewListObj(3) tcl8.4.20/doc/set.n0000644003604700454610000000465511737050674012450 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH set n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME set \- Read and write variables .SH SYNOPSIS \fBset \fIvarName \fR?\fIvalue\fR? .BE .SH DESCRIPTION .PP Returns the value of variable \fIvarName\fR. If \fIvalue\fR is specified, then set the value of \fIvarName\fR to \fIvalue\fR, creating a new variable if one doesn't already exist, and return its value. If \fIvarName\fR contains an open parenthesis and ends with a close parenthesis, then it refers to an array element: the characters before the first open parenthesis are the name of the array, and the characters between the parentheses are the index within the array. Otherwise \fIvarName\fR refers to a scalar variable. .PP If \fIvarName\fR includes namespace qualifiers (in the array name if it refers to an array element), or if \fIvarName\fR is unqualified (does not include the names of any containing namespaces) but no procedure is active, \fIvarName\fR refers to a namespace variable resolved according to the rules described under \fBNAME RESOLUTION\fR in the \fBnamespace\fR manual page. .PP If a procedure is active and \fIvarName\fR is unqualified, then \fIvarName\fR refers to a parameter or local variable of the procedure, unless \fIvarName\fR was declared to resolve differently through one of the \fBglobal\fR, \fBvariable\fR or \fBupvar\fR commands. .SH EXAMPLES Store a random number in the variable \fIr\fR: .CS \fBset\fR r [expr rand()] .CE .PP Store a short message in an array element: .CS \fBset\fR anAry(msg) "Hello, World!" .CE .PP Store a short message in an array element specified by a variable: .CS \fBset\fR elemName "msg" \fBset\fR anAry($elemName) "Hello, World!" .CE .PP Copy a value into the variable \fIout\fR from a variable whose name is stored in the \fIvbl\fR (note that it is often easier to use arrays in practice instead of doing double-dereferencing): .CS \fBset\fR in0 "small random" \fBset\fR in1 "large random" \fBset\fR vbl in[expr {rand() >= 0.5}] \fBset\fR out [\fBset\fR $vbl] .CE .SH "SEE ALSO" expr(n), global(n), namespace(n), proc(n), trace(n), unset(n), upvar(n), variable(n) .SH KEYWORDS read, write, variable tcl8.4.20/doc/append.n0000644003604700454610000000235511737050674013117 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH append n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME append \- Append to variable .SH SYNOPSIS \fBappend \fIvarName \fR?\fIvalue value value ...\fR? .BE .SH DESCRIPTION .PP Append all of the \fIvalue\fR arguments to the current value of variable \fIvarName\fR. If \fIvarName\fR doesn't exist, it is given a value equal to the concatenation of all the \fIvalue\fR arguments. The result of this command is the new value stored in variable \fIvarName\fR. This command provides an efficient way to build up long variables incrementally. For example, ``\fBappend a $b\fR'' is much more efficient than ``\fBset a $a$b\fR'' if \fB$a\fR is long. .SH EXAMPLE Building a string of comma-separated numbers piecemeal using a loop. .CS set var 0 for {set i 1} {$i<=10} {incr i} { \fBappend\fR var "," $i } puts $var # Prints 0,1,2,3,4,5,6,7,8,9,10 .CE .SH "SEE ALSO" concat(n), lappend(n) .SH KEYWORDS append, variable tcl8.4.20/doc/SaveResult.30000644003604700454610000000446411737050674013655 0ustar dgp771div'\" '\" Copyright (c) 1997 by Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_SaveResult 3 8.1 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_SaveResult, Tcl_RestoreResult, Tcl_DiscardResult \- save and restore an interpreter's result .SH SYNOPSIS .nf \fB#include \fR .sp \fBTcl_SaveResult(\fIinterp, statePtr\fB)\fR .sp \fBTcl_RestoreResult(\fIinterp, statePtr\fB)\fR .sp \fBTcl_DiscardResult(\fIstatePtr\fB)\fR .SH ARGUMENTS .AS Tcl_SavedResult statePtr .AP Tcl_Interp *interp in Interpreter for which state should be saved. .AP Tcl_SavedResult *statePtr in Pointer to location where interpreter result should be saved or restored. .BE .SH DESCRIPTION .PP These routines allows a C procedure to take a snapshot of the current interpreter result so that it can be restored after a call to \fBTcl_Eval\fR or some other routine that modifies the interpreter result. These routines are passed a pointer to a structure that is used to store enough information to restore the interpreter result state. This structure can be allocated on the stack of the calling procedure. These routines do not save the state of any error information in the interpreter (e.g. the \fBerrorCode\fR or \fBerrorInfo\fR variables). .PP \fBTcl_SaveResult\fR moves the string and object results of \fIinterp\fR into the location specified by \fIstatePtr\fR. \fBTcl_SaveResult\fR clears the result for \fIinterp\fR and leaves the result in its normal empty initialized state. .PP \fBTcl_RestoreResult\fR moves the string and object results from \fIstatePtr\fR back into \fIinterp\fR. Any result or error that was already in the interpreter will be cleared. The \fIstatePtr\fR is left in an uninitialized state and cannot be used until another call to \fBTcl_SaveResult\fR. .PP \fBTcl_DiscardResult\fR releases the saved interpreter state stored at \fBstatePtr\fR. The state structure is left in an uninitialized state and cannot be used until another call to \fBTcl_SaveResult\fR. .PP Once \fBTcl_SaveResult\fR is called to save the interpreter result, either \fBTcl_RestoreResult\fR or \fBTcl_DiscardResult\fR must be called to properly clean up the memory associated with the saved state. .SH KEYWORDS result, state, interp tcl8.4.20/doc/break.n0000644003604700454610000000237211737050674012733 0ustar dgp771div'\" '\" Copyright (c) 1993-1994 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH break n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME break \- Abort looping command .SH SYNOPSIS \fBbreak\fR .BE .SH DESCRIPTION .PP This command is typically invoked inside the body of a looping command such as \fBfor\fR or \fBforeach\fR or \fBwhile\fR. It returns a \fBTCL_BREAK\fR code, which causes a break exception to occur. The exception causes the current script to be aborted out to the innermost containing loop command, which then aborts its execution and returns normally. Break exceptions are also handled in a few other situations, such as the \fBcatch\fR command, Tk event bindings, and the outermost scripts of procedure bodies. .SH EXAMPLE Print a line for each of the integers from 0 to 5: .CS for {set x 0} {$x<10} {incr x} { if {$x > 5} { \fBbreak\fR } puts "x is $x" } .CE .SH "SEE ALSO" catch(n), continue(n), for(n), foreach(n), return(n), while(n) .SH KEYWORDS abort, break, loop tcl8.4.20/doc/SetRecLmt.30000644003604700454610000000350611737050674013416 0ustar dgp771div'\" '\" Copyright (c) 1989-1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_SetRecursionLimit 3 7.0 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_SetRecursionLimit \- set maximum allowable nesting depth in interpreter .SH SYNOPSIS .nf \fB#include \fR .sp int \fBTcl_SetRecursionLimit\fR(\fIinterp, depth\fR) .SH ARGUMENTS .AS Tcl_Interp *interp .AP Tcl_Interp *interp in Interpreter whose recursion limit is to be set. Must be greater than zero. .AP int depth in New limit for nested calls to \fBTcl_Eval\fR for \fIinterp\fR. .BE .SH DESCRIPTION .PP At any given time Tcl enforces a limit on the number of recursive calls that may be active for \fBTcl_Eval\fR and related procedures such as \fBTcl_GlobalEval\fR. Any call to \fBTcl_Eval\fR that exceeds this depth is aborted with an error. By default the recursion limit is 1000. .PP \fBTcl_SetRecursionLimit\fR may be used to change the maximum allowable nesting depth for an interpreter. The \fIdepth\fR argument specifies a new limit for \fIinterp\fR, and \fBTcl_SetRecursionLimit\fR returns the old limit. To read out the old limit without modifying it, invoke \fBTcl_SetRecursionLimit\fR with \fIdepth\fR equal to 0. .PP The \fBTcl_SetRecursionLimit\fR only sets the size of the Tcl call stack: it cannot by itself prevent stack overflows on the C stack being used by the application. If your machine has a limit on the size of the C stack, you may get stack overflows before reaching the limit set by \fBTcl_SetRecursionLimit\fR. If this happens, see if there is a mechanism in your system for increasing the maximum size of the C stack. .SH KEYWORDS nesting depth, recursion tcl8.4.20/doc/encoding.n0000644003604700454610000000621411737050674013434 0ustar dgp771div'\" '\" Copyright (c) 1998 by Scriptics Corporation. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH encoding n "8.1" Tcl "Tcl Built-In Commands" .BS .SH NAME encoding \- Manipulate encodings .SH SYNOPSIS \fBencoding \fIoption\fR ?\fIarg arg ...\fR? .BE .SH INTRODUCTION .PP Strings in Tcl are encoded using 16-bit Unicode characters. Different operating system interfaces or applications may generate strings in other encodings such as Shift-JIS. The \fBencoding\fR command helps to bridge the gap between Unicode and these other formats. .SH DESCRIPTION .PP Performs one of several encoding related operations, depending on \fIoption\fR. The legal \fIoption\fRs are: .TP \fBencoding convertfrom\fR ?\fIencoding\fR? \fIdata\fR Convert \fIdata\fR to Unicode from the specified \fIencoding\fR. The characters in \fIdata\fR are treated as binary data where the lower 8-bits of each character is taken as a single byte. The resulting sequence of bytes is treated as a string in the specified \fIencoding\fR. If \fIencoding\fR is not specified, the current system encoding is used. .TP \fBencoding convertto\fR ?\fIencoding\fR? \fIstring\fR Convert \fIstring\fR from Unicode to the specified \fIencoding\fR. The result is a sequence of bytes that represents the converted string. Each byte is stored in the lower 8-bits of a Unicode character. If \fIencoding\fR is not specified, the current system encoding is used. .TP \fBencoding names\fR Returns a list containing the names of all of the encodings that are currently available. .TP \fBencoding system\fR ?\fIencoding\fR? Set the system encoding to \fIencoding\fR. If \fIencoding\fR is omitted then the command returns the current system encoding. The system encoding is used whenever Tcl passes strings to system calls. .SH EXAMPLE .PP It is common practice to write script files using a text editor that produces output in the euc-jp encoding, which represents the ASCII characters as singe bytes and Japanese characters as two bytes. This makes it easy to embed literal strings that correspond to non-ASCII characters by simply typing the strings in place in the script. However, because the \fBsource\fR command always reads files using the current system encoding, Tcl will only source such files correctly when the encoding used to write the file is the same. This tends not to be true in an internationalized setting. For example, if such a file was sourced in North America (where the ISO8859-1 is normally used), each byte in the file would be treated as a separate character that maps to the 00 page in Unicode. The resulting Tcl strings will not contain the expected Japanese characters. Instead, they will contain a sequence of Latin-1 characters that correspond to the bytes of the original string. The \fBencoding\fR command can be used to convert this string to the expected Japanese Unicode characters. For example, .CS set s [\fBencoding convertfrom\fR euc-jp "\\xA4\\xCF"] .CE would return the Unicode string "\\u306F", which is the Hiragana letter HA. .SH "SEE ALSO" Tcl_GetEncoding(3) .SH KEYWORDS encoding tcl8.4.20/doc/CrtObjCmd.30000644003604700454610000003146611737050674013371 0ustar dgp771div'\" '\" Copyright (c) 1996-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_CreateObjCommand 3 8.0 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_CreateObjCommand, Tcl_DeleteCommand, Tcl_DeleteCommandFromToken, Tcl_GetCommandInfo, Tcl_GetCommandInfoFromToken, Tcl_SetCommandInfo, Tcl_SetCommandInfoFromToken, Tcl_GetCommandName, Tcl_GetCommandFullName, Tcl_GetCommandFromObj \- implement new commands in C .SH SYNOPSIS .nf \fB#include \fR .sp Tcl_Command \fBTcl_CreateObjCommand\fR(\fIinterp, cmdName, proc, clientData, deleteProc\fR) .sp int \fBTcl_DeleteCommand\fR(\fIinterp, cmdName\fR) .sp int \fBTcl_DeleteCommandFromToken\fR(\fIinterp, token\fR) .sp int \fBTcl_GetCommandInfo\fR(\fIinterp, cmdName, infoPtr\fR) .sp int \fBTcl_SetCommandInfo\fR(\fIinterp, cmdName, infoPtr\fR) .sp .VS 8.4 int \fBTcl_GetCommandInfoFromToken\fR(\fItoken, infoPtr\fR) .sp int \fBTcl_SetCommandInfoFromToken\fR(\fItoken, infoPtr\fR) .VE .sp .VS 8.4 CONST char * .VE \fBTcl_GetCommandName\fR(\fIinterp, token\fR) .sp void \fBTcl_GetCommandFullName\fR(\fIinterp, token, objPtr\fR) .sp Tcl_Command \fBTcl_GetCommandFromObj\fR(\fIinterp, objPtr\fR) .SH ARGUMENTS .AS Tcl_ObjCmdProc *deleteProc in/out .AP Tcl_Interp *interp in Interpreter in which to create a new command or that contains a command. .VS 8.4 .AP char *cmdName in .VE Name of command. .AP Tcl_ObjCmdProc *proc in Implementation of the new command: \fIproc\fR will be called whenever \fIcmdName\fR is invoked as a command. .AP ClientData clientData in Arbitrary one-word value to pass to \fIproc\fR and \fIdeleteProc\fR. .AP Tcl_CmdDeleteProc *deleteProc in Procedure to call before \fIcmdName\fR is deleted from the interpreter; allows for command-specific cleanup. If NULL, then no procedure is called before the command is deleted. .AP Tcl_Command token in Token for command, returned by previous call to \fBTcl_CreateObjCommand\fR. The command must not have been deleted. .AP Tcl_CmdInfo *infoPtr in/out Pointer to structure containing various information about a Tcl command. .AP Tcl_Obj *objPtr in Object containing the name of a Tcl command. .BE .SH DESCRIPTION .PP \fBTcl_CreateObjCommand\fR defines a new command in \fIinterp\fR and associates it with procedure \fIproc\fR such that whenever \fIname\fR is invoked as a Tcl command (e.g., via a call to \fBTcl_EvalObjEx\fR) the Tcl interpreter will call \fIproc\fR to process the command. .PP \fBTcl_CreateObjCommand\fR deletes any existing command \fIname\fR already associated with the interpreter (however see below for an exception where the existing command is not deleted). It returns a token that may be used to refer to the command in subsequent calls to \fBTcl_GetCommandName\fR. If \fIname\fR contains any \fB::\fR namespace qualifiers, then the command is added to the specified namespace; otherwise the command is added to the global namespace. If \fBTcl_CreateObjCommand\fR is called for an interpreter that is in the process of being deleted, then it does not create a new command and it returns NULL. \fIproc\fR should have arguments and result that match the type \fBTcl_ObjCmdProc\fR: .CS typedef int Tcl_ObjCmdProc( ClientData \fIclientData\fR, Tcl_Interp *\fIinterp\fR, int \fIobjc\fR, .VS Tcl_Obj *CONST \fIobjv\fR[]); .CE When \fIproc\fR is invoked, the \fIclientData\fR and \fIinterp\fR parameters will be copies of the \fIclientData\fR and \fIinterp\fR arguments given to \fBTcl_CreateObjCommand\fR. Typically, \fIclientData\fR points to an application-specific data structure that describes what to do when the command procedure is invoked. \fIObjc\fR and \fIobjv\fR describe the arguments to the command, \fIobjc\fR giving the number of argument objects (including the command name) and \fIobjv\fR giving the values of the arguments. The \fIobjv\fR array will contain \fIobjc\fR values, pointing to the argument objects. Unlike \fIargv\fR[\fIargv\fR] used in a string-based command procedure, \fIobjv\fR[\fIobjc\fR] will not contain NULL. .PP Additionally, when \fIproc\fR is invoked, it must not modify the contents of the \fIobjv\fR array by assigning new pointer values to any element of the array (for example, \fIobjv\fR[\fB2\fR] = \fBNULL\fR) because this will cause memory to be lost and the runtime stack to be corrupted. The \fBCONST\fR in the declaration of \fIobjv\fR will cause ANSI-compliant compilers to report any such attempted assignment as an error. However, it is acceptable to modify the internal representation of any individual object argument. For instance, the user may call \fBTcl_GetIntFromObj\fR on \fIobjv\fR[\fB2\fR] to obtain the integer representation of that object; that call may change the type of the object that \fIobjv\fR[\fB2\fR] points at, but will not change where \fIobjv\fR[\fB2\fR] points. .VE .PP \fIproc\fR must return an integer code that is either \fBTCL_OK\fR, \fBTCL_ERROR\fR, \fBTCL_RETURN\fR, \fBTCL_BREAK\fR, or \fBTCL_CONTINUE\fR. See the Tcl overview man page for details on what these codes mean. Most normal commands will only return \fBTCL_OK\fR or \fBTCL_ERROR\fR. In addition, if \fIproc\fR needs to return a non-empty result, it can call \fBTcl_SetObjResult\fR to set the interpreter's result. In the case of a \fBTCL_OK\fR return code this gives the result of the command, and in the case of \fBTCL_ERROR\fR this gives an error message. Before invoking a command procedure, \fBTcl_EvalObjEx\fR sets interpreter's result to point to an object representing an empty string, so simple commands can return an empty result by doing nothing at all. .PP The contents of the \fIobjv\fR array belong to Tcl and are not guaranteed to persist once \fIproc\fR returns: \fIproc\fR should not modify them. Call \fBTcl_SetObjResult\fR if you want to return something from the \fIobjv\fR array. .PP Ordinarily, \fBTcl_CreateObjCommand\fR deletes any existing command \fIname\fR already associated with the interpreter. However, if the existing command was created by a previous call to \fBTcl_CreateCommand\fR, \fBTcl_CreateObjCommand\fR does not delete the command but instead arranges for the Tcl interpreter to call the \fBTcl_ObjCmdProc\fR \fIproc\fR in the future. The old string-based \fBTcl_CmdProc\fR associated with the command is retained and its address can be obtained by subsequent \fBTcl_GetCommandInfo\fR calls. This is done for backwards compatibility. .PP \fIDeleteProc\fR will be invoked when (if) \fIname\fR is deleted. This can occur through a call to \fBTcl_DeleteCommand\fR, \fBTcl_DeleteCommandFromToken\fR, or \fBTcl_DeleteInterp\fR, or by replacing \fIname\fR in another call to \fBTcl_CreateObjCommand\fR. \fIDeleteProc\fR is invoked before the command is deleted, and gives the application an opportunity to release any structures associated with the command. \fIDeleteProc\fR should have arguments and result that match the type \fBTcl_CmdDeleteProc\fR: .CS typedef void Tcl_CmdDeleteProc(ClientData \fIclientData\fR); .CE The \fIclientData\fR argument will be the same as the \fIclientData\fR argument passed to \fBTcl_CreateObjCommand\fR. .PP \fBTcl_DeleteCommand\fR deletes a command from a command interpreter. Once the call completes, attempts to invoke \fIcmdName\fR in \fIinterp\fR will result in errors. If \fIcmdName\fR isn't bound as a command in \fIinterp\fR then \fBTcl_DeleteCommand\fR does nothing and returns -1; otherwise it returns 0. There are no restrictions on \fIcmdName\fR: it may refer to a built-in command, an application-specific command, or a Tcl procedure. If \fIname\fR contains any \fB::\fR namespace qualifiers, the command is deleted from the specified namespace. .PP Given a token returned by \fBTcl_CreateObjCommand\fR, \fBTcl_DeleteCommandFromToken\fR deletes the command from a command interpreter. It will delete a command even if that command has been renamed. Once the call completes, attempts to invoke the command in \fIinterp\fR will result in errors. If the command corresponding to \fItoken\fR has already been deleted from \fIinterp\fR then \fBTcl_DeleteCommand\fR does nothing and returns -1; otherwise it returns 0. .PP \fBTcl_GetCommandInfo\fR checks to see whether its \fIcmdName\fR argument exists as a command in \fIinterp\fR. \fIcmdName\fR may include \fB::\fR namespace qualifiers to identify a command in a particular namespace. If the command is not found, then it returns 0. Otherwise it places information about the command in the \fBTcl_CmdInfo\fR structure pointed to by \fIinfoPtr\fR and returns 1. A \fBTcl_CmdInfo\fR structure has the following fields: .CS typedef struct Tcl_CmdInfo { int isNativeObjectProc; Tcl_ObjCmdProc *objProc; ClientData objClientData; Tcl_CmdProc *proc; ClientData clientData; Tcl_CmdDeleteProc *deleteProc; ClientData deleteData; Tcl_Namespace *namespacePtr; } Tcl_CmdInfo; .CE The \fIisNativeObjectProc\fR field has the value 1 if \fBTcl_CreateObjCommand\fR was called to register the command; it is 0 if only \fBTcl_CreateCommand\fR was called. It allows a program to determine whether it is faster to call \fIobjProc\fR or \fIproc\fR: \fIobjProc\fR is normally faster if \fIisNativeObjectProc\fR has the value 1. The fields \fIobjProc\fR and \fIobjClientData\fR have the same meaning as the \fIproc\fR and \fIclientData\fR arguments to \fBTcl_CreateObjCommand\fR; they hold information about the object-based command procedure that the Tcl interpreter calls to implement the command. The fields \fIproc\fR and \fIclientData\fR hold information about the string-based command procedure that implements the command. If \fBTcl_CreateCommand\fR was called for this command, this is the procedure passed to it; otherwise, this is a compatibility procedure registered by \fBTcl_CreateObjCommand\fR that simply calls the command's object-based procedure after converting its string arguments to Tcl objects. The field \fIdeleteData\fR is the ClientData value to pass to \fIdeleteProc\fR; it is normally the same as \fIclientData\fR but may be set independently using the \fBTcl_SetCommandInfo\fR procedure. The field \fInamespacePtr\fR holds a pointer to the Tcl_Namespace that contains the command. .PP \fBTcl_GetCommandInfoFromToken\fR is identical to \fBTcl_GetCommandInfo\fR except that it uses a command token returned from \fBTcl_CreateObjCommand\fR in place of the command name. If the \fItoken\fR parameter is NULL, it returns 0; otherwise, it returns 1 and fills in the structure designated by \fIinfoPtr\fR. .PP \fBTcl_SetCommandInfo\fR is used to modify the procedures and ClientData values associated with a command. Its \fIcmdName\fR argument is the name of a command in \fIinterp\fR. \fIcmdName\fR may include \fB::\fR namespace qualifiers to identify a command in a particular namespace. If this command does not exist then \fBTcl_SetCommandInfo\fR returns 0. Otherwise, it copies the information from \fI*infoPtr\fR to Tcl's internal structure for the command and returns 1. .PP \fBTcl_SetCommandInfoFromToken\fR is identical to \fBTcl_SetCommandInfo\fR except that it takes a command token as returned by \fBTcl_CreateObjCommand\fR instead of the command name. If the \fItoken\fR parameter is NULL, it returns 0. Otherwise, it copies the information from \fI*infoPtr\fR to Tcl's internal structure for the command and returns 1. .PP Note that \fBTcl_SetCommandInfo\fR and \fBTcl_SetCommandInfoFromToken\fR both allow the ClientData for a command's deletion procedure to be given a different value than the ClientData for its command procedure. .PP Note that neither \fBTcl_SetCommandInfo\fR nor \fBTcl_SetCommandInfoFromToken\fR will change a command's namespace. Use \fBTcl_Eval\fR to call the \fBrename\fR command to do that. .PP \fBTcl_GetCommandName\fR provides a mechanism for tracking commands that have been renamed. Given a token returned by \fBTcl_CreateObjCommand\fR when the command was created, \fBTcl_GetCommandName\fR returns the string name of the command. If the command has been renamed since it was created, then \fBTcl_GetCommandName\fR returns the current name. This name does not include any \fB::\fR namespace qualifiers. The command corresponding to \fItoken\fR must not have been deleted. The string returned by \fBTcl_GetCommandName\fR is in dynamic memory owned by Tcl and is only guaranteed to retain its value as long as the command isn't deleted or renamed; callers should copy the string if they need to keep it for a long time. .PP \fBTcl_GetCommandFullName\fR produces the fully-qualified name of a command from a command token. The name, including all namespace prefixes, is appended to the object specified by \fIobjPtr\fP. .PP \fBTcl_GetCommandFromObj\fR returns a token for the command specified by the name in a \fBTcl_Obj\fP. The command name is resolved relative to the current namespace. Returns NULL if the command is not found. .SH "SEE ALSO" Tcl_CreateCommand, Tcl_ResetResult, Tcl_SetObjResult .SH KEYWORDS bind, command, create, delete, namespace, object tcl8.4.20/doc/Utf.30000644003604700454610000002455111737050674012315 0ustar dgp771div'\" '\" Copyright (c) 1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Utf 3 "8.1" Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_UniChar, Tcl_UniCharCaseMatch, Tcl_UniCharNcasecmp, Tcl_UniCharToUtf, Tcl_UtfToUniChar, Tcl_UniCharToUtfDString, Tcl_UtfToUniCharDString, Tcl_UniCharLen, Tcl_UniCharNcmp, Tcl_UtfCharComplete, Tcl_NumUtfChars, Tcl_UtfFindFirst, Tcl_UtfFindLast, Tcl_UtfNext, Tcl_UtfPrev, Tcl_UniCharAtIndex, Tcl_UtfAtIndex, Tcl_UtfBackslash \- routines for manipulating UTF-8 strings. .SH SYNOPSIS .nf \fB#include \fR .sp typedef ... Tcl_UniChar; .sp int \fBTcl_UniCharToUtf\fR(\fIch, buf\fR) .sp int \fBTcl_UtfToUniChar\fR(\fIsrc, chPtr\fR) .VS 8.4 .sp char * \fBTcl_UniCharToUtfDString\fR(\fIuniStr, numChars, dstPtr\fR) .sp Tcl_UniChar * \fBTcl_UtfToUniCharDString\fR(\fIsrc, len, dstPtr\fR) .VE 8.4 .sp int \fBTcl_UniCharLen\fR(\fIuniStr\fR) .sp int \fBTcl_UniCharNcmp\fR(\fIuniStr, uniStr, num\fR) .VS 8.4 .sp int \fBTcl_UniCharNcasecmp\fR(\fIuniStr, uniStr, num\fR) .sp int \fBTcl_UniCharCaseMatch\fR(\fIuniStr, uniPattern, nocase\fR) .VE 8.4 .sp int \fBTcl_UtfNcmp\fR(\fIsrc, src, num\fR) .sp int \fBTcl_UtfNcasecmp\fR(\fIsrc, src, num\fR) .sp int \fBTcl_UtfCharComplete\fR(\fIsrc, len\fR) .sp int \fBTcl_NumUtfChars\fR(\fIsrc, len\fR) .VS 8.4 .sp CONST char * \fBTcl_UtfFindFirst\fR(\fIsrc, ch\fR) .sp CONST char * \fBTcl_UtfFindLast\fR(\fIsrc, ch\fR) .sp CONST char * \fBTcl_UtfNext\fR(\fIsrc\fR) .sp CONST char * \fBTcl_UtfPrev\fR(\fIsrc, start\fR) .VE 8.4 .sp Tcl_UniChar \fBTcl_UniCharAtIndex\fR(\fIsrc, index\fR) .VS 8.4 .sp CONST char * \fBTcl_UtfAtIndex\fR(\fIsrc, index\fR) .VE 8.4 .sp int \fBTcl_UtfBackslash\fR(\fIsrc, readPtr, dst\fR) .SH ARGUMENTS .AS "CONST Tcl_UniChar" numChars in/out .AP char *buf out Buffer in which the UTF-8 representation of the Tcl_UniChar is stored. At most TCL_UTF_MAX bytes are stored in the buffer. .AP int ch in The Tcl_UniChar to be converted or examined. .AP Tcl_UniChar *chPtr out Filled with the Tcl_UniChar represented by the head of the UTF-8 string. .AP "CONST char" *src in Pointer to a UTF-8 string. .AP "CONST Tcl_UniChar" *uniStr in A null-terminated Unicode string. .AP "CONST Tcl_UniChar" *uniPattern in A null-terminated Unicode string. .AP int len in The length of the UTF-8 string in bytes (not UTF-8 characters). If negative, all bytes up to the first null byte are used. .AP int numChars in The length of the Unicode string in characters. Must be greater than or equal to 0. .AP "Tcl_DString" *dstPtr in/out A pointer to a previously-initialized \fBTcl_DString\fR. .AP "unsigned long" num in The number of characters to compare. .AP "CONST char" *start in Pointer to the beginning of a UTF-8 string. .AP int index in The index of a character (not byte) in the UTF-8 string. .AP int *readPtr out If non-NULL, filled with the number of bytes in the backslash sequence, including the backslash character. .AP char *dst out Buffer in which the bytes represented by the backslash sequence are stored. At most TCL_UTF_MAX bytes are stored in the buffer. .VS 8.4 .AP int nocase in Specifies whether the match should be done case-sensitive (0) or case-insensitive (1). .VE 8.4 .BE .SH DESCRIPTION .PP These routines convert between UTF-8 strings and Tcl_UniChars. A Tcl_UniChar is a Unicode character represented as an unsigned, fixed-size quantity. A UTF-8 character is a Unicode character represented as a varying-length sequence of up to TCL_UTF_MAX bytes. A multibyte UTF-8 sequence consists of a lead byte followed by some number of trail bytes. .PP \fBTCL_UTF_MAX\fR is the maximum number of bytes that it takes to represent one Unicode character in the UTF-8 representation. .PP \fBTcl_UniCharToUtf\fR stores the Tcl_UniChar \fIch\fR as a UTF-8 string in starting at \fIbuf\fR. The return value is the number of bytes stored in \fIbuf\fR. .PP \fBTcl_UtfToUniChar\fR reads one UTF-8 character starting at \fIsrc\fR and stores it as a Tcl_UniChar in \fI*chPtr\fR. The return value is the number of bytes read from \fIsrc\fR.. The caller must ensure that the source buffer is long enough such that this routine does not run off the end and dereference non-existent or random memory; if the source buffer is known to be null-terminated, this will not happen. If the input is not in proper UTF-8 format, \fBTcl_UtfToUniChar\fR will store the first byte of \fIsrc\fR in \fI*chPtr\fR as a Tcl_UniChar between 0x0000 and 0x00ff and return 1. .PP \fBTcl_UniCharToUtfDString\fR converts the given Unicode string to UTF-8, storing the result in a previously-initialized \fBTcl_DString\fR. You must specify the length of the given Unicode string. The return value is a pointer to the UTF-8 representation of the Unicode string. Storage for the return value is appended to the end of the \fBTcl_DString\fR. .PP \fBTcl_UtfToUniCharDString\fR converts the given UTF-8 string to Unicode, storing the result in the previously-initialized \fBTcl_DString\fR. you may either specify the length of the given UTF-8 string or "-1", in which case \fBTcl_UtfToUniCharDString\fR uses \fBstrlen\fR to calculate the length. The return value is a pointer to the Unicode representation of the UTF-8 string. Storage for the return value is appended to the end of the \fBTcl_DString\fR. The Unicode string is terminated with a Unicode null character. .PP \fBTcl_UniCharLen\fR corresponds to \fBstrlen\fR for Unicode characters. It accepts a null-terminated Unicode string and returns the number of Unicode characters (not bytes) in that string. .PP \fBTcl_UniCharNcmp\fR and \fBTcl_UniCharNcasecmp\fR correspond to \fBstrncmp\fR and \fBstrncasecmp\fR, respectively, for Unicode characters. They accepts two null-terminated Unicode strings and the number of characters to compare. Both strings are assumed to be at least \fIlen\fR characters long. \fBTcl_UniCharNcmp\fR compares the two strings character-by-character according to the Unicode character ordering. It returns an integer greater than, equal to, or less than 0 if the first string is greater than, equal to, or less than the second string respectively. \fBTcl_UniCharNcasecmp\fR is the Unicode case insensitive version. .PP .VS 8.4 \fBTcl_UniCharCaseMatch\fR is the Unicode equivalent to \fBTcl_StringCaseMatch\fR. It accepts a null-terminated Unicode string, a Unicode pattern, and a boolean value specifying whether the match should be case sensitive and returns whether the string matches the pattern. .VE 8.4 .PP \fBTcl_UtfNcmp\fR corresponds to \fBstrncmp\fR for UTF-8 strings. It accepts two null-terminated UTF-8 strings and the number of characters to compare. (Both strings are assumed to be at least \fIlen\fR characters long.) \fBTcl_UtfNcmp\fR compares the two strings character-by-character according to the Unicode character ordering. It returns an integer greater than, equal to, or less than 0 if the first string is greater than, equal to, or less than the second string respectively. .PP \fBTcl_UtfNcasecmp\fR corresponds to \fBstrncasecmp\fR for UTF-8 strings. It is similar to \fBTcl_UtfNcmp\fR except comparisons ignore differences in case when comparing upper, lower or title case characters. .PP \fBTcl_UtfCharComplete\fR returns 1 if the source UTF-8 string \fIsrc\fR of length \fIlen\fR bytes is long enough to be decoded by \fBTcl_UtfToUniChar\fR, or 0 otherwise. This function does not guarantee that the UTF-8 string is properly formed. This routine is used by procedures that are operating on a byte at a time and need to know if a full Tcl_UniChar has been seen. .PP \fBTcl_NumUtfChars\fR corresponds to \fBstrlen\fR for UTF-8 strings. It returns the number of Tcl_UniChars that are represented by the UTF-8 string \fIsrc\fR. The length of the source string is \fIlen\fR bytes. If the length is negative, all bytes up to the first null byte are used. .PP \fBTcl_UtfFindFirst\fR corresponds to \fBstrchr\fR for UTF-8 strings. It returns a pointer to the first occurrence of the Tcl_UniChar \fIch\fR in the null-terminated UTF-8 string \fIsrc\fR. The null terminator is considered part of the UTF-8 string. .PP \fBTcl_UtfFindLast\fR corresponds to \fBstrrchr\fR for UTF-8 strings. It returns a pointer to the last occurrence of the Tcl_UniChar \fIch\fR in the null-terminated UTF-8 string \fIsrc\fR. The null terminator is considered part of the UTF-8 string. .PP Given \fIsrc\fR, a pointer to some location in a UTF-8 string, \fBTcl_UtfNext\fR returns a pointer to the next UTF-8 character in the string. The caller must not ask for the next character after the last character in the string if the string is not terminated by a null character. .PP Given \fIsrc\fR, a pointer to some location in a UTF-8 string (or to a null byte immediately following such a string), \fBTcl_UtfPrev\fR returns a pointer to the closest preceding byte that starts a UTF-8 character. This function will not back up to a position before \fIstart\fR, the start of the UTF-8 string. If \fIsrc\fR was already at \fIstart\fR, the return value will be \fIstart\fR. .PP \fBTcl_UniCharAtIndex\fR corresponds to a C string array dereference or the Pascal Ord() function. It returns the Tcl_UniChar represented at the specified character (not byte) \fIindex\fR in the UTF-8 string \fIsrc\fR. The source string must contain at least \fIindex\fR characters. Behavior is undefined if a negative \fIindex\fR is given. .PP \fBTcl_UtfAtIndex\fR returns a pointer to the specified character (not byte) \fIindex\fR in the UTF-8 string \fIsrc\fR. The source string must contain at least \fIindex\fR characters. This is equivalent to calling \fBTcl_UtfNext\fR \fIindex\fR times. If a negative \fIindex\fR is given, the return pointer points to the first character in the source string. .PP \fBTcl_UtfBackslash\fR is a utility procedure used by several of the Tcl commands. It parses a backslash sequence and stores the properly formed UTF-8 character represented by the backslash sequence in the output buffer \fIdst\fR. At most TCL_UTF_MAX bytes are stored in the buffer. \fBTcl_UtfBackslash\fR modifies \fI*readPtr\fR to contain the number of bytes in the backslash sequence, including the backslash character. The return value is the number of bytes stored in the output buffer. .PP See the \fBTcl\fR manual entry for information on the valid backslash sequences. All of the sequences described in the Tcl manual entry are supported by \fBTcl_UtfBackslash\fR. .SH KEYWORDS utf, unicode, backslash tcl8.4.20/doc/expr.n0000644003604700454610000004056612052456743012632 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-2000 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH expr n 8.4 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME expr \- Evaluate an expression .SH SYNOPSIS \fBexpr \fIarg \fR?\fIarg arg ...\fR? .BE .SH DESCRIPTION .PP Concatenates \fIarg\fRs (adding separator spaces between them), evaluates the result as a Tcl expression, and returns the value. The operators permitted in Tcl expressions are a subset of the operators permitted in C expressions, and they have the same meaning and precedence as the corresponding C operators. Expressions almost always yield numeric results (integer or floating-point values). For example, the expression .CS \fBexpr 8.2 + 6\fR .CE evaluates to 14.2. Tcl expressions differ from C expressions in the way that operands are specified. Also, Tcl expressions support non-numeric operands and string comparisons. .SH OPERANDS .PP A Tcl expression consists of a combination of operands, operators, and parentheses. White space may be used between the operands and operators and parentheses; it is ignored by the expression's instructions. Where possible, operands are interpreted as integer values. Integer values may be specified in decimal (the normal case), in octal (if the first character of the operand is \fB0\fR), or in hexadecimal (if the first two characters of the operand are \fB0x\fR). If an operand does not have one of the integer formats given above, then it is treated as a floating-point number if that is possible. Floating-point numbers may be specified in any of the ways accepted by an ANSI-compliant C compiler (except that the \fBf\fR, \fBF\fR, \fBl\fR, and \fBL\fR suffixes will not be permitted in most installations). For example, all of the following are valid floating-point numbers: 2.1, 3., 6e4, 7.91e+16. If no numeric interpretation is possible (note that all literal operands that are not numeric or boolean must be quoted with either braces or with double quotes), then an operand is left as a string (and only a limited set of operators may be applied to it). .PP .VS 8.4 On 32-bit systems, integer values MAX_INT (0x7FFFFFFF) and MIN_INT (-0x80000000) will be represented as 32-bit values, and integer values outside that range will be represented as 64-bit values (if that is possible at all.) .VE 8.4 .PP Operands may be specified in any of the following ways: .IP [1] As a numeric value, either integer or floating-point. .IP [2] As a boolean value, using any form understood by \fBstring is boolean\fR. .IP [3] As a Tcl variable, using standard \fB$\fR notation. The variable's value will be used as the operand. .IP [4] As a string enclosed in double-quotes. The expression parser will perform backslash, variable, and command substitutions on the information between the quotes, and use the resulting value as the operand .IP [5] As a string enclosed in braces. The characters between the open brace and matching close brace will be used as the operand without any substitutions. .IP [6] As a Tcl command enclosed in brackets. The command will be executed and its result will be used as the operand. .IP [7] As a mathematical function whose arguments have any of the above forms for operands, such as \fBsin($x)\fR. See below for a list of defined functions. .LP Where the above substitutions occur (e.g. inside quoted strings), they are performed by the expression's instructions. However, the command parser may already have performed one round of substitution before the expression processor was called. As discussed below, it is usually best to enclose expressions in braces to prevent the command parser from performing substitutions on the contents. .PP For some examples of simple expressions, suppose the variable \fBa\fR has the value 3 and the variable \fBb\fR has the value 6. Then the command on the left side of each of the lines below will produce the value on the right side of the line: .CS .ta 6c \fBexpr 3.1 + $a 6.1 expr 2 + "$a.$b" 5.6 expr 4*[llength "6 2"] 8 expr {{word one} < "word $a"} 0\fR .CE .SH OPERATORS .PP The valid operators are listed below, grouped in decreasing order of precedence: .TP 20 \fB\-\0\0+\0\0~\0\0!\fR Unary minus, unary plus, bit-wise NOT, logical NOT. None of these operators may be applied to string operands, and bit-wise NOT may be applied only to integers. .TP 20 \fB*\0\0/\0\0%\fR Multiply, divide, remainder. None of these operators may be applied to string operands, and remainder may be applied only to integers. The remainder will always have the same sign as the divisor and an absolute value smaller than the divisor. .TP 20 \fB+\0\0\-\fR Add and subtract. Valid for any numeric operands. .TP 20 \fB<<\0\0>>\fR Left and right shift. Valid for integer operands only. A right shift always propagates the sign bit. .TP 20 \fB<\0\0>\0\0<=\0\0>=\fR Boolean less, greater, less than or equal, and greater than or equal. Each operator produces 1 if the condition is true, 0 otherwise. These operators may be applied to strings as well as numeric operands, in which case string comparison is used. .TP 20 \fB==\0\0!=\fR Boolean equal and not equal. Each operator produces a zero/one result. Valid for all operand types. .VS 8.4 .TP 20 \fBeq\0\0ne\fR Boolean string equal and string not equal. Each operator produces a zero/one result. The operand types are interpreted only as strings. .VE 8.4 .TP 20 \fB&\fR Bit-wise AND. Valid for integer operands only. .TP 20 \fB^\fR Bit-wise exclusive OR. Valid for integer operands only. .TP 20 \fB|\fR Bit-wise OR. Valid for integer operands only. .TP 20 \fB&&\fR Logical AND. Produces a 1 result if both operands are non-zero, 0 otherwise. Valid for boolean and numeric (integers or floating-point) operands only. .TP 20 \fB||\fR Logical OR. Produces a 0 result if both operands are zero, 1 otherwise. Valid for boolean and numeric (integers or floating-point) operands only. .TP 20 \fIx\fB?\fIy\fB:\fIz\fR If-then-else, as in C. If \fIx\fR evaluates to non-zero, then the result is the value of \fIy\fR. Otherwise the result is the value of \fIz\fR. The \fIx\fR operand must have a boolean or numeric value. .LP See the C manual for more details on the results produced by each operator. All of the binary operators group left-to-right within the same precedence level. For example, the command .CS \fBexpr 4*2 < 7\fR .CE returns 0. .PP The \fB&&\fR, \fB||\fR, and \fB?:\fR operators have ``lazy evaluation'', just as in C, which means that operands are not evaluated if they are not needed to determine the outcome. For example, in the command .CS \fBexpr {$v ? [a] : [b]}\fR .CE only one of \fB[a]\fR or \fB[b]\fR will actually be evaluated, depending on the value of \fB$v\fR. Note, however, that this is only true if the entire expression is enclosed in braces; otherwise the Tcl parser will evaluate both \fB[a]\fR and \fB[b]\fR before invoking the \fBexpr\fR command. .SH "MATH FUNCTIONS" .PP Tcl supports the following mathematical functions in expressions, all of which work solely with floating-point numbers unless otherwise noted: .DS .ta 3c 6c 9c \fBabs\fR \fBcosh\fR \fBlog\fR \fBsqrt\fR \fBacos\fR \fBdouble\fR \fBlog10\fR \fBsrand\fR \fBasin\fR \fBexp\fR \fBpow\fR \fBtan\fR \fBatan\fR \fBfloor\fR \fBrand\fR \fBtanh\fR \fBatan2\fR \fBfmod\fR \fBround\fR \fBwide\fR \fBceil\fR \fBhypot\fR \fBsin\fR \fBcos\fR \fBint\fR \fBsinh\fR .DE .PP .TP \fBabs(\fIarg\fB)\fR Returns the absolute value of \fIarg\fR. \fIArg\fR may be either integer or floating-point, and the result is returned in the same form. .TP \fBacos(\fIarg\fB)\fR Returns the arc cosine of \fIarg\fR, in the range [\fI0\fR,\fIpi\fR] radians. \fIArg\fR should be in the range [\fI-1\fR,\fI1\fR]. .TP \fBasin(\fIarg\fB)\fR Returns the arc sine of \fIarg\fR, in the range [\fI-pi/2\fR,\fIpi/2\fR] radians. \fIArg\fR should be in the range [\fI-1\fR,\fI1\fR]. .TP \fBatan(\fIarg\fB)\fR Returns the arc tangent of \fIarg\fR, in the range [\fI-pi/2\fR,\fIpi/2\fR] radians. .TP \fBatan2(\fIy, x\fB)\fR Returns the arc tangent of \fIy\fR/\fIx\fR, in the range [\fI-pi\fR,\fIpi\fR] radians. \fIx\fR and \fIy\fR cannot both be 0. If \fIx\fR is greater than \fI0\fR, this is equivalent to \fBatan(\fIy/x\fB)\fR. .TP \fBceil(\fIarg\fB)\fR Returns the smallest integral floating-point value (i.e. with a zero fractional part) not less than \fIarg\fR. .TP \fBcos(\fIarg\fB)\fR Returns the cosine of \fIarg\fR, measured in radians. .TP \fBcosh(\fIarg\fB)\fR Returns the hyperbolic cosine of \fIarg\fR. If the result would cause an overflow, an error is returned. .TP \fBdouble(\fIarg\fB)\fR If \fIarg\fR is a floating-point value, returns \fIarg\fR, otherwise converts \fIarg\fR to floating-point and returns the converted value. .TP \fBexp(\fIarg\fB)\fR Returns the exponential of \fIarg\fR, defined as \fIe\fR**\fIarg\fR. If the result would cause an overflow, an error is returned. .TP \fBfloor(\fIarg\fB)\fR Returns the largest integral floating-point value (i.e. with a zero fractional part) not greater than \fIarg\fR. .TP \fBfmod(\fIx, y\fB)\fR Returns the floating-point remainder of the division of \fIx\fR by \fIy\fR. If \fIy\fR is 0, an error is returned. .TP \fBhypot(\fIx, y\fB)\fR Computes the length of the hypotenuse of a right-angled triangle \fBsqrt(\fIx\fR*\fIx\fR+\fIy\fR*\fIy\fB)\fR. .TP \fBint(\fIarg\fB)\fR .VS 8.4 If \fIarg\fR is an integer value of the same width as the machine word, returns \fIarg\fR, otherwise converts \fIarg\fR to an integer (of the same size as a machine word, i.e. 32-bits on 32-bit systems, and 64-bits on 64-bit systems) by truncation and returns the converted value. .VE 8.4 .TP \fBlog(\fIarg\fB)\fR Returns the natural logarithm of \fIarg\fR. \fIArg\fR must be a positive value. .TP \fBlog10(\fIarg\fB)\fR Returns the base 10 logarithm of \fIarg\fR. \fIArg\fR must be a positive value. .TP \fBpow(\fIx, y\fB)\fR Computes the value of \fIx\fR raised to the power \fIy\fR. If \fIx\fR is negative, \fIy\fR must be an integer value. .TP \fBrand()\fR Returns a pseudo-random floating-point value in the range (\fI0\fR,\fI1\fR). The generator algorithm is a simple linear congruential generator that is not cryptographically secure. Each result from \fBrand\fR completely determines all future results from subsequent calls to \fBrand\fR, so \fBrand\fR should not be used to generate a sequence of secrets, such as one-time passwords. The seed of the generator is initialized from the internal clock of the machine or may be set with the \fBsrand\fR function. .TP \fBround(\fIarg\fB)\fR If \fIarg\fR is an integer value, returns \fIarg\fR, otherwise converts \fIarg\fR to integer by rounding and returns the converted value. .TP \fBsin(\fIarg\fB)\fR Returns the sine of \fIarg\fR, measured in radians. .TP \fBsinh(\fIarg\fB)\fR Returns the hyperbolic sine of \fIarg\fR. If the result would cause an overflow, an error is returned. .TP \fBsqrt(\fIarg\fB)\fR Returns the square root of \fIarg\fR. \fIArg\fR must be non-negative. .TP \fBsrand(\fIarg\fB)\fR The \fIarg\fR, which must be an integer, is used to reset the seed for the random number generator of \fBrand\fR. Returns the first random number (see \fBrand()\fR) from that seed. Each interpreter has its own seed. .TP \fBtan(\fIarg\fB)\fR Returns the tangent of \fIarg\fR, measured in radians. .TP \fBtanh(\fIarg\fB)\fR Returns the hyperbolic tangent of \fIarg\fR. .TP \fBwide(\fIarg\fB)\fR .VS 8.4 Converts \fIarg\fR to an integer value at least 64-bits wide (by sign-extension if \fIarg\fR is a 32-bit number) if it is not one already. .VE 8.4 .PP In addition to these predefined functions, applications may define additional functions using \fBTcl_CreateMathFunc\fR(). .SH "TYPES, OVERFLOW, AND PRECISION" .PP All internal computations involving integers are done with the C type \fIlong\fR, and all internal computations involving floating-point are done with the C type \fIdouble\fR. When converting a string to floating-point, exponent overflow is detected and results in a Tcl error. For conversion to integer from string, detection of overflow depends on the behavior of some routines in the local C library, so it should be regarded as unreliable. In any case, integer overflow and underflow are generally not detected reliably for intermediate results. Floating-point overflow and underflow are detected to the degree supported by the hardware, which is generally pretty reliable. .PP Conversion among internal representations for integer, floating-point, and string operands is done automatically as needed. For arithmetic computations, integers are used until some floating-point number is introduced, after which floating-point is used. For example, .CS \fBexpr 5 / 4\fR .CE returns 1, while .CS \fBexpr 5 / 4.0\fR \fBexpr 5 / ( [string length "abcd"] + 0.0 )\fR .CE both return 1.25. Floating-point values are always returned with a ``\fB.\fR'' or an \fBe\fR so that they will not look like integer values. For example, .CS \fBexpr 20.0/5.0\fR .CE returns \fB4.0\fR, not \fB4\fR. .SH "STRING OPERATIONS" .PP String values may be used as operands of the comparison operators, although the expression evaluator tries to do comparisons as integer or floating-point when it can, i.e., when all arguments to the operator allow numeric interpretations, .VS 8.4 except in the case of the \fBeq\fR and \fBne\fR operators. .VE 8.4 If one of the operands of a comparison is a string and the other has a numeric value, the numeric operand is converted back to a string using the C \fIsprintf\fR format specifier \fB%d\fR for integers and \fB%g\fR for floating-point values. For example, the commands .CS \fBexpr {"0x03" > "2"}\fR \fBexpr {"0y" > "0x12"}\fR .CE both return 1. The first comparison is done using integer comparison, and the second is done using string comparison. Because of Tcl's tendency to treat values as numbers whenever possible, it isn't generally a good idea to use operators like \fB==\fR when you really want string comparison and the values of the operands could be arbitrary; it's better in these cases to use .VS 8.4 the \fBeq\fR or \fBne\fR operators, or .VE 8.4 the \fBstring\fR command instead. .SH "PERFORMANCE CONSIDERATIONS" .PP Enclose expressions in braces for the best speed and the smallest storage requirements. This allows the Tcl bytecode compiler to generate the best code. .PP As mentioned above, expressions are substituted twice: once by the Tcl parser and once by the \fBexpr\fR command. For example, the commands .CS \fBset a 3\fR \fBset b {$a + 2}\fR \fBexpr $b*4\fR .CE return 11, not a multiple of 4. This is because the Tcl parser will first substitute \fB$a + 2\fR for the variable \fBb\fR, then the \fBexpr\fR command will evaluate the expression \fB$a + 2*4\fR. .PP Most expressions do not require a second round of substitutions. Either they are enclosed in braces or, if not, their variable and command substitutions yield numbers or strings that don't themselves require substitutions. However, because a few unbraced expressions need two rounds of substitutions, the bytecode compiler must emit additional instructions to handle this situation. The most expensive code is required for unbraced expressions that contain command substitutions. These expressions must be implemented by generating new code each time the expression is executed. .SH EXAMPLES Define a procedure that computes an "interesting" mathematical function: .CS proc calc {x y} { \fBexpr\fR { ($x*$x - $y*$y) / exp($x*$x + $y*$y) } } .CE .PP Convert polar coordinates into cartesian coordinates: .CS # convert from ($radius,$angle) set x [\fBexpr\fR { $radius * cos($angle) }] set y [\fBexpr\fR { $radius * sin($angle) }] .CE .PP Convert cartesian coordinates into polar coordinates: .CS # convert from ($x,$y) set radius [\fBexpr\fR { hypot($y, $x) }] set angle [\fBexpr\fR { atan2($y, $x) }] .CE .PP Print a message describing the relationship of two string values to each other: .CS puts "a and b are [\fBexpr\fR {$a eq $b ? {equal} : {different}}]" .CE .PP Set a variable to whether an environment variable is both defined at all and also set to a true boolean value: .CS set isTrue [\fBexpr\fR { [info exists ::env(SOME_ENV_VAR)] && [string is true -strict $::env(SOME_ENV_VAR)] }] .CE .PP Generate a random integer in the range 0..99 inclusive: .CS set randNum [\fBexpr\fR { int(100 * rand()) }] .CE .SH "SEE ALSO" array(n), for(n), if(n), string(n), Tcl(n), while(n) .SH KEYWORDS arithmetic, boolean, compare, expression, fuzzy comparison tcl8.4.20/doc/safe.n0000644003604700454610000003626511737050674012575 0ustar dgp771div'\" '\" Copyright (c) 1995-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH "Safe Tcl" n 8.0 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME Safe\ Base \- A mechanism for creating and manipulating safe interpreters. .SH SYNOPSIS \fB::safe::interpCreate\fR ?\fIslave\fR? ?\fIoptions...\fR? .sp \fB::safe::interpInit\fR \fIslave\fR ?\fIoptions...\fR? .sp \fB::safe::interpConfigure\fR \fIslave\fR ?\fIoptions...\fR? .sp \fB::safe::interpDelete\fR \fIslave\fR .sp \fB::safe::interpAddToAccessPath\fR \fIslave\fR \fIdirectory\fR .sp \fB::safe::interpFindInAccessPath\fR \fIslave\fR \fIdirectory\fR .sp \fB::safe::setLogCmd\fR ?\fIcmd arg...\fR? .SH OPTIONS .PP ?\fB\-accessPath\fR \fIpathList\fR? ?\fB\-statics\fR \fIboolean\fR? ?\fB\-noStatics\fR? ?\fB\-nested\fR \fIboolean\fR? ?\fB\-nestedLoadOk\fR? ?\fB\-deleteHook\fR \fIscript\fR? .BE .SH DESCRIPTION Safe Tcl is a mechanism for executing untrusted Tcl scripts safely and for providing mediated access by such scripts to potentially dangerous functionality. .PP The Safe Base ensures that untrusted Tcl scripts cannot harm the hosting application. The Safe Base prevents integrity and privacy attacks. Untrusted Tcl scripts are prevented from corrupting the state of the hosting application or computer. Untrusted scripts are also prevented from disclosing information stored on the hosting computer or in the hosting application to any party. .PP The Safe Base allows a master interpreter to create safe, restricted interpreters that contain a set of predefined aliases for the \fBsource\fR, \fBload\fR, \fBfile\fR, \fBencoding\fR, and \fBexit\fR commands and are able to use the auto-loading and package mechanisms. .PP No knowledge of the file system structure is leaked to the safe interpreter, because it has access only to a virtualized path containing tokens. When the safe interpreter requests to source a file, it uses the token in the virtual path as part of the file name to source; the master interpreter transparently translates the token into a real directory name and executes the requested operation (see the section \fBSECURITY\fR below for details). Different levels of security can be selected by using the optional flags of the commands described below. .PP All commands provided in the master interpreter by the Safe Base reside in the \fBsafe\fR namespace: .SH COMMANDS The following commands are provided in the master interpreter: .TP \fB::safe::interpCreate\fR ?\fIslave\fR? ?\fIoptions...\fR? Creates a safe interpreter, installs the aliases described in the section \fBALIASES\fR and initializes the auto-loading and package mechanism as specified by the supplied \fBoptions\fR. See the \fBOPTIONS\fR section below for a description of the optional arguments. If the \fIslave\fR argument is omitted, a name will be generated. \fB::safe::interpCreate\fR always returns the interpreter name. .TP \fB::safe::interpInit\fR \fIslave\fR ?\fIoptions...\fR? This command is similar to \fBinterpCreate\fR except it that does not create the safe interpreter. \fIslave\fR must have been created by some other means, like \fBinterp create \-safe\fR. .TP \fB::safe::interpConfigure\fR \fIslave\fR ?\fIoptions...\fR? If no \fIoptions\fR are given, returns the settings for all options for the named safe interpreter as a list of options and their current values for that \fIslave\fR. If a single additional argument is provided, it will return a list of 2 elements \fIname\fR and \fIvalue\fR where \fIname\fR is the full name of that option and \fIvalue\fR the current value for that option and the \fIslave\fR. If more than two additional arguments are provided, it will reconfigure the safe interpreter and change each and only the provided options. See the section on \fBOPTIONS\fR below for options description. Example of use: .RS .CS # Create a new interp with the same configuration as "$i0" : set i1 [eval safe::interpCreate [safe::interpConfigure $i0]] # Get the current deleteHook set dh [safe::interpConfigure $i0 \-del] # Change (only) the statics loading ok attribute of an interp # and its deleteHook (leaving the rest unchanged) : safe::interpConfigure $i0 \-delete {foo bar} \-statics 0 ; .CE .RE .TP \fB::safe::interpDelete\fR \fIslave\fR Deletes the safe interpreter and cleans up the corresponding master interpreter data structures. If a \fIdeleteHook\fR script was specified for this interpreter it is evaluated before the interpreter is deleted, with the name of the interpreter as an additional argument. .TP \fB::safe::interpFindInAccessPath\fR \fIslave\fR \fIdirectory\fR This command finds and returns the token for the real directory \fIdirectory\fR in the safe interpreter's current virtual access path. It generates an error if the directory is not found. Example of use: .RS .CS $slave eval [list set tk_library [::safe::interpFindInAccessPath $name $tk_library]] .CE .RE .TP \fB::safe::interpAddToAccessPath\fR \fIslave\fR \fIdirectory\fR This command adds \fIdirectory\fR to the virtual path maintained for the safe interpreter in the master, and returns the token that can be used in the safe interpreter to obtain access to files in that directory. If the directory is already in the virtual path, it only returns the token without adding the directory to the virtual path again. Example of use: .RS .CS $slave eval [list set tk_library [::safe::interpAddToAccessPath $name $tk_library]] .CE .RE .TP \fB::safe::setLogCmd\fR ?\fIcmd arg...\fR? This command installs a script that will be called when interesting life cycle events occur for a safe interpreter. When called with no arguments, it returns the currently installed script. When called with one argument, an empty string, the currently installed script is removed and logging is turned off. The script will be invoked with one additional argument, a string describing the event of interest. The main purpose is to help in debugging safe interpreters. Using this facility you can get complete error messages while the safe interpreter gets only generic error messages. This prevents a safe interpreter from seeing messages about failures and other events that might contain sensitive information such as real directory names. .RS Example of use: .CS ::safe::setLogCmd puts stderr .CE Below is the output of a sample session in which a safe interpreter attempted to source a file not found in its virtual access path. Note that the safe interpreter only received an error message saying that the file was not found: .CS NOTICE for slave interp10 : Created NOTICE for slave interp10 : Setting accessPath=(/foo/bar) staticsok=1 nestedok=0 deletehook=() NOTICE for slave interp10 : auto_path in interp10 has been set to {$p(:0:)} ERROR for slave interp10 : /foo/bar/init.tcl: no such file or directory .CE .RE .SH OPTIONS The following options are common to \fB::safe::interpCreate\fR, \fB::safe::interpInit\fR, and \fB::safe::interpConfigure\fR. Any option name can be abbreviated to its minimal non-ambiguous name. Option names are not case sensitive. .TP \fB\-accessPath\fR \fIdirectoryList\fR This option sets the list of directories from which the safe interpreter can \fBsource\fR and \fBload\fR files. If this option is not specified, or if it is given as the empty list, the safe interpreter will use the same directories as its master for auto-loading. See the section \fBSECURITY\fR below for more detail about virtual paths, tokens and access control. .TP \fB\-statics\fR \fIboolean\fR This option specifies if the safe interpreter will be allowed to load statically linked packages (like \fBload {} Tk\fR). The default value is \fBtrue\fR : safe interpreters are allowed to load statically linked packages. .TP \fB\-noStatics\fR This option is a convenience shortcut for \fB-statics false\fR and thus specifies that the safe interpreter will not be allowed to load statically linked packages. .TP \fB\-nested\fR \fIboolean\fR This option specifies if the safe interpreter will be allowed to load packages into its own sub-interpreters. The default value is \fBfalse\fR : safe interpreters are not allowed to load packages into their own sub-interpreters. .TP \fB\-nestedLoadOk\fR This option is a convenience shortcut for \fB-nested true\fR and thus specifies the safe interpreter will be allowed to load packages into its own sub-interpreters. .TP \fB\-deleteHook\fR \fIscript\fR When this option is given a non-empty \fIscript\fR, it will be evaluated in the master with the name of the safe interpreter as an additional argument just before actually deleting the safe interpreter. Giving an empty value removes any currently installed deletion hook script for that safe interpreter. The default value (\fB{}\fR) is not to have any deletion call back. .SH ALIASES The following aliases are provided in a safe interpreter: .TP \fBsource\fR \fIfileName\fR The requested file, a Tcl source file, is sourced into the safe interpreter if it is found. The \fBsource\fR alias can only source files from directories in the virtual path for the safe interpreter. The \fBsource\fR alias requires the safe interpreter to use one of the token names in its virtual path to denote the directory in which the file to be sourced can be found. See the section on \fBSECURITY\fR for more discussion of restrictions on valid filenames. .TP \fBload\fR \fIfileName\fR The requested file, a shared object file, is dynamically loaded into the safe interpreter if it is found. The filename must contain a token name mentioned in the virtual path for the safe interpreter for it to be found successfully. Additionally, the shared object file must contain a safe entry point; see the manual page for the \fBload\fR command for more details. .TP \fBfile\fR ?\fIsubCmd args...\fR? The \fBfile\fR alias provides access to a safe subset of the subcommands of the \fBfile\fR command; it allows only \fBdirname\fR, \fBjoin\fR, \fBextension\fR, \fBroot\fR, \fBtail\fR, \fBpathname\fR and \fBsplit\fR subcommands. For more details on what these subcommands do see the manual page for the \fBfile\fR command. .TP \fBencoding\fR ?\fIsubCmd args...\fR? The \fBencoding\fR alias provides access to a safe subset of the subcommands of the \fBencoding\fR command; it disallows setting of the system encoding, but allows all other subcommands including \fBsystem\fR to check the current encoding. .TP \fBexit\fR The calling interpreter is deleted and its computation is stopped, but the Tcl process in which this interpreter exists is not terminated. .SH SECURITY The Safe Base does not attempt to completely prevent annoyance and denial of service attacks. These forms of attack prevent the application or user from temporarily using the computer to perform useful work, for example by consuming all available CPU time or all available screen real estate. These attacks, while aggravating, are deemed to be of lesser importance in general than integrity and privacy attacks that the Safe Base is to prevent. .PP The commands available in a safe interpreter, in addition to the safe set as defined in \fBinterp\fR manual page, are mediated aliases for \fBsource\fR, \fBload\fR, \fBexit\fR, and safe subsets of \fBfile\fR and \fBencoding\fR. The safe interpreter can also auto-load code and it can request that packages be loaded. .PP Because some of these commands access the local file system, there is a potential for information leakage about its directory structure. To prevent this, commands that take file names as arguments in a safe interpreter use tokens instead of the real directory names. These tokens are translated to the real directory name while a request to, e.g., source a file is mediated by the master interpreter. This virtual path system is maintained in the master interpreter for each safe interpreter created by \fB::safe::interpCreate\fR or initialized by \fB::safe::interpInit\fR and the path maps tokens accessible in the safe interpreter into real path names on the local file system thus preventing safe interpreters from gaining knowledge about the structure of the file system of the host on which the interpreter is executing. The only valid file names arguments for the \fBsource\fR and \fBload\fR aliases provided to the slave are path in the form of \fB[file join \fR\fItoken filename\fR\fB]\fR (i.e. when using the native file path formats: \fItoken\fR\fB/\fR\fIfilename\fR on Unix, \fItoken\fR\fB\\\fIfilename\fR on Windows, and \fItoken\fR\fB:\fR\fIfilename\fR on the Mac), where \fItoken\fR is representing one of the directories of the \fIaccessPath\fR list and \fIfilename\fR is one file in that directory (no sub directories access are allowed). .PP When a token is used in a safe interpreter in a request to source or load a file, the token is checked and translated to a real path name and the file to be sourced or loaded is located on the file system. The safe interpreter never gains knowledge of the actual path name under which the file is stored on the file system. .PP To further prevent potential information leakage from sensitive files that are accidentally included in the set of files that can be sourced by a safe interpreter, the \fBsource\fR alias restricts access to files meeting the following constraints: the file name must fourteen characters or shorter, must not contain more than one dot ("\fB.\fR"), must end up with the extension \fB.tcl\fR or be called \fBtclIndex\fR. .PP Each element of the initial access path list will be assigned a token that will be set in the slave \fBauto_path\fR and the first element of that list will be set as the \fBtcl_library\fR for that slave. .PP If the access path argument is not given or is the empty list, the default behavior is to let the slave access the same packages as the master has access to (Or to be more precise: only packages written in Tcl (which by definition can't be dangerous as they run in the slave interpreter) and C extensions that provides a Safe_Init entry point). For that purpose, the master's \fBauto_path\fR will be used to construct the slave access path. In order that the slave successfully loads the Tcl library files (which includes the auto-loading mechanism itself) the \fBtcl_library\fR will be added or moved to the first position if necessary, in the slave access path, so the slave \fBtcl_library\fR will be the same as the master's (its real path will still be invisible to the slave though). In order that auto-loading works the same for the slave and the master in this by default case, the first-level sub directories of each directory in the master \fBauto_path\fR will also be added (if not already included) to the slave access path. You can always specify a more restrictive path for which sub directories will never be searched by explicitly specifying your directory list with the \fB\-accessPath\fR flag instead of relying on this default mechanism. .PP When the \fIaccessPath\fR is changed after the first creation or initialization (i.e. through \fBinterpConfigure -accessPath \fR\fIlist\fR), an \fBauto_reset\fR is automatically evaluated in the safe interpreter to synchronize its \fBauto_index\fR with the new token list. .SH "SEE ALSO" interp(n), library(n), load(n), package(n), source(n), unknown(n) .SH KEYWORDS alias, auto\-loading, auto_mkindex, load, master interpreter, safe interpreter, slave interpreter, source tcl8.4.20/doc/Thread.30000644003604700454610000002133711737050674012765 0ustar dgp771div'\" '\" Copyright (c) 1999 Scriptics Corporation '\" Copyright (c) 1998 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Threads 3 "8.1" Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_ConditionNotify, Tcl_ConditionWait, Tcl_ConditionFinalize, Tcl_GetThreadData, Tcl_MutexLock, Tcl_MutexUnlock, Tcl_MutexFinalize, Tcl_CreateThread, Tcl_JoinThread \- Tcl thread support. .SH SYNOPSIS .nf \fB#include \fR .sp void \fBTcl_ConditionNotify\fR(\fIcondPtr\fR) .sp void \fBTcl_ConditionWait\fR(\fIcondPtr, mutexPtr, timePtr\fR) .sp void \fBTcl_ConditionFinalize\fR(\fIcondPtr\fR) .sp Void * \fBTcl_GetThreadData\fR(\fIkeyPtr, size\fR) .sp void \fBTcl_MutexLock\fR(\fImutexPtr\fR) .sp void \fBTcl_MutexUnlock\fR(\fImutexPtr\fR) .sp void \fBTcl_MutexFinalize\fR(\fImutexPtr\fR) .sp int \fBTcl_CreateThread\fR(\fIidPtr, threadProc, clientData, stackSize, flags\fR) .sp int \fBTcl_JoinThread\fR(\fIid, result\fR) .SH ARGUMENTS .AS Tcl_ThreadDataKey *keyPtr .AP Tcl_Condition *condPtr in A condition variable, which must be associated with a mutex lock. .AP Tcl_Mutex *mutexPtr in A mutex lock. .AP Tcl_Time *timePtr in A time limit on the condition wait. NULL to wait forever. Note that a polling value of 0 seconds doesn't make much sense. .AP Tcl_ThreadDataKey *keyPtr in This identifies a block of thread local storage. The key should be static and process-wide, yet each thread will end up associating a different block of storage with this key. .AP int *size in The size of the thread local storage block. This amount of data is allocated and initialized to zero the first time each thread calls \fBTcl_GetThreadData\fR. .AP Tcl_ThreadId *idPtr out The referred storage will contain the id of the newly created thread as returned by the operating system. .AP Tcl_ThreadId id in Id of the thread waited upon. .AP Tcl_ThreadCreateProc threadProc in This procedure will act as the \fBmain()\fR of the newly created thread. The specified \fIclientData\fR will be its sole argument. .AP ClientData clientData in Arbitrary information. Passed as sole argument to the \fIthreadProc\fR. .AP int stackSize in The size of the stack given to the new thread. .AP int flags in Bitmask containing flags allowing the caller to modify behaviour of the new thread. .AP int *result out The referred storage is used to place the exit code of the thread waited upon into it. .BE .SH INTRODUCTION Beginning with the 8.1 release, the Tcl core is thread safe, which allows you to incorporate Tcl into multithreaded applications without customizing the Tcl core. To enable Tcl multithreading support, you must include the \fB--enable-threads\fR option to \fBconfigure\fR when you configure and compile your Tcl core. .PP An important constraint of the Tcl threads implementation is that \fIonly the thread that created a Tcl interpreter can use that interpreter\fR. In other words, multiple threads can not access the same Tcl interpreter. (However, as was the case in previous releases, a single thread can safely create and use multiple interpreters.) .PP .VS 8.3.1 Tcl does provide \fBTcl_CreateThread\fR for creating threads. The caller can determine the size of the stack given to the new thread and modify the behaviour through the supplied \fIflags\fR. The value \fBTCL_THREAD_STACK_DEFAULT\fR for the \fIstackSize\fR indicates that the default size as specified by the operating system is to be used for the new thread. As for the flags, currently are only the values \fBTCL_THREAD_NOFLAGS\fR and \fBTCL_THREAD_JOINABLE\fR defined. The first of them invokes the default behaviour with no specialties. Using the second value marks the new thread as \fIjoinable\fR. This means that another thread can wait for the such marked thread to exit and join it. .PP Restrictions: On some unix systems the pthread-library does not contain the functionality to specify the stacksize of a thread. The specified value for the stacksize is ignored on these systems. Both Windows and Macintosh currently do not support joinable threads. This flag value is therefore ignored on these platforms. .VE .PP Tcl does provide \fBTcl_ExitThread\fR and \fBTcl_FinalizeThread\fR for terminating threads and invoking optional per-thread exit handlers. See the \fBTcl_Exit\fR page for more information on these procedures. .PP .VS The \fBTcl_JoinThread\fR function is provided to allow threads to wait upon the exit of another thread, which must have been marked as joinable through usage of the \fBTCL_THREAD_JOINABLE\fR-flag during its creation via \fBTcl_CreateThread\fR. .PP Trying to wait for the exit of a non-joinable thread or a thread which is already waited upon will result in an error. Waiting for a joinable thread which already exited is possible, the system will retain the necessary information until after the call to \fBTcl_JoinThread\fR. This means that not calling \fBTcl_JoinThread\fR for a joinable thread will cause a memory leak. .VE .PP Tcl provides \fBTcl_ThreadQueueEvent\fR and \fBTcl_ThreadAlert\fR for handling event queueing in multithreaded applications. See the \fBNotifier\fR manual page for more information on these procedures. .PP In this release, the Tcl language itself provides no support for creating multithreaded scripts (for example, scripts that could spawn a Tcl interpreter in a separate thread). If you need to add this feature at this time, see the \fItclThreadTest.c\fR file in the Tcl source distribution for an experimental implementation or use the Tcl "Threading Extension" package implementing thread creation and management commands at the script level. .SH DESCRIPTION A mutex is a lock that is used to serialize all threads through a piece of code by calling \fBTcl_MutexLock\fR and \fBTcl_MutexUnlock\fR. If one thread holds a mutex, any other thread calling \fBTcl_MutexLock\fR will block until \fBTcl_MutexUnlock\fR is called. .VS A mutex can be destroyed after its use by calling \fBTcl_MutexFinalize\fR. The result of locking a mutex twice from the same thread is undefined. On some platforms it will result in a deadlock. .VE The \fBTcl_MutexLock\fR, \fBTcl_MutexUnlock\fR and \fBTcl_MutexFinalize\fR procedures are defined as empty macros if not compiling with threads enabled. For declaration of mutexes the \fBTCL_DECLARE_MUTEX\fR macro should be used. This macro assures correct mutex handling even when the core is compiled without threads enabled. .PP A condition variable is used as a signaling mechanism: a thread can lock a mutex and then wait on a condition variable with \fBTcl_ConditionWait\fR. This atomically releases the mutex lock and blocks the waiting thread until another thread calls \fBTcl_ConditionNotify\fR. The caller of \fBTcl_ConditionNotify\fR should have the associated mutex held by previously calling \fBTcl_MutexLock\fR, but this is not enforced. Notifying the condition variable unblocks all threads waiting on the condition variable, but they do not proceed until the mutex is released with \fBTcl_MutexUnlock\fR. The implementation of \fBTcl_ConditionWait\fR automatically locks the mutex before returning. .PP The caller of \fBTcl_ConditionWait\fR should be prepared for spurious notifications by calling \fBTcl_ConditionWait\fR within a while loop that tests some invariant. .PP .VS A condition variable can be destroyed after its use by calling \fBTcl_ConditionFinalize\fR. .PP The \fBTcl_ConditionNotify\fR, \fBTcl_ConditionWait\fR and \fBTcl_ConditionFinalize\fR procedures are defined as empty macros if not compiling with threads enabled. .VE .PP The \fBTcl_GetThreadData\fR call returns a pointer to a block of thread-private data. Its argument is a key that is shared by all threads and a size for the block of storage. The storage is automatically allocated and initialized to all zeros the first time each thread asks for it. The storage is automatically deallocated by \fBTcl_FinalizeThread\fR. .SH INITIALIZATION .PP All of these synchronization objects are self initializing. They are implemented as opaque pointers that should be NULL upon first use. The mutexes and condition variables are .VS either cleaned up by process exit handlers (if living that long) or explicitly by calls to \fBTcl_MutexFinalize\fR or \fBTcl_ConditionFinalize\fR. .VE Thread local storage is reclaimed during \fBTcl_FinalizeThread\fR. .SH "CREATING THREADS" The API to create threads is not finalized at this time. There are private facilities to create threads that contain a new Tcl interpreter, and to send scripts among threads. Dive into tclThreadTest.c and tclThread.c for examples. .SH "SEE ALSO" Tcl_GetCurrentThread, Tcl_ThreadQueueEvent, Tcl_ThreadAlert, Tcl_ExitThread, Tcl_FinalizeThread, Tcl_CreateThreadExitHandler, Tcl_DeleteThreadExitHandler .SH KEYWORDS thread, mutex, condition variable, thread local storage tcl8.4.20/doc/StrMatch.30000644003604700454610000000305411737050674013277 0ustar dgp771div'\" '\" Copyright (c) 1989-1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_StringMatch 3 8.1 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_StringMatch, Tcl_StringCaseMatch \- test whether a string matches a pattern .SH SYNOPSIS .nf \fB#include \fR .sp int \fBTcl_StringMatch\fR(\fIstring\fR, \fIpattern\fR) .sp int \fBTcl_StringCaseMatch\fR(\fIstring\fR, \fIpattern\fR, \fInocase\fR) .SH ARGUMENTS .AP char *string in String to test. .AP char *pattern in Pattern to match against string. May contain special characters from the set *?\e[]. .AP int nocase in Specifies whether the match should be done case-sensitive (0) or case-insensitive (1). .BE .SH DESCRIPTION .PP This utility procedure determines whether a string matches a given pattern. If it does, then \fBTcl_StringMatch\fR returns 1. Otherwise \fBTcl_StringMatch\fR returns 0. The algorithm used for matching is the same algorithm used in the ``string match'' Tcl command and is similar to the algorithm used by the C-shell for file name matching; see the Tcl manual entry for details. .VS 8.1 .PP In \fBTcl_StringCaseMatch\fR, the algorithm is the same, but you have the option to make the matching case-insensitive. If you choose this (by passing \fBnocase\fR as 1), then the string and pattern are essentially matched in the lower case. .VE 8.1 .SH KEYWORDS match, pattern, string tcl8.4.20/doc/Environment.30000644003604700454610000000170711737050674014061 0ustar dgp771div'\" '\" Copyright (c) 1997-1998 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_PutEnv 3 "7.5" Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_PutEnv \- procedures to manipulate the environment .SH SYNOPSIS .nf \fB#include \fR .sp int \fBTcl_PutEnv\fR(\fIstring\fR) .SH ARGUMENTS .AP "CONST char" *string in Info about environment variable in the form NAME=value. The \fIstring\fR argument is in the system encoding. .BE .SH DESCRIPTION .PP \fBTcl_PutEnv\fR sets an environment variable. The information is passed in a single string of the form NAME=value. This procedure is intended to be a stand-in for the UNIX \fBputenv\fR system call. All tcl-based applications using \fBputenv\fR should redefine it to \fBTcl_PutEnv\fR so that they will interface properly to the Tcl runtime. .SH KEYWORDS environment, variable tcl8.4.20/doc/Encoding.30000644003604700454610000006110111737050674013275 0ustar dgp771div'\" '\" Copyright (c) 1997-1998 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_GetEncoding 3 "8.1" Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_GetEncoding, Tcl_FreeEncoding, Tcl_ExternalToUtfDString, Tcl_ExternalToUtf, Tcl_UtfToExternalDString, Tcl_UtfToExternal, Tcl_WinTCharToUtf, Tcl_WinUtfToTChar, Tcl_GetEncodingName, Tcl_SetSystemEncoding, Tcl_GetEncodingNames, Tcl_CreateEncoding, Tcl_GetDefaultEncodingDir, Tcl_SetDefaultEncodingDir \- procedures for creating and using encodings. .SH SYNOPSIS .nf \fB#include \fR .sp Tcl_Encoding \fBTcl_GetEncoding\fR(\fIinterp, name\fR) .sp void \fBTcl_FreeEncoding\fR(\fIencoding\fR) .sp char * \fBTcl_ExternalToUtfDString\fR(\fIencoding, src, srcLen, dstPtr\fR) .sp int \fBTcl_ExternalToUtf\fR(\fIinterp, encoding, src, srcLen, flags, statePtr, dst, dstLen, srcReadPtr, dstWrotePtr, dstCharsPtr\fR) .sp char * \fBTcl_UtfToExternalDString\fR(\fIencoding, src, srcLen, dstPtr\fR) .sp int \fBTcl_UtfToExternal\fR(\fIinterp, encoding, src, srcLen, flags, statePtr, dst, dstLen, srcReadPtr, dstWrotePtr, dstCharsPtr\fR) .sp char * \fBTcl_WinTCharToUtf\fR(\fItsrc, srcLen, dstPtr\fR) .sp TCHAR * \fBTcl_WinUtfToTChar\fR(\fIsrc, srcLen, dstPtr\fR) .sp CONST char * \fBTcl_GetEncodingName\fR(\fIencoding\fR) .sp int \fBTcl_SetSystemEncoding\fR(\fIinterp, name\fR) .sp void \fBTcl_GetEncodingNames\fR(\fIinterp\fR) .sp Tcl_Encoding \fBTcl_CreateEncoding\fR(\fItypePtr\fR) .sp CONST char * \fBTcl_GetDefaultEncodingDir\fR(\fIvoid\fR) .sp void \fBTcl_SetDefaultEncodingDir\fR(\fIpath\fR) .SH ARGUMENTS .AS Tcl_EncodingState *dstWrotePtr .AP Tcl_Interp *interp in Interpreter to use for error reporting, or NULL if no error reporting is desired. .AP "CONST char" *name in Name of encoding to load. .AP Tcl_Encoding encoding in The encoding to query, free, or use for converting text. If \fIencoding\fR is NULL, the current system encoding is used. .AP "CONST char" *src in For the \fBTcl_ExternalToUtf\fR functions, an array of bytes in the specified encoding that are to be converted to UTF-8. For the \fBTcl_UtfToExternal\fR and \fBTcl_WinUtfToTChar\fR functions, an array of UTF-8 characters to be converted to the specified encoding. .AP "CONST TCHAR" *tsrc in An array of Windows TCHAR characters to convert to UTF-8. .AP int srcLen in Length of \fIsrc\fR or \fItsrc\fR in bytes. If the length is negative, the encoding-specific length of the string is used. .AP Tcl_DString *dstPtr out Pointer to an uninitialized or free \fBTcl_DString\fR in which the converted result will be stored. .AP int flags in Various flag bits OR-ed together. TCL_ENCODING_START signifies that the source buffer is the first block in a (potentially multi-block) input stream, telling the conversion routine to reset to an initial state and perform any initialization that needs to occur before the first byte is converted. TCL_ENCODING_END signifies that the source buffer is the last block in a (potentially multi-block) input stream, telling the conversion routine to perform any finalization that needs to occur after the last byte is converted and then to reset to an initial state. TCL_ENCODING_STOPONERROR signifies that the conversion routine should return immediately upon reading a source character that doesn't exist in the target encoding; otherwise a default fallback character will automatically be substituted. .AP Tcl_EncodingState *statePtr in/out Used when converting a (generally long or indefinite length) byte stream in a piece by piece fashion. The conversion routine stores its current state in \fI*statePtr\fR after \fIsrc\fR (the buffer containing the current piece) has been converted; that state information must be passed back when converting the next piece of the stream so the conversion routine knows what state it was in when it left off at the end of the last piece. May be NULL, in which case the value specified for \fIflags\fR is ignored and the source buffer is assumed to contain the complete string to convert. .AP char *dst out Buffer in which the converted result will be stored. No more than \fIdstLen\fR bytes will be stored in \fIdst\fR. .AP int dstLen in The maximum length of the output buffer \fIdst\fR in bytes. .AP int *srcReadPtr out Filled with the number of bytes from \fIsrc\fR that were actually converted. This may be less than the original source length if there was a problem converting some source characters. May be NULL. .AP int *dstWrotePtr out Filled with the number of bytes that were actually stored in the output buffer as a result of the conversion. May be NULL. .AP int *dstCharsPtr out Filled with the number of characters that correspond to the number of bytes stored in the output buffer. May be NULL. .AP Tcl_EncodingType *typePtr in Structure that defines a new type of encoding. .AP "CONST char" *path in A path to the location of the encoding file. .BE .SH INTRODUCTION .PP These routines convert between Tcl's internal character representation, UTF-8, and character representations used by various operating systems or file systems, such as Unicode, ASCII, or Shift-JIS. When operating on strings, such as such as obtaining the names of files or displaying characters using international fonts, the strings must be translated into one or possibly multiple formats that the various system calls can use. For instance, on a Japanese Unix workstation, a user might obtain a filename represented in the EUC-JP file encoding and then translate the characters to the jisx0208 font encoding in order to display the filename in a Tk widget. The purpose of the encoding package is to help bridge the translation gap. UTF-8 provides an intermediate staging ground for all the various encodings. In the example above, text would be translated into UTF-8 from whatever file encoding the operating system is using. Then it would be translated from UTF-8 into whatever font encoding the display routines require. .PP Some basic encodings are compiled into Tcl. Others can be defined by the user or dynamically loaded from encoding files in a platform-independent manner. .SH DESCRIPTION .PP \fBTcl_GetEncoding\fR finds an encoding given its \fIname\fR. The name may refer to a builtin Tcl encoding, a user-defined encoding registered by calling \fBTcl_CreateEncoding\fR, or a dynamically-loadable encoding file. The return value is a token that represents the encoding and can be used in subsequent calls to procedures such as \fBTcl_GetEncodingName\fR, \fBTcl_FreeEncoding\fR, and \fBTcl_UtfToExternal\fR. If the name did not refer to any known or loadable encoding, NULL is returned and an error message is returned in \fIinterp\fR. .PP The encoding package maintains a database of all encodings currently in use. The first time \fIname\fR is seen, \fBTcl_GetEncoding\fR returns an encoding with a reference count of 1. If the same \fIname\fR is requested further times, then the reference count for that encoding is incremented without the overhead of allocating a new encoding and all its associated data structures. .PP When an \fIencoding\fR is no longer needed, \fBTcl_FreeEncoding\fR should be called to release it. When an \fIencoding\fR is no longer in use anywhere (i.e., it has been freed as many times as it has been gotten) \fBTcl_FreeEncoding\fR will release all storage the encoding was using and delete it from the database. .PP \fBTcl_ExternalToUtfDString\fR converts a source buffer \fIsrc\fR from the specified \fIencoding\fR into UTF-8. The converted bytes are stored in \fIdstPtr\fR, which is then null-terminated. The caller should eventually call \fBTcl_DStringFree\fR to free any information stored in \fIdstPtr\fR. When converting, if any of the characters in the source buffer cannot be represented in the target encoding, a default fallback character will be used. The return value is a pointer to the value stored in the DString. .PP \fBTcl_ExternalToUtf\fR converts a source buffer \fIsrc\fR from the specified \fIencoding\fR into UTF-8. Up to \fIsrcLen\fR bytes are converted from the source buffer and up to \fIdstLen\fR converted bytes are stored in \fIdst\fR. In all cases, \fI*srcReadPtr\fR is filled with the number of bytes that were successfully converted from \fIsrc\fR and \fI*dstWrotePtr\fR is filled with the corresponding number of bytes that were stored in \fIdst\fR. The return value is one of the following: .RS .IP \fBTCL_OK\fR 29 All bytes of \fIsrc\fR were converted. .IP \fBTCL_CONVERT_NOSPACE\fR 29 The destination buffer was not large enough for all of the converted data; as many characters as could fit were converted though. .IP \fBTCL_CONVERT_MULTIBYTE\fR 29 The last fews bytes in the source buffer were the beginning of a multibyte sequence, but more bytes were needed to complete this sequence. A subsequent call to the conversion routine should pass a buffer containing the unconverted bytes that remained in \fIsrc\fR plus some further bytes from the source stream to properly convert the formerly split-up multibyte sequence. .IP \fBTCL_CONVERT_SYNTAX\fR 29 The source buffer contained an invalid character sequence. This may occur if the input stream has been damaged or if the input encoding method was misidentified. .IP \fBTCL_CONVERT_UNKNOWN\fR 29 The source buffer contained a character that could not be represented in the target encoding and TCL_ENCODING_STOPONERROR was specified. .RE .LP \fBTcl_UtfToExternalDString\fR converts a source buffer \fIsrc\fR from UTF-8 into the specified \fIencoding\fR. The converted bytes are stored in \fIdstPtr\fR, which is then terminated with the appropriate encoding-specific null. The caller should eventually call \fBTcl_DStringFree\fR to free any information stored in \fIdstPtr\fR. When converting, if any of the characters in the source buffer cannot be represented in the target encoding, a default fallback character will be used. The return value is a pointer to the value stored in the DString. .PP \fBTcl_UtfToExternal\fR converts a source buffer \fIsrc\fR from UTF-8 into the specified \fIencoding\fR. Up to \fIsrcLen\fR bytes are converted from the source buffer and up to \fIdstLen\fR converted bytes are stored in \fIdst\fR. In all cases, \fI*srcReadPtr\fR is filled with the number of bytes that were successfully converted from \fIsrc\fR and \fI*dstWrotePtr\fR is filled with the corresponding number of bytes that were stored in \fIdst\fR. The return values are the same as the return values for \fBTcl_ExternalToUtf\fR. .PP \fBTcl_WinUtfToTChar\fR and \fBTcl_WinTCharToUtf\fR are Windows-only convenience functions for converting between UTF-8 and Windows strings. On Windows 95 (as with the Macintosh and Unix operating systems), all strings exchanged between Tcl and the operating system are "char" based. On Windows NT, some strings exchanged between Tcl and the operating system are "char" oriented while others are in Unicode. By convention, in Windows a TCHAR is a character in the ANSI code page on Windows 95 and a Unicode character on Windows NT. .PP If you planned to use the same "char" based interfaces on both Windows 95 and Windows NT, you could use \fBTcl_UtfToExternal\fR and \fBTcl_ExternalToUtf\fR (or their \fBTcl_DString\fR equivalents) with an encoding of NULL (the current system encoding). On the other hand, if you planned to use the Unicode interface when running on Windows NT and the "char" interfaces when running on Windows 95, you would have to perform the following type of test over and over in your program (as represented in pseudo-code): .CS if (running NT) { encoding <- Tcl_GetEncoding("unicode"); nativeBuffer <- Tcl_UtfToExternal(encoding, utfBuffer); Tcl_FreeEncoding(encoding); } else { nativeBuffer <- Tcl_UtfToExternal(NULL, utfBuffer); .CE \fBTcl_WinUtfToTChar\fR and \fBTcl_WinTCharToUtf\fR automatically handle this test and use the proper encoding based on the current operating system. \fBTcl_WinUtfToTChar\fR returns a pointer to a TCHAR string, and \fBTcl_WinTCharToUtf\fR expects a TCHAR string pointer as the \fIsrc\fR string. Otherwise, these functions behave identically to \fBTcl_UtfToExternalDString\fR and \fBTcl_ExternalToUtfDString\fR. .PP \fBTcl_GetEncodingName\fR is roughly the inverse of \fBTcl_GetEncoding\fR. Given an \fIencoding\fR, the return value is the \fIname\fR argument that was used to create the encoding. The string returned by \fBTcl_GetEncodingName\fR is only guaranteed to persist until the \fIencoding\fR is deleted. The caller must not modify this string. .PP \fBTcl_SetSystemEncoding\fR sets the default encoding that should be used whenever the user passes a NULL value for the \fIencoding\fR argument to any of the other encoding functions. If \fIname\fR is NULL, the system encoding is reset to the default system encoding, \fBbinary\fR. If the name did not refer to any known or loadable encoding, TCL_ERROR is returned and an error message is left in \fIinterp\fR. Otherwise, this procedure increments the reference count of the new system encoding, decrements the reference count of the old system encoding, and returns TCL_OK. .PP \fBTcl_GetEncodingNames\fR sets the \fIinterp\fR result to a list consisting of the names of all the encodings that are currently defined or can be dynamically loaded, searching the encoding path specified by \fBTcl_SetDefaultEncodingDir\fR. This procedure does not ensure that the dynamically-loadable encoding files contain valid data, but merely that they exist. .PP \fBTcl_CreateEncoding\fR defines a new encoding and registers the C procedures that are called back to convert between the encoding and UTF-8. Encodings created by \fBTcl_CreateEncoding\fR are thereafter visible in the database used by \fBTcl_GetEncoding\fR. Just as with the \fBTcl_GetEncoding\fR procedure, the return value is a token that represents the encoding and can be used in subsequent calls to other encoding functions. \fBTcl_CreateEncoding\fR returns an encoding with a reference count of 1. If an encoding with the specified \fIname\fR already exists, then its entry in the database is replaced with the new encoding; the token for the old encoding will remain valid and continue to behave as before, but users of the new token will now call the new encoding procedures. .PP The \fItypePtr\fR argument to \fBTcl_CreateEncoding\fR contains information about the name of the encoding and the procedures that will be called to convert between this encoding and UTF-8. It is defined as follows: .PP .CS typedef struct Tcl_EncodingType { CONST char *\fIencodingName\fR; Tcl_EncodingConvertProc *\fItoUtfProc\fR; Tcl_EncodingConvertProc *\fIfromUtfProc\fR; Tcl_EncodingFreeProc *\fIfreeProc\fR; ClientData \fIclientData\fR; int \fInullSize\fR; } Tcl_EncodingType; .CE .PP The \fIencodingName\fR provides a string name for the encoding, by which it can be referred in other procedures such as \fBTcl_GetEncoding\fR. The \fItoUtfProc\fR refers to a callback procedure to invoke to convert text from this encoding into UTF-8. The \fIfromUtfProc\fR refers to a callback procedure to invoke to convert text from UTF-8 into this encoding. The \fIfreeProc\fR refers to a callback procedure to invoke when this encoding is deleted. The \fIfreeProc\fR field may be NULL. The \fIclientData\fR contains an arbitrary one-word value passed to \fItoUtfProc\fR, \fIfromUtfProc\fR, and \fIfreeProc\fR whenever they are called. Typically, this is a pointer to a data structure containing encoding-specific information that can be used by the callback procedures. For instance, two very similar encodings such as \fBascii\fR and \fBmacRoman\fR may use the same callback procedure, but use different values of \fIclientData\fR to control its behavior. The \fInullSize\fR specifies the number of zero bytes that signify end-of-string in this encoding. It must be \fB1\fR (for single-byte or multi-byte encodings like ASCII or Shift-JIS) or \fB2\fR (for double-byte encodings like Unicode). Constant-sized encodings with 3 or more bytes per character (such as CNS11643) are not accepted. .PP The callback procedures \fItoUtfProc\fR and \fIfromUtfProc\fR should match the type \fBTcl_EncodingConvertProc\fR: .PP .CS typedef int Tcl_EncodingConvertProc( ClientData \fIclientData\fR, CONST char *\fIsrc\fR, int \fIsrcLen\fR, int \fIflags\fR, Tcl_Encoding *\fIstatePtr\fR, char *\fIdst\fR, int \fIdstLen\fR, int *\fIsrcReadPtr\fR, int *\fIdstWrotePtr\fR, int *\fIdstCharsPtr\fR); .CE .PP The \fItoUtfProc\fR and \fIfromUtfProc\fR procedures are called by the \fBTcl_ExternalToUtf\fR or \fBTcl_UtfToExternal\fR family of functions to perform the actual conversion. The \fIclientData\fR parameter to these procedures is the same as the \fIclientData\fR field specified to \fBTcl_CreateEncoding\fR when the encoding was created. The remaining arguments to the callback procedures are the same as the arguments, documented at the top, to \fBTcl_ExternalToUtf\fR or \fBTcl_UtfToExternal\fR, with the following exceptions. If the \fIsrcLen\fR argument to one of those high-level functions is negative, the value passed to the callback procedure will be the appropriate encoding-specific string length of \fIsrc\fR. If any of the \fIsrcReadPtr\fR, \fIdstWrotePtr\fR, or \fIdstCharsPtr\fR arguments to one of the high-level functions is NULL, the corresponding value passed to the callback procedure will be a non-NULL location. .PP The callback procedure \fIfreeProc\fR, if non-NULL, should match the type \fBTcl_EncodingFreeProc\fR: .CS typedef void Tcl_EncodingFreeProc( ClientData \fIclientData\fR); .CE .PP This \fIfreeProc\fR function is called when the encoding is deleted. The \fIclientData\fR parameter is the same as the \fIclientData\fR field specified to \fBTcl_CreateEncoding\fR when the encoding was created. .PP \fBTcl_GetDefaultEncodingDir\fR and \fBTcl_SetDefaultEncodingDir\fR access and set the directory to use when locating the default encoding files. If this value is not NULL, the \fBTclpInitLibraryPath\fR routine appends the path to the head of the search path, and uses this path as the first place to look into when trying to locate the encoding file. .SH "ENCODING FILES" Space would prohibit precompiling into Tcl every possible encoding algorithm, so many encodings are stored on disk as dynamically-loadable encoding files. This behavior also allows the user to create additional encoding files that can be loaded using the same mechanism. These encoding files contain information about the tables and/or escape sequences used to map between an external encoding and Unicode. The external encoding may consist of single-byte, multi-byte, or double-byte characters. .PP Each dynamically-loadable encoding is represented as a text file. The initial line of the file, beginning with a ``#'' symbol, is a comment that provides a human-readable description of the file. The next line identifies the type of encoding file. It can be one of the following letters: .IP "[1] \fBS\fR" A single-byte encoding, where one character is always one byte long in the encoding. An example is \fBiso8859-1\fR, used by many European languages. .IP "[2] \fBD\fR" A double-byte encoding, where one character is always two bytes long in the encoding. An example is \fBbig5\fR, used for Chinese text. .IP "[3] \fBM\fR" A multi-byte encoding, where one character may be either one or two bytes long. Certain bytes are a lead bytes, indicating that another byte must follow and that together the two bytes represent one character. Other bytes are not lead bytes and represent themselves. An example is \fBshiftjis\fR, used by many Japanese computers. .IP "[4] \fBE\fR" An escape-sequence encoding, specifying that certain sequences of bytes do not represent characters, but commands that describe how following bytes should be interpreted. .PP The rest of the lines in the file depend on the type. .PP Cases [1], [2], and [3] are collectively referred to as table-based encoding files. The lines in a table-based encoding file are in the same format as this example taken from the \fBshiftjis\fR encoding (this is not the complete file): .CS # Encoding file: shiftjis, multi-byte M 003F 0 40 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D203E007F 0080000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FF61FF62FF63FF64FF65FF66FF67FF68FF69FF6AFF6BFF6CFF6DFF6EFF6F FF70FF71FF72FF73FF74FF75FF76FF77FF78FF79FF7AFF7BFF7CFF7DFF7EFF7F FF80FF81FF82FF83FF84FF85FF86FF87FF88FF89FF8AFF8BFF8CFF8DFF8EFF8F FF90FF91FF92FF93FF94FF95FF96FF97FF98FF99FF9AFF9BFF9CFF9DFF9EFF9F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 81 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 300030013002FF0CFF0E30FBFF1AFF1BFF1FFF01309B309C00B4FF4000A8FF3E FFE3FF3F30FD30FE309D309E30034EDD30053006300730FC20152010FF0F005C 301C2016FF5C2026202520182019201C201DFF08FF0930143015FF3BFF3DFF5B FF5D30083009300A300B300C300D300E300F30103011FF0B221200B100D70000 00F7FF1D2260FF1CFF1E22662267221E22342642264000B0203220332103FFE5 FF0400A200A3FF05FF03FF06FF0AFF2000A72606260525CB25CF25CE25C725C6 25A125A025B325B225BD25BC203B301221922190219121933013000000000000 000000000000000000000000000000002208220B2286228722822283222A2229 000000000000000000000000000000002227222800AC21D221D4220022030000 0000000000000000000000000000000000000000222022A52312220222072261 2252226A226B221A223D221D2235222B222C0000000000000000000000000000 212B2030266F266D266A2020202100B6000000000000000025EF000000000000 .CE .PP The third line of the file is three numbers. The first number is the fallback character (in base 16) to use when converting from UTF-8 to this encoding. The second number is a \fB1\fR if this file represents the encoding for a symbol font, or \fB0\fR otherwise. The last number (in base 10) is how many pages of data follow. .PP Subsequent lines in the example above are pages that describe how to map from the encoding into 2-byte Unicode. The first line in a page identifies the page number. Following it are 256 double-byte numbers, arranged as 16 rows of 16 numbers. Given a character in the encoding, the high byte of that character is used to select which page, and the low byte of that character is used as an index to select one of the double-byte numbers in that page \- the value obtained being the corresponding Unicode character. By examination of the example above, one can see that the characters 0x7E and 0x8163 in \fBshiftjis\fR map to 203E and 2026 in Unicode, respectively. .PP Following the first page will be all the other pages, each in the same format as the first: one number identifying the page followed by 256 double-byte Unicode characters. If a character in the encoding maps to the Unicode character 0000, it means that the character doesn't actually exist. If all characters on a page would map to 0000, that page can be omitted. .PP Case [4] is the escape-sequence encoding file. The lines in an this type of file are in the same format as this example taken from the \fBiso2022-jp\fR encoding: .CS .ta 1.5i # Encoding file: iso2022-jp, escape-driven E init {} final {} iso8859-1 \\x1b(B jis0201 \\x1b(J jis0208 \\x1b$@ jis0208 \\x1b$B jis0212 \\x1b$(D gb2312 \\x1b$A ksc5601 \\x1b$(C .CE .PP In the file, the first column represents an option and the second column is the associated value. \fBinit\fR is a string to emit or expect before the first character is converted, while \fBfinal\fR is a string to emit or expect after the last character. All other options are names of table-based encodings; the associated value is the escape-sequence that marks that encoding. Tcl syntax is used for the values; in the above example, for instance, ``\fB{}\fR'' represents the empty string and ``\fB\\x1b\fR'' represents character 27. .PP When \fBTcl_GetEncoding\fR encounters an encoding \fIname\fR that has not been loaded, it attempts to load an encoding file called \fIname\fB.enc\fR from the \fBencoding\fR subdirectory of each directory specified in the library path \fB$tcl_libPath\fR. If the encoding file exists, but is malformed, an error message will be left in \fIinterp\fR. .SH KEYWORDS utf, encoding, convert tcl8.4.20/doc/lappend.n0000644003604700454610000000274011737050674013271 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" Copyright (c) 2001 Kevin B. Kenny. All rights reserved. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH lappend n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME lappend \- Append list elements onto a variable .SH SYNOPSIS \fBlappend \fIvarName \fR?\fIvalue value value ...\fR? .BE .SH DESCRIPTION .PP This command treats the variable given by \fIvarName\fR as a list and appends each of the \fIvalue\fR arguments to that list as a separate element, with spaces between elements. If \fIvarName\fR doesn't exist, it is created as a list with elements given by the \fIvalue\fR arguments. \fBLappend\fR is similar to \fBappend\fR except that the \fIvalue\fRs are appended as list elements rather than raw text. This command provides a relatively efficient way to build up large lists. For example, ``\fBlappend a $b\fR'' is much more efficient than ``\fBset a [concat $a [list $b]]\fR'' when \fB$a\fR is long. .SH EXAMPLE Using \fBlappend\fR to build up a list of numbers. .CS % set var 1 1 % \fBlappend\fR var 2 1 2 % \fBlappend\fR var 3 4 5 1 2 3 4 5 .CE .SH "SEE ALSO" list(n), lindex(n), linsert(n), llength(n), .VS 8.4 lset(n) .VE lsort(n), lrange(n) .SH KEYWORDS append, element, list, variable tcl8.4.20/doc/Async.30000644003604700454610000001513211737050674012627 0ustar dgp771div'\" '\" Copyright (c) 1989-1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_AsyncCreate 3 7.0 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_AsyncCreate, Tcl_AsyncMark, Tcl_AsyncInvoke, Tcl_AsyncDelete, Tcl_AsyncReady \- handle asynchronous events .SH SYNOPSIS .nf \fB#include \fR .sp Tcl_AsyncHandler \fBTcl_AsyncCreate\fR(\fIproc, clientData\fR) .sp \fBTcl_AsyncMark\fR(\fIasync\fR) .sp int \fBTcl_AsyncInvoke\fR(\fIinterp, code\fR) .sp \fBTcl_AsyncDelete\fR(\fIasync\fR) .sp int \fBTcl_AsyncReady\fR() .SH ARGUMENTS .AS Tcl_AsyncHandler clientData .AP Tcl_AsyncProc *proc in Procedure to invoke to handle an asynchronous event. .AP ClientData clientData in One-word value to pass to \fIproc\fR. .AP Tcl_AsyncHandler async in Token for asynchronous event handler. .AP Tcl_Interp *interp in Tcl interpreter in which command was being evaluated when handler was invoked, or NULL if handler was invoked when there was no interpreter active. .AP int code in Completion code from command that just completed in \fIinterp\fR, or 0 if \fIinterp\fR is NULL. .BE .SH DESCRIPTION .PP These procedures provide a safe mechanism for dealing with asynchronous events such as signals. If an event such as a signal occurs while a Tcl script is being evaluated then it isn't safe to take any substantive action to process the event. For example, it isn't safe to evaluate a Tcl script since the interpreter may already be in the middle of evaluating a script; it may not even be safe to allocate memory, since a memory allocation could have been in progress when the event occurred. The only safe approach is to set a flag indicating that the event occurred, then handle the event later when the world has returned to a clean state, such as after the current Tcl command completes. .PP \fBTcl_AsyncCreate\fR, \fBTcl_AsyncDelete\fR, and \fBTcl_AsyncReady\fR are thread sensitive. They access and/or set a thread-specific data structure in the event of a core built with \fI\-\-enable\-threads\fR. The token created by \fBTcl_AsyncCreate\fR contains the needed thread information it was called from so that calling \fBTcl_AsyncMark\fR(\fItoken\fR) will only yield the origin thread into the asynchronous handler. .PP \fBTcl_AsyncCreate\fR creates an asynchronous handler and returns a token for it. The asynchronous handler must be created before any occurrences of the asynchronous event that it is intended to handle (it is not safe to create a handler at the time of an event). When an asynchronous event occurs the code that detects the event (such as a signal handler) should call \fBTcl_AsyncMark\fR with the token for the handler. \fBTcl_AsyncMark\fR will mark the handler as ready to execute, but it will not invoke the handler immediately. Tcl will call the \fIproc\fR associated with the handler later, when the world is in a safe state, and \fIproc\fR can then carry out the actions associated with the asynchronous event. \fIProc\fR should have arguments and result that match the type \fBTcl_AsyncProc\fR: .CS typedef int Tcl_AsyncProc( ClientData \fIclientData\fR, Tcl_Interp *\fIinterp\fR, int \fIcode\fR); .CE The \fIclientData\fR will be the same as the \fIclientData\fR argument passed to \fBTcl_AsyncCreate\fR when the handler was created. If \fIproc\fR is invoked just after a command has completed execution in an interpreter, then \fIinterp\fR will identify the interpreter in which the command was evaluated and \fIcode\fR will be the completion code returned by that command. The command's result will be present in the interpreter's result. When \fIproc\fR returns, whatever it leaves in the interpreter's result will be returned as the result of the command and the integer value returned by \fIproc\fR will be used as the new completion code for the command. .PP It is also possible for \fIproc\fR to be invoked when no interpreter is active. This can happen, for example, if an asynchronous event occurs while the application is waiting for interactive input or an X event. In this case \fIinterp\fR will be NULL and \fIcode\fR will be 0, and the return value from \fIproc\fR will be ignored. .PP The procedure \fBTcl_AsyncInvoke\fR is called to invoke all of the handlers that are ready. The procedure \fBTcl_AsyncReady\fR will return non-zero whenever any asynchronous handlers are ready; it can be checked to avoid calls to \fBTcl_AsyncInvoke\fR when there are no ready handlers. Tcl calls \fBTcl_AsyncReady\fR after each command is evaluated and calls \fBTcl_AsyncInvoke\fR if needed. Applications may also call \fBTcl_AsyncInvoke\fR at interesting times for that application. For example, Tcl's event handler calls \fBTcl_AsyncReady\fR after each event and calls \fBTcl_AsyncInvoke\fR if needed. The \fIinterp\fR and \fIcode\fR arguments to \fBTcl_AsyncInvoke\fR have the same meaning as for \fIproc\fR: they identify the active interpreter, if any, and the completion code from the command that just completed. .PP \fBTcl_AsyncDelete\fR removes an asynchronous handler so that its \fIproc\fR will never be invoked again. A handler can be deleted even when ready, and it will still not be invoked. .PP If multiple handlers become active at the same time, the handlers are invoked in the order they were created (oldest handler first). The \fIcode\fR and the interpreter's result for later handlers reflect the values returned by earlier handlers, so that the most recently created handler has last say about the interpreter's result and completion code. If new handlers become ready while handlers are executing, \fBTcl_AsyncInvoke\fR will invoke them all; at each point it invokes the highest-priority (oldest) ready handler, repeating this over and over until there are no longer any ready handlers. .SH WARNING .PP It is almost always a bad idea for an asynchronous event handler to modify the interpreter's result or return a code different from its \fIcode\fR argument. This sort of behavior can disrupt the execution of scripts in subtle ways and result in bugs that are extremely difficult to track down. If an asynchronous event handler needs to evaluate Tcl scripts then it should first save the interpreter's result plus the values of the variables \fBerrorInfo\fR and \fBerrorCode\fR (this can be done, for example, by storing them in dynamic strings). When the asynchronous handler is finished it should restore the interpreter's result, \fBerrorInfo\fR, and \fBerrorCode\fR, and return the \fIcode\fR argument. .SH KEYWORDS asynchronous event, handler, signal tcl8.4.20/doc/lset.n0000755003604700454610000000744211737050674012624 0ustar dgp771div'\" '\" Copyright (c) 2001 by Kevin B. Kenny. All rights reserved. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH lset n 8.4 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME lset \- Change an element in a list .SH SYNOPSIS \fBlset \fIvarName ?index...? newValue\fR .BE .SH DESCRIPTION .PP The \fBlset\fR command accepts a parameter, \fIvarName\fR, which it interprets as the name of a variable containing a Tcl list. It also accepts zero or more \fIindices\fR into the list. The indices may be presented either consecutively on the command line, or grouped in a Tcl list and presented as a single argument. Finally, it accepts a new value for an element of \fIvarName\fR. .PP If no indices are presented, the command takes the form: .CS lset varName newValue .CE or .CS lset varName {} newValue .CE In this case, \fInewValue\fR replaces the old value of the variable \fIvarName\fR. .PP When presented with a single index, the \fBlset\fR command treats the content of the \fIvarName\fR variable as a Tcl list. It addresses the \fIindex\fR'th element in it (0 refers to the first element of the list). When interpreting the list, \fBlset\fR observes the same rules concerning braces and quotes and backslashes as the Tcl command interpreter; however, variable substitution and command substitution do not occur. The command constructs a new list in which the designated element is replaced with \fInewValue\fR. This new list is stored in the variable \fIvarName\fR, and is also the return value from the \fBlset\fR command. .PP If \fIindex\fR is negative or greater than or equal to the number of elements in \fI$varName\fR, then an error occurs. .PP If \fIindex\fR has the value \fBend\fR, it refers to the last element in the list, and \fBend\-\fIinteger\fR refers to the last element in the list minus the specified integer offset. .PP If additional \fIindex\fR arguments are supplied, then each argument is used in turn to address an element within a sublist designated by the previous indexing operation, allowing the script to alter elements in sublists. The command, .CS lset a 1 2 newValue .CE or .CS lset a {1 2} newValue .CE replaces element 2 of sublist 1 with \fInewValue\fR. .PP The integer appearing in each \fIindex\fR argument must be greater than or equal to zero. The integer appearing in each \fIindex\fR argument must be strictly less than the length of the corresponding list. In other words, the \fBlset\fR command cannot change the size of a list. If an index is outside the permitted range, an error is reported. .SH EXAMPLES In each of these examples, the initial value of \fIx\fR is: .CS set x [list [list a b c] [list d e f] [list g h i]] => {a b c} {d e f} {g h i} .CE The indicated return value also becomes the new value of \fIx\fR (except in the last case, which is an error which leaves the value of \fIx\fR unchanged.) .CS lset x {j k l} => j k l lset x {} {j k l} => j k l lset x 0 j => j {d e f} {g h i} lset x 2 j => {a b c} {d e f} j lset x end j => {a b c} {d e f} j lset x end-1 j => {a b c} j {g h i} lset x 2 1 j => {a b c} {d e f} {g j i} lset x {2 1} j => {a b c} {d e f} {g j i} lset x {2 3} j => \fIlist index out of range\fR .CE In the following examples, the initial value of \fIx\fR is: .CS set x [list [list [list a b] [list c d]] \e [list [list e f] [list g h]]] => {{a b} {c d}} {{e f} {g h}} .CE The indicated return value also becomes the new value of \fIx\fR. .CS lset x 1 1 0 j => {{a b} {c d}} {{e f} {j h}} lset x {1 1 0} j => {{a b} {c d}} {{e f} {j h}} .CE .SH "SEE ALSO" list(n), lappend(n), lindex(n), linsert(n), llength(n), lsearch(n), lsort(n), lrange(n), lreplace(n) .SH KEYWORDS element, index, list, replace, set tcl8.4.20/doc/lreplace.n0000644003604700454610000000457411737050674013444 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" Copyright (c) 2001 Kevin B. Kenny. All rights reserved. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH lreplace n 7.4 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME lreplace \- Replace elements in a list with new elements .SH SYNOPSIS \fBlreplace \fIlist first last \fR?\fIelement element ...\fR? .BE .SH DESCRIPTION .PP \fBlreplace\fR returns a new list formed by replacing one or more elements of \fIlist\fR with the \fIelement\fR arguments. \fIfirst\fR and \fIlast\fR specify the first and last index of the range of elements to replace. 0 refers to the first element of the list, and \fBend\fR (or any abbreviation of it) may be used to refer to the last element of the list. If \fIlist\fR is empty, then \fIfirst\fR and \fIlast\fR are ignored. If \fIfirst\fR is less than zero, it is considered to refer to the first element of the list. For non-empty lists, the element indicated by \fIfirst\fR must exist. If \fIlast\fR is less than zero but greater than \fIfirst\fR, then any specified elements will be prepended to the list. If \fIlast\fR is less than \fIfirst\fR then no elements are deleted; the new elements are simply inserted before \fIfirst\fR. The \fIelement\fR arguments specify zero or more new arguments to be added to the list in place of those that were deleted. Each \fIelement\fR argument will become a separate element of the list. If no \fIelement\fR arguments are specified, then the elements between \fIfirst\fR and \fIlast\fR are simply deleted. If \fIlist\fR is empty, any \fIelement\fR arguments are added to the end of the list. .SH EXAMPLES Replacing an element of a list with another: .CS % \fBlreplace\fR {a b c d e} 1 1 foo a foo c d e .CE .PP Replacing two elements of a list with three: .CS % \fBlreplace\fR {a b c d e} 1 2 three more elements a three more elements d e .CE .PP Deleting the last element from a list in a variable: .CS % set var {a b c d e} a b c d e % set var [\fBlreplace\fR $var end end] a b c d .CE .SH "SEE ALSO" .VS 8.4 list(n), lappend(n), lindex(n), linsert(n), llength(n), lsearch(n), lset(n), lrange(n), lsort(n) .VE .SH KEYWORDS element, list, replace tcl8.4.20/doc/exit.n0000644003604700454610000000250311737050674012614 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH exit n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME exit \- End the application .SH SYNOPSIS \fBexit \fR?\fIreturnCode\fR? .BE .SH DESCRIPTION .PP Terminate the process, returning \fIreturnCode\fR to the system as the exit status. If \fIreturnCode\fR isn't specified then it defaults to 0. .SH EXAMPLE Since non-zero exit codes are usually interpreted as error cases by the calling process, the \fBexit\fR command is an important part of signalling that something fatal has gone wrong. This code fragment is useful in scripts to act as a general problem trap: .CS proc main {} { # ... put the real main code in here ... } if {[catch {main} msg]} { puts stderr "unexpected script error: $msg" if {[info exist env(DEBUG)]} { puts stderr "---- BEGIN TRACE ----" puts stderr $errorInfo puts stderr "---- END TRACE ----" } # Reserve code 1 for "expected" error exits... \fBexit\fR 2 } .CE .SH "SEE ALSO" exec(n), tclvars(n) .SH KEYWORDS exit, process tcl8.4.20/doc/while.n0000644003604700454610000000424011737050674012753 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH while n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME while \- Execute script repeatedly as long as a condition is met .SH SYNOPSIS \fBwhile \fItest body\fR .BE .SH DESCRIPTION .PP The \fBwhile\fR command evaluates \fItest\fR as an expression (in the same way that \fBexpr\fR evaluates its argument). The value of the expression must a proper boolean value; if it is a true value then \fIbody\fR is executed by passing it to the Tcl interpreter. Once \fIbody\fR has been executed then \fItest\fR is evaluated again, and the process repeats until eventually \fItest\fR evaluates to a false boolean value. \fBContinue\fR commands may be executed inside \fIbody\fR to terminate the current iteration of the loop, and \fBbreak\fR commands may be executed inside \fIbody\fR to cause immediate termination of the \fBwhile\fR command. The \fBwhile\fR command always returns an empty string. .PP Note: \fItest\fR should almost always be enclosed in braces. If not, variable substitutions will be made before the \fBwhile\fR command starts executing, which means that variable changes made by the loop body will not be considered in the expression. This is likely to result in an infinite loop. If \fItest\fR is enclosed in braces, variable substitutions are delayed until the expression is evaluated (before each loop iteration), so changes in the variables will be visible. For an example, try the following script with and without the braces around \fB$x<10\fR: .CS set x 0 \fBwhile\fR {$x<10} { puts "x is $x" incr x } .CE .SH EXAMPLE Read lines from a channel until we get to the end of the stream, and print them out with a line-number prepended: .CS set lineCount 0 \fBwhile\fR {[gets $chan line] >= 0} { puts "[incr lineCount]: $line" } .CE .SH "SEE ALSO" break(n), continue(n), for(n), foreach(n) .SH KEYWORDS boolean value, loop, test, while tcl8.4.20/doc/format.n0000644003604700454610000002421111737050674013133 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH format n 8.1 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME format \- Format a string in the style of sprintf .SH SYNOPSIS \fBformat \fIformatString \fR?\fIarg arg ...\fR? .BE .SH INTRODUCTION .PP This command generates a formatted string in the same way as the ANSI C \fBsprintf\fR procedure (it uses \fBsprintf\fR in its implementation). \fIFormatString\fR indicates how to format the result, using \fB%\fR conversion specifiers as in \fBsprintf\fR, and the additional arguments, if any, provide values to be substituted into the result. The return value from \fBformat\fR is the formatted string. .SH "DETAILS ON FORMATTING" .PP The command operates by scanning \fIformatString\fR from left to right. Each character from the format string is appended to the result string unless it is a percent sign. If the character is a \fB%\fR then it is not copied to the result string. Instead, the characters following the \fB%\fR character are treated as a conversion specifier. The conversion specifier controls the conversion of the next successive \fIarg\fR to a particular format and the result is appended to the result string in place of the conversion specifier. If there are multiple conversion specifiers in the format string, then each one controls the conversion of one additional \fIarg\fR. The \fBformat\fR command must be given enough \fIarg\fRs to meet the needs of all of the conversion specifiers in \fIformatString\fR. .PP Each conversion specifier may contain up to six different parts: an XPG3 position specifier, a set of flags, a minimum field width, a precision, a length modifier, and a conversion character. Any of these fields may be omitted except for the conversion character. The fields that are present must appear in the order given above. The paragraphs below discuss each of these fields in turn. .PP If the \fB%\fR is followed by a decimal number and a \fB$\fR, as in ``\fB%2$d\fR'', then the value to convert is not taken from the next sequential argument. Instead, it is taken from the argument indicated by the number, where 1 corresponds to the first \fIarg\fR. If the conversion specifier requires multiple arguments because of \fB*\fR characters in the specifier then successive arguments are used, starting with the argument given by the number. This follows the XPG3 conventions for positional specifiers. If there are any positional specifiers in \fIformatString\fR then all of the specifiers must be positional. .PP The second portion of a conversion specifier may contain any of the following flag characters, in any order: .TP 10 \fB\-\fR Specifies that the converted argument should be left-justified in its field (numbers are normally right-justified with leading spaces if needed). .TP 10 \fB+\fR Specifies that a number should always be printed with a sign, even if positive. .TP 10 \fIspace\fR Specifies that a space should be added to the beginning of the number if the first character isn't a sign. .TP 10 \fB0\fR Specifies that the number should be padded on the left with zeroes instead of spaces. .TP 10 \fB#\fR Requests an alternate output form. For \fBo\fR and \fBO\fR conversions it guarantees that the first digit is always \fB0\fR. For \fBx\fR or \fBX\fR conversions, \fB0x\fR or \fB0X\fR (respectively) will be added to the beginning of the result unless it is zero. For all floating-point conversions (\fBe\fR, \fBE\fR, \fBf\fR, \fBg\fR, and \fBG\fR) it guarantees that the result always has a decimal point. For \fBg\fR and \fBG\fR conversions it specifies that trailing zeroes should not be removed. .PP The third portion of a conversion specifier is a number giving a minimum field width for this conversion. It is typically used to make columns line up in tabular printouts. If the converted argument contains fewer characters than the minimum field width then it will be padded so that it is as wide as the minimum field width. Padding normally occurs by adding extra spaces on the left of the converted argument, but the \fB0\fR and \fB\-\fR flags may be used to specify padding with zeroes on the left or with spaces on the right, respectively. If the minimum field width is specified as \fB*\fR rather than a number, then the next argument to the \fBformat\fR command determines the minimum field width; it must be a numeric string. .PP The fourth portion of a conversion specifier is a precision, which consists of a period followed by a number. The number is used in different ways for different conversions. For \fBe\fR, \fBE\fR, and \fBf\fR conversions it specifies the number of digits to appear to the right of the decimal point. For \fBg\fR and \fBG\fR conversions it specifies the total number of digits to appear, including those on both sides of the decimal point (however, trailing zeroes after the decimal point will still be omitted unless the \fB#\fR flag has been specified). For integer conversions, it specifies a minimum number of digits to print (leading zeroes will be added if necessary). For \fBs\fR conversions it specifies the maximum number of characters to be printed; if the string is longer than this then the trailing characters will be dropped. If the precision is specified with \fB*\fR rather than a number then the next argument to the \fBformat\fR command determines the precision; it must be a numeric string. .PP The fifth part of a conversion specifier is a length modifier, which must be \fBh\fR or \fBl\fR. If it is \fBh\fR it specifies that the numeric value should be truncated to a 16-bit value before converting. This option is rarely useful. .VS 8.4 If it is \fBl\fR it specifies that the numeric value should be (at least) a 64-bit value. If neither \fBh\fR nor \fBl\fR are present, numeric values are interpreted as being values of the width of the native machine word, as described by \fBtcl_platform(wordSize)\fR. .VE .PP The last thing in a conversion specifier is an alphabetic character that determines what kind of conversion to perform. The following conversion characters are currently supported: .TP 10 \fBd\fR Convert integer to signed decimal string. .TP 10 \fBu\fR Convert integer to unsigned decimal string. .TP 10 \fBi\fR Convert integer to signed decimal string; the integer may either be in decimal, in octal (with a leading \fB0\fR) or in hexadecimal (with a leading \fB0x\fR). .TP 10 \fBo\fR Convert integer to unsigned octal string. .TP 10 \fBx\fR or \fBX\fR Convert integer to unsigned hexadecimal string, using digits ``0123456789abcdef'' for \fBx\fR and ``0123456789ABCDEF'' for \fBX\fR). .VS .TP 10 \fBc\fR Convert integer to the Unicode character it represents. .VE .TP 10 \fBs\fR No conversion; just insert string. .TP 10 \fBf\fR Convert floating-point number to signed decimal string of the form \fIxx.yyy\fR, where the number of \fIy\fR's is determined by the precision (default: 6). If the precision is 0 then no decimal point is output. .TP 10 \fBe\fR or \fBe\fR Convert floating-point number to scientific notation in the form \fIx.yyy\fBe\(+-\fIzz\fR, where the number of \fIy\fR's is determined by the precision (default: 6). If the precision is 0 then no decimal point is output. If the \fBE\fR form is used then \fBE\fR is printed instead of \fBe\fR. .TP 10 \fBg\fR or \fBG\fR If the exponent is less than \-4 or greater than or equal to the precision, then convert floating-point number as for \fB%e\fR or \fB%E\fR. Otherwise convert as for \fB%f\fR. Trailing zeroes and a trailing decimal point are omitted. .TP 10 \fB%\fR No conversion: just insert \fB%\fR. .LP For the numerical conversions the argument being converted must be an integer or floating-point string; format converts the argument to binary and then converts it back to a string according to the conversion specifier. .SH "DIFFERENCES FROM ANSI SPRINTF" .PP The behavior of the format command is the same as the ANSI C \fBsprintf\fR procedure except for the following differences: .IP [1] \fB%p\fR and \fB%n\fR specifiers are not currently supported. .IP [2] For \fB%c\fR conversions the argument must be a decimal string, which will then be converted to the corresponding character value. .IP [3] The \fBl\fR modifier .VS 8.4 is ignored for real values and on 64-bit platforms, which are always converted as if the \fBl\fR modifier were present (i.e. the types \fBdouble\fR and \fBlong\fR are used for the internal representation of real and integer values, respectively). .VE 8.4 If the \fBh\fR modifier is specified then integer values are truncated to \fBshort\fR before conversion. Both \fBh\fR and \fBl\fR modifiers are ignored on all other conversions. .SH EXAMPLES Convert the output of \fBtime\fR into seconds to an accuracy of hundredths of a second: .CS set us [lindex [time $someTclCode] 0] puts [\fBformat\fR "%.2f seconds to execute" [expr {$us / 1e6}]] .CE .PP Create a packed X11 literal color specification: .CS # Each color-component should be in range (0..255) set color [\fBformat\fR "#%02x%02x%02x" $r $g $b] .CE .PP Use XPG3 format codes to allow reordering of fields (a technique that is often used in localized message catalogs; see \fBmsgcat\fR) without reordering the data values passed to \fBformat\fR: .CS set fmt1 "Today, %d shares in %s were bought at $%.2f each" puts [\fBformat\fR $fmt1 123 "Global BigCorp" 19.37] set fmt2 "Bought %2\\$s equity ($%3$.2f x %1\\$d) today" puts [\fBformat\fR $fmt2 123 "Global BigCorp" 19.37] .CE .PP Print a small table of powers of three: .CS # Set up the column widths set w1 5 set w2 10 # Make a nice header (with separator) for the table first set sep +-[string repeat - $w1]-+-[string repeat - $w2]-+ puts $sep puts [\fBformat\fR "| %-*s | %-*s |" $w1 "Index" $w2 "Power"] puts $sep # Print the contents of the table set p 1 for {set i 0} {$i<=20} {incr i} { puts [\fBformat\fR "| %*d | %*ld |" $w1 $i $w2 $p] set p [expr {wide($p) * 3}] } # Finish off by printing the separator again puts $sep .CE .SH "SEE ALSO" scan(n), sprintf(3), string(n) .SH KEYWORDS conversion specifier, format, sprintf, string, substitution tcl8.4.20/doc/LinkVar.30000644003604700454610000001114111737050674013114 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_LinkVar 3 7.5 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_LinkVar, Tcl_UnlinkVar, Tcl_UpdateLinkedVar \- link Tcl variable to C variable .SH SYNOPSIS .nf \fB#include \fR .sp int \fBTcl_LinkVar\fR(\fIinterp, varName, addr, type\fR) .sp \fBTcl_UnlinkVar\fR(\fIinterp, varName\fR) .sp \fBTcl_UpdateLinkedVar\fR(\fIinterp, varName\fR) .SH ARGUMENTS .AS Tcl_Interp writable .AP Tcl_Interp *interp in Interpreter that contains \fIvarName\fR. Also used by \fBTcl_LinkVar\fR to return error messages. .AP "CONST char" *varName in Name of global variable. .AP char *addr in Address of C variable that is to be linked to \fIvarName\fR. .AP int type in Type of C variable. Must be one of TCL_LINK_INT, TCL_LINK_DOUBLE, .VS 8.4 TCL_LINK_WIDE_INT, .VE 8.4 TCL_LINK_BOOLEAN, or TCL_LINK_STRING, optionally OR'ed with TCL_LINK_READ_ONLY to make Tcl variable read-only. .BE .SH DESCRIPTION .PP \fBTcl_LinkVar\fR uses variable traces to keep the Tcl variable named by \fIvarName\fR in sync with the C variable at the address given by \fIaddr\fR. Whenever the Tcl variable is read the value of the C variable will be returned, and whenever the Tcl variable is written the C variable will be updated to have the same value. \fBTcl_LinkVar\fR normally returns TCL_OK; if an error occurs while setting up the link (e.g. because \fIvarName\fR is the name of array) then TCL_ERROR is returned and the interpreter's result contains an error message. .PP The \fItype\fR argument specifies the type of the C variable, and must have one of the following values, optionally OR'ed with TCL_LINK_READ_ONLY: .TP \fBTCL_LINK_INT\fR The C variable is of type \fBint\fR. Any value written into the Tcl variable must have a proper integer form acceptable to \fBTcl_GetIntFromObj\fR; attempts to write non-integer values into \fIvarName\fR will be rejected with Tcl errors. .TP \fBTCL_LINK_DOUBLE\fR The C variable is of type \fBdouble\fR. Any value written into the Tcl variable must have a proper real form acceptable to \fBTcl_GetDoubleFromObj\fR; attempts to write non-real values into \fIvarName\fR will be rejected with Tcl errors. .TP \fBTCL_LINK_WIDE_INT\fR .VS 8.4 The C variable is of type \fBTcl_WideInt\fR (which is an integer type at least 64-bits wide on all platforms that can support it.) Any value written into the Tcl variable must have a proper integer form acceptable to \fBTcl_GetWideIntFromObj\fR; attempts to write non-integer values into \fIvarName\fR will be rejected with Tcl errors. .VE 8.4 .TP \fBTCL_LINK_BOOLEAN\fR The C variable is of type \fBint\fR. If its value is zero then it will read from Tcl as ``0''; otherwise it will read from Tcl as ``1''. Whenever \fIvarName\fR is modified, the C variable will be set to a 0 or 1 value. Any value written into the Tcl variable must have a proper boolean form acceptable to \fBTcl_GetBooleanFromObj\fR; attempts to write non-boolean values into \fIvarName\fR will be rejected with Tcl errors. .TP \fBTCL_LINK_STRING\fR The C variable is of type \fBchar *\fR. .VS If its value is not NULL then it must be a pointer to a string allocated with \fBTcl_Alloc\fR or \fBckalloc\fR. .VE Whenever the Tcl variable is modified the current C string will be freed and new memory will be allocated to hold a copy of the variable's new value. If the C variable contains a NULL pointer then the Tcl variable will read as ``NULL''. .PP If the TCL_LINK_READ_ONLY flag is present in \fItype\fR then the variable will be read-only from Tcl, so that its value can only be changed by modifying the C variable. Attempts to write the variable from Tcl will be rejected with errors. .PP \fBTcl_UnlinkVar\fR removes the link previously set up for the variable given by \fIvarName\fR. If there does not exist a link for \fIvarName\fR then the procedure has no effect. .PP \fBTcl_UpdateLinkedVar\fR may be invoked after the C variable has changed to force the Tcl variable to be updated immediately. In many cases this procedure is not needed, since any attempt to read the Tcl variable will return the latest value of the C variable. However, if a trace has been set on the Tcl variable (such as a Tk widget that wishes to display the value of the variable), the trace will not trigger when the C variable has changed. \fBTcl_UpdateLinkedVar\fR ensures that any traces on the Tcl variable are invoked. .SH KEYWORDS boolean, integer, link, read-only, real, string, traces, variable tcl8.4.20/doc/SetVar.30000644003604700454610000002412711737050674012762 0ustar dgp771div'\" '\" Copyright (c) 1989-1993 The Regents of the University of California. '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_SetVar 3 8.1 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_SetVar2Ex, Tcl_SetVar, Tcl_SetVar2, Tcl_ObjSetVar2, Tcl_GetVar2Ex, Tcl_GetVar, Tcl_GetVar2, Tcl_ObjGetVar2, Tcl_UnsetVar, Tcl_UnsetVar2 \- manipulate Tcl variables .SH SYNOPSIS .nf \fB#include \fR .sp .VS 8.1 Tcl_Obj * \fBTcl_SetVar2Ex\fR(\fIinterp, name1, name2, newValuePtr, flags\fR) .VE .sp CONST char * \fBTcl_SetVar\fR(\fIinterp, varName, newValue, flags\fR) .sp CONST char * \fBTcl_SetVar2\fR(\fIinterp, name1, name2, newValue, flags\fR) .sp Tcl_Obj * \fBTcl_ObjSetVar2\fR(\fIinterp, part1Ptr, part2Ptr, newValuePtr, flags\fR) .sp .VS 8.1 Tcl_Obj * \fBTcl_GetVar2Ex\fR(\fIinterp, name1, name2, flags\fR) .VE .sp CONST char * \fBTcl_GetVar\fR(\fIinterp, varName, flags\fR) .sp CONST char * \fBTcl_GetVar2\fR(\fIinterp, name1, name2, flags\fR) .sp Tcl_Obj * \fBTcl_ObjGetVar2\fR(\fIinterp, part1Ptr, part2Ptr, flags\fR) .sp int \fBTcl_UnsetVar\fR(\fIinterp, varName, flags\fR) .sp int \fBTcl_UnsetVar2\fR(\fIinterp, name1, name2, flags\fR) .SH ARGUMENTS .AS Tcl_Interp *newValuePtr .AP Tcl_Interp *interp in Interpreter containing variable. .AP "CONST char" *name1 in Contains the name of an array variable (if \fIname2\fR is non-NULL) or (if \fIname2\fR is NULL) either the name of a scalar variable or a complete name including both variable name and index. May include \fB::\fR namespace qualifiers to specify a variable in a particular namespace. .AP "CONST char" *name2 in If non-NULL, gives name of element within array; in this case \fIname1\fR must refer to an array variable. .AP Tcl_Obj *newValuePtr in .VS 8.1 Points to a Tcl object containing the new value for the variable. .VE .AP int flags in OR-ed combination of bits providing additional information. See below for valid values. .AP "CONST char" *varName in Name of variable. May include \fB::\fR namespace qualifiers to specify a variable in a particular namespace. May refer to a scalar variable or an element of an array. .AP "CONST char" *newValue in New value for variable, specified as a null-terminated string. A copy of this value is stored in the variable. .AP Tcl_Obj *part1Ptr in Points to a Tcl object containing the variable's name. The name may include a series of \fB::\fR namespace qualifiers to specify a variable in a particular namespace. May refer to a scalar variable or an element of an array variable. .AP Tcl_Obj *part2Ptr in If non-NULL, points to an object containing the name of an element within an array and \fIpart1Ptr\fR must refer to an array variable. .BE .SH DESCRIPTION .PP These procedures are used to create, modify, read, and delete Tcl variables from C code. .PP .VS 8.1 \fBTcl_SetVar2Ex\fR, \fBTcl_SetVar\fR, \fBTcl_SetVar2\fR, and \fBTcl_ObjSetVar2\fR will create a new variable or modify an existing one. These procedures set the given variable to the value given by \fInewValuePtr\fR or \fInewValue\fR and return a pointer to the variable's new value, which is stored in Tcl's variable structure. \fBTcl_SetVar2Ex\fR and \fBTcl_ObjSetVar2\fR take the new value as a Tcl_Obj and return a pointer to a Tcl_Obj. \fBTcl_SetVar\fR and \fBTcl_SetVar2\fR take the new value as a string and return a string; they are usually less efficient than \fBTcl_ObjSetVar2\fR. Note that the return value may be different than the \fInewValuePtr\fR or .VE \fInewValue\fR argument, due to modifications made by write traces. If an error occurs in setting the variable (e.g. an array variable is referenced without giving an index into the array) NULL is returned and an error message is left in \fIinterp\fR's result if the \fBTCL_LEAVE_ERR_MSG\fR \fIflag\fR bit is set. .PP .VS 8.1 \fBTcl_GetVar2Ex\fR, \fBTcl_GetVar\fR, \fBTcl_GetVar2\fR, and \fBTcl_ObjGetVar2\fR return the current value of a variable. The arguments to these procedures are treated in the same way as the arguments to the procedures described above. Under normal circumstances, the return value is a pointer to the variable's value. For \fBTcl_GetVar2Ex\fR and \fBTcl_ObjGetVar2\fR the value is returned as a pointer to a Tcl_Obj. For \fBTcl_GetVar\fR and \fBTcl_GetVar2\fR the value is returned as a string; this is usually less efficient, so \fBTcl_GetVar2Ex\fR or \fBTcl_ObjGetVar2\fR are preferred. .VE If an error occurs while reading the variable (e.g. the variable doesn't exist or an array element is specified for a scalar variable), then NULL is returned and an error message is left in \fIinterp\fR's result if the \fBTCL_LEAVE_ERR_MSG\fR \fIflag\fR bit is set. .PP \fBTcl_UnsetVar\fR and \fBTcl_UnsetVar2\fR may be used to remove a variable, so that future attempts to read the variable will return an error. The arguments to these procedures are treated in the same way as the arguments to the procedures above. If the variable is successfully removed then TCL_OK is returned. If the variable cannot be removed because it doesn't exist then TCL_ERROR is returned and an error message is left in \fIinterp\fR's result if the \fBTCL_LEAVE_ERR_MSG\fR \fIflag\fR bit is set. If an array element is specified, the given element is removed but the array remains. If an array name is specified without an index, then the entire array is removed. .PP The name of a variable may be specified to these procedures in four ways: .IP [1] If \fBTcl_SetVar\fR, \fBTcl_GetVar\fR, or \fBTcl_UnsetVar\fR is invoked, the variable name is given as a single string, \fIvarName\fR. If \fIvarName\fR contains an open parenthesis and ends with a close parenthesis, then the value between the parentheses is treated as an index (which can have any string value) and the characters before the first open parenthesis are treated as the name of an array variable. If \fIvarName\fR doesn't have parentheses as described above, then the entire string is treated as the name of a scalar variable. .IP [2] If the \fIname1\fR and \fIname2\fR arguments are provided and \fIname2\fR is non-NULL, then an array element is specified and the array name and index have already been separated by the caller: \fIname1\fR contains the name and \fIname2\fR contains the index. .VS 8.1 An error is generated if \fIname1\fR contains an open parenthesis and ends with a close parenthesis (array element) and \fIname2\fR is non-NULL. .IP [3] If \fIname2\fR is NULL, \fIname1\fR is treated just like \fIvarName\fR in case [1] above (it can be either a scalar or an array element variable name). .VE .PP The \fIflags\fR argument may be used to specify any of several options to the procedures. It consists of an OR-ed combination of the following bits. .TP \fBTCL_GLOBAL_ONLY\fR Under normal circumstances the procedures look up variables as follows. If a procedure call is active in \fIinterp\fR, the variable is looked up at the current level of procedure call. Otherwise, the variable is looked up first in the current namespace, then in the global namespace. However, if this bit is set in \fIflags\fR then the variable is looked up only in the global namespace even if there is a procedure call active. If both \fBTCL_GLOBAL_ONLY\fR and \fBTCL_NAMESPACE_ONLY\fR are given, \fBTCL_GLOBAL_ONLY\fR is ignored. .TP \fBTCL_NAMESPACE_ONLY\fR If this bit is set in \fIflags\fR then the variable is looked up only in the current namespace; if a procedure is active its variables are ignored, and the global namespace is also ignored unless it is the current namespace. .TP \fBTCL_LEAVE_ERR_MSG\fR If an error is returned and this bit is set in \fIflags\fR, then an error message will be left in the interpreter's result, where it can be retrieved with \fBTcl_GetObjResult\fR or \fBTcl_GetStringResult\fR. If this flag bit isn't set then no error message is left and the interpreter's result will not be modified. .TP \fBTCL_APPEND_VALUE\fR If this bit is set then \fInewValuePtr\fR or \fInewValue\fR is appended to the current value instead of replacing it. If the variable is currently undefined, then the bit is ignored. This bit is only used by the \fBTcl_Set*\fR procedures. .TP \fBTCL_LIST_ELEMENT\fR If this bit is set, then \fInewValue\fR is converted to a valid Tcl list element before setting (or appending to) the variable. A separator space is appended before the new list element unless the list element is going to be the first element in a list or sublist (i.e. the variable's current value is empty, or contains the single character ``{'', or ends in `` }''). When appending, the original value of the variable must also be a valid list, so that the operation is the appending of a new list element onto a list. .PP \fBTcl_GetVar\fR and \fBTcl_GetVar2\fR return the current value of a variable. The arguments to these procedures are treated in the same way as the arguments to \fBTcl_SetVar\fR and \fBTcl_SetVar2\fR. Under normal circumstances, the return value is a pointer to the variable's value (which is stored in Tcl's variable structure and will not change before the next call to \fBTcl_SetVar\fR or \fBTcl_SetVar2\fR). \fBTcl_GetVar\fR and \fBTcl_GetVar2\fR use the flag bits TCL_GLOBAL_ONLY and TCL_LEAVE_ERR_MSG, both of which have the same meaning as for \fBTcl_SetVar\fR. If an error occurs in reading the variable (e.g. the variable doesn't exist or an array element is specified for a scalar variable), then NULL is returned. .PP \fBTcl_UnsetVar\fR and \fBTcl_UnsetVar2\fR may be used to remove a variable, so that future calls to \fBTcl_GetVar\fR or \fBTcl_GetVar2\fR for the variable will return an error. The arguments to these procedures are treated in the same way as the arguments to \fBTcl_GetVar\fR and \fBTcl_GetVar2\fR. If the variable is successfully removed then TCL_OK is returned. If the variable cannot be removed because it doesn't exist then TCL_ERROR is returned. If an array element is specified, the given element is removed but the array remains. If an array name is specified without an index, then the entire array is removed. .SH "SEE ALSO" Tcl_GetObjResult, Tcl_GetStringResult, Tcl_TraceVar .SH KEYWORDS array, get variable, interpreter, object, scalar, set, unset, variable tcl8.4.20/doc/error.n0000644003604700454610000000447011737050674013001 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH error n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME error \- Generate an error .SH SYNOPSIS \fBerror \fImessage\fR ?\fIinfo\fR? ?\fIcode\fR? .BE .SH DESCRIPTION .PP Returns a \fBTCL_ERROR\fR code, which causes command interpretation to be unwound. \fIMessage\fR is a string that is returned to the application to indicate what went wrong. .PP If the \fIinfo\fR argument is provided and is non-empty, it is used to initialize the global variable \fBerrorInfo\fR. \fBerrorInfo\fR is used to accumulate a stack trace of what was in progress when an error occurred; as nested commands unwind, the Tcl interpreter adds information to \fBerrorInfo\fR. If the \fIinfo\fR argument is present, it is used to initialize \fBerrorInfo\fR and the first increment of unwind information will not be added by the Tcl interpreter. In other words, the command containing the \fBerror\fR command will not appear in \fBerrorInfo\fR; in its place will be \fIinfo\fR. This feature is most useful in conjunction with the \fBcatch\fR command: if a caught error cannot be handled successfully, \fIinfo\fR can be used to return a stack trace reflecting the original point of occurrence of the error: .CS \fBcatch {...} errMsg set savedInfo $errorInfo \&... error $errMsg $savedInfo\fR .CE .PP If the \fIcode\fR argument is present, then its value is stored in the \fBerrorCode\fR global variable. This variable is intended to hold a machine-readable description of the error in cases where such information is available; see the \fBtclvars\fR manual page for information on the proper format for the variable. If the \fIcode\fR argument is not present, then \fBerrorCode\fR is automatically reset to ``NONE'' by the Tcl interpreter as part of processing the error generated by the command. .SH EXAMPLE Generate an error if a basic mathematical operation fails: .CS if {1+2 != 3} { \fBerror\fR "something is very wrong with addition" } .CE .SH "SEE ALSO" catch(n), return(n), tclvars(n) .SH KEYWORDS error, errorCode, errorInfo tcl8.4.20/doc/ListObj.30000644003604700454610000002404311737050674013121 0ustar dgp771div'\" '\" Copyright (c) 1996-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_ListObj 3 8.0 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_ListObjAppendList, Tcl_ListObjAppendElement, Tcl_NewListObj, Tcl_SetListObj, Tcl_ListObjGetElements, Tcl_ListObjLength, Tcl_ListObjIndex, Tcl_ListObjReplace \- manipulate Tcl objects as lists .SH SYNOPSIS .nf \fB#include \fR .sp int \fBTcl_ListObjAppendList\fR(\fIinterp, listPtr, elemListPtr\fR) .sp int \fBTcl_ListObjAppendElement\fR(\fIinterp, listPtr, objPtr\fR) .sp Tcl_Obj * \fBTcl_NewListObj\fR(\fIobjc, objv\fR) .sp \fBTcl_SetListObj\fR(\fIobjPtr, objc, objv\fR) .sp int \fBTcl_ListObjGetElements\fR(\fIinterp, listPtr, objcPtr, objvPtr\fR) .sp int \fBTcl_ListObjLength\fR(\fIinterp, listPtr, intPtr\fR) .sp int \fBTcl_ListObjIndex\fR(\fIinterp, listPtr, index, objPtrPtr\fR) .sp int \fBTcl_ListObjReplace\fR(\fIinterp, listPtr, first, count, objc, objv\fR) .SH ARGUMENTS .AS Tcl_Interp "*CONST objv[]" out .AP Tcl_Interp *interp in If an error occurs while converting an object to be a list object, an error message is left in the interpreter's result object unless \fIinterp\fR is NULL. .AP Tcl_Obj *listPtr in/out Points to the list object to be manipulated. If \fIlistPtr\fR does not already point to a list object, an attempt will be made to convert it to one. .AP Tcl_Obj *elemListPtr in/out For \fBTcl_ListObjAppendList\fR, this points to a list object containing elements to be appended onto \fIlistPtr\fR. Each element of *\fIelemListPtr\fR will become a new element of \fIlistPtr\fR. If *\fIelemListPtr\fR is not NULL and does not already point to a list object, an attempt will be made to convert it to one. .AP Tcl_Obj *objPtr in For \fBTcl_ListObjAppendElement\fR, points to the Tcl object that will be appended to \fIlistPtr\fR. For \fBTcl_SetListObj\fR, this points to the Tcl object that will be converted to a list object containing the \fIobjc\fR elements of the array referenced by \fIobjv\fR. .AP int *objcPtr in Points to location where \fBTcl_ListObjGetElements\fR stores the number of element objects in \fIlistPtr\fR. .AP Tcl_Obj ***objvPtr out A location where \fBTcl_ListObjGetElements\fR stores a pointer to an array of pointers to the element objects of \fIlistPtr\fR. .AP int objc in The number of Tcl objects that \fBTcl_NewListObj\fR will insert into a new list object, and \fBTcl_ListObjReplace\fR will insert into \fIlistPtr\fR. For \fBTcl_SetListObj\fR, the number of Tcl objects to insert into \fIobjPtr\fR. .VS .AP Tcl_Obj "*CONST\ objv[]" in An array of pointers to objects. \fBTcl_NewListObj\fR will insert these objects into a new list object and \fBTcl_ListObjReplace\fR will insert them into an existing \fIlistPtr\fR. Each object will become a separate list element. .VE .AP int *intPtr out Points to location where \fBTcl_ListObjLength\fR stores the length of the list. .AP int index in Index of the list element that \fBTcl_ListObjIndex\fR is to return. The first element has index 0. .AP Tcl_Obj **objPtrPtr out Points to place where \fBTcl_ListObjIndex\fR is to store a pointer to the resulting list element object. .AP int first in Index of the starting list element that \fBTcl_ListObjReplace\fR is to replace. The list's first element has index 0. .AP int count in The number of elements that \fBTcl_ListObjReplace\fR is to replace. .BE .SH DESCRIPTION .PP Tcl list objects have an internal representation that supports the efficient indexing and appending. The procedures described in this man page are used to create, modify, index, and append to Tcl list objects from C code. .PP \fBTcl_ListObjAppendList\fR and \fBTcl_ListObjAppendElement\fR both add one or more objects to the end of the list object referenced by \fIlistPtr\fR. \fBTcl_ListObjAppendList\fR appends each element of the list object referenced by \fIelemListPtr\fR while \fBTcl_ListObjAppendElement\fR appends the single object referenced by \fIobjPtr\fR. Both procedures will convert the object referenced by \fIlistPtr\fR to a list object if necessary. If an error occurs during conversion, both procedures return \fBTCL_ERROR\fR and leave an error message in the interpreter's result object if \fIinterp\fR is not NULL. Similarly, if \fIelemListPtr\fR does not already refer to a list object, \fBTcl_ListObjAppendList\fR will attempt to convert it to one and if an error occurs during conversion, will return \fBTCL_ERROR\fR and leave an error message in the interpreter's result object if interp is not NULL. Both procedures invalidate any old string representation of \fIlistPtr\fR and, if it was converted to a list object, free any old internal representation. Similarly, \fBTcl_ListObjAppendList\fR frees any old internal representation of \fIelemListPtr\fR if it converts it to a list object. After appending each element in \fIelemListPtr\fR, \fBTcl_ListObjAppendList\fR increments the element's reference count since \fIlistPtr\fR now also refers to it. For the same reason, \fBTcl_ListObjAppendElement\fR increments \fIobjPtr\fR's reference count. If no error occurs, the two procedures return \fBTCL_OK\fR after appending the objects. .PP \fBTcl_NewListObj\fR and \fBTcl_SetListObj\fR create a new object or modify an existing object to hold the \fIobjc\fR elements of the array referenced by \fIobjv\fR where each element is a pointer to a Tcl object. If \fIobjc\fR is less than or equal to zero, they return an empty object. The new object's string representation is left invalid. The two procedures increment the reference counts of the elements in \fIobjc\fR since the list object now refers to them. The new list object returned by \fBTcl_NewListObj\fR has reference count zero. .PP \fBTcl_ListObjGetElements\fR returns a count and a pointer to an array of the elements in a list object. It returns the count by storing it in the address \fIobjcPtr\fR. Similarly, it returns the array pointer by storing it in the address \fIobjvPtr\fR. The memory pointed to is managed by Tcl and should not be freed by the caller. If \fIlistPtr\fR is not already a list object, \fBTcl_ListObjGetElements\fR will attempt to convert it to one; if the conversion fails, it returns \fBTCL_ERROR\fR and leaves an error message in the interpreter's result object if \fIinterp\fR is not NULL. Otherwise it returns \fBTCL_OK\fR after storing the count and array pointer. .PP \fBTcl_ListObjLength\fR returns the number of elements in the list object referenced by \fIlistPtr\fR. It returns this count by storing an integer in the address \fIintPtr\fR. If the object is not already a list object, \fBTcl_ListObjLength\fR will attempt to convert it to one; if the conversion fails, it returns \fBTCL_ERROR\fR and leaves an error message in the interpreter's result object if \fIinterp\fR is not NULL. Otherwise it returns \fBTCL_OK\fR after storing the list's length. .PP The procedure \fBTcl_ListObjIndex\fR returns a pointer to the object at element \fIindex\fR in the list referenced by \fIlistPtr\fR. It returns this object by storing a pointer to it in the address \fIobjPtrPtr\fR. If \fIlistPtr\fR does not already refer to a list object, \fBTcl_ListObjIndex\fR will attempt to convert it to one; if the conversion fails, it returns \fBTCL_ERROR\fR and leaves an error message in the interpreter's result object if \fIinterp\fR is not NULL. If the index is out of range, that is, \fIindex\fR is negative or greater than or equal to the number of elements in the list, \fBTcl_ListObjIndex\fR stores a NULL in \fIobjPtrPtr\fR and returns \fBTCL_OK\fR. Otherwise it returns \fBTCL_OK\fR after storing the element's object pointer. The reference count for the list element is not incremented; the caller must do that if it needs to retain a pointer to the element. .PP \fBTcl_ListObjReplace\fR replaces zero or more elements of the list referenced by \fIlistPtr\fR with the \fIobjc\fR objects in the array referenced by \fIobjv\fR. If \fIlistPtr\fR does not point to a list object, \fBTcl_ListObjReplace\fR will attempt to convert it to one; if the conversion fails, it returns \fBTCL_ERROR\fR and leaves an error message in the interpreter's result object if \fIinterp\fR is not NULL. Otherwise, it returns \fBTCL_OK\fR after replacing the objects. If \fIobjv\fR is NULL, no new elements are added. If the argument \fIfirst\fR is zero or negative, it refers to the first element. If \fIfirst\fR is greater than or equal to the number of elements in the list, then no elements are deleted; the new elements are appended to the list. \fIcount\fR gives the number of elements to replace. If \fIcount\fR is zero or negative then no elements are deleted; the new elements are simply inserted before the one designated by \fIfirst\fR. \fBTcl_ListObjReplace\fR invalidates \fIlistPtr\fR's old string representation. The reference counts of any elements inserted from \fIobjv\fR are incremented since the resulting list now refers to them. Similarly, the reference counts for any replaced objects are decremented. .PP Because \fBTcl_ListObjReplace\fR combines both element insertion and deletion, it can be used to implement a number of list operations. For example, the following code inserts the \fIobjc\fR objects referenced by the array of object pointers \fIobjv\fR just before the element \fIindex\fR of the list referenced by \fIlistPtr\fR: .CS result = Tcl_ListObjReplace(interp, listPtr, index, 0, objc, objv); .CE Similarly, the following code appends the \fIobjc\fR objects referenced by the array \fIobjv\fR to the end of the list \fIlistPtr\fR: .CS result = Tcl_ListObjLength(interp, listPtr, &length); if (result == TCL_OK) { result = Tcl_ListObjReplace(interp, listPtr, length, 0, objc, objv); } .CE The \fIcount\fR list elements starting at \fIfirst\fR can be deleted by simply calling \fBTcl_ListObjReplace\fR with a NULL \fIobjvPtr\fR: .CS result = Tcl_ListObjReplace(interp, listPtr, first, count, 0, NULL); .CE .SH "SEE ALSO" Tcl_NewObj, Tcl_DecrRefCount, Tcl_IncrRefCount, Tcl_GetObjResult .SH KEYWORDS append, index, insert, internal representation, length, list, list object, list type, object, object type, replace, string representation tcl8.4.20/doc/vwait.n0000644003604700454610000000455711737050674013010 0ustar dgp771div'\" '\" Copyright (c) 1995-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH vwait n 8.0 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME vwait \- Process events until a variable is written .SH SYNOPSIS \fBvwait\fR \fIvarName\fR .BE .SH DESCRIPTION .PP This command enters the Tcl event loop to process events, blocking the application if no events are ready. It continues processing events until some event handler sets the value of variable \fIvarName\fR. Once \fIvarName\fR has been set, the \fBvwait\fR command will return as soon as the event handler that modified \fIvarName\fR completes. \fIvarName\fR must globally scoped (either with a call to \fBglobal\fR for the \fIvarName\fR, or with the full namespace path specification). .PP In some cases the \fBvwait\fR command may not return immediately after \fIvarName\fR is set. This can happen if the event handler that sets \fIvarName\fR does not complete immediately. For example, if an event handler sets \fIvarName\fR and then itself calls \fBvwait\fR to wait for a different variable, then it may not return for a long time. During this time the top-level \fBvwait\fR is blocked waiting for the event handler to complete, so it cannot return either. .SH EXAMPLES Run the event-loop continually until some event calls \fBexit\fR. (You can use any variable not mentioned elsewhere, but the name \fIforever\fR reminds you at a glance of the intent.) .CS \fBvwait\fR forever .CE .PP Wait five seconds for a connection to a server socket, otherwise close the socket and continue running the script: .CS # Initialise the state after 5000 set state timeout set server [socket -server accept 12345] proc accept {args} { global state connectionInfo set state accepted set connectionInfo $args } # Wait for something to happen \fBvwait\fR state # Clean up events that could have happened close $server after cancel set state timeout # Do something based on how the vwait finished... switch $state { timeout { puts "no connection on port 12345" } accepted { puts "connection: $connectionInfo" puts [lindex $connectionInfo 0] "Hello there!" } } .CE .SH "SEE ALSO" global(n), update(n) .SH KEYWORDS event, variable, wait tcl8.4.20/doc/SplitList.30000644003604700454610000001557211737050674013511 0ustar dgp771div'\" '\" Copyright (c) 1989-1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_SplitList 3 8.0 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_SplitList, Tcl_Merge, Tcl_ScanElement, Tcl_ConvertElement, Tcl_ScanCountedElement, Tcl_ConvertCountedElement \- manipulate Tcl lists .SH SYNOPSIS .nf \fB#include \fR .sp int \fBTcl_SplitList\fR(\fIinterp, list, argcPtr, argvPtr\fR) .sp char * \fBTcl_Merge\fR(\fIargc, argv\fR) .sp int \fBTcl_ScanElement\fR(\fIsrc, flagsPtr\fR) .sp int \fBTcl_ScanCountedElement\fR(\fIsrc, length, flagsPtr\fR) .sp int \fBTcl_ConvertElement\fR(\fIsrc, dst, flags\fR) .sp int \fBTcl_ConvertCountedElement\fR(\fIsrc, length, dst, flags\fR) .SH ARGUMENTS .AS "CONST char * CONST" ***argvPtr .AP Tcl_Interp *interp out Interpreter to use for error reporting. If NULL, then no error message is left. .AP char *list in Pointer to a string with proper list structure. .AP int *argcPtr out Filled in with number of elements in \fIlist\fR. .AP "CONST char" ***argvPtr out \fI*argvPtr\fR will be filled in with the address of an array of pointers to the strings that are the extracted elements of \fIlist\fR. There will be \fI*argcPtr\fR valid entries in the array, followed by a NULL entry. .AP int argc in Number of elements in \fIargv\fR. .AP "CONST char * CONST" *argv in Array of strings to merge together into a single list. Each string will become a separate element of the list. .AP "CONST char" *src in String that is to become an element of a list. .AP int *flagsPtr in Pointer to word to fill in with information about \fIsrc\fR. The value of *\fIflagsPtr\fR must be passed to \fBTcl_ConvertElement\fR. .AP int length in Number of bytes in string \fIsrc\fR. .AP char *dst in Place to copy converted list element. Must contain enough characters to hold converted string. .AP int flags in Information about \fIsrc\fR. Must be value returned by previous call to \fBTcl_ScanElement\fR, possibly OR-ed with \fBTCL_DONT_USE_BRACES\fR. .BE .SH DESCRIPTION .PP These procedures may be used to disassemble and reassemble Tcl lists. \fBTcl_SplitList\fR breaks a list up into its constituent elements, returning an array of pointers to the elements using \fIargcPtr\fR and \fIargvPtr\fR. While extracting the arguments, \fBTcl_SplitList\fR obeys the usual rules for backslash substitutions and braces. The area of memory pointed to by \fI*argvPtr\fR is dynamically allocated; in addition to the array of pointers, it also holds copies of all the list elements. It is the caller's responsibility to free up all of this storage. For example, suppose that you have called \fBTcl_SplitList\fR with the following code: .CS int argc, code; char *string; char **argv; \&... code = Tcl_SplitList(interp, string, &argc, &argv); .CE Then you should eventually free the storage with a call like the following: .CS Tcl_Free((char *) argv); .CE .PP \fBTcl_SplitList\fR normally returns \fBTCL_OK\fR, which means the list was successfully parsed. If there was a syntax error in \fIlist\fR, then \fBTCL_ERROR\fR is returned and the interpreter's result will point to an error message describing the problem (if \fIinterp\fR was not NULL). If \fBTCL_ERROR\fR is returned then no memory is allocated and \fI*argvPtr\fR is not modified. .PP \fBTcl_Merge\fR is the inverse of \fBTcl_SplitList\fR: it takes a collection of strings given by \fIargc\fR and \fIargv\fR and generates a result string that has proper list structure. This means that commands like \fBindex\fR may be used to extract the original elements again. In addition, if the result of \fBTcl_Merge\fR is passed to \fBTcl_Eval\fR, it will be parsed into \fIargc\fR words whose values will be the same as the \fIargv\fR strings passed to \fBTcl_Merge\fR. \fBTcl_Merge\fR will modify the list elements with braces and/or backslashes in order to produce proper Tcl list structure. The result string is dynamically allocated using \fBTcl_Alloc\fR; the caller must eventually release the space using \fBTcl_Free\fR. .PP If the result of \fBTcl_Merge\fR is passed to \fBTcl_SplitList\fR, the elements returned by \fBTcl_SplitList\fR will be identical to those passed into \fBTcl_Merge\fR. However, the converse is not true: if \fBTcl_SplitList\fR is passed a given string, and the resulting \fIargc\fR and \fIargv\fR are passed to \fBTcl_Merge\fR, the resulting string may not be the same as the original string passed to \fBTcl_SplitList\fR. This is because \fBTcl_Merge\fR may use backslashes and braces differently than the original string. .PP \fBTcl_ScanElement\fR and \fBTcl_ConvertElement\fR are the procedures that do all of the real work of \fBTcl_Merge\fR. \fBTcl_ScanElement\fR scans its \fIsrc\fR argument and determines how to use backslashes and braces when converting it to a list element. It returns an overestimate of the number of characters required to represent \fIsrc\fR as a list element, and it stores information in \fI*flagsPtr\fR that is needed by \fBTcl_ConvertElement\fR. .PP \fBTcl_ConvertElement\fR is a companion procedure to \fBTcl_ScanElement\fR. It does the actual work of converting a string to a list element. Its \fIflags\fR argument must be the same as the value returned by \fBTcl_ScanElement\fR. \fBTcl_ConvertElement\fR writes a proper list element to memory starting at *\fIdst\fR and returns a count of the total number of characters written, which will be no more than the result returned by \fBTcl_ScanElement\fR. \fBTcl_ConvertElement\fR writes out only the actual list element without any leading or trailing spaces: it is up to the caller to include spaces between adjacent list elements. .PP \fBTcl_ConvertElement\fR uses one of two different approaches to handle the special characters in \fIsrc\fR. Wherever possible, it handles special characters by surrounding the string with braces. This produces clean-looking output, but can't be used in some situations, such as when \fIsrc\fR contains unmatched braces. In these situations, \fBTcl_ConvertElement\fR handles special characters by generating backslash sequences for them. The caller may insist on the second approach by OR-ing the flag value returned by \fBTcl_ScanElement\fR with \fBTCL_DONT_USE_BRACES\fR. Although this will produce an uglier result, it is useful in some special situations, such as when \fBTcl_ConvertElement\fR is being used to generate a portion of an argument for a Tcl command. In this case, surrounding \fIsrc\fR with curly braces would cause the command not to be parsed correctly. .PP \fBTcl_ScanCountedElement\fR and \fBTcl_ConvertCountedElement\fR are the same as \fBTcl_ScanElement\fR and \fBTcl_ConvertElement\fR, except the length of string \fIsrc\fR is specified by the \fIlength\fR argument, and the string may contain embedded nulls. .SH KEYWORDS backslash, convert, element, list, merge, split, strings tcl8.4.20/doc/lrange.n0000644003604700454610000000405511737050674013117 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" Copyright (c) 2001 Kevin B. Kenny. All rights reserved. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH lrange n 7.4 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME lrange \- Return one or more adjacent elements from a list .SH SYNOPSIS \fBlrange \fIlist first last\fR .BE .SH DESCRIPTION .PP \fIList\fR must be a valid Tcl list. This command will return a new list consisting of elements \fIfirst\fR through \fIlast\fR, inclusive. \fIFirst\fR or \fIlast\fR may be \fBend\fR (or any abbreviation of it) to refer to the last element of the list. If \fIfirst\fR is less than zero, it is treated as if it were zero. If \fIlast\fR is greater than or equal to the number of elements in the list, then it is treated as if it were \fBend\fR. If \fIfirst\fR is greater than \fIlast\fR then an empty string is returned. Note: ``\fBlrange \fIlist first first\fR'' does not always produce the same result as ``\fBlindex \fIlist first\fR'' (although it often does for simple fields that aren't enclosed in braces); it does, however, produce exactly the same results as ``\fBlist [lindex \fIlist first\fB]\fR'' .SH EXAMPLES Selecting the first two elements: .CS % \fBlrange\fR {a b c d e} 0 1 a b .CE .PP Selecting the last three elements: .CS % \fBlrange\fR {a b c d e} end-2 end c d e .CE .PP Selecting everything except the first and last element: .CS % \fBlrange\fR {a b c d e} 1 end-1 b c d .CE .PP Selecting a single element with \fBlrange\fR is not the same as doing so with \fBlindex\fR: .CS % set var {some {elements to} select} some {elements to} select % lindex $var 1 elements to % \fBlrange\fR $var 1 1 {elements to} .CE .SH "SEE ALSO" .VS 8.4 list(n), lappend(n), lindex(n), linsert(n), llength(n), lsearch(n), lset(n), lreplace(n), lsort(n) .VE .SH KEYWORDS element, list, range, sublist tcl8.4.20/doc/BoolObj.30000644003604700454610000000643311737050674013104 0ustar dgp771div'\" '\" Copyright (c) 1996-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_BooleanObj 3 8.0 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_NewBooleanObj, Tcl_SetBooleanObj, Tcl_GetBooleanFromObj \- manipulate Tcl objects as boolean values .SH SYNOPSIS .nf \fB#include \fR .sp Tcl_Obj * \fBTcl_NewBooleanObj\fR(\fIboolValue\fR) .sp \fBTcl_SetBooleanObj\fR(\fIobjPtr, boolValue\fR) .sp int \fBTcl_GetBooleanFromObj\fR(\fIinterp, objPtr, boolPtr\fR) .SH ARGUMENTS .AS Tcl_Interp *interp .AP int boolValue in Integer value used to initialize or set a boolean object. If the integer is nonzero, the boolean object is set to 1; otherwise the boolean object is set to 0. .AP Tcl_Obj *objPtr in/out For \fBTcl_SetBooleanObj\fR, this points to the object to be converted to boolean type. For \fBTcl_GetBooleanFromObj\fR, this refers to the object from which to get a boolean value; if \fIobjPtr\fR does not already point to a boolean object, an attempt will be made to convert it to one. .AP Tcl_Interp *interp in/out If an error occurs during conversion, an error message is left in the interpreter's result object unless \fIinterp\fR is NULL. .AP int *boolPtr out Points to place where \fBTcl_GetBooleanFromObj\fR stores the boolean value (0 or 1) obtained from \fIobjPtr\fR. .BE .SH DESCRIPTION .PP These procedures are used to create, modify, and read boolean Tcl objects from C code. \fBTcl_NewBooleanObj\fR and \fBTcl_SetBooleanObj\fR will create a new object of boolean type or modify an existing object to have boolean type. Both of these procedures set the object to have the boolean value (0 or 1) specified by \fIboolValue\fR; if \fIboolValue\fR is nonzero, the object is set to 1, otherwise to 0. \fBTcl_NewBooleanObj\fR returns a pointer to a newly created object with reference count zero. Both procedures set the object's type to be boolean and assign the boolean value to the object's internal representation \fIlongValue\fR member. \fBTcl_SetBooleanObj\fR invalidates any old string representation and, if the object is not already a boolean object, frees any old internal representation. .PP \fBTcl_GetBooleanFromObj\fR attempts to return a boolean value from the Tcl object \fIobjPtr\fR. If the object is not already a boolean object, it will attempt to convert it to one. If an error occurs during conversion, it returns \fBTCL_ERROR\fR and leaves an error message in the interpreter's result object unless \fIinterp\fR is NULL. Otherwise, \fBTcl_GetBooleanFromObj\fR returns \fBTCL_OK\fR and stores the boolean value in the address given by \fIboolPtr\fR. If the object is not already a boolean object, the conversion will free any old internal representation. Objects having a string representation equal to any of \fB0\fR, \fBfalse\fR, \fBno\fR, or \fBoff\fR have a boolean value 0; if the string representation is any of \fB1\fR, \fBtrue\fR, \fByes\fR, or \fBon\fR the boolean value is 1. Any of these string values may be abbreviated, and upper-case spellings are also acceptable. .SH "SEE ALSO" Tcl_NewObj, Tcl_DecrRefCount, Tcl_IncrRefCount, Tcl_GetObjResult .SH KEYWORDS boolean, boolean object, boolean type, internal representation, object, object type, string representation tcl8.4.20/doc/gets.n0000644003604700454610000000463211737050674012612 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH gets n 7.5 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME gets \- Read a line from a channel .SH SYNOPSIS \fBgets \fIchannelId\fR ?\fIvarName\fR? .BE .SH DESCRIPTION .PP This command reads the next line from \fIchannelId\fR, returns everything in the line up to (but not including) the end-of-line character(s), and discards the end-of-line character(s). .PP .VS \fIChannelId\fR must be an identifier for an open channel such as the Tcl standard input channel (\fBstdin\fR), the return value from an invocation of \fBopen\fR or \fBsocket\fR, or the result of a channel creation command provided by a Tcl extension. The channel must have been opened for input. .VE .PP If \fIvarName\fR is omitted the line is returned as the result of the command. If \fIvarName\fR is specified then the line is placed in the variable by that name and the return value is a count of the number of characters returned. .PP If end of file occurs while scanning for an end of line, the command returns whatever input is available up to the end of file. If \fIchannelId\fR is in nonblocking mode and there is not a full line of input available, the command returns an empty string and does not consume any input. If \fIvarName\fR is specified and an empty string is returned in \fIvarName\fR because of end-of-file or because of insufficient data in nonblocking mode, then the return count is -1. Note that if \fIvarName\fR is not specified then the end-of-file and no-full-line-available cases can produce the same results as if there were an input line consisting only of the end-of-line character(s). The \fBeof\fR and \fBfblocked\fR commands can be used to distinguish these three cases. .SH "EXAMPLE" This example reads a file one line at a time and prints it out with the current line number attached to the start of each line. .PP .CS set chan [open "some.file.txt"] set lineNumber 0 while {[\fBgets\fR $chan line] >= 0} { puts "[incr lineNumber]: $line" } close $chan .CE .SH "SEE ALSO" file(n), eof(n), fblocked(n), Tcl_StandardChannels(3) .SH KEYWORDS blocking, channel, end of file, end of line, line, nonblocking, read tcl8.4.20/doc/RecordEval.30000644003604700454610000000375511737050674013610 0ustar dgp771div'\" '\" Copyright (c) 1989-1993 The Regents of the University of California. '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_RecordAndEval 3 7.4 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_RecordAndEval \- save command on history list before evaluating .SH SYNOPSIS .nf \fB#include \fR .sp int \fBTcl_RecordAndEval\fR(\fIinterp, cmd, flags\fR) .SH ARGUMENTS .AS Tcl_Interp *interp; .AP Tcl_Interp *interp in Tcl interpreter in which to evaluate command. .AP "CONST char" *cmd in Command (or sequence of commands) to execute. .AP int flags in An OR'ed combination of flag bits. TCL_NO_EVAL means record the command but don't evaluate it. TCL_EVAL_GLOBAL means evaluate the command at global level instead of the current stack level. .BE .SH DESCRIPTION .PP \fBTcl_RecordAndEval\fR is invoked to record a command as an event on the history list and then execute it using \fBTcl_Eval\fR (or \fBTcl_GlobalEval\fR if the TCL_EVAL_GLOBAL bit is set in \fIflags\fR). It returns a completion code such as TCL_OK just like \fBTcl_Eval\fR and it leaves information in the interpreter's result. If you don't want the command recorded on the history list then you should invoke \fBTcl_Eval\fR instead of \fBTcl_RecordAndEval\fR. Normally \fBTcl_RecordAndEval\fR is only called with top-level commands typed by the user, since the purpose of history is to allow the user to re-issue recently-invoked commands. If the \fIflags\fR argument contains the TCL_NO_EVAL bit then the command is recorded without being evaluated. .PP Note that \fBTcl_RecordAndEval\fR has been largely replaced by the object-based procedure \fBTcl_RecordAndEvalObj\fR. That object-based procedure records and optionally executes a command held in a Tcl object instead of a string. .SH "SEE ALSO" Tcl_RecordAndEvalObj .SH KEYWORDS command, event, execute, history, interpreter, record tcl8.4.20/doc/binary.n0000644003604700454610000006222111737050674013132 0ustar dgp771div'\" '\" Copyright (c) 1997 by Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH binary n 8.0 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME binary \- Insert and extract fields from binary strings .SH SYNOPSIS \fBbinary format \fIformatString \fR?\fIarg arg ...\fR? .br \fBbinary scan \fIstring formatString \fR?\fIvarName varName ...\fR? .BE .SH DESCRIPTION .PP This command provides facilities for manipulating binary data. The first form, \fBbinary format\fR, creates a binary string from normal Tcl values. For example, given the values 16 and 22, on a 32 bit architecture, it might produce an 8-byte binary string consisting of two 4-byte integers, one for each of the numbers. The second form of the command, \fBbinary scan\fR, does the opposite: it extracts data from a binary string and returns it as ordinary Tcl string values. .SH "BINARY FORMAT" .PP The \fBbinary format\fR command generates a binary string whose layout is specified by the \fIformatString\fR and whose contents come from the additional arguments. The resulting binary value is returned. .PP The \fIformatString\fR consists of a sequence of zero or more field specifiers separated by zero or more spaces. Each field specifier is a single type character followed by an optional numeric \fIcount\fR. Most field specifiers consume one argument to obtain the value to be formatted. The type character specifies how the value is to be formatted. The \fIcount\fR typically indicates how many items of the specified type are taken from the value. If present, the \fIcount\fR is a non-negative decimal integer or \fB*\fR, which normally indicates that all of the items in the value are to be used. If the number of arguments does not match the number of fields in the format string that consume arguments, then an error is generated. .PP Here is a small example to clarify the relation between the field specifiers and the arguments: .CS \fBbinary format d3d {1.0 2.0 3.0 4.0} 0.1\fR .CE .PP The first argument is a list of four numbers, but because of the count of 3 for the associated field specifier, only the first three will be used. The second argument is associated with the second field specifier. The resulting binary string contains the four numbers 1.0, 2.0, 3.0 and 0.1. .PP Each type-count pair moves an imaginary cursor through the binary data, storing bytes at the current position and advancing the cursor to just after the last byte stored. The cursor is initially at position 0 at the beginning of the data. The type may be any one of the following characters: .IP \fBa\fR 5 Stores a character string of length \fIcount\fR in the output string. Every character is taken as modulo 256 (i.e. the low byte of every character is used, and the high byte discarded) so when storing character strings not wholly expressible using the characters \\u0000-\\u00ff, the \fBencoding convertto\fR command should be used first if this truncation is not desired (i.e. if the characters are not part of the ISO 8859-1 character set.) If \fIarg\fR has fewer than \fIcount\fR bytes, then additional zero bytes are used to pad out the field. If \fIarg\fR is longer than the specified length, the extra characters will be ignored. If \fIcount\fR is \fB*\fR, then all of the bytes in \fIarg\fR will be formatted. If \fIcount\fR is omitted, then one character will be formatted. For example, .RS .CS \fBbinary format a7a*a alpha bravo charlie\fR .CE will return a string equivalent to \fBalpha\\000\\000bravoc\fR. .RE .IP \fBA\fR 5 This form is the same as \fBa\fR except that spaces are used for padding instead of nulls. For example, .RS .CS \fBbinary format A6A*A alpha bravo charlie\fR .CE will return \fBalpha bravoc\fR. .RE .IP \fBb\fR 5 Stores a string of \fIcount\fR binary digits in low-to-high order within each byte in the output string. \fIArg\fR must contain a sequence of \fB1\fR and \fB0\fR characters. The resulting bytes are emitted in first to last order with the bits being formatted in low-to-high order within each byte. If \fIarg\fR has fewer than \fIcount\fR digits, then zeros will be used for the remaining bits. If \fIarg\fR has more than the specified number of digits, the extra digits will be ignored. If \fIcount\fR is \fB*\fR, then all of the digits in \fIarg\fR will be formatted. If \fIcount\fR is omitted, then one digit will be formatted. If the number of bits formatted does not end at a byte boundary, the remaining bits of the last byte will be zeros. For example, .RS .CS \fBbinary format b5b* 11100 111000011010\fR .CE will return a string equivalent to \fB\\x07\\x87\\x05\fR. .RE .IP \fBB\fR 5 This form is the same as \fBb\fR except that the bits are stored in high-to-low order within each byte. For example, .RS .CS \fBbinary format B5B* 11100 111000011010\fR .CE will return a string equivalent to \fB\\xe0\\xe1\\xa0\fR. .RE .IP \fBh\fR 5 Stores a string of \fIcount\fR hexadecimal digits in low-to-high within each byte in the output string. \fIArg\fR must contain a sequence of characters in the set ``0123456789abcdefABCDEF''. The resulting bytes are emitted in first to last order with the hex digits being formatted in low-to-high order within each byte. If \fIarg\fR has fewer than \fIcount\fR digits, then zeros will be used for the remaining digits. If \fIarg\fR has more than the specified number of digits, the extra digits will be ignored. If \fIcount\fR is \fB*\fR, then all of the digits in \fIarg\fR will be formatted. If \fIcount\fR is omitted, then one digit will be formatted. If the number of digits formatted does not end at a byte boundary, the remaining bits of the last byte will be zeros. For example, .RS .CS \fBbinary format h3h* AB def\fR .CE will return a string equivalent to \fB\\xba\\x00\\xed\\x0f\fR. .RE .IP \fBH\fR 5 This form is the same as \fBh\fR except that the digits are stored in high-to-low order within each byte. For example, .RS .CS \fBbinary format H3H* ab DEF\fR .CE will return a string equivalent to \fB\\xab\\x00\\xde\\xf0\fR. .RE .IP \fBc\fR 5 Stores one or more 8-bit integer values in the output string. If no \fIcount\fR is specified, then \fIarg\fR must consist of an integer value; otherwise \fIarg\fR must consist of a list containing at least \fIcount\fR integer elements. The low-order 8 bits of each integer are stored as a one-byte value at the cursor position. If \fIcount\fR is \fB*\fR, then all of the integers in the list are formatted. If the number of elements in the list is fewer than \fIcount\fR, then an error is generated. If the number of elements in the list is greater than \fIcount\fR, then the extra elements are ignored. For example, .RS .CS \fBbinary format c3cc* {3 -3 128 1} 260 {2 5}\fR .CE will return a string equivalent to \fB\\x03\\xfd\\x80\\x04\\x02\\x05\fR, whereas .CS \fBbinary format c {2 5}\fR .CE will generate an error. .RE .IP \fBs\fR 5 This form is the same as \fBc\fR except that it stores one or more 16-bit integers in little-endian byte order in the output string. The low-order 16-bits of each integer are stored as a two-byte value at the cursor position with the least significant byte stored first. For example, .RS .CS \fBbinary format s3 {3 -3 258 1}\fR .CE will return a string equivalent to \fB\\x03\\x00\\xfd\\xff\\x02\\x01\fR. .RE .IP \fBS\fR 5 This form is the same as \fBs\fR except that it stores one or more 16-bit integers in big-endian byte order in the output string. For example, .RS .CS \fBbinary format S3 {3 -3 258 1}\fR .CE will return a string equivalent to \fB\\x00\\x03\\xff\\xfd\\x01\\x02\fR. .RE .IP \fBi\fR 5 This form is the same as \fBc\fR except that it stores one or more 32-bit integers in little-endian byte order in the output string. The low-order 32-bits of each integer are stored as a four-byte value at the cursor position with the least significant byte stored first. For example, .RS .CS \fBbinary format i3 {3 -3 65536 1}\fR .CE will return a string equivalent to \fB\\x03\\x00\\x00\\x00\\xfd\\xff\\xff\\xff\\x00\\x00\\x01\\x00\fR .RE .IP \fBI\fR 5 This form is the same as \fBi\fR except that it stores one or more one or more 32-bit integers in big-endian byte order in the output string. For example, .RS .CS \fBbinary format I3 {3 -3 65536 1}\fR .CE will return a string equivalent to \fB\\x00\\x00\\x00\\x03\\xff\\xff\\xff\\xfd\\x00\\x01\\x00\\x00\fR .RE .IP \fBw\fR 5 .VS 8.4 This form is the same as \fBc\fR except that it stores one or more 64-bit integers in little-endian byte order in the output string. The low-order 64-bits of each integer are stored as an eight-byte value at the cursor position with the least significant byte stored first. For example, .RS .CS \fBbinary format w 7810179016327718216\fR .CE will return the string \fBHelloTcl\fR .RE .IP \fBW\fR 5 This form is the same as \fBw\fR except that it stores one or more one or more 64-bit integers in big-endian byte order in the output string. For example, .RS .CS \fBbinary format Wc 4785469626960341345 110\fR .CE will return the string \fBBigEndian\fR .VE .RE .IP \fBf\fR 5 This form is the same as \fBc\fR except that it stores one or more one or more single-precision floating in the machine's native representation in the output string. This representation is not portable across architectures, so it should not be used to communicate floating point numbers across the network. The size of a floating point number may vary across architectures, so the number of bytes that are generated may vary. If the value overflows the machine's native representation, then the value of FLT_MAX as defined by the system will be used instead. Because Tcl uses double-precision floating-point numbers internally, there may be some loss of precision in the conversion to single-precision. For example, on a Windows system running on an Intel Pentium processor, .RS .CS \fBbinary format f2 {1.6 3.4}\fR .CE will return a string equivalent to \fB\\xcd\\xcc\\xcc\\x3f\\x9a\\x99\\x59\\x40\fR. .RE .IP \fBd\fR 5 This form is the same as \fBf\fR except that it stores one or more one or more double-precision floating in the machine's native representation in the output string. For example, on a Windows system running on an Intel Pentium processor, .RS .CS \fBbinary format d1 {1.6}\fR .CE will return a string equivalent to \fB\\x9a\\x99\\x99\\x99\\x99\\x99\\xf9\\x3f\fR. .RE .IP \fBx\fR 5 Stores \fIcount\fR null bytes in the output string. If \fIcount\fR is not specified, stores one null byte. If \fIcount\fR is \fB*\fR, generates an error. This type does not consume an argument. For example, .RS .CS \fBbinary format a3xa3x2a3 abc def ghi\fR .CE will return a string equivalent to \fBabc\\000def\\000\\000ghi\fR. .RE .IP \fBX\fR 5 Moves the cursor back \fIcount\fR bytes in the output string. If \fIcount\fR is \fB*\fR or is larger than the current cursor position, then the cursor is positioned at location 0 so that the next byte stored will be the first byte in the result string. If \fIcount\fR is omitted then the cursor is moved back one byte. This type does not consume an argument. For example, .RS .CS \fBbinary format a3X*a3X2a3 abc def ghi\fR .CE will return \fBdghi\fR. .RE .IP \fB@\fR 5 Moves the cursor to the absolute location in the output string specified by \fIcount\fR. Position 0 refers to the first byte in the output string. If \fIcount\fR refers to a position beyond the last byte stored so far, then null bytes will be placed in the uninitialized locations and the cursor will be placed at the specified location. If \fIcount\fR is \fB*\fR, then the cursor is moved to the current end of the output string. If \fIcount\fR is omitted, then an error will be generated. This type does not consume an argument. For example, .RS .CS \fBbinary format a5@2a1@*a3@10a1 abcde f ghi j\fR .CE will return \fBabfdeghi\\000\\000j\fR. .RE .SH "BINARY SCAN" .PP The \fBbinary scan\fR command parses fields from a binary string, returning the number of conversions performed. \fIString\fR gives the input to be parsed and \fIformatString\fR indicates how to parse it. Each \fIvarName\fR gives the name of a variable; when a field is scanned from \fIstring\fR the result is assigned to the corresponding variable. .PP As with \fBbinary format\fR, the \fIformatString\fR consists of a sequence of zero or more field specifiers separated by zero or more spaces. Each field specifier is a single type character followed by an optional numeric \fIcount\fR. Most field specifiers consume one argument to obtain the variable into which the scanned values should be placed. The type character specifies how the binary data is to be interpreted. The \fIcount\fR typically indicates how many items of the specified type are taken from the data. If present, the \fIcount\fR is a non-negative decimal integer or \fB*\fR, which normally indicates that all of the remaining items in the data are to be used. If there are not enough bytes left after the current cursor position to satisfy the current field specifier, then the corresponding variable is left untouched and \fBbinary scan\fR returns immediately with the number of variables that were set. If there are not enough arguments for all of the fields in the format string that consume arguments, then an error is generated. .PP A similar example as with \fBbinary format\fR should explain the relation between field specifiers and arguments in case of the binary scan subcommand: .CS \fBbinary scan $bytes s3s first second\fR .CE .PP This command (provided the binary string in the variable \fIbytes\fR is long enough) assigns a list of three integers to the variable \fIfirst\fR and assigns a single value to the variable \fIsecond\fR. If \fIbytes\fR contains fewer than 8 bytes (i.e. four 2-byte integers), no assignment to \fIsecond\fR will be made, and if \fIbytes\fR contains fewer than 6 bytes (i.e. three 2-byte integers), no assignment to \fIfirst\fR will be made. Hence: .CS \fBputs [binary scan abcdefg s3s first second]\fR \fBputs $first\fR \fBputs $second\fR .CE will print (assuming neither variable is set previously): .CS \fB1\fR \fB25185 25699 26213\fR \fIcan't read "second": no such variable\fR .CE .PP It is \fBimportant\fR to note that the \fBc\fR, \fBs\fR, and \fBS\fR (and \fBi\fR and \fBI\fR on 64bit systems) will be scanned into long data size values. In doing this, values that have their high bit set (0x80 for chars, 0x8000 for shorts, 0x80000000 for ints), will be sign extended. Thus the following will occur: .CS \fBset signShort [binary format s1 0x8000]\fR \fBbinary scan $signShort s1 val; \fI# val == 0xFFFF8000\fR .CE If you want to produce an unsigned value, then you can mask the return value to the desired size. For example, to produce an unsigned short value: .CS \fBset val [expr {$val & 0xFFFF}]; \fI# val == 0x8000\fR .CE .PP Each type-count pair moves an imaginary cursor through the binary data, reading bytes from the current position. The cursor is initially at position 0 at the beginning of the data. The type may be any one of the following characters: .IP \fBa\fR 5 The data is a character string of length \fIcount\fR. If \fIcount\fR is \fB*\fR, then all of the remaining bytes in \fIstring\fR will be scanned into the variable. If \fIcount\fR is omitted, then one character will be scanned. All characters scanned will be interpreted as being in the range \\u0000-\\u00ff so the \fBencoding convertfrom\fR command might be needed if the string is not an ISO 8859\-1 string. For example, .RS .CS \fBbinary scan abcde\\000fghi a6a10 var1 var2\fR .CE will return \fB1\fR with the string equivalent to \fBabcde\\000\fR stored in \fBvar1\fR and \fBvar2\fR left unmodified. .RE .IP \fBA\fR 5 This form is the same as \fBa\fR, except trailing blanks and nulls are stripped from the scanned value before it is stored in the variable. For example, .RS .CS \fBbinary scan "abc efghi \\000" A* var1\fR .CE will return \fB1\fR with \fBabc efghi\fR stored in \fBvar1\fR. .RE .IP \fBb\fR 5 The data is turned into a string of \fIcount\fR binary digits in low-to-high order represented as a sequence of ``1'' and ``0'' characters. The data bytes are scanned in first to last order with the bits being taken in low-to-high order within each byte. Any extra bits in the last byte are ignored. If \fIcount\fR is \fB*\fR, then all of the remaining bits in \fBstring\fR will be scanned. If \fIcount\fR is omitted, then one bit will be scanned. For example, .RS .CS \fBbinary scan \\x07\\x87\\x05 b5b* var1 var2\fR .CE will return \fB2\fR with \fB11100\fR stored in \fBvar1\fR and \fB1110000110100000\fR stored in \fBvar2\fR. .RE .IP \fBB\fR 5 This form is the same as \fBb\fR, except the bits are taken in high-to-low order within each byte. For example, .RS .CS \fBbinary scan \\x70\\x87\\x05 B5B* var1 var2\fR .CE will return \fB2\fR with \fB01110\fR stored in \fBvar1\fR and \fB1000011100000101\fR stored in \fBvar2\fR. .RE .IP \fBh\fR 5 The data is turned into a string of \fIcount\fR hexadecimal digits in low-to-high order represented as a sequence of characters in the set ``0123456789abcdef''. The data bytes are scanned in first to last order with the hex digits being taken in low-to-high order within each byte. Any extra bits in the last byte are ignored. If \fIcount\fR is \fB*\fR, then all of the remaining hex digits in \fBstring\fR will be scanned. If \fIcount\fR is omitted, then one hex digit will be scanned. For example, .RS .CS \fBbinary scan \\x07\\x86\\x05 h3h* var1 var2\fR .CE will return \fB2\fR with \fB706\fR stored in \fBvar1\fR and \fB50\fR stored in \fBvar2\fR. .RE .IP \fBH\fR 5 This form is the same as \fBh\fR, except the digits are taken in high-to-low order within each byte. For example, .RS .CS \fBbinary scan \\x07\\x86\\x05 H3H* var1 var2\fR .CE will return \fB2\fR with \fB078\fR stored in \fBvar1\fR and \fB05\fR stored in \fBvar2\fR. .RE .IP \fBc\fR 5 The data is turned into \fIcount\fR 8-bit signed integers and stored in the corresponding variable as a list. If \fIcount\fR is \fB*\fR, then all of the remaining bytes in \fBstring\fR will be scanned. If \fIcount\fR is omitted, then one 8-bit integer will be scanned. For example, .RS .CS \fBbinary scan \\x07\\x86\\x05 c2c* var1 var2\fR .CE will return \fB2\fR with \fB7 -122\fR stored in \fBvar1\fR and \fB5\fR stored in \fBvar2\fR. Note that the integers returned are signed, but they can be converted to unsigned 8-bit quantities using an expression like: .CS \fBexpr { $num & 0xff }\fR .CE .RE .IP \fBs\fR 5 The data is interpreted as \fIcount\fR 16-bit signed integers represented in little-endian byte order. The integers are stored in the corresponding variable as a list. If \fIcount\fR is \fB*\fR, then all of the remaining bytes in \fBstring\fR will be scanned. If \fIcount\fR is omitted, then one 16-bit integer will be scanned. For example, .RS .CS \fBbinary scan \\x05\\x00\\x07\\x00\\xf0\\xff s2s* var1 var2\fR .CE will return \fB2\fR with \fB5 7\fR stored in \fBvar1\fR and \fB-16\fR stored in \fBvar2\fR. Note that the integers returned are signed, but they can be converted to unsigned 16-bit quantities using an expression like: .CS \fBexpr { $num & 0xffff }\fR .CE .RE .IP \fBS\fR 5 This form is the same as \fBs\fR except that the data is interpreted as \fIcount\fR 16-bit signed integers represented in big-endian byte order. For example, .RS .CS \fBbinary scan \\x00\\x05\\x00\\x07\\xff\\xf0 S2S* var1 var2\fR .CE will return \fB2\fR with \fB5 7\fR stored in \fBvar1\fR and \fB-16\fR stored in \fBvar2\fR. .RE .IP \fBi\fR 5 The data is interpreted as \fIcount\fR 32-bit signed integers represented in little-endian byte order. The integers are stored in the corresponding variable as a list. If \fIcount\fR is \fB*\fR, then all of the remaining bytes in \fBstring\fR will be scanned. If \fIcount\fR is omitted, then one 32-bit integer will be scanned. For example, .RS .CS \fBbinary scan \\x05\\x00\\x00\\x00\\x07\\x00\\x00\\x00\\xf0\\xff\\xff\\xff i2i* var1 var2\fR .CE will return \fB2\fR with \fB5 7\fR stored in \fBvar1\fR and \fB-16\fR stored in \fBvar2\fR. Note that the integers returned are signed, but they can be converted to unsigned 32-bit quantities using an expression like: .CS \fBexpr { $num & 0xffffffff }\fR .CE .RE .IP \fBI\fR 5 This form is the same as \fBI\fR except that the data is interpreted as \fIcount\fR 32-bit signed integers represented in big-endian byte order. For example, .RS .CS \fBbinary scan \\x00\\x00\\x00\\x05\\x00\\x00\\x00\\x07\\xff\\xff\\xff\\xf0 I2I* var1 var2\fR .CE will return \fB2\fR with \fB5 7\fR stored in \fBvar1\fR and \fB-16\fR stored in \fBvar2\fR. .RE .IP \fBw\fR 5 .VS 8.4 The data is interpreted as \fIcount\fR 64-bit signed integers represented in little-endian byte order. The integers are stored in the corresponding variable as a list. If \fIcount\fR is \fB*\fR, then all of the remaining bytes in \fBstring\fR will be scanned. If \fIcount\fR is omitted, then one 64-bit integer will be scanned. For example, .RS .CS \fBbinary scan \\x05\\x00\\x00\\x00\\x07\\x00\\x00\\x00\\xf0\\xff\\xff\\xff wi* var1 var2\fR .CE will return \fB2\fR with \fB30064771077\fR stored in \fBvar1\fR and \fB-16\fR stored in \fBvar2\fR. Note that the integers returned are signed and cannot be represented by Tcl as unsigned values. .RE .IP \fBW\fR 5 This form is the same as \fBw\fR except that the data is interpreted as \fIcount\fR 64-bit signed integers represented in big-endian byte order. For example, .RS .CS \fBbinary scan \\x00\\x00\\x00\\x05\\x00\\x00\\x00\\x07\\xff\\xff\\xff\\xf0 WI* var1 var2\fR .CE will return \fB2\fR with \fB21474836487\fR stored in \fBvar1\fR and \fB-16\fR stored in \fBvar2\fR. .VE .RE .IP \fBf\fR 5 The data is interpreted as \fIcount\fR single-precision floating point numbers in the machine's native representation. The floating point numbers are stored in the corresponding variable as a list. If \fIcount\fR is \fB*\fR, then all of the remaining bytes in \fBstring\fR will be scanned. If \fIcount\fR is omitted, then one single-precision floating point number will be scanned. The size of a floating point number may vary across architectures, so the number of bytes that are scanned may vary. If the data does not represent a valid floating point number, the resulting value is undefined and compiler dependent. For example, on a Windows system running on an Intel Pentium processor, .RS .CS \fBbinary scan \\x3f\\xcc\\xcc\\xcd f var1\fR .CE will return \fB1\fR with \fB1.6000000238418579\fR stored in \fBvar1\fR. .RE .IP \fBd\fR 5 This form is the same as \fBf\fR except that the data is interpreted as \fIcount\fR double-precision floating point numbers in the machine's native representation. For example, on a Windows system running on an Intel Pentium processor, .RS .CS \fBbinary scan \\x9a\\x99\\x99\\x99\\x99\\x99\\xf9\\x3f d var1\fR .CE will return \fB1\fR with \fB1.6000000000000001\fR stored in \fBvar1\fR. .RE .IP \fBx\fR 5 Moves the cursor forward \fIcount\fR bytes in \fIstring\fR. If \fIcount\fR is \fB*\fR or is larger than the number of bytes after the current cursor cursor position, then the cursor is positioned after the last byte in \fIstring\fR. If \fIcount\fR is omitted, then the cursor is moved forward one byte. Note that this type does not consume an argument. For example, .RS .CS \fBbinary scan \\x01\\x02\\x03\\x04 x2H* var1\fR .CE will return \fB1\fR with \fB0304\fR stored in \fBvar1\fR. .RE .IP \fBX\fR 5 Moves the cursor back \fIcount\fR bytes in \fIstring\fR. If \fIcount\fR is \fB*\fR or is larger than the current cursor position, then the cursor is positioned at location 0 so that the next byte scanned will be the first byte in \fIstring\fR. If \fIcount\fR is omitted then the cursor is moved back one byte. Note that this type does not consume an argument. For example, .RS .CS \fBbinary scan \\x01\\x02\\x03\\x04 c2XH* var1 var2\fR .CE will return \fB2\fR with \fB1 2\fR stored in \fBvar1\fR and \fB020304\fR stored in \fBvar2\fR. .RE .IP \fB@\fR 5 Moves the cursor to the absolute location in the data string specified by \fIcount\fR. Note that position 0 refers to the first byte in \fIstring\fR. If \fIcount\fR refers to a position beyond the end of \fIstring\fR, then the cursor is positioned after the last byte. If \fIcount\fR is omitted, then an error will be generated. For example, .RS .CS \fBbinary scan \\x01\\x02\\x03\\x04 c2@1H* var1 var2\fR .CE will return \fB2\fR with \fB1 2\fR stored in \fBvar1\fR and \fB020304\fR stored in \fBvar2\fR. .RE .SH "PLATFORM ISSUES" Sometimes it is desirable to format or scan integer values in the native byte order for the machine. Refer to the \fBbyteOrder\fR element of the \fBtcl_platform\fR array to decide which type character to use when formatting or scanning integers. .SH EXAMPLES This is a procedure to write a Tcl string to a binary-encoded channel as UTF-8 data preceded by a length word: .CS proc writeString {channel string} { set data [encoding convertto utf-8 $string] puts -nonewline [\fBbinary format\fR Ia* \e [string length $data] $data] } .CE .PP This procedure reads a string from a channel that was written by the previously presented \fBwriteString\fR procedure: .CS proc readString {channel} { if {![\fBbinary scan\fR [read $channel 4] I length]} { error "missing length" } set data [read $channel $length] return [encoding convertfrom utf-8 $data] } .CE .SH "SEE ALSO" format(n), scan(n), tclvars(n) .SH KEYWORDS binary, format, scan tcl8.4.20/doc/Tcl_Main.30000644003604700454610000001463711737050674013251 0ustar dgp771div'\" '\" Copyright (c) 1994 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" Copyright (c) 2000 Ajuba Solutions. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_Main 3 8.4 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_Main, Tcl_SetMainLoop \- main program and event loop definition for Tcl-based applications .SH SYNOPSIS .nf \fB#include \fR .sp \fBTcl_Main\fR(\fIargc, argv, appInitProc\fR) .sp \fBTcl_SetMainLoop\fR(\fImainLoopProc\fR) .SH ARGUMENTS .AS Tcl_AppInitProc *appInitProc .AP int argc in Number of elements in \fIargv\fR. .AP char *argv[] in Array of strings containing command-line arguments. .AP Tcl_AppInitProc *appInitProc in Address of an application-specific initialization procedure. The value for this argument is usually \fBTcl_AppInit\fR. .AP Tcl_MainLoopProc *mainLoopProc in Address of an application-specific event loop procedure. .BE .SH DESCRIPTION .PP \fBTcl_Main\fR can serve as the main program for Tcl-based shell applications. A ``shell application'' is a program like tclsh or wish that supports both interactive interpretation of Tcl and evaluation of a script contained in a file given as a command line argument. \fBTcl_Main\fR is offered as a convenience to developers of shell applications, so they do not have to reproduce all of the code for proper initialization of the Tcl library and interactive shell operation. Other styles of embedding Tcl in an application are not supported by \fBTcl_Main\fR. Those must be achieved by calling lower level functions in the Tcl library directly. The \fBTcl_Main\fR function has been offered by the Tcl library since release Tcl 7.4. In older releases of Tcl, the Tcl library itself defined a function \fBmain\fR, but that lacks flexibility of embedding style and having a function \fBmain\fR in a library (particularly a shared library) causes problems on many systems. Having \fBmain\fR in the Tcl library would also make it hard to use Tcl in C++ programs, since C++ programs must have special C++ \fBmain\fR functions. .PP Normally each shell application contains a small \fBmain\fR function that does nothing but invoke \fBTcl_Main\fR. \fBTcl_Main\fR then does all the work of creating and running a \fBtclsh\fR-like application. .PP \fBTcl_Main\fR is not provided by the public interface of Tcl's stub library. Programs that call \fBTcl_Main\fR must be linked against the standard Tcl library. Extensions (stub-enabled or not) are not intended to call \fBTcl_Main\fR. .PP \fBTcl_Main\fR is not thread-safe. It should only be called by a single master thread of a multi-threaded application. This restriction is not a problem with normal use described above. .PP \fBTcl_Main\fR and therefore all applications based upon it, like \fBtclsh\fR, use \fBTcl_GetStdChannel\fR to initialize the standard channels to their default values. See \fBTcl_StandardChannels\fR for more information. .PP \fBTcl_Main\fR supports two modes of operation, depending on the values of \fIargc\fR and \fIargv\fR. If \fIargv[1]\fR exists and does not begin with the character \fI-\fR, it is taken to be the name of a file containing a \fIstartup script\fR, which \fBTcl_Main\fR will attempt to evaluate. Otherwise, \fBTcl_Main\fR will enter an interactive mode. .PP In either mode, \fBTcl_Main\fR will define in its master interpreter the Tcl variables \fIargc\fR, \fIargv\fR, \fIargv0\fR, and \fItcl_interactive\fR, as described in the documentation for \fBtclsh\fR. .PP When it has finished its own initialization, but before it processes commands, \fBTcl_Main\fR calls the procedure given by the \fIappInitProc\fR argument. This procedure provides a ``hook'' for the application to perform its own initialization of the interpreter created by \fBTcl_Main\fR, such as defining application-specific commands. The procedure must have an interface that matches the type \fBTcl_AppInitProc\fR: .CS typedef int Tcl_AppInitProc(Tcl_Interp *\fIinterp\fR); .CE \fIAppInitProc\fR is almost always a pointer to \fBTcl_AppInit\fR; for more details on this procedure, see the documentation for \fBTcl_AppInit\fR. .PP When the \fIappInitProc\fR is finished, \fBTcl_Main\fR enters one of its two modes. If a startup script has been provided, \fBTcl_Main\fR attempts to evaluate it. Otherwise, interactive mode begins with examination of the variable \fItcl_rcFileName\fR in the master interpreter. If that variable exists and holds the name of a readable file, the contents of that file are evaluated in the master interpreter. Then interactive operations begin, with prompts and command evaluation results written to the standard output channel, and commands read from the standard input channel and then evaluated. The prompts written to the standard output channel may be customized by defining the Tcl variables \fItcl_prompt1\fR and \fItcl_prompt2\fR as described in the documentation for \fBtclsh\fR. The prompts and command evaluation results are written to the standard output channel only if the Tcl variable \fItcl_interactive\fR in the master interpreter holds a non-zero integer value. .PP .VS 8.4 \fBTcl_SetMainLoop\fR allows setting an event loop procedure to be run. This allows, for example, Tk to be dynamically loaded and set its event loop. The event loop will run following the startup script. If you are in interactive mode, setting the main loop procedure will cause the prompt to become fileevent based and then the loop procedure is called. When the loop procedure returns in interactive mode, interactive operation will continue. The main loop procedure must have an interface that matches the type \fBTcl_MainLoopProc\fR: .CS typedef void Tcl_MainLoopProc(void); .CE .VE 8.4 .PP \fBTcl_Main\fR does not return. Normally a program based on \fBTcl_Main\fR will terminate when the \fBexit\fR command is evaluated. In interactive mode, if an EOF or channel error is encountered on the standard input channel, then \fBTcl_Main\fR itself will evaluate the \fBexit\fR command after the main loop procedure (if any) returns. In non-interactive mode, after \fBTcl_Main\fR evaluates the startup script, and the main loop procedure (if any) returns, \fBTcl_Main\fR will also evaluate the \fBexit\fR command. .SH "SEE ALSO" tclsh(1), Tcl_GetStdChannel(3), Tcl_StandardChannels(3), Tcl_AppInit(3), exit(n) .SH KEYWORDS application-specific initialization, command-line arguments, main program tcl8.4.20/doc/ChnlStack.30000644003604700454610000000746211737050674013433 0ustar dgp771div'\" '\" Copyright (c) 1999-2000 Ajuba Solutions. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. .so man.macros .TH Tcl_StackChannel 3 8.3 Tcl "Tcl Library Procedures" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME Tcl_StackChannel, Tcl_UnstackChannel, Tcl_GetStackedChannel, Tcl_GetTopChannel \- stack an I/O channel on top of another, and undo it .SH SYNOPSIS .nf .nf \fB#include \fR .sp Tcl_Channel \fBTcl_StackChannel\fR(\fIinterp, typePtr, clientData, mask, channel\fR) .sp int \fBTcl_UnstackChannel\fR(\fIinterp, channel\fR) .sp Tcl_Channel \fBTcl_GetStackedChannel\fR(\fIchannel\fR) .sp Tcl_Channel \fBTcl_GetTopChannel\fR(\fIchannel\fR) .sp .SH ARGUMENTS .AS Tcl_ChannelType .AP Tcl_Interp *interp in Interpreter for error reporting. .AP Tcl_ChannelType *typePtr in The new channel I/O procedures to use for \fIchannel\fP. .AP ClientData clientData in Arbitrary one-word value to pass to channel I/O procedures. .AP int mask in Conditions under which \fIchannel\fR will be used: OR-ed combination of \fBTCL_READABLE\fR, \fBTCL_WRITABLE\fR and \fBTCL_EXCEPTION\fR. This can be a subset of the operations currently allowed on \fIchannel\fP. .AP Tcl_Channel channel in An existing Tcl channel such as returned by \fBTcl_CreateChannel\fR. .BE .SH DESCRIPTION .PP These functions are for use by extensions that add processing layers to Tcl I/O channels. Examples include compression and encryption modules. These functions transparently stack and unstack a new channel on top of an existing one. Any number of channels can be stacked together. .PP The implementation of the Tcl channel code was rewritten in 8.3.2 to correct some problems with the previous implementation with regard to stacked channels. Anyone using stacked channels or creating stacked channel drivers should update to the new \fBTCL_CHANNEL_VERSION_2\fR \fBTcl_ChannelType\fR structure. See \fBTcl_CreateChannel\fR for details. .PP \fBTcl_StackChannel\fR stacks a new \fIchannel\fP on an existing channel with the same name that was registered for \fIchannel\fP by \fBTcl_RegisterChannel\fP. .PP \fBTcl_StackChannel\fR works by creating a new channel structure and placing itself on top of the channel stack. EOL translation, encoding and buffering options are shared between all channels in the stack. The hidden channel does no buffering, newline translations, or character set encoding. Instead, the buffering, newline translations, and encoding functions all remain at the top of the channel stack. A pointer to the new top channel structure is returned. If an error occurs when stacking the channel, NULL is returned instead. .PP The \fImask\fP parameter specifies the operations that are allowed on the new channel. These can be a subset of the operations allowed on the original channel. For example, a read-write channel may become read-only after the \fBTcl_StackChannel\fR call. .PP Closing a channel closes the channels stacked below it. The close of stacked channels is executed in a way that allows buffered data to be properly flushed. .PP \fBTcl_UnstackChannel\fP reverses the process. The old channel is associated with the channel name, and the processing module added by \fBTcl_StackChannel\fR is destroyed. If there is no old channel, then \fBTcl_UnstackChannel\fP is equivalent to \fBTcl_Close\fP. If an error occurs unstacking the channel, \fBTCL_ERROR\fR is returned, otherwise \fBTCL_OK\fR is returned. .PP \fBTcl_GetTopChannel\fR returns the top channel in the stack of channels the supplied channel is part of. .PP \fBTcl_GetStackedChannel\fR returns the channel in the stack of channels which is just below the supplied channel. .SH "SEE ALSO" Notifier(3), Tcl_CreateChannel(3), Tcl_OpenFileChannel(3), vwait(n). .SH KEYWORDS channel, compression tcl8.4.20/doc/Translate.30000644003604700454610000000444611737050674013515 0ustar dgp771div'\" '\" Copyright (c) 1989-1993 The Regents of the University of California. '\" Copyright (c) 1994-1998 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_TranslateFileName 3 8.1 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_TranslateFileName \- convert file name to native form and replace tilde with home directory .SH SYNOPSIS .nf \fB#include \fR .sp char * \fBTcl_TranslateFileName\fR(\fIinterp\fR, \fIname\fR, \fIbufferPtr\fR) .SH ARGUMENTS .AS Tcl_DString *bufferPtr .AP Tcl_Interp *interp in Interpreter in which to report an error, if any. .AP "CONST char" *name in File name, which may start with a ``~''. .AP Tcl_DString *bufferPtr in/out If needed, this dynamic string is used to store the new file name. At the time of the call it should be uninitialized or free. The caller must eventually call \fBTcl_DStringFree\fR to free up anything stored here. .BE .SH DESCRIPTION .PP This utility procedure translates a file name to a form suitable for passing to the local operating system. It converts network names into native form and does tilde substitution. .PP If \fBTcl_TranslateFileName\fR has to do tilde substitution or translate the name then it uses the dynamic string at \fI*bufferPtr\fR to hold the new string it generates. After \fBTcl_TranslateFileName\fR returns a non-NULL result, the caller must eventually invoke \fBTcl_DStringFree\fR to free any information placed in \fI*bufferPtr\fR. The caller need not know whether or not \fBTcl_TranslateFileName\fR actually used the string; \fBTcl_TranslateFileName\fR initializes \fI*bufferPtr\fR even if it doesn't use it, so the call to \fBTcl_DStringFree\fR will be safe in either case. .PP If an error occurs (e.g. because there was no user by the given name) then NULL is returned and an error message will be left in the interpreter's result. When an error occurs, \fBTcl_TranslateFileName\fR frees the dynamic string itself so that the caller need not call \fBTcl_DStringFree\fR. .PP The caller is responsible for making sure that the interpreter's result has its default empty value when \fBTcl_TranslateFileName\fR is invoked. .SH "SEE ALSO" filename .SH KEYWORDS file name, home directory, tilde, translate, user tcl8.4.20/doc/TraceVar.30000644003604700454610000004042311737050674013262 0ustar dgp771div'\" '\" Copyright (c) 1989-1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_TraceVar 3 7.4 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_TraceVar, Tcl_TraceVar2, Tcl_UntraceVar, Tcl_UntraceVar2, Tcl_VarTraceInfo, Tcl_VarTraceInfo2 \- monitor accesses to a variable .SH SYNOPSIS .nf \fB#include \fR .sp int \fBTcl_TraceVar(\fIinterp, varName, flags, proc, clientData\fB)\fR .sp int \fBTcl_TraceVar2(\fIinterp, name1, name2, flags, proc, clientData\fB)\fR .sp \fBTcl_UntraceVar(\fIinterp, varName, flags, proc, clientData\fB)\fR .sp \fBTcl_UntraceVar2(\fIinterp, name1, name2, flags, proc, clientData\fB)\fR .sp ClientData \fBTcl_VarTraceInfo(\fIinterp, varName, flags, proc, prevClientData\fB)\fR .sp ClientData \fBTcl_VarTraceInfo2(\fIinterp, name1, name2, flags, proc, prevClientData\fB)\fR .SH ARGUMENTS .AS Tcl_VarTraceProc prevClientData .AP Tcl_Interp *interp in Interpreter containing variable. .AP "CONST char" *varName in Name of variable. May refer to a scalar variable, to an array variable with no index, or to an array variable with a parenthesized index. .AP int flags in OR-ed combination of the values TCL_TRACE_READS, TCL_TRACE_WRITES, TCL_TRACE_UNSETS, TCL_TRACE_ARRAY, TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY, TCL_TRACE_RESULT_DYNAMIC and TCL_TRACE_RESULT_OBJECT. Not all flags are used by all procedures. See below for more information. .AP Tcl_VarTraceProc *proc in Procedure to invoke whenever one of the traced operations occurs. .AP ClientData clientData in Arbitrary one-word value to pass to \fIproc\fR. .AP "CONST char" *name1 in Name of scalar or array variable (without array index). .AP "CONST char" *name2 in For a trace on an element of an array, gives the index of the element. For traces on scalar variables or on whole arrays, is NULL. .AP ClientData prevClientData in If non-NULL, gives last value returned by \fBTcl_VarTraceInfo\fR or \fBTcl_VarTraceInfo2\fR, so this call will return information about next trace. If NULL, this call will return information about first trace. .BE .SH DESCRIPTION .PP \fBTcl_TraceVar\fR allows a C procedure to monitor and control access to a Tcl variable, so that the C procedure is invoked whenever the variable is read or written or unset. If the trace is created successfully then \fBTcl_TraceVar\fR returns TCL_OK. If an error occurred (e.g. \fIvarName\fR specifies an element of an array, but the actual variable isn't an array) then TCL_ERROR is returned and an error message is left in the interpreter's result. .PP The \fIflags\fR argument to \fBTcl_TraceVar\fR indicates when the trace procedure is to be invoked and provides information for setting up the trace. It consists of an OR-ed combination of any of the following values: .TP \fBTCL_GLOBAL_ONLY\fR Normally, the variable will be looked up at the current level of procedure call; if this bit is set then the variable will be looked up at global level, ignoring any active procedures. .TP \fBTCL_NAMESPACE_ONLY\fR Normally, the variable will be looked up at the current level of procedure call; if this bit is set then the variable will be looked up in the current namespace, ignoring any active procedures. .TP \fBTCL_TRACE_READS\fR Invoke \fIproc\fR whenever an attempt is made to read the variable. .TP \fBTCL_TRACE_WRITES\fR Invoke \fIproc\fR whenever an attempt is made to modify the variable. .TP \fBTCL_TRACE_UNSETS\fR Invoke \fIproc\fR whenever the variable is unset. A variable may be unset either explicitly by an \fBunset\fR command, or implicitly when a procedure returns (its local variables are automatically unset) or when the interpreter is deleted (all variables are automatically unset). .TP \fBTCL_TRACE_ARRAY\fR Invoke \fIproc\fR whenever the array command is invoked. This gives the trace procedure a chance to update the array before array names or array get is called. Note that this is called before an array set, but that will trigger write traces. .VS 8.4 .TP \fBTCL_TRACE_RESULT_DYNAMIC\fR The result of invoking the \fIproc\fR is a dynamically allocated string that will be released by the Tcl library via a call to \fBckfree\fR. Must not be specified at the same time as TCL_TRACE_RESULT_OBJECT. .TP \fBTCL_TRACE_RESULT_OBJECT\fR The result of invoking the \fIproc\fR is a Tcl_Obj* (cast to a char*) with a reference count of at least one. The ownership of that reference will be transferred to the Tcl core for release (when the core has finished with it) via a call to \fBTcl_DecrRefCount\fR. Must not be specified at the same time as TCL_TRACE_RESULT_DYNAMIC. .VE 8.4 .PP Whenever one of the specified operations occurs on the variable, \fIproc\fR will be invoked. It should have arguments and result that match the type \fBTcl_VarTraceProc\fR: .CS typedef char *Tcl_VarTraceProc( ClientData \fIclientData\fR, Tcl_Interp *\fIinterp\fR, char *\fIname1\fR, char *\fIname2\fR, int \fIflags\fR); .CE The \fIclientData\fR and \fIinterp\fR parameters will have the same values as those passed to \fBTcl_TraceVar\fR when the trace was created. \fIClientData\fR typically points to an application-specific data structure that describes what to do when \fIproc\fR is invoked. \fIName1\fR and \fIname2\fR give the name of the traced variable in the normal two-part form (see the description of \fBTcl_TraceVar2\fR below for details). \fIFlags\fR is an OR-ed combination of bits providing several pieces of information. One of the bits TCL_TRACE_READS, TCL_TRACE_WRITES, TCL_TRACE_ARRAY, or TCL_TRACE_UNSETS will be set in \fIflags\fR to indicate which operation is being performed on the variable. The bit TCL_GLOBAL_ONLY will be set whenever the variable being accessed is a global one not accessible from the current level of procedure call: the trace procedure will need to pass this flag back to variable-related procedures like \fBTcl_GetVar\fR if it attempts to access the variable. The bit TCL_NAMESPACE_ONLY will be set whenever the variable being accessed is a namespace one not accessible from the current level of procedure call: the trace procedure will need to pass this flag back to variable-related procedures like \fBTcl_GetVar\fR if it attempts to access the variable. The bit TCL_TRACE_DESTROYED will be set in \fIflags\fR if the trace is about to be destroyed; this information may be useful to \fIproc\fR so that it can clean up its own internal data structures (see the section TCL_TRACE_DESTROYED below for more details). Lastly, the bit TCL_INTERP_DESTROYED will be set if the entire interpreter is being destroyed. When this bit is set, \fIproc\fR must be especially careful in the things it does (see the section TCL_INTERP_DESTROYED below). The trace procedure's return value should normally be NULL; see ERROR RETURNS below for information on other possibilities. .PP \fBTcl_UntraceVar\fR may be used to remove a trace. If the variable specified by \fIinterp\fR, \fIvarName\fR, and \fIflags\fR has a trace set with \fIflags\fR, \fIproc\fR, and \fIclientData\fR, then the corresponding trace is removed. If no such trace exists, then the call to \fBTcl_UntraceVar\fR has no effect. The same bits are valid for \fIflags\fR as for calls to \fBTcl_TraceVar\fR. .PP \fBTcl_VarTraceInfo\fR may be used to retrieve information about traces set on a given variable. The return value from \fBTcl_VarTraceInfo\fR is the \fIclientData\fR associated with a particular trace. The trace must be on the variable specified by the \fIinterp\fR, \fIvarName\fR, and \fIflags\fR arguments (only the TCL_GLOBAL_ONLY and TCL_NAMESPACE_ONLY bits from \fIflags\fR is used; other bits are ignored) and its trace procedure must the same as the \fIproc\fR argument. If the \fIprevClientData\fR argument is NULL then the return value corresponds to the first (most recently created) matching trace, or NULL if there are no matching traces. If the \fIprevClientData\fR argument isn't NULL, then it should be the return value from a previous call to \fBTcl_VarTraceInfo\fR. In this case, the new return value will correspond to the next matching trace after the one whose \fIclientData\fR matches \fIprevClientData\fR, or NULL if no trace matches \fIprevClientData\fR or if there are no more matching traces after it. This mechanism makes it possible to step through all of the traces for a given variable that have the same \fIproc\fR. .SH "TWO-PART NAMES" .PP The procedures \fBTcl_TraceVar2\fR, \fBTcl_UntraceVar2\fR, and \fBTcl_VarTraceInfo2\fR are identical to \fBTcl_TraceVar\fR, \fBTcl_UntraceVar\fR, and \fBTcl_VarTraceInfo\fR, respectively, except that the name of the variable consists of two parts. \fIName1\fR gives the name of a scalar variable or array, and \fIname2\fR gives the name of an element within an array. .VS 8.1 When \fIname2\fR is NULL, \fIname1\fR may contain both an array and an element name: if the name contains an open parenthesis and ends with a close parenthesis, then the value between the parentheses is treated as an element name (which can have any string value) and the characters before the first open parenthesis are treated as the name of an array variable. If \fIname2\fR is NULL and \fIname1\fR does not refer to an array element .VE it means that either the variable is a scalar or the trace is to be set on the entire array rather than an individual element (see WHOLE-ARRAY TRACES below for more information). .SH "ACCESSING VARIABLES DURING TRACES" .PP During read, write, and array traces, the trace procedure can read, write, or unset the traced variable using \fBTcl_GetVar2\fR, \fBTcl_SetVar2\fR, and other procedures. While \fIproc\fR is executing, traces are temporarily disabled for the variable, so that calls to \fBTcl_GetVar2\fR and \fBTcl_SetVar2\fR will not cause \fIproc\fR or other trace procedures to be invoked again. Disabling only occurs for the variable whose trace procedure is active; accesses to other variables will still be traced. However, if a variable is unset during a read or write trace then unset traces will be invoked. .PP During unset traces the variable has already been completely expunged. It is possible for the trace procedure to read or write the variable, but this will be a new version of the variable. Traces are not disabled during unset traces as they are for read and write traces, but existing traces have been removed from the variable before any trace procedures are invoked. If new traces are set by unset trace procedures, these traces will be invoked on accesses to the variable by the trace procedures. .SH "CALLBACK TIMING" .PP When read tracing has been specified for a variable, the trace procedure will be invoked whenever the variable's value is read. This includes \fBset\fR Tcl commands, \fB$\fR-notation in Tcl commands, and invocations of the \fBTcl_GetVar\fR and \fBTcl_GetVar2\fR procedures. \fIProc\fR is invoked just before the variable's value is returned. It may modify the value of the variable to affect what is returned by the traced access. If it unsets the variable then the access will return an error just as if the variable never existed. .PP When write tracing has been specified for a variable, the trace procedure will be invoked whenever the variable's value is modified. This includes \fBset\fR commands, commands that modify variables as side effects (such as \fBcatch\fR and \fBscan\fR), and calls to the \fBTcl_SetVar\fR and \fBTcl_SetVar2\fR procedures). \fIProc\fR will be invoked after the variable's value has been modified, but before the new value of the variable has been returned. It may modify the value of the variable to override the change and to determine the value actually returned by the traced access. If it deletes the variable then the traced access will return an empty string. .PP When array tracing has been specified, the trace procedure will be invoked at the beginning of the array command implementation, before any of the operations like get, set, or names have been invoked. The trace procedure can modify the array elements with \fBTcl_SetVar\fR and \fBTcl_SetVar2\fR. .PP When unset tracing has been specified, the trace procedure will be invoked whenever the variable is destroyed. The traces will be called after the variable has been completely unset. .SH "WHOLE-ARRAY TRACES" .PP If a call to \fBTcl_TraceVar\fR or \fBTcl_TraceVar2\fR specifies the name of an array variable without an index into the array, then the trace will be set on the array as a whole. This means that \fIproc\fR will be invoked whenever any element of the array is accessed in the ways specified by \fIflags\fR. When an array is unset, a whole-array trace will be invoked just once, with \fIname1\fR equal to the name of the array and \fIname2\fR NULL; it will not be invoked once for each element. .SH "MULTIPLE TRACES" .PP It is possible for multiple traces to exist on the same variable. When this happens, all of the trace procedures will be invoked on each access, in order from most-recently-created to least-recently-created. When there exist whole-array traces for an array as well as traces on individual elements, the whole-array traces are invoked before the individual-element traces. If a read or write trace unsets the variable then all of the unset traces will be invoked but the remainder of the read and write traces will be skipped. .SH "ERROR RETURNS" .PP Under normal conditions trace procedures should return NULL, indicating successful completion. If \fIproc\fR returns a non-NULL value it signifies that an error occurred. The return value must be a pointer to a static character string containing an error message, .VS 8.4 unless (\fIexactly\fR one of) the TCL_TRACE_RESULT_DYNAMIC and TCL_TRACE_RESULT_OBJECT flags is set, which specify that the result is either a dynamic string (to be released with \fBckfree\fR) or a Tcl_Obj* (cast to char* and to be released with \fBTcl_DecrRefCount\fR) containing the error message. .VE 8.4 If a trace procedure returns an error, no further traces are invoked for the access and the traced access aborts with the given message. Trace procedures can use this facility to make variables read-only, for example (but note that the value of the variable will already have been modified before the trace procedure is called, so the trace procedure will have to restore the correct value). .PP The return value from \fIproc\fR is only used during read and write tracing. During unset traces, the return value is ignored and all relevant trace procedures will always be invoked. .SH "RESTRICTIONS" .PP A trace procedure can be called at any time, even when there is a partially-formed result in the interpreter's result area. If the trace procedure does anything that could damage this result (such as calling \fBTcl_Eval\fR) then it must save the original values of the interpreter's \fBresult\fR and \fBfreeProc\fR fields and restore them before it returns. .SH "UNDEFINED VARIABLES" .PP It is legal to set a trace on an undefined variable. The variable will still appear to be undefined until the first time its value is set. If an undefined variable is traced and then unset, the unset will fail with an error (``no such variable''), but the trace procedure will still be invoked. .SH "TCL_TRACE_DESTROYED FLAG" .PP In an unset callback to \fIproc\fR, the TCL_TRACE_DESTROYED bit is set in \fIflags\fR if the trace is being removed as part of the deletion. Traces on a variable are always removed whenever the variable is deleted; the only time TCL_TRACE_DESTROYED isn't set is for a whole-array trace invoked when only a single element of an array is unset. .SH "TCL_INTERP_DESTROYED" .PP When an interpreter is destroyed, unset traces are called for all of its variables. The TCL_INTERP_DESTROYED bit will be set in the \fIflags\fR argument passed to the trace procedures. Trace procedures must be extremely careful in what they do if the TCL_INTERP_DESTROYED bit is set. It is not safe for the procedures to invoke any Tcl procedures on the interpreter, since its state is partially deleted. All that trace procedures should do under these circumstances is to clean up and free their own internal data structures. .SH BUGS .PP Tcl doesn't do any error checking to prevent trace procedures from misusing the interpreter during traces with TCL_INTERP_DESTROYED set. .PP Array traces are not yet integrated with the Tcl "info exists" command, nor is there Tcl-level access to array traces. .SH KEYWORDS clientData, trace, variable tcl8.4.20/doc/glob.n0000644003604700454610000001763712052456743012602 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH glob n 8.3 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME glob \- Return names of files that match patterns .SH SYNOPSIS \fBglob \fR?\fIswitches\fR? \fIpattern \fR?\fIpattern ...\fR? .BE .SH DESCRIPTION .PP This command performs file name ``globbing'' in a fashion similar to the csh shell. It returns a list of the files whose names match any of the \fIpattern\fR arguments. .LP If the initial arguments to \fBglob\fR start with \fB\-\fR then they are treated as switches. The following switches are currently supported: .VS 8.3 .TP \fB\-directory\fR \fIdirectory\fR Search for files which match the given patterns starting in the given \fIdirectory\fR. This allows searching of directories whose name contains glob-sensitive characters without the need to quote such characters explicitly. This option may not be used in conjunction with \fB\-path\fR, which is used to allow searching for complete file paths whose names may contain glob-sensitive characters. .TP \fB\-join\fR The remaining pattern arguments are treated as a single pattern obtained by joining the arguments with directory separators. .VE 8.3 .TP \fB\-nocomplain\fR Allows an empty list to be returned without error; without this switch an error is returned if the result list would be empty. .VS 8.3 .TP \fB\-path\fR \fIpathPrefix\fR Search for files with the given \fIpathPrefix\fR where the rest of the name matches the given patterns. This allows searching for files with names similar to a given file (as opposed to a directory) even when the names contain glob-sensitive characters. This option may not be used in conjunction with \fB\-directory\fR. For example, to find all files with the same root name as $path, but differing extensions, you should use \fBglob -path [file rootname $path] .*\fR which will work even if $path contains numerous glob-sensitive characters. .TP \fB\-tails\fR Only return the part of each file found which follows the last directory named in any \fB\-directory\fR or \fB\-path\fR path specification. Thus \fBglob -tails -directory $dir *\fR is equivalent to \fBset pwd [pwd] ; cd $dir ; glob *; cd $pwd\fR. For \fB\-path\fR specifications, the returned names will include the last path segment, so \fBglob -tails -path [file rootname ~/foo.tex] .*\fR will return paths like \fBfoo.aux foo.bib foo.tex\fR etc. .TP \fB\-types\fR \fItypeList\fR Only list files or directories which match \fItypeList\fR, where the items in the list have two forms. The first form is like the \-type option of the Unix find command: \fIb\fR (block special file), \fIc\fR (character special file), \fId\fR (directory), \fIf\fR (plain file), \fIl\fR (symbolic link), \fIp\fR (named pipe), or \fIs\fR (socket), where multiple types may be specified in the list. \fBGlob\fR will return all files which match at least one of the types given. Note that symbolic links will be returned both if \fB\-types l\fR is given, or if the target of a link matches the requested type. So, a link to a directory will be returned if \fB\-types d\fR was specified. .RS .PP The second form specifies types where all the types given must match. These are \fIr\fR, \fIw\fR, \fIx\fR as file permissions, and \fIreadonly\fR, \fIhidden\fR as special permission cases. .PP The two forms may be mixed, so \fB\-types {d f r w}\fR will find all regular files OR directories that have both read AND write permissions. The following are equivalent: .RS .CS \fBglob \-type d *\fR \fBglob */\fR .CE .RE except that the first case doesn't return the trailing ``/'' and is more platform independent. .RE .VE 8.3 .TP \fB\-\|\-\fR Marks the end of switches. The argument following this one will be treated as a \fIpattern\fR even if it starts with a \fB\-\fR. .PP The \fIpattern\fR arguments may contain any of the following special characters: .TP 10 \fB?\fR Matches any single character. .TP 10 \fB*\fR Matches any sequence of zero or more characters. .TP 10 \fB[\fIchars\fB]\fR Matches any single character in \fIchars\fR. If \fIchars\fR contains a sequence of the form \fIa\fB\-\fIb\fR then any character between \fIa\fR and \fIb\fR (inclusive) will match. .TP 10 \fB\e\fIx\fR Matches the character \fIx\fR. .TP 10 \fB{\fIa\fB,\fIb\fB,\fI...\fR} Matches any of the strings \fIa\fR, \fIb\fR, etc. .LP On Unix, as with csh, a ``.'' at the beginning of a file's name or just after a ``/'' must be matched explicitly or with a {} construct, unless the ``-types hidden'' flag is given (since ``.'' at the beginning of a file's name indicates that it is hidden). On other platforms, files beginning with a ``.'' are handled no differently to any others, except the special directories ``.'' and ``..'' which must be matched explicitly (this is to avoid a recursive pattern like ``glob -join * * * *'' from recursing up the directory hierarchy as well as down). In addition, all ``/'' characters must be matched explicitly. .LP If the first character in a \fIpattern\fR is ``~'' then it refers to the home directory for the user whose name follows the ``~''. If the ``~'' is followed immediately by ``/'' then the value of the HOME environment variable is used. .LP The \fBglob\fR command differs from csh globbing in two ways. First, it does not sort its result list (use the \fBlsort\fR command if you want the list sorted). Second, \fBglob\fR only returns the names of files that actually exist; in csh no check for existence is made unless a pattern contains a ?, *, or [] construct. .LP When the \fBglob\fR command returns relative paths whose filenames start with a tilde ``~'' (for example through \fBglob *\fR or \fBglob -tails\fR, the returned list will not quote the tilde with ``./''. This means care must be taken if those names are later to be used with \fBfile join\fR, to avoid them being interpreted as absolute paths pointing to a given user's home directory. .SH "PORTABILITY ISSUES" .PP Unlike other Tcl commands that will accept both network and native style names (see the \fBfilename\fR manual entry for details on how native and network names are specified), the \fBglob\fR command only accepts native names. .TP \fBWindows\fR . For Windows UNC names, the servername and sharename components of the path may not contain ?, *, or [] constructs. On Windows NT, if \fIpattern\fR is of the form ``\fB~\fIusername\fB@\fIdomain\fR'' it refers to the home directory of the user whose account information resides on the specified NT domain server. Otherwise, user account information is obtained from the local computer. On Windows 95 and 98, \fBglob\fR accepts patterns like ``.../'' and ``..../'' for successively higher up parent directories. . Since the backslash character has a special meaning to the glob command, glob patterns containing Windows style path separators need special care. The pattern \fIC:\e\efoo\e\e*\fR is interpreted as \fIC:\efoo\e*\fR where \fI\ef\fR will match the single character \fIf\fR and \fI\e*\fR will match the single character \fI*\fR and will not be interpreted as a wildcard character. One solution to this problem is to use the Unix style forward slash as a path separator. Windows style paths can be converted to Unix style paths with the command \fBfile join $path\fR (or \fBfile normalize $path\fR in Tcl 8.4). .SH EXAMPLES Find all the Tcl files in the current directory: .CS \fBglob\fR *.tcl .CE .PP Find all the Tcl files in the user's home directory, irrespective of what the current directory is: .CS \fBglob\fR \-directory ~ *.tcl .CE .PP Find all subdirectories of the current directory: .CS \fBglob\fR \-type d * .CE .PP Find all files whose name contains an "a", a "b" or the sequence "cde": .CS \fBglob\fR \-type f *{a,b,cde}* .CE .SH "SEE ALSO" file(n) .SH KEYWORDS exist, file, glob, pattern tcl8.4.20/doc/TraceCmd.30000644003604700454610000001575011737050674013242 0ustar dgp771div'\" '\" Copyright (c) 2002 Donal K. Fellows '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_TraceCommand 3 7.4 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_CommandTraceInfo, Tcl_TraceCommand, Tcl_UntraceCommand \- monitor renames and deletes of a command .SH SYNOPSIS .nf \fB#include \fR .sp ClientData \fBTcl_CommandTraceInfo(\fIinterp, cmdName, flags, proc, prevClientData\fB)\fR .sp int \fBTcl_TraceCommand(\fIinterp, cmdName, flags, proc, clientData\fB)\fR .sp void \fBTcl_UntraceCommand(\fIinterp, cmdName, flags, proc, clientData\fB)\fR .SH ARGUMENTS .AS Tcl_CommandTraceProc prevClientData .AP Tcl_Interp *interp in Interpreter containing the command. .AP "CONST char" *cmdName in Name of command. .AP int flags in OR-ed collection of the value TCL_TRACE_RENAME and TCL_TRACE_DELETE. .AP Tcl_CommandTraceProc *proc in Procedure to call when specified operations occur to \fIcmdName\fR. .AP ClientData clientData in Arbitrary argument to pass to \fIproc\fR. .AP ClientData prevClientData in If non-NULL, gives last value returned by \fBTcl_CommandTraceInfo\fR, so this call will return information about next trace. If NULL, this call will return information about first trace. .BE .SH DESCRIPTION .PP \fBTcl_TraceCommand\fR allows a C procedure to monitor operations performed on a Tcl command, so that the C procedure is invoked whenever the command is renamed or deleted. If the trace is created successfully then \fBTcl_TraceCommand\fR returns TCL_OK. If an error occurred (e.g. \fIcmdName\fR specifies a non-existent command) then TCL_ERROR is returned and an error message is left in the interpreter's result. .PP The \fIflags\fR argument to \fBTcl_TraceCommand\fR indicates when the trace procedure is to be invoked. It consists of an OR-ed combination of any of the following values: .TP \fBTCL_TRACE_RENAME\fR Invoke \fIproc\fR whenever the command is renamed. .TP \fBTCL_TRACE_DELETE\fR Invoke \fIproc\fR when the command is deleted. .PP Whenever one of the specified operations occurs to the command, \fIproc\fR will be invoked. It should have arguments and result that match the type \fBTcl_CommandTraceProc\fR: .CS typedef void Tcl_CommandTraceProc( ClientData \fIclientData\fR, Tcl_Interp *\fIinterp\fR, CONST char *\fIoldName\fR, CONST char *\fInewName\fR, int \fIflags\fR); .CE The \fIclientData\fR and \fIinterp\fR parameters will have the same values as those passed to \fBTcl_TraceCommand\fR when the trace was created. \fIClientData\fR typically points to an application-specific data structure that describes what to do when \fIproc\fR is invoked. \fIOldName\fR gives the name of the command being renamed, and \fInewName\fR gives the name that the command is being renamed to (or an empty string or NULL when the command is being deleted.) \fIFlags\fR is an OR-ed combination of bits potentially providing several pieces of information. One of the bits TCL_TRACE_RENAME and TCL_TRACE_DELETE will be set in \fIflags\fR to indicate which operation is being performed on the command. The bit TCL_TRACE_DESTROYED will be set in \fIflags\fR if the trace is about to be destroyed; this information may be useful to \fIproc\fR so that it can clean up its own internal data structures (see the section TCL_TRACE_DESTROYED below for more details). Lastly, the bit TCL_INTERP_DESTROYED will be set if the entire interpreter is being destroyed. When this bit is set, \fIproc\fR must be especially careful in the things it does (see the section TCL_INTERP_DESTROYED below). .PP \fBTcl_UntraceCommand\fR may be used to remove a trace. If the command specified by \fIinterp\fR, \fIcmdName\fR, and \fIflags\fR has a trace set with \fIflags\fR, \fIproc\fR, and \fIclientData\fR, then the corresponding trace is removed. If no such trace exists, then the call to \fBTcl_UntraceCommand\fR has no effect. The same bits are valid for \fIflags\fR as for calls to \fBTcl_TraceCommand\fR. .PP \fBTcl_CommandTraceInfo\fR may be used to retrieve information about traces set on a given command. The return value from \fBTcl_CommandTraceInfo\fR is the \fIclientData\fR associated with a particular trace. The trace must be on the command specified by the \fIinterp\fR, \fIcmdName\fR, and \fIflags\fR arguments (note that currently the flags are ignored; \fIflags\fR should be set to 0 for future compatibility) and its trace procedure must the same as the \fIproc\fR argument. If the \fIprevClientData\fR argument is NULL then the return value corresponds to the first (most recently created) matching trace, or NULL if there are no matching traces. If the \fIprevClientData\fR argument isn't NULL, then it should be the return value from a previous call to \fBTcl_CommandTraceInfo\fR. In this case, the new return value will correspond to the next matching trace after the one whose \fIclientData\fR matches \fIprevClientData\fR, or NULL if no trace matches \fIprevClientData\fR or if there are no more matching traces after it. This mechanism makes it possible to step through all of the traces for a given command that have the same \fIproc\fR. .SH "CALLING COMMANDS DURING TRACES" .PP During rename traces, the command being renamed is visible with both names simultaneously, and the command still exists during delete traces (if TCL_INTERP_DESTROYED is not set). However, there is no mechanism for signaling that an error occurred in a trace procedure, so great care should be taken that errors do not get silently lost. .SH "MULTIPLE TRACES" .PP It is possible for multiple traces to exist on the same command. When this happens, all of the trace procedures will be invoked on each access, in order from most-recently-created to least-recently-created. Attempts to delete the command during a delete trace will fail silently, since the command is already scheduled for deletion anyway. If the command being renamed is renamed by one of its rename traces, that renaming takes precedence over the one that triggered the trace and the collection of traces will not be reexecuted; if several traces rename the command, the last renaming takes precedence. .SH "TCL_TRACE_DESTROYED FLAG" .PP In a delete callback to \fIproc\fR, the TCL_TRACE_DESTROYED bit is set in \fIflags\fR. '\" Perhaps need some more comments here? - DKF .SH "TCL_INTERP_DESTROYED" .PP When an interpreter is destroyed, unset traces are called for all of its commands. The TCL_INTERP_DESTROYED bit will be set in the \fIflags\fR argument passed to the trace procedures. Trace procedures must be extremely careful in what they do if the TCL_INTERP_DESTROYED bit is set. It is not safe for the procedures to invoke any Tcl procedures on the interpreter, since its state is partially deleted. All that trace procedures should do under these circumstances is to clean up and free their own internal data structures. .SH BUGS .PP Tcl doesn't do any error checking to prevent trace procedures from misusing the interpreter during traces with TCL_INTERP_DESTROYED set. .SH KEYWORDS clientData, trace, command tcl8.4.20/doc/OpenTcp.30000644003604700454610000001643012052456743013122 0ustar dgp771div'\" '\" Copyright (c) 1996-7 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_OpenTcpClient 3 8.0 Tcl "Tcl Library Procedures" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME Tcl_OpenTcpClient, Tcl_MakeTcpClientChannel, Tcl_OpenTcpServer \- procedures to open channels using TCP sockets .SH SYNOPSIS .nf \fB#include \fR .sp Tcl_Channel \fBTcl_OpenTcpClient\fR(\fIinterp, port, host, myaddr, myport, async\fR) .sp Tcl_Channel \fBTcl_MakeTcpClientChannel\fR(\fIsock\fR) .sp Tcl_Channel \fBTcl_OpenTcpServer\fR(\fIinterp, port, myaddr, proc, clientData\fR) .sp .SH ARGUMENTS .AS Tcl_ChannelType newClientProcPtr in .AP Tcl_Interp *interp in Tcl interpreter to use for error reporting. If non-NULL and an error occurs, an error message is left in the interpreter's result. .AP int port in A port number to connect to as a client or to listen on as a server. .AP "CONST char" *host in A string specifying a host name or address for the remote end of the connection. .AP int myport in A port number for the client's end of the socket. If 0, a port number is allocated at random. .AP "CONST char" *myaddr in A string specifying the host name or address for network interface to use for the local end of the connection. If NULL, a default interface is chosen. .AP int async in If nonzero, the client socket is connected asynchronously to the server. .AP ClientData sock in Platform-specific handle for client TCP socket. .AP Tcl_TcpAcceptProc *proc in Pointer to a procedure to invoke each time a new connection is accepted via the socket. .AP ClientData clientData in Arbitrary one-word value to pass to \fIproc\fR. .BE .SH DESCRIPTION .PP These functions are convenience procedures for creating channels that communicate over TCP sockets. The operations on a channel are described in the manual entry for \fBTcl_OpenFileChannel\fR. .SH TCL_OPENTCPCLIENT .PP \fBTcl_OpenTcpClient\fR opens a client TCP socket connected to a \fIport\fR on a specific \fIhost\fR, and returns a channel that can be used to communicate with the server. The host to connect to can be specified either as a domain name style name (e.g. \fBwww.sunlabs.com\fR), or as a string containing the alphanumeric representation of its four-byte address (e.g. \fB127.0.0.1\fR). Use the string \fBlocalhost\fR to connect to a TCP socket on the host on which the function is invoked. .PP The \fImyaddr\fR and \fImyport\fR arguments allow a client to specify an address for the local end of the connection. If \fImyaddr\fR is NULL, then an interface is chosen automatically by the operating system. If \fImyport\fR is 0, then a port number is chosen at random by the operating system. .PP If \fIasync\fR is zero, the call to \fBTcl_OpenTcpClient\fR returns only after the client socket has either successfully connected to the server, or the attempted connection has failed. If \fIasync\fR is nonzero the socket is connected asynchronously and the returned channel may not yet be connected to the server when the call to \fBTcl_OpenTcpClient\fR returns. If the channel is in blocking mode and an input or output operation is done on the channel before the connection is completed or fails, that operation will wait until the connection either completes successfully or fails. If the channel is in nonblocking mode, the input or output operation will return immediately and a subsequent call to \fBTcl_InputBlocked\fR on the channel will return nonzero. .PP The returned channel is opened for reading and writing. If an error occurs in opening the socket, \fBTcl_OpenTcpClient\fR returns NULL and records a POSIX error code that can be retrieved with \fBTcl_GetErrno\fR. In addition, if \fIinterp\fR is non-NULL, an error message is left in the interpreter's result. .PP The newly created channel is not registered in the supplied interpreter; to register it, use \fBTcl_RegisterChannel\fR. If one of the standard channels, \fBstdin, stdout\fR or \fBstderr\fR was previously closed, the act of creating the new channel also assigns it as a replacement for the standard channel. .SH TCL_MAKETCPCLIENTCHANNEL .PP \fBTcl_MakeTcpClientChannel\fR creates a \fBTcl_Channel\fR around an existing, platform specific, handle for a client TCP socket. .PP The newly created channel is not registered in the supplied interpreter; to register it, use \fBTcl_RegisterChannel\fR. If one of the standard channels, \fBstdin, stdout\fR or \fBstderr\fR was previously closed, the act of creating the new channel also assigns it as a replacement for the standard channel. .SH TCL_OPENTCPSERVER .PP \fBTcl_OpenTcpServer\fR opens a TCP socket on the local host on a specified \fIport\fR and uses the Tcl event mechanism to accept requests from clients to connect to it. The \fImyaddr\fP argument specifies the network interface. If \fImyaddr\fP is NULL the special address INADDR_ANY should be used to allow connections from any network interface. Each time a client connects to this socket, Tcl creates a channel for the new connection and invokes \fIproc\fR with information about the channel. \fIProc\fR must match the following prototype: .CS typedef void Tcl_TcpAcceptProc( ClientData \fIclientData\fR, Tcl_Channel \fIchannel\fR, char *\fIhostName\fR, int \fIport\fP); .CE .PP The \fIclientData\fR argument will be the same as the \fIclientData\fR argument to \fBTcl_OpenTcpServer\fR, \fIchannel\fR will be the handle for the new channel, \fIhostName\fR points to a string containing the name of the client host making the connection, and \fIport\fP will contain the client's port number. The new channel is opened for both input and output. If \fIproc\fR raises an error, the connection is closed automatically. \fIProc\fR has no return value, but if it wishes to reject the connection it can close \fIchannel\fR. .PP \fBTcl_OpenTcpServer\fR normally returns a pointer to a channel representing the server socket. If an error occurs, \fBTcl_OpenTcpServer\fR returns NULL and records a POSIX error code that can be retrieved with \fBTcl_GetErrno\fR. In addition, if the interpreter is non-NULL, an error message is left in the interpreter's result. .PP The channel returned by \fBTcl_OpenTcpServer\fR cannot be used for either input or output. It is simply a handle for the socket used to accept connections. The caller can close the channel to shut down the server and disallow further connections from new clients. .PP TCP server channels operate correctly only in applications that dispatch events through \fBTcl_DoOneEvent\fR or through Tcl commands such as \fBvwait\fR; otherwise Tcl will never notice that a connection request from a remote client is pending. .PP The newly created channel is not registered in the supplied interpreter; to register it, use \fBTcl_RegisterChannel\fR. If one of the standard channels, \fBstdin, stdout\fR or \fBstderr\fR was previously closed, the act of creating the new channel also assigns it as a replacement for the standard channel. .VS .SH "PLATFORM ISSUES" .PP On Unix platforms, the socket handle is a Unix file descriptor as returned by the \fBsocket\fR system call. On the Windows platform, the socket handle is a \fBSOCKET\fR as defined in the WinSock API. .VE .SH "SEE ALSO" Tcl_OpenFileChannel(3), Tcl_RegisterChannel(3), vwait(n) .SH KEYWORDS client, server, TCP tcl8.4.20/doc/ObjectType.30000644003604700454610000001771211737050674013630 0ustar dgp771div'\" '\" Copyright (c) 1996-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_ObjType 3 8.0 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_RegisterObjType, Tcl_GetObjType, Tcl_AppendAllObjTypes, Tcl_ConvertToType \- manipulate Tcl object types .SH SYNOPSIS .nf \fB#include \fR .sp \fBTcl_RegisterObjType\fR(\fItypePtr\fR) .sp Tcl_ObjType * \fBTcl_GetObjType\fR(\fItypeName\fR) .sp int \fBTcl_AppendAllObjTypes\fR(\fIinterp, objPtr\fR) .sp int \fBTcl_ConvertToType\fR(\fIinterp, objPtr, typePtr\fR) .SH ARGUMENTS .AS Tcl_ObjType *typeName in .AP Tcl_ObjType *typePtr in Points to the structure containing information about the Tcl object type. This storage must live forever, typically by being statically allocated. .AP "CONST char" *typeName in The name of a Tcl object type that \fBTcl_GetObjType\fR should look up. .AP Tcl_Interp *interp in Interpreter to use for error reporting. .AP Tcl_Obj *objPtr in For \fBTcl_AppendAllObjTypes\fR, this points to the object onto which it appends the name of each object type as a list element. For \fBTcl_ConvertToType\fR, this points to an object that must have been the result of a previous call to \fBTcl_NewObj\fR. .BE .SH DESCRIPTION .PP The procedures in this man page manage Tcl object types. The are used to register new object types, look up types, and force conversions from one type to another. .PP \fBTcl_RegisterObjType\fR registers a new Tcl object type in the table of all object types supported by Tcl. The argument \fItypePtr\fR points to a Tcl_ObjType structure that describes the new type by giving its name and by supplying pointers to four procedures that implement the type. If the type table already contains a type with the same name as in \fItypePtr\fR, it is replaced with the new type. The Tcl_ObjType structure is described in the section \fBTHE TCL_OBJTYPE STRUCTURE\fR below. .PP \fBTcl_GetObjType\fR returns a pointer to the Tcl_ObjType with name \fItypeName\fR. It returns NULL if no type with that name is registered. .PP \fBTcl_AppendAllObjTypes\fR appends the name of each object type as a list element onto the Tcl object referenced by \fIobjPtr\fR. The return value is \fBTCL_OK\fR unless there was an error converting \fIobjPtr\fR to a list object; in that case \fBTCL_ERROR\fR is returned. .PP \fBTcl_ConvertToType\fR converts an object from one type to another if possible. It creates a new internal representation for \fIobjPtr\fR appropriate for the target type \fItypePtr\fR and sets its \fItypePtr\fR member to that type. Any internal representation for \fIobjPtr\fR's old type is freed. If an error occurs during conversion, it returns \fBTCL_ERROR\fR and leaves an error message in the result object for \fIinterp\fR unless \fIinterp\fR is NULL. Otherwise, it returns \fBTCL_OK\fR. Passing a NULL \fIinterp\fR allows this procedure to be used as a test whether the conversion can be done (and in fact was done). .SH "THE TCL_OBJTYPE STRUCTURE" .PP Extension writers can define new object types by defining four procedures, initializing a Tcl_ObjType structure to describe the type, and calling \fBTcl_RegisterObjType\fR. The \fBTcl_ObjType\fR structure is defined as follows: .CS typedef struct Tcl_ObjType { char *\fIname\fR; Tcl_FreeInternalRepProc *\fIfreeIntRepProc\fR; Tcl_DupInternalRepProc *\fIdupIntRepProc\fR; Tcl_UpdateStringProc *\fIupdateStringProc\fR; Tcl_SetFromAnyProc *\fIsetFromAnyProc\fR; } Tcl_ObjType; .CE .PP The \fIname\fR member describes the name of the type, e.g. \fBint\fR. Extension writers can look up an object type using its name with the \fBTcl_GetObjType\fR procedure. The remaining four members are pointers to procedures called by the generic Tcl object code: .PP The \fIsetFromAnyProc\fR member contains the address of a function called to create a valid internal representation from an object's string representation. .CS typedef int (Tcl_SetFromAnyProc) (Tcl_Interp *\fIinterp\fR, Tcl_Obj *\fIobjPtr\fR); .CE If an internal representation can't be created from the string, it returns \fBTCL_ERROR\fR and puts a message describing the error in the result object for \fIinterp\fR unless \fIinterp\fR is NULL. If \fIsetFromAnyProc\fR is successful, it stores the new internal representation, sets \fIobjPtr\fR's \fItypePtr\fR member to point to \fIsetFromAnyProc\fR's \fBTcl_ObjType\fR, and returns \fBTCL_OK\fR. Before setting the new internal representation, the \fIsetFromAnyProc\fR must free any internal representation of \fIobjPtr\fR's old type; it does this by calling the old type's \fIfreeIntRepProc\fR if it is not NULL. As an example, the \fIsetFromAnyProc\fR for the builtin Tcl integer type gets an up-to-date string representation for \fIobjPtr\fR by calling \fBTcl_GetStringFromObj\fR. It parses the string to obtain an integer and, if this succeeds, stores the integer in \fIobjPtr\fR's internal representation and sets \fIobjPtr\fR's \fItypePtr\fR member to point to the integer type's Tcl_ObjType structure. Do not release \fIobjPtr\fR's old internal representation unless you replace it with a new one or reset the \fItypePtr\fR member to NULL. .PP The \fIupdateStringProc\fR member contains the address of a function called to create a valid string representation from an object's internal representation. .CS typedef void (Tcl_UpdateStringProc) (Tcl_Obj *\fIobjPtr\fR); .CE \fIobjPtr\fR's \fIbytes\fR member is always NULL when it is called. It must always set \fIbytes\fR non-NULL before returning. We require the string representation's byte array to have a null after the last byte, at offset \fIlength\fR; this allows string representations that do not contain null bytes to be treated as conventional null character-terminated C strings. Storage for the byte array must be allocated in the heap by \fBTcl_Alloc\fR or \fBckalloc\fR. Note that \fIupdateStringProc\fRs must allocate enough storage for the string's bytes and the terminating null byte. The \fIupdateStringProc\fR for Tcl's builtin list type, for example, builds an array of strings for each element object and then calls \fBTcl_Merge\fR to construct a string with proper Tcl list structure. It stores this string as the list object's string representation. .PP The \fIdupIntRepProc\fR member contains the address of a function called to copy an internal representation from one object to another. .CS typedef void (Tcl_DupInternalRepProc) (Tcl_Obj *\fIsrcPtr\fR, Tcl_Obj *\fIdupPtr\fR); .CE \fIdupPtr\fR's internal representation is made a copy of \fIsrcPtr\fR's internal representation. Before the call, \fIsrcPtr\fR's internal representation is valid and \fIdupPtr\fR's is not. \fIsrcPtr\fR's object type determines what copying its internal representation means. For example, the \fIdupIntRepProc\fR for the Tcl integer type simply copies an integer. The builtin list type's \fIdupIntRepProc\fR allocates a new array that points at the original element objects; the elements are shared between the two lists (and their reference counts are incremented to reflect the new references). .PP The \fIfreeIntRepProc\fR member contains the address of a function that is called when an object is freed. .CS typedef void (Tcl_FreeInternalRepProc) (Tcl_Obj *\fIobjPtr\fR); .CE The \fIfreeIntRepProc\fR function can deallocate the storage for the object's internal representation and do other type-specific processing necessary when an object is freed. For example, Tcl list objects have an \fIinternalRep.otherValuePtr\fR that points to an array of pointers to each element in the list. The list type's \fIfreeIntRepProc\fR decrements the reference count for each element object (since the list will no longer refer to those objects), then deallocates the storage for the array of pointers. The \fIfreeIntRepProc\fR member can be set to NULL to indicate that the internal representation does not require freeing. .SH "SEE ALSO" Tcl_NewObj, Tcl_DecrRefCount, Tcl_IncrRefCount .SH KEYWORDS internal representation, object, object type, string representation, type conversion tcl8.4.20/doc/source.n0000644003604700454610000000371712052456743013151 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" Copyright (c) 2000 Scriptics Corporation. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH source n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME source \- Evaluate a file or resource as a Tcl script .SH SYNOPSIS \fBsource \fIfileName\fR .sp \fBsource\fR \fB\-rsrc \fIresourceName \fR?\fIfileName\fR? .sp \fBsource\fR \fB\-rsrcid \fIresourceId \fR?\fIfileName\fR? .BE .SH DESCRIPTION .PP This command takes the contents of the specified file or resource and passes it to the Tcl interpreter as a text script. The return value from \fBsource\fR is the return value of the last command executed in the script. If an error occurs in evaluating the contents of the script then the \fBsource\fR command will return that error. If a \fBreturn\fR command is invoked from within the script then the remainder of the file will be skipped and the \fBsource\fR command will return normally with the result from the \fBreturn\fR command. .PP .VS 8.4 The end-of-file character for files is '\\32' (^Z) for all platforms. The source command will read files up to this character. This restriction does not exist for the \fBread\fR or \fBgets\fR commands, allowing for files containing code and data segments (scripted documents). If you require a ``^Z'' in code for string comparison, you can use ``\\032'' or ``\\u001a'', which will be safely substituted by the Tcl interpreter into ``^Z''. .VE 8.4 .SH EXAMPLE Run the script in the file \fBfoo.tcl\fR and then the script in the file \fBbar.tcl\fR: .CS \fBsource\fR foo.tcl \fBsource\fR bar.tcl .CE Alternatively: .CS foreach scriptFile {foo.tcl bar.tcl} { \fBsource\fR $scriptFile } .CE .SH "SEE ALSO" file(n), cd(n), info(n) .SH KEYWORDS file, script tcl8.4.20/doc/Object.30000644003604700454610000003300111737050674012753 0ustar dgp771div'\" '\" Copyright (c) 1996-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_Obj 3 8.1 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_NewObj, Tcl_DuplicateObj, Tcl_IncrRefCount, Tcl_DecrRefCount, Tcl_IsShared, Tcl_InvalidateStringRep \- manipulate Tcl objects .SH SYNOPSIS .nf \fB#include \fR .sp Tcl_Obj * \fBTcl_NewObj\fR() .sp Tcl_Obj * \fBTcl_DuplicateObj\fR(\fIobjPtr\fR) .sp \fBTcl_IncrRefCount\fR(\fIobjPtr\fR) .sp \fBTcl_DecrRefCount\fR(\fIobjPtr\fR) .sp int \fBTcl_IsShared\fR(\fIobjPtr\fR) .sp \fBTcl_InvalidateStringRep\fR(\fIobjPtr\fR) .SH ARGUMENTS .AS Tcl_Obj *objPtr in .AP Tcl_Obj *objPtr in Points to an object; must have been the result of a previous call to \fBTcl_NewObj\fR. .BE .SH INTRODUCTION .PP This man page presents an overview of Tcl objects and how they are used. It also describes generic procedures for managing Tcl objects. These procedures are used to create and copy objects, and increment and decrement the count of references (pointers) to objects. The procedures are used in conjunction with ones that operate on specific types of objects such as \fBTcl_GetIntFromObj\fR and \fBTcl_ListObjAppendElement\fR. The individual procedures are described along with the data structures they manipulate. .PP Tcl's \fIdual-ported\fR objects provide a general-purpose mechanism for storing and exchanging Tcl values. They largely replace the use of strings in Tcl. For example, they are used to store variable values, command arguments, command results, and scripts. Tcl objects behave like strings but also hold an internal representation that can be manipulated more efficiently. For example, a Tcl list is now represented as an object that holds the list's string representation as well as an array of pointers to the objects for each list element. Dual-ported objects avoid most runtime type conversions. They also improve the speed of many operations since an appropriate representation is immediately available. The compiler itself uses Tcl objects to cache the instruction bytecodes resulting from compiling scripts. .PP The two representations are a cache of each other and are computed lazily. That is, each representation is only computed when necessary, it is computed from the other representation, and, once computed, it is saved. In addition, a change in one representation invalidates the other one. As an example, a Tcl program doing integer calculations can operate directly on a variable's internal machine integer representation without having to constantly convert between integers and strings. Only when it needs a string representing the variable's value, say to print it, will the program regenerate the string representation from the integer. Although objects contain an internal representation, their semantics are defined in terms of strings: an up-to-date string can always be obtained, and any change to the object will be reflected in that string when the object's string representation is fetched. Because of this representation invalidation and regeneration, it is dangerous for extension writers to access \fBTcl_Obj\fR fields directly. It is better to access Tcl_Obj information using procedures like \fBTcl_GetStringFromObj\fR and \fBTcl_GetString\fR. .PP Objects are allocated on the heap and are referenced using a pointer to their \fBTcl_Obj\fR structure. Objects are shared as much as possible. This significantly reduces storage requirements because some objects such as long lists are very large. Also, most Tcl values are only read and never modified. This is especially true for procedure arguments, which can be shared between the caller and the called procedure. Assignment and argument binding is done by simply assigning a pointer to the value. Reference counting is used to determine when it is safe to reclaim an object's storage. .PP Tcl objects are typed. An object's internal representation is controlled by its type. Seven types are predefined in the Tcl core including integer, double, list, and bytecode. Extension writers can extend the set of types by using the procedure \fBTcl_RegisterObjType\fR . .SH "THE TCL_OBJ STRUCTURE" .PP Each Tcl object is represented by a \fBTcl_Obj\fR structure which is defined as follows. .CS typedef struct Tcl_Obj { int \fIrefCount\fR; char *\fIbytes\fR; int \fIlength\fR; Tcl_ObjType *\fItypePtr\fR; union { long \fIlongValue\fR; double \fIdoubleValue\fR; VOID *\fIotherValuePtr\fR; struct { VOID *\fIptr1\fR; VOID *\fIptr2\fR; } \fItwoPtrValue\fR; } \fIinternalRep\fR; } Tcl_Obj; .CE The \fIbytes\fR and the \fIlength\fR members together hold .VS 8.1 an object's UTF-8 string representation, which is a \fIcounted string\fR not containing null bytes (UTF-8 null characters should be encoded as a two byte sequence: 192, 128.) \fIbytes\fR points to the first byte of the string representation. The \fIlength\fR member gives the number of bytes. The byte array must always have a null byte after the last data byte, at offset \fIlength\fR; this allows string representations to be treated as conventional null-terminated C strings. .VE 8.1 C programs use \fBTcl_GetStringFromObj\fR and \fBTcl_GetString\fR to get an object's string representation. If \fIbytes\fR is NULL, the string representation is invalid. .PP An object's type manages its internal representation. The member \fItypePtr\fR points to the Tcl_ObjType structure that describes the type. If \fItypePtr\fR is NULL, the internal representation is invalid. .PP The \fIinternalRep\fR union member holds an object's internal representation. This is either a (long) integer, a double-precision floating point number, a pointer to a value containing additional information needed by the object's type to represent the object, or two arbitrary pointers. .PP The \fIrefCount\fR member is used to tell when it is safe to free an object's storage. It holds the count of active references to the object. Maintaining the correct reference count is a key responsibility of extension writers. Reference counting is discussed below in the section \fBSTORAGE MANAGEMENT OF OBJECTS\fR. .PP Although extension writers can directly access the members of a Tcl_Obj structure, it is much better to use the appropriate procedures and macros. For example, extension writers should never read or update \fIrefCount\fR directly; they should use macros such as \fBTcl_IncrRefCount\fR and \fBTcl_IsShared\fR instead. .PP A key property of Tcl objects is that they hold two representations. An object typically starts out containing only a string representation: it is untyped and has a NULL \fItypePtr\fR. An object containing an empty string or a copy of a specified string is created using \fBTcl_NewObj\fR or \fBTcl_NewStringObj\fR respectively. An object's string value is gotten with \fBTcl_GetStringFromObj\fR or \fBTcl_GetString\fR and changed with \fBTcl_SetStringObj\fR. If the object is later passed to a procedure like \fBTcl_GetIntFromObj\fR that requires a specific internal representation, the procedure will create one and set the object's \fItypePtr\fR. The internal representation is computed from the string representation. An object's two representations are duals of each other: changes made to one are reflected in the other. For example, \fBTcl_ListObjReplace\fR will modify an object's internal representation and the next call to \fBTcl_GetStringFromObj\fR or \fBTcl_GetString\fR will reflect that change. .PP Representations are recomputed lazily for efficiency. A change to one representation made by a procedure such as \fBTcl_ListObjReplace\fR is not reflected immediately in the other representation. Instead, the other representation is marked invalid so that it is only regenerated if it is needed later. Most C programmers never have to be concerned with how this is done and simply use procedures such as \fBTcl_GetBooleanFromObj\fR or \fBTcl_ListObjIndex\fR. Programmers that implement their own object types must check for invalid representations and mark representations invalid when necessary. The procedure \fBTcl_InvalidateStringRep\fR is used to mark an object's string representation invalid and to free any storage associated with the old string representation. .PP Objects usually remain one type over their life, but occasionally an object must be converted from one type to another. For example, a C program might build up a string in an object with repeated calls to \fBTcl_AppendToObj\fR, and then call \fBTcl_ListObjIndex\fR to extract a list element from the object. The same object holding the same string value can have several different internal representations at different times. Extension writers can also force an object to be converted from one type to another using the \fBTcl_ConvertToType\fR procedure. Only programmers that create new object types need to be concerned about how this is done. A procedure defined as part of the object type's implementation creates a new internal representation for an object and changes its \fItypePtr\fR. See the man page for \fBTcl_RegisterObjType\fR to see how to create a new object type. .SH "EXAMPLE OF THE LIFETIME OF AN OBJECT" .PP As an example of the lifetime of an object, consider the following sequence of commands: .CS \fBset x 123\fR .CE This assigns to \fIx\fR an untyped object whose \fIbytes\fR member points to \fB123\fR and \fIlength\fR member contains 3. The object's \fItypePtr\fR member is NULL. .CS \fBputs "x is $x"\fR .CE \fIx\fR's string representation is valid (since \fIbytes\fR is non-NULL) and is fetched for the command. .CS \fBincr x\fR .CE The \fBincr\fR command first gets an integer from \fIx\fR's object by calling \fBTcl_GetIntFromObj\fR. This procedure checks whether the object is already an integer object. Since it is not, it converts the object by setting the object's \fIinternalRep.longValue\fR member to the integer \fB123\fR and setting the object's \fItypePtr\fR to point to the integer Tcl_ObjType structure. Both representations are now valid. \fBincr\fR increments the object's integer internal representation then invalidates its string representation (by calling \fBTcl_InvalidateStringRep\fR) since the string representation no longer corresponds to the internal representation. .CS \fBputs "x is now $x"\fR .CE The string representation of \fIx\fR's object is needed and is recomputed. The string representation is now \fB124\fR. and both representations are again valid. .SH "STORAGE MANAGEMENT OF OBJECTS" .PP Tcl objects are allocated on the heap and are shared as much as possible to reduce storage requirements. Reference counting is used to determine when an object is no longer needed and can safely be freed. An object just created by \fBTcl_NewObj\fR or \fBTcl_NewStringObj\fR has \fIrefCount\fR 0. The macro \fBTcl_IncrRefCount\fR increments the reference count when a new reference to the object is created. The macro \fBTcl_DecrRefCount\fR decrements the count when a reference is no longer needed and, if the object's reference count drops to zero, frees its storage. An object shared by different code or data structures has \fIrefCount\fR greater than 1. Incrementing an object's reference count ensures that it won't be freed too early or have its value change accidently. .PP As an example, the bytecode interpreter shares argument objects between calling and called Tcl procedures to avoid having to copy objects. It assigns the call's argument objects to the procedure's formal parameter variables. In doing so, it calls \fBTcl_IncrRefCount\fR to increment the reference count of each argument since there is now a new reference to it from the formal parameter. When the called procedure returns, the interpreter calls \fBTcl_DecrRefCount\fR to decrement each argument's reference count. When an object's reference count drops less than or equal to zero, \fBTcl_DecrRefCount\fR reclaims its storage. Most command procedures do not have to be concerned about reference counting since they use an object's value immediately and don't retain a pointer to the object after they return. However, if they do retain a pointer to an object in a data structure, they must be careful to increment its reference count since the retained pointer is a new reference. .PP Command procedures that directly modify objects such as those for \fBlappend\fR and \fBlinsert\fR must be careful to copy a shared object before changing it. They must first check whether the object is shared by calling \fBTcl_IsShared\fR. If the object is shared they must copy the object by using \fBTcl_DuplicateObj\fR; this returns a new duplicate of the original object that has \fIrefCount\fR 0. If the object is not shared, the command procedure "owns" the object and can safely modify it directly. For example, the following code appears in the command procedure that implements \fBlinsert\fR. This procedure modifies the list object passed to it in \fIobjv[1]\fR by inserting \fIobjc-3\fR new elements before \fIindex\fR. .CS listPtr = objv[1]; if (Tcl_IsShared(listPtr)) { listPtr = Tcl_DuplicateObj(listPtr); } result = Tcl_ListObjReplace(interp, listPtr, index, 0, (objc-3), &(objv[3])); .CE As another example, \fBincr\fR's command procedure must check whether the variable's object is shared before incrementing the integer in its internal representation. If it is shared, it needs to duplicate the object in order to avoid accidently changing values in other data structures. .SH "SEE ALSO" Tcl_ConvertToType, Tcl_GetIntFromObj, Tcl_ListObjAppendElement, Tcl_ListObjIndex, Tcl_ListObjReplace, Tcl_RegisterObjType .SH KEYWORDS internal representation, object, object creation, object type, reference counting, string representation, type conversion tcl8.4.20/doc/TCL_MEM_DEBUG.30000644003604700454610000000702512052456743013600 0ustar dgp771div'\" '\" Copyright (c) 1992-1999 Karl Lehenbauer and Mark Diekhans. '\" Copyright (c) 2000 by Scriptics Corporation. '\" All rights reserved. '\" .so man.macros .TH TCL_MEM_DEBUG 3 8.1 Tcl "Tcl Library Procedures" .BS .SH NAME TCL_MEM_DEBUG \- Compile-time flag to enable Tcl memory debugging. .BE .SH DESCRIPTION When Tcl is compiled with \fBTCL_MEM_DEBUG\fR defined, a powerful set of memory debugging aids are included in the compiled binary. This includes C and Tcl functions which can aid with debugging memory leaks, memory allocation overruns, and other memory related errors. .SH "ENABLING MEMORY DEBUGGING" .PP To enable memory debugging, Tcl should be recompiled from scratch with \fBTCL_MEM_DEBUG\fR defined. This will also compile in a non-stub version of \fBTcl_InitMemory\fR to add the \fBmemory\fR command to Tcl. .PP \fBTCL_MEM_DEBUG\fR must be either left defined for all modules or undefined for all modules that are going to be linked together. If they are not, link errors will occur, with either \fBTclDbCkfree\fR and \fBTcl_DbCkalloc\fR or \fBTcl_Alloc\fR and \fBTcl_Free\fR being undefined. .PP Once memory debugging support has been compiled into Tcl, the C functions \fBTcl_ValidateAllMemory\fR, and \fBTcl_DumpActiveMemory\fR, and the Tcl \fBmemory\fR command can be used to validate and examine memory usage. .SH "GUARD ZONES" .PP When memory debugging is enabled, whenever a call to \fBckalloc\fR is made, slightly more memory than requested is allocated so the memory debugging code can keep track of the allocated memory, and eight-byte ``guard zones'' are placed in front of and behind the space that will be returned to the caller. (The sizes of the guard zones are defined by the C #define \fBLOW_GUARD_SIZE\fR and #define \fBHIGH_GUARD_SIZE\fR in the file \fIgeneric/tclCkalloc.c\fR -- it can be extended if you suspect large overwrite problems, at some cost in performance.) A known pattern is written into the guard zones and, on a call to \fBckfree\fR, the guard zones of the space being freed are checked to see if either zone has been modified in any way. If one has been, the guard bytes and their new contents are identified, and a ``low guard failed'' or ``high guard failed'' message is issued. The ``guard failed'' message includes the address of the memory packet and the file name and line number of the code that called \fBckfree\fR. This allows you to detect the common sorts of one-off problems, where not enough space was allocated to contain the data written, for example. .SH "DEBUGGING DIFFICULT MEMORY CORRUPTION PROBLEMS" .PP Normally, Tcl compiled with memory debugging enabled will make it easy to isolate a corruption problem. Turning on memory validation with the memory command can help isolate difficult problems. If you suspect (or know) that corruption is occurring before the Tcl interpreter comes up far enough for you to issue commands, you can set \fBMEM_VALIDATE\fR define, recompile tclCkalloc.c and rebuild Tcl. This will enable memory validation from the first call to \fBckalloc\fR, again, at a large performance impact. .PP If you are desperate and validating memory on every call to \fBckalloc\fR and \fBckfree\fR isn't enough, you can explicitly call \fBTcl_ValidateAllMemory\fR directly at any point. It takes a \fIchar *\fR and an \fIint\fR which are normally the filename and line number of the caller, but they can actually be anything you want. Remember to remove the calls after you find the problem. .SH "SEE ALSO" ckalloc, memory, Tcl_ValidateAllMemory, Tcl_DumpActiveMemory .SH KEYWORDS memory, debug tcl8.4.20/doc/OpenFileChnl.30000644003604700454610000007443712052456743014073 0ustar dgp771div'\" '\" Copyright (c) 1996-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_OpenFileChannel 3 8.3 Tcl "Tcl Library Procedures" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME Tcl_OpenFileChannel, Tcl_OpenCommandChannel, Tcl_MakeFileChannel, Tcl_GetChannel, Tcl_GetChannelNames, Tcl_GetChannelNamesEx, Tcl_RegisterChannel, Tcl_UnregisterChannel, Tcl_DetachChannel, Tcl_IsStandardChannel, Tcl_Close, Tcl_ReadChars, Tcl_Read, Tcl_GetsObj, Tcl_Gets, Tcl_WriteObj, Tcl_WriteChars, Tcl_Write, Tcl_Flush, Tcl_Seek, Tcl_Tell, Tcl_GetChannelOption, Tcl_SetChannelOption, Tcl_Eof, Tcl_InputBlocked, Tcl_InputBuffered, Tcl_OutputBuffered, Tcl_Ungets, Tcl_ReadRaw, Tcl_WriteRaw \- buffered I/O facilities using channels .SH SYNOPSIS .nf \fB#include \fR .sp Tcl_Channel \fBTcl_OpenFileChannel\fR(\fIinterp, fileName, mode, permissions\fR) .sp Tcl_Channel \fBTcl_OpenCommandChannel\fR(\fIinterp, argc, argv, flags\fR) .sp Tcl_Channel \fBTcl_MakeFileChannel\fR(\fIhandle, readOrWrite\fR) .sp Tcl_Channel \fBTcl_GetChannel\fR(\fIinterp, channelName, modePtr\fR) .VS 8.3 .sp int \fBTcl_GetChannelNames\fR(\fIinterp\fR) .sp int \fBTcl_GetChannelNamesEx\fR(\fIinterp, pattern\fR) .VE .sp void \fBTcl_RegisterChannel\fR(\fIinterp, channel\fR) .sp int \fBTcl_UnregisterChannel\fR(\fIinterp, channel\fR) .sp int \fBTcl_DetachChannel\fR(\fIinterp, channel\fR) .sp int \fBTcl_IsStandardChannel\fR(\fIchannel\fR) .sp int \fBTcl_Close\fR(\fIinterp, channel\fR) .sp .VS 8.1 int \fBTcl_ReadChars\fR(\fIchannel, readObjPtr, charsToRead, appendFlag\fR) .sp int \fBTcl_Read\fR(\fIchannel, readBuf, bytesToRead\fR) .sp int \fBTcl_GetsObj\fR(\fIchannel, lineObjPtr\fR) .sp int \fBTcl_Gets\fR(\fIchannel, lineRead\fR) .sp int \fBTcl_Ungets\fR(\fIchannel, input, inputLen, addAtEnd\fR) .sp int \fBTcl_WriteObj\fR(\fIchannel, writeObjPtr\fR) .sp int \fBTcl_WriteChars\fR(\fIchannel, charBuf, bytesToWrite\fR) .sp int \fBTcl_Write\fR(\fIchannel, byteBuf, bytesToWrite\fR) .VE .VS 8.3.2 .sp int \fBTcl_ReadRaw\fR(\fIchannel, readBuf, bytesToRead\fR) .sp int \fBTcl_WriteRaw\fR(\fIchannel, byteBuf, bytesToWrite\fR) .VE .sp int \fBTcl_Eof\fR(\fIchannel\fR) .sp int \fBTcl_Flush\fR(\fIchannel\fR) .sp int \fBTcl_InputBlocked\fR(\fIchannel\fR) .sp int \fBTcl_InputBuffered\fR(\fIchannel\fR) .VS 8.4 .sp int \fBTcl_OutputBuffered\fR(\fIchannel\fR) .VE .sp .VS 8.4 Tcl_WideInt \fBTcl_Seek\fR(\fIchannel, offset, seekMode\fR) .sp Tcl_WideInt \fBTcl_Tell\fR(\fIchannel\fR) .VE 8.4 .sp int \fBTcl_GetChannelOption\fR(\fIinterp, channel, optionName, optionValue\fR) .sp int \fBTcl_SetChannelOption\fR(\fIinterp, channel, optionName, newValue\fR) .sp .SH ARGUMENTS .AS Tcl_ChannelType newClientProcPtr in .AP Tcl_Interp *interp in Used for error reporting and to look up a channel registered in it. .AP "CONST char" *fileName in The name of a local or network file. .AP "CONST char" *mode in Specifies how the file is to be accessed. May have any of the values allowed for the \fImode\fR argument to the Tcl \fBopen\fR command. .AP int permissions in POSIX-style permission flags such as 0644. If a new file is created, these permissions will be set on the created file. .AP int argc in The number of elements in \fIargv\fR. .AP "CONST char" **argv in Arguments for constructing a command pipeline. These values have the same meaning as the non-switch arguments to the Tcl \fBexec\fR command. .AP int flags in Specifies the disposition of the stdio handles in pipeline: OR-ed combination of \fBTCL_STDIN\fR, \fBTCL_STDOUT\fR, \fBTCL_STDERR\fR, and \fBTCL_ENFORCE_MODE\fR. If \fBTCL_STDIN\fR is set, stdin for the first child in the pipe is the pipe channel, otherwise it is the same as the standard input of the invoking process; likewise for \fBTCL_STDOUT\fR and \fBTCL_STDERR\fR. If \fBTCL_ENFORCE_MODE\fR is not set, then the pipe can redirect stdio handles to override the stdio handles for which \fBTCL_STDIN\fR, \fBTCL_STDOUT\fR and \fBTCL_STDERR\fR have been set. If it is set, then such redirections cause an error. .AP ClientData handle in Operating system specific handle for I/O to a file. For Unix this is a file descriptor, for Windows it is a HANDLE. .AP int readOrWrite in OR-ed combination of \fBTCL_READABLE\fR and \fBTCL_WRITABLE\fR to indicate what operations are valid on \fIhandle\fR. .AP "CONST char" *channelName in The name of the channel. .AP int *modePtr out Points at an integer variable that will receive an OR-ed combination of \fBTCL_READABLE\fR and \fBTCL_WRITABLE\fR denoting whether the channel is open for reading and writing. .VS 8.3 .AP "CONST char" *pattern in The pattern to match on, passed to Tcl_StringMatch, or NULL. .VE .AP Tcl_Channel channel in A Tcl channel for input or output. Must have been the return value from a procedure such as \fBTcl_OpenFileChannel\fR. .VS 8.1 br .AP Tcl_Obj *readObjPtr in/out A pointer to a Tcl Object in which to store the characters read from the channel. .AP int charsToRead in The number of characters to read from the channel. If the channel's encoding is \fBbinary\fR, this is equivalent to the number of bytes to read from the channel. .AP int appendFlag in If non-zero, data read from the channel will be appended to the object. Otherwise, the data will replace the existing contents of the object. .AP char *readBuf out A buffer in which to store the bytes read from the channel. .AP int bytesToRead in The number of bytes to read from the channel. The buffer \fIreadBuf\fR must be large enough to hold this many bytes. .AP Tcl_Obj *lineObjPtr in/out A pointer to a Tcl object in which to store the line read from the channel. The line read will be appended to the current value of the object. .AP Tcl_DString *lineRead in/out A pointer to a Tcl dynamic string in which to store the line read from the channel. Must have been initialized by the caller. The line read will be appended to any data already in the dynamic string. .VS 8.3 .AP "CONST char" *input in The input to add to a channel buffer. .AP int inputLen in Length of the input .AP int addAtEnd in Flag indicating whether the input should be added to the end or beginning of the channel buffer. .VE .AP Tcl_Obj *writeObjPtr in A pointer to a Tcl Object whose contents will be output to the channel. .AP "CONST char" *charBuf in A buffer containing the characters to output to the channel. .AP "CONST char" *byteBuf in A buffer containing the bytes to output to the channel. .AP int bytesToWrite in The number of bytes to consume from \fIcharBuf\fR or \fIbyteBuf\fR and output to the channel. .VE .AP Tcl_WideInt offset in How far to move the access point in the channel at which the next input or output operation will be applied, measured in bytes from the position given by \fIseekMode\fR. May be either positive or negative. .AP int seekMode in Relative to which point to seek; used with \fIoffset\fR to calculate the new access point for the channel. Legal values are \fBSEEK_SET\fR, \fBSEEK_CUR\fR, and \fBSEEK_END\fR. .AP "CONST char" *optionName in The name of an option applicable to this channel, such as \fB\-blocking\fR. May have any of the values accepted by the \fBfconfigure\fR command. .AP Tcl_DString *optionValue in Where to store the value of an option or a list of all options and their values. Must have been initialized by the caller. .AP "CONST char" *newValue in New value for the option given by \fIoptionName\fR. .BE .SH DESCRIPTION .PP The Tcl channel mechanism provides a device-independent and platform-independent mechanism for performing buffered input and output operations on a variety of file, socket, and device types. The channel mechanism is extensible to new channel types, by providing a low level channel driver for the new type; the channel driver interface is described in the manual entry for \fBTcl_CreateChannel\fR. The channel mechanism provides a buffering scheme modeled after Unix's standard I/O, and it also allows for nonblocking I/O on channels. .PP The procedures described in this manual entry comprise the C APIs of the generic layer of the channel architecture. For a description of the channel driver architecture and how to implement channel drivers for new types of channels, see the manual entry for \fBTcl_CreateChannel\fR. .SH TCL_OPENFILECHANNEL .PP \fBTcl_OpenFileChannel\fR opens a file specified by \fIfileName\fR and returns a channel handle that can be used to perform input and output on the file. This API is modeled after the \fBfopen\fR procedure of the Unix standard I/O library. The syntax and meaning of all arguments is similar to those given in the Tcl \fBopen\fR command when opening a file. If an error occurs while opening the channel, \fBTcl_OpenFileChannel\fR returns NULL and records a POSIX error code that can be retrieved with \fBTcl_GetErrno\fR. In addition, if \fIinterp\fR is non-NULL, \fBTcl_OpenFileChannel\fR leaves an error message in \fIinterp\fR's result after any error. As of Tcl 8.4, the object-based API \fBTcl_FSOpenFileChannel\fR should be used in preference to \fBTcl_OpenFileChannel\fR wherever possible. .PP .PP The newly created channel is not registered in the supplied interpreter; to register it, use \fBTcl_RegisterChannel\fR, described below. If one of the standard channels, \fBstdin, stdout\fR or \fBstderr\fR was previously closed, the act of creating the new channel also assigns it as a replacement for the standard channel. .SH TCL_OPENCOMMANDCHANNEL .PP \fBTcl_OpenCommandChannel\fR provides a C-level interface to the functions of the \fBexec\fR and \fBopen\fR commands. It creates a sequence of subprocesses specified by the \fIargv\fR and \fIargc\fR arguments and returns a channel that can be used to communicate with these subprocesses. The \fIflags\fR argument indicates what sort of communication will exist with the command pipeline. .PP If the \fBTCL_STDIN\fR flag is set then the standard input for the first subprocess will be tied to the channel: writing to the channel will provide input to the subprocess. If \fBTCL_STDIN\fR is not set, then standard input for the first subprocess will be the same as this application's standard input. If \fBTCL_STDOUT\fR is set then standard output from the last subprocess can be read from the channel; otherwise it goes to this application's standard output. If \fBTCL_STDERR\fR is set, standard error output for all subprocesses is returned to the channel and results in an error when the channel is closed; otherwise it goes to this application's standard error. If \fBTCL_ENFORCE_MODE\fR is not set, then \fIargc\fR and \fIargv\fR can redirect the stdio handles to override \fBTCL_STDIN\fR, \fBTCL_STDOUT\fR, and \fBTCL_STDERR\fR; if it is set, then it is an error for argc and argv to override stdio channels for which \fBTCL_STDIN\fR, \fBTCL_STDOUT\fR, and \fBTCL_STDERR\fR have been set. .PP If an error occurs while opening the channel, \fBTcl_OpenCommandChannel\fR returns NULL and records a POSIX error code that can be retrieved with \fBTcl_GetErrno\fR. In addition, \fBTcl_OpenCommandChannel\fR leaves an error message in the interpreter's result if \fIinterp\fR is not NULL. .PP The newly created channel is not registered in the supplied interpreter; to register it, use \fBTcl_RegisterChannel\fR, described below. If one of the standard channels, \fBstdin, stdout\fR or \fBstderr\fR was previously closed, the act of creating the new channel also assigns it as a replacement for the standard channel. .SH TCL_MAKEFILECHANNEL .PP \fBTcl_MakeFileChannel\fR makes a \fBTcl_Channel\fR from an existing, platform-specific, file handle. The newly created channel is not registered in the supplied interpreter; to register it, use \fBTcl_RegisterChannel\fR, described below. If one of the standard channels, \fBstdin, stdout\fR or \fBstderr\fR was previously closed, the act of creating the new channel also assigns it as a replacement for the standard channel. .SH TCL_GETCHANNEL .PP \fBTcl_GetChannel\fR returns a channel given the \fIchannelName\fR used to create it with \fBTcl_CreateChannel\fR and a pointer to a Tcl interpreter in \fIinterp\fR. If a channel by that name is not registered in that interpreter, the procedure returns NULL. If the \fImodePtr\fR argument is not NULL, it points at an integer variable that will receive an OR-ed combination of \fBTCL_READABLE\fR and \fBTCL_WRITABLE\fR describing whether the channel is open for reading and writing. .PP \fBTcl_GetChannelNames\fR and \fBTcl_GetChannelNamesEx\fR write the names of the registered channels to the interpreter's result as a list object. \fBTcl_GetChannelNamesEx\fR will filter these names according to the \fIpattern\fR. If \fIpattern\fR is NULL, then it will not do any filtering. The return value is \fBTCL_OK\fR if no errors occurred writing to the result, otherwise it is \fBTCL_ERROR\fR, and the error message is left in the interpreter's result. .SH TCL_REGISTERCHANNEL .PP \fBTcl_RegisterChannel\fR adds a channel to the set of channels accessible in \fIinterp\fR. After this call, Tcl programs executing in that interpreter can refer to the channel in input or output operations using the name given in the call to \fBTcl_CreateChannel\fR. After this call, the channel becomes the property of the interpreter, and the caller should not call \fBTcl_Close\fR for the channel; the channel will be closed automatically when it is unregistered from the interpreter. .PP Code executing outside of any Tcl interpreter can call \fBTcl_RegisterChannel\fR with \fIinterp\fR as NULL, to indicate that it wishes to hold a reference to this channel. Subsequently, the channel can be registered in a Tcl interpreter and it will only be closed when the matching number of calls to \fBTcl_UnregisterChannel\fR have been made. This allows code executing outside of any interpreter to safely hold a reference to a channel that is also registered in a Tcl interpreter. .PP This procedure interacts with the code managing the standard channels. If no standard channels were initialized before the first call to \fBTcl_RegisterChannel\fR they will get initialized by that call. See \fBTcl_StandardChannels\fR for a general treatise about standard channels and the behaviour of the Tcl library with regard to them. .SH TCL_UNREGISTERCHANNEL .PP \fBTcl_UnregisterChannel\fR removes a channel from the set of channels accessible in \fIinterp\fR. After this call, Tcl programs will no longer be able to use the channel's name to refer to the channel in that interpreter. If this operation removed the last registration of the channel in any interpreter, the channel is also closed and destroyed. .PP Code not associated with a Tcl interpreter can call \fBTcl_UnregisterChannel\fR with \fIinterp\fR as NULL, to indicate to Tcl that it no longer holds a reference to that channel. If this is the last reference to the channel, it will now be closed. \fBTcl_UnregisterChannel\fR is very similar to \fBTcl_DetachChannel\fR except that it will also close the channel if no further references to it exist. .SH TCL_DETACHCHANNEL .PP \fBTcl_DetachChannel\fR removes a channel from the set of channels accessible in \fIinterp\fR. After this call, Tcl programs will no longer be able to use the channel's name to refer to the channel in that interpreter. Beyond that, this command has no further effect. It cannot be used on the standard channels (stdout, stderr, stdin), and will return TCL_ERROR if passed one of those channels. .PP Code not associated with a Tcl interpreter can call \fBTcl_DetachChannel\fR with \fIinterp\fR as NULL, to indicate to Tcl that it no longer holds a reference to that channel. If this is the last reference to the channel, unlike \fBTcl_UnregisterChannel\fR, it will not be closed. .SH TCL_ISSTANDARDCHANNEL .PP \fBTcl_IsStandardChannel\fR tests whether a channel is one of the three standard channels, stdin, stdout or stderr. If so, it returns 1, otherwise 0. .PP No attempt is made to check whether the given channel or the standard channels are initialized or otherwise valid. .SH TCL_CLOSE .PP \fBTcl_Close\fR destroys the channel \fIchannel\fR, which must denote a currently open channel. The channel should not be registered in any interpreter when \fBTcl_Close\fR is called. Buffered output is flushed to the channel's output device prior to destroying the channel, and any buffered input is discarded. If this is a blocking channel, the call does not return until all buffered data is successfully sent to the channel's output device. If this is a nonblocking channel and there is buffered output that cannot be written without blocking, the call returns immediately; output is flushed in the background and the channel will be closed once all of the buffered data has been output. In this case errors during flushing are not reported. .PP If the channel was closed successfully, \fBTcl_Close\fR returns \fBTCL_OK\fR. If an error occurs, \fBTcl_Close\fR returns \fBTCL_ERROR\fR and records a POSIX error code that can be retrieved with \fBTcl_GetErrno\fR. If the channel is being closed synchronously and an error occurs during closing of the channel and \fIinterp\fR is not NULL, an error message is left in the interpreter's result. .PP Note: it is not safe to call \fBTcl_Close\fR on a channel that has been registered using \fBTcl_RegisterChannel\fR; see the documentation for \fBTcl_RegisterChannel\fR, above, for details. If the channel has ever been given as the \fBchan\fR argument in a call to \fBTcl_RegisterChannel\fR, you should instead use \fBTcl_UnregisterChannel\fR, which will internally call \fBTcl_Close\fR when all calls to \fBTcl_RegisterChannel\fR have been matched by corresponding calls to \fBTcl_UnregisterChannel\fR. .VS 8.1 br .SH "TCL_READCHARS AND TCL_READ" .PP \fBTcl_ReadChars\fR consumes bytes from \fIchannel\fR, converting the bytes to UTF-8 based on the channel's encoding and storing the produced data in \fIreadObjPtr\fR's string representation. The return value of \fBTcl_ReadChars\fR is the number of characters, up to \fIcharsToRead\fR, that were stored in \fIreadObjPtr\fR. If an error occurs while reading, the return value is \-1 and \fBTcl_ReadChars\fR records a POSIX error code that can be retrieved with \fBTcl_GetErrno\fR. .PP Setting \fIcharsToRead\fR to \fB-1\fR will cause the command to read all characters currently available (non-blocking) or everything until eof (blocking mode). .PP The return value may be smaller than the value to read, indicating that less data than requested was available. This is called a \fIshort read\fR. In blocking mode, this can only happen on an end-of-file. In nonblocking mode, a short read can also occur if there is not enough input currently available: \fBTcl_ReadChars\fR returns a short count rather than waiting for more data. .PP If the channel is in blocking mode, a return value of zero indicates an end-of-file condition. If the channel is in nonblocking mode, a return value of zero indicates either that no input is currently available or an end-of-file condition. Use \fBTcl_Eof\fR and \fBTcl_InputBlocked\fR to tell which of these conditions actually occurred. .PP \fBTcl_ReadChars\fR translates the various end-of-line representations into the canonical \fB\en\fR internal representation according to the current end-of-line recognition mode. End-of-line recognition and the various platform-specific modes are described in the manual entry for the Tcl \fBfconfigure\fR command. .PP As a performance optimization, when reading from a channel with the encoding \fBbinary\fR, the bytes are not converted to UTF-8 as they are read. Instead, they are stored in \fIreadObjPtr\fR's internal representation as a byte-array object. The string representation of this object will only be constructed if it is needed (e.g., because of a call to \fBTcl_GetStringFromObj\fR). In this way, byte-oriented data can be read from a channel, manipulated by calling \fBTcl_GetByteArrayFromObj\fR and related functions, and then written to a channel without the expense of ever converting to or from UTF-8. .PP \fBTcl_Read\fR is similar to \fBTcl_ReadChars\fR, except that it doesn't do encoding conversions, regardless of the channel's encoding. It is deprecated and exists for backwards compatibility with non-internationalized Tcl extensions. It consumes bytes from \fIchannel\fR and stores them in \fIreadBuf\fR, performing end-of-line translations on the way. The return value of \fBTcl_Read\fR is the number of bytes, up to \fIbytesToRead\fR, written in \fIreadBuf\fR. The buffer produced by \fBTcl_Read\fR is not null-terminated. Its contents are valid from the zeroth position up to and excluding the position indicated by the return value. .PP \fBTcl_ReadRaw\fR is the same as \fBTcl_Read\fR but does not compensate for stacking. While \fBTcl_Read\fR (and the other functions in the API) always get their data from the topmost channel in the stack the supplied channel is part of, \fBTcl_ReadRaw\fR does not. Thus this function is \fBonly\fR usable for transformational channel drivers, i.e. drivers used in the middle of a stack of channels, to move data from the channel below into the transformation. .SH "TCL_GETSOBJ AND TCL_GETS" .PP \fBTcl_GetsObj\fR consumes bytes from \fIchannel\fR, converting the bytes to UTF-8 based on the channel's encoding, until a full line of input has been seen. If the channel's encoding is \fBbinary\fR, each byte read from the channel is treated as an individual Unicode character. All of the characters of the line except for the terminating end-of-line character(s) are appended to \fIlineObjPtr\fR's string representation. The end-of-line character(s) are read and discarded. .PP If a line was successfully read, the return value is greater than or equal to zero and indicates the number of bytes stored in \fIlineObjPtr\fR. If an error occurs, \fBTcl_GetsObj\fR returns \-1 and records a POSIX error code that can be retrieved with \fBTcl_GetErrno\fR. \fBTcl_GetsObj\fR also returns \-1 if the end of the file is reached; the \fBTcl_Eof\fR procedure can be used to distinguish an error from an end-of-file condition. .PP If the channel is in nonblocking mode, the return value can also be \-1 if no data was available or the data that was available did not contain an end-of-line character. When \-1 is returned, the \fBTcl_InputBlocked\fR procedure may be invoked to determine if the channel is blocked because of input unavailability. .PP \fBTcl_Gets\fR is the same as \fBTcl_GetsObj\fR except the resulting characters are appended to the dynamic string given by \fIlineRead\fR rather than a Tcl object. .SH "TCL_UNGETS" .PP \fBTcl_Ungets\fR is used to add data to the input queue of a channel, at either the head or tail of the queue. The pointer \fIinput\fR points to the data that is to be added. The length of the input to add is given by \fIinputLen\fR. A non-zero value of \fIaddAtEnd\fR indicates that the data is to be added at the end of queue; otherwise it will be added at the head of the queue. If \fIchannel\fR has a "sticky" EOF set, no data will be added to the input queue. \fBTcl_Ungets\fR returns \fIinputLen\fR or -1 if an error occurs. .SH "TCL_WRITECHARS, TCL_WRITEOBJ, AND TCL_WRITE" .PP \fBTcl_WriteChars\fR accepts \fIbytesToWrite\fR bytes of character data at \fIcharBuf\fR. The UTF-8 characters in the buffer are converted to the channel's encoding and queued for output to \fIchannel\fR. If \fIbytesToWrite\fR is negative, \fBTcl_WriteChars\fR expects \fIcharBuf\fR to be null-terminated and it outputs everything up to the null. .PP Data queued for output may not appear on the output device immediately, due to internal buffering. If the data should appear immediately, call \fBTcl_Flush\fR after the call to \fBTcl_WriteChars\fR, or set the \fB\-buffering\fR option on the channel to \fBnone\fR. If you wish the data to appear as soon as a complete line is accepted for output, set the \fB\-buffering\fR option on the channel to \fBline\fR mode. .PP The return value of \fBTcl_WriteChars\fR is a count of how many bytes were accepted for output to the channel. This is either greater than zero to indicate success or \-1 to indicate that an error occurred. If an error occurs, \fBTcl_WriteChars\fR records a POSIX error code that may be retrieved with \fBTcl_GetErrno\fR. .PP Newline characters in the output data are translated to platform-specific end-of-line sequences according to the \fB\-translation\fR option for the channel. This is done even if the channel has no encoding. .PP \fBTcl_WriteObj\fR is similar to \fBTcl_WriteChars\fR except it accepts a Tcl object whose contents will be output to the channel. The UTF-8 characters in \fIwriteObjPtr\fR's string representation are converted to the channel's encoding and queued for output to \fIchannel\fR. As a performance optimization, when writing to a channel with the encoding \fBbinary\fR, UTF-8 characters are not converted as they are written. Instead, the bytes in \fIwriteObjPtr\fR's internal representation as a byte-array object are written to the channel. The byte-array representation of the object will be constructed if it is needed. In this way, byte-oriented data can be read from a channel, manipulated by calling \fBTcl_GetByteArrayFromObj\fR and related functions, and then written to a channel without the expense of ever converting to or from UTF-8. .PP \fBTcl_Write\fR is similar to \fBTcl_WriteChars\fR except that it doesn't do encoding conversions, regardless of the channel's encoding. It is deprecated and exists for backwards compatibility with non-internationalized Tcl extensions. It accepts \fIbytesToWrite\fR bytes of data at \fIbyteBuf\fR and queues them for output to \fIchannel\fR. If \fIbytesToWrite\fR is negative, \fBTcl_Write\fR expects \fIbyteBuf\fR to be null-terminated and it outputs everything up to the null. .PP \fBTcl_WriteRaw\fR is the same as \fBTcl_Write\fR but does not compensate for stacking. While \fBTcl_Write\fR (and the other functions in the API) always feed their input to the topmost channel in the stack the supplied channel is part of, \fBTcl_WriteRaw\fR does not. Thus this function is \fBonly\fR usable for transformational channel drivers, i.e. drivers used in the middle of a stack of channels, to move data from the transformation into the channel below it. .VE .SH TCL_FLUSH .PP \fBTcl_Flush\fR causes all of the buffered output data for \fIchannel\fR to be written to its underlying file or device as soon as possible. If the channel is in blocking mode, the call does not return until all the buffered data has been sent to the channel or some error occurred. The call returns immediately if the channel is nonblocking; it starts a background flush that will write the buffered data to the channel eventually, as fast as the channel is able to absorb it. .PP The return value is normally \fBTCL_OK\fR. If an error occurs, \fBTcl_Flush\fR returns \fBTCL_ERROR\fR and records a POSIX error code that can be retrieved with \fBTcl_GetErrno\fR. .SH TCL_SEEK .PP \fBTcl_Seek\fR moves the access point in \fIchannel\fR where subsequent data will be read or written. Buffered output is flushed to the channel and buffered input is discarded, prior to the seek operation. .PP \fBTcl_Seek\fR normally returns the new access point. If an error occurs, \fBTcl_Seek\fR returns \-1 and records a POSIX error code that can be retrieved with \fBTcl_GetErrno\fR. After an error, the access point may or may not have been moved. .SH TCL_TELL .PP \fBTcl_Tell\fR returns the current access point for a channel. The returned value is \-1 if the channel does not support seeking. .SH TCL_GETCHANNELOPTION .PP \fBTcl_GetChannelOption\fR retrieves, in \fIoptionValue\fR, the value of one of the options currently in effect for a channel, or a list of all options and their values. The \fIchannel\fR argument identifies the channel for which to query an option or retrieve all options and their values. If \fIoptionName\fR is not NULL, it is the name of the option to query; the option's value is copied to the Tcl dynamic string denoted by \fIoptionValue\fR. If \fIoptionName\fR is NULL, the function stores an alternating list of option names and their values in \fIoptionValue\fR, using a series of calls to \fBTcl_DStringAppendElement\fR. The various preexisting options and their possible values are described in the manual entry for the Tcl \fBfconfigure\fR command. Other options can be added by each channel type. These channel type specific options are described in the manual entry for the Tcl command that creates a channel of that type; for example, the additional options for TCP based channels are described in the manual entry for the Tcl \fBsocket\fR command. The procedure normally returns \fBTCL_OK\fR. If an error occurs, it returns \fBTCL_ERROR\fR and calls \fBTcl_SetErrno\fR to store an appropriate POSIX error code. .SH TCL_SETCHANNELOPTION .PP \fBTcl_SetChannelOption\fR sets a new value \fInewValue\fR for an option \fIoptionName\fR on \fIchannel\fR. The procedure normally returns \fBTCL_OK\fR. If an error occurs, it returns \fBTCL_ERROR\fR; in addition, if \fIinterp\fR is non-NULL, \fBTcl_SetChannelOption\fR leaves an error message in the interpreter's result. .SH TCL_EOF .PP \fBTcl_Eof\fR returns a nonzero value if \fIchannel\fR encountered an end of file during the last input operation. .SH TCL_INPUTBLOCKED .PP \fBTcl_InputBlocked\fR returns a nonzero value if \fIchannel\fR is in nonblocking mode and the last input operation returned less data than requested because there was insufficient data available. The call always returns zero if the channel is in blocking mode. .SH TCL_INPUTBUFFERED .PP \fBTcl_InputBuffered\fR returns the number of bytes of input currently buffered in the internal buffers for a channel. If the channel is not open for reading, this function always returns zero. .SH TCL_OUTPUTBUFFERED .VS 8.4 \fBTcl_OutputBuffered\fR returns the number of bytes of output currently buffered in the internal buffers for a channel. If the channel is not open for writing, this function always returns zero. .VE .SH "PLATFORM ISSUES" .PP The handles returned from \fBTcl_GetChannelHandle\fR depend on the platform and the channel type. On Unix platforms, the handle is always a Unix file descriptor as returned from the \fBopen\fR system call. On Windows platforms, the handle is a file \fBHANDLE\fR when the channel was created with \fBTcl_OpenFileChannel\fR, \fBTcl_OpenCommandChannel\fR, or \fBTcl_MakeFileChannel\fR. Other channel types may return a different type of handle on Windows platforms. .SH "SEE ALSO" DString(3), fconfigure(n), filename(n), fopen(3), Tcl_CreateChannel(3) .SH KEYWORDS access point, blocking, buffered I/O, channel, channel driver, end of file, flush, input, nonblocking, output, read, seek, write tcl8.4.20/doc/ToUpper.30000644003604700454610000000565511737050674013161 0ustar dgp771div'\" '\" Copyright (c) 1997 by Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_UtfToUpper 3 "8.1" Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_UniCharToUpper, Tcl_UniCharToLower, Tcl_UniCharToTitle, Tcl_UtfToUpper, Tcl_UtfToLower, Tcl_UtfToTitle \- routines for manipulating the case of Unicode characters and UTF-8 strings. .SH SYNOPSIS .nf \fB#include \fR .sp Tcl_UniChar \fBTcl_UniCharToUpper\fR(\fIch\fR) .sp Tcl_UniChar \fBTcl_UniCharToLower\fR(\fIch\fR) .sp Tcl_UniChar \fBTcl_UniCharToTitle\fR(\fIch\fR) .sp int \fBTcl_UtfToUpper\fR(\fIstr\fR) .sp int \fBTcl_UtfToLower\fR(\fIstr\fR) .sp int \fBTcl_UtfToTitle\fR(\fIstr\fR) .SH ARGUMENTS .AS char *str in/out .AP int ch in The Tcl_UniChar to be converted. .AP char *str in/out Pointer to UTF-8 string to be converted in place. .BE .SH DESCRIPTION .PP The first three routines convert the case of individual Unicode characters: .PP If \fIch\fR represents a lower-case character, \fBTcl_UniCharToUpper\fR returns the corresponding upper-case character. If no upper-case character is defined, it returns the character unchanged. .PP If \fIch\fR represents an upper-case character, \fBTcl_UniCharToLower\fR returns the corresponding lower-case character. If no lower-case character is defined, it returns the character unchanged. .PP If \fIch\fR represents a lower-case character, \fBTcl_UniCharToTitle\fR returns the corresponding title-case character. If no title-case character is defined, it returns the corresponding upper-case character. If no upper-case character is defined, it returns the character unchanged. Title-case is defined for a small number of characters that have a different appearance when they are at the beginning of a capitalized word. .PP The next three routines convert the case of UTF-8 strings in place in memory: .PP \fBTcl_UtfToUpper\fR changes every UTF-8 character in \fIstr\fR to upper-case. Because changing the case of a character may change its size, the byte offset of each character in the resulting string may differ from its original location. \fBTcl_UtfToUpper\fR writes a null byte at the end of the converted string. \fBTcl_UtfToUpper\fR returns the new length of the string in bytes. This new length is guaranteed to be no longer than the original string length. .PP \fBTcl_UtfToLower\fR is the same as \fBTcl_UtfToUpper\fR except it turns each character in the string into its lower-case equivalent. .PP \fBTcl_UtfToTitle\fR is the same as \fBTcl_UtfToUpper\fR except it turns the first character in the string into its title-case equivalent and all following characters into their lower-case equivalents. .SH BUGS .PP At this time, the case conversions are only defined for the ISO8859-1 characters. Unicode characters above 0x00ff are not modified by these routines. .SH KEYWORDS utf, unicode, toupper, tolower, totitle, case tcl8.4.20/doc/for.n0000644003604700454610000000545611737050674012443 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH for n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME for \- ``For'' loop .SH SYNOPSIS \fBfor \fIstart test next body\fR .BE .SH DESCRIPTION .PP \fBFor\fR is a looping command, similar in structure to the C \fBfor\fR statement. The \fIstart\fR, \fInext\fR, and \fIbody\fR arguments must be Tcl command strings, and \fItest\fR is an expression string. The \fBfor\fR command first invokes the Tcl interpreter to execute \fIstart\fR. Then it repeatedly evaluates \fItest\fR as an expression; if the result is non-zero it invokes the Tcl interpreter on \fIbody\fR, then invokes the Tcl interpreter on \fInext\fR, then repeats the loop. The command terminates when \fItest\fR evaluates to 0. If a \fBcontinue\fR command is invoked within \fIbody\fR then any remaining commands in the current execution of \fIbody\fR are skipped; processing continues by invoking the Tcl interpreter on \fInext\fR, then evaluating \fItest\fR, and so on. If a \fBbreak\fR command is invoked within \fIbody\fR or \fInext\fR, then the \fBfor\fR command will return immediately. The operation of \fBbreak\fR and \fBcontinue\fR are similar to the corresponding statements in C. \fBFor\fR returns an empty string. .PP Note: \fItest\fR should almost always be enclosed in braces. If not, variable substitutions will be made before the \fBfor\fR command starts executing, which means that variable changes made by the loop body will not be considered in the expression. This is likely to result in an infinite loop. If \fItest\fR is enclosed in braces, variable substitutions are delayed until the expression is evaluated (before each loop iteration), so changes in the variables will be visible. See below for an example: .SH EXAMPLES Print a line for each of the integers from 0 to 10: .CS for {set x 0} {$x<10} {incr x} { puts "x is $x" } .CE .PP Either loop infinitely or not at all because the expression being evaluated is actually the constant, or even generate an error! The actual behaviour will depend on whether the variable \fIx\fR exists before the \fBfor\fR command is run and whether its value is a value that is less than or greater than/equal to ten, and this is because the expression will be substituted before the \fBfor\fR command is executed. .CS for {set x 0} $x<10 {incr x} { puts "x is $x" } .CE .PP Print out the powers of two from 1 to 1024: .CS for {set x 1} {$x<=1024} {set x [expr {$x * 2}]} { puts "x is $x" } .CE .SH "SEE ALSO" break, continue, foreach, while .SH KEYWORDS for, iteration, looping tcl8.4.20/doc/Exit.30000644003604700454610000001232411737050674012463 0ustar dgp771div'\" '\" Copyright (c) 1995-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_Exit 3 8.1 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_Exit, Tcl_Finalize, Tcl_CreateExitHandler, Tcl_DeleteExitHandler, Tcl_ExitThread, Tcl_FinalizeThread, Tcl_CreateThreadExitHandler, Tcl_DeleteThreadExitHandler \- end the application or thread (and invoke exit handlers) .SH SYNOPSIS .nf \fB#include \fR .sp \fBTcl_Exit\fR(\fIstatus\fR) .sp \fBTcl_Finalize\fR() .sp \fBTcl_CreateExitHandler\fR(\fIproc, clientData\fR) .sp \fBTcl_DeleteExitHandler\fR(\fIproc, clientData\fR) .sp \fBTcl_ExitThread\fR(\fIstatus\fR) .sp \fBTcl_FinalizeThread\fR() .sp \fBTcl_CreateThreadExitHandler\fR(\fIproc, clientData\fR) .sp \fBTcl_DeleteThreadExitHandler\fR(\fIproc, clientData\fR) .SH ARGUMENTS .AS Tcl_ExitProc clientData .AP int status in Provides information about why the application or thread exited. Exact meaning may be platform-specific. 0 usually means a normal exit, any nonzero value usually means that an error occurred. .AP Tcl_ExitProc *proc in Procedure to invoke before exiting application. .AP ClientData clientData in Arbitrary one-word value to pass to \fIproc\fR. .BE .SH DESCRIPTION .PP The procedures described here provide a graceful mechanism to end the execution of a \fBTcl\fR application. Exit handlers are invoked to cleanup the application's state before ending the execution of \fBTcl\fR code. .PP Invoke \fBTcl_Exit\fR to end a \fBTcl\fR application and to exit from this process. This procedure is invoked by the \fBexit\fR command, and can be invoked anyplace else to terminate the application. No-one should ever invoke the \fBexit\fR system procedure directly; always invoke \fBTcl_Exit\fR instead, so that it can invoke exit handlers. Note that if other code invokes \fBexit\fR system procedure directly, or otherwise causes the application to terminate without calling \fBTcl_Exit\fR, the exit handlers will not be run. \fBTcl_Exit\fR internally invokes the \fBexit\fR system call, thus it never returns control to its caller. .PP \fBTcl_Finalize\fR is similar to \fBTcl_Exit\fR except that it does not exit from the current process. It is useful for cleaning up when a process is finished using \fBTcl\fR but wishes to continue executing, and when \fBTcl\fR is used in a dynamically loaded extension that is about to be unloaded. On some systems \fBTcl\fR is automatically notified when it is being unloaded, and it calls \fBTcl_Finalize\fR internally; on these systems it not necessary for the caller to explicitly call \fBTcl_Finalize\fR. However, to ensure portability, your code should always invoke \fBTcl_Finalize\fR when \fBTcl\fR is being unloaded, to ensure that the code will work on all platforms. \fBTcl_Finalize\fR can be safely called more than once. .PP .VS \fBTcl_ExitThread\fR is used to terminate the current thread and invoke per-thread exit handlers. This finalization is done by \fBTcl_FinalizeThread\fR, which you can call if you just want to clean up per-thread state and invoke the thread exit handlers. \fBTcl_Finalize\fR calls \fBTcl_FinalizeThread\fR for the current thread automatically. .VE .PP \fBTcl_CreateExitHandler\fR arranges for \fIproc\fR to be invoked by \fBTcl_Finalize\fR and \fBTcl_Exit\fR. \fBTcl_CreateThreadExitHandler\fR arranges for \fIproc\fR to be invoked by \fBTcl_FinalizeThread\fR and \fBTcl_ExitThread\fR. This provides a hook for cleanup operations such as flushing buffers and freeing global memory. \fIProc\fR should match the type \fBTcl_ExitProc\fR: .CS typedef void Tcl_ExitProc(ClientData \fIclientData\fR); .CE The \fIclientData\fR parameter to \fIproc\fR is a copy of the \fIclientData\fR argument given to \fBTcl_CreateExitHandler\fR or \fBTcl_CreateThreadExitHandler\fR when the callback was created. Typically, \fIclientData\fR points to a data structure containing application-specific information about what to do in \fIproc\fR. .PP \fBTcl_DeleteExitHandler\fR and \fBTcl_DeleteThreadExitHandler\fR may be called to delete a previously-created exit handler. It removes the handler indicated by \fIproc\fR and \fIclientData\fR so that no call to \fIproc\fR will be made. If no such handler exists then \fBTcl_DeleteExitHandler\fR or \fBTcl_DeleteThreadExitHandler\fR does nothing. .PP .VS .PP \fBTcl_Finalize\fR and \fBTcl_Exit\fR execute all registered exit handlers, in reverse order from the order in which they were registered. This matches the natural order in which extensions are loaded and unloaded; if extension \fBA\fR loads extension \fBB\fR, it usually unloads \fBB\fR before it itself is unloaded. If extension \fBA\fR registers its exit handlers before loading extension \fBB\fR, this ensures that any exit handlers for \fBB\fR will be executed before the exit handlers for \fBA\fR. .VE .VS .PP \fBTcl_Finalize\fR and \fBTcl_Exit\fR call \fBTcl_FinalizeThread\fR and the thread exit handlers \fIafter\fR the process-wide exit handlers. This is because thread finalization shuts down the I/O channel system, so any attempt at I/O by the global exit handlers will vanish into the bitbucket. .VE .SH KEYWORDS callback, cleanup, dynamic loading, end application, exit, unloading, thread tcl8.4.20/doc/join.n0000644003604700454610000000221411737050674012601 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH join n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME join \- Create a string by joining together list elements .SH SYNOPSIS \fBjoin \fIlist \fR?\fIjoinString\fR? .BE .SH DESCRIPTION .PP The \fIlist\fR argument must be a valid Tcl list. This command returns the string formed by joining all of the elements of \fIlist\fR together with \fIjoinString\fR separating each adjacent pair of elements. The \fIjoinString\fR argument defaults to a space character. .SH EXAMPLES Making a comma-separated list: .CS set data {1 2 3 4 5} \fBjoin\fR $data ", " \fB=> 1, 2, 3, 4, 5\fR .CE .PP Using \fBjoin\fR to flatten a list by a single level: .CS set data {1 {2 3} 4 {5 {6 7} 8}} \fBjoin\fR $data \fB=> 1 2 3 4 5 {6 7} 8\fR .CE .SH "SEE ALSO" list(n), lappend(n), split(n) .SH KEYWORDS element, join, list, separator tcl8.4.20/doc/Concat.30000644003604700454610000000327111737050674012762 0ustar dgp771div'\" '\" Copyright (c) 1989-1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_Concat 3 7.5 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_Concat \- concatenate a collection of strings .SH SYNOPSIS .nf \fB#include \fR .sp CONST char * \fBTcl_Concat\fR(\fIargc, argv\fR) .SH ARGUMENTS .AP int argc in Number of strings. .AP "CONST char * CONST" argv[] in Array of strings to concatenate. Must have \fIargc\fR entries. .BE .SH DESCRIPTION .PP \fBTcl_Concat\fR is a utility procedure used by several of the Tcl commands. Given a collection of strings, it concatenates them together into a single string, with the original strings separated by spaces. This procedure behaves differently than \fBTcl_Merge\fR, in that the arguments are simply concatenated: no effort is made to ensure proper list structure. However, in most common usage the arguments will all be proper lists themselves; if this is true, then the result will also have proper list structure. .PP \fBTcl_Concat\fR eliminates leading and trailing white space as it copies strings from \fBargv\fR to the result. If an element of \fBargv\fR consists of nothing but white space, then that string is ignored entirely. This white-space removal was added to make the output of the \fBconcat\fR command cleaner-looking. .PP .VS The result string is dynamically allocated using \fBTcl_Alloc\fR; the caller must eventually release the space by calling \fBTcl_Free\fR. .VE .VS .SH "SEE ALSO" Tcl_ConcatObj .SH KEYWORDS concatenate, strings tcl8.4.20/doc/incr.n0000644003604700454610000000262511737050674012603 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH incr n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME incr \- Increment the value of a variable .SH SYNOPSIS \fBincr \fIvarName \fR?\fIincrement\fR? .BE .SH DESCRIPTION .PP Increments the value stored in the variable whose name is \fIvarName\fR. The value of the variable must be an integer. If \fIincrement\fR is supplied then its value (which must be an integer) is added to the value of variable \fIvarName\fR; otherwise 1 is added to \fIvarName\fR. The new value is stored as a decimal string in variable \fIvarName\fR and also returned as result. .SH EXAMPLES Add one to the contents of the variable \fIx\fR: .CS \fBincr\fR x .CE .PP Add 42 to the contents of the variable \fIx\fR: .CS \fBincr\fR x 42 .CE .PP Add the contents of the variable \fIy\fR to the contents of the variable \fIx\fR: .CS \fBincr\fR x $y .CE .PP Add nothing at all to the variable \fIx\fR (often useful for checking whether an argument to a procedure is actually numeric and generating an error if it is not): .CS \fBincr\fR x 0 .CE .SH "SEE ALSO" expr(n) .SH KEYWORDS add, increment, variable, value tcl8.4.20/doc/scan.n0000644003604700454610000002445611737050674012602 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" Copyright (c) 2000 Scriptics Corporation. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH scan n 8.4 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME scan \- Parse string using conversion specifiers in the style of sscanf .SH SYNOPSIS \fBscan \fIstring format \fR?\fIvarName varName ...\fR? .BE .SH INTRODUCTION .PP This command parses fields from an input string in the same fashion as the ANSI C \fBsscanf\fR procedure and returns a count of the number of conversions performed, or -1 if the end of the input string is reached before any conversions have been performed. \fIString\fR gives the input to be parsed and \fIformat\fR indicates how to parse it, using \fB%\fR conversion specifiers as in \fBsscanf\fR. Each \fIvarName\fR gives the name of a variable; when a field is scanned from \fIstring\fR the result is converted back into a string and assigned to the corresponding variable. If no \fIvarName\fR variables are specified, then \fBscan\fR works in an inline manner, returning the data that would otherwise be stored in the variables as a list. In the inline case, an empty string is returned when the end of the input string is reached before any conversions have been performed. .SH "DETAILS ON SCANNING" .PP \fBScan\fR operates by scanning \fIstring\fR and \fIformat\fR together. If the next character in \fIformat\fR is a blank or tab then it matches any number of white space characters in \fIstring\fR (including zero). Otherwise, if it isn't a \fB%\fR character then it must match the next character of \fIstring\fR. When a \fB%\fR is encountered in \fIformat\fR, it indicates the start of a conversion specifier. .VS 8.4 A conversion specifier contains up to four fields after the \fB%\fR: a \fB*\fR, which indicates that the converted value is to be discarded instead of assigned to a variable; a XPG3 position specifier; a number indicating a maximum field width; a field size modifier; and a conversion character. .VE 8.4 All of these fields are optional except for the conversion character. The fields that are present must appear in the order given above. .PP When \fBscan\fR finds a conversion specifier in \fIformat\fR, it first skips any white-space characters in \fIstring\fR (unless the specifier is \fB[\fR or \fBc\fR). Then it converts the next input characters according to the conversion specifier and stores the result in the variable given by the next argument to \fBscan\fR. .PP If the \fB%\fR is followed by a decimal number and a \fB$\fR, as in ``\fB%2$d\fR'', then the variable to use is not taken from the next sequential argument. Instead, it is taken from the argument indicated by the number, where 1 corresponds to the first \fIvarName\fR. If there are any positional specifiers in \fIformat\fR then all of the specifiers must be positional. Every \fIvarName\fR on the argument list must correspond to exactly one conversion specifier or an error is generated, or in the inline case, any position can be specified at most once and the empty positions will be filled in with empty strings. .PP The following conversion characters are supported: .TP 10 \fBd\fR The input field must be a decimal integer. It is read in and the value is stored in the variable as a decimal string. .VS 8.4 If the \fBl\fR or \fBL\fR field size modifier is given, the scanned value will have an internal representation that is at least 64-bits in size. .VE 8.4 .TP 10 \fBo\fR The input field must be an octal integer. It is read in and the value is stored in the variable as a decimal string. .VS 8.4 If the \fBl\fR or \fBL\fR field size modifier is given, the scanned value will have an internal representation that is at least 64-bits in size. If the value exceeds MAX_INT (017777777777 on platforms using 32-bit integers when the \fBl\fR and \fBL\fR modifiers are not given), it will be truncated to a signed integer. Hence, 037777777777 will appear as -1 on a 32-bit machine by default. .VE 8.4 .TP 10 \fBx\fR The input field must be a hexadecimal integer. It is read in and the value is stored in the variable as a decimal string. .VS 8.4 If the \fBl\fR or \fBL\fR field size modifier is given, the scanned value will have an internal representation that is at least 64-bits in size. If the value exceeds MAX_INT (0x7FFFFFFF on platforms using 32-bit integers when the \fBl\fR and \fBL\fR modifiers are not given), it will be truncated to a signed integer. Hence, 0xFFFFFFFF will appear as -1 on a 32-bit machine. .VE 8.4 .TP 10 \fBu\fR The input field must be a decimal integer. The value is stored in the variable as an unsigned decimal integer string. .VS 8.4 If the \fBl\fR or \fBL\fR field size modifier is given, the scanned value will have an internal representation that is at least 64-bits in size. .VE 8.4 .TP 10 \fBi\fR The input field must be an integer. The base (i.e. decimal, octal, or hexadecimal) is determined in the same fashion as described in \fBexpr\fR. The value is stored in the variable as a decimal string. .VS 8.4 If the \fBl\fR or \fBL\fR field size modifier is given, the scanned value will have an internal representation that is at least 64-bits in size. .VE 8.4 .TP 10 \fBc\fR A single character is read in and its binary value is stored in the variable as a decimal string. Initial white space is not skipped in this case, so the input field may be a white-space character. This conversion is different from the ANSI standard in that the input field always consists of a single character and no field width may be specified. .TP 10 \fBs\fR The input field consists of all the characters up to the next white-space character; the characters are copied to the variable. .TP 10 \fBe\fR or \fBf\fR or \fBg\fR The input field must be a floating-point number consisting of an optional sign, a string of decimal digits possibly containing a decimal point, and an optional exponent consisting of an \fBe\fR or \fBE\fR followed by an optional sign and a string of decimal digits. It is read in and stored in the variable as a floating-point string. .TP 10 \fB[\fIchars\fB]\fR The input field consists of any number of characters in \fIchars\fR. The matching string is stored in the variable. If the first character between the brackets is a \fB]\fR then it is treated as part of \fIchars\fR rather than the closing bracket for the set. If \fIchars\fR contains a sequence of the form \fIa\fB\-\fIb\fR then any character between \fIa\fR and \fIb\fR (inclusive) will match. If the first or last character between the brackets is a \fB\-\fR, then it is treated as part of \fIchars\fR rather than indicating a range. .TP 10 \fB[^\fIchars\fB]\fR The input field consists of any number of characters not in \fIchars\fR. The matching string is stored in the variable. If the character immediately following the \fB^\fR is a \fB]\fR then it is treated as part of the set rather than the closing bracket for the set. If \fIchars\fR contains a sequence of the form \fIa\fB\-\fIb\fR then any character between \fIa\fR and \fIb\fR (inclusive) will be excluded from the set. If the first or last character between the brackets is a \fB\-\fR, then it is treated as part of \fIchars\fR rather than indicating a range. .TP 10 \fBn\fR No input is consumed from the input string. Instead, the total number of characters scanned from the input string so far is stored in the variable. .LP The number of characters read from the input for a conversion is the largest number that makes sense for that particular conversion (e.g. as many decimal digits as possible for \fB%d\fR, as many octal digits as possible for \fB%o\fR, and so on). The input field for a given conversion terminates either when a white-space character is encountered or when the maximum field width has been reached, whichever comes first. If a \fB*\fR is present in the conversion specifier then no variable is assigned and the next scan argument is not consumed. .SH "DIFFERENCES FROM ANSI SSCANF" .PP The behavior of the \fBscan\fR command is the same as the behavior of the ANSI C \fBsscanf\fR procedure except for the following differences: .IP [1] \fB%p\fR conversion specifier is not currently supported. .IP [2] For \fB%c\fR conversions a single character value is converted to a decimal string, which is then assigned to the corresponding \fIvarName\fR; no field width may be specified for this conversion. .IP [3] .VS 8.4 The \fBh\fR modifier is always ignored and the \fBl\fR and \fBL\fR modifiers are ignored when converting real values (i.e. type \fBdouble\fR is used for the internal representation). .VE 8.4 .IP [4] If the end of the input string is reached before any conversions have been performed and no variables are given, an empty string is returned. .SH EXAMPLES Parse a simple color specification of the form \fI#RRGGBB\fR using hexadecimal conversions with field sizes: .CS set string "#08D03F" \fBscan\fR $string "#%2x%2x%2x" r g b .CE .PP Parse a \fIHH:MM\fR time string, noting that this avoids problems with octal numbers by forcing interpretation as decimals (if we did not care, we would use the \fB%i\fR conversion instead): .CS set string "08:08" ;# *Not* octal! if {[\fBscan\fR $string "%d:%d" hours minutes] != 2} { error "not a valid time string" } # We have to understand numeric ranges ourselves... if {$minutes < 0 || $minutes > 59} { error "invalid number of minutes" } .CE .PP Break a string up into sequences of non-whitespace characters (note the use of the \fB%n\fR conversion so that we get skipping over leading whitespace correct): .CS set string " a string {with braced words} + leading space " set words {} while {[\fBscan\fR $string %s%n word length] == 2} { lappend words $word set string [string range $string $length end] } .CE .PP Parse a simple coordinate string, checking that it is complete by looking for the terminating character explicitly: .CS set string "(5.2,-4e-2)" # Note that the spaces before the literal parts of # the scan pattern are significant, and that ")" is # the Unicode character \\u0029 if { [\fBscan\fR $string " (%f ,%f %c" x y last] != 3 || $last != 0x0029 } then { error "invalid coordinate string" } puts "X=$x, Y=$y" .CE .SH "SEE ALSO" format(n), sscanf(3) .SH KEYWORDS conversion specifier, parse, scan tcl8.4.20/doc/ExprLongObj.30000644003604700454610000000716611737050674013753 0ustar dgp771div'\" '\" Copyright (c) 1996-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_ExprLongObj 3 8.0 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_ExprLongObj, Tcl_ExprDoubleObj, Tcl_ExprBooleanObj, Tcl_ExprObj \- evaluate an expression .SH SYNOPSIS .nf \fB#include \fR .sp int \fBTcl_ExprLongObj\fR(\fIinterp, objPtr, longPtr\fR) .sp int \fBTcl_ExprDoubleObj\fR(\fIinterp, objPtr, doublePtr\fR) .sp int \fBTcl_ExprBooleanObj\fR(\fIinterp, objPtr, booleanPtr\fR) .sp int \fBTcl_ExprObj\fR(\fIinterp, objPtr, resultPtrPtr\fR) .SH ARGUMENTS .AS Tcl_Interp **resultPtrPtr out .AP Tcl_Interp *interp in Interpreter in whose context to evaluate \fIobjPtr\fR. .AP Tcl_Obj *objPtr in Pointer to an object containing the expression to evaluate. .AP long *longPtr out Pointer to location in which to store the integer value of the expression. .AP int *doublePtr out Pointer to location in which to store the floating-point value of the expression. .AP int *booleanPtr out Pointer to location in which to store the 0/1 boolean value of the expression. .AP Tcl_Obj **resultPtrPtr out Pointer to location in which to store a pointer to the object that is the result of the expression. .BE .SH DESCRIPTION .PP These four procedures all evaluate an expression, returning the result in one of four different forms. The expression is given by the \fIobjPtr\fR argument, and it can have any of the forms accepted by the \fBexpr\fR command. .PP The \fIinterp\fR argument refers to an interpreter used to evaluate the expression (e.g. for variables and nested Tcl commands) and to return error information. .PP For all of these procedures the return value is a standard Tcl result: \fBTCL_OK\fR means the expression was successfully evaluated, and \fBTCL_ERROR\fR means that an error occurred while evaluating the expression. If \fBTCL_ERROR\fR is returned, then a message describing the error can be retrieved using \fBTcl_GetObjResult\fR. If an error occurs while executing a Tcl command embedded in the expression then that error will be returned. .PP If the expression is successfully evaluated, then its value is returned in one of four forms, depending on which procedure is invoked. \fBTcl_ExprLongObj\fR stores an integer value at \fI*longPtr\fR. If the expression's actual value is a floating-point number, then it is truncated to an integer. If the expression's actual value is a non-numeric string then an error is returned. .PP \fBTcl_ExprDoubleObj\fR stores a floating-point value at \fI*doublePtr\fR. If the expression's actual value is an integer, it is converted to floating-point. If the expression's actual value is a non-numeric string then an error is returned. .PP \fBTcl_ExprBooleanObj\fR stores a 0/1 integer value at \fI*booleanPtr\fR. If the expression's actual value is an integer or floating-point number, then they store 0 at \fI*booleanPtr\fR if the value was zero and 1 otherwise. If the expression's actual value is a non-numeric string then it must be one of the values accepted by \fBTcl_GetBoolean\fR such as ``yes'' or ``no'', or else an error occurs. .PP If \fBTcl_ExprObj\fR successfully evaluates the expression, it stores a pointer to the Tcl object containing the expression's value at \fI*resultPtrPtr\fR. In this case, the caller is responsible for calling \fBTcl_DecrRefCount\fR to decrement the object's reference count when it is finished with the object. .SH "SEE ALSO" Tcl_ExprLong, Tcl_ExprDouble, Tcl_ExprBoolean, Tcl_ExprString, Tcl_GetObjResult .SH KEYWORDS boolean, double, evaluate, expression, integer, object, string tcl8.4.20/doc/GetVersion.30000755003604700454610000000307411737050674013644 0ustar dgp771div'\" '\" Copyright (c) 1999 Scriptics Corporation '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_GetVersion 3 7.5 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_GetVersion \- get the version of the library at runtime .SH SYNOPSIS .nf \fB#include \fR .sp \fBTcl_GetVersion\fR(\fImajor, minor, patchLevel, type\fR) .SH ARGUMENTS .AP int *major out Major version number of the Tcl library. .AP int *minor out Minor version number of the Tcl library. .AP int *patchLevel out The patch level of the Tcl library (or alpha or beta number). .AP Tcl_ReleaseType *type out The type of release, also indicates the type of patch level. Can be one of \fBTCL_ALPHA_RELEASE\fR, \fBTCL_BETA_RELEASE\fR, or \fBTCL_FINAL_RELEASE\fR. .BE .SH DESCRIPTION .PP \fBTcl_GetVersion\fR should be used to query the version number of the Tcl library at runtime. This is useful when using a dynamically loaded Tcl library or when writing a stubs-aware extension. For instance, if you write an extension that is linked against the Tcl stubs library, it could be loaded into a program linked to an older version of Tcl than you expected. Use \fBTcl_GetVersion\fR to verify that fact, and possibly to change the behavior of your extension. .PP \fBTcl_GetVersion\fR accepts NULL for any of the arguments. For instance if you do not care about the \fIpatchLevel\fR of the library, pass a NULL for the \fIpatchLevel\fR argument. .SH KEYWORDS version, patchlevel, major, minor, alpha, beta, release tcl8.4.20/doc/RegExp.30000644003604700454610000003535711737050674012757 0ustar dgp771div'\" '\" Copyright (c) 1994 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" Copyright (c) 1998-1999 Scriptics Corporation '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_RegExpMatch 3 8.1 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_RegExpMatch, Tcl_RegExpCompile, Tcl_RegExpExec, Tcl_RegExpRange, Tcl_GetRegExpFromObj, Tcl_RegExpMatchObj, Tcl_RegExpExecObj, Tcl_RegExpGetInfo \- Pattern matching with regular expressions .SH SYNOPSIS .nf \fB#include \fR .sp int \fBTcl_RegExpMatchObj\fR(\fIinterp\fR, \fIstrObj\fR, \fIpatObj\fR) .sp int \fBTcl_RegExpMatch\fR(\fIinterp\fR, \fIstring\fR, \fIpattern\fR) .sp Tcl_RegExp \fBTcl_RegExpCompile\fR(\fIinterp\fR, \fIpattern\fR) .sp int \fBTcl_RegExpExec\fR(\fIinterp\fR, \fIregexp\fR, \fIstring\fR, \fIstart\fR) .sp \fBTcl_RegExpRange\fR(\fIregexp\fR, \fIindex\fR, \fIstartPtr\fR, \fIendPtr\fR) .VS 8.1 .sp Tcl_RegExp \fBTcl_GetRegExpFromObj\fR(\fIinterp\fR, \fIpatObj\fR, \fIcflags\fR) .sp int \fBTcl_RegExpExecObj\fR(\fIinterp\fR, \fIregexp\fR, \fIobjPtr\fR, \fIoffset\fR, \fInmatches\fR, \fIeflags\fR) .sp \fBTcl_RegExpGetInfo\fR(\fIregexp\fR, \fIinfoPtr\fR) .VE 8.1 .SH ARGUMENTS .AS Tcl_Interp *interp .AP Tcl_Interp *interp in Tcl interpreter to use for error reporting. The interpreter may be NULL if no error reporting is desired. .VS 8.1 .AP Tcl_Obj *strObj in/out Refers to the object from which to get the string to search. The internal representation of the object may be converted to a form that can be efficiently searched. .AP Tcl_Obj *patObj in/out Refers to the object from which to get a regular expression. The compiled regular expression is cached in the object. .VE 8.1 .AP char *string in String to check for a match with a regular expression. .AP "CONST char" *pattern in String in the form of a regular expression pattern. .AP Tcl_RegExp regexp in Compiled regular expression. Must have been returned previously by \fBTcl_GetRegExpFromObj\fR or \fBTcl_RegExpCompile\fR. .AP char *start in If \fIstring\fR is just a portion of some other string, this argument identifies the beginning of the larger string. If it isn't the same as \fIstring\fR, then no \fB^\fR matches will be allowed. .AP int index in Specifies which range is desired: 0 means the range of the entire match, 1 or greater means the range that matched a parenthesized sub-expression. .VS 8.4 .AP "CONST char" **startPtr out The address of the first character in the range is stored here, or NULL if there is no such range. .AP "CONST char" **endPtr out The address of the character just after the last one in the range is stored here, or NULL if there is no such range. .VE 8.4 .VS 8.1 .AP int cflags in OR-ed combination of compilation flags. See below for more information. .AP Tcl_Obj *objPtr in/out An object which contains the string to check for a match with a regular expression. .AP int offset in The character offset into the string where matching should begin. The value of the offset has no impact on \fB^\fR matches. This behavior is controlled by \fIeflags\fR. .AP int nmatches in The number of matching subexpressions that should be remembered for later use. If this value is 0, then no subexpression match information will be computed. If the value is -1, then all of the matching subexpressions will be remembered. Any other value will be taken as the maximum number of subexpressions to remember. .AP int eflags in OR-ed combination of the values TCL_REG_NOTBOL and TCL_REG_NOTEOL. See below for more information. .AP Tcl_RegExpInfo *infoPtr out The address of the location where information about a previous match should be stored by \fBTcl_RegExpGetInfo\fR. .VE 8.1 .BE .SH DESCRIPTION .PP \fBTcl_RegExpMatch\fR determines whether its \fIpattern\fR argument matches \fIregexp\fR, where \fIregexp\fR is interpreted as a regular expression using the rules in the \fBre_syntax\fR reference page. If there is a match then \fBTcl_RegExpMatch\fR returns 1. If there is no match then \fBTcl_RegExpMatch\fR returns 0. If an error occurs in the matching process (e.g. \fIpattern\fR is not a valid regular expression) then \fBTcl_RegExpMatch\fR returns \-1 and leaves an error message in the interpreter result. .VS 8.1.2 \fBTcl_RegExpMatchObj\fR is similar to \fBTcl_RegExpMatch\fR except it operates on the Tcl objects \fIstrObj\fR and \fIpatObj\fR instead of UTF strings. \fBTcl_RegExpMatchObj\fR is generally more efficient than \fBTcl_RegExpMatch\fR, so it is the preferred interface. .VE 8.1.2 .PP \fBTcl_RegExpCompile\fR, \fBTcl_RegExpExec\fR, and \fBTcl_RegExpRange\fR provide lower-level access to the regular expression pattern matcher. \fBTcl_RegExpCompile\fR compiles a regular expression string into the internal form used for efficient pattern matching. The return value is a token for this compiled form, which can be used in subsequent calls to \fBTcl_RegExpExec\fR or \fBTcl_RegExpRange\fR. If an error occurs while compiling the regular expression then \fBTcl_RegExpCompile\fR returns NULL and leaves an error message in the interpreter result. Note: the return value from \fBTcl_RegExpCompile\fR is only valid up to the next call to \fBTcl_RegExpCompile\fR; it is not safe to retain these values for long periods of time. .PP \fBTcl_RegExpExec\fR executes the regular expression pattern matcher. It returns 1 if \fIstring\fR contains a range of characters that match \fIregexp\fR, 0 if no match is found, and \-1 if an error occurs. In the case of an error, \fBTcl_RegExpExec\fR leaves an error message in the interpreter result. When searching a string for multiple matches of a pattern, it is important to distinguish between the start of the original string and the start of the current search. For example, when searching for the second occurrence of a match, the \fIstring\fR argument might point to the character just after the first match; however, it is important for the pattern matcher to know that this is not the start of the entire string, so that it doesn't allow \fB^\fR atoms in the pattern to match. The \fIstart\fR argument provides this information by pointing to the start of the overall string containing \fIstring\fR. \fIStart\fR will be less than or equal to \fIstring\fR; if it is less than \fIstring\fR then no \fB^\fR matches will be allowed. .PP \fBTcl_RegExpRange\fR may be invoked after \fBTcl_RegExpExec\fR returns; it provides detailed information about what ranges of the string matched what parts of the pattern. \fBTcl_RegExpRange\fR returns a pair of pointers in \fI*startPtr\fR and \fI*endPtr\fR that identify a range of characters in the source string for the most recent call to \fBTcl_RegExpExec\fR. \fIIndex\fR indicates which of several ranges is desired: if \fIindex\fR is 0, information is returned about the overall range of characters that matched the entire pattern; otherwise, information is returned about the range of characters that matched the \fIindex\fR'th parenthesized subexpression within the pattern. If there is no range corresponding to \fIindex\fR then NULL is stored in \fI*startPtr\fR and \fI*endPtr\fR. .PP .VS 8.1 \fBTcl_GetRegExpFromObj\fR, \fBTcl_RegExpExecObj\fR, and \fBTcl_RegExpGetInfo\fR are object interfaces that provide the most direct control of Henry Spencer's regular expression library. For users that need to modify compilation and execution options directly, it is recommended that you use these interfaces instead of calling the internal regexp functions. These interfaces handle the details of UTF to Unicode translations as well as providing improved performance through caching in the pattern and string objects. .PP \fBTcl_GetRegExpFromObj\fR attempts to return a compiled regular expression from the \fIpatObj\fR. If the object does not already contain a compiled regular expression it will attempt to create one from the string in the object and assign it to the internal representation of the \fIpatObj\fR. The return value of this function is of type \fBTcl_RegExp\fR. The return value is a token for this compiled form, which can be used in subsequent calls to \fBTcl_RegExpExecObj\fR or \fBTcl_RegExpGetInfo\fR. If an error occurs while compiling the regular expression then \fBTcl_GetRegExpFromObj\fR returns NULL and leaves an error message in the interpreter result. The regular expression token can be used as long as the internal representation of \fIpatObj\fR refers to the compiled form. The \fIeflags\fR argument is a bitwise OR of zero or more of the following flags that control the compilation of \fIpatObj\fR: .RS 2 .TP \fBTCL_REG_ADVANCED\fR Compile advanced regular expressions (`AREs'). This mode corresponds to the normal regular expression syntax accepted by the Tcl regexp and regsub commands. .TP \fBTCL_REG_EXTENDED\fR Compile extended regular expressions (`EREs'). This mode corresponds to the regular expression syntax recognized by Tcl 8.0 and earlier versions. .TP \fBTCL_REG_BASIC\fR Compile basic regular expressions (`BREs'). This mode corresponds to the regular expression syntax recognized by common Unix utilities like \fBsed\fR and \fBgrep\fR. This is the default if no flags are specified. .TP \fBTCL_REG_EXPANDED\fR Compile the regular expression (basic, extended, or advanced) using an expanded syntax that allows comments and whitespace. This mode causes non-backslashed non-bracket-expression white space and #-to-end-of-line comments to be ignored. .TP \fBTCL_REG_QUOTE\fR Compile a literal string, with all characters treated as ordinary characters. .TP \fBTCL_REG_NOCASE\fR Compile for matching that ignores upper/lower case distinctions. .TP \fBTCL_REG_NEWLINE\fR Compile for newline-sensitive matching. By default, newline is a completely ordinary character with no special meaning in either regular expressions or strings. With this flag, `[^' bracket expressions and `.' never match newline, `^' matches an empty string after any newline in addition to its normal function, and `$' matches an empty string before any newline in addition to its normal function. \fBREG_NEWLINE\fR is the bitwise OR of \fBREG_NLSTOP\fR and \fBREG_NLANCH\fR. .TP \fBTCL_REG_NLSTOP\fR Compile for partial newline-sensitive matching, with the behavior of `[^' bracket expressions and `.' affected, but not the behavior of `^' and `$'. In this mode, `[^' bracket expressions and `.' never match newline. .TP \fBTCL_REG_NLANCH\fR Compile for inverse partial newline-sensitive matching, with the behavior of of `^' and `$' (the ``anchors'') affected, but not the behavior of `[^' bracket expressions and `.'. In this mode `^' matches an empty string after any newline in addition to its normal function, and `$' matches an empty string before any newline in addition to its normal function. .TP \fBTCL_REG_NOSUB\fR Compile for matching that reports only success or failure, not what was matched. This reduces compile overhead and may improve performance. Subsequent calls to \fBTcl_RegExpGetInfo\fR or \fBTcl_RegExpRange\fR will not report any match information. .TP \fBTCL_REG_CANMATCH\fR Compile for matching that reports the potential to complete a partial match given more text (see below). .RE .PP Only one of \fBTCL_REG_EXTENDED\fR, \fBTCL_REG_ADVANCED\fR, \fBTCL_REG_BASIC\fR, and \fBTCL_REG_QUOTE\fR may be specified. .PP \fBTcl_RegExpExecObj\fR executes the regular expression pattern matcher. It returns 1 if \fIobjPtr\fR contains a range of characters that match \fIregexp\fR, 0 if no match is found, and \-1 if an error occurs. In the case of an error, \fBTcl_RegExpExecObj\fR leaves an error message in the interpreter result. The \fInmatches\fR value indicates to the matcher how many subexpressions are of interest. If \fInmatches\fR is 0, then no subexpression match information is recorded, which may allow the matcher to make various optimizations. If the value is -1, then all of the subexpressions in the pattern are remembered. If the value is a positive integer, then only that number of subexpressions will be remembered. Matching begins at the specified Unicode character index given by \fIoffset\fR. Unlike \fBTcl_RegExpExec\fR, the behavior of anchors is not affected by the offset value. Instead the behavior of the anchors is explicitly controlled by the \fIeflags\fR argument, which is a bitwise OR of zero or more of the following flags: .RS 2 .TP \fBTCL_REG_NOTBOL\fR The starting character will not be treated as the beginning of a line or the beginning of the string, so `^' will not match there. Note that this flag has no effect on how `\fB\eA\fR' matches. .TP \fBTCL_REG_NOTEOL\fR The last character in the string will not be treated as the end of a line or the end of the string, so '$' will not match there. Note that this flag has no effect on how `\fB\eZ\fR' matches. .RE .PP \fBTcl_RegExpGetInfo\fR retrieves information about the last match performed with a given regular expression \fIregexp\fR. The \fIinfoPtr\fR argument contains a pointer to a structure that is defined as follows: .PP .CS typedef struct Tcl_RegExpInfo { int \fInsubs\fR; Tcl_RegExpIndices *\fImatches\fR; long \fIextendStart\fR; } Tcl_RegExpInfo; .CE .PP The \fInsubs\fR field contains a count of the number of parenthesized subexpressions within the regular expression. If the \fBTCL_REG_NOSUB\fR was used, then this value will be zero. The \fImatches\fR field points to an array of \fInsubs\fR values that indicate the bounds of each subexpression matched. The first element in the array refers to the range matched by the entire regular expression, and subsequent elements refer to the parenthesized subexpressions in the order that they appear in the pattern. Each element is a structure that is defined as follows: .PP .CS typedef struct Tcl_RegExpIndices { long \fIstart\fR; long \fIend\fR; } Tcl_RegExpIndices; .CE .PP The \fIstart\fR and \fIend\fR values are Unicode character indices relative to the offset location within \fIobjPtr\fR where matching began. The \fIstart\fR index identifies the first character of the matched subexpression. The \fIend\fR index identifies the first character after the matched subexpression. If the subexpression matched the empty string, then \fIstart\fR and \fIend\fR will be equal. If the subexpression did not participate in the match, then \fIstart\fR and \fIend\fR will be set to -1. .PP The \fIextendStart\fR field in \fBTcl_RegExpInfo\fR is only set if the \fBTCL_REG_CANMATCH\fR flag was used. It indicates the first character in the string where a match could occur. If a match was found, this will be the same as the beginning of the current match. If no match was found, then it indicates the earliest point at which a match might occur if additional text is appended to the string. If it is no match is possible even with further text, this field will be set to -1. .VE 8.1 .SH "SEE ALSO" re_syntax(n) .SH KEYWORDS match, pattern, regular expression, string, subexpression, Tcl_RegExpIndices, Tcl_RegExpInfo tcl8.4.20/doc/license.terms0000644003604700454610000000432111737050674014162 0ustar dgp771divThis software is copyrighted by the Regents of the University of California, Sun Microsystems, Inc., Scriptics Corporation, ActiveState Corporation and other parties. The following terms apply to all files associated with the software unless explicitly disclaimed in individual files. The authors hereby grant permission to use, copy, modify, distribute, and license this software and its documentation for any purpose, provided that existing copyright notices are retained in all copies and that this notice is included verbatim in any distributions. No written agreement, license, or royalty fee is required for any of the authorized uses. Modifications to this software may be copyrighted by their authors and need not follow the licensing terms described here, provided that the new terms are clearly indicated on the first page of each file where they apply. IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. GOVERNMENT USE: If you are acquiring this software on behalf of the U.S. government, the Government shall have only "Restricted Rights" in the software and related documentation as defined in the Federal Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are acquiring the software on behalf of the Department of Defense, the software shall be classified as "Commercial Computer Software" and the Government shall have only "Restricted Rights" as defined in Clause 252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the authors grant the U.S. Government and others acting in its behalf permission to use and distribute the software in accordance with the terms specified in this license. tcl8.4.20/doc/GetHostName.30000644003604700454610000000120511737050674013724 0ustar dgp771div'\" '\" Copyright (c) 1998-2000 by Scriptics Corporation. '\" All rights reserved. '\" .so man.macros .TH Tcl_GetHostName 3 8.3 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_GetHostName \- get the name of the local host .SH SYNOPSIS .nf \fB#include \fR .sp CONST char * \fBTcl_GetHostName\fR() .BE .SH DESCRIPTION .PP \fBTcl_GetHostName\fR is a utility procedure used by some of the Tcl commands. It returns a pointer to a string containing the name for the current machine, or an empty string if the name cannot be determined. The string is statically allocated, and the caller must not modify of free it. .PP .SH KEYWORDS hostname tcl8.4.20/doc/file.n0000644003604700454610000004527212052456743012572 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH file n 8.3 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME file \- Manipulate file names and attributes .SH SYNOPSIS \fBfile \fIoption\fR \fIname\fR ?\fIarg arg ...\fR? .BE .SH DESCRIPTION .PP This command provides several operations on a file's name or attributes. \fIName\fR is the name of a file; if it starts with a tilde, then tilde substitution is done before executing the command (see the manual entry for \fBfilename\fR for details). \fIOption\fR indicates what to do with the file name. Any unique abbreviation for \fIoption\fR is acceptable. The valid options are: .TP \fBfile atime \fIname\fR ?\fBtime\fR? . Returns a decimal string giving the time at which file \fIname\fR was last accessed. If \fItime\fR is specified, it is an access time to set for the file. The time is measured in the standard POSIX fashion as seconds from a fixed starting time (often January 1, 1970). If the file doesn't exist or its access time cannot be queried or set then an error is generated. On Windows, FAT file systems do not support access time. .TP \fBfile attributes \fIname\fR .TP \fBfile attributes \fIname\fR ?\fBoption\fR? .TP \fBfile attributes \fIname\fR ?\fBoption value option value...\fR? .RS This subcommand returns or sets platform specific values associated with a file. The first form returns a list of the platform specific flags and their values. The second form returns the value for the specific option. The third form sets one or more of the values. The values are as follows: .PP On Unix, \fB-group\fR gets or sets the group name for the file. A group id can be given to the command, but it returns a group name. \fB-owner\fR gets or sets the user name of the owner of the file. The command returns the owner name, but the numerical id can be passed when setting the owner. \fB-permissions\fR sets or retrieves the octal code that chmod(1) uses. This command does also has limited support for setting using the symbolic attributes for chmod(1), of the form [ugo]?[[+\-=][rwxst],[...]], where multiple symbolic attributes can be separated by commas (example: \fBu+s,go\-rw\fR add sticky bit for user, remove read and write permissions for group and other). A simplified \fBls\fR style string, of the form rwxrwxrwx (must be 9 characters), is also supported (example: \fBrwxr\-xr\-t\fR is equivalent to 01755). .PP On Windows, \fB-archive\fR gives the value or sets or clears the archive attribute of the file. \fB-hidden\fR gives the value or sets or clears the hidden attribute of the file. \fB-longname\fR will expand each path element to its long version. This attribute cannot be set. \fB-readonly\fR gives the value or sets or clears the readonly attribute of the file. \fB-shortname\fR gives a string where every path element is replaced with its short (8.3) version of the name. This attribute cannot be set. \fB-system\fR gives or sets or clears the value of the system attribute of the file. .RE .VS .TP \fBfile channels ?\fIpattern\fR? . If \fIpattern\fR isn't specified, returns a list of names of all registered open channels in this interpreter. If \fIpattern\fR is specified, only those names matching \fIpattern\fR are returned. Matching is determined using the same rules as for \fBstring match\fR. .VE .TP \fBfile copy \fR?\fB\-force\fR? ?\fB\-\|\-\fR? \fIsource\fR \fItarget\fR .TP \fBfile copy \fR?\fB\-force\fR? ?\fB\-\|\-\fR? \fIsource\fR ?\fIsource\fR ...? \fItargetDir\fR .RS The first form makes a copy of the file or directory \fIsource\fR under the pathname \fItarget\fR. If \fItarget\fR is an existing directory, then the second form is used. The second form makes a copy inside \fItargetDir\fR of each \fIsource\fR file listed. If a directory is specified as a \fIsource\fR, then the contents of the directory will be recursively copied into \fItargetDir\fR. Existing files will not be overwritten unless the \fB\-force\fR option is specified. When copying within a single filesystem, \fIfile copy\fR will copy soft links (i.e. the links themselves are copied, not the things they point to). Trying to overwrite a non-empty directory, overwrite a directory with a file, or overwrite a file with a directory will all result in errors even if \fI\-force\fR was specified. Arguments are processed in the order specified, halting at the first error, if any. A \fB\-\|\-\fR marks the end of switches; the argument following the \fB\-\|\-\fR will be treated as a \fIsource\fR even if it starts with a \fB\-\fR. .RE .TP \fBfile delete \fR?\fB\-force\fR? ?\fB\-\|\-\fR? \fIpathname\fR ?\fIpathname\fR ... ? . Removes the file or directory specified by each \fIpathname\fR argument. Non-empty directories will be removed only if the \fB\-force\fR option is specified. When operating on symbolic links, the links themselves will be deleted, not the objects they point to. Trying to delete a non-existent file is not considered an error. Trying to delete a read-only file will cause the file to be deleted, even if the \fB\-force\fR flags is not specified. If the \fB\-force\fR option is specified on a directory, Tcl will attempt both to change permissions and move the current directory 'pwd' out of the given path if that is necessary to allow the deletion to proceed. Arguments are processed in the order specified, halting at the first error, if any. A \fB\-\|\-\fR marks the end of switches; the argument following the \fB\-\|\-\fR will be treated as a \fIpathname\fR even if it starts with a \fB\-\fR. .TP \fBfile dirname \fIname\fR Returns a name comprised of all of the path components in \fIname\fR excluding the last element. If \fIname\fR is a relative file name and only contains one path element, then returns ``\fB.\fR''. If \fIname\fR refers to a root directory, then the root directory is returned. For example, .RS .CS \fBfile dirname c:/\fR .CE returns \fBc:/\fR. .PP Note that tilde substitution will only be performed if it is necessary to complete the command. For example, .CS \fBfile dirname ~/src/foo.c\fR .CE returns \fB~/src\fR, whereas .CS \fBfile dirname ~\fR .CE returns \fB/home\fR (or something similar). .RE .TP \fBfile executable \fIname\fR . Returns \fB1\fR if file \fIname\fR is executable by the current user, \fB0\fR otherwise. .TP \fBfile exists \fIname\fR . Returns \fB1\fR if file \fIname\fR exists and the current user has search privileges for the directories leading to it, \fB0\fR otherwise. .TP \fBfile extension \fIname\fR . Returns all of the characters in \fIname\fR after and including the last dot in the last element of \fIname\fR. If there is no dot in the last element of \fIname\fR then returns the empty string. .TP \fBfile isdirectory \fIname\fR . Returns \fB1\fR if file \fIname\fR is a directory, \fB0\fR otherwise. .TP \fBfile isfile \fIname\fR . Returns \fB1\fR if file \fIname\fR is a regular file, \fB0\fR otherwise. .TP \fBfile join \fIname\fR ?\fIname ...\fR? . Takes one or more file names and combines them, using the correct path separator for the current platform. If a particular \fIname\fR is relative, then it will be joined to the previous file name argument. Otherwise, any earlier arguments will be discarded, and joining will proceed from the current argument. For example, .RS .CS \fBfile join a b /foo bar\fR .CE returns \fB/foo/bar\fR. .PP Note that any of the names can contain separators, and that the result is always canonical for the current platform: \fB/\fR for Unix and Windows. .RE .TP \fBfile link ?\fI-linktype\fR? \fIlinkName\fR ?\fItarget\fR? . If only one argument is given, that argument is assumed to be \fIlinkName\fR, and this command returns the value of the link given by \fIlinkName\fR (i.e. the name of the file it points to). If \fIlinkName\fR isn't a link or its value cannot be read (as, for example, seems to be the case with hard links, which look just like ordinary files), then an error is returned. . If 2 arguments are given, then these are assumed to be \fIlinkName\fR and \fItarget\fR. If \fIlinkName\fR already exists, or if \fItarget\fR doesn't exist, an error will be returned. Otherwise, Tcl creates a new link called \fIlinkName\fR which points to the existing filesystem object at \fItarget\fR, where the type of the link is platform-specific (on Unix a symbolic link will be the default). This is useful for the case where the user wishes to create a link in a cross-platform way, and doesn't care what type of link is created. . If the user wishes to make a link of a specific type only, (and signal an error if for some reason that is not possible), then the optional \fI-linktype\fR argument should be given. Accepted values for \fI-linktype\fR are "-symbolic" and "-hard". . When creating links on filesystems that either do not support any links, or do not support the specific type requested, an error message will be returned. In particular Windows 95, 98 and ME do not support any links at present, but most Unix platforms support both symbolic and hard links (the latter for files only), MacOS supports symbolic links and Windows NT/2000/XP (on NTFS drives) support symbolic directory links and hard file links. .TP \fBfile lstat \fIname varName\fR . Same as \fBstat\fR option (see below) except uses the \fIlstat\fR kernel call instead of \fIstat\fR. This means that if \fIname\fR refers to a symbolic link the information returned in \fIvarName\fR is for the link rather than the file it refers to. On systems that don't support symbolic links this option behaves exactly the same as the \fBstat\fR option. .TP \fBfile mkdir \fIdir\fR ?\fIdir\fR ...? . Creates each directory specified. For each pathname \fIdir\fR specified, this command will create all non-existing parent directories as well as \fIdir\fR itself. If an existing directory is specified, then no action is taken and no error is returned. Trying to overwrite an existing file with a directory will result in an error. Arguments are processed in the order specified, halting at the first error, if any. .TP \fBfile mtime \fIname\fR ?\fItime\fR? . Returns a decimal string giving the time at which file \fIname\fR was last modified. If \fItime\fR is specified, it is a modification time to set for the file (equivalent to Unix \fBtouch\fR). The time is measured in the standard POSIX fashion as seconds from a fixed starting time (often January 1, 1970). If the file doesn't exist or its modified time cannot be queried or set then an error is generated. .TP \fBfile nativename \fIname\fR . Returns the platform-specific name of the file. This is useful if the filename is needed to pass to a platform-specific call, such as exec under Windows. .TP \fBfile normalize \fIname\fR . .RS Returns a unique normalized path representation for the file-system object (file, directory, link, etc), whose string value can be used as a unique identifier for it. A normalized path is an absolute path which has all '../', './' removed. Also it is one which is in the ``standard'' format for the native platform. On MacOS, Unix, this means the segments leading up to the path must be free of symbolic links/aliases (but the very last path component may be a symbolic link), and on Windows it also means we want the long form with that form's case-dependence (which gives us a unique, case-dependent path). The one exception concerning the last link in the path is necessary, because Tcl or the user may wish to operate on the actual symbolic link itself (for example 'file delete', 'file rename', 'file copy' are defined to operate on symbolic links, not on the things that they point to). .RE .TP \fBfile owned \fIname\fR . Returns \fB1\fR if file \fIname\fR is owned by the current user, \fB0\fR otherwise. .TP \fBfile pathtype \fIname\fR . Returns one of \fBabsolute\fR, \fBrelative\fR, \fBvolumerelative\fR. If \fIname\fR refers to a specific file on a specific volume, the path type will be \fBabsolute\fR. If \fIname\fR refers to a file relative to the current working directory, then the path type will be \fBrelative\fR. If \fIname\fR refers to a file relative to the current working directory on a specified volume, or to a specific file on the current working volume, then the path type is \fBvolumerelative\fR. .TP \fBfile readable \fIname\fR . Returns \fB1\fR if file \fIname\fR is readable by the current user, \fB0\fR otherwise. .TP \fBfile readlink \fIname\fR . Returns the value of the symbolic link given by \fIname\fR (i.e. the name of the file it points to). If \fIname\fR isn't a symbolic link or its value cannot be read, then an error is returned. On systems that don't support symbolic links this option is undefined. .TP \fBfile rename \fR?\fB\-force\fR? ?\fB\-\|\-\fR? \fIsource\fR \fItarget\fR .TP \fBfile rename \fR?\fB\-force\fR? ?\fB\-\|\-\fR? \fIsource\fR ?\fIsource\fR ...? \fItargetDir\fR .RS The first form takes the file or directory specified by pathname \fIsource\fR and renames it to \fItarget\fR, moving the file if the pathname \fItarget\fR specifies a name in a different directory. If \fItarget\fR is an existing directory, then the second form is used. The second form moves each \fIsource\fR file or directory into the directory \fItargetDir\fR. Existing files will not be overwritten unless the \fB\-force\fR option is specified. When operating inside a single filesystem, Tcl will rename symbolic links rather than the things that they point to. Trying to overwrite a non-empty directory, overwrite a directory with a file, or a file with a directory will all result in errors. Arguments are processed in the order specified, halting at the first error, if any. A \fB\-\|\-\fR marks the end of switches; the argument following the \fB\-\|\-\fR will be treated as a \fIsource\fR even if it starts with a \fB\-\fR. .RE .TP \fBfile rootname \fIname\fR . Returns all of the characters in \fIname\fR up to but not including the last ``.'' character in the last component of name. If the last component of \fIname\fR doesn't contain a dot, then returns \fIname\fR. .TP \fBfile separator\fR ?\fIname\fR? . If no argument is given, returns the character which is used to separate path segments for native files on this platform. If a path is given, the filesystem responsible for that path is asked to return its separator character. If no file system accepts \fIname\fR, an error is generated. .TP \fBfile size \fIname\fR . Returns a decimal string giving the size of file \fIname\fR in bytes. If the file doesn't exist or its size cannot be queried then an error is generated. .TP \fBfile split \fIname\fR . Returns a list whose elements are the path components in \fIname\fR. The first element of the list will have the same path type as \fIname\fR. All other elements will be relative. Path separators will be discarded unless they are needed ensure that an element is unambiguously relative. For example, under Unix .RS .CS file split /foo/~bar/baz .CE returns \fB/\0\0foo\0\0./~bar\0\0baz\fR to ensure that later commands that use the third component do not attempt to perform tilde substitution. .RE .TP \fBfile stat \fIname varName\fR . Invokes the \fBstat\fR kernel call on \fIname\fR, and uses the variable given by \fIvarName\fR to hold information returned from the kernel call. \fIVarName\fR is treated as an array variable, and the following elements of that variable are set: \fBatime\fR, \fBctime\fR, \fBdev\fR, \fBgid\fR, \fBino\fR, \fBmode\fR, \fBmtime\fR, \fBnlink\fR, \fBsize\fR, \fBtype\fR, \fBuid\fR. Each element except \fBtype\fR is a decimal string with the value of the corresponding field from the \fBstat\fR return structure; see the manual entry for \fBstat\fR for details on the meanings of the values. The \fBtype\fR element gives the type of the file in the same form returned by the command \fBfile type\fR. This command returns an empty string. .TP \fBfile system \fIname\fR . Returns a list of two elements, the first of which is the name of the filesystem to use for the file, and the second an arbitrary string representing the filesystem-specific nature or type of the location within that filesystem. If a filesystem only supports one type of file, the second element may be null. For example the native files have a first element 'native', and a second element which is a platform-specific type name for the file's system (e.g. 'NTFS', 'FAT', etc), or possibly the empty string if no further information is available or if this is not implemented. A generic virtual file system might return the list 'vfs ftp' to represent a file on a remote ftp site mounted as a virtual filesystem through an extension called 'vfs'. If the file does not belong to any filesystem, an error is generated. .TP \fBfile tail \fIname\fR . Returns all of the characters in \fIname\fR after the last directory separator. If \fIname\fR contains no separators then returns \fIname\fR. .TP \fBfile type \fIname\fR . Returns a string giving the type of file \fIname\fR, which will be one of \fBfile\fR, \fBdirectory\fR, \fBcharacterSpecial\fR, \fBblockSpecial\fR, \fBfifo\fR, \fBlink\fR, or \fBsocket\fR. .TP \fBfile volumes\fR . Returns the absolute paths to the volumes mounted on the system, as a proper Tcl list. On UNIX, the command will always return "/", since all filesystems are locally mounted. On Windows, it will return a list of the available local drives (e.g. {a:/ c:/}). .TP \fBfile writable \fIname\fR . Returns \fB1\fR if file \fIname\fR is writable by the current user, \fB0\fR otherwise. .SH "PORTABILITY ISSUES" .TP \fBUnix\fR\0\0\0\0\0\0\0 . These commands always operate using the real user and group identifiers, not the effective ones. .SH EXAMPLES This procedure shows how to search for C files in a given directory that have a correspondingly-named object file in the current directory: .CS proc findMatchingCFiles {dir} { set files {} switch $::tcl_platform(platform) { windows { set ext .obj } unix { set ext .o } } foreach file [glob -nocomplain -directory $dir *.c] { set objectFile [\fBfile tail\fR [\fBfile rootname\fR $file]]$ext if {[\fBfile exists\fR $objectFile]} { lappend files $file } } return $files } .CE .PP Rename a file and leave a symbolic link pointing from the old location to the new place: .CS set oldName foobar.txt set newName foo/bar.txt # Make sure that where we're going to move to exists... if {![\fBfile isdirectory\fR [\fBfile dirname\fR $newName]]} { \fBfile mkdir\fR [\fBfile dirname\fR $newName] } \fBfile rename\fR $oldName $newName \fBfile link\fR -symbolic $oldName $newName .CE .SH "SEE ALSO" filename(n), open(n), close(n), eof(n), gets(n), tell(n), seek(n), fblocked(n), flush(n) .SH KEYWORDS attributes, copy files, delete files, directory, file, move files, name, rename files, stat tcl8.4.20/doc/AllowExc.30000644003604700454610000000305311737050674013267 0ustar dgp771div'\" '\" Copyright (c) 1989-1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_AllowExceptions 3 7.4 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_AllowExceptions \- allow all exceptions in next script evaluation .SH SYNOPSIS .nf \fB#include \fR .sp \fBTcl_AllowExceptions\fR(\fIinterp\fR) .SH ARGUMENTS .AS Tcl_Interp *doublePtr .AP Tcl_Interp *interp in Interpreter in which script will be evaluated. .BE .SH DESCRIPTION .PP If a script is evaluated at top-level (i.e. no other scripts are pending evaluation when the script is invoked), and if the script terminates with a completion code other than TCL_OK, TCL_ERROR or TCL_RETURN, then Tcl normally converts this into a TCL_ERROR return with an appropriate message. The particular script evaluation procedures of Tcl that act in the manner are \fBTcl_EvalObjEx\fR, \fBTcl_EvalObjv\fR, \fBTcl_Eval\fR, \fBTcl_EvalEx\fR, \fBTcl_GlobalEval\fR, \fBTcl_GlobalEvalObj\fR, \fBTcl_VarEval\fR and \fBTcl_VarEvalVA\fR. .PP However, if \fBTcl_AllowExceptions\fR is invoked immediately before calling one of those a procedures, then arbitrary completion codes are permitted from the script, and they are returned without modification. This is useful in cases where the caller can deal with exceptions such as TCL_BREAK or TCL_CONTINUE in a meaningful way. .SH KEYWORDS continue, break, exception, interpreter tcl8.4.20/doc/Panic.30000644003604700454610000000747211737050674012614 0ustar dgp771div'\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_Panic 3 8.4 Tcl "Tcl Library Procedures" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME Tcl_Panic, Tcl_PanicVA, Tcl_SetPanicProc, panic, panicVA \- report fatal error and abort .SH SYNOPSIS .nf \fB#include \fR .sp void \fBTcl_Panic\fR(\fIformat\fR, \fIarg\fR, \fIarg\fR, \fI...\fR) .sp void \fBTcl_PanicVA\fR(\fIformat\fR, \fIargList\fR) .sp void \fBTcl_SetPanicProc\fR(\fIpanicProc\fR) .sp void \fBpanic\fR(\fIformat\fR, \fIarg\fR, \fIarg\fR, \fI...\fR) .sp void \fBpanicVA\fR(\fIformat\fR, \fIargList\fR) .sp .SH ARGUMENTS .AS Tcl_PanicProc *panicProc .AP "CONST char*" format in A printf-style format string. .AP "" arg in Arguments matching the format string. .AP va_list argList in An argument list of arguments matching the format string. Must have been initialized using \fBTCL_VARARGS_START\fR, and cleared using \fBva_end\fR. .AP Tcl_PanicProc *panicProc in Procedure to report fatal error message and abort. .BE .SH DESCRIPTION .PP When the Tcl library detects that its internal data structures are in an inconsistent state, or that its C procedures have been called in a manner inconsistent with their documentation, it calls \fBTcl_Panic\fR to display a message describing the error and abort the process. The \fIformat\fR argument is a format string describing how to format the remaining arguments \fIarg\fR into an error message, according to the same formatting rules used by the \fBprintf\fR family of functions. The same formatting rules are also used by the builtin Tcl command \fBformat\fR. .PP In a freshly loaded Tcl library, \fBTcl_Panic\fR prints the formatted error message to the standard error file of the process, and then calls \fBabort\fR to terminate the process. \fBTcl_Panic\fR does not return. .PP \fBTcl_SetPanicProc\fR may be used to modify the behavior of \fBTcl_Panic\fR. The \fIpanicProc\fR argument should match the type \fBTcl_PanicProc\fR: .PP .CS typedef void Tcl_PanicProc( CONST char *\fBformat\fR, \fBarg\fR, \fBarg\fR,...); .CE .PP After \fBTcl_SetPanicProc\fR returns, any future calls to \fBTcl_Panic\fR will call \fIpanicProc\fR, passing along the \fIformat\fR and \fIarg\fR arguments. To maintain consistency with the callers of \fBTcl_Panic\fR, \fIpanicProc\fR must not return; it must call \fBabort\fR. \fIpanicProc\fR should avoid making calls into the Tcl library, or into other libraries that may call the Tcl library, since the original call to \fBTcl_Panic\fR indicates the Tcl library is not in a state of reliable operation. .PP The typical use of \fBTcl_SetPanicProc\fR arranges for the error message to be displayed or reported in a manner more suitable for the application or the platform. As an example, the Windows implementation of \fBwish\fR calls \fBTcl_SetPanicProc\fR to force all panic messages to be displayed in a system dialog box, rather than to be printed to the standard error file (usually not visible under Windows). .PP Although the primary callers of \fBTcl_Panic\fR are the procedures of the Tcl library, \fBTcl_Panic\fR is a public function and may be called by any extension or application that wishes to abort the process and have a panic message displayed the same way that panic messages from Tcl will be displayed. .PP \fBTcl_PanicVA\fR is the same as \fBTcl_Panic\fR except that instead of taking a variable number of arguments it takes an argument list. The procedures \fBpanic\fR and \fBpanicVA\fR are synonyms (implemented as macros) for \fBTcl_Panic\fR and \fBTcl_PanicVA\fR, respectively. They exist to support old code; new code should use direct calls to \fBTcl_Panic\fR or \fBTcl_PanicVA\fR. .SH "SEE ALSO" abort(3), printf(3), exec(n), format(n) .SH KEYWORDS abort, fatal, error tcl8.4.20/doc/Sleep.30000644003604700454610000000204111737050674012615 0ustar dgp771div'\" '\" Copyright (c) 1990 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_Sleep 3 7.5 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_Sleep \- delay execution for a given number of milliseconds .SH SYNOPSIS .nf \fB#include \fR .sp \fBTcl_Sleep\fR(\fIms\fR) .SH ARGUMENTS .AP int ms in Number of milliseconds to sleep. .BE .SH DESCRIPTION .PP This procedure delays the calling process by the number of milliseconds given by the \fIms\fR parameter and returns after that time has elapsed. It is typically used for things like flashing a button, where the delay is short and the application needn't do anything while it waits. For longer delays where the application needs to respond to other events during the delay, the procedure \fBTcl_CreateTimerHandler\fR should be used instead of \fBTcl_Sleep\fR. .SH KEYWORDS sleep, time, wait tcl8.4.20/doc/continue.n0000644003604700454610000000242611737050674013473 0ustar dgp771div'\" '\" Copyright (c) 1993-1994 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH continue n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME continue \- Skip to the next iteration of a loop .SH SYNOPSIS \fBcontinue\fR .BE .SH DESCRIPTION .PP This command is typically invoked inside the body of a looping command such as \fBfor\fR or \fBforeach\fR or \fBwhile\fR. It returns a \fBTCL_CONTINUE\fR code, which causes a continue exception to occur. The exception causes the current script to be aborted out to the innermost containing loop command, which then continues with the next iteration of the loop. Catch exceptions are also handled in a few other situations, such as the \fBcatch\fR command and the outermost scripts of procedure bodies. .SH EXAMPLE Print a line for each of the integers from 0 to 10 \fIexcept\fR 5: .CS for {set x 0} {$x<10} {incr x} { if {$x == 5} { \fBcontinue\fR } puts "x is $x" } .CE .SH "SEE ALSO" break(n), for(n), foreach(n), return(n), while(n) .SH KEYWORDS continue, iteration, loop tcl8.4.20/doc/PrintDbl.30000644003604700454610000000274711737050674013300 0ustar dgp771div'\" '\" Copyright (c) 1989-1993 The Regents of the University of California. '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_PrintDouble 3 8.0 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_PrintDouble \- Convert floating value to string .SH SYNOPSIS .nf \fB#include \fR .sp \fBTcl_PrintDouble\fR(\fIinterp, value, dst\fR) .SH ARGUMENTS .AS Tcl_Interp *interp .AP Tcl_Interp *interp in .VS Before Tcl 8.0, the \fBtcl_precision\fR variable in this interpreter controlled the conversion. As of Tcl 8.0, this argument is ignored and the conversion is controlled by the \fBtcl_precision\fR variable that is now shared by all interpreters. .VE .AP double value in Floating-point value to be converted. .AP char *dst out Where to store string representing \fIvalue\fR. Must have at least TCL_DOUBLE_SPACE characters of storage. .BE .SH DESCRIPTION .PP \fBTcl_PrintDouble\fR generates a string that represents the value of \fIvalue\fR and stores it in memory at the location given by \fIdst\fR. It uses \fB%g\fR format to generate the string, with one special twist: the string is guaranteed to contain either a ``.'' or an ``e'' so that it doesn't look like an integer. Where \fB%g\fR would generate an integer with no decimal point, \fBTcl_PrintDouble\fR adds ``.0''. .SH KEYWORDS conversion, double-precision, floating-point, string tcl8.4.20/doc/AssocData.30000644003604700454610000000670611737050674013423 0ustar dgp771div'\" '\" Copyright (c) 1995-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_SetAssocData 3 7.5 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_GetAssocData, Tcl_SetAssocData, Tcl_DeleteAssocData \- manage associations of string keys and user specified data with Tcl interpreters. .SH SYNOPSIS .nf \fB#include \fR .sp ClientData \fBTcl_GetAssocData\fR(\fIinterp, key, delProcPtr\fR) .sp \fBTcl_SetAssocData\fR(\fIinterp, key, delProc, clientData\fR) .sp \fBTcl_DeleteAssocData\fR(\fIinterp, key\fR) .SH ARGUMENTS .AS Tcl_InterpDeleteProc *delProcPtr .AP Tcl_Interp *interp in Interpreter in which to execute the specified command. .VS 8.4 .AP "CONST char" *key in .VE Key for association with which to store data or from which to delete or retrieve data. Typically the module prefix for a package. .AP Tcl_InterpDeleteProc *delProc in Procedure to call when \fIinterp\fR is deleted. .AP Tcl_InterpDeleteProc **delProcPtr in Pointer to location in which to store address of current deletion procedure for association. Ignored if NULL. .AP ClientData clientData in Arbitrary one-word value associated with the given key in this interpreter. This data is owned by the caller. .BE .SH DESCRIPTION .PP These procedures allow extensions to associate their own data with a Tcl interpreter. An association consists of a string key, typically the name of the extension, and a one-word value, which is typically a pointer to a data structure holding data specific to the extension. Tcl makes no interpretation of either the key or the value for an association. .PP Storage management is facilitated by storing with each association a procedure to call when the interpreter is deleted. This procedure can dispose of the storage occupied by the client's data in any way it sees fit. .PP \fBTcl_SetAssocData\fR creates an association between a string key and a user specified datum in the given interpreter. If there is already an association with the given \fIkey\fR, \fBTcl_SetAssocData\fR overwrites it with the new information. It is up to callers to organize their use of names to avoid conflicts, for example, by using package names as the keys. If the \fIdeleteProc\fR argument is non-NULL it specifies the address of a procedure to invoke if the interpreter is deleted before the association is deleted. \fIDeleteProc\fR should have arguments and result that match the type \fBTcl_InterpDeleteProc\fR: .CS typedef void Tcl_InterpDeleteProc( ClientData \fIclientData\fR, Tcl_Interp *\fIinterp\fR); .CE When \fIdeleteProc\fR is invoked the \fIclientData\fR and \fIinterp\fR arguments will be the same as the corresponding arguments passed to \fBTcl_SetAssocData\fR. The deletion procedure will \fInot\fR be invoked if the association is deleted before the interpreter is deleted. .PP \fBTcl_GetAssocData\fR returns the datum stored in the association with the specified key in the given interpreter, and if the \fIdelProcPtr\fR field is non-\fBNULL\fR, the address indicated by it gets the address of the delete procedure stored with this association. If no association with the specified key exists in the given interpreter \fBTcl_GetAssocData\fR returns \fBNULL\fR. .PP \fBTcl_DeleteAssocData\fR deletes an association with a specified key in the given interpreter. Then it calls the deletion procedure. .SH KEYWORDS association, data, deletion procedure, interpreter, key tcl8.4.20/doc/BackgdErr.30000644003604700454610000000431411737050674013376 0ustar dgp771div'\" '\" Copyright (c) 1992-1994 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_BackgroundError 3 7.5 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_BackgroundError \- report Tcl error that occurred in background processing .SH SYNOPSIS .nf \fB#include \fR .sp \fBTcl_BackgroundError\fR(\fIinterp\fR) .SH ARGUMENTS .AS Tcl_Interp *interp .AP Tcl_Interp *interp in Interpreter in which the error occurred. .BE .SH DESCRIPTION .PP This procedure is typically invoked when a Tcl error occurs during ``background processing'' such as executing an event handler. When such an error occurs, the error condition is reported to Tcl or to a widget or some other C code, and there is not usually any obvious way for that code to report the error to the user. In these cases the code calls \fBTcl_BackgroundError\fR with an \fIinterp\fR argument identifying the interpreter in which the error occurred. At the time \fBTcl_BackgroundError\fR is invoked, the interpreter's result is expected to contain an error message. \fBTcl_BackgroundError\fR will invoke the \fBbgerror\fR Tcl command to report the error in an application-specific fashion. If no \fBbgerror\fR command exists, or if it returns with an error condition, then \fBTcl_BackgroundError\fR reports the error itself by printing a message on the standard error file. .PP \fBTcl_BackgroundError\fR does not invoke \fBbgerror\fR immediately because this could potentially interfere with scripts that are in process at the time the error occurred. Instead, it invokes \fBbgerror\fR later as an idle callback. \fBTcl_BackgroundError\fR saves the values of the \fBerrorInfo\fR and \fBerrorCode\fR variables and restores these values just before invoking \fBbgerror\fR. .PP It is possible for many background errors to accumulate before \fBbgerror\fR is invoked. When this happens, each of the errors is processed in order. However, if \fBbgerror\fR returns a break exception, then all remaining error reports for the interpreter are skipped. .SH KEYWORDS background, bgerror, error tcl8.4.20/doc/catch.n0000644003604700454610000000620111737050674012724 0ustar dgp771div'\" '\" Copyright (c) 1993-1994 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH catch n "8.0" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME catch \- Evaluate script and trap exceptional returns .SH SYNOPSIS \fBcatch\fI script \fR?\fIvarName\fR? .BE .SH DESCRIPTION .PP The \fBcatch\fR command may be used to prevent errors from aborting command interpretation. The \fBcatch\fR command calls the Tcl interpreter recursively to execute \fIscript\fR, and always returns without raising an error, regardless of any errors that might occur while executing \fIscript\fR. .PP If \fIscript\fR raises an error, \fBcatch\fR will return a non-zero integer value corresponding to the exceptional return code returned by evaluation of \fIscript\fR. Tcl defines the normal return code from script evaluation to be zero (0), or \fBTCL_OK\fR. Tcl also defines four exceptional return codes: 1 (\fBTCL_ERROR\fR), 2 (\fBTCL_RETURN\fR), 3 (\fBTCL_BREAK\fR), and 4 (\fBTCL_CONTINUE\fR). Errors during evaluation of a script are indicated by a return code of \fBTCL_ERROR\fR. The other exceptional return codes are returned by the \fBreturn\fR, \fBbreak\fR, and \fBcontinue\fR commands and in other special situations as documented. Tcl packages can define new commands that return other integer values as return codes as well, and scripts that make use of the \fBreturn -code\fR command can also have return codes other than the five defined by Tcl. .PP If the \fIvarName\fR argument is given, then the variable it names is set to the result of the script evaluation. When the return code from the script is 1 (\fBTCL_ERROR\fR), the value stored in \fIvarName\fR is an error message. When the return code from the script is 0 (\fBTCL_OK\fR), the value stored in \fIresultVarName\fR is the value returned from \fIscript\fR. .PP If \fIscript\fR does not raise an error, \fBcatch\fR will return 0 (\fBTCL_OK\fR) and set the variable to the value returned from \fIscript\fR. .PP Note that \fBcatch\fR catches all exceptions, including those generated by \fBbreak\fR and \fBcontinue\fR as well as errors. The only errors that are not caught are syntax errors found when the script is compiled. This is because the catch command only catches errors during runtime. When the catch statement is compiled, the script is compiled as well and any syntax errors will generate a Tcl error. .SH EXAMPLES The \fBcatch\fR command may be used in an \fBif\fR to branch based on the success of a script. .CS if { [\fBcatch\fR {open $someFile w} fid] } { puts stderr "Could not open $someFile for writing\\n$fid" exit 1 } .CE .PP The \fBcatch\fR command will not catch compiled syntax errors. The first time proc \fBfoo\fR is called, the body will be compiled and a Tcl error will be generated. .CS proc foo {} { \fBcatch\fR {expr {1 +- }} } .CE .SH "SEE ALSO" break(n), continue(n), error(n), return(n), tclvars(n) .SH KEYWORDS catch, error tcl8.4.20/doc/Interp.30000644003604700454610000001271711737050674013021 0ustar dgp771div'\" '\" Copyright (c) 1989-1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_Interp 3 7.5 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_Interp \- client-visible fields of interpreter structures .SH SYNOPSIS .nf \fB#include \fR .sp typedef struct { char *\fIresult\fR; Tcl_FreeProc *\fIfreeProc\fR; int \fIerrorLine\fR; } Tcl_Interp; typedef void Tcl_FreeProc(char *\fIblockPtr\fR); .BE .SH DESCRIPTION .PP The \fBTcl_CreateInterp\fR procedure returns a pointer to a Tcl_Interp structure. This pointer is then passed into other Tcl procedures to process commands in the interpreter and perform other operations on the interpreter. Interpreter structures contain many many fields that are used by Tcl, but only three that may be accessed by clients: \fIresult\fR, \fIfreeProc\fR, and \fIerrorLine\fR. .PP The \fIresult\fR and \fIfreeProc\fR fields are used to return results or error messages from commands. This information is returned by command procedures back to \fBTcl_Eval\fR, and by \fBTcl_Eval\fR back to its callers. The \fIresult\fR field points to the string that represents the result or error message, and the \fIfreeProc\fR field tells how to dispose of the storage for the string when it isn't needed anymore. The easiest way for command procedures to manipulate these fields is to call procedures like \fBTcl_SetResult\fR or \fBTcl_AppendResult\fR; they will hide all the details of managing the fields. The description below is for those procedures that manipulate the fields directly. .PP Whenever a command procedure returns, it must ensure that the \fIresult\fR field of its interpreter points to the string being returned by the command. The \fIresult\fR field must always point to a valid string. If a command wishes to return no result then \fIinterp->result\fR should point to an empty string. Normally, results are assumed to be statically allocated, which means that the contents will not change before the next time \fBTcl_Eval\fR is called or some other command procedure is invoked. .VS In this case, the \fIfreeProc\fR field must be zero. Alternatively, a command procedure may dynamically allocate its return value (e.g. using \fBTcl_Alloc\fR) and store a pointer to it in \fIinterp->result\fR. In this case, the command procedure must also set \fIinterp->freeProc\fR to the address of a procedure that can free the value, or \fBTCL_DYNAMIC\fR if the storage was allocated directly by Tcl or by a call to \fBTcl_Alloc\fR. .VE If \fIinterp->freeProc\fR is non-zero, then Tcl will call \fIfreeProc\fR to free the space pointed to by \fIinterp->result\fR before it invokes the next command. If a client procedure overwrites \fIinterp->result\fR when \fIinterp->freeProc\fR is non-zero, then it is responsible for calling \fIfreeProc\fR to free the old \fIinterp->result\fR (the \fBTcl_FreeResult\fR macro should be used for this purpose). .PP \fIFreeProc\fR should have arguments and result that match the \fBTcl_FreeProc\fR declaration above: it receives a single argument which is a pointer to the result value to free. .VS In most applications \fBTCL_DYNAMIC\fR is the only non-zero value ever used for \fIfreeProc\fR. .VE However, an application may store a different procedure address in \fIfreeProc\fR in order to use an alternate memory allocator or in order to do other cleanup when the result memory is freed. .PP As part of processing each command, \fBTcl_Eval\fR initializes \fIinterp->result\fR and \fIinterp->freeProc\fR just before calling the command procedure for the command. The \fIfreeProc\fR field will be initialized to zero, and \fIinterp->result\fR will point to an empty string. Commands that do not return any value can simply leave the fields alone. Furthermore, the empty string pointed to by \fIresult\fR is actually part of an array of \fBTCL_RESULT_SIZE\fR characters (approximately 200). If a command wishes to return a short string, it can simply copy it to the area pointed to by \fIinterp->result\fR. Or, it can use the sprintf procedure to generate a short result string at the location pointed to by \fIinterp->result\fR. .PP It is a general convention in Tcl-based applications that the result of an interpreter is normally in the initialized state described in the previous paragraph. Procedures that manipulate an interpreter's result (e.g. by returning an error) will generally assume that the result has been initialized when the procedure is called. If such a procedure is to be called after the result has been changed, then \fBTcl_ResetResult\fR should be called first to reset the result to its initialized state. The direct use of \fIinterp->result\fR is strongly deprecated (see \fBTcl_SetResult\fR). .PP The \fIerrorLine\fR field is valid only after \fBTcl_Eval\fR returns a \fBTCL_ERROR\fR return code. In this situation the \fIerrorLine\fR field identifies the line number of the command being executed when the error occurred. The line numbers are relative to the command being executed: 1 means the first line of the command passed to \fBTcl_Eval\fR, 2 means the second line, and so on. The \fIerrorLine\fR field is typically used in conjunction with \fBTcl_AddErrorInfo\fR to report information about where an error occurred. \fIErrorLine\fR should not normally be modified except by \fBTcl_Eval\fR. .SH KEYWORDS free, initialized, interpreter, malloc, result tcl8.4.20/doc/tell.n0000644003604700454610000000310711737050674012604 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH tell n 8.1 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME tell \- Return current access position for an open channel .SH SYNOPSIS \fBtell \fIchannelId\fR .BE .SH DESCRIPTION .PP .VS 8.1 Returns an integer string giving the current access position in \fIchannelId\fR. This value returned is a byte offset that can be passed to \fBseek\fR in order to set the channel to a particular position. Note that this value is in terms of bytes, not characters like \fBread\fR. .VE 8.1 The value returned is -1 for channels that do not support seeking. .PP .VS \fIChannelId\fR must be an identifier for an open channel such as a Tcl standard channel (\fBstdin\fR, \fBstdout\fR, or \fBstderr\fR), the return value from an invocation of \fBopen\fR or \fBsocket\fR, or the result of a channel creation command provided by a Tcl extension. .VE .SH EXAMPLE Read a line from a file channel only if it starts with \fBfoobar\fR: .CS # Save the offset in case we need to undo the read... set offset [\fBtell\fR $chan] if {[read $chan 6] eq "foobar"} { gets $chan line } else { set line {} # Undo the read... seek $chan $offset } .CE .SH "SEE ALSO" file(n), open(n), close(n), gets(n), seek(n), Tcl_StandardChannels(3) .SH KEYWORDS access position, channel, seeking tcl8.4.20/doc/Init.30000644003604700454610000000127412052456743012455 0ustar dgp771div'\" '\" Copyright (c) 1998-2000 by Scriptics Corporation. '\" All rights reserved. '\" .so man.macros .TH Tcl_Init 3 8.0 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_Init \- find and source initialization script .SH SYNOPSIS .nf \fB#include \fR .sp int \fBTcl_Init\fR(\fIinterp\fR) .SH ARGUMENTS .AP Tcl_Interp *interp in Interpreter to initialize. .BE .SH DESCRIPTION .PP \fBTcl_Init\fR is a helper procedure that finds and \fBsource\fR's the \fBinit.tcl\fR script, which should exist somewhere on the Tcl library path. .PP \fBTcl_Init\fR is typically called from \fBTcl_AppInit\fR procedures. .SH "SEE ALSO" Tcl_AppInit, Tcl_Main .SH KEYWORDS application, initialization, interpreter tcl8.4.20/doc/DumpActiveMemory.30000644003604700454610000000427711737050674015014 0ustar dgp771div'\" '\" Copyright (c) 1992-1999 Karl Lehenbauer and Mark Diekhans. '\" Copyright (c) 2000 by Scriptics Corporation. '\" All rights reserved. '\" .so man.macros .TH "Tcl_DumpActiveMemory" 3 8.1 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_DumpActiveMemory, Tcl_InitMemory, Tcl_ValidateAllMemory \- Validated memory allocation interface. .SH SYNOPSIS .nf \fB#include \fR .sp int \fBTcl_DumpActiveMemory\fR(\fIfileName\fR) .sp void \fBTcl_InitMemory\fR(\fIinterp\fR) .sp void \fBTcl_ValidateAllMemory\fR(\fIfileName, line\fR) .SH ARGUMENTS .AP Tcl_Interp *interp in Tcl interpreter in which to add commands. .AP "CONST char" *fileName in For \fBTcl_DumpActiveMemory\fR, name of the file to which memory information will be written. For \fBTcl_ValidateAllMemory\fR, name of the file from which the call is being made (normally \fB__FILE__\fR). .AP int line in Line number at which the call to \fBTcl_ValidateAllMemory\fR is made (normally \fB__LINE__\fR). .BE .SH DESCRIPTION These functions provide access to Tcl memory debugging information. They are only functional when Tcl has been compiled with \fBTCL_MEM_DEBUG\fR defined at compile-time. When \fBTCL_MEM_DEBUG\fR is not defined, these functions are all no-ops. .PP \fBTcl_DumpActiveMemory\fR will output a list of all currently allocated memory to the specified file. The information output for each allocated block of memory is: starting and ending addresses (excluding guard zone), size, source file where \fBckalloc\fR was called to allocate the block and line number in that file. It is especially useful to call \fBTcl_DumpActiveMemory\fR after the Tcl interpreter has been deleted. .PP \fBTcl_InitMemory\fR adds the Tcl \fBmemory\fR command to the interpreter given by \fIinterp\fR. \fBTcl_InitMemory\fR is called by \fBTcl_Main\fR. .PP \fBTcl_ValidateAllMemory\fR forces a validation of the guard zones of all currently allocated blocks of memory. Normally validation of a block occurs when its freed, unless full validation is enabled, in which case validation of all blocks occurs when \fBckalloc\fR and \fBckfree\fR are called. This function forces the validation to occur at any point. .SH "SEE ALSO" TCL_MEM_DEBUG, memory .SH KEYWORDS memory, debug tcl8.4.20/doc/string.n0000644003604700454610000003471712133546537013164 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH string n 8.1 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME string \- Manipulate strings .SH SYNOPSIS \fBstring \fIoption arg \fR?\fIarg ...?\fR .BE .SH DESCRIPTION .PP Performs one of several string operations, depending on \fIoption\fR. The legal \fIoption\fRs (which may be abbreviated) are: .TP \fBstring compare\fR ?\fB\-nocase\fR? ?\fB\-length int\fR? \fIstring1 string2\fR Perform a character-by-character comparison of strings \fIstring1\fR and \fIstring2\fR. Returns \-1, 0, or 1, depending on whether \fIstring1\fR is lexicographically less than, equal to, or greater than \fIstring2\fR. If \fB\-length\fR is specified, then only the first \fIlength\fR characters are used in the comparison. If \fB\-length\fR is negative, it is ignored. If \fB\-nocase\fR is specified, then the strings are compared in a case-insensitive manner. .TP \fBstring equal\fR ?\fB\-nocase\fR? ?\fB-length int\fR? \fIstring1 string2\fR Perform a character-by-character comparison of strings \fIstring1\fR and \fIstring2\fR. Returns 1 if \fIstring1\fR and \fIstring2\fR are identical, or 0 when not. If \fB\-length\fR is specified, then only the first \fIlength\fR characters are used in the comparison. If \fB\-length\fR is negative, it is ignored. If \fB\-nocase\fR is specified, then the strings are compared in a case-insensitive manner. .TP \fBstring first \fIneedleString haystackString\fR ?\fIstartIndex\fR? Search \fIhaystackString\fR for a sequence of characters that exactly match the characters in \fIneedleString\fR. If found, return the index of the first character in the first such match within \fIhaystackString\fR. If not found, return \-1. If \fIstartIndex\fR is specified (in any of the forms accepted by the \fBindex\fR method), then the search is constrained to start with the character in \fIhaystackString\fR specified by the index. For example, .RS .CS \fBstring first a 0a23456789abcdef 5\fR .CE will return \fB10\fR, but .CS \fBstring first a 0123456789abcdef 11\fR .CE will return \fB\-1\fR. .RE .TP \fBstring index \fIstring charIndex\fR Returns the \fIcharIndex\fR'th character of the \fIstring\fR argument. A \fIcharIndex\fR of 0 corresponds to the first character of the string. \fIcharIndex\fR may be specified as follows: .RS .IP \fIinteger\fR 10 The char specified at this integral index. .IP \fBend\fR 10 The last char of the string. .IP \fBend\-\fIinteger\fR 10 The last char of the string minus the specified integer offset (e.g. \fBend\-1\fR would refer to the "c" in "abcd"). .PP If \fIcharIndex\fR is less than 0 or greater than or equal to the length of the string then this command returns an empty string. .RE .TP \fBstring is \fIclass\fR ?\fB\-strict\fR? ?\fB\-failindex \fIvarname\fR? \fIstring\fR Returns 1 if \fIstring\fR is a valid member of the specified character class, otherwise returns 0. If \fB\-strict\fR is specified, then an empty string returns 0, otherwise an empty string will return 1 on any class. If \fB\-failindex\fR is specified, then if the function returns 0, the index in the string where the class was no longer valid will be stored in the variable named \fIvarname\fR. The \fIvarname\fR will not be set if \fBstring is\fR returns 1. The following character classes are recognized (the class name can be abbreviated): .RS .IP \fBalnum\fR 12 Any Unicode alphabet or digit character. .IP \fBalpha\fR 12 Any Unicode alphabet character. .IP \fBascii\fR 12 Any character with a value less than \\u0080 (those that are in the 7\-bit ascii range). .IP \fBboolean\fR 12 Any of the forms allowed to \fBTcl_GetBoolean\fR. .IP \fBcontrol\fR 12 Any Unicode control character. .IP \fBdigit\fR 12 Any Unicode digit character. Note that this includes characters outside of the [0\-9] range. .IP \fBdouble\fR 12 Any of the valid forms for a double in Tcl, with optional surrounding whitespace. In case of under/overflow in the value, 0 is returned and the \fIvarname\fR will contain \-1. .IP \fBfalse\fR 12 Any of the forms allowed to \fBTcl_GetBoolean\fR where the value is false. .IP \fBgraph\fR 12 Any Unicode printing character, except space. .IP \fBinteger\fR 12 Any of the valid forms for an ordinary integer in Tcl, with optional surrounding whitespace. In case of under/overflow in the value, 0 is returned and the \fIvarname\fR will contain \-1. .IP \fBlower\fR 12 Any Unicode lower case alphabet character. .IP \fBprint\fR 12 Any Unicode printing character, including space. .IP \fBpunct\fR 12 Any Unicode punctuation character. .IP \fBspace\fR 12 Any Unicode space character. .IP \fBtrue\fR 12 Any of the forms allowed to \fBTcl_GetBoolean\fR where the value is true. .IP \fBupper\fR 12 Any upper case alphabet character in the Unicode character set. .IP \fBwordchar\fR 12 Any Unicode word character. That is any alphanumeric character, and any Unicode connector punctuation characters (e.g. underscore). .IP \fBxdigit\fR 12 Any hexadecimal digit character ([0\-9A\-Fa\-f]). .PP In the case of \fBboolean\fR, \fBtrue\fR and \fBfalse\fR, if the function will return 0, then the \fIvarname\fR will always be set to 0, due to the varied nature of a valid boolean value. .RE .TP \fBstring last \fIneedleString haystackString\fR ?\fIlastIndex\fR? Search \fIhaystackString\fR for a sequence of characters that exactly match the characters in \fIneedleString\fR. If found, return the index of the first character in the last such match within \fIhaystackString\fR. If there is no match, then return \-1. If \fIlastIndex\fR is specified (in any of the forms accepted by the \fBindex\fR method), then only the characters in \fIhaystackString\fR at or before the specified \fIlastIndex\fR will be considered by the search. For example, .RS .CS \fBstring last a 0a23456789abcdef 15\fR .CE will return \fB10\fR, but .CS \fBstring last a 0a23456789abcdef 9\fR .CE will return \fB1\fR. .RE .TP \fBstring length \fIstring\fR Returns a decimal string giving the number of characters in \fIstring\fR. Note that this is not necessarily the same as the number of bytes used to store the string. If the object is a ByteArray object (such as those returned from reading a binary encoded channel), then this will return the actual byte length of the object. .TP \fBstring map\fR ?\fB\-nocase\fR? \fImapping string\fR Replaces substrings in \fIstring\fR based on the key-value pairs in \fImapping\fR. \fImapping\fR is a list of \fIkey value key value ...\fR as in the form returned by \fBarray get\fR. Each instance of a key in the string will be replaced with its corresponding value. If \fB\-nocase\fR is specified, then matching is done without regard to case differences. Both \fIkey\fR and \fIvalue\fR may be multiple characters. Replacement is done in an ordered manner, so the key appearing first in the list will be checked first, and so on. \fIstring\fR is only iterated over once, so earlier key replacements will have no affect for later key matches. For example, .RS .CS \fBstring map {abc 1 ab 2 a 3 1 0} 1abcaababcabababc\fR .CE will return the string \fB01321221\fR. .PP Note that if an earlier \fIkey\fR is a prefix of a later one, it will completely mask the later one. So if the previous example is reordered like this, .CS \fBstring map {1 0 ab 2 a 3 abc 1} 1abcaababcabababc\fR .CE it will return the string \fB02c322c222c\fR. .RE .TP \fBstring match\fR ?\fB\-nocase\fR? \fIpattern\fR \fIstring\fR See if \fIpattern\fR matches \fIstring\fR; return 1 if it does, 0 if it does not. If \fB\-nocase\fR is specified, then the pattern attempts to match against the string in a case insensitive manner. For the two strings to match, their contents must be identical except that the following special sequences may appear in \fIpattern\fR: .RS .IP \fB*\fR 10 Matches any sequence of characters in \fIstring\fR, including a null string. .IP \fB?\fR 10 Matches any single character in \fIstring\fR. .IP \fB[\fIchars\fB]\fR 10 Matches any character in the set given by \fIchars\fR. If a sequence of the form \fIx\fB\-\fIy\fR appears in \fIchars\fR, then any character between \fIx\fR and \fIy\fR, inclusive, will match. When used with \fB\-nocase\fR, the end points of the range are converted to lower case first. Whereas {[A\-z]} matches '_' when matching case-sensitively ('_' falls between the 'Z' and 'a'), with \fB\-nocase\fR this is considered like {[A\-Za\-z]} (and probably what was meant in the first place). .IP \fB\e\fIx\fR 10 Matches the single character \fIx\fR. This provides a way of avoiding the special interpretation of the characters \fB*?[]\e\fR in \fIpattern\fR. .RE .TP \fBstring range \fIstring first last\fR Returns a range of consecutive characters from \fIstring\fR, starting with the character whose index is \fIfirst\fR and ending with the character whose index is \fIlast\fR. An index of 0 refers to the first character of the string. \fIfirst\fR and \fIlast\fR may be specified as for the \fBindex\fR method. If \fIfirst\fR is less than zero then it is treated as if it were zero, and if \fIlast\fR is greater than or equal to the length of the string then it is treated as if it were \fBend\fR. If \fIfirst\fR is greater than \fIlast\fR then an empty string is returned. .TP \fBstring repeat \fIstring count\fR Returns \fIstring\fR repeated \fIcount\fR number of times. .TP \fBstring replace \fIstring first last\fR ?\fInewstring\fR? Removes a range of consecutive characters from \fIstring\fR, starting with the character whose index is \fIfirst\fR and ending with the character whose index is \fIlast\fR. An index of 0 refers to the first character of the string. \fIFirst\fR and \fIlast\fR may be specified as for the \fBindex\fR method. If \fInewstring\fR is specified, then it is placed in the removed character range. If \fIfirst\fR is less than zero then it is treated as if it were zero, and if \fIlast\fR is greater than or equal to the length of the string then it is treated as if it were \fBend\fR. If \fIfirst\fR is greater than \fIlast\fR or the length of the initial string, or \fIlast\fR is less than 0, then the initial string is returned untouched. .TP \fBstring tolower \fIstring\fR ?\fIfirst\fR? ?\fIlast\fR? Returns a value equal to \fIstring\fR except that all upper (or title) case letters have been converted to lower case. If \fIfirst\fR is specified, it refers to the first char index in the string to start modifying. If \fIlast\fR is specified, it refers to the char index in the string to stop at (inclusive). \fIfirst\fR and \fIlast\fR may be specified as for the \fBindex\fR method. .TP \fBstring totitle \fIstring\fR ?\fIfirst\fR? ?\fIlast\fR? Returns a value equal to \fIstring\fR except that the first character in \fIstring\fR is converted to its Unicode title case variant (or upper case if there is no title case variant) and the rest of the string is converted to lower case. If \fIfirst\fR is specified, it refers to the first char index in the string to start modifying. If \fIlast\fR is specified, it refers to the char index in the string to stop at (inclusive). \fIfirst\fR and \fIlast\fR may be specified as for the \fBindex\fR method. .TP \fBstring toupper \fIstring\fR ?\fIfirst\fR? ?\fIlast\fR? Returns a value equal to \fIstring\fR except that all lower (or title) case letters have been converted to upper case. If \fIfirst\fR is specified, it refers to the first char index in the string to start modifying. If \fIlast\fR is specified, it refers to the char index in the string to stop at (inclusive). \fIfirst\fR and \fIlast\fR may be specified as for the \fBindex\fR method. .TP \fBstring trim \fIstring\fR ?\fIchars\fR? Returns a value equal to \fIstring\fR except that any leading or trailing characters present in the string given by \fIchars\fR are removed. If \fIchars\fR is not specified then white space is removed (spaces, tabs, newlines, and carriage returns). .TP \fBstring trimleft \fIstring\fR ?\fIchars\fR? Returns a value equal to \fIstring\fR except that any leading characters present in the string given by \fIchars\fR are removed. If \fIchars\fR is not specified then white space is removed (spaces, tabs, newlines, and carriage returns). .TP \fBstring trimright \fIstring\fR ?\fIchars\fR? Returns a value equal to \fIstring\fR except that any trailing characters present in the string given by \fIchars\fR are removed. If \fIchars\fR is not specified then white space is removed (spaces, tabs, newlines, and carriage returns). .SH "OBSOLETE SUBCOMMANDS" .PP These subcommands are currently supported, but are likely to go away in a future release as their functionality is either virtually never used or highly misleading. .TP \fBstring bytelength \fIstring\fR Returns a decimal string giving the number of bytes used to represent \fIstring\fR in memory. Because UTF\-8 uses one to three bytes to represent Unicode characters, the byte length will not be the same as the character length in general. The cases where a script cares about the byte length are rare. In almost all cases, you should use the \fBstring length\fR operation (including determining the length of a Tcl ByteArray object). Refer to the \fBTcl_NumUtfChars\fR manual entry for more details on the UTF\-8 representation. .TP \fBstring wordend \fIstring charIndex\fR Returns the index of the character just after the last one in the word containing character \fIcharIndex\fR of \fIstring\fR. \fIcharIndex\fR may be specified as for the \fBindex\fR method. A word is considered to be any contiguous range of alphanumeric (Unicode letters or decimal digits) or underscore (Unicode connector punctuation) characters, or any single character other than these. .TP \fBstring wordstart \fIstring charIndex\fR Returns the index of the first character in the word containing character \fIcharIndex\fR of \fIstring\fR. \fIcharIndex\fR may be specified as for the \fBindex\fR method. A word is considered to be any contiguous range of alphanumeric (Unicode letters or decimal digits) or underscore (Unicode connector punctuation) characters, or any single character other than these. .SH EXAMPLE Test if the string in the variable \fIstring\fR is a proper non-empty prefix of the string \fBfoobar\fR. .CS set length [\fBstring length\fR $string] if {$length == 0} { set isPrefix 0 } else { set isPrefix [\fBstring equal\fR -length $length $string "foobar"] } .CE .SH "SEE ALSO" expr(n), list(n) .SH KEYWORDS case conversion, compare, index, match, pattern, string, word, equal, ctype tcl8.4.20/doc/re_syntax.n0000644003604700454610000006244211737050674013667 0ustar dgp771div'\" '\" Copyright (c) 1998 Sun Microsystems, Inc. '\" Copyright (c) 1999 Scriptics Corporation '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH re_syntax n "8.1" Tcl "Tcl Built-In Commands" .BS .SH NAME re_syntax \- Syntax of Tcl regular expressions. .BE .SH DESCRIPTION .PP A \fIregular expression\fR describes strings of characters. It's a pattern that matches certain strings and doesn't match others. .SH "DIFFERENT FLAVORS OF REs" Regular expressions (``RE''s), as defined by POSIX, come in two flavors: \fIextended\fR REs (``EREs'') and \fIbasic\fR REs (``BREs''). EREs are roughly those of the traditional \fIegrep\fR, while BREs are roughly those of the traditional \fIed\fR. This implementation adds a third flavor, \fIadvanced\fR REs (``AREs''), basically EREs with some significant extensions. .PP This manual page primarily describes AREs. BREs mostly exist for backward compatibility in some old programs; they will be discussed at the end. POSIX EREs are almost an exact subset of AREs. Features of AREs that are not present in EREs will be indicated. .SH "REGULAR EXPRESSION SYNTAX" .PP Tcl regular expressions are implemented using the package written by Henry Spencer, based on the 1003.2 spec and some (not quite all) of the Perl5 extensions (thanks, Henry!). Much of the description of regular expressions below is copied verbatim from his manual entry. .PP An ARE is one or more \fIbranches\fR, separated by `\fB|\fR', matching anything that matches any of the branches. .PP A branch is zero or more \fIconstraints\fR or \fIquantified atoms\fR, concatenated. It matches a match for the first, followed by a match for the second, etc; an empty branch matches the empty string. .PP A quantified atom is an \fIatom\fR possibly followed by a single \fIquantifier\fR. Without a quantifier, it matches a match for the atom. The quantifiers, and what a so-quantified atom matches, are: .RS 2 .TP 6 \fB*\fR a sequence of 0 or more matches of the atom .TP \fB+\fR a sequence of 1 or more matches of the atom .TP \fB?\fR a sequence of 0 or 1 matches of the atom .TP \fB{\fIm\fB}\fR a sequence of exactly \fIm\fR matches of the atom .TP \fB{\fIm\fB,}\fR a sequence of \fIm\fR or more matches of the atom .TP \fB{\fIm\fB,\fIn\fB}\fR a sequence of \fIm\fR through \fIn\fR (inclusive) matches of the atom; \fIm\fR may not exceed \fIn\fR .TP \fB*? +? ?? {\fIm\fB}? {\fIm\fB,}? {\fIm\fB,\fIn\fB}?\fR \fInon-greedy\fR quantifiers, which match the same possibilities, but prefer the smallest number rather than the largest number of matches (see MATCHING) .RE .PP The forms using \fB{\fR and \fB}\fR are known as \fIbound\fRs. The numbers \fIm\fR and \fIn\fR are unsigned decimal integers with permissible values from 0 to 255 inclusive. .PP An atom is one of: .RS 2 .TP 6 \fB(\fIre\fB)\fR (where \fIre\fR is any regular expression) matches a match for \fIre\fR, with the match noted for possible reporting .TP \fB(?:\fIre\fB)\fR as previous, but does no reporting (a ``non-capturing'' set of parentheses) .TP \fB()\fR matches an empty string, noted for possible reporting .TP \fB(?:)\fR matches an empty string, without reporting .TP \fB[\fIchars\fB]\fR a \fIbracket expression\fR, matching any one of the \fIchars\fR (see BRACKET EXPRESSIONS for more detail) .TP \fB.\fR matches any single character .TP \fB\e\fIk\fR (where \fIk\fR is a non-alphanumeric character) matches that character taken as an ordinary character, e.g. \e\e matches a backslash character .TP \fB\e\fIc\fR where \fIc\fR is alphanumeric (possibly followed by other characters), an \fIescape\fR (AREs only), see ESCAPES below .TP \fB{\fR when followed by a character other than a digit, matches the left-brace character `\fB{\fR'; when followed by a digit, it is the beginning of a \fIbound\fR (see above) .TP \fIx\fR where \fIx\fR is a single character with no other significance, matches that character. .RE .PP A \fIconstraint\fR matches an empty string when specific conditions are met. A constraint may not be followed by a quantifier. The simple constraints are as follows; some more constraints are described later, under ESCAPES. .RS 2 .TP 8 \fB^\fR matches at the beginning of a line .TP \fB$\fR matches at the end of a line .TP \fB(?=\fIre\fB)\fR \fIpositive lookahead\fR (AREs only), matches at any point where a substring matching \fIre\fR begins .TP \fB(?!\fIre\fB)\fR \fInegative lookahead\fR (AREs only), matches at any point where no substring matching \fIre\fR begins .RE .PP The lookahead constraints may not contain back references (see later), and all parentheses within them are considered non-capturing. .PP An RE may not end with `\fB\e\fR'. .SH "BRACKET EXPRESSIONS" A \fIbracket expression\fR is a list of characters enclosed in `\fB[\|]\fR'. It normally matches any single character from the list (but see below). If the list begins with `\fB^\fR', it matches any single character (but see below) \fInot\fR from the rest of the list. .PP If two characters in the list are separated by `\fB\-\fR', this is shorthand for the full \fIrange\fR of characters between those two (inclusive) in the collating sequence, e.g. \fB[0\-9]\fR in ASCII matches any decimal digit. Two ranges may not share an endpoint, so e.g. \fBa\-c\-e\fR is illegal. Ranges are very collating-sequence-dependent, and portable programs should avoid relying on them. .PP To include a literal \fB]\fR or \fB\-\fR in the list, the simplest method is to enclose it in \fB[.\fR and \fB.]\fR to make it a collating element (see below). Alternatively, make it the first character (following a possible `\fB^\fR'), or (AREs only) precede it with `\fB\e\fR'. Alternatively, for `\fB\-\fR', make it the last character, or the second endpoint of a range. To use a literal \fB\-\fR as the first endpoint of a range, make it a collating element or (AREs only) precede it with `\fB\e\fR'. With the exception of these, some combinations using \fB[\fR (see next paragraphs), and escapes, all other special characters lose their special significance within a bracket expression. .PP Within a bracket expression, a collating element (a character, a multi-character sequence that collates as if it were a single character, or a collating-sequence name for either) enclosed in \fB[.\fR and \fB.]\fR stands for the sequence of characters of that collating element. The sequence is a single element of the bracket expression's list. A bracket expression in a locale that has multi-character collating elements can thus match more than one character. .VS 8.2 So (insidiously), a bracket expression that starts with \fB^\fR can match multi-character collating elements even if none of them appear in the bracket expression! (\fINote:\fR Tcl currently has no multi-character collating elements. This information is only for illustration.) .PP For example, assume the collating sequence includes a \fBch\fR multi-character collating element. Then the RE \fB[[.ch.]]*c\fR (zero or more \fBch\fP's followed by \fBc\fP) matches the first five characters of `\fBchchcc\fR'. Also, the RE \fB[^c]b\fR matches all of `\fBchb\fR' (because \fB[^c]\fR matches the multi-character \fBch\fR). .VE 8.2 .PP Within a bracket expression, a collating element enclosed in \fB[=\fR and \fB=]\fR is an equivalence class, standing for the sequences of characters of all collating elements equivalent to that one, including itself. (If there are no other equivalent collating elements, the treatment is as if the enclosing delimiters were `\fB[.\fR'\& and `\fB.]\fR'.) For example, if \fBo\fR and \fB\o'o^'\fR are the members of an equivalence class, then `\fB[[=o=]]\fR', `\fB[[=\o'o^'=]]\fR', and `\fB[o\o'o^']\fR'\& are all synonymous. An equivalence class may not be an endpoint of a range. .VS 8.2 (\fINote:\fR Tcl currently implements only the Unicode locale. It doesn't define any equivalence classes. The examples above are just illustrations.) .VE 8.2 .PP Within a bracket expression, the name of a \fIcharacter class\fR enclosed in \fB[:\fR and \fB:]\fR stands for the list of all characters (not all collating elements!) belonging to that class. Standard character classes are: .PP .RS .ne 5 .ta 3c .nf \fBalpha\fR A letter. \fBupper\fR An upper-case letter. \fBlower\fR A lower-case letter. \fBdigit\fR A decimal digit. \fBxdigit\fR A hexadecimal digit. \fBalnum\fR An alphanumeric (letter or digit). \fBprint\fR A "printable" (same as graph, except also including space). \fBblank\fR A space or tab character. \fBspace\fR A character producing white space in displayed text. \fBpunct\fR A punctuation character. \fBgraph\fR A character with a visible representation. \fBcntrl\fR A control character. .fi .RE .PP A locale may provide others. .VS 8.2 (Note that the current Tcl implementation has only one locale: the Unicode locale.) .VE 8.2 A character class may not be used as an endpoint of a range. .PP There are two special cases of bracket expressions: the bracket expressions \fB[[:<:]]\fR and \fB[[:>:]]\fR are constraints, matching empty strings at the beginning and end of a word respectively. '\" note, discussion of escapes below references this definition of word A word is defined as a sequence of word characters that is neither preceded nor followed by word characters. A word character is an \fIalnum\fR character or an underscore (\fB_\fR). These special bracket expressions are deprecated; users of AREs should use constraint escapes instead (see below). .SH ESCAPES Escapes (AREs only), which begin with a \fB\e\fR followed by an alphanumeric character, come in several varieties: character entry, class shorthands, constraint escapes, and back references. A \fB\e\fR followed by an alphanumeric character but not constituting a valid escape is illegal in AREs. In EREs, there are no escapes: outside a bracket expression, a \fB\e\fR followed by an alphanumeric character merely stands for that character as an ordinary character, and inside a bracket expression, \fB\e\fR is an ordinary character. (The latter is the one actual incompatibility between EREs and AREs.) .PP Character-entry escapes (AREs only) exist to make it easier to specify non-printing and otherwise inconvenient characters in REs: .RS 2 .TP 5 \fB\ea\fR alert (bell) character, as in C .TP \fB\eb\fR backspace, as in C .TP \fB\eB\fR synonym for \fB\e\fR to help reduce backslash doubling in some applications where there are multiple levels of backslash processing .TP \fB\ec\fIX\fR (where X is any character) the character whose low-order 5 bits are the same as those of \fIX\fR, and whose other bits are all zero .TP \fB\ee\fR the character whose collating-sequence name is `\fBESC\fR', or failing that, the character with octal value 033 .TP \fB\ef\fR formfeed, as in C .TP \fB\en\fR newline, as in C .TP \fB\er\fR carriage return, as in C .TP \fB\et\fR horizontal tab, as in C .TP \fB\eu\fIwxyz\fR (where \fIwxyz\fR is exactly four hexadecimal digits) the Unicode character \fBU+\fIwxyz\fR in the local byte ordering .TP \fB\eU\fIstuvwxyz\fR (where \fIstuvwxyz\fR is exactly eight hexadecimal digits) reserved for a somewhat-hypothetical Unicode extension to 32 bits .TP \fB\ev\fR vertical tab, as in C are all available. .TP \fB\ex\fIhhh\fR (where \fIhhh\fR is any sequence of hexadecimal digits) the character whose hexadecimal value is \fB0x\fIhhh\fR (a single character no matter how many hexadecimal digits are used). .TP \fB\e0\fR the character whose value is \fB0\fR .TP \fB\e\fIxy\fR (where \fIxy\fR is exactly two octal digits, and is not a \fIback reference\fR (see below)) the character whose octal value is \fB0\fIxy\fR .TP \fB\e\fIxyz\fR (where \fIxyz\fR is exactly three octal digits, and is not a back reference (see below)) the character whose octal value is \fB0\fIxyz\fR .RE .PP Hexadecimal digits are `\fB0\fR'-`\fB9\fR', `\fBa\fR'-`\fBf\fR', and `\fBA\fR'-`\fBF\fR'. Octal digits are `\fB0\fR'-`\fB7\fR'. .PP The character-entry escapes are always taken as ordinary characters. For example, \fB\e135\fR is \fB]\fR in ASCII, but \fB\e135\fR does not terminate a bracket expression. Beware, however, that some applications (e.g., C compilers) interpret such sequences themselves before the regular-expression package gets to see them, which may require doubling (quadrupling, etc.) the `\fB\e\fR'. .PP Class-shorthand escapes (AREs only) provide shorthands for certain commonly-used character classes: .RS 2 .TP 10 \fB\ed\fR \fB[[:digit:]]\fR .TP \fB\es\fR \fB[[:space:]]\fR .TP \fB\ew\fR \fB[[:alnum:]_]\fR (note underscore) .TP \fB\eD\fR \fB[^[:digit:]]\fR .TP \fB\eS\fR \fB[^[:space:]]\fR .TP \fB\eW\fR \fB[^[:alnum:]_]\fR (note underscore) .RE .PP Within bracket expressions, `\fB\ed\fR', `\fB\es\fR', and `\fB\ew\fR'\& lose their outer brackets, and `\fB\eD\fR', `\fB\eS\fR', and `\fB\eW\fR'\& are illegal. .VS 8.2 (So, for example, \fB[a-c\ed]\fR is equivalent to \fB[a-c[:digit:]]\fR. Also, \fB[a-c\eD]\fR, which is equivalent to \fB[a-c^[:digit:]]\fR, is illegal.) .VE 8.2 .PP A constraint escape (AREs only) is a constraint, matching the empty string if specific conditions are met, written as an escape: .RS 2 .TP 6 \fB\eA\fR matches only at the beginning of the string (see MATCHING, below, for how this differs from `\fB^\fR') .TP \fB\em\fR matches only at the beginning of a word .TP \fB\eM\fR matches only at the end of a word .TP \fB\ey\fR matches only at the beginning or end of a word .TP \fB\eY\fR matches only at a point that is not the beginning or end of a word .TP \fB\eZ\fR matches only at the end of the string (see MATCHING, below, for how this differs from `\fB$\fR') .TP \fB\e\fIm\fR (where \fIm\fR is a nonzero digit) a \fIback reference\fR, see below .TP \fB\e\fImnn\fR (where \fIm\fR is a nonzero digit, and \fInn\fR is some more digits, and the decimal value \fImnn\fR is not greater than the number of closing capturing parentheses seen so far) a \fIback reference\fR, see below .RE .PP A word is defined as in the specification of \fB[[:<:]]\fR and \fB[[:>:]]\fR above. Constraint escapes are illegal within bracket expressions. .PP A back reference (AREs only) matches the same string matched by the parenthesized subexpression specified by the number, so that (e.g.) \fB([bc])\e1\fR matches \fBbb\fR or \fBcc\fR but not `\fBbc\fR'. The subexpression must entirely precede the back reference in the RE. Subexpressions are numbered in the order of their leading parentheses. Non-capturing parentheses do not define subexpressions. .PP There is an inherent historical ambiguity between octal character-entry escapes and back references, which is resolved by heuristics, as hinted at above. A leading zero always indicates an octal escape. A single non-zero digit, not followed by another digit, is always taken as a back reference. A multi-digit sequence not starting with a zero is taken as a back reference if it comes after a suitable subexpression (i.e. the number is in the legal range for a back reference), and otherwise is taken as octal. .SH "METASYNTAX" In addition to the main syntax described above, there are some special forms and miscellaneous syntactic facilities available. .PP Normally the flavor of RE being used is specified by application-dependent means. However, this can be overridden by a \fIdirector\fR. If an RE of any flavor begins with `\fB***:\fR', the rest of the RE is an ARE. If an RE of any flavor begins with `\fB***=\fR', the rest of the RE is taken to be a literal string, with all characters considered ordinary characters. .PP An ARE may begin with \fIembedded options\fR: a sequence \fB(?\fIxyz\fB)\fR (where \fIxyz\fR is one or more alphabetic characters) specifies options affecting the rest of the RE. These supplement, and can override, any options specified by the application. The available option letters are: .RS 2 .TP 3 \fBb\fR rest of RE is a BRE .TP 3 \fBc\fR case-sensitive matching (usual default) .TP 3 \fBe\fR rest of RE is an ERE .TP 3 \fBi\fR case-insensitive matching (see MATCHING, below) .TP 3 \fBm\fR historical synonym for \fBn\fR .TP 3 \fBn\fR newline-sensitive matching (see MATCHING, below) .TP 3 \fBp\fR partial newline-sensitive matching (see MATCHING, below) .TP 3 \fBq\fR rest of RE is a literal (``quoted'') string, all ordinary characters .TP 3 \fBs\fR non-newline-sensitive matching (usual default) .TP 3 \fBt\fR tight syntax (usual default; see below) .TP 3 \fBw\fR inverse partial newline-sensitive (``weird'') matching (see MATCHING, below) .TP 3 \fBx\fR expanded syntax (see below) .RE .PP Embedded options take effect at the \fB)\fR terminating the sequence. They are available only at the start of an ARE, and may not be used later within it. .PP In addition to the usual (\fItight\fR) RE syntax, in which all characters are significant, there is an \fIexpanded\fR syntax, available in all flavors of RE with the \fB-expanded\fR switch, or in AREs with the embedded x option. In the expanded syntax, white-space characters are ignored and all characters between a \fB#\fR and the following newline (or the end of the RE) are ignored, permitting paragraphing and commenting a complex RE. There are three exceptions to that basic rule: .RS 2 .PP a white-space character or `\fB#\fR' preceded by `\fB\e\fR' is retained .PP white space or `\fB#\fR' within a bracket expression is retained .PP white space and comments are illegal within multi-character symbols like the ARE `\fB(?:\fR' or the BRE `\fB\e(\fR' .RE .PP Expanded-syntax white-space characters are blank, tab, newline, and .VS 8.2 any character that belongs to the \fIspace\fR character class. .VE 8.2 .PP Finally, in an ARE, outside bracket expressions, the sequence `\fB(?#\fIttt\fB)\fR' (where \fIttt\fR is any text not containing a `\fB)\fR') is a comment, completely ignored. Again, this is not allowed between the characters of multi-character symbols like `\fB(?:\fR'. Such comments are more a historical artifact than a useful facility, and their use is deprecated; use the expanded syntax instead. .PP \fINone\fR of these metasyntax extensions is available if the application (or an initial \fB***=\fR director) has specified that the user's input be treated as a literal string rather than as an RE. .SH MATCHING In the event that an RE could match more than one substring of a given string, the RE matches the one starting earliest in the string. If the RE could match more than one substring starting at that point, its choice is determined by its \fIpreference\fR: either the longest substring, or the shortest. .PP Most atoms, and all constraints, have no preference. A parenthesized RE has the same preference (possibly none) as the RE. A quantified atom with quantifier \fB{\fIm\fB}\fR or \fB{\fIm\fB}?\fR has the same preference (possibly none) as the atom itself. A quantified atom with other normal quantifiers (including \fB{\fIm\fB,\fIn\fB}\fR with \fIm\fR equal to \fIn\fR) prefers longest match. A quantified atom with other non-greedy quantifiers (including \fB{\fIm\fB,\fIn\fB}?\fR with \fIm\fR equal to \fIn\fR) prefers shortest match. A branch has the same preference as the first quantified atom in it which has a preference. An RE consisting of two or more branches connected by the \fB|\fR operator prefers longest match. .PP Subject to the constraints imposed by the rules for matching the whole RE, subexpressions also match the longest or shortest possible substrings, based on their preferences, with subexpressions starting earlier in the RE taking priority over ones starting later. Note that outer subexpressions thus take priority over their component subexpressions. .PP Note that the quantifiers \fB{1,1}\fR and \fB{1,1}?\fR can be used to force longest and shortest preference, respectively, on a subexpression or a whole RE. .PP Match lengths are measured in characters, not collating elements. An empty string is considered longer than no match at all. For example, \fBbb*\fR matches the three middle characters of `\fBabbbc\fR', \fB(week|wee)(night|knights)\fR matches all ten characters of `\fBweeknights\fR', when \fB(.*).*\fR is matched against \fBabc\fR the parenthesized subexpression matches all three characters, and when \fB(a*)*\fR is matched against \fBbc\fR both the whole RE and the parenthesized subexpression match an empty string. .PP If case-independent matching is specified, the effect is much as if all case distinctions had vanished from the alphabet. When an alphabetic that exists in multiple cases appears as an ordinary character outside a bracket expression, it is effectively transformed into a bracket expression containing both cases, so that \fBx\fR becomes `\fB[xX]\fR'. When it appears inside a bracket expression, all case counterparts of it are added to the bracket expression, so that \fB[x]\fR becomes \fB[xX]\fR and \fB[^x]\fR becomes `\fB[^xX]\fR'. .PP If newline-sensitive matching is specified, \fB.\fR and bracket expressions using \fB^\fR will never match the newline character (so that matches will never cross newlines unless the RE explicitly arranges it) and \fB^\fR and \fB$\fR will match the empty string after and before a newline respectively, in addition to matching at beginning and end of string respectively. ARE \fB\eA\fR and \fB\eZ\fR continue to match beginning or end of string \fIonly\fR. .PP If partial newline-sensitive matching is specified, this affects \fB.\fR and bracket expressions as with newline-sensitive matching, but not \fB^\fR and `\fB$\fR'. .PP If inverse partial newline-sensitive matching is specified, this affects \fB^\fR and \fB$\fR as with newline-sensitive matching, but not \fB.\fR and bracket expressions. This isn't very useful but is provided for symmetry. .SH "LIMITS AND COMPATIBILITY" No particular limit is imposed on the length of REs. Programs intended to be highly portable should not employ REs longer than 256 bytes, as a POSIX-compliant implementation can refuse to accept such REs. .PP The only feature of AREs that is actually incompatible with POSIX EREs is that \fB\e\fR does not lose its special significance inside bracket expressions. All other ARE features use syntax which is illegal or has undefined or unspecified effects in POSIX EREs; the \fB***\fR syntax of directors likewise is outside the POSIX syntax for both BREs and EREs. .PP Many of the ARE extensions are borrowed from Perl, but some have been changed to clean them up, and a few Perl extensions are not present. Incompatibilities of note include `\fB\eb\fR', `\fB\eB\fR', the lack of special treatment for a trailing newline, the addition of complemented bracket expressions to the things affected by newline-sensitive matching, the restrictions on parentheses and back references in lookahead constraints, and the longest/shortest-match (rather than first-match) matching semantics. .PP The matching rules for REs containing both normal and non-greedy quantifiers have changed since early beta-test versions of this package. (The new rules are much simpler and cleaner, but don't work as hard at guessing the user's real intentions.) .PP Henry Spencer's original 1986 \fIregexp\fR package, still in widespread use (e.g., in pre-8.1 releases of Tcl), implemented an early version of today's EREs. There are four incompatibilities between \fIregexp\fR's near-EREs (`RREs' for short) and AREs. In roughly increasing order of significance: .PP .RS In AREs, \fB\e\fR followed by an alphanumeric character is either an escape or an error, while in RREs, it was just another way of writing the alphanumeric. This should not be a problem because there was no reason to write such a sequence in RREs. .PP \fB{\fR followed by a digit in an ARE is the beginning of a bound, while in RREs, \fB{\fR was always an ordinary character. Such sequences should be rare, and will often result in an error because following characters will not look like a valid bound. .PP In AREs, \fB\e\fR remains a special character within `\fB[\|]\fR', so a literal \fB\e\fR within \fB[\|]\fR must be written `\fB\e\e\fR'. \fB\e\e\fR also gives a literal \fB\e\fR within \fB[\|]\fR in RREs, but only truly paranoid programmers routinely doubled the backslash. .PP AREs report the longest/shortest match for the RE, rather than the first found in a specified search order. This may affect some RREs which were written in the expectation that the first match would be reported. (The careful crafting of RREs to optimize the search order for fast matching is obsolete (AREs examine all possible matches in parallel, and their performance is largely insensitive to their complexity) but cases where the search order was exploited to deliberately find a match which was \fInot\fR the longest/shortest will need rewriting.) .RE .SH "BASIC REGULAR EXPRESSIONS" BREs differ from EREs in several respects. `\fB|\fR', `\fB+\fR', and \fB?\fR are ordinary characters and there is no equivalent for their functionality. The delimiters for bounds are \fB\e{\fR and `\fB\e}\fR', with \fB{\fR and \fB}\fR by themselves ordinary characters. The parentheses for nested subexpressions are \fB\e(\fR and `\fB\e)\fR', with \fB(\fR and \fB)\fR by themselves ordinary characters. \fB^\fR is an ordinary character except at the beginning of the RE or the beginning of a parenthesized subexpression, \fB$\fR is an ordinary character except at the end of the RE or the end of a parenthesized subexpression, and \fB*\fR is an ordinary character if it appears at the beginning of the RE or the beginning of a parenthesized subexpression (after a possible leading `\fB^\fR'). Finally, single-digit back references are available, and \fB\e<\fR and \fB\e>\fR are synonyms for \fB[[:<:]]\fR and \fB[[:>:]]\fR respectively; no other escapes are available. .SH "SEE ALSO" RegExp(3), regexp(n), regsub(n), lsearch(n), switch(n), text(n) .SH KEYWORDS match, regular expression, string tcl8.4.20/doc/Preserve.30000644003604700454610000001067511737050674013354 0ustar dgp771div'\" '\" Copyright (c) 1990 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_Preserve 3 7.5 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_Preserve, Tcl_Release, Tcl_EventuallyFree \- avoid freeing storage while it's being used .SH SYNOPSIS .nf \fB#include \fR .sp \fBTcl_Preserve\fR(\fIclientData\fR) .sp \fBTcl_Release\fR(\fIclientData\fR) .sp \fBTcl_EventuallyFree\fR(\fIclientData, freeProc\fR) .SH ARGUMENTS .AS Tcl_FreeProc clientData .AP ClientData clientData in Token describing structure to be freed or reallocated. Usually a pointer to memory for structure. .AP Tcl_FreeProc *freeProc in Procedure to invoke to free \fIclientData\fR. .BE .SH DESCRIPTION .PP These three procedures help implement a simple reference count mechanism for managing storage. They are designed to solve a problem having to do with widget deletion, but are also useful in many other situations. When a widget is deleted, its widget record (the structure holding information specific to the widget) must be returned to the storage allocator. However, it's possible that the widget record is in active use by one of the procedures on the stack at the time of the deletion. This can happen, for example, if the command associated with a button widget causes the button to be destroyed: an X event causes an event-handling C procedure in the button to be invoked, which in turn causes the button's associated Tcl command to be executed, which in turn causes the button to be deleted, which in turn causes the button's widget record to be de-allocated. Unfortunately, when the Tcl command returns, the button's event-handling procedure will need to reference the button's widget record. Because of this, the widget record must not be freed as part of the deletion, but must be retained until the event-handling procedure has finished with it. In other situations where the widget is deleted, it may be possible to free the widget record immediately. .PP \fBTcl_Preserve\fR and \fBTcl_Release\fR implement short-term reference counts for their \fIclientData\fR argument. The \fIclientData\fR argument identifies an object and usually consists of the address of a structure. The reference counts guarantee that an object will not be freed until each call to \fBTcl_Preserve\fR for the object has been matched by calls to \fBTcl_Release\fR. There may be any number of unmatched \fBTcl_Preserve\fR calls in effect at once. .PP \fBTcl_EventuallyFree\fR is invoked to free up its \fIclientData\fR argument. It checks to see if there are unmatched \fBTcl_Preserve\fR calls for the object. If not, then \fBTcl_EventuallyFree\fR calls \fIfreeProc\fR immediately. Otherwise \fBTcl_EventuallyFree\fR records the fact that \fIclientData\fR needs eventually to be freed. When all calls to \fBTcl_Preserve\fR have been matched with calls to \fBTcl_Release\fR then \fIfreeProc\fR will be called by \fBTcl_Release\fR to do the cleanup. .PP All the work of freeing the object is carried out by \fIfreeProc\fR. \fIFreeProc\fR must have arguments and result that match the type \fBTcl_FreeProc\fR: .CS typedef void Tcl_FreeProc(char *\fIblockPtr\fR); .CE The \fIblockPtr\fR argument to \fIfreeProc\fR will be the same as the \fIclientData\fR argument to \fBTcl_EventuallyFree\fR. The type of \fIblockPtr\fR (\fBchar *\fR) is different than the type of the \fIclientData\fR argument to \fBTcl_EventuallyFree\fR for historical reasons, but the value is the same. .PP When the \fIclientData\fR argument to \fBTcl_EventuallyFree\fR refers to storage allocated and returned by a prior call to \fBTcl_Alloc\fR, \fBckalloc\fR, or another function of the Tcl library, then the \fIfreeProc\fR argument should be given the special value of \fBTCL_DYNAMIC\fR. .PP This mechanism can be used to solve the problem described above by placing \fBTcl_Preserve\fR and \fBTcl_Release\fR calls around actions that may cause undesired storage re-allocation. The mechanism is intended only for short-term use (i.e. while procedures are pending on the stack); it will not work efficiently as a mechanism for long-term reference counts. The implementation does not depend in any way on the internal structure of the objects being freed; it keeps the reference counts in a separate structure. .SH "SEE ALSO" Tcl_Interp, Tcl_Alloc .SH KEYWORDS free, reference count, storage tcl8.4.20/doc/pwd.n0000644003604700454610000000221611737050674012436 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH pwd n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME pwd \- Return the absolute path of the current working directory .SH SYNOPSIS \fBpwd\fR .BE .SH DESCRIPTION .PP Returns the absolute path name of the current working directory. .SH EXAMPLE Sometimes it is useful to change to a known directory when running some external command using \fBexec\fR, but it is important to keep the application usually running in the directory that it was started in (unless the user specifies otherwise) since that minimises user confusion. The way to do this is to save the current directory while the external command is being run: .CS set tarFile [file normalize somefile.tar] set savedDir [\fBpwd\fR] cd /tmp exec tar -xf $tarFile cd $savedDir .CE .SH "SEE ALSO" file(n), cd(n), glob(n), filename(n) .SH KEYWORDS working directory tcl8.4.20/doc/array.n0000644003604700454610000001654011737050674012767 0ustar dgp771div'\" '\" Copyright (c) 1993-1994 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH array n 8.3 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME array \- Manipulate array variables .SH SYNOPSIS \fBarray \fIoption arrayName\fR ?\fIarg arg ...\fR? .BE .SH DESCRIPTION .PP This command performs one of several operations on the variable given by \fIarrayName\fR. Unless otherwise specified for individual commands below, \fIarrayName\fR must be the name of an existing array variable. The \fIoption\fR argument determines what action is carried out by the command. The legal \fIoptions\fR (which may be abbreviated) are: .TP \fBarray anymore \fIarrayName searchId\fR Returns 1 if there are any more elements left to be processed in an array search, 0 if all elements have already been returned. \fISearchId\fR indicates which search on \fIarrayName\fR to check, and must have been the return value from a previous invocation of \fBarray startsearch\fR. This option is particularly useful if an array has an element with an empty name, since the return value from \fBarray nextelement\fR won't indicate whether the search has been completed. .TP \fBarray donesearch \fIarrayName searchId\fR This command terminates an array search and destroys all the state associated with that search. \fISearchId\fR indicates which search on \fIarrayName\fR to destroy, and must have been the return value from a previous invocation of \fBarray startsearch\fR. Returns an empty string. .TP \fBarray exists \fIarrayName\fR Returns 1 if \fIarrayName\fR is an array variable, 0 if there is no variable by that name or if it is a scalar variable. .TP \fBarray get \fIarrayName\fR ?\fIpattern\fR? Returns a list containing pairs of elements. The first element in each pair is the name of an element in \fIarrayName\fR and the second element of each pair is the value of the array element. The order of the pairs is undefined. If \fIpattern\fR is not specified, then all of the elements of the array are included in the result. If \fIpattern\fR is specified, then only those elements whose names match \fIpattern\fR (using the matching rules of \fBstring match\fR) are included. If \fIarrayName\fR isn't the name of an array variable, or if the array contains no elements, then an empty list is returned. .TP \fBarray names \fIarrayName\fR ?\fImode\fR? ?\fIpattern\fR? Returns a list containing the names of all of the elements in the array that match \fIpattern\fR. \fIMode\fR may be one of \fB-exact\fR, \fB-glob\fR, or \fB-regexp\fR. If specified, \fImode\fR designates which matching rules to use to match \fIpattern\fR against the names of the elements in the array. If not specified, \fImode\fR defaults to \fB-glob\fR. See the documentation for \fBstring match\fR for information on glob style matching, and the documentation for \fBregexp\fR for information on regexp matching. If \fIpattern\fR is omitted then the command returns all of the element names in the array. If there are no (matching) elements in the array, or if \fIarrayName\fR isn't the name of an array variable, then an empty string is returned. .TP \fBarray nextelement \fIarrayName searchId\fR Returns the name of the next element in \fIarrayName\fR, or an empty string if all elements of \fIarrayName\fR have already been returned in this search. The \fIsearchId\fR argument identifies the search, and must have been the return value of an \fBarray startsearch\fR command. Warning: if elements are added to or deleted from the array, then all searches are automatically terminated just as if \fBarray donesearch\fR had been invoked; this will cause \fBarray nextelement\fR operations to fail for those searches. .TP \fBarray set \fIarrayName list\fR Sets the values of one or more elements in \fIarrayName\fR. \fIlist\fR must have a form like that returned by \fBarray get\fR, consisting of an even number of elements. Each odd-numbered element in \fIlist\fR is treated as an element name within \fIarrayName\fR, and the following element in \fIlist\fR is used as a new value for that array element. If the variable \fIarrayName\fR does not already exist and \fIlist\fR is empty, \fIarrayName\fR is created with an empty array value. .TP \fBarray size \fIarrayName\fR Returns a decimal string giving the number of elements in the array. If \fIarrayName\fR isn't the name of an array then 0 is returned. .TP \fBarray startsearch \fIarrayName\fR This command initializes an element-by-element search through the array given by \fIarrayName\fR, such that invocations of the \fBarray nextelement\fR command will return the names of the individual elements in the array. When the search has been completed, the \fBarray donesearch\fR command should be invoked. The return value is a search identifier that must be used in \fBarray nextelement\fR and \fBarray donesearch\fR commands; it allows multiple searches to be underway simultaneously for the same array. It is currently more efficient and easier to use either the \fBarray get\fR or \fBarray names\fR, together with \fBforeach\fR, to iterate over all but very large arrays. See the examples below for how to do this. .VS 8.4 .TP \fBarray statistics \fIarrayName\fR Returns statistics about the distribution of data within the hashtable that represents the array. This information includes the number of entries in the table, the number of buckets, and the utilization of the buckets. .VE 8.4 .VS 8.3 .TP \fBarray unset \fIarrayName\fR ?\fIpattern\fR? Unsets all of the elements in the array that match \fIpattern\fR (using the matching rules of \fBstring match\fR). If \fIarrayName\fR isn't the name of an array variable or there are no matching elements in the array, no error will be raised. If \fIpattern\fR is omitted and \fIarrayName\fR is an array variable, then the command unsets the entire array. The command always returns an empty string. .VE 8.3 .SH EXAMPLES .CS \fBarray set\fR colorcount { red 1 green 5 blue 4 white 9 } foreach {color count} [\fBarray get\fR colorcount] { puts "Color: $color Count: $count" } => Color: blue Count: 4 Color: white Count: 9 Color: green Count: 5 Color: red Count: 1 foreach color [\fBarray names\fR colorcount] { puts "Color: $color Count: $colorcount($color)" } => Color: blue Count: 4 Color: white Count: 9 Color: green Count: 5 Color: red Count: 1 foreach color [lsort [array names colorcount]] { puts "Color: $color Count: $colorcount($color)" } => Color: blue Count: 4 Color: green Count: 5 Color: red Count: 1 Color: white Count: 9 \fBarray statistics\fR colorcount => 4 entries in table, 4 buckets number of buckets with 0 entries: 1 number of buckets with 1 entries: 2 number of buckets with 2 entries: 1 number of buckets with 3 entries: 0 number of buckets with 4 entries: 0 number of buckets with 5 entries: 0 number of buckets with 6 entries: 0 number of buckets with 7 entries: 0 number of buckets with 8 entries: 0 number of buckets with 9 entries: 0 number of buckets with 10 or more entries: 0 average search distance for entry: 1.2 .CE .SH "SEE ALSO" list(n), string(n), variable(n), trace(n), foreach(n) .SH KEYWORDS array, element names, search tcl8.4.20/doc/info.n0000644003604700454610000002320211737050674012575 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" Copyright (c) 1993-1997 Bell Labs Innovations for Lucent Technologies '\" Copyright (c) 1998-2000 Ajuba Solutions '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH info n 8.4 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME info \- Return information about the state of the Tcl interpreter .SH SYNOPSIS \fBinfo \fIoption \fR?\fIarg arg ...\fR? .BE .SH DESCRIPTION .PP This command provides information about various internals of the Tcl interpreter. The legal \fIoption\fR's (which may be abbreviated) are: .TP \fBinfo args \fIprocname\fR Returns a list containing the names of the arguments to procedure \fIprocname\fR, in order. \fIProcname\fR must be the name of a Tcl command procedure. .TP \fBinfo body \fIprocname\fR Returns the body of procedure \fIprocname\fR. \fIProcname\fR must be the name of a Tcl command procedure. .TP \fBinfo cmdcount\fR Returns a count of the total number of commands that have been invoked in this interpreter. .TP \fBinfo commands \fR?\fIpattern\fR? If \fIpattern\fR isn't specified, returns a list of names of all the Tcl commands in the current namespace, including both the built-in commands written in C and the command procedures defined using the \fBproc\fR command. If \fIpattern\fR is specified, only those names matching \fIpattern\fR are returned. Matching is determined using the same rules as for \fBstring match\fR. \fIpattern\fR can be a qualified name like \fBFoo::print*\fR. That is, it may specify a particular namespace using a sequence of namespace names separated by double colons (\fB::\fR), and may have pattern matching special characters at the end to specify a set of commands in that namespace. If \fIpattern\fR is a qualified name, the resulting list of command names has each one qualified with the name of the specified namespace. .TP \fBinfo complete \fIcommand\fR Returns 1 if \fIcommand\fR is a complete Tcl command in the sense of having no unclosed quotes, braces, brackets or array element names. If the command doesn't appear to be complete then 0 is returned. This command is typically used in line-oriented input environments to allow users to type in commands that span multiple lines; if the command isn't complete, the script can delay evaluating it until additional lines have been typed to complete the command. .TP \fBinfo default \fIprocname arg varname\fR \fIProcname\fR must be the name of a Tcl command procedure and \fIarg\fR must be the name of an argument to that procedure. If \fIarg\fR doesn't have a default value then the command returns \fB0\fR. Otherwise it returns \fB1\fR and places the default value of \fIarg\fR into variable \fIvarname\fR. .TP \fBinfo exists \fIvarName\fR Returns \fB1\fR if the variable named \fIvarName\fR exists in the current context (either as a global or local variable) and has been defined by being given a value, returns \fB0\fR otherwise. .VS 8.4 .TP \fBinfo functions \fR?\fIpattern\fR? If \fIpattern\fR isn't specified, returns a list of all the math functions currently defined. If \fIpattern\fR is specified, only those functions whose name matches \fIpattern\fR are returned. Matching is determined using the same rules as for \fBstring match\fR. .VE .TP \fBinfo globals \fR?\fIpattern\fR? If \fIpattern\fR isn't specified, returns a list of all the names of currently-defined global variables. Global variables are variables in the global namespace. If \fIpattern\fR is specified, only those names matching \fIpattern\fR are returned. Matching is determined using the same rules as for \fBstring match\fR. .TP \fBinfo hostname\fR Returns the name of the computer on which this invocation is being executed. .VS Note that this name is not guaranteed to be the fully qualified domain name of the host. Where machines have several different names (as is common on systems with both TCP/IP (DNS) and NetBIOS-based networking installed,) it is the name that is suitable for TCP/IP networking that is returned. .VE .TP \fBinfo level\fR ?\fInumber\fR? If \fInumber\fR is not specified, this command returns a number giving the stack level of the invoking procedure, or 0 if the command is invoked at top-level. If \fInumber\fR is specified, then the result is a list consisting of the name and arguments for the procedure call at level \fInumber\fR on the stack. If \fInumber\fR is positive then it selects a particular stack level (1 refers to the top-most active procedure, 2 to the procedure it called, and so on); otherwise it gives a level relative to the current level (0 refers to the current procedure, -1 to its caller, and so on). See the \fBuplevel\fR command for more information on what stack levels mean. .TP \fBinfo library\fR Returns the name of the library directory in which standard Tcl scripts are stored. This is actually the value of the \fBtcl_library\fR variable and may be changed by setting \fBtcl_library\fR. See the \fBtclvars\fR manual entry for more information. .TP \fBinfo loaded \fR?\fIinterp\fR? Returns a list describing all of the packages that have been loaded into \fIinterp\fR with the \fBload\fR command. Each list element is a sub-list with two elements consisting of the name of the file from which the package was loaded and the name of the package. For statically-loaded packages the file name will be an empty string. If \fIinterp\fR is omitted then information is returned for all packages loaded in any interpreter in the process. To get a list of just the packages in the current interpreter, specify an empty string for the \fIinterp\fR argument. .TP \fBinfo locals \fR?\fIpattern\fR? If \fIpattern\fR isn't specified, returns a list of all the names of currently-defined local variables, including arguments to the current procedure, if any. Variables defined with the \fBglobal\fR, \fBupvar\fR and \fBvariable\fR commands will not be returned. If \fIpattern\fR is specified, only those names matching \fIpattern\fR are returned. Matching is determined using the same rules as for \fBstring match\fR. .TP \fBinfo nameofexecutable\fR Returns the full path name of the binary file from which the application was invoked. If Tcl was unable to identify the file, then an empty string is returned. .TP \fBinfo patchlevel\fR Returns the value of the global variable \fBtcl_patchLevel\fR; see the \fBtclvars\fR manual entry for more information. .TP \fBinfo procs \fR?\fIpattern\fR? If \fIpattern\fR isn't specified, returns a list of all the names of Tcl command procedures in the current namespace. If \fIpattern\fR is specified, only those procedure names in the current namespace matching \fIpattern\fR are returned. Matching is determined using the same rules as for \fBstring match\fR. If \fIpattern\fR contains any namespace separators, they are used to select a namespace relative to the current namespace (or relative to the global namespace if \fIpattern\fR starts with \fB::\fR) to match within; the matching pattern is taken to be the part after the last namespace separator. .TP \fBinfo script\fR ?\fIfilename\fR? If a Tcl script file is currently being evaluated (i.e. there is a call to \fBTcl_EvalFile\fR active or there is an active invocation of the \fBsource\fR command), then this command returns the name of the innermost file being processed. If \fIfilename\fR is specified, then the return value of this command will be modified for the duration of the active invocation to return that name. This is useful in virtual file system applications. Otherwise the command returns an empty string. .TP \fBinfo sharedlibextension\fR Returns the extension used on this platform for the names of files containing shared libraries (for example, \fB.so\fR under Solaris). If shared libraries aren't supported on this platform then an empty string is returned. .TP \fBinfo tclversion\fR Returns the value of the global variable \fBtcl_version\fR; see the \fBtclvars\fR manual entry for more information. .TP \fBinfo vars\fR ?\fIpattern\fR? If \fIpattern\fR isn't specified, returns a list of all the names of currently-visible variables. This includes locals and currently-visible globals. If \fIpattern\fR is specified, only those names matching \fIpattern\fR are returned. Matching is determined using the same rules as for \fBstring match\fR. \fIpattern\fR can be a qualified name like \fBFoo::option*\fR. That is, it may specify a particular namespace using a sequence of namespace names separated by double colons (\fB::\fR), and may have pattern matching special characters at the end to specify a set of variables in that namespace. If \fIpattern\fR is a qualified name, the resulting list of variable names has each matching namespace variable qualified with the name of its namespace. Note that a currently-visible variable may not yet "exist" if it has not been set (e.g. a variable declared but not set by \fBvariable\fR). .SH EXAMPLE This command prints out a procedure suitable for saving in a Tcl script: .CS proc printProc {procName} { set result [list proc $procName] set formals {} foreach var [\fBinfo args\fR $procName] { if {[\fBinfo default\fR $procName $var def]} { lappend formals [list $var $def] } else { # Still need the list-quoting because variable # names may properly contain spaces. lappend formals [list $var] } } puts [lappend result $formals [\fBinfo body\fR $procName]] } .CE .SH "SEE ALSO" global(n), proc(n) .SH KEYWORDS command, information, interpreter, level, namespace, procedure, variable '\" Local Variables: '\" mode: nroff '\" End: tcl8.4.20/doc/CrtTimerHdlr.30000644003604700454610000000534411737050674014121 0ustar dgp771div'\" '\" Copyright (c) 1990 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_CreateTimerHandler 3 7.5 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_CreateTimerHandler, Tcl_DeleteTimerHandler \- call a procedure at a given time .SH SYNOPSIS .nf \fB#include \fR .sp Tcl_TimerToken \fBTcl_CreateTimerHandler\fR(\fImilliseconds, proc, clientData\fR) .sp \fBTcl_DeleteTimerHandler\fR(\fItoken\fR) .SH ARGUMENTS .AS Tcl_TimerToken milliseconds .AP int milliseconds in How many milliseconds to wait before invoking \fIproc\fR. .AP Tcl_TimerProc *proc in Procedure to invoke after \fImilliseconds\fR have elapsed. .AP ClientData clientData in Arbitrary one-word value to pass to \fIproc\fR. .AP Tcl_TimerToken token in Token for previously-created timer handler (the return value from some previous call to \fBTcl_CreateTimerHandler\fR). .BE .SH DESCRIPTION .PP \fBTcl_CreateTimerHandler\fR arranges for \fIproc\fR to be invoked at a time \fImilliseconds\fR milliseconds in the future. The callback to \fIproc\fR will be made by \fBTcl_DoOneEvent\fR, so \fBTcl_CreateTimerHandler\fR is only useful in programs that dispatch events through \fBTcl_DoOneEvent\fR or through Tcl commands such as \fBvwait\fR. The call to \fIproc\fR may not be made at the exact time given by \fImilliseconds\fR: it will be made at the next opportunity after that time. For example, if \fBTcl_DoOneEvent\fR isn't called until long after the time has elapsed, or if there are other pending events to process before the call to \fIproc\fR, then the call to \fIproc\fR will be delayed. .PP \fIProc\fR should have arguments and return value that match the type \fBTcl_TimerProc\fR: .CS typedef void Tcl_TimerProc(ClientData \fIclientData\fR); .CE The \fIclientData\fR parameter to \fIproc\fR is a copy of the \fIclientData\fR argument given to \fBTcl_CreateTimerHandler\fR when the callback was created. Typically, \fIclientData\fR points to a data structure containing application-specific information about what to do in \fIproc\fR. .PP \fBTcl_DeleteTimerHandler\fR may be called to delete a previously-created timer handler. It deletes the handler indicated by \fItoken\fR so that no call to \fIproc\fR will be made; if that handler no longer exists (e.g. because the time period has already elapsed and \fIproc\fR has been invoked then \fBTcl_DeleteTimerHandler\fR does nothing. The tokens returned by \fBTcl_CreateTimerHandler\fR never have a value of NULL, so if NULL is passed to \fBTcl_DeleteTimerHandler\fR then the procedure does nothing. .SH KEYWORDS callback, clock, handler, timer tcl8.4.20/doc/history.n0000644003604700454610000001013611737050674013345 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH history n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME history \- Manipulate the history list .SH SYNOPSIS \fBhistory \fR?\fIoption\fR? ?\fIarg arg ...\fR? .BE .SH DESCRIPTION .PP The \fBhistory\fR command performs one of several operations related to recently-executed commands recorded in a history list. Each of these recorded commands is referred to as an ``event''. When specifying an event to the \fBhistory\fR command, the following forms may be used: .IP [1] A number: if positive, it refers to the event with that number (all events are numbered starting at 1). If the number is negative, it selects an event relative to the current event (\fB\-1\fR refers to the previous event, \fB\-2\fR to the one before that, and so on). Event \fB0\fP refers to the current event. .IP [2] A string: selects the most recent event that matches the string. An event is considered to match the string either if the string is the same as the first characters of the event, or if the string matches the event in the sense of the \fBstring match\fR command. .PP The \fBhistory\fR command can take any of the following forms: .TP \fBhistory\fR Same as \fBhistory info\fR, described below. .TP \fBhistory add\fI command \fR?\fBexec\fR? Adds the \fIcommand\fR argument to the history list as a new event. If \fBexec\fR is specified (or abbreviated) then the command is also executed and its result is returned. If \fBexec\fR isn't specified then an empty string is returned as result. .TP \fBhistory change\fI newValue\fR ?\fIevent\fR? Replaces the value recorded for an event with \fInewValue\fR. \fIEvent\fR specifies the event to replace, and defaults to the \fIcurrent\fR event (not event \fB\-1\fR). This command is intended for use in commands that implement new forms of history substitution and wish to replace the current event (which invokes the substitution) with the command created through substitution. The return value is an empty string. .TP \fBhistory clear\fR Erase the history list. The current keep limit is retained. The history event numbers are reset. .TP \fBhistory event\fR ?\fIevent\fR? Returns the value of the event given by \fIevent\fR. \fIEvent\fR defaults to \fB\-1\fR. .TP \fBhistory info \fR?\fIcount\fR? Returns a formatted string (intended for humans to read) giving the event number and contents for each of the events in the history list except the current event. If \fIcount\fR is specified then only the most recent \fIcount\fR events are returned. .TP \fBhistory keep \fR?\fIcount\fR? This command may be used to change the size of the history list to \fIcount\fR events. Initially, 20 events are retained in the history list. If \fIcount\fR is not specified, the current keep limit is returned. .TP \fBhistory nextid\fR Returns the number of the next event to be recorded in the history list. It is useful for things like printing the event number in command-line prompts. .TP \fBhistory redo \fR?\fIevent\fR? Re-executes the command indicated by \fIevent\fR and returns its result. \fIEvent\fR defaults to \fB\-1\fR. This command results in history revision: see below for details. .SH "HISTORY REVISION" .PP Pre-8.0 Tcl had a complex history revision mechanism. The current mechanism is more limited, and the old history operations \fBsubstitute\fP and \fBwords\fP have been removed. (As a consolation, the \fBclear\fP operation was added.) .PP The history option \fBredo\fR results in much simpler ``history revision''. When this option is invoked then the most recent event is modified to eliminate the history command and replace it with the result of the history command. If you want to redo an event without modifying history, then use the \fBevent\fP operation to retrieve some event, and the \fBadd\fP operation to add it to history and execute it. .SH KEYWORDS event, history, record tcl8.4.20/doc/subst.n0000644003604700454610000001075611737050674013014 0ustar dgp771div'\" '\" Copyright (c) 1994 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" Copyright (c) 2001 Donal K. Fellows '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH subst n 7.4 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME subst \- Perform backslash, command, and variable substitutions .SH SYNOPSIS \fBsubst \fR?\fB\-nobackslashes\fR? ?\fB\-nocommands\fR? ?\fB\-novariables\fR? \fIstring\fR .BE .SH DESCRIPTION .PP This command performs variable substitutions, command substitutions, and backslash substitutions on its \fIstring\fR argument and returns the fully-substituted result. The substitutions are performed in exactly the same way as for Tcl commands. As a result, the \fIstring\fR argument is actually substituted twice, once by the Tcl parser in the usual fashion for Tcl commands, and again by the \fIsubst\fR command. .PP If any of the \fB\-nobackslashes\fR, \fB\-nocommands\fR, or \fB\-novariables\fR are specified, then the corresponding substitutions are not performed. For example, if \fB\-nocommands\fR is specified, command substitution is not performed: open and close brackets are treated as ordinary characters with no special interpretation. .PP .VS 8.4 Note that the substitution of one kind can include substitution of other kinds. For example, even when the \fB-novariables\fR option is specified, command substitution is performed without restriction. This means that any variable substitution necessary to complete the command substitution will still take place. Likewise, any command substitution necessary to complete a variable substitution will take place, even when \fB-nocommands\fR is specified. See the EXAMPLES below. .PP If an error occurs during substitution, then \fBsubst\fR will return that error. If a break exception occurs during command or variable substitution, the result of the whole substitution will be the string (as substituted) up to the start of the substitution that raised the exception. If a continue exception occurs during the evaluation of a command or variable substitution, an empty string will be substituted for that entire command or variable substitution (as long as it is well-formed Tcl.) If a return exception occurs, or any other return code is returned during command or variable substitution, then the returned value is substituted for that substitution. See the EXAMPLES below. In this way, all exceptional return codes are ``caught'' by \fBsubst\fR. The \fBsubst\fR command itself will either return an error, or will complete successfully. .VE .SH EXAMPLES .PP When it performs its substitutions, \fIsubst\fR does not give any special treatment to double quotes or curly braces (except within command substitutions) so the script .CS set a 44 \fBsubst\fR {xyz {$a}} .CE returns ``\fBxyz {44}\fR'', not ``\fBxyz {$a}\fR'' .VS 8.4 and the script .CS set a "p\\} q \\{r" \fBsubst\fR {xyz {$a}} .CE return ``\fBxyz {p} q {r}\fR'', not ``\fBxyz {p\\} q \\{r}\fR''. .PP When command substitution is performed, it includes any variable substitution necessary to evaluate the script. .CS set a 44 \fBsubst\fR -novariables {$a [format $a]} .CE returns ``\fB$a 44\fR'', not ``\fB$a $a\fR''. Similarly, when variable substitution is performed, it includes any command substitution necessary to retrieve the value of the variable. .CS proc b {} {return c} array set a {c c [b] tricky} \fBsubst\fR -nocommands {[b] $a([b])} .CE returns ``\fB[b] c\fR'', not ``\fB[b] tricky\fR''. .PP The continue and break exceptions allow command substitutions to prevent substitution of the rest of the command substitution and the rest of \fIstring\fR respectively, giving script authors more options when processing text using \fIsubst\fR. For example, the script .CS \fBsubst\fR {abc,[break],def} .CE returns ``\fBabc,\fR'', not ``\fBabc,,def\fR'' and the script .CS \fBsubst\fR {abc,[continue;expr 1+2],def} .CE returns ``\fBabc,,def\fR'', not ``\fBabc,3,def\fR''. .PP Other exceptional return codes substitute the returned value .CS \fBsubst\fR {abc,[return foo;expr 1+2],def} .CE returns ``\fBabc,foo,def\fR'', not ``\fBabc,3,def\fR'' and .CS \fBsubst\fR {abc,[return -code 10 foo;expr 1+2],def} .CE also returns ``\fBabc,foo,def\fR'', not ``\fBabc,3,def\fR''. .VE .SH "SEE ALSO" Tcl(n), eval(n), break(n), continue(n) .SH KEYWORDS backslash substitution, command substitution, variable substitution tcl8.4.20/doc/DoubleObj.30000644003604700454610000000542611737050674013424 0ustar dgp771div'\" '\" Copyright (c) 1996-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_DoubleObj 3 8.0 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_NewDoubleObj, Tcl_SetDoubleObj, Tcl_GetDoubleFromObj \- manipulate Tcl objects as floating-point values .SH SYNOPSIS .nf \fB#include \fR .sp Tcl_Obj * \fBTcl_NewDoubleObj\fR(\fIdoubleValue\fR) .sp \fBTcl_SetDoubleObj\fR(\fIobjPtr, doubleValue\fR) .sp int \fBTcl_GetDoubleFromObj\fR(\fIinterp, objPtr, doublePtr\fR) .SH ARGUMENTS .AS Tcl_Interp doubleValue in/out .AP double doubleValue in A double-precision floating point value used to initialize or set a double object. .AP Tcl_Obj *objPtr in/out For \fBTcl_SetDoubleObj\fR, this points to the object to be converted to double type. For \fBTcl_GetDoubleFromObj\fR, this refers to the object from which to get a double value; if \fIobjPtr\fR does not already point to a double object, an attempt will be made to convert it to one. .AP Tcl_Interp *interp in/out If an error occurs during conversion, an error message is left in the interpreter's result object unless \fIinterp\fR is NULL. .AP double *doublePtr out Points to place to store the double value obtained from \fIobjPtr\fR. .BE .SH DESCRIPTION .PP These procedures are used to create, modify, and read double Tcl objects from C code. \fBTcl_NewDoubleObj\fR and \fBTcl_SetDoubleObj\fR will create a new object of double type or modify an existing object to have double type. Both of these procedures set the object to have the double-precision floating point value given by \fIdoubleValue\fR; \fBTcl_NewDoubleObj\fR returns a pointer to a newly created object with reference count zero. Both procedures set the object's type to be double and assign the double value to the object's internal representation \fIdoubleValue\fR member. \fBTcl_SetDoubleObj\fR invalidates any old string representation and, if the object is not already a double object, frees any old internal representation. .PP \fBTcl_GetDoubleFromObj\fR attempts to return a double value from the Tcl object \fIobjPtr\fR. If the object is not already a double object, it will attempt to convert it to one. If an error occurs during conversion, it returns \fBTCL_ERROR\fR and leaves an error message in the interpreter's result object unless \fIinterp\fR is NULL. Otherwise, it returns \fBTCL_OK\fR and stores the double value in the address given by \fIdoublePtr\fR. If the object is not already a double object, the conversion will free any old internal representation. .SH "SEE ALSO" Tcl_NewObj, Tcl_DecrRefCount, Tcl_IncrRefCount, Tcl_GetObjResult .SH KEYWORDS double, double object, double type, internal representation, object, object type, string representation tcl8.4.20/doc/FindExec.30000644003604700454610000000363711737050674013246 0ustar dgp771div'\" '\" Copyright (c) 1995-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_FindExecutable 3 8.1 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_FindExecutable, Tcl_GetNameOfExecutable \- identify or return the name of the binary file containing the application .SH SYNOPSIS .nf \fB#include \fR .sp void \fBTcl_FindExecutable\fR(\fIargv0\fR) .sp CONST char * \fBTcl_GetNameOfExecutable\fR() .SH ARGUMENTS .AS char *argv0 in .AP char *argv0 in The first command-line argument to the program, which gives the application's name. .BE .SH DESCRIPTION .PP The \fBTcl_FindExecutable\fR procedure computes the full path name of the executable file from which the application was invoked and saves it for Tcl's internal use. The executable's path name is needed for several purposes in Tcl. For example, it is needed on some platforms in the implementation of the \fBload\fR command. It is also returned by the \fBinfo nameofexecutable\fR command. .PP On UNIX platforms this procedure is typically invoked as the very first thing in the application's main program; it must be passed \fIargv[0]\fR as its argument. It is important not to change the working directory before the invocation. \fBTcl_FindExecutable\fR uses \fIargv0\fR along with the \fBPATH\fR environment variable to find the application's executable, if possible. If it fails to find the binary, then future calls to \fBinfo nameofexecutable\fR will return an empty string. .PP \fBTcl_GetNameOfExecutable\fR simply returns a pointer to the internal full path name of the executable file as computed by \fBTcl_FindExecutable\fR. This procedure call is the C API equivalent to the \fBinfo nameofexecutable\fR command. NULL is returned if the internal full path name has not been computed or unknown. .SH KEYWORDS binary, executable file tcl8.4.20/doc/close.n0000644003604700454610000000552011737050674012752 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH close n 7.5 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME close \- Close an open channel. .SH SYNOPSIS \fBclose \fIchannelId\fR .BE .SH DESCRIPTION .PP Closes the channel given by \fIchannelId\fR. .PP .VS \fIChannelId\fR must be an identifier for an open channel such as a Tcl standard channel (\fBstdin\fR, \fBstdout\fR, or \fBstderr\fR), the return value from an invocation of \fBopen\fR or \fBsocket\fR, or the result of a channel creation command provided by a Tcl extension. .VE .PP All buffered output is flushed to the channel's output device, any buffered input is discarded, the underlying file or device is closed, and \fIchannelId\fR becomes unavailable for use. .VS "" br .PP If the channel is blocking, the command does not return until all output is flushed. If the channel is nonblocking and there is unflushed output, the channel remains open and the command returns immediately; output will be flushed in the background and the channel will be closed when all the flushing is complete. .VE .PP If \fIchannelId\fR is a blocking channel for a command pipeline then \fBclose\fR waits for the child processes to complete. .VS "" br .PP If the channel is shared between interpreters, then \fBclose\fR makes \fIchannelId\fR unavailable in the invoking interpreter but has no other effect until all of the sharing interpreters have closed the channel. When the last interpreter in which the channel is registered invokes \fBclose\fR, the cleanup actions described above occur. See the \fBinterp\fR command for a description of channel sharing. .PP Channels are automatically closed when an interpreter is destroyed and when the process exits. Channels are switched to blocking mode, to ensure that all output is correctly flushed before the process exits. .VE .PP The command returns an empty string, and may generate an error if an error occurs while flushing output. If a command in a command pipeline created with \fBopen\fR returns an error, \fBclose\fR generates an error (similar to the \fBexec\fR command.) .SH EXAMPLE This illustrates how you can use Tcl to ensure that files get closed even when errors happen by combining \fBcatch\fR, \fBclose\fR and \fBreturn\fR: .CS proc withOpenFile {filename channelVar script} { upvar 1 $channelVar chan set chan [open $filename] catch { uplevel 1 $script } result options \fBclose\fR $chan return -options $options $result } .CE .SH "SEE ALSO" file(n), open(n), socket(n), eof(n), Tcl_StandardChannels(3) .SH KEYWORDS blocking, channel, close, nonblocking tcl8.4.20/doc/clock.n0000644003604700454610000002364311737050674012746 0ustar dgp771div'\" '\" Copyright (c) 1992-1995 Karl Lehenbauer and Mark Diekhans. '\" Copyright (c) 1995-1997 Sun Microsystems, Inc. '\" Copyright (c) 1998-1999 Scriptics Corporation '\" Copyright (c) 2002 ActiveState Corporation '\" '\" This documentation is derived from the time and date facilities of '\" TclX, by Mark Diekhans and Karl Lehenbauer. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH clock n 8.4 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME clock \- Obtain and manipulate time .SH SYNOPSIS \fBclock \fIoption\fR ?\fIarg arg ...\fR? .BE .SH DESCRIPTION .PP This command performs one of several operations that may obtain or manipulate strings or values that represent some notion of time. The \fIoption\fR argument determines what action is carried out by the command. The legal \fIoptions\fR (which may be abbreviated) are: .VS 8.3 .TP \fBclock clicks\fR ?\fB\-milliseconds\fR? Return a high-resolution time value as a system-dependent integer value. The unit of the value is system-dependent but should be the highest resolution clock available on the system such as a CPU cycle counter. If \fB\-milliseconds\fR is specified, then the value is guaranteed to be of millisecond granularity. This value should only be used for the relative measurement of elapsed time. .VE 8.3 .TP \fBclock format \fIclockValue\fR ?\fB\-format \fIstring\fR? ?\fB\-gmt \fIboolean\fR? Converts an integer time value, typically returned by \fBclock seconds\fR, \fBclock scan\fR, or the \fBatime\fR or \fBmtime\fR options of the \fBfile\fR command, to human-readable form. If the \fB\-format\fR argument is present the next argument is a string that describes how the date and time are to be formatted. Field descriptors consist of a \fB%\fR followed by a field descriptor character. All other characters are copied into the result. Valid field descriptors are: .RS .IP \fB%%\fR Insert a %. .IP \fB%a\fR Abbreviated weekday name (Mon, Tue, etc.). .IP \fB%A\fR Full weekday name (Monday, Tuesday, etc.). .IP \fB%b\fR Abbreviated month name (Jan, Feb, etc.). .IP \fB%B\fR Full month name. .VS 8.4 .IP \fB%c\fR Locale specific date and time. The format for date and time in the default "C" locale on Unix/Mac is "%a %b %d %H:%M:%S %Y". On Windows, this value is the locale specific long date and time, as specified in the Regional Options control panel settings. .IP \fB%C\fR First two digits of the four-digit year (19 or 20). .VE 8.4 .IP \fB%d\fR Day of month (01 - 31). .VS 8.4 '\" Since the inclusion of compat/strftime.c, %D, %e, %h should work on all '\" platforms. .IP \fB%D\fR Date as %m/%d/%y. .IP \fB%e\fR Day of month (1 - 31), no leading zeros. .IP \fB%g\fR The ISO8601 year number corresponding to the ISO8601 week (%V), expressed as a two-digit year-of-the-century, with leading zero if necessary. .IP \fB%G\fR The ISO8601 year number corresponding to the ISO8601 week (%V), expressed as a four-digit number. .IP \fB%h\fR Abbreviated month name. .VE 8.4 .IP \fB%H\fR Hour in 24-hour format (00 - 23). .VS 8.4 .IP \fB%I\fR Hour in 12-hour format (01 - 12). .VE 8.4 .IP \fB%j\fR Day of year (001 - 366). .VS 8.4 .IP \fB%k\fR Hour in 24-hour format, without leading zeros (0 - 23). .IP \fB%l\fR Hour in 12-hour format, without leading zeros (1 - 12). .VE 8.4 .IP \fB%m\fR Month number (01 - 12). .IP \fB%M\fR Minute (00 - 59). .VS 8.4 .IP \fB%n\fR Insert a newline. .VE 8.4 .IP \fB%p\fR AM/PM indicator. .VS 8.4 .IP \fB%r\fR Time in a locale-specific "meridian" format. The "meridian" format in the default "C" locale is "%I:%M:%S %p". .IP \fB%R\fR Time as %H:%M. .IP \fB%s\fR Count of seconds since the epoch, expressed as a decimal integer. .VE 8.4 .IP \fB%S\fR Seconds (00 - 59). .VS 8.4 .IP \fB%t\fR Insert a tab. .IP \fB%T\fR Time as %H:%M:%S. .IP \fB%u\fR Weekday number (Monday = 1, Sunday = 7). .VE 8.4 .IP \fB%U\fR Week of year (00 - 52), Sunday is the first day of the week. .VS 8.4 .IP \fB%V\fR Week of year according to ISO-8601 rules. Week 1 of a given year is the week containing 4 January. .IP \fB%w\fR Weekday number (Sunday = 0, Saturday = 6). .VE 8.4 .IP \fB%W\fR Week of year (00 - 52), Monday is the first day of the week. .VS 8.4 .IP \fB%x\fR Locale specific date format. The format for a date in the default "C" locale for Unix/Mac is "%m/%d/%y". On Windows, this value is the locale specific short date format, as specified in the Regional Options control panel settings. .IP \fB%X\fR Locale specific 24-hour time format. The format for a 24-hour time in the default "C" locale for Unix/Mac is "%H:%M:%S". On Windows, this value is the locale specific time format, as specified in the Regional Options control panel settings. .VE 8.4 .IP \fB%y\fR Year without century (00 - 99). .IP \fB%Y\fR Year with century (e.g. 1990) .IP \fB%Z\fR Time zone name. .RE .VS 8.4 .sp '\" All the field descriptors should be portable now that '\" compat/strftime.c is in place, with the possible exception '\" of the time zone name. '\".RS '\"In addition, the following field descriptors may be supported on some '\"systems (e.g. Unix but not Windows): '\".IP \fB%D\fR '\"Date as %m/%d/%y. '\".IP \fB%e\fR '\"Day of month (1 - 31), no leading zeros. '\".IP \fB%h\fR '\"Abbreviated month name. '\".IP \fB%n\fR '\"Insert a newline. '\".IP \fB%r\fR '\"Time as %I:%M:%S %p. '\".IP \fB%R\fR '\"Time as %H:%M. '\".IP \fB%t\fR '\"Insert a tab. '\".IP \fB%T\fR '\"Time as %H:%M:%S. '\".RE '\".sp .VE 8.4 .RS If the \fB\-format\fR argument is not specified, the format string \fB"%a %b %d %H:%M:%S %Z %Y"\fR is used. If the \fB\-gmt\fR argument is present the next argument must be a boolean which if true specifies that the time will be formatted as Greenwich Mean Time. If false then the local timezone will be used as defined by the operating environment. .RE .TP \fBclock scan \fIdateString\fR ?\fB\-base \fIclockVal\fR? ?\fB\-gmt \fIboolean\fR? Convert \fIdateString\fR to an integer clock value (see \fBclock seconds\fR). This command can parse and convert virtually any standard date and/or time string, which can include standard time zone mnemonics. If only a time is specified, the current date is assumed. If the string does not contain a time zone mnemonic, the local time zone is assumed, unless the \fB\-gmt\fR argument is true, in which case the clock value is calculated assuming that the specified time is relative to Greenwich Mean Time. \fB-gmt\fR, if specified, affects only the computed time value; it does not impact the interpretation of \fB-base\fR. .sp If the \fB\-base\fR flag is specified, the next argument should contain an integer clock value. Only the date in this value is used, not the time. This is useful for determining the time on a specific day or doing other date-relative conversions. .sp The \fIdateString\fR consists of zero or more specifications of the following form: .RS .TP \fItime\fR A time of day, which is of the form: \fIhh\fR?\fI:mm\fR?\fI:ss\fR?? ?\fImeridian\fR? ?\fIzone\fR? or \fIhhmm \fR?\fImeridian\fR? ?\fIzone\fR?. If no meridian is specified, \fIhh\fR is interpreted on a 24-hour clock. .TP \fIdate\fR A specific month and day with optional year. The acceptable formats are \fImm/dd\fR?\fI/yy\fR?, \fImonthname dd\fR ?, \fIyy\fR?, \fIdd monthname \fR?\fIyy\fR?, \fIday, dd monthname yy\fR, \fI?CC?yymmdd\fR, \fI?CC?yy-mm-dd\fR, \fIdd-monthname-?CC?yy\fR. The default year is the current year. If the year is less .VS than 100, we treat the years 00-68 as 2000-2068 and the years 69-99 as 1969-1999. Not all platforms can represent the years 38-70, so an error may result if these years are used. .VE .TP \fIISO 8601 point-in-time\fR An ISO 8601 point-in-time specification, such as \fICCyymmddThhmmss\fR, where T is the literal T, \fICCyymmdd hhmmss\fR, or \fICCyymmddThh:mm:ss\fR. Note that only these three formats are accepted. The command does \fInot\fR accept the full range of point-in-time specifications specified in ISO8601. Other formats can be recognized by using commands such as \fBregexp\fR to extract their fields and reorganize them into a form accepted by the \fBclock scan\fR command. .TP \fIrelative time\fR A specification relative to the current time. The format is \fInumber unit\fR acceptable units are \fByear\fR, \fBfortnight\fR, \fBmonth\fR, \fBweek\fR, \fBday\fR, \fBhour\fR, \fBminute\fR (or \fBmin\fR), and \fBsecond\fR (or \fBsec\fR). The unit can be specified as a singular or plural, as in \fB3 weeks\fR. These modifiers may also be specified: \fBtomorrow\fR, \fByesterday\fR, \fBtoday\fR, \fBnow\fR, \fBlast\fR, \fBthis\fR, \fBnext\fR, \fBago\fR. .RE .sp .RS The actual date is calculated according to the following steps. First, any absolute date and/or time is processed and converted. Using that time as the base, day-of-week specifications are added. Next, relative specifications are used. If a date or day is specified, and no absolute or relative time is given, midnight is used. Finally, a correction is applied so that the correct hour of the day is produced after allowing for daylight savings time differences and the correct date is given when going from the end of a long month to a short month. .sp Daylight savings time correction is applied only when the relative time is specified in units of days or more, ie, days, weeks, fortnights, months or years. This means that when crossing the daylight savings time boundary, different results will be given for \fBclock scan "1 day"\fR and \fBclock scan "24 hours"\fR: .CS .ta 6c % \fBclock scan\fR "1 day" -base [\fBclock scan\fR 1999-10-31] 941443200 % \fBclock scan\fR "24 hours" -base [\fBclock scan\fR 1999-10-31] 941439600 .CE .RE .TP \fBclock seconds\fR Return the current date and time as a system-dependent integer value. The unit of the value is seconds, allowing it to be used for relative time calculations. The value is usually defined as total elapsed time from an ``epoch''. You shouldn't assume the value of the epoch. .SH "SEE ALSO" date(1), time(n) .SH KEYWORDS clock, date, time tcl8.4.20/doc/if.n0000644003604700454610000000446011737050674012245 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH if n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME if \- Execute scripts conditionally .SH SYNOPSIS \fBif \fIexpr1 \fR?\fBthen\fR? \fIbody1 \fBelseif \fIexpr2 \fR?\fBthen\fR? \fIbody2\fR \fBelseif\fR ... ?\fBelse\fR? ?\fIbodyN\fR? .BE .SH DESCRIPTION .PP The \fIif\fR command evaluates \fIexpr1\fR as an expression (in the same way that \fBexpr\fR evaluates its argument). The value of the expression must be a boolean (a numeric value, where 0 is false and anything is true, or a string value such as \fBtrue\fR or \fByes\fR for true and \fBfalse\fR or \fBno\fR for false); if it is true then \fIbody1\fR is executed by passing it to the Tcl interpreter. Otherwise \fIexpr2\fR is evaluated as an expression and if it is true then \fBbody2\fR is executed, and so on. If none of the expressions evaluates to true then \fIbodyN\fR is executed. The \fBthen\fR and \fBelse\fR arguments are optional ``noise words'' to make the command easier to read. There may be any number of \fBelseif\fR clauses, including zero. \fIBodyN\fR may also be omitted as long as \fBelse\fR is omitted too. The return value from the command is the result of the body script that was executed, or an empty string if none of the expressions was non-zero and there was no \fIbodyN\fR. .SH EXAMPLES A simple conditional: .CS \fBif\fR {$vbl == 1} { puts "vbl is one" } .CE .PP With an \fBelse\fR-clause: .CS \fBif\fR {$vbl == 1} { puts "vbl is one" } \fBelse\fR { puts "vbl is not one" } .CE .PP With an \fBelseif\fR-clause too: .CS \fBif\fR {$vbl == 1} { puts "vbl is one" } \fBelseif\fR {$vbl == 2} { puts "vbl is two" } \fBelse\fR { puts "vbl is not one or two" } .CE .PP Remember, expressions can be multi-line, but in that case it can be a good idea to use the optional \fBthen\fR keyword for clarity: .CS \fBif\fR { $vbl == 1 || $vbl == 2 || $vbl == 3 } \fBthen\fR { puts "vbl is one, two or three" } .CE .SH "SEE ALSO" expr(n), for(n), foreach(n) .SH KEYWORDS boolean, conditional, else, false, if, true tcl8.4.20/doc/PkgRequire.30000644003604700454610000000553111737050674013632 0ustar dgp771div'\" '\" Copyright (c) 1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_PkgRequire 3 7.5 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_PkgRequire, Tcl_PkgRequireEx, Tcl_PkgPresent, Tcl_PkgPresentEx, Tcl_PkgProvide, Tcl_PkgProvideEx \- package version control .SH SYNOPSIS .nf \fB#include \fR .sp CONST char * \fBTcl_PkgRequire\fR(\fIinterp, name, version, exact\fR) .sp CONST char * \fBTcl_PkgRequireEx\fR(\fIinterp, name, version, exact, clientDataPtr\fR) .sp CONST char * \fBTcl_PkgPresent\fR(\fIinterp, name, version, exact\fR) .sp CONST char * \fBTcl_PkgPresentEx\fR(\fIinterp, name, version, exact, clientDataPtr\fR) .sp int \fBTcl_PkgProvide\fR(\fIinterp, name, version\fR) .sp int \fBTcl_PkgProvideEx\fR(\fIinterp, name, version, clientData\fR) .SH ARGUMENTS .AS ClientData clientDataPtr .AP Tcl_Interp *interp in Interpreter where package is needed or available. .AP "CONST char" *name in Name of package. .AP "CONST char" *version in A version string consisting of one or more decimal numbers separated by dots. .AP int exact in Non-zero means that only the particular version specified by \fIversion\fR is acceptable. Zero means that newer versions than \fIversion\fR are also acceptable as long as they have the same major version number as \fIversion\fR. .AP ClientData clientData in Arbitrary value to be associated with the package. .AP ClientData *clientDataPtr out Pointer to place to store the value associated with the matching package. It is only changed if the pointer is not NULL and the function completed successfully. .BE .SH DESCRIPTION .PP These procedures provide C-level interfaces to Tcl's package and version management facilities. .PP \fBTcl_PkgRequire\fR is equivalent to the \fBpackage require\fR command, \fBTcl_PkgPresent\fR is equivalent to the \fBpackage present\fR command, and \fBTcl_PkgProvide\fR is equivalent to the \fBpackage provide\fR command. .PP See the documentation for the Tcl commands for details on what these procedures do. .PP If \fBTcl_PkgPresent\fR or \fBTcl_PkgRequire\fR complete successfully they return a pointer to the version string for the version of the package that is provided in the interpreter (which may be different than \fIversion\fR); if an error occurs they return NULL and leave an error message in the interpreter's result. .PP \fBTcl_PkgProvide\fR returns TCL_OK if it completes successfully; if an error occurs it returns TCL_ERROR and leaves an error message in the interpreter's result. .PP \fBTcl_PkgProvideEx\fR, \fBTcl_PkgPresentEx\fR and \fBTcl_PkgRequireEx\fR allow the setting and retrieving of the client data associated with the package. In all other respects they are equivalent to the matching functions. .SH KEYWORDS package, present, provide, require, version tcl8.4.20/doc/InitStubs.30000644003604700454610000000660312133546537013500 0ustar dgp771div'\" '\" Copyright (c) 1998-1999 Scriptics Corporation '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_InitStubs 3 8.1 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_InitStubs \- initialize the Tcl stubs mechanism .SH SYNOPSIS .nf \fB#include \fR .sp CONST char * \fBTcl_InitStubs\fR(\fIinterp, version, exact\fR) .SH ARGUMENTS .AS Tcl_Interp *interp in .AP Tcl_Interp *interp in Tcl interpreter handle. .AP "CONST char" *version in A version string consisting of one or more decimal numbers separated by dots. .AP int exact in Non-zero means that only the particular version specified by \fIversion\fR is acceptable. Zero means that versions newer than \fIversion\fR are also acceptable as long as they have the same major version number as \fIversion\fR. .BE .SH INTRODUCTION .PP The Tcl stubs mechanism defines a way to dynamically bind extensions to a particular Tcl implementation at run time. This provides two significant benefits to Tcl users: .IP 1) 5 Extensions that use the stubs mechanism can be loaded into multiple versions of Tcl without being recompiled or relinked. .IP 2) 5 Extensions that use the stubs mechanism can be dynamically loaded into statically-linked Tcl applications. .PP The stubs mechanism accomplishes this by exporting function tables that define an interface to the Tcl API. The extension then accesses the Tcl API through offsets into the function table, so there are no direct references to any of the Tcl library's symbols. This redirection is transparent to the extension, so an extension writer can continue to use all public Tcl functions as documented. .PP The stubs mechanism requires no changes to applications incorporating Tcl interpreters. Only developers creating C-based Tcl extensions need to take steps to use the stubs mechanism with their extensions. .PP Enabling the stubs mechanism for an extension requires the following steps: .IP 1) 5 Call \fBTcl_InitStubs\fR in the extension before calling any other Tcl functions. .IP 2) 5 Define the USE_TCL_STUBS symbol. Typically, you would include the -DUSE_TCL_STUBS flag when compiling the extension. .IP 3) 5 Link the extension with the Tcl stubs library instead of the standard Tcl library. On Unix platforms, the library name is \fIlibtclstub8.4.a\fR; on Windows platforms, the library name is \fItclstub84.lib\fR. .PP If the extension also requires the Tk API, it must also call \fBTk_InitStubs\fR to initialize the Tk stubs interface and link with the Tk stubs libraries. See the \fBTk_InitStubs\fR page for more information. .SH DESCRIPTION \fBTcl_InitStubs\fR attempts to initialize the stub table pointers and ensure that the correct version of Tcl is loaded. In addition to an interpreter handle, it accepts as arguments a version number and a Boolean flag indicating whether the extension requires an exact version match or not. If \fIexact\fR is 0, then the extension is indicating that newer versions of Tcl are acceptable as long as they have the same major version number as \fIversion\fR; non-zero means that only the specified \fIversion\fR is acceptable. \fBTcl_InitStubs\fR returns a string containing the actual version of Tcl satisfying the request, or NULL if the Tcl version is not acceptable, does not support stubs, or any other error condition occurred. .SH "SEE ALSO" Tk_InitStubs .SH KEYWORDS stubs tcl8.4.20/doc/msgcat.n0000644003604700454610000002616512052456743013131 0ustar dgp771div'\" '\" Copyright (c) 1998 Mark Harrison. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH "msgcat" n 1.3 msgcat "Tcl Bundled Packages" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME msgcat \- Tcl message catalog .SH SYNOPSIS \fBpackage require Tcl 8.2\fR .sp \fBpackage require msgcat 1.3.5\fR .sp \fB::msgcat::mc \fIsrc-string\fR ?\fIarg arg ...\fR? .sp \fB::msgcat::mcmax ?\fIsrc-string src-string ...\fR? .sp \fB::msgcat::mclocale \fR?\fInewLocale\fR? .sp \fB::msgcat::mcpreferences\fR .sp \fB::msgcat::mcload \fIdirname\fR .sp \fB::msgcat::mcset \fIlocale src-string \fR?\fItranslate-string\fR? .sp \fB::msgcat::mcmset \fIlocale src-trans-list\fR .sp \fB::msgcat::mcunknown \fIlocale src-string\fR .BE .SH DESCRIPTION .PP The \fBmsgcat\fR package provides a set of functions that can be used to manage multi-lingual user interfaces. Text strings are defined in a ``message catalog'' which is independent from the application, and which can be edited or localized without modifying the application source code. New languages or locales are provided by adding a new file to the message catalog. .PP Use of the message catalog is optional by any application or package, but is encouraged if the application or package wishes to be enabled for multi-lingual applications. .SH COMMANDS .TP \fB::msgcat::mc \fIsrc-string\fR ?\fIarg arg ...\fR? Returns a translation of \fIsrc-string\fR according to the user's current locale. If additional arguments past \fIsrc-string\fR are given, the \fBformat\fR command is used to substitute the additional arguments in the translation of \fIsrc-string\fR. .PP \fB::msgcat::mc\fR will search the messages defined in the current namespace for a translation of \fIsrc-string\fR; if none is found, it will search in the parent of the current namespace, and so on until it reaches the global namespace. If no translation string exists, \fB::msgcat::mcunknown\fR is called and the string returned from \fB::msgcat::mcunknown\fR is returned. .PP \fB::msgcat::mc\fR is the main function used to localize an application. Instead of using an English string directly, an application can pass the English string through \fB::msgcat::mc\fR and use the result. If an application is written for a single language in this fashion, then it is easy to add support for additional languages later simply by defining new message catalog entries. .TP \fB::msgcat::mcmax ?\fIsrc-string src-string ...\fR? Given several source strings, \fB::msgcat::mcmax\fR returns the length of the longest translated string. This is useful when designing localized GUIs, which may require that all buttons, for example, be a fixed width (which will be the width of the widest button). .TP \fB::msgcat::mclocale \fR?\fInewLocale\fR? This function sets the locale to \fInewLocale\fR. If \fInewLocale\fR is omitted, the current locale is returned, otherwise the current locale is set to \fInewLocale\fR. msgcat stores and compares the locale in a case-insensitive manner, and returns locales in lowercase. The initial locale is determined by the locale specified in the user's environment. See \fBLOCALE SPECIFICATION\fR below for a description of the locale string format. .TP \fB::msgcat::mcpreferences\fR Returns an ordered list of the locales preferred by the user, based on the user's language specification. The list is ordered from most specific to least preference. The list is derived from the current locale set in msgcat by \fB::msgcat::mclocale\fR, and cannot be set independently. For example, if the current locale is en_US_funky, then \fB::msgcat::mcpreferences\fR returns \fB{en_US_funky en_US en}\fR. .TP \fB::msgcat::mcload \fIdirname\fR Searches the specified directory for files that match the language specifications returned by \fB::msgcat::mcpreferences\fR (note that these are all lowercase), extended by the file extension ``.msg''. Each matching file is read in order, assuming a UTF-8 encoding. The file contents are then evaluated as a Tcl script. This means that Unicode characters may be present in the message file either directly in their UTF-8 encoded form, or by use of the backslash-u quoting recognized by Tcl evaluation. The number of message files which matched the specification and were loaded is returned. .TP \fB::msgcat::mcset \fIlocale src-string \fR?\fItranslate-string\fR? Sets the translation for \fIsrc-string\fR to \fItranslate-string\fR in the specified \fIlocale\fR and the current namespace. If \fItranslate-string\fR is not specified, \fIsrc-string\fR is used for both. The function returns \fItranslate-string\fR. .TP \fB::msgcat::mcmset \fIlocale src-trans-list\fR Sets the translation for multiple source strings in \fIsrc-trans-list\fR in the specified \fIlocale\fR and the current namespace. \fIsrc-trans-list\fR must have an even number of elements and is in the form {\fIsrc-string translate-string\fR ?\fIsrc-string translate-string ...\fR?} \fB::msgcat::mcmset\fR can be significantly faster than multiple invocations of \fB::msgcat::mcset\fR. The function returns the number of translations set. .TP \fB::msgcat::mcunknown \fIlocale src-string\fR This routine is called by \fB::msgcat::mc\fR in the case when a translation for \fIsrc-string\fR is not defined in the current locale. The default action is to return \fIsrc-string\fR. This procedure can be redefined by the application, for example to log error messages for each unknown string. The \fB::msgcat::mcunknown\fR procedure is invoked at the same stack context as the call to \fB::msgcat::mc\fR. The return value of \fB::msgcat::mcunknown\fR is used as the return value for the call to \fB::msgcat::mc\fR. .SH "LOCALE SPECIFICATION" .PP The locale is specified to \fBmsgcat\fR by a locale string passed to \fB::msgcat::mclocale\fR. The locale string consists of a language code, an optional country code, and an optional system-specific code, each separated by ``_''. The country and language codes are specified in standards ISO-639 and ISO-3166. For example, the locale ``en'' specifies English and ``en_US'' specifies U.S. English. .PP When the msgcat package is first loaded, the locale is initialized according to the user's environment. The variables \fBenv(LC_ALL)\fR, \fBenv(LC_MESSAGES)\fR, and \fBenv(LANG)\fR are examined in order. The first of them to have a non-empty value is used to determine the initial locale. The value is parsed according to the XPG4 pattern .CS language[_country][.codeset][@modifier] .CE to extract its parts. The initial locale is then set by calling \fB::msgcat::mclocale\fR with the argument .CS language[_country][_modifier] .CE On Windows, if none of those environment variables is set, msgcat will attempt to extract locale information from the registry. If all these attempts to discover an initial locale from the user's environment fail, msgcat defaults to an initial locale of ``C''. .PP When a locale is specified by the user, a ``best match'' search is performed during string translation. For example, if a user specifies en_GB_Funky, the locales ``en_GB_Funky'', ``en_GB'', and ``en'' are searched in order until a matching translation string is found. If no translation string is available, then \fB::msgcat::mcunknown\fR is called. .SH "NAMESPACES AND MESSAGE CATALOGS" .PP Strings stored in the message catalog are stored relative to the namespace from which they were added. This allows multiple packages to use the same strings without fear of collisions with other packages. It also allows the source string to be shorter and less prone to typographical error. .PP For example, executing the code .CS \fB::msgcat::mcset\fR en hello "hello from ::" namespace eval foo { \fB::msgcat::mcset\fR en hello "hello from ::foo" } puts [\fB::msgcat::mc\fR hello] namespace eval foo {puts [\fB::msgcat::mc\fR hello]} .CE will print .CS hello from :: hello from ::foo .CE .PP When searching for a translation of a message, the message catalog will search first the current namespace, then the parent of the current namespace, and so on until the global namespace is reached. This allows child namespaces to "inherit" messages from their parent namespace. .PP For example, executing (in the ``en'' locale) the code .CS \fB::msgcat::mcset\fR en m1 ":: message1" \fB::msgcat::mcset\fR en m2 ":: message2" \fB::msgcat::mcset\fR en m3 ":: message3" namespace eval ::foo { \fB::msgcat::mcset\fR en m2 "::foo message2" \fB::msgcat::mcset\fR en m3 "::foo message3" } namespace eval ::foo::bar { \fB::msgcat::mcset\fR en m3 "::foo::bar message3" } namespace import \fB::msgcat::mc\fR puts "[\fBmc\fR m1]; [\fBmc\fR m2]; [\fBmc\fR m3]" namespace eval ::foo {puts "[\fBmc\fR m1]; [\fBmc\fR m2]; [\fBmc\fR m3]"} namespace eval ::foo::bar {puts "[\fBmc\fR m1]; [\fBmc\fR m2]; [\fBmc\fR m3]"} .CE will print .CS :: message1; :: message2; :: message3 :: message1; ::foo message2; ::foo message3 :: message1; ::foo message2; ::foo::bar message3 .CE .SH "LOCATION AND FORMAT OF MESSAGE FILES" .PP Message files can be located in any directory, subject to the following conditions: .IP [1] All message files for a package are in the same directory. .IP [2] The message file name is a msgcat locale specifier (all lowercase) followed by ``.msg''. For example: .CS es.msg -- spanish en_gb.msg -- United Kingdom English .CE .IP [3] The file contains a series of calls to \fBmcset\fR and \fBmcmset\fR, setting the necessary translation strings for the language, likely enclosed in a \fBnamespace eval\fR so that all source strings are tied to the namespace of the package. For example, a short \fBes.msg\fR might contain: .CS namespace eval ::mypackage { \fB::msgcat::mcset\fR es "Free Beer!" "Cerveza Gracias!" } .CE .SH "RECOMMENDED MESSAGE SETUP FOR PACKAGES" .PP If a package is installed into a subdirectory of the \fBtcl_pkgPath\fR and loaded via \fBpackage require\fR, the following procedure is recommended. .IP [1] During package installation, create a subdirectory \fBmsgs\fR under your package directory. .IP [2] Copy your *.msg files into that directory. .IP [3] Add the following command to your package initialization script: .CS # load language files, stored in msgs subdirectory \fB::msgcat::mcload\fR [file join [file dirname [info script]] msgs] .CE .SH "POSITIONAL CODES FOR FORMAT AND SCAN COMMANDS" .PP It is possible that a message string used as an argument to \fBformat\fR might have positionally dependent parameters that might need to be repositioned. For example, it might be syntactically desirable to rearrange the sentence structure while translating. .CS format "We produced %d units in location %s" $num $city format "In location %s we produced %d units" $city $num .CE .PP This can be handled by using the positional parameters: .CS format "We produced %1\\$d units in location %2\\$s" $num $city format "In location %2\\$s we produced %1\\$d units" $num $city .CE .PP Similarly, positional parameters can be used with \fBscan\fR to extract values from internationalized strings. .SH CREDITS .PP The message catalog code was developed by Mark Harrison. .SH "SEE ALSO" format(n), scan(n), namespace(n), package(n) .SH KEYWORDS internationalization, i18n, localization, l10n, message, text, translation tcl8.4.20/doc/eval.n0000644003604700454610000000274011737050674012575 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH eval n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME eval \- Evaluate a Tcl script .SH SYNOPSIS \fBeval \fIarg \fR?\fIarg ...\fR? .BE .SH DESCRIPTION .PP \fBEval\fR takes one or more arguments, which together comprise a Tcl script containing one or more commands. \fBEval\fR concatenates all its arguments in the same fashion as the \fBconcat\fR command, passes the concatenated string to the Tcl interpreter recursively, and returns the result of that evaluation (or any error generated by it). Note that the \fBlist\fR command quotes sequences of words in such a way that they are not further expanded by the \fBeval\fR command. .SH EXAMPLE This procedure acts in a way that is analogous to the \fBlappend\fR command, except it inserts the argument values at the start of the list in the variable: .CS proc lprepend {varName args} { upvar 1 $varName var # Ensure that the variable exists and contains a list lappend var # Now we insert all the arguments in one go set var [\fBeval\fR [list linsert $var 0] $args] } .CE .SH KEYWORDS concatenate, evaluate, script .SH "SEE ALSO" catch(n), concat(n), error(n), list(n), subst(n), tclvars(n) tcl8.4.20/doc/flush.n0000644003604700454610000000303611737050674012766 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH flush n 7.5 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME flush \- Flush buffered output for a channel .SH SYNOPSIS \fBflush \fIchannelId\fR .BE .SH DESCRIPTION .PP Flushes any output that has been buffered for \fIchannelId\fR. .PP .VS \fIChannelId\fR must be an identifier for an open channel such as a Tcl standard channel (\fBstdout\fR or \fBstderr\fR), the return value from an invocation of \fBopen\fR or \fBsocket\fR, or the result of a channel creation command provided by a Tcl extension. The channel must have been opened for writing. .VE .PP If the channel is in blocking mode the command does not return until all the buffered output has been flushed to the channel. If the channel is in nonblocking mode, the command may return before all buffered output has been flushed; the remainder will be flushed in the background as fast as the underlying file or device is able to absorb it. .SH EXAMPLE Prompt for the user to type some information in on the console: .CS puts -nonewline "Please type your name: " \fBflush\fR stdout gets stdin name puts "Hello there, $name!" .CE .SH "SEE ALSO" file(n), open(n), socket(n), Tcl_StandardChannels(3) .SH KEYWORDS blocking, buffer, channel, flush, nonblocking, output tcl8.4.20/doc/Tcl.n0000644003604700454610000001775311737050674012402 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl n "8.1" Tcl "Tcl Built-In Commands" .BS .SH NAME Tcl \- Tool Command Language .SH SYNOPSIS Summary of Tcl language syntax. .BE .SH DESCRIPTION .PP The following rules define the syntax and semantics of the Tcl language: .IP "[1] \fBCommands.\fR" A Tcl script is a string containing one or more commands. Semi-colons and newlines are command separators unless quoted as described below. Close brackets are command terminators during command substitution (see below) unless quoted. .IP "[2] \fBEvaluation.\fR" A command is evaluated in two steps. First, the Tcl interpreter breaks the command into \fIwords\fR and performs substitutions as described below. These substitutions are performed in the same way for all commands. The first word is used to locate a command procedure to carry out the command, then all of the words of the command are passed to the command procedure. The command procedure is free to interpret each of its words in any way it likes, such as an integer, variable name, list, or Tcl script. Different commands interpret their words differently. .IP "[3] \fBWords.\fR" Words of a command are separated by white space (except for newlines, which are command separators). .IP "[4] \fBDouble quotes.\fR" If the first character of a word is double-quote (``"'') then the word is terminated by the next double-quote character. If semi-colons, close brackets, or white space characters (including newlines) appear between the quotes then they are treated as ordinary characters and included in the word. Command substitution, variable substitution, and backslash substitution are performed on the characters between the quotes as described below. The double-quotes are not retained as part of the word. .IP "[5] \fBBraces.\fR" If the first character of a word is an open brace (``{'') then the word is terminated by the matching close brace (``}''). Braces nest within the word: for each additional open brace there must be an additional close brace (however, if an open brace or close brace within the word is quoted with a backslash then it is not counted in locating the matching close brace). No substitutions are performed on the characters between the braces except for backslash-newline substitutions described below, nor do semi-colons, newlines, close brackets, or white space receive any special interpretation. The word will consist of exactly the characters between the outer braces, not including the braces themselves. .IP "[6] \fBCommand substitution.\fR" If a word contains an open bracket (``['') then Tcl performs \fIcommand substitution\fR. To do this it invokes the Tcl interpreter recursively to process the characters following the open bracket as a Tcl script. The script may contain any number of commands and must be terminated by a close bracket (``]''). The result of the script (i.e. the result of its last command) is substituted into the word in place of the brackets and all of the characters between them. There may be any number of command substitutions in a single word. Command substitution is not performed on words enclosed in braces. .IP "[7] \fBVariable substitution.\fR" If a word contains a dollar-sign (``$'') followed by one of the forms described below, then Tcl performs \fIvariable substitution\fR: the dollar-sign and the following characters are replaced in the word by the value of a variable. Variable substitution may take any of the following forms: .RS .TP 15 \fB$\fIname\fR \fIName\fR is the name of a scalar variable; the name is a sequence of one or more characters that are a letter, digit, underscore, or namespace separators (two or more colons). .TP 15 \fB$\fIname\fB(\fIindex\fB)\fR \fIName\fR gives the name of an array variable and \fIindex\fR gives the name of an element within that array. \fIName\fR must contain only letters, digits, underscores, and namespace separators, and may be an empty string. Command substitutions, variable substitutions, and backslash substitutions are performed on the characters of \fIindex\fR. .TP 15 \fB${\fIname\fB}\fR \fIName\fR is the name of a scalar variable. It may contain any characters whatsoever except for close braces. .LP There may be any number of variable substitutions in a single word. Variable substitution is not performed on words enclosed in braces. .RE .IP "[8] \fBBackslash substitution.\fR" If a backslash (``\e'') appears within a word then \fIbackslash substitution\fR occurs. In all cases but those described below the backslash is dropped and the following character is treated as an ordinary character and included in the word. This allows characters such as double quotes, close brackets, and dollar signs to be included in words without triggering special processing. The following table lists the backslash sequences that are handled specially, along with the value that replaces each sequence. .RS .TP 7 \e\fBa\fR Audible alert (bell) (0x7). .TP 7 \e\fBb\fR Backspace (0x8). .TP 7 \e\fBf\fR Form feed (0xc). .TP 7 \e\fBn\fR Newline (0xa). .TP 7 \e\fBr\fR Carriage-return (0xd). .TP 7 \e\fBt\fR Tab (0x9). .TP 7 \e\fBv\fR Vertical tab (0xb). .TP 7 \e\fB\fIwhiteSpace\fR . A single space character replaces the backslash, newline, and all spaces and tabs after the newline. This backslash sequence is unique in that it is replaced in a separate pre-pass before the command is actually parsed. This means that it will be replaced even when it occurs between braces, and the resulting space will be treated as a word separator if it isn't in braces or quotes. .TP 7 \e\e Backslash (``\e''). .VS 8.1 br .TP 7 \e\fIooo\fR . The digits \fIooo\fR (one, two, or three of them) give an eight-bit octal value for the Unicode character that will be inserted. The upper bits of the Unicode character will be 0. .TP 7 \e\fBx\fIhh\fR . The hexadecimal digits \fIhh\fR give an eight-bit hexadecimal value for the Unicode character that will be inserted. Any number of hexadecimal digits may be present; however, all but the last two are ignored (the result is always a one-byte quantity). The upper bits of the Unicode character will be 0. .TP 7 \e\fBu\fIhhhh\fR . The hexadecimal digits \fIhhhh\fR (one, two, three, or four of them) give a sixteen-bit hexadecimal value for the Unicode character that will be inserted. .VE .LP Backslash substitution is not performed on words enclosed in braces, except for backslash-newline as described above. .RE .IP "[9] \fBComments.\fR" If a hash character (``#'') appears at a point where Tcl is expecting the first character of the first word of a command, then the hash character and the characters that follow it, up through the next newline, are treated as a comment and ignored. The comment character only has significance when it appears at the beginning of a command. .IP "[10] \fBOrder of substitution.\fR" Each character is processed exactly once by the Tcl interpreter as part of creating the words of a command. For example, if variable substitution occurs then no further substitutions are performed on the value of the variable; the value is inserted into the word verbatim. If command substitution occurs then the nested command is processed entirely by the recursive call to the Tcl interpreter; no substitutions are performed before making the recursive call and no additional substitutions are performed on the result of the nested script. .RS .LP Substitutions take place from left to right, and each substitution is evaluated completely before attempting to evaluate the next. Thus, a sequence like .CS set y [set x 0][incr x][incr x] .CE will always set the variable \fIy\fR to the value, \fI012\fR. .RE .IP "[11] \fBSubstitution and word boundaries.\fR" Substitutions do not affect the word boundaries of a command. For example, during variable substitution the entire value of the variable becomes part of a single word, even if the variable's value contains spaces. tcl8.4.20/doc/CrtTrace.30000644003604700454610000002031311737050674013256 0ustar dgp771div'\" '\" Copyright (c) 1989-1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" Copyright (c) 2002 by Kevin B. Kenny. All rights reserved. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_CreateTrace 3 "" Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_CreateTrace, Tcl_CreateObjTrace, Tcl_DeleteTrace \- arrange for command execution to be traced .SH SYNOPSIS .nf \fB#include \fR .sp Tcl_Trace \fBTcl_CreateTrace\fR(\fIinterp, level, proc, clientData\fR) .sp Tcl_Trace \fBTcl_CreateObjTrace\fR(\fIinterp, level, flags, objProc, clientData, deleteProc\fR) .sp \fBTcl_DeleteTrace\fR(\fIinterp, trace\fR) .SH ARGUMENTS .AS Tcl_CmdObjTraceDeleteProc (clientData)() .AP Tcl_Interp *interp in Interpreter containing command to be traced or untraced. .AP int level in Only commands at or below this nesting level will be traced unless 0 is specified. 1 means top-level commands only, 2 means top-level commands or those that are invoked as immediate consequences of executing top-level commands (procedure bodies, bracketed commands, etc.) and so on. A value of 0 means that commands at any level are traced. .AP int flags in Flags governing the trace execution. See below for details. .AP Tcl_CmdObjTraceProc *objProc in Procedure to call for each command that's executed. See below for details of the calling sequence. .AP Tcl_CmdTraceProc *proc in Procedure to call for each command that's executed. See below for details on the calling sequence. .AP ClientData clientData in Arbitrary one-word value to pass to \fIobjProc\fR or \fIproc\fR. .AP Tcl_CmdObjTraceDeleteProc *deleteProc Procedure to call when the trace is deleted. See below for details of the calling sequence. A NULL pointer is permissible and results in no callback when the trace is deleted. .AP Tcl_Trace trace in Token for trace to be removed (return value from previous call to \fBTcl_CreateTrace\fR). .BE .SH DESCRIPTION .PP \fBTcl_CreateObjTrace\fR arranges for command tracing. After it is called, \fIobjProc\fR will be invoked before the Tcl interpreter calls any command procedure when evaluating commands in \fIinterp\fR. The return value from \fBTcl_CreateObjTrace\fR is a token for the trace, which may be passed to \fBTcl_DeleteTrace\fR to remove the trace. There may be many traces in effect simultaneously for the same interpreter. .PP \fIobjProc\fR should have arguments and result that match the type, \fBTcl_CmdObjTraceProc\fR: .CS typedef int \fBTcl_CmdObjTraceProc\fR( \fBClientData\fR \fIclientData\fR, \fBTcl_Interp\fR* \fIinterp\fR, int \fIlevel\fR, CONST char* \fIcommand\fR, \fBTcl_Command\fR \fIcommandToken\fR, int \fIobjc\fR, \fBTcl_Obj\fR *CONST \fIobjv\fR[] ); .CE The \fIclientData\fR and \fIinterp\fR parameters are copies of the corresponding arguments given to \fBTcl_CreateTrace\fR. \fIClientData\fR typically points to an application-specific data structure that describes what to do when \fIobjProc\fR is invoked. The \fIlevel\fR parameter gives the nesting level of the command (1 for top-level commands passed to \fBTcl_Eval\fR by the application, 2 for the next-level commands passed to \fBTcl_Eval\fR as part of parsing or interpreting level-1 commands, and so on). The \fIcommand\fR parameter points to a string containing the text of the command, before any argument substitution. The \fIcommandToken\fR parameter is a Tcl command token that identifies the command to be invoked. The token may be passed to \fBTcl_GetCommandName\fR, \fBTcl_GetCommandInfoFromToken\fR, or \fBTcl_SetCommandInfoFromToken\fR to manipulate the definition of the command. The \fIobjc\fR and \fIobjv\fR parameters designate the final parameter count and parameter vector that will be passed to the command, and have had all substitutions performed. .PP The \fIobjProc\fR callback is expected to return a standard Tcl status return code. If this code is \fBTCL_OK\fR (the normal case), then the Tcl interpreter will invoke the command. Any other return code is treated as if the command returned that status, and the command is \fInot\fR invoked. .PP The \fIobjProc\fR callback must not modify \fIobjv\fR in any way. It is, however, permissible to change the command by calling \fBTcl_SetCommandTokenInfo\fR prior to returning. Any such change takes effect immediately, and the command is invoked with the new information. .PP Tracing will only occur for commands at nesting level less than or equal to the \fIlevel\fR parameter (i.e. the \fIlevel\fR parameter to \fIobjProc\fR will always be less than or equal to the \fIlevel\fR parameter to \fBTcl_CreateTrace\fR). .PP Tracing has a significant effect on runtime performance because it causes the bytecode compiler to refrain from generating in-line code for Tcl commands such as \fBif\fR and \fBwhile\fR in order that they may be traced. If traces for the built-in commands are not required, the \fIflags\fR parameter may be set to the constant value \fBTCL_ALLOW_INLINE_COMPILATION\fR. In this case, traces on built-in commands may or may not result in trace callbacks, depending on the state of the interpreter, but run-time performance will be improved significantly. (This functionality is desirable, for example, when using \fBTcl_CreateObjTrace\fR to implement an execution time profiler.) .PP Calls to \fIobjProc\fR will be made by the Tcl parser immediately before it calls the command procedure for the command (\fIcmdProc\fR). This occurs after argument parsing and substitution, so tracing for substituted commands occurs before tracing of the commands containing the substitutions. If there is a syntax error in a command, or if there is no command procedure associated with a command name, then no tracing will occur for that command. If a string passed to Tcl_Eval contains multiple commands (bracketed, or on different lines) then multiple calls to \fIobjProc\fR will occur, one for each command. .PP \fBTcl_DeleteTrace\fR removes a trace, so that no future calls will be made to the procedure associated with the trace. After \fBTcl_DeleteTrace\fR returns, the caller should never again use the \fItrace\fR token. .PP When \fBTcl_DeleteTrace\fR is called, the interpreter invokes the \fIdeleteProc\fR that was passed as a parameter to \fBTcl_CreateObjTrace\fR. The \fIdeleteProc\fR must match the type, \fBTcl_CmdObjTraceDeleteProc\fR: .CS typedef void \fBTcl_CmdObjTraceDeleteProc\fR( \fBClientData\fR \fIclientData\fR ); .CE The \fIclientData\fR parameter will be the same as the \fIclientData\fR parameter that was originally passed to \fBTcl_CreateObjTrace\fR. .PP \fBTcl_CreateTrace\fR is an alternative interface for command tracing, \fInot recommended for new applications\fR. It is provided for backward compatibility with code that was developed for older versions of the Tcl interpreter. It is similar to \fBTcl_CreateObjTrace\fR, except that its \fIproc\fR parameter should have arguments and result that match the type \fBTcl_CmdTraceProc\fR: .CS typedef void Tcl_CmdTraceProc( ClientData \fIclientData\fR, Tcl_Interp *\fIinterp\fR, int \fIlevel\fR, char *\fIcommand\fR, Tcl_CmdProc *\fIcmdProc\fR, ClientData \fIcmdClientData\fR, int \fIargc\fR, CONST char *\fIargv\fR[]); .CE The parameters to the \fIproc\fR callback are similar to those of the \fIobjProc\fR callback above. The \fIcommandToken\fR is replaced with \fIcmdProc\fR, a pointer to the (string-based) command procedure that will be invoked; and \fIcmdClientData\fR, the client data that will be passed to the procedure. The \fIobjc\fR parameter is replaced with an \fIargv\fR parameter, that gives the arguments to the command as character strings. \fIProc\fR must not modify the \fIcommand\fR or \fIargv\fR strings. .PP If a trace created with \fBTcl_CreateTrace\fR is in effect, inline compilation of Tcl commands such as \fBif\fR and \fBwhile\fR is always disabled. There is no notification when a trace created with \fBTcl_CreateTrace\fR is deleted. There is no way to be notified when the trace created by \fBTcl_CreateTrace\fR is deleted. There is no way for the \fIproc\fR associated with a call to \fBTcl_CreateTrace\fR to abort execution of \fIcommand\fR. .SH KEYWORDS command, create, delete, interpreter, trace tcl8.4.20/doc/SetResult.30000644003604700454610000002272511737050674013512 0ustar dgp771div'\" '\" Copyright (c) 1989-1993 The Regents of the University of California. '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_SetResult 3 8.0 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_SetObjResult, Tcl_GetObjResult, Tcl_SetResult, Tcl_GetStringResult, Tcl_AppendResult, Tcl_AppendResultVA, Tcl_AppendElement, Tcl_ResetResult, Tcl_FreeResult \- manipulate Tcl result .SH SYNOPSIS .nf \fB#include \fR .sp \fBTcl_SetObjResult\fR(\fIinterp, objPtr\fR) .sp Tcl_Obj * \fBTcl_GetObjResult\fR(\fIinterp\fR) .sp \fBTcl_SetResult\fR(\fIinterp, string, freeProc\fR) .sp CONST char * \fBTcl_GetStringResult\fR(\fIinterp\fR) .sp \fBTcl_AppendResult\fR(\fIinterp, string, string, ... , \fB(char *) NULL\fR) .sp \fBTcl_AppendResultVA\fR(\fIinterp, argList\fR) .sp \fBTcl_AppendElement\fR(\fIinterp, string\fR) .sp \fBTcl_ResetResult\fR(\fIinterp\fR) .sp \fBTcl_FreeResult\fR(\fIinterp\fR) .SH ARGUMENTS .AS Tcl_FreeProc freeProc .AP Tcl_Interp *interp out Interpreter whose result is to be modified or read. .AP Tcl_Obj *objPtr in Object value to become result for \fIinterp\fR. .AP char *string in String value to become result for \fIinterp\fR or to be appended to the existing result. .AP Tcl_FreeProc *freeProc in Address of procedure to call to release storage at \fIstring\fR, or \fBTCL_STATIC\fR, \fBTCL_DYNAMIC\fR, or \fBTCL_VOLATILE\fR. .AP va_list argList in An argument list which must have been initialised using \fBTCL_VARARGS_START\fR, and cleared using \fBva_end\fR. .BE .SH DESCRIPTION .PP The procedures described here are utilities for manipulating the result value in a Tcl interpreter. The interpreter result may be either a Tcl object or a string. For example, \fBTcl_SetObjResult\fR and \fBTcl_SetResult\fR set the interpreter result to, respectively, an object and a string. Similarly, \fBTcl_GetObjResult\fR and \fBTcl_GetStringResult\fR return the interpreter result as an object and as a string. The procedures always keep the string and object forms of the interpreter result consistent. For example, if \fBTcl_SetObjResult\fR is called to set the result to an object, then \fBTcl_GetStringResult\fR is called, it will return the object's string value. .PP \fBTcl_SetObjResult\fR arranges for \fIobjPtr\fR to be the result for \fIinterp\fR, replacing any existing result. The result is left pointing to the object referenced by \fIobjPtr\fR. \fIobjPtr\fR's reference count is incremented since there is now a new reference to it from \fIinterp\fR. The reference count for any old result object is decremented and the old result object is freed if no references to it remain. .PP \fBTcl_GetObjResult\fR returns the result for \fIinterp\fR as an object. The object's reference count is not incremented; if the caller needs to retain a long-term pointer to the object they should use \fBTcl_IncrRefCount\fR to increment its reference count in order to keep it from being freed too early or accidently changed. .PP \fBTcl_SetResult\fR arranges for \fIstring\fR to be the result for the current Tcl command in \fIinterp\fR, replacing any existing result. The \fIfreeProc\fR argument specifies how to manage the storage for the \fIstring\fR argument; it is discussed in the section \fBTHE TCL_FREEPROC ARGUMENT TO TCL_SETRESULT\fR below. If \fIstring\fR is \fBNULL\fR, then \fIfreeProc\fR is ignored and \fBTcl_SetResult\fR re-initializes \fIinterp\fR's result to point to an empty string. .PP \fBTcl_GetStringResult\fR returns the result for \fIinterp\fR as an string. If the result was set to an object by a \fBTcl_SetObjResult\fR call, the object form will be converted to a string and returned. If the object's string representation contains null bytes, this conversion will lose information. For this reason, programmers are encouraged to write their code to use the new object API procedures and to call \fBTcl_GetObjResult\fR instead. .PP \fBTcl_ResetResult\fR clears the result for \fIinterp\fR and leaves the result in its normal empty initialized state. If the result is an object, its reference count is decremented and the result is left pointing to an unshared object representing an empty string. If the result is a dynamically allocated string, its memory is free*d and the result is left as a empty string. \fBTcl_ResetResult\fR also clears the error state managed by \fBTcl_AddErrorInfo\fR, \fBTcl_AddObjErrorInfo\fR, and \fBTcl_SetErrorCode\fR. .SH "OLD STRING PROCEDURES" .PP Use of the following procedures is deprecated since they manipulate the Tcl result as a string. Procedures such as \fBTcl_SetObjResult\fR that manipulate the result as an object can be significantly more efficient. .PP \fBTcl_AppendResult\fR makes it easy to build up Tcl results in pieces. It takes each of its \fIstring\fR arguments and appends them in order to the current result associated with \fIinterp\fR. If the result is in its initialized empty state (e.g. a command procedure was just invoked or \fBTcl_ResetResult\fR was just called), then \fBTcl_AppendResult\fR sets the result to the concatenation of its \fIstring\fR arguments. \fBTcl_AppendResult\fR may be called repeatedly as additional pieces of the result are produced. \fBTcl_AppendResult\fR takes care of all the storage management issues associated with managing \fIinterp\fR's result, such as allocating a larger result area if necessary. It also converts the current interpreter result from an object to a string, if necessary, before appending the argument strings. Any number of \fIstring\fR arguments may be passed in a single call; the last argument in the list must be a NULL pointer. .PP \fBTcl_AppendResultVA\fR is the same as \fBTcl_AppendResult\fR except that instead of taking a variable number of arguments it takes an argument list. .PP \fBTcl_AppendElement\fR is similar to \fBTcl_AppendResult\fR in that it allows results to be built up in pieces. However, \fBTcl_AppendElement\fR takes only a single \fIstring\fR argument and it appends that argument to the current result as a proper Tcl list element. \fBTcl_AppendElement\fR adds backslashes or braces if necessary to ensure that \fIinterp\fR's result can be parsed as a list and that \fIstring\fR will be extracted as a single element. Under normal conditions, \fBTcl_AppendElement\fR will add a space character to \fIinterp\fR's result just before adding the new list element, so that the list elements in the result are properly separated. However if the new list element is the first in a list or sub-list (i.e. \fIinterp\fR's current result is empty, or consists of the single character ``{'', or ends in the characters `` {'') then no space is added. .PP \fBTcl_FreeResult\fR performs part of the work of \fBTcl_ResetResult\fR. It frees up the memory associated with \fIinterp\fR's result. It also sets \fIinterp->freeProc\fR to zero, but doesn't change \fIinterp->result\fR or clear error state. \fBTcl_FreeResult\fR is most commonly used when a procedure is about to replace one result value with another. .SH "DIRECT ACCESS TO INTERP->RESULT IS DEPRECATED" .PP It used to be legal for programs to directly read and write \fIinterp->result\fR to manipulate the interpreter result. Direct access to \fIinterp->result\fR is now strongly deprecated because it can make the result's string and object forms inconsistent. Programs should always read the result using the procedures \fBTcl_GetObjResult\fR or \fBTcl_GetStringResult\fR, and write the result using \fBTcl_SetObjResult\fR or \fBTcl_SetResult\fR. .SH "THE TCL_FREEPROC ARGUMENT TO TCL_SETRESULT" .PP \fBTcl_SetResult\fR's \fIfreeProc\fR argument specifies how the Tcl system is to manage the storage for the \fIstring\fR argument. If \fBTcl_SetResult\fR or \fBTcl_SetObjResult\fR are called at a time when \fIinterp\fR holds a string result, they do whatever is necessary to dispose of the old string result (see the \fBTcl_Interp\fR manual entry for details on this). .PP If \fIfreeProc\fR is \fBTCL_STATIC\fR it means that \fIstring\fR refers to an area of static storage that is guaranteed not to be modified until at least the next call to \fBTcl_Eval\fR. If \fIfreeProc\fR is \fBTCL_DYNAMIC\fR it means that \fIstring\fR was allocated with a call to \fBTcl_Alloc\fR and is now the property of the Tcl system. \fBTcl_SetResult\fR will arrange for the string's storage to be released by calling \fBTcl_Free\fR when it is no longer needed. If \fIfreeProc\fR is \fBTCL_VOLATILE\fR it means that \fIstring\fR points to an area of memory that is likely to be overwritten when \fBTcl_SetResult\fR returns (e.g. it points to something in a stack frame). In this case \fBTcl_SetResult\fR will make a copy of the string in dynamically allocated storage and arrange for the copy to be the result for the current Tcl command. .PP If \fIfreeProc\fR isn't one of the values \fBTCL_STATIC\fR, \fBTCL_DYNAMIC\fR, and \fBTCL_VOLATILE\fR, then it is the address of a procedure that Tcl should call to free the string. This allows applications to use non-standard storage allocators. When Tcl no longer needs the storage for the string, it will call \fIfreeProc\fR. \fIFreeProc\fR should have arguments and result that match the type \fBTcl_FreeProc\fR: .CS typedef void Tcl_FreeProc(char *\fIblockPtr\fR); .CE When \fIfreeProc\fR is called, its \fIblockPtr\fR will be set to the value of \fIstring\fR passed to \fBTcl_SetResult\fR. .SH "SEE ALSO" Tcl_AddErrorInfo, Tcl_CreateObjCommand, Tcl_SetErrorCode, Tcl_Interp .SH KEYWORDS append, command, element, list, object, result, return value, interpreter tcl8.4.20/doc/GetIndex.30000644003604700454610000001054112052456743013256 0ustar dgp771div'\" '\" Copyright (c) 1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_GetIndexFromObj 3 8.1 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_GetIndexFromObj, Tcl_GetIndexFromObjStruct \- lookup string in table of keywords .SH SYNOPSIS .nf \fB#include \fR .sp int \fBTcl_GetIndexFromObj\fR(\fIinterp, objPtr, tablePtr, msg, flags, indexPtr\fR) .VS .sp int \fBTcl_GetIndexFromObjStruct\fR(\fIinterp, objPtr, structTablePtr, offset, msg, flags, indexPtr\fR) .VE .SH ARGUMENTS .AS "CONST char" **tablePtr .AP Tcl_Interp *interp in Interpreter to use for error reporting; if NULL, then no message is provided on errors. .AP Tcl_Obj *objPtr in/out The string value of this object is used to search through \fItablePtr\fR. The internal representation is modified to hold the index of the matching table entry. .AP "CONST char" **tablePtr in An array of null-terminated strings. The end of the array is marked by a NULL string pointer. Note that references to the \fItablePtr\fR may be retained in the internal representation of \fIobjPtr\fR, so this should represent the address of a statically-allocated array. .AP "CONST VOID" *structTablePtr in An array of arbitrary type, typically some \fBstruct\fP type. The first member of the structure must be a null-terminated string. The size of the structure is given by \fIoffset\fP. Note that references to the \fIstructTablePtr\fR may be retained in the internal representation of \fIobjPtr\fR, so this should represent the address of a statically-allocated array of structures. .VS .AP int offset in The offset to add to structTablePtr to get to the next entry. The end of the array is marked by a NULL string pointer. .VE .AP "CONST char" *msg in Null-terminated string describing what is being looked up, such as \fBoption\fR. This string is included in error messages. .AP int flags in OR-ed combination of bits providing additional information for operation. The only bit that is currently defined is \fBTCL_EXACT\fR. .AP int *indexPtr out The index of the string in \fItablePtr\fR that matches the value of \fIobjPtr\fR is returned here. .BE .SH DESCRIPTION .PP These procedures provide an efficient way for looking up keywords, switch names, option names, and similar things where the value of an object must be one of a predefined set of values. \fBTcl_GetIndexFromObj\fR compares \fIobjPtr\fR against each of the strings in \fItablePtr\fR to find a match. A match occurs if \fIobjPtr\fR's string value is identical to one of the strings in \fItablePtr\fR, or if it is a non-empty unique abbreviation for exactly one of the strings in \fItablePtr\fR and the \fBTCL_EXACT\fR flag was not specified; in either case the index of the matching entry is stored at \fI*indexPtr\fR and TCL_OK is returned. .PP If there is no matching entry, TCL_ERROR is returned and an error message is left in \fIinterp\fR's result if \fIinterp\fR isn't NULL. \fIMsg\fR is included in the error message to indicate what was being looked up. For example, if \fImsg\fR is \fBoption\fR the error message will have a form like \fBbad option "firt": must be first, second, or third\fR. .PP If \fBTcl_GetIndexFromObj\fR completes successfully it modifies the internal representation of \fIobjPtr\fR to hold the address of the table and the index of the matching entry. If \fBTcl_GetIndexFromObj\fR is invoked again with the same \fIobjPtr\fR and \fItablePtr\fR arguments (e.g. during a reinvocation of a Tcl command), it returns the matching index immediately without having to redo the lookup operation. Note: \fBTcl_GetIndexFromObj\fR assumes that the entries in \fItablePtr\fR are static: they must not change between invocations. If the value of \fIobjPtr\fR is the empty string, \fBTcl_GetIndexFromObj\fR will treat it as a non-matching value and return TCL_ERROR. .VS .PP \fBTcl_GetIndexFromObjStruct\fR works just like \fBTcl_GetIndexFromObj\fR, except that instead of treating \fItablePtr\fR as an array of string pointers, it treats it as the first in a series of string ptrs that are spaced apart by \fIoffset\fR bytes. This is particularly useful when processing things like \fBTk_ConfigurationSpec\fR, whose string keys are in the same place in each of several array elements. .VE .SH "SEE ALSO" Tcl_WrongNumArgs .SH KEYWORDS index, object, table lookup tcl8.4.20/doc/socket.n0000644003604700454610000001610411737050674013135 0ustar dgp771div'\" '\" Copyright (c) 1996 Sun Microsystems, Inc. '\" Copyright (c) 1998-1999 by Scriptics Corporation. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH socket n 8.0 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME socket \- Open a TCP network connection .SH SYNOPSIS .sp \fBsocket \fR?\fIoptions\fR? \fIhost port\fR .sp \fBsocket\fR \fB\-server \fIcommand\fR ?\fIoptions\fR? \fIport\fR .BE .SH DESCRIPTION .PP This command opens a network socket and returns a channel identifier that may be used in future invocations of commands like \fBread\fR, \fBputs\fR and \fBflush\fR. At present only the TCP network protocol is supported; future releases may include support for additional protocols. The \fBsocket\fR command may be used to open either the client or server side of a connection, depending on whether the \fB\-server\fR switch is specified. .PP Note that the default encoding for \fIall\fR sockets is the system encoding, as returned by \fBencoding system\fR. Most of the time, you will need to use \fBfconfigure\fR to alter this to something else, such as \fIutf\-8\fR (ideal for communicating with other Tcl processes) or \fIiso8859\-1\fR (useful for many network protocols, especially the older ones). .SH "CLIENT SOCKETS" .PP If the \fB\-server\fR option is not specified, then the client side of a connection is opened and the command returns a channel identifier that can be used for both reading and writing. \fIPort\fR and \fIhost\fR specify a port to connect to; there must be a server accepting connections on this port. \fIPort\fR is an integer port number (or service name, where supported and understood by the host operating system) and \fIhost\fR is either a domain-style name such as \fBwww.tcl.tk\fR or a numerical IP address such as \fB127.0.0.1\fR. Use \fIlocalhost\fR to refer to the host on which the command is invoked. .PP The following options may also be present before \fIhost\fR to specify additional information about the connection: .TP \fB\-myaddr\fI addr\fR \fIAddr\fR gives the domain-style name or numerical IP address of the client-side network interface to use for the connection. This option may be useful if the client machine has multiple network interfaces. If the option is omitted then the client-side interface will be chosen by the system software. .TP \fB\-myport\fI port\fR \fIPort\fR specifies an integer port number (or service name, where supported and understood by the host operating system) to use for the client's side of the connection. If this option is omitted, the client's port number will be chosen at random by the system software. .TP \fB\-async\fR The \fB\-async\fR option will cause the client socket to be connected asynchronously. This means that the socket will be created immediately but may not yet be connected to the server, when the call to \fBsocket\fR returns. When a \fBgets\fR or \fBflush\fR is done on the socket before the connection attempt succeeds or fails, if the socket is in blocking mode, the operation will wait until the connection is completed or fails. If the socket is in nonblocking mode and a \fBgets\fR or \fBflush\fR is done on the socket before the connection attempt succeeds or fails, the operation returns immediately and \fBfblocked\fR on the socket returns 1. .SH "SERVER SOCKETS" .PP If the \fB\-server\fR option is specified then the new socket will be a server for the port given by \fIport\fR (either an integer or a service name, where supported and understood by the host operating system; if \fIport\fR is zero, the operating system will allocate a free port to the server socket which may be discovered by using \fBfconfigure\fR to read the \fB\-sockname\fR option). Tcl will automatically accept connections to the given port. For each connection Tcl will create a new channel that may be used to communicate with the client. Tcl then invokes \fIcommand\fR with three additional arguments: the name of the new channel, the address, in network address notation, of the client's host, and the client's port number. .PP The following additional option may also be specified before \fIhost\fR: .TP \fB\-myaddr\fI addr\fR \fIAddr\fR gives the domain-style name or numerical IP address of the server-side network interface to use for the connection. This option may be useful if the server machine has multiple network interfaces. If the option is omitted then the server socket is bound to the special address INADDR_ANY so that it can accept connections from any interface. .PP Server channels cannot be used for input or output; their sole use is to accept new client connections. The channels created for each incoming client connection are opened for input and output. Closing the server channel shuts down the server so that no new connections will be accepted; however, existing connections will be unaffected. .PP Server sockets depend on the Tcl event mechanism to find out when new connections are opened. If the application doesn't enter the event loop, for example by invoking the \fBvwait\fR command or calling the C procedure \fBTcl_DoOneEvent\fR, then no connections will be accepted. .PP If \fIport\fR is specified as zero, the operating system will allocate an unused port for use as a server socket. The port number actually allocated may be retrieved from the created server socket using the \fBfconfigure\fR command to retrieve the \fB\-sockname\fR option as described below. .SH "CONFIGURATION OPTIONS" The \fBfconfigure\fR command can be used to query several readonly configuration options for socket channels: .TP \fB\-error\fR This option gets the current error status of the given socket. This is useful when you need to determine if an asynchronous connect operation succeeded. If there was an error, the error message is returned. If there was no error, an empty string is returned. .TP \fB\-sockname\fR This option returns a list of three elements, the address, the host name and the port number for the socket. If the host name cannot be computed, the second element is identical to the address, the first element of the list. .TP \fB\-peername\fR This option is not supported by server sockets. For client and accepted sockets, this option returns a list of three elements; these are the address, the host name and the port to which the peer socket is connected or bound. If the host name cannot be computed, the second element of the list is identical to the address, its first element. .PP .SH "EXAMPLES" Here is a very simple time server: .CS proc Server {channel clientaddr clientport} { puts "Connection from $clientaddr registered" puts $channel [clock format [clock seconds]] close $channel } \fBsocket\fR -server Server 9900 vwait forever .CE .PP And here is the corresponding client to talk to the server: .CS set server localhost set sockChan [\fBsocket\fR $server 9900] gets $sockChan line close $sockChan puts "The time on $server is $line" .CE .SH "SEE ALSO" fconfigure(n), flush(n), open(n), read(n) .SH KEYWORDS bind, channel, connection, domain name, host, network address, socket, tcp tcl8.4.20/doc/CrtCommand.30000644003604700454610000001441711737050674013606 0ustar dgp771div'\" '\" Copyright (c) 1989-1993 The Regents of the University of California. '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_CreateCommand 3 "" Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_CreateCommand \- implement new commands in C .SH SYNOPSIS .nf \fB#include \fR .sp Tcl_Command \fBTcl_CreateCommand\fR(\fIinterp, cmdName, proc, clientData, deleteProc\fR) .SH ARGUMENTS .AS Tcl_CmdDeleteProc **deleteProcPtr .AP Tcl_Interp *interp in Interpreter in which to create new command. .VS 8.4 .AP "CONST char" *cmdName in .VE Name of command. .AP Tcl_CmdProc *proc in Implementation of new command: \fIproc\fR will be called whenever \fIcmdName\fR is invoked as a command. .AP ClientData clientData in Arbitrary one-word value to pass to \fIproc\fR and \fIdeleteProc\fR. .AP Tcl_CmdDeleteProc *deleteProc in Procedure to call before \fIcmdName\fR is deleted from the interpreter; allows for command-specific cleanup. If NULL, then no procedure is called before the command is deleted. .BE .SH DESCRIPTION .PP \fBTcl_CreateCommand\fR defines a new command in \fIinterp\fR and associates it with procedure \fIproc\fR such that whenever \fIcmdName\fR is invoked as a Tcl command (via a call to \fBTcl_Eval\fR) the Tcl interpreter will call \fIproc\fR to process the command. It differs from \fBTcl_CreateObjCommand\fR in that a new string-based command is defined; that is, a command procedure is defined that takes an array of argument strings instead of objects. The object-based command procedures registered by \fBTcl_CreateObjCommand\fR can execute significantly faster than the string-based command procedures defined by \fBTcl_CreateCommand\fR. This is because they take Tcl objects as arguments and those objects can retain an internal representation that can be manipulated more efficiently. Also, Tcl's interpreter now uses objects internally. In order to invoke a string-based command procedure registered by \fBTcl_CreateCommand\fR, it must generate and fetch a string representation from each argument object before the call and create a new Tcl object to hold the string result returned by the string-based command procedure. New commands should be defined using \fBTcl_CreateObjCommand\fR. We support \fBTcl_CreateCommand\fR for backwards compatibility. .PP The procedures \fBTcl_DeleteCommand\fR, \fBTcl_GetCommandInfo\fR, and \fBTcl_SetCommandInfo\fR are used in conjunction with \fBTcl_CreateCommand\fR. .PP \fBTcl_CreateCommand\fR will delete an existing command \fIcmdName\fR, if one is already associated with the interpreter. It returns a token that may be used to refer to the command in subsequent calls to \fBTcl_GetCommandName\fR. If \fIcmdName\fR contains any \fB::\fR namespace qualifiers, then the command is added to the specified namespace; otherwise the command is added to the global namespace. If \fBTcl_CreateCommand\fR is called for an interpreter that is in the process of being deleted, then it does not create a new command and it returns NULL. \fIProc\fR should have arguments and result that match the type \fBTcl_CmdProc\fR: .CS typedef int Tcl_CmdProc( ClientData \fIclientData\fR, Tcl_Interp *\fIinterp\fR, int \fIargc\fR, CONST char *\fIargv\fR[]); .CE When \fIproc\fR is invoked the \fIclientData\fR and \fIinterp\fR parameters will be copies of the \fIclientData\fR and \fIinterp\fR arguments given to \fBTcl_CreateCommand\fR. Typically, \fIclientData\fR points to an application-specific data structure that describes what to do when the command procedure is invoked. \fIArgc\fR and \fIargv\fR describe the arguments to the command, \fIargc\fR giving the number of arguments (including the command name) and \fIargv\fR giving the values of the arguments as strings. The \fIargv\fR array will contain \fIargc\fR+1 values; the first \fIargc\fR values point to the argument strings, and the last value is NULL. .VS Note that the argument strings should not be modified as they may point to constant strings or may be shared with other parts of the interpreter. .VE .PP .VS Note that the argument strings are encoded in normalized UTF-8 since version 8.1 of Tcl. .VE .PP \fIProc\fR must return an integer code that is either \fBTCL_OK\fR, \fBTCL_ERROR\fR, \fBTCL_RETURN\fR, \fBTCL_BREAK\fR, or \fBTCL_CONTINUE\fR. See the Tcl overview man page for details on what these codes mean. Most normal commands will only return \fBTCL_OK\fR or \fBTCL_ERROR\fR. In addition, \fIproc\fR must set the interpreter result to point to a string value; in the case of a \fBTCL_OK\fR return code this gives the result of the command, and in the case of \fBTCL_ERROR\fR it gives an error message. The \fBTcl_SetResult\fR procedure provides an easy interface for setting the return value; for complete details on how the the interpreter result field is managed, see the \fBTcl_Interp\fR man page. Before invoking a command procedure, \fBTcl_Eval\fR sets the interpreter result to point to an empty string, so simple commands can return an empty result by doing nothing at all. .PP The contents of the \fIargv\fR array belong to Tcl and are not guaranteed to persist once \fIproc\fR returns: \fIproc\fR should not modify them, nor should it set the interpreter result to point anywhere within the \fIargv\fR values. Call \fBTcl_SetResult\fR with status \fBTCL_VOLATILE\fR if you want to return something from the \fIargv\fR array. .PP \fIDeleteProc\fR will be invoked when (if) \fIcmdName\fR is deleted. This can occur through a call to \fBTcl_DeleteCommand\fR or \fBTcl_DeleteInterp\fR, or by replacing \fIcmdName\fR in another call to \fBTcl_CreateCommand\fR. \fIDeleteProc\fR is invoked before the command is deleted, and gives the application an opportunity to release any structures associated with the command. \fIDeleteProc\fR should have arguments and result that match the type \fBTcl_CmdDeleteProc\fR: .CS typedef void Tcl_CmdDeleteProc(ClientData \fIclientData\fR); .CE The \fIclientData\fR argument will be the same as the \fIclientData\fR argument passed to \fBTcl_CreateCommand\fR. .PP .SH "SEE ALSO" Tcl_CreateObjCommand, Tcl_DeleteCommand, Tcl_GetCommandInfo, Tcl_SetCommandInfo, Tcl_GetCommandName, Tcl_SetObjResult .SH KEYWORDS bind, command, create, delete, interpreter, namespace tcl8.4.20/doc/pkgMkIndex.n0000644003604700454610000002450711737050674013714 0ustar dgp771div'\" '\" Copyright (c) 1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH pkg_mkIndex n 8.3 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME pkg_mkIndex \- Build an index for automatic loading of packages .SH SYNOPSIS .nf .VS 8.3.0 \fBpkg_mkIndex ?\fI\-direct\fR? ?\fI\-lazy\fR? ?\fI\-load pkgPat\fR? ?\fI\-verbose\fR? \fIdir\fR ?\fIpattern pattern ...\fR? .VE .fi .BE .SH DESCRIPTION .PP \fBPkg_mkIndex\fR is a utility procedure that is part of the standard Tcl library. It is used to create index files that allow packages to be loaded automatically when \fBpackage require\fR commands are executed. To use \fBpkg_mkIndex\fR, follow these steps: .IP [1] Create the package(s). Each package may consist of one or more Tcl script files or binary files. Binary files must be suitable for loading with the \fBload\fR command with a single argument; for example, if the file is \fBtest.so\fR it must be possible to load this file with the command \fBload test.so\fR. Each script file must contain a \fBpackage provide\fR command to declare the package and version number, and each binary file must contain a call to \fBTcl_PkgProvide\fR. .IP [2] Create the index by invoking \fBpkg_mkIndex\fR. The \fIdir\fR argument gives the name of a directory and each \fIpattern\fR argument is a \fBglob\fR-style pattern that selects script or binary files in \fIdir\fR. .VS 8.0.3 The default pattern is \fB*.tcl\fR and \fB*.[info sharedlibextension]\fR. .VE .br \fBPkg_mkIndex\fR will create a file \fBpkgIndex.tcl\fR in \fIdir\fR with package information about all the files given by the \fIpattern\fR arguments. It does this by loading each file into a slave interpreter and seeing what packages and new commands appear (this is why it is essential to have \fBpackage provide\fR commands or \fBTcl_PkgProvide\fR calls in the files, as described above). If you have a package split among scripts and binary files, or if you have dependencies among files, you may have to use the \fB\-load\fP option or adjust the order in which \fBpkg_mkIndex\fR processes the files. See COMPLEX CASES below. .IP [3] Install the package as a subdirectory of one of the directories given by the \fBtcl_pkgPath\fR variable. If \fB$tcl_pkgPath\fR contains more than one directory, machine-dependent packages (e.g., those that contain binary shared libraries) should normally be installed under the first directory and machine-independent packages (e.g., those that contain only Tcl scripts) should be installed under the second directory. The subdirectory should include the package's script and/or binary files as well as the \fBpkgIndex.tcl\fR file. As long as the package is installed as a subdirectory of a directory in \fB$tcl_pkgPath\fR it will automatically be found during \fBpackage require\fR commands. .br If you install the package anywhere else, then you must ensure that the directory containing the package is in the \fBauto_path\fR global variable or an immediate subdirectory of one of the directories in \fBauto_path\fR. \fBAuto_path\fR contains a list of directories that are searched by both the auto-loader and the package loader; by default it includes \fB$tcl_pkgPath\fR. The package loader also checks all of the subdirectories of the directories in \fBauto_path\fR. You can add a directory to \fBauto_path\fR explicitly in your application, or you can add the directory to your \fBTCLLIBPATH\fR environment variable: if this environment variable is present, Tcl initializes \fBauto_path\fR from it during application startup. .IP [4] Once the above steps have been taken, all you need to do to use a package is to invoke \fBpackage require\fR. For example, if versions 2.1, 2.3, and 3.1 of package \fBTest\fR have been indexed by \fBpkg_mkIndex\fR, the command \fBpackage require Test\fR will make version 3.1 available and the command \fBpackage require \-exact Test 2.1\fR will make version 2.1 available. There may be many versions of a package in the various index files in \fBauto_path\fR, but only one will actually be loaded in a given interpreter, based on the first call to \fBpackage require\fR. Different versions of a package may be loaded in different interpreters. .SH OPTIONS The optional switches are: .TP 15 \fB\-direct\fR The generated index will implement direct loading of the package upon \fBpackage require\fR. This is the default. .TP 15 \fB\-lazy\fR The generated index will manage to delay loading the package until the use of one of the commands provided by the package, instead of loading it immediately upon \fBpackage require\fR. .TP 15 \fB\-load \fIpkgPat\fR The index process will pre-load any packages that exist in the current interpreter and match \fIpkgPat\fP into the slave interpreter used to generate the index. The pattern match uses string match rules, but without making case distinctions. See COMPLEX CASES below. .TP 15 \fB\-verbose\fR Generate output during the indexing process. Output is via the \fBtclLog\fP procedure, which by default prints to stderr. .TP 15 \fB\-\-\fR End of the flags, in case \fIdir\fP begins with a dash. .SH "PACKAGES AND THE AUTO-LOADER" .PP The package management facilities overlap somewhat with the auto-loader, in that both arrange for files to be loaded on-demand. However, package management is a higher-level mechanism that uses the auto-loader for the last step in the loading process. It is generally better to index a package with \fBpkg_mkIndex\fR rather than \fBauto_mkindex\fR because the package mechanism provides version control: several versions of a package can be made available in the index files, with different applications using different versions based on \fBpackage require\fR commands. In contrast, \fBauto_mkindex\fR does not understand versions so it can only handle a single version of each package. It is probably not a good idea to index a given package with both \fBpkg_mkIndex\fR and \fBauto_mkindex\fR. If you use \fBpkg_mkIndex\fR to index a package, its commands cannot be invoked until \fBpackage require\fR has been used to select a version; in contrast, packages indexed with \fBauto_mkindex\fR can be used immediately since there is no version control. .SH "HOW IT WORKS" .PP \fBPkg_mkIndex\fR depends on the \fBpackage unknown\fR command, the \fBpackage ifneeded\fR command, and the auto-loader. The first time a \fBpackage require\fR command is invoked, the \fBpackage unknown\fR script is invoked. This is set by Tcl initialization to a script that evaluates all of the \fBpkgIndex.tcl\fR files in the \fBauto_path\fR. The \fBpkgIndex.tcl\fR files contain \fBpackage ifneeded\fR commands for each version of each available package; these commands invoke \fBpackage provide\fR commands to announce the availability of the package, and they setup auto-loader information to load the files of the package. .VS 8.3 If the \fI\-lazy\fR flag was provided when the \fBpkgIndex.tcl\fR was generated, .VE a given file of a given version of a given package isn't actually loaded until the first time one of its commands is invoked. Thus, after invoking \fBpackage require\fR you may not see the package's commands in the interpreter, but you will be able to invoke the commands and they will be auto-loaded. .VS 8.3 .SH "DIRECT LOADING" .PP Some packages, for instance packages which use namespaces and export commands or those which require special initialization, might select that their package files be loaded immediately upon \fBpackage require\fR instead of delaying the actual loading to the first use of one of the package's command. This is the default mode when generating the package index. It can be overridden by specifying the \fI\-lazy\fR argument. .VE .SH "COMPLEX CASES" Most complex cases of dependencies among scripts and binary files, and packages being split among scripts and binary files are handled OK. However, you may have to adjust the order in which files are processed by \fBpkg_mkIndex\fR. These issues are described in detail below. .PP If each script or file contains one package, and packages are only contained in one file, then things are easy. You simply specify all files to be indexed in any order with some glob patterns. .PP In general, it is OK for scripts to have dependencies on other packages. If scripts contain \fBpackage require\fP commands, these are stubbed out in the interpreter used to process the scripts, so these do not cause problems. If scripts call into other packages in global code, these calls are handled by a stub \fBunknown\fP command. However, if scripts make variable references to other package's variables in global code, these will cause errors. That is also bad coding style. .PP If binary files have dependencies on other packages, things can become tricky because it is not possible to stub out C-level APIs such as \fBTcl_PkgRequire\fP API when loading a binary file. For example, suppose the BLT package requires Tk, and expresses this with a call to \fBTcl_PkgRequire\fP in its \fBBlt_Init\fP routine. To support this, you must run \fBpkg_mkIndex\fR in an interpreter that has Tk loaded. You can achieve this with the \fB\-load \fIpkgPat\fR option. If you specify this option, \fBpkg_mkIndex\fR will load any packages listed by \fBinfo loaded\fP and that match \fIpkgPat\fP into the interpreter used to process files. In most cases this will satisfy the \fBTcl_PkgRequire\fP calls made by binary files. .PP If you are indexing two binary files and one depends on the other, you should specify the one that has dependencies last. This way the one without dependencies will get loaded and indexed, and then the package it provides will be available when the second file is processed. You may also need to load the first package into the temporary interpreter used to create the index by using the \fB\-load\fP flag; it won't hurt to specify package patterns that are not yet loaded. .PP If you have a package that is split across scripts and a binary file, then you should avoid the \fB\-load\fP flag. The problem is that if you load a package before computing the index it masks any other files that provide part of the same package. If you must use \fB\-load\fP, then you must specify the scripts first; otherwise the package loaded from the binary file may mask the package defined by the scripts. .SH "SEE ALSO" package(n) .SH KEYWORDS auto-load, index, package, version tcl8.4.20/doc/Notifier.30000644003604700454610000006577311737050674013351 0ustar dgp771div'\" '\" Copyright (c) 1998-1999 Scriptics Corporation '\" Copyright (c) 1995-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Notifier 3 8.1 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_CreateEventSource, Tcl_DeleteEventSource, Tcl_SetMaxBlockTime, Tcl_QueueEvent, Tcl_ThreadQueueEvent, Tcl_ThreadAlert, Tcl_GetCurrentThread, Tcl_DeleteEvents, Tcl_InitNotifier, Tcl_FinalizeNotifier, Tcl_WaitForEvent, Tcl_AlertNotifier, Tcl_SetTimer, Tcl_ServiceAll, Tcl_ServiceEvent, Tcl_GetServiceMode, Tcl_SetServiceMode \- the event queue and notifier interfaces .SH SYNOPSIS .nf \fB#include \fR .sp void \fBTcl_CreateEventSource\fR(\fIsetupProc, checkProc, clientData\fR) .sp void \fBTcl_DeleteEventSource\fR(\fIsetupProc, checkProc, clientData\fR) .sp void \fBTcl_SetMaxBlockTime\fR(\fItimePtr\fR) .sp void \fBTcl_QueueEvent\fR(\fIevPtr, position\fR) .VS 8.1 .sp void \fBTcl_ThreadQueueEvent\fR(\fIthreadId, evPtr, position\fR) .sp void \fBTcl_ThreadAlert\fR(\fIthreadId\fR) .sp Tcl_ThreadId \fBTcl_GetCurrentThread\fR() .sp void \fBTcl_DeleteEvents\fR(\fIdeleteProc, clientData\fR) .sp ClientData \fBTcl_InitNotifier\fR() .sp void \fBTcl_FinalizeNotifier\fR(\fIclientData\fR) .sp int \fBTcl_WaitForEvent\fR(\fItimePtr\fR) .sp void \fBTcl_AlertNotifier\fR(\fIclientData\fR) .sp void \fBTcl_SetTimer\fR(\fItimePtr\fR) .sp int \fBTcl_ServiceAll\fR() .sp int \fBTcl_ServiceEvent\fR(\fIflags\fR) .sp int \fBTcl_GetServiceMode\fR() .sp int \fBTcl_SetServiceMode\fR(\fImode\fR) .VE .SH ARGUMENTS .AS Tcl_EventDeleteProc milliseconds .AP Tcl_EventSetupProc *setupProc in Procedure to invoke to prepare for event wait in \fBTcl_DoOneEvent\fR. .AP Tcl_EventCheckProc *checkProc in Procedure for \fBTcl_DoOneEvent\fR to invoke after waiting for events. Checks to see if any events have occurred and, if so, queues them. .AP ClientData clientData in Arbitrary one-word value to pass to \fIsetupProc\fR, \fIcheckProc\fR, or \fIdeleteProc\fR. .AP Tcl_Time *timePtr in Indicates the maximum amount of time to wait for an event. This is specified as an interval (how long to wait), not an absolute time (when to wakeup). If the pointer passed to \fBTcl_WaitForEvent\fR is NULL, it means there is no maximum wait time: wait forever if necessary. .AP Tcl_Event *evPtr in An event to add to the event queue. The storage for the event must have been allocated by the caller using \fBTcl_Alloc\fR or \fBckalloc\fR. .AP Tcl_QueuePosition position in Where to add the new event in the queue: \fBTCL_QUEUE_TAIL\fR, \fBTCL_QUEUE_HEAD\fR, or \fBTCL_QUEUE_MARK\fR. .AP Tcl_ThreadId threadId in A unique identifier for a thread. .AP Tcl_EventDeleteProc *deleteProc in Procedure to invoke for each queued event in \fBTcl_DeleteEvents\fR. .AP int flags in What types of events to service. These flags are the same as those passed to \fBTcl_DoOneEvent\fR. .VS 8.1 .AP int mode in Indicates whether events should be serviced by \fBTcl_ServiceAll\fR. Must be one of \fBTCL_SERVICE_NONE\fR or \fBTCL_SERVICE_ALL\fR. .VE .BE .SH INTRODUCTION .PP The interfaces described here are used to customize the Tcl event loop. The two most common customizations are to add new sources of events and to merge Tcl's event loop with some other event loop, such as one provided by an application in which Tcl is embedded. Each of these tasks is described in a separate section below. .PP The procedures in this manual entry are the building blocks out of which the Tcl event notifier is constructed. The event notifier is the lowest layer in the Tcl event mechanism. It consists of three things: .IP [1] Event sources: these represent the ways in which events can be generated. For example, there is a timer event source that implements the \fBTcl_CreateTimerHandler\fR procedure and the \fBafter\fR command, and there is a file event source that implements the \fBTcl_CreateFileHandler\fR procedure on Unix systems. An event source must work with the notifier to detect events at the right times, record them on the event queue, and eventually notify higher-level software that they have occurred. The procedures \fBTcl_CreateEventSource\fR, \fBTcl_DeleteEventSource\fR, and \fBTcl_SetMaxBlockTime\fR, \fBTcl_QueueEvent\fR, and \fBTcl_DeleteEvents\fR are used primarily by event sources. .IP [2] The event queue: for non-threaded applications, there is a single queue for the whole application, containing events that have been detected but not yet serviced. Event sources place events onto the queue so that they may be processed in order at appropriate times during the event loop. The event queue guarantees a fair discipline of event handling, so that no event source can starve the others. It also allows events to be saved for servicing at a future time. .VS 8.1 Threaded applications work in a similar manner, except that there is a separate event queue for each thread containing a Tcl interpreter. \fBTcl_QueueEvent\fR is used (primarily by event sources) to add events to the event queue and \fBTcl_DeleteEvents\fR is used to remove events from the queue without processing them. In a threaded application, \fBTcl_QueueEvent\fR adds an event to the current thread's queue, and \fBTcl_ThreadQueueEvent\fR adds an event to a queue in a specific thread. .IP [3] The event loop: in order to detect and process events, the application enters a loop that waits for events to occur, places them on the event queue, and then processes them. Most applications will do this by calling the procedure \fBTcl_DoOneEvent\fR, which is described in a separate manual entry. .PP Most Tcl applications need not worry about any of the internals of the Tcl notifier. However, the notifier now has enough flexibility to be retargeted either for a new platform or to use an external event loop (such as the Motif event loop, when Tcl is embedded in a Motif application). The procedures \fBTcl_WaitForEvent\fR and \fBTcl_SetTimer\fR are normally implemented by Tcl, but may be replaced with new versions to retarget the notifier (the \fBTcl_InitNotifier\fR, \fBTcl_AlertNotifier\fR, \fBTcl_FinalizeNotifier\fR, \fBTcl_Sleep\fR, \fBTcl_CreateFileHandler\fR, and \fBTcl_DeleteFileHandler\fR must also be replaced; see CREATING A NEW NOTIFIER below for details). The procedures \fBTcl_ServiceAll\fR, \fBTcl_ServiceEvent\fR, \fBTcl_GetServiceMode\fR, and \fBTcl_SetServiceMode\fR are provided to help connect Tcl's event loop to an external event loop such as Motif's. .SH "NOTIFIER BASICS" .VE .PP The easiest way to understand how the notifier works is to consider what happens when \fBTcl_DoOneEvent\fR is called. \fBTcl_DoOneEvent\fR is passed a \fIflags\fR argument that indicates what sort of events it is OK to process and also whether or not to block if no events are ready. \fBTcl_DoOneEvent\fR does the following things: .IP [1] Check the event queue to see if it contains any events that can be serviced. If so, service the first possible event, remove it .VS 8.1 from the queue, and return. It does this by calling \fBTcl_ServiceEvent\fR and passing in the \fIflags\fR argument. .VE .IP [2] Prepare to block for an event. To do this, \fBTcl_DoOneEvent\fR invokes a \fIsetup procedure\fR in each event source. The event source will perform event-source specific initialization and .VS 8.1 possibly call \fBTcl_SetMaxBlockTime\fR to limit how long .VE \fBTcl_WaitForEvent\fR will block if no new events occur. .IP [3] Call \fBTcl_WaitForEvent\fR. This procedure is implemented differently on different platforms; it waits for an event to occur, based on the information provided by the event sources. It may cause the application to block if \fItimePtr\fR specifies an interval other than 0. \fBTcl_WaitForEvent\fR returns when something has happened, such as a file becoming readable or the interval given by \fItimePtr\fR expiring. If there are no events for \fBTcl_WaitForEvent\fR to wait for, so that it would block forever, then it returns immediately and \fBTcl_DoOneEvent\fR returns 0. .IP [4] Call a \fIcheck procedure\fR in each event source. The check procedure determines whether any events of interest to this source occurred. If so, the events are added to the event queue. .IP [5] Check the event queue to see if it contains any events that can be serviced. If so, service the first possible event, remove it from the queue, and return. .IP [6] See if there are idle callbacks pending. If so, invoke all of them and return. .IP [7] Either return 0 to indicate that no events were ready, or go back to step [2] if blocking was requested by the caller. .SH "CREATING A NEW EVENT SOURCE" .PP An event source consists of three procedures invoked by the notifier, plus additional C procedures that are invoked by higher-level code to arrange for event-driven callbacks. The three procedures called by the notifier consist of the setup and check procedures described above, plus an additional procedure that is invoked when an event is removed from the event queue for servicing. .PP The procedure \fBTcl_CreateEventSource\fR creates a new event source. Its arguments specify the setup procedure and check procedure for the event source. \fISetupProc\fR should match the following prototype: .CS typedef void Tcl_EventSetupProc( ClientData \fIclientData\fR, int \fIflags\fR); .CE The \fIclientData\fR argument will be the same as the \fIclientData\fR argument to \fBTcl_CreateEventSource\fR; it is typically used to point to private information managed by the event source. The \fIflags\fR argument will be the same as the \fIflags\fR argument passed to \fBTcl_DoOneEvent\fR except that it will never be 0 (\fBTcl_DoOneEvent\fR replaces 0 with \fBTCL_ALL_EVENTS\fR). \fIFlags\fR indicates what kinds of events should be considered; if the bit corresponding to this event source isn't set, the event source should return immediately without doing anything. For example, the file event source checks for the \fBTCL_FILE_EVENTS\fR bit. .PP \fISetupProc\fR's job is to make sure that the application wakes up when events of the desired type occur. This is typically done in a platform-dependent fashion. For example, under Unix an event source might call \fBTcl_CreateFileHandler\fR; under Windows it might request notification with a Windows event. For timer-driven event sources such as timer events or any polled event, the event source can call \fBTcl_SetMaxBlockTime\fR to force the application to wake up after a specified time even if no events have occurred. .VS 8.1 If no event source calls \fBTcl_SetMaxBlockTime\fR then \fBTcl_WaitForEvent\fR will wait as long as necessary for an event to occur; otherwise, it will only wait as long as the shortest interval passed to \fBTcl_SetMaxBlockTime\fR by one of the event sources. If an event source knows that it already has events ready to report, it can request a zero maximum block time. For example, the setup procedure for the X event source looks to see if there are events already queued. If there are, it calls \fBTcl_SetMaxBlockTime\fR with a 0 block time so that \fBTcl_WaitForEvent\fR does not block if there is no new data on the X connection. .VE The \fItimePtr\fR argument to \fBTcl_WaitForEvent\fR points to a structure that describes a time interval in seconds and microseconds: .CS typedef struct Tcl_Time { long \fIsec\fR; long \fIusec\fR; } Tcl_Time; .CE The \fIusec\fR field should be less than 1000000. .PP .VS 8.1 Information provided to \fBTcl_SetMaxBlockTime\fR is only used for the next call to \fBTcl_WaitForEvent\fR; it is discarded after \fBTcl_WaitForEvent\fR returns. .VE The next time an event wait is done each of the event sources' setup procedures will be called again, and they can specify new information for that event wait. .PP .VS 8.1 If the application uses an external event loop rather than \fBTcl_DoOneEvent\fR, the event sources may need to call \fBTcl_SetMaxBlockTime\fR at other times. For example, if a new event handler is registered that needs to poll for events, the event source may call \fBTcl_SetMaxBlockTime\fR to set the block time to zero to force the external event loop to call Tcl. In this case, \fBTcl_SetMaxBlockTime\fR invokes \fBTcl_SetTimer\fR with the shortest interval seen since the last call to \fBTcl_DoOneEvent\fR or \fBTcl_ServiceAll\fR. .PP In addition to the generic procedure \fBTcl_SetMaxBlockTime\fR, other platform-specific procedures may also be available for \fIsetupProc\fR, if there is additional information needed by \fBTcl_WaitForEvent\fR on that platform. For example, on Unix systems the \fBTcl_CreateFileHandler\fR interface can be used to wait for file events. .VE .PP The second procedure provided by each event source is its check procedure, indicated by the \fIcheckProc\fR argument to \fBTcl_CreateEventSource\fR. \fICheckProc\fR must match the following prototype: .CS typedef void Tcl_EventCheckProc( ClientData \fIclientData\fR, int \fIflags\fR); .CE The arguments to this procedure are the same as those for \fIsetupProc\fR. \fBCheckProc\fR is invoked by \fBTcl_DoOneEvent\fR after it has waited for events. Presumably at least one event source is now prepared to queue an event. \fBTcl_DoOneEvent\fR calls each of the event sources in turn, so they all have a chance to queue any events that are ready. The check procedure does two things. First, it must see if any events have triggered. Different event sources do this in different ways. .PP If an event source's check procedure detects an interesting event, it must add the event to Tcl's event queue. To do this, the event source calls \fBTcl_QueueEvent\fR. The \fIevPtr\fR argument is a pointer to a dynamically allocated structure containing the event (see below for more information on memory management issues). Each event source can define its own event structure with whatever information is relevant to that event source. However, the first element of the structure must be a structure of type \fBTcl_Event\fR, and the address of this structure is used when communicating between the event source and the rest of the notifier. A \fBTcl_Event\fR has the following definition: .CS typedef struct { Tcl_EventProc *\fIproc\fR; struct Tcl_Event *\fInextPtr\fR; } Tcl_Event; .CE The event source must fill in the \fIproc\fR field of the event before calling \fBTcl_QueueEvent\fR. The \fInextPtr\fR is used to link together the events in the queue and should not be modified by the event source. .PP An event may be added to the queue at any of three positions, depending on the \fIposition\fR argument to \fBTcl_QueueEvent\fR: .IP \fBTCL_QUEUE_TAIL\fR 24 Add the event at the back of the queue, so that all other pending events will be serviced first. This is almost always the right place for new events. .IP \fBTCL_QUEUE_HEAD\fR 24 Add the event at the front of the queue, so that it will be serviced before all other queued events. .IP \fBTCL_QUEUE_MARK\fR 24 Add the event at the front of the queue, unless there are other events at the front whose position is \fBTCL_QUEUE_MARK\fR; if so, add the new event just after all other \fBTCL_QUEUE_MARK\fR events. This value of \fIposition\fR is used to insert an ordered sequence of events at the front of the queue, such as a series of Enter and Leave events synthesized during a grab or ungrab operation in Tk. .PP .VS 8.1 When it is time to handle an event from the queue (steps 1 and 4 above) \fBTcl_ServiceEvent\fR will invoke the \fIproc\fR specified .VE in the first queued \fBTcl_Event\fR structure. \fIProc\fR must match the following prototype: .CS typedef int Tcl_EventProc( Tcl_Event *\fIevPtr\fR, int \fIflags\fR); .CE The first argument to \fIproc\fR is a pointer to the event, which will be the same as the first argument to the \fBTcl_QueueEvent\fR call that added the event to the queue. The second argument to \fIproc\fR is the \fIflags\fR argument for the .VS 8.1 current call to \fBTcl_ServiceEvent\fR; this is used by the event source .VE to return immediately if its events are not relevant. .PP It is up to \fIproc\fR to handle the event, typically by invoking one or more Tcl commands or C-level callbacks. Once the event source has finished handling the event it returns 1 to indicate that the event can be removed from the queue. If for some reason the event source decides that the event cannot be handled at this time, it may return 0 to indicate that the event .VS 8.1 should be deferred for processing later; in this case \fBTcl_ServiceEvent\fR .VE will go on to the next event in the queue and attempt to service it. There are several reasons why an event source might defer an event. One possibility is that events of this type are excluded by the \fIflags\fR argument. For example, the file event source will always return 0 if the \fBTCL_FILE_EVENTS\fR bit isn't set in \fIflags\fR. Another example of deferring events happens in Tk if \fBTk_RestrictEvents\fR has been invoked to defer certain kinds of window events. .PP .VS 8.1 When \fIproc\fR returns 1, \fBTcl_ServiceEvent\fR will remove the event from the event queue and free its storage. Note that the storage for an event must be allocated by the event source (using \fBTcl_Alloc\fR or the Tcl macro \fBckalloc\fR) before calling \fBTcl_QueueEvent\fR, but it will be freed by \fBTcl_ServiceEvent\fR, not by the event source. .PP Threaded applications work in a similar manner, except that there is a separate event queue for each thread containing a Tcl interpreter. Calling \fBTcl_QueueEvent\fR in a multithreaded application adds an event to the current thread's queue. To add an event to another thread's queue, use \fBTcl_ThreadQueueEvent\fR. \fBTcl_ThreadQueueEvent\fR accepts as an argument a Tcl_ThreadId argument, which uniquely identifies a thread in a Tcl application. To obtain the Tcl_ThreadID for the current thread, use the \fBTcl_GetCurrentThread\fR procedure. (A thread would then need to pass this identifier to other threads for those threads to be able to add events to its queue.) After adding an event to another thread's queue, you then typically need to call \fBTcl_ThreadAlert\fR to "wake up" that thread's notifier to alert it to the new event. .PP \fBTcl_DeleteEvents\fR can be used to explicitly remove one or more events from the event queue. \fBTcl_DeleteEvents\fR calls \fIproc\fR for each event in the queue, deleting those for with the procedure returns 1. Events for which the procedure returns 0 are left in the queue. \fIProc\fR should match the following prototype: .CS typedef int Tcl_EventDeleteProc( Tcl_Event *\fIevPtr\fR, ClientData \fIclientData\fR); .CE The \fIclientData\fR argument will be the same as the \fIclientData\fR argument to \fBTcl_DeleteEvents\fR; it is typically used to point to private information managed by the event source. The \fIevPtr\fR will point to the next event in the queue. .PP \fBTcl_DeleteEventSource\fR deletes an event source. The \fIsetupProc\fR, \fIcheckProc\fR, and \fIclientData\fR arguments must exactly match those provided to the \fBTcl_CreateEventSource\fR for the event source to be deleted. If no such source exists, \fBTcl_DeleteEventSource\fR has no effect. .VE .SH "CREATING A NEW NOTIFIER" .PP The notifier consists of all the procedures described in this manual entry, plus \fBTcl_DoOneEvent\fR and \fBTcl_Sleep\fR, which are .VS 8.1 available on all platforms, and \fBTcl_CreateFileHandler\fR and \fBTcl_DeleteFileHandler\fR, which are Unix-specific. Most of these procedures are generic, in that they are the same for all notifiers. However, eight of the procedures are notifier-dependent: \fBTcl_InitNotifier\fR, \fBTcl_AlertNotifier\fR, \fBTcl_FinalizeNotifier\fR, \fBTcl_SetTimer\fR, \fBTcl_Sleep\fR, \fBTcl_WaitForEvent\fR, \fBTcl_CreateFileHandler\fR and \fBTcl_DeleteFileHandler\fR. To support a new platform or to integrate Tcl with an application-specific event loop, you must write new versions of these procedures. .PP \fBTcl_InitNotifier\fR initializes the notifier state and returns a handle to the notifier state. Tcl calls this procedure when initializing a Tcl interpreter. Similarly, \fBTcl_FinalizeNotifier\fR shuts down the notifier, and is called by \fBTcl_Finalize\fR when shutting down a Tcl interpreter. .PP \fBTcl_WaitForEvent\fR is the lowest-level procedure in the notifier; it is responsible for waiting for an ``interesting'' event to occur or for a given time to elapse. Before \fBTcl_WaitForEvent\fR is invoked, each of the event sources' setup procedure will have been invoked. The \fItimePtr\fR argument to \fBTcl_WaitForEvent\fR gives the maximum time to block for an event, based on calls to \fBTcl_SetMaxBlockTime\fR made by setup procedures and on other information (such as the \fBTCL_DONT_WAIT\fR bit in \fIflags\fR). .PP Ideally, \fBTcl_WaitForEvent\fR should only wait for an event to occur; it should not actually process the event in any way. Later on, the event sources will process the raw events and create Tcl_Events on the event queue in their \fIcheckProc\fR procedures. However, on some platforms (such as Windows) this isn't possible; events may be processed in \fBTcl_WaitForEvent\fR, including queuing Tcl_Events and more (for example, callbacks for native widgets may be invoked). The return value from \fBTcl_WaitForEvent\fR must be either 0, 1, or \-1. On platforms such as Windows where events get processed in \fBTcl_WaitForEvent\fR, a return value of 1 means that there may be more events still pending that haven't been processed. This is a sign to the caller that it must call \fBTcl_WaitForEvent\fR again if it wants all pending events to be processed. A 0 return value means that calling \fBTcl_WaitForEvent\fR again will not have any effect: either this is a platform where \fBTcl_WaitForEvent\fR only waits without doing any event processing, or \fBTcl_WaitForEvent\fR knows for sure that there are no additional events to process (e.g. it returned because the time elapsed). Finally, a return value of \-1 means that the event loop is no longer operational and the application should probably unwind and terminate. Under Windows this happens when a WM_QUIT message is received; under Unix it happens when \fBTcl_WaitForEvent\fR would have waited forever because there were no active event sources and the timeout was infinite. .PP \fBTcl_AlertNotifier\fR is used in multithreaded applications to allow any thread to "wake up" the notifier to alert it to new events on its queue. \fBTcl_AlertNotifier\fR requires as an argument the notifier handle returned by \fBTcl_InitNotifier\fR. .PP If the notifier will be used with an external event loop, then it must also support the \fBTcl_SetTimer\fR interface. \fBTcl_SetTimer\fR is invoked by \fBTcl_SetMaxBlockTime\fR whenever the maximum blocking time has been reduced. \fBTcl_SetTimer\fR should arrange for the external event loop to invoke \fBTcl_ServiceAll\fR after the specified interval even if no events have occurred. This interface is needed because \fBTcl_WaitForEvent\fR isn't invoked when there is an external event loop. If the notifier will only be used from \fBTcl_DoOneEvent\fR, then \fBTcl_SetTimer\fR need not do anything. .PP On Unix systems, the file event source also needs support from the notifier. The file event source consists of the \fBTcl_CreateFileHandler\fR and \fBTcl_DeleteFileHandler\fR procedures, which are described in the \fBTcl_CreateFileHandler\fR manual page. .PP The \fBTcl_Sleep\fR and \fBTcl_DoOneEvent\fR interfaces are described in their respective manual pages. .PP The easiest way to create a new notifier is to look at the code for an existing notifier, such as the files \fBunix/tclUnixNotfy.c\fR or \fBwin/tclWinNotify.c\fR in the Tcl source distribution. .SH "EXTERNAL EVENT LOOPS" .PP The notifier interfaces are designed so that Tcl can be embedded into applications that have their own private event loops. In this case, the application does not call \fBTcl_DoOneEvent\fR except in the case of recursive event loops such as calls to the Tcl commands \fBupdate\fR or \fBvwait\fR. Most of the time is spent in the external event loop of the application. In this case the notifier must arrange for the external event loop to call back into Tcl when something happens on the various Tcl event sources. These callbacks should arrange for appropriate Tcl events to be placed on the Tcl event queue. .PP Because the external event loop is not calling \fBTcl_DoOneEvent\fR on a regular basis, it is up to the notifier to arrange for \fBTcl_ServiceEvent\fR to be called whenever events are pending on the Tcl event queue. The easiest way to do this is to invoke \fBTcl_ServiceAll\fR at the end of each callback from the external event loop. This will ensure that all of the event sources are polled, any queued events are serviced, and any pending idle handlers are processed before returning control to the application. In addition, event sources that need to poll for events can call \fBTcl_SetMaxBlockTime\fR to force the external event loop to call Tcl even if no events are available on the system event queue. .PP As a side effect of processing events detected in the main external event loop, Tcl may invoke \fBTcl_DoOneEvent\fR to start a recursive event loop in commands like \fBvwait\fR. \fBTcl_DoOneEvent\fR will invoke the external event loop, which will result in callbacks as described in the preceding paragraph, which will result in calls to \fBTcl_ServiceAll\fR. However, in these cases it is undesirable to service events in \fBTcl_ServiceAll\fR. Servicing events there is unnecessary because control will immediately return to the external event loop and hence to \fBTcl_DoOneEvent\fR, which can service the events itself. Furthermore, \fBTcl_DoOneEvent\fR is supposed to service only a single event, whereas \fBTcl_ServiceAll\fR normally services all pending events. To handle this situation, \fBTcl_DoOneEvent\fR sets a flag for \fBTcl_ServiceAll\fR that causes it to return without servicing any events. This flag is called the \fIservice mode\fR; \fBTcl_DoOneEvent\fR restores it to its previous value before it returns. .PP In some cases, however, it may be necessary for \fBTcl_ServiceAll\fR to service events even when it has been invoked from \fBTcl_DoOneEvent\fR. This happens when there is yet another recursive event loop invoked via an event handler called by \fBTcl_DoOneEvent\fR (such as one that is part of a native widget). In this case, \fBTcl_DoOneEvent\fR may not have a chance to service events so \fBTcl_ServiceAll\fR must service them all. Any recursive event loop that calls an external event loop rather than \fBTcl_DoOneEvent\fR must reset the service mode so that all events get processed in \fBTcl_ServiceAll\fR. This is done by invoking the \fBTcl_SetServiceMode\fR procedure. If \fBTcl_SetServiceMode\fR is passed \fBTCL_SERVICE_NONE\fR, then calls to \fBTcl_ServiceAll\fR will return immediately without processing any events. If \fBTcl_SetServiceMode\fR is passed \fBTCL_SERVICE_ALL\fR, then calls to \fBTcl_ServiceAll\fR will behave normally. \fBTcl_SetServiceMode\fR returns the previous value of the service mode, which should be restored when the recursive loop exits. \fBTcl_GetServiceMode\fR returns the current value of the service mode. .VE .SH "SEE ALSO" \fBTcl_CreateFileHandler\fR, \fBTcl_DeleteFileHandler\fR, \fBTcl_Sleep\fR, \fBTcl_DoOneEvent\fR, \fBThread(3)\fR .SH KEYWORDS event, notifier, event queue, event sources, file events, timer, idle, service mode, threads tcl8.4.20/doc/registry.n0000644003604700454610000001630611737050674013521 0ustar dgp771div'\" '\" Copyright (c) 1997 Sun Microsystems, Inc. '\" Copyright (c) 2002 ActiveState Corporation. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH registry n 1.1 registry "Tcl Bundled Packages" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME registry \- Manipulate the Windows registry .SH SYNOPSIS .sp \fBpackage require registry 1.1\fR .sp \fBregistry \fIoption\fR \fIkeyName\fR ?\fIarg arg ...\fR? .BE .SH DESCRIPTION .PP The \fBregistry\fR package provides a general set of operations for manipulating the Windows registry. The package implements the \fBregistry\fR Tcl command. This command is only supported on the Windows platform. Warning: this command should be used with caution as a corrupted registry can leave your system in an unusable state. .PP \fIKeyName\fR is the name of a registry key. Registry keys must be one of the following forms: .IP \fB\e\e\fIhostname\fB\e\fIrootname\fB\e\fIkeypath\fR .IP \fIrootname\fB\e\fIkeypath\fR .IP \fIrootname\fR .PP \fIHostname\fR specifies the name of any valid Windows host that exports its registry. The \fIrootname\fR component must be one of \fBHKEY_LOCAL_MACHINE\fR, \fBHKEY_USERS\fR, .VS \fBHKEY_CLASSES_ROOT\fR, \fBHKEY_CURRENT_USER\fR, \fBHKEY_CURRENT_CONFIG\fR, \fBHKEY_PERFORMANCE_DATA\fR, or \fBHKEY_DYN_DATA\fR. The \fIkeypath\fR can be one or more .VE registry key names separated by backslash (\fB\e\fR) characters. .PP \fIOption\fR indicates what to do with the registry key name. Any unique abbreviation for \fIoption\fR is acceptable. The valid options are: .VS 8.4 .TP \fBregistry broadcast \fIkeyName\fR ?\fI-timeout milliseconds\fR? . Sends a broadcast message to the system and running programs to notify them of certain updates. This is necessary to propagate changes to key registry keys like Environment. The timeout specifies the amount of time, in milliseconds, to wait for applications to respond to the broadcast message. It defaults to 3000. The following example demonstrates how to add a path to the global Environment and notify applications of the change without requiring a logoff/logon step (assumes admin privileges): .CS set regPath {HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment} set curPath [registry get $regPath "Path"] registry set $regPath "Path" "$curPath;$addPath" registry broadcast "Environment" .CE .VE 8.4 .TP \fBregistry delete \fIkeyName\fR ?\fIvalueName\fR? . If the optional \fIvalueName\fR argument is present, the specified value under \fIkeyName\fR will be deleted from the registry. If the optional \fIvalueName\fR is omitted, the specified key and any subkeys or values beneath it in the registry hierarchy will be deleted. If the key could not be deleted then an error is generated. If the key did not exist, the command has no effect. .TP \fBregistry get \fIkeyName valueName\fR . Returns the data associated with the value \fIvalueName\fR under the key \fIkeyName\fR. If either the key or the value does not exist, then an error is generated. For more details on the format of the returned data, see SUPPORTED TYPES, below. .TP \fBregistry keys \fIkeyName\fR ?\fIpattern\fR? . If \fIpattern\fR isn't specified, returns a list of names of all the subkeys of \fIkeyName\fR. If \fIpattern\fR is specified, only those names matching \fIpattern\fR are returned. Matching is determined using the same rules as for \fBstring\fR \fBmatch\fR. If the specified \fIkeyName\fR does not exist, then an error is generated. .TP \fBregistry set \fIkeyName\fR ?\fIvalueName data \fR?\fItype\fR?? . If \fIvalueName\fR isn't specified, creates the key \fIkeyName\fR if it doesn't already exist. If \fIvalueName\fR is specified, creates the key \fIkeyName\fR and value \fIvalueName\fR if necessary. The contents of \fIvalueName\fR are set to \fIdata\fR with the type indicated by \fItype\fR. If \fItype\fR isn't specified, the type \fBsz\fR is assumed. For more details on the data and type arguments, see SUPPORTED TYPES below. .TP \fBregistry type \fIkeyName valueName\fR . Returns the type of the value \fIvalueName\fR in the key \fIkeyName\fR. For more information on the possible types, see SUPPORTED TYPES, below. .TP \fBregistry values \fIkeyName\fR ?\fIpattern\fR? . If \fIpattern\fR isn't specified, returns a list of names of all the values of \fIkeyName\fR. If \fIpattern\fR is specified, only those names matching \fIpattern\fR are returned. Matching is determined using the same rules as for \fBstring\fR \fBmatch\fR. .SH "SUPPORTED TYPES" Each value under a key in the registry contains some data of a particular type in a type-specific representation. The \fBregistry\fR command converts between this internal representation and one that can be manipulated by Tcl scripts. In most cases, the data is simply returned as a Tcl string. The type indicates the intended use for the data, but does not actually change the representation. For some types, the \fBregistry\fR command returns the data in a different form to make it easier to manipulate. The following types are recognized by the registry command: .TP 17 \fBbinary\fR . The registry value contains arbitrary binary data. The data is represented exactly in Tcl, including any embedded nulls. .TP \fBnone\fR . The registry value contains arbitrary binary data with no defined type. The data is represented exactly in Tcl, including any embedded nulls. .TP \fBsz\fR . The registry value contains a null-terminated string. The data is represented in Tcl as a string. .TP \fBexpand_sz\fR . The registry value contains a null-terminated string that contains unexpanded references to environment variables in the normal Windows style (for example, "%PATH%"). The data is represented in Tcl as a string. .TP \fBdword\fR . The registry value contains a little-endian 32-bit number. The data is represented in Tcl as a decimal string. .TP \fBdword_big_endian\fR . The registry value contains a big-endian 32-bit number. The data is represented in Tcl as a decimal string. .TP \fBlink\fR . The registry value contains a symbolic link. The data is represented exactly in Tcl, including any embedded nulls. .TP \fBmulti_sz\fR . The registry value contains an array of null-terminated strings. The data is represented in Tcl as a list of strings. .TP \fBresource_list\fR . The registry value contains a device-driver resource list. The data is represented exactly in Tcl, including any embedded nulls. .PP In addition to the symbolically named types listed above, unknown types are identified using a 32-bit integer that corresponds to the type code returned by the system interfaces. In this case, the data is represented exactly in Tcl, including any embedded nulls. .SH "PORTABILITY ISSUES" The registry command is only available on Windows. .SH EXAMPLE Print out how double-clicking on a Tcl script file will invoke a Tcl interpreter: .CS package require registry set ext .tcl # Read the type name set type [\fBregistry get\fR HKEY_CLASSES_ROOT\e\e$ext {}] # Work out where to look for the command set path HKEY_CLASSES_ROOT\e\e$type\e\eShell\e\eOpen\e\ecommand # Read the command! set command [\fBregistry get\fR $path {}] puts "$ext opens with $command" .CE .SH KEYWORDS registry tcl8.4.20/doc/fcopy.n0000644003604700454610000001212111737050674012760 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH fcopy n 8.0 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME fcopy \- Copy data from one channel to another. .SH SYNOPSIS \fBfcopy \fIinchan\fR \fIoutchan\fR ?\fB\-size \fIsize\fR? ?\fB\-command \fIcallback\fR? .BE .SH DESCRIPTION .PP The \fBfcopy\fP command copies data from one I/O channel, \fIinchan\fR to another I/O channel, \fIoutchan\fR. The \fBfcopy\fP command leverages the buffering in the Tcl I/O system to avoid extra copies and to avoid buffering too much data in main memory when copying large files to slow destinations like network sockets. .PP The \fBfcopy\fP command transfers data from \fIinchan\fR until end of file or \fIsize\fP bytes have been transferred. If no \fB\-size\fP argument is given, then the copy goes until end of file. All the data read from \fIinchan\fR is copied to \fIoutchan\fR. Without the \fB\-command\fP option, \fBfcopy\fP blocks until the copy is complete and returns the number of bytes written to \fIoutchan\fR. .PP The \fB\-command\fP argument makes \fBfcopy\fP work in the background. In this case it returns immediately and the \fIcallback\fP is invoked later when the copy completes. The \fIcallback\fP is called with one or two additional arguments that indicates how many bytes were written to \fIoutchan\fR. If an error occurred during the background copy, the second argument is the error string associated with the error. With a background copy, it is not necessary to put \fIinchan\fR or \fIoutchan\fR into non-blocking mode; the \fBfcopy\fP command takes care of that automatically. However, it is necessary to enter the event loop by using the \fBvwait\fP command or by using Tk. .PP You are not allowed to do other I/O operations with \fIinchan\fR or \fIoutchan\fR during a background fcopy. If either \fIinchan\fR or \fIoutchan\fR get closed while the copy is in progress, the current copy is stopped and the command callback is \fInot\fP made. If \fIinchan\fR is closed, then all data already queued for \fIoutchan\fR is written out. .PP Note that \fIinchan\fR can become readable during a background copy. You should turn off any \fBfileevent\fP handlers during a background copy so those handlers do not interfere with the copy. Any I/O attempted by a \fBfileevent\fP handler will get a "channel busy" error. .PP \fBFcopy\fR translates end-of-line sequences in \fIinchan\fR and \fIoutchan\fR according to the \fB\-translation\fR option for these channels. See the manual entry for \fBfconfigure\fR for details on the \fB\-translation\fR option. The translations mean that the number of bytes read from \fIinchan\fR can be different than the number of bytes written to \fIoutchan\fR. Only the number of bytes written to \fIoutchan\fR is reported, either as the return value of a synchronous \fBfcopy\fP or as the argument to the callback for an asynchronous \fBfcopy\fP. .PP \fBFcopy\fR obeys the encodings configured for the channels. This means that the incoming characters are converted internally first UTF-8 and then into the encoding of the channel \fBfcopy\fR writes to. See the manual entry for \fBfconfigure\fR for details on the \fB\-encoding\fR option. No conversion is done if both channels are set to encoding "binary". If only the output channel is set to encoding "binary" the system will write the internal UTF-8 representation of the incoming characters. If only the input channel is set to encoding "binary" the system will assume that the incoming bytes are valid UTF-8 characters and convert them according to the output encoding. The behaviour of the system for bytes which are not valid UTF-8 characters is undefined in this case. .SH EXAMPLE .PP This first example shows how the callback gets passed the number of bytes transferred. It also uses vwait to put the application into the event loop. Of course, this simplified example could be done without the command callback. .DS proc Cleanup {in out bytes {error {}}} { global total set total $bytes close $in close $out if {[string length $error] != 0} { # error occurred during the copy } } set in [open $file1] set out [socket $server $port] fcopy $in $out -command [list Cleanup $in $out] vwait total .DE .PP The second example copies in chunks and tests for end of file in the command callback .DS proc CopyMore {in out chunk bytes {error {}}} { global total done incr total $bytes if {([string length $error] != 0) || [eof $in]} { set done $total close $in close $out } else { fcopy $in $out -command [list CopyMore $in $out $chunk] \\ -size $chunk } } set in [open $file1] set out [socket $server $port] set chunk 1024 set total 0 fcopy $in $out -command [list CopyMore $in $out $chunk] -size $chunk vwait done .DE .SH "SEE ALSO" eof(n), fblocked(n), fconfigure(n) .SH KEYWORDS blocking, channel, end of line, end of file, nonblocking, read, translation tcl8.4.20/doc/DoWhenIdle.30000644003604700454610000000637011737050674013540 0ustar dgp771div'\" '\" Copyright (c) 1990 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_DoWhenIdle 3 7.5 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_DoWhenIdle, Tcl_CancelIdleCall \- invoke a procedure when there are no pending events .SH SYNOPSIS .nf \fB#include \fR .sp \fBTcl_DoWhenIdle\fR(\fIproc, clientData\fR) .sp \fBTcl_CancelIdleCall\fR(\fIproc, clientData\fR) .SH ARGUMENTS .AS Tcl_IdleProc clientData .AP Tcl_IdleProc *proc in Procedure to invoke. .AP ClientData clientData in Arbitrary one-word value to pass to \fIproc\fR. .BE .SH DESCRIPTION .PP \fBTcl_DoWhenIdle\fR arranges for \fIproc\fR to be invoked when the application becomes idle. The application is considered to be idle when \fBTcl_DoOneEvent\fR has been called, couldn't find any events to handle, and is about to go to sleep waiting for an event to occur. At this point all pending \fBTcl_DoWhenIdle\fR handlers are invoked. For each call to \fBTcl_DoWhenIdle\fR there will be a single call to \fIproc\fR; after \fIproc\fR is invoked the handler is automatically removed. \fBTcl_DoWhenIdle\fR is only usable in programs that use \fBTcl_DoOneEvent\fR to dispatch events. .PP \fIProc\fR should have arguments and result that match the type \fBTcl_IdleProc\fR: .CS typedef void Tcl_IdleProc(ClientData \fIclientData\fR); .CE The \fIclientData\fR parameter to \fIproc\fR is a copy of the \fIclientData\fR argument given to \fBTcl_DoWhenIdle\fR. Typically, \fIclientData\fR points to a data structure containing application-specific information about what \fIproc\fR should do. .PP \fBTcl_CancelIdleCall\fR may be used to cancel one or more previous calls to \fBTcl_DoWhenIdle\fR: if there is a \fBTcl_DoWhenIdle\fR handler registered for \fIproc\fR and \fIclientData\fR, then it is removed without invoking it. If there is more than one handler on the idle list that refers to \fIproc\fR and \fIclientData\fR, all of the handlers are removed. If no existing handlers match \fIproc\fR and \fIclientData\fR then nothing happens. .PP \fBTcl_DoWhenIdle\fR is most useful in situations where (a) a piece of work will have to be done but (b) it's possible that something will happen in the near future that will change what has to be done or require something different to be done. \fBTcl_DoWhenIdle\fR allows the actual work to be deferred until all pending events have been processed. At this point the exact work to be done will presumably be known and it can be done exactly once. .PP For example, \fBTcl_DoWhenIdle\fR might be used by an editor to defer display updates until all pending commands have been processed. Without this feature, redundant redisplays might occur in some situations, such as the processing of a command file. .SH BUGS .PP At present it is not safe for an idle callback to reschedule itself continuously. This will interact badly with certain features of Tk that attempt to wait for all idle callbacks to complete. If you would like for an idle callback to reschedule itself continuously, it is better to use a timer handler with a zero timeout period. .SH KEYWORDS callback, defer, idle callback tcl8.4.20/doc/WrongNumArgs.30000644003604700454610000000545211737050674014147 0ustar dgp771div'\" '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_WrongNumArgs 3 8.0 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_WrongNumArgs \- generate standard error message for wrong number of arguments .SH SYNOPSIS .nf \fB#include \fR .sp \fBTcl_WrongNumArgs\fR(\fIinterp, objc, objv, message\fR) .SH ARGUMENTS .AS Tcl_Interp "*CONST objv[]" .AP Tcl_Interp interp in Interpreter in which error will be reported: error message gets stored in its result object. .AP int objc in Number of leading arguments from \fIobjv\fR to include in error message. .AP Tcl_Obj "*CONST\ objv[]" in Arguments to command that had the wrong number of arguments. .AP "CONST char" *message in Additional error information to print after leading arguments from \fIobjv\fR. This typically gives the acceptable syntax of the command. This argument may be NULL. .BE .SH DESCRIPTION .PP \fBTcl_WrongNumArgs\fR is a utility procedure that is invoked by command procedures when they discover that they have received the wrong number of arguments. \fBTcl_WrongNumArgs\fR generates a standard error message and stores it in the result object of \fIinterp\fR. The message includes the \fIobjc\fR initial elements of \fIobjv\fR plus \fImessage\fR. For example, if \fIobjv\fR consists of the values \fBfoo\fR and \fBbar\fR, \fIobjc\fR is 1, and \fImessage\fR is ``\fBfileName count\fR'' then \fIinterp\fR's result object will be set to the following string: .CS wrong # args: should be "foo fileName count" .CE If \fIobjc\fR is 2, the result will be set to the following string: .CS wrong # args: should be "foo bar fileName count" .CE \fIObjc\fR is usually 1, but may be 2 or more for commands like \fBstring\fR and the Tk widget commands, which use the first argument as a subcommand. .PP Some of the objects in the \fIobjv\fR array may be abbreviations for a subcommand. The command \fBTcl_GetIndexFromObj\fR will convert the abbreviated string object into an \fIindexObject\fR. If an error occurs in the parsing of the subcommand we would like to use the full subcommand name rather than the abbreviation. If the \fBTcl_WrongNumArgs\fR command finds any \fIindexObjects\fR in the \fIobjv\fR array it will use the full subcommand name in the error message instead of the abbreviated name that was originally passed in. Using the above example, lets assume that \fIbar\fR is actually an abbreviation for \fIbarfly\fR and the object is now an indexObject because it was passed to \fBTcl_GetIndexFromObj\fR. In this case the error message would be: .CS wrong # args: should be "foo barfly fileName count" .CE .SH "SEE ALSO" Tcl_GetIndexFromObj .SH KEYWORDS command, error message, wrong number of arguments tcl8.4.20/doc/puts.n0000644003604700454610000000654012052456743012641 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH puts n 7.5 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME puts \- Write to a channel .SH SYNOPSIS \fBputs \fR?\fB\-nonewline\fR? ?\fIchannelId\fR? \fIstring\fR .BE .SH DESCRIPTION .PP Writes the characters given by \fIstring\fR to the channel given by \fIchannelId\fR. .PP .VS \fIChannelId\fR must be an identifier for an open channel such as a Tcl standard channel (\fBstdout\fR or \fBstderr\fR), the return value from an invocation of \fBopen\fR or \fBsocket\fR, or the result of a channel creation command provided by a Tcl extension. The channel must have been opened for output. .VE .PP If no \fIchannelId\fR is specified then it defaults to \fBstdout\fR. \fBPuts\fR normally outputs a newline character after \fIstring\fR, but this feature may be suppressed by specifying the \fB\-nonewline\fR switch. .PP Newline characters in the output are translated by \fBputs\fR to platform-specific end-of-line sequences according to the current value of the \fB\-translation\fR option for the channel (for example, on PCs newlines are normally replaced with carriage-return-linefeed sequences). See the \fBfconfigure\fR manual entry for a discussion on ways in which \fBfconfigure\fR will alter output. .PP Tcl buffers output internally, so characters written with \fBputs\fR may not appear immediately on the output file or device; Tcl will normally delay output until the buffer is full or the channel is closed. You can force output to appear immediately with the \fBflush\fR command. .PP When the output buffer fills up, the \fBputs\fR command will normally block until all the buffered data has been accepted for output by the operating system. If \fIchannelId\fR is in nonblocking mode then the \fBputs\fR command will not block even if the operating system cannot accept the data. Instead, Tcl continues to buffer the data and writes it in the background as fast as the underlying file or device can accept it. The application must use the Tcl event loop for nonblocking output to work; otherwise Tcl never finds out that the file or device is ready for more output data. It is possible for an arbitrarily large amount of data to be buffered for a channel in nonblocking mode, which could consume a large amount of memory. To avoid wasting memory, nonblocking I/O should normally be used in an event-driven fashion with the \fBfileevent\fR command (don't invoke \fBputs\fR unless you have recently been notified via a file event that the channel is ready for more output data). .SH EXAMPLES Write a short message to the console (or wherever \fBstdout\fR is directed): .CS \fBputs\fR "Hello, World!" .CE .PP Print a message in several parts: .CS \fBputs\fR -nonewline "Hello, " \fBputs\fR "World!" .CE .PP Print a message to the standard error channel: .CS \fBputs\fR stderr "Hello, World!" .CE .PP Append a log message to a file: .CS set chan [open my.log a] set timestamp [clock format [clock seconds]] \fBputs\fR $chan "$timestamp - Hello, World!" close $chan .CE .SH "SEE ALSO" file(n), fileevent(n), Tcl_StandardChannels(3) .SH KEYWORDS channel, newline, output, write tcl8.4.20/doc/after.n0000644003604700454610000001251211737050674012745 0ustar dgp771div'\" '\" Copyright (c) 1990-1994 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH after n 7.5 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME after \- Execute a command after a time delay .SH SYNOPSIS \fBafter \fIms\fR .sp \fBafter \fIms \fR?\fIscript script script ...\fR? .sp \fBafter cancel \fIid\fR .sp \fBafter cancel \fIscript script script ...\fR .sp \fBafter idle \fR?\fIscript script script ...\fR? .sp \fBafter info \fR?\fIid\fR? .BE .SH DESCRIPTION .PP This command is used to delay execution of the program or to execute a command in background sometime in the future. It has several forms, depending on the first argument to the command: .TP \fBafter \fIms\fR \fIMs\fR must be an integer giving a time in milliseconds. The command sleeps for \fIms\fR milliseconds and then returns. While the command is sleeping the application does not respond to events. .TP \fBafter \fIms \fR?\fIscript script script ...\fR? In this form the command returns immediately, but it arranges for a Tcl command to be executed \fIms\fR milliseconds later as an event handler. The command will be executed exactly once, at the given time. The delayed command is formed by concatenating all the \fIscript\fR arguments in the same fashion as the \fBconcat\fR command. The command will be executed at global level (outside the context of any Tcl procedure). If an error occurs while executing the delayed command then the \fBbgerror\fR mechanism is used to report the error. The \fBafter\fR command returns an identifier that can be used to cancel the delayed command using \fBafter cancel\fR. .TP \fBafter cancel \fIid\fR Cancels the execution of a delayed command that was previously scheduled. \fIId\fR indicates which command should be canceled; it must have been the return value from a previous \fBafter\fR command. If the command given by \fIid\fR has already been executed then the \fBafter cancel\fR command has no effect. .TP \fBafter cancel \fIscript script ...\fR This command also cancels the execution of a delayed command. The \fIscript\fR arguments are concatenated together with space separators (just as in the \fBconcat\fR command). If there is a pending command that matches the string, it is cancelled and will never be executed; if no such command is currently pending then the \fBafter cancel\fR command has no effect. .TP \fBafter idle \fIscript \fR?\fIscript script ...\fR? Concatenates the \fIscript\fR arguments together with space separators (just as in the \fBconcat\fR command), and arranges for the resulting script to be evaluated later as an idle callback. The script will be run exactly once, the next time the event loop is entered and there are no events to process. The command returns an identifier that can be used to cancel the delayed command using \fBafter cancel\fR. If an error occurs while executing the script then the \fBbgerror\fR mechanism is used to report the error. .TP \fBafter info \fR?\fIid\fR? This command returns information about existing event handlers. If no \fIid\fR argument is supplied, the command returns a list of the identifiers for all existing event handlers created by the \fBafter\fR command for this interpreter. If \fIid\fR is supplied, it specifies an existing handler; \fIid\fR must have been the return value from some previous call to \fBafter\fR and it must not have triggered yet or been cancelled. In this case the command returns a list with two elements. The first element of the list is the script associated with \fIid\fR, and the second element is either \fBidle\fR or \fBtimer\fR to indicate what kind of event handler it is. .LP The \fBafter \fIms\fR and \fBafter idle\fR forms of the command assume that the application is event driven: the delayed commands will not be executed unless the application enters the event loop. In applications that are not normally event-driven, such as \fBtclsh\fR, the event loop can be entered with the \fBvwait\fR and \fBupdate\fR commands. .SH "EXAMPLES" This defines a command to make Tcl do nothing at all for \fIN\fR seconds: .CS proc sleep {N} { \fBafter\fR [expr {int($N * 1000)}] } .CE .PP This arranges for the command \fIwake_up\fR to be run in eight hours (providing the event loop is active at that time): .CS \fBafter\fR [expr {1000 * 60 * 60 * 8}] wake_up .CE .PP The following command can be used to do long-running calculations (as represented here by \fI::my_calc::one_step\fR, which is assumed to return a boolean indicating whether another step should be performed) in a step-by-step fashion, though the calculation itself needs to be arranged so it can work step-wise. This technique is extra careful to ensure that the event loop is not starved by the rescheduling of processing steps (arranging for the next step to be done using an already-triggered timer event only when the event queue has been drained) and is useful when you want to ensure that a Tk GUI remains responsive during a slow task. .CS proc doOneStep {} { if {[::my_calc::one_step]} { \fBafter idle\fR [list \fBafter\fR 0 doOneStep] } } doOneStep .CE .SH "SEE ALSO" bgerror(n), concat(n), update(n), vwait(n) .SH KEYWORDS cancel, delay, idle callback, sleep, time tcl8.4.20/doc/linsert.n0000644003604700454610000000334111737050674013324 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" Copyright (c) 2001 Kevin B. Kenny. All rights reserved. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH linsert n 8.2 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME linsert \- Insert elements into a list .SH SYNOPSIS \fBlinsert \fIlist index element \fR?\fIelement element ...\fR? .BE .SH DESCRIPTION .PP This command produces a new list from \fIlist\fR by inserting all of the \fIelement\fR arguments just before the \fIindex\fR'th element of \fIlist\fR. Each \fIelement\fR argument will become a separate element of the new list. If \fIindex\fR is less than or equal to zero, then the new elements are inserted at the beginning of the list. If \fIindex\fR has the value \fBend\fR, or if it is greater than or equal to the number of elements in the list, then the new elements are appended to the list. \fBend\-\fIinteger\fR refers to the last element in the list minus the specified integer offset. .SH EXAMPLE Putting some values into a list, first indexing from the start and then indexing from the end, and then chaining them together: .CS set oldList {the fox jumps over the dog} set midList [\fBlinsert\fR $oldList 1 quick] set newList [\fBlinsert\fR $midList end-1 lazy] # The old lists still exist though... set newerList [\fBlinsert\fR [\fBlinsert\fR $oldList end-1 quick] 1 lazy] .CE .SH "SEE ALSO" .VS 8.4 list(n), lappend(n), lindex(n), llength(n), lsearch(n), lset(n), lsort(n), lrange(n), lreplace(n) .VE .SH KEYWORDS element, insert, list tcl8.4.20/doc/fconfigure.n0000644003604700454610000002702412052456743013775 0ustar dgp771div'\" '\" Copyright (c) 1995-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH fconfigure n 8.3 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME fconfigure \- Set and get options on a channel .SH SYNOPSIS .nf \fBfconfigure \fIchannelId\fR \fBfconfigure \fIchannelId\fR \fIname\fR \fBfconfigure \fIchannelId\fR \fIname value \fR?\fIname value ...\fR? .fi .BE .SH DESCRIPTION .PP The \fBfconfigure\fR command sets and retrieves options for channels. .PP \fIChannelId\fR identifies the channel for which to set or query an option and must refer to an open channel such as a Tcl standard channel (\fBstdin\fR, \fBstdout\fR, or \fBstderr\fR), the return value from an invocation of \fBopen\fR or \fBsocket\fR, or the result of a channel creation command provided by a Tcl extension. .PP If no \fIname\fR or \fIvalue\fR arguments are supplied, the command returns a list containing alternating option names and values for the channel. If \fIname\fR is supplied but no \fIvalue\fR then the command returns the current value of the given option. If one or more pairs of \fIname\fR and \fIvalue\fR are supplied, the command sets each of the named options to the corresponding \fIvalue\fR; in this case the return value is an empty string. .PP The options described below are supported for all channels. In addition, each channel type may add options that only it supports. See the manual entry for the command that creates each type of channels for the options that that specific type of channel supports. For example, see the manual entry for the \fBsocket\fR command for its additional options. .TP \fB\-blocking\fR \fIboolean\fR The \fB\-blocking\fR option determines whether I/O operations on the channel can cause the process to block indefinitely. The value of the option must be a proper boolean value. Channels are normally in blocking mode; if a channel is placed into nonblocking mode it will affect the operation of the \fBgets\fR, \fBread\fR, \fBputs\fR, \fBflush\fR, and \fBclose\fR commands; see the documentation for those commands for details. For nonblocking mode to work correctly, the application must be using the Tcl event loop (e.g. by calling \fBTcl_DoOneEvent\fR or invoking the \fBvwait\fR command). .TP \fB\-buffering\fR \fInewValue\fR . If \fInewValue\fR is \fBfull\fR then the I/O system will buffer output until its internal buffer is full or until the \fBflush\fR command is invoked. If \fInewValue\fR is \fBline\fR, then the I/O system will automatically flush output for the channel whenever a newline character is output. If \fInewValue\fR is \fBnone\fR, the I/O system will flush automatically after every output operation. The default is for \fB\-buffering\fR to be set to \fBfull\fR except for channels that connect to terminal-like devices; for these channels the initial setting is \fBline\fR. Additionally, \fBstdin\fR and \fBstdout\fR are initially set to \fBline\fR, and \fBstderr\fR is set to \fBnone\fR. .TP \fB\-buffersize\fR \fInewSize\fR . \fINewvalue\fR must be an integer; its value is used to set the size of buffers, in bytes, subsequently allocated for this channel to store input or output. \fINewvalue\fR must be between ten and one million, allowing buffers of ten to one million bytes in size. .TP \fB\-encoding\fR \fIname\fR . This option is used to specify the encoding of the channel, so that the data can be converted to and from Unicode for use in Tcl. For instance, in order for Tcl to read characters from a Japanese file in \fBshiftjis\fR and properly process and display the contents, the encoding would be set to \fBshiftjis\fR. Thereafter, when reading from the channel, the bytes in the Japanese file would be converted to Unicode as they are read. Writing is also supported \- as Tcl strings are written to the channel they will automatically be converted to the specified encoding on output. .RS .PP If a file contains pure binary data (for instance, a JPEG image), the encoding for the channel should be configured to be \fBbinary\fR. Tcl will then assign no interpretation to the data in the file and simply read or write raw bytes. The Tcl \fBbinary\fR command can be used to manipulate this byte-oriented data. .PP The default encoding for newly opened channels is the same platform- and locale-dependent system encoding used for interfacing with the operating system. .RE .TP \fB\-eofchar\fR \fIchar\fR .TP \fB\-eofchar\fR \fB{\fIinChar outChar\fB}\fR . This option supports DOS file systems that use Control-z (\ex1a) as an end of file marker. If \fIchar\fR is not an empty string, then this character signals end-of-file when it is encountered during input. For output, the end-of-file character is output when the channel is closed. If \fIchar\fR is the empty string, then there is no special end of file character marker. For read-write channels, a two-element list specifies the end of file marker for input and output, respectively. As a convenience, when setting the end-of-file character for a read-write channel you can specify a single value that will apply to both reading and writing. When querying the end-of-file character of a read-write channel, a two-element list will always be returned. The default value for \fB\-eofchar\fR is the empty string in all cases except for files under Windows. In that case the \fB\-eofchar\fR is Control-z (\ex1a) for reading and the empty string for writing. .TP \fB\-translation\fR \fImode\fR .TP \fB\-translation\fR \fB{\fIinMode outMode\fB}\fR . In Tcl scripts the end of a line is always represented using a single newline character (\en). However, in actual files and devices the end of a line may be represented differently on different platforms, or even for different devices on the same platform. For example, under UNIX newlines are used in files, whereas carriage-return-linefeed sequences are normally used in network connections. On input (i.e., with \fBgets\fP and \fBread\fP) the Tcl I/O system automatically translates the external end-of-line representation into newline characters. Upon output (i.e., with \fBputs\fP), the I/O system translates newlines to the external end-of-line representation. The default translation mode, \fBauto\fP, handles all the common cases automatically, but the \fB\-translation\fR option provides explicit control over the end of line translations. .RS .PP The value associated with \fB\-translation\fR is a single item for read-only and write-only channels. The value is a two-element list for read-write channels; the read translation mode is the first element of the list, and the write translation mode is the second element. As a convenience, when setting the translation mode for a read-write channel you can specify a single value that will apply to both reading and writing. When querying the translation mode of a read-write channel, a two-element list will always be returned. The following values are currently supported: .TP \fBauto\fR . As the input translation mode, \fBauto\fR treats any of newline (\fBlf\fP), carriage return (\fBcr\fP), or carriage return followed by a newline (\fBcrlf\fP) as the end of line representation. The end of line representation can even change from line-to-line, and all cases are translated to a newline. As the output translation mode, \fBauto\fR chooses a platform specific representation; for sockets on all platforms Tcl chooses \fBcrlf\fR, for all Unix flavors, it chooses \fBlf\fR and for the various flavors of Windows it chooses \fBcrlf\fR. The default setting for \fB\-translation\fR is \fBauto\fR for both input and output. .TP \fBbinary\fR . No end-of-line translations are performed. This is nearly identical to \fBlf\fP mode, except that in addition \fBbinary\fP mode also sets the end-of-file character to the empty string (which disables it) and sets the encoding to \fBbinary\fR (which disables encoding filtering). See the description of \fB\-eofchar\fR and \fB\-encoding\fR for more information. .PP .RS Internally, i.e. when it comes to the actual behaviour of the translator this value \fBis\fR identical to \fBlf\fR and is therefore reported as such when queried. Even if \fBbinary\fR was used to set the translation. .RE .TP \fBcr\fR . The end of a line in the underlying file or device is represented by a single carriage return character. As the input translation mode, \fBcr\fP mode converts carriage returns to newline characters. As the output translation mode, \fBcr\fP mode translates newline characters to carriage returns. This mode is typically used on Macintosh platforms. .TP \fBcrlf\fR . The end of a line in the underlying file or device is represented by a carriage return character followed by a linefeed character. As the input translation mode, \fBcrlf\fP mode converts carriage-return-linefeed sequences to newline characters. As the output translation mode, \fBcrlf\fP mode translates newline characters to carriage-return-linefeed sequences. This mode is typically used on Windows platforms and for network connections. .TP \fBlf\fR . The end of a line in the underlying file or device is represented by a single newline (linefeed) character. In this mode no translations occur during either input or output. This mode is typically used on UNIX platforms. .RE .PP .SH "STANDARD CHANNELS" .PP The Tcl standard channels (\fBstdin\fR, \fBstdout\fR, and \fBstderr\fR) can be configured through this command like every other channel opened by the Tcl library. Beyond the standard options described above they will also support any special option according to their current type. If, for example, a Tcl application is started by the \fBinet\fR super-server common on Unix system its Tcl standard channels will be sockets and thus support the socket options. .SH EXAMPLES Instruct Tcl to always send output to \fBstdout\fR immediately, whether or not it is to a terminal: .CS \fBfconfigure\fR stdout -buffering none .CE .PP Open a socket and read lines from it without ever blocking the processing of other events: .CS set s [socket some.where.com 12345] \fBfconfigure\fR $s -blocking 0 fileevent $s readable "readMe $s" proc readMe chan { if {[gets $chan line] < 0} { if {[eof $chan]} { close $chan return } # Could not read a complete line this time; Tcl's # internal buffering will hold the partial line for us # until some more data is available over the socket. } else { puts stdout $line } } .CE .PP Read a PPM-format image from a file: .CS # Open the file and put it into Unix ASCII mode set f [open teapot.ppm] \fBfconfigure\fR $f \-encoding ascii \-translation lf # Get the header if {[gets $f] ne "P6"} { error "not a raw\-bits PPM" } # Read lines until we have got non-comment lines # that supply us with three decimal values. set words {} while {[llength $words] < 3} { gets $f line if {[string match "#*" $line]} continue lappend words [eval concat [scan $line %d%d%d]] } # Those words supply the size of the image and its # overall depth per channel. Assign to variables. foreach {xSize ySize depth} $words {break} # Now switch to binary mode to pull in the data, # one byte per channel (red,green,blue) per pixel. \fBfconfigure\fR $f \-translation binary set numDataBytes [expr {3 * $xSize * $ySize}] set data [read $f $numDataBytes] close $f .CE .SH "SEE ALSO" close(n), flush(n), gets(n), open(n), puts(n), read(n), socket(n), Tcl_StandardChannels(3) .SH KEYWORDS blocking, buffering, carriage return, end of line, flushing, linemode, newline, nonblocking, platform, translation, encoding, filter, byte array, binary tcl8.4.20/doc/AddErrInfo.30000644003604700454610000001773111737050674013536 0ustar dgp771div'\" '\" Copyright (c) 1989-1993 The Regents of the University of California. '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_AddErrorInfo 3 8.0 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_AddObjErrorInfo, Tcl_AddErrorInfo, Tcl_SetObjErrorCode, Tcl_SetErrorCode, Tcl_SetErrorCodeVA, Tcl_PosixError, Tcl_LogCommandInfo \- record information about errors .SH SYNOPSIS .nf \fB#include \fR .sp \fBTcl_AddObjErrorInfo\fR(\fIinterp, message, length\fR) .sp \fBTcl_AddErrorInfo\fR(\fIinterp, message\fR) .sp \fBTcl_SetObjErrorCode\fR(\fIinterp, errorObjPtr\fR) .sp \fBTcl_SetErrorCode\fR(\fIinterp, element, element, ... \fB(char *) NULL\fR) .sp \fBTcl_SetErrorCodeVA\fR(\fIinterp, argList\fR) .sp CONST char * \fBTcl_PosixError\fR(\fIinterp\fR) .sp void \fBTcl_LogCommandInfo\fR(\fIinterp, script, command, commandLength\fR) .SH ARGUMENTS .AS Tcl_Interp *message .AP Tcl_Interp *interp in Interpreter in which to record information. .AP char *message in For \fBTcl_AddObjErrorInfo\fR, this points to the first byte of an array of bytes containing a string to record in the \fBerrorInfo\fR variable. This byte array may contain embedded null bytes unless \fIlength\fR is negative. For \fBTcl_AddErrorInfo\fR, this is a conventional C string to record in the \fBerrorInfo\fR variable. .AP int length in The number of bytes to copy from \fImessage\fR when setting the \fBerrorInfo\fR variable. If negative, all bytes up to the first null byte are used. .AP Tcl_Obj *errorObjPtr in This variable \fBerrorCode\fR will be set to this value. .AP char *element in String to record as one element of \fBerrorCode\fR variable. Last \fIelement\fR argument must be NULL. .AP va_list argList in An argument list which must have been initialized using \fBTCL_VARARGS_START\fR, and cleared using \fBva_end\fR. .AP "CONST char" *script in Pointer to first character in script containing command (must be <= command) .AP "CONST char" *command in Pointer to first character in command that generated the error .AP int commandLength in Number of bytes in command; -1 means use all bytes up to first null byte .BE .SH DESCRIPTION .PP These procedures are used to manipulate two Tcl global variables that hold information about errors. The variable \fBerrorInfo\fR holds a stack trace of the operations that were in progress when an error occurred, and is intended to be human-readable. The variable \fBerrorCode\fR holds a list of items that are intended to be machine-readable. The first item in \fBerrorCode\fR identifies the class of error that occurred (e.g. POSIX means an error occurred in a POSIX system call) and additional elements in \fBerrorCode\fR hold additional pieces of information that depend on the class. See the Tcl overview manual entry for details on the various formats for \fBerrorCode\fR. .PP The \fBerrorInfo\fR variable is gradually built up as an error unwinds through the nested operations. Each time an error code is returned to \fBTcl_EvalObjEx\fR (or \fBTcl_Eval\fR, which calls \fBTcl_EvalObjEx\fR) it calls the procedure \fBTcl_AddObjErrorInfo\fR to add additional text to \fBerrorInfo\fR describing the command that was being executed when the error occurred. By the time the error has been passed all the way back to the application, it will contain a complete trace of the activity in progress when the error occurred. .PP It is sometimes useful to add additional information to \fBerrorInfo\fR beyond what can be supplied automatically by \fBTcl_EvalObjEx\fR. \fBTcl_AddObjErrorInfo\fR may be used for this purpose: its \fImessage\fR and \fIlength\fR arguments describe an additional string to be appended to \fBerrorInfo\fR. For example, the \fBsource\fR command calls \fBTcl_AddObjErrorInfo\fR to record the name of the file being processed and the line number on which the error occurred; for Tcl procedures, the procedure name and line number within the procedure are recorded, and so on. The best time to call \fBTcl_AddObjErrorInfo\fR is just after \fBTcl_EvalObjEx\fR has returned \fBTCL_ERROR\fR. In calling \fBTcl_AddObjErrorInfo\fR, you may find it useful to use the \fBerrorLine\fR field of the interpreter (see the \fBTcl_Interp\fR manual entry for details). .PP \fBTcl_AddErrorInfo\fR resembles \fBTcl_AddObjErrorInfo\fR but differs in initializing \fBerrorInfo\fR from the string value of the interpreter's result if the error is just starting to be logged. It does not use the result as a Tcl object so any embedded null characters in the result will cause information to be lost. It also takes a conventional C string in \fImessage\fR instead of \fBTcl_AddObjErrorInfo\fR's counted string. .PP The procedure \fBTcl_SetObjErrorCode\fR is used to set the \fBerrorCode\fR variable. \fIerrorObjPtr\fR contains a list object built up by the caller. \fBerrorCode\fR is set to this value. \fBTcl_SetObjErrorCode\fR is typically invoked just before returning an error in an object command. If an error is returned without calling \fBTcl_SetObjErrorCode\fR or \fBTcl_SetErrorCode\fR the Tcl interpreter automatically sets \fBerrorCode\fR to \fBNONE\fR. .PP The procedure \fBTcl_SetErrorCode\fR is also used to set the \fBerrorCode\fR variable. However, it takes one or more strings to record instead of an object. Otherwise, it is similar to \fBTcl_SetObjErrorCode\fR in behavior. .PP \fBTcl_SetErrorCodeVA\fR is the same as \fBTcl_SetErrorCode\fR except that instead of taking a variable number of arguments it takes an argument list. .PP \fBTcl_PosixError\fR sets the \fBerrorCode\fR variable after an error in a POSIX kernel call. It reads the value of the \fBerrno\fR C variable and calls \fBTcl_SetErrorCode\fR to set \fBerrorCode\fR in the \fBPOSIX\fR format. The caller must previously have called \fBTcl_SetErrno\fR to set \fBerrno\fR; this is necessary on some platforms (e.g. Windows) where Tcl is linked into an application as a shared library, or when the error occurs in a dynamically loaded extension. See the manual entry for \fBTcl_SetErrno\fR for more information. .PP \fBTcl_PosixError\fR returns a human-readable diagnostic message for the error (this is the same value that will appear as the third element in \fBerrorCode\fR). It may be convenient to include this string as part of the error message returned to the application in the interpreter's result. .PP \fBTcl_LogCommandInfo\fR is invoked after an error occurs in an interpreter. It adds information about the command that was being executed when the error occurred to the \fBerrorInfo\fR variable, and the line number stored internally in the interpreter is set. On the first call to \fBTcl_LogCommandInfo\fR or \fBTcl_AddObjErrorInfo\fR since an error occurred, the old information in \fBerrorInfo\fR is deleted. .PP It is important to call the procedures described here rather than setting \fBerrorInfo\fR or \fBerrorCode\fR directly with \fBTcl_ObjSetVar2\fR. The reason for this is that the Tcl interpreter keeps information about whether these procedures have been called. For example, the first time \fBTcl_AddObjErrorInfo\fR is called for an error, it clears the existing value of \fBerrorInfo\fR and adds the error message in the interpreter's result to the variable before appending \fImessage\fR; in subsequent calls, it just appends the new \fImessage\fR. When \fBTcl_SetErrorCode\fR is called, it sets a flag indicating that \fBerrorCode\fR has been set; this allows the Tcl interpreter to set \fBerrorCode\fR to \fBNONE\fR if it receives an error return when \fBTcl_SetErrorCode\fR hasn't been called. .PP If the procedure \fBTcl_ResetResult\fR is called, it clears all of the state associated with \fBerrorInfo\fR and \fBerrorCode\fR (but it doesn't actually modify the variables). If an error had occurred, this will clear the error state to make it appear as if no error had occurred after all. .SH "SEE ALSO" Tcl_DecrRefCount, Tcl_IncrRefCount, Tcl_Interp, Tcl_ResetResult, Tcl_SetErrno .SH KEYWORDS error, object, object result, stack, trace, variable tcl8.4.20/doc/Backslash.30000644003604700454610000000267611737050674013456 0ustar dgp771div'\" '\" Copyright (c) 1989-1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_Backslash 3 "8.1" Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_Backslash \- parse a backslash sequence .SH SYNOPSIS .nf \fB#include \fR .sp char \fBTcl_Backslash\fR(\fIsrc, countPtr\fR) .SH ARGUMENTS .AS char *countPtr .AP char *src in Pointer to a string starting with a backslash. .AP int *countPtr out If \fIcountPtr\fR isn't NULL, \fI*countPtr\fR gets filled in with number of characters in the backslash sequence, including the backslash character. .BE .SH DESCRIPTION .PP .VS 8.1 The use of \fBTcl_Backslash\fR is deprecated in favor of \fBTcl_UtfBackslash\fR. .PP This is a utility procedure provided for backwards compatibility with non-internationalized Tcl extensions. It parses a backslash sequence and returns the low byte of the Unicode character corresponding to the sequence. .VE \fBTcl_Backslash\fR modifies \fI*countPtr\fR to contain the number of characters in the backslash sequence. .PP See the Tcl manual entry for information on the valid backslash sequences. All of the sequences described in the Tcl manual entry are supported by \fBTcl_Backslash\fR. .VS 8.1 br .SH "SEE ALSO" Tcl(n), Tcl_UtfBackslash(3) .VE .SH KEYWORDS backslash, parse tcl8.4.20/doc/man.macros0000644003604700454610000001141611737050674013450 0ustar dgp771div'\" The definitions below are for supplemental macros used in Tcl/Tk '\" manual entries. '\" '\" .AP type name in/out ?indent? '\" Start paragraph describing an argument to a library procedure. '\" type is type of argument (int, etc.), in/out is either "in", "out", '\" or "in/out" to describe whether procedure reads or modifies arg, '\" and indent is equivalent to second arg of .IP (shouldn't ever be '\" needed; use .AS below instead) '\" '\" .AS ?type? ?name? '\" Give maximum sizes of arguments for setting tab stops. Type and '\" name are examples of largest possible arguments that will be passed '\" to .AP later. If args are omitted, default tab stops are used. '\" '\" .BS '\" Start box enclosure. From here until next .BE, everything will be '\" enclosed in one large box. '\" '\" .BE '\" End of box enclosure. '\" '\" .CS '\" Begin code excerpt. '\" '\" .CE '\" End code excerpt. '\" '\" .VS ?version? ?br? '\" Begin vertical sidebar, for use in marking newly-changed parts '\" of man pages. The first argument is ignored and used for recording '\" the version when the .VS was added, so that the sidebars can be '\" found and removed when they reach a certain age. If another argument '\" is present, then a line break is forced before starting the sidebar. '\" '\" .VE '\" End of vertical sidebar. '\" '\" .DS '\" Begin an indented unfilled display. '\" '\" .DE '\" End of indented unfilled display. '\" '\" .SO '\" Start of list of standard options for a Tk widget. The '\" options follow on successive lines, in four columns separated '\" by tabs. '\" '\" .SE '\" End of list of standard options for a Tk widget. '\" '\" .OP cmdName dbName dbClass '\" Start of description of a specific option. cmdName gives the '\" option's name as specified in the class command, dbName gives '\" the option's name in the option database, and dbClass gives '\" the option's class in the option database. '\" '\" .UL arg1 arg2 '\" Print arg1 underlined, then print arg2 normally. '\" '\" # Set up traps and other miscellaneous stuff for Tcl/Tk man pages. .if t .wh -1.3i ^B .nr ^l \n(.l .ad b '\" # Start an argument description .de AP .ie !"\\$4"" .TP \\$4 .el \{\ . ie !"\\$2"" .TP \\n()Cu . el .TP 15 .\} .ta \\n()Au \\n()Bu .ie !"\\$3"" \{\ \&\\$1 \\fI\\$2\\fP (\\$3) .\".b .\} .el \{\ .br .ie !"\\$2"" \{\ \&\\$1 \\fI\\$2\\fP .\} .el \{\ \&\\fI\\$1\\fP .\} .\} .. '\" # define tabbing values for .AP .de AS .nr )A 10n .if !"\\$1"" .nr )A \\w'\\$1'u+3n .nr )B \\n()Au+15n .\" .if !"\\$2"" .nr )B \\w'\\$2'u+\\n()Au+3n .nr )C \\n()Bu+\\w'(in/out)'u+2n .. .AS Tcl_Interp Tcl_CreateInterp in/out '\" # BS - start boxed text '\" # ^y = starting y location '\" # ^b = 1 .de BS .br .mk ^y .nr ^b 1u .if n .nf .if n .ti 0 .if n \l'\\n(.lu\(ul' .if n .fi .. '\" # BE - end boxed text (draw box now) .de BE .nf .ti 0 .mk ^t .ie n \l'\\n(^lu\(ul' .el \{\ .\" Draw four-sided box normally, but don't draw top of .\" box if the box started on an earlier page. .ie !\\n(^b-1 \{\ \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .el \}\ \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .\} .fi .br .nr ^b 0 .. '\" # VS - start vertical sidebar '\" # ^Y = starting y location '\" # ^v = 1 (for troff; for nroff this doesn't matter) .de VS .if !"\\$2"" .br .mk ^Y .ie n 'mc \s12\(br\s0 .el .nr ^v 1u .. '\" # VE - end of vertical sidebar .de VE .ie n 'mc .el \{\ .ev 2 .nf .ti 0 .mk ^t \h'|\\n(^lu+3n'\L'|\\n(^Yu-1v\(bv'\v'\\n(^tu+1v-\\n(^Yu'\h'-|\\n(^lu+3n' .sp -1 .fi .ev .\} .nr ^v 0 .. '\" # Special macro to handle page bottom: finish off current '\" # box/sidebar if in box/sidebar mode, then invoked standard '\" # page bottom macro. .de ^B .ev 2 'ti 0 'nf .mk ^t .if \\n(^b \{\ .\" Draw three-sided box if this is the box's first page, .\" draw two sides but no top otherwise. .ie !\\n(^b-1 \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .el \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .\} .if \\n(^v \{\ .nr ^x \\n(^tu+1v-\\n(^Yu \kx\h'-\\nxu'\h'|\\n(^lu+3n'\ky\L'-\\n(^xu'\v'\\n(^xu'\h'|0u'\c .\} .bp 'fi .ev .if \\n(^b \{\ .mk ^y .nr ^b 2 .\} .if \\n(^v \{\ .mk ^Y .\} .. '\" # DS - begin display .de DS .RS .nf .sp .. '\" # DE - end display .de DE .fi .RE .sp .. '\" # SO - start of list of standard options .de SO .SH "STANDARD OPTIONS" .LP .nf .ta 5.5c 11c .ft B .. '\" # SE - end of list of standard options .de SE .fi .ft R .LP See the \\fBoptions\\fR manual entry for details on the standard options. .. '\" # OP - start of full description for a single option .de OP .LP .nf .ta 4c Command-Line Name: \\fB\\$1\\fR Database Name: \\fB\\$2\\fR Database Class: \\fB\\$3\\fR .fi .IP .. '\" # CS - begin code excerpt .de CS .RS .nf .ta .25i .5i .75i 1i .. '\" # CE - end code excerpt .de CE .fi .RE .. .de UL \\$1\l'|0\(ul'\\$2 .. tcl8.4.20/doc/fileevent.n0000644003604700454610000001250011737050674013622 0ustar dgp771div'\" '\" Copyright (c) 1994 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH fileevent n 7.5 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME fileevent \- Execute a script when a channel becomes readable or writable .SH SYNOPSIS \fBfileevent \fIchannelId \fBreadable \fR?\fIscript\fR? .sp \fBfileevent \fIchannelId \fBwritable \fR?\fIscript\fR? .BE .SH DESCRIPTION .PP This command is used to create \fIfile event handlers\fR. A file event handler is a binding between a channel and a script, such that the script is evaluated whenever the channel becomes readable or writable. File event handlers are most commonly used to allow data to be received from another process on an event-driven basis, so that the receiver can continue to interact with the user while waiting for the data to arrive. If an application invokes \fBgets\fR or \fBread\fR on a blocking channel when there is no input data available, the process will block; until the input data arrives, it will not be able to service other events, so it will appear to the user to ``freeze up''. With \fBfileevent\fR, the process can tell when data is present and only invoke \fBgets\fR or \fBread\fR when they won't block. .PP .VS The \fIchannelId\fR argument to \fBfileevent\fR refers to an open channel such as a Tcl standard channel (\fBstdin\fR, \fBstdout\fR, or \fBstderr\fR), the return value from an invocation of \fBopen\fR or \fBsocket\fR, or the result of a channel creation command provided by a Tcl extension. .VE .PP If the \fIscript\fR argument is specified, then \fBfileevent\fR creates a new event handler: \fIscript\fR will be evaluated whenever the channel becomes readable or writable (depending on the second argument to \fBfileevent\fR). In this case \fBfileevent\fR returns an empty string. The \fBreadable\fR and \fBwritable\fR event handlers for a file are independent, and may be created and deleted separately. However, there may be at most one \fBreadable\fR and one \fBwritable\fR handler for a file at a given time in a given interpreter. If \fBfileevent\fR is called when the specified handler already exists in the invoking interpreter, the new script replaces the old one. .PP If the \fIscript\fR argument is not specified, \fBfileevent\fR returns the current script for \fIchannelId\fR, or an empty string if there is none. If the \fIscript\fR argument is specified as an empty string then the event handler is deleted, so that no script will be invoked. A file event handler is also deleted automatically whenever its channel is closed or its interpreter is deleted. .PP A channel is considered to be readable if there is unread data available on the underlying device. A channel is also considered to be readable if there is unread data in an input buffer, except in the special case where the most recent attempt to read from the channel was a \fBgets\fR call that could not find a complete line in the input buffer. This feature allows a file to be read a line at a time in nonblocking mode using events. A channel is also considered to be readable if an end of file or error condition is present on the underlying file or device. It is important for \fIscript\fR to check for these conditions and handle them appropriately; for example, if there is no special check for end of file, an infinite loop may occur where \fIscript\fR reads no data, returns, and is immediately invoked again. .PP A channel is considered to be writable if at least one byte of data can be written to the underlying file or device without blocking, or if an error condition is present on the underlying file or device. .PP Event-driven I/O works best for channels that have been placed into nonblocking mode with the \fBfconfigure\fR command. In blocking mode, a \fBputs\fR command may block if you give it more data than the underlying file or device can accept, and a \fBgets\fR or \fBread\fR command will block if you attempt to read more data than is ready; no events will be processed while the commands block. In nonblocking mode \fBputs\fR, \fBread\fR, and \fBgets\fR never block. See the documentation for the individual commands for information on how they handle blocking and nonblocking channels. .PP The script for a file event is executed at global level (outside the context of any Tcl procedure) in the interpreter in which the \fBfileevent\fR command was invoked. If an error occurs while executing the script then the \fBbgerror\fR mechanism is used to report the error. In addition, the file event handler is deleted if it ever returns an error; this is done in order to prevent infinite loops due to buggy handlers. .SH EXAMPLE In this setup \fBGetData\fR will be called with the channel as an argument whenever $chan becomes readable. .CS proc GetData {chan} { if {![eof $chan]} { puts [gets $chan] } } \fBfileevent\fR $chan readable [list GetData $chan] .CE .SH CREDITS .PP \fBfileevent\fR is based on the \fBaddinput\fR command created by Mark Diekhans. .SH "SEE ALSO" bgerror(n), fconfigure(n), gets(n), puts(n), read(n), Tcl_StandardChannels(3) .SH KEYWORDS asynchronous I/O, blocking, channel, event handler, nonblocking, readable, script, writable. tcl8.4.20/doc/StdChannels.30000644003604700454610000001107711737050674013764 0ustar dgp771div'\" '\" Copyright (c) 2001 by ActiveState Corporation '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH "Standard Channels" 3 7.5 Tcl "Tcl Library Procedures" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME Tcl_StandardChannels \- How the Tcl library deals with the standard channels .BE .SH DESCRIPTION .PP This page explains the initialization and use of standard channels in the Tcl library. .PP The term \fIstandard channels\fR comes out of the Unix world and refers to the three channels automatically opened by the OS for each new application. They are \fBstdin\fR, \fBstdout\fR and \fBstderr\fR. The first is the standard input an application can read from, the other two refer to writable channels, one for regular output and the other for error messages. .PP Tcl generalizes this concept in a cross-platform way and exposes standard channels to the script level. .SH APIs .PP The public API procedures dealing directly with standard channels are \fBTcl_GetStdChannel\fR and \fBTcl_SetStdChannel\fR. Additional public APIs to consider are \fBTcl_RegisterChannel\fR, \fBTcl_CreateChannel\fR and \fBTcl_GetChannel\fR. .SH "INITIALIZATION OF TCL STANDARD CHANNELS" .PP Standard channels are initialized by the Tcl library in three cases: when explicitly requested, when implicitly required before returning channel information, or when implicitly required during registration of a new channel. .PP These cases differ in how they handle unavailable platform- specific standard channels. (A channel is not ``available'' if it could not be successfully opened; for example, in a Tcl application run as a Windows NT service.) .TP 1) A single standard channel is initialized when it is explicitly specified in a call to \fBTcl_SetStdChannel\fR. The state of the other standard channels are unaffected. .sp Missing platform-specific standard channels do not matter here. This approach is not available at the script level. .TP 2) All uninitialized standard channels are initialized to platform-specific default values: .RS .TP (a) when open channels are listed with \fBTcl_GetChannelNames\fR (or the \fBfile channels\fR script command), or .TP (b) when information about any standard channel is requested with a call to \fBTcl_GetStdChannel\fR, or with a call to \fBTcl_GetChannel\fR which specifies one of the standard names (\fBstdin\fR, \fBstdout\fR and \fBstderr\fR). .RE .sp .RS In case of missing platform-specific standard channels, the Tcl standard channels are considered as initialized and then immediately closed. This means that the first three Tcl channels then opened by the application are designated as the Tcl standard channels. .RE .TP 3) All uninitialized standard channels are initialized to platform-specific default values when a user-requested channel is registered with \fBTcl_RegisterChannel\fR. .sp In case of unavailable platform-specific standard channels the channel whose creation caused the initialization of the Tcl standard channels is made a normal channel. The next three Tcl channels opened by the application are designated as the Tcl standard channels. In other words, of the first four Tcl channels opened by the application the second to fourth are designated as the Tcl standard channels. .PP .SH "RE-INITIALIZATION OF TCL STANDARD CHANNELS" .PP Once a Tcl standard channel is initialized through one of the methods above, closing this Tcl standard channel will cause the next call to \fBTcl_CreateChannel\fR to make the new channel the new standard channel, too. If more than one Tcl standard channel was closed \fBTcl_CreateChannel\fR will fill the empty slots in the order \fBstdin\fR, \fBstdout\fR and \fBstderr\fR. .PP \fBTcl_CreateChannel\fR will not try to reinitialize an empty slot if that slot was not initialized before. It is this behavior which enables an application to employ method 1 of initialization, i.e. to create and designate their own Tcl standard channels. .SH tclsh .PP The Tcl shell (or rather \fBTcl_Main\fR) uses method 2 to initialize the standard channels. .SH wish .PP The windowing shell (or rather \fBTk_MainEx\fR) uses method 1 to initialize the standard channels (See \fBTk_InitConsoleChannels\fR) on non-Unix platforms. On Unix platforms, \fBTk_MainEx\fR implicitly uses method 2 to initialize the standard channels. .SH "SEE ALSO" Tcl_CreateChannel(3), Tcl_RegisterChannel(3), Tcl_GetChannel(3), Tcl_GetStdChannel(3), Tcl_SetStdChannel(3), Tk_InitConsoleChannels(3), tclsh(1), wish(1), Tcl_Main(3), Tk_MainEx(3) .SH KEYWORDS standard channels tcl8.4.20/doc/llength.n0000644003604700454610000000241111737050674013276 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" Copyright (c) 2001 Kevin B. Kenny. All rights reserved. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH llength n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME llength \- Count the number of elements in a list .SH SYNOPSIS \fBllength \fIlist\fR .BE .SH DESCRIPTION .PP Treats \fIlist\fR as a list and returns a decimal string giving the number of elements in it. .SH EXAMPLES The result is the number of elements: .CS % \fBllength\fR {a b c d e} 5 % \fBllength\fR {a b c} 3 % \fBllength\fR {} 0 .CE .PP Elements are not guaranteed to be exactly words in a dictionary sense of course, especially when quoting is used: .CS % \fBllength\fR {a b {c d} e} 4 % \fBllength\fR {a b { } c d e} 6 .CE .PP An empty list is not necessarily an empty string: .CS % set var { }; puts "[string length $var],[\fBllength\fR $var]" 1,0 .CE .SH "SEE ALSO" .VS 8.4 list(n), lappend(n), lindex(n), linsert(n), lsearch(n), lset(n), lsort(n), lrange(n), lreplace(n) .VE .SH KEYWORDS element, list, length tcl8.4.20/doc/GetStdChan.30000644003604700454610000000702311737050674013536 0ustar dgp771div'\" '\" Copyright (c) 1996 by Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_GetStdChannel 3 7.5 Tcl "Tcl Library Procedures" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME Tcl_GetStdChannel, Tcl_SetStdChannel \- procedures for retrieving and replacing the standard channels .SH SYNOPSIS .nf \fB#include \fR .sp Tcl_Channel \fBTcl_GetStdChannel\fR(\fItype\fR) .sp \fBTcl_SetStdChannel\fR(\fIchannel, type\fR) .sp .SH ARGUMENTS .AS Tcl_Channel channel in .AP int type in The identifier for the standard channel to retrieve or modify. Must be one of \fBTCL_STDIN\fR, \fBTCL_STDOUT\fR, or \fBTCL_STDERR\fR. .AP Tcl_Channel channel in The channel to use as the new value for the specified standard channel. .BE .SH DESCRIPTION .PP Tcl defines three special channels that are used by various I/O related commands if no other channels are specified. The standard input channel has a channel name of \fBstdin\fR and is used by \fBread\fR and \fBgets\fR. The standard output channel is named \fBstdout\fR and is used by \fBputs\fR. The standard error channel is named \fBstderr\fR and is used for reporting errors. In addition, the standard channels are inherited by any child processes created using \fBexec\fR or \fBopen\fR in the absence of any other redirections. .PP The standard channels are actually aliases for other normal channels. The current channel associated with a standard channel can be retrieved by calling \fBTcl_GetStdChannel\fR with one of \fBTCL_STDIN\fR, \fBTCL_STDOUT\fR, or \fBTCL_STDERR\fR as the \fItype\fR. The return value will be a valid channel, or NULL. .PP A new channel can be set for the standard channel specified by \fItype\fR by calling \fBTcl_SetStdChannel\fR with a new channel or NULL in the \fIchannel\fR argument. If the specified channel is closed by a later call to \fBTcl_Close\fR, then the corresponding standard channel will automatically be set to NULL. .PP If a non-NULL value for \fIchannel\fR is passed to \fBTcl_SetStdChannel\fR, then that same value should be passed to \fBTcl_RegisterChannel\fR, like so: .CS Tcl_RegisterChannel(NULL, channel); .CE This is a workaround for a misfeature in \fBTcl_SetStdChannel\fR that it fails to do some reference counting housekeeping. This misfeature cannot be corrected without contradicting the assumptions of some existing code that calls \fBTcl_SetStdChannel\fR. .PP If \fBTcl_GetStdChannel\fR is called before \fBTcl_SetStdChannel\fR, Tcl will construct a new channel to wrap the appropriate platform-specific standard file handle. If \fBTcl_SetStdChannel\fR is called before \fBTcl_GetStdChannel\fR, then the default channel will not be created. .PP If one of the standard channels is set to NULL, either by calling \fBTcl_SetStdChannel\fR with a NULL \fIchannel\fR argument, or by calling \fBTcl_Close\fR on the channel, then the next call to \fBTcl_CreateChannel\fR will automatically set the standard channel with the newly created channel. If more than one standard channel is NULL, then the standard channels will be assigned starting with standard input, followed by standard output, with standard error being last. .PP See \fBTcl_StandardChannels\fR for a general treatise about standard channels and the behaviour of the Tcl library with regard to them. .PP .SH "SEE ALSO" Tcl_Close(3), Tcl_CreateChannel(3), Tcl_Main(3), tclsh(1) .SH KEYWORDS standard channel, standard input, standard output, standard error tcl8.4.20/doc/SetErrno.30000644003604700454610000000405111737050674013311 0ustar dgp771div'\" '\" Copyright (c) 1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_SetErrno 3 8.3 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_SetErrno, Tcl_GetErrno, Tcl_ErrnoId, Tcl_ErrnoMsg \- manipulate errno to store and retrieve error codes .SH SYNOPSIS .nf \fB#include \fR .sp void \fBTcl_SetErrno\fR(\fIerrorCode\fR) .sp int \fBTcl_GetErrno\fR() .sp CONST char * \fBTcl_ErrnoId\fR() .sp CONST char * \fBTcl_ErrnoMsg\fR(\fIerrorCode\fR) .sp .SH ARGUMENTS .AS int errorCode in .AP int errorCode in A POSIX error code such as \fBENOENT\fR. .BE .SH DESCRIPTION .PP \fBTcl_SetErrno\fR and \fBTcl_GetErrno\fR provide portable access to the \fBerrno\fR variable, which is used to record a POSIX error code after system calls and other operations such as \fBTcl_Gets\fR. These procedures are necessary because global variable accesses cannot be made across module boundaries on some platforms. .PP \fBTcl_SetErrno\fR sets the \fBerrno\fR variable to the value of the \fIerrorCode\fR argument C procedures that wish to return error information to their callers via \fBerrno\fR should call \fBTcl_SetErrno\fR rather than setting \fBerrno\fR directly. .PP \fBTcl_GetErrno\fR returns the current value of \fBerrno\fR. Procedures wishing to access \fBerrno\fR should call this procedure instead of accessing \fBerrno\fR directly. .PP \fBTcl_ErrnoId\fR and \fBTcl_ErrnoMsg\fR return string representations of \fBerrno\fR values. \fBTcl_ErrnoId\fR returns a machine-readable textual identifier such as "EACCES" that corresponds to the current value of \fBerrno\fR. \fBTcl_ErrnoMsg\fR returns a human-readable string such as "permission denied" that corresponds to the value of its \fIerrorCode\fR argument. The \fIerrorCode\fR argument is typically the value returned by \fBTcl_GetErrno\fR. The strings returned by these functions are statically allocated and the caller must not free or modify them. .SH KEYWORDS errno, error code, global variables tcl8.4.20/doc/rename.n0000644003604700454610000000263611737050674013121 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH rename n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME rename \- Rename or delete a command .SH SYNOPSIS \fBrename \fIoldName newName\fR .BE .SH DESCRIPTION .PP Rename the command that used to be called \fIoldName\fR so that it is now called \fInewName\fR. If \fInewName\fR is an empty string then \fIoldName\fR is deleted. \fIoldName\fR and \fInewName\fR may include namespace qualifiers (names of containing namespaces). If a command is renamed into a different namespace, future invocations of it will execute in the new namespace. The \fBrename\fR command returns an empty string as result. .SH EXAMPLE The \fBrename\fR command can be used to wrap the standard Tcl commands with your own monitoring machinery. For example, you might wish to count how often the \fBsource\fR command is called: .CS \fBrename\fR ::source ::theRealSource set sourceCount 0 proc ::source args { global sourceCount puts "called source for the [incr sourceCount]'th time" uplevel 1 ::theRealSource $args } .CE .SH "SEE ALSO" namespace(n), proc(n) .SH KEYWORDS command, delete, namespace, rename tcl8.4.20/doc/return.n0000644003604700454610000001102711737050674013163 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH return n 7.0 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME return \- Return from a procedure .SH SYNOPSIS \fBreturn \fR?\fB\-code \fIcode\fR? ?\fB\-errorinfo \fIinfo\fR? ?\fB\-errorcode\fI code\fR? ?\fIstring\fR? .BE .SH DESCRIPTION .PP Return immediately from the current procedure (or top-level command or \fBsource\fR command), with \fIstring\fR as the return value. If \fIstring\fR is not specified then an empty string will be returned as result. .SH "EXCEPTIONAL RETURN CODES" .PP In addition to the result of a procedure, the return code of a procedure may also be set by \fBreturn\fR through use of the \fB-code\fR option. In the usual case where the \fB\-code\fR option isn't specified the procedure will return normally. However, the \fB\-code\fR option may be used to generate an exceptional return from the procedure. \fICode\fR may have any of the following values: .TP 13 \fBok (or 0)\fR Normal return: same as if the option is omitted. The return code of the procedure is 0 (\fBTCL_OK\fR). .TP 13 \fBerror (1)\fR Error return: the return code of the procedure is 1 (\fBTCL_ERROR\fR). The procedure command behaves in its calling context as if it were the command \fBerror \fIresult\fR. See below for additional options. .TP 13 \fBreturn (2)\fR The return code of the procedure is 2 (\fBTCL_RETURN\fR). The procedure command behaves in its calling context as if it were the command \fBreturn\fR (with no arguments). .TP 13 \fBbreak (3)\fR The return code of the procedure is 3 (\fBTCL_BREAK\fR). The procedure command behaves in its calling context as if it were the command \fBbreak\fR. .TP 13 \fBcontinue (4)\fR The return code of the procedure is 4 (\fBTCL_CONTINUE\fR). The procedure command behaves in its calling context as if it were the command \fBcontinue\fR. .TP 13 \fIvalue\fR \fIValue\fR must be an integer; it will be returned as the return code for the current procedure. .LP The \fB\-code\fR option is rarely used. It is provided so that procedures that implement new control structures can reflect exceptional conditions back to their callers. .PP Two additional options, \fB\-errorinfo\fR and \fB\-errorcode\fR, may be used to provide additional information during error returns. These options are ignored unless \fIcode\fR is \fBerror\fR. .PP The \fB\-errorinfo\fR option specifies an initial stack trace for the \fBerrorInfo\fR variable; if it is not specified then the stack trace left in \fBerrorInfo\fR will include the call to the procedure and higher levels on the stack but it will not include any information about the context of the error within the procedure. Typically the \fIinfo\fR value is supplied from the value left in \fBerrorInfo\fR after a \fBcatch\fR command trapped an error within the procedure. .PP If the \fB\-errorcode\fR option is specified then \fIcode\fR provides a value for the \fBerrorCode\fR variable. If the option is not specified then \fBerrorCode\fR will default to \fBNONE\fR. .SH EXAMPLES First, a simple example of using \fBreturn\fR to return from a procedure, interrupting the procedure body. .CS proc printOneLine {} { puts "line 1" ;# This line will be printed. \fBreturn\fR puts "line 2" ;# This line will not be printed. } .CE .PP Next, an example of using \fBreturn\fR to set the value returned by the procedure. .CS proc returnX {} {\fBreturn\fR X} puts [returnX] ;# prints "X" .CE .PP Next, a more complete example, using \fBreturn -code error\fR to report invalid arguments. .CS proc factorial {n} { if {![string is integer $n] || ($n < 0)} { \fBreturn\fR -code error \\ "expected non-negative integer,\\ but got \\"$n\\"" } if {$n < 2} { \fBreturn\fR 1 } set m [expr {$n - 1}] set code [catch {factorial $m} factor] if {$code != 0} { \fBreturn\fR -code $code $factor } set product [expr {$n * $factor}] if {$product < 0} { \fBreturn\fR -code error \\ "overflow computing factorial of $n" } \fBreturn\fR $product } .CE .PP Next, a procedure replacement for \fBbreak\fR. .CS proc myBreak {} { \fBreturn\fR -code break } .CE .SH "SEE ALSO" break(n), catch(n), continue(n), error(n), proc(n), source(n), tclvars(n) .SH KEYWORDS break, catch, continue, error, procedure, return tcl8.4.20/doc/dde.n0000644003604700454610000001505112052456743012377 0ustar dgp771div'\" '\" Copyright (c) 1997 Sun Microsystems, Inc. '\" Copyright (c) 2001 ActiveState Corporation. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH dde n 1.2 dde "Tcl Bundled Packages" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME dde \- Execute a Dynamic Data Exchange command .SH SYNOPSIS .sp \fBpackage require dde 1.2\fR .sp \fBdde eval\fR ?\fB\-async\fR? \fIservice cmd\fR ?\fIarg ...\fR? .sp \fBdde execute\fR ?\fB\-async\fR? \fIservice topic data\fR .sp \fBdde poke \fIservice topic item data\fR .sp \fBdde request\fR ?\fB\-binary\fR? \fIservice topic data\fR .sp \fBdde servername\fR ?\fItopic\fR? .sp \fBdde services \fIservice topic\fR .BE .SH DESCRIPTION .PP This command allows an application to send Dynamic Data Exchange (DDE) command when running under Microsoft Windows. Dynamic Data Exchange is a mechanism where applications can exchange raw data. Each DDE transaction needs a \fIservice name\fR and a \fItopic\fR. Both the \fIservice name\fR and \fItopic\fR are application defined; Tcl uses the service name \fBTclEval\fR, while the topic name is the name of the interpreter given by \fBdde servername\fR. Other applications have their own \fIservice name\fRs and \fItopic\fRs. For instance, Microsoft Excel has the service name \fBExcel\fR. .PP The \fBeval\fR and \fBexecute\fR commands accept the option \fB\-async\fR: .SH "DDE COMMANDS" .PP The following commands are a subset of the full Dynamic Data Exchange set of commands. .TP \fBdde servername \fR?\fItopic\fR? \fBdde servername\fR registers the interpreter as a DDE server with the service name \fBTclEval\fR and the topic name specified by \fItopic\fR. If no \fItopic\fR is given, \fBdde servername\fR returns the name of the current topic or the empty string if it is not registered as a service. .TP \fBdde execute\fR ?\fB\-async\fR? \fIservice topic data\fR \fBdde execute\fR takes the \fIdata\fR and sends it to the server indicated by \fIservice\fR with the topic indicated by \fItopic\fR. Typically, \fIservice\fR is the name of an application, and \fItopic\fR is a file to work on. The \fIdata\fR field is given to the remote application. Typically, the application treats the \fIdata\fR field as a script, and the script is run in the application. The \fB\-async\fR option requests asynchronous invocation. The command returns an error message if the script did not run, unless the \fB\-async\fR flag was used, in which case the command returns immediately with no error. .TP \fBdde poke \fIservice topic item data\fR \fBdde poke\fR passes the \fIdata\fR to the server indicated by \fIservice\fR using the \fItopic\fR and \fIitem\fR specified. Typically, \fIservice\fR is the name of an application. \fItopic\fR is application specific but can be a command to the server or the name of a file to work on. The \fIitem\fR is also application specific and is often not used, but it must always be non-null. The \fIdata\fR field is given to the remote application. .TP \fBdde request\fR ?\fB\-binary\fR? \fIservice topic item\fR \fBdde request\fR is typically used to get the value of something; the value of a cell in Microsoft Excel or the text of a selection in Microsoft Word. \fIservice\fR is typically the name of an application, \fItopic\fR is typically the name of the file, and \fIitem\fR is application-specific. The command returns the value of \fIitem\fR as defined in the application. Normally this is interpreted to be a string with terminating null. If \fB\-binary\fR is specified, the result is returned as a byte array. .TP \fBdde services \fIservice topic\fR \fBdde services\fR returns a list of service-topic pairs that currently exist on the machine. If \fIservice\fR and \fItopic\fR are both null strings ({}), then all service-topic pairs currently available on the system are returned. If \fIservice\fR is null and \fItopic\fR is not, then all services with the specified topic are returned. If \fIservice\fR is not null and \fItopic\fR is, all topics for a given service are returned. If both are not null, if that service-topic pair currently exists, it is returned; otherwise, null is returned. .TP \fBdde eval\fR ?\fB\-async\fR? \fItopic cmd \fR?\fIarg arg ...\fR? \fBdde eval\fR evaluates a command and its arguments using the interpreter specified by \fItopic\fR. The DDE service must be the \fBTclEval\fR service. The \fB\-async\fR option requests asynchronous invocation. The command returns an error message if the script did not run, unless the \fB\-async\fR flag was used, in which case the command returns immediately with no error. This command can be used to replace \fBsend\fR on Windows. .SH "DDE AND TCL" A Tcl interpreter always has a service name of \fBTclEval\fR. Each different interpreter of all running Tcl applications must be given a unique name specified by \fBdde servername\fR. Each interp is available as a DDE topic only if the \fBdde servername\fR command was used to set the name of the topic for each interp. So a \fBdde services TclEval {}\fR command will return a list of service-topic pairs, where each of the currently running interps will be a topic. .PP When Tcl processes a \fBdde execute\fR command, the data for the execute is run as a script in the interp named by the topic of the \fBdde execute\fR command. .PP When Tcl processes a \fBdde request\fR command, it returns the value of the variable given in the dde command in the context of the interp named by the dde topic. Tcl reserves the variable \fB$TCLEVAL$EXECUTE$RESULT\fR for internal use, and \fBdde request\fR commands for that variable will give unpredictable results. .PP An external application which wishes to run a script in Tcl should have that script store its result in a variable, run the \fBdde execute\fR command, and then run \fBdde request\fR to get the value of the variable. .PP When using DDE, be careful to ensure that the event queue is flushed using either \fBupdate\fR or \fBvwait\fR. This happens by default when using \fBwish\fR unless a blocking command is called (such as \fBexec\fR without adding the \fB&\fR to place the process in the background). If for any reason the event queue is not flushed, DDE commands may hang until the event queue is flushed. This can create a deadlock situation. .SH EXAMPLE This asks Internet Explorer (which must already be running) to go to a particularly important website: .CS package require dde \fBdde execute\fR -async iexplore WWW_OpenURL http://www.tcl.tk/ .CE .SH "SEE ALSO" tk(n), winfo(n), send(n) .SH KEYWORDS application, dde, name, remote execution tcl8.4.20/doc/StringObj.30000644003604700454610000002737611737050674013470 0ustar dgp771div'\" '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_StringObj 3 8.1 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_NewStringObj, Tcl_NewUnicodeObj, Tcl_SetStringObj, Tcl_SetUnicodeObj, Tcl_GetStringFromObj, Tcl_GetString, Tcl_GetUnicodeFromObj, Tcl_GetUnicode, Tcl_GetUniChar, Tcl_GetCharLength, Tcl_GetRange, Tcl_AppendToObj, Tcl_AppendUnicodeToObj, Tcl_AppendStringsToObj, Tcl_AppendStringsToObjVA, Tcl_AppendObjToObj, Tcl_SetObjLength, Tcl_ConcatObj, Tcl_AttemptSetObjLength \- manipulate Tcl objects as strings .SH SYNOPSIS .nf \fB#include \fR .sp Tcl_Obj * \fBTcl_NewStringObj\fR(\fIbytes, length\fR) .sp Tcl_Obj * \fBTcl_NewUnicodeObj\fR(\fIunicode, numChars\fR) .sp void \fBTcl_SetStringObj\fR(\fIobjPtr, bytes, length\fR) .sp void \fBTcl_SetUnicodeObj\fR(\fIobjPtr, unicode, numChars\fR) .sp char * \fBTcl_GetStringFromObj\fR(\fIobjPtr, lengthPtr\fR) .sp char * \fBTcl_GetString\fR(\fIobjPtr\fR) .sp Tcl_UniChar * \fBTcl_GetUnicodeFromObj\fR(\fIobjPtr, lengthPtr\fR) .sp Tcl_UniChar * \fBTcl_GetUnicode\fR(\fIobjPtr\fR) .sp Tcl_UniChar \fBTcl_GetUniChar\fR(\fIobjPtr, index\fR) .sp int \fBTcl_GetCharLength\fR(\fIobjPtr\fR) .sp Tcl_Obj * \fBTcl_GetRange\fR(\fIobjPtr, first, last\fR) .sp void \fBTcl_AppendToObj\fR(\fIobjPtr, bytes, length\fR) .sp void \fBTcl_AppendUnicodeToObj\fR(\fIobjPtr, unicode, numChars\fR) .sp void \fBTcl_AppendObjToObj\fR(\fIobjPtr, appendObjPtr\fR) .sp void \fBTcl_AppendStringsToObj\fR(\fIobjPtr, string, string, ... \fB(char *) NULL\fR) .sp void \fBTcl_AppendStringsToObjVA\fR(\fIobjPtr, argList\fR) .sp void \fBTcl_SetObjLength\fR(\fIobjPtr, newLength\fR) .sp int \fBTcl_AttemptSetObjLength\fR(\fIobjPtr, newLength\fR) .sp Tcl_Obj * \fBTcl_ConcatObj\fR(\fIobjc, objv\fR) .SH ARGUMENTS .AS "CONST Tcl_UniChar" *appendObjPtr in/out .AP "CONST char" *bytes in .VS 8.1 Points to the first byte of an array of UTF-8-encoded bytes used to set or append to a string object. This byte array should not contain embedded null bytes unless \fIlength\fR is negative. (Applications needing null bytes should represent them as the two-byte sequence \fI\\700\\600\fR, use \fBTcl_ExternalToUtf\fR to convert, or \fBTcl_NewByteArrayObj\fR if the string is a collection of uninterpreted bytes.) .VE 8.1 .AP int length in The number of bytes to copy from \fIbytes\fR when initializing, setting, or appending to a string object. If negative, all bytes up to the first null are used. .AP "CONST Tcl_UniChar" *unicode in Points to the first byte of an array of Unicode characters used to set or append to a string object. This byte array may contain embedded null characters unless \fInumChars\fR is negative. .AP int numChars in The number of Unicode characters to copy from \fIunicode\fR when initializing, setting, or appending to a string object. If negative, all characters up to the first null character are used. .AP int index in The index of the Unicode character to return. .AP int first in The index of the first Unicode character in the Unicode range to be returned as a new object. .AP int last in The index of the last Unicode character in the Unicode range to be returned as a new object. .AP Tcl_Obj *objPtr in/out Points to an object to manipulate. .AP Tcl_Obj *appendObjPtr in The object to append to \fIobjPtr\fR in \fBTcl_AppendObjToObj\fR. .AP int *lengthPtr out If non-NULL, the location where \fBTcl_GetStringFromObj\fR will store the the length of an object's string representation. .AP "CONST char" *string in Null-terminated string value to append to \fIobjPtr\fR. .AP va_list argList in An argument list which must have been initialised using \fBTCL_VARARGS_START\fR, and cleared using \fBva_end\fR. .AP int newLength in New length for the string value of \fIobjPtr\fR, not including the final null character. .AP int objc in The number of elements to concatenate. .AP Tcl_Obj *objv[] in The array of objects to concatenate. .BE .SH DESCRIPTION .PP The procedures described in this manual entry allow Tcl objects to be manipulated as string values. They use the internal representation of the object to store additional information to make the string manipulations more efficient. In particular, they make a series of append operations efficient by allocating extra storage space for the string so that it doesn't have to be copied for each append. Also, indexing and length computations are optimized because the Unicode string representation is calculated and cached as needed. When using the \fBTcl_Append*\fR family of functions where the interpreter's result is the object being appended to, it is important to call Tcl_ResetResult first to ensure you are not unintentionally appending to existing data in the result object. .PP \fBTcl_NewStringObj\fR and \fBTcl_SetStringObj\fR create a new object or modify an existing object to hold a copy of the string given by \fIbytes\fR and \fIlength\fR. \fBTcl_NewUnicodeObj\fR and \fBTcl_SetUnicodeObj\fR create a new object or modify an existing object to hold a copy of the Unicode string given by \fIunicode\fR and \fInumChars\fR. \fBTcl_NewStringObj\fR and \fBTcl_NewUnicodeObj\fR return a pointer to a newly created object with reference count zero. All four procedures set the object to hold a copy of the specified string. \fBTcl_SetStringObj\fR and \fBTcl_SetUnicodeObj\fR free any old string representation as well as any old internal representation of the object. .PP \fBTcl_GetStringFromObj\fR and \fBTcl_GetString\fR return an object's string representation. This is given by the returned byte pointer and (for \fBTcl_GetStringFromObj\fR) length, which is stored in \fIlengthPtr\fR if it is non-NULL. If the object's UTF string representation is invalid (its byte pointer is NULL), the string representation is regenerated from the object's internal representation. The storage referenced by the returned byte pointer is owned by the object manager. It is passed back as a writable pointer so that extension author creating their own \fBTcl_ObjType\fR will be able to modify the string representation within the \fBTcl_UpdateStringProc\fR of their \fBTcl_ObjType\fR. Except for that limited purpose, the pointer returned by \fBTcl_GetStringFromObj\fR or \fBTcl_GetString\fR should be treated as read-only. It is recommended that this pointer be assigned to a (CONST char *) variable. Even in the limited situations where writing to this pointer is acceptable, one should take care to respect the copy-on-write semantics required by \fBTcl_Obj\fR's, with appropriate calls to \fBTcl_IsShared\fR and \fBTcl_DuplicateObj\fR prior to any in-place modification of the string representation. The procedure \fBTcl_GetString\fR is used in the common case where the caller does not need the length of the string representation. .PP \fBTcl_GetUnicodeFromObj\fR and \fBTcl_GetUnicode\fR return an object's value as a Unicode string. This is given by the returned pointer and (for \fBTcl_GetUnicodeFromObj\fR) length, which is stored in \fIlengthPtr\fR if it is non-NULL. The storage referenced by the returned byte pointer is owned by the object manager and should not be modified by the caller. The procedure \fBTcl_GetUnicode\fR is used in the common case where the caller does not need the length of the unicode string representation. .PP \fBTcl_GetUniChar\fR returns the \fIindex\fR'th character in the object's Unicode representation. .PP \fBTcl_GetRange\fR returns a newly created object comprised of the characters between \fIfirst\fR and \fIlast\fR (inclusive) in the object's Unicode representation. If the object's Unicode representation is invalid, the Unicode representation is regenerated from the object's string representation. .PP \fBTcl_GetCharLength\fR returns the number of characters (as opposed to bytes) in the string object. .PP \fBTcl_AppendToObj\fR appends the data given by \fIbytes\fR and \fIlength\fR to the string representation of the object specified by \fIobjPtr\fR. If the object has an invalid string representation, then an attempt is made to convert \fIbytes\fR is to the Unicode format. If the conversion is successful, then the converted form of \fIbytes\fR is appended to the object's Unicode representation. Otherwise, the object's Unicode representation is invalidated and converted to the UTF format, and \fIbytes\fR is appended to the object's new string representation. .PP \fBTcl_AppendUnicodeToObj\fR appends the Unicode string given by \fIunicode\fR and \fInumChars\fR to the object specified by \fIobjPtr\fR. If the object has an invalid Unicode representation, then \fIunicode\fR is converted to the UTF format and appended to the object's string representation. Appends are optimized to handle repeated appends relatively efficiently (it overallocates the string or Unicode space to avoid repeated reallocations and copies of object's string value). .PP \fBTcl_AppendObjToObj\fR is similar to \fBTcl_AppendToObj\fR, but it appends the string or Unicode value (whichever exists and is best suited to be appended to \fIobjPtr\fR) of \fIappendObjPtr\fR to \fIobjPtr\fR. .PP \fBTcl_AppendStringsToObj\fR is similar to \fBTcl_AppendToObj\fR except that it can be passed more than one value to append and each value must be a null-terminated string (i.e. none of the values may contain internal null characters). Any number of \fIstring\fR arguments may be provided, but the last argument must be a NULL pointer to indicate the end of the list. .PP \fBTcl_AppendStringsToObjVA\fR is the same as \fBTcl_AppendStringsToObj\fR except that instead of taking a variable number of arguments it takes an argument list. .PP The \fBTcl_SetObjLength\fR procedure changes the length of the string value of its \fIobjPtr\fR argument. If the \fInewLength\fR argument is greater than the space allocated for the object's string, then the string space is reallocated and the old value is copied to the new space; the bytes between the old length of the string and the new length may have arbitrary values. If the \fInewLength\fR argument is less than the current length of the object's string, with \fIobjPtr->length\fR is reduced without reallocating the string space; the original allocated size for the string is recorded in the object, so that the string length can be enlarged in a subsequent call to \fBTcl_SetObjLength\fR without reallocating storage. In all cases \fBTcl_SetObjLength\fR leaves a null character at \fIobjPtr->bytes[newLength]\fR. .PP \fBTcl_AttemptSetObjLength\fR is identical in function to \fBTcl_SetObjLength\fR except that if sufficient memory to satisfy the request cannot be allocated, it does not cause the Tcl interpreter to \fBpanic\fR. Thus, if \fInewLength\fR is greater than the space allocated for the object's string, and there is not enough memory available to satisfy the request, \fBTcl_AttemptSetObjLength\fR will take no action and return 0 to indicate failure. If there is enough memory to satisfy the request, \fBTcl_AttemptSetObjLength\fR behaves just like \fBTcl_SetObjLength\fR and returns 1 to indicate success. .PP The \fBTcl_ConcatObj\fR function returns a new string object whose value is the space-separated concatenation of the string representations of all of the objects in the \fIobjv\fR array. \fBTcl_ConcatObj\fR eliminates leading and trailing white space as it copies the string representations of the \fIobjv\fR array to the result. If an element of the \fIobjv\fR array consists of nothing but white space, then that object is ignored entirely. This white-space removal was added to make the output of the \fBconcat\fR command cleaner-looking. \fBTcl_ConcatObj\fR returns a pointer to a newly-created object whose ref count is zero. .SH "SEE ALSO" Tcl_NewObj, Tcl_IncrRefCount, Tcl_DecrRefCount .SH KEYWORDS append, internal representation, object, object type, string object, string type, string representation, concat, concatenate, unicode tcl8.4.20/doc/Alloc.30000644003604700454610000000555611737050674012615 0ustar dgp771div'\" '\" Copyright (c) 1995-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_Alloc 3 7.5 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_Alloc, Tcl_Free, Tcl_Realloc, Tcl_AttemptAlloc, Tcl_AttemptRealloc, ckalloc, ckfree, ckrealloc, attemptckalloc, attemptckrealloc \- allocate or free heap memory .SH SYNOPSIS .nf \fB#include \fR .sp char * \fBTcl_Alloc\fR(\fIsize\fR) .sp void \fBTcl_Free\fR(\fIptr\fR) .sp char * \fBTcl_Realloc\fR(\fIptr, size\fR) .sp char * \fBTcl_AttemptAlloc\fR(\fIsize\fR) .sp char * \fBTcl_AttemptRealloc\fR(\fIptr, size\fR) .sp char * \fBckalloc\fR(\fIsize\fR) .sp void \fBckfree\fR(\fIptr\fR) .sp char * \fBckrealloc\fR(\fIptr, size\fR) .sp char * \fBattemptckalloc\fR(\fIsize\fR) .sp char * \fBattemptckrealloc\fR(\fIptr, size\fR) .SH ARGUMENTS .AS char *size .AP "unsigned int" size in Size in bytes of the memory block to allocate. .AP char *ptr in Pointer to memory block to free or realloc. .BE .SH DESCRIPTION .PP These procedures provide a platform and compiler independent interface for memory allocation. Programs that need to transfer ownership of memory blocks between Tcl and other modules should use these routines rather than the native \fBmalloc()\fR and \fBfree()\fR routines provided by the C run-time library. .PP \fBTcl_Alloc\fR returns a pointer to a block of at least \fIsize\fR bytes suitably aligned for any use. .PP \fBTcl_Free\fR makes the space referred to by \fIptr\fR available for further allocation. .PP \fBTcl_Realloc\fR changes the size of the block pointed to by \fIptr\fR to \fIsize\fR bytes and returns a pointer to the new block. The contents will be unchanged up to the lesser of the new and old sizes. The returned location may be different from \fIptr\fR. .PP \fBTcl_AttemptAlloc\fR and \fBTcl_AttemptRealloc\fR are identical in function to \fBTcl_Alloc\fR and \fBTcl_Realloc\fR, except that \fBTcl_AttemptAlloc\fR and \fBTcl_AttemptRealloc\fR will not cause the Tcl interpreter to \fBpanic\fR if the memory allocation fails. If the allocation fails, these functions will return NULL. Note that on some platforms, attempting to allocate a block of memory will also cause these functions to return NULL. .PP The procedures \fBckalloc\fR, \fBckfree\fR, \fBckrealloc\fR, \fBattemptckalloc\fR, and \fBattemptckrealloc\fR are implemented as macros. Normally, they are synonyms for the corresponding procedures documented on this page. When Tcl and all modules calling Tcl are compiled with \fBTCL_MEM_DEBUG\fR defined, however, these macros are redefined to be special debugging versions of of these procedures. To support Tcl's memory debugging within a module, use the macros rather than direct calls to \fBTcl_Alloc\fR, etc. .SH KEYWORDS alloc, allocation, free, malloc, memory, realloc, TCL_MEM_DEBUG tcl8.4.20/doc/bgerror.n0000644003604700454610000001002011737050674013276 0ustar dgp771div'\" '\" Copyright (c) 1990-1994 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH bgerror n 7.5 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME bgerror \- Command invoked to process background errors .SH SYNOPSIS \fBbgerror \fImessage\fR .BE .SH DESCRIPTION .PP The \fBbgerror\fR command doesn't exist as built-in part of Tcl. Instead, individual applications or users can define a \fBbgerror\fR command (e.g. as a Tcl procedure) if they wish to handle background errors. .PP A background error is one that occurs in an event handler or some other command that didn't originate with the application. For example, if an error occurs while executing a command specified with the \fBafter\fR command, then it is a background error. For a non-background error, the error can simply be returned up through nested Tcl command evaluations until it reaches the top-level code in the application; then the application can report the error in whatever way it wishes. When a background error occurs, the unwinding ends in the Tcl library and there is no obvious way for Tcl to report the error. .PP When Tcl detects a background error, it saves information about the error and invokes the \fBbgerror\fR command later as an idle event handler. Before invoking \fBbgerror\fR, Tcl restores the \fBerrorInfo\fR and \fBerrorCode\fR variables to their values at the time the error occurred, then it invokes \fBbgerror\fR with the error message as its only argument. Tcl assumes that the application has implemented the \fBbgerror\fR command, and that the command will report the error in a way that makes sense for the application. Tcl will ignore any result returned by the \fBbgerror\fR command as long as no error is generated. .PP If another Tcl error occurs within the \fBbgerror\fR command (for example, because no \fBbgerror\fR command has been defined) then Tcl reports the error itself by writing a message to stderr. .PP If several background errors accumulate before \fBbgerror\fR is invoked to process them, \fBbgerror\fR will be invoked once for each error, in the order they occurred. However, if \fBbgerror\fR returns with a break exception, then any remaining errors are skipped without calling \fBbgerror\fR. .PP Tcl has no default implementation for \fBbgerror\fR. However, in applications using Tk there is a default \fBbgerror\fR procedure which posts a dialog box containing the error message and offers the user a chance to see a stack trace showing where the error occurred. In addition to allowing the user to view the stack trace, the dialog provides an additional application configurable button which may be used, for example, to save the stack trace to a file. By default, this is the behavior associated with that button. This behavior can be redefined by setting the option database values \fB*ErrorDialog.function.text\fR, to specify the caption for the function button, and \fB*ErrorDialog.function.command\fR, to specify the command to be run. The text of the stack trace is appended to the command when it is evaluated. If either of these options is set to the empty string, then the additional button will not be displayed in the dialog. .PP If you are writing code that will be used by others as part of a package or other kind of library, consider avoiding \fBbgerror\fR. The reason for this is that the application programmer may also want to define a \fBbgerror\fR, or use other code that does and thus will have trouble integrating your code. .SH "EXAMPLE" This \fBbgerror\fR procedure appends errors to a file, with a timestamp. .CS proc bgerror {message} { set timestamp [clock format [clock seconds]] set fl [open mylog.txt {WRONLY CREAT APPEND}] puts $fl "$timestamp: bgerror in $::argv '$message'" close $fl } .CE .SH "SEE ALSO" after(n), tclvars(n) .SH KEYWORDS background error, reporting tcl8.4.20/doc/CrtSlave.30000644003604700454610000002366611737050674013310 0ustar dgp771div'\" '\" Copyright (c) 1995-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_CreateSlave 3 7.6 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_IsSafe, Tcl_MakeSafe, Tcl_CreateSlave, Tcl_GetSlave, Tcl_GetMaster, Tcl_GetInterpPath, Tcl_CreateAlias, Tcl_CreateAliasObj, Tcl_GetAlias, Tcl_GetAliasObj, Tcl_ExposeCommand, Tcl_HideCommand \- manage multiple Tcl interpreters, aliases and hidden commands. .SH SYNOPSIS .nf \fB#include \fR .sp int \fBTcl_IsSafe\fR(\fIinterp\fR) .sp int \fBTcl_MakeSafe\fR(\fIinterp\fR) .sp Tcl_Interp * \fBTcl_CreateSlave\fR(\fIinterp, slaveName, isSafe\fR) .sp Tcl_Interp * \fBTcl_GetSlave\fR(\fIinterp, slaveName\fR) .sp Tcl_Interp * \fBTcl_GetMaster\fR(\fIinterp\fR) .sp int \fBTcl_GetInterpPath\fR(\fIaskingInterp, slaveInterp\fR) .sp .VS int \fBTcl_CreateAlias\fR(\fIslaveInterp, slaveCmd, targetInterp, targetCmd, argc, argv\fR) .sp int \fBTcl_CreateAliasObj\fR(\fIslaveInterp, slaveCmd, targetInterp, targetCmd, objc, objv\fR) .VE .sp int \fBTcl_GetAlias\fR(\fIinterp, slaveCmd, targetInterpPtr, targetCmdPtr, argcPtr, argvPtr\fR) .sp .VS int \fBTcl_GetAliasObj\fR(\fIinterp, slaveCmd, targetInterpPtr, targetCmdPtr, objcPtr, objvPtr\fR) .sp int \fBTcl_ExposeCommand\fR(\fIinterp, hiddenCmdName, cmdName\fR) .sp int \fBTcl_HideCommand\fR(\fIinterp, cmdName, hiddenCmdName\fR) .SH ARGUMENTS .AS Tcl_InterpDeleteProc **hiddenCmdName .AP Tcl_Interp *interp in Interpreter in which to execute the specified command. .AP "CONST char" *slaveName in Name of slave interpreter to create or manipulate. .AP int isSafe in If non-zero, a ``safe'' slave that is suitable for running untrusted code is created, otherwise a trusted slave is created. .AP Tcl_Interp *slaveInterp in Interpreter to use for creating the source command for an alias (see below). .AP "CONST char" *slaveCmd in Name of source command for alias. .AP Tcl_Interp *targetInterp in Interpreter that contains the target command for an alias. .AP "CONST char" *targetCmd in Name of target command for alias in \fItargetInterp\fR. .AP int argc in Count of additional arguments to pass to the alias command. .AP "CONST char * CONST" *argv in Vector of strings, the additional arguments to pass to the alias command. This storage is owned by the caller. .AP int objc in Count of additional object arguments to pass to the alias object command. .AP Tcl_Object **objv in Vector of Tcl_Obj structures, the additional object arguments to pass to the alias object command. This storage is owned by the caller. .AP Tcl_Interp **targetInterpPtr in Pointer to location to store the address of the interpreter where a target command is defined for an alias. .AP "CONST char" **targetCmdPtr out Pointer to location to store the address of the name of the target command for an alias. .AP int *argcPtr out Pointer to location to store count of additional arguments to be passed to the alias. The location is in storage owned by the caller. .AP "CONST char" ***argvPtr out Pointer to location to store a vector of strings, the additional arguments to pass to an alias. The location is in storage owned by the caller, the vector of strings is owned by the called function. .AP int *objcPtr out Pointer to location to store count of additional object arguments to be passed to the alias. The location is in storage owned by the caller. .AP Tcl_Obj ***objvPtr out Pointer to location to store a vector of Tcl_Obj structures, the additional arguments to pass to an object alias command. The location is in storage owned by the caller, the vector of Tcl_Obj structures is owned by the called function. .VS .VS 8.4 .AP "CONST char" *cmdName in .VE Name of an exposed command to hide or create. .VS 8.4 .AP "CONST char" *hiddenCmdName in .VE Name under which a hidden command is stored and with which it can be exposed or invoked. .VE .BE .SH DESCRIPTION .PP These procedures are intended for access to the multiple interpreter facility from inside C programs. They enable managing multiple interpreters in a hierarchical relationship, and the management of aliases, commands that when invoked in one interpreter execute a command in another interpreter. The return value for those procedures that return an \fBint\fR is either \fBTCL_OK\fR or \fBTCL_ERROR\fR. If \fBTCL_ERROR\fR is returned then the \fBresult\fR field of the interpreter contains an error message. .PP \fBTcl_CreateSlave\fR creates a new interpreter as a slave of \fIinterp\fR. It also creates a slave command named \fIslaveName\fR in \fIinterp\fR which allows \fIinterp\fR to manipulate the new slave. If \fIisSafe\fR is zero, the command creates a trusted slave in which Tcl code has access to all the Tcl commands. If it is \fB1\fR, the command creates a ``safe'' slave in which Tcl code has access only to set of Tcl commands defined as ``Safe Tcl''; see the manual entry for the Tcl \fBinterp\fR command for details. If the creation of the new slave interpreter failed, \fBNULL\fR is returned. .PP \fBTcl_IsSafe\fR returns \fB1\fR if \fIinterp\fR is ``safe'' (was created with the \fBTCL_SAFE_INTERPRETER\fR flag specified), \fB0\fR otherwise. .PP \fBTcl_MakeSafe\fR marks \fIinterp\fR as ``safe'', so that future calls to \fBTcl_IsSafe\fR will return 1. It also removes all known potentially-unsafe core functionality (both commands and variables) from \fIinterp\fR. However, it cannot know what parts of an extension or application are safe and does not make any attempt to remove those parts, so safety is not guaranteed after calling \fBTcl_MakeSafe\fR. Callers will want to take care with their use of \fBTcl_MakeSafe\fR to avoid false claims of safety. For many situations, \fBTcl_CreateSlave\fR may be a better choice, since it creates interpreters in a known-safe state. .PP \fBTcl_GetSlave\fR returns a pointer to a slave interpreter of \fIinterp\fR. The slave interpreter is identified by \fIslaveName\fR. If no such slave interpreter exists, \fBNULL\fR is returned. .PP \fBTcl_GetMaster\fR returns a pointer to the master interpreter of \fIinterp\fR. If \fIinterp\fR has no master (it is a top-level interpreter) then \fBNULL\fR is returned. .PP \fBTcl_GetInterpPath\fR sets the \fIresult\fR field in \fIaskingInterp\fR to the relative path between \fIaskingInterp\fR and \fIslaveInterp\fR; \fIslaveInterp\fR must be a slave of \fIaskingInterp\fR. If the computation of the relative path succeeds, \fBTCL_OK\fR is returned, else \fBTCL_ERROR\fR is returned and the \fIresult\fR field in \fIaskingInterp\fR contains the error message. .PP .VS \fBTcl_CreateAlias\fR creates an object command named \fIslaveCmd\fR in \fIslaveInterp\fR that when invoked, will cause the command \fItargetCmd\fR to be invoked in \fItargetInterp\fR. The arguments specified by the strings contained in \fIargv\fR are always prepended to any arguments supplied in the invocation of \fIslaveCmd\fR and passed to \fItargetCmd\fR. This operation returns \fBTCL_OK\fR if it succeeds, or \fBTCL_ERROR\fR if it fails; in that case, an error message is left in the object result of \fIslaveInterp\fR. Note that there are no restrictions on the ancestry relationship (as created by \fBTcl_CreateSlave\fR) between \fIslaveInterp\fR and \fItargetInterp\fR. Any two interpreters can be used, without any restrictions on how they are related. .PP \fBTcl_CreateAliasObj\fR is similar to \fBTcl_CreateAlias\fR except that it takes a vector of objects to pass as additional arguments instead of a vector of strings. .VE .PP \fBTcl_GetAlias\fR returns information about an alias \fIaliasName\fR in \fIinterp\fR. Any of the result fields can be \fBNULL\fR, in which case the corresponding datum is not returned. If a result field is non\-\fBNULL\fR, the address indicated is set to the corresponding datum. For example, if \fItargetNamePtr\fR is non\-\fBNULL\fR it is set to a pointer to the string containing the name of the target command. .VS .PP \fBTcl_GetAliasObj\fR is similar to \fBTcl_GetAlias\fR except that it returns a pointer to a vector of Tcl_Obj structures instead of a vector of strings. .PP \fBTcl_ExposeCommand\fR moves the command named \fIhiddenCmdName\fR from the set of hidden commands to the set of exposed commands, putting it under the name \fIcmdName\fR. \fIHiddenCmdName\fR must be the name of an existing hidden command, or the operation will return \fBTCL_ERROR\fR and leave an error message in the \fIresult\fR field in \fIinterp\fR. If an exposed command named \fIcmdName\fR already exists, the operation returns \fBTCL_ERROR\fR and leaves an error message in the object result of \fIinterp\fR. If the operation succeeds, it returns \fBTCL_OK\fR. After executing this command, attempts to use \fIcmdName\fR in a call to \fBTcl_Eval\fR or with the Tcl \fBeval\fR command will again succeed. .PP \fBTcl_HideCommand\fR moves the command named \fIcmdName\fR from the set of exposed commands to the set of hidden commands, under the name \fIhiddenCmdName\fR. \fICmdName\fR must be the name of an existing exposed command, or the operation will return \fBTCL_ERROR\fR and leave an error message in the object result of \fIinterp\fR. Currently both \fIcmdName\fR and \fIhiddenCmdName\fR must not contain namespace qualifiers, or the operation will return \fBTCL_ERROR\fR and leave an error message in the object result of \fIinterp\fR. The \fICmdName\fR will be looked up in the global namespace, and not relative to the current namespace, even if the current namespace is not the global one. If a hidden command whose name is \fIhiddenCmdName\fR already exists, the operation also returns \fBTCL_ERROR\fR and the \fIresult\fR field in \fIinterp\fR contains an error message. If the operation succeeds, it returns \fBTCL_OK\fR. After executing this command, attempts to use \fIcmdName\fR in a call to \fBTcl_Eval\fR or with the Tcl \fBeval\fR command will fail. .PP For a description of the Tcl interface to multiple interpreters, see \fIinterp(n)\fR. .SH "SEE ALSO" interp .SH KEYWORDS alias, command, exposed commands, hidden commands, interpreter, invoke, master, slave tcl8.4.20/doc/variable.n0000644003604700454610000000600611737050674013432 0ustar dgp771div'\" '\" Copyright (c) 1993-1997 Bell Labs Innovations for Lucent Technologies '\" Copyright (c) 1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH variable n 8.0 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME variable \- create and initialize a namespace variable .SH SYNOPSIS \fBvariable \fR?\fIname value...\fR? \fIname \fR?\fIvalue\fR? .BE .SH DESCRIPTION .PP This command is normally used within a \fBnamespace eval\fR command to create one or more variables within a namespace. Each variable \fIname\fR is initialized with \fIvalue\fR. The \fIvalue\fR for the last variable is optional. .PP If a variable \fIname\fR does not exist, it is created. In this case, if \fIvalue\fR is specified, it is assigned to the newly created variable. If no \fIvalue\fR is specified, the new variable is left undefined. If the variable already exists, it is set to \fIvalue\fR if \fIvalue\fR is specified or left unchanged if no \fIvalue\fR is given. Normally, \fIname\fR is unqualified (does not include the names of any containing namespaces), and the variable is created in the current namespace. If \fIname\fR includes any namespace qualifiers, the variable is created in the specified namespace. If the variable is not defined, it will be visible to the \fBnamespace which\fR command, but not to the \fBinfo exists\fR command. .PP If the \fBvariable\fR command is executed inside a Tcl procedure, it creates local variables linked to the corresponding namespace variables (and therefore these variables are listed by \fBinfo vars\fR.) In this way the \fBvariable\fR command resembles the \fBglobal\fR command, although the \fBglobal\fR command only links to variables in the global namespace. If any \fIvalue\fRs are given, they are used to modify the values of the associated namespace variables. If a namespace variable does not exist, it is created and optionally initialized. .PP A \fIname\fR argument cannot reference an element within an array. Instead, \fIname\fR should reference the entire array, and the initialization \fIvalue\fR should be left off. After the variable has been declared, elements within the array can be set using ordinary \fBset\fR or \fBarray\fR commands. .SH EXAMPLES Create a variable in a namespace: .CS namespace eval foo { \fBvariable\fR bar 12345 } .CE .PP Create an array in a namespace: .CS namespace eval someNS { \fBvariable\fR someAry array set someAry { someName someValue otherName otherValue } } .CE .PP Access variables in namespaces from a procedure: .CS namespace eval foo { proc spong {} { # Variable in this namespace \fBvariable\fR bar puts "bar is $bar" # Variable in another namespace \fBvariable\fR ::someNS::someAry parray someAry } } .CE .SH "SEE ALSO" global(n), namespace(n), upvar(n) .SH KEYWORDS global, namespace, procedure, variable tcl8.4.20/doc/CmdCmplt.30000644003604700454610000000171311737050674013255 0ustar dgp771div'\" '\" Copyright (c) 1989-1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_CommandComplete 3 "" Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_CommandComplete \- Check for unmatched braces in a Tcl command .SH SYNOPSIS .nf \fB#include \fR .sp int \fBTcl_CommandComplete\fR(\fIcmd\fR) .SH ARGUMENTS .AS "CONST char" *cmd .AP "CONST char" *cmd in Command string to test for completeness. .BE .SH DESCRIPTION .PP \fBTcl_CommandComplete\fR takes a Tcl command string as argument and determines whether it contains one or more complete commands (i.e. there are no unclosed quotes, braces, brackets, or variable references). If the command string is complete then it returns 1; otherwise it returns 0. .SH KEYWORDS complete command, partial command tcl8.4.20/doc/Access.30000644003604700454610000000535211737050674012756 0ustar dgp771div'\" '\" Copyright (c) 1998-1999 Scriptics Corporation '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_Access 3 8.1 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_Access, Tcl_Stat \- check file permissions and other attributes .SH SYNOPSIS .nf \fB#include \fR .sp int \fBTcl_Access\fR(\fIpath\fR, \fImode\fR) .sp int \fBTcl_Stat\fR(\fIpath\fR, \fIstatPtr\fR) .SH ARGUMENTS .AS "struct stat" *statPtr in .AP char *path in Native name of the file to check the attributes of. .AP int mode in Mask consisting of one or more of R_OK, W_OK, X_OK and F_OK. R_OK, W_OK and X_OK request checking whether the file exists and has read, write and execute permissions, respectively. F_OK just requests checking for the existence of the file. .AP "struct stat" *statPtr out The structure that contains the result. .BE .SH DESCRIPTION .PP As of Tcl 8.4, the object-based APIs \fBTcl_FSAccess\fR and \fBTcl_FSStat\fR should be used in preference to \fBTcl_Access\fR and \fBTcl_Stat\fR, wherever possible. .PP There are two reasons for calling \fBTcl_Access\fR and \fBTcl_Stat\fR rather than calling system level functions \fBaccess\fR and \fBstat\fR directly. First, the Windows implementation of both functions fixes some bugs in the system level calls. Second, both \fBTcl_Access\fR and \fBTcl_Stat\fR (as well as \fBTcl_OpenFileChannelProc\fR) hook into a linked list of functions. This allows the possibility to reroute file access to alternative media or access methods. .PP \fBTcl_Access\fR checks whether the process would be allowed to read, write or test for existence of the file (or other file system object) whose name is pathname. If pathname is a symbolic link on Unix, then permissions of the file referred by this symbolic link are tested. .PP On success (all requested permissions granted), zero is returned. On error (at least one bit in mode asked for a permission that is denied, or some other error occurred), -1 is returned. .PP \fBTcl_Stat\fR fills the stat structure \fIstatPtr\fR with information about the specified file. You do not need any access rights to the file to get this information but you need search rights to all directories named in the path leading to the file. The stat structure includes info regarding device, inode (always 0 on Windows), privilege mode, nlink (always 1 on Windows), user id (always 0 on Windows), group id (always 0 on Windows), rdev (same as device on Windows), size, last access time, last modification time, and creation time. .PP If \fIpath\fR exists, \fBTcl_Stat\fR returns 0 and the stat structure is filled with data. Otherwise, -1 is returned, and no stat info is given. .SH KEYWORDS stat, access tcl8.4.20/doc/list.n0000644003604700454610000000300511737050674012614 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" Copyright (c) 2001 Kevin B. Kenny. All rights reserved. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH list n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME list \- Create a list .SH SYNOPSIS \fBlist \fR?\fIarg arg ...\fR? .BE .SH DESCRIPTION .PP This command returns a list comprised of all the \fIarg\fRs, or an empty string if no \fIarg\fRs are specified. Braces and backslashes get added as necessary, so that the \fBlindex\fR command may be used on the result to re-extract the original arguments, and also so that \fBeval\fR may be used to execute the resulting list, with \fIarg1\fR comprising the command's name and the other \fIarg\fRs comprising its arguments. \fBList\fR produces slightly different results than \fBconcat\fR: \fBconcat\fR removes one level of grouping before forming the list, while \fBlist\fR works directly from the original arguments. .SH EXAMPLE The command .CS \fBlist\fR a b "c d e " " f {g h}" .CE will return .CS \fBa b {c d e } { f {g h}}\fR .CE while \fBconcat\fR with the same arguments will return .CS \fBa b c d e f {g h}\fR .CE .SH "SEE ALSO" lappend(n), lindex(n), linsert(n), llength(n), lrange(n), lreplace(n), lsearch(n), .VS 8.4 lset(n), .VE 8.4 lsort(n) .SH KEYWORDS element, list tcl8.4.20/doc/seek.n0000644003604700454610000000537411737050674012603 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH seek n 8.1 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME seek \- Change the access position for an open channel .SH SYNOPSIS \fBseek \fIchannelId offset \fR?\fIorigin\fR? .BE .SH DESCRIPTION .PP Changes the current access position for \fIchannelId\fR. .PP .VS \fIChannelId\fR must be an identifier for an open channel such as a Tcl standard channel (\fBstdin\fR, \fBstdout\fR, or \fBstderr\fR), the return value from an invocation of \fBopen\fR or \fBsocket\fR, or the result of a channel creation command provided by a Tcl extension. .VE .PP The \fIoffset\fR and \fIorigin\fR arguments specify the position at which the next read or write will occur for \fIchannelId\fR. \fIOffset\fR must be an integer (which may be negative) and \fIorigin\fR must be one of the following: .TP 10 \fBstart\fR The new access position will be \fIoffset\fR bytes from the start of the underlying file or device. .TP 10 \fBcurrent\fR The new access position will be \fIoffset\fR bytes from the current access position; a negative \fIoffset\fR moves the access position backwards in the underlying file or device. .TP 10 \fBend\fR The new access position will be \fIoffset\fR bytes from the end of the file or device. A negative \fIoffset\fR places the access position before the end of file, and a positive \fIoffset\fR places the access position after the end of file. .LP The \fIorigin\fR argument defaults to \fBstart\fR. .PP The command flushes all buffered output for the channel before the command returns, even if the channel is in nonblocking mode. It also discards any buffered and unread input. This command returns an empty string. An error occurs if this command is applied to channels whose underlying file or device does not support seeking. .PP .VS 8.1 Note that \fIoffset\fR values are byte offsets, not character offsets. Both \fBseek\fR and \fBtell\fR operate in terms of bytes, not characters, unlike \fBread\fR. .VE 8.1 .SH EXAMPLES Read a file twice: .CS set f [open file.txt] set data1 [read $f] \fBseek\fR $f 0 set data2 [read $f] close $f # $data1 == $data2 if the file wasn't updated .CE .PP Read the last 10 bytes from a file: .CS set f [open file.data] # This is guaranteed to work with binary data but # may fail with other encodings... fconfigure $f -translation binary \fBseek\fR $f -10 end set data [read $f 10] close $f .CE .SH "SEE ALSO" file(n), open(n), close(n), gets(n), tell(n), Tcl_StandardChannels(3) .SH KEYWORDS access position, file, seek tcl8.4.20/doc/open.n0000644003604700454610000004420712052456743012611 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH open n 8.3 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME open \- Open a file-based or command pipeline channel .SH SYNOPSIS .sp \fBopen \fIfileName\fR .br \fBopen \fIfileName access\fR .br \fBopen \fIfileName access permissions\fR .BE .SH DESCRIPTION .PP This command opens a file, serial port, or command pipeline and returns a channel identifier that may be used in future invocations of commands like \fBread\fR, \fBputs\fR, and \fBclose\fR. If the first character of \fIfileName\fR is not \fB|\fR then the command opens a file: \fIfileName\fR gives the name of the file to open, and it must conform to the conventions described in the \fBfilename\fR manual entry. .PP The \fIaccess\fR argument, if present, indicates the way in which the file (or command pipeline) is to be accessed. In the first form \fIaccess\fR may have any of the following values: .TP 15 \fBr\fR Open the file for reading only; the file must already exist. This is the default value if \fIaccess\fR is not specified. .TP 15 \fBr+\fR Open the file for both reading and writing; the file must already exist. .TP 15 \fBw\fR Open the file for writing only. Truncate it if it exists. If it doesn't exist, create a new file. .TP 15 \fBw+\fR Open the file for reading and writing. Truncate it if it exists. If it doesn't exist, create a new file. .TP 15 \fBa\fR Open the file for writing only. If the file doesn't exist, create a new empty file. Set the file pointer to the end of the file prior to each write. .TP 15 \fBa+\fR Open the file for reading and writing. If the file doesn't exist, create a new empty file. Set the initial access position to the end of the file. .PP In the second form, \fIaccess\fR consists of a list of any of the following flags, all of which have the standard POSIX meanings. One of the flags must be either \fBRDONLY\fR, \fBWRONLY\fR or \fBRDWR\fR. .TP 15 \fBRDONLY\fR Open the file for reading only. .TP 15 \fBWRONLY\fR Open the file for writing only. .TP 15 \fBRDWR\fR Open the file for both reading and writing. .TP 15 \fBAPPEND\fR Set the file pointer to the end of the file prior to each write. .TP 15 \fBCREAT\fR Create the file if it doesn't already exist (without this flag it is an error for the file not to exist). .TP 15 \fBEXCL\fR If \fBCREAT\fR is also specified, an error is returned if the file already exists. .TP 15 \fBNOCTTY\fR If the file is a terminal device, this flag prevents the file from becoming the controlling terminal of the process. .TP 15 \fBNONBLOCK\fR Prevents the process from blocking while opening the file, and possibly in subsequent I/O operations. The exact behavior of this flag is system- and device-dependent; its use is discouraged (it is better to use the \fBfconfigure\fR command to put a file in nonblocking mode). For details refer to your system documentation on the \fBopen\fR system call's \fBO_NONBLOCK\fR flag. .TP 15 \fBTRUNC\fR If the file exists it is truncated to zero length. .PP If a new file is created as part of opening it, \fIpermissions\fR (an integer) is used to set the permissions for the new file in conjunction with the process's file mode creation mask. \fIPermissions\fR defaults to 0666. .PP Note that if you are going to be reading or writing binary data from the channel created by this command, you should use the \fBfconfigure\fR command to change the \fB-translation\fR option of the channel to \fBbinary\fR before transferring any binary data. This is in contrast to the ``b'' character passed as part of the equivalent of the \fIaccess\fR parameter to some versions of the C library \fIfopen()\fR function. .SH "COMMAND PIPELINES" .PP If the first character of \fIfileName\fR is ``|'' then the remaining characters of \fIfileName\fR are treated as a list of arguments that describe a command pipeline to invoke, in the same style as the arguments for \fBexec\fR. In this case, the channel identifier returned by \fBopen\fR may be used to write to the command's input pipe or read from its output pipe, depending on the value of \fIaccess\fR. If write-only access is used (e.g. \fIaccess\fR is \fBw\fR), then standard output for the pipeline is directed to the current standard output unless overridden by the command. If read-only access is used (e.g. \fIaccess\fR is \fBr\fR), standard input for the pipeline is taken from the current standard input unless overridden by the command. The id of the spawned process is accessible through the \fBpid\fR command, using the channel id returned by \fBopen\fR as argument. .PP If the command (or one of the commands) executed in the command pipeline returns an error (according to the definition in \fBexec\fR), a Tcl error is generated when \fBclose\fR is called on the channel unless the pipeline is in non-blocking mode then no exit status is returned (a silent \fBclose\fR with -blocking 0). .PP It is often useful to use the \fBfileevent\fR command with pipelines so other processing may happen at the same time as running the command in the background. .VS 8.4 .SH "SERIAL COMMUNICATIONS" .PP If \fIfileName\fR refers to a serial port, then the specified serial port is opened and initialized in a platform-dependent manner. Acceptable values for the \fIfileName\fR to use to open a serial port are described in the PORTABILITY ISSUES section. .PP The \fBfconfigure\fR command can be used to query and set additional configuration options specific to serial ports (where supported): .TP \fB\-mode\fR \fIbaud\fB,\fIparity\fB,\fIdata\fB,\fIstop\fR This option is a set of 4 comma-separated values: the baud rate, parity, number of data bits, and number of stop bits for this serial port. The \fIbaud\fR rate is a simple integer that specifies the connection speed. \fIParity\fR is one of the following letters: \fBn\fR, \fBo\fR, \fBe\fR, \fBm\fR, \fBs\fR; respectively signifying the parity options of ``none'', ``odd'', ``even'', ``mark'', or ``space''. \fIData\fR is the number of data bits and should be an integer from 5 to 8, while \fIstop\fR is the number of stop bits and should be the integer 1 or 2. .TP \fB\-handshake\fR \fItype\fR (Windows and Unix). This option is used to setup automatic handshake control. Note that not all handshake types maybe supported by your operating system. The \fItype\fR parameter is case-independent. .sp If \fItype\fR is \fBnone\fR then any handshake is switched off. \fBrtscts\fR activates hardware handshake. Hardware handshake signals are described below. For software handshake \fBxonxoff\fR the handshake characters can be redefined with \fB-xchar\fR. An additional hardware handshake \fBdtrdsr\fR is available only under Windows. There is no default handshake configuration, the initial value depends on your operating system settings. The \fB-handshake\fR option cannot be queried. .TP \fB\-queue\fR (Windows and Unix). The \fB-queue\fR option can only be queried. It returns a list of two integers representing the current number of bytes in the input and output queue respectively. .TP \fB\-timeout\fR \fImsec\fR (Windows and Unix). This option is used to set the timeout for blocking read operations. It specifies the maximum interval between the reception of two bytes in milliseconds. For Unix systems the granularity is 100 milliseconds. The \fB-timeout\fR option does not affect write operations or nonblocking reads. This option cannot be queried. .TP \fB\-ttycontrol\fR \fI{signal boolean signal boolean ...}\fR (Windows and Unix). This option is used to setup the handshake output lines (see below) permanently or to send a BREAK over the serial line. The \fIsignal\fR names are case-independent. \fB{RTS 1 DTR 0}\fR sets the RTS output to high and the DTR output to low. The BREAK condition (see below) is enabled and disabled with \fB{BREAK 1}\fR and \fB{BREAK 0}\fR respectively. It's not a good idea to change the \fBRTS\fR (or \fBDTR\fR) signal with active hardware handshake \fBrtscts\fR (or \fBdtrdsr\fR). The result is unpredictable. The \fB-ttycontrol\fR option cannot be queried. .TP \fB\-ttystatus\fR (Windows and Unix). The \fB-ttystatus\fR option can only be queried. It returns the current modem status and handshake input signals (see below). The result is a list of signal,value pairs with a fixed order, e.g. \fB{CTS 1 DSR 0 RING 1 DCD 0}\fR. The \fIsignal\fR names are returned upper case. .TP \fB\-xchar\fR \fI{xonChar xoffChar}\fR (Windows and Unix). This option is used to query or change the software handshake characters. Normally the operating system default should be DC1 (0x11) and DC3 (0x13) representing the ASCII standard XON and XOFF characters. .TP \fB\-pollinterval\fR \fImsec\fR (Windows only). This option is used to set the maximum time between polling for fileevents. This affects the time interval between checking for events throughout the Tcl interpreter (the smallest value always wins). Use this option only if you want to poll the serial port more or less often than 10 msec (the default). .TP \fB\-sysbuffer\fR \fIinSize\fR .TP \fB\-sysbuffer\fR \fI{inSize outSize}\fR (Windows only). This option is used to change the size of Windows system buffers for a serial channel. Especially at higher communication rates the default input buffer size of 4096 bytes can overrun for latent systems. The first form specifies the input buffer size, in the second form both input and output buffers are defined. .TP \fB\-lasterror\fR (Windows only). This option is query only. In case of a serial communication error, \fBread\fR or \fBputs\fR returns a general Tcl file I/O error. \fBfconfigure -lasterror\fR can be called to get a list of error details. See below for an explanation of the various error codes. .SH "SERIAL PORT SIGNALS" .PP RS-232 is the most commonly used standard electrical interface for serial communications. A negative voltage (-3V..-12V) define a mark (on=1) bit and a positive voltage (+3..+12V) define a space (off=0) bit (RS-232C). The following signals are specified for incoming and outgoing data, status lines and handshaking. Here we are using the terms \fIworkstation\fR for your computer and \fImodem\fR for the external device, because some signal names (DCD, RI) come from modems. Of course your external device may use these signal lines for other purposes. .IP \fBTXD(output)\fR \fBTransmitted Data:\fR Outgoing serial data. .IP \fBRXD(input)\fR \fBReceived Data:\fRIncoming serial data. .IP \fBRTS(output)\fR \fBRequest To Send:\fR This hardware handshake line informs the modem that your workstation is ready to receive data. Your workstation may automatically reset this signal to indicate that the input buffer is full. .IP \fBCTS(input)\fR \fBClear To Send:\fR The complement to RTS. Indicates that the modem is ready to receive data. .IP \fBDTR(output)\fR \fBData Terminal Ready:\fR This signal tells the modem that the workstation is ready to establish a link. DTR is often enabled automatically whenever a serial port is opened. .IP \fBDSR(input)\fR \fBData Set Ready:\fR The complement to DTR. Tells the workstation that the modem is ready to establish a link. .IP \fBDCD(input)\fR \fBData Carrier Detect:\fR This line becomes active when a modem detects a "Carrier" signal. .IP \fBRI(input)\fR \fBRing Indicator:\fR Goes active when the modem detects an incoming call. .IP \fBBREAK\fR A BREAK condition is not a hardware signal line, but a logical zero on the TXD or RXD lines for a long period of time, usually 250 to 500 milliseconds. Normally a receive or transmit data signal stays at the mark (on=1) voltage until the next character is transferred. A BREAK is sometimes used to reset the communications line or change the operating mode of communications hardware. .SH "ERROR CODES (Windows only)" .PP A lot of different errors may occur during serial read operations or during event polling in background. The external device may have been switched off, the data lines may be noisy, system buffers may overrun or your mode settings may be wrong. That's why a reliable software should always \fBcatch\fR serial read operations. In cases of an error Tcl returns a general file I/O error. Then \fBfconfigure -lasterror\fR may help to locate the problem. The following error codes may be returned. .TP 10 \fBRXOVER\fR Windows input buffer overrun. The data comes faster than your scripts reads it or your system is overloaded. Use \fBfconfigure -sysbuffer\fR to avoid a temporary bottleneck and/or make your script faster. .TP 10 \fBTXFULL\fR Windows output buffer overrun. Complement to RXOVER. This error should practically not happen, because Tcl cares about the output buffer status. .TP 10 \fBOVERRUN\fR UART buffer overrun (hardware) with data lost. The data comes faster than the system driver receives it. Check your advanced serial port settings to enable the FIFO (16550) buffer and/or setup a lower(1) interrupt threshold value. .TP 10 \fBRXPARITY\fR A parity error has been detected by your UART. Wrong parity settings with \fBfconfigure -mode\fR or a noisy data line (RXD) may cause this error. .TP 10 \fBFRAME\fR A stop-bit error has been detected by your UART. Wrong mode settings with \fBfconfigure -mode\fR or a noisy data line (RXD) may cause this error. .TP 10 \fBBREAK\fR A BREAK condition has been detected by your UART (see above). .VE .SH "PORTABILITY ISSUES" .TP \fBWindows \fR(all versions) Valid values for \fIfileName\fR to open a serial port are of the form \fBcom\fIX\fB:\fR, where \fIX\fR is a number, generally from 1 to 4. This notation only works for serial ports from 1 to 9, if the system happens to have more than four. An attempt to open a serial port that does not exist or has a number greater than 9 will fail. An alternate form of opening serial ports is to use the filename \fB\e\e.\ecomX\fR, where X is any number that corresponds to a serial port; please note that this method is considerably slower on Windows 95 and Windows 98. .TP \fBWindows NT\fR When running Tcl interactively, there may be some strange interactions between the real console, if one is present, and a command pipeline that uses standard input or output. If a command pipeline is opened for reading, some of the lines entered at the console will be sent to the command pipeline and some will be sent to the Tcl evaluator. If a command pipeline is opened for writing, keystrokes entered into the console are not visible until the pipe is closed. This behavior occurs whether the command pipeline is executing 16-bit or 32-bit applications. These problems only occur because both Tcl and the child application are competing for the console at the same time. If the command pipeline is started from a script, so that Tcl is not accessing the console, or if the command pipeline does not use standard input or output, but is redirected from or to a file, then the above problems do not occur. .TP \fBWindows 95\fR A command pipeline that executes a 16-bit DOS application cannot be opened for both reading and writing, since 16-bit DOS applications that receive standard input from a pipe and send standard output to a pipe run synchronously. Command pipelines that do not execute 16-bit DOS applications run asynchronously and can be opened for both reading and writing. .sp When running Tcl interactively, there may be some strange interactions between the real console, if one is present, and a command pipeline that uses standard input or output. If a command pipeline is opened for reading from a 32-bit application, some of the keystrokes entered at the console will be sent to the command pipeline and some will be sent to the Tcl evaluator. If a command pipeline is opened for writing to a 32-bit application, no output is visible on the console until the pipe is closed. These problems only occur because both Tcl and the child application are competing for the console at the same time. If the command pipeline is started from a script, so that Tcl is not accessing the console, or if the command pipeline does not use standard input or output, but is redirected from or to a file, then the above problems do not occur. .sp Whether or not Tcl is running interactively, if a command pipeline is opened for reading from a 16-bit DOS application, the call to \fBopen\fR will not return until end-of-file has been received from the command pipeline's standard output. If a command pipeline is opened for writing to a 16-bit DOS application, no data will be sent to the command pipeline's standard output until the pipe is actually closed. This problem occurs because 16-bit DOS applications are run synchronously, as described above. .TP \fBUnix\fR\0\0\0\0\0\0\0 Valid values for \fIfileName\fR to open a serial port are generally of the form \fB/dev/tty\fIX\fR, where \fIX\fR is \fBa\fR or \fBb\fR, but the name of any pseudo-file that maps to a serial port may be used. .VS 8.4 Advanced configuration options are only supported for serial ports when Tcl is built to use the POSIX serial interface. .VE 8.4 .sp When running Tcl interactively, there may be some strange interactions between the console, if one is present, and a command pipeline that uses standard input. If a command pipeline is opened for reading, some of the lines entered at the console will be sent to the command pipeline and some will be sent to the Tcl evaluator. This problem only occurs because both Tcl and the child application are competing for the console at the same time. If the command pipeline is started from a script, so that Tcl is not accessing the console, or if the command pipeline does not use standard input, but is redirected from a file, then the above problem does not occur. .LP See the PORTABILITY ISSUES section of the \fBexec\fR command for additional information not specific to command pipelines about executing applications on the various platforms .SH "EXAMPLE" Open a command pipeline and catch any errors: .CS set fl [\fBopen\fR "| ls this_file_does_not_exist"] set data [read $fl] if {[catch {close $fl} err]} { puts "ls command failed: $err" } .CE .SH "SEE ALSO" file(n), close(n), filename(n), fconfigure(n), gets(n), read(n), puts(n), exec(n), pid(n), fopen(3) .SH KEYWORDS access mode, append, create, file, non-blocking, open, permissions, pipeline, process, serial tcl8.4.20/doc/UniCharIsAlpha.30000644003604700454610000000505211737050674014345 0ustar dgp771div'\" '\" Copyright (c) 1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_UniCharIsAlpha 3 "8.1" Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_UniCharIsAlnum, Tcl_UniCharIsAlpha, Tcl_UniCharIsControl, Tcl_UniCharIsDigit, Tcl_UniCharIsGraph, Tcl_UniCharIsLower, Tcl_UniCharIsPrint, Tcl_UniCharIsPunct, Tcl_UniCharIsSpace, Tcl_UniCharIsUpper, Tcl_UniCharIsWordChar \- routines for classification of Tcl_UniChar characters .SH SYNOPSIS .nf \fB#include \fR .sp int \fBTcl_UniCharIsAlnum\fR(\fIch\fR) .sp int \fBTcl_UniCharIsAlpha\fR(\fIch\fR) .sp int \fBTcl_UniCharIsControl\fR(\fIch\fR) .sp int \fBTcl_UniCharIsDigit\fR(\fIch\fR) .sp int \fBTcl_UniCharIsGraph\fR(\fIch\fR) .sp int \fBTcl_UniCharIsLower\fR(\fIch\fR) .sp int \fBTcl_UniCharIsPrint\fR(\fIch\fR) .sp int \fBTcl_UniCharIsPunct\fR(\fIch\fR) .sp int \fBTcl_UniCharIsSpace\fR(\fIch\fR) .sp int \fBTcl_UniCharIsUpper\fR(\fIch\fR) .sp int \fBTcl_UniCharIsWordChar\fR(\fIch\fR) .SH ARGUMENTS .AP int ch in The Tcl_UniChar to be examined. .BE .SH DESCRIPTION .PP All of the routines described examine Tcl_UniChars and return a boolean value. A non-zero return value means that the character does belong to the character class associated with the called routine. The rest of this document just describes the character classes associated with the various routines. .PP Note: A Tcl_UniChar is a Unicode character represented as an unsigned, fixed-size quantity. .SH CHARACTER CLASSES .PP \fBTcl_UniCharIsAlnum\fR tests if the character is an alphanumeric Unicode character. .PP \fBTcl_UniCharIsAlpha\fR tests if the character is an alphabetic Unicode character. .PP \fBTcl_UniCharIsControl\fR tests if the character is a Unicode control character. .PP \fBTcl_UniCharIsDigit\fR tests if the character is a numeric Unicode character. .PP \fBTcl_UniCharIsGraph\fR tests if the character is any Unicode print character except space. .PP \fBTcl_UniCharIsLower\fR tests if the character is a lowercase Unicode character. .PP \fBTcl_UniCharIsPrint\fR tests if the character is a Unicode print character. .PP \fBTcl_UniCharIsPunct\fR tests if the character is a Unicode punctuation character. .PP \fBTcl_UniCharIsSpace\fR tests if the character is a whitespace Unicode character. .PP \fBTcl_UniCharIsUpper\fR tests if the character is an uppercase Unicode character. .PP \fBTcl_UniCharIsWordChar\fR tests if the character is alphanumeric or a connector punctuation mark. .SH KEYWORDS unicode, classification tcl8.4.20/doc/DoOneEvent.30000644003604700454610000001000611737050674013553 0ustar dgp771div'\" '\" Copyright (c) 1990-1992 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_DoOneEvent 3 7.5 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_DoOneEvent \- wait for events and invoke event handlers .SH SYNOPSIS .nf \fB#include \fR .sp int \fBTcl_DoOneEvent\fR(\fIflags\fR) .SH ARGUMENTS .AS int flags .AP int flags in This parameter is normally zero. It may be an OR-ed combination of any of the following flag bits: TCL_WINDOW_EVENTS, TCL_FILE_EVENTS, TCL_TIMER_EVENTS, TCL_IDLE_EVENTS, TCL_ALL_EVENTS, or TCL_DONT_WAIT. .BE .SH DESCRIPTION .PP This procedure is the entry point to Tcl's event loop; it is responsible for waiting for events and dispatching event handlers created with procedures such as \fBTk_CreateEventHandler\fR, \fBTcl_CreateFileHandler\fR, \fBTcl_CreateTimerHandler\fR, and \fBTcl_DoWhenIdle\fR. \fBTcl_DoOneEvent\fR checks to see if events are already present on the Tcl event queue; if so, it calls the handler(s) for the first (oldest) event, removes it from the queue, and returns. If there are no events ready to be handled, then \fBTcl_DoOneEvent\fR checks for new events from all possible sources. If any are found, it puts all of them on Tcl's event queue, calls handlers for the first event on the queue, and returns. If no events are found, \fBTcl_DoOneEvent\fR checks for \fBTcl_DoWhenIdle\fR callbacks; if any are found, it invokes all of them and returns. Finally, if no events or idle callbacks have been found, then \fBTcl_DoOneEvent\fR sleeps until an event occurs; then it adds any new events to the Tcl event queue, calls handlers for the first event, and returns. The normal return value is 1 to signify that some event was processed (see below for other alternatives). .PP If the \fIflags\fR argument to \fBTcl_DoOneEvent\fR is non-zero, it restricts the kinds of events that will be processed by \fBTcl_DoOneEvent\fR. \fIFlags\fR may be an OR-ed combination of any of the following bits: .TP 27 \fBTCL_WINDOW_EVENTS\fR \- Process window system events. .TP 27 \fBTCL_FILE_EVENTS\fR \- Process file events. .TP 27 \fBTCL_TIMER_EVENTS\fR \- Process timer events. .TP 27 \fBTCL_IDLE_EVENTS\fR \- Process idle callbacks. .TP 27 \fBTCL_ALL_EVENTS\fR \- Process all kinds of events: equivalent to OR-ing together all of the above flags or specifying none of them. .TP 27 \fBTCL_DONT_WAIT\fR \- Don't sleep: process only events that are ready at the time of the call. .LP If any of the flags \fBTCL_WINDOW_EVENTS\fR, \fBTCL_FILE_EVENTS\fR, \fBTCL_TIMER_EVENTS\fR, or \fBTCL_IDLE_EVENTS\fR is set, then the only events that will be considered are those for which flags are set. Setting none of these flags is equivalent to the value \fBTCL_ALL_EVENTS\fR, which causes all event types to be processed. If an application has defined additional event sources with \fBTcl_CreateEventSource\fR, then additional \fIflag\fR values may also be valid, depending on those event sources. .PP The \fBTCL_DONT_WAIT\fR flag causes \fBTcl_DoOneEvent\fR not to put the process to sleep: it will check for events but if none are found then it returns immediately with a return value of 0 to indicate that no work was done. \fBTcl_DoOneEvent\fR will also return 0 without doing anything if the only alternative is to block forever (this can happen, for example, if \fIflags\fR is \fBTCL_IDLE_EVENTS\fR and there are no \fBTcl_DoWhenIdle\fR callbacks pending, or if no event handlers or timer handlers exist). .PP \fBTcl_DoOneEvent\fR may be invoked recursively. For example, it is possible to invoke \fBTcl_DoOneEvent\fR recursively from a handler called by \fBTcl_DoOneEvent\fR. This sort of operation is useful in some modal situations, such as when a notification dialog has been popped up and an application wishes to wait for the user to click a button in the dialog before doing anything else. .SH KEYWORDS callback, event, handler, idle, timer tcl8.4.20/doc/memory.n0000644003604700454610000001027711737050674013162 0ustar dgp771div'\" '\" Copyright (c) 1992-1999 by Karl Lehenbauer and Mark Diekhans '\" Copyright (c) 2000 by Scriptics Corporation. '\" All rights reserved. '\" .so man.macros .TH memory n 8.1 Tcl "Tcl Built-In Commands" .BS .SH NAME memory \- Control Tcl memory debugging capabilities. .SH SYNOPSIS \fBmemory \fIoption \fR?\fIarg arg ...\fR? .BE .SH DESCRIPTION .PP The \fBmemory\fR command gives the Tcl developer control of Tcl's memory debugging capabilities. The memory command has several suboptions, which are described below. It is only available when Tcl has been compiled with memory debugging enabled (when \fBTCL_MEM_DEBUG\fR is defined at compile time), and after \fBTcl_InitMemory\fR has been called. .TP \fBmemory active\fR \fIfile\fR Write a list of all currently allocated memory to the specified \fIfile\fR. .TP \fBmemory break_on_malloc\fR \fIcount\fR After the \fIcount\fR allocations have been performed, \fBckalloc\fR outputs a message to this effect and that it is now attempting to enter the C debugger. Tcl will then issue a \fISIGINT\fR signal against itself. If you are running Tcl under a C debugger, it should then enter the debugger command mode. .TP \fBmemory info\fR Returns a report containing the total allocations and frees since Tcl began, the current packets allocated (the current number of calls to \fBckalloc\fR not met by a corresponding call to \fBckfree\fR), the current bytes allocated, and the maximum number of packets and bytes allocated. .TP \fB memory init [on|off]\fR Turn on or off the pre-initialization of all allocated memory with bogus bytes. Useful for detecting the use of uninitialized values. .TP \fBmemory onexit\fR \fIfile\fR Causes a list of all allocated memory to be written to the specified \fIfile\fR during the finalization of Tcl's memory subsystem. Useful for checking that memory is properly cleaned up during process exit. .TP \fBmemory tag\fR \fIstring\fR Each packet of memory allocated by \fBckalloc\fR can have associated with it a string-valued tag. In the lists of allocated memory generated by \fBmemory active\fR and \fBmemory onexit\fR, the tag for each packet is printed along with other information about the packet. The \fBmemory tag\fR command sets the tag value for subsequent calls to \fBckalloc\fR to be \fIstring\fR. .TP \fBmemory trace [on|off]\fR .br Turns memory tracing on or off. When memory tracing is on, every call to \fBckalloc\fR causes a line of trace information to be written to \fIstderr\fR, consisting of the word \fIckalloc\fR, followed by the address returned, the amount of memory allocated, and the C filename and line number of the code performing the allocation. For example: .RS .CS ckalloc 40e478 98 tclProc.c 1406 .CE Calls to \fBckfree\fR are traced in the same manner. .RE .TP \fBmemory trace_on_at_malloc\fR \fIcount\fR Enable memory tracing after \fIcount\fR \fBckalloc\fR's have been performed. For example, if you enter \fBmemory trace_on_at_malloc 100\fR, after the 100th call to \fBckalloc\fR, memory trace information will begin being displayed for all allocations and frees. Since there can be a lot of memory activity before a problem occurs, judicious use of this option can reduce the slowdown caused by tracing (and the amount of trace information produced), if you can identify a number of allocations that occur before the problem sets in. The current number of memory allocations that have occurred since Tcl started is printed on a guard zone failure. .TP \fBmemory validate [on|off]\fR Turns memory validation on or off. When memory validation is enabled, on every call to \fBckalloc\fR or \fBckfree\fR, the guard zones are checked for every piece of memory currently in existence that was allocated by \fBckalloc\fR. This has a large performance impact and should only be used when overwrite problems are strongly suspected. The advantage of enabling memory validation is that a guard zone overwrite can be detected on the first call to \fBckalloc\fR or \fBckfree\fR after the overwrite occurred, rather than when the specific memory with the overwritten guard zone(s) is freed, which may occur long after the overwrite occurred. .SH "SEE ALSO" ckalloc, ckfree, Tcl_ValidateAllMemory, Tcl_DumpActiveMemory, TCL_MEM_DEBUG .SH KEYWORDS memory, debug tcl8.4.20/doc/DetachPids.30000644003604700454610000000576611737050674013576 0ustar dgp771div'\" '\" Copyright (c) 1989-1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_DetachPids 3 "" Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_DetachPids, Tcl_ReapDetachedProcs, Tcl_WaitPid \- manage child processes in background .SH SYNOPSIS .nf \fB#include \fR .sp \fBTcl_DetachPids\fR(\fInumPids, pidPtr\fR) .sp \fBTcl_ReapDetachedProcs\fR() .sp Tcl_Pid \fBTcl_WaitPid\fR(\fIpid, statPtr, options\fR) .SH ARGUMENTS .AS int *statusPtr .AP int numPids in Number of process ids contained in the array pointed to by \fIpidPtr\fR. .AP int *pidPtr in Address of array containing \fInumPids\fR process ids. .AP Tcl_Pid pid in The id of the process (pipe) to wait for. .AP int* statPtr out The result of waiting on a process (pipe). Either 0 or ECHILD. .AP int options The options controlling the wait. WNOHANG specifies not to wait when checking the process. .BE .SH DESCRIPTION .PP \fBTcl_DetachPids\fR and \fBTcl_ReapDetachedProcs\fR provide a mechanism for managing subprocesses that are running in background. These procedures are needed because the parent of a process must eventually invoke the \fBwaitpid\fR kernel call (or one of a few other similar kernel calls) to wait for the child to exit. Until the parent waits for the child, the child's state cannot be completely reclaimed by the system. If a parent continually creates children and doesn't wait on them, the system's process table will eventually overflow, even if all the children have exited. .PP \fBTcl_DetachPids\fR may be called to ask Tcl to take responsibility for one or more processes whose process ids are contained in the \fIpidPtr\fR array passed as argument. The caller presumably has started these processes running in background and doesn't want to have to deal with them again. .PP \fBTcl_ReapDetachedProcs\fR invokes the \fBwaitpid\fR kernel call on each of the background processes so that its state can be cleaned up if it has exited. If the process hasn't exited yet, \fBTcl_ReapDetachedProcs\fR doesn't wait for it to exit; it will check again the next time it is invoked. Tcl automatically calls \fBTcl_ReapDetachedProcs\fR each time the \fBexec\fR command is executed, so in most cases it isn't necessary for any code outside of Tcl to invoke \fBTcl_ReapDetachedProcs\fR. However, if you call \fBTcl_DetachPids\fR in situations where the \fBexec\fR command may never get executed, you may wish to call \fBTcl_ReapDetachedProcs\fR from time to time so that background processes can be cleaned up. .PP \fBTcl_WaitPid\fR is a thin wrapper around the facilities provided by the operating system to wait on the end of a spawned process and to check a whether spawned process is still running. It is used by \fBTcl_ReapDetachedProcs\fR and the channel system to portably access the operating system. .SH KEYWORDS background, child, detach, process, wait tcl8.4.20/doc/Signal.30000644003604700454610000000173311737050674012771 0ustar dgp771div'\" '\" Copyright (c) 2001 ActiveState Tool Corp. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_SignalId 3 8.3 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_SignalId, Tcl_SignalMsg \- Convert signal codes .SH SYNOPSIS .nf \fB#include \fR .sp CONST char * \fBTcl_SignalId\fR(\fIsig\fR) .sp CONST char * \fBTcl_SignalMsg\fR(\fIsig\fR) .sp .SH ARGUMENTS .AP int sig in A POSIX signal number such as \fBSIGPIPE\fR. .BE .SH DESCRIPTION .PP \fBTcl_SignalId\fR and \fBTcl_SignalMsg\fR return a string representation of the provided signal number (\fIsig\fR). \fBTcl_SignalId\fR returns a machine-readable textual identifier such as "SIGPIPE". \fBTcl_SignalMsg\fR returns a human-readable string such as "bus error". The strings returned by these functions are statically allocated and the caller must not free or modify them. .SH KEYWORDS signals, signal numbers tcl8.4.20/doc/namespace.n0000644003604700454610000005534311737050674013611 0ustar dgp771div'\" '\" Copyright (c) 1993-1997 Bell Labs Innovations for Lucent Technologies '\" Copyright (c) 1997 Sun Microsystems, Inc. '\" Copyright (c) 2000 Scriptics Corporation. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH namespace n 8.0 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME namespace \- create and manipulate contexts for commands and variables .SH SYNOPSIS \fBnamespace \fR?\fIoption\fR? ?\fIarg ...\fR? .BE .SH DESCRIPTION .PP The \fBnamespace\fR command lets you create, access, and destroy separate contexts for commands and variables. See the section \fBWHAT IS A NAMESPACE?\fR below for a brief overview of namespaces. The legal values of \fIoption\fR are listed below. Note that you can abbreviate the \fIoption\fRs. .TP \fBnamespace children \fR?\fInamespace\fR? ?\fIpattern\fR? Returns a list of all child namespaces that belong to the namespace \fInamespace\fR. If \fInamespace\fR is not specified, then the children are returned for the current namespace. This command returns fully-qualified names, which start with a double colon (\fB::\fR). If the optional \fIpattern\fR is given, then this command returns only the names that match the glob-style pattern. The actual pattern used is determined as follows: a pattern that starts with double colon (\fB::\fR) is used directly, otherwise the namespace \fInamespace\fR (or the fully-qualified name of the current namespace) is prepended onto the pattern. .TP \fBnamespace code \fIscript\fR Captures the current namespace context for later execution of the script \fIscript\fR. It returns a new script in which \fIscript\fR has been wrapped in a \fBnamespace inscope\fR command. The new script has two important properties. First, it can be evaluated in any namespace and will cause \fIscript\fR to be evaluated in the current namespace (the one where the \fBnamespace code\fR command was invoked). Second, additional arguments can be appended to the resulting script and they will be passed to \fIscript\fR as additional arguments. For example, suppose the command \fBset script [namespace code {foo bar}]\fR is invoked in namespace \fB::a::b\fR. Then \fBeval "$script x y"\fR can be executed in any namespace (assuming the value of \fBscript\fR has been passed in properly) and will have the same effect as the command \fB::namespace eval ::a::b {foo bar x y}\fR. This command is needed because extensions like Tk normally execute callback scripts in the global namespace. A scoped command captures a command together with its namespace context in a way that allows it to be executed properly later. See the section \fBSCOPED SCRIPTS\fR for some examples of how this is used to create callback scripts. .TP \fBnamespace current\fR Returns the fully-qualified name for the current namespace. The actual name of the global namespace is ``'' (i.e., an empty string), but this command returns \fB::\fR for the global namespace as a convenience to programmers. .TP \fBnamespace delete \fR?\fInamespace namespace ...\fR? Each namespace \fInamespace\fR is deleted and all variables, procedures, and child namespaces contained in the namespace are deleted. If a procedure is currently executing inside the namespace, the namespace will be kept alive until the procedure returns; however, the namespace is marked to prevent other code from looking it up by name. If a namespace doesn't exist, this command returns an error. If no namespace names are given, this command does nothing. .TP \fBnamespace eval\fR \fInamespace arg\fR ?\fIarg ...\fR? Activates a namespace called \fInamespace\fR and evaluates some code in that context. If the namespace does not already exist, it is created. If more than one \fIarg\fR argument is specified, the arguments are concatenated together with a space between each one in the same fashion as the \fBeval\fR command, and the result is evaluated. .br .sp If \fInamespace\fR has leading namespace qualifiers and any leading namespaces do not exist, they are automatically created. .TP \fBnamespace exists\fR \fInamespace\fR Returns \fB1\fR if \fInamespace\fR is a valid namespace in the current context, returns \fB0\fR otherwise. .TP \fBnamespace export \fR?\-\fBclear\fR? ?\fIpattern pattern ...\fR? Specifies which commands are exported from a namespace. The exported commands are those that can be later imported into another namespace using a \fBnamespace import\fR command. Both commands defined in a namespace and commands the namespace has previously imported can be exported by a namespace. The commands do not have to be defined at the time the \fBnamespace export\fR command is executed. Each \fIpattern\fR may contain glob-style special characters, but it may not include any namespace qualifiers. That is, the pattern can only specify commands in the current (exporting) namespace. Each \fIpattern\fR is appended onto the namespace's list of export patterns. If the \-\fBclear\fR flag is given, the namespace's export pattern list is reset to empty before any \fIpattern\fR arguments are appended. If no \fIpattern\fRs are given and the \-\fBclear\fR flag isn't given, this command returns the namespace's current export list. .TP \fBnamespace forget \fR?\fIpattern pattern ...\fR? Removes previously imported commands from a namespace. Each \fIpattern\fR is a simple or qualified name such as \fBx\fR, \fBfoo::x\fR or \fBa::b::p*\fR. Qualified names contain double colons (\fB::\fR) and qualify a name with the name of one or more namespaces. Each \fIqualified pattern\fR is qualified with the name of an exporting namespace and may have glob-style special characters in the command name at the end of the qualified name. Glob characters may not appear in a namespace name. For each \fIsimple pattern\fR this command deletes the matching commands of the current namespace that were imported from a different namespace. For \fIqualified patterns\fR, this command first finds the matching exported commands. It then checks whether any of those commands were previously imported by the current namespace. If so, this command deletes the corresponding imported commands. In effect, this un-does the action of a \fBnamespace import\fR command. .TP \fBnamespace import \fR?\fB\-force\fR? ?\fIpattern\fR \fIpattern ...\fR? Imports commands into a namespace. Each \fIpattern\fR is a qualified name like \fBfoo::x\fR or \fBa::p*\fR. That is, it includes the name of an exporting namespace and may have glob-style special characters in the command name at the end of the qualified name. Glob characters may not appear in a namespace name. All the commands that match a \fIpattern\fR string and which are currently exported from their namespace are added to the current namespace. This is done by creating a new command in the current namespace that points to the exported command in its original namespace; when the new imported command is called, it invokes the exported command. This command normally returns an error if an imported command conflicts with an existing command. However, if the \-\fBforce\fR option is given, imported commands will silently replace existing commands. The \fBnamespace import\fR command has snapshot semantics: that is, only requested commands that are currently defined in the exporting namespace are imported. In other words, you can import only the commands that are in a namespace at the time when the \fBnamespace import\fR command is executed. If another command is defined and exported in this namespace later on, it will not be imported. .TP \fBnamespace inscope\fR \fInamespace\fR \fIscript\fR ?\fIarg ...\fR? Executes a script in the context of the specified \fInamespace\fR. This command is not expected to be used directly by programmers; calls to it are generated implicitly when applications use \fBnamespace code\fR commands to create callback scripts that the applications then register with, e.g., Tk widgets. The \fBnamespace inscope\fR command is much like the \fBnamespace eval\fR command except that the \fInamespace\fR must already exist, and \fBnamespace inscope\fR appends additional \fIarg\fRs as proper list elements. .br \fBnamespace inscope ::foo $script $x $y $z\fR is equivalent to \fBnamespace eval ::foo [concat $script [list $x $y $z]]\fR thus additional arguments will not undergo a second round of substitution, as is the case with \fBnamespace eval\fR. .TP \fBnamespace origin \fIcommand\fR Returns the fully-qualified name of the original command to which the imported command \fIcommand\fR refers. When a command is imported into a namespace, a new command is created in that namespace that points to the actual command in the exporting namespace. If a command is imported into a sequence of namespaces \fIa, b,...,n\fR where each successive namespace just imports the command from the previous namespace, this command returns the fully-qualified name of the original command in the first namespace, \fIa\fR. If \fIcommand\fR does not refer to an imported command, the command's own fully-qualified name is returned. .TP \fBnamespace parent\fR ?\fInamespace\fR? Returns the fully-qualified name of the parent namespace for namespace \fInamespace\fR. If \fInamespace\fR is not specified, the fully-qualified name of the current namespace's parent is returned. .TP \fBnamespace qualifiers\fR \fIstring\fR Returns any leading namespace qualifiers for \fIstring\fR. Qualifiers are namespace names separated by double colons (\fB::\fR). For the \fIstring\fR \fB::foo::bar::x\fR, this command returns \fB::foo::bar\fR, and for \fB::\fR it returns an empty string. This command is the complement of the \fBnamespace tail\fR command. Note that it does not check whether the namespace names are, in fact, the names of currently defined namespaces. .TP \fBnamespace tail\fR \fIstring\fR Returns the simple name at the end of a qualified string. Qualifiers are namespace names separated by double colons (\fB::\fR). For the \fIstring\fR \fB::foo::bar::x\fR, this command returns \fBx\fR, and for \fB::\fR it returns an empty string. This command is the complement of the \fBnamespace qualifiers\fR command. It does not check whether the namespace names are, in fact, the names of currently defined namespaces. .TP \fBnamespace which\fR ?\-\fBcommand\fR? ?\-\fBvariable\fR? \fIname\fR Looks up \fIname\fR as either a command or variable and returns its fully-qualified name. For example, if \fIname\fR does not exist in the current namespace but does exist in the global namespace, this command returns a fully-qualified name in the global namespace. If the command or variable does not exist, this command returns an empty string. If the variable has been created but not defined, such as with the \fBvariable\fR command or through a \fBtrace\fR on the variable, this command will return the fully-qualified name of the variable. If no flag is given, \fIname\fR is treated as a command name. See the section \fBNAME RESOLUTION\fR below for an explanation of the rules regarding name resolution. .SH "WHAT IS A NAMESPACE?" .PP A namespace is a collection of commands and variables. It encapsulates the commands and variables to ensure that they won't interfere with the commands and variables of other namespaces. Tcl has always had one such collection, which we refer to as the \fIglobal namespace\fR. The global namespace holds all global variables and commands. The \fBnamespace eval\fR command lets you create new namespaces. For example, .CS \fBnamespace eval\fR Counter { \fBnamespace export\fR bump variable num 0 proc bump {} { variable num incr num } } .CE creates a new namespace containing the variable \fBnum\fR and the procedure \fBbump\fR. The commands and variables in this namespace are separate from other commands and variables in the same program. If there is a command named \fBbump\fR in the global namespace, for example, it will be different from the command \fBbump\fR in the \fBCounter\fR namespace. .PP Namespace variables resemble global variables in Tcl. They exist outside of the procedures in a namespace but can be accessed in a procedure via the \fBvariable\fR command, as shown in the example above. .PP Namespaces are dynamic. You can add and delete commands and variables at any time, so you can build up the contents of a namespace over time using a series of \fBnamespace eval\fR commands. For example, the following series of commands has the same effect as the namespace definition shown above: .CS \fBnamespace eval\fR Counter { variable num 0 proc bump {} { variable num return [incr num] } } \fBnamespace eval\fR Counter { proc test {args} { return $args } } \fBnamespace eval\fR Counter { rename test "" } .CE Note that the \fBtest\fR procedure is added to the \fBCounter\fR namespace, and later removed via the \fBrename\fR command. .PP Namespaces can have other namespaces within them, so they nest hierarchically. A nested namespace is encapsulated inside its parent namespace and can not interfere with other namespaces. .SH "QUALIFIED NAMES" .PP Each namespace has a textual name such as \fBhistory\fR or \fB::safe::interp\fR. Since namespaces may nest, qualified names are used to refer to commands, variables, and child namespaces contained inside namespaces. Qualified names are similar to the hierarchical path names for Unix files or Tk widgets, except that \fB::\fR is used as the separator instead of \fB/\fR or \fB.\fR. The topmost or global namespace has the name ``'' (i.e., an empty string), although \fB::\fR is a synonym. As an example, the name \fB::safe::interp::create\fR refers to the command \fBcreate\fR in the namespace \fBinterp\fR that is a child of namespace \fB::safe\fR, which in turn is a child of the global namespace, \fB::\fR. .PP If you want to access commands and variables from another namespace, you must use some extra syntax. Names must be qualified by the namespace that contains them. From the global namespace, we might access the \fBCounter\fR procedures like this: .CS Counter::bump 5 Counter::Reset .CE We could access the current count like this: .CS puts "count = $Counter::num" .CE When one namespace contains another, you may need more than one qualifier to reach its elements. If we had a namespace \fBFoo\fR that contained the namespace \fBCounter\fR, you could invoke its \fBbump\fR procedure from the global namespace like this: .CS Foo::Counter::bump 3 .CE .PP You can also use qualified names when you create and rename commands. For example, you could add a procedure to the \fBFoo\fR namespace like this: .CS proc Foo::Test {args} {return $args} .CE And you could move the same procedure to another namespace like this: .CS rename Foo::Test Bar::Test .CE .PP There are a few remaining points about qualified names that we should cover. Namespaces have nonempty names except for the global namespace. \fB::\fR is disallowed in simple command, variable, and namespace names except as a namespace separator. Extra colons in any separator part of a qualified name are ignored; i.e. two or more colons are treated as a namespace separator. A trailing \fB::\fR in a qualified variable or command name refers to the variable or command named {}. However, a trailing \fB::\fR in a qualified namespace name is ignored. .SH "NAME RESOLUTION" .PP In general, all Tcl commands that take variable and command names support qualified names. This means you can give qualified names to such commands as \fBset\fR, \fBproc\fR, \fBrename\fR, and \fBinterp alias\fR. If you provide a fully-qualified name that starts with a \fB::\fR, there is no question about what command, variable, or namespace you mean. However, if the name does not start with a \fB::\fR (i.e., is \fIrelative\fR), Tcl follows a fixed rule for looking it up: Command and variable names are always resolved by looking first in the current namespace, and then in the global namespace. Namespace names, on the other hand, are always resolved by looking in only the current namespace. .PP In the following example, .CS set traceLevel 0 \fBnamespace eval\fR Debug { printTrace $traceLevel } .CE Tcl looks for \fBtraceLevel\fR in the namespace \fBDebug\fR and then in the global namespace. It looks up the command \fBprintTrace\fR in the same way. If a variable or command name is not found in either context, the name is undefined. To make this point absolutely clear, consider the following example: .CS set traceLevel 0 \fBnamespace eval\fR Foo { variable traceLevel 3 \fBnamespace eval\fR Debug { printTrace $traceLevel } } .CE Here Tcl looks for \fBtraceLevel\fR first in the namespace \fBFoo::Debug\fR. Since it is not found there, Tcl then looks for it in the global namespace. The variable \fBFoo::traceLevel\fR is completely ignored during the name resolution process. .PP You can use the \fBnamespace which\fR command to clear up any question about name resolution. For example, the command: .CS \fBnamespace eval\fR Foo::Debug {\fBnamespace which\fR \-variable traceLevel} .CE returns \fB::traceLevel\fR. On the other hand, the command, .CS \fBnamespace eval\fR Foo {\fBnamespace which\fR \-variable traceLevel} .CE returns \fB::Foo::traceLevel\fR. .PP As mentioned above, namespace names are looked up differently than the names of variables and commands. Namespace names are always resolved in the current namespace. This means, for example, that a \fBnamespace eval\fR command that creates a new namespace always creates a child of the current namespace unless the new namespace name begins with \fB::\fR. .PP Tcl has no access control to limit what variables, commands, or namespaces you can reference. If you provide a qualified name that resolves to an element by the name resolution rule above, you can access the element. .PP You can access a namespace variable from a procedure in the same namespace by using the \fBvariable\fR command. Much like the \fBglobal\fR command, this creates a local link to the namespace variable. If necessary, it also creates the variable in the current namespace and initializes it. Note that the \fBglobal\fR command only creates links to variables in the global namespace. It is not necessary to use a \fBvariable\fR command if you always refer to the namespace variable using an appropriate qualified name. .SH "IMPORTING COMMANDS" .PP Namespaces are often used to represent libraries. Some library commands are used so frequently that it is a nuisance to type their qualified names. For example, suppose that all of the commands in a package like BLT are contained in a namespace called \fBBlt\fR. Then you might access these commands like this: .CS Blt::graph .g \-background red Blt::table . .g 0,0 .CE If you use the \fBgraph\fR and \fBtable\fR commands frequently, you may want to access them without the \fBBlt::\fR prefix. You can do this by importing the commands into the current namespace, like this: .CS \fBnamespace import\fR Blt::* .CE This adds all exported commands from the \fBBlt\fR namespace into the current namespace context, so you can write code like this: .CS graph .g \-background red table . .g 0,0 .CE The \fBnamespace import\fR command only imports commands from a namespace that that namespace exported with a \fBnamespace export\fR command. .PP Importing \fIevery\fR command from a namespace is generally a bad idea since you don't know what you will get. It is better to import just the specific commands you need. For example, the command .CS \fBnamespace import\fR Blt::graph Blt::table .CE imports only the \fBgraph\fR and \fBtable\fR commands into the current context. .PP If you try to import a command that already exists, you will get an error. This prevents you from importing the same command from two different packages. But from time to time (perhaps when debugging), you may want to get around this restriction. You may want to reissue the \fBnamespace import\fR command to pick up new commands that have appeared in a namespace. In that case, you can use the \fB\-force\fR option, and existing commands will be silently overwritten: .CS \fBnamespace import\fR \-force Blt::graph Blt::table .CE If for some reason, you want to stop using the imported commands, you can remove them with a \fBnamespace forget\fR command, like this: .CS \fBnamespace forget\fR Blt::* .CE This searches the current namespace for any commands imported from \fBBlt\fR. If it finds any, it removes them. Otherwise, it does nothing. After this, the \fBBlt\fR commands must be accessed with the \fBBlt::\fR prefix. .PP When you delete a command from the exporting namespace like this: .CS rename Blt::graph "" .CE the command is automatically removed from all namespaces that import it. .SH "EXPORTING COMMANDS" You can export commands from a namespace like this: .CS \fBnamespace eval\fR Counter { \fBnamespace export\fR bump reset variable Num 0 variable Max 100 proc bump {{by 1}} { variable Num incr Num $by Check return $Num } proc reset {} { variable Num set Num 0 } proc Check {} { variable Num variable Max if {$Num > $Max} { error "too high!" } } } .CE The procedures \fBbump\fR and \fBreset\fR are exported, so they are included when you import from the \fBCounter\fR namespace, like this: .CS \fBnamespace import\fR Counter::* .CE However, the \fBCheck\fR procedure is not exported, so it is ignored by the import operation. .PP The \fBnamespace import\fR command only imports commands that were declared as exported by their namespace. The \fBnamespace export\fR command specifies what commands may be imported by other namespaces. If a \fBnamespace import\fR command specifies a command that is not exported, the command is not imported. .SH "SCOPED SCRIPTS" The \fBnamespace code\fR command is the means by which a script may be packaged for evaluation in a namespace other than the one in which it was created. It is used most often to create event handlers, Tk bindings, and traces for evaluation in the global context. For instance, the following code indicates how to direct a variable trace callback into the current namespace: .CS \fBnamespace eval\fR a { variable b proc theTraceCallback { n1 n2 op } { upvar 1 $n1 var puts "the value of $n1 has changed to $var" return } trace variable b w [\fBnamespace code\fR theTraceCallback] } set a::b c .CE When executed, it prints the message: .CS the value of a::b has changed to c .CE .SH EXAMPLES Create a namespace containing a variable and an exported command: .CS \fBnamespace eval\fR foo { variable bar 0 proc grill {} { variable bar puts "called [incr bar] times" } \fBnamespace export\fR grill } .CE .PP Call the command defined in the previous example in various ways. .CS # Direct call foo::grill # Import into current namespace, then call local alias namespace import foo::grill grill .CE .PP Look up where the command imported in the previous example came from: .CS puts "grill came from [\fBnamespace origin\fR grill]" .CE .SH "SEE ALSO" variable(n) .SH KEYWORDS exported, internal, variable tcl8.4.20/doc/tclvars.n0000644003604700454610000003704712052456743013332 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH tclvars n 8.0 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME tclvars \- Variables used by Tcl .BE .SH DESCRIPTION .PP The following global variables are created and managed automatically by the Tcl library. Except where noted below, these variables should normally be treated as read-only by application-specific code and by users. .TP \fBenv\fR This variable is maintained by Tcl as an array whose elements are the environment variables for the process. Reading an element will return the value of the corresponding environment variable. Setting an element of the array will modify the corresponding environment variable or create a new one if it doesn't already exist. Unsetting an element of \fBenv\fR will remove the corresponding environment variable. Changes to the \fBenv\fR array will affect the environment passed to children by commands like \fBexec\fR. If the entire \fBenv\fR array is unset then Tcl will stop monitoring \fBenv\fR accesses and will not update environment variables. .RS .VS 8.0 Under Windows, the environment variables PATH and COMSPEC in any capitalization are converted automatically to upper case. For instance, the PATH variable could be exported by the operating system as ``path'', ``Path'', ``PaTh'', etc., causing otherwise simple Tcl code to have to support many special cases. All other environment variables inherited by Tcl are left unmodified. Setting an env array variable to blank is the same as unsetting it as this is the behavior of the underlying Windows OS. It should be noted that relying on an existing and empty environment variable won't work on windows and is discouraged for cross-platform usage. .RE .TP \fBerrorCode\fR After an error has occurred, this variable will be set to hold a list value representing additional information about the error in a form that is easy to process with programs. The first element of the list identifies a general class of errors, and determines the format of the rest of the list. The following formats for \fBerrorCode\fR are used by the Tcl core; individual applications may define additional formats. .RS .TP \fBARITH\fI code msg\fR This format is used when an arithmetic error occurs (e.g. an attempt to divide by zero in the \fBexpr\fR command). \fICode\fR identifies the precise error and \fImsg\fR provides a human-readable description of the error. \fICode\fR will be either DIVZERO (for an attempt to divide by zero), DOMAIN (if an argument is outside the domain of a function, such as acos(\-3)), IOVERFLOW (for integer overflow), OVERFLOW (for a floating-point overflow), or UNKNOWN (if the cause of the error cannot be determined). .TP \fBCHILDKILLED\fI pid sigName msg\fR This format is used when a child process has been killed because of a signal. The second element of \fBerrorCode\fR will be the process's identifier (in decimal). The third element will be the symbolic name of the signal that caused the process to terminate; it will be one of the names from the include file signal.h, such as \fBSIGPIPE\fR. The fourth element will be a short human-readable message describing the signal, such as ``write on pipe with no readers'' for \fBSIGPIPE\fR. .TP \fBCHILDSTATUS\fI pid code\fR This format is used when a child process has exited with a non-zero exit status. The second element of \fBerrorCode\fR will be the process's identifier (in decimal) and the third element will be the exit code returned by the process (also in decimal). .TP \fBCHILDSUSP\fI pid sigName msg\fR This format is used when a child process has been suspended because of a signal. The second element of \fBerrorCode\fR will be the process's identifier, in decimal. The third element will be the symbolic name of the signal that caused the process to suspend; this will be one of the names from the include file signal.h, such as \fBSIGTTIN\fR. The fourth element will be a short human-readable message describing the signal, such as ``background tty read'' for \fBSIGTTIN\fR. .TP \fBNONE\fR This format is used for errors where no additional information is available for an error besides the message returned with the error. In these cases \fBerrorCode\fR will consist of a list containing a single element whose contents are \fBNONE\fR. .TP \fBPOSIX \fIerrName msg\fR If the first element of \fBerrorCode\fR is \fBPOSIX\fR, then the error occurred during a POSIX kernel call. The second element of the list will contain the symbolic name of the error that occurred, such as \fBENOENT\fR; this will be one of the values defined in the include file errno.h. The third element of the list will be a human-readable message corresponding to \fIerrName\fR, such as ``no such file or directory'' for the \fBENOENT\fR case. .PP To set \fBerrorCode\fR, applications should use library procedures such as \fBTcl_SetErrorCode\fR and \fBTcl_PosixError\fR, or they may invoke the \fBerror\fR command. If one of these methods hasn't been used, then the Tcl interpreter will reset the variable to \fBNONE\fR after the next error. .RE .TP \fBerrorInfo\fR After an error has occurred, this string will contain one or more lines identifying the Tcl commands and procedures that were being executed when the most recent error occurred. Its contents take the form of a stack trace showing the various nested Tcl commands that had been invoked at the time of the error. .TP \fBtcl_library\fR This variable holds the name of a directory containing the system library of Tcl scripts, such as those used for auto-loading. The value of this variable is returned by the \fBinfo library\fR command. See the \fBlibrary\fR manual entry for details of the facilities provided by the Tcl script library. Normally each application or package will have its own application-specific script library in addition to the Tcl script library; each application should set a global variable with a name like \fB$\fIapp\fB_library\fR (where \fIapp\fR is the application's name) to hold the network file name for that application's library directory. The initial value of \fBtcl_library\fR is set when an interpreter is created by searching several different directories until one is found that contains an appropriate Tcl startup script. If the \fBTCL_LIBRARY\fR environment variable exists, then the directory it names is checked first. If \fBTCL_LIBRARY\fR isn't set or doesn't refer to an appropriate directory, then Tcl checks several other directories based on a compiled-in default location, the location of the binary containing the application, and the current working directory. .TP \fBtcl_patchLevel\fR When an interpreter is created Tcl initializes this variable to hold a string giving the current patch level for Tcl, such as \fB7.3p2\fR for Tcl 7.3 with the first two official patches, or \fB7.4b4\fR for the fourth beta release of Tcl 7.4. The value of this variable is returned by the \fBinfo patchlevel\fR command. .VS 8.0 br .TP \fBtcl_pkgPath\fR This variable holds a list of directories indicating where packages are normally installed. It is not used on Windows. It typically contains either one or two entries; if it contains two entries, the first is normally a directory for platform-dependent packages (e.g., shared library binaries) and the second is normally a directory for platform-independent packages (e.g., script files). Typically a package is installed as a subdirectory of one of the entries in \fB$tcl_pkgPath\fR. The directories in \fB$tcl_pkgPath\fR are included by default in the \fBauto_path\fR variable, so they and their immediate subdirectories are automatically searched for packages during \fBpackage require\fR commands. Note: \fBtcl_pkgPath\fR it not intended to be modified by the application. Its value is added to \fBauto_path\fR at startup; changes to \fBtcl_pkgPath\fR are not reflected in \fBauto_path\fR. If you want Tcl to search additional directories for packages you should add the names of those directories to \fBauto_path\fR, not \fBtcl_pkgPath\fR. .VE .TP \fBtcl_platform\fR This is an associative array whose elements contain information about the platform on which the application is running, such as the name of the operating system, its current release number, and the machine's instruction set. The elements listed below will always be defined, but they may have empty strings as values if Tcl couldn't retrieve any relevant information. In addition, extensions and applications may add additional values to the array. The predefined elements are: .RS .VS .TP \fBbyteOrder\fR The native byte order of this machine: either \fBlittleEndian\fR or \fBbigEndian\fR. .VE .TP \fBdebug\fR If this variable exists, then the interpreter was compiled with and linked to a debug-enabled C run-time. This variable will only exist on Windows, so extension writers can specify which package to load depending on the C run-time library that is in use. This is not an indication that this core contains symbols. .TP \fBmachine\fR The instruction set executed by this machine, such as \fBintel\fR, \fBPPC\fR, \fB68k\fR, or \fBsun4m\fR. On UNIX machines, this is the value returned by \fBuname -m\fR. .TP \fBos\fR The name of the operating system running on this machine, such as \fBWindows 95\fR, \fBWindows NT\fR, \fBMacOS\fR, or \fBSunOS\fR. On UNIX machines, this is the value returned by \fBuname -s\fR. On Windows 95 and Windows 98, the value returned will be \fBWindows 95\fR to provide better backwards compatibility to Windows 95; to distinguish between the two, check the \fBosVersion\fR. .TP \fBosVersion\fR The version number for the operating system running on this machine. On UNIX machines, this is the value returned by \fBuname -r\fR. On Windows 95, the version will be 4.0; on Windows 98, the version will be 4.10. .TP \fBplatform\fR Either \fBwindows\fR or \fBunix\fR. This identifies the general operating environment of the machine. .TP \fBthreaded\fR If this variable exists, then the interpreter was compiled with threads enabled. .TP \fBuser\fR This identifies the current user based on the login information available on the platform. This comes from the USER or LOGNAME environment variable on Unix, and the value from GetUserName on Windows. .TP \fBwordSize\fR .VS 8.4 This gives the size of the native-machine word in bytes (strictly, it is same as the result of evaluating \fIsizeof(long)\fR in C.) .VE 8.4 .RE .TP \fBtcl_precision\fR .VS This variable controls the number of digits to generate when converting floating-point values to strings. It defaults to 12. 17 digits is ``perfect'' for IEEE floating-point in that it allows double-precision values to be converted to strings and back to binary with no loss of information. However, using 17 digits prevents any rounding, which produces longer, less intuitive results. For example, \fBexpr 1.4\fR returns 1.3999999999999999 with \fBtcl_precision\fR set to 17, vs. 1.4 if \fBtcl_precision\fR is 12. .RS All interpreters in a process share a single \fBtcl_precision\fR value: changing it in one interpreter will affect all other interpreters as well. However, safe interpreters are not allowed to modify the variable. .RE .VE .TP \fBtcl_rcFileName\fR This variable is used during initialization to indicate the name of a user-specific startup file. If it is set by application-specific initialization, then the Tcl startup code will check for the existence of this file and \fBsource\fR it if it exists. For example, for \fBwish\fR the variable is set to \fB~/.wishrc\fR for Unix and \fB~/wishrc.tcl\fR for Windows. .TP \fBtcl_traceCompile\fR The value of this variable can be set to control how much tracing information is displayed during bytecode compilation. By default, tcl_traceCompile is zero and no information is displayed. Setting tcl_traceCompile to 1 generates a one-line summary in stdout whenever a procedure or top-level command is compiled. Setting it to 2 generates a detailed listing in stdout of the bytecode instructions emitted during every compilation. This variable is useful in tracking down suspected problems with the Tcl compiler. It is also occasionally useful when converting existing code to use Tcl8.0. .PP This variable and functionality only exist if \fBTCL_COMPILE_DEBUG\fR was defined during Tcl's compilation. .TP \fBtcl_traceExec\fR The value of this variable can be set to control how much tracing information is displayed during bytecode execution. By default, tcl_traceExec is zero and no information is displayed. Setting tcl_traceExec to 1 generates a one-line trace in stdout on each call to a Tcl procedure. Setting it to 2 generates a line of output whenever any Tcl command is invoked that contains the name of the command and its arguments. Setting it to 3 produces a detailed trace showing the result of executing each bytecode instruction. Note that when tcl_traceExec is 2 or 3, commands such as \fBset\fR and \fBincr\fR that have been entirely replaced by a sequence of bytecode instructions are not shown. Setting this variable is useful in tracking down suspected problems with the bytecode compiler and interpreter. It is also occasionally useful when converting code to use Tcl8.0. .PP This variable and functionality only exist if \fBTCL_COMPILE_DEBUG\fR was defined during Tcl's compilation. .TP \fBtcl_wordchars\fR The value of this variable is a regular expression that can be set to control what are considered ``word'' characters, for instances like selecting a word by double-clicking in text in Tk. It is platform dependent. On Windows, it defaults to \fB\\S\fR, meaning anything but a Unicode space character. Otherwise it defaults to \fB\\w\fR, which is any Unicode word character (number, letter, or underscore). .TP \fBtcl_nonwordchars\fR The value of this variable is a regular expression that can be set to control what are considered ``non-word'' characters, for instances like selecting a word by double-clicking in text in Tk. It is platform dependent. On Windows, it defaults to \fB\\s\fR, meaning any Unicode space character. Otherwise it defaults to \fB\\W\fR, which is anything but a Unicode word character (number, letter, or underscore). .TP \fBtcl_version\fR When an interpreter is created Tcl initializes this variable to hold the version number for this version of Tcl in the form \fIx.y\fR. Changes to \fIx\fR represent major changes with probable incompatibilities and changes to \fIy\fR represent small enhancements and bug fixes that retain backward compatibility. The value of this variable is returned by the \fBinfo tclversion\fR command. .SH "OTHER GLOBAL VARIABLES" The following variables are only guaranteed to exist in \fBtclsh\fR and \fBwish\fR executables; the Tcl library does not define them itself but many Tcl environments do. .TP 6 \fBargc\fR The number of arguments to \fBtclsh\fR or \fBwish\fR. .TP 6 \fBargv\fR Tcl list of arguments to \fBtclsh\fR or \fBwish\fR. .TP 6 \fBargv0\fR The script that \fBtclsh\fR or \fBwish\fR started executing (if it was specified) or otherwise the name by which \fBtclsh\fR or \fBwish\fR was invoked. .TP 6 \fBtcl_interactive\fR Contains 1 if \fBtclsh\fR or \fBwish\fR is running interactively (no script was specified and standard input is a terminal-like device), 0 otherwise. .PP The \fBwish\fR executably additionally specifies the following global variable: .TP 6 \fBgeometry\fR If set, contains the user-supplied geometry specification to use for the main Tk window. .SH "SEE ALSO" eval(n), tclsh(1), wish(1) .SH KEYWORDS arithmetic, bytecode, compiler, error, environment, POSIX, precision, subprocess, variables tcl8.4.20/doc/lsearch.n0000644003604700454610000001166211737050674013272 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" Copyright (c) 2001 Kevin B. Kenny. All rights reserved. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH lsearch n 8.4 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME lsearch \- See if a list contains a particular element .SH SYNOPSIS \fBlsearch \fR?\fIoptions\fR? \fIlist pattern\fR .BE .SH DESCRIPTION .PP This command searches the elements of \fIlist\fR to see if one of them matches \fIpattern\fR. If so, the command returns the index of the first matching element .VS 8.4 (unless the options \fB\-all\fR or \fB\-inline\fR are specified.) .VE 8.4 If not, the command returns \fB\-1\fR. The \fIoption\fR arguments indicates how the elements of the list are to be matched against \fIpattern\fR and it must have one of the following values: .TP \fB\-all\fR .VS 8.4 Changes the result to be the list of all matching indices (or all matching values if \fB\-inline\fR is specified as well.) .VE 8.4 .TP \fB\-ascii\fR The list elements are to be examined as Unicode strings (the name is for backward-compatability reasons.) This option is only meaningful when used with \fB\-exact\fR or \fB\-sorted\fR. .TP \fB\-decreasing\fR The list elements are sorted in decreasing order. This option is only meaningful when used with \fB\-sorted\fR. .TP \fB\-dictionary\fR The list elements are to be compared using dictionary-style comparisons (see \fBlsort\fR for a fuller description). This option is only meaningful when used with \fB\-exact\fR or \fB\-sorted\fR, and it is only distinguishable from the \fB\-ascii\fR option when the \fB\-sorted\fR option is given, because values are only dictionary-equal when exactly equal. .TP \fB\-exact\fR The list element must contain exactly the same string as \fIpattern\fR. .TP \fB\-glob\fR \fIPattern\fR is a glob-style pattern which is matched against each list element using the same rules as the \fBstring match\fR command. .TP \fB\-increasing\fR The list elements are sorted in increasing order. This option is only meaningful when used with \fB\-sorted\fR. .TP \fB\-inline\fR .VS 8.4 The matching value is returned instead of its index (or an empty string if no value matches.) If \fB\-all\fR is also specified, then the result of the command is the list of all values that matched. .VE 8.4 .TP \fB\-integer\fR The list elements are to be compared as integers. This option is only meaningful when used with \fB\-exact\fR or \fB\-sorted\fR. .TP \fB\-not\fR .VS 8.4 This negates the sense of the match, returning the index of the first non-matching value in the list. .VE 8.4 .TP \fB\-real\fR The list elements are to be compared as floating-point values. This option is only meaningful when used with \fB\-exact\fR or \fB\-sorted\fR. .TP \fB\-regexp\fR \fIPattern\fR is treated as a regular expression and matched against each list element using the rules described in the \fBre_syntax\fR reference page. .TP \fB\-sorted\fR The list elements are in sorted order. If this option is specified, \fBlsearch\fR will use a more efficient searching algorithm to search \fIlist\fR. If no other options are specified, \fIlist\fR is assumed to be sorted in increasing order, and to contain ASCII strings. This option is mutually exclusive with \fB\-glob\fR and \fB\-regexp\fR, and is treated exactly like \fB-exact\fR when either \fB\-all\fR, or \fB\-not\fR is specified. .TP \fB\-start\fR \fIindex\fR .VS 8.4 The list is searched starting at position \fIindex\fR. If \fIindex\fR has the value \fBend\fR, it refers to the last element in the list, and \fBend\-\fIinteger\fR refers to the last element in the list minus the specified integer offset. .VE 8.4 .PP If \fIoption\fR is omitted then it defaults to \fB\-glob\fR. If more than one of \fB\-exact\fR, \fB\-glob\fR, \fB\-regexp\fR, and \fB\-sorted\fR is specified, whichever option is specified last takes precedence. If more than one of \fB\-ascii\fR, \fB\-dictionary\fR, \fB\-integer\fR and \fB\-real\fR is specified, the option specified last takes precedence. If more than one of \fB\-increasing\fR and \fB\-decreasing\fR is specified, the option specified last takes precedence. .VS 8.4 .SH EXAMPLES .CS \fBlsearch\fR {a b c d e} c \fI=> 2\fR \fBlsearch\fR -all {a b c a b c} c \fI=> 2 5\fR \fBlsearch\fR -inline {a20 b35 c47} b* \fI=> b35\fR \fBlsearch\fR -inline -not {a20 b35 c47} b* \fI=> a20\fR \fBlsearch\fR -all -inline -not {a20 b35 c47} b* \fI=> a20 c47\fR \fBlsearch\fR -all -not {a20 b35 c47} b* \fI=> 0 2\fR \fBlsearch\fR -start 3 {a b c a b c} c \fI=> 5\fR .CE .VE 8.4 .SH "SEE ALSO" .VS 8.4 foreach(n), list(n), lappend(n), lindex(n), linsert(n), llength(n), lset(n), lsort(n), lrange(n), lreplace(n) .VE .SH KEYWORDS list, match, pattern, regular expression, search, string '\" Local Variables: '\" mode: nroff '\" End: tcl8.4.20/doc/StaticPkg.30000644003604700454610000000541211737050674013443 0ustar dgp771div'\" '\" Copyright (c) 1995-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_StaticPackage 3 7.5 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_StaticPackage \- make a statically linked package available via the \fBload\fR command .SH SYNOPSIS .nf \fB#include \fR .sp \fBTcl_StaticPackage\fR(\fIinterp, pkgName, initProc, safeInitProc\fR) .SH ARGUMENTS .AS Tcl_PackageInitProc *safeInitProc .AP Tcl_Interp *interp in If not NULL, points to an interpreter into which the package has already been loaded (i.e., the caller has already invoked the appropriate initialization procedure). NULL means the package hasn't yet been incorporated into any interpreter. .AP "CONST char" *pkgName in Name of the package; should be properly capitalized (first letter upper-case, all others lower-case). .AP Tcl_PackageInitProc *initProc in Procedure to invoke to incorporate this package into a trusted interpreter. .AP Tcl_PackageInitProc *safeInitProc in Procedure to call to incorporate this package into a safe interpreter (one that will execute untrusted scripts). NULL means the package can't be used in safe interpreters. .BE .SH DESCRIPTION .PP This procedure may be invoked to announce that a package has been linked statically with a Tcl application and, optionally, that it has already been loaded into an interpreter. Once \fBTcl_StaticPackage\fR has been invoked for a package, it may be loaded into interpreters using the \fBload\fR command. \fBTcl_StaticPackage\fR is normally invoked only by the \fBTcl_AppInit\fR procedure for the application, not by packages for themselves (\fBTcl_StaticPackage\fR should only be invoked for statically loaded packages, and code in the package itself should not need to know whether the package is dynamically or statically loaded). .PP When the \fBload\fR command is used later to load the package into an interpreter, one of \fIinitProc\fR and \fIsafeInitProc\fR will be invoked, depending on whether the target interpreter is safe or not. \fIinitProc\fR and \fIsafeInitProc\fR must both match the following prototype: .CS typedef int Tcl_PackageInitProc(Tcl_Interp *\fIinterp\fR); .CE The \fIinterp\fR argument identifies the interpreter in which the package is to be loaded. The initialization procedure must return \fBTCL_OK\fR or \fBTCL_ERROR\fR to indicate whether or not it completed successfully; in the event of an error it should set the interpreter's result to point to an error message. The result or error from the initialization procedure will be returned as the result of the \fBload\fR command that caused the initialization procedure to be invoked. .SH KEYWORDS initialization procedure, package, static linking tcl8.4.20/doc/ByteArrObj.30000644003604700454610000000767111737050674013566 0ustar dgp771div'\" '\" Copyright (c) 1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_ByteArrayObj 3 8.1 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_NewByteArrayObj, Tcl_SetByteArrayObj, Tcl_GetByteArrayFromObj, Tcl_SetByteArrayLength \- manipulate Tcl objects as a arrays of bytes .SH SYNOPSIS .nf \fB#include \fR .sp Tcl_Obj * \fBTcl_NewByteArrayObj\fR(\fIbytes, length\fR) .sp void \fBTcl_SetByteArrayObj\fR(\fIobjPtr, bytes, length\fR) .sp unsigned char * \fBTcl_GetByteArrayFromObj\fR(\fIobjPtr, lengthPtr\fR) .sp unsigned char * \fBTcl_SetByteArrayLength\fR(\fIobjPtr, length\fR) .SH ARGUMENTS .AS "unsigned char" *lengthPtr in/out .AP "CONST unsigned char" *bytes in The array of bytes used to initialize or set a byte-array object. .AP int length in The length of the array of bytes. It must be >= 0. .AP Tcl_Obj *objPtr in/out For \fBTcl_SetByteArrayObj\fR, this points to the object to be converted to byte-array type. For \fBTcl_GetByteArrayFromObj\fR and \fBTcl_SetByteArrayLength\fR, this points to the object from which to get the byte-array value; if \fIobjPtr\fR does not already point to a byte-array object, it will be converted to one. .AP int *lengthPtr out If non-NULL, filled with the length of the array of bytes in the object. .BE .SH DESCRIPTION .PP These procedures are used to create, modify, and read Tcl byte-array objects from C code. Byte-array objects are typically used to hold the results of binary IO operations or data structures created with the \fBbinary\fR command. In Tcl, an array of bytes is not equivalent to a string. Conceptually, a string is an array of Unicode characters, while a byte-array is an array of 8-bit quantities with no implicit meaning. Accesser functions are provided to get the string representation of a byte-array or to convert an arbitrary object to a byte-array. Obtaining the string representation of a byte-array object (by calling \fBTcl_GetStringFromObj\fR) produces a properly formed UTF-8 sequence with a one-to-one mapping between the bytes in the internal representation and the UTF-8 characters in the string representation. .PP \fBTcl_NewByteArrayObj\fR and \fBTcl_SetByteArrayObj\fR will create a new object of byte-array type or modify an existing object to have a byte-array type. Both of these procedures set the object's type to be byte-array and set the object's internal representation to a copy of the array of bytes given by \fIbytes\fR. \fBTcl_NewByteArrayObj\fR returns a pointer to a newly allocated object with a reference count of zero. \fBTcl_SetByteArrayObj\fR invalidates any old string representation and, if the object is not already a byte-array object, frees any old internal representation. .PP \fBTcl_GetByteArrayFromObj\fR converts a Tcl object to byte-array type and returns a pointer to the object's new internal representation as an array of bytes. The length of this array is stored in \fIlengthPtr\fR if \fIlengthPtr\fR is non-NULL. The storage for the array of bytes is owned by the object and should not be freed. The contents of the array may be modified by the caller only if the object is not shared and the caller invalidates the string representation. .PP \fBTcl_SetByteArrayLength\fR converts the Tcl object to byte-array type and changes the length of the object's internal representation as an array of bytes. If \fIlength\fR is greater than the space currently allocated for the array, the array is reallocated to the new length; the newly allocated bytes at the end of the array have arbitrary values. If \fIlength\fR is less than the space currently allocated for the array, the length of array is reduced to the new length. The return value is a pointer to the object's new array of bytes. .SH "SEE ALSO" Tcl_GetStringFromObj, Tcl_NewObj, Tcl_IncrRefCount, Tcl_DecrRefCount .SH KEYWORDS object, byte array, utf, unicode, internationalization tcl8.4.20/doc/upvar.n0000644003604700454610000001107411737050674013003 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH upvar n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME upvar \- Create link to variable in a different stack frame .SH SYNOPSIS \fBupvar \fR?\fIlevel\fR? \fIotherVar myVar \fR?\fIotherVar myVar \fR...? .BE .SH DESCRIPTION .PP This command arranges for one or more local variables in the current procedure to refer to variables in an enclosing procedure call or to global variables. \fILevel\fR may have any of the forms permitted for the \fBuplevel\fR command, and may be omitted if the first letter of the first \fIotherVar\fR isn't \fB#\fR or a digit (it defaults to \fB1\fR). For each \fIotherVar\fR argument, \fBupvar\fR makes the variable by that name in the procedure frame given by \fIlevel\fR (or at global level, if \fIlevel\fR is \fB#0\fR) accessible in the current procedure by the name given in the corresponding \fImyVar\fR argument. The variable named by \fIotherVar\fR need not exist at the time of the call; it will be created the first time \fImyVar\fR is referenced, just like an ordinary variable. There must not exist a variable by the name \fImyVar\fR at the time \fBupvar\fR is invoked. \fIMyVar\fR is always treated as the name of a variable, not an array element. Even if the name looks like an array element, such as \fBa(b)\fR, a regular variable is created. \fIOtherVar\fR may refer to a scalar variable, an array, or an array element. \fBUpvar\fR returns an empty string. .PP The \fBupvar\fR command simplifies the implementation of call-by-name procedure calling and also makes it easier to build new control constructs as Tcl procedures. For example, consider the following procedure: .CS proc add2 name { \fBupvar\fR $name x set x [expr $x+2] } .CE \fBadd2\fR is invoked with an argument giving the name of a variable, and it adds two to the value of that variable. Although \fBadd2\fR could have been implemented using \fBuplevel\fR instead of \fBupvar\fR, \fBupvar\fR makes it simpler for \fBadd2\fR to access the variable in the caller's procedure frame. .PP \fBnamespace eval\fR is another way (besides procedure calls) that the Tcl naming context can change. It adds a call frame to the stack to represent the namespace context. This means each \fBnamespace eval\fR command counts as another call level for \fBuplevel\fR and \fBupvar\fR commands. For example, \fBinfo level 1\fR will return a list describing a command that is either the outermost procedure call or the outermost \fBnamespace eval\fR command. Also, \fBuplevel #0\fR evaluates a script at top-level in the outermost namespace (the global namespace). .PP .VS If an upvar variable is unset (e.g. \fBx\fR in \fBadd2\fR above), the \fBunset\fR operation affects the variable it is linked to, not the upvar variable. There is no way to unset an upvar variable except by exiting the procedure in which it is defined. However, it is possible to retarget an upvar variable by executing another \fBupvar\fR command. .SH "TRACES AND UPVAR" .PP Upvar interacts with traces in a straightforward but possibly unexpected manner. If a variable trace is defined on \fIotherVar\fR, that trace will be triggered by actions involving \fImyVar\fR. However, the trace procedure will be passed the name of \fImyVar\fR, rather than the name of \fIotherVar\fR. Thus, the output of the following code will be \fBlocalVar\fR rather than \fBoriginalVar\fR: .CS proc \fBtraceproc\fR { name index op } { puts $name } proc \fBsetByUpvar\fR { name value } { \fBupvar\fR $name localVar set localVar $value } set originalVar 1 trace variable originalVar w \fBtraceproc\fR \fBsetByUpvar\fR originalVar 2 } .CE .PP If \fIotherVar\fR refers to an element of an array, then variable traces set for the entire array will not be invoked when \fImyVar\fR is accessed (but traces on the particular element will still be invoked). In particular, if the array is \fBenv\fR, then changes made to \fImyVar\fR will not be passed to subprocesses correctly. .VE .SH EXAMPLE A \fBdecr\fR command that works like \fBincr\fR except it subtracts the value from the variable instead of adding it: .CS proc decr {varName {decrement 1}} { \fBupvar\fR 1 $varName var incr var [expr {-$decrement}] } .CE .SH "SEE ALSO" global(n), namespace(n), uplevel(n), variable(n) .SH KEYWORDS context, frame, global, level, namespace, procedure, variable tcl8.4.20/doc/switch.n0000644003604700454610000001003011737050674013136 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH switch n 7.0 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME switch \- Evaluate one of several scripts, depending on a given value .SH SYNOPSIS \fBswitch \fR?\fIoptions\fR?\fI string pattern body \fR?\fIpattern body \fR...? .sp \fBswitch \fR?\fIoptions\fR?\fI string \fR{\fIpattern body \fR?\fIpattern body \fR...?} .BE .SH DESCRIPTION .PP The \fBswitch\fR command matches its \fIstring\fR argument against each of the \fIpattern\fR arguments in order. As soon as it finds a \fIpattern\fR that matches \fIstring\fR it evaluates the following \fIbody\fR argument by passing it recursively to the Tcl interpreter and returns the result of that evaluation. If the last \fIpattern\fR argument is \fBdefault\fR then it matches anything. If no \fIpattern\fR argument matches \fIstring\fR and no default is given, then the \fBswitch\fR command returns an empty string. .PP If the initial arguments to \fBswitch\fR start with \fB\-\fR then they are treated as options. The following options are currently supported: .TP 10 \fB\-exact\fR Use exact matching when comparing \fIstring\fR to a pattern. This is the default. .TP 10 \fB\-glob\fR When matching \fIstring\fR to the patterns, use glob-style matching (i.e. the same as implemented by the \fBstring match\fR command). .TP 10 \fB\-regexp\fR When matching \fIstring\fR to the patterns, use regular expression matching (as described in the \fBre_syntax\fR reference page). .TP 10 \fB\-\|\-\fR Marks the end of options. The argument following this one will be treated as \fIstring\fR even if it starts with a \fB\-\fR. .PP Two syntaxes are provided for the \fIpattern\fR and \fIbody\fR arguments. The first uses a separate argument for each of the patterns and commands; this form is convenient if substitutions are desired on some of the patterns or commands. The second form places all of the patterns and commands together into a single argument; the argument must have proper list structure, with the elements of the list being the patterns and commands. The second form makes it easy to construct multi-line switch commands, since the braces around the whole list make it unnecessary to include a backslash at the end of each line. Since the \fIpattern\fR arguments are in braces in the second form, no command or variable substitutions are performed on them; this makes the behavior of the second form different than the first form in some cases. .PP If a \fIbody\fR is specified as ``\fB\-\fR'' it means that the \fIbody\fR for the next pattern should also be used as the body for this pattern (if the next pattern also has a body of ``\fB\-\fR'' then the body after that is used, and so on). This feature makes it possible to share a single \fIbody\fR among several patterns. .PP Beware of how you place comments in \fBswitch\fR commands. Comments should only be placed \fBinside\fR the execution body of one of the patterns, and not intermingled with the patterns. .SH "EXAMPLES" The \fBswitch\fR command can match against variables and not just literals, as shown here (the result is \fI2\fR): .CS set foo "abc" \fBswitch\fR abc a \- b {expr 1} $foo {expr 2} default {expr 3} .CE .PP Using glob matching and the fall-through body is an alternative to writing regular expressions with alternations, as can be seen here (this returns \fI1\fR): .CS \fBswitch\fR \-glob aaab { a*b \- b {expr 1} a* {expr 2} default {expr 3} } .CE .PP Whenever nothing matches, the \fBdefault\fR clause (which must be last) is taken. This example has a result of \fI3\fR: .CS \fBswitch\fR xyz { a \- b { # Correct Comment Placement expr 1 } c { expr 2 } default { expr 3 } } .CE .SH "SEE ALSO" for(n), if(n), regexp(n) .SH KEYWORDS switch, match, regular expression tcl8.4.20/doc/IntObj.30000644003604700454610000001227211737050674012741 0ustar dgp771div'\" '\" Copyright (c) 1996-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_IntObj 3 8.0 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_NewIntObj, Tcl_NewLongObj, Tcl_NewWideIntObj, Tcl_SetIntObj, Tcl_SetLongObj, Tcl_SetWideIntObj, Tcl_GetIntFromObj, Tcl_GetLongFromObj, Tcl_GetWideIntFromObj \- manipulate Tcl objects as integers and wide integers .SH SYNOPSIS .nf \fB#include \fR .sp Tcl_Obj * \fBTcl_NewIntObj\fR(\fIintValue\fR) .sp Tcl_Obj * \fBTcl_NewLongObj\fR(\fIlongValue\fR) .sp .VS 8.4 Tcl_Obj * \fBTcl_NewWideIntObj\fR(\fIwideValue\fR) .VE 8.4 .sp \fBTcl_SetIntObj\fR(\fIobjPtr, intValue\fR) .sp \fBTcl_SetLongObj\fR(\fIobjPtr, longValue\fR) .sp .VS 8.4 \fBTcl_SetWideIntObj\fR(\fIobjPtr, wideValue\fR) .VE 8.4 .sp int \fBTcl_GetIntFromObj\fR(\fIinterp, objPtr, intPtr\fR) .sp int \fBTcl_GetLongFromObj\fR(\fIinterp, objPtr, longPtr\fR) .sp .VS 8.4 int \fBTcl_GetWideIntFromObj\fR(\fIinterp, objPtr, widePtr\fR) .VE 8.4 .SH ARGUMENTS .AS Tcl_WideInt *interp .AP int intValue in Integer value used to initialize or set an integer object. .AP long longValue in Long integer value used to initialize or set an integer object. .AP Tcl_WideInt wideValue in .VS 8.4 Wide integer value (minimum 64-bits wide where supported by the compiler) used to initialize or set a wide integer object. .VE 8.4 .AP Tcl_Obj *objPtr in/out For \fBTcl_SetIntObj\fR, \fBTcl_SetLongObj\fR, and .VS 8.4 \fBTcl_SetWideIntObj\fR, this points to the object to be converted to integer type. For \fBTcl_GetIntFromObj\fR, \fBTcl_GetLongFromObj\fR, and \fBTcl_GetWideIntFromObj\fR, this refers to the object from which to get an integer or long integer value; if \fIobjPtr\fR does not already point to an integer object (or a wide integer object in the case of \fBTcl_SetWideIntObj\fR and \fBTcl_GetWideIntFromObj\fR,) an .VE 8.4 attempt will be made to convert it to one. .AP Tcl_Interp *interp in/out If an error occurs during conversion, an error message is left in the interpreter's result object unless \fIinterp\fR is NULL. .AP int *intPtr out Points to place to store the integer value obtained by \fBTcl_GetIntFromObj\fR from \fIobjPtr\fR. .AP long *longPtr out Points to place to store the long integer value obtained by \fBTcl_GetLongFromObj\fR from \fIobjPtr\fR. .AP Tcl_WideInt *widePtr out .VS 8.4 Points to place to store the wide integer value obtained by \fBTcl_GetWideIntFromObj\fR from \fIobjPtr\fR. .VE 8.4 .BE .SH DESCRIPTION .PP These procedures are used to create, modify, and read integer and wide integer Tcl objects from C code. \fBTcl_NewIntObj\fR, \fBTcl_NewLongObj\fR, \fBTcl_SetIntObj\fR, and \fBTcl_SetLongObj\fR create a new object of integer type or modify an existing object to have integer type, .VS 8.4 and \fBTcl_NewWideIntObj\fR and \fBTcl_SetWideIntObj\fR create a new object of wide integer type or modify an existing object to have wide integer type. .VE 8.4 \fBTcl_NewIntObj\fR and \fBTcl_SetIntObj\fR set the object to have the integer value given by \fIintValue\fR, \fBTcl_NewLongObj\fR and \fBTcl_SetLongObj\fR set the object to have the long integer value given by \fIlongValue\fR, .VS 8.4 and \fBTcl_NewWideIntObj\fR and \fBTcl_SetWideIntObj\fR set the object to have the wide integer value given by \fIwideValue\fR. \fBTcl_NewIntObj\fR, \fBTcl_NewLongObj\fR and \fBTcl_NewWideIntObj\fR return a pointer to a newly created object with reference count zero. These procedures set the object's type to be integer and assign the integer value to the object's internal representation \fIlongValue\fR or \fIwideValue\fR member (as appropriate). \fBTcl_SetIntObj\fR, \fBTcl_SetLongObj\fR and \fBTcl_SetWideIntObj\fR .VE 8.4 invalidate any old string representation and, if the object is not already an integer object, free any old internal representation. .PP \fBTcl_GetIntFromObj\fR and \fBTcl_GetLongFromObj\fR attempt to return an integer value from the Tcl object \fIobjPtr\fR, .VS 8.4 and \fBTcl_GetWideIntFromObj\fR attempts to return a wide integer value from the Tcl object \fIobjPtr\fR. If the object is not already an integer object, or a wide integer object in the case of \fBTcl_GetWideIntFromObj\fR .VE 8.4 they will attempt to convert it to one. If an error occurs during conversion, they return \fBTCL_ERROR\fR and leave an error message in the interpreter's result object unless \fIinterp\fR is NULL. Also, if the long integer held in the object's internal representation \fIlongValue\fR member can not be represented in a (non-long) integer, \fBTcl_GetIntFromObj\fR returns \fBTCL_ERROR\fR and leaves an error message in the interpreter's result object unless \fIinterp\fR is NULL. Otherwise, all three procedures return \fBTCL_OK\fR and store the integer, long integer value .VS 8.4 or wide integer in the address given by \fIintPtr\fR, \fIlongPtr\fR and \fIwidePtr\fR .VE 8.4 respectively. If the object is not already an integer or wide integer object, the conversion will free any old internal representation. .SH "SEE ALSO" Tcl_NewObj, Tcl_DecrRefCount, Tcl_IncrRefCount, Tcl_GetObjResult .SH KEYWORDS integer, integer object, integer type, internal representation, object, object type, string representation tcl8.4.20/doc/time.n0000644003604700454610000000210011737050674012572 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH time n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME time \- Time the execution of a script .SH SYNOPSIS \fBtime \fIscript\fR ?\fIcount\fR? .BE .SH DESCRIPTION .PP This command will call the Tcl interpreter \fIcount\fR times to evaluate \fIscript\fR (or once if \fIcount\fR isn't specified). It will then return a string of the form .CS \fB503 microseconds per iteration\fR .CE which indicates the average amount of time required per iteration, in microseconds. Time is measured in elapsed time, not CPU time. .SH EXAMPLE Estimate how long it takes for a simple Tcl \fBfor\fR loop to count to a thousand: .CS time { for {set i 0} {$i<1000} {incr i} { # empty body } } .CE .SH "SEE ALSO" clock(n) .SH KEYWORDS script, time tcl8.4.20/doc/AppInit.30000644003604700454610000000526311737050674013122 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_AppInit 3 7.0 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_AppInit \- perform application-specific initialization .SH SYNOPSIS .nf \fB#include \fR .sp int \fBTcl_AppInit\fR(\fIinterp\fR) .SH ARGUMENTS .AS Tcl_Interp *interp .AP Tcl_Interp *interp in Interpreter for the application. .BE .SH DESCRIPTION .PP \fBTcl_AppInit\fR is a ``hook'' procedure that is invoked by the main programs for Tcl applications such as \fBtclsh\fR and \fBwish\fR. Its purpose is to allow new Tcl applications to be created without modifying the main programs provided as part of Tcl and Tk. To create a new application you write a new version of \fBTcl_AppInit\fR to replace the default version provided by Tcl, then link your new \fBTcl_AppInit\fR with the Tcl library. .PP \fBTcl_AppInit\fR is invoked by \fBTcl_Main\fR and \fBTk_Main\fR after their own initialization and before entering the main loop to process commands. Here are some examples of things that \fBTcl_AppInit\fR might do: .IP [1] Call initialization procedures for various packages used by the application. Each initialization procedure adds new commands to \fIinterp\fR for its package and performs other package-specific initialization. .IP [2] Process command-line arguments, which can be accessed from the Tcl variables \fBargv\fR and \fBargv0\fR in \fIinterp\fR. .IP [3] Invoke a startup script to initialize the application. .LP \fBTcl_AppInit\fR returns TCL_OK or TCL_ERROR. If it returns TCL_ERROR then it must leave an error message in for the interpreter's result; otherwise the result is ignored. .PP In addition to \fBTcl_AppInit\fR, your application should also contain a procedure \fBmain\fR that calls \fBTcl_Main\fR as follows: .CS Tcl_Main(argc, argv, Tcl_AppInit); .CE The third argument to \fBTcl_Main\fR gives the address of the application-specific initialization procedure to invoke. This means that you don't have to use the name \fBTcl_AppInit\fR for the procedure, but in practice the name is nearly always \fBTcl_AppInit\fR (in versions before Tcl 7.4 the name \fBTcl_AppInit\fR was implicit; there was no way to specify the procedure explicitly). The best way to get started is to make a copy of the file \fBtclAppInit.c\fR from the Tcl library or source directory. It already contains a \fBmain\fR procedure and a template for \fBTcl_AppInit\fR that you can modify for your application. .SH KEYWORDS application, argument, command, initialization, interpreter tcl8.4.20/doc/GetCwd.30000755003604700454610000000325611737050674012736 0ustar dgp771div'\" '\" Copyright (c) 1998-1999 Scriptics Corporation '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_GetCwd 3 8.1 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_GetCwd, Tcl_Chdir \- manipulate the current working directory .SH SYNOPSIS .nf \fB#include \fR .sp char * \fBTcl_GetCwd\fR(\fIinterp\fR, \fIbufferPtr\fR) .sp int \fBTcl_Chdir\fR(\fIpath\fR) .SH ARGUMENTS .AS Tcl_DString *bufferPtr .AP Tcl_Interp *interp in Interpreter in which to report an error, if any. .AP Tcl_DString *bufferPtr in/out This dynamic string is used to store the current working directory. At the time of the call it should be uninitialized or free. The caller must eventually call \fBTcl_DStringFree\fR to free up anything stored here. .AP char *path in File path in UTF\-8 format. .BE .SH DESCRIPTION .PP These procedures may be used to manipulate the current working directory for the application. They provide C\-level access to the same functionality as the Tcl \fBpwd\fR command. .PP \fBTcl_GetCwd\fR returns a pointer to a string specifying the current directory, or NULL if the current directory could not be determined. If NULL is returned, an error message is left in the interp's result. Storage for the result string is allocated in bufferPtr; the caller must call \fBTcl_DStringFree()\fR when the result is no longer needed. The format of the path is UTF\-8. .PP \fBTcl_Chdir\fR changes the applications current working directory to the value specified in \fIpath\fR. The format of the passed in string must be UTF\-8. The function returns -1 on error or 0 on success. .SH KEYWORDS pwd tcl8.4.20/doc/split.n0000644003604700454610000000504411737050674013001 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH split n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME split \- Split a string into a proper Tcl list .SH SYNOPSIS \fBsplit \fIstring \fR?\fIsplitChars\fR? .BE .SH DESCRIPTION .PP Returns a list created by splitting \fIstring\fR at each character that is in the \fIsplitChars\fR argument. Each element of the result list will consist of the characters from \fIstring\fR that lie between instances of the characters in \fIsplitChars\fR. Empty list elements will be generated if \fIstring\fR contains adjacent characters in \fIsplitChars\fR, or if the first or last character of \fIstring\fR is in \fIsplitChars\fR. If \fIsplitChars\fR is an empty string then each character of \fIstring\fR becomes a separate element of the result list. \fISplitChars\fR defaults to the standard white-space characters. .SH EXAMPLES Divide up a USENET group name into its hierarchical components: .CS \fBsplit\fR "comp.lang.tcl.announce" . \fI=> comp lang tcl announce\fR .CE .PP See how the \fBsplit\fR command splits on \fIevery\fR character in \fIsplitChars\fR, which can result in information loss if you are not careful: .CS \fBsplit\fR "alpha beta gamma" "temp" \fI=> al {ha b} {} {a ga} {} a\fR .CE .PP Extract the list words from a string that is not a well-formed list: .CS \fBsplit\fR "Example with {unbalanced brace character" \fI=> Example with \\{unbalanced brace character\fR .CE .PP Split a string into its constituent characters .CS \fBsplit\fR "Hello world" {} \fI=> H e l l o { } w o r l d\fR .CE .SH "PARSING RECORD-ORIENTED FILES" Parse a Unix /etc/passwd file, which consists of one entry per line, with each line consisting of a colon-separated list of fields: .CS ## Read the file set fid [open /etc/passwd] set content [read $fid] close $fid ## Split into records on newlines set records [\fBsplit\fR $content "\\n"] ## Iterate over the records foreach rec $records { ## Split into fields on colons set fields [\fBsplit\fR $rec ":"] ## Assign fields to variables and print some out... lassign $fields \\ userName password uid grp longName homeDir shell puts "$longName uses [file tail $shell] for a login shell" } .CE .SH "SEE ALSO" join(n), list(n), string(n) .SH KEYWORDS list, split, string tcl8.4.20/doc/CrtChannel.30000644003604700454610000011143311737050674013574 0ustar dgp771div'\" '\" Copyright (c) 1996-1997 Sun Microsystems, Inc. '\" Copyright (c) 1997-2000 Ajuba Solutions. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. .so man.macros .TH Tcl_CreateChannel 3 8.4 Tcl "Tcl Library Procedures" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME Tcl_CreateChannel, Tcl_GetChannelInstanceData, Tcl_GetChannelType, Tcl_GetChannelName, Tcl_GetChannelHandle, Tcl_GetChannelMode, Tcl_GetChannelBufferSize, Tcl_SetChannelBufferSize, Tcl_NotifyChannel, Tcl_BadChannelOption, Tcl_ChannelName, Tcl_ChannelVersion, Tcl_ChannelBlockModeProc, Tcl_ChannelCloseProc, Tcl_ChannelClose2Proc, Tcl_ChannelInputProc, Tcl_ChannelOutputProc, Tcl_ChannelSeekProc, Tcl_ChannelWideSeekProc, Tcl_ChannelSetOptionProc, Tcl_ChannelGetOptionProc, Tcl_ChannelWatchProc, Tcl_ChannelGetHandleProc, Tcl_ChannelFlushProc, Tcl_ChannelHandlerProc, Tcl_ChannelThreadActionProc, Tcl_IsChannelShared, Tcl_IsChannelRegistered, Tcl_CutChannel, Tcl_SpliceChannel, Tcl_IsChannelExisting, Tcl_ClearChannelHandlers, Tcl_GetChannelThread, Tcl_ChannelBuffered \- procedures for creating and manipulating channels .SH SYNOPSIS .nf \fB#include \fR .sp Tcl_Channel \fBTcl_CreateChannel\fR(\fItypePtr, channelName, instanceData, mask\fR) .sp ClientData \fBTcl_GetChannelInstanceData\fR(\fIchannel\fR) .sp Tcl_ChannelType * \fBTcl_GetChannelType\fR(\fIchannel\fR) .sp CONST char * \fBTcl_GetChannelName\fR(\fIchannel\fR) .sp int \fBTcl_GetChannelHandle\fR(\fIchannel, direction, handlePtr\fR) .sp .VS 8.4 Tcl_ThreadId \fBTcl_GetChannelThread\fR(\fIchannel\fR) .VE 8.4 .sp int \fBTcl_GetChannelMode\fR(\fIchannel\fR) .sp int \fBTcl_GetChannelBufferSize\fR(\fIchannel\fR) .sp \fBTcl_SetChannelBufferSize\fR(\fIchannel, size\fR) .sp \fBTcl_NotifyChannel\fR(\fIchannel, mask\fR) .sp int \fBTcl_BadChannelOption\fR(\fIinterp, optionName, optionList\fR) .VS 8.4 .sp int \fBTcl_IsChannelShared\fR(\fIchannel\fR) .sp int \fBTcl_IsChannelRegistered\fR(\fIinterp, channel\fR) .sp int \fBTcl_IsChannelExisting\fR(\fIchannelName\fR) .sp void \fBTcl_CutChannel\fR(\fIchannel\fR) .sp void \fBTcl_SpliceChannel\fR(\fIchannel\fR) .sp void \fBTcl_ClearChannelHandlers\fR(\fIchannel\fR) .VE 8.4 .sp int \fBTcl_ChannelBuffered\fR(\fIchannel\fR) .sp CONST char * \fBTcl_ChannelName\fR(\fItypePtr\fR) .sp Tcl_ChannelTypeVersion \fBTcl_ChannelVersion\fR(\fItypePtr\fR) .sp Tcl_DriverBlockModeProc * \fBTcl_ChannelBlockModeProc\fR(\fItypePtr\fR) .sp Tcl_DriverCloseProc * \fBTcl_ChannelCloseProc\fR(\fItypePtr\fR) .sp Tcl_DriverClose2Proc * \fBTcl_ChannelClose2Proc\fR(\fItypePtr\fR) .sp Tcl_DriverInputProc * \fBTcl_ChannelInputProc\fR(\fItypePtr\fR) .sp Tcl_DriverOutputProc * \fBTcl_ChannelOutputProc\fR(\fItypePtr\fR) .sp Tcl_DriverSeekProc * \fBTcl_ChannelSeekProc\fR(\fItypePtr\fR) .sp .VS 8.4 Tcl_DriverWideSeekProc * \fBTcl_ChannelWideSeekProc\fR(\fItypePtr\fR) .sp Tcl_DriverThreadActionProc * \fBTcl_ChannelThreadActionProc\fR(\fItypePtr\fR) .VE 8.4 .sp Tcl_DriverSetOptionProc * \fBTcl_ChannelSetOptionProc\fR(\fItypePtr\fR) .sp Tcl_DriverGetOptionProc * \fBTcl_ChannelGetOptionProc\fR(\fItypePtr\fR) .sp Tcl_DriverWatchProc * \fBTcl_ChannelWatchProc\fR(\fItypePtr\fR) .sp Tcl_DriverGetHandleProc * \fBTcl_ChannelGetHandleProc\fR(\fItypePtr\fR) .sp Tcl_DriverFlushProc * \fBTcl_ChannelFlushProc\fR(\fItypePtr\fR) .sp Tcl_DriverHandlerProc * \fBTcl_ChannelHandlerProc\fR(\fItypePtr\fR) .sp .SH ARGUMENTS .AS Tcl_ChannelType *channelName in .AP Tcl_ChannelType *typePtr in Points to a structure containing the addresses of procedures that can be called to perform I/O and other functions on the channel. .AP "CONST char" *channelName in The name of this channel, such as \fBfile3\fR; must not be in use by any other channel. Can be NULL, in which case the channel is created without a name. .AP ClientData instanceData in Arbitrary one-word value to be associated with this channel. This value is passed to procedures in \fItypePtr\fR when they are invoked. .AP int mask in OR-ed combination of \fBTCL_READABLE\fR and \fBTCL_WRITABLE\fR to indicate whether a channel is readable and writable. .AP Tcl_Channel channel in The channel to operate on. .AP int direction in \fBTCL_READABLE\fR means the input handle is wanted; \fBTCL_WRITABLE\fR means the output handle is wanted. .AP ClientData *handlePtr out Points to the location where the desired OS-specific handle should be stored. .AP int size in The size, in bytes, of buffers to allocate in this channel. .AP int mask in An OR-ed combination of \fBTCL_READABLE\fR, \fBTCL_WRITABLE\fR and \fBTCL_EXCEPTION\fR that indicates events that have occurred on this channel. .AP Tcl_Interp *interp in Current interpreter. (can be NULL) .AP "CONST char" *optionName in Name of the invalid option. .AP "CONST char" *optionList in Specific options list (space separated words, without "-") to append to the standard generic options list. Can be NULL for generic options error message only. .BE .SH DESCRIPTION .PP Tcl uses a two-layered channel architecture. It provides a generic upper layer to enable C and Tcl programs to perform input and output using the same APIs for a variety of files, devices, sockets etc. The generic C APIs are described in the manual entry for \fBTcl_OpenFileChannel\fR. .PP The lower layer provides type-specific channel drivers for each type of device supported on each platform. This manual entry describes the C APIs used to communicate between the generic layer and the type-specific channel drivers. It also explains how new types of channels can be added by providing new channel drivers. .PP Channel drivers consist of a number of components: First, each channel driver provides a \fBTcl_ChannelType\fR structure containing pointers to functions implementing the various operations used by the generic layer to communicate with the channel driver. The \fBTcl_ChannelType\fR structure and the functions referenced by it are described in the section TCL_CHANNELTYPE, below. .PP Second, channel drivers usually provide a Tcl command to create instances of that type of channel. For example, the Tcl \fBopen\fR command creates channels that use the file and command channel drivers, and the Tcl \fBsocket\fR command creates channels that use TCP sockets for network communication. .PP Third, a channel driver optionally provides a C function to open channel instances of that type. For example, \fBTcl_OpenFileChannel\fR opens a channel that uses the file channel driver, and \fBTcl_OpenTcpClient\fR opens a channel that uses the TCP network protocol. These creation functions typically use \fBTcl_CreateChannel\fR internally to open the channel. .PP To add a new type of channel you must implement a C API or a Tcl command that opens a channel by invoking \fBTcl_CreateChannel\fR. When your driver calls \fBTcl_CreateChannel\fR it passes in a \fBTcl_ChannelType\fR structure describing the driver's I/O procedures. The generic layer will then invoke the functions referenced in that structure to perform operations on the channel. .PP \fBTcl_CreateChannel\fR opens a new channel and associates the supplied \fItypePtr\fR and \fIinstanceData\fR with it. The channel is opened in the mode indicated by \fImask\fR. For a discussion of channel drivers, their operations and the \fBTcl_ChannelType\fR structure, see the section TCL_CHANNELTYPE, below. .PP \fBTcl_CreateChannel\fR interacts with the code managing the standard channels. Once a standard channel was initialized either through a call to \fBTcl_GetStdChannel\fR or a call to \fBTcl_SetStdChannel\fR closing this standard channel will cause the next call to \fBTcl_CreateChannel\fR to make the new channel the new standard channel too. See \fBTcl_StandardChannels\fR for a general treatise about standard channels and the behaviour of the Tcl library with regard to them. .PP \fBTcl_GetChannelInstanceData\fR returns the instance data associated with the channel in \fIchannel\fR. This is the same as the \fIinstanceData\fR argument in the call to \fBTcl_CreateChannel\fR that created this channel. .PP \fBTcl_GetChannelType\fR returns a pointer to the \fBTcl_ChannelType\fR structure used by the channel in the \fIchannel\fR argument. This is the same as the \fItypePtr\fR argument in the call to \fBTcl_CreateChannel\fR that created this channel. .PP \fBTcl_GetChannelName\fR returns a string containing the name associated with the channel, or NULL if the \fIchannelName\fR argument to \fBTcl_CreateChannel\fR was NULL. .PP \fBTcl_GetChannelHandle\fR places the OS-specific device handle associated with \fIchannel\fR for the given \fIdirection\fR in the location specified by \fIhandlePtr\fR and returns \fBTCL_OK\fR. If the channel does not have a device handle for the specified direction, then \fBTCL_ERROR\fR is returned instead. Different channel drivers will return different types of handle. Refer to the manual entries for each driver to determine what type of handle is returned. .PP .VS 8.4 \fBTcl_GetChannelThread\fR returns the id of the thread currently managing the specified \fIchannel\fR. This allows channel drivers to send their file events to the correct event queue even for a multi-threaded core. .VE 8.4 .PP \fBTcl_GetChannelMode\fR returns an OR-ed combination of \fBTCL_READABLE\fR and \fBTCL_WRITABLE\fR, indicating whether the channel is open for input and output. .PP \fBTcl_GetChannelBufferSize\fR returns the size, in bytes, of buffers allocated to store input or output in \fIchannel\fR. If the value was not set by a previous call to \fBTcl_SetChannelBufferSize\fR, described below, then the default value of 4096 is returned. .PP \fBTcl_SetChannelBufferSize\fR sets the size, in bytes, of buffers that will be allocated in subsequent operations on the channel to store input or output. The \fIsize\fR argument should be between ten and one million, allowing buffers of ten bytes to one million bytes. If \fIsize\fR is outside this range, \fBTcl_SetChannelBufferSize\fR sets the buffer size to 4096. .PP \fBTcl_NotifyChannel\fR is called by a channel driver to indicate to the generic layer that the events specified by \fImask\fR have occurred on the channel. Channel drivers are responsible for invoking this function whenever the channel handlers need to be called for the channel. See \fBWATCHPROC\fR below for more details. .PP \fBTcl_BadChannelOption\fR is called from driver specific set or get option procs to generate a complete error message. .PP \fBTcl_ChannelBuffered\fR returns the number of bytes of input currently buffered in the internal buffer (push back area) of the channel itself. It does not report about the data in the overall buffers for the stack of channels the supplied channel is part of. .PP .VS 8.4 \fBTcl_IsChannelShared\fR checks the refcount of the specified \fIchannel\fR and returns whether the \fIchannel\fR was shared among multiple interpreters (result == 1) or not (result == 0). .PP \fBTcl_IsChannelRegistered\fR checks whether the specified \fIchannel\fR is registered in the given \fIinterp\fRreter (result == 1) or not (result == 0). .PP \fBTcl_IsChannelExisting\fR checks whether a channel with the specified name is registered in the (thread)-global list of all channels (result == 1) or not (result == 0). .PP \fBTcl_CutChannel\fR removes the specified \fIchannel\fR from the (thread)global list of all channels (of the current thread). Application to a channel still registered in some interpreter is not allowed. .VS 8.4 Also notifies the driver if the \fBTcl_ChannelType\fR version is \fBTCL_CHANNEL_VERSION_4\fR (or higher), and \fBTcl_DriverThreadActionProc\fR is defined for it. .VE 8.4 .PP \fBTcl_SpliceChannel\fR adds the specified \fIchannel\fR to the (thread)global list of all channels (of the current thread). Application to a channel registered in some interpreter is not allowed. .VS 8.4 Also notifies the driver if the \fBTcl_ChannelType\fR version is \fBTCL_CHANNEL_VERSION_4\fR (or higher), and \fBTcl_DriverThreadActionProc\fR is defined for it. .VE 8.4 .PP \fBTcl_ClearChannelHandlers\fR removes all channelhandlers and event scripts associated with the specified \fIchannel\fR, thus shutting down all event processing for this channel. .VE 8.4 .SH TCL_CHANNELTYPE .PP A channel driver provides a \fBTcl_ChannelType\fR structure that contains pointers to functions that implement the various operations on a channel; these operations are invoked as needed by the generic layer. The structure was versioned starting in Tcl 8.3.2/8.4 to correct a problem with stacked channel drivers. See the \fBOLD CHANNEL TYPES\fR section below for details about the old structure. .PP The \fBTcl_ChannelType\fR structure contains the following fields: .CS typedef struct Tcl_ChannelType { char *\fItypeName\fR; Tcl_ChannelTypeVersion \fIversion\fR; Tcl_DriverCloseProc *\fIcloseProc\fR; Tcl_DriverInputProc *\fIinputProc\fR; Tcl_DriverOutputProc *\fIoutputProc\fR; Tcl_DriverSeekProc *\fIseekProc\fR; Tcl_DriverSetOptionProc *\fIsetOptionProc\fR; Tcl_DriverGetOptionProc *\fIgetOptionProc\fR; Tcl_DriverWatchProc *\fIwatchProc\fR; Tcl_DriverGetHandleProc *\fIgetHandleProc\fR; Tcl_DriverClose2Proc *\fIclose2Proc\fR; Tcl_DriverBlockModeProc *\fIblockModeProc\fR; Tcl_DriverFlushProc *\fIflushProc\fR; Tcl_DriverHandlerProc *\fIhandlerProc\fR; Tcl_DriverWideSeekProc *\fIwideSeekProc\fR; Tcl_DriverThreadActionProc *\fIthreadActionProc\fR; } Tcl_ChannelType; .CE .PP It is not necessary to provide implementations for all channel operations. Those which are not necessary may be set to NULL in the struct: \fIblockModeProc\fR, \fIseekProc\fR, \fIsetOptionProc\fR, \fIgetOptionProc\fR, and \fIclose2Proc\fR, in addition to \fIflushProc\fR, \fIhandlerProc\fR, and \fIthreadActionProc\fR. Other functions that cannot be implemented in a meaningful way should return \fBEINVAL\fR when called, to indicate that the operations they represent are not available. Also note that \fIwideSeekProc\fR can be NULL if \fIseekProc\fR is. .PP The user should only use the above structure for \fBTcl_ChannelType\fR instantiation. When referencing fields in a \fBTcl_ChannelType\fR structure, the following functions should be used to obtain the values: \fBTcl_ChannelName\fR, \fBTcl_ChannelVersion\fR, \fBTcl_ChannelBlockModeProc\fR, \fBTcl_ChannelCloseProc\fR, \fBTcl_ChannelClose2Proc\fR, \fBTcl_ChannelInputProc\fR, \fBTcl_ChannelOutputProc\fR, \fBTcl_ChannelSeekProc\fR, .VS 8.4 \fBTcl_ChannelWideSeekProc\fR, \fBTcl_ChannelThreadActionProc\fR, .VE 8.4 \fBTcl_ChannelSetOptionProc\fR, \fBTcl_ChannelGetOptionProc\fR, \fBTcl_ChannelWatchProc\fR, \fBTcl_ChannelGetHandleProc\fR, \fBTcl_ChannelFlushProc\fR, or \fBTcl_ChannelHandlerProc\fR. .PP The change to the structures was made in such a way that standard channel types are binary compatible. However, channel types that use stacked channels (ie: TLS, Trf) have new versions to correspond to the above change since the previous code for stacked channels had problems. .SH TYPENAME .PP The \fItypeName\fR field contains a null-terminated string that identifies the type of the device implemented by this driver, e.g. \fBfile\fR or \fBsocket\fR. .PP This value can be retrieved with \fBTcl_ChannelName\fR, which returns a pointer to the string. .SH VERSION .PP The \fIversion\fR field should be set to the version of the structure that you require. \fBTCL_CHANNEL_VERSION_2\fR is the minimum recommended. .VS 8.4 \fBTCL_CHANNEL_VERSION_3\fR must be set to specifiy the \fIwideSeekProc\fR member. .VE 8.4 .VS 8.4 \fBTCL_CHANNEL_VERSION_4\fR must be set to specifiy the \fIthreadActionProc\fR member (includes \fIwideSeekProc\fR). .VE 8.4 If it is not set to any of these, then this \fBTcl_ChannelType\fR is assumed to have the original structure. See \fBOLD CHANNEL TYPES\fR for more details. While Tcl will recognize and function with either structures, stacked channels must be of at least \fBTCL_CHANNEL_VERSION_2\fR to function correctly. .PP This value can be retrieved with \fBTcl_ChannelVersion\fR, which returns .VS 8.4 one of \fBTCL_CHANNEL_VERSION_4\fR, \fBTCL_CHANNEL_VERSION_3\fR, .VE 8.4 \fBTCL_CHANNEL_VERSION_2\fR, or \fBTCL_CHANNEL_VERSION_1\fR. .SH BLOCKMODEPROC .PP The \fIblockModeProc\fR field contains the address of a function called by the generic layer to set blocking and nonblocking mode on the device. \fIBlockModeProc\fR should match the following prototype: .PP .CS typedef int Tcl_DriverBlockModeProc( ClientData \fIinstanceData\fR, int \fImode\fR); .CE .PP The \fIinstanceData\fR is the same as the value passed to \fBTcl_CreateChannel\fR when this channel was created. The \fImode\fR argument is either \fBTCL_MODE_BLOCKING\fR or \fBTCL_MODE_NONBLOCKING\fR to set the device into blocking or nonblocking mode. The function should return zero if the operation was successful, or a nonzero POSIX error code if the operation failed. .PP If the operation is successful, the function can modify the supplied \fIinstanceData\fR to record that the channel entered blocking or nonblocking mode and to implement the blocking or nonblocking behavior. For some device types, the blocking and nonblocking behavior can be implemented by the underlying operating system; for other device types, the behavior must be emulated in the channel driver. .PP This value can be retrieved with \fBTcl_ChannelBlockModeProc\fR, which returns a pointer to the function. .PP A channel driver \fBnot\fR supplying a \fIblockModeProc\fR has to be very, very careful. It has to tell the generic layer exactly which blocking mode is acceptable to it, and should this also document for the user so that the blocking mode of the channel is not changed to an inacceptable value. Any confusion here may lead the interpreter into a (spurious and difficult to find) deadlock. .SH "CLOSEPROC AND CLOSE2PROC" .PP The \fIcloseProc\fR field contains the address of a function called by the generic layer to clean up driver-related information when the channel is closed. \fICloseProc\fR must match the following prototype: .PP .CS typedef int Tcl_DriverCloseProc( ClientData \fIinstanceData\fR, Tcl_Interp *\fIinterp\fR); .CE .PP The \fIinstanceData\fR argument is the same as the value provided to \fBTcl_CreateChannel\fR when the channel was created. The function should release any storage maintained by the channel driver for this channel, and close the input and output devices encapsulated by this channel. All queued output will have been flushed to the device before this function is called, and no further driver operations will be invoked on this instance after calling the \fIcloseProc\fR. If the close operation is successful, the procedure should return zero; otherwise it should return a nonzero POSIX error code. In addition, if an error occurs and \fIinterp\fR is not NULL, the procedure should store an error message in the interpreter's result. .PP Alternatively, channels that support closing the read and write sides independently may set \fIcloseProc\fR to \fBTCL_CLOSE2PROC\fR and set \fIclose2Proc\fR to the address of a function that matches the following prototype: .PP .CS typedef int Tcl_DriverClose2Proc( ClientData \fIinstanceData\fR, Tcl_Interp *\fIinterp\fR, int \fIflags\fR); .CE .PP The \fIclose2Proc\fR will be called with \fIflags\fR set to an OR'ed combination of \fBTCL_CLOSE_READ\fR or \fBTCL_CLOSE_WRITE\fR to indicate that the driver should close the read and/or write side of the channel. The channel driver may be invoked to perform additional operations on the channel after \fIclose2Proc\fR is called to close one or both sides of the channel. If \fIflags\fR is \fB0\fR (zero), the driver should close the channel in the manner described above for \fIcloseProc\fR. No further operations will be invoked on this instance after \fIclose2Proc\fR is called with all flags cleared. In all cases, the \fIclose2Proc\fR function should return zero if the close operation was successful; otherwise it should return a nonzero POSIX error code. In addition, if an error occurs and \fIinterp\fR is not NULL, the procedure should store an error message in the interpreter's result. .PP These value can be retrieved with \fBTcl_ChannelCloseProc\fR or \fBTcl_ChannelClose2Proc\fR, which returns a pointer to the respective function. .SH INPUTPROC .PP The \fIinputProc\fR field contains the address of a function called by the generic layer to read data from the file or device and store it in an internal buffer. \fIInputProc\fR must match the following prototype: .PP .CS typedef int Tcl_DriverInputProc( ClientData \fIinstanceData\fR, char *\fIbuf\fR, int \fIbufSize\fR, int *\fIerrorCodePtr\fR); .CE .PP \fIInstanceData\fR is the same as the value passed to \fBTcl_CreateChannel\fR when the channel was created. The \fIbuf\fR argument points to an array of bytes in which to store input from the device, and the \fIbufSize\fR argument indicates how many bytes are available at \fIbuf\fR. .PP The \fIerrorCodePtr\fR argument points to an integer variable provided by the generic layer. If an error occurs, the function should set the variable to a POSIX error code that identifies the error that occurred. .PP The function should read data from the input device encapsulated by the channel and store it at \fIbuf\fR. On success, the function should return a nonnegative integer indicating how many bytes were read from the input device and stored at \fIbuf\fR. On error, the function should return -1. If an error occurs after some data has been read from the device, that data is lost. .PP If \fIinputProc\fR can determine that the input device has some data available but less than requested by the \fIbufSize\fR argument, the function should only attempt to read as much data as is available and return without blocking. If the input device has no data available whatsoever and the channel is in nonblocking mode, the function should return an \fBEAGAIN\fR error. If the input device has no data available whatsoever and the channel is in blocking mode, the function should block for the shortest possible time until at least one byte of data can be read from the device; then, it should return as much data as it can read without blocking. .PP This value can be retrieved with \fBTcl_ChannelInputProc\fR, which returns a pointer to the function. .SH OUTPUTPROC .PP The \fIoutputProc\fR field contains the address of a function called by the generic layer to transfer data from an internal buffer to the output device. \fIOutputProc\fR must match the following prototype: .PP .CS typedef int Tcl_DriverOutputProc( ClientData \fIinstanceData\fR, CONST char *\fIbuf\fR, int \fItoWrite\fR, int *\fIerrorCodePtr\fR); .CE .PP \fIInstanceData\fR is the same as the value passed to \fBTcl_CreateChannel\fR when the channel was created. The \fIbuf\fR argument contains an array of bytes to be written to the device, and the \fItoWrite\fR argument indicates how many bytes are to be written from the \fIbuf\fR argument. .PP The \fIerrorCodePtr\fR argument points to an integer variable provided by the generic layer. If an error occurs, the function should set this variable to a POSIX error code that identifies the error. .PP The function should write the data at \fIbuf\fR to the output device encapsulated by the channel. On success, the function should return a nonnegative integer indicating how many bytes were written to the output device. The return value is normally the same as \fItoWrite\fR, but may be less in some cases such as if the output operation is interrupted by a signal. If an error occurs the function should return -1. In case of error, some data may have been written to the device. .PP If the channel is nonblocking and the output device is unable to absorb any data whatsoever, the function should return -1 with an \fBEAGAIN\fR error without writing any data. .PP This value can be retrieved with \fBTcl_ChannelOutputProc\fR, which returns a pointer to the function. .SH "SEEKPROC AND WIDESEEKPROC" .PP The \fIseekProc\fR field contains the address of a function called by the generic layer to move the access point at which subsequent input or output operations will be applied. \fISeekProc\fR must match the following prototype: .PP .CS typedef int Tcl_DriverSeekProc( ClientData \fIinstanceData\fR, long \fIoffset\fR, int \fIseekMode\fR, int *\fIerrorCodePtr\fR); .CE .PP The \fIinstanceData\fR argument is the same as the value given to \fBTcl_CreateChannel\fR when this channel was created. \fIOffset\fR and \fIseekMode\fR have the same meaning as for the \fBTcl_Seek\fR procedure (described in the manual entry for \fBTcl_OpenFileChannel\fR). .PP The \fIerrorCodePtr\fR argument points to an integer variable provided by the generic layer for returning \fBerrno\fR values from the function. The function should set this variable to a POSIX error code if an error occurs. The function should store an \fBEINVAL\fR error code if the channel type does not implement seeking. .PP The return value is the new access point or -1 in case of error. If an error occurred, the function should not move the access point. .PP .VS 8.4 If there is a non-NULL \fIseekProc\fR field, the \fIwideSeekProc\fR field may contain the address of an alternative function to use which handles wide (i.e. larger than 32-bit) offsets, so allowing seeks within files larger than 2GB. The \fIwideSeekProc\fR will be called in preference to the \fIseekProc\fR, but both must be defined if the \fIwideSeekProc\fR is defined. \fIWideSeekProc\fR must match the following prototype: .PP .CS typedef Tcl_WideInt Tcl_DriverWideSeekProc( ClientData \fIinstanceData\fR, Tcl_WideInt \fIoffset\fR, int \fIseekMode\fR, int *\fIerrorCodePtr\fR); .CE .PP The arguments and return values mean the same thing as with \fIseekProc\fR above, except that the type of offsets and the return type are different. .PP The \fIseekProc\fR value can be retrieved with \fBTcl_ChannelSeekProc\fR, which returns a pointer to the function, and similarly the \fIwideSeekProc\fR can be retrieved with \fBTcl_ChannelWideSeekProc\fR. .VE 8.4 .SH SETOPTIONPROC .PP The \fIsetOptionProc\fR field contains the address of a function called by the generic layer to set a channel type specific option on a channel. \fIsetOptionProc\fR must match the following prototype: .PP .CS typedef int Tcl_DriverSetOptionProc( ClientData \fIinstanceData\fR, Tcl_Interp *\fIinterp\fR, CONST char *\fIoptionName\fR, CONST char *\fInewValue\fR); .CE .PP \fIoptionName\fR is the name of an option to set, and \fInewValue\fR is the new value for that option, as a string. The \fIinstanceData\fR is the same as the value given to \fBTcl_CreateChannel\fR when this channel was created. The function should do whatever channel type specific action is required to implement the new value of the option. .PP Some options are handled by the generic code and this function is never called to set them, e.g. \fB-blockmode\fR. Other options are specific to each channel type and the \fIsetOptionProc\fR procedure of the channel driver will get called to implement them. The \fIsetOptionProc\fR field can be NULL, which indicates that this channel type supports no type specific options. .PP If the option value is successfully modified to the new value, the function returns \fBTCL_OK\fR. It should call \fBTcl_BadChannelOption\fR which itself returns \fBTCL_ERROR\fR if the \fIoptionName\fR is unrecognized. If \fInewValue\fR specifies a value for the option that is not supported or if a system call error occurs, the function should leave an error message in the \fIresult\fR field of \fIinterp\fR if \fIinterp\fR is not NULL. The function should also call \fBTcl_SetErrno\fR to store an appropriate POSIX error code. .PP This value can be retrieved with \fBTcl_ChannelSetOptionProc\fR, which returns a pointer to the function. .SH GETOPTIONPROC .PP The \fIgetOptionProc\fR field contains the address of a function called by the generic layer to get the value of a channel type specific option on a channel. \fIgetOptionProc\fR must match the following prototype: .PP .CS typedef int Tcl_DriverGetOptionProc( ClientData \fIinstanceData\fR, Tcl_Interp *\fIinterp\fR, CONST char *\fIoptionName\fR, Tcl_DString *\fIoptionValue\fR); .CE .PP \fIOptionName\fR is the name of an option supported by this type of channel. If the option name is not NULL, the function stores its current value, as a string, in the Tcl dynamic string \fIoptionValue\fR. If \fIoptionName\fR is NULL, the function stores in \fIoptionValue\fR an alternating list of all supported options and their current values. On success, the function returns \fBTCL_OK\fR. It should call \fBTcl_BadChannelOption\fR which itself returns \fBTCL_ERROR\fR if the \fIoptionName\fR is unrecognized. If a system call error occurs, the function should leave an error message in the result of \fIinterp\fR if \fIinterp\fR is not NULL. The function should also call \fBTcl_SetErrno\fR to store an appropriate POSIX error code. .PP Some options are handled by the generic code and this function is never called to retrieve their value, e.g. \fB-blockmode\fR. Other options are specific to each channel type and the \fIgetOptionProc\fR procedure of the channel driver will get called to implement them. The \fIgetOptionProc\fR field can be NULL, which indicates that this channel type supports no type specific options. .PP This value can be retrieved with \fBTcl_ChannelGetOptionProc\fR, which returns a pointer to the function. .SH WATCHPROC .PP The \fIwatchProc\fR field contains the address of a function called by the generic layer to initialize the event notification mechanism to notice events of interest on this channel. \fIWatchProc\fR should match the following prototype: .PP .CS typedef void Tcl_DriverWatchProc( ClientData \fIinstanceData\fR, int \fImask\fR); .CE .PP The \fIinstanceData\fR is the same as the value passed to \fBTcl_CreateChannel\fR when this channel was created. The \fImask\fR argument is an OR-ed combination of \fBTCL_READABLE\fR, \fBTCL_WRITABLE\fR and \fBTCL_EXCEPTION\fR; it indicates events the caller is interested in noticing on this channel. .PP The function should initialize device type specific mechanisms to notice when an event of interest is present on the channel. When one or more of the designated events occurs on the channel, the channel driver is responsible for calling \fBTcl_NotifyChannel\fR to inform the generic channel module. The driver should take care not to starve other channel drivers or sources of callbacks by invoking Tcl_NotifyChannel too frequently. Fairness can be insured by using the Tcl event queue to allow the channel event to be scheduled in sequence with other events. See the description of \fBTcl_QueueEvent\fR for details on how to queue an event. .PP This value can be retrieved with \fBTcl_ChannelWatchProc\fR, which returns a pointer to the function. .SH GETHANDLEPROC .PP The \fIgetHandleProc\fR field contains the address of a function called by the generic layer to retrieve a device-specific handle from the channel. \fIGetHandleProc\fR should match the following prototype: .PP .CS typedef int Tcl_DriverGetHandleProc( ClientData \fIinstanceData\fR, int \fIdirection\fR, ClientData *\fIhandlePtr\fR); .CE .PP \fIInstanceData\fR is the same as the value passed to \fBTcl_CreateChannel\fR when this channel was created. The \fIdirection\fR argument is either \fBTCL_READABLE\fR to retrieve the handle used for input, or \fBTCL_WRITABLE\fR to retrieve the handle used for output. .PP If the channel implementation has device-specific handles, the function should retrieve the appropriate handle associated with the channel, according the \fIdirection\fR argument. The handle should be stored in the location referred to by \fIhandlePtr\fR, and \fBTCL_OK\fR should be returned. If the channel is not open for the specified direction, or if the channel implementation does not use device handles, the function should return \fBTCL_ERROR\fR. .PP This value can be retrieved with \fBTcl_ChannelGetHandleProc\fR, which returns a pointer to the function. .SH FLUSHPROC .PP The \fIflushProc\fR field is currently reserved for future use. It should be set to NULL. \fIFlushProc\fR should match the following prototype: .PP .CS typedef int Tcl_DriverFlushProc( ClientData \fIinstanceData\fR); .CE .PP This value can be retrieved with \fBTcl_ChannelFlushProc\fR, which returns a pointer to the function. .SH HANDLERPROC .PP The \fIhandlerProc\fR field contains the address of a function called by the generic layer to notify the channel that an event occurred. It should be defined for stacked channel drivers that wish to be notified of events that occur on the underlying (stacked) channel. \fIHandlerProc\fR should match the following prototype: .PP .CS typedef int Tcl_DriverHandlerProc( ClientData \fIinstanceData\fR, int \fIinterestMask\fR); .CE .PP \fIInstanceData\fR is the same as the value passed to \fBTcl_CreateChannel\fR when this channel was created. The \fIinterestMask\fR is an OR-ed combination of \fBTCL_READABLE\fR or \fBTCL_WRITABLE\fR; it indicates what type of event occurred on this channel. .PP This value can be retrieved with \fBTcl_ChannelHandlerProc\fR, which returns a pointer to the function. .VS 8.4 .SH "THREADACTIONPROC" .PP The \fIthreadActionProc\fR field contains the address of the function called by the generic layer when a channel is created, closed, or going to move to a different thread, i.e. whenever thread-specific driver state might have to initialized or updated. It can be NULL. The action \fITCL_CHANNEL_THREAD_REMOVE\fR is used to notify the driver that it should update or remove any thread-specific data it might be maintaining for the channel. .PP The action \fITCL_CHANNEL_THREAD_INSERT\fR is used to notify the driver that it should update or initialize any thread-specific data it might be maintaining using the calling thread as the associate. See \fBTcl_CutChannel\fR and \fBTcl_SpliceChannel\fR for more detail. .PP .CS typedef void Tcl_DriverThreadActionProc( ClientData \fIinstanceData\fR, int \fIaction\fR); .CE .PP \fIInstanceData\fR is the same as the value passed to \fBTcl_CreateChannel\fR when this channel was created. .PP These values can be retrieved with \fBTcl_ChannelThreadActionProc\fR, which returns a pointer to the function. .VE 8.4 .SH TCL_BADCHANNELOPTION .PP This procedure generates a "bad option" error message in an (optional) interpreter. It is used by channel drivers when a invalid Set/Get option is requested. Its purpose is to concatenate the generic options list to the specific ones and factorize the generic options error message string. .PP It always return \fBTCL_ERROR\fR .PP An error message is generated in \fIinterp\fR's result object to indicate that a command was invoked with the a bad option The message has the form .CS bad option "blah": should be one of <...generic options...>+<...specific options...> so you get for instance: bad option "-blah": should be one of -blocking, -buffering, -buffersize, -eofchar, -translation, -peername, or -sockname when called with \fIoptionList\fR="peername sockname" .CE ``blah'' is the \fIoptionName\fR argument and ``'' is a space separated list of specific option words. The function takes good care of inserting minus signs before each option, commas after, and an ``or'' before the last option. .SH "OLD CHANNEL TYPES" The original (8.3.1 and below) \fBTcl_ChannelType\fR structure contains the following fields: .PP .CS typedef struct Tcl_ChannelType { char *\fItypeName\fR; Tcl_DriverBlockModeProc *\fIblockModeProc\fR; Tcl_DriverCloseProc *\fIcloseProc\fR; Tcl_DriverInputProc *\fIinputProc\fR; Tcl_DriverOutputProc *\fIoutputProc\fR; Tcl_DriverSeekProc *\fIseekProc\fR; Tcl_DriverSetOptionProc *\fIsetOptionProc\fR; Tcl_DriverGetOptionProc *\fIgetOptionProc\fR; Tcl_DriverWatchProc *\fIwatchProc\fR; Tcl_DriverGetHandleProc *\fIgetHandleProc\fR; Tcl_DriverClose2Proc *\fIclose2Proc\fR; } Tcl_ChannelType; .CE .PP It is still possible to create channel with the above structure. The internal channel code will determine the version. It is imperative to use the new \fBTcl_ChannelType\fR structure if you are creating a stacked channel driver, due to problems with the earlier stacked channel implementation (in 8.2.0 to 8.3.1). .PP .VS 8.4 Prior to 8.4.0 (i.e. during the later releases of 8.3 and early part of the 8.4 development cycle) the \fBTcl_ChannelType\fR structure contained the following fields: .PP .CS typedef struct Tcl_ChannelType { char *\fItypeName\fR; Tcl_ChannelTypeVersion \fIversion\fR; Tcl_DriverCloseProc *\fIcloseProc\fR; Tcl_DriverInputProc *\fIinputProc\fR; Tcl_DriverOutputProc *\fIoutputProc\fR; Tcl_DriverSeekProc *\fIseekProc\fR; Tcl_DriverSetOptionProc *\fIsetOptionProc\fR; Tcl_DriverGetOptionProc *\fIgetOptionProc\fR; Tcl_DriverWatchProc *\fIwatchProc\fR; Tcl_DriverGetHandleProc *\fIgetHandleProc\fR; Tcl_DriverClose2Proc *\fIclose2Proc\fR; Tcl_DriverBlockModeProc *\fIblockModeProc\fR; Tcl_DriverFlushProc *\fIflushProc\fR; Tcl_DriverHandlerProc *\fIhandlerProc\fR; } Tcl_ChannelType; .CE .PP When the above structure is registered as a channel type, the \fIversion\fR field should always be \fBTCL_CHANNEL_VERSION_2\fR. .VE 8.4 .SH "SEE ALSO" Tcl_Close(3), Tcl_OpenFileChannel(3), Tcl_SetErrno(3), Tcl_QueueEvent(3), Tcl_StackChannel(3), Tcl_GetStdChannel(3) .SH KEYWORDS blocking, channel driver, channel registration, channel type, nonblocking tcl8.4.20/doc/pid.n0000644003604700454610000000276511737050674012431 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH pid n 7.0 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME pid \- Retrieve process identifiers .SH SYNOPSIS \fBpid \fR?\fIfileId\fR? .BE .SH DESCRIPTION .PP If the \fIfileId\fR argument is given then it should normally refer to a process pipeline created with the \fBopen\fR command. In this case the \fBpid\fR command will return a list whose elements are the process identifiers of all the processes in the pipeline, in order. The list will be empty if \fIfileId\fR refers to an open file that isn't a process pipeline. If no \fIfileId\fR argument is given then \fBpid\fR returns the process identifier of the current process. All process identifiers are returned as decimal strings. .SH EXAMPLE Print process information about the processes in a pipeline using the SysV \fBps\fR program before reading the output of that pipeline: .PP .CS set pipeline [open "| zcat somefile.gz | grep foobar | sort -u"] # Print process information exec ps -fp [\fBpid\fR $pipeline] >@stdout # Print a separator and then the output of the pipeline puts [string repeat - 70] puts [read $pipeline] close $pipeline .CE .SH "SEE ALSO" exec(n), open(n) .SH KEYWORDS file, pipeline, process identifier tcl8.4.20/doc/library.n0000644003604700454610000003337211737050674013317 0ustar dgp771div'\" '\" Copyright (c) 1991-1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH library n "8.0" Tcl "Tcl Built-In Commands" .BS .SH NAME auto_execok, auto_import, auto_load, auto_mkindex, auto_mkindex_old, auto_qualify, auto_reset, tcl_findLibrary, parray, tcl_endOfWord, tcl_startOfNextWord, tcl_startOfPreviousWord, tcl_wordBreakAfter, tcl_wordBreakBefore \- standard library of Tcl procedures .SH SYNOPSIS .nf \fBauto_execok \fIcmd\fR \fBauto_import \fIpattern\fR \fBauto_load \fIcmd\fR \fBauto_mkindex \fIdir pattern pattern ...\fR \fBauto_mkindex_old \fIdir pattern pattern ...\fR \fBauto_qualify \fIcommand namespace\fR \fBauto_reset\fR \fBtcl_findLibrary \fIbasename version patch initScript enVarName varName\fR \fBparray \fIarrayName\fR .VS \fBtcl_endOfWord \fIstr start\fR \fBtcl_startOfNextWord \fIstr start\fR \fBtcl_startOfPreviousWord \fIstr start\fR \fBtcl_wordBreakAfter \fIstr start\fR \fBtcl_wordBreakBefore \fIstr start\fR .VE .BE .SH INTRODUCTION .PP Tcl includes a library of Tcl procedures for commonly-needed functions. The procedures defined in the Tcl library are generic ones suitable for use by many different applications. The location of the Tcl library is returned by the \fBinfo library\fR command. In addition to the Tcl library, each application will normally have its own library of support procedures as well; the location of this library is normally given by the value of the \fB$\fIapp\fB_library\fR global variable, where \fIapp\fR is the name of the application. For example, the location of the Tk library is kept in the variable \fB$tk_library\fR. .PP To access the procedures in the Tcl library, an application should source the file \fBinit.tcl\fR in the library, for example with the Tcl command .CS \fBsource [file join [info library] init.tcl]\fR .CE If the library procedure \fBTcl_Init\fR is invoked from an application's \fBTcl_AppInit\fR procedure, this happens automatically. The code in \fBinit.tcl\fR will define the \fBunknown\fR procedure and arrange for the other procedures to be loaded on-demand using the auto-load mechanism defined below. .SH "COMMAND PROCEDURES" .PP The following procedures are provided in the Tcl library: .TP \fBauto_execok \fIcmd\fR Determines whether there is an executable file or shell builtin by the name \fIcmd\fR. If so, it returns a list of arguments to be passed to \fBexec\fR to execute the executable file or shell builtin named by \fIcmd\fR. If not, it returns an empty string. This command examines the directories in the current search path (given by the PATH environment variable) in its search for an executable file named \fIcmd\fR. On Windows platforms, the search is expanded with the same directories and file extensions as used by \fBexec\fR. \fBAuto_exec\fR remembers information about previous searches in an array named \fBauto_execs\fR; this avoids the path search in future calls for the same \fIcmd\fR. The command \fBauto_reset\fR may be used to force \fBauto_execok\fR to forget its cached information. .TP \fBauto_import \fIpattern\fR \fBAuto_import\fR is invoked during \fBnamespace import\fR to see if the imported commands specified by \fIpattern\fR reside in an autoloaded library. If so, the commands are loaded so that they will be available to the interpreter for creating the import links. If the commands do not reside in an autoloaded library, \fBauto_import\fR does nothing. The pattern matching is performed according to the matching rules of \fBnamespace import\fR. .TP \fBauto_load \fIcmd\fR This command attempts to load the definition for a Tcl command named \fIcmd\fR. To do this, it searches an \fIauto-load path\fR, which is a list of one or more directories. The auto-load path is given by the global variable \fB$auto_path\fR if it exists. If there is no \fB$auto_path\fR variable, then the TCLLIBPATH environment variable is used, if it exists. Otherwise the auto-load path consists of just the Tcl library directory. Within each directory in the auto-load path there must be a file \fBtclIndex\fR that describes one or more commands defined in that directory and a script to evaluate to load each of the commands. The \fBtclIndex\fR file should be generated with the \fBauto_mkindex\fR command. If \fIcmd\fR is found in an index file, then the appropriate script is evaluated to create the command. The \fBauto_load\fR command returns 1 if \fIcmd\fR was successfully created. The command returns 0 if there was no index entry for \fIcmd\fR or if the script didn't actually define \fIcmd\fR (e.g. because index information is out of date). If an error occurs while processing the script, then that error is returned. \fBAuto_load\fR only reads the index information once and saves it in the array \fBauto_index\fR; future calls to \fBauto_load\fR check for \fIcmd\fR in the array rather than re-reading the index files. The cached index information may be deleted with the command \fBauto_reset\fR. This will force the next \fBauto_load\fR command to reload the index database from disk. .TP \fBauto_mkindex \fIdir pattern pattern ...\fR Generates an index suitable for use by \fBauto_load\fR. The command searches \fIdir\fR for all files whose names match any of the \fIpattern\fR arguments (matching is done with the \fBglob\fR command), generates an index of all the Tcl command procedures defined in all the matching files, and stores the index information in a file named \fBtclIndex\fR in \fIdir\fR. If no pattern is given a pattern of \fB*.tcl\fR will be assumed. For example, the command .RS .CS \fBauto_mkindex foo *.tcl\fR .CE .LP will read all the \fB.tcl\fR files in subdirectory \fBfoo\fR and generate a new index file \fBfoo/tclIndex\fR. .PP \fBAuto_mkindex\fR parses the Tcl scripts by sourcing them into a slave interpreter and monitoring the proc and namespace commands that are executed. Extensions can use the (undocumented) auto_mkindex_parser package to register other commands that can contribute to the auto_load index. You will have to read through auto.tcl to see how this works. .PP \fBAuto_mkindex_old\fR parses the Tcl scripts in a relatively unsophisticated way: if any line contains the word \fBproc\fR as its first characters then it is assumed to be a procedure definition and the next word of the line is taken as the procedure's name. Procedure definitions that don't appear in this way (e.g. they have spaces before the \fBproc\fR) will not be indexed. If your script contains "dangerous" code, such as global initialization code or procedure names with special characters like \fB$\fR, \fB*\fR, \fB[\fR or \fB]\fR, you are safer using auto_mkindex_old. .RE .TP \fBauto_reset\fR Destroys all the information cached by \fBauto_execok\fR and \fBauto_load\fR. This information will be re-read from disk the next time it is needed. \fBAuto_reset\fR also deletes any procedures listed in the auto-load index, so that fresh copies of them will be loaded the next time that they're used. .TP \fBauto_qualify \fIcommand namespace\fR Computes a list of fully qualified names for \fIcommand\fR. This list mirrors the path a standard Tcl interpreter follows for command lookups: first it looks for the command in the current namespace, and then in the global namespace. Accordingly, if \fIcommand\fR is relative and \fInamespace\fR is not \fB::\fR, the list returned has two elements: \fIcommand\fR scoped by \fInamespace\fR, as if it were a command in the \fInamespace\fR namespace; and \fIcommand\fR as if it were a command in the global namespace. Otherwise, if either \fIcommand\fR is absolute (it begins with \fB::\fR), or \fInamespace\fR is \fB::\fR, the list contains only \fIcommand\fR as if it were a command in the global namespace. .RS .PP \fBAuto_qualify\fR is used by the auto-loading facilities in Tcl, both for producing auto-loading indexes such as \fIpkgIndex.tcl\fR, and for performing the actual auto-loading of functions at runtime. .RE .TP \fBtcl_findLibrary \fIbasename version patch initScript enVarName varName\fR This is a standard search procedure for use by extensions during their initialization. They call this procedure to look for their script library in several standard directories. The last component of the name of the library directory is normally \fIbasenameversion\fP (e.g., tk8.0), but it might be "library" when in the build hierarchies. The \fIinitScript\fR file will be sourced into the interpreter once it is found. The directory in which this file is found is stored into the global variable \fIvarName\fP. If this variable is already defined (e.g., by C code during application initialization) then no searching is done. Otherwise the search looks in these directories: the directory named by the environment variable \fIenVarName\fP; relative to the Tcl library directory; relative to the executable file in the standard installation bin or bin/\fIarch\fP directory; relative to the executable file in the current build tree; relative to the executable file in a parallel build tree. .TP \fBparray \fIarrayName\fR Prints on standard output the names and values of all the elements in the array \fIarrayName\fR. \fBArrayName\fR must be an array accessible to the caller of \fBparray\fR. It may be either local or global. .TP \fBtcl_endOfWord \fIstr start\fR .VS Returns the index of the first end-of-word location that occurs after a starting index \fIstart\fR in the string \fIstr\fR. An end-of-word location is defined to be the first non-word character following the first word character after the starting point. Returns -1 if there are no more end-of-word locations after the starting point. See the description of \fBtcl_wordchars\fR and \fBtcl_nonwordchars\fR below for more details on how Tcl determines which characters are word characters. .TP \fBtcl_startOfNextWord \fIstr start\fR Returns the index of the first start-of-word location that occurs after a starting index \fIstart\fR in the string \fIstr\fR. A start-of-word location is defined to be the first word character following a non-word character. Returns \-1 if there are no more start-of-word locations after the starting point. .TP \fBtcl_startOfPreviousWord \fIstr start\fR Returns the index of the first start-of-word location that occurs before a starting index \fIstart\fR in the string \fIstr\fR. Returns \-1 if there are no more start-of-word locations before the starting point. .TP \fBtcl_wordBreakAfter \fIstr start\fR Returns the index of the first word boundary after the starting index \fIstart\fR in the string \fIstr\fR. Returns \-1 if there are no more boundaries after the starting point in the given string. The index returned refers to the second character of the pair that comprises a boundary. .TP \fBtcl_wordBreakBefore \fIstr start\fR Returns the index of the first word boundary before the starting index \fIstart\fR in the string \fIstr\fR. Returns \-1 if there are no more boundaries before the starting point in the given string. The index returned refers to the second character of the pair that comprises a boundary. .VE .SH "VARIABLES" .PP The following global variables are defined or used by the procedures in the Tcl library: .TP \fBauto_execs\fR Used by \fBauto_execok\fR to record information about whether particular commands exist as executable files. .TP \fBauto_index\fR Used by \fBauto_load\fR to save the index information read from disk. .TP \fBauto_noexec\fR If set to any value, then \fBunknown\fR will not attempt to auto-exec any commands. .TP \fBauto_noload\fR If set to any value, then \fBunknown\fR will not attempt to auto-load any commands. .TP \fBauto_path\fR If set, then it must contain a valid Tcl list giving directories to search during auto-load operations. This variable is initialized during startup to contain, in order: the directories listed in the TCLLIBPATH environment variable, the directory named by the $tcl_library variable, the parent directory of $tcl_library, the directories listed in the $tcl_pkgPath variable. .TP \fBenv(TCL_LIBRARY)\fR If set, then it specifies the location of the directory containing library scripts (the value of this variable will be assigned to the \fBtcl_library\fR variable and therefore returned by the command \fBinfo library\fR). If this variable isn't set then a default value is used. .TP \fBenv(TCLLIBPATH)\fR If set, then it must contain a valid Tcl list giving directories to search during auto-load operations. Directories must be specified in Tcl format, using "/" as the path separator, regardless of platform. This variable is only used when initializing the \fBauto_path\fR variable. .TP \fBtcl_nonwordchars\fR .VS This variable contains a regular expression that is used by routines like \fBtcl_endOfWord\fR to identify whether a character is part of a word or not. If the pattern matches a character, the character is considered to be a non-word character. On Windows platforms, spaces, tabs, and newlines are considered non-word characters. Under Unix, everything but numbers, letters and underscores are considered non-word characters. .TP \fBtcl_wordchars\fR This variable contains a regular expression that is used by routines like \fBtcl_endOfWord\fR to identify whether a character is part of a word or not. If the pattern matches a character, the character is considered to be a word character. On Windows platforms, words are comprised of any character that is not a space, tab, or newline. Under Unix, words are comprised of numbers, letters or underscores. .VE .TP \fBunknown_pending\fR Used by \fBunknown\fR to record the command(s) for which it is searching. It is used to detect errors where \fBunknown\fR recurses on itself infinitely. The variable is unset before \fBunknown\fR returns. .SH "SEE ALSO" info(n), re_syntax(n) .SH KEYWORDS auto-exec, auto-load, library, unknown, word, whitespace tcl8.4.20/doc/lsort.n0000644003604700454610000001272711737050674013017 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" Copyright (c) 1999 Scriptics Corporation '\" Copyright (c) 2001 Kevin B. Kenny. All rights reserved. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH lsort n 8.3 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME lsort \- Sort the elements of a list .SH SYNOPSIS \fBlsort \fR?\fIoptions\fR? \fIlist\fR .BE .SH DESCRIPTION .PP This command sorts the elements of \fIlist\fR, returning a new list in sorted order. The implementation of the \fBlsort\fR command uses the merge\-sort algorithm which is a stable sort that has O(n log n) performance characteristics. .PP By default ASCII sorting is used with the result returned in increasing order. However, any of the following options may be specified before \fIlist\fR to control the sorting process (unique abbreviations are accepted): .TP 20 \fB\-ascii\fR Use string comparison with Unicode code-point collation order (the name is for backward-compatibility reasons.) This is the default. .TP 20 \fB\-dictionary\fR Use dictionary-style comparison. This is the same as \fB\-ascii\fR except (a) case is ignored except as a tie-breaker and (b) if two strings contain embedded numbers, the numbers compare as integers, not characters. For example, in \fB\-dictionary\fR mode, \fBbigBoy\fR sorts between \fBbigbang\fR and \fBbigboy\fR, and \fBx10y\fR sorts between \fBx9y\fR and \fBx11y\fR. .TP 20 \fB\-integer\fR Convert list elements to integers and use integer comparison. .TP 20 \fB\-real\fR Convert list elements to floating-point values and use floating comparison. .TP 20 \fB\-command\0\fIcommand\fR Use \fIcommand\fR as a comparison command. To compare two elements, evaluate a Tcl script consisting of \fIcommand\fR with the two elements appended as additional arguments. The script should return an integer less than, equal to, or greater than zero if the first element is to be considered less than, equal to, or greater than the second, respectively. .TP 20 \fB\-increasing\fR Sort the list in increasing order (``smallest'' items first). This is the default. .TP 20 \fB\-decreasing\fR Sort the list in decreasing order (``largest'' items first). .TP 20 \fB\-index\0\fIindex\fR If this option is specified, each of the elements of \fIlist\fR must itself be a proper Tcl sublist. Instead of sorting based on whole sublists, \fBlsort\fR will extract the \fIindex\fR'th element from each sublist and sort based on the given element. The keyword \fBend\fP is allowed for the \fIindex\fP to sort on the last sublist element, .VS 8.4 and \fBend-\fIindex\fR sorts on a sublist element offset from the end. .VE For example, .RS .CS lsort -integer -index 1 {{First 24} {Second 18} {Third 30}} .CE returns \fB{Second 18} {First 24} {Third 30}\fR, and .VS 8.4 '\" '\" This example is from the test suite! '\" .CS lsort -index end-1 {{a 1 e i} {b 2 3 f g} {c 4 5 6 d h}} .CE returns \fB{c 4 5 6 d h} {a 1 e i} {b 2 3 f g}\fR. .VE This option is much more efficient than using \fB\-command\fR to achieve the same effect. .RE .TP 20 \fB\-unique\fR If this option is specified, then only the last set of duplicate elements found in the list will be retained. Note that duplicates are determined relative to the comparison used in the sort. Thus if \fI-index 0\fR is used, \fB{1 a}\fR and \fB{1 b}\fR would be considered duplicates and only the second element, \fB{1 b}\fR, would be retained. .SH "NOTES" .PP The options to \fBlsort\fR only control what sort of comparison is used, and do not necessarily constrain what the values themselves actually are. This distinction is only noticeable when the list to be sorted has fewer than two elements. .PP The \fBlsort\fR command is reentrant, meaning it is safe to use as part of the implementation of a command used in the \fB\-command\fR option. .SH "EXAMPLES" .PP Sorting a list using ASCII sorting: .CS % \fBlsort\fR {a10 B2 b1 a1 a2} B2 a1 a10 a2 b1 .CE .PP Sorting a list using Dictionary sorting: .CS % \fBlsort\fR -dictionary {a10 B2 b1 a1 a2} a1 a2 a10 b1 B2 .CE .PP Sorting lists of integers: .CS % \fBlsort\fR -integer {5 3 1 2 11 4} 1 2 3 4 5 11 % \fBlsort\fR -integer {1 2 0x5 7 0 4 -1} -1 0 1 2 4 0x5 7 .CE .PP Sorting lists of floating-point numbers: .CS % \fBlsort\fR -real {5 3 1 2 11 4} 1 2 3 4 5 11 % \fBlsort\fR -real {.5 0.07e1 0.4 6e-1} 0.4 .5 6e-1 0.07e1 .CE .PP Sorting using indices: .CS % # Note the space character before the c % \fBlsort\fR {{a 5} { c 3} {b 4} {e 1} {d 2}} { c 3} {a 5} {b 4} {d 2} {e 1} % \fBlsort\fR -index 0 {{a 5} { c 3} {b 4} {e 1} {d 2}} {a 5} {b 4} { c 3} {d 2} {e 1} % \fBlsort\fR -index 1 {{a 5} { c 3} {b 4} {e 1} {d 2}} {e 1} {d 2} { c 3} {b 4} {a 5} .CE .PP Stripping duplicate values using sorting: .CS % \fBlsort\fR -unique {a b c a b c a b c} a b c .CE .PP More complex sorting using a comparison function: .CS % proc compare {a b} { set a0 [lindex $a 0] set b0 [lindex $b 0] if {$a0 < $b0} { return -1 } elseif {$a0 > $b0} { return 1 } return [string compare [lindex $a 1] [lindex $b 1]] } % \fBlsort\fR -command compare \\ {{3 apple} {0x2 carrot} {1 dingo} {2 banana}} {1 dingo} {2 banana} {0x2 carrot} {3 apple} .CE .SH "SEE ALSO" .VS 8.4 list(n), lappend(n), lindex(n), linsert(n), llength(n), lsearch(n), lset(n), lrange(n), lreplace(n) .VE .SH KEYWORDS element, list, order, sort tcl8.4.20/doc/FileSystem.30000644003604700454610000016315712052456743013647 0ustar dgp771div'\" '\" Copyright (c) 2001 Vincent Darley '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Filesystem 3 8.4 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_FSRegister, Tcl_FSUnregister, Tcl_FSData, Tcl_FSMountsChanged, Tcl_FSGetFileSystemForPath, Tcl_FSGetPathType, Tcl_FSCopyFile, Tcl_FSCopyDirectory, Tcl_FSCreateDirectory, Tcl_FSDeleteFile, Tcl_FSRemoveDirectory, Tcl_FSRenameFile, Tcl_FSListVolumes, Tcl_FSEvalFile, Tcl_FSLoadFile, Tcl_FSMatchInDirectory, Tcl_FSLink, Tcl_FSLstat, Tcl_FSUtime, Tcl_FSFileAttrsGet, Tcl_FSFileAttrsSet, Tcl_FSFileAttrStrings, Tcl_FSStat, Tcl_FSAccess, Tcl_FSOpenFileChannel, Tcl_FSGetCwd, Tcl_FSChdir, Tcl_FSPathSeparator, Tcl_FSJoinPath, Tcl_FSSplitPath, Tcl_FSEqualPaths, Tcl_FSGetNormalizedPath, Tcl_FSJoinToPath, Tcl_FSConvertToPathType, Tcl_FSGetInternalRep, Tcl_FSGetTranslatedPath, Tcl_FSGetTranslatedStringPath, Tcl_FSNewNativePath, Tcl_FSGetNativePath, Tcl_FSFileSystemInfo, Tcl_AllocStatBuf \- procedures to interact with any filesystem .SH SYNOPSIS .nf \fB#include \fR .sp int \fBTcl_FSRegister\fR(\fIclientData, fsPtr\fR) .sp int \fBTcl_FSUnregister\fR(\fIfsPtr\fR) .sp ClientData \fBTcl_FSData\fR(\fIfsPtr\fR) .sp void \fBTcl_FSMountsChanged\fR(\fIfsPtr\fR) .sp Tcl_Filesystem* \fBTcl_FSGetFileSystemForPath\fR(\fIpathObjPtr\fR) .sp Tcl_PathType \fBTcl_FSGetPathType\fR(\fIpathObjPtr\fR) .sp int \fBTcl_FSCopyFile\fR(\fIsrcPathPtr, destPathPtr\fR) .sp int \fBTcl_FSCopyDirectory\fR(\fIsrcPathPtr, destPathPtr, errorPtr\fR) .sp int \fBTcl_FSCreateDirectory\fR(\fIpathPtr\fR) .sp int \fBTcl_FSDeleteFile\fR(\fIpathPtr\fR) .sp int \fBTcl_FSRemoveDirectory\fR(\fIpathPtr, int recursive, errorPtr\fR) .sp int \fBTcl_FSRenameFile\fR(\fIsrcPathPtr, destPathPtr\fR) .sp Tcl_Obj* \fBTcl_FSListVolumes\fR(\fIvoid\fR) .sp int \fBTcl_FSEvalFile\fR(\fIinterp, pathPtr\fR) .sp int \fBTcl_FSLoadFile\fR(\fIinterp, pathPtr, sym1, sym2, proc1Ptr, proc2Ptr, handlePtr, unloadProcPtr\fR) .sp int \fBTcl_FSMatchInDirectory\fR(\fIinterp, result, pathPtr, pattern, types\fR) .sp Tcl_Obj* \fBTcl_FSLink\fR(\fIlinkNamePtr, toPtr, linkAction\fR) .sp int \fBTcl_FSLstat\fR(\fIpathPtr, statPtr\fR) .sp int \fBTcl_FSUtime\fR(\fIpathPtr, tval\fR) .sp int \fBTcl_FSFileAttrsGet\fR(\fIinterp, int index, pathPtr, objPtrRef\fR) .sp int \fBTcl_FSFileAttrsSet\fR(\fIinterp, int index, pathPtr, Tcl_Obj *objPtr\fR) .sp CONST char** \fBTcl_FSFileAttrStrings\fR(\fIpathPtr, objPtrRef\fR) .sp int \fBTcl_FSStat\fR(\fIpathPtr, statPtr\fR) .sp int \fBTcl_FSAccess\fR(\fIpathPtr, mode\fR) .sp Tcl_Channel \fBTcl_FSOpenFileChannel\fR(\fIinterp, pathPtr, modeString, permissions\fR) .sp Tcl_Obj* \fBTcl_FSGetCwd\fR(\fIinterp\fR) .sp int \fBTcl_FSChdir\fR(\fIpathPtr\fR) .sp Tcl_Obj* \fBTcl_FSPathSeparator\fR(\fIpathPtr\fR) .sp Tcl_Obj* \fBTcl_FSJoinPath\fR(\fIlistObj, elements\fR) .sp Tcl_Obj* \fBTcl_FSSplitPath\fR(\fIpathPtr, lenPtr\fR) .sp int \fBTcl_FSEqualPaths\fR(\fIfirstPtr, secondPtr\fR) .sp Tcl_Obj* \fBTcl_FSGetNormalizedPath\fR(\fIinterp, pathPtr\fR) .sp Tcl_Obj* \fBTcl_FSJoinToPath\fR(\fIbasePtr, objc, objv\fR) .sp int \fBTcl_FSConvertToPathType\fR(\fIinterp, pathPtr\fR) .sp ClientData \fBTcl_FSGetInternalRep\fR(\fIpathPtr, fsPtr\fR) .sp Tcl_Obj* \fBTcl_FSGetTranslatedPath\fR(\fIinterp, pathPtr\fR) .sp CONST char* \fBTcl_FSGetTranslatedStringPath\fR(\fIinterp, pathPtr\fR) .sp Tcl_Obj* \fBTcl_FSNewNativePath\fR(\fIfsPtr, clientData\fR) .sp CONST char* \fBTcl_FSGetNativePath\fR(\fIpathPtr\fR) .sp Tcl_Obj* \fBTcl_FSFileSystemInfo\fR(\fIpathPtr\fR) .sp Tcl_StatBuf* \fBTcl_AllocStatBuf\fR() .SH ARGUMENTS .AS Tcl_Filesystem *fsPtr in .AP Tcl_Filesystem *fsPtr in Points to a structure containing the addresses of procedures that can be called to perform the various filesystem operations. .AP Tcl_Obj *pathPtr in The path represented by this object is used for the operation in question. If the object does not already have an internal \fBpath\fR representation, it will be converted to have one. .AP Tcl_Obj *srcPathPtr in As for \fBpathPtr\fR, but used for the source file for a copy or rename operation. .AP Tcl_Obj *destPathPtr in As for \fBpathPtr\fR, but used for the destination filename for a copy or rename operation. .AP "CONST char" *pattern in Only files or directories matching this pattern will be returned by \fBTcl_FSMatchInDirectory\fR. .AP GlobTypeData *types in Only files or directories matching the type descriptions contained in this structure will be returned by \fBTcl_FSMatchInDirectory\fR. It is very important that the 'directory' flag is properly handled. This parameter may be NULL. .AP Tcl_Interp *interp in Interpreter to use either for results, evaluation, or reporting error messages. .AP ClientData clientData in The native description of the path object to create. .AP Tcl_Obj *firstPtr in The first of two path objects to compare. The object may be converted to \fBpath\fR type. .AP Tcl_Obj *secondPtr in The second of two path objects to compare. The object may be converted to \fBpath\fR type. .AP Tcl_Obj *listObj in The list of path elements to operate on with a \fBjoin\fR operation. .AP int elements in If non-negative, the number of elements in the listObj which should be joined together. If negative, then all elements are joined. .AP Tcl_Obj **errorPtr out In the case of an error, filled with an object containing the name of the file which caused an error in the various copy/rename operations. .AP Tcl_Obj **objPtrRef out Filled with an object containing the result of the operation. .AP Tcl_Obj *result out Pre-allocated object in which to store (by lappending) the list of files or directories which are successfully matched in \fBTcl_FSMatchInDirectory\fR. .AP int mode in Mask consisting of one or more of R_OK, W_OK, X_OK and F_OK. R_OK, W_OK and X_OK request checking whether the file exists and has read, write and execute permissions, respectively. F_OK just requests checking for the existence of the file. .AP Tcl_StatBuf *statPtr out The structure that contains the result of a stat or lstat operation. .AP "CONST char" *sym1 in Name of a procedure to look up in the file's symbol table .AP "CONST char" *sym2 in Name of a procedure to look up in the file's symbol table .AP Tcl_PackageInitProc **proc1Ptr out Filled with the init function for this code. .AP Tcl_PackageInitProc **proc2Ptr out Filled with the safe-init function for this code. .AP Tcl_LoadHandle *handlePtr out Filled with an abstract token representing the loaded file. .AP ClientData *clientDataPtr out Filled with the clientData value to pass to this code's unload function when it is called. .AP TclfsUnloadFileProc_ **unloadProcPtr out Filled with the function to use to unload this piece of code. .AP utimbuf *tval in The access and modification times in this structure are read and used to set those values for a given file. .AP "CONST char" *modeString in Specifies how the file is to be accessed. May have any of the values allowed for the \fImode\fR argument to the Tcl \fBopen\fR command. .AP int permissions in POSIX-style permission flags such as 0644. If a new file is created, these permissions will be set on the created file. .AP int *lenPtr out If non-NULL, filled with the number of elements in the split path. .AP Tcl_Obj *basePtr in The base path on to which to join the given elements. May be NULL. .AP int objc in The number of elements in \fIobjv\fR. .AP "Tcl_Obj *CONST" objv[] in The elements to join to the given base path. .BE .SH DESCRIPTION .PP There are several reasons for calling the \fBTcl_FS...\fR functions rather than calling system level functions like \fBaccess\fR and \fBstat\fR directly. First, they will work cross-platform, so an extension which calls them should work unmodified on Unix, MacOS and Windows. Second, the Windows implementation of some of these functions fixes some bugs in the system level calls. Third, these function calls deal with any 'Utf to platform-native' path conversions which may be required (and may cache the results of such conversions for greater efficiency on subsequent calls). Fourth, and perhaps most importantly, all of these functions are 'virtual filesystem aware'. Any virtual filesystem which has been registered (through \fBTcl_FSRegister\fR) may reroute file access to alternative media or access methods. This means that all of these functions (and therefore the corresponding \fBfile\fR, \fBglob\fR, \fBpwd\fR, \fBcd\fR, \fBopen\fR, etc. Tcl commands) may be operate on 'files' which are not native files in the native filesystem. This also means that any Tcl extension which accesses the filesystem through this API is automatically 'virtual filesystem aware'. Of course, if an extension accesses the native filesystem directly (through platform-specific APIs, for example), then Tcl cannot intercept such calls. .PP If appropriate vfs's have been registered, the 'files' may, to give two examples, be remote (e.g. situated on a remote ftp server) or archived (e.g. lying inside a .zip archive). Such registered filesystems provide a lookup table of functions to implement all or some of the functionality listed here. Finally, the \fBTcl_FSStat\fR and \fBTcl_FSLstat\fR calls abstract away from what the 'struct stat' buffer buffer is actually declared to be, allowing the same code to be used both on systems with and systems without support for files larger than 2GB in size. .PP The \fBTcl_FS...\fR are objectified and may cache internal representations and other path-related strings (e.g. the current working directory). One side-effect of this is that one must not pass in objects with a refCount of zero to any of these functions. If such calls were handled, they might result in memory leaks (under some circumstances, the filesystem code may wish to retain a reference to the passed in object, and so one must not assume that after any of these calls return, the object still has a refCount of zero - it may have been incremented), or in a direct segfault due to the object being freed part way through the complex object manipulation required to ensure that the path is fully normalized and absolute for filesystem determination. The practical lesson to learn from this is that \fBTcl_Obj *path = Tcl_NewStringObj(...) ; Tcl_FS...(path) ; Tcl_DecrRefCount(path)\fR is wrong, and may segfault. The 'path' must have its refCount incremented before passing it in, or decrementing it. For this reason, objects with a refCount of zero are considered not to be valid filesystem paths and calling any Tcl_FS API with such an object will result in no action being taken. .PP \fBTcl_FSCopyFile\fR attempts to copy the file given by srcPathPtr to the path name given by destPathPtr. If the two paths given lie in the same filesystem (according to \fBTcl_FSGetFileSystemForPath\fR) then that filesystem's 'copy file' function is called (if it is non-NULL). Otherwise the function returns -1 and sets Tcl's errno to the 'EXDEV' posix error code (which signifies a 'cross-domain link'). .PP \fBTcl_FSCopyDirectory\fR attempts to copy the directory given by srcPathPtr to the path name given by destPathPtr. If the two paths given lie in the same filesystem (according to \fBTcl_FSGetFileSystemForPath\fR) then that filesystem's 'copy file' function is called (if it is non-NULL). Otherwise the function returns -1 and sets Tcl's errno to the 'EXDEV' posix error code (which signifies a 'cross-domain link'). .PP \fBTcl_FSCreateDirectory\fR attempts to create the directory given by pathPtr by calling the owning filesystem's 'create directory' function. .PP \fBTcl_FSDeleteFile\fR attempts to delete the file given by pathPtr by calling the owning filesystem's 'delete file' function. .PP \fBTcl_FSRemoveDirectory\fR attempts to remove the directory given by pathPtr by calling the owning filesystem's 'remove directory' function. .PP \fBTcl_FSRenameFile\fR attempts to rename the file or directory given by srcPathPtr to the path name given by destPathPtr. If the two paths given lie in the same filesystem (according to \fBTcl_FSGetFileSystemForPath\fR) then that filesystem's 'rename file' function is called (if it is non-NULL). Otherwise the function returns -1 and sets Tcl's errno to the 'EXDEV' posix error code (which signifies a ``cross-domain link''). .PP \fBTcl_FSListVolumes\fR calls each filesystem which has a non-NULL 'list volumes' function and asks them to return their list of root volumes. It accumulates the return values in a list which is returned to the caller (with a refCount of 0). .PP \fBTcl_FSEvalFile\fR reads the file given by \fIpathPtr\fR and evaluates its contents as a Tcl script. It returns the same information as \fBTcl_EvalObjEx\fR. If the file couldn't be read then a Tcl error is returned to describe why the file couldn't be read. The eofchar for files is '\\32' (^Z) for all platforms. If you require a ``^Z'' in code for string comparison, you can use ``\\032'' or ``\\u001a'', which will be safely substituted by the Tcl interpreter into ``^Z''. .PP \fBTcl_FSLoadFile\fR dynamically loads a binary code file into memory and returns the addresses of two procedures within that file, if they are defined. The appropriate function for the filesystem to which pathPtr belongs will be called. If that filesystem does not implement this function (most virtual filesystems will not, because of OS limitations in dynamically loading binary code), Tcl will attempt to copy the file to a temporary directory and load that temporary file. .PP Returns a standard Tcl completion code. If an error occurs, an error message is left in the interp's result. .PP \fBTcl_FSMatchInDirectory\fR is used by the globbing code to search a directory for all files which match a given pattern. The appropriate function for the filesystem to which pathPtr belongs will be called. .PP The return value is a standard Tcl result indicating whether an error occurred in globbing. Error messages are placed in interp, but good results are placed in the resultPtr given. Note that the 'glob' code implements recursive patterns internally, so this function will only ever be passed simple patterns, which can be matched using the logic of 'string match'. To handle recursion, Tcl will call this function frequently asking only for directories to be returned. .PP \fBTcl_FSLink\fR replaces the library version of readlink(), and extends it to support the creation of links. The appropriate function for the filesystem to which linkNamePtr belongs will be called. .PP If the \fItoPtr\fR is NULL, a readlink action is performed. The result is a Tcl_Obj specifying the contents of the symbolic link given by \fIlinkNamePtr\fR, or NULL if the link could not be read. The result is owned by the caller, which should call Tcl_DecrRefCount when the result is no longer needed. If the \fItoPtr\fR is not NULL, Tcl should create a link of one of the types passed in in the \fIlinkAction\fR flag. This flag is an or'd combination of TCL_CREATE_SYMBOLIC_LINK and TCL_CREATE_HARD_LINK. Where a choice exists (i.e. more than one flag is passed in), the Tcl convention is to prefer symbolic links. When a link is successfully created, the return value should be \fItoPtr\fR (which is therefore already owned by the caller). If unsuccessful, NULL should be returned. .PP \fBTcl_FSLstat\fR fills the stat structure \fIstatPtr\fR with information about the specified file. You do not need any access rights to the file to get this information but you need search rights to all directories named in the path leading to the file. The stat structure includes info regarding device, inode (always 0 on Windows), privilege mode, nlink (always 1 on Windows), user id (always 0 on Windows), group id (always 0 on Windows), rdev (same as device on Windows), size, last access time, last modification time, and last metadata change time. .PP If \fIpath\fR exists, \fBTcl_FSLstat\fR returns 0 and the stat structure is filled with data. Otherwise, -1 is returned, and no stat info is given. .PP \fBTcl_FSUtime\fR replaces the library version of utime. .PP For results see 'utime' documentation. If successful, the function will update the 'atime' and 'mtime' values of the file given. .PP \fBTcl_FSFileAttrsGet\fR implements read access for the hookable 'file attributes' subcommand. The appropriate function for the filesystem to which pathPtr belongs will be called. .PP If the result is TCL_OK, then an object was placed in objPtrRef, which will only be temporarily valid (unless Tcl_IncrRefCount is called). .PP \fBTcl_FSFileAttrsSet\fR implements write access for the hookable 'file attributes' subcommand. The appropriate function for the filesystem to which pathPtr belongs will be called. .PP \fBTcl_FSFileAttrStrings\fR implements part of the hookable 'file attributes' subcommand. The appropriate function for the filesystem to which pathPtr belongs will be called. .PP The called procedure may either return an array of strings, or may instead return NULL and place a Tcl list into the given objPtrRef. Tcl will take that list and first increment its refCount before using it. On completion of that use, Tcl will decrement its refCount. Hence if the list should be disposed of by Tcl when done, it should have a refCount of zero, and if the list should not be disposed of, the filesystem should ensure it retains a refCount on the object. .PP \fBTcl_FSAccess\fR checks whether the process would be allowed to read, write or test for existence of the file (or other file system object) whose name is pathname. If pathname is a symbolic link on Unix, then permissions of the file referred by this symbolic link are tested. .PP On success (all requested permissions granted), zero is returned. On error (at least one bit in mode asked for a permission that is denied, or some other error occurred), -1 is returned. .PP \fBTcl_FSStat\fR fills the stat structure \fIstatPtr\fR with information about the specified file. You do not need any access rights to the file to get this information but you need search rights to all directories named in the path leading to the file. The stat structure includes info regarding device, inode (always 0 on Windows), privilege mode, nlink (always 1 on Windows), user id (always 0 on Windows), group id (always 0 on Windows), rdev (same as device on Windows), size, last access time, last modification time, and last metadata change time. .PP If \fIpath\fR exists, \fBTcl_FSStat\fR returns 0 and the stat structure is filled with data. Otherwise, -1 is returned, and no stat info is given. .PP \fBTcl_FSOpenFileChannel\fR opens a file specified by \fIpathPtr\fR and returns a channel handle that can be used to perform input and output on the file. This API is modeled after the \fBfopen\fR procedure of the Unix standard I/O library. The syntax and meaning of all arguments is similar to those given in the Tcl \fBopen\fR command when opening a file. If an error occurs while opening the channel, \fBTcl_FSOpenFileChannel\fR returns NULL and records a POSIX error code that can be retrieved with \fBTcl_GetErrno\fR. In addition, if \fIinterp\fR is non-NULL, \fBTcl_FSOpenFileChannel\fR leaves an error message in \fIinterp\fR's result after any error. .PP The newly created channel is not registered in the supplied interpreter; to register it, use \fBTcl_RegisterChannel\fR. If one of the standard channels, \fBstdin, stdout\fR or \fBstderr\fR was previously closed, the act of creating the new channel also assigns it as a replacement for the standard channel. .PP \fBTcl_FSGetCwd\fR replaces the library version of getcwd(). .PP It returns the Tcl library's current working directory. This may be different to the native platform's working directory, in the case for which the cwd is not in the native filesystem. .PP The result is a pointer to a Tcl_Obj specifying the current directory, or NULL if the current directory could not be determined. If NULL is returned, an error message is left in the interp's result. The result already has its refCount incremented for the caller. When it is no longer needed, that refCount should be decremented. This is needed for thread-safety purposes, to allow multiple threads to access this and related functions, while ensuring the results are always valid. .PP \fBTcl_FSChdir\fR replaces the library version of chdir(). The path is normalized and then passed to the filesystem which claims it. If that filesystem does not implement this function, Tcl will fallback to a combination of stat and access to check whether the directory exists and has appropriate permissions. .PP For results, see chdir() documentation. If successful, we keep a record of the successful path in cwdPathPtr for subsequent calls to getcwd. .PP \fBTcl_FSPathSeparator\fR returns the separator character to be used for most specific element of the path specified by pathPtr (i.e. the last part of the path). .PP The separator is returned as a Tcl_Obj containing a string of length 1. If the path is invalid, NULL is returned. .PP \fBTcl_FSJoinPath\fR takes the given Tcl_Obj, which should be a valid list, and returns the path object given by considering the first 'elements' elements as valid path segments. If elements < 0, we use the entire list. .PP Returns object with refCount of zero, containing the joined path. .PP \fBTcl_FSSplitPath\fR takes the given Tcl_Obj, which should be a valid path, and returns a Tcl List object containing each segment of that path as an element. .PP Returns list object with refCount of zero. If the passed in lenPtr is non-NULL, we use it to return the number of elements in the returned list. .PP \fBTcl_FSEqualPaths\fR tests whether the two paths given represent the same filesystem object .PP It returns 1 if the paths are equal, and 0 if they are different. If either path is NULL, 0 is always returned. .PP \fBTcl_FSGetNormalizedPath\fR this important function attempts to extract from the given Tcl_Obj a unique normalized path representation, whose string value can be used as a unique identifier for the file. .PP It returns the normalized path object, with refCount of zero, or NULL if the path was invalid or could otherwise not be successfully converted. Extraction of absolute, normalized paths is very efficient (because the filesystem operates on these representations internally), although the result when the filesystem contains numerous symbolic links may not be the most user-friendly version of a path. .PP \fBTcl_FSJoinToPath\fR takes the given object, which should usually be a valid path or NULL, and joins onto it the array of paths segments given. .PP Returns object with refCount of zero, containing the joined path. .PP \fBTcl_FSConvertToPathType\fR tries to convert the given Tcl_Obj to a valid Tcl path type, taking account of the fact that the cwd may have changed even if this object is already supposedly of the correct type. The filename may begin with "~" (to indicate current user's home directory) or "~" (to indicate any user's home directory). .PP If the conversion succeeds (i.e. the object is a valid path in one of the current filesystems), then TCL_OK is returned. Otherwise TCL_ERROR is returned, and an error message may be left in the interpreter. .PP \fBTcl_FSGetInternalRep\fR extracts the internal representation of a given path object, in the given filesystem. If the path object belongs to a different filesystem, we return NULL. If the internal representation is currently NULL, we attempt to generate it, by calling the filesystem's \fBTcl_FSCreateInternalRepProc\fR. .PP Returns NULL or a valid internal path representation. This internal representation is cached, so that repeated calls to this function will not require additional conversions. .PP \fBTcl_FSGetTranslatedPath\fR attempts to extract the translated path from the given Tcl_Obj. .PP If the translation succeeds (i.e. the object is a valid path), then it is returned. Otherwise NULL will be returned, and an error message may be left in the interpreter. A "translated" path is one which contains no "~" or "~user" sequences (these have been expanded to their current representation in the filesystem). The object returned is owned by the caller, which must store it or call Tcl_DecrRefCount to ensure memory is freed. This function is of little practical use, and \fBTcl_FSGetNormalizedPath\fR or \fBTcl_GetNativePath\fR are usually better functions to use for most purposes. .PP \fBTcl_FSGetTranslatedStringPath\fR does the same as \fBTcl_FSGetTranslatedPath\fR, but returns a character string or NULL. The string returned is dynamically allocated and owned by the caller, which must store it or call ckfree to ensure it is freed. Again, \fBTcl_FSGetNormalizedPath\fR or \fBTcl_GetNativePath\fR are usually better functions to use for most purposes. .PP \fBTcl_FSNewNativePath\fR performs something like that reverse of the usual obj->path->nativerep conversions. If some code retrieves a path in native form (from, e.g. readlink or a native dialog), and that path is to be used at the Tcl level, then calling this function is an efficient way of creating the appropriate path object type. .PP The resulting object is a pure 'path' object, which will only receive a Utf-8 string representation if that is required by some Tcl code. .PP \fBTcl_FSGetNativePath\fR is for use by the Win/Unix/MacOS native filesystems, so that they can easily retrieve the native (char* or TCHAR*) representation of a path. This function is a convenience wrapper around \fBTcl_FSGetInternalRep\fR, and assumes the native representation is string-based. It may be desirable in the future to have non-string-based native representations (for example, on MacOS, a representation using a fileSpec of FSRef structure would probably be more efficient). On Windows a full Unicode representation would allow for paths of unlimited length. Currently the representation is simply a character string containing the complete, absolute path in the native encoding. .PP The native representation is cached so that repeated calls to this function will not require additional conversions. .PP \fBTcl_FSFileSystemInfo\fR returns a list of two elements. The first element is the name of the filesystem (e.g. "native" or "vfs" or "zip" or "prowrap", perhaps), and the second is the particular type of the given path within that filesystem (which is filesystem dependent). The second element may be empty if the filesystem does not provide a further categorization of files. .PP A valid list object is returned, unless the path object is not recognized, when NULL will be returned. .PP \fBTcl_FSGetFileSystemForPath\fR returns the a pointer to the \fBTcl_Filesystem\fR which accepts this path as valid. .PP If no filesystem will accept the path, NULL is returned. .PP \fBTcl_FSGetPathType\fR determines whether the given path is relative to the current directory, relative to the current volume, or absolute. .PP It returns one of TCL_PATH_ABSOLUTE, TCL_PATH_RELATIVE, or TCL_PATH_VOLUME_RELATIVE .PP \fBTcl_AllocStatBuf\fR allocates a \fITcl_StatBuf\fR on the system heap (which may be deallocated by being passed to \fBckfree\fR.) This allows extensions to invoke \fBTcl_FSStat\fR and \fBTcl_FSLStat\fR without being dependent on the size of the buffer. That in turn depends on the flags used to build Tcl. .PP .SH TCL_FILESYSTEM .PP A filesystem provides a \fBTcl_Filesystem\fR structure that contains pointers to functions that implement the various operations on a filesystem; these operations are invoked as needed by the generic layer, which generally occurs through the functions listed above. .PP The \fBTcl_Filesystem\fR structures are manipulated using the following methods. .PP \fBTcl_FSRegister\fR takes a pointer to a filesystem structure and an optional piece of data to associated with that filesystem. On calling this function, Tcl will attach the filesystem to the list of known filesystems, and it will become fully functional immediately. Tcl does not check if the same filesystem is registered multiple times (and in general that is not a good thing to do). TCL_OK will be returned. .PP \fBTcl_FSUnregister\fR removes the given filesystem structure from the list of known filesystems, if it is known, and returns TCL_OK. If the filesystem is not currently registered, TCL_ERROR is returned. .PP \fBTcl_FSData\fR will return the ClientData associated with the given filesystem, if that filesystem is registered. Otherwise it will return NULL. .PP \fBTcl_FSMountsChanged\fR is used to inform the Tcl's core that the set of mount points for the given (already registered) filesystem have changed, and that cached file representations may therefore no longer be correct. .PP The \fBTcl_Filesystem\fR structure contains the following fields: .CS typedef struct Tcl_Filesystem { CONST char *\fItypeName\fR; int \fIstructureLength\fR; Tcl_FSVersion \fIversion\fR; Tcl_FSPathInFilesystemProc *\fIpathInFilesystemProc\fR; Tcl_FSDupInternalRepProc *\fIdupInternalRepProc\fR; Tcl_FSFreeInternalRepProc *\fIfreeInternalRepProc\fR; Tcl_FSInternalToNormalizedProc *\fIinternalToNormalizedProc\fR; Tcl_FSCreateInternalRepProc *\fIcreateInternalRepProc\fR; Tcl_FSNormalizePathProc *\fInormalizePathProc\fR; Tcl_FSFilesystemPathTypeProc *\fIfilesystemPathTypeProc\fR; Tcl_FSFilesystemSeparatorProc *\fIfilesystemSeparatorProc\fR; Tcl_FSStatProc *\fIstatProc\fR; Tcl_FSAccessProc *\fIaccessProc\fR; Tcl_FSOpenFileChannelProc *\fIopenFileChannelProc\fR; Tcl_FSMatchInDirectoryProc *\fImatchInDirectoryProc\fR; Tcl_FSUtimeProc *\fIutimeProc\fR; Tcl_FSLinkProc *\fIlinkProc\fR; Tcl_FSListVolumesProc *\fIlistVolumesProc\fR; Tcl_FSFileAttrStringsProc *\fIfileAttrStringsProc\fR; Tcl_FSFileAttrsGetProc *\fIfileAttrsGetProc\fR; Tcl_FSFileAttrsSetProc *\fIfileAttrsSetProc\fR; Tcl_FSCreateDirectoryProc *\fIcreateDirectoryProc\fR; Tcl_FSRemoveDirectoryProc *\fIremoveDirectoryProc\fR; Tcl_FSDeleteFileProc *\fIdeleteFileProc\fR; Tcl_FSCopyFileProc *\fIcopyFileProc\fR; Tcl_FSRenameFileProc *\fIrenameFileProc\fR; Tcl_FSCopyDirectoryProc *\fIcopyDirectoryProc\fR; Tcl_FSLstatProc *\fIlstatProc\fR; Tcl_FSLoadFileProc *\fIloadFileProc\fR; Tcl_FSGetCwdProc *\fIgetCwdProc\fR; Tcl_FSChdirProc *\fIchdirProc\fR; } Tcl_Filesystem; .CE .PP Except for the first three fields in this structure which contain simple data elements, all entries contain addresses of functions called by the generic filesystem layer to perform the complete range of filesystem related actions. .PP The many functions in this structure are broken down into three categories: infrastructure functions (almost all of which must be implemented), operational functions (which must be implemented if a complete filesystem is provided), and efficiency functions (which need only be implemented if they can be done so efficiently, or if they have side-effects which are required by the filesystem; Tcl has less efficient emulations it can fall back on). It is important to note that, in the current version of Tcl, most of these fallbacks are only used to handle commands initiated in Tcl, not in C. What this means is, that if a 'file rename' command is issued in Tcl, and the relevant filesystem(s) do not implement their \fITcl_FSRenameFileProc\fR, Tcl's core will instead fallback on a combination of other filesystem functions (it will use \fITcl_FSCopyFileProc\fR followed by \fITcl_FSDeleteFileProc\fR, and if \fITcl_FSCopyFileProc\fR is not implemented there is a further fallback). However, if a \fITcl_FSRenameFile\fR command is issued at the C level, no such fallbacks occur. This is true except for the last four entries in the filesystem table (lstat, load, getcwd and chdir) for which fallbacks do in fact occur at the C level. .PP As an example, here is the filesystem lookup table used by the "vfs" extension which allows filesystem actions to be implemented in Tcl. .CS static Tcl_Filesystem vfsFilesystem = { "tclvfs", sizeof(Tcl_Filesystem), TCL_FILESYSTEM_VERSION_1, &VfsPathInFilesystem, &VfsDupInternalRep, &VfsFreeInternalRep, /* No internal to normalized, since we don't create any * pure 'internal' Tcl_Obj path representations */ NULL, /* No create native rep function, since we don't use it * and don't choose to support uses of 'Tcl_FSNewNativePath' */ NULL, /* Normalize path isn't needed - we assume paths only have * one representation */ NULL, &VfsFilesystemPathType, &VfsFilesystemSeparator, &VfsStat, &VfsAccess, &VfsOpenFileChannel, &VfsMatchInDirectory, &VfsUtime, /* We choose not to support symbolic links inside our vfs's */ NULL, &VfsListVolumes, &VfsFileAttrStrings, &VfsFileAttrsGet, &VfsFileAttrsSet, &VfsCreateDirectory, &VfsRemoveDirectory, &VfsDeleteFile, /* No copy file - fallback will occur at Tcl level */ NULL, /* No rename file - fallback will occur at Tcl level */ NULL, /* No copy directory - fallback will occur at Tcl level */ NULL, /* Core will use stat for lstat */ NULL, /* No load - fallback on core implementation */ NULL, /* We don't need a getcwd or chdir - fallback on Tcl's versions */ NULL, NULL }; .CE .PP Any functions which take path names in Tcl_Obj form take those names in UTF\-8 form. The filesystem infrastructure API is designed to support efficient, cached conversion of these UTF\-8 paths to other native representations. .SH TYPENAME .PP The \fItypeName\fR field contains a null-terminated string that identifies the type of the filesystem implemented, e.g. \fBnative\fR or \fBzip\fR or \fBvfs\fR. .PP .SH "STRUCTURE LENGTH" .PP The \fIstructureLength\fR field is generally implemented as \fIsizeof(Tcl_Filesystem)\fR, and is there to allow easier binary backwards compatibility if the size of the structure changes in a future Tcl release. .SH VERSION .PP The \fIversion\fR field should be set to \fBTCL_FILESYSTEM_VERSION_1\fR. .SH "FILESYSTEM INFRASTRUCTURE" .PP These fields contain addresses of functions which are used to associate a particular filesystem with a file path, and deal with the internal handling of path representations, for example copying and freeing such representations. .SH PATHINFILESYSTEMPROC .PP The \fIpathInFilesystemProc\fR field contains the address of a function which is called to determine whether a given path object belongs to this filesystem or not. Tcl will only call the rest of the filesystem functions with a path for which this function has returned \fBTCL_OK\fR. If the path does not belong, -1 should be returned (the behaviour of Tcl for any other return value is not defined). If \fBTCL_OK\fR is returned, then the optional \fBclientDataPtr\fR output parameter can be used to return an internal (filesystem specific) representation of the path, which will be cached inside the path object, and may be retrieved efficiently by the other filesystem functions. Tcl will simultaneously cache the fact that this path belongs to this filesystem. Such caches are invalidated when filesystem structures are added or removed from Tcl's internal list of known filesystems. .PP .CS typedef int Tcl_FSPathInFilesystemProc( Tcl_Obj *\fIpathPtr\fR, ClientData *\fIclientDataPtr\fR); .CE .SH DUPINTERNALREPPROC .PP This function makes a copy of a path's internal representation, and is called when Tcl needs to duplicate a path object. If NULL, Tcl will simply not copy the internal representation, which may then need to be regenerated later. .PP .CS typedef ClientData Tcl_FSDupInternalRepProc( ClientData \fIclientData\fR); .CE .SH FREEINTERNALREPPROC Free the internal representation. This must be implemented if internal representations need freeing (i.e. if some memory is allocated when an internal representation is generated), but may otherwise be NULL. .PP .CS typedef void Tcl_FSFreeInternalRepProc( ClientData \fIclientData\fR); .CE .SH INTERNALTONORMALIZEDPROC .PP Function to convert internal representation to a normalized path. Only required if the filesystem creates pure path objects with no string/path representation. The return value is a Tcl object whose string representation is the normalized path. .PP .CS typedef Tcl_Obj* Tcl_FSInternalToNormalizedProc( ClientData \fIclientData\fR); .CE .SH CREATEINTERNALREPPROC .PP Function to take a path object, and calculate an internal representation for it, and store that native representation in the object. May be NULL if paths have no internal representation, or if the \fITcl_FSPathInFilesystemProc\fR for this filesystem always immediately creates an internal representation for paths it accepts. .PP .CS typedef ClientData Tcl_FSCreateInternalRepProc( Tcl_Obj *\fIpathPtr\fR); .CE .SH NORMALIZEPATHPROC .PP Function to normalize a path. Should be implemented for all filesystems which can have multiple string representations for the same path object. In Tcl, every 'path' must have a single unique 'normalized' string representation. Depending on the filesystem, there may be more than one unnormalized string representation which refers to that path (e.g. a relative path, a path with different character case if the filesystem is case insensitive, a path contain a reference to a home directory such as '~', a path containing symbolic links, etc). If the very last component in the path is a symbolic link, it should not be converted into the object it points to (but its case or other aspects should be made unique). All other path components should be converted from symbolic links. This one exception is required to agree with Tcl's semantics with 'file delete', 'file rename', 'file copy' operating on symbolic links. This function may be called with 'nextCheckpoint' either at the beginning of the path (i.e. zero), at the end of the path, or at any intermediate file separator in the path. It will never point to any other arbitrary position in the path. In the last of the three valid cases, the implementation can assume that the path up to and including the file separator is known and normalized. .PP .CS typedef int Tcl_FSNormalizePathProc( Tcl_Interp *\fIinterp\fR, Tcl_Obj *\fIpathPtr\fR, int \fInextCheckpoint\fR); .CE .SH "FILESYSTEM OPERATIONS" .PP The fields in this section of the structure contain addresses of functions which are called to carry out the basic filesystem operations. A filesystem which expects to be used with the complete standard Tcl command set must implement all of these. If some of them are not implemented, then certain Tcl commands may fail when operating on paths within that filesystem. However, in some instances this may be desirable (for example, a read-only filesystem should not implement the last four functions, and a filesystem which does not support symbolic links need not implement the \fBreadlink\fR function, etc. The Tcl core expects filesystems to behave in this way). .SH FILESYSTEMPATHTYPEPROC .PP Function to determine the type of a path in this filesystem. May be NULL, in which case no type information will be available to users of the filesystem. The 'type' is used only for informational purposes, and should be returned as the string representation of the Tcl_Obj which is returned. A typical return value might be "networked", "zip" or "ftp". The Tcl_Obj result is owned by the filesystem and so Tcl will increment the refCount of that object if it wishes to retain a reference to it. .PP .CS typedef Tcl_Obj* Tcl_FSFilesystemPathTypeProc( Tcl_Obj *\fIpathPtr\fR); .CE .SH FILESYSTEMSEPARATORPROC .PP Function to return the separator character(s) for this filesystem. Must be implemented, otherwise the \fBfile separator\fR command will not function correctly. The usual return value will be a Tcl_Obj containing the string "/". .PP .CS typedef Tcl_Obj* Tcl_FSFilesystemSeparatorProc( Tcl_Obj *\fIpathPtr\fR); .CE .SH STATPROC .PP Function to process a \fBTcl_FSStat()\fR call. Must be implemented for any reasonable filesystem, since many Tcl level commands depend crucially upon it (e.g. \fBfile atime\fR, \fBfile isdirectory\fR, \fBfile size\fR, \fBglob\fR). .PP .CS typedef int Tcl_FSStatProc( Tcl_Obj *\fIpathPtr\fR, Tcl_StatBuf *\fIstatPtr\fR); .CE .PP The \fBTcl_FSStatProc\fR fills the stat structure \fIstatPtr\fR with information about the specified file. You do not need any access rights to the file to get this information but you need search rights to all directories named in the path leading to the file. The stat structure includes info regarding device, inode (always 0 on Windows), privilege mode, nlink (always 1 on Windows), user id (always 0 on Windows), group id (always 0 on Windows), rdev (same as device on Windows), size, last access time, last modification time, and last metadata change time. .PP If the file represented by \fIpathPtr\fR exists, the \fBTcl_FSStatProc\fR returns 0 and the stat structure is filled with data. Otherwise, -1 is returned, and no stat info is given. .SH ACCESSPROC .PP Function to process a \fBTcl_FSAccess()\fR call. Must be implemented for any reasonable filesystem, since many Tcl level commands depend crucially upon it (e.g. \fBfile exists\fR, \fBfile readable\fR). .PP .CS typedef int Tcl_FSAccessProc( Tcl_Obj *\fIpathPtr\fR, int \fImode\fR); .CE .PP The \fBTcl_FSAccessProc\fR checks whether the process would be allowed to read, write or test for existence of the file (or other file system object) whose name is pathname. If pathname is a symbolic link, then permissions of the file referred by this symbolic link should be tested. .PP On success (all requested permissions granted), zero is returned. On error (at least one bit in mode asked for a permission that is denied, or some other error occurred), -1 is returned. .PP .SH OPENFILECHANNELPROC .PP Function to process a \fBTcl_FSOpenFileChannel()\fR call. Must be implemented for any reasonable filesystem, since any operations which require open or accessing a file's contents will use it (e.g. \fBopen\fR, \fBencoding\fR, and many Tk commands). .PP .CS typedef Tcl_Channel Tcl_FSOpenFileChannelProc( Tcl_Interp *\fIinterp\fR, Tcl_Obj *\fIpathPtr\fR, int \fImode\fR, int \fIpermissions\fR); .CE .PP The \fBTcl_FSOpenFileChannelProc\fR opens a file specified by \fIpathPtr\fR and returns a channel handle that can be used to perform input and output on the file. This API is modeled after the \fBfopen\fR procedure of the Unix standard I/O library. The syntax and meaning of all arguments is similar to those given in the Tcl \fBopen\fR command when opening a file, where the \fImode\fR argument is a combination of the POSIX flags O_RDONLY, O_WRONLY, etc. If an error occurs while opening the channel, the \fBTcl_FSOpenFileChannelProc\fR returns NULL and records a POSIX error code that can be retrieved with \fBTcl_GetErrno\fR. In addition, if \fIinterp\fR is non-NULL, the \fBTcl_FSOpenFileChannelProc\fR leaves an error message in \fIinterp\fR's result after any error. .PP The newly created channel must not registered in the supplied interpreter; that task is up to the caller of \fBTcl_FSOpenFileChannel\fR (if necessary). If one of the standard channels, \fBstdin, stdout\fR or \fBstderr\fR was previously closed, the act of creating the new channel also assigns it as a replacement for the standard channel. .SH MATCHINDIRECTORYPROC .PP Function to process a \fBTcl_FSMatchInDirectory()\fR call. If not implemented, then glob and recursive copy functionality will be lacking in the filesystem (and this may impact commands like 'encoding names' which use glob functionality internally). .PP .CS typedef int Tcl_FSMatchInDirectoryProc( Tcl_Interp* \fIinterp\fR, Tcl_Obj *\fIresult\fR, Tcl_Obj *\fIpathPtr\fR, CONST char *\fIpattern\fR, Tcl_GlobTypeData * \fItypes\fR); .CE .PP The function should return all files or directories (or other filesystem objects) which match the given pattern and accord with the \fItypes\fR specification given. There are two ways in which this function may be called. If \fIpattern\fR is NULL, then \fIpathPtr\fR is a full path specification of a single file or directory which should be checked for existence and correct type. Otherwise, \fIpathPtr\fR is a directory, the contents of which the function should search for files or directories which have the correct type. In either case, \fIpathPtr\fR can be assumed to be both non-NULL and non-empty. It is not currently documented whether \fIpathPtr\fR will have a file separator at its end of not, so code should be flexible to both possibilities. .PP The return value is a standard Tcl result indicating whether an error occurred in the matching process. Error messages are placed in \fIinterp\fR; on a \fBTCL_OK\fR result, results should be added to the \fIresult\fR object given (which can be assumed to be a valid unshared Tcl list). The matches added to \fIresult\fR should include any path prefix given in \fIpathPtr\fR (this usually means they will be absolute path specifications). Note that if no matches are found, that simply leads to an empty result; errors are only signaled for actual file or filesystem problems which may occur during the matching process. .PP The \fBTcl_GlobTypeData\fR structure passed in the \fItypes\fR parameter contains the following fields: .CS typedef struct Tcl_GlobTypeData { /* Corresponds to bcdpfls as in 'find -t' */ int \fItype\fR; /* Corresponds to file permissions */ int \fIperm\fR; /* Acceptable mac type */ Tcl_Obj *\fImacType\fR; /* Acceptable mac creator */ Tcl_Obj *\fImacCreator\fR; } Tcl_GlobTypeData; .CE .PP There are two specific cases which it is important to handle correctly, both when \fItypes\fR is non-NULL. The two cases are when \fItypes->types & TCL_GLOB_TYPE_DIR\fR or \fItypes->types & TCL_GLOB_TYPE_MOUNT\fR are true (and in particular when the other flags are false). In the first of these cases, the function must list the contained directories. Tcl uses this to implement recursive globbing, so it is critical that filesystems implement directory matching correctly. In the second of these cases, with \fBTCL_GLOB_TYPE_MOUNT\fR, the filesystem must list the mount points which lie within the given \fIpathPtr\fR (and in this case, \fIpathPtr\fR need not lie within the same filesystem - different to all other cases in which this function is called). Support for this is critical if Tcl is to have seamless transitions between from one filesystem to another. .SH UTIMEPROC .PP Function to process a \fBTcl_FSUtime()\fR call. Required to allow setting (not reading) of times with 'file mtime', 'file atime' and the open-r/open-w/fcopy implementation of 'file copy'. .PP .CS typedef int Tcl_FSUtimeProc( Tcl_Obj *\fIpathPtr\fR, struct utimbuf *\fItval\fR); .CE .PP The access and modification times of the file specified by \fIpathPtr\fR should be changed to the values given in the \fItval\fR structure. .PP The return value is a standard Tcl result indicating whether an error occurred in the process. .SH LINKPROC .PP Function to process a \fBTcl_FSLink()\fR call. Should be implemented only if the filesystem supports links, and may otherwise be NULL. .PP .CS typedef Tcl_Obj* Tcl_FSLinkProc( Tcl_Obj *\fIlinkNamePtr\fR, Tcl_Obj *\fItoPtr\fR, int \fIlinkAction\fR); .CE .PP If \fItoPtr\fR is NULL, the function is being asked to read the contents of a link. The result is a Tcl_Obj specifying the contents of the link given by \fIlinkNamePtr\fR, or NULL if the link could not be read. The result is owned by the caller, which should call Tcl_DecrRefCount when the result is no longer needed. If \fItoPtr\fR is not NULL, the function should attempt to create a link. The result in this case should be \fItoPtr\fR if the link was successful and NULL otherwise. In this case the result is not owned by the caller. See the documentation for \fBTcl_FSLink\fR for the correct interpretation of the \fIlinkAction\fR flags. .SH LISTVOLUMESPROC .PP Function to list any filesystem volumes added by this filesystem. Should be implemented only if the filesystem adds volumes at the head of the filesystem, so that they can be returned by 'file volumes'. .PP .CS typedef Tcl_Obj* Tcl_FSListVolumesProc(void); .CE .PP The result should be a list of volumes added by this filesystem, or NULL (or an empty list) if no volumes are provided. The result object is considered to be owned by the filesystem (not by Tcl's core), but should be given a refCount for Tcl. Tcl will use the contents of the list and then decrement that refCount. This allows filesystems to choose whether they actually want to retain a 'master list' of volumes or not (if not, they generate the list on the fly and pass it to Tcl with a refCount of 1 and then forget about the list, if yes, then they simply increment the refCount of their master list and pass it to Tcl which will copy the contents and then decrement the count back to where it was). .PP Therefore, Tcl considers return values from this proc to be read-only. .PP .SH FILEATTRSTRINGSPROC .PP Function to list all attribute strings which are valid for this filesystem. If not implemented the filesystem will not support the \fBfile attributes\fR command. This allows arbitrary additional information to be attached to files in the filesystem. If it is not implemented, there is no need to implement the \fBget\fR and \fBset\fR methods. .PP .CS typedef CONST char** Tcl_FSFileAttrStringsProc( Tcl_Obj *\fIpathPtr\fR, Tcl_Obj** \fIobjPtrRef\fR); .CE .PP The called function may either return an array of strings, or may instead return NULL and place a Tcl list into the given objPtrRef. Tcl will take that list and first increment its refCount before using it. On completion of that use, Tcl will decrement its refCount. Hence if the list should be disposed of by Tcl when done, it should have a refCount of zero, and if the list should not be disposed of, the filesystem should ensure it retains a refCount on the object. .SH FILEATTRSGETPROC .PP Function to process a \fBTcl_FSFileAttrsGet()\fR call, used by 'file attributes'. .PP .CS typedef int Tcl_FSFileAttrsGetProc( Tcl_Interp *\fIinterp\fR, int \fIindex\fR, Tcl_Obj *\fIpathPtr\fR, Tcl_Obj **\fIobjPtrRef\fR); .CE .PP Returns a standard Tcl return code. The attribute value retrieved, which corresponds to the \fIindex\fR'th element in the list returned by the Tcl_FSFileAttrStringsProc, is a Tcl_Obj placed in objPtrRef (if TCL_OK was returned) and is likely to have a refCount of zero. Either way we must either store it somewhere (e.g. the Tcl result), or Incr/Decr its refCount to ensure it is properly freed. .SH FILEATTRSSETPROC .PP Function to process a \fBTcl_FSFileAttrsSet()\fR call, used by 'file attributes'. If the filesystem is read-only, there is no need to implement this. .PP .CS typedef int Tcl_FSFileAttrsSetProc( Tcl_Interp *\fIinterp\fR, int \fIindex\fR, Tcl_Obj *\fIpathPtr\fR, Tcl_Obj *\fIobjPtr\fR); .CE .PP The attribute value of the \fIindex\fR'th element in the list returned by the Tcl_FSFileAttrStringsProc should be set to the \fIobjPtr\fR given. .SH CREATEDIRECTORYPROC .PP Function to process a \fBTcl_FSCreateDirectory()\fR call. Should be implemented unless the FS is read-only. .PP .CS typedef int Tcl_FSCreateDirectoryProc( Tcl_Obj *\fIpathPtr\fR); .CE .PP The return value is a standard Tcl result indicating whether an error occurred in the process. If successful, a new directory should have been added to the filesystem in the location specified by \fIpathPtr\fR. .SH REMOVEDIRECTORYPROC .PP Function to process a 'Tcl_FSRemoveDirectory()' call. Should be implemented unless the FS is read-only. .PP .CS typedef int Tcl_FSRemoveDirectoryProc( Tcl_Obj *\fIpathPtr\fR, int \fIrecursive\fR, Tcl_Obj **\fIerrorPtr\fR); .CE .PP The return value is a standard Tcl result indicating whether an error occurred in the process. If successful, the directory specified by \fIpathPtr\fR should have been removed from the filesystem. If the \fIrecursive\fR flag is given, then a non-empty directory should be deleted without error. If an error does occur, the name of the file or directory which caused the error should be placed in \fIerrorPtr\fR. .SH DELETEFILEPROC .PP Function to process a \fBTcl_FSDeleteFile()\fR call. Should be implemented unless the FS is read-only. .PP .CS typedef int Tcl_FSDeleteFileProc( Tcl_Obj *\fIpathPtr\fR); .CE .PP The return value is a standard Tcl result indicating whether an error occurred in the process. If successful, the file specified by \fIpathPtr\fR should have been removed from the filesystem. Note that, if the filesystem supports symbolic links, Tcl will always call this function and not Tcl_FSRemoveDirectoryProc when needed to delete them (even if they are symbolic links to directories). .SH "FILESYSTEM EFFICIENCY" .PP .SH LSTATPROC .PP Function to process a \fBTcl_FSLstat()\fR call. If not implemented, Tcl will attempt to use the \fIstatProc\fR defined above instead. Therefore it need only be implemented if a filesystem can differentiate between \fBstat\fR and \fBlstat\fR calls. .PP .CS typedef int Tcl_FSLstatProc( Tcl_Obj *\fIpathPtr\fR, Tcl_StatBuf *\fIstatPtr\fR); .CE .PP The behavior of this function is very similar to that of the Tcl_FSStatProc defined above, except that if it is applied to a symbolic link, it returns information about the link, not about the target file. .PP .SH COPYFILEPROC .PP Function to process a \fBTcl_FSCopyFile()\fR call. If not implemented Tcl will fall back on open-r, open-w and fcopy as a copying mechanism. Therefore it need only be implemented if the filesystem can perform that action more efficiently. .PP .CS typedef int Tcl_FSCopyFileProc( Tcl_Obj *\fIsrcPathPtr\fR, Tcl_Obj *\fIdestPathPtr\fR); .CE .PP The return value is a standard Tcl result indicating whether an error occurred in the copying process. Note that, \fIdestPathPtr\fR is the name of the file which should become the copy of \fIsrcPathPtr\fR. It is never the name of a directory into which \fIsrcPathPtr\fR could be copied (i.e. the function is much simpler than the Tcl level 'file copy' subcommand). Note that, if the filesystem supports symbolic links, Tcl will always call this function and not Tcl_FSCopyDirectoryProc when needed to copy them (even if they are symbolic links to directories). .SH RENAMEFILEPROC .PP Function to process a \fBTcl_FSRenameFile()\fR call. If not implemented, Tcl will fall back on a copy and delete mechanism. Therefore it need only be implemented if the filesystem can perform that action more efficiently. .PP .CS typedef int Tcl_FSRenameFileProc( Tcl_Obj *\fIsrcPathPtr\fR, Tcl_Obj *\fIdestPathPtr\fR); .CE .PP The return value is a standard Tcl result indicating whether an error occurred in the renaming process. .SH COPYDIRECTORYPROC .PP Function to process a \fBTcl_FSCopyDirectory()\fR call. If not implemented, Tcl will fall back on a recursive create-dir, file copy mechanism. Therefore it need only be implemented if the filesystem can perform that action more efficiently. .PP .CS typedef int Tcl_FSCopyDirectoryProc( Tcl_Obj *\fIsrcPathPtr\fR, Tcl_Obj *\fIdestPathPtr\fR, Tcl_Obj **\fIerrorPtr\fR); .CE .PP The return value is a standard Tcl result indicating whether an error occurred in the copying process. If an error does occur, the name of the file or directory which caused the error should be placed in \fIerrorPtr\fR. Note that, \fIdestPathPtr\fR is the name of the directory-name which should become the mirror-image of \fIsrcPathPtr\fR. It is not the name of a directory into which \fIsrcPathPtr\fR should be copied (i.e. the function is much simpler than the Tcl level 'file copy' subcommand). .SH LOADFILEPROC .PP Function to process a \fBTcl_FSLoadFile()\fR call. If not implemented, Tcl will fall back on a copy to native-temp followed by a Tcl_FSLoadFile on that temporary copy. Therefore it need only be implemented if the filesystem can load code directly, or it can be implemented simply to return TCL_ERROR to disable load functionality in this filesystem entirely. .PP .CS typedef int Tcl_FSLoadFileProc( Tcl_Interp * \fIinterp\fR, Tcl_Obj *\fIpathPtr\fR, Tcl_LoadHandle * \fIhandlePtr\fR, Tcl_FSUnloadFileProc * \fIunloadProcPtr\fR); .CE .PP Returns a standard Tcl completion code. If an error occurs, an error message is left in the interp's result. The function dynamically loads a binary code file into memory. On a successful load, the \fIhandlePtr\fR should be filled with a token for the dynamically loaded file, and the \fIunloadProcPtr\fR should be filled in with the address of a procedure. The procedure will be called with the given Tcl_LoadHandle as its only parameter when Tcl needs to unload the file. .SH UNLOADFILEPROC .PP Function to unload a previously successfully loaded file. If load was implemented, then this should also be implemented, if there is any cleanup action required. .PP .CS typedef void Tcl_FSUnloadFileProc( Tcl_LoadHandle \fIloadHandle\fR); .CE .SH GETCWDPROC .PP Function to process a \fBTcl_FSGetCwd()\fR call. Most filesystems need not implement this. It will usually only be called once, if 'getcwd' is called before 'chdir'. May be NULL. .PP .CS typedef Tcl_Obj* Tcl_FSGetCwdProc( Tcl_Interp *\fIinterp\fR); .CE .PP If the filesystem supports a native notion of a current working directory (which might perhaps change independent of Tcl), this function should return that cwd as the result, or NULL if the current directory could not be determined (e.g. the user does not have appropriate permissions on the cwd directory). If NULL is returned, an error message is left in the interp's result. .PP .SH CHDIRPROC .PP Function to process a \fBTcl_FSChdir()\fR call. If filesystems do not implement this, it will be emulated by a series of directory access checks. Otherwise, virtual filesystems which do implement it need only respond with a positive return result if the dirName is a valid, accessible directory in their filesystem. They need not remember the result, since that will be automatically remembered for use by GetCwd. Real filesystems should carry out the correct action (i.e. call the correct system 'chdir' api). .PP .CS typedef int Tcl_FSChdirProc( Tcl_Obj *\fIpathPtr\fR); .CE .PP The \fBTcl_FSChdirProc\fR changes the applications current working directory to the value specified in \fIpathPtr\fR. The function returns -1 on error or 0 on success. .SH KEYWORDS stat access filesystem vfs tcl8.4.20/doc/unset.n0000644003604700454610000000413511737050674013004 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" Copyright (c) 2000 Ajuba Solutions. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH unset n 8.4 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME unset \- Delete variables .SH SYNOPSIS \fBunset \fR?\fI\-nocomplain\fR? ?\fI\-\-\fR? ?\fIname name name ...\fR? .BE .SH DESCRIPTION .PP This command removes one or more variables. Each \fIname\fR is a variable name, specified in any of the ways acceptable to the \fBset\fR command. If a \fIname\fR refers to an element of an array then that element is removed without affecting the rest of the array. If a \fIname\fR consists of an array name with no parenthesized index, then the entire array is deleted. The \fBunset\fR command returns an empty string as result. .VS 8.4 If \fI\-nocomplain\fR is specified as the first argument, any possible errors are suppressed. The option may not be abbreviated, in order to disambiguate it from possible variable names. The option \fI\-\-\fR indicates the end of the options, and should be used if you wish to remove a variable with the same name as any of the options. .VE 8.4 If an error occurs, any variables after the named one causing the error are not deleted. An error can occur when the named variable doesn't exist, or the name refers to an array element but the variable is a scalar, or the name refers to a variable in a non-existent namespace. .SH EXAMPLE Create an array containing a mapping from some numbers to their squares and remove the array elements for non-prime numbers: .CS array set squares { 1 1 6 36 2 4 7 49 3 9 8 64 4 16 9 81 5 25 10 100 } puts "The squares are:" parray squares \fBunset\fR squares(1) squares(4) squares(6) \fBunset\fR squares(8) squares(9) squares(10) puts "The prime squares are:" parray squares .CE .SH "SEE ALSO" set(n), trace(n), upvar(n) .SH KEYWORDS remove, variable tcl8.4.20/doc/CrtChnlHdlr.30000644003604700454610000000721111737050674013720 0ustar dgp771div'\" '\" Copyright (c) 1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_CreateChannelHandler 3 7.5 Tcl "Tcl Library Procedures" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME Tcl_CreateChannelHandler, Tcl_DeleteChannelHandler \- call a procedure when a channel becomes readable or writable .SH SYNOPSIS .nf .nf \fB#include \fR .sp void \fBTcl_CreateChannelHandler\fR(\fIchannel, mask, proc, clientData\fR) .sp void \fBTcl_DeleteChannelHandler\fR(\fIchannel, proc, clientData\fR) .sp .SH ARGUMENTS .AS Tcl_ChannelProc clientData .AP Tcl_Channel channel in Tcl channel such as returned by \fBTcl_CreateChannel\fR. .AP int mask in Conditions under which \fIproc\fR should be called: OR-ed combination of \fBTCL_READABLE\fR, \fBTCL_WRITABLE\fR and \fBTCL_EXCEPTION\fR. Specify a zero value to temporarily disable an existing handler. .AP Tcl_FileProc *proc in Procedure to invoke whenever the channel indicated by \fIchannel\fR meets the conditions specified by \fImask\fR. .AP ClientData clientData in Arbitrary one-word value to pass to \fIproc\fR. .BE .SH DESCRIPTION .PP \fBTcl_CreateChannelHandler\fR arranges for \fIproc\fR to be called in the future whenever input or output becomes possible on the channel identified by \fIchannel\fR, or whenever an exceptional condition exists for \fIchannel\fR. The conditions of interest under which \fIproc\fR will be invoked are specified by the \fImask\fR argument. See the manual entry for \fBfileevent\fR for a precise description of what it means for a channel to be readable or writable. \fIProc\fR must conform to the following prototype: .CS typedef void Tcl_ChannelProc( ClientData \fIclientData\fR, int \fImask\fR); .CE .PP The \fIclientData\fR argument is the same as the value passed to \fBTcl_CreateChannelHandler\fR when the handler was created. Typically, \fIclientData\fR points to a data structure containing application-specific information about the channel. \fIMask\fR is an integer mask indicating which of the requested conditions actually exists for the channel; it will contain a subset of the bits from the \fImask\fR argument to \fBTcl_CreateChannelHandler\fR when the handler was created. .PP Each channel handler is identified by a unique combination of \fIchannel\fR, \fIproc\fR and \fIclientData\fR. There may be many handlers for a given channel as long as they don't have the same \fIchannel\fR, \fIproc\fR, and \fIclientData\fR. If \fBTcl_CreateChannelHandler\fR is invoked when there is already a handler for \fIchannel\fR, \fIproc\fR, and \fIclientData\fR, then no new handler is created; instead, the \fImask\fR is changed for the existing handler. .PP \fBTcl_DeleteChannelHandler\fR deletes a channel handler identified by \fIchannel\fR, \fIproc\fR and \fIclientData\fR; if no such handler exists, the call has no effect. .PP Channel handlers are invoked via the Tcl event mechanism, so they are only useful in applications that are event-driven. Note also that the conditions specified in the \fImask\fR argument to \fIproc\fR may no longer exist when \fIproc\fR is invoked: for example, if there are two handlers for \fBTCL_READABLE\fR on the same channel, the first handler could consume all of the available input so that the channel is no longer readable when the second handler is invoked. For this reason it may be useful to use nonblocking I/O on channels for which there are event handlers. .SH "SEE ALSO" Notifier(3), Tcl_CreateChannel(3), Tcl_OpenFileChannel(3), vwait(n). .SH KEYWORDS blocking, callback, channel, events, handler, nonblocking. tcl8.4.20/doc/concat.n0000644003604700454610000000274311737050674013120 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH concat n 8.3 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME concat \- Join lists together .SH SYNOPSIS \fBconcat\fI \fR?\fIarg arg ...\fR? .BE .SH DESCRIPTION .PP This command joins each of its arguments together with spaces after trimming leading and trailing white-space from each of them. If all the arguments are lists, this has the same effect as concatenating them into a single list. It permits any number of arguments; if no \fIarg\fRs are supplied, the result is an empty string. .SH EXAMPLES Although \fBconcat\fR will concatenate lists (so the command: .CS \fBconcat\fR a b {c d e} {f {g h}} .CE will return "\fBa b c d e f {g h}\fR" as its result), it will also concatenate things that are not lists, and hence the command: .CS \fBconcat\fR " a b {c " d " e} f" .CE will return "\fBa b {c d e} f\fR" as its result. .PP Note that the concatenation does not remove spaces from the middle of its arguments, so the command: .CS \fBconcat\fR "a b c" { d e f } .CE will return "\fBa b c d e f\fR" (i.e. with three spaces between the \fBa\fR, the \fBb\fR and the \fBc\fR). .SH "SEE ALSO" append(n), eval(n) .SH KEYWORDS concatenate, join, lists tcl8.4.20/doc/exec.n0000644003604700454610000003736712052456743012605 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH exec n 7.6 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME exec \- Invoke subprocesses .SH SYNOPSIS \fBexec \fR?\fIswitches\fR? \fIarg \fR?\fIarg ...\fR? .BE .SH DESCRIPTION .PP This command treats its arguments as the specification of one or more subprocesses to execute. The arguments take the form of a standard shell pipeline where each \fIarg\fR becomes one word of a command, and each distinct command becomes a subprocess. .PP If the initial arguments to \fBexec\fR start with \fB\-\fR then they are treated as command-line switches and are not part of the pipeline specification. The following switches are currently supported: .TP 13 \fB\-keepnewline\fR Retains a trailing newline in the pipeline's output. Normally a trailing newline will be deleted. .TP 13 \fB\-\|\-\fR Marks the end of switches. The argument following this one will be treated as the first \fIarg\fR even if it starts with a \fB\-\fR. .PP If an \fIarg\fR (or pair of \fIarg\fRs) has one of the forms described below then it is used by \fBexec\fR to control the flow of input and output among the subprocess(es). Such arguments will not be passed to the subprocess(es). In forms such as ``< \fIfileName\fR'' \fIfileName\fR may either be in a separate argument from ``<'' or in the same argument with no intervening space (i.e. ``<\fIfileName\fR''). .TP 15 | Separates distinct commands in the pipeline. The standard output of the preceding command will be piped into the standard input of the next command. .TP 15 |& Separates distinct commands in the pipeline. Both standard output and standard error of the preceding command will be piped into the standard input of the next command. This form of redirection overrides forms such as 2> and >&. .TP 15 <\0\fIfileName\fR The file named by \fIfileName\fR is opened and used as the standard input for the first command in the pipeline. .TP 15 <@\0\fIfileId\fR \fIFileId\fR must be the identifier for an open file, such as the return value from a previous call to \fBopen\fR. It is used as the standard input for the first command in the pipeline. \fIFileId\fR must have been opened for reading. .TP 15 <<\0\fIvalue\fR \fIValue\fR is passed to the first command as its standard input. .TP 15 >\0\fIfileName\fR Standard output from the last command is redirected to the file named \fIfileName\fR, overwriting its previous contents. .TP 15 2>\0\fIfileName\fR Standard error from all commands in the pipeline is redirected to the file named \fIfileName\fR, overwriting its previous contents. .TP 15 >&\0\fIfileName\fR Both standard output from the last command and standard error from all commands are redirected to the file named \fIfileName\fR, overwriting its previous contents. .TP 15 >>\0\fIfileName\fR Standard output from the last command is redirected to the file named \fIfileName\fR, appending to it rather than overwriting it. .TP 15 2>>\0\fIfileName\fR Standard error from all commands in the pipeline is redirected to the file named \fIfileName\fR, appending to it rather than overwriting it. .TP 15 >>&\0\fIfileName\fR Both standard output from the last command and standard error from all commands are redirected to the file named \fIfileName\fR, appending to it rather than overwriting it. .TP 15 >@\0\fIfileId\fR \fIFileId\fR must be the identifier for an open file, such as the return value from a previous call to \fBopen\fR. Standard output from the last command is redirected to \fIfileId\fR's file, which must have been opened for writing. .TP 15 2>@\0\fIfileId\fR \fIFileId\fR must be the identifier for an open file, such as the return value from a previous call to \fBopen\fR. Standard error from all commands in the pipeline is redirected to \fIfileId\fR's file. The file must have been opened for writing. .TP 15 >&@\0\fIfileId\fR \fIFileId\fR must be the identifier for an open file, such as the return value from a previous call to \fBopen\fR. Both standard output from the last command and standard error from all commands are redirected to \fIfileId\fR's file. The file must have been opened for writing. .PP If standard output has not been redirected then the \fBexec\fR command returns the standard output from the last command in the pipeline. If any of the commands in the pipeline exit abnormally or are killed or suspended, then \fBexec\fR will return an error and the error message will include the pipeline's output followed by error messages describing the abnormal terminations; the \fBerrorCode\fR variable will contain additional information about the last abnormal termination encountered. If any of the commands writes to its standard error file and that standard error isn't redirected, then \fBexec\fR will return an error; the error message will include the pipeline's standard output, followed by messages about abnormal terminations (if any), followed by the standard error output. .PP If the last character of the result or error message is a newline then that character is normally deleted from the result or error message. This is consistent with other Tcl return values, which don't normally end with newlines. However, if \fB\-keepnewline\fR is specified then the trailing newline is retained. .PP If standard input isn't redirected with ``<'' or ``<<'' or ``<@'' then the standard input for the first command in the pipeline is taken from the application's current standard input. .PP If the last \fIarg\fR is ``&'' then the pipeline will be executed in background. In this case the \fBexec\fR command will return a list whose elements are the process identifiers for all of the subprocesses in the pipeline. The standard output from the last command in the pipeline will go to the application's standard output if it hasn't been redirected, and error output from all of the commands in the pipeline will go to the application's standard error file unless redirected. .PP The first word in each command is taken as the command name; tilde-substitution is performed on it, and if the result contains no slashes then the directories in the PATH environment variable are searched for an executable by the given name. If the name contains a slash then it must refer to an executable reachable from the current directory. No ``glob'' expansion or other shell-like substitutions are performed on the arguments to commands. .VS .SH "PORTABILITY ISSUES" .TP \fBWindows\fR (all versions) . Reading from or writing to a socket, using the ``\fB@\0\fIfileId\fR'' notation, does not work. When reading from a socket, a 16-bit DOS application will hang and a 32-bit application will return immediately with end-of-file. When either type of application writes to a socket, the information is instead sent to the console, if one is present, or is discarded. .sp The Tk console text widget does not provide real standard IO capabilities. Under Tk, when redirecting from standard input, all applications will see an immediate end-of-file; information redirected to standard output or standard error will be discarded. .sp Either forward or backward slashes are accepted as path separators for arguments to Tcl commands. When executing an application, the path name specified for the application may also contain forward or backward slashes as path separators. Bear in mind, however, that most Windows applications accept arguments with forward slashes only as option delimiters and backslashes only in paths. Any arguments to an application that specify a path name with forward slashes will not automatically be converted to use the backslash character. If an argument contains forward slashes as the path separator, it may or may not be recognized as a path name, depending on the program. .sp Additionally, when calling a 16-bit DOS or Windows 3.X application, all path names must use the short, cryptic, path format (e.g., using ``applba~1.def'' instead of ``applbakery.default''), which can be obtained with the \fBfile attributes $fileName -shortname\fR command. .sp Two or more forward or backward slashes in a row in a path refer to a network path. For example, a simple concatenation of the root directory \fBc:/\fR with a subdirectory \fB/windows/system\fR will yield \fBc://windows/system\fR (two slashes together), which refers to the mount point called \fBsystem\fR on the machine called \fBwindows\fR (and the \fBc:/\fR is ignored), and is not equivalent to \fBc:/windows/system\fR, which describes a directory on the current computer. The \fBfile join\fR command should be used to concatenate path components. .sp .RS Note that there are two general types of Win32 console applications: .RS 1) CLI -- CommandLine Interface, simple stdio exchange. \fBnetstat.exe\fR for example. .br 2) TUI -- Textmode User Interface, any application that accesses the console API for doing such things as cursor movement, setting text color, detecting key presses and mouse movement, etc. An example would be \fBtelnet.exe\fR from Windows 2000. These types of applications are not common in a windows environment, but do exist. .RE \fBexec\fR will not work well with TUI applications when a console is not present, as is done when launching applications under wish. It is desirable to have console applications hidden and detached. This is a designed-in limitation as \fBexec\fR wants to communicate over pipes. The Expect extension addresses this issue when communicating with a TUI application. .sp .RE .TP \fBWindows NT\fR . When attempting to execute an application, \fBexec\fR first searches for the name as it was specified. Then, in order, \fB.com\fR, \fB.exe\fR, and \fB.bat\fR are appended to the end of the specified name and it searches for the longer name. If a directory name was not specified as part of the application name, the following directories are automatically searched in order when attempting to locate the application: .sp .RS .RS The directory from which the Tcl executable was loaded. .br The current directory. .br The Windows NT 32-bit system directory. .br The Windows NT 16-bit system directory. .br The Windows NT home directory. .br The directories listed in the path. .RE .sp In order to execute shell built-in commands like \fBdir\fR and \fBcopy\fR, the caller must prepend the desired command with ``\fBcmd.exe /c\0\fR'' because built-in commands are not implemented using executables. .sp .RE .TP \fBWindows 9x\fR . When attempting to execute an application, \fBexec\fR first searches for the name as it was specified. Then, in order, \fB.com\fR, \fB.exe\fR, and \fB.bat\fR are appended to the end of the specified name and it searches for the longer name. If a directory name was not specified as part of the application name, the following directories are automatically searched in order when attempting to locate the application: .sp .RS .RS The directory from which the Tcl executable was loaded. .br The current directory. .br The Windows 9x system directory. .br The Windows 9x home directory. .br The directories listed in the path. .RE .sp In order to execute shell built-in commands like \fBdir\fR and \fBcopy\fR, the caller must prepend the desired command with ``\fBcommand.com /c\0\fR'' because built-in commands are not implemented using executables. .sp Once a 16-bit DOS application has read standard input from a console and then quit, all subsequently run 16-bit DOS applications will see the standard input as already closed. 32-bit applications do not have this problem and will run correctly, even after a 16-bit DOS application thinks that standard input is closed. There is no known workaround for this bug at this time. .sp Redirection between the \fBNUL:\fR device and a 16-bit application does not always work. When redirecting from \fBNUL:\fR, some applications may hang, others will get an infinite stream of ``0x01'' bytes, and some will actually correctly get an immediate end-of-file; the behavior seems to depend upon something compiled into the application itself. When redirecting greater than 4K or so to \fBNUL:\fR, some applications will hang. The above problems do not happen with 32-bit applications. .sp All DOS 16-bit applications are run synchronously. All standard input from a pipe to a 16-bit DOS application is collected into a temporary file; the other end of the pipe must be closed before the 16-bit DOS application begins executing. All standard output or error from a 16-bit DOS application to a pipe is collected into temporary files; the application must terminate before the temporary files are redirected to the next stage of the pipeline. This is due to a workaround for a Windows 95 bug in the implementation of pipes, and is how the standard Windows 95 DOS shell handles pipes itself. .sp Certain applications, such as \fBcommand.com\fR, should not be executed interactively. Applications which directly access the console window, rather than reading from their standard input and writing to their standard output may fail, hang Tcl, or even hang the system if their own private console window is not available to them. .RE .TP \fBUnix\fR\0\0\0\0\0\0\0 The \fBexec\fR command is fully functional and works as described. .SH "UNIX EXAMPLES" Here are some examples of the use of the \fBexec\fR command on Unix. .PP To execute a simple program and get its result: .CS \fBexec\fR uname -a .CE .PP To execute a program that can return a non-zero result, you should wrap the call to \fBexec\fR in \fBcatch\fR and check what the contents of the global \fBerrorCode\fR variable is if you have an error: .CS set status 0 if {[catch {\fBexec\fR grep foo bar.txt} results]} { if {[lindex $::errorCode 0] eq "CHILDSTATUS"} { set status [lindex $::errorCode 2] } else { # Some kind of unexpected failure } } .CE .PP When translating a command from a Unix shell invocation, care should be taken over the fact that single quote characters have no special significance to Tcl. Thus: .CS awk '{sum += $1} END {print sum}' numbers.list .CE would be translated into something like: .CS \fBexec\fR awk {{sum += $1} END {print sum}} numbers.list .CE .PP If you are converting invocations involving shell globbing, you should remember that Tcl does not handle globbing or expand things into multiple arguments by default. Instead you should write things like this: .CS eval [list \fBexec\fR ls -l] [glob *.tcl] .CE .PP .SH "WINDOWS EXAMPLES" Here are some examples of the use of the \fBexec\fR command on Windows. .PP To start an instance of \fInotepad\fR editing a file without waiting for the user to finish editing the file: .CS \fBexec\fR notepad myfile.txt & .CE .PP To print a text file using \fInotepad\fR: .CS \fBexec\fR notepad /p myfile.txt .CE .PP If a program calls other programs, such as is common with compilers, then you may need to resort to batch files to hide the console windows that sometimes pop up: .CS \fBexec\fR cmp.bat somefile.c -o somefile .CE With the file \fIcmp.bat\fR looking something like: .CS @gcc %1 %2 %3 %4 %5 %6 %7 %8 %9 .CE .PP Sometimes you need to be careful, as different programs may have the same name and be in the path. It can then happen that typing a command at the DOS prompt finds \fIa different program\fR than the same command run via \fBexec\fR. This is because of the (documented) differences in behaviour between \fBexec\fR and DOS batch files. .PP When in doubt, use the command \fBauto_execok\fR: it will return the complete path to the program as seen by the \fBexec\fR command. This applies especially when you want to run "internal" commands like \fIdir\fR from a Tcl script (if you just want to list filenames, use the \fBglob\fR command.) To do that, use this: .CS eval [list \fBexec\fR] [auto_execok dir] [list *.tcl] .CE .SH "SEE ALSO" error(n), open(n) .SH KEYWORDS execute, pipeline, redirection, subprocess tcl8.4.20/doc/DString.30000644003604700454610000001351611737050674013130 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_DString 3 7.4 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_DStringInit, Tcl_DStringAppend, Tcl_DStringAppendElement, Tcl_DStringStartSublist, Tcl_DStringEndSublist, Tcl_DStringLength, Tcl_DStringValue, Tcl_DStringSetLength, Tcl_DStringTrunc, Tcl_DStringFree, Tcl_DStringResult, Tcl_DStringGetResult \- manipulate dynamic strings .SH SYNOPSIS .nf \fB#include \fR .sp \fBTcl_DStringInit\fR(\fIdsPtr\fR) .sp char * \fBTcl_DStringAppend\fR(\fIdsPtr, string, length\fR) .sp char * \fBTcl_DStringAppendElement\fR(\fIdsPtr, string\fR) .sp \fBTcl_DStringStartSublist\fR(\fIdsPtr\fR) .sp \fBTcl_DStringEndSublist\fR(\fIdsPtr\fR) .sp int \fBTcl_DStringLength\fR(\fIdsPtr\fR) .sp char * \fBTcl_DStringValue\fR(\fIdsPtr\fR) .sp \fBTcl_DStringSetLength\fR(\fIdsPtr, newLength\fR) .sp \fBTcl_DStringTrunc\fR(\fIdsPtr, newLength\fR) .sp \fBTcl_DStringFree\fR(\fIdsPtr\fR) .sp \fBTcl_DStringResult\fR(\fIinterp, dsPtr\fR) .sp \fBTcl_DStringGetResult\fR(\fIinterp, dsPtr\fR) .SH ARGUMENTS .AS Tcl_DString newLength .AP Tcl_DString *dsPtr in/out Pointer to structure that is used to manage a dynamic string. .AP "CONST char" *string in Pointer to characters to add to dynamic string. .AP int length in Number of characters from string to add to dynamic string. If -1, add all characters up to null terminating character. .AP int newLength in New length for dynamic string, not including null terminating character. .AP Tcl_Interp *interp in/out Interpreter whose result is to be set from or moved to the dynamic string. .BE .SH DESCRIPTION .PP Dynamic strings provide a mechanism for building up arbitrarily long strings by gradually appending information. If the dynamic string is short then there will be no memory allocation overhead; as the string gets larger, additional space will be allocated as needed. .PP \fBTcl_DStringInit\fR initializes a dynamic string to zero length. The Tcl_DString structure must have been allocated by the caller. No assumptions are made about the current state of the structure; anything already in it is discarded. If the structure has been used previously, \fBTcl_DStringFree\fR should be called first to free up any memory allocated for the old string. .PP \fBTcl_DStringAppend\fR adds new information to a dynamic string, allocating more memory for the string if needed. If \fIlength\fR is less than zero then everything in \fIstring\fR is appended to the dynamic string; otherwise \fIlength\fR specifies the number of bytes to append. \fBTcl_DStringAppend\fR returns a pointer to the characters of the new string. The string can also be retrieved from the \fIstring\fR field of the Tcl_DString structure. .PP \fBTcl_DStringAppendElement\fR is similar to \fBTcl_DStringAppend\fR except that it doesn't take a \fIlength\fR argument (it appends all of \fIstring\fR) and it converts the string to a proper list element before appending. \fBTcl_DStringAppendElement\fR adds a separator space before the new list element unless the new list element is the first in a list or sub-list (i.e. either the current string is empty, or it contains the single character ``{'', or the last two characters of the current string are `` {''). \fBTcl_DStringAppendElement\fR returns a pointer to the characters of the new string. .PP \fBTcl_DStringStartSublist\fR and \fBTcl_DStringEndSublist\fR can be used to create nested lists. To append a list element that is itself a sublist, first call \fBTcl_DStringStartSublist\fR, then call \fBTcl_DStringAppendElement\fR for each of the elements in the sublist, then call \fBTcl_DStringEndSublist\fR to end the sublist. \fBTcl_DStringStartSublist\fR appends a space character if needed, followed by an open brace; \fBTcl_DStringEndSublist\fR appends a close brace. Lists can be nested to any depth. .PP \fBTcl_DStringLength\fR is a macro that returns the current length of a dynamic string (not including the terminating null character). \fBTcl_DStringValue\fR is a macro that returns a pointer to the current contents of a dynamic string. .PP .PP \fBTcl_DStringSetLength\fR changes the length of a dynamic string. If \fInewLength\fR is less than the string's current length, then the string is truncated. If \fInewLength\fR is greater than the string's current length, then the string will become longer and new space will be allocated for the string if needed. However, \fBTcl_DStringSetLength\fR will not initialize the new space except to provide a terminating null character; it is up to the caller to fill in the new space. \fBTcl_DStringSetLength\fR does not free up the string's storage space even if the string is truncated to zero length, so \fBTcl_DStringFree\fR will still need to be called. .PP \fBTcl_DStringTrunc\fR changes the length of a dynamic string. This procedure is now deprecated. \fBTcl_DStringSetLength\fR should be used instead. .PP \fBTcl_DStringFree\fR should be called when you're finished using the string. It frees up any memory that was allocated for the string and reinitializes the string's value to an empty string. .PP \fBTcl_DStringResult\fR sets the result of \fIinterp\fR to the value of the dynamic string given by \fIdsPtr\fR. It does this by moving a pointer from \fIdsPtr\fR to the interpreter's result. This saves the cost of allocating new memory and copying the string. \fBTcl_DStringResult\fR also reinitializes the dynamic string to an empty string. .PP \fBTcl_DStringGetResult\fR does the opposite of \fBTcl_DStringResult\fR. It sets the value of \fIdsPtr\fR to the result of \fIinterp\fR and it clears \fIinterp\fR's result. If possible it does this by moving a pointer rather than by copying the string. .SH KEYWORDS append, dynamic string, free, result tcl8.4.20/doc/load.n0000644003604700454610000001473411737050674012573 0ustar dgp771div'\" '\" Copyright (c) 1995-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH load n 7.5 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME load \- Load machine code and initialize new commands. .SH SYNOPSIS \fBload \fIfileName\fR .br \fBload \fIfileName packageName\fR .br \fBload \fIfileName packageName interp\fR .BE .SH DESCRIPTION .PP This command loads binary code from a file into the application's address space and calls an initialization procedure in the package to incorporate it into an interpreter. \fIfileName\fR is the name of the file containing the code; its exact form varies from system to system but on most systems it is a shared library, such as a \fB.so\fR file under Solaris or a DLL under Windows. \fIpackageName\fR is the name of the package, and is used to compute the name of an initialization procedure. \fIinterp\fR is the path name of the interpreter into which to load the package (see the \fBinterp\fR manual entry for details); if \fIinterp\fR is omitted, it defaults to the interpreter in which the \fBload\fR command was invoked. .PP Once the file has been loaded into the application's address space, one of two initialization procedures will be invoked in the new code. Typically the initialization procedure will add new commands to a Tcl interpreter. The name of the initialization procedure is determined by \fIpackageName\fR and whether or not the target interpreter is a safe one. For normal interpreters the name of the initialization procedure will have the form \fIpkg\fB_Init\fR, where \fIpkg\fR is the same as \fIpackageName\fR except that the first letter is converted to upper case and all other letters are converted to lower case. For example, if \fIpackageName\fR is \fBfoo\fR or \fBFOo\fR, the initialization procedure's name will be \fBFoo_Init\fR. .PP If the target interpreter is a safe interpreter, then the name of the initialization procedure will be \fIpkg\fB_SafeInit\fR instead of \fIpkg\fB_Init\fR. The \fIpkg\fB_SafeInit\fR function should be written carefully, so that it initializes the safe interpreter only with partial functionality provided by the package that is safe for use by untrusted code. For more information on Safe\-Tcl, see the \fBsafe\fR manual entry. .PP The initialization procedure must match the following prototype: .CS typedef int Tcl_PackageInitProc(Tcl_Interp *\fIinterp\fR); .CE The \fIinterp\fR argument identifies the interpreter in which the package is to be loaded. The initialization procedure must return \fBTCL_OK\fR or \fBTCL_ERROR\fR to indicate whether or not it completed successfully; in the event of an error it should set the interpreter's result to point to an error message. The result of the \fBload\fR command will be the result returned by the initialization procedure. .PP The actual loading of a file will only be done once for each \fIfileName\fR in an application. If a given \fIfileName\fR is loaded into multiple interpreters, then the first \fBload\fR will load the code and call the initialization procedure; subsequent \fBload\fRs will call the initialization procedure without loading the code again. It is not possible to unload or reload a package. .PP The \fBload\fR command also supports packages that are statically linked with the application, if those packages have been registered by calling the \fBTcl_StaticPackage\fR procedure. If \fIfileName\fR is an empty string, then \fIpackageName\fR must be specified. .PP If \fIpackageName\fR is omitted or specified as an empty string, Tcl tries to guess the name of the package. This may be done differently on different platforms. The default guess, which is used on most UNIX platforms, is to take the last element of \fIfileName\fR, strip off the first three characters if they are \fBlib\fR, and use any following .VS alphabetic and underline characters as the module name. .VE For example, the command \fBload libxyz4.2.so\fR uses the module name \fBxyz\fR and the command \fBload bin/last.so {}\fR uses the module name \fBlast\fR. .VS "" br .PP If \fIfileName\fR is an empty string, then \fIpackageName\fR must be specified. The \fBload\fR command first searches for a statically loaded package (one that has been registered by calling the \fBTcl_StaticPackage\fR procedure) by that name; if one is found, it is used. Otherwise, the \fBload\fR command searches for a dynamically loaded package by that name, and uses it if it is found. If several different files have been \fBload\fRed with different versions of the package, Tcl picks the file that was loaded first. .VE .SH "PORTABILITY ISSUES" .TP \fBWindows\fR\0\0\0\0\0 . When a load fails with "library not found" error, it is also possible that a dependent library was not found. To see the dependent libraries, type ``dumpbin -imports '' in a DOS console to see what the library must import. When loading a DLL in the current directory, Windows will ignore ``./'' as a path specifier and use a search heuristic to find the DLL instead. To avoid this, load the DLL with: .CS \fBload\fR [file join [pwd] mylib.DLL] .CE .SH BUGS .PP If the same file is \fBload\fRed by different \fIfileName\fRs, it will be loaded into the process's address space multiple times. The behavior of this varies from system to system (some systems may detect the redundant loads, others may not). .SH EXAMPLE The following is a minimal extension: .PP .CS #include #include static int fooCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { printf("called with %d arguments\\n", objc); return TCL_OK; } int Foo_Init(Tcl_Interp *interp) { if (Tcl_InitStubs(interp, "8.1", 0) == NULL) { return TCL_ERROR; } printf("creating foo command"); Tcl_CreateObjCommand(interp, "foo", fooCmd, NULL, NULL); return TCL_OK; } .CE .PP When built into a shared/dynamic library with a suitable name (e.g. \fBfoo.dll\fR on Windows, \fBlibfoo.so\fR on Solaris and Linux) it can then be loaded into Tcl with the following: .PP .CS # Load the extension switch $tcl_platform(platform) { windows { \fBload\fR [file join [pwd] foo.dll] } unix { \fBload\fR [file join [pwd] libfoo[info sharedlibextension]] } } # Now execute the command defined by the extension foo .CE .SH "SEE ALSO" info sharedlibextension, Tcl_StaticPackage(3), safe(n) .SH KEYWORDS binary code, loading, safe interpreter, shared library tcl8.4.20/doc/CallDel.30000644003604700454610000000414111737050674013050 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_CallWhenDeleted 3 7.0 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_CallWhenDeleted, Tcl_DontCallWhenDeleted \- Arrange for callback when interpreter is deleted .SH SYNOPSIS .nf \fB#include \fR .sp \fBTcl_CallWhenDeleted\fR(\fIinterp\fR, \fIproc\fR, \fIclientData\fR) .sp \fBTcl_DontCallWhenDeleted\fR(\fIinterp\fR, \fIproc\fR, \fIclientData\fR) .SH ARGUMENTS .AS Tcl_InterpDeleteProc clientData .AP Tcl_Interp *interp in Interpreter with which to associated callback. .AP Tcl_InterpDeleteProc *proc in Procedure to call when \fIinterp\fR is deleted. .AP ClientData clientData in Arbitrary one-word value to pass to \fIproc\fR. .BE .SH DESCRIPTION .PP \fBTcl_CallWhenDeleted\fR arranges for \fIproc\fR to be called by \fBTcl_DeleteInterp\fR if/when \fIinterp\fR is deleted at some future time. \fIProc\fR will be invoked just before the interpreter is deleted, but the interpreter will still be valid at the time of the call. \fIProc\fR should have arguments and result that match the type \fBTcl_InterpDeleteProc\fR: .CS typedef void Tcl_InterpDeleteProc( ClientData \fIclientData\fR, Tcl_Interp *\fIinterp\fR); .CE The \fIclientData\fR and \fIinterp\fR parameters are copies of the \fIclientData\fR and \fIinterp\fR arguments given to \fBTcl_CallWhenDeleted\fR. Typically, \fIclientData\fR points to an application-specific data structure that \fIproc\fR uses to perform cleanup when an interpreter is about to go away. \fIProc\fR does not return a value. .PP \fBTcl_DontCallWhenDeleted\fR cancels a previous call to \fBTcl_CallWhenDeleted\fR with the same arguments, so that \fIproc\fR won't be called after all when \fIinterp\fR is deleted. If there is no deletion callback that matches \fIinterp\fR, \fIproc\fR, and \fIclientData\fR then the call to \fBTcl_DontCallWhenDeleted\fR has no effect. .SH KEYWORDS callback, delete, interpreter tcl8.4.20/doc/packagens.n0000644003604700454610000000361411737050674013603 0ustar dgp771div'\" '\" Copyright (c) 1998-2000 by Scriptics Corporation. '\" All rights reserved. '\" .so man.macros .TH pkg::create n 8.3 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME pkg::create \- Construct an appropriate \fBpackage ifneeded\fR command for a given package specification .SH SYNOPSIS \fB::pkg::create \fI\-name packageName\fR \fI\-version packageVersion\fR ?\fI\-load filespec\fR? ... ?\fI\-source filespec\fR? ... .BE .SH DESCRIPTION .PP \fB::pkg::create\fR is a utility procedure that is part of the standard Tcl library. It is used to create an appropriate \fBpackage ifneeded\fR command for a given package specification. It can be used to construct a \fBpkgIndex.tcl\fR file for use with the \fBpackage\fR mechanism. .SH OPTIONS The parameters supported are: .TP \fB\-name\fR\0\fIpackageName\fR This parameter specifies the name of the package. It is required. .TP \fB\-version\fR\0\fIpackageVersion\fR This parameter specifies the version of the package. It is required. .TP \fB\-load\fR\0\fIfilespec\fR This parameter specifies a binary library that must be loaded with the \fBload\fR command. \fIfilespec\fR is a list with two elements. The first element is the name of the file to load. The second, optional element is a list of commands supplied by loading that file. If the list of procedures is empty or omitted, \fB::pkg::create\fR will set up the library for direct loading (see \fBpkg_mkIndex\fR). Any number of \fB\-load\fR parameters may be specified. .TP \fB\-source\fR\0\fIfilespec\fR This parameter is similar to the \fB\-load\fR parameter, except that it specifies a Tcl library that must be loaded with the \fBsource\fR command. Any number of \fB\-source\fR parameters may be specified. .PP At least one \fB\-load\fR or \fB\-source\fR parameter must be given. .SH "SEE ALSO" package(n) .SH KEYWORDS auto-load, index, package, version tcl8.4.20/doc/cd.n0000644003604700454610000000215711737050674012236 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH cd n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME cd \- Change working directory .SH SYNOPSIS \fBcd \fR?\fIdirName\fR? .BE .SH DESCRIPTION .PP Change the current working directory to \fIdirName\fR, or to the home directory (as specified in the HOME environment variable) if \fIdirName\fR is not given. Returns an empty string. Note that the current working directory is a per-process resource; the \fBcd\fR command changes the working directory for all interpreters and (in a threaded environment) all threads. .SH EXAMPLES Change to the home directory of the user \fBfred\fR: .CS \fBcd\fR ~fred .CE .PP Change to the directory \fBlib\fR that is a sibling directory of the current one: .CS \fBcd\fR ../lib .CE .SH "SEE ALSO" filename(n), glob(n), pwd(n) .SH KEYWORDS working directory tcl8.4.20/doc/RecEvalObj.30000644003604700454610000000355611737050674013535 0ustar dgp771div'\" '\" Copyright (c) 1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_RecordAndEvalObj 3 8.0 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_RecordAndEvalObj \- save command on history list before evaluating .SH SYNOPSIS .nf \fB#include \fR .sp int \fBTcl_RecordAndEvalObj\fR(\fIinterp, cmdPtr, flags\fR) .SH ARGUMENTS .AS Tcl_Interp *interp; .AP Tcl_Interp *interp in Tcl interpreter in which to evaluate command. .AP Tcl_Obj *cmdPtr in Points to a Tcl object containing a command (or sequence of commands) to execute. .AP int flags in An OR'ed combination of flag bits. TCL_NO_EVAL means record the command but don't evaluate it. TCL_EVAL_GLOBAL means evaluate the command at global level instead of the current stack level. .BE .SH DESCRIPTION .PP \fBTcl_RecordAndEvalObj\fR is invoked to record a command as an event on the history list and then execute it using \fBTcl_EvalObjEx\fR (or \fBTcl_GlobalEvalObj\fR if the TCL_EVAL_GLOBAL bit is set in \fIflags\fR). It returns a completion code such as TCL_OK just like \fBTcl_EvalObjEx\fR, as well as a result object containing additional information (a result value or error message) that can be retrieved using \fBTcl_GetObjResult\fR. If you don't want the command recorded on the history list then you should invoke \fBTcl_EvalObjEx\fR instead of \fBTcl_RecordAndEvalObj\fR. Normally \fBTcl_RecordAndEvalObj\fR is only called with top-level commands typed by the user, since the purpose of history is to allow the user to re-issue recently-invoked commands. If the \fIflags\fR argument contains the TCL_NO_EVAL bit then the command is recorded without being evaluated. .SH "SEE ALSO" Tcl_EvalObjEx, Tcl_GetObjResult .SH KEYWORDS command, event, execute, history, interpreter, object, record tcl8.4.20/doc/uplevel.n0000644003604700454610000000752111737050674013324 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH uplevel n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME uplevel \- Execute a script in a different stack frame .SH SYNOPSIS \fBuplevel \fR?\fIlevel\fR?\fI arg \fR?\fIarg ...\fR? .BE .SH DESCRIPTION .PP All of the \fIarg\fR arguments are concatenated as if they had been passed to \fBconcat\fR; the result is then evaluated in the variable context indicated by \fIlevel\fR. \fBUplevel\fR returns the result of that evaluation. .PP If \fIlevel\fR is an integer then it gives a distance (up the procedure calling stack) to move before executing the command. If \fIlevel\fR consists of \fB#\fR followed by a number then the number gives an absolute level number. If \fIlevel\fR is omitted then it defaults to \fB1\fR. \fILevel\fR cannot be defaulted if the first \fIcommand\fR argument starts with a digit or \fB#\fR. .PP For example, suppose that procedure \fBa\fR was invoked from top-level, and that it called \fBb\fR, and that \fBb\fR called \fBc\fR. Suppose that \fBc\fR invokes the \fBuplevel\fR command. If \fIlevel\fR is \fB1\fR or \fB#2\fR or omitted, then the command will be executed in the variable context of \fBb\fR. If \fIlevel\fR is \fB2\fR or \fB#1\fR then the command will be executed in the variable context of \fBa\fR. If \fIlevel\fR is \fB3\fR or \fB#0\fR then the command will be executed at top-level (only global variables will be visible). .PP The \fBuplevel\fR command causes the invoking procedure to disappear from the procedure calling stack while the command is being executed. In the above example, suppose \fBc\fR invokes the command .CS \fBuplevel\fR 1 {set x 43; d} .CE where \fBd\fR is another Tcl procedure. The \fBset\fR command will modify the variable \fBx\fR in \fBb\fR's context, and \fBd\fR will execute at level 3, as if called from \fBb\fR. If it in turn executes the command .CS \fBuplevel\fR {set x 42} .CE then the \fBset\fR command will modify the same variable \fBx\fR in \fBb\fR's context: the procedure \fBc\fR does not appear to be on the call stack when \fBd\fR is executing. The command ``\fBinfo level\fR'' may be used to obtain the level of the current procedure. .PP \fBUplevel\fR makes it possible to implement new control constructs as Tcl procedures (for example, \fBuplevel\fR could be used to implement the \fBwhile\fR construct as a Tcl procedure). .PP \fBnamespace eval\fR is another way (besides procedure calls) that the Tcl naming context can change. It adds a call frame to the stack to represent the namespace context. This means each \fBnamespace eval\fR command counts as another call level for \fBuplevel\fR and \fBupvar\fR commands. For example, \fBinfo level 1\fR will return a list describing a command that is either the outermost procedure call or the outermost \fBnamespace eval\fR command. Also, \fBuplevel #0\fR evaluates a script at top-level in the outermost namespace (the global namespace). .SH EXAMPLE As stated above, the \fBuplevel\fR command is useful for creating new control constructs. This example shows how (without error handling) it can be used to create a \fBdo\fR command that is the counterpart of \fBwhile\fR except for always performing the test after running the loop body: .CS proc do {body while condition} { if {$while ne "while"} { error "required word missing" } set conditionCmd [list expr $condition] while {1} { \fBuplevel\fR 1 $body if {![\fBuplevel\fR 1 $conditionCmd]} { break } } } .CE .SH "SEE ALSO" namespace(n), upvar(n) .SH KEYWORDS context, level, namespace, stack frame, variables tcl8.4.20/doc/http.n0000644003604700454610000004770711737050674012641 0ustar dgp771div'\" '\" Copyright (c) 1995-1997 Sun Microsystems, Inc. '\" Copyright (c) 1998-2000 by Ajuba Solutions. '\" Copyright (c) 2004 ActiveState Corporation. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH "http" n 2.5 http "Tcl Bundled Packages" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME http \- Client-side implementation of the HTTP/1.0 protocol. .SH SYNOPSIS \fBpackage require http ?2.5?\fR .sp \fB::http::config \fI?options?\fR .sp \fB::http::geturl \fIurl ?options?\fR .sp \fB::http::formatQuery\fP \fIkey value\fP ?\fIkey value\fP ...? .sp \fB::http::reset\fP \fItoken\fP ?\fIwhy\fP? .sp \fB::http::wait \fItoken\fR .sp \fB::http::status \fItoken\fR .sp \fB::http::size \fItoken\fR .sp \fB::http::code \fItoken\fR .sp \fB::http::ncode \fItoken\fR .sp \fB::http::meta \fItoken\fR .sp \fB::http::data \fItoken\fR .sp \fB::http::error \fItoken\fR .sp \fB::http::cleanup \fItoken\fR .sp \fB::http::register \fIproto port command\fR .sp \fB::http::unregister \fIproto\fR .BE .SH DESCRIPTION .PP The \fBhttp\fR package provides the client side of the HTTP/1.0 protocol. The package implements the GET, POST, and HEAD operations of HTTP/1.0. It allows configuration of a proxy host to get through firewalls. The package is compatible with the \fBSafesock\fR security policy, so it can be used by untrusted applets to do URL fetching from a restricted set of hosts. This package can be extended to support additional HTTP transport protocols, such as HTTPS, by providing a custom \fBsocket\fR command, via \fB::http::register\fR. .PP The \fB::http::geturl\fR procedure does a HTTP transaction. Its \fIoptions \fR determine whether a GET, POST, or HEAD transaction is performed. The return value of \fB::http::geturl\fR is a token for the transaction. The value is also the name of an array in the ::http namespace that contains state information about the transaction. The elements of this array are described in the STATE ARRAY section. .PP If the \fB-command\fP option is specified, then the HTTP operation is done in the background. \fB::http::geturl\fR returns immediately after generating the HTTP request and the callback is invoked when the transaction completes. For this to work, the Tcl event loop must be active. In Tk applications this is always true. For pure-Tcl applications, the caller can use \fB::http::wait\fR after calling \fB::http::geturl\fR to start the event loop. .SH COMMANDS .TP \fB::http::config\fP ?\fIoptions\fR? The \fB::http::config\fR command is used to set and query the name of the proxy server and port, and the User-Agent name used in the HTTP requests. If no options are specified, then the current configuration is returned. If a single argument is specified, then it should be one of the flags described below. In this case the current value of that setting is returned. Otherwise, the options should be a set of flags and values that define the configuration: .RS .TP \fB\-accept\fP \fImimetypes\fP The Accept header of the request. The default is */*, which means that all types of documents are accepted. Otherwise you can supply a comma-separated list of mime type patterns that you are willing to receive. For example, "image/gif, image/jpeg, text/*". .TP \fB\-proxyhost\fP \fIhostname\fP The name of the proxy host, if any. If this value is the empty string, the URL host is contacted directly. .TP \fB\-proxyport\fP \fInumber\fP The proxy port number. .TP \fB\-proxyfilter\fP \fIcommand\fP The command is a callback that is made during \fB::http::geturl\fR to determine if a proxy is required for a given host. One argument, a host name, is added to \fIcommand\fR when it is invoked. If a proxy is required, the callback should return a two-element list containing the proxy server and proxy port. Otherwise the filter should return an empty list. The default filter returns the values of the \fB\-proxyhost\fR and \fB\-proxyport\fR settings if they are non-empty. .TP \fB\-urlencoding\fP \fIencoding\fP The \fIencoding\fR used for creating the x-url-encoded URLs with \fB::http::formatQuery\fR. The default is \fButf-8\fR, as specified by RFC 2718. Prior to http 2.5 this was unspecified, and that behavior can be returned by specifying the empty string (\fB{}\fR), although \fIiso8859-1\fR is recommended to restore similar behavior but without the \fB::http::formatQuery\fR throwing an error processing non-latin-1 characters. .TP \fB\-useragent\fP \fIstring\fP The value of the User-Agent header in the HTTP request. The default is \fB"Tcl http client package 2.4."\fR .RE .TP \fB::http::geturl\fP \fIurl\fP ?\fIoptions\fP? The \fB::http::geturl\fR command is the main procedure in the package. The \fB\-query\fR option causes a POST operation and the \fB\-validate\fR option causes a HEAD operation; otherwise, a GET operation is performed. The \fB::http::geturl\fR command returns a \fItoken\fR value that can be used to get information about the transaction. See the STATE ARRAY and ERRORS section for details. The \fB::http::geturl\fR command blocks until the operation completes, unless the \fB\-command\fR option specifies a callback that is invoked when the HTTP transaction completes. \fB::http::geturl\fR takes several options: .RS .TP \fB\-binary\fP \fIboolean\fP Specifies whether to force interpreting the URL data as binary. Normally this is auto-detected (anything not beginning with a \fBtext\fR content type or whose content encoding is \fBgzip\fR or \fBcompress\fR is considered binary data). .TP \fB\-blocksize\fP \fIsize\fP The block size used when reading the URL. At most \fIsize\fR bytes are read at once. After each block, a call to the \fB\-progress\fR callback is made (if that option is specified). .TP \fB\-channel\fP \fIname\fP Copy the URL contents to channel \fIname\fR instead of saving it in \fBstate(body)\fR. .TP \fB\-command\fP \fIcallback\fP Invoke \fIcallback\fP after the HTTP transaction completes. This option causes \fB::http::geturl\fP to return immediately. The \fIcallback\fP gets an additional argument that is the \fItoken\fR returned from \fB::http::geturl\fR. This token is the name of an array that is described in the STATE ARRAY section. Here is a template for the callback: .RS .CS proc httpCallback {token} { upvar #0 $token state # Access state as a Tcl array } .CE .RE .TP \fB\-handler\fP \fIcallback\fP Invoke \fIcallback\fP whenever HTTP data is available; if present, nothing else will be done with the HTTP data. This procedure gets two additional arguments: the socket for the HTTP data and the \fItoken\fR returned from \fB::http::geturl\fR. The token is the name of a global array that is described in the STATE ARRAY section. The procedure is expected to return the number of bytes read from the socket. Here is a template for the callback: .RS .CS proc httpHandlerCallback {socket token} { upvar #0 $token state # Access socket, and state as a Tcl array ... (example: set data [read $socket 1000];set nbytes [string length $data]) ... return nbytes } .CE .RE .TP \fB\-headers\fP \fIkeyvaluelist\fP This option is used to add extra headers to the HTTP request. The \fIkeyvaluelist\fR argument must be a list with an even number of elements that alternate between keys and values. The keys become header field names. Newlines are stripped from the values so the header cannot be corrupted. For example, if \fIkeyvaluelist\fR is \fBPragma no-cache\fR then the following header is included in the HTTP request: .CS Pragma: no-cache .CE .TP \fB\-progress\fP \fIcallback\fP The \fIcallback\fR is made after each transfer of data from the URL. The callback gets three additional arguments: the \fItoken\fR from \fB::http::geturl\fR, the expected total size of the contents from the \fBContent-Length\fR meta-data, and the current number of bytes transferred so far. The expected total size may be unknown, in which case zero is passed to the callback. Here is a template for the progress callback: .RS .CS proc httpProgress {token total current} { upvar #0 $token state } .CE .RE .TP \fB\-query\fP \fIquery\fP This flag causes \fB::http::geturl\fR to do a POST request that passes the \fIquery\fR to the server. The \fIquery\fR must be an x-url-encoding formatted query. The \fB::http::formatQuery\fR procedure can be used to do the formatting. .TP \fB\-queryblocksize\fP \fIsize\fP The block size used when posting query data to the URL. At most \fIsize\fR bytes are written at once. After each block, a call to the \fB\-queryprogress\fR callback is made (if that option is specified). .TP \fB\-querychannel\fP \fIchannelID\fP This flag causes \fB::http::geturl\fR to do a POST request that passes the data contained in \fIchannelID\fR to the server. The data contained in \fIchannelID\fR must be an x-url-encoding formatted query unless the \fB\-type\fP option below is used. If a Content-Length header is not specified via the \fB\-headers\fR options, \fB::http::geturl\fR attempts to determine the size of the post data in order to create that header. If it is unable to determine the size, it returns an error. .TP \fB\-queryprogress\fP \fIcallback\fP The \fIcallback\fR is made after each transfer of data to the URL (i.e. POST) and acts exactly like the \fB\-progress\fR option (the callback format is the same). .TP \fB\-timeout\fP \fImilliseconds\fP If \fImilliseconds\fR is non-zero, then \fB::http::geturl\fR sets up a timeout to occur after the specified number of milliseconds. A timeout results in a call to \fB::http::reset\fP and to the \fB-command\fP callback, if specified. The return value of \fB::http::status\fP is \fBtimeout\fP after a timeout has occurred. .TP \fB\-type\fP \fImime-type\fP Use \fImime-type\fR as the \fBContent-Type\fR value, instead of the default value (\fBapplication/x-www-form-urlencoded\fR) during a POST operation. .TP \fB\-validate\fP \fIboolean\fP If \fIboolean\fR is non-zero, then \fB::http::geturl\fR does an HTTP HEAD request. This request returns meta information about the URL, but the contents are not returned. The meta information is available in the \fBstate(meta) \fR variable after the transaction. See the STATE ARRAY section for details. .RE .TP \fB::http::formatQuery\fP \fIkey value\fP ?\fIkey value\fP ...? This procedure does x-url-encoding of query data. It takes an even number of arguments that are the keys and values of the query. It encodes the keys and values, and generates one string that has the proper & and = separators. The result is suitable for the \fB\-query\fR value passed to \fB::http::geturl\fR. .TP \fB::http::reset\fP \fItoken\fP ?\fIwhy\fP? This command resets the HTTP transaction identified by \fItoken\fR, if any. This sets the \fBstate(status)\fP value to \fIwhy\fP, which defaults to \fBreset\fR, and then calls the registered \fB\-command\fR callback. .TP \fB::http::wait\fP \fItoken\fP This is a convenience procedure that blocks and waits for the transaction to complete. This only works in trusted code because it uses \fBvwait\fR. Also, it's not useful for the case where \fB::http::geturl\fP is called \fIwithout\fP the \fB-command\fP option because in this case the \fB::http::geturl\fP call doesn't return until the HTTP transaction is complete, and thus there's nothing to wait for. .TP \fB::http::data\fP \fItoken\fP This is a convenience procedure that returns the \fBbody\fP element (i.e., the URL data) of the state array. .TP \fB::http::error\fP \fItoken\fP This is a convenience procedure that returns the \fBerror\fP element of the state array. .TP \fB::http::status\fP \fItoken\fP This is a convenience procedure that returns the \fBstatus\fP element of the state array. .TP \fB::http::code\fP \fItoken\fP This is a convenience procedure that returns the \fBhttp\fP element of the state array. .TP \fB::http::ncode\fP \fItoken\fP This is a convenience procedure that returns just the numeric return code (200, 404, etc.) from the \fBhttp\fP element of the state array. .TP \fB::http::size\fP \fItoken\fP This is a convenience procedure that returns the \fBcurrentsize\fP element of the state array, which represents the number of bytes received from the URL in the \fB::http::geturl\fP call. .TP \fB::http::meta\fP \fItoken\fP This is a convenience procedure that returns the \fBmeta\fP element of the state array which contains the HTTP response headers. See below for an explanation of this element. .TP \fB::http::cleanup\fP \fItoken\fP This procedure cleans up the state associated with the connection identified by \fItoken\fP. After this call, the procedures like \fB::http::data\fP cannot be used to get information about the operation. It is \fIstrongly\fP recommended that you call this function after you're done with a given HTTP request. Not doing so will result in memory not being freed, and if your app calls \fB::http::geturl\fP enough times, the memory leak could cause a performance hit...or worse. .TP \fB::http::register\fP \fIproto port command\fP This procedure allows one to provide custom HTTP transport types such as HTTPS, by registering a prefix, the default port, and the command to execute to create the Tcl \fBchannel\fR. E.g.: .RS .CS package require http package require tls ::http::register https 443 ::tls::socket set token [::http::geturl https://my.secure.site/] .CE .RE .TP \fB::http::unregister\fP \fIproto\fP This procedure unregisters a protocol handler that was previously registered via \fB::http::register\fR. .SH "ERRORS" The \fB::http::geturl\fP procedure will raise errors in the following cases: invalid command line options, an invalid URL, a URL on a non-existent host, or a URL at a bad port on an existing host. These errors mean that it cannot even start the network transaction. It will also raise an error if it gets an I/O error while writing out the HTTP request header. For synchronous \fB::http::geturl\fP calls (where \fB-command\fP is not specified), it will raise an error if it gets an I/O error while reading the HTTP reply headers or data. Because \fB::http::geturl\fP doesn't return a token in these cases, it does all the required cleanup and there's no issue of your app having to call \fB::http::cleanup\fP. .PP For asynchronous \fB::http::geturl\fP calls, all of the above error situations apply, except that if there's any error while reading the HTTP reply headers or data, no exception is thrown. This is because after writing the HTTP headers, \fB::http::geturl\fP returns, and the rest of the HTTP transaction occurs in the background. The command callback can check if any error occurred during the read by calling \fB::http::status\fP to check the status and if its \fIerror\fP, calling \fB::http::error\fP to get the error message. .PP Alternatively, if the main program flow reaches a point where it needs to know the result of the asynchronous HTTP request, it can call \fB::http::wait\fP and then check status and error, just as the callback does. .PP In any case, you must still call \fB::http::cleanup\fP to delete the state array when you're done. .PP There are other possible results of the HTTP transaction determined by examining the status from \fB::http::status\fP. These are described below. .TP ok If the HTTP transaction completes entirely, then status will be \fBok\fP. However, you should still check the \fB::http::code\fP value to get the HTTP status. The \fB::http::ncode\fP procedure provides just the numeric error (e.g., 200, 404 or 500) while the \fB::http::code\fP procedure returns a value like "HTTP 404 File not found". .TP eof If the server closes the socket without replying, then no error is raised, but the status of the transaction will be \fBeof\fP. .TP error The error message will also be stored in the \fBerror\fP status array element, accessible via \fB::http::error\fP. .PP Another error possibility is that \fB::http::geturl\fP is unable to write all the post query data to the server before the server responds and closes the socket. The error message is saved in the \fBposterror\fP status array element and then \fB::http::geturl\fP attempts to complete the transaction. If it can read the server's response it will end up with an \fBok\fP status, otherwise it will have an \fBeof\fP status. .SH "STATE ARRAY" The \fB::http::geturl\fR procedure returns a \fItoken\fR that can be used to get to the state of the HTTP transaction in the form of a Tcl array. Use this construct to create an easy-to-use array variable: .CS upvar #0 $token state .CE Once the data associated with the URL is no longer needed, the state array should be unset to free up storage. The \fB::http::cleanup\fP procedure is provided for that purpose. The following elements of the array are supported: .RS .TP \fBbody\fR The contents of the URL. This will be empty if the \fB\-channel\fR option has been specified. This value is returned by the \fB::http::data\fP command. .TP \fBcharset\fR The value of the charset attribute from the \fBContent-Type\fR meta-data value. If none was specified, this defaults to the RFC standard \fBiso8859-1\fR, or the value of \fB$::http::defaultCharset\fR. Incoming text data will be automatically converted from this charset to utf-8. .TP \fBcoding\fR A copy of the \fBContent-Encoding\fR meta-data value. .TP \fBcurrentsize\fR The current number of bytes fetched from the URL. This value is returned by the \fB::http::size\fP command. .TP \fBerror\fR If defined, this is the error string seen when the HTTP transaction was aborted. .TP \fBhttp\fR The HTTP status reply from the server. This value is returned by the \fB::http::code\fP command. The format of this value is: .RS .CS \fIHTTP/1.0 code string\fP .CE The \fIcode\fR is a three-digit number defined in the HTTP standard. A code of 200 is OK. Codes beginning with 4 or 5 indicate errors. Codes beginning with 3 are redirection errors. In this case the \fBLocation\fR meta-data specifies a new URL that contains the requested information. .RE .TP \fBmeta\fR The HTTP protocol returns meta-data that describes the URL contents. The \fBmeta\fR element of the state array is a list of the keys and values of the meta-data. This is in a format useful for initializing an array that just contains the meta-data: .RS .CS array set meta $state(meta) .CE Some of the meta-data keys are listed below, but the HTTP standard defines more, and servers are free to add their own. .TP \fBContent-Type\fR The type of the URL contents. Examples include \fBtext/html\fR, \fBimage/gif,\fR \fBapplication/postscript\fR and \fBapplication/x-tcl\fR. .TP \fBContent-Length\fR The advertised size of the contents. The actual size obtained by \fB::http::geturl\fR is available as \fBstate(size)\fR. .TP \fBLocation\fR An alternate URL that contains the requested data. .RE .TP \fBposterror\fR The error, if any, that occurred while writing the post query data to the server. .TP \fBstatus\fR Either \fBok\fR, for successful completion, \fBreset\fR for user-reset, \fBtimeout\fP if a timeout occurred before the transaction could complete, or \fBerror\fR for an error condition. During the transaction this value is the empty string. .TP \fBtotalsize\fR A copy of the \fBContent-Length\fR meta-data value. .TP \fBtype\fR A copy of the \fBContent-Type\fR meta-data value. .TP \fBurl\fR The requested URL. .RE .SH EXAMPLE .CS # Copy a URL to a file and print meta-data proc httpcopy { url file {chunk 4096} } { set out [open $file w] set token [\fB::http::geturl\fR $url -channel $out \\ -progress httpCopyProgress -blocksize $chunk] close $out # This ends the line started by httpCopyProgress puts stderr "" upvar #0 $token state set max 0 foreach {name value} $state(meta) { if {[string length $name] > $max} { set max [string length $name] } if {[regexp -nocase ^location$ $name]} { # Handle URL redirects puts stderr "Location:$value" return [httpcopy [string trim $value] $file $chunk] } } incr max foreach {name value} $state(meta) { puts [format "%-*s %s" $max $name: $value] } return $token } proc httpCopyProgress {args} { puts -nonewline stderr . flush stderr } .CE .SH "SEE ALSO" safe(n), socket(n), safesock(n) .SH KEYWORDS security policy, socket tcl8.4.20/doc/SourceRCFile.30000644003604700454610000000147012052456743014035 0ustar dgp771div'\" '\" Copyright (c) 1998-2000 by Scriptics Corporation. '\" All rights reserved. '\" .so man.macros .TH Tcl_SourceRCFile 3 8.3 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_SourceRCFile \- source the Tcl rc file .SH SYNOPSIS .nf \fB#include \fR .sp void \fBTcl_SourceRCFile\fR(\fIinterp\fR) .SH ARGUMENTS .AP Tcl_Interp *interp in Tcl interpreter to source rc file into. .BE .SH DESCRIPTION .PP \fBTcl_SourceRCFile\fR is used to source the Tcl rc file at startup. It is typically invoked by Tcl_Main or Tk_Main. The name of the file sourced is obtained from the global variable \fBtcl_rcFileName\fR in the interpreter given by \fIinterp\fR. If this variable is not defined, or if the file it indicates cannot be found, no action is taken. .SH KEYWORDS application-specific initialization, main program, rc file tcl8.4.20/doc/package.n0000644003604700454610000002301011737050674013232 0ustar dgp771div'\" '\" Copyright (c) 1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH package n 7.5 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME package \- Facilities for package loading and version control .SH SYNOPSIS .nf \fBpackage forget ?\fIpackage package ...\fR? \fBpackage ifneeded \fIpackage version\fR ?\fIscript\fR? \fBpackage names\fR \fBpackage present \fR?\fB\-exact\fR? \fIpackage \fR?\fIversion\fR? \fBpackage provide \fIpackage \fR?\fIversion\fR? \fBpackage require \fR?\fB\-exact\fR? \fIpackage \fR?\fIversion\fR? \fBpackage unknown \fR?\fIcommand\fR? \fBpackage vcompare \fIversion1 version2\fR \fBpackage versions \fIpackage\fR \fBpackage vsatisfies \fIversion1 version2\fR .fi .BE .SH DESCRIPTION .PP This command keeps a simple database of the packages available for use by the current interpreter and how to load them into the interpreter. It supports multiple versions of each package and arranges for the correct version of a package to be loaded based on what is needed by the application. This command also detects and reports version clashes. Typically, only the \fBpackage require\fR and \fBpackage provide\fR commands are invoked in normal Tcl scripts; the other commands are used primarily by system scripts that maintain the package database. .PP The behavior of the \fBpackage\fR command is determined by its first argument. The following forms are permitted: .TP \fBpackage forget ?\fIpackage package ...\fR? Removes all information about each specified package from this interpreter, including information provided by both \fBpackage ifneeded\fR and \fBpackage provide\fR. .TP \fBpackage ifneeded \fIpackage version\fR ?\fIscript\fR? This command typically appears only in system configuration scripts to set up the package database. It indicates that a particular version of a particular package is available if needed, and that the package can be added to the interpreter by executing \fIscript\fR. The script is saved in a database for use by subsequent \fBpackage require\fR commands; typically, \fIscript\fR sets up auto-loading for the commands in the package (or calls \fBload\fR and/or \fBsource\fR directly), then invokes \fBpackage provide\fR to indicate that the package is present. There may be information in the database for several different versions of a single package. If the database already contains information for \fIpackage\fR and \fIversion\fR, the new \fIscript\fR replaces the existing one. If the \fIscript\fR argument is omitted, the current script for version \fIversion\fR of package \fIpackage\fR is returned, or an empty string if no \fBpackage ifneeded\fR command has been invoked for this \fIpackage\fR and \fIversion\fR. .TP \fBpackage names\fR Returns a list of the names of all packages in the interpreter for which a version has been provided (via \fBpackage provide\fR) or for which a \fBpackage ifneeded\fR script is available. The order of elements in the list is arbitrary. .TP \fBpackage present \fR?\fB\-exact\fR? \fIpackage \fR?\fIversion\fR? This command is equivalent to \fBpackage require\fR except that it does not try and load the package if it is not already loaded. .TP \fBpackage provide \fIpackage \fR?\fIversion\fR? This command is invoked to indicate that version \fIversion\fR of package \fIpackage\fR is now present in the interpreter. It is typically invoked once as part of an \fBifneeded\fR script, and again by the package itself when it is finally loaded. An error occurs if a different version of \fIpackage\fR has been provided by a previous \fBpackage provide\fR command. If the \fIversion\fR argument is omitted, then the command returns the version number that is currently provided, or an empty string if no \fBpackage provide\fR command has been invoked for \fIpackage\fR in this interpreter. .TP \fBpackage require \fR?\fB\-exact\fR? \fIpackage \fR?\fIversion\fR? This command is typically invoked by Tcl code that wishes to use a particular version of a particular package. The arguments indicate which package is wanted, and the command ensures that a suitable version of the package is loaded into the interpreter. If the command succeeds, it returns the version number that is loaded; otherwise it generates an error. If both the \fB\-exact\fR switch and the \fIversion\fR argument are specified then only the given version is acceptable. If \fB\-exact\fR is omitted but \fIversion\fR is specified, then versions later than \fIversion\fR are also acceptable as long as they have the same major version number as \fIversion\fR. If both \fB\-exact\fR and \fIversion\fR are omitted then any version whatsoever is acceptable. If a version of \fIpackage\fR has already been provided (by invoking the \fBpackage provide\fR command), then its version number must satisfy the criteria given by \fB\-exact\fR and \fIversion\fR and the command returns immediately. Otherwise, the command searches the database of information provided by previous \fBpackage ifneeded\fR commands to see if an acceptable version of the package is available. If so, the script for the highest acceptable version number is evaluated in the global namespace; it must do whatever is necessary to load the package, including calling \fBpackage provide\fR for the package. If the \fBpackage ifneeded\fR database does not contain an acceptable version of the package and a \fBpackage unknown\fR command has been specified for the interpreter then that command is evaluated in the global namespace; when it completes, Tcl checks again to see if the package is now provided or if there is a \fBpackage ifneeded\fR script for it. If all of these steps fail to provide an acceptable version of the package, then the command returns an error. .TP \fBpackage unknown \fR?\fIcommand\fR? This command supplies a ``last resort'' command to invoke during \fBpackage require\fR if no suitable version of a package can be found in the \fBpackage ifneeded\fR database. If the \fIcommand\fR argument is supplied, it contains the first part of a command; when the command is invoked during a \fBpackage require\fR command, Tcl appends two additional arguments giving the desired package name and version. For example, if \fIcommand\fR is \fBfoo bar\fR and later the command \fBpackage require test 2.4\fR is invoked, then Tcl will execute the command \fBfoo bar test 2.4\fR to load the package. If no version number is supplied to the \fBpackage require\fR command, then the version argument for the invoked command will be an empty string. If the \fBpackage unknown\fR command is invoked without a \fIcommand\fR argument, then the current \fBpackage unknown\fR script is returned, or an empty string if there is none. If \fIcommand\fR is specified as an empty string, then the current \fBpackage unknown\fR script is removed, if there is one. .TP \fBpackage vcompare \fIversion1 version2\fR Compares the two version numbers given by \fIversion1\fR and \fIversion2\fR. Returns -1 if \fIversion1\fR is an earlier version than \fIversion2\fR, 0 if they are equal, and 1 if \fIversion1\fR is later than \fBversion2\fR. .TP \fBpackage versions \fIpackage\fR Returns a list of all the version numbers of \fIpackage\fR for which information has been provided by \fBpackage ifneeded\fR commands. .TP \fBpackage vsatisfies \fIversion1 version2\fR Returns 1 if scripts written for \fIversion2\fR will work unchanged with \fIversion1\fR (i.e. \fIversion1\fR is equal to or greater than \fIversion2\fR and they both have the same major version number), 0 otherwise. .SH "VERSION NUMBERS" .PP Version numbers consist of one or more decimal numbers separated by dots, such as 2 or 1.162 or 3.1.13.1. The first number is called the major version number. Larger numbers correspond to later versions of a package, with leftmost numbers having greater significance. For example, version 2.1 is later than 1.3 and version 3.4.6 is later than 3.3.5. Missing fields are equivalent to zeroes: version 1.3 is the same as version 1.3.0 and 1.3.0.0, so it is earlier than 1.3.1 or 1.3.0.2. A later version number is assumed to be upwards compatible with an earlier version number as long as both versions have the same major version number. For example, Tcl scripts written for version 2.3 of a package should work unchanged under versions 2.3.2, 2.4, and 2.5.1. Changes in the major version number signify incompatible changes: if code is written to use version 2.1 of a package, it is not guaranteed to work unmodified with either version 1.7.3 or version 3.1. .SH "PACKAGE INDICES" .PP The recommended way to use packages in Tcl is to invoke \fBpackage require\fR and \fBpackage provide\fR commands in scripts, and use the procedure \fBpkg_mkIndex\fR to create package index files. Once you've done this, packages will be loaded automatically in response to \fBpackage require\fR commands. See the documentation for \fBpkg_mkIndex\fR for details. .SH EXAMPLES To state that a Tcl script requires the Tk and http packages, put this at the top of the script: .CS \fBpackage require\fR Tk \fBpackage require\fR http .CE .PP To test to see if the Snack package is available and load if it is (often useful for optional enhancements to programs where the loss of the functionality is not critical) do this: .CS if {[catch {\fBpackage require\fR Snack}]} { # Error thrown - package not found. # Set up a dummy interface to work around the absence } else { # We have the package, configure the app to use it } .CE .SH "SEE ALSO" msgcat(n), packagens(n), pkgMkIndex(n) .SH KEYWORDS package, version tcl8.4.20/doc/CrtCloseHdlr.30000644003604700454610000000337111737050674014104 0ustar dgp771div'\" '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_CreateCloseHandler 3 7.5 Tcl "Tcl Library Procedures" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME Tcl_CreateCloseHandler, Tcl_DeleteCloseHandler \- arrange for callbacks when channels are closed .SH SYNOPSIS .nf \fB#include \fR .sp void \fBTcl_CreateCloseHandler\fR(\fIchannel, proc, clientData\fR) .sp void \fBTcl_DeleteCloseHandler\fR(\fIchannel, proc, clientData\fR) .sp .SH ARGUMENTS .AS Tcl_CloseProc callbackData in .AP Tcl_Channel channel in The channel for which to create or delete a close callback. .AP Tcl_CloseProc *proc in The procedure to call as the callback. .AP ClientData clientData in Arbitrary one-word value to pass to \fIproc\fR. .BE .SH DESCRIPTION .PP \fBTcl_CreateCloseHandler\fR arranges for \fIproc\fR to be called when \fIchannel\fR is closed with \fBTcl_Close\fR or \fBTcl_UnregisterChannel\fR, or using the Tcl \fBclose\fR command. \fIProc\fR should match the following prototype: .PP .CS typedef void Tcl_CloseProc( ClientData \fIclientData\fR); .CE .PP The \fIclientData\fR is the same as the value provided in the call to \fBTcl_CreateCloseHandler\fR. .PP \fBTcl_DeleteCloseHandler\fR removes a close callback for \fIchannel\fR. The \fIproc\fR and \fIclientData\fR identify which close callback to remove; \fBTcl_DeleteCloseHandler\fR does nothing if its \fIproc\fR and \fIclientData\fR arguments do not match the \fIproc\fR and \fIclientData\fR for a close handler for \fIchannel\fR. .SH "SEE ALSO" close(n), Tcl_Close(3), Tcl_UnregisterChannel(3) .SH KEYWORDS callback, channel closing tcl8.4.20/doc/proc.n0000644003604700454610000000726511737050674012620 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH proc n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME proc \- Create a Tcl procedure .SH SYNOPSIS \fBproc \fIname args body\fR .BE .SH DESCRIPTION .PP The \fBproc\fR command creates a new Tcl procedure named \fIname\fR, replacing any existing command or procedure there may have been by that name. Whenever the new command is invoked, the contents of \fIbody\fR will be executed by the Tcl interpreter. Normally, \fIname\fR is unqualified (does not include the names of any containing namespaces), and the new procedure is created in the current namespace. If \fIname\fR includes any namespace qualifiers, the procedure is created in the specified namespace. \fIArgs\fR specifies the formal arguments to the procedure. It consists of a list, possibly empty, each of whose elements specifies one argument. Each argument specifier is also a list with either one or two fields. If there is only a single field in the specifier then it is the name of the argument; if there are two fields, then the first is the argument name and the second is its default value. .PP When \fIname\fR is invoked a local variable will be created for each of the formal arguments to the procedure; its value will be the value of corresponding argument in the invoking command or the argument's default value. Arguments with default values need not be specified in a procedure invocation. However, there must be enough actual arguments for all the formal arguments that don't have defaults, and there must not be any extra actual arguments. There is one special case to permit procedures with variable numbers of arguments. If the last formal argument has the name \fBargs\fR, then a call to the procedure may contain more actual arguments than the procedure has formals. In this case, all of the actual arguments starting at the one that would be assigned to \fBargs\fR are combined into a list (as if the \fBlist\fR command had been used); this combined value is assigned to the local variable \fBargs\fR. .PP When \fIbody\fR is being executed, variable names normally refer to local variables, which are created automatically when referenced and deleted when the procedure returns. One local variable is automatically created for each of the procedure's arguments. Global variables can only be accessed by invoking the \fBglobal\fR command or the \fBupvar\fR command. Namespace variables can only be accessed by invoking the \fBvariable\fR command or the \fBupvar\fR command. .PP The \fBproc\fR command returns an empty string. When a procedure is invoked, the procedure's return value is the value specified in a \fBreturn\fR command. If the procedure doesn't execute an explicit \fBreturn\fR, then its return value is the value of the last command executed in the procedure's body. If an error occurs while executing the procedure body, then the procedure-as-a-whole will return that same error. .SH EXAMPLES This is a procedure that accepts arbitrarily many arguments and prints them out, one by one. .CS \fBproc\fR printArguments args { foreach arg $args { puts $arg } } .CE .PP This procedure is a bit like the \fBincr\fR command, except it multiplies the contents of the named variable by the value, which defaults to \fB2\fR: .CS \fBproc\fR mult {varName {multiplier 2}} { upvar 1 $varName var set var [expr {$var * $multiplier}] } .CE .SH "SEE ALSO" info(n), unknown(n) .SH KEYWORDS argument, procedure tcl8.4.20/doc/regexp.n0000644003604700454610000001425011737050674013137 0ustar dgp771div'\" '\" Copyright (c) 1998 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH regexp n 8.3 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME regexp \- Match a regular expression against a string .SH SYNOPSIS \fBregexp \fR?\fIswitches\fR? \fIexp string \fR?\fImatchVar\fR? ?\fIsubMatchVar subMatchVar ...\fR? .BE .SH DESCRIPTION .PP Determines whether the regular expression \fIexp\fR matches part or all of \fIstring\fR and returns 1 if it does, 0 if it doesn't, unless \fB-inline\fR is specified (see below). (Regular expression matching is described in the \fBre_syntax\fR reference page.) .LP If additional arguments are specified after \fIstring\fR then they are treated as the names of variables in which to return information about which part(s) of \fIstring\fR matched \fIexp\fR. \fIMatchVar\fR will be set to the range of \fIstring\fR that matched all of \fIexp\fR. The first \fIsubMatchVar\fR will contain the characters in \fIstring\fR that matched the leftmost parenthesized subexpression within \fIexp\fR, the next \fIsubMatchVar\fR will contain the characters that matched the next parenthesized subexpression to the right in \fIexp\fR, and so on. .PP If the initial arguments to \fBregexp\fR start with \fB\-\fR then they are treated as switches. The following switches are currently supported: .TP 15 \fB\-about\fR Instead of attempting to match the regular expression, returns a list containing information about the regular expression. The first element of the list is a subexpression count. The second element is a list of property names that describe various attributes of the regular expression. This switch is primarily intended for debugging purposes. .TP 15 \fB\-expanded\fR Enables use of the expanded regular expression syntax where whitespace and comments are ignored. This is the same as specifying the \fB(?x)\fR embedded option (see the \fBre_syntax\fR manual page). .TP 15 \fB\-indices\fR Changes what is stored in the \fIsubMatchVar\fRs. Instead of storing the matching characters from \fIstring\fR, each variable will contain a list of two decimal strings giving the indices in \fIstring\fR of the first and last characters in the matching range of characters. .TP 15 \fB\-line\fR Enables newline-sensitive matching. By default, newline is a completely ordinary character with no special meaning. With this flag, `[^' bracket expressions and `.' never match newline, `^' matches an empty string after any newline in addition to its normal function, and `$' matches an empty string before any newline in addition to its normal function. This flag is equivalent to specifying both \fB\-linestop\fR and \fB\-lineanchor\fR, or the \fB(?n)\fR embedded option (see the \fBre_syntax\fR manual page). .TP 15 \fB\-linestop\fR Changes the behavior of `[^' bracket expressions and `.' so that they stop at newlines. This is the same as specifying the \fB(?p)\fR embedded option (see the \fBre_syntax\fR manual page). .TP 15 \fB\-lineanchor\fR Changes the behavior of `^' and `$' (the ``anchors'') so they match the beginning and end of a line respectively. This is the same as specifying the \fB(?w)\fR embedded option (see the \fBre_syntax\fR manual page). .TP 15 \fB\-nocase\fR Causes upper-case characters in \fIstring\fR to be treated as lower case during the matching process. .VS 8.3 .TP 15 \fB\-all\fR Causes the regular expression to be matched as many times as possible in the string, returning the total number of matches found. If this is specified with match variables, they will contain information for the last match only. .TP 15 \fB\-inline\fR Causes the command to return, as a list, the data that would otherwise be placed in match variables. When using \fB-inline\fR, match variables may not be specified. If used with \fB-all\fR, the list will be concatenated at each iteration, such that a flat list is always returned. For each match iteration, the command will append the overall match data, plus one element for each subexpression in the regular expression. Examples are: .CS regexp -inline -- {\\w(\\w)} " inlined " => {in n} regexp -all -inline -- {\\w(\\w)} " inlined " => {in n li i ne e} .CE .TP 15 \fB\-start\fR \fIindex\fR Specifies a character index offset into the string to start matching the regular expression at. When using this switch, `^' will not match the beginning of the line, and \\A will still match the start of the string at \fIindex\fR. If \fB\-indices\fR is specified, the indices will be indexed starting from the absolute beginning of the input string. \fIindex\fR will be constrained to the bounds of the input string. .VE 8.3 .TP 15 \fB\-\|\-\fR Marks the end of switches. The argument following this one will be treated as \fIexp\fR even if it starts with a \fB\-\fR. .PP If there are more \fIsubMatchVar\fR's than parenthesized subexpressions within \fIexp\fR, or if a particular subexpression in \fIexp\fR doesn't match the string (e.g. because it was in a portion of the expression that wasn't matched), then the corresponding \fIsubMatchVar\fR will be set to ``\fB\-1 \-1\fR'' if \fB\-indices\fR has been specified or to an empty string otherwise. .SH EXAMPLES Find the first occurrence of a word starting with \fBfoo\fR in a string that is not actually an instance of \fBfoobar\fR, and get the letters following it up to the end of the word into a variable: .CS \fBregexp\fR {\\)(\\w*)} $string \-> restOfWord .CE Note that the whole matched substring has been placed in the variable \fB\->\fR which is a name chosen to look nice given that we are not actually interested in its contents. .PP Find the index of the word \fBbadger\fR (in any case) within a string and store that in the variable \fBlocation\fR: .CS \fBregexp\fR \-indices {(?i)\\} $string location .CE .PP Count the number of octal digits in a string: .CS \fBregexp\fR \-all {[0\-7]} $string .CE .PP List all words (consisting of all sequences of non-whitespace characters) in a string: .CS \fBregexp\fR \-all \-inline {\\S+} $string .CE .SH "SEE ALSO" re_syntax(n), regsub(n) .SH KEYWORDS match, regular expression, string tcl8.4.20/doc/ParseCmd.30000644003604700454610000005020311737050674013246 0ustar dgp771div'\" '\" Copyright (c) 1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_ParseCommand 3 8.3 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_ParseCommand, Tcl_ParseExpr, Tcl_ParseBraces, Tcl_ParseQuotedString, Tcl_ParseVarName, Tcl_ParseVar, Tcl_FreeParse, Tcl_EvalTokens, Tcl_EvalTokensStandard \- parse Tcl scripts and expressions .SH SYNOPSIS .nf \fB#include \fR .sp int \fBTcl_ParseCommand\fR(\fIinterp, string, numBytes, nested, parsePtr\fR) .sp int \fBTcl_ParseExpr\fR(\fIinterp, string, numBytes, parsePtr\fR) .sp int \fBTcl_ParseBraces\fR(\fIinterp, string, numBytes, parsePtr, append, termPtr\fR) .sp int \fBTcl_ParseQuotedString\fR(\fIinterp, string, numBytes, parsePtr, append, termPtr\fR) .sp int \fBTcl_ParseVarName\fR(\fIinterp, string, numBytes, parsePtr, append\fR) .sp CONST char * \fBTcl_ParseVar\fR(\fIinterp, string, termPtr\fR) .sp \fBTcl_FreeParse\fR(\fIusedParsePtr\fR) .sp Tcl_Obj * \fBTcl_EvalTokens\fR(\fIinterp, tokenPtr, numTokens\fR) .sp int \fBTcl_EvalTokensStandard\fR(\fIinterp, tokenPtr, numTokens\fR) .SH ARGUMENTS .AS Tcl_Interp *usedParsePtr .AP Tcl_Interp *interp out For procedures other than \fBTcl_FreeParse\fR, \fBTcl_EvalTokens\fR and \fBTcl_EvalTokensStandard\fR, used only for error reporting; if NULL, then no error messages are left after errors. For \fBTcl_EvalTokens\fR and \fBTcl_EvalTokensStandard\fR, determines the context for evaluating the script and also is used for error reporting; must not be NULL. .AP "CONST char" *string in Pointer to first character in string to parse. .AP int numBytes in Number of bytes in \fIstring\fR, not including any terminating null character. If less than 0 then the script consists of all characters in \fIstring\fR up to the first null character. .AP int nested in Non-zero means that the script is part of a command substitution so an unquoted close bracket should be treated as a command terminator. If zero, close brackets have no special meaning. .AP int append in Non-zero means that \fI*parsePtr\fR already contains valid tokens; the new tokens should be appended to those already present. Zero means that \fI*parsePtr\fR is uninitialized; any information in it is ignored. This argument is normally 0. .AP Tcl_Parse *parsePtr out Points to structure to fill in with information about the parsed command, expression, variable name, etc. Any previous information in this structure is ignored, unless \fIappend\fR is non-zero in a call to \fBTcl_ParseBraces\fR, \fBTcl_ParseQuotedString\fR, or \fBTcl_ParseVarName\fR. .AP "CONST char" **termPtr out If not NULL, points to a location where \fBTcl_ParseBraces\fR, \fBTcl_ParseQuotedString\fR, and \fBTcl_ParseVar\fR will store a pointer to the character just after the terminating character (the close-brace, the last character of the variable name, or the close-quote (respectively)) if the parse was successful. .AP Tcl_Parse *usedParsePtr in Points to structure that was filled in by a previous call to \fBTcl_ParseCommand\fR, \fBTcl_ParseExpr\fR, \fBTcl_ParseVarName\fR, etc. .BE .SH DESCRIPTION .PP These procedures parse Tcl commands or portions of Tcl commands such as expressions or references to variables. Each procedure takes a pointer to a script (or portion thereof) and fills in the structure pointed to by \fIparsePtr\fR with a collection of tokens describing the information that was parsed. The procedures normally return \fBTCL_OK\fR. However, if an error occurs then they return \fBTCL_ERROR\fR, leave an error message in \fIinterp's\fR result (if \fIinterp\fR is not NULL), and leave nothing in \fIparsePtr\fR. .PP \fBTcl_ParseCommand\fR is a procedure that parses Tcl scripts. Given a pointer to a script, it parses the first command from the script. If the command was parsed successfully, \fBTcl_ParseCommand\fR returns \fBTCL_OK\fR and fills in the structure pointed to by \fIparsePtr\fR with information about the structure of the command (see below for details). If an error occurred in parsing the command then \fBTCL_ERROR\fR is returned, an error message is left in \fIinterp\fR's result, and no information is left at \fI*parsePtr\fR. .PP \fBTcl_ParseExpr\fR parses Tcl expressions. Given a pointer to a script containing an expression, \fBTcl_ParseExpr\fR parses the expression. If the expression was parsed successfully, \fBTcl_ParseExpr\fR returns \fBTCL_OK\fR and fills in the structure pointed to by \fIparsePtr\fR with information about the structure of the expression (see below for details). If an error occurred in parsing the command then \fBTCL_ERROR\fR is returned, an error message is left in \fIinterp\fR's result, and no information is left at \fI*parsePtr\fR. .PP \fBTcl_ParseBraces\fR parses a string or command argument enclosed in braces such as \fB{hello}\fR or \fB{string \\t with \\t tabs}\fR from the beginning of its argument \fIstring\fR. The first character of \fIstring\fR must be \fB{\fR. If the braced string was parsed successfully, \fBTcl_ParseBraces\fR returns \fBTCL_OK\fR, fills in the structure pointed to by \fIparsePtr\fR with information about the structure of the string (see below for details), and stores a pointer to the character just after the terminating \fB}\fR in the location given by \fI*termPtr\fR. If an error occurs while parsing the string then \fBTCL_ERROR\fR is returned, an error message is left in \fIinterp\fR's result, and no information is left at \fI*parsePtr\fR or \fI*termPtr\fR. .PP \fBTcl_ParseQuotedString\fR parses a double-quoted string such as \fB"sum is [expr $a+$b]"\fR from the beginning of the argument \fIstring\fR. The first character of \fIstring\fR must be \fB"\fR. If the double-quoted string was parsed successfully, \fBTcl_ParseQuotedString\fR returns \fBTCL_OK\fR, fills in the structure pointed to by \fIparsePtr\fR with information about the structure of the string (see below for details), and stores a pointer to the character just after the terminating \fB"\fR in the location given by \fI*termPtr\fR. If an error occurs while parsing the string then \fBTCL_ERROR\fR is returned, an error message is left in \fIinterp\fR's result, and no information is left at \fI*parsePtr\fR or \fI*termPtr\fR. .PP \fBTcl_ParseVarName\fR parses a Tcl variable reference such as \fB$abc\fR or \fB$x([expr $index + 1])\fR from the beginning of its \fIstring\fR argument. The first character of \fIstring\fR must be \fB$\fR. If a variable name was parsed successfully, \fBTcl_ParseVarName\fR returns \fBTCL_OK\fR and fills in the structure pointed to by \fIparsePtr\fR with information about the structure of the variable name (see below for details). If an error occurs while parsing the command then \fBTCL_ERROR\fR is returned, an error message is left in \fIinterp\fR's result (if \fIinterp\fR isn't NULL), and no information is left at \fI*parsePtr\fR. .PP \fBTcl_ParseVar\fR parse a Tcl variable reference such as \fB$abc\fR or \fB$x([expr $index + 1])\fR from the beginning of its \fIstring\fR argument. The first character of \fIstring\fR must be \fB$\fR. If the variable name is parsed successfully, \fBTcl_ParseVar\fR returns a pointer to the string value of the variable. If an error occurs while parsing, then NULL is returned and an error message is left in \fIinterp\fR's result. .PP The information left at \fI*parsePtr\fR by \fBTcl_ParseCommand\fR, \fBTcl_ParseExpr\fR, \fBTcl_ParseBraces\fR, \fBTcl_ParseQuotedString\fR, and \fBTcl_ParseVarName\fR may include dynamically allocated memory. If these five parsing procedures return \fBTCL_OK\fR then the caller must invoke \fBTcl_FreeParse\fR to release the storage at \fI*parsePtr\fR. These procedures ignore any existing information in \fI*parsePtr\fR (unless \fIappend\fR is non-zero), so if repeated calls are being made to any of them then \fBTcl_FreeParse\fR must be invoked once after each call. .PP \fBTcl_EvalTokensStandard\fR evaluates a sequence of parse tokens from a Tcl_Parse structure. The tokens typically consist of all the tokens in a word or all the tokens that make up the index for a reference to an array variable. \fBTcl_EvalTokensStandard\fR performs the substitutions requested by the tokens and concatenates the resulting values. The return value from \fBTcl_EvalTokensStandard\fR is a Tcl completion code with one of the values \fBTCL_OK\fR, \fBTCL_ERROR\fR, \fBTCL_RETURN\fR, \fBTCL_BREAK\fR, or \fBTCL_CONTINUE\fR, or possibly some other integer value originating in an extension. In addition, a result value or error message is left in \fIinterp\fR's result; it can be retrieved using \fBTcl_GetObjResult\fR. .PP \fBTcl_EvalTokens\fR differs from \fBTcl_EvalTokensStandard\fR only in the return convention used: it returns the result in a new Tcl_Obj. The reference count of the object returned as result has been incremented, so the caller must invoke \fBTcl_DecrRefCount\fR when it is finished with the object. If an error or other exception occurs while evaluating the tokens (such as a reference to a non-existent variable) then the return value is NULL and an error message is left in \fIinterp\fR's result. The use of \fBTcl_EvalTokens\fR is deprecated. .SH "TCL_PARSE STRUCTURE" .PP \fBTcl_ParseCommand\fR, \fBTcl_ParseExpr\fR, \fBTcl_ParseBraces\fR, \fBTcl_ParseQuotedString\fR, and \fBTcl_ParseVarName\fR return parse information in two data structures, Tcl_Parse and Tcl_Token: .CS typedef struct Tcl_Parse { CONST char *\fIcommentStart\fR; int \fIcommentSize\fR; CONST char *\fIcommandStart\fR; int \fIcommandSize\fR; int \fInumWords\fR; Tcl_Token *\fItokenPtr\fR; int \fInumTokens\fR; ... } Tcl_Parse; typedef struct Tcl_Token { int \fItype\fR; CONST char *\fIstart\fR; int \fIsize\fR; int \fInumComponents\fR; } Tcl_Token; .CE .PP The first five fields of a Tcl_Parse structure are filled in only by \fBTcl_ParseCommand\fR. These fields are not used by the other parsing procedures. .PP \fBTcl_ParseCommand\fR fills in a Tcl_Parse structure with information that describes one Tcl command and any comments that precede the command. If there are comments, the \fIcommentStart\fR field points to the \fB#\fR character that begins the first comment and \fIcommentSize\fR indicates the number of bytes in all of the comments preceding the command, including the newline character that terminates the last comment. If the command is not preceded by any comments, \fIcommentSize\fR is 0. \fBTcl_ParseCommand\fR also sets the \fIcommandStart\fR field to point to the first character of the first word in the command (skipping any comments and leading space) and \fIcommandSize\fR gives the total number of bytes in the command, including the character pointed to by \fIcommandStart\fR up to and including the newline, close bracket, or semicolon character that terminates the command. The \fInumWords\fR field gives the total number of words in the command. .PP All parsing procedures set the remaining fields, \fItokenPtr\fR and \fInumTokens\fR. The \fItokenPtr\fR field points to the first in an array of Tcl_Token structures that describe the components of the entity being parsed. The \fInumTokens\fR field gives the total number of tokens present in the array. Each token contains four fields. The \fItype\fR field selects one of several token types that are described below. The \fIstart\fR field points to the first character in the token and the \fIsize\fR field gives the total number of characters in the token. Some token types, such as \fBTCL_TOKEN_WORD\fR and \fBTCL_TOKEN_VARIABLE\fR, consist of several component tokens, which immediately follow the parent token; the \fInumComponents\fR field describes how many of these there are. The \fItype\fR field has one of the following values: .TP 20 \fBTCL_TOKEN_WORD\fR This token ordinarily describes one word of a command but it may also describe a quoted or braced string in an expression. The token describes a component of the script that is the result of concatenating together a sequence of subcomponents, each described by a separate subtoken. The token starts with the first non-blank character of the component (which may be a double-quote or open brace) and includes all characters in the component up to but not including the space, semicolon, close bracket, close quote, or close brace that terminates the component. The \fInumComponents\fR field counts the total number of sub-tokens that make up the word, including sub-tokens of \fBTCL_TOKEN_VARIABLE\fR and \fBTCL_TOKEN_BS\fR tokens. .TP \fBTCL_TOKEN_SIMPLE_WORD\fR This token has the same meaning as \fBTCL_TOKEN_WORD\fR, except that the word is guaranteed to consist of a single \fBTCL_TOKEN_TEXT\fR sub-token. The \fInumComponents\fR field is always 1. .TP \fBTCL_TOKEN_TEXT\fR The token describes a range of literal text that is part of a word. The \fInumComponents\fR field is always 0. .TP \fBTCL_TOKEN_BS\fR The token describes a backslash sequence such as \fB\en\fR or \fB\e0xa3\fR. The \fInumComponents\fR field is always 0. .TP \fBTCL_TOKEN_COMMAND\fR The token describes a command whose result result must be substituted into the word. The token includes the square brackets that surround the command. The \fInumComponents\fR field is always 0 (the nested command is not parsed; call \fBTcl_ParseCommand\fR recursively if you want to see its tokens). .TP \fBTCL_TOKEN_VARIABLE\fR The token describes a variable substitution, including the \fB$\fR, variable name, and array index (if there is one) up through the close parenthesis that terminates the index. This token is followed by one or more additional tokens that describe the variable name and array index. If \fInumComponents\fR is 1 then the variable is a scalar and the next token is a \fBTCL_TOKEN_TEXT\fR token that gives the variable name. If \fInumComponents\fR is greater than 1 then the variable is an array: the first sub-token is a \fBTCL_TOKEN_TEXT\fR token giving the array name and the remaining sub-tokens are \fBTCL_TOKEN_TEXT\fR, \fBTCL_TOKEN_BS\fR, \fBTCL_TOKEN_COMMAND\fR, and \fBTCL_TOKEN_VARIABLE\fR tokens that must be concatenated to produce the array index. The \fInumComponents\fR field includes nested sub-tokens that are part of \fBTCL_TOKEN_VARIABLE\fR tokens in the array index. .TP \fBTCL_TOKEN_SUB_EXPR\fR The token describes one subexpression of an expression (or an entire expression). A subexpression may consist of a value such as an integer literal, variable substitution, or parenthesized subexpression; it may also consist of an operator and its operands. The token starts with the first non-blank character of the subexpression up to but not including the space, brace, close-paren, or bracket that terminates the subexpression. This token is followed by one or more additional tokens that describe the subexpression. If the first sub-token after the \fBTCL_TOKEN_SUB_EXPR\fR token is a \fBTCL_TOKEN_OPERATOR\fR token, the subexpression consists of an operator and its token operands. If the operator has no operands, the subexpression consists of just the \fBTCL_TOKEN_OPERATOR\fR token. Each operand is described by a \fBTCL_TOKEN_SUB_EXPR\fR token. Otherwise, the subexpression is a value described by one of the token types \fBTCL_TOKEN_WORD\fR, \fBTCL_TOKEN_TEXT\fR, \fBTCL_TOKEN_BS\fR, \fBTCL_TOKEN_COMMAND\fR, \fBTCL_TOKEN_VARIABLE\fR, and \fBTCL_TOKEN_SUB_EXPR\fR. The \fInumComponents\fR field counts the total number of sub-tokens that make up the subexpression; this includes the sub-tokens for any nested \fBTCL_TOKEN_SUB_EXPR\fR tokens. .TP \fBTCL_TOKEN_OPERATOR\fR The token describes one operator of an expression such as \fB&&\fR or \fBhypot\fR. An \fBTCL_TOKEN_OPERATOR\fR token is always preceded by a \fBTCL_TOKEN_SUB_EXPR\fR token that describes the operator and its operands; the \fBTCL_TOKEN_SUB_EXPR\fR token's \fInumComponents\fR field can be used to determine the number of operands. A binary operator such as \fB*\fR is followed by two \fBTCL_TOKEN_SUB_EXPR\fR tokens that describe its operands. A unary operator like \fB-\fR is followed by a single \fBTCL_TOKEN_SUB_EXPR\fR token for its operand. If the operator is a math function such as \fBlog10\fR, the \fBTCL_TOKEN_OPERATOR\fR token will give its name and the following \fBTCL_TOKEN_SUB_EXPR\fR tokens will describe its operands; if there are no operands (as with \fBrand\fR), no \fBTCL_TOKEN_SUB_EXPR\fR tokens follow. There is one trinary operator, \fB?\fR, that appears in if-then-else subexpressions such as \fIx\fB?\fIy\fB:\fIz\fR; in this case, the \fB?\fR \fBTCL_TOKEN_OPERATOR\fR token is followed by three \fBTCL_TOKEN_SUB_EXPR\fR tokens for the operands \fIx\fR, \fIy\fR, and \fIz\fR. The \fInumComponents\fR field for a \fBTCL_TOKEN_OPERATOR\fR token is always 0. .PP After \fBTcl_ParseCommand\fR returns, the first token pointed to by the \fItokenPtr\fR field of the Tcl_Parse structure always has type \fBTCL_TOKEN_WORD\fR or \fBTCL_TOKEN_SIMPLE_WORD\fR. It is followed by the sub-tokens that must be concatenated to produce the value of that word. The next token is the \fBTCL_TOKEN_WORD\fR or \fBTCL_TOKEN_SIMPLE_WORD\fR token for the second word, followed by sub-tokens for that word, and so on until all \fInumWords\fR have been accounted for. .PP After \fBTcl_ParseExpr\fR returns, the first token pointed to by the \fItokenPtr\fR field of the Tcl_Parse structure always has type \fBTCL_TOKEN_SUB_EXPR\fR. It is followed by the sub-tokens that must be evaluated to produce the value of the expression. Only the token information in the Tcl_Parse structure is modified: the \fIcommentStart\fR, \fIcommentSize\fR, \fIcommandStart\fR, and \fIcommandSize\fR fields are not modified by \fBTcl_ParseExpr\fR. .PP After \fBTcl_ParseBraces\fR returns, the array of tokens pointed to by the \fItokenPtr\fR field of the Tcl_Parse structure will contain a single \fBTCL_TOKEN_TEXT\fR token if the braced string does not contain any backslash-newlines. If the string does contain backslash-newlines, the array of tokens will contain one or more \fBTCL_TOKEN_TEXT\fR or \fBTCL_TOKEN_BS\fR sub-tokens that must be concatenated to produce the value of the string. If the braced string was just \fB{}\fR (that is, the string was empty), the single \fBTCL_TOKEN_TEXT\fR token will have a \fIsize\fR field containing zero; this ensures that at least one token appears to describe the braced string. Only the token information in the Tcl_Parse structure is modified: the \fIcommentStart\fR, \fIcommentSize\fR, \fIcommandStart\fR, and \fIcommandSize\fR fields are not modified by \fBTcl_ParseBraces\fR. .PP After \fBTcl_ParseQuotedString\fR returns, the array of tokens pointed to by the \fItokenPtr\fR field of the Tcl_Parse structure depends on the contents of the quoted string. It will consist of one or more \fBTCL_TOKEN_TEXT\fR, \fBTCL_TOKEN_BS\fR, \fBTCL_TOKEN_COMMAND\fR, and \fBTCL_TOKEN_VARIABLE\fR sub-tokens. The array always contains at least one token; for example, if the argument \fIstring\fR is empty, the array returned consists of a single \fBTCL_TOKEN_TEXT\fR token with a zero \fIsize\fR field. Only the token information in the Tcl_Parse structure is modified: the \fIcommentStart\fR, \fIcommentSize\fR, \fIcommandStart\fR, and \fIcommandSize\fR fields are not modified. .PP After \fBTcl_ParseVarName\fR returns, the first token pointed to by the \fItokenPtr\fR field of the Tcl_Parse structure always has type \fBTCL_TOKEN_VARIABLE\fR. It is followed by the sub-tokens that make up the variable name as described above. The total length of the variable name is contained in the \fIsize\fR field of the first token. As in \fBTcl_ParseExpr\fR, only the token information in the Tcl_Parse structure is modified by \fBTcl_ParseVarName\fR: the \fIcommentStart\fR, \fIcommentSize\fR, \fIcommandStart\fR, and \fIcommandSize\fR fields are not modified. .PP All of the character pointers in the Tcl_Parse and Tcl_Token structures refer to characters in the \fIstring\fR argument passed to \fBTcl_ParseCommand\fR, \fBTcl_ParseExpr\fR, \fBTcl_ParseBraces\fR, \fBTcl_ParseQuotedString\fR, and \fBTcl_ParseVarName\fR. .PP There are additional fields in the Tcl_Parse structure after the \fInumTokens\fR field, but these are for the private use of \fBTcl_ParseCommand\fR, \fBTcl_ParseExpr\fR, \fBTcl_ParseBraces\fR, \fBTcl_ParseQuotedString\fR, and \fBTcl_ParseVarName\fR; they should not be referenced by code outside of these procedures. .SH KEYWORDS backslash substitution, braces, command, expression, parse, token, variable substitution tcl8.4.20/doc/ExprLong.30000644003604700454610000000720511737050674013312 0ustar dgp771div'\" '\" Copyright (c) 1989-1993 The Regents of the University of California. '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_ExprLong 3 7.0 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_ExprLong, Tcl_ExprDouble, Tcl_ExprBoolean, Tcl_ExprString \- evaluate an expression .SH SYNOPSIS .nf \fB#include \fR .sp int \fBTcl_ExprLong\fR(\fIinterp, string, longPtr\fR) .sp int \fBTcl_ExprDouble\fR(\fIinterp, string, doublePtr\fR) .sp int \fBTcl_ExprBoolean\fR(\fIinterp, string, booleanPtr\fR) .sp int \fBTcl_ExprString\fR(\fIinterp, string\fR) .SH ARGUMENTS .AS Tcl_Interp *booleanPtr .AP Tcl_Interp *interp in Interpreter in whose context to evaluate \fIstring\fR. .VS 8.4 .AP "CONST char" *string in .VE Expression to be evaluated. .AP long *longPtr out Pointer to location in which to store the integer value of the expression. .AP int *doublePtr out Pointer to location in which to store the floating-point value of the expression. .AP int *booleanPtr out Pointer to location in which to store the 0/1 boolean value of the expression. .BE .SH DESCRIPTION .PP These four procedures all evaluate the expression given by the \fIstring\fR argument and return the result in one of four different forms. The expression can have any of the forms accepted by the \fBexpr\fR command. Note that these procedures have been largely replaced by the object-based procedures \fBTcl_ExprLongObj\fR, \fBTcl_ExprDoubleObj\fR, \fBTcl_ExprBooleanObj\fR, and \fBTcl_ExprObj\fR. Those object-based procedures evaluate an expression held in a Tcl object instead of a string. The object argument can retain an internal representation that is more efficient to execute. .PP The \fIinterp\fR argument refers to an interpreter used to evaluate the expression (e.g. for variables and nested Tcl commands) and to return error information. .PP For all of these procedures the return value is a standard Tcl result: \fBTCL_OK\fR means the expression was successfully evaluated, and \fBTCL_ERROR\fR means that an error occurred while evaluating the expression. If \fBTCL_ERROR\fR is returned then the interpreter's result will hold a message describing the error. If an error occurs while executing a Tcl command embedded in the expression then that error will be returned. .PP If the expression is successfully evaluated, then its value is returned in one of four forms, depending on which procedure is invoked. \fBTcl_ExprLong\fR stores an integer value at \fI*longPtr\fR. If the expression's actual value is a floating-point number, then it is truncated to an integer. If the expression's actual value is a non-numeric string then an error is returned. .PP \fBTcl_ExprDouble\fR stores a floating-point value at \fI*doublePtr\fR. If the expression's actual value is an integer, it is converted to floating-point. If the expression's actual value is a non-numeric string then an error is returned. .PP \fBTcl_ExprBoolean\fR stores a 0/1 integer value at \fI*booleanPtr\fR. If the expression's actual value is an integer or floating-point number, then they store 0 at \fI*booleanPtr\fR if the value was zero and 1 otherwise. If the expression's actual value is a non-numeric string then it must be one of the values accepted by \fBTcl_GetBoolean\fR such as ``yes'' or ``no'', or else an error occurs. .PP \fBTcl_ExprString\fR returns the value of the expression as a string stored in the interpreter's result. .SH "SEE ALSO" Tcl_ExprLongObj, Tcl_ExprDoubleObj, Tcl_ExprBooleanObj, Tcl_ExprObj .SH KEYWORDS boolean, double, evaluate, expression, integer, object, string tcl8.4.20/doc/read.n0000644003604700454610000000670211737050674012563 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH read n 8.1 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME read \- Read from a channel .SH SYNOPSIS \fBread \fR?\fB\-nonewline\fR? \fIchannelId\fR .sp \fBread \fIchannelId numChars\fR .BE .SH DESCRIPTION .PP In the first form, the \fBread\fR command reads all of the data from \fIchannelId\fR up to the end of the file. If the \fB\-nonewline\fR switch is specified then the last character of the file is discarded if it is a newline. In the second form, the extra argument specifies how many characters to read. Exactly that many characters will be read and returned, unless there are fewer than \fInumChars\fR left in the file; in this case all the remaining characters are returned. If the channel is configured to use a multi-byte encoding, then the number of characters read may not be the same as the number of bytes read. .PP .VS \fIChannelId\fR must be an identifier for an open channel such as the Tcl standard input channel (\fBstdin\fR), the return value from an invocation of \fBopen\fR or \fBsocket\fR, or the result of a channel creation command provided by a Tcl extension. The channel must have been opened for input. .VE .PP If \fIchannelId\fR is in nonblocking mode, the command may not read as many characters as requested: once all available input has been read, the command will return the data that is available rather than blocking for more input. If the channel is configured to use a multi-byte encoding, then there may actually be some bytes remaining in the internal buffers that do not form a complete character. These bytes will not be returned until a complete character is available or end-of-file is reached. The \fB\-nonewline\fR switch is ignored if the command returns before reaching the end of the file. .PP \fBRead\fR translates end-of-line sequences in the input into newline characters according to the \fB\-translation\fR option for the channel. See the \fBfconfigure\fR manual entry for a discussion on ways in which \fBfconfigure\fR will alter input. .SH "USE WITH SERIAL PORTS" '\" Note: this advice actually applies to many versions of Tcl For most applications a channel connected to a serial port should be configured to be nonblocking: \fBfconfigure \fIchannelId \fB\-blocking \fI0\fR. Then \fBread\fR behaves much like described above. Care must be taken when using \fBread\fR on blocking serial ports: .TP \fBread \fIchannelId numChars\fR In this form \fBread\fR blocks until \fInumChars\fR have been received from the serial port. .TP \fBread \fIchannelId\fR In this form \fBread\fR blocks until the reception of the end-of-file character, see \fBfconfigure -eofchar\fR. If there no end-of-file character has been configured for the channel, then \fBread\fR will block forever. .SH "EXAMPLE" This example code reads a file all at once, and splits it into a list, with each line in the file corresponding to an element in the list: .CS set fl [open /proc/meminfo] set data [\fBread\fR $fl] close $fl set lines [split $data \\n] .CE .SH "SEE ALSO" file(n), eof(n), fblocked(n), fconfigure(n), Tcl_StandardChannels(3) .SH KEYWORDS blocking, channel, end of line, end of file, nonblocking, read, translation, encoding tcl8.4.20/doc/GetOpnFl.30000644003604700454610000000403611737050674013231 0ustar dgp771div'\" '\" Copyright (c) 1996-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_GetOpenFile 3 8.0 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_GetOpenFile \- Get a standard IO File * handle from a channel. (Unix only) .SH SYNOPSIS .nf \fB#include \fR .sp int \fBTcl_GetOpenFile\fR(\fIinterp, string, write, checkUsage, filePtr\fR) .sp .SH ARGUMENTS .AS Tcl_Interp checkUsage .AP Tcl_Interp *interp in Tcl interpreter from which file handle is to be obtained. .AP "CONST char" *string in String identifying channel, such as \fBstdin\fR or \fBfile4\fR. .AP int write in Non-zero means the file will be used for writing, zero means it will be used for reading. .AP int checkUsage in If non-zero, then an error will be generated if the file wasn't opened for the access indicated by \fIwrite\fR. .AP ClientData *filePtr out Points to word in which to store pointer to FILE structure for the file given by \fIstring\fR. .BE .SH DESCRIPTION .PP \fBTcl_GetOpenFile\fR takes as argument a file identifier of the form returned by the \fBopen\fR command and returns at \fI*filePtr\fR a pointer to the FILE structure for the file. The \fIwrite\fR argument indicates whether the FILE pointer will be used for reading or writing. In some cases, such as a channel that connects to a pipeline of subprocesses, different FILE pointers will be returned for reading and writing. \fBTcl_GetOpenFile\fR normally returns TCL_OK. If an error occurs in \fBTcl_GetOpenFile\fR (e.g. \fIstring\fR didn't make any sense or \fIcheckUsage\fR was set and the file wasn't opened for the access specified by \fIwrite\fR) then TCL_ERROR is returned and the interpreter's result will contain an error message. In the current implementation \fIcheckUsage\fR is ignored and consistency checks are always performed. .VS .PP Note that this interface is only supported on the Unix platform. .VE .SH KEYWORDS channel, file handle, permissions, pipeline, read, write tcl8.4.20/doc/regsub.n0000644003604700454610000001302011737050674013126 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" Copyright (c) 2000 Scriptics Corporation. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH regsub n 8.3 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME regsub \- Perform substitutions based on regular expression pattern matching .SH SYNOPSIS .VS 8.4 \fBregsub \fR?\fIswitches\fR? \fIexp string subSpec \fR?\fIvarName\fR? .VE 8.4 .BE .SH DESCRIPTION .PP This command matches the regular expression \fIexp\fR against \fIstring\fR, .VS 8.4 and either copies \fIstring\fR to the variable whose name is given by \fIvarName\fR or returns \fIstring\fR if \fIvarName\fR is not present. .VE 8.4 (Regular expression matching is described in the \fBre_syntax\fR reference page.) If there is a match, then while copying \fIstring\fR to \fIvarName\fR .VS 8.4 (or to the result of this command if \fIvarName\fR is not present) .VE 8.4 the portion of \fIstring\fR that matched \fIexp\fR is replaced with \fIsubSpec\fR. If \fIsubSpec\fR contains a ``&'' or ``\e0'', then it is replaced in the substitution with the portion of \fIstring\fR that matched \fIexp\fR. If \fIsubSpec\fR contains a ``\e\fIn\fR'', where \fIn\fR is a digit between 1 and 9, then it is replaced in the substitution with the portion of \fIstring\fR that matched the \fIn\fR-th parenthesized subexpression of \fIexp\fR. Additional backslashes may be used in \fIsubSpec\fR to prevent special interpretation of ``&'' or ``\e0'' or ``\e\fIn\fR'' or backslash. The use of backslashes in \fIsubSpec\fR tends to interact badly with the Tcl parser's use of backslashes, so it's generally safest to enclose \fIsubSpec\fR in braces if it includes backslashes. .LP If the initial arguments to \fBregsub\fR start with \fB\-\fR then they are treated as switches. The following switches are currently supported: .TP 10 \fB\-all\fR All ranges in \fIstring\fR that match \fIexp\fR are found and substitution is performed for each of these ranges. Without this switch only the first matching range is found and substituted. If \fB\-all\fR is specified, then ``&'' and ``\e\fIn\fR'' sequences are handled for each substitution using the information from the corresponding match. .TP 15 \fB\-expanded\fR Enables use of the expanded regular expression syntax where whitespace and comments are ignored. This is the same as specifying the \fB(?x)\fR embedded option (see the \fBre_syntax\fR manual page). .TP 15 \fB\-line\fR Enables newline-sensitive matching. By default, newline is a completely ordinary character with no special meaning. With this flag, `[^' bracket expressions and `.' never match newline, `^' matches an empty string after any newline in addition to its normal function, and `$' matches an empty string before any newline in addition to its normal function. This flag is equivalent to specifying both \fB\-linestop\fR and \fB\-lineanchor\fR, or the \fB(?n)\fR embedded option (see the \fBre_syntax\fR manual page). .TP 15 \fB\-linestop\fR Changes the behavior of `[^' bracket expressions and `.' so that they stop at newlines. This is the same as specifying the \fB(?p)\fR embedded option (see the \fBre_syntax\fR manual page). .TP 15 \fB\-lineanchor\fR Changes the behavior of `^' and `$' (the ``anchors'') so they match the beginning and end of a line respectively. This is the same as specifying the \fB(?w)\fR embedded option (see the \fBre_syntax\fR manual page). .TP 10 \fB\-nocase\fR Upper-case characters in \fIstring\fR will be converted to lower-case before matching against \fIexp\fR; however, substitutions specified by \fIsubSpec\fR use the original unconverted form of \fIstring\fR. .TP 10 \fB\-start\fR \fIindex\fR Specifies a character index offset into the string to start matching the regular expression at. When using this switch, `^' will not match the beginning of the line, and \\A will still match the start of the string at \fIindex\fR. \fIindex\fR will be constrained to the bounds of the input string. .TP 10 \fB\-\|\-\fR Marks the end of switches. The argument following this one will be treated as \fIexp\fR even if it starts with a \fB\-\fR. .PP .VS 8.4 If \fIvarName\fR is supplied, the command returns a count of the number of matching ranges that were found and replaced, otherwise the string after replacement is returned. .VE 8.4 See the manual entry for \fBregexp\fR for details on the interpretation of regular expressions. .SH EXAMPLES Replace (in the string in variable \fIstring\fR) every instance of \fBfoo\fR which is a word by itself with \fBbar\fR: .CS \fBregsub\fR -all {\e} $string bar string .CE .PP Insert double-quotes around the first instance of the word \fBinteresting\fR, however it is capitalised. .CS \fBregsub\fR -nocase {\e} $string {"&"} string .CE .PP Convert all non-ASCII and Tcl-significant characters into \eu escape sequences by using \fBregsub\fR and \fBsubst\fR in combination: .CS # This RE is just a character class for everything "bad" set RE {[][{}\e$\es\eu0100-\euffff]} # We will substitute with a fragment of Tcl script in brackets set substitution {[format \e\e\e\eu%04x [scan "\e\e&" %c]]} # Now we apply the substitution to get a subst-string that # will perform the computational parts of the conversion. set quoted [subst [\fBregsub\fR -all $RE $string $substitution]] .CE .SH "SEE ALSO" regexp(n), re_syntax(n), subst(n) .SH KEYWORDS match, pattern, regular expression, substitute tcl8.4.20/doc/Eval.30000644003604700454610000002066411737050674012447 0ustar dgp771div'\" '\" Copyright (c) 1989-1993 The Regents of the University of California. '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" Copyright (c) 2000 Scriptics Corporation. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_Eval 3 8.1 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_EvalObjEx, Tcl_EvalFile, Tcl_EvalObjv, Tcl_Eval, Tcl_EvalEx, Tcl_GlobalEval, Tcl_GlobalEvalObj, Tcl_VarEval, Tcl_VarEvalVA \- execute Tcl scripts .SH SYNOPSIS .nf \fB#include \fR .sp .VS int \fBTcl_EvalObjEx\fR(\fIinterp, objPtr, flags\fR) .sp int \fBTcl_EvalFile\fR(\fIinterp, fileName\fR) .sp int \fBTcl_EvalObjv\fR(\fIinterp, objc, objv, flags\fR) .sp int \fBTcl_Eval\fR(\fIinterp, script\fR) .sp int \fBTcl_EvalEx\fR(\fIinterp, script, numBytes, flags\fR) .sp int \fBTcl_GlobalEval\fR(\fIinterp, script\fR) .sp int \fBTcl_GlobalEvalObj\fR(\fIinterp, objPtr\fR) .sp int \fBTcl_VarEval\fR(\fIinterp, string, string, ... \fB(char *) NULL\fR) .sp int \fBTcl_VarEvalVA\fR(\fIinterp, argList\fR) .SH ARGUMENTS .AS Tcl_Interp **termPtr; .AP Tcl_Interp *interp in Interpreter in which to execute the script. The interpreter's result is modified to hold the result or error message from the script. .AP Tcl_Obj *objPtr in A Tcl object containing the script to execute. .AP int flags in ORed combination of flag bits that specify additional options. \fBTCL_EVAL_GLOBAL\fR and \fBTCL_EVAL_DIRECT\fR are currently supported. .AP "CONST char" *fileName in Name of a file containing a Tcl script. .AP int objc in The number of objects in the array pointed to by \fIobjPtr\fR; this is also the number of words in the command. .AP Tcl_Obj **objv in Points to an array of pointers to objects; each object holds the value of a single word in the command to execute. .AP int numBytes in The number of bytes in \fIscript\fR, not including any null terminating character. If \-1, then all characters up to the first null byte are used. .AP "CONST char" *script in Points to first byte of script to execute (null-terminated and UTF-8). .AP char *string in String forming part of a Tcl script. .AP va_list argList in An argument list which must have been initialised using \fBTCL_VARARGS_START\fR, and cleared using \fBva_end\fR. .BE .SH DESCRIPTION .PP The procedures described here are invoked to execute Tcl scripts in various forms. \fBTcl_EvalObjEx\fR is the core procedure and is used by many of the others. It executes the commands in the script stored in \fIobjPtr\fR until either an error occurs or the end of the script is reached. If this is the first time \fIobjPtr\fR has been executed, its commands are compiled into bytecode instructions which are then executed. The bytecodes are saved in \fIobjPtr\fR so that the compilation step can be skipped if the object is evaluated again in the future. .PP The return value from \fBTcl_EvalObjEx\fR (and all the other procedures described here) is a Tcl completion code with one of the values \fBTCL_OK\fR, \fBTCL_ERROR\fR, \fBTCL_RETURN\fR, \fBTCL_BREAK\fR, or \fBTCL_CONTINUE\fR, or possibly some other integer value originating in an extension. In addition, a result value or error message is left in \fIinterp\fR's result; it can be retrieved using \fBTcl_GetObjResult\fR. .PP \fBTcl_EvalFile\fR reads the file given by \fIfileName\fR and evaluates its contents as a Tcl script. It returns the same information as \fBTcl_EvalObjEx\fR. If the file couldn't be read then a Tcl error is returned to describe why the file couldn't be read. .VS 8.4 The eofchar for files is '\\32' (^Z) for all platforms. If you require a ``^Z'' in code for string comparison, you can use ``\\032'' or ``\\u001a'', which will be safely substituted by the Tcl interpreter into ``^Z''. .VE 8.4 .PP \fBTcl_EvalObjv\fR executes a single pre-parsed command instead of a script. The \fIobjc\fR and \fIobjv\fR arguments contain the values of the words for the Tcl command, one word in each object in \fIobjv\fR. \fBTcl_EvalObjv\fR evaluates the command and returns a completion code and result just like \fBTcl_EvalObjEx\fR. .PP \fBTcl_Eval\fR is similar to \fBTcl_EvalObjEx\fR except that the script to be executed is supplied as a string instead of an object and no compilation occurs. The string should be a proper UTF-8 string as converted by \fBTcl_ExternalToUtfDString\fR or \fBTcl_ExternalToUtf\fR when it is known to possibly contain upper ASCII characters who's possible combinations might be a UTF-8 special code. The string is parsed and executed directly (using \fBTcl_EvalObjv\fR) instead of compiling it and executing the bytecodes. In situations where it is known that the script will never be executed again, \fBTcl_Eval\fR may be faster than \fBTcl_EvalObjEx\fR. \fBTcl_Eval\fR returns a completion code and result just like \fBTcl_EvalObjEx\fR. Note: for backward compatibility with versions before Tcl 8.0, \fBTcl_Eval\fR copies the object result in \fIinterp\fR to \fIinterp->result\fR (use is deprecated) where it can be accessed directly. This makes \fBTcl_Eval\fR somewhat slower than \fBTcl_EvalEx\fR, which doesn't do the copy. .PP \fBTcl_EvalEx\fR is an extended version of \fBTcl_Eval\fR that takes additional arguments \fInumBytes\fR and \fIflags\fR. For the efficiency reason given above, \fBTcl_EvalEx\fR is generally preferred over \fBTcl_Eval\fR. .PP \fBTcl_GlobalEval\fR and \fBTcl_GlobalEvalObj\fR are older procedures that are now deprecated. They are similar to \fBTcl_EvalEx\fR and \fBTcl_EvalObjEx\fR except that the script is evaluated in the global namespace and its variable context consists of global variables only (it ignores any Tcl procedures that are active). These functions are equivalent to using the \fBTCL_EVAL_GLOBAL\fR flag (see below). .PP \fBTcl_VarEval\fR takes any number of string arguments of any length, concatenates them into a single string, then calls \fBTcl_Eval\fR to execute that string as a Tcl command. It returns the result of the command and also modifies \fIinterp->result\fR in the same way as \fBTcl_Eval\fR. The last argument to \fBTcl_VarEval\fR must be NULL to indicate the end of arguments. \fBTcl_VarEval\fR is now deprecated. .PP \fBTcl_VarEvalVA\fR is the same as \fBTcl_VarEval\fR except that instead of taking a variable number of arguments it takes an argument list. Like \fBTcl_VarEval\fR, \fBTcl_VarEvalVA\fR is deprecated. .SH "FLAG BITS" Any ORed combination of the following values may be used for the \fIflags\fR argument to procedures such as \fBTcl_EvalObjEx\fR: .TP 23 \fBTCL_EVAL_DIRECT\fR This flag is only used by \fBTcl_EvalObjEx\fR; it is ignored by other procedures. If this flag bit is set, the script is not compiled to bytecodes; instead it is executed directly as is done by \fBTcl_EvalEx\fR. The \fBTCL_EVAL_DIRECT\fR flag is useful in situations where the contents of an object are going to change immediately, so the bytecodes won't be reused in a future execution. In this case, it's faster to execute the script directly. .TP 23 \fBTCL_EVAL_GLOBAL\fR If this flag is set, the script is processed at global level. This means that it is evaluated in the global namespace and its variable context consists of global variables only (it ignores any Tcl procedures at are active). .SH "MISCELLANEOUS DETAILS" .PP During the processing of a Tcl command it is legal to make nested calls to evaluate other commands (this is how procedures and some control structures are implemented). If a code other than \fBTCL_OK\fR is returned from a nested \fBTcl_EvalObjEx\fR invocation, then the caller should normally return immediately, passing that same return code back to its caller, and so on until the top-level application is reached. A few commands, like \fBfor\fR, will check for certain return codes, like \fBTCL_BREAK\fR and \fBTCL_CONTINUE\fR, and process them specially without returning. .PP \fBTcl_EvalObjEx\fR keeps track of how many nested \fBTcl_EvalObjEx\fR invocations are in progress for \fIinterp\fR. If a code of \fBTCL_RETURN\fR, \fBTCL_BREAK\fR, or \fBTCL_CONTINUE\fR is about to be returned from the topmost \fBTcl_EvalObjEx\fR invocation for \fIinterp\fR, it converts the return code to \fBTCL_ERROR\fR and sets \fIinterp\fR's result to an error message indicating that the \fBreturn\fR, \fBbreak\fR, or \fBcontinue\fR command was invoked in an inappropriate place. This means that top-level applications should never see a return code from \fBTcl_EvalObjEx\fR other then \fBTCL_OK\fR or \fBTCL_ERROR\fR. .VE .SH KEYWORDS execute, file, global, object, result, script tcl8.4.20/doc/GetInt.30000644003604700454610000000605211737050674012745 0ustar dgp771div'\" '\" Copyright (c) 1989-1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_GetInt 3 "" Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_GetInt, Tcl_GetDouble, Tcl_GetBoolean \- convert from string to integer, double, or boolean .SH SYNOPSIS .nf \fB#include \fR .sp int \fBTcl_GetInt\fR(\fIinterp, string, intPtr\fR) .sp int \fBTcl_GetDouble\fR(\fIinterp, string, doublePtr\fR) .sp int \fBTcl_GetBoolean\fR(\fIinterp, string, boolPtr\fR) .SH ARGUMENTS .AS Tcl_Interp *doublePtr .AP Tcl_Interp *interp in Interpreter to use for error reporting. .AP "CONST char" *string in Textual value to be converted. .AP int *intPtr out Points to place to store integer value converted from \fIstring\fR. .AP double *doublePtr out Points to place to store double-precision floating-point value converted from \fIstring\fR. .AP int *boolPtr out Points to place to store boolean value (0 or 1) converted from \fIstring\fR. .BE .SH DESCRIPTION .PP These procedures convert from strings to integers or double-precision floating-point values or booleans (represented as 0- or 1-valued integers). Each of the procedures takes a \fIstring\fR argument, converts it to an internal form of a particular type, and stores the converted value at the location indicated by the procedure's third argument. If all goes well, each of the procedures returns TCL_OK. If \fIstring\fR doesn't have the proper syntax for the desired type then TCL_ERROR is returned, an error message is left in the interpreter's result, and nothing is stored at *\fIintPtr\fR or *\fIdoublePtr\fR or *\fIboolPtr\fR. .PP \fBTcl_GetInt\fR expects \fIstring\fR to consist of a collection of integer digits, optionally signed and optionally preceded by white space. If the first two characters of \fIstring\fR are ``0x'' then \fIstring\fR is expected to be in hexadecimal form; otherwise, if the first character of \fIstring\fR is ``0'' then \fIstring\fR is expected to be in octal form; otherwise, \fIstring\fR is expected to be in decimal form. .PP \fBTcl_GetDouble\fR expects \fIstring\fR to consist of a floating-point number, which is: white space; a sign; a sequence of digits; a decimal point; a sequence of digits; the letter ``e''; and a signed decimal exponent. Any of the fields may be omitted, except that the digits either before or after the decimal point must be present and if the ``e'' is present then it must be followed by the exponent number. .PP \fBTcl_GetBoolean\fR expects \fIstring\fR to specify a boolean value. If \fIstring\fR is any of \fB0\fR, \fBfalse\fR, \fBno\fR, or \fBoff\fR, then \fBTcl_GetBoolean\fR stores a zero value at \fI*boolPtr\fR. If \fIstring\fR is any of \fB1\fR, \fBtrue\fR, \fByes\fR, or \fBon\fR, then 1 is stored at \fI*boolPtr\fR. Any of these values may be abbreviated, and upper-case spellings are also acceptable. .SH KEYWORDS boolean, conversion, double, floating-point, integer tcl8.4.20/doc/filename.n0000644003604700454610000001543212052456743013426 0ustar dgp771div'\" '\" Copyright (c) 1995-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH filename n 7.5 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME filename \- File name conventions supported by Tcl commands .BE .SH INTRODUCTION .PP All Tcl commands and C procedures that take file names as arguments expect the file names to be in one of three forms, depending on the current platform. On each platform, Tcl supports file names in the standard forms(s) for that platform. In addition, on all platforms, Tcl supports a Unix-like syntax intended to provide a convenient way of constructing simple file names. However, scripts that are intended to be portable should not assume a particular form for file names. Instead, portable scripts must use the \fBfile split\fR and \fBfile join\fR commands to manipulate file names (see the \fBfile\fR manual entry for more details). .SH "PATH TYPES" .PP File names are grouped into three general types based on the starting point for the path used to specify the file: absolute, relative, and volume-relative. Absolute names are completely qualified, giving a path to the file relative to a particular volume and the root directory on that volume. Relative names are unqualified, giving a path to the file relative to the current working directory. Volume-relative names are partially qualified, either giving the path relative to the root directory on the current volume, or relative to the current directory of the specified volume. The \fBfile pathtype\fR command can be used to determine the type of a given path. .SH "PATH SYNTAX" .PP The rules for native names depend on the value reported in the Tcl array element \fBtcl_platform(platform)\fR: .TP 10 \fBunix\fR On Unix platforms, Tcl uses path names where the components are separated by slashes. Path names may be relative or absolute, and file names may contain any character other than slash. The file names \fB\&.\fR and \fB\&..\fR are special and refer to the current directory and the parent of the current directory respectively. Multiple adjacent slash characters are interpreted as a single separator. The following examples illustrate various forms of path names: .RS .TP 15 \fB/\fR Absolute path to the root directory. .TP 15 \fB/etc/passwd\fR Absolute path to the file named \fBpasswd\fR in the directory \fBetc\fR in the root directory. .TP 15 \fB\&.\fR Relative path to the current directory. .TP 15 \fBfoo\fR Relative path to the file \fBfoo\fR in the current directory. .TP 15 \fBfoo/bar\fR Relative path to the file \fBbar\fR in the directory \fBfoo\fR in the current directory. .TP 15 \fB\&../foo\fR Relative path to the file \fBfoo\fR in the directory above the current directory. .RE .TP \fBwindows\fR On Microsoft Windows platforms, Tcl supports both drive-relative and UNC style names. Both \fB/\fR and \fB\e\fR may be used as directory separators in either type of name. Drive-relative names consist of an optional drive specifier followed by an absolute or relative path. UNC paths follow the general form \fB\e\eservername\esharename\epath\efile\fR, but must at the very least contain the server and share components, i.e. \fB\e\eservername\esharename\fR. In both forms, the file names \fB.\fR and \fB..\fR are special and refer to the current directory and the parent of the current directory respectively. The following examples illustrate various forms of path names: .RS .TP 15 \fB\&\e\eHost\eshare/file\fR Absolute UNC path to a file called \fBfile\fR in the root directory of the export point \fBshare\fR on the host \fBHost\fR. Note that repeated use of \fBfile dirname\fR on this path will give \fB//Host/share\fR, and will never give just \fB//Host\fR. .TP 15 \fBc:foo\fR Volume-relative path to a file \fBfoo\fR in the current directory on drive \fBc\fR. .TP 15 \fBc:/foo\fR Absolute path to a file \fBfoo\fR in the root directory of drive \fBc\fR. .TP 15 \fBfoo\ebar\fR Relative path to a file \fBbar\fR in the \fBfoo\fR directory in the current directory on the current volume. .TP 15 \fB\&\efoo\fR Volume-relative path to a file \fBfoo\fR in the root directory of the current volume. .TP 15 \fB\&\e\efoo\fR Volume-relative path to a file \fBfoo\fR in the root directory of the current volume. This is not a valid UNC path, so the assumption is that the extra backslashes are superfluous. .RE .SH "TILDE SUBSTITUTION" .PP In addition to the file name rules described above, Tcl also supports \fIcsh\fR-style tilde substitution. If a file name starts with a tilde, then the file name will be interpreted as if the first element is replaced with the location of the home directory for the given user. If the tilde is followed immediately by a separator, then the \fB$HOME\fR environment variable is substituted. Otherwise the characters between the tilde and the next separator are taken as a user name, which is used to retrieve the user's home directory for substitution. .PP The Windows platform does not support tilde substitution when a user name follows the tilde. On these platforms, attempts to use a tilde followed by a user name will generate an error that the user does not exist when Tcl attempts to interpret that part of the path or otherwise access the file. The behaviour of these paths when not trying to interpret them is the same as on Unix. File names that have a tilde without a user name will be correctly substituted using the \fB$HOME\fR environment variable, just like for Unix. .SH "PORTABILITY ISSUES" .PP Not all file systems are case sensitive, so scripts should avoid code that depends on the case of characters in a file name. In addition, the character sets allowed on different devices may differ, so scripts should choose file names that do not contain special characters like: \fB<>:"/\e|\fR. The safest approach is to use names consisting of alphanumeric characters only. Also Windows 3.1 only supports file names with a root of no more than 8 characters and an extension of no more than 3 characters. .PP On Windows platforms there are file and path length restrictions. Complete paths or filenames longer than about 260 characters will lead to errors in most file operations. .PP Another Windows peculiarity is that any number of trailing dots '.' in filenames are totally ignored, so, for example, attempts to create a file or directory with a name "foo." will result in the creation of a file/directory with name "foo". This fact is reflected in the results of 'file normalize'. Furthermore, a file name consisting only of dots '.........' or dots with trailing characters '.....abc' is illegal. .SH KEYWORDS current directory, absolute file name, relative file name, volume-relative file name, portability .SH "SEE ALSO" file(n), glob(n) tcl8.4.20/doc/SplitPath.30000644003604700454610000000650011737050674013461 0ustar dgp771div'\" '\" Copyright (c) 1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_SplitPath 3 7.5 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_SplitPath, Tcl_JoinPath, Tcl_GetPathType \- manipulate platform-dependent file paths .SH SYNOPSIS .nf \fB#include \fR .sp \fBTcl_SplitPath\fR(\fIpath, argcPtr, argvPtr\fR) .sp char * \fBTcl_JoinPath\fR(\fIargc, argv, resultPtr\fR) .sp Tcl_PathType \fBTcl_GetPathType\fR(\fIpath\fR) .SH ARGUMENTS .AS Tcl_DString ***argvPtr .AP "CONST char * CONST" *argvPtr in File path in a form appropriate for the current platform (see the \fBfilename\fR manual entry for acceptable forms for path names). .AP int *argcPtr out Filled in with number of path elements in \fIpath\fR. .AP "CONST char" ***argvPtr out \fI*argvPtr\fR will be filled in with the address of an array of pointers to the strings that are the extracted elements of \fIpath\fR. There will be \fI*argcPtr\fR valid entries in the array, followed by a NULL entry. .AP int argc in Number of elements in \fIargv\fR. .AP "CONST char * CONST" *argv in Array of path elements to merge together into a single path. .AP Tcl_DString *resultPtr in/out A pointer to an initialized \fBTcl_DString\fR to which the result of \fBTcl_JoinPath\fR will be appended. .BE .SH DESCRIPTION .PP These procedures have been superceded by the objectified procedures in the \fBFileSystem\fR man page, which are more efficient. .PP These procedures may be used to disassemble and reassemble file paths in a platform independent manner: they provide C-level access to the same functionality as the \fBfile split\fR, \fBfile join\fR, and \fBfile pathtype\fR commands. .PP \fBTcl_SplitPath\fR breaks a path into its constituent elements, returning an array of pointers to the elements using \fIargcPtr\fR and \fIargvPtr\fR. The area of memory pointed to by \fI*argvPtr\fR is dynamically allocated; in addition to the array of pointers, it also holds copies of all the path elements. It is the caller's responsibility to free all of this storage. For example, suppose that you have called \fBTcl_SplitPath\fR with the following code: .CS int argc; char *path; char **argv; \&... Tcl_SplitPath(string, &argc, &argv); .CE Then you should eventually free the storage with a call like the following: .CS Tcl_Free((char *) argv); .CE .PP \fBTcl_JoinPath\fR is the inverse of \fBTcl_SplitPath\fR: it takes a collection of path elements given by \fIargc\fR and \fIargv\fR and generates a result string that is a properly constructed path. The result string is appended to \fIresultPtr\fR. \fIResultPtr\fR must refer to an initialized \fBTcl_DString\fR. .PP If the result of \fBTcl_SplitPath\fR is passed to \fBTcl_JoinPath\fR, the result will refer to the same location, but may not be in the same form. This is because \fBTcl_SplitPath\fR and \fBTcl_JoinPath\fR eliminate duplicate path separators and return a normalized form for each platform. .PP \fBTcl_GetPathType\fR returns the type of the specified \fIpath\fR, where \fBTcl_PathType\fR is one of \fBTCL_PATH_ABSOLUTE\fR, \fBTCL_PATH_RELATIVE\fR, or \fBTCL_PATH_VOLUME_RELATIVE\fR. See the \fBfilename\fR manual entry for a description of the path types for each platform. .SH KEYWORDS file, filename, join, path, split, type tcl8.4.20/doc/case.n0000644003604700454610000000477611737050674012574 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH case n 7.0 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME case \- Evaluate one of several scripts, depending on a given value .SH SYNOPSIS \fBcase\fI string \fR?\fBin\fR? \fIpatList body \fR?\fIpatList body \fR...? .sp \fBcase\fI string \fR?\fBin\fR? {\fIpatList body \fR?\fIpatList body \fR...?} .BE .SH DESCRIPTION .PP \fINote: the \fBcase\fI command is obsolete and is supported only for backward compatibility. At some point in the future it may be removed entirely. You should use the \fBswitch\fI command instead.\fR .PP The \fBcase\fR command matches \fIstring\fR against each of the \fIpatList\fR arguments in order. Each \fIpatList\fR argument is a list of one or more patterns. If any of these patterns matches \fIstring\fR then \fBcase\fR evaluates the following \fIbody\fR argument by passing it recursively to the Tcl interpreter and returns the result of that evaluation. Each \fIpatList\fR argument consists of a single pattern or list of patterns. Each pattern may contain any of the wild-cards described under \fBstring match\fR. If a \fIpatList\fR argument is \fBdefault\fR, the corresponding body will be evaluated if no \fIpatList\fR matches \fIstring\fR. If no \fIpatList\fR argument matches \fIstring\fR and no default is given, then the \fBcase\fR command returns an empty string. .PP Two syntaxes are provided for the \fIpatList\fR and \fIbody\fR arguments. The first uses a separate argument for each of the patterns and commands; this form is convenient if substitutions are desired on some of the patterns or commands. The second form places all of the patterns and commands together into a single argument; the argument must have proper list structure, with the elements of the list being the patterns and commands. The second form makes it easy to construct multi-line case commands, since the braces around the whole list make it unnecessary to include a backslash at the end of each line. Since the \fIpatList\fR arguments are in braces in the second form, no command or variable substitutions are performed on them; this makes the behavior of the second form different than the first form in some cases. .SH "SEE ALSO" switch(n) .SH KEYWORDS case, match, regular expression tcl8.4.20/doc/fblocked.n0000644003604700454610000000452711737050674013424 0ustar dgp771div'\" '\" Copyright (c) 1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH fblocked n 7.5 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME fblocked \- Test whether the last input operation exhausted all available input .SH SYNOPSIS \fBfblocked \fIchannelId\fR .BE .SH DESCRIPTION .PP The \fBfblocked\fR command returns 1 if the most recent input operation on \fIchannelId\fR returned less information than requested because all available input was exhausted. For example, if \fBgets\fR is invoked when there are only three characters available for input and no end-of-line sequence, \fBgets\fR returns an empty string and a subsequent call to \fBfblocked\fR will return 1. .PP .VS \fIChannelId\fR must be an identifier for an open channel such as a Tcl standard channel (\fBstdin\fR, \fBstdout\fR, or \fBstderr\fR), the return value from an invocation of \fBopen\fR or \fBsocket\fR, or the result of a channel creation command provided by a Tcl extension. .VE .SH EXAMPLE The \fBfblocked\fR command is particularly useful when writing network servers, as it allows you to write your code in a line-by-line style without preventing the servicing of other connections. This can be seen in this simple echo-service: .PP .CS # This is called whenever a new client connects to the server proc connect {chan host port} { set clientName [format <%s:%d> $host $port] puts "connection from $clientName" fconfigure $chan -blocking 0 -buffering line fileevent $chan readable [list echoLine $chan $clientName] } # This is called whenever either at least one byte of input # data is available, or the channel was closed by the client. proc echoLine {chan clientName} { gets $chan line if {[eof $chan]} { puts "finishing connection from $clientName" close $chan } elseif {![\fBfblocked\fR $chan]} { # Didn't block waiting for end-of-line puts "$clientName - $line" puts $chan $line } } # Create the server socket and enter the event-loop to wait # for incoming connections... socket -server connect 12345 vwait forever .CE .SH "SEE ALSO" gets(n), open(n), read(n), socket(n), Tcl_StandardChannels(3) .SH KEYWORDS blocking, nonblocking tcl8.4.20/doc/trace.n0000644003604700454610000004076511737050674012755 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" Copyright (c) 2000 Ajuba Solutions. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH trace n "8.4" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME trace \- Monitor variable accesses, command usages and command executions .SH SYNOPSIS \fBtrace \fIoption\fR ?\fIarg arg ...\fR? .BE .SH DESCRIPTION .PP This command causes Tcl commands to be executed whenever certain operations are invoked. The legal \fIoption\fR's (which may be abbreviated) are: .TP \fBtrace add \fItype name ops ?args?\fR Where \fItype\fR is \fBcommand\fR, \fBexecution\fR, or \fBvariable\fR. .RS .TP \fBtrace add command\fR \fIname ops command\fR Arrange for \fIcommand\fR to be executed whenever command \fIname\fR is modified in one of the ways given by the list \fIops\fR. \fIName\fR will be resolved using the usual namespace resolution rules used by procedures. If the command does not exist, an error will be thrown. .RS .PP \fIOps\fR indicates which operations are of interest, and is a list of one or more of the following items: .TP \fBrename\fR Invoke \fIcommand\fR whenever the command is renamed. Note that renaming to the empty string is considered deletion, and will not be traced with '\fBrename\fR'. .TP \fBdelete\fR Invoke \fIcommand\fR when the command is deleted. Commands can be deleted explicitly by using the \fBrename\fR command to rename the command to an empty string. Commands are also deleted when the interpreter is deleted, but traces will not be invoked because there is no interpreter in which to execute them. .PP When the trace triggers, depending on the operations being traced, a number of arguments are appended to \fIcommand\fR so that the actual command is as follows: .CS \fIcommand oldName newName op\fR .CE \fIOldName\fR and \fInewName\fR give the traced command's current (old) name, and the name to which it is being renamed (the empty string if this is a 'delete' operation). \fIOp\fR indicates what operation is being performed on the command, and is one of \fBrename\fR or \fBdelete\fR as defined above. The trace operation cannot be used to stop a command from being deleted. Tcl will always remove the command once the trace is complete. Recursive renaming or deleting will not cause further traces of the same type to be evaluated, so a delete trace which itself deletes the command, or a rename trace which itself renames the command will not cause further trace evaluations to occur. Both \fIoldName\fR and \fInewName\fR are fully qualified with any namespace(s) in which they appear. .RE .TP \fBtrace add execution\fR \fIname ops command\fR Arrange for \fIcommand\fR to be executed whenever command \fIname\fR is executed, with traces occurring at the points indicated by the list \fIops\fR. \fIName\fR will be resolved using the usual namespace resolution rules used by procedures. If the command does not exist, an error will be thrown. .RS .PP \fIOps\fR indicates which operations are of interest, and is a list of one or more of the following items: .TP \fBenter\fR Invoke \fIcommand\fR whenever the command \fIname\fR is executed, just before the actual execution takes place. .TP \fBleave\fR Invoke \fIcommand\fR whenever the command \fIname\fR is executed, just after the actual execution takes place. .TP \fBenterstep\fR Invoke \fIcommand\fR for every Tcl command which is executed inside the procedure \fIname\fR, just before the actual execution takes place. For example if we have 'proc foo {} { puts "hello" }', then an \fIenterstep\fR trace would be invoked just before \fIputs "hello"\fR is executed. Setting an \fIenterstep\fR trace on a \fIcommand\fR will not result in an error and is simply ignored. .TP \fBleavestep\fR Invoke \fIcommand\fR for every Tcl command which is executed inside the procedure \fIname\fR, just after the actual execution takes place. Setting a \fIleavestep\fR trace on a \fIcommand\fR will not result in an error and is simply ignored. .PP When the trace triggers, depending on the operations being traced, a number of arguments are appended to \fIcommand\fR so that the actual command is as follows: .PP For \fBenter\fR and \fBenterstep\fR operations: .CS \fIcommand command-string op\fR .CE \fICommand-string\fR gives the complete current command being executed (the traced command for a \fBenter\fR operation, an arbitrary command for a \fBenterstep\fR operation), including all arguments in their fully expanded form. \fIOp\fR indicates what operation is being performed on the command execution, and is one of \fBenter\fR or \fBenterstep\fR as defined above. The trace operation can be used to stop the command from executing, by deleting the command in question. Of course when the command is subsequently executed, an 'invalid command' error will occur. .PP For \fBleave\fR and \fBleavestep\fR operations: .CS \fIcommand command-string code result op\fR .CE \fICommand-string\fR gives the complete current command being executed (the traced command for a \fBenter\fR operation, an arbitrary command for a \fBenterstep\fR operation), including all arguments in their fully expanded form. \fICode\fR gives the result code of that execution, and \fIresult\fR the result string. \fIOp\fR indicates what operation is being performed on the command execution, and is one of \fBleave\fR or \fBleavestep\fR as defined above. Note that the creation of many \fBenterstep\fR or \fBleavestep\fR traces can lead to unintuitive results, since the invoked commands from one trace can themselves lead to further command invocations for other traces. .PP \fICommand\fR executes in the same context as the code that invoked the traced operation: thus the \fIcommand\fR, if invoked from a procedure, will have access to the same local variables as code in the procedure. This context may be different than the context in which the trace was created. If \fIcommand\fR invokes a procedure (which it normally does) then the procedure will have to use upvar or uplevel commands if it wishes to access the local variables of the code which invoked the trace operation. .PP While \fIcommand\fR is executing during an execution trace, traces on \fIname\fR are temporarily disabled. This allows the \fIcommand\fR to execute \fIname\fR in its body without invoking any other traces again. If an error occurs while executing the \fIcommand\fR body, then the command \fIname\fR as a whole will return that same error. .PP When multiple traces are set on \fIname\fR, then for \fIenter\fR and \fIenterstep\fR operations, the traced commands are invoked in the reverse order of how the traces were originally created; and for \fIleave\fR and \fIleavestep\fR operations, the traced commands are invoked in the original order of creation. .PP The behavior of execution traces is currently undefined for a command \fIname\fR imported into another namespace. .RE .TP \fBtrace add variable\fI name ops command\fR Arrange for \fIcommand\fR to be executed whenever variable \fIname\fR is accessed in one of the ways given by the list \fIops\fR. \fIName\fR may refer to a normal variable, an element of an array, or to an array as a whole (i.e. \fIname\fR may be just the name of an array, with no parenthesized index). If \fIname\fR refers to a whole array, then \fIcommand\fR is invoked whenever any element of the array is manipulated. If the variable does not exist, it will be created but will not be given a value, so it will be visible to \fBnamespace which\fR queries, but not to \fBinfo exists\fR queries. .RS .PP \fIOps\fR indicates which operations are of interest, and is a list of one or more of the following items: .TP \fBarray\fR Invoke \fIcommand\fR whenever the variable is accessed or modified via the \fBarray\fR command, provided that \fIname\fR is not a scalar variable at the time that the \fBarray\fR command is invoked. If \fIname\fR is a scalar variable, the access via the \fBarray\fR command will not trigger the trace. .TP \fBread\fR Invoke \fIcommand\fR whenever the variable is read. .TP \fBwrite\fR Invoke \fIcommand\fR whenever the variable is written. .TP \fBunset\fR Invoke \fIcommand\fR whenever the variable is unset. Variables can be unset explicitly with the \fBunset\fR command, or implicitly when procedures return (all of their local variables are unset). Variables are also unset when interpreters are deleted, but traces will not be invoked because there is no interpreter in which to execute them. .PP When the trace triggers, three arguments are appended to \fIcommand\fR so that the actual command is as follows: .CS \fIcommand name1 name2 op\fR .CE \fIName1\fR and \fIname2\fR give the name(s) for the variable being accessed: if the variable is a scalar then \fIname1\fR gives the variable's name and \fIname2\fR is an empty string; if the variable is an array element then \fIname1\fR gives the name of the array and name2 gives the index into the array; if an entire array is being deleted and the trace was registered on the overall array, rather than a single element, then \fIname1\fR gives the array name and \fIname2\fR is an empty string. \fIName1\fR and \fIname2\fR are not necessarily the same as the name used in the \fBtrace variable\fR command: the \fBupvar\fR command allows a procedure to reference a variable under a different name. \fIOp\fR indicates what operation is being performed on the variable, and is one of \fBread\fR, \fBwrite\fR, or \fBunset\fR as defined above. .PP \fICommand\fR executes in the same context as the code that invoked the traced operation: if the variable was accessed as part of a Tcl procedure, then \fIcommand\fR will have access to the same local variables as code in the procedure. This context may be different than the context in which the trace was created. If \fIcommand\fR invokes a procedure (which it normally does) then the procedure will have to use \fBupvar\fR or \fBuplevel\fR if it wishes to access the traced variable. Note also that \fIname1\fR may not necessarily be the same as the name used to set the trace on the variable; differences can occur if the access is made through a variable defined with the \fBupvar\fR command. .PP For read and write traces, \fIcommand\fR can modify the variable to affect the result of the traced operation. If \fIcommand\fR modifies the value of a variable during a read or write trace, then the new value will be returned as the result of the traced operation. The return value from \fIcommand\fR is ignored except that if it returns an error of any sort then the traced operation also returns an error with the same error message returned by the trace command (this mechanism can be used to implement read-only variables, for example). For write traces, \fIcommand\fR is invoked after the variable's value has been changed; it can write a new value into the variable to override the original value specified in the write operation. To implement read-only variables, \fIcommand\fR will have to restore the old value of the variable. .PP While \fIcommand\fR is executing during a read or write trace, traces on the variable are temporarily disabled. This means that reads and writes invoked by \fIcommand\fR will occur directly, without invoking \fIcommand\fR (or any other traces) again. However, if \fIcommand\fR unsets the variable then unset traces will be invoked. .PP When an unset trace is invoked, the variable has already been deleted: it will appear to be undefined with no traces. If an unset occurs because of a procedure return, then the trace will be invoked in the variable context of the procedure being returned to: the stack frame of the returning procedure will no longer exist. Traces are not disabled during unset traces, so if an unset trace command creates a new trace and accesses the variable, the trace will be invoked. Any errors in unset traces are ignored. .PP If there are multiple traces on a variable they are invoked in order of creation, most-recent first. If one trace returns an error, then no further traces are invoked for the variable. If an array element has a trace set, and there is also a trace set on the array as a whole, the trace on the overall array is invoked before the one on the element. .PP Once created, the trace remains in effect either until the trace is removed with the \fBtrace remove variable\fR command described below, until the variable is unset, or until the interpreter is deleted. Unsetting an element of array will remove any traces on that element, but will not remove traces on the overall array. .PP This command returns an empty string. .RE .RE .TP \fBtrace remove \fItype name opList command\fR Where \fItype\fR is either \fBcommand\fR, \fBexecution\fR or \fBvariable\fR. .RS .TP \fBtrace remove command\fI name opList command\fR If there is a trace set on command \fIname\fR with the operations and command given by \fIopList\fR and \fIcommand\fR, then the trace is removed, so that \fIcommand\fR will never again be invoked. Returns an empty string. If \fIname\fR doesn't exist, the command will throw an error. .TP \fBtrace remove execution\fI name opList command\fR If there is a trace set on command \fIname\fR with the operations and command given by \fIopList\fR and \fIcommand\fR, then the trace is removed, so that \fIcommand\fR will never again be invoked. Returns an empty string. If \fIname\fR doesn't exist, the command will throw an error. .TP \fBtrace remove variable\fI name opList command\fR If there is a trace set on variable \fIname\fR with the operations and command given by \fIopList\fR and \fIcommand\fR, then the trace is removed, so that \fIcommand\fR will never again be invoked. Returns an empty string. .RE .TP \fBtrace info \fItype name\fR Where \fItype\fR is either \fBcommand\fR, \fBexecution\fR or \fBvariable\fR. .RS .TP \fBtrace info command\fI name\fR Returns a list containing one element for each trace currently set on command \fIname\fR. Each element of the list is itself a list containing two elements, which are the \fIopList\fR and \fIcommand\fR associated with the trace. If \fIname\fR doesn't have any traces set, then the result of the command will be an empty string. If \fIname\fR doesn't exist, the command will throw an error. .TP \fBtrace info execution\fI name\fR Returns a list containing one element for each trace currently set on command \fIname\fR. Each element of the list is itself a list containing two elements, which are the \fIopList\fR and \fIcommand\fR associated with the trace. If \fIname\fR doesn't have any traces set, then the result of the command will be an empty string. If \fIname\fR doesn't exist, the command will throw an error. .TP \fBtrace info variable\fI name\fR Returns a list containing one element for each trace currently set on variable \fIname\fR. Each element of the list is itself a list containing two elements, which are the \fIopList\fR and \fIcommand\fR associated with the trace. If \fIname\fR doesn't exist or doesn't have any traces set, then the result of the command will be an empty string. .RE .PP For backwards compatibility, three other subcommands are available: .RS .TP \fBtrace variable \fIname ops command\fR This is equivalent to \fBtrace add variable \fIname ops command\fR. .TP \fBtrace vdelete \fIname ops command\fR This is equivalent to \fBtrace remove variable \fIname ops command\fR .TP \fBtrace vinfo \fIname\fR This is equivalent to \fBtrace info variable \fIname\fR .RE .PP These subcommands are deprecated and will likely be removed in a future version of Tcl. They use an older syntax in which \fBarray\fR, \fBread\fR, \fBwrite\fR, \fBunset\fR are replaced by \fBa\fR, \fBr\fR, \fBw\fR and \fBu\fR respectively, and the \fIops\fR argument is not a list, but simply a string concatenation of the operations, such as \fBrwua\fR. .SH EXAMPLES Print a message whenever either of the global variables \fBfoo\fR and \fBbar\fR are updated, even if they have a different local name at the time (which can be done with the \fBupvar\fR command): .CS proc tracer {varname args} { upvar #0 $varname var puts "$varname was updated to be \e"$var\e"" } \fBtrace add\fR variable foo write "tracer foo" \fBtrace add\fR variable bar write "tracer bar" .CE .PP Ensure that the global variable \fBfoobar\fR always contains the product of the global variables \fBfoo\fR and \fBbar\fR: .CS proc doMult args { global foo bar foobar set foobar [expr {$foo * $bar}] } \fBtrace add\fR variable foo write doMult \fBtrace add\fR variable bar write doMult .CE .SH "SEE ALSO" set(n), unset(n) .SH KEYWORDS read, command, rename, variable, write, trace, unset tcl8.4.20/doc/unknown.n0000644003604700454610000000734211737050674013350 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH unknown n "" Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME unknown \- Handle attempts to use non-existent commands .SH SYNOPSIS \fBunknown \fIcmdName \fR?\fIarg arg ...\fR? .BE .SH DESCRIPTION .PP This command is invoked by the Tcl interpreter whenever a script tries to invoke a command that doesn't exist. The default implementation of \fBunknown\fR is a library procedure defined when Tcl initializes an interpreter. You can override the default \fBunknown\fR to change its functionality. Note that there is no default implementation of \fBunknown\fR in a safe interpreter. .PP If the Tcl interpreter encounters a command name for which there is not a defined command, then Tcl checks for the existence of a command named \fBunknown\fR. If there is no such command, then the interpreter returns an error. If the \fBunknown\fR command exists, then it is invoked with arguments consisting of the fully-substituted name and arguments for the original non-existent command. The \fBunknown\fR command typically does things like searching through library directories for a command procedure with the name \fIcmdName\fR, or expanding abbreviated command names to full-length, or automatically executing unknown commands as sub-processes. In some cases (such as expanding abbreviations) \fBunknown\fR will change the original command slightly and then (re-)execute it. The result of the \fBunknown\fR command is used as the result for the original non-existent command. .PP The default implementation of \fBunknown\fR behaves as follows. It first calls the \fBauto_load\fR library procedure to load the command. If this succeeds, then it executes the original command with its original arguments. If the auto-load fails then \fBunknown\fR calls \fBauto_execok\fR to see if there is an executable file by the name \fIcmd\fR. If so, it invokes the Tcl \fBexec\fR command with \fIcmd\fR and all the \fIargs\fR as arguments. If \fIcmd\fR can't be auto-executed, \fBunknown\fR checks to see if the command was invoked at top-level and outside of any script. If so, then \fBunknown\fR takes two additional steps. First, it sees if \fIcmd\fR has one of the following three forms: \fB!!\fR, \fB!\fIevent\fR, or \fB^\fIold\fB^\fInew\fR?\fB^\fR?. If so, then \fBunknown\fR carries out history substitution in the same way that \fBcsh\fR would for these constructs. Finally, \fBunknown\fR checks to see if \fIcmd\fR is a unique abbreviation for an existing Tcl command. If so, it expands the command name and executes the command with the original arguments. If none of the above efforts has been able to execute the command, \fBunknown\fR generates an error return. If the global variable \fBauto_noload\fR is defined, then the auto-load step is skipped. If the global variable \fBauto_noexec\fR is defined then the auto-exec step is skipped. Under normal circumstances the return value from \fBunknown\fR is the return value from the command that was eventually executed. .SH EXAMPLE Arrange for the \fBunknown\fR command to have its standard behavior except for first logging the fact that a command was not found: .PP .CS # Save the original one so we can chain to it rename \fBunknown\fR _original_unknown # Provide our own implementation proc \fBunknown\fR args { puts stderr "WARNING: unknown command: $args" uplevel 1 [list _original_unknown {expand}$args] } .CE .SH "SEE ALSO" info(n), proc(n), interp(n), library(n) .SH KEYWORDS error, non-existent command tcl8.4.20/doc/CrtInterp.30000644003604700454610000001345711737050674013474 0ustar dgp771div'\" '\" Copyright (c) 1989-1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_CreateInterp 3 7.5 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_CreateInterp, Tcl_DeleteInterp, Tcl_InterpDeleted \- create and delete Tcl command interpreters .SH SYNOPSIS .nf \fB#include \fR .sp Tcl_Interp * \fBTcl_CreateInterp\fR() .sp \fBTcl_DeleteInterp\fR(\fIinterp\fR) .sp int \fBTcl_InterpDeleted\fR(\fIinterp\fR) .SH ARGUMENTS .AS Tcl_Interp *interp .AP Tcl_Interp *interp in Token for interpreter to be destroyed. .BE .SH DESCRIPTION .PP \fBTcl_CreateInterp\fR creates a new interpreter structure and returns a token for it. The token is required in calls to most other Tcl procedures, such as \fBTcl_CreateCommand\fR, \fBTcl_Eval\fR, and \fBTcl_DeleteInterp\fR. Clients are only allowed to access a few of the fields of Tcl_Interp structures; see the \fBTcl_Interp\fR and \fBTcl_CreateCommand\fR man pages for details. The new interpreter is initialized with the built-in Tcl commands and with the variables documented in tclvars(n). To bind in additional commands, call \fBTcl_CreateCommand\fR. .PP \fBTcl_DeleteInterp\fR marks an interpreter as deleted; the interpreter will eventually be deleted when all calls to \fBTcl_Preserve\fR for it have been matched by calls to \fBTcl_Release\fR. At that time, all of the resources associated with it, including variables, procedures, and application-specific command bindings, will be deleted. After \fBTcl_DeleteInterp\fR returns any attempt to use \fBTcl_Eval\fR on the interpreter will fail and return \fBTCL_ERROR\fR. After the call to \fBTcl_DeleteInterp\fR it is safe to examine the interpreter's result, query or set the values of variables, define, undefine or retrieve procedures, and examine the runtime evaluation stack. See below, in the section \fBINTERPRETERS AND MEMORY MANAGEMENT\fR for details. .PP \fBTcl_InterpDeleted\fR returns nonzero if \fBTcl_DeleteInterp\fR was called with \fIinterp\fR as its argument; this indicates that the interpreter will eventually be deleted, when the last call to \fBTcl_Preserve\fR for it is matched by a call to \fBTcl_Release\fR. If nonzero is returned, further calls to \fBTcl_Eval\fR in this interpreter will return \fBTCL_ERROR\fR. .PP \fBTcl_InterpDeleted\fR is useful in deletion callbacks to distinguish between when only the memory the callback is responsible for is being deleted and when the whole interpreter is being deleted. In the former case the callback may recreate the data being deleted, but this would lead to an infinite loop if the interpreter were being deleted. .SH "INTERPRETERS AND MEMORY MANAGEMENT" .PP \fBTcl_DeleteInterp\fR can be called at any time on an interpreter that may be used by nested evaluations and C code in various extensions. Tcl implements a simple mechanism that allows callers to use interpreters without worrying about the interpreter being deleted in a nested call, and without requiring special code to protect the interpreter, in most cases. This mechanism ensures that nested uses of an interpreter can safely continue using it even after \fBTcl_DeleteInterp\fR is called. .PP The mechanism relies on matching up calls to \fBTcl_Preserve\fR with calls to \fBTcl_Release\fR. If \fBTcl_DeleteInterp\fR has been called, only when the last call to \fBTcl_Preserve\fR is matched by a call to \fBTcl_Release\fR, will the interpreter be freed. See the manual entry for \fBTcl_Preserve\fR for a description of these functions. .PP The rules for when the user of an interpreter must call \fBTcl_Preserve\fR and \fBTcl_Release\fR are simple: .TP Interpreters Passed As Arguments Functions that are passed an interpreter as an argument can safely use the interpreter without any special protection. Thus, when you write an extension consisting of new Tcl commands, no special code is needed to protect interpreters received as arguments. This covers the majority of all uses. .TP Interpreter Creation And Deletion When a new interpreter is created and used in a call to \fBTcl_Eval\fR, \fBTcl_VarEval\fR, \fBTcl_GlobalEval\fR, \fBTcl_SetVar\fR, or \fBTcl_GetVar\fR, a pair of calls to \fBTcl_Preserve\fR and \fBTcl_Release\fR should be wrapped around all uses of the interpreter. Remember that it is unsafe to use the interpreter once \fBTcl_Release\fR has been called. To ensure that the interpreter is properly deleted when it is no longer needed, call \fBTcl_InterpDeleted\fR to test if some other code already called \fBTcl_DeleteInterp\fR; if not, call \fBTcl_DeleteInterp\fR before calling \fBTcl_Release\fR in your own code. .TP Retrieving An Interpreter From A Data Structure When an interpreter is retrieved from a data structure (e.g. the client data of a callback) for use in \fBTcl_Eval\fR, \fBTcl_VarEval\fR, \fBTcl_GlobalEval\fR, \fBTcl_SetVar\fR, or \fBTcl_GetVar\fR, a pair of calls to \fBTcl_Preserve\fR and \fBTcl_Release\fR should be wrapped around all uses of the interpreter; it is unsafe to reuse the interpreter once \fBTcl_Release\fR has been called. If an interpreter is stored inside a callback data structure, an appropriate deletion cleanup mechanism should be set up by the code that creates the data structure so that the interpreter is removed from the data structure (e.g. by setting the field to NULL) when the interpreter is deleted. Otherwise, you may be using an interpreter that has been freed and whose memory may already have been reused. .PP All uses of interpreters in Tcl and Tk have already been protected. Extension writers should ensure that their code also properly protects any additional interpreters used, as described above. .SH "SEE ALSO" Tcl_Preserve(3), Tcl_Release(3) .SH KEYWORDS command, create, delete, interpreter tcl8.4.20/doc/eof.n0000644003604700454610000000305111737050674012413 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH eof n 7.5 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME eof \- Check for end of file condition on channel .SH SYNOPSIS \fBeof \fIchannelId\fR .BE .SH DESCRIPTION .PP Returns 1 if an end of file condition occurred during the most recent input operation on \fIchannelId\fR (such as \fBgets\fR), 0 otherwise. .PP \fIChannelId\fR must be an identifier for an open channel such as a Tcl standard channel (\fBstdin\fR, \fBstdout\fR, or \fBstderr\fR), the return value from an invocation of \fBopen\fR or \fBsocket\fR, or the result of a channel creation command provided by a Tcl extension. .SH EXAMPLES Read and print out the contents of a file line-by-line: .CS set f [open somefile.txt] while {1} { set line [gets $f] if {[\fBeof\fR $f]} { close $f break } puts "Read line: $line" } .CE .PP Read and print out the contents of a file by fixed-size records: .CS set f [open somefile.dat] fconfigure $f -translation binary set recordSize 40 while {1} { set record [read $f $recordSize] if {[\fBeof\fR $f]} { close $f break } puts "Read record: $record" } .CE .SH "SEE ALSO" file(n), open(n), close(n), fblocked(n), Tcl_StandardChannels(3) .SH KEYWORDS channel, end of file tcl8.4.20/doc/lindex.n0000644003604700454610000000530711737050674013133 0ustar dgp771div'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" Copyright (c) 2001 by Kevin B. Kenny. All rights reserved. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH lindex n 8.4 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME lindex \- Retrieve an element from a list .SH SYNOPSIS \fBlindex \fIlist ?index...?\fR .BE .SH DESCRIPTION .PP .VS 8.4 The \fBlindex\fP command accepts a parameter, \fIlist\fP, which it treats as a Tcl list. It also accepts zero or more \fIindices\fP into the list. The indices may be presented either consecutively on the command line, or grouped in a Tcl list and presented as a single argument. .PP If no indices are presented, the command takes the form: .CS lindex list .CE or .CS lindex list {} .CE In this case, the return value of \fBlindex\fR is simply the value of the \fIlist\fR parameter. .PP When presented with a single index, the \fBlindex\fR command treats \fIlist\fR as a Tcl list and returns the .VE \fIindex\fR'th element from it (0 refers to the first element of the list). In extracting the element, \fBlindex\fR observes the same rules concerning braces and quotes and backslashes as the Tcl command interpreter; however, variable substitution and command substitution do not occur. If \fIindex\fR is negative or greater than or equal to the number of elements in \fIvalue\fR, then an empty string is returned. If \fIindex\fR has the value \fBend\fR, it refers to the last element in the list, and \fBend\-\fIinteger\fR refers to the last element in the list minus the specified integer offset. .PP .VS 8.4 If additional \fIindex\fR arguments are supplied, then each argument is used in turn to select an element from the previous indexing operation, allowing the script to select elements from sublists. The command, .CS lindex $a 1 2 3 .CE or .CS lindex $a {1 2 3} .CE is synonymous with .CS lindex [lindex [lindex $a 1] 2] 3 .CE .SH EXAMPLES .CS \fBlindex\fR {a b c} \fI=> a b c\fR \fBlindex\fR {a b c} {} \fI=> a b c\fR \fBlindex\fR {a b c} 0 \fI=> a\fR \fBlindex\fR {a b c} 2 \fI=> c\fR \fBlindex\fR {a b c} end \fI=> c\fR \fBlindex\fR {a b c} end-1 \fI=> b\fR \fBlindex\fR {{a b c} {d e f} {g h i}} 2 1 \fI=> h\fR \fBlindex\fR {{a b c} {d e f} {g h i}} {2 1} \fI=> h\fR \fBlindex\fR {{{a b} {c d}} {{e f} {g h}}} 1 1 0 \fI=> g\fR \fBlindex\fR {{{a b} {c d}} {{e f} {g h}}} {1 1 0} \fI=> g\fR .CE .VE .SH "SEE ALSO" list(n), lappend(n), linsert(n), llength(n), lsearch(n), .VS 8.4 lset(n), .VE lsort(n), lrange(n), lreplace(n) .SH KEYWORDS element, index, list tcl8.4.20/doc/interp.n0000644003604700454610000007467711737050674013171 0ustar dgp771div'\" '\" Copyright (c) 1995-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH interp n 7.6 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME interp \- Create and manipulate Tcl interpreters .SH SYNOPSIS \fBinterp \fIoption \fR?\fIarg arg ...\fR? .BE .SH DESCRIPTION .PP This command makes it possible to create one or more new Tcl interpreters that co-exist with the creating interpreter in the same application. The creating interpreter is called the \fImaster\fR and the new interpreter is called a \fIslave\fR. A master can create any number of slaves, and each slave can itself create additional slaves for which it is master, resulting in a hierarchy of interpreters. .PP Each interpreter is independent from the others: it has its own name space for commands, procedures, and global variables. A master interpreter may create connections between its slaves and itself using a mechanism called an \fIalias\fR. An \fIalias\fR is a command in a slave interpreter which, when invoked, causes a command to be invoked in its master interpreter or in another slave interpreter. The only other connections between interpreters are through environment variables (the \fBenv\fR variable), which are normally shared among all interpreters in the application. Note that the name space for files (such as the names returned by the \fBopen\fR command) is no longer shared between interpreters. Explicit commands are provided to share files and to transfer references to open files from one interpreter to another. .PP The \fBinterp\fR command also provides support for \fIsafe\fR interpreters. A safe interpreter is a slave whose functions have been greatly restricted, so that it is safe to execute untrusted scripts without fear of them damaging other interpreters or the application's environment. For example, all IO channel creation commands and subprocess creation commands are made inaccessible to safe interpreters. .VS See \fBSAFE INTERPRETERS\fR below for more information on what features are present in a safe interpreter. The dangerous functionality is not removed from the safe interpreter; instead, it is \fIhidden\fR, so that only trusted interpreters can obtain access to it. For a detailed explanation of hidden commands, see \fBHIDDEN COMMANDS\fR, below. The alias mechanism can be used for protected communication (analogous to a kernel call) between a slave interpreter and its master. See \fBALIAS INVOCATION\fR, below, for more details on how the alias mechanism works. .VE .PP A qualified interpreter name is a proper Tcl lists containing a subset of its ancestors in the interpreter hierarchy, terminated by the string naming the interpreter in its immediate master. Interpreter names are relative to the interpreter in which they are used. For example, if \fBa\fR is a slave of the current interpreter and it has a slave \fBa1\fR, which in turn has a slave \fBa11\fR, the qualified name of \fBa11\fR in \fBa\fR is the list \fBa1 a11\fR. .PP The \fBinterp\fR command, described below, accepts qualified interpreter names as arguments; the interpreter in which the command is being evaluated can always be referred to as \fB{}\fR (the empty list or string). Note that it is impossible to refer to a master (ancestor) interpreter by name in a slave interpreter except through aliases. Also, there is no global name by which one can refer to the first interpreter created in an application. Both restrictions are motivated by safety concerns. .SH "THE INTERP COMMAND" .PP The \fBinterp\fR command is used to create, delete, and manipulate slave interpreters, and to share or transfer channels between interpreters. It can have any of several forms, depending on the \fIoption\fR argument: .TP \fBinterp\fR \fBalias\fR \fIsrcPath\fR \fIsrcToken\fR Returns a Tcl list whose elements are the \fItargetCmd\fR and \fIarg\fRs associated with the alias represented by \fIsrcToken\fR (this is the value returned when the alias was created; it is possible that the name of the source command in the slave is different from \fIsrcToken\fR). .TP \fBinterp\fR \fBalias\fR \fIsrcPath\fR \fIsrcToken\fR \fB{}\fR Deletes the alias for \fIsrcToken\fR in the slave interpreter identified by \fIsrcPath\fR. \fIsrcToken\fR refers to the value returned when the alias was created; if the source command has been renamed, the renamed command will be deleted. .TP \fBinterp\fR \fBalias\fR \fIsrcPath\fR \fIsrcCmd\fR \fItargetPath\fR \fItargetCmd \fR?\fIarg arg ...\fR? This command creates an alias between one slave and another (see the \fBalias\fR slave command below for creating aliases between a slave and its master). In this command, either of the slave interpreters may be anywhere in the hierarchy of interpreters under the interpreter invoking the command. \fISrcPath\fR and \fIsrcCmd\fR identify the source of the alias. \fISrcPath\fR is a Tcl list whose elements select a particular interpreter. For example, ``\fBa b\fR'' identifies an interpreter \fBb\fR, which is a slave of interpreter \fBa\fR, which is a slave of the invoking interpreter. An empty list specifies the interpreter invoking the command. \fIsrcCmd\fR gives the name of a new command, which will be created in the source interpreter. \fITargetPath\fR and \fItargetCmd\fR specify a target interpreter and command, and the \fIarg\fR arguments, if any, specify additional arguments to \fItargetCmd\fR which are prepended to any arguments specified in the invocation of \fIsrcCmd\fR. \fITargetCmd\fR may be undefined at the time of this call, or it may already exist; it is not created by this command. The alias arranges for the given target command to be invoked in the target interpreter whenever the given source command is invoked in the source interpreter. See \fBALIAS INVOCATION\fR below for more details. The command returns a token that uniquely identifies the command created \fIsrcCmd\fR, even if the command is renamed afterwards. The token may but does not have to be equal to \fIsrcCmd\fR. .TP \fBinterp\fR \fBaliases \fR?\fIpath\fR? This command returns a Tcl list of the tokens of all the source commands for aliases defined in the interpreter identified by \fIpath\fR. The tokens correspond to the values returned when the aliases were created (which may not be the same as the current names of the commands). .TP \fBinterp\fR \fBcreate \fR?\fB\-safe\fR? ?\fB\-\|\-\fR? ?\fIpath\fR? Creates a slave interpreter identified by \fIpath\fR and a new command, called a \fIslave command\fR. The name of the slave command is the last component of \fIpath\fR. The new slave interpreter and the slave command are created in the interpreter identified by the path obtained by removing the last component from \fIpath\fR. For example, if \fIpath is \fBa b c\fR then a new slave interpreter and slave command named \fBc\fR are created in the interpreter identified by the path \fBa b\fR. The slave command may be used to manipulate the new interpreter as described below. If \fIpath\fR is omitted, Tcl creates a unique name of the form \fBinterp\fIx\fR, where \fIx\fR is an integer, and uses it for the interpreter and the slave command. If the \fB\-safe\fR switch is specified (or if the master interpreter is a safe interpreter), the new slave interpreter will be created as a safe interpreter with limited functionality; otherwise the slave will include the full set of Tcl built-in commands and variables. The \fB\-\|\-\fR switch can be used to mark the end of switches; it may be needed if \fIpath\fR is an unusual value such as \fB\-safe\fR. The result of the command is the name of the new interpreter. The name of a slave interpreter must be unique among all the slaves for its master; an error occurs if a slave interpreter by the given name already exists in this master. The initial recursion limit of the slave interpreter is set to the current recursion limit of its parent interpreter. .TP \fBinterp\fR \fBdelete \fR?\fIpath ...?\fR Deletes zero or more interpreters given by the optional \fIpath\fR arguments, and for each interpreter, it also deletes its slaves. The command also deletes the slave command for each interpreter deleted. For each \fIpath\fR argument, if no interpreter by that name exists, the command raises an error. .TP \fBinterp\fR \fBeval\fR \fIpath arg \fR?\fIarg ...\fR? This command concatenates all of the \fIarg\fR arguments in the same fashion as the \fBconcat\fR command, then evaluates the resulting string as a Tcl script in the slave interpreter identified by \fIpath\fR. The result of this evaluation (including error information such as the \fBerrorInfo\fR and \fBerrorCode\fR variables, if an error occurs) is returned to the invoking interpreter. Note that the script will be executed in the current context stack frame of the \fIpath\fR interpreter; this is so that the implementations (in a master interpreter) of aliases in a slave interpreter can execute scripts in the slave that find out information about the slave's current state and stack frame. .TP \fBinterp exists \fIpath\fR Returns \fB1\fR if a slave interpreter by the specified \fIpath\fR exists in this master, \fB0\fR otherwise. If \fIpath\fR is omitted, the invoking interpreter is used. .VS "" BR .TP \fBinterp expose \fIpath\fR \fIhiddenName\fR ?\fIexposedCmdName\fR? Makes the hidden command \fIhiddenName\fR exposed, eventually bringing it back under a new \fIexposedCmdName\fR name (this name is currently accepted only if it is a valid global name space name without any ::), in the interpreter denoted by \fIpath\fR. If an exposed command with the targeted name already exists, this command fails. Hidden commands are explained in more detail in \fBHIDDEN COMMANDS\fR, below. .TP \fBinterp\fR \fBhide\fR \fIpath\fR \fIexposedCmdName\fR ?\fIhiddenCmdName\fR? Makes the exposed command \fIexposedCmdName\fR hidden, renaming it to the hidden command \fIhiddenCmdName\fR, or keeping the same name if \fIhiddenCmdName\fR is not given, in the interpreter denoted by \fIpath\fR. If a hidden command with the targeted name already exists, this command fails. Currently both \fIexposedCmdName\fR and \fIhiddenCmdName\fR can not contain namespace qualifiers, or an error is raised. Commands to be hidden by \fBinterp hide\fR are looked up in the global namespace even if the current namespace is not the global one. This prevents slaves from fooling a master interpreter into hiding the wrong command, by making the current namespace be different from the global one. Hidden commands are explained in more detail in \fBHIDDEN COMMANDS\fR, below. .TP \fBinterp\fR \fBhidden\fR \fIpath\fR Returns a list of the names of all hidden commands in the interpreter identified by \fIpath\fR. .TP \fBinterp\fR \fBinvokehidden\fR \fIpath\fR ?\fB-global\fR? \fIhiddenCmdName\fR ?\fIarg ...\fR? Invokes the hidden command \fIhiddenCmdName\fR with the arguments supplied in the interpreter denoted by \fIpath\fR. No substitutions or evaluation are applied to the arguments. If the \fB-global\fR flag is present, the hidden command is invoked at the global level in the target interpreter; otherwise it is invoked at the current call frame and can access local variables in that and outer call frames. Hidden commands are explained in more detail in \fBHIDDEN COMMANDS\fR, below. .VE .TP \fBinterp issafe\fR ?\fIpath\fR? Returns \fB1\fR if the interpreter identified by the specified \fIpath\fR is safe, \fB0\fR otherwise. .VS "" BR .TP \fBinterp marktrusted\fR \fIpath\fR Marks the interpreter identified by \fIpath\fR as trusted. Does not expose the hidden commands. This command can only be invoked from a trusted interpreter. The command has no effect if the interpreter identified by \fIpath\fR is already trusted. .VE .TP \fBinterp\fR \fBrecursionlimit\fR \fIpath\fR ?\fInewlimit\fR? Returns the maximum allowable nesting depth for the interpreter specified by \fIpath\fR. If \fInewlimit\fR is specified, the interpreter recursion limit will be set so that nesting of more than \fInewlimit\fR calls to \fBTcl_Eval()\fR and related procedures in that interpreter will return an error. The \fInewlimit\fR value is also returned. The \fInewlimit\fR value must be a positive integer between 1 and the maximum value of a non-long integer on the platform. .sp The command sets the maximum size of the Tcl call stack only. It cannot by itself prevent stack overflows on the C stack being used by the application. If your machine has a limit on the size of the C stack, you may get stack overflows before reaching the limit set by the command. If this happens, see if there is a mechanism in your system for increasing the maximum size of the C stack. .TP \fBinterp\fR \fBshare\fR \fIsrcPath channelId destPath\fR Causes the IO channel identified by \fIchannelId\fR to become shared between the interpreter identified by \fIsrcPath\fR and the interpreter identified by \fIdestPath\fR. Both interpreters have the same permissions on the IO channel. Both interpreters must close it to close the underlying IO channel; IO channels accessible in an interpreter are automatically closed when an interpreter is destroyed. .TP \fBinterp\fR \fBslaves\fR ?\fIpath\fR? Returns a Tcl list of the names of all the slave interpreters associated with the interpreter identified by \fIpath\fR. If \fIpath\fR is omitted, the invoking interpreter is used. .TP \fBinterp\fR \fBtarget\fR \fIpath alias\fR Returns a Tcl list describing the target interpreter for an alias. The alias is specified with an interpreter path and source command name, just as in \fBinterp alias\fR above. The name of the target interpreter is returned as an interpreter path, relative to the invoking interpreter. If the target interpreter for the alias is the invoking interpreter then an empty list is returned. If the target interpreter for the alias is not the invoking interpreter or one of its descendants then an error is generated. The target command does not have to be defined at the time of this invocation. .TP \fBinterp\fR \fBtransfer\fR \fIsrcPath channelId destPath\fR Causes the IO channel identified by \fIchannelId\fR to become available in the interpreter identified by \fIdestPath\fR and unavailable in the interpreter identified by \fIsrcPath\fR. .SH "SLAVE COMMAND" .PP For each slave interpreter created with the \fBinterp\fR command, a new Tcl command is created in the master interpreter with the same name as the new interpreter. This command may be used to invoke various operations on the interpreter. It has the following general form: .CS \fIslave command \fR?\fIarg arg ...\fR? .CE \fISlave\fR is the name of the interpreter, and \fIcommand\fR and the \fIarg\fRs determine the exact behavior of the command. The valid forms of this command are: .TP \fIslave \fBaliases\fR Returns a Tcl list whose elements are the tokens of all the aliases in \fIslave\fR. The tokens correspond to the values returned when the aliases were created (which may not be the same as the current names of the commands). .TP \fIslave \fBalias \fIsrcToken\fR Returns a Tcl list whose elements are the \fItargetCmd\fR and \fIarg\fRs associated with the alias represented by \fIsrcToken\fR (this is the value returned when the alias was created; it is possible that the actual source command in the slave is different from \fIsrcToken\fR). .TP \fIslave \fBalias \fIsrcToken \fB{}\fR Deletes the alias for \fIsrcToken\fR in the slave interpreter. \fIsrcToken\fR refers to the value returned when the alias was created; if the source command has been renamed, the renamed command will be deleted. .TP \fIslave \fBalias \fIsrcCmd targetCmd \fR?\fIarg ..\fR? Creates an alias such that whenever \fIsrcCmd\fR is invoked in \fIslave\fR, \fItargetCmd\fR is invoked in the master. The \fIarg\fR arguments will be passed to \fItargetCmd\fR as additional arguments, prepended before any arguments passed in the invocation of \fIsrcCmd\fR. See \fBALIAS INVOCATION\fR below for details. The command returns a token that uniquely identifies the command created \fIsrcCmd\fR, even if the command is renamed afterwards. The token may but does not have to be equal to \fIsrcCmd\fR. .TP \fIslave \fBeval \fIarg \fR?\fIarg ..\fR? This command concatenates all of the \fIarg\fR arguments in the same fashion as the \fBconcat\fR command, then evaluates the resulting string as a Tcl script in \fIslave\fR. The result of this evaluation (including error information such as the \fBerrorInfo\fR and \fBerrorCode\fR variables, if an error occurs) is returned to the invoking interpreter. Note that the script will be executed in the current context stack frame of \fIslave\fR; this is so that the implementations (in a master interpreter) of aliases in a slave interpreter can execute scripts in the slave that find out information about the slave's current state and stack frame. .VS "" BR .TP \fIslave \fBexpose \fIhiddenName \fR?\fIexposedCmdName\fR? This command exposes the hidden command \fIhiddenName\fR, eventually bringing it back under a new \fIexposedCmdName\fR name (this name is currently accepted only if it is a valid global name space name without any ::), in \fIslave\fR. If an exposed command with the targeted name already exists, this command fails. For more details on hidden commands, see \fBHIDDEN COMMANDS\fR, below. .TP \fIslave \fBhide \fIexposedCmdName\fR ?\fIhiddenCmdName\fR? This command hides the exposed command \fIexposedCmdName\fR, renaming it to the hidden command \fIhiddenCmdName\fR, or keeping the same name if the argument is not given, in the \fIslave\fR interpreter. If a hidden command with the targeted name already exists, this command fails. Currently both \fIexposedCmdName\fR and \fIhiddenCmdName\fR can not contain namespace qualifiers, or an error is raised. Commands to be hidden are looked up in the global namespace even if the current namespace is not the global one. This prevents slaves from fooling a master interpreter into hiding the wrong command, by making the current namespace be different from the global one. For more details on hidden commands, see \fBHIDDEN COMMANDS\fR, below. .TP \fIslave \fBhidden\fR Returns a list of the names of all hidden commands in \fIslave\fR. .TP \fIslave \fBinvokehidden\fR ?\fB-global\fR \fIhiddenName \fR?\fIarg ..\fR? This command invokes the hidden command \fIhiddenName\fR with the supplied arguments, in \fIslave\fR. No substitutions or evaluations are applied to the arguments. If the \fB-global\fR flag is given, the command is invoked at the global level in the slave; otherwise it is invoked at the current call frame and can access local variables in that or outer call frames. For more details on hidden commands, see \fBHIDDEN COMMANDS\fR, below. .VE .TP \fIslave \fBissafe\fR Returns \fB1\fR if the slave interpreter is safe, \fB0\fR otherwise. .VS "" BR .TP \fIslave \fBmarktrusted\fR Marks the slave interpreter as trusted. Can only be invoked by a trusted interpreter. This command does not expose any hidden commands in the slave interpreter. The command has no effect if the slave is already trusted. .VE .TP \fIslave\fR \fBrecursionlimit\fR ?\fInewlimit\fR? Returns the maximum allowable nesting depth for the \fIslave\fR interpreter. If \fInewlimit\fR is specified, the recursion limit in \fIslave\fR will be set so that nesting of more than \fInewlimit\fR calls to \fBTcl_Eval()\fR and related procedures in \fIslave\fR will return an error. The \fInewlimit\fR value is also returned. The \fInewlimit\fR value must be a positive integer between 1 and the maximum value of a non-long integer on the platform. .sp The command sets the maximum size of the Tcl call stack only. It cannot by itself prevent stack overflows on the C stack being used by the application. If your machine has a limit on the size of the C stack, you may get stack overflows before reaching the limit set by the command. If this happens, see if there is a mechanism in your system for increasing the maximum size of the C stack. .SH "SAFE INTERPRETERS" .PP A safe interpreter is one with restricted functionality, so that is safe to execute an arbitrary script from your worst enemy without fear of that script damaging the enclosing application or the rest of your computing environment. In order to make an interpreter safe, certain commands and variables are removed from the interpreter. For example, commands to create files on disk are removed, and the \fBexec\fR command is removed, since it could be used to cause damage through subprocesses. Limited access to these facilities can be provided, by creating aliases to the master interpreter which check their arguments carefully and provide restricted access to a safe subset of facilities. For example, file creation might be allowed in a particular subdirectory and subprocess invocation might be allowed for a carefully selected and fixed set of programs. .PP A safe interpreter is created by specifying the \fB\-safe\fR switch to the \fBinterp create\fR command. Furthermore, any slave created by a safe interpreter will also be safe. .PP A safe interpreter is created with exactly the following set of built-in commands: .DS .ta 1.2i 2.4i 3.6i \fBafter append array binary break case catch clock close concat continue eof error eval expr fblocked fcopy fileevent flush for foreach format gets global if incr info interp join lappend lindex linsert list llength lrange lreplace lsearch lsort namespace package pid proc puts read regexp regsub rename return scan seek set split string subst switch tell time trace unset update uplevel upvar variable vwait while\fR .DE .VS "" BR The following commands are hidden by \fBinterp create\fR when it creates a safe interpreter: .DS .ta 1.2i 2.4i 3.6i \fBcd encoding exec exit fconfigure file glob load open pwd socket source\fR .DE These commands can be recreated later as Tcl procedures or aliases, or re-exposed by \fBinterp expose\fR. .PP The following commands from Tcl's library of support procedures are not present in a safe interpreter: .DS .ta 1.6i 3.2i \fBauto_exec_ok auto_import auto_load auto_load_index auto_qualify unknown\fR .DE Note in particular that safe interpreters have no default \fBunknown\fR command, so Tcl's default autoloading facilities are not available. Autoload access to Tcl's commands that are normally autoloaded: .DS .ta 2.1i \fB auto_mkindex auto_mkindex_old auto_reset history parray pkg_mkIndex ::pkg::create ::safe::interpAddToAccessPath ::safe::interpCreate ::safe::interpConfigure ::safe::interpDelete ::safe::interpFindInAccessPath ::safe::interpInit ::safe::setLogCmd tcl_endOfWord tcl_findLibrary tcl_startOfNextWord tcl_startOfPreviousWord tcl_wordBreakAfter tcl_wordBreakBefore\fR .DE can only be provided by explicit definition of an \fBunknown\fR command in the safe interpreter. This will involve exposing the \fBsource\fR command. This is most easily accomplished by creating the safe interpreter with Tcl's \fBSafe\-Tcl\fR mechanism. \fBSafe\-Tcl\fR provides safe versions of \fBsource\fR, \fBload\fR, and other Tcl commands needed to support autoloading of commands and the loading of packages. .VE .PP In addition, the \fBenv\fR variable is not present in a safe interpreter, so it cannot share environment variables with other interpreters. The \fBenv\fR variable poses a security risk, because users can store sensitive information in an environment variable. For example, the PGP manual recommends storing the PGP private key protection password in the environment variable \fIPGPPASS\fR. Making this variable available to untrusted code executing in a safe interpreter would incur a security risk. .PP If extensions are loaded into a safe interpreter, they may also restrict their own functionality to eliminate unsafe commands. For a discussion of management of extensions for safety see the manual entries for \fBSafe\-Tcl\fR and the \fBload\fR Tcl command. .PP A safe interpreter may not alter the recursion limit of any interpreter, including itself. .SH "ALIAS INVOCATION" .PP The alias mechanism has been carefully designed so that it can be used safely when an untrusted script is executing in a safe slave and the target of the alias is a trusted master. The most important thing in guaranteeing safety is to ensure that information passed from the slave to the master is never evaluated or substituted in the master; if this were to occur, it would enable an evil script in the slave to invoke arbitrary functions in the master, which would compromise security. .PP When the source for an alias is invoked in the slave interpreter, the usual Tcl substitutions are performed when parsing that command. These substitutions are carried out in the source interpreter just as they would be for any other command invoked in that interpreter. The command procedure for the source command takes its arguments and merges them with the \fItargetCmd\fR and \fIarg\fRs for the alias to create a new array of arguments. If the words of \fIsrcCmd\fR were ``\fIsrcCmd arg1 arg2 ... argN\fR'', the new set of words will be ``\fItargetCmd arg arg ... arg arg1 arg2 ... argN\fR'', where \fItargetCmd\fR and \fIarg\fRs are the values supplied when the alias was created. \fITargetCmd\fR is then used to locate a command procedure in the target interpreter, and that command procedure is invoked with the new set of arguments. An error occurs if there is no command named \fItargetCmd\fR in the target interpreter. No additional substitutions are performed on the words: the target command procedure is invoked directly, without going through the normal Tcl evaluation mechanism. Substitutions are thus performed on each word exactly once: \fItargetCmd\fR and \fIargs\fR were substituted when parsing the command that created the alias, and \fIarg1 - argN\fR are substituted when the alias's source command is parsed in the source interpreter. .PP When writing the \fItargetCmd\fRs for aliases in safe interpreters, it is very important that the arguments to that command never be evaluated or substituted, since this would provide an escape mechanism whereby the slave interpreter could execute arbitrary code in the master. This in turn would compromise the security of the system. .VS .SH "HIDDEN COMMANDS" .PP Safe interpreters greatly restrict the functionality available to Tcl programs executing within them. Allowing the untrusted Tcl program to have direct access to this functionality is unsafe, because it can be used for a variety of attacks on the environment. However, there are times when there is a legitimate need to use the dangerous functionality in the context of the safe interpreter. For example, sometimes a program must be \fBsource\fRd into the interpreter. Another example is Tk, where windows are bound to the hierarchy of windows for a specific interpreter; some potentially dangerous functions, e.g. window management, must be performed on these windows within the interpreter context. .PP The \fBinterp\fR command provides a solution to this problem in the form of \fIhidden commands\fR. Instead of removing the dangerous commands entirely from a safe interpreter, these commands are hidden so they become unavailable to Tcl scripts executing in the interpreter. However, such hidden commands can be invoked by any trusted ancestor of the safe interpreter, in the context of the safe interpreter, using \fBinterp invoke\fR. Hidden commands and exposed commands reside in separate name spaces. It is possible to define a hidden command and an exposed command by the same name within one interpreter. .PP Hidden commands in a slave interpreter can be invoked in the body of procedures called in the master during alias invocation. For example, an alias for \fBsource\fR could be created in a slave interpreter. When it is invoked in the slave interpreter, a procedure is called in the master interpreter to check that the operation is allowable (e.g. it asks to source a file that the slave interpreter is allowed to access). The procedure then it invokes the hidden \fBsource\fR command in the slave interpreter to actually source in the contents of the file. Note that two commands named \fBsource\fR exist in the slave interpreter: the alias, and the hidden command. .PP Because a master interpreter may invoke a hidden command as part of handling an alias invocation, great care must be taken to avoid evaluating any arguments passed in through the alias invocation. Otherwise, malicious slave interpreters could cause a trusted master interpreter to execute dangerous commands on their behalf. See the section on \fBALIAS INVOCATION\fR for a more complete discussion of this topic. To help avoid this problem, no substitutions or evaluations are applied to arguments of \fBinterp invokehidden\fR. .PP Safe interpreters are not allowed to invoke hidden commands in themselves or in their descendants. This prevents safe slaves from gaining access to hidden functionality in themselves or their descendants. .PP The set of hidden commands in an interpreter can be manipulated by a trusted interpreter using \fBinterp expose\fR and \fBinterp hide\fR. The \fBinterp expose\fR command moves a hidden command to the set of exposed commands in the interpreter identified by \fIpath\fR, potentially renaming the command in the process. If an exposed command by the targeted name already exists, the operation fails. Similarly, \fBinterp hide\fR moves an exposed command to the set of hidden commands in that interpreter. Safe interpreters are not allowed to move commands between the set of hidden and exposed commands, in either themselves or their descendants. .PP Currently, the names of hidden commands cannot contain namespace qualifiers, and you must first rename a command in a namespace to the global namespace before you can hide it. Commands to be hidden by \fBinterp hide\fR are looked up in the global namespace even if the current namespace is not the global one. This prevents slaves from fooling a master interpreter into hiding the wrong command, by making the current namespace be different from the global one. .VE .SH CREDITS .PP This mechanism is based on the Safe-Tcl prototype implemented by Nathaniel Borenstein and Marshall Rose. .SH EXAMPLES Creating and using an alias for a command in the current interpreter: .CS \fBinterp alias\fR {} getIndex {} lsearch {alpha beta gamma delta} set idx [getIndex delta] .CE .PP Executing an arbitrary command in a safe interpreter where every invokation of \fBlappend\fR is logged: .CS set i [\fBinterp create\fR -safe] \fBinterp hide\fR $i lappend \fBinterp alias\fR $i lappend {} loggedLappend $i proc loggedLappend {i args} { puts "logged invokation of lappend $args" # Be extremely careful about command construction eval [linsert $args 0 \\ \fBinterp invokehidden\fR $i lappend] } \fBinterp eval\fR $i $someUntrustedScript .CE .SH "SEE ALSO" load(n), safe(n), Tcl_CreateSlave(3) .SH KEYWORDS alias, master interpreter, safe interpreter, slave interpreter tcl8.4.20/doc/Hash.30000644003604700454610000003076711737050674012450 0ustar dgp771div'\" '\" Copyright (c) 1989-1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_Hash 3 "" Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_InitHashTable, Tcl_InitCustomHashTable, Tcl_InitObjHashTable, Tcl_DeleteHashTable, Tcl_CreateHashEntry, Tcl_DeleteHashEntry, Tcl_FindHashEntry, Tcl_GetHashValue, Tcl_SetHashValue, Tcl_GetHashKey, Tcl_FirstHashEntry, Tcl_NextHashEntry, Tcl_HashStats \- procedures to manage hash tables .SH SYNOPSIS .nf \fB#include \fR .sp \fBTcl_InitHashTable\fR(\fItablePtr, keyType\fR) .sp \fBTcl_InitCustomHashTable\fR(\fItablePtr, keyType, typePtr\fR) .sp \fBTcl_InitObjHashTable\fR(\fItablePtr\fR) .sp \fBTcl_DeleteHashTable\fR(\fItablePtr\fR) .sp Tcl_HashEntry * \fBTcl_CreateHashEntry\fR(\fItablePtr, key, newPtr\fR) .sp \fBTcl_DeleteHashEntry\fR(\fIentryPtr\fR) .sp Tcl_HashEntry * \fBTcl_FindHashEntry\fR(\fItablePtr, key\fR) .sp ClientData \fBTcl_GetHashValue\fR(\fIentryPtr\fR) .sp \fBTcl_SetHashValue\fR(\fIentryPtr, value\fR) .sp char * \fBTcl_GetHashKey\fR(\fItablePtr, entryPtr\fR) .sp Tcl_HashEntry * \fBTcl_FirstHashEntry\fR(\fItablePtr, searchPtr\fR) .sp Tcl_HashEntry * \fBTcl_NextHashEntry\fR(\fIsearchPtr\fR) .sp CONST char * \fBTcl_HashStats\fR(\fItablePtr\fR) .SH ARGUMENTS .AS Tcl_HashSearch *searchPtr .AP Tcl_HashTable *tablePtr in Address of hash table structure (for all procedures but \fBTcl_InitHashTable\fR, this must have been initialized by previous call to \fBTcl_InitHashTable\fR). .AP int keyType in Kind of keys to use for new hash table. Must be either TCL_STRING_KEYS, TCL_ONE_WORD_KEYS, TCL_CUSTOM_TYPE_KEYS, TCL_CUSTOM_PTR_KEYS, or an integer value greater than 1. .AP Tcl_HashKeyType *typePtr in Address of structure which defines the behaviour of the hash table. .AP "CONST char" *key in Key to use for probe into table. Exact form depends on \fIkeyType\fR used to create table. .AP int *newPtr out The word at \fI*newPtr\fR is set to 1 if a new entry was created and 0 if there was already an entry for \fIkey\fR. .AP Tcl_HashEntry *entryPtr in Pointer to hash table entry. .AP ClientData value in New value to assign to hash table entry. Need not have type ClientData, but must fit in same space as ClientData. .AP Tcl_HashSearch *searchPtr in Pointer to record to use to keep track of progress in enumerating all the entries in a hash table. .BE .SH DESCRIPTION .PP A hash table consists of zero or more entries, each consisting of a key and a value. Given the key for an entry, the hashing routines can very quickly locate the entry, and hence its value. There may be at most one entry in a hash table with a particular key, but many entries may have the same value. Keys can take one of four forms: strings, one-word values, integer arrays, or custom keys defined by a Tcl_HashKeyType structure (See section \fBTHE TCL_HASHKEYTYPE STRUCTURE\fR below). All of the keys in a given table have the same form, which is specified when the table is initialized. .PP The value of a hash table entry can be anything that fits in the same space as a ``char *'' pointer. Values for hash table entries are managed entirely by clients, not by the hash module itself. Typically each entry's value is a pointer to a data structure managed by client code. .PP Hash tables grow gracefully as the number of entries increases, so that there are always less than three entries per hash bucket, on average. This allows for fast lookups regardless of the number of entries in a table. .PP The core provides three functions for the initialization of hash tables, Tcl_InitHashTable, Tcl_InitObjHashTable and Tcl_InitCustomHashTable. .PP \fBTcl_InitHashTable\fR initializes a structure that describes a new hash table. The space for the structure is provided by the caller, not by the hash module. The value of \fIkeyType\fR indicates what kinds of keys will be used for all entries in the table. All of the key types described later are allowed, with the exception of \fBTCL_CUSTOM_TYPE_KEYS\fR and \fBTCL_CUSTOM_PTR_KEYS\fR. .PP \fBTcl_InitObjHashTable\fR is a wrapper around \fBTcl_InitCustomHashTable\fR and initializes a hash table whose keys are Tcl_Obj *. .PP \fBTcl_InitCustomHashTable\fR initializes a structure that describes a new hash table. The space for the structure is provided by the caller, not by the hash module. The value of \fIkeyType\fR indicates what kinds of keys will be used for all entries in the table. \fIKeyType\fR must have one of the following values: .IP \fBTCL_STRING_KEYS\fR 25 Keys are null-terminated strings. They are passed to hashing routines using the address of the first character of the string. .IP \fBTCL_ONE_WORD_KEYS\fR 25 Keys are single-word values; they are passed to hashing routines and stored in hash table entries as ``char *'' values. The pointer value is the key; it need not (and usually doesn't) actually point to a string. .IP \fBTCL_CUSTOM_TYPE_KEYS\fR 25 Keys are of arbitrary type, and are stored in the entry. Hashing and comparison is determined by \fItypePtr\fR. The Tcl_HashKeyType structure is described in the section \fBTHE TCL_HASHKEYTYPE STRUCTURE\fR below. .IP \fBTCL_CUSTOM_PTR_KEYS\fR 25 Keys are pointers to an arbitrary type, and are stored in the entry. Hashing and comparison is determined by \fItypePtr\fR. The Tcl_HashKeyType structure is described in the section \fBTHE TCL_HASHKEYTYPE STRUCTURE\fR below. .IP \fIother\fR 25 If \fIkeyType\fR is not one of the above, then it must be an integer value greater than 1. In this case the keys will be arrays of ``int'' values, where \fIkeyType\fR gives the number of ints in each key. This allows structures to be used as keys. All keys must have the same size. Array keys are passed into hashing functions using the address of the first int in the array. .PP \fBTcl_DeleteHashTable\fR deletes all of the entries in a hash table and frees up the memory associated with the table's bucket array and entries. It does not free the actual table structure (pointed to by \fItablePtr\fR), since that memory is assumed to be managed by the client. \fBTcl_DeleteHashTable\fR also does not free or otherwise manipulate the values of the hash table entries. If the entry values point to dynamically-allocated memory, then it is the client's responsibility to free these structures before deleting the table. .PP \fBTcl_CreateHashEntry\fR locates the entry corresponding to a particular key, creating a new entry in the table if there wasn't already one with the given key. If an entry already existed with the given key then \fI*newPtr\fR is set to zero. If a new entry was created, then \fI*newPtr\fR is set to a non-zero value and the value of the new entry will be set to zero. The return value from \fBTcl_CreateHashEntry\fR is a pointer to the entry, which may be used to retrieve and modify the entry's value or to delete the entry from the table. .PP \fBTcl_DeleteHashEntry\fR will remove an existing entry from a table. The memory associated with the entry itself will be freed, but the client is responsible for any cleanup associated with the entry's value, such as freeing a structure that it points to. .PP \fBTcl_FindHashEntry\fR is similar to \fBTcl_CreateHashEntry\fR except that it doesn't create a new entry if the key doesn't exist; instead, it returns NULL as result. .PP \fBTcl_GetHashValue\fR and \fBTcl_SetHashValue\fR are used to read and write an entry's value, respectively. Values are stored and retrieved as type ``ClientData'', which is large enough to hold a pointer value. On almost all machines this is large enough to hold an integer value too. .PP \fBTcl_GetHashKey\fR returns the key for a given hash table entry, either as a pointer to a string, a one-word (``char *'') key, or as a pointer to the first word of an array of integers, depending on the \fIkeyType\fR used to create a hash table. In all cases \fBTcl_GetHashKey\fR returns a result with type ``char *''. When the key is a string or array, the result of \fBTcl_GetHashKey\fR points to information in the table entry; this information will remain valid until the entry is deleted or its table is deleted. .PP \fBTcl_FirstHashEntry\fR and \fBTcl_NextHashEntry\fR may be used to scan all of the entries in a hash table. A structure of type ``Tcl_HashSearch'', provided by the client, is used to keep track of progress through the table. \fBTcl_FirstHashEntry\fR initializes the search record and returns the first entry in the table (or NULL if the table is empty). Each subsequent call to \fBTcl_NextHashEntry\fR returns the next entry in the table or NULL if the end of the table has been reached. A call to \fBTcl_FirstHashEntry\fR followed by calls to \fBTcl_NextHashEntry\fR will return each of the entries in the table exactly once, in an arbitrary order. It is unadvisable to modify the structure of the table, e.g. by creating or deleting entries, while the search is in progress. .PP \fBTcl_HashStats\fR returns a dynamically-allocated string with overall information about a hash table, such as the number of entries it contains, the number of buckets in its hash array, and the utilization of the buckets. It is the caller's responsibility to free the result string by passing it to \fBckfree\fR. .PP The header file \fBtcl.h\fR defines the actual data structures used to implement hash tables. This is necessary so that clients can allocate Tcl_HashTable structures and so that macros can be used to read and write the values of entries. However, users of the hashing routines should never refer directly to any of the fields of any of the hash-related data structures; use the procedures and macros defined here. .SH "THE TCL_HASHKEYTYPE STRUCTURE" .PP Extension writers can define new hash key types by defining four procedures, initializing a Tcl_HashKeyType structure to describe the type, and calling \fBTcl_InitCustomHashTable\fR. The \fBTcl_HashKeyType\fR structure is defined as follows: .CS typedef struct Tcl_HashKeyType { int \fIversion\fR; int \fIflags\fR; Tcl_HashKeyProc *\fIhashKeyProc\fR; Tcl_CompareHashKeysProc *\fIcompareKeysProc\fR; Tcl_AllocHashEntryProc *\fIallocEntryProc\fR; Tcl_FreeHashEntryProc *\fIfreeEntryProc\fR; } Tcl_HashKeyType; .CE .PP The \fIversion\fR member is the version of the table. If this structure is extended in future then the version can be used to distinguish between different structures. It should be set to \fBTCL_HASH_KEY_TYPE_VERSION\fR. .PP The \fIflags\fR member is one or more of the following values OR'ed together: .IP \fBTCL_HASH_KEY_RANDOMIZE_HASH\fR 25 There are some things, pointers for example which don't hash well because they do not use the lower bits. If this flag is set then the hash table will attempt to rectify this by randomising the bits and then using the upper N bits as the index into the table. .PP The \fIhashKeyProc\fR member contains the address of a function called to calculate a hash value for the key. .CS typedef unsigned int (Tcl_HashKeyProc) ( Tcl_HashTable *\fItablePtr\fR, VOID *\fIkeyPtr\fR); .CE If this is NULL then \fIkeyPtr\fR is used and \fBTCL_HASH_KEY_RANDOMIZE_HASH\fR is assumed. .PP The \fIcompareKeysProc\fR member contains the address of a function called to compare two keys. .CS typedef int (Tcl_CompareHashKeysProc) (VOID *\fIkeyPtr\fR, Tcl_HashEntry *\fIhPtr\fR); .CE If this is NULL then the \fIkeyPtr\fR pointers are compared. If the keys don't match then the function returns 0, otherwise it returns 1. .PP The \fIallocEntryProc\fR member contains the address of a function called to allocate space for an entry and initialise the key. .CS typedef Tcl_HashEntry *(Tcl_AllocHashEntryProc) ( Tcl_HashTable *\fItablePtr\fR, VOID *\fIkeyPtr\fR); .CE If this is NULL then Tcl_Alloc is used to allocate enough space for a Tcl_HashEntry and the key pointer is assigned to key.oneWordValue. String keys and array keys use this function to allocate enough space for the entry and the key in one block, rather than doing it in two blocks. This saves space for a pointer to the key from the entry and another memory allocation. Tcl_Obj * keys use this function to allocate enough space for an entry and increment the reference count on the object. If .PP The \fIfreeEntryProc\fR member contains the address of a function called to free space for an entry. .CS typedef void (Tcl_FreeHashEntryProc) (Tcl_HashEntry *\fIhPtr\fR); .CE If this is NULL then Tcl_Free is used to free the space for the entry. Tcl_Obj * keys use this function to decrement the reference count on the object. .SH KEYWORDS hash table, key, lookup, search, value tcl8.4.20/doc/update.n0000644003604700454610000000440511737050674013130 0ustar dgp771div'\" '\" Copyright (c) 1990-1992 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH update n 7.5 Tcl "Tcl Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME update \- Process pending events and idle callbacks .SH SYNOPSIS \fBupdate\fR ?\fBidletasks\fR? .BE .SH DESCRIPTION .PP This command is used to bring the application ``up to date'' by entering the event loop repeatedly until all pending events (including idle callbacks) have been processed. .PP If the \fBidletasks\fR keyword is specified as an argument to the command, then no new events or errors are processed; only idle callbacks are invoked. This causes operations that are normally deferred, such as display updates and window layout calculations, to be performed immediately. .PP The \fBupdate idletasks\fR command is useful in scripts where changes have been made to the application's state and you want those changes to appear on the display immediately, rather than waiting for the script to complete. Most display updates are performed as idle callbacks, so \fBupdate idletasks\fR will cause them to run. However, there are some kinds of updates that only happen in response to events, such as those triggered by window size changes; these updates will not occur in \fBupdate idletasks\fR. .PP The \fBupdate\fR command with no options is useful in scripts where you are performing a long-running computation but you still want the application to respond to events such as user interactions; if you occasionally call \fBupdate\fR then user input will be processed during the next call to \fBupdate\fR. .SH EXAMPLE Run computations for about a second and then finish: .CS set x 1000 set done 0 after 1000 set done 1 while {!$done} { # A very silly example! set x [expr {log($x) ** 2.8}] # Test to see if our time-limit has been hit. This would # also give a chance for serving network sockets and, if # the Tk package is loaded, updating a user interface. \fBupdate\fR } .CE .SH "SEE ALSO" after(n), bgerror(n) .SH KEYWORDS event, flush, handler, idle, update tcl8.4.20/doc/CrtFileHdlr.30000644003604700454610000000672311737050674013722 0ustar dgp771div'\" '\" Copyright (c) 1990-1994 The Regents of the University of California. '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_CreateFileHandler 3 8.0 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_CreateFileHandler, Tcl_DeleteFileHandler \- associate procedure callbacks with files or devices (Unix only) .SH SYNOPSIS .nf \fB#include \fR .VS .sp \fBTcl_CreateFileHandler\fR(\fIfd, mask, proc, clientData\fR) .sp \fBTcl_DeleteFileHandler\fR(\fIfd\fR) .VE .SH ARGUMENTS .AS Tcl_FileProc clientData .VS .AP int fd in Unix file descriptor for an open file or device. .VE .AP int mask in Conditions under which \fIproc\fR should be called: OR-ed combination of \fBTCL_READABLE\fR, \fBTCL_WRITABLE\fR, and \fBTCL_EXCEPTION\fR. May be set to 0 to temporarily disable a handler. .AP Tcl_FileProc *proc in Procedure to invoke whenever the file or device indicated by \fIfile\fR meets the conditions specified by \fImask\fR. .AP ClientData clientData in Arbitrary one-word value to pass to \fIproc\fR. .BE .SH DESCRIPTION .PP .VS \fBTcl_CreateFileHandler\fR arranges for \fIproc\fR to be invoked in the future whenever I/O becomes possible on a file or an exceptional condition exists for the file. The file is indicated by \fIfd\fR, and the conditions of interest .VE are indicated by \fImask\fR. For example, if \fImask\fR is \fBTCL_READABLE\fR, \fIproc\fR will be called when the file is readable. The callback to \fIproc\fR is made by \fBTcl_DoOneEvent\fR, so \fBTcl_CreateFileHandler\fR is only useful in programs that dispatch events through \fBTcl_DoOneEvent\fR or through Tcl commands such as \fBvwait\fR. .PP \fIProc\fR should have arguments and result that match the type \fBTcl_FileProc\fR: .CS typedef void Tcl_FileProc( ClientData \fIclientData\fR, int \fImask\fR); .CE The \fIclientData\fR parameter to \fIproc\fR is a copy of the \fIclientData\fR argument given to \fBTcl_CreateFileHandler\fR when the callback was created. Typically, \fIclientData\fR points to a data structure containing application-specific information about the file. \fIMask\fR is an integer mask indicating which of the requested conditions actually exists for the file; it will contain a subset of the bits in the \fImask\fR argument to \fBTcl_CreateFileHandler\fR. .PP .PP There may exist only one handler for a given file at a given time. If \fBTcl_CreateFileHandler\fR is called when a handler already exists for \fIfd\fR, then the new callback replaces the information that was previously recorded. .PP \fBTcl_DeleteFileHandler\fR may be called to delete the file handler for \fIfd\fR; if no handler exists for the file given by \fIfd\fR then the procedure has no effect. .PP The purpose of file handlers is to enable an application to respond to events while waiting for files to become ready for I/O. For this to work correctly, the application may need to use non-blocking I/O operations on the files for which handlers are declared. Otherwise the application may block if it reads or writes too much data; while waiting for the I/O to complete the application won't be able to service other events. Use \fBTcl_SetChannelOption\fR with \fB\-blocking\fR to set the channel into blocking or nonblocking mode as required. .PP .VS Note that these interfaces are only supported by the Unix implementation of the Tcl notifier. .VE .SH KEYWORDS callback, file, handler tcl8.4.20/doc/SubstObj.30000644003604700454610000000527111737050674013310 0ustar dgp771div'\" '\" Copyright (c) 2001 Donal K. Fellows '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros .TH Tcl_SubstObj 3 8.4 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_SubstObj \- perform substitutions on Tcl objects .SH SYNOPSIS .nf \fB#include \fR .sp Tcl_Obj * \fBTcl_SubstObj\fR(\fIinterp, objPtr, flags\fR) .SH ARGUMENTS .AS Tcl_Interp **termPtr; .AP Tcl_Interp *interp in Interpreter in which to execute Tcl scripts and lookup variables. If an error occurs, the interpreter's result is modified to hold an error message. .AP Tcl_Obj *objPtr in A Tcl object containing the string to perform substitutions on. .AP int flags in ORed combination of flag bits that specify which substitutions to perform. The flags \fBTCL_SUBST_COMMANDS\fR, \fBTCL_SUBST_VARIABLES\fR and \fBTCL_SUBST_BACKSLASHES\fR are currently supported, and \fBTCL_SUBST_ALL\fR is provided as a convenience for the common case where all substitutions are desired. .BE .SH DESCRIPTION .PP The \fBTcl_SubstObj\fR function is used to perform substitutions on strings in the fashion of the \fBsubst\fR command. It gets the value of the string contained in \fIobjPtr\fR and scans it, copying characters and performing the chosen substitutions as it goes to an output object which is returned as the result of the function. In the event of an error occurring during the execution of a command or variable substitution, the function returns NULL and an error message is left in \fIinterp\fR's result. .PP Three kinds of substitutions are supported. When the \fBTCL_SUBST_BACKSLASHES\fR bit is set in \fIflags\fR, sequences that look like backslash substitutions for Tcl commands are replaced by their corresponding character. .PP When the \fBTCL_SUBST_VARIABLES\fR bit is set in \fIflags\fR, sequences that look like variable substitutions for Tcl commands are replaced by the contents of the named variable. .PP When th \fBTCL_SUBST_COMMANDS\fR bit is set in \fIflags\fR, sequences that look like command substitutions for Tcl commands are replaced by the result of evaluating that script. Where an uncaught continue exception occurs during the evaluation of a command substitution, an empty string is substituted for the command. Where an uncaught break exception occurs during the evaluation of a command substitution, the result of the whole substitution on \fIobjPtr\fR will be truncated at the point immediately before the start of the command substitution, and no characters will be added to the result or substitutions performed after that point. .SH "SEE ALSO" subst(n) .SH KEYWORDS backslash substitution, command substitution, variable substitution tcl8.4.20/license.terms0000644003604700454610000000432111737050674013415 0ustar dgp771divThis software is copyrighted by the Regents of the University of California, Sun Microsystems, Inc., Scriptics Corporation, ActiveState Corporation and other parties. The following terms apply to all files associated with the software unless explicitly disclaimed in individual files. The authors hereby grant permission to use, copy, modify, distribute, and license this software and its documentation for any purpose, provided that existing copyright notices are retained in all copies and that this notice is included verbatim in any distributions. No written agreement, license, or royalty fee is required for any of the authorized uses. Modifications to this software may be copyrighted by their authors and need not follow the licensing terms described here, provided that the new terms are clearly indicated on the first page of each file where they apply. IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. GOVERNMENT USE: If you are acquiring this software on behalf of the U.S. government, the Government shall have only "Restricted Rights" in the software and related documentation as defined in the Federal Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are acquiring the software on behalf of the Department of Defense, the software shall be classified as "Commercial Computer Software" and the Government shall have only "Restricted Rights" as defined in Clause 252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the authors grant the U.S. Government and others acting in its behalf permission to use and distribute the software in accordance with the terms specified in this license. tcl8.4.20/compat/0000755003604700454610000000000012153151142012163 5ustar dgp771divtcl8.4.20/compat/strtoul.c0000644003604700454610000001163711737050674014072 0ustar dgp771div/* * strtoul.c -- * * Source code for the "strtoul" library procedure. * * Copyright (c) 1988 The Regents of the University of California. * Copyright (c) 1994 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" /* * The table below is used to convert from ASCII digits to a * numerical equivalent. It maps from '0' through 'z' to integers * (100 for non-digit characters). */ static char cvtIn[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, /* '0' - '9' */ 100, 100, 100, 100, 100, 100, 100, /* punctuation */ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, /* 'A' - 'Z' */ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 100, 100, 100, 100, 100, 100, /* punctuation */ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, /* 'a' - 'z' */ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35}; /* *---------------------------------------------------------------------- * * strtoul -- * * Convert an ASCII string into an integer. * * Results: * The return value is the integer equivalent of string. If endPtr * is non-NULL, then *endPtr is filled in with the character * after the last one that was part of the integer. If string * doesn't contain a valid integer value, then zero is returned * and *endPtr is set to string. * * Side effects: * None. * *---------------------------------------------------------------------- */ unsigned long int strtoul(string, endPtr, base) CONST char *string; /* String of ASCII digits, possibly * preceded by white space. For bases * greater than 10, either lower- or * upper-case digits may be used. */ char **endPtr; /* Where to store address of terminating * character, or NULL. */ int base; /* Base for conversion. Must be less * than 37. If 0, then the base is chosen * from the leading characters of string: * "0x" means hex, "0" means octal, anything * else means decimal. */ { register CONST char *p; register unsigned long int result = 0; register unsigned digit; int anyDigits = 0; int negative=0; int overflow=0; /* * Skip any leading blanks. */ p = string; while (isspace(UCHAR(*p))) { p += 1; } if (*p == '-') { negative = 1; p += 1; } else { if (*p == '+') { p += 1; } } /* * If no base was provided, pick one from the leading characters * of the string. */ if (base == 0) { if (*p == '0') { p += 1; if ((*p == 'x') || (*p == 'X')) { p += 1; base = 16; } else { /* * Must set anyDigits here, otherwise "0" produces a * "no digits" error. */ anyDigits = 1; base = 8; } } else base = 10; } else if (base == 16) { /* * Skip a leading "0x" from hex numbers. */ if ((p[0] == '0') && ((p[1] == 'x') || (p[1] == 'X'))) { p += 2; } } /* * Sorry this code is so messy, but speed seems important. Do * different things for base 8, 10, 16, and other. */ if (base == 8) { unsigned long maxres = ULONG_MAX >> 3; for ( ; ; p += 1) { digit = *p - '0'; if (digit > 7) { break; } if (result > maxres) { overflow = 1; } result = (result << 3); if (digit > (ULONG_MAX - result)) { overflow = 1; } result += digit; anyDigits = 1; } } else if (base == 10) { unsigned long maxres = ULONG_MAX / 10; for ( ; ; p += 1) { digit = *p - '0'; if (digit > 9) { break; } if (result > maxres) { overflow = 1; } result *= 10; if (digit > (ULONG_MAX - result)) { overflow = 1; } result += digit; anyDigits = 1; } } else if (base == 16) { unsigned long maxres = ULONG_MAX >> 4; for ( ; ; p += 1) { digit = *p - '0'; if (digit > ('z' - '0')) { break; } digit = cvtIn[digit]; if (digit > 15) { break; } if (result > maxres) { overflow = 1; } result = (result << 4); if (digit > (ULONG_MAX - result)) { overflow = 1; } result += digit; anyDigits = 1; } } else if ( base >= 2 && base <= 36 ) { unsigned long maxres = ULONG_MAX / base; for ( ; ; p += 1) { digit = *p - '0'; if (digit > ('z' - '0')) { break; } digit = cvtIn[digit]; if (digit >= ( (unsigned) base )) { break; } if (result > maxres) { overflow = 1; } result *= base; if (digit > (ULONG_MAX - result)) { overflow = 1; } result += digit; anyDigits = 1; } } /* * See if there were any digits at all. */ if (!anyDigits) { p = string; } if (endPtr != 0) { /* unsafe, but required by the strtoul prototype */ *endPtr = (char *) p; } if (overflow) { errno = ERANGE; return ULONG_MAX; } if (negative) { return -result; } return result; } tcl8.4.20/compat/tmpnam.c0000644003604700454610000000172511737050674013647 0ustar dgp771div/* * Copyright (c) 1988 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and that due credit is given * to the University of California at Berkeley. The name of the University * may not be used to endorse or promote products derived from this * software without specific written prior permission. This software * is provided ``as is'' without express or implied warranty. */ #include #include #include #include /* * Use /tmp instead of /usr/tmp, because L_tmpname is only 14 chars * on some machines (like NeXT machines) and /usr/tmp will cause * buffer overflows. */ #ifdef P_tmpdir # undef P_tmpdir #endif #define P_tmpdir "/tmp" char * tmpnam(s) char *s; { static char name[50]; char *mktemp(); if (!s) s = name; (void)sprintf(s, "%s/XXXXXX", P_tmpdir); return(mktemp(s)); } tcl8.4.20/compat/fixstrtod.c0000644003604700454610000000150111737050674014371 0ustar dgp771div/* * fixstrtod.c -- * * Source code for the "fixstrtod" procedure. This procedure is * used in place of strtod under Solaris 2.4, in order to fix * a bug where the "end" pointer gets set incorrectly. * * Copyright (c) 1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include #undef strtod /* * Declare strtod explicitly rather than including stdlib.h, since in * somes systems (e.g. SunOS 4.1.4) stdlib.h doesn't declare strtod. */ extern double strtod(); double fixstrtod(string, endPtr) char *string; char **endPtr; { double d; d = strtod(string, endPtr); if ((endPtr != NULL) && (*endPtr != string) && ((*endPtr)[-1] == 0)) { *endPtr -= 1; } return d; } tcl8.4.20/compat/tclErrno.h0000644003604700454610000001065111737050674014146 0ustar dgp771div/* * tclErrno.h -- * * This header file contains the various POSIX errno definitions that * are used by Tcl. This file is derived from the spec POSIX 2.4 and * previous implementations for Berkeley UNIX. * * Copyright (c) 1982, 1986, 1989 Regents of the University of California. * Copyright (c) 1996 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ extern int errno; /* global error number */ #define EPERM 1 /* Operation not permitted */ #define ENOENT 2 /* No such file or directory */ #define ESRCH 3 /* No such process */ #define EINTR 4 /* Interrupted system call */ #define EIO 5 /* Input/output error */ #define ENXIO 6 /* Device not configured */ #define E2BIG 7 /* Argument list too long */ #define ENOEXEC 8 /* Exec format error */ #define EBADF 9 /* Bad file descriptor */ #define ECHILD 10 /* No child processes */ #define EDEADLK 11 /* Resource deadlock avoided */ /* 11 was EAGAIN */ #define ENOMEM 12 /* Cannot allocate memory */ #define EACCES 13 /* Permission denied */ #define EFAULT 14 /* Bad address */ #define ENOTBLK 15 /* Block device required */ #define EBUSY 16 /* Device busy */ #define EEXIST 17 /* File exists */ #define EXDEV 18 /* Cross-device link */ #define ENODEV 19 /* Operation not supported by device */ #define ENOTDIR 20 /* Not a directory */ #define EISDIR 21 /* Is a directory */ #define EINVAL 22 /* Invalid argument */ #define ENFILE 23 /* Too many open files in system */ #define EMFILE 24 /* Too many open files */ #define ENOTTY 25 /* Inappropriate ioctl for device */ #define ETXTBSY 26 /* Text file busy */ #define EFBIG 27 /* File too large */ #define ENOSPC 28 /* No space left on device */ #define ESPIPE 29 /* Illegal seek */ #define EROFS 30 /* Read-only file system */ #define EMLINK 31 /* Too many links */ #define EPIPE 32 /* Broken pipe */ #define EDOM 33 /* Numerical argument out of domain */ #define ERANGE 34 /* Result too large */ #define EAGAIN 35 /* Resource temporarily unavailable */ #define EWOULDBLOCK EAGAIN /* Operation would block */ #define EINPROGRESS 36 /* Operation now in progress */ #define EALREADY 37 /* Operation already in progress */ #define ENOTSOCK 38 /* Socket operation on non-socket */ #define EDESTADDRREQ 39 /* Destination address required */ #define EMSGSIZE 40 /* Message too long */ #define EPROTOTYPE 41 /* Protocol wrong type for socket */ #define ENOPROTOOPT 42 /* Protocol not available */ #define EPROTONOSUPPORT 43 /* Protocol not supported */ #define ESOCKTNOSUPPORT 44 /* Socket type not supported */ #define EOPNOTSUPP 45 /* Operation not supported on socket */ #define EPFNOSUPPORT 46 /* Protocol family not supported */ #define EAFNOSUPPORT 47 /* Address family not supported by protocol family */ #define EADDRINUSE 48 /* Address already in use */ #define EADDRNOTAVAIL 49 /* Can't assign requested address */ #define ENETDOWN 50 /* Network is down */ #define ENETUNREACH 51 /* Network is unreachable */ #define ENETRESET 52 /* Network dropped connection on reset */ #define ECONNABORTED 53 /* Software caused connection abort */ #define ECONNRESET 54 /* Connection reset by peer */ #define ENOBUFS 55 /* No buffer space available */ #define EISCONN 56 /* Socket is already connected */ #define ENOTCONN 57 /* Socket is not connected */ #define ESHUTDOWN 58 /* Can't send after socket shutdown */ #define ETOOMANYREFS 59 /* Too many references: can't splice */ #define ETIMEDOUT 60 /* Connection timed out */ #define ECONNREFUSED 61 /* Connection refused */ #define ELOOP 62 /* Too many levels of symbolic links */ #define ENAMETOOLONG 63 /* File name too long */ #define EHOSTDOWN 64 /* Host is down */ #define EHOSTUNREACH 65 /* No route to host */ #define ENOTEMPTY 66 /* Directory not empty */ #define EPROCLIM 67 /* Too many processes */ #define EUSERS 68 /* Too many users */ #define EDQUOT 69 /* Disc quota exceeded */ #define ESTALE 70 /* Stale NFS file handle */ #define EREMOTE 71 /* Too many levels of remote in path */ #define EBADRPC 72 /* RPC struct is bad */ #define ERPCMISMATCH 73 /* RPC version wrong */ #define EPROGUNAVAIL 74 /* RPC prog. not avail */ #define EPROGMISMATCH 75 /* Program version wrong */ #define EPROCUNAVAIL 76 /* Bad procedure for program */ #define ENOLCK 77 /* No locks available */ #define ENOSYS 78 /* Function not implemented */ #define EOVERFLOW 79 /* Value too large to be stored in data type */ tcl8.4.20/compat/strtod.c0000644003604700454610000001335111737050674013670 0ustar dgp771div/* * strtod.c -- * * Source code for the "strtod" library procedure. * * Copyright (c) 1988-1993 The Regents of the University of California. * Copyright (c) 1994 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" #include #ifndef TRUE #define TRUE 1 #define FALSE 0 #endif #ifndef NULL #define NULL 0 #endif static int maxExponent = 511; /* Largest possible base 10 exponent. Any * exponent larger than this will already * produce underflow or overflow, so there's * no need to worry about additional digits. */ static double powersOf10[] = { /* Table giving binary powers of 10. Entry */ 10., /* is 10^2^i. Used to convert decimal */ 100., /* exponents into floating-point numbers. */ 1.0e4, 1.0e8, 1.0e16, 1.0e32, 1.0e64, 1.0e128, 1.0e256 }; /* *---------------------------------------------------------------------- * * strtod -- * * This procedure converts a floating-point number from an ASCII * decimal representation to internal double-precision format. * * Results: * The return value is the double-precision floating-point * representation of the characters in string. If endPtr isn't * NULL, then *endPtr is filled in with the address of the * next character after the last one that was part of the * floating-point number. * * Side effects: * None. * *---------------------------------------------------------------------- */ double strtod(string, endPtr) CONST char *string; /* A decimal ASCII floating-point number, * optionally preceded by white space. * Must have form "-I.FE-X", where I is the * integer part of the mantissa, F is the * fractional part of the mantissa, and X * is the exponent. Either of the signs * may be "+", "-", or omitted. Either I * or F may be omitted, or both. The decimal * point isn't necessary unless F is present. * The "E" may actually be an "e". E and X * may both be omitted (but not just one). */ char **endPtr; /* If non-NULL, store terminating character's * address here. */ { int sign, expSign = FALSE; double fraction, dblExp, *d; register CONST char *p; register int c; int exp = 0; /* Exponent read from "EX" field. */ int fracExp = 0; /* Exponent that derives from the fractional * part. Under normal circumstatnces, it is * the negative of the number of digits in F. * However, if I is very long, the last digits * of I get dropped (otherwise a long I with a * large negative exponent could cause an * unnecessary overflow on I alone). In this * case, fracExp is incremented one for each * dropped digit. */ int mantSize; /* Number of digits in mantissa. */ int decPt; /* Number of mantissa digits BEFORE decimal * point. */ CONST char *pExp; /* Temporarily holds location of exponent * in string. */ /* * Strip off leading blanks and check for a sign. */ p = string; while (isspace(UCHAR(*p))) { p += 1; } if (*p == '-') { sign = TRUE; p += 1; } else { if (*p == '+') { p += 1; } sign = FALSE; } /* * Count the number of digits in the mantissa (including the decimal * point), and also locate the decimal point. */ decPt = -1; for (mantSize = 0; ; mantSize += 1) { c = *p; if (!isdigit(c)) { if ((c != '.') || (decPt >= 0)) { break; } decPt = mantSize; } p += 1; } /* * Now suck up the digits in the mantissa. Use two integers to * collect 9 digits each (this is faster than using floating-point). * If the mantissa has more than 18 digits, ignore the extras, since * they can't affect the value anyway. */ pExp = p; p -= mantSize; if (decPt < 0) { decPt = mantSize; } else { mantSize -= 1; /* One of the digits was the point. */ } if (mantSize > 18) { fracExp = decPt - 18; mantSize = 18; } else { fracExp = decPt - mantSize; } if (mantSize == 0) { fraction = 0.0; p = string; goto done; } else { int frac1, frac2; frac1 = 0; for ( ; mantSize > 9; mantSize -= 1) { c = *p; p += 1; if (c == '.') { c = *p; p += 1; } frac1 = 10*frac1 + (c - '0'); } frac2 = 0; for (; mantSize > 0; mantSize -= 1) { c = *p; p += 1; if (c == '.') { c = *p; p += 1; } frac2 = 10*frac2 + (c - '0'); } fraction = (1.0e9 * frac1) + frac2; } /* * Skim off the exponent. */ p = pExp; if ((*p == 'E') || (*p == 'e')) { p += 1; if (*p == '-') { expSign = TRUE; p += 1; } else { if (*p == '+') { p += 1; } expSign = FALSE; } if (!isdigit(UCHAR(*p))) { p = pExp; goto done; } while (isdigit(UCHAR(*p))) { exp = exp * 10 + (*p - '0'); p += 1; } } if (expSign) { exp = fracExp - exp; } else { exp = fracExp + exp; } /* * Generate a floating-point number that represents the exponent. * Do this by processing the exponent one bit at a time to combine * many powers of 2 of 10. Then combine the exponent with the * fraction. */ if (exp < 0) { expSign = TRUE; exp = -exp; } else { expSign = FALSE; } if (exp > maxExponent) { exp = maxExponent; errno = ERANGE; } dblExp = 1.0; for (d = powersOf10; exp != 0; exp >>= 1, d += 1) { if (exp & 01) { dblExp *= *d; } } if (expSign) { fraction /= dblExp; } else { fraction *= dblExp; } done: if (endPtr != NULL) { *endPtr = (char *) p; } if (sign) { return -fraction; } return fraction; } tcl8.4.20/compat/opendir.c0000644003604700454610000000367411737050674014020 0ustar dgp771div/* * opendir.c -- * * This file provides dirent-style directory-reading procedures * for V7 Unix systems that don't have such procedures. The * origin of this code is unclear, but it seems to have come * originally from Larry Wall. */ #include "tclInt.h" #include "tclPort.h" #undef DIRSIZ #define DIRSIZ(dp) \ ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3)) /* * open a directory. */ DIR * opendir(name) char *name; { register DIR *dirp; register int fd; char *myname; myname = ((*name == '\0') ? "." : name); if ((fd = open(myname, 0, 0)) == -1) return NULL; if ((dirp = (DIR *)ckalloc(sizeof(DIR))) == NULL) { close (fd); return NULL; } dirp->dd_fd = fd; dirp->dd_loc = 0; return dirp; } /* * read an old style directory entry and present it as a new one */ #ifndef pyr #define ODIRSIZ 14 struct olddirect { ino_t od_ino; char od_name[ODIRSIZ]; }; #else /* a Pyramid in the ATT universe */ #define ODIRSIZ 248 struct olddirect { long od_ino; short od_fill1, od_fill2; char od_name[ODIRSIZ]; }; #endif /* * get next entry in a directory. */ struct dirent * readdir(dirp) register DIR *dirp; { register struct olddirect *dp; static struct dirent dir; for (;;) { if (dirp->dd_loc == 0) { dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ); if (dirp->dd_size <= 0) return NULL; } if (dirp->dd_loc >= dirp->dd_size) { dirp->dd_loc = 0; continue; } dp = (struct olddirect *)(dirp->dd_buf + dirp->dd_loc); dirp->dd_loc += sizeof(struct olddirect); if (dp->od_ino == 0) continue; dir.d_ino = dp->od_ino; strncpy(dir.d_name, dp->od_name, ODIRSIZ); dir.d_name[ODIRSIZ] = '\0'; /* insure null termination */ dir.d_namlen = strlen(dir.d_name); dir.d_reclen = DIRSIZ(&dir); return (&dir); } } /* * close a directory. */ void closedir(dirp) register DIR *dirp; { close(dirp->dd_fd); dirp->dd_fd = -1; dirp->dd_loc = 0; ckfree((char *) dirp); } tcl8.4.20/compat/dlfcn.h0000644003604700454610000000326411737050674013446 0ustar dgp771div/* * dlfcn.h -- * * This file provides a replacement for the header file "dlfcn.h" * on systems where dlfcn.h is missing. It's primary use is for * AIX, where Tcl emulates the dl library. * * This file is subject to the following copyright notice, which is * different from the notice used elsewhere in Tcl but rougly * equivalent in meaning. * * Copyright (c) 1992,1993,1995,1996, Jens-Uwe Mager, Helios Software GmbH * Not derived from licensed software. * * Permission is granted to freely use, copy, modify, and redistribute * this software, provided that the author is not construed to be liable * for any results of using the software, alterations are clearly marked * as such, and this notice is not modified. */ /* * @(#)dlfcn.h 1.4 revision of 95/04/25 09:36:52 * This is an unpublished work copyright (c) 1992 HELIOS Software GmbH * 30159 Hannover, Germany */ #ifndef __dlfcn_h__ #define __dlfcn_h__ #ifndef _TCL #include #endif #ifdef __cplusplus extern "C" { #endif /* * Mode flags for the dlopen routine. */ #define RTLD_LAZY 1 /* lazy function call binding */ #define RTLD_NOW 2 /* immediate function call binding */ #define RTLD_GLOBAL 0x100 /* allow symbols to be global */ /* * To be able to intialize, a library may provide a dl_info structure * that contains functions to be called to initialize and terminate. */ struct dl_info { void (*init) _ANSI_ARGS_((void)); void (*fini) _ANSI_ARGS_((void)); }; VOID *dlopen _ANSI_ARGS_((const char *path, int mode)); VOID *dlsym _ANSI_ARGS_((void *handle, const char *symbol)); char *dlerror _ANSI_ARGS_((void)); int dlclose _ANSI_ARGS_((void *handle)); #ifdef __cplusplus } #endif #endif /* __dlfcn_h__ */ tcl8.4.20/compat/memcmp.c0000644003604700454610000000264711737050674013635 0ustar dgp771div/* * memcmp.c -- * * Source code for the "memcmp" library routine. * * Copyright (c) 1998 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tcl.h" #include "tclPort.h" /* * Here is the prototype just in case it is not included * in tclPort.h. */ int memcmp _ANSI_ARGS_((CONST VOID *s1, CONST VOID *s2, size_t n)); /* *---------------------------------------------------------------------- * * memcmp -- * * Compares two bytes sequences. * * Results: * compares its arguments, looking at the first n * bytes (each interpreted as an unsigned char), and returns * an integer less than, equal to, or greater than 0, accord- * ing as s1 is less than, equal to, or * greater than s2 when taken to be unsigned 8 bit numbers. * * Side effects: * None. * *---------------------------------------------------------------------- */ int memcmp(s1, s2, n) CONST VOID *s1; /* First string. */ CONST VOID *s2; /* Second string. */ size_t n; /* Length to compare. */ { CONST unsigned char *ptr1 = (CONST unsigned char *) s1; CONST unsigned char *ptr2 = (CONST unsigned char *) s2; for ( ; n-- ; ptr1++, ptr2++) { unsigned char u1 = *ptr1, u2 = *ptr2; if ( u1 != u2) { return (u1-u2); } } return 0; } tcl8.4.20/compat/gettod.c0000644003604700454610000000110211737050674013626 0ustar dgp771div/* * gettod.c -- * * This file provides the gettimeofday function on systems * that only have the System V ftime function. * * Copyright (c) 1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tcl.h" #include "tclPort.h" #include #undef timezone int gettimeofday(tp, tz) struct timeval *tp; struct timezone *tz; { struct timeb t; ftime(&t); tp->tv_sec = t.time; tp->tv_usec = t. millitm * 1000; return 0; } tcl8.4.20/compat/dirent2.h0000644003604700454610000000250611737050674013725 0ustar dgp771div/* * dirent.h -- * * Declarations of a library of directory-reading procedures * in the POSIX style ("struct dirent"). * * Copyright (c) 1991 The Regents of the University of California. * Copyright (c) 1994 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef _DIRENT #define _DIRENT #ifndef _TCL #include #endif /* * Dirent structure, which holds information about a single * directory entry. */ #define MAXNAMLEN 255 #define DIRBLKSIZ 512 struct dirent { long d_ino; /* Inode number of entry */ short d_reclen; /* Length of this record */ short d_namlen; /* Length of string in d_name */ char d_name[MAXNAMLEN + 1]; /* Name must be no longer than this */ }; /* * State that keeps track of the reading of a directory (clients * should never look inside this structure; the fields should * only be accessed by the library procedures). */ typedef struct _dirdesc { int dd_fd; long dd_loc; long dd_size; char dd_buf[DIRBLKSIZ]; } DIR; /* * Procedures defined for reading directories: */ extern void closedir _ANSI_ARGS_((DIR *dirp)); extern DIR * opendir _ANSI_ARGS_((char *name)); extern struct dirent * readdir _ANSI_ARGS_((DIR *dirp)); #endif /* _DIRENT */ tcl8.4.20/compat/strtoll.c0000644003604700454610000000502111737050674014047 0ustar dgp771div/* * strtoll.c -- * * Source code for the "strtoll" library procedure. * * Copyright (c) 1988 The Regents of the University of California. * Copyright (c) 1994 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tcl.h" #include "tclPort.h" #include #define TCL_WIDEINT_MAX (((Tcl_WideUInt)Tcl_LongAsWide(-1))>>1) /* *---------------------------------------------------------------------- * * strtoll -- * * Convert an ASCII string into an integer. * * Results: * The return value is the integer equivalent of string. If endPtr * is non-NULL, then *endPtr is filled in with the character * after the last one that was part of the integer. If string * doesn't contain a valid integer value, then zero is returned * and *endPtr is set to string. * * Side effects: * None. * *---------------------------------------------------------------------- */ #if TCL_WIDE_INT_IS_LONG long long #else Tcl_WideInt #endif strtoll(string, endPtr, base) CONST char *string; /* String of ASCII digits, possibly * preceded by white space. For bases * greater than 10, either lower- or * upper-case digits may be used. */ char **endPtr; /* Where to store address of terminating * character, or NULL. */ int base; /* Base for conversion. Must be less * than 37. If 0, then the base is chosen * from the leading characters of string: * "0x" means hex, "0" means octal, anything * else means decimal. */ { register CONST char *p; Tcl_WideInt result = Tcl_LongAsWide(0); Tcl_WideUInt uwResult; /* * Skip any leading blanks. */ p = string; while (isspace(UCHAR(*p))) { p += 1; } /* * Check for a sign. */ errno = 0; if (*p == '-') { p += 1; uwResult = strtoull(p, endPtr, base); if (errno != ERANGE) { if (uwResult > TCL_WIDEINT_MAX+1) { errno = ERANGE; return Tcl_LongAsWide(-1); } else if (uwResult > TCL_WIDEINT_MAX) { return ~((Tcl_WideInt)TCL_WIDEINT_MAX); } else { result = -((Tcl_WideInt) uwResult); } } } else { if (*p == '+') { p += 1; } uwResult = strtoull(p, endPtr, base); if (errno != ERANGE) { if (uwResult > TCL_WIDEINT_MAX) { errno = ERANGE; return Tcl_LongAsWide(-1); } else { result = uwResult; } } } if ((result == 0) && (endPtr != 0) && (*endPtr == p)) { *endPtr = (char *) string; } return result; } tcl8.4.20/compat/license.terms0000644003604700454610000000432111737050674014700 0ustar dgp771divThis software is copyrighted by the Regents of the University of California, Sun Microsystems, Inc., Scriptics Corporation, ActiveState Corporation and other parties. The following terms apply to all files associated with the software unless explicitly disclaimed in individual files. The authors hereby grant permission to use, copy, modify, distribute, and license this software and its documentation for any purpose, provided that existing copyright notices are retained in all copies and that this notice is included verbatim in any distributions. No written agreement, license, or royalty fee is required for any of the authorized uses. Modifications to this software may be copyrighted by their authors and need not follow the licensing terms described here, provided that the new terms are clearly indicated on the first page of each file where they apply. IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. GOVERNMENT USE: If you are acquiring this software on behalf of the U.S. government, the Government shall have only "Restricted Rights" in the software and related documentation as defined in the Federal Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are acquiring the software on behalf of the Department of Defense, the software shall be classified as "Commercial Computer Software" and the Government shall have only "Restricted Rights" as defined in Clause 252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the authors grant the U.S. Government and others acting in its behalf permission to use and distribute the software in accordance with the terms specified in this license. tcl8.4.20/compat/stdlib.h0000644003604700454610000000320211737050674013631 0ustar dgp771div/* * stdlib.h -- * * Declares facilities exported by the "stdlib" portion of * the C library. This file isn't complete in the ANSI-C * sense; it only declares things that are needed by Tcl. * This file is needed even on many systems with their own * stdlib.h (e.g. SunOS) because not all stdlib.h files * declare all the procedures needed here (such as strtod). * * Copyright (c) 1991 The Regents of the University of California. * Copyright (c) 1994-1998 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef _STDLIB #define _STDLIB #include extern void abort _ANSI_ARGS_((void)); extern double atof _ANSI_ARGS_((CONST char *string)); extern int atoi _ANSI_ARGS_((CONST char *string)); extern long atol _ANSI_ARGS_((CONST char *string)); extern char * calloc _ANSI_ARGS_((unsigned int numElements, unsigned int size)); extern void exit _ANSI_ARGS_((int status)); extern int free _ANSI_ARGS_((char *blockPtr)); extern char * getenv _ANSI_ARGS_((CONST char *name)); extern char * malloc _ANSI_ARGS_((unsigned int numBytes)); extern void qsort _ANSI_ARGS_((VOID *base, int n, int size, int (*compar)(CONST VOID *element1, CONST VOID *element2))); extern char * realloc _ANSI_ARGS_((char *ptr, unsigned int numBytes)); extern double strtod _ANSI_ARGS_((CONST char *string, char **endPtr)); extern long strtol _ANSI_ARGS_((CONST char *string, char **endPtr, int base)); extern unsigned long strtoul _ANSI_ARGS_((CONST char *string, char **endPtr, int base)); #endif /* _STDLIB */ tcl8.4.20/compat/strstr.c0000644003604700454610000000310211737050674013703 0ustar dgp771div/* * strstr.c -- * * Source code for the "strstr" library routine. * * Copyright (c) 1988-1993 The Regents of the University of California. * Copyright (c) 1994 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include #ifndef NULL #define NULL 0 #endif /* *---------------------------------------------------------------------- * * strstr -- * * Locate the first instance of a substring in a string. * * Results: * If string contains substring, the return value is the * location of the first matching instance of substring * in string. If string doesn't contain substring, the * return value is 0. Matching is done on an exact * character-for-character basis with no wildcards or special * characters. * * Side effects: * None. * *---------------------------------------------------------------------- */ char * strstr(string, substring) register char *string; /* String to search. */ char *substring; /* Substring to try to find in string. */ { register char *a, *b; /* First scan quickly through the two strings looking for a * single-character match. When it's found, then compare the * rest of the substring. */ b = substring; if (*b == 0) { return string; } for ( ; *string != 0; string += 1) { if (*string != *b) { continue; } a = string; while (1) { if (*b == 0) { return string; } if (*a++ != *b++) { break; } } b = substring; } return NULL; } tcl8.4.20/compat/strtoull.c0000644003604700454610000001245111737050674014241 0ustar dgp771div/* * strtoull.c -- * * Source code for the "strtoull" library procedure. * * Copyright (c) 1988 The Regents of the University of California. * Copyright (c) 1994 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tcl.h" #include "tclPort.h" #include /* * The table below is used to convert from ASCII digits to a * numerical equivalent. It maps from '0' through 'z' to integers * (100 for non-digit characters). */ static char cvtIn[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, /* '0' - '9' */ 100, 100, 100, 100, 100, 100, 100, /* punctuation */ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, /* 'A' - 'Z' */ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 100, 100, 100, 100, 100, 100, /* punctuation */ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, /* 'a' - 'z' */ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35}; /* *---------------------------------------------------------------------- * * strtoull -- * * Convert an ASCII string into an integer. * * Results: * The return value is the integer equivalent of string. If endPtr * is non-NULL, then *endPtr is filled in with the character * after the last one that was part of the integer. If string * doesn't contain a valid integer value, then zero is returned * and *endPtr is set to string. * * Side effects: * None. * *---------------------------------------------------------------------- */ #if TCL_WIDE_INT_IS_LONG unsigned long long #else Tcl_WideUInt #endif strtoull(string, endPtr, base) CONST char *string; /* String of ASCII digits, possibly * preceded by white space. For bases * greater than 10, either lower- or * upper-case digits may be used. */ char **endPtr; /* Where to store address of terminating * character, or NULL. */ int base; /* Base for conversion. Must be less * than 37. If 0, then the base is chosen * from the leading characters of string: * "0x" means hex, "0" means octal, anything * else means decimal. */ { register CONST char *p; register Tcl_WideUInt result = 0; register unsigned digit; register Tcl_WideUInt shifted; int anyDigits = 0, negative = 0; /* * Skip any leading blanks. */ p = string; while (isspace(UCHAR(*p))) { /* INTL: locale-dependent */ p += 1; } /* * Check for a sign. */ if (*p == '-') { p += 1; negative = 1; } else { if (*p == '+') { p += 1; } } /* * If no base was provided, pick one from the leading characters * of the string. */ if (base == 0) { if (*p == '0') { p += 1; if (*p == 'x' || *p == 'X') { p += 1; base = 16; } else { /* * Must set anyDigits here, otherwise "0" produces a * "no digits" error. */ anyDigits = 1; base = 8; } } else { base = 10; } } else if (base == 16) { /* * Skip a leading "0x" from hex numbers. */ if ((p[0] == '0') && (p[1] == 'x' || *p == 'X')) { p += 2; } } /* * Sorry this code is so messy, but speed seems important. Do * different things for base 8, 10, 16, and other. */ if (base == 8) { for ( ; ; p += 1) { digit = *p - '0'; if (digit > 7) { break; } shifted = result << 3; if ((shifted >> 3) != result) { goto overflow; } result = shifted + digit; if ( result < shifted ) { goto overflow; } anyDigits = 1; } } else if (base == 10) { for ( ; ; p += 1) { digit = *p - '0'; if (digit > 9) { break; } shifted = 10 * result; if ((shifted / 10) != result) { goto overflow; } result = shifted + digit; if ( result < shifted ) { goto overflow; } anyDigits = 1; } } else if (base == 16) { for ( ; ; p += 1) { digit = *p - '0'; if (digit > ('z' - '0')) { break; } digit = cvtIn[digit]; if (digit > 15) { break; } shifted = result << 4; if ((shifted >> 4) != result) { goto overflow; } result = shifted + digit; if ( result < shifted ) { goto overflow; } anyDigits = 1; } } else if ( base >= 2 && base <= 36 ) { for ( ; ; p += 1) { digit = *p - '0'; if (digit > ('z' - '0')) { break; } digit = cvtIn[digit]; if (digit >= (unsigned) base) { break; } shifted = result * base; if ((shifted/base) != result) { goto overflow; } result = shifted + digit; if ( result < shifted ) { goto overflow; } anyDigits = 1; } } /* * Negate if we found a '-' earlier. */ if (negative) { result = (Tcl_WideUInt)(-((Tcl_WideInt)result)); } /* * See if there were any digits at all. */ if (!anyDigits) { p = string; } if (endPtr != 0) { *endPtr = (char *) p; } return result; /* * On overflow generate the right output */ overflow: errno = ERANGE; if (endPtr != 0) { for ( ; ; p += 1) { digit = *p - '0'; if (digit > ('z' - '0')) { break; } digit = cvtIn[digit]; if (digit >= (unsigned) base) { break; } } *endPtr = (char *) p; } return (Tcl_WideUInt)Tcl_LongAsWide(-1); } tcl8.4.20/compat/unistd.h0000644003604700454610000000624711737050674013672 0ustar dgp771div/* * unistd.h -- * * Macros, CONSTants and prototypes for Posix conformance. * * Copyright 1989 Regents of the University of California * Permission to use, copy, modify, and distribute this * software and its documentation for any purpose and without * fee is hereby granted, provided that the above copyright * notice appear in all copies. The University of California * makes no representations about the suitability of this * software for any purpose. It is provided "as is" without * express or implied warranty. */ #ifndef _UNISTD #define _UNISTD #include #ifndef _TCL # include "tcl.h" #endif #ifndef NULL #define NULL 0 #endif /* * Strict POSIX stuff goes here. Extensions go down below, in the * ifndef _POSIX_SOURCE section. */ extern void _exit _ANSI_ARGS_((int status)); extern int access _ANSI_ARGS_((CONST char *path, int mode)); extern int chdir _ANSI_ARGS_((CONST char *path)); extern int chown _ANSI_ARGS_((CONST char *path, uid_t owner, gid_t group)); extern int close _ANSI_ARGS_((int fd)); extern int dup _ANSI_ARGS_((int oldfd)); extern int dup2 _ANSI_ARGS_((int oldfd, int newfd)); extern int execl _ANSI_ARGS_((CONST char *path, ...)); extern int execle _ANSI_ARGS_((CONST char *path, ...)); extern int execlp _ANSI_ARGS_((CONST char *file, ...)); extern int execv _ANSI_ARGS_((CONST char *path, char **argv)); extern int execve _ANSI_ARGS_((CONST char *path, char **argv, char **envp)); extern int execvp _ANSI_ARGS_((CONST char *file, char **argv)); extern pid_t fork _ANSI_ARGS_((void)); extern char *getcwd _ANSI_ARGS_((char *buf, size_t size)); extern gid_t getegid _ANSI_ARGS_((void)); extern uid_t geteuid _ANSI_ARGS_((void)); extern gid_t getgid _ANSI_ARGS_((void)); extern int getgroups _ANSI_ARGS_((int bufSize, int *buffer)); extern pid_t getpid _ANSI_ARGS_((void)); extern uid_t getuid _ANSI_ARGS_((void)); extern int isatty _ANSI_ARGS_((int fd)); extern long lseek _ANSI_ARGS_((int fd, long offset, int whence)); extern int pipe _ANSI_ARGS_((int *fildes)); extern int read _ANSI_ARGS_((int fd, char *buf, size_t size)); extern int setgid _ANSI_ARGS_((gid_t group)); extern int setuid _ANSI_ARGS_((uid_t user)); extern unsigned sleep _ANSI_ARGS_ ((unsigned seconds)); extern char *ttyname _ANSI_ARGS_((int fd)); extern int unlink _ANSI_ARGS_((CONST char *path)); extern int write _ANSI_ARGS_((int fd, CONST char *buf, size_t size)); #ifndef _POSIX_SOURCE extern char *crypt _ANSI_ARGS_((CONST char *, CONST char *)); extern int fchown _ANSI_ARGS_((int fd, uid_t owner, gid_t group)); extern int flock _ANSI_ARGS_((int fd, int operation)); extern int ftruncate _ANSI_ARGS_((int fd, unsigned long length)); extern int ioctl _ANSI_ARGS_((int fd, int request, ...)); extern int readlink _ANSI_ARGS_((CONST char *path, char *buf, int bufsize)); extern int setegid _ANSI_ARGS_((gid_t group)); extern int seteuid _ANSI_ARGS_((uid_t user)); extern int setreuid _ANSI_ARGS_((int ruid, int euid)); extern int symlink _ANSI_ARGS_((CONST char *, CONST char *)); extern int ttyslot _ANSI_ARGS_((void)); extern int truncate _ANSI_ARGS_((CONST char *path, unsigned long length)); extern int vfork _ANSI_ARGS_((void)); #endif /* _POSIX_SOURCE */ #endif /* _UNISTD */ tcl8.4.20/compat/limits.h0000644003604700454610000000126011737050674013653 0ustar dgp771div/* * limits.h -- * * This is a dummy header file to #include in Tcl when there * is no limits.h in /usr/include. There are only a few * definitions here; also see tclPort.h, which already * #defines some of the things here if they're not arleady * defined. * * Copyright (c) 1991 The Regents of the University of California. * Copyright (c) 1994 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #define LONG_MIN 0x80000000 #define LONG_MAX 0x7fffffff #define INT_MIN 0x80000000 #define INT_MAX 0x7fffffff #define SHRT_MIN 0x8000 #define SHRT_MAX 0x7fff tcl8.4.20/compat/waitpid.c0000644003604700454610000001107211737050674014010 0ustar dgp771div/* * waitpid.c -- * * This procedure emulates the POSIX waitpid kernel call on * BSD systems that don't have waitpid but do have wait3. * This code is based on a prototype version written by * Mark Diekhans and Karl Lehenbauer. * * Copyright (c) 1993 The Regents of the University of California. * Copyright (c) 1994 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" #ifndef pid_t #define pid_t int #endif /* * A linked list of the following structures is used to keep track * of processes for which we received notification from the kernel, * but the application hasn't waited for them yet (this can happen * because wait may not return the process we really want). We * save the information here until the application finally does * wait for the process. */ typedef struct WaitInfo { pid_t pid; /* Pid of process that exited. */ WAIT_STATUS_TYPE status; /* Status returned when child exited * or suspended. */ struct WaitInfo *nextPtr; /* Next in list of exited processes. */ } WaitInfo; static WaitInfo *deadList = NULL; /* First in list of all dead * processes. */ /* *---------------------------------------------------------------------- * * waitpid -- * * This procedure emulates the functionality of the POSIX * waitpid kernel call, using the BSD wait3 kernel call. * Note: it doesn't emulate absolutely all of the waitpid * functionality, in that it doesn't support pid's of 0 * or < -1. * * Results: * -1 is returned if there is an error in the wait kernel call. * Otherwise the pid of an exited or suspended process is * returned and *statusPtr is set to the status value of the * process. * * Side effects: * None. * *---------------------------------------------------------------------- */ #ifdef waitpid # undef waitpid #endif pid_t waitpid(pid, statusPtr, options) pid_t pid; /* The pid to wait on. Must be -1 or * greater than zero. */ int *statusPtr; /* Where to store wait status for the * process. */ int options; /* OR'ed combination of WNOHANG and * WUNTRACED. */ { register WaitInfo *waitPtr, *prevPtr; pid_t result; WAIT_STATUS_TYPE status; if ((pid < -1) || (pid == 0)) { errno = EINVAL; return -1; } /* * See if there's a suitable process that has already stopped or * exited. If so, remove it from the list of exited processes and * return its information. */ for (waitPtr = deadList, prevPtr = NULL; waitPtr != NULL; prevPtr = waitPtr, waitPtr = waitPtr->nextPtr) { if ((pid != waitPtr->pid) && (pid != -1)) { continue; } if (!(options & WUNTRACED) && (WIFSTOPPED(waitPtr->status))) { continue; } result = waitPtr->pid; *statusPtr = *((int *) &waitPtr->status); if (prevPtr == NULL) { deadList = waitPtr->nextPtr; } else { prevPtr->nextPtr = waitPtr->nextPtr; } ckfree((char *) waitPtr); return result; } /* * Wait for any process to stop or exit. If it's an acceptable one * then return it to the caller; otherwise store information about it * in the list of exited processes and try again. On systems that * have only wait but not wait3, there are several situations we can't * handle, but we do the best we can (e.g. can still handle some * combinations of options by invoking wait instead of wait3). */ while (1) { #if NO_WAIT3 if (options & WNOHANG) { return 0; } if (options != 0) { errno = EINVAL; return -1; } result = wait(&status); #else result = wait3(&status, options, 0); #endif if ((result == -1) && (errno == EINTR)) { continue; } if (result <= 0) { return result; } if ((pid != result) && (pid != -1)) { goto saveInfo; } if (!(options & WUNTRACED) && (WIFSTOPPED(status))) { goto saveInfo; } *statusPtr = *((int *) &status); return result; /* * Can't return this info to caller. Save it in the list of * stopped or exited processes. Tricky point: first check for * an existing entry for the process and overwrite it if it * exists (e.g. a previously stopped process might now be dead). */ saveInfo: for (waitPtr = deadList; waitPtr != NULL; waitPtr = waitPtr->nextPtr) { if (waitPtr->pid == result) { waitPtr->status = status; goto waitAgain; } } waitPtr = (WaitInfo *) ckalloc(sizeof(WaitInfo)); waitPtr->pid = result; waitPtr->status = status; waitPtr->nextPtr = deadList; deadList = waitPtr; waitAgain: continue; } } tcl8.4.20/compat/strncasecmp.c0000644003604700454610000001015711737050674014674 0ustar dgp771div/* * strncasecmp.c -- * * Source code for the "strncasecmp" library routine. * * Copyright (c) 1988-1993 The Regents of the University of California. * Copyright (c) 1995-1996 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclPort.h" /* * This array is designed for mapping upper and lower case letter * together for a case independent comparison. The mappings are * based upon ASCII character sequences. */ static unsigned char charmap[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xe1, 0xe2, 0xe3, 0xe4, 0xc5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, }; /* * Here are the prototypes just in case they are not included * in tclPort.h. */ int strncasecmp _ANSI_ARGS_((CONST char *s1, CONST char *s2, size_t n)); int strcasecmp _ANSI_ARGS_((CONST char *s1, CONST char *s2)); /* *---------------------------------------------------------------------- * * strcasecmp -- * * Compares two strings, ignoring case differences. * * Results: * Compares two null-terminated strings s1 and s2, returning -1, 0, * or 1 if s1 is lexicographically less than, equal to, or greater * than s2. * * Side effects: * None. * *---------------------------------------------------------------------- */ int strcasecmp(s1, s2) CONST char *s1; /* First string. */ CONST char *s2; /* Second string. */ { unsigned char u1, u2; for ( ; ; s1++, s2++) { u1 = (unsigned char) *s1; u2 = (unsigned char) *s2; if ((u1 == '\0') || (charmap[u1] != charmap[u2])) { break; } } return charmap[u1] - charmap[u2]; } /* *---------------------------------------------------------------------- * * strncasecmp -- * * Compares two strings, ignoring case differences. * * Results: * Compares up to length chars of s1 and s2, returning -1, 0, or 1 * if s1 is lexicographically less than, equal to, or greater * than s2 over those characters. * * Side effects: * None. * *---------------------------------------------------------------------- */ int strncasecmp(s1, s2, length) CONST char *s1; /* First string. */ CONST char *s2; /* Second string. */ size_t length; /* Maximum number of characters to compare * (stop earlier if the end of either string * is reached). */ { unsigned char u1, u2; for (; length != 0; length--, s1++, s2++) { u1 = (unsigned char) *s1; u2 = (unsigned char) *s2; if (charmap[u1] != charmap[u2]) { return charmap[u1] - charmap[u2]; } if (u1 == '\0') { return 0; } } return 0; } tcl8.4.20/compat/dirent.h0000644003604700454610000000076611737050674013651 0ustar dgp771div/* * dirent.h -- * * This file is a replacement for in systems that * support the old BSD-style with a "struct direct". * * Copyright (c) 1991 The Regents of the University of California. * Copyright (c) 1994 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef _DIRENT #define _DIRENT #include #define dirent direct #endif /* _DIRENT */ tcl8.4.20/compat/README0000644003604700454610000000057611737050674013072 0ustar dgp771divThis directory contains various header and code files that are used make Tcl compatible with various releases of UNIX and UNIX-like systems. Typically, files from this directory are used to compile Tcl when a system doesn't contain the corresponding files or when they are known to be incorrect. When the whole world becomes POSIX- compliant this directory should be unnecessary. tcl8.4.20/compat/strtol.c0000644003604700454610000000366311737050674013705 0ustar dgp771div/* * strtol.c -- * * Source code for the "strtol" library procedure. * * Copyright (c) 1988 The Regents of the University of California. * Copyright (c) 1994 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include #include "tclInt.h" #include "tclPort.h" /* *---------------------------------------------------------------------- * * strtol -- * * Convert an ASCII string into an integer. * * Results: * The return value is the integer equivalent of string. If endPtr * is non-NULL, then *endPtr is filled in with the character * after the last one that was part of the integer. If string * doesn't contain a valid integer value, then zero is returned * and *endPtr is set to string. * * Side effects: * None. * *---------------------------------------------------------------------- */ long int strtol(string, endPtr, base) CONST char *string; /* String of ASCII digits, possibly * preceded by white space. For bases * greater than 10, either lower- or * upper-case digits may be used. */ char **endPtr; /* Where to store address of terminating * character, or NULL. */ int base; /* Base for conversion. Must be less * than 37. If 0, then the base is chosen * from the leading characters of string: * "0x" means hex, "0" means octal, anything * else means decimal. */ { register CONST char *p; long result; /* * Skip any leading blanks. */ p = string; while (isspace(UCHAR(*p))) { p += 1; } /* * Check for a sign. */ if (*p == '-') { p += 1; result = -(strtoul(p, endPtr, base)); } else { if (*p == '+') { p += 1; } result = strtoul(p, endPtr, base); } if ((result == 0) && (endPtr != 0) && (*endPtr == p)) { *endPtr = (char *) string; } return result; } tcl8.4.20/compat/float.h0000644003604700454610000000100611737050674013455 0ustar dgp771div/* * float.h -- * * This is a dummy header file to #include in Tcl when there * is no float.h in /usr/include. Right now this file is empty: * Tcl contains #ifdefs to deal with the lack of definitions; * all it needs is for the #include statement to work. * * Copyright (c) 1993 The Regents of the University of California. * Copyright (c) 1994 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ tcl8.4.20/compat/strftime.c0000644003604700454610000003004212151137515014171 0ustar dgp771div/* * strftime.c -- * * This file contains a modified version of the BSD 4.4 strftime * function. * * This file is a modified version of the strftime.c file from the BSD 4.4 * source. See the copyright notice below for details on redistribution * restrictions. The "license.terms" file does not apply to this file. * * Changes 2002 Copyright (c) 2002 ActiveState Corporation. */ /* * Copyright (c) 1989 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if defined(_WIN32) && !defined(_WIN64) # define _USE_32BIT_TIME_T #endif #include #include #include #include "tclInt.h" #include "tclPort.h" #define TM_YEAR_BASE 1900 #define IsLeapYear(x) ((x % 4 == 0) && (x % 100 != 0 || x % 400 == 0)) typedef struct { const char *abday[7]; const char *day[7]; const char *abmon[12]; const char *mon[12]; const char *am_pm[2]; const char *d_t_fmt; const char *d_fmt; const char *t_fmt; const char *t_fmt_ampm; } _TimeLocale; /* * This is the C locale default. On Windows, if we wanted to make this * localized, we would use GetLocaleInfo to get the correct values. * It may be acceptable to do localization of month/day names, as the * numerical values would be considered the locale-independent versions. */ static const _TimeLocale _DefaultTimeLocale = { { "Sun","Mon","Tue","Wed","Thu","Fri","Sat", }, { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }, { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }, { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }, { "AM", "PM" }, "%a %b %d %H:%M:%S %Y", "%m/%d/%y", "%H:%M:%S", "%I:%M:%S %p" }; static const _TimeLocale *_CurrentTimeLocale = &_DefaultTimeLocale; static int isGMT; static size_t gsize; static char *pt; static int _add _ANSI_ARGS_((const char* str)); static int _conv _ANSI_ARGS_((int n, int digits, int pad)); static int _secs _ANSI_ARGS_((const struct tm *t)); static size_t _fmt _ANSI_ARGS_((const char *format, const struct tm *t)); static int ISO8601Week _ANSI_ARGS_((CONST struct tm* t, int *year )); size_t TclpStrftime(s, maxsize, format, t, useGMT) char *s; size_t maxsize; const char *format; const struct tm *t; int useGMT; { if (format[0] == '%' && format[1] == 'Q') { /* Format as a stardate */ sprintf(s, "Stardate %2d%03d.%01d", (((t->tm_year + TM_YEAR_BASE) + 377) - 2323), (((t->tm_yday + 1) * 1000) / (365 + IsLeapYear((t->tm_year + TM_YEAR_BASE)))), (((t->tm_hour * 60) + t->tm_min)/144)); return(strlen(s)); } isGMT = useGMT; /* * We may be able to skip this for useGMT, but it should be harmless. * -- hobbs */ tzset(); pt = s; if ((gsize = maxsize) < 1) return(0); if (_fmt(format, t)) { *pt = '\0'; return(maxsize - gsize); } return(0); } #define SUN_WEEK(t) (((t)->tm_yday + 7 - \ ((t)->tm_wday)) / 7) #define MON_WEEK(t) (((t)->tm_yday + 7 - \ ((t)->tm_wday ? (t)->tm_wday - 1 : 6)) / 7) static size_t _fmt(format, t) const char *format; const struct tm *t; { #ifdef WIN32 #define BUF_SIZ 256 TCHAR buf[BUF_SIZ]; SYSTEMTIME syst = { t->tm_year + 1900, t->tm_mon + 1, t->tm_wday, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, 0, }; #endif for (; *format; ++format) { if (*format == '%') { ++format; if (*format == 'E') { /* Alternate Era */ ++format; } else if (*format == 'O') { /* Alternate numeric symbols */ ++format; } switch(*format) { case '\0': --format; break; case 'A': if (t->tm_wday < 0 || t->tm_wday > 6) return(0); if (!_add(_CurrentTimeLocale->day[t->tm_wday])) return(0); continue; case 'a': if (t->tm_wday < 0 || t->tm_wday > 6) return(0); if (!_add(_CurrentTimeLocale->abday[t->tm_wday])) return(0); continue; case 'B': if (t->tm_mon < 0 || t->tm_mon > 11) return(0); if (!_add(_CurrentTimeLocale->mon[t->tm_mon])) return(0); continue; case 'b': case 'h': if (t->tm_mon < 0 || t->tm_mon > 11) return(0); if (!_add(_CurrentTimeLocale->abmon[t->tm_mon])) return(0); continue; case 'C': if (!_conv((t->tm_year + TM_YEAR_BASE) / 100, 2, '0')) return(0); continue; case 'D': if (!_fmt("%m/%d/%y", t)) return(0); continue; case 'd': if (!_conv(t->tm_mday, 2, '0')) return(0); continue; case 'e': if (!_conv(t->tm_mday, 2, ' ')) return(0); continue; case 'g': { int year; ISO8601Week( t, &year ); if ( !_conv( year%100, 2, '0' ) ) { return( 0 ); } continue; } case 'G': { int year; ISO8601Week( t, &year ); if ( !_conv( year, 4, '0' ) ) { return( 0 ); } continue; } case 'H': if (!_conv(t->tm_hour, 2, '0')) return(0); continue; case 'I': if (!_conv(t->tm_hour % 12 ? t->tm_hour % 12 : 12, 2, '0')) return(0); continue; case 'j': if (!_conv(t->tm_yday + 1, 3, '0')) return(0); continue; case 'k': if (!_conv(t->tm_hour, 2, ' ')) return(0); continue; case 'l': if (!_conv(t->tm_hour % 12 ? t->tm_hour % 12: 12, 2, ' ')) return(0); continue; case 'M': if (!_conv(t->tm_min, 2, '0')) return(0); continue; case 'm': if (!_conv(t->tm_mon + 1, 2, '0')) return(0); continue; case 'n': if (!_add("\n")) return(0); continue; case 'p': if (!_add(_CurrentTimeLocale->am_pm[t->tm_hour >= 12])) return(0); continue; case 'R': if (!_fmt("%H:%M", t)) return(0); continue; case 'r': if (!_fmt(_CurrentTimeLocale->t_fmt_ampm, t)) return(0); continue; case 'S': if (!_conv(t->tm_sec, 2, '0')) return(0); continue; case 's': if (!_secs(t)) return(0); continue; case 'T': if (!_fmt("%H:%M:%S", t)) return(0); continue; case 't': if (!_add("\t")) return(0); continue; case 'U': if (!_conv(SUN_WEEK(t), 2, '0')) return(0); continue; case 'u': if (!_conv(t->tm_wday ? t->tm_wday : 7, 1, '0')) return(0); continue; case 'V': { int week = ISO8601Week( t, NULL ); if (!_conv(week, 2, '0')) return(0); continue; } case 'W': if (!_conv(MON_WEEK(t), 2, '0')) return(0); continue; case 'w': if (!_conv(t->tm_wday, 1, '0')) return(0); continue; #ifdef WIN32 /* * To properly handle the localized time routines on Windows, * we must make use of the special localized calls. */ case 'c': if (!GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE | LOCALE_USE_CP_ACP, &syst, NULL, buf, BUF_SIZ) || !_add(buf) || !_add(" ")) { return(0); } /* * %c is created with LONGDATE + " " + TIME on Windows, * so continue to %X case here. */ case 'X': if (!GetTimeFormat(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP, &syst, NULL, buf, BUF_SIZ) || !_add(buf)) { return(0); } continue; case 'x': if (!GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE | LOCALE_USE_CP_ACP, &syst, NULL, buf, BUF_SIZ) || !_add(buf)) { return(0); } continue; #else case 'c': if (!_fmt(_CurrentTimeLocale->d_t_fmt, t)) return(0); continue; case 'x': if (!_fmt(_CurrentTimeLocale->d_fmt, t)) return(0); continue; case 'X': if (!_fmt(_CurrentTimeLocale->t_fmt, t)) return(0); continue; #endif case 'y': if (!_conv((t->tm_year + TM_YEAR_BASE) % 100, 2, '0')) return(0); continue; case 'Y': if (!_conv((t->tm_year + TM_YEAR_BASE), 4, '0')) return(0); continue; case 'Z': { char *name = (isGMT ? "GMT" : TclpGetTZName(t->tm_isdst)); int wrote; Tcl_UtfToExternal(NULL, NULL, name, -1, 0, NULL, pt, gsize, NULL, &wrote, NULL); pt += wrote; gsize -= wrote; continue; } case '%': /* * X311J/88-090 (4.12.3.5): if conversion char is * undefined, behavior is undefined. Print out the * character itself as printf(3) does. */ default: break; } } if (!gsize--) return(0); *pt++ = *format; } return(gsize); } static int _secs(t) const struct tm *t; { static char buf[15]; register time_t s; register char *p; struct tm tmp; /* Make a copy, mktime(3) modifies the tm struct. */ tmp = *t; s = mktime(&tmp); for (p = buf + sizeof(buf) - 2; s > 0 && p > buf; s /= 10) *p-- = (char)(s % 10 + '0'); return(_add(++p)); } static int _conv(n, digits, pad) int n, digits; int pad; { static char buf[10]; register char *p; p = buf + sizeof( buf ) - 1; *p-- = '\0'; if ( n == 0 ) { *p-- = '0'; --digits; } else { for (; n > 0 && p > buf; n /= 10, --digits) *p-- = (char)(n % 10 + '0'); } while (p > buf && digits-- > 0) *p-- = (char) pad; return(_add(++p)); } static int _add(str) const char *str; { for (;; ++pt, --gsize) { if (!gsize) return(0); if (!(*pt = *str++)) return(1); } } static int ISO8601Week( t, year ) CONST struct tm* t; int* year; { /* Find the day-of-year of the Thursday in * the week in question. */ int ydayThursday; int week; if ( t->tm_wday == 0 ) { ydayThursday = t->tm_yday - 3; } else { ydayThursday = t->tm_yday - t->tm_wday + 4; } if ( ydayThursday < 0 ) { /* This is the last week of the previous year. */ if ( IsLeapYear(( t->tm_year + TM_YEAR_BASE - 1 )) ) { ydayThursday += 366; } else { ydayThursday += 365; } week = ydayThursday / 7 + 1; if ( year != NULL ) { *year = t->tm_year + 1899; } } else if ( ( IsLeapYear(( t -> tm_year + TM_YEAR_BASE )) && ydayThursday >= 366 ) || ( !IsLeapYear(( t -> tm_year + TM_YEAR_BASE )) && ydayThursday >= 365 ) ) { /* This is week 1 of the following year */ week = 1; if ( year != NULL ) { *year = t->tm_year + 1901; } } else { week = ydayThursday / 7 + 1; if ( year != NULL ) { *year = t->tm_year + 1900; } } return week; } tcl8.4.20/compat/string.h0000644003604700454610000000477412052456743013673 0ustar dgp771div/* * string.h -- * * Declarations of ANSI C library procedures for string handling. * * Copyright (c) 1991-1993 The Regents of the University of California. * Copyright (c) 1994-1996 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef _STRING #define _STRING #include /* * The following #include is needed to define size_t. (This used to * include sys/stdtypes.h but that doesn't exist on older versions * of SunOS, e.g. 4.0.2, so I'm trying sys/types.h now.... hopefully * it exists everywhere) */ #include #ifdef __APPLE__ extern VOID * memchr _ANSI_ARGS_((CONST VOID *s, int c, size_t n)); #else extern char * memchr _ANSI_ARGS_((CONST VOID *s, int c, size_t n)); #endif extern int memcmp _ANSI_ARGS_((CONST VOID *s1, CONST VOID *s2, size_t n)); extern char * memcpy _ANSI_ARGS_((VOID *t, CONST VOID *f, size_t n)); #ifdef NO_MEMMOVE #define memmove(d, s, n) bcopy ((s), (d), (n)) #else extern char * memmove _ANSI_ARGS_((VOID *t, CONST VOID *f, size_t n)); #endif extern char * memset _ANSI_ARGS_((VOID *s, int c, size_t n)); extern int strcasecmp _ANSI_ARGS_((CONST char *s1, CONST char *s2)); extern char * strcat _ANSI_ARGS_((char *dst, CONST char *src)); extern char * strchr _ANSI_ARGS_((CONST char *string, int c)); extern int strcmp _ANSI_ARGS_((CONST char *s1, CONST char *s2)); extern char * strcpy _ANSI_ARGS_((char *dst, CONST char *src)); extern size_t strcspn _ANSI_ARGS_((CONST char *string, CONST char *chars)); extern char * strdup _ANSI_ARGS_((CONST char *string)); extern char * strerror _ANSI_ARGS_((int error)); extern size_t strlen _ANSI_ARGS_((CONST char *string)); extern int strncasecmp _ANSI_ARGS_((CONST char *s1, CONST char *s2, size_t n)); extern char * strncat _ANSI_ARGS_((char *dst, CONST char *src, size_t numChars)); extern int strncmp _ANSI_ARGS_((CONST char *s1, CONST char *s2, size_t nChars)); extern char * strncpy _ANSI_ARGS_((char *dst, CONST char *src, size_t numChars)); extern char * strpbrk _ANSI_ARGS_((CONST char *string, CONST char *chars)); extern char * strrchr _ANSI_ARGS_((CONST char *string, int c)); extern size_t strspn _ANSI_ARGS_((CONST char *string, CONST char *chars)); extern char * strstr _ANSI_ARGS_((CONST char *string, CONST char *substring)); extern char * strtok _ANSI_ARGS_((char *s, CONST char *delim)); #endif /* _STRING */ tcl8.4.20/tests/0000755003604700454610000000000012153151142012042 5ustar dgp771divtcl8.4.20/tests/info.test0000644003604700454610000013524411737050674013726 0ustar dgp771div# -*- tcl -*- # Commands covered: info # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1994 The Regents of the University of California. # Copyright (c) 1994-1997 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # Copyright (c) 2006 ActiveState # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # DO NOT DELETE THIS LINE. Keep line numbers correct for testing 'info frame'. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import -force ::tcltest::* } # Set up namespaces needed to test operation of "info args", "info body", # "info default", and "info procs" with imported procedures. catch {namespace delete test_ns_info1 test_ns_info2} namespace eval test_ns_info1 { namespace export * proc p {x} {return "x=$x"} proc q {{y 27} {z {}}} {return "y=$y"} } testConstraint tip280 [info exists tcl_platform(tip,280)] testConstraint !tip280 [expr {![info exists tcl_platform(tip,280)]}] test info-1.1 {info args option} { proc t1 {a bbb c} {return foo} info args t1 } {a bbb c} test info-1.2 {info args option} { proc t1 {{a default1} {bbb default2} {c default3} args} {return foo} info a t1 } {a bbb c args} test info-1.3 {info args option} { proc t1 "" {return foo} info args t1 } {} test info-1.4 {info args option} { catch {rename t1 {}} list [catch {info args t1} msg] $msg } {1 {"t1" isn't a procedure}} test info-1.5 {info args option} { list [catch {info args set} msg] $msg } {1 {"set" isn't a procedure}} test info-1.6 {info args option} { proc t1 {a b} {set c 123; set d $c} t1 1 2 info args t1 } {a b} test info-1.7 {info args option} { catch {namespace delete test_ns_info2} namespace eval test_ns_info2 { namespace import ::test_ns_info1::* list [info args p] [info args q] } } {x {y z}} test info-2.1 {info body option} { proc t1 {} {body of t1} info body t1 } {body of t1} test info-2.2 {info body option} { list [catch {info body set} msg] $msg } {1 {"set" isn't a procedure}} test info-2.3 {info body option} { list [catch {info args set 1} msg] $msg } {1 {wrong # args: should be "info args procname"}} test info-2.4 {info body option} { catch {namespace delete test_ns_info2} namespace eval test_ns_info2 { namespace import ::test_ns_info1::* list [info body p] [info body q] } } {{return "x=$x"} {return "y=$y"}} # Prior to 8.3.0 this would cause a crash because [info body] # would return the bytecompiled version of foo, which the catch # would then try and eval out of the foo context, accessing # compiled local indices test info-2.5 {info body option, returning bytecompiled bodies} { catch {unset args} proc foo {args} { foreach v $args { upvar $v var return "variable $v existence: [info exists var]" } } foo a list [catch [info body foo] msg] $msg } {1 {can't read "args": no such variable}} # Fix for problem tested for in info-2.5 caused problems when # procedure body had no string rep (i.e. was not yet bytecode) # causing an empty string to be returned [Bug #545644] test info-2.6 {info body option, returning list bodies} { proc foo args [list subst bar] list [string bytelength [info body foo]] \ [foo; string bytelength [info body foo]] } {9 9} # "info cmdcount" is no longer accurate for compiled commands! # The expected result for info-3.1 used to be "3" and is now "1" # since the "set"s have been compiled away. info-3.2 was corrected # in 8.3 because the eval'ed body won't be compiled. proc testinfocmdcount {} { set x [info cmdcount] set y 12345 set z [info cm] expr $z-$x } test info-3.1 {info cmdcount compiled} { testinfocmdcount } 1 test info-3.2 {info cmdcount evaled} { set x [info cmdcount] set y 12345 set z [info cm] expr $z-$x } 3 test info-3.3 {info cmdcount evaled} [info body testinfocmdcount] 3 test info-3.4 {info cmdcount option} { list [catch {info cmdcount 1} msg] $msg } {1 {wrong # args: should be "info cmdcount"}} test info-4.1 {info commands option} { proc t1 {} {} proc t2 {} {} set x " [info commands] " list [string match {* t1 *} $x] [string match {* t2 *} $x] \ [string match {* set *} $x] [string match {* list *} $x] } {1 1 1 1} test info-4.2 {info commands option} { proc t1 {} {} rename t1 {} set x [info comm] string match {* t1 *} $x } 0 test info-4.3 {info commands option} { proc _t1_ {} {} proc _t2_ {} {} info commands _t1_ } _t1_ test info-4.4 {info commands option} { proc _t1_ {} {} proc _t2_ {} {} lsort [info commands _t*] } {_t1_ _t2_} catch {rename _t1_ {}} catch {rename _t2_ {}} test info-4.5 {info commands option} { list [catch {info commands a b} msg] $msg } {1 {wrong # args: should be "info commands ?pattern?"}} test info-5.1 {info complete option} { list [catch {info complete} msg] $msg } {1 {wrong # args: should be "info complete command"}} test info-5.2 {info complete option} { info complete abc } 1 test info-5.3 {info complete option} { info complete "\{abcd " } 0 test info-5.4 {info complete option} { info complete {# Comment should be complete command} } 1 test info-5.5 {info complete option} { info complete {[a [b] } } 0 test info-5.6 {info complete option} { info complete {[a [b]} } 0 test info-6.1 {info default option} { proc t1 {a b {c d} {e "long default value"}} {} info default t1 a value } 0 test info-6.2 {info default option} { proc t1 {a b {c d} {e "long default value"}} {} set value 12345 info d t1 a value set value } {} test info-6.3 {info default option} { proc t1 {a b {c d} {e "long default value"}} {} info default t1 c value } 1 test info-6.4 {info default option} { proc t1 {a b {c d} {e "long default value"}} {} set value 12345 info default t1 c value set value } d test info-6.5 {info default option} { proc t1 {a b {c d} {e "long default value"}} {} set value 12345 set x [info default t1 e value] list $x $value } {1 {long default value}} test info-6.6 {info default option} { list [catch {info default a b} msg] $msg } {1 {wrong # args: should be "info default procname arg varname"}} test info-6.7 {info default option} { list [catch {info default _nonexistent_ a b} msg] $msg } {1 {"_nonexistent_" isn't a procedure}} test info-6.8 {info default option} { proc t1 {a b} {} list [catch {info default t1 x value} msg] $msg } {1 {procedure "t1" doesn't have an argument "x"}} test info-6.9 {info default option} { catch {unset a} set a(0) 88 proc t1 {a b} {} list [catch {info default t1 a a} msg] $msg } {1 {couldn't store default value in variable "a"}} test info-6.10 {info default option} { catch {unset a} set a(0) 88 proc t1 {{a 18} b} {} list [catch {info default t1 a a} msg] $msg } {1 {couldn't store default value in variable "a"}} test info-6.11 {info default option} { catch {namespace delete test_ns_info2} namespace eval test_ns_info2 { namespace import ::test_ns_info1::* list [info default p x foo] $foo [info default q y bar] $bar } } {0 {} 1 27} catch {unset a} test info-7.1 {info exists option} { set value foo info exists value } 1 catch {unset _nonexistent_} test info-7.2 {info exists option} { info exists _nonexistent_ } 0 test info-7.3 {info exists option} { proc t1 {x} {return [info exists x]} t1 2 } 1 test info-7.4 {info exists option} { proc t1 {x} { global _nonexistent_ return [info exists _nonexistent_] } t1 2 } 0 test info-7.5 {info exists option} { proc t1 {x} { set y 47 return [info exists y] } t1 2 } 1 test info-7.6 {info exists option} { proc t1 {x} {return [info exists value]} t1 2 } 0 test info-7.7 {info exists option} { catch {unset x} set x(2) 44 list [info exists x] [info exists x(1)] [info exists x(2)] } {1 0 1} catch {unset x} test info-7.8 {info exists option} { list [catch {info exists} msg] $msg } {1 {wrong # args: should be "info exists varName"}} test info-7.9 {info exists option} { list [catch {info exists 1 2} msg] $msg } {1 {wrong # args: should be "info exists varName"}} test info-8.1 {info globals option} { set x 1 set y 2 set value 23 set a " [info globals] " list [string match {* x *} $a] [string match {* y *} $a] \ [string match {* value *} $a] [string match {* _foobar_ *} $a] } {1 1 1 0} test info-8.2 {info globals option} { set _xxx1 1 set _xxx2 2 lsort [info g _xxx*] } {_xxx1 _xxx2} test info-8.3 {info globals option} { list [catch {info globals 1 2} msg] $msg } {1 {wrong # args: should be "info globals ?pattern?"}} test info-8.4 {info globals option: may have leading namespace qualifiers} { set x 0 list [info globals x] [info globals :x] [info globals ::x] [info globals :::x] [info globals ::::x] } {x {} x x x} test info-8.5 {info globals option: only return existing global variables} { -setup { catch {unset ::NO_SUCH_VAR} proc evalInProc script {eval $script} } -body { evalInProc {global NO_SUCH_VAR; info globals NO_SUCH_VAR} } -cleanup { rename evalInProc {} } -result {} } test info-9.1 {info level option} { info level } 0 test info-9.2 {info level option} { proc t1 {a b} { set x [info le] set y [info level 1] list $x $y } t1 146 testString } {1 {t1 146 testString}} test info-9.3 {info level option} { proc t1 {a b} { t2 [expr $a*2] $b } proc t2 {x y} { list [info level] [info level 1] [info level 2] [info level -1] \ [info level 0] } t1 146 {a {b c} {{{c}}}} } {2 {t1 146 {a {b c} {{{c}}}}} {t2 292 {a {b c} {{{c}}}}} {t1 146 {a {b c} {{{c}}}}} {t2 292 {a {b c} {{{c}}}}}} test info-9.4 {info level option} { proc t1 {} { set x [info level] set y [info level 1] list $x $y } t1 } {1 t1} test info-9.5 {info level option} { list [catch {info level 1 2} msg] $msg } {1 {wrong # args: should be "info level ?number?"}} test info-9.6 {info level option} { list [catch {info level 123a} msg] $msg } {1 {expected integer but got "123a"}} test info-9.7 {info level option} { list [catch {info level 0} msg] $msg } {1 {bad level "0"}} test info-9.8 {info level option} { proc t1 {} {info level -1} list [catch {t1} msg] $msg } {1 {bad level "-1"}} test info-9.9 {info level option} { proc t1 {x} {info level $x} list [catch {t1 -3} msg] $msg } {1 {bad level "-3"}} test info-9.10 {info level option, namespaces} { set msg [namespace eval t {info level 0}] namespace delete t set msg } {namespace eval t {info level 0}} set savedLibrary $tcl_library test info-10.1 {info library option} { list [catch {info library x} msg] $msg } {1 {wrong # args: should be "info library"}} test info-10.2 {info library option} { set tcl_library 12345 info library } {12345} test info-10.3 {info library option} { unset tcl_library list [catch {info library} msg] $msg } {1 {no library has been specified for Tcl}} set tcl_library $savedLibrary test info-11.1 {info loaded option} { list [catch {info loaded a b} msg] $msg } {1 {wrong # args: should be "info loaded ?interp?"}} test info-11.2 {info loaded option} { list [catch {info loaded {}}] [catch {info loaded gorp} msg] $msg } {0 1 {could not find interpreter "gorp"}} test info-12.1 {info locals option} { set a 22 proc t1 {x y} { set b 13 set c testing global a global aa set aa 23 return [info locals] } lsort [t1 23 24] } {b c x y} test info-12.2 {info locals option} { proc t1 {x y} { set xx1 2 set xx2 3 set y 4 return [info loc x*] } lsort [t1 2 3] } {x xx1 xx2} test info-12.3 {info locals option} { list [catch {info locals 1 2} msg] $msg } {1 {wrong # args: should be "info locals ?pattern?"}} test info-12.4 {info locals option} { info locals } {} test info-12.5 {info locals option} { proc t1 {} {return [info locals]} t1 } {} test info-12.6 {info locals vs unset compiled locals} { proc t1 {lst} { foreach $lst $lst {} unset lst return [info locals] } lsort [t1 {a b c c d e f}] } {a b c d e f} test info-12.7 {info locals with temporary variables} { proc t1 {} { foreach a {b c} {} info locals } t1 } {a} test info-13.1 {info nameofexecutable option} { list [catch {info nameofexecutable foo} msg] $msg } {1 {wrong # args: should be "info nameofexecutable"}} test info-14.1 {info patchlevel option} { set a [info patchlevel] regexp {[0-9]+\.[0-9]+([p[0-9]+)?} $a } 1 test info-14.2 {info patchlevel option} { list [catch {info patchlevel a} msg] $msg } {1 {wrong # args: should be "info patchlevel"}} test info-14.3 {info patchlevel option} { set t $tcl_patchLevel unset tcl_patchLevel set result [list [catch {info patchlevel} msg] $msg] set tcl_patchLevel $t set result } {1 {can't read "tcl_patchLevel": no such variable}} test info-15.1 {info procs option} { proc t1 {} {} proc t2 {} {} set x " [info procs] " list [string match {* t1 *} $x] [string match {* t2 *} $x] \ [string match {* _undefined_ *} $x] } {1 1 0} test info-15.2 {info procs option} { proc _tt1 {} {} proc _tt2 {} {} lsort [info pr _tt*] } {_tt1 _tt2} catch {rename _tt1 {}} catch {rename _tt2 {}} test info-15.3 {info procs option} { list [catch {info procs 2 3} msg] $msg } {1 {wrong # args: should be "info procs ?pattern?"}} test info-15.4 {info procs option} { catch {namespace delete test_ns_info2} namespace eval test_ns_info2 { namespace import ::test_ns_info1::* proc r {} {} list [info procs] [info procs p*] } } {{p q r} p} test info-15.5 {info procs option with a proc in a namespace} { catch {namespace delete test_ns_info2} namespace eval test_ns_info2 { proc p1 { arg } { puts cmd } proc p2 { arg } { puts cmd } } info procs ::test_ns_info2::p1 } {::test_ns_info2::p1} test info-15.6 {info procs option with a pattern in a namespace} { catch {namespace delete test_ns_info2} namespace eval test_ns_info2 { proc p1 { arg } { puts cmd } proc p2 { arg } { puts cmd } } lsort [info procs ::test_ns_info2::p*] } [lsort [list ::test_ns_info2::p1 ::test_ns_info2::p2]] test info-15.7 {info procs option with a global shadowing proc} { catch {namespace delete test_ns_info2} proc string_cmd { arg } { puts cmd } namespace eval test_ns_info2 { proc string_cmd { arg } { puts cmd } } info procs test_ns_info2::string* } {::test_ns_info2::string_cmd} # This regression test is currently commented out because it requires # that the implementation of "info procs" looks into the global namespace, # which it does not (in contrast to "info commands") if {0} { test info-15.8 {info procs option with a global shadowing proc} { catch {namespace delete test_ns_info2} proc string_cmd { arg } { puts cmd } proc string_cmd2 { arg } { puts cmd } namespace eval test_ns_info2 { proc string_cmd { arg } { puts cmd } } namespace eval test_ns_info2 { lsort [info procs string*] } } [lsort [list string_cmd string_cmd2]] } test info-16.1 {info script option} { list [catch {info script x x} msg] $msg } {1 {wrong # args: should be "info script ?filename?"}} test info-16.2 {info script option} { file tail [info sc] } "info.test" set gorpfile [makeFile "info script\n" gorp.info] test info-16.3 {info script option} { list [source $gorpfile] [file tail [info script]] } [list $gorpfile info.test] test info-16.4 {resetting "info script" after errors} { catch {source ~_nobody_/foo} file tail [info script] } "info.test" test info-16.5 {resetting "info script" after errors} { catch {source _nonexistent_} file tail [info script] } "info.test" test info-16.6 {info script option} { set script [info script] list [file tail [info script]] \ [info script newname.txt] \ [file tail [info script $script]] } [list info.test newname.txt info.test] test info-16.7 {info script option} { set script [info script] info script newname.txt list [source $gorpfile] [file tail [info script]] \ [file tail [info script $script]] } [list $gorpfile newname.txt info.test] removeFile gorp.info set gorpfile [makeFile {list [info script] [info script foo.bar]} gorp.info] test info-16.8 {info script option} { list [source $gorpfile] [file tail [info script]] } [list [list $gorpfile foo.bar] info.test] removeFile gorp.info test info-17.1 {info sharedlibextension option} { list [catch {info sharedlibextension foo} msg] $msg } {1 {wrong # args: should be "info sharedlibextension"}} test info-18.1 {info tclversion option} { set x [info tclversion] scan $x "%d.%d%c" a b c } 2 test info-18.2 {info tclversion option} { list [catch {info t 2} msg] $msg } {1 {wrong # args: should be "info tclversion"}} test info-18.3 {info tclversion option} { set t $tcl_version unset tcl_version set result [list [catch {info tclversion} msg] $msg] set tcl_version $t set result } {1 {can't read "tcl_version": no such variable}} test info-19.1 {info vars option} { set a 1 set b 2 proc t1 {x y} { global a b set c 33 return [info vars] } lsort [t1 18 19] } {a b c x y} test info-19.2 {info vars option} { set xxx1 1 set xxx2 2 proc t1 {xxa y} { global xxx1 xxx2 set c 33 return [info vars x*] } lsort [t1 18 19] } {xxa xxx1 xxx2} test info-19.3 {info vars option} { lsort [info vars] } [lsort [info globals]] test info-19.4 {info vars option} { list [catch {info vars a b} msg] $msg } {1 {wrong # args: should be "info vars ?pattern?"}} test info-19.5 {info vars with temporary variables} { proc t1 {} { foreach a {b c} {} info vars } t1 } {a} test info-19.6 {info vars: Bug 1072654} -setup { namespace eval :: unset -nocomplain foo catch {namespace delete x} } -body { namespace eval x info vars foo } -cleanup { namespace delete x } -result {} # Check whether the extra testing functions are defined... if {([catch {expr T1()} msg] == 1) && ($msg == {unknown math function "T1"})} { set functions {abs acos asin atan atan2 ceil cos cosh double exp floor fmod hypot int log log10 pow rand round sin sinh sqrt srand tan tanh wide} } else { set functions {T1 T2 T3 abs acos asin atan atan2 ceil cos cosh double exp floor fmod hypot int log log10 pow rand round sin sinh sqrt srand tan tanh wide} } test info-20.1 {info functions option} {info functions sin} sin test info-20.2 {info functions option} {lsort [info functions]} $functions test info-20.3 {info functions option} { lsort [info functions a*] } {abs acos asin atan atan2} test info-20.4 {info functions option} { lsort [info functions *tan*] } {atan atan2 tan tanh} test info-20.5 {info functions option} { list [catch {info functions raise an error} msg] $msg } {1 {wrong # args: should be "info functions ?pattern?"}} test info-21.1 {miscellaneous error conditions} { list [catch {info} msg] $msg } {1 {wrong # args: should be "info option ?arg arg ...?"}} test info-21.2 {miscellaneous error conditions} !tip280 { list [catch {info gorp} msg] $msg } {1 {bad option "gorp": must be args, body, cmdcount, commands, complete, default, exists, functions, globals, hostname, level, library, loaded, locals, nameofexecutable, patchlevel, procs, script, sharedlibextension, tclversion, or vars}} test info-21.2-280 {miscellaneous error conditions} tip280 { list [catch {info gorp} msg] $msg } {1 {bad option "gorp": must be args, body, cmdcount, commands, complete, default, exists, frame, functions, globals, hostname, level, library, loaded, locals, nameofexecutable, patchlevel, procs, script, sharedlibextension, tclversion, or vars}} test info-21.3 {miscellaneous error conditions} !tip280 { list [catch {info c} msg] $msg } {1 {ambiguous option "c": must be args, body, cmdcount, commands, complete, default, exists, functions, globals, hostname, level, library, loaded, locals, nameofexecutable, patchlevel, procs, script, sharedlibextension, tclversion, or vars}} test info-21.3-280 {miscellaneous error conditions} tip280 { list [catch {info c} msg] $msg } {1 {ambiguous option "c": must be args, body, cmdcount, commands, complete, default, exists, frame, functions, globals, hostname, level, library, loaded, locals, nameofexecutable, patchlevel, procs, script, sharedlibextension, tclversion, or vars}} test info-21.4 {miscellaneous error conditions} !tip280 { list [catch {info l} msg] $msg } {1 {ambiguous option "l": must be args, body, cmdcount, commands, complete, default, exists, functions, globals, hostname, level, library, loaded, locals, nameofexecutable, patchlevel, procs, script, sharedlibextension, tclversion, or vars}} test info-21.4-280 {miscellaneous error conditions} tip280 { list [catch {info l} msg] $msg } {1 {ambiguous option "l": must be args, body, cmdcount, commands, complete, default, exists, frame, functions, globals, hostname, level, library, loaded, locals, nameofexecutable, patchlevel, procs, script, sharedlibextension, tclversion, or vars}} test info-21.5 {miscellaneous error conditions} !tip280 { list [catch {info s} msg] $msg } {1 {ambiguous option "s": must be args, body, cmdcount, commands, complete, default, exists, functions, globals, hostname, level, library, loaded, locals, nameofexecutable, patchlevel, procs, script, sharedlibextension, tclversion, or vars}} test info-21.5-280 {miscellaneous error conditions} tip280 { list [catch {info s} msg] $msg } {1 {ambiguous option "s": must be args, body, cmdcount, commands, complete, default, exists, frame, functions, globals, hostname, level, library, loaded, locals, nameofexecutable, patchlevel, procs, script, sharedlibextension, tclversion, or vars}} ## # ### ### ### ######### ######### ######### ## info frame ## Helper # For the more complex results we cut the file name down to remove # path dependencies, and we use only part of the first line of the # reported command. The latter is required because otherwise the whole # test case may appear in some results, but the result is part of the # testcase. An infinite string would be required to describe that. The # cutting-down breaks this. proc reduce {frame} { set pos [lsearch -exact $frame cmd] incr pos set cmd [lindex $frame $pos] if {[regexp \n $cmd]} { set first [lindex [split $cmd \n] 0] ; set first [expr {[string length $first] > 11 ? [string range $first 0 end-11] : [string range $first 0 end-4]}] set frame [lreplace $frame $pos $pos $first] } set pos [lsearch -exact $frame file] if {$pos >=0} { incr pos set tail [file tail [lindex $frame $pos]] set frame [lreplace $frame $pos $pos $tail] } set frame } ## Helper # Generate a stacktrace from the current location to top. This code # not only depends on the exact location of things, but also on the # implementation of tcltest. Any changes and these tests will have to # be updated. proc etrace {} { set res {} set level [info frame] while {$level} { lappend res [list $level [reduce [info frame $level]]] incr level -1 } return $res } ## test info-22.0.0 {info frame, levels} {tip280 && !singleTestInterp} { info frame } 7 test info-22.0.1 {info frame, levels} {tip280 && singleTestInterp} { info frame } 10 test info-22.1.0 {info frame, bad level relative} {tip280 && !singleTestInterp} { # catch is another level!, i.e. we have 8, not 7 catch {info frame -8} msg set msg } {bad level "-8"} test info-22.1.1 {info frame, bad level relative} {tip280 && singleTestInterp} { # catch is another level!, i.e. we have 11, not 10 catch {info frame -11} msg set msg } {bad level "-11"} test info-22.2.0 {info frame, bad level absolute} {tip280 && !singleTestInterp} { # catch is another level!, i.e. we have 8, not 7 catch {info frame 9} msg set msg } {bad level "9"} test info-22.2.1 {info frame, bad level absolute} {tip280 && singleTestInterp} { # catch is another level!, i.e. we have 12, not 10 catch {info frame 12} msg set msg } {bad level "12"} test info-22.3 {info frame, current, relative} -constraints tip280 -match glob -body { info frame 0 } -result {type source line 761 file * cmd {info frame 0} proc ::tcltest::RunTest} test info-22.4 {info frame, current, relative, nested} -constraints tip280 -match glob -body { set res [info frame 0] } -result {type source line 765 file * cmd {info frame 0} proc ::tcltest::RunTest} test info-22.5.0 {info frame, current, absolute} -constraints {tip280 && !singleTestInterp} -match glob -body { reduce [info frame 7] } -result {type source line 769 file * cmd {info frame 7} proc ::tcltest::RunTest} test info-22.5.1 {info frame, current, absolute} -constraints {tip280 && singleTestInterp} -match glob -body { reduce [info frame 10] } -result {type source line 772 file * cmd {info frame 10} proc ::tcltest::RunTest} test info-22.6.0 {info frame, global, relative} {tip280 && !singleTestInterp} { reduce [info frame -6] } {type source line 775 file info.test cmd test\ info-22.6.0\ \{info\ frame,\ global,\ relative\}\ \{tip280\ &&\ !singleTe} test info-22.6.1 {info frame, global, relative} {tip280 && singleTestInterp} { reduce [info frame -6] } {type source line 778 file info.test cmd test\ info-22.6.1\ \{info\ frame,\ global,\ relative\}\ \{tip280\ &&\ singleTe proc ::tcltest::runAllTests} test info-22.7.0 {info frame, global, absolute} {tip280 && !singleTestInterp} { reduce [info frame 1] } {type source line 782 file info.test cmd test\ info-22.7.0\ \{info\ frame,\ global,\ absolute\}\ \{tip280\ &&\ !singleTe} test info-22.7.1 {info frame, global, absolute} {tip280 && singleTestInterp} { reduce [info frame 4] } {type source line 785 file info.test cmd test\ info-22.7.1\ \{info\ frame,\ global,\ absolute\}\ \{tip280\ &&\ singleTe proc ::tcltest::runAllTests} test info-22.8 {info frame, basic trace} -constraints {tip280} -match glob -body { join [lrange [etrace] 0 1] \n } -result {* {type source line 723 file info.test cmd {info frame $level} proc ::etrace level 0} * {type source line 790 file info.test cmd etrace proc ::tcltest::RunTest}} test info-23.0.0 {eval'd info frame} {tip280 && !singleTestInterp} { eval {info frame} } 8 test info-23.0.1 {eval'd info frame} {tip280 && singleTestInterp} { eval {info frame} } 11 test info-23.1.0 {eval'd info frame, semi-dynamic} {tip280 && !singleTestInterp} { eval info frame } 8 test info-23.1.1 {eval'd info frame, semi-dynamic} {tip280 && singleTestInterp} { eval info frame } 11 test info-23.2.0 {eval'd info frame, dynamic} {tip280 && !singleTestInterp} { set script {info frame} eval $script } 8 test info-23.2.1 {eval'd info frame, dynamic} {tip280 && singleTestInterp} { set script {info frame} eval $script } 11 test info-23.3 {eval'd info frame, literal} -constraints tip280 -match glob -body { eval { info frame 0 } } -result {type source line 819 file *info.test cmd {info frame 0} proc ::tcltest::RunTest} test info-23.4 {eval'd info frame, semi-dynamic} tip280 { eval info frame 0 } {type eval line 1 cmd {info frame 0} proc ::tcltest::RunTest} test info-23.5 {eval'd info frame, dynamic} tip280 { set script {info frame 0} eval $script } {type eval line 1 cmd {info frame 0} proc ::tcltest::RunTest} test info-23.6 {eval'd info frame, trace} -constraints {tip280} -match glob -body { set script {etrace} join [lrange [eval $script] 0 2] \n } -result {* {type source line 723 file info.test cmd {info frame $level} proc ::etrace level 0} * {type eval line 1 cmd etrace proc ::tcltest::RunTest} * {type source line 834 file info.test cmd {eval $script} proc ::tcltest::RunTest}} # ------------------------------------------------------------------------- # Procedures defined in scripts which are arguments to control # structures (like 'namespace eval', 'interp eval', 'if', 'while', # 'switch', 'catch', 'for', 'foreach', etc.) have no absolute # location. The command implementations execute such scripts through # Tcl_EvalObjEx. Flag 0 causes it to use the bytecode compiler. This # causes the connection to the context to be lost. Currently only # procedure bodies are able to remember their context. # ------------------------------------------------------------------------- namespace eval foo { proc bar {} {info frame 0} } test info-24.0 {info frame, interaction, namespace eval} tip280 { reduce [foo::bar] } {type source line 852 file info.test cmd {info frame 0} proc ::foo::bar level 0} namespace delete foo # ------------------------------------------------------------------------- set flag 1 if {$flag} { namespace eval foo {} proc ::foo::bar {} {info frame 0} } test info-24.1 {info frame, interaction, if} tip280 { reduce [foo::bar] } {type source line 866 file info.test cmd {info frame 0} proc ::foo::bar level 0} namespace delete foo # ------------------------------------------------------------------------- set flag 1 while {$flag} { namespace eval foo {} proc ::foo::bar {} {info frame 0} set flag 0 } test info-24.2 {info frame, interaction, while} tip280 { reduce [foo::bar] } {type source line 880 file info.test cmd {info frame 0} proc ::foo::bar level 0} namespace delete foo # ------------------------------------------------------------------------- catch { namespace eval foo {} proc ::foo::bar {} {info frame 0} } test info-24.3 {info frame, interaction, catch} tip280 { reduce [foo::bar] } {type source line 894 file info.test cmd {info frame 0} proc ::foo::bar level 0} namespace delete foo # ------------------------------------------------------------------------- foreach var val { namespace eval foo {} proc ::foo::bar {} {info frame 0} break } test info-24.4 {info frame, interaction, foreach} tip280 { reduce [foo::bar] } {type source line 907 file info.test cmd {info frame 0} proc ::foo::bar level 0} namespace delete foo # ------------------------------------------------------------------------- for {} {1} {} { namespace eval foo {} proc ::foo::bar {} {info frame 0} break } test info-24.5 {info frame, interaction, for} tip280 { reduce [foo::bar] } {type source line 921 file info.test cmd {info frame 0} proc ::foo::bar level 0} namespace delete foo # ------------------------------------------------------------------------- eval { proc bar {} {info frame 0} } test info-25.0 {info frame, proc in eval} tip280 { reduce [bar] } {type source line 934 file info.test cmd {info frame 0} proc ::bar level 0} proc bar {} {info frame 0} test info-25.1 {info frame, regular proc} tip280 { reduce [bar] } {type source line 941 file info.test cmd {info frame 0} proc ::bar level 0} rename bar {} # More info-30.x test cases at the end of the file. test info-30.0 {bs+nl in literal words} {tip280} { if {1} { set res \ [reduce [info frame 0]];# line 952 } set res # This was reporting line 3 instead of the correct 4 because the # bs+nl combination is subst by the parser before the 'if' # command, and the bcc, see the word. Fixed by recording the # offsets of all bs+nl sequences in literal words, then using the # information in the bcc and other places to bump line numbers when # parsing over the location. Also affected: testcases 22.8 and 23.6. } {type source line 952 file info.test cmd {info frame 0} proc ::tcltest::RunTest} # ------------------------------------------------------------------------- # See 24.0 - 24.5 for similar situations, using literal scripts. set body {set flag 0 set a c set res [info frame 0]} ;# line 3! test info-31.0 {ns eval, script in variable} tip280 {set res {} namespace eval foo $body set res } {type eval line 3 cmd {info frame 0} level 0} catch {namespace delete foo} test info-31.1 {if, script in variable} tip280 { if 1 $body set res } {type eval line 3 cmd {info frame 0} proc ::tcltest::RunTest} test info-31.1a {if, script in variable} tip280 { if 1 then $body set res } {type eval line 3 cmd {info frame 0} proc ::tcltest::RunTest} test info-31.2 {while, script in variable} tip280 { set flag 1 while {$flag} $body set res } {type eval line 3 cmd {info frame 0} proc ::tcltest::RunTest} # .3 - proc - scoping prevent return of result ... test info-31.4 {foreach, script in variable} tip280 { foreach var val $body set res } {type eval line 3 cmd {info frame 0} proc ::tcltest::RunTest} test info-31.5 {for, script in variable} tip280 { set flag 1 for {} {$flag} {} $body set res } {type eval line 3 cmd {info frame 0} proc ::tcltest::RunTest} test info-31.6 {eval, script in variable} tip280 { eval $body set res } {type eval line 3 cmd {info frame 0} proc ::tcltest::RunTest} # ------------------------------------------------------------------------- namespace eval foo {} set x foo switch -exact -- $x { foo { proc ::foo::bar {} {info frame 0} } } test info-24.6.0 {info frame, interaction, switch, list body} tip280 { reduce [foo::bar] } {type source line 1021 file info.test cmd {info frame 0} proc ::foo::bar level 0} namespace delete foo unset x # ------------------------------------------------------------------------- namespace eval foo {} set x foo switch -exact -- $x foo { proc ::foo::bar {} {info frame 0} } test info-24.6.1 {info frame, interaction, switch, multi-body} tip280 { reduce [foo::bar] } {type source line 1037 file info.test cmd {info frame 0} proc ::foo::bar level 0} namespace delete foo unset x # ------------------------------------------------------------------------- namespace eval foo {} set x foo switch -exact -- $x [list foo { proc ::foo::bar {} {info frame 0} }] test info-24.6.2 {info frame, interaction, switch, list body, dynamic} tip280 { reduce [foo::bar] } {type proc line 1 cmd {info frame 0} proc ::foo::bar level 0} namespace delete foo unset x # ------------------------------------------------------------------------- set body { foo { proc ::foo::bar {} {info frame 0} } } namespace eval foo {} set x foo switch -exact -- $x $body test info-31.7 {info frame, interaction, switch, dynamic} tip280 { reduce [foo::bar] } {type proc line 1 cmd {info frame 0} proc ::foo::bar level 0} namespace delete foo unset x # ------------------------------------------------------------------------- set body { proc ::foo::bar {} {info frame 0} } namespace eval foo {} eval $body test info-32.0 {info frame, dynamic procedure} tip280 { reduce [foo::bar] } {type proc line 1 cmd {info frame 0} proc ::foo::bar level 0} namespace delete foo # ------------------------------------------------------------------------- test info-34.0 {eval pure list, single line} -constraints {tip280} -match glob -body { # Basically, counting the newline in the word seen through $foo # doesn't really make sense. It makes a bit of sense if the word # would have been a string literal in the command list. # # Problem: At the point where we see the list elements we cannot # distinguish the two cases, thus we cannot switch between # count/not-count, it is has to be one or the other for all # cases. Of the two possibilities miguel convinced me that 'not # counting' is the more proper. set foo {b c} set cmd [list foreach $foo {x y} { set res [join [lrange [etrace] 0 2] \n] break }] eval $cmd set res } -result {* {type source line 723 file info.test cmd {info frame $level} proc ::etrace level 0} * {type eval line 2 cmd etrace proc ::tcltest::RunTest} * {type eval line 1 cmd foreac proc ::tcltest::RunTest}} # ------------------------------------------------------------------------- # 6 cases. ## DV. direct-var - unchanged ## DPV direct-proc-var - ditto ## PPV proc-proc-var - ditto ## DL. direct-literal - now tracking absolute location ## DPL direct-proc-literal - ditto ## PPL proc-proc-literal - ditto ## ### ### ### ######### ######### #########" proc control {vv script} { upvar 1 $vv var return [uplevel 1 $script] } proc datal {} { control y { set y PPL etrace } } proc datav {} { set script { set y PPV etrace } control y $script } test info-38.1 {location information for uplevel, dv, direct-var} -constraints tip280 -match glob -body { set script { set y DV. etrace } join [lrange [uplevel \#0 $script] 0 2] \n } -result {* {type source line 723 file info.test cmd {info frame $level} proc ::etrace level 0} * {type eval line 3 cmd etrace proc ::tcltest::RunTest} * {type source line 1156 file info.test cmd {uplevel \\#0 $script} proc ::tcltest::RunTest}} test info-38.2 {location information for uplevel, dl, direct-literal} -constraints tip280 -match glob -body { join [lrange [uplevel \#0 { set y DL. etrace }] 0 2] \n } -result {* {type source line 723 file info.test cmd {info frame $level} proc ::etrace level 0} * {type source line 1164 file info.test cmd etrace proc ::tcltest::RunTest} * {type source line 1162 file info.test cmd up proc ::tcltest::RunTest}} test info-38.3 {location information for uplevel, dpv, direct-proc-var} -constraints tip280 -match glob -body { set script { set y DPV etrace } join [lrange [control y $script] 0 3] \n } -result {* {type source line 723 file info.test cmd {info frame $level} proc ::etrace level 0} * {type eval line 3 cmd etrace proc ::control} * {type source line 1133 file info.test cmd {uplevel 1 $script} proc ::control} * {type source line 1175 file info.test cmd {control y $script} proc ::tcltest::RunTest}} test info-38.4 {location information for uplevel, dpv, direct-proc-literal} -constraints tip280 -match glob -body { join [lrange [control y { set y DPL etrace }] 0 3] \n } -result {* {type source line 723 file info.test cmd {info frame $level} proc ::etrace level 0} * {type source line 1184 file info.test cmd etrace proc ::control} * {type source line 1133 file info.test cmd {uplevel 1 $script} proc ::control} * {type source line 1182 file info.test cmd control proc ::tcltest::RunTest}} test info-38.5 {location information for uplevel, ppv, proc-proc-var} -constraints tip280 -match glob -body { join [lrange [datav] 0 4] \n } -result {* {type source line 723 file info.test cmd {info frame $level} proc ::etrace level 0} * {type eval line 3 cmd etrace proc ::control} * {type source line 1133 file info.test cmd {uplevel 1 $script} proc ::control} * {type source line 1148 file info.test cmd {control y $script} proc ::datav level 1} * {type source line 1192 file info.test cmd datav proc ::tcltest::RunTest}} test info-38.6 {location information for uplevel, ppl, proc-proc-literal} -constraints tip280 -match glob -body { join [lrange [datal] 0 4] \n } -result {* {type source line 723 file info.test cmd {info frame $level} proc ::etrace level 0} * {type source line 1139 file info.test cmd etrace proc ::control} * {type source line 1133 file info.test cmd {uplevel 1 $script} proc ::control} * {type source line 1137 file info.test cmd control proc ::datal level 1} * {type source line 1200 file info.test cmd datal proc ::tcltest::RunTest}} # ------------------------------------------------------------------------- # literal sharing test info-39.0 {location information not confused by literal sharing} -constraints tip280 -body { namespace eval ::foo {} proc ::foo::bar {} { lappend res {} lappend res [reduce [eval {info frame 0}]] lappend res [reduce [eval {info frame 0}]] return $res } set res [::foo::bar] namespace delete ::foo join $res \n } -result { type source line 1214 file info.test cmd {info frame 0} proc ::foo::bar level 0 type source line 1215 file info.test cmd {info frame 0} proc ::foo::bar level 0} # ------------------------------------------------------------------------- # Additional tests for info-30.*, handling of continuation lines (bs+nl sequences). test info-30.1 {bs+nl in literal words, procedure body, compiled} {tip280} { proc abra {} { if {1} \ { return \ [reduce [info frame 0]];# line 1233 } } set res [abra] rename abra {} set res } {type source line 1233 file info.test cmd {info frame 0} proc ::abra level 0} test info-30.2 {bs+nl in literal words, namespace script} {tip280} { namespace eval xxx { set res \ [reduce [info frame 0]];# line 1244 } set res } {type source line 1244 file info.test cmd {info frame 0} level 0} test info-30.3 {bs+nl in literal words, namespace multi-word script} {tip280} { namespace eval xxx set res \ [list [reduce [info frame 0]]];# line 1251 set res } {type source line 1251 file info.test cmd {info frame 0} proc ::tcltest::RunTest} test info-30.4 {bs+nl in literal words, eval script} {tip280} { eval { set ::res \ [reduce [info frame 0]];# line 1258 } set res } {type source line 1258 file info.test cmd {info frame 0} proc ::tcltest::RunTest} test info-30.5 {bs+nl in literal words, eval script, with nested words} {tip280} { eval { if {1} \ { set ::res \ [reduce [info frame 0]];# line 1268 } } set res } {type source line 1268 file info.test cmd {info frame 0} proc ::tcltest::RunTest} test info-30.6 {bs+nl in computed word} {tip280} { set res "\ [reduce [info frame 0]]";# line 1276 } { type source line 1276 file info.test cmd {info frame 0} proc ::tcltest::RunTest} test info-30.7 {bs+nl in computed word, in proc} {tip280} { proc abra {} { return "\ [reduce [info frame 0]]";# line 1282 } set res [abra] rename abra {} set res } { type source line 1282 file info.test cmd {info frame 0} proc ::abra level 0} test info-30.8 {bs+nl in computed word, nested eval} {tip280} { eval { set \ res "\ [reduce [info frame 0]]";# line 1293 } } { type source line 1293 file info.test cmd {info frame 0} proc ::tcltest::RunTest} test info-30.9 {bs+nl in computed word, nested eval} {tip280} { eval { set \ res "\ [reduce \ [info frame 0]]";# line 1302 } } { type source line 1302 file info.test cmd {info frame 0} proc ::tcltest::RunTest} test info-30.10 {bs+nl in computed word, key to array} {tip280} { set tmp([set \ res "\ [reduce \ [info frame 0]]"]) x ; #1310 unset tmp set res } { type source line 1310 file info.test cmd {info frame 0} proc ::tcltest::RunTest} test info-30.11 {bs+nl in subst arguments, no true counting} {tip280} { subst {[set \ res "\ [reduce \ [info frame 0]]"]} } { type eval line 2 cmd {info frame 0} proc ::tcltest::RunTest} test info-30.12 {bs+nl in computed word, nested eval} {tip280} { eval { set \ res "\ [set x {}] \ [reduce \ [info frame 0]]";# line 1328 } } { type source line 1328 file info.test cmd {info frame 0} proc ::tcltest::RunTest} test info-30.13 {bs+nl in literal words, uplevel script, with nested words} {tip280} { uplevel #0 { if {1} \ { set ::res \ [reduce [info frame 0]];# line 1337 } } set res } {type source line 1337 file info.test cmd {info frame 0} proc ::tcltest::RunTest} test info-30.14 {bs+nl, literal word, uplevel through proc} {tip280} { proc abra {script} { uplevel 1 $script } set res [abra { return "\ [reduce [info frame 0]]";# line 1349 }] rename abra {} set res } { type source line 1349 file info.test cmd {info frame 0} proc ::abra} test info-30.15 {bs+nl in literal words, nested proc body, compiled} {tip280} { proc a {} { proc b {} { if {1} \ { return \ [reduce [info frame 0]];# line 1361 } } } a ; set res [b] rename a {} rename b {} set res } {type source line 1361 file info.test cmd {info frame 0} proc ::b level 0} test info-30.16 {bs+nl in multi-body switch, compiled} {tip280} { proc a {value} { switch -regexp -- $value \ ^key { info frame 0; # 1374 } \ \t { info frame 0; # 1375 } \ {[0-9]*} { info frame 0; # 1376 } } set res {} lappend res [reduce [a {key }]] lappend res [reduce [a {1alpha}]] set res "\n[join $res \n]" } { type source line 1374 file info.test cmd {info frame 0} proc ::a level 0 type source line 1376 file info.test cmd {info frame 0} proc ::a level 0} test info-30.17 {bs+nl in multi-body switch, direct} {tip280} { switch -regexp -- {key } \ ^key { reduce [info frame 0] ;# 1388 } \ \t### { } \ {[0-9]*} { } } {type source line 1388 file info.test cmd {info frame 0} proc ::tcltest::RunTest} test info-30.18 {bs+nl, literal word, uplevel through proc, appended, loss of primary tracking data} {tip280} { proc abra {script} { append script "\n# end of script" uplevel 1 $script } set res [abra { return "\ [reduce [info frame 0]]";# line 1400, still line of 3 appended script }] rename abra {} set res } { type eval line 3 cmd {info frame 0} proc ::abra} # { type source line 1400 file info.test cmd {info frame 0} proc ::abra} test info-30.19 {bs+nl in single-body switch, compiled} {tip280} { proc a {value} { switch -regexp -- $value { ^key { reduce \ [info frame 0] } \t { reduce \ [info frame 0] } {[0-9]*} { reduce \ [info frame 0] } } } set res {} lappend res [a {key }] lappend res [a {1alpha}] set res "\n[join $res \n]" } { type source line 1411 file info.test cmd {info frame 0} proc ::a level 0 type source line 1415 file info.test cmd {info frame 0} proc ::a level 0} test info-30.20 {bs+nl in single-body switch, direct} {tip280} { switch -regexp -- {key } { \ ^key { reduce \ [info frame 0] } \t { } {[0-9]*} { } } } {type source line 1430 file info.test cmd {info frame 0} proc ::tcltest::RunTest} test info-30.21 {bs+nl in if, full compiled} {tip280} { proc a {value} { if {$value} \ {info frame 0} \ {info frame 0} } set res {} lappend res [reduce [a 1]] lappend res [reduce [a 0]] set res "\n[join $res \n]" } { type source line 1439 file info.test cmd {info frame 0} proc ::a level 0 type source line 1440 file info.test cmd {info frame 0} proc ::a level 0} test info-30.22 {bs+nl in computed word, key to array, compiled} {tip280} { proc a {} { set tmp([set \ res "\ [reduce \ [info frame 0]]"]) x ; #1454 unset tmp set res } set res [a] rename a {} set res } { type source line 1455 file info.test cmd {info frame 0} proc ::a level 0} # ------------------------------------------------------------------------- # cleanup catch {namespace delete test_ns_info1 test_ns_info2} ::tcltest::cleanupTests return tcl8.4.20/tests/incr.test0000644003604700454610000004204311737050674013720 0ustar dgp771div# Commands covered: incr # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1996 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } # Basic "incr" operation. catch {unset x} catch {unset i} test incr-1.1 {TclCompileIncrCmd: missing variable name} { list [catch {incr} msg] $msg } {1 {wrong # args: should be "incr varName ?increment?"}} test incr-1.2 {TclCompileIncrCmd: simple variable name} { set i 10 list [incr i] $i } {11 11} test incr-1.3 {TclCompileIncrCmd: error compiling variable name} { set i 10 catch {incr "i"xxx} msg set msg } {extra characters after close-quote} test incr-1.4 {TclCompileIncrCmd: simple variable name in quotes} { set i 17 list [incr "i"] $i } {18 18} test incr-1.5 {TclCompileIncrCmd: simple variable name in braces} { catch {unset {a simple var}} set {a simple var} 27 list [incr {a simple var}] ${a simple var} } {28 28} test incr-1.6 {TclCompileIncrCmd: simple array variable name} { catch {unset a} set a(foo) 37 list [incr a(foo)] $a(foo) } {38 38} test incr-1.7 {TclCompileIncrCmd: non-simple (computed) variable name} { set x "i" set i 77 list [incr $x 2] $i } {79 79} test incr-1.8 {TclCompileIncrCmd: non-simple (computed) variable name} { set x "i" set i 77 list [incr [set x] +2] $i } {79 79} test incr-1.9 {TclCompileIncrCmd: increment given} { set i 10 list [incr i +07] $i } {17 17} test incr-1.10 {TclCompileIncrCmd: no increment given} { set i 10 list [incr i] $i } {11 11} test incr-1.11 {TclCompileIncrCmd: simple global name} { proc p {} { global i set i 54 incr i } p } {55} test incr-1.12 {TclCompileIncrCmd: simple local name} { proc p {} { set foo 100 incr foo } p } {101} test incr-1.13 {TclCompileIncrCmd: simple but new (unknown) local name} { proc p {} { incr bar } catch {p} msg set msg } {can't read "bar": no such variable} test incr-1.14 {TclCompileIncrCmd: simple local name, >255 locals} { proc 260locals {} { # create 260 locals set a0 0; set a1 0; set a2 0; set a3 0; set a4 0 set a5 0; set a6 0; set a7 0; set a8 0; set a9 0 set b0 0; set b1 0; set b2 0; set b3 0; set b4 0 set b5 0; set b6 0; set b7 0; set b8 0; set b9 0 set c0 0; set c1 0; set c2 0; set c3 0; set c4 0 set c5 0; set c6 0; set c7 0; set c8 0; set c9 0 set d0 0; set d1 0; set d2 0; set d3 0; set d4 0 set d5 0; set d6 0; set d7 0; set d8 0; set d9 0 set e0 0; set e1 0; set e2 0; set e3 0; set e4 0 set e5 0; set e6 0; set e7 0; set e8 0; set e9 0 set f0 0; set f1 0; set f2 0; set f3 0; set f4 0 set f5 0; set f6 0; set f7 0; set f8 0; set f9 0 set g0 0; set g1 0; set g2 0; set g3 0; set g4 0 set g5 0; set g6 0; set g7 0; set g8 0; set g9 0 set h0 0; set h1 0; set h2 0; set h3 0; set h4 0 set h5 0; set h6 0; set h7 0; set h8 0; set h9 0 set i0 0; set i1 0; set i2 0; set i3 0; set i4 0 set i5 0; set i6 0; set i7 0; set i8 0; set i9 0 set j0 0; set j1 0; set j2 0; set j3 0; set j4 0 set j5 0; set j6 0; set j7 0; set j8 0; set j9 0 set k0 0; set k1 0; set k2 0; set k3 0; set k4 0 set k5 0; set k6 0; set k7 0; set k8 0; set k9 0 set l0 0; set l1 0; set l2 0; set l3 0; set l4 0 set l5 0; set l6 0; set l7 0; set l8 0; set l9 0 set m0 0; set m1 0; set m2 0; set m3 0; set m4 0 set m5 0; set m6 0; set m7 0; set m8 0; set m9 0 set n0 0; set n1 0; set n2 0; set n3 0; set n4 0 set n5 0; set n6 0; set n7 0; set n8 0; set n9 0 set o0 0; set o1 0; set o2 0; set o3 0; set o4 0 set o5 0; set o6 0; set o7 0; set o8 0; set o9 0 set p0 0; set p1 0; set p2 0; set p3 0; set p4 0 set p5 0; set p6 0; set p7 0; set p8 0; set p9 0 set q0 0; set q1 0; set q2 0; set q3 0; set q4 0 set q5 0; set q6 0; set q7 0; set q8 0; set q9 0 set r0 0; set r1 0; set r2 0; set r3 0; set r4 0 set r5 0; set r6 0; set r7 0; set r8 0; set r9 0 set s0 0; set s1 0; set s2 0; set s3 0; set s4 0 set s5 0; set s6 0; set s7 0; set s8 0; set s9 0 set t0 0; set t1 0; set t2 0; set t3 0; set t4 0 set t5 0; set t6 0; set t7 0; set t8 0; set t9 0 set u0 0; set u1 0; set u2 0; set u3 0; set u4 0 set u5 0; set u6 0; set u7 0; set u8 0; set u9 0 set v0 0; set v1 0; set v2 0; set v3 0; set v4 0 set v5 0; set v6 0; set v7 0; set v8 0; set v9 0 set w0 0; set w1 0; set w2 0; set w3 0; set w4 0 set w5 0; set w6 0; set w7 0; set w8 0; set w9 0 set x0 0; set x1 0; set x2 0; set x3 0; set x4 0 set x5 0; set x6 0; set x7 0; set x8 0; set x9 0 set y0 0; set y1 0; set y2 0; set y3 0; set y4 0 set y5 0; set y6 0; set y7 0; set y8 0; set y9 0 set z0 0; set z1 0; set z2 0; set z3 0; set z4 0 set z5 0; set z6 0; set z7 0; set z8 0; set z9 0 # now increment the last one (local var index > 255) incr z9 } 260locals } {1} test incr-1.15 {TclCompileIncrCmd: variable is array} { catch {unset a} set a(foo) 27 set x [incr a(foo) 11] catch {unset a} set x } 38 test incr-1.16 {TclCompileIncrCmd: variable is array, elem substitutions} { catch {unset a} set i 5 set a(foo5) 27 set x [incr a(foo$i) 11] catch {unset a} set x } 38 test incr-1.17 {TclCompileIncrCmd: increment given, simple int} { set i 5 incr i 123 } 128 test incr-1.18 {TclCompileIncrCmd: increment given, simple int} { set i 5 incr i -100 } -95 test incr-1.19 {TclCompileIncrCmd: increment given, but erroneous} { set i 5 catch {incr i [set]} msg set errorInfo } {wrong # args: should be "set varName ?newValue?" while compiling "set" while compiling "incr i [set]"} test incr-1.20 {TclCompileIncrCmd: increment given, in quotes} { set i 25 incr i "-100" } -75 test incr-1.21 {TclCompileIncrCmd: increment given, in braces} { set i 24 incr i {126} } 150 test incr-1.22 {TclCompileIncrCmd: increment given, large int} { set i 5 incr i 200000 } 200005 test incr-1.23 {TclCompileIncrCmd: increment given, formatted int != int} { set i 25 incr i 000012345 ;# an octal literal } 5374 test incr-1.24 {TclCompileIncrCmd: increment given, formatted int != int} { set i 25 catch {incr i 1a} msg set msg } {expected integer but got "1a"} test incr-1.25 {TclCompileIncrCmd: too many arguments} { set i 10 catch {incr i 10 20} msg set msg } {wrong # args: should be "incr varName ?increment?"} test incr-1.26 {TclCompileIncrCmd: runtime error, bad variable name} { list [catch {incr {"foo}} msg] $msg $errorInfo } {1 {can't read ""foo": no such variable} {can't read ""foo": no such variable (reading value of variable to increment) invoked from within "incr {"foo}"}} test incr-1.27 {TclCompileIncrCmd: runtime error, bad variable name} { list [catch {incr [set]} msg] $msg $errorInfo } {1 {wrong # args: should be "set varName ?newValue?"} {wrong # args: should be "set varName ?newValue?" while compiling "set" while compiling "incr [set]"}} test incr-1.28 {TclCompileIncrCmd: runtime error, readonly variable} { proc readonly args {error "variable is read-only"} set x 123 trace var x w readonly list [catch {incr x 1} msg] $msg $errorInfo } {1 {can't set "x": variable is read-only} {can't set "x": variable is read-only while executing "incr x 1"}} catch {unset x} test incr-1.29 {TclCompileIncrCmd: runtime error, bad variable value} { set x " - " list [catch {incr x 1} msg] $msg } {1 {expected integer but got " - "}} test incr-1.30 {TclCompileIncrCmd: array var, braced (no subs)} { catch {unset array} set array(\$foo) 4 incr {array($foo)} } 5 # Check "incr" and computed command names. test incr-2.0 {incr and computed command names} { set i 5 set z incr $z i -1 set i } 4 catch {unset x} catch {unset i} test incr-2.1 {incr command (not compiled): missing variable name} { set z incr list [catch {$z} msg] $msg } {1 {wrong # args: should be "incr varName ?increment?"}} test incr-2.2 {incr command (not compiled): simple variable name} { set z incr set i 10 list [$z i] $i } {11 11} test incr-2.3 {incr command (not compiled): error compiling variable name} { set z incr set i 10 catch {$z "i"xxx} msg set msg } {extra characters after close-quote} test incr-2.4 {incr command (not compiled): simple variable name in quotes} { set z incr set i 17 list [$z "i"] $i } {18 18} test incr-2.5 {incr command (not compiled): simple variable name in braces} { set z incr catch {unset {a simple var}} set {a simple var} 27 list [$z {a simple var}] ${a simple var} } {28 28} test incr-2.6 {incr command (not compiled): simple array variable name} { set z incr catch {unset a} set a(foo) 37 list [$z a(foo)] $a(foo) } {38 38} test incr-2.7 {incr command (not compiled): non-simple (computed) variable name} { set z incr set x "i" set i 77 list [$z $x 2] $i } {79 79} test incr-2.8 {incr command (not compiled): non-simple (computed) variable name} { set z incr set x "i" set i 77 list [$z [set x] +2] $i } {79 79} test incr-2.9 {incr command (not compiled): increment given} { set z incr set i 10 list [$z i +07] $i } {17 17} test incr-2.10 {incr command (not compiled): no increment given} { set z incr set i 10 list [$z i] $i } {11 11} test incr-2.11 {incr command (not compiled): simple global name} { proc p {} { set z incr global i set i 54 $z i } p } {55} test incr-2.12 {incr command (not compiled): simple local name} { proc p {} { set z incr set foo 100 $z foo } p } {101} test incr-2.13 {incr command (not compiled): simple but new (unknown) local name} { proc p {} { set z incr $z bar } catch {p} msg set msg } {can't read "bar": no such variable} test incr-2.14 {incr command (not compiled): simple local name, >255 locals} { proc 260locals {} { set z incr # create 260 locals set a0 0; set a1 0; set a2 0; set a3 0; set a4 0 set a5 0; set a6 0; set a7 0; set a8 0; set a9 0 set b0 0; set b1 0; set b2 0; set b3 0; set b4 0 set b5 0; set b6 0; set b7 0; set b8 0; set b9 0 set c0 0; set c1 0; set c2 0; set c3 0; set c4 0 set c5 0; set c6 0; set c7 0; set c8 0; set c9 0 set d0 0; set d1 0; set d2 0; set d3 0; set d4 0 set d5 0; set d6 0; set d7 0; set d8 0; set d9 0 set e0 0; set e1 0; set e2 0; set e3 0; set e4 0 set e5 0; set e6 0; set e7 0; set e8 0; set e9 0 set f0 0; set f1 0; set f2 0; set f3 0; set f4 0 set f5 0; set f6 0; set f7 0; set f8 0; set f9 0 set g0 0; set g1 0; set g2 0; set g3 0; set g4 0 set g5 0; set g6 0; set g7 0; set g8 0; set g9 0 set h0 0; set h1 0; set h2 0; set h3 0; set h4 0 set h5 0; set h6 0; set h7 0; set h8 0; set h9 0 set i0 0; set i1 0; set i2 0; set i3 0; set i4 0 set i5 0; set i6 0; set i7 0; set i8 0; set i9 0 set j0 0; set j1 0; set j2 0; set j3 0; set j4 0 set j5 0; set j6 0; set j7 0; set j8 0; set j9 0 set k0 0; set k1 0; set k2 0; set k3 0; set k4 0 set k5 0; set k6 0; set k7 0; set k8 0; set k9 0 set l0 0; set l1 0; set l2 0; set l3 0; set l4 0 set l5 0; set l6 0; set l7 0; set l8 0; set l9 0 set m0 0; set m1 0; set m2 0; set m3 0; set m4 0 set m5 0; set m6 0; set m7 0; set m8 0; set m9 0 set n0 0; set n1 0; set n2 0; set n3 0; set n4 0 set n5 0; set n6 0; set n7 0; set n8 0; set n9 0 set o0 0; set o1 0; set o2 0; set o3 0; set o4 0 set o5 0; set o6 0; set o7 0; set o8 0; set o9 0 set p0 0; set p1 0; set p2 0; set p3 0; set p4 0 set p5 0; set p6 0; set p7 0; set p8 0; set p9 0 set q0 0; set q1 0; set q2 0; set q3 0; set q4 0 set q5 0; set q6 0; set q7 0; set q8 0; set q9 0 set r0 0; set r1 0; set r2 0; set r3 0; set r4 0 set r5 0; set r6 0; set r7 0; set r8 0; set r9 0 set s0 0; set s1 0; set s2 0; set s3 0; set s4 0 set s5 0; set s6 0; set s7 0; set s8 0; set s9 0 set t0 0; set t1 0; set t2 0; set t3 0; set t4 0 set t5 0; set t6 0; set t7 0; set t8 0; set t9 0 set u0 0; set u1 0; set u2 0; set u3 0; set u4 0 set u5 0; set u6 0; set u7 0; set u8 0; set u9 0 set v0 0; set v1 0; set v2 0; set v3 0; set v4 0 set v5 0; set v6 0; set v7 0; set v8 0; set v9 0 set w0 0; set w1 0; set w2 0; set w3 0; set w4 0 set w5 0; set w6 0; set w7 0; set w8 0; set w9 0 set x0 0; set x1 0; set x2 0; set x3 0; set x4 0 set x5 0; set x6 0; set x7 0; set x8 0; set x9 0 set y0 0; set y1 0; set y2 0; set y3 0; set y4 0 set y5 0; set y6 0; set y7 0; set y8 0; set y9 0 set z0 0; set z1 0; set z2 0; set z3 0; set z4 0 set z5 0; set z6 0; set z7 0; set z8 0; set z9 0 # now increment the last one (local var index > 255) $z z9 } 260locals } {1} test incr-2.15 {incr command (not compiled): variable is array} { set z incr catch {unset a} set a(foo) 27 set x [$z a(foo) 11] catch {unset a} set x } 38 test incr-2.16 {incr command (not compiled): variable is array, elem substitutions} { set z incr catch {unset a} set i 5 set a(foo5) 27 set x [$z a(foo$i) 11] catch {unset a} set x } 38 test incr-2.17 {incr command (not compiled): increment given, simple int} { set z incr set i 5 $z i 123 } 128 test incr-2.18 {incr command (not compiled): increment given, simple int} { set z incr set i 5 $z i -100 } -95 test incr-2.19 {incr command (not compiled): increment given, but erroneous} { set z incr set i 5 catch {$z i [set]} msg set errorInfo } {wrong # args: should be "set varName ?newValue?" while compiling "set" while compiling "$z i [set]"} test incr-2.20 {incr command (not compiled): increment given, in quotes} { set z incr set i 25 $z i "-100" } -75 test incr-2.21 {incr command (not compiled): increment given, in braces} { set z incr set i 24 $z i {126} } 150 test incr-2.22 {incr command (not compiled): increment given, large int} { set z incr set i 5 $z i 200000 } 200005 test incr-2.23 {incr command (not compiled): increment given, formatted int != int} { set z incr set i 25 $z i 000012345 ;# an octal literal } 5374 test incr-2.24 {incr command (not compiled): increment given, formatted int != int} { set z incr set i 25 catch {$z i 1a} msg set msg } {expected integer but got "1a"} test incr-2.25 {incr command (not compiled): too many arguments} { set z incr set i 10 catch {$z i 10 20} msg set msg } {wrong # args: should be "incr varName ?increment?"} test incr-2.26 {incr command (not compiled): runtime error, bad variable name} { set z incr list [catch {$z {"foo}} msg] $msg $errorInfo } {1 {can't read ""foo": no such variable} {can't read ""foo": no such variable (reading value of variable to increment) invoked from within "$z {"foo}"}} test incr-2.27 {incr command (not compiled): runtime error, bad variable name} { set z incr list [catch {$z [set]} msg] $msg $errorInfo } {1 {wrong # args: should be "set varName ?newValue?"} {wrong # args: should be "set varName ?newValue?" while compiling "set" while compiling "$z [set]"}} test incr-2.28 {incr command (not compiled): runtime error, readonly variable} { set z incr proc readonly args {error "variable is read-only"} set x 123 trace var x w readonly list [catch {$z x 1} msg] $msg $errorInfo } {1 {can't set "x": variable is read-only} {can't set "x": variable is read-only while executing "$z x 1"}} catch {unset x} test incr-2.29 {incr command (not compiled): runtime error, bad variable value} { set z incr set x " - " list [catch {$z x 1} msg] $msg } {1 {expected integer but got " - "}} test incr-2.30 {incr command (not compiled): bad increment} { set z incr set x 0 list [catch {$z x 1a} msg] $msg $errorInfo } {1 {expected integer but got "1a"} {expected integer but got "1a" (reading increment) invoked from within "$z x 1a"}} test incr-2.31 {incr command (compiled): bad increment} { list [catch {incr x 1a} msg] $msg $errorInfo } {1 {expected integer but got "1a"} {expected integer but got "1a" (reading increment) invoked from within "incr x 1a"}} # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/thread.test0000644003604700454610000001654011737050674014237 0ustar dgp771div# Commands covered: (test)thread # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1996 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } # Some tests require the testthread command set ::tcltest::testConstraints(testthread) \ [expr {[info commands testthread] != {}}] if {$::tcltest::testConstraints(testthread)} { testthread errorproc ThreadError proc ThreadError {id info} { global threadError set threadError $info } proc ThreadNullError {id info} { # ignore } } test thread-1.1 {Tcl_ThreadObjCmd: no args} {testthread} { list [catch {testthread} msg] $msg } {1 {wrong # args: should be "testthread option ?args?"}} test thread-1.2 {Tcl_ThreadObjCmd: bad option} {testthread} { list [catch {testthread foo} msg] $msg } {1 {bad option "foo": must be create, exit, id, join, names, send, wait, or errorproc}} test thread-1.3 {Tcl_ThreadObjCmd: initial thread list} {testthread} { list [threadReap] [llength [testthread names]] } {1 1} test thread-1.4 {Tcl_ThreadObjCmd: thread create } {testthread} { threadReap set serverthread [testthread create] update set numthreads [llength [testthread names]] threadReap set numthreads } {2} test thread-1.5 {Tcl_ThreadObjCmd: thread create one shot} {testthread} { threadReap testthread create {set x 5} foreach try {0 1 2 4 5 6} { # Try various ways to yield update after 10 set l [llength [testthread names]] if {$l == 1} { break } } threadReap set l } {1} test thread-1.6 {Tcl_ThreadObjCmd: thread exit} {testthread} { threadReap testthread create {testthread exit} update after 10 set result [llength [testthread names]] threadReap set result } {1} test thread-1.7 {Tcl_ThreadObjCmd: thread id args} {testthread} { set x [catch {testthread id x} msg] list $x $msg } {1 {wrong # args: should be "testthread id"}} test thread-1.8 {Tcl_ThreadObjCmd: thread id} {testthread} { string compare [testthread id] $::tcltest::mainThread } {0} test thread-1.9 {Tcl_ThreadObjCmd: thread names args} {testthread} { set x [catch {testthread names x} msg] list $x $msg } {1 {wrong # args: should be "testthread names"}} test thread-1.10 {Tcl_ThreadObjCmd: thread id} {testthread} { string compare [testthread names] $::tcltest::mainThread } {0} test thread-1.11 {Tcl_ThreadObjCmd: send args} {testthread} { set x [catch {testthread send} msg] list $x $msg } {1 {wrong # args: should be "testthread send ?-async? id script"}} test thread-1.12 {Tcl_ThreadObjCmd: send nonint} {testthread} { set x [catch {testthread send abc command} msg] list $x $msg } {1 {expected integer but got "abc"}} test thread-1.13 {Tcl_ThreadObjCmd: send args} {testthread} { threadReap set serverthread [testthread create] set five [testthread send $serverthread {set x 5}] threadReap set five } 5 test thread-1.14 {Tcl_ThreadObjCmd: send bad id} {testthread} { set tid [expr $::tcltest::mainThread + 10] set x [catch {testthread send $tid {set x 5}} msg] list $x $msg } {1 {invalid thread id}} test thread-1.15 {Tcl_ThreadObjCmd: wait} {testthread} { threadReap set serverthread [testthread create {set z 5 ; testthread wait}] set five [testthread send $serverthread {set z}] threadReap set five } 5 test thread-1.16 {Tcl_ThreadObjCmd: errorproc args} {testthread} { set x [catch {testthread errorproc foo bar} msg] list $x $msg } {1 {wrong # args: should be "testthread errorproc proc"}} test thread-1.17 {Tcl_ThreadObjCmd: errorproc change} {testthread} { testthread errorproc foo testthread errorproc ThreadError } {} # The tests above also cover: # TclCreateThread, except when pthread_create fails # NewThread, safe and regular # ThreadErrorProc, except for printing to standard error test thread-2.1 {ListUpdateInner and ListRemove} {testthread} { threadReap catch {unset tid} foreach t {0 1 2} { upvar #0 t$t tid set tid [testthread create] } threadReap } 1 test thread-3.1 {TclThreadList} {testthread} { threadReap catch {unset tid} set len [llength [testthread names]] set l1 {} foreach t {0 1 2} { lappend l1 [testthread create] } set l2 [testthread names] list $l1 $l2 set c [string compare \ [lsort -integer [concat $::tcltest::mainThread $l1]] \ [lsort -integer $l2]] threadReap list $len $c } {1 0} test thread-4.1 {TclThreadSend to self} {testthread} { catch {unset x} testthread send [testthread id] { set x 4 } set x } {4} test thread-4.2 {TclThreadSend -async} {testthread} { threadReap set len [llength [testthread names]] set serverthread [testthread create] testthread send -async $serverthread { after 1000 testthread exit } set two [llength [testthread names]] after 1500 {set done 1} vwait done threadReap list $len [llength [testthread names]] $two } {1 1 2} test thread-4.3 {TclThreadSend preserve errorInfo} {testthread} { threadReap set len [llength [testthread names]] set serverthread [testthread create] set x [catch {testthread send $serverthread {set undef}} msg] set savedErrorInfo $errorInfo threadReap list $len $x $msg $savedErrorInfo } {1 1 {can't read "undef": no such variable} {can't read "undef": no such variable while executing "set undef" invoked from within "testthread send $serverthread {set undef}"}} test thread-4.4 {TclThreadSend preserve code} {testthread} { threadReap set len [llength [testthread names]] set serverthread [testthread create] set x [catch {testthread send $serverthread {break}} msg] set savedErrorInfo $errorInfo threadReap list $len $x $msg $savedErrorInfo } {1 3 {} {}} test thread-4.5 {TclThreadSend preserve errorCode} {testthread} { threadReap set ::tcltest::mainThread [testthread names] set serverthread [testthread create] set x [catch {testthread send $serverthread {error ERR INFO CODE}} msg] set savedErrorCode $errorCode threadReap list $x $msg $savedErrorCode } {1 ERR CODE} test thread-5.0 {Joining threads} {testthread} { threadReap set serverthread [testthread create -joinable] testthread send -async $serverthread {after 1000 ; testthread exit} set res [testthread join $serverthread] threadReap set res } {0} test thread-5.1 {Joining threads after the fact} {testthread} { threadReap set serverthread [testthread create -joinable] testthread send -async $serverthread {testthread exit} after 2000 set res [testthread join $serverthread] threadReap set res } {0} test thread-5.2 {Try to join a detached thread} {testthread} { threadReap set serverthread [testthread create] testthread send -async $serverthread {after 1000 ; testthread exit} catch {set res [testthread join $serverthread]} msg threadReap lrange $msg 0 2 } {cannot join thread} # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/package.test0000644003604700454610000000732411737050674014363 0ustar dgp771div# This file contains tests for the ::package::* commands. # Note that the tests are limited to Tcl scripts only, there are no shared # libraries against which to test. # # Sourcing this file into Tcl runs the tests and generates output for # errors. No output means no errors were found. # # Copyright (c) 1998-1999 by Scriptics Corporation. # All rights reserved. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } test package-1.1 {pkg::create gives error on insufficient args} { catch {::pkg::create} } 1 test package-1.2 {pkg::create gives error on bad args} { catch {::pkg::create -foo bar -bar baz -baz boo} } 1 test package-1.3 {pkg::create gives error on no value given} { catch {::pkg::create -name foo -version 1.0 -source test.tcl -load} } 1 test package-1.4 {pkg::create gives error on no name given} { catch {::pkg::create -version 1.0 -source test.tcl -load foo.so} } 1 test package-1.5 {pkg::create gives error on no version given} { catch {::pkg::create -name foo -source test.tcl -load foo.so} } 1 test package-1.6 {pkg::create gives error on no source or load options} { catch {::pkg::create -name foo -version 1.0 -version 2.0} } 1 test package-1.7 {pkg::create gives correct output for 1 direct source} { ::pkg::create -name foo -version 1.0 -source test.tcl } {package ifneeded foo 1.0 [list source [file join $dir test.tcl]]} test package-1.8 {pkg::create gives correct output for 2 direct sources} { ::pkg::create -name foo -version 1.0 -source test.tcl -source test2.tcl } {package ifneeded foo 1.0 [list source [file join $dir test.tcl]]\n[list source [file join $dir test2.tcl]]} test package-1.9 {pkg::create gives correct output for 1 direct load} { ::pkg::create -name foo -version 1.0 -load test.so } {package ifneeded foo 1.0 [list load [file join $dir test.so]]} test package-1.10 {pkg::create gives correct output for 2 direct loads} { ::pkg::create -name foo -version 1.0 -load test.so -load test2.so } {package ifneeded foo 1.0 [list load [file join $dir test.so]]\n[list load [file join $dir test2.so]]} test package-1.11 {pkg::create gives correct output for 1 lazy source} { ::pkg::create -name foo -version 1.0 -source {test.tcl {foo bar}} } {package ifneeded foo 1.0 [list tclPkgSetup $dir foo 1.0 {{test.tcl source {foo bar}}}]} test package-1.12 {pkg::create gives correct output for 2 lazy sources} { ::pkg::create -name foo -version 1.0 -source {test.tcl {foo bar}} \ -source {test2.tcl {baz boo}} } {package ifneeded foo 1.0 [list tclPkgSetup $dir foo 1.0 {{test.tcl source {foo bar}} {test2.tcl source {baz boo}}}]} test package-1.13 {pkg::create gives correct output for 1 lazy load} { ::pkg::create -name foo -version 1.0 -load {test.so {foo bar}} } {package ifneeded foo 1.0 [list tclPkgSetup $dir foo 1.0 {{test.so load {foo bar}}}]} test package-1.14 {pkg::create gives correct output for 2 lazy loads} { ::pkg::create -name foo -version 1.0 -load {test.so {foo bar}} \ -load {test2.so {baz boo}} } {package ifneeded foo 1.0 [list tclPkgSetup $dir foo 1.0 {{test.so load {foo bar}} {test2.so load {baz boo}}}]} test package-1.15 {pkg::create gives correct output for 1 each, direct} { ::pkg::create -name foo -version 1.0 -source test.tcl -load test2.so } {package ifneeded foo 1.0 [list load [file join $dir test2.so]]\n[list source [file join $dir test.tcl]]} test package-1.16 {pkg::create gives correct output for 1 direct, 1 lazy} { ::pkg::create -name foo -version 1.0 -source test.tcl \ -source {test2.tcl {foo bar}} } {package ifneeded foo 1.0 [list source [file join $dir test.tcl]]\n[list tclPkgSetup $dir foo 1.0 {{test2.tcl source {foo bar}}}]} ::tcltest::cleanupTests return tcl8.4.20/tests/lsearch.test0000644003604700454610000002755111737050674014415 0ustar dgp771div# Commands covered: lsearch # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } set x {abcd bbcd 123 234 345} test lsearch-1.1 {lsearch command} { lsearch $x 123 } 2 test lsearch-1.2 {lsearch command} { lsearch $x 3456 } -1 test lsearch-1.3 {lsearch command} { lsearch $x *5 } 4 test lsearch-1.4 {lsearch command} { lsearch $x *bc* } 0 test lsearch-2.1 {search modes} { lsearch -exact {xyz bbcc *bc*} *bc* } 2 test lsearch-2.2 {search modes} { lsearch -exact {b.x ^bc xy bcx} ^bc } 1 test lsearch-2.3 {search modes} { lsearch -exact {foo bar cat} ba } -1 test lsearch-2.4 {search modes} { lsearch -exact {foo bar cat} bart } -1 test lsearch-2.5 {search modes} { lsearch -exact {foo bar cat} bar } 1 test lsearch-2.6 {search modes} { list [catch {lsearch -regexp {xyz bbcc *bc*} *bc*} msg] $msg } {1 {couldn't compile regular expression pattern: quantifier operand invalid}} test lsearch-2.7 {search modes} { lsearch -regexp {b.x ^bc xy bcx} ^bc } 3 test lsearch-2.8 {search modes} { lsearch -glob {xyz bbcc *bc*} *bc* } 1 test lsearch-2.9 {search modes} { lsearch -glob {b.x ^bc xy bcx} ^bc } 1 test lsearch-2.10 {search modes} { list [catch {lsearch -glib {b.x bx xy bcx} b.x} msg] $msg } {1 {bad option "-glib": must be -all, -ascii, -decreasing, -dictionary, -exact, -glob, -increasing, -inline, -integer, -not, -real, -regexp, -sorted, or -start}} test lsearch-3.1 {lsearch errors} { list [catch lsearch msg] $msg } {1 {wrong # args: should be "lsearch ?options? list pattern"}} test lsearch-3.2 {lsearch errors} { list [catch {lsearch a} msg] $msg } {1 {wrong # args: should be "lsearch ?options? list pattern"}} test lsearch-3.3 {lsearch errors} { list [catch {lsearch a b c} msg] $msg } {1 {bad option "a": must be -all, -ascii, -decreasing, -dictionary, -exact, -glob, -increasing, -inline, -integer, -not, -real, -regexp, -sorted, or -start}} test lsearch-3.4 {lsearch errors} { list [catch {lsearch a b c d} msg] $msg } {1 {bad option "a": must be -all, -ascii, -decreasing, -dictionary, -exact, -glob, -increasing, -inline, -integer, -not, -real, -regexp, -sorted, or -start}} test lsearch-3.5 {lsearch errors} { list [catch {lsearch "\{" b} msg] $msg } {1 {unmatched open brace in list}} test lsearch-4.1 {binary data} { lsearch -exact [list foo one\000two bar] bar } 2 test lsearch-4.2 {binary data} { set x one append x \x00 append x two lsearch -exact [list foo one\000two bar] $x } 1 # Make a sorted list set l {} set l2 {} for {set i 0} {$i < 100} {incr i} { lappend l $i lappend l2 [expr {double($i)/2}] } set increasingIntegers [lsort -integer $l] set decreasingIntegers [lsort -decreasing -integer $l] set increasingDoubles [lsort -real $l2] set decreasingDoubles [lsort -decreasing -real $l2] set increasingStrings [lsort {48 6a 18b 22a 21aa 35 36}] set decreasingStrings [lsort -decreasing {48 6a 18b 22a 21aa 35 36}] set increasingDictionary [lsort -dictionary {48 6a 18b 22a 21aa 35 36}] set decreasingDictionary [lsort -dictionary -decreasing $increasingDictionary] set l {} for {set i 0} {$i < 10} {incr i} { lappend l $i $i $i $i $i } set repeatingIncreasingIntegers [lsort -integer $l] set repeatingDecreasingIntegers [lsort -integer -decreasing $l] test lsearch-5.1 {binary search} { set res {} for {set i 0} {$i < 100} {incr i} { lappend res [lsearch -integer -sorted $increasingIntegers $i] } set res } $increasingIntegers test lsearch-5.2 {binary search} { set res {} for {set i 0} {$i < 100} {incr i} { lappend res [lsearch -integer -decreasing -sorted \ $decreasingIntegers $i] } set res } $decreasingIntegers test lsearch-5.3 {binary search finds leftmost occurances} { set res {} for {set i 0} {$i < 10} {incr i} { lappend res [lsearch -integer -sorted $repeatingIncreasingIntegers $i] } set res } [list 0 5 10 15 20 25 30 35 40 45] test lsearch-5.4 {binary search -decreasing finds leftmost occurances} { set res {} for {set i 9} {$i >= 0} {incr i -1} { lappend res [lsearch -sorted -integer -decreasing \ $repeatingDecreasingIntegers $i] } set res } [list 0 5 10 15 20 25 30 35 40 45] test lsearch-6.1 {integer search} { set res {} for {set i 0} {$i < 100} {incr i} { lappend res [lsearch -exact -integer $increasingIntegers $i] } set res } [lrange $increasingIntegers 0 99] test lsearch-6.2 {decreasing integer search} { set res {} for {set i 0} {$i < 100} {incr i} { lappend res [lsearch -exact -integer -decreasing \ $decreasingIntegers $i] } set res } [lrange $decreasingIntegers 0 99] test lsearch-6.3 {sorted integer search} { set res {} for {set i 0} {$i < 100} {incr i} { lappend res [lsearch -sorted -integer $increasingIntegers $i] } set res } [lrange $increasingIntegers 0 99] test lsearch-6.4 {sorted decreasing integer search} { set res {} for {set i 0} {$i < 100} {incr i} { lappend res [lsearch -integer -sorted -decreasing \ $decreasingIntegers $i] } set res } [lrange $decreasingIntegers 0 99] test lsearch-7.1 {double search} { set res {} for {set i 0} {$i < 100} {incr i} { lappend res [lsearch -exact -real $increasingDoubles \ [expr {double($i)/2}]] } set res } [lrange $increasingIntegers 0 99] test lsearch-7.2 {decreasing double search} { set res {} for {set i 0} {$i < 100} {incr i} { lappend res [lsearch -exact -real -decreasing \ $decreasingDoubles [expr {double($i)/2}]] } set res } [lrange $decreasingIntegers 0 99] test lsearch-7.3 {sorted double search} { set res {} for {set i 0} {$i < 100} {incr i} { lappend res [lsearch -sorted -real \ $increasingDoubles [expr {double($i)/2}]] } set res } [lrange $increasingIntegers 0 99] test lsearch-7.4 {sorted decreasing double search} { set res {} for {set i 0} {$i < 100} {incr i} { lappend res [lsearch -sorted -real -decreasing \ $decreasingDoubles [expr {double($i)/2}]] } set res } [lrange $decreasingIntegers 0 99] test lsearch-8.1 {dictionary search} { set res {} foreach val {6a 18b 21aa 22a 35 36 48} { lappend res [lsearch -exact -dictionary $increasingDictionary $val] } set res } [list 0 1 2 3 4 5 6] test lsearch-8.2 {decreasing dictionary search} { set res {} foreach val {6a 18b 21aa 22a 35 36 48} { lappend res [lsearch -exact -dictionary $decreasingDictionary $val] } set res } [list 6 5 4 3 2 1 0] test lsearch-8.3 {sorted dictionary search} { set res {} foreach val {6a 18b 21aa 22a 35 36 48} { lappend res [lsearch -sorted -dictionary $increasingDictionary $val] } set res } [list 0 1 2 3 4 5 6] test lsearch-8.4 {decreasing sorted dictionary search} { set res {} foreach val {6a 18b 21aa 22a 35 36 48} { lappend res [lsearch -decreasing -sorted -dictionary \ $decreasingDictionary $val] } set res } [list 6 5 4 3 2 1 0] test lsearch-9.1 {ascii search} { set res {} foreach val {18b 21aa 22a 35 36 48 6a} { lappend res [lsearch -exact -ascii $increasingStrings $val] } set res } [list 0 1 2 3 4 5 6] test lsearch-9.2 {decreasing ascii search} { set res {} foreach val {18b 21aa 22a 35 36 48 6a} { lappend res [lsearch -exact -ascii $decreasingStrings $val] } set res } [list 6 5 4 3 2 1 0] test lsearch-9.3 {sorted ascii search} { set res {} foreach val {18b 21aa 22a 35 36 48 6a} { lappend res [lsearch -sorted -ascii $increasingStrings $val] } set res } [list 0 1 2 3 4 5 6] test lsearch-9.4 {decreasing sorted ascii search} { set res {} foreach val {18b 21aa 22a 35 36 48 6a} { lappend res [lsearch -decreasing -sorted -ascii \ $decreasingStrings $val] } set res } [list 6 5 4 3 2 1 0] test lsearch-10.1 {offset searching} { lsearch -start 2 {a b c a b c} a } 3 test lsearch-10.2 {offset searching} { lsearch -start 2 {a b c d e f} a } -1 test lsearch-10.3 {offset searching} { lsearch -start end-4 {a b c a b c} a } 3 test lsearch-10.4 {offset searching} { list [catch {lsearch -start foobar {a b c a b c} a} msg] $msg } {1 {bad index "foobar": must be integer or end?-integer?}} test lsearch-10.5 {offset searching} { list [catch {lsearch -start 1 2} msg] $msg } {1 {missing starting index}} test lsearch-10.6 {binary search with offset} { set res {} for {set i 0} {$i < 100} {incr i} { lappend res [lsearch -integer -start 2 -sorted $increasingIntegers $i] } set res } [concat -1 -1 [lrange $increasingIntegers 2 end]] test lsearch-10.7 {offset searching with an empty list} { # Stop bug #694232 from reocurring lsearch -start 0 {} x } -1 test lsearch-10.8 {offset searching past the end of the list} { # Stop [Bug 1374778] from reoccurring lsearch -start 10 {a b c} c } -1 test lsearch-10.9 {offset searching past the end of the list} { # Stop [Bug 1374778] from reoccurring lsearch -start 10 -all {a b c} c } {} test lsearch-10.10 {offset searching past the end of the list} { # Stop [Bug 1374778] from reoccurring lsearch -start 10 -inline {a b c} c } {} test lsearch-11.1 {negated searches} { lsearch -not {a a a b a a a} a } 3 test lsearch-11.2 {negated searches} { lsearch -not {a a a a a a a} a } -1 test lsearch-12.1 {return values instead of indices} { lsearch -glob -inline {a1 b2 c3 d4} c* } c3 test lsearch-12.2 {return values instead of indices} { lsearch -glob -inline {a1 b2 c3 d4} e* } {} test lsearch-13.1 {search for all matches} { lsearch -all {a b a c a d} 1 } {} test lsearch-13.2 {search for all matches} { lsearch -all {a b a c a d} a } {0 2 4} test lsearch-14.1 {combinations: -all and -inline} { lsearch -all -inline -glob {a1 b2 a3 c4 a5 d6} a* } {a1 a3 a5} test lsearch-14.2 {combinations: -all, -inline and -not} { lsearch -all -inline -not -glob {a1 b2 a3 c4 a5 d6} a* } {b2 c4 d6} test lsearch-14.3 {combinations: -all and -not} { lsearch -all -not -glob {a1 b2 a3 c4 a5 d6} a* } {1 3 5} test lsearch-14.4 {combinations: -inline and -not} { lsearch -inline -not -glob {a1 b2 a3 c4 a5 d6} a* } {b2} test lsearch-14.5 {combinations: -start, -all and -inline} { lsearch -start 2 -all -inline -glob {a1 b2 a3 c4 a5 d6} a* } {a3 a5} test lsearch-14.6 {combinations: -start, -all, -inline and -not} { lsearch -start 2 -all -inline -not -glob {a1 b2 a3 c4 a5 d6} a* } {c4 d6} test lsearch-14.7 {combinations: -start, -all and -not} { lsearch -start 2 -all -not -glob {a1 b2 a3 c4 a5 d6} a* } {3 5} test lsearch-14.8 {combinations: -start, -inline and -not} { lsearch -start 2 -inline -not -glob {a1 b2 a3 c4 a5 d6} a* } {c4} test lsearch-15.1 {make sure no shimmering occurs} { set x [expr int(sin(0))] lsearch -start $x $x $x } 0 test lsearch-16.1 {lsearch -regexp shared object} { set str a lsearch -regexp $str $str } 0 # Bug 1366683 test lsearch-16.2 {lsearch -regexp allows internal backrefs} { lsearch -regexp {a aa b} {(.)\1} } 1 test lsearch-21.1 {lsearch shimmering crash} { set x 0 lsearch -exact -integer $x $x } 0 test lsearch-21.2 {lsearch shimmering crash} { set x 0.5 lsearch -exact -real $x $x } 0 # cleanup catch {unset res} catch {unset increasingIntegers} catch {unset decreasingIntegers} catch {unset increasingDoubles} catch {unset decreasingDoubles} catch {unset increasingStrings} catch {unset decreasingStrings} catch {unset increasingDictionary} catch {unset decreasingDictionary} ::tcltest::cleanupTests return tcl8.4.20/tests/foreach.test0000644003604700454610000001505011737050674014372 0ustar dgp771div# Commands covered: foreach, continue, break # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994-1997 Sun Microsystems, Inc. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } catch {unset a} catch {unset x} # Basic "foreach" operation. test foreach-1.1 {basic foreach tests} { set a {} foreach i {a b c d} { set a [concat $a $i] } set a } {a b c d} test foreach-1.2 {basic foreach tests} { set a {} foreach i {a b {{c d} e} {123 {{x}}}} { set a [concat $a $i] } set a } {a b {c d} e 123 {{x}}} test foreach-1.3 {basic foreach tests} {catch {foreach} msg} 1 test foreach-1.4 {basic foreach tests} { catch {foreach} msg set msg } {wrong # args: should be "foreach varList list ?varList list ...? command"} test foreach-1.5 {basic foreach tests} {catch {foreach i} msg} 1 test foreach-1.6 {basic foreach tests} { catch {foreach i} msg set msg } {wrong # args: should be "foreach varList list ?varList list ...? command"} test foreach-1.7 {basic foreach tests} {catch {foreach i j} msg} 1 test foreach-1.8 {basic foreach tests} { catch {foreach i j} msg set msg } {wrong # args: should be "foreach varList list ?varList list ...? command"} test foreach-1.9 {basic foreach tests} {catch {foreach i j k l} msg} 1 test foreach-1.10 {basic foreach tests} { catch {foreach i j k l} msg set msg } {wrong # args: should be "foreach varList list ?varList list ...? command"} test foreach-1.11 {basic foreach tests} { set a {} foreach i {} { set a [concat $a $i] } set a } {} test foreach-1.12 {foreach errors} { list [catch {foreach {{a}{b}} {1 2 3} {}} msg] $msg } {1 {list element in braces followed by "{b}" instead of space}} test foreach-1.13 {foreach errors} { list [catch {foreach a {{1 2}3} {}} msg] $msg } {1 {list element in braces followed by "3" instead of space}} catch {unset a} test foreach-1.14 {foreach errors} { catch {unset a} set a(0) 44 list [catch {foreach a {1 2 3} {}} msg] $msg } {1 {couldn't set loop variable: "a"}} test foreach-1.15 {foreach errors} { list [catch {foreach {} {} {}} msg] $msg } {1 {foreach varlist is empty}} catch {unset a} test foreach-2.1 {parallel foreach tests} { set x {} foreach {a b} {1 2 3 4} { append x $b $a } set x } {2143} test foreach-2.2 {parallel foreach tests} { set x {} foreach {a b} {1 2 3 4 5} { append x $b $a } set x } {21435} test foreach-2.3 {parallel foreach tests} { set x {} foreach a {1 2 3} b {4 5 6} { append x $b $a } set x } {415263} test foreach-2.4 {parallel foreach tests} { set x {} foreach a {1 2 3} b {4 5 6 7 8} { append x $b $a } set x } {41526378} test foreach-2.5 {parallel foreach tests} { set x {} foreach {a b} {a b A B aa bb} c {c C cc CC} { append x $a $b $c } set x } {abcABCaabbccCC} test foreach-2.6 {parallel foreach tests} { set x {} foreach a {1 2 3} b {1 2 3} c {1 2 3} d {1 2 3} e {1 2 3} { append x $a $b $c $d $e } set x } {111112222233333} test foreach-2.7 {parallel foreach tests} { set x {} foreach a {} b {1 2 3} c {1 2} d {1 2 3 4} e {{1 2}} { append x $a $b $c $d $e } set x } {1111 2222334} test foreach-2.8 {foreach only sets vars if repeating loop} { proc foo {} { set rgb {65535 0 0} foreach {r g b} [set rgb] {} return "r=$r, g=$g, b=$b" } foo } {r=65535, g=0, b=0} test foreach-2.9 {foreach only supports local scalar variables} { proc foo {} { set x {} foreach {a(3)} {1 2 3 4} {lappend x [set {a(3)}]} set x } foo } {1 2 3 4} test foreach-3.1 {compiled foreach backward jump works correctly} { catch {unset x} proc foo {arrayName} { upvar 1 $arrayName a set l {} foreach member [array names a] { lappend l [list $member [set a($member)]] } return $l } array set x {0 zero 1 one 2 two 3 three} lsort [foo x] } [lsort {{0 zero} {1 one} {2 two} {3 three}}] test foreach-4.1 {noncompiled foreach and shared variable or value list objects that are converted to another type} { catch {unset x} foreach {12.0} {a b c} { set x 12.0 set x [expr $x + 1] } set x } 13.0 # Check "continue". test foreach-5.1 {continue tests} {catch continue} 4 test foreach-5.2 {continue tests} { set a {} foreach i {a b c d} { if {[string compare $i "b"] == 0} continue set a [concat $a $i] } set a } {a c d} test foreach-5.3 {continue tests} { set a {} foreach i {a b c d} { if {[string compare $i "b"] != 0} continue set a [concat $a $i] } set a } {b} test foreach-5.4 {continue tests} {catch {continue foo} msg} 1 test foreach-5.5 {continue tests} { catch {continue foo} msg set msg } {wrong # args: should be "continue"} # Check "break". test foreach-6.1 {break tests} {catch break} 3 test foreach-6.2 {break tests} { set a {} foreach i {a b c d} { if {[string compare $i "c"] == 0} break set a [concat $a $i] } set a } {a b} test foreach-6.3 {break tests} {catch {break foo} msg} 1 test foreach-6.4 {break tests} { catch {break foo} msg set msg } {wrong # args: should be "break"} # Check for bug #406709 test foreach-6.5 {break tests} { proc a {} { set a 1 foreach b b {list [concat a; break]; incr a} incr a } a } {2} # Test for incorrect "double evaluation" semantics test foreach-7.1 {delayed substitution of body} { proc foo {} { set a 0 foreach a [list 1 2 3] " set x $a " set x } foo } {0} # [Bug 1671138]; infinite loop with empty var list in bytecompiled version test foreach-9.1 {compiled empty var list} { proc foo {} { foreach {} x { error "reached body" } } list [catch { foo } msg] $msg } {1 {foreach varlist is empty}} test foreach-10.1 {foreach: [Bug 1671087]} -setup { proc demo {} { set vals {1 2 3 4} trace add variable x write {string length $vals ;# } foreach {x y} $vals {format $y} } } -body { demo } -cleanup { rename demo {} } -result {} # cleanup catch {unset a} catch {unset x} ::tcltest::cleanupTests return tcl8.4.20/tests/expr-old.test0000644003604700454610000012161711737050674014524 0ustar dgp771div# Commands covered: expr # # This file contains the original set of tests for Tcl's expr command. # Since the expr command is now compiled, a new set of tests covering # the new implementation are in the files "parseExpr.test" and # "compExpr.test". Sourcing this file into Tcl runs the tests and generates # output for errors. No output means no errors were found. # # Copyright (c) 1991-1994 The Regents of the University of California. # Copyright (c) 1994-1997 Sun Microsystems, Inc. # Copyright (c) 1998-2000 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2.1 namespace import -force ::tcltest::* } if {([catch {expr T1()} msg] == 1) && ($msg == {unknown math function "T1"})} { set gotT1 0 puts "This application hasn't been compiled with the \"T1\" and" puts "\"T2\" math functions, so I'll skip some of the expr tests." } else { set gotT1 1 } # First, test all of the integer operators individually. test expr-old-1.1 {integer operators} {expr -4} -4 test expr-old-1.2 {integer operators} {expr -(1+4)} -5 test expr-old-1.3 {integer operators} {expr ~3} -4 test expr-old-1.4 {integer operators} {expr !2} 0 test expr-old-1.5 {integer operators} {expr !0} 1 test expr-old-1.6 {integer operators} {expr 4*6} 24 test expr-old-1.7 {integer operators} {expr 36/12} 3 test expr-old-1.8 {integer operators} {expr 27/4} 6 test expr-old-1.9 {integer operators} {expr 27%4} 3 test expr-old-1.10 {integer operators} {expr 2+2} 4 test expr-old-1.11 {integer operators} {expr 2-6} -4 test expr-old-1.12 {integer operators} {expr 1<<3} 8 test expr-old-1.13 {integer operators} {expr 0xff>>2} 63 test expr-old-1.14 {integer operators} {expr -1>>2} -1 test expr-old-1.15 {integer operators} {expr 3>2} 1 test expr-old-1.16 {integer operators} {expr 2>2} 0 test expr-old-1.17 {integer operators} {expr 1>2} 0 test expr-old-1.18 {integer operators} {expr 3<2} 0 test expr-old-1.19 {integer operators} {expr 2<2} 0 test expr-old-1.20 {integer operators} {expr 1<2} 1 test expr-old-1.21 {integer operators} {expr 3>=2} 1 test expr-old-1.22 {integer operators} {expr 2>=2} 1 test expr-old-1.23 {integer operators} {expr 1>=2} 0 test expr-old-1.24 {integer operators} {expr 3<=2} 0 test expr-old-1.25 {integer operators} {expr 2<=2} 1 test expr-old-1.26 {integer operators} {expr 1<=2} 1 test expr-old-1.27 {integer operators} {expr 3==2} 0 test expr-old-1.28 {integer operators} {expr 2==2} 1 test expr-old-1.29 {integer operators} {expr 3!=2} 1 test expr-old-1.30 {integer operators} {expr 2!=2} 0 test expr-old-1.31 {integer operators} {expr 7&0x13} 3 test expr-old-1.32 {integer operators} {expr 7^0x13} 20 test expr-old-1.33 {integer operators} {expr 7|0x13} 23 test expr-old-1.34 {integer operators} {expr 0&&1} 0 test expr-old-1.35 {integer operators} {expr 0&&0} 0 test expr-old-1.36 {integer operators} {expr 1&&3} 1 test expr-old-1.37 {integer operators} {expr 0||1} 1 test expr-old-1.38 {integer operators} {expr 3||0} 1 test expr-old-1.39 {integer operators} {expr 0||0} 0 test expr-old-1.40 {integer operators} {expr 3>2?44:66} 44 test expr-old-1.41 {integer operators} {expr 2>3?44:66} 66 test expr-old-1.42 {integer operators} {expr 36/5} 7 test expr-old-1.43 {integer operators} {expr 36%5} 1 test expr-old-1.44 {integer operators} {expr -36/5} -8 test expr-old-1.45 {integer operators} {expr -36%5} 4 test expr-old-1.46 {integer operators} {expr 36/-5} -8 test expr-old-1.47 {integer operators} {expr 36%-5} -4 test expr-old-1.48 {integer operators} {expr -36/-5} 7 test expr-old-1.49 {integer operators} {expr -36%-5} -1 test expr-old-1.50 {integer operators} {expr +36} 36 test expr-old-1.51 {integer operators} {expr +--++36} 36 test expr-old-1.52 {integer operators} {expr +36%+5} 1 test expr-old-1.53 {integer operators} { catch {unset x} set x yes list [expr {1 && $x}] [expr {$x && 1}] \ [expr {0 || $x}] [expr {$x || 0}] } {1 1 1 1} # Check the floating-point operators individually, along with # automatic conversion to integers where needed. test expr-old-2.1 {floating-point operators} {expr -4.2} -4.2 test expr-old-2.2 {floating-point operators} {expr -(1.1+4.2)} -5.3 test expr-old-2.3 {floating-point operators} {expr +5.7} 5.7 test expr-old-2.4 {floating-point operators} {expr +--+-62.0} -62.0 test expr-old-2.5 {floating-point operators} {expr !2.1} 0 test expr-old-2.6 {floating-point operators} {expr !0.0} 1 test expr-old-2.7 {floating-point operators} {expr 4.2*6.3} 26.46 test expr-old-2.8 {floating-point operators} {expr 36.0/12.0} 3.0 test expr-old-2.9 {floating-point operators} {expr 27/4.0} 6.75 test expr-old-2.10 {floating-point operators} {expr 2.3+2.1} 4.4 test expr-old-2.11 {floating-point operators} {expr 2.3-6.5} -4.2 test expr-old-2.12 {floating-point operators} {expr 3.1>2.1} 1 test expr-old-2.13 {floating-point operators} {expr {2.1 > 2.1}} 0 test expr-old-2.14 {floating-point operators} {expr 1.23>2.34e+1} 0 test expr-old-2.15 {floating-point operators} {expr 3.45<2.34} 0 test expr-old-2.16 {floating-point operators} {expr 0.002e3<--200e-2} 0 test expr-old-2.17 {floating-point operators} {expr 1.1<2.1} 1 test expr-old-2.18 {floating-point operators} {expr 3.1>=2.2} 1 test expr-old-2.19 {floating-point operators} {expr 2.345>=2.345} 1 test expr-old-2.20 {floating-point operators} {expr 1.1>=2.2} 0 test expr-old-2.21 {floating-point operators} {expr 3.0<=2.0} 0 test expr-old-2.22 {floating-point operators} {expr 2.2<=2.2} 1 test expr-old-2.23 {floating-point operators} {expr 2.2<=2.2001} 1 test expr-old-2.24 {floating-point operators} {expr 3.2==2.2} 0 test expr-old-2.25 {floating-point operators} {expr 2.2==2.2} 1 test expr-old-2.26 {floating-point operators} {expr 3.2!=2.2} 1 test expr-old-2.27 {floating-point operators} {expr 2.2!=2.2} 0 test expr-old-2.28 {floating-point operators} {expr 0.0&&0.0} 0 test expr-old-2.29 {floating-point operators} {expr 0.0&&1.3} 0 test expr-old-2.30 {floating-point operators} {expr 1.3&&0.0} 0 test expr-old-2.31 {floating-point operators} {expr 1.3&&3.3} 1 test expr-old-2.32 {floating-point operators} {expr 0.0||0.0} 0 test expr-old-2.33 {floating-point operators} {expr 0.0||1.3} 1 test expr-old-2.34 {floating-point operators} {expr 1.3||0.0} 1 test expr-old-2.35 {floating-point operators} {expr 3.3||0.0} 1 test expr-old-2.36 {floating-point operators} {expr 3.3>2.3?44.3:66.3} 44.3 test expr-old-2.37 {floating-point operators} {expr 2.3>3.3?44.3:66.3} 66.3 test expr-old-2.38 {floating-point operators} { list [catch {expr 028.1 + 09.2} msg] $msg } {0 37.3} # Operators that aren't legal on floating-point numbers test expr-old-3.1 {illegal floating-point operations} { list [catch {expr ~4.0} msg] $msg } {1 {can't use floating-point value as operand of "~"}} test expr-old-3.2 {illegal floating-point operations} { list [catch {expr 27%4.0} msg] $msg } {1 {can't use floating-point value as operand of "%"}} test expr-old-3.3 {illegal floating-point operations} { list [catch {expr 27.0%4} msg] $msg } {1 {can't use floating-point value as operand of "%"}} test expr-old-3.4 {illegal floating-point operations} { list [catch {expr 1.0<<3} msg] $msg } {1 {can't use floating-point value as operand of "<<"}} test expr-old-3.5 {illegal floating-point operations} { list [catch {expr 3<<1.0} msg] $msg } {1 {can't use floating-point value as operand of "<<"}} test expr-old-3.6 {illegal floating-point operations} { list [catch {expr 24.0>>3} msg] $msg } {1 {can't use floating-point value as operand of ">>"}} test expr-old-3.7 {illegal floating-point operations} { list [catch {expr 24>>3.0} msg] $msg } {1 {can't use floating-point value as operand of ">>"}} test expr-old-3.8 {illegal floating-point operations} { list [catch {expr 24&3.0} msg] $msg } {1 {can't use floating-point value as operand of "&"}} test expr-old-3.9 {illegal floating-point operations} { list [catch {expr 24.0|3} msg] $msg } {1 {can't use floating-point value as operand of "|"}} test expr-old-3.10 {illegal floating-point operations} { list [catch {expr 24.0^3} msg] $msg } {1 {can't use floating-point value as operand of "^"}} # Check the string operators individually. test expr-old-4.1 {string operators} {expr {"abc" > "def"}} 0 test expr-old-4.2 {string operators} {expr {"def" > "def"}} 0 test expr-old-4.3 {string operators} {expr {"g" > "def"}} 1 test expr-old-4.4 {string operators} {expr {"abc" < "abd"}} 1 test expr-old-4.5 {string operators} {expr {"abd" < "abd"}} 0 test expr-old-4.6 {string operators} {expr {"abe" < "abd"}} 0 test expr-old-4.7 {string operators} {expr {"abc" >= "def"}} 0 test expr-old-4.8 {string operators} {expr {"def" >= "def"}} 1 test expr-old-4.9 {string operators} {expr {"g" >= "def"}} 1 test expr-old-4.10 {string operators} {expr {"abc" <= "abd"}} 1 test expr-old-4.11 {string operators} {expr {"abd" <= "abd"}} 1 test expr-old-4.12 {string operators} {expr {"abe" <= "abd"}} 0 test expr-old-4.13 {string operators} {expr {"abc" == "abd"}} 0 test expr-old-4.14 {string operators} {expr {"abd" == "abd"}} 1 test expr-old-4.15 {string operators} {expr {"abc" != "abd"}} 1 test expr-old-4.16 {string operators} {expr {"abd" != "abd"}} 0 test expr-old-4.17 {string operators} {expr {"0y" < "0x12"}} 0 test expr-old-4.18 {string operators} {expr {"." < " "}} 0 test expr-old-4.19 {string operators} {expr {"abc" eq "abd"}} 0 test expr-old-4.20 {string operators} {expr {"abd" eq "abd"}} 1 test expr-old-4.21 {string operators} {expr {"abc" ne "abd"}} 1 test expr-old-4.22 {string operators} {expr {"abd" ne "abd"}} 0 test expr-old-4.23 {string operators} {expr {"" eq "abd"}} 0 test expr-old-4.24 {string operators} {expr {"" eq ""}} 1 test expr-old-4.25 {string operators} {expr {"abd" ne ""}} 1 test expr-old-4.26 {string operators} {expr {"" ne ""}} 0 test expr-old-4.27 {string operators} {expr {"longerstring" eq "shorter"}} 0 test expr-old-4.28 {string operators} {expr {"longerstring" ne "shorter"}} 1 # The following tests are non-portable because on some systems "+" # and "-" can be parsed as numbers. test expr-old-4.29 {string operators} {nonPortable} {expr {"0" == "+"}} 0 test expr-old-4.30 {string operators} {nonPortable} {expr {"0" == "-"}} 0 test expr-old-4.31 {string operators} {expr {1?"foo":"bar"}} foo test expr-old-4.32 {string operators} {expr {0?"foo":"bar"}} bar # Operators that aren't legal on string operands. test expr-old-5.1 {illegal string operations} { list [catch {expr {-"a"}} msg] $msg } {1 {can't use non-numeric string as operand of "-"}} test expr-old-5.2 {illegal string operations} { list [catch {expr {+"a"}} msg] $msg } {1 {can't use non-numeric string as operand of "+"}} test expr-old-5.3 {illegal string operations} { list [catch {expr {~"a"}} msg] $msg } {1 {can't use non-numeric string as operand of "~"}} test expr-old-5.4 {illegal string operations} { list [catch {expr {!"a"}} msg] $msg } {1 {can't use non-numeric string as operand of "!"}} test expr-old-5.5 {illegal string operations} { list [catch {expr {"a"*"b"}} msg] $msg } {1 {can't use non-numeric string as operand of "*"}} test expr-old-5.6 {illegal string operations} { list [catch {expr {"a"/"b"}} msg] $msg } {1 {can't use non-numeric string as operand of "/"}} test expr-old-5.7 {illegal string operations} { list [catch {expr {"a"%"b"}} msg] $msg } {1 {can't use non-numeric string as operand of "%"}} test expr-old-5.8 {illegal string operations} { list [catch {expr {"a"+"b"}} msg] $msg } {1 {can't use non-numeric string as operand of "+"}} test expr-old-5.9 {illegal string operations} { list [catch {expr {"a"-"b"}} msg] $msg } {1 {can't use non-numeric string as operand of "-"}} test expr-old-5.10 {illegal string operations} { list [catch {expr {"a"<<"b"}} msg] $msg } {1 {can't use non-numeric string as operand of "<<"}} test expr-old-5.11 {illegal string operations} { list [catch {expr {"a">>"b"}} msg] $msg } {1 {can't use non-numeric string as operand of ">>"}} test expr-old-5.12 {illegal string operations} { list [catch {expr {"a"&"b"}} msg] $msg } {1 {can't use non-numeric string as operand of "&"}} test expr-old-5.13 {illegal string operations} { list [catch {expr {"a"^"b"}} msg] $msg } {1 {can't use non-numeric string as operand of "^"}} test expr-old-5.14 {illegal string operations} { list [catch {expr {"a"|"b"}} msg] $msg } {1 {can't use non-numeric string as operand of "|"}} test expr-old-5.15 {illegal string operations} { list [catch {expr {"a"&&"b"}} msg] $msg } {1 {expected boolean value but got "a"}} test expr-old-5.16 {illegal string operations} { list [catch {expr {"a"||"b"}} msg] $msg } {1 {expected boolean value but got "a"}} test expr-old-5.17 {illegal string operations} { list [catch {expr {"a"?4:2}} msg] $msg } {1 {expected boolean value but got "a"}} # Check precedence pairwise. test expr-old-6.1 {precedence checks} {expr -~3} 4 test expr-old-6.2 {precedence checks} {expr -!3} 0 test expr-old-6.3 {precedence checks} {expr -~0} 1 test expr-old-7.1 {precedence checks} {expr 2*4/6} 1 test expr-old-7.2 {precedence checks} {expr 24/6*3} 12 test expr-old-7.3 {precedence checks} {expr 24/6/2} 2 test expr-old-8.1 {precedence checks} {expr -2+4} 2 test expr-old-8.2 {precedence checks} {expr -2-4} -6 test expr-old-8.3 {precedence checks} {expr +2-4} -2 test expr-old-9.1 {precedence checks} {expr 2*3+4} 10 test expr-old-9.2 {precedence checks} {expr 8/2+4} 8 test expr-old-9.3 {precedence checks} {expr 8%3+4} 6 test expr-old-9.4 {precedence checks} {expr 2*3-1} 5 test expr-old-9.5 {precedence checks} {expr 8/2-1} 3 test expr-old-9.6 {precedence checks} {expr 8%3-1} 1 test expr-old-10.1 {precedence checks} {expr 6-3-2} 1 test expr-old-11.1 {precedence checks} {expr 7+1>>2} 2 test expr-old-11.2 {precedence checks} {expr 7+1<<2} 32 test expr-old-11.3 {precedence checks} {expr 7>>3-2} 3 test expr-old-11.4 {precedence checks} {expr 7<<3-2} 14 test expr-old-12.1 {precedence checks} {expr 6>>1>4} 0 test expr-old-12.2 {precedence checks} {expr 6>>1<2} 0 test expr-old-12.3 {precedence checks} {expr 6>>1>=3} 1 test expr-old-12.4 {precedence checks} {expr 6>>1<=2} 0 test expr-old-12.5 {precedence checks} {expr 6<<1>5} 1 test expr-old-12.6 {precedence checks} {expr 6<<1<5} 0 test expr-old-12.7 {precedence checks} {expr 5<=6<<1} 1 test expr-old-12.8 {precedence checks} {expr 5>=6<<1} 0 test expr-old-13.1 {precedence checks} {expr 2<3<4} 1 test expr-old-13.2 {precedence checks} {expr 0<4>2} 0 test expr-old-13.3 {precedence checks} {expr 4>2<1} 0 test expr-old-13.4 {precedence checks} {expr 4>3>2} 0 test expr-old-13.5 {precedence checks} {expr 4>3>=2} 0 test expr-old-13.6 {precedence checks} {expr 4>=3>2} 0 test expr-old-13.7 {precedence checks} {expr 4>=3>=2} 0 test expr-old-13.8 {precedence checks} {expr 0<=4>=2} 0 test expr-old-13.9 {precedence checks} {expr 4>=2<=0} 0 test expr-old-13.10 {precedence checks} {expr 2<=3<=4} 1 test expr-old-14.1 {precedence checks} {expr 1==4>3} 1 test expr-old-14.2 {precedence checks} {expr 0!=4>3} 1 test expr-old-14.3 {precedence checks} {expr 1==3<4} 1 test expr-old-14.4 {precedence checks} {expr 0!=3<4} 1 test expr-old-14.5 {precedence checks} {expr 1==4>=3} 1 test expr-old-14.6 {precedence checks} {expr 0!=4>=3} 1 test expr-old-14.7 {precedence checks} {expr 1==3<=4} 1 test expr-old-14.8 {precedence checks} {expr 0!=3<=4} 1 test expr-old-14.9 {precedence checks} {expr 1eq4>3} 1 test expr-old-14.10 {precedence checks} {expr 0ne4>3} 1 test expr-old-14.11 {precedence checks} {expr 1eq3<4} 1 test expr-old-14.12 {precedence checks} {expr 0ne3<4} 1 test expr-old-14.13 {precedence checks} {expr 1eq4>=3} 1 test expr-old-14.14 {precedence checks} {expr 0ne4>=3} 1 test expr-old-14.15 {precedence checks} {expr 1eq3<=4} 1 test expr-old-14.16 {precedence checks} {expr 0ne3<=4} 1 test expr-old-15.1 {precedence checks} {expr 1==3==3} 0 test expr-old-15.2 {precedence checks} {expr 3==3!=2} 1 test expr-old-15.3 {precedence checks} {expr 2!=3==3} 0 test expr-old-15.4 {precedence checks} {expr 2!=1!=1} 0 test expr-old-15.5 {precedence checks} {expr 1eq3eq3} 0 test expr-old-15.6 {precedence checks} {expr 3eq3ne2} 1 test expr-old-15.7 {precedence checks} {expr 2ne3eq3} 0 test expr-old-15.8 {precedence checks} {expr 2ne1ne1} 0 test expr-old-16.1 {precedence checks} {expr 2&3eq2} 0 test expr-old-16.2 {precedence checks} {expr 1&3ne3} 0 test expr-old-16.3 {precedence checks} {expr 2&3eq2} 0 test expr-old-16.4 {precedence checks} {expr 1&3ne3} 0 test expr-old-17.1 {precedence checks} {expr 7&3^0x10} 19 test expr-old-17.2 {precedence checks} {expr 7^0x10&3} 7 test expr-old-18.1 {precedence checks} {expr 7^0x10|3} 23 test expr-old-18.2 {precedence checks} {expr 7|0x10^3} 23 test expr-old-19.1 {precedence checks} {expr 7|3&&1} 1 test expr-old-19.2 {precedence checks} {expr 1&&3|7} 1 test expr-old-19.3 {precedence checks} {expr 0&&1||1} 1 test expr-old-19.4 {precedence checks} {expr 1||1&&0} 1 test expr-old-20.1 {precedence checks} {expr 1||0?3:4} 3 test expr-old-20.2 {precedence checks} {expr 1?0:4||1} 0 test expr-old-20.3 {precedence checks} {expr 1?2:0?3:4} 2 test expr-old-20.4 {precedence checks} {expr 0?2:0?3:4} 4 test expr-old-20.5 {precedence checks} {expr 1?2?3:4:0} 3 test expr-old-20.6 {precedence checks} {expr 0?2?3:4:0} 0 # Parentheses. test expr-old-21.1 {parenthesization} {expr (2+4)*6} 36 test expr-old-21.2 {parenthesization} {expr (1?0:4)||1} 1 test expr-old-21.3 {parenthesization} {expr +(3-4)} -1 # Embedded commands and variable names. set a 16 test expr-old-22.1 {embedded variables} {expr {2*$a}} 32 test expr-old-22.2 {embedded variables} { set x -5 set y 10 expr {$x + $y} } {5} test expr-old-22.3 {embedded variables} { set x " -5" set y " +10" expr {$x + $y} } {5} test expr-old-22.4 {embedded commands and variables} {expr {[set a] - 14}} 2 test expr-old-22.5 {embedded commands and variables} { list [catch {expr {12 - [bad_command_name]}} msg] $msg } {1 {invalid command name "bad_command_name"}} # Double-quotes and things inside them. test expr-old-23.1 {double quotes} {expr {"abc"}} abc test expr-old-23.2 {double quotes} { set a 189 expr {"$a.bc"} } 189.bc test expr-old-23.3 {double quotes} { set b2 xyx expr {"$b2$b2$b2.[set b2].[set b2]"} } xyxxyxxyx.xyx.xyx test expr-old-23.4 {double quotes} {expr {"11\}\}22"}} 11}}22 test expr-old-23.5 {double quotes} {expr {"\*bc"}} {*bc} test expr-old-23.6 {double quotes} { catch {unset bogus__} list [catch {expr {"$bogus__"}} msg] $msg } {1 {can't read "bogus__": no such variable}} test expr-old-23.7 {double quotes} { list [catch {expr {"a[error Testing]bc"}} msg] $msg } {1 Testing} test expr-old-23.8 {double quotes} { list [catch {expr {"12398712938788234-1298379" != ""}} msg] $msg } {0 1} # Numbers in various bases. test expr-old-24.1 {numbers in different bases} {expr 0x20} 32 test expr-old-24.2 {numbers in different bases} {expr 015} 13 # Conversions between various data types. test expr-old-25.1 {type conversions} {expr 2+2.5} 4.5 test expr-old-25.2 {type conversions} {expr 2.5+2} 4.5 test expr-old-25.3 {type conversions} {expr 2-2.5} -0.5 test expr-old-25.4 {type conversions} {expr 2/2.5} 0.8 test expr-old-25.5 {type conversions} {expr 2>2.5} 0 test expr-old-25.6 {type conversions} {expr 2.5>2} 1 test expr-old-25.7 {type conversions} {expr 2<2.5} 1 test expr-old-25.8 {type conversions} {expr 2>=2.5} 0 test expr-old-25.9 {type conversions} {expr 2<=2.5} 1 test expr-old-25.10 {type conversions} {expr 2==2.5} 0 test expr-old-25.11 {type conversions} {expr 2!=2.5} 1 test expr-old-25.12 {type conversions} {expr 2>"ab"} 0 test expr-old-25.13 {type conversions} {expr {2>" "}} 1 test expr-old-25.14 {type conversions} {expr {"24.1a" > 24.1}} 1 test expr-old-25.15 {type conversions} {expr {24.1 > "24.1a"}} 0 test expr-old-25.16 {type conversions} {expr 2+2.5} 4.5 test expr-old-25.17 {type conversions} {expr 2+2.5} 4.5 test expr-old-25.18 {type conversions} {expr 2.0e2} 200.0 test expr-old-25.19 {type conversions} {eformat} {expr 2.0e15} 2e+15 test expr-old-25.20 {type conversions} {expr 10.0} 10.0 # Various error conditions. test expr-old-26.1 {error conditions} { list [catch {expr 2+"a"} msg] $msg } {1 {can't use non-numeric string as operand of "+"}} test expr-old-26.2 {error conditions} { list [catch {expr 2+4*} msg] $msg } {1 {syntax error in expression "2+4*": premature end of expression}} test expr-old-26.3 {error conditions} { list [catch {expr 2+4*(} msg] $msg } {1 {syntax error in expression "2+4*(": premature end of expression}} catch {unset _non_existent_} test expr-old-26.4 {error conditions} { list [catch {expr 2+$_non_existent_} msg] $msg } {1 {can't read "_non_existent_": no such variable}} set a xx test expr-old-26.5 {error conditions} { list [catch {expr {2+$a}} msg] $msg } {1 {can't use non-numeric string as operand of "+"}} test expr-old-26.6 {error conditions} { list [catch {expr {2+[set a]}} msg] $msg } {1 {can't use non-numeric string as operand of "+"}} test expr-old-26.7 {error conditions} { list [catch {expr {2+(4}} msg] $msg } {1 {syntax error in expression "2+(4": looking for close parenthesis}} test expr-old-26.8 {error conditions} { list [catch {expr 2/0} msg] $msg $errorCode } {1 {divide by zero} {ARITH DIVZERO {divide by zero}}} test expr-old-26.9 {error conditions} { list [catch {expr 2%0} msg] $msg $errorCode } {1 {divide by zero} {ARITH DIVZERO {divide by zero}}} test expr-old-26.10 {error conditions} { list [catch {expr 2.0/0.0} msg] $msg $errorCode } {1 {divide by zero} {ARITH DIVZERO {divide by zero}}} test expr-old-26.11 {error conditions} { list [catch {expr 2#} msg] $msg } {1 {syntax error in expression "2#": extra tokens at end of expression}} test expr-old-26.12 {error conditions} { list [catch {expr a.b} msg] $msg } {1 {syntax error in expression "a.b": variable references require preceding $}} test expr-old-26.13 {error conditions} { list [catch {expr {"a"/"b"}} msg] $msg } {1 {can't use non-numeric string as operand of "/"}} test expr-old-26.14 {error conditions} { list [catch {expr 2:3} msg] $msg } {1 {syntax error in expression "2:3": extra tokens at end of expression}} test expr-old-26.15 {error conditions} { list [catch {expr a@b} msg] $msg } {1 {syntax error in expression "a@b": variable references require preceding $}} test expr-old-26.16 {error conditions} { list [catch {expr a[b} msg] $msg } {1 {missing close-bracket}} test expr-old-26.17 {error conditions} { list [catch {expr a`b} msg] $msg } {1 {syntax error in expression "a`b": variable references require preceding $}} test expr-old-26.18 {error conditions} { list [catch {expr \"a\"\{b} msg] $msg } {1 syntax\ error\ in\ expression\ \"\"a\"\{b\":\ extra\ tokens\ at\ end\ of\ expression} test expr-old-26.19 {error conditions} { list [catch {expr a} msg] $msg } {1 {syntax error in expression "a": variable references require preceding $}} test expr-old-26.20 {error conditions} { list [catch expr msg] $msg } {1 {wrong # args: should be "expr arg ?arg ...?"}} # Cancelled evaluation. test expr-old-27.1 {cancelled evaluation} { set a 1 expr {0&&[set a 2]} set a } 1 test expr-old-27.2 {cancelled evaluation} { set a 1 expr {1||[set a 2]} set a } 1 test expr-old-27.3 {cancelled evaluation} { set a 1 expr {0?[set a 2]:1} set a } 1 test expr-old-27.4 {cancelled evaluation} { set a 1 expr {1?2:[set a 2]} set a } 1 catch {unset x} test expr-old-27.5 {cancelled evaluation} { list [catch {expr {[info exists x] && $x}} msg] $msg } {0 0} test expr-old-27.6 {cancelled evaluation} { list [catch {expr {0 && [concat $x]}} msg] $msg } {0 0} test expr-old-27.7 {cancelled evaluation} { set one 1 list [catch {expr {1 || 1/$one}} msg] $msg } {0 1} test expr-old-27.8 {cancelled evaluation} { list [catch {expr {1 || -"string"}} msg] $msg } {0 1} test expr-old-27.9 {cancelled evaluation} { list [catch {expr {1 || ("string" * ("x" && "y"))}} msg] $msg } {0 1} test expr-old-27.10 {cancelled evaluation} { set x -1.0 list [catch {expr {($x > 0) ? round(log($x)) : 0}} msg] $msg } {0 0} test expr-old-27.11 {cancelled evaluation} { list [catch {expr {0 && foo}} msg] $msg } {1 {syntax error in expression "0 && foo": variable references require preceding $}} test expr-old-27.12 {cancelled evaluation} { list [catch {expr {0 ? 1 : foo}} msg] $msg } {1 {syntax error in expression "0 ? 1 : foo": variable references require preceding $}} # Tcl_ExprBool as used in "if" statements test expr-old-28.1 {Tcl_ExprBoolean usage} { set a 1 if {2} {set a 2} set a } 2 test expr-old-28.2 {Tcl_ExprBoolean usage} { set a 1 if {0} {set a 2} set a } 1 test expr-old-28.3 {Tcl_ExprBoolean usage} { set a 1 if {1.2} {set a 2} set a } 2 test expr-old-28.4 {Tcl_ExprBoolean usage} { set a 1 if {-1.1} {set a 2} set a } 2 test expr-old-28.5 {Tcl_ExprBoolean usage} { set a 1 if {0.0} {set a 2} set a } 1 test expr-old-28.6 {Tcl_ExprBoolean usage} { set a 1 if {"YES"} {set a 2} set a } 2 test expr-old-28.7 {Tcl_ExprBoolean usage} { set a 1 if {"no"} {set a 2} set a } 1 test expr-old-28.8 {Tcl_ExprBoolean usage} { set a 1 if {"true"} {set a 2} set a } 2 test expr-old-28.9 {Tcl_ExprBoolean usage} { set a 1 if {"fAlse"} {set a 2} set a } 1 test expr-old-28.10 {Tcl_ExprBoolean usage} { set a 1 if {"on"} {set a 2} set a } 2 test expr-old-28.11 {Tcl_ExprBoolean usage} { set a 1 if {"Off"} {set a 2} set a } 1 test expr-old-28.12 {Tcl_ExprBool usage} { list [catch {if {"abc"} {}} msg] $msg } {1 {expected boolean value but got "abc"}} test expr-old-28.13 {Tcl_ExprBool usage} { list [catch {if {"ogle"} {}} msg] $msg } {1 {expected boolean value but got "ogle"}} test expr-old-28.14 {Tcl_ExprBool usage} { list [catch {if {"o"} {}} msg] $msg } {1 {expected boolean value but got "o"}} # Operands enclosed in braces test expr-old-29.1 {braces} {expr {{abc}}} abc test expr-old-29.2 {braces} {expr {{00010}}} 8 test expr-old-29.3 {braces} {expr {{3.1200000}}} 3.12 test expr-old-29.4 {braces} {expr {{a{b}{1 {2 3}}c}}} "a{b}{1 {2 3}}c" test expr-old-29.5 {braces} { list [catch {expr "\{abc"} msg] $msg } {1 {missing close-brace}} # Very long values test expr-old-30.1 {long values} { set a "0000 1111 2222 3333 4444" set a "$a | $a | $a | $a | $a" set a "$a || $a || $a || $a || $a" expr {$a} } {0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 || 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 || 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 || 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 || 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444} test expr-old-30.2 {long values} { set a "000000000000000000000000000000" set a "$a$a$a$a$a$a$a$a$a$a$a$a$a$a$a$a${a}5" expr $a } 5 # Expressions spanning multiple arguments test expr-old-31.1 {multiple arguments to expr command} { expr 4 + ( 6 *12) -3 } 73 test expr-old-31.2 {multiple arguments to expr command} { list [catch {expr 2 + (3 + 4} msg] $msg } {1 {syntax error in expression "2 + (3 + 4": looking for close parenthesis}} test expr-old-31.3 {multiple arguments to expr command} { list [catch {expr 2 + 3 +} msg] $msg } {1 {syntax error in expression "2 + 3 +": premature end of expression}} test expr-old-31.4 {multiple arguments to expr command} { list [catch {expr 2 + 3 )} msg] $msg } {1 {syntax error in expression "2 + 3 )": extra tokens at end of expression}} # Math functions test expr-old-32.1 {math functions in expressions} { format %.6g [expr acos(0.5)] } {1.0472} test expr-old-32.2 {math functions in expressions} { format %.6g [expr asin(0.5)] } {0.523599} test expr-old-32.3 {math functions in expressions} { format %.6g [expr atan(1.0)] } {0.785398} test expr-old-32.4 {math functions in expressions} { format %.6g [expr atan2(2.0, 2.0)] } {0.785398} test expr-old-32.5 {math functions in expressions} { format %.6g [expr ceil(1.999)] } {2} test expr-old-32.6 {math functions in expressions} { format %.6g [expr cos(.1)] } {0.995004} test expr-old-32.7 {math functions in expressions} { format %.6g [expr cosh(.1)] } {1.005} test expr-old-32.8 {math functions in expressions} { format %.6g [expr exp(1.0)] } {2.71828} test expr-old-32.9 {math functions in expressions} { format %.6g [expr floor(2.000)] } {2} test expr-old-32.10 {math functions in expressions} { format %.6g [expr floor(2.001)] } {2} test expr-old-32.11 {math functions in expressions} { format %.6g [expr fmod(7.3, 3.2)] } {0.9} test expr-old-32.12 {math functions in expressions} { format %.6g [expr hypot(3.0, 4.0)] } {5} test expr-old-32.13 {math functions in expressions} { format %.6g [expr log(2.8)] } {1.02962} test expr-old-32.14 {math functions in expressions} { format %.6g [expr log10(2.8)] } {0.447158} test expr-old-32.15 {math functions in expressions} { format %.6g [expr pow(2.1, 3.1)] } {9.97424} test expr-old-32.16 {math functions in expressions} { format %.6g [expr sin(.1)] } {0.0998334} test expr-old-32.17 {math functions in expressions} { format %.6g [expr sinh(.1)] } {0.100167} test expr-old-32.18 {math functions in expressions} { format %.6g [expr sqrt(2.0)] } {1.41421} test expr-old-32.19 {math functions in expressions} { format %.6g [expr tan(0.8)] } {1.02964} test expr-old-32.20 {math functions in expressions} { format %.6g [expr tanh(0.8)] } {0.664037} test expr-old-32.21 {math functions in expressions} { format %.6g [expr abs(-1.8)] } {1.8} test expr-old-32.22 {math functions in expressions} { expr abs(10.0) } {10.0} test expr-old-32.23 {math functions in expressions} { format %.6g [expr abs(-4)] } {4} test expr-old-32.24 {math functions in expressions} { format %.6g [expr abs(66)] } {66} # The following test is different for 32-bit versus 64-bit architectures. if {0x80000000 > 0} { test expr-old-32.25 {math functions in expressions} {nonPortable} { list [catch {expr abs(0x8000000000000000)} msg] $msg } {1 {integer value too large to represent}} } else { test expr-old-32.25 {math functions in expressions} {nonPortable} { list [catch {expr abs(0x80000000)} msg] $msg } {1 {integer value too large to represent}} } test expr-old-32.26 {math functions in expressions} { expr double(1) } {1.0} test expr-old-32.27 {math functions in expressions} { expr double(1.1) } {1.1} test expr-old-32.28 {math functions in expressions} { expr int(1) } {1} test expr-old-32.29 {math functions in expressions} { expr int(1.4) } {1} test expr-old-32.30 {math functions in expressions} { expr int(1.6) } {1} test expr-old-32.31 {math functions in expressions} { expr int(-1.4) } {-1} test expr-old-32.32 {math functions in expressions} { expr int(-1.6) } {-1} test expr-old-32.33 {math functions in expressions} { list [catch {expr int(1e60)} msg] $msg } {1 {integer value too large to represent}} test expr-old-32.34 {math functions in expressions} { list [catch {expr int(-1e60)} msg] $msg } {1 {integer value too large to represent}} test expr-old-32.35 {math functions in expressions} { expr round(1.49) } {1} test expr-old-32.36 {math functions in expressions} { expr round(1.51) } {2} test expr-old-32.37 {math functions in expressions} { expr round(-1.49) } {-1} test expr-old-32.38 {math functions in expressions} { expr round(-1.51) } {-2} test expr-old-32.39 {math functions in expressions} { list [catch {expr round(1e60)} msg] $msg } {1 {integer value too large to represent}} test expr-old-32.40 {math functions in expressions} { list [catch {expr round(-1e60)} msg] $msg } {1 {integer value too large to represent}} test expr-old-32.41 {math functions in expressions} { list [catch {expr pow(1.0 + 3.0 - 2, .8 * 5)} msg] $msg } {0 16.0} test expr-old-32.42 {math functions in expressions} { list [catch {expr hypot(5*.8,3)} msg] $msg } {0 5.0} if $gotT1 { test expr-old-32.43 {math functions in expressions} { expr 2*T1() } 246 test expr-old-32.44 {math functions in expressions} { expr T2()*3 } 1035 } test expr-old-32.45 {math functions in expressions} { expr (0 <= rand()) && (rand() < 1) } {1} test expr-old-32.46 {math functions in expressions} { list [catch {expr rand(24)} msg] $msg } {1 {too many arguments for math function}} test expr-old-32.47 {math functions in expressions} { list [catch {expr srand()} msg] $msg } {1 {too few arguments for math function}} test expr-old-32.48 {math functions in expressions} { list [catch {expr srand(3.79)} msg] $msg } {1 {expected integer but got "3.79"}} test expr-old-32.49 {math functions in expressions} { list [catch {expr srand("")} msg] $msg } {1 {argument to math function didn't have numeric value}} test expr-old-32.50 {math functions in expressions} { set result [expr round(srand(12345) * 1000)] for {set i 0} {$i < 10} {incr i} { lappend result [expr round(rand() * 1000)] } set result } {97 834 948 36 12 51 766 585 914 784 333} test expr-old-32.51 {math functions in expressions} { list [catch {expr {srand([lindex "6ty" 0])}} msg] $msg } {1 {argument to math function didn't have numeric value}} test expr-old-32.52 {math functions in expressions} { expr {srand(int(1<<37)) < 1} } {1} test expr-old-32.53 {math functions in expressions} { expr {srand((1<<31) - 1) > 0} } {1} test expr-old-33.1 {conversions and fancy args to math functions} { expr hypot ( 3 , 4 ) } 5.0 test expr-old-33.2 {conversions and fancy args to math functions} { expr hypot ( (2.0+1.0) , 4 ) } 5.0 test expr-old-33.3 {conversions and fancy args to math functions} { expr hypot ( 3 , (3.0 + 1.0) ) } 5.0 test expr-old-33.4 {conversions and fancy args to math functions} { format %.6g [expr cos(acos(0.1))] } 0.1 test expr-old-34.1 {errors in math functions} { list [catch {expr func_2(1.0)} msg] $msg } {1 {unknown math function "func_2"}} test expr-old-34.2 {errors in math functions} { list [catch {expr func|(1.0)} msg] $msg } {1 {syntax error in expression "func|(1.0)": variable references require preceding $}} test expr-old-34.3 {errors in math functions} { list [catch {expr {hypot("a b", 2.0)}} msg] $msg } {1 {argument to math function didn't have numeric value}} test expr-old-34.4 {errors in math functions} { list [catch {expr hypot(1.0 2.0)} msg] $msg } {1 {syntax error in expression "hypot(1.0 2.0)": missing close parenthesis at end of function call}} test expr-old-34.5 {errors in math functions} { list [catch {expr hypot(1.0, 2.0} msg] $msg } {1 {syntax error in expression "hypot(1.0, 2.0": missing close parenthesis at end of function call}} test expr-old-34.6 {errors in math functions} { list [catch {expr hypot(1.0 ,} msg] $msg } {1 {syntax error in expression "hypot(1.0 ,": premature end of expression}} test expr-old-34.7 {errors in math functions} { list [catch {expr hypot(1.0)} msg] $msg } {1 {too few arguments for math function}} test expr-old-34.8 {errors in math functions} { list [catch {expr hypot(1.0, 2.0, 3.0)} msg] $msg } {1 {too many arguments for math function}} test expr-old-34.9 {errors in math functions} { list [catch {expr acos(-2.0)} msg] $msg $errorCode } {1 {domain error: argument not in valid range} {ARITH DOMAIN {domain error: argument not in valid range}}} test expr-old-34.10 {errors in math functions} {nonPortable} { list [catch {expr pow(-3, 1000001)} msg] $msg $errorCode } {1 {floating-point value too large to represent} {ARITH OVERFLOW {floating-point value too large to represent}}} test expr-old-34.11 {errors in math functions} { list [catch {expr pow(3, 1000001)} msg] $msg $errorCode } {1 {floating-point value too large to represent} {ARITH OVERFLOW {floating-point value too large to represent}}} test expr-old-34.12 {errors in math functions} { list [catch {expr -14.0*exp(100000)} msg] $msg $errorCode } {1 {floating-point value too large to represent} {ARITH OVERFLOW {floating-point value too large to represent}}} test expr-old-34.13 {errors in math functions} { list [catch {expr int(1.0e30)} msg] $msg $errorCode } {1 {integer value too large to represent} {ARITH IOVERFLOW {integer value too large to represent}}} test expr-old-34.14 {errors in math functions} { list [catch {expr int(-1.0e30)} msg] $msg $errorCode } {1 {integer value too large to represent} {ARITH IOVERFLOW {integer value too large to represent}}} test expr-old-34.15 {errors in math functions} { list [catch {expr round(1.0e30)} msg] $msg $errorCode } {1 {integer value too large to represent} {ARITH IOVERFLOW {integer value too large to represent}}} test expr-old-34.16 {errors in math functions} { list [catch {expr round(-1.0e30)} msg] $msg $errorCode } {1 {integer value too large to represent} {ARITH IOVERFLOW {integer value too large to represent}}} if $gotT1 { test expr-old-34.17 {errors in math functions} { list [catch {expr T1(4)} msg] $msg } {1 {too many arguments for math function}} } test expr-old-36.1 {ExprLooksLikeInt procedure} -body { expr 0289 } -returnCodes error -match glob -result {*invalid octal number*} test expr-old-36.2 {ExprLooksLikeInt procedure} { set x 0289 list [catch {expr {$x+1}} msg] $msg } {1 {can't use invalid octal number as operand of "+"}} test expr-old-36.3 {ExprLooksLikeInt procedure} { list [catch {expr 0289.1} msg] $msg } {0 289.1} test expr-old-36.4 {ExprLooksLikeInt procedure} { set x 0289.1 list [catch {expr {$x+1}} msg] $msg } {0 290.1} test expr-old-36.5 {ExprLooksLikeInt procedure} { set x { +22} list [catch {expr {$x+1}} msg] $msg } {0 23} test expr-old-36.6 {ExprLooksLikeInt procedure} { set x { -22} list [catch {expr {$x+1}} msg] $msg } {0 -21} test expr-old-36.7 {ExprLooksLikeInt procedure} {nonPortable unixOnly} { list [catch {expr nan} msg] $msg } {1 {domain error: argument not in valid range}} test expr-old-36.8 {ExprLooksLikeInt procedure} { list [catch {expr 78e1} msg] $msg } {0 780.0} test expr-old-36.9 {ExprLooksLikeInt procedure} { list [catch {expr 24E1} msg] $msg } {0 240.0} test expr-old-36.10 {ExprLooksLikeInt procedure} {nonPortable unixOnly} { list [catch {expr 78e} msg] $msg } {1 {syntax error in expression "78e"}} # test for [Bug #542588] test expr-old-36.11 {ExprLooksLikeInt procedure} { # define a "too large integer"; this one works also for 64bit arith set x 665802003400000000000000 list [catch {expr {$x+1}} msg] $msg } {1 {can't use integer value too large to represent as operand of "+"}} # tests for [Bug #587140] test expr-old-36.12 {ExprLooksLikeInt procedure} { set x "10;" list [catch {expr {$x+1}} msg] $msg } {1 {can't use non-numeric string as operand of "+"}} test expr-old-36.13 {ExprLooksLikeInt procedure} { set x " +" list [catch {expr {$x+1}} msg] $msg } {1 {can't use non-numeric string as operand of "+"}} test expr-old-36.14 {ExprLooksLikeInt procedure} { set x "123456789012345678901234567890 " list [catch {expr {$x+1}} msg] $msg } {1 {can't use integer value too large to represent as operand of "+"}} test expr-old-36.15 {ExprLooksLikeInt procedure} { set x "099 " list [catch {expr {$x+1}} msg] $msg } {1 {can't use invalid octal number as operand of "+"}} test expr-old-36.16 {ExprLooksLikeInt procedure} { set x " 0xffffffffffffffffffffffffffffffffffffff " list [catch {expr {$x+1}} msg] $msg } {1 {can't use integer value too large to represent as operand of "+"}} if {[info commands testexprlong] == {}} { puts "This application hasn't been compiled with the \"testexprlong\"" puts "command, so I can't test Tcl_ExprLong etc." } else { test expr-old-37.1 {Check that Tcl_ExprLong doesn't modify interpreter result if no error} { testexprlong } {This is a result: 5} } if {[info commands testexprstring] == {}} { puts "This application hasn't been compiled with the \"testexprstring\"" puts "command, so I can't test Tcl_ExprString etc." } else { test expr-old-38.1 {Verify Tcl_ExprString's basic operation} { list [testexprstring "1+4"] [testexprstring "2*3+4.2"] \ [catch {testexprstring "1+"} msg] $msg } {5 10.2 1 {syntax error in expression "1+": premature end of expression}} } # # Test for bug #908375: rounding numbers that do not fit in a # long but do fit in a wide # test expr-old-39.1 {Rounding with wide result} { set x 1.0e10 set y [expr $x + 0.1] catch { set x [list [expr {$x == round($y)}] [expr $x == -round(-$y)]] } set x } {1 1} unset -nocomplain x y # Special test for Pentium arithmetic bug of 1994: if {(4195835.0 - (4195835.0/3145727.0)*3145727.0) == 256.0} { puts "Warning: this machine contains a defective Pentium processor" puts "that performs arithmetic incorrectly. I recommend that you" puts "call Intel customer service immediately at 1-800-628-8686" puts "to request a replacement processor." } # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/appendComp.test0000644003604700454610000002500711737050674015054 0ustar dgp771div# Commands covered: append lappend # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994-1996 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } catch {unset x} test appendComp-1.1 {append command} { catch {unset x} proc foo {} {append ::x 1 2 abc "long string"} list [foo] $x } {{12abclong string} {12abclong string}} test appendComp-1.2 {append command} { proc foo {} { set x "" list [append x first] [append x second] [append x third] $x } foo } {first firstsecond firstsecondthird firstsecondthird} test appendComp-1.3 {append command} { proc foo {} { set x "abcd" append x } foo } abcd test appendComp-2.1 {long appends} { proc foo {} { set x "" for {set i 0} {$i < 1000} {set i [expr $i+1]} { append x "foobar " } set y "foobar" set y "$y $y $y $y $y $y $y $y $y $y" set y "$y $y $y $y $y $y $y $y $y $y" set y "$y $y $y $y $y $y $y $y $y $y " expr {$x == $y} } foo } 1 test appendComp-3.1 {append errors} { proc foo {} {append} list [catch {foo} msg] $msg } {1 {wrong # args: should be "append varName ?value value ...?"}} test appendComp-3.2 {append errors} { proc foo {} { set x "" append x(0) 44 } list [catch {foo} msg] $msg } {1 {can't set "x(0)": variable isn't array}} test appendComp-3.3 {append errors} { proc foo {} { catch {unset x} append x } list [catch {foo} msg] $msg } {1 {can't read "x": no such variable}} test appendComp-4.1 {lappend command} { proc foo {} { global x catch {unset x} lappend x 1 2 abc "long string" } list [foo] $x } {{1 2 abc {long string}} {1 2 abc {long string}}} test appendComp-4.2 {lappend command} { proc foo {} { set x "" list [lappend x first] [lappend x second] [lappend x third] $x } foo } {first {first second} {first second third} {first second third}} test appendComp-4.3 {lappend command} { proc foo {} { global x set x old unset x lappend x new } set result [foo] rename foo {} set result } {new} test appendComp-4.4 {lappend command} { proc foo {} { set x {} lappend x \{\ abc } foo } {\{\ abc} test appendComp-4.5 {lappend command} { proc foo {} { set x {} lappend x \{ abc } foo } {\{ abc} test appendComp-4.6 {lappend command} { proc foo {} { set x {1 2 3} lappend x } foo } {1 2 3} test appendComp-4.7 {lappend command} { proc foo {} { set x "a\{" lappend x abc } foo } "a\\\{ abc" test appendComp-4.8 {lappend command} { proc foo {} { set x "\\\{" lappend x abc } foo } "\\{ abc" test appendComp-4.9 {lappend command} { proc foo {} { set x " \{" list [catch {lappend x abc} msg] $msg } foo } {1 {unmatched open brace in list}} test appendComp-4.10 {lappend command} { proc foo {} { set x " \{" list [catch {lappend x abc} msg] $msg } foo } {1 {unmatched open brace in list}} test appendComp-4.11 {lappend command} { proc foo {} { set x "\{\{\{" list [catch {lappend x abc} msg] $msg } foo } {1 {unmatched open brace in list}} test appendComp-4.12 {lappend command} { proc foo {} { set x "x \{\{\{" list [catch {lappend x abc} msg] $msg } foo } {1 {unmatched open brace in list}} test appendComp-4.13 {lappend command} { proc foo {} { set x "x\{\{\{" lappend x abc } foo } "x\\\{\\\{\\\{ abc" test appendComp-4.14 {lappend command} { proc foo {} { set x " " lappend x abc } foo } "abc" test appendComp-4.15 {lappend command} { proc foo {} { set x "\\ " lappend x abc } foo } "{ } abc" test appendComp-4.16 {lappend command} { proc foo {} { set x "x " lappend x abc } foo } "x abc" test appendComp-4.17 {lappend command} { proc foo {} { lappend x } foo } {} test appendComp-4.18 {lappend command} { proc foo {} { lappend x {} } foo } {{}} test appendComp-4.19 {lappend command} { proc foo {} { lappend x(0) } foo } {} test appendComp-4.20 {lappend command} { proc foo {} { lappend x(0) abc } foo } {abc} proc check {var size} { set l [llength $var] if {$l != $size} { return "length mismatch: should have been $size, was $l" } for {set i 0} {$i < $size} {set i [expr $i+1]} { set j [lindex $var $i] if {$j != "item $i"} { return "element $i should have been \"item $i\", was \"$j\"" } } return ok } test appendComp-5.1 {long lappends} { catch {unset x} set x "" for {set i 0} {$i < 300} {set i [expr $i+1]} { lappend x "item $i" } check $x 300 } ok test appendComp-6.1 {lappend errors} { proc foo {} {lappend} list [catch {foo} msg] $msg } {1 {wrong # args: should be "lappend varName ?value value ...?"}} test appendComp-6.2 {lappend errors} { proc foo {} { set x "" lappend x(0) 44 } list [catch {foo} msg] $msg } {1 {can't set "x(0)": variable isn't array}} test appendComp-7.1 {lappendComp-created var and error in trace on that var} { proc bar {} { global x catch {rename foo ""} catch {unset x} trace variable x w foo proc foo {} {global x; unset x} catch {lappend x 1} proc foo {args} {global x; unset x} info exists x set x lappend x 1 list [info exists x] [catch {set x} msg] $msg } bar } {0 1 {can't read "x": no such variable}} test appendComp-7.2 {lappend var triggers read trace, index var} {bug-3057639} { proc bar {} { catch {unset myvar} catch {unset ::result} trace variable myvar r foo proc foo {args} {append ::result $args} lappend myvar a list [catch {set ::result} msg] $msg } bar } {0 {myvar {} r}} test appendComp-7.3 {lappend var triggers read trace, stack var} {bug-3057639} { proc bar {} { catch {unset ::myvar} catch {unset ::result} trace variable ::myvar r foo proc foo {args} {append ::result $args} lappend ::myvar a list [catch {set ::result} msg] $msg } bar } {0 {::myvar {} r}} test appendComp-7.4 {lappend var triggers read trace, array var} {bug-3057639} { # The behavior of read triggers on lappend changed in 8.0 to # not trigger them. Maybe not correct, but been there a while. proc bar {} { catch {unset myvar} catch {unset ::result} trace variable myvar r foo proc foo {args} {append ::result $args} lappend myvar(b) a list [catch {set ::result} msg] $msg } bar } {0 {myvar b r}} test appendComp-7.5 {lappend var triggers read trace, array var} { # The behavior of read triggers on lappend changed in 8.0 to # not trigger them. Maybe not correct, but been there a while. proc bar {} { catch {unset myvar} catch {unset ::result} trace variable myvar r foo proc foo {args} {append ::result $args} lappend myvar(b) a b list [catch {set ::result} msg] $msg } bar } {0 {myvar b r}} test appendComp-7.6 {lappend var triggers read trace, array var exists} {bug-3057639} { proc bar {} { catch {unset myvar} catch {unset ::result} set myvar(0) 1 trace variable myvar r foo proc foo {args} {append ::result $args} lappend myvar(b) a list [catch {set ::result} msg] $msg } bar } {0 {myvar b r}} test appendComp-7.7 {lappend var triggers read trace, array stack var} {bug-3057639} { proc bar {} { catch {unset ::myvar} catch {unset ::result} trace variable ::myvar r foo proc foo {args} {append ::result $args} lappend ::myvar(b) a list [catch {set ::result} msg] $msg } bar } {0 {::myvar b r}} test appendComp-7.8 {lappend var triggers read trace, array stack var} { proc bar {} { catch {unset ::myvar} catch {unset ::result} trace variable ::myvar r foo proc foo {args} {append ::result $args} lappend ::myvar(b) a b list [catch {set ::result} msg] $msg } bar } {0 {::myvar b r}} test appendComp-7.9 {append var does not trigger read trace} { proc bar {} { catch {unset myvar} catch {unset ::result} trace variable myvar r foo proc foo {args} {append ::result $args} append myvar a info exists ::result } bar } {0} # New tests for bug 3057639 to show off the more consistent behaviour # of lappend in both direct-eval and bytecompiled code paths (see # append.test for the direct-eval variants). lappend now behaves like # append. 9.0/1 lappend - 9.2/3 append. # Note also the tests above now constrained by bug-3057639, these # changed behaviour with the triggering of read traces in bc mode # gone. # Going back to the tests below. The direct-eval tests are ok before # and after patch (no read traces run for lappend, append). The # compiled tests are failing for lappend (9.0/1) before the patch, # showing how it invokes read traces in the compiled path. The append # tests are good (9.2/3). After the patch the failues are gone. test appendComp-9.0 {bug 3057639, lappend compiled, read trace on non-existing array variable element} { catch {unset myvar} array set myvar {} proc nonull {var key val} { upvar 1 $var lvar if {![info exists lvar($key)]} { return -code error "BOOM. no such variable" } } trace add variable myvar read nonull proc foo {} { lappend ::myvar(key) "new value" } list [catch { foo } msg] $msg } {0 {{new value}}} test appendComp-9.1 {bug 3057639, lappend direct eval, read trace on non-existing env element} { catch {unset ::env(__DUMMY__)} proc foo {} { lappend ::env(__DUMMY__) "new value" } list [catch { foo } msg] $msg } {0 {{new value}}} test appendComp-9.2 {bug 3057639, append compiled, read trace on non-existing array variable element} { catch {unset myvar} array set myvar {} proc nonull {var key val} { upvar 1 $var lvar if {![info exists lvar($key)]} { return -code error "BOOM. no such variable" } } trace add variable myvar read nonull proc foo {} { append ::myvar(key) "new value" } list [catch { foo } msg] $msg } {0 {new value}} test appendComp-9.3 {bug 3057639, append direct eval, read trace on non-existing env element} { catch {unset ::env(__DUMMY__)} proc foo {} { append ::env(__DUMMY__) "new value" } list [catch { foo } msg] $msg } {0 {new value}} catch {unset i x result y} catch {rename foo ""} catch {rename bar ""} catch {rename check ""} catch {rename bar {}} # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/winDde.test0000644003604700454610000001220112144442333014156 0ustar dgp771div# This file tests the tclWinDde.c file. # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } if {$tcl_platform(platform) == "windows"} { if [catch { set lib [lindex [glob -directory [file join [pwd] [file dirname \ [info nameofexecutable]]] tcldde*.dll] 0] load $lib dde }] { puts "WARNING: Unable to find the dde package. Skipping dde tests." ::tcltest::cleanupTests return } } set scriptName script1.tcl proc createChildProcess { ddeServerName } { file delete -force $::scriptName set f [open $::scriptName w+] puts $f { if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } if [catch { set lib [lindex [glob -directory \ [file join [pwd] [file dirname [info nameofexecutable]]] \ tcldde*.dll] 0] load $lib dde }] { puts "Unable to find the dde package. Skipping dde tests." ::tcltest::cleanupTests return } } puts $f [list dde servername $ddeServerName] puts $f { after 200 {set ready 1} vwait ready puts ready vwait done after 200 {set final 1} vwait final exit } close $f set f [open |[list [interpreter] $::scriptName] r] fconfigure $f -buffering line -blocking 1 gets $f return $f } # ------------------------------------------------------------------------- test winDde-1.1 {Settings the server's topic name} {pcOnly} { list [dde servername foobar] [dde servername] [dde servername self] } {foobar foobar self} test winDde-2.1 {Checking for other services} {pcOnly} { expr [llength [dde services {} {}]] >= 0 } 1 test winDde-2.2 {Checking for existence, with service and topic specified} \ {pcOnly} { llength [dde services TclEval self] } 1 test winDde-2.3 {Checking for existence, with only the service specified} \ {pcOnly} { expr [llength [dde services TclEval {}]] >= 1 } 1 # ------------------------------------------------------------------------- test winDde-3.1 {DDE execute locally} {pcOnly} { set a "" dde execute TclEval self {set a "foo"} set a } foo test winDde-3.2 {DDE execute -async locally} {pcOnly} { set a "" dde execute -async TclEval self {set a "foo"} update set a } foo test winDde-3.3 {DDE request locally} {pcOnly} { set a "" dde execute TclEval self {set a "foo"} dde request TclEval self a } foo test winDde-3.4 {DDE eval locally} {pcOnly} { set a "" dde eval self set a "foo" } foo test winDde-3.5 {DDE request locally} {pcOnly} { set a "" dde execute TclEval self {set a "foo"} dde request -binary TclEval self a } "foo\x00" # ------------------------------------------------------------------------- test winDde-4.1 {DDE execute remotely} {stdio pcOnly} { set a "" set name child-4.1 set child [createChildProcess $name] dde execute TclEval $name {set a "foo"} dde execute TclEval $name {set done 1} update set a } "" test winDde-4.2 {DDE execute async remotely} {stdio pcOnly} { set a "" set name child-4.2 set child [createChildProcess $name] dde execute -async TclEval $name {set a "foo"} update dde execute TclEval $name {set done 1} update set a } "" test winDde-4.3 {DDE request remotely} {stdio pcOnly} { set a "" set name chile-4.3 set child [createChildProcess $name] dde execute TclEval $name {set a "foo"} set a [dde request TclEval $name a] dde execute TclEval $name {set done 1} update set a } foo test winDde-4.4 {DDE eval remotely} {stdio pcOnly} { set a "" set name child-4.4 set child [createChildProcess $name] set a [dde eval $name set a "foo"] dde execute TclEval $name {set done 1} update set a } foo # ------------------------------------------------------------------------- test winDde-5.1 {check for bad arguments} {pcOnly} { catch {dde execute "" "" "" ""} result set result } {wrong # args: should be "dde execute ?-async? serviceName topicName value"} test winDde-5.2 {check for bad arguments} {pcOnly} { catch {dde execute "" "" ""} result set result } {cannot execute null data} test winDde-5.3 {check for bad arguments} {pcOnly} { catch {dde execute -foo "" "" ""} result set result } {wrong # args: should be "dde execute ?-async? serviceName topicName value"} test winDde-5.4 {DDE eval bad arguments} {pcOnly} { list [catch {dde eval "" "foo"} msg] $msg } {1 {invalid service name ""}} # ------------------------------------------------------------------------- #cleanup #catch {interp delete $slave}; # ensure we clean up the slave. file delete -force $::scriptName ::tcltest::cleanupTests return # Local Variables: # mode: tcl # End: tcl8.4.20/tests/list.test0000644003604700454610000000757311737050674013751 0ustar dgp771div# Commands covered: list # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } # First, a bunch of individual tests test list-1.1 {basic tests} {list a b c} {a b c} test list-1.2 {basic tests} {list {a b} c} {{a b} c} test list-1.3 {basic tests} {list \{a b c} {\{a b c} test list-1.4 {basic tests} "list a{}} b{} c}" "a\\{\\}\\} b{} c\\}" test list-1.5 {basic tests} {list a\[ b\] } "{a\[} b\\]" test list-1.6 {basic tests} {list c\ d\t } "{c } {d\t}" test list-1.7 {basic tests} {list e\n f\$ } "{e\n} {f\$}" test list-1.8 {basic tests} {list g\; h\\} {{g;} h\\} test list-1.9 {basic tests} "list a\\\[} b\\\]} " "a\\\[\\\} b\\\]\\\}" test list-1.10 {basic tests} "list c\\\} d\\t} " "c\\} d\\t\\}" test list-1.11 {basic tests} "list e\\n} f\\$} " "e\\n\\} f\\$\\}" test list-1.12 {basic tests} "list g\\;} h\\\\} " "g\\;\\} {h\\}}" test list-1.13 {basic tests} {list a {{}} b} {a {{}} b} test list-1.14 {basic tests} {list a b xy\\} "a b xy\\\\" test list-1.15 {basic tests} "list a b\} e\\" "a b\\} e\\\\" test list-1.16 {basic tests} "list a b\}\\\$ e\\\$\\" "a b\\}\\\$ e\\\$\\\\" test list-1.17 {basic tests} {list a\f \{\f} "{a\f} \\\{\\f" test list-1.18 {basic tests} {list a\r \{\r} "{a\r} \\\{\\r" test list-1.19 {basic tests} {list a\v \{\v} "{a\v} \\\{\\v" test list-1.20 {basic tests} {list \"\}\{} "\\\"\\}\\{" test list-1.21 {basic tests} {list a b c\\\nd} "a b c\\\\\\nd" test list-1.22 {basic tests} {list "{ab}\\"} \\{ab\\}\\\\ test list-1.23 {basic tests} {list \{} "\\{" test list-1.24 {basic tests} {list} {} # For the next round of tests create a list and then pick it apart # with "index" to make sure that we get back exactly what went in. set num 0 proc lcheck {testid a b c} { global num d set d [list $a $b $c] test ${testid}-0 {what goes in must come out} {lindex $d 0} $a test ${testid}-1 {what goes in must come out} {lindex $d 1} $b test ${testid}-2 {what goes in must come out} {lindex $d 2} $c } lcheck list-2.1 a b c lcheck list-2.2 "a b" c\td e\nf lcheck list-2.3 {{a b}} {} { } lcheck list-2.4 \$ \$ab ab\$ lcheck list-2.5 \; \;ab ab\; lcheck list-2.6 \[ \[ab ab\[ lcheck list-2.7 \\ \\ab ab\\ lcheck list-2.8 {"} {"ab} {ab"} ;#" Stupid emacs highlighting! lcheck list-2.9 {a b} { ab} {ab } lcheck list-2.10 a{ a{b \{ab lcheck list-2.11 a} a}b }ab lcheck list-2.12 a\\} {a \}b} {a \{c} lcheck list-2.13 xyz \\ 1\\\n2 lcheck list-2.14 "{ab}\\" "{ab}xy" abc concat {} # Check that tclListObj.c's SetListFromAny handles possible overlarge # string rep lengths in the source object. proc slowsort list { set result {} set last [expr [llength $list] - 1] while {$last > 0} { set minIndex [expr [llength $list] - 1] set min [lindex $list $last] set i [expr $minIndex-1] while {$i >= 0} { if {[string compare [lindex $list $i] $min] < 0} { set minIndex $i set min [lindex $list $i] } set i [expr $i-1] } set result [concat $result [list $min]] if {$minIndex == 0} { set list [lrange $list 1 end] } else { set list [concat [lrange $list 0 [expr $minIndex-1]] \ [lrange $list [expr $minIndex+1] end]] } set last [expr $last-1] } return [concat $result $list] } test list-3.1 {SetListFromAny and lrange/concat results} { slowsort {fred julie alex carol bill annie} } {alex annie bill carol fred julie} # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/winPipe.test0000644003604700454610000004261311737050674014403 0ustar dgp771div# # winPipe.test -- # # This file contains a collection of tests for tclWinPipe.c # # Sourcing this file into Tcl runs the tests and generates output for # errors. No output means no errors were found. # # Copyright (c) 1996 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. package require tcltest namespace import -force ::tcltest::* unset -nocomplain path testConstraint exec [llength [info commands exec]] set bindir [file join [pwd] [file dirname [info nameofexecutable]]] set cat32 [file join $bindir cat32.exe] set ::tcltest::testConstraints(cat32) [file exists $cat32] if {[catch {puts console1 ""}]} { set ::tcltest::testConstraints(AllocConsole) 1 } else { set ::tcltest::testConstraints(.console) 1 } set big bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n append big $big append big $big append big $big append big $big append big $big append big $big set path(little) [makeFile {} little] set f [open $path(little) w] puts -nonewline $f "little" close $f set path(big) [makeFile {} big] set f [open $path(big) w] puts -nonewline $f $big close $f proc contents {file} { set f [open $file r] set r [read $f] close $f set r } set path(more) [makeFile { while {[eof stdin] == 0} { puts -nonewline [read stdin] } } more] set path(stdout) [makeFile {} stdout] set path(stderr) [makeFile {} stderr] test winpipe-1.1 {32 bit comprehensive tests: from little file} {pcOnly exec cat32} { exec $cat32 < $path(little) > $path(stdout) 2> $path(stderr) list [contents $path(stdout)] [contents $path(stderr)] } {little stderr32} test winpipe-1.2 {32 bit comprehensive tests: from big file} {pcOnly exec cat32} { exec $cat32 < $path(big) > $path(stdout) 2> $path(stderr) list [contents $path(stdout)] [contents $path(stderr)] } "{$big} stderr32" test winpipe-1.3 {32 bit comprehensive tests: a little from pipe} {pcOnly nt exec cat32} { exec [interpreter] more < little | $cat32 > $path(stdout) 2> $path(stderr) list [contents $path(stdout)] [contents $path(stderr)] } {little stderr32} test winpipe-1.4 {32 bit comprehensive tests: a lot from pipe} {pcOnly nt exec cat32} { exec [interpreter] more < big | $cat32 > $path(stdout) 2> $path(stderr) list [contents $path(stdout)] [contents $path(stderr)] } "{$big} stderr32" test winpipe-1.5 {32 bit comprehensive tests: a lot from pipe} {pcOnly 95 exec cat32} { exec command /c type big |& $cat32 > $path(stdout) 2> $path(stderr) list [contents $path(stdout)] [contents $path(stderr)] } "{$big} stderr32" test winpipe-1.6 {32 bit comprehensive tests: from console} \ {pcOnly cat32 AllocConsole} { # would block waiting for human input } {} test winpipe-1.7 {32 bit comprehensive tests: from NUL} {pcOnly exec cat32} { exec $cat32 < nul > $path(stdout) 2> $path(stderr) list [contents $path(stdout)] [contents $path(stderr)] } {{} stderr32} test winpipe-1.8 {32 bit comprehensive tests: from socket} {pcOnly cat32} { # doesn't work } {} test winpipe-1.9 {32 bit comprehensive tests: from nowhere} \ {pcOnly exec cat32 .console} { exec $cat32 > $path(stdout) 2> $path(stderr) list [contents $path(stdout)] [contents $path(stderr)] } {{} stderr32} test winpipe-1.10 {32 bit comprehensive tests: from file handle} \ {pcOnly exec cat32} { set f [open $path(little) r] exec $cat32 <@$f > $path(stdout) 2> $path(stderr) close $f list [contents $path(stdout)] [contents $path(stderr)] } {little stderr32} test winpipe-1.11 {32 bit comprehensive tests: read from application} \ {pcOnly exec cat32} { set f [open "|[list $cat32] < $path(little)" r] gets $f line catch {close $f} msg list $line $msg } {little stderr32} test winpipe-1.12 {32 bit comprehensive tests: a little to file} \ {pcOnly exec cat32} { exec $cat32 < $path(little) > $path(stdout) 2> $path(stderr) list [contents $path(stdout)] [contents $path(stderr)] } {little stderr32} test winpipe-1.13 {32 bit comprehensive tests: a lot to file} \ {pcOnly exec cat32} { exec $cat32 < $path(big) > $path(stdout) 2> $path(stderr) list [contents $path(stdout)] [contents $path(stderr)] } "{$big} stderr32" test winpipe-1.14 {32 bit comprehensive tests: a little to pipe} \ {pcOnly exec stdio cat32} { exec $cat32 < $path(little) | [interpreter] $path(more) > $path(stdout) 2> $path(stderr) list [contents $path(stdout)] [contents $path(stderr)] } {little stderr32} test winpipe-1.15 {32 bit comprehensive tests: a lot to pipe} \ {pcOnly exec stdio cat32} { exec $cat32 < $path(big) | [interpreter] $path(more) > $path(stdout) 2> $path(stderr) list [contents $path(stdout)] [contents $path(stderr)] } "{$big} stderr32" test winpipe-1.16 {32 bit comprehensive tests: to console} {pcOnly exec cat32} { catch {exec $cat32 << "You should see this\n" >@stdout} msg set msg } stderr32 test winpipe-1.17 {32 bit comprehensive tests: to NUL} {pcOnly exec cat32} { # some apps hang when sending a large amount to NUL. $cat32 isn't one. catch {exec $cat32 < $path(big) > nul} msg set msg } stderr32 test winpipe-1.18 {32 bit comprehensive tests: to nowhere} \ {pcOnly exec cat32 .console} { exec $cat32 < $path(big) >&@stdout } {} test winpipe-1.19 {32 bit comprehensive tests: to file handle} {pcOnly exec cat32} { set f1 [open $path(stdout) w] set f2 [open $path(stderr) w] exec $cat32 < $path(little) >@$f1 2>@$f2 close $f1 close $f2 list [contents $path(stdout)] [contents $path(stderr)] } {little stderr32} test winpipe-1.20 {32 bit comprehensive tests: write to application} \ {pcOnly exec cat32} { set f [open |[list $cat32 >$path(stdout)] w] puts -nonewline $f "foo" catch {close $f} msg list [contents $path(stdout)] $msg } {foo stderr32} test winpipe-1.21 {32 bit comprehensive tests: read/write application} \ {pcOnly exec cat32} { set f [open "|[list $cat32]" r+] puts $f $big puts $f \032 flush $f set r [read $f 64] catch {close $f} set r } "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" test winpipe-1.22 {Checking command.com for Win95/98 hanging} {pcOnly 95 exec} { exec command.com /c dir /b set result 1 } 1 file delete more test winpipe-4.1 {Tcl_WaitPid} {pcOnly nt exec cat32} { proc readResults {f} { global x result if { [eof $f] } { close $f set x 1 } else { set line [read $f ] set result "$result$line" } } set f [open "|[list $cat32] < big 2> $path(stderr)" r] fconfigure $f -buffering none -blocking 0 fileevent $f readable "readResults $f" set x 0 set result "" vwait x list $result $x [contents $path(stderr)] } "{$big} 1 stderr32" test winpipe-4.2 {Tcl_WaitPid: return of exception codes, SIGFPE} {pcOnly exec} { set f [open "|[tcltest::interpreter]" w+] set pid [pid $f] puts $f "testexcept float_underflow" set status [catch {close $f}] list $status [expr {$pid == [lindex $::errorCode 1]}] [lindex $::errorCode 2] } {1 1 SIGFPE} test winpipe-4.3 {Tcl_WaitPid: return of exception codes, SIGSEGV} {pcOnly exec} { set f [open "|[tcltest::interpreter]" w+] set pid [pid $f] puts $f "testexcept access_violation" set status [catch {close $f}] list $status [expr {$pid == [lindex $::errorCode 1]}] [lindex $::errorCode 2] } {1 1 SIGSEGV} test winpipe-4.4 {Tcl_WaitPid: return of exception codes, SIGILL} {pcOnly exec} { set f [open "|[tcltest::interpreter]" w+] set pid [pid $f] puts $f "testexcept illegal_instruction" set status [catch {close $f}] list $status [expr {$pid == [lindex $::errorCode 1]}] [lindex $::errorCode 2] } {1 1 SIGILL} test winpipe-4.5 {Tcl_WaitPid: return of exception codes, SIGINT} {pcOnly exec} { set f [open "|[tcltest::interpreter]" w+] set pid [pid $f] puts $f "testexcept ctrl+c" set status [catch {close $f}] list $status [expr {$pid == [lindex $::errorCode 1]}] [lindex $::errorCode 2] } {1 1 SIGINT} set path(nothing) [makeFile {} nothing] close [open $path(nothing) w] catch {set env_tmp $env(TMP)} catch {set env_temp $env(TEMP)} set env(TMP) c:/ set env(TEMP) c:/ test winpipe-5.1 {TclpCreateTempFile: cleanup temp files} {pcOnly exec} { set x {} set existing [glob -nocomplain c:/tcl*.tmp] exec [interpreter] < nothing foreach p [glob -nocomplain c:/tcl*.tmp] { if {[lsearch $existing $p] == -1} { lappend x $p } } set x } {} test winpipe-5.2 {TclpCreateTempFile: TMP and TEMP not defined} {pcOnly exec} { set tmp $env(TMP) set temp $env(TEMP) unset env(TMP) unset env(TEMP) exec [interpreter] < nothing set env(TMP) $tmp set env(TEMP) $temp set x {} } {} test winpipe-5.3 {TclpCreateTempFile: TMP specifies non-existent directory} \ {pcOnly exec } { set tmp $env(TMP) set env(TMP) snarky exec [interpreter] < nothing set env(TMP) $tmp set x {} } {} test winpipe-5.4 {TclpCreateTempFile: TEMP specifies non-existent directory} \ {pcOnly exec} { set tmp $env(TMP) set temp $env(TEMP) unset env(TMP) set env(TEMP) snarky exec [interpreter] < nothing set env(TMP) $tmp set env(TEMP) $temp set x {} } {} test winpipe-6.1 {PipeSetupProc & PipeCheckProc: read threads} \ {pcOnly exec cat32} { set f [open "|[list $cat32]" r+] fconfigure $f -blocking 0 fileevent $f writable { set x writable } set x {} vwait x fileevent $f writable {} fileevent $f readable { lappend x readable } after 100 { lappend x timeout } vwait x puts $f foobar flush $f vwait x lappend x [read $f] after 100 { lappend x timeout } vwait x fconfigure $f -blocking 1 lappend x [catch {close $f} msg] $msg } {writable timeout readable {foobar } timeout 1 stderr32} test winpipe-6.2 {PipeSetupProc & PipeCheckProc: write threads} \ {pcOnly exec cat32} { set f [open "|[list $cat32]" r+] fconfigure $f -blocking 0 fileevent $f writable { set x writable } set x {} vwait x puts -nonewline $f $big$big$big$big flush $f after 100 { lappend x timeout } vwait x lappend x [catch {close $f} msg] $msg } {writable timeout 0 {}} set path(echoArgs.tcl) [makeFile { puts "[list $argv0 $argv]" } echoArgs.tcl] ### validate the raw output of BuildCommandLine(). ### test winpipe-7.1 {BuildCommandLine: null arguments} {pcOnly exec} { exec $env(COMSPEC) /c echo foo "" bar } {foo "" bar} test winpipe-7.2 {BuildCommandLine: null arguments} {pcOnly exec} { exec $env(COMSPEC) /c echo foo {} bar } {foo "" bar} test winpipe-7.3 {BuildCommandLine: dbl quote quoting #1} {pcOnly exec} { exec $env(COMSPEC) /c echo foo {"} bar } {foo \" bar} test winpipe-7.4 {BuildCommandLine: dbl quote quoting #2} {pcOnly exec} { exec $env(COMSPEC) /c echo foo {""} bar } {foo \"\" bar} test winpipe-7.5 {BuildCommandLine: dbl quote quoting #3} {pcOnly exec} { exec $env(COMSPEC) /c echo foo {" } bar } {foo "\" " bar} test winpipe-7.6 {BuildCommandLine: dbl quote quoting #4} {pcOnly exec} { exec $env(COMSPEC) /c echo foo {a="b"} bar } {foo a=\"b\" bar} test winpipe-7.7 {BuildCommandLine: dbl quote quoting #5} {pcOnly exec} { exec $env(COMSPEC) /c echo foo {a = "b"} bar } {foo "a = \"b\"" bar} test winpipe-7.8 {BuildCommandLine: dbl quote quoting #6} {pcOnly exec} { exec $env(COMSPEC) /c echo {"hello"} {""hello""} {"""hello"""} {"\"hello\""} {he llo} {he " llo} } {\"hello\" \"\"hello\"\" \"\"\"hello\"\"\" \"\\\"hello\\\"\" "he llo" "he \" llo"} test winpipe-7.9 {BuildCommandLine: N backslashes followed a quote rule #1} {pcOnly exec} { exec $env(COMSPEC) /c echo foo \\ bar } {foo \ bar} test winpipe-7.10 {BuildCommandLine: N backslashes followed a quote rule #2} {pcOnly exec} { exec $env(COMSPEC) /c echo foo \\\\ bar } {foo \\ bar} test winpipe-7.11 {BuildCommandLine: N backslashes followed a quote rule #3} {pcOnly exec} { exec $env(COMSPEC) /c echo foo \\\ \\ bar } {foo "\ \\" bar} test winpipe-7.12 {BuildCommandLine: N backslashes followed a quote rule #4} {pcOnly exec} { exec $env(COMSPEC) /c echo foo \\\ \\\\ bar } {foo "\ \\\\" bar} test winpipe-7.13 {BuildCommandLine: N backslashes followed a quote rule #5} {pcOnly exec} { exec $env(COMSPEC) /c echo foo \\\ \\\\\\ bar } {foo "\ \\\\\\" bar} test winpipe-7.14 {BuildCommandLine: N backslashes followed a quote rule #6} {pcOnly exec} { exec $env(COMSPEC) /c echo foo \\\ \\\" bar } {foo "\ \\\"" bar} test winpipe-7.15 {BuildCommandLine: N backslashes followed a quote rule #7} {pcOnly exec} { exec $env(COMSPEC) /c echo foo \\\ \\\\\" bar } {foo "\ \\\\\"" bar} test winpipe-7.16 {BuildCommandLine: N backslashes followed a quote rule #8} {pcOnly exec} { exec $env(COMSPEC) /c echo foo \\\ \\\\\\\" bar } {foo "\ \\\\\\\"" bar} test winpipe-7.17 {BuildCommandLine: special chars #4} {pcOnly exec} { exec $env(COMSPEC) /c echo foo \{ bar } "foo \{ bar" test winpipe-7.18 {BuildCommandLine: special chars #5} {pcOnly exec} { exec $env(COMSPEC) /c echo foo \} bar } "foo \} bar" ### validate the pass-thru from BuildCommandLine() to the crt's parse_cmdline(). ### test winpipe-8.1 {BuildCommandLine/parse_cmdline pass-thru: null arguments} {pcOnly exec} { exec [interpreter] $path(echoArgs.tcl) foo "" bar } [list $path(echoArgs.tcl) [list foo {} bar]] test winpipe-8.2 {BuildCommandLine/parse_cmdline pass-thru: null arguments} {pcOnly exec} { exec [interpreter] $path(echoArgs.tcl) foo {} bar } [list $path(echoArgs.tcl) [list foo {} bar]] test winpipe-8.3 {BuildCommandLine/parse_cmdline pass-thru: dbl quote quoting #1} {pcOnly exec} { exec [interpreter] $path(echoArgs.tcl) foo {"} bar } [list $path(echoArgs.tcl) [list foo {"} bar]] test winpipe-8.4 {BuildCommandLine/parse_cmdline pass-thru: dbl quote quoting #2} {pcOnly exec} { exec [interpreter] $path(echoArgs.tcl) foo {""} bar } [list $path(echoArgs.tcl) [list foo {""} bar]] test winpipe-8.5 {BuildCommandLine/parse_cmdline pass-thru: dbl quote quoting #3} {pcOnly exec} { exec [interpreter] $path(echoArgs.tcl) foo {" } bar } [list $path(echoArgs.tcl) [list foo {" } bar]] test winpipe-8.6 {BuildCommandLine/parse_cmdline pass-thru: dbl quote quoting #4} {pcOnly exec} { exec [interpreter] $path(echoArgs.tcl) foo {a="b"} bar } [list $path(echoArgs.tcl) [list foo {a="b"} bar]] test winpipe-8.7 {BuildCommandLine/parse_cmdline pass-thru: dbl quote quoting #5} {pcOnly exec} { exec [interpreter] $path(echoArgs.tcl) foo {a = "b"} bar } [list $path(echoArgs.tcl) [list foo {a = "b"} bar]] test winpipe-8.8 {BuildCommandLine/parse_cmdline pass-thru: dbl quote quoting #6} {pcOnly exec} { exec [interpreter] $path(echoArgs.tcl) {"hello"} {""hello""} {"""hello"""} {"\"hello\""} {he llo} {he " llo} } [list $path(echoArgs.tcl) [list {"hello"} {""hello""} {"""hello"""} {"\"hello\""} {he llo} {he " llo}]] test winpipe-8.9 {BuildCommandLine/parse_cmdline pass-thru: N backslashes followed a quote rule #1} {pcOnly exec} { exec [interpreter] $path(echoArgs.tcl) foo \\ bar } [list $path(echoArgs.tcl) [list foo \\ bar]] test winpipe-8.10 {BuildCommandLine/parse_cmdline pass-thru: N backslashes followed a quote rule #2} {pcOnly exec} { exec [interpreter] $path(echoArgs.tcl) foo \\\\ bar } [list $path(echoArgs.tcl) [list foo \\\\ bar]] test winpipe-8.11 {BuildCommandLine/parse_cmdline pass-thru: N backslashes followed a quote rule #3} {pcOnly exec} { exec [interpreter] $path(echoArgs.tcl) foo \\\ \\ bar } [list $path(echoArgs.tcl) [list foo \\\ \\ bar]] test winpipe-8.12 {BuildCommandLine/parse_cmdline pass-thru: N backslashes followed a quote rule #4} {pcOnly exec} { exec [interpreter] $path(echoArgs.tcl) foo \\\ \\\\ bar } [list $path(echoArgs.tcl) [list foo \\\ \\\\ bar]] test winpipe-8.13 {BuildCommandLine/parse_cmdline pass-thru: N backslashes followed a quote rule #5} {pcOnly exec} { exec [interpreter] $path(echoArgs.tcl) foo \\\ \\\\\\ bar } [list $path(echoArgs.tcl) [list foo \\\ \\\\\\ bar]] test winpipe-8.14 {BuildCommandLine/parse_cmdline pass-thru: N backslashes followed a quote rule #6} {pcOnly exec} { exec [interpreter] $path(echoArgs.tcl) foo \\\ \\\" bar } [list $path(echoArgs.tcl) [list foo \\\ \\\" bar]] test winpipe-8.15 {BuildCommandLine/parse_cmdline pass-thru: N backslashes followed a quote rule #7} {pcOnly exec} { exec [interpreter] $path(echoArgs.tcl) foo \\\ \\\\\" bar } [list $path(echoArgs.tcl) [list foo \\\ \\\\\" bar]] test winpipe-8.16 {BuildCommandLine/parse_cmdline pass-thru: N backslashes followed a quote rule #8} {pcOnly exec} { exec [interpreter] $path(echoArgs.tcl) foo \\\ \\\\\\\" bar } [list $path(echoArgs.tcl) [list foo \\\ \\\\\\\" bar]] test winpipe-8.17 {BuildCommandLine/parse_cmdline pass-thru: special chars #1} {pcOnly exec} { exec [interpreter] $path(echoArgs.tcl) foo \{ bar } [list $path(echoArgs.tcl) [list foo \{ bar]] test winpipe-8.18 {BuildCommandLine/parse_cmdline pass-thru: special chars #2} {pcOnly exec} { exec [interpreter] $path(echoArgs.tcl) foo \} bar } [list $path(echoArgs.tcl) [list foo \} bar]] test winpipe-8.19 {ensure parse_cmdline isn't doing wildcard replacement} {pcOnly exec} { exec [interpreter] $path(echoArgs.tcl) foo * makefile.?c bar } [list $path(echoArgs.tcl) [list foo * makefile.?c bar]] # restore old values for env(TMP) and env(TEMP) if {[catch {set env(TMP) $env_tmp}]} { unset env(TMP) } if {[catch {set env(TEMP) $env_temp}]} { unset env(TEMP) } # cleanup file delete big little stdout stderr nothing echoArgs.tcl ::tcltest::cleanupTests return tcl8.4.20/tests/pid.test0000644003604700454610000000365411737050674013546 0ustar dgp771div# Commands covered: pid # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994-1995 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import -force ::tcltest::* } # If pid is not defined just return with no error # Some platforms may not have the pid command implemented if {[info commands pid] == ""} { puts "pid is not implemented for this machine" ::tcltest::cleanupTests return } test pid-1.1 {pid command} { regexp {(^[0-9]+$)|(^0x[0-9a-fA-F]+$)} [pid] } 1 test pid-1.2 {pid command} -constraints {unixOrPc unixExecs} -setup { set path(test1) [makeFile {} test1] file delete $path(test1) } -body { set f [open |[list echo foo | cat >$path(test1)] w] set pids [pid $f] close $f list [llength $pids] [regexp {^[0-9]+$} [lindex $pids 0]] \ [regexp {^[0-9]+$} [lindex $pids 1]] \ [expr {[lindex $pids 0] == [lindex $pids 1]}] } -cleanup { removeFile test1 } -result {2 1 1 0} test pid-1.3 {pid command} -setup { set path(test1) [makeFile {} test1] file delete $path(test1) } -body { set f [open $path(test1) w] set pids [pid $f] close $f set pids } -cleanup { removeFile test1 } -result {} test pid-1.4 {pid command} { list [catch {pid a b} msg] $msg } {1 {wrong # args: should be "pid ?channelId?"}} test pid-1.5 {pid command} { list [catch {pid gorp} msg] $msg } {1 {can not find channel named "gorp"}} # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/winTime.test0000644003604700454610000000365511737050674014407 0ustar dgp771div# This file tests the tclWinTime.c file. # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1997 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } testConstraint testwinclock [llength [info commands testwinclock]] # The next two tests will crash on Windows if the check for negative # clock values is not done properly. test winTime-1.1 {TclpGetDate} {pcOnly} { set ::env(TZ) JST-9 set result [clock format -1 -format %Y] unset ::env(TZ) set result } {1970} test winTime-1.2 {TclpGetDate} {pcOnly} { set ::env(TZ) PST8 set result [clock format 1 -format %Y] unset ::env(TZ) set result } {1969} # Next test tries to make sure that the Tcl clock stays in step # with the Windows clock. 30 sec really isn't enough, # but how much time does a tester have patience for? test winTime-2.1 {Synchronization of Tcl and Windows clocks} {testwinclock} { # May fail due to OS/hardware discrepancies. See: # http://support.microsoft.com/default.aspx?scid=kb;en-us;274323 set failed {} set ok 1 foreach start_sec [testwinclock] break while { 1 } { foreach { sys_sec sys_usec tcl_sec tcl_usec } [testwinclock] break set diff [expr { $tcl_sec - $sys_sec + 1.0e-6 * ( $tcl_usec - $sys_usec ) }] if { abs($diff) > 0.06 } { set failed "Tcl clock differs from system clock by $diff sec" break } else { testwinsleep 1 } if { $sys_sec - $start_sec >= 30 } break } set failed } {} # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/reg.test0000644003604700454610000007356111737050674013553 0ustar dgp771div# reg.test -- # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # (Don't panic if you are seeing this as part of the reg distribution # and aren't using Tcl -- reg's own regression tester also knows how # to read this file, ignoring the Tcl-isms.) # # Copyright (c) 1998, 1999 Henry Spencer. All rights reserved. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import -force ::tcltest::* } # All tests require the testregexp command, return if this # command doesn't exist ::tcltest::testConstraint testregexp \ [expr {[info commands testregexp] != {}}] ::tcltest::testConstraint localeRegexp 0 # This file uses some custom procedures, defined below, for regexp regression # testing. The name of the procedure indicates the general nature of the # test: # e compile error expected # f match failure expected # m successful match # i successful match with -indices (used in checking things like # nonparticipating subexpressions) # p unsuccessful match with -indices (!!) (used in checking # partial-match reporting) # There is also "doing" which sets up title and major test number for each # block of tests. # The first 3 arguments are constant: a minor number (which often gets # a letter or two suffixed to it internally), some flags, and the RE itself. # For e, the remaining argument is the name of the compile error expected, # less the leading "REG_". For the rest, the next argument is the string # to try the match against. Remaining arguments are the substring expected # to be matched, and any substrings expected to be matched by subexpressions. # (For f, these arguments are optional, and if present are ignored except # that they indicate how many subexpressions should be present in the RE.) # It is an error for the number of subexpression arguments to be wrong. # Cases involving nonparticipating subexpressions, checking where empty # substrings are located, etc. should be done using i and p. # The flag characters are complex and a bit eclectic. Generally speaking, # lowercase letters are compile options, uppercase are expected re_info # bits, and nonalphabetics are match options, controls for how the test is # run, or testing options. The one small surprise is that AREs are the # default, and you must explicitly request lesser flavors of RE. The flags # are as follows. It is admitted that some are not very mnemonic. # There are some others which are purely debugging tools and are not # useful in this file. # # - no-op (placeholder) # + provide fake xy equivalence class and ch collating element # % force small state-set cache in matcher (to test cache replace) # ^ beginning of string is not beginning of line # $ end of string is not end of line # * test is Unicode-specific, needs big character set # # & test as both ARE and BRE # b BRE # e ERE # a turn advanced-features bit on (error unless ERE already) # q literal string, no metacharacters at all # # i case-independent matching # o ("opaque") no subexpression capture # p newlines are half-magic, excluded from . and [^ only # w newlines are half-magic, significant to ^ and $ only # n newlines are fully magic, both effects # x expanded RE syntax # t incomplete-match reporting # # A backslash-_a_lphanumeric seen # B ERE/ARE literal-_b_race heuristic used # E backslash (_e_scape) seen within [] # H looka_h_ead constraint seen # I _i_mpossible to match # L _l_ocale-specific construct seen # M unportable (_m_achine-specific) construct seen # N RE can match empty (_n_ull) string # P non-_P_OSIX construct seen # Q {} _q_uantifier seen # R back _r_eference seen # S POSIX-un_s_pecified syntax seen # T prefers shortest (_t_iny) # U saw original-POSIX botch: unmatched right paren in ERE (_u_gh) # The one area we can't easily test is memory-allocation failures (which # are hard to provoke on command). Embedded NULs also are not tested at # the moment, but this is a historical accident which should be fixed. # test procedures and related set ask "about" set xflags "xflags" set testbypassed 0 # re_info abbreviation mapping table set infonames(A) "REG_UBSALNUM" set infonames(B) "REG_UBRACES" set infonames(E) "REG_UBBS" set infonames(H) "REG_ULOOKAHEAD" set infonames(I) "REG_UIMPOSSIBLE" set infonames(L) "REG_ULOCALE" set infonames(M) "REG_UUNPORT" set infonames(N) "REG_UEMPTYMATCH" set infonames(P) "REG_UNONPOSIX" set infonames(Q) "REG_UBOUNDS" set infonames(R) "REG_UBACKREF" set infonames(S) "REG_UUNSPEC" set infonames(T) "REG_USHORTEST" set infonames(U) "REG_UPBOTCH" set infonameorder "RHQBAUEPSMLNIT" ;# must match bit order, lsb first # set major test number and description proc doing {major desc} { global prefix description testbypassed if {$testbypassed != 0} { puts stdout "!!! bypassed $testbypassed tests in\ $prefix, `$description'" } set prefix reg-$major set description "reg $desc" set testbypassed 0 } # build test number (internal) proc tno {testid} { return [join $testid .] } # build description, with possible modifiers (internal) proc desc {testid} { global description set d $description if {[llength $testid] > 1} { set d "([lreplace $testid 0 0]) $d" } return $d } # build trailing options and flags argument from a flags string (internal) proc flags {fl} { global xflags set args [list] set flags "" foreach f [split $fl ""] { switch -exact -- $f { "i" { lappend args "-nocase" } "x" { lappend args "-expanded" } "n" { lappend args "-line" } "p" { lappend args "-linestop" } "w" { lappend args "-lineanchor" } "-" { } default { append flags $f } } } if {[string compare $flags ""] != 0} { lappend args -$xflags $flags } return $args } # build info-flags list from a flags string (internal) proc infoflags {fl} { global infonames infonameorder set ret [list] foreach f [split $infonameorder ""] { if {[string first $f $fl] >= 0} { lappend ret $infonames($f) } } return $ret } # compilation error expected proc e {testid flags re err} { global prefix ask errorCode # Tcl locale stuff doesn't do the ch/xy test fakery yet if {[string first "+" $flags] >= 0} { # This will register as a skipped test test $prefix.[tno $testid] [desc $testid] localeRegexp {} {} return } # if &, test as both ARE and BRE set amp [string first "&" $flags] if {$amp >= 0} { set f [string range $flags 0 [expr $amp - 1]] append f [string range $flags [expr $amp + 1] end] e [linsert $testid end ARE] ${f} $re $err e [linsert $testid end BRE] ${f}b $re $err return } set cmd [concat [list testregexp -$ask] [flags $flags] [list $re]] set run "list \[catch \{$cmd\}\] \[lindex \$errorCode 1\]" test $prefix.[tno $testid] [desc $testid] \ {testregexp} $run [list 1 REG_$err] } # match failure expected proc f {testid flags re target args} { global prefix description ask # Tcl locale stuff doesn't do the ch/xy test fakery yet if {[string first "+" $flags] >= 0} { # This will register as a skipped test test $prefix.[tno $testid] [desc $testid] localeRegexp {} {} return } # if &, test as both ARE and BRE set amp [string first "&" $flags] if {$amp >= 0} { set f [string range $flags 0 [expr $amp - 1]] append f [string range $flags [expr $amp + 1] end] eval [linsert $args 0 f [linsert $testid end ARE] ${f} $re \ $target] eval [linsert $args 0 f [linsert $testid end BRE] ${f}b $re \ $target] return } set f [flags $flags] set infoflags [infoflags $flags] set ccmd [concat [list testregexp -$ask] $f [list $re]] set nsub [expr [llength $args] - 1] if {$nsub == -1} { # didn't tell us number of subexps set ccmd "lreplace \[$ccmd\] 0 0" set info [list $infoflags] } else { set info [list $nsub $infoflags] } lappend testid "compile" test $prefix.[tno $testid] [desc $testid] {testregexp} $ccmd $info set testid [lreplace $testid end end "execute"] set ecmd [concat [list testregexp] $f [list $re $target]] test $prefix.[tno $testid] [desc $testid] {testregexp} $ecmd 0 } # match expected, internal routine that does the work # parameters like the "real" routines except they don't have "opts", # which is a possibly-empty list of switches for the regexp match attempt # The ! flag is used to indicate expected match failure (for REG_EXPECT, # which wants argument testing even in the event of failure). proc matchexpected {opts testid flags re target args} { global prefix description ask regBug if {[info exists regBug] && $regBug} { # This will register as a skipped test test $prefix.[tno $testid] [desc $testid] knownBug {format 0} {1} return } # Tcl locale stuff doesn't do the ch/xy test fakery yet if {[string first "+" $flags] >= 0} { # This will register as a skipped test test $prefix.[tno $testid] [desc $testid] localeRegexp {} {} return } # if &, test as both BRE and ARE set amp [string first "&" $flags] if {$amp >= 0} { set f [string range $flags 0 [expr $amp - 1]] append f [string range $flags [expr $amp + 1] end] eval [concat [list matchexpected $opts \ [linsert $testid end ARE] ${f} $re $target] $args] eval [concat [list matchexpected $opts \ [linsert $testid end BRE] ${f}b $re $target] $args] return } set f [flags $flags] set infoflags [infoflags $flags] set ccmd [concat [list testregexp -$ask] $f [list $re]] set ecmd [concat [list testregexp] $opts $f [list $re $target]] set nsub [expr [llength $args] - 1] set names [list] set refs "" for {set i 0} {$i <= $nsub} {incr i} { if {$i == 0} { set name match } else { set name sub$i } lappend names $name append refs " \$$name" set $name "" } if {[string first "o" $flags] >= 0} { ;# REG_NOSUB kludge set nsub 0 ;# unsigned value cannot be -1 } if {[string first "t" $flags] >= 0} { ;# REG_EXPECT incr nsub -1 ;# the extra does not count } set ecmd [concat $ecmd $names] set erun "list \[$ecmd\] $refs" set retcode [list 1] if {[string first "!" $flags] >= 0} { set retcode [list 0] } set result [concat $retcode $args] set info [list $nsub $infoflags] lappend testid "compile" test $prefix.[tno $testid] [desc $testid] {testregexp} $ccmd $info set testid [lreplace $testid end end "execute"] test $prefix.[tno $testid] [desc $testid] {testregexp} $erun $result } # match expected (no missing, empty, or ambiguous submatches) # m testno flags re target mat submat ... proc m {args} { eval matchexpected [linsert $args 0 [list]] } # match expected (full fanciness) # i testno flags re target mat submat ... proc i {args} { eval matchexpected [linsert $args 0 [list "-indices"]] } # partial match expected # p testno flags re target mat "" ... # Quirk: number of ""s must be one more than number of subREs. proc p {args} { set f [lindex $args 1] ;# add ! flag set args [lreplace $args 1 1 "!$f"] eval matchexpected [linsert $args 0 [list "-indices"]] } # test is a knownBug proc knownBug {args} { set ::regBug 1 uplevel #0 $args set ::regBug 0 } # the tests themselves # support functions and preliminary misc. # This is sensitive to changes in message wording, but we really have to # test the code->message expansion at least once. test reg-0.1 "regexp error reporting" { list [catch {regexp (*) ign} msg] $msg } {1 {couldn't compile regular expression pattern: quantifier operand invalid}} doing 1 "basic sanity checks" m 1 & abc abc abc f 2 & abc def m 3 & abc xyabxabce abc doing 2 "invalid option combinations" e 1 qe a INVARG e 2 qa a INVARG e 3 qx a INVARG e 4 qn a INVARG e 5 ba a INVARG doing 3 "basic syntax" i 1 &NS "" a {0 -1} m 2 NS a| a a m 3 - a|b a a m 4 - a|b b b m 5 NS a||b b b m 6 & ab ab ab doing 4 "parentheses" m 1 - (a)e ae ae a m 2 o (a)e ae m 3 b {\(a\)b} ab ab a m 4 - a((b)c) abc abc bc b m 5 - a(b)(c) abc abc b c e 6 - a(b EPAREN e 7 b {a\(b} EPAREN # sigh, we blew it on the specs here... someday this will be fixed in POSIX, # but meanwhile, it's fixed in AREs m 8 eU a)b a)b a)b e 9 - a)b EPAREN e 10 b {a\)b} EPAREN m 11 P a(?:b)c abc abc e 12 e a(?:b)c BADRPT i 13 S a()b ab {0 1} {1 0} m 14 SP a(?:)b ab ab i 15 S a(|b)c ac {0 1} {1 0} m 16 S a(b|)c abc abc b doing 5 "simple one-char matching" # general case of brackets done later m 1 & a.b axb axb f 2 &n "a.b" "a\nb" m 3 & {a[bc]d} abd abd m 4 & {a[bc]d} acd acd f 5 & {a[bc]d} aed f 6 & {a[^bc]d} abd m 7 & {a[^bc]d} aed aed f 8 &p "a\[^bc]d" "a\nd" doing 6 "context-dependent syntax" # plus odds and ends e 1 - * BADRPT m 2 b * * * m 3 b {\(*\)} * * * e 4 - (*) BADRPT m 5 b ^* * * e 6 - ^* BADRPT f 7 & ^b ^b m 8 b x^ x^ x^ f 9 I x^ x m 10 n "\n^" "x\nb" "\n" f 11 bS {\(^b\)} ^b m 12 - (^b) b b b m 13 & {x$} x x m 14 bS {\(x$\)} x x x m 15 - {(x$)} x x x m 16 b {x$y} "x\$y" "x\$y" f 17 I {x$y} xy m 18 n "x\$\n" "x\n" "x\n" e 19 - + BADRPT e 20 - ? BADRPT doing 7 "simple quantifiers" m 1 &N a* aa aa i 2 &N a* b {0 -1} m 3 - a+ aa aa m 4 - a?b ab ab m 5 - a?b b b e 6 - ** BADRPT m 7 bN ** *** *** e 8 & a** BADRPT e 9 & a**b BADRPT e 10 & *** BADRPT e 11 - a++ BADRPT e 12 - a?+ BADRPT e 13 - a?* BADRPT e 14 - a+* BADRPT e 15 - a*+ BADRPT doing 8 "braces" m 1 NQ "a{0,1}" "" "" m 2 NQ "a{0,1}" ac a e 3 - "a{1,0}" BADBR e 4 - "a{1,2,3}" BADBR e 5 - "a{257}" BADBR e 6 - "a{1000}" BADBR e 7 - "a{1" EBRACE e 8 - "a{1n}" BADBR m 9 BS "a{b" "a\{b" "a\{b" m 10 BS "a{" "a\{" "a\{" m 11 bQ "a\\{0,1\\}b" cb b e 12 b "a\\{0,1" EBRACE e 13 - "a{0,1\\" BADBR m 14 Q "a{0}b" ab b m 15 Q "a{0,0}b" ab b m 16 Q "a{0,1}b" ab ab m 17 Q "a{0,2}b" b b m 18 Q "a{0,2}b" aab aab m 19 Q "a{0,}b" aab aab m 20 Q "a{1,1}b" aab ab m 21 Q "a{1,3}b" aaaab aaab f 22 Q "a{1,3}b" b m 23 Q "a{1,}b" aab aab f 24 Q "a{2,3}b" ab m 25 Q "a{2,3}b" aaaab aaab f 26 Q "a{2,}b" ab m 27 Q "a{2,}b" aaaab aaaab doing 9 "brackets" m 1 & {a[bc]} ac ac m 2 & {a[-]} a- a- m 3 & {a[[.-.]]} a- a- m 4 &L {a[[.zero.]]} a0 a0 m 5 &LM {a[[.zero.]-9]} a2 a2 m 6 &M {a[0-[.9.]]} a2 a2 m 7 &+L {a[[=x=]]} ax ax m 8 &+L {a[[=x=]]} ay ay f 9 &+L {a[[=x=]]} az e 10 & {a[0-[=x=]]} ERANGE m 11 &L {a[[:digit:]]} a0 a0 e 12 & {a[[:woopsie:]]} ECTYPE f 13 &L {a[[:digit:]]} ab e 14 & {a[0-[:digit:]]} ERANGE m 15 &LP {[[:<:]]a} a a m 16 &LP {a[[:>:]]} a a e 17 & {a[[..]]b} ECOLLATE e 18 & {a[[==]]b} ECOLLATE e 19 & {a[[::]]b} ECTYPE e 20 & {a[[.a} EBRACK e 21 & {a[[=a} EBRACK e 22 & {a[[:a} EBRACK e 23 & {a[} EBRACK e 24 & {a[b} EBRACK e 25 & {a[b-} EBRACK e 26 & {a[b-c} EBRACK m 27 &M {a[b-c]} ab ab m 28 & {a[b-b]} ab ab m 29 &M {a[1-2]} a2 a2 e 30 & {a[c-b]} ERANGE e 31 & {a[a-b-c]} ERANGE m 32 &M {a[--?]b} a?b a?b m 33 & {a[---]b} a-b a-b m 34 & {a[]b]c} a]c a]c m 35 EP {a[\]]b} a]b a]b f 36 bE {a[\]]b} a]b m 37 bE {a[\]]b} "a\\]b" "a\\]b" m 38 eE {a[\]]b} "a\\]b" "a\\]b" m 39 EP {a[\\]b} "a\\b" "a\\b" m 40 eE {a[\\]b} "a\\b" "a\\b" m 41 bE {a[\\]b} "a\\b" "a\\b" e 42 - {a[\Z]b} EESCAPE m 43 & {a[[b]c} "a\[c" "a\[c" m 44 EMP* {a[\u00fe-\u0507][\u00ff-\u0300]b} \ "a\u0102\u02ffb" "a\u0102\u02ffb" doing 10 "anchors and newlines" m 1 & ^a a a f 2 &^ ^a a i 3 &N ^ a {0 -1} i 4 & {a$} aba {2 2} f 5 {&$} {a$} a i 6 &N {$} ab {2 1} m 7 &n ^a a a m 8 &n "^a" "b\na" "a" i 9 &w "^a" "a\na" {0 0} i 10 &n^ "^a" "a\na" {2 2} m 11 &n {a$} a a m 12 &n "a\$" "a\nb" "a" i 13 &n "a\$" "a\na" {0 0} i 14 N ^^ a {0 -1} m 15 b ^^ ^ ^ i 16 N {$$} a {1 0} m 17 b {$$} "\$" "\$" m 18 &N {^$} "" "" f 19 &N {^$} a i 20 &nN "^\$" "a\n\nb" {2 1} m 21 N {$^} "" "" m 22 b {$^} "\$^" "\$^" m 23 P {\Aa} a a m 24 ^P {\Aa} a a f 25 ^nP {\Aa} "b\na" m 26 P {a\Z} a a m 27 {$P} {a\Z} a a f 28 {$nP} {a\Z} "a\nb" e 29 - ^* BADRPT e 30 - {$*} BADRPT e 31 - {\A*} BADRPT e 32 - {\Z*} BADRPT doing 11 "boundary constraints" m 1 &LP {[[:<:]]a} a a m 2 &LP {[[:<:]]a} -a a f 3 &LP {[[:<:]]a} ba m 4 &LP {a[[:>:]]} a a m 5 &LP {a[[:>:]]} a- a f 6 &LP {a[[:>:]]} ab m 7 bLP {\} a a f 10 bLP {a\>} ab m 11 LP {\ya} a a f 12 LP {\ya} ba m 13 LP {a\y} a a f 14 LP {a\y} ab m 15 LP {a\Y} ab a f 16 LP {a\Y} a- f 17 LP {a\Y} a f 18 LP {-\Y} -a m 19 LP {-\Y} -% - f 20 LP {\Y-} a- e 21 - {[[:<:]]*} BADRPT e 22 - {[[:>:]]*} BADRPT e 23 b {\<*} BADRPT e 24 b {\>*} BADRPT e 25 - {\y*} BADRPT e 26 - {\Y*} BADRPT m 27 LP {\ma} a a f 28 LP {\ma} ba m 29 LP {a\M} a a f 30 LP {a\M} ab f 31 ILP {\Ma} a f 32 ILP {a\m} a doing 12 "character classes" m 1 LP {a\db} a0b a0b f 2 LP {a\db} axb f 3 LP {a\Db} a0b m 4 LP {a\Db} axb axb m 5 LP "a\\sb" "a b" "a b" m 6 LP "a\\sb" "a\tb" "a\tb" m 7 LP "a\\sb" "a\nb" "a\nb" f 8 LP {a\sb} axb m 9 LP {a\Sb} axb axb f 10 LP "a\\Sb" "a b" m 11 LP {a\wb} axb axb f 12 LP {a\wb} a-b f 13 LP {a\Wb} axb m 14 LP {a\Wb} a-b a-b m 15 LP {\y\w+z\y} adze-guz guz m 16 LPE {a[\d]b} a1b a1b m 17 LPE "a\[\\s]b" "a b" "a b" m 18 LPE {a[\w]b} axb axb doing 13 "escapes" e 1 & "a\\" EESCAPE m 2 - {a\]+)>} a } 1 test reg-33.4 {Bug 505048} { regexp {\A\s*([^b]*)b} ab } 1 test reg-33.5 {Bug 505048} { regexp {\A\s*[^b]*(b)} ab } 1 test reg-33.6 {Bug 505048} { regexp {\A(\s*)[^b]*(b)} ab } 1 test reg-33.7 {Bug 505048} { regexp {\A\s*[^b]*b} ab } 1 test reg-33.8 {Bug 505048} { regexp -inline {\A\s*[^b]*b} ab } ab test reg-33.9 {Bug 505048} { regexp -indices -inline {\A\s*[^b]*b} ab } {{0 1}} test reg-33.10 {Bug 840258} { regsub {(^|\n)+\.*b} \n.b {} tmp } 1 test reg-33.11 {Bug 840258} { regsub {(^|[\n\r]+)\.*\?<.*?(\n|\r)+} \ "TQ\r\n.?<5000267>Test already stopped\r\n" {} tmp } 1 test reg-33.12 {Bug 1810264 - bad read} { regexp {\3161573148} {\3161573148} } 0 test reg-33.13 {Bug 1810264 - infinite loop} { regexp {($|^)*} {x} } 1 test reg-33.14 {Bug 1810264 - super-expensive expression} { set start [clock seconds] regexp {(x{100}){100}$y} {x} set time [expr {[clock seconds] - $start}] expr {$time < 5 ? "ok" : "Complex RE took $time seconds - bad!"} } ok # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/notify.test0000755003604700454610000002105011737050674014273 0ustar dgp771div# -*- tcl -*- # # notify.test -- # # This file tests several functions in the file, 'generic/tclNotify.c'. # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 2003 by Kevin B. Kenny. All rights reserved. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import -force ::tcltest::* } testConstraint testevent [llength [info commands testevent]] test notify-1.1 {Tcl_QueueEvent and delivery of a single event} \ -constraints {testevent} \ -body { set delivered {} after 10 set done 1 testevent queue one tail {lappend delivered one; expr 1} vwait done set delivered } \ -result {one} test notify-1.2 {Tcl_QueueEvent and delivery of events in order} \ -constraints {testevent} \ -body { set delivered {} after 10 set done 1 testevent queue one tail {lappend delivered one; expr 1} testevent queue two tail {lappend delivered two; expr 1} testevent queue three tail {lappend delivered three; expr 1} vwait done set delivered } \ -result {one two three} test notify-1.3 {Tcl_QueueEvent at head} \ -constraints {testevent} \ -body { set delivered {} after 10 set done 1 testevent queue one head {lappend delivered one; expr 1} vwait done set delivered } \ -result one test notify-1.4 {Tcl_QueueEvent multiple events at head} \ -constraints {testevent} \ -body { set delivered {} after 10 set done 1 testevent queue one head {lappend delivered one; expr 1} testevent queue two head {lappend delivered two; expr 1} testevent queue three head {lappend delivered three; expr 1} vwait done set delivered } \ -result {three two one} test notify-1.5 {Tcl_QueueEvent marker event into an empty queue} \ -constraints {testevent} \ -body { set delivered {} after 10 set done 1 testevent queue one mark {lappend delivered one; expr 1} vwait done set delivered } \ -result one test notify-1.6 {Tcl_QueueEvent first marker event in a nonempty queue} \ -constraints {testevent} \ -body { set delivered {} after 10 set done 1 testevent queue one tail {lappend delivered one; expr 1} testevent queue two mark {lappend delivered two; expr 1} testevent queue three head {lappend delivered three; expr 1} vwait done set delivered } \ -result {three two one} test notify-1.7 {Tcl_QueueEvent second marker event} \ -constraints {testevent} \ -body { set delivered {} after 10 set done 1 testevent queue one mark {lappend delivered one; expr 1} testevent queue two mark {lappend delivered two; expr 1} vwait done set delivered } \ -result {one two} test notify-1.8 {Tcl_QueueEvent preexisting event following second marker} \ -constraints {testevent} \ -body { set delivered {} after 10 set done 1 testevent queue one mark {lappend delivered one; expr 1} testevent queue two tail {lappend delivered two; expr 1} testevent queue three mark {lappend delivered three; expr 1} vwait done set delivered } \ -result {one three two} test notify-2.1 {remove sole element, don't replace } \ -constraints {testevent} \ -body { set delivered {} after 10 set done 1 testevent queue one tail {lappend delivered one; expr 1} testevent delete one vwait done set delivered } \ -result {} test notify-2.2 {remove and replace sole element} \ -constraints {testevent} \ -body { set delivered {} after 10 set done 1 testevent queue one tail {lappend delivered one; expr 1} testevent delete one testevent queue two tail {lappend delivered two; expr 1} vwait done set delivered } \ -result two test notify-2.3 {remove first element} \ -constraints {testevent} \ -body { set delivered {} after 10 set done 1 testevent queue one tail {lappend delivered one; expr 1} testevent queue two tail {lappend delivered two; expr 1} testevent delete one vwait done set delivered } \ -result {two} test notify-2.4 {remove and replace first element} \ -constraints {testevent} \ -body { set delivered {} after 10 set done 1 testevent queue one tail {lappend delivered one; expr 1} testevent queue two tail {lappend delivered two; expr 1} testevent delete one testevent queue three head {lappend delivered three; expr 1}; vwait done set delivered } \ -result {three two} test notify-2.5 {remove last element} \ -constraints {testevent} \ -body { set delivered {} after 10 set done 1 testevent queue one tail {lappend delivered one; expr 1} testevent queue two tail {lappend delivered two; expr 1} testevent delete two vwait done set delivered } \ -result {one} test notify-2.6 {remove and replace last element} \ -constraints {testevent} \ -body { set delivered {} after 10 set done 1 testevent queue one tail {lappend delivered one; expr 1} testevent queue two tail {lappend delivered two; expr 1} testevent delete two testevent queue three tail {lappend delivered three; expr 1}; vwait done set delivered } \ -result {one three} test notify-2.7 {remove a middle element} \ -constraints {testevent} \ -body { set delivered {} after 10 set done 1 testevent queue one tail {lappend delivered one; expr 1} testevent queue two tail {lappend delivered two; expr 1} testevent queue three tail {lappend delivered three; expr 1} testevent delete two vwait done set delivered } \ -result {one three} test notify-2.8 {remove a marker event that's the sole event in the queue} \ -constraints {testevent} \ -body { set delivered {} after 10 set done 1 testevent queue one mark {lappend delivered one; expr 1} testevent delete one vwait done set delivered } \ -result {} test notify-2.9 {remove and replace a marker event that's the sole event} \ -constraints {testevent} \ -body { set delivered {} after 10 set done 1 testevent queue one mark {lappend delivered one; expr 1} testevent delete one testevent queue two mark {lappend delivered two; expr 1} vwait done set delivered } \ -result two test notify-2.10 {remove marker event from head} \ -constraints {testevent} \ -body { set delivered {} after 10 set done 1 testevent queue one mark {lappend delivered one; expr 1} testevent queue two mark {lappend delivered two; expr 1} testevent delete one vwait done set delivered } \ -result two test notify-2.11 {remove and replace marker event at head} \ -constraints {testevent} \ -body { set delivered {} after 10 set done 1 testevent queue one mark {lappend delivered one; expr 1} testevent queue two tail {lappend delivered two; expr 1} testevent delete one testevent queue three mark {lappend delivered three; expr 1} vwait done set delivered } \ -result {three two} test notify-2.12 {remove marker event at tail} \ -constraints {testevent} \ -body { set delivered {} after 10 set done 1 testevent queue one mark {lappend delivered one; expr 1} testevent queue two mark {lappend delivered two; expr 1} testevent delete two vwait done set delivered } \ -result {one} test notify-2.13 {remove and replace marker event at tail} \ -constraints {testevent} \ -body { set delivered {} after 10 set done 1 testevent queue one mark {lappend delivered one; expr 1} testevent queue two mark {lappend delivered two; expr 1} testevent delete two testevent queue three mark {lappend delivered three; expr 1} vwait done set delivered } \ -result {one three} test notify-2.14 {remove marker event from middle} \ -constraints {testevent} \ -body { set delivered {} after 10 set done 1 testevent queue one mark {lappend delivered one; expr 1} testevent queue two mark {lappend delivered two; expr 1} testevent queue three mark {lappend delivered three; expr 1} testevent delete two vwait done set delivered } \ -result {one three} test notify-2.15 {remove and replace marker event at middle} \ -constraints {testevent} \ -body { set delivered {} after 10 set done 1 testevent queue one mark {lappend delivered one; expr 1} testevent queue two mark {lappend delivered two; expr 1} testevent queue three tail {lappend delivered three; expr 1} testevent delete two testevent queue four mark {lappend delivered four; expr 1}; vwait done set delivered } \ -result {one four three} # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/unknown.test0000644003604700454610000000351511737050674014465 0ustar dgp771div# Commands covered: unknown # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } catch {unset x} catch {rename unknown unknown.old} test unknown-1.1 {non-existent "unknown" command} { list [catch {_non-existent_ foo bar} msg] $msg } {1 {invalid command name "_non-existent_"}} proc unknown {args} { global x set x $args } test unknown-2.1 {calling "unknown" command} { foobar x y z set x } {foobar x y z} test unknown-2.2 {calling "unknown" command with lots of args} { foobar 1 2 3 4 5 6 7 set x } {foobar 1 2 3 4 5 6 7} test unknown-2.3 {calling "unknown" command with lots of args} { foobar 1 2 3 4 5 6 7 8 set x } {foobar 1 2 3 4 5 6 7 8} test unknown-2.4 {calling "unknown" command with lots of args} { foobar 1 2 3 4 5 6 7 8 9 set x } {foobar 1 2 3 4 5 6 7 8 9} test unknown-3.1 {argument quoting in calls to "unknown"} { foobar \{ \} a\{b \; "\\" \$a a\[b \] set x } "foobar \\{ \\} a\\{b {;} \\\\ {\$a} {a\[b} \\]" proc unknown args { error "unknown failed" } test unknown-4.1 {errors in "unknown" procedure} { list [catch {non-existent a b} msg] $msg $errorCode } {1 {unknown failed} NONE} # cleanup catch {rename unknown {}} catch {rename unknown.old unknown} ::tcltest::cleanupTests return tcl8.4.20/tests/io.test0000644003604700454610000064456012052456744013407 0ustar dgp771div# -*- tcl -*- # Functionality covered: operation of all IO commands, and all procedures # defined in generic/tclIO.c. # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1994 The Regents of the University of California. # Copyright (c) 1994-1997 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[catch {package require tcltest 2}]} { puts stderr "Skipping tests in [info script]. tcltest 2 required." return } namespace eval ::tcl::test::io { namespace import ::tcltest::cleanupTests namespace import ::tcltest::interpreter namespace import ::tcltest::makeFile namespace import ::tcltest::removeFile namespace import ::tcltest::test namespace import ::tcltest::testConstraint namespace import ::tcltest::viewFile testConstraint testchannel [llength [info commands testchannel]] testConstraint exec [llength [info commands exec]] testConstraint openpipe 1 testConstraint fileevent [llength [info commands fileevent]] testConstraint fcopy [llength [info commands fcopy]] # You need a *very* special environment to do some tests. In # particular, many file systems do not support large-files... testConstraint largefileSupport 0 # set up a long data file for some of the following tests set path(longfile) [makeFile {} longfile] set f [open $path(longfile) w] fconfigure $f -eofchar {} -translation lf for { set i 0 } { $i < 100 } { incr i} { puts $f "#123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef \#123456789abcdef01 \#" } close $f set path(cat) [makeFile { set f stdin if {$argv != ""} { set f [open [lindex $argv 0]] } fconfigure $f -encoding binary -translation lf -blocking 0 -eofchar \x1a fconfigure stdout -encoding binary -translation lf -buffering none fileevent $f readable "foo $f" proc foo {f} { set x [read $f] catch {puts -nonewline $x} if {[eof $f]} { close $f exit 0 } } vwait forever } cat] set thisScript [file join [pwd] [info script]] proc contents {file} { set f [open $file] fconfigure $f -translation binary set a [read $f] close $f return $a } test io-1.5 {Tcl_WriteChars: CheckChannelErrors} {emptyTest} { # no test, need to cause an async error. } {} set path(test1) [makeFile {} test1] test io-1.6 {Tcl_WriteChars: WriteBytes} { set f [open $path(test1) w] fconfigure $f -encoding binary puts -nonewline $f "a\u4e4d\0" close $f contents $path(test1) } "a\x4d\x00" test io-1.7 {Tcl_WriteChars: WriteChars} { set f [open $path(test1) w] fconfigure $f -encoding shiftjis puts -nonewline $f "a\u4e4d\0" close $f contents $path(test1) } "a\x93\xe1\x00" set path(test2) [makeFile {} test2] test io-1.8 {Tcl_WriteChars: WriteChars} { # This test written for SF bug #506297. # # Executing this test without the fix for the referenced bug # applied to tcl will cause tcl, more specifically WriteChars, to # go into an infinite loop. set f [open $path(test2) w] fconfigure $f -encoding iso2022-jp puts -nonewline $f [format %s%c [string repeat " " 4] 12399] close $f contents $path(test2) } " \x1b\$B\$O\x1b(B" test io-1.9 {Tcl_WriteChars: WriteChars} { # When closing a channel with an encoding that appends # escape bytes, check for the case where the escape # bytes overflow the current IO buffer. The bytes # should be moved into a new buffer. set data "1234567890 [format %c 12399]" set sizes [list] # With default buffer size set f [open $path(test2) w] fconfigure $f -encoding iso2022-jp puts -nonewline $f $data close $f lappend sizes [file size $path(test2)] # With buffer size equal to the length # of the data, the escape bytes would # go into the next buffer. set f [open $path(test2) w] fconfigure $f -encoding iso2022-jp -buffersize 16 puts -nonewline $f $data close $f lappend sizes [file size $path(test2)] # With buffer size that is large enough # to hold 1 byte of escaped data, but # not all 3. This should not write # the escape bytes to the first buffer # and then again to the second buffer. set f [open $path(test2) w] fconfigure $f -encoding iso2022-jp -buffersize 17 puts -nonewline $f $data close $f lappend sizes [file size $path(test2)] # With buffer size that can hold 2 out of # 3 bytes of escaped data. set f [open $path(test2) w] fconfigure $f -encoding iso2022-jp -buffersize 18 puts -nonewline $f $data close $f lappend sizes [file size $path(test2)] # With buffer size that can hold all the # data and escape bytes. set f [open $path(test2) w] fconfigure $f -encoding iso2022-jp -buffersize 19 puts -nonewline $f $data close $f lappend sizes [file size $path(test2)] set sizes } {19 19 19 19 19} test io-2.1 {WriteBytes} { # loop until all bytes are written set f [open $path(test1) w] fconfigure $f -encoding binary -buffersize 16 -translation crlf puts $f "abcdefghijklmnopqrstuvwxyz" close $f contents $path(test1) } "abcdefghijklmnopqrstuvwxyz\r\n" test io-2.2 {WriteBytes: savedLF > 0} { # After flushing buffer, there was a \n left over from the last # \n -> \r\n expansion. It gets stuck at beginning of this buffer. set f [open $path(test1) w] fconfigure $f -encoding binary -buffersize 16 -translation crlf puts -nonewline $f "123456789012345\n12" set x [list [contents $path(test1)]] close $f lappend x [contents $path(test1)] } [list "123456789012345\r" "123456789012345\r\n12"] test io-2.3 {WriteBytes: flush on line} { # Tcl "line" buffering has weird behavior: if current buffer contains # a \n, entire buffer gets flushed. Logical behavior would be to flush # only up to the \n. set f [open $path(test1) w] fconfigure $f -encoding binary -buffering line -translation crlf puts -nonewline $f "\n12" set x [contents $path(test1)] close $f set x } "\r\n12" test io-2.4 {WriteBytes: reset sawLF after each buffer} { set f [open $path(test1) w] fconfigure $f -encoding binary -buffering line -translation lf \ -buffersize 16 puts -nonewline $f "abcdefg\nhijklmnopqrstuvwxyz" set x [list [contents $path(test1)]] close $f lappend x [contents $path(test1)] } [list "abcdefg\nhijklmno" "abcdefg\nhijklmnopqrstuvwxyz"] test io-3.1 {WriteChars: compatibility with WriteBytes} { # loop until all bytes are written set f [open $path(test1) w] fconfigure $f -encoding ascii -buffersize 16 -translation crlf puts $f "abcdefghijklmnopqrstuvwxyz" close $f contents $path(test1) } "abcdefghijklmnopqrstuvwxyz\r\n" test io-3.2 {WriteChars: compatibility with WriteBytes: savedLF > 0} { # After flushing buffer, there was a \n left over from the last # \n -> \r\n expansion. It gets stuck at beginning of this buffer. set f [open $path(test1) w] fconfigure $f -encoding ascii -buffersize 16 -translation crlf puts -nonewline $f "123456789012345\n12" set x [list [contents $path(test1)]] close $f lappend x [contents $path(test1)] } [list "123456789012345\r" "123456789012345\r\n12"] test io-3.3 {WriteChars: compatibility with WriteBytes: flush on line} { # Tcl "line" buffering has weird behavior: if current buffer contains # a \n, entire buffer gets flushed. Logical behavior would be to flush # only up to the \n. set f [open $path(test1) w] fconfigure $f -encoding ascii -buffering line -translation crlf puts -nonewline $f "\n12" set x [contents $path(test1)] close $f set x } "\r\n12" test io-3.4 {WriteChars: loop over stage buffer} { # stage buffer maps to more than can be queued at once. set f [open $path(test1) w] fconfigure $f -encoding jis0208 -buffersize 16 puts -nonewline $f "\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\" set x [list [contents $path(test1)]] close $f lappend x [contents $path(test1)] } [list "!)!)!)!)!)!)!)!)" "!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)"] test io-3.5 {WriteChars: saved != 0} { # Bytes produced by UtfToExternal from end of last channel buffer # had to be moved to beginning of next channel buffer to preserve # requested buffersize. set f [open $path(test1) w] fconfigure $f -encoding jis0208 -buffersize 17 puts -nonewline $f "\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\" set x [list [contents $path(test1)]] close $f lappend x [contents $path(test1)] } [list "!)!)!)!)!)!)!)!)!" "!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)"] test io-3.6 {WriteChars: (stageRead + dstWrote == 0)} { # One incomplete UTF-8 character at end of staging buffer. Backup # in src to the beginning of that UTF-8 character and try again. # # Translate the first 16 bytes, produce 14 bytes of output, 2 left over # (first two bytes of \uff21 in UTF-8). Given those two bytes try # translating them again, find that no bytes are read produced, and break # to outer loop where those two bytes will have the remaining 4 bytes # (the last byte of \uff21 plus the all of \uff22) appended. set f [open $path(test1) w] fconfigure $f -encoding shiftjis -buffersize 16 puts -nonewline $f "12345678901234\uff21\uff22" set x [list [contents $path(test1)]] close $f lappend x [contents $path(test1)] } [list "12345678901234\x82\x60" "12345678901234\x82\x60\x82\x61"] test io-3.7 {WriteChars: (bufPtr->nextAdded > bufPtr->length)} { # When translating UTF-8 to external, the produced bytes went past end # of the channel buffer. This is done purpose -- we then truncate the # bytes at the end of the partial character to preserve the requested # blocksize on flush. The truncated bytes are moved to the beginning # of the next channel buffer. set f [open $path(test1) w] fconfigure $f -encoding jis0208 -buffersize 17 puts -nonewline $f "\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\" set x [list [contents $path(test1)]] close $f lappend x [contents $path(test1)] } [list "!)!)!)!)!)!)!)!)!" "!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)"] test io-3.8 {WriteChars: reset sawLF after each buffer} { set f [open $path(test1) w] fconfigure $f -encoding ascii -buffering line -translation lf \ -buffersize 16 puts -nonewline $f "abcdefg\nhijklmnopqrstuvwxyz" set x [list [contents $path(test1)]] close $f lappend x [contents $path(test1)] } [list "abcdefg\nhijklmno" "abcdefg\nhijklmnopqrstuvwxyz"] test io-4.1 {TranslateOutputEOL: lf} { # search for \n set f [open $path(test1) w] fconfigure $f -buffering line -translation lf puts $f "abcde" set x [list [contents $path(test1)]] close $f lappend x [contents $path(test1)] } [list "abcde\n" "abcde\n"] test io-4.2 {TranslateOutputEOL: cr} { # search for \n, replace with \r set f [open $path(test1) w] fconfigure $f -buffering line -translation cr puts $f "abcde" set x [list [contents $path(test1)]] close $f lappend x [contents $path(test1)] } [list "abcde\r" "abcde\r"] test io-4.3 {TranslateOutputEOL: crlf} { # simple case: search for \n, replace with \r set f [open $path(test1) w] fconfigure $f -buffering line -translation crlf puts $f "abcde" set x [list [contents $path(test1)]] close $f lappend x [contents $path(test1)] } [list "abcde\r\n" "abcde\r\n"] test io-4.4 {TranslateOutputEOL: crlf} { # keep storing more bytes in output buffer until output buffer is full. # We have 13 bytes initially that would turn into 18 bytes. Fill # dest buffer while (dstEnd < dstMax). set f [open $path(test1) w] fconfigure $f -translation crlf -buffersize 16 puts -nonewline $f "1234567\n\n\n\n\nA" set x [list [contents $path(test1)]] close $f lappend x [contents $path(test1)] } [list "1234567\r\n\r\n\r\n\r\n\r" "1234567\r\n\r\n\r\n\r\n\r\nA"] test io-4.5 {TranslateOutputEOL: crlf} { # Check for overflow of the destination buffer set f [open $path(test1) w] fconfigure $f -translation crlf -buffersize 12 puts -nonewline $f "12345678901\n456789012345678901234" close $f set x [contents $path(test1)] } "12345678901\r\n456789012345678901234" test io-5.1 {CheckFlush: not full} { set f [open $path(test1) w] fconfigure $f puts -nonewline $f "12345678901234567890" set x [list [contents $path(test1)]] close $f lappend x [contents $path(test1)] } [list "" "12345678901234567890"] test io-5.2 {CheckFlush: full} { set f [open $path(test1) w] fconfigure $f -buffersize 16 puts -nonewline $f "12345678901234567890" set x [list [contents $path(test1)]] close $f lappend x [contents $path(test1)] } [list "1234567890123456" "12345678901234567890"] test io-5.3 {CheckFlush: not line} { set f [open $path(test1) w] fconfigure $f -buffering line puts -nonewline $f "12345678901234567890" set x [list [contents $path(test1)]] close $f lappend x [contents $path(test1)] } [list "" "12345678901234567890"] test io-5.4 {CheckFlush: line} { set f [open $path(test1) w] fconfigure $f -buffering line -translation lf -encoding ascii puts -nonewline $f "1234567890\n1234567890" set x [list [contents $path(test1)]] close $f lappend x [contents $path(test1)] } [list "1234567890\n1234567890" "1234567890\n1234567890"] test io-5.5 {CheckFlush: none} { set f [open $path(test1) w] fconfigure $f -buffering none puts -nonewline $f "1234567890" set x [list [contents $path(test1)]] close $f lappend x [contents $path(test1)] } [list "1234567890" "1234567890"] test io-6.1 {Tcl_GetsObj: working} { set f [open $path(test1) w] puts $f "foo\nboo" close $f set f [open $path(test1)] set x [gets $f] close $f set x } {foo} test io-6.2 {Tcl_GetsObj: CheckChannelErrors() != 0} { # no test, need to cause an async error. } {} test io-6.3 {Tcl_GetsObj: how many have we used?} { # if (bufPtr != NULL) {oldRemoved = bufPtr->nextRemoved} set f [open $path(test1) w] fconfigure $f -translation crlf puts $f "abc\ndefg" close $f set f [open $path(test1)] set x [list [tell $f] [gets $f line] [tell $f] [gets $f line] $line] close $f set x } {0 3 5 4 defg} test io-6.4 {Tcl_GetsObj: encoding == NULL} { set f [open $path(test1) w] fconfigure $f -translation binary puts $f "\x81\u1234\0" close $f set f [open $path(test1)] fconfigure $f -translation binary set x [list [gets $f line] $line] close $f set x } [list 3 "\x81\x34\x00"] test io-6.5 {Tcl_GetsObj: encoding != NULL} { set f [open $path(test1) w] fconfigure $f -translation binary puts $f "\x88\xea\x92\x9a" close $f set f [open $path(test1)] fconfigure $f -encoding shiftjis set x [list [gets $f line] $line] close $f set x } [list 2 "\u4e00\u4e01"] set a "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" append a $a append a $a test io-6.6 {Tcl_GetsObj: loop test} { # if (dst >= dstEnd) set f [open $path(test1) w] puts $f $a puts $f hi close $f set f [open $path(test1)] set x [list [gets $f line] $line] close $f set x } [list 256 $a] test io-6.7 {Tcl_GetsObj: error in input} {stdio openpipe} { # if (FilterInputBytes(chanPtr, &gs) != 0) set f [open "|[list [interpreter] $path(cat)]" w+] puts -nonewline $f "hi\nwould" flush $f gets $f fconfigure $f -blocking 0 set x [gets $f line] close $f set x } {-1} test io-6.8 {Tcl_GetsObj: remember if EOF is seen} { set f [open $path(test1) w] puts $f "abcdef\x1aghijk\nwombat" close $f set f [open $path(test1)] fconfigure $f -eofchar \x1a set x [list [gets $f line] $line [gets $f line] $line] close $f set x } {6 abcdef -1 {}} test io-6.9 {Tcl_GetsObj: remember if EOF is seen} { set f [open $path(test1) w] puts $f "abcdefghijk\nwom\u001abat" close $f set f [open $path(test1)] fconfigure $f -eofchar \x1a set x [list [gets $f line] $line [gets $f line] $line] close $f set x } {11 abcdefghijk 3 wom} # Comprehensive tests test io-6.10 {Tcl_GetsObj: lf mode: no chars} { set f [open $path(test1) w] close $f set f [open $path(test1)] fconfigure $f -translation lf set x [list [gets $f line] $line] close $f set x } {-1 {}} test io-6.11 {Tcl_GetsObj: lf mode: lone \n} { set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "\n" close $f set f [open $path(test1)] fconfigure $f -translation lf set x [list [gets $f line] $line [gets $f line] $line] close $f set x } {0 {} -1 {}} test io-6.12 {Tcl_GetsObj: lf mode: lone \r} { set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "\r" close $f set f [open $path(test1)] fconfigure $f -translation lf set x [list [gets $f line] $line [gets $f line] $line] close $f set x } [list 1 "\r" -1 ""] test io-6.13 {Tcl_GetsObj: lf mode: 1 char} { set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f a close $f set f [open $path(test1)] fconfigure $f -translation lf set x [list [gets $f line] $line [gets $f line] $line] close $f set x } {1 a -1 {}} test io-6.14 {Tcl_GetsObj: lf mode: 1 char followed by EOL} { set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "a\n" close $f set f [open $path(test1)] fconfigure $f -translation lf set x [list [gets $f line] $line [gets $f line] $line] close $f set x } {1 a -1 {}} test io-6.15 {Tcl_GetsObj: lf mode: several chars} { set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "abcd\nefgh\rijkl\r\nmnop" close $f set f [open $path(test1)] fconfigure $f -translation lf set x [list [gets $f line] $line [gets $f line] $line [gets $f line] $line [gets $f line] $line] close $f set x } [list 4 "abcd" 10 "efgh\rijkl\r" 4 "mnop" -1 ""] test io-6.16 {Tcl_GetsObj: cr mode: no chars} { set f [open $path(test1) w] close $f set f [open $path(test1)] fconfigure $f -translation cr set x [list [gets $f line] $line] close $f set x } {-1 {}} test io-6.17 {Tcl_GetsObj: cr mode: lone \n} { set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "\n" close $f set f [open $path(test1)] fconfigure $f -translation cr set x [list [gets $f line] $line [gets $f line] $line] close $f set x } [list 1 "\n" -1 ""] test io-6.18 {Tcl_GetsObj: cr mode: lone \r} { set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "\r" close $f set f [open $path(test1)] fconfigure $f -translation cr set x [list [gets $f line] $line [gets $f line] $line] close $f set x } {0 {} -1 {}} test io-6.19 {Tcl_GetsObj: cr mode: 1 char} { set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f a close $f set f [open $path(test1)] fconfigure $f -translation cr set x [list [gets $f line] $line [gets $f line] $line] close $f set x } {1 a -1 {}} test io-6.20 {Tcl_GetsObj: cr mode: 1 char followed by EOL} { set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "a\r" close $f set f [open $path(test1)] fconfigure $f -translation cr set x [list [gets $f line] $line [gets $f line] $line] close $f set x } {1 a -1 {}} test io-6.21 {Tcl_GetsObj: cr mode: several chars} { set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "abcd\nefgh\rijkl\r\nmnop" close $f set f [open $path(test1)] fconfigure $f -translation cr set x [list [gets $f line] $line [gets $f line] $line [gets $f line] $line [gets $f line] $line] close $f set x } [list 9 "abcd\nefgh" 4 "ijkl" 5 "\nmnop" -1 ""] test io-6.22 {Tcl_GetsObj: crlf mode: no chars} { set f [open $path(test1) w] close $f set f [open $path(test1)] fconfigure $f -translation crlf set x [list [gets $f line] $line] close $f set x } {-1 {}} test io-6.23 {Tcl_GetsObj: crlf mode: lone \n} { set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "\n" close $f set f [open $path(test1)] fconfigure $f -translation crlf set x [list [gets $f line] $line [gets $f line] $line] close $f set x } [list 1 "\n" -1 ""] test io-6.24 {Tcl_GetsObj: crlf mode: lone \r} { set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "\r" close $f set f [open $path(test1)] fconfigure $f -translation crlf set x [list [gets $f line] $line [gets $f line] $line] close $f set x } [list 1 "\r" -1 ""] test io-6.25 {Tcl_GetsObj: crlf mode: \r\r} { set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "\r\r" close $f set f [open $path(test1)] fconfigure $f -translation crlf set x [list [gets $f line] $line [gets $f line] $line] close $f set x } [list 2 "\r\r" -1 ""] test io-6.26 {Tcl_GetsObj: crlf mode: \r\n} { set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "\r\n" close $f set f [open $path(test1)] fconfigure $f -translation crlf set x [list [gets $f line] $line [gets $f line] $line] close $f set x } [list 0 "" -1 ""] test io-6.27 {Tcl_GetsObj: crlf mode: 1 char} { set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f a close $f set f [open $path(test1)] fconfigure $f -translation crlf set x [list [gets $f line] $line [gets $f line] $line] close $f set x } {1 a -1 {}} test io-6.28 {Tcl_GetsObj: crlf mode: 1 char followed by EOL} { set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "a\r\n" close $f set f [open $path(test1)] fconfigure $f -translation crlf set x [list [gets $f line] $line [gets $f line] $line] close $f set x } {1 a -1 {}} test io-6.29 {Tcl_GetsObj: crlf mode: several chars} { set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "abcd\nefgh\rijkl\r\nmnop" close $f set f [open $path(test1)] fconfigure $f -translation crlf set x [list [gets $f line] $line [gets $f line] $line [gets $f line] $line] close $f set x } [list 14 "abcd\nefgh\rijkl" 4 "mnop" -1 ""] test io-6.30 {Tcl_GetsObj: crlf mode: buffer exhausted} {testchannel} { # if (eol >= dstEnd) set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "123456789012345\r\nabcdefghijklmnoprstuvwxyz" close $f set f [open $path(test1)] fconfigure $f -translation crlf -buffersize 16 set x [list [gets $f line] $line [testchannel inputbuffered $f]] close $f set x } [list 15 "123456789012345" 15] test io-6.31 {Tcl_GetsObj: crlf mode: buffer exhausted, blocked} {stdio testchannel openpipe fileevent} { # (FilterInputBytes() != 0) set f [open "|[list [interpreter] $path(cat)]" w+] fconfigure $f -translation {crlf lf} -buffering none puts -nonewline $f "bbbbbbbbbbbbbb\r\n123456789012345\r" fconfigure $f -buffersize 16 set x [gets $f] fconfigure $f -blocking 0 lappend x [gets $f line] $line [fblocked $f] [testchannel inputbuffered $f] close $f set x } [list "bbbbbbbbbbbbbb" -1 "" 1 16] test io-6.32 {Tcl_GetsObj: crlf mode: buffer exhausted, more data} {testchannel} { # not (FilterInputBytes() != 0) set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "123456789012345\r\n123" close $f set f [open $path(test1)] fconfigure $f -translation crlf -buffersize 16 set x [list [gets $f line] $line [tell $f] [testchannel inputbuffered $f]] close $f set x } [list 15 "123456789012345" 17 3] test io-6.33 {Tcl_GetsObj: crlf mode: buffer exhausted, at eof} { # eol still equals dstEnd set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "123456789012345\r" close $f set f [open $path(test1)] fconfigure $f -translation crlf -buffersize 16 set x [list [gets $f line] $line [eof $f]] close $f set x } [list 16 "123456789012345\r" 1] test io-6.34 {Tcl_GetsObj: crlf mode: buffer exhausted, not followed by \n} { # not (*eol == '\n') set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "123456789012345\rabcd\r\nefg" close $f set f [open $path(test1)] fconfigure $f -translation crlf -buffersize 16 set x [list [gets $f line] $line [tell $f]] close $f set x } [list 20 "123456789012345\rabcd" 22] test io-6.35 {Tcl_GetsObj: auto mode: no chars} { set f [open $path(test1) w] close $f set f [open $path(test1)] fconfigure $f -translation auto set x [list [gets $f line] $line] close $f set x } {-1 {}} test io-6.36 {Tcl_GetsObj: auto mode: lone \n} { set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "\n" close $f set f [open $path(test1)] fconfigure $f -translation auto set x [list [gets $f line] $line [gets $f line] $line] close $f set x } [list 0 "" -1 ""] test io-6.37 {Tcl_GetsObj: auto mode: lone \r} { set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "\r" close $f set f [open $path(test1)] fconfigure $f -translation auto set x [list [gets $f line] $line [gets $f line] $line] close $f set x } [list 0 "" -1 ""] test io-6.38 {Tcl_GetsObj: auto mode: \r\r} { set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "\r\r" close $f set f [open $path(test1)] fconfigure $f -translation auto set x [list [gets $f line] $line [gets $f line] $line [gets $f line] $line] close $f set x } [list 0 "" 0 "" -1 ""] test io-6.39 {Tcl_GetsObj: auto mode: \r\n} { set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "\r\n" close $f set f [open $path(test1)] fconfigure $f -translation auto set x [list [gets $f line] $line [gets $f line] $line] close $f set x } [list 0 "" -1 ""] test io-6.40 {Tcl_GetsObj: auto mode: 1 char} { set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f a close $f set f [open $path(test1)] fconfigure $f -translation auto set x [list [gets $f line] $line [gets $f line] $line] close $f set x } {1 a -1 {}} test io-6.41 {Tcl_GetsObj: auto mode: 1 char followed by EOL} { set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "a\r\n" close $f set f [open $path(test1)] fconfigure $f -translation auto set x [list [gets $f line] $line [gets $f line] $line] close $f set x } {1 a -1 {}} test io-6.42 {Tcl_GetsObj: auto mode: several chars} { set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "abcd\nefgh\rijkl\r\nmnop" close $f set f [open $path(test1)] fconfigure $f -translation auto set x [list [gets $f line] $line [gets $f line] $line] lappend x [gets $f line] $line [gets $f line] $line [gets $f line] $line close $f set x } [list 4 "abcd" 4 "efgh" 4 "ijkl" 4 "mnop" -1 ""] test io-6.43 {Tcl_GetsObj: input saw cr} {stdio testchannel openpipe fileevent} { # if (chanPtr->flags & INPUT_SAW_CR) set f [open "|[list [interpreter] $path(cat)]" w+] fconfigure $f -translation {auto lf} -buffering none puts -nonewline $f "bbbbbbbbbbbbbbb\n123456789abcdef\r" fconfigure $f -buffersize 16 set x [list [gets $f]] fconfigure $f -blocking 0 lappend x [gets $f line] $line [testchannel queuedcr $f] fconfigure $f -blocking 1 puts -nonewline $f "\nabcd\refg\x1a" lappend x [gets $f line] $line [testchannel queuedcr $f] lappend x [gets $f line] $line close $f set x } [list "bbbbbbbbbbbbbbb" 15 "123456789abcdef" 1 4 "abcd" 0 3 "efg"] test io-6.44 {Tcl_GetsObj: input saw cr, not followed by cr} {stdio testchannel openpipe fileevent} { # not (*eol == '\n') set f [open "|[list [interpreter] $path(cat)]" w+] fconfigure $f -translation {auto lf} -buffering none puts -nonewline $f "bbbbbbbbbbbbbbb\n123456789abcdef\r" fconfigure $f -buffersize 16 set x [list [gets $f]] fconfigure $f -blocking 0 lappend x [gets $f line] $line [testchannel queuedcr $f] fconfigure $f -blocking 1 puts -nonewline $f "abcd\refg\x1a" lappend x [gets $f line] $line [testchannel queuedcr $f] lappend x [gets $f line] $line close $f set x } [list "bbbbbbbbbbbbbbb" 15 "123456789abcdef" 1 4 "abcd" 0 3 "efg"] test io-6.45 {Tcl_GetsObj: input saw cr, skip right number of bytes} {stdio testchannel openpipe fileevent} { # Tcl_ExternalToUtf() set f [open "|[list [interpreter] $path(cat)]" w+] fconfigure $f -translation {auto lf} -buffering none fconfigure $f -encoding unicode puts -nonewline $f "bbbbbbbbbbbbbbb\n123456789abcdef\r" fconfigure $f -buffersize 16 gets $f fconfigure $f -blocking 0 set x [list [gets $f line] $line [testchannel queuedcr $f]] fconfigure $f -blocking 1 puts -nonewline $f "\nabcd\refg" lappend x [gets $f line] $line [testchannel queuedcr $f] close $f set x } [list 15 "123456789abcdef" 1 4 "abcd" 0] test io-6.46 {Tcl_GetsObj: input saw cr, followed by just \n should give eof} {stdio testchannel openpipe fileevent} { # memmove() set f [open "|[list [interpreter] $path(cat)]" w+] fconfigure $f -translation {auto lf} -buffering none puts -nonewline $f "bbbbbbbbbbbbbbb\n123456789abcdef\r" fconfigure $f -buffersize 16 gets $f fconfigure $f -blocking 0 set x [list [gets $f line] $line [testchannel queuedcr $f]] fconfigure $f -blocking 1 puts -nonewline $f "\n\x1a" lappend x [gets $f line] $line [testchannel queuedcr $f] close $f set x } [list 15 "123456789abcdef" 1 -1 "" 0] test io-6.47 {Tcl_GetsObj: auto mode: \r at end of buffer, peek for \n} {testchannel} { # (eol == dstEnd) set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "123456789012345\r\nabcdefghijklmnopq" close $f set f [open $path(test1)] fconfigure $f -translation auto -buffersize 16 set x [list [gets $f] [testchannel inputbuffered $f]] close $f set x } [list "123456789012345" 15] test io-6.48 {Tcl_GetsObj: auto mode: \r at end of buffer, no more avail} {testchannel} { # PeekAhead() did not get any, so (eol >= dstEnd) set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "123456789012345\r" close $f set f [open $path(test1)] fconfigure $f -translation auto -buffersize 16 set x [list [gets $f] [testchannel queuedcr $f]] close $f set x } [list "123456789012345" 1] test io-6.49 {Tcl_GetsObj: auto mode: \r followed by \n} {testchannel} { # if (*eol == '\n') {skip++} set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "123456\r\n78901" close $f set f [open $path(test1)] set x [list [gets $f] [testchannel queuedcr $f] [tell $f] [gets $f]] close $f set x } [list "123456" 0 8 "78901"] test io-6.50 {Tcl_GetsObj: auto mode: \r not followed by \n} {testchannel} { # not (*eol == '\n') set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "123456\r78901" close $f set f [open $path(test1)] set x [list [gets $f] [testchannel queuedcr $f] [tell $f] [gets $f]] close $f set x } [list "123456" 0 7 "78901"] test io-6.51 {Tcl_GetsObj: auto mode: \n} { # else if (*eol == '\n') {goto gotoeol;} set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "123456\n78901" close $f set f [open $path(test1)] set x [list [gets $f] [tell $f] [gets $f]] close $f set x } [list "123456" 7 "78901"] test io-6.52 {Tcl_GetsObj: saw EOF character} {testchannel} { # if (eof != NULL) set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "123456\x1ak9012345\r" close $f set f [open $path(test1)] fconfigure $f -eofchar \x1a set x [list [gets $f] [testchannel queuedcr $f] [tell $f] [gets $f]] close $f set x } [list "123456" 0 6 ""] test io-6.53 {Tcl_GetsObj: device EOF} { # didn't produce any bytes set f [open $path(test1) w] close $f set f [open $path(test1)] set x [list [gets $f line] $line [eof $f]] close $f set x } {-1 {} 1} test io-6.54 {Tcl_GetsObj: device EOF} { # got some bytes before EOF. set f [open $path(test1) w] puts -nonewline $f abc close $f set f [open $path(test1)] set x [list [gets $f line] $line [eof $f]] close $f set x } {3 abc 1} test io-6.55 {Tcl_GetsObj: overconverted} { # Tcl_ExternalToUtf(), make sure state updated set f [open $path(test1) w] fconfigure $f -encoding iso2022-jp puts $f "there\u4e00ok\n\u4e01more bytes\nhere" close $f set f [open $path(test1)] fconfigure $f -encoding iso2022-jp set x [list [gets $f line] $line [gets $f line] $line [gets $f line] $line] close $f set x } [list 8 "there\u4e00ok" 11 "\u4e01more bytes" 4 "here"] test io-6.56 {Tcl_GetsObj: incomplete lines should disable file events} {stdio openpipe fileevent} { update set f [open "|[list [interpreter] $path(cat)]" w+] fconfigure $f -buffering none puts -nonewline $f "foobar" fconfigure $f -blocking 0 variable x {} after 500 [namespace code { lappend x timeout }] fileevent $f readable [namespace code { lappend x [gets $f] }] vwait [namespace which -variable x] vwait [namespace which -variable x] fconfigure $f -blocking 1 puts -nonewline $f "baz\n" after 500 [namespace code { lappend x timeout }] fconfigure $f -blocking 0 vwait [namespace which -variable x] vwait [namespace which -variable x] close $f set x } {{} timeout foobarbaz timeout} test io-7.1 {FilterInputBytes: split up character at end of buffer} { # (result == TCL_CONVERT_MULTIBYTE) set f [open $path(test1) w] fconfigure $f -encoding shiftjis puts $f "1234567890123\uff10\uff11\uff12\uff13\uff14\nend" close $f set f [open $path(test1)] fconfigure $f -encoding shiftjis -buffersize 16 set x [gets $f] close $f set x } "1234567890123\uff10\uff11\uff12\uff13\uff14" test io-7.2 {FilterInputBytes: split up character in middle of buffer} { # (bufPtr->nextAdded < bufPtr->bufLength) set f [open $path(test1) w] fconfigure $f -encoding binary puts -nonewline $f "1234567890\n123\x82\x4f\x82\x50\x82" close $f set f [open $path(test1)] fconfigure $f -encoding shiftjis set x [list [gets $f line] $line [eof $f]] close $f set x } [list 10 "1234567890" 0] test io-7.3 {FilterInputBytes: split up character at EOF} {testchannel} { set f [open $path(test1) w] fconfigure $f -encoding binary puts -nonewline $f "1234567890123\x82\x4f\x82\x50\x82" close $f set f [open $path(test1)] fconfigure $f -encoding shiftjis set x [list [gets $f line] $line] lappend x [tell $f] [testchannel inputbuffered $f] [eof $f] lappend x [gets $f line] $line close $f set x } [list 15 "1234567890123\uff10\uff11" 18 0 1 -1 ""] test io-7.4 {FilterInputBytes: recover from split up character} {stdio openpipe fileevent} { set f [open "|[list [interpreter] $path(cat)]" w+] fconfigure $f -encoding binary -buffering none puts -nonewline $f "1234567890123\x82\x4f\x82\x50\x82" fconfigure $f -encoding shiftjis -blocking 0 fileevent $f read [namespace code "ready $f"] variable x {} proc ready {f} { variable x lappend x [gets $f line] $line [fblocked $f] } vwait [namespace which -variable x] fconfigure $f -encoding binary -blocking 1 puts $f "\x51\x82\x52" fconfigure $f -encoding shiftjis vwait [namespace which -variable x] close $f set x } [list -1 "" 1 17 "1234567890123\uff10\uff11\uff12\uff13" 0] test io-8.1 {PeekAhead: only go to device if no more cached data} {testchannel} { # (bufPtr->nextPtr == NULL) set f [open $path(test1) w] fconfigure $f -encoding ascii -translation lf puts -nonewline $f "123456789012345\r\n2345678" close $f set f [open $path(test1)] fconfigure $f -encoding ascii -translation auto -buffersize 16 # here gets $f set x [testchannel inputbuffered $f] close $f set x } "7" test io-8.2 {PeekAhead: only go to device if no more cached data} {stdio testchannel openpipe fileevent} { # not (bufPtr->nextPtr == NULL) set f [open "|[list [interpreter] $path(cat)]" w+] fconfigure $f -translation lf -encoding ascii -buffering none puts -nonewline $f "123456789012345\r\nbcdefghijklmnopqrstuvwxyz" variable x {} fileevent $f read [namespace code "ready $f"] proc ready {f} { variable x lappend x [gets $f line] $line [testchannel inputbuffered $f] } fconfigure $f -encoding unicode -buffersize 16 -blocking 0 vwait [namespace which -variable x] fconfigure $f -translation auto -encoding ascii -blocking 1 # here vwait [namespace which -variable x] close $f set x } [list -1 "" 42 15 "123456789012345" 25] test io-8.3 {PeekAhead: no cached data available} {stdio testchannel openpipe fileevent} { # (bytesLeft == 0) set f [open "|[list [interpreter] $path(cat)]" w+] fconfigure $f -translation {auto binary} puts -nonewline $f "abcdefghijklmno\r" flush $f set x [list [gets $f line] $line [testchannel queuedcr $f]] close $f set x } [list 15 "abcdefghijklmno" 1] set a "123456789012345678901234567890" append a "123456789012345678901234567890" append a "1234567890123456789012345678901" test io-8.4 {PeekAhead: cached data available in this buffer} { # not (bytesLeft == 0) set f [open $path(test1) w+] fconfigure $f -translation binary puts $f "${a}\r\nabcdef" close $f set f [open $path(test1)] fconfigure $f -encoding binary -translation auto # "${a}\r" was converted in one operation (because ENCODING_LINESIZE # is 30). To check if "\n" follows, calls PeekAhead and determines # that cached data is available in buffer w/o having to call driver. set x [gets $f] close $f set x } $a unset a test io-8.5 {PeekAhead: don't peek if last read was short} {stdio testchannel openpipe fileevent} { # (bufPtr->nextAdded < bufPtr->length) set f [open "|[list [interpreter] $path(cat)]" w+] fconfigure $f -translation {auto binary} puts -nonewline $f "abcdefghijklmno\r" flush $f # here set x [list [gets $f line] $line [testchannel queuedcr $f]] close $f set x } {15 abcdefghijklmno 1} test io-8.6 {PeekAhead: change to non-blocking mode} {stdio testchannel openpipe fileevent} { # ((chanPtr->flags & CHANNEL_NONBLOCKING) == 0) set f [open "|[list [interpreter] $path(cat)]" w+] fconfigure $f -translation {auto binary} -buffersize 16 puts -nonewline $f "abcdefghijklmno\r" flush $f # here set x [list [gets $f line] $line [testchannel queuedcr $f]] close $f set x } {15 abcdefghijklmno 1} test io-8.7 {PeekAhead: cleanup} {stdio testchannel openpipe fileevent} { # Make sure bytes are removed from buffer. set f [open "|[list [interpreter] $path(cat)]" w+] fconfigure $f -translation {auto binary} -buffering none puts -nonewline $f "abcdefghijklmno\r" # here set x [list [gets $f line] $line [testchannel queuedcr $f]] puts -nonewline $f "\x1a" lappend x [gets $f line] $line close $f set x } {15 abcdefghijklmno 1 -1 {}} test io-9.1 {CommonGetsCleanup} { } {} test io-10.1 {Tcl_ReadChars: CheckChannelErrors} { # no test, need to cause an async error. } {} test io-10.2 {Tcl_ReadChars: loop until enough copied} { # one time # for (copied = 0; (unsigned) toRead > 0; ) set f [open $path(test1) w] puts $f abcdefghijklmnop close $f set f [open $path(test1)] set x [read $f 5] close $f set x } {abcde} test io-10.3 {Tcl_ReadChars: loop until enough copied} { # multiple times # for (copied = 0; (unsigned) toRead > 0; ) set f [open $path(test1) w] puts $f abcdefghijklmnopqrstuvwxyz close $f set f [open $path(test1)] fconfigure $f -buffersize 16 # here set x [read $f 19] close $f set x } {abcdefghijklmnopqrs} test io-10.4 {Tcl_ReadChars: no more in channel buffer} { # (copiedNow < 0) set f [open $path(test1) w] puts -nonewline $f abcdefghijkl close $f set f [open $path(test1)] # here set x [read $f 1000] close $f set x } {abcdefghijkl} test io-10.5 {Tcl_ReadChars: stop on EOF} { # (chanPtr->flags & CHANNEL_EOF) set f [open $path(test1) w] puts -nonewline $f abcdefghijkl close $f set f [open $path(test1)] # here set x [read $f 1000] close $f set x } {abcdefghijkl} test io-11.1 {ReadBytes: want to read a lot} { # ((unsigned) toRead > (unsigned) srcLen) set f [open $path(test1) w] puts -nonewline $f abcdefghijkl close $f set f [open $path(test1)] fconfigure $f -encoding binary # here set x [read $f 1000] close $f set x } {abcdefghijkl} test io-11.2 {ReadBytes: want to read all} { # ((unsigned) toRead > (unsigned) srcLen) set f [open $path(test1) w] puts -nonewline $f abcdefghijkl close $f set f [open $path(test1)] fconfigure $f -encoding binary # here set x [read $f] close $f set x } {abcdefghijkl} test io-11.3 {ReadBytes: allocate more space} { # (toRead > length - offset - 1) set f [open $path(test1) w] puts -nonewline $f abcdefghijklmnopqrstuvwxyz close $f set f [open $path(test1)] fconfigure $f -buffersize 16 -encoding binary # here set x [read $f] close $f set x } {abcdefghijklmnopqrstuvwxyz} test io-11.4 {ReadBytes: EOF char found} { # (TranslateInputEOL() != 0) set f [open $path(test1) w] puts $f abcdefghijklmnopqrstuvwxyz close $f set f [open $path(test1)] fconfigure $f -eofchar m -encoding binary # here set x [list [read $f] [eof $f] [read $f] [eof $f]] close $f set x } [list "abcdefghijkl" 1 "" 1] test io-12.1 {ReadChars: want to read a lot} { # ((unsigned) toRead > (unsigned) srcLen) set f [open $path(test1) w] puts -nonewline $f abcdefghijkl close $f set f [open $path(test1)] # here set x [read $f 1000] close $f set x } {abcdefghijkl} test io-12.2 {ReadChars: want to read all} { # ((unsigned) toRead > (unsigned) srcLen) set f [open $path(test1) w] puts -nonewline $f abcdefghijkl close $f set f [open $path(test1)] # here set x [read $f] close $f set x } {abcdefghijkl} test io-12.3 {ReadChars: allocate more space} { # (toRead > length - offset - 1) set f [open $path(test1) w] puts -nonewline $f abcdefghijklmnopqrstuvwxyz close $f set f [open $path(test1)] fconfigure $f -buffersize 16 # here set x [read $f] close $f set x } {abcdefghijklmnopqrstuvwxyz} test io-12.4 {ReadChars: split-up char} {stdio testchannel openpipe fileevent} { # (srcRead == 0) set f [open "|[list [interpreter] $path(cat)]" w+] fconfigure $f -encoding binary -buffering none -buffersize 16 puts -nonewline $f "123456789012345\x96" fconfigure $f -encoding shiftjis -blocking 0 fileevent $f read [namespace code "ready $f"] proc ready {f} { variable x lappend x [read $f] [testchannel inputbuffered $f] } variable x {} fconfigure $f -encoding shiftjis vwait [namespace which -variable x] fconfigure $f -encoding binary -blocking 1 puts -nonewline $f "\x7b" after 500 ;# Give the cat process time to catch up fconfigure $f -encoding shiftjis -blocking 0 vwait [namespace which -variable x] close $f set x } [list "123456789012345" 1 "\u672c" 0] test io-12.5 {ReadChars: fileevents on partial characters} {stdio openpipe fileevent} { set path(test1) [makeFile { fconfigure stdout -encoding binary -buffering none gets stdin; puts -nonewline "\xe7" gets stdin; puts -nonewline "\x89" gets stdin; puts -nonewline "\xa6" } test1] set f [open "|[list [interpreter] $path(test1)]" r+] fileevent $f readable [namespace code { lappend x [read $f] if {[eof $f]} { lappend x eof } }] puts $f "go1" flush $f fconfigure $f -blocking 0 -encoding utf-8 variable x {} vwait [namespace which -variable x] after 500 [namespace code { lappend x timeout }] vwait [namespace which -variable x] puts $f "go2" flush $f vwait [namespace which -variable x] after 500 [namespace code { lappend x timeout }] vwait [namespace which -variable x] puts $f "go3" flush $f vwait [namespace which -variable x] vwait [namespace which -variable x] lappend x [catch {close $f} msg] $msg set x } "{} timeout {} timeout \u7266 {} eof 0 {}" test io-13.1 {TranslateInputEOL: cr mode} {} { set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "abcd\rdef\r" close $f set f [open $path(test1)] fconfigure $f -translation cr set x [read $f] close $f set x } "abcd\ndef\n" test io-13.2 {TranslateInputEOL: crlf mode} { set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "abcd\r\ndef\r\n" close $f set f [open $path(test1)] fconfigure $f -translation crlf set x [read $f] close $f set x } "abcd\ndef\n" test io-13.3 {TranslateInputEOL: crlf mode: naked cr} { # (src >= srcMax) set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "abcd\r\ndef\r" close $f set f [open $path(test1)] fconfigure $f -translation crlf set x [read $f] close $f set x } "abcd\ndef\r" test io-13.4 {TranslateInputEOL: crlf mode: cr followed by not \n} { # (src >= srcMax) set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "abcd\r\ndef\rfgh" close $f set f [open $path(test1)] fconfigure $f -translation crlf set x [read $f] close $f set x } "abcd\ndef\rfgh" test io-13.5 {TranslateInputEOL: crlf mode: naked lf} { # (src >= srcMax) set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "abcd\r\ndef\nfgh" close $f set f [open $path(test1)] fconfigure $f -translation crlf set x [read $f] close $f set x } "abcd\ndef\nfgh" test io-13.6 {TranslateInputEOL: auto mode: saw cr in last segment} {stdio testchannel openpipe fileevent} { # (chanPtr->flags & INPUT_SAW_CR) # This test may fail on slower machines. set f [open "|[list [interpreter] $path(cat)]" w+] fconfigure $f -blocking 0 -buffering none -translation {auto lf} fileevent $f read [namespace code "ready $f"] proc ready {f} { variable x lappend x [read $f] [testchannel queuedcr $f] } variable x {} variable y {} puts -nonewline $f "abcdefghj\r" after 500 [namespace code {set y ok}] vwait [namespace which -variable y] puts -nonewline $f "\n01234" after 500 [namespace code {set y ok}] vwait [namespace which -variable y] close $f set x } [list "abcdefghj\n" 1 "01234" 0] test io-13.7 {TranslateInputEOL: auto mode: naked \r} {testchannel openpipe} { # (src >= srcMax) set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "abcd\r" close $f set f [open $path(test1)] fconfigure $f -translation auto set x [list [read $f] [testchannel queuedcr $f]] close $f set x } [list "abcd\n" 1] test io-13.8 {TranslateInputEOL: auto mode: \r\n} { # (*src == '\n') set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "abcd\r\ndef" close $f set f [open $path(test1)] fconfigure $f -translation auto set x [read $f] close $f set x } "abcd\ndef" test io-13.9 {TranslateInputEOL: auto mode: \r followed by not \n} { set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "abcd\rdef" close $f set f [open $path(test1)] fconfigure $f -translation auto set x [read $f] close $f set x } "abcd\ndef" test io-13.10 {TranslateInputEOL: auto mode: \n} { # not (*src == '\r') set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "abcd\ndef" close $f set f [open $path(test1)] fconfigure $f -translation auto set x [read $f] close $f set x } "abcd\ndef" test io-13.11 {TranslateInputEOL: EOF char} { # (*chanPtr->inEofChar != '\0') set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "abcd\ndefgh" close $f set f [open $path(test1)] fconfigure $f -translation auto -eofchar e set x [read $f] close $f set x } "abcd\nd" test io-13.12 {TranslateInputEOL: find EOF char in src} { # (*chanPtr->inEofChar != '\0') set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "\r\n\r\n\r\nab\r\n\r\ndef\r\n\r\n\r\n" close $f set f [open $path(test1)] fconfigure $f -translation auto -eofchar e set x [read $f] close $f set x } "\n\n\nab\n\nd" # Test standard handle management. The functions tested are # Tcl_SetStdChannel and Tcl_GetStdChannel. Incidentally we are # also testing channel table management. if {[info commands testchannel] != ""} { set consoleFileNames [lsort [testchannel open]] } else { # just to avoid an error set consoleFileNames [list] } test io-14.1 {Tcl_SetStdChannel and Tcl_GetStdChannel} {testchannel} { set l "" lappend l [fconfigure stdin -buffering] lappend l [fconfigure stdout -buffering] lappend l [fconfigure stderr -buffering] lappend l [lsort [testchannel open]] set l } [list line line none $consoleFileNames] test io-14.2 {Tcl_SetStdChannel and Tcl_GetStdChannel} { interp create x set l "" lappend l [x eval {fconfigure stdin -buffering}] lappend l [x eval {fconfigure stdout -buffering}] lappend l [x eval {fconfigure stderr -buffering}] interp delete x set l } {line line none} set path(test3) [makeFile {} test3] test io-14.3 {Tcl_SetStdChannel & Tcl_GetStdChannel} {exec openpipe} { set f [open $path(test1) w] puts -nonewline $f { close stdin close stdout close stderr set f [} puts $f [list open $path(test1) r]] puts $f "set f2 \[[list open $path(test2) w]]" puts $f "set f3 \[[list open $path(test3) w]]" puts $f { puts stdout [gets stdin] puts stdout out puts stderr err close $f close $f2 close $f3 } close $f set result [exec [interpreter] $path(test1)] set f [open $path(test2) r] set f2 [open $path(test3) r] lappend result [read $f] [read $f2] close $f close $f2 set result } {{ out } {err }} # This test relies on the fact that the smallest available fd is used first. test io-14.4 {Tcl_SetStdChannel & Tcl_GetStdChannel} {exec unixOnly} { set f [open $path(test1) w] puts -nonewline $f { close stdin close stdout close stderr set f [} puts $f [list open $path(test1) r]] puts $f "set f2 \[[list open $path(test2) w]]" puts $f "set f3 \[[list open $path(test3) w]]" puts $f { puts stdout [gets stdin] puts stdout $f2 puts stderr $f3 close $f close $f2 close $f3 } close $f set result [exec [interpreter] $path(test1)] set f [open $path(test2) r] set f2 [open $path(test3) r] lappend result [read $f] [read $f2] close $f close $f2 set result } {{ close stdin file1 } {file2 }} catch {interp delete z} test io-14.5 {Tcl_GetChannel: stdio name translation} { interp create z eof stdin catch {z eval flush stdin} msg1 catch {z eval close stdin} msg2 catch {z eval flush stdin} msg3 set result [list $msg1 $msg2 $msg3] interp delete z set result } {{channel "stdin" wasn't opened for writing} {} {can not find channel named "stdin"}} test io-14.6 {Tcl_GetChannel: stdio name translation} { interp create z eof stdout catch {z eval flush stdout} msg1 catch {z eval close stdout} msg2 catch {z eval flush stdout} msg3 set result [list $msg1 $msg2 $msg3] interp delete z set result } {{} {} {can not find channel named "stdout"}} test io-14.7 {Tcl_GetChannel: stdio name translation} { interp create z eof stderr catch {z eval flush stderr} msg1 catch {z eval close stderr} msg2 catch {z eval flush stderr} msg3 set result [list $msg1 $msg2 $msg3] interp delete z set result } {{} {} {can not find channel named "stderr"}} set path(script) [makeFile {} script] test io-14.8 {reuse of stdio special channels} {stdio openpipe} { file delete $path(script) file delete $path(test1) set f [open $path(script) w] puts -nonewline $f { close stderr set f [} puts $f [list open $path(test1) w]] puts -nonewline $f { puts stderr hello close $f set f [} puts $f [list open $path(test1) r]] puts $f { puts [gets $f] } close $f set f [open "|[list [interpreter] $path(script)]" r] set c [gets $f] close $f set c } hello test io-14.9 {reuse of stdio special channels} {stdio openpipe fileevent} { file delete $path(script) file delete $path(test1) set f [open $path(script) w] puts $f { array set path [lindex $argv 0] set f [open $path(test1) w] puts $f hello close $f close stderr set f [open "|[list [info nameofexecutable] $path(cat) $path(test1)]" r] puts [gets $f] } close $f set f [open "|[list [interpreter] $path(script) [array get path]]" r] set c [gets $f] close $f # Added delay to give Windows time to stop the spawned process and clean # up its grip on the file test1. Added delete as proper test cleanup. # The failing tests were 18.1 and 18.2 as first re-users of file "test1". after 10000 file delete $path(script) file delete $path(test1) set c } hello test io-15.1 {Tcl_CreateCloseHandler} { } {} test io-16.1 {Tcl_DeleteCloseHandler} { } {} # Test channel table management. The functions tested are # GetChannelTable, DeleteChannelTable, Tcl_RegisterChannel, # Tcl_UnregisterChannel, Tcl_GetChannel and Tcl_CreateChannel. # # These functions use "eof stdin" to ensure that the standard # channels are added to the channel table of the interpreter. test io-17.1 {GetChannelTable, DeleteChannelTable on std handles} {testchannel} { set l1 [testchannel refcount stdin] eof stdin interp create x set l "" lappend l [expr [testchannel refcount stdin] - $l1] x eval {eof stdin} lappend l [expr [testchannel refcount stdin] - $l1] interp delete x lappend l [expr [testchannel refcount stdin] - $l1] set l } {0 1 0} test io-17.2 {GetChannelTable, DeleteChannelTable on std handles} {testchannel} { set l1 [testchannel refcount stdout] eof stdin interp create x set l "" lappend l [expr [testchannel refcount stdout] - $l1] x eval {eof stdout} lappend l [expr [testchannel refcount stdout] - $l1] interp delete x lappend l [expr [testchannel refcount stdout] - $l1] set l } {0 1 0} test io-17.3 {GetChannelTable, DeleteChannelTable on std handles} {testchannel} { set l1 [testchannel refcount stderr] eof stdin interp create x set l "" lappend l [expr [testchannel refcount stderr] - $l1] x eval {eof stderr} lappend l [expr [testchannel refcount stderr] - $l1] interp delete x lappend l [expr [testchannel refcount stderr] - $l1] set l } {0 1 0} test io-18.1 {Tcl_RegisterChannel, Tcl_UnregisterChannel} {testchannel} { file delete $path(test1) set l "" set f [open $path(test1) w] lappend l [lindex [testchannel info $f] 15] close $f if {[catch {lindex [testchannel info $f] 15} msg]} { lappend l $msg } else { lappend l "very broken: $f found after being closed" } string compare [string tolower $l] \ [list 1 [format "can not find channel named \"%s\"" $f]] } 0 test io-18.2 {Tcl_RegisterChannel, Tcl_UnregisterChannel} {testchannel} { file delete $path(test1) set l "" set f [open $path(test1) w] lappend l [lindex [testchannel info $f] 15] interp create x interp share "" $f x lappend l [lindex [testchannel info $f] 15] x eval close $f lappend l [lindex [testchannel info $f] 15] interp delete x lappend l [lindex [testchannel info $f] 15] close $f if {[catch {lindex [testchannel info $f] 15} msg]} { lappend l $msg } else { lappend l "very broken: $f found after being closed" } string compare [string tolower $l] \ [list 1 2 1 1 [format "can not find channel named \"%s\"" $f]] } 0 test io-18.3 {Tcl_RegisterChannel, Tcl_UnregisterChannel} {testchannel} { file delete $path(test1) set l "" set f [open $path(test1) w] lappend l [lindex [testchannel info $f] 15] interp create x interp share "" $f x lappend l [lindex [testchannel info $f] 15] interp delete x lappend l [lindex [testchannel info $f] 15] close $f if {[catch {lindex [testchannel info $f] 15} msg]} { lappend l $msg } else { lappend l "very broken: $f found after being closed" } string compare [string tolower $l] \ [list 1 2 1 [format "can not find channel named \"%s\"" $f]] } 0 test io-19.1 {Tcl_GetChannel->Tcl_GetStdChannel, standard handles} { eof stdin } 0 test io-19.2 {testing Tcl_GetChannel, user opened handle} { file delete $path(test1) set f [open $path(test1) w] set x [eof $f] close $f set x } 0 test io-19.3 {Tcl_GetChannel, channel not found} { list [catch {eof file34} msg] $msg } {1 {can not find channel named "file34"}} test io-19.4 {Tcl_CreateChannel, insertion into channel table} {testchannel} { file delete $path(test1) set f [open $path(test1) w] set l "" lappend l [eof $f] close $f if {[catch {lindex [testchannel info $f] 15} msg]} { lappend l $msg } else { lappend l "very broken: $f found after being closed" } string compare [string tolower $l] \ [list 0 [format "can not find channel named \"%s\"" $f]] } 0 test io-20.1 {Tcl_CreateChannel: initial settings} { set a [open $path(test2) w] set old [encoding system] encoding system ascii set f [open $path(test1) w] set x [fconfigure $f -encoding] close $f encoding system $old close $a set x } {ascii} test io-20.2 {Tcl_CreateChannel: initial settings} {pcOnly} { set f [open $path(test1) w+] set x [list [fconfigure $f -eofchar] [fconfigure $f -translation]] close $f set x } [list [list \x1a ""] {auto crlf}] test io-20.3 {Tcl_CreateChannel: initial settings} {unixOnly} { set f [open $path(test1) w+] set x [list [fconfigure $f -eofchar] [fconfigure $f -translation]] close $f set x } {{{} {}} {auto lf}} set path(stdout) [makeFile {} stdout] test io-20.5 {Tcl_CreateChannel: install channel in empty slot} {stdio openpipe} { set f [open $path(script) w] puts -nonewline $f { close stdout set f1 [} puts $f [list open $path(stdout) w]] puts $f { fconfigure $f1 -buffersize 777 puts stderr [fconfigure stdout -buffersize] } close $f set f [open "|[list [interpreter] $path(script)]"] catch {close $f} msg set msg } {777} test io-21.1 {CloseChannelsOnExit} { } {} # Test management of attributes associated with a channel, such as # its default translation, its name and type, etc. The functions # tested in this group are Tcl_GetChannelName, # Tcl_GetChannelType and Tcl_GetChannelFile. Tcl_GetChannelInstanceData # not tested because files do not use the instance data. test io-22.1 {Tcl_GetChannelMode} { # Not used anywhere in Tcl. } {} test io-23.1 {Tcl_GetChannelName} {testchannel} { file delete $path(test1) set f [open $path(test1) w] set n [testchannel name $f] close $f string compare $n $f } 0 test io-24.1 {Tcl_GetChannelType} {testchannel} { file delete $path(test1) set f [open $path(test1) w] set t [testchannel type $f] close $f string compare $t file } 0 test io-25.1 {Tcl_GetChannelHandle, input} {testchannel} { set f [open $path(test1) w] fconfigure $f -translation lf -eofchar {} puts $f "1234567890\n098765432" close $f set f [open $path(test1) r] gets $f set l "" lappend l [testchannel inputbuffered $f] lappend l [tell $f] close $f set l } {10 11} test io-25.2 {Tcl_GetChannelHandle, output} {testchannel} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf puts $f hello set l "" lappend l [testchannel outputbuffered $f] lappend l [tell $f] flush $f lappend l [testchannel outputbuffered $f] lappend l [tell $f] close $f file delete $path(test1) set l } {6 6 0 6} test io-26.1 {Tcl_GetChannelInstanceData} {stdio openpipe} { # "pid" command uses Tcl_GetChannelInstanceData # Don't care what pid is (but must be a number), just want to exercise it. set f [open "|[list [interpreter] << exit]"] expr [pid $f] close $f } {} # Test flushing. The functions tested here are FlushChannel. test io-27.1 {FlushChannel, no output buffered} { file delete $path(test1) set f [open $path(test1) w] flush $f set s [file size $path(test1)] close $f set s } 0 test io-27.2 {FlushChannel, some output buffered} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf -eofchar {} set l "" puts $f hello lappend l [file size $path(test1)] flush $f lappend l [file size $path(test1)] close $f lappend l [file size $path(test1)] set l } {0 6 6} test io-27.3 {FlushChannel, implicit flush on close} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf -eofchar {} set l "" puts $f hello lappend l [file size $path(test1)] close $f lappend l [file size $path(test1)] set l } {0 6} test io-27.4 {FlushChannel, implicit flush when buffer fills} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf -eofchar {} fconfigure $f -buffersize 60 set l "" lappend l [file size $path(test1)] for {set i 0} {$i < 12} {incr i} { puts $f hello } lappend l [file size $path(test1)] flush $f lappend l [file size $path(test1)] close $f set l } {0 60 72} test io-27.5 {FlushChannel, implicit flush when buffer fills and on close} \ {unixOrPc} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf -buffersize 60 -eofchar {} set l "" lappend l [file size $path(test1)] for {set i 0} {$i < 12} {incr i} { puts $f hello } lappend l [file size $path(test1)] close $f lappend l [file size $path(test1)] set l } {0 60 72} set path(pipe) [makeFile {} pipe] set path(output) [makeFile {} output] test io-27.6 {FlushChannel, async flushing, async close} \ {stdio asyncPipeClose openpipe} { file delete $path(pipe) file delete $path(output) set f [open $path(pipe) w] puts $f "set f \[[list open $path(output) w]]" puts $f { fconfigure $f -translation lf -buffering none -eofchar {} while {![eof stdin]} { after 20 puts -nonewline $f [read stdin 1024] } close $f } close $f set x 01234567890123456789012345678901 for {set i 0} {$i < 11} {incr i} { set x "$x$x" } set f [open $path(output) w] close $f set f [open "|[list [interpreter] $path(pipe)]" w] fconfigure $f -blocking off puts -nonewline $f $x close $f set counter 0 while {([file size $path(output)] < 65536) && ($counter < 1000)} { incr counter after 20 update } if {$counter == 1000} { set result "file size only [file size $path(output)]" } else { set result ok } } ok # Tests closing a channel. The functions tested are CloseChannel and Tcl_Close. test io-28.1 {CloseChannel called when all references are dropped} {testchannel} { file delete $path(test1) set f [open $path(test1) w] interp create x interp share "" $f x set l "" lappend l [testchannel refcount $f] x eval close $f interp delete x lappend l [testchannel refcount $f] close $f set l } {2 1} test io-28.2 {CloseChannel called when all references are dropped} { file delete $path(test1) set f [open $path(test1) w] interp create x interp share "" $f x puts -nonewline $f abc close $f x eval puts $f def x eval close $f interp delete x set f [open $path(test1) r] set l [gets $f] close $f set l } abcdef test io-28.3 {CloseChannel, not called before output queue is empty} \ {stdio asyncPipeClose nonPortable openpipe} { file delete $path(pipe) file delete $path(output) set f [open $path(pipe) w] puts $f { # Need to not have eof char appended on close, because the other # side of the pipe already closed, so that writing would cause an # error "invalid file". fconfigure stdout -eofchar {} fconfigure stderr -eofchar {} set f [open $path(output) w] fconfigure $f -translation lf -buffering none for {set x 0} {$x < 20} {incr x} { after 20 puts -nonewline $f [read stdin 1024] } close $f } close $f set x 01234567890123456789012345678901 for {set i 0} {$i < 11} {incr i} { set x "$x$x" } set f [open $path(output) w] close $f set f [open "|[list [interpreter] pipe]" r+] fconfigure $f -blocking off -eofchar {} puts -nonewline $f $x close $f set counter 0 while {([file size $path(output)] < 20480) && ($counter < 1000)} { incr counter after 20 update } if {$counter == 1000} { set result probably_broken } else { set result ok } } ok test io-28.4 {Tcl_Close} {testchannel} { file delete $path(test1) set l "" lappend l [lsort [testchannel open]] set f [open $path(test1) w] lappend l [lsort [testchannel open]] close $f lappend l [lsort [testchannel open]] set x [list $consoleFileNames \ [lsort [eval list $consoleFileNames $f]] \ $consoleFileNames] string compare $l $x } 0 test io-28.5 {Tcl_Close vs standard handles} {stdio unixOnly testchannel openpipe} { file delete $path(script) set f [open $path(script) w] puts $f { close stdin puts [testchannel open] } close $f set f [open "|[list [interpreter] $path(script)]" r] set l [gets $f] close $f set l } {file1 file2} test io-29.1 {Tcl_WriteChars, channel not writable} { list [catch {puts stdin hello} msg] $msg } {1 {channel "stdin" wasn't opened for writing}} test io-29.2 {Tcl_WriteChars, empty string} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -eofchar {} puts -nonewline $f "" close $f file size $path(test1) } 0 test io-29.3 {Tcl_WriteChars, nonempty string} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -eofchar {} puts -nonewline $f hello close $f file size $path(test1) } 5 test io-29.4 {Tcl_WriteChars, buffering in full buffering mode} {testchannel} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf -buffering full -eofchar {} puts $f hello set l "" lappend l [testchannel outputbuffered $f] lappend l [file size $path(test1)] flush $f lappend l [testchannel outputbuffered $f] lappend l [file size $path(test1)] close $f set l } {6 0 0 6} test io-29.5 {Tcl_WriteChars, buffering in line buffering mode} {testchannel} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf -buffering line -eofchar {} puts -nonewline $f hello set l "" lappend l [testchannel outputbuffered $f] lappend l [file size $path(test1)] puts $f hello lappend l [testchannel outputbuffered $f] lappend l [file size $path(test1)] close $f set l } {5 0 0 11} test io-29.6 {Tcl_WriteChars, buffering in no buffering mode} {testchannel} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf -buffering none -eofchar {} puts -nonewline $f hello set l "" lappend l [testchannel outputbuffered $f] lappend l [file size $path(test1)] puts $f hello lappend l [testchannel outputbuffered $f] lappend l [file size $path(test1)] close $f set l } {0 5 0 11} test io-29.7 {Tcl_Flush, full buffering} {testchannel} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf -buffering full -eofchar {} puts -nonewline $f hello set l "" lappend l [testchannel outputbuffered $f] lappend l [file size $path(test1)] puts $f hello lappend l [testchannel outputbuffered $f] lappend l [file size $path(test1)] flush $f lappend l [testchannel outputbuffered $f] lappend l [file size $path(test1)] close $f set l } {5 0 11 0 0 11} test io-29.8 {Tcl_Flush, full buffering} {testchannel} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf -buffering line puts -nonewline $f hello set l "" lappend l [testchannel outputbuffered $f] lappend l [file size $path(test1)] flush $f lappend l [testchannel outputbuffered $f] lappend l [file size $path(test1)] puts $f hello lappend l [testchannel outputbuffered $f] lappend l [file size $path(test1)] flush $f lappend l [testchannel outputbuffered $f] lappend l [file size $path(test1)] close $f set l } {5 0 0 5 0 11 0 11} test io-29.9 {Tcl_Flush, channel not writable} { list [catch {flush stdin} msg] $msg } {1 {channel "stdin" wasn't opened for writing}} test io-29.10 {Tcl_WriteChars, looping and buffering} { file delete $path(test1) set f1 [open $path(test1) w] fconfigure $f1 -translation lf -eofchar {} set f2 [open $path(longfile) r] for {set x 0} {$x < 10} {incr x} { puts $f1 [gets $f2] } close $f2 close $f1 file size $path(test1) } 387 test io-29.11 {Tcl_WriteChars, no newline, implicit flush} { file delete $path(test1) set f1 [open $path(test1) w] fconfigure $f1 -eofchar {} set f2 [open $path(longfile) r] for {set x 0} {$x < 10} {incr x} { puts -nonewline $f1 [gets $f2] } close $f1 close $f2 file size $path(test1) } 377 test io-29.12 {Tcl_WriteChars on a pipe} {stdio openpipe} { file delete $path(test1) file delete $path(pipe) set f1 [open $path(pipe) w] puts $f1 "set f1 \[[list open $path(longfile) r]]" puts $f1 { for {set x 0} {$x < 10} {incr x} { puts [gets $f1] } } close $f1 set f1 [open "|[list [interpreter] $path(pipe)]" r] set f2 [open $path(longfile) r] set y ok for {set x 0} {$x < 10} {incr x} { set l1 [gets $f1] set l2 [gets $f2] if {"$l1" != "$l2"} { set y broken } } close $f1 close $f2 set y } ok test io-29.13 {Tcl_WriteChars to a pipe, line buffered} {stdio openpipe} { file delete $path(test1) file delete $path(pipe) set f1 [open $path(pipe) w] puts $f1 { puts [gets stdin] puts [gets stdin] } close $f1 set y ok set f1 [open "|[list [interpreter] $path(pipe)]" r+] fconfigure $f1 -buffering line set f2 [open $path(longfile) r] set line [gets $f2] puts $f1 $line set backline [gets $f1] if {"$line" != "$backline"} { set y broken } set line [gets $f2] puts $f1 $line set backline [gets $f1] if {"$line" != "$backline"} { set y broken } close $f1 close $f2 set y } ok test io-29.14 {Tcl_WriteChars, buffering and implicit flush at close} { file delete $path(test3) set f [open $path(test3) w] puts -nonewline $f "Text1" puts -nonewline $f " Text 2" puts $f " Text 3" close $f set f [open $path(test3) r] set x [gets $f] close $f set x } {Text1 Text 2 Text 3} test io-29.15 {Tcl_Flush, channel not open for writing} { file delete $path(test1) set fd [open $path(test1) w] close $fd set fd [open $path(test1) r] set x [list [catch {flush $fd} msg] $msg] close $fd string compare $x \ [list 1 "channel \"$fd\" wasn't opened for writing"] } 0 test io-29.16 {Tcl_Flush on pipe opened only for reading} {stdio openpipe} { set fd [open "|[list [interpreter] cat longfile]" r] set x [list [catch {flush $fd} msg] $msg] catch {close $fd} string compare $x \ [list 1 "channel \"$fd\" wasn't opened for writing"] } 0 test io-29.17 {Tcl_WriteChars buffers, then Tcl_Flush flushes} { file delete $path(test1) set f1 [open $path(test1) w] fconfigure $f1 -translation lf puts $f1 hello puts $f1 hello puts $f1 hello flush $f1 set x [file size $path(test1)] close $f1 set x } 18 test io-29.18 {Tcl_WriteChars and Tcl_Flush intermixed} { file delete $path(test1) set x "" set f1 [open $path(test1) w] fconfigure $f1 -translation lf puts $f1 hello puts $f1 hello puts $f1 hello flush $f1 lappend x [file size $path(test1)] puts $f1 hello flush $f1 lappend x [file size $path(test1)] puts $f1 hello flush $f1 lappend x [file size $path(test1)] close $f1 set x } {18 24 30} test io-29.19 {Explicit and implicit flushes} { file delete $path(test1) set f1 [open $path(test1) w] fconfigure $f1 -translation lf -eofchar {} set x "" puts $f1 hello puts $f1 hello puts $f1 hello flush $f1 lappend x [file size $path(test1)] puts $f1 hello flush $f1 lappend x [file size $path(test1)] puts $f1 hello close $f1 lappend x [file size $path(test1)] set x } {18 24 30} test io-29.20 {Implicit flush when buffer is full} { file delete $path(test1) set f1 [open $path(test1) w] fconfigure $f1 -translation lf -eofchar {} set line "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" for {set x 0} {$x < 100} {incr x} { puts $f1 $line } set z "" lappend z [file size $path(test1)] for {set x 0} {$x < 100} {incr x} { puts $f1 $line } lappend z [file size $path(test1)] close $f1 lappend z [file size $path(test1)] set z } {4096 12288 12600} test io-29.21 {Tcl_Flush to pipe} {stdio openpipe} { file delete $path(pipe) set f1 [open $path(pipe) w] puts $f1 {set x [read stdin 6]} puts $f1 {set cnt [string length $x]} puts $f1 {puts "read $cnt characters"} close $f1 set f1 [open "|[list [interpreter] $path(pipe)]" r+] puts $f1 hello flush $f1 set x [gets $f1] catch {close $f1} set x } "read 6 characters" test io-29.22 {Tcl_Flush called at other end of pipe} {stdio openpipe} { file delete $path(pipe) set f1 [open $path(pipe) w] puts $f1 { fconfigure stdout -buffering full puts hello puts hello flush stdout gets stdin puts bye flush stdout } close $f1 set f1 [open "|[list [interpreter] $path(pipe)]" r+] set x "" lappend x [gets $f1] lappend x [gets $f1] puts $f1 hello flush $f1 lappend x [gets $f1] close $f1 set x } {hello hello bye} test io-29.23 {Tcl_Flush and line buffering at end of pipe} {stdio openpipe} { file delete $path(pipe) set f1 [open $path(pipe) w] puts $f1 { puts hello puts hello gets stdin puts bye } close $f1 set f1 [open "|[list [interpreter] $path(pipe)]" r+] set x "" lappend x [gets $f1] lappend x [gets $f1] puts $f1 hello flush $f1 lappend x [gets $f1] close $f1 set x } {hello hello bye} test io-29.24 {Tcl_WriteChars and Tcl_Flush move end of file} { set f [open $path(test3) w] puts $f "Line 1" puts $f "Line 2" set f2 [open $path(test3)] set x {} lappend x [read -nonewline $f2] close $f2 flush $f set f2 [open $path(test3)] lappend x [read -nonewline $f2] close $f2 close $f set x } "{} {Line 1\nLine 2}" test io-29.25 {Implicit flush with Tcl_Flush to command pipelines} {stdio openpipe fileevent} { file delete $path(test3) set f [open "|[list [interpreter] $path(cat) | [interpreter] $path(cat) > $path(test3)]" w] puts $f "Line 1" puts $f "Line 2" close $f after 100 set f [open $path(test3) r] set x [read $f] close $f set x } "Line 1\nLine 2\n" test io-29.26 {Tcl_Flush, Tcl_Write on bidirectional pipelines} {stdio unixExecs openpipe} { set f [open "|[list cat -u]" r+] puts $f "Line1" flush $f set x [gets $f] close $f set x } {Line1} test io-29.27 {Tcl_Flush on closed pipeline} {stdio openpipe} { file delete $path(pipe) set f [open $path(pipe) w] puts $f {exit} close $f set f [open "|[list [interpreter] $path(pipe)]" r+] gets $f puts $f output after 50 # # The flush below will get a SIGPIPE. This is an expected part of # test and indicates that the test operates correctly. If you run # this test under a debugger, the signal will by intercepted unless # you disable the debugger's signal interception. # if {[catch {flush $f} msg]} { set x [list 1 $msg $errorCode] catch {close $f} } else { if {[catch {close $f} msg]} { set x [list 1 $msg $errorCode] } else { set x {this was supposed to fail and did not} } } regsub {".*":} $x {"":} x string tolower $x } {1 {error flushing "": broken pipe} {posix epipe {broken pipe}}} test io-29.28 {Tcl_WriteChars, lf mode} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf -eofchar {} puts $f hello\nthere\nand\nhere flush $f set s [file size $path(test1)] close $f set s } 21 test io-29.29 {Tcl_WriteChars, cr mode} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation cr -eofchar {} puts $f hello\nthere\nand\nhere close $f file size $path(test1) } 21 test io-29.30 {Tcl_WriteChars, crlf mode} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation crlf -eofchar {} puts $f hello\nthere\nand\nhere close $f file size $path(test1) } 25 test io-29.31 {Tcl_WriteChars, background flush} {stdio openpipe} { file delete $path(pipe) file delete $path(output) set f [open $path(pipe) w] puts $f "set f \[[list open $path(output) w]]" puts $f {fconfigure $f -translation lf} set x [list while {![eof stdin]}] set x "$x {" puts $f $x puts $f { puts -nonewline $f [read stdin 4096]} puts $f { flush $f} puts $f "}" puts $f {close $f} close $f set x 01234567890123456789012345678901 for {set i 0} {$i < 11} {incr i} { set x "$x$x" } set f [open $path(output) w] close $f set f [open "|[list [interpreter] $path(pipe)]" r+] fconfigure $f -blocking off puts -nonewline $f $x close $f set counter 0 while {([file size $path(output)] < 65536) && ($counter < 1000)} { incr counter after 5 update } if {$counter == 1000} { set result "file size only [file size $path(output)]" } else { set result ok } } ok test io-29.32 {Tcl_WriteChars, background flush to slow reader} \ {stdio asyncPipeClose openpipe} { file delete $path(pipe) file delete $path(output) set f [open $path(pipe) w] puts $f "set f \[[list open $path(output) w]]" puts $f {fconfigure $f -translation lf} set x [list while {![eof stdin]}] set x "$x \{" puts $f $x puts $f { after 20} puts $f { puts -nonewline $f [read stdin 1024]} puts $f { flush $f} puts $f "\}" puts $f {close $f} close $f set x 01234567890123456789012345678901 for {set i 0} {$i < 11} {incr i} { set x "$x$x" } set f [open $path(output) w] close $f set f [open "|[list [interpreter] $path(pipe)]" r+] fconfigure $f -blocking off puts -nonewline $f $x close $f set counter 0 while {([file size $path(output)] < 65536) && ($counter < 1000)} { incr counter after 20 update } if {$counter == 1000} { set result "file size only [file size $path(output)]" } else { set result ok } } ok test io-29.33 {Tcl_Flush, implicit flush on exit} {exec} { set f [open $path(script) w] puts $f "set f \[[list open $path(test1) w]]" puts $f {fconfigure $f -translation lf puts $f hello puts $f bye puts $f strange } close $f exec [interpreter] $path(script) set f [open $path(test1) r] set r [read $f] close $f set r } "hello\nbye\nstrange\n" test io-29.34 {Tcl_Close, async flush on close, using sockets} {socket tempNotMac fileevent} { variable c 0 variable x running set l abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz proc writelots {s l} { for {set i 0} {$i < 2000} {incr i} { puts $s $l } } proc accept {s a p} { variable x fileevent $s readable [namespace code [list readit $s]] fconfigure $s -blocking off set x accepted } proc readit {s} { variable c variable x set l [gets $s] if {[eof $s]} { close $s set x done } elseif {([string length $l] > 0) || ![fblocked $s]} { incr c } } set ss [socket -server [namespace code accept] 0] set cs [socket [info hostname] [lindex [fconfigure $ss -sockname] 2]] vwait [namespace which -variable x] fconfigure $cs -blocking off writelots $cs $l close $cs close $ss vwait [namespace which -variable x] set c } 2000 test io-29.35 {Tcl_Close vs fileevent vs multiple interpreters} {socket tempNotMac fileevent} { # On Mac, this test screws up sockets such that subsequent tests using port 2828 # either cause errors or panic(). catch {interp delete x} catch {interp delete y} interp create x interp create y set s [socket -server [namespace code accept] 0] proc accept {s a p} { puts $s hello close $s } set c [socket [info hostname] [lindex [fconfigure $s -sockname] 2]] interp share {} $c x interp share {} $c y close $c x eval { proc readit {s} { gets $s if {[eof $s]} { close $s } } } y eval { proc readit {s} { gets $s if {[eof $s]} { close $s } } } x eval "fileevent $c readable \{readit $c\}" y eval "fileevent $c readable \{readit $c\}" y eval [list close $c] update close $s interp delete x interp delete y } "" # Test end of line translations. Procedures tested are Tcl_Write, Tcl_Read. test io-30.1 {Tcl_Write lf, Tcl_Read lf} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf puts $f hello\nthere\nand\nhere close $f set f [open $path(test1) r] fconfigure $f -translation lf set x [read $f] close $f set x } "hello\nthere\nand\nhere\n" test io-30.2 {Tcl_Write lf, Tcl_Read cr} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf puts $f hello\nthere\nand\nhere close $f set f [open $path(test1) r] fconfigure $f -translation cr set x [read $f] close $f set x } "hello\nthere\nand\nhere\n" test io-30.3 {Tcl_Write lf, Tcl_Read crlf} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf puts $f hello\nthere\nand\nhere close $f set f [open $path(test1) r] fconfigure $f -translation crlf set x [read $f] close $f set x } "hello\nthere\nand\nhere\n" test io-30.4 {Tcl_Write cr, Tcl_Read cr} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation cr puts $f hello\nthere\nand\nhere close $f set f [open $path(test1) r] fconfigure $f -translation cr set x [read $f] close $f set x } "hello\nthere\nand\nhere\n" test io-30.5 {Tcl_Write cr, Tcl_Read lf} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation cr puts $f hello\nthere\nand\nhere close $f set f [open $path(test1) r] fconfigure $f -translation lf set x [read $f] close $f set x } "hello\rthere\rand\rhere\r" test io-30.6 {Tcl_Write cr, Tcl_Read crlf} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation cr puts $f hello\nthere\nand\nhere close $f set f [open $path(test1) r] fconfigure $f -translation crlf set x [read $f] close $f set x } "hello\rthere\rand\rhere\r" test io-30.7 {Tcl_Write crlf, Tcl_Read crlf} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation crlf puts $f hello\nthere\nand\nhere close $f set f [open $path(test1) r] fconfigure $f -translation crlf set x [read $f] close $f set x } "hello\nthere\nand\nhere\n" test io-30.8 {Tcl_Write crlf, Tcl_Read lf} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation crlf puts $f hello\nthere\nand\nhere close $f set f [open $path(test1) r] fconfigure $f -translation lf set x [read $f] close $f set x } "hello\r\nthere\r\nand\r\nhere\r\n" test io-30.9 {Tcl_Write crlf, Tcl_Read cr} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation crlf puts $f hello\nthere\nand\nhere close $f set f [open $path(test1) r] fconfigure $f -translation cr set x [read $f] close $f set x } "hello\n\nthere\n\nand\n\nhere\n\n" test io-30.10 {Tcl_Write lf, Tcl_Read auto} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf puts $f hello\nthere\nand\nhere close $f set f [open $path(test1) r] set c [read $f] set x [fconfigure $f -translation] close $f list $c $x } {{hello there and here } auto} test io-30.11 {Tcl_Write cr, Tcl_Read auto} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation cr puts $f hello\nthere\nand\nhere close $f set f [open $path(test1) r] set c [read $f] set x [fconfigure $f -translation] close $f list $c $x } {{hello there and here } auto} test io-30.12 {Tcl_Write crlf, Tcl_Read auto} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation crlf puts $f hello\nthere\nand\nhere close $f set f [open $path(test1) r] set c [read $f] set x [fconfigure $f -translation] close $f list $c $x } {{hello there and here } auto} test io-30.13 {Tcl_Write crlf on block boundary, Tcl_Read auto} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation crlf set line "123456789ABCDE" ;# 14 char plus crlf puts -nonewline $f x ;# shift crlf across block boundary for {set i 0} {$i < 700} {incr i} { puts $f $line } close $f set f [open $path(test1) r] fconfigure $f -translation auto set c [read $f] close $f string length $c } [expr 700*15+1] test io-30.14 {Tcl_Write crlf on block boundary, Tcl_Read crlf} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation crlf set line "123456789ABCDE" ;# 14 char plus crlf puts -nonewline $f x ;# shift crlf across block boundary for {set i 0} {$i < 700} {incr i} { puts $f $line } close $f set f [open $path(test1) r] fconfigure $f -translation crlf set c [read $f] close $f string length $c } [expr 700*15+1] test io-30.15 {Tcl_Write mixed, Tcl_Read auto} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf puts $f hello\nthere\nand\rhere close $f set f [open $path(test1) r] fconfigure $f -translation auto set c [read $f] close $f set c } {hello there and here } test io-30.16 {Tcl_Write ^Z at end, Tcl_Read auto} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f hello\nthere\nand\rhere\n\x1a close $f set f [open $path(test1) r] fconfigure $f -eofchar \x1a -translation auto set c [read $f] close $f set c } {hello there and here } test io-30.17 {Tcl_Write, implicit ^Z at end, Tcl_Read auto} {pcOnly} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -eofchar \x1a -translation lf puts $f hello\nthere\nand\rhere close $f set f [open $path(test1) r] fconfigure $f -eofchar \x1a -translation auto set c [read $f] close $f set c } {hello there and here } test io-30.18 {Tcl_Write, ^Z in middle, Tcl_Read auto} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf set s [format "abc\ndef\n%cghi\nqrs" 26] puts $f $s close $f set f [open $path(test1) r] fconfigure $f -eofchar \x1a -translation auto set l "" lappend l [gets $f] lappend l [gets $f] lappend l [eof $f] lappend l [gets $f] lappend l [eof $f] lappend l [gets $f] lappend l [eof $f] close $f set l } {abc def 0 {} 1 {} 1} test io-30.19 {Tcl_Write, ^Z no newline in middle, Tcl_Read auto} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf set s [format "abc\ndef\n%cghi\nqrs" 26] puts $f $s close $f set f [open $path(test1) r] fconfigure $f -eofchar \x1a -translation auto set l "" lappend l [gets $f] lappend l [gets $f] lappend l [eof $f] lappend l [gets $f] lappend l [eof $f] lappend l [gets $f] lappend l [eof $f] close $f set l } {abc def 0 {} 1 {} 1} test io-30.20 {Tcl_Write, ^Z in middle ignored, Tcl_Read lf} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf -eofchar {} set s [format "abc\ndef\n%cghi\nqrs" 26] puts $f $s close $f set f [open $path(test1) r] fconfigure $f -translation lf -eofchar {} set l "" lappend l [gets $f] lappend l [gets $f] lappend l [eof $f] lappend l [gets $f] lappend l [eof $f] lappend l [gets $f] lappend l [eof $f] lappend l [gets $f] lappend l [eof $f] close $f set l } "abc def 0 \x1aghi 0 qrs 0 {} 1" test io-30.21 {Tcl_Write, ^Z in middle ignored, Tcl_Read cr} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf -eofchar {} set s [format "abc\ndef\n%cghi\nqrs" 26] puts $f $s close $f set f [open $path(test1) r] fconfigure $f -translation cr -eofchar {} set l "" set x [gets $f] lappend l [string compare $x "abc\ndef\n\x1aghi\nqrs\n"] lappend l [eof $f] lappend l [gets $f] lappend l [eof $f] close $f set l } {0 1 {} 1} test io-30.22 {Tcl_Write, ^Z in middle ignored, Tcl_Read crlf} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf -eofchar {} set s [format "abc\ndef\n%cghi\nqrs" 26] puts $f $s close $f set f [open $path(test1) r] fconfigure $f -translation crlf -eofchar {} set l "" set x [gets $f] lappend l [string compare $x "abc\ndef\n\x1aghi\nqrs\n"] lappend l [eof $f] lappend l [gets $f] lappend l [eof $f] close $f set l } {0 1 {} 1} test io-30.23 {Tcl_Write lf, ^Z in middle, Tcl_Read auto} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf set c [format abc\ndef\n%cqrs\ntuv 26] puts $f $c close $f set f [open $path(test1) r] fconfigure $f -translation auto -eofchar \x1a set c [string length [read $f]] set e [eof $f] close $f list $c $e } {8 1} test io-30.24 {Tcl_Write lf, ^Z in middle, Tcl_Read lf} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf set c [format abc\ndef\n%cqrs\ntuv 26] puts $f $c close $f set f [open $path(test1) r] fconfigure $f -translation lf -eofchar \x1a set c [string length [read $f]] set e [eof $f] close $f list $c $e } {8 1} test io-30.25 {Tcl_Write cr, ^Z in middle, Tcl_Read auto} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation cr set c [format abc\ndef\n%cqrs\ntuv 26] puts $f $c close $f set f [open $path(test1) r] fconfigure $f -translation auto -eofchar \x1a set c [string length [read $f]] set e [eof $f] close $f list $c $e } {8 1} test io-30.26 {Tcl_Write cr, ^Z in middle, Tcl_Read cr} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation cr set c [format abc\ndef\n%cqrs\ntuv 26] puts $f $c close $f set f [open $path(test1) r] fconfigure $f -translation cr -eofchar \x1a set c [string length [read $f]] set e [eof $f] close $f list $c $e } {8 1} test io-30.27 {Tcl_Write crlf, ^Z in middle, Tcl_Read auto} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation crlf set c [format abc\ndef\n%cqrs\ntuv 26] puts $f $c close $f set f [open $path(test1) r] fconfigure $f -translation auto -eofchar \x1a set c [string length [read $f]] set e [eof $f] close $f list $c $e } {8 1} test io-30.28 {Tcl_Write crlf, ^Z in middle, Tcl_Read crlf} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation crlf set c [format abc\ndef\n%cqrs\ntuv 26] puts $f $c close $f set f [open $path(test1) r] fconfigure $f -translation crlf -eofchar \x1a set c [string length [read $f]] set e [eof $f] close $f list $c $e } {8 1} # Test end of line translations. Functions tested are Tcl_Write and Tcl_Gets. test io-31.1 {Tcl_Write lf, Tcl_Gets auto} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf puts $f hello\nthere\nand\nhere close $f set f [open $path(test1) r] set l "" lappend l [gets $f] lappend l [tell $f] lappend l [fconfigure $f -translation] lappend l [gets $f] lappend l [tell $f] lappend l [fconfigure $f -translation] close $f set l } {hello 6 auto there 12 auto} test io-31.2 {Tcl_Write cr, Tcl_Gets auto} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation cr puts $f hello\nthere\nand\nhere close $f set f [open $path(test1) r] set l "" lappend l [gets $f] lappend l [tell $f] lappend l [fconfigure $f -translation] lappend l [gets $f] lappend l [tell $f] lappend l [fconfigure $f -translation] close $f set l } {hello 6 auto there 12 auto} test io-31.3 {Tcl_Write crlf, Tcl_Gets auto} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation crlf puts $f hello\nthere\nand\nhere close $f set f [open $path(test1) r] set l "" lappend l [gets $f] lappend l [tell $f] lappend l [fconfigure $f -translation] lappend l [gets $f] lappend l [tell $f] lappend l [fconfigure $f -translation] close $f set l } {hello 7 auto there 14 auto} test io-31.4 {Tcl_Write lf, Tcl_Gets lf} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf puts $f hello\nthere\nand\nhere close $f set f [open $path(test1) r] fconfigure $f -translation lf set l "" lappend l [gets $f] lappend l [tell $f] lappend l [fconfigure $f -translation] lappend l [gets $f] lappend l [tell $f] lappend l [fconfigure $f -translation] close $f set l } {hello 6 lf there 12 lf} test io-31.5 {Tcl_Write lf, Tcl_Gets cr} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf puts $f hello\nthere\nand\nhere close $f set f [open $path(test1) r] fconfigure $f -translation cr set l "" lappend l [string length [gets $f]] lappend l [tell $f] lappend l [fconfigure $f -translation] lappend l [eof $f] lappend l [gets $f] lappend l [tell $f] lappend l [fconfigure $f -translation] lappend l [eof $f] close $f set l } {21 21 cr 1 {} 21 cr 1} test io-31.6 {Tcl_Write lf, Tcl_Gets crlf} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf puts $f hello\nthere\nand\nhere close $f set f [open $path(test1) r] fconfigure $f -translation crlf set l "" lappend l [string length [gets $f]] lappend l [tell $f] lappend l [fconfigure $f -translation] lappend l [eof $f] lappend l [gets $f] lappend l [tell $f] lappend l [fconfigure $f -translation] lappend l [eof $f] close $f set l } {21 21 crlf 1 {} 21 crlf 1} test io-31.7 {Tcl_Write cr, Tcl_Gets cr} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation cr puts $f hello\nthere\nand\nhere close $f set f [open $path(test1) r] fconfigure $f -translation cr set l "" lappend l [gets $f] lappend l [tell $f] lappend l [fconfigure $f -translation] lappend l [eof $f] lappend l [gets $f] lappend l [tell $f] lappend l [fconfigure $f -translation] lappend l [eof $f] close $f set l } {hello 6 cr 0 there 12 cr 0} test io-31.8 {Tcl_Write cr, Tcl_Gets lf} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation cr puts $f hello\nthere\nand\nhere close $f set f [open $path(test1) r] fconfigure $f -translation lf set l "" lappend l [string length [gets $f]] lappend l [tell $f] lappend l [fconfigure $f -translation] lappend l [eof $f] lappend l [gets $f] lappend l [tell $f] lappend l [fconfigure $f -translation] lappend l [eof $f] close $f set l } {21 21 lf 1 {} 21 lf 1} test io-31.9 {Tcl_Write cr, Tcl_Gets crlf} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation cr puts $f hello\nthere\nand\nhere close $f set f [open $path(test1) r] fconfigure $f -translation crlf set l "" lappend l [string length [gets $f]] lappend l [tell $f] lappend l [fconfigure $f -translation] lappend l [eof $f] lappend l [gets $f] lappend l [tell $f] lappend l [fconfigure $f -translation] lappend l [eof $f] close $f set l } {21 21 crlf 1 {} 21 crlf 1} test io-31.10 {Tcl_Write crlf, Tcl_Gets crlf} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation crlf puts $f hello\nthere\nand\nhere close $f set f [open $path(test1) r] fconfigure $f -translation crlf set l "" lappend l [gets $f] lappend l [tell $f] lappend l [fconfigure $f -translation] lappend l [eof $f] lappend l [gets $f] lappend l [tell $f] lappend l [fconfigure $f -translation] lappend l [eof $f] close $f set l } {hello 7 crlf 0 there 14 crlf 0} test io-31.11 {Tcl_Write crlf, Tcl_Gets cr} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation crlf puts $f hello\nthere\nand\nhere close $f set f [open $path(test1) r] fconfigure $f -translation cr set l "" lappend l [gets $f] lappend l [tell $f] lappend l [fconfigure $f -translation] lappend l [eof $f] lappend l [string length [gets $f]] lappend l [tell $f] lappend l [fconfigure $f -translation] lappend l [eof $f] close $f set l } {hello 6 cr 0 6 13 cr 0} test io-31.12 {Tcl_Write crlf, Tcl_Gets lf} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation crlf puts $f hello\nthere\nand\nhere close $f set f [open $path(test1) r] fconfigure $f -translation lf set l "" lappend l [string length [gets $f]] lappend l [tell $f] lappend l [fconfigure $f -translation] lappend l [eof $f] lappend l [string length [gets $f]] lappend l [tell $f] lappend l [fconfigure $f -translation] lappend l [eof $f] close $f set l } {6 7 lf 0 6 14 lf 0} test io-31.13 {binary mode is synonym of lf mode} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation binary set x [fconfigure $f -translation] close $f set x } lf # # Test io-9.14 has been removed because "auto" output translation mode is # not supoprted. # test io-31.14 {Tcl_Write mixed, Tcl_Gets auto} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf puts $f hello\nthere\rand\r\nhere close $f set f [open $path(test1) r] fconfigure $f -translation auto set l "" lappend l [gets $f] lappend l [gets $f] lappend l [gets $f] lappend l [gets $f] lappend l [eof $f] lappend l [gets $f] lappend l [eof $f] close $f set l } {hello there and here 0 {} 1} test io-31.15 {Tcl_Write mixed, Tcl_Gets auto} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f hello\nthere\rand\r\nhere\r close $f set f [open $path(test1) r] fconfigure $f -translation auto set l "" lappend l [gets $f] lappend l [gets $f] lappend l [gets $f] lappend l [gets $f] lappend l [eof $f] lappend l [gets $f] lappend l [eof $f] close $f set l } {hello there and here 0 {} 1} test io-31.16 {Tcl_Write mixed, Tcl_Gets auto} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f hello\nthere\rand\r\nhere\n close $f set f [open $path(test1) r] set l "" lappend l [gets $f] lappend l [gets $f] lappend l [gets $f] lappend l [gets $f] lappend l [eof $f] lappend l [gets $f] lappend l [eof $f] close $f set l } {hello there and here 0 {} 1} test io-31.17 {Tcl_Write mixed, Tcl_Gets auto} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f hello\nthere\rand\r\nhere\r\n close $f set f [open $path(test1) r] fconfigure $f -translation auto set l "" lappend l [gets $f] lappend l [gets $f] lappend l [gets $f] lappend l [gets $f] lappend l [eof $f] lappend l [gets $f] lappend l [eof $f] close $f set l } {hello there and here 0 {} 1} test io-31.18 {Tcl_Write ^Z at end, Tcl_Gets auto} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf set s [format "hello\nthere\nand\rhere\n\%c" 26] puts $f $s close $f set f [open $path(test1) r] fconfigure $f -eofchar \x1a -translation auto set l "" lappend l [gets $f] lappend l [gets $f] lappend l [gets $f] lappend l [gets $f] lappend l [eof $f] lappend l [gets $f] lappend l [eof $f] close $f set l } {hello there and here 0 {} 1} test io-31.19 {Tcl_Write, implicit ^Z at end, Tcl_Gets auto} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -eofchar \x1a -translation lf puts $f hello\nthere\nand\rhere close $f set f [open $path(test1) r] fconfigure $f -eofchar \x1a -translation auto set l "" lappend l [gets $f] lappend l [gets $f] lappend l [gets $f] lappend l [gets $f] lappend l [eof $f] lappend l [gets $f] lappend l [eof $f] close $f set l } {hello there and here 0 {} 1} test io-31.20 {Tcl_Write, ^Z in middle, Tcl_Gets auto, eofChar} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf set s [format "abc\ndef\n%cqrs\ntuv" 26] puts $f $s close $f set f [open $path(test1) r] fconfigure $f -eofchar \x1a fconfigure $f -translation auto set l "" lappend l [gets $f] lappend l [gets $f] lappend l [eof $f] lappend l [gets $f] lappend l [eof $f] close $f set l } {abc def 0 {} 1} test io-31.21 {Tcl_Write, no newline ^Z in middle, Tcl_Gets auto, eofChar} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf set s [format "abc\ndef\n%cqrs\ntuv" 26] puts $f $s close $f set f [open $path(test1) r] fconfigure $f -eofchar \x1a -translation auto set l "" lappend l [gets $f] lappend l [gets $f] lappend l [eof $f] lappend l [gets $f] lappend l [eof $f] close $f set l } {abc def 0 {} 1} test io-31.22 {Tcl_Write, ^Z in middle ignored, Tcl_Gets lf} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf -eofchar {} set s [format "abc\ndef\n%cqrs\ntuv" 26] puts $f $s close $f set f [open $path(test1) r] fconfigure $f -translation lf -eofchar {} set l "" lappend l [gets $f] lappend l [gets $f] lappend l [eof $f] lappend l [gets $f] lappend l [eof $f] lappend l [gets $f] lappend l [eof $f] lappend l [gets $f] lappend l [eof $f] close $f set l } "abc def 0 \x1aqrs 0 tuv 0 {} 1" test io-31.23 {Tcl_Write, ^Z in middle ignored, Tcl_Gets cr} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation cr -eofchar {} set s [format "abc\ndef\n%cqrs\ntuv" 26] puts $f $s close $f set f [open $path(test1) r] fconfigure $f -translation cr -eofchar {} set l "" lappend l [gets $f] lappend l [gets $f] lappend l [eof $f] lappend l [gets $f] lappend l [eof $f] lappend l [gets $f] lappend l [eof $f] lappend l [gets $f] lappend l [eof $f] close $f set l } "abc def 0 \x1aqrs 0 tuv 0 {} 1" test io-31.24 {Tcl_Write, ^Z in middle ignored, Tcl_Gets crlf} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation crlf -eofchar {} set s [format "abc\ndef\n%cqrs\ntuv" 26] puts $f $s close $f set f [open $path(test1) r] fconfigure $f -translation crlf -eofchar {} set l "" lappend l [gets $f] lappend l [gets $f] lappend l [eof $f] lappend l [gets $f] lappend l [eof $f] lappend l [gets $f] lappend l [eof $f] lappend l [gets $f] lappend l [eof $f] close $f set l } "abc def 0 \x1aqrs 0 tuv 0 {} 1" test io-31.25 {Tcl_Write lf, ^Z in middle, Tcl_Gets auto} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf set s [format "abc\ndef\n%cqrs\ntuv" 26] puts $f $s close $f set f [open $path(test1) r] fconfigure $f -translation auto -eofchar \x1a set l "" lappend l [gets $f] lappend l [gets $f] lappend l [eof $f] lappend l [gets $f] lappend l [eof $f] close $f set l } {abc def 0 {} 1} test io-31.26 {Tcl_Write lf, ^Z in middle, Tcl_Gets lf} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf set s [format "abc\ndef\n%cqrs\ntuv" 26] puts $f $s close $f set f [open $path(test1) r] fconfigure $f -translation lf -eofchar \x1a set l "" lappend l [gets $f] lappend l [gets $f] lappend l [eof $f] lappend l [gets $f] lappend l [eof $f] close $f set l } {abc def 0 {} 1} test io-31.27 {Tcl_Write cr, ^Z in middle, Tcl_Gets auto} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation cr -eofchar {} set s [format "abc\ndef\n%cqrs\ntuv" 26] puts $f $s close $f set f [open $path(test1) r] fconfigure $f -translation auto -eofchar \x1a set l "" lappend l [gets $f] lappend l [gets $f] lappend l [eof $f] lappend l [gets $f] lappend l [eof $f] close $f set l } {abc def 0 {} 1} test io-31.28 {Tcl_Write cr, ^Z in middle, Tcl_Gets cr} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation cr -eofchar {} set s [format "abc\ndef\n%cqrs\ntuv" 26] puts $f $s close $f set f [open $path(test1) r] fconfigure $f -translation cr -eofchar \x1a set l "" lappend l [gets $f] lappend l [gets $f] lappend l [eof $f] lappend l [gets $f] lappend l [eof $f] close $f set l } {abc def 0 {} 1} test io-31.29 {Tcl_Write crlf, ^Z in middle, Tcl_Gets auto} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation crlf -eofchar {} set s [format "abc\ndef\n%cqrs\ntuv" 26] puts $f $s close $f set f [open $path(test1) r] fconfigure $f -translation auto -eofchar \x1a set l "" lappend l [gets $f] lappend l [gets $f] lappend l [eof $f] lappend l [gets $f] lappend l [eof $f] close $f set l } {abc def 0 {} 1} test io-31.30 {Tcl_Write crlf, ^Z in middle, Tcl_Gets crlf} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation crlf -eofchar {} set s [format "abc\ndef\n%cqrs\ntuv" 26] puts $f $s close $f set f [open $path(test1) r] fconfigure $f -translation crlf -eofchar \x1a set l "" lappend l [gets $f] lappend l [gets $f] lappend l [eof $f] lappend l [gets $f] lappend l [eof $f] close $f set l } {abc def 0 {} 1} test io-31.31 {Tcl_Write crlf on block boundary, Tcl_Gets crlf} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation crlf set line "123456789ABCDE" ;# 14 char plus crlf puts -nonewline $f x ;# shift crlf across block boundary for {set i 0} {$i < 700} {incr i} { puts $f $line } close $f set f [open $path(test1) r] fconfigure $f -translation crlf set c "" while {[gets $f line] >= 0} { append c $line\n } close $f string length $c } [expr 700*15+1] test io-31.32 {Tcl_Write crlf on block boundary, Tcl_Gets auto} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation crlf set line "123456789ABCDE" ;# 14 char plus crlf puts -nonewline $f x ;# shift crlf across block boundary for {set i 0} {$i < 700} {incr i} { puts $f $line } close $f set f [open $path(test1) r] fconfigure $f -translation auto set c "" while {[gets $f line] >= 0} { append c $line\n } close $f string length $c } [expr 700*15+1] # Test Tcl_Read and buffering. test io-32.1 {Tcl_Read, channel not readable} { list [catch {read stdout} msg] $msg } {1 {channel "stdout" wasn't opened for reading}} test io-32.2 {Tcl_Read, zero byte count} { read stdin 0 } "" test io-32.3 {Tcl_Read, negative byte count} { set f [open $path(longfile) r] set l [list [catch {read $f -1} msg] $msg] close $f set l } {1 {bad argument "-1": should be "nonewline"}} test io-32.4 {Tcl_Read, positive byte count} { set f [open $path(longfile) r] set x [read $f 1024] set s [string length $x] unset x close $f set s } 1024 test io-32.5 {Tcl_Read, multiple buffers} { set f [open $path(longfile) r] fconfigure $f -buffersize 100 set x [read $f 1024] set s [string length $x] unset x close $f set s } 1024 test io-32.6 {Tcl_Read, very large read} { set f1 [open $path(longfile) r] set z [read $f1 1000000] close $f1 set l [string length $z] set x ok set z [file size $path(longfile)] if {$z != $l} { set x broken } set x } ok test io-32.7 {Tcl_Read, nonblocking, file} {nonBlockFiles} { set f1 [open $path(longfile) r] fconfigure $f1 -blocking off set z [read $f1 20] close $f1 set l [string length $z] set x ok if {$l != 20} { set x broken } set x } ok test io-32.8 {Tcl_Read, nonblocking, file} {nonBlockFiles} { set f1 [open $path(longfile) r] fconfigure $f1 -blocking off set z [read $f1 1000000] close $f1 set x ok set l [string length $z] set z [file size $path(longfile)] if {$z != $l} { set x broken } set x } ok test io-32.9 {Tcl_Read, read to end of file} { set f1 [open $path(longfile) r] set z [read $f1] close $f1 set l [string length $z] set x ok set z [file size $path(longfile)] if {$z != $l} { set x broken } set x } ok test io-32.10 {Tcl_Read from a pipe} {stdio openpipe} { file delete $path(pipe) set f1 [open $path(pipe) w] puts $f1 {puts [gets stdin]} close $f1 set f1 [open "|[list [interpreter] $path(pipe)]" r+] puts $f1 hello flush $f1 set x [read $f1] close $f1 set x } "hello\n" test io-32.11 {Tcl_Read from a pipe} {stdio openpipe} { file delete $path(pipe) set f1 [open $path(pipe) w] puts $f1 {puts [gets stdin]} puts $f1 {puts [gets stdin]} close $f1 set f1 [open "|[list [interpreter] $path(pipe)]" r+] puts $f1 hello flush $f1 set x "" lappend x [read $f1 6] puts $f1 hello flush $f1 lappend x [read $f1] close $f1 set x } {{hello } {hello }} test io-32.12 {Tcl_Read, -nonewline} { file delete $path(test1) set f1 [open $path(test1) w] puts $f1 hello puts $f1 bye close $f1 set f1 [open $path(test1) r] set c [read -nonewline $f1] close $f1 set c } {hello bye} test io-32.13 {Tcl_Read, -nonewline} { file delete $path(test1) set f1 [open $path(test1) w] puts $f1 hello puts $f1 bye close $f1 set f1 [open $path(test1) r] set c [read -nonewline $f1] close $f1 list [string length $c] $c } {9 {hello bye}} test io-32.14 {Tcl_Read, reading in small chunks} { file delete $path(test1) set f [open $path(test1) w] puts $f "Two lines: this one" puts $f "and this one" close $f set f [open $path(test1)] set x [list [read $f 1] [read $f 2] [read $f]] close $f set x } {T wo { lines: this one and this one }} test io-32.15 {Tcl_Read, asking for more input than available} { file delete $path(test1) set f [open $path(test1) w] puts $f "Two lines: this one" puts $f "and this one" close $f set f [open $path(test1)] set x [read $f 100] close $f set x } {Two lines: this one and this one } test io-32.16 {Tcl_Read, read to end of file with -nonewline} { file delete $path(test1) set f [open $path(test1) w] puts $f "Two lines: this one" puts $f "and this one" close $f set f [open $path(test1)] set x [read -nonewline $f] close $f set x } {Two lines: this one and this one} # Test Tcl_Gets. test io-33.1 {Tcl_Gets, reading what was written} { file delete $path(test1) set f1 [open $path(test1) w] set y "first line" puts $f1 $y close $f1 set f1 [open $path(test1) r] set x [gets $f1] set z ok if {"$x" != "$y"} { set z broken } close $f1 set z } ok test io-33.2 {Tcl_Gets into variable} { set f1 [open $path(longfile) r] set c [gets $f1 x] set l [string length x] set z ok if {$l != $l} { set z broken } close $f1 set z } ok test io-33.3 {Tcl_Gets from pipe} {stdio openpipe} { file delete $path(pipe) set f1 [open $path(pipe) w] puts $f1 {puts [gets stdin]} close $f1 set f1 [open "|[list [interpreter] $path(pipe)]" r+] puts $f1 hello flush $f1 set x [gets $f1] close $f1 set z ok if {"$x" != "hello"} { set z broken } set z } ok test io-33.4 {Tcl_Gets with long line} { file delete $path(test3) set f [open $path(test3) w] puts -nonewline $f "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" puts -nonewline $f "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" puts -nonewline $f "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" puts -nonewline $f "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" puts $f "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" close $f set f [open $path(test3)] set x [gets $f] close $f set x } {abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ} test io-33.5 {Tcl_Gets with long line} { set f [open $path(test3)] set x [gets $f y] close $f list $x $y } {260 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ} test io-33.6 {Tcl_Gets and end of file} { file delete $path(test3) set f [open $path(test3) w] puts -nonewline $f "Test1\nTest2" close $f set f [open $path(test3)] set x {} set y {} lappend x [gets $f y] $y set y {} lappend x [gets $f y] $y set y {} lappend x [gets $f y] $y close $f set x } {5 Test1 5 Test2 -1 {}} test io-33.7 {Tcl_Gets and bad variable} { set f [open $path(test3) w] puts $f "Line 1" puts $f "Line 2" close $f catch {unset x} set x 24 set f [open $path(test3) r] set result [list [catch {gets $f x(0)} msg] $msg] close $f set result } {1 {can't set "x(0)": variable isn't array}} test io-33.8 {Tcl_Gets, exercising double buffering} { set f [open $path(test3) w] fconfigure $f -translation lf -eofchar {} set x "" for {set y 0} {$y < 99} {incr y} {set x "a$x"} for {set y 0} {$y < 100} {incr y} {puts $f $x} close $f set f [open $path(test3) r] fconfigure $f -translation lf for {set y 0} {$y < 100} {incr y} {gets $f} close $f set y } 100 test io-33.9 {Tcl_Gets, exercising double buffering} { set f [open $path(test3) w] fconfigure $f -translation lf -eofchar {} set x "" for {set y 0} {$y < 99} {incr y} {set x "a$x"} for {set y 0} {$y < 200} {incr y} {puts $f $x} close $f set f [open $path(test3) r] fconfigure $f -translation lf for {set y 0} {$y < 200} {incr y} {gets $f} close $f set y } 200 test io-33.10 {Tcl_Gets, exercising double buffering} { set f [open $path(test3) w] fconfigure $f -translation lf -eofchar {} set x "" for {set y 0} {$y < 99} {incr y} {set x "a$x"} for {set y 0} {$y < 300} {incr y} {puts $f $x} close $f set f [open $path(test3) r] fconfigure $f -translation lf for {set y 0} {$y < 300} {incr y} {gets $f} close $f set y } 300 # Test Tcl_Seek and Tcl_Tell. test io-34.1 {Tcl_Seek to current position at start of file} { set f1 [open $path(longfile) r] seek $f1 0 current set c [tell $f1] close $f1 set c } 0 test io-34.2 {Tcl_Seek to offset from start} { file delete $path(test1) set f1 [open $path(test1) w] fconfigure $f1 -translation lf -eofchar {} puts $f1 "abcdefghijklmnopqrstuvwxyz" puts $f1 "abcdefghijklmnopqrstuvwxyz" close $f1 set f1 [open $path(test1) r] seek $f1 10 start set c [tell $f1] close $f1 set c } 10 test io-34.3 {Tcl_Seek to end of file} { file delete $path(test1) set f1 [open $path(test1) w] fconfigure $f1 -translation lf -eofchar {} puts $f1 "abcdefghijklmnopqrstuvwxyz" puts $f1 "abcdefghijklmnopqrstuvwxyz" close $f1 set f1 [open $path(test1) r] seek $f1 0 end set c [tell $f1] close $f1 set c } 54 test io-34.4 {Tcl_Seek to offset from end of file} { file delete $path(test1) set f1 [open $path(test1) w] fconfigure $f1 -translation lf -eofchar {} puts $f1 "abcdefghijklmnopqrstuvwxyz" puts $f1 "abcdefghijklmnopqrstuvwxyz" close $f1 set f1 [open $path(test1) r] seek $f1 -10 end set c [tell $f1] close $f1 set c } 44 test io-34.5 {Tcl_Seek to offset from current position} { file delete $path(test1) set f1 [open $path(test1) w] fconfigure $f1 -translation lf -eofchar {} puts $f1 "abcdefghijklmnopqrstuvwxyz" puts $f1 "abcdefghijklmnopqrstuvwxyz" close $f1 set f1 [open $path(test1) r] seek $f1 10 current seek $f1 10 current set c [tell $f1] close $f1 set c } 20 test io-34.6 {Tcl_Seek to offset from end of file} { file delete $path(test1) set f1 [open $path(test1) w] fconfigure $f1 -translation lf -eofchar {} puts $f1 "abcdefghijklmnopqrstuvwxyz" puts $f1 "abcdefghijklmnopqrstuvwxyz" close $f1 set f1 [open $path(test1) r] seek $f1 -10 end set c [tell $f1] set r [read $f1] close $f1 list $c $r } {44 {rstuvwxyz }} test io-34.7 {Tcl_Seek to offset from end of file, then to current position} { file delete $path(test1) set f1 [open $path(test1) w] fconfigure $f1 -translation lf -eofchar {} puts $f1 "abcdefghijklmnopqrstuvwxyz" puts $f1 "abcdefghijklmnopqrstuvwxyz" close $f1 set f1 [open $path(test1) r] seek $f1 -10 end set c1 [tell $f1] set r1 [read $f1 5] seek $f1 0 current set c2 [tell $f1] close $f1 list $c1 $r1 $c2 } {44 rstuv 49} test io-34.8 {Tcl_Seek on pipes: not supported} {stdio openpipe} { set f1 [open "|[list [interpreter]]" r+] set x [list [catch {seek $f1 0 current} msg] $msg] close $f1 regsub {".*":} $x {"":} x string tolower $x } {1 {error during seek on "": invalid argument}} test io-34.9 {Tcl_Seek, testing buffered input flushing} { file delete $path(test3) set f [open $path(test3) w] fconfigure $f -eofchar {} puts -nonewline $f "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" close $f set f [open $path(test3) RDWR] set x [read $f 1] seek $f 3 lappend x [read $f 1] seek $f 0 start lappend x [read $f 1] seek $f 10 current lappend x [read $f 1] seek $f -2 end lappend x [read $f 1] seek $f 50 end lappend x [read $f 1] seek $f 1 lappend x [read $f 1] close $f set x } {a d a l Y {} b} set path(test3) [makeFile {} test3] test io-34.10 {Tcl_Seek testing flushing of buffered input} { set f [open $path(test3) w] fconfigure $f -translation lf puts $f xyz\n123 close $f set f [open $path(test3) r+] fconfigure $f -translation lf set x [gets $f] seek $f 0 current puts $f 456 close $f list $x [viewFile test3] } "xyz {xyz 456}" test io-34.11 {Tcl_Seek testing flushing of buffered output} { set f [open $path(test3) w] puts $f xyz\n123 close $f set f [open $path(test3) w+] puts $f xyzzy seek $f 2 set x [gets $f] close $f list $x [viewFile test3] } "zzy xyzzy" test io-34.12 {Tcl_Seek testing combination of write, seek back and read} { set f [open $path(test3) w] fconfigure $f -translation lf -eofchar {} puts $f xyz\n123 close $f set f [open $path(test3) a+] fconfigure $f -translation lf -eofchar {} puts $f xyzzy flush $f set x [tell $f] seek $f -4 cur set y [gets $f] close $f list $x [viewFile test3] $y } {14 {xyz 123 xyzzy} zzy} test io-34.13 {Tcl_Tell at start of file} { file delete $path(test1) set f1 [open $path(test1) w] set p [tell $f1] close $f1 set p } 0 test io-34.14 {Tcl_Tell after seek to end of file} { file delete $path(test1) set f1 [open $path(test1) w] fconfigure $f1 -translation lf -eofchar {} puts $f1 "abcdefghijklmnopqrstuvwxyz" puts $f1 "abcdefghijklmnopqrstuvwxyz" close $f1 set f1 [open $path(test1) r] seek $f1 0 end set c1 [tell $f1] close $f1 set c1 } 54 test io-34.15 {Tcl_Tell combined with seeking} { file delete $path(test1) set f1 [open $path(test1) w] fconfigure $f1 -translation lf -eofchar {} puts $f1 "abcdefghijklmnopqrstuvwxyz" puts $f1 "abcdefghijklmnopqrstuvwxyz" close $f1 set f1 [open $path(test1) r] seek $f1 10 start set c1 [tell $f1] seek $f1 10 current set c2 [tell $f1] close $f1 list $c1 $c2 } {10 20} test io-34.16 {Tcl_tell on pipe: always -1} {stdio openpipe} { set f1 [open "|[list [interpreter]]" r+] set c [tell $f1] close $f1 set c } -1 test io-34.17 {Tcl_Tell on pipe: always -1} {stdio openpipe} { set f1 [open "|[list [interpreter]]" r+] puts $f1 {puts hello} flush $f1 set c [tell $f1] gets $f1 close $f1 set c } -1 test io-34.18 {Tcl_Tell combined with seeking and reading} { file delete $path(test2) set f [open $path(test2) w] fconfigure $f -translation lf -eofchar {} puts -nonewline $f "line1\nline2\nline3\nline4\nline5\n" close $f set f [open $path(test2)] fconfigure $f -translation lf set x [tell $f] read $f 3 lappend x [tell $f] seek $f 2 lappend x [tell $f] seek $f 10 current lappend x [tell $f] seek $f 0 end lappend x [tell $f] close $f set x } {0 3 2 12 30} test io-34.19 {Tcl_Tell combined with opening in append mode} { set f [open $path(test3) w] fconfigure $f -translation lf -eofchar {} puts $f "abcdefghijklmnopqrstuvwxyz" puts $f "abcdefghijklmnopqrstuvwxyz" close $f set f [open $path(test3) a] set c [tell $f] close $f set c } 54 test io-34.20 {Tcl_Tell combined with writing} { set f [open $path(test3) w] set l "" seek $f 29 start lappend l [tell $f] puts -nonewline $f a seek $f 39 start lappend l [tell $f] puts -nonewline $f a lappend l [tell $f] seek $f 407 end lappend l [tell $f] close $f set l } {29 39 40 447} test io-34.21 {Tcl_Seek and Tcl_Tell on large files} {largefileSupport} { file delete $path(test3) set f [open $path(test3) w] fconfigure $f -encoding binary set l "" lappend l [tell $f] puts -nonewline $f abcdef lappend l [tell $f] flush $f lappend l [tell $f] # 4GB offset! seek $f 0x100000000 lappend l [tell $f] puts -nonewline $f abcdef lappend l [tell $f] close $f lappend l [file size $f] # truncate... close [open $path(test3) w] lappend l [file size $f] set l } {0 6 6 4294967296 4294967302 4294967302 0} # Test Tcl_Eof test io-35.1 {Tcl_Eof} { file delete $path(test1) set f [open $path(test1) w] puts $f hello puts $f hello close $f set f [open $path(test1)] set x [eof $f] lappend x [eof $f] gets $f lappend x [eof $f] gets $f lappend x [eof $f] gets $f lappend x [eof $f] lappend x [eof $f] close $f set x } {0 0 0 0 1 1} test io-35.2 {Tcl_Eof with pipe} {stdio openpipe} { file delete $path(pipe) set f1 [open $path(pipe) w] puts $f1 {gets stdin} puts $f1 {puts hello} close $f1 set f1 [open "|[list [interpreter] $path(pipe)]" r+] puts $f1 hello set x [eof $f1] flush $f1 lappend x [eof $f1] gets $f1 lappend x [eof $f1] gets $f1 lappend x [eof $f1] close $f1 set x } {0 0 0 1} test io-35.3 {Tcl_Eof with pipe} {stdio openpipe} { file delete $path(pipe) set f1 [open $path(pipe) w] puts $f1 {gets stdin} puts $f1 {puts hello} close $f1 set f1 [open "|[list [interpreter] $path(pipe)]" r+] puts $f1 hello set x [eof $f1] flush $f1 lappend x [eof $f1] gets $f1 lappend x [eof $f1] gets $f1 lappend x [eof $f1] gets $f1 lappend x [eof $f1] gets $f1 lappend x [eof $f1] close $f1 set x } {0 0 0 1 1 1} test io-35.4 {Tcl_Eof, eof detection on nonblocking file} {nonBlockFiles} { file delete $path(test1) set f [open $path(test1) w] close $f set f [open $path(test1) r] fconfigure $f -blocking off set l "" lappend l [gets $f] lappend l [eof $f] close $f set l } {{} 1} test io-35.5 {Tcl_Eof, eof detection on nonblocking pipe} {stdio openpipe} { file delete $path(pipe) set f [open $path(pipe) w] puts $f { exit } close $f set f [open "|[list [interpreter] $path(pipe)]" r] set l "" lappend l [gets $f] lappend l [eof $f] close $f set l } {{} 1} test io-35.6 {Tcl_Eof, eof char, lf write, auto read} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf -eofchar \x1a puts $f abc\ndef close $f set s [file size $path(test1)] set f [open $path(test1) r] fconfigure $f -translation auto -eofchar \x1a set l [string length [read $f]] set e [eof $f] close $f list $s $l $e } {9 8 1} test io-35.7 {Tcl_Eof, eof char, lf write, lf read} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf -eofchar \x1a puts $f abc\ndef close $f set s [file size $path(test1)] set f [open $path(test1) r] fconfigure $f -translation lf -eofchar \x1a set l [string length [read $f]] set e [eof $f] close $f list $s $l $e } {9 8 1} test io-35.8 {Tcl_Eof, eof char, cr write, auto read} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation cr -eofchar \x1a puts $f abc\ndef close $f set s [file size $path(test1)] set f [open $path(test1) r] fconfigure $f -translation auto -eofchar \x1a set l [string length [read $f]] set e [eof $f] close $f list $s $l $e } {9 8 1} test io-35.9 {Tcl_Eof, eof char, cr write, cr read} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation cr -eofchar \x1a puts $f abc\ndef close $f set s [file size $path(test1)] set f [open $path(test1) r] fconfigure $f -translation cr -eofchar \x1a set l [string length [read $f]] set e [eof $f] close $f list $s $l $e } {9 8 1} test io-35.10 {Tcl_Eof, eof char, crlf write, auto read} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation crlf -eofchar \x1a puts $f abc\ndef close $f set s [file size $path(test1)] set f [open $path(test1) r] fconfigure $f -translation auto -eofchar \x1a set l [string length [read $f]] set e [eof $f] close $f list $s $l $e } {11 8 1} test io-35.11 {Tcl_Eof, eof char, crlf write, crlf read} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation crlf -eofchar \x1a puts $f abc\ndef close $f set s [file size $path(test1)] set f [open $path(test1) r] fconfigure $f -translation crlf -eofchar \x1a set l [string length [read $f]] set e [eof $f] close $f list $s $l $e } {11 8 1} test io-35.12 {Tcl_Eof, eof char in middle, lf write, auto read} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf -eofchar {} set i [format abc\ndef\n%cqrs\nuvw 26] puts $f $i close $f set c [file size $path(test1)] set f [open $path(test1) r] fconfigure $f -translation auto -eofchar \x1a set l [string length [read $f]] set e [eof $f] close $f list $c $l $e } {17 8 1} test io-35.13 {Tcl_Eof, eof char in middle, lf write, lf read} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf -eofchar {} set i [format abc\ndef\n%cqrs\nuvw 26] puts $f $i close $f set c [file size $path(test1)] set f [open $path(test1) r] fconfigure $f -translation lf -eofchar \x1a set l [string length [read $f]] set e [eof $f] close $f list $c $l $e } {17 8 1} test io-35.14 {Tcl_Eof, eof char in middle, cr write, auto read} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation cr -eofchar {} set i [format abc\ndef\n%cqrs\nuvw 26] puts $f $i close $f set c [file size $path(test1)] set f [open $path(test1) r] fconfigure $f -translation auto -eofchar \x1a set l [string length [read $f]] set e [eof $f] close $f list $c $l $e } {17 8 1} test io-35.15 {Tcl_Eof, eof char in middle, cr write, cr read} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation cr -eofchar {} set i [format abc\ndef\n%cqrs\nuvw 26] puts $f $i close $f set c [file size $path(test1)] set f [open $path(test1) r] fconfigure $f -translation cr -eofchar \x1a set l [string length [read $f]] set e [eof $f] close $f list $c $l $e } {17 8 1} test io-35.16 {Tcl_Eof, eof char in middle, crlf write, auto read} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation crlf -eofchar {} set i [format abc\ndef\n%cqrs\nuvw 26] puts $f $i close $f set c [file size $path(test1)] set f [open $path(test1) r] fconfigure $f -translation auto -eofchar \x1a set l [string length [read $f]] set e [eof $f] close $f list $c $l $e } {21 8 1} test io-35.17 {Tcl_Eof, eof char in middle, crlf write, crlf read} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation crlf -eofchar {} set i [format abc\ndef\n%cqrs\nuvw 26] puts $f $i close $f set c [file size $path(test1)] set f [open $path(test1) r] fconfigure $f -translation crlf -eofchar \x1a set l [string length [read $f]] set e [eof $f] close $f list $c $l $e } {21 8 1} # Test Tcl_InputBlocked test io-36.1 {Tcl_InputBlocked on nonblocking pipe} {stdio openpipe} { set f1 [open "|[list [interpreter]]" r+] puts $f1 {puts hello_from_pipe} flush $f1 gets $f1 fconfigure $f1 -blocking off -buffering full puts $f1 {puts hello} set x "" lappend x [gets $f1] lappend x [fblocked $f1] flush $f1 after 200 lappend x [gets $f1] lappend x [fblocked $f1] lappend x [gets $f1] lappend x [fblocked $f1] close $f1 set x } {{} 1 hello 0 {} 1} test io-36.2 {Tcl_InputBlocked on blocking pipe} {stdio openpipe} { set f1 [open "|[list [interpreter]]" r+] fconfigure $f1 -buffering line puts $f1 {puts hello_from_pipe} set x "" lappend x [gets $f1] lappend x [fblocked $f1] puts $f1 {exit} lappend x [gets $f1] lappend x [fblocked $f1] lappend x [eof $f1] close $f1 set x } {hello_from_pipe 0 {} 0 1} test io-36.3 {Tcl_InputBlocked vs files, short read} { file delete $path(test1) set f [open $path(test1) w] puts $f abcdefghijklmnop close $f set f [open $path(test1) r] set l "" lappend l [fblocked $f] lappend l [read $f 3] lappend l [fblocked $f] lappend l [read -nonewline $f] lappend l [fblocked $f] lappend l [eof $f] close $f set l } {0 abc 0 defghijklmnop 0 1} test io-36.4 {Tcl_InputBlocked vs files, event driven read} {fileevent} { proc in {f} { variable l variable x lappend l [read $f 3] if {[eof $f]} {lappend l eof; close $f; set x done} } file delete $path(test1) set f [open $path(test1) w] puts $f abcdefghijklmnop close $f set f [open $path(test1) r] set l "" fileevent $f readable [namespace code [list in $f]] variable x vwait [namespace which -variable x] set l } {abc def ghi jkl mno {p } eof} test io-36.5 {Tcl_InputBlocked vs files, short read, nonblocking} {nonBlockFiles} { file delete $path(test1) set f [open $path(test1) w] puts $f abcdefghijklmnop close $f set f [open $path(test1) r] fconfigure $f -blocking off set l "" lappend l [fblocked $f] lappend l [read $f 3] lappend l [fblocked $f] lappend l [read -nonewline $f] lappend l [fblocked $f] lappend l [eof $f] close $f set l } {0 abc 0 defghijklmnop 0 1} test io-36.6 {Tcl_InputBlocked vs files, event driven read} {nonBlockFiles fileevent} { proc in {f} { variable l variable x lappend l [read $f 3] if {[eof $f]} {lappend l eof; close $f; set x done} } file delete $path(test1) set f [open $path(test1) w] puts $f abcdefghijklmnop close $f set f [open $path(test1) r] fconfigure $f -blocking off set l "" fileevent $f readable [namespace code [list in $f]] variable x vwait [namespace which -variable x] set l } {abc def ghi jkl mno {p } eof} # Test Tcl_InputBuffered test io-37.1 {Tcl_InputBuffered} {testchannel} { set f [open $path(longfile) r] fconfigure $f -buffersize 4096 read $f 3 set l "" lappend l [testchannel inputbuffered $f] lappend l [tell $f] close $f set l } {4093 3} test io-37.2 {Tcl_InputBuffered, test input flushing on seek} {testchannel} { set f [open $path(longfile) r] fconfigure $f -buffersize 4096 read $f 3 set l "" lappend l [testchannel inputbuffered $f] lappend l [tell $f] seek $f 0 current lappend l [testchannel inputbuffered $f] lappend l [tell $f] close $f set l } {4093 3 0 3} # Test Tcl_SetChannelBufferSize, Tcl_GetChannelBufferSize test io-38.1 {Tcl_GetChannelBufferSize, default buffer size} { set f [open $path(longfile) r] set s [fconfigure $f -buffersize] close $f set s } 4096 test io-38.2 {Tcl_SetChannelBufferSize, Tcl_GetChannelBufferSize} { set f [open $path(longfile) r] set l "" lappend l [fconfigure $f -buffersize] fconfigure $f -buffersize 10000 lappend l [fconfigure $f -buffersize] fconfigure $f -buffersize 1 lappend l [fconfigure $f -buffersize] fconfigure $f -buffersize -1 lappend l [fconfigure $f -buffersize] fconfigure $f -buffersize 0 lappend l [fconfigure $f -buffersize] fconfigure $f -buffersize 100000 lappend l [fconfigure $f -buffersize] fconfigure $f -buffersize 10000000 lappend l [fconfigure $f -buffersize] close $f set l } {4096 10000 1 1 1 100000 1048576} test io-38.3 {Tcl_SetChannelBufferSize, changing buffersize between reads} { # This test crashes the interp if Bug #427196 is not fixed set chan [open [info script] r] fconfigure $chan -buffersize 10 set var [read $chan 2] fconfigure $chan -buffersize 32 append var [read $chan] close $chan } {} # Test Tcl_SetChannelOption, Tcl_GetChannelOption test io-39.1 {Tcl_GetChannelOption} { file delete $path(test1) set f1 [open $path(test1) w] set x [fconfigure $f1 -blocking] close $f1 set x } 1 # # Test 17.2 was removed. # test io-39.2 {Tcl_GetChannelOption} { file delete $path(test1) set f1 [open $path(test1) w] set x [fconfigure $f1 -buffering] close $f1 set x } full test io-39.3 {Tcl_GetChannelOption} { file delete $path(test1) set f1 [open $path(test1) w] fconfigure $f1 -buffering line set x [fconfigure $f1 -buffering] close $f1 set x } line test io-39.4 {Tcl_GetChannelOption, Tcl_SetChannelOption} { file delete $path(test1) set f1 [open $path(test1) w] set l "" lappend l [fconfigure $f1 -buffering] fconfigure $f1 -buffering line lappend l [fconfigure $f1 -buffering] fconfigure $f1 -buffering none lappend l [fconfigure $f1 -buffering] fconfigure $f1 -buffering line lappend l [fconfigure $f1 -buffering] fconfigure $f1 -buffering full lappend l [fconfigure $f1 -buffering] close $f1 set l } {full line none line full} test io-39.5 {Tcl_GetChannelOption, invariance} { file delete $path(test1) set f1 [open $path(test1) w] set l "" lappend l [fconfigure $f1 -buffering] lappend l [list [catch {fconfigure $f1 -buffering green} msg] $msg] lappend l [fconfigure $f1 -buffering] close $f1 set l } {full {1 {bad value for -buffering: must be one of full, line, or none}} full} test io-39.6 {Tcl_SetChannelOption, multiple options} { file delete $path(test1) set f1 [open $path(test1) w] fconfigure $f1 -translation lf -buffering line puts $f1 hello puts $f1 bye set x [file size $path(test1)] close $f1 set x } 10 test io-39.7 {Tcl_SetChannelOption, buffering, translation} { file delete $path(test1) set f1 [open $path(test1) w] fconfigure $f1 -translation lf puts $f1 hello puts $f1 bye set x "" fconfigure $f1 -buffering line lappend x [file size $path(test1)] puts $f1 really_bye lappend x [file size $path(test1)] close $f1 set x } {0 21} test io-39.8 {Tcl_SetChannelOption, different buffering options} { file delete $path(test1) set f1 [open $path(test1) w] set l "" fconfigure $f1 -translation lf -buffering none -eofchar {} puts -nonewline $f1 hello lappend l [file size $path(test1)] puts -nonewline $f1 hello lappend l [file size $path(test1)] fconfigure $f1 -buffering full puts -nonewline $f1 hello lappend l [file size $path(test1)] fconfigure $f1 -buffering none lappend l [file size $path(test1)] puts -nonewline $f1 hello lappend l [file size $path(test1)] close $f1 lappend l [file size $path(test1)] set l } {5 10 10 10 20 20} test io-39.9 {Tcl_SetChannelOption, blocking mode} {nonBlockFiles} { file delete $path(test1) set f1 [open $path(test1) w] close $f1 set f1 [open $path(test1) r] set x "" lappend x [fconfigure $f1 -blocking] fconfigure $f1 -blocking off lappend x [fconfigure $f1 -blocking] lappend x [gets $f1] lappend x [read $f1 1000] lappend x [fblocked $f1] lappend x [eof $f1] close $f1 set x } {1 0 {} {} 0 1} test io-39.10 {Tcl_SetChannelOption, blocking mode} {stdio openpipe} { file delete $path(pipe) set f1 [open $path(pipe) w] puts $f1 { gets stdin after 100 puts hi gets stdin } close $f1 set x "" set f1 [open "|[list [interpreter] $path(pipe)]" r+] fconfigure $f1 -blocking off -buffering line lappend x [fconfigure $f1 -blocking] lappend x [gets $f1] lappend x [fblocked $f1] fconfigure $f1 -blocking on puts $f1 hello fconfigure $f1 -blocking off lappend x [gets $f1] lappend x [fblocked $f1] fconfigure $f1 -blocking on puts $f1 bye fconfigure $f1 -blocking off lappend x [gets $f1] lappend x [fblocked $f1] fconfigure $f1 -blocking on lappend x [fconfigure $f1 -blocking] lappend x [gets $f1] lappend x [fblocked $f1] lappend x [eof $f1] lappend x [gets $f1] lappend x [eof $f1] close $f1 set x } {0 {} 1 {} 1 {} 1 1 hi 0 0 {} 1} test io-39.11 {Tcl_SetChannelOption, Tcl_GetChannelOption, buffer size clipped to lower bound} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -buffersize -10 set x [fconfigure $f -buffersize] close $f set x } 1 test io-39.12 {Tcl_SetChannelOption, Tcl_GetChannelOption buffer size clipped to upper bound} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -buffersize 10000000 set x [fconfigure $f -buffersize] close $f set x } 1048576 test io-39.13 {Tcl_SetChannelOption, Tcl_GetChannelOption, buffer size} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -buffersize 40000 set x [fconfigure $f -buffersize] close $f set x } 40000 test io-39.14 {Tcl_SetChannelOption: -encoding, binary & utf-8} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -encoding {} puts -nonewline $f \xe7\x89\xa6 close $f set f [open $path(test1) r] fconfigure $f -encoding utf-8 set x [read $f] close $f set x } \u7266 test io-39.15 {Tcl_SetChannelOption: -encoding, binary & utf-8} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -encoding binary puts -nonewline $f \xe7\x89\xa6 close $f set f [open $path(test1) r] fconfigure $f -encoding utf-8 set x [read $f] close $f set x } \u7266 test io-39.16 {Tcl_SetChannelOption: -encoding, errors} { file delete $path(test1) set f [open $path(test1) w] set result [list [catch {fconfigure $f -encoding foobar} msg] $msg] close $f set result } {1 {unknown encoding "foobar"}} test io-39.17 {Tcl_SetChannelOption: -encoding, clearing CHANNEL_NEED_MORE_DATA} {stdio openpipe fileevent} { set f [open "|[list [interpreter] $path(cat)]" r+] fconfigure $f -encoding binary puts -nonewline $f "\xe7" flush $f fconfigure $f -encoding utf-8 -blocking 0 variable x {} fileevent $f readable [namespace code { lappend x [read $f] }] vwait [namespace which -variable x] after 300 [namespace code { lappend x timeout }] vwait [namespace which -variable x] fconfigure $f -encoding utf-8 vwait [namespace which -variable x] after 300 [namespace code { lappend x timeout }] vwait [namespace which -variable x] fconfigure $f -encoding binary vwait [namespace which -variable x] after 300 [namespace code { lappend x timeout }] vwait [namespace which -variable x] close $f set x } "{} timeout {} timeout \xe7 timeout" test io-39.18 {Tcl_SetChannelOption, setting read mode independently} \ {socket} { proc accept {s a p} {close $s} set s1 [socket -server [namespace code accept] 0] set port [lindex [fconfigure $s1 -sockname] 2] set s2 [socket 127.0.0.1 $port] update fconfigure $s2 -translation {auto lf} set modes [fconfigure $s2 -translation] close $s1 close $s2 set modes } {auto lf} test io-39.19 {Tcl_SetChannelOption, setting read mode independently} \ {socket} { proc accept {s a p} {close $s} set s1 [socket -server [namespace code accept] 0] set port [lindex [fconfigure $s1 -sockname] 2] set s2 [socket 127.0.0.1 $port] update fconfigure $s2 -translation {auto crlf} set modes [fconfigure $s2 -translation] close $s1 close $s2 set modes } {auto crlf} test io-39.20 {Tcl_SetChannelOption, setting read mode independently} \ {socket} { proc accept {s a p} {close $s} set s1 [socket -server [namespace code accept] 0] set port [lindex [fconfigure $s1 -sockname] 2] set s2 [socket 127.0.0.1 $port] update fconfigure $s2 -translation {auto cr} set modes [fconfigure $s2 -translation] close $s1 close $s2 set modes } {auto cr} test io-39.21 {Tcl_SetChannelOption, setting read mode independently} \ {socket} { proc accept {s a p} {close $s} set s1 [socket -server [namespace code accept] 0] set port [lindex [fconfigure $s1 -sockname] 2] set s2 [socket 127.0.0.1 $port] update fconfigure $s2 -translation {auto auto} set modes [fconfigure $s2 -translation] close $s1 close $s2 set modes } {auto crlf} test io-39.22 {Tcl_SetChannelOption, invariance} {unixOnly} { file delete $path(test1) set f1 [open $path(test1) w+] set l "" lappend l [fconfigure $f1 -eofchar] fconfigure $f1 -eofchar {ON GO} lappend l [fconfigure $f1 -eofchar] fconfigure $f1 -eofchar D lappend l [fconfigure $f1 -eofchar] close $f1 set l } {{{} {}} {O G} {D D}} test io-39.22a {Tcl_SetChannelOption, invariance} { file delete $path(test1) set f1 [open $path(test1) w+] set l [list] fconfigure $f1 -eofchar {ON GO} lappend l [fconfigure $f1 -eofchar] fconfigure $f1 -eofchar D lappend l [fconfigure $f1 -eofchar] lappend l [list [catch {fconfigure $f1 -eofchar {1 2 3}} msg] $msg] close $f1 set l } {{O G} {D D} {1 {bad value for -eofchar: should be a list of zero, one, or two elements}}} test io-39.23 {Tcl_GetChannelOption, server socket is not readable or writeable, it should still have valid -eofchar and -translation options } { set l [list] set sock [socket -server [namespace code accept] 0] lappend l [fconfigure $sock -eofchar] [fconfigure $sock -translation] close $sock set l } {{{}} auto} test io-39.24 {Tcl_SetChannelOption, server socket is not readable or writable so we can't change -eofchar or -translation } { set l [list] set sock [socket -server [namespace code accept] 0] fconfigure $sock -eofchar D -translation lf lappend l [fconfigure $sock -eofchar] [fconfigure $sock -translation] close $sock set l } {{{}} auto} test io-40.1 {POSIX open access modes: RDWR} { file delete $path(test3) set f [open $path(test3) w] puts $f xyzzy close $f set f [open $path(test3) RDWR] puts -nonewline $f "ab" seek $f 0 current set x [gets $f] close $f set f [open $path(test3) r] lappend x [gets $f] close $f set x } {zzy abzzy} test io-40.2 {POSIX open access modes: CREAT} {unixOnly} { file delete $path(test3) set f [open $path(test3) {WRONLY CREAT} 0600] file stat $path(test3) stats set x [format "0%o" [expr $stats(mode)&0777]] puts $f "line 1" close $f set f [open $path(test3) r] lappend x [gets $f] close $f set x } {0600 {line 1}} # some tests can only be run is umask is 2 # if "umask" cannot be run, the tests will be skipped. catch {testConstraint umask2 [expr {[exec umask] == 2}]} test io-40.3 {POSIX open access modes: CREAT} {unixOnly umask2} { # This test only works if your umask is 2, like ouster's. file delete $path(test3) set f [open $path(test3) {WRONLY CREAT}] close $f file stat test3 stats format "0%o" [expr $stats(mode)&0777] } 0664 test io-40.4 {POSIX open access modes: CREAT} { file delete $path(test3) set f [open $path(test3) w] fconfigure $f -eofchar {} puts $f xyzzy close $f set f [open $path(test3) {WRONLY CREAT}] fconfigure $f -eofchar {} puts -nonewline $f "ab" close $f set f [open $path(test3) r] set x [gets $f] close $f set x } abzzy test io-40.5 {POSIX open access modes: APPEND} { file delete $path(test3) set f [open $path(test3) w] fconfigure $f -translation lf -eofchar {} puts $f xyzzy close $f set f [open $path(test3) {WRONLY APPEND}] fconfigure $f -translation lf puts $f "new line" seek $f 0 puts $f "abc" close $f set f [open $path(test3) r] fconfigure $f -translation lf set x "" seek $f 6 current lappend x [gets $f] lappend x [gets $f] close $f set x } {{new line} abc} test io-40.6 {POSIX open access modes: EXCL} -match regexp -body { file delete $path(test3) set f [open $path(test3) w] puts $f xyzzy close $f open $path(test3) {WRONLY CREAT EXCL} } -returnCodes error -result {(?i)couldn't open ".*test3": file (already )?exists} test io-40.7 {POSIX open access modes: EXCL} { file delete $path(test3) set f [open $path(test3) {WRONLY CREAT EXCL}] fconfigure $f -eofchar {} puts $f "A test line" close $f viewFile test3 } {A test line} test io-40.8 {POSIX open access modes: TRUNC} { file delete $path(test3) set f [open $path(test3) w] puts $f xyzzy close $f set f [open $path(test3) {WRONLY TRUNC}] puts $f abc close $f set f [open $path(test3) r] set x [gets $f] close $f set x } abc test io-40.9 {POSIX open access modes: NONBLOCK} {nonPortable macOrUnix} { file delete $path(test3) set f [open $path(test3) {WRONLY NONBLOCK CREAT}] puts $f "NONBLOCK test" close $f set f [open $path(test3) r] set x [gets $f] close $f set x } {NONBLOCK test} test io-40.10 {POSIX open access modes: RDONLY} { set f [open $path(test1) w] puts $f "two lines: this one" puts $f "and this" close $f set f [open $path(test1) RDONLY] set x [list [gets $f] [catch {puts $f Test} msg] $msg] close $f string compare [string tolower $x] \ [list {two lines: this one} 1 \ [format "channel \"%s\" wasn't opened for writing" $f]] } 0 test io-40.11 {POSIX open access modes: RDONLY} -match regexp -body { file delete $path(test3) open $path(test3) RDONLY } -returnCodes error -result {(?i)couldn't open ".*test3": no such file or directory} test io-40.12 {POSIX open access modes: WRONLY} -match regexp -body { file delete $path(test3) open $path(test3) WRONLY } -returnCodes error -result {(?i)couldn't open ".*test3": no such file or directory} test io-40.13 {POSIX open access modes: WRONLY} { makeFile xyzzy test3 set f [open $path(test3) WRONLY] fconfigure $f -eofchar {} puts -nonewline $f "ab" seek $f 0 current set x [list [catch {gets $f} msg] $msg] close $f lappend x [viewFile test3] string compare [string tolower $x] \ [list 1 "channel \"$f\" wasn't opened for reading" abzzy] } 0 test io-40.14 {POSIX open access modes: RDWR} -match regexp -body { file delete $path(test3) open $path(test3) RDWR } -returnCodes error -result {(?i)couldn't open ".*test3": no such file or directory} test io-40.15 {POSIX open access modes: RDWR} { makeFile xyzzy test3 set f [open $path(test3) RDWR] puts -nonewline $f "ab" seek $f 0 current set x [gets $f] close $f lappend x [viewFile test3] } {zzy abzzy} if {![file exists ~/_test_] && [file writable ~]} { test io-40.16 {tilde substitution in open} -setup { makeFile {Some text} _test_ ~ } -body { file exists [file join $env(HOME) _test_] } -cleanup { removeFile _test_ ~ } -result 1 } test io-40.17 {tilde substitution in open} { set home $env(HOME) unset env(HOME) set x [list [catch {open ~/foo} msg] $msg] set env(HOME) $home set x } {1 {couldn't find HOME environment variable to expand path}} test io-41.1 {Tcl_FileeventCmd: errors} {fileevent} { list [catch {fileevent foo} msg] $msg } {1 {wrong # args: should be "fileevent channelId event ?script?"}} test io-41.2 {Tcl_FileeventCmd: errors} {fileevent} { list [catch {fileevent foo bar baz q} msg] $msg } {1 {wrong # args: should be "fileevent channelId event ?script?"}} test io-41.3 {Tcl_FileeventCmd: errors} {fileevent} { list [catch {fileevent gorp readable} msg] $msg } {1 {can not find channel named "gorp"}} test io-41.4 {Tcl_FileeventCmd: errors} {fileevent} { list [catch {fileevent gorp writable} msg] $msg } {1 {can not find channel named "gorp"}} test io-41.5 {Tcl_FileeventCmd: errors} {fileevent} { list [catch {fileevent gorp who-knows} msg] $msg } {1 {bad event name "who-knows": must be readable or writable}} # # Test fileevent on a file # set path(foo) [makeFile {} foo] set f [open $path(foo) w+] test io-42.1 {Tcl_FileeventCmd: creating, deleting, querying} {fileevent} { list [fileevent $f readable] [fileevent $f writable] } {{} {}} test io-42.2 {Tcl_FileeventCmd: replacing} {fileevent} { set result {} fileevent $f r "first script" lappend result [fileevent $f readable] fileevent $f r "new script" lappend result [fileevent $f readable] fileevent $f r "yet another" lappend result [fileevent $f readable] fileevent $f r "" lappend result [fileevent $f readable] } {{first script} {new script} {yet another} {}} test io-42.3 {Tcl_FileeventCmd: replacing, with NULL chars in script} {fileevent} { set result {} fileevent $f r "first scr\0ipt" lappend result [string length [fileevent $f readable]] fileevent $f r "new scr\0ipt" lappend result [string length [fileevent $f readable]] fileevent $f r "yet ano\0ther" lappend result [string length [fileevent $f readable]] fileevent $f r "" lappend result [fileevent $f readable] } {13 11 12 {}} test io-43.1 {Tcl_FileeventCmd: creating, deleting, querying} {stdio unixExecs fileevent} { set result {} fileevent $f readable "script 1" lappend result [fileevent $f readable] [fileevent $f writable] fileevent $f writable "write script" lappend result [fileevent $f readable] [fileevent $f writable] fileevent $f readable {} lappend result [fileevent $f readable] [fileevent $f writable] fileevent $f writable {} lappend result [fileevent $f readable] [fileevent $f writable] } {{script 1} {} {script 1} {write script} {} {write script} {} {}} test io-43.2 {Tcl_FileeventCmd: deleting when many present} -setup { set f2 [open "|[list cat -u]" r+] set f3 [open "|[list cat -u]" r+] } -constraints {stdio unixExecs fileevent openpipe} -body { set result {} lappend result [fileevent $f r] [fileevent $f2 r] [fileevent $f3 r] fileevent $f r "read f" fileevent $f2 r "read f2" fileevent $f3 r "read f3" lappend result [fileevent $f r] [fileevent $f2 r] [fileevent $f3 r] fileevent $f2 r {} lappend result [fileevent $f r] [fileevent $f2 r] [fileevent $f3 r] fileevent $f3 r {} lappend result [fileevent $f r] [fileevent $f2 r] [fileevent $f3 r] fileevent $f r {} lappend result [fileevent $f r] [fileevent $f2 r] [fileevent $f3 r] } -cleanup { catch {close $f2} catch {close $f3} } -result {{} {} {} {read f} {read f2} {read f3} {read f} {} {read f3} {read f} {} {} {} {} {}} test io-44.1 {FileEventProc procedure: normal read event} -setup { set f2 [open "|[list cat -u]" r+] set f3 [open "|[list cat -u]" r+] } -constraints {stdio unixExecs fileevent openpipe} -body { fileevent $f2 readable [namespace code { set x [gets $f2]; fileevent $f2 readable {} }] puts $f2 text; flush $f2 variable x initial vwait [namespace which -variable x] set x } -cleanup { catch {close $f2} catch {close $f3} } -result {text} test io-44.2 {FileEventProc procedure: error in read event} -setup { set f2 [open "|[list cat -u]" r+] set f3 [open "|[list cat -u]" r+] } -constraints {stdio unixExecs fileevent openpipe} -body { proc ::bgerror args "set [namespace which -variable x] \$args" fileevent $f2 readable {error bogus} puts $f2 text; flush $f2 variable x initial vwait [namespace which -variable x] rename ::bgerror {} list $x [fileevent $f2 readable] } -cleanup { catch {close $f2} catch {close $f3} } -result {bogus {}} test io-44.3 {FileEventProc procedure: normal write event} -setup { set f2 [open "|[list cat -u]" r+] set f3 [open "|[list cat -u]" r+] } -constraints {stdio unixExecs fileevent openpipe} -body { fileevent $f2 writable [namespace code { lappend x "triggered" incr count -1 if {$count <= 0} { fileevent $f2 writable {} } }] variable x initial set count 3 vwait [namespace which -variable x] vwait [namespace which -variable x] vwait [namespace which -variable x] set x } -cleanup { catch {close $f2} catch {close $f3} } -result {initial triggered triggered triggered} test io-44.4 {FileEventProc procedure: eror in write event} -setup { set f2 [open "|[list cat -u]" r+] set f3 [open "|[list cat -u]" r+] } -constraints {stdio unixExecs fileevent openpipe} -body { proc ::bgerror args "set [namespace which -variable x] \$args" fileevent $f2 writable {error bad-write} variable x initial vwait [namespace which -variable x] rename ::bgerror {} list $x [fileevent $f2 writable] } -cleanup { catch {close $f2} catch {close $f3} } -result {bad-write {}} test io-44.5 {FileEventProc procedure: end of file} {stdio unixExecs openpipe fileevent} { set f4 [open "|[list [interpreter] $path(cat) << foo]" r] fileevent $f4 readable [namespace code { if {[gets $f4 line] < 0} { lappend x eof fileevent $f4 readable {} } else { lappend x $line } }] variable x initial vwait [namespace which -variable x] vwait [namespace which -variable x] close $f4 set x } {initial foo eof} close $f makeFile "foo bar" foo test io-45.1 {DeleteFileEvent, cleanup on close} {fileevent} { set f [open $path(foo) r] fileevent $f readable [namespace code { lappend x "binding triggered: \"[gets $f]\"" fileevent $f readable {} }] close $f set x initial after 100 [namespace code { set y done }] variable y vwait [namespace which -variable y] set x } {initial} test io-45.2 {DeleteFileEvent, cleanup on close} {fileevent} { set f [open $path(foo) r] set f2 [open $path(foo) r] fileevent $f readable [namespace code { lappend x "f triggered: \"[gets $f]\"" fileevent $f readable {} }] fileevent $f2 readable [namespace code { lappend x "f2 triggered: \"[gets $f2]\"" fileevent $f2 readable {} }] close $f variable x initial vwait [namespace which -variable x] close $f2 set x } {initial {f2 triggered: "foo bar"}} test io-45.3 {DeleteFileEvent, cleanup on close} {fileevent} { set f [open $path(foo) r] set f2 [open $path(foo) r] set f3 [open $path(foo) r] fileevent $f readable {f script} fileevent $f2 readable {f2 script} fileevent $f3 readable {f3 script} set x {} close $f2 lappend x [catch {fileevent $f readable} msg] $msg \ [catch {fileevent $f2 readable}] \ [catch {fileevent $f3 readable} msg] $msg close $f3 lappend x [catch {fileevent $f readable} msg] $msg \ [catch {fileevent $f2 readable}] \ [catch {fileevent $f3 readable}] close $f lappend x [catch {fileevent $f readable}] \ [catch {fileevent $f2 readable}] \ [catch {fileevent $f3 readable}] } {0 {f script} 1 0 {f3 script} 0 {f script} 1 1 1 1 1} # Execute these tests only if the "testfevent" command is present. testConstraint testfevent [llength [info commands testfevent]] test io-46.1 {Tcl event loop vs multiple interpreters} {testfevent fileevent} { testfevent create set script "set f \[[list open $path(foo) r]]\n" append script { set x "no event" fileevent $f readable [namespace code { set x "f triggered: [gets $f]" fileevent $f readable {} }] } testfevent cmd $script after 1 ;# We must delay because Windows takes a little time to notice update testfevent cmd {close $f} list [testfevent cmd {set x}] [testfevent cmd {info commands after}] } {{f triggered: foo bar} after} test io-46.2 {Tcl event loop vs multiple interpreters} testfevent { testfevent create testfevent cmd { variable x 0 after 100 {set x triggered} vwait [namespace which -variable x] set x } } {triggered} test io-46.3 {Tcl event loop vs multiple interpreters} testfevent { testfevent create testfevent cmd { set x 0 after 10 {lappend x timer} after 30 set result $x update idletasks lappend result $x update lappend result $x } } {0 0 {0 timer}} test io-47.1 {fileevent vs multiple interpreters} {testfevent fileevent} { set f [open $path(foo) r] set f2 [open $path(foo) r] set f3 [open $path(foo) r] fileevent $f readable {script 1} testfevent create testfevent share $f2 testfevent cmd "fileevent $f2 readable {script 2}" fileevent $f3 readable {sript 3} set x {} lappend x [fileevent $f2 readable] testfevent delete lappend x [fileevent $f readable] [fileevent $f2 readable] \ [fileevent $f3 readable] close $f close $f2 close $f3 set x } {{} {script 1} {} {sript 3}} test io-47.2 {deleting fileevent on interpreter delete} {testfevent fileevent} { set f [open $path(foo) r] set f2 [open $path(foo) r] set f3 [open $path(foo) r] set f4 [open $path(foo) r] fileevent $f readable {script 1} testfevent create testfevent share $f2 testfevent share $f3 testfevent cmd "fileevent $f2 readable {script 2} fileevent $f3 readable {script 3}" fileevent $f4 readable {script 4} testfevent delete set x [list [fileevent $f readable] [fileevent $f2 readable] \ [fileevent $f3 readable] [fileevent $f4 readable]] close $f close $f2 close $f3 close $f4 set x } {{script 1} {} {} {script 4}} test io-47.3 {deleting fileevent on interpreter delete} {testfevent fileevent} { set f [open $path(foo) r] set f2 [open $path(foo) r] set f3 [open $path(foo) r] set f4 [open $path(foo) r] testfevent create testfevent share $f3 testfevent share $f4 fileevent $f readable {script 1} fileevent $f2 readable {script 2} testfevent cmd "fileevent $f3 readable {script 3} fileevent $f4 readable {script 4}" testfevent delete set x [list [fileevent $f readable] [fileevent $f2 readable] \ [fileevent $f3 readable] [fileevent $f4 readable]] close $f close $f2 close $f3 close $f4 set x } {{script 1} {script 2} {} {}} test io-47.4 {file events on shared files and multiple interpreters} {testfevent fileevent} { set f [open $path(foo) r] set f2 [open $path(foo) r] testfevent create testfevent share $f testfevent cmd "fileevent $f readable {script 1}" fileevent $f readable {script 2} fileevent $f2 readable {script 3} set x [list [fileevent $f2 readable] \ [testfevent cmd "fileevent $f readable"] \ [fileevent $f readable]] testfevent delete close $f close $f2 set x } {{script 3} {script 1} {script 2}} test io-47.5 {file events on shared files, deleting file events} {testfevent fileevent} { set f [open $path(foo) r] testfevent create testfevent share $f testfevent cmd "fileevent $f readable {script 1}" fileevent $f readable {script 2} testfevent cmd "fileevent $f readable {}" set x [list [testfevent cmd "fileevent $f readable"] \ [fileevent $f readable]] testfevent delete close $f set x } {{} {script 2}} test io-47.6 {file events on shared files, deleting file events} {testfevent fileevent} { set f [open $path(foo) r] testfevent create testfevent share $f testfevent cmd "fileevent $f readable {script 1}" fileevent $f readable {script 2} fileevent $f readable {} set x [list [testfevent cmd "fileevent $f readable"] \ [fileevent $f readable]] testfevent delete close $f set x } {{script 1} {}} set path(bar) [makeFile {} bar] test io-48.1 {testing readability conditions} {fileevent} { set f [open $path(bar) w] puts $f abcdefg puts $f abcdefg puts $f abcdefg puts $f abcdefg puts $f abcdefg close $f set f [open $path(bar) r] fileevent $f readable [namespace code [list consume $f]] proc consume {f} { variable l variable x lappend l called if {[eof $f]} { close $f set x done } else { gets $f } } set l "" variable x not_done vwait [namespace which -variable x] list $x $l } {done {called called called called called called called}} test io-48.2 {testing readability conditions} {nonBlockFiles fileevent} { set f [open $path(bar) w] puts $f abcdefg puts $f abcdefg puts $f abcdefg puts $f abcdefg puts $f abcdefg close $f set f [open $path(bar) r] fileevent $f readable [namespace code [list consume $f]] fconfigure $f -blocking off proc consume {f} { variable x variable l lappend l called if {[eof $f]} { close $f set x done } else { gets $f } } set l "" variable x not_done vwait [namespace which -variable x] list $x $l } {done {called called called called called called called}} set path(my_script) [makeFile {} my_script] test io-48.3 {testing readability conditions} {stdio unixOnly nonBlockFiles openpipe fileevent} { set f [open $path(bar) w] puts $f abcdefg puts $f abcdefg puts $f abcdefg puts $f abcdefg puts $f abcdefg close $f set f [open $path(my_script) w] puts $f { proc copy_slowly {f} { while {![eof $f]} { puts [gets $f] after 200 } close $f } } close $f set f [open "|[list [interpreter]]" r+] fileevent $f readable [namespace code [list consume $f]] fconfigure $f -buffering line fconfigure $f -blocking off proc consume {f} { variable l variable x if {[eof $f]} { set x done } else { gets $f lappend l [fblocked $f] gets $f lappend l [fblocked $f] } } set l "" variable x not_done puts $f [list source $path(my_script)] puts $f "set f \[[list open $path(bar) r]]" puts $f {copy_slowly $f} puts $f {exit} vwait [namespace which -variable x] close $f list $x $l } {done {0 1 0 1 0 1 0 1 0 1 0 1 0 0}} test io-48.4 {lf write, testing readability, ^Z termination, auto read mode} {fileevent} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf variable c [format "abc\ndef\n%c" 26] puts -nonewline $f $c close $f proc consume {f} { variable l variable c variable x if {[eof $f]} { set x done close $f } else { lappend l [gets $f] incr c } } set c 0 set l "" set f [open $path(test1) r] fconfigure $f -translation auto -eofchar \x1a fileevent $f readable [namespace code [list consume $f]] variable x vwait [namespace which -variable x] list $c $l } {3 {abc def {}}} test io-48.5 {lf write, testing readability, ^Z in middle, auto read mode} {fileevent} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf set c [format "abc\ndef\n%cfoo\nbar\n" 26] puts -nonewline $f $c close $f proc consume {f} { variable l variable x variable c if {[eof $f]} { set x done close $f } else { lappend l [gets $f] incr c } } set c 0 set l "" set f [open $path(test1) r] fconfigure $f -eofchar \x1a -translation auto fileevent $f readable [namespace code [list consume $f]] variable x vwait [namespace which -variable x] list $c $l } {3 {abc def {}}} test io-48.6 {cr write, testing readability, ^Z termination, auto read mode} {fileevent} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation cr set c [format "abc\ndef\n%c" 26] puts -nonewline $f $c close $f proc consume {f} { variable l variable x variable c if {[eof $f]} { set x done close $f } else { lappend l [gets $f] incr c } } set c 0 set l "" set f [open $path(test1) r] fconfigure $f -translation auto -eofchar \x1a fileevent $f readable [namespace code [list consume $f]] variable x vwait [namespace which -variable x] list $c $l } {3 {abc def {}}} test io-48.7 {cr write, testing readability, ^Z in middle, auto read mode} {fileevent} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation cr set c [format "abc\ndef\n%cfoo\nbar\n" 26] puts -nonewline $f $c close $f proc consume {f} { variable l variable c variable x if {[eof $f]} { set x done close $f } else { lappend l [gets $f] incr c } } set c 0 set l "" set f [open $path(test1) r] fconfigure $f -eofchar \x1a -translation auto fileevent $f readable [namespace code [list consume $f]] variable x vwait [namespace which -variable x] list $c $l } {3 {abc def {}}} test io-48.8 {crlf write, testing readability, ^Z termination, auto read mode} {fileevent} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation crlf set c [format "abc\ndef\n%c" 26] puts -nonewline $f $c close $f proc consume {f} { variable l variable x variable c if {[eof $f]} { set x done close $f } else { lappend l [gets $f] incr c } } set c 0 set l "" set f [open $path(test1) r] fconfigure $f -translation auto -eofchar \x1a fileevent $f readable [namespace code [list consume $f]] variable x vwait [namespace which -variable x] list $c $l } {3 {abc def {}}} test io-48.9 {crlf write, testing readability, ^Z in middle, auto read mode} {fileevent} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation crlf set c [format "abc\ndef\n%cfoo\nbar\n" 26] puts -nonewline $f $c close $f proc consume {f} { variable l variable c variable x if {[eof $f]} { set x done close $f } else { lappend l [gets $f] incr c } } set c 0 set l "" set f [open $path(test1) r] fconfigure $f -eofchar \x1a -translation auto fileevent $f readable [namespace code [list consume $f]] variable x vwait [namespace which -variable x] list $c $l } {3 {abc def {}}} test io-48.10 {lf write, testing readability, ^Z in middle, lf read mode} {fileevent} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf set c [format "abc\ndef\n%cfoo\nbar\n" 26] puts -nonewline $f $c close $f proc consume {f} { variable l variable c variable x if {[eof $f]} { set x done close $f } else { lappend l [gets $f] incr c } } set c 0 set l "" set f [open $path(test1) r] fconfigure $f -eofchar \x1a -translation lf fileevent $f readable [namespace code [list consume $f]] variable x vwait [namespace which -variable x] list $c $l } {3 {abc def {}}} test io-48.11 {lf write, testing readability, ^Z termination, lf read mode} {fileevent} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf set c [format "abc\ndef\n%c" 26] puts -nonewline $f $c close $f proc consume {f} { variable l variable x variable c if {[eof $f]} { set x done close $f } else { lappend l [gets $f] incr c } } set c 0 set l "" set f [open $path(test1) r] fconfigure $f -translation lf -eofchar \x1a fileevent $f readable [namespace code [list consume $f]] variable x vwait [namespace which -variable x] list $c $l } {3 {abc def {}}} test io-48.12 {cr write, testing readability, ^Z in middle, cr read mode} {fileevent} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation cr set c [format "abc\ndef\n%cfoo\nbar\n" 26] puts -nonewline $f $c close $f proc consume {f} { variable l variable x variable c if {[eof $f]} { set x done close $f } else { lappend l [gets $f] incr c } } set c 0 set l "" set f [open $path(test1) r] fconfigure $f -eofchar \x1a -translation cr fileevent $f readable [namespace code [list consume $f]] variable x vwait [namespace which -variable x] list $c $l } {3 {abc def {}}} test io-48.13 {cr write, testing readability, ^Z termination, cr read mode} {fileevent} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation cr set c [format "abc\ndef\n%c" 26] puts -nonewline $f $c close $f proc consume {f} { variable c variable x variable l if {[eof $f]} { set x done close $f } else { lappend l [gets $f] incr c } } set c 0 set l "" set f [open $path(test1) r] fconfigure $f -translation cr -eofchar \x1a fileevent $f readable [namespace code [list consume $f]] variable x vwait [namespace which -variable x] list $c $l } {3 {abc def {}}} test io-48.14 {crlf write, testing readability, ^Z in middle, crlf read mode} {fileevent} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation crlf set c [format "abc\ndef\n%cfoo\nbar\n" 26] puts -nonewline $f $c close $f proc consume {f} { variable c variable x variable l if {[eof $f]} { set x done close $f } else { lappend l [gets $f] incr c } } set c 0 set l "" set f [open $path(test1) r] fconfigure $f -eofchar \x1a -translation crlf fileevent $f readable [namespace code [list consume $f]] variable x vwait [namespace which -variable x] list $c $l } {3 {abc def {}}} test io-48.15 {crlf write, testing readability, ^Z termi, crlf read mode} {fileevent} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation crlf set c [format "abc\ndef\n%c" 26] puts -nonewline $f $c close $f proc consume {f} { variable c variable x variable l if {[eof $f]} { set x done close $f } else { lappend l [gets $f] incr c } } set c 0 set l "" set f [open $path(test1) r] fconfigure $f -translation crlf -eofchar \x1a fileevent $f readable [namespace code [list consume $f]] variable x vwait [namespace which -variable x] list $c $l } {3 {abc def {}}} test io-49.1 {testing crlf reading, leftover cr disgorgment} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "a\rb\rc\r\n" close $f set f [open $path(test1) r] set l "" lappend l [file size $path(test1)] fconfigure $f -translation crlf lappend l [read $f 1] lappend l [tell $f] lappend l [read $f 1] lappend l [tell $f] lappend l [read $f 1] lappend l [tell $f] lappend l [read $f 1] lappend l [tell $f] lappend l [read $f 1] lappend l [tell $f] lappend l [read $f 1] lappend l [tell $f] lappend l [eof $f] lappend l [read $f 1] lappend l [eof $f] close $f set l } "7 a 1 [list \r] 2 b 3 [list \r] 4 c 5 { } 7 0 {} 1" test io-49.2 {testing crlf reading, leftover cr disgorgment} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "a\rb\rc\r\n" close $f set f [open $path(test1) r] set l "" lappend l [file size $path(test1)] fconfigure $f -translation crlf lappend l [read $f 2] lappend l [tell $f] lappend l [read $f 2] lappend l [tell $f] lappend l [read $f 2] lappend l [tell $f] lappend l [eof $f] lappend l [read $f 2] lappend l [tell $f] lappend l [eof $f] close $f set l } "7 [list a\r] 2 [list b\r] 4 [list c\n] 7 0 {} 7 1" test io-49.3 {testing crlf reading, leftover cr disgorgment} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "a\rb\rc\r\n" close $f set f [open $path(test1) r] set l "" lappend l [file size $path(test1)] fconfigure $f -translation crlf lappend l [read $f 3] lappend l [tell $f] lappend l [read $f 3] lappend l [tell $f] lappend l [eof $f] lappend l [read $f 3] lappend l [tell $f] lappend l [eof $f] close $f set l } "7 [list a\rb] 3 [list \rc\n] 7 0 {} 7 1" test io-49.4 {testing crlf reading, leftover cr disgorgment} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "a\rb\rc\r\n" close $f set f [open $path(test1) r] set l "" lappend l [file size $path(test1)] fconfigure $f -translation crlf lappend l [read $f 3] lappend l [tell $f] lappend l [gets $f] lappend l [tell $f] lappend l [eof $f] lappend l [gets $f] lappend l [tell $f] lappend l [eof $f] close $f set l } "7 [list a\rb] 3 [list \rc] 7 0 {} 7 1" test io-49.5 {testing crlf reading, leftover cr disgorgment} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation lf puts -nonewline $f "a\rb\rc\r\n" close $f set f [open $path(test1) r] set l "" lappend l [file size $path(test1)] fconfigure $f -translation crlf lappend l [set x [gets $f]] lappend l [tell $f] lappend l [gets $f] lappend l [tell $f] lappend l [eof $f] close $f set l } [list 7 a\rb\rc 7 {} 7 1] testConstraint testchannelevent [llength [info commands testchannelevent]] test io-50.1 {testing handler deletion} {testchannelevent} { file delete $path(test1) set f [open $path(test1) w] close $f set f [open $path(test1) r] testchannelevent $f add readable [namespace code [list delhandler $f]] proc delhandler {f} { variable z set z called testchannelevent $f delete 0 } set z not_called update close $f set z } called test io-50.2 {testing handler deletion with multiple handlers} {testchannelevent} { file delete $path(test1) set f [open $path(test1) w] close $f set f [open $path(test1) r] testchannelevent $f add readable [namespace code [list delhandler $f 1]] testchannelevent $f add readable [namespace code [list delhandler $f 0]] proc delhandler {f i} { variable z lappend z "called delhandler $f $i" testchannelevent $f delete 0 } set z "" update close $f string compare [string tolower $z] \ [list [list called delhandler $f 0] [list called delhandler $f 1]] } 0 test io-50.3 {testing handler deletion with multiple handlers} {testchannelevent} { file delete $path(test1) set f [open $path(test1) w] close $f set f [open $path(test1) r] testchannelevent $f add readable [namespace code [list notcalled $f 1]] testchannelevent $f add readable [namespace code [list delhandler $f 0]] set z "" proc notcalled {f i} { variable z lappend z "notcalled was called!! $f $i" } proc delhandler {f i} { variable z testchannelevent $f delete 1 lappend z "delhandler $f $i called" testchannelevent $f delete 0 lappend z "delhandler $f $i deleted myself" } set z "" update close $f string compare [string tolower $z] \ [list [list delhandler $f 0 called] \ [list delhandler $f 0 deleted myself]] } 0 test io-50.4 {testing handler deletion vs reentrant calls} {testchannelevent} { file delete $path(test1) set f [open $path(test1) w] close $f set f [open $path(test1) r] testchannelevent $f add readable [namespace code [list delrecursive $f]] proc delrecursive {f} { variable z variable u if {"$u" == "recursive"} { testchannelevent $f delete 0 lappend z "delrecursive deleting recursive" } else { lappend z "delrecursive calling recursive" set u recursive update } } set u toplevel set z "" update close $f string compare [string tolower $z] \ {{delrecursive calling recursive} {delrecursive deleting recursive}} } 0 test io-50.5 {testing handler deletion vs reentrant calls} {testchannelevent} { file delete $path(test1) set f [open $path(test1) w] close $f set f [open $path(test1) r] testchannelevent $f add readable [namespace code [list notcalled $f]] testchannelevent $f add readable [namespace code [list del $f]] proc notcalled {f} { variable z lappend z "notcalled was called!! $f" } proc del {f} { variable u variable z if {"$u" == "recursive"} { testchannelevent $f delete 1 testchannelevent $f delete 0 lappend z "del deleted notcalled" lappend z "del deleted myself" } else { set u recursive lappend z "del calling recursive" update lappend z "del after update" } } set z "" set u toplevel update close $f string compare [string tolower $z] \ [list {del calling recursive} {del deleted notcalled} \ {del deleted myself} {del after update}] } 0 test io-50.6 {testing handler deletion vs reentrant calls} {testchannelevent} { file delete $path(test1) set f [open $path(test1) w] close $f set f [open $path(test1) r] testchannelevent $f add readable [namespace code [list second $f]] testchannelevent $f add readable [namespace code [list first $f]] proc first {f} { variable u variable z if {"$u" == "toplevel"} { lappend z "first called" set u first update lappend z "first after update" } else { lappend z "first called not toplevel" } } proc second {f} { variable u variable z if {"$u" == "first"} { lappend z "second called, first time" set u second testchannelevent $f delete 0 } elseif {"$u" == "second"} { lappend z "second called, second time" testchannelevent $f delete 0 } else { lappend z "second called, cannot happen!" testchannelevent $f removeall } } set z "" set u toplevel update close $f string compare [string tolower $z] \ [list {first called} {first called not toplevel} \ {second called, first time} {second called, second time} \ {first after update}] } 0 test io-51.1 {Test old socket deletion on Macintosh} {socket} { set x 0 set result "" proc accept {s a p} { variable x variable wait fconfigure $s -blocking off puts $s "sock[incr x]" close $s set wait done } set ss [socket -server [namespace code accept] 0] variable wait "" set cs [socket [info hostname] [lindex [fconfigure $ss -sockname] 2]] vwait [namespace which -variable wait] lappend result [gets $cs] close $cs set wait "" set cs [socket [info hostname] [lindex [fconfigure $ss -sockname] 2]] vwait [namespace which -variable wait] lappend result [gets $cs] close $cs set wait "" set cs [socket [info hostname] [lindex [fconfigure $ss -sockname] 2]] vwait [namespace which -variable wait] lappend result [gets $cs] close $cs set wait "" set cs [socket [info hostname] [lindex [fconfigure $ss -sockname] 2]] vwait [namespace which -variable wait] lappend result [gets $cs] close $cs close $ss set result } {sock1 sock2 sock3 sock4} test io-52.1 {TclCopyChannel} {fcopy} { file delete $path(test1) set f1 [open $thisScript] set f2 [open $path(test1) w] fcopy $f1 $f2 -command { # } catch { fcopy $f1 $f2 } msg close $f1 close $f2 string compare $msg "channel \"$f1\" is busy" } {0} test io-52.2 {TclCopyChannel} {fcopy} { file delete $path(test1) set f1 [open $thisScript] set f2 [open $path(test1) w] set f3 [open $thisScript] fcopy $f1 $f2 -command { # } catch { fcopy $f3 $f2 } msg close $f1 close $f2 close $f3 string compare $msg "channel \"$f2\" is busy" } {0} test io-52.3 {TclCopyChannel} {fcopy} { file delete $path(test1) set f1 [open $thisScript] set f2 [open $path(test1) w] fconfigure $f1 -translation lf -blocking 0 fconfigure $f2 -translation cr -blocking 0 set s0 [fcopy $f1 $f2] set result [list [fconfigure $f1 -blocking] [fconfigure $f2 -blocking]] close $f1 close $f2 set s1 [file size $thisScript] set s2 [file size $path(test1)] if {("$s1" == "$s2") && ($s0 == $s1)} { lappend result ok } set result } {0 0 ok} test io-52.4 {TclCopyChannel} {fcopy} { file delete $path(test1) set f1 [open $thisScript] set f2 [open $path(test1) w] fconfigure $f1 -translation lf -blocking 0 fconfigure $f2 -translation cr -blocking 0 fcopy $f1 $f2 -size 40 set result [list [fconfigure $f1 -blocking] [fconfigure $f2 -blocking]] close $f1 close $f2 lappend result [file size $path(test1)] } {0 0 40} test io-52.5 {TclCopyChannel, all} {fcopy} { file delete $path(test1) set f1 [open $thisScript] set f2 [open $path(test1) w] fconfigure $f1 -translation lf -blocking 0 fconfigure $f2 -translation lf -blocking 0 fcopy $f1 $f2 -size -1 ;# -1 means 'copy all', same as if no -size specified. set result [list [fconfigure $f1 -blocking] [fconfigure $f2 -blocking]] close $f1 close $f2 set s1 [file size $thisScript] set s2 [file size $path(test1)] if {"$s1" == "$s2"} { lappend result ok } set result } {0 0 ok} test io-52.5a {TclCopyChannel, all, other negative value} {fcopy} { file delete $path(test1) set f1 [open $thisScript] set f2 [open $path(test1) w] fconfigure $f1 -translation lf -blocking 0 fconfigure $f2 -translation lf -blocking 0 fcopy $f1 $f2 -size -2 ;# < 0 behaves like -1, copy all set result [list [fconfigure $f1 -blocking] [fconfigure $f2 -blocking]] close $f1 close $f2 set s1 [file size $thisScript] set s2 [file size $path(test1)] if {"$s1" == "$s2"} { lappend result ok } set result } {0 0 ok} test io-52.5b {TclCopyChannel, all, wrap to negative value} {fcopy} { file delete $path(test1) set f1 [open $thisScript] set f2 [open $path(test1) w] fconfigure $f1 -translation lf -blocking 0 fconfigure $f2 -translation lf -blocking 0 fcopy $f1 $f2 -size 3221176172 ;# Wrapped to < 0, behaves like -1, copy all set result [list [fconfigure $f1 -blocking] [fconfigure $f2 -blocking]] close $f1 close $f2 set s1 [file size $thisScript] set s2 [file size $path(test1)] if {"$s1" == "$s2"} { lappend result ok } set result } {0 0 ok} test io-52.6 {TclCopyChannel} {fcopy} { file delete $path(test1) set f1 [open $thisScript] set f2 [open $path(test1) w] fconfigure $f1 -translation lf -blocking 0 fconfigure $f2 -translation lf -blocking 0 set s0 [fcopy $f1 $f2 -size [expr [file size $thisScript] + 5]] set result [list [fconfigure $f1 -blocking] [fconfigure $f2 -blocking]] close $f1 close $f2 set s1 [file size $thisScript] set s2 [file size $path(test1)] if {("$s1" == "$s2") && ($s0 == $s1)} { lappend result ok } set result } {0 0 ok} test io-52.7 {TclCopyChannel} {fcopy} { file delete $path(test1) set f1 [open $thisScript] set f2 [open $path(test1) w] fconfigure $f1 -translation lf -blocking 0 fconfigure $f2 -translation lf -blocking 0 fcopy $f1 $f2 set result [list [fconfigure $f1 -blocking] [fconfigure $f2 -blocking]] set s1 [file size $thisScript] set s2 [file size $path(test1)] close $f1 close $f2 if {"$s1" == "$s2"} { lappend result ok } set result } {0 0 ok} test io-52.8 {TclCopyChannel} {stdio openpipe fcopy} { file delete $path(test1) file delete $path(pipe) set f1 [open $path(pipe) w] fconfigure $f1 -translation lf puts $f1 " puts ready gets stdin set f1 \[open [list $thisScript] r\] fconfigure \$f1 -translation lf puts \[read \$f1 100\] close \$f1 " close $f1 set f1 [open "|[list [interpreter] $path(pipe)]" r+] fconfigure $f1 -translation lf gets $f1 puts $f1 ready flush $f1 set f2 [open $path(test1) w] fconfigure $f2 -translation lf set s0 [fcopy $f1 $f2 -size 40] catch {close $f1} close $f2 list $s0 [file size $path(test1)] } {40 40} # Empty files, to register them with the test facility set path(kyrillic.txt) [makeFile {} kyrillic.txt] set path(utf8-fcopy.txt) [makeFile {} utf8-fcopy.txt] set path(utf8-rp.txt) [makeFile {} utf8-rp.txt] # Create kyrillic file, use lf translation to avoid os eol issues set out [open $path(kyrillic.txt) w] fconfigure $out -encoding koi8-r -translation lf puts $out "\u0410\u0410" close $out test io-52.9 {TclCopyChannel & encodings} {fcopy} { # Copy kyrillic to UTF-8, using fcopy. set in [open $path(kyrillic.txt) r] set out [open $path(utf8-fcopy.txt) w] fconfigure $in -encoding koi8-r -translation lf fconfigure $out -encoding utf-8 -translation lf fcopy $in $out close $in close $out # Do the same again, but differently (read/puts). set in [open $path(kyrillic.txt) r] set out [open $path(utf8-rp.txt) w] fconfigure $in -encoding koi8-r -translation lf fconfigure $out -encoding utf-8 -translation lf puts -nonewline $out [read $in] close $in close $out list [file size $path(kyrillic.txt)] \ [file size $path(utf8-fcopy.txt)] \ [file size $path(utf8-rp.txt)] } {3 5 5} test io-52.10 {TclCopyChannel & encodings} {fcopy} { # encoding to binary (=> implies that the # internal utf-8 is written) set in [open $path(kyrillic.txt) r] set out [open $path(utf8-fcopy.txt) w] fconfigure $in -encoding koi8-r -translation lf # -translation binary is also -encoding binary fconfigure $out -translation binary fcopy $in $out close $in close $out file size $path(utf8-fcopy.txt) } 5 test io-52.11 {TclCopyChannel & encodings} {fcopy} { # binary to encoding => the input has to be # in utf-8 to make sense to the encoder set in [open $path(utf8-fcopy.txt) r] set out [open $path(kyrillic.txt) w] # -translation binary is also -encoding binary fconfigure $in -translation binary fconfigure $out -encoding koi8-r -translation lf fcopy $in $out close $in close $out file size $path(kyrillic.txt) } 3 test io-53.1 {CopyData} {fcopy} { file delete $path(test1) set f1 [open $thisScript] set f2 [open $path(test1) w] fconfigure $f1 -translation lf -blocking 0 fconfigure $f2 -translation cr -blocking 0 fcopy $f1 $f2 -size 0 set result [list [fconfigure $f1 -blocking] [fconfigure $f2 -blocking]] close $f1 close $f2 lappend result [file size $path(test1)] } {0 0 0} test io-53.2 {CopyData} {fcopy} { file delete $path(test1) set f1 [open $thisScript] set f2 [open $path(test1) w] fconfigure $f1 -translation lf -blocking 0 fconfigure $f2 -translation cr -blocking 0 fcopy $f1 $f2 -command [namespace code {set s0}] set result [list [fconfigure $f1 -blocking] [fconfigure $f2 -blocking]] variable s0 vwait [namespace which -variable s0] close $f1 close $f2 set s1 [file size $thisScript] set s2 [file size $path(test1)] if {("$s1" == "$s2") && ($s0 == $s1)} { lappend result ok } set result } {0 0 ok} test io-53.3 {CopyData: background read underflow} {stdio unixOnly openpipe fcopy} { file delete $path(test1) file delete $path(pipe) set f1 [open $path(pipe) w] puts -nonewline $f1 { puts ready flush stdout ;# Don't assume line buffered! fcopy stdin stdout -command { set x } vwait x set f [} puts $f1 [list open $path(test1) w]] puts $f1 { fconfigure $f -translation lf puts $f "done" close $f } close $f1 set f1 [open "|[list [interpreter] $path(pipe)]" r+] set result [gets $f1] puts $f1 line1 flush $f1 lappend result [gets $f1] puts $f1 line2 flush $f1 lappend result [gets $f1] close $f1 after 500 set f [open $path(test1)] lappend result [read $f] close $f set result } "ready line1 line2 {done\n}" test io-53.4 {CopyData: background write overflow} {stdio unixOnly openpipe fileevent fcopy} { set big bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n variable x for {set x 0} {$x < 12} {incr x} { append big $big } file delete $path(test1) file delete $path(pipe) set f1 [open $path(pipe) w] puts $f1 { puts ready fcopy stdin stdout -command { set x } vwait x set f [open $path(test1) w] fconfigure $f -translation lf puts $f "done" close $f } close $f1 set f1 [open "|[list [interpreter] $path(pipe)]" r+] set result [gets $f1] fconfigure $f1 -blocking 0 puts $f1 $big flush $f1 after 500 set result "" fileevent $f1 read [namespace code { append result [read $f1 1024] if {[string length $result] >= [string length $big]} { set x done } }] vwait [namespace which -variable x] close $f1 set big {} set x } done set result {} proc FcopyTestAccept {sock args} { after 1000 "close $sock" } proc FcopyTestDone {bytes {error {}}} { variable fcopyTestDone if {[string length $error]} { set fcopyTestDone 1 } else { set fcopyTestDone 0 } } test io-53.5 {CopyData: error during fcopy} {socket fcopy} { variable fcopyTestDone set listen [socket -server [namespace code FcopyTestAccept] 0] set in [open $thisScript] ;# 126 K set out [socket 127.0.0.1 [lindex [fconfigure $listen -sockname] 2]] catch {unset fcopyTestDone} close $listen ;# This means the socket open never really succeeds fcopy $in $out -command [namespace code FcopyTestDone] variable fcopyTestDone if ![info exists fcopyTestDone] { vwait [namespace which -variable fcopyTestDone] ;# The error occurs here in the b.g. } close $in close $out set fcopyTestDone ;# 1 for error condition } 1 test io-53.6 {CopyData: error during fcopy} {stdio openpipe fcopy} { variable fcopyTestDone file delete $path(pipe) file delete $path(test1) catch {unset fcopyTestDone} set f1 [open $path(pipe) w] puts $f1 "exit 1" close $f1 set in [open "|[list [interpreter] $path(pipe)]" r+] set out [open $path(test1) w] fcopy $in $out -command [namespace code FcopyTestDone] variable fcopyTestDone if ![info exists fcopyTestDone] { vwait [namespace which -variable fcopyTestDone] } catch {close $in} close $out set fcopyTestDone ;# 0 for plain end of file } {0} proc doFcopy {in out {bytes 0} {error {}}} { variable fcopyTestDone variable fcopyTestCount incr fcopyTestCount $bytes if {[string length $error]} { set fcopyTestDone 1 } elseif {[eof $in]} { set fcopyTestDone 0 } else { # Delay next fcopy to wait for size>0 input bytes after 100 [list fcopy $in $out -size 1000 \ -command [namespace code [list doFcopy $in $out]] ] } } test io-53.7 {CopyData: Flooding fcopy from pipe} {stdio openpipe fcopy} { variable fcopyTestDone file delete $path(pipe) catch {unset fcopyTestDone} set fcopyTestCount 0 set f1 [open $path(pipe) w] puts $f1 { # Write 10 bytes / 10 msec proc Write {count} { puts -nonewline "1234567890" if {[incr count -1]} { after 10 [list Write $count] } else { set ::ready 1 } } fconfigure stdout -buffering none Write 345 ;# 3450 bytes ~3.45 sec vwait ready exit 0 } close $f1 set in [open "|[list [interpreter] $path(pipe) &]" r+] set out [open $path(test1) w] doFcopy $in $out variable fcopyTestDone if ![info exists fcopyTestDone] { vwait [namespace which -variable fcopyTestDone] } catch {close $in} close $out # -1=error 0=script error N=number of bytes expr ($fcopyTestDone == 0) ? $fcopyTestCount : -1 } {3450} test io-53.8 {CopyData: async callback and error handling, Bug 1932639} -setup { # copy progress callback. errors out intentionally proc ::cmd args { lappend ::RES "CMD $args" error !STOP } # capture callback error here proc ::bgerror args { lappend ::RES "bgerror/OK $args" set ::forever has-been-reached return } # Files we use for our channels set foo [makeFile ashgdfashdgfasdhgfasdhgf foo] set bar [makeFile {} bar] # Channels to copy between set f [open $foo r] ; fconfigure $f -translation binary set g [open $bar w] ; fconfigure $g -translation binary -buffering none } -constraints {stdio openpipe fcopy} -body { # Record input size, so that result is always defined lappend ::RES [file size $bar] # Run the copy. Should not invoke -command now. fcopy $f $g -size 2 -command ::cmd # Check that -command was not called synchronously set sbs [file size $bar] lappend ::RES [expr {($sbs > 0) ? "sync/FAIL" : "sync/OK"}] $sbs # Now let the async part happen. Should capture the error in cmd # via bgerror. If not break the event loop via timer. set token [after 1000 { lappend ::RES {bgerror/FAIL timeout} set ::forever has-been-reached }] vwait ::forever catch {after cancel $token} # Report set ::RES } -cleanup { close $f close $g catch {unset ::RES} catch {unset ::forever} rename ::cmd {} rename ::bgerror {} removeFile foo removeFile bar } -result {0 sync/OK 0 {CMD 2} {bgerror/OK !STOP}} test io-53.8a {CopyData: async callback and error handling, Bug 1932639, at eof} -setup { # copy progress callback. errors out intentionally proc ::cmd args { lappend ::RES "CMD $args" set ::forever has-been-reached return } # Files we use for our channels set foo [makeFile ashgdfashdgfasdhgfasdhgf foo] set bar [makeFile {} bar] # Channels to copy between set f [open $foo r] ; fconfigure $f -translation binary set g [open $bar w] ; fconfigure $g -translation binary -buffering none } -constraints {stdio openpipe fcopy} -body { # Initialize and force eof on the input. seek $f 0 end ; read $f 1 set ::RES [eof $f] # Run the copy. Should not invoke -command now. fcopy $f $g -size 2 -command ::cmd # Check that -command was not called synchronously lappend ::RES [expr {([llength $::RES] > 1) ? "sync/FAIL" : "sync/OK"}] # Now let the async part happen. Should capture the eof in cmd # If not break the event loop via timer. set token [after 1000 { lappend ::RES {cmd/FAIL timeout} set ::forever has-been-reached }] vwait ::forever catch {after cancel $token} # Report set ::RES } -cleanup { close $f close $g catch {unset ::RES} catch {unset ::forever} rename ::cmd {} removeFile foo removeFile bar } -result {1 sync/OK {CMD 0}} test io-53.9 {CopyData: -size and event interaction, Bug 780533} -setup { set out [makeFile {} out] set err [makeFile {} err] set pipe [open "|[list [info nameofexecutable] 2> $err]" r+] fconfigure $pipe -translation binary -buffering line puts $pipe { fconfigure stdout -translation binary -buffering line puts stderr Waiting... after 1000 foreach x {a b c} { puts stderr Looping... puts $x after 500 } proc bye args { if {[gets stdin line]<0} { puts stderr "CHILD: EOF detected, exiting" exit } else { puts stderr "CHILD: ignoring line: $line" } } puts stderr Now-sleeping-forever fileevent stdin readable bye vwait forever } proc ::done args { set ::forever OK return } set ::forever {} set out [open $out w] } -constraints {stdio openpipe fcopy} -body { fcopy $pipe $out -size 6 -command ::done set token [after 5000 { set ::forever {fcopy hangs} }] vwait ::forever catch {after cancel $token} set ::forever } -cleanup { close $pipe rename ::done {} after 1000 ;# Give Windows time to kill the process catch {close $out} removeFile out removeFile err catch {unset ::forever} } -result OK test io-53.10 {Bug 1350564, multi-directional fcopy} -setup { set err [makeFile {} err] set pipe [open "|[list [info nameofexecutable] 2> $err]" r+] fconfigure $pipe -translation binary -buffering line puts $pipe { fconfigure stderr -buffering line # Kill server when pipe closed by invoker. proc bye args { if {![eof stdin]} { gets stdin ; return } puts stderr BYE exit } # Server code. Bi-directional copy between 2 sockets. proc geof {sok} { puts stderr DONE/$sok close $sok } proc new {sok args} { puts stderr NEW/$sok global l srv fconfigure $sok -translation binary -buffering none lappend l $sok if {[llength $l]==2} { close $srv foreach {a b} $l break fcopy $a $b -command [list geof $a] fcopy $b $a -command [list geof $b] puts stderr 2COPY } puts stderr ... } puts stderr SRV set l {} set srv [socket -server new 9999] puts stderr WAITING fileevent stdin readable bye puts OK vwait forever } # wait for OK from server. gets $pipe # Now the two clients. proc ::done {sock} { if {[eof $sock]} { close $sock ; return } lappend ::forever [gets $sock] return } set a [socket 127.0.0.1 9999] set b [socket 127.0.0.1 9999] fconfigure $a -translation binary -buffering none fconfigure $b -translation binary -buffering none fileevent $a readable [list ::done $a] fileevent $b readable [list ::done $b] } -constraints {stdio openpipe fcopy} -body { # Now pass data through the server in both directions. set ::forever {} puts $a AB vwait ::forever puts $b BA vwait ::forever set ::forever } -cleanup { catch {close $a} catch {close $b} close $pipe rename ::done {} after 1000 ;# Give Windows time to kill the process removeFile err catch {unset ::forever} } -result {AB BA} test io-53.11 {Bug 2895565} -setup { set in [makeFile {} in] set f [open $in w] fconfigure $f -encoding utf-8 -translation binary puts -nonewline $f [string repeat "Ho hum\n" 11] close $f set inChan [open $in r] fconfigure $inChan -translation binary set out [makeFile {} out] set outChan [open $out w] fconfigure $outChan -encoding cp1252 -translation crlf proc CopyDone {bytes args} { variable done if {[llength $args]} { set done "Error: '[lindex $args 0]' after $bytes bytes copied" } else { set done "$bytes bytes copied" } } } -body { variable done after 2000 [list set [namespace which -variable done] timeout] fcopy $inChan $outChan -size 40 -command [namespace which CopyDone] vwait [namespace which -variable done] set done } -cleanup { close $outChan close $inChan removeFile out removeFile in } -result {40 bytes copied} test io-54.1 {Recursive channel events} {socket fileevent} { # This test checks to see if file events are delivered during recursive # event loops when there is buffered data on the channel. proc accept {s a p} { variable as fconfigure $s -translation lf puts $s "line 1\nline2\nline3" flush $s set as $s } proc readit {s next} { variable x variable result lappend result $next if {$next == 1} { fileevent $s readable [namespace code [list readit $s 2]] vwait [namespace which -variable x] } incr x } set ss [socket -server [namespace code accept] 0] # We need to delay on some systems until the creation of the # server socket completes. set done 0 for {set i 0} {$i < 10} {incr i} { if {![catch {set cs [socket [info hostname] [lindex [fconfigure $ss -sockname] 2]]}]} { set done 1 break } after 100 } if {$done == 0} { close $ss error "failed to connect to server" } variable result {} variable x 0 variable as vwait [namespace which -variable as] fconfigure $cs -translation lf lappend result [gets $cs] fconfigure $cs -blocking off fileevent $cs readable [namespace code [list readit $cs 1]] set a [after 2000 [namespace code { set x failure }]] vwait [namespace which -variable x] after cancel $a close $as close $ss close $cs list $result $x } {{{line 1} 1 2} 2} test io-54.2 {Testing for busy-wait in recursive channel events} {socket fileevent} { set accept {} set after {} variable s [socket -server [namespace code accept] 0] proc accept {s a p} { variable counter variable accept set accept $s set counter 0 fconfigure $s -blocking off -buffering line -translation lf fileevent $s readable [namespace code "doit $s"] } proc doit {s} { variable counter variable after incr counter set l [gets $s] if {"$l" == ""} { fileevent $s readable [namespace code "doit1 $s"] set after [after 1000 [namespace code newline]] } } proc doit1 {s} { variable counter variable accept incr counter set l [gets $s] close $s set accept {} } proc producer {} { variable s variable writer set writer [socket 127.0.0.1 [lindex [fconfigure $s -sockname] 2]] fconfigure $writer -buffering line puts -nonewline $writer hello flush $writer } proc newline {} { variable done variable writer puts $writer hello flush $writer set done 1 } producer variable done vwait [namespace which -variable done] close $writer close $s after cancel $after if {$accept != {}} {close $accept} set counter } 1 set path(fooBar) [makeFile {} fooBar] test io-55.1 {ChannelEventScriptInvoker: deletion} {fileevent} { variable x proc eventScript {fd} { variable x close $fd error "planned error" set x whoops } proc ::bgerror {args} "set [namespace which -variable x] got_error" set f [open $path(fooBar) w] fileevent $f writable [namespace code [list eventScript $f]] variable x not_done vwait [namespace which -variable x] set x } {got_error} test io-56.1 {ChannelTimerProc} {testchannelevent} { set f [open $path(fooBar) w] puts $f "this is a test" close $f set f [open $path(fooBar) r] testchannelevent $f add readable [namespace code { read $f 1 incr x }] variable x 0 vwait [namespace which -variable x] vwait [namespace which -variable x] set result $x testchannelevent $f set 0 none after idle [namespace code {set y done}] variable y vwait [namespace which -variable y] close $f lappend result $y } {2 done} test io-57.1 {buffered data and file events, gets} {fileevent} { proc accept {sock args} { variable s2 set s2 $sock } set server [socket -server [namespace code accept] 0] set s [socket 127.0.0.1 [lindex [fconfigure $server -sockname] 2]] variable s2 vwait [namespace which -variable s2] update fileevent $s2 readable [namespace code {lappend result readable}] puts $s "12\n34567890" flush $s variable result [gets $s2] after 1000 [namespace code {lappend result timer}] vwait [namespace which -variable result] lappend result [gets $s2] vwait [namespace which -variable result] close $s close $s2 close $server set result } {12 readable 34567890 timer} test io-57.2 {buffered data and file events, read} {fileevent} { proc accept {sock args} { variable s2 set s2 $sock } set server [socket -server [namespace code accept] 0] set s [socket 127.0.0.1 [lindex [fconfigure $server -sockname] 2]] variable s2 vwait [namespace which -variable s2] update fileevent $s2 readable [namespace code {lappend result readable}] puts -nonewline $s "1234567890" flush $s variable result [read $s2 1] after 1000 [namespace code {lappend result timer}] vwait [namespace which -variable result] lappend result [read $s2 9] vwait [namespace which -variable result] close $s close $s2 close $server set result } {1 readable 234567890 timer} test io-58.1 {Tcl_NotifyChannel and error when closing} {stdio unixOrPc openpipe fileevent} { set out [open $path(script) w] puts $out { puts "normal message from pipe" puts stderr "error message from pipe" exit 1 } proc readit {pipe} { variable x variable result if {[eof $pipe]} { set x [catch {close $pipe} line] lappend result catch $line } else { gets $pipe line lappend result gets $line } } close $out set pipe [open "|[list [interpreter] $path(script)]" r] fileevent $pipe readable [namespace code [list readit $pipe]] variable x "" set result "" vwait [namespace which -variable x] list $x $result } {1 {gets {normal message from pipe} gets {} catch {error message from pipe}}} testConstraint testmainthread [llength [info commands testmainthread]] test io-59.1 {Thread reference of channels} {testmainthread testchannel} { # TIP #10 # More complicated tests (like that the reference changes as a # channel is moved from thread to thread) can be done only in the # extension which fully implements the moving of channels between # threads, i.e. 'Threads'. Or we have to extend [testthread] as well. set f [open $path(longfile) r] set result [testchannel mthread $f] close $f string equal $result [testmainthread] } {1} test io-60.1 {writing illegal utf sequences} {openpipe fileevent} { # This test will hang in older revisions of the core. set out [open $path(script) w] puts $out { puts [encoding convertfrom identity \xe2] exit 1 } proc readit {pipe} { variable x variable result if {[eof $pipe]} { set x [catch {close $pipe} line] lappend result catch $line } else { gets $pipe line lappend result gets $line } } close $out set pipe [open "|[list [interpreter] $path(script)]" r] fileevent $pipe readable [namespace code [list readit $pipe]] variable x "" set result "" vwait [namespace which -variable x] # cut of the remainder of the error stack, especially the filename set result [lreplace $result 3 3 [lindex [split [lindex $result 3] \n] 0]] list $x $result } {1 {gets {} catch {error writing "stdout": invalid argument}}} test io-61.1 {Reset eof state after changing the eof char} -setup { set datafile [makeFile {} eofchar] set f [open $datafile w] fconfigure $f -translation binary puts -nonewline $f [string repeat "Ho hum\n" 11] puts $f = set line [string repeat "Ge gla " 4] puts -nonewline $f [string repeat [string trimright $line]\n 834] close $f } -body { set f [open $datafile r] fconfigure $f -eofchar = set res {} lappend res [read $f; tell $f] fconfigure $f -eofchar {} lappend res [read $f 1] lappend res [read $f; tell $f] # Any seek zaps the internals into a good state. #seek $f 0 start #seek $f 0 current #lappend res [read $f; tell $f] close $f set res } -cleanup { removeFile eofchar } -result {77 = 23431} # cleanup foreach file [list fooBar longfile script output test1 pipe my_script \ test2 test3 cat stdout kyrillic.txt utf8-fcopy.txt utf8-rp.txt] { removeFile $file } cleanupTests } namespace delete ::tcl::test::io return tcl8.4.20/tests/lrange.test0000644003604700454610000000554511737050674014243 0ustar dgp771div# Commands covered: lrange # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } test lrange-1.1 {range of list elements} { lrange {a b c d} 1 2 } {b c} test lrange-1.2 {range of list elements} { lrange {a {bcd e {f g {}}} l14 l15 d} 1 1 } {{bcd e {f g {}}}} test lrange-1.3 {range of list elements} { lrange {a {bcd e {f g {}}} l14 l15 d} 3 end } {l15 d} test lrange-1.4 {range of list elements} { lrange {a {bcd e {f g {}}} l14 l15 d} 4 10000 } {d} test lrange-1.5 {range of list elements} { lrange {a {bcd e {f g {}}} l14 l15 d} 4 3 } {} test lrange-1.6 {range of list elements} { lrange {a {bcd e {f g {}}} l14 l15 d} 10 11 } {} test lrange-1.7 {range of list elements} { lrange {a b c d e} -1 2 } {a b c} test lrange-1.8 {range of list elements} { lrange {a b c d e} -2 -1 } {} test lrange-1.9 {range of list elements} { lrange {a b c d e} -2 e } {a b c d e} test lrange-1.10 {range of list elements} { lrange "a b\{c d" 1 2 } "b\\{c d" test lrange-1.11 {range of list elements} { lrange "a b c d" end end } d test lrange-1.12 {range of list elements} { lrange "a b c d" end 100000 } d test lrange-1.13 {range of list elements} { lrange "a b c d" e 3 } d test lrange-1.14 {range of list elements} { lrange "a b c d" end 2 } {} test lrange-1.15 {range of list elements} { concat \"[lrange {a b \{\ } 0 2]" } {"a b \{\ "} test lrange-1.16 {list element quoting} { lrange {[append a .b]} 0 end } {{[append} a .b\]} test lrange-2.1 {error conditions} { list [catch {lrange a b} msg] $msg } {1 {wrong # args: should be "lrange list first last"}} test lrange-2.2 {error conditions} { list [catch {lrange a b 6 7} msg] $msg } {1 {wrong # args: should be "lrange list first last"}} test lrange-2.3 {error conditions} { list [catch {lrange a b 6} msg] $msg } {1 {bad index "b": must be integer or end?-integer?}} test lrange-2.4 {error conditions} { list [catch {lrange a 0 enigma} msg] $msg } {1 {bad index "enigma": must be integer or end?-integer?}} test lrange-2.5 {error conditions} { list [catch {lrange "a \{b c" 3 4} msg] $msg } {1 {unmatched open brace in list}} test lrange-2.6 {error conditions} { list [catch {lrange "a b c \{ d e" 1 4} msg] $msg } {1 {unmatched open brace in list}} # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/lsetComp.test0000755003604700454610000004011011737050674014547 0ustar dgp771div# This file is a -*- tcl -*- test script # Commands covered: lset # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 2001 by Kevin B. Kenny. All rights reserved. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } # Procedure to evaluate a script within a proc, to test compilation # functionality proc evalInProc { script } { proc testProc {} $script set status [catch { testProc } result] rename testProc {} return [list $status $result] } # Tests for the bytecode compilation of the 'lset' command test lsetComp-1.1 {lset, compiled, wrong \# args} { evalInProc { lset } } "1 {wrong \# args: should be \"lset listVar index ?index...? value\"}" test lsetComp-2.1 {lset, compiled, list of args, not a simple var name} { evalInProc { set y x set x {{1 2} {3 4}} lset $y {1 1} 5 } } "0 {{1 2} {3 5}}" test lsetComp-2.2 {lset, compiled, list of args, scalar on stack} { evalInProc { set ::x {{1 2} {3 4}} lset ::x {1 1} 5 } } "0 {{1 2} {3 5}}" test lsetComp-2.3 {lset, compiled, list of args, scalar, one-byte offset} { evalInProc { set x {{1 2} {3 4}} lset x {1 1} 5 } } "0 {{1 2} {3 5}}" test lsetComp-2.4 {lset, compiled, list of args, scalar, four-byte offset} { evalInProc { set x0 0; set x1 0; set x2 0; set x3 0; set x4 0; set x5 0; set x6 0; set x7 0; set x8 0; set x9 0; set x10 0; set x11 0; set x12 0; set x13 0; set x14 0; set x15 0; set x16 0; set x17 0; set x18 0; set x19 0; set x20 0; set x21 0; set x22 0; set x23 0; set x24 0; set x25 0; set x26 0; set x27 0; set x28 0; set x29 0; set x30 0; set x31 0; set x32 0; set x33 0; set x34 0; set x35 0; set x36 0; set x37 0; set x38 0; set x39 0; set x40 0; set x41 0; set x42 0; set x43 0; set x44 0; set x45 0; set x46 0; set x47 0; set x48 0; set x49 0; set x50 0; set x51 0; set x52 0; set x53 0; set x54 0; set x55 0; set x56 0; set x57 0; set x58 0; set x59 0; set x60 0; set x61 0; set x62 0; set x63 0; set x64 0; set x65 0; set x66 0; set x67 0; set x68 0; set x69 0; set x70 0; set x71 0; set x72 0; set x73 0; set x74 0; set x75 0; set x76 0; set x77 0; set x78 0; set x79 0; set x80 0; set x81 0; set x82 0; set x83 0; set x84 0; set x85 0; set x86 0; set x87 0; set x88 0; set x89 0; set x90 0; set x91 0; set x92 0; set x93 0; set x94 0; set x95 0; set x96 0; set x97 0; set x98 0; set x99 0; set x100 0; set x101 0; set x102 0; set x103 0; set x104 0; set x105 0; set x106 0; set x107 0; set x108 0; set x109 0; set x110 0; set x111 0; set x112 0; set x113 0; set x114 0; set x115 0; set x116 0; set x117 0; set x118 0; set x119 0; set x120 0; set x121 0; set x122 0; set x123 0; set x124 0; set x125 0; set x126 0; set x127 0; set x128 0; set x129 0; set x130 0; set x131 0; set x132 0; set x133 0; set x134 0; set x135 0; set x136 0; set x137 0; set x138 0; set x139 0; set x140 0; set x141 0; set x142 0; set x143 0; set x144 0; set x145 0; set x146 0; set x147 0; set x148 0; set x149 0; set x150 0; set x151 0; set x152 0; set x153 0; set x154 0; set x155 0; set x156 0; set x157 0; set x158 0; set x159 0; set x160 0; set x161 0; set x162 0; set x163 0; set x164 0; set x165 0; set x166 0; set x167 0; set x168 0; set x169 0; set x170 0; set x171 0; set x172 0; set x173 0; set x174 0; set x175 0; set x176 0; set x177 0; set x178 0; set x179 0; set x180 0; set x181 0; set x182 0; set x183 0; set x184 0; set x185 0; set x186 0; set x187 0; set x188 0; set x189 0; set x190 0; set x191 0; set x192 0; set x193 0; set x194 0; set x195 0; set x196 0; set x197 0; set x198 0; set x199 0; set x200 0; set x201 0; set x202 0; set x203 0; set x204 0; set x205 0; set x206 0; set x207 0; set x208 0; set x209 0; set x210 0; set x211 0; set x212 0; set x213 0; set x214 0; set x215 0; set x216 0; set x217 0; set x218 0; set x219 0; set x220 0; set x221 0; set x222 0; set x223 0; set x224 0; set x225 0; set x226 0; set x227 0; set x228 0; set x229 0; set x230 0; set x231 0; set x232 0; set x233 0; set x234 0; set x235 0; set x236 0; set x237 0; set x238 0; set x239 0; set x240 0; set x241 0; set x242 0; set x243 0; set x244 0; set x245 0; set x246 0; set x247 0; set x248 0; set x249 0; set x250 0; set x251 0; set x252 0; set x253 0; set x254 0; set x255 0; set x {{1 2} {3 4}} lset x {1 1} 5 } } "0 {{1 2} {3 5}}" test lsetComp-2.5 {lset, compiled, list of args, array on stack} { evalInProc { set ::y(0) {{1 2} {3 4}} lset ::y(0) {1 1} 5 } } "0 {{1 2} {3 5}}" test lsetComp-2.6 {lset, compiled, list of args, array, one-byte offset} { evalInProc { set y(0) {{1 2} {3 4}} lset y(0) {1 1} 5 } } "0 {{1 2} {3 5}}" test lsetComp-2.7 {lset, compiled, list of args, array, four-byte offset} { evalInProc { set x0 0; set x1 0; set x2 0; set x3 0; set x4 0; set x5 0; set x6 0; set x7 0; set x8 0; set x9 0; set x10 0; set x11 0; set x12 0; set x13 0; set x14 0; set x15 0; set x16 0; set x17 0; set x18 0; set x19 0; set x20 0; set x21 0; set x22 0; set x23 0; set x24 0; set x25 0; set x26 0; set x27 0; set x28 0; set x29 0; set x30 0; set x31 0; set x32 0; set x33 0; set x34 0; set x35 0; set x36 0; set x37 0; set x38 0; set x39 0; set x40 0; set x41 0; set x42 0; set x43 0; set x44 0; set x45 0; set x46 0; set x47 0; set x48 0; set x49 0; set x50 0; set x51 0; set x52 0; set x53 0; set x54 0; set x55 0; set x56 0; set x57 0; set x58 0; set x59 0; set x60 0; set x61 0; set x62 0; set x63 0; set x64 0; set x65 0; set x66 0; set x67 0; set x68 0; set x69 0; set x70 0; set x71 0; set x72 0; set x73 0; set x74 0; set x75 0; set x76 0; set x77 0; set x78 0; set x79 0; set x80 0; set x81 0; set x82 0; set x83 0; set x84 0; set x85 0; set x86 0; set x87 0; set x88 0; set x89 0; set x90 0; set x91 0; set x92 0; set x93 0; set x94 0; set x95 0; set x96 0; set x97 0; set x98 0; set x99 0; set x100 0; set x101 0; set x102 0; set x103 0; set x104 0; set x105 0; set x106 0; set x107 0; set x108 0; set x109 0; set x110 0; set x111 0; set x112 0; set x113 0; set x114 0; set x115 0; set x116 0; set x117 0; set x118 0; set x119 0; set x120 0; set x121 0; set x122 0; set x123 0; set x124 0; set x125 0; set x126 0; set x127 0; set x128 0; set x129 0; set x130 0; set x131 0; set x132 0; set x133 0; set x134 0; set x135 0; set x136 0; set x137 0; set x138 0; set x139 0; set x140 0; set x141 0; set x142 0; set x143 0; set x144 0; set x145 0; set x146 0; set x147 0; set x148 0; set x149 0; set x150 0; set x151 0; set x152 0; set x153 0; set x154 0; set x155 0; set x156 0; set x157 0; set x158 0; set x159 0; set x160 0; set x161 0; set x162 0; set x163 0; set x164 0; set x165 0; set x166 0; set x167 0; set x168 0; set x169 0; set x170 0; set x171 0; set x172 0; set x173 0; set x174 0; set x175 0; set x176 0; set x177 0; set x178 0; set x179 0; set x180 0; set x181 0; set x182 0; set x183 0; set x184 0; set x185 0; set x186 0; set x187 0; set x188 0; set x189 0; set x190 0; set x191 0; set x192 0; set x193 0; set x194 0; set x195 0; set x196 0; set x197 0; set x198 0; set x199 0; set x200 0; set x201 0; set x202 0; set x203 0; set x204 0; set x205 0; set x206 0; set x207 0; set x208 0; set x209 0; set x210 0; set x211 0; set x212 0; set x213 0; set x214 0; set x215 0; set x216 0; set x217 0; set x218 0; set x219 0; set x220 0; set x221 0; set x222 0; set x223 0; set x224 0; set x225 0; set x226 0; set x227 0; set x228 0; set x229 0; set x230 0; set x231 0; set x232 0; set x233 0; set x234 0; set x235 0; set x236 0; set x237 0; set x238 0; set x239 0; set x240 0; set x241 0; set x242 0; set x243 0; set x244 0; set x245 0; set x246 0; set x247 0; set x248 0; set x249 0; set x250 0; set x251 0; set x252 0; set x253 0; set x254 0; set x255 0; set y(0) {{1 2} {3 4}} lset y(0) {1 1} 5 } } "0 {{1 2} {3 5}}" test lsetComp-2.8 {lset, compiled, list of args, error } { evalInProc { set x { {1 2} {3 4} } lset x {1 5} 5 } } "1 {list index out of range}" test lsetComp-2.9 {lset, compiled, list of args, error - is string preserved} { set ::x { { 1 2 } { 3 4 } } evalInProc { lset ::x { 1 5 } 5 } list $::x [lindex $::x 1] } "{ { 1 2 } { 3 4 } } { 3 4 }" test lsetComp-3.1 {lset, compiled, flat args, not a simple var name} { evalInProc { set y x set x {{1 2} {3 4}} lset $y 1 1 5 } } "0 {{1 2} {3 5}}" test lsetComp-3.2 {lset, compiled, flat args, scalar on stack} { evalInProc { set ::x {{1 2} {3 4}} lset ::x 1 1 5 } } "0 {{1 2} {3 5}}" test lsetComp-3.3 {lset, compiled, flat args, scalar, one-byte offset} { evalInProc { set x {{1 2} {3 4}} lset x 1 1 5 } } "0 {{1 2} {3 5}}" test lsetComp-3.4 {lset, compiled, scalar, four-byte offset} { evalInProc { set x0 0; set x1 0; set x2 0; set x3 0; set x4 0; set x5 0; set x6 0; set x7 0; set x8 0; set x9 0; set x10 0; set x11 0; set x12 0; set x13 0; set x14 0; set x15 0; set x16 0; set x17 0; set x18 0; set x19 0; set x20 0; set x21 0; set x22 0; set x23 0; set x24 0; set x25 0; set x26 0; set x27 0; set x28 0; set x29 0; set x30 0; set x31 0; set x32 0; set x33 0; set x34 0; set x35 0; set x36 0; set x37 0; set x38 0; set x39 0; set x40 0; set x41 0; set x42 0; set x43 0; set x44 0; set x45 0; set x46 0; set x47 0; set x48 0; set x49 0; set x50 0; set x51 0; set x52 0; set x53 0; set x54 0; set x55 0; set x56 0; set x57 0; set x58 0; set x59 0; set x60 0; set x61 0; set x62 0; set x63 0; set x64 0; set x65 0; set x66 0; set x67 0; set x68 0; set x69 0; set x70 0; set x71 0; set x72 0; set x73 0; set x74 0; set x75 0; set x76 0; set x77 0; set x78 0; set x79 0; set x80 0; set x81 0; set x82 0; set x83 0; set x84 0; set x85 0; set x86 0; set x87 0; set x88 0; set x89 0; set x90 0; set x91 0; set x92 0; set x93 0; set x94 0; set x95 0; set x96 0; set x97 0; set x98 0; set x99 0; set x100 0; set x101 0; set x102 0; set x103 0; set x104 0; set x105 0; set x106 0; set x107 0; set x108 0; set x109 0; set x110 0; set x111 0; set x112 0; set x113 0; set x114 0; set x115 0; set x116 0; set x117 0; set x118 0; set x119 0; set x120 0; set x121 0; set x122 0; set x123 0; set x124 0; set x125 0; set x126 0; set x127 0; set x128 0; set x129 0; set x130 0; set x131 0; set x132 0; set x133 0; set x134 0; set x135 0; set x136 0; set x137 0; set x138 0; set x139 0; set x140 0; set x141 0; set x142 0; set x143 0; set x144 0; set x145 0; set x146 0; set x147 0; set x148 0; set x149 0; set x150 0; set x151 0; set x152 0; set x153 0; set x154 0; set x155 0; set x156 0; set x157 0; set x158 0; set x159 0; set x160 0; set x161 0; set x162 0; set x163 0; set x164 0; set x165 0; set x166 0; set x167 0; set x168 0; set x169 0; set x170 0; set x171 0; set x172 0; set x173 0; set x174 0; set x175 0; set x176 0; set x177 0; set x178 0; set x179 0; set x180 0; set x181 0; set x182 0; set x183 0; set x184 0; set x185 0; set x186 0; set x187 0; set x188 0; set x189 0; set x190 0; set x191 0; set x192 0; set x193 0; set x194 0; set x195 0; set x196 0; set x197 0; set x198 0; set x199 0; set x200 0; set x201 0; set x202 0; set x203 0; set x204 0; set x205 0; set x206 0; set x207 0; set x208 0; set x209 0; set x210 0; set x211 0; set x212 0; set x213 0; set x214 0; set x215 0; set x216 0; set x217 0; set x218 0; set x219 0; set x220 0; set x221 0; set x222 0; set x223 0; set x224 0; set x225 0; set x226 0; set x227 0; set x228 0; set x229 0; set x230 0; set x231 0; set x232 0; set x233 0; set x234 0; set x235 0; set x236 0; set x237 0; set x238 0; set x239 0; set x240 0; set x241 0; set x242 0; set x243 0; set x244 0; set x245 0; set x246 0; set x247 0; set x248 0; set x249 0; set x250 0; set x251 0; set x252 0; set x253 0; set x254 0; set x255 0; set x {{1 2} {3 4}} lset x 1 1 5 } } "0 {{1 2} {3 5}}" test lsetComp-3.5 {lset, compiled, flat args, array on stack} { evalInProc { set ::y(0) {{1 2} {3 4}} lset ::y(0) 1 1 5 } } "0 {{1 2} {3 5}}" test lsetComp-3.6 {lset, compiled, flat args, array, one-byte offset} { evalInProc { set y(0) {{1 2} {3 4}} lset y(0) 1 1 5 } } "0 {{1 2} {3 5}}" test lsetComp-3.7 {lset, compiled, flat args, array, four-byte offset} { evalInProc { set x0 0; set x1 0; set x2 0; set x3 0; set x4 0; set x5 0; set x6 0; set x7 0; set x8 0; set x9 0; set x10 0; set x11 0; set x12 0; set x13 0; set x14 0; set x15 0; set x16 0; set x17 0; set x18 0; set x19 0; set x20 0; set x21 0; set x22 0; set x23 0; set x24 0; set x25 0; set x26 0; set x27 0; set x28 0; set x29 0; set x30 0; set x31 0; set x32 0; set x33 0; set x34 0; set x35 0; set x36 0; set x37 0; set x38 0; set x39 0; set x40 0; set x41 0; set x42 0; set x43 0; set x44 0; set x45 0; set x46 0; set x47 0; set x48 0; set x49 0; set x50 0; set x51 0; set x52 0; set x53 0; set x54 0; set x55 0; set x56 0; set x57 0; set x58 0; set x59 0; set x60 0; set x61 0; set x62 0; set x63 0; set x64 0; set x65 0; set x66 0; set x67 0; set x68 0; set x69 0; set x70 0; set x71 0; set x72 0; set x73 0; set x74 0; set x75 0; set x76 0; set x77 0; set x78 0; set x79 0; set x80 0; set x81 0; set x82 0; set x83 0; set x84 0; set x85 0; set x86 0; set x87 0; set x88 0; set x89 0; set x90 0; set x91 0; set x92 0; set x93 0; set x94 0; set x95 0; set x96 0; set x97 0; set x98 0; set x99 0; set x100 0; set x101 0; set x102 0; set x103 0; set x104 0; set x105 0; set x106 0; set x107 0; set x108 0; set x109 0; set x110 0; set x111 0; set x112 0; set x113 0; set x114 0; set x115 0; set x116 0; set x117 0; set x118 0; set x119 0; set x120 0; set x121 0; set x122 0; set x123 0; set x124 0; set x125 0; set x126 0; set x127 0; set x128 0; set x129 0; set x130 0; set x131 0; set x132 0; set x133 0; set x134 0; set x135 0; set x136 0; set x137 0; set x138 0; set x139 0; set x140 0; set x141 0; set x142 0; set x143 0; set x144 0; set x145 0; set x146 0; set x147 0; set x148 0; set x149 0; set x150 0; set x151 0; set x152 0; set x153 0; set x154 0; set x155 0; set x156 0; set x157 0; set x158 0; set x159 0; set x160 0; set x161 0; set x162 0; set x163 0; set x164 0; set x165 0; set x166 0; set x167 0; set x168 0; set x169 0; set x170 0; set x171 0; set x172 0; set x173 0; set x174 0; set x175 0; set x176 0; set x177 0; set x178 0; set x179 0; set x180 0; set x181 0; set x182 0; set x183 0; set x184 0; set x185 0; set x186 0; set x187 0; set x188 0; set x189 0; set x190 0; set x191 0; set x192 0; set x193 0; set x194 0; set x195 0; set x196 0; set x197 0; set x198 0; set x199 0; set x200 0; set x201 0; set x202 0; set x203 0; set x204 0; set x205 0; set x206 0; set x207 0; set x208 0; set x209 0; set x210 0; set x211 0; set x212 0; set x213 0; set x214 0; set x215 0; set x216 0; set x217 0; set x218 0; set x219 0; set x220 0; set x221 0; set x222 0; set x223 0; set x224 0; set x225 0; set x226 0; set x227 0; set x228 0; set x229 0; set x230 0; set x231 0; set x232 0; set x233 0; set x234 0; set x235 0; set x236 0; set x237 0; set x238 0; set x239 0; set x240 0; set x241 0; set x242 0; set x243 0; set x244 0; set x245 0; set x246 0; set x247 0; set x248 0; set x249 0; set x250 0; set x251 0; set x252 0; set x253 0; set x254 0; set x255 0; set y(0) {{1 2} {3 4}} lset y(0) 1 1 5 } } "0 {{1 2} {3 5}}" test lsetComp-3.8 {lset, compiled, flat args, error } { evalInProc { set x { {1 2} {3 4} } lset x 1 5 5 } } "1 {list index out of range}" test lsetComp-3.9 {lset, compiled, flat args, error - is string preserved} { set ::x { { 1 2 } { 3 4 } } evalInProc { lset ::x 1 5 5 } list $::x [lindex $::x 1] } "{ { 1 2 } { 3 4 } } { 3 4 }" catch { rename evalInProc {} } catch { unset ::x } catch { unset ::y } # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/fileName.test0000644003604700454610000015252712052456744014515 0ustar dgp771div# This file tests the filename manipulation routines. # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1995-1996 Sun Microsystems, Inc. # Copyright (c) 1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import -force ::tcltest::* } tcltest::testConstraint testsetplatform [string equal testsetplatform [info commands testsetplatform]] tcltest::testConstraint testtranslatefilename [string equal testtranslatefilename [info commands testtranslatefilename]] global env if {[tcltest::testConstraint testsetplatform]} { set platform [testgetplatform] } test filename-1.1 {Tcl_GetPathType: unix} {testsetplatform} { testsetplatform unix file pathtype / } absolute test filename-1.2 {Tcl_GetPathType: unix} {testsetplatform} { testsetplatform unix file pathtype /foo } absolute test filename-1.3 {Tcl_GetPathType: unix} {testsetplatform} { testsetplatform unix file pathtype foo } relative test filename-1.4 {Tcl_GetPathType: unix} {testsetplatform} { testsetplatform unix file pathtype c:/foo } relative test filename-1.5 {Tcl_GetPathType: unix} {testsetplatform} { testsetplatform unix file pathtype ~ } absolute test filename-1.6 {Tcl_GetPathType: unix} {testsetplatform} { testsetplatform unix file pathtype ~/foo } absolute test filename-1.7 {Tcl_GetPathType: unix} {testsetplatform} { testsetplatform unix file pathtype ~foo } absolute test filename-1.8 {Tcl_GetPathType: unix} {testsetplatform} { testsetplatform unix file pathtype ./~foo } relative test filename-3.1 {Tcl_GetPathType: windows} {testsetplatform} { testsetplatform windows file pathtype / } volumerelative test filename-3.2 {Tcl_GetPathType: windows} {testsetplatform} { testsetplatform windows file pathtype \\ } volumerelative test filename-3.3 {Tcl_GetPathType: windows} {testsetplatform} { testsetplatform windows file pathtype /foo } volumerelative test filename-3.4 {Tcl_GetPathType: windows} {testsetplatform} { testsetplatform windows file pathtype \\foo } volumerelative test filename-3.5 {Tcl_GetPathType: windows} {testsetplatform} { testsetplatform windows file pathtype c:/ } absolute test filename-3.6 {Tcl_GetPathType: windows} {testsetplatform} { testsetplatform windows file pathtype c:\\ } absolute test filename-3.7 {Tcl_GetPathType: windows} {testsetplatform} { testsetplatform windows file pathtype c:/foo } absolute test filename-3.8 {Tcl_GetPathType: windows} {testsetplatform} { testsetplatform windows file pathtype c:\\foo } absolute test filename-3.9 {Tcl_GetPathType: windows} {testsetplatform} { testsetplatform windows file pathtype c: } volumerelative test filename-3.10 {Tcl_GetPathType: windows} {testsetplatform} { testsetplatform windows file pathtype c:foo } volumerelative test filename-3.11 {Tcl_GetPathType: windows} {testsetplatform} { testsetplatform windows file pathtype foo } relative test filename-3.12 {Tcl_GetPathType: windows} {testsetplatform} { testsetplatform windows file pathtype //foo/bar } absolute test filename-3.13 {Tcl_GetPathType: windows} {testsetplatform} { testsetplatform windows file pathtype ~foo } absolute test filename-3.14 {Tcl_GetPathType: windows} {testsetplatform} { testsetplatform windows file pathtype ~ } absolute test filename-3.15 {Tcl_GetPathType: windows} {testsetplatform} { testsetplatform windows file pathtype ~/foo } absolute test filename-3.16 {Tcl_GetPathType: windows} {testsetplatform} { testsetplatform windows file pathtype ./~foo } relative test filename-4.1 {Tcl_SplitPath: unix} {testsetplatform} { testsetplatform unix file split / } {/} test filename-4.2 {Tcl_SplitPath: unix} {testsetplatform} { testsetplatform unix file split /foo } {/ foo} test filename-4.3 {Tcl_SplitPath: unix} {testsetplatform} { testsetplatform unix file split /foo/bar } {/ foo bar} test filename-4.4 {Tcl_SplitPath: unix} {testsetplatform} { testsetplatform unix file split /foo/bar/baz } {/ foo bar baz} test filename-4.5 {Tcl_SplitPath: unix} {testsetplatform} { testsetplatform unix file split foo/bar } {foo bar} test filename-4.6 {Tcl_SplitPath: unix} {testsetplatform} { testsetplatform unix file split ./foo/bar } {. foo bar} test filename-4.7 {Tcl_SplitPath: unix} {testsetplatform} { testsetplatform unix file split /foo/../././foo/bar } {/ foo .. . . foo bar} test filename-4.8 {Tcl_SplitPath: unix} {testsetplatform} { testsetplatform unix file split ../foo/bar } {.. foo bar} test filename-4.9 {Tcl_SplitPath: unix} {testsetplatform} { testsetplatform unix file split {} } {} test filename-4.10 {Tcl_SplitPath: unix} {testsetplatform} { testsetplatform unix file split . } {.} test filename-4.11 {Tcl_SplitPath: unix} {testsetplatform} { testsetplatform unix file split ../ } {..} test filename-4.12 {Tcl_SplitPath: unix} {testsetplatform} { testsetplatform unix file split ../.. } {.. ..} test filename-4.13 {Tcl_SplitPath: unix} {testsetplatform} { testsetplatform unix file split //foo } {/ foo} test filename-4.14 {Tcl_SplitPath: unix} {testsetplatform} { testsetplatform unix file split foo//bar } {foo bar} test filename-4.15 {Tcl_SplitPath: unix} {testsetplatform} { testsetplatform unix file split ~foo } {~foo} test filename-4.16 {Tcl_SplitPath: unix} {testsetplatform} { testsetplatform unix file split ~foo/~bar } {~foo ./~bar} test filename-4.17 {Tcl_SplitPath: unix} {testsetplatform} { testsetplatform unix file split ~foo/~bar/~baz } {~foo ./~bar ./~baz} test filename-4.18 {Tcl_SplitPath: unix} {testsetplatform} { testsetplatform unix file split foo/bar~/baz } {foo bar~ baz} if {[tcltest::testConstraint testsetplatform]} { testsetplatform $platform } test filename-4.19 {Tcl_SplitPath} { set oldDir [pwd] set res [catch { cd [temporaryDirectory] file mkdir tildetmp set nastydir [file join tildetmp ./~tilde] file mkdir $nastydir set norm [file normalize $nastydir] cd tildetmp cd ./~tilde glob -nocomplain * set idx [string first tildetmp $norm] set norm [string range $norm $idx end] # fix path away so all platforms are the same regsub {(.*):$} $norm {\1} norm regsub -all ":" $norm "/" norm # make sure we can delete the directory we created cd $oldDir file delete -force $nastydir set norm } err] cd $oldDir catch {file delete -force [file join [temporaryDirectory] tildetmp]} list $res $err } {0 tildetmp/~tilde} test filename-6.1 {Tcl_SplitPath: win} {testsetplatform} { testsetplatform win file split / } {/} test filename-6.2 {Tcl_SplitPath: win} {testsetplatform} { testsetplatform win file split /foo } {/ foo} test filename-6.3 {Tcl_SplitPath: win} {testsetplatform} { testsetplatform win file split /foo/bar } {/ foo bar} test filename-6.4 {Tcl_SplitPath: win} {testsetplatform} { testsetplatform win file split /foo/bar/baz } {/ foo bar baz} test filename-6.5 {Tcl_SplitPath: win} {testsetplatform} { testsetplatform win file split foo/bar } {foo bar} test filename-6.6 {Tcl_SplitPath: win} {testsetplatform} { testsetplatform win file split ./foo/bar } {. foo bar} test filename-6.7 {Tcl_SplitPath: win} {testsetplatform} { testsetplatform win file split /foo/../././foo/bar } {/ foo .. . . foo bar} test filename-6.8 {Tcl_SplitPath: win} {testsetplatform} { testsetplatform win file split ../foo/bar } {.. foo bar} test filename-6.9 {Tcl_SplitPath: win} {testsetplatform} { testsetplatform win file split {} } {} test filename-6.10 {Tcl_SplitPath: win} {testsetplatform} { testsetplatform win file split . } {.} test filename-6.11 {Tcl_SplitPath: win} {testsetplatform} { testsetplatform win file split ../ } {..} test filename-6.12 {Tcl_SplitPath: win} {testsetplatform} { testsetplatform win file split ../.. } {.. ..} test filename-6.13 {Tcl_SplitPath: win} {testsetplatform} { testsetplatform win file split //foo } {/ foo} test filename-6.14 {Tcl_SplitPath: win} {testsetplatform} { testsetplatform win file split foo//bar } {foo bar} test filename-6.15 {Tcl_SplitPath: win} {testsetplatform} { testsetplatform win file split /\\/foo//bar } {//foo/bar} test filename-6.16 {Tcl_SplitPath: win} {testsetplatform} { testsetplatform win file split /\\/foo//bar } {//foo/bar} test filename-6.17 {Tcl_SplitPath: win} {testsetplatform} { testsetplatform win file split /\\/foo//bar } {//foo/bar} test filename-6.18 {Tcl_SplitPath: win} {testsetplatform} { testsetplatform win file split \\\\foo\\bar } {//foo/bar} test filename-6.19 {Tcl_SplitPath: win} {testsetplatform} { testsetplatform win file split \\\\foo\\bar/baz } {//foo/bar baz} test filename-6.20 {Tcl_SplitPath: win} {testsetplatform} { testsetplatform win file split c:/foo } {c:/ foo} test filename-6.21 {Tcl_SplitPath: win} {testsetplatform} { testsetplatform win file split c:foo } {c: foo} test filename-6.22 {Tcl_SplitPath: win} {testsetplatform} { testsetplatform win file split c: } {c:} test filename-6.23 {Tcl_SplitPath: win} {testsetplatform} { testsetplatform win file split c:\\ } {c:/} test filename-6.24 {Tcl_SplitPath: win} {testsetplatform} { testsetplatform win file split c:/ } {c:/} test filename-6.25 {Tcl_SplitPath: win} {testsetplatform} { testsetplatform win file split c:/./.. } {c:/ . ..} test filename-6.26 {Tcl_SplitPath: win} {testsetplatform} { testsetplatform win file split ~foo } {~foo} test filename-6.27 {Tcl_SplitPath: win} {testsetplatform} { testsetplatform win file split ~foo/~bar } {~foo ./~bar} test filename-6.28 {Tcl_SplitPath: win} {testsetplatform} { testsetplatform win file split ~foo/~bar/~baz } {~foo ./~bar ./~baz} test filename-6.29 {Tcl_SplitPath: win} {testsetplatform} { testsetplatform win file split foo/bar~/baz } {foo bar~ baz} test filename-6.30 {Tcl_SplitPath: win} {testsetplatform} { testsetplatform win file split c:~foo } {c: ./~foo} test filename-7.1 {Tcl_JoinPath: unix} {testsetplatform} { testsetplatform unix file join / a } {/a} test filename-7.2 {Tcl_JoinPath: unix} {testsetplatform} { testsetplatform unix file join a b } {a/b} test filename-7.3 {Tcl_JoinPath: unix} {testsetplatform} { testsetplatform unix file join /a c /b d } {/b/d} test filename-7.4 {Tcl_JoinPath: unix} {testsetplatform} { testsetplatform unix file join / } {/} test filename-7.5 {Tcl_JoinPath: unix} {testsetplatform} { testsetplatform unix file join a } {a} test filename-7.6 {Tcl_JoinPath: unix} {testsetplatform} { testsetplatform unix file join {} } {} test filename-7.7 {Tcl_JoinPath: unix} {testsetplatform} { testsetplatform unix file join /a/ b } {/a/b} test filename-7.8 {Tcl_JoinPath: unix} {testsetplatform} { testsetplatform unix file join /a// b } {/a/b} test filename-7.9 {Tcl_JoinPath: unix} {testsetplatform} { testsetplatform unix file join /a/./../. b } {/a/./.././b} test filename-7.10 {Tcl_JoinPath: unix} {testsetplatform} { testsetplatform unix file join ~ a } {~/a} test filename-7.11 {Tcl_JoinPath: unix} {testsetplatform} { testsetplatform unix file join ~a ~b } {~b} test filename-7.12 {Tcl_JoinPath: unix} {testsetplatform} { testsetplatform unix file join ./~a b } {./~a/b} test filename-7.13 {Tcl_JoinPath: unix} {testsetplatform} { testsetplatform unix file join ./~a ~b } {~b} test filename-7.14 {Tcl_JoinPath: unix} {testsetplatform} { testsetplatform unix file join ./~a ./~b } {./~a/~b} test filename-7.15 {Tcl_JoinPath: unix} {testsetplatform} { testsetplatform unix file join a . b } {a/./b} test filename-7.16 {Tcl_JoinPath: unix} {testsetplatform} { testsetplatform unix file join a . ./~b } {a/./~b} test filename-7.17 {Tcl_JoinPath: unix} {testsetplatform} { testsetplatform unix file join //a b } {/a/b} test filename-7.18 {Tcl_JoinPath: unix} {testsetplatform} { testsetplatform unix file join /// a b } {/a/b} test filename-9.1 {Tcl_JoinPath: win} {testsetplatform} { testsetplatform win file join a b } {a/b} test filename-9.2 {Tcl_JoinPath: win} {testsetplatform} { testsetplatform win file join /a b } {/a/b} test filename-9.3 {Tcl_JoinPath: win} {testsetplatform} { testsetplatform win file join /a /b } {/b} test filename-9.4 {Tcl_JoinPath: win} {testsetplatform} { testsetplatform win file join c: foo } {c:foo} test filename-9.5 {Tcl_JoinPath: win} {testsetplatform} { testsetplatform win file join c:/ foo } {c:/foo} test filename-9.6 {Tcl_JoinPath: win} {testsetplatform} { testsetplatform win file join c:\\bar foo } {c:/bar/foo} test filename-9.7 {Tcl_JoinPath: win} {testsetplatform} { testsetplatform win file join /foo c:bar } {c:bar} test filename-9.8 {Tcl_JoinPath: win} {testsetplatform} { testsetplatform win file join ///host//share dir } {//host/share/dir} test filename-9.9 {Tcl_JoinPath: win} {testsetplatform} { testsetplatform win file join ~ foo } {~/foo} test filename-9.10 {Tcl_JoinPath: win} {testsetplatform} { testsetplatform win file join ~/~foo } {~/~foo} test filename-9.11 {Tcl_JoinPath: win} {testsetplatform} { testsetplatform win file join ~ ./~foo } {~/~foo} test filename-9.12 {Tcl_JoinPath: win} {testsetplatform} { testsetplatform win file join / ~foo } {~foo} test filename-9.13 {Tcl_JoinPath: win} {testsetplatform} { testsetplatform win file join ./a/ b c } {./a/b/c} test filename-9.14 {Tcl_JoinPath: win} {testsetplatform} { testsetplatform win file join ./~a/ b c } {./~a/b/c} test filename-9.15 {Tcl_JoinPath: win} {testsetplatform} { testsetplatform win file join // host share path } {/host/share/path} test filename-9.16 {Tcl_JoinPath: win} {testsetplatform} { testsetplatform win file join foo . bar } {foo/./bar} test filename-9.17 {Tcl_JoinPath: win} {testsetplatform} { testsetplatform win file join foo .. bar } {foo/../bar} test filename-9.18 {Tcl_JoinPath: win} {testsetplatform} { testsetplatform win file join foo/./bar } {foo/./bar} test filename-9.19 {Tcl_JoinPath: win} {testsetplatform} { testsetplatform win set res {} lappend res \ [file join {C:\foo\bar}] \ [file join C:/blah {C:\foo\bar}] \ [file join C:/blah C:/blah {C:\foo\bar}] } {C:/foo/bar C:/foo/bar C:/foo/bar} test filename-9.19.1 {Tcl_JoinPath: win} {testsetplatform} { testsetplatform win set res {} lappend res \ [file join {foo\bar}] \ [file join C:/blah {foo\bar}] \ [file join C:/blah C:/blah {foo\bar}] } {foo/bar C:/blah/foo/bar C:/blah/foo/bar} test filename-9.19.2 {Tcl_JoinPath: win} {testsetplatform winOnly} { testsetplatform win set res {} lappend res \ [file join {foo\bar}] \ [file join [pwd] {foo\bar}] \ [file join [pwd] [pwd] {foo\bar}] string map [list [pwd] pwd] $res } {foo/bar pwd/foo/bar pwd/foo/bar} test filename-9.20 {Tcl_JoinPath: unix} {testsetplatform} { testsetplatform unix set res {} lappend res \ [file join {/foo/bar}] \ [file join /x {/foo/bar}] \ [file join /x /x {/foo/bar}] } {/foo/bar /foo/bar /foo/bar} test filename-9.23 {Tcl_JoinPath: win} {testsetplatform} { testsetplatform win set res {} lappend res \ [file join {foo\bar}] \ [file join C:/blah {foo\bar}] \ [file join C:/blah C:/blah {foo\bar}] string map [list C:/blah ""] $res } {foo/bar /foo/bar /foo/bar} test filename-9.24 {Tcl_JoinPath: unix} {testsetplatform} { testsetplatform unix set res {} lappend res \ [file join {foo/bar}] \ [file join /x {foo/bar}] \ [file join /x /x {foo/bar}] string map [list /x ""] $res } {foo/bar /foo/bar /foo/bar} test filename-10.1 {Tcl_TranslateFileName} {testsetplatform} { testsetplatform unix list [catch {testtranslatefilename foo} msg] $msg } {0 foo} test filename-10.2 {Tcl_TranslateFileName} {testsetplatform} { testsetplatform windows list [catch {testtranslatefilename {c:/foo}} msg] $msg } {0 {c:\foo}} test filename-10.3 {Tcl_TranslateFileName} {testsetplatform} { testsetplatform windows list [catch {testtranslatefilename {c:/\\foo/}} msg] $msg } {0 {c:\foo}} test filename-10.6 {Tcl_TranslateFileName} {testsetplatform} { global env set temp $env(HOME) set env(HOME) "/home/test" testsetplatform unix set result [list [catch {testtranslatefilename ~/foo} msg] $msg] set env(HOME) $temp set result } {0 /home/test/foo} test filename-10.7 {Tcl_TranslateFileName} {testsetplatform} { global env set temp $env(HOME) unset env(HOME) testsetplatform unix set result [list [catch {testtranslatefilename ~/foo} msg] $msg] set env(HOME) $temp set result } {1 {couldn't find HOME environment variable to expand path}} test filename-10.8 {Tcl_TranslateFileName} {testsetplatform} { global env set temp $env(HOME) set env(HOME) "/home/test" testsetplatform unix set result [list [catch {testtranslatefilename ~} msg] $msg] set env(HOME) $temp set result } {0 /home/test} test filename-10.9 {Tcl_TranslateFileName} {testsetplatform} { global env set temp $env(HOME) set env(HOME) "/home/test/" testsetplatform unix set result [list [catch {testtranslatefilename ~} msg] $msg] set env(HOME) $temp set result } {0 /home/test} test filename-10.10 {Tcl_TranslateFileName} {testsetplatform} { global env set temp $env(HOME) set env(HOME) "/home/test/" testsetplatform unix set result [list [catch {testtranslatefilename ~/foo} msg] $msg] set env(HOME) $temp set result } {0 /home/test/foo} test filename-10.17 {Tcl_TranslateFileName} {testsetplatform} { global env set temp $env(HOME) set env(HOME) "\\home\\" testsetplatform windows set result [list [catch {testtranslatefilename ~/foo} msg] $msg] set env(HOME) $temp set result } {0 {\home\foo}} test filename-10.18 {Tcl_TranslateFileName} {testsetplatform} { global env set temp $env(HOME) set env(HOME) "\\home\\" testsetplatform windows set result [list [catch {testtranslatefilename ~/foo\\bar} msg] $msg] set env(HOME) $temp set result } {0 {\home\foo\bar}} test filename-10.19 {Tcl_TranslateFileName} {testsetplatform} { global env set temp $env(HOME) set env(HOME) "c:" testsetplatform windows set result [list [catch {testtranslatefilename ~/foo} msg] $msg] set env(HOME) $temp set result } {0 c:foo} test filename-10.20 {Tcl_TranslateFileName} {testtranslatefilename} { list [catch {testtranslatefilename ~blorp/foo} msg] $msg } {1 {user "blorp" doesn't exist}} test filename-10.21 {Tcl_TranslateFileName} {testsetplatform} { global env set temp $env(HOME) set env(HOME) "c:\\" testsetplatform windows set result [list [catch {testtranslatefilename ~/foo} msg] $msg] set env(HOME) $temp set result } {0 {c:\foo}} test filename-10.22 {Tcl_TranslateFileName} {testsetplatform} { testsetplatform windows list [catch {testtranslatefilename foo//bar} msg] $msg } {0 {foo\bar}} if {[tcltest::testConstraint testsetplatform]} { testsetplatform $platform } test filename-10.23 {Tcl_TranslateFileName} {unixOnly nonPortable} { # this test fails if ~ouster is not /home/ouster list [catch {testtranslatefilename ~ouster} msg] $msg } {0 /home/ouster} test filename-10.24 {Tcl_TranslateFileName} {unixOnly nonPortable} { # this test fails if ~ouster is not /home/ouster list [catch {testtranslatefilename ~ouster/foo} msg] $msg } {0 /home/ouster/foo} test filename-11.1 {Tcl_GlobCmd} { list [catch {glob} msg] $msg } {1 {wrong # args: should be "glob ?switches? name ?name ...?"}} test filename-11.2 {Tcl_GlobCmd} { list [catch {glob -gorp} msg] $msg } {1 {bad option "-gorp": must be -directory, -join, -nocomplain, -path, -tails, -types, or --}} test filename-11.3 {Tcl_GlobCmd} { list [catch {glob -nocomplai} msg] $msg } {1 {wrong # args: should be "glob ?switches? name ?name ...?"}} test filename-11.4 {Tcl_GlobCmd} { list [catch {glob -nocomplain} msg] $msg } {1 {wrong # args: should be "glob ?switches? name ?name ...?"}} test filename-11.5 {Tcl_GlobCmd} { list [catch {glob -nocomplain ~xyqrszzz} msg] $msg } {0 {}} test filename-11.6 {Tcl_GlobCmd} { list [catch {glob ~xyqrszzz} msg] $msg } {1 {user "xyqrszzz" doesn't exist}} test filename-11.7 {Tcl_GlobCmd} { list [catch {glob -- -nocomplain} msg] $msg } {1 {no files matched glob pattern "-nocomplain"}} test filename-11.8 {Tcl_GlobCmd} { list [catch {glob -nocomplain -- -nocomplain} msg] $msg } {0 {}} test filename-11.9 {Tcl_GlobCmd} {testsetplatform} { testsetplatform unix list [catch {glob ~\\xyqrszzz/bar} msg] $msg } {1 {user "\xyqrszzz" doesn't exist}} test filename-11.10 {Tcl_GlobCmd} {testsetplatform} { testsetplatform unix list [catch {glob -nocomplain ~\\xyqrszzz/bar} msg] $msg } {0 {}} test filename-11.11 {Tcl_GlobCmd} {testsetplatform} { testsetplatform unix list [catch {glob ~xyqrszzz\\/\\bar} msg] $msg } {1 {user "xyqrszzz" doesn't exist}} test filename-11.12 {Tcl_GlobCmd} {testsetplatform} { testsetplatform unix set home $env(HOME) unset env(HOME) set x [list [catch {glob ~/*} msg] $msg] set env(HOME) $home set x } {1 {couldn't find HOME environment variable to expand path}} if {[tcltest::testConstraint testsetplatform]} { testsetplatform $platform } test filename-11.13 {Tcl_GlobCmd} { list [catch {file join [lindex [glob ~] 0]} msg] $msg } [list 0 [file join $env(HOME)]] set oldpwd [pwd] set oldhome $env(HOME) cd [temporaryDirectory] set env(HOME) [pwd] file delete -force globTest file mkdir globTest/a1/b1 file mkdir globTest/a1/b2 file mkdir globTest/a2/b3 file mkdir globTest/a3 close [open globTest/x1.c w] close [open globTest/y1.c w] close [open globTest/z1.c w] close [open "globTest/weird name.c" w] close [open globTest/a1/b1/x2.c w] close [open globTest/a1/b2/y2.c w] catch {close [open globTest/.1 w]} catch {close [open globTest/x,z1.c w]} test filename-11.14 {Tcl_GlobCmd} { list [catch {glob ~/globTest} msg] $msg } [list 0 [list [file join $env(HOME) globTest]]] test filename-11.15 {Tcl_GlobCmd} { list [catch {glob ~\\/globTest} msg] $msg } [list 0 [list [file join $env(HOME) globTest]]] test filename-11.16 {Tcl_GlobCmd} { list [catch {glob globTest} msg] $msg } {0 globTest} set globname "globTest" set horribleglobname "glob\[\{Test" test filename-11.17 {Tcl_GlobCmd} {unixOnly} { list [catch {lsort [glob -directory $globname *]} msg] $msg } [list 0 [lsort [list [file join $globname a1] [file join $globname a2]\ [file join $globname a3]\ [file join $globname "weird name.c"]\ [file join $globname x,z1.c]\ [file join $globname x1.c]\ [file join $globname y1.c] [file join $globname z1.c]]]] test filename-11.17.1 {Tcl_GlobCmd} {pcOnly} { list [catch {lsort [glob -directory $globname *]} msg] $msg } [list 0 [lsort [list [file join $globname a1] [file join $globname a2]\ [file join $globname .1]\ [file join $globname a3]\ [file join $globname "weird name.c"]\ [file join $globname x,z1.c]\ [file join $globname x1.c]\ [file join $globname y1.c] [file join $globname z1.c]]]] if {[string equal $tcl_platform(platform) "windows"]} { if {[string index $tcl_platform(osVersion) 0] >= 5 \ && ([lindex [file system [temporaryDirectory]] 1] == "NTFS")} { tcltest::testConstraint linkDirectory 1 } else { tcltest::testConstraint linkDirectory 0 } } else { tcltest::testConstraint linkDirectory 1 } if {[string equal $tcl_platform(platform) "windows"]} { tcltest::testConstraint symbolicLinkFile 0 } else { tcltest::testConstraint symbolicLinkFile 1 } test filename-11.17.2 {Tcl_GlobCmd} {notRoot linkDirectory} { set dir [pwd] set ret "error in test" if {[catch { cd $globname file link -symbolic link a1 cd $dir set ret [list [catch { lsort [glob -directory $globname -join * b1] } msg] $msg] }]} { cd $dir } file delete [file join $globname link] set ret } [list 0 [lsort [list [file join $globname a1 b1] \ [file join $globname link b1]]]] # Simpler version of the above test to illustrate a given bug. test filename-11.17.3 {Tcl_GlobCmd} {notRoot linkDirectory} { set dir [pwd] set ret "error in test" if {[catch { cd $globname file link -symbolic link a1 cd $dir set ret [list [catch { lsort [glob -directory $globname -type d *] } msg] $msg] }]} { cd $dir } file delete [file join $globname link] set ret } [list 0 [lsort [list [file join $globname a1] \ [file join $globname a2] \ [file join $globname a3] \ [file join $globname link]]]] # Make sure the bugfix isn't too simple. We don't want # to break 'glob -type l'. test filename-11.17.4 {Tcl_GlobCmd} {notRoot linkDirectory} { set dir [pwd] set ret "error in test" if {[catch { cd $globname file link -symbolic link a1 cd $dir set ret [list [catch { lsort [glob -directory $globname -type l *] } msg] $msg] }]} { cd $dir } file delete [file join $globname link] set ret } [list 0 [list [file join $globname link]]] test filename-11.17.5 {Tcl_GlobCmd} { list [catch {lsort [glob -directory $globname -tails *.c]} msg] $msg } [list 0 [lsort [list "weird name.c" x,z1.c x1.c y1.c z1.c]]] test filename-11.17.6 {Tcl_GlobCmd} { list [catch {lsort [glob -directory $globname -tails *.c *.c]} msg] $msg } [list 0 [lsort [concat [list "weird name.c" x,z1.c x1.c y1.c z1.c] \ [list "weird name.c" x,z1.c x1.c y1.c z1.c]]]] test filename-11.17.7 {Tcl_GlobCmd: broken link and glob -l} {linkDirectory} { set dir [pwd] set ret "error in test" if {[catch { cd $globname file mkdir nonexistent file link -symbolic link nonexistent file delete nonexistent cd $dir set ret [list [catch { lsort [glob -nocomplain -directory $globname -type l *] } msg] $msg] }]} { cd $dir } file delete [file join $globname link] set ret } [list 0 [list [file join $globname link]]] test filename-11.17.8 {Tcl_GlobCmd: broken link and glob -l} {symbolicLinkFile} { set dir [pwd] set ret "error in test" if {[catch { cd $globname close [open "nonexistent" w] file link -symbolic link nonexistent file delete nonexistent cd $dir set ret [list [catch { lsort [glob -nocomplain -directory $globname -type l *] } msg] $msg] }]} { cd $dir } file delete [file join $globname link] set ret } [list 0 [list [file join $globname link]]] test filename-11.18 {Tcl_GlobCmd} {unixOnly} { list [catch {lsort [glob -path $globname/ *]} msg] $msg } [list 0 [lsort [list [file join $globname a1] [file join $globname a2]\ [file join $globname a3]\ [file join $globname "weird name.c"]\ [file join $globname x,z1.c]\ [file join $globname x1.c]\ [file join $globname y1.c] [file join $globname z1.c]]]] test filename-11.18.1 {Tcl_GlobCmd} {pcOnly} { list [catch {lsort [glob -path $globname/ *]} msg] $msg } [list 0 [lsort [list [file join $globname a1] [file join $globname a2]\ [file join $globname .1]\ [file join $globname a3]\ [file join $globname "weird name.c"]\ [file join $globname x,z1.c]\ [file join $globname x1.c]\ [file join $globname y1.c] [file join $globname z1.c]]]] test filename-11.19 {Tcl_GlobCmd} {unixOnly} { list [catch {lsort [glob -join -path \ [string range $globname 0 5] * *]} msg] $msg } [list 0 [lsort [list [file join $globname a1] [file join $globname a2]\ [file join $globname a3]\ [file join $globname "weird name.c"]\ [file join $globname x,z1.c]\ [file join $globname x1.c]\ [file join $globname y1.c] [file join $globname z1.c]]]] test filename-11.19.1 {Tcl_GlobCmd} {pcOnly} { list [catch {lsort [glob -join -path \ [string range $globname 0 5] * *]} msg] $msg } [list 0 [lsort [list [file join $globname a1] [file join $globname a2]\ [file join $globname .1]\ [file join $globname a3]\ [file join $globname "weird name.c"]\ [file join $globname x,z1.c]\ [file join $globname x1.c]\ [file join $globname y1.c] [file join $globname z1.c]]]] test filename-11.20 {Tcl_GlobCmd} { list [catch {lsort [glob -type d -dir $globname *]} msg] $msg } [list 0 [lsort [list [file join $globname a1]\ [file join $globname a2]\ [file join $globname a3]]]] test filename-11.21 {Tcl_GlobCmd} { list [catch {lsort [glob -type d -path $globname *]} msg] $msg } [list 0 [lsort [list $globname]]] test filename-11.21.1 {Tcl_GlobCmd} { close [open {[tcl].testremains} w] set res [list [catch {lsort [glob -path {[tcl]} *]} msg] $msg] file delete -force {[tcl].testremains} set res } [list 0 {{[tcl].testremains}}] # Get rid of file/dir if it exists, since it will have # been left behind by a previous failed run. if {[file exists $horribleglobname]} { file delete -force $horribleglobname } file rename globTest $horribleglobname set globname $horribleglobname test filename-11.22 {Tcl_GlobCmd} {unixOnly} { list [catch {lsort [glob -dir $globname *]} msg] $msg } [list 0 [lsort [list [file join $globname a1] [file join $globname a2]\ [file join $globname a3]\ [file join $globname "weird name.c"]\ [file join $globname x,z1.c]\ [file join $globname x1.c]\ [file join $globname y1.c] [file join $globname z1.c]]]] test filename-11.22.1 {Tcl_GlobCmd} {pcOnly} { list [catch {lsort [glob -dir $globname *]} msg] $msg } [list 0 [lsort [list [file join $globname a1] [file join $globname a2]\ [file join $globname .1]\ [file join $globname a3]\ [file join $globname "weird name.c"]\ [file join $globname x,z1.c]\ [file join $globname x1.c]\ [file join $globname y1.c] [file join $globname z1.c]]]] test filename-11.23 {Tcl_GlobCmd} {unixOnly} { list [catch {lsort [glob -path $globname/ *]} msg] $msg } [list 0 [lsort [list [file join $globname a1] [file join $globname a2]\ [file join $globname a3]\ [file join $globname "weird name.c"]\ [file join $globname x,z1.c]\ [file join $globname x1.c]\ [file join $globname y1.c] [file join $globname z1.c]]]] test filename-11.23.1 {Tcl_GlobCmd} {pcOnly} { list [catch {lsort [glob -path $globname/ *]} msg] $msg } [list 0 [lsort [list [file join $globname a1] [file join $globname a2]\ [file join $globname .1]\ [file join $globname a3]\ [file join $globname "weird name.c"]\ [file join $globname x,z1.c]\ [file join $globname x1.c]\ [file join $globname y1.c] [file join $globname z1.c]]]] test filename-11.24 {Tcl_GlobCmd} {unixOnly} { list [catch {lsort [glob -join -path \ [string range $globname 0 5] * *]} msg] $msg } [list 0 [lsort [list [file join $globname a1] [file join $globname a2]\ [file join $globname a3]\ [file join $globname "weird name.c"]\ [file join $globname x,z1.c]\ [file join $globname x1.c]\ [file join $globname y1.c] [file join $globname z1.c]]]] test filename-11.24.1 {Tcl_GlobCmd} {pcOnly} { list [catch {lsort [glob -join -path \ [string range $globname 0 5] * *]} msg] $msg } [list 0 [lsort [list [file join $globname a1] [file join $globname a2]\ [file join $globname .1]\ [file join $globname a3]\ [file join $globname "weird name.c"]\ [file join $globname x,z1.c]\ [file join $globname x1.c]\ [file join $globname y1.c] [file join $globname z1.c]]]] test filename-11.25 {Tcl_GlobCmd} { list [catch {lsort [glob -type d -dir $globname *]} msg] $msg } [list 0 [lsort [list [file join $globname a1]\ [file join $globname a2]\ [file join $globname a3]]]] test filename-11.25.1 {Tcl_GlobCmd} { list [catch {lsort [glob -type {d r} -dir $globname *]} msg] $msg } [list 0 [lsort [list [file join $globname a1]\ [file join $globname a2]\ [file join $globname a3]]]] test filename-11.25.2 {Tcl_GlobCmd} { list [catch {lsort [glob -type {d r w} -dir $globname *]} msg] $msg } [list 0 [lsort [list [file join $globname a1]\ [file join $globname a2]\ [file join $globname a3]]]] test filename-11.26 {Tcl_GlobCmd} { list [catch {glob -type d -path $globname *} msg] $msg } [list 0 [list $globname]] test filename-11.27 {Tcl_GlobCmd} { list [catch {glob -types abcde *} msg] $msg } {1 {bad argument to "-types": abcde}} test filename-11.28 {Tcl_GlobCmd} { list [catch {glob -types z *} msg] $msg } {1 {bad argument to "-types": z}} test filename-11.29 {Tcl_GlobCmd} { list [catch {glob -types {abcd efgh} *} msg] $msg } {1 {only one MacOS type or creator argument to "-types" allowed}} test filename-11.30 {Tcl_GlobCmd} { list [catch {glob -types {{macintosh type TEXT} \ {macintosh creator ALFA} efgh} *} msg] $msg } {1 {only one MacOS type or creator argument to "-types" allowed}} test filename-11.31 {Tcl_GlobCmd} { list [catch {glob -types} msg] $msg } {1 {missing argument to "-types"}} test filename-11.32 {Tcl_GlobCmd} { list [catch {glob -path hello -dir hello *} msg] $msg } {1 {"-directory" cannot be used with "-path"}} test filename-11.33 {Tcl_GlobCmd} { list [catch {glob -path} msg] $msg } {1 {missing argument to "-path"}} test filename-11.34 {Tcl_GlobCmd} { list [catch {glob -direct} msg] $msg } {1 {missing argument to "-directory"}} test filename-11.35 {Tcl_GlobCmd} { list [catch {glob -paths *} msg] $msg } {1 {bad option "-paths": must be -directory, -join, -nocomplain, -path, -tails, -types, or --}} # Test '-tails' flag to glob. test filename-11.36 {Tcl_GlobCmd} { list [catch {glob -tails *} msg] $msg } {1 {"-tails" must be used with either "-directory" or "-path"}} test filename-11.37 {Tcl_GlobCmd} { list [catch {glob -type d -tails -path $globname *} msg] $msg } [list 0 [list $globname]] test filename-11.38 {Tcl_GlobCmd} { list [catch {glob -tails -path $globname *} msg] $msg } [list 0 [list $globname]] test filename-11.39 {Tcl_GlobCmd} { list [catch {glob -tails -join -path $globname *} msg] $msg } [list 0 [list $globname]] test filename-11.40 {Tcl_GlobCmd} { expr {[glob -dir [pwd] -tails *] == [glob *]} } {1} test filename-11.41 {Tcl_GlobCmd} { expr {[glob -dir [pwd] -tails *] != [glob -dir [pwd] *]} } {1} test filename-11.42 {Tcl_GlobCmd} { set res [list] foreach f [glob -dir [pwd] *] { lappend res [file tail $f] } expr {$res == [glob *]} } {1} test filename-11.43 {Tcl_GlobCmd} { list [catch {glob -t *} msg] $msg } {1 {ambiguous option "-t": must be -directory, -join, -nocomplain, -path, -tails, -types, or --}} test filename-11.44 {Tcl_GlobCmd} { list [catch {glob -tails -path hello -directory hello *} msg] $msg } {1 {"-directory" cannot be used with "-path"}} test filename-11.45 {Tcl_GlobCmd on root volume} { set res1 "" set res2 "" catch { set res1 [glob -dir [lindex [file volumes] 0] -tails *] } catch { set tmpd [pwd] cd [lindex [file volumes] 0] set res2 [glob *] cd $tmpd } expr {$res1 == $res2} } {1} test filename-11.46 {Tcl_GlobCmd} { list [catch {glob -types abcde -dir foo *} msg] $msg } {1 {bad argument to "-types": abcde}} test filename-11.47 {Tcl_GlobCmd} { list [catch {glob -types abcde -path foo *} msg] $msg } {1 {bad argument to "-types": abcde}} test filename-11.48 {Tcl_GlobCmd} { list [catch {glob -types abcde -dir foo -join * *} msg] $msg } {1 {bad argument to "-types": abcde}} test filename-11.49 {Tcl_GlobCmd} { list [catch {glob -types abcde -path foo -join * *} msg] $msg } {1 {bad argument to "-types": abcde}} file rename $horribleglobname globTest set globname globTest unset horribleglobname test filename-12.1 {simple globbing} {unixOrPc} { list [catch {glob {}} msg] $msg } {0 .} test filename-12.1.1 {simple globbing} {unixOrPc} { list [catch {glob -types f {}} msg] $msg } {1 {no files matched glob pattern ""}} test filename-12.1.2 {simple globbing} {unixOrPc} { list [catch {glob -types d {}} msg] $msg } {0 .} test filename-12.1.3 {simple globbing} {unixOnly} { list [catch {glob -types hidden {}} msg] $msg } {0 .} test filename-12.1.4 {simple globbing} {pcOnly} { list [catch {glob -types hidden {}} msg] $msg } {1 {no files matched glob pattern ""}} test filename-12.1.5 {simple globbing} {pcOnly} { list [catch {glob -types hidden c:/} msg] $msg } {1 {no files matched glob pattern "c:/"}} test filename-12.1.6 {simple globbing} {pcOnly} { list [catch {glob c:/} msg] $msg } {0 c:/} test filename-12.3 {simple globbing} { list [catch {glob -nocomplain \{a1,a2\}} msg] $msg } {0 {}} set globPreResult globTest/ set x1 x1.c set y1 y1.c test filename-12.4 {simple globbing} {unixOrPc} { lsort [glob globTest/x1.c globTest/y1.c globTest/foo] } "$globPreResult$x1 $globPreResult$y1" test filename-12.5 {simple globbing} { list [catch {glob globTest\\/x1.c} msg] $msg } "0 $globPreResult$x1" test filename-12.6 {simple globbing} { list [catch {glob globTest\\/\\x1.c} msg] $msg } "0 $globPreResult$x1" test filename-12.7 {globbing at filesystem root} {unixOnly} { set res1 [glob -nocomplain /*] set res2 [glob -path / *] set equal [string equal $res1 $res2] if {!$equal} { lappend equal "not equal" $res1 $res2 } set equal } {1} test filename-12.8 {globbing at filesystem root} {unixOnly} { set dir [lindex [glob -type d /*] 0] set first [string range $dir 0 1] set res1 [glob -nocomplain ${first}*] set res2 [glob -path $first *] set equal [string equal $res1 $res2] if {!$equal} { lappend equal "not equal" $res1 $res2 } set equal } {1} test filename-12.9 {globbing at filesystem root} {winOnly} { # Can't grab just anything from 'file volumes' because we need a dir # that has subdirs - assume that C:/ exists across Windows machines. set dir [lindex [glob -type d C:/*] 0] set first [string range $dir 0 3] set res1 [glob -nocomplain ${first}*] set res2 [glob -path $first *] set equal [string equal $res1 $res2] if {!$equal} { lappend equal "not equal" $res1 $res2 } set equal } {1} test filename-13.1 {globbing with brace substitution} { list [catch {glob globTest/\{\}} msg] $msg } "0 $globPreResult" test filename-13.2 {globbing with brace substitution} { list [catch {glob globTest/\{} msg] $msg } {1 {unmatched open-brace in file name}} test filename-13.3 {globbing with brace substitution} { list [catch {glob globTest/\{\\\}} msg] $msg } {1 {unmatched open-brace in file name}} test filename-13.4 {globbing with brace substitution} { list [catch {glob globTest/\{\\} msg] $msg } {1 {unmatched open-brace in file name}} test filename-13.5 {globbing with brace substitution} { list [catch {glob globTest/\}} msg] $msg } {1 {unmatched close-brace in file name}} test filename-13.6 {globbing with brace substitution} { list [catch {glob globTest/\{\}x1.c} msg] $msg } "0 $globPreResult$x1" test filename-13.7 {globbing with brace substitution} { list [catch {glob globTest/\{x\}1.c} msg] $msg } "0 $globPreResult$x1" test filename-13.8 {globbing with brace substitution} { list [catch {glob globTest/\{x\{\}\}1.c} msg] $msg } "0 $globPreResult$x1" test filename-13.9 {globbing with brace substitution} { list [lsort [catch {glob globTest/\{x,y\}1.c} msg]] $msg } [list 0 [list $globPreResult$x1 $globPreResult$y1]] test filename-13.10 {globbing with brace substitution} { list [lsort [catch {glob globTest/\{x,,y\}1.c} msg]] $msg } [list 0 [list $globPreResult$x1 $globPreResult$y1]] test filename-13.11 {globbing with brace substitution} {unixOrPc} { list [lsort [catch {glob globTest/\{x,x\\,z,z\}1.c} msg]] $msg } {0 {globTest/x1.c globTest/x,z1.c globTest/z1.c}} test filename-13.13 {globbing with brace substitution} { lsort [glob globTest/{a,b,x,y}1.c] } [list $globPreResult$x1 $globPreResult$y1] test filename-13.14 {globbing with brace substitution} {unixOrPc} { lsort [glob {globTest/{x1,y2,weird name}.c}] } {{globTest/weird name.c} globTest/x1.c} test filename-13.16 {globbing with brace substitution} {unixOrPc} { lsort [glob globTest/{x1.c,a1/*}] } {globTest/a1/b1 globTest/a1/b2 globTest/x1.c} test filename-13.18 {globbing with brace substitution} {unixOrPc} { lsort [glob globTest/{x1.c,{a},a1/*}] } {globTest/a1/b1 globTest/a1/b2 globTest/x1.c} test filename-13.20 {globbing with brace substitution} {unixOrPc} { lsort [glob globTest/{a,x}1/*/{x,y}*] } {globTest/a1/b1/x2.c globTest/a1/b2/y2.c} test filename-13.22 {globbing with brace substitution} { list [catch {glob globTest/\{a,x\}1/*/\{} msg] $msg } {1 {unmatched open-brace in file name}} test filename-14.1 {asterisks, question marks, and brackets} {unixOrPc} { lsort [glob glo*/*.c] } {{globTest/weird name.c} globTest/x,z1.c globTest/x1.c globTest/y1.c globTest/z1.c} test filename-14.3 {asterisks, question marks, and brackets} {unixOrPc} { lsort [glob globTest/?1.c] } {globTest/x1.c globTest/y1.c globTest/z1.c} # The current directory could be anywhere; do this to stop spurious matches file mkdir globTestContext file rename globTest [file join globTestContext globTest] set savepwd [pwd] cd globTestContext test filename-14.5 {asterisks, question marks, and brackets} {unixOrPc} { lsort [glob */*/*/*.c] } {globTest/a1/b1/x2.c globTest/a1/b2/y2.c} # Reset to where we were cd $savepwd file rename [file join globTestContext globTest] globTest file delete globTestContext test filename-14.7 {asterisks, question marks, and brackets} {unixOnly} { lsort [glob globTest/*] } {globTest/a1 globTest/a2 globTest/a3 {globTest/weird name.c} globTest/x,z1.c globTest/x1.c globTest/y1.c globTest/z1.c} test filename-14.7.1 {asterisks, question marks, and brackets} {pcOnly} { lsort [glob globTest/*] } {globTest/.1 globTest/a1 globTest/a2 globTest/a3 {globTest/weird name.c} globTest/x,z1.c globTest/x1.c globTest/y1.c globTest/z1.c} test filename-14.9 {asterisks, question marks, and brackets} {unixOrPc} { lsort [glob globTest/.*] } {globTest/. globTest/.. globTest/.1} test filename-14.11 {asterisks, question marks, and brackets} {unixOrPc} { lsort [glob globTest/*/*] } {globTest/a1/b1 globTest/a1/b2 globTest/a2/b3} test filename-14.13 {asterisks, question marks, and brackets} {unixOrPc} { lsort [glob {globTest/[xyab]1.*}] } {globTest/x1.c globTest/y1.c} test filename-14.15 {asterisks, question marks, and brackets} {unixOrPc} { lsort [glob globTest/*/] } {globTest/a1/ globTest/a2/ globTest/a3/} test filename-14.17 {asterisks, question marks, and brackets} { global env set temp $env(HOME) set env(HOME) [file join $env(HOME) globTest] set result [list [catch {glob ~/z*} msg] $msg] set env(HOME) $temp set result } [list 0 [list [file join $env(HOME) globTest z1.c]]] test filename-14.18 {asterisks, question marks, and brackets} {unixOrPc} { list [catch {lsort [glob globTest/*.c goo/*]} msg] $msg } {0 {{globTest/weird name.c} globTest/x,z1.c globTest/x1.c globTest/y1.c globTest/z1.c}} test filename-14.20 {asterisks, question marks, and brackets} { list [catch {glob -nocomplain goo/*} msg] $msg } {0 {}} test filename-14.21 {asterisks, question marks, and brackets} { list [catch {glob globTest/*/gorp} msg] $msg } {1 {no files matched glob pattern "globTest/*/gorp"}} test filename-14.22 {asterisks, question marks, and brackets} { list [catch {glob goo/* x*z foo?q} msg] $msg } {1 {no files matched glob patterns "goo/* x*z foo?q"}} test filename-14.23 {slash globbing} {unixOrPc} { glob / } / test filename-14.24 {slash globbing} {pcOnly} { glob {\\} } / test filename-14.25 {type specific globbing} {unixOnly} { list [catch {lsort [glob -dir globTest -types f *]} msg] $msg } [list 0 [lsort [list \ [file join $globname "weird name.c"]\ [file join $globname x,z1.c]\ [file join $globname x1.c]\ [file join $globname y1.c] [file join $globname z1.c]]]] test filename-14.26 {type specific globbing} { list [catch {glob -nocomplain -dir globTest -types {readonly} *} msg] $msg } [list 0 {}] test filename-14.27 {Bug 2710920} {unixOrPc} { file tail [lindex [lsort [glob globTest/*/]] 0] } a1 test filename-14.28 {Bug 2710920} {unixOrPc} { file dirname [lindex [lsort [glob globTest/*/]] 0] } globTest test filename-14.29 {Bug 2710920} {unixOrPc} { file extension [lindex [lsort [glob globTest/*/]] 0] } {} test filename-14.30 {Bug 2710920} {unixOrPc} { file rootname [lindex [lsort [glob globTest/*/]] 0] } globTest/a1/ test filename-14.31 {Bug 2918610} -setup { set d [makeDirectory foo] makeFile {} bar.soom $d } -body { foreach fn [glob $d/bar.soom] { set root [file rootname $fn] close [open $root {WRONLY CREAT}] } llength [glob -directory $d *] } -cleanup { file delete -force $d/bar removeFile bar.soom $d removeDirectory foo } -result 2 unset globname # The following tests are only valid for Unix systems. # On some systems, like AFS, "000" protection doesn't prevent # access by owner, so the following test is not portable. catch {file attributes globTest/a1 -permissions 0000} test filename-15.1 {unix specific globbing} {unixOnly nonPortable} { string tolower [list [catch {glob globTest/a1/*} msg] $msg $errorCode] } {1 {couldn't read directory "globtest/a1": permission denied} {posix eacces {permission denied}}} test filename-15.2 {unix specific no complain: no errors} {unixOnly nonPortable} { glob -nocomplain globTest/a1/* } {} test filename-15.3 {unix specific no complain: no errors, good result} \ {unixOnly nonPortable} { # test fails because if an error occur , the interp's result # is reset... glob -nocomplain globTest/a2 globTest/a1/* globTest/a3 } {globTest/a2 globTest/a3} catch {file attributes globTest/a1 -permissions 0755} test filename-15.4 {unix specific no complain: no errors, good result} \ {unixOnly nonPortable} { # test fails because if an error occurs, the interp's result # is reset... or you don't run at scriptics where the # outser and welch users exists glob -nocomplain ~ouster ~foo ~welch } {/home/ouster /home/welch} test filename-15.4.1 {no complain: no errors, good result} { # test used to fail because if an error occurs, the interp's result # is reset... string equal [glob -nocomplain ~wontexist ~blah ~] \ [glob -nocomplain ~ ~blah ~wontexist] } {1} test filename-15.5 {unix specific globbing} {unixOnly nonPortable} { glob ~ouster/.csh* } "/home/ouster/.cshrc" catch {close [open globTest/odd\\\[\]*?\{\}name w]} test filename-15.6 {unix specific globbing} {unixOnly} { global env set temp $env(HOME) set env(HOME) $env(HOME)/globTest/odd\\\[\]*?\{\}name set result [list [catch {glob ~} msg] $msg] set env(HOME) $temp set result } [list 0 [list [lindex [glob ~] 0]/globTest/odd\\\[\]*?\{\}name]] catch {file delete -force globTest/odd\\\[\]*?\{\}name} # The following tests are only valid for Windows systems. set oldDir [pwd] if {$::tcltest::testConstraints(pcOnly)} { cd c:/ file delete -force globTest file mkdir globTest close [open globTest/x1.BAT w] close [open globTest/y1.Bat w] close [open globTest/z1.bat w] } test filename-16.1 {windows specific globbing} {pcOnly} { lsort [glob globTest/*.bat] } {globTest/x1.BAT globTest/y1.Bat globTest/z1.bat} test filename-16.2 {windows specific globbing} {pcOnly} { glob c: } c: test filename-16.3 {windows specific globbing} {pcOnly} { glob c:\\\\ } c:/ test filename-16.4 {windows specific globbing} {pcOnly} { glob c:/ } c:/ test filename-16.5 {windows specific globbing} {pcOnly} { glob c:*bTest } c:globTest test filename-16.6 {windows specific globbing} {pcOnly} { glob c:\\\\*bTest } c:/globTest test filename-16.7 {windows specific globbing} {pcOnly} { glob c:/*bTest } c:/globTest test filename-16.8 {windows specific globbing} {pcOnly} { lsort [glob c:globTest/*.bat] } {c:globTest/x1.BAT c:globTest/y1.Bat c:globTest/z1.bat} test filename-16.9 {windows specific globbing} {pcOnly} { lsort [glob c:/globTest/*.bat] } {c:/globTest/x1.BAT c:/globTest/y1.Bat c:/globTest/z1.bat} test filename-16.10 {windows specific globbing} {pcOnly} { lsort [glob c:globTest\\\\*.bat] } {c:globTest/x1.BAT c:globTest/y1.Bat c:globTest/z1.bat} test filename-16.11 {windows specific globbing} {pcOnly} { lsort [glob c:\\\\globTest\\\\*.bat] } {c:/globTest/x1.BAT c:/globTest/y1.Bat c:/globTest/z1.bat} # some tests require a shared C drive if {[catch {cd //[info hostname]/c}]} { set ::tcltest::testConstraints(sharedCdrive) 0 } else { set ::tcltest::testConstraints(sharedCdrive) 1 } test filename-16.12 {windows specific globbing} {pcOnly sharedCdrive} { cd //[info hostname]/c glob //[info hostname]/c/*Test } //[info hostname]/c/globTest test filename-16.13 {windows specific globbing} {pcOnly sharedCdrive} { cd //[info hostname]/c glob "\\\\\\\\[info hostname]\\\\c\\\\*Test" } //[info hostname]/c/globTest test filename-16.14 {windows specific globbing} {pcOnly} { cd [lindex [glob -types d -dir C:/ *] 0] expr {[lsearch -exact [glob {{.,*}*}] ".."] != -1} } {1} test filename-16.15 {windows specific globbing} {pcOnly} { cd [lindex [glob -types d -dir C:/ *] 0] glob .. } {..} test filename-16.16 {windows specific globbing} {pcOnly} { file tail [lindex [glob "[lindex [glob -types d -dir C:/ *] 0]/.."] 0] } {..} test filename-17.1 {windows specific special files} {testsetplatform} { testsetplatform win list [file pathtype com1] [file pathtype con] [file pathtype lpt3] \ [file pathtype prn] [file pathtype nul] [file pathtype aux] \ [file pathtype foo] } {absolute absolute absolute absolute absolute absolute relative} test filename-17.2 {windows specific glob with executable} {winOnly} { makeDirectory execglob makeFile contents execglob/abc.exe makeFile contents execglob/abc.notexecutable set res [glob -nocomplain -dir [temporaryDirectory]/execglob \ -tails -types x *] removeFile execglob/abc.exe removeFile execglob/abc.notexecutable removeDirectory execglob set res } {abc.exe} test filename-17.3 {Bug 2571597} win { set p /a file pathtype $p file normalize $p file pathtype $p } volumerelative test fileName-18.1 {windows - split ADS name correctly} {winOnly} { # bug 1194458 set x [file split c:/c:d] set y [eval [linsert $x 0 file join]] list $x $y } {{c:/ ./c:d} c:/c:d} test fileName-20.1 {Bug 1750300} -setup { set d [makeDirectory foo] makeFile {} TAGS $d } -body { llength [glob -nocomplain -directory $d -- TAGS one two] } -cleanup { removeFile TAGS $d removeDirectory foo } -result 1 test fileName-20.2 {Bug 1750300} -setup { set d [makeDirectory foo] makeFile {} TAGS $d } -body { llength [glob -nocomplain -directory $d -types {} -- TAGS one two] } -cleanup { removeFile TAGS $d removeDirectory foo } -result 1 test fileName-20.3 {Bug 1750300} -setup { set d [makeDirectory foo] makeFile {} TAGS $d } -body { llength [glob -nocomplain -directory $d -types {} -- *U*] } -cleanup { removeFile TAGS $d removeDirectory foo } -result 0 test fileName-20.4 {Bug 1750300} -setup { set d [makeDirectory foo] makeFile {} TAGS $d } -body { llength [glob -nocomplain -directory $d -types {} -- URGENT Urkle] } -cleanup { removeFile TAGS $d removeDirectory foo } -result 0 test fileName-20.5 {Bug 2837800} -setup { set dd [makeDirectory isolate] set d [makeDirectory ./~foo $dd] makeFile {} test $d set savewd [pwd] cd $dd } -body { glob -nocomplain */test } -cleanup { cd $savewd removeFile test $d removeDirectory ./~foo $dd removeDirectory isolate } -result ~foo/test test fileName-20.6 {Bug 2837800} -setup { # Recall that we have $env(HOME) set so that references # to ~ point to [temporaryDirectory] makeFile {} test ~ set dd [makeDirectory isolate] set d [makeDirectory ./~ $dd] set savewd [pwd] cd $dd } -body { glob -nocomplain */test } -cleanup { cd $savewd removeDirectory ./~ $dd removeDirectory isolate removeFile test ~ } -result {} test fileName-20.7 {Bug 2806250} -setup { set d [makeDirectory isolate] makeFile {} ./~test $d } -body { file exists [lindex [glob -nocomplain isolate/*] 0] } -cleanup { removeFile ./~test $d removeDirectory isolate } -result 1 test fileName-20.8 {Bug 2806250} -setup { set d [makeDirectory isolate] makeFile {} ./~test $d } -body { file tail [lindex [glob -nocomplain isolate/*] 0] } -cleanup { removeFile ./~test $d removeDirectory isolate } -result ./~test test fileName-20.9 {} -setup { makeFile {} test ~ set d [makeDirectory isolate] set savewd [pwd] cd $d } -body { glob -nocomplain -directory ~ test } -cleanup { cd $savewd removeDirectory isolate removeFile test ~ } -result [file normalize ~/test] # The normalized result here is arguably buggy, but consistent # with (some?) 8.4.* releases. test fileName-20.10 {} -setup { set s [makeDirectory sub ~] makeFile {} fileName-20.10 $s set d [makeDirectory isolate] set savewd [pwd] cd $d } -body { glob -nocomplain -directory ~ -join * fileName-20.10 } -cleanup { cd $savewd removeDirectory isolate removeFile fileName-20.10 $s removeDirectory sub ~ } -result [file normalize ~/sub/fileName-20.10] # The normalized result here is arguably buggy, but consistent # with (some?) 8.4.* releases. # cleanup catch {file delete -force C:/globTest} cd [temporaryDirectory] file delete -force globTest cd $oldpwd set env(HOME) $oldhome if {[tcltest::testConstraint testsetplatform]} { testsetplatform $platform catch {unset platform} } catch {unset oldhome temp result globPreResult} ::tcltest::cleanupTests return tcl8.4.20/tests/lindex.test0000644003604700454610000002750411737050674014255 0ustar dgp771div# Commands covered: lindex # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # Copyright (c) 2001 by Kevin B. Kenny. All rights reserved. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } set lindex lindex set minus - # Tests of Tcl_LindexObjCmd, NOT COMPILED test lindex-1.1 {wrong # args} { list [catch {eval $lindex} result] $result } "1 {wrong # args: should be \"lindex list ?index...?\"}" # Indices that are lists or convertible to lists test lindex-2.1 {empty index list} { set x {} list [eval [list $lindex {a b c} $x]] [eval [list $lindex {a b c} $x]] } {{a b c} {a b c}} test lindex-2.2 {singleton index list} { set x { 1 } list [eval [list $lindex {a b c} $x]] [eval [list $lindex {a b c} $x]] } {b b} test lindex-2.3 {multiple indices in list} { set x {1 2} list [eval [list $lindex {{a b c} {d e f}} $x]] \ [eval [list $lindex {{a b c} {d e f}} $x]] } {f f} test lindex-2.4 {malformed index list} { set x \{ list [catch { eval [list $lindex {a b c} $x] } result] $result } {1 bad\ index\ \"\{\":\ must\ be\ integer\ or\ end?-integer?} # Indices that are integers or convertible to integers test lindex-3.1 {integer -1} { set x ${minus}1 list [eval [list $lindex {a b c} $x]] [eval [list $lindex {a b c} $x]] } {{} {}} test lindex-3.2 {integer 0} { set x [string range 00 0 0] list [eval [list $lindex {a b c} $x]] [eval [list $lindex {a b c} $x]] } {a a} test lindex-3.3 {integer 2} { set x [string range 22 0 0] list [eval [list $lindex {a b c} $x]] [eval [list $lindex {a b c} $x]] } {c c} test lindex-3.4 {integer 3} { set x [string range 33 0 0] list [eval [list $lindex {a b c} $x]] [eval [list $lindex {a b c} $x]] } {{} {}} test lindex-3.5 {bad octal} { set x 08 list [catch { eval [list $lindex {a b c} $x] } result] $result } "1 {bad index \"08\": must be integer or end?-integer? (looks like invalid octal number)}" test lindex-3.6 {bad octal} { set x -09 list [catch { eval [list $lindex {a b c} $x] } result] $result } "1 {bad index \"-09\": must be integer or end?-integer? (looks like invalid octal number)}" test lindex-3.7 {indexes don't shimmer wide ints} { set x [expr {(wide(1)<<31) - 2}] list $x [lindex {1 2 3} $x] [incr x] [incr x] } {2147483646 {} 2147483647 2147483648} # Indices relative to end test lindex-4.1 {index = end} { set x end list [eval [list $lindex {a b c} $x]] [eval [list $lindex {a b c} $x]] } {c c} test lindex-4.2 {index = end--1} { set x end--1 list [eval [list $lindex {a b c} $x]] [eval [list $lindex {a b c} $x]] } {{} {}} test lindex-4.3 {index = end-0} { set x end-0 list [eval [list $lindex {a b c} $x]] [eval [list $lindex {a b c} $x]] } {c c} test lindex-4.4 {index = end-2} { set x end-2 list [eval [list $lindex {a b c} $x]] [eval [list $lindex {a b c} $x]] } {a a} test lindex-4.5 {index = end-3} { set x end-3 list [eval [list $lindex {a b c} $x]] [eval [list $lindex {a b c} $x]] } {{} {}} test lindex-4.6 {bad octal} { set x end-08 list [catch { eval [list $lindex {a b c} $x] } result] $result } "1 {bad index \"end-08\": must be integer or end?-integer? (looks like invalid octal number)}" test lindex-4.7 {bad octal} { set x end--09 list [catch { eval [list $lindex {a b c} $x] } result] $result } "1 {bad index \"end--09\": must be integer or end?-integer?}" test lindex-4.8 {bad integer, not octal} { set x end-0a2 list [catch { eval [list $lindex {a b c} $x] } result] $result } "1 {bad index \"end-0a2\": must be integer or end?-integer?}" test lindex-4.9 {incomplete end} { set x en list [eval [list $lindex {a b c} $x]] [eval [list $lindex {a b c} $x]] } {c c} test lindex-4.10 {incomplete end-} { set x end- list [catch { eval [list $lindex {a b c} $x] } result] $result } "1 {bad index \"end-\": must be integer or end?-integer?}" test lindex-5.1 {bad second index} { list [catch { eval [list $lindex {a b c} 0 0a2] } result] $result } "1 {bad index \"0a2\": must be integer or end?-integer?}" test lindex-5.2 {good second index} { eval [list $lindex {{a b c} {d e f} {g h i}} 1 2] } f test lindex-5.3 {three indices} { eval [list $lindex {{{a b} {c d}} {{e f} {g h}}} 1 0 1] } f test lindex-6.1 {error conditions in parsing list} { list [catch {eval [list $lindex "a \{" 2]} msg] $msg } {1 {unmatched open brace in list}} test lindex-6.2 {error conditions in parsing list} { list [catch {eval [list $lindex {a {b c}d e} 2]} msg] $msg } {1 {list element in braces followed by "d" instead of space}} test lindex-6.3 {error conditions in parsing list} { list [catch {eval [list $lindex {a "b c"def ghi} 2]} msg] $msg } {1 {list element in quotes followed by "def" instead of space}} test lindex-7.1 {quoted elements} { eval [list $lindex {a "b c" d} 1] } {b c} test lindex-7.2 {quoted elements} { eval [list $lindex {"{}" b c} 0] } {{}} test lindex-7.3 {quoted elements} { eval [list $lindex {ab "c d \" x" y} 1] } {c d " x} test lindex-7.4 {quoted elements} { lindex {a b {c d "e} {f g"}} 2 } {c d "e} test lindex-8.1 {data reuse} { set x 0 eval [list $lindex $x $x] } {0} test lindex-8.2 {data reuse} { set a 0 eval [list $lindex $a $a $a] } 0 test lindex-8.3 {data reuse} { set a 1 eval [list $lindex $a $a $a] } {} test lindex-8.4 {data reuse} { set x [list 0 0] eval [list $lindex $x $x] } {0} test lindex-8.5 {data reuse} { set x 0 eval [list $lindex $x [list $x $x]] } {0} test lindex-8.6 {data reuse} { set x [list 1 1] eval [list $lindex $x $x] } {} test lindex-8.7 {data reuse} { set x 1 eval [list lindex $x [list $x $x]] } {} #---------------------------------------------------------------------- # Compilation tests for lindex test lindex-9.1 {wrong # args} { list [catch {lindex} result] $result } "1 {wrong # args: should be \"lindex list ?index...?\"}" # Indices that are lists or convertible to lists test lindex-10.1 {empty index list} { set x {} catch { list [lindex {a b c} $x] [lindex {a b c} $x] } result set result } {{a b c} {a b c}} test lindex-10.2 {singleton index list} { set x { 1 } catch { list [lindex {a b c} $x] [lindex {a b c} $x] } result set result } {b b} test lindex-10.3 {multiple indices in list} { set x {1 2} catch { list [lindex {{a b c} {d e f}} $x] [lindex {{a b c} {d e f}} $x] } result set result } {f f} test lindex-10.4 {malformed index list} { set x \{ list [catch { lindex {a b c} $x } result] $result } {1 bad\ index\ \"\{\":\ must\ be\ integer\ or\ end?-integer?} # Indices that are integers or convertible to integers test lindex-11.1 {integer -1} { set x ${minus}1 catch { list [lindex {a b c} $x] [lindex {a b c} $x] } result set result } {{} {}} test lindex-11.2 {integer 0} { set x [string range 00 0 0] catch { list [lindex {a b c} $x] [lindex {a b c} $x] } result set result } {a a} test lindex-11.3 {integer 2} { set x [string range 22 0 0] catch { list [lindex {a b c} $x] [lindex {a b c} $x] } result set result } {c c} test lindex-11.4 {integer 3} { set x [string range 33 0 0] catch { list [lindex {a b c} $x] [lindex {a b c} $x] } result set result } {{} {}} test lindex-11.5 {bad octal} { set x 08 list [catch { lindex {a b c} $x } result] $result } "1 {bad index \"08\": must be integer or end?-integer? (looks like invalid octal number)}" test lindex-11.6 {bad octal} { set x -09 list [catch { lindex {a b c} $x } result] $result } "1 {bad index \"-09\": must be integer or end?-integer? (looks like invalid octal number)}" # Indices relative to end test lindex-12.1 {index = end} { set x end catch { list [lindex {a b c} $x] [lindex {a b c} $x] } result set result } {c c} test lindex-12.2 {index = end--1} { set x end--1 catch { list [lindex {a b c} $x] [lindex {a b c} $x] } result set result } {{} {}} test lindex-12.3 {index = end-0} { set x end-0 catch { list [lindex {a b c} $x] [lindex {a b c} $x] } result set result } {c c} test lindex-12.4 {index = end-2} { set x end-2 catch { list [lindex {a b c} $x] [lindex {a b c} $x] } result set result } {a a} test lindex-12.5 {index = end-3} { set x end-3 catch { list [lindex {a b c} $x] [lindex {a b c} $x] } result set result } {{} {}} test lindex-12.6 {bad octal} { set x end-08 list [catch { lindex {a b c} $x } result] $result } "1 {bad index \"end-08\": must be integer or end?-integer? (looks like invalid octal number)}" test lindex-12.7 {bad octal} { set x end--09 list [catch { lindex {a b c} $x } result] $result } "1 {bad index \"end--09\": must be integer or end?-integer?}" test lindex-12.8 {bad integer, not octal} { set x end-0a2 list [catch { lindex {a b c} $x } result] $result } "1 {bad index \"end-0a2\": must be integer or end?-integer?}" test lindex-12.9 {incomplete end} { set x en catch { list [lindex {a b c} $x] [lindex {a b c} $x] } result set result } {c c} test lindex-12.10 {incomplete end-} { set x end- list [catch { lindex {a b c} $x } result] $result } "1 {bad index \"end-\": must be integer or end?-integer?}" test lindex-13.1 {bad second index} { list [catch { lindex {a b c} 0 0a2 } result] $result } "1 {bad index \"0a2\": must be integer or end?-integer?}" test lindex-13.2 {good second index} { catch { lindex {{a b c} {d e f} {g h i}} 1 2 } result set result } f test lindex-13.3 {three indices} { catch { lindex {{{a b} {c d}} {{e f} {g h}}} 1 0 1 } result set result } f test lindex-14.1 {error conditions in parsing list} { list [catch { lindex "a \{" 2 } msg] $msg } {1 {unmatched open brace in list}} test lindex-14.2 {error conditions in parsing list} { list [catch { lindex {a {b c}d e} 2 } msg] $msg } {1 {list element in braces followed by "d" instead of space}} test lindex-14.3 {error conditions in parsing list} { list [catch { lindex {a "b c"def ghi} 2 } msg] $msg } {1 {list element in quotes followed by "def" instead of space}} test lindex-15.1 {quoted elements} { catch { lindex {a "b c" d} 1 } result set result } {b c} test lindex-15.2 {quoted elements} { catch { lindex {"{}" b c} 0 } result set result } {{}} test lindex-15.3 {quoted elements} { catch { lindex {ab "c d \" x" y} 1 } result set result } {c d " x} test lindex-15.4 {quoted elements} { catch { lindex {a b {c d "e} {f g"}} 2 } result set result } {c d "e} test lindex-16.1 {data reuse} { set x 0 catch { lindex $x $x } result set result } {0} test lindex-16.2 {data reuse} { set a 0 catch { lindex $a $a $a } result set result } 0 test lindex-16.3 {data reuse} { set a 1 catch { lindex $a $a $a } result set result } {} test lindex-16.4 {data reuse} { set x [list 0 0] catch { lindex $x $x } result set result } {0} test lindex-16.5 {data reuse} { set x 0 catch { lindex $x [list $x $x] } result set result } {0} test lindex-16.6 {data reuse} { set x [list 1 1] catch { lindex $x $x } result set result } {} test lindex-16.7 {data reuse} { set x 1 catch { lindex $x [list $x $x] } result set result } {} catch { unset lindex} catch { unset minus } # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/eval.test0000644003604700454610000000314511737050674013714 0ustar dgp771div# Commands covered: eval # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } test eval-1.1 {single argument} { eval {format 22} } 22 test eval-1.2 {multiple arguments} { set a {$b} set b xyzzy eval format $a } xyzzy test eval-1.3 {single argument} { eval concat a b c d e f g } {a b c d e f g} test eval-2.1 {error: not enough arguments} {catch eval} 1 test eval-2.2 {error: not enough arguments} { catch eval msg set msg } {wrong # args: should be "eval arg ?arg ...?"} test eval-2.3 {error in eval'ed command} { catch {eval {error "test error"}} } 1 test eval-2.4 {error in eval'ed command} { catch {eval {error "test error"}} msg set msg } {test error} test eval-2.5 {error in eval'ed command: setting errorInfo} { catch {eval { set a 1 error "test error" }} msg set errorInfo } "test error while executing \"error \"test error\"\" (\"eval\" body line 3) invoked from within \"eval { set a 1 error \"test error\" }\"" # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/unixInit.test0000644003604700454610000003074511737050674014602 0ustar dgp771div# The file tests the functions in the tclUnixInit.c file. # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1997 by Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. package require tcltest 2 namespace import -force ::tcltest::* unset -nocomplain path if {[info exists env(TCL_LIBRARY)]} { set oldlibrary $env(TCL_LIBRARY) unset env(TCL_LIBRARY) } catch {set oldlang $env(LANG)} set env(LANG) C test unixInit-1.1 {TclpInitPlatform: ignore SIGPIPE} {unixOnly stdio} { set x {} # Watch out for a race condition here. If tcltest is too slow to start # then we'll kill it before it has a chance to set up its signal handler. set f [open "|[list [interpreter]]" w+] puts $f "puts hi" flush $f gets $f exec kill -PIPE [pid $f] lappend x [catch {close $f}] set f [open "|[list [interpreter]]" w+] puts $f "puts hi" flush $f gets $f exec kill [pid $f] lappend x [catch {close $f}] set x } {0 1} # This test is really a test of code in tclUnixChan.c, but the # channels are set up as part of initialisation of the interpreter so # the test seems to me to fit here as well as anywhere else. test unixInit-1.2 {initialisation: standard channel type deduction} {unixOnly stdio} { # pipe1 is a connection to a server that reports what port it # starts on, and delivers a constant string to the first client to # connect to that port before exiting. set pipe1 [open "|[list [interpreter]]" r+] puts $pipe1 { proc accept {channel host port} { puts $channel {puts [fconfigure stdin -peername]; exit} close $channel exit } puts [fconfigure [socket -server accept 0] -sockname] vwait forever \ } # Note the backslash above; this is important to make sure that the # whole string is read before an [exit] can happen... flush $pipe1 set port [lindex [gets $pipe1] 2] set sock [socket localhost $port] # pipe2 is a connection to a Tcl interpreter that takes its orders # from the socket we hand it (i.e. the server we create above.) # These orders will tell it to print out the details about the # socket it is taking instructions from, hopefully identifying it # as a socket. Which is what this test is all about. set pipe2 [open "|[list [interpreter] <@$sock]" r] set result [gets $pipe2] # Clear any pending data; stops certain kinds of (non-important) errors fconfigure $pipe1 -blocking 0; gets $pipe1 fconfigure $pipe2 -blocking 0; gets $pipe2 # Close the pipes and the socket. close $pipe2 close $pipe1 catch {close $sock} # Can't use normal comparison, as hostname varies due to some # installations having a messed up /etc/hosts file. if { [string equal 127.0.0.1 [lindex $result 0]] && [string equal $port [lindex $result 2]] } then { subst "OK" } else { subst "Expected: `[list 127.0.0.1 localhost $port]', Got `$result'" } } {OK} proc getlibpath [list [list program [interpreter]]] { set f [open "|[list $program]" w+] fconfigure $f -buffering none puts $f {puts $tcl_libPath; exit} set path [gets $f] close $f return $path } # Some tests require the testgetdefenc command testConstraint testgetdefenc [llength [info commands testgetdefenc]] test unixInit-2.0 {TclpInitLibraryPath: setting tclDefaultEncodingDir} \ {unixOnly testgetdefenc} { set origDir [testgetdefenc] testsetdefenc slappy set path [testgetdefenc] testsetdefenc $origDir set path } {slappy} test unixInit-2.1 {TclpInitLibraryPath: value of installLib, developLib} \ {unixOnly stdio} { set path [getlibpath] set installLib lib/tcl[info tclversion] set developLib tcl[info patchlevel]/library set prefix [file dirname [file dirname [interpreter]]] set x {} lappend x [string compare [lindex $path 0] $prefix/$installLib] lappend x [string compare [lindex $path 4] [file dirname $prefix]/$developLib] set x } {0 0} test unixInit-2.2 {TclpInitLibraryPath: TCL_LIBRARY} {unixOnly stdio} { # ((str != NULL) && (str[0] != '\0')) set env(TCL_LIBRARY) sparkly set path [getlibpath] unset env(TCL_LIBRARY) lindex $path 0 } "sparkly" test unixInit-2.3 {TclpInitLibraryPath: TCL_LIBRARY wrong version} \ {unixOnly stdio} { # ((pathc > 0) && (strcasecmp(installLib + 4, pathv[pathc - 1]) != 0)) set env(TCL_LIBRARY) /a/b/tcl1.7 set path [getlibpath] unset env(TCL_LIBRARY) lrange $path 0 1 } [list /a/b/tcl1.7 /a/b/tcl[info tclversion]] test unixInit-2.4 {TclpInitLibraryPath: TCL_LIBRARY: INTL} \ {unixOnly stdio} { # Child process translates env variable from native encoding. set env(TCL_LIBRARY) "\xa7" set x [lindex [getlibpath] 0] unset env(TCL_LIBRARY) unset env(LANG) set x } "\xa7" test unixInit-2.5 {TclpInitLibraryPath: compiled-in library path} \ {emptyTest unixOnly} { # cannot test } {} test unixInit-2.6 {TclpInitLibraryPath: executable relative} \ {unixOnly stdio} { makeDirectory tmp makeDirectory [file join tmp sparkly] makeDirectory [file join tmp sparkly bin] file copy [interpreter] [file join [temporaryDirectory] tmp sparkly \ bin tcltest] makeDirectory [file join tmp sparkly lib] makeDirectory [file join tmp sparkly lib tcl[info tclversion]] makeFile {} [file join tmp sparkly lib tcl[info tclversion] init.tcl] set x [lrange [getlibpath [file join [temporaryDirectory] tmp sparkly \ bin tcltest]] 0 1] removeFile [file join tmp sparkly lib tcl[info tclversion] init.tcl] removeDirectory [file join tmp sparkly lib tcl[info tclversion]] removeDirectory [file join tmp sparkly lib] removeDirectory [file join tmp sparkly bin] removeDirectory [file join tmp sparkly] removeDirectory tmp set x } [list [temporaryDirectory]/tmp/sparkly/lib/tcl[info tclversion] [temporaryDirectory]/tmp/lib/tcl[info tclversion]] test unixInit-2.7 {TclpInitLibraryPath: compiled-in library path} \ {emptyTest unixOnly} { # would need test command to get defaultLibDir and compare it to # [lindex $auto_path end] } {} # # The following two tests write to the directory /tmp/sparkly instead # of to [temporaryDirectory]. This is because the failures tested by # these tests need paths near the "root" of the file system to present # themselves. # testConstraint noSparkly [expr {![file exists [file join /tmp sparkly]]}] testConstraint noTmpInstall [expr {![file exists \ [file join /tmp lib tcl[info tclversion]]]}] test unixInit-2.8 {TclpInitLibraryPath: all absolute pathtype} {unix noSparkly noTmpInstall} { # Checking for Bug 219416 # When a program that embeds the Tcl library, like tcltest, is # installed near the "root" of the file system, there was a problem # constructing directories relative to the executable. When a # relative ".." went past the root, relative path names were created # rather than absolute pathnames. In some cases, accessing past the # root caused memory access violations too. # # The bug is now fixed, but here we check for it by making sure that # the directories constructed relative to the executable are all # absolute pathnames, even when the executable is installed near # the root of the filesystem. # # The only directory near the root we are likely to have write access # to is /tmp. file delete -force /tmp/sparkly file delete -force /tmp/lib/tcl[info tclversion] file mkdir /tmp/sparkly file copy [interpreter] /tmp/sparkly/tcltest # Keep any existing /tmp/lib directory set deletelib 1 if {[file exists /tmp/lib]} { if {[file isdirectory /tmp/lib]} { set deletelib 0 } else { file delete -force /tmp/lib } } # For a successful Tcl_Init, we need a [source]-able init.tcl in # ../lib/tcl$version relative to the executable. file mkdir /tmp/lib/tcl[info tclversion] close [open /tmp/lib/tcl[info tclversion]/init.tcl w] # Check that all directories in the library path are absolute pathnames set allAbsolute 1 foreach dir [getlibpath /tmp/sparkly/tcltest] { set allAbsolute [expr {$allAbsolute \ && [string equal absolute [file pathtype $dir]]}] } # Clean up temporary installation file delete -force /tmp/sparkly file delete -force /tmp/lib/tcl[info tclversion] if {$deletelib} {file delete -force /tmp/lib} set allAbsolute } 1 testConstraint noTmpBuild [expr {![file exists [file join /tmp library]]}] test unixInit-2.9 {TclpInitLibraryPath: paths relative to executable} {unix noSparkly noTmpBuild} { # Checking for Bug 438014 file delete -force /tmp/sparkly file delete -force /tmp/library file mkdir /tmp/sparkly file copy [interpreter] /tmp/sparkly/tcltest file mkdir /tmp/library/ close [open /tmp/library/init.tcl w] set x [lrange [getlibpath /tmp/sparkly/tcltest] 0 4] file delete -force /tmp/sparkly file delete -force /tmp/library set x } [list /tmp/lib/tcl[info tclversion] /lib/tcl[info tclversion] \ /tmp/library /library /tcl[info patchlevel]/library] test unixInit-2.10 {TclpInitLibraryPath: executable relative} -constraints { unixOnly stdio } -setup { set tmpDir [makeDirectory tmp] set sparklyDir [makeDirectory sparkly $tmpDir] set execPath [file join [makeDirectory bin $sparklyDir] tcltest] file copy [interpreter] $execPath set libDir [makeDirectory lib $sparklyDir] set scriptDir [makeDirectory tcl[info tclversion] $libDir] makeFile {} init.tcl $scriptDir set saveDir [pwd] cd $libDir } -body { # Checking for Bug 832657 set x [lrange [getlibpath [file join .. bin tcltest]] 2 3] foreach p $x { lappend y [file normalize $p] } set y } -cleanup { cd $saveDir unset saveDir removeFile init.tcl $scriptDir unset scriptDir removeDirectory tcl[info tclversion] $libDir unset libDir file delete $execPath unset execPath removeDirectory bin $sparklyDir removeDirectory lib $sparklyDir unset sparklyDir removeDirectory sparkly $tmpDir unset tmpDir removeDirectory tmp unset x p y } -result [list [file join [temporaryDirectory] tmp sparkly library] \ [file join [temporaryDirectory] tmp library] ] test unixInit-3.1 {TclpSetInitialEncodings} -constraints { unixOnly stdio } -body { set env(LANG) C set f [open "|[list [interpreter]]" w+] fconfigure $f -buffering none puts $f {puts [encoding system]; exit} set enc [gets $f] close $f unset env(LANG) set enc } -match regexp -result [expr { ($tcl_platform(os) eq "Darwin") ? "^utf-8$" : "^iso8859-15?$"}] test unixInit-3.2 {TclpSetInitialEncodings} {unixOnly stdio} { set env(LANG) japanese catch {set oldlc_all $env(LC_ALL)} set env(LC_ALL) japanese set f [open "|[list [interpreter]]" w+] fconfigure $f -buffering none puts $f {puts [encoding system]; exit} set enc [gets $f] close $f unset env(LANG) unset env(LC_ALL) catch {set env(LC_ALL) $oldlc_all} set validEncodings [list euc-jp] if {[string match HP-UX $tcl_platform(os)]} { # Some older HP-UX systems need us to accept this as valid # Bug 453883 reports that newer HP-UX systems report euc-jp # like everybody else. lappend validEncodings shiftjis } expr {[lsearch -exact $validEncodings $enc] < 0} } 0 test unixInit-4.1 {TclpSetVariables} {unixOnly} { # just make sure they exist set a [list $tcl_library $tcl_pkgPath $tcl_platform(os)] set a [list $tcl_platform(osVersion) $tcl_platform(machine)] set tcl_platform(platform) } "unix" test unixInit-5.1 {Tcl_Init} {emptyTest unixOnly} { # test initScript } {} test unixInit-6.1 {Tcl_SourceRCFile} {emptyTest unixOnly} { } {} test unixInit-7.1 {closed standard channel: Bug 772288} -constraints { unixOnly stdio } -body { set tclsh [interpreter] set crash [makeFile {puts [open /dev/null]} crash.tcl] set crashtest [makeFile " close stdin [list exec $tclsh $crash] " crashtest.tcl] exec $tclsh $crashtest } -cleanup { removeFile crash.tcl removeFile crashtest.tcl } -returnCodes 0 # cleanup if {[info exists oldlibrary]} { set env(TCL_LIBRARY) $oldlibrary } catch {unset env(LANG)} catch {set env(LANG) $oldlang} unset -nocomplain path ::tcltest::cleanupTests return tcl8.4.20/tests/llength.test0000644003604700454610000000240511737050674014420 0ustar dgp771div# Commands covered: llength # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } test llength-1.1 {length of list} { llength {a b c d} } 4 test llength-1.2 {length of list} { llength {a b c {a b {c d}} d} } 5 test llength-1.3 {length of list} { llength {} } 0 test llength-2.1 {error conditions} { list [catch {llength} msg] $msg } {1 {wrong # args: should be "llength list"}} test llength-2.2 {error conditions} { list [catch {llength 123 2} msg] $msg } {1 {wrong # args: should be "llength list"}} test llength-2.3 {error conditions} { list [catch {llength "a b c \{"} msg] $msg } {1 {unmatched open brace in list}} # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/unixNotfy.test0000644003604700454610000000630211737050674014766 0ustar dgp771div# This file contains tests for tclUnixNotfy.c. # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1997 by Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # The tests should not be run if you have a notifier which is unable to # detect infinite vwaits, as the tests below will hang. The presence of # the "testthread" command indicates that this is the case. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import -force ::tcltest::* } if {[info exists tk_version]} { puts "When run in a Tk shell, these tests run hang. Skipping tests ..." ::tcltest::cleanupTests return } set ::tcltest::testConstraints(testthread) \ [expr {[info commands testthread] != {}}] # Darwin always uses a threaded notifier testConstraint unthreaded [expr { (![info exist tcl_platform(threaded)] || !$tcl_platform(threaded)) && $tcl_platform(os) ne "Darwin" }] # The next two tests will hang if threads are enabled because the notifier # will not necessarily wait for ever in this case, so it does not generate # an error. test unixNotfy-1.1 {Tcl_DeleteFileHandler} \ -constraints {unixOnly && unthreaded} \ -body { catch {vwait x} set f [open [makeFile "" foo] w] fileevent $f writable {set x 1} vwait x close $f list [catch {vwait x} msg] $msg } \ -result {1 {can't wait for variable "x": would wait forever}} \ -cleanup { catch { close $f } catch { removeFile foo } } test unixNotfy-1.2 {Tcl_DeleteFileHandler} \ -constraints {unixOnly && unthreaded} \ -body { catch {vwait x} set f1 [open [makeFile "" foo] w] set f2 [open [makeFile "" foo2] w] fileevent $f1 writable {set x 1} fileevent $f2 writable {set y 1} vwait x close $f1 vwait y close $f2 list [catch {vwait x} msg] $msg } \ -result {1 {can't wait for variable "x": would wait forever}} \ -cleanup { catch { close $f1 } catch { close $f2 } catch { removeFile foo } catch { removeFile foo2 } } test unixNotfy-2.1 {Tcl_DeleteFileHandler} \ -constraints {unixOnly testthread} \ -body { update set f [open [makeFile "" foo] w] fileevent $f writable {set x 1} vwait x close $f testthread create "testthread send [testthread id] {set x ok}" vwait x threadReap set x } \ -result {ok} \ -cleanup { catch { close $f } catch { removeFile foo } } test unixNotfy-2.2 {Tcl_DeleteFileHandler} \ -constraints {unixOnly testthread} \ -body { update set f1 [open [makeFile "" foo] w] set f2 [open [makeFile "" foo2] w] fileevent $f1 writable {set x 1} fileevent $f2 writable {set y 1} vwait x close $f1 vwait y close $f2 testthread create "testthread send [testthread id] {set x ok}" vwait x threadReap set x } \ -result {ok} \ -cleanup { catch { close $f1 } catch { close $f2 } catch { removeFile foo } catch { removeFile foo2 } } # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/var.test0000644003604700454610000005600711737050674013562 0ustar dgp771div# This file contains tests for the tclVar.c source file. Tests appear in # the same order as the C code that they test. The set of tests is # currently incomplete since it currently includes only new tests for # code changed for the addition of Tcl namespaces. Other variable- # related tests appear in several other test files including # namespace.test, set.test, trace.test, and upvar.test. # # Sourcing this file into Tcl runs the tests and generates output for # errors. No output means no errors were found. # # Copyright (c) 1997 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2.2 namespace import -force ::tcltest::* } catch {rename p ""} catch {namespace delete test_ns_var} catch {unset xx} catch {unset x} catch {unset y} catch {unset i} catch {unset a} catch {unset arr} test var-1.1 {TclLookupVar, Array handling} { catch {unset a} set x "incr" ;# force no compilation and runtime call to Tcl_IncrCmd set i 10 set arr(foo) 37 list [$x i] $i [$x arr(foo)] $arr(foo) } {11 11 38 38} test var-1.2 {TclLookupVar, TCL_GLOBAL_ONLY implies global namespace var} { set x "global value" namespace eval test_ns_var { variable x "namespace value" proc p {} { global x ;# specifies TCL_GLOBAL_ONLY to get global x return $x } } test_ns_var::p } {global value} test var-1.3 {TclLookupVar, TCL_NAMESPACE_ONLY implies namespace var} { namespace eval test_ns_var { proc q {} { variable x ;# specifies TCL_NAMESPACE_ONLY to get namespace x return $x } } test_ns_var::q } {namespace value} test var-1.4 {TclLookupVar, no active call frame implies global namespace var} { set x } {global value} test var-1.5 {TclLookupVar, active call frame pushed for namespace eval implies namespace var} { namespace eval test_ns_var {set x} } {namespace value} test var-1.6 {TclLookupVar, name starts with :: implies some namespace var} { namespace eval test_ns_var {set ::x} } {global value} test var-1.7 {TclLookupVar, error finding namespace var} { list [catch {set a:::b} msg] $msg } {1 {can't read "a:::b": no such variable}} test var-1.8 {TclLookupVar, error finding namespace var} { list [catch {set ::foobarfoo} msg] $msg } {1 {can't read "::foobarfoo": no such variable}} test var-1.9 {TclLookupVar, create new namespace var} { namespace eval test_ns_var { set v hello } } {hello} test var-1.10 {TclLookupVar, create new namespace var} { catch {unset y} namespace eval test_ns_var { set ::y 789 } set y } {789} test var-1.11 {TclLookupVar, error creating new namespace var} { namespace eval test_ns_var { list [catch {set ::test_ns_var::foo::bar 314159} msg] $msg } } {1 {can't set "::test_ns_var::foo::bar": parent namespace doesn't exist}} test var-1.12 {TclLookupVar, error creating new namespace var} { namespace eval test_ns_var { list [catch {set ::test_ns_var::foo:: 1997} msg] $msg } } {1 {can't set "::test_ns_var::foo::": parent namespace doesn't exist}} test var-1.13 {TclLookupVar, new namespace var is created in a particular namespace} { catch {unset aNeWnAmEiNnS} namespace eval test_ns_var { namespace eval test_ns_var2::test_ns_var3 { set aNeWnAmEiNnS 77777 } # namespace which builds a name by traversing nsPtr chain to :: namespace which -variable test_ns_var2::test_ns_var3::aNeWnAmEiNnS } } {::test_ns_var::test_ns_var2::test_ns_var3::aNeWnAmEiNnS} test var-1.14 {TclLookupVar, namespace code ignores ":"s in middle and end of var names} { namespace eval test_ns_var { set : 123 set v: 456 set x:y: 789 list [set :] [set v:] [set x:y:] \ ${:} ${v:} ${x:y:} \ [expr {[lsearch [info vars] :] != -1}] \ [expr {[lsearch [info vars] v:] != -1}] \ [expr {[lsearch [info vars] x:y:] != -1}] } } {123 456 789 123 456 789 1 1 1} test var-1.15 {TclLookupVar, resurrect variable via upvar to deleted namespace: compiled code path} { namespace eval test_ns_var { variable foo 2 } proc p {} { variable ::test_ns_var::foo lappend result [catch {set foo} msg] $msg namespace delete ::test_ns_var lappend result [catch {set foo 3} msg] $msg lappend result [catch {set foo(3) 3} msg] $msg } p } {0 2 1 {can't set "foo": upvar refers to variable in deleted namespace} 1 {can't set "foo(3)": upvar refers to variable in deleted namespace}} test var-1.16 {TclLookupVar, resurrect variable via upvar to deleted namespace: uncompiled code path} { namespace eval test_ns_var { variable result namespace eval subns { variable foo 2 } upvar 0 subns::foo foo lappend result [catch {set foo} msg] $msg namespace delete subns lappend result [catch {set foo 3} msg] $msg lappend result [catch {set foo(3) 3} msg] $msg namespace delete [namespace current] set result } } {0 2 1 {can't set "foo": upvar refers to variable in deleted namespace} 1 {can't set "foo(3)": upvar refers to variable in deleted namespace}} test var-1.17 {TclLookupVar, resurrect array element via upvar to deleted array: compiled code path} { namespace eval test_ns_var { variable result proc p {} { array set x {1 2 3 4} upvar 0 x(1) foo lappend result [catch {set foo} msg] $msg unset x lappend result [catch {set foo 3} msg] $msg } set result [p] namespace delete [namespace current] set result } } {0 2 1 {can't set "foo": upvar refers to element in deleted array}} test var-1.18 {TclLookupVar, resurrect array element via upvar to deleted array: uncompiled code path} { namespace eval test_ns_var { variable result {} variable x array set x {1 2 3 4} upvar 0 x(1) foo lappend result [catch {set foo} msg] $msg unset x lappend result [catch {set foo 3} msg] $msg namespace delete [namespace current] set result } } {0 2 1 {can't set "foo": upvar refers to element in deleted array}} test var-1.19 {TclLookupVar, right error message when parsing variable name} { list [catch {[format set] thisvar(doesntexist)} msg] $msg } {1 {can't read "thisvar(doesntexist)": no such variable}} test var-2.1 {Tcl_LappendObjCmd, create var if new} { catch {unset x} lappend x 1 2 } {1 2} test var-3.1 {MakeUpvar, TCL_NAMESPACE_ONLY not specified for other var} { catch {unset x} set x 1997 proc p {} { global x ;# calls MakeUpvar with TCL_NAMESPACE_ONLY for other var x return $x } p } {1997} test var-3.2 {MakeUpvar, other var has TCL_NAMESPACE_ONLY specified} { namespace eval test_ns_var { catch {unset v} variable v 1998 proc p {} { variable v ;# TCL_NAMESPACE_ONLY specified for other var x return $v } p } } {1998} if {[info commands testupvar] != {}} { test var-3.3 {MakeUpvar, my var has TCL_GLOBAL_ONLY specified} { catch {unset a} set a 123321 proc p {} { # create global xx linked to global a testupvar 1 a {} xx global } list [p] $xx [set xx 789] $a } {{} 123321 789 789} test var-3.4 {MakeUpvar, my var has TCL_NAMESPACE_ONLY specified} { catch {unset a} set a 456 namespace eval test_ns_var { catch {unset ::test_ns_var::vv} proc p {} { # create namespace var vv linked to global a testupvar 1 a {} vv namespace } p } list $test_ns_var::vv [set test_ns_var::vv 123] $a } {456 123 123} } test var-3.5 {MakeUpvar, no call frame so my var will be in global :: ns} { catch {unset aaaaa} catch {unset xxxxx} set aaaaa 77777 upvar #0 aaaaa xxxxx list [set xxxxx] [set aaaaa] } {77777 77777} test var-3.6 {MakeUpvar, active call frame pushed for namespace eval} { catch {unset a} set a 121212 namespace eval test_ns_var { upvar ::a vvv set vvv } } {121212} test var-3.7 {MakeUpvar, my var has ::s} { catch {unset a} set a 789789 upvar #0 a test_ns_var::lnk namespace eval test_ns_var { set lnk } } {789789} test var-3.8 {MakeUpvar, my var already exists in global ns} { catch {unset aaaaa} catch {unset xxxxx} set aaaaa 456654 set xxxxx hello upvar #0 aaaaa xxxxx set xxxxx } {hello} test var-3.9 {MakeUpvar, my var has invalid ns name} { catch {unset aaaaa} set aaaaa 789789 list [catch {upvar #0 aaaaa test_ns_fred::lnk} msg] $msg } {1 {can't create "test_ns_fred::lnk": parent namespace doesn't exist}} test var-3.10 {MakeUpvar, } { namespace eval {} { set bar 0 namespace eval foo upvar bar bar set foo::bar 1 catch {list $bar $foo::bar} msg unset ::aaaaa set msg } } {1 1} if {[info commands testgetvarfullname] != {}} { test var-4.1 {Tcl_GetVariableName, global variable} { catch {unset a} set a 123 testgetvarfullname a global } ::a test var-4.2 {Tcl_GetVariableName, namespace variable} { namespace eval test_ns_var { variable george testgetvarfullname george namespace } } ::test_ns_var::george test var-4.3 {Tcl_GetVariableName, variable can't be array element} { catch {unset a} set a(1) foo list [catch {testgetvarfullname a(1) global} msg] $msg } {1 {unknown variable "a(1)"}} } test var-5.1 {Tcl_GetVariableFullName, global variable} { catch {unset a} set a bar namespace which -variable a } {::a} test var-5.2 {Tcl_GetVariableFullName, namespace variable} { namespace eval test_ns_var { variable martha namespace which -variable martha } } {::test_ns_var::martha} test var-5.3 {Tcl_GetVariableFullName, namespace variable} { namespace which -variable test_ns_var::martha } {::test_ns_var::martha} test var-6.1 {Tcl_GlobalObjCmd, variable is qualified by a namespace name} { namespace eval test_ns_var { variable boeing 777 } proc p {} { global ::test_ns_var::boeing set boeing } p } {777} test var-6.2 {Tcl_GlobalObjCmd, variable is qualified by a namespace name} { namespace eval test_ns_var { namespace eval test_ns_nested { variable java java } proc p {} { global ::test_ns_var::test_ns_nested::java set java } } test_ns_var::p } {java} test var-6.3 {Tcl_GlobalObjCmd, variable named {} qualified by a namespace name} { set ::test_ns_var::test_ns_nested:: 24 proc p {} { global ::test_ns_var::test_ns_nested:: set {} } p } {24} test var-6.4 {Tcl_GlobalObjCmd, variable name matching :*} { # Test for Tcl Bug 480176 set :v broken proc p {} { global :v set :v fixed } p set :v } {fixed} test var-7.1 {Tcl_VariableObjCmd, create and initialize one new ns variable} { catch {namespace delete test_ns_var} namespace eval test_ns_var { variable one 1 } list [info vars test_ns_var::*] [set test_ns_var::one] } {::test_ns_var::one 1} test var-7.2 {Tcl_VariableObjCmd, if new and no value, leave undefined} { set two 2222222 namespace eval test_ns_var { variable two } list [info exists test_ns_var::two] [catch {set test_ns_var::two} msg] $msg } {0 1 {can't read "test_ns_var::two": no such variable}} test var-7.3 {Tcl_VariableObjCmd, "define" var already created above} { namespace eval test_ns_var { variable two 2 } list [lsort [info vars test_ns_var::*]] \ [namespace eval test_ns_var {set two}] } [list [lsort {::test_ns_var::two ::test_ns_var::one}] 2] test var-7.4 {Tcl_VariableObjCmd, list of vars} { namespace eval test_ns_var { variable three 3 four 4 } list [lsort [info vars test_ns_var::*]] \ [namespace eval test_ns_var {expr $three+$four}] } [list [lsort {::test_ns_var::four ::test_ns_var::three ::test_ns_var::two ::test_ns_var::one}] 7] test var-7.5 {Tcl_VariableObjCmd, value for last var is optional} { catch {unset a} catch {unset five} catch {unset six} set a "" set five 555 set six 666 namespace eval test_ns_var { variable five 5 six lappend a $five } lappend a $test_ns_var::five \ [set test_ns_var::six 6] [set test_ns_var::six] $six catch {unset five} catch {unset six} set a } {5 5 6 6 666} catch {unset newvar} test var-7.6 {Tcl_VariableObjCmd, variable name can be qualified} { namespace eval test_ns_var { variable ::newvar cheers! } set newvar } {cheers!} catch {unset newvar} test var-7.7 {Tcl_VariableObjCmd, bad var name} { namespace eval test_ns_var { list [catch {variable sev:::en 7} msg] $msg } } {1 {can't define "sev:::en": parent namespace doesn't exist}} test var-7.8 {Tcl_VariableObjCmd, if var already exists and no value is given, leave value unchanged} { set a "" namespace eval test_ns_var { variable eight 8 lappend a $eight variable eight lappend a $eight } set a } {8 8} test var-7.9 {Tcl_VariableObjCmd, mark as namespace var so var persists until namespace is destroyed or var is unset} { catch {namespace delete test_ns_var2} set a "" namespace eval test_ns_var2 { variable x 123 variable y variable z } lappend a [lsort [info vars test_ns_var2::*]] lappend a [info exists test_ns_var2::x] [info exists test_ns_var2::y] \ [info exists test_ns_var2::z] lappend a [list [catch {set test_ns_var2::y} msg] $msg] lappend a [lsort [info vars test_ns_var2::*]] lappend a [info exists test_ns_var2::y] [info exists test_ns_var2::z] lappend a [set test_ns_var2::y hello] lappend a [info exists test_ns_var2::y] [info exists test_ns_var2::z] lappend a [list [catch {unset test_ns_var2::y} msg] $msg] lappend a [lsort [info vars test_ns_var2::*]] lappend a [info exists test_ns_var2::y] [info exists test_ns_var2::z] lappend a [list [catch {unset test_ns_var2::z} msg] $msg] lappend a [namespace delete test_ns_var2] set a } [list [lsort {::test_ns_var2::x ::test_ns_var2::y ::test_ns_var2::z}] 1 0 0\ {1 {can't read "test_ns_var2::y": no such variable}}\ [lsort {::test_ns_var2::x ::test_ns_var2::y ::test_ns_var2::z}] 0 0\ hello 1 0\ {0 {}}\ [lsort {::test_ns_var2::x ::test_ns_var2::z}] 0 0\ {1 {can't unset "test_ns_var2::z": no such variable}}\ {}] test var-7.10 {Tcl_VariableObjCmd, variable cmd inside proc creates local link var} { namespace eval test_ns_var { proc p {} { variable eight list [set eight] [info vars] } p } } {8 eight} test var-7.11 {Tcl_VariableObjCmd, variable cmd inside proc creates local link var} { proc p {} { ;# note this proc is at global :: scope variable test_ns_var::eight list [set eight] [info vars] } p } {8 eight} test var-7.12 {Tcl_VariableObjCmd, variable cmd inside proc creates local link var} { namespace eval test_ns_var { variable {} {My name is empty} } proc p {} { ;# note this proc is at global :: scope variable test_ns_var:: list [set {}] [info vars] } p } {{My name is empty} {{}}} test var-7.13 {Tcl_VariableObjCmd, variable named ":"} { namespace eval test_ns_var { variable : {My name is ":"} proc p {} { variable : list [set :] [info vars] } p } } {{My name is ":"} :} test var-7.14 {Tcl_VariableObjCmd, array element parameter} { catch {namespace eval test_ns_var { variable arrayvar(1) }} res set res } "can't define \"arrayvar(1)\": name refers to an element in an array" test var-7.15 {Tcl_VariableObjCmd, array element parameter} { catch { namespace eval test_ns_var { variable arrayvar set arrayvar(1) x variable arrayvar(1) y } } res set res } "can't define \"arrayvar(1)\": name refers to an element in an array" test var-7.16 {Tcl_VariableObjCmd, no args} { list [catch {variable} msg] $msg } {1 {wrong # args: should be "variable ?name value...? name ?value?"}} test var-7.17 {Tcl_VariableObjCmd, no args} { namespace eval test_ns_var { list [catch {variable} msg] $msg } } {1 {wrong # args: should be "variable ?name value...? name ?value?"}} test var-8.1 {TclDeleteVars, "unset" traces are called with fully-qualified var names} { catch {namespace delete test_ns_var} catch {unset a} namespace eval test_ns_var { variable v 123 variable info "" proc traceUnset {name1 name2 op} { variable info set info [concat $info [list $name1 $name2 $op]] } trace var v u [namespace code traceUnset] } list [unset test_ns_var::v] $test_ns_var::info } {{} {test_ns_var::v {} u}} if {[info commands testsetnoerr] == {}} { puts "This application hasn't been compiled with the \"testsetnoerr\"" puts "command, so I can't test TclSetVar etc." } else { test var-9.1 {behaviour of TclGet/SetVar simple get/set} { catch {unset u}; catch {unset v} list \ [set u a; testsetnoerr u] \ [testsetnoerr v b] \ [testseterr u] \ [unset v; testseterr v b] } [list {before get a} {before set b} {before get a} {before set b}] test var-9.2 {behaviour of TclGet/SetVar namespace get/set} { catch {namespace delete ns} namespace eval ns {variable u a; variable v} list \ [testsetnoerr ns::u] \ [testsetnoerr ns::v b] \ [testseterr ns::u] \ [unset ns::v; testseterr ns::v b] } [list {before get a} {before set b} {before get a} {before set b}] test var-9.3 {behaviour of TclGetVar no variable} { catch {unset u} list \ [catch {testsetnoerr u} res] $res \ [catch {testseterr u} res] $res } {1 {before get} 1 {can't read "u": no such variable}} test var-9.4 {behaviour of TclGetVar no namespace variable} { catch {namespace delete ns} namespace eval ns {} list \ [catch {testsetnoerr ns::w} res] $res \ [catch {testseterr ns::w} res] $res } {1 {before get} 1 {can't read "ns::w": no such variable}} test var-9.5 {behaviour of TclGetVar no namespace} { catch {namespace delete ns} list \ [catch {testsetnoerr ns::u} res] $res \ [catch {testseterr ns::v} res] $res } {1 {before get} 1 {can't read "ns::v": no such variable}} test var-9.6 {behaviour of TclSetVar no namespace} { catch {namespace delete ns} list \ [catch {testsetnoerr ns::v 1} res] $res \ [catch {testseterr ns::v 1} res] $res } {1 {before set} 1 {can't set "ns::v": parent namespace doesn't exist}} test var-9.7 {behaviour of TclGetVar array variable} { catch {unset arr} set arr(1) 1; list \ [catch {testsetnoerr arr} res] $res \ [catch {testseterr arr} res] $res } {1 {before get} 1 {can't read "arr": variable is array}} test var-9.8 {behaviour of TclSetVar array variable} { catch {unset arr} set arr(1) 1 list \ [catch {testsetnoerr arr 2} res] $res \ [catch {testseterr arr 2} res] $res } {1 {before set} 1 {can't set "arr": variable is array}} test var-9.9 {behaviour of TclGetVar read trace success} { proc resetvar {val name elem op} {upvar 1 $name v; set v $val} catch {unset u}; catch {unset v} set u 10 trace var u r [list resetvar 1] trace var v r [list resetvar 2] list \ [testsetnoerr u] \ [testseterr v] } {{before get 1} {before get 2}} test var-9.10 {behaviour of TclGetVar read trace error} { proc writeonly args {error "write-only"} set v 456 trace var v r writeonly list \ [catch {testsetnoerr v} msg] $msg \ [catch {testseterr v} msg] $msg } {1 {before get} 1 {can't read "v": write-only}} test var-9.11 {behaviour of TclSetVar write trace success} { proc doubleval {name elem op} {upvar 1 $name v; set v [expr {2 * $v}]} catch {unset u}; catch {unset v} set v 1 trace var v w doubleval trace var u w doubleval list \ [testsetnoerr u 2] \ [testseterr v 3] } {{before set 4} {before set 6}} test var-9.12 {behaviour of TclSetVar write trace error} { proc readonly args {error "read-only"} set v 456 trace var v w readonly list \ [catch {testsetnoerr v 2} msg] $msg $v \ [catch {testseterr v 3} msg] $msg $v } {1 {before set} 2 1 {can't set "v": read-only} 3} } test var-10.1 {can't nest arrays with array set} { catch {unset arr} list [catch {array set arr(x) {a 1 b 2}} res] $res } {1 {can't set "arr(x)": variable isn't array}} test var-10.2 {can't nest arrays with array set} { catch {unset arr} list [catch {array set arr(x) {}} res] $res } {1 {can't set "arr(x)": variable isn't array}} test var-11.1 {array unset} { catch {unset a} array set a { 1,1 a 1,2 b 2,1 c 2,3 d } array unset a 1,* lsort -dict [array names a] } {2,1 2,3} test var-11.2 {array unset} { catch {unset a} array set a { 1,1 a 1,2 b } array unset a array exists a } 0 test var-11.3 {array unset errors} { catch {unset a} array set a { 1,1 a 1,2 b } list [catch {array unset a pattern too} msg] $msg } {1 {wrong # args: should be "array unset arrayName ?pattern?"}} test var-12.1 {TclFindCompiledLocals, {} array name} { namespace eval n { proc p {} { variable {} set (0) 0 set (1) 1 set n 2 set ($n) 2 set ($n,foo) 2 } p lsort -dictionary [array names {}] } } {0 1 2 2,foo} test var-13.1 {Tcl_UnsetVar2, unset array with trace set on element} { catch {unset t} proc foo {var ind op} { global t set foo bar } namespace eval :: { set t(1) 1 trace variable t(1) u foo unset t } set x "If you see this, it worked" } "If you see this, it worked" test var-14.1 {array names syntax} -body { array names foo bar baz snafu } -returnCodes 1 -match glob -result * test var-15.1 {segfault in [unset], [Bug 735335]} { proc A { name } { upvar $name var set var $name } # # Note that the variable name has to be # unused previously for the segfault to # be triggered. # namespace eval test A useSomeUnlikelyNameHere namespace eval test unset useSomeUnlikelyNameHere } {} test var-16.1 {CallVarTraces: save/restore interp error state: 1038021} { trace add variable errorCode write { ;#} catch {error foo bar baz} trace remove variable errorCode write { ;#} set errorInfo } bar test var-17.1 {TclArraySet [Bug 1669489]} -setup { unset -nocomplain ::a } -body { namespace eval :: { set elements {1 2 3 4} trace add variable a write {string length $elements ;#} array set a $elements } } -cleanup { unset -nocomplain ::a ::elements } -result {} catch {namespace delete ns} catch {unset arr} catch {unset v} catch {rename p ""} catch {namespace delete test_ns_var} catch {namespace delete test_ns_var2} catch {unset xx} catch {unset x} catch {unset y} catch {unset i} catch {unset a} catch {unset xxxxx} catch {unset aaaaa} # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/if.test0000644003604700454610000006543611737050674013376 0ustar dgp771div# Commands covered: if # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1996 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } # Basic "if" operation. catch {unset a} test if-1.1 {TclCompileIfCmd: missing if/elseif test} { list [catch {if} msg] $msg } {1 {wrong # args: no expression after "if" argument}} test if-1.2 {TclCompileIfCmd: error in if/elseif test} { list [catch {if {[error "error in condition"]} foo} msg] $msg } {1 {error in condition}} test if-1.3 {TclCompileIfCmd: error in if/elseif test} { list [catch {if {1+}} msg] $msg $errorInfo } {1 {syntax error in expression "1+": premature end of expression} {syntax error in expression "1+": premature end of expression ("if" test expression) while compiling "if {1+}"}} test if-1.4 {TclCompileIfCmd: if/elseif test in braces} { set a {} if {1<2} {set a 1} set a } {1} test if-1.5 {TclCompileIfCmd: if/elseif test not in braces} { set a {} if 1<2 {set a 1} set a } {1} test if-1.6 {TclCompileIfCmd: multiline test expr} { set a {} if {($tcl_platform(platform) != "foobar1") && \ ($tcl_platform(platform) != "foobar2")} {set a 3} else {set a 4} set a } 3 test if-1.7 {TclCompileIfCmd: "then" after if/elseif test} { set a {} if 4>3 then {set a 1} set a } {1} test if-1.8 {TclCompileIfCmd: keyword other than "then" after if/elseif test} { set a {} catch {if 1<2 therefore {set a 1}} msg set msg } {invalid command name "therefore"} test if-1.9 {TclCompileIfCmd: missing "then" body} { set a {} catch {if 1<2 then} msg set msg } {wrong # args: no script following "then" argument} test if-1.10 {TclCompileIfCmd: error in "then" body} { set a {} list [catch {if {$a!="xxx"} then {set}} msg] $msg $errorInfo } {1 {wrong # args: should be "set varName ?newValue?"} {wrong # args: should be "set varName ?newValue?" while compiling "set" ("if" then script line 1) while compiling "if {$a!="xxx"} then {set}"}} test if-1.11 {TclCompileIfCmd: error in "then" body} { list [catch {if 2 then {[error "error in then clause"]}} msg] $msg } {1 {error in then clause}} test if-1.12 {TclCompileIfCmd: "then" body in quotes} { set a {} if 27>17 "append a x" set a } {x} test if-1.13 {TclCompileIfCmd: computed "then" body} { catch {unset x1} catch {unset x2} set a {} set x1 {append a x1} set x2 {; append a x2} set a {} if 1 $x1$x2 set a } {x1x2} test if-1.14 {TclCompileIfCmd: taking proper branch} { set a {} if 1<2 {set a 1} set a } 1 test if-1.15 {TclCompileIfCmd: taking proper branch} { set a {} if 1>2 {set a 1} set a } {} test if-1.16 {TclCompileIfCmd: test jumpFalse instruction replacement after long "then" body} { catch {unset i} set a {} if 1<2 { set a 1 while {$a != "xxx"} { break; while {$i >= 0} { if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } set i [expr $i-1] } } set a 2 while {$a != "xxx"} { break; while {$i >= 0} { if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } set i [expr $i-1] } } set a 3 } set a } 3 test if-1.17 {TclCompileIfCmd: if/elseif test in quotes} { set a {} list [catch {if {"0 < 3"} {set a 1}} msg] $msg } {1 {expected boolean value but got "0 < 3"}} test if-2.1 {TclCompileIfCmd: "elseif" after if/elseif test} { set a {} if 3>4 {set a 1} elseif 1 {set a 2} set a } {2} # Since "else" is optional, the "elwood" below is treated as a command. # But then there shouldn't be any additional argument words for the "if". test if-2.2 {TclCompileIfCmd: keyword other than "elseif"} { set a {} catch {if 1<2 {set a 1} elwood {set a 2}} msg set msg } {wrong # args: extra words after "else" clause in "if" command} test if-2.3 {TclCompileIfCmd: missing expression after "elseif"} { set a {} catch {if 1<2 {set a 1} elseif} msg set msg } {wrong # args: no expression after "elseif" argument} test if-2.4 {TclCompileIfCmd: error in expression after "elseif"} { set a {} list [catch {if 3>4 {set a 1} elseif {1>}} msg] $msg $errorInfo } {1 {syntax error in expression "1>": premature end of expression} {syntax error in expression "1>": premature end of expression ("if" test expression) while compiling "if 3>4 {set a 1} elseif {1>}"}} test if-2.5 {TclCompileIfCmd: test jumpFalse instruction replacement after long "elseif" body} { catch {unset i} set a {} if 1>2 { set a 1 while {$a != "xxx"} { break; while {$i >= 0} { if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } set i [expr $i-1] } } set a 2 while {$a != "xxx"} { break; while {$i >= 0} { if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } set i [expr $i-1] } } set a 3 } elseif 1<2 then { #; this if arm should be taken set a 4 while {$a != "xxx"} { break; while {$i >= 0} { if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } set i [expr $i-1] } } set a 5 while {$a != "xxx"} { break; while {$i >= 0} { if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } set i [expr $i-1] } } set a 6 } set a } 6 test if-3.1 {TclCompileIfCmd: "else" clause} { set a {} if 3>4 {set a 1} elseif {$a == "foo"} {set a 2} else {set a 3} set a } 3 # Since "else" is optional, the "elsex" below is treated as a command. # But then there shouldn't be any additional argument words for the "if". test if-3.2 {TclCompileIfCmd: keyword other than "else"} { set a {} catch {if 1<2 then {set a 1} elsex {set a 2}} msg set msg } {wrong # args: extra words after "else" clause in "if" command} test if-3.3 {TclCompileIfCmd: missing body after "else"} { set a {} catch {if 2<1 {set a 1} else} msg set msg } {wrong # args: no script following "else" argument} test if-3.4 {TclCompileIfCmd: error compiling body after "else"} { set a {} catch {if 2<1 {set a 1} else {set}} msg set errorInfo } {wrong # args: should be "set varName ?newValue?" while compiling "set" ("if" else script line 1) while compiling "if 2<1 {set a 1} else {set}"} test if-3.5 {TclCompileIfCmd: extra arguments after "else" argument} { set a {} catch {if 2<1 {set a 1} else {set a 2} or something} msg set msg } {wrong # args: extra words after "else" clause in "if" command} # The following test also checks whether contained loops and other # commands are properly relocated because a short jump must be replaced # by a "long distance" one. test if-3.6 {TclCompileIfCmd: test jumpFalse instruction replacement after long "else" clause} { catch {unset i} set a {} if 1>2 { set a 1 while {$a != "xxx"} { break; while {$i >= 0} { if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } set i [expr $i-1] } } set a 2 while {$a != "xxx"} { break; while {$i >= 0} { if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } set i [expr $i-1] } } set a 3 } elseif 1==2 then { #; this if arm should be taken set a 4 while {$a != "xxx"} { break; while {$i >= 0} { if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } set i [expr $i-1] } } set a 5 while {$a != "xxx"} { break; while {$i >= 0} { if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } set i [expr $i-1] } } set a 6 } else { set a 7 while {$a != "xxx"} { break; while {$i >= 0} { if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } set i [expr $i-1] } } set a 8 while {$a != "xxx"} { break; while {$i >= 0} { if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } if {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } set i [expr $i-1] } } set a 9 } set a } 9 test if-4.1 {TclCompileIfCmd: "if" command result} { set a {} set a [if 3<4 {set i 27}] set a } 27 test if-4.2 {TclCompileIfCmd: "if" command result} { set a {} set a [if 3>4 {set i 27}] set a } {} test if-4.3 {TclCompileIfCmd: "if" command result} { set a {} set a [if 0 {set i 1} elseif 1 {set i 2}] set a } 2 test if-4.4 {TclCompileIfCmd: "if" command result} { set a {} set a [if 0 {set i 1} elseif 0 {set i 2} elseif 2>5 {set i 3} else {set i 4}] set a } 4 test if-4.5 {TclCompileIfCmd: return value} { if 0 then {set a 22; concat abc} elseif 1 {concat def} {concat ghi} } def # Check "if" and computed command names. catch {unset a} test if-5.1 {if cmd with computed command names: missing if/elseif test} { set z if list [catch {$z} msg] $msg } {1 {wrong # args: no expression after "if" argument}} test if-5.2 {if cmd with computed command names: error in if/elseif test} { set z if list [catch {$z {[error "error in condition"]} foo} msg] $msg } {1 {error in condition}} test if-5.3 {if cmd with computed command names: error in if/elseif test} { set z if list [catch {$z {1+}} msg] $msg $errorInfo } {1 {syntax error in expression "1+": premature end of expression} {syntax error in expression "1+": premature end of expression while executing "$z {1+}"}} test if-5.4 {if cmd with computed command names: if/elseif test in braces} { set z if set a {} $z {1<2} {set a 1} set a } {1} test if-5.5 {if cmd with computed command names: if/elseif test not in braces} { set z if set a {} $z 1<2 {set a 1} set a } {1} test if-5.6 {if cmd with computed command names: multiline test expr} { set z if set a {} $z {($tcl_platform(platform) != "foobar1") && \ ($tcl_platform(platform) != "foobar2")} {set a 3} else {set a 4} set a } 3 test if-5.7 {if cmd with computed command names: "then" after if/elseif test} { set z if set a {} $z 4>3 then {set a 1} set a } {1} test if-5.8 {if cmd with computed command names: keyword other than "then" after if/elseif test} { set z if set a {} catch {$z 1<2 therefore {set a 1}} msg set msg } {invalid command name "therefore"} test if-5.9 {if cmd with computed command names: missing "then" body} { set z if set a {} catch {$z 1<2 then} msg set msg } {wrong # args: no script following "then" argument} test if-5.10 {if cmd with computed command names: error in "then" body} { set z if set a {} list [catch {$z {$a!="xxx"} then {set}} msg] $msg $errorInfo } {1 {wrong # args: should be "set varName ?newValue?"} {wrong # args: should be "set varName ?newValue?" while compiling "set" invoked from within "$z {$a!="xxx"} then {set}"}} test if-5.11 {if cmd with computed command names: error in "then" body} { set z if list [catch {$z 2 then {[error "error in then clause"]}} msg] $msg } {1 {error in then clause}} test if-5.12 {if cmd with computed command names: "then" body in quotes} { set z if set a {} $z 27>17 "append a x" set a } {x} test if-5.13 {if cmd with computed command names: computed "then" body} { set z if catch {unset x1} catch {unset x2} set a {} set x1 {append a x1} set x2 {; append a x2} set a {} $z 1 $x1$x2 set a } {x1x2} test if-5.14 {if cmd with computed command names: taking proper branch} { set z if set a {} $z 1<2 {set a 1} set a } 1 test if-5.15 {if cmd with computed command names: taking proper branch} { set z if set a {} $z 1>2 {set a 1} set a } {} test if-5.16 {if cmd with computed command names: test jumpFalse instruction replacement after long "then" body} { set z if catch {unset i} set a {} $z 1<2 { set a 1 while {$a != "xxx"} { break; while {$i >= 0} { $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } set i [expr $i-1] } } set a 2 while {$a != "xxx"} { break; while {$i >= 0} { $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } set i [expr $i-1] } } set a 3 } set a } 3 test if-5.17 {if cmd with computed command names: if/elseif test in quotes} { set z if set a {} list [catch {$z {"0 < 3"} {set a 1}} msg] $msg } {1 {expected boolean value but got "0 < 3"}} test if-6.1 {if cmd with computed command names: "elseif" after if/elseif test} { set z if set a {} $z 3>4 {set a 1} elseif 1 {set a 2} set a } {2} # Since "else" is optional, the "elwood" below is treated as a command. # But then there shouldn't be any additional argument words for the "if". test if-6.2 {if cmd with computed command names: keyword other than "elseif"} { set z if set a {} catch {$z 1<2 {set a 1} elwood {set a 2}} msg set msg } {wrong # args: extra words after "else" clause in "if" command} test if-6.3 {if cmd with computed command names: missing expression after "elseif"} { set z if set a {} catch {$z 1<2 {set a 1} elseif} msg set msg } {wrong # args: no expression after "elseif" argument} test if-6.4 {if cmd with computed command names: error in expression after "elseif"} { set z if set a {} list [catch {$z 3>4 {set a 1} elseif {1>}} msg] $msg $errorInfo } {1 {syntax error in expression "1>": premature end of expression} {syntax error in expression "1>": premature end of expression while executing "$z 3>4 {set a 1} elseif {1>}"}} test if-6.5 {if cmd with computed command names: test jumpFalse instruction replacement after long "elseif" body} { set z if catch {unset i} set a {} $z 1>2 { set a 1 while {$a != "xxx"} { break; while {$i >= 0} { $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } set i [expr $i-1] } } set a 2 while {$a != "xxx"} { break; while {$i >= 0} { $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } set i [expr $i-1] } } set a 3 } elseif 1<2 then { #; this if arm should be taken set a 4 while {$a != "xxx"} { break; while {$i >= 0} { $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } set i [expr $i-1] } } set a 5 while {$a != "xxx"} { break; while {$i >= 0} { $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } set i [expr $i-1] } } set a 6 } set a } 6 test if-7.1 {if cmd with computed command names: "else" clause} { set z if set a {} $z 3>4 {set a 1} elseif {$a == "foo"} {set a 2} else {set a 3} set a } 3 # Since "else" is optional, the "elsex" below is treated as a command. # But then there shouldn't be any additional argument words for the "if". test if-7.2 {if cmd with computed command names: keyword other than "else"} { set z if set a {} catch {$z 1<2 then {set a 1} elsex {set a 2}} msg set msg } {wrong # args: extra words after "else" clause in "if" command} test if-7.3 {if cmd with computed command names: missing body after "else"} { set z if set a {} catch {$z 2<1 {set a 1} else} msg set msg } {wrong # args: no script following "else" argument} test if-7.4 {if cmd with computed command names: error compiling body after "else"} { set z if set a {} catch {$z 2<1 {set a 1} else {set}} msg set errorInfo } {wrong # args: should be "set varName ?newValue?" while compiling "set" invoked from within "$z 2<1 {set a 1} else {set}"} test if-7.5 {if cmd with computed command names: extra arguments after "else" argument} { set z if set a {} catch {$z 2<1 {set a 1} else {set a 2} or something} msg set msg } {wrong # args: extra words after "else" clause in "if" command} # The following test also checks whether contained loops and other # commands are properly relocated because a short jump must be replaced # by a "long distance" one. test if-7.6 {if cmd with computed command names: test jumpFalse instruction replacement after long "else" clause} { set z if catch {unset i} set a {} $z 1>2 { set a 1 while {$a != "xxx"} { break; while {$i >= 0} { $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } set i [expr $i-1] } } set a 2 while {$a != "xxx"} { break; while {$i >= 0} { $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } set i [expr $i-1] } } set a 3 } elseif 1==2 then { #; this if arm should be taken set a 4 while {$a != "xxx"} { break; while {$i >= 0} { $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } set i [expr $i-1] } } set a 5 while {$a != "xxx"} { break; while {$i >= 0} { $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } set i [expr $i-1] } } set a 6 } else { set a 7 while {$a != "xxx"} { break; while {$i >= 0} { $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } set i [expr $i-1] } } set a 8 while {$a != "xxx"} { break; while {$i >= 0} { $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } $z {[string compare $a "bar"] < 0} { set i $i set i [lindex $s $i] } set i [expr $i-1] } } set a 9 } set a } 9 test if-8.1 {if cmd with computed command names: "if" command result} { set z if set a {} set a [$z 3<4 {set i 27}] set a } 27 test if-8.2 {if cmd with computed command names: "if" command result} { set z if set a {} set a [$z 3>4 {set i 27}] set a } {} test if-8.3 {if cmd with computed command names: "if" command result} { set z if set a {} set a [$z 0 {set i 1} elseif 1 {set i 2}] set a } 2 test if-8.4 {if cmd with computed command names: "if" command result} { set z if set a {} set a [$z 0 {set i 1} elseif 0 {set i 2} elseif 2>5 {set i 3} else {set i 4}] set a } 4 test if-8.5 {if cmd with computed command names: return value} { set z if $z 0 then {set a 22; concat abc} elseif 1 {concat def} {concat ghi} } def test if-9.1 {if cmd with namespace qualifiers} { ::if {1} {set x 4} } 4 # Test for incorrect "double evaluation semantics" test if-10.1 {delayed substitution of then body} { set j 0 set if if # this is not compiled $if {[incr j] == 1} " set result $j " # this will be compiled proc p {} { set j 0 if {[incr j]} " set result $j " set result } append result [p] } {00} test if-10.2 {delayed substitution of elseif expression} { set j 0 set if if # this is not compiled $if {[incr j] == 0} { set result badthen } elseif "$j == 1" { set result badelseif } else { set result 0 } # this will be compiled proc p {} { set j 0 if {[incr j] == 0} { set result badthen } elseif "$j == 1" { set result badelseif } else { set result 0 } set result } append result [p] } {00} test if-10.3 {delayed substitution of elseif body} { set j 0 set if if # this is not compiled $if {[incr j] == 0} { set result badthen } elseif {1} " set result $j " # this will be compiled proc p {} { set j 0 if {[incr j] == 0} { set result badthen } elseif {1} " set result $j " } append result [p] } {00} test if-10.4 {delayed substitution of else body} { set j 0 if {[incr j] == 0} { set result badthen } else " set result $j " set result } {0} test if-10.5 {substituted control words} { set then then; proc then {} {return badthen} set else else; proc else {} {return badelse} set elseif elseif; proc elseif {} {return badelseif} list [catch {if 1 $then {if 0 {} $elseif 1 {if 0 {} $else {list ok}}}} a] $a } {0 ok} test if-10.6 {double invocation of variable traces} { set iftracecounter 0 proc iftraceproc {args} { upvar #0 iftracecounter counter set argc [llength $args] set extraargs [lrange $args 0 [expr {$argc - 4}]] set name [lindex $args [expr {$argc - 3}]] upvar 1 $name var if {[incr counter] % 2 == 1} { set var "$counter oops [concat $extraargs]" } else { set var "$counter + [concat $extraargs]" } } trace variable iftracevar r [list iftraceproc 10] list [catch {if "$iftracevar + 20" {}} a] $a \ [catch {if "$iftracevar + 20" {}} b] $b \ [unset iftracevar iftracecounter] } {1 {syntax error in expression "1 oops 10 + 20": extra tokens at end of expression} 0 {} {}} # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/utf.test0000644003604700454610000002501711737050674013565 0ustar dgp771div# This file contains a collection of tests for tclUtf.c # Sourcing this file into Tcl runs the tests and generates output for # errors. No output means no errors were found. # # Copyright (c) 1997 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import -force ::tcltest::* } catch {unset x} test utf-1.1 {Tcl_UniCharToUtf: 1 byte sequences} { set x \x01 } [bytestring "\x01"] test utf-1.2 {Tcl_UniCharToUtf: 2 byte sequences} { set x "\x00" } [bytestring "\xc0\x80"] test utf-1.3 {Tcl_UniCharToUtf: 2 byte sequences} { set x "\xe0" } [bytestring "\xc3\xa0"] test utf-1.4 {Tcl_UniCharToUtf: 3 byte sequences} { set x "\u4e4e" } [bytestring "\xe4\xb9\x8e"] test utf-1.5 {Tcl_UniCharToUtf: overflowed Tcl_UniChar} { format %c 0x110000 } [bytestring "\xef\xbf\xbd"] test utf-1.6 {Tcl_UniCharToUtf: negative Tcl_UniChar} { format %c -1 } [bytestring "\xef\xbf\xbd"] test utf-2.1 {Tcl_UtfToUniChar: low ascii} { string length "abc" } {3} test utf-2.2 {Tcl_UtfToUniChar: naked trail bytes} { string length [bytestring "\x82\x83\x84"] } {3} test utf-2.3 {Tcl_UtfToUniChar: lead (2-byte) followed by non-trail} { string length [bytestring "\xC2"] } {1} test utf-2.4 {Tcl_UtfToUniChar: lead (2-byte) followed by trail} { string length [bytestring "\xC2\xa2"] } {1} test utf-2.5 {Tcl_UtfToUniChar: lead (3-byte) followed by non-trail} { string length [bytestring "\xE2"] } {1} test utf-2.6 {Tcl_UtfToUniChar: lead (3-byte) followed by 1 trail} { string length [bytestring "\xE2\xA2"] } {2} test utf-2.7 {Tcl_UtfToUniChar: lead (3-byte) followed by 2 trail} { string length [bytestring "\xE4\xb9\x8e"] } {1} test utf-2.8 {Tcl_UtfToUniChar: longer UTF sequences not supported} { string length [bytestring "\xF4\xA2\xA2\xA2"] } {4} test utf-3.1 {Tcl_UtfCharComplete} { } {} testConstraint testnumutfchars [llength [info commands testnumutfchars]] test utf-4.1 {Tcl_NumUtfChars: zero length} testnumutfchars { testnumutfchars "" } {0} test utf-4.2 {Tcl_NumUtfChars: length 1} testnumutfchars { testnumutfchars [bytestring "\xC2\xA2"] } {1} test utf-4.3 {Tcl_NumUtfChars: long string} testnumutfchars { testnumutfchars [bytestring "abc\xC2\xA2\xe4\xb9\x8e\uA2\u4e4e"] } {7} test utf-4.4 {Tcl_NumUtfChars: #u0000} testnumutfchars { testnumutfchars [bytestring "\xC0\x80"] } {1} test utf-4.5 {Tcl_NumUtfChars: zero length, calc len} testnumutfchars { testnumutfchars "" 1 } {0} test utf-4.6 {Tcl_NumUtfChars: length 1, calc len} testnumutfchars { testnumutfchars [bytestring "\xC2\xA2"] 1 } {1} test utf-4.7 {Tcl_NumUtfChars: long string, calc len} testnumutfchars { testnumutfchars [bytestring "abc\xC2\xA2\xe4\xb9\x8e\uA2\u4e4e"] 1 } {7} test utf-4.8 {Tcl_NumUtfChars: #u0000, calc len} testnumutfchars { testnumutfchars [bytestring "\xC0\x80"] 1 } {1} test utf-5.1 {Tcl_UtfFindFirsts} { } {} test utf-6.1 {Tcl_UtfNext} { } {} test utf-7.1 {Tcl_UtfPrev} { } {} test utf-8.1 {Tcl_UniCharAtIndex: index = 0} { string index abcd 0 } {a} test utf-8.2 {Tcl_UniCharAtIndex: index = 0} { string index \u4e4e\u25a 0 } "\u4e4e" test utf-8.3 {Tcl_UniCharAtIndex: index > 0} { string index abcd 2 } {c} test utf-8.4 {Tcl_UniCharAtIndex: index > 0} { string index \u4e4e\u25a\xff\u543 2 } "\uff" test utf-9.1 {Tcl_UtfAtIndex: index = 0} { string range abcd 0 2 } {abc} test utf-9.2 {Tcl_UtfAtIndex: index > 0} { string range \u4e4e\u25a\xff\u543klmnop 1 5 } "\u25a\xff\u543kl" test utf-10.1 {Tcl_UtfBackslash: dst == NULL} { set x \n } { } test utf-10.2 {Tcl_UtfBackslash: \u subst} { set x \ua2 } [bytestring "\xc2\xa2"] test utf-10.3 {Tcl_UtfBackslash: longer \u subst} { set x \u4e21 } [bytestring "\xe4\xb8\xa1"] test utf-10.4 {Tcl_UtfBackslash: stops at first non-hex} { set x \u4e2k } "[bytestring \xd3\xa2]k" test utf-10.5 {Tcl_UtfBackslash: stops after 4 hex chars} { set x \u4e216 } "[bytestring \xe4\xb8\xa1]6" proc bsCheck {char num} { global errNum test utf-10.$errNum {backslash substitution} { scan $char %c value set value } $num incr errNum } set errNum 6 bsCheck \b 8 bsCheck \e 101 bsCheck \f 12 bsCheck \n 10 bsCheck \r 13 bsCheck \t 9 bsCheck \v 11 bsCheck \{ 123 bsCheck \} 125 bsCheck \[ 91 bsCheck \] 93 bsCheck \$ 36 bsCheck \ 32 bsCheck \; 59 bsCheck \\ 92 bsCheck \Ca 67 bsCheck \Ma 77 bsCheck \CMa 67 # prior to 8.3, this returned 8, as \8 as accepted as an # octal value - but it isn't! [Bug: 3975] bsCheck \8a 56 bsCheck \14 12 bsCheck \141 97 bsCheck b\0 98 bsCheck \x 120 bsCheck \xa 10 bsCheck \xA 10 bsCheck \x41 65 bsCheck \x541 65 bsCheck \u 117 bsCheck \uk 117 bsCheck \u41 65 bsCheck \ua 10 bsCheck \uA 10 bsCheck \340 224 bsCheck \ua1 161 bsCheck \u4e21 20001 test utf-11.1 {Tcl_UtfToUpper} { string toupper {} } {} test utf-11.2 {Tcl_UtfToUpper} { string toupper abc } ABC test utf-11.3 {Tcl_UtfToUpper} { string toupper \u00e3ab } \u00c3AB test utf-11.4 {Tcl_UtfToUpper} { string toupper \u01e3ab } \u01e2AB test utf-12.1 {Tcl_UtfToLower} { string tolower {} } {} test utf-12.2 {Tcl_UtfToLower} { string tolower ABC } abc test utf-12.3 {Tcl_UtfToLower} { string tolower \u00c3AB } \u00e3ab test utf-12.4 {Tcl_UtfToLower} { string tolower \u01e2AB } \u01e3ab test utf-13.1 {Tcl_UtfToTitle} { string totitle {} } {} test utf-13.2 {Tcl_UtfToTitle} { string totitle abc } Abc test utf-13.3 {Tcl_UtfToTitle} { string totitle \u00e3ab } \u00c3ab test utf-13.4 {Tcl_UtfToTitle} { string totitle \u01f3ab } \u01f2ab test utf-14.1 {Tcl_UtfNcasecmp} { string compare -nocase a b } -1 test utf-14.2 {Tcl_UtfNcasecmp} { string compare -nocase b a } 1 test utf-14.3 {Tcl_UtfNcasecmp} { string compare -nocase B a } 1 test utf-14.4 {Tcl_UtfNcasecmp} { string compare -nocase aBcB abca } 1 test utf-15.1 {Tcl_UniCharToUpper, negative delta} { string toupper aA } AA test utf-15.2 {Tcl_UniCharToUpper, positive delta} { string toupper \u0178\u00ff } \u0178\u0178 test utf-15.3 {Tcl_UniCharToUpper, no delta} { string toupper ! } ! test utf-16.1 {Tcl_UniCharToLower, negative delta} { string tolower aA } aa test utf-16.2 {Tcl_UniCharToLower, positive delta} { string tolower \u0178\u00ff\uA78D\u01c5 } \u00ff\u00ff\u0265\u01c6 test utf-17.1 {Tcl_UniCharToLower, no delta} { string tolower ! } ! test utf-18.1 {Tcl_UniCharToTitle, add one for title} { string totitle \u01c4 } \u01c5 test utf-18.2 {Tcl_UniCharToTitle, subtract one for title} { string totitle \u01c6 } \u01c5 test utf-18.3 {Tcl_UniCharToTitle, subtract delta for title (positive)} { string totitle \u017f } \u0053 test utf-18.4 {Tcl_UniCharToTitle, subtract delta for title (negative)} { string totitle \u00ff } \u0178 test utf-18.5 {Tcl_UniCharToTitle, no delta} { string totitle ! } ! test utf-19.1 {TclUniCharLen} { list [regexp \\d abc456def foo] $foo } {1 4} test utf-20.1 {TclUniCharNcmp} { } {} test utf-21.1 {TclUniCharIsAlnum} { # this returns 1 with Unicode 6 compliance string is alnum \u1040\u021f\u0220 } {1} test utf-21.2 {unicode alnum char in regc_locale.c} { # this returns 1 with Unicode 6 compliance list [regexp {^[[:alnum:]]+$} \u1040\u021f\u0220] [regexp {^\w+$} \u1040\u021f\u0220] } {1 1} test utf-21.4 {TclUniCharIsGraph} { # [Bug 3464428] string is graph \u0120 } {1} test utf-21.5 {unicode graph char in regc_locale.c} { # [Bug 3464428] regexp {^[[:graph:]]+$} \u0120 } {1} test utf-21.6 {TclUniCharIsGraph} { # [Bug 3464428] string is graph \u00a0 } {0} test utf-21.7 {unicode graph char in regc_locale.c} { # [Bug 3464428] regexp {[[:graph:]]} \u0020\u00a0\u2028\u2029 } {0} test utf-21.8 {TclUniCharIsPrint} { # [Bug 3464428] string is print \u0009 } {0} test utf-21.9 {unicode print char in regc_locale.c} { # [Bug 3464428] regexp {[[:print:]]} \u0009 } {0} test utf-21.10 {unicode print char in regc_locale.c} { # [Bug 3464428] regexp {[[:print:]]} \u0009 } {0} test utf-21.11 {TclUniCharIsControl} { # [Bug 3464428] string is control \u00ad } {1} test utf-21.12 {unicode control char in regc_locale.c} { # [Bug 3464428] regexp {^[[:cntrl:]]$} \u00ad } {1} test utf-22.1 {TclUniCharIsWordChar} { string wordend "xyz123_bar fg" 0 } 10 test utf-22.2 {TclUniCharIsWordChar} { string wordend "x\u5080z123_bar\u203c fg" 0 } 10 test utf-23.1 {TclUniCharIsAlpha} { # this returns 1 with Unicode 6 compliance string is alpha \u021f\u0220 } {1} test utf-23.2 {unicode alpha char in regc_locale.c} { # this returns 1 with Unicode 6 compliance regexp {^[[:alpha:]]+$} \u021f\u0220 } {1} test utf-24.1 {TclUniCharIsDigit} { # this returns 1 with Unicode 6 compliance string is digit \u1040\uabf0 } {1} test utf-24.2 {unicode digit char in regc_locale.c} { # this returns 1 with Unicode 6 compliance list [regexp {^[[:digit:]]+$} \u1040\uabf0] [regexp {^\d+$} \u1040\uabf0] } {1 1} test utf-24.3 {TclUniCharIsSpace} { # this returns 1 with Unicode 6 compliance string is space \u1680\u180e } {1} test utf-24.4 {unicode space char in regc_locale.c} { # this returns 1 with Unicode 6 compliance list [regexp {^[[:space:]]+$} \u1680\u180e] [regexp {^\s+$} \u1680\u180e] } {1 1} testConstraint teststringobj [llength [info commands teststringobj]] test utf-25.1 {Tcl_UniCharNcasecmp} teststringobj { testobj freeallvars teststringobj set 1 a teststringobj set 2 b teststringobj getunicode 1 teststringobj getunicode 2 string compare -nocase [teststringobj get 1] [teststringobj get 2] } -1 test utf-25.2 {Tcl_UniCharNcasecmp} teststringobj { testobj freeallvars teststringobj set 1 b teststringobj set 2 a teststringobj getunicode 1 teststringobj getunicode 2 string compare -nocase [teststringobj get 1] [teststringobj get 2] } 1 test utf-25.3 {Tcl_UniCharNcasecmp} teststringobj { testobj freeallvars teststringobj set 1 B teststringobj set 2 a teststringobj getunicode 1 teststringobj getunicode 2 string compare -nocase [teststringobj get 1] [teststringobj get 2] } 1 test utf-25.4 {Tcl_UniCharNcasecmp} teststringobj { testobj freeallvars teststringobj set 1 aBcB teststringobj set 2 abca teststringobj getunicode 1 teststringobj getunicode 2 string compare -nocase [teststringobj get 1] [teststringobj get 2] } 1 # cleanup ::tcltest::cleanupTests return # Local Variables: # mode: tcl # End: tcl8.4.20/tests/set-old.test0000644003604700454610000007334411737050674014344 0ustar dgp771div# Commands covered: set, unset, array # # This file includes the original set of tests for Tcl's set command. # Since the set command is now compiled, a new set of tests covering # the new implementation is in the file "set.test". Sourcing this file # into Tcl runs the tests and generates output for errors. # No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994-1997 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } proc ignore args {} # Simple variable operations. catch {unset a} test set-old-1.1 {basic variable setting and unsetting} { set a 22 } 22 test set-old-1.2 {basic variable setting and unsetting} { set a 123 set a } 123 test set-old-1.3 {basic variable setting and unsetting} { set a xxx format %s $a } xxx test set-old-1.4 {basic variable setting and unsetting} { set a 44 unset a list [catch {set a} msg] $msg } {1 {can't read "a": no such variable}} # Basic array operations. catch {unset a} set a(xyz) 2 set a(44) 3 set {a(a long name)} test test set-old-2.1 {basic array operations} { lsort [array names a] } {44 {a long name} xyz} test set-old-2.2 {basic array operations} { set a(44) } 3 test set-old-2.3 {basic array operations} { set a(xyz) } 2 test set-old-2.4 {basic array operations} { set "a(a long name)" } test test set-old-2.5 {basic array operations} { list [catch {set a(other)} msg] $msg } {1 {can't read "a(other)": no such element in array}} test set-old-2.6 {basic array operations} { list [catch {set a} msg] $msg } {1 {can't read "a": variable is array}} test set-old-2.7 {basic array operations} { format %s $a(44) } 3 test set-old-2.8 {basic array operations} { format %s $a(a long name) } test unset a(44) test set-old-2.9 {basic array operations} { lsort [array names a] } {{a long name} xyz} test set-old-2.10 {basic array operations} { catch {unset b} list [catch {set b(123)} msg] $msg } {1 {can't read "b(123)": no such variable}} test set-old-2.11 {basic array operations} { catch {unset b} set b 44 list [catch {set b(123)} msg] $msg } {1 {can't read "b(123)": variable isn't array}} test set-old-2.12 {basic array operations} { list [catch {set a 14} msg] $msg } {1 {can't set "a": variable is array}} unset a test set-old-2.13 {basic array operations} { list [catch {set a(xyz)} msg] $msg } {1 {can't read "a(xyz)": no such variable}} # Test the set commands, and exercise the corner cases of the code # that parses array references into two parts. test set-old-3.1 {set command} { list [catch {set} msg] $msg } {1 {wrong # args: should be "set varName ?newValue?"}} test set-old-3.2 {set command} { list [catch {set x y z} msg] $msg } {1 {wrong # args: should be "set varName ?newValue?"}} test set-old-3.3 {set command} { catch {unset a} list [catch {set a} msg] $msg } {1 {can't read "a": no such variable}} test set-old-3.4 {set command} { catch {unset a} set a(14) 83 list [catch {set a 22} msg] $msg } {1 {can't set "a": variable is array}} # Test the corner-cases of parsing array names, using set and unset. test set-old-4.1 {parsing array names} { catch {unset a} set a(()) 44 list [catch {array names a} msg] $msg } {0 ()} test set-old-4.2 {parsing array names} { catch {unset a a(abcd} set a(abcd 33 info exists a(abcd } 1 test set-old-4.3 {parsing array names} { catch {unset a a(abcd} set a(abcd 33 list [catch {array names a} msg] $msg } {0 {}} test set-old-4.4 {parsing array names} { catch {unset a abcd)} set abcd) 33 info exists abcd) } 1 test set-old-4.5 {parsing array names} { set a(bcd yyy catch {unset a} list [catch {set a(bcd} msg] $msg } {0 yyy} test set-old-4.6 {parsing array names} { catch {unset a} set a 44 list [catch {set a(bcd test} msg] $msg } {0 test} # Errors in reading variables test set-old-5.1 {errors in reading variables} { catch {unset a} list [catch {set a} msg] $msg } {1 {can't read "a": no such variable}} test set-old-5.2 {errors in reading variables} { catch {unset a} set a 44 list [catch {set a(18)} msg] $msg } {1 {can't read "a(18)": variable isn't array}} test set-old-5.3 {errors in reading variables} { catch {unset a} set a(6) 44 list [catch {set a(18)} msg] $msg } {1 {can't read "a(18)": no such element in array}} test set-old-5.4 {errors in reading variables} { catch {unset a} set a(6) 44 list [catch {set a} msg] $msg } {1 {can't read "a": variable is array}} # Errors and other special cases in writing variables test set-old-6.1 {creating array during write} { catch {unset a} trace var a rwu ignore list [catch {set a(14) 186} msg] $msg [array names a] } {0 186 14} test set-old-6.2 {errors in writing variables} { catch {unset a} set a xxx list [catch {set a(14) 186} msg] $msg } {1 {can't set "a(14)": variable isn't array}} test set-old-6.3 {errors in writing variables} { catch {unset a} set a(100) yyy list [catch {set a 2} msg] $msg } {1 {can't set "a": variable is array}} test set-old-6.4 {expanding variable size} { catch {unset a} list [set a short] [set a "longer name"] [set a "even longer name"] \ [set a "a much much truly longer name"] } {short {longer name} {even longer name} {a much much truly longer name}} # Unset command, Tcl_UnsetVar procedures test set-old-7.1 {unset command} { catch {unset a}; catch {unset b}; catch {unset c}; catch {unset d} set a 44 set b 55 set c 66 set d 77 unset a b c list [catch {set a(0) 0}] [catch {set b(0) 0}] [catch {set c(0) 0}] \ [catch {set d(0) 0}] } {0 0 0 1} test set-old-7.2 {unset command} { list [catch {unset} msg] $msg } {0 {}} # Used to return: #{1 {wrong # args: should be "unset ?-nocomplain? ?--? ?varName varName ...?"}} test set-old-7.3 {unset command} { catch {unset a} list [catch {unset a} msg] $msg } {1 {can't unset "a": no such variable}} test set-old-7.4 {unset command} { catch {unset a} set a 44 list [catch {unset a(14)} msg] $msg } {1 {can't unset "a(14)": variable isn't array}} test set-old-7.5 {unset command} { catch {unset a} set a(0) xx list [catch {unset a(14)} msg] $msg } {1 {can't unset "a(14)": no such element in array}} test set-old-7.6 {unset command} { catch {unset a}; catch {unset b}; catch {unset c} set a foo set c gorp list [catch {unset a a a(14)} msg] $msg [info exists c] } {1 {can't unset "a": no such variable} 1} test set-old-7.7 {unsetting globals from within procedures} { set y 0 proc p1 {} { global y set z [p2] return [list $z [catch {set y} msg] $msg] } proc p2 {} {global y; unset y; list [catch {set y} msg] $msg} p1 } {{1 {can't read "y": no such variable}} 1 {can't read "y": no such variable}} test set-old-7.8 {unsetting globals from within procedures} { set y 0 proc p1 {} { global y p2 return [list [catch {set y 44} msg] $msg] } proc p2 {} {global y; unset y} concat [p1] [list [catch {set y} msg] $msg] } {0 44 0 44} test set-old-7.9 {unsetting globals from within procedures} { set y 0 proc p1 {} { global y unset y return [list [catch {set y 55} msg] $msg] } concat [p1] [list [catch {set y} msg] $msg] } {0 55 0 55} test set-old-7.10 {unset command} { catch {unset a} set a(14) 22 unset a(14) list [catch {set a(14)} msg] $msg [catch {array names a} msg2] $msg2 } {1 {can't read "a(14)": no such element in array} 0 {}} test set-old-7.11 {unset command} { catch {unset a} set a(14) 22 unset a list [catch {set a(14)} msg] $msg [catch {array names a} msg2] $msg2 } {1 {can't read "a(14)": no such variable} 0 {}} test set-old-7.12 {unset command, -nocomplain} { catch {unset a} list [info exists a] [catch {unset -nocomplain a}] [info exists a] } {0 0 0} test set-old-7.13 {unset command, -nocomplain} { set -nocomplain abc list [info exists -nocomplain] [catch {unset -nocomplain}] \ [info exists -nocomplain] [catch {unset -- -nocomplain}] \ [info exists -nocomplain] } {1 0 1 0 0} test set-old-7.14 {unset command, --} { set -- abc list [info exists --] [catch {unset --}] \ [info exists --] [catch {unset -- --}] \ [info exists --] } {1 0 1 0 0} test set-old-7.15 {unset command, -nocomplain} { set -nocomplain abc set -- abc list [info exists -nocomplain] [catch {unset -- -nocomplain}] \ [info exists -nocomplain] [info exists --] \ [catch {unset -- -nocomplain}] [info exists --] \ [catch {unset -- --}] [info exists --] } {1 0 0 1 1 1 0 0} test set-old-7.16 {unset command, -nocomplain} { set -nocomplain abc set var abc list [info exists bogus] [catch {unset -nocomplain bogus var bogus}] \ [info exists -nocomplain] [info exists var] \ [catch {unset -nocomplain -nocomplain}] [info exists -nocomplain] } {0 0 1 0 0 0} test set-old-7.17 {unset command, -nocomplain (no abbreviation)} { set -nocomp abc list [info exists -nocomp] [catch {unset -nocomp}] [info exists -nocomp] } {1 0 0} test set-old-7.18 {unset command, -nocomplain (no abbreviation)} { catch {unset -nocomp} list [info exists -nocomp] [catch {unset -nocomp}] } {0 1} # Array command. test set-old-8.1 {array command} { list [catch {array} msg] $msg } {1 {wrong # args: should be "array option arrayName ?arg ...?"}} test set-old-8.2 {array command} { list [catch {array a} msg] $msg } {1 {wrong # args: should be "array option arrayName ?arg ...?"}} test set-old-8.3 {array command} { catch {unset a} list [catch {array anymore a b} msg] $msg } {1 {"a" isn't an array}} test set-old-8.4 {array command} { catch {unset a} set a 44 list [catch {array anymore a b} msg] $msg } {1 {"a" isn't an array}} test set-old-8.5 {array command} { proc foo {} { set a 44 upvar 0 a x list [catch {array anymore x b} msg] $msg } foo } {1 {"x" isn't an array}} test set-old-8.6 {array command} { catch {unset a} set a(22) 3 list [catch {array gorp a} msg] $msg } {1 {bad option "gorp": must be anymore, donesearch, exists, get, names, nextelement, set, size, startsearch, statistics, or unset}} test set-old-8.7 {array command, anymore option} { catch {unset a} list [catch {array anymore a x} msg] $msg } {1 {"a" isn't an array}} test set-old-8.8 {array command, anymore option, array doesn't exist yet but has compiler-allocated procedure slot} { proc foo {x} { if {$x==1} { return [array anymore a x] } set a(x) 123 } list [catch {foo 1} msg] $msg } {1 {"a" isn't an array}} test set-old-8.9 {array command, donesearch option} { catch {unset a} list [catch {array donesearch a x} msg] $msg } {1 {"a" isn't an array}} test set-old-8.10 {array command, donesearch option, array doesn't exist yet but has compiler-allocated procedure slot} { proc foo {x} { if {$x==1} { return [array donesearch a x] } set a(x) 123 } list [catch {foo 1} msg] $msg } {1 {"a" isn't an array}} test set-old-8.11 {array command, exists option} { list [catch {array exists a b} msg] $msg } {1 {wrong # args: should be "array exists arrayName"}} test set-old-8.12 {array command, exists option} { catch {unset a} array exists a } {0} test set-old-8.13 {array command, exists option} { catch {unset a} set a(0) 1 array exists a } {1} test set-old-8.14 {array command, exists option, array doesn't exist yet but has compiler-allocated procedure slot} { proc foo {x} { if {$x==1} { return [array exists a] } set a(x) 123 } list [catch {foo 1} msg] $msg } {0 0} test set-old-8.15 {array command, get option} { list [catch {array get} msg] $msg } {1 {wrong # args: should be "array option arrayName ?arg ...?"}} test set-old-8.16 {array command, get option} { list [catch {array get a b c} msg] $msg } {1 {wrong # args: should be "array get arrayName ?pattern?"}} test set-old-8.17 {array command, get option} { catch {unset a} array get a } {} test set-old-8.18 {array command, get option} { catch {unset a} set a(22) 3 set {a(long name)} {} lsort [array get a] } {{} 22 3 {long name}} test set-old-8.19 {array command, get option (unset variable)} { catch {unset a} set a(x) 3 trace var a(y) w ignore array get a } {x 3} test set-old-8.20 {array command, get option, with pattern} { catch {unset a} set a(x1) 3 set a(x2) 4 set a(x3) 5 set a(b1) 24 set a(b2) 25 lsort [array get a x*] } {3 4 5 x1 x2 x3} test set-old-8.21 {array command, get option, array doesn't exist yet but has compiler-allocated procedure slot} { proc foo {x} { if {$x==1} { return [array get a] } set a(x) 123 } list [catch {foo 1} msg] $msg } {0 {}} test set-old-8.22 {array command, names option} { catch {unset a} set a(22) 3 list [catch {array names a 4 5} msg] $msg } {1 {bad option "4": must be -exact, -glob, or -regexp}} test set-old-8.23 {array command, names option} { catch {unset a} array names a } {} test set-old-8.24 {array command, names option} { catch {unset a} set a(22) 3; set a(Textual_name) 44; set "a(name with spaces)" xxx list [catch {lsort [array names a]} msg] $msg } {0 {22 Textual_name {name with spaces}}} test set-old-8.25 {array command, names option} { catch {unset a} set a(22) 3; set a(33) 44; trace var a(xxx) w ignore list [catch {lsort [array names a]} msg] $msg } {0 {22 33}} test set-old-8.26 {array command, names option} { catch {unset a} set a(22) 3; set a(33) 44; trace var a(xxx) w ignore set a(xxx) value list [catch {lsort [array names a]} msg] $msg } {0 {22 33 xxx}} test set-old-8.27 {array command, names option} { catch {unset a} set a(axy) 3 set a(bxy) 44 set a(no) yes set a(xxx) value list [lsort [array names a *xy]] [lsort [array names a]] } {{axy bxy} {axy bxy no xxx}} test set-old-8.28 {array command, names option, array doesn't exist yet but has compiler-allocated procedure slot} { proc foo {x} { if {$x==1} { return [array names a] } set a(x) 123 } list [catch {foo 1} msg] $msg } {0 {}} test set-old-8.29 {array command, nextelement option} { list [catch {array nextelement a} msg] $msg } {1 {wrong # args: should be "array nextelement arrayName searchId"}} test set-old-8.30 {array command, nextelement option} { catch {unset a} list [catch {array nextelement a b} msg] $msg } {1 {"a" isn't an array}} test set-old-8.31 {array command, nextelement option, array doesn't exist yet but has compiler-allocated procedure slot} { proc foo {x} { if {$x==1} { return [array nextelement a b] } set a(x) 123 } list [catch {foo 1} msg] $msg } {1 {"a" isn't an array}} test set-old-8.32 {array command, set option} { list [catch {array set a} msg] $msg } {1 {wrong # args: should be "array set arrayName list"}} test set-old-8.33 {array command, set option} { list [catch {array set a 1 2} msg] $msg } {1 {wrong # args: should be "array set arrayName list"}} test set-old-8.34 {array command, set option} { list [catch {array set a "a \{ c"} msg] $msg } {1 {unmatched open brace in list}} test set-old-8.35 {array command, set option} { catch {unset a} set a 44 list [catch {array set a {a b c d}} msg] $msg } {1 {can't set "a(a)": variable isn't array}} test set-old-8.36 {array command, set option} { catch {unset a} set a(xx) yy array set a {b c d e} lsort [array get a] } {b c d e xx yy} test set-old-8.37 {array command, set option, array doesn't exist yet but has compiler-allocated procedure slot} { proc foo {x} { if {$x==1} { return [array set a {x 0}] } set a(x) } list [catch {foo 1} msg] $msg } {0 {}} test set-old-8.38 {array command, set option} { catch {unset aVaRnAmE} array set aVaRnAmE {} list [info exists aVaRnAmE] [catch {set aVaRnAmE} msg] $msg } {1 1 {can't read "aVaRnAmE": variable is array}} test set-old-8.38.1 {array command, set scalar} { catch {unset aVaRnAmE} set aVaRnAmE 1 list [catch {array set aVaRnAmE {}} msg] $msg } {1 {can't array set "aVaRnAmE": variable isn't array}} test set-old-8.38.2 {array command, set alias} { catch {unset aVaRnAmE} upvar 0 aVaRnAmE anAliAs array set anAliAs {} list [array exists aVaRnAmE] [catch {set anAliAs} msg] $msg } {1 1 {can't read "anAliAs": variable is array}} test set-old-8.38.3 {array command, set element alias} { catch {unset aVaRnAmE} list [catch {upvar 0 aVaRnAmE(elem) elemAliAs}] \ [catch {array set elemAliAs {}} msg] $msg } {0 1 {can't array set "elemAliAs": variable isn't array}} test set-old-8.38.4 {array command, empty set with populated array} { catch {unset aVaRnAmE} array set aVaRnAmE [list e1 v1 e2 v2] array set aVaRnAmE {} array set aVaRnAmE [list e3 v3] list [lsort [array names aVaRnAmE]] [catch {set aVaRnAmE(e2)} msg] $msg } {{e1 e2 e3} 0 v2} test set-old-8.38.5 {array command, set with non-existent namespace} { list [catch {array set bogusnamespace::var {}} msg] $msg } {1 {can't set "bogusnamespace::var": parent namespace doesn't exist}} test set-old-8.38.6 {array command, set with non-existent namespace} { list [catch {array set bogusnamespace::var {a b}} msg] $msg } {1 {can't set "bogusnamespace::var": parent namespace doesn't exist}} test set-old-8.38.7 {array command, set with non-existent namespace} { list [catch {array set bogusnamespace::var(0) {a b}} msg] $msg } {1 {can't set "bogusnamespace::var(0)": variable isn't array}} test set-old-8.39 {array command, size option} { catch {unset a} array size a } {0} test set-old-8.40 {array command, size option} { list [catch {array size a 4} msg] $msg } {1 {wrong # args: should be "array size arrayName"}} test set-old-8.41 {array command, size option} { catch {unset a} array size a } {0} test set-old-8.42 {array command, size option} { catch {unset a} set a(22) 3; set a(Textual_name) 44; set "a(name with spaces)" xxx list [catch {array size a} msg] $msg } {0 3} test set-old-8.43 {array command, size option} { catch {unset a} set a(22) 3; set a(xx) 44; set a(y) xxx unset a(22) a(y) a(xx) list [catch {array size a} msg] $msg } {0 0} test set-old-8.44 {array command, size option} { catch {unset a} set a(22) 3; trace var a(33) rwu ignore list [catch {array size a} msg] $msg } {0 1} test set-old-8.45 {array command, size option, array doesn't exist yet but has compiler-allocated procedure slot} { proc foo {x} { if {$x==1} { return [array size a] } set a(x) 123 } list [catch {foo 1} msg] $msg } {0 0} test set-old-8.46 {array command, startsearch option} { list [catch {array startsearch a b} msg] $msg } {1 {wrong # args: should be "array startsearch arrayName"}} test set-old-8.47 {array command, startsearch option} { catch {unset a} list [catch {array startsearch a} msg] $msg } {1 {"a" isn't an array}} test set-old-8.48 {array command, startsearch option, array doesn't exist yet but has compiler-allocated procedure slot} { catch {rename p ""} proc p {x} { if {$x==1} { return [array startsearch a] } set a(x) 123 } list [catch {p 1} msg] $msg } {1 {"a" isn't an array}} test set-old-8.49 {array command, statistics option} { catch {unset a} set a(abc) 1 set a(def) 2 set a(ghi) 3 set a(jkl) 4 set a(mno) 5 set a(pqr) 6 set a(stu) 7 set a(vwx) 8 set a(yz) 9 array statistics a } "9 entries in table, 4 buckets number of buckets with 0 entries: 0 number of buckets with 1 entries: 0 number of buckets with 2 entries: 3 number of buckets with 3 entries: 1 number of buckets with 4 entries: 0 number of buckets with 5 entries: 0 number of buckets with 6 entries: 0 number of buckets with 7 entries: 0 number of buckets with 8 entries: 0 number of buckets with 9 entries: 0 number of buckets with 10 or more entries: 0 average search distance for entry: 1.7" test set-old-8.50 {array command, array names -exact on glob pattern} { catch {unset a} set a(1*2) 1 list [catch {array names a -exact 1*2} msg] $msg } {0 1*2} test set-old-8.51 {array command, array names -glob on glob pattern} { catch {unset a} set a(1*2) 1 set a(12) 1 set a(11) 1 list [catch {lsort [array names a -glob 1*2]} msg] $msg } {0 {1*2 12}} test set-old-8.52 {array command, array names -regexp on regexp pattern} { catch {unset a} set a(1*2) 1 set a(12) 1 set a(11) 1 list [catch {lsort [array names a -regexp ^1]} msg] $msg } {0 {1*2 11 12}} test set-old-8.53 {array command, array names -regexp} { catch {unset a} set a(-glob) 1 set a(-regexp) 1 set a(-exact) 1 list [catch {array names a -regexp} msg] $msg } {0 -regexp} test set-old-8.54 {array command, array names -exact} { catch {unset a} set a(-glob) 1 set a(-regexp) 1 set a(-exact) 1 list [catch {array names a -exact} msg] $msg } {0 -exact} test set-old-8.55 {array command, array names -glob} { catch {unset a} set a(-glob) 1 set a(-regexp) 1 set a(-exact) 1 list [catch {array names a -glob} msg] $msg } {0 -glob} test set-old-8.56 {array command, array statistics on a non-array} { catch {unset a} list [catch {array statistics a} msg] $msg } [list 1 "\"a\" isn't an array"] test set-old-9.1 {ids for array enumeration} { catch {unset a} set a(a) 1 list [array star a] [array star a] [array done a s-1-a; array star a] \ [array done a s-2-a; array d a s-3-a; array start a] } {s-1-a s-2-a s-3-a s-1-a} test set-old-9.2 {array enumeration} { catch {unset a} set a(a) 1 set a(b) 1 set a(c) 1 set x [array startsearch a] lsort [list [array nextelement a $x] [array ne a $x] [array next a $x] \ [array next a $x] [array next a $x]] } {{} {} a b c} test set-old-9.3 {array enumeration} { catch {unset a} set a(a) 1 set a(b) 1 set a(c) 1 set x [array startsearch a] set y [array startsearch a] set z [array startsearch a] lsort [list [array nextelement a $x] [array ne a $x] \ [array next a $y] [array next a $z] [array next a $y] \ [array next a $z] [array next a $y] [array next a $z] \ [array next a $y] [array next a $z] [array next a $x] \ [array next a $x]] } {{} {} {} a a a b b b c c c} test set-old-9.4 {array enumeration: stopping searches} { catch {unset a} set a(a) 1 set a(b) 1 set a(c) 1 set x [array startsearch a] set y [array startsearch a] set z [array startsearch a] lsort [list [array next a $x] [array next a $x] [array next a $y] \ [array done a $z; array next a $x] \ [array done a $x; array next a $y] [array next a $y]] } {a a b b c c} test set-old-9.5 {array enumeration: stopping searches} { catch {unset a} set a(a) 1 set x [array startsearch a] array done a $x list [catch {array next a $x} msg] $msg } {1 {couldn't find search "s-1-a"}} test set-old-9.6 {array enumeration: searches automatically stopped} { catch {unset a} set a(a) 1 set x [array startsearch a] set y [array startsearch a] set a(b) 1 list [catch {array next a $x} msg] $msg \ [catch {array next a $y} msg2] $msg2 } {1 {couldn't find search "s-1-a"} 1 {couldn't find search "s-2-a"}} test set-old-9.7 {array enumeration: searches automatically stopped} { catch {unset a} set a(a) 1 set x [array startsearch a] set y [array startsearch a] set a(a) 2 list [catch {array next a $x} msg] $msg \ [catch {array next a $y} msg2] $msg2 } {0 a 0 a} test set-old-9.8 {array enumeration: searches automatically stopped} { catch {unset a} set a(a) 1 set a(c) 2 set x [array startsearch a] set y [array startsearch a] catch {unset a(c)} list [catch {array next a $x} msg] $msg \ [catch {array next a $y} msg2] $msg2 } {1 {couldn't find search "s-1-a"} 1 {couldn't find search "s-2-a"}} test set-old-9.9 {array enumeration: searches automatically stopped} { catch {unset a} set a(a) 1 set x [array startsearch a] set y [array startsearch a] catch {unset a(c)} list [catch {array next a $x} msg] $msg \ [catch {array next a $y} msg2] $msg2 } {0 a 0 a} test set-old-9.10 {array enumeration: searches automatically stopped} { catch {unset a} set a(a) 1 set x [array startsearch a] set y [array startsearch a] trace var a(b) r {} list [catch {array next a $x} msg] $msg \ [catch {array next a $y} msg2] $msg2 } {1 {couldn't find search "s-1-a"} 1 {couldn't find search "s-2-a"}} test set-old-9.11 {array enumeration: searches automatically stopped} { catch {unset a} set a(a) 1 set x [array startsearch a] set y [array startsearch a] trace var a(a) r {} list [catch {array next a $x} msg] $msg \ [catch {array next a $y} msg2] $msg2 } {0 a 0 a} test set-old-9.12 {array enumeration with traced undefined elements} { catch {unset a} set a(a) 1 trace var a(b) r {} set x [array startsearch a] lsort [list [array next a $x] [array next a $x]] } {{} a} test set-old-10.1 {array enumeration errors} { list [catch {array start} msg] $msg } {1 {wrong # args: should be "array option arrayName ?arg ...?"}} test set-old-10.2 {array enumeration errors} { list [catch {array start a b} msg] $msg } {1 {wrong # args: should be "array startsearch arrayName"}} test set-old-10.3 {array enumeration errors} { catch {unset a} list [catch {array start a} msg] $msg } {1 {"a" isn't an array}} test set-old-10.4 {array enumeration errors} { catch {unset a} set a(a) 1 set x [array startsearch a] list [catch {array next a} msg] $msg } {1 {wrong # args: should be "array nextelement arrayName searchId"}} test set-old-10.5 {array enumeration errors} { catch {unset a} set a(a) 1 set x [array startsearch a] list [catch {array next a b c} msg] $msg } {1 {wrong # args: should be "array nextelement arrayName searchId"}} test set-old-10.6 {array enumeration errors} { catch {unset a} set a(a) 1 set x [array startsearch a] list [catch {array next a a-1-a} msg] $msg } {1 {illegal search identifier "a-1-a"}} test set-old-10.7 {array enumeration errors} { catch {unset a} set a(a) 1 set x [array startsearch a] list [catch {array next a sx1-a} msg] $msg } {1 {illegal search identifier "sx1-a"}} test set-old-10.8 {array enumeration errors} { catch {unset a} set a(a) 1 set x [array startsearch a] list [catch {array next a s--a} msg] $msg } {1 {illegal search identifier "s--a"}} test set-old-10.9 {array enumeration errors} { catch {unset a} set a(a) 1 set x [array startsearch a] list [catch {array next a s-1-b} msg] $msg } {1 {search identifier "s-1-b" isn't for variable "a"}} test set-old-10.10 {array enumeration errors} { catch {unset a} set a(a) 1 set x [array startsearch a] list [catch {array next a s-1ba} msg] $msg } {1 {illegal search identifier "s-1ba"}} test set-old-10.11 {array enumeration errors} { catch {unset a} set a(a) 1 set x [array startsearch a] list [catch {array next a s-2-a} msg] $msg } {1 {couldn't find search "s-2-a"}} test set-old-10.12 {array enumeration errors} { list [catch {array done a} msg] $msg } {1 {wrong # args: should be "array donesearch arrayName searchId"}} test set-old-10.13 {array enumeration errors} { list [catch {array done a b c} msg] $msg } {1 {wrong # args: should be "array donesearch arrayName searchId"}} test set-old-10.14 {array enumeration errors} { list [catch {array done a b} msg] $msg } {1 {illegal search identifier "b"}} test set-old-10.15 {array enumeration errors} { list [catch {array anymore a} msg] $msg } {1 {wrong # args: should be "array anymore arrayName searchId"}} test set-old-10.16 {array enumeration errors} { list [catch {array any a b c} msg] $msg } {1 {wrong # args: should be "array anymore arrayName searchId"}} test set-old-10.17 {array enumeration errors} { catch {unset a} set a(0) 44 list [catch {array any a bogus} msg] $msg } {1 {illegal search identifier "bogus"}} # Array enumeration with "anymore" option test set-old-11.1 {array anymore option} { catch {unset a} set a(a) 1 set a(b) 2 set a(c) 3 array startsearch a lsort [list [array anymore a s-1-a] [array next a s-1-a] \ [array anymore a s-1-a] [array next a s-1-a] \ [array anymore a s-1-a] [array next a s-1-a] \ [array anymore a s-1-a] [array next a s-1-a]] } {{} 0 1 1 1 a b c} test set-old-11.2 {array anymore option} { catch {unset a} set a(a) 1 set a(b) 2 set a(c) 3 array startsearch a lsort [list [array next a s-1-a] [array next a s-1-a] \ [array anymore a s-1-a] [array next a s-1-a] \ [array next a s-1-a] [array anymore a s-1-a]] } {{} 0 1 a b c} # Special check to see that the value of a variable is handled correctly # if it is returned as the result of a procedure (must not free the variable # string while deleting the call frame). Errors will only be detected if # a memory consistency checker such as Purify is being used. test set-old-12.1 {cleanup on procedure return} { proc foo {} { set x 12345 } foo } 12345 test set-old-12.2 {cleanup on procedure return} { proc foo {} { set x(1) 23456 } foo } 23456 # Must delete variables when done, since these arrays get used as # scalars by other tests. catch {unset a} catch {unset b} catch {unset c} catch {unset aVaRnAmE} # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/socket.test0000644003604700454610000013010512052456744014251 0ustar dgp771div# Commands tested in this file: socket. # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1994-1996 Sun Microsystems, Inc. # Copyright (c) 1998-2000 Ajuba Solutions. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # Running socket tests with a remote server: # ------------------------------------------ # # Some tests in socket.test depend on the existence of a remote server to # which they connect. The remote server must be an instance of tcltest and it # must run the script found in the file "remote.tcl" in this directory. You # can start the remote server on any machine reachable from the machine on # which you want to run the socket tests, by issuing: # # tcltest remote.tcl -port 2048 # Or choose another port number. # # If the machine you are running the remote server on has several IP # interfaces, you can choose which interface the server listens on for # connections by specifying the -address command line flag, so: # # tcltest remote.tcl -address your.machine.com # # These options can also be set by environment variables. On Unix, you can # type these commands to the shell from which the remote server is started: # # shell% setenv serverPort 2048 # shell% setenv serverAddress your.machine.com # # and subsequently you can start the remote server with: # # tcltest remote.tcl # # to have it listen on port 2048 on the interface your.machine.com. # # When the server starts, it prints out a detailed message containing its # configuration information, and it will block until killed with a Ctrl-C. # Once the remote server exists, you can run the tests in socket.test with # the server by setting two Tcl variables: # # % set remoteServerIP # % set remoteServerPort 2048 # # These variables are also settable from the environment. On Unix, you can: # # shell% setenv remoteServerIP machine.where.server.runs # shell% senetv remoteServerPort 2048 # # The preamble of the socket.test file checks to see if the variables are set # either in Tcl or in the environment; if they are, it attempts to connect to # the server. If the connection is successful, the tests using the remote # server will be performed; otherwise, it will attempt to start the remote # server (via exec) on platforms that support this, on the local host, # listening at port 2048. If all fails, a message is printed and the tests # using the remote server are not performed. package require tcltest 2 namespace import -force ::tcltest::* # Some tests require the testthread and exec commands testConstraint testthread [llength [info commands testthread]] testConstraint exec [llength [info commands exec]] # If remoteServerIP or remoteServerPort are not set, check in the # environment variables for externally set values. # if {![info exists remoteServerIP]} { if {[info exists env(remoteServerIP)]} { set remoteServerIP $env(remoteServerIP) } } if {![info exists remoteServerPort]} { if {[info exists env(remoteServerIP)]} { set remoteServerPort $env(remoteServerPort) } else { if {[info exists remoteServerIP]} { set remoteServerPort 2048 } } } # # Check if we're supposed to do tests against the remote server # set doTestsWithRemoteServer 1 if {![info exists remoteServerIP]} { set remoteServerIP 127.0.0.1 } if {($doTestsWithRemoteServer == 1) && (![info exists remoteServerPort])} { set remoteServerPort 2048 } # Attempt to connect to a remote server if one is already running. If it # is not running or for some other reason the connect fails, attempt to # start the remote server on the local host listening on port 2048. This # is only done on platforms that support exec (i.e. not on the Mac). On # platforms that do not support exec, the remote server must be started # by the user before running the tests. set remoteProcChan "" set commandSocket "" if {$doTestsWithRemoteServer} { catch {close $commandSocket} if {[catch {set commandSocket [socket $remoteServerIP \ $remoteServerPort]}] != 0} { if {[info commands exec] == ""} { set noRemoteTestReason "can't exec" set doTestsWithRemoteServer 0 } else { set remoteServerIP 127.0.0.1 # Be *extra* careful in case this file is sourced from # a directory other than the current one... set remoteFile [file join [pwd] [file dirname [info script]] \ remote.tcl] if {[catch {set remoteProcChan \ [open "|[list [interpreter] $remoteFile \ -serverIsSilent \ -port $remoteServerPort \ -address $remoteServerIP]" \ w+]} \ msg] == 0} { after 1000 if {[catch {set commandSocket [socket $remoteServerIP \ $remoteServerPort]} msg] == 0} { fconfigure $commandSocket -translation crlf -buffering line } else { set noRemoteTestReason $msg set doTestsWithRemoteServer 0 } } else { set noRemoteTestReason "$msg [interpreter]" set doTestsWithRemoteServer 0 } } } else { fconfigure $commandSocket -translation crlf -buffering line } } # Some tests are run only if we are doing testing against a remote server. set ::tcltest::testConstraints(doTestsWithRemoteServer) $doTestsWithRemoteServer if {$doTestsWithRemoteServer == 0} { if {[string first s $::tcltest::verbose] != -1} { puts "Skipping tests with remote server. See tests/socket.test for" puts "information on how to run remote server." puts "Reason for not doing remote tests: $noRemoteTestReason" } } # # If we do the tests, define a command to send a command to the # remote server. # if {$doTestsWithRemoteServer == 1} { proc sendCommand {c} { global commandSocket if {[eof $commandSocket]} { error "remote server disappeared" } if {[catch {puts $commandSocket $c} msg]} { error "remote server disappaered: $msg" } if {[catch {puts $commandSocket "--Marker--Marker--Marker--"} msg]} { error "remote server disappeared: $msg" } set resp "" while {1} { set line [gets $commandSocket] if {[eof $commandSocket]} { error "remote server disappaered" } if {[string compare $line "--Marker--Marker--Marker--"] == 0} { if {[string compare [lindex $resp 0] error] == 0} { error [lindex $resp 1] } else { return [lindex $resp 1] } } else { append resp $line "\n" } } } } test socket-1.1 {arg parsing for socket command} {socket} { list [catch {socket -server} msg] $msg } {1 {no argument given for -server option}} test socket-1.2 {arg parsing for socket command} {socket} { list [catch {socket -server foo} msg] $msg } {1 {wrong # args: should be either: socket ?-myaddr addr? ?-myport myport? ?-async? host port socket -server command ?-myaddr addr? port}} test socket-1.3 {arg parsing for socket command} {socket} { list [catch {socket -myaddr} msg] $msg } {1 {no argument given for -myaddr option}} test socket-1.4 {arg parsing for socket command} {socket} { list [catch {socket -myaddr 127.0.0.1} msg] $msg } {1 {wrong # args: should be either: socket ?-myaddr addr? ?-myport myport? ?-async? host port socket -server command ?-myaddr addr? port}} test socket-1.5 {arg parsing for socket command} {socket} { list [catch {socket -myport} msg] $msg } {1 {no argument given for -myport option}} test socket-1.6 {arg parsing for socket command} {socket} { list [catch {socket -myport xxxx} msg] $msg } {1 {expected integer but got "xxxx"}} test socket-1.7 {arg parsing for socket command} {socket} { list [catch {socket -myport 2522} msg] $msg } {1 {wrong # args: should be either: socket ?-myaddr addr? ?-myport myport? ?-async? host port socket -server command ?-myaddr addr? port}} test socket-1.8 {arg parsing for socket command} {socket} { list [catch {socket -froboz} msg] $msg } {1 {bad option "-froboz": must be -async, -myaddr, -myport, or -server}} test socket-1.9 {arg parsing for socket command} {socket} { list [catch {socket -server foo -myport 2521 3333} msg] $msg } {1 {Option -myport is not valid for servers}} test socket-1.10 {arg parsing for socket command} {socket} { list [catch {socket host 2528 -junk} msg] $msg } {1 {wrong # args: should be either: socket ?-myaddr addr? ?-myport myport? ?-async? host port socket -server command ?-myaddr addr? port}} test socket-1.11 {arg parsing for socket command} {socket} { list [catch {socket -server callback 2520 --} msg] $msg } {1 {wrong # args: should be either: socket ?-myaddr addr? ?-myport myport? ?-async? host port socket -server command ?-myaddr addr? port}} test socket-1.12 {arg parsing for socket command} {socket} { list [catch {socket foo badport} msg] $msg } {1 {expected integer but got "badport"}} test socket-1.13 {arg parsing for socket command} {socket} { list [catch {socket -async -server} msg] $msg } {1 {cannot set -async option for server sockets}} test socket-1.14 {arg parsing for socket command} {socket} { list [catch {socket -server foo -async} msg] $msg } {1 {cannot set -async option for server sockets}} set path(script) [makeFile {} script] test socket-2.1 {tcp connection} {socket stdio} { file delete $path(script) set f [open $path(script) w] puts $f { set timer [after 10000 "set x timed_out"] set f [socket -server accept 0] proc accept {file addr port} { global x set x done close $file } puts ready puts [lindex [fconfigure $f -sockname] 2] vwait x after cancel $timer close $f puts $x } close $f set f [open "|[list [interpreter] $path(script)]" r] gets $f x gets $f listen if {[catch {socket 127.0.0.1 $listen} msg]} { set x $msg } else { lappend x [gets $f] close $msg } lappend x [gets $f] close $f set x } {ready done {}} if [info exists port] { incr port } else { set port [expr 2048 + [pid]%1024] } test socket-2.2 {tcp connection with client port specified} {socket stdio} { file delete $path(script) set f [open $path(script) w] puts $f { set timer [after 10000 "set x timeout"] set f [socket -server accept 0] proc accept {file addr port} { global x puts "[gets $file] $port" close $file set x done } puts ready puts [lindex [fconfigure $f -sockname] 2] vwait x after cancel $timer close $f } close $f set f [open "|[list [interpreter] $path(script)]" r] gets $f x gets $f listen global port if {[catch {socket -myport $port 127.0.0.1 $listen} sock]} { set x $sock close [socket 127.0.0.1 $listen] puts stderr $sock } else { puts $sock hello flush $sock lappend x [gets $f] close $sock } close $f set x } [list ready "hello $port"] test socket-2.3 {tcp connection with client interface specified} {socket stdio} { file delete $path(script) set f [open $path(script) w] puts $f { set timer [after 2000 "set x done"] set f [socket -server accept 2830] proc accept {file addr port} { global x puts "[gets $file] $addr" close $file set x done } puts ready vwait x after cancel $timer close $f } close $f set f [open "|[list [interpreter] $path(script)]" r] gets $f x if {[catch {socket -myaddr 127.0.0.1 127.0.0.1 2830} sock]} { set x $sock } else { puts $sock hello flush $sock lappend x [gets $f] close $sock } close $f set x } {ready {hello 127.0.0.1}} test socket-2.4 {tcp connection with server interface specified} {socket stdio} { file delete $path(script) set f [open $path(script) w] puts $f { set timer [after 2000 "set x done"] set f [socket -server accept -myaddr 127.0.0.1 0] proc accept {file addr port} { global x puts "[gets $file]" close $file set x done } puts ready puts [lindex [fconfigure $f -sockname] 2] vwait x after cancel $timer close $f } close $f set f [open "|[list [interpreter] $path(script)]" r] gets $f x gets $f listen if {[catch {socket 127.0.0.1 $listen} sock]} { set x $sock } else { puts $sock hello flush $sock lappend x [gets $f] close $sock } close $f set x } {ready hello} test socket-2.5 {tcp connection with redundant server port} {socket stdio} { file delete $path(script) set f [open $path(script) w] puts $f { set timer [after 10000 "set x timeout"] set f [socket -server accept 0] proc accept {file addr port} { global x puts "[gets $file]" close $file set x done } puts ready puts [lindex [fconfigure $f -sockname] 2] vwait x after cancel $timer close $f } close $f set f [open "|[list [interpreter] $path(script)]" r] gets $f x gets $f listen if {[catch {socket 127.0.0.1 $listen} sock]} { set x $sock } else { puts $sock hello flush $sock lappend x [gets $f] close $sock } close $f set x } {ready hello} test socket-2.6 {tcp connection} {socket} { set status ok if {![catch {set sock [socket 127.0.0.1 2833]}]} { if {![catch {gets $sock}]} { set status broken } close $sock } set status } ok test socket-2.7 {echo server, one line} {socket stdio} { file delete $path(script) set f [open $path(script) w] puts $f { set timer [after 10000 "set x timeout"] set f [socket -server accept 0] proc accept {s a p} { fileevent $s readable [list echo $s] fconfigure $s -translation lf -buffering line } proc echo {s} { set l [gets $s] if {[eof $s]} { global x close $s set x done } else { puts $s $l } } puts ready puts [lindex [fconfigure $f -sockname] 2] vwait x after cancel $timer close $f puts $x } close $f set f [open "|[list [interpreter] $path(script)]" r] gets $f gets $f listen set s [socket 127.0.0.1 $listen] fconfigure $s -buffering line -translation lf puts $s "hello abcdefghijklmnop" after 1000 set x [gets $s] close $s set y [gets $f] close $f list $x $y } {{hello abcdefghijklmnop} done} removeFile script test socket-2.8 {echo server, loop 50 times, single connection} -constraints {socket stdio} -setup { set path(script) [makeFile { set f [socket -server accept 0] proc accept {s a p} { fileevent $s readable [list echo $s] fconfigure $s -buffering line } proc echo {s} { global i set l [gets $s] if {[eof $s]} { global x close $s set x done } else { incr i puts $s $l } } set i 0 puts ready puts [lindex [fconfigure $f -sockname] 2] set timer [after 20000 "set x done"] vwait x after cancel $timer close $f puts "done $i" } script] } -body { set f [open "|[list [interpreter] $path(script)]" r] gets $f gets $f listen set s [socket 127.0.0.1 $listen] fconfigure $s -buffering line catch { for {set x 0} {$x < 50} {incr x} { puts $s "hello abcdefghijklmnop" gets $s } } close $s catch {set x [gets $f]} close $f set x } -cleanup { removeFile script } -result {done 50} set path(script) [makeFile {} script] test socket-2.9 {socket conflict} {socket stdio} { set s [socket -server accept 0] file delete $path(script) set f [open $path(script) w] puts -nonewline $f "socket -server accept [lindex [fconfigure $s -sockname] 2]" close $f set f [open "|[list [interpreter] $path(script)]" r] gets $f after 100 set x [list [catch {close $f} msg]] regsub "\n.*$" $msg {} msg ; # cut part of the error message containing the port number lappend x $msg close $s set x } {1 {couldn't open socket: address already in use}} test socket-2.10 {close on accept, accepted socket lives} {socket} { set done 0 set timer [after 20000 "set done timed_out"] set ss [socket -server accept 0] proc accept {s a p} { global ss close $ss fileevent $s readable "readit $s" fconfigure $s -trans lf } proc readit {s} { global done gets $s close $s set done 1 } set cs [socket [info hostname] [lindex [fconfigure $ss -sockname] 2]] puts $cs hello close $cs vwait done after cancel $timer set done } 1 test socket-2.11 {detecting new data} {socket} { proc accept {s a p} { global sock set sock $s } set s [socket -server accept 0] set sock "" set s2 [socket 127.0.0.1 [lindex [fconfigure $s -sockname] 2]] vwait sock puts $s2 one flush $s2 after 500 fconfigure $sock -blocking 0 set result a:[gets $sock] lappend result b:[gets $sock] fconfigure $sock -blocking 1 puts $s2 two flush $s2 after 500 fconfigure $sock -blocking 0 lappend result c:[gets $sock] fconfigure $sock -blocking 1 close $s2 close $s close $sock set result } {a:one b: c:two} test socket-3.1 {socket conflict} {socket stdio} { file delete $path(script) set f [open $path(script) w] puts $f { set f [socket -server accept 0] puts ready puts [lindex [fconfigure $f -sockname] 2] gets stdin close $f } close $f set f [open "|[list [interpreter] $path(script)]" r+] gets $f gets $f listen set x [list [catch {socket -server accept $listen} msg] \ $msg] puts $f bye close $f set x } {1 {couldn't open socket: address already in use}} test socket-3.2 {server with several clients} {socket stdio} { file delete $path(script) set f [open $path(script) w] puts $f { set t1 [after 30000 "set x timed_out"] set t2 [after 31000 "set x timed_out"] set t3 [after 32000 "set x timed_out"] set counter 0 set s [socket -server accept 0] proc accept {s a p} { fileevent $s readable [list echo $s] fconfigure $s -buffering line } proc echo {s} { global x set l [gets $s] if {[eof $s]} { close $s set x done } else { puts $s $l } } puts ready puts [lindex [fconfigure $s -sockname] 2] vwait x after cancel $t1 vwait x after cancel $t2 vwait x after cancel $t3 close $s puts $x } close $f set f [open "|[list [interpreter] $path(script)]" r+] set x [gets $f] gets $f listen set s1 [socket 127.0.0.1 $listen] fconfigure $s1 -buffering line set s2 [socket 127.0.0.1 $listen] fconfigure $s2 -buffering line set s3 [socket 127.0.0.1 $listen] fconfigure $s3 -buffering line for {set i 0} {$i < 100} {incr i} { puts $s1 hello,s1 gets $s1 puts $s2 hello,s2 gets $s2 puts $s3 hello,s3 gets $s3 } close $s1 close $s2 close $s3 lappend x [gets $f] close $f set x } {ready done} test socket-4.1 {server with several clients} {socket stdio} { file delete $path(script) set f [open $path(script) w] puts $f { set port [gets stdin] set s [socket 127.0.0.1 $port] fconfigure $s -buffering line for {set i 0} {$i < 100} {incr i} { puts $s hello gets $s } close $s puts bye gets stdin } close $f set p1 [open "|[list [interpreter] $path(script)]" r+] fconfigure $p1 -buffering line set p2 [open "|[list [interpreter] $path(script)]" r+] fconfigure $p2 -buffering line set p3 [open "|[list [interpreter] $path(script)]" r+] fconfigure $p3 -buffering line proc accept {s a p} { fconfigure $s -buffering line fileevent $s readable [list echo $s] } proc echo {s} { global x set l [gets $s] if {[eof $s]} { close $s set x done } else { puts $s $l } } set t1 [after 30000 "set x timed_out"] set t2 [after 31000 "set x timed_out"] set t3 [after 32000 "set x timed_out"] set s [socket -server accept 0] set listen [lindex [fconfigure $s -sockname] 2] puts $p1 $listen puts $p2 $listen puts $p3 $listen vwait x vwait x vwait x after cancel $t1 after cancel $t2 after cancel $t3 close $s set l "" lappend l [list p1 [gets $p1] $x] lappend l [list p2 [gets $p2] $x] lappend l [list p3 [gets $p3] $x] puts $p1 bye puts $p2 bye puts $p3 bye close $p1 close $p2 close $p3 set l } {{p1 bye done} {p2 bye done} {p3 bye done}} test socket-4.2 {byte order problems, socket numbers, htons} {socket} { set x ok if {[catch {socket -server dodo 0x3000} msg]} { set x $msg } else { close $msg } set x } ok test socket-5.1 {byte order problems, socket numbers, htons} \ {socket unixOnly notRoot} { set x {couldn't open socket: not owner} if {![catch {socket -server dodo 0x1} msg]} { set x {htons problem, should be disallowed, are you running as SU?} close $msg } set x } {couldn't open socket: not owner} test socket-5.2 {byte order problems, socket numbers, htons} {socket} { set x {couldn't open socket: port number too high} if {![catch {socket -server dodo 0x10000} msg]} { set x {port resolution problem, should be disallowed} close $msg } set x } {couldn't open socket: port number too high} test socket-5.3 {byte order problems, socket numbers, htons} \ {socket unixOnly notRoot} { set x {couldn't open socket: not owner} if {![catch {socket -server dodo 21} msg]} { set x {htons problem, should be disallowed, are you running as SU?} close $msg } set x } {couldn't open socket: not owner} test socket-6.1 {accept callback error} {socket stdio} { file delete $path(script) set f [open $path(script) w] puts $f { gets stdin port socket 127.0.0.1 $port } close $f set f [open "|[list [interpreter] $path(script)]" r+] proc bgerror args { global x set x $args } proc accept {s a p} {expr 10 / 0} set s [socket -server accept 0] puts $f [lindex [fconfigure $s -sockname] 2] close $f set timer [after 10000 "set x timed_out"] vwait x after cancel $timer close $s rename bgerror {} set x } {{divide by zero}} test socket-7.1 {testing socket specific options} {socket stdio} { file delete $path(script) set f [open $path(script) w] puts $f { set ss [socket -server accept 0] proc accept args { global x set x done } puts ready puts [lindex [fconfigure $ss -sockname] 2] set timer [after 10000 "set x timed_out"] vwait x after cancel $timer } close $f set f [open "|[list [interpreter] $path(script)]" r] gets $f gets $f listen set s [socket 127.0.0.1 $listen] set p [fconfigure $s -peername] close $s close $f set l "" lappend l [string compare [lindex $p 0] 127.0.0.1] lappend l [string compare [lindex $p 2] $listen] lappend l [llength $p] } {0 0 3} test socket-7.2 {testing socket specific options} {socket stdio} { file delete $path(script) set f [open $path(script) w] puts $f { set ss [socket -server accept 2821] proc accept args { global x set x done } puts ready puts [lindex [fconfigure $ss -sockname] 2] set timer [after 10000 "set x timed_out"] vwait x after cancel $timer } close $f set f [open "|[list [interpreter] $path(script)]" r] gets $f gets $f listen set s [socket 127.0.0.1 $listen] set p [fconfigure $s -sockname] close $s close $f list [llength $p] \ [regexp {^(127\.0\.0\.1|0\.0\.0\.0)$} [lindex $p 0]] \ [expr {[lindex $p 2] == $listen}] } {3 1 0} test socket-7.3 {testing socket specific options} {socket} { set s [socket -server accept 0] set l [fconfigure $s] close $s update llength $l } 14 test socket-7.4 {testing socket specific options} {socket} { set s [socket -server accept 0] proc accept {s a p} { global x set x [fconfigure $s -sockname] close $s } set listen [lindex [fconfigure $s -sockname] 2] set s1 [socket [info hostname] $listen] set timer [after 10000 "set x timed_out"] vwait x after cancel $timer close $s close $s1 set l "" lappend l [expr {[lindex $x 2] == $listen}] [llength $x] } {1 3} test socket-7.5 {testing socket specific options} {socket unixOrPc} { set s [socket -server accept 0] proc accept {s a p} { global x set x [fconfigure $s -sockname] close $s } set listen [lindex [fconfigure $s -sockname] 2] set s1 [socket 127.0.0.1 $listen] set timer [after 10000 "set x timed_out"] vwait x after cancel $timer close $s close $s1 set l "" lappend l [lindex $x 0] [expr {[lindex $x 2] == $listen}] [llength $x] } {127.0.0.1 1 3} test socket-8.1 {testing -async flag on sockets} {socket} { # NOTE: This test may fail on some Solaris 2.4 systems. If it does, # check that you have these patches installed (using showrev -p): # # 101907-05, 101925-02, 101945-14, 101959-03, 101969-05, 101973-03, # 101977-03, 101981-02, 101985-01, 102001-03, 102003-01, 102007-01, # 102011-02, 102024-01, 102039-01, 102044-01, 102048-01, 102062-03, # 102066-04, 102070-01, 102105-01, 102153-03, 102216-01, 102232-01, # 101878-03, 101879-01, 101880-03, 101933-01, 101950-01, 102030-01, # 102057-08, 102140-01, 101920-02, 101921-09, 101922-07, 101923-03 # # If after installing these patches you are still experiencing a # problem, please email jyl@eng.sun.com. We have not observed this # failure on Solaris 2.5, so another option (instead of installing # these patches) is to upgrade to Solaris 2.5. set s [socket -server accept 0] proc accept {s a p} { global x puts $s bye close $s set x done } set s1 [socket -async [info hostname] [lindex [fconfigure $s -sockname] 2]] vwait x set z [gets $s1] close $s close $s1 set z } bye test socket-9.1 {testing spurious events} {socket} { set len 0 set spurious 0 set done 0 proc readlittle {s} { global spurious done len set l [read $s 1] if {[string length $l] == 0} { if {![eof $s]} { incr spurious } else { close $s set done 1 } } else { incr len [string length $l] } } proc accept {s a p} { fconfigure $s -buffering none -blocking off fileevent $s readable [list readlittle $s] } set s [socket -server accept 0] set c [socket [info hostname] [lindex [fconfigure $s -sockname] 2]] puts -nonewline $c 01234567890123456789012345678901234567890123456789 close $c set timer [after 10000 "set done timed_out"] vwait done after cancel $timer close $s list $spurious $len } {0 50} test socket-9.2 {testing async write, fileevents, flush on close} {socket} { set firstblock "" for {set i 0} {$i < 5} {incr i} {set firstblock "a$firstblock$firstblock"} set secondblock "" for {set i 0} {$i < 16} {incr i} { set secondblock "b$secondblock$secondblock" } set l [socket -server accept 0] proc accept {s a p} { fconfigure $s -blocking 0 -translation lf -buffersize 16384 \ -buffering line fileevent $s readable "readable $s" } proc readable {s} { set l [gets $s] fileevent $s readable {} after 1000 respond $s } proc respond {s} { global firstblock puts -nonewline $s $firstblock after 1000 writedata $s } proc writedata {s} { global secondblock puts -nonewline $s $secondblock close $s } set s [socket [info hostname] [lindex [fconfigure $l -sockname] 2]] fconfigure $s -blocking 0 -trans lf -buffering line set count 0 puts $s hello proc readit {s} { global count done set l [read $s] incr count [string length $l] if {[eof $s]} { close $s set done 1 } } fileevent $s readable "readit $s" set timer [after 10000 "set done timed_out"] vwait done after cancel $timer close $l set count } 65566 test socket-9.3 {testing EOF stickyness} {socket} { proc count_to_eof {s} { global count done timer set l [gets $s] if {[eof $s]} { incr count if {$count > 9} { close $s set done true set count {eof is sticky} after cancel $timer } } } proc timerproc {} { global done count c set done true set count {timer went off, eof is not sticky} close $c } set count 0 set done false proc write_then_close {s} { puts $s bye close $s } proc accept {s a p} { fconfigure $s -buffering line -translation lf fileevent $s writable "write_then_close $s" } set s [socket -server accept 0] set c [socket [info hostname] [lindex [fconfigure $s -sockname] 2]] fconfigure $c -blocking off -buffering line -translation lf fileevent $c readable "count_to_eof $c" set timer [after 1000 timerproc] vwait done close $s set count } {eof is sticky} removeFile script test socket-10.1 {testing socket accept callback error handling} {socket} { set goterror 0 proc bgerror args {global goterror; set goterror 1} set s [socket -server accept 0] proc accept {s a p} {close $s; error} set c [socket 127.0.0.1 [lindex [fconfigure $s -sockname] 2]] vwait goterror close $s close $c set goterror } 1 test socket-11.1 {tcp connection} {socket doTestsWithRemoteServer} { sendCommand { set socket9_1_test_server [socket -server accept 2834] proc accept {s a p} { puts $s done close $s } } set s [socket $remoteServerIP 2834] set r [gets $s] close $s sendCommand {close $socket9_1_test_server} set r } done test socket-11.2 {client specifies its port} {socket doTestsWithRemoteServer} { if {[info exists port]} { incr port } else { set port [expr 2048 + [pid]%1024] } sendCommand { set socket9_2_test_server [socket -server accept 2835] proc accept {s a p} { puts $s $p close $s } } set s [socket -myport $port $remoteServerIP 2835] set r [gets $s] close $s sendCommand {close $socket9_2_test_server} if {$r == $port} { set result ok } else { set result broken } set result } ok test socket-11.3 {trying to connect, no server} {socket doTestsWithRemoteServer} { set status ok if {![catch {set s [socket $remoteServerIp 2836]}]} { if {![catch {gets $s}]} { set status broken } close $s } set status } ok test socket-11.4 {remote echo, one line} {socket doTestsWithRemoteServer} { sendCommand { set socket10_6_test_server [socket -server accept 2836] proc accept {s a p} { fileevent $s readable [list echo $s] fconfigure $s -buffering line -translation crlf } proc echo {s} { set l [gets $s] if {[eof $s]} { close $s } else { puts $s $l } } } set f [socket $remoteServerIP 2836] fconfigure $f -translation crlf -buffering line puts $f hello set r [gets $f] close $f sendCommand {close $socket10_6_test_server} set r } hello test socket-11.5 {remote echo, 50 lines} {socket doTestsWithRemoteServer} { sendCommand { set socket10_7_test_server [socket -server accept 2836] proc accept {s a p} { fileevent $s readable [list echo $s] fconfigure $s -buffering line -translation crlf } proc echo {s} { set l [gets $s] if {[eof $s]} { close $s } else { puts $s $l } } } set f [socket $remoteServerIP 2836] fconfigure $f -translation crlf -buffering line for {set cnt 0} {$cnt < 50} {incr cnt} { puts $f "hello, $cnt" if {[string compare [gets $f] "hello, $cnt"] != 0} { break } } close $f sendCommand {close $socket10_7_test_server} set cnt } 50 test socket-11.6 {socket conflict} {socket doTestsWithRemoteServer} { set s1 [socket -server accept 2836] if {[catch {set s2 [socket -server accept 2836]} msg]} { set result [list 1 $msg] } else { set result [list 0 [lindex [fconfigure $s2 -sockname] 2]] close $s2 } close $s1 set result } {1 {couldn't open socket: address already in use}} test socket-11.7 {server with several clients} {socket doTestsWithRemoteServer} { sendCommand { set socket10_9_test_server [socket -server accept 2836] proc accept {s a p} { fconfigure $s -buffering line fileevent $s readable [list echo $s] } proc echo {s} { set l [gets $s] if {[eof $s]} { close $s } else { puts $s $l } } } set s1 [socket $remoteServerIP 2836] fconfigure $s1 -buffering line set s2 [socket $remoteServerIP 2836] fconfigure $s2 -buffering line set s3 [socket $remoteServerIP 2836] fconfigure $s3 -buffering line for {set i 0} {$i < 100} {incr i} { puts $s1 hello,s1 gets $s1 puts $s2 hello,s2 gets $s2 puts $s3 hello,s3 gets $s3 } close $s1 close $s2 close $s3 sendCommand {close $socket10_9_test_server} set i } 100 test socket-11.8 {client with several servers} {socket doTestsWithRemoteServer} { sendCommand { set s1 [socket -server "accept 4003" 4003] set s2 [socket -server "accept 4004" 4004] set s3 [socket -server "accept 4005" 4005] proc accept {mp s a p} { puts $s $mp close $s } } set s1 [socket $remoteServerIP 4003] set s2 [socket $remoteServerIP 4004] set s3 [socket $remoteServerIP 4005] set l "" lappend l [gets $s1] [gets $s1] [eof $s1] [gets $s2] [gets $s2] [eof $s2] \ [gets $s3] [gets $s3] [eof $s3] close $s1 close $s2 close $s3 sendCommand { close $s1 close $s2 close $s3 } set l } {4003 {} 1 4004 {} 1 4005 {} 1} test socket-11.9 {accept callback error} {socket doTestsWithRemoteServer} { set s [socket -server accept 2836] proc accept {s a p} {expr 10 / 0} proc bgerror args { global x set x $args } if {[catch {sendCommand { set peername [fconfigure $callerSocket -peername] set s [socket [lindex $peername 0] 2836] close $s }} msg]} { close $s error $msg } set timer [after 10000 "set x timed_out"] vwait x after cancel $timer close $s rename bgerror {} set x } {{divide by zero}} test socket-11.10 {testing socket specific options} {socket doTestsWithRemoteServer} { sendCommand { set socket10_12_test_server [socket -server accept 2836] proc accept {s a p} {close $s} } set s [socket $remoteServerIP 2836] set p [fconfigure $s -peername] set n [fconfigure $s -sockname] set l "" lappend l [lindex $p 2] [llength $p] [llength $p] close $s sendCommand {close $socket10_12_test_server} set l } {2836 3 3} test socket-11.11 {testing spurious events} {socket doTestsWithRemoteServer} { sendCommand { set socket10_13_test_server [socket -server accept 2836] proc accept {s a p} { fconfigure $s -translation "auto lf" after 100 writesome $s } proc writesome {s} { for {set i 0} {$i < 100} {incr i} { puts $s "line $i from remote server" } close $s } } set len 0 set spurious 0 set done 0 proc readlittle {s} { global spurious done len set l [read $s 1] if {[string length $l] == 0} { if {![eof $s]} { incr spurious } else { close $s set done 1 } } else { incr len [string length $l] } } set c [socket $remoteServerIP 2836] fileevent $c readable "readlittle $c" set timer [after 40000 "set done timed_out"] vwait done after cancel $timer sendCommand {close $socket10_13_test_server} list $spurious $len $done } {0 2690 1} test socket-11.12 {testing EOF stickyness} {socket doTestsWithRemoteServer} { set counter 0 set done 0 proc count_up {s} { global counter done after_id set l [gets $s] if {[eof $s]} { incr counter if {$counter > 9} { set done {EOF is sticky} after cancel $after_id close $s } } } proc timed_out {} { global c done set done {timed_out, EOF is not sticky} close $c } sendCommand { set socket10_14_test_server [socket -server accept 2836] proc accept {s a p} { after 100 close $s } } set c [socket $remoteServerIP 2836] fileevent $c readable [list count_up $c] set after_id [after 1000 timed_out] vwait done sendCommand {close $socket10_14_test_server} set done } {EOF is sticky} test socket-11.13 {testing async write, async flush, async close} \ {socket doTestsWithRemoteServer} { proc readit {s} { global count done set l [read $s] incr count [string length $l] if {[eof $s]} { close $s set done 1 } } sendCommand { set firstblock "" for {set i 0} {$i < 5} {incr i} { set firstblock "a$firstblock$firstblock" } set secondblock "" for {set i 0} {$i < 16} {incr i} { set secondblock "b$secondblock$secondblock" } set l [socket -server accept 2845] proc accept {s a p} { fconfigure $s -blocking 0 -translation lf -buffersize 16384 \ -buffering line fileevent $s readable "readable $s" } proc readable {s} { set l [gets $s] fileevent $s readable {} after 1000 respond $s } proc respond {s} { global firstblock puts -nonewline $s $firstblock after 1000 writedata $s } proc writedata {s} { global secondblock puts -nonewline $s $secondblock close $s } } set s [socket $remoteServerIP 2845] fconfigure $s -blocking 0 -trans lf -buffering line set count 0 puts $s hello fileevent $s readable "readit $s" set timer [after 10000 "set done timed_out"] vwait done after cancel $timer sendCommand {close $l} set count } 65566 set path(script1) [makeFile {} script1] set path(script2) [makeFile {} script2] test socket-12.1 {testing inheritance of server sockets} {socket stdio exec} { file delete $path(script1) file delete $path(script2) # Script1 is just a 10 second delay. If the server socket # is inherited, it will be held open for 10 seconds set f [open $path(script1) w] puts $f { after 10000 exit vwait forever } close $f # Script2 creates the server socket, launches script1, # waits a second, and exits. The server socket will now # be closed unless script1 inherited it. set f [open $path(script2) w] puts $f [list set tcltest [interpreter]] puts -nonewline $f { set f [socket -server accept 0] puts [lindex [fconfigure $f -sockname] 2] proc accept { file addr port } { close $file } exec $tcltest } puts $f [list $path(script1) &] puts $f { close $f after 1000 exit vwait forever } close $f # Launch script2 and wait 5 seconds ### exec [interpreter] script2 & set p [open "|[list [interpreter] $path(script2)]" r] gets $p listen after 5000 { set ok_to_proceed 1 } vwait ok_to_proceed # If we can still connect to the server, the socket got inherited. if {[catch {socket 127.0.0.1 $listen} msg]} { set x {server socket was not inherited} } else { close $msg set x {server socket was inherited} } close $p set x } {server socket was not inherited} test socket-12.2 {testing inheritance of client sockets} {socket stdio exec} { file delete $path(script1) file delete $path(script2) # Script1 is just a 20 second delay. If the server socket # is inherited, it will be held open for 10 seconds set f [open $path(script1) w] puts $f { after 20000 exit vwait forever } close $f # Script2 opens the client socket and writes to it. It then # launches script1 and exits. If the child process inherited the # client socket, the socket will still be open. set f [open $path(script2) w] puts $f [list set tcltest [interpreter]] puts -nonewline $f { gets stdin port set f [socket 127.0.0.1 $port] exec $tcltest } puts $f [list $path(script1) &] puts $f { puts $f testing flush $f after 1000 exit vwait forever } close $f # Create the server socket set server [socket -server accept 0] proc accept { file host port } { # When the client connects, establish the read handler global server close $server fileevent $file readable [list getdata $file] fconfigure $file -buffering line -blocking 0 return } proc getdata { file } { # Read handler on the accepted socket. global x global failed set status [catch {read $file} data] if {$status != 0} { set x {read failed, error was $data} catch { close $file } } elseif {[string compare {} $data]} { } elseif {[fblocked $file]} { } elseif {[eof $file]} { if {$failed} { set x {client socket was inherited} } else { set x {client socket was not inherited} } catch { close $file } } else { set x {impossible case} catch { close $file } } return } # If the socket doesn't hit end-of-file in 10 seconds, the # script1 process must have inherited the client. set failed 0 after 10000 [list set failed 1] # Launch the script2 process ### exec [interpreter] script2 & set p [open "|[list [interpreter] $path(script2)]" w] puts $p [lindex [fconfigure $server -sockname] 2] ; flush $p vwait x if {!$failed} { vwait failed } close $p set x } {client socket was not inherited} test socket-12.3 {testing inheritance of accepted sockets} {socket stdio exec} { file delete $path(script1) file delete $path(script2) set f [open $path(script1) w] puts $f { after 10000 exit vwait forever } close $f set f [open $path(script2) w] puts $f [list set tcltest [interpreter]] puts -nonewline $f { set server [socket -server accept 0] puts stdout [lindex [fconfigure $server -sockname] 2] proc accept { file host port } } puts $f \{ puts -nonewline $f { global tcltest puts $file {test data on socket} exec $tcltest } puts $f [list $path(script1) &] puts $f { after 1000 exit } puts $f \} puts $f { vwait forever } close $f # Launch the script2 process and connect to it. See how long # the socket stays open ## exec [interpreter] script2 & set p [open "|[list [interpreter] $path(script2)]" r] gets $p listen after 1000 set ok_to_proceed 1 vwait ok_to_proceed set f [socket 127.0.0.1 $listen] fconfigure $f -buffering full -blocking 0 fileevent $f readable [list getdata $f] # If the socket is still open after 5 seconds, the script1 process # must have inherited the accepted socket. set failed 0 after 5000 set failed 1 proc getdata { file } { # Read handler on the client socket. global x global failed set status [catch {read $file} data] if {$status != 0} { set x {read failed, error was $data} catch { close $file } } elseif {[string compare {} $data]} { } elseif {[fblocked $file]} { } elseif {[eof $file]} { if {$failed} { set x {accepted socket was inherited} } else { set x {accepted socket was not inherited} } catch { close $file } } else { set x {impossible case} catch { close $file } } return } vwait x close $p set x } {accepted socket was not inherited} test socket-13.1 {Testing use of shared socket between two threads} \ -constraints {socket testthread} -setup { threadReap set path(script) [makeFile { set f [socket -server accept 0] set listen [lindex [fconfigure $f -sockname] 2] proc accept {s a p} { fileevent $s readable [list echo $s] fconfigure $s -buffering line } proc echo {s} { global i set l [gets $s] if {[eof $s]} { global x close $s set x done } else { incr i puts $s $l } } set i 0 vwait x close $f # thread cleans itself up. testthread exit } script] } -body { # create a thread set serverthread [testthread create [list source $path(script) ] ] update set port [testthread send $serverthread {set listen}] update after 1000 set s [socket 127.0.0.1 $port] fconfigure $s -buffering line catch { puts $s "hello" gets $s result } close $s update after 2000 lappend result [threadReap] } -cleanup { removeFile script } -result {hello 1} removeFile script1 removeFile script2 # cleanup if {[string match sock* $commandSocket] == 1} { puts $commandSocket exit flush $commandSocket } catch {close $commandSocket} catch {close $remoteProcChan} ::tcltest::cleanupTests flush stdout return tcl8.4.20/tests/timer.test0000644003604700454610000003361111737050674014106 0ustar dgp771div# This file contains a collection of tests for the procedures in the # file tclTimer.c, which includes the "after" Tcl command. Sourcing # this file into Tcl runs the tests and generates output for errors. # No output means no errors were found. # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1997 by Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import -force ::tcltest::* } test timer-1.1 {Tcl_CreateTimerHandler procedure} { foreach i [after info] { after cancel $i } set x "" foreach i {100 200 1000 50 150} { after $i lappend x $i } after 200 update set x } {50 100 150 200} test timer-2.1 {Tcl_DeleteTimerHandler procedure} { foreach i [after info] { after cancel $i } set x "" foreach i {100 200 300 50 150} { after $i lappend x $i } after cancel lappend x 150 after cancel lappend x 50 after 200 update set x } {100 200} # No tests for Tcl_ServiceTimer or ResetTimer, since it is already tested # above. test timer-3.1 {TimerHandlerEventProc procedure: event masks} { set x start after 100 { set x fired } update idletasks set result $x after 200 update lappend result $x } {start fired} test timer-3.2 {TimerHandlerEventProc procedure: multiple timers} { foreach i [after info] { after cancel $i } foreach i {200 600 1000} { after $i lappend x $i } after 200 set result "" set x "" update lappend result $x after 400 update lappend result $x after 400 update lappend result $x } {200 {200 600} {200 600 1000}} test timer-3.3 {TimerHandlerEventProc procedure: reentrant timer deletion} { foreach i [after info] { after cancel $i } set x {} after 100 lappend x 100 set i [after 300 lappend x 300] after 200 after cancel $i after 400 update set x } 100 test timer-3.4 {TimerHandlerEventProc procedure: all expired timers fire} { foreach i [after info] { after cancel $i } set x {} after 100 lappend x a after 200 lappend x b after 300 lappend x c after 300 vwait x set x } {a b c} test timer-3.5 {TimerHandlerEventProc procedure: reentrantly added timers don't fire} { foreach i [after info] { after cancel $i } set x {} after 100 {lappend x a; after 0 lappend x b} after 100 vwait x set x } a test timer-3.6 {TimerHandlerEventProc procedure: reentrantly added timers don't fire} { foreach i [after info] { after cancel $i } set x {} after 100 {lappend x a; after 100 lappend x b; after 100} after 100 vwait x set result $x vwait x lappend result $x } {a {a b}} # No tests for Tcl_DoWhenIdle: it's already tested by other tests # below. test timer-4.1 {Tcl_CancelIdleCall procedure} { foreach i [after info] { after cancel $i } set x before set y before set z before after idle set x after1 after idle set y after2 after idle set z after3 after cancel set y after2 update idletasks concat $x $y $z } {after1 before after3} test timer-4.2 {Tcl_CancelIdleCall procedure} { foreach i [after info] { after cancel $i } set x before set y before set z before after idle set x after1 after idle set y after2 after idle set z after3 after cancel set x after1 update idletasks concat $x $y $z } {before after2 after3} test timer-5.1 {Tcl_ServiceIdle, self-rescheduling handlers} { foreach i [after info] { after cancel $i } set x 1 set y 23 after idle {incr x; after idle {incr x; after idle {incr x}}} after idle {incr y} vwait x set result "$x $y" update idletasks lappend result $x } {2 24 4} test timer-6.1 {Tcl_AfterCmd procedure, basics} { list [catch {after} msg] $msg } {1 {wrong # args: should be "after option ?arg arg ...?"}} test timer-6.2 {Tcl_AfterCmd procedure, basics} { list [catch {after 2x} msg] $msg } {1 {expected integer but got "2x"}} test timer-6.3 {Tcl_AfterCmd procedure, basics} { list [catch {after gorp} msg] $msg } {1 {bad argument "gorp": must be cancel, idle, info, or a number}} test timer-6.4 {Tcl_AfterCmd procedure, ms argument} { set x before after 400 {set x after} after 200 update set y $x after 400 update list $y $x } {before after} test timer-6.5 {Tcl_AfterCmd procedure, ms argument} { set x before after 300 set x after after 200 update set y $x after 200 update list $y $x } {before after} test timer-6.6 {Tcl_AfterCmd procedure, cancel option} { list [catch {after cancel} msg] $msg } {1 {wrong # args: should be "after cancel id|command"}} test timer-6.7 {Tcl_AfterCmd procedure, cancel option} { after cancel after#1 } {} test timer-6.8 {Tcl_AfterCmd procedure, cancel option} { after cancel {foo bar} } {} test timer-6.9 {Tcl_AfterCmd procedure, cancel option} { foreach i [after info] { after cancel $i } set x before set y [after 100 set x after] after cancel $y after 200 update set x } {before} test timer-6.10 {Tcl_AfterCmd procedure, cancel option} { foreach i [after info] { after cancel $i } set x before after 100 set x after after cancel {set x after} after 200 update set x } {before} test timer-6.11 {Tcl_AfterCmd procedure, cancel option} { foreach i [after info] { after cancel $i } set x before after 100 set x after set id [after 300 set x after] after cancel $id after 200 update set y $x set x cleared after 200 update list $y $x } {after cleared} test timer-6.12 {Tcl_AfterCmd procedure, cancel option} { foreach i [after info] { after cancel $i } set x first after idle lappend x second after idle lappend x third set i [after idle lappend x fourth] after cancel {lappend x second} after cancel $i update idletasks set x } {first third} test timer-6.13 {Tcl_AfterCmd procedure, cancel option, multiple arguments for command} { foreach i [after info] { after cancel $i } set x first after idle lappend x second after idle lappend x third set i [after idle lappend x fourth] after cancel lappend x second after cancel $i update idletasks set x } {first third} test timer-6.14 {Tcl_AfterCmd procedure, cancel option, cancel during handler, used to dump core} { foreach i [after info] { after cancel $i } set id [ after 100 { set x done after cancel $id } ] vwait x } {} test timer-6.15 {Tcl_AfterCmd procedure, cancel option, multiple interps} { foreach i [after info] { after cancel $i } interp create x x eval {set a before; set b before; after idle {set a a-after}; after idle {set b b-after}} set result [llength [x eval after info]] lappend result [llength [after info]] after cancel {set b b-after} set a aaa set b bbb x eval {after cancel set a a-after} update idletasks lappend result $a $b [x eval {list $a $b}] interp delete x set result } {2 0 aaa bbb {before b-after}} test timer-6.16 {Tcl_AfterCmd procedure, idle option} { list [catch {after idle} msg] $msg } {1 {wrong # args: should be "after idle script script ..."}} test timer-6.17 {Tcl_AfterCmd procedure, idle option} { set x before after idle {set x after} set y $x update idletasks list $y $x } {before after} test timer-6.18 {Tcl_AfterCmd procedure, idle option} { set x before after idle set x after set y $x update idletasks list $y $x } {before after} set event1 [after idle event 1] set event2 [after 1000 event 2] interp create x set childEvent [x eval {after idle event in child}] test timer-6.19 {Tcl_AfterCmd, info option} { lsort [after info] } [lsort "$event1 $event2"] test timer-6.20 {Tcl_AfterCmd, info option} { list [catch {after info a b} msg] $msg } {1 {wrong # args: should be "after info ?id?"}} test timer-6.21 {Tcl_AfterCmd, info option} { list [catch {after info $childEvent} msg] $msg } "1 {event \"$childEvent\" doesn't exist}" test timer-6.22 {Tcl_AfterCmd, info option} { list [after info $event1] [after info $event2] } {{{event 1} idle} {{event 2} timer}} after cancel $event1 after cancel $event2 interp delete x test timer-6.23 {Tcl_AfterCmd procedure, no option, script with NULL} { foreach i [after info] { after cancel $i } set x "hello world" after 1 "set x ab\0cd" after 10 update string length $x } {5} test timer-6.24 {Tcl_AfterCmd procedure, no option, script with NULL} { foreach i [after info] { after cancel $i } set x "hello world" after 1 set x ab\0cd after 10 update string length $x } {5} test timer-6.25 {Tcl_AfterCmd procedure, cancel option, script with NULL} { foreach i [after info] { after cancel $i } set x "hello world" after 1 set x ab\0cd after cancel "set x ab\0ef" set x [llength [after info]] foreach i [after info] { after cancel $i } set x } {1} test timer-6.26 {Tcl_AfterCmd procedure, cancel option, script with NULL} { foreach i [after info] { after cancel $i } set x "hello world" after 1 set x ab\0cd after cancel set x ab\0ef set y [llength [after info]] foreach i [after info] { after cancel $i } set y } {1} test timer-6.27 {Tcl_AfterCmd procedure, idle option, script with NULL} { foreach i [after info] { after cancel $i } set x "hello world" after idle "set x ab\0cd" update string length $x } {5} test timer-6.28 {Tcl_AfterCmd procedure, idle option, script with NULL} { foreach i [after info] { after cancel $i } set x "hello world" after idle set x ab\0cd update string length $x } {5} test timer-6.29 {Tcl_AfterCmd procedure, info option, script with NULL} { foreach i [after info] { after cancel $i } set x "hello world" set id junk set id [after 10 set x ab\0cd] update set y [string length [lindex [lindex [after info $id] 0] 2]] foreach i [after info] { after cancel $i } set y } {5} set event [after idle foo bar] scan $event after#%d id test timer-7.1 {GetAfterEvent procedure} { list [catch {after info xfter#$id} msg] $msg } "1 {event \"xfter#$id\" doesn't exist}" test timer-7.2 {GetAfterEvent procedure} { list [catch {after info afterx$id} msg] $msg } "1 {event \"afterx$id\" doesn't exist}" test timer-7.3 {GetAfterEvent procedure} { list [catch {after info after#ab} msg] $msg } {1 {event "after#ab" doesn't exist}} test timer-7.4 {GetAfterEvent procedure} { list [catch {after info after#} msg] $msg } {1 {event "after#" doesn't exist}} test timer-7.5 {GetAfterEvent procedure} { list [catch {after info after#${id}x} msg] $msg } "1 {event \"after#${id}x\" doesn't exist}" test timer-7.6 {GetAfterEvent procedure} { list [catch {after info afterx[expr $id+1]} msg] $msg } "1 {event \"afterx[expr $id+1]\" doesn't exist}" after cancel $event test timer-8.1 {AfterProc procedure} { set x before proc foo {} { set x untouched after 100 {set x after} after 200 update return $x } list [foo] $x } {untouched after} test timer-8.2 {AfterProc procedure} { catch {rename bgerror {}} proc bgerror msg { global x errorInfo set x [list $msg $errorInfo] } set x empty after 100 {error "After error"} after 200 set y $x update catch {rename bgerror {}} list $y $x } {empty {{After error} {After error while executing "error "After error"" ("after" script)}}} test timer-8.3 {AfterProc procedure, deleting handler from itself} { foreach i [after info] { after cancel $i } proc foo {} { global x set x {} foreach i [after info] { lappend x [after info $i] } after cancel foo } after idle foo after 1000 {error "I shouldn't ever have executed"} update idletasks set x } {{{error "I shouldn't ever have executed"} timer}} test timer-8.4 {AfterProc procedure, deleting handler from itself} { foreach i [after info] { after cancel $i } proc foo {} { global x set x {} foreach i [after info] { lappend x [after info $i] } after cancel foo } after 1000 {error "I shouldn't ever have executed"} after idle foo update idletasks set x } {{{error "I shouldn't ever have executed"} timer}} foreach i [after info] { after cancel $i } # No test for FreeAfterPtr, since it is already tested above. test timer-9.1 {AfterCleanupProc procedure} { catch {interp delete x} interp create x x eval {after 200 { lappend x after puts "part 1: this message should not appear" }} after 200 {lappend x after2} x eval {after 200 { lappend x after3 puts "part 2: this message should not appear" }} after 200 {lappend x after4} x eval {after 200 { lappend x after5 puts "part 3: this message should not appear" }} interp delete x set x before after 300 update set x } {before after2 after4} test timer-10.1 {Bug 1016167: [after] overwrites imports} -setup { interp create slave slave eval namespace export after slave eval namespace eval foo namespace import ::after } -body { slave eval foo::after 1 slave eval namespace origin foo::after } -cleanup { # Bug will cause crash here; would cause failure otherwise interp delete slave } -result ::after test timer-11.2 {Bug 1350293: [after] negative argument} \ -body { set l {} after 100 {lappend l 100; set done 1} after -1 {lappend l -1} vwait done set l } \ -result {-1 100} # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/lreplace.test0000644003604700454610000001017111737050674014551 0ustar dgp771div# Commands covered: lreplace # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } test lreplace-1.1 {lreplace command} { lreplace {1 2 3 4 5} 0 0 a } {a 2 3 4 5} test lreplace-1.2 {lreplace command} { lreplace {1 2 3 4 5} 1 1 a } {1 a 3 4 5} test lreplace-1.3 {lreplace command} { lreplace {1 2 3 4 5} 2 2 a } {1 2 a 4 5} test lreplace-1.4 {lreplace command} { lreplace {1 2 3 4 5} 3 3 a } {1 2 3 a 5} test lreplace-1.5 {lreplace command} { lreplace {1 2 3 4 5} 4 4 a } {1 2 3 4 a} test lreplace-1.6 {lreplace command} { lreplace {1 2 3 4 5} 4 5 a } {1 2 3 4 a} test lreplace-1.7 {lreplace command} { lreplace {1 2 3 4 5} -1 -1 a } {a 1 2 3 4 5} test lreplace-1.8 {lreplace command} { lreplace {1 2 3 4 5} 2 end a b c d } {1 2 a b c d} test lreplace-1.9 {lreplace command} { lreplace {1 2 3 4 5} 0 3 } {5} test lreplace-1.10 {lreplace command} { lreplace {1 2 3 4 5} 0 4 } {} test lreplace-1.11 {lreplace command} { lreplace {1 2 3 4 5} 0 1 } {3 4 5} test lreplace-1.12 {lreplace command} { lreplace {1 2 3 4 5} 2 3 } {1 2 5} test lreplace-1.13 {lreplace command} { lreplace {1 2 3 4 5} 3 end } {1 2 3} test lreplace-1.14 {lreplace command} { lreplace {1 2 3 4 5} -1 4 a b c } {a b c} test lreplace-1.15 {lreplace command} { lreplace {a b "c c" d e f} 3 3 } {a b {c c} e f} test lreplace-1.16 {lreplace command} { lreplace { 1 2 3 4 5} 0 0 a } {a 2 3 4 5} test lreplace-1.17 {lreplace command} { lreplace {1 2 3 4 "5 6"} 4 4 a } {1 2 3 4 a} test lreplace-1.18 {lreplace command} { lreplace {1 2 3 4 {5 6}} 4 4 a } {1 2 3 4 a} test lreplace-1.19 {lreplace command} { lreplace {1 2 3 4} 2 end x y z } {1 2 x y z} test lreplace-1.20 {lreplace command} { lreplace {1 2 3 4} end end a } {1 2 3 a} test lreplace-1.21 {lreplace command} { lreplace {1 2 3 4} end 3 a } {1 2 3 a} test lreplace-1.22 {lreplace command} { lreplace {1 2 3 4} end end } {1 2 3} test lreplace-1.23 {lreplace command} { lreplace {1 2 3 4} 2 -1 xy } {1 2 xy 3 4} test lreplace-1.24 {lreplace command} { lreplace {1 2 3 4} end -1 z } {1 2 3 z 4} test lreplace-1.25 {lreplace command} { concat \"[lreplace {\}\ hello} end end]\" } {"\}\ "} test lreplace-1.26 {lreplace command} { catch {unset foo} set foo {a b} list [set foo [lreplace $foo end end]] \ [set foo [lreplace $foo end end]] \ [set foo [lreplace $foo end end]] } {a {} {}} test lreplace-2.1 {lreplace errors} { list [catch lreplace msg] $msg } {1 {wrong # args: should be "lreplace list first last ?element element ...?"}} test lreplace-2.2 {lreplace errors} { list [catch {lreplace a b} msg] $msg } {1 {wrong # args: should be "lreplace list first last ?element element ...?"}} test lreplace-2.3 {lreplace errors} { list [catch {lreplace x a 10} msg] $msg } {1 {bad index "a": must be integer or end?-integer?}} test lreplace-2.4 {lreplace errors} { list [catch {lreplace x 10 x} msg] $msg } {1 {bad index "x": must be integer or end?-integer?}} test lreplace-2.5 {lreplace errors} { list [catch {lreplace x 10 1x} msg] $msg } {1 {bad index "1x": must be integer or end?-integer?}} test lreplace-2.6 {lreplace errors} { list [catch {lreplace x 3 2} msg] $msg } {1 {list doesn't contain element 3}} test lreplace-2.7 {lreplace errors} { list [catch {lreplace x 1 1} msg] $msg } {1 {list doesn't contain element 1}} test lreplace-3.1 {lreplace won't modify shared argument objects} { proc p {} { lreplace "a b c" 1 1 "x y" return "a b c" } p } "a b c" # cleanup catch {unset foo} ::tcltest::cleanupTests return tcl8.4.20/tests/source.test0000644003604700454610000001417112052456744014265 0ustar dgp771div# Commands covered: source # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994-1996 Sun Microsystems, Inc. # Copyright (c) 1998-2000 by Scriptics Corporation. # Contributions from Don Porter, NIST, 2003. (not subject to US copyright) # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[catch {package require tcltest 2.1}]} { puts stderr "Skipping tests in [info script]. tcltest 2.1 required." return } namespace eval ::tcl::test::source { namespace import ::tcltest::test namespace import ::tcltest::testConstraint namespace import ::tcltest::cleanupTests namespace import ::tcltest::makeFile namespace import ::tcltest::removeFile namespace import ::tcltest::customMatch test source-1.1 {source command} -setup { set x "old x value" set y "old y value" set z "old z value" set sourcefile [makeFile { set x 22 set y 33 set z 44 } source.file] } -body { source $sourcefile list $x $y $z } -cleanup { removeFile source.file } -result {22 33 44} test source-1.2 {source command} -setup { set sourcefile [makeFile {list result} source.file] } -body { source $sourcefile } -cleanup { removeFile source.file } -result result test source-1.3 {source command} -setup { set sourcefile [makeFile {} source.file] set fd [open $sourcefile w] fconfigure $fd -translation lf puts $fd "list a b c \\" puts $fd "d e f" close $fd } -body { source $sourcefile } -cleanup { removeFile source.file } -result {a b c d e f} proc ListGlobMatch {expected actual} { if {[llength $expected] != [llength $actual]} { return 0 } foreach e $expected a $actual { if {![string match $e $a]} { return 0 } } return 1 } customMatch listGlob [namespace which ListGlobMatch] test source-2.3 {source error conditions} -setup { set sourcefile [makeFile { set x 146 error "error in sourced file" set y $x } source.file] } -body { list [catch {source $sourcefile} msg] $msg $::errorInfo } -cleanup { removeFile source.file } -match listGlob -result [list 1 {error in sourced file} \ {error in sourced file while executing "error "error in sourced file"" (file "*source.file" line 3) invoked from within "source $sourcefile"}] test source-2.4 {source error conditions} -setup { set sourcefile [makeFile {break} source.file] } -body { source $sourcefile } -cleanup { removeFile source.file } -returnCodes break test source-2.5 {source error conditions} -setup { set sourcefile [makeFile {continue} source.file] } -body { source $sourcefile } -cleanup { removeFile source.file } -returnCodes continue test source-2.6 {source error conditions} -setup { set sourcefile [makeFile {} _non_existent_] removeFile _non_existent_ } -body { list [catch {source $sourcefile} msg] $msg $::errorCode } -match listGlob -result [list 1 \ {couldn't read file "*_non_existent_": no such file or directory} \ {POSIX ENOENT {no such file or directory}}] test source-2.7 {utf-8 with BOM} -setup { set sourcefile [makeFile {} source.file] set saveencoding [encoding system] } -body { encoding system utf-8 set out [open $sourcefile w] puts $out "\ufeffset y new-y" close $out set y old-y source $sourcefile return $y } -cleanup { removeFile $sourcefile encoding system $saveencoding } -result {new-y} test source-3.1 {return in middle of source file} -setup { set sourcefile [makeFile { set x new-x return allDone set y new-y } source.file] } -body { set x old-x set y old-y set z [source $sourcefile] list $x $y $z } -cleanup { removeFile source.file } -result {new-x old-y allDone} test source-3.2 {return with special code etc.} -setup { set sourcefile [makeFile { set x new-x return -code break "Silly result" set y new-y } source.file] } -body { source $sourcefile } -cleanup { removeFile source.file } -returnCodes break -result {Silly result} test source-3.3 {return with special code etc.} -setup { set sourcefile [makeFile { set x new-x return -code error "Simulated error" set y new-y } source.file] } -body { list [catch {source $sourcefile} msg] $msg $::errorInfo $::errorCode } -cleanup { removeFile source.file } -result {1 {Simulated error} {Simulated error while executing "source $sourcefile"} NONE} test source-3.4 {return with special code etc.} -setup { set sourcefile [makeFile { set x new-x return -code error -errorinfo "Simulated errorInfo stuff" set y new-y } source.file] } -body { list [catch {source $sourcefile} msg] $msg $::errorInfo $::errorCode } -cleanup { removeFile source.file } -result {1 {} {Simulated errorInfo stuff invoked from within "source $sourcefile"} NONE} test source-3.5 {return with special code etc.} -setup { set sourcefile [makeFile { set x new-x return -code error -errorinfo "Simulated errorInfo stuff" \ -errorcode {a b c} set y new-y } source.file] } -body { list [catch {source $sourcefile} msg] $msg $::errorInfo $::errorCode } -cleanup { removeFile source.file } -result {1 {} {Simulated errorInfo stuff invoked from within "source $sourcefile"} {a b c}} test source-6.1 {source is binary ok} -setup { # Note [makeFile] writes in the system encoding. # [source] defaults to reading in the system encoding. set sourcefile [makeFile [list set x "a b\0c"] source.file] } -body { set x {} source $sourcefile string length $x } -cleanup { removeFile source.file } -result 5 test source-6.2 {source skips everything after Ctrl-Z: Bug 2040} -setup { set sourcefile [makeFile "set x ab\32c" source.file] } -body { set x {} source $sourcefile string length $x } -cleanup { removeFile source.file } -result 2 cleanupTests } namespace delete ::tcl::test::source return tcl8.4.20/tests/httpold.test0000644003604700454610000001726411737050674014452 0ustar dgp771div# Commands covered: http_config, http_get, http_wait, http_reset # # This file contains a collection of tests for the http script library. # Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994-1996 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } if {[catch {package require http 1.0}]} { if {[info exists httpold]} { catch {puts "Cannot load http 1.0 package"} ::tcltest::cleanupTests return } else { catch {puts "Running http 1.0 tests in slave interp"} set interp [interp create httpold] $interp eval [list set httpold "running"] $interp eval [list set argv $argv] $interp eval [list source [info script]] interp delete $interp ::tcltest::cleanupTests return } } set bindata "This is binary data\x0d\x0amore\x0dmore\x0amore\x00null" catch {unset data} ## ## The httpd script implement a stub http server ## source [file join [file dirname [info script]] httpd] set port 8010 if [catch {httpd_init $port} listen] { puts "Cannot start http server, http test skipped" unset port ::tcltest::cleanupTests return } test httpold-1.1 {http_config} { http_config } {-accept */* -proxyfilter httpProxyRequired -proxyhost {} -proxyport {} -useragent {Tcl http client package 1.0}} test httpold-1.2 {http_config} { http_config -proxyfilter } httpProxyRequired test httpold-1.3 {http_config} { catch {http_config -junk} } 1 test httpold-1.4 {http_config} { http_config -proxyhost nowhere.come -proxyport 8080 -proxyfilter myFilter -useragent "Tcl Test Suite" set x [http_config] http_config -proxyhost {} -proxyport {} -proxyfilter httpProxyRequired \ -useragent "Tcl http client package 1.0" set x } {-accept */* -proxyfilter myFilter -proxyhost nowhere.come -proxyport 8080 -useragent {Tcl Test Suite}} test httpold-1.5 {http_config} { catch {http_config -proxyhost {} -junk 8080} } 1 test httpold-2.1 {http_reset} { catch {http_reset http#1} } 0 test httpold-3.1 {http_get} { catch {http_get -bogus flag} } 1 test httpold-3.2 {http_get} { catch {http_get http:junk} err set err } {Unsupported URL: http:junk} set url [info hostname]:$port test httpold-3.3 {http_get} { set token [http_get $url] http_data $token } "HTTP/1.0 TEST

Hello, World!

GET /

" set tail /a/b/c set url [info hostname]:$port/a/b/c set binurl [info hostname]:$port/binary test httpold-3.4 {http_get} { set token [http_get $url] http_data $token } "HTTP/1.0 TEST

Hello, World!

GET $tail

" proc selfproxy {host} { global port return [list [info hostname] $port] } test httpold-3.5 {http_get} { http_config -proxyfilter selfproxy set token [http_get $url] http_config -proxyfilter httpProxyRequired http_data $token } "HTTP/1.0 TEST

Hello, World!

GET http://$url

" test httpold-3.6 {http_get} { http_config -proxyfilter bogus set token [http_get $url] http_config -proxyfilter httpProxyRequired http_data $token } "HTTP/1.0 TEST

Hello, World!

GET $tail

" test httpold-3.7 {http_get} { set token [http_get $url -headers {Pragma no-cache}] http_data $token } "HTTP/1.0 TEST

Hello, World!

GET $tail

" test httpold-3.8 {http_get} { set token [http_get $url -query Name=Value&Foo=Bar] http_data $token } "HTTP/1.0 TEST

Hello, World!

POST $tail

Query

Name
Value
Foo
Bar
" test httpold-3.9 {http_get} { set token [http_get $url -validate 1] http_code $token } "HTTP/1.0 200 OK" test httpold-4.1 {httpEvent} { set token [http_get $url] upvar #0 $token data array set meta $data(meta) expr ($data(totalsize) == $meta(Content-Length)) } 1 test httpold-4.2 {httpEvent} { set token [http_get $url] upvar #0 $token data array set meta $data(meta) string compare $data(type) [string trim $meta(Content-Type)] } 0 test httpold-4.3 {httpEvent} { set token [http_get $url] http_code $token } {HTTP/1.0 200 Data follows} test httpold-4.4 {httpEvent} { set testfile [makeFile "" testfile] set out [open $testfile w] set token [http_get $url -channel $out] close $out set in [open $testfile] set x [read $in] close $in removeFile $testfile set x } "HTTP/1.0 TEST

Hello, World!

GET $tail

" test httpold-4.5 {httpEvent} { set testfile [makeFile "" testfile] set out [open $testfile w] set token [http_get $url -channel $out] close $out upvar #0 $token data removeFile $testfile expr $data(currentsize) == $data(totalsize) } 1 test httpold-4.6 {httpEvent} { set testfile [makeFile "" testfile] set out [open $testfile w] set token [http_get $binurl -channel $out] close $out set in [open $testfile] fconfigure $in -translation binary set x [read $in] close $in removeFile $testfile set x } "$bindata$binurl" proc myProgress {token total current} { global progress httpLog if {[info exists httpLog] && $httpLog} { puts "progress $total $current" } set progress [list $total $current] } if 0 { # This test hangs on Windows95 because the client never gets EOF set httpLog 1 test httpold-4.6 {httpEvent} { set token [http_get $url -blocksize 50 -progress myProgress] set progress } {111 111} } test httpold-4.7 {httpEvent} { set token [http_get $url -progress myProgress] set progress } {111 111} test httpold-4.8 {httpEvent} { set token [http_get $url] http_status $token } {ok} test httpold-4.9 {httpEvent} { set token [http_get $url -progress myProgress] http_code $token } {HTTP/1.0 200 Data follows} test httpold-4.10 {httpEvent} { set token [http_get $url -progress myProgress] http_size $token } {111} test httpold-4.11 {httpEvent} { set token [http_get $url -timeout 1 -command {#}] http_reset $token http_status $token } {reset} test httpold-4.12 {httpEvent} { update set x {} after 500 {lappend x ok} set token [http_get $url -timeout 1 -command {lappend x fail}] vwait x list [http_status $token] $x } {timeout ok} test httpold-5.1 {http_formatQuery} { http_formatQuery name1 value1 name2 "value two" } {name1=value1&name2=value+two} test httpold-5.2 {http_formatQuery} { http_formatQuery name1 ~bwelch name2 \xa1\xa2\xa2 } {name1=%7ebwelch&name2=%a1%a2%a2} test httpold-5.3 {http_formatQuery} { http_formatQuery lines "line1\nline2\nline3" } {lines=line1%0d%0aline2%0d%0aline3} test httpold-6.1 {httpProxyRequired} { update http_config -proxyhost [info hostname] -proxyport $port set token [http_get $url] http_wait $token http_config -proxyhost {} -proxyport {} upvar #0 $token data set data(body) } "HTTP/1.0 TEST

Hello, World!

GET http://$url

" # cleanup catch {unset url} catch {unset port} catch {unset data} close $listen ::tcltest::cleanupTests return tcl8.4.20/tests/obj.test0000644003604700454610000005673511737050674013554 0ustar dgp771div# Functionality covered: this file contains a collection of tests for the # procedures in tclObj.c that implement Tcl's basic type support and the # type managers for the types boolean, double, and integer. # # Sourcing this file into Tcl runs the tests and generates output for # errors. No output means no errors were found. # # Copyright (c) 1995-1996 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } if {[info commands testobj] == {}} { puts "This application hasn't been compiled with the \"testobj\"" puts "command, so I can't test the Tcl type and object support." ::tcltest::cleanupTests return } # Procedure to determine the integer range of the machine proc int_range {} { for { set MIN_INT 1 } { $MIN_INT > 0 } {} { set MIN_INT [expr { $MIN_INT << 1 }] } set MAX_INT [expr { ~ $MIN_INT }] return [list $MIN_INT $MAX_INT] } # Procedure to determine the range of wide integers on the machine. proc wide_range {} { for { set MIN_WIDE [expr { wide(1) }] } { $MIN_WIDE > wide(0) } {} { set MIN_WIDE [expr { $MIN_WIDE << 1 }] } set MAX_WIDE [expr { ~ $MIN_WIDE }] return [list $MIN_WIDE $MAX_WIDE] } foreach { MIN_INT MAX_INT } [int_range] break foreach { MIN_WIDE MAX_WIDE } [wide_range] break ::tcltest::testConstraint 32bit \ [expr { $MAX_INT == 0x7fffffff }] ::tcltest::testConstraint wideBiggerThanInt \ [expr { $MAX_WIDE > wide($MAX_INT) }] test obj-1.1 {Tcl_AppendAllObjTypes, and InitTypeTable, Tcl_RegisterObjType} { set r 1 foreach {t} { {array search} boolean bytearray bytecode double end-offset index int list nsName procbody string } { set first [string first $t [testobj types]] set r [expr {$r && ($first != -1)}] } set result $r } {1} test obj-2.1 {Tcl_GetObjType error} { list [testintobj set 1 0] [catch {testobj convert 1 foo} msg] $msg } {0 1 {no type foo found}} test obj-2.2 {Tcl_GetObjType and Tcl_ConvertToType} { set result "" lappend result [testobj freeallvars] lappend result [testintobj set 1 12] lappend result [testobj convert 1 double] lappend result [testobj type 1] lappend result [testobj refcount 1] } {{} 12 12 double 3} test obj-3.1 {Tcl_ConvertToType error} { list [testdoubleobj set 1 12.34] [catch {testobj convert 1 int} msg] $msg } {12.34 1 {expected integer but got "12.34"}} test obj-3.2 {Tcl_ConvertToType error, "empty string" object} { list [testobj newobj 1] [catch {testobj convert 1 int} msg] $msg } {{} 1 {expected integer but got ""}} test obj-4.1 {Tcl_NewObj and AllocateFreeObjects} { set result "" lappend result [testobj freeallvars] lappend result [testobj newobj 1] lappend result [testobj type 1] lappend result [testobj refcount 1] } {{} {} string 2} test obj-5.1 {Tcl_FreeObj} { set result "" lappend result [testintobj set 1 12345] lappend result [testobj freeallvars] lappend result [catch {testintobj get 1} msg] lappend result $msg } {12345 {} 1 {variable 1 is unset (NULL)}} test obj-6.1 {Tcl_DuplicateObj, object has internal rep} { set result "" lappend result [testobj freeallvars] lappend result [testintobj set 1 47] lappend result [testobj duplicate 1 2] lappend result [testintobj get 2] lappend result [testobj refcount 1] lappend result [testobj refcount 2] } {{} 47 47 47 2 3} test obj-6.2 {Tcl_DuplicateObj, "empty string" object} { set result "" lappend result [testobj freeallvars] lappend result [testobj newobj 1] lappend result [testobj duplicate 1 2] lappend result [testintobj get 2] lappend result [testobj refcount 1] lappend result [testobj refcount 2] } {{} {} {} {} 2 3} test obj-7.1 {Tcl_GetString, return existing string rep} { set result "" lappend result [testintobj set 1 47] lappend result [testintobj get2 1] } {47 47} test obj-7.2 {Tcl_GetString, "empty string" object} { set result "" lappend result [testobj newobj 1] lappend result [teststringobj append 1 abc -1] lappend result [teststringobj get2 1] } {{} abc abc} test obj-7.3 {Tcl_GetString, returns string internal rep (DString)} { set result "" lappend result [teststringobj set 1 xyz] lappend result [teststringobj append 1 abc -1] lappend result [teststringobj get2 1] } {xyz xyzabc xyzabc} test obj-7.4 {Tcl_GetString, recompute string rep from internal rep} { set result "" lappend result [testintobj set 1 77] lappend result [testintobj mult10 1] lappend result [teststringobj get2 1] } {77 770 770} test obj-8.1 {Tcl_GetStringFromObj, return existing string rep} { set result "" lappend result [testintobj set 1 47] lappend result [testintobj get 1] } {47 47} test obj-8.2 {Tcl_GetStringFromObj, "empty string" object} { set result "" lappend result [testobj newobj 1] lappend result [teststringobj append 1 abc -1] lappend result [teststringobj get 1] } {{} abc abc} test obj-8.3 {Tcl_GetStringFromObj, returns string internal rep (DString)} { set result "" lappend result [teststringobj set 1 xyz] lappend result [teststringobj append 1 abc -1] lappend result [teststringobj get 1] } {xyz xyzabc xyzabc} test obj-8.4 {Tcl_GetStringFromObj, recompute string rep from internal rep} { set result "" lappend result [testintobj set 1 77] lappend result [testintobj mult10 1] lappend result [teststringobj get 1] } {77 770 770} test obj-9.1 {Tcl_NewBooleanObj} { set result "" lappend result [testobj freeallvars] lappend result [testbooleanobj set 1 0] lappend result [testobj type 1] lappend result [testobj refcount 1] } {{} 0 boolean 2} test obj-10.1 {Tcl_SetBooleanObj, existing "empty string" object} { set result "" lappend result [testobj freeallvars] lappend result [testobj newobj 1] lappend result [testbooleanobj set 1 0] ;# makes existing obj boolean lappend result [testobj type 1] lappend result [testobj refcount 1] } {{} {} 0 boolean 2} test obj-10.2 {Tcl_SetBooleanObj, existing non-"empty string" object} { set result "" lappend result [testobj freeallvars] lappend result [testintobj set 1 98765] lappend result [testbooleanobj set 1 1] ;# makes existing obj boolean lappend result [testobj type 1] lappend result [testobj refcount 1] } {{} 98765 1 boolean 2} test obj-11.1 {Tcl_GetBooleanFromObj, existing boolean object} { set result "" lappend result [testbooleanobj set 1 1] lappend result [testbooleanobj not 1] ;# gets existing boolean rep } {1 0} test obj-11.2 {Tcl_GetBooleanFromObj, convert to boolean} { set result "" lappend result [testintobj set 1 47] lappend result [testbooleanobj not 1] ;# must convert to bool lappend result [testobj type 1] } {47 0 boolean} test obj-11.3 {Tcl_GetBooleanFromObj, error converting to boolean} { set result "" lappend result [teststringobj set 1 abc] lappend result [catch {testbooleanobj not 1} msg] lappend result $msg } {abc 1 {expected boolean value but got "abc"}} test obj-11.4 {Tcl_GetBooleanFromObj, error converting from "empty string"} { set result "" lappend result [testobj newobj 1] lappend result [catch {testbooleanobj not 1} msg] lappend result $msg } {{} 1 {expected boolean value but got ""}} test obj-11.5 {Tcl_GetBooleanFromObj, convert hex to boolean} { set result "" lappend result [teststringobj set 1 0xac] lappend result [testbooleanobj not 1] lappend result [testobj type 1] } {0xac 0 boolean} test obj-11.6 {Tcl_GetBooleanFromObj, convert float to boolean} { set result "" lappend result [teststringobj set 1 5.42] lappend result [testbooleanobj not 1] lappend result [testobj type 1] } {5.42 0 boolean} test obj-12.1 {DupBooleanInternalRep} { set result "" lappend result [testbooleanobj set 1 1] lappend result [testobj duplicate 1 2] ;# uses DupBooleanInternalRep lappend result [testbooleanobj get 2] } {1 1 1} test obj-13.1 {SetBooleanFromAny, int to boolean special case} { set result "" lappend result [testintobj set 1 1234] lappend result [testbooleanobj not 1] ;# converts with SetBooleanFromAny lappend result [testobj type 1] } {1234 0 boolean} test obj-13.2 {SetBooleanFromAny, double to boolean special case} { set result "" lappend result [testdoubleobj set 1 3.14159] lappend result [testbooleanobj not 1] ;# converts with SetBooleanFromAny lappend result [testobj type 1] } {3.14159 0 boolean} test obj-13.3 {SetBooleanFromAny, special case strings representing booleans} { set result "" foreach s {yes no true false on off} { teststringobj set 1 $s lappend result [testbooleanobj not 1] } lappend result [testobj type 1] } {0 1 0 1 0 1 boolean} test obj-13.4 {SetBooleanFromAny, recompute string rep then parse it} { set result "" lappend result [testintobj set 1 456] lappend result [testintobj div10 1] lappend result [testbooleanobj not 1] ;# converts with SetBooleanFromAny lappend result [testobj type 1] } {456 45 0 boolean} test obj-13.5 {SetBooleanFromAny, error parsing string} { set result "" lappend result [teststringobj set 1 abc] lappend result [catch {testbooleanobj not 1} msg] lappend result $msg } {abc 1 {expected boolean value but got "abc"}} test obj-13.6 {SetBooleanFromAny, error parsing string} { set result "" lappend result [teststringobj set 1 x1.0] lappend result [catch {testbooleanobj not 1} msg] lappend result $msg } {x1.0 1 {expected boolean value but got "x1.0"}} test obj-13.7 {SetBooleanFromAny, error converting from "empty string"} { set result "" lappend result [testobj newobj 1] lappend result [catch {testbooleanobj not 1} msg] lappend result $msg } {{} 1 {expected boolean value but got ""}} test obj-13.8 {SetBooleanFromAny, unicode strings} { set result "" lappend result [teststringobj set 1 1\u7777] lappend result [catch {testbooleanobj not 1} msg] lappend result $msg } "1\u7777 1 {expected boolean value but got \"1\u7777\"}" test obj-14.1 {UpdateStringOfBoolean} { set result "" lappend result [testbooleanobj set 1 0] lappend result [testbooleanobj not 1] lappend result [testbooleanobj get 1] ;# must update string rep } {0 1 1} test obj-15.1 {Tcl_NewDoubleObj} { set result "" lappend result [testobj freeallvars] lappend result [testdoubleobj set 1 3.1459] lappend result [testobj type 1] lappend result [testobj refcount 1] } {{} 3.1459 double 2} test obj-16.1 {Tcl_SetDoubleObj, existing "empty string" object} { set result "" lappend result [testobj freeallvars] lappend result [testobj newobj 1] lappend result [testdoubleobj set 1 0.123] ;# makes existing obj boolean lappend result [testobj type 1] lappend result [testobj refcount 1] } {{} {} 0.123 double 2} test obj-16.2 {Tcl_SetDoubleObj, existing non-"empty string" object} { set result "" lappend result [testobj freeallvars] lappend result [testintobj set 1 98765] lappend result [testdoubleobj set 1 27.56] ;# makes existing obj double lappend result [testobj type 1] lappend result [testobj refcount 1] } {{} 98765 27.56 double 2} test obj-17.1 {Tcl_GetDoubleFromObj, existing double object} { set result "" lappend result [testdoubleobj set 1 16.1] lappend result [testdoubleobj mult10 1] ;# gets existing double rep } {16.1 161.0} test obj-17.2 {Tcl_GetDoubleFromObj, convert to double} { set result "" lappend result [testintobj set 1 477] lappend result [testdoubleobj div10 1] ;# must convert to bool lappend result [testobj type 1] } {477 47.7 double} test obj-17.3 {Tcl_GetDoubleFromObj, error converting to double} { set result "" lappend result [teststringobj set 1 abc] lappend result [catch {testdoubleobj mult10 1} msg] lappend result $msg } {abc 1 {expected floating-point number but got "abc"}} test obj-17.4 {Tcl_GetDoubleFromObj, error converting from "empty string"} { set result "" lappend result [testobj newobj 1] lappend result [catch {testdoubleobj div10 1} msg] lappend result $msg } {{} 1 {expected floating-point number but got ""}} test obj-18.1 {DupDoubleInternalRep} { set result "" lappend result [testdoubleobj set 1 17.1] lappend result [testobj duplicate 1 2] ;# uses DupDoubleInternalRep lappend result [testdoubleobj get 2] } {17.1 17.1 17.1} test obj-19.1 {SetDoubleFromAny, int to double special case} { set result "" lappend result [testintobj set 1 1234] lappend result [testdoubleobj mult10 1] ;# converts with SetDoubleFromAny lappend result [testobj type 1] } {1234 12340.0 double} test obj-19.2 {SetDoubleFromAny, boolean to double special case} { set result "" lappend result [testbooleanobj set 1 1] lappend result [testdoubleobj mult10 1] ;# converts with SetDoubleFromAny lappend result [testobj type 1] } {1 10.0 double} test obj-19.3 {SetDoubleFromAny, recompute string rep then parse it} { set result "" lappend result [testintobj set 1 456] lappend result [testintobj div10 1] lappend result [testdoubleobj mult10 1] ;# converts with SetDoubleFromAny lappend result [testobj type 1] } {456 45 450.0 double} test obj-19.4 {SetDoubleFromAny, error parsing string} { set result "" lappend result [teststringobj set 1 abc] lappend result [catch {testdoubleobj mult10 1} msg] lappend result $msg } {abc 1 {expected floating-point number but got "abc"}} test obj-19.5 {SetDoubleFromAny, error parsing string} { set result "" lappend result [teststringobj set 1 x1.0] lappend result [catch {testdoubleobj mult10 1} msg] lappend result $msg } {x1.0 1 {expected floating-point number but got "x1.0"}} test obj-19.6 {SetDoubleFromAny, error converting from "empty string"} { set result "" lappend result [testobj newobj 1] lappend result [catch {testdoubleobj div10 1} msg] lappend result $msg } {{} 1 {expected floating-point number but got ""}} test obj-20.1 {UpdateStringOfDouble} { set result "" lappend result [testdoubleobj set 1 3.14159] lappend result [testdoubleobj mult10 1] lappend result [testdoubleobj get 1] ;# must update string rep } {3.14159 31.4159 31.4159} test obj-21.1 {Tcl_NewIntObj} { set result "" lappend result [testobj freeallvars] lappend result [testintobj set 1 55] lappend result [testobj type 1] lappend result [testobj refcount 1] } {{} 55 int 2} test obj-22.1 {Tcl_SetIntObj, existing "empty string" object} { set result "" lappend result [testobj freeallvars] lappend result [testobj newobj 1] lappend result [testintobj set 1 77] ;# makes existing obj int lappend result [testobj type 1] lappend result [testobj refcount 1] } {{} {} 77 int 2} test obj-22.2 {Tcl_SetIntObj, existing non-"empty string" object} { set result "" lappend result [testobj freeallvars] lappend result [testdoubleobj set 1 12.34] lappend result [testintobj set 1 77] ;# makes existing obj int lappend result [testobj type 1] lappend result [testobj refcount 1] } {{} 12.34 77 int 2} test obj-23.1 {Tcl_GetIntFromObj, existing int object} { set result "" lappend result [testintobj set 1 22] lappend result [testintobj mult10 1] ;# gets existing int rep } {22 220} test obj-23.2 {Tcl_GetIntFromObj, convert to int} { set result "" lappend result [testintobj set 1 477] lappend result [testintobj div10 1] ;# must convert to bool lappend result [testobj type 1] } {477 47 int} test obj-23.3 {Tcl_GetIntFromObj, error converting to int} { set result "" lappend result [teststringobj set 1 abc] lappend result [catch {testintobj mult10 1} msg] lappend result $msg } {abc 1 {expected integer but got "abc"}} test obj-23.4 {Tcl_GetIntFromObj, error converting from "empty string"} { set result "" lappend result [testobj newobj 1] lappend result [catch {testintobj div10 1} msg] lappend result $msg } {{} 1 {expected integer but got ""}} test obj-23.5 {Tcl_GetIntFromObj, integer too large to represent as non-long error} {nonPortable} { set result "" lappend result [testobj newobj 1] lappend result [testintobj inttoobigtest 1] } {{} 1} test obj-24.1 {DupIntInternalRep} { set result "" lappend result [testintobj set 1 23] lappend result [testobj duplicate 1 2] ;# uses DupIntInternalRep lappend result [testintobj get 2] } {23 23 23} test obj-25.1 {SetIntFromAny, int to int special case} { set result "" lappend result [testintobj set 1 1234] lappend result [testintobj mult10 1] ;# converts with SetIntFromAny lappend result [testobj type 1] } {1234 12340 int} test obj-25.2 {SetIntFromAny, boolean to int special case} { set result "" lappend result [testbooleanobj set 1 1] lappend result [testintobj mult10 1] ;# converts with SetIntFromAny lappend result [testobj type 1] } {1 10 int} test obj-25.3 {SetIntFromAny, recompute string rep then parse it} { set result "" lappend result [testintobj set 1 456] lappend result [testintobj div10 1] lappend result [testintobj mult10 1] ;# converts with SetIntFromAny lappend result [testobj type 1] } {456 45 450 int} test obj-25.4 {SetIntFromAny, error parsing string} { set result "" lappend result [teststringobj set 1 abc] lappend result [catch {testintobj mult10 1} msg] lappend result $msg } {abc 1 {expected integer but got "abc"}} test obj-25.5 {SetIntFromAny, error parsing string} { set result "" lappend result [teststringobj set 1 x17] lappend result [catch {testintobj mult10 1} msg] lappend result $msg } {x17 1 {expected integer but got "x17"}} test obj-25.6 {SetIntFromAny, integer too large} {nonPortable} { set result "" lappend result [teststringobj set 1 123456789012345678901] lappend result [catch {testintobj mult10 1} msg] lappend result $msg } {123456789012345678901 1 {integer value too large to represent}} test obj-25.7 {SetIntFromAny, error converting from "empty string"} { set result "" lappend result [testobj newobj 1] lappend result [catch {testintobj div10 1} msg] lappend result $msg } {{} 1 {expected integer but got ""}} test obj-26.1 {UpdateStringOfInt} { set result "" lappend result [testintobj set 1 512] lappend result [testintobj mult10 1] lappend result [testintobj get 1] ;# must update string rep } {512 5120 5120} test obj-27.1 {Tcl_NewLongObj} { set result "" lappend result [testobj freeallvars] testintobj setmaxlong 1 lappend result [testintobj ismaxlong 1] lappend result [testobj type 1] lappend result [testobj refcount 1] } {{} 1 int 1} test obj-28.1 {Tcl_SetLongObj, existing "empty string" object} { set result "" lappend result [testobj freeallvars] lappend result [testobj newobj 1] lappend result [testintobj setlong 1 77] ;# makes existing obj long int lappend result [testobj type 1] lappend result [testobj refcount 1] } {{} {} 77 int 2} test obj-28.2 {Tcl_SetLongObj, existing non-"empty string" object} { set result "" lappend result [testobj freeallvars] lappend result [testdoubleobj set 1 12.34] lappend result [testintobj setlong 1 77] ;# makes existing obj long int lappend result [testobj type 1] lappend result [testobj refcount 1] } {{} 12.34 77 int 2} test obj-29.1 {Tcl_GetLongFromObj, existing long integer object} { set result "" lappend result [testintobj setlong 1 22] lappend result [testintobj mult10 1] ;# gets existing long int rep } {22 220} test obj-29.2 {Tcl_GetLongFromObj, convert to long} { set result "" lappend result [testintobj setlong 1 477] lappend result [testintobj div10 1] ;# must convert to bool lappend result [testobj type 1] } {477 47 int} test obj-29.3 {Tcl_GetLongFromObj, error converting to long integer} { set result "" lappend result [teststringobj set 1 abc] lappend result [catch {testintobj ismaxlong 1} msg] ;# cvts to long int lappend result $msg } {abc 1 {expected integer but got "abc"}} test obj-29.4 {Tcl_GetLongFromObj, error converting from "empty string"} { set result "" lappend result [testobj newobj 1] lappend result [catch {testintobj ismaxlong 1} msg] ;# cvts to long int lappend result $msg } {{} 1 {expected integer but got ""}} test obj-30.1 {Ref counting and object deletion, simple types} { set result "" lappend result [testobj freeallvars] lappend result [testintobj set 1 1024] lappend result [testobj assign 1 2] ;# vars 1 and 2 share the int obj lappend result [testobj type 2] lappend result [testobj refcount 1] lappend result [testobj refcount 2] lappend result [testbooleanobj set 2 0] ;# must copy on write, now 2 objs lappend result [testobj type 2] lappend result [testobj refcount 1] lappend result [testobj refcount 2] } {{} 1024 1024 int 4 4 0 boolean 3 2} test obj-31.1 {regenerate string rep of "end"} { testobj freeallvars teststringobj set 1 end testobj convert 1 end-offset testobj invalidateStringRep 1 } end test obj-31.2 {regenerate string rep of "end-1"} { testobj freeallvars teststringobj set 1 end-0x1 testobj convert 1 end-offset testobj invalidateStringRep 1 } end-1 test obj-31.3 {regenerate string rep of "end--1"} { testobj freeallvars teststringobj set 1 end--0x1 testobj convert 1 end-offset testobj invalidateStringRep 1 } end--1 test obj-31.4 {regenerate string rep of "end-bigInteger"} { testobj freeallvars teststringobj set 1 end-0x7fffffff testobj convert 1 end-offset testobj invalidateStringRep 1 } end-2147483647 test obj-31.5 {regenerate string rep of "end--bigInteger"} { testobj freeallvars teststringobj set 1 end--0x7fffffff testobj convert 1 end-offset testobj invalidateStringRep 1 } end--2147483647 test obj-31.6 {regenerate string rep of "end--bigInteger"} {nonPortable} { testobj freeallvars teststringobj set 1 end--0x80000000 testobj convert 1 end-offset testobj invalidateStringRep 1 } end--2147483648 test obj-32.1 {integer overflow on input} {32bit wideBiggerThanInt} { set x 0x8000; append x 0000 list [string is integer $x] [expr { wide($x) }] } {1 2147483648} test obj-32.2 {integer overflow on input} {32bit wideBiggerThanInt} { set x 0xffff; append x ffff list [string is integer $x] [expr { wide($x) }] } {1 4294967295} test obj-32.3 {integer overflow on input} {32bit wideBiggerThanInt} { set x 0x10000; append x 0000 list [string is integer $x] [expr { wide($x) }] } {0 4294967296} test obj-32.4 {integer overflow on input} {32bit wideBiggerThanInt} { set x -0x8000; append x 0000 list [string is integer $x] [expr { wide($x) }] } {1 -2147483648} test obj-32.5 {integer overflow on input} {32bit wideBiggerThanInt} { set x -0x8000; append x 0001 list [string is integer $x] [expr { wide($x) }] } {1 -2147483649} test obj-32.6 {integer overflow on input} {32bit wideBiggerThanInt} { set x -0xffff; append x ffff list [string is integer $x] [expr { wide($x) }] } {1 -4294967295} test obj-32.7 {integer overflow on input} {32bit wideBiggerThanInt} { set x -0x10000; append x 0000 list [string is integer $x] [expr { wide($x) }] } {0 -4294967296} testobj freeallvars # cleanup ::tcltest::cleanupTests return # Local Variables: # mode: tcl # End: tcl8.4.20/tests/load.test0000644003604700454610000002077412052456744013712 0ustar dgp771div# Commands covered: load # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1995 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import -force ::tcltest::* } # Figure out what extension is used for shared libraries on this # platform. # Tests require the existence of one of the DLLs in the dltest directory. set ext [info sharedlibextension] set testDir [file join [file dirname [info nameofexecutable]] dltest] set x [file join $testDir pkga$ext] set dll "[file tail $x]Required" ::tcltest::testConstraint $dll [file readable $x] # Tests also require that this DLL has not already been loaded. set loaded "[file tail $x]Loaded" set alreadyLoaded [info loaded] ::tcltest::testConstraint $loaded \ [expr {![string match *pkga* $alreadyLoaded]}] set alreadyTotalLoaded [info loaded] # Certain tests require the 'teststaticpkg' command from tcltest ::tcltest::testConstraint teststaticpkg \ [string compare {} [info commands teststaticpkg]] # Test load-10.1 requires the 'testsimplefilesystem' command from tcltest ::tcltest::testConstraint testsimplefilesystem \ [string compare {} [info commands testsimplefilesystem]] test load-1.1 {basic errors} {} { list [catch {load} msg] $msg } "1 {wrong \# args: should be \"load fileName ?packageName? ?interp?\"}" test load-1.2 {basic errors} {} { list [catch {load a b c d} msg] $msg } "1 {wrong \# args: should be \"load fileName ?packageName? ?interp?\"}" test load-1.3 {basic errors} {} { list [catch {load a b foobar} msg] $msg } {1 {could not find interpreter "foobar"}} test load-1.4 {basic errors} {} { list [catch {load {}} msg] $msg } {1 {must specify either file name or package name}} test load-1.5 {basic errors} {} { list [catch {load {} {}} msg] $msg } {1 {must specify either file name or package name}} test load-1.6 {basic errors} {} { list [catch {load {} Unknown} msg] $msg } {1 {package "Unknown" isn't loaded statically}} test load-2.1 {basic loading, with guess for package name} \ [list $dll $loaded] { load [file join $testDir pkga$ext] list [pkga_eq abc def] [info commands pkga_*] } {0 {pkga_eq pkga_quote}} interp create -safe child test load-2.2 {loading into a safe interpreter, with package name conversion} \ [list $dll $loaded] { load [file join $testDir pkgb$ext] pKgB child list [child eval pkgb_sub 44 13] [catch {child eval pkgb_unsafe} msg] $msg \ [catch {pkgb_sub 12 10} msg2] $msg2 } {31 1 {invalid command name "pkgb_unsafe"} 1 {invalid command name "pkgb_sub"}} test load-2.3 {loading with no _Init procedure} -constraints [list $dll $loaded] \ -body { list [catch {load [file join $testDir pkgc$ext] foo} msg] $msg } -match glob -result {1 {*couldn't find procedure Foo_Init}} test load-2.4 {loading with no _SafeInit procedure} [list $dll $loaded] { list [catch {load [file join $testDir pkga$ext] {} child} msg] $msg } {1 {can't use package in a safe interpreter: no Pkga_SafeInit procedure}} test load-3.1 {error in _Init procedure, same interpreter} \ [list $dll $loaded] { list [catch {load [file join $testDir pkge$ext] pkge} msg] \ $msg $errorInfo $errorCode } {1 {couldn't open "non_existent": no such file or directory} {couldn't open "non_existent": no such file or directory while executing "open non_existent" invoked from within "if 44 {open non_existent}" invoked from within "load [file join $testDir pkge$ext] pkge"} {POSIX ENOENT {no such file or directory}}} test load-3.2 {error in _Init procedure, slave interpreter} \ [list $dll $loaded] { catch {interp delete x} interp create x set errorCode foo set errorInfo bar set result [list [catch {load [file join $testDir pkge$ext] pkge x} msg] \ $msg $errorInfo $errorCode] interp delete x set result } {1 {couldn't open "non_existent": no such file or directory} {couldn't open "non_existent": no such file or directory while executing "open non_existent" invoked from within "if 44 {open non_existent}" invoked from within "load [file join $testDir pkge$ext] pkge x"} {POSIX ENOENT {no such file or directory}}} test load-4.1 {reloading package into same interpreter} [list $dll $loaded] { list [catch {load [file join $testDir pkga$ext] pkga} msg] $msg } {0 {}} test load-4.2 {reloading package into same interpreter} [list $dll $loaded] { list [catch {load [file join $testDir pkga$ext] pkgb} msg] $msg } [list 1 "file \"[file join $testDir pkga$ext]\" is already loaded for package \"Pkga\""] test load-5.1 {file name not specified and no static package: pick default} \ [list $dll $loaded] { catch {interp delete x} interp create x load [file join $testDir pkga$ext] pkga load {} pkga x set result [info loaded x] interp delete x set result } [list [list [file join $testDir pkga$ext] Pkga]] # On some platforms, like SunOS 4.1.3, these tests can't be run because # they cause the process to exit. test load-6.1 {errors loading file} [list $dll $loaded nonPortable] { catch {load foo foo} } {1} test load-7.1 {Tcl_StaticPackage procedure} [list teststaticpkg] { set x "not loaded" teststaticpkg Test 1 0 load {} Test load {} Test child list [set x] [child eval set x] } {loaded loaded} test load-7.2 {Tcl_StaticPackage procedure} [list teststaticpkg] { set x "not loaded" teststaticpkg Another 0 0 load {} Another child eval {set x "not loaded"} list [catch {load {} Another child} msg] $msg \ [child eval set x] [set x] } {1 {can't use package in a safe interpreter: no Another_SafeInit procedure} {not loaded} loaded} test load-7.3 {Tcl_StaticPackage procedure} [list teststaticpkg] { set x "not loaded" teststaticpkg More 0 1 load {} More set x } {not loaded} test load-7.4 {Tcl_StaticPackage procedure, redundant calls} \ [list teststaticpkg $dll $loaded] { teststaticpkg Double 0 1 teststaticpkg Double 0 1 info loaded } [concat [list {{} Double} {{} More} {{} Another} {{} Test} [list [file join $testDir pkge$ext] Pkge] [list [file join $testDir pkgb$ext] Pkgb] [list [file join $testDir pkga$ext] Pkga]] $alreadyTotalLoaded] test load-8.1 {TclGetLoadedPackages procedure} [list teststaticpkg $dll $loaded] { info loaded } [concat [list {{} Double} {{} More} {{} Another} {{} Test} [list [file join $testDir pkge$ext] Pkge] [list [file join $testDir pkgb$ext] Pkgb] [list [file join $testDir pkga$ext] Pkga]] $alreadyTotalLoaded] test load-8.2 {TclGetLoadedPackages procedure} [list teststaticpkg] { list [catch {info loaded gorp} msg] $msg } {1 {could not find interpreter "gorp"}} test load-8.3 {TclGetLoadedPackages procedure} [list teststaticpkg $dll $loaded] { list [info loaded {}] [info loaded child] } [list [concat [list {{} Double} {{} More} {{} Another} {{} Test} [list [file join $testDir pkga$ext] Pkga]] $alreadyLoaded] [list {{} Test} [list [file join $testDir pkgb$ext] Pkgb]]] test load-8.4 {TclGetLoadedPackages procedure} [list $dll $loaded teststaticpkg] { load [file join $testDir pkgb$ext] pkgb list [info loaded {}] [lsort [info commands pkgb_*]] } [list [concat [list [list [file join $testDir pkgb$ext] Pkgb] {{} Double} {{} More} {{} Another} {{} Test} [list [file join $testDir pkga$ext] Pkga]] $alreadyLoaded] {pkgb_sub pkgb_unsafe}] interp delete child test load-9.1 {Tcl_StaticPackage, load already-loaded package into another interp} \ -constraints {teststaticpkg} \ -setup { interp create child1 interp create child2 load {} Tcltest child1 load {} Tcltest child2 } \ -body { child1 eval { teststaticpkg Loadninepointone 0 1 } child2 eval { teststaticpkg Loadninepointone 0 1 } list \ [child1 eval { info loaded {} }] \ [child2 eval { info loaded {} }] } \ -result {{{{} Loadninepointone} {{} Tcltest}} {{{} Loadninepointone} {{} Tcltest}}} \ -cleanup { interp delete child1 ; interp delete child2 } test load-10.1 {load from vfs} \ -constraints [list $dll $loaded testsimplefilesystem] \ -setup {set dir [pwd]; cd $testDir; testsimplefilesystem 1} \ -body {list [catch {load simplefs:/pkgd$ext pkgd} msg] $msg} \ -result {0 {}} \ -cleanup {testsimplefilesystem 0; cd $dir; unset dir} # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/namespace-old.test0000644003604700454610000010036111737050674015473 0ustar dgp771div# Functionality covered: this file contains slightly modified versions of # the original tests written by Mike McLennan of Lucent Technologies for # the procedures in tclNamesp.c that implement Tcl's basic support for # namespaces. Other namespace-related tests appear in namespace.test # and variable.test. # # Sourcing this file into Tcl runs the tests and generates output for # errors. No output means no errors were found. # # Copyright (c) 1997 Sun Microsystems, Inc. # Copyright (c) 1997 Lucent Technologies # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } # Clear out any namespaces called test_ns_* catch {eval namespace delete [namespace children :: test_ns_*]} test namespace-old-1.1 {usage for "namespace" command} { list [catch {namespace} msg] $msg } {1 {wrong # args: should be "namespace subcommand ?arg ...?"}} test namespace-old-1.2 {global namespace's name is "::" or {}} { list [namespace current] [namespace eval {} {namespace current}] } {:: ::} test namespace-old-1.3 {usage for "namespace eval"} { list [catch {namespace eval} msg] $msg } {1 {wrong # args: should be "namespace eval name arg ?arg...?"}} test namespace-old-1.4 {create new namespaces} { list [lsort [namespace children :: test_ns_simple*]] \ [namespace eval test_ns_simple {}] \ [namespace eval test_ns_simple2 {}] \ [lsort [namespace children :: test_ns_simple*]] } {{} {} {} {::test_ns_simple ::test_ns_simple2}} test namespace-old-1.5 {access a new namespace} { namespace eval test_ns_simple { namespace current } } {::test_ns_simple} test namespace-old-1.6 {usage for "namespace eval"} { list [catch {namespace eval} msg] $msg } {1 {wrong # args: should be "namespace eval name arg ?arg...?"}} test namespace-old-1.7 {usage for "namespace eval"} { list [catch {namespace eval test_ns_xyzzy} msg] $msg } {1 {wrong # args: should be "namespace eval name arg ?arg...?"}} test namespace-old-1.8 {command "namespace eval" concatenates args} { namespace eval test_ns_simple namespace current } {::test_ns_simple} test namespace-old-1.9 {add elements to a namespace} { namespace eval test_ns_simple { variable test_ns_x 0 proc test {test_ns_x} { return "test: $test_ns_x" } } } {} test namespace-old-1.10 {commands in a namespace} { namespace eval test_ns_simple { info commands [namespace current]::*} } {::test_ns_simple::test} test namespace-old-1.11 {variables in a namespace} { namespace eval test_ns_simple { info vars [namespace current]::* } } {::test_ns_simple::test_ns_x} test namespace-old-1.12 {global vars are separate from locals vars} { list [test_ns_simple::test 123] [set test_ns_simple::test_ns_x] } {{test: 123} 0} test namespace-old-1.13 {add to an existing namespace} { namespace eval test_ns_simple { variable test_ns_y 123 proc _backdoor {cmd} { eval $cmd } } } "" test namespace-old-1.14 {commands in a namespace} { lsort [namespace eval test_ns_simple {info commands [namespace current]::*}] } {::test_ns_simple::_backdoor ::test_ns_simple::test} test namespace-old-1.15 {variables in a namespace} { lsort [namespace eval test_ns_simple {info vars [namespace current]::*}] } {::test_ns_simple::test_ns_x ::test_ns_simple::test_ns_y} test namespace-old-1.16 {variables in a namespace} { lsort [info vars test_ns_simple::*] } {::test_ns_simple::test_ns_x ::test_ns_simple::test_ns_y} test namespace-old-1.17 {commands in a namespace are hidden} { list [catch "_backdoor {return yes!}" msg] $msg } {1 {invalid command name "_backdoor"}} test namespace-old-1.18 {using namespace qualifiers} { list [catch "test_ns_simple::_backdoor {return yes!}" msg] $msg } {0 yes!} test namespace-old-1.19 {using absolute namespace qualifiers} { list [catch "::test_ns_simple::_backdoor {return yes!}" msg] $msg } {0 yes!} test namespace-old-1.20 {variables in a namespace are hidden} { list [catch "set test_ns_x" msg] $msg [catch "set test_ns_y" msg] $msg } {1 {can't read "test_ns_x": no such variable} 1 {can't read "test_ns_y": no such variable}} test namespace-old-1.21 {using namespace qualifiers} { list [catch "set test_ns_simple::test_ns_x" msg] $msg \ [catch "set test_ns_simple::test_ns_y" msg] $msg } {0 0 0 123} test namespace-old-1.22 {using absolute namespace qualifiers} { list [catch "set ::test_ns_simple::test_ns_x" msg] $msg \ [catch "set ::test_ns_simple::test_ns_y" msg] $msg } {0 0 0 123} test namespace-old-1.23 {variables can be accessed within a namespace} { test_ns_simple::_backdoor { variable test_ns_x variable test_ns_y return "$test_ns_x $test_ns_y" } } {0 123} test namespace-old-1.24 {setting global variables} { test_ns_simple::_backdoor {variable test_ns_x; set test_ns_x "new val"} namespace eval test_ns_simple {set test_ns_x} } {new val} test namespace-old-1.25 {qualified variables don't need a global declaration} { namespace eval test_ns_another { variable test_ns_x 456 } set cmd {set ::test_ns_another::test_ns_x} list [catch {test_ns_simple::_backdoor "$cmd some-value"} msg] $msg \ [eval $cmd] } {0 some-value some-value} test namespace-old-1.26 {namespace qualifiers are okay after $'s} { namespace eval test_ns_simple { set test_ns_x 12; set test_ns_y 34 } set cmd {list $::test_ns_simple::test_ns_x $::test_ns_simple::test_ns_y} list [test_ns_simple::_backdoor $cmd] [eval $cmd] } {{12 34} {12 34}} test namespace-old-1.27 {can create commands with null names} { proc test_ns_simple:: {args} {return $args} } {} # ----------------------------------------------------------------------- # TEST: using "info" in namespace contexts # ----------------------------------------------------------------------- test namespace-old-2.1 {querying: info commands} { lsort [test_ns_simple::_backdoor {info commands [namespace current]::*}] } {::test_ns_simple:: ::test_ns_simple::_backdoor ::test_ns_simple::test} test namespace-old-2.2 {querying: info procs} { lsort [test_ns_simple::_backdoor {info procs}] } {{} _backdoor test} test namespace-old-2.3 {querying: info vars} { lsort [info vars test_ns_simple::*] } {::test_ns_simple::test_ns_x ::test_ns_simple::test_ns_y} test namespace-old-2.4 {querying: info vars} { lsort [test_ns_simple::_backdoor {info vars [namespace current]::*}] } {::test_ns_simple::test_ns_x ::test_ns_simple::test_ns_y} test namespace-old-2.5 {querying: info locals} { lsort [test_ns_simple::_backdoor {info locals}] } {cmd} test namespace-old-2.6 {querying: info exists} { test_ns_simple::_backdoor {info exists test_ns_x} } {0} test namespace-old-2.7 {querying: info exists} { test_ns_simple::_backdoor {info exists cmd} } {1} test namespace-old-2.8 {querying: info args} { info args test_ns_simple::_backdoor } {cmd} test namespace-old-2.9 {querying: info body} { string trim [info body test_ns_simple::test] } {return "test: $test_ns_x"} # ----------------------------------------------------------------------- # TEST: namespace qualifiers, namespace tail # ----------------------------------------------------------------------- test namespace-old-3.1 {usage for "namespace qualifiers"} { list [catch "namespace qualifiers" msg] $msg } {1 {wrong # args: should be "namespace qualifiers string"}} test namespace-old-3.2 {querying: namespace qualifiers} { list [namespace qualifiers ""] \ [namespace qualifiers ::] \ [namespace qualifiers x] \ [namespace qualifiers ::x] \ [namespace qualifiers foo::x] \ [namespace qualifiers ::foo::bar::xyz] } {{} {} {} {} foo ::foo::bar} test namespace-old-3.3 {usage for "namespace tail"} { list [catch "namespace tail" msg] $msg } {1 {wrong # args: should be "namespace tail string"}} test namespace-old-3.4 {querying: namespace tail} { list [namespace tail ""] \ [namespace tail ::] \ [namespace tail x] \ [namespace tail ::x] \ [namespace tail foo::x] \ [namespace tail ::foo::bar::xyz] } {{} {} x x x xyz} # ----------------------------------------------------------------------- # TEST: delete commands and namespaces # ----------------------------------------------------------------------- test namespace-old-4.1 {define test namespaces} { namespace eval test_ns_delete { namespace eval ns1 { variable var1 1 proc cmd1 {} {return "cmd1"} } namespace eval ns2 { variable var2 2 proc cmd2 {} {return "cmd2"} } namespace eval another {} lsort [namespace children] } } {::test_ns_delete::another ::test_ns_delete::ns1 ::test_ns_delete::ns2} test namespace-old-4.2 {it's okay to invoke "namespace delete" with no args} { list [catch {namespace delete} msg] $msg } {0 {}} test namespace-old-4.3 {command "namespace delete" doesn't support patterns} { set cmd { namespace eval test_ns_delete {namespace delete ns*} } list [catch $cmd msg] $msg } {1 {unknown namespace "ns*" in namespace delete command}} test namespace-old-4.4 {command "namespace delete" handles multiple args} { set cmd { namespace eval test_ns_delete { eval namespace delete \ [namespace children [namespace current] ns?] } } list [catch $cmd msg] $msg [namespace children test_ns_delete] } {0 {} ::test_ns_delete::another} # ----------------------------------------------------------------------- # TEST: namespace hierarchy # ----------------------------------------------------------------------- test namespace-old-5.1 {define nested namespaces} { set test_ns_var_global "var in ::" proc test_ns_cmd_global {} {return "cmd in ::"} namespace eval test_ns_hier1 { set test_ns_var_hier1 "particular to hier1" proc test_ns_cmd_hier1 {} {return "particular to hier1"} set test_ns_level 1 proc test_ns_show {} {return "[namespace current]: 1"} namespace eval test_ns_hier2 { set test_ns_var_hier2 "particular to hier2" proc test_ns_cmd_hier2 {} {return "particular to hier2"} set test_ns_level 2 proc test_ns_show {} {return "[namespace current]: 2"} namespace eval test_ns_hier3a {} namespace eval test_ns_hier3b {} } namespace eval test_ns_hier2a {} namespace eval test_ns_hier2b {} } } {} test namespace-old-5.2 {namespaces can be nested} { list [namespace eval test_ns_hier1 {namespace current}] \ [namespace eval test_ns_hier1 { namespace eval test_ns_hier2 {namespace current} }] } {::test_ns_hier1 ::test_ns_hier1::test_ns_hier2} test namespace-old-5.3 {namespace qualifiers work in namespace command} { list [namespace eval ::test_ns_hier1 {namespace current}] \ [namespace eval test_ns_hier1::test_ns_hier2 {namespace current}] \ [namespace eval ::test_ns_hier1::test_ns_hier2 {namespace current}] } {::test_ns_hier1 ::test_ns_hier1::test_ns_hier2 ::test_ns_hier1::test_ns_hier2} test namespace-old-5.4 {nested namespaces can access global namespace} { list [namespace eval test_ns_hier1 {set test_ns_var_global}] \ [namespace eval test_ns_hier1 {test_ns_cmd_global}] \ [namespace eval test_ns_hier1::test_ns_hier2 {set test_ns_var_global}] \ [namespace eval test_ns_hier1::test_ns_hier2 {test_ns_cmd_global}] } {{var in ::} {cmd in ::} {var in ::} {cmd in ::}} test namespace-old-5.5 {variables in different namespaces don't conflict} { list [set test_ns_hier1::test_ns_level] \ [set test_ns_hier1::test_ns_hier2::test_ns_level] } {1 2} test namespace-old-5.6 {commands in different namespaces don't conflict} { list [test_ns_hier1::test_ns_show] \ [test_ns_hier1::test_ns_hier2::test_ns_show] } {{::test_ns_hier1: 1} {::test_ns_hier1::test_ns_hier2: 2}} test namespace-old-5.7 {nested namespaces don't see variables in parent} { set cmd { namespace eval test_ns_hier1::test_ns_hier2 {set test_ns_var_hier1} } list [catch $cmd msg] $msg } {1 {can't read "test_ns_var_hier1": no such variable}} test namespace-old-5.8 {nested namespaces don't see commands in parent} { set cmd { namespace eval test_ns_hier1::test_ns_hier2 {test_ns_cmd_hier1} } list [catch $cmd msg] $msg } {1 {invalid command name "test_ns_cmd_hier1"}} test namespace-old-5.9 {usage for "namespace children"} { list [catch {namespace children test_ns_hier1 y z} msg] $msg } {1 {wrong # args: should be "namespace children ?name? ?pattern?"}} test namespace-old-5.10 {command "namespace children" must get valid namespace} { list [catch {namespace children xyzzy} msg] $msg } {1 {unknown namespace "xyzzy" in namespace children command}} test namespace-old-5.11 {querying namespace children} { lsort [namespace children :: test_ns_hier*] } {::test_ns_hier1} test namespace-old-5.12 {querying namespace children} { lsort [namespace children test_ns_hier1] } {::test_ns_hier1::test_ns_hier2 ::test_ns_hier1::test_ns_hier2a ::test_ns_hier1::test_ns_hier2b} test namespace-old-5.13 {querying namespace children} { lsort [namespace eval test_ns_hier1 {namespace children}] } {::test_ns_hier1::test_ns_hier2 ::test_ns_hier1::test_ns_hier2a ::test_ns_hier1::test_ns_hier2b} test namespace-old-5.14 {querying namespace children} { lsort [namespace children test_ns_hier1::test_ns_hier2] } {::test_ns_hier1::test_ns_hier2::test_ns_hier3a ::test_ns_hier1::test_ns_hier2::test_ns_hier3b} test namespace-old-5.15 {querying namespace children} { lsort [namespace eval test_ns_hier1::test_ns_hier2 {namespace children}] } {::test_ns_hier1::test_ns_hier2::test_ns_hier3a ::test_ns_hier1::test_ns_hier2::test_ns_hier3b} test namespace-old-5.16 {querying namespace children with patterns} { lsort [namespace children test_ns_hier1::test_ns_hier2 test_ns_*] } {::test_ns_hier1::test_ns_hier2::test_ns_hier3a ::test_ns_hier1::test_ns_hier2::test_ns_hier3b} test namespace-old-5.17 {querying namespace children with patterns} { lsort [namespace children test_ns_hier1::test_ns_hier2 *b] } {::test_ns_hier1::test_ns_hier2::test_ns_hier3b} test namespace-old-5.18 {usage for "namespace parent"} { list [catch {namespace parent x y} msg] $msg } {1 {wrong # args: should be "namespace parent ?name?"}} test namespace-old-5.19 {command "namespace parent" must get valid namespace} { list [catch {namespace parent xyzzy} msg] $msg } {1 {unknown namespace "xyzzy" in namespace parent command}} test namespace-old-5.20 {querying namespace parent} { list [namespace eval :: {namespace parent}] \ [namespace eval test_ns_hier1 {namespace parent}] \ [namespace eval test_ns_hier1::test_ns_hier2 {namespace parent}] \ [namespace eval test_ns_hier1::test_ns_hier2::test_ns_hier3a {namespace parent}] \ } {{} :: ::test_ns_hier1 ::test_ns_hier1::test_ns_hier2} test namespace-old-5.21 {querying namespace parent for explicit namespace} { list [namespace parent ::] \ [namespace parent test_ns_hier1] \ [namespace parent test_ns_hier1::test_ns_hier2] \ [namespace parent test_ns_hier1::test_ns_hier2::test_ns_hier3a] } {{} :: ::test_ns_hier1 ::test_ns_hier1::test_ns_hier2} # ----------------------------------------------------------------------- # TEST: name resolution and caching # ----------------------------------------------------------------------- test namespace-old-6.1 {relative ns names only looked up in current ns} { namespace eval test_ns_cache1 {} namespace eval test_ns_cache2 {} namespace eval test_ns_cache2::test_ns_cache3 {} set trigger { namespace eval test_ns_cache2 {namespace current} } set trigger2 { namespace eval test_ns_cache2::test_ns_cache3 {namespace current} } list [namespace eval test_ns_cache1 $trigger] \ [namespace eval test_ns_cache1 $trigger2] } {::test_ns_cache1::test_ns_cache2 ::test_ns_cache1::test_ns_cache2::test_ns_cache3} test namespace-old-6.2 {relative ns names only looked up in current ns} { namespace eval test_ns_cache1::test_ns_cache2 {} list [namespace eval test_ns_cache1 $trigger] \ [namespace eval test_ns_cache1 $trigger2] } {::test_ns_cache1::test_ns_cache2 ::test_ns_cache1::test_ns_cache2::test_ns_cache3} test namespace-old-6.3 {relative ns names only looked up in current ns} { namespace eval test_ns_cache1::test_ns_cache2::test_ns_cache3 {} list [namespace eval test_ns_cache1 $trigger] \ [namespace eval test_ns_cache1 $trigger2] } {::test_ns_cache1::test_ns_cache2 ::test_ns_cache1::test_ns_cache2::test_ns_cache3} test namespace-old-6.4 {relative ns names only looked up in current ns} { namespace delete test_ns_cache1::test_ns_cache2 list [namespace eval test_ns_cache1 $trigger] \ [namespace eval test_ns_cache1 $trigger2] } {::test_ns_cache1::test_ns_cache2 ::test_ns_cache1::test_ns_cache2::test_ns_cache3} test namespace-old-6.5 {define test commands} { proc test_ns_cache_cmd {} { return "global version" } namespace eval test_ns_cache1 { proc trigger {} { test_ns_cache_cmd } } test_ns_cache1::trigger } {global version} test namespace-old-6.6 {one-level check for command shadowing} { proc test_ns_cache1::test_ns_cache_cmd {} { return "cache1 version" } test_ns_cache1::trigger } {cache1 version} test namespace-old-6.7 {renaming commands changes command epoch} { namespace eval test_ns_cache1 { rename test_ns_cache_cmd test_ns_new } test_ns_cache1::trigger } {global version} test namespace-old-6.8 {renaming back handles shadowing} { namespace eval test_ns_cache1 { rename test_ns_new test_ns_cache_cmd } test_ns_cache1::trigger } {cache1 version} test namespace-old-6.9 {deleting commands changes command epoch} { namespace eval test_ns_cache1 { rename test_ns_cache_cmd "" } test_ns_cache1::trigger } {global version} test namespace-old-6.10 {define test namespaces} { namespace eval test_ns_cache2 { proc test_ns_cache_cmd {} { return "global cache2 version" } } namespace eval test_ns_cache1 { proc trigger {} { test_ns_cache2::test_ns_cache_cmd } } namespace eval test_ns_cache1::test_ns_cache2 { proc trigger {} { test_ns_cache_cmd } } list [test_ns_cache1::trigger] [test_ns_cache1::test_ns_cache2::trigger] } {{global cache2 version} {global version}} test namespace-old-6.11 {commands affect all parent namespaces} { proc test_ns_cache1::test_ns_cache2::test_ns_cache_cmd {} { return "cache2 version" } list [test_ns_cache1::trigger] [test_ns_cache1::test_ns_cache2::trigger] } {{cache2 version} {cache2 version}} test namespace-old-6.12 {define test variables} { variable test_ns_cache_var "global version" set trigger {set test_ns_cache_var} namespace eval test_ns_cache1 $trigger } {global version} test namespace-old-6.13 {one-level check for variable shadowing} { namespace eval test_ns_cache1 { variable test_ns_cache_var "cache1 version" } namespace eval test_ns_cache1 $trigger } {cache1 version} test namespace-old-6.14 {deleting variables changes variable epoch} { namespace eval test_ns_cache1 { unset test_ns_cache_var } namespace eval test_ns_cache1 $trigger } {global version} test namespace-old-6.15 {define test namespaces} { namespace eval test_ns_cache2 { variable test_ns_cache_var "global cache2 version" } set trigger2 {set test_ns_cache2::test_ns_cache_var} list [namespace eval test_ns_cache1 $trigger2] \ [namespace eval test_ns_cache1::test_ns_cache2 $trigger] } {{global cache2 version} {global version}} test namespace-old-6.16 {public variables affect all parent namespaces} { variable test_ns_cache1::test_ns_cache2::test_ns_cache_var "cache2 version" list [namespace eval test_ns_cache1 $trigger2] \ [namespace eval test_ns_cache1::test_ns_cache2 $trigger] } {{cache2 version} {cache2 version}} test namespace-old-6.17 {usage for "namespace which"} { list [catch "namespace which -baz" msg] $msg } {1 {wrong # args: should be "namespace which ?-command? ?-variable? name"}} test namespace-old-6.18 {usage for "namespace which"} { list [catch "namespace which -command" msg] $msg } {1 {wrong # args: should be "namespace which ?-command? ?-variable? name"}} test namespace-old-6.19 {querying: namespace which -command} { proc test_ns_cache1::test_ns_cache_cmd {} { return "cache1 version" } list [namespace eval :: {namespace which test_ns_cache_cmd}] \ [namespace eval test_ns_cache1 {namespace which test_ns_cache_cmd}] \ [namespace eval :: {namespace which -command test_ns_cache_cmd}] \ [namespace eval test_ns_cache1 {namespace which -command test_ns_cache_cmd}] } {::test_ns_cache_cmd ::test_ns_cache1::test_ns_cache_cmd ::test_ns_cache_cmd ::test_ns_cache1::test_ns_cache_cmd} test namespace-old-6.20 {command "namespace which" may not find commands} { namespace eval test_ns_cache1 {namespace which -command xyzzy} } {} test namespace-old-6.21 {querying: namespace which -variable} { namespace eval test_ns_cache1::test_ns_cache2 { namespace which -variable test_ns_cache_var } } {::test_ns_cache1::test_ns_cache2::test_ns_cache_var} test namespace-old-6.22 {command "namespace which" may not find variables} { namespace eval test_ns_cache1 {namespace which -variable xyzzy} } {} # ----------------------------------------------------------------------- # TEST: uplevel/upvar across namespace boundaries # ----------------------------------------------------------------------- test namespace-old-7.1 {define test namespace} { namespace eval test_ns_uplevel { variable x 0 variable y 1 proc show_vars {num} { return [uplevel $num {info vars}] } proc test_uplevel {num} { set a 0 set b 1 namespace eval ::test_ns_uplevel " return \[show_vars $num\] " } } } {} test namespace-old-7.2 {uplevel can access namespace call frame} { list [expr {[lsearch -exact [test_ns_uplevel::test_uplevel 1] x]>=0}] \ [expr {[lsearch -exact [test_ns_uplevel::test_uplevel 1] y]>=0}] } {1 1} test namespace-old-7.3 {uplevel can go beyond namespace call frame} { lsort [test_ns_uplevel::test_uplevel 2] } {a b num} test namespace-old-7.4 {uplevel can go up to global context} { expr {[test_ns_uplevel::test_uplevel 3] == [info globals]} } {1} test namespace-old-7.5 {absolute call frame references work too} { list [expr {[lsearch -exact [test_ns_uplevel::test_uplevel #2] x]>=0}] \ [expr {[lsearch -exact [test_ns_uplevel::test_uplevel #2] y]>=0}] } {1 1} test namespace-old-7.6 {absolute call frame references work too} { lsort [test_ns_uplevel::test_uplevel #1] } {a b num} test namespace-old-7.7 {absolute call frame references work too} { expr {[test_ns_uplevel::test_uplevel #0] == [info globals]} } {1} test namespace-old-7.8 {namespaces are included in the call stack} { namespace eval test_ns_upvar { variable scope "test_ns_upvar" proc show_val {var num} { upvar $num $var x return $x } proc test_upvar {num} { set scope "test_ns_upvar::test_upvar" namespace eval ::test_ns_upvar " return \[show_val scope $num\] " } } } {} test namespace-old-7.9 {upvar can access namespace call frame} { test_ns_upvar::test_upvar 1 } {test_ns_upvar} test namespace-old-7.10 {upvar can go beyond namespace call frame} { test_ns_upvar::test_upvar 2 } {test_ns_upvar::test_upvar} test namespace-old-7.11 {absolute call frame references work too} { test_ns_upvar::test_upvar #2 } {test_ns_upvar} test namespace-old-7.12 {absolute call frame references work too} { test_ns_upvar::test_upvar #1 } {test_ns_upvar::test_upvar} # ----------------------------------------------------------------------- # TEST: variable traces across namespace boundaries # ----------------------------------------------------------------------- test namespace-old-8.1 {traces work across namespace boundaries} { namespace eval test_ns_trace { namespace eval foo { variable x "" } variable status "" proc monitor {name1 name2 op} { variable status lappend status "$op: $name1" } trace variable foo::x rwu [namespace code monitor] } set test_ns_trace::foo::x "yes!" set test_ns_trace::foo::x unset test_ns_trace::foo::x namespace eval test_ns_trace { set status } } {{w: test_ns_trace::foo::x} {r: test_ns_trace::foo::x} {u: test_ns_trace::foo::x}} # ----------------------------------------------------------------------- # TEST: imported commands # ----------------------------------------------------------------------- test namespace-old-9.1 {empty "namespace export" list} { list [catch "namespace export" msg] $msg } {0 {}} test namespace-old-9.2 {usage for "namespace export" command} { list [catch "namespace export test_ns_trace::zzz" msg] $msg } {1 {invalid export pattern "test_ns_trace::zzz": pattern can't specify a namespace}} test namespace-old-9.3 {define test namespaces for import} { namespace eval test_ns_export { namespace export cmd1 cmd2 cmd3 proc cmd1 {args} {return "cmd1: $args"} proc cmd2 {args} {return "cmd2: $args"} proc cmd3 {args} {return "cmd3: $args"} proc cmd4 {args} {return "cmd4: $args"} proc cmd5 {args} {return "cmd5: $args"} proc cmd6 {args} {return "cmd6: $args"} } lsort [info commands test_ns_export::*] } {::test_ns_export::cmd1 ::test_ns_export::cmd2 ::test_ns_export::cmd3 ::test_ns_export::cmd4 ::test_ns_export::cmd5 ::test_ns_export::cmd6} test namespace-old-9.4 {check export status} { set x "" namespace eval test_ns_import { namespace export cmd1 cmd2 namespace import ::test_ns_export::* } foreach cmd [lsort [info commands test_ns_import::*]] { lappend x $cmd } set x } {::test_ns_import::cmd1 ::test_ns_import::cmd2 ::test_ns_import::cmd3} test namespace-old-9.5 {empty import list in "namespace import" command} { namespace import } {} test namespace-old-9.6 {empty import list for "namespace import" command} { namespace import } {} test namespace-old-9.7 {empty forget list for "namespace forget" command} { namespace forget } {} catch {rename cmd1 {}} catch {rename cmd2 {}} catch {rename ncmd {}} catch {rename ncmd1 {}} catch {rename ncmd2 {}} test namespace-old-9.8 {only exported commands are imported} { namespace import test_ns_import::cmd* set x [lsort [info commands cmd*]] } {cmd1 cmd2} test namespace-old-9.9 {imported commands work just the same as original} { list [cmd1 test 1 2 3] [test_ns_import::cmd1 test 4 5 6] } {{cmd1: test 1 2 3} {cmd1: test 4 5 6}} test namespace-old-9.10 {commands can be imported from many namespaces} { namespace eval test_ns_import2 { namespace export ncmd ncmd1 ncmd2 proc ncmd {args} {return "ncmd: $args"} proc ncmd1 {args} {return "ncmd1: $args"} proc ncmd2 {args} {return "ncmd2: $args"} proc ncmd3 {args} {return "ncmd3: $args"} } namespace import test_ns_import2::* lsort [concat [info commands cmd*] [info commands ncmd*]] } {cmd1 cmd2 ncmd ncmd1 ncmd2} test namespace-old-9.11 {imported commands can be removed by deleting them} { rename cmd1 "" lsort [concat [info commands cmd*] [info commands ncmd*]] } {cmd2 ncmd ncmd1 ncmd2} test namespace-old-9.12 {command "namespace forget" checks for valid namespaces} { list [catch {namespace forget xyzzy::*} msg] $msg } {1 {unknown namespace in namespace forget pattern "xyzzy::*"}} test namespace-old-9.13 {command "namespace forget" ignores patterns that don't match} { list [catch {namespace forget test_ns_import::xy*zzy} msg] $msg \ [lsort [info commands cmd?]] } {0 {} cmd2} test namespace-old-9.14 {imported commands can be removed} { namespace forget test_ns_import::cmd? list [lsort [info commands cmd?]] \ [catch {cmd1 another test} msg] $msg } {{} 1 {invalid command name "cmd1"}} test namespace-old-9.15 {existing commands can't be overwritten} { proc cmd1 {x y} { return [expr $x+$y] } list [catch {namespace import test_ns_import::cmd?} msg] $msg \ [cmd1 3 5] } {1 {can't import command "cmd1": already exists} 8} test namespace-old-9.16 {use "-force" option to override existing commands} { list [cmd1 3 5] \ [namespace import -force test_ns_import::cmd?] \ [cmd1 3 5] } {8 {} {cmd1: 3 5}} test namespace-old-9.17 {commands can be imported into many namespaces} { namespace eval test_ns_import_use { namespace import ::test_ns_import::* ::test_ns_import2::ncmd? lsort [concat [info commands ::test_ns_import_use::cmd*] \ [info commands ::test_ns_import_use::ncmd*]] } } {::test_ns_import_use::cmd1 ::test_ns_import_use::cmd2 ::test_ns_import_use::ncmd1 ::test_ns_import_use::ncmd2} test namespace-old-9.18 {when command is deleted, imported commands go away} { namespace eval test_ns_import { rename cmd1 "" } list [info commands cmd1] \ [namespace eval test_ns_import_use {info commands cmd1}] } {{} {}} test namespace-old-9.19 {when namesp is deleted, all imported commands go away} { namespace delete test_ns_import test_ns_import2 list [info commands cmd*] \ [info commands ncmd*] \ [namespace eval test_ns_import_use {info commands cmd*}] \ [namespace eval test_ns_import_use {info commands ncmd*}] \ } {{} {} {} {}} # ----------------------------------------------------------------------- # TEST: scoped values # ----------------------------------------------------------------------- test namespace-old-10.1 {define namespace for scope test} { namespace eval test_ns_inscope { variable x "x-value" proc show {args} { return "show: $args" } proc do {args} { return [eval $args] } list [set x] [show test] } } {x-value {show: test}} test namespace-old-10.2 {command "namespace code" requires one argument} { list [catch {namespace code} msg] $msg } {1 {wrong # args: should be "namespace code arg"}} test namespace-old-10.3 {command "namespace code" requires one argument} { list [catch {namespace code first "second arg" third} msg] $msg } {1 {wrong # args: should be "namespace code arg"}} test namespace-old-10.4 {command "namespace code" gets current namesp context} { namespace eval test_ns_inscope { namespace code {"1 2 3" "4 5" 6} } } {::namespace inscope ::test_ns_inscope {"1 2 3" "4 5" 6}} test namespace-old-10.5 {with one arg, first "scope" sticks} { set sval [namespace eval test_ns_inscope {namespace code {one two}}] namespace code $sval } {::namespace inscope ::test_ns_inscope {one two}} test namespace-old-10.6 {with many args, each "scope" adds new args} { set sval [namespace eval test_ns_inscope {namespace code {one two}}] namespace code "$sval three" } {::namespace inscope ::test_ns_inscope {one two} three} test namespace-old-10.7 {scoped commands work with eval} { set cref [namespace eval test_ns_inscope {namespace code show}] list [eval $cref "a" "b c" "d e f"] } {{show: a b c d e f}} test namespace-old-10.8 {scoped commands execute in namespace context} { set cref [namespace eval test_ns_inscope { namespace code {set x "some new value"} }] list [set test_ns_inscope::x] [eval $cref] [set test_ns_inscope::x] } {x-value {some new value} {some new value}} foreach cmd [info commands test_ns_*] { rename $cmd "" } catch {rename cmd {}} catch {rename cmd1 {}} catch {rename cmd2 {}} catch {rename ncmd {}} catch {rename ncmd1 {}} catch {rename ncmd2 {}} catch {unset cref} catch {unset trigger} catch {unset trigger2} catch {unset sval} catch {unset msg} catch {unset x} catch {unset test_ns_var_global} catch {unset cmd} eval namespace delete [namespace children :: test_ns_*] # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/stack.test0000644003604700454610000000562312133546540014066 0ustar dgp771div# Tests that the stack size is big enough for the application. # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1998-2000 Ajuba Solutions. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import -force ::tcltest::* } # Note that a failure in this test results in a crash of the executable. # In order to avoid that, we do a basic check of the current stacksize. # This size can be changed with ulimit (ksh/bash/sh) or limit (csh/tcsh). # This doesn't catch all cases, for example threads of lower stacksize # can still squeak through. A core check is really needed. -- JH if {[string equal $::tcl_platform(platform) "unix"] && ![string equal $::tcl_platform(os) "Windows NT"]} { set stackSize [exec /bin/sh -c "ulimit -s"] if {[string is integer $stackSize] && ($stackSize < 2400)} { puts stderr "WARNING: the default application stacksize of $stackSize\ may cause Tcl to\ncrash due to stack overflow before the\ recursion limit is reached.\nA minimum stacksize of 2400\ kbytes is recommended.\nSkipping infinite recursion test." ::tcltest::testConstraint minStack2400 0 } else { ::tcltest::testConstraint minStack2400 1 } } else { ::tcltest::testConstraint minStack2400 1 } test stack-1.1 {maxNestingDepth reached on infinite recursion} {minStack2400} { proc recurse {} { return [recurse] } catch {recurse} rv rename recurse {} set rv } {too many nested evaluations (infinite loop?)} test stack-2.1 {maxNestingDepth reached on infinite recursion} {minStack2400} { # do this in a slave to not mess with parent set slave stack-2.1 interp create $slave $slave eval { interp alias {} unknown {} notaknownproc } set msg [$slave eval { catch {foo} msg ; set msg }] interp delete $slave set msg } {too many nested evaluations (infinite loop?)} # Make sure that there is enough stack to run regexp even if we're # close to the recursion limit. [Bug 947070] test stack-3.1 {enough room for regexp near recursion limit} \ -constraints { win } \ -setup { set ::limit [interp recursionlimit {} 10000] set ::depth 0 proc a { max } { if { [info level] < $max } { set ::depth [info level] a $max } else { regexp {^ ?} x } } list [catch { a 10001 }] incr depth -3 set depth2 $depth } -body { list [catch { a $::depth } result] \ $result [expr { $::depth2 - $::depth }] } -cleanup { interp recursionlimit {} $::limit } -result {0 1 1} # cleanup ::tcltest::cleanupTests return # Local Variables: # mode: tcl # End: tcl8.4.20/tests/stringObj.test0000644003604700454610000004213511737050674014730 0ustar dgp771div# Commands covered: none # # This file contains tests for the procedures in tclStringObj.c # that implement the Tcl type manager for the string type. # # Sourcing this file into Tcl runs the tests and generates output for # errors. No output means no errors were found. # # Copyright (c) 1995-1997 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } if {[info commands testobj] == {}} { puts "This application hasn't been compiled with the \"testobj\"" puts "command, so I can't test the Tcl type and object support." ::tcltest::cleanupTests return } test stringObj-1.1 {string type registration} { set t [testobj types] set first [string first "string" $t] set result [expr {$first != -1}] } {1} test stringObj-2.1 {Tcl_NewStringObj} { set result "" lappend result [testobj freeallvars] lappend result [teststringobj set 1 abcd] lappend result [testobj type 1] lappend result [testobj refcount 1] } {{} abcd string 2} test stringObj-3.1 {Tcl_SetStringObj, existing "empty string" object} { set result "" lappend result [testobj freeallvars] lappend result [testobj newobj 1] lappend result [teststringobj set 1 xyz] ;# makes existing obj a string lappend result [testobj type 1] lappend result [testobj refcount 1] } {{} {} xyz string 2} test stringObj-3.2 {Tcl_SetStringObj, existing non-"empty string" object} { set result "" lappend result [testobj freeallvars] lappend result [testintobj set 1 512] lappend result [teststringobj set 1 foo] ;# makes existing obj a string lappend result [testobj type 1] lappend result [testobj refcount 1] } {{} 512 foo string 2} test stringObj-4.1 {Tcl_SetObjLength procedure, string gets shorter} { testobj freeallvars teststringobj set 1 test teststringobj setlength 1 3 list [teststringobj length 1] [teststringobj length2 1] \ [teststringobj get 1] } {3 4 tes} test stringObj-4.2 {Tcl_SetObjLength procedure, string gets longer} { testobj freeallvars teststringobj set 1 abcdef teststringobj setlength 1 10 list [teststringobj length 1] [teststringobj length2 1] } {10 10} test stringObj-4.3 {Tcl_SetObjLength procedure, string gets longer} { testobj freeallvars teststringobj set 1 abcdef teststringobj append 1 xyzq -1 list [teststringobj length 1] [teststringobj length2 1] \ [teststringobj get 1] } {10 20 abcdefxyzq} test stringObj-4.4 {Tcl_SetObjLength procedure, "expty string", length 0} { testobj freeallvars testobj newobj 1 teststringobj setlength 1 0 list [teststringobj length2 1] [teststringobj get 1] } {0 {}} test stringObj-5.1 {Tcl_AppendToObj procedure, type conversion} { testobj freeallvars testintobj set2 1 43 teststringobj append 1 xyz -1 teststringobj get 1 } {43xyz} test stringObj-5.2 {Tcl_AppendToObj procedure, length calculation} { testobj freeallvars teststringobj set 1 {x y } teststringobj append 1 bbCCddEE 4 teststringobj append 1 123 -1 teststringobj get 1 } {x y bbCC123} test stringObj-5.3 {Tcl_AppendToObj procedure, reallocating space} { testobj freeallvars teststringobj set 1 xyz teststringobj setlength 1 15 teststringobj setlength 1 2 set result {} teststringobj append 1 1234567890123 -1 lappend result [teststringobj length 1] [teststringobj length2 1] teststringobj setlength 1 10 teststringobj append 1 abcdef -1 lappend result [teststringobj length 1] [teststringobj length2 1] \ [teststringobj get 1] } {15 15 16 32 xy12345678abcdef} test stringObj-6.1 {Tcl_AppendStringsToObj procedure, type conversion} { testobj freeallvars teststringobj set2 1 [list a b] teststringobj appendstrings 1 xyz { 1234 } foo teststringobj get 1 } {a bxyz 1234 foo} test stringObj-6.2 {Tcl_AppendStringsToObj procedure, counting space} { testobj freeallvars teststringobj set 1 abc teststringobj appendstrings 1 list [teststringobj length 1] [teststringobj get 1] } {3 abc} test stringObj-6.3 {Tcl_AppendStringsToObj procedure, counting space} { testobj freeallvars teststringobj set 1 abc teststringobj appendstrings 1 {} {} {} {} list [teststringobj length 1] [teststringobj get 1] } {3 abc} test stringObj-6.4 {Tcl_AppendStringsToObj procedure, counting space} { testobj freeallvars teststringobj set 1 abc teststringobj appendstrings 1 { 123 } abcdefg list [teststringobj length 1] [teststringobj get 1] } {15 {abc 123 abcdefg}} test stringObj-6.5 {Tcl_AppendStringsToObj procedure, don't double space if initial string empty} { testobj freeallvars testobj newobj 1 teststringobj appendstrings 1 123 abcdefg list [teststringobj length 1] [teststringobj length2 1] [teststringobj get 1] } {10 10 123abcdefg} test stringObj-6.6 {Tcl_AppendStringsToObj procedure, space reallocation} { testobj freeallvars teststringobj set 1 abc teststringobj setlength 1 10 teststringobj setlength 1 2 teststringobj appendstrings 1 34567890 list [teststringobj length 1] [teststringobj length2 1] \ [teststringobj get 1] } {10 10 ab34567890} test stringObj-6.7 {Tcl_AppendStringsToObj procedure, space reallocation} { testobj freeallvars teststringobj set 1 abc teststringobj setlength 1 10 teststringobj setlength 1 2 teststringobj appendstrings 1 34567890x list [teststringobj length 1] [teststringobj length2 1] \ [teststringobj get 1] } {11 22 ab34567890x} test stringObj-6.8 {Tcl_AppendStringsToObj procedure, object totally empty} { testobj freeallvars testobj newobj 1 teststringobj appendstrings 1 {} list [teststringobj length2 1] [teststringobj get 1] } {0 {}} test stringObj-6.9 {Tcl_AppendStringToObj, pure unicode} { testobj freeallvars teststringobj set2 1 [string replace abc 1 1 d] teststringobj appendstrings 1 foo bar soom teststringobj get 1 } adcfoobarsoom test stringObj-7.1 {SetStringFromAny procedure} { testobj freeallvars teststringobj set2 1 [list a b] teststringobj append 1 x -1 list [teststringobj length 1] [teststringobj length2 1] \ [teststringobj get 1] } {4 8 {a bx}} test stringObj-7.2 {SetStringFromAny procedure, null object} { testobj freeallvars testobj newobj 1 teststringobj appendstrings 1 {} list [teststringobj length 1] [teststringobj length2 1] \ [teststringobj get 1] } {0 0 {}} test stringObj-7.3 {SetStringFromAny called with non-string obj} { set x 2345 list [incr x] [testobj objtype $x] [string index $x end] \ [testobj objtype $x] } {2346 int 6 string} test stringObj-7.4 {SetStringFromAny called with string obj} { set x "abcdef" list [string length $x] [testobj objtype $x] \ [string length $x] [testobj objtype $x] } {6 string 6 string} test stringObj-8.1 {DupStringInternalRep procedure} { testobj freeallvars teststringobj set 1 {} teststringobj append 1 abcde -1 testobj duplicate 1 2 list [teststringobj length 1] [teststringobj length2 1] \ [teststringobj ualloc 1] [teststringobj get 1] \ [teststringobj length 2] [teststringobj length2 2] \ [teststringobj ualloc 2] [teststringobj get 2] } {5 10 0 abcde 5 5 0 abcde} test stringObj-8.2 {DupUnicodeInternalRep, mixed width chars} { set x abcяПЎghi string length $x set y $x list [testobj objtype $x] [testobj objtype $y] [append x "ЎПя"] \ [set y] [testobj objtype $x] [testobj objtype $y] } {string string abcяПЎghiЎПя abcяПЎghi string string} test stringObj-8.3 {DupUnicodeInternalRep, mixed width chars} { set x abcяПЎghi set y $x string length $x list [testobj objtype $x] [testobj objtype $y] [append x "ЎПя"] \ [set y] [testobj objtype $x] [testobj objtype $y] } {string string abcяПЎghiЎПя abcяПЎghi string string} test stringObj-8.4 {DupUnicodeInternalRep, all byte-size chars} { set x abcdefghi string length $x set y $x list [testobj objtype $x] [testobj objtype $y] [append x jkl] \ [set y] [testobj objtype $x] [testobj objtype $y] } {string string abcdefghijkl abcdefghi string string} test stringObj-8.5 {DupUnicodeInternalRep, all byte-size chars} { set x abcdefghi set y $x string length $x list [testobj objtype $x] [testobj objtype $y] [append x jkl] \ [set y] [testobj objtype $x] [testobj objtype $y] } {string string abcdefghijkl abcdefghi string string} test stringObj-9.1 {TclAppendObjToObj, mixed src & dest} { set x abcяПЎghi set y ЎПя string length $x list [testobj objtype $x] [testobj objtype $y] [append x $y] \ [set y] [testobj objtype $x] [testobj objtype $y] } {string none abcяПЎghiЎПя ЎПя string none} test stringObj-9.2 {TclAppendObjToObj, mixed src & dest} { set x abcяПЎghi string length $x list [testobj objtype $x] [append x $x] [testobj objtype $x] \ [append x $x] [testobj objtype $x] } {string abcяПЎghiabcяПЎghi string\ abcяПЎghiabcяПЎghiabcяПЎghiabcяПЎghi\ string} test stringObj-9.3 {TclAppendObjToObj, mixed src & 1-byte dest} { set x abcdefghi set y ЎПя string length $x list [testobj objtype $x] [testobj objtype $y] [append x $y] \ [set y] [testobj objtype $x] [testobj objtype $y] } {string none abcdefghiЎПя ЎПя string none} test stringObj-9.4 {TclAppendObjToObj, 1-byte src & dest} { set x abcdefghi set y jkl string length $x list [testobj objtype $x] [testobj objtype $y] [append x $y] \ [set y] [testobj objtype $x] [testobj objtype $y] } {string none abcdefghijkl jkl string none} test stringObj-9.5 {TclAppendObjToObj, 1-byte src & dest} { set x abcdefghi string length $x list [testobj objtype $x] [append x $x] [testobj objtype $x] \ [append x $x] [testobj objtype $x] } {string abcdefghiabcdefghi string abcdefghiabcdefghiabcdefghiabcdefghi\ string} test stringObj-9.6 {TclAppendObjToObj, 1-byte src & mixed dest} { set x abcяПЎghi set y jkl string length $x list [testobj objtype $x] [testobj objtype $y] [append x $y] \ [set y] [testobj objtype $x] [testobj objtype $y] } {string none abcяПЎghijkl jkl string none} test stringObj-9.7 {TclAppendObjToObj, integer src & dest} { set x [expr {4 * 5}] set y [expr {4 + 5}] list [testobj objtype $x] [testobj objtype $y] [append x $y] \ [testobj objtype $x] [append x $y] [testobj objtype $x] \ [testobj objtype $y] } {int int 209 string 2099 string int} test stringObj-9.8 {TclAppendObjToObj, integer src & dest} { set x [expr {4 * 5}] list [testobj objtype $x] [append x $x] [testobj objtype $x] \ [append x $x] [testobj objtype $x] } {int 2020 string 20202020 string} test stringObj-9.9 {TclAppendObjToObj, integer src & 1-byte dest} { set x abcdefghi set y [expr {4 + 5}] string length $x list [testobj objtype $x] [testobj objtype $y] [append x $y] \ [set y] [testobj objtype $x] [testobj objtype $y] } {string int abcdefghi9 9 string int} test stringObj-9.10 {TclAppendObjToObj, integer src & mixed dest} { set x abcяПЎghi set y [expr {4 + 5}] string length $x list [testobj objtype $x] [testobj objtype $y] [append x $y] \ [set y] [testobj objtype $x] [testobj objtype $y] } {string int abcяПЎghi9 9 string int} test stringObj-9.11 {TclAppendObjToObj, mixed src & 1-byte dest index check} { # bug 2678, in <=8.2.0, the second obj (the one to append) in # Tcl_AppendObjToObj was not correctly checked to see if it was # all one byte chars, so a unicode string would be added as one # byte chars. set x abcdef set len [string length $x] set y aќbхcя set len [string length $y] append x $y string length $x set q {} for {set i 0} {$i < 12} {incr i} { lappend q [string index $x $i] } set q } {a b c d e f a ќ b х c я} test stringObj-10.1 {Tcl_GetRange with all byte-size chars} { set x "abcdef" list [testobj objtype $x] [set y [string range $x 1 end-1]] \ [testobj objtype $x] [testobj objtype $y] } [list none bcde string string] test stringObj-10.2 {Tcl_GetRange with some mixed width chars} { # Because this test does not use \uXXXX notation below instead of # hardcoding the values, it may fail in multibyte locales. However, # we need to test that the parser produces untyped objects even when there # are high-ASCII characters in the input (like "я"). I don't know what # else to do but inline those characters here. set x "abcяяdef" list [testobj objtype $x] [set y [string range $x 1 end-1]] \ [testobj objtype $x] [testobj objtype $y] } [list none "bc\u00EF\u00EFde" string string] test stringObj-10.3 {Tcl_GetRange with some mixed width chars} { # set x "abcяяdef" # Use \uXXXX notation below instead of hardcoding the values, otherwise # the test will fail in multibyte locales. set x "abc\u00EF\u00EFdef" string length $x list [testobj objtype $x] [set y [string range $x 1 end-1]] \ [testobj objtype $x] [testobj objtype $y] } [list string "bc\u00EF\u00EFde" string string] test stringObj-10.4 {Tcl_GetRange with some mixed width chars} { # set a "яaПbЎcяПdЎ" # Use \uXXXX notation below instead of hardcoding the values, otherwise # the test will fail in multibyte locales. set a "\u00EFa\u00BFb\u00AEc\u00EF\u00BFd\u00AE" set result [list] while {[string length $a] > 0} { set a [string range $a 1 end-1] lappend result $a } set result } [list a\u00BFb\u00AEc\u00EF\u00BFd \ \u00BFb\u00AEc\u00EF\u00BF \ b\u00AEc\u00EF \ \u00AEc \ {}] test stringObj-11.1 {UpdateStringOfString} { set x 2345 list [string index $x end] [testobj objtype $x] [incr x] \ [testobj objtype $x] } {5 string 2346 int} test stringObj-12.1 {Tcl_GetUniChar with byte-size chars} { set x "abcdefghi" list [string index $x 0] [string index $x 1] } {a b} test stringObj-12.2 {Tcl_GetUniChar with byte-size chars} { set x "abcdefghi" list [string index $x 3] [string index $x end] } {d i} test stringObj-12.3 {Tcl_GetUniChar with byte-size chars} { set x "abcdefghi" list [string index $x end] [string index $x end-1] } {i h} test stringObj-12.4 {Tcl_GetUniChar with mixed width chars} { string index "яaПbЎcЎПdя" 0 } "я" test stringObj-12.5 {Tcl_GetUniChar} { set x "яaПbЎcЎПdя" list [string index $x 4] [string index $x 0] } {Ў я} test stringObj-12.6 {Tcl_GetUniChar} { string index "яaПbЎcяПdЎ" end } "Ў" test stringObj-13.1 {Tcl_GetCharLength with byte-size chars} { set a "" list [string length $a] [string length $a] } {0 0} test stringObj-13.2 {Tcl_GetCharLength with byte-size chars} { string length "a" } 1 test stringObj-13.3 {Tcl_GetCharLength with byte-size chars} { set a "abcdef" list [string length $a] [string length $a] } {6 6} test stringObj-13.4 {Tcl_GetCharLength with mixed width chars} { string length "Ў" } 1 test stringObj-13.5 {Tcl_GetCharLength with mixed width chars} { # string length "яПЎяПЎ" # Use \uXXXX notation below instead of hardcoding the values, otherwise # the test will fail in multibyte locales. string length "\u00EF\u00BF\u00AE\u00EF\u00BF\u00AE" } 6 test stringObj-13.6 {Tcl_GetCharLength with mixed width chars} { # set a "яaПbЎcяПdЎ" # Use \uXXXX notation below instead of hardcoding the values, otherwise # the test will fail in multibyte locales. set a "\u00EFa\u00BFb\u00AEc\u00EF\u00BFd\u00AE" list [string length $a] [string length $a] } {10 10} test stringObj-13.7 {Tcl_GetCharLength with identity nulls} { # SF bug #684699 string length [encoding convertfrom identity \x00] } 1 test stringObj-13.8 {Tcl_GetCharLength with identity nulls} { string length [encoding convertfrom identity \x01\x00\x02] } 3 test stringObj-14.1 {Tcl_SetObjLength on pure unicode object} { teststringobj set 1 foo teststringobj getunicode 1 teststringobj append 1 bar -1 teststringobj getunicode 1 teststringobj append 1 bar -1 teststringobj setlength 1 0 teststringobj append 1 bar -1 teststringobj get 1 } {bar} test stringObj-15.1 {Tcl_Append*ToObj: self appends} { teststringobj set 1 foo teststringobj appendself 1 0 } foofoo test stringObj-15.2 {Tcl_Append*ToObj: self appends} { teststringobj set 1 foo teststringobj appendself 1 1 } foooo test stringObj-15.3 {Tcl_Append*ToObj: self appends} { teststringobj set 1 foo teststringobj appendself 1 2 } fooo test stringObj-15.4 {Tcl_Append*ToObj: self appends} { teststringobj set 1 foo teststringobj appendself 1 3 } foo test stringObj-15.5 {Tcl_Append*ToObj: self appends} { teststringobj set 1 foo teststringobj appendself2 1 0 } foofoo test stringObj-15.6 {Tcl_Append*ToObj: self appends} { teststringobj set 1 foo teststringobj appendself2 1 1 } foooo test stringObj-15.7 {Tcl_Append*ToObj: self appends} { teststringobj set 1 foo teststringobj appendself2 1 2 } fooo test stringObj-15.8 {Tcl_Append*ToObj: self appends} { teststringobj set 1 foo teststringobj appendself2 1 3 } foo testobj freeallvars # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/httpd0000644003604700454610000001215512153150337013121 0ustar dgp771div# # The httpd_ procedures implement a stub http server. # # Copyright (c) 1997-1998 Sun Microsystems, Inc. # Copyright (c) 1999-2000 Scriptics Corporation # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. #set httpLog 1 proc httpd_init {{port 8015}} { socket -server httpdAccept $port } proc httpd_log {args} { global httpLog if {[info exists httpLog] && $httpLog} { puts stderr "httpd: [join $args { }]" } } array set httpdErrors { 204 {No Content} 400 {Bad Request} 401 {Authorization Required} 404 {Not Found} 503 {Service Unavailable} 504 {Service Temporarily Unavailable} } proc httpdError {sock code args} { global httpdErrors puts $sock "$code $httpdErrors($code)" httpd_log "error: [join $args { }]" } proc httpdAccept {newsock ipaddr port} { global httpd upvar #0 httpd$newsock data fconfigure $newsock -blocking 0 -translation {auto crlf} httpd_log $newsock Connect $ipaddr $port set data(ipaddr) $ipaddr after 50 [list fileevent $newsock readable [list httpdRead $newsock]] } # read data from a client request proc httpdRead { sock } { upvar #0 httpd$sock data if {[eof $sock]} { set readCount -1 } elseif {![info exists data(state)]} { # Read the protocol line and parse out the URL and query set readCount [gets $sock line] if [regexp {(POST|GET|HEAD) ([^?]+)\??([^ ]*) HTTP/(1.[01])} \ $line x data(proto) data(url) data(query) data(httpversion)] { set data(state) mime httpd_log $sock Query $line } else { httpdError $sock 400 httpd_log $sock Error "bad first line:$line" httpdSockDone $sock } return } elseif {$data(state) == "mime"} { # Read the HTTP headers set readCount [gets $sock line] } elseif {$data(state) == "query"} { # Read the query data if {![info exists data(length_orig)]} { set data(length_orig) $data(length) } set line [read $sock $data(length)] set readCount [string length $line] incr data(length) -$readCount } # string compare $readCount 0 maps -1 to -1, 0 to 0, and > 0 to 1 set state [string compare $readCount 0],$data(state),$data(proto) httpd_log $sock $state switch -- $state { -1,mime,HEAD - -1,mime,GET - -1,mime,POST { # gets would block return } 0,mime,HEAD - 0,mime,GET - 0,query,POST { # Empty line at end of headers, # or eof after query data httpdRespond $sock } 0,mime,POST { # Empty line between headers and query data if {![info exists data(mime,content-length)]} { httpd_log $sock Error "No Content-Length for POST" httpdError $sock 400 httpdSockDone $sock } else { set data(state) query set data(length) $data(mime,content-length) # Special case to simulate servers that respond # without reading the post data. if {[string match *droppost* $data(url)]} { fileevent $sock readable {} httpdRespond $sock } } } 1,mime,HEAD - 1,mime,POST - 1,mime,GET { # A line of HTTP headers if {[regexp {([^:]+):[ ]*(.*)} $line dummy key value]} { set data(mime,[string tolower $key]) $value } } -1,query,POST { httpd_log $sock Error "unexpected eof on <$data(url)> request" httpdError $sock 400 httpdSockDone $sock } 1,query,POST { append data(query) $line if {$data(length) <= 0} { set data(length) $data(length_orig) httpdRespond $sock } } default { if {[eof $sock]} { httpd_log $sock Error "unexpected eof on <$data(url)> request" } else { httpd_log $sock Error "unhandled state <$state> fetching <$data(url)>" } httpdError $sock 404 httpdSockDone $sock } } } proc httpdSockDone { sock } { upvar #0 httpd$sock data unset data catch {close $sock} } # Respond to the query. proc httpdRespond { sock } { global httpd bindata port upvar #0 httpd$sock data switch -glob -- $data(url) { *binary* { set html "$bindata[info hostname]:$port$data(url)" set type application/octet-stream } *post* { set html "Got [string length $data(query)] bytes" set type text/plain } default { set type text/html set html "HTTP/1.0 TEST

Hello, World!

$data(proto) $data(url)

" if {[info exists data(query)] && [string length $data(query)]} { append html "

Query

\n
\n" foreach {key value} [split $data(query) &=] { append html "
$key
$value\n" if {$key == "timeout"} { after $value ;# pause } } append html
\n } append html } } # Catch errors from premature client closes catch { if {$data(proto) == "HEAD"} { puts $sock "HTTP/1.0 200 OK" } else { puts $sock "HTTP/1.0 200 Data follows" } puts $sock "Date: [clock format [clock clicks]]" puts $sock "Content-Type: $type" puts $sock "Content-Length: [string length $html]" puts $sock "" flush $sock if {$data(proto) != "HEAD"} { fconfigure $sock -translation binary puts -nonewline $sock $html } } httpd_log $sock Done "" httpdSockDone $sock } tcl8.4.20/tests/parseOld.test0000644003604700454610000003743711737050674014551 0ustar dgp771div# Commands covered: set (plus basic command syntax). Also tests the # procedures in the file tclOldParse.c. This set of tests is an old # one that predates the new parser in Tcl 8.1. # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994-1996 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } tcltest::testConstraint testwordend \ [string equal "testwordend" [info commands testwordend]] # Save the argv value for restoration later set savedArgv $argv proc fourArgs {a b c d} { global arg1 arg2 arg3 arg4 set arg1 $a set arg2 $b set arg3 $c set arg4 $d } proc getArgs args { global argv set argv $args } # Basic argument parsing. test parseOld-1.1 {basic argument parsing} { set arg1 {} fourArgs a b c d list $arg1 $arg2 $arg3 $arg4 } {a b c d} test parseOld-1.2 {basic argument parsing} { set arg1 {} eval "fourArgs 123\v4\f56\r7890" list $arg1 $arg2 $arg3 $arg4 } {123 4 56 7890} # Quotes. test parseOld-2.1 {quotes and variable-substitution} { getArgs "a b c" d set argv } {{a b c} d} test parseOld-2.2 {quotes and variable-substitution} { set a 101 getArgs "a$a b c" set argv } {{a101 b c}} test parseOld-2.3 {quotes and variable-substitution} { set argv "xy[format xabc]" set argv } {xyxabc} test parseOld-2.4 {quotes and variable-substitution} { set argv "xy\t" set argv } xy\t test parseOld-2.5 {quotes and variable-substitution} { set argv "a b c d e f" set argv } a\ b\tc\nd\ e\ f test parseOld-2.6 {quotes and variable-substitution} { set argv a"bcd"e set argv } {a"bcd"e} # Braces. test parseOld-3.1 {braces} { getArgs {a b c} d set argv } "{a b c} d" test parseOld-3.2 {braces} { set a 101 set argv {a$a b c} set b [string index $argv 1] set b } {$} test parseOld-3.3 {braces} { set argv {a[format xyz] b} string length $argv } 15 test parseOld-3.4 {braces} { set argv {a\nb\}} string length $argv } 6 test parseOld-3.5 {braces} { set argv {{{{}}}} set argv } "{{{}}}" test parseOld-3.6 {braces} { set argv a{{}}b set argv } "a{{}}b" test parseOld-3.7 {braces} { set a [format "last]"] set a } {last]} # Command substitution. test parseOld-4.1 {command substitution} { set a [format xyz] set a } xyz test parseOld-4.2 {command substitution} { set a a[format xyz]b[format q] set a } axyzbq test parseOld-4.3 {command substitution} { set a a[ set b 22; format %s $b ]b set a } a22b test parseOld-4.4 {command substitution} { set a 7.7 if [catch {expr int($a)}] {set a foo} set a } 7.7 # Variable substitution. test parseOld-5.1 {variable substitution} { set a 123 set b $a set b } 123 test parseOld-5.2 {variable substitution} { set a 345 set b x$a.b set b } x345.b test parseOld-5.3 {variable substitution} { set _123z xx set b $_123z^ set b } xx^ test parseOld-5.4 {variable substitution} { set a 78 set b a${a}b set b } a78b test parseOld-5.5 {variable substitution} {catch {$_non_existent_} msg} 1 test parseOld-5.6 {variable substitution} { catch {$_non_existent_} msg set msg } {can't read "_non_existent_": no such variable} test parseOld-5.7 {array variable substitution} { catch {unset a} set a(xyz) 123 set b $a(xyz)foo set b } 123foo test parseOld-5.8 {array variable substitution} { catch {unset a} set "a(x y z)" 123 set b $a(x y z)foo set b } 123foo test parseOld-5.9 {array variable substitution} { catch {unset a}; catch {unset qqq} set "a(x y z)" qqq set $a([format x]\ y [format z]) foo set qqq } foo test parseOld-5.10 {array variable substitution} { catch {unset a} list [catch {set b $a(22)} msg] $msg } {1 {can't read "a(22)": no such variable}} test parseOld-5.11 {array variable substitution} { set b a$! set b } {a$!} test parseOld-5.12 {empty array name support} { list [catch {set b a$()} msg] $msg } {1 {can't read "()": no such variable}} catch {unset a} test parseOld-5.13 {array variable substitution} { catch {unset a} set long {This is a very long variable, long enough to cause storage \ allocation to occur in Tcl_ParseVar. If that storage isn't getting \ freed up correctly, then a core leak will occur when this test is \ run. This text is probably beginning to sound like drivel, but I've \ run out of things to say and I need more characters still.} set a($long) 777 set b $a($long) list $b [array names a] } {777 {{This is a very long variable, long enough to cause storage \ allocation to occur in Tcl_ParseVar. If that storage isn't getting \ freed up correctly, then a core leak will occur when this test is \ run. This text is probably beginning to sound like drivel, but I've \ run out of things to say and I need more characters still.}}} test parseOld-5.14 {array variable substitution} { catch {unset a}; catch {unset b}; catch {unset a1} set a1(22) foo set a(foo) bar set b $a($a1(22)) set b } bar catch {unset a}; catch {unset a1} test parseOld-7.1 {backslash substitution} { set a "\a\c\n\]\}" string length $a } 5 test parseOld-7.2 {backslash substitution} { set a {\a\c\n\]\}} string length $a } 10 test parseOld-7.3 {backslash substitution} { set a "abc\ def" set a } {abc def} test parseOld-7.4 {backslash substitution} { set a {abc\ def} set a } {abc def} test parseOld-7.5 {backslash substitution} { set msg {} set a xxx set error [catch {if {24 < \ 35} {set a 22} {set \ a 33}} msg] list $error $msg $a } {0 22 22} test parseOld-7.6 {backslash substitution} { eval "concat abc\\" } "abc\\" test parseOld-7.7 {backslash substitution} { eval "concat \\\na" } "a" test parseOld-7.8 {backslash substitution} { eval "concat x\\\n a" } "x a" test parseOld-7.9 {backslash substitution} { eval "concat \\x" } "x" test parseOld-7.10 {backslash substitution} { eval "list a b\\\nc d" } {a b c d} test parseOld-7.11 {backslash substitution} { eval "list a \"b c\"\\\nd e" } {a {b c} d e} test parseOld-7.12 {backslash substitution} { list \ua2 } [bytestring "\xc2\xa2"] test parseOld-7.13 {backslash substitution} { list \u4e21 } [bytestring "\xe4\xb8\xa1"] test parseOld-7.14 {backslash substitution} { list \u4e2k } [bytestring "\xd3\xa2k"] # Semi-colon. test parseOld-8.1 {semi-colons} { set b 0 getArgs a;set b 2 set argv } a test parseOld-8.2 {semi-colons} { set b 0 getArgs a;set b 2 set b } 2 test parseOld-8.3 {semi-colons} { getArgs a b ; set b 1 set argv } {a b} test parseOld-8.4 {semi-colons} { getArgs a b ; set b 1 set b } 1 # The following checks are to ensure that the interpreter's result # gets re-initialized by Tcl_Eval in all the right places. test parseOld-9.1 {result initialization} {concat abc} abc test parseOld-9.2 {result initialization} {concat abc; proc foo {} {}} {} test parseOld-9.3 {result initialization} {concat abc; proc foo {} $a} {} test parseOld-9.4 {result initialization} {proc foo {} [concat abc]} {} test parseOld-9.5 {result initialization} {concat abc; } abc test parseOld-9.6 {result initialization} { eval { concat abc }} abc test parseOld-9.7 {result initialization} {} {} test parseOld-9.8 {result initialization} {concat abc; ; ;} abc # Syntax errors. test parseOld-10.1 {syntax errors} {catch "set a \{bcd" msg} 1 test parseOld-10.2 {syntax errors} { catch "set a \{bcd" msg set msg } {missing close-brace} test parseOld-10.3 {syntax errors} {catch {set a "bcd} msg} 1 test parseOld-10.4 {syntax errors} { catch {set a "bcd} msg set msg } {missing "} #" Emacs formatting >:^( test parseOld-10.5 {syntax errors} {catch {set a "bcd"xy} msg} 1 test parseOld-10.6 {syntax errors} { catch {set a "bcd"xy} msg set msg } {extra characters after close-quote} test parseOld-10.7 {syntax errors} {catch "set a {bcd}xy" msg} 1 test parseOld-10.8 {syntax errors} { catch "set a {bcd}xy" msg set msg } {extra characters after close-brace} test parseOld-10.9 {syntax errors} {catch {set a [format abc} msg} 1 test parseOld-10.10 {syntax errors} { catch {set a [format abc} msg set msg } {missing close-bracket} test parseOld-10.11 {syntax errors} {catch gorp-a-lot msg} 1 test parseOld-10.12 {syntax errors} { catch gorp-a-lot msg set msg } {invalid command name "gorp-a-lot"} test parseOld-10.13 {syntax errors} { set a [concat {a}\ {b}] set a } {a b} # The next test will fail on the Mac, 'cause the MSL uses a fixed sized # buffer for %d conversions (LAME!). I won't leave the test out, however, # since MetroWerks may some day fix this. test parseOld-10.14 {syntax errors} { list [catch {eval \$x[format "%01000d" 0](} msg] $msg $errorInfo } {1 {missing )} {missing ) while executing "$x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000..." ("eval" body line 1) invoked from within "eval \$x[format "%01000d" 0]("}} test parseOld-10.15 {syntax errors, missplaced braces} { catch { proc misplaced_end_brace {} { set what foo set when [expr ${what}size - [set off$what]}] } msg set msg } {extra characters after close-brace} test parseOld-10.16 {syntax errors, missplaced braces} { catch { set a { set what foo set when [expr ${what}size - [set off$what]}] } msg set msg } {extra characters after close-brace} test parseOld-10.17 {syntax errors, unusual spacing} { list [catch {return [ [1]]} msg] $msg } {1 {invalid command name "1"}} # Long values (stressing storage management) set a {1111 2222 3333 4444 5555 6666 7777 8888 9999 aaaa bbbb cccc dddd eeee ffff gggg hhhh iiii jjjj kkkk llll mmmm nnnn oooo pppp qqqq rrrr ssss tttt uuuu vvvv wwww xxxx yyyy zzzz AAAA BBBB CCCC DDDD EEEE FFFF GGGG HHHH} test parseOld-11.1 {long values} { string length $a } 214 test parseOld-11.2 {long values} { llength $a } 43 test parseOld-11.3 {long values} { set b "1111 2222 3333 4444 5555 6666 7777 8888 9999 aaaa bbbb cccc dddd eeee ffff gggg hhhh iiii jjjj kkkk llll mmmm nnnn oooo pppp qqqq rrrr ssss tttt uuuu vvvv wwww xxxx yyyy zzzz AAAA BBBB CCCC DDDD EEEE FFFF GGGG HHHH" set b } $a test parseOld-11.4 {long values} { set b "$a" set b } $a test parseOld-11.5 {long values} { set b [set a] set b } $a test parseOld-11.6 {long values} { set b [concat 1111 2222 3333 4444 5555 6666 7777 8888 9999 aaaa bbbb cccc dddd eeee ffff gggg hhhh iiii jjjj kkkk llll mmmm nnnn oooo pppp qqqq rrrr ssss tttt uuuu vvvv wwww xxxx yyyy zzzz AAAA BBBB CCCC DDDD EEEE FFFF GGGG HHHH] string length $b } 214 test parseOld-11.7 {long values} { set b [concat 1111 2222 3333 4444 5555 6666 7777 8888 9999 aaaa bbbb cccc dddd eeee ffff gggg hhhh iiii jjjj kkkk llll mmmm nnnn oooo pppp qqqq rrrr ssss tttt uuuu vvvv wwww xxxx yyyy zzzz AAAA BBBB CCCC DDDD EEEE FFFF GGGG HHHH] llength $b } 43 test parseOld-11.8 {long values} { set b } $a test parseOld-11.9 {long values} { set a [concat 0000 1111 2222 3333 4444 5555 6666 7777 8888 9999 aaaa bbbb cccc dddd eeee ffff gggg hhhh iiii jjjj kkkk llll mmmm nnnn oooo pppp qqqq rrrr ssss tttt uuuu vvvv wwww xxxx yyyy zzzz AAAA BBBB CCCC DDDD EEEE FFFF GGGG HHHH IIII JJJJ KKKK LLLL MMMM NNNN OOOO PPPP QQQQ RRRR SSSS TTTT UUUU VVVV WWWW XXXX YYYY ZZZZ] llength $a } 62 set i 0 foreach j [concat 0000 1111 2222 3333 4444 5555 6666 7777 8888 9999 aaaa bbbb cccc dddd eeee ffff gggg hhhh iiii jjjj kkkk llll mmmm nnnn oooo pppp qqqq rrrr ssss tttt uuuu vvvv wwww xxxx yyyy zzzz AAAA BBBB CCCC DDDD EEEE FFFF GGGG HHHH IIII JJJJ KKKK LLLL MMMM NNNN OOOO PPPP QQQQ RRRR SSSS TTTT UUUU VVVV WWWW XXXX YYYY ZZZZ] { set test [string index 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ $i] set test $test$test$test$test test parseOld-11.10-[incr i] {long values} { set j } $test } test parseOld-11.11 {test buffer overflow in backslashes in braces} { expr {"a" == {xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy\101\101\101\101\101\101\101\101\101\101\101\101\101\101\101\101\101\101\101\101\101\101\101\101\101\101}} } 0 test parseOld-12.1 {comments} { set a old eval { # set a new} set a } {old} test parseOld-12.2 {comments} { set a old eval " # set a new\nset a new" set a } {new} test parseOld-12.3 {comments} { set a old eval " # set a new\\\nset a new" set a } {old} test parseOld-12.4 {comments} { set a old eval " # set a new\\\\\nset a new" set a } {new} test parseOld-13.1 {comments at the end of a bracketed script} { set x "[ expr 1+1 # skip this! ]" } {2} test parseOld-14.1 {TclWordEnd procedure} {testwordend} { testwordend " \n abc" } {c} test parseOld-14.2 {TclWordEnd procedure} {testwordend} { testwordend " \\\n" } {} test parseOld-14.3 {TclWordEnd procedure} {testwordend} { testwordend " \\\n " } { } test parseOld-14.4 {TclWordEnd procedure} {testwordend} { testwordend {"abc"} } {"} #" Emacs formatting >:^( test parseOld-14.5 {TclWordEnd procedure} {testwordend} { testwordend {{xyz}} } \} test parseOld-14.6 {TclWordEnd procedure} {testwordend} { testwordend {{a{}b{}\}} xyz} } "\} xyz" test parseOld-14.7 {TclWordEnd procedure} {testwordend} { testwordend {abc[this is a]def ghi} } {f ghi} test parseOld-14.8 {TclWordEnd procedure} {testwordend} { testwordend "puts\\\n\n " } "s\\\n\n " test parseOld-14.9 {TclWordEnd procedure} {testwordend} { testwordend "puts\\\n " } "s\\\n " test parseOld-14.10 {TclWordEnd procedure} {testwordend} { testwordend "puts\\\n xyz" } "s\\\n xyz" test parseOld-14.11 {TclWordEnd procedure} {testwordend} { testwordend {a$x.$y(a long index) foo} } ") foo" test parseOld-14.12 {TclWordEnd procedure} {testwordend} { testwordend {abc; def} } {; def} test parseOld-14.13 {TclWordEnd procedure} {testwordend} { testwordend {abc def} } {c def} test parseOld-14.14 {TclWordEnd procedure} {testwordend} { testwordend {abc def} } {c def} test parseOld-14.15 {TclWordEnd procedure} {testwordend} { testwordend "abc\ndef" } "c\ndef" test parseOld-14.16 {TclWordEnd procedure} {testwordend} { testwordend "abc" } {c} test parseOld-14.17 {TclWordEnd procedure} {testwordend} { testwordend "a\000bc" } {c} test parseOld-14.18 {TclWordEnd procedure} {testwordend} { testwordend \[a\000\] } {]} test parseOld-14.19 {TclWordEnd procedure} {testwordend} { testwordend \"a\000\" } {"} #" Emacs formatting >:^( test parseOld-14.20 {TclWordEnd procedure} {testwordend} { testwordend a{\000}b } {b} test parseOld-14.21 {TclWordEnd procedure} {testwordend} { testwordend " \000b" } {b} test parseOld-15.1 {TclScriptEnd procedure} { info complete {puts [ expr 1+1 #this is a comment ]} } {0} test parseOld-15.2 {TclScriptEnd procedure} { info complete "abc\\\n" } {0} test parseOld-15.3 {TclScriptEnd procedure} { info complete "abc\\\\\n" } {1} test parseOld-15.4 {TclScriptEnd procedure} { info complete "xyz \[abc \{abc\]" } {0} test parseOld-15.5 {TclScriptEnd procedure} { info complete "xyz \[abc" } {0} # cleanup set argv $savedArgv ::tcltest::cleanupTests return tcl8.4.20/tests/all.tcl0000644003604700454610000000105512052456744013335 0ustar dgp771div# all.tcl -- # # This file contains a top-level script to run all of the Tcl # tests. Execute it by invoking "source all.test" when running tcltest # in this directory. # # Copyright (c) 1998-1999 by Scriptics Corporation. # Copyright (c) 2000 by Ajuba Solutions # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. set tcltestVersion [package require tcltest] namespace import -force tcltest::* tcltest::testsDirectory [file dir [info script]] tcltest::runAllTests return tcl8.4.20/tests/binary.test0000644003604700454610000015001212052456744014244 0ustar dgp771div# This file tests the tclBinary.c file and the "binary" Tcl command. # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1997 by Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } test binary-0.1 {DupByteArrayInternalRep} { set hdr [binary format cc 0 0316] set buf hellomatt set data $hdr append data $buf string length $data } 11 test binary-1.1 {Tcl_BinaryObjCmd: bad args} { list [catch {binary} msg] $msg } {1 {wrong # args: should be "binary option ?arg arg ...?"}} test binary-1.2 {Tcl_BinaryObjCmd: bad args} { list [catch {binary foo} msg] $msg } {1 {bad option "foo": must be format or scan}} test binary-1.3 {Tcl_BinaryObjCmd: format error} { list [catch {binary f} msg] $msg } {1 {wrong # args: should be "binary format formatString ?arg arg ...?"}} test binary-1.4 {Tcl_BinaryObjCmd: format} { binary format "" } {} test binary-2.1 {Tcl_BinaryObjCmd: format} { list [catch {binary format a } msg] $msg } {1 {not enough arguments for all format specifiers}} test binary-2.2 {Tcl_BinaryObjCmd: format} { binary format a0 foo } {} test binary-2.3 {Tcl_BinaryObjCmd: format} { binary format a f } {f} test binary-2.4 {Tcl_BinaryObjCmd: format} { binary format a foo } {f} test binary-2.5 {Tcl_BinaryObjCmd: format} { binary format a3 foo } {foo} test binary-2.6 {Tcl_BinaryObjCmd: format} { binary format a5 foo } foo\x00\x00 test binary-2.7 {Tcl_BinaryObjCmd: format} { binary format a*a3 foobarbaz blat } foobarbazbla test binary-2.8 {Tcl_BinaryObjCmd: format} { binary format a*X3a2 foobar x } foox\x00r test binary-3.1 {Tcl_BinaryObjCmd: format} { list [catch {binary format A} msg] $msg } {1 {not enough arguments for all format specifiers}} test binary-3.2 {Tcl_BinaryObjCmd: format} { binary format A0 f } {} test binary-3.3 {Tcl_BinaryObjCmd: format} { binary format A f } {f} test binary-3.4 {Tcl_BinaryObjCmd: format} { binary format A foo } {f} test binary-3.5 {Tcl_BinaryObjCmd: format} { binary format A3 foo } {foo} test binary-3.6 {Tcl_BinaryObjCmd: format} { binary format A5 foo } {foo } test binary-3.7 {Tcl_BinaryObjCmd: format} { binary format A*A3 foobarbaz blat } foobarbazbla test binary-3.8 {Tcl_BinaryObjCmd: format} { binary format A*X3A2 foobar x } {foox r} test binary-4.1 {Tcl_BinaryObjCmd: format} { list [catch {binary format B} msg] $msg } {1 {not enough arguments for all format specifiers}} test binary-4.2 {Tcl_BinaryObjCmd: format} { binary format B0 1 } {} test binary-4.3 {Tcl_BinaryObjCmd: format} { binary format B 1 } \x80 test binary-4.4 {Tcl_BinaryObjCmd: format} { binary format B* 010011 } \x4c test binary-4.5 {Tcl_BinaryObjCmd: format} { binary format B8 01001101 } \x4d test binary-4.6 {Tcl_BinaryObjCmd: format} { binary format A2X2B9 oo 01001101 } \x4d\x00 test binary-4.7 {Tcl_BinaryObjCmd: format} { binary format B9 010011011010 } \x4d\x80 test binary-4.8 {Tcl_BinaryObjCmd: format} { binary format B2B3 10 010 } \x80\x40 test binary-4.9 {Tcl_BinaryObjCmd: format} { list [catch {binary format B1B5 1 foo} msg] $msg } {1 {expected binary string but got "foo" instead}} test binary-5.1 {Tcl_BinaryObjCmd: format} { list [catch {binary format b} msg] $msg } {1 {not enough arguments for all format specifiers}} test binary-5.2 {Tcl_BinaryObjCmd: format} { binary format b0 1 } {} test binary-5.3 {Tcl_BinaryObjCmd: format} { binary format b 1 } \x01 test binary-5.4 {Tcl_BinaryObjCmd: format} { binary format b* 010011 } 2 test binary-5.5 {Tcl_BinaryObjCmd: format} { binary format b8 01001101 } \xb2 test binary-5.6 {Tcl_BinaryObjCmd: format} { binary format A2X2b9 oo 01001101 } \xb2\x00 test binary-5.7 {Tcl_BinaryObjCmd: format} { binary format b9 010011011010 } \xb2\x01 test binary-5.8 {Tcl_BinaryObjCmd: format} { binary format b17 1 } \x01\00\00 test binary-5.9 {Tcl_BinaryObjCmd: format} { binary format b2b3 10 010 } \x01\x02 test binary-5.10 {Tcl_BinaryObjCmd: format} { list [catch {binary format b1b5 1 foo} msg] $msg } {1 {expected binary string but got "foo" instead}} test binary-6.1 {Tcl_BinaryObjCmd: format} { list [catch {binary format h} msg] $msg } {1 {not enough arguments for all format specifiers}} test binary-6.2 {Tcl_BinaryObjCmd: format} { binary format h0 1 } {} test binary-6.3 {Tcl_BinaryObjCmd: format} { binary format h 1 } \x01 test binary-6.4 {Tcl_BinaryObjCmd: format} { binary format h c } \x0c test binary-6.5 {Tcl_BinaryObjCmd: format} { binary format h* baadf00d } \xab\xda\x0f\xd0 test binary-6.6 {Tcl_BinaryObjCmd: format} { binary format h4 c410 } \x4c\x01 test binary-6.7 {Tcl_BinaryObjCmd: format} { binary format h6 c4102 } \x4c\x01\x02 test binary-6.8 {Tcl_BinaryObjCmd: format} { binary format h5 c41020304 } \x4c\x01\x02 test binary-6.9 {Tcl_BinaryObjCmd: format} { binary format a3X3h5 foo 2 } \x02\x00\x00 test binary-6.10 {Tcl_BinaryObjCmd: format} { binary format h2h3 23 456 } \x32\x54\x06 test binary-6.11 {Tcl_BinaryObjCmd: format} { list [catch {binary format h2 foo} msg] $msg } {1 {expected hexadecimal string but got "foo" instead}} test binary-7.1 {Tcl_BinaryObjCmd: format} { list [catch {binary format H} msg] $msg } {1 {not enough arguments for all format specifiers}} test binary-7.2 {Tcl_BinaryObjCmd: format} { binary format H0 1 } {} test binary-7.3 {Tcl_BinaryObjCmd: format} { binary format H 1 } \x10 test binary-7.4 {Tcl_BinaryObjCmd: format} { binary format H c } \xc0 test binary-7.5 {Tcl_BinaryObjCmd: format} { binary format H* baadf00d } \xba\xad\xf0\x0d test binary-7.6 {Tcl_BinaryObjCmd: format} { binary format H4 c410 } \xc4\x10 test binary-7.7 {Tcl_BinaryObjCmd: format} { binary format H6 c4102 } \xc4\x10\x20 test binary-7.8 {Tcl_BinaryObjCmd: format} { binary format H5 c41023304 } \xc4\x10\x20 test binary-7.9 {Tcl_BinaryObjCmd: format} { binary format a3X3H5 foo 2 } \x20\x00\x00 test binary-7.10 {Tcl_BinaryObjCmd: format} { binary format H2H3 23 456 } \x23\x45\x60 test binary-7.11 {Tcl_BinaryObjCmd: format} { list [catch {binary format H2 foo} msg] $msg } {1 {expected hexadecimal string but got "foo" instead}} test binary-8.1 {Tcl_BinaryObjCmd: format} { list [catch {binary format c} msg] $msg } {1 {not enough arguments for all format specifiers}} test binary-8.2 {Tcl_BinaryObjCmd: format} { list [catch {binary format c blat} msg] $msg } {1 {expected integer but got "blat"}} test binary-8.3 {Tcl_BinaryObjCmd: format} { binary format c0 0x50 } {} test binary-8.4 {Tcl_BinaryObjCmd: format} { binary format c 0x50 } P test binary-8.5 {Tcl_BinaryObjCmd: format} { binary format c 0x5052 } R test binary-8.6 {Tcl_BinaryObjCmd: format} { binary format c2 {0x50 0x52} } PR test binary-8.7 {Tcl_BinaryObjCmd: format} { binary format c2 {0x50 0x52 0x53} } PR test binary-8.8 {Tcl_BinaryObjCmd: format} { binary format c* {0x50 0x52} } PR test binary-8.9 {Tcl_BinaryObjCmd: format} { list [catch {binary format c2 {0x50}} msg] $msg } {1 {number of elements in list does not match count}} test binary-8.10 {Tcl_BinaryObjCmd: format} { set a {0x50 0x51} list [catch {binary format c $a} msg] $msg } [list 1 "expected integer but got \"0x50 0x51\""] test binary-8.11 {Tcl_BinaryObjCmd: format} { set a {0x50 0x51} binary format c1 $a } P test binary-9.1 {Tcl_BinaryObjCmd: format} { list [catch {binary format s} msg] $msg } {1 {not enough arguments for all format specifiers}} test binary-9.2 {Tcl_BinaryObjCmd: format} { list [catch {binary format s blat} msg] $msg } {1 {expected integer but got "blat"}} test binary-9.3 {Tcl_BinaryObjCmd: format} { binary format s0 0x50 } {} test binary-9.4 {Tcl_BinaryObjCmd: format} { binary format s 0x50 } P\x00 test binary-9.5 {Tcl_BinaryObjCmd: format} { binary format s 0x5052 } RP test binary-9.6 {Tcl_BinaryObjCmd: format} { binary format s 0x505251 0x53 } QR test binary-9.7 {Tcl_BinaryObjCmd: format} { binary format s2 {0x50 0x52} } P\x00R\x00 test binary-9.8 {Tcl_BinaryObjCmd: format} { binary format s* {0x5051 0x52} } QPR\x00 test binary-9.9 {Tcl_BinaryObjCmd: format} { binary format s2 {0x50 0x52 0x53} 0x54 } P\x00R\x00 test binary-9.10 {Tcl_BinaryObjCmd: format} { list [catch {binary format s2 {0x50}} msg] $msg } {1 {number of elements in list does not match count}} test binary-9.11 {Tcl_BinaryObjCmd: format} { set a {0x50 0x51} list [catch {binary format s $a} msg] $msg } [list 1 "expected integer but got \"0x50 0x51\""] test binary-9.12 {Tcl_BinaryObjCmd: format} { set a {0x50 0x51} binary format s1 $a } P\x00 test binary-10.1 {Tcl_BinaryObjCmd: format} { list [catch {binary format S} msg] $msg } {1 {not enough arguments for all format specifiers}} test binary-10.2 {Tcl_BinaryObjCmd: format} { list [catch {binary format S blat} msg] $msg } {1 {expected integer but got "blat"}} test binary-10.3 {Tcl_BinaryObjCmd: format} { binary format S0 0x50 } {} test binary-10.4 {Tcl_BinaryObjCmd: format} { binary format S 0x50 } \x00P test binary-10.5 {Tcl_BinaryObjCmd: format} { binary format S 0x5052 } PR test binary-10.6 {Tcl_BinaryObjCmd: format} { binary format S 0x505251 0x53 } RQ test binary-10.7 {Tcl_BinaryObjCmd: format} { binary format S2 {0x50 0x52} } \x00P\x00R test binary-10.8 {Tcl_BinaryObjCmd: format} { binary format S* {0x5051 0x52} } PQ\x00R test binary-10.9 {Tcl_BinaryObjCmd: format} { binary format S2 {0x50 0x52 0x53} 0x54 } \x00P\x00R test binary-10.10 {Tcl_BinaryObjCmd: format} { list [catch {binary format S2 {0x50}} msg] $msg } {1 {number of elements in list does not match count}} test binary-10.11 {Tcl_BinaryObjCmd: format} { set a {0x50 0x51} list [catch {binary format S $a} msg] $msg } [list 1 "expected integer but got \"0x50 0x51\""] test binary-10.12 {Tcl_BinaryObjCmd: format} { set a {0x50 0x51} binary format S1 $a } \x00P test binary-11.1 {Tcl_BinaryObjCmd: format} { list [catch {binary format i} msg] $msg } {1 {not enough arguments for all format specifiers}} test binary-11.2 {Tcl_BinaryObjCmd: format} { list [catch {binary format i blat} msg] $msg } {1 {expected integer but got "blat"}} test binary-11.3 {Tcl_BinaryObjCmd: format} { binary format i0 0x50 } {} test binary-11.4 {Tcl_BinaryObjCmd: format} { binary format i 0x50 } P\x00\x00\x00 test binary-11.5 {Tcl_BinaryObjCmd: format} { binary format i 0x5052 } RP\x00\x00 test binary-11.6 {Tcl_BinaryObjCmd: format} { binary format i 0x505251 0x53 } QRP\x00 test binary-11.7 {Tcl_BinaryObjCmd: format} { binary format i1 {0x505251 0x53} } QRP\x00 test binary-11.8 {Tcl_BinaryObjCmd: format} { binary format i 0x53525150 } PQRS test binary-11.9 {Tcl_BinaryObjCmd: format} { binary format i2 {0x50 0x52} } P\x00\x00\x00R\x00\x00\x00 test binary-11.10 {Tcl_BinaryObjCmd: format} { binary format i* {0x50515253 0x52} } SRQPR\x00\x00\x00 test binary-11.11 {Tcl_BinaryObjCmd: format} { list [catch {binary format i2 {0x50}} msg] $msg } {1 {number of elements in list does not match count}} test binary-11.12 {Tcl_BinaryObjCmd: format} { set a {0x50 0x51} list [catch {binary format i $a} msg] $msg } [list 1 "expected integer but got \"0x50 0x51\""] test binary-11.13 {Tcl_BinaryObjCmd: format} { set a {0x50 0x51} binary format i1 $a } P\x00\x00\x00 test binary-12.1 {Tcl_BinaryObjCmd: format} { list [catch {binary format I} msg] $msg } {1 {not enough arguments for all format specifiers}} test binary-12.2 {Tcl_BinaryObjCmd: format} { list [catch {binary format I blat} msg] $msg } {1 {expected integer but got "blat"}} test binary-12.3 {Tcl_BinaryObjCmd: format} { binary format I0 0x50 } {} test binary-12.4 {Tcl_BinaryObjCmd: format} { binary format I 0x50 } \x00\x00\x00P test binary-12.5 {Tcl_BinaryObjCmd: format} { binary format I 0x5052 } \x00\x00PR test binary-12.6 {Tcl_BinaryObjCmd: format} { binary format I 0x505251 0x53 } \x00PRQ test binary-12.7 {Tcl_BinaryObjCmd: format} { binary format I1 {0x505251 0x53} } \x00PRQ test binary-12.8 {Tcl_BinaryObjCmd: format} { binary format I 0x53525150 } SRQP test binary-12.9 {Tcl_BinaryObjCmd: format} { binary format I2 {0x50 0x52} } \x00\x00\x00P\x00\x00\x00R test binary-12.10 {Tcl_BinaryObjCmd: format} { binary format I* {0x50515253 0x52} } PQRS\x00\x00\x00R test binary-12.11 {Tcl_BinaryObjCmd: format} { list [catch {binary format i2 {0x50}} msg] $msg } {1 {number of elements in list does not match count}} test binary-12.12 {Tcl_BinaryObjCmd: format} { set a {0x50 0x51} list [catch {binary format I $a} msg] $msg } [list 1 "expected integer but got \"0x50 0x51\""] test binary-12.13 {Tcl_BinaryObjCmd: format} { set a {0x50 0x51} binary format I1 $a } \x00\x00\x00P test binary-13.1 {Tcl_BinaryObjCmd: format} { list [catch {binary format f} msg] $msg } {1 {not enough arguments for all format specifiers}} test binary-13.2 {Tcl_BinaryObjCmd: format} { list [catch {binary format f blat} msg] $msg } {1 {expected floating-point number but got "blat"}} test binary-13.3 {Tcl_BinaryObjCmd: format} { binary format f0 1.6 } {} test binary-13.4 {Tcl_BinaryObjCmd: format} {nonPortable macOrUnix} { binary format f 1.6 } \x3f\xcc\xcc\xcd test binary-13.5 {Tcl_BinaryObjCmd: format} {nonPortable pcOnly} { binary format f 1.6 } \xcd\xcc\xcc\x3f test binary-13.6 {Tcl_BinaryObjCmd: format} {nonPortable macOrUnix} { binary format f* {1.6 3.4} } \x3f\xcc\xcc\xcd\x40\x59\x99\x9a test binary-13.7 {Tcl_BinaryObjCmd: format} {nonPortable pcOnly} { binary format f* {1.6 3.4} } \xcd\xcc\xcc\x3f\x9a\x99\x59\x40 test binary-13.8 {Tcl_BinaryObjCmd: format} {nonPortable macOrUnix} { binary format f2 {1.6 3.4} } \x3f\xcc\xcc\xcd\x40\x59\x99\x9a test binary-13.9 {Tcl_BinaryObjCmd: format} {nonPortable pcOnly} { binary format f2 {1.6 3.4} } \xcd\xcc\xcc\x3f\x9a\x99\x59\x40 test binary-13.10 {Tcl_BinaryObjCmd: format} {nonPortable macOrUnix} { binary format f2 {1.6 3.4 5.6} } \x3f\xcc\xcc\xcd\x40\x59\x99\x9a test binary-13.11 {Tcl_BinaryObjCmd: format} {nonPortable pcOnly} { binary format f2 {1.6 3.4 5.6} } \xcd\xcc\xcc\x3f\x9a\x99\x59\x40 test binary-13.12 {Tcl_BinaryObjCmd: float overflow} {nonPortable macOrUnix} { binary format f -3.402825e+38 } \xff\x7f\xff\xff test binary-13.13 {Tcl_BinaryObjCmd: float overflow} {nonPortable pcOnly} { binary format f -3.402825e+38 } \xff\xff\x7f\xff test binary-13.14 {Tcl_BinaryObjCmd: float underflow} {nonPortable macOrUnix} { binary format f -3.402825e-100 } \x80\x00\x00\x00 test binary-13.15 {Tcl_BinaryObjCmd: float underflow} {nonPortable pcOnly} { binary format f -3.402825e-100 } \x00\x00\x00\x80 test binary-13.16 {Tcl_BinaryObjCmd: format} { list [catch {binary format f2 {1.6}} msg] $msg } {1 {number of elements in list does not match count}} test binary-13.17 {Tcl_BinaryObjCmd: format} { set a {1.6 3.4} list [catch {binary format f $a} msg] $msg } [list 1 "expected floating-point number but got \"1.6 3.4\""] test binary-13.18 {Tcl_BinaryObjCmd: format} {nonPortable macOrUnix} { set a {1.6 3.4} binary format f1 $a } \x3f\xcc\xcc\xcd test binary-13.19 {Tcl_BinaryObjCmd: format} {nonPortable pcOnly} { set a {1.6 3.4} binary format f1 $a } \xcd\xcc\xcc\x3f test binary-14.1 {Tcl_BinaryObjCmd: format} { list [catch {binary format d} msg] $msg } {1 {not enough arguments for all format specifiers}} test binary-14.2 {Tcl_BinaryObjCmd: format} { list [catch {binary format d blat} msg] $msg } {1 {expected floating-point number but got "blat"}} test binary-14.3 {Tcl_BinaryObjCmd: format} { binary format d0 1.6 } {} test binary-14.4 {Tcl_BinaryObjCmd: format} {nonPortable macOrUnix} { binary format d 1.6 } \x3f\xf9\x99\x99\x99\x99\x99\x9a test binary-14.5 {Tcl_BinaryObjCmd: format} {nonPortable pcOnly} { binary format d 1.6 } \x9a\x99\x99\x99\x99\x99\xf9\x3f test binary-14.6 {Tcl_BinaryObjCmd: format} {nonPortable macOrUnix} { binary format d* {1.6 3.4} } \x3f\xf9\x99\x99\x99\x99\x99\x9a\x40\x0b\x33\x33\x33\x33\x33\x33 test binary-14.7 {Tcl_BinaryObjCmd: format} {nonPortable pcOnly} { binary format d* {1.6 3.4} } \x9a\x99\x99\x99\x99\x99\xf9\x3f\x33\x33\x33\x33\x33\x33\x0b\x40 test binary-14.8 {Tcl_BinaryObjCmd: format} {nonPortable macOrUnix} { binary format d2 {1.6 3.4} } \x3f\xf9\x99\x99\x99\x99\x99\x9a\x40\x0b\x33\x33\x33\x33\x33\x33 test binary-14.9 {Tcl_BinaryObjCmd: format} {nonPortable pcOnly} { binary format d2 {1.6 3.4} } \x9a\x99\x99\x99\x99\x99\xf9\x3f\x33\x33\x33\x33\x33\x33\x0b\x40 test binary-14.10 {Tcl_BinaryObjCmd: format} {nonPortable macOrUnix} { binary format d2 {1.6 3.4 5.6} } \x3f\xf9\x99\x99\x99\x99\x99\x9a\x40\x0b\x33\x33\x33\x33\x33\x33 test binary-14.11 {Tcl_BinaryObjCmd: format} {nonPortable pcOnly} { binary format d2 {1.6 3.4 5.6} } \x9a\x99\x99\x99\x99\x99\xf9\x3f\x33\x33\x33\x33\x33\x33\x0b\x40 test binary-14.12 {Tcl_BinaryObjCmd: float overflow} {nonPortable unixOnly} { binary format d NaN } \x7f\xff\xff\xff\xff\xff\xff\xff test binary-14.14 {Tcl_BinaryObjCmd: format} { list [catch {binary format d2 {1.6}} msg] $msg } {1 {number of elements in list does not match count}} test binary-14.15 {Tcl_BinaryObjCmd: format} { set a {1.6 3.4} list [catch {binary format d $a} msg] $msg } [list 1 "expected floating-point number but got \"1.6 3.4\""] test binary-14.16 {Tcl_BinaryObjCmd: format} {nonPortable macOrUnix} { set a {1.6 3.4} binary format d1 $a } \x3f\xf9\x99\x99\x99\x99\x99\x9a test binary-14.17 {Tcl_BinaryObjCmd: format} {nonPortable pcOnly} { set a {1.6 3.4} binary format d1 $a } \x9a\x99\x99\x99\x99\x99\xf9\x3f test binary-14.18 {FormatNumber: Bug 1116542} { binary scan [binary format d 1.25] d w set w } 1.25 test binary-15.1 {Tcl_BinaryObjCmd: format} { list [catch {binary format ax*a "y" "z"} msg] $msg } {1 {cannot use "*" in format string with "x"}} test binary-15.2 {Tcl_BinaryObjCmd: format} { binary format axa "y" "z" } y\x00z test binary-15.3 {Tcl_BinaryObjCmd: format} { binary format ax3a "y" "z" } y\x00\x00\x00z test binary-15.4 {Tcl_BinaryObjCmd: format} { binary format a*X3x3a* "foo" "z" } \x00\x00\x00z test binary-15.5 {Tcl_BinaryObjCmd: format - bug #1923966} { binary format x0s 1 } \x01\x00 test binary-15.6 {Tcl_BinaryObjCmd: format - bug #1923966} { binary format x0ss 1 1 } \x01\x00\x01\x00 test binary-15.7 {Tcl_BinaryObjCmd: format - bug #1923966} { binary format x1s 1 } \x00\x01\x00 test binary-15.8 {Tcl_BinaryObjCmd: format - bug #1923966} { binary format x1ss 1 1 } \x00\x01\x00\x01\x00 test binary-16.1 {Tcl_BinaryObjCmd: format} { binary format a*X*a "foo" "z" } zoo test binary-16.2 {Tcl_BinaryObjCmd: format} { binary format aX3a "y" "z" } z test binary-16.3 {Tcl_BinaryObjCmd: format} { binary format a*Xa* "foo" "zy" } fozy test binary-16.4 {Tcl_BinaryObjCmd: format} { binary format a*X3a "foobar" "z" } foozar test binary-16.5 {Tcl_BinaryObjCmd: format} { binary format a*X3aX2a "foobar" "z" "b" } fobzar test binary-17.1 {Tcl_BinaryObjCmd: format} { binary format @1 } \x00 test binary-17.2 {Tcl_BinaryObjCmd: format} { binary format @5a2 "ab" } \x00\x00\x00\x00\x00\x61\x62 test binary-17.3 {Tcl_BinaryObjCmd: format} { binary format {a* @0 a2 @* a*} "foobar" "ab" "blat" } abobarblat test binary-18.1 {Tcl_BinaryObjCmd: format} { list [catch {binary format u0a3 abc abd} msg] $msg } {1 {bad field specifier "u"}} test binary-19.1 {Tcl_BinaryObjCmd: errors} { list [catch {binary s} msg] $msg } {1 {wrong # args: should be "binary scan value formatString ?varName varName ...?"}} test binary-19.2 {Tcl_BinaryObjCmd: errors} { list [catch {binary scan foo} msg] $msg } {1 {wrong # args: should be "binary scan value formatString ?varName varName ...?"}} test binary-19.3 {Tcl_BinaryObjCmd: scan} { binary scan {} {} } 0 test binary-20.1 {Tcl_BinaryObjCmd: scan} { list [catch {binary scan abc a} msg] $msg } {1 {not enough arguments for all format specifiers}} test binary-20.2 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} set arg1 1 list [catch {binary scan abc a arg1(a)} msg] $msg } {1 {can't set "arg1(a)": variable isn't array}} test binary-20.3 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} set arg1 abc list [binary scan abc a0 arg1] $arg1 } {1 {}} test binary-20.4 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan abc a* arg1] $arg1 } {1 abc} test binary-20.5 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan abc a5 arg1] [info exists arg1] } {0 0} test binary-20.6 {Tcl_BinaryObjCmd: scan} { set arg1 foo list [binary scan abc a2 arg1] $arg1 } {1 ab} test binary-20.7 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} catch {unset arg2} list [binary scan abcdef a2a2 arg1 arg2] $arg1 $arg2 } {2 ab cd} test binary-20.8 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan abc a2 arg1(a)] $arg1(a) } {1 ab} test binary-20.9 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan abc a arg1(a)] $arg1(a) } {1 a} test binary-21.1 {Tcl_BinaryObjCmd: scan} { list [catch {binary scan abc A} msg] $msg } {1 {not enough arguments for all format specifiers}} test binary-21.2 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} set arg1 1 list [catch {binary scan abc A arg1(a)} msg] $msg } {1 {can't set "arg1(a)": variable isn't array}} test binary-21.3 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} set arg1 abc list [binary scan abc A0 arg1] $arg1 } {1 {}} test binary-21.4 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan abc A* arg1] $arg1 } {1 abc} test binary-21.5 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan abc A5 arg1] [info exists arg1] } {0 0} test binary-21.6 {Tcl_BinaryObjCmd: scan} { set arg1 foo list [binary scan abc A2 arg1] $arg1 } {1 ab} test binary-21.7 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} catch {unset arg2} list [binary scan abcdef A2A2 arg1 arg2] $arg1 $arg2 } {2 ab cd} test binary-21.8 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan abc A2 arg1(a)] $arg1(a) } {1 ab} test binary-21.9 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan abc A2 arg1(a)] $arg1(a) } {1 ab} test binary-21.10 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan abc A arg1(a)] $arg1(a) } {1 a} test binary-21.11 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan "abc def \x00 " A* arg1] $arg1 } {1 {abc def}} test binary-21.12 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan "abc def \x00ghi " A* arg1] $arg1 } [list 1 "abc def \x00ghi"] test binary-22.1 {Tcl_BinaryObjCmd: scan} { list [catch {binary scan abc b} msg] $msg } {1 {not enough arguments for all format specifiers}} test binary-22.2 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x52\x53 b* arg1] $arg1 } {1 0100101011001010} test binary-22.3 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x82\x53 b arg1] $arg1 } {1 0} test binary-22.4 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x82\x53 b1 arg1] $arg1 } {1 0} test binary-22.5 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x82\x53 b0 arg1] $arg1 } {1 {}} test binary-22.6 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x52\x53 b5 arg1] $arg1 } {1 01001} test binary-22.7 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x52\x53 b8 arg1] $arg1 } {1 01001010} test binary-22.8 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x52\x53 b14 arg1] $arg1 } {1 01001010110010} test binary-22.9 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} set arg1 foo list [binary scan \x52 b14 arg1] $arg1 } {0 foo} test binary-22.10 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} set arg1 1 list [catch {binary scan \x52\x53 b1 arg1(a)} msg] $msg } {1 {can't set "arg1(a)": variable isn't array}} test binary-22.11 {Tcl_BinaryObjCmd: scan} { catch {unset arg1 arg2} set arg1 foo set arg2 bar list [binary scan \x07\x87\x05 b5b* arg1 arg2] $arg1 $arg2 } {2 11100 1110000110100000} test binary-23.1 {Tcl_BinaryObjCmd: scan} { list [catch {binary scan abc B} msg] $msg } {1 {not enough arguments for all format specifiers}} test binary-23.2 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x52\x53 B* arg1] $arg1 } {1 0101001001010011} test binary-23.3 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x82\x53 B arg1] $arg1 } {1 1} test binary-23.4 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x82\x53 B1 arg1] $arg1 } {1 1} test binary-23.5 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x52\x53 B0 arg1] $arg1 } {1 {}} test binary-23.6 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x52\x53 B5 arg1] $arg1 } {1 01010} test binary-23.7 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x52\x53 B8 arg1] $arg1 } {1 01010010} test binary-23.8 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x52\x53 B14 arg1] $arg1 } {1 01010010010100} test binary-23.9 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} set arg1 foo list [binary scan \x52 B14 arg1] $arg1 } {0 foo} test binary-23.10 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} set arg1 1 list [catch {binary scan \x52\x53 B1 arg1(a)} msg] $msg } {1 {can't set "arg1(a)": variable isn't array}} test binary-23.11 {Tcl_BinaryObjCmd: scan} { catch {unset arg1 arg2} set arg1 foo set arg2 bar list [binary scan \x70\x87\x05 B5B* arg1 arg2] $arg1 $arg2 } {2 01110 1000011100000101} test binary-24.1 {Tcl_BinaryObjCmd: scan} { list [catch {binary scan abc h} msg] $msg } {1 {not enough arguments for all format specifiers}} test binary-24.2 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x52\xa3 h* arg1] $arg1 } {1 253a} test binary-24.3 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \xc2\xa3 h arg1] $arg1 } {1 2} test binary-24.4 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x82\x53 h1 arg1] $arg1 } {1 2} test binary-24.5 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x52\x53 h0 arg1] $arg1 } {1 {}} test binary-24.6 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \xf2\x53 h2 arg1] $arg1 } {1 2f} test binary-24.7 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x52\x53 h3 arg1] $arg1 } {1 253} test binary-24.8 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} set arg1 foo list [binary scan \x52 h3 arg1] $arg1 } {0 foo} test binary-24.9 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} set arg1 1 list [catch {binary scan \x52\x53 h1 arg1(a)} msg] $msg } {1 {can't set "arg1(a)": variable isn't array}} test binary-24.10 {Tcl_BinaryObjCmd: scan} { catch {unset arg1 arg2} set arg1 foo set arg2 bar list [binary scan \x70\x87\x05 h2h* arg1 arg2] $arg1 $arg2 } {2 07 7850} test binary-25.1 {Tcl_BinaryObjCmd: scan} { list [catch {binary scan abc H} msg] $msg } {1 {not enough arguments for all format specifiers}} test binary-25.2 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x52\xa3 H* arg1] $arg1 } {1 52a3} test binary-25.3 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \xc2\xa3 H arg1] $arg1 } {1 c} test binary-25.4 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x82\x53 H1 arg1] $arg1 } {1 8} test binary-25.5 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x52\x53 H0 arg1] $arg1 } {1 {}} test binary-25.6 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \xf2\x53 H2 arg1] $arg1 } {1 f2} test binary-25.7 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x52\x53 H3 arg1] $arg1 } {1 525} test binary-25.8 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} set arg1 foo list [binary scan \x52 H3 arg1] $arg1 } {0 foo} test binary-25.9 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} set arg1 1 list [catch {binary scan \x52\x53 H1 arg1(a)} msg] $msg } {1 {can't set "arg1(a)": variable isn't array}} test binary-25.10 {Tcl_BinaryObjCmd: scan} { catch {unset arg1 arg2} set arg1 foo set arg2 bar list [binary scan \x70\x87\x05 H2H* arg1 arg2] $arg1 $arg2 } {2 70 8705} test binary-26.1 {Tcl_BinaryObjCmd: scan} { list [catch {binary scan abc c} msg] $msg } {1 {not enough arguments for all format specifiers}} test binary-26.2 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x52\xa3 c* arg1] $arg1 } {1 {82 -93}} test binary-26.3 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x52\xa3 c arg1] $arg1 } {1 82} test binary-26.4 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x52\xa3 c1 arg1] $arg1 } {1 82} test binary-26.5 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x52\xa3 c0 arg1] $arg1 } {1 {}} test binary-26.6 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x52\xa3 c2 arg1] $arg1 } {1 {82 -93}} test binary-26.7 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \xff c arg1] $arg1 } {1 -1} test binary-26.8 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} set arg1 foo list [binary scan \x52 c3 arg1] $arg1 } {0 foo} test binary-26.9 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} set arg1 1 list [catch {binary scan \x52\x53 c1 arg1(a)} msg] $msg } {1 {can't set "arg1(a)": variable isn't array}} test binary-26.10 {Tcl_BinaryObjCmd: scan} { catch {unset arg1 arg2} set arg1 foo set arg2 bar list [binary scan \x70\x87\x05 c2c* arg1 arg2] $arg1 $arg2 } {2 {112 -121} 5} test binary-27.1 {Tcl_BinaryObjCmd: scan} { list [catch {binary scan abc s} msg] $msg } {1 {not enough arguments for all format specifiers}} test binary-27.2 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x52\xa3\x53\x54 s* arg1] $arg1 } {1 {-23726 21587}} test binary-27.3 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x52\xa3\x53\x54 s arg1] $arg1 } {1 -23726} test binary-27.4 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x52\xa3 s1 arg1] $arg1 } {1 -23726} test binary-27.5 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x52\xa3 s0 arg1] $arg1 } {1 {}} test binary-27.6 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x52\xa3\x53\x54 s2 arg1] $arg1 } {1 {-23726 21587}} test binary-27.7 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} set arg1 foo list [binary scan \x52 s1 arg1] $arg1 } {0 foo} test binary-27.8 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} set arg1 1 list [catch {binary scan \x52\x53 s1 arg1(a)} msg] $msg } {1 {can't set "arg1(a)": variable isn't array}} test binary-27.9 {Tcl_BinaryObjCmd: scan} { catch {unset arg1 arg2} set arg1 foo set arg2 bar list [binary scan \x52\xa3\x53\x54\x05 s2c* arg1 arg2] $arg1 $arg2 } {2 {-23726 21587} 5} test binary-28.1 {Tcl_BinaryObjCmd: scan} { list [catch {binary scan abc S} msg] $msg } {1 {not enough arguments for all format specifiers}} test binary-28.2 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x52\xa3\x53\x54 S* arg1] $arg1 } {1 {21155 21332}} test binary-28.3 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x52\xa3\x53\x54 S arg1] $arg1 } {1 21155} test binary-28.4 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x52\xa3 S1 arg1] $arg1 } {1 21155} test binary-28.5 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x52\xa3 S0 arg1] $arg1 } {1 {}} test binary-28.6 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x52\xa3\x53\x54 S2 arg1] $arg1 } {1 {21155 21332}} test binary-28.7 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} set arg1 foo list [binary scan \x52 S1 arg1] $arg1 } {0 foo} test binary-28.8 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} set arg1 1 list [catch {binary scan \x52\x53 S1 arg1(a)} msg] $msg } {1 {can't set "arg1(a)": variable isn't array}} test binary-28.9 {Tcl_BinaryObjCmd: scan} { catch {unset arg1 arg2} set arg1 foo set arg2 bar list [binary scan \x52\xa3\x53\x54\x05 S2c* arg1 arg2] $arg1 $arg2 } {2 {21155 21332} 5} test binary-29.1 {Tcl_BinaryObjCmd: scan} { list [catch {binary scan abc i} msg] $msg } {1 {not enough arguments for all format specifiers}} test binary-29.2 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x52\xa3\x53\x54\x01\x02\x03\x04 i* arg1] $arg1 } {1 {1414767442 67305985}} test binary-29.3 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x52\xa3\x53\x54\x01\x02\x03\x04 i arg1] $arg1 } {1 1414767442} test binary-29.4 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x52\xa3\x53\x54 i1 arg1] $arg1 } {1 1414767442} test binary-29.5 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x52\xa3\x53 i0 arg1] $arg1 } {1 {}} test binary-29.6 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x52\xa3\x53\x54\x01\x02\x03\x04 i2 arg1] $arg1 } {1 {1414767442 67305985}} test binary-29.7 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} set arg1 foo list [binary scan \x52 i1 arg1] $arg1 } {0 foo} test binary-29.8 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} set arg1 1 list [catch {binary scan \x52\x53\x53\x54 i1 arg1(a)} msg] $msg } {1 {can't set "arg1(a)": variable isn't array}} test binary-29.9 {Tcl_BinaryObjCmd: scan} { catch {unset arg1 arg2} set arg1 foo set arg2 bar list [binary scan \x52\xa3\x53\x54\x01\x02\x03\x04\x05 i2c* arg1 arg2] $arg1 $arg2 } {2 {1414767442 67305985} 5} test binary-30.1 {Tcl_BinaryObjCmd: scan} { list [catch {binary scan abc I} msg] $msg } {1 {not enough arguments for all format specifiers}} test binary-30.2 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x52\xa3\x53\x54\x01\x02\x03\x04 I* arg1] $arg1 } {1 {1386435412 16909060}} test binary-30.3 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x52\xa3\x53\x54\x01\x02\x03\x04 I arg1] $arg1 } {1 1386435412} test binary-30.4 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x52\xa3\x53\x54 I1 arg1] $arg1 } {1 1386435412} test binary-30.5 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x52\xa3\x53 I0 arg1] $arg1 } {1 {}} test binary-30.6 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan \x52\xa3\x53\x54\x01\x02\x03\x04 I2 arg1] $arg1 } {1 {1386435412 16909060}} test binary-30.7 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} set arg1 foo list [binary scan \x52 I1 arg1] $arg1 } {0 foo} test binary-30.8 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} set arg1 1 list [catch {binary scan \x52\x53\x53\x54 I1 arg1(a)} msg] $msg } {1 {can't set "arg1(a)": variable isn't array}} test binary-30.9 {Tcl_BinaryObjCmd: scan} { catch {unset arg1 arg2} set arg1 foo set arg2 bar list [binary scan \x52\xa3\x53\x54\x01\x02\x03\x04\x05 I2c* arg1 arg2] $arg1 $arg2 } {2 {1386435412 16909060} 5} test binary-31.1 {Tcl_BinaryObjCmd: scan} { list [catch {binary scan abc f} msg] $msg } {1 {not enough arguments for all format specifiers}} test binary-31.2 {Tcl_BinaryObjCmd: scan} {nonPortable macOrUnix} { catch {unset arg1} list [binary scan \x3f\xcc\xcc\xcd\x40\x59\x99\x9a f* arg1] $arg1 } {1 {1.60000002384 3.40000009537}} test binary-31.3 {Tcl_BinaryObjCmd: scan} {nonPortable pcOnly} { catch {unset arg1} list [binary scan \xcd\xcc\xcc\x3f\x9a\x99\x59\x40 f* arg1] $arg1 } {1 {1.60000002384 3.40000009537}} test binary-31.4 {Tcl_BinaryObjCmd: scan} {nonPortable macOrUnix} { catch {unset arg1} list [binary scan \x3f\xcc\xcc\xcd\x40\x59\x99\x9a f arg1] $arg1 } {1 1.60000002384} test binary-31.5 {Tcl_BinaryObjCmd: scan} {nonPortable pcOnly} { catch {unset arg1} list [binary scan \xcd\xcc\xcc\x3f\x9a\x99\x59\x40 f arg1] $arg1 } {1 1.60000002384} test binary-31.6 {Tcl_BinaryObjCmd: scan} {nonPortable macOrUnix} { catch {unset arg1} list [binary scan \x3f\xcc\xcc\xcd f1 arg1] $arg1 } {1 1.60000002384} test binary-31.7 {Tcl_BinaryObjCmd: scan} {nonPortable pcOnly} { catch {unset arg1} list [binary scan \xcd\xcc\xcc\x3f f1 arg1] $arg1 } {1 1.60000002384} test binary-31.8 {Tcl_BinaryObjCmd: scan} {nonPortable macOrUnix} { catch {unset arg1} list [binary scan \x3f\xcc\xcc\xcd f0 arg1] $arg1 } {1 {}} test binary-31.9 {Tcl_BinaryObjCmd: scan} {nonPortable pcOnly} { catch {unset arg1} list [binary scan \xcd\xcc\xcc\x3f f0 arg1] $arg1 } {1 {}} test binary-31.10 {Tcl_BinaryObjCmd: scan} {nonPortable macOrUnix} { catch {unset arg1} list [binary scan \x3f\xcc\xcc\xcd\x40\x59\x99\x9a f2 arg1] $arg1 } {1 {1.60000002384 3.40000009537}} test binary-31.11 {Tcl_BinaryObjCmd: scan} {nonPortable pcOnly} { catch {unset arg1} list [binary scan \xcd\xcc\xcc\x3f\x9a\x99\x59\x40 f2 arg1] $arg1 } {1 {1.60000002384 3.40000009537}} test binary-31.12 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} set arg1 foo list [binary scan \x52 f1 arg1] $arg1 } {0 foo} test binary-31.13 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} set arg1 1 list [catch {binary scan \x3f\xcc\xcc\xcd f1 arg1(a)} msg] $msg } {1 {can't set "arg1(a)": variable isn't array}} test binary-31.14 {Tcl_BinaryObjCmd: scan} {nonPortable macOrUnix} { catch {unset arg1 arg2} set arg1 foo set arg2 bar list [binary scan \x3f\xcc\xcc\xcd\x40\x59\x99\x9a\x05 f2c* arg1 arg2] $arg1 $arg2 } {2 {1.60000002384 3.40000009537} 5} test binary-31.15 {Tcl_BinaryObjCmd: scan} {nonPortable pcOnly} { catch {unset arg1 arg2} set arg1 foo set arg2 bar list [binary scan \xcd\xcc\xcc\x3f\x9a\x99\x59\x40\x05 f2c* arg1 arg2] $arg1 $arg2 } {2 {1.60000002384 3.40000009537} 5} test binary-32.1 {Tcl_BinaryObjCmd: scan} { list [catch {binary scan abc d} msg] $msg } {1 {not enough arguments for all format specifiers}} test binary-32.2 {Tcl_BinaryObjCmd: scan} {nonPortable macOrUnix} { catch {unset arg1} list [binary scan \x3f\xf9\x99\x99\x99\x99\x99\x9a\x40\x0b\x33\x33\x33\x33\x33\x33 d* arg1] $arg1 } {1 {1.6 3.4}} test binary-32.3 {Tcl_BinaryObjCmd: scan} {nonPortable pcOnly} { catch {unset arg1} list [binary scan \x9a\x99\x99\x99\x99\x99\xf9\x3f\x33\x33\x33\x33\x33\x33\x0b\x40 d* arg1] $arg1 } {1 {1.6 3.4}} test binary-32.4 {Tcl_BinaryObjCmd: scan} {nonPortable macOrUnix} { catch {unset arg1} list [binary scan \x3f\xf9\x99\x99\x99\x99\x99\x9a\x40\x0b\x33\x33\x33\x33\x33\x33 d arg1] $arg1 } {1 1.6} test binary-32.5 {Tcl_BinaryObjCmd: scan} {nonPortable pcOnly} { catch {unset arg1} list [binary scan \x9a\x99\x99\x99\x99\x99\xf9\x3f\x33\x33\x33\x33\x33\x33\x0b\x40 d arg1] $arg1 } {1 1.6} test binary-32.6 {Tcl_BinaryObjCmd: scan} {nonPortable macOrUnix} { catch {unset arg1} list [binary scan \x3f\xf9\x99\x99\x99\x99\x99\x9a d1 arg1] $arg1 } {1 1.6} test binary-32.7 {Tcl_BinaryObjCmd: scan} {nonPortable pcOnly} { catch {unset arg1} list [binary scan \x9a\x99\x99\x99\x99\x99\xf9\x3f d1 arg1] $arg1 } {1 1.6} test binary-32.8 {Tcl_BinaryObjCmd: scan} {nonPortable macOrUnix} { catch {unset arg1} list [binary scan \x3f\xf9\x99\x99\x99\x99\x99\x9a d0 arg1] $arg1 } {1 {}} test binary-32.9 {Tcl_BinaryObjCmd: scan} {nonPortable pcOnly} { catch {unset arg1} list [binary scan \x9a\x99\x99\x99\x99\x99\xf9\x3f d0 arg1] $arg1 } {1 {}} test binary-32.10 {Tcl_BinaryObjCmd: scan} {nonPortable macOrUnix} { catch {unset arg1} list [binary scan \x3f\xf9\x99\x99\x99\x99\x99\x9a\x40\x0b\x33\x33\x33\x33\x33\x33 d2 arg1] $arg1 } {1 {1.6 3.4}} test binary-32.11 {Tcl_BinaryObjCmd: scan} {nonPortable pcOnly} { catch {unset arg1} list [binary scan \x9a\x99\x99\x99\x99\x99\xf9\x3f\x33\x33\x33\x33\x33\x33\x0b\x40 d2 arg1] $arg1 } {1 {1.6 3.4}} test binary-32.12 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} set arg1 foo list [binary scan \x52 d1 arg1] $arg1 } {0 foo} test binary-32.13 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} set arg1 1 list [catch {binary scan \x3f\xf9\x99\x99\x99\x99\x99\x9a d1 arg1(a)} msg] $msg } {1 {can't set "arg1(a)": variable isn't array}} test binary-32.14 {Tcl_BinaryObjCmd: scan} {nonPortable macOrUnix} { catch {unset arg1 arg2} set arg1 foo set arg2 bar list [binary scan \x3f\xf9\x99\x99\x99\x99\x99\x9a\x40\x0b\x33\x33\x33\x33\x33\x33\x05 d2c* arg1 arg2] $arg1 $arg2 } {2 {1.6 3.4} 5} test binary-32.15 {Tcl_BinaryObjCmd: scan} {nonPortable pcOnly} { catch {unset arg1 arg2} set arg1 foo set arg2 bar list [binary scan \x9a\x99\x99\x99\x99\x99\xf9\x3f\x33\x33\x33\x33\x33\x33\x0b\x40\x05 d2c* arg1 arg2] $arg1 $arg2 } {2 {1.6 3.4} 5} test binary-33.1 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} catch {unset arg2} list [binary scan abcdefg a2xa3 arg1 arg2] $arg1 $arg2 } {2 ab def} test binary-33.2 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} catch {unset arg2} set arg2 foo list [binary scan abcdefg a3x*a3 arg1 arg2] $arg1 $arg2 } {1 abc foo} test binary-33.3 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} catch {unset arg2} set arg2 foo list [binary scan abcdefg a3x20a3 arg1 arg2] $arg1 $arg2 } {1 abc foo} test binary-33.4 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} catch {unset arg2} set arg2 foo list [binary scan abc a3x20a3 arg1 arg2] $arg1 $arg2 } {1 abc foo} test binary-33.5 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan abcdef x1a1 arg1] $arg1 } {1 b} test binary-33.6 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan abcdef x5a1 arg1] $arg1 } {1 f} test binary-33.7 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan abcdef x0a1 arg1] $arg1 } {1 a} test binary-34.1 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} catch {unset arg2} list [binary scan abcdefg a2Xa3 arg1 arg2] $arg1 $arg2 } {2 ab bcd} test binary-34.2 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} catch {unset arg2} set arg2 foo list [binary scan abcdefg a3X*a3 arg1 arg2] $arg1 $arg2 } {2 abc abc} test binary-34.3 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} catch {unset arg2} set arg2 foo list [binary scan abcdefg a3X20a3 arg1 arg2] $arg1 $arg2 } {2 abc abc} test binary-34.4 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan abc X20a3 arg1] $arg1 } {1 abc} test binary-34.5 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan abcdef x*X1a1 arg1] $arg1 } {1 f} test binary-34.6 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan abcdef x*X5a1 arg1] $arg1 } {1 b} test binary-34.7 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan abcdef x3X0a1 arg1] $arg1 } {1 d} test binary-35.1 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} catch {unset arg2} list [catch {binary scan abcdefg a2@a3 arg1 arg2} msg] $msg } {1 {missing count for "@" field specifier}} test binary-35.2 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} catch {unset arg2} set arg2 foo list [binary scan abcdefg a3@*a3 arg1 arg2] $arg1 $arg2 } {1 abc foo} test binary-35.3 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} catch {unset arg2} set arg2 foo list [binary scan abcdefg a3@20a3 arg1 arg2] $arg1 $arg2 } {1 abc foo} test binary-35.4 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan abcdef @2a3 arg1] $arg1 } {1 cde} test binary-35.5 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan abcdef x*@1a1 arg1] $arg1 } {1 b} test binary-35.6 {Tcl_BinaryObjCmd: scan} { catch {unset arg1} list [binary scan abcdef x*@0a1 arg1] $arg1 } {1 a} test binary-36.1 {Tcl_BinaryObjCmd: scan} { list [catch {binary scan abcdef u0a3} msg] $msg } {1 {bad field specifier "u"}} # GetFormatSpec is pretty thoroughly tested above, but there are a few # cases we should text explicitly test binary-37.1 {GetFormatSpec: whitespace} { binary format "a3 a5 a3" foo barblat baz } foobarblbaz test binary-37.2 {GetFormatSpec: whitespace} { binary format " " foo } {} test binary-37.3 {GetFormatSpec: whitespace} { binary format " a3" foo } foo test binary-37.4 {GetFormatSpec: whitespace} { binary format "" foo } {} test binary-37.5 {GetFormatSpec: whitespace} { binary format "" foo } {} test binary-37.6 {GetFormatSpec: whitespace} { binary format " a3 " foo } foo test binary-37.7 {GetFormatSpec: numbers} { list [catch {binary scan abcdef "x-1" foo} msg] $msg } {1 {bad field specifier "-"}} test binary-37.8 {GetFormatSpec: numbers} { catch {unset arg1} set arg1 foo list [binary scan abcdef "a0x3" arg1] $arg1 } {1 {}} test binary-37.9 {GetFormatSpec: numbers} { # test format of neg numbers # bug report/fix provided by Harald Kirsch set x [binary format f* {1 -1 2 -2 0}] binary scan $x f* bla set bla } {1.0 -1.0 2.0 -2.0 0.0} test binary-38.1 {FormatNumber: word alignment} { set x [binary format c1s1 1 1] } \x01\x01\x00 test binary-38.2 {FormatNumber: word alignment} { set x [binary format c1S1 1 1] } \x01\x00\x01 test binary-38.3 {FormatNumber: word alignment} { set x [binary format c1i1 1 1] } \x01\x01\x00\x00\x00 test binary-38.4 {FormatNumber: word alignment} { set x [binary format c1I1 1 1] } \x01\x00\x00\x00\x01 test binary-38.5 {FormatNumber: word alignment} {nonPortable macOrUnix} { set x [binary format c1d1 1 1.6] } \x01\x3f\xf9\x99\x99\x99\x99\x99\x9a test binary-38.6 {FormatNumber: word alignment} {nonPortable pcOnly} { set x [binary format c1d1 1 1.6] } \x01\x9a\x99\x99\x99\x99\x99\xf9\x3f test binary-38.7 {FormatNumber: word alignment} {nonPortable macOrUnix} { set x [binary format c1f1 1 1.6] } \x01\x3f\xcc\xcc\xcd test binary-38.8 {FormatNumber: word alignment} {nonPortable pcOnly} { set x [binary format c1f1 1 1.6] } \x01\xcd\xcc\xcc\x3f test binary-39.1 {ScanNumber: sign extension} { catch {unset arg1} list [binary scan \x52\xa3 c2 arg1] $arg1 } {1 {82 -93}} test binary-39.2 {ScanNumber: sign extension} { catch {unset arg1} list [binary scan \x01\x02\x01\x81\x82\x01\x81\x82 s4 arg1] $arg1 } {1 {513 -32511 386 -32127}} test binary-39.3 {ScanNumber: sign extension} { catch {unset arg1} list [binary scan \x01\x02\x01\x81\x82\x01\x81\x82 S4 arg1] $arg1 } {1 {258 385 -32255 -32382}} test binary-39.4 {ScanNumber: sign extension} { catch {unset arg1} list [binary scan \x01\x01\x01\x02\x81\x01\x01\x01\x01\x82\x01\x01\x01\x01\x82\x01\x01\x01\x01\x81 i5 arg1] $arg1 } {1 {33620225 16843137 16876033 25297153 -2130640639}} test binary-39.5 {ScanNumber: sign extension} { catch {unset arg1} list [binary scan \x01\x01\x01\x02\x81\x01\x01\x01\x01\x82\x01\x01\x01\x01\x82\x01\x01\x01\x01\x81 I5 arg1] $arg1 } {1 {16843010 -2130640639 25297153 16876033 16843137}} test binary-40.1 {ScanNumber: floating point overflow} {nonPortable unixOnly} { catch {unset arg1} list [binary scan \xff\xff\xff\xff f1 arg1] $arg1 } {1 -NaN} test binary-40.3 {ScanNumber: floating point overflow} {nonPortable pcOnly} { catch {unset arg1} set result [binary scan \xff\xff\xff\xff f1 arg1] if {([string compare $arg1 -1.\#QNAN] == 0) || ([string compare $arg1 -NAN] == 0)} { lappend result success } else { lappend result failure } } {1 success} test binary-40.4 {ScanNumber: floating point overflow} {nonPortable unixOnly} { catch {unset arg1} list [binary scan \xff\xff\xff\xff\xff\xff\xff\xff d1 arg1] $arg1 } {1 -NaN} test binary-40.6 {ScanNumber: floating point overflow} {nonPortable pcOnly} { catch {unset arg1} set result [binary scan \xff\xff\xff\xff\xff\xff\xff\xff d1 arg1] if {([string compare $arg1 -1.\#QNAN] == 0) || ([string compare $arg1 -NAN] == 0)} { lappend result success } else { lappend result failure } } {1 success} test binary-41.1 {ScanNumber: word alignment} { catch {unset arg1; unset arg2} list [binary scan \x01\x01\x00 c1s1 arg1 arg2] $arg1 $arg2 } {2 1 1} test binary-41.2 {ScanNumber: word alignment} { catch {unset arg1; unset arg2} list [binary scan \x01\x00\x01 c1S1 arg1 arg2] $arg1 $arg2 } {2 1 1} test binary-41.3 {ScanNumber: word alignment} { catch {unset arg1; unset arg2} list [binary scan \x01\x01\x00\x00\x00 c1i1 arg1 arg2] $arg1 $arg2 } {2 1 1} test binary-41.4 {ScanNumber: word alignment} { catch {unset arg1; unset arg2} list [binary scan \x01\x00\x00\x00\x01 c1I1 arg1 arg2] $arg1 $arg2 } {2 1 1} test binary-41.5 {ScanNumber: word alignment} {nonPortable macOrUnix} { catch {unset arg1; unset arg2} list [binary scan \x01\x3f\xcc\xcc\xcd c1f1 arg1 arg2] $arg1 $arg2 } {2 1 1.60000002384} test binary-41.6 {ScanNumber: word alignment} {nonPortable pcOnly} { catch {unset arg1; unset arg2} list [binary scan \x01\xcd\xcc\xcc\x3f c1f1 arg1 arg2] $arg1 $arg2 } {2 1 1.60000002384} test binary-41.7 {ScanNumber: word alignment} {nonPortable macOrUnix} { catch {unset arg1; unset arg2} list [binary scan \x01\x3f\xf9\x99\x99\x99\x99\x99\x9a c1d1 arg1 arg2] $arg1 $arg2 } {2 1 1.6} test binary-41.8 {ScanNumber: word alignment} {nonPortable pcOnly} { catch {unset arg1; unset arg2} list [binary scan \x01\x9a\x99\x99\x99\x99\x99\xf9\x3f c1d1 arg1 arg2] $arg1 $arg2 } {2 1 1.6} test binary-42.1 {Tcl_BinaryObjCmd: bad arguments} {} { catch {binary ?} result set result } {bad option "?": must be format or scan} # Wide int (guaranteed at least 64-bit) handling test binary-43.1 {Tcl_BinaryObjCmd: format wide int} {} { binary format w 7810179016327718216 } HelloTcl test binary-43.2 {Tcl_BinaryObjCmd: format wide int} {} { binary format W 7810179016327718216 } lcTolleH test binary-44.1 {Tcl_BinaryObjCmd: scan wide int} {} { binary scan HelloTcl W x set x } 5216694956358656876 test binary-44.2 {Tcl_BinaryObjCmd: scan wide int} {} { binary scan lcTolleH w x set x } 5216694956358656876 test binary-44.3 {Tcl_BinaryObjCmd: scan wide int with bit 31 set} {} { binary scan [binary format w [expr {wide(3) << 31}]] w x set x } 6442450944 test binary-44.4 {Tcl_BinaryObjCmd: scan wide int with bit 31 set} {} { binary scan [binary format W [expr {wide(3) << 31}]] W x set x } 6442450944 test binary-45.1 {Tcl_BinaryObjCmd: combined wide int handling} { binary scan [binary format sws 16450 -1 19521] c* x set x } {66 64 -1 -1 -1 -1 -1 -1 -1 -1 65 76} test binary-45.2 {Tcl_BinaryObjCmd: combined wide int handling} { binary scan [binary format sWs 16450 0x7fffffff 19521] c* x set x } {66 64 0 0 0 0 127 -1 -1 -1 65 76} test binary-46.1 {Tcl_BinaryObjCmd: handling of non-ISO8859-1 chars} { binary format a* \u20ac } \u00ac test binary-46.2 {Tcl_BinaryObjCmd: handling of non-ISO8859-1 chars} { list [binary scan [binary format a* \u20ac\u20bd] s x] $x } {1 -16980} test binary-46.3 {Tcl_BinaryObjCmd: handling of non-ISO8859-1 chars} { set x {} set y {} set z {} list [binary scan [binary format a* \u20ac\u20bd] aaa x y z] $x $y $z } "2 \u00ac \u00bd {}" test binary-46.4 {Tcl_BinaryObjCmd: handling of non-ISO8859-1 chars} { set x [encoding convertto iso8859-15 \u20ac] set y [binary format a* $x] list $x $y } "\u00a4 \u00a4" test binary-46.5 {Tcl_BinaryObjCmd: handling of non-ISO8859-1 chars} { set x [binary scan \u00a4 a* y] list $x $y [encoding convertfrom iso8859-15 $y] } "1 \u00a4 \u20ac" test binary-47.1 {Tcl_BinaryObjCmd: number cache reference count handling} { # This test is only reliable when memory debugging is turned on, # but without even memory debugging it should still generate the # expected answers and might therefore still pick up memory corruption # caused by [Bug 851747]. list [binary scan aba ccc x x x] $x } {3 97} # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/append.test0000644003604700454610000001767011737050674014244 0ustar dgp771div# Commands covered: append lappend # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994-1996 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } catch {unset x} test append-1.1 {append command} { catch {unset x} list [append x 1 2 abc "long string"] $x } {{12abclong string} {12abclong string}} test append-1.2 {append command} { set x "" list [append x first] [append x second] [append x third] $x } {first firstsecond firstsecondthird firstsecondthird} test append-1.3 {append command} { set x "abcd" append x } abcd test append-2.1 {long appends} { set x "" for {set i 0} {$i < 1000} {set i [expr $i+1]} { append x "foobar " } set y "foobar" set y "$y $y $y $y $y $y $y $y $y $y" set y "$y $y $y $y $y $y $y $y $y $y" set y "$y $y $y $y $y $y $y $y $y $y " expr {$x == $y} } 1 test append-3.1 {append errors} { list [catch {append} msg] $msg } {1 {wrong # args: should be "append varName ?value value ...?"}} test append-3.2 {append errors} { set x "" list [catch {append x(0) 44} msg] $msg } {1 {can't set "x(0)": variable isn't array}} test append-3.3 {append errors} { catch {unset x} list [catch {append x} msg] $msg } {1 {can't read "x": no such variable}} test append-4.1 {lappend command} { catch {unset x} list [lappend x 1 2 abc "long string"] $x } {{1 2 abc {long string}} {1 2 abc {long string}}} test append-4.2 {lappend command} { set x "" list [lappend x first] [lappend x second] [lappend x third] $x } {first {first second} {first second third} {first second third}} test append-4.3 {lappend command} { proc foo {} { global x set x old unset x lappend x new } set result [foo] rename foo {} set result } {new} test append-4.4 {lappend command} { set x {} lappend x \{\ abc } {\{\ abc} test append-4.5 {lappend command} { set x {} lappend x \{ abc } {\{ abc} test append-4.6 {lappend command} { set x {1 2 3} lappend x } {1 2 3} test append-4.7 {lappend command} { set x "a\{" lappend x abc } "a\\\{ abc" test append-4.8 {lappend command} { set x "\\\{" lappend x abc } "\\{ abc" test append-4.9 {lappend command} { set x " \{" list [catch {lappend x abc} msg] $msg } {1 {unmatched open brace in list}} test append-4.10 {lappend command} { set x " \{" list [catch {lappend x abc} msg] $msg } {1 {unmatched open brace in list}} test append-4.11 {lappend command} { set x "\{\{\{" list [catch {lappend x abc} msg] $msg } {1 {unmatched open brace in list}} test append-4.12 {lappend command} { set x "x \{\{\{" list [catch {lappend x abc} msg] $msg } {1 {unmatched open brace in list}} test append-4.13 {lappend command} { set x "x\{\{\{" lappend x abc } "x\\\{\\\{\\\{ abc" test append-4.14 {lappend command} { set x " " lappend x abc } "abc" test append-4.15 {lappend command} { set x "\\ " lappend x abc } "{ } abc" test append-4.16 {lappend command} { set x "x " lappend x abc } "x abc" test append-4.17 {lappend command} { catch {unset x} lappend x } {} test append-4.18 {lappend command} { catch {unset x} lappend x {} } {{}} test append-4.19 {lappend command} { catch {unset x} lappend x(0) } {} test append-4.20 {lappend command} { catch {unset x} lappend x(0) abc } {abc} unset x test append-4.21 {lappend command} { set x \" list [catch {lappend x} msg] $msg } {1 {unmatched open quote in list}} test append-4.22 {lappend command} { set x \" list [catch {lappend x abc} msg] $msg } {1 {unmatched open quote in list}} proc check {var size} { set l [llength $var] if {$l != $size} { return "length mismatch: should have been $size, was $l" } for {set i 0} {$i < $size} {set i [expr $i+1]} { set j [lindex $var $i] if {$j != "item $i"} { return "element $i should have been \"item $i\", was \"$j\"" } } return ok } test append-5.1 {long lappends} { catch {unset x} set x "" for {set i 0} {$i < 300} {set i [expr $i+1]} { lappend x "item $i" } check $x 300 } ok test append-6.1 {lappend errors} { list [catch {lappend} msg] $msg } {1 {wrong # args: should be "lappend varName ?value value ...?"}} test append-6.2 {lappend errors} { set x "" list [catch {lappend x(0) 44} msg] $msg } {1 {can't set "x(0)": variable isn't array}} test append-7.1 {lappend-created var and error in trace on that var} { catch {rename foo ""} catch {unset x} trace variable x w foo proc foo {} {global x; unset x} catch {lappend x 1} proc foo {args} {global x; unset x} info exists x set x lappend x 1 list [info exists x] [catch {set x} msg] $msg } {0 1 {can't read "x": no such variable}} test append-7.2 {lappend var triggers read trace} { catch {unset myvar} catch {unset ::result} trace variable myvar r foo proc foo {args} {append ::result $args} lappend myvar a list [catch {set ::result} msg] $msg } {0 {myvar {} r}} test append-7.3 {lappend var triggers read trace, array var} { # The behavior of read triggers on lappend changed in 8.0 to # not trigger them, and was changed back in 8.4. catch {unset myvar} catch {unset ::result} trace variable myvar r foo proc foo {args} {append ::result $args} lappend myvar(b) a list [catch {set ::result} msg] $msg } {0 {myvar b r}} test append-7.4 {lappend var triggers read trace, array var exists} { catch {unset myvar} catch {unset ::result} set myvar(0) 1 trace variable myvar r foo proc foo {args} {append ::result $args} lappend myvar(b) a list [catch {set ::result} msg] $msg } {0 {myvar b r}} test append-7.5 {append var does not trigger read trace} { catch {unset myvar} catch {unset ::result} trace variable myvar r foo proc foo {args} {append ::result $args} append myvar a info exists ::result } {0} # New tests for bug 3057639 to show off the more consistent behaviour # of lappend in both direct-eval and bytecompiled code paths (see # appendComp.test for the compiled variants). lappend now behaves like # append. 9.0/1 lappend - 9.2/3 append test append-9.0 {bug 3057639, lappend direct eval, read trace on non-existing array variable element} { catch {unset myvar} array set myvar {} proc nonull {var key val} { upvar 1 $var lvar if {![info exists lvar($key)]} { return -code error "no such variable" } } trace add variable myvar read nonull list [catch { lappend myvar(key) "new value" } msg] $msg } {0 {{new value}}} test append-9.1 {bug 3057639, lappend direct eval, read trace on non-existing env element} { catch {unset ::env(__DUMMY__)} list [catch { lappend ::env(__DUMMY__) "new value" } msg] $msg } {0 {{new value}}} test append-9.2 {bug 3057639, append direct eval, read trace on non-existing array variable element} { catch {unset myvar} array set myvar {} proc nonull {var key val} { upvar 1 $var lvar if {![info exists lvar($key)]} { return -code error "no such variable" } } trace add variable myvar read nonull list [catch { append myvar(key) "new value" } msg] $msg } {0 {new value}} test append-9.3 {bug 3057639, append direct eval, read trace on non-existing env element} { catch {unset ::env(__DUMMY__)} list [catch { append ::env(__DUMMY__) "new value" } msg] $msg } {0 {new value}} catch {unset i x result y} catch {rename foo ""} catch {rename check ""} # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/link.test0000644003604700454610000002034611737050674013724 0ustar dgp771div# Commands covered: none # # This file contains a collection of tests for Tcl_LinkVar and related # library procedures. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1993 The Regents of the University of California. # Copyright (c) 1994 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import -force ::tcltest::* } ::tcltest::testConstraint testlink \ [expr {[info commands testlink] != {}}] foreach i {int real bool string} { catch {unset $i} } test link-1.1 {reading C variables from Tcl} {testlink} { testlink delete testlink set 43 1.23 4 - 12341234 testlink create 1 1 1 1 1 list $int $real $bool $string $wide } {43 1.23 1 NULL 12341234} test link-1.2 {reading C variables from Tcl} {testlink} { testlink delete testlink create 1 1 1 1 1 testlink set -3 2 0 "A long string with spaces" 43214321 list $int $real $bool $string $wide $int $real $bool $string $wide } {-3 2.0 0 {A long string with spaces} 43214321 -3 2.0 0 {A long string with spaces} 43214321} test link-2.1 {writing C variables from Tcl} {testlink} { testlink delete testlink set 43 1.21 4 - 56785678 testlink create 1 1 1 1 1 set int "00721" set real -10.5 set bool true set string abcdef set wide 135135 concat [testlink get] $int $real $bool $string $wide } {465 -10.5 1 abcdef 135135 00721 -10.5 true abcdef 135135} test link-2.2 {writing bad values into variables} {testlink} { testlink delete testlink set 43 1.23 4 - 56785678 testlink create 1 1 1 1 1 list [catch {set int 09a} msg] $msg $int } {1 {can't set "int": variable must have integer value} 43} test link-2.3 {writing bad values into variables} {testlink} { testlink delete testlink set 43 1.23 4 - 56785678 testlink create 1 1 1 1 1 list [catch {set real 1.x3} msg] $msg $real } {1 {can't set "real": variable must have real value} 1.23} test link-2.4 {writing bad values into variables} {testlink} { testlink delete testlink set 43 1.23 4 - 56785678 testlink create 1 1 1 1 1 list [catch {set bool gorp} msg] $msg $bool } {1 {can't set "bool": variable must have boolean value} 1} test link-2.5 {writing bad values into variables} {testlink} { testlink delete testlink set 43 1.23 4 - 56785678 testlink create 1 1 1 1 1 list [catch {set wide gorp} msg] $msg $bool } {1 {can't set "wide": variable must have integer value} 1} test link-3.1 {read-only variables} {testlink} { testlink delete testlink set 43 1.23 4 - 56785678 testlink create 0 1 1 0 0 list [catch {set int 4} msg] $msg $int \ [catch {set real 10.6} msg] $msg $real \ [catch {set bool no} msg] $msg $bool \ [catch {set string "new value"} msg] $msg $string \ [catch {set wide 12341234} msg] $msg $wide } {1 {can't set "int": linked variable is read-only} 43 0 10.6 10.6 0 no no 1 {can't set "string": linked variable is read-only} NULL 1 {can't set "wide": linked variable is read-only} 56785678} test link-3.2 {read-only variables} {testlink} { testlink delete testlink set 43 1.23 4 - 56785678 testlink create 1 0 0 1 1 list [catch {set int 4} msg] $msg $int \ [catch {set real 10.6} msg] $msg $real \ [catch {set bool no} msg] $msg $bool \ [catch {set string "new value"} msg] $msg $string\ [catch {set wide 12341234} msg] $msg $wide } {0 4 4 1 {can't set "real": linked variable is read-only} 1.23 1 {can't set "bool": linked variable is read-only} 1 0 {new value} {new value} 0 12341234 12341234} test link-4.1 {unsetting linked variables} {testlink} { testlink delete testlink set -6 -2.5 0 stringValue 13579 testlink create 1 1 1 1 1 unset int real bool string wide list [catch {set int} msg] $msg [catch {set real} msg] $msg \ [catch {set bool} msg] $msg [catch {set string} msg] $msg \ [catch {set wide} msg] $msg } {0 -6 0 -2.5 0 0 0 stringValue 0 13579} test link-4.2 {unsetting linked variables} {testlink} { testlink delete testlink set -6 -2.1 0 stringValue 97531 testlink create 1 1 1 1 1 unset int real bool string wide set int 102 set real 16 set bool true set string newValue set wide 333555 testlink get } {102 16.0 1 newValue 333555} test link-5.1 {unlinking variables} {testlink} { testlink delete testlink set -6 -2.25 0 stringValue 13579 testlink delete set int xx1 set real qrst set bool bogus set string 12345 set wide 875421 testlink get } {-6 -2.25 0 stringValue 13579} test link-5.2 {unlinking variables} {testlink} { testlink delete testlink set -6 -2.25 0 stringValue 97531 testlink create 1 1 1 1 1 testlink delete testlink set 25 14.7 7 - 999999 list $int $real $bool $string $wide } {-6 -2.25 0 stringValue 97531} test link-6.1 {errors in setting up link} {testlink} { testlink delete catch {unset int} set int(44) 1 list [catch {testlink create 1 1 1 1 1} msg] $msg } {1 {can't set "int": variable is array}} catch {unset int} test link-7.1 {access to linked variables via upvar} {testlink} { proc x {} { upvar int y unset y } testlink delete testlink create 1 0 0 0 0 testlink set 14 {} {} {} {} x list [catch {set int} msg] $msg } {0 14} test link-7.2 {access to linked variables via upvar} {testlink} { proc x {} { upvar int y return [set y] } testlink delete testlink create 1 0 0 0 0 testlink set 0 {} {} {} {} set int testlink set 23 {} {} {} {} x list [x] $int } {23 23} test link-7.3 {access to linked variables via upvar} {testlink} { proc x {} { upvar int y set y 44 } testlink delete testlink create 0 0 0 0 0 testlink set 11 {} {} {} {} list [catch x msg] $msg $int } {1 {can't set "y": linked variable is read-only} 11} test link-7.4 {access to linked variables via upvar} {testlink} { proc x {} { upvar int y set y abc } testlink delete testlink create 1 1 1 1 1 testlink set -4 {} {} {} {} list [catch x msg] $msg $int } {1 {can't set "y": variable must have integer value} -4} test link-7.5 {access to linked variables via upvar} {testlink} { proc x {} { upvar real y set y abc } testlink delete testlink create 1 1 1 1 1 testlink set -4 16.75 {} {} {} list [catch x msg] $msg $real } {1 {can't set "y": variable must have real value} 16.75} test link-7.6 {access to linked variables via upvar} {testlink} { proc x {} { upvar bool y set y abc } testlink delete testlink create 1 1 1 1 1 testlink set -4 16.3 1 {} {} list [catch x msg] $msg $bool } {1 {can't set "y": variable must have boolean value} 1} test link-7.7 {access to linked variables via upvar} {testlink} { proc x {} { upvar wide y set y abc } testlink delete testlink create 1 1 1 1 1 testlink set -4 16.3 1 {} 778899 list [catch x msg] $msg $wide } {1 {can't set "y": variable must have integer value} 778899} test link-8.1 {Tcl_UpdateLinkedVar procedure} {testlink} { proc x args { global x int real bool string wide lappend x $args $int $real $bool $string $wide } set x {} testlink create 1 1 1 1 1 testlink set 14 -2.0 0 xyzzy 995511 trace var int w x testlink update 32 4.0 3 abcd 113355 trace vdelete int w x set x } {{int {} w} 32 -2.0 0 xyzzy 995511} test link-8.2 {Tcl_UpdateLinkedVar procedure} {testlink} { proc x args { global x int real bool string wide lappend x $args $int $real $bool $string $wide } set x {} testlink create 1 1 1 1 1 testlink set 14 -2.0 0 xyzzy 995511 testlink delete trace var int w x testlink update 32 4.0 6 abcd 113355 trace vdelete int w x set x } {} test link-8.3 {Tcl_UpdateLinkedVar procedure, read-only variable} {testlink} { testlink create 0 0 0 0 0 list [catch {testlink update 47 {} {} {} {}} msg] $msg $int } {0 {} 47} catch {testlink set 0 0 0 - 0} catch {testlink delete} foreach i {int real bool string wide} { catch {unset $i} } # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/for-old.test0000644003604700454610000000364111737050674014330 0ustar dgp771div# Commands covered: for, continue, break # # This file contains the original set of tests for Tcl's for command. # Since the for command is now compiled, a new set of tests covering # the new implementation is in the file "for.test". Sourcing this file # into Tcl runs the tests and generates output for errors. # No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994-1996 Sun Microsystems, Inc. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } # Check "for" and its use of continue and break. catch {unset a i} test for-old-1.1 {for tests} { set a {} for {set i 1} {$i<6} {set i [expr $i+1]} { set a [concat $a $i] } set a } {1 2 3 4 5} test for-old-1.2 {for tests} { set a {} for {set i 1} {$i<6} {set i [expr $i+1]} { if $i==4 continue set a [concat $a $i] } set a } {1 2 3 5} test for-old-1.3 {for tests} { set a {} for {set i 1} {$i<6} {set i [expr $i+1]} { if $i==4 break set a [concat $a $i] } set a } {1 2 3} test for-old-1.4 {for tests} {catch {for 1 2 3} msg} 1 test for-old-1.5 {for tests} { catch {for 1 2 3} msg set msg } {wrong # args: should be "for start test next command"} test for-old-1.6 {for tests} {catch {for 1 2 3 4 5} msg} 1 test for-old-1.7 {for tests} { catch {for 1 2 3 4 5} msg set msg } {wrong # args: should be "for start test next command"} test for-old-1.8 {for tests} { set a {xyz} for {set i 1} {$i<6} {set i [expr $i+1]} {} set a } xyz test for-old-1.9 {for tests} { set a {} for {set i 1} {$i<6} {set i [expr $i+1]; if $i==4 break} { set a [concat $a $i] } set a } {1 2 3} # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/interp.test0000644003604700454610000023461312052456744014273 0ustar dgp771div# This file tests the multiple interpreter facility of Tcl # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1995-1996 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2.1 namespace import -force ::tcltest::* } set hidden_cmds {cd encoding exec exit fconfigure file glob load open pwd socket source} foreach i [interp slaves] { interp delete $i } proc equiv {x} {return $x} # Part 0: Check out options for interp command test interp-1.1 {options for interp command} { list [catch {interp} msg] $msg } {1 {wrong # args: should be "interp cmd ?arg ...?"}} test interp-1.2 {options for interp command} { list [catch {interp frobox} msg] $msg } {1 {bad option "frobox": must be alias, aliases, create, delete, eval, exists, expose, hide, hidden, issafe, invokehidden, marktrusted, recursionlimit, slaves, share, target, or transfer}} test interp-1.3 {options for interp command} { interp delete } "" test interp-1.4 {options for interp command} { list [catch {interp delete foo bar} msg] $msg } {1 {could not find interpreter "foo"}} test interp-1.5 {options for interp command} { list [catch {interp exists foo bar} msg] $msg } {1 {wrong # args: should be "interp exists ?path?"}} # # test interp-0.6 was removed # test interp-1.6 {options for interp command} { list [catch {interp slaves foo bar zop} msg] $msg } {1 {wrong # args: should be "interp slaves ?path?"}} test interp-1.7 {options for interp command} { list [catch {interp hello} msg] $msg } {1 {bad option "hello": must be alias, aliases, create, delete, eval, exists, expose, hide, hidden, issafe, invokehidden, marktrusted, recursionlimit, slaves, share, target, or transfer}} test interp-1.8 {options for interp command} { list [catch {interp -froboz} msg] $msg } {1 {bad option "-froboz": must be alias, aliases, create, delete, eval, exists, expose, hide, hidden, issafe, invokehidden, marktrusted, recursionlimit, slaves, share, target, or transfer}} test interp-1.9 {options for interp command} { list [catch {interp -froboz -safe} msg] $msg } {1 {bad option "-froboz": must be alias, aliases, create, delete, eval, exists, expose, hide, hidden, issafe, invokehidden, marktrusted, recursionlimit, slaves, share, target, or transfer}} test interp-1.10 {options for interp command} { list [catch {interp target} msg] $msg } {1 {wrong # args: should be "interp target path alias"}} # Part 1: Basic interpreter creation tests: test interp-2.1 {basic interpreter creation} { interp create a } a test interp-2.2 {basic interpreter creation} { catch {interp create} } 0 test interp-2.3 {basic interpreter creation} { catch {interp create -safe} } 0 test interp-2.4 {basic interpreter creation} { list [catch {interp create a} msg] $msg } {1 {interpreter named "a" already exists, cannot create}} test interp-2.5 {basic interpreter creation} { interp create b -safe } b test interp-2.6 {basic interpreter creation} { interp create d -safe } d test interp-2.7 {basic interpreter creation} { list [catch {interp create -froboz} msg] $msg } {1 {bad option "-froboz": must be -safe or --}} test interp-2.8 {basic interpreter creation} { interp create -- -froboz } -froboz test interp-2.9 {basic interpreter creation} { interp create -safe -- -froboz1 } -froboz1 test interp-2.10 {basic interpreter creation} { interp create {a x1} interp create {a x2} interp create {a x3} -safe } {a x3} test interp-2.11 {anonymous interps vs existing procs} { set x [interp create] regexp "interp(\[0-9]+)" $x dummy thenum interp delete $x proc interp$thenum {} {} set x [interp create] regexp "interp(\[0-9]+)" $x dummy anothernum expr $anothernum > $thenum } 1 test interp-2.12 {anonymous interps vs existing procs} { set x [interp create -safe] regexp "interp(\[0-9]+)" $x dummy thenum interp delete $x proc interp$thenum {} {} set x [interp create -safe] regexp "interp(\[0-9]+)" $x dummy anothernum expr $anothernum - $thenum } 1 test interp-2.13 {correct default when no $path arg is given} -body { interp create -- } -match regexp -result {interp[0-9]+} foreach i [interp slaves] { interp delete $i } # Part 2: Testing "interp slaves" and "interp exists" test interp-3.1 {testing interp exists and interp slaves} { interp slaves } "" test interp-3.2 {testing interp exists and interp slaves} { interp create a interp exists a } 1 test interp-3.3 {testing interp exists and interp slaves} { interp exists nonexistent } 0 test interp-3.4 {testing interp exists and interp slaves} { list [catch {interp slaves a b c} msg] $msg } {1 {wrong # args: should be "interp slaves ?path?"}} test interp-3.5 {testing interp exists and interp slaves} { list [catch {interp exists a b c} msg] $msg } {1 {wrong # args: should be "interp exists ?path?"}} test interp-3.6 {testing interp exists and interp slaves} { interp exists } 1 test interp-3.7 {testing interp exists and interp slaves} { interp slaves } a test interp-3.8 {testing interp exists and interp slaves} { list [catch {interp slaves a b c} msg] $msg } {1 {wrong # args: should be "interp slaves ?path?"}} test interp-3.9 {testing interp exists and interp slaves} { interp create {a a2} -safe expr {[lsearch [interp slaves a] a2] >= 0} } 1 test interp-3.10 {testing interp exists and interp slaves} { interp exists {a a2} } 1 # Part 3: Testing "interp delete" test interp-3.11 {testing interp delete} { interp delete } "" test interp-4.1 {testing interp delete} { catch {interp create a} interp delete a } "" test interp-4.2 {testing interp delete} { list [catch {interp delete nonexistent} msg] $msg } {1 {could not find interpreter "nonexistent"}} test interp-4.3 {testing interp delete} { list [catch {interp delete x y z} msg] $msg } {1 {could not find interpreter "x"}} test interp-4.4 {testing interp delete} { interp delete } "" test interp-4.5 {testing interp delete} { interp create a interp create {a x1} interp delete {a x1} expr {[lsearch [interp slaves a] x1] >= 0} } 0 test interp-4.6 {testing interp delete} { interp create c1 interp create c2 interp create c3 interp delete c1 c2 c3 } "" test interp-4.7 {testing interp delete} { interp create c1 interp create c2 list [catch {interp delete c1 c2 c3} msg] $msg } {1 {could not find interpreter "c3"}} test interp-4.8 {testing interp delete} { list [catch {interp delete {}} msg] $msg } {1 {cannot delete the current interpreter}} foreach i [interp slaves] { interp delete $i } # Part 4: Consistency checking - all nondeleted interpreters should be # there: test interp-5.1 {testing consistency} { interp slaves } "" test interp-5.2 {testing consistency} { interp exists a } 0 test interp-5.3 {testing consistency} { interp exists nonexistent } 0 # Recreate interpreter "a" interp create a # Part 5: Testing eval in interpreter object command and with interp command test interp-6.1 {testing eval} { a eval expr 3 + 5 } 8 test interp-6.2 {testing eval} { list [catch {a eval foo} msg] $msg } {1 {invalid command name "foo"}} test interp-6.3 {testing eval} { a eval {proc foo {} {expr 3 + 5}} a eval foo } 8 test interp-6.4 {testing eval} { interp eval a foo } 8 test interp-6.5 {testing eval} { interp create {a x2} interp eval {a x2} {proc frob {} {expr 4 * 9}} interp eval {a x2} frob } 36 test interp-6.6 {testing eval} { list [catch {interp eval {a x2} foo} msg] $msg } {1 {invalid command name "foo"}} # UTILITY PROCEDURE RUNNING IN MASTER INTERPRETER: proc in_master {args} { return [list seen in master: $args] } # Part 6: Testing basic alias creation test interp-7.1 {testing basic alias creation} { a alias foo in_master } foo test interp-7.2 {testing basic alias creation} { a alias bar in_master a1 a2 a3 } bar # Test 6.3 has been deleted. test interp-7.3 {testing basic alias creation} { a alias foo } in_master test interp-7.4 {testing basic alias creation} { a alias bar } {in_master a1 a2 a3} test interp-7.5 {testing basic alias creation} { lsort [a aliases] } {bar foo} test interp-7.6 {testing basic aliases arg checking} { list [catch {a aliases too many args} msg] $msg } {1 {wrong # args: should be "a aliases"}} # Part 7: testing basic alias invocation test interp-8.1 {testing basic alias invocation} { catch {interp create a} a alias foo in_master a eval foo s1 s2 s3 } {seen in master: {s1 s2 s3}} test interp-8.2 {testing basic alias invocation} { catch {interp create a} a alias bar in_master a1 a2 a3 a eval bar s1 s2 s3 } {seen in master: {a1 a2 a3 s1 s2 s3}} test interp-8.3 {testing basic alias invocation} { catch {interp create a} list [catch {a alias} msg] $msg } {1 {wrong # args: should be "a alias aliasName ?targetName? ?args..?"}} # Part 8: Testing aliases for non-existent or hidden targets test interp-9.1 {testing aliases for non-existent targets} { catch {interp create a} a alias zop nonexistent-command-in-master list [catch {a eval zop} msg] $msg } {1 {invalid command name "nonexistent-command-in-master"}} test interp-9.2 {testing aliases for non-existent targets} { catch {interp create a} a alias zop nonexistent-command-in-master proc nonexistent-command-in-master {} {return i_exist!} a eval zop } i_exist! test interp-9.3 {testing aliases for hidden commands} { catch {interp create a} a eval {proc p {} {return ENTER_A}} interp alias {} p a p set res {} lappend res [list [catch p msg] $msg] interp hide a p lappend res [list [catch p msg] $msg] rename p {} interp delete a set res } {{0 ENTER_A} {1 {invalid command name "p"}}} test interp-9.4 {testing aliases and namespace commands} { proc p {} {return GLOBAL} namespace eval tst { proc p {} {return NAMESPACE} } interp alias {} a {} p set res [a] lappend res [namespace eval tst a] rename p {} rename a {} namespace delete tst set res } {GLOBAL GLOBAL} if {[info command nonexistent-command-in-master] != ""} { rename nonexistent-command-in-master {} } # Part 9: Aliasing between interpreters test interp-10.1 {testing aliasing between interpreters} { catch {interp delete a} catch {interp delete b} interp create a interp create b interp alias a a_alias b b_alias 1 2 3 } a_alias test interp-10.2 {testing aliasing between interpreters} { catch {interp delete a} catch {interp delete b} interp create a interp create b b eval {proc b_alias {args} {return [list got $args]}} interp alias a a_alias b b_alias 1 2 3 a eval a_alias a b c } {got {1 2 3 a b c}} test interp-10.3 {testing aliasing between interpreters} { catch {interp delete a} catch {interp delete b} interp create a interp create b interp alias a a_alias b b_alias 1 2 3 list [catch {a eval a_alias a b c} msg] $msg } {1 {invalid command name "b_alias"}} test interp-10.4 {testing aliasing between interpreters} { catch {interp delete a} interp create a a alias a_alias puts a aliases } a_alias test interp-10.5 {testing aliasing between interpreters} { catch {interp delete a} catch {interp delete b} interp create a interp create b a alias a_alias puts interp alias a a_del b b_del interp delete b a aliases } a_alias test interp-10.6 {testing aliasing between interpreters} { catch {interp delete a} catch {interp delete b} interp create a interp create b interp alias a a_command b b_command a1 a2 a3 b alias b_command in_master b1 b2 b3 a eval a_command m1 m2 m3 } {seen in master: {b1 b2 b3 a1 a2 a3 m1 m2 m3}} test interp-10.7 {testing aliases between interpreters} { catch {interp delete a} interp create a interp alias "" foo a zoppo a eval {proc zoppo {x} {list $x $x $x}} set x [foo 33] a eval {rename zoppo {}} interp alias "" foo a {} equiv $x } {33 33 33} # Part 10: Testing "interp target" test interp-11.1 {testing interp target} { list [catch {interp target} msg] $msg } {1 {wrong # args: should be "interp target path alias"}} test interp-11.2 {testing interp target} { list [catch {interp target nosuchinterpreter foo} msg] $msg } {1 {could not find interpreter "nosuchinterpreter"}} test interp-11.3 {testing interp target} { catch {interp delete a} interp create a a alias boo no_command interp target a boo } "" test interp-11.4 {testing interp target} { catch {interp delete x1} interp create x1 x1 eval interp create x2 x1 eval x2 eval interp create x3 catch {interp delete y1} interp create y1 y1 eval interp create y2 y1 eval y2 eval interp create y3 interp alias {x1 x2 x3} xcommand {y1 y2 y3} ycommand interp target {x1 x2 x3} xcommand } {y1 y2 y3} test interp-11.5 {testing interp target} { catch {interp delete x1} interp create x1 interp create {x1 x2} interp create {x1 x2 x3} catch {interp delete y1} interp create y1 interp create {y1 y2} interp create {y1 y2 y3} interp alias {x1 x2 x3} xcommand {y1 y2 y3} ycommand list [catch {x1 eval {interp target {x2 x3} xcommand}} msg] $msg } {1 {target interpreter for alias "xcommand" in path "x2 x3" is not my descendant}} test interp-11.6 {testing interp target} { foreach a [interp aliases] { rename $a {} } list [catch {interp target {} foo} msg] $msg } {1 {alias "foo" in path "" not found}} test interp-11.7 {testing interp target} { catch {interp delete a} interp create a list [catch {interp target a foo} msg] $msg } {1 {alias "foo" in path "a" not found}} # Part 11: testing "interp issafe" test interp-12.1 {testing interp issafe} { interp issafe } 0 test interp-12.2 {testing interp issafe} { catch {interp delete a} interp create a interp issafe a } 0 test interp-12.3 {testing interp issafe} { catch {interp delete a} interp create a interp create {a x3} -safe interp issafe {a x3} } 1 test interp-12.4 {testing interp issafe} { catch {interp delete a} interp create a interp create {a x3} -safe interp create {a x3 foo} interp issafe {a x3 foo} } 1 # Part 12: testing interpreter object command "issafe" sub-command test interp-13.1 {testing foo issafe} { catch {interp delete a} interp create a a issafe } 0 test interp-13.2 {testing foo issafe} { catch {interp delete a} interp create a interp create {a x3} -safe a eval x3 issafe } 1 test interp-13.3 {testing foo issafe} { catch {interp delete a} interp create a interp create {a x3} -safe interp create {a x3 foo} a eval x3 eval foo issafe } 1 test interp-13.4 {testing issafe arg checking} { catch {interp create a} list [catch {a issafe too many args} msg] $msg } {1 {wrong # args: should be "a issafe"}} # part 14: testing interp aliases test interp-14.1 {testing interp aliases} { interp aliases } "" test interp-14.2 {testing interp aliases} { catch {interp delete a} interp create a a alias a1 puts a alias a2 puts a alias a3 puts lsort [interp aliases a] } {a1 a2 a3} test interp-14.3 {testing interp aliases} { catch {interp delete a} interp create a interp create {a x3} interp alias {a x3} froboz "" puts interp aliases {a x3} } froboz test interp-14.4 {testing interp alias - alias over master} { # SF Bug 641195 catch {interp delete a} interp create a list [catch {interp alias "" a a eval} msg] $msg [info commands a] } {1 {cannot define or rename alias "a": interpreter deleted} {}} # part 15: testing file sharing test interp-15.1 {testing file sharing} { catch {interp delete z} interp create z z eval close stdout list [catch {z eval puts hello} msg] $msg } {1 {can not find channel named "stdout"}} test interp-15.2 {testing file sharing} -body { catch {interp delete z} interp create z set f [open [makeFile {} file-15.2] w] interp share "" $f z z eval puts $f hello z eval close $f close $f } -cleanup { removeFile file-15.2 } -result "" test interp-15.3 {testing file sharing} { catch {interp delete xsafe} interp create xsafe -safe list [catch {xsafe eval puts hello} msg] $msg } {1 {can not find channel named "stdout"}} test interp-15.4 {testing file sharing} -body { catch {interp delete xsafe} interp create xsafe -safe set f [open [makeFile {} file-15.4] w] interp share "" $f xsafe xsafe eval puts $f hello xsafe eval close $f close $f } -cleanup { removeFile file-15.4 } -result "" test interp-15.5 {testing file sharing} { catch {interp delete xsafe} interp create xsafe -safe interp share "" stdout xsafe list [catch {xsafe eval gets stdout} msg] $msg } {1 {channel "stdout" wasn't opened for reading}} test interp-15.6 {testing file sharing} -body { catch {interp delete xsafe} interp create xsafe -safe set f [open [makeFile {} file-15.6] w] interp share "" $f xsafe set x [list [catch [list xsafe eval gets $f] msg] $msg] xsafe eval close $f close $f string compare [string tolower $x] \ [list 1 [format "channel \"%s\" wasn't opened for reading" $f]] } -cleanup { removeFile file-15.6 } -result 0 test interp-15.7 {testing file transferring} -body { catch {interp delete xsafe} interp create xsafe -safe set f [open [makeFile {} file-15.7] w] interp transfer "" $f xsafe xsafe eval puts $f hello xsafe eval close $f } -cleanup { removeFile file-15.7 } -result "" test interp-15.8 {testing file transferring} -body { catch {interp delete xsafe} interp create xsafe -safe set f [open [makeFile {} file-15.8] w] interp transfer "" $f xsafe xsafe eval close $f set x [list [catch {close $f} msg] $msg] string compare [string tolower $x] \ [list 1 [format "can not find channel named \"%s\"" $f]] } -cleanup { removeFile file-15.8 } -result 0 # # Torture tests for interpreter deletion order # proc kill {} {interp delete xxx} test interp-15.9 {testing deletion order} { catch {interp delete xxx} interp create xxx xxx alias kill kill list [catch {xxx eval kill} msg] $msg } {0 {}} test interp-16.1 {testing deletion order} { catch {interp delete xxx} interp create xxx interp create {xxx yyy} interp alias {xxx yyy} kill "" kill list [catch {interp eval {xxx yyy} kill} msg] $msg } {0 {}} test interp-16.2 {testing deletion order} { catch {interp delete xxx} interp create xxx interp create {xxx yyy} interp alias {xxx yyy} kill "" kill list [catch {xxx eval yyy eval kill} msg] $msg } {0 {}} test interp-16.3 {testing deletion order} { catch {interp delete xxx} interp create xxx interp create ddd xxx alias kill kill interp alias ddd kill xxx kill set x [ddd eval kill] interp delete ddd set x } "" test interp-16.4 {testing deletion order} { catch {interp delete xxx} interp create xxx interp create {xxx yyy} interp alias {xxx yyy} kill "" kill interp create ddd interp alias ddd kill {xxx yyy} kill set x [ddd eval kill] interp delete ddd set x } "" test interp-16.5 {testing deletion order, bgerror} { catch {interp delete xxx} interp create xxx xxx eval {proc bgerror {args} {exit}} xxx alias exit kill xxx proc kill {i} {interp delete $i} xxx eval after 100 expr a + b after 200 update interp exists xxx } 0 # # Alias loop prevention testing. # test interp-17.1 {alias loop prevention} { list [catch {interp alias {} a {} a} msg] $msg } {1 {cannot define or rename alias "a": would create a loop}} test interp-17.2 {alias loop prevention} { catch {interp delete x} interp create x x alias a loop list [catch {interp alias {} loop x a} msg] $msg } {1 {cannot define or rename alias "loop": would create a loop}} test interp-17.3 {alias loop prevention} { catch {interp delete x} interp create x interp alias x a x b list [catch {interp alias x b x a} msg] $msg } {1 {cannot define or rename alias "b": would create a loop}} test interp-17.4 {alias loop prevention} { catch {interp delete x} interp create x interp alias x b x a list [catch {x eval rename b a} msg] $msg } {1 {cannot define or rename alias "b": would create a loop}} test interp-17.5 {alias loop prevention} { catch {interp delete x} interp create x x alias z l1 interp alias {} l2 x z list [catch {rename l2 l1} msg] $msg } {1 {cannot define or rename alias "l2": would create a loop}} # # Test robustness of Tcl_DeleteInterp when applied to a slave interpreter. # If there are bugs in the implementation these tests are likely to expose # the bugs as a core dump. # if {[info commands testinterpdelete] == ""} { puts "This application hasn't been compiled with the \"testinterpdelete\"" puts "command, so I can't test slave delete calls" } else { test interp-18.1 {testing Tcl_DeleteInterp vs slaves} { list [catch {testinterpdelete} msg] $msg } {1 {wrong # args: should be "testinterpdelete path"}} test interp-18.2 {testing Tcl_DeleteInterp vs slaves} { catch {interp delete a} interp create a testinterpdelete a } "" test interp-18.3 {testing Tcl_DeleteInterp vs slaves} { catch {interp delete a} interp create a interp create {a b} testinterpdelete {a b} } "" test interp-18.4 {testing Tcl_DeleteInterp vs slaves} { catch {interp delete a} interp create a interp create {a b} testinterpdelete a } "" test interp-18.5 {testing Tcl_DeleteInterp vs slaves} { catch {interp delete a} interp create a interp create {a b} interp alias {a b} dodel {} dodel proc dodel {x} {testinterpdelete $x} list [catch {interp eval {a b} {dodel {a b}}} msg] $msg } {0 {}} test interp-18.6 {testing Tcl_DeleteInterp vs slaves} { catch {interp delete a} interp create a interp create {a b} interp alias {a b} dodel {} dodel proc dodel {x} {testinterpdelete $x} list [catch {interp eval {a b} {dodel a}} msg] $msg } {0 {}} test interp-18.7 {eval in deleted interp} { catch {interp delete a} interp create a a eval { proc dodel {} { delme dosomething else } proc dosomething args { puts "I should not have been called!!" } } a alias delme dela proc dela {} {interp delete a} list [catch {a eval dodel} msg] $msg } {1 {attempt to call eval in deleted interpreter}} test interp-18.8 {eval in deleted interp} { catch {interp delete a} interp create a a eval { interp create b b eval { proc dodel {} { dela } } proc foo {} { b eval dela dosomething else } proc dosomething args { puts "I should not have been called!!" } } interp alias {a b} dela {} dela proc dela {} {interp delete a} list [catch {a eval foo} msg] $msg } {1 {attempt to call eval in deleted interpreter}} } test interp-18.9 {eval in deleted interp, bug 495830} {knownBug} { interp create tst interp alias tst suicide {} interp delete tst list [catch {tst eval {suicide; set a 5}} msg] $msg } {1 {attempt to call eval in deleted interpreter}} test interp-18.10 {eval in deleted interp, bug 495830} { interp create tst interp alias tst suicide {} interp delete tst list [catch {tst eval {set set set; suicide; $set a 5}} msg] $msg } {1 {attempt to call eval in deleted interpreter}} # Test alias deletion test interp-19.1 {alias deletion} { catch {interp delete a} interp create a interp alias a foo a bar set s [interp alias a foo {}] interp delete a set s } {} test interp-19.2 {alias deletion} { catch {interp delete a} interp create a catch {interp alias a foo {}} msg interp delete a set msg } {alias "foo" not found} test interp-19.3 {alias deletion} { catch {interp delete a} interp create a interp alias a foo a bar interp eval a {rename foo zop} interp alias a foo a zop catch {interp eval a foo} msg interp delete a set msg } {invalid command name "zop"} test interp-19.4 {alias deletion} { catch {interp delete a} interp create a interp alias a foo a bar interp eval a {rename foo zop} catch {interp eval a foo} msg interp delete a set msg } {invalid command name "foo"} test interp-19.5 {alias deletion} { catch {interp delete a} interp create a interp eval a {proc bar {} {return 1}} interp alias a foo a bar interp eval a {rename foo zop} catch {interp eval a zop} msg interp delete a set msg } 1 test interp-19.6 {alias deletion} { catch {interp delete a} interp create a interp alias a foo a bar interp eval a {rename foo zop} interp alias a foo a zop set s [interp aliases a] interp delete a set s } foo test interp-19.7 {alias deletion, renaming} { catch {interp delete a} interp create a interp alias a foo a bar interp eval a rename foo blotz interp alias a foo {} set s [interp aliases a] interp delete a set s } {} test interp-19.8 {alias deletion, renaming} { catch {interp delete a} interp create a interp alias a foo a bar interp eval a rename foo blotz set l "" lappend l [interp aliases a] interp alias a foo {} lappend l [interp aliases a] interp delete a set l } {foo {}} test interp-19.9 {alias deletion, renaming} { catch {interp delete a} interp create a interp alias a foo a bar interp eval a rename foo blotz interp eval a {proc foo {} {expr 34 * 34}} interp alias a foo {} set l [interp eval a foo] interp delete a set l } 1156 test interp-20.1 {interp hide, interp expose and interp invokehidden} { catch {interp delete a} interp create a a eval {proc unknown {x args} {error "invalid command name \"$x\""}} a eval {proc foo {} {}} a hide foo catch {a eval foo something} msg interp delete a set msg } {invalid command name "foo"} test interp-20.2 {interp hide, interp expose and interp invokehidden} { catch {interp delete a} interp create a a eval {proc unknown {x args} {error "invalid command name \"$x\""}} a hide list set l "" lappend l [catch {a eval {list 1 2 3}} msg] lappend l $msg a expose list lappend l [catch {a eval {list 1 2 3}} msg] lappend l $msg interp delete a set l } {1 {invalid command name "list"} 0 {1 2 3}} test interp-20.3 {interp hide, interp expose and interp invokehidden} { catch {interp delete a} interp create a a eval {proc unknown {x args} {error "invalid command name \"$x\""}} a hide list set l "" lappend l [catch {a eval {list 1 2 3}} msg] lappend l $msg lappend l [catch {a invokehidden list 1 2 3} msg] lappend l $msg a expose list lappend l [catch {a eval {list 1 2 3}} msg] lappend l $msg interp delete a set l } {1 {invalid command name "list"} 0 {1 2 3} 0 {1 2 3}} test interp-20.4 {interp hide, interp expose and interp invokehidden -- passing {}} { catch {interp delete a} interp create a a eval {proc unknown {x args} {error "invalid command name \"$x\""}} a hide list set l "" lappend l [catch {a eval {list 1 2 3}} msg] lappend l $msg lappend l [catch {a invokehidden list {"" 1 2 3}} msg] lappend l $msg a expose list lappend l [catch {a eval {list 1 2 3}} msg] lappend l $msg interp delete a set l } {1 {invalid command name "list"} 0 {{"" 1 2 3}} 0 {1 2 3}} test interp-20.5 {interp hide, interp expose and interp invokehidden -- passing {}} { catch {interp delete a} interp create a a eval {proc unknown {x args} {error "invalid command name \"$x\""}} a hide list set l "" lappend l [catch {a eval {list 1 2 3}} msg] lappend l $msg lappend l [catch {a invokehidden list {{} 1 2 3}} msg] lappend l $msg a expose list lappend l [catch {a eval {list 1 2 3}} msg] lappend l $msg interp delete a set l } {1 {invalid command name "list"} 0 {{{} 1 2 3}} 0 {1 2 3}} test interp-20.6 {interp invokehidden -- eval args} { catch {interp delete a} interp create a a hide list set l "" set z 45 lappend l [catch {a invokehidden list $z 1 2 3} msg] lappend l $msg a expose list lappend l [catch {a eval list $z 1 2 3} msg] lappend l $msg interp delete a set l } {0 {45 1 2 3} 0 {45 1 2 3}} test interp-20.7 {interp invokehidden vs variable eval} { catch {interp delete a} interp create a a hide list set z 45 set l "" lappend l [catch {a invokehidden list {$z a b c}} msg] lappend l $msg interp delete a set l } {0 {{$z a b c}}} test interp-20.8 {interp invokehidden vs variable eval} { catch {interp delete a} interp create a a hide list a eval set z 89 set z 45 set l "" lappend l [catch {a invokehidden list {$z a b c}} msg] lappend l $msg interp delete a set l } {0 {{$z a b c}}} test interp-20.9 {interp invokehidden vs variable eval} { catch {interp delete a} interp create a a hide list a eval set z 89 set z 45 set l "" lappend l [catch {a invokehidden list $z {$z a b c}} msg] lappend l $msg interp delete a set l } {0 {45 {$z a b c}}} test interp-20.10 {interp hide, interp expose and interp invokehidden} { catch {interp delete a} interp create a a eval {proc unknown {x args} {error "invalid command name \"$x\""}} a eval {proc foo {} {}} interp hide a foo catch {interp eval a foo something} msg interp delete a set msg } {invalid command name "foo"} test interp-20.11 {interp hide, interp expose and interp invokehidden} { catch {interp delete a} interp create a a eval {proc unknown {x args} {error "invalid command name \"$x\""}} interp hide a list set l "" lappend l [catch {interp eval a {list 1 2 3}} msg] lappend l $msg interp expose a list lappend l [catch {interp eval a {list 1 2 3}} msg] lappend l $msg interp delete a set l } {1 {invalid command name "list"} 0 {1 2 3}} test interp-20.12 {interp hide, interp expose and interp invokehidden} { catch {interp delete a} interp create a a eval {proc unknown {x args} {error "invalid command name \"$x\""}} interp hide a list set l "" lappend l [catch {interp eval a {list 1 2 3}} msg] lappend l $msg lappend l [catch {interp invokehidden a list 1 2 3} msg] lappend l $msg interp expose a list lappend l [catch {interp eval a {list 1 2 3}} msg] lappend l $msg interp delete a set l } {1 {invalid command name "list"} 0 {1 2 3} 0 {1 2 3}} test interp-20.13 {interp hide, interp expose, interp invokehidden -- passing {}} { catch {interp delete a} interp create a a eval {proc unknown {x args} {error "invalid command name \"$x\""}} interp hide a list set l "" lappend l [catch {interp eval a {list 1 2 3}} msg] lappend l $msg lappend l [catch {interp invokehidden a list {"" 1 2 3}} msg] lappend l $msg interp expose a list lappend l [catch {interp eval a {list 1 2 3}} msg] lappend l $msg interp delete a set l } {1 {invalid command name "list"} 0 {{"" 1 2 3}} 0 {1 2 3}} test interp-20.14 {interp hide, interp expose, interp invokehidden -- passing {}} { catch {interp delete a} interp create a a eval {proc unknown {x args} {error "invalid command name \"$x\""}} interp hide a list set l "" lappend l [catch {interp eval a {list 1 2 3}} msg] lappend l $msg lappend l [catch {interp invokehidden a list {{} 1 2 3}} msg] lappend l $msg interp expose a list lappend l [catch {a eval {list 1 2 3}} msg] lappend l $msg interp delete a set l } {1 {invalid command name "list"} 0 {{{} 1 2 3}} 0 {1 2 3}} test interp-20.15 {interp invokehidden -- eval args} { catch {interp delete a} interp create a interp hide a list set l "" set z 45 lappend l [catch {interp invokehidden a list $z 1 2 3} msg] lappend l $msg a expose list lappend l [catch {interp eval a list $z 1 2 3} msg] lappend l $msg interp delete a set l } {0 {45 1 2 3} 0 {45 1 2 3}} test interp-20.16 {interp invokehidden vs variable eval} { catch {interp delete a} interp create a interp hide a list set z 45 set l "" lappend l [catch {interp invokehidden a list {$z a b c}} msg] lappend l $msg interp delete a set l } {0 {{$z a b c}}} test interp-20.17 {interp invokehidden vs variable eval} { catch {interp delete a} interp create a interp hide a list a eval set z 89 set z 45 set l "" lappend l [catch {interp invokehidden a list {$z a b c}} msg] lappend l $msg interp delete a set l } {0 {{$z a b c}}} test interp-20.18 {interp invokehidden vs variable eval} { catch {interp delete a} interp create a interp hide a list a eval set z 89 set z 45 set l "" lappend l [catch {interp invokehidden a list $z {$z a b c}} msg] lappend l $msg interp delete a set l } {0 {45 {$z a b c}}} test interp-20.19 {interp invokehidden vs nested commands} { catch {interp delete a} interp create a a hide list set l [a invokehidden list {[list x y z] f g h} z] interp delete a set l } {{[list x y z] f g h} z} test interp-20.20 {interp invokehidden vs nested commands} { catch {interp delete a} interp create a a hide list set l [interp invokehidden a list {[list x y z] f g h} z] interp delete a set l } {{[list x y z] f g h} z} test interp-20.21 {interp hide vs safety} { catch {interp delete a} interp create a -safe set l "" lappend l [catch {a hide list} msg] lappend l $msg interp delete a set l } {0 {}} test interp-20.22 {interp hide vs safety} { catch {interp delete a} interp create a -safe set l "" lappend l [catch {interp hide a list} msg] lappend l $msg interp delete a set l } {0 {}} test interp-20.23 {interp hide vs safety} { catch {interp delete a} interp create a -safe set l "" lappend l [catch {a eval {interp hide {} list}} msg] lappend l $msg interp delete a set l } {1 {permission denied: safe interpreter cannot hide commands}} test interp-20.24 {interp hide vs safety} { catch {interp delete a} interp create a -safe interp create {a b} set l "" lappend l [catch {a eval {interp hide b list}} msg] lappend l $msg interp delete a set l } {1 {permission denied: safe interpreter cannot hide commands}} test interp-20.25 {interp hide vs safety} { catch {interp delete a} interp create a -safe interp create {a b} set l "" lappend l [catch {interp hide {a b} list} msg] lappend l $msg interp delete a set l } {0 {}} test interp-20.26 {interp expoose vs safety} { catch {interp delete a} interp create a -safe set l "" lappend l [catch {a hide list} msg] lappend l $msg lappend l [catch {a expose list} msg] lappend l $msg interp delete a set l } {0 {} 0 {}} test interp-20.27 {interp expose vs safety} { catch {interp delete a} interp create a -safe set l "" lappend l [catch {interp hide a list} msg] lappend l $msg lappend l [catch {interp expose a list} msg] lappend l $msg interp delete a set l } {0 {} 0 {}} test interp-20.28 {interp expose vs safety} { catch {interp delete a} interp create a -safe set l "" lappend l [catch {a hide list} msg] lappend l $msg lappend l [catch {a eval {interp expose {} list}} msg] lappend l $msg interp delete a set l } {0 {} 1 {permission denied: safe interpreter cannot expose commands}} test interp-20.29 {interp expose vs safety} { catch {interp delete a} interp create a -safe set l "" lappend l [catch {interp hide a list} msg] lappend l $msg lappend l [catch {a eval {interp expose {} list}} msg] lappend l $msg interp delete a set l } {0 {} 1 {permission denied: safe interpreter cannot expose commands}} test interp-20.30 {interp expose vs safety} { catch {interp delete a} interp create a -safe interp create {a b} set l "" lappend l [catch {interp hide {a b} list} msg] lappend l $msg lappend l [catch {a eval {interp expose b list}} msg] lappend l $msg interp delete a set l } {0 {} 1 {permission denied: safe interpreter cannot expose commands}} test interp-20.31 {interp expose vs safety} { catch {interp delete a} interp create a -safe interp create {a b} set l "" lappend l [catch {interp hide {a b} list} msg] lappend l $msg lappend l [catch {interp expose {a b} list} msg] lappend l $msg interp delete a set l } {0 {} 0 {}} test interp-20.32 {interp invokehidden vs safety} { catch {interp delete a} interp create a -safe interp hide a list set l "" lappend l [catch {a eval {interp invokehidden {} list a b c}} msg] lappend l $msg interp delete a set l } {1 {not allowed to invoke hidden commands from safe interpreter}} test interp-20.33 {interp invokehidden vs safety} { catch {interp delete a} interp create a -safe interp hide a list set l "" lappend l [catch {a eval {interp invokehidden {} list a b c}} msg] lappend l $msg lappend l [catch {a invokehidden list a b c} msg] lappend l $msg interp delete a set l } {1 {not allowed to invoke hidden commands from safe interpreter}\ 0 {a b c}} test interp-20.34 {interp invokehidden vs safety} { catch {interp delete a} interp create a -safe interp create {a b} interp hide {a b} list set l "" lappend l [catch {a eval {interp invokehidden b list a b c}} msg] lappend l $msg lappend l [catch {interp invokehidden {a b} list a b c} msg] lappend l $msg interp delete a set l } {1 {not allowed to invoke hidden commands from safe interpreter}\ 0 {a b c}} test interp-20.35 {invokehidden at local level} { catch {interp delete a} interp create a a eval { proc p1 {} { set z 90 a1 set z } proc h1 {} { upvar z z set z 91 } } a hide h1 a alias a1 a1 proc a1 {} { interp invokehidden a h1 } set r [interp eval a p1] interp delete a set r } 91 test interp-20.36 {invokehidden at local level} { catch {interp delete a} interp create a a eval { set z 90 proc p1 {} { global z a1 set z } proc h1 {} { upvar z z set z 91 } } a hide h1 a alias a1 a1 proc a1 {} { interp invokehidden a h1 } set r [interp eval a p1] interp delete a set r } 91 test interp-20.37 {invokehidden at local level} { catch {interp delete a} interp create a a eval { proc p1 {} { a1 set z } proc h1 {} { upvar z z set z 91 } } a hide h1 a alias a1 a1 proc a1 {} { interp invokehidden a h1 } set r [interp eval a p1] interp delete a set r } 91 test interp-20.38 {invokehidden at global level} { catch {interp delete a} interp create a a eval { proc p1 {} { a1 set z } proc h1 {} { upvar z z set z 91 } } a hide h1 a alias a1 a1 proc a1 {} { interp invokehidden a -global h1 } set r [catch {interp eval a p1} msg] interp delete a list $r $msg } {1 {can't read "z": no such variable}} test interp-20.39 {invokehidden at global level} { catch {interp delete a} interp create a a eval { proc p1 {} { global z a1 set z } proc h1 {} { upvar z z set z 91 } } a hide h1 a alias a1 a1 proc a1 {} { interp invokehidden a -global h1 } set r [catch {interp eval a p1} msg] interp delete a list $r $msg } {0 91} test interp-20.40 {safe, invokehidden at local level} { catch {interp delete a} interp create a -safe a eval { proc p1 {} { set z 90 a1 set z } proc h1 {} { upvar z z set z 91 } } a hide h1 a alias a1 a1 proc a1 {} { interp invokehidden a h1 } set r [interp eval a p1] interp delete a set r } 91 test interp-20.41 {safe, invokehidden at local level} { catch {interp delete a} interp create a -safe a eval { set z 90 proc p1 {} { global z a1 set z } proc h1 {} { upvar z z set z 91 } } a hide h1 a alias a1 a1 proc a1 {} { interp invokehidden a h1 } set r [interp eval a p1] interp delete a set r } 91 test interp-20.42 {safe, invokehidden at local level} { catch {interp delete a} interp create a -safe a eval { proc p1 {} { a1 set z } proc h1 {} { upvar z z set z 91 } } a hide h1 a alias a1 a1 proc a1 {} { interp invokehidden a h1 } set r [interp eval a p1] interp delete a set r } 91 test interp-20.43 {invokehidden at global level} { catch {interp delete a} interp create a a eval { proc p1 {} { a1 set z } proc h1 {} { upvar z z set z 91 } } a hide h1 a alias a1 a1 proc a1 {} { interp invokehidden a -global h1 } set r [catch {interp eval a p1} msg] interp delete a list $r $msg } {1 {can't read "z": no such variable}} test interp-20.44 {invokehidden at global level} { catch {interp delete a} interp create a a eval { proc p1 {} { global z a1 set z } proc h1 {} { upvar z z set z 91 } } a hide h1 a alias a1 a1 proc a1 {} { interp invokehidden a -global h1 } set r [catch {interp eval a p1} msg] interp delete a list $r $msg } {0 91} test interp-20.45 {interp hide vs namespaces} { catch {interp delete a} interp create a a eval { namespace eval foo {} proc foo::x {} {} } set l [list [catch {interp hide a foo::x} msg] $msg] interp delete a set l } {1 {cannot use namespace qualifiers in hidden command token (rename)}} test interp-20.46 {interp hide vs namespaces} { catch {interp delete a} interp create a a eval { namespace eval foo {} proc foo::x {} {} } set l [list [catch {interp hide a foo::x x} msg] $msg] interp delete a set l } {1 {can only hide global namespace commands (use rename then hide)}} test interp-20.47 {interp hide vs namespaces} { catch {interp delete a} interp create a a eval { proc x {} {} } set l [list [catch {interp hide a x foo::x} msg] $msg] interp delete a set l } {1 {cannot use namespace qualifiers in hidden command token (rename)}} test interp-20.48 {interp hide vs namespaces} { catch {interp delete a} interp create a a eval { namespace eval foo {} proc foo::x {} {} } set l [list [catch {interp hide a foo::x bar::x} msg] $msg] interp delete a set l } {1 {cannot use namespace qualifiers in hidden command token (rename)}} test interp-21.1 {interp hidden} { interp hidden {} } "" test interp-21.2 {interp hidden} { interp hidden } "" test interp-21.3 {interp hidden vs interp hide, interp expose} { set l "" lappend l [interp hidden] interp hide {} pwd lappend l [interp hidden] interp expose {} pwd lappend l [interp hidden] set l } {{} pwd {}} test interp-21.4 {interp hidden} { catch {interp delete a} interp create a set l [interp hidden a] interp delete a set l } "" test interp-21.5 {interp hidden} { catch {interp delete a} interp create -safe a set l [lsort [interp hidden a]] interp delete a set l } $hidden_cmds test interp-21.6 {interp hidden vs interp hide, interp expose} { catch {interp delete a} interp create a set l "" lappend l [interp hidden a] interp hide a pwd lappend l [interp hidden a] interp expose a pwd lappend l [interp hidden a] interp delete a set l } {{} pwd {}} test interp-21.7 {interp hidden} { catch {interp delete a} interp create a set l [a hidden] interp delete a set l } "" test interp-21.8 {interp hidden} { catch {interp delete a} interp create a -safe set l [lsort [a hidden]] interp delete a set l } $hidden_cmds test interp-21.9 {interp hidden vs interp hide, interp expose} { catch {interp delete a} interp create a set l "" lappend l [a hidden] a hide pwd lappend l [a hidden] a expose pwd lappend l [a hidden] interp delete a set l } {{} pwd {}} test interp-22.1 {testing interp marktrusted} { catch {interp delete a} interp create a set l "" lappend l [a issafe] lappend l [a marktrusted] lappend l [a issafe] interp delete a set l } {0 {} 0} test interp-22.2 {testing interp marktrusted} { catch {interp delete a} interp create a set l "" lappend l [interp issafe a] lappend l [interp marktrusted a] lappend l [interp issafe a] interp delete a set l } {0 {} 0} test interp-22.3 {testing interp marktrusted} { catch {interp delete a} interp create a -safe set l "" lappend l [a issafe] lappend l [a marktrusted] lappend l [a issafe] interp delete a set l } {1 {} 0} test interp-22.4 {testing interp marktrusted} { catch {interp delete a} interp create a -safe set l "" lappend l [interp issafe a] lappend l [interp marktrusted a] lappend l [interp issafe a] interp delete a set l } {1 {} 0} test interp-22.5 {testing interp marktrusted} { catch {interp delete a} interp create a -safe interp create {a b} catch {a eval {interp marktrusted b}} msg interp delete a set msg } {permission denied: safe interpreter cannot mark trusted} test interp-22.6 {testing interp marktrusted} { catch {interp delete a} interp create a -safe interp create {a b} catch {a eval {b marktrusted}} msg interp delete a set msg } {permission denied: safe interpreter cannot mark trusted} test interp-22.7 {testing interp marktrusted} { catch {interp delete a} interp create a -safe set l "" lappend l [interp issafe a] interp marktrusted a interp create {a b} lappend l [interp issafe a] lappend l [interp issafe {a b}] interp delete a set l } {1 0 0} test interp-22.8 {testing interp marktrusted} { catch {interp delete a} interp create a -safe set l "" lappend l [interp issafe a] interp create {a b} lappend l [interp issafe {a b}] interp marktrusted a interp create {a c} lappend l [interp issafe a] lappend l [interp issafe {a c}] interp delete a set l } {1 1 0 0} test interp-22.9 {testing interp marktrusted} { catch {interp delete a} interp create a -safe set l "" lappend l [interp issafe a] interp create {a b} lappend l [interp issafe {a b}] interp marktrusted {a b} lappend l [interp issafe a] lappend l [interp issafe {a b}] interp create {a b c} lappend l [interp issafe {a b c}] interp delete a set l } {1 1 1 0 0} test interp-23.1 {testing hiding vs aliases} { catch {interp delete a} interp create a set l "" lappend l [interp hidden a] a alias bar bar lappend l [interp aliases a] lappend l [interp hidden a] a hide bar lappend l [interp aliases a] lappend l [interp hidden a] a alias bar {} lappend l [interp aliases a] lappend l [interp hidden a] interp delete a set l } {{} bar {} bar bar {} {}} test interp-23.2 {testing hiding vs aliases} {unixOrPc} { catch {interp delete a} interp create a -safe set l "" lappend l [lsort [interp hidden a]] a alias bar bar lappend l [interp aliases a] lappend l [lsort [interp hidden a]] a hide bar lappend l [interp aliases a] lappend l [lsort [interp hidden a]] a alias bar {} lappend l [interp aliases a] lappend l [lsort [interp hidden a]] interp delete a set l } {{cd encoding exec exit fconfigure file glob load open pwd socket source} bar {cd encoding exec exit fconfigure file glob load open pwd socket source} bar {bar cd encoding exec exit fconfigure file glob load open pwd socket source} {} {cd encoding exec exit fconfigure file glob load open pwd socket source}} test interp-24.1 {result resetting on error} { catch {interp delete a} interp create a proc foo args {error $args} interp alias a foo {} foo set l [interp eval a { set l {} lappend l [catch {foo 1 2 3} msg] lappend l $msg lappend l [catch {foo 3 4 5} msg] lappend l $msg set l }] interp delete a set l } {1 {1 2 3} 1 {3 4 5}} test interp-24.2 {result resetting on error} { catch {interp delete a} interp create a -safe proc foo args {error $args} interp alias a foo {} foo set l [interp eval a { set l {} lappend l [catch {foo 1 2 3} msg] lappend l $msg lappend l [catch {foo 3 4 5} msg] lappend l $msg set l }] interp delete a set l } {1 {1 2 3} 1 {3 4 5}} test interp-24.3 {result resetting on error} { catch {interp delete a} interp create a interp create {a b} interp eval a { proc foo args {error $args} } interp alias {a b} foo a foo set l [interp eval {a b} { set l {} lappend l [catch {foo 1 2 3} msg] lappend l $msg lappend l [catch {foo 3 4 5} msg] lappend l $msg set l }] interp delete a set l } {1 {1 2 3} 1 {3 4 5}} test interp-24.4 {result resetting on error} { catch {interp delete a} interp create a -safe interp create {a b} interp eval a { proc foo args {error $args} } interp alias {a b} foo a foo set l [interp eval {a b} { set l {} lappend l [catch {foo 1 2 3} msg] lappend l $msg lappend l [catch {foo 3 4 5} msg] lappend l $msg set l }] interp delete a set l } {1 {1 2 3} 1 {3 4 5}} test interp-24.5 {result resetting on error} { catch {interp delete a} catch {interp delete b} interp create a interp create b interp eval a { proc foo args {error $args} } interp alias b foo a foo set l [interp eval b { set l {} lappend l [catch {foo 1 2 3} msg] lappend l $msg lappend l [catch {foo 3 4 5} msg] lappend l $msg set l }] interp delete a set l } {1 {1 2 3} 1 {3 4 5}} test interp-24.6 {result resetting on error} { catch {interp delete a} catch {interp delete b} interp create a -safe interp create b -safe interp eval a { proc foo args {error $args} } interp alias b foo a foo set l [interp eval b { set l {} lappend l [catch {foo 1 2 3} msg] lappend l $msg lappend l [catch {foo 3 4 5} msg] lappend l $msg set l }] interp delete a set l } {1 {1 2 3} 1 {3 4 5}} test interp-24.7 {result resetting on error} { catch {interp delete a} interp create a interp eval a { proc foo args {error $args} } set l {} lappend l [catch {interp eval a foo 1 2 3} msg] lappend l $msg lappend l [catch {interp eval a foo 3 4 5} msg] lappend l $msg interp delete a set l } {1 {1 2 3} 1 {3 4 5}} test interp-24.8 {result resetting on error} { catch {interp delete a} interp create a -safe interp eval a { proc foo args {error $args} } set l {} lappend l [catch {interp eval a foo 1 2 3} msg] lappend l $msg lappend l [catch {interp eval a foo 3 4 5} msg] lappend l $msg interp delete a set l } {1 {1 2 3} 1 {3 4 5}} test interp-24.9 {result resetting on error} { catch {interp delete a} interp create a interp create {a b} interp eval {a b} { proc foo args {error $args} } interp eval a { proc foo args { eval interp eval b foo $args } } set l {} lappend l [catch {interp eval a foo 1 2 3} msg] lappend l $msg lappend l [catch {interp eval a foo 3 4 5} msg] lappend l $msg interp delete a set l } {1 {1 2 3} 1 {3 4 5}} test interp-24.10 {result resetting on error} { catch {interp delete a} interp create a -safe interp create {a b} interp eval {a b} { proc foo args {error $args} } interp eval a { proc foo args { eval interp eval b foo $args } } set l {} lappend l [catch {interp eval a foo 1 2 3} msg] lappend l $msg lappend l [catch {interp eval a foo 3 4 5} msg] lappend l $msg interp delete a set l } {1 {1 2 3} 1 {3 4 5}} test interp-24.11 {result resetting on error} { catch {interp delete a} interp create a interp create {a b} interp eval {a b} { proc foo args {error $args} } interp eval a { proc foo args { set l {} lappend l [catch {eval interp eval b foo $args} msg] lappend l $msg lappend l [catch {eval interp eval b foo $args} msg] lappend l $msg set l } } set l [interp eval a foo 1 2 3] interp delete a set l } {1 {1 2 3} 1 {1 2 3}} test interp-24.12 {result resetting on error} { catch {interp delete a} interp create a -safe interp create {a b} interp eval {a b} { proc foo args {error $args} } interp eval a { proc foo args { set l {} lappend l [catch {eval interp eval b foo $args} msg] lappend l $msg lappend l [catch {eval interp eval b foo $args} msg] lappend l $msg set l } } set l [interp eval a foo 1 2 3] interp delete a set l } {1 {1 2 3} 1 {1 2 3}} unset hidden_cmds test interp-25.1 {testing aliasing of string commands} { catch {interp delete a} interp create a a alias exec foo ;# Relies on exec being a string command! interp delete a } "" # # Interps result transmission # test interp-26.1 {result code transmission : interp eval direct} { # Test that all the possibles error codes from Tcl get passed up # from the slave interp's context to the master, even though the # slave nominally thinks the command is running at the root level. catch {interp delete a} interp create a set res {} # use a for so if a return -code break 'escapes' we would notice for {set code -1} {$code<=5} {incr code} { lappend res [catch {interp eval a return -code $code} msg] } interp delete a set res } {-1 0 1 2 3 4 5} test interp-26.2 {result code transmission : interp eval indirect} { # retcode == 2 == return is special catch {interp delete a} interp create a interp eval a {proc retcode {code} {return -code $code ret$code}} set res {} # use a for so if a return -code break 'escapes' we would notice for {set code -1} {$code<=5} {incr code} { lappend res [catch {interp eval a retcode $code} msg] $msg } interp delete a set res } {-1 ret-1 0 ret0 1 ret1 0 ret2 3 ret3 4 ret4 5 ret5} test interp-26.3 {result code transmission : aliases} { # Test that all the possibles error codes from Tcl get passed up # from the slave interp's context to the master, even though the # slave nominally thinks the command is running at the root level. catch {interp delete a} interp create a set res {} proc MyTestAlias {code} { return -code $code ret$code } interp alias a Test {} MyTestAlias for {set code -1} {$code<=5} {incr code} { lappend res [interp eval a [list catch [list Test $code] msg]] } interp delete a set res } {-1 0 1 2 3 4 5} test interp-26.4 {result code transmission: invoke hidden direct--bug 1637} \ {knownBug} { # The known bug is that code 2 is returned, not the -code argument catch {interp delete a} interp create a set res {} interp hide a return for {set code -1} {$code<=5} {incr code} { lappend res [catch {interp invokehidden a return -code $code ret$code}] } interp delete a set res } {-1 0 1 2 3 4 5} test interp-26.5 {result code transmission: invoke hidden indirect--bug 1637} \ {knownBug} { # The known bug is that the break and continue should raise errors # that they are used outside a loop. catch {interp delete a} interp create a set res {} interp eval a {proc retcode {code} {return -code $code ret$code}} interp hide a retcode for {set code -1} {$code<=5} {incr code} { lappend res [catch {interp invokehidden a retcode $code} msg] $msg } interp delete a set res } {-1 ret-1 0 ret0 1 ret1 0 ret2 3 ret3 4 ret4 5 ret5} test interp-26.6 {result code transmission: all combined--bug 1637} \ {knownBug} { # Test that all the possibles error codes from Tcl get passed # In both directions. This doesn't work. set interp [interp create]; proc MyTestAlias {interp args} { global aliasTrace; lappend aliasTrace $args; eval interp invokehidden [list $interp] $args } foreach c {return} { interp hide $interp $c; interp alias $interp $c {} MyTestAlias $interp $c; } interp eval $interp {proc ret {code} {return -code $code ret$code}} set res {} set aliasTrace {} for {set code -1} {$code<=5} {incr code} { lappend res [catch {interp eval $interp ret $code} msg] $msg } interp delete $interp; set res } {-1 ret-1 0 ret0 1 ret1 0 ret2 3 ret3 4 ret4 5 ret5} # Some tests might need to be added to check for difference between # toplevel and non toplevel evals. # End of return code transmission section test interp-26.7 {errorInfo transmission: regular interps} { set interp [interp create]; proc MyError {secret} { return -code error "msg" } proc MyTestAlias {interp args} { MyError "some secret" } interp alias $interp test {} MyTestAlias $interp; set res [interp eval $interp {catch test;set errorInfo}] interp delete $interp; set res } {msg while executing "MyError "some secret"" (procedure "MyTestAlias" line 2) invoked from within "test"} test interp-26.8 {errorInfo transmission: safe interps--bug 1637} {knownBug} { # this test fails because the errorInfo is fully transmitted # whether the interp is safe or not. The errorInfo should never # report data from the master interpreter because it could # contain sensitive information. set interp [interp create -safe]; proc MyError {secret} { return -code error "msg" } proc MyTestAlias {interp args} { MyError "some secret" } interp alias $interp test {} MyTestAlias $interp; set res [interp eval $interp {catch test;set errorInfo}] interp delete $interp; set res } {msg while executing "test"} # Interps & Namespaces test interp-27.1 {interp aliases & namespaces} { set i [interp create]; set aliasTrace {}; proc tstAlias {args} { global aliasTrace; lappend aliasTrace [list [namespace current] $args]; } $i alias foo::bar tstAlias foo::bar; $i eval foo::bar test interp delete $i set aliasTrace; } {{:: {foo::bar test}}} test interp-27.2 {interp aliases & namespaces} { set i [interp create]; set aliasTrace {}; proc tstAlias {args} { global aliasTrace; lappend aliasTrace [list [namespace current] $args]; } $i alias foo::bar tstAlias foo::bar; $i eval namespace eval foo {bar test} interp delete $i set aliasTrace; } {{:: {foo::bar test}}} test interp-27.3 {interp aliases & namespaces} { set i [interp create]; set aliasTrace {}; proc tstAlias {args} { global aliasTrace; lappend aliasTrace [list [namespace current] $args]; } interp eval $i {namespace eval foo {proc bar {} {error "bar called"}}} interp alias $i foo::bar {} tstAlias foo::bar; interp eval $i {namespace eval foo {bar test}} interp delete $i set aliasTrace; } {{:: {foo::bar test}}} test interp-27.4 {interp aliases & namespaces} { set i [interp create]; namespace eval foo2 { variable aliasTrace {}; proc bar {args} { variable aliasTrace; lappend aliasTrace [list [namespace current] $args]; } } $i alias foo::bar foo2::bar foo::bar; $i eval namespace eval foo {bar test} set r $foo2::aliasTrace; namespace delete foo2; set r } {{::foo2 {foo::bar test}}} # the following tests are commented out while we don't support # hiding in namespaces # test interp-27.5 {interp hidden & namespaces} { # set i [interp create]; # interp eval $i { # namespace eval foo { # proc bar {args} { # return "bar called ([namespace current]) ($args)" # } # } # } # set res [list [interp eval $i {namespace eval foo {bar test1}}]] # interp hide $i foo::bar; # lappend res [list [catch {interp eval $i {namespace eval foo {bar test2}}} msg] $msg] # interp delete $i; # set res; #} {{bar called (::foo) (test1)} {1 {invalid command name "bar"}}} # test interp-27.6 {interp hidden & aliases & namespaces} { # set i [interp create]; # set v root-master; # namespace eval foo { # variable v foo-master; # proc bar {interp args} { # variable v; # list "master bar called ($v) ([namespace current]) ($args)"\ # [interp invokehidden $interp foo::bar $args]; # } # } # interp eval $i { # namespace eval foo { # namespace export * # variable v foo-slave; # proc bar {args} { # variable v; # return "slave bar called ($v) ([namespace current]) ($args)" # } # } # } # set res [list [interp eval $i {namespace eval foo {bar test1}}]] # $i hide foo::bar; # $i alias foo::bar foo::bar $i; # set res [concat $res [interp eval $i { # set v root-slave; # namespace eval test { # variable v foo-test; # namespace import ::foo::*; # bar test2 # } # }]] # namespace delete foo; # interp delete $i; # set res # } {{slave bar called (foo-slave) (::foo) (test1)} {master bar called (foo-master) (::foo) (test2)} {slave bar called (foo-slave) (::foo) (test2)}} # test interp-27.7 {interp hidden & aliases & imports & namespaces} { # set i [interp create]; # set v root-master; # namespace eval mfoo { # variable v foo-master; # proc bar {interp args} { # variable v; # list "master bar called ($v) ([namespace current]) ($args)"\ # [interp invokehidden $interp test::bar $args]; # } # } # interp eval $i { # namespace eval foo { # namespace export * # variable v foo-slave; # proc bar {args} { # variable v; # return "slave bar called ($v) ([info level 0]) ([uplevel namespace current]) ([namespace current]) ($args)" # } # } # set v root-slave; # namespace eval test { # variable v foo-test; # namespace import ::foo::*; # } # } # set res [list [interp eval $i {namespace eval test {bar test1}}]] # $i hide test::bar; # $i alias test::bar mfoo::bar $i; # set res [concat $res [interp eval $i {test::bar test2}]]; # namespace delete mfoo; # interp delete $i; # set res # } {{slave bar called (foo-slave) (bar test1) (::tcltest) (::foo) (test1)} {master bar called (foo-master) (::mfoo) (test2)} {slave bar called (foo-slave) (test::bar test2) (::) (::foo) (test2)}} #test interp-27.8 {hiding, namespaces and integrity} { # namespace eval foo { # variable v 3; # proc bar {} {variable v; set v} # # next command would currently generate an unknown command "bar" error. # interp hide {} bar; # } # namespace delete foo; # list [catch {interp invokehidden {} foo} msg] $msg; #} {1 {invalid hidden command name "foo"}} test interp-28.1 {getting fooled by slave's namespace ?} { set i [interp create -safe]; proc master {interp args} {interp hide $interp list} $i alias master master $i; set r [interp eval $i { namespace eval foo { proc list {args} { return "dummy foo::list"; } master; } info commands list }] interp delete $i; set r } {} # Part 29: recursion limit # 29.1.* Argument checking # 29.2.* Reading and setting the recursion limit # 29.3.* Does the recursion limit work? # 29.4.* Recursion limit inheritance by sub-interpreters # 29.5.* Confirming the recursionlimit command does not affect the parent # 29.6.* Safe interpreter restriction test interp-29.1.1 {interp recursionlimit argument checking} { list [catch {interp recursionlimit} msg] $msg } {1 {wrong # args: should be "interp recursionlimit path ?newlimit?"}} test interp-29.1.2 {interp recursionlimit argument checking} { list [catch {interp recursionlimit foo bar} msg] $msg } {1 {could not find interpreter "foo"}} test interp-29.1.3 {interp recursionlimit argument checking} { list [catch {interp recursionlimit foo bar baz} msg] $msg } {1 {wrong # args: should be "interp recursionlimit path ?newlimit?"}} test interp-29.1.4 {interp recursionlimit argument checking} { interp create moo set result [catch {interp recursionlimit moo bar} msg] interp delete moo list $result $msg } {1 {expected integer but got "bar"}} test interp-29.1.5 {interp recursionlimit argument checking} { interp create moo set result [catch {interp recursionlimit moo 0} msg] interp delete moo list $result $msg } {1 {recursion limit must be > 0}} test interp-29.1.6 {interp recursionlimit argument checking} { interp create moo set result [catch {interp recursionlimit moo -1} msg] interp delete moo list $result $msg } {1 {recursion limit must be > 0}} test interp-29.1.7 {interp recursionlimit argument checking} { interp create moo set result [catch {interp recursionlimit moo [expr {wide(1)<<32}]} msg] interp delete moo list $result [string range $msg 0 35] } {1 {integer value too large to represent}} test interp-29.1.8 {slave recursionlimit argument checking} { interp create moo set result [catch {moo recursionlimit foo bar} msg] interp delete moo list $result $msg } {1 {wrong # args: should be "moo recursionlimit ?newlimit?"}} test interp-29.1.9 {slave recursionlimit argument checking} { interp create moo set result [catch {moo recursionlimit foo} msg] interp delete moo list $result $msg } {1 {expected integer but got "foo"}} test interp-29.1.10 {slave recursionlimit argument checking} { interp create moo set result [catch {moo recursionlimit 0} msg] interp delete moo list $result $msg } {1 {recursion limit must be > 0}} test interp-29.1.11 {slave recursionlimit argument checking} { interp create moo set result [catch {moo recursionlimit -1} msg] interp delete moo list $result $msg } {1 {recursion limit must be > 0}} test interp-29.1.12 {slave recursionlimit argument checking} { interp create moo set result [catch {moo recursionlimit [expr {wide(1)<<32}]} msg] interp delete moo list $result [string range $msg 0 35] } {1 {integer value too large to represent}} test interp-29.2.1 {query recursion limit} { interp recursionlimit {} } 1000 test interp-29.2.2 {query recursion limit} { set i [interp create] set n [interp recursionlimit $i] interp delete $i set n } 1000 test interp-29.2.3 {query recursion limit} { set i [interp create] set n [$i recursionlimit] interp delete $i set n } 1000 test interp-29.2.4 {query recursion limit} { set i [interp create] set r [$i eval { set n1 [interp recursionlimit {} 42] set n2 [interp recursionlimit {}] list $n1 $n2 }] interp delete $i set r } {42 42} test interp-29.2.5 {query recursion limit} { set i [interp create] set n1 [interp recursionlimit $i 42] set n2 [interp recursionlimit $i] interp delete $i list $n1 $n2 } {42 42} test interp-29.2.6 {query recursion limit} { set i [interp create] set n1 [interp recursionlimit $i 42] set n2 [$i recursionlimit] interp delete $i list $n1 $n2 } {42 42} test interp-29.2.7 {query recursion limit} { set i [interp create] set n1 [$i recursionlimit 42] set n2 [interp recursionlimit $i] interp delete $i list $n1 $n2 } {42 42} test interp-29.2.8 {query recursion limit} { set i [interp create] set n1 [$i recursionlimit 42] set n2 [$i recursionlimit] interp delete $i list $n1 $n2 } {42 42} test interp-29.3.1 {recursion limit} { set i [interp create] set r [interp eval $i { interp recursionlimit {} 50 proc p {} {incr ::i; p} set i 0 list [catch p msg] $msg $i }] interp delete $i set r } {1 {too many nested evaluations (infinite loop?)} 48} test interp-29.3.2 {recursion limit} { set i [interp create] interp recursionlimit $i 50 set r [interp eval $i { proc p {} {incr ::i; p} set i 0 list [catch p msg] $msg $i }] interp delete $i set r } {1 {too many nested evaluations (infinite loop?)} 48} test interp-29.3.3 {recursion limit} { set i [interp create] $i recursionlimit 50 set r [interp eval $i { proc p {} {incr ::i; p} set i 0 list [catch p msg] $msg $i }] interp delete $i set r } {1 {too many nested evaluations (infinite loop?)} 48} test interp-29.3.4 {recursion limit error reporting} { interp create slave set r1 [slave eval { catch { # nesting level 1 eval { # 2 eval { # 3 eval { # 4 eval { # 5 interp recursionlimit {} 5 set x ok } } } } } msg }] set r2 [slave eval { set msg }] interp delete slave list $r1 $r2 } {1 {falling back due to new recursion limit}} test interp-29.3.5 {recursion limit error reporting} { interp create slave set r1 [slave eval { catch { # nesting level 1 eval { # 2 eval { # 3 eval { # 4 eval { # 5 interp recursionlimit {} 4 set x ok } } } } } msg }] set r2 [slave eval { set msg }] interp delete slave list $r1 $r2 } {1 {falling back due to new recursion limit}} test interp-29.3.6 {recursion limit error reporting} { interp create slave set r1 [slave eval { catch { # nesting level 1 eval { # 2 eval { # 3 eval { # 4 eval { # 5 interp recursionlimit {} 6 set x ok } } } } } msg }] set r2 [slave eval { set msg }] interp delete slave list $r1 $r2 } {0 ok} test interp-29.3.7 {recursion limit error reporting} { interp create slave after 0 {interp recursionlimit slave 5} set r1 [slave eval { catch { # nesting level 1 eval { # 2 eval { # 3 eval { # 4 eval { # 5 update set x ok } } } } } msg }] set r2 [slave eval { set msg }] interp delete slave list $r1 $r2 } {1 {too many nested evaluations (infinite loop?)}} test interp-29.3.8 {recursion limit error reporting} { interp create slave after 0 {interp recursionlimit slave 4} set r1 [slave eval { catch { # nesting level 1 eval { # 2 eval { # 3 eval { # 4 eval { # 5 update set x ok } } } } } msg }] set r2 [slave eval { set msg }] interp delete slave list $r1 $r2 } {1 {too many nested evaluations (infinite loop?)}} test interp-29.3.9 {recursion limit error reporting} { interp create slave after 0 {interp recursionlimit slave 6} set r1 [slave eval { catch { # nesting level 1 eval { # 2 eval { # 3 eval { # 4 eval { # 5 update set x ok } } } } } msg }] set r2 [slave eval { set msg }] interp delete slave list $r1 $r2 } {0 ok} test interp-29.3.10 {recursion limit error reporting} { interp create slave after 0 {slave recursionlimit 4} set r1 [slave eval { catch { # nesting level 1 eval { # 2 eval { # 3 eval { # 4 eval { # 5 update set x ok } } } } } msg }] set r2 [slave eval { set msg }] interp delete slave list $r1 $r2 } {1 {too many nested evaluations (infinite loop?)}} test interp-29.3.11 {recursion limit error reporting} { interp create slave after 0 {slave recursionlimit 5} set r1 [slave eval { catch { # nesting level 1 eval { # 2 eval { # 3 eval { # 4 eval { # 5 update set x ok } } } } } msg }] set r2 [slave eval { set msg }] interp delete slave list $r1 $r2 } {1 {too many nested evaluations (infinite loop?)}} test interp-29.3.12 {recursion limit error reporting} { interp create slave after 0 {slave recursionlimit 6} set r1 [slave eval { catch { # nesting level 1 eval { # 2 eval { # 3 eval { # 4 eval { # 5 update set x ok } } } } } msg }] set r2 [slave eval { set msg }] interp delete slave list $r1 $r2 } {0 ok} test interp-29.4.1 {recursion limit inheritance} { set i [interp create] set ii [interp eval $i { interp recursionlimit {} 50 interp create }] set r [interp eval [list $i $ii] { proc p {} {incr ::i; p} set i 0 catch p set i }] interp delete $i set r } 49 test interp-29.4.2 {recursion limit inheritance} { set i [interp create] $i recursionlimit 50 set ii [interp eval $i {interp create}] set r [interp eval [list $i $ii] { proc p {} {incr ::i; p} set i 0 catch p set i }] interp delete $i set r } 49 test interp-29.5.1 {does slave recursion limit affect master?} { set before [interp recursionlimit {}] set i [interp create] interp recursionlimit $i 20000 set after [interp recursionlimit {}] set slavelimit [interp recursionlimit $i] interp delete $i list [expr {$before == $after}] $slavelimit } {1 20000} test interp-29.5.2 {does slave recursion limit affect master?} { set before [interp recursionlimit {}] set i [interp create] interp recursionlimit $i 20000 set after [interp recursionlimit {}] set slavelimit [$i recursionlimit] interp delete $i list [expr {$before == $after}] $slavelimit } {1 20000} test interp-29.5.3 {does slave recursion limit affect master?} { set before [interp recursionlimit {}] set i [interp create] $i recursionlimit 20000 set after [interp recursionlimit {}] set slavelimit [interp recursionlimit $i] interp delete $i list [expr {$before == $after}] $slavelimit } {1 20000} test interp-29.5.4 {does slave recursion limit affect master?} { set before [interp recursionlimit {}] set i [interp create] $i recursionlimit 20000 set after [interp recursionlimit {}] set slavelimit [$i recursionlimit] interp delete $i list [expr {$before == $after}] $slavelimit } {1 20000} test interp-29.6.1 {safe interpreter recursion limit} { interp create slave -safe set n [interp recursionlimit slave] interp delete slave set n } 1000 test interp-29.6.2 {safe interpreter recursion limit} { interp create slave -safe set n [slave recursionlimit] interp delete slave set n } 1000 test interp-29.6.3 {safe interpreter recursion limit} { interp create slave -safe set n1 [interp recursionlimit slave 42] set n2 [interp recursionlimit slave] interp delete slave list $n1 $n2 } {42 42} test interp-29.6.4 {safe interpreter recursion limit} { interp create slave -safe set n1 [slave recursionlimit 42] set n2 [interp recursionlimit slave] interp delete slave list $n1 $n2 } {42 42} test interp-29.6.5 {safe interpreter recursion limit} { interp create slave -safe set n1 [interp recursionlimit slave 42] set n2 [slave recursionlimit] interp delete slave list $n1 $n2 } {42 42} test interp-29.6.6 {safe interpreter recursion limit} { interp create slave -safe set n1 [slave recursionlimit 42] set n2 [slave recursionlimit] interp delete slave list $n1 $n2 } {42 42} test interp-29.6.7 {safe interpreter recursion limit} { interp create slave -safe set n1 [slave recursionlimit 42] set n2 [slave recursionlimit] interp delete slave list $n1 $n2 } {42 42} test interp-29.6.8 {safe interpreter recursion limit} { interp create slave -safe set n [catch {slave eval {interp recursionlimit {} 42}} msg] interp delete slave list $n $msg } {1 {permission denied: safe interpreters cannot change recursion limit}} test interp-29.6.9 {safe interpreter recursion limit} { interp create slave -safe set result [ slave eval { interp create slave2 -safe set n [catch { interp recursionlimit slave2 42 } msg] list $n $msg } ] interp delete slave set result } {1 {permission denied: safe interpreters cannot change recursion limit}} test interp-29.6.10 {safe interpreter recursion limit} { interp create slave -safe set result [ slave eval { interp create slave2 -safe set n [catch { slave2 recursionlimit 42 } msg] list $n $msg } ] interp delete slave set result } {1 {permission denied: safe interpreters cannot change recursion limit}} # # Deep recursion (into interps when the regular one fails): # # still crashes... # proc p {} { # if {[catch p ret]} { # catch { # set i [interp create] # interp eval $i [list proc p {} [info body p]] # interp eval $i p # } # interp delete $i # return ok # } # return $ret # } # p # more tests needed... # Interp & stack #test interp-29.1 {interp and stack (info level)} { #} {} # End of stack-recursion tests # This test dumps core in Tcl 8.0.3! test interp-30.1 {deletion of aliases inside namespaces} { set i [interp create] $i alias ns::cmd list $i alias ns::cmd {} } {} test interp-31.1 {alias invocation scope} { proc mySet {varName value} { upvar 1 $varName localVar set localVar $value } interp alias {} myNewSet {} mySet proc testMyNewSet {value} { myNewSet a $value return $a } catch {unset a} set result [testMyNewSet "ok"] rename testMyNewSet {} rename mySet {} rename myNewSet {} set result } ok test interp-32.1 { parent's working directory should be inherited by a child interp } { cd [temporaryDirectory] set parent [pwd] set i [interp create] set child [$i eval pwd] interp delete $i file mkdir cwd_test cd cwd_test lappend parent [pwd] set i [interp create] lappend child [$i eval pwd] cd .. file delete cwd_test interp delete $i cd [workingDirectory] expr {[string equal $parent $child] ? 1 : "\{$parent\} != \{$child\}"} } 1 test interp-33.1 {refCounting for target words of alias [Bug 730244]} { # This test will panic if Bug 730244 is not fixed. set i [interp create] proc testHelper args {rename testHelper {}; return $args} # Note: interp names are simple words by default trace add execution testHelper enter "interp alias $i alias {} ;#" interp alias $i alias {} testHelper this $i eval alias } this # cleanup foreach i [interp slaves] { interp delete $i } ::tcltest::cleanupTests return tcl8.4.20/tests/license.terms0000644003604700454610000000432111737050674014557 0ustar dgp771divThis software is copyrighted by the Regents of the University of California, Sun Microsystems, Inc., Scriptics Corporation, ActiveState Corporation and other parties. The following terms apply to all files associated with the software unless explicitly disclaimed in individual files. The authors hereby grant permission to use, copy, modify, distribute, and license this software and its documentation for any purpose, provided that existing copyright notices are retained in all copies and that this notice is included verbatim in any distributions. No written agreement, license, or royalty fee is required for any of the authorized uses. Modifications to this software may be copyrighted by their authors and need not follow the licensing terms described here, provided that the new terms are clearly indicated on the first page of each file where they apply. IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. GOVERNMENT USE: If you are acquiring this software on behalf of the U.S. government, the Government shall have only "Restricted Rights" in the software and related documentation as defined in the Federal Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are acquiring the software on behalf of the Department of Defense, the software shall be classified as "Commercial Computer Software" and the Government shall have only "Restricted Rights" as defined in Clause 252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the authors grant the U.S. Government and others acting in its behalf permission to use and distribute the software in accordance with the terms specified in this license. tcl8.4.20/tests/proc.test0000644003604700454610000002717111737050674013735 0ustar dgp771div# This file contains tests for the tclProc.c source file. Tests appear in # the same order as the C code that they test. The set of tests is # currently incomplete since it includes only new tests, in particular # tests for code changed for the addition of Tcl namespaces. Other # procedure-related tests appear in other test files such as proc-old.test. # # Sourcing this file into Tcl runs the tests and generates output for # errors. No output means no errors were found. # # Copyright (c) 1997 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } testConstraint memory [llength [info commands memory]] catch {eval namespace delete [namespace children :: test_ns_*]} catch {rename p ""} catch {rename {} ""} catch {unset msg} test proc-1.1 {Tcl_ProcObjCmd, put proc in namespace specified in name, if any} { catch {eval namespace delete [namespace children :: test_ns_*]} namespace eval test_ns_1 { namespace eval baz {} } proc test_ns_1::baz::p {} { return "p in [namespace current]" } list [test_ns_1::baz::p] \ [namespace eval test_ns_1 {baz::p}] \ [info commands test_ns_1::baz::*] } {{p in ::test_ns_1::baz} {p in ::test_ns_1::baz} ::test_ns_1::baz::p} test proc-1.2 {Tcl_ProcObjCmd, namespace specified in proc name must exist} { catch {eval namespace delete [namespace children :: test_ns_*]} list [catch {proc test_ns_1::baz::p {} {}} msg] $msg } {1 {can't create procedure "test_ns_1::baz::p": unknown namespace}} test proc-1.3 {Tcl_ProcObjCmd, empty proc name} { catch {eval namespace delete [namespace children :: test_ns_*]} proc :: {} { return "empty called" } list [::] \ [info body {}] } {{empty called} { return "empty called" }} test proc-1.4 {Tcl_ProcObjCmd, simple proc name and proc defined in namespace} { catch {eval namespace delete [namespace children :: test_ns_*]} namespace eval test_ns_1 { namespace eval baz { proc p {} { return "p in [namespace current]" } } } list [test_ns_1::baz::p] \ [info commands test_ns_1::baz::*] } {{p in ::test_ns_1::baz} ::test_ns_1::baz::p} test proc-1.5 {Tcl_ProcObjCmd, qualified proc name and proc defined in namespace} { catch {eval namespace delete [namespace children :: test_ns_*]} namespace eval test_ns_1::baz {} namespace eval test_ns_1 { proc baz::p {} { return "p in [namespace current]" } } list [test_ns_1::baz::p] \ [info commands test_ns_1::baz::*] \ [namespace eval test_ns_1::baz {namespace which p}] } {{p in ::test_ns_1::baz} ::test_ns_1::baz::p ::test_ns_1::baz::p} test proc-1.6 {Tcl_ProcObjCmd, namespace code ignores single ":"s in middle or end of command names} { catch {eval namespace delete [namespace children :: test_ns_*]} namespace eval test_ns_1 { proc q: {} {return "q:"} proc value:at: {} {return "value:at:"} } list [namespace eval test_ns_1 {q:}] \ [namespace eval test_ns_1 {value:at:}] \ [test_ns_1::q:] \ [test_ns_1::value:at:] \ [lsort [info commands test_ns_1::*]] \ [namespace eval test_ns_1 {namespace which q:}] \ [namespace eval test_ns_1 {namespace which value:at:}] } {q: value:at: q: value:at: {::test_ns_1::q: ::test_ns_1::value:at:} ::test_ns_1::q: ::test_ns_1::value:at:} test proc-1.7 {Tcl_ProcObjCmd, check that formal parameter names are not array elements} { catch {rename p ""} list [catch {proc p {a(1) a(2)} { set z [expr $a(1)+$a(2)] puts "$z=z, $a(1)=$a(1)" }} msg] $msg } {1 {procedure "p" has formal parameter "a(1)" that is an array element}} test proc-1.8 {Tcl_ProcObjCmd, check that formal parameter names are simple names} { catch {rename p ""} list [catch {proc p {b:a b::a} { }} msg] $msg } {1 {procedure "p" has formal parameter "b::a" that is not a simple name}} test proc-2.1 {TclFindProc, simple proc name and proc not in namespace} { catch {eval namespace delete [namespace children :: test_ns_*]} catch {rename p ""} proc p {} {return "p in [namespace current]"} info body p } {return "p in [namespace current]"} test proc-2.2 {TclFindProc, simple proc name and proc defined in namespace} { catch {eval namespace delete [namespace children :: test_ns_*]} namespace eval test_ns_1 { namespace eval baz { proc p {} {return "p in [namespace current]"} } } namespace eval test_ns_1::baz {info body p} } {return "p in [namespace current]"} test proc-2.3 {TclFindProc, qualified proc name and proc defined in namespace} { catch {eval namespace delete [namespace children :: test_ns_*]} namespace eval test_ns_1::baz {} namespace eval test_ns_1 { proc baz::p {} {return "p in [namespace current]"} } namespace eval test_ns_1 {info body baz::p} } {return "p in [namespace current]"} test proc-2.4 {TclFindProc, global proc and executing in namespace} { catch {eval namespace delete [namespace children :: test_ns_*]} catch {rename p ""} proc p {} {return "global p"} namespace eval test_ns_1::baz {info body p} } {return "global p"} test proc-3.1 {TclObjInterpProc, proc defined and executing in same namespace} { catch {eval namespace delete [namespace children :: test_ns_*]} proc p {} {return "p in [namespace current]"} p } {p in ::} test proc-3.2 {TclObjInterpProc, proc defined and executing in same namespace} { catch {eval namespace delete [namespace children :: test_ns_*]} namespace eval test_ns_1::baz { proc p {} {return "p in [namespace current]"} p } } {p in ::test_ns_1::baz} test proc-3.3 {TclObjInterpProc, proc defined and executing in different namespaces} { catch {eval namespace delete [namespace children :: test_ns_*]} catch {rename p ""} proc p {} {return "p in [namespace current]"} namespace eval test_ns_1::baz { p } } {p in ::} test proc-3.4 {TclObjInterpProc, procs execute in the namespace in which they were defined unless renamed into new namespace} { catch {eval namespace delete [namespace children :: test_ns_*]} catch {rename p ""} namespace eval test_ns_1::baz { proc p {} {return "p in [namespace current]"} rename ::test_ns_1::baz::p ::p list [p] [namespace which p] } } {{p in ::} ::p} test proc-3.5 {TclObjInterpProc, any old result is reset before appending error msg about missing arguments} { proc p {x} {info commands 3m} list [catch {p} msg] $msg } {1 {wrong # args: should be "p x"}} test proc-3.6 {TclObjInterpProc, proper quoting of proc name, Bug 942757} { proc {a b c} {x} {info commands 3m} list [catch {{a b c}} msg] $msg } {1 {wrong # args: should be "{a b c} x"}} test proc-3.7 {TclObjInterpProc, wrong num args, Bug 3366265} { proc {} {x} {} list [catch {{}} msg] $msg } {1 {wrong # args: should be "{} x"}} catch {eval namespace delete [namespace children :: test_ns_*]} catch {rename p ""} catch {rename {} ""} catch {rename {a b c} {}} catch {unset msg} if {[catch {package require procbodytest}]} { puts "This application couldn't load the \"procbodytest\" package, so I" puts "can't test creation of procs whose bodies have type \"procbody\"." ::tcltest::cleanupTests return } catch {rename p ""} catch {rename t ""} # Note that the test require that procedures whose body is used to create # procbody objects must be executed before the procbodytest::proc command # is executed, so that the Proc struct is populated correctly (CompiledLocals # are added at compile time). test proc-4.1 {TclCreateProc, procbody obj} { catch { proc p x {return "$x:$x"} set rv [p P] procbodytest::proc t x p lappend rv [t T] set rv } result catch {rename p ""} catch {rename t ""} set result } {P:P T:T} test proc-4.2 {TclCreateProc, procbody obj, use compiled locals} { catch { proc p x { set y [string tolower $x] return "$x:$y" } set rv [p P] procbodytest::proc t x p lappend rv [t T] set rv } result catch {rename p ""} catch {rename t ""} set result } {P:p T:t} test proc-4.3 {TclCreateProc, procbody obj, too many args} { catch { proc p x { set y [string tolower $x] return "$x:$y" } set rv [p P] procbodytest::proc t {x x1 x2} p lappend rv [t T] set rv } result catch {rename p ""} catch {rename t ""} set result } {procedure "t": arg list contains 3 entries, precompiled header expects 1} test proc-4.4 {TclCreateProc, procbody obj, inconsistent arg name} { catch { proc p {x y z} { set v [join [list $x $y $z]] set w [string tolower $v] return "$v:$w" } set rv [p P Q R] procbodytest::proc t {x x1 z} p lappend rv [t S T U] set rv } result catch {rename p ""} catch {rename t ""} set result } {procedure "t": formal parameter 1 is inconsistent with precompiled body} test proc-4.5 {TclCreateProc, procbody obj, inconsistent arg default type} { catch { proc p {x y {z Z}} { set v [join [list $x $y $z]] set w [string tolower $v] return "$v:$w" } set rv [p P Q R] procbodytest::proc t {x y z} p lappend rv [t S T U] set rv } result catch {rename p ""} catch {rename t ""} set result } {procedure "t": formal parameter 2 is inconsistent with precompiled body} test proc-4.6 {TclCreateProc, procbody obj, inconsistent arg default type} { catch { proc p {x y z} { set v [join [list $x $y $z]] set w [string tolower $v] return "$v:$w" } set rv [p P Q R] procbodytest::proc t {x y {z Z}} p lappend rv [t S T U] set rv } result catch {rename p ""} catch {rename t ""} set result } {procedure "t": formal parameter 2 is inconsistent with precompiled body} test proc-4.7 {TclCreateProc, procbody obj, inconsistent arg default value} { catch { proc p {x y {z Z}} { set v [join [list $x $y $z]] set w [string tolower $v] return "$v:$w" } set rv [p P Q R] procbodytest::proc t {x y {z ZZ}} p lappend rv [t S T U] set rv } result catch {rename p ""} catch {rename t ""} set result } {procedure "t": formal parameter "z" has default value inconsistent with precompiled body} test proc-4.8 {TclCreateProc, procbody obj, no leak on multiple iterations} -setup { proc getbytes {} { set lines [split [memory info] "\n"] lindex $lines 3 3 } proc px x { set y [string tolower $x] return "$x:$y" } px x } -constraints memory -body { set end [getbytes] for {set i 0} {$i < 5} {incr i} { procbodytest::proc tx x px set tmp $end set end [getbytes] } set leakedBytes [expr {$end - $tmp}] } -cleanup { rename getbytes {} } -result 0 test proc-5.1 {Bytecompiling noop; test for correct argument substitution} { proc p args {} ; # this will be bytecompiled into t proc t {} { set res {} set a 0 set b 0 trace add variable a read {append res a ;#} trace add variable b write {append res b ;#} p $a ccccccw {bfe} {$a} [incr b] [incr a] {[incr b]} {$a} hello set res } set result [t] catch {rename p ""} catch {rename t ""} set result } {aba} test proc-6.1 {ProcessProcResultCode: Bug 647307 (negative return code)} { proc a {} {return -code -5} proc b {} a set result [catch b] rename a {} rename b {} set result } -5 # cleanup catch {rename p ""} catch {rename t ""} ::tcltest::cleanupTests return tcl8.4.20/tests/string.test0000644003604700454610000013263211737050674014277 0ustar dgp771div# Commands covered: string # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # Copyright (c) 2001 by Kevin B. Kenny. All rights reserved. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } # Some tests require the testobj command set ::tcltest::testConstraints(testobj) \ [expr {[info commands testobj] != {}}] set ::tcltest::testConstraints(testindexobj) \ [expr {[info commands testindexobj] != {}}] test string-1.1 {error conditions} { list [catch {string gorp a b} msg] $msg } {1 {bad option "gorp": must be bytelength, compare, equal, first, index, is, last, length, map, match, range, repeat, replace, tolower, toupper, totitle, trim, trimleft, trimright, wordend, or wordstart}} test string-1.2 {error conditions} { list [catch {string} msg] $msg } {1 {wrong # args: should be "string option arg ?arg ...?"}} test string-2.1 {string compare, too few args} { list [catch {string compare a} msg] $msg } {1 {wrong # args: should be "string compare ?-nocase? ?-length int? string1 string2"}} test string-2.2 {string compare, bad args} { list [catch {string compare a b c} msg] $msg } {1 {bad option "a": must be -nocase or -length}} test string-2.3 {string compare, bad args} { list [catch {string compare -length -nocase str1 str2} msg] $msg } {1 {expected integer but got "-nocase"}} test string-2.4 {string compare, too many args} { list [catch {string compare -length 10 -nocase str1 str2 str3} msg] $msg } {1 {wrong # args: should be "string compare ?-nocase? ?-length int? string1 string2"}} test string-2.5 {string compare with length unspecified} { list [catch {string compare -length 10 10} msg] $msg } {1 {wrong # args: should be "string compare ?-nocase? ?-length int? string1 string2"}} test string-2.6 {string compare} { string compare abcde abdef } -1 test string-2.7 {string compare, shortest method name} { string c abcde ABCDE } 1 test string-2.8 {string compare} { string compare abcde abcde } 0 test string-2.9 {string compare with length} { string compare -length 2 abcde abxyz } 0 test string-2.10 {string compare with special index} { list [catch {string compare -length end-3 abcde abxyz} msg] $msg } {1 {expected integer but got "end-3"}} test string-2.11 {string compare, unicode} { string compare ab\u7266 ab\u7267 } -1 test string-2.12 {string compare, high bit} { # This test will fail if the underlying comparaison # is using signed chars instead of unsigned chars. # (like SunOS's default memcmp thus the compat/memcmp.c) string compare "\x80" "@" # Nb this tests works also in utf8 space because \x80 is # translated into a 2 or more bytelength but whose first byte has # the high bit set. } 1 test string-2.13 {string compare -nocase} { string compare -nocase abcde abdef } -1 test string-2.14 {string compare -nocase} { string c -nocase abcde ABCDE } 0 test string-2.15 {string compare -nocase} { string compare -nocase abcde abcde } 0 test string-2.16 {string compare -nocase with length} { string compare -length 2 -nocase abcde Abxyz } 0 test string-2.17 {string compare -nocase with length} { string compare -nocase -length 3 abcde Abxyz } -1 test string-2.18 {string compare -nocase with length <= 0} { string compare -nocase -length -1 abcde AbCdEf } -1 test string-2.19 {string compare -nocase with excessive length} { string compare -nocase -length 50 AbCdEf abcde } 1 test string-2.20 {string compare -len unicode} { # These are strings that are 6 BYTELENGTH long, but the length # shouldn't make a different because there are actually 3 CHARS long string compare -len 5 \334\334\334 \334\334\374 } -1 test string-2.21 {string compare -nocase with special index} { list [catch {string compare -nocase -length end-3 Abcde abxyz} msg] $msg } {1 {expected integer but got "end-3"}} test string-2.22 {string compare, null strings} { string compare "" "" } 0 test string-2.23 {string compare, null strings} { string compare "" foo } -1 test string-2.24 {string compare, null strings} { string compare foo "" } 1 test string-2.25 {string compare -nocase, null strings} { string compare -nocase "" "" } 0 test string-2.26 {string compare -nocase, null strings} { string compare -nocase "" foo } -1 test string-2.27 {string compare -nocase, null strings} { string compare -nocase foo "" } 1 test string-2.28 {string compare with length, unequal strings} { string compare -length 2 abc abde } 0 test string-2.29 {string compare with length, unequal strings} { string compare -length 2 ab abde } 0 test string-2.30 {string compare with NUL character vs. other ASCII} { # Be careful here, since UTF-8 rep comparison with memcmp() of # these puts chars in the wrong order string compare \x00 \x01 } -1 test string-2.31 {string compare, high bit} { proc foo {} {string compare "a\x80" "a@"} foo } 1 test string-2.32 {string compare, high bit} { proc foo {} {string compare "a\x00" "a\x01"} foo } -1 test string-2.33 {string compare, high bit} { proc foo {} {string compare "\x00\x00" "\x00\x01"} foo } -1 # only need a few tests on equal, since it uses the same code as # string compare, but just modifies the return output test string-3.1 {string equal} { string equal abcde abdef } 0 test string-3.2 {string equal} { string eq abcde ABCDE } 0 test string-3.3 {string equal} { string equal abcde abcde } 1 test string-3.4 {string equal -nocase} { string equal -nocase \334\334\334\334\374\374\374\374 \334\334\334\334\334\334\334\334 } 1 test string-3.5 {string equal -nocase} { string equal -nocase abcde abdef } 0 test string-3.6 {string equal -nocase} { string eq -nocase abcde ABCDE } 1 test string-3.7 {string equal -nocase} { string equal -nocase abcde abcde } 1 test string-3.8 {string equal with length, unequal strings} { string equal -length 2 abc abde } 1 test string-4.1 {string first, too few args} { list [catch {string first a} msg] $msg } {1 {wrong # args: should be "string first subString string ?startIndex?"}} test string-4.2 {string first, bad args} { list [catch {string first a b c} msg] $msg } {1 {bad index "c": must be integer or end?-integer?}} test string-4.3 {string first, too many args} { list [catch {string first a b 5 d} msg] $msg } {1 {wrong # args: should be "string first subString string ?startIndex?"}} test string-4.4 {string first} { string first bq abcdefgbcefgbqrs } 12 test string-4.5 {string first} { string fir bcd abcdefgbcefgbqrs } 1 test string-4.6 {string first} { string f b abcdefgbcefgbqrs } 1 test string-4.7 {string first} { string first xxx x123xx345xxx789xxx012 } 9 test string-4.8 {string first} { string first "" x123xx345xxx789xxx012 } -1 test string-4.9 {string first, unicode} { string first x abc\u7266x } 4 test string-4.10 {string first, unicode} { string first \u7266 abc\u7266x } 3 test string-4.11 {string first, start index} { string first \u7266 abc\u7266x 3 } 3 test string-4.12 {string first, start index} { string first \u7266 abc\u7266x 4 } -1 test string-4.13 {string first, start index} { string first \u7266 abc\u7266x end-2 } 3 test string-4.14 {string first, negative start index} { string first b abc -1 } 1 test string-4.15 {string first, ability to two-byte encoded utf-8 chars} { # Test for a bug in Tcl 8.3 where test for all-single-byte-encoded # strings was incorrect, leading to an index returned by [string first] # which pointed past the end of the string. set uchar \u057e ;# character with two-byte encoding in utf-8 string first % %#$uchar$uchar#$uchar$uchar#% 3 } 8 test string-5.1 {string index} { list [catch {string index} msg] $msg } {1 {wrong # args: should be "string index string charIndex"}} test string-5.2 {string index} { list [catch {string index a b c} msg] $msg } {1 {wrong # args: should be "string index string charIndex"}} test string-5.3 {string index} { string index abcde 0 } a test string-5.4 {string index} { string in abcde 4 } e test string-5.5 {string index} { string index abcde 5 } {} test string-5.6 {string index} { list [catch {string index abcde -10} msg] $msg } {0 {}} test string-5.7 {string index} { list [catch {string index a xyz} msg] $msg } {1 {bad index "xyz": must be integer or end?-integer?}} test string-5.8 {string index} { string index abc end } c test string-5.9 {string index} { string index abc end-1 } b test string-5.10 {string index, unicode} { string index abc\u7266d 4 } d test string-5.11 {string index, unicode} { string index abc\u7266d 3 } \u7266 test string-5.12 {string index, unicode over char length, under byte length} { string index \334\374\334\374 6 } {} test string-5.13 {string index, bytearray object} { string index [binary format a5 fuz] 0 } f test string-5.14 {string index, bytearray object} { string index [binary format I* {0x50515253 0x52}] 3 } S test string-5.15 {string index, bytearray object} { set b [binary format I* {0x50515253 0x52}] set i1 [string index $b end-6] set i2 [string index $b 1] string compare $i1 $i2 } 0 test string-5.16 {string index, bytearray object with string obj shimmering} { set str "0123456789\x00 abcdedfghi" binary scan $str H* dump string compare [string index $str 10] \x00 } 0 test string-5.17 {string index, bad integer} { list [catch {string index "abc" 08} msg] $msg } {1 {bad index "08": must be integer or end?-integer? (looks like invalid octal number)}} test string-5.18 {string index, bad integer} { list [catch {string index "abc" end-00289} msg] $msg } {1 {bad index "end-00289": must be integer or end?-integer? (looks like invalid octal number)}} test string-5.19 {string index, bytearray object out of bounds} { string index [binary format I* {0x50515253 0x52}] -1 } {} test string-5.20 {string index, bytearray object out of bounds} { string index [binary format I* {0x50515253 0x52}] 20 } {} proc largest_int {} { # This will give us what the largest valid int on this machine is, # so we can test for overflow properly below on >32 bit systems set int 1 set exp 7; # assume we get at least 8 bits while {$int > 0} { set int [expr {wide(1) << [incr exp]}] } return [expr {$int-1}] } test string-6.1 {string is, too few args} { list [catch {string is} msg] $msg } {1 {wrong # args: should be "string is class ?-strict? ?-failindex var? str"}} test string-6.2 {string is, too few args} { list [catch {string is alpha} msg] $msg } {1 {wrong # args: should be "string is class ?-strict? ?-failindex var? str"}} test string-6.3 {string is, bad args} { list [catch {string is alpha -failin str} msg] $msg } {1 {wrong # args: should be "string is alpha ?-strict? ?-failindex var? str"}} test string-6.4 {string is, too many args} { list [catch {string is alpha -failin var -strict str more} msg] $msg } {1 {wrong # args: should be "string is class ?-strict? ?-failindex var? str"}} test string-6.5 {string is, class check} { list [catch {string is bogus str} msg] $msg } {1 {bad class "bogus": must be alnum, alpha, ascii, control, boolean, digit, double, false, graph, integer, lower, print, punct, space, true, upper, wordchar, or xdigit}} test string-6.6 {string is, ambiguous class} { list [catch {string is al str} msg] $msg } {1 {ambiguous class "al": must be alnum, alpha, ascii, control, boolean, digit, double, false, graph, integer, lower, print, punct, space, true, upper, wordchar, or xdigit}} test string-6.7 {string is alpha, all ok} { string is alpha -strict -failindex var abc } 1 test string-6.8 {string is, error in var} { list [string is alpha -failindex var abc5def] $var } {0 3} test string-6.9 {string is, var shouldn't get set} { catch {unset var} list [catch {string is alpha -failindex var abc; set var} msg] $msg } {1 {can't read "var": no such variable}} test string-6.10 {string is, ok on empty} { string is alpha {} } 1 test string-6.11 {string is, -strict check against empty} { string is alpha -strict {} } 0 test string-6.12 {string is alnum, true} { string is alnum abc123 } 1 test string-6.13 {string is alnum, false} { list [string is alnum -failindex var abc1.23] $var } {0 4} test string-6.14 {string is alnum, unicode} { string is alnum abcќ } 1 test string-6.15 {string is alpha, true} { string is alpha abc } 1 test string-6.16 {string is alpha, false} { list [string is alpha -fail var a1bcde] $var } {0 1} test string-6.17 {string is alpha, unicode} { string is alpha abc\374 } 1 test string-6.18 {string is ascii, true} { string is ascii abc\u007Fend } 1 test string-6.19 {string is ascii, false} { list [string is ascii -fail var abcdef\u0080more] $var } {0 6} test string-6.20 {string is boolean, true} { string is boolean true } 1 test string-6.21 {string is boolean, true} { string is boolean f } 1 test string-6.22 {string is boolean, true based on type} { string is bool [string compare a a] } 1 test string-6.23 {string is boolean, false} { list [string is bool -fail var yada] $var } {0 0} test string-6.24 {string is digit, true} { string is digit 0123456789 } 1 test string-6.25 {string is digit, false} { list [string is digit -fail var 0123м567] $var } {0 4} test string-6.26 {string is digit, false} { list [string is digit -fail var +123567] $var } {0 0} test string-6.27 {string is double, true} { string is double 1 } 1 test string-6.28 {string is double, true} { string is double [expr double(1)] } 1 test string-6.29 {string is double, true} { string is double 1.0 } 1 test string-6.30 {string is double, true} { string is double [string compare a a] } 1 test string-6.31 {string is double, true} { string is double " +1.0e-1 " } 1 test string-6.32 {string is double, true} { string is double "\n1.0\v" } 1 test string-6.33 {string is double, false} { list [string is double -fail var 1abc] $var } {0 1} test string-6.34 {string is double, false} { list [string is double -fail var abc] $var } {0 0} test string-6.35 {string is double, false} { list [string is double -fail var " 1.0e4e4 "] $var } {0 8} test string-6.36 {string is double, false} { list [string is double -fail var "\n"] $var } {0 0} test string-6.37 {string is double, false on int overflow} { # Make it the largest int recognizable, with one more digit for overflow list [string is double -fail var [largest_int]0] $var } {0 -1} test string-6.38 {string is double, false on underflow} { catch {unset var} list [string is double -fail var 123e-9999] $var } {0 -1} test string-6.39 {string is double, false} {nonPortable} { # This test is non-portable because IRIX thinks # that .e1 is a valid double - this is really a bug # on IRIX as .e1 should NOT be a valid double list [string is double -fail var .e1] $var } {0 0} test string-6.40 {string is false, true} { string is false false } 1 test string-6.41 {string is false, true} { string is false FaLsE } 1 test string-6.42 {string is false, true} { string is false N } 1 test string-6.43 {string is false, true} { string is false 0 } 1 test string-6.44 {string is false, true} { string is false off } 1 test string-6.45 {string is false, false} { list [string is false -fail var abc] $var } {0 0} test string-6.46 {string is false, false} { catch {unset var} list [string is false -fail var Y] $var } {0 0} test string-6.47 {string is false, false} { catch {unset var} list [string is false -fail var offensive] $var } {0 0} test string-6.48 {string is integer, true} { string is integer +1234567890 } 1 test string-6.49 {string is integer, true on type} { string is integer [expr int(50.0)] } 1 test string-6.50 {string is integer, true} { string is integer [list -10] } 1 test string-6.51 {string is integer, true as hex} { string is integer 0xabcdef } 1 test string-6.52 {string is integer, true as octal} { string is integer 012345 } 1 test string-6.53 {string is integer, true with whitespace} { string is integer " \n1234\v" } 1 test string-6.54 {string is integer, false} { list [string is integer -fail var 123abc] $var } {0 3} test string-6.55 {string is integer, false on overflow} { list [string is integer -fail var +[largest_int]0] $var } {0 -1} test string-6.56 {string is integer, false} { list [string is integer -fail var [expr double(1)]] $var } {0 1} test string-6.57 {string is integer, false} { list [string is integer -fail var " "] $var } {0 0} test string-6.58 {string is integer, false on bad octal} { list [string is integer -fail var 036963] $var } {0 3} test string-6.59 {string is integer, false on bad hex} { list [string is integer -fail var 0X345XYZ] $var } {0 5} test string-6.60 {string is lower, true} { string is lower abc } 1 test string-6.61 {string is lower, unicode true} { string is lower abcќue } 1 test string-6.62 {string is lower, false} { list [string is lower -fail var aBc] $var } {0 1} test string-6.63 {string is lower, false} { list [string is lower -fail var abc1] $var } {0 3} test string-6.64 {string is lower, unicode false} { list [string is lower -fail var abмUE] $var } {0 2} test string-6.65 {string is space, true} { string is space " \t\n\v\f" } 1 test string-6.66 {string is space, false} { list [string is space -fail var " \t\n\v1\f"] $var } {0 4} test string-6.67 {string is true, true} { string is true true } 1 test string-6.68 {string is true, true} { string is true TrU } 1 test string-6.69 {string is true, true} { string is true ye } 1 test string-6.70 {string is true, true} { string is true 1 } 1 test string-6.71 {string is true, true} { string is true on } 1 test string-6.72 {string is true, false} { list [string is true -fail var onto] $var } {0 0} test string-6.73 {string is true, false} { catch {unset var} list [string is true -fail var 25] $var } {0 0} test string-6.74 {string is true, false} { catch {unset var} list [string is true -fail var no] $var } {0 0} test string-6.75 {string is upper, true} { string is upper ABC } 1 test string-6.76 {string is upper, unicode true} { string is upper ABCмUE } 1 test string-6.77 {string is upper, false} { list [string is upper -fail var AbC] $var } {0 1} test string-6.78 {string is upper, false} { list [string is upper -fail var AB2C] $var } {0 2} test string-6.79 {string is upper, unicode false} { list [string is upper -fail var ABCќue] $var } {0 3} test string-6.80 {string is wordchar, true} { string is wordchar abc_123 } 1 test string-6.81 {string is wordchar, unicode true} { string is wordchar abcќabмAB\u5001 } 1 test string-6.82 {string is wordchar, false} { list [string is wordchar -fail var abcd.ef] $var } {0 4} test string-6.83 {string is wordchar, unicode false} { list [string is wordchar -fail var abc\u0080def] $var } {0 3} test string-6.84 {string is control} { ## Control chars are in the ranges ## 00..1F && 7F..9F list [string is control -fail var \x00\x01\x10\x1F\x7F\x80\x9F\x60] $var } {0 7} test string-6.85 {string is control} { string is control \u0100 } 0 test string-6.86 {string is graph} { ## graph is any print char, except space list [string is gra -fail var "0123abc!@#\$\u0100 "] $var } {0 12} test string-6.87 {string is print} { ## basically any printable char list [string is print -fail var "0123abc!@#\$\u0100 \u0010"] $var } {0 13} test string-6.88 {string is punct} { ## any graph char that isn't alnum list [string is punct -fail var "_!@#\u00beq0"] $var } {0 4} test string-6.89 {string is xdigit} { list [string is xdigit -fail var 0123456789\u0061bcdefABCDEFg] $var } {0 22} test string-6.90 {string is integer, bad integers} { # SF bug #634856 set result "" set numbers [list 1 +1 ++1 +-1 -+1 -1 --1 "- +1"] foreach num $numbers { lappend result [string is int -strict $num] } set result } {1 1 0 0 0 1 0 0} test string-6.91 {string is double, bad doubles} { set result "" set numbers [list 1.0 +1.0 ++1.0 +-1.0 -+1.0 -1.0 --1.0 "- +1.0"] foreach num $numbers { lappend result [string is double -strict $num] } set result } {1 1 0 0 0 1 0 0} test string-6.92 {string is integer, 32-bit overflow} { # Bug 718878 set x 0x100000000 list [string is integer -failindex var $x] $var } {0 -1} test string-6.93 {string is integer, 32-bit overflow} { # Bug 718878 set x 0x100000000 append x "" list [string is integer -failindex var $x] $var } {0 -1} test string-6.94 {string is integer, 32-bit overflow} { # Bug 718878 set x 0x100000000 list [string is integer -failindex var [expr {$x}]] $var } {0 -1} catch {rename largest_int {}} test string-7.1 {string last, too few args} { list [catch {string last a} msg] $msg } {1 {wrong # args: should be "string last subString string ?startIndex?"}} test string-7.2 {string last, bad args} { list [catch {string last a b c} msg] $msg } {1 {bad index "c": must be integer or end?-integer?}} test string-7.3 {string last, too many args} { list [catch {string last a b c d} msg] $msg } {1 {wrong # args: should be "string last subString string ?startIndex?"}} test string-7.4 {string last} { string la xxx xxxx123xx345x678 } 1 test string-7.5 {string last} { string last xx xxxx123xx345x678 } 7 test string-7.6 {string last} { string las x xxxx123xx345x678 } 12 test string-7.7 {string last, unicode} { string las x xxxx12\u7266xx345x678 } 12 test string-7.8 {string last, unicode} { string las \u7266 xxxx12\u7266xx345x678 } 6 test string-7.9 {string last, stop index} { string las \u7266 xxxx12\u7266xx345x678 } 6 test string-7.10 {string last, unicode} { string las \u7266 xxxx12\u7266xx345x678 } 6 test string-7.11 {string last, start index} { string last \u7266 abc\u7266x 3 } 3 test string-7.12 {string last, start index} { string last \u7266 abc\u7266x 2 } -1 test string-7.13 {string last, start index} { ## Constrain to last 'a' should work string last ba badbad end-1 } 3 test string-7.14 {string last, start index} { ## Constrain to last 'b' should skip last 'ba' string last ba badbad end-2 } 0 test string-7.15 {string last, start index} { string last \334a \334ad\334ad 0 } -1 test string-7.16 {string last, start index} { string last \334a \334ad\334ad end-1 } 3 test string-8.1 {string bytelength} { list [catch {string bytelength} msg] $msg } {1 {wrong # args: should be "string bytelength string"}} test string-8.2 {string bytelength} { list [catch {string bytelength a b} msg] $msg } {1 {wrong # args: should be "string bytelength string"}} test string-8.3 {string bytelength} { string bytelength "\u00c7" } 2 test string-8.4 {string bytelength} { string b "" } 0 test string-9.1 {string length} { list [catch {string length} msg] $msg } {1 {wrong # args: should be "string length string"}} test string-9.2 {string length} { list [catch {string length a b} msg] $msg } {1 {wrong # args: should be "string length string"}} test string-9.3 {string length} { string length "a little string" } 15 test string-9.4 {string length} { string le "" } 0 test string-9.5 {string length, unicode} { string le "abcd\u7266" } 5 test string-9.6 {string length, bytearray object} { string length [binary format a5 foo] } 5 test string-9.7 {string length, bytearray object} { string length [binary format I* {0x50515253 0x52}] } 8 test string-10.1 {string map, too few args} { list [catch {string map} msg] $msg } {1 {wrong # args: should be "string map ?-nocase? charMap string"}} test string-10.2 {string map, bad args} { list [catch {string map {a b} abba oops} msg] $msg } {1 {bad option "a b": must be -nocase}} test string-10.3 {string map, too many args} { list [catch {string map -nocase {a b} str1 str2} msg] $msg } {1 {wrong # args: should be "string map ?-nocase? charMap string"}} test string-10.4 {string map} { string map {a b} abba } {bbbb} test string-10.5 {string map} { string map {a b} a } {b} test string-10.6 {string map -nocase} { string map -nocase {a b} Abba } {bbbb} test string-10.7 {string map} { string map {abc 321 ab * a A} aabcabaababcab } {A321*A*321*} test string-10.8 {string map -nocase} { string map -nocase {aBc 321 Ab * a A} aabcabaababcab } {A321*A*321*} test string-10.9 {string map -nocase} { string map -no {abc 321 Ab * a A} aAbCaBaAbAbcAb } {A321*A*321*} test string-10.10 {string map} { list [catch {string map {a b c} abba} msg] $msg } {1 {char map list unbalanced}} test string-10.11 {string map, nulls} { string map {\x00 NULL blah \x00nix} {qwerty} } {qwerty} test string-10.12 {string map, unicode} { string map [list \374 ue UE \334] "a\374ueUE\000EU" } aueue\334\0EU test string-10.13 {string map, -nocase unicode} { string map -nocase [list \374 ue UE \334] "a\374ueUE\000EU" } aue\334\334\0EU test string-10.14 {string map, -nocase null arguments} { string map -nocase {{} abc} foo } foo test string-10.15 {string map, one pair case} { string map -nocase {abc 32} aAbCaBaAbAbcAb } {a32aBaAb32Ab} test string-10.16 {string map, one pair case} { string map -nocase {ab 4321} aAbCaBaAbAbcAb } {a4321C4321a43214321c4321} test string-10.17 {string map, one pair case} { string map {Ab 4321} aAbCaBaAbAbcAb } {a4321CaBa43214321c4321} test string-10.18 {string map, empty argument} { string map -nocase {{} abc} foo } foo test string-10.19 {string map, empty arguments} { string map -nocase {{} abc f bar {} def} foo } baroo test string-10.20 {string map, nasty sharing crash from [Bug 1018562]} { set a {a b} string map $a $a } {b b} test string-10.21 {string map, ABR checks} { string map {longstring foob} long } long test string-10.22 {string map, ABR checks} { string map {long foob} long } foob test string-10.23 {string map, ABR checks} { string map {lon foob} long } foobg test string-10.24 {string map, ABR checks} { string map {lon foob} longlo } foobglo test string-10.25 {string map, ABR checks} { string map {lon foob} longlon } foobgfoob test string-10.26 {string map, ABR checks} { string map {longstring foob longstring bar} long } long test string-10.27 {string map, ABR checks} { string map {long foob longstring bar} long } foob test string-10.28 {string map, ABR checks} { string map {lon foob longstring bar} long } foobg test string-10.29 {string map, ABR checks} { string map {lon foob longstring bar} longlo } foobglo test string-10.30 {string map, ABR checks} { string map {lon foob longstring bar} longlon } foobgfoob test string-11.1 {string match, too few args} { list [catch {string match a} msg] $msg } {1 {wrong # args: should be "string match ?-nocase? pattern string"}} test string-11.2 {string match, too many args} { list [catch {string match a b c d} msg] $msg } {1 {wrong # args: should be "string match ?-nocase? pattern string"}} test string-11.3 {string match} { string match abc abc } 1 test string-11.4 {string match} { string mat abc abd } 0 test string-11.5 {string match} { string match ab*c abc } 1 test string-11.6 {string match} { string match ab**c abc } 1 test string-11.7 {string match} { string match ab* abcdef } 1 test string-11.8 {string match} { string match *c abc } 1 test string-11.9 {string match} { string match *3*6*9 0123456789 } 1 test string-11.10 {string match} { string match *3*6*9 01234567890 } 0 test string-11.11 {string match} { string match a?c abc } 1 test string-11.12 {string match} { string match a??c abc } 0 test string-11.13 {string match} { string match ?1??4???8? 0123456789 } 1 test string-11.14 {string match} { string match {[abc]bc} abc } 1 test string-11.15 {string match} { string match {a[abc]c} abc } 1 test string-11.16 {string match} { string match {a[xyz]c} abc } 0 test string-11.17 {string match} { string match {12[2-7]45} 12345 } 1 test string-11.18 {string match} { string match {12[ab2-4cd]45} 12345 } 1 test string-11.19 {string match} { string match {12[ab2-4cd]45} 12b45 } 1 test string-11.20 {string match} { string match {12[ab2-4cd]45} 12d45 } 1 test string-11.21 {string match} { string match {12[ab2-4cd]45} 12145 } 0 test string-11.22 {string match} { string match {12[ab2-4cd]45} 12545 } 0 test string-11.23 {string match} { string match {a\*b} a*b } 1 test string-11.24 {string match} { string match {a\*b} ab } 0 test string-11.25 {string match} { string match {a\*\?\[\]\\\x} "a*?\[\]\\x" } 1 test string-11.26 {string match} { string match ** "" } 1 test string-11.27 {string match} { string match *. "" } 0 test string-11.28 {string match} { string match "" "" } 1 test string-11.29 {string match} { string match \[a a } 1 test string-11.30 {string match, bad args} { list [catch {string match - b c} msg] $msg } {1 {bad option "-": must be -nocase}} test string-11.31 {string match case} { string match a A } 0 test string-11.32 {string match nocase} { string match -n a A } 1 test string-11.33 {string match nocase} { string match -nocase a\334 A\374 } 1 test string-11.34 {string match nocase} { string match -nocase a*f ABCDEf } 1 test string-11.35 {string match case, false hope} { # This is true because '_' lies between the A-Z and a-z ranges string match {[A-z]} _ } 1 test string-11.36 {string match nocase range} { # This is false because although '_' lies between the A-Z and a-z ranges, # we lower case the end points before checking the ranges. string match -nocase {[A-z]} _ } 0 test string-11.37 {string match nocase} { string match -nocase {[A-fh-Z]} g } 0 test string-11.38 {string match case, reverse range} { string match {[A-fh-Z]} g } 1 test string-11.39 {string match, *\ case} { string match {*\abc} abc } 1 test string-11.40 {string match, *special case} { string match {*[ab]} abc } 0 test string-11.41 {string match, *special case} { string match {*[ab]*} abc } 1 test string-11.42 {string match, *special case} { string match "*\\" "\\" } 0 test string-11.43 {string match, *special case} { string match "*\\\\" "\\" } 1 test string-11.44 {string match, *special case} { string match "*???" "12345" } 1 test string-11.45 {string match, *special case} { string match "*???" "12" } 0 test string-11.46 {string match, *special case} { string match "*\\*" "abc*" } 1 test string-11.47 {string match, *special case} { string match "*\\*" "*" } 1 test string-11.48 {string match, *special case} { string match "*\\*" "*abc" } 0 test string-11.49 {string match, *special case} { string match "?\\*" "a*" } 1 test string-11.50 {string match, *special case} { string match "\\" "\\" } 0 test string-11.51 {string match; *, -nocase and UTF-8} { string match -nocase [binary format I 717316707] \ [binary format I 2028036707] } 1 test string-11.52 {string match, null char in string} { set out "" set ptn "*abc*" foreach elem [list "\u0000@abc" "@abc" "\u0000@abc\u0000" "blahabcblah"] { lappend out [string match $ptn $elem] } set out } {1 1 1 1} test string-11.53 {string match, null char in pattern} { set out "" foreach {ptn elem} [list \ "*\u0000abc\u0000" "\u0000abc\u0000" \ "*\u0000abc\u0000" "\u0000abc\u0000ef" \ "*\u0000abc\u0000*" "\u0000abc\u0000ef" \ "*\u0000abc\u0000" "@\u0000abc\u0000ef" \ "*\u0000abc\u0000*" "@\u0000abc\u0000ef" \ ] { lappend out [string match $ptn $elem] } set out } {1 0 1 0 1} test string-11.54 {string match, failure} { set longString "" for {set i 0} {$i < 10} {incr i} { append longString "abcdefghijklmnopqrstuvwxy\u0000z01234567890123" } string first $longString 123 list [string match *cba* $longString] \ [string match *a*l*\u0000* $longString] \ [string match *a*l*\u0000*123 $longString] \ [string match *a*l*\u0000*123* $longString] \ [string match *a*l*\u0000*cba* $longString] \ [string match *===* $longString] } {0 1 1 1 0 0} test string-12.1 {string range} { list [catch {string range} msg] $msg } {1 {wrong # args: should be "string range string first last"}} test string-12.2 {string range} { list [catch {string range a 1} msg] $msg } {1 {wrong # args: should be "string range string first last"}} test string-12.3 {string range} { list [catch {string range a 1 2 3} msg] $msg } {1 {wrong # args: should be "string range string first last"}} test string-12.4 {string range} { string range abcdefghijklmnop 2 14 } {cdefghijklmno} test string-12.5 {string range, last > length} { string range abcdefghijklmnop 7 1000 } {hijklmnop} test string-12.6 {string range} { string range abcdefghijklmnop 10 e } {klmnop} test string-12.7 {string range, last < first} { string range abcdefghijklmnop 10 9 } {} test string-12.8 {string range, first < 0} { string range abcdefghijklmnop -3 2 } {abc} test string-12.9 {string range} { string range abcdefghijklmnop -3 -2 } {} test string-12.10 {string range} { string range abcdefghijklmnop 1000 1010 } {} test string-12.11 {string range} { string range abcdefghijklmnop -100 end } {abcdefghijklmnop} test string-12.12 {string range} { list [catch {string range abc abc 1} msg] $msg } {1 {bad index "abc": must be integer or end?-integer?}} test string-12.13 {string range} { list [catch {string range abc 1 eof} msg] $msg } {1 {bad index "eof": must be integer or end?-integer?}} test string-12.14 {string range} { string range abcdefghijklmnop end-1 end } {op} test string-12.15 {string range} { string range abcdefghijklmnop e 1000 } {p} test string-12.16 {string range} { string range abcdefghijklmnop end end-1 } {} test string-12.17 {string range, unicode} { string range ab\u7266cdefghijklmnop 5 5 } e test string-12.18 {string range, unicode} { string range ab\u7266cdefghijklmnop 2 3 } \u7266c test string-12.19 {string range, bytearray object} { set b [binary format I* {0x50515253 0x52}] set r1 [string range $b 1 end-1] set r2 [string range $b 1 6] string equal $r1 $r2 } 1 test string-12.20 {string range, out of bounds indices} { string range \u00ff 0 1 } \u00ff test string-12.21 {string range, regenerates correct reps, bug 1410553} { set bytes "\x00 \x03 \x41" set rxBuffer {} foreach ch $bytes { append rxBuffer $ch if {$ch eq "\x03"} { string length $rxBuffer } } set rxCRC [string range $rxBuffer end-1 end] binary scan [join $bytes {}] "H*" input_hex binary scan $rxBuffer "H*" rxBuffer_hex binary scan $rxCRC "H*" rxCRC_hex list $input_hex $rxBuffer_hex $rxCRC_hex } {000341 000341 0341} test string-13.1 {string repeat} { list [catch {string repeat} msg] $msg } {1 {wrong # args: should be "string repeat string count"}} test string-13.2 {string repeat} { list [catch {string repeat abc 10 oops} msg] $msg } {1 {wrong # args: should be "string repeat string count"}} test string-13.3 {string repeat} { string repeat {} 100 } {} test string-13.4 {string repeat} { string repeat { } 5 } { } test string-13.5 {string repeat} { string repeat abc 3 } {abcabcabc} test string-13.6 {string repeat} { string repeat abc -1 } {} test string-13.7 {string repeat} { list [catch {string repeat abc end} msg] $msg } {1 {expected integer but got "end"}} test string-13.8 {string repeat} { string repeat {} -1000 } {} test string-13.9 {string repeat} { string repeat {} 0 } {} test string-13.10 {string repeat} { string repeat def 0 } {} test string-13.11 {string repeat} { string repeat def 1 } def test string-13.12 {string repeat} { string repeat ab\u7266cd 3 } ab\u7266cdab\u7266cdab\u7266cd test string-13.13 {string repeat} { string repeat \x00 3 } \x00\x00\x00 test string-13.14 {string repeat} { # The string range will ensure us that string repeat gets a unicode string string repeat [string range ab\u7266cd 2 3] 3 } \u7266c\u7266c\u7266c test string-14.1 {string replace} { list [catch {string replace} msg] $msg } {1 {wrong # args: should be "string replace string first last ?string?"}} test string-14.2 {string replace} { list [catch {string replace a 1} msg] $msg } {1 {wrong # args: should be "string replace string first last ?string?"}} test string-14.3 {string replace} { list [catch {string replace a 1 2 3 4} msg] $msg } {1 {wrong # args: should be "string replace string first last ?string?"}} test string-14.4 {string replace} { } {} test string-14.5 {string replace} { string replace abcdefghijklmnop 2 14 } {abp} test string-14.6 {string replace} { string replace abcdefghijklmnop 7 1000 } {abcdefg} test string-14.7 {string replace} { string replace abcdefghijklmnop 10 e } {abcdefghij} test string-14.8 {string replace} { string replace abcdefghijklmnop 10 9 } {abcdefghijklmnop} test string-14.9 {string replace} { string replace abcdefghijklmnop -3 2 } {defghijklmnop} test string-14.10 {string replace} { string replace abcdefghijklmnop -3 -2 } {abcdefghijklmnop} test string-14.11 {string replace} { string replace abcdefghijklmnop 1000 1010 } {abcdefghijklmnop} test string-14.12 {string replace} { string replace abcdefghijklmnop -100 end } {} test string-14.13 {string replace} { list [catch {string replace abc abc 1} msg] $msg } {1 {bad index "abc": must be integer or end?-integer?}} test string-14.14 {string replace} { list [catch {string replace abc 1 eof} msg] $msg } {1 {bad index "eof": must be integer or end?-integer?}} test string-14.15 {string replace} { string replace abcdefghijklmnop end-10 end-2 NEW } {abcdeNEWop} test string-14.16 {string replace} { string replace abcdefghijklmnop 0 e foo } {foo} test string-14.17 {string replace} { string replace abcdefghijklmnop end end-1 } {abcdefghijklmnop} test string-15.1 {string tolower too few args} { list [catch {string tolower} msg] $msg } {1 {wrong # args: should be "string tolower string ?first? ?last?"}} test string-15.2 {string tolower bad args} { list [catch {string tolower a b} msg] $msg } {1 {bad index "b": must be integer or end?-integer?}} test string-15.3 {string tolower too many args} { list [catch {string tolower ABC 1 end oops} msg] $msg } {1 {wrong # args: should be "string tolower string ?first? ?last?"}} test string-15.4 {string tolower} { string tolower ABCDeF } {abcdef} test string-15.5 {string tolower} { string tolower "ABC XyZ" } {abc xyz} test string-15.6 {string tolower} { string tolower {123#$&*()} } {123#$&*()} test string-15.7 {string tolower} { string tolower ABC 1 } AbC test string-15.8 {string tolower} { string tolower ABC 1 end } Abc test string-15.9 {string tolower} { string tolower ABC 0 end-1 } abC test string-15.10 {string tolower, unicode} { string tolower ABCabc\xc7\xe7 } "abcabc\xe7\xe7" test string-16.1 {string toupper} { list [catch {string toupper} msg] $msg } {1 {wrong # args: should be "string toupper string ?first? ?last?"}} test string-16.2 {string toupper} { list [catch {string toupper a b} msg] $msg } {1 {bad index "b": must be integer or end?-integer?}} test string-16.3 {string toupper} { list [catch {string toupper a 1 end oops} msg] $msg } {1 {wrong # args: should be "string toupper string ?first? ?last?"}} test string-16.4 {string toupper} { string toupper abCDEf } {ABCDEF} test string-16.5 {string toupper} { string toupper "abc xYz" } {ABC XYZ} test string-16.6 {string toupper} { string toupper {123#$&*()} } {123#$&*()} test string-16.7 {string toupper} { string toupper abc 1 } aBc test string-16.8 {string toupper} { string toupper abc 1 end } aBC test string-16.9 {string toupper} { string toupper abc 0 end-1 } ABc test string-16.10 {string toupper, unicode} { string toupper ABCabc\xc7\xe7 } "ABCABC\xc7\xc7" test string-17.1 {string totitle} { list [catch {string totitle} msg] $msg } {1 {wrong # args: should be "string totitle string ?first? ?last?"}} test string-17.2 {string totitle} { list [catch {string totitle a b} msg] $msg } {1 {bad index "b": must be integer or end?-integer?}} test string-17.3 {string totitle} { string totitle abCDEf } {Abcdef} test string-17.4 {string totitle} { string totitle "abc xYz" } {Abc xyz} test string-17.5 {string totitle} { string totitle {123#$&*()} } {123#$&*()} test string-17.6 {string totitle, unicode} { string totitle ABCabc\xc7\xe7 } "Abcabc\xe7\xe7" test string-17.7 {string totitle, unicode} { string totitle \u01f3BCabc\xc7\xe7 } "\u01f2bcabc\xe7\xe7" test string-18.1 {string trim} { list [catch {string trim} msg] $msg } {1 {wrong # args: should be "string trim string ?chars?"}} test string-18.2 {string trim} { list [catch {string trim a b c} msg] $msg } {1 {wrong # args: should be "string trim string ?chars?"}} test string-18.3 {string trim} { string trim " XYZ " } {XYZ} test string-18.4 {string trim} { string trim "\t\nXYZ\t\n\r\n" } {XYZ} test string-18.5 {string trim} { string trim " A XYZ A " } {A XYZ A} test string-18.6 {string trim} { string trim "XXYYZZABC XXYYZZ" ZYX } {ABC } test string-18.7 {string trim} { string trim " \t\r " } {} test string-18.8 {string trim} { string trim {abcdefg} {} } {abcdefg} test string-18.9 {string trim} { string trim {} } {} test string-18.10 {string trim} { string trim ABC DEF } {ABC} test string-18.11 {string trim, unicode} { string trim "\xe7\xe8 AB\xe7C \xe8\xe7" \xe7\xe8 } " AB\xe7C " test string-19.1 {string trimleft} { list [catch {string trimleft} msg] $msg } {1 {wrong # args: should be "string trimleft string ?chars?"}} test string-19.2 {string trimleft} { string trimleft " XYZ " } {XYZ } test string-20.1 {string trimright errors} { list [catch {string trimright} msg] $msg } {1 {wrong # args: should be "string trimright string ?chars?"}} test string-20.2 {string trimright errors} { list [catch {string trimg a} msg] $msg } {1 {bad option "trimg": must be bytelength, compare, equal, first, index, is, last, length, map, match, range, repeat, replace, tolower, toupper, totitle, trim, trimleft, trimright, wordend, or wordstart}} test string-20.3 {string trimright} { string trimright " XYZ " } { XYZ} test string-20.4 {string trimright} { string trimright " " } {} test string-20.5 {string trimright} { string trimright "" } {} test string-21.1 {string wordend} { list [catch {string wordend a} msg] $msg } {1 {wrong # args: should be "string wordend string index"}} test string-21.2 {string wordend} { list [catch {string wordend a b c} msg] $msg } {1 {wrong # args: should be "string wordend string index"}} test string-21.3 {string wordend} { list [catch {string wordend a gorp} msg] $msg } {1 {bad index "gorp": must be integer or end?-integer?}} test string-21.4 {string wordend} { string wordend abc. -1 } 3 test string-21.5 {string wordend} { string wordend abc. 100 } 4 test string-21.6 {string wordend} { string wordend "word_one two three" 2 } 8 test string-21.7 {string wordend} { string wordend "one .&# three" 5 } 6 test string-21.8 {string wordend} { string worde "x.y" 0 } 1 test string-21.9 {string wordend} { string worde "x.y" end-1 } 2 test string-21.10 {string wordend, unicode} { string wordend "xyz\u00c7de fg" 0 } 6 test string-21.11 {string wordend, unicode} { string wordend "xyz\uc700de fg" 0 } 6 test string-21.12 {string wordend, unicode} { string wordend "xyz\u203fde fg" 0 } 6 test string-21.13 {string wordend, unicode} { string wordend "xyz\u2045de fg" 0 } 3 test string-21.14 {string wordend, unicode} { string wordend "\uc700\uc700 abc" 8 } 6 test string-22.1 {string wordstart} { list [catch {string word a} msg] $msg } {1 {ambiguous option "word": must be bytelength, compare, equal, first, index, is, last, length, map, match, range, repeat, replace, tolower, toupper, totitle, trim, trimleft, trimright, wordend, or wordstart}} test string-22.2 {string wordstart} { list [catch {string wordstart a} msg] $msg } {1 {wrong # args: should be "string wordstart string index"}} test string-22.3 {string wordstart} { list [catch {string wordstart a b c} msg] $msg } {1 {wrong # args: should be "string wordstart string index"}} test string-22.4 {string wordstart} { list [catch {string wordstart a gorp} msg] $msg } {1 {bad index "gorp": must be integer or end?-integer?}} test string-22.5 {string wordstart} { string wordstart "one two three_words" 400 } 8 test string-22.6 {string wordstart} { string wordstart "one two three_words" 2 } 0 test string-22.7 {string wordstart} { string wordstart "one two three_words" -2 } 0 test string-22.8 {string wordstart} { string wordstart "one .*&^ three" 6 } 6 test string-22.9 {string wordstart} { string wordstart "one two three" 4 } 4 test string-22.10 {string wordstart} { string wordstart "one two three" end-5 } 7 test string-22.11 {string wordstart, unicode} { string wordstart "one tw\u00c7o three" 7 } 4 test string-22.12 {string wordstart, unicode} { string wordstart "ab\uc700\uc700 cdef ghi" 12 } 10 test string-22.13 {string wordstart, unicode} { string wordstart "\uc700\uc700 abc" 8 } 3 test string-23.0 {string is boolean, Bug 1187123} testindexobj { set x 5 catch {testindexobj $x foo bar soom} string is boolean $x } 0 # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/safe.test0000644003604700454610000004215011737050674013702 0ustar dgp771div# safe.test -- # # This file contains a collection of tests for safe Tcl, packages loading, # and using safe interpreters. Sourcing this file into tcl runs the tests # and generates output for errors. No output means no errors were found. # # Copyright (c) 1995-1996 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } foreach i [interp slaves] { interp delete $i } set saveAutoPath $::auto_path set ::auto_path [info library] # Force actual loading of the safe package # because we use un exported (and thus un-autoindexed) APIs # in this test result arguments: catch {safe::interpConfigure} proc equiv {x} {return $x} test safe-1.1 {safe::interpConfigure syntax} { list [catch {safe::interpConfigure} msg] $msg; } {1 {no value given for parameter "slave" (use -help for full usage) : slave name () name of the slave}} test safe-1.2 {safe::interpCreate syntax} { list [catch {safe::interpCreate -help} msg] $msg; } {1 {Usage information: Var/FlagName Type Value Help ------------ ---- ----- ---- ( -help gives this help ) ?slave? name () name of the slave (optional) -accessPath list () access path for the slave -noStatics boolflag (false) prevent loading of statically linked pkgs -statics boolean (true) loading of statically linked pkgs -nestedLoadOk boolflag (false) allow nested loading -nested boolean (false) nested loading -deleteHook script () delete hook}} test safe-1.3 {safe::interpInit syntax} { list [catch {safe::interpInit -noStatics} msg] $msg; } {1 {bad value "-noStatics" for parameter slave name () name of the slave}} test safe-2.1 {creating interpreters, should have no aliases} { interp aliases } "" test safe-2.2 {creating interpreters, should have no aliases} { catch {safe::interpDelete a} interp create a set l [a aliases] safe::interpDelete a set l } "" test safe-2.3 {creating safe interpreters, should have no aliases} { catch {safe::interpDelete a} interp create a -safe set l [a aliases] interp delete a set l } "" test safe-3.1 {calling safe::interpInit is safe} { catch {safe::interpDelete a} interp create a -safe safe::interpInit a catch {interp eval a exec ls} msg safe::interpDelete a set msg } {invalid command name "exec"} test safe-3.2 {calling safe::interpCreate on trusted interp} { catch {safe::interpDelete a} safe::interpCreate a set l [lsort [a aliases]] safe::interpDelete a set l } {encoding exit file load source} test safe-3.3 {calling safe::interpCreate on trusted interp} { catch {safe::interpDelete a} safe::interpCreate a set x [interp eval a {source [file join $tcl_library init.tcl]}] safe::interpDelete a set x } "" test safe-3.4 {calling safe::interpCreate on trusted interp} { catch {safe::interpDelete a} safe::interpCreate a catch {set x \ [interp eval a {source [file join $tcl_library init.tcl]}]} msg safe::interpDelete a list $x $msg } {{} {}} test safe-4.1 {safe::interpDelete} { catch {safe::interpDelete a} interp create a safe::interpDelete a } "" test safe-4.2 {safe::interpDelete, indirectly} { catch {safe::interpDelete a} interp create a a alias exit safe::interpDelete a a eval exit } "" test safe-4.3 {safe::interpDelete, state array (not a public api)} { catch {safe::interpDelete a} namespace eval safe {set [InterpStateName a](foo) 33} # not an error anymore to call it if interp is already # deleted, to make trhings smooth if it's called twice... catch {safe::interpDelete a} m1 catch {namespace eval safe {set [InterpStateName a](foo)}} m2 list $m1 $m2 } "{}\ {can't read \"[safe::InterpStateName a](foo)\": no such variable}" test safe-4.4 {safe::interpDelete, state array, indirectly (not a public api)} { catch {safe::interpDelete a} safe::interpCreate a namespace eval safe {set [InterpStateName a](foo) 33} a eval exit catch {namespace eval safe {set [InterpStateName a](foo)}} msg } 1 test safe-4.5 {safe::interpDelete} { catch {safe::interpDelete a} safe::interpCreate a catch {safe::interpCreate a} msg set msg } {interpreter named "a" already exists, cannot create} test safe-4.6 {safe::interpDelete, indirectly} { catch {safe::interpDelete a} safe::interpCreate a a eval exit } "" # The following test checks whether the definition of tcl_endOfWord can be # obtained from auto_loading. test safe-5.1 {test auto-loading in safe interpreters} { catch {safe::interpDelete a} safe::interpCreate a set r [catch {interp eval a {tcl_endOfWord "" 0}} msg] safe::interpDelete a list $r $msg } {0 -1} # test safe interps 'information leak' proc SI {} { global I set I [interp create -safe]; } proc DI {} { global I; interp delete $I; } test safe-6.1 {test safe interpreters knowledge of the world} { SI; set r [lsort [$I eval {info globals}]]; DI; set r } {tcl_interactive tcl_patchLevel tcl_platform tcl_version} test safe-6.2 {test safe interpreters knowledge of the world} { SI; set r [$I eval {info script}]; DI; set r } {} test safe-6.3 {test safe interpreters knowledge of the world} { SI set r [lsort [$I eval {array names tcl_platform}]] DI # If running a windows-debug shell, remove the "debug" element from r. if {$tcl_platform(platform) == "windows" && \ [lsearch $r "debug"] != -1} { set r [lreplace $r 1 1] } set threaded [lsearch $r "threaded"] if {$threaded != -1} { set r [lreplace $r $threaded $threaded] } set tip [lsearch $r "tip,268"] if {$tip != -1} { set r [lreplace $r $tip $tip] } set tip [lsearch $r "tip,280"] if {$tip != -1} { set r [lreplace $r $tip $tip] } set r } {byteOrder platform wordSize} # more test should be added to check that hostname, nameofexecutable, # aren't leaking infos, but they still do... # high level general test test safe-7.1 {tests that everything works at high level} { set i [safe::interpCreate]; # no error shall occur: # (because the default access_path shall include 1st level sub dirs # so package require in a slave works like in the master) set v [interp eval $i {package require http 1}] # no error shall occur: interp eval $i {http_config}; safe::interpDelete $i set v } 1.0 test safe-7.2 {tests specific path and interpFind/AddToAccessPath} { set i [safe::interpCreate -nostat -nested 1 -accessPath [list [info library]]]; # should not add anything (p0) set token1 [safe::interpAddToAccessPath $i [info library]] # should add as p1 set token2 [safe::interpAddToAccessPath $i "/dummy/unixlike/test/path"]; # an error shall occur (http is not anymore in the secure 0-level # provided deep path) list $token1 $token2 \ [catch {interp eval $i {package require http 1}} msg] $msg \ [safe::interpConfigure $i]\ [safe::interpDelete $i] } "{\$p(:0:)} {\$p(:1:)} 1 {can't find package http 1} {-accessPath {[list $tcl_library /dummy/unixlike/test/path]} -statics 0 -nested 1 -deleteHook {}} {}" # test source control on file name test safe-8.1 {safe source control on file} { set i "a"; catch {safe::interpDelete $i} safe::interpCreate $i; list [catch {$i eval {source}} msg] \ $msg \ [safe::interpDelete $i] ; } {1 {wrong # args: should be "source fileName"} {}} # test source control on file name test safe-8.2 {safe source control on file} { set i "a"; catch {safe::interpDelete $i} safe::interpCreate $i; list [catch {$i eval {source}} msg] \ $msg \ [safe::interpDelete $i] ; } {1 {wrong # args: should be "source fileName"} {}} test safe-8.3 {safe source control on file} { set i "a"; catch {safe::interpDelete $i} safe::interpCreate $i; set log {}; proc safe-test-log {str} {global log; lappend log $str} set prevlog [safe::setLogCmd]; safe::setLogCmd safe-test-log; list [catch {$i eval {source .}} msg] \ $msg \ $log \ [safe::setLogCmd $prevlog; unset log] \ [safe::interpDelete $i] ; } {1 {permission denied} {{ERROR for slave a : ".": is a directory}} {} {}} test safe-8.4 {safe source control on file} { set i "a"; catch {safe::interpDelete $i} safe::interpCreate $i; set log {}; proc safe-test-log {str} {global log; lappend log $str} set prevlog [safe::setLogCmd]; safe::setLogCmd safe-test-log; list [catch {$i eval {source /abc/def}} msg] \ $msg \ $log \ [safe::setLogCmd $prevlog; unset log] \ [safe::interpDelete $i] ; } {1 {permission denied} {{ERROR for slave a : "/abc/def": not in access_path}} {} {}} test safe-8.5 {safe source control on file} { # This tested filename == *.tcl or tclIndex, but that restriction # was removed in 8.4a4 - hobbs set i "a"; catch {safe::interpDelete $i} safe::interpCreate $i; set log {}; proc safe-test-log {str} {global log; lappend log $str} set prevlog [safe::setLogCmd]; safe::setLogCmd safe-test-log; list [catch {$i eval {source [file join [info lib] blah]}} msg] \ $msg \ $log \ [safe::setLogCmd $prevlog; unset log] \ [safe::interpDelete $i] ; } [list 1 {no such file or directory} [list "ERROR for slave a : [file join [info library] blah]:no such file or directory"] {} {}] test safe-8.6 {safe source control on file} { set i "a"; catch {safe::interpDelete $i} safe::interpCreate $i; set log {}; proc safe-test-log {str} {global log; lappend log $str} set prevlog [safe::setLogCmd]; safe::setLogCmd safe-test-log; list [catch {$i eval {source [file join [info lib] blah.tcl]}} msg] \ $msg \ $log \ [safe::setLogCmd $prevlog; unset log] \ [safe::interpDelete $i] ; } [list 1 {no such file or directory} [list "ERROR for slave a : [file join [info library] blah.tcl]:no such file or directory"] {} {}] test safe-8.7 {safe source control on file} { # This tested length of filename, but that restriction # was removed in 8.4a4 - hobbs set i "a"; catch {safe::interpDelete $i} safe::interpCreate $i; set log {}; proc safe-test-log {str} {global log; lappend log $str} set prevlog [safe::setLogCmd]; safe::setLogCmd safe-test-log; list [catch {$i eval {source [file join [info lib] xxxxxxxxxxx.tcl]}}\ msg] \ $msg \ $log \ [safe::setLogCmd $prevlog; unset log] \ [safe::interpDelete $i] ; } [list 1 {no such file or directory} [list "ERROR for slave a : [file join [info library] xxxxxxxxxxx.tcl]:no such file or directory"] {} {}] test safe-8.8 {safe source forbids -rsrc} { set i "a"; catch {safe::interpDelete $i} safe::interpCreate $i; list [catch {$i eval {source -rsrc Init}} msg] \ $msg \ [safe::interpDelete $i] ; } {1 {wrong # args: should be "source fileName"} {}} test safe-9.1 {safe interps' deleteHook} { set i "a"; catch {safe::interpDelete $i} set res {} proc testDelHook {args} { global res; # the interp still exists at that point interp eval a {set delete 1} # mark that we've been here (successfully) set res $args; } safe::interpCreate $i -deleteHook "testDelHook arg1 arg2"; list [interp eval $i exit] $res } {{} {arg1 arg2 a}} test safe-9.2 {safe interps' error in deleteHook} { set i "a"; catch {safe::interpDelete $i} set res {} proc testDelHook {args} { global res; # the interp still exists at that point interp eval a {set delete 1} # mark that we've been here (successfully) set res $args; # create an exception error "being catched"; } set log {}; proc safe-test-log {str} {global log; lappend log $str} safe::interpCreate $i -deleteHook "testDelHook arg1 arg2"; set prevlog [safe::setLogCmd]; safe::setLogCmd safe-test-log; list [safe::interpDelete $i] $res \ $log \ [safe::setLogCmd $prevlog; unset log]; } {{} {arg1 arg2 a} {{NOTICE for slave a : About to delete} {ERROR for slave a : Delete hook error (being catched)} {NOTICE for slave a : Deleted}} {}} test safe-9.3 {dual specification of statics} { list [catch {safe::interpCreate -stat true -nostat} msg] $msg } {1 {conflicting values given for -statics and -noStatics}} test safe-9.4 {dual specification of statics} { # no error shall occur safe::interpDelete [safe::interpCreate -stat false -nostat] } {} test safe-9.5 {dual specification of nested} { list [catch {safe::interpCreate -nested 0 -nestedload} msg] $msg } {1 {conflicting values given for -nested and -nestedLoadOk}} test safe-9.6 {interpConfigure widget like behaviour} { # this test shall work, don't try to "fix it" unless # you *really* know what you are doing (ie you are me :p) -- dl list [set i [safe::interpCreate \ -noStatics \ -nestedLoadOk \ -deleteHook {foo bar}]; safe::interpConfigure $i -accessPath /foo/bar ; safe::interpConfigure $i]\ [safe::interpConfigure $i -aCCess]\ [safe::interpConfigure $i -nested]\ [safe::interpConfigure $i -statics]\ [safe::interpConfigure $i -DEL]\ [safe::interpConfigure $i -accessPath /blah -statics 1; safe::interpConfigure $i]\ [safe::interpConfigure $i -deleteHook toto -nosta -nested 0; safe::interpConfigure $i] } {{-accessPath /foo/bar -statics 0 -nested 1 -deleteHook {foo bar}} {-accessPath /foo/bar} {-nested 1} {-statics 0} {-deleteHook {foo bar}} {-accessPath /blah -statics 1 -nested 1 -deleteHook {foo bar}} {-accessPath /blah -statics 0 -nested 0 -deleteHook toto}} # testing that nested and statics do what is advertised # (we use a static package : Tcltest) if {[catch {package require Tcltest} msg]} { puts "This application hasn't been compiled with Tcltest" puts "skipping remining safe test that relies on it." } else { # we use the Tcltest package , which has no Safe_Init test safe-10.1 {testing statics loading} { set i [safe::interpCreate] list \ [catch {interp eval $i {load {} Tcltest}} msg] \ $msg \ [safe::interpDelete $i]; } {1 {can't use package in a safe interpreter: no Tcltest_SafeInit procedure} {}} test safe-10.2 {testing statics loading / -nostatics} { set i [safe::interpCreate -nostatics] list \ [catch {interp eval $i {load {} Tcltest}} msg] \ $msg \ [safe::interpDelete $i]; } {1 {permission denied (static package)} {}} test safe-10.3 {testing nested statics loading / no nested by default} { set i [safe::interpCreate] list \ [catch {interp eval $i {interp create x; load {} Tcltest x}} msg] \ $msg \ [safe::interpDelete $i]; } {1 {permission denied (nested load)} {}} test safe-10.4 {testing nested statics loading / -nestedloadok} { set i [safe::interpCreate -nestedloadok] list \ [catch {interp eval $i {interp create x; load {} Tcltest x}} msg] \ $msg \ [safe::interpDelete $i]; } {1 {can't use package in a safe interpreter: no Tcltest_SafeInit procedure} {}} } test safe-11.1 {testing safe encoding} { set i [safe::interpCreate] list \ [catch {interp eval $i encoding} msg] \ $msg \ [safe::interpDelete $i]; } {1 {wrong # args: should be "encoding option ?arg ...?"} {}} test safe-11.2 {testing safe encoding} { set i [safe::interpCreate] list \ [catch {interp eval $i encoding system cp775} msg] \ $msg \ [safe::interpDelete $i]; } {1 {wrong # args: should be "encoding system"} {}} test safe-11.3 {testing safe encoding} { set i [safe::interpCreate] set result [catch { string match [encoding system] [interp eval $i encoding system] } msg] list $result $msg [safe::interpDelete $i] } {0 1 {}} test safe-11.4 {testing safe encoding} { set i [safe::interpCreate] set result [catch { string match [encoding names] [interp eval $i encoding names] } msg] list $result $msg [safe::interpDelete $i] } {0 1 {}} test safe-11.5 {testing safe encoding} { set i [safe::interpCreate] list \ [catch {interp eval $i encoding convertfrom cp1258 foobar} msg] \ $msg \ [safe::interpDelete $i]; } {0 foobar {}} test safe-11.6 {testing safe encoding} { set i [safe::interpCreate] list \ [catch {interp eval $i encoding convertto cp1258 foobar} msg] \ $msg \ [safe::interpDelete $i]; } {0 foobar {}} test safe-11.7 {testing safe encoding} { set i [safe::interpCreate] list \ [catch {interp eval $i encoding convertfrom} msg] \ $msg \ [safe::interpDelete $i]; } {1 {wrong # args: should be "encoding convertfrom ?encoding? data"} {}} test safe-11.8 {testing safe encoding} { set i [safe::interpCreate] list \ [catch {interp eval $i encoding convertto} msg] \ $msg \ [safe::interpDelete $i]; } {1 {wrong # args: should be "encoding convertto ?encoding? data"} {}} set ::auto_path $saveAutoPath # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/history.test0000644003604700454610000001533111737050674014466 0ustar dgp771div# Commands covered: history # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } if {[catch {history}]} { puts stdout "This version of Tcl was built without the history command;\n" puts stdout "history tests will be skipped.\n" ::tcltest::cleanupTests return } set num [history nextid] history keep 3 history add {set a 12345} history add {set b [format {A test %s} string]} history add {Another test} # "history event" test history-1.1 {event option} {history event -1} \ {set b [format {A test %s} string]} test history-1.2 {event option} {history event $num} \ {set a 12345} test history-1.3 {event option} {history event [expr $num+2]} \ {Another test} test history-1.4 {event option} {history event set} \ {set b [format {A test %s} string]} test history-1.5 {event option} {history e "* a*"} \ {set a 12345} test history-1.6 {event option} {catch {history event *gorp} msg} 1 test history-1.7 {event option} { catch {history event *gorp} msg set msg } {no event matches "*gorp"} test history-1.8 {event option} {history event} \ {set b [format {A test %s} string]} test history-1.9 {event option} {catch {history event 123 456} msg} 1 test history-1.10 {event option} { catch {history event 123 456} msg set msg } {wrong # args: should be "history event ?event?"} # "history redo" set a 0 history redo -2 test history-2.1 {redo option} {set a} 12345 set b 0 history redo test history-2.2 {redo option} {set b} {A test string} test history-2.3 {redo option} {catch {history redo -3 -4}} 1 test history-2.4 {redo option} { catch {history redo -3 -4} msg set msg } {wrong # args: should be "history redo ?event?"} # "history add" history add "set a 444" exec test history-3.1 {add option} {set a} 444 test history-3.2 {add option} {catch {history add "set a 444" execGorp}} 1 test history-3.3 {add option} { catch {history add "set a 444" execGorp} msg set msg } {bad argument "execGorp": should be "exec"} test history-3.4 {add option} {catch {history add "set a 444" a} msg} 1 test history-3.5 {add option} { catch {history add "set a 444" a} msg set msg } {bad argument "a": should be "exec"} history add "set a 555" e test history-3.6 {add option} {set a} 555 history add "set a 666" test history-3.7 {add option} {set a} 555 test history-3.8 {add option} {catch {history add "set a 666" e f} msg} 1 test history-3.9 {add option} { catch {history add "set a 666" e f} msg set msg } {wrong # args: should be "history add event ?exec?"} # "history change" history change "A test value" test history-4.1 {change option} {history event [expr {[history n]-1}]} \ "A test value" history ch "Another test" -1 test history-4.2 {change option} {history e} "Another test" test history-4.3 {change option} {history event [expr {[history n]-1}]} \ "A test value" test history-4.4 {change option} {catch {history change Foo 4 10}} 1 test history-4.5 {change option} { catch {history change Foo 4 10} msg set msg } {wrong # args: should be "history change newValue ?event?"} test history-4.6 {change option} { catch {history change Foo [expr {[history n]-4}]} } 1 set num [expr {[history n]-4}] test history-4.7 {change option} { catch {history change Foo $num} msg set msg } "event \"$num\" is too far in the past" # "history info" set num [history n] history add set\ a\ {b\nc\ d\ e} history add {set b 1234} history add set\ c\ {a\nb\nc} test history-5.1 {info option} {history info} [format {%6d set a {b c d e} %6d set b 1234 %6d set c {a b c}} $num [expr $num+1] [expr $num+2]] test history-5.2 {info option} {history i 2} [format {%6d set b 1234 %6d set c {a b c}} [expr $num+1] [expr $num+2]] test history-5.3 {info option} {catch {history i 2 3}} 1 test history-5.4 {info option} { catch {history i 2 3} msg set msg } {wrong # args: should be "history info ?count?"} test history-5.5 {info option} {history} [format {%6d set a {b c d e} %6d set b 1234 %6d set c {a b c}} $num [expr $num+1] [expr $num+2]] # "history keep" history add "foo1" history add "foo2" history add "foo3" history keep 2 test history-6.1 {keep option} {history event [expr [history n]-1]} foo3 test history-6.2 {keep option} {history event -1} foo2 test history-6.3 {keep option} {catch {history event -3}} 1 test history-6.4 {keep option} { catch {history event -3} msg set msg } {event "-3" is too far in the past} history k 5 test history-6.5 {keep option} {history event -1} foo2 test history-6.6 {keep option} {history event -2} {} test history-6.7 {keep option} {history event -3} {} test history-6.8 {keep option} {history event -4} {} test history-6.9 {keep option} {catch {history event -5}} 1 test history-6.10 {keep option} {catch {history keep 4 6}} 1 test history-6.11 {keep option} { catch {history keep 4 6} msg set msg } {wrong # args: should be "history keep ?count?"} test history-6.12 {keep option} {catch {history keep}} 0 test history-6.13 {keep option} { history keep } {5} test history-6.14 {keep option} {catch {history keep -3}} 1 test history-6.15 {keep option} { catch {history keep -3} msg set msg } {illegal keep count "-3"} test history-6.16 {keep option} { catch {history keep butter} msg set msg } {illegal keep count "butter"} # "history nextid" set num [history n] history add "Testing" history add "Testing2" test history-7.1 {nextid option} {history event} "Testing" test history-7.2 {nextid option} {history next} [expr $num+2] test history-7.3 {nextid option} {catch {history nextid garbage}} 1 test history-7.4 {nextid option} { catch {history nextid garbage} msg set msg } {wrong # args: should be "history nextid"} # "history clear" set num [history n] history add "Testing" history add "Testing2" test history-8.1 {clear option} {catch {history clear junk}} 1 test history-8.2 {clear option} {history clear} {} history add "Testing" test history-8.3 {clear option} {history} { 1 Testing} # miscellaneous test history-9.1 {miscellaneous} {catch {history gorp} msg} 1 test history-9.2 {miscellaneous} { catch {history gorp} msg set msg } {bad option "gorp": must be add, change, clear, event, info, keep, nextid, or redo} # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/format.test0000644003604700454610000004621011737050674014255 0ustar dgp771div# Commands covered: format # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1994 The Regents of the University of California. # Copyright (c) 1994-1998 Sun Microsystems, Inc. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import -force ::tcltest::* } # The following code is needed because some versions of SCO Unix have # a round-off error in sprintf which would cause some of the tests to # fail. Someday I hope this code shouldn't be necessary (code added # 9/9/91). set ::tcltest::testConstraints(roundOffBug) \ [expr {"[format %7.1e 68.514]" != "6.8e+01"}] test format-1.1 {integer formatting} { format "%*d %d %d %d" 6 34 16923 -12 -1 } { 34 16923 -12 -1} test format-1.2 {integer formatting} {nonPortable} { format "%4d %4d %4d %4d %d %#x %#X" 6 34 16923 -12 -1 14 12 } { 6 34 16923 -12 -1 0xe 0XC} # %u output depends on word length, so this test is not portable. test format-1.3 {integer formatting} {nonPortable} { format "%4u %4u %4u %4u %d %#o" 6 34 16923 -12 -1 0 } { 6 34 16923 4294967284 -1 0} test format-1.4 {integer formatting} { format "%-4d %-4i %-4d %-4ld" 6 34 16923 -12 -1 } {6 34 16923 -12 } test format-1.5 {integer formatting} { format "%04d %04d %04d %04i" 6 34 16923 -12 -1 } {0006 0034 16923 -012} test format-1.6 {integer formatting} { format "%00*d" 6 34 } {000034} # Printing negative numbers in hex or octal format depends on word # length, so these tests are not portable. test format-1.7 {integer formatting} {nonPortable} { format "%4x %4x %4x %4x" 6 34 16923 -12 -1 } { 6 22 421b fffffff4} test format-1.8 {integer formatting} {nonPortable} { format "%#x %#X %#X %#x" 6 34 16923 -12 -1 } {0x6 0X22 0X421B 0xfffffff4} test format-1.9 {integer formatting} {nonPortable} { format "%#20x %#20x %#20x %#20x" 6 34 16923 -12 -1 } { 0x6 0x22 0x421b 0xfffffff4} test format-1.10 {integer formatting} {nonPortable} { format "%-#20x %-#20x %-#20x %-#20x" 6 34 16923 -12 -1 } {0x6 0x22 0x421b 0xfffffff4 } test format-1.11 {integer formatting} {nonPortable} { format "%-#20o %#-20o %#-20o %#-20o" 6 34 16923 -12 -1 } {06 042 041033 037777777764 } test format-2.1 {string formatting} { format "%s %s %c %s" abcd {This is a very long test string.} 120 x } {abcd This is a very long test string. x x} test format-2.2 {string formatting} { format "%20s %20s %20c %20s" abcd {This is a very long test string.} 120 x } { abcd This is a very long test string. x x} test format-2.3 {string formatting} { format "%.10s %.10s %c %.10s" abcd {This is a very long test string.} 120 x } {abcd This is a x x} test format-2.4 {string formatting} { format "%s %s %% %c %s" abcd {This is a very long test string.} 120 x } {abcd This is a very long test string. % x x} test format-2.5 {string formatting, embedded nulls} { format "%10s" abc\0def } " abc\0def" test format-2.6 {string formatting, international chars} { format "%10s" abc\ufeffdef } " abc\ufeffdef" test format-2.7 {string formatting, international chars} { format "%.5s" abc\ufeffdef } "abc\ufeffd" test format-2.8 {string formatting, international chars} { format "foo\ufeffbar%s" baz } "foo\ufeffbarbaz" test format-2.9 {string formatting, width} { format "a%5sa" f } "a fa" test format-2.10 {string formatting, width} { format "a%-5sa" f } "af a" test format-2.11 {string formatting, width} { format "a%2sa" foo } "afooa" test format-2.12 {string formatting, width} { format "a%0sa" foo } "afooa" test format-2.13 {string formatting, precision} { format "a%.2sa" foobarbaz } "afoa" test format-2.14 {string formatting, precision} { format "a%.sa" foobarbaz } "aa" test format-2.15 {string formatting, precision} { list [catch {format "a%.-2sa" foobarbaz} msg] $msg } {1 {bad field specifier "-"}} test format-2.16 {string formatting, width and precision} { format "a%5.2sa" foobarbaz } "a foa" test format-2.17 {string formatting, width and precision} { format "a%5.7sa" foobarbaz } "afoobarba" test format-3.1 {Tcl_FormatObjCmd: character formatting} { format "|%c|%0c|%-1c|%1c|%-6c|%6c|%*c|%*c|" 65 65 65 65 65 65 3 65 -4 65 } "|A|A|A|A|A | A| A|A |" test format-3.2 {Tcl_FormatObjCmd: international character formatting} { format "|%c|%0c|%-1c|%1c|%-6c|%6c|%*c|%*c|" 0xa2 0x4e4e 0x25a 0xc3 0xff08 0 3 0x6575 -4 0x4e4f } "|\ua2|\u4e4e|\u25a|\uc3|\uff08 | \0| \u6575|\u4e4f |" test format-4.1 {e and f formats} {eformat} { format "%e %e %e %e" 34.2e12 68.514 -.125 -16000. .000053 } {3.420000e+13 6.851400e+01 -1.250000e-01 -1.600000e+04} test format-4.2 {e and f formats} {eformat} { format "%20e %20e %20e %20e" 34.2e12 68.514 -.125 -16000. .000053 } { 3.420000e+13 6.851400e+01 -1.250000e-01 -1.600000e+04} test format-4.3 {e and f formats} {eformat roundOffBug} { format "%.1e %.1e %.1e %.1e" 34.2e12 68.514 -.126 -16000. .000053 } {3.4e+13 6.9e+01 -1.3e-01 -1.6e+04} test format-4.4 {e and f formats} {eformat roundOffBug} { format "%020e %020e %020e %020e" 34.2e12 68.514 -.126 -16000. .000053 } {000000003.420000e+13 000000006.851400e+01 -00000001.260000e-01 -00000001.600000e+04} test format-4.5 {e and f formats} {eformat roundOffBug} { format "%7.1e %7.1e %7.1e %7.1e" 34.2e12 68.514 -.126 -16000. .000053 } {3.4e+13 6.9e+01 -1.3e-01 -1.6e+04} test format-4.6 {e and f formats roundOffBug} { format "%f %f %f %f" 34.2e12 68.514 -.125 -16000. .000053 } {34200000000000.000000 68.514000 -0.125000 -16000.000000} test format-4.7 {e and f formats} {nonPortable} { format "%.4f %.4f %.4f %.4f %.4f" 34.2e12 68.514 -.125 -16000. .000053 } {34200000000000.0000 68.5140 -0.1250 -16000.0000 0.0001} test format-4.8 {e and f formats} {eformat} { format "%.4e %.5e %.6e" -9.99996 -9.99996 9.99996 } {-1.0000e+01 -9.99996e+00 9.999960e+00} test format-4.9 {e and f formats} { format "%.4f %.5f %.6f" -9.99996 -9.99996 9.99996 } {-10.0000 -9.99996 9.999960} test format-4.10 {e and f formats} { format "%20f %-20f %020f" -9.99996 -9.99996 9.99996 } { -9.999960 -9.999960 0000000000009.999960} test format-4.11 {e and f formats} { format "%-020f %020f" -9.99996 -9.99996 9.99996 } {-9.999960 -000000000009.999960} test format-4.12 {e and f formats} {eformat} { format "%.0e %#.0e" -9.99996 -9.99996 9.99996 } {-1e+01 -1.e+01} test format-4.13 {e and f formats} { format "%.0f %#.0f" -9.99996 -9.99996 9.99996 } {-10 -10.} test format-4.14 {e and f formats} { format "%.4f %.5f %.6f" -9.99996 -9.99996 9.99996 } {-10.0000 -9.99996 9.999960} test format-4.15 {e and f formats} { format "%3.0f %3.0f %3.0f %3.0f" 1.0 1.1 1.01 1.001 } { 1 1 1 1} test format-4.16 {e and f formats} { format "%3.1f %3.1f %3.1f %3.1f" 0.0 0.1 0.01 0.001 } {0.0 0.1 0.0 0.0} test format-5.1 {g-format} {eformat} { format "%.3g" 12341.0 } {1.23e+04} test format-5.2 {g-format} {eformat} { format "%.3G" 1234.12345 } {1.23E+03} test format-5.3 {g-format} { format "%.3g" 123.412345 } {123} test format-5.4 {g-format} { format "%.3g" 12.3412345 } {12.3} test format-5.5 {g-format} { format "%.3g" 1.23412345 } {1.23} test format-5.6 {g-format} { format "%.3g" 1.23412345 } {1.23} test format-5.7 {g-format} { format "%.3g" .123412345 } {0.123} test format-5.8 {g-format} { format "%.3g" .012341 } {0.0123} test format-5.9 {g-format} { format "%.3g" .0012341 } {0.00123} test format-5.10 {g-format} { format "%.3g" .00012341 } {0.000123} test format-5.11 {g-format} {eformat} { format "%.3g" .00001234 } {1.23e-05} test format-5.12 {g-format} {eformat} { format "%.4g" 9999.6 } {1e+04} test format-5.13 {g-format} { format "%.4g" 999.96 } {1000} test format-5.14 {g-format} { format "%.3g" 1.0 } {1} test format-5.15 {g-format} { format "%.3g" .1 } {0.1} test format-5.16 {g-format} { format "%.3g" .01 } {0.01} test format-5.17 {g-format} { format "%.3g" .001 } {0.001} test format-5.18 {g-format} {eformat} { format "%.3g" .00001 } {1e-05} test format-5.19 {g-format} {eformat} { format "%#.3g" 1234.0 } {1.23e+03} test format-5.20 {g-format} {eformat} { format "%#.3G" 9999.5 } {1.00E+04} test format-6.1 {floating-point zeroes} {eformat} { format "%e %f %g" 0.0 0.0 0.0 0.0 } {0.000000e+00 0.000000 0} test format-6.2 {floating-point zeroes} {eformat} { format "%.4e %.4f %.4g" 0.0 0.0 0.0 0.0 } {0.0000e+00 0.0000 0} test format-6.3 {floating-point zeroes} {eformat} { format "%#.4e %#.4f %#.4g" 0.0 0.0 0.0 0.0 } {0.0000e+00 0.0000 0.000} test format-6.4 {floating-point zeroes} {eformat} { format "%.0e %.0f %.0g" 0.0 0.0 0.0 0.0 } {0e+00 0 0} test format-6.5 {floating-point zeroes} {eformat} { format "%#.0e %#.0f %#.0g" 0.0 0.0 0.0 0.0 } {0.e+00 0. 0.} test format-6.6 {floating-point zeroes} { format "%3.0f %3.0f %3.0f %3.0f" 0.0 0.0 0.0 0.0 } { 0 0 0 0} test format-6.7 {floating-point zeroes} { format "%3.0f %3.0f %3.0f %3.0f" 1.0 1.1 1.01 1.001 } { 1 1 1 1} test format-6.8 {floating-point zeroes} { format "%3.1f %3.1f %3.1f %3.1f" 0.0 0.1 0.01 0.001 } {0.0 0.1 0.0 0.0} test format-7.1 {various syntax features} { format "%*.*f" 12 3 12.345678901 } { 12.346} test format-7.2 {various syntax features} { format "%0*.*f" 12 3 12.345678901 } {00000012.346} test format-7.3 {various syntax features} { format "\*\t\\n" } {* \n} test format-8.1 {error conditions} { catch format } 1 test format-8.2 {error conditions} { catch format msg set msg } {wrong # args: should be "format formatString ?arg arg ...?"} test format-8.3 {error conditions} { catch {format %*d} } 1 test format-8.4 {error conditions} { catch {format %*d} msg set msg } {not enough arguments for all format specifiers} test format-8.5 {error conditions} { catch {format %*.*f 12} } 1 test format-8.6 {error conditions} { catch {format %*.*f 12} msg set msg } {not enough arguments for all format specifiers} test format-8.7 {error conditions} { catch {format %*.*f 12 3} } 1 test format-8.8 {error conditions} { catch {format %*.*f 12 3} msg set msg } {not enough arguments for all format specifiers} test format-8.9 {error conditions} { list [catch {format %*d x 3} msg] $msg } {1 {expected integer but got "x"}} test format-8.10 {error conditions} { list [catch {format %*.*f 2 xyz 3} msg] $msg } {1 {expected integer but got "xyz"}} test format-8.11 {error conditions} { catch {format %d 2a} } 1 test format-8.12 {error conditions} { catch {format %d 2a} msg set msg } {expected integer but got "2a"} test format-8.13 {error conditions} { catch {format %c 2x} } 1 test format-8.14 {error conditions} { catch {format %c 2x} msg set msg } {expected integer but got "2x"} test format-8.15 {error conditions} { catch {format %f 2.1z} } 1 test format-8.16 {error conditions} { catch {format %f 2.1z} msg set msg } {expected floating-point number but got "2.1z"} test format-8.17 {error conditions} { catch {format ab%} } 1 test format-8.18 {error conditions} { catch {format ab% 12} msg set msg } {format string ended in middle of field specifier} test format-8.19 {error conditions} { catch {format %q x} } 1 test format-8.20 {error conditions} { catch {format %q x} msg set msg } {bad field specifier "q"} test format-8.21 {error conditions} { catch {format %d} } 1 test format-8.22 {error conditions} { catch {format %d} msg set msg } {not enough arguments for all format specifiers} test format-8.23 {error conditions} { catch {format "%d %d" 24 xyz} msg set msg } {expected integer but got "xyz"} test format-9.1 {long result} { set a {1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ 1 2 3 4 5 6 7 8 9 0 a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z} format {1111 2222 3333 4444 5555 6666 7777 8888 9999 aaaa bbbb cccc dddd eeee ffff gggg hhhh iiii jjjj kkkk llll mmmm nnnn oooo pppp qqqq rrrr ssss tttt uuuu vvvv wwww xxxx yyyy zzzz AAAA BBBB CCCC DDDD EEEE FFFF GGGG %s %s} $a $a } {1111 2222 3333 4444 5555 6666 7777 8888 9999 aaaa bbbb cccc dddd eeee ffff gggg hhhh iiii jjjj kkkk llll mmmm nnnn oooo pppp qqqq rrrr ssss tttt uuuu vvvv wwww xxxx yyyy zzzz AAAA BBBB CCCC DDDD EEEE FFFF GGGG 1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ 1 2 3 4 5 6 7 8 9 0 a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ 1 2 3 4 5 6 7 8 9 0 a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z} test format-10.1 {"h" format specifier} {nonPortable} { format %hd 0xffff } -1 test format-10.2 {"h" format specifier} {nonPortable} { format %hx 0x10fff } fff test format-10.3 {"h" format specifier} {nonPortable} { format %hd 0x10000 } 0 test format-10.4 {"h" format specifier} { # Bug 1154163: This is minimal behaviour for %hx specifier! format %hx 1 } 1 test format-10.5 {"h" format specifier} { # Bug 1284178: Highly out-of-range values shouldn't cause errors format %hu 0x100000000 } 0 test format-11.1 {XPG3 %$n specifiers} { format {%2$d %1$d} 4 5 } {5 4} test format-11.2 {XPG3 %$n specifiers} { format {%2$d %1$d %1$d %3$d} 4 5 6 } {5 4 4 6} test format-11.3 {XPG3 %$n specifiers} { list [catch {format {%2$d %3$d} 4 5} msg] $msg } {1 {"%n$" argument index out of range}} test format-11.4 {XPG3 %$n specifiers} { list [catch {format {%2$d %0$d} 4 5 6} msg] $msg } {1 {"%n$" argument index out of range}} test format-11.5 {XPG3 %$n specifiers} { list [catch {format {%d %1$d} 4 5 6} msg] $msg } {1 {cannot mix "%" and "%n$" conversion specifiers}} test format-11.6 {XPG3 %$n specifiers} { list [catch {format {%2$d %d} 4 5 6} msg] $msg } {1 {cannot mix "%" and "%n$" conversion specifiers}} test format-11.7 {XPG3 %$n specifiers} { list [catch {format {%2$d %3d} 4 5 6} msg] $msg } {1 {cannot mix "%" and "%n$" conversion specifiers}} test format-11.8 {XPG3 %$n specifiers} { format {%2$*d %3$d} 1 10 4 } { 4 4} test format-11.9 {XPG3 %$n specifiers} { format {%2$.*s %4$d} 1 5 abcdefghijklmnop 44 } {abcde 44} test format-11.10 {XPG3 %$n specifiers} { list [catch {format {%2$*d} 4} msg] $msg } {1 {"%n$" argument index out of range}} test format-11.11 {XPG3 %$n specifiers} { list [catch {format {%2$*d} 4 5} msg] $msg } {1 {"%n$" argument index out of range}} test format-11.12 {XPG3 %$n specifiers} { list [catch {format {%2$*d} 4 5 6} msg] $msg } {0 { 6}} test format-12.1 {negative width specifiers} { format "%*d" -47 25 } {25 } test format-13.1 {tcl_precision fuzzy comparison} { catch {unset a} catch {unset b} catch {unset c} catch {unset d} set a 0.0000000000001 set b 0.00000000000001 set c 0.00000000000000001 set d [expr $a + $b + $c] format {%0.10f %0.12f %0.15f %0.17f} $d $d $d $d } {0.0000000000 0.000000000000 0.000000000000110 0.00000000000011001} test format-13.2 {tcl_precision fuzzy comparison} { catch {unset a} catch {unset b} catch {unset c} catch {unset d} set a 0.000000000001 set b 0.000000000000005 set c 0.0000000000000008 set d [expr $a + $b + $c] format {%0.10f %0.12f %0.15f %0.17f} $d $d $d $d } {0.0000000000 0.000000000001 0.000000000001006 0.00000000000100580} test format-13.3 {tcl_precision fuzzy comparison} { catch {unset a} catch {unset b} catch {unset c} set a 0.00000000000099 set b 0.000000000000011 set c [expr $a + $b] format {%0.10f %0.12f %0.15f %0.17f} $c $c $c $c } {0.0000000000 0.000000000001 0.000000000001001 0.00000000000100100} test format-13.4 {tcl_precision fuzzy comparison} { catch {unset a} catch {unset b} catch {unset c} set a 0.444444444444 set b 0.33333333333333 set c [expr $a + $b] format {%0.10f %0.12f %0.15f %0.16f} $c $c $c $c } {0.7777777778 0.777777777777 0.777777777777330 0.7777777777773300} test format-13.5 {tcl_precision fuzzy comparison} { catch {unset a} catch {unset b} catch {unset c} set a 0.444444444444 set b 0.99999999999999 set c [expr $a + $b] format {%0.10f %0.12f %0.15f} $c $c $c } {1.4444444444 1.444444444444 1.444444444443990} test format-14.1 {testing MAX_FLOAT_SIZE for 0 and 1} { format {%s} "" } {} test format-14.2 {testing MAX_FLOAT_SIZE for 0 and 1} { format {%s} "a" } {a} test format-15.1 {testing %0..s 0 padding for chars/strings} { format %05s a } {0000a} test format-15.2 {testing %0..s 0 padding for chars/strings} { format "% 5s" a } { a} test format-15.3 {testing %0..s 0 padding for chars/strings} { format %5s a } { a} test format-15.4 {testing %0..s 0 padding for chars/strings} { format %05c 61 } {0000=} set a "0123456789" set b "" for {set i 0} {$i < 290} {incr i} { append b $a } for {set i 290} {$i < 400} {incr i} { test format-16.[expr $i -289] {testing MAX_FLOAT_SIZE} { format {%s} $b } $b append b "x" } ::tcltest::testConstraint 64bitInts \ [expr {0x80000000 > 0}] ::tcltest::testConstraint wideIntExpressions \ [expr {wide(0x80000000) != int(0x80000000)}] test format-17.1 {testing %d with wide} {64bitInts wideIntExpressions} { format %d 7810179016327718216 } 1819043144 test format-17.2 {testing %ld with wide} {64bitInts} { format %ld 7810179016327718216 } 7810179016327718216 test format-17.3 {testing %ld with non-wide} {64bitInts} { format %ld 42 } 42 test format-17.4 {testing %l with non-integer} { format %lf 1 } 1.000000 test format-17.5 {type conversions with wides} { set a 0xAAAAAAAA ;# NB: Careful to make separate objects here! set b 0xAAAAAAA; append b A set result [expr {$a == $b}] format %x $a lappend result [expr {$a == $b}] } {1 1} test format-18.1 {do not demote existing numeric values} { set a 0xaaaaaaaa # Ensure $a and $b are separate objects set b 0xaaaa append b aaaa set result [expr {$a == $b}] format %08lx $b lappend result [expr {$a == $b}] set b 0xaaaa append b aaaa lappend result [expr {$a == $b}] format %08x $b lappend result [expr {$a == $b}] } {1 1 1 1} test format-18.2 {do not demote existing numeric values} {wideIntExpressions} { set a [expr {0xaaaaaaaaaa + 1}] set b 0xaaaaaaaaab list [format %08x $a] [expr {$a == $b}] } {aaaaaaab 1} test format-19.1 { regression test - tcl-core message by Brian Griffin on 26 0ctober 2004 } -body { set x 0x8fedc654 list [expr { ~ $x }] [format %08x [expr { ~$x }]] } -match regexp -result {-2414724693 f*701239ab} # cleanup catch {unset a} catch {unset b} catch {unset c} catch {unset d} ::tcltest::cleanupTests return tcl8.4.20/tests/compile.test0000644003604700454610000003360011737050674014414 0ustar dgp771div# This file contains tests for the files tclCompile.c, tclCompCmds.c # and tclLiteral.c # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1997 by Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. package require tcltest 2 namespace import -force ::tcltest::* # The following tests are very incomplete, although the rest of the # test suite covers this file fairly well. catch {rename p ""} catch {namespace delete test_ns_compile} catch {unset x} catch {unset y} catch {unset a} test compile-1.1 {TclCompileString: look up cmds in proc ns, not current ns} { catch {namespace delete test_ns_compile} catch {unset x} set x 123 namespace eval test_ns_compile { proc set {args} { global x lappend x test_ns_compile::set } proc p {} { set 0 } } list [test_ns_compile::p] [set x] } {{123 test_ns_compile::set} {123 test_ns_compile::set}} test compile-1.2 {TclCompileString, error result is reset if TclGetLong determines word isn't an integer} { proc p {x} {info commands 3m} list [catch {p} msg] $msg } {1 {wrong # args: should be "p x"}} test compile-2.1 {TclCompileDollarVar: global scalar name with ::s} { catch {unset x} set x 123 list $::x [expr {[lsearch -exact [info globals] x] != 0}] } {123 1} test compile-2.2 {TclCompileDollarVar: global scalar name with ::s} { catch {unset y} proc p {} { set ::y 789 return $::y } list [p] $::y [expr {[lsearch -exact [info globals] y] != 0}] } {789 789 1} test compile-2.3 {TclCompileDollarVar: global array name with ::s} { catch {unset a} set ::a(1) 2 list $::a(1) [set ::a($::a(1)) 3] $::a(2) [expr {[lsearch -exact [info globals] a] != 0}] } {2 3 3 1} test compile-2.4 {TclCompileDollarVar: global scalar name with ::s} { catch {unset a} proc p {} { set ::a(1) 1 return $::a($::a(1)) } list [p] $::a(1) [expr {[lsearch -exact [info globals] a] != 0}] } {1 1 1} test compile-2.5 {TclCompileDollarVar: global array, called as ${arrName(0)}} { catch {unset a} proc p {} { global a set a(1) 1 return ${a(1)}$::a(1)$a(1) } list [p] $::a(1) [expr {[lsearch -exact [info globals] a] != 0}] } {111 1 1} test compile-3.1 {TclCompileCatchCmd: only catch cmds with scalar vars are compiled inline} { catch {unset a} set a(1) xyzzyx proc p {} { global a catch {set x 123} a(1) } list [p] $a(1) } {0 123} test compile-3.2 {TclCompileCatchCmd: non-local variables} { set ::foo 1 proc catch-test {} { catch {set x 3} ::foo } catch-test set ::foo } 3 test compile-3.3 {TclCompileCatchCmd: overagressive compiling [bug 219184]} { proc catch-test {str} { catch [eval $str GOOD] error BAD } catch {catch-test error} ::foo set ::foo } {GOOD} test compile-3.4 {TclCompileCatchCmd: bcc'ed [return] is caught} { proc foo {} { set fail [catch { return 1 }] ; # {} return 2 } foo } {2} test compile-3.5 {TclCompileCatchCmd: recover from error, [Bug 705406]} { proc foo {} { catch { if {[a]} { if b {} } } } list [catch foo msg] $msg } {0 1} test compile-4.1 {TclCompileForCmd: command substituted test expression} { set i 0 set j 0 # Should be "forever" for {} [expr $i < 3] {} { set j [incr i] if {$j > 3} break } set j } {4} test compile-5.1 {TclCompileForeachCmd: exception stack} { proc foreach-exception-test {} { foreach array(index) [list 1 2 3] break foreach array(index) [list 1 2 3] break foreach scalar [list 1 2 3] break } list [catch foreach-exception-test result] $result } {0 {}} test compile-5.2 {TclCompileForeachCmd: non-local variables} { set ::foo 1 proc foreach-test {} { foreach ::foo {1 2 3} {} } foreach-test set ::foo } 3 test compile-6.1 {TclCompileSetCmd: global scalar names with ::s} { catch {unset x} catch {unset y} set x 123 proc p {} { set ::y 789 return $::y } list $::x [expr {[lsearch -exact [info globals] x] != 0}] \ [p] $::y [expr {[lsearch -exact [info globals] y] != 0}] } {123 1 789 789 1} test compile-6.2 {TclCompileSetCmd: global array names with ::s} { catch {unset a} set ::a(1) 2 proc p {} { set ::a(1) 1 return $::a($::a(1)) } list $::a(1) [p] [set ::a($::a(1)) 3] $::a(1) [expr {[lsearch -exact [info globals] a] != 0}] } {2 1 3 3 1} test compile-6.3 {TclCompileSetCmd: namespace var names with ::s} { catch {namespace delete test_ns_compile} catch {unset x} namespace eval test_ns_compile { variable v hello variable arr set ::x $::test_ns_compile::v set ::test_ns_compile::arr(1) 123 } list $::x $::test_ns_compile::arr(1) } {hello 123} test compile-7.1 {TclCompileWhileCmd: command substituted test expression} { set i 0 set j 0 # Should be "forever" while [expr $i < 3] { set j [incr i] if {$j > 3} break } set j } {4} test compile-8.1 {CollectArgInfo: binary data} { list [catch "string length \000foo" msg] $msg } {0 4} test compile-8.2 {CollectArgInfo: binary data} { list [catch "string length foo\000" msg] $msg } {0 4} test compile-8.3 {CollectArgInfo: handle "]" at end of command properly} { set x ] } {]} test compile-9.1 {UpdateStringOfByteCode: called for duplicate of compiled empty object} { proc p {} { set x {} eval $x append x { } eval $x } p } {} test compile-10.1 {BLACKBOX: exception stack overflow} { set x {{0}} set y 0 while {$y < 100} { if !$x {incr y} } } {} test compile-11.1 {Tcl_Append*: ensure Tcl_ResetResult is used properly} { proc p {} { # shared object - Interp result && Var 'r' set r [list foobar] # command that will add error to result lindex a bogus } list [catch {p} msg] $msg } {1 {bad index "bogus": must be integer or end?-integer?}} test compile-11.2 {Tcl_Append*: ensure Tcl_ResetResult is used properly} { proc p {} { set r [list foobar] ; string index a bogus } list [catch {p} msg] $msg } {1 {bad index "bogus": must be integer or end?-integer?}} test compile-11.3 {Tcl_Append*: ensure Tcl_ResetResult is used properly} { proc p {} { set r [list foobar] ; string index a 09 } list [catch {p} msg] $msg } {1 {bad index "09": must be integer or end?-integer? (looks like invalid octal number)}} test compile-11.4 {Tcl_Append*: ensure Tcl_ResetResult is used properly} { proc p {} { set r [list foobar] ; array set var {one two many} } list [catch {p} msg] $msg } {1 {list must have an even number of elements}} test compile-11.5 {Tcl_Append*: ensure Tcl_ResetResult is used properly} { proc p {} { set r [list foobar] ; incr foo } list [catch {p} msg] $msg } {1 {can't read "foo": no such variable}} test compile-11.6 {Tcl_Append*: ensure Tcl_ResetResult is used properly} { proc p {} { set r [list foobar] ; incr foo bogus } list [catch {p} msg] $msg } {1 {expected integer but got "bogus"}} test compile-11.7 {Tcl_Append*: ensure Tcl_ResetResult is used properly} { proc p {} { set r [list foobar] ; expr !a } list [catch {p} msg] $msg } {1 {syntax error in expression "!a": variable references require preceding $}} test compile-11.8 {Tcl_Append*: ensure Tcl_ResetResult is used properly} { proc p {} { set r [list foobar] ; expr {!a} } list [catch {p} msg] $msg } {1 {syntax error in expression "!a": variable references require preceding $}} test compile-11.9 {Tcl_Append*: ensure Tcl_ResetResult is used properly} { proc p {} { set r [list foobar] ; llength "\{" } list [catch {p} msg] $msg } {1 {unmatched open brace in list}} # # Special section for tests of tclLiteral.c # The following tests check for incorrect memory handling in # TclReleaseLiteral. They are only effective when tcl is compiled # with TCL_MEM_DEBUG # # Special test for leak on interp delete [Bug 467523]. ::tcltest::testConstraint exec [llength [info commands exec]] ::tcltest::testConstraint memDebug [llength [info commands memory]] test compile-12.1 {testing literal leak on interp delete} {memDebug} { proc getbytes {} { set lines [split [memory info] "\n"] lindex [lindex $lines 3] 3 } set end [getbytes] for {set i 0} {$i < 5} {incr i} { interp create foo foo eval { namespace eval bar {} } interp delete foo set tmp $end set end [getbytes] } rename getbytes {} set leak [expr {$end - $tmp}] } 0 # Special test for a memory error in a preliminary fix of [Bug 467523]. # It requires executing a helpfile. Presumably the child process is # used because when this test fails, it crashes. test compile-12.2 {testing error on literal deletion} {memDebug exec} { makeFile { for {set i 0} {$i < 5} {incr i} { namespace eval bar {} namespace delete bar } puts 0 } source.file set res [catch { exec [interpreter] source.file }] catch {removeFile source.file} set res } 0 # Test to catch buffer overrun in TclCompileTokens from buf 530320 test compile-12.3 {check for a buffer overrun} { proc crash {} { puts $array([expr {a+2}]) } list [catch crash msg] $msg } {1 {syntax error in expression "a+2": variable references require preceding $}} test compile-12.4 {TclCleanupLiteralTable segfault} { # Tcl Bug 1001997 # Here, we're trying to test a case that causes a crash in # TclCleanupLiteralTable. The conditions that we're trying to # establish are: # - TclCleanupLiteralTable is attempting to clean up a bytecode # object in the literal table. # - The bytecode object in question contains the only reference # to another literal. # - The literal in question is in the same hash bucket as the bytecode # object, and immediately follows it in the chain. # Since newly registered literals are added at the FRONT of the # bucket chains, and since the bytecode object is registered before # its literals, this is difficult to achieve. What we do is: # (a) do a [namespace eval] of a string that's calculated to # hash into the same bucket as a literal that it contains. # In this case, the script and the variable 'bugbug' # land in the same bucket. # (b) do a [namespace eval] of a string that contains enough # literals to force TclRegisterLiteral to rebuild the global # literal table. The newly created hash buckets will contain # the literals, IN REVERSE ORDER, thus putting the bytecode # immediately ahead of 'bugbug' and 'bug4345bug'. The bytecode # object will contain the only references to those two literals. # (c) Delete the interpreter to invoke TclCleanupLiteralTable # and tickle the bug. proc foo {} { set i [interp create] $i eval { namespace eval ::w {concat 4649; variable bugbug} namespace eval ::w { concat x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 \ x11 x12 x13 x14 x15 x16 x17 x18 x19 x20 \ x21 x22 x23 x24 x25 x26 x27 x28 x29 x30 \ x31 x32 X33 X34 X35 X36 X37 X38 X39 X40 \ x41 x42 x43 x44 x45 x46 x47 x48 x49 x50 \ x51 x52 x53 x54 x55 x56 x57 x58 x59 x60 \ x61 x62 x63 x64 concat y1 y2 y3 y4 y5 y6 y7 y8 y9 y10 \ y11 y12 y13 y14 y15 y16 y17 y18 y19 y20 \ y21 y22 y23 y24 y25 y26 y27 y28 y29 y30 \ y31 y32 Y33 Y34 Y35 Y36 Y37 Y38 Y39 Y40 \ y41 y42 y43 y44 y45 y46 y47 y48 y49 y50 \ y51 y52 y53 y54 y55 y56 y57 y58 y59 y60 \ y61 y62 y63 y64 concat z1 z2 z3 z4 z5 z6 z7 z8 z9 z10 \ z11 z12 z13 z14 z15 z16 z17 z18 z19 z20 \ z21 z22 z23 z24 z25 z26 z27 z28 z29 z30 \ z31 z32 } } interp delete $i; # must not crash return ok } foo } ok # Special test for underestimating the maxStackSize required for a # compiled command. A failure will cause a segfault in the child # process. test compile-13.1 {testing underestimate of maxStackSize in list cmd} {exec} { set body {set x [list} for {set i 0} {$i < 3000} {incr i} { append body " $i" } append body {]; puts OK} regsub BODY {proc crash {} {BODY}; crash} $body script list [catch {exec [interpreter] << $script} msg] $msg } {0 OK} # Special test for compiling tokens from a copy of the source # string [Bug #599788] test compile-14.1 {testing errors in element name; segfault?} {} { catch {set a([error])} msg1 catch {set bubba([join $abba $jubba]) $vol} msg2 list $msg1 $msg2 } {{wrong # args: should be "error message ?errorInfo? ?errorCode?"} {can't read "abba": no such variable}} # Next 4 tests cover Tcl Bug 633204 test compile-15.1 {proper TCL_RETURN code from [return]} { proc p {} {catch return} set result [p] rename p {} set result } 2 test compile-15.2 {proper TCL_RETURN code from [return]} { proc p {} {catch {return foo}} set result [p] rename p {} set result } 2 test compile-15.3 {proper TCL_RETURN code from [return]} { proc p {} {catch {return $::tcl_library}} set result [p] rename p {} set result } 2 test compile-15.4 {proper TCL_RETURN code from [return]} { proc p {} {catch {return [info library]}} set result [p] rename p {} set result } 2 test compile-15.5 {proper TCL_RETURN code from [return]} { proc p {} {catch {set a 1}; return} set result [p] rename p {} set result } "" # cleanup catch {rename p ""} catch {namespace delete test_ns_compile} catch {unset x} catch {unset y} catch {unset a} ::tcltest::cleanupTests return tcl8.4.20/tests/split.test0000644003604700454610000000456711737050674014131 0ustar dgp771div# Commands covered: split # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994-1996 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } test split-1.1 {basic split commands} { split "a\n b\t\r c\n " } {a {} b {} {} c {} {}} test split-1.2 {basic split commands} { split "word 1xyzword 2zword 3" xyz } {{word 1} {} {} {word 2} {word 3}} test split-1.3 {basic split commands} { split "12345" {} } {1 2 3 4 5} test split-1.4 {basic split commands} { split "a\}b\[c\{\]\$" } "a\\}b\\\[c\\{\\\]\\\$" test split-1.5 {basic split commands} { split {} {} } {} test split-1.6 {basic split commands} { split {} } {} test split-1.7 {basic split commands} { split { } } {{} {} {} {}} test split-1.8 {basic split commands} { proc foo {} { set x {} foreach f [split {]\n} {}] { append x $f } return $x } foo } {]\n} test split-1.9 {basic split commands} { proc foo {} { set x ab\000c set y [split $x {}] return $y } foo } "a b \000 c" test split-1.10 {basic split commands} { split "a0ab1b2bbb3\000c4" ab\000c } {{} 0 {} 1 2 {} {} 3 {} 4} test split-1.11 {basic split commands} { split "12,3,45" {,} } {12 3 45} test split-1.12 {basic split commands} { split "\u0001ab\u0001cd\u0001\u0001ef\u0001" \1 } {{} ab cd {} ef {}} test split-1.13 {basic split commands} { split "12,34,56," {,} } {12 34 56 {}} test split-1.14 {basic split commands} { split ",12,,,34,56," {,} } {{} 12 {} {} 34 56 {}} test split-2.1 {split errors} { list [catch split msg] $msg $errorCode } {1 {wrong # args: should be "split string ?splitChars?"} NONE} test split-2.2 {split errors} { list [catch {split a b c} msg] $msg $errorCode } {1 {wrong # args: should be "split string ?splitChars?"} NONE} # cleanup catch {rename foo {}} ::tcltest::cleanupTests return tcl8.4.20/tests/parseExpr.test0000644003604700454610000013143311737050674014740 0ustar dgp771div# This file contains a collection of tests for the procedures in the # file tclParseExpr.c. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1997 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import -force ::tcltest::* } # Note that the Tcl expression parser (tclParseExpr.c) does not check # the semantic validity of the expressions it parses. It does not check, # for example, that a math function actually exists, or that the operands # of "<<" are integers. if {[info commands testexprparser] == {}} { puts "This application hasn't been compiled with the \"testexprparser\"" puts "command, so I can't test the Tcl expression parser." ::tcltest::cleanupTests return } # Some tests only work if wide integers (>32bit) are not found to be # integers at all. set ::tcltest::testConstraints(wideIntegerUnparsed) \ [expr {-1 == 0xffffffff}] test parseExpr-1.1 {Tcl_ParseExpr procedure, computing string length} { testexprparser [bytestring "1+2\0 +3"] -1 } {- {} 0 subexpr 1+2 5 operator + 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 {}} test parseExpr-1.2 {Tcl_ParseExpr procedure, computing string length} { testexprparser "1 + 2" -1 } {- {} 0 subexpr {1 + 2} 5 operator + 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 {}} test parseExpr-1.3 {Tcl_ParseExpr procedure, error getting initial lexeme} {wideIntegerUnparsed} { list [catch {testexprparser {12345678901234567890} -1} msg] $msg } {1 {integer value too large to represent}} test parseExpr-1.4 {Tcl_ParseExpr procedure, error in conditional expression} { list [catch {testexprparser {foo+} -1} msg] $msg } {1 {syntax error in expression "foo+": variable references require preceding $}} test parseExpr-1.5 {Tcl_ParseExpr procedure, lexemes after the expression} { list [catch {testexprparser {1+2 345} -1} msg] $msg } {1 {syntax error in expression "1+2 345": extra tokens at end of expression}} test parseExpr-2.1 {ParseCondExpr procedure, valid test subexpr} { testexprparser {2>3? 1 : 0} -1 } {- {} 0 subexpr {2>3? 1 : 0} 11 operator ? 0 subexpr 2>3 5 operator > 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 subexpr 1 1 text 1 0 subexpr 0 1 text 0 0 {}} test parseExpr-2.2 {ParseCondExpr procedure, error in test subexpr} { list [catch {testexprparser {0 || foo} -1} msg] $msg } {1 {syntax error in expression "0 || foo": variable references require preceding $}} test parseExpr-2.3 {ParseCondExpr procedure, next lexeme isn't "?"} { testexprparser {1+2} -1 } {- {} 0 subexpr 1+2 5 operator + 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 {}} test parseExpr-2.4 {ParseCondExpr procedure, next lexeme is "?"} { testexprparser {1+2 ? 3 : 4} -1 } {- {} 0 subexpr {1+2 ? 3 : 4} 11 operator ? 0 subexpr 1+2 5 operator + 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 subexpr 4 1 text 4 0 {}} test parseExpr-2.5 {ParseCondExpr procedure, bad lexeme after "?"} {wideIntegerUnparsed} { list [catch {testexprparser {1+2 ? 12345678901234567890} -1} msg] $msg } {1 {integer value too large to represent}} test parseExpr-2.6 {ParseCondExpr procedure, valid "then" subexpression} { testexprparser {1? 3 : 4} -1 } {- {} 0 subexpr {1? 3 : 4} 7 operator ? 0 subexpr 1 1 text 1 0 subexpr 3 1 text 3 0 subexpr 4 1 text 4 0 {}} test parseExpr-2.7 {ParseCondExpr procedure, error in "then" subexpression} { list [catch {testexprparser {1? fred : martha} -1} msg] $msg } {1 {syntax error in expression "1? fred : martha": variable references require preceding $}} test parseExpr-2.8 {ParseCondExpr procedure, lexeme after "then" subexpr isn't ":"} { list [catch {testexprparser {1? 2 martha 3} -1} msg] $msg } {1 {syntax error in expression "1? 2 martha 3": missing colon from ternary conditional}} test parseExpr-2.9 {ParseCondExpr procedure, valid "else" subexpression} { testexprparser {27||3? 3 : 4&&9} -1 } {- {} 0 subexpr {27||3? 3 : 4&&9} 15 operator ? 0 subexpr 27||3 5 operator || 0 subexpr 27 1 text 27 0 subexpr 3 1 text 3 0 subexpr 3 1 text 3 0 subexpr 4&&9 5 operator && 0 subexpr 4 1 text 4 0 subexpr 9 1 text 9 0 {}} test parseExpr-2.10 {ParseCondExpr procedure, error in "else" subexpression} { list [catch {testexprparser {1? 2 : martha} -1} msg] $msg } {1 {syntax error in expression "1? 2 : martha": variable references require preceding $}} test parseExpr-3.1 {ParseLorExpr procedure, valid logical and subexpr} { testexprparser {1&&2 || 3} -1 } {- {} 0 subexpr {1&&2 || 3} 9 operator || 0 subexpr 1&&2 5 operator && 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 {}} test parseExpr-3.2 {ParseLorExpr procedure, error in logical and subexpr} { list [catch {testexprparser {1&&foo || 3} -1} msg] $msg } {1 {syntax error in expression "1&&foo || 3": variable references require preceding $}} test parseExpr-3.3 {ParseLorExpr procedure, next lexeme isn't "||"} { testexprparser {1&&2? 1 : 0} -1 } {- {} 0 subexpr {1&&2? 1 : 0} 11 operator ? 0 subexpr 1&&2 5 operator && 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 1 1 text 1 0 subexpr 0 1 text 0 0 {}} test parseExpr-3.4 {ParseLorExpr procedure, next lexeme is "||"} { testexprparser {1&&2 || 3} -1 } {- {} 0 subexpr {1&&2 || 3} 9 operator || 0 subexpr 1&&2 5 operator && 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 {}} test parseExpr-3.5 {ParseLorExpr procedure, bad lexeme after "||"} {wideIntegerUnparsed} { list [catch {testexprparser {1&&2 || 12345678901234567890} -1} msg] $msg } {1 {integer value too large to represent}} test parseExpr-3.6 {ParseLorExpr procedure, valid RHS subexpression} { testexprparser {1&&2 || 3 || 4} -1 } {- {} 0 subexpr {1&&2 || 3 || 4} 13 operator || 0 subexpr {1&&2 || 3} 9 operator || 0 subexpr 1&&2 5 operator && 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 subexpr 4 1 text 4 0 {}} test parseExpr-3.7 {ParseLorExpr procedure, error in RHS subexpression} { list [catch {testexprparser {1&&2 || 3 || martha} -1} msg] $msg } {1 {syntax error in expression "1&&2 || 3 || martha": variable references require preceding $}} test parseExpr-4.1 {ParseLandExpr procedure, valid LHS "|" subexpr} { testexprparser {1|2 && 3} -1 } {- {} 0 subexpr {1|2 && 3} 9 operator && 0 subexpr 1|2 5 operator | 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 {}} test parseExpr-4.2 {ParseLandExpr procedure, error in LHS "|" subexpr} { list [catch {testexprparser {1&&foo && 3} -1} msg] $msg } {1 {syntax error in expression "1&&foo && 3": variable references require preceding $}} test parseExpr-4.3 {ParseLandExpr procedure, next lexeme isn't "&&"} { testexprparser {1|2? 1 : 0} -1 } {- {} 0 subexpr {1|2? 1 : 0} 11 operator ? 0 subexpr 1|2 5 operator | 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 1 1 text 1 0 subexpr 0 1 text 0 0 {}} test parseExpr-4.4 {ParseLandExpr procedure, next lexeme is "&&"} { testexprparser {1|2 && 3} -1 } {- {} 0 subexpr {1|2 && 3} 9 operator && 0 subexpr 1|2 5 operator | 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 {}} test parseExpr-4.5 {ParseLandExpr procedure, bad lexeme after "&&"} {wideIntegerUnparsed} { list [catch {testexprparser {1|2 && 12345678901234567890} -1} msg] $msg } {1 {integer value too large to represent}} test parseExpr-4.6 {ParseLandExpr procedure, valid RHS subexpression} { testexprparser {1|2 && 3 && 4} -1 } {- {} 0 subexpr {1|2 && 3 && 4} 13 operator && 0 subexpr {1|2 && 3} 9 operator && 0 subexpr 1|2 5 operator | 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 subexpr 4 1 text 4 0 {}} test parseExpr-4.7 {ParseLandExpr procedure, error in RHS subexpression} { list [catch {testexprparser {1|2 && 3 && martha} -1} msg] $msg } {1 {syntax error in expression "1|2 && 3 && martha": variable references require preceding $}} test parseExpr-5.1 {ParseBitOrExpr procedure, valid LHS "^" subexpr} { testexprparser {1^2 | 3} -1 } {- {} 0 subexpr {1^2 | 3} 9 operator | 0 subexpr 1^2 5 operator ^ 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 {}} test parseExpr-5.2 {ParseBitOrExpr procedure, error in LHS "^" subexpr} { list [catch {testexprparser {1|foo | 3} -1} msg] $msg } {1 {syntax error in expression "1|foo | 3": variable references require preceding $}} test parseExpr-5.3 {ParseBitOrExpr procedure, next lexeme isn't "|"} { testexprparser {1^2? 1 : 0} -1 } {- {} 0 subexpr {1^2? 1 : 0} 11 operator ? 0 subexpr 1^2 5 operator ^ 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 1 1 text 1 0 subexpr 0 1 text 0 0 {}} test parseExpr-5.4 {ParseBitOrExpr procedure, next lexeme is "|"} { testexprparser {1^2 | 3} -1 } {- {} 0 subexpr {1^2 | 3} 9 operator | 0 subexpr 1^2 5 operator ^ 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 {}} test parseExpr-5.5 {ParseBitOrExpr procedure, bad lexeme after "|"} {wideIntegerUnparsed} { list [catch {testexprparser {1^2 | 12345678901234567890} -1} msg] $msg } {1 {integer value too large to represent}} test parseExpr-5.6 {ParseBitOrExpr procedure, valid RHS subexpression} { testexprparser {1^2 | 3 | 4} -1 } {- {} 0 subexpr {1^2 | 3 | 4} 13 operator | 0 subexpr {1^2 | 3} 9 operator | 0 subexpr 1^2 5 operator ^ 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 subexpr 4 1 text 4 0 {}} test parseExpr-5.7 {ParseBitOrExpr procedure, error in RHS subexpression} { list [catch {testexprparser {1^2 | 3 | martha} -1} msg] $msg } {1 {syntax error in expression "1^2 | 3 | martha": variable references require preceding $}} test parseExpr-6.1 {ParseBitXorExpr procedure, valid LHS "&" subexpr} { testexprparser {1&2 ^ 3} -1 } {- {} 0 subexpr {1&2 ^ 3} 9 operator ^ 0 subexpr 1&2 5 operator & 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 {}} test parseExpr-6.2 {ParseBitXorExpr procedure, error in LHS "&" subexpr} { list [catch {testexprparser {1^foo ^ 3} -1} msg] $msg } {1 {syntax error in expression "1^foo ^ 3": variable references require preceding $}} test parseExpr-6.3 {ParseBitXorExpr procedure, next lexeme isn't "^"} { testexprparser {1&2? 1 : 0} -1 } {- {} 0 subexpr {1&2? 1 : 0} 11 operator ? 0 subexpr 1&2 5 operator & 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 1 1 text 1 0 subexpr 0 1 text 0 0 {}} test parseExpr-6.4 {ParseBitXorExpr procedure, next lexeme is "^"} { testexprparser {1&2 ^ 3} -1 } {- {} 0 subexpr {1&2 ^ 3} 9 operator ^ 0 subexpr 1&2 5 operator & 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 {}} test parseExpr-6.5 {ParseBitXorExpr procedure, bad lexeme after "^"} {wideIntegerUnparsed} { list [catch {testexprparser {1&2 ^ 12345678901234567890} -1} msg] $msg } {1 {integer value too large to represent}} test parseExpr-6.6 {ParseBitXorExpr procedure, valid RHS subexpression} { testexprparser {1&2 ^ 3 ^ 4} -1 } {- {} 0 subexpr {1&2 ^ 3 ^ 4} 13 operator ^ 0 subexpr {1&2 ^ 3} 9 operator ^ 0 subexpr 1&2 5 operator & 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 subexpr 4 1 text 4 0 {}} test parseExpr-6.7 {ParseBitXorExpr procedure, error in RHS subexpression} { list [catch {testexprparser {1&2 ^ 3 ^ martha} -1} msg] $msg } {1 {syntax error in expression "1&2 ^ 3 ^ martha": variable references require preceding $}} test parseExpr-7.1 {ParseBitAndExpr procedure, valid LHS equality subexpr} { testexprparser {1==2 & 3} -1 } {- {} 0 subexpr {1==2 & 3} 9 operator & 0 subexpr 1==2 5 operator == 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 {}} test parseExpr-7.2 {ParseBitAndExpr procedure, error in LHS equality subexpr} { list [catch {testexprparser {1!=foo & 3} -1} msg] $msg } {1 {syntax error in expression "1!=foo & 3": variable references require preceding $}} test parseExpr-7.3 {ParseBitAndExpr procedure, next lexeme isn't "&"} { testexprparser {1==2? 1 : 0} -1 } {- {} 0 subexpr {1==2? 1 : 0} 11 operator ? 0 subexpr 1==2 5 operator == 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 1 1 text 1 0 subexpr 0 1 text 0 0 {}} test parseExpr-7.4 {ParseBitAndExpr procedure, next lexeme is "&"} { testexprparser {1>2 & 3} -1 } {- {} 0 subexpr {1>2 & 3} 9 operator & 0 subexpr 1>2 5 operator > 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 {}} test parseExpr-7.5 {ParseBitAndExpr procedure, bad lexeme after "&"} {wideIntegerUnparsed} { list [catch {testexprparser {1==2 & 12345678901234567890} -1} msg] $msg } {1 {integer value too large to represent}} test parseExpr-7.6 {ParseBitAndExpr procedure, valid RHS subexpression} { testexprparser {1<2 & 3 & 4} -1 } {- {} 0 subexpr {1<2 & 3 & 4} 13 operator & 0 subexpr {1<2 & 3} 9 operator & 0 subexpr 1<2 5 operator < 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 subexpr 4 1 text 4 0 {}} test parseExpr-7.7 {ParseBitAndExpr procedure, error in RHS subexpression} { list [catch {testexprparser {1==2 & 3>2 & martha} -1} msg] $msg } {1 {syntax error in expression "1==2 & 3>2 & martha": variable references require preceding $}} test parseExpr-8.1 {ParseEqualityExpr procedure, valid LHS relational subexpr} { testexprparser {1<2 == 3} -1 } {- {} 0 subexpr {1<2 == 3} 9 operator == 0 subexpr 1<2 5 operator < 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 {}} test parseExpr-8.2 {ParseEqualityExpr procedure, error in LHS relational subexpr} { list [catch {testexprparser {1>=foo == 3} -1} msg] $msg } {1 {syntax error in expression "1>=foo == 3": variable references require preceding $}} test parseExpr-8.3 {ParseEqualityExpr procedure, next lexeme isn't "==" or "!="} { testexprparser {1<2? 1 : 0} -1 } {- {} 0 subexpr {1<2? 1 : 0} 11 operator ? 0 subexpr 1<2 5 operator < 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 1 1 text 1 0 subexpr 0 1 text 0 0 {}} test parseExpr-8.4 {ParseEqualityExpr procedure, next lexeme is "==" or "!="} { testexprparser {1<2 == 3} -1 } {- {} 0 subexpr {1<2 == 3} 9 operator == 0 subexpr 1<2 5 operator < 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 {}} test parseExpr-8.5 {ParseEqualityExpr procedure, next lexeme is "==" or "!="} { testexprparser {1<2 != 3} -1 } {- {} 0 subexpr {1<2 != 3} 9 operator != 0 subexpr 1<2 5 operator < 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 {}} test parseExpr-8.6 {ParseEqualityExpr procedure, bad lexeme after "==" or "!="} {wideIntegerUnparsed} { list [catch {testexprparser {1<2 == 12345678901234567890} -1} msg] $msg } {1 {integer value too large to represent}} test parseExpr-8.7 {ParseEqualityExpr procedure, valid RHS subexpression} { testexprparser {1<2 == 3 == 4} -1 } {- {} 0 subexpr {1<2 == 3 == 4} 13 operator == 0 subexpr {1<2 == 3} 9 operator == 0 subexpr 1<2 5 operator < 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 subexpr 4 1 text 4 0 {}} test parseExpr-8.8 {ParseEqualityExpr procedure, error in RHS subexpression} { list [catch {testexprparser {1<2 == 3 != martha} -1} msg] $msg } {1 {syntax error in expression "1<2 == 3 != martha": variable references require preceding $}} test parseExpr-9.1 {ParseRelationalExpr procedure, valid LHS shift subexpr} { testexprparser {1<<2 < 3} -1 } {- {} 0 subexpr {1<<2 < 3} 9 operator < 0 subexpr 1<<2 5 operator << 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 {}} test parseExpr-9.2 {ParseRelationalExpr procedure, error in LHS shift subexpr} { list [catch {testexprparser {1>=foo < 3} -1} msg] $msg } {1 {syntax error in expression "1>=foo < 3": variable references require preceding $}} test parseExpr-9.3 {ParseRelationalExpr procedure, next lexeme isn't relational op} { testexprparser {1<<2? 1 : 0} -1 } {- {} 0 subexpr {1<<2? 1 : 0} 11 operator ? 0 subexpr 1<<2 5 operator << 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 1 1 text 1 0 subexpr 0 1 text 0 0 {}} test parseExpr-9.4 {ParseRelationalExpr procedure, next lexeme is relational op} { testexprparser {1<<2 < 3} -1 } {- {} 0 subexpr {1<<2 < 3} 9 operator < 0 subexpr 1<<2 5 operator << 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 {}} test parseExpr-9.5 {ParseRelationalExpr procedure, next lexeme is relational op} { testexprparser {1>>2 > 3} -1 } {- {} 0 subexpr {1>>2 > 3} 9 operator > 0 subexpr 1>>2 5 operator >> 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 {}} test parseExpr-9.6 {ParseRelationalExpr procedure, next lexeme is relational op} { testexprparser {1<<2 <= 3} -1 } {- {} 0 subexpr {1<<2 <= 3} 9 operator <= 0 subexpr 1<<2 5 operator << 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 {}} test parseExpr-9.7 {ParseRelationalExpr procedure, next lexeme is relational op} { testexprparser {1<<2 >= 3} -1 } {- {} 0 subexpr {1<<2 >= 3} 9 operator >= 0 subexpr 1<<2 5 operator << 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 {}} test parseExpr-9.8 {ParseRelationalExpr procedure, bad lexeme after relational op} {wideIntegerUnparsed} { list [catch {testexprparser {1<<2 < 12345678901234567890} -1} msg] $msg } {1 {integer value too large to represent}} test parseExpr-9.9 {ParseRelationalExpr procedure, valid RHS subexpression} { testexprparser {1<<2 < 3 < 4} -1 } {- {} 0 subexpr {1<<2 < 3 < 4} 13 operator < 0 subexpr {1<<2 < 3} 9 operator < 0 subexpr 1<<2 5 operator << 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 subexpr 4 1 text 4 0 {}} test parseExpr-9.10 {ParseRelationalExpr procedure, error in RHS subexpression} { list [catch {testexprparser {1<<2 < 3 > martha} -1} msg] $msg } {1 {syntax error in expression "1<<2 < 3 > martha": variable references require preceding $}} test parseExpr-10.1 {ParseShiftExpr procedure, valid LHS add subexpr} { testexprparser {1+2 << 3} -1 } {- {} 0 subexpr {1+2 << 3} 9 operator << 0 subexpr 1+2 5 operator + 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 {}} test parseExpr-10.2 {ParseShiftExpr procedure, error in LHS add subexpr} { list [catch {testexprparser {1-foo << 3} -1} msg] $msg } {1 {syntax error in expression "1-foo << 3": variable references require preceding $}} test parseExpr-10.3 {ParseShiftExpr procedure, next lexeme isn't "<<" or ">>"} { testexprparser {1+2? 1 : 0} -1 } {- {} 0 subexpr {1+2? 1 : 0} 11 operator ? 0 subexpr 1+2 5 operator + 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 1 1 text 1 0 subexpr 0 1 text 0 0 {}} test parseExpr-10.4 {ParseShiftExpr procedure, next lexeme is "<<" or ">>"} { testexprparser {1+2 << 3} -1 } {- {} 0 subexpr {1+2 << 3} 9 operator << 0 subexpr 1+2 5 operator + 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 {}} test parseExpr-10.5 {ParseShiftExpr procedure, next lexeme is "<<" or ">>"} { testexprparser {1+2 >> 3} -1 } {- {} 0 subexpr {1+2 >> 3} 9 operator >> 0 subexpr 1+2 5 operator + 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 {}} test parseExpr-10.6 {ParseShiftExpr procedure, bad lexeme after "<<" or ">>"} {wideIntegerUnparsed} { list [catch {testexprparser {1+2 << 12345678901234567890} -1} msg] $msg } {1 {integer value too large to represent}} test parseExpr-10.7 {ParseShiftExpr procedure, valid RHS subexpression} { testexprparser {1+2 << 3 << 4} -1 } {- {} 0 subexpr {1+2 << 3 << 4} 13 operator << 0 subexpr {1+2 << 3} 9 operator << 0 subexpr 1+2 5 operator + 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 subexpr 4 1 text 4 0 {}} test parseExpr-10.8 {ParseShiftExpr procedure, error in RHS subexpression} { list [catch {testexprparser {1+2 << 3 >> martha} -1} msg] $msg } {1 {syntax error in expression "1+2 << 3 >> martha": variable references require preceding $}} test parseExpr-11.1 {ParseAddExpr procedure, valid LHS multiply subexpr} { testexprparser {1*2 + 3} -1 } {- {} 0 subexpr {1*2 + 3} 9 operator + 0 subexpr 1*2 5 operator * 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 {}} test parseExpr-11.2 {ParseAddExpr procedure, error in LHS multiply subexpr} { list [catch {testexprparser {1/foo + 3} -1} msg] $msg } {1 {syntax error in expression "1/foo + 3": variable references require preceding $}} test parseExpr-11.3 {ParseAddExpr procedure, next lexeme isn't "+" or "-"} { testexprparser {1*2? 1 : 0} -1 } {- {} 0 subexpr {1*2? 1 : 0} 11 operator ? 0 subexpr 1*2 5 operator * 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 1 1 text 1 0 subexpr 0 1 text 0 0 {}} test parseExpr-11.4 {ParseAddExpr procedure, next lexeme is "+" or "-"} { testexprparser {1*2 + 3} -1 } {- {} 0 subexpr {1*2 + 3} 9 operator + 0 subexpr 1*2 5 operator * 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 {}} test parseExpr-11.5 {ParseAddExpr procedure, next lexeme is "+" or "-"} { testexprparser {1*2 - 3} -1 } {- {} 0 subexpr {1*2 - 3} 9 operator - 0 subexpr 1*2 5 operator * 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 {}} test parseExpr-11.6 {ParseAddExpr procedure, bad lexeme after "+" or "-"} {wideIntegerUnparsed} { list [catch {testexprparser {1*2 + 12345678901234567890} -1} msg] $msg } {1 {integer value too large to represent}} test parseExpr-11.7 {ParseAddExpr procedure, valid RHS subexpression} { testexprparser {1*2 + 3 + 4} -1 } {- {} 0 subexpr {1*2 + 3 + 4} 13 operator + 0 subexpr {1*2 + 3} 9 operator + 0 subexpr 1*2 5 operator * 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 subexpr 4 1 text 4 0 {}} test parseExpr-11.8 {ParseAddExpr procedure, error in RHS subexpression} { list [catch {testexprparser {1*2 + 3 - martha} -1} msg] $msg } {1 {syntax error in expression "1*2 + 3 - martha": variable references require preceding $}} test parseExpr-12.1 {ParseAddExpr procedure, valid LHS multiply subexpr} { testexprparser {1*2 + 3} -1 } {- {} 0 subexpr {1*2 + 3} 9 operator + 0 subexpr 1*2 5 operator * 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 {}} test parseExpr-12.2 {ParseAddExpr procedure, error in LHS multiply subexpr} { list [catch {testexprparser {1/foo + 3} -1} msg] $msg } {1 {syntax error in expression "1/foo + 3": variable references require preceding $}} test parseExpr-12.3 {ParseAddExpr procedure, next lexeme isn't "+" or "-"} { testexprparser {1*2? 1 : 0} -1 } {- {} 0 subexpr {1*2? 1 : 0} 11 operator ? 0 subexpr 1*2 5 operator * 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 1 1 text 1 0 subexpr 0 1 text 0 0 {}} test parseExpr-12.4 {ParseAddExpr procedure, next lexeme is "+" or "-"} { testexprparser {1*2 + 3} -1 } {- {} 0 subexpr {1*2 + 3} 9 operator + 0 subexpr 1*2 5 operator * 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 {}} test parseExpr-12.5 {ParseAddExpr procedure, next lexeme is "+" or "-"} { testexprparser {1*2 - 3} -1 } {- {} 0 subexpr {1*2 - 3} 9 operator - 0 subexpr 1*2 5 operator * 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 {}} test parseExpr-12.6 {ParseAddExpr procedure, bad lexeme after "+" or "-"} {wideIntegerUnparsed} { list [catch {testexprparser {1*2 + 12345678901234567890} -1} msg] $msg } {1 {integer value too large to represent}} test parseExpr-12.7 {ParseAddExpr procedure, valid RHS subexpression} { testexprparser {1*2 + 3 + 4} -1 } {- {} 0 subexpr {1*2 + 3 + 4} 13 operator + 0 subexpr {1*2 + 3} 9 operator + 0 subexpr 1*2 5 operator * 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 subexpr 4 1 text 4 0 {}} test parseExpr-12.8 {ParseAddExpr procedure, error in RHS subexpression} { list [catch {testexprparser {1*2 + 3 - martha} -1} msg] $msg } {1 {syntax error in expression "1*2 + 3 - martha": variable references require preceding $}} test parseExpr-13.1 {ParseMultiplyExpr procedure, valid LHS unary subexpr} { testexprparser {+2 * 3} -1 } {- {} 0 subexpr {+2 * 3} 7 operator * 0 subexpr +2 3 operator + 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 {}} test parseExpr-13.2 {ParseMultiplyExpr procedure, error in LHS unary subexpr} {wideIntegerUnparsed} { list [catch {testexprparser {-12345678901234567890 * 3} -1} msg] $msg } {1 {integer value too large to represent}} test parseExpr-13.3 {ParseMultiplyExpr procedure, next lexeme isn't "*", "/", or "%"} { testexprparser {+2? 1 : 0} -1 } {- {} 0 subexpr {+2? 1 : 0} 9 operator ? 0 subexpr +2 3 operator + 0 subexpr 2 1 text 2 0 subexpr 1 1 text 1 0 subexpr 0 1 text 0 0 {}} test parseExpr-13.4 {ParseMultiplyExpr procedure, next lexeme is "*", "/", or "%"} { testexprparser {-123 * 3} -1 } {- {} 0 subexpr {-123 * 3} 7 operator * 0 subexpr -123 3 operator - 0 subexpr 123 1 text 123 0 subexpr 3 1 text 3 0 {}} test parseExpr-13.5 {ParseMultiplyExpr procedure, next lexeme is "*", "/", or "%"} { testexprparser {+-456 / 3} -1 } {- {} 0 subexpr {+-456 / 3} 9 operator / 0 subexpr +-456 5 operator + 0 subexpr -456 3 operator - 0 subexpr 456 1 text 456 0 subexpr 3 1 text 3 0 {}} test parseExpr-13.6 {ParseMultiplyExpr procedure, next lexeme is "*", "/", or "%"} { testexprparser {+-456 % 3} -1 } {- {} 0 subexpr {+-456 % 3} 9 operator % 0 subexpr +-456 5 operator + 0 subexpr -456 3 operator - 0 subexpr 456 1 text 456 0 subexpr 3 1 text 3 0 {}} test parseExpr-13.7 {ParseMultiplyExpr procedure, bad lexeme after "*", "/", or "%"} {wideIntegerUnparsed} { list [catch {testexprparser {--++5 / 12345678901234567890} -1} msg] $msg } {1 {integer value too large to represent}} test parseExpr-13.8 {ParseMultiplyExpr procedure, valid RHS subexpression} { testexprparser {-2 / 3 % 4} -1 } {- {} 0 subexpr {-2 / 3 % 4} 11 operator % 0 subexpr {-2 / 3} 7 operator / 0 subexpr -2 3 operator - 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 subexpr 4 1 text 4 0 {}} test parseExpr-13.9 {ParseMultiplyExpr procedure, error in RHS subexpression} { list [catch {testexprparser {++2 / 3 * martha} -1} msg] $msg } {1 {syntax error in expression "++2 / 3 * martha": variable references require preceding $}} test parseExpr-14.1 {ParseUnaryExpr procedure, first token is unary operator} { testexprparser {+2} -1 } {- {} 0 subexpr +2 3 operator + 0 subexpr 2 1 text 2 0 {}} test parseExpr-14.2 {ParseUnaryExpr procedure, first token is unary operator} { testexprparser {-2} -1 } {- {} 0 subexpr -2 3 operator - 0 subexpr 2 1 text 2 0 {}} test parseExpr-14.3 {ParseUnaryExpr procedure, first token is unary operator} { testexprparser {~2} -1 } {- {} 0 subexpr ~2 3 operator ~ 0 subexpr 2 1 text 2 0 {}} test parseExpr-14.4 {ParseUnaryExpr procedure, first token is unary operator} { testexprparser {!2} -1 } {- {} 0 subexpr !2 3 operator ! 0 subexpr 2 1 text 2 0 {}} test parseExpr-14.5 {ParseUnaryExpr procedure, error in lexeme after unary op} {wideIntegerUnparsed} { list [catch {testexprparser {-12345678901234567890} -1} msg] $msg } {1 {integer value too large to represent}} test parseExpr-14.6 {ParseUnaryExpr procedure, simple unary expr after unary op} { testexprparser {+"1234"} -1 } {- {} 0 subexpr +\"1234\" 3 operator + 0 subexpr {"1234"} 1 text 1234 0 {}} test parseExpr-14.7 {ParseUnaryExpr procedure, another unary expr after unary op} { testexprparser {~!{fred}} -1 } {- {} 0 subexpr ~!{fred} 5 operator ~ 0 subexpr !{fred} 3 operator ! 0 subexpr {{fred}} 1 text fred 0 {}} test parseExpr-14.8 {ParseUnaryExpr procedure, error in unary expr after unary op} { list [catch {testexprparser {+-||27} -1} msg] $msg } {1 {syntax error in expression "+-||27": unexpected operator ||}} test parseExpr-14.9 {ParseUnaryExpr procedure, error in unary expr after unary op} { list [catch {testexprparser {+-||27} -1} msg] $msg } {1 {syntax error in expression "+-||27": unexpected operator ||}} test parseExpr-14.10 {ParseUnaryExpr procedure, first token is not unary op} { testexprparser {123} -1 } {- {} 0 subexpr 123 1 text 123 0 {}} test parseExpr-14.11 {ParseUnaryExpr procedure, not unary expr, complex primary expr} { testexprparser {(1+2)} -1 } {- {} 0 subexpr 1+2 5 operator + 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 {}} test parseExpr-14.12 {ParseUnaryExpr procedure, not unary expr, error in primary expr} {wideIntegerUnparsed} { list [catch {testexprparser {(12345678901234567890)} -1} msg] $msg } {1 {integer value too large to represent}} test parseExpr-15.1 {ParsePrimaryExpr procedure, just parenthesized subexpr} { testexprparser {({abc}/{def})} -1 } {- {} 0 subexpr {{abc}/{def}} 5 operator / 0 subexpr {{abc}} 1 text abc 0 subexpr {{def}} 1 text def 0 {}} test parseExpr-15.2 {ParsePrimaryExpr procedure, bad lexeme after "("} {wideIntegerUnparsed} { list [catch {testexprparser {(12345678901234567890)} -1} msg] $msg } {1 {integer value too large to represent}} test parseExpr-15.3 {ParsePrimaryExpr procedure, valid parenthesized subexpr} { testexprparser {({abc}? 2*4 : -6)} -1 } {- {} 0 subexpr {{abc}? 2*4 : -6} 13 operator ? 0 subexpr {{abc}} 1 text abc 0 subexpr 2*4 5 operator * 0 subexpr 2 1 text 2 0 subexpr 4 1 text 4 0 subexpr -6 3 operator - 0 subexpr 6 1 text 6 0 {}} test parseExpr-15.4 {ParsePrimaryExpr procedure, error in parenthesized subexpr} { list [catch {testexprparser {(? 123 : 456)} -1} msg] $msg } {1 {syntax error in expression "(? 123 : 456)": unexpected ternary 'then' separator}} test parseExpr-15.5 {ParsePrimaryExpr procedure, missing ")" after in parenthesized subexpr} { list [catch {testexprparser {({abc}/{def}} -1} msg] $msg } {1 {syntax error in expression "({abc}/{def}": looking for close parenthesis}} test parseExpr-15.6 {ParsePrimaryExpr procedure, primary is literal} { testexprparser {12345} -1 } {- {} 0 subexpr 12345 1 text 12345 0 {}} test parseExpr-15.7 {ParsePrimaryExpr procedure, primary is literal} { testexprparser {12345.6789} -1 } {- {} 0 subexpr 12345.6789 1 text 12345.6789 0 {}} test parseExpr-15.8 {ParsePrimaryExpr procedure, primary is var reference} { testexprparser {$a} -1 } {- {} 0 subexpr {$a} 2 variable {$a} 1 text a 0 {}} test parseExpr-15.9 {ParsePrimaryExpr procedure, primary is var reference} { testexprparser {$a(hello$there)} -1 } {- {} 0 subexpr {$a(hello$there)} 5 variable {$a(hello$there)} 4 text a 0 text hello 0 variable {$there} 1 text there 0 {}} test parseExpr-15.10 {ParsePrimaryExpr procedure, primary is var reference} { testexprparser {$a()} -1 } {- {} 0 subexpr {$a()} 3 variable {$a()} 2 text a 0 text {} 0 {}} test parseExpr-15.11 {ParsePrimaryExpr procedure, error in var reference} { list [catch {testexprparser {$a(} -1} msg] $msg } {1 {missing )}} test parseExpr-15.12 {ParsePrimaryExpr procedure, primary is quoted string} { testexprparser {"abc $xyz def"} -1 } {- {} 0 subexpr {"abc $xyz def"} 5 word {"abc $xyz def"} 4 text {abc } 0 variable {$xyz} 1 text xyz 0 text { def} 0 {}} test parseExpr-15.13 {ParsePrimaryExpr procedure, error in quoted string} { list [catch {testexprparser {"$a(12"} -1} msg] $msg } {1 {missing )}} test parseExpr-15.14 {ParsePrimaryExpr procedure, quoted string has multiple tokens} { testexprparser {"abc [xyz] $def"} -1 } {- {} 0 subexpr {"abc [xyz] $def"} 6 word {"abc [xyz] $def"} 5 text {abc } 0 command {[xyz]} 0 text { } 0 variable {$def} 1 text def 0 {}} test parseExpr-15.15 {ParsePrimaryExpr procedure, primary is command} { testexprparser {[def]} -1 } {- {} 0 subexpr {[def]} 1 command {[def]} 0 {}} test parseExpr-15.16 {ParsePrimaryExpr procedure, primary is multiple commands} { testexprparser {[one; two; three; four;]} -1 } {- {} 0 subexpr {[one; two; three; four;]} 1 command {[one; two; three; four;]} 0 {}} test parseExpr-15.17 {ParsePrimaryExpr procedure, primary is multiple commands} { testexprparser {[one; two; three; four;]} -1 } {- {} 0 subexpr {[one; two; three; four;]} 1 command {[one; two; three; four;]} 0 {}} test parseExpr-15.18 {ParsePrimaryExpr procedure, missing close bracket} { list [catch {testexprparser {[one} -1} msg] $msg } {1 {missing close-bracket}} test parseExpr-15.19 {ParsePrimaryExpr procedure, primary is braced string} { testexprparser {{hello world}} -1 } {- {} 0 subexpr {{hello world}} 1 text {hello world} 0 {}} test parseExpr-15.20 {ParsePrimaryExpr procedure, error in primary, which is braced string} { list [catch {testexprparser "\{abc\\\n" -1} msg] $msg } {1 {missing close-brace}} test parseExpr-15.21 {ParsePrimaryExpr procedure, primary is braced string with multiple tokens} { testexprparser "\{ \\ +123 \}" -1 } {- {} 0 subexpr \{\ \ \\\n\ +123\ \} 4 word \{\ \ \\\n\ +123\ \} 3 text { } 0 backslash \\\n\ 0 text {+123 } 0 {}} test parseExpr-15.22 {ParsePrimaryExpr procedure, primary is function call} { testexprparser {foo(123)} -1 } {- {} 0 subexpr foo(123) 3 operator foo 0 subexpr 123 1 text 123 0 {}} test parseExpr-15.23 {ParsePrimaryExpr procedure, bad lexeme after function name} {wideIntegerUnparsed} { list [catch {testexprparser {foo 12345678901234567890 123)} -1} msg] $msg } {1 {integer value too large to represent}} test parseExpr-15.24 {ParsePrimaryExpr procedure, lexeme after function name isn't "("} { list [catch {testexprparser {foo 27.4 123)} -1} msg] $msg } {1 {syntax error in expression "foo 27.4 123)": variable references require preceding $}} test parseExpr-15.25 {ParsePrimaryExpr procedure, bad lexeme after "("} {wideIntegerUnparsed} { list [catch {testexprparser {foo(12345678901234567890)} -1} msg] $msg } {1 {integer value too large to represent}} test parseExpr-15.26 {ParsePrimaryExpr procedure, function call, one arg} { testexprparser {foo(27*4)} -1 } {- {} 0 subexpr foo(27*4) 7 operator foo 0 subexpr 27*4 5 operator * 0 subexpr 27 1 text 27 0 subexpr 4 1 text 4 0 {}} test parseExpr-15.27 {ParsePrimaryExpr procedure, error in function arg} { list [catch {testexprparser {foo(*1-2)} -1} msg] $msg } {1 {syntax error in expression "foo(*1-2)": unexpected operator *}} test parseExpr-15.28 {ParsePrimaryExpr procedure, error in function arg} { list [catch {testexprparser {foo(*1-2)} -1} msg] $msg } {1 {syntax error in expression "foo(*1-2)": unexpected operator *}} test parseExpr-15.29 {ParsePrimaryExpr procedure, function call, comma after arg} { testexprparser {foo(27-2, (-2*[foo]))} -1 } {- {} 0 subexpr {foo(27-2, (-2*[foo]))} 15 operator foo 0 subexpr 27-2 5 operator - 0 subexpr 27 1 text 27 0 subexpr 2 1 text 2 0 subexpr {-2*[foo]} 7 operator * 0 subexpr -2 3 operator - 0 subexpr 2 1 text 2 0 subexpr {[foo]} 1 command {[foo]} 0 {}} test parseExpr-15.30 {ParsePrimaryExpr procedure, bad lexeme after comma} {wideIntegerUnparsed} { list [catch {testexprparser {foo(123, 12345678901234567890)} -1} msg] $msg } {1 {integer value too large to represent}} test parseExpr-15.31 {ParsePrimaryExpr procedure, lexeme not "," or ")" after arg} { list [catch {testexprparser {foo(123 [foo])} -1} msg] $msg } {1 {syntax error in expression "foo(123 [foo])": missing close parenthesis at end of function call}} test parseExpr-15.32 {ParsePrimaryExpr procedure, bad lexeme after primary} {wideIntegerUnparsed} { list [catch {testexprparser {123 12345678901234567890} -1} msg] $msg } {1 {integer value too large to represent}} test parseExpr-15.33 {ParsePrimaryExpr procedure, comma-specific message} { list [catch {testexprparser {123+,456} -1} msg] $msg } {1 {syntax error in expression "123+,456": commas can only separate function arguments}} test parseExpr-15.34 {ParsePrimaryExpr procedure, single equal-specific message} { list [catch {testexprparser {123+=456} -1} msg] $msg } {1 {syntax error in expression "123+=456": single equality character not legal in expressions}} test parseExpr-15.35 {ParsePrimaryExpr procedure, error in parenthesized subexpr} { list [catch {testexprparser {(: 123 : 456)} -1} msg] $msg } {1 {syntax error in expression "(: 123 : 456)": unexpected ternary 'else' separator}} test parseExpr-15.36 {ParsePrimaryExpr procedure, missing close-bracket} { # Test for Bug 681841 list [catch {testexprparser {[set a [format bc]} -1} msg] $msg } {1 {missing close-bracket}} test parseExpr-16.1 {GetLexeme procedure, whitespace before lexeme} { testexprparser { 123} -1 } {- {} 0 subexpr 123 1 text 123 0 {}} test parseExpr-16.2 {GetLexeme procedure, whitespace before lexeme} { testexprparser { \ 456} -1 } {- {} 0 subexpr 456 1 text 456 0 {}} test parseExpr-16.3 {GetLexeme procedure, no lexeme after whitespace} { testexprparser { 123 \ } -1 } {- {} 0 subexpr 123 1 text 123 0 {}} test parseExpr-16.4 {GetLexeme procedure, integer lexeme} { testexprparser {000} -1 } {- {} 0 subexpr 000 1 text 000 0 {}} test parseExpr-16.5 {GetLexeme procedure, integer lexeme too big} {wideIntegerUnparsed} { list [catch {testexprparser {12345678901234567890} -1} msg] $msg } {1 {integer value too large to represent}} test parseExpr-16.6 {GetLexeme procedure, bad integer lexeme} -body { testexprparser {0999} -1 } -returnCodes error -match glob -result {*invalid octal number*} test parseExpr-16.7 {GetLexeme procedure, double lexeme} { testexprparser {0.999} -1 } {- {} 0 subexpr 0.999 1 text 0.999 0 {}} test parseExpr-16.8 {GetLexeme procedure, double lexeme} { testexprparser {.123} -1 } {- {} 0 subexpr .123 1 text .123 0 {}} test parseExpr-16.9 {GetLexeme procedure, double lexeme} {nonPortable unixOnly} { testexprparser {nan} -1 } {- {} 0 subexpr nan 1 text nan 0 {}} test parseExpr-16.10 {GetLexeme procedure, double lexeme} {nonPortable unixOnly} { testexprparser {NaN} -1 } {- {} 0 subexpr NaN 1 text NaN 0 {}} test parseExpr-16.11 {GetLexeme procedure, bad double lexeme too big} { list [catch {testexprparser {123.e+99999999999999} -1} msg] $msg } {1 {floating-point value too large to represent}} test parseExpr-16.12 {GetLexeme procedure, bad double lexeme} { list [catch {testexprparser {123.4x56} -1} msg] $msg } {1 {syntax error in expression "123.4x56": extra tokens at end of expression}} test parseExpr-16.13 {GetLexeme procedure, lexeme is "["} { testexprparser {[foo]} -1 } {- {} 0 subexpr {[foo]} 1 command {[foo]} 0 {}} test parseExpr-16.14 {GetLexeme procedure, lexeme is open brace} { testexprparser {{bar}} -1 } {- {} 0 subexpr {{bar}} 1 text bar 0 {}} test parseExpr-16.15 {GetLexeme procedure, lexeme is "("} { testexprparser {(123)} -1 } {- {} 0 subexpr 123 1 text 123 0 {}} test parseExpr-16.16 {GetLexeme procedure, lexeme is ")"} { testexprparser {(2*3)} -1 } {- {} 0 subexpr 2*3 5 operator * 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 {}} test parseExpr-16.17 {GetLexeme procedure, lexeme is "$"} { testexprparser {$wombat} -1 } {- {} 0 subexpr {$wombat} 2 variable {$wombat} 1 text wombat 0 {}} test parseExpr-16.18 "GetLexeme procedure, lexeme is '\"'" { testexprparser {"fred"} -1 } {- {} 0 subexpr {"fred"} 1 text fred 0 {}} test parseExpr-16.19 {GetLexeme procedure, lexeme is ","} { testexprparser {foo(1,2)} -1 } {- {} 0 subexpr foo(1,2) 5 operator foo 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 {}} test parseExpr-16.20 {GetLexeme procedure, lexeme is "*"} { testexprparser {$a*$b} -1 } {- {} 0 subexpr {$a*$b} 7 operator * 0 subexpr {$a} 2 variable {$a} 1 text a 0 subexpr {$b} 2 variable {$b} 1 text b 0 {}} test parseExpr-16.21 {GetLexeme procedure, lexeme is "/"} { testexprparser {5/6} -1 } {- {} 0 subexpr 5/6 5 operator / 0 subexpr 5 1 text 5 0 subexpr 6 1 text 6 0 {}} test parseExpr-16.22 {GetLexeme procedure, lexeme is "%"} { testexprparser {5%[xxx]} -1 } {- {} 0 subexpr {5%[xxx]} 5 operator % 0 subexpr 5 1 text 5 0 subexpr {[xxx]} 1 command {[xxx]} 0 {}} test parseExpr-16.23 {GetLexeme procedure, lexeme is "+"} { testexprparser {1+2} -1 } {- {} 0 subexpr 1+2 5 operator + 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 {}} test parseExpr-16.24 {GetLexeme procedure, lexeme is "-"} { testexprparser {.12-0e27} -1 } {- {} 0 subexpr .12-0e27 5 operator - 0 subexpr .12 1 text .12 0 subexpr 0e27 1 text 0e27 0 {}} test parseExpr-16.25 {GetLexeme procedure, lexeme is "?" or ":"} { testexprparser {$b? 1 : 0} -1 } {- {} 0 subexpr {$b? 1 : 0} 8 operator ? 0 subexpr {$b} 2 variable {$b} 1 text b 0 subexpr 1 1 text 1 0 subexpr 0 1 text 0 0 {}} test parseExpr-16.26 {GetLexeme procedure, lexeme is "<"} { testexprparser {2<3} -1 } {- {} 0 subexpr 2<3 5 operator < 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 {}} test parseExpr-16.27 {GetLexeme procedure, lexeme is "<<"} { testexprparser {2<<3} -1 } {- {} 0 subexpr 2<<3 5 operator << 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 {}} test parseExpr-16.28 {GetLexeme procedure, lexeme is "<="} { testexprparser {2<=3} -1 } {- {} 0 subexpr 2<=3 5 operator <= 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 {}} test parseExpr-16.29 {GetLexeme procedure, lexeme is ">"} { testexprparser {2>3} -1 } {- {} 0 subexpr 2>3 5 operator > 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 {}} test parseExpr-16.30 {GetLexeme procedure, lexeme is ">>"} { testexprparser {2>>3} -1 } {- {} 0 subexpr 2>>3 5 operator >> 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 {}} test parseExpr-16.31 {GetLexeme procedure, lexeme is ">="} { testexprparser {2>=3} -1 } {- {} 0 subexpr 2>=3 5 operator >= 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 {}} test parseExpr-16.32 {GetLexeme procedure, lexeme is "=="} { testexprparser {2==3} -1 } {- {} 0 subexpr 2==3 5 operator == 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 {}} test parseExpr-16.33 {GetLexeme procedure, bad lexeme starting with "="} { list [catch {testexprparser {2=+3} -1} msg] $msg } {1 {syntax error in expression "2=+3": extra tokens at end of expression}} test parseExpr-16.34 {GetLexeme procedure, lexeme is "!="} { testexprparser {2!=3} -1 } {- {} 0 subexpr 2!=3 5 operator != 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 {}} test parseExpr-16.35 {GetLexeme procedure, lexeme is "!"} { testexprparser {!2} -1 } {- {} 0 subexpr !2 3 operator ! 0 subexpr 2 1 text 2 0 {}} test parseExpr-16.36 {GetLexeme procedure, lexeme is "&&"} { testexprparser {2&&3} -1 } {- {} 0 subexpr 2&&3 5 operator && 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 {}} test parseExpr-16.37 {GetLexeme procedure, lexeme is "&"} { testexprparser {1&2} -1 } {- {} 0 subexpr 1&2 5 operator & 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 {}} test parseExpr-16.38 {GetLexeme procedure, lexeme is "^"} { testexprparser {1^2} -1 } {- {} 0 subexpr 1^2 5 operator ^ 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 {}} test parseExpr-16.39 {GetLexeme procedure, lexeme is "||"} { testexprparser {2||3} -1 } {- {} 0 subexpr 2||3 5 operator || 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 {}} test parseExpr-16.40 {GetLexeme procedure, lexeme is "|"} { testexprparser {1|2} -1 } {- {} 0 subexpr 1|2 5 operator | 0 subexpr 1 1 text 1 0 subexpr 2 1 text 2 0 {}} test parseExpr-16.41 {GetLexeme procedure, lexeme is "~"} { testexprparser {~2} -1 } {- {} 0 subexpr ~2 3 operator ~ 0 subexpr 2 1 text 2 0 {}} test parseExpr-16.42 {GetLexeme procedure, lexeme is func name} { testexprparser {george()} -1 } {- {} 0 subexpr george() 1 operator george 0 {}} test parseExpr-16.43 {GetLexeme procedure, lexeme is func name} { testexprparser {harmonic_ratio(2,3)} -1 } {- {} 0 subexpr harmonic_ratio(2,3) 5 operator harmonic_ratio 0 subexpr 2 1 text 2 0 subexpr 3 1 text 3 0 {}} test parseExpr-16.44 {GetLexeme procedure, unknown lexeme} { list [catch {testexprparser {@27} -1} msg] $msg } {1 {syntax error in expression "@27": character not legal in expressions}} test parseExpr-17.1 {PrependSubExprTokens procedure, expand token array} { testexprparser {[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]} -1 } {- {} 0 subexpr {[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]} 13 operator && 0 subexpr {[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]} 9 operator && 0 subexpr {[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]} 5 operator && 0 subexpr {[string compare [format %c $i] [string index $a $i]]} 1 command {[string compare [format %c $i] [string index $a $i]]} 0 subexpr {[string compare [format %c $i] [string index $a $i]]} 1 command {[string compare [format %c $i] [string index $a $i]]} 0 subexpr {[string compare [format %c $i] [string index $a $i]]} 1 command {[string compare [format %c $i] [string index $a $i]]} 0 subexpr {[string compare [format %c $i] [string index $a $i]]} 1 command {[string compare [format %c $i] [string index $a $i]]} 0 {}} test parseExpr-18.1 {LogSyntaxError procedure, error in expr longer than 60 chars} { list [catch {testexprparser {(+0123456)*(+0123456)*(+0123456)*(+0123456)*(+0123456)*(+0123456)*(+0123456)/} -1} msg] $msg } {1 {syntax error in expression "(+0123456)*(+0123456)*(+0123456)*(+0123456)*(+0123456)*(+012...": premature end of expression}} test parseExpr-19.1 {TclParseInteger: [Bug 648441]} { # Should see this as integer "0" followed by incomplete function "x" # Thus, syntax error. # If Bug 648441 is not fixed, "0x" will be seen as floating point 0.0 list [catch {expr 0x} result] $result } [list 1 {syntax error in expression "0x": extra tokens at end of expression}] # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/subst.test0000644003604700454610000002134511737050674014127 0ustar dgp771div# Commands covered: subst # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1994 The Regents of the University of California. # Copyright (c) 1994 Sun Microsystems, Inc. # Copyright (c) 1998-2000 Ajuba Solutions. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } test subst-1.1 {basics} { list [catch {subst} msg] $msg } {1 {wrong # args: should be "subst ?-nobackslashes? ?-nocommands? ?-novariables? string"}} test subst-1.2 {basics} { list [catch {subst a b c} msg] $msg } {1 {bad switch "a": must be -nobackslashes, -nocommands, or -novariables}} test subst-2.1 {simple strings} { subst {} } {} test subst-2.2 {simple strings} { subst a } a test subst-2.3 {simple strings} { subst abcdefg } abcdefg test subst-2.4 {simple strings} { # Tcl Bug 685106 subst [bytestring bar\x00soom] } [bytestring bar\x00soom] test subst-3.1 {backslash substitutions} { subst {\x\$x\[foo bar]\\} } "x\$x\[foo bar]\\" test subst-3.2 {backslash substitutions with utf chars} { # 'j' is just a char that doesn't mean anything, and \344 is 'ф' # that also doesn't mean anything, but is multi-byte in UTF-8. list [subst \j] [subst \\j] [subst \\344] [subst \\\344] } "j j \344 \344" test subst-4.1 {variable substitutions} { set a 44 subst {$a} } {44} test subst-4.2 {variable substitutions} { set a 44 subst {x$a.y{$a}.z} } {x44.y{44}.z} test subst-4.3 {variable substitutions} { catch {unset a} set a(13) 82 set i 13 subst {x.$a($i)} } {x.82} catch {unset a} set long {This is a very long string, intentionally made so long that it will overflow the static character size for dstrings, so that additional memory will have to be allocated by subst. That way, if the subst procedure forgets to free up memory while returning an error, there will be memory that isn't freed (this will be detected when the tests are run under a checking memory allocator such as Purify).} test subst-4.4 {variable substitutions} { list [catch {subst {$long $a}} msg] $msg } {1 {can't read "a": no such variable}} test subst-5.1 {command substitutions} { subst {[concat {}]} } {} test subst-5.2 {command substitutions} { subst {[concat A test string]} } {A test string} test subst-5.3 {command substitutions} { subst {x.[concat foo].y.[concat bar].z} } {x.foo.y.bar.z} test subst-5.4 {command substitutions} { list [catch {subst {$long [set long] [bogus_command]}} msg] $msg } {1 {invalid command name "bogus_command"}} test subst-5.5 {command substitutions} { set a 0 list [catch {subst {[set a 1}} msg] $a $msg } {1 0 {missing close-bracket}} test subst-5.6 {command substitutions} { set a 0 list [catch {subst {0[set a 1}} msg] $a $msg } {1 0 {missing close-bracket}} test subst-5.7 {command substitutions} { set a 0 list [catch {subst {0[set a 1; set a 2}} msg] $a $msg } {1 1 {missing close-bracket}} # repeat the tests above simulating cmd line input test subst-5.8 {command substitutions} { set script {[subst {[set a 1}]} list [catch {exec [info nameofexecutable] << $script} msg] $msg } {1 {missing close-bracket}} test subst-5.9 {command substitutions} { set script {[subst {0[set a 1}]} list [catch {exec [info nameofexecutable] << $script} msg] $msg } {1 {missing close-bracket}} test subst-5.10 {command substitutions} { set script {[subst {0[set a 1; set a 2}]} list [catch {exec [info nameofexecutable] << $script} msg] $msg } {1 {missing close-bracket}} test subst-6.1 {clear the result after command substitution} { catch {unset a} list [catch {subst {[concat foo] $a}} msg] $msg } {1 {can't read "a": no such variable}} test subst-7.1 {switches} { list [catch {subst foo bar} msg] $msg } {1 {bad switch "foo": must be -nobackslashes, -nocommands, or -novariables}} test subst-7.2 {switches} { list [catch {subst -no bar} msg] $msg } {1 {ambiguous switch "-no": must be -nobackslashes, -nocommands, or -novariables}} test subst-7.3 {switches} { list [catch {subst -bogus bar} msg] $msg } {1 {bad switch "-bogus": must be -nobackslashes, -nocommands, or -novariables}} test subst-7.4 {switches} { set x 123 subst -nobackslashes {abc $x [expr 1+2] \\\x41} } {abc 123 3 \\\x41} test subst-7.5 {switches} { set x 123 subst -nocommands {abc $x [expr 1+2] \\\x41} } {abc 123 [expr 1+2] \A} test subst-7.6 {switches} { set x 123 subst -novariables {abc $x [expr 1+2] \\\x41} } {abc $x 3 \A} test subst-7.7 {switches} { set x 123 subst -nov -nob -noc {abc $x [expr 1+2] \\\x41} } {abc $x [expr 1+2] \\\x41} test subst-8.1 {return in a subst} { subst {foo [return {x}; bogus code] bar} } {foo x bar} test subst-8.2 {return in a subst} { subst {foo [return x ; bogus code] bar} } {foo x bar} test subst-8.3 {return in a subst} { subst {foo [if 1 { return {x}; bogus code }] bar} } {foo x bar} test subst-8.4 {return in a subst} { subst {[eval {return hi}] there} } {hi there} test subst-8.5 {return in a subst} { subst {foo [return {]}; bogus code] bar} } {foo ] bar} test subst-8.6 {return in a subst} { list [catch {subst {foo [return {x}; bogus code bar}} msg] $msg } {1 {missing close-bracket}} test subst-8.7 {return in a subst, parse error} { subst {foo [return {x} ; set a {}" ; stuff] bar} } {foo xset a {}" ; stuff] bar} test subst-8.8 {return in a subst, parse error} { subst {foo [return {x} ; set bar baz ; set a {}" ; stuff] bar} } {foo xset bar baz ; set a {}" ; stuff] bar} test subst-8.9 {return in a variable subst} { subst {foo $var([return {x}]) bar} } {foo x bar} test subst-9.1 {error in a subst} { list [catch {subst {[error foo; bogus code]bar}} msg] $msg } {1 foo} test subst-9.2 {error in a subst} { list [catch {subst {[if 1 { error foo; bogus code}]bar}} msg] $msg } {1 foo} test subst-9.3 {error in a variable subst} { list [catch {subst {foo $var([error foo]) bar}} msg] $msg } {1 foo} test subst-10.1 {break in a subst} { subst {foo [break; bogus code] bar} } {foo } test subst-10.2 {break in a subst} { subst {foo [break; return x; bogus code] bar} } {foo } test subst-10.3 {break in a subst} { subst {foo [if 1 { break; bogus code}] bar} } {foo } test subst-10.4 {break in a subst, parse error} { subst {foo [break ; set a {}{} ; stuff] bar} } {foo } test subst-10.5 {break in a subst, parse error} { subst {foo [break ;set bar baz ;set a {}{} ; stuff] bar} } {foo } test subst-10.6 {break in a variable subst} { subst {foo $var([break]) bar} } {foo } test subst-11.1 {continue in a subst} { subst {foo [continue; bogus code] bar} } {foo bar} test subst-11.2 {continue in a subst} { subst {foo [continue; return x; bogus code] bar} } {foo bar} test subst-11.3 {continue in a subst} { subst {foo [if 1 { continue; bogus code}] bar} } {foo bar} test subst-11.4 {continue in a subst, parse error} { subst {foo [continue ; set a {}{} ; stuff] bar} } {foo set a {}{} ; stuff] bar} test subst-11.5 {continue in a subst, parse error} { subst {foo [continue ;set bar baz ;set a {}{} ; stuff] bar} } {foo set bar baz ;set a {}{} ; stuff] bar} test subst-11.6 {continue in a variable subst} { subst {foo $var([continue]) bar} } {foo bar} test subst-12.1 {nasty case, Bug 1036649} { for {set i 0} {$i < 10} {incr i} { set res [list [catch {subst "\[subst {};"} msg] $msg] if {$msg ne "missing close-bracket"} break } set res } {1 {missing close-bracket}} test subst-12.2 {nasty case, Bug 1036649} { for {set i 0} {$i < 10} {incr i} { set res [list [catch {subst "\[subst {}; "} msg] $msg] if {$msg ne "missing close-bracket"} break } set res } {1 {missing close-bracket}} test subst-12.3 {nasty case, Bug 1036649} { set x 0 for {set i 0} {$i < 10} {incr i} { set res [list [catch {subst "\[incr x;"} msg] $msg] if {$msg ne "missing close-bracket"} break } list $res $x } {{1 {missing close-bracket}} 10} test subst-12.4 {nasty case, Bug 1036649} { set x 0 for {set i 0} {$i < 10} {incr i} { set res [list [catch {subst "\[incr x; "} msg] $msg] if {$msg ne "missing close-bracket"} break } list $res $x } {{1 {missing close-bracket}} 10} test subst-12.5 {nasty case, Bug 1036649} { set x 0 for {set i 0} {$i < 10} {incr i} { set res [list [catch {subst "\[incr x"} msg] $msg] if {$msg ne "missing close-bracket"} break } list $res $x } {{1 {missing close-bracket}} 0} # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/platform.test0000644003604700454610000000403312052456744014605 0ustar dgp771div# The file tests the tcl_platform variable # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1999 by Scriptics Corporation # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } testConstraint testCPUID [llength [info commands testcpuid]] test platform-1.1 {TclpSetVariables: tcl_platform} { interp create i i eval {catch {unset tcl_platform(debug)}} i eval {catch {unset tcl_platform(threaded)}} i eval {catch {unset tcl_platform(tip,268)}} i eval {catch {unset tcl_platform(tip,280)}} set result [i eval {lsort [array names tcl_platform]}] interp delete i set result } {byteOrder machine os osVersion platform user wordSize} # Test assumes twos-complement arithmetic, which is true of virtually # everything these days. Note that this does *not* use wide(), and # this is intentional since that could make Tcl's numbers wider than # the machine-integer on some platforms... test platform-2.1 {tcl_platform(wordSize) indicates size of native word} { set result [expr {1 << (8 * $tcl_platform(wordSize) - 1)}] # Result must be the largest bit in a machine word, which this checks # without assuming how wide the word really is list [expr {$result < 0}] [expr {$result ^ ($result - 1)}] } {1 -1} # On Windows/UNIX, test that the CPU ID works test platform-3.1 {CPU ID on Windows/UNIX} \ -constraints testCPUID \ -body { set cpudata [testcpuid 0] binary format iii \ [lindex $cpudata 1] \ [lindex $cpudata 3] \ [lindex $cpudata 2] } \ -match regexp \ -result {^(?:AuthenticAMD|CentaurHauls|CyrixInstead|GenuineIntel)$} # cleanup ::tcltest::cleanupTests return # Local Variables: # mode: tcl # End: tcl8.4.20/tests/basic.test0000644003604700454610000005577011737050674014061 0ustar dgp771div# This file contains tests for the tclBasic.c source file. Tests appear in # the same order as the C code that they test. The set of tests is # currently incomplete since it currently includes only new tests for # code changed for the addition of Tcl namespaces. Other variable- # related tests appear in several other test files including # assocd.test, cmdInfo.test, eval.test, expr.test, interp.test, # and trace.test. # # Sourcing this file into Tcl runs the tests and generates output for # errors. No output means no errors were found. # # Copyright (c) 1997 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. package require tcltest 2 namespace import -force ::tcltest::* testConstraint testcmdtoken [llength [info commands testcmdtoken]] testConstraint testcmdtrace [llength [info commands testcmdtrace]] testConstraint testcreatecommand [llength [info commands testcreatecommand]] testConstraint testevalex [llength [info commands testevalex]] testConstraint exec [llength [info commands exec]] # This variable needs to be changed when the major or minor version number for # Tcl changes. set tclvers 8.4 catch {namespace delete test_ns_basic} catch {interp delete test_interp} catch {rename p ""} catch {rename q ""} catch {rename cmd ""} catch {unset x} test basic-1.1 {Tcl_CreateInterp, creates interp's global namespace} { catch {interp delete test_interp} interp create test_interp interp eval test_interp { namespace eval test_ns_basic { proc p {} { return [namespace current] } } } list [interp eval test_interp {test_ns_basic::p}] \ [interp delete test_interp] } {::test_ns_basic {}} test basic-2.1 {TclHideUnsafeCommands} {emptyTest} { } {} test basic-3.1 {Tcl_CallWhenDeleted: see dcall.test} {emptyTest} { } {} test basic-4.1 {Tcl_DontCallWhenDeleted: see dcall.test} {emptyTest} { } {} test basic-5.1 {Tcl_SetAssocData: see assoc.test} {emptyTest} { } {} test basic-6.1 {Tcl_DeleteAssocData: see assoc.test} {emptyTest} { } {} test basic-7.1 {Tcl_GetAssocData: see assoc.test} {emptyTest} { } {} test basic-8.1 {Tcl_InterpDeleted} {emptyTest} { } {} test basic-9.1 {Tcl_DeleteInterp: see interp.test} {emptyTest} { } {} test basic-10.1 {DeleteInterpProc, destroys interp's global namespace} { catch {interp delete test_interp} interp create test_interp interp eval test_interp { namespace eval test_ns_basic { namespace export p proc p {} { return [namespace current] } } namespace eval test_ns_2 { namespace import ::test_ns_basic::p variable v 27 proc q {} { variable v return "[p] $v" } } } list [interp eval test_interp {test_ns_2::q}] \ [interp eval test_interp {namespace delete ::}] \ [catch {interp eval test_interp {set a 123}} msg] $msg \ [interp delete test_interp] } {{::test_ns_basic 27} {} 1 {invalid command name "set"} {}} test basic-11.1 {HiddenCmdsDeleteProc, invalidate cached refs to deleted hidden cmd} { catch {interp delete test_interp} interp create test_interp interp eval test_interp { proc p {} { return 27 } } interp alias {} localP test_interp p list [interp eval test_interp {p}] \ [localP] \ [test_interp hide p] \ [catch {localP} msg] $msg \ [interp delete test_interp] \ [catch {localP} msg] $msg } {27 27 {} 1 {invalid command name "p"} {} 1 {invalid command name "localP"}} # NB: More tests about hide/expose are found in interp.test test basic-12.1 {Tcl_HideCommand, names of hidden cmds can't have namespace qualifiers} { catch {interp delete test_interp} interp create test_interp interp eval test_interp { namespace eval test_ns_basic { proc p {} { return [namespace current] } } } list [catch {test_interp hide test_ns_basic::p x} msg] $msg \ [catch {test_interp hide x test_ns_basic::p} msg1] $msg1 \ [interp delete test_interp] } {1 {can only hide global namespace commands (use rename then hide)} 1 {cannot use namespace qualifiers in hidden command token (rename)} {}} test basic-12.2 {Tcl_HideCommand, a hidden cmd remembers its containing namespace} { catch {namespace delete test_ns_basic} catch {rename cmd ""} proc cmd {} { ;# note that this is global return [namespace current] } namespace eval test_ns_basic { proc hideCmd {} { interp hide {} cmd } proc exposeCmd {} { interp expose {} cmd } proc callCmd {} { cmd } } list [test_ns_basic::callCmd] \ [test_ns_basic::hideCmd] \ [catch {cmd} msg] $msg \ [test_ns_basic::exposeCmd] \ [test_ns_basic::callCmd] \ [namespace delete test_ns_basic] } {:: {} 1 {invalid command name "cmd"} {} :: {}} test basic-13.1 {Tcl_ExposeCommand, a command stays in the global namespace and can not go to another namespace} { catch {namespace delete test_ns_basic} catch {rename cmd ""} proc cmd {} { ;# note that this is global return [namespace current] } namespace eval test_ns_basic { proc hideCmd {} { interp hide {} cmd } proc exposeCmdFailing {} { interp expose {} cmd ::test_ns_basic::newCmd } proc exposeCmdWorkAround {} { interp expose {} cmd; rename cmd ::test_ns_basic::newCmd; } proc callCmd {} { cmd } } list [test_ns_basic::callCmd] \ [test_ns_basic::hideCmd] \ [catch {test_ns_basic::exposeCmdFailing} msg] $msg \ [test_ns_basic::exposeCmdWorkAround] \ [test_ns_basic::newCmd] \ [namespace delete test_ns_basic] } {:: {} 1 {can not expose to a namespace (use expose to toplevel, then rename)} {} ::test_ns_basic {}} test basic-13.2 {Tcl_ExposeCommand, invalidate cached refs to cmd now being exposed} { catch {rename p ""} catch {rename cmd ""} proc p {} { cmd } proc cmd {} { return 42 } list [p] \ [interp hide {} cmd] \ [proc cmd {} {return Hello}] \ [cmd] \ [rename cmd ""] \ [interp expose {} cmd] \ [p] } {42 {} {} Hello {} {} 42} test basic-14.1 {Tcl_CreateCommand, new cmd goes into a namespace specified in its name, if any} {testcreatecommand} { catch {eval namespace delete [namespace children :: test_ns_*]} list [testcreatecommand create] \ [test_ns_basic::createdcommand] \ [testcreatecommand delete] } {{} {CreatedCommandProc in ::test_ns_basic} {}} test basic-14.2 {Tcl_CreateCommand, namespace code ignore single ":"s in middle or end of names} {testcreatecommand} { catch {eval namespace delete [namespace children :: test_ns_*]} catch {rename value:at: ""} list [testcreatecommand create2] \ [value:at:] \ [testcreatecommand delete2] } {{} {CreatedCommandProc2 in ::} {}} test basic-15.1 {Tcl_CreateObjCommand, new cmd goes into a namespace specified in its name, if any} { catch {eval namespace delete [namespace children :: test_ns_*]} namespace eval test_ns_basic {} proc test_ns_basic::cmd {} { ;# proc requires that ns already exist return [namespace current] } list [test_ns_basic::cmd] \ [namespace delete test_ns_basic] } {::test_ns_basic {}} test basic-16.1 {TclInvokeStringCommand} {emptyTest} { } {} test basic-17.1 {TclInvokeObjCommand} {emptyTest} { } {} test basic-18.1 {TclRenameCommand, name of existing cmd can have namespace qualifiers} { catch {eval namespace delete [namespace children :: test_ns_*]} catch {rename cmd ""} namespace eval test_ns_basic { proc p {} { return "p in [namespace current]" } } list [test_ns_basic::p] \ [rename test_ns_basic::p test_ns_basic::q] \ [test_ns_basic::q] } {{p in ::test_ns_basic} {} {p in ::test_ns_basic}} test basic-18.2 {TclRenameCommand, existing cmd must be found} { catch {eval namespace delete [namespace children :: test_ns_*]} list [catch {rename test_ns_basic::p test_ns_basic::q} msg] $msg } {1 {can't rename "test_ns_basic::p": command doesn't exist}} test basic-18.3 {TclRenameCommand, delete cmd if new name is empty} { catch {eval namespace delete [namespace children :: test_ns_*]} namespace eval test_ns_basic { proc p {} { return "p in [namespace current]" } } list [info commands test_ns_basic::*] \ [rename test_ns_basic::p ""] \ [info commands test_ns_basic::*] } {::test_ns_basic::p {} {}} test basic-18.4 {TclRenameCommand, bad new name} { catch {eval namespace delete [namespace children :: test_ns_*]} namespace eval test_ns_basic { proc p {} { return "p in [namespace current]" } } rename test_ns_basic::p :::george::martha } {} test basic-18.5 {TclRenameCommand, new name must not already exist} { namespace eval test_ns_basic { proc q {} { return 42 } } list [catch {rename test_ns_basic::q :::george::martha} msg] $msg } {1 {can't rename to ":::george::martha": command already exists}} test basic-18.6 {TclRenameCommand, check for command shadowing by newly renamed cmd} { catch {eval namespace delete [namespace children :: test_ns_*]} catch {rename p ""} catch {rename q ""} proc p {} { return "p in [namespace current]" } proc q {} { return "q in [namespace current]" } namespace eval test_ns_basic { proc callP {} { p } } list [test_ns_basic::callP] \ [rename q test_ns_basic::p] \ [test_ns_basic::callP] } {{p in ::} {} {q in ::test_ns_basic}} test basic-19.1 {Tcl_SetCommandInfo} {emptyTest} { } {} test basic-20.1 {Tcl_GetCommandInfo, names for commands created inside namespaces} {testcmdtoken} { catch {eval namespace delete [namespace children :: test_ns_*]} catch {rename p ""} catch {rename q ""} catch {unset x} set x [namespace eval test_ns_basic::test_ns_basic2 { # the following creates a cmd in the global namespace testcmdtoken create p }] list [testcmdtoken name $x] \ [rename ::p q] \ [testcmdtoken name $x] } {{p ::p} {} {q ::q}} test basic-20.2 {Tcl_GetCommandInfo, names for commands created outside namespaces} {testcmdtoken} { catch {rename q ""} set x [testcmdtoken create test_ns_basic::test_ns_basic2::p] list [testcmdtoken name $x] \ [rename test_ns_basic::test_ns_basic2::p q] \ [testcmdtoken name $x] } {{p ::test_ns_basic::test_ns_basic2::p} {} {q ::q}} test basic-21.1 {Tcl_GetCommandName} {emptyTest} { } {} test basic-22.1 {Tcl_GetCommandFullName} { catch {eval namespace delete [namespace children :: test_ns_*]} namespace eval test_ns_basic1 { namespace export cmd* proc cmd1 {} {} proc cmd2 {} {} } namespace eval test_ns_basic2 { namespace export * namespace import ::test_ns_basic1::* proc p {} {} } namespace eval test_ns_basic3 { namespace import ::test_ns_basic2::* proc q {} {} list [namespace which -command foreach] \ [namespace which -command q] \ [namespace which -command p] \ [namespace which -command cmd1] \ [namespace which -command ::test_ns_basic2::cmd2] } } {::foreach ::test_ns_basic3::q ::test_ns_basic3::p ::test_ns_basic3::cmd1 ::test_ns_basic2::cmd2} test basic-23.1 {Tcl_DeleteCommand} {emptyTest} { } {} test basic-24.1 {Tcl_DeleteCommandFromToken, invalidate all compiled code if cmd has compile proc} { catch {interp delete test_interp} catch {unset x} interp create test_interp interp eval test_interp { proc useSet {} { return [set a 123] } } set x [interp eval test_interp {useSet}] interp eval test_interp { rename set "" proc set {args} { return "set called with $args" } } list $x \ [interp eval test_interp {useSet}] \ [interp delete test_interp] } {123 {set called with a 123} {}} test basic-24.2 {Tcl_DeleteCommandFromToken, deleting commands changes command epoch} { catch {eval namespace delete [namespace children :: test_ns_*]} catch {rename p ""} proc p {} { return "global p" } namespace eval test_ns_basic { proc p {} { return "namespace p" } proc callP {} { p } } list [test_ns_basic::callP] \ [rename test_ns_basic::p ""] \ [test_ns_basic::callP] } {{namespace p} {} {global p}} test basic-24.3 {Tcl_DeleteCommandFromToken, delete imported cmds that refer to a deleted cmd} { catch {eval namespace delete [namespace children :: test_ns_*]} catch {rename p ""} namespace eval test_ns_basic { namespace export p proc p {} {return 42} } namespace eval test_ns_basic2 { namespace import ::test_ns_basic::* proc callP {} { p } } list [test_ns_basic2::callP] \ [info commands test_ns_basic2::*] \ [rename test_ns_basic::p ""] \ [catch {test_ns_basic2::callP} msg] $msg \ [info commands test_ns_basic2::*] } {42 {::test_ns_basic2::callP ::test_ns_basic2::p} {} 1 {invalid command name "p"} ::test_ns_basic2::callP} test basic-25.1 {TclCleanupCommand} {emptyTest} { } {} test basic-26.1 {Tcl_EvalObj: preserve object while evaling it} { # If object isn't preserved, errorInfo would be set to # "foo\n while executing\n\"garbage bytes\"" because the object's # string would have been freed, leaving garbage bytes for the error # message. proc bgerror {args} {set ::x $::errorInfo} set fName [makeFile {} test1] set f [open $fName w] fileevent $f writable "fileevent $f writable {}; error foo" set x {} vwait x close $f removeFile test1 rename bgerror {} set x } "foo\n while executing\n\"error foo\"" test basic-26.2 {Tcl_EvalObjEx, pure-list branch: preserve "objv"} { # # Follow the pure-list branch in a manner that # a - the pure-list internal rep is destroyed by shimmering # b - the command returns an error # As the error code in Tcl_EvalObjv accesses the list elements, this will # cause a segfault if [Bug 1119369] has not been fixed. # set SRC [list foo 1] ;# pure-list command proc foo str { # Shimmer pure-list to cmdName, cleanup and error proc $::SRC {} {}; $::SRC error "BAD CALL" } catch {eval $SRC} } 1 test basic-27.1 {Tcl_ExprLong} {emptyTest} { } {} test basic-28.1 {Tcl_ExprDouble} {emptyTest} { } {} test basic-29.1 {Tcl_ExprBoolean} {emptyTest} { } {} test basic-30.1 {Tcl_ExprLongObj} {emptyTest} { } {} test basic-31.1 {Tcl_ExprDoubleObj} {emptyTest} { } {} test basic-32.1 {Tcl_ExprBooleanObj} {emptyTest} { } {} test basic-33.1 {TclInvoke} {emptyTest} { } {} test basic-34.1 {TclGlobalInvoke} {emptyTest} { } {} test basic-35.1 {TclObjInvokeGlobal} {emptyTest} { } {} test basic-36.1 {TclObjInvoke, lookup of "unknown" command} { catch {eval namespace delete [namespace children :: test_ns_*]} catch {interp delete test_interp} interp create test_interp interp eval test_interp { proc unknown {args} { return "global unknown" } namespace eval test_ns_basic { proc unknown {args} { return "namespace unknown" } } } list [interp alias test_interp newAlias test_interp doesntExist] \ [catch {interp eval test_interp {newAlias}} msg] $msg \ [interp delete test_interp] } {newAlias 0 {global unknown} {}} test basic-37.1 {Tcl_ExprString: see expr.test} {emptyTest} { } {} test basic-38.1 {Tcl_ExprObj} {emptyTest} { } {} test basic-39.1 {Tcl_CreateTrace, correct command and argc/argv arguments of trace proc} {testcmdtrace} { testcmdtrace tracetest {set stuff [expr 14 + 16]} } {{expr 14 + 16} {expr 14 + 16} {set stuff [expr 14 + 16]} {set stuff 30}} test basic-39.2 {Tcl_CreateTrace, correct command and argc/argv arguments of trace proc} {testcmdtrace} { testcmdtrace tracetest {set stuff [info tclversion]} } [list {info tclversion} {info tclversion} {set stuff [info tclversion]} "set stuff $tclvers"] test basic-39.3 {Tcl_CreateTrace, correct command and argc/argv arguments of trace proc} {testcmdtrace} { testcmdtrace deletetest {set stuff [info tclversion]} } $tclvers test basic-39.4 {Tcl_CreateTrace, check that tracing doesn't cause memory faults} {testcmdtrace} { # Note that the proc call is the same as the variable name, and that # the call can be direct or indirect by way of another procedure proc tracer {args} {} proc tracedLoop {level} { incr level tracer foreach tracer [expr {$level==1 ? {1 2} : {}}] {tracedLoop $level} } testcmdtrace tracetest {tracedLoop 0} } {{tracedLoop 0} {tracedLoop 0} {incr level} {incr level} tracer {tracer} {expr {$level==1 ? {1 2} : {}}} {expr {$level==1 ? {1 2} : {}}} {foreach tracer [expr {$level==1 ? {1 2} : {}}] {tracedLoop $level}} {foreach tracer {1 2} {tracedLoop $level}} {tracedLoop $level} {tracedLoop 1} {incr level} {incr level} tracer {tracer} {expr {$level==1 ? {1 2} : {}}} {expr {$level==1 ? {1 2} : {}}} {foreach tracer [expr {$level==1 ? {1 2} : {}}] {tracedLoop $level}} {foreach tracer {} {tracedLoop $level}} {tracedLoop $level} {tracedLoop 1} {incr level} {incr level} tracer {tracer} {expr {$level==1 ? {1 2} : {}}} {expr {$level==1 ? {1 2} : {}}} {foreach tracer [expr {$level==1 ? {1 2} : {}}] {tracedLoop $level}} {foreach tracer {} {tracedLoop $level}}} catch {rename tracer {}} catch {rename tracedLoop {}} test basic-39.5 {Tcl_CreateObjTrace, status return TCL_ERROR} {testcmdtrace} { proc Error { args } { error "Shouldn't get here" } set x 1; list [catch {testcmdtrace resulttest {Error $x}} result] [set result] } {1 {Error $x}} test basic-39.6 {Tcl_CreateObjTrace, status return TCL_RETURN} {testcmdtrace} { proc Return { args } { error "Shouldn't get here" } set x 1; list [catch {testcmdtrace resulttest {Return $x}} result] [set result] } {2 {}} test basic-39.7 {Tcl_CreateObjTrace, status return TCL_BREAK} {testcmdtrace} { proc Break { args } { error "Shouldn't get here" } set x 1; list [catch {testcmdtrace resulttest {Break $x}} result] [set result] } {3 {}} test basic-39.8 {Tcl_CreateObjTrace, status return TCL_CONTINUE} {testcmdtrace} { proc Continue { args } { error "Shouldn't get here" } set x 1; list [catch {testcmdtrace resulttest {Continue $x}} result] [set result] } {4 {}} test basic-39.9 {Tcl_CreateObjTrace, status return unknown} {testcmdtrace} { proc OtherStatus { args } { error "Shouldn't get here" } set x 1; list [catch {testcmdtrace resulttest {OtherStatus $x}} result] [set result] } {6 {}} test basic-39.10 {Tcl_CreateTrace, correct level interpretation} {testcmdtrace} { proc foo {} {uplevel 1 bar} proc bar {} {uplevel 1 grok} proc grok {} {uplevel 1 spock} proc spock {} {uplevel 1 fascinating} proc fascinating {} {} testcmdtrace leveltest {foo} } {foo {foo} {uplevel 1 bar} {uplevel 1 bar} bar {bar} {uplevel 1 grok} {uplevel 1 grok}} test basic-39.11 {Tcl_CreateTrace, multiple traces} {testcmdtrace} { testcmdtrace doubletest {format xx} } {{format xx} {format xx}} test basic-40.1 {Tcl_DeleteTrace} {emptyTest} { # the above tests have tested Tcl_DeleteTrace } {} test basic-41.1 {Tcl_AddErrorInfo} {emptyTest} { } {} test basic-42.1 {Tcl_AddObjErrorInfo} {emptyTest} { } {} test basic-43.1 {Tcl_VarEval} {emptyTest} { } {} test basic-44.1 {Tcl_GlobalEval} {emptyTest} { } {} test basic-45.1 {Tcl_SetRecursionLimit: see interp.test} {emptyTest} { } {} test basic-46.1 {Tcl_AllowExceptions: exception return not allowed} {stdio} { catch {close $f} set res [catch { set f [open |[list [interpreter]] w+] fconfigure $f -buffering line puts $f {fconfigure stdout -buffering line} puts $f continue puts $f {puts $errorInfo} puts $f {puts DONE} set newMsg {} set msg {} while {$newMsg != "DONE"} { set newMsg [gets $f] append msg "${newMsg}\n" } close $f } error] list $res $msg } {1 {invoked "continue" outside of a loop while executing "continue" DONE }} test basic-46.2 {Tcl_AllowExceptions: exception return not allowed} -setup { set fName [makeFile { puts hello break } BREAKtest] } -constraints { exec } -body { exec [interpreter] $fName } -cleanup { removeFile BREAKtest } -returnCodes error -match glob -result {hello invoked "break" outside of a loop while executing "break" (file "*BREAKtest" line 3)} test basic-46.3 {Tcl_AllowExceptions: exception return not allowed} -setup { set fName [makeFile { interp alias {} patch {} info patchlevel patch break } BREAKtest] } -constraints { exec } -body { exec [interpreter] $fName } -cleanup { removeFile BREAKtest } -returnCodes error -match glob -result {invoked "break" outside of a loop while executing "break" (file "*BREAKtest" line 4)} test basic-46.4 {Tcl_AllowExceptions: exception return not allowed} -setup { set fName [makeFile { foo [set a 1] [break] } BREAKtest] } -constraints { exec } -body { exec [interpreter] $fName } -cleanup { removeFile BREAKtest } -returnCodes error -match glob -result {invoked "break" outside of a loop while executing* "foo \[set a 1] \[break]" (file "*BREAKtest" line 2)} test basic-46.5 {Tcl_AllowExceptions: exception return not allowed} -setup { set fName [makeFile { return -code return } BREAKtest] } -constraints { exec } -body { exec [interpreter] $fName } -cleanup { removeFile BREAKtest } -returnCodes error -match glob -result {command returned bad code: 2 while executing "return -code return" (file "*BREAKtest" line 2)} test basic-47.1 {Tcl_EvalEx: check for missing close-bracket} -body { subst {a[set b [format cd]} } -returnCodes error -result {missing close-bracket} test basic-49.1 {Tcl_EvalEx: verify TCL_EVAL_GLOBAL operation} testevalex { set ::x global namespace eval ns { variable x namespace testevalex {set x changed} global set ::result [list $::x $x] } namespace delete ns set ::result } {changed namespace} test basic-49.2 {Tcl_EvalEx: verify TCL_EVAL_GLOBAL operation} testevalex { set ::x global namespace eval ns { variable x namespace testevalex {set ::context $x} global } namespace delete ns set ::context } {global} # cleanup catch {eval namespace delete [namespace children :: test_ns_*]} catch {namespace delete george} catch {interp delete test_interp} catch {rename p ""} catch {rename q ""} catch {rename cmd ""} catch {rename value:at: ""} catch {unset x} ::tcltest::cleanupTests return tcl8.4.20/tests/winNotify.test0000644003604700454610000000744011737050674014755 0ustar dgp771div# This file tests the tclWinNotify.c file. # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1997 by Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } set ::tcltest::testConstraints(testeventloop) \ [expr {[info commands testeventloop] != {}}] # There is no explicit test for InitNotifier or NotifierExitHandler test winNotify-1.1 {Tcl_SetTimer: positive timeout} {pcOnly} { set done 0 after 1000 { set done 1 } vwait done set done } 1 test winNotify-1.2 {Tcl_SetTimer: positive timeout, message pending} {pcOnly} { set x 0 set y 1 set a1 [after 0 { incr y }] after cancel $a1 after 500 { incr x } vwait x list $x $y } {1 1} test winNotify-1.3 {Tcl_SetTimer: cancelling positive timeout} {pcOnly} { set x 0 set y 1 set id [after 10000 { incr y }] after 0 { incr x } vwait x after cancel $id list $x $y } {1 1} test winNotify-1.4 {Tcl_SetTimer: null timeout, message pending} {pcOnly} { set x 0 set y 1 after 0 { incr x } after 0 { incr y } vwait x list $x $y } {1 2} test winNotify-2.1 {Tcl_ResetIdleTimer} {pcOnly} { set x 0 update after idle { incr x } vwait x set x } 1 test winNotify-2.2 {Tcl_ResetIdleTimer: message pending} {pcOnly} { set x 0 set y 1 update after idle { incr x } after idle { incr y } update list $x $y } {1 2} test winNotify-3.1 {NotifierProc: non-modal normal timer} {pcOnly testeventloop} { update set x 0 foreach i [after info] { after cancel $i } after 500 { incr x; testeventloop done } testeventloop wait set x } 1 test winNotify-3.2 {NotifierProc: non-modal normal timer, rescheduled} {pcOnly testeventloop} { update set x 0 foreach i [after info] { after cancel $i } after 500 { incr x; after 100 {incr x; testeventloop done }} testeventloop wait set x } 2 test winNotify-3.3 {NotifierProc: modal normal timer} {pcOnly} { update set x 0 foreach i [after info] { after cancel $i } after 500 { incr x } vwait x set x } 1 test winNotify-3.4 {NotifierProc: modal normal timer, rescheduled} {pcOnly} { update set x 0 foreach i [after info] { after cancel $i } set y 0 after 500 { incr y; after 100 {incr x}} vwait x list $x $y } {1 1} test winNotify-3.5 {NotifierProc: non-modal idle timer} {pcOnly testeventloop} { update set x 0 foreach i [after info] { after cancel $i } after idle { incr x; testeventloop done } testeventloop wait set x } 1 test winNotify-3.6 {NotifierProc: non-modal idle timer, rescheduled} {pcOnly testeventloop} { update set x 0 foreach i [after info] { after cancel $i } after idle { incr x; after idle {incr x; testeventloop done }} testeventloop wait set x } 2 test winNotify-3.7 {NotifierProc: modal idle timer} {pcOnly} { update set x 0 foreach i [after info] { after cancel $i } after idle { incr x } vwait x set x } 1 test winNotify-3.8 {NotifierProc: modal idle timer, rescheduled} {pcOnly} { update set x 0 foreach i [after info] { after cancel $i } set y 0 after idle { incr y; after idle {incr x}} vwait x list $x $y } {1 1} # Tcl_DoOneEvent is tested by the timer.test, io.test, and event.test files # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/linsert.test0000644003604700454610000000662511737050674014453 0ustar dgp771div# Commands covered: linsert # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } catch {unset lis} catch {rename p ""} test linsert-1.1 {linsert command} { linsert {1 2 3 4 5} 0 a } {a 1 2 3 4 5} test linsert-1.2 {linsert command} { linsert {1 2 3 4 5} 1 a } {1 a 2 3 4 5} test linsert-1.3 {linsert command} { linsert {1 2 3 4 5} 2 a } {1 2 a 3 4 5} test linsert-1.4 {linsert command} { linsert {1 2 3 4 5} 3 a } {1 2 3 a 4 5} test linsert-1.5 {linsert command} { linsert {1 2 3 4 5} 4 a } {1 2 3 4 a 5} test linsert-1.6 {linsert command} { linsert {1 2 3 4 5} 5 a } {1 2 3 4 5 a} test linsert-1.7 {linsert command} { linsert {1 2 3 4 5} 2 one two \{three \$four } {1 2 one two \{three {$four} 3 4 5} test linsert-1.8 {linsert command} { linsert {\{one \$two \{three \ four \ five} 2 a b c } {\{one {$two} a b c \{three { four} { five}} test linsert-1.9 {linsert command} { linsert {{1 2} {3 4} {5 6} {7 8}} 2 {x y} {a b} } {{1 2} {3 4} {x y} {a b} {5 6} {7 8}} test linsert-1.10 {linsert command} { linsert {} 2 a b c } {a b c} test linsert-1.11 {linsert command} { linsert {} 2 {} } {{}} test linsert-1.12 {linsert command} { linsert {a b "c c" d e} 3 1 } {a b {c c} 1 d e} test linsert-1.13 {linsert command} { linsert { a b c d} 0 1 2 } {1 2 a b c d} test linsert-1.14 {linsert command} { linsert {a b c {d e f}} 4 1 2 } {a b c {d e f} 1 2} test linsert-1.15 {linsert command} { linsert {a b c \{\ abc} 4 q r } {a b c \{\ q r abc} test linsert-1.16 {linsert command} { linsert {a b c \{ abc} 4 q r } {a b c \{ q r abc} test linsert-1.17 {linsert command} { linsert {a b c} end q r } {a b c q r} test linsert-1.18 {linsert command} { linsert {a} end q r } {a q r} test linsert-1.19 {linsert command} { linsert {} end q r } {q r} test linsert-1.20 {linsert command, use of end-int index} { linsert {a b c d} end-2 e f } {a b e f c d} test linsert-2.1 {linsert errors} { list [catch linsert msg] $msg } {1 {wrong # args: should be "linsert list index element ?element ...?"}} test linsert-2.2 {linsert errors} { list [catch {linsert a b} msg] $msg } {1 {wrong # args: should be "linsert list index element ?element ...?"}} test linsert-2.3 {linsert errors} { list [catch {linsert a 12x 2} msg] $msg } {1 {bad index "12x": must be integer or end?-integer?}} test linsert-2.4 {linsert errors} { list [catch {linsert \{ 12 2} msg] $msg } {1 {unmatched open brace in list}} test linsert-3.1 {linsert won't modify shared argument objects} { proc p {} { linsert "a b c" 1 "x y" return "a b c" } p } "a b c" test linsert-3.2 {linsert won't modify shared argument objects} { catch {unset lis} set lis [format "a \"%s\" c" "b"] linsert $lis 0 [string length $lis] } "7 a b c" # cleanup catch {unset lis} catch {rename p ""} ::tcltest::cleanupTests return tcl8.4.20/tests/winConsole.test0000644003604700454610000000220011737050674015074 0ustar dgp771div# This file tests the tclWinConsole.c file. # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } test winConsole-1.1 {Console file channel: non-blocking gets} \ {pcOnly interactive} { set oldmode [fconfigure stdin] puts stdout "Enter abcdef now: " nonewline flush stdout fileevent stdin readable { if {[gets stdin line] >= 0} { set result $line } else { set result "gets failed" } } fconfigure stdin -blocking 0 -buffering line set result {} vwait result #cleanup the fileevent fileevent stdin readable {} eval fconfigure stdin $oldmode set result } "abcdef" #cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/parse.test0000644003604700454610000011066411737050674014104 0ustar dgp771div# This file contains a collection of tests for the procedures in the # file tclParse.c. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1997 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import -force ::tcltest::* } if {[info commands testparser] == {}} { puts "This application hasn't been compiled with the \"testparser\"" puts "command, so I can't test the Tcl parser." ::tcltest::cleanupTests return } test parse-1.1 {Tcl_ParseCommand procedure, computing string length} { testparser [bytestring "foo\0 bar"] -1 } {- foo 1 simple foo 1 text foo 0 {}} test parse-1.2 {Tcl_ParseCommand procedure, computing string length} { testparser "foo bar" -1 } {- {foo bar} 2 simple foo 1 text foo 0 simple bar 1 text bar 0 {}} test parse-1.3 {Tcl_ParseCommand procedure, leading space} { testparser " \n\t foo" 0 } {- foo 1 simple foo 1 text foo 0 {}} test parse-1.4 {Tcl_ParseCommand procedure, leading space} { testparser "\f\r\vfoo" 0 } {- foo 1 simple foo 1 text foo 0 {}} test parse-1.5 {Tcl_ParseCommand procedure, backslash-newline in leading space} { testparser " \\\n foo" 0 } {- foo 1 simple foo 1 text foo 0 {}} test parse-1.6 {Tcl_ParseCommand procedure, backslash-newline in leading space} { testparser { \a foo} 0 } {- {\a foo} 2 word {\a} 1 backslash {\a} 0 simple foo 1 text foo 0 {}} test parse-1.7 {Tcl_ParseCommand procedure, missing continuation line in leading space} { testparser " \\\n" 0 } {- {} 0 {}} test parse-1.8 {Tcl_ParseCommand procedure, eof in leading space} { testparser " foo" 3 } {- {} 0 { foo}} test parse-2.1 {Tcl_ParseCommand procedure, comments} { testparser "# foo bar\n foo" 0 } {{# foo bar } foo 1 simple foo 1 text foo 0 {}} test parse-2.2 {Tcl_ParseCommand procedure, several comments} { testparser " # foo bar\n # another comment\n\n foo" 0 } {{# foo bar # another comment } foo 1 simple foo 1 text foo 0 {}} test parse-2.3 {Tcl_ParseCommand procedure, backslash-newline in comments} { testparser " # foo bar\\\ncomment on continuation line\nfoo" 0 } {#\ foo\ bar\\\ncomment\ on\ continuation\ line\n foo 1 simple foo 1 text foo 0 {}} test parse-2.4 {Tcl_ParseCommand procedure, missing continuation line in comment} { testparser "# \\\n" 0 } {#\ \ \ \\\n {} 0 {}} test parse-2.5 {Tcl_ParseCommand procedure, eof in comment} { testparser " # foo bar\nfoo" 8 } {{# foo b} {} 0 {ar foo}} test parse-3.1 {Tcl_ParseCommand procedure, parsing words, skipping space} { testparser "foo bar\t\tx" 0 } {- {foo bar x} 3 simple foo 1 text foo 0 simple bar 1 text bar 0 simple x 1 text x 0 {}} test parse-3.2 {Tcl_ParseCommand procedure, missing continuation line in leading space} { testparser "abc \\\n" 0 } {- abc\ \ \\\n 1 simple abc 1 text abc 0 {}} test parse-3.3 {Tcl_ParseCommand procedure, parsing words, command ends in space} { testparser "foo ; bar x" 0 } {- {foo ;} 1 simple foo 1 text foo 0 { bar x}} test parse-3.4 {Tcl_ParseCommand procedure, parsing words, command ends in space} { testparser "foo " 5 } {- {foo } 1 simple foo 1 text foo 0 { }} test parse-3.5 {Tcl_ParseCommand procedure, quoted words} { testparser {foo "a b c" d "efg";} 0 } {- {foo "a b c" d "efg";} 4 simple foo 1 text foo 0 simple {"a b c"} 1 text {a b c} 0 simple d 1 text d 0 simple {"efg"} 1 text efg 0 {}} test parse-3.6 {Tcl_ParseCommand procedure, words in braces} { testparser {foo {a $b [concat foo]} {c d}} 0 } {- {foo {a $b [concat foo]} {c d}} 3 simple foo 1 text foo 0 simple {{a $b [concat foo]}} 1 text {a $b [concat foo]} 0 simple {{c d}} 1 text {c d} 0 {}} test parse-3.7 {Tcl_ParseCommand procedure, error in unquoted word} { list [catch {testparser "foo \$\{abc" 0} msg] $msg $errorInfo } {1 {missing close-brace for variable name} missing\ close-brace\ for\ variable\ name\n\ \ \ \ (remainder\ of\ script:\ \"\{abc\")\n\ \ \ \ invoked\ from\ within\n\"testparser\ \"foo\ \\\$\\\{abc\"\ 0\"} test parse-4.1 {Tcl_ParseCommand procedure, simple words} { testparser {foo} 0 } {- foo 1 simple foo 1 text foo 0 {}} test parse-4.2 {Tcl_ParseCommand procedure, simple words} { testparser {{abc}} 0 } {- {{abc}} 1 simple {{abc}} 1 text abc 0 {}} test parse-4.3 {Tcl_ParseCommand procedure, simple words} { testparser {"c d"} 0 } {- {"c d"} 1 simple {"c d"} 1 text {c d} 0 {}} test parse-4.4 {Tcl_ParseCommand procedure, simple words} { testparser {x$d} 0 } {- {x$d} 1 word {x$d} 3 text x 0 variable {$d} 1 text d 0 {}} test parse-4.5 {Tcl_ParseCommand procedure, simple words} { testparser {"a [foo] b"} 0 } {- {"a [foo] b"} 1 word {"a [foo] b"} 3 text {a } 0 command {[foo]} 0 text { b} 0 {}} test parse-4.6 {Tcl_ParseCommand procedure, simple words} { testparser {$x} 0 } {- {$x} 1 word {$x} 2 variable {$x} 1 text x 0 {}} test parse-5.1 {Tcl_ParseCommand procedure, backslash-newline terminates word} { testparser "{abc}\\\n" 0 } {- \{abc\}\\\n 1 simple {{abc}} 1 text abc 0 {}} test parse-5.2 {Tcl_ParseCommand procedure, backslash-newline terminates word} { testparser "foo\\\nbar" 0 } {- foo\\\nbar 2 simple foo 1 text foo 0 simple bar 1 text bar 0 {}} test parse-5.3 {Tcl_ParseCommand procedure, word terminator is command terminator} { testparser "foo\n bar" 0 } {- {foo } 1 simple foo 1 text foo 0 { bar}} test parse-5.4 {Tcl_ParseCommand procedure, word terminator is command terminator} { testparser "foo; bar" 0 } {- {foo;} 1 simple foo 1 text foo 0 { bar}} test parse-5.5 {Tcl_ParseCommand procedure, word terminator is end of string} { testparser "\"foo\" bar" 5 } {- {"foo"} 1 simple {"foo"} 1 text foo 0 { bar}} test parse-5.6 {Tcl_ParseCommand procedure, junk after close quote} { list [catch {testparser {foo "bar"x} 0} msg] $msg $errorInfo } {1 {extra characters after close-quote} {extra characters after close-quote (remainder of script: "x") invoked from within "testparser {foo "bar"x} 0"}} test parse-5.7 {Tcl_ParseCommand procedure, backslash-newline after close quote} { testparser "foo \"bar\"\\\nx" 0 } {- foo\ \"bar\"\\\nx 3 simple foo 1 text foo 0 simple {"bar"} 1 text bar 0 simple x 1 text x 0 {}} test parse-5.8 {Tcl_ParseCommand procedure, junk after close brace} { list [catch {testparser {foo {bar}x} 0} msg] $msg $errorInfo } {1 {extra characters after close-brace} {extra characters after close-brace (remainder of script: "x") invoked from within "testparser {foo {bar}x} 0"}} test parse-5.9 {Tcl_ParseCommand procedure, backslash-newline after close brace} { testparser "foo {bar}\\\nx" 0 } {- foo\ \{bar\}\\\nx 3 simple foo 1 text foo 0 simple {{bar}} 1 text bar 0 simple x 1 text x 0 {}} test parse-5.10 {Tcl_ParseCommand procedure, multiple deletion of non-static buffer} { # This test is designed to catch bug 1681. list [catch {testparser "a \"\\1\\2\\3\\4\\5\\6\\7\\8\\9\\1\\2\\3\\4\\5\\6\\7\\8" 0} msg] $msg $errorInfo } "1 {missing \"} {missing \" (remainder of script: \"\"\\1\\2\\3\\4\\5\\6\\7\\8\\9\\1\\2\\3\\4\\5\\6\\7\\8\") invoked from within \"testparser \"a \\\"\\\\1\\\\2\\\\3\\\\4\\\\5\\\\6\\\\7\\\\8\\\\9\\\\1\\\\2\\\\3\\\\4\\\\5\\\\6\\\\7\\\\8\" 0\"}" test parse-6.1 {ParseTokens procedure, empty word} { testparser {""} 0 } {- {""} 1 simple {""} 1 text {} 0 {}} test parse-6.2 {ParseTokens procedure, simple range} { testparser {"abc$x.e"} 0 } {- {"abc$x.e"} 1 word {"abc$x.e"} 4 text abc 0 variable {$x} 1 text x 0 text .e 0 {}} test parse-6.3 {ParseTokens procedure, variable reference} { testparser {abc$x.e $y(z)} 0 } {- {abc$x.e $y(z)} 2 word {abc$x.e} 4 text abc 0 variable {$x} 1 text x 0 text .e 0 word {$y(z)} 3 variable {$y(z)} 2 text y 0 text z 0 {}} test parse-6.4 {ParseTokens procedure, variable reference} { list [catch {testparser {$x([a )} 0} msg] $msg } {1 {missing close-bracket}} test parse-6.5 {ParseTokens procedure, command substitution} { testparser {[foo $x bar]z} 0 } {- {[foo $x bar]z} 1 word {[foo $x bar]z} 2 command {[foo $x bar]} 0 text z 0 {}} test parse-6.6 {ParseTokens procedure, command substitution} { testparser {[foo \] [a b]]} 0 } {- {[foo \] [a b]]} 1 word {[foo \] [a b]]} 1 command {[foo \] [a b]]} 0 {}} test parse-6.7 {ParseTokens procedure, error in command substitution} { list [catch {testparser {a [b {}c d] e} 0} msg] $msg $errorInfo } {1 {extra characters after close-brace} {extra characters after close-brace (remainder of script: "c d] e") invoked from within "testparser {a [b {}c d] e} 0"}} test parse-6.8 {ParseTokens procedure, error in command substitution} { info complete {a [b {}c d]} } {1} test parse-6.9 {ParseTokens procedure, error in command substitution} { info complete {a [b "c d} } {0} test parse-6.10 {ParseTokens procedure, incomplete sub-command} { info complete {puts [ expr 1+1 #this is a comment ]} } {0} test parse-6.11 {ParseTokens procedure, memory allocation for big nested command} { testparser {[$a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b)]} 0 } {- {[$a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b)]} 1 word {[$a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b)]} 1 command {[$a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b)]} 0 {}} test parse-6.12 {ParseTokens procedure, missing close bracket} { list [catch {testparser {[foo $x bar} 0} msg] $msg $errorInfo } {1 {missing close-bracket} {missing close-bracket (remainder of script: "[foo $x bar") invoked from within "testparser {[foo $x bar} 0"}} test parse-6.13 {ParseTokens procedure, backslash-newline without continuation line} { list [catch {testparser "\"a b\\\n" 0} msg] $msg $errorInfo } {1 {missing "} missing\ \"\n\ \ \ \ (remainder\ of\ script:\ \"\"a\ b\\\n\")\n\ \ \ \ invoked\ from\ within\n\"testparser\ \"\\\"a\ b\\\\\\n\"\ 0\"} test parse-6.14 {ParseTokens procedure, backslash-newline} { testparser "b\\\nc" 0 } {- b\\\nc 2 simple b 1 text b 0 simple c 1 text c 0 {}} test parse-6.15 {ParseTokens procedure, backslash-newline} { testparser "\"b\\\nc\"" 0 } {- \"b\\\nc\" 1 word \"b\\\nc\" 3 text b 0 backslash \\\n 0 text c 0 {}} test parse-6.16 {ParseTokens procedure, backslash substitution} { testparser {\n\a\x7f} 0 } {- {\n\a\x7f} 1 word {\n\a\x7f} 3 backslash {\n} 0 backslash {\a} 0 backslash {\x7f} 0 {}} test parse-6.17 {ParseTokens procedure, null characters} { testparser [bytestring "foo\0zz"] 0 } "- [bytestring foo\0zz] 1 word [bytestring foo\0zz] 3 text foo 0 text [bytestring \0] 0 text zz 0 {}" test parse-6.18 {ParseTokens procedure, seek past numBytes for close-bracket} { # Test for Bug 681841 list [catch {testparser {[a]} 2} msg] $msg } {1 {missing close-bracket}} test parse-7.1 {Tcl_FreeParse and ExpandTokenArray procedures} { testparser {$a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) } 0 } {- {$a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) } 16 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 {}} testConstraint testevalobjv [llength [info commands testevalobjv]] testConstraint testevalex [llength [info commands testevalex]] test parse-8.1 {Tcl_EvalObjv procedure} testevalobjv { testevalobjv 0 concat this is a test } {this is a test} test parse-8.2 {Tcl_EvalObjv procedure, unknown commands} testevalobjv { rename unknown unknown.old set x [catch {testevalobjv 10 asdf poiu} msg] rename unknown.old unknown list $x $msg } {1 {invalid command name "asdf"}} test parse-8.3 {Tcl_EvalObjv procedure, unknown commands} testevalobjv { rename unknown unknown.old proc unknown args { return "unknown $args" } set x [catch {testevalobjv 0 asdf poiu} msg] rename unknown {} rename unknown.old unknown list $x $msg } {0 {unknown asdf poiu}} test parse-8.4 {Tcl_EvalObjv procedure, unknown commands} testevalobjv { rename unknown unknown.old proc unknown args { error "I don't like that command" } set x [catch {testevalobjv 0 asdf poiu} msg] rename unknown {} rename unknown.old unknown list $x $msg } {1 {I don't like that command}} test parse-8.5 {Tcl_EvalObjv procedure, command traces} testevalobjv { testevalobjv 0 set x 123 testcmdtrace tracetest {testevalobjv 0 set x $x} } {{testevalobjv 0 set x $x} {testevalobjv 0 set x 123} {set x 123} {set x 123}} test parse-8.7 {Tcl_EvalObjv procedure, TCL_EVAL_GLOBAL flag} testevalobjv { proc x {} { set y 23 set z [testevalobjv 1 set y] return [list $z $y] } catch {unset y} set y 16 x } {16 23} test parse-8.8 {Tcl_EvalObjv procedure, async handlers} testevalobjv { proc async1 {result code} { global aresult acode set aresult $result set acode $code return "new result" } set handler1 [testasync create async1] set aresult xxx set acode yyy set x [list [catch [list testevalobjv 0 testasync mark $handler1 original 0] msg] $msg $acode $aresult] testasync delete set x } {0 {new result} 0 original} test parse-8.9 {Tcl_EvalObjv procedure, exceptional return} testevalobjv { list [catch {testevalobjv 0 error message} msg] $msg } {1 message} test parse-8.10 {Tcl_EvalObjv procedure, TCL_EVAL_GLOBAL} testevalobjv { rename ::unknown unknown.save proc ::unknown args {lappend ::info [info level]} catch {rename ::noSuchCommand {}} set ::info {} namespace eval test_ns_1 { testevalobjv 1 noSuchCommand uplevel #0 noSuchCommand } namespace delete test_ns_1 rename ::unknown {} rename unknown.save ::unknown set ::info } {1 1} test parse-8.11 {Tcl_EvalObjv procedure, TCL_EVAL_INVOKE} testevalobjv { rename ::unknown unknown.save proc ::unknown args {lappend ::info [info level]; uplevel 1 foo} proc ::foo args {lappend ::info global} catch {rename ::noSuchCommand {}} set ::slave [interp create] $::slave alias bar noSuchCommand set ::info {} namespace eval test_ns_1 { proc foo args {lappend ::info namespace} $::slave eval bar testevalobjv 1 [list $::slave eval bar] uplevel #0 [list $::slave eval bar] } namespace delete test_ns_1 rename ::foo {} rename ::unknown {} rename unknown.save ::unknown set ::info } [subst {[set level 2; incr level [info level]] global 1 global 1 global}] test parse-8.12 {Tcl_EvalObjv procedure, TCL_EVAL_INVOKE} { set ::auto_index(noSuchCommand) { proc noSuchCommand {} {lappend ::info global} } set ::auto_index(::[string trimleft [namespace current]::test_ns_1::noSuchCommand :]) [list \ proc [namespace current]::test_ns_1::noSuchCommand {} { lappend ::info ns }] catch {rename ::noSuchCommand {}} set ::slave [interp create] $::slave alias bar noSuchCommand set ::info {} namespace eval test_ns_1 { $::slave eval bar } namespace delete test_ns_1 interp delete $::slave catch {rename ::noSuchCommand {}} set ::info } global test parse-9.1 {Tcl_LogCommandInfo, line numbers} { catch {unset x} list [catch {testevalex {for {} 1 {} { # asdf set x }}}] $errorInfo } {1 {can't read "x": no such variable while executing "set x" ("for" body line 5) invoked from within "for {} 1 {} { # asdf set x }" invoked from within "testevalex {for {} 1 {} { # asdf set x }}"}} test parse-9.2 {Tcl_LogCommandInfo, truncating long commands} { list [testevalex {catch {set a b 111111111 222222222 333333333 444444444 555555555 666666666 777777777 888888888 999999999 000000000 aaaaaaaaa bbbbbbbbb ccccccccc ddddddddd eeeeeeeee fffffffff ggggggggg}}] $errorInfo } {1 {wrong # args: should be "set varName ?newValue?" while executing "set a b 111111111 222222222 333333333 444444444 555555555 666666666 777777777 888888888 999999999 000000000 aaaaaaaaa bbbbbbbbb ccccccccc ddddddddd ee..."}} test parse-10.1 {Tcl_EvalTokens, simple text} { testevalex {concat test} } {test} test parse-10.2 {Tcl_EvalTokens, backslash sequences} { testevalex {concat test\063\062test} } {test32test} test parse-10.3 {Tcl_EvalTokens, nested commands} { testevalex {concat [expr 2 + 6]} } {8} test parse-10.4 {Tcl_EvalTokens, nested commands} { catch {unset a} list [catch {testevalex {concat xxx[expr $a]}} msg] $msg } {1 {can't read "a": no such variable}} test parse-10.5 {Tcl_EvalTokens, simple variables} { set a hello testevalex {concat $a} } {hello} test parse-10.6 {Tcl_EvalTokens, array variables} { catch {unset a} set a(12) 46 testevalex {concat $a(12)} } {46} test parse-10.7 {Tcl_EvalTokens, array variables} { catch {unset a} set a(12) 46 testevalex {concat $a(1[expr 3 - 1])} } {46} test parse-10.8 {Tcl_EvalTokens, array variables} { catch {unset a} list [catch {testevalex {concat $x($a)}} msg] $msg } {1 {can't read "a": no such variable}} test parse-10.9 {Tcl_EvalTokens, array variables} { catch {unset a} list [catch {testevalex {concat xyz$a(1)}} msg] $msg } {1 {can't read "a(1)": no such variable}} test parse-10.10 {Tcl_EvalTokens, object values} { set a 123 testevalex {concat $a} } {123} test parse-10.11 {Tcl_EvalTokens, object values} { set a 123 testevalex {concat $a$a$a} } {123123123} test parse-10.12 {Tcl_EvalTokens, object values} { testevalex {concat [expr 2][expr 4][expr 6]} } {246} test parse-10.13 {Tcl_EvalTokens, string values} { testevalex {concat {a" b"}} } {a" b"} test parse-10.14 {Tcl_EvalTokens, string values} { set a 111 testevalex {concat x$a.$a.$a} } {x111.111.111} test parse-11.1 {Tcl_EvalEx, TCL_EVAL_GLOBAL flag} { proc x {} { set y 777 set z [testevalex "set y" global] return [list $z $y] } catch {unset y} set y 321 x } {321 777} test parse-11.2 {Tcl_EvalEx, error while parsing} { list [catch {testevalex {concat "abc}} msg] $msg } {1 {missing "}} test parse-11.3 {Tcl_EvalEx, error while collecting words} { catch {unset a} list [catch {testevalex {concat xyz $a}} msg] $msg } {1 {can't read "a": no such variable}} test parse-11.4 {Tcl_EvalEx, error in Tcl_EvalObjv call} { catch {unset a} list [catch {testevalex {_bogus_ a b c d}} msg] $msg } {1 {invalid command name "_bogus_"}} test parse-11.5 {Tcl_EvalEx, exceptional return} { list [catch {testevalex {break}} msg] $msg } {3 {}} test parse-11.6 {Tcl_EvalEx, freeing memory} { testevalex {concat a b c d e f g h i j k l m n o p q r s t u v w x y z} } {a b c d e f g h i j k l m n o p q r s t u v w x y z} test parse-11.7 {Tcl_EvalEx, multiple commands in script} { list [testevalex {set a b; set c d}] $a $c } {d b d} test parse-11.8 {Tcl_EvalEx, multiple commands in script} { list [testevalex { set a b set c d }] $a $c } {d b d} test parse-11.9 {Tcl_EvalEx, freeing memory after error} { catch {unset a} list [catch {testevalex {concat a b c d e f g h i j k l m n o p q r s t u v w x y z $a}} msg] $msg } {1 {can't read "a": no such variable}} test parse-11.10 {Tcl_EvalTokens, empty commands} { testevalex {concat xyz; } } {xyz} test parse-11.11 {Tcl_EvalTokens, empty commands} { testevalex "concat abc; ; # this is a comment\n" } {abc} test parse-11.12 {Tcl_EvalTokens, empty commands} { testevalex {} } {} test parse-12.1 {Tcl_ParseVarName procedure, initialization} { list [catch {testparsevarname {$a([first second])} 8 0} msg] $msg } {1 {missing close-bracket}} test parse-12.2 {Tcl_ParseVarName procedure, initialization} { testparsevarname {$a([first second])} 0 0 } {- {} 0 variable {$a([first second])} 2 text a 0 command {[first second]} 0 {}} test parse-12.3 {Tcl_ParseVarName procedure, initialization} { list [catch {testparsevarname {$abcd} 3 0} msg] $msg } {0 {- {} 0 variable {$ab} 1 text ab 0 cd}} test parse-12.4 {Tcl_ParseVarName procedure, initialization} { testparsevarname {$abcd} 0 0 } {- {} 0 variable {$abcd} 1 text abcd 0 {}} test parse-12.5 {Tcl_ParseVarName procedure, just a dollar sign} { testparsevarname {$abcd} 1 0 } {- {} 0 text {$} 0 abcd} test parse-12.6 {Tcl_ParseVarName procedure, braced variable name} { testparser {${..[]b}cd} 0 } {- {${..[]b}cd} 1 word {${..[]b}cd} 3 variable {${..[]b}} 1 text {..[]b} 0 text cd 0 {}} test parse-12.7 {Tcl_ParseVarName procedure, braced variable name} { testparser "\$\{\{\} " 0 } {- \$\{\{\}\ 1 word \$\{\{\} 2 variable \$\{\{\} 1 text \{ 0 {}} test parse-12.8 {Tcl_ParseVarName procedure, missing close brace} { list [catch {testparser "$\{abc" 0} msg] $msg $errorInfo } {1 {missing close-brace for variable name} missing\ close-brace\ for\ variable\ name\n\ \ \ \ (remainder\ of\ script:\ \"\{abc\")\n\ \ \ \ invoked\ from\ within\n\"testparser\ \"\$\\\{abc\"\ 0\"} test parse-12.9 {Tcl_ParseVarName procedure, missing close brace} { list [catch {testparsevarname {${bcd}} 4 0} msg] $msg } {1 {missing close-brace for variable name}} test parse-12.10 {Tcl_ParseVarName procedure, missing close brace} { list [catch {testparsevarname {${bc}} 4 0} msg] $msg } {1 {missing close-brace for variable name}} test parse-12.11 {Tcl_ParseVarName procedure, simple variable name} { testparser {$az_AZ.} 0 } {- {$az_AZ.} 1 word {$az_AZ.} 3 variable {$az_AZ} 1 text az_AZ 0 text . 0 {}} test parse-12.12 {Tcl_ParseVarName procedure, simple variable name} { testparser {$abcdefg} 4 } {- {$abc} 1 word {$abc} 2 variable {$abc} 1 text abc 0 defg} test parse-12.13 {Tcl_ParseVarName procedure, simple variable name with ::} { testparser {$xyz::ab:c} 0 } {- {$xyz::ab:c} 1 word {$xyz::ab:c} 3 variable {$xyz::ab} 1 text xyz::ab 0 text :c 0 {}} test parse-12.14 {Tcl_ParseVarName procedure, variable names with many colons} { testparser {$xyz:::::c} 0 } {- {$xyz:::::c} 1 word {$xyz:::::c} 2 variable {$xyz:::::c} 1 text xyz:::::c 0 {}} test parse-12.15 {Tcl_ParseVarName procedure, : vs. ::} { testparsevarname {$ab:cd} 0 0 } {- {} 0 variable {$ab} 1 text ab 0 :cd} test parse-12.16 {Tcl_ParseVarName procedure, eof in ::} { testparsevarname {$ab::cd} 4 0 } {- {} 0 variable {$ab} 1 text ab 0 ::cd} test parse-12.17 {Tcl_ParseVarName procedure, eof in ::} { testparsevarname {$ab:::cd} 5 0 } {- {} 0 variable {$ab::} 1 text ab:: 0 :cd} test parse-12.18 {Tcl_ParseVarName procedure, no variable name} { testparser {$$ $.} 0 } {- {$$ $.} 2 word {$$} 2 text {$} 0 text {$} 0 word {$.} 2 text {$} 0 text . 0 {}} test parse-12.19 {Tcl_ParseVarName procedure, EOF before (} { testparsevarname {$ab(cd)} 3 0 } {- {} 0 variable {$ab} 1 text ab 0 (cd)} test parse-12.20 {Tcl_ParseVarName procedure, array reference} { testparser {$x(abc)} 0 } {- {$x(abc)} 1 word {$x(abc)} 3 variable {$x(abc)} 2 text x 0 text abc 0 {}} test parse-12.21 {Tcl_ParseVarName procedure, array reference} { testparser {$x(ab$cde[foo bar])} 0 } {- {$x(ab$cde[foo bar])} 1 word {$x(ab$cde[foo bar])} 6 variable {$x(ab$cde[foo bar])} 5 text x 0 text ab 0 variable {$cde} 1 text cde 0 command {[foo bar]} 0 {}} test parse-12.22 {Tcl_ParseVarName procedure, array reference} { testparser {$x([cmd arg]zz)} 0 } {- {$x([cmd arg]zz)} 1 word {$x([cmd arg]zz)} 4 variable {$x([cmd arg]zz)} 3 text x 0 command {[cmd arg]} 0 text zz 0 {}} test parse-12.23 {Tcl_ParseVarName procedure, missing close paren in array reference} { list [catch {testparser {$x(poiu} 0} msg] $msg $errorInfo } {1 {missing )} {missing ) (remainder of script: "(poiu") invoked from within "testparser {$x(poiu} 0"}} test parse-12.24 {Tcl_ParseVarName procedure, missing close paren in array reference} { list [catch {testparsevarname {$ab(cd)} 6 0} msg] $msg $errorInfo } {1 {missing )} {missing ) (remainder of script: "(cd)") invoked from within "testparsevarname {$ab(cd)} 6 0"}} test parse-12.25 {Tcl_ParseVarName procedure, nested array reference} { testparser {$x(a$y(b$z))} 0 } {- {$x(a$y(b$z))} 1 word {$x(a$y(b$z))} 8 variable {$x(a$y(b$z))} 7 text x 0 text a 0 variable {$y(b$z)} 4 text y 0 text b 0 variable {$z} 1 text z 0 {}} test parse-13.1 {Tcl_ParseVar procedure} { set abc 24 testparsevar {$abc.fg} } {24 .fg} test parse-13.2 {Tcl_ParseVar procedure, no variable name} { testparsevar {$} } {{$} {}} test parse-13.3 {Tcl_ParseVar procedure, no variable name} { testparsevar {$.123} } {{$} .123} test parse-13.4 {Tcl_ParseVar procedure, error looking up variable} { catch {unset abc} list [catch {testparsevar {$abc}} msg] $msg } {1 {can't read "abc": no such variable}} test parse-13.5 {Tcl_ParseVar procedure, error looking up variable} { catch {unset abc} list [catch {testparsevar {$abc([bogus x y z])}} msg] $msg } {1 {invalid command name "bogus"}} test parse-14.1 {Tcl_ParseBraces procedure, computing string length} { testparser [bytestring "foo\0 bar"] -1 } {- foo 1 simple foo 1 text foo 0 {}} test parse-14.2 {Tcl_ParseBraces procedure, computing string length} { testparser "foo bar" -1 } {- {foo bar} 2 simple foo 1 text foo 0 simple bar 1 text bar 0 {}} test parse-14.3 {Tcl_ParseBraces procedure, words in braces} { testparser {foo {a $b [concat foo]} {c d}} 0 } {- {foo {a $b [concat foo]} {c d}} 3 simple foo 1 text foo 0 simple {{a $b [concat foo]}} 1 text {a $b [concat foo]} 0 simple {{c d}} 1 text {c d} 0 {}} test parse-14.4 {Tcl_ParseBraces procedure, empty nested braces} { testparser {foo {{}}} 0 } {- {foo {{}}} 2 simple foo 1 text foo 0 simple {{{}}} 1 text {{}} 0 {}} test parse-14.5 {Tcl_ParseBraces procedure, nested braces} { testparser {foo {{a {b} c} {} {d e}}} 0 } {- {foo {{a {b} c} {} {d e}}} 2 simple foo 1 text foo 0 simple {{{a {b} c} {} {d e}}} 1 text {{a {b} c} {} {d e}} 0 {}} test parse-14.6 {Tcl_ParseBraces procedure, backslashes in words in braces} { testparser "foo {a \\n\\\{}" 0 } {- {foo {a \n\{}} 2 simple foo 1 text foo 0 simple {{a \n\{}} 1 text {a \n\{} 0 {}} test parse-14.7 {Tcl_ParseBraces procedure, missing continuation line in braces} { list [catch {testparser "\{abc\\\n" 0} msg] $msg $errorInfo } {1 {missing close-brace} missing\ close-brace\n\ \ \ \ (remainder\ of\ script:\ \"\{abc\\\n\")\n\ \ \ \ invoked\ from\ within\n\"testparser\ \"\\\{abc\\\\\\n\"\ 0\"} test parse-14.8 {Tcl_ParseBraces procedure, backslash-newline in braces} { testparser "foo {\\\nx}" 0 } {- foo\ \{\\\nx\} 2 simple foo 1 text foo 0 word \{\\\nx\} 2 backslash \\\n 0 text x 0 {}} test parse-14.9 {Tcl_ParseBraces procedure, backslash-newline in braces} { testparser "foo {a \\\n b}" 0 } {- foo\ \{a\ \\\n\ \ \ b\} 2 simple foo 1 text foo 0 word \{a\ \\\n\ \ \ b\} 3 text {a } 0 backslash \\\n\ \ \ 0 text b 0 {}} test parse-14.10 {Tcl_ParseBraces procedure, backslash-newline in braces} { testparser "foo {xyz\\\n }" 0 } {- foo\ \{xyz\\\n\ \} 2 simple foo 1 text foo 0 word \{xyz\\\n\ \} 2 text xyz 0 backslash \\\n\ 0 {}} test parse-14.11 {Tcl_ParseBraces procedure, empty braced string} { testparser {foo {}} 0 } {- {foo {}} 2 simple foo 1 text foo 0 simple {{}} 1 text {} 0 {}} test parse-14.12 {Tcl_ParseBraces procedure, missing close brace} { list [catch {testparser "foo \{xy\\\nz" 0} msg] $msg $errorInfo } {1 {missing close-brace} missing\ close-brace\n\ \ \ \ (remainder\ of\ script:\ \"\{xy\\\nz\")\n\ \ \ \ invoked\ from\ within\n\"testparser\ \"foo\ \\\{xy\\\\\\nz\"\ 0\"} test parse-15.1 {Tcl_ParseQuotedString procedure, computing string length} { testparser [bytestring "foo\0 bar"] -1 } {- foo 1 simple foo 1 text foo 0 {}} test parse-15.2 {Tcl_ParseQuotedString procedure, computing string length} { testparser "foo bar" -1 } {- {foo bar} 2 simple foo 1 text foo 0 simple bar 1 text bar 0 {}} test parse-15.3 {Tcl_ParseQuotedString procedure, word is quoted string} { testparser {foo "a b c" d "efg";} 0 } {- {foo "a b c" d "efg";} 4 simple foo 1 text foo 0 simple {"a b c"} 1 text {a b c} 0 simple d 1 text d 0 simple {"efg"} 1 text efg 0 {}} test parse-15.4 {Tcl_ParseQuotedString procedure, garbage after quoted string} { list [catch {testparser {foo "a b c"d} 0} msg] $msg $errorInfo } {1 {extra characters after close-quote} {extra characters after close-quote (remainder of script: "d") invoked from within "testparser {foo "a b c"d} 0"}} test parse-15.5 {CommandComplete procedure} { info complete "" } 1 test parse-15.6 {CommandComplete procedure} { info complete " \n" } 1 test parse-15.7 {CommandComplete procedure} { info complete "abc def" } 1 test parse-15.8 {CommandComplete procedure} { info complete "a b c d e f \t\n" } 1 test parse-15.9 {CommandComplete procedure} { info complete {a b c"d} } 1 test parse-15.10 {CommandComplete procedure} { info complete {a b "c d" e} } 1 test parse-15.11 {CommandComplete procedure} { info complete {a b "c d"} } 1 test parse-15.12 {CommandComplete procedure} { info complete {a b "c d"} } 1 test parse-15.13 {CommandComplete procedure} { info complete {a b "c d} } 0 test parse-15.14 {CommandComplete procedure} { info complete {a b "} } 0 test parse-15.15 {CommandComplete procedure} { info complete {a b "cd"xyz} } 1 test parse-15.16 {CommandComplete procedure} { info complete {a b "c $d() d"} } 1 test parse-15.17 {CommandComplete procedure} { info complete {a b "c $dd("} } 0 test parse-15.18 {CommandComplete procedure} { info complete {a b "c \"} } 0 test parse-15.19 {CommandComplete procedure} { info complete {a b "c [d e f]"} } 1 test parse-15.20 {CommandComplete procedure} { info complete {a b "c [d e f] g"} } 1 test parse-15.21 {CommandComplete procedure} { info complete {a b "c [d e f"} } 0 test parse-15.22 {CommandComplete procedure} { info complete {a {b c d} e} } 1 test parse-15.23 {CommandComplete procedure} { info complete {a {b c d}} } 1 test parse-15.24 {CommandComplete procedure} { info complete "a b\{c d" } 1 test parse-15.25 {CommandComplete procedure} { info complete "a b \{c" } 0 test parse-15.26 {CommandComplete procedure} { info complete "a b \{c{ }" } 0 test parse-15.27 {CommandComplete procedure} { info complete "a b {c d e}xxx" } 1 test parse-15.28 {CommandComplete procedure} { info complete "a b {c \\\{d e}xxx" } 1 test parse-15.29 {CommandComplete procedure} { info complete {a b [ab cd ef]} } 1 test parse-15.30 {CommandComplete procedure} { info complete {a b x[ab][cd][ef] gh} } 1 test parse-15.31 {CommandComplete procedure} { info complete {a b x[ab][cd[ef] gh} } 0 test parse-15.32 {CommandComplete procedure} { info complete {a b x[ gh} } 0 test parse-15.33 {CommandComplete procedure} { info complete {[]]]} } 1 test parse-15.34 {CommandComplete procedure} { info complete {abc x$yyy} } 1 test parse-15.35 {CommandComplete procedure} { info complete "abc x\${abc\[\\d} xyz" } 1 test parse-15.36 {CommandComplete procedure} { info complete "abc x\$\{ xyz" } 0 test parse-15.37 {CommandComplete procedure} { info complete {word $a(xyz)} } 1 test parse-15.38 {CommandComplete procedure} { info complete {word $a(} } 0 test parse-15.39 {CommandComplete procedure} { info complete "set a \\\n" } 0 test parse-15.40 {CommandComplete procedure} { info complete "set a \\\\\n" } 1 test parse-15.41 {CommandComplete procedure} { info complete "set a \\n " } 1 test parse-15.42 {CommandComplete procedure} { info complete "set a \\" } 1 test parse-15.43 {CommandComplete procedure} { info complete "foo \\\n\{" } 0 test parse-15.44 {CommandComplete procedure} { info complete "a\nb\n# \{\n# \{\nc\n" } 1 test parse-15.45 {CommandComplete procedure} { info complete "#Incomplete comment\\\n" } 0 test parse-15.46 {CommandComplete procedure} { info complete "#Incomplete comment\\\nBut now it's complete.\n" } 1 test parse-15.47 {CommandComplete procedure} { info complete "# Complete comment\\\\\n" } 1 test parse-15.48 {CommandComplete procedure} { info complete "abc\\\n def" } 1 test parse-15.49 {CommandComplete procedure} { info complete "abc\\\n " } 1 test parse-15.50 {CommandComplete procedure} { info complete "abc\\\n" } 0 test parse-15.51 {CommandComplete procedure} " info complete \"\\{abc\\}\\{\" " 1 test parse-15.52 {CommandComplete procedure} { info complete "\"abc\"(" } 1 test parse-15.53 {CommandComplete procedure} " info complete \" # {\" " 1 test parse-15.54 {CommandComplete procedure} " info complete \"foo bar;# {\" " 1 test parse-15.55 {CommandComplete procedure} { info complete "set x [bytestring \0]; puts hi" } 1 test parse-15.56 {CommandComplete procedure} { info complete "set x [bytestring \0]; \{" } 0 test parse-15.57 {CommandComplete procedure} { info complete "# Comment should be complete command" } 1 test parse-15.58 {CommandComplete procedure, memory leaks} { info complete "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22" } 1 test parse-15.59 {CommandComplete procedure} { # Test for Tcl Bug 684744 info complete [encoding convertfrom identity "\x00;if 1 \{"] } 0 test parse-16.1 {Tcl_EvalEx, check termOffset is set correctly for non TCL_OK cases, bug 2535} { subst {[eval {return foo}]bar} } foobar test parse-17.1 {Correct return codes from errors during substitution} { catch {eval {w[continue]}} } 4 test parse-19.1 {Bug 1115904: recursion limit in Tcl_EvalEx} -constraints { testevalex } -setup { interp create i load {} Tcltest i i eval {proc {} args {}} interp recursionlimit i 3 } -body { i eval {testevalex {[]}} } -cleanup { interp delete i } test parse-19.2 {Bug 1115904: recursion limit in Tcl_EvalEx} -constraints { testevalex } -setup { interp create i load {} Tcltest i i eval {proc {} args {}} interp recursionlimit i 3 } -body { i eval {testevalex {[[]]}} } -cleanup { interp delete i } -returnCodes error -match glob -result {too many nested*} test parse-19.3 {Bug 1115904: recursion limit in Tcl_EvalEx} -setup { interp create i i eval {proc {} args {}} interp recursionlimit i 3 } -body { i eval {subst {[]}} } -cleanup { interp delete i } test parse-19.4 {Bug 1115904: recursion limit in Tcl_EvalEx} -setup { interp create i i eval {proc {} args {}} interp recursionlimit i 3 } -body { i eval {subst {[[]]}} } -cleanup { interp delete i } -returnCodes error -match glob -result {too many nested*} test parse-20.1 {TclParseBackslash: truncated escape} { testparser {\u12345} 1 } {- \\ 1 simple \\ 1 text \\ 0 u12345} test parse-20.2 {TclParseBackslash: truncated escape} { testparser {\u12345} 2 } {- {\u} 1 word {\u} 1 backslash {\u} 0 12345} test parse-20.3 {TclParseBackslash: truncated escape} { testparser {\u12345} 3 } {- {\u1} 1 word {\u1} 1 backslash {\u1} 0 2345} test parse-20.4 {TclParseBackslash: truncated escape} { testparser {\u12345} 4 } {- {\u12} 1 word {\u12} 1 backslash {\u12} 0 345} test parse-20.5 {TclParseBackslash: truncated escape} { testparser {\u12345} 5 } {- {\u123} 1 word {\u123} 1 backslash {\u123} 0 45} test parse-20.6 {TclParseBackslash: truncated escape} { testparser {\u12345} 6 } {- {\u1234} 1 word {\u1234} 1 backslash {\u1234} 0 5} test parse-20.7 {TclParseBackslash: truncated escape} { testparser {\u12345} 7 } {- {\u12345} 1 word {\u12345} 2 backslash {\u1234} 0 text 5 0 {}} test parse-20.8 {TclParseBackslash: truncated escape} { testparser {\x12X} 1 } {- \\ 1 simple \\ 1 text \\ 0 x12X} test parse-20.9 {TclParseBackslash: truncated escape} { testparser {\x12X} 2 } {- {\x} 1 word {\x} 1 backslash {\x} 0 12X} test parse-20.10 {TclParseBackslash: truncated escape} { testparser {\x12X} 3 } {- {\x1} 1 word {\x1} 1 backslash {\x1} 0 2X} test parse-20.11 {TclParseBackslash: truncated escape} { testparser {\x12X} 4 } {- {\x12} 1 word {\x12} 1 backslash {\x12} 0 X} test parse-20.12 {TclParseBackslash: truncated escape} { testparser {\x12X} 5 } {- {\x12X} 1 word {\x12X} 2 backslash {\x12} 0 text X 0 {}} # cleanup catch {unset a} ::tcltest::cleanupTests return tcl8.4.20/tests/compExpr.test0000644003604700454610000004013411737050674014561 0ustar dgp771div# This file contains a collection of tests for the procedures in the # file tclCompExpr.c. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1997 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import -force ::tcltest::* } if {([catch {expr T1()} msg] == 1) && ($msg == {unknown math function "T1"})} { set gotT1 0 puts "This application hasn't been compiled with the \"T1\" and" puts "\"T2\" math functions, so I'll skip some of the expr tests." } else { set gotT1 1 } catch {unset a} test compExpr-1.1 {TclCompileExpr procedure, successful expr parse and compile} { expr 1+2 } 3 test compExpr-1.2 {TclCompileExpr procedure, error parsing expr} { list [catch {expr 1+2+} msg] $msg } {1 {syntax error in expression "1+2+": premature end of expression}} test compExpr-1.3 {TclCompileExpr procedure, error compiling expr} { list [catch {expr "foo(123)"} msg] $msg } {1 {unknown math function "foo"}} test compExpr-1.4 {TclCompileExpr procedure, expr has no operators} { set a {000123} expr {$a} } 83 test compExpr-2.1 {CompileSubExpr procedure, TCL_TOKEN_WORD parse token} { catch {unset a} set a 27 expr {"foo$a" < "bar"} } 0 test compExpr-2.2 {CompileSubExpr procedure, error compiling TCL_TOKEN_WORD parse token} { list [catch {expr {"00[expr 1+]" + 17}} msg] $msg } {1 {syntax error in expression "1+": premature end of expression}} test compExpr-2.3 {CompileSubExpr procedure, TCL_TOKEN_TEXT parse token} { expr {{12345}} } 12345 test compExpr-2.4 {CompileSubExpr procedure, empty TCL_TOKEN_TEXT parse token} { expr {{}} } {} test compExpr-2.5 {CompileSubExpr procedure, TCL_TOKEN_BS parse token} { expr "\{ \\ +123 \}" } 123 test compExpr-2.6 {CompileSubExpr procedure, TCL_TOKEN_COMMAND parse token} { expr {[info tclversion] != ""} } 1 test compExpr-2.7 {CompileSubExpr procedure, TCL_TOKEN_COMMAND parse token} { expr {[]} } {} test compExpr-2.8 {CompileSubExpr procedure, error in TCL_TOKEN_COMMAND parse token} { list [catch {expr {[foo "bar"xxx] + 17}} msg] $msg } {1 {extra characters after close-quote}} test compExpr-2.9 {CompileSubExpr procedure, TCL_TOKEN_VARIABLE parse token} { catch {unset a} set a 123 expr {$a*2} } 246 test compExpr-2.10 {CompileSubExpr procedure, TCL_TOKEN_VARIABLE parse token} { catch {unset a} catch {unset b} set a(george) martha set b geo expr {$a(${b}rge)} } martha test compExpr-2.11 {CompileSubExpr procedure, error in TCL_TOKEN_VARIABLE parse token} { catch {unset a} list [catch {expr {$a + 17}} msg] $msg } {1 {can't read "a": no such variable}} test compExpr-2.12 {CompileSubExpr procedure, TCL_TOKEN_SUB_EXPR parse token} { expr {27||3? 3<<(1+4) : 4&&9} } 96 test compExpr-2.13 {CompileSubExpr procedure, error in TCL_TOKEN_SUB_EXPR parse token} { catch {unset a} set a 15 list [catch {expr {27 || "$a[expr 1+]00"}} msg] $msg } {1 {syntax error in expression "1+": premature end of expression}} test compExpr-2.14 {CompileSubExpr procedure, TCL_TOKEN_OPERATOR token, op found} { expr {5*6} } 30 test compExpr-2.15 {CompileSubExpr procedure, TCL_TOKEN_OPERATOR token, math function found} { format %.6g [expr {sin(2.0)}] } 0.909297 test compExpr-2.16 {CompileSubExpr procedure, TCL_TOKEN_OPERATOR token, math function not found} { list [catch {expr {fred(2.0)}} msg] $msg } {1 {unknown math function "fred"}} test compExpr-2.17 {CompileSubExpr procedure, TCL_TOKEN_OPERATOR token, normal operator} { expr {4*2} } 8 test compExpr-2.18 {CompileSubExpr procedure, TCL_TOKEN_OPERATOR token, normal operator} { expr {4/2} } 2 test compExpr-2.19 {CompileSubExpr procedure, TCL_TOKEN_OPERATOR token, normal operator} { expr {4%2} } 0 test compExpr-2.20 {CompileSubExpr procedure, TCL_TOKEN_OPERATOR token, normal operator} { expr {4<<2} } 16 test compExpr-2.21 {CompileSubExpr procedure, TCL_TOKEN_OPERATOR token, normal operator} { expr {4>>2} } 1 test compExpr-2.22 {CompileSubExpr procedure, TCL_TOKEN_OPERATOR token, normal operator} { expr {4<2} } 0 test compExpr-2.23 {CompileSubExpr procedure, TCL_TOKEN_OPERATOR token, normal operator} { expr {4>2} } 1 test compExpr-2.24 {CompileSubExpr procedure, TCL_TOKEN_OPERATOR token, normal operator} { expr {4<=2} } 0 test compExpr-2.25 {CompileSubExpr procedure, TCL_TOKEN_OPERATOR token, normal operator} { expr {4>=2} } 1 test compExpr-2.26 {CompileSubExpr procedure, TCL_TOKEN_OPERATOR token, normal operator} { expr {4==2} } 0 test compExpr-2.27 {CompileSubExpr procedure, TCL_TOKEN_OPERATOR token, normal operator} { expr {4!=2} } 1 test compExpr-2.28 {CompileSubExpr procedure, TCL_TOKEN_OPERATOR token, normal operator} { expr {4&2} } 0 test compExpr-2.29 {CompileSubExpr procedure, TCL_TOKEN_OPERATOR token, normal operator} { expr {4^2} } 6 test compExpr-2.30 {CompileSubExpr procedure, TCL_TOKEN_OPERATOR token, normal operator} { expr {4|2} } 6 test compExpr-2.31 {CompileSubExpr procedure, TCL_TOKEN_OPERATOR token, normal operator, 1 operand} { expr {!4} } 0 test compExpr-2.32 {CompileSubExpr procedure, TCL_TOKEN_OPERATOR token, normal operator, 1 operand} { expr {~4} } -5 test compExpr-2.33 {CompileSubExpr procedure, TCL_TOKEN_OPERATOR token, normal operator, comparison} { catch {unset a} set a 15 expr {$a==15} ;# compiled out-of-line to runtime call on Tcl_ExprObjCmd } 1 test compExpr-2.34 {CompileSubExpr procedure, TCL_TOKEN_OPERATOR token, special operator} { expr {+2} } 2 test compExpr-2.35 {CompileSubExpr procedure, TCL_TOKEN_OPERATOR token, error in special operator} { list [catch {expr {+[expr 1+]}} msg] $msg } {1 {syntax error in expression "1+": premature end of expression}} test compExpr-2.36 {CompileSubExpr procedure, TCL_TOKEN_OPERATOR token, special operator} { expr {4+2} } 6 test compExpr-2.37 {CompileSubExpr procedure, TCL_TOKEN_OPERATOR token, error in special operator} { list [catch {expr {[expr 1+]+5}} msg] $msg } {1 {syntax error in expression "1+": premature end of expression}} test compExpr-2.38 {CompileSubExpr procedure, TCL_TOKEN_OPERATOR token, error in special operator} { list [catch {expr {5+[expr 1+]}} msg] $msg } {1 {syntax error in expression "1+": premature end of expression}} test compExpr-2.39 {CompileSubExpr procedure, TCL_TOKEN_OPERATOR token, special operator} { expr {-2} } -2 test compExpr-2.40 {CompileSubExpr procedure, TCL_TOKEN_OPERATOR token, special operator} { expr {4-2} } 2 test compExpr-2.41 {CompileSubExpr procedure, TCL_TOKEN_OPERATOR token, special operator} { catch {unset a} set a true expr {0||$a} } 1 test compExpr-2.42 {CompileSubExpr procedure, error in TCL_TOKEN_SUB_EXPR parse token} { catch {unset a} set a 15 list [catch {expr {27 || "$a[expr 1+]00"}} msg] $msg } {1 {syntax error in expression "1+": premature end of expression}} test compExpr-2.43 {CompileSubExpr procedure, TCL_TOKEN_OPERATOR token, special operator} { catch {unset a} set a false expr {3&&$a} } 0 test compExpr-2.44 {CompileSubExpr procedure, TCL_TOKEN_OPERATOR token, special operator} { catch {unset a} set a false expr {$a||1? 1 : 0} } 1 test compExpr-2.45 {CompileSubExpr procedure, error in TCL_TOKEN_SUB_EXPR parse token} { catch {unset a} set a 15 list [catch {expr {1? 54 : "$a[expr 1+]00"}} msg] $msg } {1 {syntax error in expression "1+": premature end of expression}} test compExpr-3.1 {CompileLandOrLorExpr procedure, numeric 1st operand} { catch {unset a} set a 2 expr {[set a]||0} } 1 test compExpr-3.2 {CompileLandOrLorExpr procedure, nonnumeric 1st operand} { catch {unset a} set a no expr {$a&&1} } 0 test compExpr-3.3 {CompileSubExpr procedure, error in 1st operand} { list [catch {expr {[expr *2]||0}} msg] $msg } {1 {syntax error in expression "*2": unexpected operator *}} test compExpr-3.4 {CompileLandOrLorExpr procedure, result is 1 or 0} { catch {unset a} catch {unset b} set a no set b true expr {$a || $b} } 1 test compExpr-3.5 {CompileLandOrLorExpr procedure, short-circuit semantics} { catch {unset a} set a yes expr {$a || [exit]} } 1 test compExpr-3.6 {CompileLandOrLorExpr procedure, short-circuit semantics} { catch {unset a} set a no expr {$a && [exit]} } 0 test compExpr-3.7 {CompileLandOrLorExpr procedure, numeric 2nd operand} { catch {unset a} set a 2 expr {0||[set a]} } 1 test compExpr-3.8 {CompileLandOrLorExpr procedure, nonnumeric 2nd operand} { catch {unset a} set a no expr {1&&$a} } 0 test compExpr-3.9 {CompileLandOrLorExpr procedure, error in 2nd operand} { list [catch {expr {0||[expr %2]}} msg] $msg } {1 {syntax error in expression "%2": unexpected operator %}} test compExpr-3.10 {CompileLandOrLorExpr procedure, long lor/land arm} { set a "abcdefghijkl" set i 7 expr {[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]] || [string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]] || [string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]] || [string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]} } 1 test compExpr-4.1 {CompileCondExpr procedure, simple test} { catch {unset a} set a 2 expr {($a > 1)? "ok" : "nope"} } ok test compExpr-4.2 {CompileCondExpr procedure, complex test, convert to numeric} { catch {unset a} set a no expr {[set a]? 27 : -54} } -54 test compExpr-4.3 {CompileCondExpr procedure, error in test} { list [catch {expr {[expr *2]? +1 : -1}} msg] $msg } {1 {syntax error in expression "*2": unexpected operator *}} test compExpr-4.4 {CompileCondExpr procedure, simple "true" clause} { catch {unset a} set a no expr {1? (27-2) : -54} } 25 test compExpr-4.5 {CompileCondExpr procedure, convert "true" clause to numeric} { catch {unset a} set a no expr {1? $a : -54} } no test compExpr-4.6 {CompileCondExpr procedure, error in "true" clause} { list [catch {expr {1? [expr *2] : -127}} msg] $msg } {1 {syntax error in expression "*2": unexpected operator *}} test compExpr-4.7 {CompileCondExpr procedure, simple "false" clause} { catch {unset a} set a no expr {(2-2)? -3.14159 : "nope"} } nope test compExpr-4.8 {CompileCondExpr procedure, convert "false" clause to numeric} { catch {unset a} set a 00123 expr {0? 42 : $a} } 83 test compExpr-4.9 {CompileCondExpr procedure, error in "false" clause} { list [catch {expr {1? 15 : [expr *2]}} msg] $msg } {1 {syntax error in expression "*2": unexpected operator *}} test compExpr-5.1 {CompileMathFuncCall procedure, math function found} { format %.6g [expr atan2(1.0, 2.0)] } 0.463648 test compExpr-5.2 {CompileMathFuncCall procedure, math function not found} { list [catch {expr {do_it()}} msg] $msg } {1 {unknown math function "do_it"}} if $gotT1 { test compExpr-5.3 {CompileMathFuncCall: call registered math function} { expr 3*T1()-1 } 368 test compExpr-5.4 {CompileMathFuncCall: call registered math function} { expr T2()*3 } 1035 } test compExpr-5.5 {CompileMathFuncCall procedure, too few arguments} { list [catch {expr {atan2(1.0)}} msg] $msg } {1 {too few arguments for math function}} test compExpr-5.6 {CompileMathFuncCall procedure, complex argument} { format %.6g [expr pow(2.1, 27.5-(24.4*(5%2)))] } 9.97424 test compExpr-5.7 {CompileMathFuncCall procedure, error in argument} { list [catch {expr {sinh(2.*)}} msg] $msg } {1 {syntax error in expression "sinh(2.*)": unexpected close parenthesis}} test compExpr-5.8 {CompileMathFuncCall procedure, too many arguments} { list [catch {expr {sinh(2.0, 3.0)}} msg] $msg } {1 {too many arguments for math function}} test compExpr-5.9 {CompileMathFuncCall procedure, too many arguments} { list [catch {expr {0 <= rand(5.2)}} msg] $msg } {1 {too many arguments for math function}} test compExpr-5.10 {error return from unbraced math func call of unknown function} -body { expr {bogus()} } -returnCodes error -result {unknown math function "bogus"} test compExpr-6.1 {LogSyntaxError procedure, error in expr longer than 60 chars} { list [catch {expr {(+0123456)*(+0123456)*(+0123456)*(+0123456)*(+0123456)*(+0123456)*(+0123456)/} -1 foo 3} msg] $msg } {1 {syntax error in expression "(+0123456)*(+0123456)*(+0123456)*(+0123456)*(+0123456)*(+012...": extra tokens at end of expression}} # cleanup catch {unset a} catch {unset b} ::tcltest::cleanupTests return tcl8.4.20/tests/regexp.test0000644003604700454610000006041312133546540014251 0ustar dgp771div# Commands covered: regexp, regsub # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1998 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import -force ::tcltest::* } catch {unset foo} test regexp-1.1 {basic regexp operation} { regexp ab*c abbbc } 1 test regexp-1.2 {basic regexp operation} { regexp ab*c ac } 1 test regexp-1.3 {basic regexp operation} { regexp ab*c ab } 0 test regexp-1.4 {basic regexp operation} { regexp -- -gorp abc-gorpxxx } 1 test regexp-1.5 {basic regexp operation} { regexp {^([^ ]*)[ ]*([^ ]*)} "" a } 1 test regexp-1.6 {basic regexp operation} { list [catch {regexp {} abc} msg] $msg } {0 1} test regexp-1.7 {regexp utf compliance} { # if not UTF-8 aware, result is "0 1" set foo "\u4e4eb q" regexp "\u4e4eb q" "a\u4e4eb qw\u5e4e\x4e wq" bar list [string compare $foo $bar] [regexp 4 $bar] } {0 0} test regexp-2.1 {getting substrings back from regexp} { set foo {} list [regexp ab*c abbbbc foo] $foo } {1 abbbbc} test regexp-2.2 {getting substrings back from regexp} { set foo {} set f2 {} list [regexp a(b*)c abbbbc foo f2] $foo $f2 } {1 abbbbc bbbb} test regexp-2.3 {getting substrings back from regexp} { set foo {} set f2 {} list [regexp a(b*)(c) abbbbc foo f2] $foo $f2 } {1 abbbbc bbbb} test regexp-2.4 {getting substrings back from regexp} { set foo {} set f2 {} set f3 {} list [regexp a(b*)(c) abbbbc foo f2 f3] $foo $f2 $f3 } {1 abbbbc bbbb c} test regexp-2.5 {getting substrings back from regexp} { set foo {}; set f1 {}; set f2 {}; set f3 {}; set f4 {}; set f5 {}; set f6 {}; set f7 {}; set f8 {}; set f9 {}; set fa {}; set fb {}; list [regexp (1*)(2*)(3*)(4*)(5*)(6*)(7*)(8*)(9*)(a*)(b*) \ 12223345556789999aabbb \ foo f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb] $foo $f1 $f2 $f3 $f4 $f5 \ $f6 $f7 $f8 $f9 $fa $fb } {1 12223345556789999aabbb 1 222 33 4 555 6 7 8 9999 aa bbb} test regexp-2.6 {getting substrings back from regexp} { set foo 2; set f2 2; set f3 2; set f4 2 list [regexp (a)(b)? xay foo f2 f3 f4] $foo $f2 $f3 $f4 } {1 a a {} {}} test regexp-2.7 {getting substrings back from regexp} { set foo 1; set f2 1; set f3 1; set f4 1 list [regexp (a)(b)?(c) xacy foo f2 f3 f4] $foo $f2 $f3 $f4 } {1 ac a {} c} test regexp-2.8 {getting substrings back from regexp} { set match {} list [regexp {^a*b} aaaab match] $match } {1 aaaab} test regexp-2.9 {getting substrings back from regexp} { set foo {} set f2 {} list [regexp f\352te(b*)c f\352tebbbbc foo f2] $foo $f2 } [list 1 f\352tebbbbc bbbb] test regexp-2.10 {getting substrings back from regexp} { set foo {} set f2 {} list [regexp f\352te(b*)c eff\352tebbbbc foo f2] $foo $f2 } [list 1 f\352tebbbbc bbbb] test regexp-3.1 {-indices option to regexp} { set foo {} list [regexp -indices ab*c abbbbc foo] $foo } {1 {0 5}} test regexp-3.2 {-indices option to regexp} { set foo {} set f2 {} list [regexp -indices a(b*)c abbbbc foo f2] $foo $f2 } {1 {0 5} {1 4}} test regexp-3.3 {-indices option to regexp} { set foo {} set f2 {} list [regexp -indices a(b*)(c) abbbbc foo f2] $foo $f2 } {1 {0 5} {1 4}} test regexp-3.4 {-indices option to regexp} { set foo {} set f2 {} set f3 {} list [regexp -indices a(b*)(c) abbbbc foo f2 f3] $foo $f2 $f3 } {1 {0 5} {1 4} {5 5}} test regexp-3.5 {-indices option to regexp} { set foo {}; set f1 {}; set f2 {}; set f3 {}; set f4 {}; set f5 {}; set f6 {}; set f7 {}; set f8 {}; set f9 {} list [regexp -indices (1*)(2*)(3*)(4*)(5*)(6*)(7*)(8*)(9*) \ 12223345556789999 \ foo f1 f2 f3 f4 f5 f6 f7 f8 f9] $foo $f1 $f2 $f3 $f4 $f5 \ $f6 $f7 $f8 $f9 } {1 {0 16} {0 0} {1 3} {4 5} {6 6} {7 9} {10 10} {11 11} {12 12} {13 16}} test regexp-3.6 {getting substrings back from regexp} { set foo 2; set f2 2; set f3 2; set f4 2 list [regexp -indices (a)(b)? xay foo f2 f3 f4] $foo $f2 $f3 $f4 } {1 {1 1} {1 1} {-1 -1} {-1 -1}} test regexp-3.7 {getting substrings back from regexp} { set foo 1; set f2 1; set f3 1; set f4 1 list [regexp -indices (a)(b)?(c) xacy foo f2 f3 f4] $foo $f2 $f3 $f4 } {1 {1 2} {1 1} {-1 -1} {2 2}} test regexp-4.1 {-nocase option to regexp} { regexp -nocase foo abcFOo } 1 test regexp-4.2 {-nocase option to regexp} { set f1 22 set f2 33 set f3 44 list [regexp -nocase {a(b*)([xy]*)z} aBbbxYXxxZ22 f1 f2 f3] $f1 $f2 $f3 } {1 aBbbxYXxxZ Bbb xYXxx} test regexp-4.3 {-nocase option to regexp} { regexp -nocase FOo abcFOo } 1 set x abcdefghijklmnopqrstuvwxyz1234567890 set x $x$x$x$x$x$x$x$x$x$x$x$x test regexp-4.4 {case conversion in regexp} { list [regexp -nocase $x $x foo] $foo } "1 $x" catch {unset x} test regexp-5.1 {exercise cache of compiled expressions} { regexp .*a b regexp .*b c regexp .*c d regexp .*d e regexp .*e f regexp .*a bbba } 1 test regexp-5.2 {exercise cache of compiled expressions} { regexp .*a b regexp .*b c regexp .*c d regexp .*d e regexp .*e f regexp .*b xxxb } 1 test regexp-5.3 {exercise cache of compiled expressions} { regexp .*a b regexp .*b c regexp .*c d regexp .*d e regexp .*e f regexp .*c yyyc } 1 test regexp-5.4 {exercise cache of compiled expressions} { regexp .*a b regexp .*b c regexp .*c d regexp .*d e regexp .*e f regexp .*d 1d } 1 test regexp-5.5 {exercise cache of compiled expressions} { regexp .*a b regexp .*b c regexp .*c d regexp .*d e regexp .*e f regexp .*e xe } 1 test regexp-6.1 {regexp errors} { list [catch {regexp a} msg] $msg } {1 {wrong # args: should be "regexp ?switches? exp string ?matchVar? ?subMatchVar subMatchVar ...?"}} test regexp-6.2 {regexp errors} { list [catch {regexp -nocase a} msg] $msg } {1 {wrong # args: should be "regexp ?switches? exp string ?matchVar? ?subMatchVar subMatchVar ...?"}} test regexp-6.3 {regexp errors} { list [catch {regexp -gorp a} msg] $msg } {1 {bad switch "-gorp": must be -all, -about, -indices, -inline, -expanded, -line, -linestop, -lineanchor, -nocase, -start, or --}} test regexp-6.4 {regexp errors} { list [catch {regexp a( b} msg] $msg } {1 {couldn't compile regular expression pattern: parentheses () not balanced}} test regexp-6.5 {regexp errors} { list [catch {regexp a( b} msg] $msg } {1 {couldn't compile regular expression pattern: parentheses () not balanced}} test regexp-6.6 {regexp errors} { list [catch {regexp a a f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1} msg] $msg } {0 1} test regexp-6.7 {regexp errors} { list [catch {regexp (x)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.) xyzzy} msg] $msg } {0 0} test regexp-6.8 {regexp errors} { catch {unset f1} set f1 44 list [catch {regexp abc abc f1(f2)} msg] $msg } {1 {couldn't set variable "f1(f2)"}} test regexp-6.9 {regexp errors, -start bad int check} { list [catch {regexp -start bogus {^$} {}} msg] $msg } {1 {expected integer but got "bogus"}} test regexp-7.1 {basic regsub operation} { list [regsub aa+ xaxaaaxaa 111&222 foo] $foo } {1 xax111aaa222xaa} test regexp-7.2 {basic regsub operation} { list [regsub aa+ aaaxaa &111 foo] $foo } {1 aaa111xaa} test regexp-7.3 {basic regsub operation} { list [regsub aa+ xaxaaa 111& foo] $foo } {1 xax111aaa} test regexp-7.4 {basic regsub operation} { list [regsub aa+ aaa 11&2&333 foo] $foo } {1 11aaa2aaa333} test regexp-7.5 {basic regsub operation} { list [regsub aa+ xaxaaaxaa &2&333 foo] $foo } {1 xaxaaa2aaa333xaa} test regexp-7.6 {basic regsub operation} { list [regsub aa+ xaxaaaxaa 1&22& foo] $foo } {1 xax1aaa22aaaxaa} test regexp-7.7 {basic regsub operation} { list [regsub a(a+) xaxaaaxaa {1\122\1} foo] $foo } {1 xax1aa22aaxaa} test regexp-7.8 {basic regsub operation} { list [regsub a(a+) xaxaaaxaa {1\\\122\1} foo] $foo } "1 {xax1\\aa22aaxaa}" test regexp-7.9 {basic regsub operation} { list [regsub a(a+) xaxaaaxaa {1\\122\1} foo] $foo } "1 {xax1\\122aaxaa}" test regexp-7.10 {basic regsub operation} { list [regsub a(a+) xaxaaaxaa {1\\&\1} foo] $foo } "1 {xax1\\aaaaaxaa}" test regexp-7.11 {basic regsub operation} { list [regsub a(a+) xaxaaaxaa {1\&\1} foo] $foo } {1 xax1&aaxaa} test regexp-7.12 {basic regsub operation} { list [regsub a(a+) xaxaaaxaa {\1\1\1\1&&} foo] $foo } {1 xaxaaaaaaaaaaaaaaxaa} test regexp-7.13 {basic regsub operation} { set foo xxx list [regsub abc xyz 111 foo] $foo } {0 xyz} test regexp-7.14 {basic regsub operation} { set foo xxx list [regsub ^ xyz "111 " foo] $foo } {1 {111 xyz}} test regexp-7.15 {basic regsub operation} { set foo xxx list [regsub -- -foo abc-foodef "111 " foo] $foo } {1 {abc111 def}} test regexp-7.16 {basic regsub operation} { set foo xxx list [regsub x "" y foo] $foo } {0 {}} test regexp-7.17 {regsub utf compliance} { # if not UTF-8 aware, result is "0 1" set foo "xyz555ijka\u4e4ebpqr" regsub a\u4e4eb xyza\u4e4ebijka\u4e4ebpqr 555 bar list [string compare $foo $bar] [regexp 4 $bar] } {0 0} test regexp-8.1 {case conversion in regsub} { list [regsub -nocase a(a+) xaAAaAAay & foo] $foo } {1 xaAAaAAay} test regexp-8.2 {case conversion in regsub} { list [regsub -nocase a(a+) xaAAaAAay & foo] $foo } {1 xaAAaAAay} test regexp-8.3 {case conversion in regsub} { set foo 123 list [regsub a(a+) xaAAaAAay & foo] $foo } {0 xaAAaAAay} test regexp-8.4 {case conversion in regsub} { set foo 123 list [regsub -nocase a CaDE b foo] $foo } {1 CbDE} test regexp-8.5 {case conversion in regsub} { set foo 123 list [regsub -nocase XYZ CxYzD b foo] $foo } {1 CbD} test regexp-8.6 {case conversion in regsub} { set x abcdefghijklmnopqrstuvwxyz1234567890 set x $x$x$x$x$x$x$x$x$x$x$x$x set foo 123 list [regsub -nocase $x $x b foo] $foo } {1 b} test regexp-9.1 {-all option to regsub} { set foo 86 list [regsub -all x+ axxxbxxcxdx |&| foo] $foo } {4 a|xxx|b|xx|c|x|d|x|} test regexp-9.2 {-all option to regsub} { set foo 86 list [regsub -nocase -all x+ aXxXbxxcXdx |&| foo] $foo } {4 a|XxX|b|xx|c|X|d|x|} test regexp-9.3 {-all option to regsub} { set foo 86 list [regsub x+ axxxbxxcxdx |&| foo] $foo } {1 a|xxx|bxxcxdx} test regexp-9.4 {-all option to regsub} { set foo 86 list [regsub -all bc axxxbxxcxdx |&| foo] $foo } {0 axxxbxxcxdx} test regexp-9.5 {-all option to regsub} { set foo xxx list [regsub -all node "node node more" yy foo] $foo } {2 {yy yy more}} test regexp-9.6 {-all option to regsub} { set foo xxx list [regsub -all ^ xxx 123 foo] $foo } {1 123xxx} test regexp-10.1 {expanded syntax in regsub} { set foo xxx list [regsub -expanded ". \#comment\n . \#comment2" abc def foo] $foo } {1 defc} test regexp-10.2 {newline sensitivity in regsub} { set foo xxx list [regsub -line {^a.*b$} "dabc\naxyb\n" 123 foo] $foo } "1 {dabc\n123\n}" test regexp-10.3 {newline sensitivity in regsub} { set foo xxx list [regsub -line {^a.*b$} "dabc\naxyb\nxb" 123 foo] $foo } "1 {dabc\n123\nxb}" test regexp-10.4 {partial newline sensitivity in regsub} { set foo xxx list [regsub -lineanchor {^a.*b$} "da\naxyb\nxb" 123 foo] $foo } "1 {da\n123}" test regexp-10.5 {inverse partial newline sensitivity in regsub} { set foo xxx list [regsub -linestop {a.*b} "da\nbaxyb\nxb" 123 foo] $foo } "1 {da\nb123\nxb}" test regexp-11.1 {regsub errors} { list [catch {regsub a b} msg] $msg } {1 {wrong # args: should be "regsub ?switches? exp string subSpec ?varName?"}} test regexp-11.2 {regsub errors} { list [catch {regsub -nocase a b} msg] $msg } {1 {wrong # args: should be "regsub ?switches? exp string subSpec ?varName?"}} test regexp-11.3 {regsub errors} { list [catch {regsub -nocase -all a b} msg] $msg } {1 {wrong # args: should be "regsub ?switches? exp string subSpec ?varName?"}} test regexp-11.4 {regsub errors} { list [catch {regsub a b c d e f} msg] $msg } {1 {wrong # args: should be "regsub ?switches? exp string subSpec ?varName?"}} test regexp-11.5 {regsub errors} { list [catch {regsub -gorp a b c} msg] $msg } {1 {bad switch "-gorp": must be -all, -nocase, -expanded, -line, -linestop, -lineanchor, -start, or --}} test regexp-11.6 {regsub errors} { list [catch {regsub -nocase a( b c d} msg] $msg } {1 {couldn't compile regular expression pattern: parentheses () not balanced}} test regexp-11.7 {regsub errors} { catch {unset f1} set f1 44 list [catch {regsub -nocase aaa aaa xxx f1(f2)} msg] $msg } {1 {couldn't set variable "f1(f2)"}} test regexp-11.8 {regsub errors, -start bad int check} { list [catch {regsub -start bogus pattern string rep var} msg] $msg } {1 {expected integer but got "bogus"}} test regexp-11.9 {regsub without final variable name returns value} { regsub b abaca X } {aXaca} test regexp-11.10 {regsub without final variable name returns value} { regsub -all a abaca X } {XbXcX} test regexp-11.11 {regsub without final variable name returns value} { regsub b(.*?)d abcdeabcfde {,&,\1,} } {a,bcd,c,eabcfde} test regexp-11.12 {regsub without final variable name returns value} { regsub -all b(.*?)d abcdeabcfde {,&,\1,} } {a,bcd,c,ea,bcfd,cf,e} # This test crashes on the Mac unless you increase the Stack Space to about 1 # Meg. This is probably bigger than most users want... # 8.2.3 regexp reduced stack space requirements, but this should be # tested again test regexp-12.1 {Tcl_RegExpExec: large number of subexpressions} {macCrash} { list [regexp (.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.) abcdefghijklmnopqrstuvwxyz all a b c d e f g h i j k l m n o p q r s t u v w x y z] $all $a $b $c $d $e $f $g $h $i $j $k $l $m $n $o $p $q $r $s $t $u $v $w $x $y $z } {1 abcdefghijklmnopqrstuvwxyz a b c d e f g h i j k l m n o p q r s t u v w x y z} test regexp-13.1 {regsub of a very large string} { # This test is designed to stress the memory subsystem in order # to catch Bug #933. It only fails if the Tcl memory allocator # is in use. set line {BEGIN_TABLE ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; END_TABLE} set filedata [string repeat $line 200] for {set i 1} {$i<10} {incr i} { regsub -all "BEGIN_TABLE " $filedata "" newfiledata } set x done } {done} test regexp-14.1 {CompileRegexp: regexp cache} { regexp .*a b regexp .*b c regexp .*c d regexp .*d e regexp .*e f set x . append x *a regexp $x bbba } 1 test regexp-14.2 {CompileRegexp: regexp cache, different flags} { regexp .*a b regexp .*b c regexp .*c d regexp .*d e regexp .*e f set x . append x *a regexp -nocase $x bbba } 1 testConstraint exec [llength [info commands exec]] test regexp-14.3 {CompileRegexp: regexp cache, empty regexp and empty cache} -constraints { exec } -setup { set junk [makeFile {puts [regexp {} foo]} junk.tcl] } -body { exec [interpreter] $junk } -cleanup { removeFile junk.tcl } -result 1 test regexp-15.1 {regexp -start} { catch {unset x} list [regexp -start -10 {\d} 1abc2de3 x] $x } {1 1} test regexp-15.2 {regexp -start} { catch {unset x} list [regexp -start 2 {\d} 1abc2de3 x] $x } {1 2} test regexp-15.3 {regexp -start} { catch {unset x} list [regexp -start 4 {\d} 1abc2de3 x] $x } {1 2} test regexp-15.4 {regexp -start} { catch {unset x} list [regexp -start 5 {\d} 1abc2de3 x] $x } {1 3} test regexp-15.5 {regexp -start, over end of string} { catch {unset x} list [regexp -start [string length 1abc2de3] {\d} 1abc2de3 x] [info exists x] } {0 0} test regexp-15.6 {regexp -start, loss of ^$ behavior} { list [regexp -start 2 {^$} {}] } {0} test regexp-16.1 {regsub -start} { catch {unset x} list [regsub -all -start 2 {\d} a1b2c3d4e5 {/&} x] $x } {4 a1b/2c/3d/4e/5} test regexp-16.2 {regsub -start} { catch {unset x} list [regsub -all -start -25 {z} hello {/&} x] $x } {0 hello} test regexp-16.3 {regsub -start} { catch {unset x} list [regsub -all -start 3 {z} hello {/&} x] $x } {0 hello} test regexp-16.4 {regsub -start, \A behavior} { set out {} lappend out [regsub -start 0 -all {\A(\w)} {abcde} {/\1} x] $x lappend out [regsub -start 2 -all {\A(\w)} {abcde} {/\1} x] $x } {5 /a/b/c/d/e 3 ab/c/d/e} test regexp-17.1 {regexp -inline} { regexp -inline b ababa } {b} test regexp-17.2 {regexp -inline} { regexp -inline (b) ababa } {b b} test regexp-17.3 {regexp -inline -indices} { regexp -inline -indices (b) ababa } {{1 1} {1 1}} test regexp-17.4 {regexp -inline} { regexp -inline {\w(\d+)\w} " hello 23 there456def " } {e456d 456} test regexp-17.5 {regexp -inline no matches} { regexp -inline {\w(\d+)\w} "" } {} test regexp-17.6 {regexp -inline no matches} { regexp -inline hello goodbye } {} test regexp-17.7 {regexp -inline, no matchvars allowed} { list [catch {regexp -inline b abc match} msg] $msg } {1 {regexp match variables not allowed when using -inline}} test regexp-18.1 {regexp -all} { regexp -all b bbbbb } {5} test regexp-18.2 {regexp -all} { regexp -all b abababbabaaaaaaaaaab } {6} test regexp-18.3 {regexp -all -inline} { regexp -all -inline b abababbabaaaaaaaaaab } {b b b b b b} test regexp-18.4 {regexp -all -inline} { regexp -all -inline {\w(\w)} abcdefg } {ab b cd d ef f} test regexp-18.5 {regexp -all -inline} { regexp -all -inline {\w(\w)$} abcdefg } {fg g} test regexp-18.6 {regexp -all -inline} { regexp -all -inline {\d+} 10:20:30:40 } {10 20 30 40} test regexp-18.7 {regexp -all -inline} { list [catch {regexp -all -inline b abc match} msg] $msg } {1 {regexp match variables not allowed when using -inline}} test regexp-18.8 {regexp -all} { # This should not cause an infinite loop regexp -all -inline {a*} a } {a} test regexp-18.9 {regexp -all} { # Yes, the expected result is {a {}}. Here's why: # Start at index 0; a* matches the "a" there then stops. # Go to index 1; a* matches the lambda (or {}) there then stops. Recall # that a* matches zero or more "a"'s; thus it matches the string "b", as # there are zero or more "a"'s there. # Go to index 2; this is past the end of the string, so stop. regexp -all -inline {a*} ab } {a {}} test regexp-18.10 {regexp -all} { # Yes, the expected result is {a {} a}. Here's why: # Start at index 0; a* matches the "a" there then stops. # Go to index 1; a* matches the lambda (or {}) there then stops. Recall # that a* matches zero or more "a"'s; thus it matches the string "b", as # there are zero or more "a"'s there. # Go to index 2; a* matches the "a" there then stops. # Go to index 3; this is past the end of the string, so stop. regexp -all -inline {a*} aba } {a {} a} test regexp-18.11 {regexp -all} { regexp -all -inline {^a} aaaa } {a} test regexp-18.12 {regexp -all -inline -indices} { regexp -all -inline -indices a(b(c)d|e(f)g)h abcdhaefgh } {{0 4} {1 3} {2 2} {-1 -1} {5 9} {6 8} {-1 -1} {7 7}} test regexp-19.1 {regsub null replacement} { regsub -all {@} {@hel@lo@} "\0a\0" result list $result [string length $result] } "\0a\0hel\0a\0lo\0a\0 14" test regexp-20.1 {regsub shared object shimmering} { # Bug #461322 set a abcdefghijklmnopqurstuvwxyz set b $a set c abcdefghijklmnopqurstuvwxyz0123456789 regsub $a $c $b d list $d [string length $d] [string bytelength $d] } [list abcdefghijklmnopqurstuvwxyz0123456789 37 37] test regexp-20.2 {regsub shared object shimmering with -about} { eval regexp -about abc } {0 {}} test regexp-21.1 {regsub works with empty string} { regsub -- ^ {} foo } {foo} test regexp-21.2 {regsub works with empty string} { regsub -- \$ {} foo } {foo} test regexp-21.3 {regsub works with empty string offset} { regsub -start 0 -- ^ {} foo } {foo} test regexp-21.4 {regsub works with empty string offset} { regsub -start 0 -- \$ {} foo } {foo} test regexp-21.5 {regsub works with empty string offset} { regsub -start 3 -- \$ {123} foo } {123foo} test regexp-21.6 {regexp works with empty string} { regexp -- ^ {} } {1} test regexp-21.7 {regexp works with empty string} { regexp -start 0 -- ^ {} } {1} test regexp-21.8 {regexp works with empty string offset} { regexp -start 3 -- ^ {123} } {0} test regexp-21.9 {regexp works with empty string offset} { regexp -start 3 -- \$ {123} } {1} test regexp-21.10 {multiple matches handle newlines} { regsub -all -lineanchor -- {^#[^\n]*\n} "#one\n#two\n#three\n" foo\n } "foo\nfoo\nfoo\n" test regexp-21.11 {multiple matches handle newlines} { regsub -all -line -- ^ "a\nb\nc" \# } "\#a\n\#b\n\#c" test regexp-21.12 {multiple matches handle newlines} { regsub -all -line -- ^ "\n\n" \# } "\#\n\#\n\#" test regexp-21.13 {multiple matches handle newlines} { regexp -all -inline -indices -line -- ^ "a\nb\nc" } {{0 -1} {2 1} {4 3}} test regexp-22.1 {Bug 1810038} { regexp ($|^X)* {} } 1 test regexp-22.2 {regexp compile and backrefs, Bug 1857126} { regexp -- {([bc])\1} bb } 1 test regexp-22.3 {Bug 3604074} { # This will hang in interps where the bug is not fixed regexp ((((((((a)*)*)*)*)*)*)*)* a } 1 test regexp-22.4 {Bug 3606139} -setup { interp alias {} a {} string repeat a } -body { # This crashes in interps where the bug is not fixed regexp [join [list [a 160]([a 55])[a 668]([a 55])[a 669]([a 55]) \ [a 668]([a 55])[a 649]([a 55])[a 668]([a 55])[a 668]([a 55]) \ [a 672]([a 55])[a 669]([a 55])[a 671]([a 55])[a 671]([a 55]) \ [a 672]([a 55])[a 652]([a 55])[a 672]([a 55])[a 671]([a 55]) \ [a 671]([a 55])[a 671]([a 55])[a 653]([a 55])[a 672]([a 55]) \ [a 653]([a 55])[a 672]([a 55])[a 672]([a 55])[a 652]([a 55]) \ [a 671]([a 55])[a 652]([a 55])[a 652]([a 55])[a 672]([a 55]) \ [a 672]([a 55])[a 672]([a 55])[a 653]([a 55])[a 671]([a 55]) \ [a 669]([a 55])[a 649]([a 55])[a 668]([a 55])[a 668]([a 55]) \ [a 668]([a 55])[a 650]([a 55])[a 650]([a 55])[a 672]([a 55]) \ [a 669]([a 55])[a 669]([a 55])[a 668]([a 55])[a 668]([a 55]) \ [a 668]([a 55])[a 669]([a 55])[a 672]([a 55])[a 669]([a 55]) \ [a 669]([a 55])[a 669]([a 55])[a 669]([a 55])[a 672]([a 55]) \ [a 670]([a 55])[a 671]([a 55])[a 672]([a 55])[a 672]([a 55]) \ [a 671]([a 55])[a 671]([a 55])[a 672]([a 55])[a 669]([a 55]) \ [a 668]([a 55])[a 668]([a 55])[a 669]([a 55])[a 668]([a 55]) \ [a 669]([a 55])[a 668]([a 55])[a 669]([a 55])[a 669]([a 55]) \ [a 668]([a 55])[a 668]([a 55])[a 669]([a 55])[a 668]([a 55]) \ [a 669]([a 55])[a 669]([a 55])[a 669]([a 55])[a 669]([a 55]) \ [a 668]([a 55])[a 669]([a 55])[a 672]([a 55])[a 669]([a 55]) \ [a 669]([a 55])[a 669]([a 55])[a 669]([a 55])[a 668]([a 55]) \ [a 669]([a 55])[a 669]([a 55])[a 668]([a 55])[a 668]([a 55]) \ [a 668]([a 55])[a 669]([a 55])[a 668]([a 55])[a 669]([a 55]) \ [a 672]([a 55])[a 669]([a 55])[a 669]([a 55])[a 710]([a 55]) \ [a 668]([a 55])[a 669]([a 55])[a 668]([a 55])[a 669]([a 55]) \ [a 668]([a 55])[a 669]([a 55])[a 668]([a 55])[a 668]([a 55]) \ [a 668]([a 55])[a 668]([a 55])[a 668]([a 55])[a 669]([a 55]) \ [a 672]([a 55])[a 669]([a 55])[a 669]([a 55])[a 668]([a 55]) \ [a 669]([a 55])[a 669]([a 55])[a 668]([a 55])[a 668]([a 55]) \ [a 668]([a 55])[a 668]([a 55])[a 668]([a 55])[a 668]([a 55]) \ [a 667]([a 55])[a 668]([a 55])[a 669]([a 55])[a 668]([a 55]) \ [a 671]([a 55])[a 669]([a 55])[a 668]([a 55])[a 669]([a 55]) \ [a 669]([a 55])[a 669]([a 55])[a 668]([a 55])[a 669]([a 55]) \ [a 668]([a 55])[a 710]([a 55])[a 668]([a 55])[a 668]([a 55]) \ [a 668]([a 55])[a 668]([a 55])[a 668]([a 55])[a 511]] {}] a } -cleanup { rename a {} } -returnCodes 1 -result {couldn't compile regular expression pattern: nfa has too many states} test regexp-22.5 {Bug 3610026} -setup { set e {} set cp 99 while {$cp < 32864} { append e [format %c [incr cp]] } } -body { regexp -about $e } -cleanup { unset -nocomplain e cp } -returnCodes error -match glob -result {*too many colors*} # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/unixFCmd.test0000644003604700454610000002577511737050674014517 0ustar dgp771div# This file tests the tclUnixFCmd.c file. # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1996 Sun Microsystems, Inc. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } # These tests really need to be run from a writable directory, which # it is assumed [temporaryDirectory] is. set oldcwd [pwd] cd [temporaryDirectory] # Several tests require need to match results against the unix username set user {} if {$tcl_platform(platform) == "unix"} { catch {set user [exec whoami]} if {$user == ""} { catch {regexp {^[^(]*\(([^)]*)\)} [exec id] dummy user} } if {$user == ""} { set user "root" } } proc openup {path} { testchmod 777 $path if {[file isdirectory $path]} { catch { foreach p [glob -directory $path *] { openup $p } } } } proc cleanup {args} { foreach p ". $args" { set x "" catch { set x [glob -directory $p tf* td*] } foreach file $x { if {[catch {file delete -force -- $file}]} { openup $file file delete -force -- $file } } } } test unixFCmd-1.1 {TclpRenameFile: EACCES} {unixOnly notRoot} { cleanup file mkdir td1/td2/td3 file attributes td1/td2 -permissions 0000 set msg [list [catch {file rename td1/td2/td3 td2} msg] $msg] file attributes td1/td2 -permissions 0755 set msg } {1 {error renaming "td1/td2/td3": permission denied}} test unixFCmd-1.2 {TclpRenameFile: EEXIST} {unixOnly notRoot} { cleanup file mkdir td1/td2 file mkdir td2 list [catch {file rename td2 td1} msg] $msg } {1 {error renaming "td2" to "td1/td2": file already exists}} test unixFCmd-1.3 {TclpRenameFile: EINVAL} {unixOnly notRoot} { cleanup file mkdir td1 list [catch {file rename td1 td1} msg] $msg } {1 {error renaming "td1" to "td1/td1": trying to rename a volume or move a directory into itself}} test unixFCmd-1.4 {TclpRenameFile: EISDIR} {emptyTest unixOnly notRoot} { # can't make it happen } {} test unixFCmd-1.5 {TclpRenameFile: ENOENT} {unixOnly notRoot} { cleanup file mkdir td1 list [catch {file rename td2 td1} msg] $msg } {1 {error renaming "td2": no such file or directory}} test unixFCmd-1.6 {TclpRenameFile: ENOTDIR} {emptyTest unixOnly notRoot} { # can't make it happen } {} test unixFCmd-1.7 {TclpRenameFile: EXDEV} {unixOnly notRoot} { cleanup file mkdir foo/bar file attr foo -perm 040555 set catchResult [catch {file rename foo/bar /tmp} msg] set msg [lindex [split $msg :] end] catch {file delete /tmp/bar} catch {file attr foo -perm 040777} catch {file delete -force foo} list $catchResult $msg } {1 { permission denied}} test unixFCmd-1.8 {Checking EINTR Bug} {unixOnly notRoot nonPortable} { testalarm after 2000 list [testgotsig] [testgotsig] } {1 0} test unixFCmd-1.9 {Checking EINTR Bug} {unixOnly notRoot nonPortable} { cleanup set f [open tfalarm w] puts $f { after 2000 puts "hello world" exit 0 } close $f testalarm set pipe [open "|[info nameofexecutable] tfalarm" r+] set line [read $pipe 1] catch {close $pipe} list $line [testgotsig] } {h 1} test unixFCmd-2.1 {TclpCopyFile: target exists: lstat(dst) == 0} \ {unixOnly notRoot} { cleanup close [open tf1 a] close [open tf2 a] file copy -force tf1 tf2 } {} test unixFCmd-2.2.1 {TclpCopyFile: src is symlink} {unixOnly notRoot dontCopyLinks} { # copying links should end up with real files cleanup close [open tf1 a] file link -symbolic tf2 tf1 file copy tf2 tf3 file type tf3 } {file} test unixFCmd-2.2.2 {TclpCopyFile: src is symlink} {unixOnly notRoot} { # copying links should end up with the links copied cleanup close [open tf1 a] file link -symbolic tf2 tf1 file copy tf2 tf3 file type tf3 } {link} test unixFCmd-2.3 {TclpCopyFile: src is block} {unixOnly notRoot} { cleanup set null "/dev/null" while {[file type $null] != "characterSpecial"} { set null [file join [file dirname $null] [file readlink $null]] } # file copy $null tf1 } {} test unixFCmd-2.4 {TclpCopyFile: src is fifo} {unixOnly notRoot} { cleanup if [catch {exec mknod tf1 p}] { list 1 } else { file copy tf1 tf2 expr {"[file type tf1]" == "[file type tf2]"} } } {1} test unixFCmd-2.5 {TclpCopyFile: copy attributes} {unixOnly notRoot} { cleanup close [open tf1 a] file attributes tf1 -permissions 0472 file copy tf1 tf2 file attributes tf2 -permissions } 00472 ;# i.e. perms field of [exec ls -l tf2] is -r--rwx-w- test unixFCmd-3.1 {CopyFile not done} {emptyTest unixOnly notRoot} { } {} test unixFCmd-4.1 {TclpDeleteFile not done} {emptyTest unixOnly notRoot} { } {} test unixFCmd-5.1 {TclpCreateDirectory not done} {emptyTest unixOnly notRoot} { } {} test unixFCmd-6.1 {TclpCopyDirectory not done} {emptyTest unixOnly notRoot} { } {} test unixFCmd-7.1 {TclpRemoveDirectory not done} {emptyTest unixOnly notRoot} { } {} test unixFCmd-8.1 {TraverseUnixTree not done} {emptyTest unixOnly notRoot} { } {} test unixFCmd-9.1 {TraversalCopy not done} {emptyTest unixOnly notRoot} { } {} test unixFCmd-10.1 {TraversalDelete not done} {emptyTest unixOnly notRoot} { } {} test unixFCmd-11.1 {CopyFileAttrs not done} {emptyTest unixOnly notRoot} { } {} test unixFCmd-12.1 {GetGroupAttribute - file not found} {unixOnly notRoot} { catch {file delete -force -- foo.test} list [catch {file attributes foo.test -group} msg] $msg } {1 {could not read "foo.test": no such file or directory}} test unixFCmd-12.2 {GetGroupAttribute - file found} {unixOnly notRoot} { catch {file delete -force -- foo.test} close [open foo.test w] list [catch {file attributes foo.test -group}] [file delete -force -- foo.test] } {0 {}} test unixFCmd-13.1 {GetOwnerAttribute - file not found} {unixOnly notRoot} { catch {file delete -force -- foo.test} list [catch {file attributes foo.test -group} msg] $msg } {1 {could not read "foo.test": no such file or directory}} test unixFCmd-13.2 {GetOwnerAttribute} {unixOnly notRoot} { catch {file delete -force -- foo.test} close [open foo.test w] list [catch {file attributes foo.test -owner} msg] \ [string compare $msg $user] [file delete -force -- foo.test] } {0 0 {}} test unixFCmd-14.1 {GetPermissionsAttribute - file not found} {unixOnly notRoot} { catch {file delete -force -- foo.test} list [catch {file attributes foo.test -permissions} msg] $msg } {1 {could not read "foo.test": no such file or directory}} test unixFCmd-14.2 {GetPermissionsAttribute} {unixOnly notRoot} { catch {file delete -force -- foo.test} close [open foo.test w] list [catch {file attribute foo.test -permissions}] \ [file delete -force -- foo.test] } {0 {}} # Find a group that exists on this system, or else skip tests that require # groups set ::tcltest::testConstraints(foundGroup) 0 if {$tcl_platform(platform) == "unix"} { catch { set groupList [exec groups] set group [lindex $groupList 0] set ::tcltest::testConstraints(foundGroup) 1 } } #groups hard to test test unixFCmd-15.1 {SetGroupAttribute - invalid group} {unixOnly notRoot} { catch {file delete -force -- foo.test} list [catch {file attributes foo.test -group foozzz} msg] \ $msg [file delete -force -- foo.test] } {1 {could not set group for file "foo.test": group "foozzz" does not exist} {}} test unixFCmd-15.2 {SetGroupAttribute - invalid file} \ {unixOnly notRoot foundGroup} { catch {file delete -force -- foo.test} list [catch {file attributes foo.test -group $group} msg] $msg } {1 {could not set group for file "foo.test": no such file or directory}} #changing owners hard to do test unixFCmd-16.1 {SetOwnerAttribute - current owner} {unixOnly notRoot} { catch {file delete -force -- foo.test} close [open foo.test w] list [catch {file attributes foo.test -owner $user} msg] \ $msg [string compare [file attributes foo.test -owner] $user] \ [file delete -force -- foo.test] } {0 {} 0 {}} test unixFCmd-16.2 {SetOwnerAttribute - invalid file} {unixOnly notRoot} { catch {file delete -force -- foo.test} list [catch {file attributes foo.test -owner $user} msg] $msg } {1 {could not set owner for file "foo.test": no such file or directory}} test unixFCmd-16.3 {SetOwnerAttribute - invalid owner} {unixOnly notRoot} { catch {file delete -force -- foo.test} list [catch {file attributes foo.test -owner foozzz} msg] $msg } {1 {could not set owner for file "foo.test": user "foozzz" does not exist}} test unixFCmd-17.1 {SetPermissionsAttribute} {unixOnly notRoot} { catch {file delete -force -- foo.test} close [open foo.test w] list [catch {file attributes foo.test -permissions 0000} msg] \ $msg [file attributes foo.test -permissions] \ [file delete -force -- foo.test] } {0 {} 00000 {}} test unixFCmd-17.2 {SetPermissionsAttribute} {unixOnly notRoot} { catch {file delete -force -- foo.test} list [catch {file attributes foo.test -permissions 0000} msg] $msg } {1 {could not set permissions for file "foo.test": no such file or directory}} test unixFCmd-17.3 {SetPermissionsAttribute} {unixOnly notRoot} { catch {file delete -force -- foo.test} close [open foo.test w] list [catch {file attributes foo.test -permissions foo} msg] $msg \ [file delete -force -- foo.test] } {1 {unknown permission string format "foo"} {}} test unixFCmd-17.4 {SetPermissionsAttribute} {unixOnly notRoot} { catch {file delete -force -- foo.test} close [open foo.test w] list [catch {file attributes foo.test -permissions ---rwx} msg] $msg \ [file delete -force -- foo.test] } {1 {unknown permission string format "---rwx"} {}} close [open foo.test w] set ::i 4 proc permcheck {testnum permstr expected} { test $testnum {SetPermissionsAttribute} {unixOnly notRoot} { file attributes foo.test -permissions $permstr file attributes foo.test -permissions } $expected } permcheck unixFCmd-17.5 rwxrwxrwx 00777 permcheck unixFCmd-17.6 r--r---w- 00442 permcheck unixFCmd-17.7 0 00000 permcheck unixFCmd-17.8 u+rwx,g+r 00740 permcheck unixFCmd-17.9 u-w 00540 permcheck unixFCmd-17.10 o+rwx 00547 permcheck unixFCmd-17.11 --x--x--x 00111 permcheck unixFCmd-17.12 a+rwx 00777 file delete -force -- foo.test test unixFCmd-18.1 {Unix pwd} {nonPortable unixOnly notRoot} { # This test is nonportable because SunOS generates a weird error # message when the current directory isn't readable. set cd [pwd] set nd $cd/tstdir file mkdir $nd cd $nd file attributes $nd -permissions 0000 set r [list [catch {pwd} res] [string range $res 0 36]]; cd $cd; file attributes $nd -permissions 0755 file delete $nd set r } {1 {error getting working directory name:}} # cleanup cleanup cd $oldcwd ::tcltest::cleanupTests return tcl8.4.20/tests/dstring.test0000644003604700454610000001710711737050674014442 0ustar dgp771div# Commands covered: none # # This file contains a collection of tests for Tcl's dynamic string # library procedures. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1993 The Regents of the University of California. # Copyright (c) 1994 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } if {[info commands testdstring] == {}} { puts "This application hasn't been compiled with the \"testdstring\"" puts "command, so I can't test Tcl_DStringAppend et al." ::tcltest::cleanupTests return } test dstring-1.1 {appending and retrieving} { testdstring free testdstring append "abc" -1 list [testdstring get] [testdstring length] } {abc 3} test dstring-1.2 {appending and retrieving} { testdstring free testdstring append "abc" -1 testdstring append " xyzzy" 3 testdstring append " 12345" -1 list [testdstring get] [testdstring length] } {{abc xy 12345} 12} test dstring-1.3 {appending and retrieving} { testdstring free foreach l {a b c d e f g h i j k l m n o p} { testdstring append $l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l\n -1 } list [testdstring get] [testdstring length] } {{aaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbb ccccccccccccccccccccc ddddddddddddddddddddd eeeeeeeeeeeeeeeeeeeee fffffffffffffffffffff ggggggggggggggggggggg hhhhhhhhhhhhhhhhhhhhh iiiiiiiiiiiiiiiiiiiii jjjjjjjjjjjjjjjjjjjjj kkkkkkkkkkkkkkkkkkkkk lllllllllllllllllllll mmmmmmmmmmmmmmmmmmmmm nnnnnnnnnnnnnnnnnnnnn ooooooooooooooooooooo ppppppppppppppppppppp } 352} test dstring-2.1 {appending list elements} { testdstring free testdstring element "abc" testdstring element "d e f" list [testdstring get] [testdstring length] } {{abc {d e f}} 11} test dstring-2.2 {appending list elements} { testdstring free testdstring element "x" testdstring element "\{" testdstring element "ab\}" testdstring get } {x \{ ab\}} test dstring-2.3 {appending list elements} { testdstring free foreach l {a b c d e f g h i j k l m n o p} { testdstring element $l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l } testdstring get } {aaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbb ccccccccccccccccccccc ddddddddddddddddddddd eeeeeeeeeeeeeeeeeeeee fffffffffffffffffffff ggggggggggggggggggggg hhhhhhhhhhhhhhhhhhhhh iiiiiiiiiiiiiiiiiiiii jjjjjjjjjjjjjjjjjjjjj kkkkkkkkkkkkkkkkkkkkk lllllllllllllllllllll mmmmmmmmmmmmmmmmmmmmm nnnnnnnnnnnnnnnnnnnnn ooooooooooooooooooooo ppppppppppppppppppppp} test dstring-2.4 {appending list elements} { testdstring free testdstring append "a\{" -1 testdstring element abc testdstring append " \{" -1 testdstring element xyzzy testdstring get } "a{ abc {xyzzy" test dstring-2.5 {appending list elements} { testdstring free testdstring append " \{" -1 testdstring element abc testdstring get } " {abc" test dstring-2.6 {appending list elements} { testdstring free testdstring append " " -1 testdstring element abc testdstring get } { abc} test dstring-2.7 {appending list elements} { testdstring free testdstring append "\\ " -1 testdstring element abc testdstring get } "\\ abc" test dstring-2.8 {appending list elements} { testdstring free testdstring append "x " -1 testdstring element abc testdstring get } {x abc} test dstring-3.1 {nested sublists} { testdstring free testdstring start testdstring element foo testdstring element bar testdstring end testdstring element another testdstring get } {{foo bar} another} test dstring-3.2 {nested sublists} { testdstring free testdstring start testdstring start testdstring element abc testdstring element def testdstring end testdstring end testdstring element ghi testdstring get } {{{abc def}} ghi} test dstring-3.3 {nested sublists} { testdstring free testdstring start testdstring start testdstring start testdstring element foo testdstring element foo2 testdstring end testdstring end testdstring element foo3 testdstring end testdstring element foo4 testdstring get } {{{{foo foo2}} foo3} foo4} test dstring-3.4 {nested sublists} { testdstring free testdstring element before testdstring start testdstring element during testdstring element more testdstring end testdstring element last testdstring get } {before {during more} last} test dstring-3.5 {nested sublists} { testdstring free testdstring element "\{" testdstring start testdstring element first testdstring element second testdstring end testdstring get } {\{ {first second}} test dstring-4.1 {truncation} { testdstring free testdstring append "abcdefg" -1 testdstring trunc 3 list [testdstring get] [testdstring length] } {abc 3} test dstring-4.2 {truncation} { testdstring free testdstring append "xyzzy" -1 testdstring trunc 0 list [testdstring get] [testdstring length] } {{} 0} test dstring-5.1 {copying to result} { testdstring free testdstring append xyz -1 testdstring result } xyz test dstring-5.2 {copying to result} { testdstring free catch {unset a} foreach l {a b c d e f g h i j k l m n o p} { testdstring append $l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l\n -1 } set a [testdstring result] testdstring append abc -1 list $a [testdstring get] } {{aaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbb ccccccccccccccccccccc ddddddddddddddddddddd eeeeeeeeeeeeeeeeeeeee fffffffffffffffffffff ggggggggggggggggggggg hhhhhhhhhhhhhhhhhhhhh iiiiiiiiiiiiiiiiiiiii jjjjjjjjjjjjjjjjjjjjj kkkkkkkkkkkkkkkkkkkkk lllllllllllllllllllll mmmmmmmmmmmmmmmmmmmmm nnnnnnnnnnnnnnnnnnnnn ooooooooooooooooooooo ppppppppppppppppppppp } abc} test dstring-6.1 {Tcl_DStringGetResult} { testdstring free list [testdstring gresult staticsmall] [testdstring get] } {{} short} test dstring-6.2 {Tcl_DStringGetResult} { testdstring free foreach l {a b c d e f g h i j k l m n o p} { testdstring append $l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l$l\n -1 } list [testdstring gresult staticsmall] [testdstring get] } {{} short} test dstring-6.3 {Tcl_DStringGetResult} { set result {} lappend result [testdstring gresult staticlarge] testdstring append x 1 lappend result [testdstring get] } {{} {first0 first1 first2 first3 first4 first5 first6 first7 first8 first9 second0 second1 second2 second3 second4 second5 second6 second7 second8 second9 third0 third1 third2 third3 third4 third5 third6 third7 third8 third9 fourth0 fourth1 fourth2 fourth3 fourth4 fourth5 fourth6 fourth7 fourth8 fourth9 fifth0 fifth1 fifth2 fifth3 fifth4 fifth5 fifth6 fifth7 fifth8 fifth9 sixth0 sixth1 sixth2 sixth3 sixth4 sixth5 sixth6 sixth7 sixth8 sixth9 seventh0 seventh1 seventh2 seventh3 seventh4 seventh5 seventh6 seventh7 seventh8 seventh9 x}} test dstring-6.4 {Tcl_DStringGetResult} { set result {} lappend result [testdstring gresult free] testdstring append y 1 lappend result [testdstring get] } {{} {This is a malloc-ed stringy}} test dstring-6.5 {Tcl_DStringGetResult} { set result {} lappend result [testdstring gresult special] testdstring append z 1 lappend result [testdstring get] } {{} {This is a specially-allocated stringz}} # cleanup testdstring free ::tcltest::cleanupTests return tcl8.4.20/tests/expr.test0000644003604700454610000013165011737050674013746 0ustar dgp771div# Commands covered: expr # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1996-1997 Sun Microsystems, Inc. # Copyright (c) 1998-2000 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } testConstraint registeredMathFuncs [expr { ([catch {expr T1()} msg] != 1) || ($msg ne {unknown math function "T1"}) }] testConstraint wideIs64bit [expr {(0x80000000 > 0) && (0x8000000000000000 < 0)}] # procedures used below proc put_hello_char {c} { global a append a [format %c $c] return $c } proc hello_world {} { global a set a "" set L1 [set l0 [set h_1 [set q 0]]] for {put_hello_char [expr [put_hello_char [expr [set h 7]*10+2]]+29]} {$l0?[put_hello_char $l0] :!$h_1} {put_hello_char $ll;expr {$L1==2?[set ll [expr 32+0-0+[set bar 0]]]:0}} {expr {[incr L1]==[expr 1+([string length "abc"]-[string length "abc"])] ?[set ll [set l0 [expr 54<<1]]]:$ll==108&&$L1<3? [incr ll [expr 1|1<<1]; set ll $ll; set ll $ll; set ll $ll; set ll $ll; set l0 [expr ([string length "abc"]-[string length "abc"])+([string length "abc"]-[string length "abc"])-([string length "abc"]-[string length "abc"])+([string length "abc"]-[string length "abc"])]; set l0; set l0 $l0; set l0; set l0]:$L1==4&&$ll==32?[set ll [expr 19+$h1+([string length "abc"]-[string length "abc"])-([string length "abc"]-[string length "abc"])+([string length "abc"]-[string length "abc"])-([string length "abc"]-[string length "abc"])+[set foo [expr ([string length "abc"]-[string length "abc"])+([string length "abc"]-[string length "abc"])+([string length "abc"]-[string length "abc"])]]]] :[set q [expr $q-$h1+([string length "abc"]-[string length "abc"])-([string length "abc"]-[string length "abc"])]]};expr {$L1==5?[incr ll -8; set ll $ll; set ll]:$q&&$h1&&1};expr {$L1==4+2 ?[incr ll 3]:[expr ([string length "abc"]-[string length "abc"])+1]};expr {$ll==($h<<4)+2+0&&$L1!=6?[incr ll -6]:[set h1 [expr 100+([string length "abc"]-[string length "abc"])-([string length "abc"]-[string length "abc"])]]} expr {$L1!=1<<3?[incr q [expr ([string length "abc"]-[string length "abc"])-1]]:[set h_1 [set ll $h1]]} } set a } proc 12days {a b c} { global xxx expr {1<$a?[expr {$a<3?[12days -79 -13 [string range $c [12days -87 \ [expr 1-$b] [string range $c [12days -86 0 [string range $c 1 end]] \ end]] end]]:1};expr {$a<$b?[12days [expr $a+1] $b $c]:3};expr {[12days \ -94 [expr $a-27] $c]&&$a==2?$b<13?[12days 2 [expr $b+1] "%s %d %d\n"]:9 :16}]:$a<0?$a<-72?[12days $b $a "@n'+,#'/*\{\}w+/w#cdnr/+,\{\}r/*de\}+,/*\{*+,/w\{%+,/w#q#n+,/#\{l+,/n\{n+,/+#n+,/#;#q#n+,/+k#;*+,/'r :'d*'3,\}\{w+K w'K:'+\}e#';dq#'l q#'+d'K#!/+k#;q#'r\}eKK#\}w'r\}eKK\{nl\]'/#;#q#n')\{)#\}w')\{)\{nl\]'/+#n';d\}rw' i;# )\{nl\]!/n\{n#'; r\{#w'r nc\{nl\]'/#\{l,+'K \{rw' iK\{;\[\{nl\]'/w#q#n'wk nw' iwk\{KK\{nl\]!/w\{%'l##w#' i; :\{nl\]'/*\{q#'ld;r'\}\{nlwb!/*de\}'c ;;\{nl'-\{\}rw\]'/+,\}##'*\}#nc,',#nw\]'/+kd'+e\}+;#'rdq#w! nr'/ ') \}+\}\{rl#'\{n' ')# \}'+\}##(!!/"] :$a<-50?[string compare [format %c $b] [string index $c 0]]==0?[append \ xxx [string index $c 31];scan [string index $c 31] %c x;set x] :[12days -65 $b [string range $c 1 end]]:[12days [expr ([string compare \ [string index $c 0] "/"]==0)+$a] $b [string range $c 1 end]]:0<$a ?[12days 2 2 "%s"]:[string compare [string index $c 0] "/"]==0|| [12days 0 [12days -61 [scan [string index $c 0] %c x; set x] \ "!ek;dc i@bK'(q)-\[w\]*%n+r3#l,\{\}:\nuwloca-O;m .vpbks,fxntdCeghiry"] \ [string range $c 1 end]]} } proc do_twelve_days {} { global xxx set xxx "" 12days 1 1 1 string length $xxx } # start of tests catch {unset a b i x} test expr-1.1 {TclCompileExprCmd: no expression} { list [catch {expr } msg] $msg } {1 {wrong # args: should be "expr arg ?arg ...?"}} test expr-1.2 {TclCompileExprCmd: one expression word} { expr -25 } -25 test expr-1.3 {TclCompileExprCmd: two expression words} { expr -8.2 -6 } -14.2 test expr-1.4 {TclCompileExprCmd: five expression words} { expr 20 - 5 +10 -7 } 18 test expr-1.5 {TclCompileExprCmd: quoted expression word} { expr "0005" } 5 test expr-1.6 {TclCompileExprCmd: quoted expression word} { catch {expr "0005"zxy} msg set msg } {extra characters after close-quote} test expr-1.7 {TclCompileExprCmd: expression word in braces} { expr {-0005} } -5 test expr-1.8 {TclCompileExprCmd: expression word in braces} { expr {{-0x1234}} } -4660 test expr-1.9 {TclCompileExprCmd: expression word in braces} { catch {expr {-0005}foo} msg set msg } {extra characters after close-brace} test expr-1.10 {TclCompileExprCmd: other expression word in braces} { expr 4*[llength "6 2"] } 8 test expr-1.11 {TclCompileExprCmd: expression word terminated by ;} { expr 4*[llength "6 2"]; } 8 test expr-1.12 {TclCompileExprCmd: inlined expr (in "catch") inside other catch} { set a xxx catch { # Might not be a number set a [expr 10*$a] } } 1 test expr-1.13 {TclCompileExprCmd: second level of substitutions in expr not in braces with single var reference} { set a xxx set x 27; set bool {$x}; if $bool {set a foo} set a } foo test expr-1.14 {TclCompileExprCmd: second level of substitutions in expr with comparison as top-level operator} { set a xxx set x 2; set b {$x}; set a [expr $b == 2] set a } 1 test expr-1.15 {TclCompileExprCmd: second level of substitutions in expr with comparison as top-level operator} { set a xxx set x 2; set b {$x}; set a [expr $b eq 2] set a } 1 test expr-2.1 {TclCompileExpr: are builtin functions registered?} { expr double(5*[llength "6 2"]) } 10.0 test expr-2.2 {TclCompileExpr: error in expr} { catch {expr 2**3} msg set msg } {syntax error in expression "2**3": unexpected operator *} test expr-2.3 {TclCompileExpr: junk after legal expr} { catch {expr 7*[llength "a b"]foo} msg set msg } {syntax error in expression "7*2foo": extra tokens at end of expression} test expr-2.4 {TclCompileExpr: numeric expr string rep == formatted int rep} { expr {0001} } 1 test expr-3.1 {CompileCondExpr: just lor expr} {expr 3||0} 1 test expr-3.2 {CompileCondExpr: error in lor expr} { catch {expr x||3} msg set msg } {syntax error in expression "x||3": variable references require preceding $} test expr-3.3 {CompileCondExpr: test true arm} {expr 3>2?44:66} 44 test expr-3.4 {CompileCondExpr: error compiling true arm} { catch {expr 3>2?2**3:66} msg set msg } {syntax error in expression "3>2?2**3:66": unexpected operator *} test expr-3.5 {CompileCondExpr: test false arm} {expr 2>3?44:66} 66 test expr-3.6 {CompileCondExpr: error compiling false arm} { catch {expr 2>3?44:2**3} msg set msg } {syntax error in expression "2>3?44:2**3": unexpected operator *} test expr-3.7 {CompileCondExpr: long arms & nested cond exprs} {unixOnly nonPortable} { puts "Note: doing test expr-3.7 which can take several minutes to run" hello_world } {Hello world} catch {unset xxx} test expr-3.8 {CompileCondExpr: long arms & nested cond exprs} {unixOnly nonPortable} { puts "Note: doing test expr-3.8 which can take several minutes to run" do_twelve_days } 2358 catch {unset xxx} test expr-4.1 {CompileLorExpr: just land expr} {expr 1.3&&3.3} 1 test expr-4.2 {CompileLorExpr: error in land expr} { catch {expr x&&3} msg set msg } {syntax error in expression "x&&3": variable references require preceding $} test expr-4.3 {CompileLorExpr: simple lor exprs} {expr 0||1.0} 1 test expr-4.4 {CompileLorExpr: simple lor exprs} {expr 3.0||0.0} 1 test expr-4.5 {CompileLorExpr: simple lor exprs} {expr 0||0||1} 1 test expr-4.6 {CompileLorExpr: error compiling lor arm} { catch {expr 2**3||4.0} msg set msg } {syntax error in expression "2**3||4.0": unexpected operator *} test expr-4.7 {CompileLorExpr: error compiling lor arm} { catch {expr 1.3||2**3} msg set msg } {syntax error in expression "1.3||2**3": unexpected operator *} test expr-4.8 {CompileLorExpr: error compiling lor arms} { list [catch {expr {"a"||"b"}} msg] $msg } {1 {expected boolean value but got "a"}} test expr-4.9 {CompileLorExpr: long lor arm} { set a "abcdefghijkl" set i 7 expr {[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]] || [string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]] || [string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]] || [string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]} } 1 test expr-5.1 {CompileLandExpr: just bitor expr} {expr 7|0x13} 23 test expr-5.2 {CompileLandExpr: error in bitor expr} { catch {expr x|3} msg set msg } {syntax error in expression "x|3": variable references require preceding $} test expr-5.3 {CompileLandExpr: simple land exprs} {expr 0&&1.0} 0 test expr-5.4 {CompileLandExpr: simple land exprs} {expr 0&&0} 0 test expr-5.5 {CompileLandExpr: simple land exprs} {expr 3.0&&1.2} 1 test expr-5.6 {CompileLandExpr: simple land exprs} {expr 1&&1&&2} 1 test expr-5.7 {CompileLandExpr: error compiling land arm} { catch {expr 2**3&&4.0} msg set msg } {syntax error in expression "2**3&&4.0": unexpected operator *} test expr-5.8 {CompileLandExpr: error compiling land arm} { catch {expr 1.3&&2**3} msg set msg } {syntax error in expression "1.3&&2**3": unexpected operator *} test expr-5.9 {CompileLandExpr: error compiling land arm} { list [catch {expr {"a"&&"b"}} msg] $msg } {1 {expected boolean value but got "a"}} test expr-5.10 {CompileLandExpr: long land arms} { set a "abcdefghijkl" set i 7 expr {[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]] && [string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]] && [string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]] && [string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]} } 1 test expr-6.1 {CompileBitXorExpr: just bitand expr} {expr 7&0x13} 3 test expr-6.2 {CompileBitXorExpr: error in bitand expr} { catch {expr x|3} msg set msg } {syntax error in expression "x|3": variable references require preceding $} test expr-6.3 {CompileBitXorExpr: simple bitxor exprs} {expr 7^0x13} 20 test expr-6.4 {CompileBitXorExpr: simple bitxor exprs} {expr 3^0x10} 19 test expr-6.5 {CompileBitXorExpr: simple bitxor exprs} {expr 0^7} 7 test expr-6.6 {CompileBitXorExpr: simple bitxor exprs} {expr -1^7} -8 test expr-6.7 {CompileBitXorExpr: error compiling bitxor arm} { catch {expr 2**3|6} msg set msg } {syntax error in expression "2**3|6": unexpected operator *} test expr-6.8 {CompileBitXorExpr: error compiling bitxor arm} { catch {expr 2^x} msg set msg } {syntax error in expression "2^x": variable references require preceding $} test expr-6.9 {CompileBitXorExpr: runtime error in bitxor arm} { list [catch {expr {24.0^3}} msg] $msg } {1 {can't use floating-point value as operand of "^"}} test expr-6.10 {CompileBitXorExpr: runtime error in bitxor arm} { list [catch {expr {"a"^"b"}} msg] $msg } {1 {can't use non-numeric string as operand of "^"}} test expr-7.1 {CompileBitAndExpr: just equality expr} {expr 3==2} 0 test expr-7.2 {CompileBitAndExpr: just equality expr} {expr 2.0==2} 1 test expr-7.3 {CompileBitAndExpr: just equality expr} {expr 3.2!=2.2} 1 test expr-7.4 {CompileBitAndExpr: just equality expr} {expr {"abc" == "abd"}} 0 test expr-7.5 {CompileBitAndExpr: error in equality expr} { catch {expr x==3} msg set msg } {syntax error in expression "x==3": variable references require preceding $} test expr-7.6 {CompileBitAndExpr: simple bitand exprs} {expr 7&0x13} 3 test expr-7.7 {CompileBitAndExpr: simple bitand exprs} {expr 0xf2&0x53} 82 test expr-7.8 {CompileBitAndExpr: simple bitand exprs} {expr 3&6} 2 test expr-7.9 {CompileBitAndExpr: simple bitand exprs} {expr -1&-7} -7 test expr-7.10 {CompileBitAndExpr: error compiling bitand arm} { catch {expr 2**3&6} msg set msg } {syntax error in expression "2**3&6": unexpected operator *} test expr-7.11 {CompileBitAndExpr: error compiling bitand arm} { catch {expr 2&x} msg set msg } {syntax error in expression "2&x": variable references require preceding $} test expr-7.12 {CompileBitAndExpr: runtime error in bitand arm} { list [catch {expr {24.0&3}} msg] $msg } {1 {can't use floating-point value as operand of "&"}} test expr-7.13 {CompileBitAndExpr: runtime error in bitand arm} { list [catch {expr {"a"&"b"}} msg] $msg } {1 {can't use non-numeric string as operand of "&"}} test expr-7.14 {CompileBitAndExpr: equality expr} {expr 3eq2} 0 test expr-7.18 {CompileBitAndExpr: equality expr} {expr {"abc" eq "abd"}} 0 test expr-7.20 {CompileBitAndExpr: error in equality expr} { catch {expr xne3} msg set msg } {syntax error in expression "xne3": variable references require preceding $} test expr-8.1 {CompileEqualityExpr: just relational expr} {expr 3>=2} 1 test expr-8.2 {CompileEqualityExpr: just relational expr} {expr 2<=2.1} 1 test expr-8.3 {CompileEqualityExpr: just relational expr} {expr 3.2>"2.2"} 1 test expr-8.4 {CompileEqualityExpr: just relational expr} {expr {"0y"<"0x12"}} 0 test expr-8.5 {CompileEqualityExpr: error in relational expr} { catch {expr x>3} msg set msg } {syntax error in expression "x>3": variable references require preceding $} test expr-8.6 {CompileEqualityExpr: simple equality exprs} {expr 7==0x13} 0 test expr-8.7 {CompileEqualityExpr: simple equality exprs} {expr -0xf2!=0x53} 1 test expr-8.8 {CompileEqualityExpr: simple equality exprs} {expr {"12398712938788234-1298379" != ""}} 1 test expr-8.9 {CompileEqualityExpr: simple equality exprs} {expr -1!="abc"} 1 test expr-8.10 {CompileEqualityExpr: error compiling equality arm} { catch {expr 2**3==6} msg set msg } {syntax error in expression "2**3==6": unexpected operator *} test expr-8.11 {CompileEqualityExpr: error compiling equality arm} { catch {expr 2!=x} msg set msg } {syntax error in expression "2!=x": variable references require preceding $} test expr-8.12 {CompileBitAndExpr: equality expr} {expr {"a"eq"a"}} 1 test expr-8.13 {CompileBitAndExpr: equality expr} { set s \u00fc expr {"\374" eq $s} } 1 test expr-8.14 {CompileBitAndExpr: equality expr} {expr 3eq2} 0 test expr-8.15 {CompileBitAndExpr: equality expr} {expr 2.0eq2} 0 test expr-8.16 {CompileBitAndExpr: equality expr} {expr 3.2ne2.2} 1 test expr-8.17 {CompileBitAndExpr: equality expr} {expr 01eq1} 0 test expr-8.18 {CompileBitAndExpr: equality expr} {expr {"abc" eq "abd"}} 0 test expr-8.19 {CompileBitAndExpr: equality expr} {expr {"abc" ne "abd"}} 1 test expr-8.20 {CompileBitAndExpr: error in equality expr} { catch {expr x ne3} msg set msg } {syntax error in expression "x ne3": variable references require preceding $} test expr-8.21 {CompileBitAndExpr: error in equality expr} { # These should be ""ed to avoid the error catch {expr a eq b} msg set msg } {syntax error in expression "a eq b": variable references require preceding $} test expr-9.1 {CompileRelationalExpr: just shift expr} {expr 3<<2} 12 test expr-9.2 {CompileRelationalExpr: just shift expr} {expr 0xff>>2} 63 test expr-9.3 {CompileRelationalExpr: just shift expr} {expr -1>>2} -1 test expr-9.4 {CompileRelationalExpr: just shift expr} {expr {1<<3}} 8 # The following test is different for 32-bit versus 64-bit # architectures because LONG_MIN is different if {0x80000000 > 0} { test expr-9.5 {CompileRelationalExpr: shift expr producing LONG_MIN} {nonPortable} { expr {1<<63} } -9223372036854775808 } else { test expr-9.5 {CompileRelationalExpr: shift expr producing LONG_MIN} {nonPortable} { expr {1<<31} } -2147483648 } test expr-9.6 {CompileRelationalExpr: error in shift expr} { catch {expr x>>3} msg set msg } {syntax error in expression "x>>3": variable references require preceding $} test expr-9.7 {CompileRelationalExpr: simple relational exprs} {expr 0xff>=+0x3} 1 test expr-9.8 {CompileRelationalExpr: simple relational exprs} {expr -0xf2<0x3} 1 test expr-9.9 {CompileRelationalExpr: error compiling relational arm} { catch {expr 2**3>6} msg set msg } {syntax error in expression "2**3>6": unexpected operator *} test expr-9.10 {CompileRelationalExpr: error compiling relational arm} { catch {expr 2>0x3} 31 test expr-10.7 {CompileShiftExpr: simple shift exprs} {expr -0xf2<<0x3} -1936 test expr-10.8 {CompileShiftExpr: error compiling shift arm} { catch {expr 2**3>>6} msg set msg } {syntax error in expression "2**3>>6": unexpected operator *} test expr-10.9 {CompileShiftExpr: error compiling shift arm} { catch {expr 2<>43}} msg] $msg } {1 {can't use floating-point value as operand of ">>"}} test expr-10.11 {CompileShiftExpr: runtime error} { list [catch {expr {"a"<<"b"}} msg] $msg } {1 {can't use non-numeric string as operand of "<<"}} test expr-11.1 {CompileAddExpr: just multiply expr} {expr 4*-2} -8 test expr-11.2 {CompileAddExpr: just multiply expr} {expr 0xff%2} 1 test expr-11.3 {CompileAddExpr: just multiply expr} {expr -1/2} -1 test expr-11.4 {CompileAddExpr: just multiply expr} {expr 7891%0123} 6 test expr-11.5 {CompileAddExpr: error in multiply expr} { catch {expr x*3} msg set msg } {syntax error in expression "x*3": variable references require preceding $} test expr-11.6 {CompileAddExpr: simple add exprs} {expr 0xff++0x3} 258 test expr-11.7 {CompileAddExpr: simple add exprs} {expr -0xf2--0x3} -239 test expr-11.8 {CompileAddExpr: error compiling add arm} { catch {expr 2**3+6} msg set msg } {syntax error in expression "2**3+6": unexpected operator *} test expr-11.9 {CompileAddExpr: error compiling add arm} { catch {expr 2-x} msg set msg } {syntax error in expression "2-x": variable references require preceding $} test expr-11.10 {CompileAddExpr: runtime error} { list [catch {expr {24.0+"xx"}} msg] $msg } {1 {can't use non-numeric string as operand of "+"}} test expr-11.11 {CompileAddExpr: runtime error} { list [catch {expr {"a"-"b"}} msg] $msg } {1 {can't use non-numeric string as operand of "-"}} test expr-11.12 {CompileAddExpr: runtime error} { list [catch {expr {3/0}} msg] $msg } {1 {divide by zero}} test expr-11.13 {CompileAddExpr: runtime error} { list [catch {expr {2.3/0.0}} msg] $msg } {1 {divide by zero}} test expr-12.1 {CompileMultiplyExpr: just unary expr} {expr ~4} -5 test expr-12.2 {CompileMultiplyExpr: just unary expr} {expr --5} 5 test expr-12.3 {CompileMultiplyExpr: just unary expr} {expr !27} 0 test expr-12.4 {CompileMultiplyExpr: just unary expr} {expr ~0xff00ff} -16711936 test expr-12.5 {CompileMultiplyExpr: error in unary expr} { catch {expr ~x} msg set msg } {syntax error in expression "~x": variable references require preceding $} test expr-12.6 {CompileMultiplyExpr: simple multiply exprs} {expr 0xff*0x3} 765 test expr-12.7 {CompileMultiplyExpr: simple multiply exprs} {expr -0xf2%-0x3} -2 test expr-12.8 {CompileMultiplyExpr: error compiling multiply arm} { catch {expr 2*3%%6} msg set msg } {syntax error in expression "2*3%%6": unexpected operator %} test expr-12.9 {CompileMultiplyExpr: error compiling multiply arm} { catch {expr 2*x} msg set msg } {syntax error in expression "2*x": variable references require preceding $} test expr-12.10 {CompileMultiplyExpr: runtime error} { list [catch {expr {24.0*"xx"}} msg] $msg } {1 {can't use non-numeric string as operand of "*"}} test expr-12.11 {CompileMultiplyExpr: runtime error} { list [catch {expr {"a"/"b"}} msg] $msg } {1 {can't use non-numeric string as operand of "/"}} test expr-13.1 {CompileUnaryExpr: unary exprs} {expr -0xff} -255 test expr-13.2 {CompileUnaryExpr: unary exprs} {expr +000123} 83 test expr-13.3 {CompileUnaryExpr: unary exprs} {expr +--++36} 36 test expr-13.4 {CompileUnaryExpr: unary exprs} {expr !2} 0 test expr-13.5 {CompileUnaryExpr: unary exprs} {expr +--+-62.0} -62.0 test expr-13.6 {CompileUnaryExpr: unary exprs} {expr !0.0} 1 test expr-13.7 {CompileUnaryExpr: unary exprs} {expr !0xef} 0 test expr-13.8 {CompileUnaryExpr: error compiling unary expr} { catch {expr ~x} msg set msg } {syntax error in expression "~x": variable references require preceding $} test expr-13.9 {CompileUnaryExpr: error compiling unary expr} { catch {expr !1.x} msg set msg } {syntax error in expression "!1.x": extra tokens at end of expression} test expr-13.10 {CompileUnaryExpr: runtime error} { list [catch {expr {~"xx"}} msg] $msg } {1 {can't use non-numeric string as operand of "~"}} test expr-13.11 {CompileUnaryExpr: runtime error} { list [catch {expr ~4.0} msg] $msg } {1 {can't use floating-point value as operand of "~"}} test expr-13.12 {CompileUnaryExpr: just primary expr} {expr 0x123} 291 test expr-13.13 {CompileUnaryExpr: just primary expr} { set a 27 expr $a } 27 test expr-13.14 {CompileUnaryExpr: just primary expr} { expr double(27) } 27.0 test expr-13.15 {CompileUnaryExpr: just primary expr} {expr "123"} 123 test expr-13.16 {CompileUnaryExpr: error in primary expr} { catch {expr [set]} msg set msg } {wrong # args: should be "set varName ?newValue?"} test expr-13.17 {CompileUnaryExpr: negating non-numeric boolean literals} { set a1 yes; set a0 no; set b1 true; set b0 false list [expr {!$a1}] [expr {!$a0}] [expr {!$b1}] [expr {!$b0}] } {0 1 0 1} test expr-14.1 {CompilePrimaryExpr: literal primary} {expr 1} 1 test expr-14.2 {CompilePrimaryExpr: literal primary} {expr 123} 123 test expr-14.3 {CompilePrimaryExpr: literal primary} {expr 0xff} 255 test expr-14.4 {CompilePrimaryExpr: literal primary} {expr 00010} 8 test expr-14.5 {CompilePrimaryExpr: literal primary} {expr 62.0} 62.0 test expr-14.6 {CompilePrimaryExpr: literal primary} { expr 3.1400000 } 3.14 test expr-14.7 {CompilePrimaryExpr: literal primary} {expr {{abcde}<{abcdef}}} 1 test expr-14.8 {CompilePrimaryExpr: literal primary} {expr {{abc\ def} < {abcdef}}} 1 test expr-14.9 {CompilePrimaryExpr: literal primary} {expr {{abc\tde} > {abc\tdef}}} 0 test expr-14.10 {CompilePrimaryExpr: literal primary} {expr {{123}}} 123 test expr-14.11 {CompilePrimaryExpr: var reference primary} { set i 789 list [expr {$i}] [expr $i] } {789 789} test expr-14.12 {CompilePrimaryExpr: var reference primary} { set i {789} ;# test expr's aggressive conversion to numeric semantics list [expr {$i}] [expr $i] } {789 789} test expr-14.13 {CompilePrimaryExpr: var reference primary} { catch {unset a} set a(foo) foo set a(bar) bar set a(123) 123 set result "" lappend result [expr $a(123)] [expr {$a(bar)<$a(foo)}] catch {unset a} set result } {123 1} test expr-14.14 {CompilePrimaryExpr: var reference primary} { set i 123 ;# test "$var.0" floating point conversion hack list [expr $i] [expr $i.0] [expr $i.0/12.0] } {123 123.0 10.25} test expr-14.15 {CompilePrimaryExpr: var reference primary} { set i 123 catch {expr $i.2} msg set msg } 123.2 test expr-14.16 {CompilePrimaryExpr: error compiling var reference primary} { catch {expr {$a(foo}} msg set errorInfo } {missing ) while compiling "expr {$a(foo}"} test expr-14.17 {CompilePrimaryExpr: string primary that looks like var ref} { expr $ } $ test expr-14.18 {CompilePrimaryExpr: quoted string primary} { expr "21" } 21 test expr-14.19 {CompilePrimaryExpr: quoted string primary} { set i 123 set x 456 expr "$i+$x" } 579 test expr-14.20 {CompilePrimaryExpr: quoted string primary} { set i 3 set x 6 expr 2+"$i.$x" } 5.6 test expr-14.21 {CompilePrimaryExpr: error in quoted string primary} { catch {expr "[set]"} msg set msg } {wrong # args: should be "set varName ?newValue?"} test expr-14.22 {CompilePrimaryExpr: subcommand primary} { expr {[set i 123; set i]} } 123 test expr-14.23 {CompilePrimaryExpr: error in subcommand primary} { catch {expr {[set]}} msg set errorInfo } {wrong # args: should be "set varName ?newValue?" while compiling "set" while compiling "expr {[set]}"} test expr-14.24 {CompilePrimaryExpr: error in subcommand primary} { catch {expr {[set i}} msg set errorInfo } {missing close-bracket while compiling "expr {[set i}"} test expr-14.25 {CompilePrimaryExpr: math function primary} { format %.6g [expr exp(1.0)] } 2.71828 test expr-14.26 {CompilePrimaryExpr: math function primary} { format %.6g [expr pow(2.0+0.1,3.0+0.1)] } 9.97424 test expr-14.27 {CompilePrimaryExpr: error in math function primary} { catch {expr sinh::(2.0)} msg set errorInfo } {syntax error in expression "sinh::(2.0)": expected parenthesis enclosing function arguments while compiling "expr sinh::(2.0)"} test expr-14.28 {CompilePrimaryExpr: subexpression primary} { expr 2+(3*4) } 14 test expr-14.29 {CompilePrimaryExpr: error in subexpression primary} { catch {expr 2+(3*[set])} msg set errorInfo } {wrong # args: should be "set varName ?newValue?" while compiling "set" while compiling "expr 2+(3*[set])"} test expr-14.30 {CompilePrimaryExpr: missing paren in subexpression primary} { catch {expr 2+(3*(4+5)} msg set errorInfo } {syntax error in expression "2+(3*(4+5)": looking for close parenthesis while compiling "expr 2+(3*(4+5)"} test expr-14.31 {CompilePrimaryExpr: just var ref in subexpression primary} { set i "5+10" list "[expr $i] == 15" "[expr ($i)] == 15" "[eval expr ($i)] == 15" } {{15 == 15} {15 == 15} {15 == 15}} test expr-14.32 {CompilePrimaryExpr: unexpected token} { catch {expr @} msg set errorInfo } {syntax error in expression "@": character not legal in expressions while compiling "expr @"} test expr-15.1 {CompileMathFuncCall: missing parenthesis} { catch {expr sinh2.0)} msg set errorInfo } {syntax error in expression "sinh2.0)": variable references require preceding $ while compiling "expr sinh2.0)"} test expr-15.2 {CompileMathFuncCall: unknown math function} { catch {expr whazzathuh(1)} msg set errorInfo } {unknown math function "whazzathuh" while compiling "expr whazzathuh(1)"} test expr-15.3 {CompileMathFuncCall: too many arguments} { catch {expr sin(1,2,3)} msg set errorInfo } {too many arguments for math function while compiling "expr sin(1,2,3)"} test expr-15.4 {CompileMathFuncCall: ')' found before last required arg} { catch {expr sin()} msg set errorInfo } {too few arguments for math function while compiling "expr sin()"} test expr-15.5 {CompileMathFuncCall: too few arguments} { catch {expr pow(1)} msg set errorInfo } {too few arguments for math function while compiling "expr pow(1)"} test expr-15.6 {CompileMathFuncCall: missing ')'} { catch {expr sin(1} msg set errorInfo } {syntax error in expression "sin(1": missing close parenthesis at end of function call while compiling "expr sin(1"} test expr-15.7 {CompileMathFuncCall: call registered math function} {registeredMathFuncs} { expr 2*T1() } 246 test expr-15.8 {CompileMathFuncCall: call registered math function} {registeredMathFuncs} { expr T2()*3 } 1035 test expr-15.9 {CompileMathFuncCall: call registered math function} {registeredMathFuncs} { expr T3(21, 37) } 37 test expr-15.10 {CompileMathFuncCall: call registered math function} {registeredMathFuncs} { expr T3(21.2, 37) } 37.0 test expr-15.11 {CompileMathFuncCall: call registered math function} {registeredMathFuncs} { expr T3(-21.2, -17.5) } -17.5 test expr-15.12 {ExprCallMathFunc: call registered math function} {registeredMathFuncs} { expr T3(21, wide(37)) } 37 test expr=15.13 {ExprCallMathFunc: call registered math function} {registeredMathFuncs} { expr T3(wide(21), 37) } 37 test expr=15.14 {ExprCallMathFunc: call registered math function} {registeredMathFuncs} { expr T3(wide(21), wide(37)) } 37 test expr-15.15 {ExprCallMathFunc: call registered math function} {registeredMathFuncs} { expr T3(21.0, wide(37)) } 37.0 test expr=15.16 {ExprCallMathFunc: call registered math function} {registeredMathFuncs} { expr T3(wide(21), 37.0) } 37.0 test expr-16.1 {GetToken: checks whether integer token starting with "0x" (e.g., "0x$") is invalid} { catch {unset a} set a(VALUE) ff15 set i 123 if {[expr 0x$a(VALUE)] & 16} { set i {} } set i } {} test expr-16.2 {GetToken: check for string literal in braces} { expr {{1}} } {1} # Check "expr" and computed command names. test expr-17.1 {expr and computed command names} { set i 0 set z expr $z 1+2 } 3 # Check correct conversion of operands to numbers: If the string looks like # an integer, convert to integer. Otherwise, if the string looks like a # double, convert to double. test expr-18.1 {expr and conversion of operands to numbers} { set x [lindex 11 0] catch {expr int($x)} expr {$x} } 11 test expr-18.2 {whitespace strings should not be == 0 (buggy strtod)} { expr {" "} } { } # Check "expr" and interpreter result object resetting before appending # an error msg during evaluation of exprs not in {}s test expr-19.1 {expr and interpreter result object resetting} { proc p {} { set t 10.0 set x 2.0 set dx 0.2 set f {$dx-$x/10} set g {-$x/5} set center 1.0 set x [expr $x-$center] set dx [expr $dx+$g] set x [expr $x+$f+$center] set x [expr $x+$f+$center] set y [expr round($x)] } p } 3 # Test for incorrect "double evaluation" semantics test expr-20.1 {wrong brace matching} { catch {unset l} catch {unset r} catch {unset q} catch {unset cmd} catch {unset a} set l "\{"; set r "\}"; set q "\"" set cmd "expr $l$q|$q == $q$r$q$r" list [catch $cmd a] $a } {1 {extra characters after close-brace}} test expr-20.2 {double invocation of variable traces} { set exprtracecounter 0 proc exprtraceproc {args} { upvar #0 exprtracecounter counter set argc [llength $args] set extraargs [lrange $args 0 [expr {$argc - 4}]] set name [lindex $args [expr {$argc - 3}]] upvar 1 $name var if {[incr counter] % 2 == 1} { set var "$counter oops [concat $extraargs]" } else { set var "$counter + [concat $extraargs]" } } trace variable exprtracevar r [list exprtraceproc 10] list [catch {expr "$exprtracevar + 20"} a] $a \ [catch {expr "$exprtracevar + 20"} b] $b \ [unset exprtracevar exprtracecounter] } {1 {syntax error in expression "1 oops 10 + 20": extra tokens at end of expression} 0 32 {}} test expr-20.3 {broken substitution of integer digits} { # fails with 8.0.x, but not 8.1b2 list [set a 000; expr 0x1$a] [set a 1; expr ${a}000] } {4096 1000} test expr-20.4 {proper double evaluation compilation, error case} { catch {unset a}; # make sure $a doesn't exist list [catch {expr 1?{$a}:0} msg] $msg } {1 {can't read "a": no such variable}} test expr-20.5 {proper double evaluation compilation, working case} { set a yellow expr 1?{$a}:0 } yellow test expr-20.6 {handling of compile error in trial compile} { list [catch {expr + {[incr]}} msg] $msg } {1 {wrong # args: should be "incr varName ?increment?"}} test expr-20.7 {handling of compile error in runtime case} { list [catch {expr + {[error foo]}} msg] $msg } {1 foo} # Test for non-numeric boolean literal handling test expr-21.1 {non-numeric boolean literals} {expr false } false test expr-21.2 {non-numeric boolean literals} {expr true } true test expr-21.3 {non-numeric boolean literals} {expr off } off test expr-21.4 {non-numeric boolean literals} {expr on } on test expr-21.5 {non-numeric boolean literals} {expr no } no test expr-21.6 {non-numeric boolean literals} {expr yes } yes test expr-21.7 {non-numeric boolean literals} {expr !false} 1 test expr-21.8 {non-numeric boolean literals} {expr !true } 0 test expr-21.9 {non-numeric boolean literals} {expr !off } 1 test expr-21.10 {non-numeric boolean literals} {expr !on } 0 test expr-21.11 {non-numeric boolean literals} {expr !no } 1 test expr-21.12 {non-numeric boolean literals} {expr !yes } 0 # Test for non-numeric float handling. # # These are non-portable because strtod()-support for "Inf" and "NaN" # is so wildly variable. This sucks... test expr-22.1 {non-numeric floats} nonPortable { list [catch {expr {NaN + 1}} msg] $msg } {1 {can't use non-numeric floating-point value as operand of "+"}} test expr-22.2 {non-numeric floats} nonPortable { list [catch {expr {Inf + 1}} msg] $msg } {1 {can't use infinite floating-point value as operand of "+"}} test expr-22.3 {non-numeric floats} nonPortable { set nan NaN list [catch {expr {$nan + 1}} msg] $msg } {1 {can't use non-numeric floating-point value as operand of "+"}} test expr-22.4 {non-numeric floats} nonPortable { set inf Inf list [catch {expr {$inf + 1}} msg] $msg } {1 {can't use infinite floating-point value as operand of "+"}} test expr-22.5 {non-numeric floats} nonPortable { list [catch {expr NaN} msg] $msg } {1 {domain error: argument not in valid range}} test expr-22.6 {non-numeric floats} nonPortable { list [catch {expr Inf} msg] $msg } {1 {floating-point value too large to represent}} test expr-22.7 {non-numeric floats} nonPortable { list [catch {expr {1 / NaN}} msg] $msg } {1 {can't use non-numeric floating-point value as operand of "/"}} test expr-22.8 {non-numeric floats} nonPortable { list [catch {expr {1 / Inf}} msg] $msg } {1 {can't use infinite floating-point value as operand of "/"}} # Make sure [Bug 761471] stays fixed. test expr-22.9 {non-numeric floats: shared object equality and NaN} nonPortable { set x NaN expr {$x == $x} } 0 # Some compilers get this wrong; ensure that we work around it correctly test expr-24.1 {expr edge cases; shifting} {expr int(5)>>31} 0 test expr-24.2 {expr edge cases; shifting} {expr int(5)>>63} 0 test expr-24.3 {expr edge cases; shifting} {expr wide(5)>>31} 0 test expr-24.4 {expr edge cases; shifting} {expr wide(5)>>63} 0 test expr-24.5 {expr edge cases; shifting} nonPortable {expr int(5)<<31} 0 test expr-24.6 {expr edge cases; shifting} nonPortable {expr int(5)<<63} 0 test expr-24.7 {expr edge cases; shifting} {expr wide(5)<<31} 10737418240 test expr-24.8 {expr edge cases; shifting} nonPortable {expr wide(5)<<63} -9223372036854775808 test expr-24.9 {expr edge cases; shifting} {expr 5>>32} 0 test expr-38.1 {abs of smallest 32-bit integer [Bug 1241572]} {wideIs64bit} { expr {abs(int(-2147483648))} } 2147483648 test expr-38.2 {abs and -0 [Bug 1893815]} { expr {abs(-0)} } 0 test expr-38.3 {abs and -0 [Bug 1893815]} { expr {abs(-0.0)} } 0.0 # tests 38.4 to 38.8 not backported test expr-38.9 {abs and 0.0 [Bug 2954959]} { expr {abs(0.0)} } 0.0 test expr-38.10 {abs and -0x0 [Bug 2954959]} { expr {abs(-0x0)} } 0 # tests 38.11 to 38.13 not backported test expr-46.1 {round() rounds to +-infinity} { expr round(0.5) } 1 test expr-46.2 {round() rounds to +-infinity} { expr round(1.5) } 2 test expr-46.3 {round() rounds to +-infinity} { expr round(-0.5) } -1 test expr-46.4 {round() rounds to +-infinity} { expr round(-1.5) } -2 test expr-46.5 {round() overflow} { list [catch {expr round(9.2233720368547758e+018)} result] $result } {1 {integer value too large to represent}} test expr-46.6 {round() overflow} { list [catch {expr round(-9.2233720368547758e+018)} result] $result } {1 {integer value too large to represent}} test expr-46.7 {round() bad value} { set x trash list [catch {expr {round($x)}} result] $result } {1 {argument to math function didn't have numeric value}} test expr-46.8 {round() already an integer} { set x 123456789012 incr x expr round($x) } 123456789013 test expr-46.9 {round() boundary case - 1/2 - 1 ulp} { set x 0.25 set bit 0.125 while 1 { set newx [expr {$x + $bit}] if { $newx == $x || $newx == 0.5 } break set x $newx set bit [expr { $bit / 2.0 }] } expr {round($x)} } 0 test expr-46.10 {round() boundary case - 1/2 + 1 ulp} { set x 0.75 set bit 0.125 while 1 { set newx [expr { $x - $bit }] if { $newx == $x || $newx == 0.5 } break set x $newx set bit [expr { $bit / 2.0 }] } expr {round($x)} } 1 test expr-46.11 {round() boundary case - -1/2 - 1 ulp} { set x -0.75 set bit 0.125 while 1 { set newx [expr { $x + $bit }] if { $newx == $x || $newx == -0.5 } break set x $newx set bit [expr { $bit / 2.0 }] } expr {round($x)} } -1 test expr-46.12 {round() boundary case - -1/2 + 1 ulp} { set x -0.25 set bit 0.125 while 1 { set newx [expr { $x - $bit }] if { $newx == $x || $newx == -0.5 } break set x $newx set bit [expr { $bit / 2.0 }] } expr {round($x)} } 0 test expr-46.13 {round() boundary case - round down} { expr {round(2147483647 - 0.51)} } 2147483646 test expr-46.14 {round() boundary case - round up} { expr {round(2147483647 - 0.50)} } 2147483647 test expr-46.15 {round() boundary case - round up to wide} { expr {round(2147483647 + 0.50)} } [expr {wide(2147483647) + 1}] test expr-46.16 {round() boundary case - round up} { expr {round(-2147483648 + 0.51)} } -2147483647 test expr-46.17 {round() boundary case - round down} { expr {round(-2147483648 + 0.50)} } -2147483648 test expr-46.18 {round() boundary case - round down to wide} { expr {round(-2147483648 - 0.50)} } [expr {wide(-2147483648) - 1}] # cleanup if {[info exists a]} { unset a } ::tcltest::cleanupTests return tcl8.4.20/tests/remote.tcl0000644003604700454610000001011311737050674014054 0ustar dgp771div# This file contains Tcl code to implement a remote server that can be # used during testing of Tcl socket code. This server is used by some # of the tests in socket.test. # # Source this file in the remote server you are using to test Tcl against. # # Copyright (c) 1995-1996 Sun Microsystems, Inc. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # Initialize message delimitor # Initialize command array catch {unset command} set command(0) "" set callerSocket "" # Detect whether we should print out connection messages etc. if {![info exists VERBOSE]} { set VERBOSE 0 } proc __doCommands__ {l s} { global callerSocket VERBOSE if {$VERBOSE} { puts "--- Server executing the following for socket $s:" puts $l puts "---" } set callerSocket $s if {[catch {uplevel #0 $l} msg]} { list error $msg } else { list success $msg } } proc __readAndExecute__ {s} { global command VERBOSE set l [gets $s] if {[string compare $l "--Marker--Marker--Marker--"] == 0} { if {[info exists command($s)]} { puts $s [list error incomplete_command] } puts $s "--Marker--Marker--Marker--" return } if {[string compare $l ""] == 0} { if {[eof $s]} { if {$VERBOSE} { puts "Server closing $s, eof from client" } close $s } return } append command($s) $l "\n" if {[info complete $command($s)]} { set cmds $command($s) unset command($s) puts $s [__doCommands__ $cmds $s] } if {[eof $s]} { if {$VERBOSE} { puts "Server closing $s, eof from client" } close $s } } proc __accept__ {s a p} { global VERBOSE if {$VERBOSE} { puts "Server accepts new connection from $a:$p on $s" } fileevent $s readable [list __readAndExecute__ $s] fconfigure $s -buffering line -translation crlf } set serverIsSilent 0 for {set i 0} {$i < $argc} {incr i} { if {[string compare -serverIsSilent [lindex $argv $i]] == 0} { set serverIsSilent 1 break } } if {![info exists serverPort]} { if {[info exists env(serverPort)]} { set serverPort $env(serverPort) } } if {![info exists serverPort]} { for {set i 0} {$i < $argc} {incr i} { if {[string compare -port [lindex $argv $i]] == 0} { if {$i < [expr $argc - 1]} { set serverPort [lindex $argv [expr $i + 1]] } break } } } if {![info exists serverPort]} { set serverPort 2048 } if {![info exists serverAddress]} { if {[info exists env(serverAddress)]} { set serverAddress $env(serverAddress) } } if {![info exists serverAddress]} { for {set i 0} {$i < $argc} {incr i} { if {[string compare -address [lindex $argv $i]] == 0} { if {$i < [expr $argc - 1]} { set serverAddress [lindex $argv [expr $i + 1]] } break } } } if {![info exists serverAddress]} { set serverAddress 0.0.0.0 } if {$serverIsSilent == 0} { set l "Remote server listening on port $serverPort, IP $serverAddress." puts "" puts $l for {set c [string length $l]} {$c > 0} {incr c -1} {puts -nonewline "-"} puts "" puts "" puts "You have set the Tcl variables serverAddress to $serverAddress and" puts "serverPort to $serverPort. You can set these with the -address and" puts "-port command line options, or as environment variables in your" puts "shell." puts "" puts "NOTE: The tests will not work properly if serverAddress is set to" puts "\"localhost\" or 127.0.0.1." puts "" puts "When you invoke tcltest to run the tests, set the variables" puts "remoteServerPort to $serverPort and remoteServerIP to" puts "[info hostname]. You can set these as environment variables" puts "from the shell. The tests will not work properly if you set" puts "remoteServerIP to \"localhost\" or 127.0.0.1." puts "" puts -nonewline "Type Ctrl-C to terminate--> " flush stdout } if {[catch {set serverSocket \ [socket -myaddr $serverAddress -server __accept__ $serverPort]} msg]} { puts "Server on $serverAddress:$serverPort cannot start: $msg" } else { vwait __server_wait_variable__ } tcl8.4.20/tests/get.test0000644003604700454610000001045111737050674013542 0ustar dgp771div# Commands covered: none # # This file contains a collection of tests for the procedures in the # file tclGet.c. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1995-1996 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } test get-1.1 {Tcl_GetInt procedure} { set x 44 incr x { 22} } {66} test get-1.2 {Tcl_GetInt procedure} { set x 44 incr x -3 } {41} test get-1.3 {Tcl_GetInt procedure} { set x 44 incr x +8 } {52} test get-1.4 {Tcl_GetInt procedure} { set x 44 list [catch {incr x foo} msg] $msg } {1 {expected integer but got "foo"}} test get-1.5 {Tcl_GetInt procedure} { set x 44 list [catch {incr x {16 }} msg] $msg } {0 60} test get-1.6 {Tcl_GetInt procedure} { set x 44 list [catch {incr x {16 x}} msg] $msg } {1 {expected integer but got "16 x"}} # The following tests are non-portable because they depend on # word size. if {wide(0x80000000) > wide(0)} { test get-1.7 {Tcl_GetInt procedure} { set x 44 list [catch {eval incr x 18446744073709551616} msg] $msg $errorCode } {1 {integer value too large to represent} {ARITH IOVERFLOW {integer value too large to represent}}} test get-1.8 {Tcl_GetInt procedure} { set x 0 list [catch {incr x 18446744073709551614} msg] $msg } {0 -2} test get-1.9 {Tcl_GetInt procedure} { set x 0 list [catch {incr x +18446744073709551614} msg] $msg } {0 -2} test get-1.10 {Tcl_GetInt procedure} { set x 0 list [catch {incr x -18446744073709551614} msg] $msg } {0 2} } else { test get-1.11 {Tcl_GetInt procedure} { set x 44 list [catch {incr x 4294967296} msg] $msg $errorCode } {1 {integer value too large to represent} {ARITH IOVERFLOW {integer value too large to represent}}} test get-1.12 {Tcl_GetInt procedure} { set x 0 list [catch {incr x 4294967294} msg] $msg } {0 -2} test get-1.13 {Tcl_GetInt procedure} { set x 0 list [catch {incr x +4294967294} msg] $msg } {0 -2} test get-1.14 {Tcl_GetInt procedure} { set x 0 list [catch {incr x -4294967294} msg] $msg } {0 2} } test get-2.1 {Tcl_GetInt procedure} { format %g 1.23 } {1.23} test get-2.2 {Tcl_GetInt procedure} { format %g { 1.23 } } {1.23} test get-2.3 {Tcl_GetInt procedure} { list [catch {format %g clip} msg] $msg } {1 {expected floating-point number but got "clip"}} test get-2.4 {Tcl_GetInt procedure} {nonPortable} { list [catch {format %g .000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001} msg] $msg $errorCode } {1 {floating-point value too small to represent} {ARITH UNDERFLOW {floating-point value too small to represent}}} test get-3.1 {Tcl_GetInt(FromObj), bad numbers} { # SF bug #634856 set result "" set numbers [list 1 +1 ++1 +-1 -+1 -1 --1 "- +1" "+12345678987654321" "++12345678987654321"] foreach num $numbers { lappend result [catch {format %ld $num} msg] $msg } set result } {0 1 0 1 1 {expected integer but got "++1"} 1 {expected integer but got "+-1"} 1 {expected integer but got "-+1"} 0 -1 1 {expected integer but got "--1"} 1 {expected integer but got "- +1"} 0 12345678987654321 1 {expected integer but got "++12345678987654321"}} test get-3.2 {Tcl_GetDouble(FromObj), bad numbers} { set result "" set numbers [list 1.0 +1.0 ++1.0 +-1.0 -+1.0 -1.0 --1.0 "- +1.0"] foreach num $numbers { lappend result [catch {format %g $num} msg] $msg } set result } {0 1 0 1 1 {expected floating-point number but got "++1.0"} 1 {expected floating-point number but got "+-1.0"} 1 {expected floating-point number but got "-+1.0"} 0 -1 1 {expected floating-point number but got "--1.0"} 1 {expected floating-point number but got "- +1.0"}} # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/ioCmd.test0000644003604700454610000005310111737050674014015 0ustar dgp771div# -*- tcl -*- # Commands covered: open, close, gets, read, puts, seek, tell, eof, flush, # fblocked, fconfigure, open, channel, fcopy # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1994 The Regents of the University of California. # Copyright (c) 1994-1996 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } testConstraint fcopy [llength [info commands fcopy]] test iocmd-1.1 {puts command} { list [catch {puts} msg] $msg } {1 {wrong # args: should be "puts ?-nonewline? ?channelId? string"}} test iocmd-1.2 {puts command} { list [catch {puts a b c d e f g} msg] $msg } {1 {wrong # args: should be "puts ?-nonewline? ?channelId? string"}} test iocmd-1.3 {puts command} { list [catch {puts froboz -nonewline kablooie} msg] $msg } {1 {bad argument "kablooie": should be "nonewline"}} test iocmd-1.4 {puts command} { list [catch {puts froboz hello} msg] $msg } {1 {can not find channel named "froboz"}} test iocmd-1.5 {puts command} { list [catch {puts stdin hello} msg] $msg } {1 {channel "stdin" wasn't opened for writing}} set path(test1) [makeFile {} test1] test iocmd-1.6 {puts command} { set f [open $path(test1) w] fconfigure $f -translation lf -eofchar {} puts -nonewline $f foobar close $f file size $path(test1) } 6 test iocmd-1.7 {puts command} { set f [open $path(test1) w] fconfigure $f -translation lf -eofchar {} puts $f foobar close $f file size $path(test1) } 7 test iocmd-1.8 {puts command} { set f [open $path(test1) w] fconfigure $f -translation lf -eofchar {} -encoding iso8859-1 puts -nonewline $f [binary format a4a5 foo bar] close $f file size $path(test1) } 9 test iocmd-2.1 {flush command} { list [catch {flush} msg] $msg } {1 {wrong # args: should be "flush channelId"}} test iocmd-2.2 {flush command} { list [catch {flush a b c d e} msg] $msg } {1 {wrong # args: should be "flush channelId"}} test iocmd-2.3 {flush command} { list [catch {flush foo} msg] $msg } {1 {can not find channel named "foo"}} test iocmd-2.4 {flush command} { list [catch {flush stdin} msg] $msg } {1 {channel "stdin" wasn't opened for writing}} test iocmd-3.1 {gets command} { list [catch {gets} msg] $msg } {1 {wrong # args: should be "gets channelId ?varName?"}} test iocmd-3.2 {gets command} { list [catch {gets a b c d e f g} msg] $msg } {1 {wrong # args: should be "gets channelId ?varName?"}} test iocmd-3.3 {gets command} { list [catch {gets aaa} msg] $msg } {1 {can not find channel named "aaa"}} test iocmd-3.4 {gets command} { list [catch {gets stdout} msg] $msg } {1 {channel "stdout" wasn't opened for reading}} test iocmd-3.5 {gets command} { set f [open $path(test1) w] puts $f [binary format a4a5 foo bar] close $f set f [open $path(test1) r] set result [gets $f] close $f set x foo\x00 set x "${x}bar\x00\x00" string compare $x $result } 0 test iocmd-4.1 {read command} { list [catch {read} msg] $msg } {1 {wrong # args: should be "read channelId ?numChars?" or "read ?-nonewline? channelId"}} test iocmd-4.2 {read command} { list [catch {read a b c d e f g h} msg] $msg } {1 {wrong # args: should be "read channelId ?numChars?" or "read ?-nonewline? channelId"}} test iocmd-4.3 {read command} { list [catch {read aaa} msg] $msg } {1 {can not find channel named "aaa"}} test iocmd-4.4 {read command} { list [catch {read -nonewline} msg] $msg } {1 {wrong # args: should be "read channelId ?numChars?" or "read ?-nonewline? channelId"}} test iocmd-4.5 {read command} { list [catch {read -nonew file4} msg] $msg $errorCode } {1 {can not find channel named "-nonew"} NONE} test iocmd-4.6 {read command} { list [catch {read stdout} msg] $msg } {1 {channel "stdout" wasn't opened for reading}} test iocmd-4.7 {read command} { list [catch {read -nonewline stdout} msg] $msg } {1 {channel "stdout" wasn't opened for reading}} test iocmd-4.8 {read command with incorrect combination of arguments} { file delete $path(test1) set f [open $path(test1) w] puts $f "Two lines: this one" puts $f "and this one" close $f set f [open $path(test1)] set x [list [catch {read -nonewline $f 20 z} msg] $msg $errorCode] close $f set x } {1 {wrong # args: should be "read channelId ?numChars?" or "read ?-nonewline? channelId"} NONE} test iocmd-4.9 {read command} { list [catch {read stdin foo} msg] $msg $errorCode } {1 {bad argument "foo": should be "nonewline"} NONE} test iocmd-4.10 {read command} { list [catch {read file107} msg] $msg $errorCode } {1 {can not find channel named "file107"} NONE} set path(test3) [makeFile {} test3] test iocmd-4.11 {read command} { set f [open $path(test3) w] set x [list [catch {read $f} msg] $msg $errorCode] close $f string compare [string tolower $x] \ [list 1 [format "channel \"%s\" wasn't opened for reading" $f] none] } 0 test iocmd-4.12 {read command} { set f [open $path(test1)] set x [list [catch {read $f 12z} msg] $msg $errorCode] close $f set x } {1 {expected integer but got "12z"} NONE} test iocmd-5.1 {seek command} { list [catch {seek} msg] $msg } {1 {wrong # args: should be "seek channelId offset ?origin?"}} test iocmd-5.2 {seek command} { list [catch {seek a b c d e f g} msg] $msg } {1 {wrong # args: should be "seek channelId offset ?origin?"}} test iocmd-5.3 {seek command} { list [catch {seek stdin gugu} msg] $msg } {1 {expected integer but got "gugu"}} test iocmd-5.4 {seek command} { list [catch {seek stdin 100 gugu} msg] $msg } {1 {bad origin "gugu": must be start, current, or end}} test iocmd-6.1 {tell command} { list [catch {tell} msg] $msg } {1 {wrong # args: should be "tell channelId"}} test iocmd-6.2 {tell command} { list [catch {tell a b c d e} msg] $msg } {1 {wrong # args: should be "tell channelId"}} test iocmd-6.3 {tell command} { list [catch {tell aaa} msg] $msg } {1 {can not find channel named "aaa"}} test iocmd-7.1 {close command} { list [catch {close} msg] $msg } {1 {wrong # args: should be "close channelId"}} test iocmd-7.2 {close command} { list [catch {close a b c d e} msg] $msg } {1 {wrong # args: should be "close channelId"}} test iocmd-7.3 {close command} { list [catch {close aaa} msg] $msg } {1 {can not find channel named "aaa"}} test iocmd-8.1 {fconfigure command} { list [catch {fconfigure} msg] $msg } {1 {wrong # args: should be "fconfigure channelId ?optionName? ?value? ?optionName value?..."}} test iocmd-8.2 {fconfigure command} { list [catch {fconfigure a b c d e f} msg] $msg } {1 {wrong # args: should be "fconfigure channelId ?optionName? ?value? ?optionName value?..."}} test iocmd-8.3 {fconfigure command} { list [catch {fconfigure a b} msg] $msg } {1 {can not find channel named "a"}} test iocmd-8.4 {fconfigure command} { file delete $path(test1) set f1 [open $path(test1) w] set x [list [catch {fconfigure $f1 froboz} msg] $msg] close $f1 set x } {1 {bad option "froboz": should be one of -blocking, -buffering, -buffersize, -encoding, -eofchar, or -translation}} test iocmd-8.5 {fconfigure command} { list [catch {fconfigure stdin -buffering froboz} msg] $msg } {1 {bad value for -buffering: must be one of full, line, or none}} test iocmd-8.6 {fconfigure command} { list [catch {fconfigure stdin -translation froboz} msg] $msg } {1 {bad value for -translation: must be one of auto, binary, cr, lf, crlf, or platform}} test iocmd-8.7 {fconfigure command} { file delete $path(test1) set f1 [open $path(test1) w] fconfigure $f1 -translation lf -eofchar {} -encoding unicode set x [fconfigure $f1] close $f1 set x } {-blocking 1 -buffering full -buffersize 4096 -encoding unicode -eofchar {} -translation lf} test iocmd-8.8 {fconfigure command} { file delete $path(test1) set f1 [open $path(test1) w] fconfigure $f1 -translation lf -buffering line -buffersize 3030 \ -eofchar {} -encoding unicode set x "" lappend x [fconfigure $f1 -buffering] lappend x [fconfigure $f1] close $f1 set x } {line {-blocking 1 -buffering line -buffersize 3030 -encoding unicode -eofchar {} -translation lf}} test iocmd-8.9 {fconfigure command} { file delete $path(test1) set f1 [open $path(test1) w] fconfigure $f1 -translation binary -buffering none -buffersize 4040 \ -eofchar {} -encoding binary set x [fconfigure $f1] close $f1 set x } {-blocking 1 -buffering none -buffersize 4040 -encoding binary -eofchar {} -translation lf} test iocmd-8.10 {fconfigure command} { list [catch {fconfigure a b} msg] $msg } {1 {can not find channel named "a"}} set path(fconfigure.dummy) [makeFile {} fconfigure.dummy] test iocmd-8.11 {fconfigure command} { set chan [open $path(fconfigure.dummy) r] set res [list [catch {fconfigure $chan -froboz blarfo} msg] $msg] close $chan set res } {1 {bad option "-froboz": should be one of -blocking, -buffering, -buffersize, -encoding, -eofchar, or -translation}} test iocmd-8.12 {fconfigure command} { set chan [open $path(fconfigure.dummy) r] set res [list [catch {fconfigure $chan -b blarfo} msg] $msg] close $chan set res } {1 {bad option "-b": should be one of -blocking, -buffering, -buffersize, -encoding, -eofchar, or -translation}} test iocmd-8.13 {fconfigure command} { set chan [open $path(fconfigure.dummy) r] set res [list [catch {fconfigure $chan -buffer blarfo} msg] $msg] close $chan set res } {1 {bad option "-buffer": should be one of -blocking, -buffering, -buffersize, -encoding, -eofchar, or -translation}} removeFile fconfigure.dummy test iocmd-8.14 {fconfigure command} { fconfigure stdin -buffers } 4096 proc iocmdSSETUP {} { uplevel { set srv [socket -server iocmdSRV 0] set port [lindex [fconfigure $srv -sockname] 2] proc iocmdSRV {sock ip port} {close $sock} set cli [socket 127.0.0.1 $port] } } proc iocmdSSHTDWN {} { uplevel { close $cli close $srv unset cli srv port rename iocmdSRV {} } } test iocmd-8.15.0 {fconfigure command / tcp channel} {socket macOnly} { iocmdSSETUP set r [list [catch {fconfigure $cli -blah} msg] $msg] iocmdSSHTDWN set r } {1 {bad option "-blah": should be one of -blocking, -buffering, -buffersize, -encoding, -eofchar, -translation, -error, -peername, or -sockname}} test iocmd-8.15.1 {fconfigure command / tcp channel} {socket unixOrPc} { iocmdSSETUP set r [list [catch {fconfigure $cli -blah} msg] $msg] iocmdSSHTDWN set r } {1 {bad option "-blah": should be one of -blocking, -buffering, -buffersize, -encoding, -eofchar, -translation, -peername, or -sockname}} test iocmd-8.16 {fconfigure command / tcp channel} {socket} { iocmdSSETUP set r [expr [lindex [fconfigure $cli -peername] 2]==$port] iocmdSSHTDWN set r } 1 test iocmd-8.17 {fconfigure command / tcp channel} {nonPortable} { # It is possible that you don't get the connection reset by peer # error but rather a valid answer. depends of the tcp implementation iocmdSSETUP update; puts $cli "blah"; flush $cli; # that flush could/should fail too update; set r [catch {fconfigure $cli -peername} msg] iocmdSSHTDWN regsub -all {can([^:])+: } $r {} r; set r } 1 test iocmd-8.18 {fconfigure command / unix tty channel} {nonPortable unixOnly} { # might fail if /dev/ttya is unavailable set tty [open /dev/ttya] set r [list [catch {fconfigure $tty -blah blih} msg] $msg]; close $tty; set r; } {1 {bad option "-blah": should be one of -blocking, -buffering, -buffersize, -encoding, -eofchar, -translation, or -mode}} test iocmd-8.19 {fconfigure command / win tty channel} {nonPortable pcOnly} { # might fail if com1 is unavailable set tty [open com1] set r [list [catch {fconfigure $tty -blah blih} msg] $msg]; close $tty; set r; } {1 {bad option "-blah": should be one of -blocking, -buffering, -buffersize, -encoding, -eofchar, -translation, -mode, or -pollinterval}} test iocmd-9.1 {eof command} { list [catch {eof} msg] $msg $errorCode } {1 {wrong # args: should be "eof channelId"} NONE} test iocmd-9.2 {eof command} { list [catch {eof a b} msg] $msg $errorCode } {1 {wrong # args: should be "eof channelId"} NONE} test iocmd-9.3 {eof command} { catch {close file100} list [catch {eof file100} msg] $msg $errorCode } {1 {can not find channel named "file100"} NONE} # The tests for Tcl_ExecObjCmd are in exec.test test iocmd-10.1 {fblocked command} { list [catch {fblocked} msg] $msg } {1 {wrong # args: should be "fblocked channelId"}} test iocmd-10.2 {fblocked command} { list [catch {fblocked a b c d e f g} msg] $msg } {1 {wrong # args: should be "fblocked channelId"}} test iocmd-10.3 {fblocked command} { list [catch {fblocked file1000} msg] $msg } {1 {can not find channel named "file1000"}} test iocmd-10.4 {fblocked command} { list [catch {fblocked stdout} msg] $msg } {1 {channel "stdout" wasn't opened for reading}} test iocmd-10.5 {fblocked command} { fblocked stdin } 0 set path(test4) [makeFile {} test4] set path(test5) [makeFile {} test5] file delete $path(test5) test iocmd-11.1 {I/O to command pipelines} {unixOrPc unixExecs} { set f [open $path(test4) w] close $f list [catch {open "| cat < $path(test4) > $path(test5)" w} msg] $msg $errorCode } {1 {can't write input to command: standard input was redirected} NONE} test iocmd-11.2 {I/O to command pipelines} {unixOrPc unixExecs} { list [catch {open "| echo > $path(test5)" r} msg] $msg $errorCode } {1 {can't read output from command: standard output was redirected} NONE} test iocmd-11.3 {I/O to command pipelines} {unixOrPc unixExecs} { list [catch {open "| echo > $path(test5)" r+} msg] $msg $errorCode } {1 {can't read output from command: standard output was redirected} NONE} test iocmd-12.1 {POSIX open access modes: RDONLY} { file delete $path(test1) set f [open $path(test1) w] puts $f "Two lines: this one" puts $f "and this one" close $f set f [open $path(test1) RDONLY] set x [list [gets $f] [catch {puts $f Test} msg] $msg] close $f string compare $x \ "{Two lines: this one} 1 [list [format "channel \"%s\" wasn't opened for writing" $f]]" } 0 test iocmd-12.2 {POSIX open access modes: RDONLY} -match regexp -body { file delete $path(test3) open $path(test3) RDONLY } -returnCodes error -result {(?i)couldn't open ".*test3": no such file or directory} test iocmd-12.3 {POSIX open access modes: WRONLY} -match regexp -body { file delete $path(test3) open $path(test3) WRONLY } -returnCodes error -result {(?i)couldn't open ".*test3": no such file or directory} # # Test 13.4 relies on assigning the same channel name twice. # test iocmd-12.4 {POSIX open access modes: WRONLY} {unixOnly} { file delete $path(test3) set f [open $path(test3) w] fconfigure $f -eofchar {} puts $f xyzzy close $f set f [open $path(test3) WRONLY] fconfigure $f -eofchar {} puts -nonewline $f "ab" seek $f 0 current set x [list [catch {gets $f} msg] $msg] close $f set f [open $path(test3) r] fconfigure $f -eofchar {} lappend x [gets $f] close $f set y [list 1 [format "channel \"%s\" wasn't opened for reading" $f] abzzy] string compare $x $y } 0 test iocmd-12.5 {POSIX open access modes: RDWR} -match regexp -body { file delete $path(test3) open $path(test3) RDWR } -returnCodes error -result {(?i)couldn't open ".*test3": no such file or directory} test iocmd-12.6 {POSIX open access modes: errors} { concat [catch {open $path(test3) "FOO \{BAR BAZ"} msg] $msg\n$errorInfo } "1 unmatched open brace in list unmatched open brace in list while processing open access modes \"FOO {BAR BAZ\" invoked from within \"open \$path(test3) \"FOO \\{BAR BAZ\"\"" test iocmd-12.7 {POSIX open access modes: errors} { list [catch {open $path(test3) {FOO BAR BAZ}} msg] $msg } {1 {invalid access mode "FOO": must be RDONLY, WRONLY, RDWR, APPEND, CREAT EXCL, NOCTTY, NONBLOCK, or TRUNC}} test iocmd-12.8 {POSIX open access modes: errors} { list [catch {open $path(test3) {TRUNC CREAT}} msg] $msg } {1 {access mode must include either RDONLY, WRONLY, or RDWR}} close [open $path(test3) w] test iocmd-13.1 {errors in open command} { list [catch {open} msg] $msg } {1 {wrong # args: should be "open fileName ?access? ?permissions?"}} test iocmd-13.2 {errors in open command} { list [catch {open a b c d} msg] $msg } {1 {wrong # args: should be "open fileName ?access? ?permissions?"}} test iocmd-13.3 {errors in open command} { list [catch {open $path(test1) x} msg] $msg } {1 {illegal access mode "x"}} test iocmd-13.4 {errors in open command} { list [catch {open $path(test1) rw} msg] $msg } {1 {illegal access mode "rw"}} test iocmd-13.5 {errors in open command} { list [catch {open $path(test1) r+1} msg] $msg } {1 {illegal access mode "r+1"}} test iocmd-13.6 {errors in open command} { set msg [list [catch {open _non_existent_} msg] $msg $errorCode] regsub [file join {} _non_existent_] $msg "_non_existent_" msg string tolower $msg } {1 {couldn't open "_non_existent_": no such file or directory} {posix enoent {no such file or directory}}} test iocmd-13.7.1 {open for append, a mode} -setup { set log [makeFile {} out] set chans {} } -body { foreach i { 0 1 2 3 4 5 6 7 8 9 } { puts [set ch [open $log a]] $i lappend chans $ch } foreach ch $chans {catch {close $ch}} lsort [split [string trim [viewFile out]] \n] } -cleanup { removeFile out # Ensure that channels are gone, even if body failed to do so foreach ch $chans {catch {close $ch}} } -result {0 1 2 3 4 5 6 7 8 9} test iocmd-13.7.2 {open for append, O_APPEND} -setup { set log [makeFile {} out] set chans {} } -body { foreach i { 0 1 2 3 4 5 6 7 8 9 } { puts [set ch [open $log {WRONLY CREAT APPEND}]] $i lappend chans $ch } foreach ch $chans {catch {close $ch}} lsort [split [string trim [viewFile out]] \n] } -cleanup { removeFile out # Ensure that channels are gone, even if body failed to do so foreach ch $chans {catch {close $ch}} } -result {0 1 2 3 4 5 6 7 8 9} test iocmd-14.1 {file id parsing errors} { list [catch {eof gorp} msg] $msg $errorCode } {1 {can not find channel named "gorp"} NONE} test iocmd-14.2 {file id parsing errors} { list [catch {eof filex} msg] $msg } {1 {can not find channel named "filex"}} test iocmd-14.3 {file id parsing errors} { list [catch {eof file12a} msg] $msg } {1 {can not find channel named "file12a"}} test iocmd-14.4 {file id parsing errors} { list [catch {eof file123} msg] $msg } {1 {can not find channel named "file123"}} test iocmd-14.5 {file id parsing errors} { list [catch {eof stdout} msg] $msg } {0 0} test iocmd-14.6 {file id parsing errors} { list [catch {eof stdin} msg] $msg } {0 0} test iocmd-14.7 {file id parsing errors} { list [catch {eof stdout} msg] $msg } {0 0} test iocmd-14.8 {file id parsing errors} { list [catch {eof stderr} msg] $msg } {0 0} test iocmd-14.9 {file id parsing errors} { list [catch {eof stderr1} msg] $msg } {1 {can not find channel named "stderr1"}} set f [open $path(test1) w] close $f set expect "1 {can not find channel named \"$f\"}" test iocmd-14.10 {file id parsing errors} { list [catch {eof $f} msg] $msg } $expect test iocmd-15.1 {Tcl_FcopyObjCmd} {fcopy} { list [catch {fcopy} msg] $msg } {1 {wrong # args: should be "fcopy input output ?-size size? ?-command callback?"}} test iocmd-15.2 {Tcl_FcopyObjCmd} {fcopy} { list [catch {fcopy 1} msg] $msg } {1 {wrong # args: should be "fcopy input output ?-size size? ?-command callback?"}} test iocmd-15.3 {Tcl_FcopyObjCmd} {fcopy} { list [catch {fcopy 1 2 3 4 5 6 7} msg] $msg } {1 {wrong # args: should be "fcopy input output ?-size size? ?-command callback?"}} test iocmd-15.4 {Tcl_FcopyObjCmd} {fcopy} { list [catch {fcopy 1 2 3} msg] $msg } {1 {wrong # args: should be "fcopy input output ?-size size? ?-command callback?"}} test iocmd-15.5 {Tcl_FcopyObjCmd} {fcopy} { list [catch {fcopy 1 2 3 4 5} msg] $msg } {1 {wrong # args: should be "fcopy input output ?-size size? ?-command callback?"}} set path(test2) [makeFile {} test2] set f [open $path(test1) w] close $f set rfile [open $path(test1) r] set wfile [open $path(test2) w] test iocmd-15.6 {Tcl_FcopyObjCmd} {fcopy} { list [catch {fcopy foo $wfile} msg] $msg } {1 {can not find channel named "foo"}} test iocmd-15.7 {Tcl_FcopyObjCmd} {fcopy} { list [catch {fcopy $rfile foo} msg] $msg } {1 {can not find channel named "foo"}} test iocmd-15.8 {Tcl_FcopyObjCmd} {fcopy} { list [catch {fcopy $wfile $wfile} msg] $msg } "1 {channel \"$wfile\" wasn't opened for reading}" test iocmd-15.9 {Tcl_FcopyObjCmd} {fcopy} { list [catch {fcopy $rfile $rfile} msg] $msg } "1 {channel \"$rfile\" wasn't opened for writing}" test iocmd-15.10 {Tcl_FcopyObjCmd} {fcopy} { list [catch {fcopy $rfile $wfile foo bar} msg] $msg } {1 {bad switch "foo": must be -size or -command}} test iocmd-15.11 {Tcl_FcopyObjCmd} {fcopy} { list [catch {fcopy $rfile $wfile -size foo} msg] $msg } {1 {expected integer but got "foo"}} test iocmd-15.12 {Tcl_FcopyObjCmd} {fcopy} { list [catch {fcopy $rfile $wfile -command bar -size foo} msg] $msg } {1 {expected integer but got "foo"}} close $rfile close $wfile # cleanup foreach file [list test1 test2 test3 test4] { removeFile $file } # delay long enough for background processes to finish after 500 foreach file [list test5] { removeFile $file } cleanupTests return tcl8.4.20/tests/namespace.test0000644003604700454610000015073112133546540014716 0ustar dgp771div# Functionality covered: this file contains a collection of tests for the # procedures in tclNamesp.c that implement Tcl's basic support for # namespaces. Other namespace-related tests appear in variable.test. # # Sourcing this file into Tcl runs the tests and generates output for # errors. No output means no errors were found. # # Copyright (c) 1997 Sun Microsystems, Inc. # Copyright (c) 1998-2000 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import -force ::tcltest::* } # Clear out any namespaces called test_ns_* catch {eval namespace delete [namespace children :: test_ns_*]} test namespace-1.1 {TclInitNamespaces, GetNamespaceFromObj, NamespaceChildrenCmd} { namespace children :: test_ns_* } {} catch {unset l} test namespace-2.1 {Tcl_GetCurrentNamespace} { list [namespace current] [namespace eval {} {namespace current}] \ [namespace eval {} {namespace current}] } {:: :: ::} test namespace-2.2 {Tcl_GetCurrentNamespace} { set l {} lappend l [namespace current] namespace eval test_ns_1 { lappend l [namespace current] namespace eval foo { lappend l [namespace current] } } lappend l [namespace current] set l } {:: ::test_ns_1 ::test_ns_1::foo ::} test namespace-3.1 {Tcl_GetGlobalNamespace} { namespace eval test_ns_1 {namespace eval foo {namespace eval bar {} } } # namespace children uses Tcl_GetGlobalNamespace namespace eval test_ns_1 {namespace children foo b*} } {::test_ns_1::foo::bar} test namespace-4.1 {Tcl_PushCallFrame with isProcCallFrame=1} { namespace eval test_ns_1 { variable v 123 proc p {} { variable v return $v } } test_ns_1::p ;# does Tcl_PushCallFrame to push p's namespace } {123} test namespace-4.2 {Tcl_PushCallFrame with isProcCallFrame=0} { namespace eval test_ns_1::baz {} ;# does Tcl_PushCallFrame to create baz proc test_ns_1::baz::p {} { variable v set v 789 set v} test_ns_1::baz::p } {789} test namespace-5.1 {Tcl_PopCallFrame, no vars} { namespace eval test_ns_1::blodge {} ;# pushes then pops frame } {} test namespace-5.2 {Tcl_PopCallFrame, local vars must be deleted} { proc test_ns_1::r {} { set a 123 } test_ns_1::r ;# pushes then pop's r's frame } {123} test namespace-6.1 {Tcl_CreateNamespace} { catch {eval namespace delete [namespace children :: test_ns_*]} list [lsort [namespace children :: test_ns_*]] \ [namespace eval test_ns_1 {namespace current}] \ [namespace eval test_ns_2 {namespace current}] \ [namespace eval ::test_ns_3 {namespace current}] \ [namespace eval ::test_ns_4 \ {namespace eval foo {namespace current}}] \ [namespace eval ::test_ns_5 \ {namespace eval ::test_ns_6 {namespace current}}] \ [lsort [namespace children :: test_ns_*]] } {{} ::test_ns_1 ::test_ns_2 ::test_ns_3 ::test_ns_4::foo ::test_ns_6 {::test_ns_1 ::test_ns_2 ::test_ns_3 ::test_ns_4 ::test_ns_5 ::test_ns_6}} test namespace-6.2 {Tcl_CreateNamespace, odd number of :'s in name is okay} { list [namespace eval :::test_ns_1::::foo {namespace current}] \ [namespace eval test_ns_2:::::foo {namespace current}] } {::test_ns_1::foo ::test_ns_2::foo} test namespace-6.3 {Tcl_CreateNamespace, trailing ::s in ns name are ignored} { list [catch {namespace eval test_ns_7::: {namespace current}} msg] $msg } {0 ::test_ns_7} test namespace-6.4 {Tcl_CreateNamespace, trailing ::s in ns name are ignored} { catch {eval namespace delete [namespace children :: test_ns_*]} namespace eval test_ns_1:: { namespace eval test_ns_2:: {} namespace eval test_ns_3:: {} } lsort [namespace children ::test_ns_1] } [lsort {::test_ns_1::test_ns_2 ::test_ns_1::test_ns_3}] test namespace-6.5 {Tcl_CreateNamespace, relative ns names now only looked up in current ns} { set trigger { namespace eval test_ns_2 {namespace current} } set l {} lappend l [namespace eval test_ns_1 $trigger] namespace eval test_ns_1::test_ns_2 {} lappend l [namespace eval test_ns_1 $trigger] } {::test_ns_1::test_ns_2 ::test_ns_1::test_ns_2} test namespace-7.1 {Tcl_DeleteNamespace, active call frames in ns} { catch {eval namespace delete [namespace children :: test_ns_*]} namespace eval test_ns_1 { proc p {} { namespace delete [namespace current] return [namespace current] } } list [test_ns_1::p] [catch {test_ns_1::p} msg] $msg } {::test_ns_1 1 {invalid command name "test_ns_1::p"}} test namespace-7.2 {Tcl_DeleteNamespace, no active call frames in ns} { namespace eval test_ns_2 { proc p {} { return [namespace current] } } list [test_ns_2::p] [namespace delete test_ns_2] } {::test_ns_2 {}} test namespace-7.3 {recursive Tcl_DeleteNamespace, active call frames in ns} { # [Bug 1355942] namespace eval test_ns_2 { set x 1 trace add variable x unset "namespace delete [namespace current];#" namespace delete [namespace current] } } {} test namespace-7.4 {recursive Tcl_DeleteNamespace, active call frames in ns} { # [Bug 1355942] namespace eval test_ns_2 { proc x {} {} trace add command x delete "namespace delete [namespace current];#" namespace delete [namespace current] } } {} test namespace-7.5 {recursive Tcl_DeleteNamespace, no active call frames in ns} { # [Bug 1355942] namespace eval test_ns_2 { set x 1 trace add variable x unset "namespace delete [namespace current];#" } namespace delete test_ns_2 } {} test namespace-7.6 {recursive Tcl_DeleteNamespace, no active call frames in ns} { # [Bug 1355942] namespace eval test_ns_2 { proc x {} {} trace add command x delete "namespace delete [namespace current];#" } namespace delete test_ns_2 } {} test namespace-8.1 {TclTeardownNamespace, delete global namespace} { catch {interp delete test_interp} interp create test_interp interp eval test_interp { namespace eval test_ns_1 { namespace export p proc p {} { return [namespace current] } } namespace eval test_ns_2 { namespace import ::test_ns_1::p variable v 27 proc q {} { variable v return "[p] $v" } } set x [test_ns_2::q] catch {set xxxx} } list [interp eval test_interp {test_ns_2::q}] \ [interp eval test_interp {namespace delete ::}] \ [catch {interp eval test_interp {set a 123}} msg] $msg \ [interp delete test_interp] } {{::test_ns_1 27} {} 1 {invalid command name "set"} {}} test namespace-8.2 {TclTeardownNamespace, remove deleted ns from parent} { catch {eval namespace delete [namespace children :: test_ns_*]} namespace eval test_ns_1::test_ns_2::test_ns_3a {proc p {} {}} namespace eval test_ns_1::test_ns_2::test_ns_3b {proc q {} {}} list [namespace children test_ns_1] \ [namespace delete test_ns_1::test_ns_2] \ [namespace children test_ns_1] } {::test_ns_1::test_ns_2 {} {}} test namespace-8.3 {TclTeardownNamespace, delete child namespaces} { catch {eval namespace delete [namespace children :: test_ns_*]} namespace eval test_ns_1::test_ns_2::test_ns_3a {proc p {} {}} namespace eval test_ns_1::test_ns_2::test_ns_3b {proc q {} {}} list [namespace children test_ns_1] \ [namespace delete test_ns_1::test_ns_2] \ [namespace children test_ns_1] \ [catch {namespace children test_ns_1::test_ns_2} msg] $msg \ [info commands test_ns_1::test_ns_2::test_ns_3a::*] } {::test_ns_1::test_ns_2 {} {} 1 {unknown namespace "test_ns_1::test_ns_2" in namespace children command} {}} test namespace-8.4 {TclTeardownNamespace, cmds imported from deleted ns go away} { catch {eval namespace delete [namespace children :: test_ns_*]} namespace eval test_ns_export { namespace export cmd1 cmd2 proc cmd1 {args} {return "cmd1: $args"} proc cmd2 {args} {return "cmd2: $args"} } namespace eval test_ns_import { namespace import ::test_ns_export::* proc p {} {return foo} } list [lsort [info commands test_ns_import::*]] \ [namespace delete test_ns_export] \ [info commands test_ns_import::*] } [list [lsort {::test_ns_import::p ::test_ns_import::cmd1 ::test_ns_import::cmd2}] {} ::test_ns_import::p] test namespace-8.5 {TclTeardownNamespace: preserve errorInfo; errorCode values} { interp create slave slave eval {trace add execution error leave {namespace delete :: ;#}} catch {slave eval error foo bar baz} interp delete slave set ::errorInfo } {bar invoked from within "slave eval error foo bar baz"} test namespace-8.6 {TclTeardownNamespace: preserve errorInfo; errorCode values} { interp create slave slave eval {trace add variable errorCode write {namespace delete :: ;#}} catch {slave eval error foo bar baz} interp delete slave set ::errorInfo } {bar invoked from within "slave eval error foo bar baz"} test namespace-8.7 {TclTeardownNamespace: preserve errorInfo; errorCode values} { interp create slave slave eval {trace add execution error leave {namespace delete :: ;#}} catch {slave eval error foo bar baz} interp delete slave set ::errorCode } baz test namespace-9.1 {Tcl_Import, empty import pattern} { catch {eval namespace delete [namespace children :: test_ns_*]} list [catch {namespace eval test_ns_import {namespace import {}}} msg] $msg } {1 {empty import pattern}} test namespace-9.2 {Tcl_Import, unknown namespace in import pattern} { list [catch {namespace eval test_ns_import {namespace import fred::x}} msg] $msg } {1 {unknown namespace in import pattern "fred::x"}} test namespace-9.3 {Tcl_Import, import ns == export ns} { list [catch {namespace eval test_ns_import {namespace import ::test_ns_import::puts}} msg] $msg } {1 {import pattern "::test_ns_import::puts" tries to import from namespace "test_ns_import" into itself}} test namespace-9.4 {Tcl_Import, simple import} { catch {eval namespace delete [namespace children :: test_ns_*]} namespace eval test_ns_export { namespace export cmd1 proc cmd1 {args} {return "cmd1: $args"} proc cmd2 {args} {return "cmd2: $args"} } namespace eval test_ns_import { namespace import ::test_ns_export::* proc p {} {return [cmd1 123]} } test_ns_import::p } {cmd1: 123} test namespace-9.5 {Tcl_Import, can't redefine cmd unless allowOverwrite!=0} { list [catch {namespace eval test_ns_import {namespace import ::test_ns_export::*}} msg] $msg } {0 {}} test namespace-9.6 {Tcl_Import, cmd redefinition ok if allowOverwrite!=0} { namespace eval test_ns_import { namespace import -force ::test_ns_export::* cmd1 555 } } {cmd1: 555} test namespace-9.7 {Tcl_Import, links are preserved if cmd is redefined} { catch {eval namespace delete [namespace children :: test_ns_*]} namespace eval test_ns_export { namespace export cmd1 proc cmd1 {args} {return "cmd1: $args"} } namespace eval test_ns_import { namespace import -force ::test_ns_export::* } list [test_ns_import::cmd1 a b c] \ [test_ns_export::cmd1 d e f] \ [proc test_ns_export::cmd1 {args} {return "new1: $args"}] \ [namespace origin test_ns_import::cmd1] \ [namespace origin test_ns_export::cmd1] \ [test_ns_import::cmd1 g h i] \ [test_ns_export::cmd1 j k l] } {{cmd1: a b c} {cmd1: d e f} {} ::test_ns_export::cmd1 ::test_ns_export::cmd1 {new1: g h i} {new1: j k l}} test namespace-9.8 {Tcl_Import: Bug 1017299} -setup { namespace eval one { namespace export cmd proc cmd {} {} } namespace eval two { namespace export cmd proc other args {} } namespace eval two \ [list namespace import [namespace current]::one::cmd] namespace eval three \ [list namespace import [namespace current]::two::cmd] namespace eval three { rename cmd other namespace export other } } -body { namespace eval two [list namespace import -force \ [namespace current]::three::other] namespace origin two::other } -cleanup { namespace delete one two three } -match glob -result *::one::cmd test namespace-9.9 {Tcl_Import: Bug 1017299} -setup { namespace eval one { namespace export cmd proc cmd {} {} } namespace eval two namespace export cmd namespace eval two \ [list namespace import [namespace current]::one::cmd] namespace eval three namespace export cmd namespace eval three \ [list namespace import [namespace current]::two::cmd] } -body { namespace eval two [list namespace import -force \ [namespace current]::three::cmd] namespace origin two::cmd } -cleanup { namespace delete one two three } -returnCodes error -match glob -result {import pattern * would create a loop*} test namespace-10.1 {Tcl_ForgetImport, check for valid namespaces} { catch {eval namespace delete [namespace children :: test_ns_*]} list [catch {namespace forget xyzzy::*} msg] $msg } {1 {unknown namespace in namespace forget pattern "xyzzy::*"}} test namespace-10.2 {Tcl_ForgetImport, ignores patterns that don't match} { namespace eval test_ns_export { namespace export cmd1 proc cmd1 {args} {return "cmd1: $args"} proc cmd2 {args} {return "cmd2: $args"} } namespace eval test_ns_import { namespace forget ::test_ns_export::wombat } } {} test namespace-10.3 {Tcl_ForgetImport, deletes matching imported cmds} { namespace eval test_ns_import { namespace import ::test_ns_export::* proc p {} {return [cmd1 123]} set l {} lappend l [lsort [info commands ::test_ns_import::*]] namespace forget ::test_ns_export::cmd1 lappend l [info commands ::test_ns_import::*] lappend l [catch {cmd1 777} msg] $msg } } [list [lsort {::test_ns_import::p ::test_ns_import::cmd1}] ::test_ns_import::p 1 {invalid command name "cmd1"}] test namespace-10.4 {Tcl_ForgetImport: Bug 560297} -setup { namespace eval origin { namespace export cmd proc cmd {} {} } namespace eval unrelated { proc cmd {} {} } namespace eval my \ [list namespace import [namespace current]::origin::cmd] } -body { namespace eval my \ [list namespace forget [namespace current]::unrelated::cmd] my::cmd } -cleanup { namespace delete origin unrelated my } test namespace-10.5 {Tcl_ForgetImport: Bug 560297} -setup { namespace eval origin { namespace export cmd proc cmd {} {} } namespace eval my \ [list namespace import [namespace current]::origin::cmd] namespace eval my rename cmd newname } -body { namespace eval my \ [list namespace forget [namespace current]::origin::cmd] my::newname } -cleanup { namespace delete origin my } -returnCodes error -match glob -result * test namespace-10.6 {Tcl_ForgetImport: Bug 560297} -setup { namespace eval origin { namespace export cmd proc cmd {} {} } namespace eval my \ [list namespace import [namespace current]::origin::cmd] namespace eval your {} namespace eval my \ [list rename cmd [namespace current]::your::newname] } -body { namespace eval your namespace forget newname your::newname } -cleanup { namespace delete origin my your } -returnCodes error -match glob -result * test namespace-10.7 {Tcl_ForgetImport: Bug 560297} -setup { namespace eval origin { namespace export cmd proc cmd {} {} } namespace eval link namespace export cmd namespace eval link \ [list namespace import [namespace current]::origin::cmd] namespace eval link2 namespace export cmd namespace eval link2 \ [list namespace import [namespace current]::link::cmd] namespace eval my \ [list namespace import [namespace current]::link2::cmd] } -body { namespace eval my \ [list namespace forget [namespace current]::origin::cmd] my::cmd } -cleanup { namespace delete origin link link2 my } -returnCodes error -match glob -result * test namespace-10.8 {Tcl_ForgetImport: Bug 560297} -setup { namespace eval origin { namespace export cmd proc cmd {} {} } namespace eval link namespace export cmd namespace eval link \ [list namespace import [namespace current]::origin::cmd] namespace eval link2 namespace export cmd namespace eval link2 \ [list namespace import [namespace current]::link::cmd] namespace eval my \ [list namespace import [namespace current]::link2::cmd] } -body { namespace eval my \ [list namespace forget [namespace current]::link::cmd] my::cmd } -cleanup { namespace delete origin link link2 my } test namespace-10.9 {Tcl_ForgetImport: Bug 560297} -setup { namespace eval origin { namespace export cmd proc cmd {} {} } namespace eval link namespace export cmd namespace eval link \ [list namespace import [namespace current]::origin::cmd] namespace eval link2 namespace export cmd namespace eval link2 \ [list namespace import [namespace current]::link::cmd] namespace eval my \ [list namespace import [namespace current]::link2::cmd] } -body { namespace eval my \ [list namespace forget [namespace current]::link2::cmd] my::cmd } -cleanup { namespace delete origin link link2 my } -returnCodes error -match glob -result * test namespace-11.1 {TclGetOriginalCommand, check if not imported cmd} { catch {eval namespace delete [namespace children :: test_ns_*]} namespace eval test_ns_export { namespace export cmd1 proc cmd1 {args} {return "cmd1: $args"} } list [namespace origin set] [namespace origin test_ns_export::cmd1] } {::set ::test_ns_export::cmd1} test namespace-11.2 {TclGetOriginalCommand, directly imported cmd} { namespace eval test_ns_import1 { namespace import ::test_ns_export::* namespace export * proc p {} {namespace origin cmd1} } list [test_ns_import1::p] [namespace origin test_ns_import1::cmd1] } {::test_ns_export::cmd1 ::test_ns_export::cmd1} test namespace-11.3 {TclGetOriginalCommand, indirectly imported cmd} { namespace eval test_ns_import2 { namespace import ::test_ns_import1::* proc q {} {return [cmd1 123]} } list [test_ns_import2::q] [namespace origin test_ns_import2::cmd1] } {{cmd1: 123} ::test_ns_export::cmd1} test namespace-12.1 {InvokeImportedCmd} { catch {eval namespace delete [namespace children :: test_ns_*]} namespace eval test_ns_export { namespace export cmd1 proc cmd1 {args} {namespace current} } namespace eval test_ns_import { namespace import ::test_ns_export::* } list [test_ns_import::cmd1] } {::test_ns_export} test namespace-13.1 {DeleteImportedCmd, deletes imported cmds} { namespace eval test_ns_import { set l {} lappend l [info commands ::test_ns_import::*] namespace forget ::test_ns_export::cmd1 lappend l [info commands ::test_ns_import::*] } } {::test_ns_import::cmd1 {}} test namespace-14.1 {TclGetNamespaceForQualName, absolute names} { catch {eval namespace delete [namespace children :: test_ns_*]} variable v 10 namespace eval test_ns_1::test_ns_2 { variable v 20 } namespace eval test_ns_2 { variable v 30 } namespace eval test_ns_1 { list $::v $::test_ns_2::v $::test_ns_1::test_ns_2::v \ [lsort [namespace children :: test_ns_*]] } } [list 10 30 20 [lsort {::test_ns_1 ::test_ns_2}]] test namespace-14.2 {TclGetNamespaceForQualName, invalid absolute names} { namespace eval test_ns_1 { list [catch {set ::test_ns_777::v} msg] $msg \ [catch {namespace children test_ns_777} msg] $msg } } {1 {can't read "::test_ns_777::v": no such variable} 1 {unknown namespace "test_ns_777" in namespace children command}} test namespace-14.3 {TclGetNamespaceForQualName, relative names} { namespace eval test_ns_1 { list $v $test_ns_2::v } } {10 20} test namespace-14.4 {TclGetNamespaceForQualName, relative ns names looked up only in current ns} { namespace eval test_ns_1::test_ns_2 { namespace eval foo {} } namespace eval test_ns_1 { list [namespace children test_ns_2] \ [catch {namespace children test_ns_1} msg] $msg } } {::test_ns_1::test_ns_2::foo 1 {unknown namespace "test_ns_1" in namespace children command}} test namespace-14.5 {TclGetNamespaceForQualName, relative ns names looked up only in current ns} { namespace eval ::test_ns_2 { namespace eval bar {} } namespace eval test_ns_1 { set l [list [catch {namespace delete test_ns_2::bar} msg] $msg] } set l } {1 {unknown namespace "test_ns_2::bar" in namespace delete command}} test namespace-14.6 {TclGetNamespaceForQualName, relative ns names looked up only in current ns} { namespace eval test_ns_1::test_ns_2 { namespace eval foo {} } namespace eval test_ns_1 { list [namespace children test_ns_2] \ [catch {namespace children test_ns_1} msg] $msg } } {::test_ns_1::test_ns_2::foo 1 {unknown namespace "test_ns_1" in namespace children command}} test namespace-14.7 {TclGetNamespaceForQualName, ignore extra :s if ns} { namespace children test_ns_1::: } {::test_ns_1::test_ns_2} test namespace-14.8 {TclGetNamespaceForQualName, ignore extra :s if ns} { namespace children :::test_ns_1:::::test_ns_2::: } {::test_ns_1::test_ns_2::foo} test namespace-14.9 {TclGetNamespaceForQualName, extra ::s are significant for vars} { set l {} lappend l [catch {set test_ns_1::test_ns_2::} msg] $msg namespace eval test_ns_1::test_ns_2 {variable {} 2525} lappend l [set test_ns_1::test_ns_2::] } {1 {can't read "test_ns_1::test_ns_2::": no such variable} 2525} test namespace-14.10 {TclGetNamespaceForQualName, extra ::s are significant for vars} { catch {unset test_ns_1::test_ns_2::} set l {} lappend l [catch {set test_ns_1::test_ns_2::} msg] $msg set test_ns_1::test_ns_2:: 314159 lappend l [set test_ns_1::test_ns_2::] } {1 {can't read "test_ns_1::test_ns_2::": no such variable} 314159} test namespace-14.11 {TclGetNamespaceForQualName, extra ::s are significant for commands} { catch {rename test_ns_1::test_ns_2:: {}} set l {} lappend l [catch {test_ns_1::test_ns_2:: hello} msg] $msg proc test_ns_1::test_ns_2:: {args} {return "\{\}: $args"} lappend l [test_ns_1::test_ns_2:: hello] } {1 {invalid command name "test_ns_1::test_ns_2::"} {{}: hello}} test namespace-14.12 {TclGetNamespaceForQualName, extra ::s are significant for vars} { catch {eval namespace delete [namespace children :: test_ns_*]} namespace eval test_ns_1 { variable {} set test_ns_1::(x) y } set test_ns_1::(x) } y test namespace-14.13 {TclGetNamespaceForQualName, namespace other than global ns can't have empty name} { catch {eval namespace delete [namespace children :: test_ns_*]} list [catch {namespace eval test_ns_1 {proc {} {} {}; namespace eval {} {}; {}}} msg] $msg } {1 {can't create namespace "": only global namespace can have empty name}} test namespace-15.1 {Tcl_FindNamespace, absolute name found} { catch {eval namespace delete [namespace children :: test_ns_*]} namespace eval test_ns_delete { namespace eval test_ns_delete2 {} proc cmd {args} {namespace current} } list [namespace delete ::test_ns_delete::test_ns_delete2] \ [namespace children ::test_ns_delete] } {{} {}} test namespace-15.2 {Tcl_FindNamespace, absolute name not found} { list [catch {namespace delete ::test_ns_delete::test_ns_delete2} msg] $msg } {1 {unknown namespace "::test_ns_delete::test_ns_delete2" in namespace delete command}} test namespace-15.3 {Tcl_FindNamespace, relative name found} { namespace eval test_ns_delete { namespace eval test_ns_delete2 {} namespace eval test_ns_delete3 {} list [namespace delete test_ns_delete2] \ [namespace children [namespace current]] } } {{} ::test_ns_delete::test_ns_delete3} test namespace-15.4 {Tcl_FindNamespace, relative name not found} { namespace eval test_ns_delete2 {} namespace eval test_ns_delete { list [catch {namespace delete test_ns_delete2} msg] $msg } } {1 {unknown namespace "test_ns_delete2" in namespace delete command}} test namespace-16.1 {Tcl_FindCommand, absolute name found} { catch {eval namespace delete [namespace children :: test_ns_*]} namespace eval test_ns_1 { proc cmd {args} {return "[namespace current]::cmd: $args"} variable v "::test_ns_1::cmd" eval $v one } } {::test_ns_1::cmd: one} test namespace-16.2 {Tcl_FindCommand, absolute name found} { eval $test_ns_1::v two } {::test_ns_1::cmd: two} test namespace-16.3 {Tcl_FindCommand, absolute name not found} { namespace eval test_ns_1 { variable v2 "::test_ns_1::ladidah" list [catch {eval $v2} msg] $msg } } {1 {invalid command name "::test_ns_1::ladidah"}} # save the "unknown" proc, which is redefined by the following two tests catch {rename unknown unknown.old} proc unknown {args} { return "unknown: $args" } test namespace-16.4 {Tcl_FindCommand, absolute name and TCL_GLOBAL_ONLY} { ::test_ns_1::foobar x y z } {unknown: ::test_ns_1::foobar x y z} test namespace-16.5 {Tcl_FindCommand, absolute name and TCL_GLOBAL_ONLY} { ::foobar 1 2 3 4 5 } {unknown: ::foobar 1 2 3 4 5} test namespace-16.6 {Tcl_FindCommand, relative name and TCL_GLOBAL_ONLY} { test_ns_1::foobar x y z } {unknown: test_ns_1::foobar x y z} test namespace-16.7 {Tcl_FindCommand, relative name and TCL_GLOBAL_ONLY} { foobar 1 2 3 4 5 } {unknown: foobar 1 2 3 4 5} # restore the "unknown" proc saved previously catch {rename unknown {}} catch {rename unknown.old unknown} test namespace-16.8 {Tcl_FindCommand, relative name found} { namespace eval test_ns_1 { cmd a b c } } {::test_ns_1::cmd: a b c} test namespace-16.9 {Tcl_FindCommand, relative name found} { catch {rename cmd2 {}} proc cmd2 {args} {return "[namespace current]::cmd2: $args"} namespace eval test_ns_1 { cmd2 a b c } } {::::cmd2: a b c} test namespace-16.10 {Tcl_FindCommand, relative name found, only look in current then global ns} { namespace eval test_ns_1 { proc cmd2 {args} { return "[namespace current]::cmd2 in test_ns_1: $args" } namespace eval test_ns_12 { cmd2 a b c } } } {::::cmd2: a b c} test namespace-16.11 {Tcl_FindCommand, relative name not found} { namespace eval test_ns_1 { list [catch {cmd3 a b c} msg] $msg } } {1 {invalid command name "cmd3"}} catch {unset x} test namespace-17.1 {Tcl_FindNamespaceVar, absolute name found} { catch {eval namespace delete [namespace children :: test_ns_*]} set x 314159 namespace eval test_ns_1 { set ::x } } {314159} test namespace-17.2 {Tcl_FindNamespaceVar, absolute name found} { namespace eval test_ns_1 { variable x 777 set ::test_ns_1::x } } {777} test namespace-17.3 {Tcl_FindNamespaceVar, absolute name found} { namespace eval test_ns_1 { namespace eval test_ns_2 { variable x 1111 } set ::test_ns_1::test_ns_2::x } } {1111} test namespace-17.4 {Tcl_FindNamespaceVar, absolute name not found} { namespace eval test_ns_1 { namespace eval test_ns_2 { variable x 1111 } list [catch {set ::test_ns_1::test_ns_2::y} msg] $msg } } {1 {can't read "::test_ns_1::test_ns_2::y": no such variable}} test namespace-17.5 {Tcl_FindNamespaceVar, absolute name and TCL_GLOBAL_ONLY} { namespace eval test_ns_1 { namespace eval test_ns_3 { variable ::test_ns_1::test_ns_2::x 2222 } } set ::test_ns_1::test_ns_2::x } {2222} test namespace-17.6 {Tcl_FindNamespaceVar, relative name found} { namespace eval test_ns_1 { set x } } {777} test namespace-17.7 {Tcl_FindNamespaceVar, relative name found} { namespace eval test_ns_1 { unset x set x ;# must be global x now } } {314159} test namespace-17.8 {Tcl_FindNamespaceVar, relative name not found} { namespace eval test_ns_1 { list [catch {set wuzzat} msg] $msg } } {1 {can't read "wuzzat": no such variable}} test namespace-17.9 {Tcl_FindNamespaceVar, relative name and TCL_GLOBAL_ONLY} { namespace eval test_ns_1 { variable a hello } set test_ns_1::a } {hello} catch {unset x} catch {unset l} catch {rename foo {}} test namespace-18.1 {TclResetShadowedCmdRefs, one-level check for command shadowing} { catch {eval namespace delete [namespace children :: test_ns_*]} proc foo {} {return "global foo"} namespace eval test_ns_1 { proc trigger {} { return [foo] } } set l "" lappend l [test_ns_1::trigger] namespace eval test_ns_1 { # force invalidation of cached ref to "foo" in proc trigger proc foo {} {return "foo in test_ns_1"} } lappend l [test_ns_1::trigger] set l } {{global foo} {foo in test_ns_1}} test namespace-18.2 {TclResetShadowedCmdRefs, multilevel check for command shadowing} { namespace eval test_ns_2 { proc foo {} {return "foo in ::test_ns_2"} } namespace eval test_ns_1 { namespace eval test_ns_2 {} proc trigger {} { return [test_ns_2::foo] } } set l "" lappend l [test_ns_1::trigger] namespace eval test_ns_1 { namespace eval test_ns_2 { # force invalidation of cached ref to "foo" in proc trigger proc foo {} {return "foo in ::test_ns_1::test_ns_2"} } } lappend l [test_ns_1::trigger] set l } {{foo in ::test_ns_2} {foo in ::test_ns_1::test_ns_2}} catch {unset l} catch {rename foo {}} test namespace-19.1 {GetNamespaceFromObj, global name found} { catch {eval namespace delete [namespace children :: test_ns_*]} namespace eval test_ns_1::test_ns_2 {} namespace children ::test_ns_1 } {::test_ns_1::test_ns_2} test namespace-19.2 {GetNamespaceFromObj, relative name found} { namespace eval test_ns_1 { namespace children test_ns_2 } } {} test namespace-19.3 {GetNamespaceFromObj, name not found} { namespace eval test_ns_1 { list [catch {namespace children test_ns_99} msg] $msg } } {1 {unknown namespace "test_ns_99" in namespace children command}} test namespace-19.4 {GetNamespaceFromObj, invalidation of cached ns refs} { namespace eval test_ns_1 { proc foo {} { return [namespace children test_ns_2] } list [catch {namespace children test_ns_99} msg] $msg } set l {} lappend l [test_ns_1::foo] namespace delete test_ns_1::test_ns_2 namespace eval test_ns_1::test_ns_2::test_ns_3 {} lappend l [test_ns_1::foo] set l } {{} ::test_ns_1::test_ns_2::test_ns_3} test namespace-20.1 {Tcl_NamespaceObjCmd, bad subcommand} { catch {eval namespace delete [namespace children :: test_ns_*]} list [catch {namespace} msg] $msg } {1 {wrong # args: should be "namespace subcommand ?arg ...?"}} test namespace-20.2 {Tcl_NamespaceObjCmd, bad subcommand} { list [catch {namespace wombat {}} msg] $msg } {1 {bad option "wombat": must be children, code, current, delete, eval, exists, export, forget, import, inscope, origin, parent, qualifiers, tail, or which}} test namespace-20.3 {Tcl_NamespaceObjCmd, abbreviations are okay} { namespace ch :: test_ns_* } {} test namespace-21.1 {NamespaceChildrenCmd, no args} { catch {eval namespace delete [namespace children :: test_ns_*]} namespace eval test_ns_1::test_ns_2 {} expr {[string first ::test_ns_1 [namespace children]] != -1} } {1} test namespace-21.2 {NamespaceChildrenCmd, no args} { namespace eval test_ns_1 { namespace children } } {::test_ns_1::test_ns_2} test namespace-21.3 {NamespaceChildrenCmd, ns name given} { namespace children ::test_ns_1 } {::test_ns_1::test_ns_2} test namespace-21.4 {NamespaceChildrenCmd, ns name given} { namespace eval test_ns_1 { namespace children test_ns_2 } } {} test namespace-21.5 {NamespaceChildrenCmd, too many args} { namespace eval test_ns_1 { list [catch {namespace children test_ns_2 xxx yyy} msg] $msg } } {1 {wrong # args: should be "namespace children ?name? ?pattern?"}} test namespace-21.6 {NamespaceChildrenCmd, glob-style pattern given} { namespace eval test_ns_1::test_ns_foo {} namespace children test_ns_1 *f* } {::test_ns_1::test_ns_foo} test namespace-21.7 {NamespaceChildrenCmd, glob-style pattern given} { namespace eval test_ns_1::test_ns_foo {} lsort [namespace children test_ns_1 test*] } [lsort {::test_ns_1::test_ns_2 ::test_ns_1::test_ns_foo}] test namespace-22.1 {NamespaceCodeCmd, bad args} { catch {eval namespace delete [namespace children :: test_ns_*]} list [catch {namespace code} msg] $msg \ [catch {namespace code xxx yyy} msg] $msg } {1 {wrong # args: should be "namespace code arg"} 1 {wrong # args: should be "namespace code arg"}} test namespace-22.2 {NamespaceCodeCmd, arg is already scoped value} { namespace eval test_ns_1 { proc cmd {} {return "test_ns_1::cmd"} } namespace code {namespace inscope ::test_ns_1 cmd} } {namespace inscope ::test_ns_1 cmd} test namespace-22.3 {NamespaceCodeCmd, arg is already scoped value} { namespace code {namespace inscope ::test_ns_1 cmd} } {namespace inscope ::test_ns_1 cmd} test namespace-22.4 {NamespaceCodeCmd, in :: namespace} { namespace code unknown } {::namespace inscope :: unknown} test namespace-22.5 {NamespaceCodeCmd, in other namespace} { namespace eval test_ns_1 { namespace code cmd } } {::namespace inscope ::test_ns_1 cmd} test namespace-22.6 {NamespaceCodeCmd, in other namespace} { namespace eval test_ns_1 { variable v 42 } namespace eval test_ns_2 { proc namespace args {} } namespace eval test_ns_2 [namespace eval test_ns_1 { namespace code {set v} }] } {42} test namespace-23.1 {NamespaceCurrentCmd, bad args} { catch {eval namespace delete [namespace children :: test_ns_*]} list [catch {namespace current xxx} msg] $msg \ [catch {namespace current xxx yyy} msg] $msg } {1 {wrong # args: should be "namespace current"} 1 {wrong # args: should be "namespace current"}} test namespace-23.2 {NamespaceCurrentCmd, at global level} { namespace current } {::} test namespace-23.3 {NamespaceCurrentCmd, in nested ns} { namespace eval test_ns_1::test_ns_2 { namespace current } } {::test_ns_1::test_ns_2} test namespace-24.1 {NamespaceDeleteCmd, no args} { catch {eval namespace delete [namespace children :: test_ns_*]} namespace delete } {} test namespace-24.2 {NamespaceDeleteCmd, one arg} { namespace eval test_ns_1::test_ns_2 {} namespace delete ::test_ns_1 } {} test namespace-24.3 {NamespaceDeleteCmd, two args} { namespace eval test_ns_1::test_ns_2 {} list [namespace delete ::test_ns_1::test_ns_2] [namespace delete ::test_ns_1] } {{} {}} test namespace-24.4 {NamespaceDeleteCmd, unknown ns} { list [catch {namespace delete ::test_ns_foo} msg] $msg } {1 {unknown namespace "::test_ns_foo" in namespace delete command}} test namespace-25.1 {NamespaceEvalCmd, bad args} { catch {eval namespace delete [namespace children :: test_ns_*]} list [catch {namespace eval} msg] $msg } {1 {wrong # args: should be "namespace eval name arg ?arg...?"}} test namespace-25.2 {NamespaceEvalCmd, bad args} { list [catch {namespace test_ns_1} msg] $msg } {1 {bad option "test_ns_1": must be children, code, current, delete, eval, exists, export, forget, import, inscope, origin, parent, qualifiers, tail, or which}} catch {unset v} test namespace-25.3 {NamespaceEvalCmd, new namespace} { set v 123 namespace eval test_ns_1 { variable v 314159 proc p {} { variable v return $v } } test_ns_1::p } {314159} test namespace-25.4 {NamespaceEvalCmd, existing namespace} { namespace eval test_ns_1 { proc q {} {return [expr {[p]+1}]} } test_ns_1::q } {314160} test namespace-25.5 {NamespaceEvalCmd, multiple args} { namespace eval test_ns_1 "set" "v" } {314159} test namespace-25.6 {NamespaceEvalCmd, error in eval'd script} { list [catch {namespace eval test_ns_1 {xxxx}} msg] $msg $errorInfo } {1 {invalid command name "xxxx"} {invalid command name "xxxx" while executing "xxxx" (in namespace eval "::test_ns_1" script line 1) invoked from within "namespace eval test_ns_1 {xxxx}"}} test namespace-25.7 {NamespaceEvalCmd, error in eval'd script} { list [catch {namespace eval test_ns_1 {error foo bar baz}} msg] $msg $errorInfo } {1 foo {bar (in namespace eval "::test_ns_1" script line 1) invoked from within "namespace eval test_ns_1 {error foo bar baz}"}} test namespace-25.8 {NamespaceEvalCmd, error in eval'd script} knownBug { list [catch {namespace eval test_ns_1 error foo bar baz} msg] $msg $errorInfo } {1 foo {bar (in namespace eval "::test_ns_1" script line 1) invoked from within "namespace eval test_ns_1 error foo bar baz"}} catch {unset v} test namespace-25.9 {NamespaceEvalCmd, 545325} { namespace eval test_ns_1 info level 0 } {namespace eval test_ns_1 info level 0} test namespace-26.1 {NamespaceExportCmd, no args and new ns} { catch {eval namespace delete [namespace children :: test_ns_*]} namespace export } {} test namespace-26.2 {NamespaceExportCmd, just -clear arg} { namespace export -clear } {} test namespace-26.3 {NamespaceExportCmd, pattern can't specify a namespace} { namespace eval test_ns_1 { list [catch {namespace export ::zzz} msg] $msg } } {1 {invalid export pattern "::zzz": pattern can't specify a namespace}} test namespace-26.4 {NamespaceExportCmd, one pattern} { namespace eval test_ns_1 { namespace export cmd1 proc cmd1 {args} {return "cmd1: $args"} proc cmd2 {args} {return "cmd2: $args"} proc cmd3 {args} {return "cmd3: $args"} proc cmd4 {args} {return "cmd4: $args"} } namespace eval test_ns_2 { namespace import ::test_ns_1::* } list [info commands test_ns_2::*] [test_ns_2::cmd1 hello] } {::test_ns_2::cmd1 {cmd1: hello}} test namespace-26.5 {NamespaceExportCmd, sequence of patterns, patterns accumulate} { namespace eval test_ns_1 { namespace export cmd1 cmd3 } namespace eval test_ns_2 { namespace import -force ::test_ns_1::* } list [lsort [info commands test_ns_2::*]] [test_ns_2::cmd3 hello] } [list [lsort {::test_ns_2::cmd1 ::test_ns_2::cmd3}] {cmd3: hello}] test namespace-26.6 {NamespaceExportCmd, no patterns means return uniq'ed export list} { namespace eval test_ns_1 { namespace export } } {cmd1 cmd3} test namespace-26.7 {NamespaceExportCmd, -clear resets export list} { namespace eval test_ns_1 { namespace export -clear cmd4 } namespace eval test_ns_2 { namespace import ::test_ns_1::* } list [lsort [info commands test_ns_2::*]] [test_ns_2::cmd4 hello] } [list [lsort {::test_ns_2::cmd4 ::test_ns_2::cmd1 ::test_ns_2::cmd3}] {cmd4: hello}] test namespace-26.8 {NamespaceExportCmd, -clear resets export list} { catch {namespace delete foo} namespace eval foo { namespace export x namespace export -clear } list [namespace eval foo namespace export] [namespace delete foo] } {{} {}} test namespace-27.1 {NamespaceForgetCmd, no args} { catch {eval namespace delete [namespace children :: test_ns_*]} namespace forget } {} test namespace-27.2 {NamespaceForgetCmd, args must be valid namespaces} { list [catch {namespace forget ::test_ns_1::xxx} msg] $msg } {1 {unknown namespace in namespace forget pattern "::test_ns_1::xxx"}} test namespace-27.3 {NamespaceForgetCmd, arg is forgotten} { namespace eval test_ns_1 { namespace export cmd* proc cmd1 {args} {return "cmd1: $args"} proc cmd2 {args} {return "cmd2: $args"} } namespace eval test_ns_2 { namespace import ::test_ns_1::* namespace forget ::test_ns_1::cmd1 } info commands ::test_ns_2::* } {::test_ns_2::cmd2} test namespace-28.1 {NamespaceImportCmd, no args} { catch {eval namespace delete [namespace children :: test_ns_*]} namespace import } {} test namespace-28.2 {NamespaceImportCmd, no args and just "-force"} { namespace import -force } {} test namespace-28.3 {NamespaceImportCmd, arg is imported} { namespace eval test_ns_1 { namespace export cmd2 proc cmd1 {args} {return "cmd1: $args"} proc cmd2 {args} {return "cmd2: $args"} } namespace eval test_ns_2 { namespace import ::test_ns_1::* namespace forget ::test_ns_1::cmd1 } info commands test_ns_2::* } {::test_ns_2::cmd2} test namespace-29.1 {NamespaceInscopeCmd, bad args} { catch {eval namespace delete [namespace children :: test_ns_*]} list [catch {namespace inscope} msg] $msg } {1 {wrong # args: should be "namespace inscope name arg ?arg...?"}} test namespace-29.2 {NamespaceInscopeCmd, bad args} { list [catch {namespace inscope ::} msg] $msg } {1 {wrong # args: should be "namespace inscope name arg ?arg...?"}} test namespace-29.3 {NamespaceInscopeCmd, specified ns must exist} { list [catch {namespace inscope test_ns_1 {set v}} msg] $msg } {1 {unknown namespace "test_ns_1" in inscope namespace command}} test namespace-29.4 {NamespaceInscopeCmd, simple case} { namespace eval test_ns_1 { variable v 747 proc cmd {args} { variable v return "[namespace current]::cmd: v=$v, args=$args" } } namespace inscope test_ns_1 cmd } {::test_ns_1::cmd: v=747, args=} test namespace-29.5 {NamespaceInscopeCmd, has lappend semantics} { list [namespace inscope test_ns_1 cmd x y z] \ [namespace eval test_ns_1 [concat cmd [list x y z]]] } {{::test_ns_1::cmd: v=747, args=x y z} {::test_ns_1::cmd: v=747, args=x y z}} test namespace-29.6 {NamespaceInscopeCmd, 1400572} knownBug { namespace inscope test_ns_1 {info level 0} } {namespace inscope test_ns_1 {info level 0}} test namespace-30.1 {NamespaceOriginCmd, bad args} { catch {eval namespace delete [namespace children :: test_ns_*]} list [catch {namespace origin} msg] $msg } {1 {wrong # args: should be "namespace origin name"}} test namespace-30.2 {NamespaceOriginCmd, bad args} { list [catch {namespace origin x y} msg] $msg } {1 {wrong # args: should be "namespace origin name"}} test namespace-30.3 {NamespaceOriginCmd, command not found} { list [catch {namespace origin fred} msg] $msg } {1 {invalid command name "fred"}} test namespace-30.4 {NamespaceOriginCmd, command isn't imported} { namespace origin set } {::set} test namespace-30.5 {NamespaceOriginCmd, imported command} { namespace eval test_ns_1 { namespace export cmd* proc cmd1 {args} {return "cmd1: $args"} proc cmd2 {args} {return "cmd2: $args"} } namespace eval test_ns_2 { namespace export * namespace import ::test_ns_1::* proc p {} {} } namespace eval test_ns_3 { namespace import ::test_ns_2::* list [namespace origin foreach] \ [namespace origin p] \ [namespace origin cmd1] \ [namespace origin ::test_ns_2::cmd2] } } {::foreach ::test_ns_2::p ::test_ns_1::cmd1 ::test_ns_1::cmd2} test namespace-31.1 {NamespaceParentCmd, bad args} { catch {eval namespace delete [namespace children :: test_ns_*]} list [catch {namespace parent a b} msg] $msg } {1 {wrong # args: should be "namespace parent ?name?"}} test namespace-31.2 {NamespaceParentCmd, no args} { namespace parent } {} test namespace-31.3 {NamespaceParentCmd, namespace specified} { namespace eval test_ns_1 { namespace eval test_ns_2 { namespace eval test_ns_3 {} } } list [namespace parent ::] \ [namespace parent test_ns_1::test_ns_2] \ [namespace eval test_ns_1::test_ns_2::test_ns_3 {namespace parent ::test_ns_1::test_ns_2}] } {{} ::test_ns_1 ::test_ns_1} test namespace-31.4 {NamespaceParentCmd, bad namespace specified} { list [catch {namespace parent test_ns_1::test_ns_foo} msg] $msg } {1 {unknown namespace "test_ns_1::test_ns_foo" in namespace parent command}} test namespace-32.1 {NamespaceQualifiersCmd, bad args} { catch {eval namespace delete [namespace children :: test_ns_*]} list [catch {namespace qualifiers} msg] $msg } {1 {wrong # args: should be "namespace qualifiers string"}} test namespace-32.2 {NamespaceQualifiersCmd, bad args} { list [catch {namespace qualifiers x y} msg] $msg } {1 {wrong # args: should be "namespace qualifiers string"}} test namespace-32.3 {NamespaceQualifiersCmd, simple name} { namespace qualifiers foo } {} test namespace-32.4 {NamespaceQualifiersCmd, leading ::} { namespace qualifiers ::x::y::z } {::x::y} test namespace-32.5 {NamespaceQualifiersCmd, no leading ::} { namespace qualifiers a::b } {a} test namespace-32.6 {NamespaceQualifiersCmd, :: argument} { namespace qualifiers :: } {} test namespace-32.7 {NamespaceQualifiersCmd, odd number of :s} { namespace qualifiers ::::: } {} test namespace-32.8 {NamespaceQualifiersCmd, odd number of :s} { namespace qualifiers foo::: } {foo} test namespace-33.1 {NamespaceTailCmd, bad args} { catch {eval namespace delete [namespace children :: test_ns_*]} list [catch {namespace tail} msg] $msg } {1 {wrong # args: should be "namespace tail string"}} test namespace-33.2 {NamespaceTailCmd, bad args} { list [catch {namespace tail x y} msg] $msg } {1 {wrong # args: should be "namespace tail string"}} test namespace-33.3 {NamespaceTailCmd, simple name} { namespace tail foo } {foo} test namespace-33.4 {NamespaceTailCmd, leading ::} { namespace tail ::x::y::z } {z} test namespace-33.5 {NamespaceTailCmd, no leading ::} { namespace tail a::b } {b} test namespace-33.6 {NamespaceTailCmd, :: argument} { namespace tail :: } {} test namespace-33.7 {NamespaceTailCmd, odd number of :s} { namespace tail ::::: } {} test namespace-33.8 {NamespaceTailCmd, odd number of :s} { namespace tail foo::: } {} test namespace-34.1 {NamespaceWhichCmd, bad args} { catch {eval namespace delete [namespace children :: test_ns_*]} list [catch {namespace which} msg] $msg } {1 {wrong # args: should be "namespace which ?-command? ?-variable? name"}} test namespace-34.2 {NamespaceWhichCmd, bad args} { list [catch {namespace which -fred} msg] $msg } {1 {wrong # args: should be "namespace which ?-command? ?-variable? name"}} test namespace-34.3 {NamespaceWhichCmd, bad args} { list [catch {namespace which -command} msg] $msg } {1 {wrong # args: should be "namespace which ?-command? ?-variable? name"}} test namespace-34.4 {NamespaceWhichCmd, bad args} { list [catch {namespace which a b} msg] $msg } {1 {wrong # args: should be "namespace which ?-command? ?-variable? name"}} test namespace-34.5 {NamespaceWhichCmd, command lookup} { namespace eval test_ns_1 { namespace export cmd* variable v1 111 proc cmd1 {args} {return "cmd1: $args"} proc cmd2 {args} {return "cmd2: $args"} } namespace eval test_ns_2 { namespace export * namespace import ::test_ns_1::* variable v2 222 proc p {} {} } namespace eval test_ns_3 { namespace import ::test_ns_2::* variable v3 333 list [namespace which -command foreach] \ [namespace which -command p] \ [namespace which -command cmd1] \ [namespace which -command ::test_ns_2::cmd2] \ [catch {namespace which -command ::test_ns_2::noSuchCmd} msg] $msg } } {::foreach ::test_ns_3::p ::test_ns_3::cmd1 ::test_ns_2::cmd2 0 {}} test namespace-34.6 {NamespaceWhichCmd, -command is default} { namespace eval test_ns_3 { list [namespace which foreach] \ [namespace which p] \ [namespace which cmd1] \ [namespace which ::test_ns_2::cmd2] } } {::foreach ::test_ns_3::p ::test_ns_3::cmd1 ::test_ns_2::cmd2} test namespace-34.7 {NamespaceWhichCmd, variable lookup} { namespace eval test_ns_3 { list [namespace which -variable env] \ [namespace which -variable v3] \ [namespace which -variable ::test_ns_2::v2] \ [catch {namespace which -variable ::test_ns_2::noSuchVar} msg] $msg } } {::env ::test_ns_3::v3 ::test_ns_2::v2 0 {}} test namespace-35.1 {FreeNsNameInternalRep, resulting ref count > 0} { catch {eval namespace delete [namespace children :: test_ns_*]} namespace eval test_ns_1 { proc p {} { namespace delete [namespace current] return [namespace current] } } test_ns_1::p } {::test_ns_1} test namespace-35.2 {FreeNsNameInternalRep, resulting ref count == 0} { namespace eval test_ns_1 { proc q {} { return [namespace current] } } list [test_ns_1::q] \ [namespace delete test_ns_1] \ [catch {test_ns_1::q} msg] $msg } {::test_ns_1 {} 1 {invalid command name "test_ns_1::q"}} catch {unset x} catch {unset y} test namespace-36.1 {DupNsNameInternalRep} { catch {eval namespace delete [namespace children :: test_ns_*]} namespace eval test_ns_1 {} set x "::test_ns_1" list [namespace parent $x] [set y $x] [namespace parent $y] } {:: ::test_ns_1 ::} catch {unset x} catch {unset y} test namespace-37.1 {SetNsNameFromAny, ns name found} { catch {eval namespace delete [namespace children :: test_ns_*]} namespace eval test_ns_1::test_ns_2 {} namespace eval test_ns_1 { namespace children ::test_ns_1 } } {::test_ns_1::test_ns_2} test namespace-37.2 {SetNsNameFromAny, ns name not found} { namespace eval test_ns_1 { list [catch {namespace children ::test_ns_1::test_ns_foo} msg] $msg } } {1 {unknown namespace "::test_ns_1::test_ns_foo" in namespace children command}} test namespace-38.1 {UpdateStringOfNsName} { catch {eval namespace delete [namespace children :: test_ns_*]} ;# Tcl_NamespaceObjCmd calls UpdateStringOfNsName to get subcmd name list [namespace eval {} {namespace current}] \ [namespace eval {} {namespace current}] } {:: ::} test namespace-39.1 {NamespaceExistsCmd} { catch {eval namespace delete [namespace children :: test_ns_*]} namespace eval ::test_ns_z::test_me { variable foo } list [namespace exists ::] \ [namespace exists ::bogus_namespace] \ [namespace exists ::test_ns_z] \ [namespace exists test_ns_z] \ [namespace exists ::test_ns_z::foo] \ [namespace exists ::test_ns_z::test_me] \ [namespace eval ::test_ns_z { namespace exists ::test_me }] \ [namespace eval ::test_ns_z { namespace exists test_me }] \ [namespace exists :::::test_ns_z] } {1 0 1 1 0 1 0 1 1} test namespace-39.2 {NamespaceExistsCmd error} { list [catch {namespace exists} msg] $msg } {1 {wrong # args: should be "namespace exists name"}} test namespace-39.3 {NamespaceExistsCmd error} { list [catch {namespace exists a b} msg] $msg } {1 {wrong # args: should be "namespace exists name"}} test namespace-40.1 {Ignoring namespace proc "unknown"} { rename unknown _unknown proc unknown args {return global} namespace eval ns {proc unknown args {return local}} set l [list [namespace eval ns aaa bbb] [namespace eval ns aaa]] rename unknown {} rename _unknown unknown namespace delete ns set l } {global global} test namespace-41.1 {Shadowing byte-compiled commands, Bug: 231259} { set res {} namespace eval ns { set res {} proc test {} { set ::g 0 } lappend ::res [test] proc set {a b} { ::set a [incr b] } lappend ::res [test] } namespace delete ns set res } {0 1} test namespace-41.2 {Shadowing byte-compiled commands, Bug: 231259} { set res {} namespace eval ns {} proc ns::a {i} { variable b proc set args {return "New proc is called"} return [set b $i] } ns::a 1 set res [ns::a 2] namespace delete ns set res } {New proc is called} test namespace-41.3 {Shadowing byte-compiled commands, Bug: 231259} {knownBug} { set res {} namespace eval ns { variable b 0 } proc ns::a {i} { variable b proc set args {return "New proc is called"} return [set b $i] } set res [list [ns::a 1] $ns::b] namespace delete ns set res } {{New proc is called} 0} # cleanup catch {rename cmd1 {}} catch {unset l} catch {unset msg} catch {unset trigger} eval namespace delete [namespace children :: test_ns_*] ::tcltest::cleanupTests return tcl8.4.20/tests/indexObj.test0000644003604700454610000001201311737050674014521 0ustar dgp771div# This file is a Tcl script to test out the the procedures in file # tkIndexObj.c, which implement indexed table lookups. The tests here # are organized in the standard fashion for Tcl tests. # # Copyright (c) 1997 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } if {[info commands testindexobj] == {}} { puts "This application hasn't been compiled with the \"testindexobj\"" puts "command, so I can't test Tcl_GetIndexFromObj etc." ::tcltest::cleanupTests return } test indexObj-1.1 {exact match} { testindexobj 1 1 xyz abc def xyz alm } {2} test indexObj-1.2 {exact match} { testindexobj 1 1 abc abc def xyz alm } {0} test indexObj-1.3 {exact match} { testindexobj 1 1 alm abc def xyz alm } {3} test indexObj-1.4 {unique abbreviation} { testindexobj 1 1 xy abc def xalb xyz alm } {3} test indexObj-1.5 {multiple abbreviations and exact match} { testindexobj 1 1 x abc def xalb xyz alm x } {5} test indexObj-1.6 {forced exact match} { testindexobj 1 0 xy abc def xalb xy alm } {3} test indexObj-1.7 {forced exact match} { testindexobj 1 0 x abc def xalb xyz alm x } {5} test indexObj-1.8 {exact match of empty values} { testindexobj 1 1 {} a aa aaa {} b bb bbb } 3 test indexObj-1.9 {exact match of empty values} { testindexobj 1 0 {} a aa aaa {} b bb bbb } 3 test indexObj-2.1 {no match} { list [catch {testindexobj 1 1 dddd abc def xalb xyz alm x} msg] $msg } {1 {bad token "dddd": must be abc, def, xalb, xyz, alm, or x}} test indexObj-2.2 {no match} { list [catch {testindexobj 1 1 dddd abc} msg] $msg } {1 {bad token "dddd": must be abc}} test indexObj-2.3 {no match: no abbreviations} { list [catch {testindexobj 1 0 xy abc def xalb xyz alm} msg] $msg } {1 {bad token "xy": must be abc, def, xalb, xyz, or alm}} test indexObj-2.4 {ambiguous value} { list [catch {testindexobj 1 1 d dumb daughter a c} msg] $msg } {1 {ambiguous token "d": must be dumb, daughter, a, or c}} test indexObj-2.5 {omit error message} { list [catch {testindexobj 0 1 d x} msg] $msg } {1 {}} test indexObj-2.6 {TCL_EXACT => no "ambiguous" error message} { list [catch {testindexobj 1 0 d dumb daughter a c} msg] $msg } {1 {bad token "d": must be dumb, daughter, a, or c}} test indexObj-2.7 {exact match of empty values} { list [catch {testindexobj 1 1 {} a b c} msg] $msg } {1 {ambiguous token "": must be a, b, or c}} test indexObj-2.8 {exact match of empty values: singleton case} { list [catch {testindexobj 1 0 {} a} msg] $msg } {1 {bad token "": must be a}} test indexObj-2.9 {non-exact match of empty values: singleton case} { # NOTE this is a special case. Although the empty string is a # unique prefix, we have an established history of rejecting # empty lookup keys, requiring any unique prefix match to have # at least one character. list [catch {testindexobj 1 1 {} a} msg] $msg } {1 {bad token "": must be a}} test indexObj-3.1 {cache result to skip next lookup} { testindexobj check 42 } {42} test indexObj-4.1 {free old internal representation} { set x {a b} lindex $x 1 testindexobj 1 1 $x abc def {a b} zzz } {2} test indexObj-5.1 {Tcl_WrongNumArgs} { testwrongnumargs 1 "?option?" mycmd } "wrong # args: should be \"mycmd ?option?\"" test indexObj-5.2 {Tcl_WrongNumArgs} { testwrongnumargs 2 "bar" mycmd foo } "wrong # args: should be \"mycmd foo bar\"" test indexObj-5.3 {Tcl_WrongNumArgs} { testwrongnumargs 0 "bar" mycmd foo } "wrong # args: should be \"bar\"" test indexObj-5.4 {Tcl_WrongNumArgs} { testwrongnumargs 0 "" mycmd foo } "wrong # args: should be \"\"" test indexObj-5.5 {Tcl_WrongNumArgs} { testwrongnumargs 1 "" mycmd foo } "wrong # args: should be \"mycmd\"" test indexObj-5.6 {Tcl_WrongNumArgs} { testwrongnumargs 2 "" mycmd foo } "wrong # args: should be \"mycmd foo\"" # Contrast this with test proc-3.6; they have to be like this because # of [Bug 1066837] so Itcl won't break. test indexObj-5.7 {Tcl_WrongNumArgs} testindexobj { testwrongnumargs 2 "fee fi" "fo fum" foo bar } "wrong # args: should be \"fo fum foo fee fi\"" test indexObj-6.1 {Tcl_GetIndexFromObjStruct} { set x a testgetindexfromobjstruct $x 0 } "wrong # args: should be \"testgetindexfromobjstruct a 0\"" test indexObj-6.2 {Tcl_GetIndexFromObjStruct} { set x a testgetindexfromobjstruct $x 0 testgetindexfromobjstruct $x 0 } "wrong # args: should be \"testgetindexfromobjstruct a 0\"" test indexObj-6.3 {Tcl_GetIndexFromObjStruct} { set x c testgetindexfromobjstruct $x 1 } "wrong # args: should be \"testgetindexfromobjstruct c 1\"" test indexObj-6.4 {Tcl_GetIndexFromObjStruct} { set x c testgetindexfromobjstruct $x 1 testgetindexfromobjstruct $x 1 } "wrong # args: should be \"testgetindexfromobjstruct c 1\"" # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/regexpComp.test0000644003604700454610000005573611737050674015113 0ustar dgp771div# Commands covered: regexp, regsub # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1998 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import -force ::tcltest::* } # Procedure to evaluate a script within a proc, to test compilation # functionality proc evalInProc { script } { proc testProc {} $script set status [catch { testProc } result] rename testProc {} return $result #return [list $status $result] } catch {unset foo} test regexpComp-1.1 {basic regexp operation} { evalInProc { regexp ab*c abbbc } } 1 test regexpComp-1.2 {basic regexp operation} { evalInProc { regexp ab*c ac } } 1 test regexpComp-1.3 {basic regexp operation} { evalInProc { regexp ab*c ab } } 0 test regexpComp-1.4 {basic regexp operation} { evalInProc { regexp -- -gorp abc-gorpxxx } } 1 test regexpComp-1.5 {basic regexp operation} { evalInProc { regexp {^([^ ]*)[ ]*([^ ]*)} "" a } } 1 test regexpComp-1.6 {basic regexp operation} { list [catch {regexp {} abc} msg] $msg } {0 1} test regexpComp-1.7 {regexp utf compliance} { # if not UTF-8 aware, result is "0 1" evalInProc { set foo "\u4e4eb q" regexp "\u4e4eb q" "a\u4e4eb qw\u5e4e\x4e wq" bar list [string compare $foo $bar] [regexp 4 $bar] } } {0 0} test regexpComp-2.1 {getting substrings back from regexp} { evalInProc { set foo {} list [regexp ab*c abbbbc foo] $foo } } {1 abbbbc} test regexpComp-2.2 {getting substrings back from regexp} { evalInProc { set foo {} set f2 {} list [regexp a(b*)c abbbbc foo f2] $foo $f2 } } {1 abbbbc bbbb} test regexpComp-2.3 {getting substrings back from regexp} { evalInProc { set foo {} set f2 {} list [regexp a(b*)(c) abbbbc foo f2] $foo $f2 } } {1 abbbbc bbbb} test regexpComp-2.4 {getting substrings back from regexp} { evalInProc { set foo {} set f2 {} set f3 {} list [regexp a(b*)(c) abbbbc foo f2 f3] $foo $f2 $f3 } } {1 abbbbc bbbb c} test regexpComp-2.5 {getting substrings back from regexp} { evalInProc { set foo {}; set f1 {}; set f2 {}; set f3 {}; set f4 {}; set f5 {}; set f6 {}; set f7 {}; set f8 {}; set f9 {}; set fa {}; set fb {}; list [regexp (1*)(2*)(3*)(4*)(5*)(6*)(7*)(8*)(9*)(a*)(b*) \ 12223345556789999aabbb \ foo f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb] $foo $f1 $f2 $f3 $f4 $f5 \ $f6 $f7 $f8 $f9 $fa $fb } } {1 12223345556789999aabbb 1 222 33 4 555 6 7 8 9999 aa bbb} test regexpComp-2.6 {getting substrings back from regexp} { evalInProc { set foo 2; set f2 2; set f3 2; set f4 2 list [regexp (a)(b)? xay foo f2 f3 f4] $foo $f2 $f3 $f4 } } {1 a a {} {}} test regexpComp-2.7 {getting substrings back from regexp} { evalInProc { set foo 1; set f2 1; set f3 1; set f4 1 list [regexp (a)(b)?(c) xacy foo f2 f3 f4] $foo $f2 $f3 $f4 } } {1 ac a {} c} test regexpComp-2.8 {getting substrings back from regexp} { evalInProc { set match {} list [regexp {^a*b} aaaab match] $match } } {1 aaaab} test regexpComp-3.1 {-indices option to regexp} { evalInProc { set foo {} list [regexp -indices ab*c abbbbc foo] $foo } } {1 {0 5}} test regexpComp-3.2 {-indices option to regexp} { evalInProc { set foo {} set f2 {} list [regexp -indices a(b*)c abbbbc foo f2] $foo $f2 } } {1 {0 5} {1 4}} test regexpComp-3.3 {-indices option to regexp} { evalInProc { set foo {} set f2 {} list [regexp -indices a(b*)(c) abbbbc foo f2] $foo $f2 } } {1 {0 5} {1 4}} test regexpComp-3.4 {-indices option to regexp} { evalInProc { set foo {} set f2 {} set f3 {} list [regexp -indices a(b*)(c) abbbbc foo f2 f3] $foo $f2 $f3 } } {1 {0 5} {1 4} {5 5}} test regexpComp-3.5 {-indices option to regexp} { evalInProc { set foo {}; set f1 {}; set f2 {}; set f3 {}; set f4 {}; set f5 {}; set f6 {}; set f7 {}; set f8 {}; set f9 {} list [regexp -indices (1*)(2*)(3*)(4*)(5*)(6*)(7*)(8*)(9*) \ 12223345556789999 \ foo f1 f2 f3 f4 f5 f6 f7 f8 f9] $foo $f1 $f2 $f3 $f4 $f5 \ $f6 $f7 $f8 $f9 } } {1 {0 16} {0 0} {1 3} {4 5} {6 6} {7 9} {10 10} {11 11} {12 12} {13 16}} test regexpComp-3.6 {getting substrings back from regexp} { evalInProc { set foo 2; set f2 2; set f3 2; set f4 2 list [regexp -indices (a)(b)? xay foo f2 f3 f4] $foo $f2 $f3 $f4 } } {1 {1 1} {1 1} {-1 -1} {-1 -1}} test regexpComp-3.7 {getting substrings back from regexp} { evalInProc { set foo 1; set f2 1; set f3 1; set f4 1 list [regexp -indices (a)(b)?(c) xacy foo f2 f3 f4] $foo $f2 $f3 $f4 } } {1 {1 2} {1 1} {-1 -1} {2 2}} test regexpComp-4.1 {-nocase option to regexp} { evalInProc { regexp -nocase foo abcFOo } } 1 test regexpComp-4.2 {-nocase option to regexp} { evalInProc { set f1 22 set f2 33 set f3 44 list [regexp -nocase {a(b*)([xy]*)z} aBbbxYXxxZ22 f1 f2 f3] $f1 $f2 $f3 } } {1 aBbbxYXxxZ Bbb xYXxx} test regexpComp-4.3 {-nocase option to regexp} { evalInProc { regexp -nocase FOo abcFOo } } 1 set ::x abcdefghijklmnopqrstuvwxyz1234567890 set ::x $x$x$x$x$x$x$x$x$x$x$x$x test regexpComp-4.4 {case conversion in regexp} { evalInProc { list [regexp -nocase $::x $::x foo] $foo } } "1 $x" catch {unset ::x} test regexpComp-5.1 {exercise cache of compiled expressions} { evalInProc { regexp .*a b regexp .*b c regexp .*c d regexp .*d e regexp .*e f regexp .*a bbba } } 1 test regexpComp-5.2 {exercise cache of compiled expressions} { evalInProc { regexp .*a b regexp .*b c regexp .*c d regexp .*d e regexp .*e f regexp .*b xxxb } } 1 test regexpComp-5.3 {exercise cache of compiled expressions} { evalInProc { regexp .*a b regexp .*b c regexp .*c d regexp .*d e regexp .*e f regexp .*c yyyc } } 1 test regexpComp-5.4 {exercise cache of compiled expressions} { evalInProc { regexp .*a b regexp .*b c regexp .*c d regexp .*d e regexp .*e f regexp .*d 1d } } 1 test regexpComp-5.5 {exercise cache of compiled expressions} { evalInProc { regexp .*a b regexp .*b c regexp .*c d regexp .*d e regexp .*e f regexp .*e xe } } 1 test regexpComp-6.1 {regexp errors} { evalInProc { list [catch {regexp a} msg] $msg } } {1 {wrong # args: should be "regexp ?switches? exp string ?matchVar? ?subMatchVar subMatchVar ...?"}} test regexpComp-6.2 {regexp errors} { evalInProc { list [catch {regexp -nocase a} msg] $msg } } {1 {wrong # args: should be "regexp ?switches? exp string ?matchVar? ?subMatchVar subMatchVar ...?"}} test regexpComp-6.3 {regexp errors} { evalInProc { list [catch {regexp -gorp a} msg] $msg } } {1 {bad switch "-gorp": must be -all, -about, -indices, -inline, -expanded, -line, -linestop, -lineanchor, -nocase, -start, or --}} test regexpComp-6.4 {regexp errors} { evalInProc { list [catch {regexp a( b} msg] $msg } } {1 {couldn't compile regular expression pattern: parentheses () not balanced}} test regexpComp-6.5 {regexp errors} { evalInProc { list [catch {regexp a( b} msg] $msg } } {1 {couldn't compile regular expression pattern: parentheses () not balanced}} test regexpComp-6.6 {regexp errors} { evalInProc { list [catch {regexp a a f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1} msg] $msg } } {0 1} test regexpComp-6.7 {regexp errors} { evalInProc { list [catch {regexp (x)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.) xyzzy} msg] $msg } } {0 0} test regexpComp-6.8 {regexp errors} { evalInProc { catch {unset f1} set f1 44 list [catch {regexp abc abc f1(f2)} msg] $msg } } {1 {couldn't set variable "f1(f2)"}} test regexpComp-6.9 {regexp errors, -start bad int check} { evalInProc { list [catch {regexp -start bogus {^$} {}} msg] $msg } } {1 {expected integer but got "bogus"}} test regexpComp-7.1 {basic regsub operation} { evalInProc { list [regsub aa+ xaxaaaxaa 111&222 foo] $foo } } {1 xax111aaa222xaa} test regexpComp-7.2 {basic regsub operation} { evalInProc { list [regsub aa+ aaaxaa &111 foo] $foo } } {1 aaa111xaa} test regexpComp-7.3 {basic regsub operation} { evalInProc { list [regsub aa+ xaxaaa 111& foo] $foo } } {1 xax111aaa} test regexpComp-7.4 {basic regsub operation} { evalInProc { list [regsub aa+ aaa 11&2&333 foo] $foo } } {1 11aaa2aaa333} test regexpComp-7.5 {basic regsub operation} { evalInProc { list [regsub aa+ xaxaaaxaa &2&333 foo] $foo } } {1 xaxaaa2aaa333xaa} test regexpComp-7.6 {basic regsub operation} { evalInProc { list [regsub aa+ xaxaaaxaa 1&22& foo] $foo } } {1 xax1aaa22aaaxaa} test regexpComp-7.7 {basic regsub operation} { evalInProc { list [regsub a(a+) xaxaaaxaa {1\122\1} foo] $foo } } {1 xax1aa22aaxaa} test regexpComp-7.8 {basic regsub operation} { evalInProc { list [regsub a(a+) xaxaaaxaa {1\\\122\1} foo] $foo } } "1 {xax1\\aa22aaxaa}" test regexpComp-7.9 {basic regsub operation} { evalInProc { list [regsub a(a+) xaxaaaxaa {1\\122\1} foo] $foo } } "1 {xax1\\122aaxaa}" test regexpComp-7.10 {basic regsub operation} { evalInProc { list [regsub a(a+) xaxaaaxaa {1\\&\1} foo] $foo } } "1 {xax1\\aaaaaxaa}" test regexpComp-7.11 {basic regsub operation} { evalInProc { list [regsub a(a+) xaxaaaxaa {1\&\1} foo] $foo } } {1 xax1&aaxaa} test regexpComp-7.12 {basic regsub operation} { evalInProc { list [regsub a(a+) xaxaaaxaa {\1\1\1\1&&} foo] $foo } } {1 xaxaaaaaaaaaaaaaaxaa} test regexpComp-7.13 {basic regsub operation} { evalInProc { set foo xxx list [regsub abc xyz 111 foo] $foo } } {0 xyz} test regexpComp-7.14 {basic regsub operation} { evalInProc { set foo xxx list [regsub ^ xyz "111 " foo] $foo } } {1 {111 xyz}} test regexpComp-7.15 {basic regsub operation} { evalInProc { set foo xxx list [regsub -- -foo abc-foodef "111 " foo] $foo } } {1 {abc111 def}} test regexpComp-7.16 {basic regsub operation} { evalInProc { set foo xxx list [regsub x "" y foo] $foo } } {0 {}} test regexpComp-7.17 {regsub utf compliance} { evalInProc { # if not UTF-8 aware, result is "0 1" set foo "xyz555ijka\u4e4ebpqr" regsub a\u4e4eb xyza\u4e4ebijka\u4e4ebpqr 555 bar list [string compare $foo $bar] [regexp 4 $bar] } } {0 0} test regexpComp-8.1 {case conversion in regsub} { evalInProc { list [regsub -nocase a(a+) xaAAaAAay & foo] $foo } } {1 xaAAaAAay} test regexpComp-8.2 {case conversion in regsub} { evalInProc { list [regsub -nocase a(a+) xaAAaAAay & foo] $foo } } {1 xaAAaAAay} test regexpComp-8.3 {case conversion in regsub} { evalInProc { set foo 123 list [regsub a(a+) xaAAaAAay & foo] $foo } } {0 xaAAaAAay} test regexpComp-8.4 {case conversion in regsub} { evalInProc { set foo 123 list [regsub -nocase a CaDE b foo] $foo } } {1 CbDE} test regexpComp-8.5 {case conversion in regsub} { evalInProc { set foo 123 list [regsub -nocase XYZ CxYzD b foo] $foo } } {1 CbD} test regexpComp-8.6 {case conversion in regsub} { evalInProc { set x abcdefghijklmnopqrstuvwxyz1234567890 set x $x$x$x$x$x$x$x$x$x$x$x$x set foo 123 list [regsub -nocase $x $x b foo] $foo } } {1 b} test regexpComp-9.1 {-all option to regsub} { evalInProc { set foo 86 list [regsub -all x+ axxxbxxcxdx |&| foo] $foo } } {4 a|xxx|b|xx|c|x|d|x|} test regexpComp-9.2 {-all option to regsub} { evalInProc { set foo 86 list [regsub -nocase -all x+ aXxXbxxcXdx |&| foo] $foo } } {4 a|XxX|b|xx|c|X|d|x|} test regexpComp-9.3 {-all option to regsub} { evalInProc { set foo 86 list [regsub x+ axxxbxxcxdx |&| foo] $foo } } {1 a|xxx|bxxcxdx} test regexpComp-9.4 {-all option to regsub} { evalInProc { set foo 86 list [regsub -all bc axxxbxxcxdx |&| foo] $foo } } {0 axxxbxxcxdx} test regexpComp-9.5 {-all option to regsub} { evalInProc { set foo xxx list [regsub -all node "node node more" yy foo] $foo } } {2 {yy yy more}} test regexpComp-9.6 {-all option to regsub} { evalInProc { set foo xxx list [regsub -all ^ xxx 123 foo] $foo } } {1 123xxx} test regexpComp-10.1 {expanded syntax in regsub} { evalInProc { set foo xxx list [regsub -expanded ". \#comment\n . \#comment2" abc def foo] $foo } } {1 defc} test regexpComp-10.2 {newline sensitivity in regsub} { evalInProc { set foo xxx list [regsub -line {^a.*b$} "dabc\naxyb\n" 123 foo] $foo } } "1 {dabc\n123\n}" test regexpComp-10.3 {newline sensitivity in regsub} { evalInProc { set foo xxx list [regsub -line {^a.*b$} "dabc\naxyb\nxb" 123 foo] $foo } } "1 {dabc\n123\nxb}" test regexpComp-10.4 {partial newline sensitivity in regsub} { evalInProc { set foo xxx list [regsub -lineanchor {^a.*b$} "da\naxyb\nxb" 123 foo] $foo } } "1 {da\n123}" test regexpComp-10.5 {inverse partial newline sensitivity in regsub} { evalInProc { set foo xxx list [regsub -linestop {a.*b} "da\nbaxyb\nxb" 123 foo] $foo } } "1 {da\nb123\nxb}" test regexpComp-11.1 {regsub errors} { evalInProc { list [catch {regsub a b} msg] $msg } } {1 {wrong # args: should be "regsub ?switches? exp string subSpec ?varName?"}} test regexpComp-11.2 {regsub errors} { evalInProc { list [catch {regsub -nocase a b} msg] $msg } } {1 {wrong # args: should be "regsub ?switches? exp string subSpec ?varName?"}} test regexpComp-11.3 {regsub errors} { evalInProc { list [catch {regsub -nocase -all a b} msg] $msg } } {1 {wrong # args: should be "regsub ?switches? exp string subSpec ?varName?"}} test regexpComp-11.4 {regsub errors} { evalInProc { list [catch {regsub a b c d e f} msg] $msg } } {1 {wrong # args: should be "regsub ?switches? exp string subSpec ?varName?"}} test regexpComp-11.5 {regsub errors} { evalInProc { list [catch {regsub -gorp a b c} msg] $msg } } {1 {bad switch "-gorp": must be -all, -nocase, -expanded, -line, -linestop, -lineanchor, -start, or --}} test regexpComp-11.6 {regsub errors} { evalInProc { list [catch {regsub -nocase a( b c d} msg] $msg } } {1 {couldn't compile regular expression pattern: parentheses () not balanced}} test regexpComp-11.7 {regsub errors} { evalInProc { catch {unset f1} set f1 44 list [catch {regsub -nocase aaa aaa xxx f1(f2)} msg] $msg } } {1 {couldn't set variable "f1(f2)"}} test regexpComp-11.8 {regsub errors, -start bad int check} { evalInProc { list [catch {regsub -start bogus pattern string rep var} msg] $msg } } {1 {expected integer but got "bogus"}} # This test crashes on the Mac unless you increase the Stack Space to about 1 # Meg. This is probably bigger than most users want... # 8.2.3 regexp reduced stack space requirements, but this should be # tested again test regexpComp-12.1 {Tcl_RegExpExec: large number of subexpressions} {macCrash} { evalInProc { list [regexp (.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.) abcdefghijklmnopqrstuvwxyz all a b c d e f g h i j k l m n o p q r s t u v w x y z] $all $a $b $c $d $e $f $g $h $i $j $k $l $m $n $o $p $q $r $s $t $u $v $w $x $y $z } } {1 abcdefghijklmnopqrstuvwxyz a b c d e f g h i j k l m n o p q r s t u v w x y z} test regexpComp-13.1 {regsub of a very large string} { # This test is designed to stress the memory subsystem in order # to catch Bug #933. It only fails if the Tcl memory allocator # is in use. set line {BEGIN_TABLE ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; END_TABLE} set filedata [string repeat $line 200] for {set i 1} {$i<10} {incr i} { regsub -all "BEGIN_TABLE " $filedata "" newfiledata } set x done } {done} test regexpComp-14.1 {CompileRegexp: regexp cache} { evalInProc { regexp .*a b regexp .*b c regexp .*c d regexp .*d e regexp .*e f set x . append x *a regexp $x bbba } } 1 test regexpComp-14.2 {CompileRegexp: regexp cache, different flags} { evalInProc { regexp .*a b regexp .*b c regexp .*c d regexp .*d e regexp .*e f set x . append x *a regexp -nocase $x bbba } } 1 testConstraint exec [llength [info commands exec]] test regexpComp-14.3 {CompileRegexp: regexp cache, empty regexp and empty cache} -constraints { exec } -setup { set junk [makeFile {puts [regexp {} foo]} junk.tcl] } -body { exec [interpreter] $junk } -cleanup { removeFile junk.tcl } -result 1 test regexpComp-15.1 {regexp -start} { catch {unset x} list [regexp -start -10 {\d} 1abc2de3 x] $x } {1 1} test regexpComp-15.2 {regexp -start} { catch {unset x} list [regexp -start 2 {\d} 1abc2de3 x] $x } {1 2} test regexpComp-15.3 {regexp -start} { catch {unset x} list [regexp -start 4 {\d} 1abc2de3 x] $x } {1 2} test regexpComp-15.4 {regexp -start} { catch {unset x} list [regexp -start 5 {\d} 1abc2de3 x] $x } {1 3} test regexpComp-15.5 {regexp -start, over end of string} { catch {unset x} list [regexp -start [string length 1abc2de3] {\d} 1abc2de3 x] [info exists x] } {0 0} test regexpComp-15.6 {regexp -start, loss of ^$ behavior} { list [regexp -start 2 {^$} {}] } {0} test regexpComp-16.1 {regsub -start} { catch {unset x} list [regsub -all -start 2 {\d} a1b2c3d4e5 {/&} x] $x } {4 a1b/2c/3d/4e/5} test regexpComp-16.2 {regsub -start} { catch {unset x} list [regsub -all -start -25 {z} hello {/&} x] $x } {0 hello} test regexpComp-16.3 {regsub -start} { catch {unset x} list [regsub -all -start 3 {z} hello {/&} x] $x } {0 hello} test regexpComp-16.4 {regsub -start, \A behavior} { set out {} lappend out [regsub -start 0 -all {\A(\w)} {abcde} {/\1} x] $x lappend out [regsub -start 2 -all {\A(\w)} {abcde} {/\1} x] $x } {5 /a/b/c/d/e 3 ab/c/d/e} test regexpComp-17.1 {regexp -inline} { regexp -inline b ababa } {b} test regexpComp-17.2 {regexp -inline} { regexp -inline (b) ababa } {b b} test regexpComp-17.3 {regexp -inline -indices} { regexp -inline -indices (b) ababa } {{1 1} {1 1}} test regexpComp-17.4 {regexp -inline} { regexp -inline {\w(\d+)\w} " hello 23 there456def " } {e456d 456} test regexpComp-17.5 {regexp -inline no matches} { regexp -inline {\w(\d+)\w} "" } {} test regexpComp-17.6 {regexp -inline no matches} { regexp -inline hello goodbye } {} test regexpComp-17.7 {regexp -inline, no matchvars allowed} { list [catch {regexp -inline b abc match} msg] $msg } {1 {regexp match variables not allowed when using -inline}} test regexpComp-18.1 {regexp -all} { regexp -all b bbbbb } {5} test regexpComp-18.2 {regexp -all} { regexp -all b abababbabaaaaaaaaaab } {6} test regexpComp-18.3 {regexp -all -inline} { regexp -all -inline b abababbabaaaaaaaaaab } {b b b b b b} test regexpComp-18.4 {regexp -all -inline} { regexp -all -inline {\w(\w)} abcdefg } {ab b cd d ef f} test regexpComp-18.5 {regexp -all -inline} { regexp -all -inline {\w(\w)$} abcdefg } {fg g} test regexpComp-18.6 {regexp -all -inline} { regexp -all -inline {\d+} 10:20:30:40 } {10 20 30 40} test regexpComp-18.7 {regexp -all -inline} { list [catch {regexp -all -inline b abc match} msg] $msg } {1 {regexp match variables not allowed when using -inline}} test regexpComp-18.8 {regexp -all} { # This should not cause an infinite loop regexp -all -inline {a*} a } {a} test regexpComp-18.9 {regexp -all} { # Yes, the expected result is {a {}}. Here's why: # Start at index 0; a* matches the "a" there then stops. # Go to index 1; a* matches the lambda (or {}) there then stops. Recall # that a* matches zero or more "a"'s; thus it matches the string "b", as # there are zero or more "a"'s there. # Go to index 2; this is past the end of the string, so stop. regexp -all -inline {a*} ab } {a {}} test regexpComp-18.10 {regexp -all} { # Yes, the expected result is {a {} a}. Here's why: # Start at index 0; a* matches the "a" there then stops. # Go to index 1; a* matches the lambda (or {}) there then stops. Recall # that a* matches zero or more "a"'s; thus it matches the string "b", as # there are zero or more "a"'s there. # Go to index 2; a* matches the "a" there then stops. # Go to index 3; this is past the end of the string, so stop. regexp -all -inline {a*} aba } {a {} a} test regexpComp-18.11 {regexp -all} { evalInProc { regexp -all -inline {^a} aaaa } } {a} test regexpComp-18.12 {regexp -all -inline -indices} { evalInProc { regexp -all -inline -indices a(b(c)d|e(f)g)h abcdhaefgh } } {{0 4} {1 3} {2 2} {-1 -1} {5 9} {6 8} {-1 -1} {7 7}} test regexpComp-19.1 {regsub null replacement} { evalInProc { regsub -all {@} {@hel@lo@} "\0a\0" result list $result [string length $result] } } "\0a\0hel\0a\0lo\0a\0 14" test regexpComp-20.1 {regsub shared object shimmering} { evalInProc { # Bug #461322 set a abcdefghijklmnopqurstuvwxyz set b $a set c abcdefghijklmnopqurstuvwxyz0123456789 regsub $a $c $b d list $d [string length $d] [string bytelength $d] } } [list abcdefghijklmnopqurstuvwxyz0123456789 37 37] test regexpComp-20.2 {regsub shared object shimmering with -about} { evalInProc { eval regexp -about abc } } {0 {}} test regexpComp-21.1 {regexp command compiling tests} { evalInProc { regexp foo bar } } 0 test regexpComp-21.2 {regexp command compiling tests} { evalInProc { regexp {^foo$} dogfood } } 0 test regexpComp-21.3 {regexp command compiling tests} { evalInProc { set a foo regexp {^foo$} $a } } 1 test regexpComp-21.4 {regexp command compiling tests} { evalInProc { regexp foo dogfood } } 1 test regexpComp-21.5 {regexp command compiling tests} { evalInProc { regexp -nocase FOO dogfod } } 0 test regexpComp-21.6 {regexp command compiling tests} { evalInProc { regexp -n foo dogfoOd } } 1 test regexpComp-21.7 {regexp command compiling tests} { evalInProc { regexp -no -- FoO dogfood } } 1 test regexpComp-21.8 {regexp command compiling tests} { evalInProc { regexp -- foo dogfod } } 0 test regexpComp-21.9 {regexp command compiling tests} { evalInProc { list [catch {regexp -- -nocase foo dogfod} msg] $msg } } {0 0} test regexpComp-21.10 {regexp command compiling tests} { evalInProc { list [regsub -all "" foo bar str] $str } } {3 barfbarobaro} test regexpComp-21.11 {regexp command compiling tests} { evalInProc { list [regsub -all "" "" bar str] $str } } {0 {}} set i 0 foreach {str exp result} { foo ^foo 1 foobar ^foobar$ 1 foobar bar$ 1 foobar ^$ 0 "" ^$ 1 anything $ 1 anything ^.*$ 1 anything ^.*a$ 0 anything ^.*a.*$ 1 anything ^.*.*$ 1 anything ^.*..*$ 1 anything ^.*b$ 0 anything ^a.*$ 1 } { test regexpComp-22.[incr i] {regexp command compiling tests} \ [subst {evalInProc {set a "$str"; regexp {$exp} \$a}}] $result } # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/security.test0000644003604700454610000000154411737050674014635 0ustar dgp771div# security.test -- # # Functionality covered: this file contains a collection of tests for the # auto loading and namespaces. # # Sourcing this file into Tcl runs the tests and generates output for # errors. No output means no errors were found. # # Copyright (c) 1997 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # All rights reserved. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } # If this proc becomes invoked, then there is a bug proc BUG {args} { set ::BUG 1 } # Check and Clear the bug flag (to do before each test) set ::BUG 0 proc CB {} { set ret $::BUG set ::BUG 0 return $ret } test sec-1.1 {tcl_endOfPreviousWord} { catch {tcl_startOfPreviousWord x {[BUG]}} CB } 0 # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/winFCmd.test0000644003604700454610000010455012052456744014315 0ustar dgp771div# This file tests the tclWinFCmd.c file. # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1996-1997 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } ::tcltest::loadTestedCommands catch [list package require -exact Tcltest [info patchlevel]] # Initialise the test constraints testConstraint winVista 0 testConstraint win2000orXP 0 testConstraint winOlderThan2000 0 testConstraint testvolumetype [llength [info commands testvolumetype]] testConstraint testfile [llength [info commands testfile]] testConstraint testchmod [llength [info commands testchmod]] testConstraint cdrom 0 testConstraint exdev 0 testConstraint longFileNames 0 proc createfile {file {string a}} { set f [open $file w] puts -nonewline $f $string close $f return $string } proc contents {file} { set f [open $file r] set r [read $f] close $f set r } proc cleanup {args} { foreach p ". $args" { set x "" catch { set x [glob -directory $p tf* td*] } if {$x != ""} { catch {eval file delete -force -- $x} } } } if {[testConstraint winOnly]} { set major [string index $tcl_platform(osVersion) 0] if {[testConstraint nt] && $major > 4} { if {$major > 5} { testConstraint winVista 1 } elseif {$major == 5} { testConstraint win2000orXP 1 } } else { testConstraint winOlderThan2000 1 } } # find a CD-ROM so we can test read-only filesystems. set cdrom {} if { [info commands ::testvolumetype] ne {} } { foreach p {d e f g h i j k l m n o p q r s t u v w x y z} { if { ! [catch { testvolumetype ${p}: } result] && $result eq {CDFS} } { set cdrom ${p}: } } } proc findfile {dir} { foreach p [glob $dir/*] { if {[file type $p] == "file"} { return $p } } foreach p [glob $dir/*] { if {[file type $p] == "directory"} { set f [findfile $p] if {$f != ""} { return $f } } } return "" } if {$cdrom != ""} { set ::tcltest::testConstraints(cdrom) 1 set cdfile [findfile $cdrom] } if {[file exists c:/] && [file exists d:/]} { catch {file delete d:/tf1} if {[catch {close [open d:/tf1 w]}] == 0} { file delete d:/tf1 set ::tcltest::testConstraints(exdev) 1 } } file delete -force -- td1 set foo [catch {open td1 w} testfile] if {$foo} { set ::tcltest::testConstraints(longFileNames) 0 } else { close $testfile set ::tcltest::testConstraints(longFileNames) 1 file delete -force -- td1 } # A really long file name # length of longname is 1216 chars, which should be greater than any static # buffer or allowable filename. set longname "abcdefghihjllmnopqrstuvwxyz01234567890" append longname $longname append longname $longname append longname $longname append longname $longname append longname $longname # Uses the "testfile" command instead of the "file" command. The "file" # command provides several layers of sanity checks on the arguments and # it can be difficult to actually forward "insane" arguments to the # low-level posix emulation layer. test winFCmd-1.1 {TclpRenameFile: errno: EACCES} {pcOnly cdrom} { list [catch {testfile mv $cdfile $cdrom/dummy~~.fil} msg] $msg } {1 EACCES} test winFCmd-1.2 {TclpRenameFile: errno: EEXIST} {pcOnly} { cleanup file mkdir td1/td2/td3 file mkdir td2 list [catch {testfile mv td2 td1/td2} msg] $msg } {1 EEXIST} test winFCmd-1.3 {TclpRenameFile: errno: EINVAL} {pcOnly} { cleanup list [catch {testfile mv / td1} msg] $msg } {1 EINVAL} test winFCmd-1.4 {TclpRenameFile: errno: EINVAL} {pcOnly} { cleanup file mkdir td1 list [catch {testfile mv td1 td1/td2} msg] $msg } {1 EINVAL} test winFCmd-1.5 {TclpRenameFile: errno: EISDIR} {pcOnly} { cleanup file mkdir td1 createfile tf1 list [catch {testfile mv tf1 td1} msg] $msg } {1 EISDIR} test winFCmd-1.6 {TclpRenameFile: errno: ENOENT} {pcOnly} { cleanup list [catch {testfile mv tf1 tf2} msg] $msg } {1 ENOENT} test winFCmd-1.7 {TclpRenameFile: errno: ENOENT} {pcOnly} { cleanup list [catch {testfile mv "" tf2} msg] $msg } {1 ENOENT} test winFCmd-1.8 {TclpRenameFile: errno: ENOENT} {pcOnly} { cleanup createfile tf1 list [catch {testfile mv tf1 ""} msg] $msg } {1 ENOENT} test winFCmd-1.9 {TclpRenameFile: errno: ENOTDIR} {pcOnly} { cleanup file mkdir td1 createfile tf1 list [catch {testfile mv td1 tf1} msg] $msg } {1 ENOTDIR} test winFCmd-1.10 {TclpRenameFile: errno: EXDEV} {pcOnly exdev} { file delete -force d:/tf1 file mkdir c:/tf1 set msg [list [catch {testfile mv c:/tf1 d:/tf1} msg] $msg] file delete -force c:/tf1 set msg } {1 EXDEV} test winFCmd-1.11 {TclpRenameFile: errno: EACCES} {pcOnly} { cleanup set fd [open tf1 w] set msg [list [catch {testfile mv tf1 tf2} msg] $msg] close $fd set msg } {1 EACCES} test winFCmd-1.12 {TclpRenameFile: errno: EACCES} {pcOnly} { cleanup createfile tf1 set fd [open tf2 w] set msg [list [catch {testfile mv tf1 tf2} msg] $msg] close $fd set msg } {1 EACCES} test winFCmd-1.13 {TclpRenameFile: errno: EACCES} {pcOnly win2000orXP} { cleanup list [catch {testfile mv nul tf1} msg] $msg } {1 EINVAL} test winFCmd-1.13.1 {TclpRenameFile: errno: EACCES} {pcOnly winOlderThan2000} { cleanup list [catch {testfile mv nul tf1} msg] $msg } {1 EACCES} test winFCmd-1.14 {TclpRenameFile: errno: EACCES} {pcOnly 95} { cleanup createfile tf1 list [catch {testfile mv tf1 nul} msg] $msg } {1 EACCES} test winFCmd-1.15 {TclpRenameFile: errno: EEXIST} {pcOnly nt} { cleanup createfile tf1 list [catch {testfile mv tf1 nul} msg] $msg } {1 EEXIST} test winFCmd-1.16 {TclpRenameFile: MoveFile() != FALSE} {pcOnly} { cleanup createfile tf1 tf1 testfile mv tf1 tf2 list [file exists tf1] [contents tf2] } {0 tf1} test winFCmd-1.17 {TclpRenameFile: MoveFile() == FALSE} {pcOnly} { cleanup list [catch {testfile mv tf1 tf2} msg] $msg } {1 ENOENT} test winFCmd-1.18 {TclpRenameFile: srcAttr == -1} {pcOnly} { cleanup list [catch {testfile mv tf1 tf2} msg] $msg } {1 ENOENT} test winFCmd-1.19 {TclpRenameFile: errno == EACCES} {pcOnly win2000orXP} { cleanup list [catch {testfile mv nul tf1} msg] $msg } {1 EINVAL} test winFCmd-1.19.1 {TclpRenameFile: errno == EACCES} {pcOnly winOlderThan2000} { cleanup list [catch {testfile mv nul tf1} msg] $msg } {1 EACCES} test winFCmd-1.20 {TclpRenameFile: src is dir} {pcOnly nt} { # under 95, this would actually succeed and move the current dir out from # under the current process! cleanup file delete /tf1 list [catch {testfile mv [pwd] /tf1} msg] $msg } {1 EACCES} test winFCmd-1.21 {TclpRenameFile: long src} {pcOnly} { cleanup list [catch {testfile mv $longname tf1} msg] $msg } {1 ENAMETOOLONG} test winFCmd-1.22 {TclpRenameFile: long dst} {pcOnly} { cleanup createfile tf1 list [catch {testfile mv tf1 $longname} msg] $msg } {1 ENAMETOOLONG} test winFCmd-1.23 {TclpRenameFile: move dir into self} {pcOnly} { cleanup file mkdir td1 list [catch {testfile mv [pwd]/td1 td1/td2} msg] $msg } {1 EINVAL} test winFCmd-1.24 {TclpRenameFile: move a root dir} {pcOnly} { cleanup list [catch {testfile mv / c:/} msg] $msg } {1 EINVAL} test winFCmd-1.25 {TclpRenameFile: cross file systems} {pcOnly cdrom} { cleanup file mkdir td1 list [catch {testfile mv td1 $cdrom/td1} msg] $msg } {1 EXDEV} test winFCmd-1.26 {TclpRenameFile: readonly fs} {pcOnly cdrom} { cleanup list [catch {testfile mv $cdfile $cdrom/dummy~~.fil} msg] $msg } {1 EACCES} test winFCmd-1.27 {TclpRenameFile: open file} {pcOnly} { cleanup set fd [open tf1 w] set msg [list [catch {testfile mv tf1 tf2} msg] $msg] close $fd set msg } {1 EACCES} test winFCmd-1.28 {TclpRenameFile: errno == EEXIST} {pcOnly} { cleanup createfile tf1 createfile tf2 testfile mv tf1 tf2 list [file exists tf1] [file exists tf2] } {0 1} test winFCmd-1.29 {TclpRenameFile: src is dir} {pcOnly} { cleanup file mkdir td1 createfile tf1 list [catch {testfile mv td1 tf1} msg] $msg } {1 ENOTDIR} test winFCmd-1.30 {TclpRenameFile: dst is dir} {pcOnly} { cleanup file mkdir td1 file mkdir td2/td2 list [catch {testfile mv td1 td2} msg] $msg } {1 EEXIST} test winFCmd-1.31 {TclpRenameFile: TclpRemoveDirectory fails} {pcOnly} { cleanup file mkdir td1 file mkdir td2/td2 list [catch {testfile mv td1 td2} msg] $msg } {1 EEXIST} test winFCmd-1.32 {TclpRenameFile: TclpRemoveDirectory succeeds} {pcOnly} { cleanup file mkdir td1/td2 file mkdir td2 testfile mv td1 td2 list [file exists td1] [file exists td2] [file exists td2/td2] } {0 1 1} test winFCmd-1.33 {TclpRenameFile: After removing dst dir, MoveFile fails} \ {pcOnly exdev} { file mkdir d:/td1 testchmod 000 d:/td1 file mkdir c:/tf1 set msg [list [catch {testfile mv c:/tf1 d:/td1} msg] $msg] set msg "$msg [file writable d:/td1]" file delete d:/td1 file delete -force c:/tf1 set msg } {1 EXDEV 0} test winFCmd-1.34 {TclpRenameFile: src is dir, dst is not} {pcOnly} { file mkdir td1 createfile tf1 list [catch {testfile mv td1 tf1} msg] $msg } {1 ENOTDIR} test winFCmd-1.35 {TclpRenameFile: src is not dir, dst is} {pcOnly} { file mkdir td1 createfile tf1 list [catch {testfile mv tf1 td1} msg] $msg } {1 EISDIR} test winFCmd-1.36 {TclpRenameFile: src and dst not dir} {pcOnly} { createfile tf1 tf1 createfile tf2 tf2 testfile mv tf1 tf2 contents tf2 } {tf1} test winFCmd-1.37 {TclpRenameFile: need to restore temp file} {pcOnly} { # Can't figure out how to cause this. # Need a file that can't be copied. } {} test winFCmd-2.1 {TclpCopyFile: errno: EACCES} {pcOnly cdrom} { cleanup list [catch {testfile cp $cdfile $cdrom/dummy~~.fil} msg] $msg } {1 EACCES} test winFCmd-2.2 {TclpCopyFile: errno: EISDIR} {pcOnly} { cleanup file mkdir td1 list [catch {testfile cp td1 tf1} msg] $msg } {1 EISDIR} test winFCmd-2.3 {TclpCopyFile: errno: EISDIR} {pcOnly} { cleanup createfile tf1 file mkdir td1 list [catch {testfile cp tf1 td1} msg] $msg } {1 EISDIR} test winFCmd-2.4 {TclpCopyFile: errno: ENOENT} {pcOnly} { cleanup list [catch {testfile cp tf1 tf2} msg] $msg } {1 ENOENT} test winFCmd-2.5 {TclpCopyFile: errno: ENOENT} {pcOnly} { cleanup list [catch {testfile cp "" tf2} msg] $msg } {1 ENOENT} test winFCmd-2.6 {TclpCopyFile: errno: ENOENT} {pcOnly} { cleanup createfile tf1 list [catch {testfile cp tf1 ""} msg] $msg } {1 ENOENT} test winFCmd-2.7 {TclpCopyFile: errno: EACCES} {pcOnly 95} { cleanup createfile tf1 set fd [open tf2 w] set msg [list [catch {testfile cp tf1 tf2} msg] $msg] close $fd set msg } {1 EACCES} test winFCmd-2.8 {TclpCopyFile: errno: EACCES} {pcOnly win2000orXP} { cleanup list [catch {testfile cp nul tf1} msg] $msg } {1 EINVAL} test winFCmd-2.8.1 {TclpCopyFile: errno: EACCES} {pcOnly nt winOlderThan2000} { cleanup list [catch {testfile cp nul tf1} msg] $msg } {1 EACCES} test winFCmd-2.9 {TclpCopyFile: errno: ENOENT} {pcOnly 95} { cleanup list [catch {testfile cp nul tf1} msg] $msg } {1 ENOENT} test winFCmd-2.10 {TclpCopyFile: CopyFile succeeds} {pcOnly} { cleanup createfile tf1 tf1 testfile cp tf1 tf2 list [contents tf1] [contents tf2] } {tf1 tf1} test winFCmd-2.11 {TclpCopyFile: CopyFile succeeds} {pcOnly} { cleanup createfile tf1 tf1 createfile tf2 tf2 testfile cp tf1 tf2 list [contents tf1] [contents tf2] } {tf1 tf1} test winFCmd-2.12 {TclpCopyFile: CopyFile succeeds} {pcOnly} { cleanup createfile tf1 tf1 testchmod 000 tf1 testfile cp tf1 tf2 list [contents tf2] [file writable tf2] } {tf1 0} test winFCmd-2.13 {TclpCopyFile: CopyFile fails} {pcOnly} { cleanup createfile tf1 file mkdir td1 list [catch {testfile cp tf1 td1} msg] $msg } {1 EISDIR} test winFCmd-2.14 {TclpCopyFile: errno == EACCES} {pcOnly} { cleanup file mkdir td1 list [catch {testfile cp td1 tf1} msg] $msg } {1 EISDIR} test winFCmd-2.15 {TclpCopyFile: src is directory} {pcOnly} { cleanup file mkdir td1 list [catch {testfile cp td1 tf1} msg] $msg } {1 EISDIR} test winFCmd-2.16 {TclpCopyFile: dst is directory} {pcOnly} { cleanup createfile tf1 file mkdir td1 list [catch {testfile cp tf1 td1} msg] $msg } {1 EISDIR} test winFCmd-2.17 {TclpCopyFile: dst is readonly} {pcOnly} { cleanup createfile tf1 tf1 createfile tf2 tf2 testchmod 000 tf2 testfile cp tf1 tf2 list [file writable tf2] [contents tf2] } {1 tf1} test winFCmd-2.18 {TclpCopyFile: still can't copy onto dst} {pcOnly 95} { cleanup createfile tf1 createfile tf2 testchmod 000 tf2 set fd [open tf2] set msg [list [catch {testfile cp tf1 tf2} msg] $msg] close $fd set msg "$msg [file writable tf2]" } {1 EACCES 0} test winFCmd-3.1 {TclpDeleteFile: errno: EACCES} {pcOnly cdrom} { list [catch {testfile rm $cdfile $cdrom/dummy~~.fil} msg] $msg } {1 EACCES} test winFCmd-3.2 {TclpDeleteFile: errno: EISDIR} {pcOnly} { cleanup file mkdir td1 list [catch {testfile rm td1} msg] $msg } {1 EISDIR} test winFCmd-3.3 {TclpDeleteFile: errno: ENOENT} {pcOnly} { cleanup list [catch {testfile rm tf1} msg] $msg } {1 ENOENT} test winFCmd-3.4 {TclpDeleteFile: errno: ENOENT} {pcOnly} { cleanup list [catch {testfile rm ""} msg] $msg } {1 ENOENT} test winFCmd-3.5 {TclpDeleteFile: errno: EACCES} {pcOnly} { cleanup set fd [open tf1 w] set msg [list [catch {testfile rm tf1} msg] $msg] close $fd set msg } {1 EACCES} test winFCmd-3.6 {TclpDeleteFile: errno: EACCES} {pcOnly} { cleanup list [catch {testfile rm nul} msg] $msg } {1 EACCES} test winFCmd-3.7 {TclpDeleteFile: DeleteFile succeeds} {pcOnly} { cleanup createfile tf1 testfile rm tf1 file exists tf1 } {0} test winFCmd-3.8 {TclpDeleteFile: DeleteFile fails} {pcOnly} { cleanup file mkdir td1 list [catch {testfile rm td1} msg] $msg } {1 EISDIR} test winFCmd-3.9 {TclpDeleteFile: errno == EACCES} {pcOnly} { cleanup set fd [open tf1 w] set msg [list [catch {testfile rm tf1} msg] $msg] close $fd set msg } {1 EACCES} test winFCmd-3.10 {TclpDeleteFile: path is readonly} {pcOnly} { cleanup createfile tf1 testchmod 000 tf1 testfile rm tf1 file exists tf1 } {0} test winFCmd-3.11 {TclpDeleteFile: still can't remove path} {pcOnly} { cleanup set fd [open tf1 w] testchmod 000 tf1 set msg [list [catch {testfile rm tf1} msg] $msg] close $fd set msg } {1 EACCES} test winFCmd-4.1 {TclpCreateDirectory: errno: EACCES} {pcOnly nt cdrom} { list [catch {testfile mkdir $cdrom/dummy~~.dir} msg] $msg } {1 EACCES} test winFCmd-4.2 {TclpCreateDirectory: errno: EACCES} {pcOnly 95 cdrom} { list [catch {testfile mkdir $cdrom/dummy~~.dir} msg] $msg } {1 ENOSPC} test winFCmd-4.3 {TclpCreateDirectory: errno: EEXIST} {pcOnly} { cleanup file mkdir td1 list [catch {testfile mkdir td1} msg] $msg } {1 EEXIST} test winFCmd-4.4 {TclpCreateDirectory: errno: ENOENT} {pcOnly} { cleanup list [catch {testfile mkdir td1/td2} msg] $msg } {1 ENOENT} test winFCmd-4.5 {TclpCreateDirectory: CreateDirectory succeeds} {pcOnly} { cleanup testfile mkdir td1 file type td1 } {directory} test winFCmd-5.1 {TclpCopyDirectory: calls TraverseWinTree} {pcOnly} { cleanup file mkdir td1 testfile cpdir td1 td2 list [file type td1] [file type td2] } {directory directory} test winFCmd-6.1 {TclpRemoveDirectory: errno: EACCES} {pcOnly} { cleanup file mkdir td1 testchmod 000 td1 catch { testfile rmdir td1 file exists td1 } r catch { testchmod 777 td1 cleanup } set r } {0} test winFCmd-6.2 {TclpRemoveDirectory: errno: EEXIST} {pcOnly} { cleanup file mkdir td1/td2 list [catch {testfile rmdir td1} msg] [file tail $msg] } {1 {td1 EEXIST}} test winFCmd-6.3 {TclpRemoveDirectory: errno: EACCES} {pcOnly} { # can't test this w/o removing everything on your hard disk first! # testfile rmdir / } {} test winFCmd-6.4 {TclpRemoveDirectory: errno: ENOENT} {pcOnly} { cleanup list [catch {testfile rmdir td1} msg] [file tail $msg] } {1 {td1 ENOENT}} test winFCmd-6.5 {TclpRemoveDirectory: errno: ENOENT} {pcOnly} { cleanup list [catch {testfile rmdir ""} msg] $msg } {1 ENOENT} test winFCmd-6.6 {TclpRemoveDirectory: errno: ENOTDIR} {pcOnly} { cleanup createfile tf1 list [catch {testfile rmdir tf1} msg] [file tail $msg] } {1 {tf1 ENOTDIR}} test winFCmd-6.7 {TclpRemoveDirectory: RemoveDirectory succeeds} {pcOnly} { cleanup file mkdir td1 testfile rmdir td1 file exists td1 } {0} test winFCmd-6.8 {TclpRemoveDirectory: RemoveDirectory fails} {pcOnly} { cleanup createfile tf1 list [catch {testfile rmdir tf1} msg] [file tail $msg] } {1 {tf1 ENOTDIR}} test winFCmd-6.9 {TclpRemoveDirectory: errno == EACCES} {pcOnly} { cleanup file mkdir td1 testchmod 000 td1 catch { testfile rmdir td1 file exists td1 } r catch { testchmod 777 td1 cleanup } set r } {0} test winFCmd-6.10 {TclpRemoveDirectory: attr == -1} {pcOnly 95} { cleanup list [catch {testfile rmdir nul} msg] $msg } {1 {nul EACCES}} test winFCmd-6.11 {TclpRemoveDirectory: attr == -1} {pcOnly nt} { cleanup set res [list [catch {testfile rmdir /} msg] $msg] # WinXP returns EEXIST, WinNT seems to return EACCES. No policy # decision has been made as to which is correct. regsub {E(ACCES|EXIST)} $res "EACCES or EEXIST" res # Don't mind which drive we're on regsub {[A-Z]:} $res "" } {1 {/ EACCES or EEXIST}} test winFCmd-6.12 {TclpRemoveDirectory: errno == EACCES} {pcOnly 95} { cleanup createfile tf1 list [catch {testfile rmdir tf1} msg] $msg } {1 {tf1 ENOTDIR}} test winFCmd-6.13 {TclpRemoveDirectory: write-protected} {pcOnly} { cleanup file mkdir td1 testchmod 000 td1 catch { testfile rmdir td1 file exists td1 } r catch { testchmod 777 td1 cleanup } set r } {0} test winFCmd-6.14 {TclpRemoveDirectory: check if empty dir} {pcOnly 95} { cleanup file mkdir td1/td2 list [catch {testfile rmdir td1} msg] $msg } {1 {td1 EEXIST}} test winFCmd-6.15 {TclpRemoveDirectory: !recursive} {pcOnly} { cleanup file mkdir td1/td2 list [catch {testfile rmdir td1} msg] [file tail $msg] } {1 {td1 EEXIST}} test winFCmd-6.16 {TclpRemoveDirectory: recursive, but errno != EEXIST} {pcOnly} { cleanup createfile tf1 list [catch {testfile rmdir -force tf1} msg] $msg } {1 {tf1 ENOTDIR}} test winFCmd-6.17 {TclpRemoveDirectory: calls TraverseWinTree} {pcOnly} { cleanup file mkdir td1/td2 testfile rmdir -force td1 file exists td1 } {0} test winFCmd-7.1 {TraverseWinTree: targetPtr == NULL} {pcOnly} { cleanup file mkdir td1/td2/td3 testfile rmdir -force td1 file exists td1 } {0} test winFCmd-7.2 {TraverseWinTree: targetPtr != NULL} {pcOnly} { cleanup file mkdir td1/td2/td3 testfile cpdir td1 td2 list [file exists td1] [file exists td2] } {1 1} test winFCmd-7.3 {TraverseWinTree: sourceAttr == -1} {pcOnly} { cleanup list [catch {testfile cpdir td1 td2} msg] $msg } {1 {td1 ENOENT}} test winFCmd-7.4 {TraverseWinTree: source isn't directory} {pcOnly} { cleanup file mkdir td1 createfile td1/tf1 tf1 testfile cpdir td1 td2 contents td2/tf1 } {tf1} test winFCmd-7.5 {TraverseWinTree: call TraversalCopy: DOTREE_F} {pcOnly} { cleanup file mkdir td1 createfile td1/tf1 tf1 testfile cpdir td1 td2 contents td2/tf1 } {tf1} test winFCmd-7.6 {TraverseWinTree: call TraversalDelete: DOTREE_F} {pcOnly} { cleanup file mkdir td1 createfile td1/tf1 tf1 testfile rmdir -force td1 file exists td1 } {0} test winFCmd-7.7 {TraverseWinTree: append \ to source if necessary} {pcOnly} { cleanup file mkdir td1 createfile td1/tf1 tf1 testfile cpdir td1 td2 contents td2/tf1 } {tf1} test winFCmd-7.8 {TraverseWinTree: append \ to source if necessary} {pcOnly 95 cdrom} { # cdrom can return either d:\ or D:/, but we only care about the errcode list [catch {testfile rmdir $cdrom/} msg] [lindex $msg 1] } {1 EEXIST} test winFCmd-7.9 {TraverseWinTree: append \ to source if necessary} {pcOnly nt cdrom} { list [catch {testfile rmdir $cdrom/} msg] [lindex $msg 1] } {1 EACCES} test winFCmd-7.10 {TraverseWinTree: can't read directory: handle == INVALID} \ {pcOnly} { # can't make it happen } {} test winFCmd-7.11 {TraverseWinTree: call TraversalCopy: DOTREE_PRED} {pcOnly} { cleanup file mkdir td1 createfile td1/tf1 tf1 testchmod 000 td1 catch { testfile cpdir td1 td2 list [file exists td2] [file writable td2] } r catch { testchmod 777 td1 cleanup } set r } {1 1} test winFCmd-7.12 {TraverseWinTree: call TraversalDelete: DOTREE_PRED} {pcOnly} { cleanup file mkdir td1 createfile td1/tf1 tf1 testfile rmdir -force td1 file exists td1 } {0} test winFCmd-7.13 {TraverseWinTree: append \ to target if necessary} {pcOnly} { cleanup file mkdir td1 createfile td1/tf1 tf1 testfile cpdir td1 td2 contents td2/tf1 } {tf1} test winFCmd-7.14 {TraverseWinTree: append \ to target if necessary} {pcOnly 95} { cleanup file mkdir td1 list [catch {testfile cpdir td1 /} msg] $msg } {1 {/ EEXIST}} test winFCmd-7.15 {TraverseWinTree: append \ to target if necessary} -setup { cleanup } -constraints {pcOnly nt} -body { file mkdir td1 testfile cpdir td1 / } -cleanup { cleanup # Windows7 returns EEXIST, XP returns EACCES } -returnCodes error -match regexp -result {^/ E(ACCES|EXIST)$} test winFCmd-7.16 {TraverseWinTree: recurse on files: no files} {pcOnly} { cleanup file mkdir td1 testfile cpdir td1 td2 } {} test winFCmd-7.17 {TraverseWinTree: recurse on files: one file} {pcOnly} { cleanup file mkdir td1 createfile td1/td2 testfile cpdir td1 td2 glob td2/* } {td2/td2} test winFCmd-7.18 {TraverseWinTree: recurse on files: several files and dir} \ {pcOnly} { cleanup file mkdir td1 createfile td1/tf1 createfile td1/tf2 file mkdir td1/td2/td3 createfile td1/tf3 createfile td1/tf4 testfile cpdir td1 td2 lsort [glob td2/*] } {td2/td2 td2/tf1 td2/tf2 td2/tf3 td2/tf4} test winFCmd-7.19 {TraverseWinTree: call TraversalCopy: DOTREE_POSTD} {pcOnly} { cleanup file mkdir td1 createfile td1/tf1 tf1 testchmod 000 td1 catch { testfile cpdir td1 td2 list [file exists td2] [file writable td2] } r catch { testchmod 777 td1 cleanup } set r } {1 1} test winFCmd-7.20 {TraverseWinTree: call TraversalDelete: DOTREE_POSTD} \ {pcOnly} { cleanup file mkdir td1 createfile td1/tf1 tf1 testfile rmdir -force td1 file exists td1 } {0} test winFCmd-7.21 {TraverseWinTree: fill errorPtr} {pcOnly} { cleanup list [catch {testfile cpdir td1 td2} msg] $msg } {1 {td1 ENOENT}} test winFCmd-8.1 {TraversalCopy: DOTREE_F} {pcOnly} { cleanup file mkdir td1 list [catch {testfile cpdir td1 td1} msg] $msg } {1 {td1 EEXIST}} test winFCmd-8.2 {TraversalCopy: DOTREE_PRED} {pcOnly} { cleanup file mkdir td1/td2 testchmod 000 td1 catch { testfile cpdir td1 td2 list [file writable td1] [file writable td1/td2] } r catch { testchmod 777 td1 cleanup } set r } {0 1} test winFCmd-8.3 {TraversalCopy: DOTREE_POSTD} {pcOnly} { cleanup file mkdir td1 testfile cpdir td1 td2 } {} test winFCmd-9.1 {TraversalDelete: DOTREE_F} {pcOnly} { cleanup file mkdir td1 createfile td1/tf1 testfile rmdir -force td1 } {} test winFCmd-9.2 {TraversalDelete: DOTREE_F} {pcOnly 95} { cleanup file mkdir td1 set fd [open td1/tf1 w] set msg [list [catch {testfile rmdir -force td1} msg] $msg] close $fd set msg } {1 {td1\tf1 EACCES}} test winFCmd-9.3 {TraversalDelete: DOTREE_PRED} {pcOnly} { cleanup file mkdir td1/td2 testchmod 000 td1 catch { testfile rmdir -force td1 file exists td1 } r catch { testchmod 777 td1 cleanup } set r } {0} test winFCmd-9.4 {TraversalDelete: DOTREE_POSTD} {pcOnly} { cleanup file mkdir td1/td1/td3/td4/td5 testfile rmdir -force td1 } {} test winFCmd-10.1 {AttributesPosixError - get} {pcOnly} { cleanup list [catch {file attributes td1 -archive} msg] $msg } {1 {could not read "td1": no such file or directory}} test winFCmd-10.2 {AttributesPosixError - set} {pcOnly} { cleanup list [catch {file attributes td1 -archive 0} msg] $msg } {1 {could not read "td1": no such file or directory}} test winFCmd-11.1 {GetWinFileAttributes} {pcOnly} { cleanup close [open td1 w] list [catch {file attributes td1 -archive} msg] $msg [cleanup] } {0 1 {}} test winFCmd-11.2 {GetWinFileAttributes} {pcOnly} { cleanup close [open td1 w] list [catch {file attributes td1 -readonly} msg] $msg [cleanup] } {0 0 {}} test winFCmd-11.3 {GetWinFileAttributes} {pcOnly} { cleanup close [open td1 w] list [catch {file attributes td1 -hidden} msg] $msg [cleanup] } {0 0 {}} test winFCmd-11.4 {GetWinFileAttributes} {pcOnly} { cleanup close [open td1 w] list [catch {file attributes td1 -system} msg] $msg [cleanup] } {0 0 {}} test winFCmd-11.5 {GetWinFileAttributes} {pcOnly} { # attr of relative paths that resolve to root was failing # don't care about answer, just that test runs. set old [pwd] cd c:/ file attr c: file attr c:. file attr . cd $old } {} test winFCmd-11.6 {GetWinFileAttributes} {pcOnly} { file attr c:/ -hidden } {0} test winFCmd-12.1 {ConvertFileNameFormat} {pcOnly} { cleanup close [open td1 w] list [catch {string tolower [file attributes td1 -longname]} msg] $msg [cleanup] } {0 td1 {}} test winFCmd-12.2 {ConvertFileNameFormat} {pcOnly} { cleanup file mkdir td1 close [open td1/td1 w] list [catch {string tolower [file attributes td1/td1 -longname]} msg] $msg [cleanup] } {0 td1/td1 {}} test winFCmd-12.3 {ConvertFileNameFormat} {pcOnly} { cleanup file mkdir td1 file mkdir td1/td2 close [open td1/td3 w] list [catch {string tolower [file attributes td1/td2/../td3 -longname]} msg] $msg [cleanup] } {0 td1/td2/../td3 {}} test winFCmd-12.4 {ConvertFileNameFormat} {pcOnly} { cleanup close [open td1 w] list [catch {string tolower [file attributes ./td1 -longname]} msg] $msg [cleanup] } {0 ./td1 {}} test winFCmd-12.5 {ConvertFileNameFormat: absolute path} {pcOnly} { list [file attributes / -longname] [file attributes \\ -longname] } {/ /} test winFCmd-12.6 {ConvertFileNameFormat: absolute path with drive} {pcOnly} { catch {file delete -force -- c:/td1} close [open c:/td1 w] list [catch {string tolower [file attributes c:/td1 -longname]} msg] $msg [file delete -force -- c:/td1] } {0 c:/td1 {}} test winFCmd-12.7 {ConvertFileNameFormat} {nonPortable pcOnly} { string tolower [file attributes //bisque/tcl/ws -longname] } {//bisque/tcl/ws} test winFCmd-12.8 {ConvertFileNameFormat} {pcOnly longFileNames} { cleanup close [open td1 w] list [catch {string tolower [file attributes td1 -longname]} msg] $msg [cleanup] } {0 td1 {}} test winFCmd-12.10 {ConvertFileNameFormat} {longFileNames pcOnly} { cleanup close [open td1td1td1 w] list [catch {file attributes td1td1td1 -shortname}] [cleanup] } {0 {}} test winFCmd-12.11 {ConvertFileNameFormat} {longFileNames pcOnly} { cleanup close [open td1 w] list [catch {string tolower [file attributes td1 -shortname]} msg] $msg [cleanup] } {0 td1 {}} test winFCmd-13.1 {GetWinFileLongName} {pcOnly} { cleanup close [open td1 w] list [catch {string tolower [file attributes td1 -longname]} msg] $msg [cleanup] } {0 td1 {}} test winFCmd-14.1 {GetWinFileShortName} {pcOnly} { cleanup close [open td1 w] list [catch {string tolower [file attributes td1 -shortname]} msg] $msg [cleanup] } {0 td1 {}} test winFCmd-15.1 {SetWinFileAttributes} {pcOnly} { cleanup list [catch {file attributes td1 -archive 0} msg] $msg } {1 {could not read "td1": no such file or directory}} test winFCmd-15.2 {SetWinFileAttributes - archive} {pcOnly} { cleanup close [open td1 w] list [catch {file attributes td1 -archive 1} msg] $msg [file attributes td1 -archive] [cleanup] } {0 {} 1 {}} test winFCmd-15.3 {SetWinFileAttributes - archive} {pcOnly} { cleanup close [open td1 w] list [catch {file attributes td1 -archive 0} msg] $msg [file attributes td1 -archive] [cleanup] } {0 {} 0 {}} test winFCmd-15.4 {SetWinFileAttributes - hidden} {pcOnly} { cleanup close [open td1 w] list [catch {file attributes td1 -hidden 1} msg] $msg [file attributes td1 -hidden] [file attributes td1 -hidden 0] [cleanup] } {0 {} 1 {} {}} test winFCmd-15.5 {SetWinFileAttributes - hidden} {pcOnly} { cleanup close [open td1 w] list [catch {file attributes td1 -hidden 0} msg] $msg [file attributes td1 -hidden] [cleanup] } {0 {} 0 {}} test winFCmd-15.6 {SetWinFileAttributes - readonly} {pcOnly} { cleanup close [open td1 w] list [catch {file attributes td1 -readonly 1} msg] $msg [file attributes td1 -readonly] [cleanup] } {0 {} 1 {}} test winFCmd-15.7 {SetWinFileAttributes - readonly} {pcOnly} { cleanup close [open td1 w] list [catch {file attributes td1 -readonly 0} msg] $msg [file attributes td1 -readonly] [cleanup] } {0 {} 0 {}} test winFCmd-15.8 {SetWinFileAttributes - system} {pcOnly} { cleanup close [open td1 w] list [catch {file attributes td1 -system 1} msg] $msg [file attributes td1 -system] [cleanup] } {0 {} 1 {}} test winFCmd-15.9 {SetWinFileAttributes - system} {pcOnly} { cleanup close [open td1 w] list [catch {file attributes td1 -system 0} msg] $msg [file attributes td1 -system] [cleanup] } {0 {} 0 {}} test winFCmd-15.10 {SetWinFileAttributes - failing} {pcOnly cdrom} { cleanup catch {file attributes $cdfile -archive 1} } {1} test winFCmd-16.1 {Windows file normalization} {pcOnly} { list [file normalize c:/] [file normalize C:/] } {C:/ C:/} test winFCmd-16.2 {Windows file normalization} {pcOnly} { close [open td1... w] set res [file tail [file normalize td1]] file delete td1... set res } {td1} set pwd [pwd] set d [string index $pwd 0] test winFCmd-16.3 {Windows file normalization} {pcOnly} { file norm ${d}:foo } [file join $pwd foo] test winFCmd-16.4 {Windows file normalization} {pcOnly} { file norm [string tolower ${d}]:foo } [file join $pwd foo] test winFCmd-16.5 {Windows file normalization} {pcOnly} { file norm ${d}:foo/bar } [file join $pwd foo/bar] test winFCmd-16.6 {Windows file normalization} {pcOnly} { file norm ${d}:foo\\bar } [file join $pwd foo/bar] test winFCmd-16.7 {Windows file normalization} {pcOnly} { file norm /bar } "${d}:/bar" test winFCmd-16.8 {Windows file normalization} {pcOnly} { file norm ///bar } "${d}:/bar" test winFCmd-16.9 {Windows file normalization} {pcOnly} { file norm /bar/foo } "${d}:/bar/foo" if {$d eq "C"} { set dd "D" } else { set dd "C" } test winFCmd-16.10 {Windows file normalization} {pcOnly} { file norm ${dd}:foo } "${dd}:/foo" test winFCmd-16.11 {Windows file normalization} {pcOnly cdrom} { cd ${d}: cd $cdrom cd ${d}: cd $cdrom # Must not crash set result "no crash" } {no crash} test winFCmd-16.12 {Windows file normalization} {pcOnly} { set oldhome "" catch {set oldhome $::env(HOME)} set ::env(HOME) ${d}: cd set result [pwd]; # <- Must not crash set ::env(HOME) $oldhome set result } ${d}:/ cd $pwd unset d dd pwd test winFCmd-18.1 {Windows reserved path names} -constraints win -body { file pathtype com1 } -result "absolute" test winFCmd-18.1.2 {Windows reserved path names} -constraints win -body { file pathtype com4 } -result "absolute" test winFCmd-18.1.3 {Windows reserved path names} -constraints win -body { file pathtype com5 } -result "relative" test winFCmd-18.1.4 {Windows reserved path names} -constraints win -body { file pathtype lpt3 } -result "absolute" test winFCmd-18.1.5 {Windows reserved path names} -constraints win -body { file pathtype lpt4 } -result "relative" test winFCmd-18.1.6 {Windows reserved path names} -constraints win -body { file pathtype nul } -result "absolute" test winFCmd-18.1.7 {Windows reserved path names} -constraints win -body { file pathtype null } -result "relative" test winFCmd-18.2 {Windows reserved path names} -constraints win -body { file pathtype com1: } -result "absolute" test winFCmd-18.3 {Windows reserved path names} -constraints win -body { file pathtype COM1 } -result "absolute" test winFCmd-18.4 {Windows reserved path names} -constraints win -body { file pathtype CoM1: } -result "absolute" test winFCmd-18.5 {Windows reserved path names} -constraints win -body { file normalize com1: } -result COM1 test winFCmd-18.6 {Windows reserved path names} -constraints win -body { file normalize COM1: } -result COM1 test winFCmd-18.7 {Windows reserved path names} -constraints win -body { file normalize cOm1 } -result COM1 test winFCmd-18.8 {Windows reserved path names} -constraints win -body { file normalize cOm1: } -result COM1 # This block of code used to occur after the "return" call, so I'm # commenting it out and assuming that this code is still under construction. #foreach source {tef ted tnf tnd "" nul com1} { # foreach chmodsrc {000 755} { # foreach dest "tfn tfe tdn tdempty tdfull td1/td2 $p $p/td1 {} nul" { # foreach chmoddst {000 755} { # puts hi # cleanup # file delete -force ted tef # file mkdir ted # createfile tef # createfile tfe # file mkdir tdempty # file mkdir tdfull/td1/td2 # # catch {testchmod $chmodsrc $source} # catch {testchmod $chmoddst $dest} # # if [catch {file rename $source $dest} msg] { # puts "file rename $source ($chmodsrc) $dest ($chmoddst)" # puts $msg # } # } # } # } #} # cleanup cleanup ::tcltest::cleanupTests return # Local Variables: # mode: tcl # End: tcl8.4.20/tests/while-old.test0000644003604700454610000000644011737050674014652 0ustar dgp771div# Commands covered: while # # This file contains the original set of tests for Tcl's while command. # Since the while command is now compiled, a new set of tests covering # the new implementation is in the file "while.test". Sourcing this file # into Tcl runs the tests and generates output for errors. # No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994-1996 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } test while-old-1.1 {basic while loops} { set count 0 while {$count < 10} {set count [expr $count+1]} set count } 10 test while-old-1.2 {basic while loops} { set value xxx while {2 > 3} {set value yyy} set value } xxx test while-old-1.3 {basic while loops} { set value 1 while {"true"} { incr value; if {$value > 5} { break; } } set value } 6 test while-old-1.4 {basic while loops, multiline test expr} { set value 1 while {($tcl_platform(platform) != "foobar1") && \ ($tcl_platform(platform) != "foobar2")} { incr value break } set value } {2} test while-old-1.5 {basic while loops, test expr in quotes} { set value 1 while "0 < 3" {set value 2; break} set value } {2} test while-old-2.1 {continue in while loop} { set list {1 2 3 4 5} set index 0 set result {} while {$index < 5} { if {$index == 2} {set index [expr $index+1]; continue} set result [concat $result [lindex $list $index]] set index [expr $index+1] } set result } {1 2 4 5} test while-old-3.1 {break in while loop} { set list {1 2 3 4 5} set index 0 set result {} while {$index < 5} { if {$index == 3} break set result [concat $result [lindex $list $index]] set index [expr $index+1] } set result } {1 2 3} test while-old-4.1 {errors in while loops} { set err [catch {while} msg] list $err $msg } {1 {wrong # args: should be "while test command"}} test while-old-4.2 {errors in while loops} { set err [catch {while 1} msg] list $err $msg } {1 {wrong # args: should be "while test command"}} test while-old-4.3 {errors in while loops} { set err [catch {while 1 2 3} msg] list $err $msg } {1 {wrong # args: should be "while test command"}} test while-old-4.4 {errors in while loops} { set err [catch {while {"a"+"b"} {error "loop aborted"}} msg] list $err $msg } {1 {can't use non-numeric string as operand of "+"}} test while-old-4.5 {errors in while loops} { catch {unset x} set x 1 set err [catch {while {$x} {set x foo}} msg] list $err $msg } {1 {expected boolean value but got "foo"}} test while-old-4.6 {errors in while loops} { set err [catch {while {1} {error "loop aborted"}} msg] list $err $msg $errorInfo } {1 {loop aborted} {loop aborted while executing "error "loop aborted""}} test while-old-5.1 {while return result} { while {0} {set a 400} } {} test while-old-5.2 {while return result} { set x 1 while {$x} {set x 0} } {} # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/async.test0000644003604700454610000000744011737050674014104 0ustar dgp771div# Commands covered: none # # This file contains a collection of tests for Tcl_AsyncCreate and related # library procedures. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1993 The Regents of the University of California. # Copyright (c) 1994-1996 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } if {[info commands testasync] == {}} { puts "This application hasn't been compiled with the \"testasync\"" puts "command, so I can't test Tcl_AsyncCreate et al." ::tcltest::cleanupTests return } proc async1 {result code} { global aresult acode set aresult $result set acode $code return "new result" } proc async2 {result code} { global aresult acode set aresult $result set acode $code return -code error "xyzzy" } proc async3 {result code} { global aresult set aresult "test pattern" return -code $code $result } set handler1 [testasync create async1] set handler2 [testasync create async2] set handler3 [testasync create async3] test async-1.1 {basic async handlers} { set aresult xxx set acode yyy list [catch {testasync mark $handler1 "original" 0} msg] $msg \ $acode $aresult } {0 {new result} 0 original} test async-1.2 {basic async handlers} { set aresult xxx set acode yyy list [catch {testasync mark $handler1 "original" 1} msg] $msg \ $acode $aresult } {0 {new result} 1 original} test async-1.3 {basic async handlers} { set aresult xxx set acode yyy list [catch {testasync mark $handler2 "old" 0} msg] $msg \ $acode $aresult } {1 xyzzy 0 old} test async-1.4 {basic async handlers} { set aresult xxx set acode yyy list [catch {testasync mark $handler2 "old" 3} msg] $msg \ $acode $aresult } {1 xyzzy 3 old} test async-1.5 {basic async handlers} { set aresult xxx list [catch {testasync mark $handler3 "foobar" 0} msg] $msg $aresult } {0 foobar {test pattern}} test async-1.6 {basic async handlers} { set aresult xxx list [catch {testasync mark $handler3 "foobar" 1} msg] $msg $aresult } {1 foobar {test pattern}} proc mult1 {result code} { global x lappend x mult1 return -code 7 mult1 } set hm1 [testasync create mult1] proc mult2 {result code} { global x lappend x mult2 return -code 9 mult2 } set hm2 [testasync create mult2] proc mult3 {result code} { global x hm1 hm2 lappend x [catch {testasync mark $hm2 serial2 0}] lappend x [catch {testasync mark $hm1 serial1 0}] lappend x mult3 return -code 11 mult3 } set hm3 [testasync create mult3] test async-2.1 {multiple handlers} { set x {} list [catch {testasync mark $hm3 "foobar" 5} msg] $msg $x } {9 mult2 {0 0 mult3 mult1 mult2}} proc del1 {result code} { global x hm1 hm2 hm3 hm4 lappend x [catch {testasync mark $hm3 serial2 0}] lappend x [catch {testasync mark $hm1 serial1 0}] lappend x [catch {testasync mark $hm4 serial1 0}] testasync delete $hm1 testasync delete $hm2 testasync delete $hm3 lappend x del1 return -code 13 del1 } proc del2 {result code} { global x lappend x del2 return -code 3 del2 } testasync delete $handler1 testasync delete $hm2 testasync delete $hm3 set hm2 [testasync create del1] set hm3 [testasync create mult2] set hm4 [testasync create del2] test async-3.1 {deleting handlers} { set x {} list [catch {testasync mark $hm2 "foobar" 5} msg] $msg $x } {3 del2 {0 0 0 del1 del2}} # cleanup testasync delete ::tcltest::cleanupTests return tcl8.4.20/tests/winFile.test0000644003604700454610000000447011737050674014364 0ustar dgp771div# This file tests the tclWinFile.c file. # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1997 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } test winFile-1.1 {TclpGetUserHome} {pcOnly} { list [catch {glob ~nosuchuser} msg] $msg } {1 {user "nosuchuser" doesn't exist}} test winFile-1.2 {TclpGetUserHome} {pcOnly nt nonPortable} { # The administrator account should always exist. catch {glob ~administrator} } {0} test winFile-1.3 {TclpGetUserHome} {pcOnly 95} { # Find some user in system.ini and then see if they have a home. set f [open $::env(windir)/system.ini] set x 0 while {![eof $f]} { set line [gets $f] if {$line == "\[Password Lists]"} { gets $f set name [lindex [split [gets $f] =] 0] if {$name != ""} { set x [catch {glob ~$name}] break } } } close $f set x } {0} test winFile-1.4 {TclpGetUserHome} {pcOnly nt nonPortable} { catch {glob ~stanton@workgroup} } {0} test winFile-2.1 {TclpMatchFiles: case sensitivity} {pcOnly} { makeFile {} GlobCapS set result [list [glob -nocomplain GlobC*] [glob -nocomplain globc*]] removeFile GlobCapS set result } {GlobCapS GlobCapS} test winFile-2.2 {TclpMatchFiles: case sensitivity} {pcOnly} { makeFile {} globlower set result [list [glob -nocomplain globl*] [glob -nocomplain gLOBl*]] removeFile globlower set result } {globlower globlower} test winFile-3.1 {file system} {pcOnly} { set res "volume types ok" foreach vol [file volumes] { # Have to catch in case there is a removable drive (CDROM, floppy) # with nothing in it. catch { if {![string equal [lindex [file system $vol] 1] [testvolumetype $vol]]} { set res "For $vol, we found [file system $vol]\ and [testvolumetype $vol] are different" break } } } set res } {volume types ok} # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/for.test0000644003604700454610000005640511737050674013562 0ustar dgp771div# Commands covered: for, continue, break # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1996 Sun Microsystems, Inc. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } # Basic "for" operation. test for-1.1 {TclCompileForCmd: missing initial command} { list [catch {for} msg] $msg } {1 {wrong # args: should be "for start test next command"}} test for-1.2 {TclCompileForCmd: error in initial command} { list [catch {for {set}} msg] $msg $errorInfo } {1 {wrong # args: should be "for start test next command"} {wrong # args: should be "for start test next command" while compiling "for {set}"}} catch {unset i} test for-1.3 {TclCompileForCmd: missing test expression} { catch {for {set i 0}} msg set msg } {wrong # args: should be "for start test next command"} test for-1.4 {TclCompileForCmd: error in test expression} { catch {for {set i 0} {$i<}} msg set errorInfo } {wrong # args: should be "for start test next command" while compiling "for {set i 0} {$i<}"} test for-1.5 {TclCompileForCmd: test expression is enclosed in quotes} { set i 0 for {} "$i > 5" {incr i} {} } {} test for-1.6 {TclCompileForCmd: missing "next" command} { catch {for {set i 0} {$i < 5}} msg set msg } {wrong # args: should be "for start test next command"} test for-1.7 {TclCompileForCmd: missing command body} { catch {for {set i 0} {$i < 5} {incr i}} msg set msg } {wrong # args: should be "for start test next command"} test for-1.8 {TclCompileForCmd: error compiling command body} { catch {for {set i 0} {$i < 5} {incr i} {set}} msg set errorInfo } {wrong # args: should be "set varName ?newValue?" while compiling "set" ("for" body line 1) while compiling "for {set i 0} {$i < 5} {incr i} {set}"} catch {unset a} test for-1.9 {TclCompileForCmd: simple command body} { set a {} for {set i 1} {$i<6} {set i [expr $i+1]} { if $i==4 break set a [concat $a $i] } set a } {1 2 3} test for-1.10 {TclCompileForCmd: command body in quotes} { set a {} for {set i 1} {$i<6} {set i [expr $i+1]} "append a x" set a } {xxxxx} test for-1.11 {TclCompileForCmd: computed command body} { catch {unset x1} catch {unset bb} catch {unset x2} set x1 {append a x1; } set bb {break} set x2 {; append a x2} set a {} for {set i 1} {$i<6} {set i [expr $i+1]} $x1$bb$x2 set a } {x1} test for-1.12 {TclCompileForCmd: error in "next" command} { catch {for {set i 0} {$i < 5} {set} {puts $i}} msg set errorInfo } {wrong # args: should be "set varName ?newValue?" while compiling "set" ("for" loop-end command) while compiling "for {set i 0} {$i < 5} {set} {puts $i}"} test for-1.13 {TclCompileForCmd: long command body} { set a {} for {set i 1} {$i<6} {set i [expr $i+1]} { if $i==4 break if $i>5 continue if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } set a [concat $a $i] } set a } {1 2 3} test for-1.14 {TclCompileForCmd: for command result} { set a [for {set i 0} {$i < 5} {incr i} {}] set a } {} test for-1.15 {TclCompileForCmd: for command result} { set a [for {set i 0} {$i < 5} {incr i} {if $i==3 break}] set a } {} # Check "for" and "continue". test for-2.1 {TclCompileContinueCmd: arguments after "continue"} { catch {continue foo} msg set msg } {wrong # args: should be "continue"} test for-2.2 {TclCompileContinueCmd: continue result} { catch continue } 4 test for-2.3 {continue tests} { set a {} for {set i 1} {$i <= 4} {set i [expr $i+1]} { if {$i == 2} continue set a [concat $a $i] } set a } {1 3 4} test for-2.4 {continue tests} { set a {} for {set i 1} {$i <= 4} {set i [expr $i+1]} { if {$i != 2} continue set a [concat $a $i] } set a } {2} test for-2.5 {continue tests, nested loops} { set msg {} for {set i 1} {$i <= 4} {incr i} { for {set a 1} {$a <= 2} {incr a} { if {$i>=2 && $a>=2} continue set msg [concat $msg "$i.$a"] } } set msg } {1.1 1.2 2.1 3.1 4.1} test for-2.6 {continue tests, long command body} { set a {} for {set i 1} {$i<6} {set i [expr $i+1]} { if $i==2 continue if $i==4 break if $i>5 continue if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } set a [concat $a $i] } set a } {1 3} # Check "for" and "break". test for-3.1 {TclCompileBreakCmd: arguments after "break"} { catch {break foo} msg set msg } {wrong # args: should be "break"} test for-3.2 {TclCompileBreakCmd: break result} { catch break } 3 test for-3.3 {break tests} { set a {} for {set i 1} {$i <= 4} {incr i} { if {$i == 3} break set a [concat $a $i] } set a } {1 2} test for-3.4 {break tests, nested loops} { set msg {} for {set i 1} {$i <= 4} {incr i} { for {set a 1} {$a <= 2} {incr a} { if {$i>=2 && $a>=2} break set msg [concat $msg "$i.$a"] } } set msg } {1.1 1.2 2.1 3.1 4.1} test for-3.5 {break tests, long command body} { set a {} for {set i 1} {$i<6} {set i [expr $i+1]} { if $i==2 continue if $i==5 break if $i>5 continue if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if $i==4 break if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } set a [concat $a $i] } set a } {1 3} # A simplified version of exmh's mail formatting routine to stress "for", # "break", "while", and "if". proc formatMail {} { array set lines { 0 {Return-path: george@tcl} \ 1 {Return-path: } \ 2 {Received: from tcl by tcl.Somewhere.COM (SMI-8.6/SMI-SVR4)} \ 3 { id LAA10027; Wed, 11 Sep 1996 11:14:53 -0700} \ 4 {Message-id: <199609111814.LAA10027@tcl.Somewhere.COM>} \ 5 {X-mailer: exmh version 1.6.9 8/22/96} \ 6 {Mime-version: 1.0} \ 7 {Content-type: text/plain; charset=iso-8859-1} \ 8 {Content-transfer-encoding: quoted-printable} \ 9 {Content-length: 2162} \ 10 {To: fred} \ 11 {Subject: tcl7.6} \ 12 {Date: Wed, 11 Sep 1996 11:14:53 -0700} \ 13 {From: George } \ 14 {The Tcl 7.6 and Tk 4.2 releases} \ 15 {} \ 16 {This page contains information about Tcl 7.6 and Tk4.2, which are the most recent} \ 17 {releases of the Tcl scripting language and the Tk toolkit. The first beta versions of these} \ 18 {releases were released on August 30, 1996. These releases contain only minor changes,} \ 19 {so we hope to have only a single beta release and to go final in early October, 1996. } \ 20 {} \ 21 {} \ 22 {What's new } \ 23 {} \ 24 {The most important changes in the releases are summarized below. See the README} \ 25 {and changes files in the distributions for more complete information on what has} \ 26 {changed, including both feature changes and bug fixes. } \ 27 {} \ 28 { There are new options to the file command for copying files (file copy),} \ 29 { deleting files and directories (file delete), creating directories (file} \ 30 { mkdir), and renaming files (file rename). } \ 31 { The implementation of exec has been improved greatly for Windows 95 and} \ 32 { Windows NT. } \ 33 { There is a new memory allocator for the Macintosh version, which should be} \ 34 { more efficient than the old one. } \ 35 { Tk's grid geometry manager has been completely rewritten. The layout} \ 36 { algorithm produces much better layouts than before, especially where rows or} \ 37 { columns were stretchable. } \ 38 { There are new commands for creating common dialog boxes:} \ 39 { tk_chooseColor, tk_getOpenFile, tk_getSaveFile and} \ 40 { tk_messageBox. These use native dialog boxes if they are available. } \ 41 { There is a new virtual event mechanism for handling events in a more portable} \ 42 { way. See the new command event. It also allows events (both physical and} \ 43 { virtual) to be generated dynamically. } \ 44 {} \ 45 {Tcl 7.6 and Tk 4.2 are backwards-compatible with Tcl 7.5 and Tk 4.1 except for} \ 46 {changes in the C APIs for custom channel drivers. Scripts written for earlier releases} \ 47 {should work on these new releases as well. } \ 48 {} \ 49 {Obtaining The Releases} \ 50 {} \ 51 {Binary Releases} \ 52 {} \ 53 {Pre-compiled releases are available for the following platforms: } \ 54 {} \ 55 { Windows 3.1, Windows 95, and Windows NT: Fetch} \ 56 { ftp://ftp.sunlabs.com/pub/tcl/win42b1.exe, then execute it. The file is a} \ 57 { self-extracting executable. It will install the Tcl and Tk libraries, the wish and} \ 58 { tclsh programs, and documentation. } \ 59 { Macintosh (both 68K and PowerPC): Fetch} \ 60 { ftp://ftp.sunlabs.com/pub/tcl/mactk4.2b1.sea.hqx. The file is in binhex format,} \ 61 { which is understood by Fetch, StuffIt, and many other Mac utilities. The} \ 62 { unpacked file is a self-installing executable: double-click on it and it will create a} \ 63 { folder containing all that you need to run Tcl and Tk. } \ 64 { UNIX (Solaris 2.* and SunOS, other systems soon to follow). Easy to install} \ 65 { binary packages are now for sale at the Sun Labs Tcl/Tk Shop. Check it out!} \ } set result "" set NL " " set tag {level= type=text/plain part=0 sel Charset} set ix [lsearch -regexp $tag text/enriched] if {$ix < 0} { set ranges {} set quote 0 } set breakrange {6.42 78.0} set F1 [lindex $breakrange 0] set F2 [lindex $breakrange 1] set breakrange [lrange $breakrange 2 end] if {[string length $F1] == 0} { set F1 -1 set break 0 } else { set break 1 } set xmailer 0 set inheaders 1 set last [array size lines] set plen 2 for {set L 1} {$L < $last} {incr L} { set line $lines($L) if {$inheaders} { # Blank or empty line terminates headers # Leading --- terminates headers if {[regexp {^[ ]*$} $line] || [regexp {^--+} $line]} { set inheaders 0 } if {[regexp -nocase {^x-mailer:} $line]} { continue } } if $inheaders { set limit 55 } else { set limit 55 # Decide whether or not to break the body line if {$plen > 0} { if {[string first {> } $line] == 0} { # This is quoted text from previous message, don't reformat append result $line $NL if {$quote && !$inheaders} { # Fix from to handle text/enriched if {$L > $L1 && $L < $L2 && $line != {}} { # enriched requires two newlines for each one. append result $NL } elseif {$L > $L2} { set L1 [lindex $ranges 0] set L2 [lindex $ranges 1] set ranges [lrange $ranges 2 end] set quote [llength $L1] } } continue } } if {$F1 < 0} { # Nothing left to format append result $line $NL continue } elseif {$L < $F1} { # Not yet to formatted block append result $line $NL continue } elseif {$L > $F2} { # Past formatted block set F1 [lindex $breakrange 0] set F2 [lindex $breakrange 1] set breakrange [lrange $breakrange 2 end] append result $line $NL if {[string length $F1] == 0} { set F1 -1 } continue } } set climit [expr $limit-1] set cutoff 50 set continuation 0 while {[string length $line] > $limit} { for {set c [expr $limit-1]} {$c >= $cutoff} {incr c -1} { set char [string index $line $c] if {$char == " " || $char == "\t"} { break } if {$char == ">"} { ;# Hack for enriched formatting break } } if {$c < $cutoff} { if {! $inheaders} { set c [expr $limit-1] } else { set c [string length $line] } } set newline [string range $line 0 $c] if {! $continuation} { append result $newline $NL } else { append result \ $newline $NL } incr c set line [string trimright [string range $line $c end]] if {$inheaders} { set continuation 1 set limit $climit } } if {$continuation} { if {[string length $line] != 0} { append result \ $line $NL } } else { append result $line $NL if {$quote && !$inheaders} { if {$L > $L1 && $L < $L2 && $line != {}} { # enriched requires two newlines for each one. append result "" $NL } elseif {$L > $L2} { set L1 [lindex $ranges 0] set L2 [lindex $ranges 1] set ranges [lrange $ranges 2 end] set quote [llength $L1] } } } } return $result } test for-3.6 {break tests} { formatMail } {Return-path: Received: from tcl by tcl.Somewhere.COM (SMI-8.6/SMI-SVR4) id LAA10027; Wed, 11 Sep 1996 11:14:53 -0700 Message-id: <199609111814.LAA10027@tcl.Somewhere.COM> Mime-version: 1.0 Content-type: text/plain; charset=iso-8859-1 Content-transfer-encoding: quoted-printable Content-length: 2162 To: fred Subject: tcl7.6 Date: Wed, 11 Sep 1996 11:14:53 -0700 From: George The Tcl 7.6 and Tk 4.2 releases This page contains information about Tcl 7.6 and Tk4.2, which are the most recent releases of the Tcl scripting language and the Tk toolk it. The first beta versions of these releases were released on August 30, 1996. These releas es contain only minor changes, so we hope to have only a single beta release and to go final in early October, 1996. What's new The most important changes in the releases are summariz ed below. See the README and changes files in the distributions for more complet e information on what has changed, including both feature changes and bug fixes. There are new options to the file command for copying files (file copy), deleting files and directories (file delete), creating directories (file mkdir), and renaming files (file rename). The implementation of exec has been improved great ly for Windows 95 and Windows NT. There is a new memory allocator for the Macintosh version, which should be more efficient than the old one. Tk's grid geometry manager has been completely rewritten. The layout algorithm produces much better layouts than before , especially where rows or columns were stretchable. There are new commands for creating common dialog boxes: tk_chooseColor, tk_getOpenFile, tk_getSaveFile and tk_messageBox. These use native dialog boxes if they are available. There is a new virtual event mechanism for handlin g events in a more portable way. See the new command event. It also allows events (both physical and virtual) to be generated dynamically. Tcl 7.6 and Tk 4.2 are backwards-compatible with Tcl 7.5 and Tk 4.1 except for changes in the C APIs for custom channel drivers. Scrip ts written for earlier releases should work on these new releases as well. Obtaining The Releases Binary Releases Pre-compiled releases are available for the following platforms: Windows 3.1, Windows 95, and Windows NT: Fetch ftp://ftp.sunlabs.com/pub/tcl/win42b1.exe, then execute it. The file is a self-extracting executable. It will install the Tcl and Tk libraries, the wish and tclsh programs, and documentation. Macintosh (both 68K and PowerPC): Fetch ftp://ftp.sunlabs.com/pub/tcl/mactk4.2b1.sea.hqx. The file is in binhex format, which is understood by Fetch, StuffIt, and many other Mac utilities. The unpacked file is a self-installing executable: double-click on it and it will create a folder containing all that you need to run Tcl and Tk. UNIX (Solaris 2.* and SunOS, other systems soon to follow). Easy to install binary packages are now for sale at the Sun Labs Tcl/Tk Shop. Check it out! } # Check that "break" resets the interpreter's result test for-4.1 {break must reset the interp result} { catch { set z GLOBTESTDIR/dir2/file2.c if [string match GLOBTESTDIR/dir2/* $z] { break } } j set j } {} # Test for incorrect "double evaluation" semantics test for-5.1 {possible delayed substitution of increment command} { # Increment should be 5, and lappend should always append $a catch {unset a} catch {unset i} set a 5 set i {} for {set a 1} {$a < 12} "incr a $a" {lappend i $a} set i } {1 6 11} test for-5.2 {possible delayed substitution of increment command} { # Increment should be 5, and lappend should always append $a catch {rename p ""} proc p {} { set a 5 set i {} for {set a 1} {$a < 12} "incr a $a" {lappend i $a} set i } p } {1 6 11} test for-5.3 {possible delayed substitution of body command} { # Increment should be $a, and lappend should always append 5 set a 5 set i {} for {set a 1} {$a < 12} {incr a $a} "lappend i $a" set i } {5 5 5 5} test for-5.4 {possible delayed substitution of body command} { # Increment should be $a, and lappend should always append 5 catch {rename p ""} proc p {} { set a 5 set i {} for {set a 1} {$a < 12} {incr a $a} "lappend i $a" set i } p } {5 5 5 5} # In the following tests we need to bypass the bytecode compiler by # substituting the command from a variable. This ensures that command # procedure is invoked directly. test for-6.1 {Tcl_ForObjCmd: number of args} { set z for catch {$z} msg set msg } {wrong # args: should be "for start test next command"} test for-6.2 {Tcl_ForObjCmd: number of args} { set z for catch {$z {set i 0}} msg set msg } {wrong # args: should be "for start test next command"} test for-6.3 {Tcl_ForObjCmd: number of args} { set z for catch {$z {set i 0} {$i < 5}} msg set msg } {wrong # args: should be "for start test next command"} test for-6.4 {Tcl_ForObjCmd: number of args} { set z for catch {$z {set i 0} {$i < 5} {incr i}} msg set msg } {wrong # args: should be "for start test next command"} test for-6.5 {Tcl_ForObjCmd: number of args} { set z for catch {$z {set i 0} {$i < 5} {incr i} {body} extra} msg set msg } {wrong # args: should be "for start test next command"} test for-6.6 {Tcl_ForObjCmd: error in initial command} { set z for list [catch {$z {set} {$i < 5} {incr i} {body}} msg] $msg $errorInfo } {1 {wrong # args: should be "set varName ?newValue?"} {wrong # args: should be "set varName ?newValue?" while compiling "set" ("for" initial command) invoked from within "$z {set} {$i < 5} {incr i} {body}"}} test for-6.7 {Tcl_ForObjCmd: error in test expression} { set z for list [catch {$z {set i 0} {i < 5} {incr i} {body}} msg] $msg $errorInfo } {1 {syntax error in expression "i < 5": variable references require preceding $} {syntax error in expression "i < 5": variable references require preceding $ while executing "$z {set i 0} {i < 5} {incr i} {body}"}} test for-6.8 {Tcl_ForObjCmd: test expression is enclosed in quotes} { set z for set i 0 $z {set i 6} "$i > 5" {incr i} {set y $i} set i } 6 test for-6.9 {Tcl_ForObjCmd: error executing command body} { set z for catch {$z {set i 0} {$i < 5} {incr i} {set}} msg set errorInfo } {wrong # args: should be "set varName ?newValue?" while compiling "set" ("for" body line 1) invoked from within "$z {set i 0} {$i < 5} {incr i} {set}"} test for-6.10 {Tcl_ForObjCmd: simple command body} { set z for set a {} $z {set i 1} {$i<6} {set i [expr $i+1]} { if $i==4 break set a [concat $a $i] } set a } {1 2 3} test for-6.11 {Tcl_ForObjCmd: command body in quotes} { set z for set a {} $z {set i 1} {$i<6} {set i [expr $i+1]} "append a x" set a } {xxxxx} test for-6.12 {Tcl_ForObjCmd: computed command body} { set z for catch {unset x1} catch {unset bb} catch {unset x2} set x1 {append a x1; } set bb {break} set x2 {; append a x2} set a {} $z {set i 1} {$i<6} {set i [expr $i+1]} $x1$bb$x2 set a } {x1} test for-6.13 {Tcl_ForObjCmd: error in "next" command} { set z for catch {$z {set i 0} {$i < 5} {set} {set j 4}} msg set errorInfo } {wrong # args: should be "set varName ?newValue?" while compiling "set" ("for" loop-end command) invoked from within "$z {set i 0} {$i < 5} {set} {set j 4}"} test for-6.14 {Tcl_ForObjCmd: long command body} { set z for set a {} $z {set i 1} {$i<6} {set i [expr $i+1]} { if $i==4 break if $i>5 continue if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } set a [concat $a $i] } set a } {1 2 3} test for-6.15 {Tcl_ForObjCmd: for command result} { set z for set a [$z {set i 0} {$i < 5} {incr i} {}] set a } {} test for-6.16 {Tcl_ForObjCmd: for command result} { set z for set a [$z {set i 0} {$i < 5} {incr i} {if $i==3 break}] set a } {} # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/dcall.test0000644003604700454610000000262711737050674014050 0ustar dgp771div# Commands covered: none # # This file contains a collection of tests for Tcl_CallWhenDeleted. # Sourcing this file into Tcl runs the tests and generates output for # errors. No output means no errors were found. # # Copyright (c) 1993 The Regents of the University of California. # Copyright (c) 1994 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } if {[info commands testdcall] == {}} { puts "This application hasn't been compiled with the \"testdcall\"" puts "command, so I can't test Tcl_CallWhenDeleted." ::tcltest::cleanupTests return } test dcall-1.1 {deletion callbacks} { lsort -increasing [testdcall 1 2 3] } {1 2 3} test dcall-1.2 {deletion callbacks} { testdcall } {} test dcall-1.3 {deletion callbacks} { lsort -increasing [testdcall 20 21 22 -22] } {20 21} test dcall-1.4 {deletion callbacks} { lsort -increasing [testdcall 20 21 22 -20] } {21 22} test dcall-1.5 {deletion callbacks} { lsort -increasing [testdcall 20 21 22 -21] } {20 22} test dcall-1.6 {deletion callbacks} { lsort -increasing [testdcall 20 21 22 -21 -22 -20] } {} # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/fCmd.test0000644003604700454610000023240012133546540013625 0ustar dgp771div# This file tests the tclFCmd.c file. # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1996-1997 Sun Microsystems, Inc. # Copyright (c) 1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import -force ::tcltest::* } tcltest::testConstraint testsetplatform [string equal testsetplatform [info commands testsetplatform]] tcltest::testConstraint testchmod [string equal testchmod [info commands testchmod]] tcltest::testConstraint notNetworkFilesystem 0 testConstraint 95or98 [expr {[testConstraint 95] || [testConstraint 98]}] testConstraint 2000orNewer [expr {![testConstraint 95or98]}] testConstraint winVista 0 testConstraint win2000orXP 0 testConstraint winOlderThan2000 0 # Several tests require need to match results against the unix username set user {} if {$tcl_platform(platform) == "unix"} { catch {set user [exec whoami]} if {$user == ""} { catch {regexp {^[^(]*\(([^)]*)\)} [exec id] dummy user} } if {$user == ""} { set user "root" } } # Also used in winFCmd... if {[testConstraint winOnly]} { set major [string index $tcl_platform(osVersion) 0] if {[testConstraint nt] && $major > 4} { if {$major > 5} { testConstraint winVista 1 } elseif {$major == 5} { testConstraint win2000orXP 1 } } else { testConstraint winOlderThan2000 1 } } proc createfile {file {string a}} { set f [open $file w] puts -nonewline $f $string close $f return $string } # # checkcontent -- # # Ensures that file "file" contains only the string "matchString" # returns 0 if the file does not exist, or has a different content # proc checkcontent {file matchString} { if {[catch { set f [open $file] set fileString [read $f] close $f }]} { return 0 } return [string match $matchString $fileString] } proc openup {path} { testchmod 777 $path if {[file isdirectory $path]} { catch { foreach p [glob -directory $path *] { openup $p } } } } proc cleanup {args} { set wd [list .] foreach p [concat $wd $args] { set x "" catch { set x [glob -directory $p tf* td*] } foreach file $x { if {[catch {file delete -force -- $file}]} { catch {openup $file} catch {file delete -force -- $file} } } } } proc contents {file} { set f [open $file r] set r [read $f] close $f set r } cd [temporaryDirectory] set ::tcltest::testConstraints(fileSharing) 0 set ::tcltest::testConstraints(notFileSharing) 1 set ::tcltest::testConstraints(xdev) 0 if {$tcl_platform(platform) == "unix"} { if {[catch {set m1 [exec df .]; set m2 [exec df /tmp]}] == 0} { set m1 [string range $m1 0 [expr [string first " " $m1]-1]] set m2 [string range $m2 0 [expr [string first " " $m2]-1]] if {$m1 != "" && $m2 != "" && $m1 != $m2 && [file exists $m1] && [file exists $m2]} { set ::tcltest::testConstraints(xdev) 1 } } } set root [lindex [file split [pwd]] 0] # A really long file name # length of long is 1216 chars, which should be greater than any static # buffer or allowable filename. set long "abcdefghihjllmnopqrstuvwxyz01234567890" append long $long append long $long append long $long append long $long append long $long test fCmd-1.1 {TclFileRenameCmd} {notRoot} { cleanup createfile tf1 file rename tf1 tf2 glob tf* } {tf2} test fCmd-2.1 {TclFileCopyCmd} {notRoot} { cleanup createfile tf1 file copy tf1 tf2 lsort [glob tf*] } {tf1 tf2} test fCmd-3.1 {FileCopyRename: FileForceOption fails} {notRoot} { list [catch {file rename -xyz} msg] $msg } {1 {bad option "-xyz": should be -force or --}} test fCmd-3.2 {FileCopyRename: not enough args} {notRoot} { list [catch {file rename xyz} msg] $msg } {1 {wrong # args: should be "file rename ?options? source ?source ...? target"}} test fCmd-3.3 {FileCopyRename: Tcl_TranslateFileName fails} {notRoot} { list [catch {file rename xyz ~_totally_bogus_user} msg] $msg } {1 {user "_totally_bogus_user" doesn't exist}} test fCmd-3.4 {FileCopyRename: Tcl_TranslateFileName passes} {notRoot} { cleanup list [catch {file copy tf1 ~} msg] $msg } {1 {error copying "tf1": no such file or directory}} test fCmd-3.5 {FileCopyRename: target doesn't exist: stat(target) != 0} {notRoot} { cleanup list [catch {file rename tf1 tf2 tf3} msg] $msg } {1 {error renaming: target "tf3" is not a directory}} test fCmd-3.6 {FileCopyRename: target tf3 is not a dir: !S_ISDIR(target)} \ {notRoot} { cleanup createfile tf3 list [catch {file rename tf1 tf2 tf3} msg] $msg } {1 {error renaming: target "tf3" is not a directory}} test fCmd-3.7 {FileCopyRename: target exists & is directory} {notRoot} { cleanup file mkdir td1 createfile tf1 tf1 file rename tf1 td1 contents [file join td1 tf1] } {tf1} test fCmd-3.8 {FileCopyRename: too many arguments: argc - i > 2} {notRoot} { cleanup list [catch {file rename tf1 tf2 tf3} msg] $msg } {1 {error renaming: target "tf3" is not a directory}} test fCmd-3.9 {FileCopyRename: too many arguments: argc - i > 2} {notRoot} { cleanup list [catch {file copy -force -- tf1 tf2 tf3} msg] $msg } {1 {error copying: target "tf3" is not a directory}} test fCmd-3.10 {FileCopyRename: just 2 arguments} {notRoot} { cleanup createfile tf1 tf1 file rename tf1 tf2 contents tf2 } {tf1} test fCmd-3.11 {FileCopyRename: just 2 arguments} {notRoot} { cleanup createfile tf1 tf1 file rename -force -force -- tf1 tf2 contents tf2 } {tf1} test fCmd-3.12 {FileCopyRename: move each source: 1 source} {notRoot} { cleanup createfile tf1 tf1 file mkdir td1 file rename tf1 td1 contents [file join td1 tf1] } {tf1} test fCmd-3.13 {FileCopyRename: move each source: multiple sources} {notRoot} { cleanup createfile tf1 tf1 createfile tf2 tf2 createfile tf3 tf3 createfile tf4 tf4 file mkdir td1 file rename tf1 tf2 tf3 tf4 td1 list [contents [file join td1 tf1]] [contents [file join td1 tf2]] \ [contents [file join td1 tf3]] [contents [file join td1 tf4]] } {tf1 tf2 tf3 tf4} test fCmd-3.14 {FileCopyRename: FileBasename fails} {notRoot} { cleanup file mkdir td1 list [catch {file rename ~_totally_bogus_user td1} msg] $msg } {1 {user "_totally_bogus_user" doesn't exist}} test fCmd-3.15 {FileCopyRename: source[0] == '\0'} {notRoot unixOrPc} { cleanup file mkdir td1 list [catch {file rename / td1} msg] $msg } {1 {error renaming "/" to "td1": file already exists}} test fCmd-3.16 {FileCopyRename: break on first error} {notRoot} { cleanup createfile tf1 createfile tf2 createfile tf3 createfile tf4 file mkdir td1 createfile [file join td1 tf3] list [catch {file rename tf1 tf2 tf3 tf4 td1} msg] $msg } [subst {1 {error renaming "tf3" to "[file join td1 tf3]": file already exists}}] test fCmd-4.1 {TclFileMakeDirsCmd: make each dir: 1 dir} {notRoot} { cleanup file mkdir td1 glob td* } {td1} test fCmd-4.2 {TclFileMakeDirsCmd: make each dir: multiple dirs} {notRoot} { cleanup file mkdir td1 td2 td3 lsort [glob td*] } {td1 td2 td3} test fCmd-4.3 {TclFileMakeDirsCmd: stops on first error} {notRoot} { cleanup createfile tf1 catch {file mkdir td1 td2 tf1 td3 td4} glob td1 td2 tf1 td3 td4 } {td1 td2 tf1} test fCmd-4.4 {TclFileMakeDirsCmd: Tcl_TranslateFileName fails} {notRoot} { cleanup list [catch {file mkdir ~_totally_bogus_user} msg] $msg } {1 {user "_totally_bogus_user" doesn't exist}} test fCmd-4.5 {TclFileMakeDirsCmd: Tcl_SplitPath returns 0: *name == '\0'} \ {notRoot} { cleanup list [catch {file mkdir ""} msg] $msg } {1 {can't create directory "": no such file or directory}} test fCmd-4.6 {TclFileMakeDirsCmd: one level deep} {notRoot} { cleanup file mkdir td1 glob td1 } {td1} test fCmd-4.7 {TclFileMakeDirsCmd: multi levels deep} {notRoot} { cleanup file mkdir [file join td1 td2 td3 td4] glob td1 [file join td1 td2] } "td1 [file join td1 td2]" test fCmd-4.8 {TclFileMakeDirsCmd: already exist: lstat(target) == 0} {notRoot} { cleanup file mkdir td1 set x [file exists td1] file mkdir td1 list $x [file exists td1] } {1 1} test fCmd-4.9 {TclFileMakeDirsCmd: exists, not dir} {notRoot} { cleanup createfile tf1 list [catch {file mkdir tf1} msg] $msg } [subst {1 {can't create directory "[file join tf1]": file already exists}}] test fCmd-4.10 {TclFileMakeDirsCmd: exists, is dir} {notRoot} { cleanup file mkdir td1 set x [file exists td1] file mkdir td1 list $x [file exists td1] } {1 1} test fCmd-4.11 {TclFileMakeDirsCmd: doesn't exist: errno != ENOENT} \ {unixOnly notRoot testchmod} { cleanup file mkdir td1/td2/td3 testchmod 000 td1/td2 set msg [list [catch {file mkdir td1/td2/td3/td4} msg] $msg] testchmod 755 td1/td2 set msg } {1 {can't create directory "td1/td2/td3": permission denied}} test fCmd-4.13 {TclFileMakeDirsCmd: doesn't exist: errno == ENOENT} {notRoot} { cleanup set x [file exists td1] file mkdir td1 list $x [file exists td1] } {0 1} test fCmd-4.14 {TclFileMakeDirsCmd: TclpCreateDirectory fails} \ {unixOnly notRoot} { cleanup file delete -force foo file mkdir foo file attr foo -perm 040000 set result [list [catch {file mkdir foo/tf1} msg] $msg] file delete -force foo set result } {1 {can't create directory "foo/tf1": permission denied}} test fCmd-4.16 {TclFileMakeDirsCmd: TclpCreateDirectory succeeds} {notRoot} { cleanup file mkdir tf1 file exists tf1 } {1} test fCmd-5.1 {TclFileDeleteCmd: FileForceOption fails} {notRoot} { list [catch {file delete -xyz} msg] $msg } {1 {bad option "-xyz": should be -force or --}} test fCmd-5.2 {TclFileDeleteCmd: not enough args} {notRoot} { list [catch {file delete -force -force} msg] $msg } {1 {wrong # args: should be "file delete ?options? file ?file ...?"}} test fCmd-5.3 {TclFileDeleteCmd: 1 file} {notRoot} { cleanup createfile tf1 createfile tf2 file mkdir td1 file delete tf2 glob tf* td* } {tf1 td1} test fCmd-5.4 {TclFileDeleteCmd: multiple files} {notRoot} { cleanup createfile tf1 createfile tf2 file mkdir td1 set x [list [file exists tf1] [file exists tf2] [file exists td1]] file delete tf1 td1 tf2 lappend x [file exists tf1] [file exists tf2] [file exists tf3] } {1 1 1 0 0 0} test fCmd-5.5 {TclFileDeleteCmd: stop at first error} {notRoot unixOrPc} { cleanup createfile tf1 createfile tf2 file mkdir td1 catch {file delete tf1 td1 $root tf2} list [file exists tf1] [file exists tf2] [file exists td1] } {0 1 0} test fCmd-5.6 {TclFileDeleteCmd: Tcl_TranslateFileName fails} {notRoot} { list [catch {file delete ~_totally_bogus_user} msg] $msg } {1 {user "_totally_bogus_user" doesn't exist}} test fCmd-5.7 {TclFileDeleteCmd: Tcl_TranslateFileName succeeds} {notRoot} { catch {file delete ~/tf1} createfile ~/tf1 file delete ~/tf1 } {} test fCmd-5.8 {TclFileDeleteCmd: file doesn't exist: lstat(name) != 0} {notRoot} { cleanup set x [file exists tf1] file delete tf1 list $x [file exists tf1] } {0 0} test fCmd-5.9 {TclFileDeleteCmd: is directory} {notRoot} { cleanup file mkdir td1 file delete td1 file exists td1 } {0} test fCmd-5.10 {TclFileDeleteCmd: TclpRemoveDirectory fails} {notRoot} { cleanup file mkdir [file join td1 td2] list [catch {file delete td1} msg] $msg } {1 {error deleting "td1": directory not empty}} test fCmd-5.11 {TclFileDeleteCmd: TclpRemoveDirectory with cwd inside} {notRoot} { cleanup set dir [pwd] file mkdir [file join td1 td2] cd [file join td1 td2] set res [list [catch {file delete -force [file dirname [pwd]]} msg]] cd $dir lappend res [file exists td1] $msg } {0 0 {}} test fCmd-5.12 {TclFileDeleteCmd: TclpRemoveDirectory with bad perms} {unixOnly} { cleanup file mkdir [file join td1 td2] #exec chmod u-rwx [file join td1 td2] file attributes [file join td1 td2] -permissions u+rwx set res [list [catch {file delete -force td1} msg]] lappend res [file exists td1] $msg } {0 0 {}} test fCmd-6.1 {CopyRenameOneFile: bad source} {notRoot} { # can't test this, because it's caught by FileCopyRename } {} test fCmd-6.2 {CopyRenameOneFile: bad target} {notRoot} { # can't test this, because it's caught by FileCopyRename } {} test fCmd-6.3 {CopyRenameOneFile: lstat(source) != 0} {notRoot} { cleanup list [catch {file rename tf1 tf2} msg] $msg } {1 {error renaming "tf1": no such file or directory}} test fCmd-6.4 {CopyRenameOneFile: lstat(source) == 0} {notRoot} { cleanup createfile tf1 file rename tf1 tf2 glob tf* } {tf2} test fCmd-6.5 {CopyRenameOneFile: lstat(target) != 0} {notRoot} { cleanup createfile tf1 file rename tf1 tf2 glob tf* } {tf2} test fCmd-6.6 {CopyRenameOneFile: errno != ENOENT} {unixOnly notRoot testchmod} { cleanup file mkdir td1 testchmod 000 td1 createfile tf1 set msg [list [catch {file rename tf1 td1} msg] $msg] testchmod 755 td1 set msg } {1 {error renaming "tf1" to "td1/tf1": permission denied}} test fCmd-6.7 {CopyRenameOneFile: errno != ENOENT} {pcOnly 95} { cleanup createfile tf1 list [catch {file rename tf1 $long} msg] $msg } [subst {1 {error renaming "tf1" to "$long": file name too long}}] test fCmd-6.9 {CopyRenameOneFile: errno == ENOENT} {unixOnly notRoot} { cleanup createfile tf1 file rename tf1 tf2 glob tf* } {tf2} test fCmd-6.10 {CopyRenameOneFile: lstat(target) == 0} {notRoot} { cleanup createfile tf1 createfile tf2 list [catch {file rename tf1 tf2} msg] $msg } {1 {error renaming "tf1" to "tf2": file already exists}} test fCmd-6.11 {CopyRenameOneFile: force == 0} {notRoot} { cleanup createfile tf1 createfile tf2 list [catch {file rename tf1 tf2} msg] $msg } {1 {error renaming "tf1" to "tf2": file already exists}} test fCmd-6.12 {CopyRenameOneFile: force != 0} {notRoot} { cleanup createfile tf1 createfile tf2 file rename -force tf1 tf2 glob tf* } {tf2} test fCmd-6.13 {CopyRenameOneFile: source is dir, target is file} {notRoot} { cleanup file mkdir td1 file mkdir td2 createfile [file join td2 td1] list [catch {file rename -force td1 td2} msg] $msg } [subst {1 {can't overwrite file "[file join td2 td1]" with directory "td1"}}] test fCmd-6.14 {CopyRenameOneFile: source is file, target is dir} {notRoot} { cleanup createfile tf1 file mkdir [file join td1 tf1] list [catch {file rename -force tf1 td1} msg] $msg } [subst {1 {can't overwrite directory "[file join td1 tf1]" with file "tf1"}}] test fCmd-6.15 {CopyRenameOneFile: TclpRenameFile succeeds} {notRoot notNetworkFilesystem} { cleanup file mkdir [file join td1 td2] file mkdir td2 createfile [file join td2 tf1] file rename -force td2 td1 file exists [file join td1 td2 tf1] } {1} test fCmd-6.16 {CopyRenameOneFile: TclpCopyRenameOneFile fails} {notRoot} { cleanup file mkdir [file join td1 td2] createfile [file join td1 td2 tf1] file mkdir td2 list [catch {file rename -force td2 td1} msg] $msg } [subst {1 {error renaming "td2" to "[file join td1 td2]": file already exists}}] test fCmd-6.17 {CopyRenameOneFile: errno == EINVAL} {notRoot} { cleanup list [catch {file rename -force $root tf1} msg] $msg } [subst {1 {error renaming "$root" to "tf1": trying to rename a volume or move a directory into itself}}] test fCmd-6.18 {CopyRenameOneFile: errno != EXDEV} {notRoot} { cleanup file mkdir [file join td1 td2] createfile [file join td1 td2 tf1] file mkdir td2 list [catch {file rename -force td2 td1} msg] $msg } [subst {1 {error renaming "td2" to "[file join td1 td2]": file already exists}}] test fCmd-6.19 {CopyRenameOneFile: errno == EXDEV} {unixOnly notRoot} { cleanup /tmp createfile tf1 file rename tf1 /tmp glob tf* /tmp/tf1 } {/tmp/tf1} test fCmd-6.20 {CopyRenameOneFile: errno == EXDEV} {pcOnly} { catch {file delete -force c:/tcl8975@ d:/tcl8975@} file mkdir c:/tcl8975@ if [catch {file rename c:/tcl8975@ d:/}] { set msg d:/tcl8975@ } else { set msg [glob c:/tcl8975@ d:/tcl8975@] file delete -force d:/tcl8975@ } file delete -force c:/tcl8975@ set msg } {d:/tcl8975@} test fCmd-6.21 {CopyRenameOneFile: copy/rename: S_ISDIR(source)} \ {unixOnly notRoot} { cleanup /tmp file mkdir td1 file rename td1 /tmp glob td* /tmp/td* } {/tmp/td1} test fCmd-6.22 {CopyRenameOneFile: copy/rename: !S_ISDIR(source)} \ {unixOnly notRoot} { cleanup /tmp createfile tf1 file rename tf1 /tmp glob tf* /tmp/tf* } {/tmp/tf1} test fCmd-6.23 {CopyRenameOneFile: TclpCopyDirectory failed} \ {unixOnly notRoot xdev} { cleanup /tmp file mkdir td1/td2/td3 file attributes td1 -permissions 0000 set msg [list [catch {file rename td1 /tmp} msg] $msg] file attributes td1 -permissions 0755 set msg } {1 {error renaming "td1": permission denied}} test fCmd-6.24 {CopyRenameOneFile: error uses original name} \ {unixOnly notRoot} { cleanup file mkdir ~/td1/td2 set td1name [file join [file dirname ~] [file tail ~] td1] file attributes $td1name -permissions 0000 set msg [list [catch {file copy ~/td1 td1} msg] $msg] file attributes $td1name -permissions 0755 file delete -force ~/td1 set msg } {1 {error copying "~/td1": permission denied}} test fCmd-6.25 {CopyRenameOneFile: error uses original name} \ {unixOnly notRoot} { cleanup file mkdir td2 file mkdir ~/td1 set td1name [file join [file dirname ~] [file tail ~] td1] file attributes $td1name -permissions 0000 set msg [list [catch {file copy td2 ~/td1} msg] $msg] file attributes $td1name -permissions 0755 file delete -force ~/td1 set msg } {1 {error copying "td2" to "~/td1/td2": permission denied}} test fCmd-6.26 {CopyRenameOneFile: doesn't use original name} \ {unixOnly notRoot} { cleanup file mkdir ~/td1/td2 set td2name [file join [file dirname ~] [file tail ~] td1 td2] file attributes $td2name -permissions 0000 set msg [list [catch {file copy ~/td1 td1} msg] $msg] file attributes $td2name -permissions 0755 file delete -force ~/td1 set msg } "1 {error copying \"~/td1\" to \"td1\": \"[file join [file dirname ~] [file tail ~] td1 td2]\": permission denied}" test fCmd-6.27 {CopyRenameOneFile: TclpCopyDirectory failed} \ {unixOnly notRoot xdev} { cleanup /tmp file mkdir td1/td2/td3 file mkdir /tmp/td1 createfile /tmp/td1/tf1 list [catch {file rename -force td1 /tmp} msg] $msg } {1 {error renaming "td1" to "/tmp/td1": file already exists}} test fCmd-6.28 {CopyRenameOneFile: TclpCopyDirectory failed} \ {unixOnly notRoot xdev} { cleanup /tmp file mkdir td1/td2/td3 file attributes td1/td2/td3 -permissions 0000 set msg [list [catch {file rename td1 /tmp} msg] $msg] file attributes td1/td2/td3 -permissions 0755 set msg } {1 {error renaming "td1" to "/tmp/td1": "td1/td2/td3": permission denied}} test fCmd-6.29 {CopyRenameOneFile: TclpCopyDirectory passed} \ {unixOnly notRoot xdev} { cleanup /tmp file mkdir td1/td2/td3 file rename td1 /tmp glob td* /tmp/td1/t* } {/tmp/td1/td2} test fCmd-6.30 {CopyRenameOneFile: TclpRemoveDirectory failed} \ {unixOnly notRoot} { cleanup file mkdir foo/bar file attr foo -perm 040555 set catchResult [catch {file rename foo/bar /tmp} msg] set msg [lindex [split $msg :] end] catch {file delete /tmp/bar} catch {file attr foo -perm 040777} catch {file delete -force foo} list $catchResult $msg } {1 { permission denied}} test fCmd-6.31 {CopyRenameOneFile: TclpDeleteFile passed} \ {unixOnly notRoot xdev} { catch {cleanup /tmp} file mkdir /tmp/td1 createfile /tmp/td1/tf1 file rename /tmp/td1/tf1 tf1 list [file exists /tmp/td1/tf1] [file exists tf1] } {0 1} test fCmd-6.32 {CopyRenameOneFile: copy} {notRoot} { cleanup list [catch {file copy tf1 tf2} msg] $msg } {1 {error copying "tf1": no such file or directory}} catch {cleanup /tmp} test fCmd-7.1 {FileForceOption: none} {notRoot} { cleanup file mkdir [file join tf1 tf2] list [catch {file delete tf1} msg] $msg } {1 {error deleting "tf1": directory not empty}} test fCmd-7.2 {FileForceOption: -force} {notRoot} { cleanup file mkdir [file join tf1 tf2] file delete -force tf1 } {} test fCmd-7.3 {FileForceOption: --} {notRoot} { createfile -tf1 file delete -- -tf1 } {} test fCmd-7.4 {FileForceOption: bad option} {notRoot} { createfile -tf1 set msg [list [catch {file delete -tf1} msg] $msg] file delete -- -tf1 set msg } {1 {bad option "-tf1": should be -force or --}} test fCmd-7.5 {FileForceOption: multiple times through loop} {notRoot} { createfile -- createfile -force file delete -force -force -- -- -force list [catch {glob -- -- -force} msg] $msg } {1 {no files matched glob patterns "-- -force"}} test fCmd-8.1 {FileBasename: basename of ~user: argc == 1 && *path == ~} \ {unixOnly notRoot knownBug} { # Labelled knownBug because it is dangerous [Bug: 3881] file mkdir td1 file attr td1 -perm 040000 set result [list [catch {file rename ~$user td1} msg] $msg] file delete -force td1 set result } "1 {error renaming \"~$user\" to \"td1/[file tail ~$user]\": permission denied}" test fCmd-8.2 {FileBasename: basename of ~user: argc == 1 && *path == ~} { string equal [file tail ~$user] ~$user } 0 test fCmd-8.3 {file copy and path translation: ensure correct error} { list [catch {file copy ~ [file join this file doesnt exist]} res] $res } [list 1 \ "error copying \"~\" to \"[file join this file doesnt exist]\":\ no such file or directory"] test fCmd-9.1 {file rename: comprehensive: EACCES} {unixOnly notRoot} { cleanup file mkdir td1 file mkdir td2 file attr td2 -perm 040000 set result [list [catch {file rename td1 td2/} msg] $msg] file delete -force td2 file delete -force td1 set result } {1 {error renaming "td1" to "td2/td1": permission denied}} test fCmd-9.2 {file rename: comprehensive: source doesn't exist} {notRoot} { cleanup list [catch {file rename tf1 tf2} msg] $msg } {1 {error renaming "tf1": no such file or directory}} test fCmd-9.3 {file rename: comprehensive: file to new name} {notRoot testchmod} { cleanup createfile tf1 createfile tf2 testchmod 444 tf2 file rename tf1 tf3 file rename tf2 tf4 list [lsort [glob tf*]] [file writable tf3] [file writable tf4] } {{tf3 tf4} 1 0} test fCmd-9.4 {file rename: comprehensive: dir to new name} {unixOrPc notRoot testchmod win2000orXP} { cleanup file mkdir td1 td2 testchmod 555 td2 file rename td1 td3 file rename td2 td4 list [lsort [glob td*]] [file writable td3] [file writable td4] } {{td3 td4} 1 0} test fCmd-9.5 {file rename: comprehensive: file to self} {notRoot testchmod} { cleanup createfile tf1 tf1 createfile tf2 tf2 testchmod 444 tf2 file rename -force tf1 tf1 file rename -force tf2 tf2 list [contents tf1] [contents tf2] [file writable tf1] [file writable tf2] } {tf1 tf2 1 0} test fCmd-9.6 {file rename: comprehensive: dir to self} {notRoot unixOrPc testchmod win2000orXP} { cleanup file mkdir td1 file mkdir td2 testchmod 555 td2 file rename -force td1 . file rename -force td2 . list [lsort [glob td*]] [file writable td1] [file writable td2] } {{td1 td2} 1 0} test fCmd-9.7 {file rename: comprehensive: file to existing file} {notRoot testchmod} { cleanup createfile tf1 createfile tf2 createfile tfs1 createfile tfs2 createfile tfs3 createfile tfs4 createfile tfd1 createfile tfd2 createfile tfd3 createfile tfd4 testchmod 444 tfs3 testchmod 444 tfs4 testchmod 444 tfd2 testchmod 444 tfd4 set msg [list [catch {file rename tf1 tf2} msg] $msg] file rename -force tfs1 tfd1 file rename -force tfs2 tfd2 file rename -force tfs3 tfd3 file rename -force tfs4 tfd4 list [lsort [glob tf*]] $msg [file writable tfd1] [file writable tfd2] [file writable tfd3] [file writable tfd4] } {{tf1 tf2 tfd1 tfd2 tfd3 tfd4} {1 {error renaming "tf1" to "tf2": file already exists}} 1 1 0 0} test fCmd-9.8 {file rename: comprehensive: dir to empty dir} {notRoot testchmod notNetworkFilesystem} { # Under unix, you can rename a read-only directory, but you can't # move it into another directory. cleanup file mkdir td1 file mkdir [file join td2 td1] file mkdir tds1 file mkdir tds2 file mkdir tds3 file mkdir tds4 file mkdir [file join tdd1 tds1] file mkdir [file join tdd2 tds2] file mkdir [file join tdd3 tds3] file mkdir [file join tdd4 tds4] if {$tcl_platform(platform) != "unix"} { testchmod 555 tds3 testchmod 555 tds4 } testchmod 555 [file join tdd2 tds2] testchmod 555 [file join tdd4 tds4] set msg [list [catch {file rename td1 td2} msg] $msg] file rename -force tds1 tdd1 file rename -force tds2 tdd2 file rename -force tds3 tdd3 file rename -force tds4 tdd4 if {$tcl_platform(platform) != "unix"} { set w3 [file writable [file join tdd3 tds3]] set w4 [file writable [file join tdd4 tds4]] } else { set w3 0 set w4 0 } list [lsort [glob td*]] $msg [file writable [file join tdd1 tds1]] \ [file writable [file join tdd2 tds2]] $w3 $w4 } [subst {{td1 td2 tdd1 tdd2 tdd3 tdd4} {1 {error renaming "td1" to "[file join td2 td1]": file already exists}} 1 1 0 0}] test fCmd-9.9 {file rename: comprehensive: dir to non-empty dir} {notRoot testchmod} { cleanup file mkdir tds1 file mkdir tds2 file mkdir [file join tdd1 tds1 xxx] file mkdir [file join tdd2 tds2 xxx] if {!([testConstraint unix] || [testConstraint winVista])} { testchmod 555 tds2 } set a1 [list [catch {file rename -force tds1 tdd1} msg] $msg] set a2 [list [catch {file rename -force tds2 tdd2} msg] $msg] if {!([testConstraint unix] || [testConstraint winVista])} { set w2 [file writable tds2] } else { set w2 0 } list [lsort [glob td*]] $a1 $a2 [file writable tds1] $w2 } [subst {{tdd1 tdd2 tds1 tds2} {1 {error renaming "tds1" to "[file join tdd1 tds1]": file already exists}} {1 {error renaming "tds2" to "[file join tdd2 tds2]": file already exists}} 1 0}] test fCmd-9.10 {file rename: comprehensive: file to new name and dir} {notRoot testchmod} { cleanup createfile tf1 createfile tf2 file mkdir td1 testchmod 444 tf2 file rename tf1 [file join td1 tf3] file rename tf2 [file join td1 tf4] list [catch {glob tf*}] [lsort [glob -directory td1 t*]] \ [file writable [file join td1 tf3]] [file writable [file join td1 tf4]] } [subst {1 {[file join td1 tf3] [file join td1 tf4]} 1 0}] test fCmd-9.11 {file rename: comprehensive: dir to new name and dir} {notRoot testchmod} { cleanup file mkdir td1 file mkdir td2 file mkdir td3 if {!([testConstraint unix] || [testConstraint winVista])} { testchmod 555 td2 } file rename td1 [file join td3 td3] file rename td2 [file join td3 td4] if {!([testConstraint unix] || [testConstraint winVista])} { set w4 [file writable [file join td3 td4]] } else { set w4 0 } list [lsort [glob td*]] [lsort [glob -directory td3 t*]] \ [file writable [file join td3 td3]] $w4 } [subst {td3 {[file join td3 td3] [file join td3 td4]} 1 0}] test fCmd-9.12 {file rename: comprehensive: target exists} {notRoot testchmod notNetworkFilesystem} { cleanup file mkdir [file join td1 td2] [file join td2 td1] testchmod 555 [file join td2 td1] file mkdir [file join td3 td4] [file join td4 td3] file rename -force td3 td4 set msg [list [file exists td3] [file exists [file join td4 td3 td4]] \ [catch {file rename td1 td2} msg] $msg] testchmod 755 [file join td2 td1] set msg } [subst {0 1 1 {error renaming "td1" to "[file join td2 td1]": file already exists}}] test fCmd-9.13 {file rename: comprehensive: can't overwrite target} {notRoot} { cleanup file mkdir [file join td1 td2] [file join td2 td1 td4] list [catch {file rename -force td1 td2} msg] $msg } [subst {1 {error renaming "td1" to "[file join td2 td1]": file already exists}}] test fCmd-9.14 {file rename: comprehensive: dir into self} {notRoot} { cleanup file mkdir td1 list [glob td*] [list [catch {file rename td1 td1} msg] $msg] } [subst {td1 {1 {error renaming "td1" to "[file join td1 td1]": trying to rename a volume or move a directory into itself}}}] test fCmd-9.15 {file rename: comprehensive: source and target incompatible} \ {notRoot} { cleanup file mkdir td1 createfile tf1 list [catch {file rename -force td1 tf1} msg] $msg } {1 {can't overwrite file "tf1" with directory "td1"}} test fCmd-9.16 {file rename: comprehensive: source and target incompatible} \ {notRoot} { cleanup file mkdir td1/tf1 createfile tf1 list [catch {file rename -force tf1 td1} msg] $msg } [subst {1 {can't overwrite directory "[file join td1 tf1]" with file "tf1"}}] test fCmd-10.1 {file copy: comprehensive: source doesn't exist} {notRoot} { cleanup list [catch {file copy tf1 tf2} msg] $msg } {1 {error copying "tf1": no such file or directory}} test fCmd-10.2 {file copy: comprehensive: file to new name} {notRoot testchmod} { cleanup createfile tf1 tf1 createfile tf2 tf2 testchmod 444 tf2 file copy tf1 tf3 file copy tf2 tf4 list [lsort [glob tf*]] [contents tf3] [contents tf4] [file writable tf3] [file writable tf4] } {{tf1 tf2 tf3 tf4} tf1 tf2 1 0} test fCmd-10.3 {file copy: comprehensive: dir to new name} {notRoot unixOrPc 95or98 testchmod} { cleanup file mkdir [file join td1 tdx] file mkdir [file join td2 tdy] testchmod 555 td2 file copy td1 td3 file copy td2 td4 set msg [list [lsort [glob td*]] [glob -directory td3 t*] \ [glob -directory td4 t*] [file writable td3] [file writable td4]] testchmod 755 td2 testchmod 755 td4 set msg } [subst {{td1 td2 td3 td4} [file join td3 tdx] [file join td4 tdy] 1 0}] test fCmd-10.3.1 {file copy: comprehensive: dir to new name} {notRoot pc 2000orNewer testchmod} { # On Windows with ACLs, copying a directory is defined like this cleanup file mkdir [file join td1 tdx] file mkdir [file join td2 tdy] testchmod 555 td2 file copy td1 td3 file copy td2 td4 set msg [list [lsort [glob td*]] [glob -directory td3 t*] \ [glob -directory td4 t*] [file writable td3] [file writable td4]] testchmod 755 td2 testchmod 755 td4 set msg } [subst {{td1 td2 td3 td4} [file join td3 tdx] [file join td4 tdy] 1 1}] test fCmd-10.4 {file copy: comprehensive: file to existing file} {notRoot testchmod} { cleanup createfile tf1 createfile tf2 createfile tfs1 createfile tfs2 createfile tfs3 createfile tfs4 createfile tfd1 createfile tfd2 createfile tfd3 createfile tfd4 testchmod 444 tfs3 testchmod 444 tfs4 testchmod 444 tfd2 testchmod 444 tfd4 set msg [list [catch {file copy tf1 tf2} msg] $msg] file copy -force tfs1 tfd1 file copy -force tfs2 tfd2 file copy -force tfs3 tfd3 file copy -force tfs4 tfd4 list [lsort [glob tf*]] $msg [file writable tfd1] [file writable tfd2] [file writable tfd3] [file writable tfd4] } {{tf1 tf2 tfd1 tfd2 tfd3 tfd4 tfs1 tfs2 tfs3 tfs4} {1 {error copying "tf1" to "tf2": file already exists}} 1 1 0 0} test fCmd-10.5 {file copy: comprehensive: dir to empty dir} {notRoot testchmod} { cleanup file mkdir td1 file mkdir [file join td2 td1] file mkdir tds1 file mkdir tds2 file mkdir tds3 file mkdir tds4 file mkdir [file join tdd1 tds1] file mkdir [file join tdd2 tds2] file mkdir [file join tdd3 tds3] file mkdir [file join tdd4 tds4] testchmod 555 tds3 testchmod 555 tds4 testchmod 555 [file join tdd2 tds2] testchmod 555 [file join tdd4 tds4] set a1 [list [catch {file copy td1 td2} msg] $msg] set a2 [list [catch {file copy -force tds1 tdd1} msg] $msg] set a3 [catch {file copy -force tds2 tdd2}] set a4 [catch {file copy -force tds3 tdd3}] set a5 [catch {file copy -force tds4 tdd4}] list [lsort [glob td*]] $a1 $a2 $a3 $a4 $a5 } [subst {{td1 td2 tdd1 tdd2 tdd3 tdd4 tds1 tds2 tds3 tds4} {1 {error copying "td1" to "[file join td2 td1]": file already exists}} {1 {error copying "tds1" to "[file join tdd1 tds1]": file already exists}} 1 1 1}] test fCmd-10.6 {file copy: comprehensive: dir to non-empty dir} \ {notRoot unixOrPc testchmod} { cleanup file mkdir tds1 file mkdir tds2 file mkdir [file join tdd1 tds1 xxx] file mkdir [file join tdd2 tds2 xxx] testchmod 555 tds2 set a1 [list [catch {file copy -force tds1 tdd1} msg] $msg] set a2 [list [catch {file copy -force tds2 tdd2} msg] $msg] list [lsort [glob td*]] $a1 $a2 [file writable tds1] [file writable tds2] } [subst {{tdd1 tdd2 tds1 tds2} {1 {error copying "tds1" to "[file join tdd1 tds1]": file already exists}} {1 {error copying "tds2" to "[file join tdd2 tds2]": file already exists}} 1 0}] test fCmd-10.7 {file rename: comprehensive: file to new name and dir} {notRoot testchmod} { cleanup createfile tf1 createfile tf2 file mkdir td1 testchmod 444 tf2 file copy tf1 [file join td1 tf3] file copy tf2 [file join td1 tf4] list [lsort [glob tf*]] [lsort [glob -directory td1 t*]] \ [file writable [file join td1 tf3]] [file writable [file join td1 tf4]] } [subst {{tf1 tf2} {[file join td1 tf3] [file join td1 tf4]} 1 0}] test fCmd-10.8 {file rename: comprehensive: dir to new name and dir} \ {notRoot unixOrPc 95or98 testchmod} { cleanup file mkdir td1 file mkdir td2 file mkdir td3 testchmod 555 td2 file copy td1 [file join td3 td3] file copy td2 [file join td3 td4] list [lsort [glob td*]] [lsort [glob -directory td3 t*]] \ [file writable [file join td3 td3]] [file writable [file join td3 td4]] } [subst {{td1 td2 td3} {[file join td3 td3] [file join td3 td4]} 1 0}] test fCmd-10.8.1 {file rename: comprehensive: dir to new name and dir} \ {notRoot pc 2000orNewer testchmod} { # On Windows with ACLs, copying a directory is defined like this cleanup file mkdir td1 file mkdir td2 file mkdir td3 testchmod 555 td2 file copy td1 [file join td3 td3] file copy td2 [file join td3 td4] list [lsort [glob td*]] [lsort [glob -directory td3 t*]] \ [file writable [file join td3 td3]] [file writable [file join td3 td4]] } [subst {{td1 td2 td3} {[file join td3 td3] [file join td3 td4]} 1 1}] test fCmd-10.9 {file copy: comprehensive: source and target incompatible} \ {notRoot} { cleanup file mkdir td1 createfile tf1 list [catch {file copy -force td1 tf1} msg] $msg } {1 {can't overwrite file "tf1" with directory "td1"}} test fCmd-10.10 {file copy: comprehensive: source and target incompatible} \ {notRoot} { cleanup file mkdir [file join td1 tf1] createfile tf1 list [catch {file copy -force tf1 td1} msg] $msg } [subst {1 {can't overwrite directory "[file join td1 tf1]" with file "tf1"}}] test fCmd-10.11 {file copy: copy to empty file name} { cleanup createfile tf1 list [catch {file copy tf1 ""} msg] $msg } {1 {error copying "tf1" to "": no such file or directory}} test fCmd-10.12 {file rename: rename to empty file name} { cleanup createfile tf1 list [catch {file rename tf1 ""} msg] $msg } {1 {error renaming "tf1" to "": no such file or directory}} cleanup # old tests test fCmd-11.1 {TclFileRenameCmd: -- option } {notRoot} { catch {file delete -force -- -tfa1} set s [createfile -tfa1] file rename -- -tfa1 tfa2 set result [expr [checkcontent tfa2 $s] && ![file exists -tfa1]] file delete tfa2 set result } {1} test fCmd-11.2 {TclFileRenameCmd: bad option } {notRoot} { catch {file delete -force -- tfa1} set s [createfile tfa1] set r1 [catch {file rename -x tfa1 tfa2}] set result [expr $r1 && [checkcontent tfa1 $s] && ![file exists tfa2]] file delete tfa1 set result } {1} test fCmd-11.3 {TclFileRenameCmd: bad \# args} { catch {file rename -- } } {1} test fCmd-11.4 {TclFileRenameCmd: target filename translation failing} {notRoot} { global env set temp $env(HOME) unset env(HOME) set result [catch {file rename tfa ~/foobar }] set env(HOME) $temp set result } {1} test fCmd-11.5 {TclFileRenameCmd: > 1 source & target is not a dir} {notRoot} { catch {file delete -force -- tfa1 tfa2 tfa3} createfile tfa1 createfile tfa2 createfile tfa3 set result [catch {file rename tfa1 tfa2 tfa3}] file delete tfa1 tfa2 tfa3 set result } {1} test fCmd-11.6 {TclFileRenameCmd: : single file into directory} {notRoot} { catch {file delete -force -- tfa1 tfad} set s [createfile tfa1] file mkdir tfad file rename tfa1 tfad set result [expr [checkcontent tfad/tfa1 $s] && ![file exists tfa1]] file delete -force tfad set result } {1} test fCmd-11.7 {TclFileRenameCmd: : multiple files into directory} {notRoot} { catch {file delete -force -- tfa1 tfa2 tfad} set s1 [createfile tfa1 ] set s2 [createfile tfa2 ] file mkdir tfad file rename tfa1 tfa2 tfad set r1 [checkcontent tfad/tfa1 $s1] set r2 [checkcontent tfad/tfa2 $s2] set result [expr $r1 && $r2 && ![file exists tfa1] && ![file exists tfa2]] file delete -force tfad set result } {1} test fCmd-11.8 {TclFileRenameCmd: error renaming file to directory} {notRoot} { catch {file delete -force -- tfa tfad} set s [createfile tfa ] file mkdir tfad file mkdir tfad/tfa set r1 [catch {file rename tfa tfad}] set r2 [checkcontent tfa $s] set r3 [file isdir tfad] set result [expr $r1 && $r2 && $r3 ] file delete -force tfa tfad set result } {1} # # Coverage tests for renamefile() ; # test fCmd-12.1 {renamefile: source filename translation failing} {notRoot} { global env set temp $env(HOME) unset env(HOME) set result [catch {file rename ~/tfa1 tfa2}] set env(HOME) $temp set result } {1} test fCmd-12.2 {renamefile: src filename translation failing} {notRoot} { global env set temp $env(HOME) unset env(HOME) set s [createfile tfa1] file mkdir tfad set result [catch {file rename tfa1 ~/tfa2 tfad}] set env(HOME) $temp file delete -force tfad set result } {1} test fCmd-12.3 {renamefile: stat failing on source} {notRoot} { catch {file delete -force -- tfa1 tfa2} set r1 [catch {file rename tfa1 tfa2}] expr {$r1 && ![file exists tfa1] && ![file exists tfa2]} } {1} test fCmd-12.4 {renamefile: error renaming file to directory} {notRoot} { catch {file delete -force -- tfa tfad} set s1 [createfile tfa ] file mkdir tfad file mkdir tfad/tfa set r1 [catch {file rename tfa tfad}] set r2 [checkcontent tfa $s1] set r3 [file isdir tfad/tfa] set result [expr $r1 && $r2 && $r3] file delete -force tfa tfad set result } {1} test fCmd-12.5 {renamefile: error renaming directory to file} {notRoot} { catch {file delete -force -- tfa tfad} file mkdir tfa file mkdir tfad set s [createfile tfad/tfa] set r1 [catch {file rename tfa tfad}] set r2 [checkcontent tfad/tfa $s] set r3 [file isdir tfad] set r4 [file isdir tfa] set result [expr $r1 && $r2 && $r3 && $r4 ] file delete -force tfa tfad set result } {1} test fCmd-12.6 {renamefile: TclRenameFile succeeding} {notRoot} { catch {file delete -force -- tfa1 tfa2} set s [createfile tfa1] file rename tfa1 tfa2 set result [expr [checkcontent tfa2 $s] && ![file exists tfa1]] file delete tfa2 set result } {1} test fCmd-12.7 {renamefile: renaming directory into offspring} {notRoot} { catch {file delete -force -- tfad} file mkdir tfad file mkdir tfad/dir set result [catch {file rename tfad tfad/dir}] file delete -force tfad set result } {1} test fCmd-12.8 {renamefile: generic error} {unixOnly notRoot} { catch {file delete -force -- tfa} file mkdir tfa file mkdir tfa/dir file attributes tfa -permissions 0555 set result [catch {file rename tfa/dir tfa2}] file attributes tfa -permissions 0777 file delete -force tfa set result } {1} test fCmd-12.9 {renamefile: moving a file across volumes} {unixOnly notRoot} { catch {file delete -force -- tfa /tmp/tfa} set s [createfile tfa ] file rename tfa /tmp set result [expr [checkcontent /tmp/tfa $s] && ![file exists tfa]] file delete /tmp/tfa set result } {1} test fCmd-12.10 {renamefile: moving a directory across volumes } \ {unixOnly notRoot} { catch {file delete -force -- tfad /tmp/tfad} file mkdir tfad set s [createfile tfad/a ] file rename tfad /tmp set restul [expr [checkcontent /tmp/tfad/a $s] && ![file exists tfad]] file delete -force /tmp/tfad set result } {1} # # Coverage tests for TclCopyFilesCmd() # test fCmd-13.1 {TclCopyFilesCmd: -force option} {notRoot} { catch {file delete -force -- tfa1} set s [createfile tfa1] file copy -force tfa1 tfa2 set result [expr [checkcontent tfa2 $s] && [checkcontent tfa1 $s]] file delete tfa1 tfa2 set result } {1} test fCmd-13.2 {TclCopyFilesCmd: -- option} {notRoot} { catch {file delete -force -- tfa1} set s [createfile -tfa1] file copy -- -tfa1 tfa2 set result [expr [checkcontent tfa2 $s] && [checkcontent -tfa1 $s]] file delete -- -tfa1 tfa2 set result } {1} test fCmd-13.3 {TclCopyFilesCmd: bad option} {notRoot} { catch {file delete -force -- tfa1} set s [createfile tfa1] set r1 [catch {file copy -x tfa1 tfa2}] set result [expr $r1 && [checkcontent tfa1 $s] && ![file exists tfa2]] file delete tfa1 set result } {1} test fCmd-13.4 {TclCopyFilesCmd: bad \# args} {notRoot} { catch {file copy -- } } {1} test fCmd-13.5 {TclCopyFilesCmd: target filename translation failing} { global env set temp $env(HOME) unset env(HOME) set result [catch {file copy tfa ~/foobar }] set env(HOME) $temp set result } {1} test fCmd-13.6 {TclCopyFilesCmd: > 1 source & target is not a dir} {notRoot} { catch {file delete -force -- tfa1 tfa2 tfa3} createfile tfa1 createfile tfa2 createfile tfa3 set result [catch {file copy tfa1 tfa2 tfa3}] file delete tfa1 tfa2 tfa3 set result } {1} test fCmd-13.7 {TclCopyFilesCmd: single file into directory} {notRoot} { catch {file delete -force -- tfa1 tfad} set s [createfile tfa1] file mkdir tfad file copy tfa1 tfad set result [expr [checkcontent tfad/tfa1 $s] && [checkcontent tfa1 $s]] file delete -force tfad tfa1 set result } {1} test fCmd-13.8 {TclCopyFilesCmd: multiple files into directory} {notRoot} { catch {file delete -force -- tfa1 tfa2 tfad} set s1 [createfile tfa1 ] set s2 [createfile tfa2 ] file mkdir tfad file copy tfa1 tfa2 tfad set r1 [checkcontent tfad/tfa1 $s1] set r2 [checkcontent tfad/tfa2 $s2] set r3 [checkcontent tfa1 $s1] set r4 [checkcontent tfa2 $s2] set result [expr $r1 && $r2 && $r3 && $r4 ] file delete -force tfad tfa1 tfa2 set result } {1} test fCmd-13.9 {TclCopyFilesCmd: error copying file to directory} {notRoot} { catch {file delete -force -- tfa tfad} set s [createfile tfa ] file mkdir tfad file mkdir tfad/tfa set r1 [catch {file copy tfa tfad}] set r2 [expr [checkcontent tfa $s] && [file isdir tfad/tfa]] set r3 [file isdir tfad] set result [expr $r1 && $r2 && $r3 ] file delete -force tfa tfad set result } {1} # # Coverage tests for copyfile() # test fCmd-14.1 {copyfile: source filename translation failing} {notRoot} { global env set temp $env(HOME) unset env(HOME) set result [catch {file copy ~/tfa1 tfa2}] set env(HOME) $temp set result } {1} test fCmd-14.2 {copyfile: dst filename translation failing} {notRoot} { global env set temp $env(HOME) unset env(HOME) set s [createfile tfa1] file mkdir tfad set r1 [catch {file copy tfa1 ~/tfa2 tfad}] set result [expr $r1 && [checkcontent tfad/tfa1 $s]] set env(HOME) $temp file delete -force tfa1 tfad set result } {1} test fCmd-14.3 {copyfile: stat failing on source} {notRoot} { catch {file delete -force -- tfa1 tfa2} set r1 [catch {file copy tfa1 tfa2}] expr $r1 && ![file exists tfa1] && ![file exists tfa2] } {1} test fCmd-14.4 {copyfile: error copying file to directory} {notRoot} { catch {file delete -force -- tfa tfad} set s1 [createfile tfa ] file mkdir tfad file mkdir tfad/tfa set r1 [catch {file copy tfa tfad}] set r2 [checkcontent tfa $s1] set r3 [file isdir tfad] set r4 [file isdir tfad/tfa] set result [expr $r1 && $r2 && $r3 && $r4 ] file delete -force tfa tfad set result } {1} test fCmd-14.5 {copyfile: error copying directory to file} {notRoot} { catch {file delete -force -- tfa tfad} file mkdir tfa file mkdir tfad set s [createfile tfad/tfa] set r1 [catch {file copy tfa tfad}] set r2 [checkcontent tfad/tfa $s] set r3 [file isdir tfad] set r4 [file isdir tfa] set result [expr $r1 && $r2 && $r3 && $r4 ] file delete -force tfa tfad set result } {1} test fCmd-14.6 {copyfile: copy file succeeding} {notRoot} { catch {file delete -force -- tfa tfa2} set s [createfile tfa] file copy tfa tfa2 set result [expr [checkcontent tfa $s] && [checkcontent tfa2 $s]] file delete tfa tfa2 set result } {1} test fCmd-14.7 {copyfile: copy directory succeeding} {notRoot} { catch {file delete -force -- tfa tfa2} file mkdir tfa set s [createfile tfa/file] file copy tfa tfa2 set result [expr [checkcontent tfa/file $s] && [checkcontent tfa2/file $s]] file delete -force tfa tfa2 set result } {1} test fCmd-14.8 {copyfile: copy directory failing} {unixOnly notRoot} { catch {file delete -force -- tfa} file mkdir tfa/dir/a/b/c file attributes tfa/dir -permissions 0000 set r1 [catch {file copy tfa tfa2}] file attributes tfa/dir -permissions 0777 set result $r1 file delete -force tfa tfa2 set result } {1} # # Coverage tests for TclMkdirCmd() # test fCmd-15.1 {TclMakeDirsCmd: target filename translation failing} {notRoot} { global env set temp $env(HOME) unset env(HOME) set result [catch {file mkdir ~/tfa}] set env(HOME) $temp set result } {1} # # Can Tcl_SplitPath return argc == 0? If so them we need a # test for that code. # test fCmd-15.2 {TclMakeDirsCmd - one directory } {notRoot} { catch {file delete -force -- tfa} file mkdir tfa set result [file isdirectory tfa] file delete tfa set result } {1} test fCmd-15.3 {TclMakeDirsCmd: - two directories} {notRoot} { catch {file delete -force -- tfa1 tfa2} file mkdir tfa1 tfa2 set result [expr [file isdirectory tfa1] && [file isdirectory tfa2]] file delete tfa1 tfa2 set result } {1} test fCmd-15.4 {TclMakeDirsCmd - stat failing} {unixOnly notRoot} { catch {file delete -force -- tfa} file mkdir tfa createfile tfa/file file attributes tfa -permissions 0000 set result [catch {file mkdir tfa/file}] file attributes tfa -permissions 0777 file delete -force tfa set result } {1} test fCmd-15.5 {TclMakeDirsCmd: - making a directory several levels deep} \ {notRoot} { catch {file delete -force -- tfa} file mkdir tfa/a/b/c set result [file isdir tfa/a/b/c] file delete -force tfa set result } {1} test fCmd-15.6 {TclMakeDirsCmd: - trying to overwrite a file} {notRoot} { catch {file delete -force -- tfa} set s [createfile tfa] set r1 [catch {file mkdir tfa}] set r2 [file isdir tfa] set r3 [file exists tfa] set result [expr $r1 && !$r2 && $r3 && [checkcontent tfa $s]] file delete tfa set result } {1} test fCmd-15.7 {TclMakeDirsCmd - making several directories} {notRoot} { catch {file delete -force -- tfa1 tfa2} file mkdir tfa1 tfa2/a/b/c set result [expr [file isdir tfa1] && [file isdir tfa2/a/b/c]] file delete -force tfa1 tfa2 set result } {1} test fCmd-15.8 {TclFileMakeDirsCmd: trying to create an existing dir} {notRoot} { file mkdir tfa file mkdir tfa set result [file isdir tfa] file delete tfa set result } {1} # Coverage tests for TclDeleteFilesCommand() test fCmd-16.1 {test the -- argument} {notRoot} { catch {file delete -force -- tfa} createfile tfa file delete -- tfa file exists tfa } {0} test fCmd-16.2 {test the -force and -- arguments} {notRoot} { catch {file delete -force -- tfa} createfile tfa file delete -force -- tfa file exists tfa } {0} test fCmd-16.3 {test bad option} {notRoot} { catch {file delete -force -- tfa} createfile tfa set result [catch {file delete -dog tfa}] file delete tfa set result } {1} test fCmd-16.4 {test not enough args} {notRoot} { catch {file delete} } {1} test fCmd-16.5 {test not enough args with options} {notRoot} { catch {file delete --} } {1} test fCmd-16.6 {delete: source filename translation failing} {notRoot} { global env set temp $env(HOME) unset env(HOME) set result [catch {file delete ~/tfa}] set env(HOME) $temp set result } {1} test fCmd-16.7 {remove a non-empty directory without -force } {notRoot} { catch {file delete -force -- tfa} file mkdir tfa createfile tfa/a set result [catch {file delete tfa }] file delete -force tfa set result } {1} test fCmd-16.8 {remove a normal file } {notRoot} { catch {file delete -force -- tfa} file mkdir tfa createfile tfa/a set result [catch {file delete tfa }] file delete -force tfa set result } {1} test fCmd-16.9 {error while deleting file } {unixOnly notRoot} { catch {file delete -force -- tfa} file mkdir tfa createfile tfa/a file attributes tfa -permissions 0555 set result [catch {file delete tfa/a }] ####### ####### If any directory in a tree that is being removed does not ####### have write permission, the process will fail! ####### This is also the case with "rm -rf" ####### file attributes tfa -permissions 0777 file delete -force tfa set result } {1} test fCmd-16.10 {deleting multiple files} {notRoot} { catch {file delete -force -- tfa1 tfa2} createfile tfa1 createfile tfa2 file delete tfa1 tfa2 expr ![file exists tfa1] && ![file exists tfa2] } {1} test fCmd-16.11 {TclFileDeleteCmd: removing a nonexistant file} {notRoot} { catch {file delete -force -- tfa} file delete tfa set result 1 } {1} # More coverage tests for mkpath() test fCmd-17.1 {mkdir stat failing on target but not ENOENT} {unixOnly notRoot} { catch {file delete -force -- tfa1} file mkdir tfa1 file attributes tfa1 -permissions 0555 set result [catch {file mkdir tfa1/tfa2}] file attributes tfa1 -permissions 0777 file delete -force tfa1 set result } {1} test fCmd-17.2 {mkdir several levels deep - relative } {notRoot} { catch {file delete -force -- tfa} file mkdir tfa/a/b set result [file isdir tfa/a/b ] file delete tfa/a/b tfa/a tfa set result } {1} test fCmd-17.3 {mkdir several levels deep - absolute } {notRoot} { catch {file delete -force -- tfa} set f [file join [pwd] tfa a ] file mkdir $f set result [file isdir $f ] file delete $f [file join [pwd] tfa] set result } {1} # # Functionality tests for TclFileRenameCmd() # test fCmd-18.1 {TclFileRenameCmd: rename (first form) in the same directory} \ {notRoot} { catch {file delete -force -- tfad} file mkdir tfad/dir cd tfad/dir set s [createfile foo ] file rename foo bar file rename bar ./foo file rename ./foo bar file rename ./bar ./foo file rename foo ../dir/bar file rename ../dir/bar ./foo file rename ../../tfad/dir/foo ../../tfad/dir/bar file rename [file join [pwd] bar] foo file rename foo [file join [pwd] bar] set result [expr [checkcontent bar $s] && ![file exists foo]] cd ../.. file delete -force tfad set result } {1} test fCmd-18.2 {TclFileRenameCmd: single dir to nonexistant} {notRoot} { catch {file delete -force -- tfa1 tfa2} file mkdir tfa1 file rename tfa1 tfa2 set result [expr [file exists tfa2] && ![file exists tfa1]] file delete tfa2 set result } {1} test fCmd-18.3 {TclFileRenameCmd: mixed dirs and files into directory} {notRoot} { catch {file delete -force -- tfa1 tfad1 tfad2} set s [createfile tfa1 ] file mkdir tfad1 tfad2 file rename tfa1 tfad1 tfad2 set r1 [checkcontent tfad2/tfa1 $s] set r2 [file isdir tfad2/tfad1] set result [expr $r1 && $r2 && ![file exists tfa1] && ![file exists tfad1]] file delete tfad2/tfa1 file delete -force tfad2 set result } {1} test fCmd-18.4 {TclFileRenameCmd: attempt to replace non-dir with dir} {notRoot} { catch {file delete -force -- tfa tfad} set s [createfile tfa ] file mkdir tfad set r1 [catch {file rename tfad tfa}] set r2 [checkcontent tfa $s] set r3 [file isdir tfad] set result [expr $r1 && $r2 && $r3 ] file delete tfa tfad set result } {1} test fCmd-18.5 {TclFileRenameCmd: attempt to replace dir with non-dir} {notRoot} { catch {file delete -force -- tfa tfad} set s [createfile tfa ] file mkdir tfad/tfa set r1 [catch {file rename tfa tfad}] set r2 [checkcontent tfa $s] set r3 [file isdir tfad/tfa] set result [expr $r1 && $r2 && $r3 ] file delete -force tfa tfad set result } {1} # # On Windows there is no easy way to determine if two files are the same # test fCmd-18.6 {TclFileRenameCmd: rename a file to itself} {macOrUnix notRoot} { catch {file delete -force -- tfa} set s [createfile tfa] set r1 [catch {file rename tfa tfa}] set result [expr $r1 && [checkcontent tfa $s]] file delete tfa set result } {1} test fCmd-18.7 {TclFileRenameCmd: rename dir on top of another empty dir w/o -force} \ {notRoot} { catch {file delete -force -- tfa tfad} file mkdir tfa tfad/tfa set r1 [catch {file rename tfa tfad}] set result [expr $r1 && [file isdir tfa]] file delete -force tfa tfad set result } {1} test fCmd-18.8 {TclFileRenameCmd: rename dir on top of another empty dir w/ -force} \ {notRoot notNetworkFilesystem} { catch {file delete -force -- tfa tfad} file mkdir tfa tfad/tfa file rename -force tfa tfad set result [expr ![file isdir tfa]] file delete -force tfad set result } {1} test fCmd-18.9 {TclFileRenameCmd: rename dir on top of a non-empty dir w/o -force} \ {notRoot} { catch {file delete -force -- tfa tfad} file mkdir tfa tfad/tfa/file set r1 [catch {file rename tfa tfad}] set result [expr $r1 && [file isdir tfa] && [file isdir tfad/tfa/file]] file delete -force tfa tfad set result } {1} test fCmd-18.10 {TclFileRenameCmd: rename dir on top of a non-empty dir w/ -force} \ {notRoot notNetworkFilesystem} { catch {file delete -force -- tfa tfad} file mkdir tfa tfad/tfa/file set r1 [catch {file rename -force tfa tfad}] set result [expr $r1 && [file isdir tfa] && [file isdir tfad/tfa/file]] file delete -force tfa tfad set result } {1} test fCmd-18.11 {TclFileRenameCmd: rename a non-existant file} {notRoot} { catch {file delete -force -- tfa1} set r1 [catch {file rename tfa1 tfa2}] set result [expr $r1 && ![file exists tfa1] && ![file exists tfa2]] } {1} test fCmd-18.12 {TclFileRenameCmd : rename a symbolic link to file} \ {unixOnly notRoot} { catch {file delete -force -- tfa1 tfa2 tfa3} set s [createfile tfa1] file link -symbolic tfa2 tfa1 file rename tfa2 tfa3 set t [file type tfa3] set result [expr {$t eq "link"}] file delete tfa1 tfa3 set result } {1} test fCmd-18.13 {TclFileRenameCmd : rename a symbolic link to dir} \ {unixOnly notRoot} { catch {file delete -force -- tfa1 tfa2 tfa3} file mkdir tfa1 file link -symbolic tfa2 tfa1 file rename tfa2 tfa3 set t [file type tfa3] set result [expr {$t eq "link"}] file delete tfa1 tfa3 set result } {1} test fCmd-18.14 {TclFileRenameCmd : rename a path with sym link} \ {unixOnly notRoot} { catch {file delete -force -- tfa1 tfa2 tfa3} file mkdir tfa1/a/b/c/d file mkdir tfa2 set f [file join [pwd] tfa1/a/b] set f2 [file join [pwd] {tfa2/b alias}] file link -symbolic $f2 $f file rename {tfa2/b alias/c} tfa3 set r1 [file isdir tfa3] set r2 [file exists tfa1/a/b/c] set result [expr $r1 && !$r2] file delete -force tfa1 tfa2 tfa3 set result } {1} test fCmd-18.15 {TclFileRenameCmd : rename a file to a symlink dir} \ {unixOnly notRoot} { catch {file delete -force -- tfa1 tfa2 tfalink} file mkdir tfa1 set s [createfile tfa2] file link -symbolic tfalink tfa1 file rename tfa2 tfalink set result [checkcontent tfa1/tfa2 $s ] file delete -force tfa1 tfalink set result } {1} test fCmd-18.16 {TclFileRenameCmd: rename a dangling symlink} {unixOnly notRoot} { catch {file delete -force -- tfa1 tfalink} file mkdir tfa1 file link -symbolic tfalink tfa1 file delete tfa1 file rename tfalink tfa2 set result [expr [string compare [file type tfa2] "link"] == 0] file delete tfa2 set result } {1} # # Coverage tests for TclUnixRmdir # test fCmd-19.1 {remove empty directory} {notRoot} { catch {file delete -force -- tfa} file mkdir tfa file delete tfa file exists tfa } {0} test fCmd-19.2 {rmdir error besides EEXIST} {unixOnly notRoot} { catch {file delete -force -- tfa} file mkdir tfa file mkdir tfa/a file attributes tfa -permissions 0555 set result [catch {file delete tfa/a}] file attributes tfa -permissions 0777 file delete -force tfa set result } {1} test fCmd-19.3 {recursive remove} {notRoot} { catch {file delete -force -- tfa} file mkdir tfa file mkdir tfa/a file delete -force tfa file exists tfa } {0} # # TclUnixDeleteFile and TraversalDelete are covered by tests from the # TclDeleteFilesCmd suite # # # # Coverage tests for TraverseUnixTree(), called from TclDeleteFilesCmd # test fCmd-20.1 {TraverseUnixTree : failure opening a subdirectory directory } \ {unixOnly notRoot} { catch {file delete -force -- tfa} file mkdir tfa file mkdir tfa/a file attributes tfa/a -permissions 0000 set result [catch {file delete -force tfa}] file attributes tfa/a -permissions 0777 file delete -force tfa set result } {1} test fCmd-20.2 {TraverseUnixTree : recursive delete of large directory: Bug 1034337} \ {unix notRoot} { catch {file delete -force -- tfa} file mkdir tfa for {set i 1} {$i <= 300} {incr i} {createfile tfa/testfile_$i} set result [catch {file delete -force tfa} msg] while {[catch {file delete -force tfa}]} {} list $result $msg } {0 {}} # # Feature testing for TclCopyFilesCmd # test fCmd-21.1 {copy : single file to nonexistant } {notRoot} { catch {file delete -force -- tfa1 tfa2} set s [createfile tfa1] file copy tfa1 tfa2 set result [expr [checkcontent tfa2 $s] && [checkcontent tfa1 $s]] file delete tfa1 tfa2 set result } {1} test fCmd-21.2 {copy : single dir to nonexistant } {notRoot} { catch {file delete -force -- tfa1 tfa2} file mkdir tfa1 file copy tfa1 tfa2 set result [expr [file isdir tfa2] && [file isdir tfa1]] file delete tfa1 tfa2 set result } {1} test fCmd-21.3 {copy : single file into directory } {notRoot} { catch {file delete -force -- tfa1 tfad} set s [createfile tfa1] file mkdir tfad file copy tfa1 tfad set result [expr [checkcontent tfad/tfa1 $s] && [checkcontent tfa1 $s]] file delete -force tfa1 tfad set result } {1} test fCmd-21.4 {copy : more than one source and target is not a directory} \ {notRoot} { catch {file delete -force -- tfa1 tfa2 tfa3} createfile tfa1 createfile tfa2 createfile tfa3 set result [catch {file copy tfa1 tfa2 tfa3}] file delete tfa1 tfa2 tfa3 set result } {1} test fCmd-21.5 {copy : multiple files into directory } {notRoot} { catch {file delete -force -- tfa1 tfa2 tfad} set s1 [createfile tfa1 ] set s2 [createfile tfa2 ] file mkdir tfad file copy tfa1 tfa2 tfad set r1 [checkcontent tfad/tfa1 $s1] set r2 [checkcontent tfad/tfa2 $s2] set r3 [checkcontent tfa1 $s1] set r4 [checkcontent tfa2 $s2] set result [expr $r1 && $r2 && $r3 && $r4] file delete -force tfa1 tfa2 tfad set result } {1} test fCmd-21.6 {copy: mixed dirs and files into directory} \ {notRoot notFileSharing} { catch {file delete -force -- tfa1 tfad1 tfad2} set s [createfile tfa1 ] file mkdir tfad1 tfad2 file copy tfa1 tfad1 tfad2 set r1 [checkcontent [file join tfad2 tfa1] $s] set r2 [file isdir [file join tfad2 tfad1]] set r3 [checkcontent tfa1 $s] set result [expr $r1 && $r2 && $r3 && [file isdir tfad1]] file delete -force tfa1 tfad1 tfad2 set result } {1} test fCmd-21.7.1 {TclCopyFilesCmd: copy a dangling link} {unixOnly notRoot dontCopyLinks} { file mkdir tfad1 file link -symbolic tfalink tfad1 file delete tfad1 set result [list [catch {file copy tfalink tfalink2} msg] $msg] file delete -force tfalink tfalink2 set result } {1 {error copying "tfalink": the target of this link doesn't exist}} test fCmd-21.7.2 {TclCopyFilesCmd: copy a dangling link} {unixOnly notRoot} { file mkdir tfad1 file link -symbolic tfalink tfad1 file delete tfad1 file copy tfalink tfalink2 set result [string match [file type tfalink2] link] file delete tfalink tfalink2 set result } {1} test fCmd-21.8.1 {TclCopyFilesCmd: copy a link } {unixOnly notRoot dontCopyLinks} { file mkdir tfad1 file link -symbolic tfalink tfad1 file copy tfalink tfalink2 set r1 [file type tfalink]; # link set r2 [file type tfalink2]; # directory set r3 [file isdir tfad1]; # 1 set result [expr {("$r1" == "link") && ("$r2" == "directory") && $r3}] file delete -force tfad1 tfalink tfalink2 set result } {1} test fCmd-21.8.2 {TclCopyFilesCmd: copy a link } {unixOnly notRoot} { file mkdir tfad1 file link -symbolic tfalink tfad1 file copy tfalink tfalink2 set r1 [file type tfalink]; # link set r2 [file type tfalink2]; # link set r3 [file isdir tfad1]; # 1 set result [expr {("$r1" == "link") && ("$r2" == "link") && $r3}] file delete -force tfad1 tfalink tfalink2 set result } {1} test fCmd-21.9 {TclCopyFilesCmd: copy dir with a link in it} {unixOnly notRoot} { file mkdir tfad1 file link -symbolic tfad1/tfalink "[pwd]/tfad1" file copy tfad1 tfad2 set result [string match [file type tfad2/tfalink] link] file delete -force tfad1 tfad2 set result } {1} test fCmd-21.10 {TclFileCopyCmd: copy dir on top of another empty dir w/o -force} \ {notRoot} { catch {file delete -force -- tfa tfad} file mkdir tfa [file join tfad tfa] set r1 [catch {file copy tfa tfad}] set result [expr $r1 && [file isdir tfa]] file delete -force tfa tfad set result } {1} test fCmd-21.11 {TclFileCopyCmd: copy dir on top of a dir w/o -force} {notRoot} { catch {file delete -force -- tfa tfad} file mkdir tfa [file join tfad tfa file] set r1 [catch {file copy tfa tfad}] set result [expr $r1 && [file isdir tfa] && [file isdir [file join tfad tfa file]]] file delete -force tfa tfad set result } {1} test fCmd-21.12 {TclFileCopyCmd: copy dir on top of a non-empty dir w/ -force} \ {notRoot} { catch {file delete -force -- tfa tfad} file mkdir tfa [file join tfad tfa file] set r1 [catch {file copy -force tfa tfad}] set result [expr $r1 && [file isdir tfa] && [file isdir [file join tfad tfa file]]] file delete -force tfa tfad set result } {1} # # Coverage testing for TclpRenameFile # test fCmd-22.1 {TclpRenameFile: rename and overwrite in a single dir} {notRoot} { catch {file delete -force -- tfa1 tfa2} set s [createfile tfa1] set s2 [createfile tfa2 q] set r1 [catch {rename tfa1 tfa2}] file rename -force tfa1 tfa2 set result [expr $r1 && [checkcontent tfa2 $s]] file delete [glob tfa1 tfa2] set result } {1} test fCmd-22.2 {TclpRenameFile: attempt to overwrite itself} {macOrUnix notRoot} { catch {file delete -force -- tfa1} set s [createfile tfa1] file rename -force tfa1 tfa1 set result [checkcontent tfa1 $s] file delete tfa1 set result } {1} test fCmd-22.3 {TclpRenameFile: rename dir to existing dir} {notRoot} { catch {file delete -force -- d1 tfad} file mkdir d1 [file join tfad d1] set r1 [catch {file rename d1 tfad}] set result [expr $r1 && [file isdir d1] && [file isdir [file join tfad d1]]] file delete -force d1 tfad set result } {1} test fCmd-22.4 {TclpRenameFile: rename dir to dir several levels deep} {notRoot} { catch {file delete -force -- d1 tfad} file mkdir d1 [file join tfad a b c] file rename d1 [file join tfad a b c d1] set result [expr ![file isdir d1] && [file isdir [file join tfad a b c d1]]] file delete -force [glob d1 tfad] set result } {1} # # TclMacCopyFile needs to be redone. # test fCmd-22.5 {TclMacCopyFile: copy and overwrite in a single dir} {notRoot} { catch {file delete -force -- tfa1 tfa2} set s [createfile tfa1] set s2 [createfile tfa2 q] set r1 [catch {file copy tfa1 tfa2}] file copy -force tfa1 tfa2 set result [expr $r1 && [checkcontent tfa2 $s] && [checkcontent tfa1 $s]] file delete tfa1 tfa2 set result } {1} # # TclMacMkdir - basic cases are covered elsewhere. # Error cases are not covered. # # # TclMacRmdir # Error cases are not covered. # test fCmd-23.1 {TclMacRmdir: trying to remove a nonempty directory} {notRoot} { catch {file delete -force -- tfad} file mkdir [file join tfad dir] set result [catch {file delete tfad}] file delete -force tfad set result } {1} # # TclMacDeleteFile # Error cases are not covered. # test fCmd-24.1 {TclMacDeleteFile: deleting a normal file} {notRoot} { catch {file delete -force -- tfa1} createfile tfa1 file delete tfa1 file exists tfa1 } {0} # # TclMacCopyDirectory # Error cases are not covered. # test fCmd-25.1 {TclMacCopyDirectory: copying a normal directory} {notRoot notFileSharing} { catch {file delete -force -- tfad1 tfad2} file mkdir [file join tfad1 a b c] file copy tfad1 tfad2 set result [expr [file isdir [file join tfad1 a b c]] && [file isdir [file join tfad2 a b c]]] file delete -force tfad1 tfad2 set result } {1} test fCmd-25.2 {TclMacCopyDirectory: copying a short path normal directory} {notRoot notFileSharing} { catch {file delete -force -- tfad1 tfad2} file mkdir tfad1 file copy tfad1 tfad2 set result [expr [file isdir tfad1] && [file isdir tfad2]] file delete tfad1 tfad2 set result } {1} test fCmd-25.3 {TclMacCopyDirectory: copying dirs between different dirs} {notRoot notFileSharing} { catch {file delete -force -- tfad1 tfad2} file mkdir [file join tfad1 x y z] file mkdir [file join tfad2 dir] file copy tfad1 [file join tfad2 dir] set result [expr [file isdir [file join tfad1 x y z]] && [file isdir [file join tfad2 dir tfad1 x y z]]] file delete -force tfad1 tfad2 set result } {1} # # Functionality tests for TclDeleteFilesCmd # test fCmd-26.1 {TclDeleteFilesCmd: delete symlink} {unixOnly notRoot} { catch {file delete -force -- tfad1 tfad2} file mkdir tfad1 file link -symbolic tfalink tfad1 file delete tfalink set r1 [file isdir tfad1] set r2 [file exists tfalink] set result [expr $r1 && !$r2] file delete tfad1 set result } {1} test fCmd-26.2 {TclDeleteFilesCmd: delete dir with symlink} {unixOnly notRoot} { catch {file delete -force -- tfad1 tfad2} file mkdir tfad1 file mkdir tfad2 file link -symbolic [file join tfad2 link] tfad1 file delete -force tfad2 set r1 [file isdir tfad1] set r2 [file exists tfad2] set result [expr $r1 && !$r2] file delete tfad1 set result } {1} test fCmd-26.3 {TclDeleteFilesCmd: delete dangling symlink} {unixOnly notRoot} { catch {file delete -force -- tfad1 tfad2} file mkdir tfad1 file link -symbolic tfad2 tfad1 file delete tfad1 file delete tfad2 set r1 [file exists tfad1] set r2 [file exists tfad2] set result [expr !$r1 && !$r2] set result } {1} test fCmd-27.2 {TclFileAttrsCmd - Tcl_TranslateFileName fails} {testsetplatform} { set platform [testgetplatform] testsetplatform unix list [catch {file attributes ~_totally_bogus_user} msg] $msg [testsetplatform $platform] } {1 {user "_totally_bogus_user" doesn't exist} {}} test fCmd-27.3 {TclFileAttrsCmd - all attributes} { catch {file delete -force -- foo.tmp} createfile foo.tmp list [catch {file attributes foo.tmp} msg] [expr {[llength $msg] > 0}] [file delete -force -- foo.tmp] } {0 1 {}} test fCmd-27.4 {TclFileAttrsCmd - getting one option} { catch {file delete -force -- foo.tmp} createfile foo.tmp set attrs [file attributes foo.tmp] list [catch {eval file attributes foo.tmp [lindex $attrs 0]}] [file delete -force -- foo.tmp] } {0 {}} # Find a group that exists on this Unix system, or else skip tests that # require Unix groups. if {$tcl_platform(platform) == "unix"} { ::tcltest::testConstraint foundGroup 0 catch { set groupList [exec groups] set group [lindex $groupList 0] ::tcltest::testConstraint foundGroup 1 } } else { ::tcltest::testConstraint foundGroup 1 } test fCmd-27.5 {TclFileAttrsCmd - setting one option} {foundGroup} { catch {file delete -force -- foo.tmp} createfile foo.tmp set attrs [file attributes foo.tmp] list [catch {eval file attributes foo.tmp [lrange $attrs 0 1]} msg] $msg [file delete -force -- foo.tmp] } {0 {} {}} test fCmd-27.6 {TclFileAttrsCmd - setting more than one option} {foundGroup} { catch {file delete -force -- foo.tmp} createfile foo.tmp set attrs [file attributes foo.tmp] list [catch {eval file attributes foo.tmp [lrange $attrs 0 3]} msg] $msg [file delete -force -- foo.tmp] } {0 {} {}} if {[string equal $tcl_platform(platform) "windows"]} { if {[string index $tcl_platform(osVersion) 0] >= 5 \ && ([lindex [file system [temporaryDirectory]] 1] == "NTFS")} { tcltest::testConstraint linkDirectory 1 tcltest::testConstraint linkFile 1 } else { tcltest::testConstraint linkDirectory 0 tcltest::testConstraint linkFile 0 } } else { tcltest::testConstraint linkFile 1 tcltest::testConstraint linkDirectory 1 } test fCmd-28.1 {file link} { list [catch {file link} msg] $msg } {1 {wrong # args: should be "file link ?-linktype? linkname ?target?"}} test fCmd-28.2 {file link} { list [catch {file link a b c d} msg] $msg } {1 {wrong # args: should be "file link ?-linktype? linkname ?target?"}} test fCmd-28.3 {file link} { list [catch {file link abc b c} msg] $msg } {1 {bad switch "abc": must be -symbolic or -hard}} test fCmd-28.4 {file link} { list [catch {file link -abc b c} msg] $msg } {1 {bad switch "-abc": must be -symbolic or -hard}} cd [workingDirectory] makeDirectory abc.dir makeDirectory abc2.dir makeFile contents abc.file makeFile contents abc2.file cd [temporaryDirectory] test fCmd-28.5 {file link: source already exists} {linkDirectory} { cd [temporaryDirectory] set res [list [catch {file link abc.dir abc2.dir} msg] $msg] cd [workingDirectory] set res } {1 {could not create new link "abc.dir": that path already exists}} test fCmd-28.6 {file link: unsupported operation} {linkDirectory macOrWin} { cd [temporaryDirectory] set res [list [catch {file link -hard abc.link abc.dir} msg] $msg] cd [workingDirectory] set res } {1 {could not create new link "abc.link" pointing to "abc.dir": illegal operation on a directory}} test fCmd-28.7 {file link: source already exists} {linkFile} { cd [temporaryDirectory] set res [list [catch {file link abc.file abc2.file} msg] $msg] cd [workingDirectory] set res } {1 {could not create new link "abc.file": that path already exists}} test fCmd-28.8 {file link} {linkFile winOnly} { cd [temporaryDirectory] set res [list [catch {file link -symbolic abc.link abc.file} msg] $msg] cd [workingDirectory] set res } {1 {could not create new link "abc.link" pointing to "abc.file": not a directory}} test fCmd-28.9 {file link: success with file} {linkFile} { cd [temporaryDirectory] file delete -force abc.link set res [list [catch {file link abc.link abc.file} msg] $msg] cd [workingDirectory] set res } {0 abc.file} cd [temporaryDirectory] catch {file delete -force abc.link} cd [workingDirectory] test fCmd-28.10 {file link: linking to nonexistent path} {linkDirectory} { cd [temporaryDirectory] file delete -force abc.link set res [list [catch {file link abc.link abc2.doesnt} msg] $msg] cd [workingDirectory] set res } {1 {could not create new link "abc.link" since target "abc2.doesnt" doesn't exist}} test fCmd-28.11 {file link: success with directory} {linkDirectory} { cd [temporaryDirectory] file delete -force abc.link set res [list [catch {file link abc.link abc.dir} msg] $msg] cd [workingDirectory] set res } {0 abc.dir} test fCmd-28.12 {file link: cd into a link} {linkDirectory} { cd [temporaryDirectory] file delete -force abc.link file link abc.link abc.dir set orig [pwd] cd abc.link set dir [pwd] cd .. set up [pwd] cd $orig # now '$up' should be either $orig or [file dirname abc.dir], # depending on whether 'cd' actually moves to the destination # of a link, or simply treats the link as a directory. # (on windows the former, on unix the latter, I believe) if {([file normalize $up] != [file normalize $orig]) \ && ([file normalize $up] != [file normalize [file dirname abc.dir]])} { set res "wrong directory with 'cd $link ; cd ..'" } else { set res "ok" } cd [workingDirectory] set res } {ok} test fCmd-28.13 {file link} {linkDirectory} { # duplicate link throws error cd [temporaryDirectory] set res [list [catch {file link abc.link abc.dir} msg] $msg] cd [workingDirectory] set res } {1 {could not create new link "abc.link": that path already exists}} test fCmd-28.14 {file link: deletes link not dir} {linkDirectory} { cd [temporaryDirectory] file delete -force abc.link set res [list [file exists abc.link] [file exists abc.dir]] cd [workingDirectory] set res } {0 1} test fCmd-28.15.1 {file link: copies link not dir} {linkDirectory dontCopyLinks} { cd [temporaryDirectory] file delete -force abc.link file link abc.link abc.dir file copy abc.link abc2.link # abc2.linkdir was a copy of a link to a dir, so it should end up as # a directory, not a link (links trace to endpoint). set res [list [file type abc2.link] [file tail [file link abc.link]]] cd [workingDirectory] set res } {directory abc.dir} test fCmd-28.15.2 {file link: copies link not dir} {linkDirectory} { cd [temporaryDirectory] file delete -force abc.link file link abc.link abc.dir file copy abc.link abc2.link set res [list [file type abc2.link] [file tail [file link abc2.link]]] cd [workingDirectory] set res } {link abc.dir} cd [temporaryDirectory] file delete -force abc.link file delete -force abc2.link file copy abc.file abc.dir file copy abc2.file abc.dir cd [workingDirectory] test fCmd-28.16 {file link: glob inside link} {linkDirectory} { cd [temporaryDirectory] file delete -force abc.link file link abc.link abc.dir set res [lsort [glob -dir abc.link -tails *]] cd [workingDirectory] set res } [lsort [list abc.file abc2.file]] test fCmd-28.17 {file link: glob -type l} {linkDirectory} { cd [temporaryDirectory] set res [glob -dir [pwd] -type l -tails abc*] cd [workingDirectory] set res } {abc.link} test fCmd-28.18 {file link: glob -type d} {linkDirectory} { cd [temporaryDirectory] set res [lsort [glob -dir [pwd] -type d -tails abc*]] cd [workingDirectory] set res } [lsort [list abc.link abc.dir abc2.dir]] test fCmd-29.1 {weird memory corruption fault} { catch {set res [open [file join ~a_totally_bogus_user_id/foo bar]]} } 1 cd [temporaryDirectory] file delete -force abc.link cd [workingDirectory] test fCmd-30.1 {file writable on 'My Documents'} -setup { # Get the localized version of the folder name by looking in the registry. set mydocsname [registry get {HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders} Personal] } -constraints {win reg} -body { file writable $mydocsname } -result 1 test fCmd-30.2 {file readable on 'NTUSER.DAT'} -constraints {win} -body { expr {[info exists env(USERPROFILE)] && [file exists $env(USERPROFILE)/NTUSER.DAT] && [file readable $env(USERPROFILE)/NTUSER.DAT]} } -result {1} test fCmd-30.3 {file readable on 'pagefile.sys'} -constraints {win} -body { set r {} if {[info exists env(SystemDrive)]} { set path $env(SystemDrive)/pagefile.sys lappend r exists [file exists $path] lappend r readable [file readable $path] lappend r stat [catch {file stat $path a} e] $e } return $r } -result {exists 1 readable 0 stat 0 {}} removeFile abc2.file removeFile abc.file removeDirectory abc2.dir removeDirectory abc.dir # cleanup cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/env.test0000644003604700454610000001652011737050674013556 0ustar dgp771div# Commands covered: none (tests environment variable implementation) # # This file contains a collection of tests for one or more of the Tcl built-in # commands. Sourcing this file into Tcl runs the tests and generates output # for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution of # this file, and for a DISCLAIMER OF ALL WARRANTIES. package require tcltest 2 namespace import -force ::tcltest::* # # These tests will run on any platform (and indeed crashed on the Mac). So put # them before you test for the existance of exec. # test env-1.1 {propagation of env values to child interpreters} { catch {interp delete child} catch {unset env(test)} interp create child set env(test) garbage set return [child eval {set env(test)}] interp delete child unset env(test) set return } {garbage} # # This one crashed on Solaris under Tcl8.0, so we only want to make sure it # runs. # test env-1.2 {lappend to env value} { catch {unset env(test)} set env(test) aaaaaaaaaaaaaaaa append env(test) bbbbbbbbbbbbbb unset env(test) } {} test env-1.3 {reflection of env by "array names"} { catch {interp delete child} catch {unset env(test)} interp create child child eval {set env(test) garbage} set names [array names env] interp delete child set ix [lsearch $names test] catch {unset env(test)} expr {$ix >= 0} } {1} # Some tests require the "exec" command. # Skip them if exec is not defined. testConstraint exec [llength [info commands exec]] set printenvScript [makeFile { proc lrem {listname name} { upvar $listname list set i [lsearch $list $name] if {$i >= 0} { set list [lreplace $list $i $i] } return $list } proc mangle s { regsub -all {\[|\\|\]} $s {\\&} s regsub -all {[\u0000-\u001f\u007f-\uffff]} $s {[manglechar &]} s return [subst -novariables $s] } proc manglechar c { return [format {\u%04x} [scan $c %c]] } set names [lsort [array names env]] if {$tcl_platform(platform) == "windows"} { lrem names HOME lrem names COMSPEC lrem names ComSpec lrem names "" } foreach name { TCL_LIBRARY PATH LD_LIBRARY_PATH LIBPATH PURE_PROG_NAME DISPLAY SHLIB_PATH SYSTEMDRIVE SYSTEMROOT DYLD_LIBRARY_PATH DYLD_FRAMEWORK_PATH DYLD_NEW_LOCAL_SHARED_REGIONS DYLD_NO_FIX_PREBINDING __CF_USER_TEXT_ENCODING SECURITYSESSIONID LANG WINDIR TERM CommonProgramFiles ProgramFiles } { lrem names $name } foreach p $names { puts "[mangle $p]=[mangle $env($p)]" } exit } printenv] # [exec] is required here to see the actual environment received # by child processes. proc getenv {} { global printenvScript tcltest catch {exec [interpreter] $printenvScript} out if {$out == "child process exited abnormally"} { set out {} } return $out } # Save the current environment variables at the start of the test. foreach name [array names env] { set env2([string toupper $name]) $env($name) unset env($name) } # Added the following lines so that child tcltest can actually find its # library if the initial tcltest is run from a non-standard place. # ('saved' env vars) foreach name { TCL_LIBRARY PATH LD_LIBRARY_PATH LIBPATH DISPLAY SHLIB_PATH SYSTEMDRIVE SYSTEMROOT DYLD_LIBRARY_PATH DYLD_FRAMEWORK_PATH DYLD_NEW_LOCAL_SHARED_REGIONS DYLD_NO_FIX_PREBINDING SECURITYSESSIONID LANG WINDIR TERM CommonProgramFiles ProgramFiles } { if {[info exists env2($name)]} { set env($name) $env2($name); } } test env-2.1 {adding environment variables} {exec} { getenv } {} set env(NAME1) "test string" test env-2.2 {adding environment variables} {exec} { getenv } {NAME1=test string} set env(NAME2) "more" test env-2.3 {adding environment variables} {exec} { getenv } {NAME1=test string NAME2=more} set env(XYZZY) "garbage" test env-2.4 {adding environment variables} {exec} { getenv } {NAME1=test string NAME2=more XYZZY=garbage} set env(NAME2) "new value" test env-3.1 {changing environment variables} {exec} { set result [getenv] unset env(NAME2) set result } {NAME1=test string NAME2=new value XYZZY=garbage} test env-4.1 {unsetting environment variables} {exec} { set result [getenv] unset env(NAME1) set result } {NAME1=test string XYZZY=garbage} test env-4.2 {unsetting environment variables} {exec} { set result [getenv] unset env(XYZZY) set result } {XYZZY=garbage} test env-4.3 {setting international environment variables} {exec} { set env(\ua7) \ub6 getenv } {\u00a7=\u00b6} test env-4.4 {changing international environment variables} {exec} { set env(\ua7) \ua7 getenv } {\u00a7=\u00a7} test env-4.5 {unsetting international environment variables} {exec} { set env(\ub6) \ua7 unset env(\ua7) set result [getenv] unset env(\ub6) set result } {\u00b6=\u00a7} test env-5.0 {corner cases - set a value, it should exist} {} { set env(temp) a set result [set env(temp)] unset env(temp) set result } {a} test env-5.1 {corner cases - remove one elem at a time} {} { # When no environment variables exist, the env var will # contain no entries. The "array names" call synchs up # the C-level environ array with the Tcl level env array. # Make sure an empty Tcl array is created. set x [array get env] foreach e [array names env] { unset env($e) } set result [catch {array names env}] array set env $x set result } {0} test env-5.2 {corner cases - unset the env array} {} { # Unsetting a variable in an interp detaches the C-level # traces from the Tcl "env" variable. interp create i i eval { unset env } i eval { set env(THIS_SHOULDNT_EXIST) a} set result [info exists env(THIS_SHOULDNT_EXIST)] interp delete i set result } {0} test env-5.3 {corner cases - unset the env in master should unset child} {} { # Variables deleted in a master interp should be deleted in # child interp too. interp create i i eval { set env(THIS_SHOULD_EXIST) a} set result [set env(THIS_SHOULD_EXIST)] unset env(THIS_SHOULD_EXIST) lappend result [i eval {catch {set env(THIS_SHOULD_EXIST)}}] interp delete i set result } {a 1} test env-5.4 {corner cases - unset the env array} {} { # The info exists command should be in synch with the env array. # Know Bug: 1737 interp create i i eval { set env(THIS_SHOULD_EXIST) a} set result [info exists env(THIS_SHOULD_EXIST)] lappend result [set env(THIS_SHOULD_EXIST)] lappend result [info exists env(THIS_SHOULD_EXIST)] interp delete i set result } {1 a 1} test env-5.5 {corner cases - cannot have null entries on Windows} {pcOnly} { set env() a catch {set env()} } {1} test env-6.1 {corner cases - add lots of env variables} {} { set size [array size env] for {set i 0} {$i < 100} {incr i} { set env(BOGUS$i) $i } expr {[array size env] - $size} } 100 # Restore the environment variables at the end of the test. foreach name [array names env] { unset env($name) } foreach name [array names env2] { set env($name) $env2($name) } # cleanup removeFile $printenvScript ::tcltest::cleanupTests return # Local Variables: # mode: tcl # End: tcl8.4.20/tests/util.test0000644003604700454610000002654111737050674013747 0ustar dgp771div# This file is a Tcl script to test the code in the file tclUtil.c. # This file is organized in the standard fashion for Tcl tests. # # Copyright (c) 1995-1998 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } test util-1.1 {TclFindElement procedure - binary element in middle of list} { lindex {0 foo\x00help 1} 1 } "foo\x00help" test util-1.2 {TclFindElement procedure - binary element at end of list} { lindex {0 foo\x00help} 1 } "foo\x00help" test util-2.1 {TclCopyAndCollapse procedure - normal string} { lindex {0 foo} 1 } {foo} test util-2.2 {TclCopyAndCollapse procedure - string with backslashes} { lindex {0 foo\n\x00help 1} 1 } "foo\n\x00help" test util-3.1 {Tcl_ScanCountedElement procedure - don't leave unmatched braces} { # This test checks for a very tricky feature. Any list element # generated with Tcl_ScanCountedElement and Tcl_ConvertElement must # have the property that it can be enclosing in curly braces to make # an embedded sub-list. If this property doesn't hold, then # Tcl_DStringStartSublist doesn't work. set x {} lappend x " \\\{ \\" concat $x [llength "{$x}"] } {\ \\\{\ \\ 1} test util-4.1 {Tcl_ConcatObj - backslash-space at end of argument} { concat a {b\ } c } {a b\ c} test util-4.2 {Tcl_ConcatObj - backslash-space at end of argument} { concat a {b\ } c } {a b\ c} test util-4.3 {Tcl_ConcatObj - backslash-space at end of argument} { concat a {b\\ } c } {a b\\ c} test util-4.4 {Tcl_ConcatObj - backslash-space at end of argument} { concat a {b } c } {a b c} test util-4.5 {Tcl_ConcatObj - backslash-space at end of argument} { concat a { } c } {a c} test util-4.6 {Tcl_ConcatObj - utf-8 sequence with "whitespace" char} { # Check for Bug #227512. If this violates C isspace, then it returns \xc3. concat \xe0 } \xe0 proc Wrapper_Tcl_StringMatch {pattern string} { # Forces use of Tcl_StringMatch, not Tcl_UniCharCaseMatch switch -glob -- $string $pattern {return 1} default {return 0} } test util-5.1 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch ab*c abc } 1 test util-5.2 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch ab**c abc } 1 test util-5.3 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch ab* abcdef } 1 test util-5.4 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch *c abc } 1 test util-5.5 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch *3*6*9 0123456789 } 1 test util-5.6 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch *3*6*9 01234567890 } 0 test util-5.7 {Tcl_StringMatch: UTF-8} { Wrapper_Tcl_StringMatch *u \u4e4fu } 1 test util-5.8 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch a?c abc } 1 test util-5.9 {Tcl_StringMatch: UTF-8} { # skip one character in string Wrapper_Tcl_StringMatch a?c a\u4e4fc } 1 test util-5.10 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch a??c abc } 0 test util-5.11 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch ?1??4???8? 0123456789 } 1 test util-5.12 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch {[abc]bc} abc } 1 test util-5.13 {Tcl_StringMatch: UTF-8} { # string += Tcl_UtfToUniChar(string, &ch); Wrapper_Tcl_StringMatch "\[\u4e4fxy\]bc" "\u4e4fbc" } 1 test util-5.14 {Tcl_StringMatch} { # if ((*pattern == ']') || (*pattern == '\0')) # badly formed pattern Wrapper_Tcl_StringMatch {[]} {[]} } 0 test util-5.15 {Tcl_StringMatch} { # if ((*pattern == ']') || (*pattern == '\0')) # badly formed pattern Wrapper_Tcl_StringMatch {[} {[} } 0 test util-5.16 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch {a[abc]c} abc } 1 test util-5.17 {Tcl_StringMatch: UTF-8} { # pattern += Tcl_UtfToUniChar(pattern, &endChar); # get 1 UTF-8 character Wrapper_Tcl_StringMatch "a\[a\u4e4fc]c" "a\u4e4fc" } 1 test util-5.18 {Tcl_StringMatch: UTF-8} { # pattern += Tcl_UtfToUniChar(pattern, &endChar); # proper advance: wrong answer would match on UTF trail byte of \u4e4f Wrapper_Tcl_StringMatch {a[a\u4e4fc]c} [bytestring a\u008fc] } 0 test util-5.19 {Tcl_StringMatch: UTF-8} { # pattern += Tcl_UtfToUniChar(pattern, &endChar); # proper advance. Wrapper_Tcl_StringMatch {a[a\u4e4fc]c} "acc" } 1 test util-5.20 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch {a[xyz]c} abc } 0 test util-5.21 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch {12[2-7]45} 12345 } 1 test util-5.22 {Tcl_StringMatch: UTF-8 range} { Wrapper_Tcl_StringMatch "\[\u4e00-\u4e4f]" "0" } 0 test util-5.23 {Tcl_StringMatch: UTF-8 range} { Wrapper_Tcl_StringMatch "\[\u4e00-\u4e4f]" "\u4e33" } 1 test util-5.24 {Tcl_StringMatch: UTF-8 range} { Wrapper_Tcl_StringMatch "\[\u4e00-\u4e4f]" "\uff08" } 0 test util-5.25 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch {12[ab2-4cd]45} 12345 } 1 test util-5.26 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch {12[ab2-4cd]45} 12b45 } 1 test util-5.27 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch {12[ab2-4cd]45} 12d45 } 1 test util-5.28 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch {12[ab2-4cd]45} 12145 } 0 test util-5.29 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch {12[ab2-4cd]45} 12545 } 0 test util-5.30 {Tcl_StringMatch: forwards range} { Wrapper_Tcl_StringMatch {[k-w]} "z" } 0 test util-5.31 {Tcl_StringMatch: forwards range} { Wrapper_Tcl_StringMatch {[k-w]} "w" } 1 test util-5.32 {Tcl_StringMatch: forwards range} { Wrapper_Tcl_StringMatch {[k-w]} "r" } 1 test util-5.33 {Tcl_StringMatch: forwards range} { Wrapper_Tcl_StringMatch {[k-w]} "k" } 1 test util-5.34 {Tcl_StringMatch: forwards range} { Wrapper_Tcl_StringMatch {[k-w]} "a" } 0 test util-5.35 {Tcl_StringMatch: reverse range} { Wrapper_Tcl_StringMatch {[w-k]} "z" } 0 test util-5.36 {Tcl_StringMatch: reverse range} { Wrapper_Tcl_StringMatch {[w-k]} "w" } 1 test util-5.37 {Tcl_StringMatch: reverse range} { Wrapper_Tcl_StringMatch {[w-k]} "r" } 1 test util-5.38 {Tcl_StringMatch: reverse range} { Wrapper_Tcl_StringMatch {[w-k]} "k" } 1 test util-5.39 {Tcl_StringMatch: reverse range} { Wrapper_Tcl_StringMatch {[w-k]} "a" } 0 test util-5.40 {Tcl_StringMatch: skip correct number of ']'} { Wrapper_Tcl_StringMatch {[A-]x} Ax } 0 test util-5.41 {Tcl_StringMatch: skip correct number of ']'} { Wrapper_Tcl_StringMatch {[A-]]x} Ax } 1 test util-5.42 {Tcl_StringMatch: skip correct number of ']'} { Wrapper_Tcl_StringMatch {[A-]]x} \ue1x } 0 test util-5.43 {Tcl_StringMatch: skip correct number of ']'} { Wrapper_Tcl_StringMatch \[A-]\ue1]x \ue1x } 1 test util-5.44 {Tcl_StringMatch: skip correct number of ']'} { Wrapper_Tcl_StringMatch {[A-]h]x} hx } 1 test util-5.45 {Tcl_StringMatch} { # if (*pattern == '\0') # badly formed pattern, still treats as a set Wrapper_Tcl_StringMatch {[a} a } 1 test util-5.46 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch {a\*b} a*b } 1 test util-5.47 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch {a\*b} ab } 0 test util-5.48 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch {a\*\?\[\]\\\x} "a*?\[\]\\x" } 1 test util-5.49 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch ** "" } 1 test util-5.50 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch *. "" } 0 test util-5.51 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch "" "" } 1 test util-6.1 {Tcl_PrintDouble - using tcl_precision} { concat x[expr 1.4] } {x1.4} test util-6.2 {Tcl_PrintDouble - using tcl_precision} { concat x[expr 1.39999999999] } {x1.39999999999} test util-6.3 {Tcl_PrintDouble - using tcl_precision} { concat x[expr 1.399999999999] } {x1.4} test util-6.4 {Tcl_PrintDouble - using tcl_precision} { set tcl_precision 5 concat x[expr 1.123412341234] } {x1.1234} set tcl_precision 12 test util-6.5 {Tcl_PrintDouble - make sure there's a decimal point} { concat x[expr 2.0] } {x2.0} test util-6.6 {Tcl_PrintDouble - make sure there's a decimal point} {eformat} { concat x[expr 3.0e98] } {x3e+98} test util-7.1 {TclPrecTraceProc - unset callbacks} { set tcl_precision 7 set x $tcl_precision unset tcl_precision list $x $tcl_precision } {7 7} test util-7.2 {TclPrecTraceProc - read traces, sharing among interpreters} { set tcl_precision 12 interp create child set x [child eval set tcl_precision] child eval {set tcl_precision 6} interp delete child list $x $tcl_precision } {12 6} test util-7.3 {TclPrecTraceProc - write traces, safe interpreters} { set tcl_precision 12 interp create -safe child set x [child eval { list [catch {set tcl_precision 8} msg] $msg }] interp delete child list $x $tcl_precision } {{1 {can't set "tcl_precision": can't modify precision from a safe interpreter}} 12} test util-7.4 {TclPrecTraceProc - write traces, bogus values} { set tcl_precision 12 list [catch {set tcl_precision abc} msg] $msg $tcl_precision } {1 {can't set "tcl_precision": improper value for precision} 12} set tcl_precision 12 # This test always succeeded in the C locale anyway... test util-8.1 {TclNeedSpace - correct UTF8 handling} { # Bug 411825 # Note that this test relies on the fact that # [interp target] calls on Tcl_AppendElement() # which calls on TclNeedSpace(). If [interp target] # is ever updated, this test will no longer test # TclNeedSpace. interp create \u5420 interp create [list \u5420 foo] interp alias {} fooset [list \u5420 foo] set set result [interp target {} fooset] interp delete \u5420 set result } "\u5420 foo" tcltest::testConstraint testdstring [expr {[info commands testdstring] != {}}] test util-8.2 {TclNeedSpace - correct UTF8 handling} testdstring { # Bug 411825 # This tests the same bug as the previous test, but # should be more future-proof, as the DString # operations will likely continue to call TclNeedSpace testdstring free testdstring append \u5420 -1 testdstring element foo llength [testdstring get] } 2 test util-8.3 {TclNeedSpace - correct UTF8 handling} testdstring { # Bug 411825 - new variant reported by Dossy Shiobara testdstring free testdstring append \u00A0 -1 testdstring element foo llength [testdstring get] } 2 test util-8.4 {TclNeedSpace - correct UTF8 handling} testdstring { # Another bug uncovered while fixing 411825 testdstring free testdstring append {\ } -1 testdstring append \{ -1 testdstring element foo llength [testdstring get] } 2 test util-8.5 {TclNeedSpace - correct UTF8 handling} testdstring { # Note that in this test TclNeedSpace actually gets it wrong, # claiming we need a space when we really do not. Extra space # between list elements is harmless though, and better to have # extra space in really weird string reps of lists, than to # invest the effort required to make TclNeedSpace foolproof. testdstring free testdstring append {\\ } -1 testdstring element foo list [llength [testdstring get]] [string length [testdstring get]] } {2 7} test util-8.6 {TclNeedSpace - correct UTF8 handling} testdstring { # Another example of TclNeedSpace harmlessly getting it wrong. testdstring free testdstring append {\\ } -1 testdstring append \{ -1 testdstring element foo testdstring append \} -1 list [llength [testdstring get]] [string length [testdstring get]] } {2 9} # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/join.test0000644003604700454610000000302411737050674013720 0ustar dgp771div# Commands covered: join # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } test join-1.1 {basic join commands} { join {a b c} xyz } axyzbxyzc test join-1.2 {basic join commands} { join {a b c} {} } abc test join-1.3 {basic join commands} { join {} xyz } {} test join-1.4 {basic join commands} { join {12 34 56} } {12 34 56} test join-2.1 {join errors} { list [catch join msg] $msg $errorCode } {1 {wrong # args: should be "join list ?joinString?"} NONE} test join-2.2 {join errors} { list [catch {join a b c} msg] $msg $errorCode } {1 {wrong # args: should be "join list ?joinString?"} NONE} test join-2.3 {join errors} { list [catch {join "a \{ c" 111} msg] $msg $errorCode } {1 {unmatched open brace in list} NONE} test join-3.1 {joinString is binary ok} { string length [join {a b c} a\0b] } 9 test join-3.2 {join is binary ok} { string length [join "a\0b a\0b a\0b"] } 11 # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/uplevel.test0000644003604700454610000000624211737050674014442 0ustar dgp771div# Commands covered: uplevel # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } proc a {x y} { newset z [expr $x+$y] return $z } proc newset {name value} { uplevel set $name $value uplevel 1 {uplevel 1 {set xyz 22}} } test uplevel-1.1 {simple operation} { set xyz 0 a 22 33 } 55 test uplevel-1.2 {command is another uplevel command} { set xyz 0 a 22 33 set xyz } 22 proc a1 {} { b1 global a a1 set a $x set a1 $y } proc b1 {} { c1 global b b1 set b $x set b1 $y } proc c1 {} { uplevel 1 set x 111 uplevel #2 set y 222 uplevel 2 set x 333 uplevel #1 set y 444 uplevel 3 set x 555 uplevel #0 set y 666 } a1 test uplevel-2.1 {relative and absolute uplevel} {set a} 333 test uplevel-2.2 {relative and absolute uplevel} {set a1} 444 test uplevel-2.3 {relative and absolute uplevel} {set b} 111 test uplevel-2.4 {relative and absolute uplevel} {set b1} 222 test uplevel-2.5 {relative and absolute uplevel} {set x} 555 test uplevel-2.6 {relative and absolute uplevel} {set y} 666 test uplevel-3.1 {uplevel to same level} { set x 33 uplevel #0 set x 44 set x } 44 test uplevel-3.2 {uplevel to same level} { set x 33 uplevel 0 set x } 33 test uplevel-3.3 {uplevel to same level} { set y xxx proc a1 {} {set y 55; uplevel 0 set y 66; return $y} a1 } 66 test uplevel-3.4 {uplevel to same level} { set y zzz proc a1 {} {set y 55; uplevel #1 set y} a1 } 55 test uplevel-4.1 {error: non-existent level} { list [catch c1 msg] $msg } {1 {bad level "#2"}} test uplevel-4.2 {error: non-existent level} { proc c2 {} {uplevel 3 {set a b}} list [catch c2 msg] $msg } {1 {bad level "3"}} test uplevel-4.3 {error: not enough args} { list [catch uplevel msg] $msg } {1 {wrong # args: should be "uplevel ?level? command ?arg ...?"}} test uplevel-4.4 {error: not enough args} { proc upBug {} {uplevel 1} list [catch upBug msg] $msg } {1 {wrong # args: should be "uplevel ?level? command ?arg ...?"}} proc a2 {} { uplevel a3 } proc a3 {} { global x y set x [info level] set y [info level 1] } a2 test uplevel-5.1 {info level} {set x} 1 test uplevel-5.2 {info level} {set y} a3 namespace eval ns1 { proc set args {return ::ns1} } proc a2 {} { uplevel {set x ::} } test uplevel-6.1 {uplevel and shadowed cmds} { set res [namespace eval ns1 a2] lappend res [namespace eval ns2 a2] lappend res [namespace eval ns1 a2] namespace eval ns1 {rename set {}} lappend res [namespace eval ns1 a2] } {::ns1 :: ::ns1 ::} # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/error.test0000644003604700454610000001415511737050674014121 0ustar dgp771div# Commands covered: error, catch # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994-1996 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import -force ::tcltest::* } proc foo {} { global errorInfo set a [catch {format [error glorp2]} b] error {Human-generated} } proc foo2 {} { global errorInfo set a [catch {format [error glorp2]} b] error {Human-generated} $errorInfo } # Catch errors occurring in commands and errors from "error" command test error-1.1 {simple errors from commands} { catch {format [string index]} b } 1 test error-1.2 {simple errors from commands} { catch {format [string index]} b set b } {wrong # args: should be "string index string charIndex"} test error-1.3 {simple errors from commands} { catch {format [string index]} b set errorInfo # this used to return '... while executing ...', but # string index is fully compiled as of 8.4a3 } {wrong # args: should be "string index string charIndex" while executing "string index"} test error-1.4 {simple errors from commands} { catch {error glorp} b } 1 test error-1.5 {simple errors from commands} { catch {error glorp} b set b } glorp test error-1.6 {simple errors from commands} { catch {catch a b c} b } 1 test error-1.7 {simple errors from commands} { catch {catch a b c} b set b } {wrong # args: should be "catch command ?varName?"} test error-1.8 {simple errors from commands} {nonPortable} { # This test is non-portable: it generates a memory fault on # machines like DEC Alphas (infinite recursion overflows # stack?) proc p {} { uplevel 1 catch p error } p } 0 # Check errors nested in procedures. Also check the optional argument # to "error" to generate a new error trace. test error-2.1 {errors in nested procedures} { catch foo b } 1 test error-2.2 {errors in nested procedures} { catch foo b set b } {Human-generated} test error-2.3 {errors in nested procedures} { catch foo b set errorInfo } {Human-generated while executing "error {Human-generated}" (procedure "foo" line 4) invoked from within "foo"} test error-2.4 {errors in nested procedures} { catch foo2 b } 1 test error-2.5 {errors in nested procedures} { catch foo2 b set b } {Human-generated} test error-2.6 {errors in nested procedures} { catch foo2 b set errorInfo } {glorp2 while executing "error glorp2" (procedure "foo2" line 3) invoked from within "foo2"} # Error conditions related to "catch". test error-3.1 {errors in catch command} { list [catch {catch} msg] $msg } {1 {wrong # args: should be "catch command ?varName?"}} test error-3.2 {errors in catch command} { list [catch {catch a b c} msg] $msg } {1 {wrong # args: should be "catch command ?varName?"}} test error-3.3 {errors in catch command} { catch {unset a} set a(0) 22 list [catch {catch {format 44} a} msg] $msg } {1 {couldn't save command result in variable}} catch {unset a} # More tests related to errorInfo and errorCode test error-4.1 {errorInfo and errorCode variables} { list [catch {error msg1 msg2 msg3} msg] $msg $errorInfo $errorCode } {1 msg1 msg2 msg3} test error-4.2 {errorInfo and errorCode variables} { list [catch {error msg1 {} msg3} msg] $msg $errorInfo $errorCode } {1 msg1 {msg1 while executing "error msg1 {} msg3"} msg3} test error-4.3 {errorInfo and errorCode variables} { list [catch {error msg1 {}} msg] $msg $errorInfo $errorCode } {1 msg1 {msg1 while executing "error msg1 {}"} NONE} test error-4.4 {errorInfo and errorCode variables} { set errorCode bogus list [catch {error msg1} msg] $msg $errorInfo $errorCode } {1 msg1 {msg1 while executing "error msg1"} NONE} test error-4.5 {errorInfo and errorCode variables} { set errorCode bogus list [catch {error msg1 msg2 {}} msg] $msg $errorInfo $errorCode } {1 msg1 msg2 {}} # Errors in error command itself test error-5.1 {errors in error command} { list [catch {error} msg] $msg } {1 {wrong # args: should be "error message ?errorInfo? ?errorCode?"}} test error-5.2 {errors in error command} { list [catch {error a b c d} msg] $msg } {1 {wrong # args: should be "error message ?errorInfo? ?errorCode?"}} # Make sure that catch resets error information test error-6.1 {catch must reset error state} { catch {error outer [catch {error inner inner.errorInfo inner.errorCode}]} list $errorCode $errorInfo } {NONE 1} test error-6.3 {catch must reset error state} { set errorCode BUG catch {error outer [catch set]} list $errorCode $errorInfo } {NONE 1} test error-6.4 {catch must reset error state} { catch {error [catch {error foo bar baz}] 1} list $errorCode $errorInfo } {NONE 1} test error-6.7 {catch must reset error state} { proc foo {} { return -code error -errorinfo [catch {error foo bar baz}] } catch foo list $errorCode } {NONE} test error-6.9 {catch must reset error state} { proc foo {} { return -code error [catch {error foo bar baz}] } catch foo list $errorCode } {NONE} namespace eval ::tcl::test::error { test error-7.0 {Bug 1397843} -body { variable cmds proc EIWrite args { variable cmds lappend cmds [lindex [info level -2] 0] } proc BadProc {} { set i a incr i } trace add variable ::errorInfo write [namespace code EIWrite] catch BadProc trace remove variable ::errorInfo write [namespace code EIWrite] set cmds } -match glob -result {*BadProc*} } namespace delete ::tcl::test::error # cleanup catch {rename p ""} ::tcltest::cleanupTests return tcl8.4.20/tests/cmdIL.test0000644003604700454610000003420311737050674013754 0ustar dgp771div# This file contains a collection of tests for the procedures in the # file tclCmdIL.c. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1997 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } test cmdIL-1.1 {Tcl_LsortObjCmd procedure} { list [catch {lsort} msg] $msg } {1 {wrong # args: should be "lsort ?options? list"}} test cmdIL-1.2 {Tcl_LsortObjCmd procedure} { list [catch {lsort -foo {1 3 2 5}} msg] $msg } {1 {bad option "-foo": must be -ascii, -command, -decreasing, -dictionary, -increasing, -index, -integer, -real, or -unique}} test cmdIL-1.3 {Tcl_LsortObjCmd procedure, default options} { lsort {d e c b a \{ d35 d300} } {a b c d d300 d35 e \{} test cmdIL-1.4 {Tcl_LsortObjCmd procedure, -ascii option} { lsort -integer -ascii {d e c b a d35 d300} } {a b c d d300 d35 e} test cmdIL-1.5 {Tcl_LsortObjCmd procedure, -command option} { list [catch {lsort -command {1 3 2 5}} msg] $msg } {1 {"-command" option must be followed by comparison command}} test cmdIL-1.6 {Tcl_LsortObjCmd procedure, -command option} { proc cmp {a b} { expr {[string match x* $b] - [string match x* $a]} } lsort -command cmp {x1 abc x2 def x3 x4} } {x1 x2 x3 x4 abc def} test cmdIL-1.7 {Tcl_LsortObjCmd procedure, -decreasing option} { lsort -decreasing {d e c b a d35 d300} } {e d35 d300 d c b a} test cmdIL-1.8 {Tcl_LsortObjCmd procedure, -dictionary option} { lsort -dictionary {d e c b a d35 d300} } {a b c d d35 d300 e} test cmdIL-1.9 {Tcl_LsortObjCmd procedure, -dictionary option} { lsort -dictionary {1k 0k 10k} } {0k 1k 10k} test cmdIL-1.10 {Tcl_LsortObjCmd procedure, -increasing option} { lsort -decreasing -increasing {d e c b a d35 d300} } {a b c d d300 d35 e} test cmdIL-1.11 {Tcl_LsortObjCmd procedure, -index option} { list [catch {lsort -index {1 3 2 5}} msg] $msg } {1 {"-index" option must be followed by list index}} test cmdIL-1.12 {Tcl_LsortObjCmd procedure, -index option} { list [catch {lsort -index foo {1 3 2 5}} msg] $msg } {1 {bad index "foo": must be integer or end?-integer?}} test cmdIL-1.13 {Tcl_LsortObjCmd procedure, -index option} { lsort -index end -integer {{2 25} {10 20 50 100} {3 16 42} 1} } {1 {2 25} {3 16 42} {10 20 50 100}} test cmdIL-1.14 {Tcl_LsortObjCmd procedure, -index option} { lsort -index 1 -integer {{1 25 100} {3 16 42} {10 20 50}} } {{3 16 42} {10 20 50} {1 25 100}} test cmdIL-1.15 {Tcl_LsortObjCmd procedure, -integer option} { lsort -integer {24 6 300 18} } {6 18 24 300} test cmdIL-1.16 {Tcl_LsortObjCmd procedure, -integer option} { list [catch {lsort -integer {1 3 2.4}} msg] $msg } {1 {expected integer but got "2.4"}} test cmdIL-1.17 {Tcl_LsortObjCmd procedure, -real option} { lsort -real {24.2 6e3 150e-1} } {150e-1 24.2 6e3} test cmdIL-1.18 {Tcl_LsortObjCmd procedure, bogus list} { list [catch {lsort "1 2 3 \{ 4"} msg] $msg } {1 {unmatched open brace in list}} test cmdIL-1.19 {Tcl_LsortObjCmd procedure, empty list} { lsort {} } {} test cmdIL-1.22 {Tcl_LsortObjCmd procedure, unique sort} { lsort -integer -unique {3 1 2 3 1 4 3} } {1 2 3 4} test cmdIL-1.23 {Tcl_LsortObjCmd procedure, unique sort with index} { # lsort -unique should return the last unique item lsort -unique -index 0 {{a b} {c b} {a c} {d a}} } {{a c} {c b} {d a}} test cmdIL-1.24 {Tcl_LsortObjCmd procedure, order of -index and -command} { catch {rename 1 ""} proc testcmp {a b} {return [string compare $a $b]} set l [list [list a b] [list c d]] set result [list [catch {lsort -command testcmp -index 1 $l} msg] $msg] rename testcmp "" set result } [list 0 [list [list a b] [list c d]]] test cmdIL-1.25 {Tcl_LsortObjCmd procedure, order of -index and -command} { catch {rename 1 ""} proc testcmp {a b} {return [string compare $a $b]} set l [list [list a b] [list c d]] set result [list [catch {lsort -index 1 -command testcmp $l} msg] $msg] rename testcmp "" set result } [list 0 [list [list a b] [list c d]]] # Note that the required order only exists in the end-1'th element; # indexing using the end element or any fixed offset from the start # will not work... test cmdIL-1.26 {Tcl_LsortObjCmd procedure, offset indexing from end} { lsort -index end-1 {{a 1 e i} {b 2 3 f g} {c 4 5 6 d h}} } {{c 4 5 6 d h} {a 1 e i} {b 2 3 f g}} test cmdIL-1.29 {Tcl_LsortObjCmd procedure, loss of list rep during sorting} { set l {1 2 3} proc testcmp args {string length $::l} string length [lsort -command testcmp $l] } 5 # Can't think of any good tests for the MergeSort and MergeLists # procedures, except a bunch of random lists to sort. test cmdIL-2.1 {MergeSort and MergeLists procedures} { set result {} set r 1435753299 proc rand {} { global r set r [expr {(16807 * $r) % (0x7fffffff)}] } for {set i 0} {$i < 150} {incr i} { set x {} for {set j 0} {$j < $i} {incr j} { lappend x [expr {[rand] & 0xfff}] } set y [lsort -integer $x] set old -1 foreach el $y { if {$el < $old} { append result "list {$x} sorted to {$y}, element $el out of order\n" break } set old $el } } set result } {} test cmdIL-3.1 {SortCompare procedure, skip comparisons after error} { set x 0 proc cmp {a b} { global x incr x error "error #$x" } list [catch {lsort -integer -command cmp {48 6 28 190 16 2 3 6 1}} msg] \ $msg $x } {1 {error #1} 1} test cmdIL-3.2 {SortCompare procedure, -index option} { list [catch {lsort -integer -index 2 "\\\{ {30 40 50}"} msg] $msg } {1 {unmatched open brace in list}} test cmdIL-3.3 {SortCompare procedure, -index option} { list [catch {lsort -integer -index 2 {{20 10} {15 30 40}}} msg] $msg } {1 {element 2 missing from sublist "20 10"}} test cmdIL-3.4 {SortCompare procedure, -index option} { list [catch {lsort -integer -index 2 "{a b c} \\\{"} msg] $msg } {1 {unmatched open brace in list}} test cmdIL-3.5 {SortCompare procedure, -index option} { list [catch {lsort -integer -index 2 {{20 10 13} {15}}} msg] $msg } {1 {element 2 missing from sublist "15"}} test cmdIL-3.6 {SortCompare procedure, -index option} { lsort -integer -index 2 {{1 15 30} {2 5 25} {3 25 20}} } {{3 25 20} {2 5 25} {1 15 30}} test cmdIL-3.7 {SortCompare procedure, -ascii option} { lsort -ascii {d e c b a d35 d300 100 20} } {100 20 a b c d d300 d35 e} test cmdIL-3.8 {SortCompare procedure, -dictionary option} { lsort -dictionary {d e c b a d35 d300 100 20} } {20 100 a b c d d35 d300 e} test cmdIL-3.9 {SortCompare procedure, -integer option} { list [catch {lsort -integer {x 3}} msg] $msg } {1 {expected integer but got "x"}} test cmdIL-3.10 {SortCompare procedure, -integer option} { list [catch {lsort -integer {3 q}} msg] $msg } {1 {expected integer but got "q"}} test cmdIL-3.11 {SortCompare procedure, -integer option} { lsort -integer {35 21 0x20 30 023 100 8} } {8 023 21 30 0x20 35 100} test cmdIL-3.12 {SortCompare procedure, -real option} { list [catch {lsort -real {6...4 3}} msg] $msg } {1 {expected floating-point number but got "6...4"}} test cmdIL-3.13 {SortCompare procedure, -real option} { list [catch {lsort -real {3 1x7}} msg] $msg } {1 {expected floating-point number but got "1x7"}} test cmdIL-3.14 {SortCompare procedure, -real option} { lsort -real {24 2.5e01 16.7 85e-1 10.004} } {85e-1 10.004 16.7 24 2.5e01} test cmdIL-3.15 {SortCompare procedure, -command option} { proc cmp {a b} { error "comparison error" } list [catch {lsort -command cmp {48 6}} msg] $msg $errorInfo } {1 {comparison error} {comparison error while executing "error "comparison error"" (procedure "cmp" line 2) invoked from within "cmp 48 6" (-compare command) invoked from within "lsort -command cmp {48 6}"}} test cmdIL-3.16 {SortCompare procedure, -command option, long command} { proc cmp {dummy a b} { string compare $a $b } lsort -command {cmp {this argument is very very long in order to make the dstring overflow its statically allocated space}} {{this first element is also long in order to help expand the dstring} {the second element, last but not least, is quite long also, in order to make absolutely sure that space is allocated dynamically for the dstring}} } {{the second element, last but not least, is quite long also, in order to make absolutely sure that space is allocated dynamically for the dstring} {this first element is also long in order to help expand the dstring}} test cmdIL-3.17 {SortCompare procedure, -command option, non-integer result} { proc cmp {a b} { return foow } list [catch {lsort -command cmp {48 6}} msg] $msg } {1 {-compare command returned non-integer result}} test cmdIL-3.18 {SortCompare procedure, -command option} { proc cmp {a b} { expr {$b - $a} } lsort -command cmp {48 6 18 22 21 35 36} } {48 36 35 22 21 18 6} test cmdIL-3.19 {SortCompare procedure, -decreasing option} { lsort -decreasing -integer {35 21 0x20 30 023 100 8} } {100 35 0x20 30 21 023 8} test cmdIL-4.1 {DictionaryCompare procedure, numerics, leading zeros} { lsort -dictionary {a003b a03b} } {a03b a003b} test cmdIL-4.2 {DictionaryCompare procedure, numerics, leading zeros} { lsort -dictionary {a3b a03b} } {a3b a03b} test cmdIL-4.3 {DictionaryCompare procedure, numerics, leading zeros} { lsort -dictionary {a3b A03b} } {A03b a3b} test cmdIL-4.4 {DictionaryCompare procedure, numerics, leading zeros} { lsort -dictionary {a3b a03B} } {a3b a03B} test cmdIL-4.5 {DictionaryCompare procedure, numerics, leading zeros} { lsort -dictionary {00000 000} } {000 00000} test cmdIL-4.6 {DictionaryCompare procedure, numerics, different lengths} { lsort -dictionary {a321b a03210b} } {a321b a03210b} test cmdIL-4.7 {DictionaryCompare procedure, numerics, different lengths} { lsort -dictionary {a03210b a321b} } {a321b a03210b} test cmdIL-4.8 {DictionaryCompare procedure, numerics} { lsort -dictionary {48 6a 18b 22a 21aa 35 36} } {6a 18b 21aa 22a 35 36 48} test cmdIL-4.9 {DictionaryCompare procedure, numerics} { lsort -dictionary {a123x a123b} } {a123b a123x} test cmdIL-4.10 {DictionaryCompare procedure, numerics} { lsort -dictionary {a123b a123x} } {a123b a123x} test cmdIL-4.11 {DictionaryCompare procedure, numerics} { lsort -dictionary {a1b aab} } {a1b aab} test cmdIL-4.12 {DictionaryCompare procedure, numerics} { lsort -dictionary {a1b a!b} } {a!b a1b} test cmdIL-4.13 {DictionaryCompare procedure, numerics} { lsort -dictionary {a1b2c a1b1c} } {a1b1c a1b2c} test cmdIL-4.14 {DictionaryCompare procedure, numerics} { lsort -dictionary {a1b2c a1b3c} } {a1b2c a1b3c} test cmdIL-4.15 {DictionaryCompare procedure, long numbers} { lsort -dictionary {a7654884321988762b a7654884321988761b} } {a7654884321988761b a7654884321988762b} test cmdIL-4.16 {DictionaryCompare procedure, long numbers} { lsort -dictionary {a8765488432198876b a7654884321988761b} } {a7654884321988761b a8765488432198876b} test cmdIL-4.17 {DictionaryCompare procedure, case} { lsort -dictionary {aBCd abcc} } {abcc aBCd} test cmdIL-4.18 {DictionaryCompare procedure, case} { lsort -dictionary {aBCd abce} } {aBCd abce} test cmdIL-4.19 {DictionaryCompare procedure, case} { lsort -dictionary {abcd ABcc} } {ABcc abcd} test cmdIL-4.20 {DictionaryCompare procedure, case} { lsort -dictionary {abcd ABce} } {abcd ABce} test cmdIL-4.21 {DictionaryCompare procedure, case} { lsort -dictionary {abCD ABcd} } {ABcd abCD} test cmdIL-4.22 {DictionaryCompare procedure, case} { lsort -dictionary {ABcd aBCd} } {ABcd aBCd} test cmdIL-4.23 {DictionaryCompare procedure, case} { lsort -dictionary {ABcd AbCd} } {ABcd AbCd} test cmdIL-4.24 {DictionaryCompare procedure, international characters} {hasIsoLocale} { ::tcltest::set_iso8859_1_locale set result [lsort -dictionary "a b c A B C \xe3 \xc4"] ::tcltest::restore_locale set result } "A a B b C c \xe3 \xc4" test cmdIL-4.25 {DictionaryCompare procedure, international characters} {hasIsoLocale} { ::tcltest::set_iso8859_1_locale set result [lsort -dictionary "a23\xe3 a23\xc5 a23\xe4"] ::tcltest::restore_locale set result } "a23\xe3 a23\xe4 a23\xc5" test cmdIL-4.26 {DefaultCompare procedure, signed characters} { set l [lsort [list "abc\200" "abc"]] set viewlist {} foreach s $l { set viewelem "" set len [string length $s] for {set i 0} {$i < $len} {incr i} { set c [string index $s $i] scan $c %c d if {$d > 0 && $d < 128} { append viewelem $c } else { append viewelem "\\[format %03o $d]" } } lappend viewlist $viewelem } set viewlist } [list "abc" "abc\\200"] test cmdIL-4.27 {DictionaryCompare procedure, signed characters} { set l [lsort -dictionary [list "abc\200" "abc"]] set viewlist {} foreach s $l { set viewelem "" set len [string length $s] for {set i 0} {$i < $len} {incr i} { set c [string index $s $i] scan $c %c d if {$d > 0 && $d < 128} { append viewelem $c } else { append viewelem "\\[format %03o $d]" } } lappend viewlist $viewelem } set viewlist } [list "abc" "abc\\200"] test cmdIL-4.28 {DictionaryCompare procedure, chars between Z and a in ASCII} { lsort -dictionary [list AA ` c CC] } [list ` AA c CC] test cmdIL-4.29 {DictionaryCompare procedure, chars between Z and a in ASCII} { lsort -dictionary [list AA ` c ^ \\ CC \[ \]] } [list \[ \\ \] ^ ` AA c CC] test cmdIL-4.30 {DictionaryCompare procedure, chars between Z and a in ASCII} { lsort -dictionary [list AA ` c ^ _ \\ CC \[ dude \] funky] } [list \[ \\ \] ^ _ ` AA c CC dude funky] test cmdIL-4.31 {DictionaryCompare procedure, chars between Z and a in ASCII} { lsort -dictionary [list AA c ` CC] } [list ` AA c CC] test cmdIL-4.32 {DictionaryCompare procedure, chars between Z and a in ASCII} { lsort -dictionary [list AA c CC `] } [list ` AA c CC] test cmdIL-4.33 {DictionaryCompare procedure, chars between Z and a in ASCII} { lsort -dictionary [list AA ! c CC `] } [list ! ` AA c CC] # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/init.test0000644003604700454610000001340311737050674013726 0ustar dgp771div# Functionality covered: this file contains a collection of tests for the # auto loading and namespaces. # # Sourcing this file into Tcl runs the tests and generates output for # errors. No output means no errors were found. # # Copyright (c) 1997 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } # Clear out any namespaces called test_ns_* catch {eval namespace delete [namespace children :: test_ns_*]} # Six cases - white box testing test init-1.1 {auto_qualify - absolute cmd - namespace} { auto_qualify ::foo::bar ::blue } ::foo::bar test init-1.2 {auto_qualify - absolute cmd - global} { auto_qualify ::global ::sub } global test init-1.3 {auto_qualify - no colons cmd - global} { auto_qualify nocolons :: } nocolons test init-1.4 {auto_qualify - no colons cmd - namespace} { auto_qualify nocolons ::sub } {::sub::nocolons nocolons} test init-1.5 {auto_qualify - colons in cmd - global} { auto_qualify foo::bar :: } ::foo::bar test init-1.6 {auto_qualify - colons in cmd - namespace} { auto_qualify foo::bar ::sub } {::sub::foo::bar ::foo::bar} # Some additional tests test init-1.7 {auto_qualify - multiples colons 1} { auto_qualify :::foo::::bar ::blue } ::foo::bar test init-1.8 {auto_qualify - multiple colons 2} { auto_qualify :::foo ::bar } foo # we use a sub interp and auto_reset and double the tests because there is 2 # places where auto_loading occur (before loading the indexes files and after) set testInterp [interp create] interp eval $testInterp [list set argv $argv] interp eval $testInterp [list package require tcltest] interp eval $testInterp [list namespace import -force ::tcltest::*] interp eval $testInterp { auto_reset catch {rename parray {}} test init-2.0 {load parray - stage 1} { set ret [catch {parray} error] rename parray {} ; # remove it, for the next test - that should not fail. list $ret $error } {1 {wrong # args: should be "parray a ?pattern?"}} test init-2.1 {load parray - stage 2} { set ret [catch {parray} error] list $ret $error } {1 {wrong # args: should be "parray a ?pattern?"}} auto_reset catch {rename ::safe::setLogCmd {}} #unset auto_index(::safe::setLogCmd) #unset auto_oldpath test init-2.2 {load ::safe::setLogCmd - stage 1} { ::safe::setLogCmd rename ::safe::setLogCmd {} ; # should not fail } {} test init-2.3 {load ::safe::setLogCmd - stage 2} { ::safe::setLogCmd rename ::safe::setLogCmd {} ; # should not fail } {} auto_reset catch {rename ::safe::setLogCmd {}} test init-2.4 {load safe:::setLogCmd - stage 1} { safe:::setLogCmd ; # intentionally 3 : rename ::safe::setLogCmd {} ; # should not fail } {} test init-2.5 {load safe:::setLogCmd - stage 2} { safe:::setLogCmd ; # intentionally 3 : rename ::safe::setLogCmd {} ; # should not fail } {} auto_reset catch {rename ::safe::setLogCmd {}} test init-2.6 {load setLogCmd from safe:: - stage 1} { namespace eval safe setLogCmd rename ::safe::setLogCmd {} ; # should not fail } {} test init-2.7 {oad setLogCmd from safe:: - stage 2} { namespace eval safe setLogCmd rename ::safe::setLogCmd {} ; # should not fail } {} test init-2.8 {load tcl::HistAdd} -setup { auto_reset catch {rename ::tcl::HistAdd {}} } -body { # 3 ':' on purpose list [catch {tcl:::HistAdd} error] $error } -cleanup { rename ::tcl::HistAdd {} ; } -result {1 {wrong # args: should be "tcl:::HistAdd command ?exec?"}} test init-3.0 {random stuff in the auto_index, should still work} { set auto_index(foo:::bar::blah) { namespace eval foo {namespace eval bar {proc blah {} {return 1}}} } foo:::bar::blah } 1 # Tests that compare the error stack trace generated when autoloading # with that generated when no autoloading is necessary. Ideally they # should be the same. set count 0 foreach arg [subst -nocommands -novariables { c {argument which spans multiple lines} {argument which is all on one line but which is of such great length that the Tcl C library will truncate it when appending it onto the global error stack} {argument which spans multiple lines and is long enough to be truncated and " <- includes a false lead in the prune point search and must be longer still to force truncation} {contrived example: rare circumstance where the point at which to prune the error stack cannot be uniquely determined. foo bar foo "} {contrived example: rare circumstance where the point at which to prune the error stack cannot be uniquely determined. foo bar "} {argument that contains non-ASCII character, \u20ac, and which is of such great length that it will be longer than 150 bytes so it will be truncated by the Tcl C library} }] { test init-4.$count.0 {::errorInfo produced by [unknown]} { auto_reset catch {parray a b $arg} set first $::errorInfo catch {parray a b $arg} set second $::errorInfo string equal $first $second } 1 test init-4.$count.1 {::errorInfo produced by [unknown]} { auto_reset namespace eval junk [list array set $arg [list 1 2 3 4]] trace variable ::junk::$arg r \ "[list error [subst {Variable \"$arg\" is write-only}]] ;# " catch {parray ::junk::$arg} set first $::errorInfo catch {parray ::junk::$arg} set second $::errorInfo string equal $first $second } 1 incr count } cleanupTests } ;# End of [interp eval $testInterp] # cleanup interp delete $testInterp ::tcltest::cleanupTests return tcl8.4.20/tests/main.test0000644003604700454610000006474011737050674013721 0ustar dgp771div# This file contains a collection of tests for generic/tclMain.c. if {[catch {package require tcltest 2.0.2}]} { puts stderr "Skipping tests in [info script]. tcltest 2.0.2 required." return } namespace eval ::tcl::test::main { namespace import ::tcltest::test namespace import ::tcltest::testConstraint namespace import ::tcltest::interpreter namespace import ::tcltest::cleanupTests namespace import ::tcltest::makeFile namespace import ::tcltest::removeFile namespace import ::tcltest::temporaryDirectory namespace import ::tcltest::workingDirectory # Is [exec] defined? testConstraint exec [llength [info commands exec]] # Is the Tcltest package loaded? # - that is, the special C-coded testing commands in tclTest.c # - tests use testing commands introduced in Tcltest 8.4 testConstraint Tcltest [expr { [llength [package provide Tcltest]] && [package vsatisfies [package provide Tcltest] 8.4]}] # Procedure to simulate interactive typing of commands, line by line proc type {chan script} { foreach line [split $script \n] { if {[catch { puts $chan $line flush $chan }]} { return } # Grrr... Behavior depends on this value. after 1000 } } cd [temporaryDirectory] # Tests Tcl_Main-1.*: variable initializations test Tcl_Main-1.1 { Tcl_Main: startup script - normal } -constraints { stdio } -setup { makeFile {puts [list $argv0 $argv $tcl_interactive]} script catch {set f [open "|[list [interpreter] script]" r]} } -body { read $f } -cleanup { close $f removeFile script } -result [list script {} 0]\n test Tcl_Main-1.2 { Tcl_Main: startup script - can't begin with '-' } -constraints { stdio } -setup { makeFile {puts [list $argv0 $argv $tcl_interactive]} -script catch {set f [open "|[list [interpreter] -script]" w+]} } -body { puts $f {puts [list $argv0 $argv $tcl_interactive]; exit} flush $f read $f } -cleanup { close $f removeFile -script } -result [list [interpreter] -script 0]\n test Tcl_Main-1.3 { Tcl_Main: encoding of arguments: done by system encoding Note the shortcoming explained in Tcl Feature Request 491789 } -constraints { stdio } -setup { makeFile {puts [list $argv0 $argv $tcl_interactive]} script catch {set f [open "|[list [interpreter] script \u00c0]" r]} } -body { read $f } -cleanup { close $f removeFile script } -result [list script [list [encoding convertfrom [encoding system] \ [encoding convertto [encoding system] \u00c0]]] 0]\n test Tcl_Main-1.4 { Tcl_Main: encoding of arguments: done by system encoding Note the shortcoming explained in Tcl Feature Request 491789 } -constraints { stdio tempNotWin } -setup { makeFile {puts [list $argv0 $argv $tcl_interactive]} script catch {set f [open "|[list [interpreter] script \u20ac]" r]} } -body { read $f } -cleanup { close $f removeFile script } -result [list script [list [encoding convertfrom [encoding system] \ [encoding convertto [encoding system] \u20ac]]] 0]\n test Tcl_Main-1.5 { Tcl_Main: encoding of script name: system encoding loss Note the shortcoming explained in Tcl Feature Request 491789 } -constraints { stdio } -setup { makeFile {puts [list $argv0 $argv $tcl_interactive]} \u00c0 catch {set f [open "|[list [interpreter] \u00c0]" r]} } -body { read $f } -cleanup { close $f removeFile \u00c0 } -result [list [list [encoding convertfrom [encoding system] \ [encoding convertto [encoding system] \u00c0]]] {} 0]\n test Tcl_Main-1.6 { Tcl_Main: encoding of script name: system encoding loss Note the shortcoming explained in Tcl Feature Request 491789 } -constraints { stdio tempNotWin } -setup { makeFile {puts [list $argv0 $argv $tcl_interactive]} \u20ac catch {set f [open "|[list [interpreter] \u20ac]" r]} } -body { read $f } -cleanup { close $f removeFile \u20ac } -result [list [list [encoding convertfrom [encoding system] \ [encoding convertto [encoding system] \u20ac]]] {} 0]\n # Tests Tcl_Main-2.*: application-initialization procedure test Tcl_Main-2.1 { Tcl_Main: appInitProc returns error } -constraints { exec Tcltest } -setup { makeFile {puts "In script"} script } -body { exec [interpreter] script -appinitprocerror >& result set f [open result] read $f } -cleanup { close $f file delete result removeFile script } -result "application-specific initialization failed: \nIn script\n" test Tcl_Main-2.2 { Tcl_Main: appInitProc returns error } -constraints { exec Tcltest } -body { exec [interpreter] << {puts "In script"} -appinitprocerror >& result set f [open result] read $f } -cleanup { close $f file delete result } -result "application-specific initialization failed: \nIn script\n" test Tcl_Main-2.3 { Tcl_Main: appInitProc deletes interp } -constraints { exec Tcltest } -setup { makeFile {puts "In script"} script } -body { exec [interpreter] script -appinitprocdeleteinterp >& result set f [open result] read $f } -cleanup { close $f file delete result removeFile script } -result "application-specific initialization failed: \n" test Tcl_Main-2.4 { Tcl_Main: appInitProc deletes interp } -constraints { exec Tcltest } -body { exec [interpreter] << {puts "In script"} \ -appinitprocdeleteinterp >& result set f [open result] read $f } -cleanup { close $f file delete result } -result "application-specific initialization failed: \n" test Tcl_Main-2.5 { Tcl_Main: appInitProc closes stderr } -constraints { exec Tcltest } -body { exec [interpreter] << {puts "In script"} \ -appinitprocclosestderr >& result set f [open result] read $f } -cleanup { close $f file delete result } -result "In script\n" # Tests Tcl_Main-3.*: startup script evaluation test Tcl_Main-3.1 { Tcl_Main: startup script does not exist } -constraints { exec } -setup { if {[file exists no-such-file]} { error "Can't run test Tcl_Main-3.1\ where a file named \"no-such-file\" exists" } } -body { set code [catch {exec [interpreter] no-such-file >& result} result] set f [open result] list $code $result [read $f] } -cleanup { close $f file delete result } -match glob -result [list 1 {child process exited abnormally} \ {couldn't read file "no-such-file":*}] test Tcl_Main-3.2 { Tcl_Main: startup script raises error } -constraints { exec } -setup { makeFile {error ERROR} script } -body { set code [catch {exec [interpreter] script >& result} result] set f [open result] list $code $result [read $f] } -cleanup { close $f file delete result removeFile script } -match glob -result [list 1 {child process exited abnormally} \ "ERROR\n while executing*"] test Tcl_Main-3.3 { Tcl_Main: startup script closes stderr } -constraints { exec } -setup { makeFile {close stderr; error ERROR} script } -body { set code [catch {exec [interpreter] script >& result} result] set f [open result] list $code $result [read $f] } -cleanup { close $f file delete result removeFile script } -result [list 1 {child process exited abnormally} {}] test Tcl_Main-3.4 { Tcl_Main: startup script holds incomplete script } -constraints { exec } -setup { makeFile "if 1 \{" script } -body { set code [catch {exec [interpreter] script >& result} result] set f [open result] join [list $code $result [read $f]] \n } -cleanup { close $f file delete result removeFile script } -match glob -result [join [list 1 {child process exited abnormally}\ "missing close-brace\n while executing*"] \n] test Tcl_Main-3.5 { Tcl_Main: startup script sets main loop } -constraints { exec Tcltest } -setup { makeFile { rename exit _exit proc exit {code} { puts "In exit" _exit $code } after 0 { puts event testexitmainloop } testexithandler create 0 testsetmainloop } script } -body { exec [interpreter] script >& result set f [open result] read $f } -cleanup { close $f file delete result removeFile script } -result "event\nExit MainLoop\nIn exit\neven 0\n" test Tcl_Main-3.6 { Tcl_Main: startup script sets main loop and closes stdin } -constraints { exec Tcltest } -setup { makeFile { close stdin testsetmainloop rename exit _exit proc exit {code} { puts "In exit" _exit $code } after 0 { puts event testexitmainloop } testexithandler create 0 } script } -body { exec [interpreter] script >& result set f [open result] read $f } -cleanup { close $f file delete result removeFile script } -result "event\nExit MainLoop\nIn exit\neven 0\n" test Tcl_Main-3.7 { Tcl_Main: startup script deletes interp } -constraints { exec Tcltest } -setup { makeFile { rename exit _exit proc exit {code} { puts "In exit" _exit $code } testexithandler create 0 testinterpdelete {} } script } -body { exec [interpreter] script >& result set f [open result] read $f } -cleanup { close $f file delete result removeFile script } -result "even 0\n" test Tcl_Main-3.8 { Tcl_Main: startup script deletes interp and sets mainloop } -constraints { exec Tcltest } -setup { makeFile { testsetmainloop rename exit _exit proc exit {code} { puts "In exit" _exit $code } testexitmainloop testexithandler create 0 testinterpdelete {} } script } -body { exec [interpreter] script >& result set f [open result] read $f } -cleanup { close $f file delete result removeFile script } -result "Exit MainLoop\neven 0\n" test Tcl_Main-3.9 { Tcl_Main: startup script can set tcl_interactive without limit } -constraints { exec } -setup { makeFile {set tcl_interactive foo} script } -body { exec [interpreter] script >& result set f [open result] read $f } -cleanup { close $f file delete result removeFile script } -result {} # Tests Tcl_Main-4.*: rc file evaluation test Tcl_Main-4.1 { Tcl_Main: rcFile evaluation deletes interp } -constraints { exec Tcltest } -setup { set rc [makeFile {testinterpdelete {}} rc] } -body { exec [interpreter] << {puts "In script"} \ -appinitprocsetrcfile $rc >& result set f [open result] read $f } -cleanup { close $f file delete result removeFile rc } -result "application-specific initialization failed: \n" test Tcl_Main-4.2 { Tcl_Main: rcFile evaluation closes stdin } -constraints { exec Tcltest } -setup { set rc [makeFile {close stdin} rc] } -body { exec [interpreter] << {puts "In script"} \ -appinitprocsetrcfile $rc >& result set f [open result] read $f } -cleanup { close $f file delete result removeFile rc } -result "application-specific initialization failed: \n" test Tcl_Main-4.3 { Tcl_Main: rcFile evaluation closes stdin and sets main loop } -constraints { exec Tcltest } -setup { set rc [makeFile { close stdin testsetmainloop after 0 testexitmainloop testexithandler create 0 rename exit _exit proc exit code { puts "In exit" _exit $code } } rc] } -body { exec [interpreter] << {puts "In script"} \ -appinitprocsetrcfile $rc >& result set f [open result] read $f } -cleanup { close $f file delete result removeFile rc } -result "application-specific initialization failed:\ \nExit MainLoop\nIn exit\neven 0\n" test Tcl_Main-4.4 { Tcl_Main: rcFile evaluation sets main loop } -constraints { exec Tcltest } -setup { set rc [makeFile { testsetmainloop after 0 testexitmainloop testexithandler create 0 rename exit _exit proc exit code { puts "In exit" _exit $code } } rc] } -body { exec [interpreter] << {} \ -appinitprocsetrcfile $rc >& result set f [open result] read $f } -cleanup { close $f file delete result removeFile rc } -result "application-specific initialization failed:\ \nExit MainLoop\nIn exit\neven 0\n" test Tcl_Main-4.5 { Tcl_Main: Bug 1481986 } -constraints { exec Tcltest } -setup { set rc [makeFile { testsetmainloop after 0 {puts "Event callback"} } rc] } -body { set f [open "|[list [interpreter] -appinitprocsetrcfile $rc]" w+] after 1000 type $f {puts {Interactive output} exit } read $f } -cleanup { catch {close $f} removeFile rc } -result "Event callback\nInteractive output\n" # Tests Tcl_Main-5.*: interactive operations test Tcl_Main-5.1 { Tcl_Main: tcl_interactive must be boolean } -constraints { exec } -body { exec [interpreter] << {set tcl_interactive foo} >& result set f [open result] read $f } -cleanup { close $f file delete result } -result "can't set \"tcl_interactive\":\ variable must have boolean value\n" test Tcl_Main-5.2 { Tcl_Main able to handle non-blocking stdin } -constraints { exec } -setup { catch {set f [open "|[list [interpreter]]" w+]} } -body { type $f { fconfigure stdin -blocking 0 puts SUCCESS } list [catch {gets $f} line] $line } -cleanup { close $f } -result [list 0 SUCCESS] test Tcl_Main-5.3 { Tcl_Main handles stdin EOF in mid-command } -constraints { exec } -setup { catch {set f [open "|[list [interpreter]]" w+]} catch {fconfigure $f -blocking 0} } -body { type $f "fconfigure stdin -eofchar \\032 if 1 \{\n\032" variable wait fileevent $f readable \ [list set [namespace which -variable wait] "child exit"] set id [after 2000 [list set [namespace which -variable wait] timeout]] vwait [namespace which -variable wait] after cancel $id set wait } -cleanup { if {[string equal timeout $wait] && [string equal unix $::tcl_platform(platform)]} { exec kill [pid $f] } close $f } -result {child exit} test Tcl_Main-5.4 { Tcl_Main handles stdin EOF in mid-command } -constraints { exec } -setup { set cmd {makeFile "if 1 \{" script} catch {set f [open "|[list [interpreter]] < [list [eval $cmd]]" r]} catch {fconfigure $f -blocking 0} } -body { variable wait fileevent $f readable \ [list set [namespace which -variable wait] "child exit"] set id [after 2000 [list set [namespace which -variable wait] timeout]] vwait [namespace which -variable wait] after cancel $id set wait } -cleanup { if {[string equal timeout $wait] && [string equal unix $::tcl_platform(platform)]} { exec kill [pid $f] } close $f removeFile script } -result {child exit} test Tcl_Main-5.5 { Tcl_Main: error raised in interactive mode } -constraints { exec } -body { exec [interpreter] << {error foo} >& result set f [open result] read $f } -cleanup { close $f file delete result } -result "foo\n" test Tcl_Main-5.6 { Tcl_Main: interactive mode: errors don't stop command loop } -constraints { exec } -body { exec [interpreter] << { error foo puts bar } >& result set f [open result] read $f } -cleanup { close $f file delete result } -result "foo\nbar\n" test Tcl_Main-5.7 { Tcl_Main: interactive mode: closed stderr } -constraints { exec } -body { exec [interpreter] << { close stderr error foo puts bar } >& result set f [open result] read $f } -cleanup { close $f file delete result } -result "bar\n" test Tcl_Main-5.8 { Tcl_Main: interactive mode: close stdin -> main loop & [exit] & exit handlers } -constraints { exec Tcltest } -body { exec [interpreter] << { rename exit _exit proc exit code { puts "In exit" _exit $code } testsetmainloop testexitmainloop testexithandler create 0 close stdin } >& result set f [open result] read $f } -cleanup { close $f file delete result } -result "Exit MainLoop\nIn exit\neven 0\n" test Tcl_Main-5.9 { Tcl_Main: interactive mode: delete interp -> main loop & exit handlers, but no [exit] } -constraints { exec Tcltest } -body { exec [interpreter] << { rename exit _exit proc exit code { puts "In exit" _exit $code } testsetmainloop testexitmainloop testexithandler create 0 testinterpdelete {} } >& result set f [open result] read $f } -cleanup { close $f file delete result } -result "Exit MainLoop\neven 0\n" test Tcl_Main-5.10 { Tcl_Main: exit main loop in mid-interactive command } -constraints { exec Tcltest } -setup { catch {set f [open "|[list [interpreter]]" w+]} catch {fconfigure $f -blocking 0} } -body { type $f "testsetmainloop after 2000 testexitmainloop puts \{1 2" after 4000 type $f "3 4\}" set code1 [catch {gets $f} line1] set code2 [catch {gets $f} line2] set code3 [catch {gets $f} line3] list $code1 $line1 $code2 $line2 $code3 $line3 } -cleanup { close $f } -result [list 0 {Exit MainLoop} 0 {1 2} 0 {3 4}] test Tcl_Main-5.11 { Tcl_Main: EOF in interactive main loop } -constraints { exec Tcltest } -body { exec [interpreter] << { rename exit _exit proc exit code { puts "In exit" _exit $code } testexithandler create 0 after 0 testexitmainloop testsetmainloop } >& result set f [open result] read $f } -cleanup { close $f file delete result } -result "Exit MainLoop\nIn exit\neven 0\n" test Tcl_Main-5.12 { Tcl_Main: close stdin in interactive main loop } -constraints { exec Tcltest } -body { exec [interpreter] << { rename exit _exit proc exit code { puts "In exit" _exit $code } testexithandler create 0 after 100 testexitmainloop testsetmainloop close stdin puts "don't reach this" } >& result set f [open result] read $f } -cleanup { close $f file delete result } -result "Exit MainLoop\nIn exit\neven 0\n" # Tests Tcl_Main-6.*: interactive operations with prompts test Tcl_Main-6.1 { Tcl_Main: enable prompts with tcl_interactive } -constraints { exec } -body { exec [interpreter] << {set tcl_interactive 1} >& result set f [open result] read $f } -cleanup { close $f file delete result } -result "1\n% " test Tcl_Main-6.2 { Tcl_Main: prompt deletes interp } -constraints { exec Tcltest } -body { exec [interpreter] << { set tcl_prompt1 {testinterpdelete {}} set tcl_interactive 1 puts "not reached" } >& result set f [open result] read $f } -cleanup { close $f file delete result } -result "1\n" test Tcl_Main-6.3 { Tcl_Main: prompt closes stdin } -constraints { exec } -body { exec [interpreter] << { set tcl_prompt1 {close stdin} set tcl_interactive 1 puts "not reached" } >& result set f [open result] read $f } -cleanup { close $f file delete result } -result "1\n" test Tcl_Main-6.4 { Tcl_Main: interactive output, closed stdout } -constraints { exec } -body { exec [interpreter] << { set tcl_interactive 1 close stdout set a NO puts stderr YES } >& result set f [open result] read $f } -cleanup { close $f file delete result } -result "1\n% YES\n" test Tcl_Main-6.5 { Tcl_Main: interactive entry to main loop } -constraints { exec Tcltest } -body { exec [interpreter] << { set tcl_interactive 1 testsetmainloop testexitmainloop} >& result set f [open result] read $f } -cleanup { close $f file delete result } -result "1\n% % % Exit MainLoop\n" test Tcl_Main-6.6 { Tcl_Main: number of prompts during stdin close exit } -constraints { exec } -body { exec [interpreter] << { set tcl_interactive 1 close stdin} >& result set f [open result] read $f } -cleanup { close $f file delete result } -result "1\n% " test Tcl_Main-6.7 { [unknown]: interactive auto-completion. } -constraints { exec } -body { exec [interpreter] << { proc foo\{ x {} set ::auto_noexec xxx set tcl_interactive 1 foo y} >& result set f [open result] read $f } -cleanup { close $f file delete result } -result "1\n% % " # Tests Tcl_Main-7.*: exiting test Tcl_Main-7.1 { Tcl_Main: [exit] defined as no-op -> still have exithandlers } -constraints { exec Tcltest } -body { exec [interpreter] << { proc exit args {} testexithandler create 0 } >& result set f [open result] read $f } -cleanup { close $f file delete result } -result "even 0\n" test Tcl_Main-7.2 { Tcl_Main: [exit] defined as no-op -> still have exithandlers } -constraints { exec Tcltest } -body { exec [interpreter] << { proc exit args {} testexithandler create 0 after 0 testexitmainloop testsetmainloop } >& result set f [open result] read $f } -cleanup { close $f file delete result } -result "Exit MainLoop\neven 0\n" # Tests Tcl_Main-8.*: StdinProc operations test Tcl_Main-8.1 { StdinProc: handles non-blocking stdin } -constraints { exec Tcltest } -body { exec [interpreter] << { testsetmainloop fconfigure stdin -blocking 0 testexitmainloop } >& result set f [open result] read $f } -cleanup { close $f file delete result } -result "Exit MainLoop\n" test Tcl_Main-8.2 { StdinProc: handles stdin EOF } -constraints { exec Tcltest } -body { exec [interpreter] << { testsetmainloop testexithandler create 0 rename exit _exit proc exit code { puts "In exit" _exit $code } after 100 testexitmainloop } >& result set f [open result] read $f } -cleanup { close $f file delete result } -result "Exit MainLoop\nIn exit\neven 0\n" test Tcl_Main-8.3 { StdinProc: handles interactive stdin EOF } -constraints { exec Tcltest } -body { exec [interpreter] << { testsetmainloop testexithandler create 0 rename exit _exit proc exit code { puts "In exit" _exit $code } set tcl_interactive 1} >& result set f [open result] read $f } -cleanup { close $f file delete result } -result "1\n% even 0\n" test Tcl_Main-8.4 { StdinProc: handles stdin close } -constraints { exec Tcltest } -body { exec [interpreter] << { testsetmainloop rename exit _exit proc exit code { puts "In exit" _exit $code } after 100 testexitmainloop after 0 puts 1 close stdin } >& result set f [open result] read $f } -cleanup { close $f file delete result } -result "1\nExit MainLoop\nIn exit\n" test Tcl_Main-8.5 { StdinProc: handles interactive stdin close } -constraints { exec Tcltest } -body { exec [interpreter] << { testsetmainloop set tcl_interactive 1 rename exit _exit proc exit code { puts "In exit" _exit $code } after 100 testexitmainloop after 0 puts 1 close stdin } >& result set f [open result] read $f } -cleanup { close $f file delete result } -result "1\n% % % after#0\n% after#1\n% 1\nExit MainLoop\nIn exit\n" test Tcl_Main-8.6 { StdinProc: handles event loop re-entry } -constraints { exec Tcltest } -body { exec [interpreter] << { testsetmainloop after 100 {puts 1; set delay 1} vwait delay puts 2 testexitmainloop } >& result set f [open result] read $f } -cleanup { close $f file delete result } -result "1\n2\nExit MainLoop\n" test Tcl_Main-8.7 { StdinProc: handling of errors } -constraints { exec Tcltest } -body { exec [interpreter] << { testsetmainloop error foo testexitmainloop } >& result set f [open result] read $f } -cleanup { close $f file delete result } -result "foo\nExit MainLoop\n" test Tcl_Main-8.8 { StdinProc: handling of errors, closed stderr } -constraints { exec Tcltest } -body { exec [interpreter] << { testsetmainloop close stderr error foo testexitmainloop } >& result set f [open result] read $f } -cleanup { close $f file delete result } -result "Exit MainLoop\n" test Tcl_Main-8.9 { StdinProc: interactive output } -constraints { exec Tcltest } -body { exec [interpreter] << { testsetmainloop set tcl_interactive 1 testexitmainloop} >& result set f [open result] read $f } -cleanup { close $f file delete result } -result "1\n% % Exit MainLoop\n" test Tcl_Main-8.10 { StdinProc: interactive output, closed stdout } -constraints { exec Tcltest } -body { exec [interpreter] << { testsetmainloop close stdout set tcl_interactive 1 testexitmainloop } >& result set f [open result] read $f } -cleanup { close $f file delete result } -result {} test Tcl_Main-8.11 { StdinProc: prompt deletes interp } -constraints { exec Tcltest } -body { exec [interpreter] << { testsetmainloop set tcl_prompt1 {testinterpdelete {}} set tcl_interactive 1} >& result set f [open result] read $f } -cleanup { close $f file delete result } -result "1\n" test Tcl_Main-8.12 { StdinProc: prompt closes stdin } -constraints { exec Tcltest } -body { exec [interpreter] << { testsetmainloop set tcl_prompt1 {close stdin} after 100 testexitmainloop set tcl_interactive 1 puts "not reached" } >& result set f [open result] read $f } -cleanup { close $f file delete result } -result "1\nExit MainLoop\n" # Tests Tcl_Main-9.*: Prompt operations test Tcl_Main-9.1 { Prompt: custom prompt variables } -constraints { exec } -body { exec [interpreter] << { set tcl_prompt1 {puts -nonewline stdout "one "} set tcl_prompt2 {puts -nonewline stdout "two "} set tcl_interactive 1 puts {This is a test}} >& result set f [open result] read $f } -cleanup { close $f file delete result } -result "1\none two This is\n\t\ta test\none " test Tcl_Main-9.2 { Prompt: error in custom prompt variables } -constraints { exec } -body { exec [interpreter] << { set tcl_prompt1 {error foo} set tcl_interactive 1 set errorInfo} >& result set f [open result] read $f } -cleanup { close $f file delete result } -result "1\nfoo\n% foo\n while executing\n\"error foo\"\n (script\ that generates prompt)\nfoo\n% " test Tcl_Main-9.3 { Prompt: error in custom prompt variables, closed stderr } -constraints { exec } -body { exec [interpreter] << { set tcl_prompt1 {close stderr; error foo} set tcl_interactive 1} >& result set f [open result] read $f } -cleanup { close $f file delete result } -result "1\n% " test Tcl_Main-9.4 { Prompt: error in custom prompt variables, closed stdout } -constraints { exec } -body { exec [interpreter] << { set tcl_prompt1 {close stdout; error foo} set tcl_interactive 1} >& result set f [open result] read $f } -cleanup { close $f file delete result } -result "1\nfoo\n" cd [workingDirectory] cleanupTests } namespace delete ::tcl::test::main return tcl8.4.20/tests/event.test0000644003604700454610000005313212052456730014101 0ustar dgp771div# This file contains a collection of tests for the procedures in the file # tclEvent.c, which includes the "update", and "vwait" Tcl # commands. Sourcing this file into Tcl runs the tests and generates # output for errors. No output means no errors were found. # # Copyright (c) 1995-1997 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. package require tcltest 2 namespace import -force ::tcltest::* testConstraint testfilehandler [llength [info commands testfilehandler]] testConstraint testexithandler [llength [info commands testexithandler]] testConstraint testfilewait [llength [info commands testfilewait]] test event-1.1 {Tcl_CreateFileHandler, reading} {testfilehandler} { testfilehandler close testfilehandler create 0 readable off testfilehandler clear 0 testfilehandler oneevent set result "" lappend result [testfilehandler counts 0] testfilehandler fillpartial 0 testfilehandler oneevent lappend result [testfilehandler counts 0] testfilehandler oneevent lappend result [testfilehandler counts 0] testfilehandler close set result } {{0 0} {1 0} {2 0}} test event-1.2 {Tcl_CreateFileHandler, writing} {testfilehandler nonPortable} { # This test is non-portable because on some systems (e.g. # SunOS 4.1.3) pipes seem to be writable always. testfilehandler close testfilehandler create 0 off writable testfilehandler clear 0 testfilehandler oneevent set result "" lappend result [testfilehandler counts 0] testfilehandler fillpartial 0 testfilehandler oneevent lappend result [testfilehandler counts 0] testfilehandler fill 0 testfilehandler oneevent lappend result [testfilehandler counts 0] testfilehandler close set result } {{0 1} {0 2} {0 2}} test event-1.3 {Tcl_DeleteFileHandler} {testfilehandler nonPortable} { testfilehandler close testfilehandler create 2 disabled disabled testfilehandler create 1 readable writable testfilehandler create 0 disabled disabled testfilehandler fillpartial 1 set result "" testfilehandler oneevent lappend result [testfilehandler counts 1] testfilehandler oneevent lappend result [testfilehandler counts 1] testfilehandler oneevent lappend result [testfilehandler counts 1] testfilehandler create 1 off off testfilehandler oneevent lappend result [testfilehandler counts 1] testfilehandler close set result } {{0 1} {1 1} {1 2} {0 0}} test event-2.1 {Tcl_DeleteFileHandler} {testfilehandler nonPortable} { testfilehandler close testfilehandler create 2 disabled disabled testfilehandler create 1 readable writable testfilehandler fillpartial 1 set result "" testfilehandler oneevent lappend result [testfilehandler counts 1] testfilehandler oneevent lappend result [testfilehandler counts 1] testfilehandler oneevent lappend result [testfilehandler counts 1] testfilehandler create 1 off off testfilehandler oneevent lappend result [testfilehandler counts 1] testfilehandler close set result } {{0 1} {1 1} {1 2} {0 0}} test event-2.2 {Tcl_DeleteFileHandler, fd reused & events still pending} \ {testfilehandler nonPortable} { testfilehandler close testfilehandler create 0 readable writable testfilehandler fillpartial 0 set result "" testfilehandler oneevent lappend result [testfilehandler counts 0] testfilehandler close testfilehandler create 0 readable writable testfilehandler oneevent lappend result [testfilehandler counts 0] testfilehandler close set result } {{0 1} {0 0}} test event-3.1 {FileHandlerCheckProc, TCL_FILE_EVENTS off } {testfilehandler} { testfilehandler close testfilehandler create 1 readable writable testfilehandler fillpartial 1 testfilehandler windowevent set result [testfilehandler counts 1] testfilehandler close set result } {0 0} test event-4.1 {FileHandlerEventProc, race between event and disabling} \ {testfilehandler nonPortable} { update testfilehandler close testfilehandler create 2 disabled disabled testfilehandler create 1 readable writable testfilehandler fillpartial 1 set result "" testfilehandler oneevent lappend result [testfilehandler counts 1] testfilehandler oneevent lappend result [testfilehandler counts 1] testfilehandler oneevent lappend result [testfilehandler counts 1] testfilehandler create 1 disabled disabled testfilehandler oneevent lappend result [testfilehandler counts 1] testfilehandler close set result } {{0 1} {1 1} {1 2} {0 0}} test event-4.2 {FileHandlerEventProc, TCL_FILE_EVENTS off} \ {testfilehandler nonPortable} { update testfilehandler close testfilehandler create 1 readable writable testfilehandler create 2 readable writable testfilehandler fillpartial 1 testfilehandler fillpartial 2 testfilehandler oneevent set result "" lappend result [testfilehandler counts 1] [testfilehandler counts 2] testfilehandler windowevent lappend result [testfilehandler counts 1] [testfilehandler counts 2] testfilehandler close set result } {{0 0} {0 1} {0 0} {0 1}} update test event-5.1 {Tcl_BackgroundError, HandleBgErrors procedures} { catch {rename bgerror {}} proc bgerror msg { global errorInfo errorCode x lappend x [list $msg $errorInfo $errorCode] } after idle {error "a simple error"} after idle {open non_existent} after idle {set errorInfo foobar; set errorCode xyzzy} set x {} update idletasks rename bgerror {} regsub -all [file join {} non_existent] $x "non_existent" x set x } {{{a simple error} {a simple error while executing "error "a simple error"" ("after" script)} NONE} {{couldn't open "non_existent": no such file or directory} {couldn't open "non_existent": no such file or directory while executing "open non_existent" ("after" script)} {POSIX ENOENT {no such file or directory}}}} test event-5.2 {Tcl_BackgroundError, HandleBgErrors procedures} { catch {rename bgerror {}} proc bgerror msg { global x lappend x $msg return -code break } after idle {error "a simple error"} after idle {open non_existent} set x {} update idletasks rename bgerror {} set x } {{a simple error}} test event-6.1 {BgErrorDeleteProc procedure} { catch {interp delete foo} interp create foo set erroutfile [makeFile Unmodified err.out] foo eval [list set erroutfile $erroutfile] foo eval { proc bgerror args { global errorInfo erroutfile set f [open $erroutfile r+] seek $f 0 end puts $f "$args $errorInfo" close $f } after 100 {error "first error"} after 100 {error "second error"} } after 100 {interp delete foo} after 200 update set f [open $erroutfile r] set result [read $f] close $f removeFile $erroutfile set result } {Unmodified } test event-7.1 {bgerror / regular} { set errRes {} proc bgerror {err} { global errRes; set errRes $err; } after 0 {error err1} vwait errRes; set errRes; } err1 test event-7.2 {bgerror / accumulation} { set errRes {} proc bgerror {err} { global errRes; lappend errRes $err; } after 0 {error err1} after 0 {error err2} after 0 {error err3} update set errRes; } {err1 err2 err3} test event-7.3 {bgerror / accumulation / break} { set errRes {} proc bgerror {err} { global errRes; lappend errRes $err; return -code break "skip!"; } after 0 {error err1} after 0 {error err2} after 0 {error err3} update set errRes; } err1 test event-7.4 {tkerror is nothing special anymore to tcl} { set errRes {} # we don't just rename bgerror to empty because it could then # be autoloaded... proc bgerror {err} { global errRes; lappend errRes "bg:$err"; } proc tkerror {err} { global errRes; lappend errRes "tk:$err"; } after 0 {error err1} update rename tkerror {} set errRes } bg:err1 testConstraint exec [llength [info commands exec]] test event-7.5 {correct behaviour when there is no bgerror [Bug 219142]} {exec} { set script { after 1000 error hello after 2000 set a 0 vwait a } list [catch {exec [interpreter] << $script} errMsg] $errMsg } {1 {hello while executing "error hello" ("after" script)}} # someday : add a test checking that # when there is no bgerror, an error msg goes to stderr # ideally one would use sub interp and transfer a fake stderr # to it, unfortunatly the current interp tcl API does not allow # that. the other option would be to use fork a test but it # then becomes more a file/exec test than a bgerror test. # end of bgerror tests catch {rename bgerror {}} test event-8.1 {Tcl_CreateExitHandler procedure} {stdio testexithandler} { set child [open |[list [interpreter]] r+] puts $child "testexithandler create 41; testexithandler create 4" puts $child "testexithandler create 6; exit" flush $child set result [read $child] close $child set result } {even 6 even 4 odd 41 } test event-9.1 {Tcl_DeleteExitHandler procedure} {stdio testexithandler} { set child [open |[list [interpreter]] r+] puts $child "testexithandler create 41; testexithandler create 4" puts $child "testexithandler create 6; testexithandler delete 41" puts $child "testexithandler create 16; exit" flush $child set result [read $child] close $child set result } {even 16 even 6 even 4 } test event-9.2 {Tcl_DeleteExitHandler procedure} {stdio testexithandler} { set child [open |[list [interpreter]] r+] puts $child "testexithandler create 41; testexithandler create 4" puts $child "testexithandler create 6; testexithandler delete 4" puts $child "testexithandler create 16; exit" flush $child set result [read $child] close $child set result } {even 16 even 6 odd 41 } test event-9.3 {Tcl_DeleteExitHandler procedure} {stdio testexithandler} { set child [open |[list [interpreter]] r+] puts $child "testexithandler create 41; testexithandler create 4" puts $child "testexithandler create 6; testexithandler delete 6" puts $child "testexithandler create 16; exit" flush $child set result [read $child] close $child set result } {even 16 even 4 odd 41 } test event-9.4 {Tcl_DeleteExitHandler procedure} {stdio testexithandler} { set child [open |[list [interpreter]] r+] puts $child "testexithandler create 41; testexithandler delete 41" puts $child "testexithandler create 16; exit" flush $child set result [read $child] close $child set result } {even 16 } test event-10.1 {Tcl_Exit procedure} {stdio} { set child [open |[list [interpreter]] r+] puts $child "exit 3" list [catch {close $child} msg] $msg [lindex $errorCode 0] \ [lindex $errorCode 2] } {1 {child process exited abnormally} CHILDSTATUS 3} test event-11.1 {Tcl_VwaitCmd procedure} { list [catch {vwait} msg] $msg } {1 {wrong # args: should be "vwait name"}} test event-11.2 {Tcl_VwaitCmd procedure} { list [catch {vwait a b} msg] $msg } {1 {wrong # args: should be "vwait name"}} test event-11.3 {Tcl_VwaitCmd procedure} { catch {unset x} set x 1 list [catch {vwait x(1)} msg] $msg } {1 {can't trace "x(1)": variable isn't array}} test event-11.4 {Tcl_VwaitCmd procedure} {} { foreach i [after info] { after cancel $i } after 10; update; # On Mac make sure update won't take long after 100 {set x x-done} after 200 {set y y-done} after 300 {set z z-done} after idle {set q q-done} set x before set y before set z before set q before list [vwait y] $x $y $z $q } {{} x-done y-done before q-done} foreach i [after info] { after cancel $i } test event-11.5 {Tcl_VwaitCmd procedure: round robin scheduling, 2 sources} {socket} { set test1file [makeFile "" test1] set f1 [open $test1file w] proc accept {s args} { puts $s foobar close $s } catch {set s1 [socket -server accept 0]} after 1000 catch {set s2 [socket 127.0.0.1 [lindex [fconfigure $s1 -sockname] 2]]} close $s1 set x 0 set y 0 set z 0 fileevent $s2 readable {incr z} vwait z fileevent $f1 writable {incr x; if {$y == 3} {set z done}} fileevent $s2 readable {incr y; if {$x == 3} {set z done}} vwait z close $f1 close $s2 removeFile $test1file list $x $y $z } {3 3 done} test event-11.6 {Tcl_VwaitCmd procedure: round robin scheduling, same source} { set test1file [makeFile "" test1] set test2file [makeFile "" test2] set f1 [open $test1file w] set f2 [open $test2file w] set x 0 set y 0 set z 0 update fileevent $f1 writable {incr x; if {$y == 3} {set z done}} fileevent $f2 writable {incr y; if {$x == 3} {set z done}} vwait z close $f1 close $f2 removeFile $test1file removeFile $test2file list $x $y $z } {3 3 done} test event-12.1 {Tcl_UpdateCmd procedure} { list [catch {update a b} msg] $msg } {1 {wrong # args: should be "update ?idletasks?"}} test event-12.2 {Tcl_UpdateCmd procedure} { list [catch {update bogus} msg] $msg } {1 {bad option "bogus": must be idletasks}} test event-12.3 {Tcl_UpdateCmd procedure} { foreach i [after info] { after cancel $i } after 500 {set x after} after idle {set y after} after idle {set z "after, y = $y"} set x before set y before set z before update idletasks list $x $y $z } {before after {after, y = after}} test event-12.4 {Tcl_UpdateCmd procedure} { foreach i [after info] { after cancel $i } after 10; update; # On Mac make sure update won't take long after 200 {set x x-done} after 600 {set y y-done} after idle {set z z-done} set x before set y before set z before after 300 update list $x $y $z } {x-done before z-done} test event-13.1 {Tcl_WaitForFile procedure, readable} {testfilehandler} { foreach i [after info] { after cancel $i } after 100 set x timeout testfilehandler close testfilehandler create 1 off off set x "no timeout" set result [testfilehandler wait 1 readable 0] update testfilehandler close list $result $x } {{} {no timeout}} test event-13.2 {Tcl_WaitForFile procedure, readable} testfilehandler { foreach i [after info] { after cancel $i } after 100 set x timeout testfilehandler close testfilehandler create 1 off off set x "no timeout" set result [testfilehandler wait 1 readable 100] update testfilehandler close list $result $x } {{} timeout} test event-13.3 {Tcl_WaitForFile procedure, readable} testfilehandler { foreach i [after info] { after cancel $i } after 100 set x timeout testfilehandler close testfilehandler create 1 off off testfilehandler fillpartial 1 set x "no timeout" set result [testfilehandler wait 1 readable 100] update testfilehandler close list $result $x } {readable {no timeout}} test event-13.4 {Tcl_WaitForFile procedure, writable} \ {testfilehandler nonPortable} { foreach i [after info] { after cancel $i } after 100 set x timeout testfilehandler close testfilehandler create 1 off off testfilehandler fill 1 set x "no timeout" set result [testfilehandler wait 1 writable 0] update testfilehandler close list $result $x } {{} {no timeout}} test event-13.5 {Tcl_WaitForFile procedure, writable} \ {testfilehandler nonPortable} { foreach i [after info] { after cancel $i } after 100 set x timeout testfilehandler close testfilehandler create 1 off off testfilehandler fill 1 set x "no timeout" set result [testfilehandler wait 1 writable 100] update testfilehandler close list $result $x } {{} timeout} test event-13.6 {Tcl_WaitForFile procedure, writable} testfilehandler { foreach i [after info] { after cancel $i } after 100 set x timeout testfilehandler close testfilehandler create 1 off off set x "no timeout" set result [testfilehandler wait 1 writable 100] update testfilehandler close list $result $x } {writable {no timeout}} test event-13.7 {Tcl_WaitForFile procedure, don't call other event handlers} testfilehandler { foreach i [after info] { after cancel $i } after 100 lappend x timeout after idle lappend x idle testfilehandler close testfilehandler create 1 off off set x "" set result [list [testfilehandler wait 1 readable 200] $x] update testfilehandler close lappend result $x } {{} {} {timeout idle}} test event-13.8 {Tcl_WaitForFile procedure, waiting indefinitely} testfilewait { set f [open "|sleep 2" r] set result "" lappend result [testfilewait $f readable 100] lappend result [testfilewait $f readable -1] close $f set result } {{} readable} test event-14.1 {Tcl_WaitForFile procedure, readable, big fd} \ -constraints {testfilehandler unix} \ -setup { set chanList {} for {set i 0} {$i < 32} {incr i} { lappend chanList [open /dev/null r] } } \ -body { foreach i [after info] { after cancel $i } after 100 set x timeout testfilehandler close testfilehandler create 1 off off set x "no timeout" set result [testfilehandler wait 1 readable 0] update testfilehandler close list $result $x } \ -result {{} {no timeout}} \ -cleanup { foreach chan $chanList {close $chan} } test event-14.2 {Tcl_WaitForFile procedure, readable, big fd} \ -constraints {testfilehandler unix} \ -setup { set chanList {} for {set i 0} {$i < 32} {incr i} { lappend chanList [open /dev/null r] } } \ -body { foreach i [after info] { after cancel $i } after 100 set x timeout testfilehandler close testfilehandler create 1 off off set x "no timeout" set result [testfilehandler wait 1 readable 100] update testfilehandler close list $result $x } \ -result {{} timeout} \ -cleanup { foreach chan $chanList {close $chan} } test event-14.3 {Tcl_WaitForFile procedure, readable, big fd} \ -constraints {testfilehandler unix} \ -setup { set chanList {} for {set i 0} {$i < 32} {incr i} { lappend chanList [open /dev/null r] } } \ -body { foreach i [after info] { after cancel $i } after 100 set x timeout testfilehandler close testfilehandler create 1 off off testfilehandler fillpartial 1 set x "no timeout" set result [testfilehandler wait 1 readable 100] update testfilehandler close list $result $x } \ -result {readable {no timeout}} \ -cleanup { foreach chan $chanList {close $chan} } test event-14.4 {Tcl_WaitForFile procedure, writable, big fd} \ -constraints {testfilehandler unix nonPortable} \ -setup { set chanList {} for {set i 0} {$i < 32} {incr i} { lappend chanList [open /dev/null r] } } \ -body { foreach i [after info] { after cancel $i } after 100 set x timeout testfilehandler close testfilehandler create 1 off off testfilehandler fill 1 set x "no timeout" set result [testfilehandler wait 1 writable 0] update testfilehandler close list $result $ } \ -result {{} {no timeout}} \ -cleanup { foreach chan $chanList {close $chan} } test event-14.5 {Tcl_WaitForFile procedure, writable, big fd} \ -constraints {testfilehandler unix nonPortable} \ -setup { set chanList {} for {set i 0} {$i < 32} {incr i} { lappend chanList [open /dev/null r] } } \ -body { foreach i [after info] { after cancel $i } after 100 set x timeout testfilehandler close testfilehandler create 1 off off testfilehandler fill 1 set x "no timeout" set result [testfilehandler wait 1 writable 100] update testfilehandler close list $result $x } \ -result {{} timeout} \ -cleanup { foreach chan $chanList {close $chan} } test event-14.6 {Tcl_WaitForFile procedure, writable, big fd} \ -constraints {testfilehandler unix} \ -setup { set chanList {} for {set i 0} {$i < 32} {incr i} { lappend chanList [open /dev/null r] } } \ -body { foreach i [after info] { after cancel $i } after 100 set x timeout testfilehandler close testfilehandler create 1 off off set x "no timeout" set result [testfilehandler wait 1 writable 100] update testfilehandler close list $result $x } \ -result {writable {no timeout}} \ -cleanup { foreach chan $chanList {close $chan} } test event-14.7 {Tcl_WaitForFile, don't call other event handlers, big fd} \ -constraints {testfilehandler unix} \ -setup { set chanList {} for {set i 0} {$i < 32} {incr i} { lappend chanList [open /dev/null r] } } \ -body { foreach i [after info] { after cancel $i } after 100 lappend x timeout after idle lappend x idle testfilehandler close testfilehandler create 1 off off set x "" set result [list [testfilehandler wait 1 readable 200] $x] update testfilehandler close lappend result $x } \ -result {{} {} {timeout idle}} \ -cleanup { foreach chan $chanList {close $chan} } test event-14.8 {Tcl_WaitForFile procedure, waiting indefinitely, big fd} \ -constraints {testfilewait unix} \ -body { set f [open "|sleep 2" r] set result "" lappend result [testfilewait $f readable 100] lappend result [testfilewait $f readable -1] close $f set result } \ -setup { set chanList {} for {set i 0} {$i < 32} {incr i} { lappend chanList [open /dev/null r] } } \ -result {{} readable} \ -cleanup { foreach chan $chanList {close $chan} } # cleanup foreach i [after info] { after cancel $i } ::tcltest::cleanupTests return tcl8.4.20/tests/msgcat.test0000644003604700454610000003736012052456744014250 0ustar dgp771div# This file contains a collection of tests for the msgcat package. # Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1998 Mark Harrison. # Copyright (c) 1998-1999 by Scriptics Corporation. # Contributions from Don Porter, NIST, 2002. (not subject to US copyright) # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # Note that after running these tests, entries will be left behind in the # message catalogs for locales foo, foo_BAR, and foo_BAR_baz. package require Tcl 8.2 if {[catch {package require tcltest 2}]} { puts stderr "Skipping tests in [info script]. tcltest 2 required." return } if {[catch {package require msgcat 1.3.5}]} { puts stderr "Skipping tests in [info script]. No msgcat 1.3.5 found to test." return } namespace eval ::msgcat::test { namespace import ::msgcat::* namespace import ::tcltest::test namespace import ::tcltest::cleanupTests namespace import ::tcltest::temporaryDirectory namespace import ::tcltest::make* namespace import ::tcltest::remove* # Tests msgcat-0.*: locale initialization proc PowerSet {l} { if {[llength $l] == 0} {return [list [list]]} set element [lindex $l 0] set rest [lrange $l 1 end] set result [list] foreach x [PowerSet $rest] { lappend result [linsert $x 0 $element] lappend result $x } return $result } variable envVars {LC_ALL LC_MESSAGES LANG} variable count 0 variable body variable result variable setVars foreach setVars [PowerSet $envVars] { set result [string tolower [lindex $setVars 0]] if {[string length $result] == 0} { if {[info exists ::tcl::mac::locale]} { set result [string tolower $::tcl::mac::locale] } else { if {([info sharedlibextension] == ".dll") && ![catch {package require registry}]} { # Windows and Cygwin have other ways to determine the # locale when the environment variables are missing # and the registry package is present continue } set result c } } test msgcat-0.$count [list \ locale initialization from environment variables $setVars \ ] -setup { variable var foreach var $envVars { catch {variable $var $::env($var)} catch {unset ::env($var)} } foreach var $setVars { set ::env($var) $var } interp create [namespace current]::i i eval [list package ifneeded msgcat [package provide msgcat] \ [package ifneeded msgcat [package provide msgcat]]] i eval package require msgcat } -cleanup { interp delete [namespace current]::i foreach var $envVars { catch {unset ::env($var)} catch {set ::env($var) [set [namespace current]::$var]} } } -body {i eval msgcat::mclocale} -result $result incr count } catch {unset result} # Could add tests of initialization from Windows registry here. # Use a fake registry package. # Tests msgcat-1.*: [mclocale], [mcpreferences] test msgcat-1.3 {mclocale set, single element} -setup { variable locale [mclocale] } -cleanup { mclocale $locale } -body { mclocale en } -result en test msgcat-1.4 {mclocale get, single element} -setup { variable locale [mclocale] mclocale en } -cleanup { mclocale $locale } -body { mclocale } -result en test msgcat-1.5 {mcpreferences, single element} -setup { variable locale [mclocale] mclocale en } -cleanup { mclocale $locale } -body { mcpreferences } -result en test msgcat-1.6 {mclocale set, two elements} -setup { variable locale [mclocale] } -cleanup { mclocale $locale } -body { mclocale en_US } -result en_us test msgcat-1.7 {mclocale get, two elements} -setup { variable locale [mclocale] mclocale en_US } -cleanup { mclocale $locale } -body { mclocale } -result en_us test msgcat-1.8 {mcpreferences, two elements} -setup { variable locale [mclocale] mclocale en_US } -cleanup { mclocale $locale } -body { mcpreferences } -result {en_us en} test msgcat-1.9 {mclocale set, three elements} -setup { variable locale [mclocale] } -cleanup { mclocale $locale } -body { mclocale en_US_funky } -result en_us_funky test msgcat-1.10 {mclocale get, three elements} -setup { variable locale [mclocale] mclocale en_US_funky } -cleanup { mclocale $locale } -body { mclocale } -result en_us_funky test msgcat-1.11 {mcpreferences, three elements} -setup { variable locale [mclocale] mclocale en_US_funky } -cleanup { mclocale $locale } -body { mcpreferences } -result {en_us_funky en_us en} test msgcat-1.12 {mclocale set, reject evil input} -setup { variable locale [mclocale] } -cleanup { mclocale $locale } -body { mclocale /path/to/evil/code } -returnCodes error -match glob -result {invalid newLocale value *} test msgcat-1.13 {mclocale set, reject evil input} -setup { variable locale [mclocale] } -cleanup { mclocale $locale } -body { mclocale looks/ok/../../../../but/is/path/to/evil/code } -returnCodes error -match glob -result {invalid newLocale value *} # Tests msgcat-2.*: [mcset], [mcmset], namespace partitioning test msgcat-2.1 {mcset, global scope} { namespace eval :: ::msgcat::mcset foo_BAR text1 text2 } {text2} test msgcat-2.2 {mcset, global scope, default} { namespace eval :: ::msgcat::mcset foo_BAR text3 } {text3} test msgcat-2.2.1 {mcset, namespace overlap} { namespace eval baz {::msgcat::mcset foo_BAR con1 con1baz} } {con1baz} test msgcat-2.3 {mcset, namespace overlap} -setup { namespace eval bar {::msgcat::mcset foo_BAR con1 con1bar} namespace eval baz {::msgcat::mcset foo_BAR con1 con1baz} variable locale [mclocale] mclocale foo_BAR } -cleanup { mclocale $locale } -body { namespace eval bar {::msgcat::mc con1} } -result con1bar test msgcat-2.4 {mcset, namespace overlap} -setup { namespace eval bar {::msgcat::mcset foo_BAR con1 con1bar} namespace eval baz {::msgcat::mcset foo_BAR con1 con1baz} variable locale [mclocale] mclocale foo_BAR } -cleanup { mclocale $locale } -body { namespace eval baz {::msgcat::mc con1} } -result con1baz test msgcat-2.5 {mcmset, global scope} -setup { namespace eval :: { ::msgcat::mcmset foo_BAR { src1 trans1 src2 trans2 } } variable locale [mclocale] mclocale foo_BAR } -cleanup { mclocale $locale } -body { namespace eval :: { ::msgcat::mc src1 } } -result trans1 test msgcat-2.6 {mcmset, namespace overlap} -setup { namespace eval bar {::msgcat::mcmset foo_BAR {con2 con2bar}} namespace eval baz {::msgcat::mcmset foo_BAR {con2 con2baz}} variable locale [mclocale] mclocale foo_BAR } -cleanup { mclocale $locale } -body { namespace eval bar {::msgcat::mc con2} } -result con2bar test msgcat-2.7 {mcmset, namespace overlap} -setup { namespace eval bar {::msgcat::mcmset foo_BAR {con2 con2bar}} namespace eval baz {::msgcat::mcmset foo_BAR {con2 con2baz}} variable locale [mclocale] mclocale foo_BAR } -cleanup { mclocale $locale } -body { namespace eval baz {::msgcat::mc con2} } -result con2baz # Tests msgcat-3.*: [mcset], [mc], catalog "inheritance" # # Test mcset and mc, ensuring that more specific locales # (e.g. en_UK) will search less specific locales # (e.g. en) for translation strings. # # Do this for the 12 permutations of # locales: {foo foo_BAR foo_BAR_baz} # strings: {ov1 ov2 ov3 ov4} # locale foo defines ov1, ov2, ov3 # locale foo_BAR defines ov2, ov3 # locale foo_BAR_BAZ defines ov3 # (ov4 is defined in none) # So, # ov3 should be resolved in foo, foo_BAR, foo_BAR_baz # ov2 should be resolved in foo, foo_BAR # ov2 should resolve to foo_BAR in foo_BAR_baz # ov1 should be resolved in foo # ov1 should resolve to foo in foo_BAR, foo_BAR_baz # ov4 should be resolved in none, and call mcunknown # variable count 2 variable result array set result { foo,ov1 ov1_foo foo,ov2 ov2_foo foo,ov3 ov3_foo foo,ov4 ov4 foo_BAR,ov1 ov1_foo foo_BAR,ov2 ov2_foo_BAR foo_BAR,ov3 ov3_foo_BAR foo_BAR,ov4 ov4 foo_BAR_baz,ov1 ov1_foo foo_BAR_baz,ov2 ov2_foo_BAR foo_BAR_baz,ov3 ov3_foo_BAR_baz foo_BAR_baz,ov4 ov4 } variable loc variable string foreach loc {foo foo_BAR foo_BAR_baz} { foreach string {ov1 ov2 ov3 ov4} { test msgcat-3.$count {mcset, overlap} -setup { mcset foo ov1 ov1_foo mcset foo ov2 ov2_foo mcset foo ov3 ov3_foo mcset foo_BAR ov2 ov2_foo_BAR mcset foo_BAR ov3 ov3_foo_BAR mcset foo_BAR_baz ov3 ov3_foo_BAR_baz variable locale [mclocale] mclocale $loc } -cleanup { mclocale $locale } -body { mc $string } -result $result($loc,$string) incr count } } catch {unset result} # Tests msgcat-4.*: [mcunknown] test msgcat-4.2 {mcunknown, default} -setup { mcset foo unk1 "unknown 1" variable locale [mclocale] mclocale foo } -cleanup { mclocale $locale } -body { mc unk1 } -result {unknown 1} test msgcat-4.3 {mcunknown, default} -setup { mcset foo unk1 "unknown 1" variable locale [mclocale] mclocale foo } -cleanup { mclocale $locale } -body { mc unk2 } -result unk2 test msgcat-4.4 {mcunknown, overridden} -setup { rename ::msgcat::mcunknown SavedMcunknown proc ::msgcat::mcunknown {dom s} { return unknown:$dom:$s } mcset foo unk1 "unknown 1" variable locale [mclocale] mclocale foo } -cleanup { mclocale $locale rename ::msgcat::mcunknown {} rename SavedMcunknown ::msgcat::mcunknown } -body { mc unk1 } -result {unknown 1} test msgcat-4.5 {mcunknown, overridden} -setup { rename ::msgcat::mcunknown SavedMcunknown proc ::msgcat::mcunknown {dom s} { return unknown:$dom:$s } mcset foo unk1 "unknown 1" variable locale [mclocale] mclocale foo } -cleanup { mclocale $locale rename ::msgcat::mcunknown {} rename SavedMcunknown ::msgcat::mcunknown } -body { mc unk2 } -result {unknown:foo:unk2} test msgcat-4.6 {mcunknown, uplevel context} -setup { rename ::msgcat::mcunknown SavedMcunknown proc ::msgcat::mcunknown {dom s} { return "unknown:$dom:$s:[expr {[info level] - 1}]" } mcset foo unk1 "unknown 1" variable locale [mclocale] mclocale foo } -cleanup { mclocale $locale rename ::msgcat::mcunknown {} rename SavedMcunknown ::msgcat::mcunknown } -body { mc unk2 } -result unknown:foo:unk2:[info level] # Tests msgcat-5.*: [mcload] variable locales {foo foo_BAR foo_BAR_baz} makeDirectory msgdir foreach loc $locales { makeFile "::msgcat::mcset $loc abc abc-$loc" \ [string tolower [file join msgdir $loc.msg]] } variable count 1 foreach loc {foo foo_BAR foo_BAR_baz} { test msgcat-5.$count {mcload} -setup { variable locale [mclocale] mclocale $loc } -cleanup { mclocale $locale } -body { mcload [file join [temporaryDirectory] msgdir] } -result $count incr count } # Even though foo_BAR_notexist does not exist, # foo_BAR and foo should be loaded. test msgcat-5.4 {mcload} -setup { variable locale [mclocale] mclocale foo_BAR_notexist } -cleanup { mclocale $locale } -body { mcload [file join [temporaryDirectory] msgdir] } -result 2 test msgcat-5.5 {mcload} -setup { variable locale [mclocale] mclocale no_FI_notexist } -cleanup { mclocale $locale } -body { mcload [file join [temporaryDirectory] msgdir] } -result 0 test msgcat-5.6 {mcload} -setup { variable locale [mclocale] mclocale foo } -cleanup { mclocale $locale } -body { mc abc } -result abc-foo test msgcat-5.7 {mcload} -setup { variable locale [mclocale] mclocale foo_BAR } -cleanup { mclocale $locale } -body { mc abc } -result abc-foo_BAR test msgcat-5.8 {mcload} -setup { variable locale [mclocale] mclocale foo_BAR_baz } -cleanup { mclocale $locale } -body { mc abc } -result abc-foo_BAR_baz test msgcat-5.9 {mcload} -setup { rename ::msgcat::mcunknown SavedMcunknown proc ::msgcat::mcunknown {dom s} { return unknown:$dom:$s } variable locale [mclocale] mclocale no_FI_notexist } -cleanup { mclocale $locale rename ::msgcat::mcunknown {} rename SavedMcunknown ::msgcat::mcunknown } -body { mc abc } -result unknown:no_fi_notexist:abc foreach loc $locales { removeFile [string tolower [file join msgdir $loc.msg]] } removeDirectory msgdir # Tests msgcat-6.*: [mcset], [mc] namespace inheritance # # Test mcset and mc, ensuring that resolution for messages # proceeds from the current ns to its parent and so on to the # global ns. # # Do this for the 12 permutations of # locales: foo # namespaces: foo foo::bar foo::bar::baz # strings: {ov1 ov2 ov3 ov4} # namespace ::foo defines ov1, ov2, ov3 # namespace ::foo::bar defines ov2, ov3 # namespace ::foo::bar::baz defines ov3 # # ov4 is not defined in any namespace. # # So, # ov3 should be resolved in ::foo::bar::baz, ::foo::bar, ::foo; # ov2 should be resolved in ::foo, ::foo::bar # ov1 should be resolved in ::foo # ov4 should be resolved in none, and call mcunknown # variable result array set result { foo,ov1 ov1_foo foo,ov2 ov2_foo foo,ov3 ov3_foo foo,ov4 ov4 foo::bar,ov1 ov1_foo foo::bar,ov2 ov2_foo_bar foo::bar,ov3 ov3_foo_bar foo::bar,ov4 ov4 foo::bar::baz,ov1 ov1_foo foo::bar::baz,ov2 ov2_foo_bar foo::bar::baz,ov3 ov3_foo_bar_baz foo::bar::baz,ov4 ov4 } variable count 1 variable ns foreach ns {foo foo::bar foo::bar::baz} { foreach string {ov1 ov2 ov3 ov4} { test msgcat-6.$count {mcset, overlap} -setup { namespace eval foo { ::msgcat::mcset foo ov1 ov1_foo ::msgcat::mcset foo ov2 ov2_foo ::msgcat::mcset foo ov3 ov3_foo namespace eval bar { ::msgcat::mcset foo ov2 ov2_foo_bar ::msgcat::mcset foo ov3 ov3_foo_bar namespace eval baz { ::msgcat::mcset foo ov3 "ov3_foo_bar_baz" } } } variable locale [mclocale] mclocale foo } -cleanup { mclocale $locale namespace delete foo } -body { namespace eval $ns [list ::msgcat::mc $string] } -result $result($ns,$string) incr count } } # Tests msgcat-7.*: [mc] extra args processed by [format] test msgcat-7.1 {mc extra args go through to format} -setup { mcset foo format1 "this is a test" mcset foo format2 "this is a %s" mcset foo format3 "this is a %s %s" variable locale [mclocale] mclocale foo } -cleanup { mclocale $locale } -body { mc format1 "good test" } -result "this is a test" test msgcat-7.2 {mc extra args go through to format} -setup { mcset foo format1 "this is a test" mcset foo format2 "this is a %s" mcset foo format3 "this is a %s %s" variable locale [mclocale] mclocale foo } -cleanup { mclocale $locale } -body { mc format2 "good test" } -result "this is a good test" test msgcat-7.3 {mc errors from format are propagated} -setup { mcset foo format1 "this is a test" mcset foo format2 "this is a %s" mcset foo format3 "this is a %s %s" variable locale [mclocale] mclocale foo } -cleanup { mclocale $locale } -body { catch {mc format3 "good test"} } -result 1 test msgcat-7.4 {mc, extra args are given to unknown} -setup { mcset foo format1 "this is a test" mcset foo format2 "this is a %s" mcset foo format3 "this is a %s %s" variable locale [mclocale] mclocale foo } -cleanup { mclocale $locale } -body { mc "this is a %s" "good test" } -result "this is a good test" cleanupTests } namespace delete ::msgcat::test return tcl8.4.20/tests/pkgMkIndex.test0000644003604700454610000004651211737050674015033 0ustar dgp771div# This file contains tests for the pkg_mkIndex command. # Note that the tests are limited to Tcl scripts only, there are no shared # libraries against which to test. # # Sourcing this file into Tcl runs the tests and generates output for # errors. No output means no errors were found. # # Copyright (c) 1998-1999 by Scriptics Corporation. # All rights reserved. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import -force ::tcltest::* } set fullPkgPath [makeDirectory pkg] namespace eval pkgtest { # Namespace for procs we can discard } # pkgtest::parseArgs -- # # Parse an argument list. # # Arguments: # (optional) arguments starting with a dash are collected # as options to pkg_mkIndex and passed to pkg_mkIndex. # dirPath the directory to index # pattern0 pattern to index # ... pattern to index # patternN pattern to index # # Results: # Returns a three element list: # 0: the options # 1: the directory to index # 2: the patterns list proc pkgtest::parseArgs { args } { set options "" set argc [llength $args] for {set iarg 0} {$iarg < $argc} {incr iarg} { set a [lindex $args $iarg] if {[regexp {^-} $a]} { lappend options $a if {[string compare -load $a] == 0} { incr iarg lappend options [lindex $args $iarg] } } else { break } } set dirPath [lindex $args $iarg] incr iarg set patternList [lrange $args $iarg end] return [list $options $dirPath $patternList] } # pkgtest::parseIndex -- # # Loads a pkgIndex.tcl file, records all the calls to "package ifneeded". # # Arguments: # filePath path to the pkgIndex.tcl file. # # Results: # Returns a list, in "array set/get" format, where the keys are the package # name and version (in the form "$name:$version"), and the values the rest # of the command line. proc pkgtest::parseIndex { filePath } { # create a slave interpreter, where we override "package ifneeded" set slave [interp create] if {[catch { $slave eval { rename package package_original proc package { args } { if {[string compare [lindex $args 0] ifneeded] == 0} { set pkg [lindex $args 1] set ver [lindex $args 2] set ::PKGS($pkg:$ver) [lindex $args 3] } else { return [eval package_original $args] } } array set ::PKGS {} } set dir [file dirname $filePath] $slave eval {set curdir [pwd]} $slave eval [list cd $dir] $slave eval [list set dir $dir] $slave eval [list source [file tail $filePath]] $slave eval {cd $curdir} # Create the list in sorted order, so that we don't get spurious # errors because the order has changed. array set P {} foreach {k v} [$slave eval {array get ::PKGS}] { set P($k) $v } set PKGS "" foreach k [lsort [array names P]] { lappend PKGS $k $P($k) } } err]} { set ei $::errorInfo set ec $::errorCode catch {interp delete $slave} error $ei $ec } interp delete $slave return $PKGS } # pkgtest::createIndex -- # # Runs pkg_mkIndex for the given directory and set of patterns. # This procedure deletes any pkgIndex.tcl file in the target directory, # then runs pkg_mkIndex. # # Arguments: # (optional) arguments starting with a dash are collected # as options to pkg_mkIndex and passed to pkg_mkIndex. # dirPath the directory to index # pattern0 pattern to index # ... pattern to index # patternN pattern to index # # Results: # Returns a two element list: # 0: 1 if the procedure encountered an error, 0 otherwise. # 1: the error result if element 0 was 1 proc pkgtest::createIndex { args } { set parsed [eval parseArgs $args] set options [lindex $parsed 0] set dirPath [lindex $parsed 1] set patternList [lindex $parsed 2] file mkdir $dirPath if {[catch { file delete [file join $dirPath pkgIndex.tcl] eval pkg_mkIndex $options [list $dirPath] $patternList } err]} { return [list 1 $err] } return [list 0 {}] } # makePkgList -- # # Takes the output of a pkgtest::parseIndex call, filters it and returns a # cleaned up list of packages and their actions. # # Arguments: # inList output from a pkgtest::parseIndex. # # Results: # Returns a list of two element lists: # 0: the name:version # 1: a list describing the package. # For tclPkgSetup packages it consists of: # 0: the keyword tclPkgSetup # 1: the first file to source, with its exported procedures # 2: the second file ... # N: the N-1st file ... proc makePkgList { inList } { set pkgList "" foreach {k v} $inList { switch [lindex $v 0] { tclPkgSetup { set l tclPkgSetup foreach s [lindex $v 4] { lappend l $s } } source { set l $v } default { error "can't handle $k $v" } } lappend pkgList [list $k $l] } return $pkgList } # pkgtest::runIndex -- # # Runs pkg_mkIndex, parses the generated index file. # # Arguments: # (optional) arguments starting with a dash are collected # as options to pkg_mkIndex and passed to pkg_mkIndex. # dirPath the directory to index # pattern0 pattern to index # ... pattern to index # patternN pattern to index # # Results: # Returns a two element list: # 0: 1 if the procedure encountered an error, 0 otherwise. # 1: if no error, this is the parsed generated index file, in the format # returned by pkgtest::parseIndex. # If error, this is the error result. proc pkgtest::runCreatedIndex {rv args} { if {[lindex $rv 0] == 0} { set parsed [eval parseArgs $args] set dirPath [lindex $parsed 1] set idxFile [file join $dirPath pkgIndex.tcl] if {[catch { set result [list 0 [makePkgList [parseIndex $idxFile]]] } err]} { set result [list 1 $err] } file delete $idxFile } else { set result $rv } return $result } proc pkgtest::runIndex { args } { set rv [eval createIndex $args] return [eval [list runCreatedIndex $rv] $args] } # If there is no match to the patterns, make sure the directory hasn't # changed on us test pkgMkIndex-1.1 {nothing matches pattern - current dir is the same} { list [pkgtest::runIndex -lazy $fullPkgPath nomatch.tcl] [pwd] } [list {1 {no files matched glob pattern "nomatch.tcl"}} [pwd]] makeFile { # This is a simple package, just to check basic functionality. package provide simple 1.0 namespace eval simple { namespace export lower upper } proc simple::lower { stg } { return [string tolower $stg] } proc simple::upper { stg } { return [string toupper $stg] } } [file join pkg simple.tcl] test pkgMkIndex-2.1 {simple package} { pkgtest::runIndex -lazy $fullPkgPath simple.tcl } {0 {{simple:1.0 {tclPkgSetup {simple.tcl source {::simple::lower ::simple::upper}}}}}} test pkgMkIndex-2.2 {simple package - use -direct} { pkgtest::runIndex -direct $fullPkgPath simple.tcl } "0 {{simple:1.0 {[list source [file join $fullPkgPath simple.tcl]]}}}" test pkgMkIndex-2.3 {simple package - direct loading is default} { pkgtest::runIndex $fullPkgPath simple.tcl } "0 {{simple:1.0 {[list source [file join $fullPkgPath simple.tcl]]}}}" test pkgMkIndex-2.4 {simple package - use -verbose} -body { pkgtest::runIndex -verbose $fullPkgPath simple.tcl } -result "0 {{simple:1.0 {[list source [file join $fullPkgPath simple.tcl]]}}}" \ -errorOutput {successful sourcing of simple.tcl packages provided were {simple 1.0} processed simple.tcl } removeFile [file join pkg simple.tcl] makeFile { # Contains global symbols, used to check that they don't have a leading :: package provide global 1.0 proc global_lower { stg } { return [string tolower $stg] } proc global_upper { stg } { return [string toupper $stg] } } [file join pkg global.tcl] test pkgMkIndex-3.1 {simple package with global symbols} { pkgtest::runIndex -lazy $fullPkgPath global.tcl } {0 {{global:1.0 {tclPkgSetup {global.tcl source {global_lower global_upper}}}}}} removeFile [file join pkg global.tcl] makeFile { # This package is required by pkg1. # This package is split into two files, to test packages that are split # over multiple files. package provide pkg2 1.0 namespace eval pkg2 { namespace export p2-1 } proc pkg2::p2-1 { num } { return [expr $num * 2] } } [file join pkg pkg2_a.tcl] makeFile { # This package is required by pkg1. # This package is split into two files, to test packages that are split # over multiple files. package provide pkg2 1.0 namespace eval pkg2 { namespace export p2-2 } proc pkg2::p2-2 { num } { return [expr $num * 3] } } [file join pkg pkg2_b.tcl] test pkgMkIndex-4.1 {split package} { pkgtest::runIndex -lazy $fullPkgPath pkg2_a.tcl pkg2_b.tcl } {0 {{pkg2:1.0 {tclPkgSetup {pkg2_a.tcl source ::pkg2::p2-1} {pkg2_b.tcl source ::pkg2::p2-2}}}}} test pkgMkIndex-4.2 {split package - direct loading} { pkgtest::runIndex -direct $fullPkgPath pkg2_a.tcl pkg2_b.tcl } "0 {{pkg2:1.0 {[list source [file join $fullPkgPath pkg2_a.tcl]] [list source [file join $fullPkgPath pkg2_b.tcl]]}}}" # Add the direct1 directory to auto_path, so that the direct1 package # can be found. set direct1 [makeDirectory direct1] lappend auto_path $direct1 makeFile { # This is referenced by pkgIndex.tcl as a -direct script. package provide direct1 1.0 namespace eval direct1 { namespace export pd1 pd2 } proc direct1::pd1 { stg } { return [string tolower $stg] } proc direct1::pd2 { stg } { return [string toupper $stg] } } [file join direct1 direct1.tcl] pkg_mkIndex -direct $direct1 direct1.tcl makeFile { # Does a package require of direct1, whose pkgIndex.tcl entry # is created above with option -direct. This tests that pkg_mkIndex # can handle code that is sourced in pkgIndex.tcl files. package require direct1 package provide std 1.0 namespace eval std { namespace export p1 p2 } proc std::p1 { stg } { return [string tolower $stg] } proc std::p2 { stg } { return [string toupper $stg] } } [file join pkg std.tcl] test pkgMkIndex-5.1 {requires -direct package} { pkgtest::runIndex -lazy $fullPkgPath std.tcl } {0 {{std:1.0 {tclPkgSetup {std.tcl source {::std::p1 ::std::p2}}}}}} removeFile [file join direct1 direct1.tcl] file delete [file join $direct1 pkgIndex.tcl] removeDirectory direct1 removeFile [file join pkg std.tcl] makeFile { # This package requires pkg3, but it does # not use any of pkg3's procs in the code that is executed by the file # (i.e. references to pkg3's procs are in the proc bodies only). package require pkg3 1.0 package provide pkg1 1.0 namespace eval pkg1 { namespace export p1-1 p1-2 } proc pkg1::p1-1 { num } { return [pkg3::p3-1 $num] } proc pkg1::p1-2 { num } { return [pkg3::p3-2 $num] } } [file join pkg pkg1.tcl] makeFile { package provide pkg3 1.0 namespace eval pkg3 { namespace export p3-1 p3-2 } proc pkg3::p3-1 { num } { return {[expr $num * 2]} } proc pkg3::p3-2 { num } { return {[expr $num * 3]} } } [file join pkg pkg3.tcl] test pkgMkIndex-6.1 {pkg1 requires pkg3} { pkgtest::runIndex -lazy $fullPkgPath pkg1.tcl pkg3.tcl } {0 {{pkg1:1.0 {tclPkgSetup {pkg1.tcl source {::pkg1::p1-1 ::pkg1::p1-2}}}} {pkg3:1.0 {tclPkgSetup {pkg3.tcl source {::pkg3::p3-1 ::pkg3::p3-2}}}}}} test pkgMkIndex-6.2 {pkg1 requires pkg3 - use -direct} { pkgtest::runIndex -direct $fullPkgPath pkg1.tcl pkg3.tcl } "0 {{pkg1:1.0 {[list source [file join $fullPkgPath pkg1.tcl]]}} {pkg3:1.0 {[list source [file join $fullPkgPath pkg3.tcl]]}}}" removeFile [file join pkg pkg1.tcl] makeFile { # This package requires pkg3, and it calls # a pkg3 proc in the code that is executed by the file package require pkg3 1.0 package provide pkg4 1.0 namespace eval pkg4 { namespace export p4-1 p4-2 variable m2 [pkg3::p3-1 10] } proc pkg4::p4-1 { num } { variable m2 return [expr {$m2 * $num}] } proc pkg4::p4-2 { num } { return [pkg3::p3-2 $num] } } [file join pkg pkg4.tcl] test pkgMkIndex-7.1 {pkg4 uses pkg3} { pkgtest::runIndex -lazy $fullPkgPath pkg4.tcl pkg3.tcl } {0 {{pkg3:1.0 {tclPkgSetup {pkg3.tcl source {::pkg3::p3-1 ::pkg3::p3-2}}}} {pkg4:1.0 {tclPkgSetup {pkg4.tcl source {::pkg4::p4-1 ::pkg4::p4-2}}}}}} test pkgMkIndex-7.2 {pkg4 uses pkg3 - use -direct} { pkgtest::runIndex -direct $fullPkgPath pkg4.tcl pkg3.tcl } "0 {{pkg3:1.0 {[list source [file join $fullPkgPath pkg3.tcl]]}} {pkg4:1.0 {[list source [file join $fullPkgPath pkg4.tcl]]}}}" removeFile [file join pkg pkg4.tcl] removeFile [file join pkg pkg3.tcl] makeFile { # This package requires pkg2, and it calls # a pkg2 proc in the code that is executed by the file. # Pkg2 is a split package. package require pkg2 1.0 package provide pkg5 1.0 namespace eval pkg5 { namespace export p5-1 p5-2 variable m2 [pkg2::p2-1 10] variable m3 [pkg2::p2-2 10] } proc pkg5::p5-1 { num } { variable m2 return [expr {$m2 * $num}] } proc pkg5::p5-2 { num } { variable m2 return [expr {$m2 * $num}] } } [file join pkg pkg5.tcl] test pkgMkIndex-8.1 {pkg5 uses pkg2} { pkgtest::runIndex -lazy $fullPkgPath pkg5.tcl pkg2_a.tcl pkg2_b.tcl } {0 {{pkg2:1.0 {tclPkgSetup {pkg2_a.tcl source ::pkg2::p2-1} {pkg2_b.tcl source ::pkg2::p2-2}}} {pkg5:1.0 {tclPkgSetup {pkg5.tcl source {::pkg5::p5-1 ::pkg5::p5-2}}}}}} test pkgMkIndex-8.2 {pkg5 uses pkg2 - use -direct} { pkgtest::runIndex -direct $fullPkgPath pkg5.tcl pkg2_a.tcl pkg2_b.tcl } "0 {{pkg2:1.0 {[list source [file join $fullPkgPath pkg2_a.tcl]] [list source [file join $fullPkgPath pkg2_b.tcl]]}} {pkg5:1.0 {[list source [file join $fullPkgPath pkg5.tcl]]}}}" removeFile [file join pkg pkg5.tcl] removeFile [file join pkg pkg2_a.tcl] removeFile [file join pkg pkg2_b.tcl] makeFile { # This package requires circ2, and circ2 # requires circ3, which in turn requires circ1. # In case of cirularities, pkg_mkIndex should give up when it gets stuck. package require circ2 1.0 package provide circ1 1.0 namespace eval circ1 { namespace export c1-1 c1-2 c1-3 c1-4 } proc circ1::c1-1 { num } { return [circ2::c2-1 $num] } proc circ1::c1-2 { num } { return [circ2::c2-2 $num] } proc circ1::c1-3 {} { return 10 } proc circ1::c1-4 {} { return 20 } } [file join pkg circ1.tcl] makeFile { # This package is required by circ1, and # requires circ3. Circ3, in turn, requires circ1 to give us a circularity. package require circ3 1.0 package provide circ2 1.0 namespace eval circ2 { namespace export c2-1 c2-2 } proc circ2::c2-1 { num } { return [expr $num * [circ3::c3-1]] } proc circ2::c2-2 { num } { return [expr $num * [circ3::c3-2]] } } [file join pkg circ2.tcl] makeFile { # This package is required by circ2, and in # turn requires circ1. This closes the circularity. package require circ1 1.0 package provide circ3 1.0 namespace eval circ3 { namespace export c3-1 c3-4 } proc circ3::c3-1 {} { return [circ1::c1-3] } proc circ3::c3-2 {} { return [circ1::c1-4] } } [file join pkg circ3.tcl] test pkgMkIndex-9.1 {circular packages} { pkgtest::runIndex -lazy $fullPkgPath circ1.tcl circ2.tcl circ3.tcl } {0 {{circ1:1.0 {tclPkgSetup {circ1.tcl source {::circ1::c1-1 ::circ1::c1-2 ::circ1::c1-3 ::circ1::c1-4}}}} {circ2:1.0 {tclPkgSetup {circ2.tcl source {::circ2::c2-1 ::circ2::c2-2}}}} {circ3:1.0 {tclPkgSetup {circ3.tcl source ::circ3::c3-1}}}}} removeFile [file join pkg circ1.tcl] removeFile [file join pkg circ2.tcl] removeFile [file join pkg circ3.tcl] # Some tests require the existence of one of the DLLs in the dltest directory set x [file join [file dirname [info nameofexecutable]] dltest \ pkga[info sharedlibextension]] set dll "[file tail $x]Required" ::tcltest::testConstraint $dll [file exists $x] if {[testConstraint $dll]} { makeFile { # This package provides Pkga, which is also provided by a DLL. package provide Pkga 1.0 proc pkga_neq { x } { return [expr {! [pkgq_eq $x]}] } } [file join pkg pkga.tcl] file copy -force $x $fullPkgPath } testConstraint exec [llength [info commands ::exec]] test pkgMkIndex-10.1 {package in DLL and script} [list exec $dll] { # Do all [load]ing of shared libraries in another process, so # we can delete the file and not get stuck because we're holding # a reference to it. set cmd [list pkg_mkIndex -lazy $fullPkgPath [file tail $x] pkga.tcl] exec [interpreter] << $cmd pkgtest::runCreatedIndex {0 {}} -lazy $fullPkgPath pkga[info sharedlibextension] pkga.tcl } "0 {{Pkga:1.0 {tclPkgSetup {pkga[info sharedlibextension] load {pkga_eq pkga_quote}} {pkga.tcl source pkga_neq}}}}" test pkgMkIndex-10.2 {package in DLL hidden by -load} [list exec $dll] { # Do all [load]ing of shared libraries in another process, so # we can delete the file and not get stuck because we're holding # a reference to it. # # This test depends on context from prior test, so repeat it. set script "[list pkg_mkIndex -lazy $fullPkgPath [file tail $x] pkga.tcl]\n" append script \ "[list pkg_mkIndex -lazy -load Pkg* $fullPkgPath [file tail $x]]" exec [interpreter] << $script pkgtest::runCreatedIndex {0 {}} -lazy -load Pkg* -- $fullPkgPath pkga[info sharedlibextension] } {0 {}} if {[testConstraint $dll]} { file delete -force [file join $fullPkgPath [file tail $x]] removeFile [file join pkg pkga.tcl] } # Tolerate "namespace import" at the global scope makeFile { package provide fubar 1.0 namespace eval ::fubar:: { # # export only public functions. # namespace export {[a-z]*} } proc ::fubar::foo {bar} { puts "$bar" return true } namespace import ::fubar::foo } [file join pkg import.tcl] test pkgMkIndex-11.1 {conflicting namespace imports} { pkgtest::runIndex -lazy $fullPkgPath import.tcl } {0 {{fubar:1.0 {tclPkgSetup {import.tcl source ::fubar::foo}}}}} removeFile [file join pkg import.tcl] # Verify that the auto load list generated is correct even when there # is a proc name conflict between two namespaces (ie, ::foo::baz and # ::bar::baz) makeFile { package provide football 1.0 namespace eval ::pro:: { # # export only public functions. # namespace export {[a-z]*} } namespace eval ::college:: { # # export only public functions. # namespace export {[a-z]*} } proc ::pro::team {} { puts "go packers!" return true } proc ::college::team {} { puts "go badgers!" return true } } [file join pkg samename.tcl] test pkgMkIndex-12.1 {same name procs in different namespace} { pkgtest::runIndex -lazy $fullPkgPath samename.tcl } {0 {{football:1.0 {tclPkgSetup {samename.tcl source {::college::team ::pro::team}}}}}} removeFile [file join pkg samename.tcl] # Proc names with embedded spaces are properly listed (ie, correct number of # braces) in result makeFile { package provide spacename 1.0 proc {a b} {} {} proc {c d} {} {} } [file join pkg spacename.tcl] test pkgMkIndex-13.1 {proc names with embedded spaces} { pkgtest::runIndex -lazy $fullPkgPath spacename.tcl } {0 {{spacename:1.0 {tclPkgSetup {spacename.tcl source {{a b} {c d}}}}}}} removeFile [file join pkg spacename.tcl] # Test the pkg_compareExtension helper function test pkgMkIndex-14.1 {pkg_compareExtension} {unixOnly} { pkg_compareExtension foo.so .so } 1 test pkgMkIndex-14.2 {pkg_compareExtension} {unixOnly} { pkg_compareExtension foo.so.bar .so } 0 test pkgMkIndex-14.3 {pkg_compareExtension} {unixOnly} { pkg_compareExtension foo.so.1 .so } 1 test pkgMkIndex-14.4 {pkg_compareExtension} {unixOnly} { pkg_compareExtension foo.so.1.2 .so } 1 test pkgMkIndex-14.5 {pkg_compareExtension} {unixOnly} { pkg_compareExtension foo .so } 0 test pkgMkIndex-14.6 {pkg_compareExtension} {unixOnly} { pkg_compareExtension foo.so.1.2.bar .so } 0 # cleanup removeDirectory pkg namespace delete pkgtest ::tcltest::cleanupTests return tcl8.4.20/tests/proc-old.test0000644003604700454610000003544011737050674014507 0ustar dgp771div# Commands covered: proc, return, global # # This file, proc-old.test, includes the original set of tests for Tcl's # proc, return, and global commands. There is now a new file proc.test # that contains tests for the tclProc.c source file. # # Sourcing this file into Tcl runs the tests and generates output for # errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994-1997 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } catch {rename t1 ""} catch {rename foo ""} proc tproc {} {return a; return b} test proc-old-1.1 {simple procedure call and return} {tproc} a proc tproc x { set x [expr $x+1] return $x } test proc-old-1.2 {simple procedure call and return} {tproc 2} 3 test proc-old-1.3 {simple procedure call and return} { proc tproc {} {return foo} } {} test proc-old-1.4 {simple procedure call and return} { proc tproc {} {return} tproc } {} proc tproc1 {a} {incr a; return $a} proc tproc2 {a b} {incr a; return $a} test proc-old-1.5 {simple procedure call and return (2 procs with same body but different parameters)} { list [tproc1 123] [tproc2 456 789] } {124 457} test proc-old-1.6 {simple procedure call and return (shared proc body string)} { set x {} proc tproc {} {} ;# body is shared with x list [tproc] [append x foo] } {{} foo} test proc-old-2.1 {local and global variables} { proc tproc x { set x [expr $x+1] return $x } set x 42 list [tproc 6] $x } {7 42} test proc-old-2.2 {local and global variables} { proc tproc x { set y [expr $x+1] return $y } set y 18 list [tproc 6] $y } {7 18} test proc-old-2.3 {local and global variables} { proc tproc x { global y set y [expr $x+1] return $y } set y 189 list [tproc 6] $y } {7 7} test proc-old-2.4 {local and global variables} { proc tproc x { global y return [expr $x+$y] } set y 189 list [tproc 6] $y } {195 189} catch {unset _undefined_} test proc-old-2.5 {local and global variables} { proc tproc x { global _undefined_ return $_undefined_ } list [catch {tproc xxx} msg] $msg } {1 {can't read "_undefined_": no such variable}} test proc-old-2.6 {local and global variables} { set a 114 set b 115 global a b list $a $b } {114 115} proc do {cmd} {eval $cmd} test proc-old-3.1 {local and global arrays} { catch {unset a} set a(0) 22 list [catch {do {global a; set a(0)}} msg] $msg } {0 22} test proc-old-3.2 {local and global arrays} { catch {unset a} set a(x) 22 list [catch {do {global a; set a(x) newValue}} msg] $msg $a(x) } {0 newValue newValue} test proc-old-3.3 {local and global arrays} { catch {unset a} set a(x) 22 set a(y) 33 list [catch {do {global a; unset a(y)}; array names a} msg] $msg } {0 x} test proc-old-3.4 {local and global arrays} { catch {unset a} set a(x) 22 set a(y) 33 list [catch {do {global a; unset a; info exists a}} msg] $msg \ [info exists a] } {0 0 0} test proc-old-3.5 {local and global arrays} { catch {unset a} set a(x) 22 set a(y) 33 list [catch {do {global a; unset a(y); array names a}} msg] $msg } {0 x} catch {unset a} test proc-old-3.6 {local and global arrays} { catch {unset a} set a(x) 22 set a(y) 33 do {global a; do {global a; unset a}; set a(z) 22} list [catch {array names a} msg] $msg } {0 z} test proc-old-3.7 {local and global arrays} { proc t1 {args} {global info; set info 1} catch {unset a} set info {} do {global a; trace var a(1) w t1} set a(1) 44 set info } 1 test proc-old-3.8 {local and global arrays} { proc t1 {args} {global info; set info 1} catch {unset a} trace var a(1) w t1 set info {} do {global a; trace vdelete a(1) w t1} set a(1) 44 set info } {} test proc-old-3.9 {local and global arrays} { proc t1 {args} {global info; set info 1} catch {unset a} trace var a(1) w t1 do {global a; trace vinfo a(1)} } {{w t1}} catch {unset a} test proc-old-30.1 {arguments and defaults} { proc tproc {x y z} { return [list $x $y $z] } tproc 11 12 13 } {11 12 13} test proc-old-30.2 {arguments and defaults} { proc tproc {x y z} { return [list $x $y $z] } list [catch {tproc 11 12} msg] $msg } {1 {wrong # args: should be "tproc x y z"}} test proc-old-30.3 {arguments and defaults} { proc tproc {x y z} { return [list $x $y $z] } list [catch {tproc 11 12 13 14} msg] $msg } {1 {wrong # args: should be "tproc x y z"}} test proc-old-30.4 {arguments and defaults} { proc tproc {x {y y-default} {z z-default}} { return [list $x $y $z] } tproc 11 12 13 } {11 12 13} test proc-old-30.5 {arguments and defaults} { proc tproc {x {y y-default} {z z-default}} { return [list $x $y $z] } tproc 11 12 } {11 12 z-default} test proc-old-30.6 {arguments and defaults} { proc tproc {x {y y-default} {z z-default}} { return [list $x $y $z] } tproc 11 } {11 y-default z-default} test proc-old-30.7 {arguments and defaults} { proc tproc {x {y y-default} {z z-default}} { return [list $x $y $z] } list [catch {tproc} msg] $msg } {1 {wrong # args: should be "tproc x ?y? ?z?"}} test proc-old-30.8 {arguments and defaults} { list [catch { proc tproc {x {y y-default} z} { return [list $x $y $z] } tproc 2 3 } msg] $msg } {1 {wrong # args: should be "tproc x ?y? z"}} test proc-old-30.9 {arguments and defaults} { proc tproc {x {y y-default} args} { return [list $x $y $args] } tproc 2 3 4 5 } {2 3 {4 5}} test proc-old-30.10 {arguments and defaults} { proc tproc {x {y y-default} args} { return [list $x $y $args] } tproc 2 3 } {2 3 {}} test proc-old-30.11 {arguments and defaults} { proc tproc {x {y y-default} args} { return [list $x $y $args] } tproc 2 } {2 y-default {}} test proc-old-30.12 {arguments and defaults} { proc tproc {x {y y-default} args} { return [list $x $y $args] } list [catch {tproc} msg] $msg } {1 {wrong # args: should be "tproc x ?y? args"}} test proc-old-4.1 {variable numbers of arguments} { proc tproc args {return $args} tproc } {} test proc-old-4.2 {variable numbers of arguments} { proc tproc args {return $args} tproc 1 2 3 4 5 6 7 8 } {1 2 3 4 5 6 7 8} test proc-old-4.3 {variable numbers of arguments} { proc tproc args {return $args} tproc 1 {2 3} {4 {5 6} {{{7}}}} 8 } {1 {2 3} {4 {5 6} {{{7}}}} 8} test proc-old-4.4 {variable numbers of arguments} { proc tproc {x y args} {return $args} tproc 1 2 3 4 5 6 7 } {3 4 5 6 7} test proc-old-4.5 {variable numbers of arguments} { proc tproc {x y args} {return $args} tproc 1 2 } {} test proc-old-4.6 {variable numbers of arguments} { proc tproc {x missing args} {return $args} list [catch {tproc 1} msg] $msg } {1 {wrong # args: should be "tproc x missing args"}} test proc-old-5.1 {error conditions} { list [catch {proc} msg] $msg } {1 {wrong # args: should be "proc name args body"}} test proc-old-5.2 {error conditions} { list [catch {proc tproc b} msg] $msg } {1 {wrong # args: should be "proc name args body"}} test proc-old-5.3 {error conditions} { list [catch {proc tproc b c d e} msg] $msg } {1 {wrong # args: should be "proc name args body"}} test proc-old-5.4 {error conditions} { list [catch {proc tproc \{xyz {return foo}} msg] $msg } {1 {unmatched open brace in list}} test proc-old-5.5 {error conditions} { list [catch {proc tproc {{} y} {return foo}} msg] $msg } {1 {procedure "tproc" has argument with no name}} test proc-old-5.6 {error conditions} { list [catch {proc tproc {{} y} {return foo}} msg] $msg } {1 {procedure "tproc" has argument with no name}} test proc-old-5.7 {error conditions} { list [catch {proc tproc {{x 1 2} y} {return foo}} msg] $msg } {1 {too many fields in argument specifier "x 1 2"}} test proc-old-5.8 {error conditions} { catch {return} } 2 test proc-old-5.9 {error conditions} { list [catch {global} msg] $msg } {1 {wrong # args: should be "global varName ?varName ...?"}} proc tproc {} { set a 22 global a } test proc-old-5.10 {error conditions} { list [catch {tproc} msg] $msg } {1 {variable "a" already exists}} test proc-old-5.11 {error conditions} { catch {rename tproc {}} catch { proc tproc {x {} z} {return foo} } list [catch {tproc 1} msg] $msg } {1 {invalid command name "tproc"}} test proc-old-5.12 {error conditions} { proc tproc {} { set a 22 error "error in procedure" return } list [catch tproc msg] $msg } {1 {error in procedure}} test proc-old-5.13 {error conditions} { proc tproc {} { set a 22 error "error in procedure" return } catch tproc msg set errorInfo } {error in procedure while executing "error "error in procedure"" (procedure "tproc" line 3) invoked from within "tproc"} test proc-old-5.14 {error conditions} { proc tproc {} { set a 22 break return } catch tproc msg set errorInfo } {invoked "break" outside of a loop (procedure "tproc" line 1) invoked from within "tproc"} test proc-old-5.15 {error conditions} { proc tproc {} { set a 22 continue return } catch tproc msg set errorInfo } {invoked "continue" outside of a loop (procedure "tproc" line 1) invoked from within "tproc"} test proc-old-5.16 {error conditions} { proc foo args { global fooMsg set fooMsg "foo was called: $args" } proc tproc {} { set x 44 trace var x u foo while {$x < 100} { error "Nested error" } } set fooMsg "foo not called" list [catch tproc msg] $msg $errorInfo $fooMsg } {1 {Nested error} {Nested error while executing "error "Nested error"" (procedure "tproc" line 5) invoked from within "tproc"} {foo was called: x {} u}} # The tests below will really only be useful when run under Purify or # some other system that can detect accesses to freed memory... test proc-old-6.1 {procedure that redefines itself} { proc tproc {} { proc tproc {} { return 44 } return 45 } tproc } 45 test proc-old-6.2 {procedure that deletes itself} { proc tproc {} { rename tproc {} return 45 } tproc } 45 proc tproc code { return -code $code abc } test proc-old-7.1 {return with special completion code} { list [catch {tproc ok} msg] $msg } {0 abc} test proc-old-7.2 {return with special completion code} { list [catch {tproc error} msg] $msg $errorInfo $errorCode } {1 abc {abc while executing "tproc error"} NONE} test proc-old-7.3 {return with special completion code} { list [catch {tproc return} msg] $msg } {2 abc} test proc-old-7.4 {return with special completion code} { list [catch {tproc break} msg] $msg } {3 abc} test proc-old-7.5 {return with special completion code} { list [catch {tproc continue} msg] $msg } {4 abc} test proc-old-7.6 {return with special completion code} { list [catch {tproc -14} msg] $msg } {-14 abc} test proc-old-7.7 {return with special completion code} { list [catch {tproc gorp} msg] $msg } {1 {bad completion code "gorp": must be ok, error, return, break, continue, or an integer}} test proc-old-7.8 {return with special completion code} { list [catch {tproc 10b} msg] $msg } {1 {bad completion code "10b": must be ok, error, return, break, continue, or an integer}} test proc-old-7.9 {return with special completion code} { proc tproc2 {} { tproc return } list [catch tproc2 msg] $msg } {0 abc} test proc-old-7.10 {return with special completion code} { proc tproc2 {} { return -code error } list [catch tproc2 msg] $msg } {1 {}} test proc-old-7.11 {return with special completion code} { proc tproc2 {} { global errorCode errorInfo catch {open _bad_file_name r} msg return -code error -errorinfo $errorInfo -errorcode $errorCode $msg } set msg [list [catch tproc2 msg] $msg $errorInfo $errorCode] regsub -all [file join {} _bad_file_name] $msg "_bad_file_name" msg normalizeMsg $msg } {1 {couldn't open "_bad_file_name": no such file or directory} {couldn't open "_bad_file_name": no such file or directory while executing "open _bad_file_name r" invoked from within "tproc2"} {posix enoent {no such file or directory}}} test proc-old-7.12 {return with special completion code} { proc tproc2 {} { global errorCode errorInfo catch {open _bad_file_name r} msg return -code error -errorcode $errorCode $msg } set msg [list [catch tproc2 msg] $msg $errorInfo $errorCode] regsub -all [file join {} _bad_file_name] $msg "_bad_file_name" msg normalizeMsg $msg } {1 {couldn't open "_bad_file_name": no such file or directory} {couldn't open "_bad_file_name": no such file or directory while executing "tproc2"} {posix enoent {no such file or directory}}} test proc-old-7.13 {return with special completion code} { proc tproc2 {} { global errorCode errorInfo catch {open _bad_file_name r} msg return -code error -errorinfo $errorInfo $msg } set msg [list [catch tproc2 msg] $msg $errorInfo $errorCode] regsub -all [file join {} _bad_file_name] $msg "_bad_file_name" msg normalizeMsg $msg } {1 {couldn't open "_bad_file_name": no such file or directory} {couldn't open "_bad_file_name": no such file or directory while executing "open _bad_file_name r" invoked from within "tproc2"} none} test proc-old-7.14 {return with special completion code} { proc tproc2 {} { global errorCode errorInfo catch {open _bad_file_name r} msg return -code error $msg } set msg [list [catch tproc2 msg] $msg $errorInfo $errorCode] regsub -all [file join {} _bad_file_name] $msg "_bad_file_name" msg normalizeMsg $msg } {1 {couldn't open "_bad_file_name": no such file or directory} {couldn't open "_bad_file_name": no such file or directory while executing "tproc2"} none} test proc-old-7.15 {return with special completion code} { list [catch {return -badOption foo message} msg] $msg } {1 {bad option "-badOption": must be -code, -errorcode, or -errorinfo}} test proc-old-8.1 {unset and undefined local arrays} { proc t1 {} { foreach v {xxx, yyy} { catch {unset $v} } set yyy(foo) bar } t1 } bar test proc-old-9.1 {empty command name} { catch {rename {} ""} proc t1 {args} { return } set v [t1] catch {$v} } 1 test proc-old-10.1 {ByteCode epoch change during recursive proc execution} { proc t1 x { set y 20 rename expr expr.old rename expr.old expr if $x then {t1 0} ;# recursive call after foo's code is invalidated return 20 } t1 1 } 20 # cleanup catch {rename t1 ""} catch {rename foo ""} ::tcltest::cleanupTests return tcl8.4.20/tests/ioUtil.test0000644003604700454610000003110011737050674014222 0ustar dgp771div# This file (ioUtil.test) tests the hookable TclStat(), TclAccess(), # and Tcl_OpenFileChannel, routines in the file generic/tclIOUtils.c. # Sourcing this file into Tcl runs the tests and generates output for # errors. No output means no errors were found. # # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import -force ::tcltest::* } ::tcltest::testConstraint testopenfilechannelproc \ [llength [info commands testopenfilechannelproc]] ::tcltest::testConstraint testaccessproc \ [llength [info commands testaccessproc]] ::tcltest::testConstraint teststatproc \ [llength [info commands teststatproc]] set unsetScript { catch {unset testStat1(size)} catch {unset testStat2(size)} catch {unset testStat3(size)} } test ioUtil-1.1 {TclStat: Check that none of the test procs are there.} {} { catch {file stat testStat1%.fil testStat1} err1 catch {file stat testStat2%.fil testStat2} err2 catch {file stat testStat3%.fil testStat3} err3 list $err1 $err2 $err3 } {{could not read "testStat1%.fil": no such file or directory} {could not read "testStat2%.fil": no such file or directory} {could not read "testStat3%.fil": no such file or directory}} test ioUtil-1.2 {TclStatInsertProc: Insert the 3 test TclStat_ procedures.} {teststatproc} { catch {teststatproc insert TclpStat} err1 teststatproc insert TestStatProc1 teststatproc insert TestStatProc2 teststatproc insert TestStatProc3 set err1 } {bad arg "insert": must be TestStatProc1, TestStatProc2, or TestStatProc3} test ioUtil-1.3 {TclStat: Use "file stat ?" to invoke each procedure.} {teststatproc} { file stat testStat2%.fil testStat2 file stat testStat1%.fil testStat1 file stat testStat3%.fil testStat3 list $testStat2(size) $testStat1(size) $testStat3(size) } {2345 1234 3456} eval $unsetScript test ioUtil-1.4 {TclStatDeleteProc: "TclpStat" function should not be deletable.} {teststatproc} { catch {teststatproc delete TclpStat} err2 set err2 } {"TclpStat": could not be deleteed} test ioUtil-1.5 {TclStatDeleteProc: Delete the 2nd TclStat procedure.} {teststatproc} { # Delete the 2nd procedure and test that it longer exists but that # the others do actually return a result. teststatproc delete TestStatProc2 file stat testStat1%.fil testStat1 catch {file stat testStat2%.fil testStat2} err3 file stat testStat3%.fil testStat3 list $testStat1(size) $err3 $testStat3(size) } {1234 {could not read "testStat2%.fil": no such file or directory} 3456} eval $unsetScript test ioUtil-1.6 {TclStatDeleteProc: Delete the 1st TclStat procedure.} {teststatproc} { # Next delete the 1st procedure and test that only the 3rd procedure # is the only one that exists. teststatproc delete TestStatProc1 catch {file stat testStat1%.fil testStat1} err4 catch {file stat testStat2%.fil testStat2} err5 file stat testStat3%.fil testStat3 list $err4 $err5 $testStat3(size) } {{could not read "testStat1%.fil": no such file or directory} {could not read "testStat2%.fil": no such file or directory} 3456} eval $unsetScript test ioUtil-1.7 {TclStatDeleteProc: Delete the 3rd procedure & verify all are gone.} {teststatproc} { # Finally delete the 3rd procedure and check that none of the # procedures exist. teststatproc delete TestStatProc3 catch {file stat testStat1%.fil testStat1} err6 catch {file stat testStat2%.fil testStat2} err7 catch {file stat testStat3%.fil testStat3} err8 list $err6 $err7 $err8 } {{could not read "testStat1%.fil": no such file or directory} {could not read "testStat2%.fil": no such file or directory} {could not read "testStat3%.fil": no such file or directory}} eval $unsetScript test ioUtil-1.8 {TclStatDeleteProc: Verify that all procs have been deleted.} {teststatproc} { # Attempt to delete all the Stat procs. again to ensure they no longer # exist and an error is returned. catch {teststatproc delete TestStatProc1} err9 catch {teststatproc delete TestStatProc2} err10 catch {teststatproc delete TestStatProc3} err11 list $err9 $err10 $err11 } {{"TestStatProc1": could not be deleteed} {"TestStatProc2": could not be deleteed} {"TestStatProc3": could not be deleteed}} eval $unsetScript test ioUtil-1.9 {TclAccess: Check that none of the test procs are there.} { catch {file exists testAccess1%.fil} err1 catch {file exists testAccess2%.fil} err2 catch {file exists testAccess3%.fil} err3 list $err1 $err2 $err3 } {0 0 0} test ioUtil-1.10 {TclAccessInsertProc: Insert the 3 test TclAccess_ procedures.} {testaccessproc} { catch {testaccessproc insert TclpAccess} err1 testaccessproc insert TestAccessProc1 testaccessproc insert TestAccessProc2 testaccessproc insert TestAccessProc3 set err1 } {bad arg "insert": must be TestAccessProc1, TestAccessProc2, or TestAccessProc3} test ioUtil-2.3 {TclAccess: Use "file access ?" to invoke each procedure.} {testaccessproc} { list [file exists testAccess2%.fil] \ [file exists testAccess1%.fil] \ [file exists testAccess3%.fil] } {1 1 1} test ioUtil-2.4 {TclAccessDeleteProc: "TclpAccess" function should not be deletable.} {testaccessproc} { catch {testaccessproc delete TclpAccess} err2 set err2 } {"TclpAccess": could not be deleteed} test ioUtil-2.5 {TclAccessDeleteProc: Delete the 2nd TclAccess procedure.} {testaccessproc} { # Delete the 2nd procedure and test that it longer exists but that # the others do actually return a result. testaccessproc delete TestAccessProc2 set res1 [file exists testAccess1%.fil] catch {file exists testAccess2%.fil} err3 set res2 [file exists testAccess3%.fil] list $res1 $err3 $res2 } {1 0 1} test ioUtil-2.6 {TclAccessDeleteProc: Delete the 1st TclAccess procedure.} {testaccessproc} { # Next delete the 1st procedure and test that only the 3rd procedure # is the only one that exists. testaccessproc delete TestAccessProc1 catch {file exists testAccess1%.fil} err4 catch {file exists testAccess2%.fil} err5 set res3 [file exists testAccess3%.fil] list $err4 $err5 $res3 } {0 0 1} test ioUtil-2.7 {TclAccessDeleteProc: Delete the 3rd procedure & verify all are gone.} {testaccessproc} { # Finally delete the 3rd procedure and check that none of the # procedures exist. testaccessproc delete TestAccessProc3 catch {file exists testAccess1%.fil} err6 catch {file exists testAccess2%.fil} err7 catch {file exists testAccess3%.fil} err8 list $err6 $err7 $err8 } {0 0 0} test ioUtil-2.8 {TclAccessDeleteProc: Verify that all procs have been deleted.} {testaccessproc} { # Attempt to delete all the Access procs. again to ensure they no longer # exist and an error is returned. catch {testaccessproc delete TestAccessProc1} err9 catch {testaccessproc delete TestAccessProc2} err10 catch {testaccessproc delete TestAccessProc3} err11 list $err9 $err10 $err11 } {{"TestAccessProc1": could not be deleteed} {"TestAccessProc2": could not be deleteed} {"TestAccessProc3": could not be deleteed}} # Some of the following tests require a writable current directory set oldpwd [pwd] cd [temporaryDirectory] test ioUtil-3.1 {TclOpenFileChannel: Check that none of the test procs are there.} {testopenfilechannelproc} { catch {eval [list file delete -force] [glob *testOpenFileChannel*]} catch {file exists testOpenFileChannel1%.fil} err1 catch {file exists testOpenFileChannel2%.fil} err2 catch {file exists testOpenFileChannel3%.fil} err3 catch {file exists __testOpenFileChannel1%__.fil} err4 catch {file exists __testOpenFileChannel2%__.fil} err5 catch {file exists __testOpenFileChannel3%__.fil} err6 list $err1 $err2 $err3 $err4 $err5 $err6 } {0 0 0 0 0 0} test ioUtil-3.2 {TclOpenFileChannelInsertProc: Insert the 3 test TclOpenFileChannel_ procedures.} {testopenfilechannelproc} { catch {testopenfilechannelproc insert TclpOpenFileChannel} err1 testopenfilechannelproc insert TestOpenFileChannelProc1 testopenfilechannelproc insert TestOpenFileChannelProc2 testopenfilechannelproc insert TestOpenFileChannelProc3 set err1 } {bad arg "insert": must be TestOpenFileChannelProc1, TestOpenFileChannelProc2, or TestOpenFileChannelProc3} test ioUtil-3.3 {TclOpenFileChannel: Use "file openfilechannel ?" to invoke each procedure.} {testopenfilechannelproc} { close [open __testOpenFileChannel1%__.fil w] close [open __testOpenFileChannel2%__.fil w] close [open __testOpenFileChannel3%__.fil w] catch { close [open testOpenFileChannel1%.fil r] close [open testOpenFileChannel2%.fil r] close [open testOpenFileChannel3%.fil r] } err file delete __testOpenFileChannel1%__.fil file delete __testOpenFileChannel2%__.fil file delete __testOpenFileChannel3%__.fil set err } {} test ioUtil-3.4 {TclOpenFileChannelDeleteProc: "TclpOpenFileChannel" function should not be deletable.} {testopenfilechannelproc} { catch {testopenfilechannelproc delete TclpOpenFileChannel} err2 set err2 } {"TclpOpenFileChannel": could not be deleteed} test ioUtil-3.5 {TclOpenFileChannelDeleteProc: Delete the 2nd TclOpenFileChannel procedure.} {testopenfilechannelproc} { # Delete the 2nd procedure and test that it longer exists but that # the others do actually return a result. testopenfilechannelproc delete TestOpenFileChannelProc2 close [open __testOpenFileChannel1%__.fil w] close [open __testOpenFileChannel3%__.fil w] catch { close [open testOpenFileChannel1%.fil r] catch {close [open testOpenFileChannel2%.fil r]} msg1 close [open testOpenFileChannel3%.fil r] } err3 file delete __testOpenFileChannel1%__.fil file delete __testOpenFileChannel3%__.fil list $err3 $msg1 } {{} {couldn't open "testOpenFileChannel2%.fil": no such file or directory}} test ioUtil-3.6 {TclOpenFileChannelDeleteProc: Delete the 1st TclOpenFileChannel procedure.} {testopenfilechannelproc} { # Next delete the 1st procedure and test that only the 3rd procedure # is the only one that exists. testopenfilechannelproc delete TestOpenFileChannelProc1 close [open __testOpenFileChannel3%__.fil w] catch { catch {close [open testOpenFileChannel1%.fil r]} msg2 catch {close [open testOpenFileChannel2%.fil r]} msg3 close [open testOpenFileChannel3%.fil r] } err4 file delete __testOpenFileChannel3%__.fil list $err4 $msg2 $msg3 } [list {} \ {couldn't open "testOpenFileChannel1%.fil": no such file or directory}\ {couldn't open "testOpenFileChannel2%.fil": no such file or directory}] test ioUtil-3.7 {TclOpenFileChannelDeleteProc: Delete the 3rd procedure & verify all are gone.} {testopenfilechannelproc} { # Finally delete the 3rd procedure and check that none of the # procedures exist. testopenfilechannelproc delete TestOpenFileChannelProc3 catch { catch {close [open testOpenFileChannel1%.fil r]} msg4 catch {close [open testOpenFileChannel2%.fil r]} msg5 catch {close [open testOpenFileChannel3%.fil r]} msg6 } err5 list $err5 $msg4 $msg5 $msg6 } [list 1 \ {couldn't open "testOpenFileChannel1%.fil": no such file or directory}\ {couldn't open "testOpenFileChannel2%.fil": no such file or directory}\ {couldn't open "testOpenFileChannel3%.fil": no such file or directory}] test ioUtil-3.8 {TclOpenFileChannelDeleteProc: Verify that all procs have been deleted.} {testopenfilechannelproc} { # Attempt to delete all the OpenFileChannel procs. again to ensure they no # longer exist and an error is returned. catch {testopenfilechannelproc delete TestOpenFileChannelProc1} err9 catch {testopenfilechannelproc delete TestOpenFileChannelProc2} err10 catch {testopenfilechannelproc delete TestOpenFileChannelProc3} err11 list $err9 $err10 $err11 } {{"TestOpenFileChannelProc1": could not be deleteed} {"TestOpenFileChannelProc2": could not be deleteed} {"TestOpenFileChannelProc3": could not be deleteed}} test ioUtil-4.1 {open ... a+ must not use O_APPEND: Bug 1773127} -setup { set f [tcltest::makeFile {} ioutil41.tmp] set fid [open $f w] puts -nonewline $fid 123 close $fid } -body { set fid [open $f a+] puts -nonewline $fid 456 seek $fid 2 set d [read $fid 2] seek $fid 4 puts -nonewline $fid x close $fid set fid [open $f r] append d [read $fid] close $fid return $d } -cleanup { tcltest::removeFile $f } -result 341234x6 cd $oldpwd # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/incr-old.test0000644003604700454610000000560611737050674014500 0ustar dgp771div# Commands covered: incr # # This file contains the original set of tests for Tcl's incr command. # Since the incr command is now compiled, a new set of tests covering # the new implementation is in the file "incr.test". Sourcing this file # into Tcl runs the tests and generates output for errors. # No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994-1996 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } catch {unset x} test incr-old-1.1 {basic incr operation} { set x 23 list [incr x] $x } {24 24} test incr-old-1.2 {basic incr operation} { set x 106 list [incr x -5] $x } {101 101} test incr-old-1.3 {basic incr operation} { set x " -106" list [incr x 1] $x } {-105 -105} test incr-old-1.4 {basic incr operation} { set x " +106" list [incr x 1] $x } {107 107} test incr-old-2.1 {incr errors} { list [catch incr msg] $msg } {1 {wrong # args: should be "incr varName ?increment?"}} test incr-old-2.2 {incr errors} { list [catch {incr a b c} msg] $msg } {1 {wrong # args: should be "incr varName ?increment?"}} test incr-old-2.3 {incr errors} { catch {unset x} list [catch {incr x} msg] $msg $errorInfo } {1 {can't read "x": no such variable} {can't read "x": no such variable (reading value of variable to increment) invoked from within "incr x"}} test incr-old-2.4 {incr errors} { set x abc list [catch {incr x} msg] $msg $errorInfo } {1 {expected integer but got "abc"} {expected integer but got "abc" while executing "incr x"}} test incr-old-2.5 {incr errors} { set x 123 list [catch {incr x 1a} msg] $msg $errorInfo } {1 {expected integer but got "1a"} {expected integer but got "1a" (reading increment) invoked from within "incr x 1a"}} test incr-old-2.6 {incr errors} { proc readonly args {error "variable is read-only"} set x 123 trace var x w readonly list [catch {incr x 1} msg] $msg $errorInfo } {1 {can't set "x": variable is read-only} {can't set "x": variable is read-only while executing "incr x 1"}} catch {unset x} test incr-old-2.7 {incr errors} { set x - list [catch {incr x 1} msg] $msg } {1 {expected integer but got "-"}} test incr-old-2.8 {incr errors} { set x { - } list [catch {incr x 1} msg] $msg } {1 {expected integer but got " - "}} test incr-old-2.9 {incr errors} { set x + list [catch {incr x 1} msg] $msg } {1 {expected integer but got "+"}} test incr-old-2.10 {incr errors} { set x {20 x} list [catch {incr x 1} msg] $msg } {1 {expected integer but got "20 x"}} # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/execute.test0000644003604700454610000007152411737050674014435 0ustar dgp771div# This file contains tests for the tclExecute.c source file. Tests appear # in the same order as the C code that they test. The set of tests is # currently incomplete since it currently includes only new tests for # code changed for the addition of Tcl namespaces. Other execution- # related tests appear in several other test files including # namespace.test, basic.test, eval.test, for.test, etc. # # Sourcing this file into Tcl runs the tests and generates output for # errors. No output means no errors were found. # # Copyright (c) 1997 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import -force ::tcltest::* } catch {eval namespace delete [namespace children :: test_ns_*]} catch {rename foo ""} catch {unset x} catch {unset y} catch {unset msg} ::tcltest::testConstraint testobj \ [expr {[info commands testobj] != {} \ && [info commands testdoubleobj] != {} \ && [info commands teststringobj] != {} \ && [info commands testobj] != {}}] ::tcltest::testConstraint longIs32bit \ [expr {int(0x80000000) < 0}] ::tcltest::testConstraint testexprlongobj \ [llength [info commands testexprlongobj]] # Tests for the omnibus TclExecuteByteCode function: # INST_DONE not tested # INST_PUSH1 not tested # INST_PUSH4 not tested # INST_POP not tested # INST_DUP not tested # INST_CONCAT1 not tested # INST_INVOKE_STK4 not tested # INST_INVOKE_STK1 not tested # INST_EVAL_STK not tested # INST_EXPR_STK not tested # INST_LOAD_SCALAR1 test execute-1.1 {TclExecuteByteCode, INST_LOAD_SCALAR1, small opnd} { proc foo {} { set x 1 return $x } foo } 1 test execute-1.2 {TclExecuteByteCode, INST_LOAD_SCALAR1, large opnd} { # Bug: 2243 set body {} for {set i 0} {$i < 129} {incr i} { append body "set x$i x\n" } append body { set y 1 return $y } proc foo {} $body foo } 1 test execute-1.3 {TclExecuteByteCode, INST_LOAD_SCALAR1, error} { proc foo {} { set x 1 unset x return $x } list [catch {foo} msg] $msg } {1 {can't read "x": no such variable}} # INST_LOAD_SCALAR4 test execute-2.1 {TclExecuteByteCode, INST_LOAD_SCALAR4, simple case} { set body {} for {set i 0} {$i < 256} {incr i} { append body "set x$i x\n" } append body { set y 1 return $y } proc foo {} $body foo } 1 test execute-2.2 {TclExecuteByteCode, INST_LOAD_SCALAR4, error} { set body {} for {set i 0} {$i < 256} {incr i} { append body "set x$i x\n" } append body { set y 1 unset y return $y } proc foo {} $body list [catch {foo} msg] $msg } {1 {can't read "y": no such variable}} # INST_LOAD_SCALAR_STK not tested # INST_LOAD_ARRAY4 not tested # INST_LOAD_ARRAY1 not tested # INST_LOAD_ARRAY_STK not tested # INST_LOAD_STK not tested # INST_STORE_SCALAR4 not tested # INST_STORE_SCALAR1 not tested # INST_STORE_SCALAR_STK not tested # INST_STORE_ARRAY4 not tested # INST_STORE_ARRAY1 not tested # INST_STORE_ARRAY_STK not tested # INST_STORE_STK not tested # INST_INCR_SCALAR1 not tested # INST_INCR_SCALAR_STK not tested # INST_INCR_STK not tested # INST_INCR_ARRAY1 not tested # INST_INCR_ARRAY_STK not tested # INST_INCR_SCALAR1_IMM not tested # INST_INCR_SCALAR_STK_IMM not tested # INST_INCR_STK_IMM not tested # INST_INCR_ARRAY1_IMM not tested # INST_INCR_ARRAY_STK_IMM not tested # INST_JUMP1 not tested # INST_JUMP4 not tested # INST_JUMP_TRUE4 not tested # INST_JUMP_TRUE1 not tested # INST_JUMP_FALSE4 not tested # INST_JUMP_FALSE1 not tested # INST_LOR not tested # INST_LAND not tested # INST_EQ not tested # INST_NEQ not tested # INST_LT not tested # INST_GT not tested # INST_LE not tested # INST_GE not tested # INST_MOD not tested # INST_LSHIFT not tested # INST_RSHIFT not tested # INST_BITOR not tested # INST_BITXOR not tested # INST_BITAND not tested # INST_ADD is partially tested: test execute-3.1 {TclExecuteByteCode, INST_ADD, op1 is int} {testobj} { set x [testintobj set 0 1] expr {$x + 1} } 2 test execute-3.2 {TclExecuteByteCode, INST_ADD, op1 is double} {testobj} { set x [testdoubleobj set 0 1] expr {$x + 1} } 2.0 test execute-3.3 {TclExecuteByteCode, INST_ADD, op1 is double with string} {testobj} { set x [testintobj set 0 1] testobj convert 0 double expr {$x + 1} } 2 test execute-3.4 {TclExecuteByteCode, INST_ADD, op1 is string int} {testobj} { set x [teststringobj set 0 1] expr {$x + 1} } 2 test execute-3.5 {TclExecuteByteCode, INST_ADD, op1 is string double} {testobj} { set x [teststringobj set 0 1.0] expr {$x + 1} } 2.0 test execute-3.6 {TclExecuteByteCode, INST_ADD, op1 is non-numeric} {testobj} { set x [teststringobj set 0 foo] list [catch {expr {$x + 1}} msg] $msg } {1 {can't use non-numeric string as operand of "+"}} test execute-3.7 {TclExecuteByteCode, INST_ADD, op2 is int} {testobj} { set x [testintobj set 0 1] expr {1 + $x} } 2 test execute-3.8 {TclExecuteByteCode, INST_ADD, op2 is double} {testobj} { set x [testdoubleobj set 0 1] expr {1 + $x} } 2.0 test execute-3.9 {TclExecuteByteCode, INST_ADD, op2 is double with string} {testobj} { set x [testintobj set 0 1] testobj convert 0 double expr {1 + $x} } 2 test execute-3.10 {TclExecuteByteCode, INST_ADD, op2 is string int} {testobj} { set x [teststringobj set 0 1] expr {1 + $x} } 2 test execute-3.11 {TclExecuteByteCode, INST_ADD, op2 is string double} {testobj} { set x [teststringobj set 0 1.0] expr {1 + $x} } 2.0 test execute-3.12 {TclExecuteByteCode, INST_ADD, op2 is non-numeric} {testobj} { set x [teststringobj set 0 foo] list [catch {expr {1 + $x}} msg] $msg } {1 {can't use non-numeric string as operand of "+"}} # INST_SUB is partially tested: test execute-3.13 {TclExecuteByteCode, INST_SUB, op1 is int} {testobj} { set x [testintobj set 0 1] expr {$x - 1} } 0 test execute-3.14 {TclExecuteByteCode, INST_SUB, op1 is double} {testobj} { set x [testdoubleobj set 0 1] expr {$x - 1} } 0.0 test execute-3.15 {TclExecuteByteCode, INST_SUB, op1 is double with string} {testobj} { set x [testintobj set 0 1] testobj convert 0 double expr {$x - 1} } 0 test execute-3.16 {TclExecuteByteCode, INST_SUB, op1 is string int} {testobj} { set x [teststringobj set 0 1] expr {$x - 1} } 0 test execute-3.17 {TclExecuteByteCode, INST_SUB, op1 is string double} {testobj} { set x [teststringobj set 0 1.0] expr {$x - 1} } 0.0 test execute-3.18 {TclExecuteByteCode, INST_SUB, op1 is non-numeric} {testobj} { set x [teststringobj set 0 foo] list [catch {expr {$x - 1}} msg] $msg } {1 {can't use non-numeric string as operand of "-"}} test execute-3.19 {TclExecuteByteCode, INST_SUB, op2 is int} {testobj} { set x [testintobj set 0 1] expr {1 - $x} } 0 test execute-3.20 {TclExecuteByteCode, INST_SUB, op2 is double} {testobj} { set x [testdoubleobj set 0 1] expr {1 - $x} } 0.0 test execute-3.21 {TclExecuteByteCode, INST_SUB, op2 is double with string} {testobj} { set x [testintobj set 0 1] testobj convert 0 double expr {1 - $x} } 0 test execute-3.22 {TclExecuteByteCode, INST_SUB, op2 is string int} {testobj} { set x [teststringobj set 0 1] expr {1 - $x} } 0 test execute-3.23 {TclExecuteByteCode, INST_SUB, op2 is string double} {testobj} { set x [teststringobj set 0 1.0] expr {1 - $x} } 0.0 test execute-3.24 {TclExecuteByteCode, INST_SUB, op2 is non-numeric} {testobj} { set x [teststringobj set 0 foo] list [catch {expr {1 - $x}} msg] $msg } {1 {can't use non-numeric string as operand of "-"}} # INST_MULT is partially tested: test execute-3.25 {TclExecuteByteCode, INST_MULT, op1 is int} {testobj} { set x [testintobj set 1 1] expr {$x * 1} } 1 test execute-3.26 {TclExecuteByteCode, INST_MULT, op1 is double} {testobj} { set x [testdoubleobj set 1 2.0] expr {$x * 1} } 2.0 test execute-3.27 {TclExecuteByteCode, INST_MULT, op1 is double with string} {testobj} { set x [testintobj set 1 2] testobj convert 1 double expr {$x * 1} } 2 test execute-3.28 {TclExecuteByteCode, INST_MULT, op1 is string int} {testobj} { set x [teststringobj set 1 1] expr {$x * 1} } 1 test execute-3.29 {TclExecuteByteCode, INST_MULT, op1 is string double} {testobj} { set x [teststringobj set 1 1.0] expr {$x * 1} } 1.0 test execute-3.30 {TclExecuteByteCode, INST_MULT, op1 is non-numeric} {testobj} { set x [teststringobj set 1 foo] list [catch {expr {$x * 1}} msg] $msg } {1 {can't use non-numeric string as operand of "*"}} test execute-3.31 {TclExecuteByteCode, INST_MULT, op2 is int} {testobj} { set x [testintobj set 1 1] expr {1 * $x} } 1 test execute-3.32 {TclExecuteByteCode, INST_MULT, op2 is double} {testobj} { set x [testdoubleobj set 1 2.0] expr {1 * $x} } 2.0 test execute-3.33 {TclExecuteByteCode, INST_MULT, op2 is double with string} {testobj} { set x [testintobj set 1 2] testobj convert 1 double expr {1 * $x} } 2 test execute-3.34 {TclExecuteByteCode, INST_MULT, op2 is string int} {testobj} { set x [teststringobj set 1 1] expr {1 * $x} } 1 test execute-3.35 {TclExecuteByteCode, INST_MULT, op2 is string double} {testobj} { set x [teststringobj set 1 1.0] expr {1 * $x} } 1.0 test execute-3.36 {TclExecuteByteCode, INST_MULT, op2 is non-numeric} {testobj} { set x [teststringobj set 1 foo] list [catch {expr {1 * $x}} msg] $msg } {1 {can't use non-numeric string as operand of "*"}} # INST_DIV is partially tested: test execute-3.37 {TclExecuteByteCode, INST_DIV, op1 is int} {testobj} { set x [testintobj set 1 1] expr {$x / 1} } 1 test execute-3.38 {TclExecuteByteCode, INST_DIV, op1 is double} {testobj} { set x [testdoubleobj set 1 2.0] expr {$x / 1} } 2.0 test execute-3.39 {TclExecuteByteCode, INST_DIV, op1 is double with string} {testobj} { set x [testintobj set 1 2] testobj convert 1 double expr {$x / 1} } 2 test execute-3.40 {TclExecuteByteCode, INST_DIV, op1 is string int} {testobj} { set x [teststringobj set 1 1] expr {$x / 1} } 1 test execute-3.41 {TclExecuteByteCode, INST_DIV, op1 is string double} {testobj} { set x [teststringobj set 1 1.0] expr {$x / 1} } 1.0 test execute-3.42 {TclExecuteByteCode, INST_DIV, op1 is non-numeric} {testobj} { set x [teststringobj set 1 foo] list [catch {expr {$x / 1}} msg] $msg } {1 {can't use non-numeric string as operand of "/"}} test execute-3.43 {TclExecuteByteCode, INST_DIV, op2 is int} {testobj} { set x [testintobj set 1 1] expr {2 / $x} } 2 test execute-3.44 {TclExecuteByteCode, INST_DIV, op2 is double} {testobj} { set x [testdoubleobj set 1 1.0] expr {2 / $x} } 2.0 test execute-3.45 {TclExecuteByteCode, INST_DIV, op2 is double with string} {testobj} { set x [testintobj set 1 1] testobj convert 1 double expr {2 / $x} } 2 test execute-3.46 {TclExecuteByteCode, INST_DIV, op2 is string int} {testobj} { set x [teststringobj set 1 1] expr {2 / $x} } 2 test execute-3.47 {TclExecuteByteCode, INST_DIV, op2 is string double} {testobj} { set x [teststringobj set 1 1.0] expr {2 / $x} } 2.0 test execute-3.48 {TclExecuteByteCode, INST_DIV, op2 is non-numeric} {testobj} { set x [teststringobj set 1 foo] list [catch {expr {1 / $x}} msg] $msg } {1 {can't use non-numeric string as operand of "/"}} # INST_UPLUS is partially tested: test execute-3.49 {TclExecuteByteCode, INST_UPLUS, op is int} {testobj} { set x [testintobj set 1 1] expr {+ $x} } 1 test execute-3.50 {TclExecuteByteCode, INST_UPLUS, op is double} {testobj} { set x [testdoubleobj set 1 1.0] expr {+ $x} } 1.0 test execute-3.51 {TclExecuteByteCode, INST_UPLUS, op is double with string} {testobj} { set x [testintobj set 1 1] testobj convert 1 double expr {+ $x} } 1 test execute-3.52 {TclExecuteByteCode, INST_UPLUS, op is string int} {testobj} { set x [teststringobj set 1 1] expr {+ $x} } 1 test execute-3.53 {TclExecuteByteCode, INST_UPLUS, op is string double} {testobj} { set x [teststringobj set 1 1.0] expr {+ $x} } 1.0 test execute-3.54 {TclExecuteByteCode, INST_UPLUS, op is non-numeric} {testobj} { set x [teststringobj set 1 foo] list [catch {expr {+ $x}} msg] $msg } {1 {can't use non-numeric string as operand of "+"}} # INST_UMINUS is partially tested: test execute-3.55 {TclExecuteByteCode, INST_UMINUS, op is int} {testobj} { set x [testintobj set 1 1] expr {- $x} } -1 test execute-3.56 {TclExecuteByteCode, INST_UMINUS, op is double} {testobj} { set x [testdoubleobj set 1 1.0] expr {- $x} } -1.0 test execute-3.57 {TclExecuteByteCode, INST_UMINUS, op is double with string} {testobj} { set x [testintobj set 1 1] testobj convert 1 double expr {- $x} } -1 test execute-3.58 {TclExecuteByteCode, INST_UMINUS, op is string int} {testobj} { set x [teststringobj set 1 1] expr {- $x} } -1 test execute-3.59 {TclExecuteByteCode, INST_UMINUS, op is string double} {testobj} { set x [teststringobj set 1 1.0] expr {- $x} } -1.0 test execute-3.60 {TclExecuteByteCode, INST_UMINUS, op is non-numeric} {testobj} { set x [teststringobj set 1 foo] list [catch {expr {- $x}} msg] $msg } {1 {can't use non-numeric string as operand of "-"}} # INST_LNOT is partially tested: test execute-3.61 {TclExecuteByteCode, INST_LNOT, op is int} {testobj} { set x [testintobj set 1 2] expr {! $x} } 0 test execute-3.62 {TclExecuteByteCode, INST_LNOT, op is int} {testobj} { set x [testintobj set 1 0] expr {! $x} } 1 test execute-3.63 {TclExecuteByteCode, INST_LNOT, op is double} {testobj} { set x [testdoubleobj set 1 1.0] expr {! $x} } 0 test execute-3.64 {TclExecuteByteCode, INST_LNOT, op is double} {testobj} { set x [testdoubleobj set 1 0.0] expr {! $x} } 1 test execute-3.65 {TclExecuteByteCode, INST_LNOT, op is double with string} {testobj} { set x [testintobj set 1 1] testobj convert 1 double expr {! $x} } 0 test execute-3.66 {TclExecuteByteCode, INST_LNOT, op is double with string} {testobj} { set x [testintobj set 1 0] testobj convert 1 double expr {! $x} } 1 test execute-3.67 {TclExecuteByteCode, INST_LNOT, op is string int} {testobj} { set x [teststringobj set 1 1] expr {! $x} } 0 test execute-3.68 {TclExecuteByteCode, INST_LNOT, op is string int} {testobj} { set x [teststringobj set 1 0] expr {! $x} } 1 test execute-3.69 {TclExecuteByteCode, INST_LNOT, op is string double} {testobj} { set x [teststringobj set 1 1.0] expr {! $x} } 0 test execute-3.70 {TclExecuteByteCode, INST_LNOT, op is string double} {testobj} { set x [teststringobj set 1 0.0] expr {! $x} } 1 test execute-3.71 {TclExecuteByteCode, INST_LNOT, op is non-numeric} {testobj} { set x [teststringobj set 1 foo] list [catch {expr {! $x}} msg] $msg } {1 {can't use non-numeric string as operand of "!"}} # INST_BITNOT not tested # INST_CALL_BUILTIN_FUNC1 not tested # INST_CALL_FUNC1 not tested # INST_TRY_CVT_TO_NUMERIC is partially tested: test execute-3.72 {TclExecuteByteCode, INST_TRY_CVT_TO_NUMERIC, op is int} {testobj} { set x [testintobj set 1 1] expr {$x} } 1 test execute-3.73 {TclExecuteByteCode, INST_TRY_CVT_TO_NUMERIC, op is double} {testobj} { set x [testdoubleobj set 1 1.0] expr {$x} } 1.0 test execute-3.74 {TclExecuteByteCode, INST_TRY_CVT_TO_NUMERIC, op is double with string} {testobj} { set x [testintobj set 1 1] testobj convert 1 double expr {$x} } 1 test execute-3.75 {TclExecuteByteCode, INST_TRY_CVT_TO_NUMERIC, op is string int} {testobj} { set x [teststringobj set 1 1] expr {$x} } 1 test execute-3.76 {TclExecuteByteCode, INST_TRY_CVT_TO_NUMERIC, op is string double} {testobj} { set x [teststringobj set 1 1.0] expr {$x} } 1.0 test execute-3.77 {TclExecuteByteCode, INST_TRY_CVT_TO_NUMERIC, op is non-numeric} {testobj} { set x [teststringobj set 1 foo] expr {$x} } foo # INST_BREAK not tested # INST_CONTINUE not tested # INST_FOREACH_START4 not tested # INST_FOREACH_STEP4 not tested # INST_BEGIN_CATCH4 not tested # INST_END_CATCH not tested # INST_PUSH_RESULT not tested # INST_PUSH_RETURN_CODE not tested test execute-4.1 {Tcl_GetCommandFromObj, convert to tclCmdNameType} { catch {eval namespace delete [namespace children :: test_ns_*]} catch {unset x} catch {unset y} namespace eval test_ns_1 { namespace export cmd1 proc cmd1 {args} {return "cmd1: $args"} proc cmd2 {args} {return "cmd2: $args"} } namespace eval test_ns_1::test_ns_2 { namespace import ::test_ns_1::* } set x "test_ns_1::" set y "test_ns_2::" list [namespace which -command ${x}${y}cmd1] \ [catch {namespace which -command ${x}${y}cmd2} msg] $msg \ [catch {namespace which -command ${x}${y}:cmd2} msg] $msg } {::test_ns_1::test_ns_2::cmd1 0 {} 0 {}} test execute-4.2 {Tcl_GetCommandFromObj, check if cached tclCmdNameType is invalid} { catch {eval namespace delete [namespace children :: test_ns_*]} catch {rename foo ""} catch {unset l} proc foo {} { return "global foo" } namespace eval test_ns_1 { proc whichFoo {} { return [namespace which -command foo] } } set l "" lappend l [test_ns_1::whichFoo] namespace eval test_ns_1 { proc foo {} { return "namespace foo" } } lappend l [test_ns_1::whichFoo] set l } {::foo ::test_ns_1::foo} test execute-4.3 {Tcl_GetCommandFromObj, command never found} { catch {eval namespace delete [namespace children :: test_ns_*]} catch {rename foo ""} namespace eval test_ns_1 { proc foo {} { return "namespace foo" } } namespace eval test_ns_1 { proc foo {} { return "namespace foo" } } list [namespace eval test_ns_1 {namespace which -command foo}] \ [rename test_ns_1::foo ""] \ [catch {namespace eval test_ns_1 {namespace which -command foo}} msg] $msg } {::test_ns_1::foo {} 0 {}} test execute-5.1 {SetCmdNameFromAny, set cmd name to empty heap string if NULL} { catch {eval namespace delete [namespace children :: test_ns_*]} catch {unset l} proc {} {} {return {}} {} set l {} lindex {} 0 {} } {} test execute-6.1 {UpdateStringOfCmdName: called for duplicate of empty cmdName object} { proc {} {} {} proc { } {} {} proc p {} { set x {} $x append x { } $x } p } {} test execute-6.2 {Evaluate an expression in a variable; compile the first time, do not the second} { set w {3*5} proc a {obj} {expr $obj} set res "[a $w]:[a $w]" } {15:15} test execute-6.3 {Tcl_ExprObj: don't use cached script bytecode [Bug 1899164]} -setup { proc 0+0 {} {return SCRIPT} } -body { set e { 0+0 } if 1 $e if 1 {expr $e} } -cleanup { rename 0+0 {} } -result 0 test execute-6.4 {TclCompEvalObj: don't use cached expr bytecode [Bug 1899164]} -setup { proc 0+0 {} {return SCRIPT} } -body { set e { 0+0 } if 1 {expr $e} if 1 $e } -cleanup { rename 0+0 {} } -result SCRIPT test execute-6.5 {TclCompEvalObj: bytecode epoch validation} { set script { llength {} } set result {} lappend result [if 1 $script] set origName [namespace which llength] rename $origName llength.orig proc $origName {args} {return AHA!} lappend result [if 1 $script] rename $origName {} rename llength.orig $origName set result } {0 AHA!} test execute-6.6 {TclCompEvalObj: proc-body bytecode invalid for script} { proc foo {} {set a 1} set a untouched set result {} lappend result [foo] $a lappend result [if 1 [info body foo]] $a rename foo {} set result } {1 untouched 1 1} test execute-6.7 {TclCompEvalObj: bytecode context validation} { set script { llength {} } namespace eval foo { proc llength {args} {return AHA!} } set result {} lappend result [if 1 $script] lappend result [namespace eval foo $script] namespace delete foo set result } {0 AHA!} test execute-6.8 {TclCompEvalObj: bytecode name resolution epoch validation} { set script { llength {} } set result {} lappend result [namespace eval foo $script] namespace eval foo { proc llength {args} {return AHA!} } lappend result [namespace eval foo $script] namespace delete foo set result } {0 AHA!} test execute-6.9 {TclCompEvalObj: bytecode interp validation} { set script { llength {} } interp create slave slave eval {proc llength args {return AHA!}} set result {} lappend result [if 1 $script] lappend result [slave eval $script] interp delete slave set result } {0 AHA!} test execute-6.10 {TclCompEvalObj: bytecode interp validation} { set script { llength {} } interp create slave set result {} lappend result [slave eval $script] interp delete slave interp create slave lappend result [slave eval $script] interp delete slave set result } {0 0} test execute-6.11 {Tcl_ExprObj: exprcode interp validation} testexprlongobj { set e { [llength {}]+1 } set result {} interp create slave load {} Tcltest slave interp alias {} e slave testexprlongobj lappend result [e $e] interp delete slave interp create slave load {} Tcltest slave interp alias {} e slave testexprlongobj lappend result [e $e] interp delete slave set result } {{This is a result: 1} {This is a result: 1}} test execute-6.12 {Tcl_ExprObj: exprcode interp validation} { set e { [llength {}]+1 } set result {} interp create slave interp alias {} e slave expr lappend result [e $e] interp delete slave interp create slave interp alias {} e slave expr lappend result [e $e] interp delete slave set result } {1 1} test execute-6.13 {Tcl_ExprObj: exprcode epoch validation} { set e { [llength {}]+1 } set result {} lappend result [expr $e] set origName [namespace which llength] rename $origName llength.orig proc $origName {args} {return 1} lappend result [expr $e] rename $origName {} rename llength.orig $origName set result } {1 2} test execute-6.14 {Tcl_ExprObj: exprcode context validation} { set e { [llength {}]+1 } namespace eval foo { proc llength {args} {return 1} } set result {} lappend result [expr $e] lappend result [namespace eval foo {expr $e}] namespace delete foo set result } {1 2} test execute-6.15 {Tcl_ExprObj: exprcode name resolution epoch validation} { set e { [llength {}]+1 } set result {} lappend result [namespace eval foo {expr $e}] namespace eval foo { proc llength {args} {return 1} } lappend result [namespace eval foo {expr $e}] namespace delete foo set result } {1 2} test execute-6.16 {Tcl_ExprObj: exprcode interp validation} { set e { [llength {}]+1 } interp create slave interp alias {} e slave expr slave eval {proc llength args {return 1}} set result {} lappend result [expr $e] lappend result [e $e] interp delete slave set result } {1 2} test execute-6.17 {Tcl_ExprObj: exprcode context validation} { set e { $v } proc foo e {set v 0; expr $e} proc bar e {set v 1; expr $e} set result {} lappend result [foo $e] lappend result [bar $e] rename foo {} rename bar {} set result } {0 1} test execute-6.18 {Tcl_ExprObj: exprcode context validation} { set e { [llength $v] } proc foo e {set v {}; expr $e} proc bar e {set v v; expr $e} set result {} lappend result [foo $e] lappend result [bar $e] rename foo {} rename bar {} set result } {0 1} test execute-7.0 {Wide int handling in INST_JUMP_FALSE/LAND} {longIs32bit} { set x 0x100000000 expr {$x && 1} } 1 test execute-7.1 {Wide int handling in INST_JUMP_FALSE/LAND} {longIs32bit} { expr {0x100000000 && 1} } 1 test execute-7.2 {Wide int handling in INST_JUMP_FALSE/LAND} {longIs32bit} { expr {1 && 0x100000000} } 1 test execute-7.3 {Wide int handling in INST_JUMP_FALSE/LAND} {longIs32bit} { expr {wide(0x100000000) && 1} } 1 test execute-7.4 {Wide int handling in INST_JUMP_FALSE/LAND} {longIs32bit} { expr {1 && wide(0x100000000)} } 1 test execute-7.5 {Wide int handling in INST_EQ} {longIs32bit} { expr {4 == (wide(1)+wide(3))} } 1 test execute-7.6 {Wide int handling in INST_EQ and [incr]} {longIs32bit} { set x 399999999999 expr {400000000000 == [incr x]} } 1 # wide ints have more bits of precision than doubles, but we convert anyway test execute-7.7 {Wide int handling in INST_EQ and [incr]} {longIs32bit} { set x [expr {wide(1)<<62}] set y [expr {$x+1}] expr {double($x) == double($y)} } 1 test execute-7.8 {Wide int conversions can change sign} {longIs32bit} { set x 0x80000000 expr {int($x) < wide($x)} } 1 test execute-7.9 {Wide int handling in INST_MOD} {longIs32bit} { expr {(wide(1)<<60) % ((wide(47)<<45)-1)} } 316659348800185 test execute-7.10 {Wide int handling in INST_MOD} {longIs32bit} { expr {((wide(1)<<60)-1) % 0x400000000} } 17179869183 test execute-7.11 {Wide int handling in INST_LSHIFT} {longIs32bit} { expr wide(42)<<30 } 45097156608 test execute-7.12 {Wide int handling in INST_LSHIFT} {longIs32bit} { expr 12345678901<<3 } 98765431208 test execute-7.13 {Wide int handling in INST_RSHIFT} {longIs32bit} { expr 0x543210febcda9876>>7 } 47397893236700464 test execute-7.14 {Wide int handling in INST_RSHIFT} {longIs32bit} { expr 0x9876543210febcda>>7 } -58286587177206407 test execute-7.15 {Wide int handling in INST_BITOR} {longIs32bit} { expr 0x9876543210febcda | 0x543210febcda9876 } -2560765885044310786 test execute-7.16 {Wide int handling in INST_BITXOR} {longIs32bit} { expr 0x9876543210febcda ^ 0x543210febcda9876 } -3727778945703861076 test execute-7.17 {Wide int handling in INST_BITAND} {longIs32bit} { expr 0x9876543210febcda & 0x543210febcda9876 } 1167013060659550290 test execute-7.18 {Wide int handling in INST_ADD} {longIs32bit} { expr wide(0x7fffffff)+wide(0x7fffffff) } 4294967294 test execute-7.19 {Wide int handling in INST_ADD} {longIs32bit} { expr 0x7fffffff+wide(0x7fffffff) } 4294967294 test execute-7.20 {Wide int handling in INST_ADD} {longIs32bit} { expr wide(0x7fffffff)+0x7fffffff } 4294967294 test execute-7.21 {Wide int handling in INST_ADD} {longIs32bit} { expr double(0x7fffffff)+wide(0x7fffffff) } 4294967294.0 test execute-7.22 {Wide int handling in INST_ADD} {longIs32bit} { expr wide(0x7fffffff)+double(0x7fffffff) } 4294967294.0 test execute-7.23 {Wide int handling in INST_SUB} {longIs32bit} { expr 0x123456789a-0x20406080a } 69530054800 test execute-7.24 {Wide int handling in INST_MULT} {longIs32bit} { expr 0x123456789a*193 } 15090186251290 test execute-7.25 {Wide int handling in INST_DIV} {longIs32bit} { expr 0x123456789a/193 } 405116546 test execute-7.26 {Wide int handling in INST_UPLUS} {longIs32bit} { set x 0x123456871234568 expr {+ $x} } 81985533099853160 test execute-7.27 {Wide int handling in INST_UMINUS} {longIs32bit} { set x 0x123456871234568 expr {- $x} } -81985533099853160 test execute-7.28 {Wide int handling in INST_LNOT} {longIs32bit} { set x 0x123456871234568 expr {! $x} } 0 test execute-7.29 {Wide int handling in INST_BITNOT} {longIs32bit} { set x 0x123456871234568 expr {~ $x} } -81985533099853161 test execute-7.30 {Wide int handling in function call} {longIs32bit} { set x 0x12345687123456 incr x expr {log($x) == log(double($x))} } 1 test execute-7.31 {Wide int handling in abs()} {longIs32bit} { set x 0xa23456871234568 incr x set y 0x123456871234568 concat [expr {abs($x)}] [expr {abs($y)}] } {730503879441204585 81985533099853160} test execute-7.32 {Wide int handling} {longIs32bit} { expr {1024 * 1024 * 1024 * 1024} } 0 test execute-7.33 {Wide int handling} {longIs32bit} { expr {0x1 * 1024 * 1024 * 1024 * 1024} } 0 test execute-7.34 {Wide int handling} {longIs32bit} { expr {wide(0x1) * 1024 * 1024 * 1024 * 1024} } 1099511627776 test execute-8.1 {Stack protection} -setup { # If [Bug #804681] has not been properly # taken care of, this should segfault proc whatever args {llength $args} trace add variable ::errorInfo {write unset} whatever } -body { expr {1+9/0} } -cleanup { trace remove variable ::errorInfo {write unset} whatever rename whatever {} } -returnCodes error -match glob -result * test execute-10.2 {Bug 2802881} -setup { interp create slave } -body { # If [Bug 2802881] is not fixed, this will segfault slave eval { trace add variable ::errorInfo write {expr {$foo} ;#} proc demo {} {a {}{}} demo } } -cleanup { interp delete slave } -returnCodes error -match glob -result * # cleanup if {[info commands testobj] != {}} { testobj freeallvars } catch {eval namespace delete [namespace children :: test_ns_*]} catch {rename foo ""} catch {rename p ""} catch {rename {} ""} catch {rename { } ""} catch {unset x} catch {unset y} catch {unset msg} ::tcltest::cleanupTests return tcl8.4.20/tests/clock.test0000644003604700454610000006665711737050674014101 0ustar dgp771div# Commands covered: clock # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1995-1998 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. set env(LC_TIME) POSIX if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } test clock-1.1 {clock tests} { list [catch {clock} msg] $msg } {1 {wrong # args: should be "clock option ?arg ...?"}} test clock-1.2 {clock tests} { list [catch {clock foo} msg] $msg } {1 {bad option "foo": must be clicks, format, scan, or seconds}} # clock clicks test clock-2.1 {clock clicks tests} { expr [clock clicks]+1 concat {} } {} test clock-2.2 {clock clicks tests} { set start [clock clicks] after 10 set end [clock clicks] expr "$end > $start" } {1} test clock-2.3 {clock clicks tests} { list [catch {clock clicks foo} msg] $msg } {1 {bad switch "foo": must be -milliseconds}} test clock-2.4 {clock clicks tests} { expr [clock clicks -milliseconds]+1 concat {} } {} test clock-2.5 {clock clicks tests, millisecond timing test} { set start [clock clicks -milli] after 10 set end [clock clicks -milli] # 60 msecs seems to be the max time slice under Windows 95/98 expr {($end > $start) && (($end - $start) <= 60)} } {1} test clock-2.6 {clock clicks, milli with too much abbreviation} { list [catch { clock clicks {} } msg] $msg } {1 {bad switch "": must be -milliseconds}} test clock-2.7 {clock clicks, milli with too much abbreviation} { list [catch { clock clicks - } msg] $msg } {1 {bad switch "-": must be -milliseconds}} # clock format test clock-3.1 {clock format tests} {unixOnly} { set clockval 657687766 clock format $clockval -format {%a %b %d %I:%M:%S %p %Y} -gmt true } {Sun Nov 04 03:02:46 AM 1990} test clock-3.2 {clock format tests} \ -body { # TCL_USE_TIMEZONE_VAR catch {set oldtz $env(TZ)} set env(TZ) PST set x {} append x [clock format 863800000 -format %Z -gmt 1] append x [set env(TZ)] catch {unset env(TZ); set env(TZ) $oldtz} set x } \ -match regexp \ -result {(?:GMT|UTC)PST} test clock-3.3 {clock format tests} { # tzset() under Borland doesn't seem to set up tzname[] for local # timezone, which caused "clock format" to think that %Z was an invalid # string. Don't care about answer, just that test runs w/o error. clock format 863800000 -format %Z set x {} } {} test clock-3.4 {clock format tests} \ -body { # tzset() under Borland doesn't seem to set up tzname[] for gmt # timezone. tzset() under MSVC has the following weird observed # behavior: # First time we call "clock format [clock seconds] -format %Z -gmt 1" # we get "GMT", but on all subsequent calls we get the current time # zone string, even though env(TZ) is GMT and the variable _timezone # is 0. set x {} append x [clock format 863800000 -format %Z -gmt 1] append x [clock format 863800000 -format %Z -gmt 1] } \ -match regexp \ -result {GMTGMT|UTCUTC} test clock-3.5 {clock format tests} { list [catch {clock format} msg] $msg } {1 {wrong # args: should be "clock format clockval ?-format string? ?-gmt boolean?"}} test clock-3.6 {clock format tests} { list [catch {clock format foo} msg] $msg } {1 {expected integer but got "foo"}} test clock-3.7 {clock format tests} {unixOrPc} { set clockval 657687766 clock format $clockval -format "%a %b %d %I:%M:%S %p %Y" -gmt true } "Sun Nov 04 03:02:46 AM 1990" test clock-3.8 {clock format tests} { list [catch {clock format a b c d e g} msg] $msg } {1 {wrong # args: should be "clock format clockval ?-format string? ?-gmt boolean?"}} test clock-3.9 {clock format tests} {unixOrPc nonPortable} { set clockval -1 clock format $clockval -format "%a %b %d %I:%M:%S %p %Y" -gmt true } "Wed Dec 31 11:59:59 PM 1969" test clock-3.10 {clock format tests} { list [catch {clock format 123 -bad arg} msg] $msg } {1 {bad switch "-bad": must be -format or -gmt}} test clock-3.11 {clock format tests} { clock format 123 -format "x" } x test clock-3.12 {clock format tests} { clock format 123 -format "" } "" test clock-3.13 {clock format with non-ASCII character in the format string} { set oldenc [encoding system] encoding system iso8859-1 set res [clock format 0 -format \u00c4] encoding system $oldenc unset oldenc set res } "\u00c4" # Bug 942078 test clock-3.14 {change of time zone} -setup { catch { unset oldTZ } if { [info exists env(TZ)] } { set oldTZ $env(TZ) } } -body { set env(TZ) PST8PDT set s [clock format 0 -format %H%M] set env(TZ) GMT0 append s -[clock format 0 -format %H%M] } -cleanup { if { [info exists oldTZ] } { set env(TZ) $oldTZ unset oldTZ } else { unset env(TZ) } } -result {1600-0000} # clock scan test clock-4.1 {clock scan tests} { list [catch {clock scan} msg] $msg } {1 {wrong # args: should be "clock scan dateString ?-base clockValue? ?-gmt boolean?"}} test clock-4.2 {clock scan tests} { list [catch {clock scan "bad-string"} msg] $msg } {1 {unable to convert date-time string "bad-string"}} test clock-4.3 {clock scan tests} { clock format [clock scan "14 Feb 92" -gmt true] \ -format {%m/%d/%y %I:%M:%S %p} -gmt true } {02/14/92 12:00:00 AM} test clock-4.4 {clock scan tests} { clock format [clock scan "Feb 14, 1992 12:20 PM" -gmt true] \ -format {%m/%d/%y %I:%M:%S %p} -gmt true } {02/14/92 12:20:00 PM} test clock-4.5 {clock scan tests} { clock format \ [clock scan "Feb 14, 1992 12:20 PM" -base 319363200 -gmt true] \ -format {%m/%d/%y %I:%M:%S %p} -gmt true } {02/14/92 12:20:00 PM} test clock-4.6 {clock scan tests} { set time [clock scan "Oct 23,1992 15:00"] clock format $time -format {%b %d,%Y %H:%M} } {Oct 23,1992 15:00} test clock-4.7 {clock scan tests} { set time [clock scan "Oct 23,1992 15:00 GMT"] clock format $time -format {%b %d,%Y %H:%M GMT} -gmt true } {Oct 23,1992 15:00 GMT} test clock-4.8 {clock scan tests} { set time [clock scan "Oct 23,1992 15:00" -gmt true] clock format $time -format {%b %d,%Y %H:%M GMT} -gmt true } {Oct 23,1992 15:00 GMT} test clock-4.9 {clock scan tests} { list [catch {clock scan "Jan 12" -bad arg} msg] $msg } {1 {bad switch "-bad": must be -base or -gmt}} # The following two two tests test the two year date policy test clock-4.10 {clock scan tests} { set time [clock scan "1/1/71" -gmt true] clock format $time -format {%b %d,%Y %H:%M GMT} -gmt true } {Jan 01,1971 00:00 GMT} test clock-4.11 {clock scan tests} { set time [clock scan "1/1/37" -gmt true] clock format $time -format {%b %d,%Y %H:%M GMT} -gmt true } {Jan 01,2037 00:00 GMT} test clock-4.12 {clock scan, relative times} { set time [clock scan "Oct 23, 1992 -1 day"] clock format $time -format {%b %d, %Y} } "Oct 22, 1992" test clock-4.13 {clock scan, ISO 8601 base date format} { set time [clock scan "19921023"] clock format $time -format {%b %d, %Y} } "Oct 23, 1992" test clock-4.14 {clock scan, ISO 8601 expanded date format} { set time [clock scan "1992-10-23"] clock format $time -format {%b %d, %Y} } "Oct 23, 1992" test clock-4.15 {clock scan, DD-Mon-YYYY format} { set time [clock scan "23-Oct-1992"] clock format $time -format {%b %d, %Y} } "Oct 23, 1992" test clock-4.16 {clock scan, ISO 8601 point in time format} { set time [clock scan "19921023T235959"] clock format $time -format {%b %d, %Y %H:%M:%S} } "Oct 23, 1992 23:59:59" test clock-4.17 {clock scan, ISO 8601 point in time format} { set time [clock scan "19921023 235959"] clock format $time -format {%b %d, %Y %H:%M:%S} } "Oct 23, 1992 23:59:59" test clock-4.18 {clock scan, ISO 8601 point in time format} { set time [clock scan "19921023T000000"] clock format $time -format {%b %d, %Y %H:%M:%S} } "Oct 23, 1992 00:00:00" # CLOCK SCAN REAL TESTS # We use 5am PST, 31-12-1999 as the base for these scans because irrespective # of your local timezone it should always give us times on December 31, 1999 set 5amPST 946645200 test clock-4.19 {clock scan, number meridian} { set t1 [clock scan "5 am" -base $5amPST -gmt true] set t2 [clock scan "5 pm" -base $5amPST -gmt true] set t3 [clock scan "5 a.m." -base $5amPST -gmt true] set t4 [clock scan "5 p.m." -base $5amPST -gmt true] list \ [clock format $t1 -format {%b %d, %Y %H:%M:%S} -gmt true] \ [clock format $t2 -format {%b %d, %Y %H:%M:%S} -gmt true] \ [clock format $t3 -format {%b %d, %Y %H:%M:%S} -gmt true] \ [clock format $t4 -format {%b %d, %Y %H:%M:%S} -gmt true] } [list "Dec 31, 1999 05:00:00" "Dec 31, 1999 17:00:00" \ "Dec 31, 1999 05:00:00" "Dec 31, 1999 17:00:00"] test clock-4.20 {clock scan, number:number meridian} { clock format [clock scan "5:30 pm" -base $5amPST -gmt true] \ -format {%b %d, %Y %H:%M:%S} -gmt true } "Dec 31, 1999 17:30:00" test clock-4.21 {clock scan, number:number-timezone} { clock format [clock scan "00:00-0800" -gmt true -base $5amPST] \ -format {%b %d, %Y %H:%M:%S} -gmt true } "Dec 31, 1999 08:00:00" test clock-4.22 {clock scan, number:number:number o_merid} { clock format [clock scan "8:00:00" -gmt true -base $5amPST] \ -format {%b %d, %Y %H:%M:%S} -gmt true } "Dec 31, 1999 08:00:00" test clock-4.23 {clock scan, number:number:number o_merid} { clock format [clock scan "8:00:00 am" -gmt true -base $5amPST] \ -format {%b %d, %Y %H:%M:%S} -gmt true } "Dec 31, 1999 08:00:00" test clock-4.24 {clock scan, number:number:number o_merid} { clock format [clock scan "8:00:00 pm" -gmt true -base $5amPST] \ -format {%b %d, %Y %H:%M:%S} -gmt true } "Dec 31, 1999 20:00:00" test clock-4.25 {clock scan, number:number:number-timezone} { clock format [clock scan "00:00:30-0800" -gmt true -base $5amPST] \ -format {%b %d, %Y %H:%M:%S} -gmt true } "Dec 31, 1999 08:00:30" test clock-4.26 {clock scan, DST for days} { clock scan "tomorrow" -base [clock scan "19991031 00:00:00"] } [clock scan "19991101 00:00:00"] test clock-4.27 {clock scan, DST for days} { clock scan "yesterday" -base [clock scan "19991101 00:00:00"] } [clock scan "19991031 00:00:00"] test clock-4.28 {clock scan, day} knownBug { clock format [clock scan "Monday" -gmt true -base 946627200] \ -format {%b %d, %Y %H:%M:%S} -gmt true } "Jan 03, 2000 00:00:00" test clock-4.29 {clock scan, number/number} { clock format [clock scan "1/1" -gmt true -base 946627200] \ -format {%b %d, %Y %H:%M:%S} -gmt true } "Jan 01, 1999 00:00:00" test clock-4.30 {clock scan, number/number} { clock format [clock scan "1/1/1999" -gmt true -base 946627200] \ -format {%b %d, %Y %H:%M:%S} -gmt true } "Jan 01, 1999 00:00:00" test clock-4.31 {clock scan, number/number} { clock format [clock scan "19990101" -gmt true -base 946627200] \ -format {%b %d, %Y %H:%M:%S} -gmt true } "Jan 01, 1999 00:00:00" test clock-4.32 {clock scan, relative minutes} { clock scan "now + 1 minute" -base 946627200 } 946627260 test clock-4.33 {clock scan, relative minutes} { clock scan "now +1 minute" -base 946627200 } 946627260 test clock-4.34 {clock scan, relative minutes} { clock scan "now 1 minute" -base 946627200 } 946627260 test clock-4.35 {clock scan, relative minutes} { clock scan "now - 1 minute" -base 946627200 } 946627140 test clock-4.36 {clock scan, relative minutes} { clock scan "now -1 minute" -base 946627200 } 946627140 test clock-4.37 {clock scan, day of week} { clock format [clock scan "wednesday" -base [clock scan 20000112]] \ -format {%b %d, %Y} } "Jan 12, 2000" test clock-4.38 {clock scan, next day of week} { clock format [clock scan "next wednesday" -base [clock scan 20000112]] \ -format {%b %d, %Y} } "Jan 19, 2000" test clock-4.39 {clock scan, day of week} { clock format [clock scan "thursday" -base [clock scan 20000112]] \ -format {%b %d, %Y} } "Jan 13, 2000" test clock-4.40 {clock scan, next day of week} { clock format [clock scan "next thursday" -base [clock scan 20000112]] \ -format {%b %d, %Y} } "Jan 20, 2000" # weekday specification and base. test clock-4.41 {2nd monday in november} { set res {} foreach i {91 92 93 94 95 96} { set nov8th [clock scan 11/8/$i] set monday [clock scan monday -base $nov8th] lappend res [clock format $monday -format %Y-%m-%d] } set res } {1991-11-11 1992-11-09 1993-11-08 1994-11-14 1995-11-13 1996-11-11} test clock-4.42 {2nd monday in november (2nd try)} { set res {} foreach i {91 92 93 94 95 96} { set nov1th [clock scan 11/1/$i] set monday [clock scan "2 monday" -base $nov1th] lappend res [clock format $monday -format %Y-%m-%d] } set res } {1991-11-11 1992-11-09 1993-11-08 1994-11-14 1995-11-13 1996-11-11} test clock-4.43 {last monday in november} { set res {} foreach i {91 92 93 94 95 96} { set dec1th [clock scan 12/1/$i] set monday [clock scan "monday 1 week ago" -base $dec1th] lappend res [clock format $monday -format %Y-%m-%d] } set res } {1991-11-25 1992-11-30 1993-11-29 1994-11-28 1995-11-27 1996-11-25} test clock-4.44 {2nd monday in november} knownBug { set res {} foreach i {91 92 93 94 95 96} { set nov8th [clock scan 11/8/$i -gmt 1] set monday [clock scan monday -base $nov8th -gmt 1] lappend res [clock format $monday -format %Y-%m-%d -gmt 1] } set res } {1991-11-11 1992-11-09 1993-11-08 1994-11-14 1995-11-13 1996-11-11} test clock-4.45 {2nd monday in november (2nd try)} knownBug { set res {} foreach i {91 92 93 94 95 96} { set nov1th [clock scan 11/1/$i -gmt 1] set monday [clock scan "2 monday" -base $nov1th -gmt 1] lappend res [clock format $monday -format %Y-%m-%d -gmt 1] } set res } {1991-11-11 1992-11-09 1993-11-08 1994-11-14 1995-11-13 1996-11-11} test clock-4.46 {last monday in november} knownBug { set res {} foreach i {91 92 93 94 95 96} { set dec1th [clock scan 12/1/$i -gmt 1] set monday [clock scan "monday 1 week ago" -base $dec1th -gmt 1] lappend res [clock format $monday -format %Y-%m-%d -gmt 1] } set res } {1991-11-25 1992-11-30 1993-11-29 1994-11-28 1995-11-27 1996-11-25} test clock-4.47 {ago with multiple relative units} { set base [clock scan "12/31/1999 00:00:00"] set res [clock scan "2 days 2 hours ago" -base $base] expr {$base - $res} } 180000 # clock seconds test clock-5.1 {clock seconds tests} { expr [clock seconds]+1 concat {} } {} test clock-5.2 {clock seconds tests} { list [catch {clock seconds foo} msg] $msg } {1 {wrong # args: should be "clock seconds"}} test clock-5.3 {clock seconds tests} { set start [clock seconds] after 2000 set end [clock seconds] expr "$end > $start" } {1} # The following dates check certain roll over dates set day [expr 24 * 60 * 60] test clock-6.1 {clock roll over dates} { set time [clock scan "12/31/1998" -gmt true] clock format [expr $time + $day] -format {%b %d,%Y %H:%M GMT} -gmt true } {Jan 01,1999 00:00 GMT} test clock-6.2 {clock roll over dates} { set time [clock scan "12/31/1999" -gmt true] clock format [expr $time + $day] -format {%b %d,%Y %H:%M GMT} -gmt true } {Jan 01,2000 00:00 GMT} test clock-6.3 {clock roll over dates} { set time [clock scan "2/28/2000" -gmt true] clock format [expr $time + $day] -format {%b %d,%Y %H:%M GMT} -gmt true } {Feb 29,2000 00:00 GMT} test clock-6.4 {clock roll over dates} { set time [clock scan "2/29/2000" -gmt true] clock format [expr $time + $day] -format {%b %d,%Y %H:%M GMT} -gmt true } {Mar 01,2000 00:00 GMT} test clock-6.5 {clock roll over dates} { set time [clock scan "January 1, 2000" -gmt true] clock format $time -format %A -gmt true } {Saturday} test clock-6.6 {clock roll over dates} { set time [clock scan "January 1, 2000" -gmt true] clock format $time -format %j -gmt true } {001} test clock-6.7 {clock roll over dates} { set time [clock scan "February 29, 2000" -gmt true] clock format $time -format %A -gmt true } {Tuesday} test clock-6.8 {clock roll over dates} { set time [clock scan "February 29, 2000" -gmt true] clock format $time -format %j -gmt true } {060} test clock-6.9 {clock roll over dates} { set time [clock scan "March 1, 2000" -gmt true] clock format $time -format %A -gmt true } {Wednesday} test clock-6.10 {clock roll over dates} { set time [clock scan "March 1, 2000" -gmt true] clock format $time -format %j -gmt true } {061} test clock-6.11 {clock roll over dates} { set time [clock scan "March 1, 2001" -gmt true] clock format $time -format %j -gmt true } {060} test clock-7.1 {clock scan next monthname} { clock format [clock scan "next june" -base [clock scan "june 1, 2000"]] \ -format %m.%Y } "06.2001" test clock-7.2 {clock scan next monthname} { clock format [clock scan "next july" -base [clock scan "june 1, 2000"]] \ -format %m.%Y } "07.2000" test clock-7.3 {clock scan next monthname} { clock format [clock scan "next may" -base [clock scan "june 1, 2000"]] \ -format %m.%Y } "05.2001" # We use 5am PST, 31-12-1999 as the base for these scans because irrespective # of your local timezone it should always give us times on December 31 set 5amPST 946645200 test clock-8.1 {clock scan midnight/gmt range bug 413397} { set fmt "%m/%d" list [clock format [clock scan year -base $5amPST -gmt 0] -format $fmt] \ [clock format [clock scan year -base $5amPST -gmt 1] -format $fmt] } {12/31 12/31} ::tcltest::testConstraint needPST [expr { [regexp {^(Pacific.*|P[DS]T)$} [clock format 1 -format %Z]] && ([clock format 1 -format %s] != "%s") }] test clock-9.1 {%s gmt testing} {needPST} { # Note that this test will fail if the strftime on the underlying # system doesn't support the %s format group. Systems that are known # to have trouble include the native C libraries on AIX and HP-UX # We need PST to guarantee the difference value below, and %s isn't # valid on all OSes (like Solaris). set s 100000 set a [clock format $s -format %s -gmt 0] set b [clock format $s -format %s -gmt 1] # This should be the offset in seconds between current locale and GMT. # This didn't seem to be correctly on Windows until the fix for # Bug #559376, which fiddled with env(TZ) when -gmt 1 was used. # It's hard-coded to check P[SD]T now. (8 hours) set c [expr {$b-$a}] } {28800} ::tcltest::testConstraint percentG \ [expr { ![catch { clock format 0 -format %G -gmt true } y1970] && $y1970 eq {1970} }] test clock-10.0 {Can strftime do %G?} { clock format 0 -format %G -gmt true } 1970 test clock-10.1 {ISO week-based calendar 2000-W52-1} {percentG} { clock format 977702400 -format {%a %A %g %G %u %V %w} -gmt true; # 2000-12-25 } {Mon Monday 00 2000 1 52 1} test clock-10.2 {ISO week-based calendar 2000-W52-7} {percentG} { clock format 978220800 -format {%a %A %g %G %u %V %w} -gmt true; # 2000-12-31 } {Sun Sunday 00 2000 7 52 0} test clock-10.3 {ISO week-based calendar 2001-W01-1} {percentG} { clock format 978307200 -format {%a %A %g %G %u %V %w} -gmt true; # 2001-1-1 } {Mon Monday 01 2001 1 01 1} test clock-10.4 {ISO week-based calendar 2001-W01-7} {percentG} { clock format 978825600 -format {%a %A %g %G %u %V %w} -gmt true; # 2001-1-7 } {Sun Sunday 01 2001 7 01 0} test clock-10.5 {ISO week-based calendar 2001-W02-1} {percentG} { clock format 978912000 -format {%a %A %g %G %u %V %w} -gmt true; # 2001-1-8 } {Mon Monday 01 2001 1 02 1} test clock-10.6 {ISO week-based calendar 2001-W52-1} {percentG} { clock format 1009152000 -format {%a %A %g %G %u %V %w} -gmt true; # 2001-12-24 } {Mon Monday 01 2001 1 52 1} test clock-10.7 {ISO week-based calendar 2001-W52-7} {percentG} { clock format 1009670400 -format {%a %A %g %G %u %V %w} -gmt true; # 2001-12-30 } {Sun Sunday 01 2001 7 52 0} test clock-10.8 {ISO week-based calendar 2002-W01-1} {percentG} { clock format 1009756800 -format {%a %A %g %G %u %V %w} -gmt true; # 2001-12-31 } {Mon Monday 02 2002 1 01 1} test clock-10.9 {ISO week-based calendar 2002-W01-2} {percentG} { clock format 1009843200 -format {%a %A %g %G %u %V %w} -gmt true; # 2002-1-1 } {Tue Tuesday 02 2002 2 01 2} test clock-10.10 {ISO week-based calendar 2002-W01-7} {percentG} { clock format 1010275200 -format {%a %A %g %G %u %V %w} -gmt true; # 2002-1-6 } {Sun Sunday 02 2002 7 01 0} test clock-10.11 {ISO week-based calendar 2002-W02-1} {percentG} { clock format 1010361600 -format {%a %A %g %G %u %V %w} -gmt true; # 2002-1-7 } {Mon Monday 02 2002 1 02 1} test clock-10.12 {ISO week-based calendar 2002-W52-1} {percentG} { clock format 1040601600 -format {%a %A %g %G %u %V %w} -gmt true; # 2002-12-23 } {Mon Monday 02 2002 1 52 1} test clock-10.13 {ISO week-based calendar 2002-W52-7} {percentG} { clock format 1041120000 -format {%a %A %g %G %u %V %w} -gmt true; # 2002-12-29 } {Sun Sunday 02 2002 7 52 0} test clock-10.14 {ISO week-based calendar 2003-W01-1} {percentG} { clock format 1041206400 -format {%a %A %g %G %u %V %w} -gmt true; # 2002-12-30 } {Mon Monday 03 2003 1 01 1} test clock-10.15 {ISO week-based calendar 2003-W01-2} {percentG} { clock format 1041292800 -format {%a %A %g %G %u %V %w} -gmt true; # 2002-12-31 } {Tue Tuesday 03 2003 2 01 2} test clock-10.16 {ISO week-based calendar 2003-W01-3} {percentG} { clock format 1041379200 -format {%a %A %g %G %u %V %w} -gmt true; # 2003-1-1 } {Wed Wednesday 03 2003 3 01 3} test clock-10.17 {ISO week-based calendar 2003-W01-7} {percentG} { clock format 1041724800 -format {%a %A %g %G %u %V %w} -gmt true; # 2003-1-5 } {Sun Sunday 03 2003 7 01 0} test clock-10.18 {ISO week-based calendar 2003-W02-1} {percentG} { clock format 1041811200 -format {%a %A %g %G %u %V %w} -gmt true; # 2003-1-6 } {Mon Monday 03 2003 1 02 1} test clock-10.19 {ISO week-based calendar 2003-W52-1} {percentG} { clock format 1072051200 -format {%a %A %g %G %u %V %w} -gmt true; # 2003-12-22 } {Mon Monday 03 2003 1 52 1} test clock-10.20 {ISO week-based calendar 2003-W52-7} {percentG} { clock format 1072569600 -format {%a %A %g %G %u %V %w} -gmt true; # 2003-12-28 } {Sun Sunday 03 2003 7 52 0} test clock-10.21 {ISO week-based calendar 2004-W01-1} {percentG} { clock format 1072656000 -format {%a %A %g %G %u %V %w} -gmt true; # 2003-12-29 } {Mon Monday 04 2004 1 01 1} test clock-10.22 {ISO week-based calendar 2004-W01-3} {percentG} { clock format 1072828800 -format {%a %A %g %G %u %V %w} -gmt true; # 2003-12-31 } {Wed Wednesday 04 2004 3 01 3} test clock-10.23 {ISO week-based calendar 2004-W01-4} {percentG} { clock format 1072915200 -format {%a %A %g %G %u %V %w} -gmt true; # 2004-1-1 } {Thu Thursday 04 2004 4 01 4} test clock-10.24 {ISO week-based calendar 2004-W01-7} {percentG} { clock format 1073174400 -format {%a %A %g %G %u %V %w} -gmt true; # 2004-1-4 } {Sun Sunday 04 2004 7 01 0} test clock-10.25 {ISO week-based calendar 2004-W02-1} {percentG} { clock format 1073260800 -format {%a %A %g %G %u %V %w} -gmt true; # 2004-1-5 } {Mon Monday 04 2004 1 02 1} test clock-10.26 {ISO week-based calendar 2004-W52-1} {percentG} { clock format 1103500800 -format {%a %A %g %G %u %V %w} -gmt true; # 2004-12-20 } {Mon Monday 04 2004 1 52 1} test clock-10.27 {ISO week-based calendar 2004-W52-7} {percentG} { clock format 1104019200 -format {%a %A %g %G %u %V %w} -gmt true; # 2004-12-26 } {Sun Sunday 04 2004 7 52 0} test clock-10.28 {ISO week-based calendar 2004-W53-1} {percentG} { clock format 1104105600 -format {%a %A %g %G %u %V %w} -gmt true; # 2004-12-27 } {Mon Monday 04 2004 1 53 1} test clock-10.29 {ISO week-based calendar 2004-W53-5} {percentG} { clock format 1104451200 -format {%a %A %g %G %u %V %w} -gmt true; # 2004-12-31 } {Fri Friday 04 2004 5 53 5} test clock-10.30 {ISO week-based calendar 2004-W53-6} {percentG} { clock format 1104537600 -format {%a %A %g %G %u %V %w} -gmt true; # 2005-1-1 } {Sat Saturday 04 2004 6 53 6} test clock-10.31 {ISO week-based calendar 2004-W53-7} {percentG} { clock format 1104624000 -format {%a %A %g %G %u %V %w} -gmt true; # 2005-1-2 } {Sun Sunday 04 2004 7 53 0} test clock-10.32 {ISO week-based calendar 2005-W01-1} {percentG} { clock format 1104710400 -format {%a %A %g %G %u %V %w} -gmt true; # 2005-1-3 } {Mon Monday 05 2005 1 01 1} test clock-10.33 {ISO week-based calendar 2005-W01-7} {percentG} { clock format 1105228800 -format {%a %A %g %G %u %V %w} -gmt true; # 2005-1-9 } {Sun Sunday 05 2005 7 01 0} test clock-10.34 {ISO week-based calendar 2005-W02-1} {percentG} { clock format 1105315200 -format {%a %A %g %G %u %V %w} -gmt true; # 2005-1-10 } {Mon Monday 05 2005 1 02 1} test clock-10.35 {ISO week-based calendar 2005-W52-1} {percentG} { clock format 1135555200 -format {%a %A %g %G %u %V %w} -gmt true; # 2005-12-26 } {Mon Monday 05 2005 1 52 1} test clock-10.36 {ISO week-based calendar 2005-W52-6} {percentG} { clock format 1135987200 -format {%a %A %g %G %u %V %w} -gmt true; # 2005-12-31 } {Sat Saturday 05 2005 6 52 6} test clock-10.37 {ISO week-based calendar 2005-W52-7} {percentG} { clock format 1136073600 -format {%a %A %g %G %u %V %w} -gmt true; # 2006-1-1 } {Sun Sunday 05 2005 7 52 0} test clock-10.38 {ISO week-based calendar 2006-W01-1} {percentG} { clock format 1136160000 -format {%a %A %g %G %u %V %w} -gmt true; # 2006-1-2 } {Mon Monday 06 2006 1 01 1} test clock-10.39 {ISO week-based calendar 2006-W01-7} {percentG} { clock format 1136678400 -format {%a %A %g %G %u %V %w} -gmt true; # 2006-1-8 } {Sun Sunday 06 2006 7 01 0} test clock-10.40 {ISO week-based calendar 2006-W02-1} {percentG} { clock format 1136764800 -format {%a %A %g %G %u %V %w} -gmt true; # 2006-1-9 } {Mon Monday 06 2006 1 02 1} test clock-10.41 {ISO week-based calendar 2009-W52-1} {percentG} { clock format 1261353600 -format {%a %A %g %G %u %V %w} -gmt true; # 2009-12-21 } {Mon Monday 09 2009 1 52 1} test clock-10.42 {ISO week-based calendar 2009-W52-7} {percentG} { clock format 1261872000 -format {%a %A %g %G %u %V %w} -gmt true; # 2009-12-27 } {Sun Sunday 09 2009 7 52 0} test clock-10.43 {ISO week-based calendar 2009-W53-1} {percentG} { clock format 1261958400 -format {%a %A %g %G %u %V %w} -gmt true; # 2009-12-28 } {Mon Monday 09 2009 1 53 1} test clock-10.44 {ISO week-based calendar 2009-W53-4} {percentG} { clock format 1262217600 -format {%a %A %g %G %u %V %w} -gmt true; # 2009-12-31 } {Thu Thursday 09 2009 4 53 4} test clock-10.45 {ISO week-based calendar 2009-W53-5} {percentG} { clock format 1262304000 -format {%a %A %g %G %u %V %w} -gmt true; # 2010-1-1 } {Fri Friday 09 2009 5 53 5} test clock-10.46 {ISO week-based calendar 2009-W53-7} {percentG} { clock format 1262476800 -format {%a %A %g %G %u %V %w} -gmt true; # 2010-1-3 } {Sun Sunday 09 2009 7 53 0} test clock-10.47 {ISO week-based calendar 2010-W01-1} {percentG} { clock format 1262563200 -format {%a %A %g %G %u %V %w} -gmt true; # 2010-1-4 } {Mon Monday 10 2010 1 01 1} test clock-10.48 {ISO week-based calendar 2010-W01-7} {percentG} { clock format 1263081600 -format {%a %A %g %G %u %V %w} -gmt true; # 2010-1-10 } {Sun Sunday 10 2010 7 01 0} test clock-10.49 {ISO week-based calendar 2010-W02-1} {percentG} { clock format 1263168000 -format {%a %A %g %G %u %V %w} -gmt true; # 2010-1-11 } {Mon Monday 10 2010 1 02 1} test clock-41.1 {regression test - format group %k when hour is 0 } { clock format 0 -format %k -gmt true } { 0} # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/autoMkindex.test0000644003604700454610000002446211737050674015262 0ustar dgp771div# Commands covered: auto_mkindex auto_import # # This file contains tests related to autoloading and generating # the autoloading index. # # Copyright (c) 1998 Lucent Technologies, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import -force ::tcltest::* } makeFile {# Test file for: # auto_mkindex # # This file provides example cases for testing the Tcl autoloading # facility. Things are much more complicated with namespaces and classes. # The "auto_mkindex" facility can no longer be built on top of a simple # regular expression parser. It must recognize constructs like this: # # namespace eval foo { # proc test {x y} { ... } # namespace eval bar { # proc another {args} { ... } # } # } # # Note that procedures and itcl class definitions can be nested inside # of namespaces. # # Copyright (c) 1993-1998 Lucent Technologies, Inc. # This shouldn't cause any problems namespace import -force blt::* # Should be able to handle "proc" definitions, even if they are # preceded by white space. proc normal {x y} {return [expr $x+$y]} proc indented {x y} {return [expr $x+$y]} # # Should be able to handle proc declarations within namespaces, # even if they have explicit namespace paths. # namespace eval buried { proc inside {args} {return "inside: $args"} namespace export pub_* proc pub_one {args} {return "one: $args"} proc pub_two {args} {return "two: $args"} } proc buried::within {args} {return "within: $args"} namespace eval buried { namespace eval under { proc neath {args} {return "neath: $args"} } namespace eval ::buried { proc relative {args} {return "relative: $args"} proc ::top {args} {return "top: $args"} proc ::buried::explicit {args} {return "explicit: $args"} } } # With proper hooks, we should be able to support other commands # that create procedures proc buried::myproc {name body args} { ::proc $name $body $args } namespace eval ::buried { proc mycmd1 args {return "mycmd"} myproc mycmd2 args {return "mycmd"} } ::buried::myproc mycmd3 args {return "another"} proc {buried::my proc} {name body args} { ::proc $name $body $args } namespace eval ::buried { proc mycmd4 args {return "mycmd"} {my proc} mycmd5 args {return "mycmd"} } {::buried::my proc} mycmd6 args {return "another"} # A correctly functioning [auto_import] won't choke when a child # namespace [namespace import]s from its parent. # namespace eval ::parent::child { namespace import ::parent::* } proc ::parent::child::test {} {} } autoMkindex.tcl # Save initial state of auto_mkindex_parser auto_load auto_mkindex if {[info exists auto_mkindex_parser::initCommands]} { set saveCommands $auto_mkindex_parser::initCommands } proc AutoMkindexTestReset {} { global saveCommands if {[info exists saveCommands]} { set auto_mkindex_parser::initCommands $saveCommands } elseif {[info exists auto_mkindex_parser::initCommands]} { unset auto_mkindex_parser::initCommands } } set result "" set origDir [pwd] cd $::tcltest::temporaryDirectory test autoMkindex-1.1 {remove any existing tclIndex file} { file delete tclIndex file exists tclIndex } {0} test autoMkindex-1.2 {build tclIndex based on a test file} { auto_mkindex . autoMkindex.tcl file exists tclIndex } {1} set element "{source [file join . autoMkindex.tcl]}" test autoMkindex-1.3 {examine tclIndex} { file delete tclIndex auto_mkindex . autoMkindex.tcl namespace eval tcl_autoMkindex_tmp { set dir "." variable auto_index source tclIndex set ::result "" foreach elem [lsort [array names auto_index]] { lappend ::result [list $elem $auto_index($elem)] } } namespace delete tcl_autoMkindex_tmp set ::result } "{::buried::explicit $element} {::buried::inside $element} {{::buried::my proc} $element} {::buried::mycmd1 $element} {::buried::mycmd4 $element} {::buried::myproc $element} {::buried::pub_one $element} {::buried::pub_two $element} {::buried::relative $element} {::buried::under::neath $element} {::buried::within $element} {::parent::child::test $element} {indented $element} {normal $element} {top $element}" test autoMkindex-2.1 {commands on the autoload path can be imported} { file delete tclIndex auto_mkindex . autoMkindex.tcl set interp [interp create] set final [$interp eval { namespace eval blt {} set auto_path [linsert $auto_path 0 .] set info [list [catch {namespace import buried::*} result] $result] foreach name [lsort [info commands pub_*]] { lappend info $name [namespace origin $name] } set info }] interp delete $interp set final } "0 {} pub_one ::buried::pub_one pub_two ::buried::pub_two" # Test auto_mkindex hooks # Slave hook executes interesting code in the interp used to watch code. test autoMkindex-3.1 {slaveHook} { auto_mkindex_parser::slavehook { _%@namespace eval ::blt { proc foo {} {} _%@namespace export foo } } auto_mkindex_parser::slavehook { _%@namespace import -force ::blt::* } file delete tclIndex auto_mkindex . autoMkindex.tcl # Reset initCommands to avoid trashing other tests AutoMkindexTestReset file exists tclIndex } 1 # The auto_mkindex_parser::command is used to register commands # that create new commands. test autoMkindex-3.2 {auto_mkindex_parser::command} { auto_mkindex_parser::command buried::myproc {name args} { variable index variable scriptFile append index [list set auto_index([fullname $name])] \ " \[list source \[file join \$dir [list $scriptFile]\]\]\n" } file delete tclIndex auto_mkindex . autoMkindex.tcl namespace eval tcl_autoMkindex_tmp { set dir "." variable auto_index source tclIndex set ::result "" foreach elem [lsort [array names auto_index]] { lappend ::result [list $elem $auto_index($elem)] } } namespace delete tcl_autoMkindex_tmp # Reset initCommands to avoid trashing other tests AutoMkindexTestReset set ::result } "{::buried::explicit $element} {::buried::inside $element} {{::buried::my proc} $element} {::buried::mycmd1 $element} {::buried::mycmd2 $element} {::buried::mycmd4 $element} {::buried::myproc $element} {::buried::pub_one $element} {::buried::pub_two $element} {::buried::relative $element} {::buried::under::neath $element} {::buried::within $element} {::parent::child::test $element} {indented $element} {mycmd3 $element} {normal $element} {top $element}" test autoMkindex-3.3 {auto_mkindex_parser::command} {knownBug} { auto_mkindex_parser::command {buried::my proc} {name args} { variable index variable scriptFile puts "my proc $name" append index [list set auto_index([fullname $name])] \ " \[list source \[file join \$dir [list $scriptFile]\]\]\n" } file delete tclIndex auto_mkindex . autoMkindex.tcl namespace eval tcl_autoMkindex_tmp { set dir "." variable auto_index source tclIndex set ::result "" foreach elem [lsort [array names auto_index]] { lappend ::result [list $elem $auto_index($elem)] } } namespace delete tcl_autoMkindex_tmp # Reset initCommands to avoid trashing other tests AutoMkindexTestReset proc lvalue {list pattern} { set ix [lsearch $list $pattern] if {$ix >= 0} { return [lindex $list $ix] } else { return {} } } list [lvalue $::result *mycmd4*] [lvalue $::result *mycmd5*] [lvalue $::result *mycmd6*] } "{::buried::mycmd4 $element} {::buried::mycmd5 $element} {mycmd6 $element}" makeDirectory pkg makeFile { package provide football 1.0 namespace eval ::pro:: { # # export only public functions. # namespace export {[a-z]*} } namespace eval ::college:: { # # export only public functions. # namespace export {[a-z]*} } proc ::pro::team {} { puts "go packers!" return true } proc ::college::team {} { puts "go badgers!" return true } } [file join pkg samename.tcl] test autoMkindex-4.1 {platform indenpendant source commands} { file delete tclIndex auto_mkindex . pkg/samename.tcl set f [open tclIndex r] set dat [split [string trim [read $f]] "\n"] set len [llength $dat] set result [lsort [lrange $dat [expr {$len-2}] [expr {$len-1}]]] close $f set result } {{set auto_index(::college::team) [list source [file join $dir pkg samename.tcl]]} {set auto_index(::pro::team) [list source [file join $dir pkg samename.tcl]]}} removeFile [file join pkg samename.tcl] makeFile { set dollar1 "this string contains an unescaped dollar sign -> \\$foo" set dollar2 "this string contains an escaped dollar sign -> \$foo \\\$foo" set bracket1 "this contains an unescaped bracket [NoSuchProc]" set bracket2 "this contains an escaped bracket \[NoSuchProc\]" set bracket3 "this contains nested unescaped brackets [[NoSuchProc]]" proc testProc {} {} } [file join pkg magicchar.tcl] test autoMkindex-5.1 {escape magic tcl chars in general code} { file delete tclIndex set result {} if { ![catch {auto_mkindex . pkg/magicchar.tcl}] } { set f [open tclIndex r] set dat [split [string trim [read $f]] "\n"] set result [lindex $dat end] close $f } set result } {set auto_index(testProc) [list source [file join $dir pkg magicchar.tcl]]} removeFile [file join pkg magicchar.tcl] makeFile { proc {[magic mojo proc]} {} {} } [file join pkg magicchar2.tcl] test autoMkindex-5.2 {correctly locate auto loaded procs with []} { file delete tclIndex set result {} if { ![catch {auto_mkindex . pkg/magicchar2.tcl}] } { # Make a slave interp to test the autoloading set c [interp create] $c eval {lappend auto_path [pwd]} set result [$c eval {catch {{[magic mojo proc]}}}] interp delete $c } set result } 0 removeFile [file join pkg magicchar2.tcl] removeDirectory pkg # Clean up. unset result AutoMkindexTestReset if {[info exists saveCommands]} { unset saveCommands } rename AutoMkindexTestReset "" removeFile autoMkindex.tcl if {[file exists tclIndex]} { file delete -force tclIndex } cd $origDir ::tcltest::cleanupTests tcl8.4.20/tests/while.test0000644003604700454610000003376311737050674014106 0ustar dgp771div# Commands covered: while # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1996 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } # Basic "while" operation. catch {unset i} catch {unset a} test while-1.1 {TclCompileWhileCmd: missing test expression} { catch {while } msg set msg } {wrong # args: should be "while test command"} test while-1.2 {TclCompileWhileCmd: error in test expression} { set i 0 catch {while {$i<} break} msg set errorInfo } {syntax error in expression "$i<": premature end of expression ("while" test expression) while compiling "while {$i<} break"} test while-1.3 {TclCompileWhileCmd: error in test expression} { set err [catch {while {"a"+"b"} {error "loop aborted"}} msg] list $err $msg } {1 {can't use non-numeric string as operand of "+"}} test while-1.4 {TclCompileWhileCmd: multiline test expr} { set value 1 while {($tcl_platform(platform) != "foobar1") && \ ($tcl_platform(platform) != "foobar2")} { incr value break } set value } {2} test while-1.5 {TclCompileWhileCmd: non-numeric boolean test expr} { set value 1 while {"true"} { incr value; if {$value > 5} { break; } } set value } 6 test while-1.6 {TclCompileWhileCmd: test expr is enclosed in quotes} { set i 0 while "$i > 5" {} } {} test while-1.7 {TclCompileWhileCmd: missing command body} { set i 0 catch {while {$i < 5} } msg set msg } {wrong # args: should be "while test command"} test while-1.8 {TclCompileWhileCmd: error compiling command body} { set i 0 catch {while {$i < 5} {set}} msg set errorInfo } {wrong # args: should be "set varName ?newValue?" while compiling "set" ("while" body line 1) while compiling "while {$i < 5} {set}"} test while-1.9 {TclCompileWhileCmd: simple command body} { set a {} set i 1 while {$i<6} { if $i==4 break set a [concat $a $i] incr i } set a } {1 2 3} test while-1.10 {TclCompileWhileCmd: command body in quotes} { set a {} set i 1 while {$i<6} "append a x; incr i" set a } {xxxxx} test while-1.11 {TclCompileWhileCmd: computed command body} { catch {unset x1} catch {unset bb} catch {unset x2} set x1 {append a x1; } set bb {break} set x2 {; append a x2; incr i} set a {} set i 1 while {$i<6} $x1$bb$x2 set a } {x1} test while-1.12 {TclCompileWhileCmd: long command body} { set a {} set i 1 while {$i<6} { if $i==4 break if $i>5 continue if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } set a [concat $a $i] incr i } set a } {1 2 3} test while-1.13 {TclCompileWhileCmd: while command result} { set i 0 set a [while {$i < 5} {incr i}] set a } {} test while-1.14 {TclCompileWhileCmd: while command result} { set i 0 set a [while {$i < 5} {if $i==3 break; incr i}] set a } {} # Check "while" and "continue". test while-2.1 {continue tests} { set a {} set i 1 while {$i <= 4} { incr i if {$i == 3} continue set a [concat $a $i] } set a } {2 4 5} test while-2.2 {continue tests} { set a {} set i 1 while {$i <= 4} { incr i if {$i != 2} continue set a [concat $a $i] } set a } {2} test while-2.3 {continue tests, nested loops} { set msg {} set i 1 while {$i <= 4} { incr i set a 1 while {$a <= 2} { incr a if {$i>=3 && $a>=3} continue set msg [concat $msg "$i.$a"] } } set msg } {2.2 2.3 3.2 4.2 5.2} test while-2.4 {continue tests, long command body} { set a {} set i 1 while {$i<6} { if $i==2 {incr i; continue} if $i==4 break if $i>5 continue if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } set a [concat $a $i] incr i } set a } {1 3} # Check "while" and "break". test while-3.1 {break tests} { set a {} set i 1 while {$i <= 4} { if {$i == 3} break set a [concat $a $i] incr i } set a } {1 2} test while-3.2 {break tests, nested loops} { set msg {} set i 1 while {$i <= 4} { set a 1 while {$a <= 2} { if {$i>=2 && $a>=2} break set msg [concat $msg "$i.$a"] incr a } incr i } set msg } {1.1 1.2 2.1 3.1 4.1} test while-3.3 {break tests, long command body} { set a {} set i 1 while {$i<6} { if $i==2 {incr i; continue} if $i==5 break if $i>5 continue if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if $i==4 break if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } set a [concat $a $i] incr i } set a } {1 3} # Check "while" with computed command names. test while-4.1 {while and computed command names} { set i 0 set z while $z {$i < 10} { incr i } set i } 10 test while-4.2 {while (not compiled): missing test expression} { set z while catch {$z } msg set msg } {wrong # args: should be "while test command"} test while-4.3 {while (not compiled): error in test expression} { set i 0 set z while catch {$z {$i<} {set x 1}} msg set errorInfo } {syntax error in expression "$i<": premature end of expression while executing "$z {$i<} {set x 1}"} test while-4.4 {while (not compiled): error in test expression} { set z while set err [catch {$z {"a"+"b"} {error "loop aborted"}} msg] list $err $msg } {1 {can't use non-numeric string as operand of "+"}} test while-4.5 {while (not compiled): multiline test expr} { set value 1 set z while $z {($tcl_platform(platform) != "foobar1") && \ ($tcl_platform(platform) != "foobar2")} { incr value break } set value } {2} test while-4.6 {while (not compiled): non-numeric boolean test expr} { set value 1 set z while $z {"true"} { incr value; if {$value > 5} { break; } } set value } 6 test while-4.7 {while (not compiled): test expr is enclosed in quotes} { set i 0 set z while $z "$i > 5" {} } {} test while-4.8 {while (not compiled): missing command body} { set i 0 set z while catch {$z {$i < 5} } msg set msg } {wrong # args: should be "while test command"} test while-4.9 {while (not compiled): error compiling command body} { set i 0 set z while catch {$z {$i < 5} {set}} msg set errorInfo } {wrong # args: should be "set varName ?newValue?" while compiling "set" ("while" body line 1) invoked from within "$z {$i < 5} {set}"} test while-4.10 {while (not compiled): simple command body} { set a {} set i 1 set z while $z {$i<6} { if $i==4 break set a [concat $a $i] incr i } set a } {1 2 3} test while-4.11 {while (not compiled): command body in quotes} { set a {} set i 1 set z while $z {$i<6} "append a x; incr i" set a } {xxxxx} test while-4.12 {while (not compiled): computed command body} { set z while catch {unset x1} catch {unset bb} catch {unset x2} set x1 {append a x1; } set bb {break} set x2 {; append a x2; incr i} set a {} set i 1 $z {$i<6} $x1$bb$x2 set a } {x1} test while-4.13 {while (not compiled): long command body} { set a {} set z while set i 1 $z {$i<6} { if $i==4 break if $i>5 continue if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } set a [concat $a $i] incr i } set a } {1 2 3} test while-4.14 {while (not compiled): while command result} { set i 0 set z while set a [$z {$i < 5} {incr i}] set a } {} test while-4.15 {while (not compiled): while command result} { set i 0 set z while set a [$z {$i < 5} {if $i==3 break; incr i}] set a } {} # Check "break" with computed command names. test while-5.1 {break and computed command names} { set i 0 set z break while 1 { if {$i > 10} $z incr i } set i } 11 test while-5.2 {break tests with computed command names} { set a {} set i 1 set z break while {$i <= 4} { if {$i == 3} $z set a [concat $a $i] incr i } set a } {1 2} test while-5.3 {break tests, nested loops with computed command names} { set msg {} set i 1 set z break while {$i <= 4} { set a 1 while {$a <= 2} { if {$i>=2 && $a>=2} $z set msg [concat $msg "$i.$a"] incr a } incr i } set msg } {1.1 1.2 2.1 3.1 4.1} test while-5.4 {break tests, long command body with computed command names} { set a {} set i 1 set z break while {$i<6} { if $i==2 {incr i; continue} if $i==5 $z if $i>5 continue if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if $i==4 $z if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } set a [concat $a $i] incr i } set a } {1 3} # Check "continue" with computed command names. test while-6.1 {continue and computed command names} { set i 0 set z continue while 1 { incr i if {$i < 10} $z break } set i } 10 test while-6.2 {continue tests} { set a {} set i 1 set z continue while {$i <= 4} { incr i if {$i == 3} $z set a [concat $a $i] } set a } {2 4 5} test while-6.3 {continue tests with computed command names} { set a {} set i 1 set z continue while {$i <= 4} { incr i if {$i != 2} $z set a [concat $a $i] } set a } {2} test while-6.4 {continue tests, nested loops with computed command names} { set msg {} set i 1 set z continue while {$i <= 4} { incr i set a 1 while {$a <= 2} { incr a if {$i>=3 && $a>=3} $z set msg [concat $msg "$i.$a"] } } set msg } {2.2 2.3 3.2 4.2 5.2} test while-6.5 {continue tests, long command body with computed command names} { set a {} set i 1 set z continue while {$i<6} { if $i==2 {incr i; continue} if $i==4 break if $i>5 $z if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine)=="xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } set a [concat $a $i] incr i } set a } {1 3} # Test for incorrect "double evaluation" semantics test while-7.1 {delayed substitution of body} { set i 0 while {[incr i] < 10} " set result $i " proc p {} { set i 0 while {[incr i] < 10} " set result $i " set result } append result [p] } {00} # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/listObj.test0000644003604700454610000001541612133546540014370 0ustar dgp771div# Functionality covered: operation of the procedures in tclListObj.c that # implement the Tcl type manager for the list object type. # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1995-1996 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } if {[info commands testobj] == {}} { puts "This application hasn't been compiled with the \"testobj\"" puts "command, so I can't test the Tcl type and object support." ::tcltest::cleanupTests return } catch {unset x} test listobj-1.1 {Tcl_GetListObjType} { set t [testobj types] set first [string first "list" $t] set result [expr {$first != -1}] } {1} test listobj-2.1 {Tcl_SetListObj, use in lappend} { catch {unset x} list [lappend x 1 abc def] [lappend x 1 ghi jkl] $x } {{1 abc def} {1 abc def 1 ghi jkl} {1 abc def 1 ghi jkl}} test listobj-2.2 {Tcl_SetListObj, use in ObjInterpProc} { proc return_args {args} { return $args } list [return_args] [return_args x] [return_args x y] } {{} x {x y}} test listobj-2.3 {Tcl_SetListObj, zero element count} { list } {} test listobj-3.1 {Tcl_ListObjAppend, list conversion} { catch {unset x} list [lappend x 1 2 abc "long string"] $x } {{1 2 abc {long string}} {1 2 abc {long string}}} test listobj-3.2 {Tcl_ListObjAppend, list conversion} { set x "" list [lappend x first second] [lappend x third fourth] $x } {{first second} {first second third fourth} {first second third fourth}} test listobj-3.3 {Tcl_ListObjAppend, list conversion} { set x "abc def" list [lappend x first second] $x } {{abc def first second} {abc def first second}} test listobj-3.4 {Tcl_ListObjAppend, error in conversion} { set x " \{" list [catch {lappend x abc def} msg] $msg } {1 {unmatched open brace in list}} test listobj-3.5 {Tcl_ListObjAppend, force internal rep array to grow} { set x "" list [lappend x 1 1] [lappend x 2 2] [lappend x 3 3] [lappend x 4 4] \ [lappend x 5 5] [lappend x 6 6] [lappend x 7 7] [lappend x 8 8] $x } {{1 1} {1 1 2 2} {1 1 2 2 3 3} {1 1 2 2 3 3 4 4} {1 1 2 2 3 3 4 4 5 5} {1 1 2 2 3 3 4 4 5 5 6 6} {1 1 2 2 3 3 4 4 5 5 6 6 7 7} {1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8} {1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8}} test listobj-4.1 {Tcl_ListObjAppendElement, list conversion} { catch {unset x} list [lappend x 1] $x } {1 1} test listobj-4.2 {Tcl_ListObjAppendElement, list conversion} { set x "" list [lappend x first] [lappend x second] $x } {first {first second} {first second}} test listobj-4.3 {Tcl_ListObjAppendElement, list conversion} { set x "abc def" list [lappend x first] $x } {{abc def first} {abc def first}} test listobj-4.4 {Tcl_ListObjAppendElement, error in conversion} { set x " \{" list [catch {lappend x abc} msg] $msg } {1 {unmatched open brace in list}} test listobj-4.5 {Tcl_ListObjAppendElement, force internal rep array to grow} { set x "" list [lappend x 1] [lappend x 2] [lappend x 3] [lappend x 4] \ [lappend x 5] [lappend x 6] [lappend x 7] [lappend x 8] $x } {1 {1 2} {1 2 3} {1 2 3 4} {1 2 3 4 5} {1 2 3 4 5 6} {1 2 3 4 5 6 7} {1 2 3 4 5 6 7 8} {1 2 3 4 5 6 7 8}} test listobj-5.1 {Tcl_ListObjIndex, basic tests} { lindex {a b c} 0 } a test listobj-5.2 {Tcl_ListObjIndex, basic tests} { lindex a 0 } a test listobj-5.3 {Tcl_ListObjIndex, basic tests} { lindex {a {b c d} x} 1 } {b c d} test listobj-5.4 {Tcl_ListObjIndex, basic tests} { lindex {a b c} 3 } {} test listobj-5.5 {Tcl_ListObjIndex, basic tests} { lindex {a b c} 100 } {} test listobj-5.6 {Tcl_ListObjIndex, basic tests} { lindex a 100 } {} test listobj-5.7 {Tcl_ListObjIndex, basic tests} { lindex {} -1 } {} test listobj-5.8 {Tcl_ListObjIndex, error in conversion} { set x " \{" list [catch {lindex $x 0} msg] $msg } {1 {unmatched open brace in list}} test listobj-6.1 {Tcl_ListObjLength} { llength {a b c d} } 4 test listobj-6.2 {Tcl_ListObjLength} { llength {a b c {a b {c d}} d} } 5 test listobj-6.3 {Tcl_ListObjLength} { llength {} } 0 test listobj-6.4 {Tcl_ListObjLength, convert from non-list} { llength 123 } 1 test listobj-6.5 {Tcl_ListObjLength, error converting from non-list} { list [catch {llength "a b c \{"} msg] $msg } {1 {unmatched open brace in list}} test listobj-6.6 {Tcl_ListObjLength, error converting from non-list} { list [catch {llength "a {b}c"} msg] $msg } {1 {list element in braces followed by "c" instead of space}} test listobj-7.1 {Tcl_ListObjReplace, conversion from non-list} { lreplace 123 0 0 x } {x} test listobj-7.2 {Tcl_ListObjReplace, error converting from non-list} { list [catch {lreplace "a b c \{" 1 1 x} msg] $msg } {1 {unmatched open brace in list}} test listobj-7.3 {Tcl_ListObjReplace, error converting from non-list} { list [catch {lreplace "a {b}c" 1 2 x} msg] $msg } {1 {list element in braces followed by "c" instead of space}} test listobj-7.4 {Tcl_ListObjReplace, negative first element index} { lreplace {1 2 3 4 5} -1 1 a } {a 3 4 5} test listobj-7.5 {Tcl_ListObjReplace, last element index >= num elems} { lreplace {1 2 3 4 5} 3 7 a b c } {1 2 3 a b c} test listobj-7.6 {Tcl_ListObjReplace, first element index > last index} { lreplace {1 2 3 4 5} 3 1 a b c } {1 2 3 a b c 4 5} test listobj-7.7 {Tcl_ListObjReplace, no new elements} { lreplace {1 2 3 4 5} 1 1 } {1 3 4 5} test listobj-7.8 {Tcl_ListObjReplace, shrink array in place} { lreplace {1 2 3 4 5 6 7} 4 5 } {1 2 3 4 7} test listobj-7.9 {Tcl_ListObjReplace, grow array in place} { lreplace {1 2 3 4 5 6 7} 1 3 a b c d e } {1 a b c d e 5 6 7} test listobj-7.10 {Tcl_ListObjReplace, replace tail of array} { lreplace {1 2 3 4 5 6 7} 3 6 a } {1 2 3 a} test listobj-7.11 {Tcl_ListObjReplace, must grow internal array} { lreplace {1 2 3 4 5} 2 3 a b c d e f g h i j k l } {1 2 a b c d e f g h i j k l 5} test listobj-7.12 {Tcl_ListObjReplace, grow array, insert at start} { lreplace {1 2 3 4 5} -1 -1 a b c d e f g h i j k l } {a b c d e f g h i j k l 1 2 3 4 5} test listobj-7.13 {Tcl_ListObjReplace, grow array, insert at end} { lreplace {1 2 3 4 5} 4 1 a b c d e f g h i j k l } {1 2 3 4 a b c d e f g h i j k l 5} test listobj-8.1 {SetListFromAny} { lindex {0 foo\x00help 2} 1 } "foo\x00help" test listobj-9.1 {UpdateStringOfList} { string length [list foo\x00help] } 8 test listobj-11.1 {bug 3598580} { testobj bug3598580 } 123 # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/http.test0000644003604700454610000004277612133546540013752 0ustar dgp771div# Commands covered: http::config, http::geturl, http::wait, http::reset # # This file contains a collection of tests for the http script library. # Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994-1996 Sun Microsystems, Inc. # Copyright (c) 1998-2000 by Ajuba Solutions. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import -force ::tcltest::* } if {[catch {package require http 2} version]} { if {[info exists http2]} { catch {puts "Cannot load http 2.* package"} return } else { catch {puts "Running http 2.* tests in slave interp"} set interp [interp create http2] $interp eval [list set http2 "running"] $interp eval [list set argv $argv] $interp eval [list source [info script]] interp delete $interp return } } proc bgerror {args} { global errorInfo puts stderr "http.test bgerror" puts stderr [join $args] puts stderr $errorInfo } set port 8010 set bindata "This is binary data\x0d\x0amore\x0dmore\x0amore\x00null" catch {unset data} # Ensure httpd file exists set origFile [file join [pwd] [file dirname [info script]] httpd] set httpdFile [file join [temporaryDirectory] httpd_[pid]] if {![file exists $httpdFile]} { makeFile "" $httpdFile file delete $httpdFile file copy $origFile $httpdFile set removeHttpd 1 } if {[info commands testthread] == "testthread" && [file exists $httpdFile]} { set httpthread [testthread create " source [list $httpdFile] testthread wait "] testthread send $httpthread [list set port $port] testthread send $httpthread [list set bindata $bindata] testthread send $httpthread {httpd_init $port} puts "Running httpd in thread $httpthread" } else { if {![file exists $httpdFile]} { puts "Cannot read $httpdFile script, http test skipped" unset port return } source $httpdFile # Let the OS pick the port; that's much more flexible if {[catch {httpd_init 0} listen]} { puts "Cannot start http server, http test skipped" unset port return } else { set port [lindex [fconfigure $listen -sockname] 2] } } test http-1.1 {http::config} { http::config } [list -accept */* -proxyfilter http::ProxyRequired -proxyhost {} -proxyport {} -urlencoding utf-8 -useragent "Tcl http client package $version"] test http-1.2 {http::config} { http::config -proxyfilter } http::ProxyRequired test http-1.3 {http::config} { catch {http::config -junk} } 1 test http-1.4 {http::config} { set savedconf [http::config] http::config -proxyhost nowhere.come -proxyport 8080 \ -proxyfilter myFilter -useragent "Tcl Test Suite" \ -urlencoding iso8859-1 set x [http::config] eval http::config $savedconf set x } {-accept */* -proxyfilter myFilter -proxyhost nowhere.come -proxyport 8080 -urlencoding iso8859-1 -useragent {Tcl Test Suite}} test http-1.5 {http::config} { list [catch {http::config -proxyhost {} -junk 8080} msg] $msg } {1 {Unknown option -junk, must be: -accept, -proxyfilter, -proxyhost, -proxyport, -urlencoding, -useragent}} test http-1.6 {http::config} { set enc [list [http::config -urlencoding]] http::config -urlencoding iso8859-1 lappend enc [http::config -urlencoding] http::config -urlencoding [lindex $enc 0] set enc } {utf-8 iso8859-1} test http-2.1 {http::reset} { catch {http::reset http#1} } 0 test http-3.1 {http::geturl} { list [catch {http::geturl -bogus flag} msg] $msg } {1 {Unknown option flag, can be: -binary, -blocksize, -channel, -command, -handler, -headers, -progress, -query, -queryblocksize, -querychannel, -queryprogress, -validate, -timeout, -type}} test http-3.2 {http::geturl} { catch {http::geturl http:junk} err set err } {Unsupported URL: http:junk} set url //[info hostname]:$port set badurl //[info hostname]:6666 test http-3.3 {http::geturl} { set token [http::geturl $url] http::data $token } "HTTP/1.0 TEST

Hello, World!

GET /

" set tail /a/b/c set url //[info hostname]:$port/a/b/c set fullurl http://user:pass@[info hostname]:$port/a/b/c set binurl //[info hostname]:$port/binary set posturl //[info hostname]:$port/post set badposturl //[info hostname]:$port/droppost set badcharurl //%user@[info hostname]:$port/a/^b/c set authorityurl //[info hostname]:$port test http-3.4 {http::geturl} { set token [http::geturl $url] http::data $token } "HTTP/1.0 TEST

Hello, World!

GET $tail

" proc selfproxy {host} { global port return [list [info hostname] $port] } test http-3.5 {http::geturl} { http::config -proxyfilter selfproxy set token [http::geturl $url] http::config -proxyfilter http::ProxyRequired http::data $token } "HTTP/1.0 TEST

Hello, World!

GET http:$url

" test http-3.6 {http::geturl} { http::config -proxyfilter bogus set token [http::geturl $url] http::config -proxyfilter http::ProxyRequired http::data $token } "HTTP/1.0 TEST

Hello, World!

GET $tail

" test http-3.7 {http::geturl} { set token [http::geturl $url -headers {Pragma no-cache}] http::data $token } "HTTP/1.0 TEST

Hello, World!

GET $tail

" test http-3.8 {http::geturl} { set token [http::geturl $url -query Name=Value&Foo=Bar -timeout 2000] http::data $token } "HTTP/1.0 TEST

Hello, World!

POST $tail

Query

Name
Value
Foo
Bar
" test http-3.9 {http::geturl} { set token [http::geturl $url -validate 1] http::code $token } "HTTP/1.0 200 OK" test http-3.10 {http::geturl queryprogress} { set query foo=bar set sep "" set i 0 # Create about 120K of query data while {$i < 14} { incr i append query $sep$query set sep & } proc postProgress {token x y} { global postProgress lappend postProgress $y } set postProgress {} set t [http::geturl $posturl -query $query \ -queryprogress postProgress -queryblocksize 16384] http::wait $t list [http::status $t] [string length $query] $postProgress [http::data $t] } {ok 122879 {16384 32768 49152 65536 81920 98304 114688 122879} {Got 122879 bytes}} test http-3.11 {http::geturl querychannel with -command} { set query foo=bar set sep "" set i 0 # Create about 120K of query data while {$i < 14} { incr i append query $sep$query set sep & } set file [makeFile $query outdata] set fp [open $file] proc asyncCB {token} { global postResult lappend postResult [http::data $token] } set postResult [list ] set t [http::geturl $posturl -querychannel $fp] http::wait $t set testRes [list [http::status $t] [string length $query] [http::data $t]] # Now do async http::cleanup $t close $fp set fp [open $file] set t [http::geturl $posturl -querychannel $fp -command asyncCB] set postResult [list PostStart] http::wait $t close $fp lappend testRes [http::status $t] $postResult removeFile outdata set testRes } {ok 122879 {Got 122880 bytes} ok {PostStart {Got 122880 bytes}}} # On Linux platforms when the client and server are on the same host, the # client is unable to read the server's response one it hits the write error. # The status is "eof". # On Windows, the http::wait procedure gets a "connection reset by peer" error # while reading the reply. test http-3.12 {http::geturl querychannel with aborted request} {nonPortable} { set query foo=bar set sep "" set i 0 # Create about 120K of query data while {$i < 14} { incr i append query $sep$query set sep & } set file [makeFile $query outdata] set fp [open $file] proc asyncCB {token} { global postResult lappend postResult [http::data $token] } proc postProgress {token x y} { global postProgress lappend postProgress $y } set postProgress {} # Now do async set postResult [list PostStart] if {[catch { set t [http::geturl $badposturl -querychannel $fp -command asyncCB \ -queryprogress postProgress] http::wait $t upvar #0 $t state } err]} { puts $errorInfo error $err } removeFile outdata list [http::status $t] [http::code $t] } {ok {HTTP/1.0 200 Data follows}} test http-3.13 {http::geturl socket leak test} { set chanCount [llength [file channels]] for {set i 0} {$i < 3} {incr i} { catch {http::geturl $badurl -timeout 5000} } # No extra channels should be taken expr {[llength [file channels]] == $chanCount} } 1 test http-3.14 "http::geturl $fullurl" { set token [http::geturl $fullurl -validate 1] http::code $token } "HTTP/1.0 200 OK" test http-3.15 {http::geturl parse failures} -body { http::geturl "{invalid}:url" } -returnCodes error -result {Unsupported URL: {invalid}:url} test http-3.16 {http::geturl parse failures} -body { http::geturl http:relative/url } -returnCodes error -result {Unsupported URL: http:relative/url} test http-3.17 {http::geturl parse failures} -body { http::geturl /absolute/url } -returnCodes error -result {Missing host part: /absolute/url} test http-3.18 {http::geturl parse failures} -body { http::geturl http://somewhere:123456789/ } -returnCodes error -result {Invalid port number: 123456789} test http-3.19 {http::geturl parse failures} -body { set ::http::strict 1 http::geturl http://{user}@somewhere } -returnCodes error -result {Illegal characters in URL user} test http-3.20 {http::geturl parse failures} -body { set ::http::strict 1 http::geturl http://%user@somewhere } -returnCodes error -result {Illegal encoding character usage "%us" in URL user} test http-3.21 {http::geturl parse failures} -body { set ::http::strict 1 http::geturl http://somewhere/{path} } -returnCodes error -result {Illegal characters in URL path} test http-3.22 {http::geturl parse failures} -body { set ::http::strict 1 http::geturl http://somewhere/%path } -returnCodes error -result {Illegal encoding character usage "%pa" in URL path} test http-3.23 {http::geturl parse failures} -body { set ::http::strict 1 http::geturl http://somewhere/path?{query} } -returnCodes error -result {Illegal characters in URL path} test http-3.24 {http::geturl parse failures} -body { set ::http::strict 1 http::geturl http://somewhere/path?%query } -returnCodes error -result {Illegal encoding character usage "%qu" in URL path} test http-3.25 {http::geturl parse failures} -body { set ::http::strict 0 set token [http::geturl $badcharurl] http::cleanup $token } -returnCodes ok -result {} test http-3.30 {http::geturl query without path} -body { set token [http::geturl $authorityurl?var=val] http::ncode $token } -cleanup { catch { http::cleanup $token } } -result 200 test http-3.31 {http::geturl fragment without path} -body { set token [http::geturl "$authorityurl#fragment42"] http::ncode $token } -cleanup { catch { http::cleanup $token } } -result 200 test http-4.1 {http::Event} { set token [http::geturl $url] upvar #0 $token data array set meta $data(meta) expr ($data(totalsize) == $meta(Content-Length)) } 1 test http-4.2 {http::Event} { set token [http::geturl $url] upvar #0 $token data array set meta $data(meta) string compare $data(type) [string trim $meta(Content-Type)] } 0 test http-4.3 {http::Event} { set token [http::geturl $url] http::code $token } {HTTP/1.0 200 Data follows} test http-4.4 {http::Event} { set testfile [makeFile "" testfile] set out [open $testfile w] set token [http::geturl $url -channel $out] close $out set in [open $testfile] set x [read $in] close $in removeFile $testfile set x } "HTTP/1.0 TEST

Hello, World!

GET $tail

" test http-4.5 {http::Event} { set testfile [makeFile "" testfile] set out [open $testfile w] set token [http::geturl $url -channel $out] close $out upvar #0 $token data removeFile $testfile expr $data(currentsize) == $data(totalsize) } 1 test http-4.6 {http::Event} { set testfile [makeFile "" testfile] set out [open $testfile w] set token [http::geturl $binurl -channel $out] close $out set in [open $testfile] fconfigure $in -translation binary set x [read $in] close $in removeFile $testfile set x } "$bindata[string trimleft $binurl /]" proc myProgress {token total current} { global progress httpLog if {[info exists httpLog] && $httpLog} { puts "progress $total $current" } set progress [list $total $current] } if 0 { # This test hangs on Windows95 because the client never gets EOF set httpLog 1 test http-4.6.1 {http::Event} knownBug { set token [http::geturl $url -blocksize 50 -progress myProgress] set progress } {111 111} } test http-4.7 {http::Event} { set token [http::geturl $url -progress myProgress] set progress } {111 111} test http-4.8 {http::Event} { set token [http::geturl $url] http::status $token } {ok} test http-4.9 {http::Event} { set token [http::geturl $url -progress myProgress] http::code $token } {HTTP/1.0 200 Data follows} test http-4.10 {http::Event} { set token [http::geturl $url -progress myProgress] http::size $token } {111} # Timeout cases # Short timeout to working server (the test server). This lets us try a # reset during the connection. test http-4.11 {http::Event} { set token [http::geturl $url -timeout 1 -command {#}] http::reset $token http::status $token } {reset} # Longer timeout with reset. test http-4.12 {http::Event} { set token [http::geturl $url/?timeout=10 -command {#}] http::reset $token http::status $token } {reset} # Medium timeout to working server that waits even longer. The timeout # hits while waiting for a reply. test http-4.13 {http::Event} { set token [http::geturl $url?timeout=30 -timeout 10 -command {#}] http::wait $token http::status $token } {timeout} # Longer timeout to good host, bad port, gets an error after the # connection "completes" but the socket is bad. test http-4.14 {http::Event} { set code [catch { set token [http::geturl $badurl/?timeout=10 -timeout 10000 -command {#}] if {[string length $token] == 0} { error "bogus return from http::geturl" } http::wait $token http::status $token } err] # error code varies among platforms. list $code [regexp {(connect failed|couldn't open socket)} $err] } {1 1} # Bogus host test http-4.15 {http::Event} { # This test may fail if you use a proxy server. That is to be # expected and is not a problem with Tcl. set code [catch { set token [http::geturl //not_a_host.tcl.tk -timeout 1000 -command {#}] http::wait $token http::status $token } err] # error code varies among platforms. list $code [string match "couldn't open socket*" $err] } {1 1} test http-5.1 {http::formatQuery} { http::formatQuery name1 value1 name2 "value two" } {name1=value1&name2=value%20two} # test http-5.2 obsoleted by 5.4 and 5.5 with http 2.5 test http-5.3 {http::formatQuery} { http::formatQuery lines "line1\nline2\nline3" } {lines=line1%0D%0Aline2%0D%0Aline3} test http-5.4 {http::formatQuery} { http::formatQuery name1 ~bwelch name2 \xa1\xa2\xa2 } {name1=~bwelch&name2=%C2%A1%C2%A2%C2%A2} test http-5.5 {http::formatQuery} { set enc [http::config -urlencoding] http::config -urlencoding iso8859-1 set res [http::formatQuery name1 ~bwelch name2 \xa1\xa2\xa2] http::config -urlencoding $enc set res } {name1=~bwelch&name2=%A1%A2%A2} test http-6.1 {http::ProxyRequired} { http::config -proxyhost [info hostname] -proxyport $port set token [http::geturl $url] http::wait $token http::config -proxyhost {} -proxyport {} upvar #0 $token data set data(body) } "HTTP/1.0 TEST

Hello, World!

GET http:$url

" test http-7.1 {http::mapReply} { http::mapReply "abc\$\[\]\"\\()\}\{" } {abc%24%5B%5D%22%5C%28%29%7D%7B} test http-7.2 {http::mapReply} { # RFC 2718 specifies that we pass urlencoding on utf-8 chars by default, # so make sure this gets converted to utf-8 then urlencoded. http::mapReply "\u2208" } {%E2%88%88} test http-7.3 {http::formatQuery} { set enc [http::config -urlencoding] # this would be reverting to http <=2.4 behavior http::config -urlencoding "" set res [list [catch {http::mapReply "\u2208"} msg] $msg] http::config -urlencoding $enc set res } [list 1 "can't read \"formMap(\u2208)\": no such element in array"] test http-7.4 {http::formatQuery} { set enc [http::config -urlencoding] # this would be reverting to http <=2.4 behavior w/o errors # (unknown chars become '?') http::config -urlencoding "iso8859-1" set res [http::mapReply "\u2208"] http::config -urlencoding $enc set res } {%3F} # cleanup catch {unset url} catch {unset badurl} catch {unset port} catch {unset data} if {[info exists httpthread]} { testthread send -async $httpthread { testthread exit } } else { close $listen } if {[info exists removeHttpd]} { removeFile $httpdFile } rename bgerror {} ::tcltest::cleanupTests tcl8.4.20/tests/cmdMZ.test0000644003604700454610000001500212052456744013771 0ustar dgp771div# The tests in this file cover the procedures in tclCmdMZ.c. # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2.1 namespace import -force ::tcltest::* } # Tcl_PwdObjCmd test cmdMZ-1.1 {Tcl_PwdObjCmd} { list [catch {pwd a} msg] $msg } {1 {wrong # args: should be "pwd"}} test cmdMZ-1.2 {Tcl_PwdObjCmd: simple pwd} { catch pwd } 0 test cmdMZ-1.3 {Tcl_PwdObjCmd: simple pwd} { expr [string length pwd]>0 } 1 test cmdMZ-1.4 {Tcl_PwdObjCmd: failure} {unixOnly nonPortable} { # This test fails on various unix platforms (eg Linux) where # permissions caching causes this to fail. The caching is strictly # incorrect, but we have no control over that. set foodir [file join [temporaryDirectory] foo] file delete -force $foodir file mkdir $foodir set cwd [pwd] cd $foodir file attr . -permissions 000 set result [list [catch {pwd} msg] $msg] cd $cwd file delete -force $foodir set result } {1 {error getting working directory name: permission denied}} # The tests for Tcl_RegexpObjCmd, Tcl_RegsubObjCmd are in regexp.test # Tcl_RenameObjCmd test cmdMZ-2.1 {Tcl_RenameObjCmd: error conditions} { list [catch {rename r1} msg] $msg $errorCode } {1 {wrong # args: should be "rename oldName newName"} NONE} test cmdMZ-2.2 {Tcl_RenameObjCmd: error conditions} { list [catch {rename r1 r2 r3} msg] $msg $errorCode } {1 {wrong # args: should be "rename oldName newName"} NONE} test cmdMZ-2.3 {Tcl_RenameObjCmd: success} { catch {rename r2 {}} proc r1 {} {return "r1"} rename r1 r2 r2 } {r1} test cmdMZ-2.4 {Tcl_RenameObjCmd: success} { proc r1 {} {return "r1"} rename r1 {} list [catch {r1} msg] $msg } {1 {invalid command name "r1"}} # The tests for Tcl_ReturnObjCmd are in proc-old.test # The tests for Tcl_ScanObjCmd are in scan.test # Tcl_SourceObjCmd test cmdMZ-3.3 {Tcl_SourceObjCmd: error conditions} {unixOrPc} { list [catch {source} msg] $msg } {1 {wrong # args: should be "source fileName"}} test cmdMZ-3.4 {Tcl_SourceObjCmd: error conditions} {unixOrPc} { list [catch {source a b} msg] $msg } {1 {wrong # args: should be "source fileName"}} proc ListGlobMatch {expected actual} { if {[llength $expected] != [llength $actual]} { return 0 } foreach e $expected a $actual { if {![string match $e $a]} { return 0 } } return 1 } customMatch listGlob ListGlobMatch test cmdMZ-3.5 {Tcl_SourceObjCmd: error in script} -setup { set file [makeFile { set x 146 error "error in sourced file" set y $x } source.file] } -body { list [catch {source $file} msg] $msg $errorInfo } -cleanup { removeFile source.file } -match listGlob -result {1 {error in sourced file} {error in sourced file while executing "error "error in sourced file"" (file "*" line 3) invoked from within "source $file"}} test cmdMZ-3.6 {Tcl_SourceObjCmd: simple script} { set file [makeFile {list result} source.file] set result [source $file] removeFile source.file set result } result # Tcl_SplitObjCmd test cmdMZ-4.1 {Tcl_SplitObjCmd: split errors} { list [catch split msg] $msg $errorCode } {1 {wrong # args: should be "split string ?splitChars?"} NONE} test cmdMZ-4.2 {Tcl_SplitObjCmd: split errors} { list [catch {split a b c} msg] $msg $errorCode } {1 {wrong # args: should be "split string ?splitChars?"} NONE} test cmdMZ-4.3 {Tcl_SplitObjCmd: basic split commands} { split "a\n b\t\r c\n " } {a {} b {} {} c {} {}} test cmdMZ-4.4 {Tcl_SplitObjCmd: basic split commands} { split "word 1xyzword 2zword 3" xyz } {{word 1} {} {} {word 2} {word 3}} test cmdMZ-4.5 {Tcl_SplitObjCmd: basic split commands} { split "12345" {} } {1 2 3 4 5} test cmdMZ-4.6 {Tcl_SplitObjCmd: basic split commands} { split "a\}b\[c\{\]\$" } "a\\}b\\\[c\\{\\\]\\\$" test cmdMZ-4.7 {Tcl_SplitObjCmd: basic split commands} { split {} {} } {} test cmdMZ-4.8 {Tcl_SplitObjCmd: basic split commands} { split {} } {} test cmdMZ-4.9 {Tcl_SplitObjCmd: basic split commands} { split { } } {{} {} {} {}} test cmdMZ-4.10 {Tcl_SplitObjCmd: basic split commands} { proc foo {} { set x {} foreach f [split {]\n} {}] { append x $f } return $x } foo } {]\n} test cmdMZ-4.11 {Tcl_SplitObjCmd: basic split commands} { proc foo {} { set x ab\000c set y [split $x {}] return $y } foo } "a b \000 c" test cmdMZ-4.12 {Tcl_SplitObjCmd: basic split commands} { split "a0ab1b2bbb3\000c4" ab\000c } {{} 0 {} 1 2 {} {} 3 {} 4} test cmdMZ-4.13 {Tcl_SplitObjCmd: basic split commands} { # if not UTF-8 aware, result is "a {} {} b qw\xe5 {} N wq" split "a\u4e4eb qw\u5e4e\x4e wq" " \u4e4e" } "a b qw\u5e4eN wq" # The tests for Tcl_StringObjCmd are in string.test # The tests for Tcl_SubstObjCmd are in subst.test # The tests for Tcl_SwitchObjCmd are in switch.test test cmdMZ-5.1 {Tcl_TimeObjCmd: basic format of command} { list [catch {time} msg] $msg } {1 {wrong # args: should be "time command ?count?"}} test cmdMZ-5.2 {Tcl_TimeObjCmd: basic format of command} { list [catch {time a b c} msg] $msg } {1 {wrong # args: should be "time command ?count?"}} test cmdMZ-5.3 {Tcl_TimeObjCmd: basic format of command} { list [catch {time a b} msg] $msg } {1 {expected integer but got "b"}} test cmdMZ-5.4 {Tcl_TimeObjCmd: nothing happens with negative iteration counts} { time bogusCmd -12456 } {0 microseconds per iteration} test cmdMZ-5.5 {Tcl_TimeObjCmd: result format} { regexp {^\d+ microseconds per iteration} [time {format 1}] } 1 test cmdMZ-5.6 {Tcl_TimeObjCmd: slower commands take longer} { expr {[lindex [time {after 2}] 0] < [lindex [time {after 1000}] 0]} } 1 test cmdMZ-5.7 {Tcl_TimeObjCmd: errors generate right trace} { list [catch {time {error foo}} msg] $msg $::errorInfo } {1 foo {foo while executing "error foo" invoked from within "time {error foo}"}} # The tests for Tcl_TraceObjCmd and TraceVarProc are in trace.test # The tests for Tcl_WhileObjCmd are in while.test # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/exec.test0000644003604700454610000006150111737050674013711 0ustar dgp771div# Commands covered: exec # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1994 The Regents of the University of California. # Copyright (c) 1994-1997 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. package require tcltest 2 namespace import -force ::tcltest::* # All tests require the "exec" command. # Skip them if exec is not defined. testConstraint exec [llength [info commands exec]] unset -nocomplain path set path(echo) [makeFile { puts -nonewline [lindex $argv 0] foreach str [lrange $argv 1 end] { puts -nonewline " $str" } puts {} exit } echo] set path(cat) [makeFile { if {$argv == {}} { set argv - } foreach name $argv { if {$name == "-"} { set f stdin } elseif {[catch {open $name r} f] != 0} { puts stderr $f continue } while {[eof $f] == 0} { puts -nonewline [read $f] } if {$f != "stdin"} { close $f } } exit } cat] set path(wc) [makeFile { set data [read stdin] set lines [regsub -all "\n" $data {} dummy] set words [regsub -all "\[^ \t\n]+" $data {} dummy] set chars [string length $data] puts [format "%8.d%8.d%8.d" $lines $words $chars] exit } wc] set path(sh) [makeFile { if {[lindex $argv 0] != "-c"} { error "sh: unexpected arguments $argv" } set cmd [lindex $argv 1] lappend cmd ";" set newcmd {} foreach arg $cmd { if {$arg == ";"} { eval exec >@stdout 2>@stderr [list [info nameofexecutable]] $newcmd set newcmd {} continue } if {$arg == "1>&2"} { set arg >@stderr } lappend newcmd $arg } exit } sh] set path(sleep) [makeFile { after [expr $argv*1000] exit } sleep] set path(exit) [makeFile { exit $argv } exit] # Basic operations. test exec-1.1 {basic exec operation} {exec} { exec [interpreter] $path(echo) a b c } "a b c" test exec-1.2 {pipelining} {exec stdio} { exec [interpreter] $path(echo) a b c d | [interpreter] $path(cat) | [interpreter] $path(cat) } "a b c d" test exec-1.3 {pipelining} {exec stdio} { set a [exec [interpreter] $path(echo) a b c d | [interpreter] $path(cat) | [interpreter] $path(wc)] list [scan $a "%d %d %d" b c d] $b $c } {3 1 4} set arg {12345678901234567890123456789012345678901234567890} set arg "$arg$arg$arg$arg$arg$arg" test exec-1.4 {long command lines} {exec} { exec [interpreter] $path(echo) $arg } $arg set arg {} # I/O redirection: input from Tcl command. test exec-2.1 {redirecting input from immediate source} {exec stdio} { exec [interpreter] $path(cat) << "Sample text" } {Sample text} test exec-2.2 {redirecting input from immediate source} {exec stdio} { exec << "Sample text" [interpreter] $path(cat) | [interpreter] $path(cat) } {Sample text} test exec-2.3 {redirecting input from immediate source} {exec stdio} { exec [interpreter] $path(cat) << "Sample text" | [interpreter] $path(cat) } {Sample text} test exec-2.4 {redirecting input from immediate source} {exec stdio} { exec [interpreter] $path(cat) | [interpreter] $path(cat) << "Sample text" } {Sample text} test exec-2.5 {redirecting input from immediate source} {exec} { exec [interpreter] $path(cat) "< external conversion did not # occur before writing out the temp file. exec [interpreter] $path(cat) << "\uE9\uE0\uFC\uF1" } "\uE9\uE0\uFC\uF1" # I/O redirection: output to file. set path(gorp.file) [makeFile {} gorp.file] file delete $path(gorp.file) test exec-3.1 {redirecting output to file} {exec} { exec [interpreter] $path(echo) "Some simple words" > $path(gorp.file) exec [interpreter] $path(cat) $path(gorp.file) } "Some simple words" test exec-3.2 {redirecting output to file} {exec stdio} { exec [interpreter] $path(echo) "More simple words" | >$path(gorp.file) [interpreter] $path(cat) | [interpreter] $path(cat) exec [interpreter] $path(cat) $path(gorp.file) } "More simple words" test exec-3.3 {redirecting output to file} {exec stdio} { exec > $path(gorp.file) [interpreter] $path(echo) "Different simple words" | [interpreter] $path(cat) | [interpreter] $path(cat) exec [interpreter] $path(cat) $path(gorp.file) } "Different simple words" test exec-3.4 {redirecting output to file} {exec} { exec [interpreter] $path(echo) "Some simple words" >$path(gorp.file) exec [interpreter] $path(cat) $path(gorp.file) } "Some simple words" test exec-3.5 {redirecting output to file} {exec} { exec [interpreter] $path(echo) "First line" >$path(gorp.file) exec [interpreter] $path(echo) "Second line" >> $path(gorp.file) exec [interpreter] $path(cat) $path(gorp.file) } "First line\nSecond line" test exec-3.6 {redirecting output to file} {exec} { exec [interpreter] $path(echo) "First line" >$path(gorp.file) exec [interpreter] $path(echo) "Second line" >>$path(gorp.file) exec [interpreter] $path(cat) $path(gorp.file) } "First line\nSecond line" test exec-3.7 {redirecting output to file} {exec} { set f [open $path(gorp.file) w] puts $f "Line 1" flush $f exec [interpreter] $path(echo) "More text" >@ $f exec [interpreter] $path(echo) >@$f "Even more" puts $f "Line 3" close $f exec [interpreter] $path(cat) $path(gorp.file) } "Line 1\nMore text\nEven more\nLine 3" # I/O redirection: output and stderr to file. file delete $path(gorp.file) test exec-4.1 {redirecting output and stderr to file} {exec} { exec [interpreter] "$path(echo)" "test output" >& $path(gorp.file) exec [interpreter] "$path(cat)" "$path(gorp.file)" } "test output" test exec-4.2 {redirecting output and stderr to file} {exec} { list [exec [interpreter] "$path(sh)" -c "\"$path(echo)\" foo bar 1>&2" >&$path(gorp.file)] \ [exec [interpreter] "$path(cat)" "$path(gorp.file)"] } {{} {foo bar}} test exec-4.3 {redirecting output and stderr to file} {exec} { exec [interpreter] $path(echo) "first line" > $path(gorp.file) list [exec [interpreter] "$path(sh)" -c "\"$path(echo)\" foo bar 1>&2" >>&$path(gorp.file)] \ [exec [interpreter] "$path(cat)" "$path(gorp.file)"] } "{} {first line\nfoo bar}" test exec-4.4 {redirecting output and stderr to file} {exec} { set f [open "$path(gorp.file)" w] puts $f "Line 1" flush $f exec [interpreter] "$path(echo)" "More text" >&@ $f exec [interpreter] "$path(echo)" >&@$f "Even more" puts $f "Line 3" close $f exec [interpreter] "$path(cat)" "$path(gorp.file)" } "Line 1\nMore text\nEven more\nLine 3" test exec-4.5 {redirecting output and stderr to file} {exec} { set f [open "$path(gorp.file)" w] puts $f "Line 1" flush $f exec >&@ $f [interpreter] "$path(sh)" -c "\"$path(echo)\" foo bar 1>&2" exec >&@$f [interpreter] "$path(sh)" -c "\"$path(echo)\" xyzzy 1>&2" puts $f "Line 3" close $f exec [interpreter] "$path(cat)" "$path(gorp.file)" } "Line 1\nfoo bar\nxyzzy\nLine 3" # I/O redirection: input from file. if { [set ::tcltest::testConstraints(exec)] } { exec [interpreter] $path(echo) "Just a few thoughts" > $path(gorp.file) } test exec-5.1 {redirecting input from file} {exec} { exec [interpreter] $path(cat) < $path(gorp.file) } {Just a few thoughts} test exec-5.2 {redirecting input from file} {exec stdio} { exec [interpreter] $path(cat) | [interpreter] $path(cat) < $path(gorp.file) } {Just a few thoughts} test exec-5.3 {redirecting input from file} {exec stdio} { exec [interpreter] $path(cat) < $path(gorp.file) | [interpreter] $path(cat) } {Just a few thoughts} test exec-5.4 {redirecting input from file} {exec stdio} { exec < $path(gorp.file) [interpreter] $path(cat) | [interpreter] $path(cat) } {Just a few thoughts} test exec-5.5 {redirecting input from file} {exec} { exec [interpreter] $path(cat) <$path(gorp.file) } {Just a few thoughts} test exec-5.6 {redirecting input from file} {exec} { set f [open $path(gorp.file) r] set result [exec [interpreter] $path(cat) <@ $f] close $f set result } {Just a few thoughts} test exec-5.7 {redirecting input from file} {exec} { set f [open $path(gorp.file) r] set result [exec <@$f [interpreter] $path(cat)] close $f set result } {Just a few thoughts} # I/O redirection: standard error through a pipeline. test exec-6.1 {redirecting stderr through a pipeline} {exec stdio} { exec [interpreter] "$path(sh)" -c "\"$path(echo)\" foo bar" |& [interpreter] "$path(cat)" } "foo bar" test exec-6.2 {redirecting stderr through a pipeline} {exec stdio} { exec [interpreter] "$path(sh)" -c "\"$path(echo)\" foo bar 1>&2" |& [interpreter] "$path(cat)" } "foo bar" test exec-6.3 {redirecting stderr through a pipeline} {exec stdio} { exec [interpreter] "$path(sh)" -c "\"$path(echo)\" foo bar 1>&2" \ |& [interpreter] "$path(sh)" -c "\"$path(echo)\" second msg 1>&2 ; \"$path(cat)\"" |& [interpreter] "$path(cat)" } "second msg\nfoo bar" # I/O redirection: combinations. set path(gorp.file2) [makeFile {} gorp.file2] file delete $path(gorp.file2) test exec-7.1 {multiple I/O redirections} {exec} { exec << "command input" > $path(gorp.file2) [interpreter] $path(cat) < $path(gorp.file) exec [interpreter] $path(cat) $path(gorp.file2) } {Just a few thoughts} test exec-7.2 {multiple I/O redirections} {exec} { exec < $path(gorp.file) << "command input" [interpreter] $path(cat) } {command input} # Long input to command and output from command. set a "0123456789 xxxxxxxxx abcdefghi ABCDEFGHIJK\n" set a [concat $a $a $a $a] set a [concat $a $a $a $a] set a [concat $a $a $a $a] set a [concat $a $a $a $a] test exec-8.1 {long input and output} {exec} { exec [interpreter] $path(cat) << $a } $a # More than 20 arguments to exec. test exec-8.2 {long input and output} {exec} { exec [interpreter] $path(echo) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 } {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23} # Commands that return errors. test exec-9.1 {commands returning errors} {exec} { set x [catch {exec gorp456} msg] list $x [string tolower $msg] [string tolower $errorCode] } {1 {couldn't execute "gorp456": no such file or directory} {posix enoent {no such file or directory}}} test exec-9.2 {commands returning errors} {exec} { string tolower [list [catch {exec [interpreter] echo foo | foo123} msg] $msg $errorCode] } {1 {couldn't execute "foo123": no such file or directory} {posix enoent {no such file or directory}}} test exec-9.3 {commands returning errors} {exec stdio} { list [catch {exec [interpreter] $path(sleep) 1 | [interpreter] $path(exit) 43 | [interpreter] $path(sleep) 1} msg] $msg } {1 {child process exited abnormally}} test exec-9.4 {commands returning errors} {exec stdio} { list [catch {exec [interpreter] $path(exit) 43 | [interpreter] $path(echo) "foo bar"} msg] $msg } {1 {foo bar child process exited abnormally}} test exec-9.5 {commands returning errors} {exec stdio} { list [catch {exec gorp456 | [interpreter] echo a b c} msg] [string tolower $msg] } {1 {couldn't execute "gorp456": no such file or directory}} test exec-9.6 {commands returning errors} {exec} { list [catch {exec [interpreter] "$path(sh)" -c "\"$path(echo)\" error msg 1>&2"} msg] $msg } {1 {error msg}} test exec-9.7 {commands returning errors} {exec stdio} { list [catch {exec [interpreter] "$path(sh)" -c "\"$path(echo)\" error msg 1>&2 ; \"$path(sleep)\" 1" \ | [interpreter] "$path(sh)" -c "\"$path(echo)\" error msg 1>&2 ; \"$path(sleep)\" 1"} msg] $msg } {1 {error msg error msg}} set path(err) [makeFile {} err] test exec-9.8 {commands returning errors} {exec} { set f [open $path(err) w] puts $f { puts stdout out puts stderr err } close $f list [catch {exec [interpreter] $path(err)} msg] $msg } {1 {out err}} # Errors in executing the Tcl command, as opposed to errors in the # processes that are invoked. test exec-10.1 {errors in exec invocation} {exec} { list [catch {exec} msg] $msg } {1 {wrong # args: should be "exec ?switches? arg ?arg ...?"}} test exec-10.2 {errors in exec invocation} {exec} { list [catch {exec | cat} msg] $msg } {1 {illegal use of | or |& in command}} test exec-10.3 {errors in exec invocation} {exec} { list [catch {exec cat |} msg] $msg } {1 {illegal use of | or |& in command}} test exec-10.4 {errors in exec invocation} {exec} { list [catch {exec cat | | cat} msg] $msg } {1 {illegal use of | or |& in command}} test exec-10.5 {errors in exec invocation} {exec} { list [catch {exec cat | |& cat} msg] $msg } {1 {illegal use of | or |& in command}} test exec-10.6 {errors in exec invocation} {exec} { list [catch {exec cat |&} msg] $msg } {1 {illegal use of | or |& in command}} test exec-10.7 {errors in exec invocation} {exec} { list [catch {exec cat <} msg] $msg } {1 {can't specify "<" as last word in command}} test exec-10.8 {errors in exec invocation} {exec} { list [catch {exec cat >} msg] $msg } {1 {can't specify ">" as last word in command}} test exec-10.9 {errors in exec invocation} {exec} { list [catch {exec cat <<} msg] $msg } {1 {can't specify "<<" as last word in command}} test exec-10.10 {errors in exec invocation} {exec} { list [catch {exec cat >>} msg] $msg } {1 {can't specify ">>" as last word in command}} test exec-10.11 {errors in exec invocation} {exec} { list [catch {exec cat >&} msg] $msg } {1 {can't specify ">&" as last word in command}} test exec-10.12 {errors in exec invocation} {exec} { list [catch {exec cat >>&} msg] $msg } {1 {can't specify ">>&" as last word in command}} test exec-10.13 {errors in exec invocation} {exec} { list [catch {exec cat >@} msg] $msg } {1 {can't specify ">@" as last word in command}} test exec-10.14 {errors in exec invocation} {exec} { list [catch {exec cat <@} msg] $msg } {1 {can't specify "<@" as last word in command}} test exec-10.15 {errors in exec invocation} {exec} { list [catch {exec cat < a/b/c} msg] [string tolower $msg] } {1 {couldn't read file "a/b/c": no such file or directory}} test exec-10.16 {errors in exec invocation} {exec} { list [catch {exec cat << foo > a/b/c} msg] [string tolower $msg] } {1 {couldn't write file "a/b/c": no such file or directory}} test exec-10.17 {errors in exec invocation} {exec} { list [catch {exec cat << foo > a/b/c} msg] [string tolower $msg] } {1 {couldn't write file "a/b/c": no such file or directory}} set f [open $path(gorp.file) w] test exec-10.18 {errors in exec invocation} {exec} { list [catch {exec cat <@ $f} msg] $msg } "1 {channel \"$f\" wasn't opened for reading}" close $f set f [open $path(gorp.file) r] test exec-10.19 {errors in exec invocation} {exec} { list [catch {exec cat >@ $f} msg] $msg } "1 {channel \"$f\" wasn't opened for writing}" close $f test exec-10.20 {errors in exec invocation} {exec} { list [catch {exec ~non_existent_user/foo/bar} msg] $msg } {1 {user "non_existent_user" doesn't exist}} test exec-10.21 {errors in exec invocation} {exec} { list [catch {exec [interpreter] true | ~xyzzy_bad_user/x | false} msg] $msg } {1 {user "xyzzy_bad_user" doesn't exist}} test exec-10.22 {errors in exec invocation} \ -constraints exec \ -returnCodes 1 \ -body {exec echo test > ~non_existent_user/foo/bar} \ -result {user "non_existent_user" doesn't exist} # Commands in background. test exec-11.1 {commands in background} {exec} { set x [lindex [time {exec [interpreter] $path(sleep) 2 &}] 0] expr $x<1000000 } 1 test exec-11.2 {commands in background} {exec} { list [catch {exec [interpreter] $path(echo) a &b} msg] $msg } {0 {a &b}} test exec-11.3 {commands in background} {exec} { llength [exec [interpreter] $path(sleep) 1 &] } 1 test exec-11.4 {commands in background} {exec stdio} { llength [exec [interpreter] $path(sleep) 1 | [interpreter] $path(sleep) 1 | [interpreter] $path(sleep) 1 &] } 3 test exec-11.5 {commands in background} {exec} { set f [open $path(gorp.file) w] puts $f [list catch [list exec [info nameofexecutable] $path(echo) foo &]] close $f string compare "foo" [exec [interpreter] $path(gorp.file)] } 0 # Make sure that background commands are properly reaped when # they eventually die. if { [set ::tcltest::testConstraints(exec)] } { exec [interpreter] $path(sleep) 3 } test exec-12.1 {reaping background processes} \ {exec unixOnly nonPortable} { for {set i 0} {$i < 20} {incr i} { exec echo foo > /dev/null & } exec sleep 1 catch {exec ps | fgrep "echo foo" | fgrep -v fgrep | wc} msg lindex $msg 0 } 0 test exec-12.2 {reaping background processes} \ {exec unixOnly nonPortable} { exec sleep 2 | sleep 2 | sleep 2 & catch {exec ps | fgrep -i "sleep" | fgrep -i -v fgrep | wc} msg set x [lindex $msg 0] exec sleep 3 catch {exec ps | fgrep -i "sleep" | fgrep -i -v fgrep | wc} msg list $x [lindex $msg 0] } {3 0} test exec-12.3 {reaping background processes} \ {exec unixOnly nonPortable} { exec sleep 1000 & exec sleep 1000 & set x [exec ps | fgrep "sleep" | fgrep -v fgrep] set pids {} foreach i [split $x \n] { lappend pids [lindex $i 0] } foreach i $pids { catch {exec kill -STOP $i} } catch {exec ps | fgrep "sleep" | fgrep -v fgrep | wc} msg set x [lindex $msg 0] foreach i $pids { catch {exec kill -KILL $i} } catch {exec ps | fgrep "sleep" | fgrep -v fgrep | wc} msg list $x [lindex $msg 0] } {2 0} # Make sure "errorCode" is set correctly. test exec-13.1 {setting errorCode variable} {exec} { list [catch {exec [interpreter] $path(cat) < a/b/c} msg] [string tolower $errorCode] } {1 {posix enoent {no such file or directory}}} test exec-13.2 {setting errorCode variable} {exec} { list [catch {exec [interpreter] $path(cat) > a/b/c} msg] [string tolower $errorCode] } {1 {posix enoent {no such file or directory}}} test exec-13.3 {setting errorCode variable} {exec} { set x [catch {exec _weird_cmd_} msg] list $x [string tolower $msg] [lindex $errorCode 0] \ [string tolower [lrange $errorCode 2 end]] } {1 {couldn't execute "_weird_cmd_": no such file or directory} POSIX {{no such file or directory}}} test exec-13.4 {extended exit result codes} { -constraints {win} -setup { set tmp [makeFile {exit 0x00000101} tmpfile.exec-13.4] } -body { list [catch {exec [interpreter] $tmp} err]\ [lreplace $::errorCode 1 1 {}] } -cleanup { removeFile $tmp } -result {1 {CHILDSTATUS {} 257}} } test exec-13.5 {extended exit result codes: max value} { -constraints {win} -setup { set tmp [makeFile {exit 0x3fffffff} tmpfile.exec-13.5] } -body { list [catch {exec [interpreter] $tmp} err]\ [lreplace $::errorCode 1 1 {}] } -cleanup { removeFile $tmp } -result {1 {CHILDSTATUS {} 1073741823}} } test exec-13.6 {extended exit result codes: signalled} { -constraints {win} -setup { set tmp [makeFile {exit 0xffffffff} tmpfile.exec-13.6] } -body { list [catch {exec [interpreter] $tmp} err]\ [lreplace $::errorCode 1 1 {}] } -cleanup { removeFile $tmp } -result {1 {CHILDKILLED {} SIGABRT SIGABRT}} } # Switches before the first argument test exec-14.1 {-keepnewline switch} {exec} { exec -keepnewline [interpreter] $path(echo) foo } "foo\n" test exec-14.2 {-keepnewline switch} {exec} { list [catch {exec -keepnewline} msg] $msg } {1 {wrong # args: should be "exec ?switches? arg ?arg ...?"}} test exec-14.3 {unknown switch} {exec} { list [catch {exec -gorp} msg] $msg } {1 {bad switch "-gorp": must be -keepnewline or --}} test exec-14.4 {-- switch} {exec} { list [catch {exec -- -gorp} msg] [string tolower $msg] } {1 {couldn't execute "-gorp": no such file or directory}} # Redirecting standard error separately from standard output test exec-15.1 {standard error redirection} {exec} { exec [interpreter] "$path(echo)" "First line" > "$path(gorp.file)" list [exec [interpreter] "$path(sh)" -c "\"$path(echo)\" foo bar 1>&2" 2> "$path(gorp.file)"] \ [exec [interpreter] "$path(cat)" "$path(gorp.file)"] } {{} {foo bar}} test exec-15.2 {standard error redirection} {exec stdio} { list [exec [interpreter] "$path(sh)" -c "\"$path(echo)\" foo bar 1>&2" \ | [interpreter] "$path(echo)" biz baz >$path(gorp.file) 2> "$path(gorp.file2)"] \ [exec [interpreter] "$path(cat)" "$path(gorp.file)"] \ [exec [interpreter] "$path(cat)" "$path(gorp.file2)"] } {{} {biz baz} {foo bar}} test exec-15.3 {standard error redirection} {exec stdio} { list [exec [interpreter] "$path(sh)" -c "\"$path(echo)\" foo bar 1>&2" \ | [interpreter] "$path(echo)" biz baz 2>$path(gorp.file) > "$path(gorp.file2)"] \ [exec [interpreter] "$path(cat)" "$path(gorp.file)"] \ [exec [interpreter] "$path(cat)" "$path(gorp.file2)"] } {{} {foo bar} {biz baz}} test exec-15.4 {standard error redirection} {exec} { set f [open "$path(gorp.file)" w] puts $f "Line 1" flush $f exec [interpreter] "$path(sh)" -c "\"$path(echo)\" foo bar 1>&2" 2>@ $f puts $f "Line 3" close $f exec [interpreter] "$path(cat)" "$path(gorp.file)" } {Line 1 foo bar Line 3} test exec-15.5 {standard error redirection} {exec} { exec [interpreter] "$path(echo)" "First line" > "$path(gorp.file)" exec [interpreter] "$path(sh)" -c "\"$path(echo)\" foo bar 1>&2" 2>> "$path(gorp.file)" exec [interpreter] "$path(cat)" "$path(gorp.file)" } {First line foo bar} test exec-15.6 {standard error redirection} {exec stdio} { exec [interpreter] "$path(sh)" -c "\"$path(echo)\" foo bar 1>&2" > "$path(gorp.file2)" 2> "$path(gorp.file)" \ >& "$path(gorp.file)" 2> "$path(gorp.file2)" | [interpreter] "$path(echo)" biz baz list [exec [interpreter] "$path(cat)" "$path(gorp.file)"] [exec [interpreter] "$path(cat)" "$path(gorp.file2)"] } {{biz baz} {foo bar}} test exec-15.7 {standard error redirection 2>@1} {exec stdio} { # This redirects stderr output into normal result output from exec exec [interpreter] "$path(sh)" -c "\"$path(echo)\" foo bar 1>&2" 2>@1 } {foo bar} test exec-16.1 {flush output before exec} {exec} { set f [open $path(gorp.file) w] puts $f "First line" exec [interpreter] $path(echo) "Second line" >@ $f puts $f "Third line" close $f exec [interpreter] $path(cat) $path(gorp.file) } {First line Second line Third line} test exec-16.2 {flush output before exec} {exec} { set f [open $path(gorp.file) w] puts $f "First line" exec [interpreter] << {puts stderr {Second line}} >&@ $f > $path(gorp.file2) puts $f "Third line" close $f exec [interpreter] $path(cat) $path(gorp.file) } {First line Second line Third line} set path(script) [makeFile {} script] test exec-17.1 { inheriting standard I/O } {exec} { set f [open $path(script) w] puts -nonewline $f {close stdout set f [} puts $f [list open $path(gorp.file) w]] puts $f [list catch \ [list exec [info nameofexecutable] $path(echo) foobar &]] puts $f [list exec [info nameofexecutable] $path(sleep) 2] puts $f {close $f} close $f catch {exec [interpreter] $path(script)} result set f [open $path(gorp.file) r] lappend result [read $f] close $f set result } {{foobar }} test exec-18.1 { exec cat deals with weird file names} {exec tempNotWin} { # This is cross-platform, but the cat isn't predictably correct on # Windows. set f "foo\[\{blah" set path(fooblah) [makeFile {} $f] set fout [open $path(fooblah) w] puts $fout "contents" close $fout set res [list [catch {exec cat $path(fooblah)} msg] $msg] removeFile $f set res } {0 contents} # Note that this test cannot be adapted to work on Windows; that platform has # no kernel support for an analog of O_APPEND. test exec-19.1 {exec >> uses O_APPEND} { -constraints {exec unix} -setup { set tmpfile [makeFile {0} tmpfile.exec-19.1] } -body { # Note that we have to allow for the current contents of the # temporary file, which is why the result is 14 and not 12 exec /bin/sh -c \ {for a in 1 2 3; do sleep 1; echo $a; done} >>$tmpfile & exec /bin/sh -c \ {for a in a b c; do sleep 1; echo $a; done} >>$tmpfile & # The above two shell invokations take about 3 seconds to # finish, so allow 5s (in case the machine is busy) after 5000 # Check that no bytes have got lost through mixups with # overlapping appends, which is only guaranteed to work when # we set O_APPEND on the file descriptor in the [exec >>...] file size $tmpfile } -cleanup { removeFile $tmpfile } -result 14 } # cleanup foreach file {script gorp.file gorp.file2 echo cat wc sh sleep exit err} { removeFile $file } unset -nocomplain path ::tcltest::cleanupTests return tcl8.4.20/tests/cmdAH.test0000644003604700454610000013657012133546540013743 0ustar dgp771div# The file tests the tclCmdAH.c file. # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1996-1998 by Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2.1 namespace import -force ::tcltest::* } tcltest::testConstraint testchmod [string equal testchmod [info commands testchmod]] global env set cmdAHwd [pwd] catch {set platform [testgetplatform]} test cmdAH-0.1 {Tcl_BreakObjCmd, errors} { list [catch {break foo} msg] $msg } {1 {wrong # args: should be "break"}} test cmdAH-0.2 {Tcl_BreakObjCmd, success} { list [catch {break} msg] $msg } {3 {}} # Tcl_CaseObjCmd is tested in case.test test cmdAH-1.1 {Tcl_CatchObjCmd, errors} { list [catch {catch} msg] $msg } {1 {wrong # args: should be "catch command ?varName?"}} test cmdAH-1.2 {Tcl_CatchObjCmd, errors} { list [catch {catch foo bar baz} msg] $msg } {1 {wrong # args: should be "catch command ?varName?"}} test cmdAH-2.1 {Tcl_CdObjCmd} { list [catch {cd foo bar} msg] $msg } {1 {wrong # args: should be "cd ?dirName?"}} set foodir [file join [temporaryDirectory] foo] test cmdAH-2.2 {Tcl_CdObjCmd} { file delete -force $foodir file mkdir $foodir cd $foodir set result [file tail [pwd]] cd .. file delete $foodir set result } foo test cmdAH-2.3 {Tcl_CdObjCmd} { global env set oldpwd [pwd] set temp $env(HOME) set env(HOME) $oldpwd file delete -force $foodir file mkdir $foodir cd $foodir cd ~ set result [string equal [pwd] $oldpwd] file delete $foodir set env(HOME) $temp set result } 1 test cmdAH-2.4 {Tcl_CdObjCmd} { global env set oldpwd [pwd] set temp $env(HOME) set env(HOME) $oldpwd file delete -force $foodir file mkdir $foodir cd $foodir cd set result [string equal [pwd] $oldpwd] file delete $foodir set env(HOME) $temp set result } 1 test cmdAH-2.5 {Tcl_CdObjCmd} { list [catch {cd ~~} msg] $msg } {1 {user "~" doesn't exist}} test cmdAH-2.6 {Tcl_CdObjCmd} { list [catch {cd _foobar} msg] $msg } {1 {couldn't change working directory to "_foobar": no such file or directory}} test cmdAH-2.6.1 {Tcl_CdObjCmd} { list [catch {cd ""} msg] $msg } {1 {couldn't change working directory to "": no such file or directory}} test cmdAH-2.7 {Tcl_ConcatObjCmd} { concat } {} test cmdAH-2.8 {Tcl_ConcatObjCmd} { concat a } a test cmdAH-2.9 {Tcl_ConcatObjCmd} { concat a {b c} } {a b c} test cmdAH-3.1 {Tcl_ContinueObjCmd, errors} { list [catch {continue foo} msg] $msg } {1 {wrong # args: should be "continue"}} test cmdAH-3.2 {Tcl_ContinueObjCmd, success} { list [catch {continue} msg] $msg } {4 {}} test cmdAH-4.1 {Tcl_EncodingObjCmd} { list [catch {encoding} msg] $msg } {1 {wrong # args: should be "encoding option ?arg ...?"}} test cmdAH-4.2 {Tcl_EncodingObjCmd} { list [catch {encoding foo} msg] $msg } {1 {bad option "foo": must be convertfrom, convertto, names, or system}} test cmdAH-4.3 {Tcl_EncodingObjCmd} { list [catch {encoding convertto} msg] $msg } {1 {wrong # args: should be "encoding convertto ?encoding? data"}} test cmdAH-4.4 {Tcl_EncodingObjCmd} { list [catch {encoding convertto foo bar} msg] $msg } {1 {unknown encoding "foo"}} test cmdAH-4.5 {Tcl_EncodingObjCmd} { set system [encoding system] encoding system jis0208 set x [encoding convertto \u4e4e] encoding system $system set x } 8C test cmdAH-4.6 {Tcl_EncodingObjCmd} { set system [encoding system] encoding system identity set x [encoding convertto jis0208 \u4e4e] encoding system $system set x } 8C test cmdAH-4.7 {Tcl_EncodingObjCmd} { list [catch {encoding convertfrom} msg] $msg } {1 {wrong # args: should be "encoding convertfrom ?encoding? data"}} test cmdAH-4.8 {Tcl_EncodingObjCmd} { list [catch {encoding convertfrom foo bar} msg] $msg } {1 {unknown encoding "foo"}} test cmdAH-4.9 {Tcl_EncodingObjCmd} { set system [encoding system] encoding system jis0208 set x [encoding convertfrom 8C] encoding system $system set x } \u4e4e test cmdAH-4.10 {Tcl_EncodingObjCmd} { set system [encoding system] encoding system identity set x [encoding convertfrom jis0208 8C] encoding system $system set x } \u4e4e test cmdAH-4.11 {Tcl_EncodingObjCmd} { list [catch {encoding names foo} msg] $msg } {1 {wrong # args: should be "encoding names"}} test cmdAH-4.12 {Tcl_EncodingObjCmd} { list [catch {encoding system foo bar} msg] $msg } {1 {wrong # args: should be "encoding system ?encoding?"}} test cmdAH-4.13 {Tcl_EncodingObjCmd} { set system [encoding system] encoding system identity set x [encoding system] encoding system $system set x } identity test cmdAH-5.1 {Tcl_FileObjCmd} { list [catch file msg] $msg } {1 {wrong # args: should be "file option ?arg ...?"}} test cmdAH-5.2 {Tcl_FileObjCmd} { list [catch {file x} msg] $msg } {1 {bad option "x": must be atime, attributes, channels, copy, delete, dirname, executable, exists, extension, isdirectory, isfile, join, link, lstat, mtime, mkdir, nativename, normalize, owned, pathtype, readable, readlink, rename, rootname, separator, size, split, stat, system, tail, type, volumes, or writable}} test cmdAH-5.3 {Tcl_FileObjCmd} { list [catch {file exists} msg] $msg } {1 {wrong # args: should be "file exists name"}} test cmdAH-5.4 {Tcl_FileObjCmd} { list [catch {file exists ""} msg] $msg } {0 0} #volume test cmdAH-6.1 {Tcl_FileObjCmd: volumes} { list [catch {file volumes x} msg] $msg } {1 {wrong # args: should be "file volumes"}} test cmdAH-6.2 {Tcl_FileObjCmd: volumes} { set volumeList [file volumes] if { [llength $volumeList] == 0 } { set result 0 } else { set result 1 } } {1} test cmdAH-6.3 {Tcl_FileObjCmd: volumes} {macOrUnix} { set volumeList [file volumes] catch [list glob -nocomplain [lindex $volumeList 0]*] } {0} test cmdAH-6.4 {Tcl_FileObjCmd: volumes} winOnly { set volumeList [string tolower [file volumes]] list [catch {lsearch $volumeList "c:/"} element] [expr $element != -1] [catch {list glob -nocomplain [lindex $volumeList $element]*}] } {0 1 0} test cmdAH-6.5 {cd} {unixOnly nonPortable} { set dir [pwd] cd / set res [pwd] cd $dir set res } {/} # attributes test cmdAH-7.1 {Tcl_FileObjCmd - file attrs} { set foofile [makeFile abcde foo.file] catch {file delete -force $foofile} close [open $foofile w] set res [catch {file attributes $foofile}] # We used [makeFile] so we undo with [removeFile] removeFile $foofile set res } {0} # dirname if {[info commands testsetplatform] == {}} { puts "This application hasn't been compiled with the \"testsetplatform\"" puts "command, so I can't test Tcl_FileObjCmd etc." } else { test cmdAH-8.1 {Tcl_FileObjCmd: dirname} { testsetplatform unix list [catch {file dirname a b} msg] $msg } {1 {wrong # args: should be "file dirname name"}} test cmdAH-8.2 {Tcl_FileObjCmd: dirname} { testsetplatform unix file dirname /a/b } /a test cmdAH-8.3 {Tcl_FileObjCmd: dirname} { testsetplatform unix file dirname {} } . test cmdAH-8.5 {Tcl_FileObjCmd: dirname} { testsetplatform win file dirname {} } . test cmdAH-8.6 {Tcl_FileObjCmd: dirname} { testsetplatform unix file dirname .def } . test cmdAH-8.8 {Tcl_FileObjCmd: dirname} { testsetplatform win file dirname a } . test cmdAH-8.9 {Tcl_FileObjCmd: dirname} { testsetplatform unix file dirname a/b/c.d } a/b test cmdAH-8.10 {Tcl_FileObjCmd: dirname} { testsetplatform unix file dirname a/b.c/d } a/b.c test cmdAH-8.11 {Tcl_FileObjCmd: dirname} { testsetplatform unix file dirname /. } / test cmdAH-8.12 {Tcl_FileObjCmd: dirname} { testsetplatform unix list [catch {file dirname /} msg] $msg } {0 /} test cmdAH-8.13 {Tcl_FileObjCmd: dirname} { testsetplatform unix list [catch {file dirname /foo} msg] $msg } {0 /} test cmdAH-8.14 {Tcl_FileObjCmd: dirname} { testsetplatform unix list [catch {file dirname //foo} msg] $msg } {0 /} test cmdAH-8.15 {Tcl_FileObjCmd: dirname} { testsetplatform unix list [catch {file dirname //foo/bar} msg] $msg } {0 /foo} test cmdAH-8.16 {Tcl_FileObjCmd: dirname} { testsetplatform unix list [catch {file dirname {//foo\/bar/baz}} msg] $msg } {0 {/foo\/bar}} test cmdAH-8.17 {Tcl_FileObjCmd: dirname} { testsetplatform unix list [catch {file dirname {//foo\/bar/baz/blat}} msg] $msg } {0 {/foo\/bar/baz}} test cmdAH-8.18 {Tcl_FileObjCmd: dirname} { testsetplatform unix list [catch {file dirname /foo//} msg] $msg } {0 /} test cmdAH-8.19 {Tcl_FileObjCmd: dirname} { testsetplatform unix list [catch {file dirname ./a} msg] $msg } {0 .} test cmdAH-8.20 {Tcl_FileObjCmd: dirname} { testsetplatform unix list [catch {file dirname a/.a} msg] $msg } {0 a} test cmdAH-8.21 {Tcl_FileObjCmd: dirname} { testsetplatform windows list [catch {file dirname c:foo} msg] $msg } {0 c:} test cmdAH-8.22 {Tcl_FileObjCmd: dirname} { testsetplatform windows list [catch {file dirname c:} msg] $msg } {0 c:} test cmdAH-8.23 {Tcl_FileObjCmd: dirname} { testsetplatform windows list [catch {file dirname c:/} msg] $msg } {0 c:/} test cmdAH-8.24 {Tcl_FileObjCmd: dirname} { testsetplatform windows list [catch {file dirname {c:\foo}} msg] $msg } {0 c:/} test cmdAH-8.25 {Tcl_FileObjCmd: dirname} { testsetplatform windows list [catch {file dirname {//foo/bar/baz}} msg] $msg } {0 //foo/bar} test cmdAH-8.26 {Tcl_FileObjCmd: dirname} { testsetplatform windows list [catch {file dirname {//foo/bar}} msg] $msg } {0 //foo/bar} test cmdAH-8.38 {Tcl_FileObjCmd: dirname} { testsetplatform unix list [catch {file dirname ~/foo} msg] $msg } {0 ~} test cmdAH-8.39 {Tcl_FileObjCmd: dirname} { testsetplatform unix list [catch {file dirname ~bar/foo} msg] $msg } {0 ~bar} test cmdAH-8.43 {Tcl_FileObjCmd: dirname} { global env set temp $env(HOME) set env(HOME) "/homewontexist/test" testsetplatform unix set result [list [catch {file dirname ~} msg] $msg] set env(HOME) $temp set result } {0 /homewontexist} test cmdAH-8.44 {Tcl_FileObjCmd: dirname} { global env set temp $env(HOME) set env(HOME) "~" testsetplatform unix set result [list [catch {file dirname ~} msg] $msg] set env(HOME) $temp set result } {0 ~} test cmdAH-8.45 {Tcl_FileObjCmd: dirname} { global env set temp $env(HOME) set env(HOME) "/homewontexist/test" testsetplatform windows set result [list [catch {file dirname ~} msg] $msg] set env(HOME) $temp set result } {0 /homewontexist} # tail test cmdAH-9.1 {Tcl_FileObjCmd: tail} { testsetplatform unix list [catch {file tail a b} msg] $msg } {1 {wrong # args: should be "file tail name"}} test cmdAH-9.2 {Tcl_FileObjCmd: tail} { testsetplatform unix file tail /a/b } b test cmdAH-9.3 {Tcl_FileObjCmd: tail} { testsetplatform unix file tail {} } {} test cmdAH-9.5 {Tcl_FileObjCmd: tail} { testsetplatform win file tail {} } {} test cmdAH-9.6 {Tcl_FileObjCmd: tail} { testsetplatform unix file tail .def } .def test cmdAH-9.8 {Tcl_FileObjCmd: tail} { testsetplatform win file tail a } a test cmdAH-9.9 {Tcl_FileObjCmd: tail} { testsetplatform unix file ta a/b/c.d } c.d test cmdAH-9.10 {Tcl_FileObjCmd: tail} { testsetplatform unix file tail a/b.c/d } d test cmdAH-9.11 {Tcl_FileObjCmd: tail} { testsetplatform unix file tail /. } . test cmdAH-9.12 {Tcl_FileObjCmd: tail} { testsetplatform unix file tail / } {} test cmdAH-9.13 {Tcl_FileObjCmd: tail} { testsetplatform unix file tail /foo } foo test cmdAH-9.14 {Tcl_FileObjCmd: tail} { testsetplatform unix file tail //foo } foo test cmdAH-9.15 {Tcl_FileObjCmd: tail} { testsetplatform unix file tail //foo/bar } bar test cmdAH-9.16 {Tcl_FileObjCmd: tail} { testsetplatform unix file tail {//foo\/bar/baz} } baz test cmdAH-9.17 {Tcl_FileObjCmd: tail} { testsetplatform unix file tail {//foo\/bar/baz/blat} } blat test cmdAH-9.18 {Tcl_FileObjCmd: tail} { testsetplatform unix file tail /foo// } foo test cmdAH-9.19 {Tcl_FileObjCmd: tail} { testsetplatform unix file tail ./a } a test cmdAH-9.20 {Tcl_FileObjCmd: tail} { testsetplatform unix file tail a/.a } .a test cmdAH-9.21 {Tcl_FileObjCmd: tail} { testsetplatform windows file tail c:foo } foo test cmdAH-9.22 {Tcl_FileObjCmd: tail} { testsetplatform windows file tail c: } {} test cmdAH-9.23 {Tcl_FileObjCmd: tail} { testsetplatform windows file tail c:/ } {} test cmdAH-9.24 {Tcl_FileObjCmd: tail} { testsetplatform windows file tail {c:\foo} } foo test cmdAH-9.25 {Tcl_FileObjCmd: tail} { testsetplatform windows file tail {//foo/bar/baz} } baz test cmdAH-9.26 {Tcl_FileObjCmd: tail} { testsetplatform windows file tail {//foo/bar} } {} test cmdAH-9.42 {Tcl_FileObjCmd: tail} { global env set temp $env(HOME) set env(HOME) "/home/test" testsetplatform unix set result [file tail ~] set env(HOME) $temp set result } test test cmdAH-9.43 {Tcl_FileObjCmd: tail} { global env set temp $env(HOME) set env(HOME) "~" testsetplatform unix set result [file tail ~] set env(HOME) $temp set result } {} test cmdAH-9.44 {Tcl_FileObjCmd: tail} { global env set temp $env(HOME) set env(HOME) "/home/test" testsetplatform windows set result [file tail ~] set env(HOME) $temp set result } test test cmdAH-9.46 {Tcl_FileObjCmd: tail} { testsetplatform unix file tail {f.oo\bar/baz.bat} } baz.bat test cmdAH-9.47 {Tcl_FileObjCmd: tail} { testsetplatform windows file tail c:foo } foo test cmdAH-9.48 {Tcl_FileObjCmd: tail} { testsetplatform windows file tail c: } {} test cmdAH-9.49 {Tcl_FileObjCmd: tail} { testsetplatform windows file tail c:/foo } foo test cmdAH-9.50 {Tcl_FileObjCmd: tail} { testsetplatform windows file tail {c:/foo\bar} } bar test cmdAH-9.51 {Tcl_FileObjCmd: tail} { testsetplatform windows file tail {foo\bar} } bar # rootname test cmdAH-10.1 {Tcl_FileObjCmd: rootname} { testsetplatform unix list [catch {file rootname a b} msg] $msg } {1 {wrong # args: should be "file rootname name"}} test cmdAH-10.2 {Tcl_FileObjCmd: rootname} { testsetplatform unix file rootname {} } {} test cmdAH-10.3 {Tcl_FileObjCmd: rootname} { testsetplatform unix file ro foo } foo test cmdAH-10.4 {Tcl_FileObjCmd: rootname} { testsetplatform unix file rootname foo. } foo test cmdAH-10.5 {Tcl_FileObjCmd: rootname} { testsetplatform unix file rootname .foo } {} test cmdAH-10.6 {Tcl_FileObjCmd: rootname} { testsetplatform unix file rootname abc.def } abc test cmdAH-10.7 {Tcl_FileObjCmd: rootname} { testsetplatform unix file rootname abc.def.ghi } abc.def test cmdAH-10.8 {Tcl_FileObjCmd: rootname} { testsetplatform unix file rootname a/b/c.d } a/b/c test cmdAH-10.9 {Tcl_FileObjCmd: rootname} { testsetplatform unix file rootname a/b.c/d } a/b.c/d test cmdAH-10.10 {Tcl_FileObjCmd: rootname} { testsetplatform unix file rootname a/b.c/ } a/b.c/ test cmdAH-10.23 {Tcl_FileObjCmd: rootname} { testsetplatform windows file rootname {} } {} test cmdAH-10.24 {Tcl_FileObjCmd: rootname} { testsetplatform windows file ro foo } foo test cmdAH-10.25 {Tcl_FileObjCmd: rootname} { testsetplatform windows file rootname foo. } foo test cmdAH-10.26 {Tcl_FileObjCmd: rootname} { testsetplatform windows file rootname .foo } {} test cmdAH-10.27 {Tcl_FileObjCmd: rootname} { testsetplatform windows file rootname abc.def } abc test cmdAH-10.28 {Tcl_FileObjCmd: rootname} { testsetplatform windows file rootname abc.def.ghi } abc.def test cmdAH-10.29 {Tcl_FileObjCmd: rootname} { testsetplatform windows file rootname a/b/c.d } a/b/c test cmdAH-10.30 {Tcl_FileObjCmd: rootname} { testsetplatform windows file rootname a/b.c/d } a/b.c/d test cmdAH-10.31 {Tcl_FileObjCmd: rootname} { testsetplatform windows file rootname a\\b.c\\ } a\\b.c\\ test cmdAH-10.32 {Tcl_FileObjCmd: rootname} { testsetplatform windows file rootname a\\b\\c.d } a\\b\\c test cmdAH-10.33 {Tcl_FileObjCmd: rootname} { testsetplatform windows file rootname a\\b.c\\d } a\\b.c\\d test cmdAH-10.34 {Tcl_FileObjCmd: rootname} { testsetplatform windows file rootname a\\b.c\\ } a\\b.c\\ set num 35 foreach outer { {} a .a a. a.a } { foreach inner { {} a .a a. a.a } { set thing [format %s/%s $outer $inner] ; test cmdAH-6.$num {Tcl_FileObjCmd: rootname and extension options} { testsetplatform unix format %s%s [file rootname $thing] [file ext $thing] } $thing set num [expr $num+1] } } # extension test cmdAH-11.1 {Tcl_FileObjCmd: extension} { testsetplatform unix list [catch {file extension a b} msg] $msg } {1 {wrong # args: should be "file extension name"}} test cmdAH-11.2 {Tcl_FileObjCmd: extension} { testsetplatform unix file extension {} } {} test cmdAH-11.3 {Tcl_FileObjCmd: extension} { testsetplatform unix file ext foo } {} test cmdAH-11.4 {Tcl_FileObjCmd: extension} { testsetplatform unix file extension foo. } . test cmdAH-11.5 {Tcl_FileObjCmd: extension} { testsetplatform unix file extension .foo } .foo test cmdAH-11.6 {Tcl_FileObjCmd: extension} { testsetplatform unix file extension abc.def } .def test cmdAH-11.7 {Tcl_FileObjCmd: extension} { testsetplatform unix file extension abc.def.ghi } .ghi test cmdAH-11.8 {Tcl_FileObjCmd: extension} { testsetplatform unix file extension a/b/c.d } .d test cmdAH-11.9 {Tcl_FileObjCmd: extension} { testsetplatform unix file extension a/b.c/d } {} test cmdAH-11.10 {Tcl_FileObjCmd: extension} { testsetplatform unix file extension a/b.c/ } {} test cmdAH-11.23 {Tcl_FileObjCmd: extension} { testsetplatform windows file extension {} } {} test cmdAH-11.24 {Tcl_FileObjCmd: extension} { testsetplatform windows file ext foo } {} test cmdAH-11.25 {Tcl_FileObjCmd: extension} { testsetplatform windows file extension foo. } . test cmdAH-11.26 {Tcl_FileObjCmd: extension} { testsetplatform windows file extension .foo } .foo test cmdAH-11.27 {Tcl_FileObjCmd: extension} { testsetplatform windows file extension abc.def } .def test cmdAH-11.28 {Tcl_FileObjCmd: extension} { testsetplatform windows file extension abc.def.ghi } .ghi test cmdAH-11.29 {Tcl_FileObjCmd: extension} { testsetplatform windows file extension a/b/c.d } .d test cmdAH-11.30 {Tcl_FileObjCmd: extension} { testsetplatform windows file extension a/b.c/d } {} test cmdAH-11.31 {Tcl_FileObjCmd: extension} { testsetplatform windows file extension a\\b.c\\ } {} test cmdAH-11.32 {Tcl_FileObjCmd: extension} { testsetplatform windows file extension a\\b\\c.d } .d test cmdAH-11.33 {Tcl_FileObjCmd: extension} { testsetplatform windows file extension a\\b.c\\d } {} test cmdAH-11.34 {Tcl_FileObjCmd: extension} { testsetplatform windows file extension a\\b.c\\ } {} set num 35 foreach value {a..b a...b a.c..b ..b} result {.b .b .b .b} { foreach p {unix windows} { ; test cmdAH-7.$num {Tcl_FileObjCmd: extension} " testsetplatform $p file extension $value " $result incr num } } # pathtype test cmdAH-12.1 {Tcl_FileObjCmd: pathtype} { testsetplatform unix list [catch {file pathtype a b} msg] $msg } {1 {wrong # args: should be "file pathtype name"}} test cmdAH-12.2 {Tcl_FileObjCmd: pathtype} { testsetplatform unix file pathtype /a } absolute test cmdAH-12.3 {Tcl_FileObjCmd: pathtype} { testsetplatform unix file p a } relative test cmdAH-12.4 {Tcl_FileObjCmd: pathtype} { testsetplatform windows file pathtype c:a } volumerelative # split test cmdAH-13.1 {Tcl_FileObjCmd: split} { testsetplatform unix list [catch {file split a b} msg] $msg } {1 {wrong # args: should be "file split name"}} test cmdAH-13.2 {Tcl_FileObjCmd: split} { testsetplatform unix file split a } a test cmdAH-13.3 {Tcl_FileObjCmd: split} { testsetplatform unix file split a/b } {a b} # join test cmdAH-14.1 {Tcl_FileObjCmd: join} { testsetplatform unix file join a } a test cmdAH-14.2 {Tcl_FileObjCmd: join} { testsetplatform unix file join a b } a/b test cmdAH-14.3 {Tcl_FileObjCmd: join} { testsetplatform unix file join a b c d } a/b/c/d # error handling of Tcl_TranslateFileName test cmdAH-15.1 {Tcl_FileObjCmd} { testsetplatform unix list [catch {file atime ~_bad_user} msg] $msg } {1 {user "_bad_user" doesn't exist}} testsetplatform $platform } # readable set gorpfile [makeFile abcde gorp.file] set dirfile [makeDirectory dir.file] if {[info commands testchmod] == {}} { puts "This application hasn't been compiled with the \"testchmod\"" puts "command, so I can't test Tcl_FileObjCmd etc." } else { test cmdAH-16.1 {Tcl_FileObjCmd: readable} {testchmod} { list [catch {file readable a b} msg] $msg } {1 {wrong # args: should be "file readable name"}} testchmod 0444 $gorpfile test cmdAH-16.2 {Tcl_FileObjCmd: readable} {testchmod} { file readable $gorpfile } 1 testchmod 0333 $gorpfile test cmdAH-16.3 {Tcl_FileObjCmd: readable} {unixOnly notRoot testchmod} { file reada $gorpfile } 0 # writable test cmdAH-17.1 {Tcl_FileObjCmd: writable} {testchmod} { list [catch {file writable a b} msg] $msg } {1 {wrong # args: should be "file writable name"}} testchmod 0555 $gorpfile test cmdAH-17.2 {Tcl_FileObjCmd: writable} {notRoot testchmod} { file writable $gorpfile } 0 testchmod 0222 $gorpfile test cmdAH-17.3 {Tcl_FileObjCmd: writable} {testchmod} { file writable $gorpfile } 1 } # executable removeFile $gorpfile removeDirectory $dirfile set dirfile [makeDirectory dir.file] set gorpfile [makeFile abcde gorp.file] test cmdAH-18.1 {Tcl_FileObjCmd: executable} {testchmod} { list [catch {file executable a b} msg] $msg } {1 {wrong # args: should be "file executable name"}} test cmdAH-18.2 {Tcl_FileObjCmd: executable} {testchmod notRoot} { file executable $gorpfile } 0 test cmdAH-18.3 {Tcl_FileObjCmd: executable} {unixOnly testchmod} { # Only on unix will setting the execute bit on a regular file # cause that file to be executable. testchmod 0775 $gorpfile file exe $gorpfile } 1 test cmdAH-18.5 {Tcl_FileObjCmd: executable} {winOnly testchmod} { # On pc, must be a .exe, .com, etc. set x [file exe $gorpfile] set gorpexe [makeFile foo gorp.exe] lappend x [file exe $gorpexe] removeFile $gorpexe set x } {0 1} test cmdAH-18.6 {Tcl_FileObjCmd: executable} {testchmod} { # Directories are always executable. file exe $dirfile } 1 removeDirectory $dirfile removeFile $gorpfile set linkfile [file join [temporaryDirectory] link.file] file delete $linkfile # exists test cmdAH-19.1 {Tcl_FileObjCmd: exists} { list [catch {file exists a b} msg] $msg } {1 {wrong # args: should be "file exists name"}} test cmdAH-19.2 {Tcl_FileObjCmd: exists} {file exists $gorpfile} 0 test cmdAH-19.3 {Tcl_FileObjCmd: exists} { file exists [file join [temporaryDirectory] dir.file gorp.file] } 0 catch { set gorpfile [makeFile abcde gorp.file] set dirfile [makeDirectory dir.file] set subgorp [makeFile 12345 [file join $dirfile gorp.file]] } test cmdAH-19.4 {Tcl_FileObjCmd: exists} { file exists $gorpfile } 1 test cmdAH-19.5 {Tcl_FileObjCmd: exists} { file exists $subgorp } 1 # nativename if {[info commands testsetplatform] == {}} { puts "This application hasn't been compiled with the \"testsetplatform\"" puts "command, so I can't test Tcl_FileObjCmd etc." } else { test cmdAH-19.6 {Tcl_FileObjCmd: nativename} { testsetplatform unix list [catch {file nativename a/b} msg] $msg [testsetplatform $platform] } {0 a/b {}} test cmdAH-19.7 {Tcl_FileObjCmd: nativename} { testsetplatform windows list [catch {file nativename a/b} msg] $msg [testsetplatform $platform] } {0 {a\b} {}} } test cmdAH-19.9 {Tcl_FileObjCmd: ~ : exists} { file exists ~nOsUcHuSeR } 0 test cmdAH-19.10 {Tcl_FileObjCmd: ~ : nativename} { # should probably be 0 in fact... catch {file nativename ~nOsUcHuSeR} } 1 # The test below has to be done in /tmp rather than the current # directory in order to guarantee (?) a local file system: some # NFS file systems won't do the stuff below correctly. test cmdAH-19.11 {Tcl_FileObjCmd: exists} {unixOnly notRoot} { file delete -force /tmp/tcl.foo.dir/file file delete -force /tmp/tcl.foo.dir makeDirectory /tmp/tcl.foo.dir makeFile 12345 /tmp/tcl.foo.dir/file file attributes /tmp/tcl.foo.dir -permissions 0000 set result [file exists /tmp/tcl.foo.dir/file] file attributes /tmp/tcl.foo.dir -permissions 0775 removeFile /tmp/tcl.foo.dir/file removeDirectory /tmp/tcl.foo.dir set result } 0 test cmdAH-19.12 {Bug 3608360: [file exists] mustn't do globbing} -setup { set newdirfile [makeDirectory newdir.file] set cwd [pwd] cd $newdirfile # Content of file is totally unimportant; name is *not* set innocentBystander [makeFile "abc" [file join $newdirfile foo.bar]] } -body { list [file exists foo.bar] [file exists *.bar] } -cleanup { cd $cwd removeFile $innocentBystander removeDirectory $newdirfile } -result {1 0} # Stat related commands catch {testsetplatform $platform} removeFile $gorpfile set gorpfile [makeFile "Test string" gorp.file] catch {file attributes $gorpfile -permissions 0765} # atime set file [makeFile "data" touch.me] test cmdAH-20.1 {Tcl_FileObjCmd: atime} { list [catch {file atime a b c} msg] $msg } {1 {wrong # args: should be "file atime name ?time?"}} test cmdAH-20.2 {Tcl_FileObjCmd: atime} { catch {unset stat} file stat $gorpfile stat list [expr {[file mtime $gorpfile] == $stat(mtime)}] \ [expr {[file atime $gorpfile] == $stat(atime)}] } {1 1} test cmdAH-20.3 {Tcl_FileObjCmd: atime} { string tolower [list [catch {file atime _bogus_} msg] \ $msg $errorCode] } {1 {could not read "_bogus_": no such file or directory} {posix enoent {no such file or directory}}} test cmdAH-20.4 {Tcl_FileObjCmd: atime} { list [catch {file atime $file notint} msg] $msg } {1 {expected integer but got "notint"}} test cmdAH-20.5 {Tcl_FileObjCmd: atime touch} {unixOrPc} { if {[string equal $tcl_platform(platform) "windows"]} { set old [pwd] cd $::tcltest::temporaryDirectory if {![string equal "NTFS" [testvolumetype]]} { # Windows FAT doesn't understand atime, but NTFS does # May also fail for Windows on NFS mounted disks cd $old return 1 } cd $old } set atime [file atime $file] after 1100; # pause a sec to notice change in atime set newatime [clock seconds] set modatime [file atime $file $newatime] expr {$newatime == $modatime ? 1 : "$newatime != $modatime"} } 1 removeFile touch.me # isdirectory test cmdAH-21.1 {Tcl_FileObjCmd: isdirectory} { list [catch {file isdirectory a b} msg] $msg } {1 {wrong # args: should be "file isdirectory name"}} test cmdAH-21.2 {Tcl_FileObjCmd: isdirectory} { file isdirectory $gorpfile } 0 test cmdAH-21.3 {Tcl_FileObjCmd: isdirectory} { file isd $dirfile } 1 # isfile test cmdAH-22.1 {Tcl_FileObjCmd: isfile} { list [catch {file isfile a b} msg] $msg } {1 {wrong # args: should be "file isfile name"}} test cmdAH-22.2 {Tcl_FileObjCmd: isfile} {file isfile $gorpfile} 1 test cmdAH-22.3 {Tcl_FileObjCmd: isfile} {file isfile $dirfile} 0 # lstat and readlink: don't run these tests everywhere, since not all # sites will have symbolic links catch {file link -symbolic $linkfile $gorpfile} test cmdAH-23.1 {Tcl_FileObjCmd: lstat} { list [catch {file lstat a} msg] $msg } {1 {wrong # args: should be "file lstat name varName"}} test cmdAH-23.2 {Tcl_FileObjCmd: lstat} { list [catch {file lstat a b c} msg] $msg } {1 {wrong # args: should be "file lstat name varName"}} test cmdAH-23.3 {Tcl_FileObjCmd: lstat} {unixOnly nonPortable} { catch {unset stat} file lstat $linkfile stat lsort [array names stat] } {atime ctime dev gid ino mode mtime nlink size type uid} test cmdAH-23.4 {Tcl_FileObjCmd: lstat} {unixOnly nonPortable} { catch {unset stat} file lstat $linkfile stat list $stat(nlink) [expr $stat(mode)&0777] $stat(type) } {1 511 link} test cmdAH-23.5 {Tcl_FileObjCmd: lstat errors} {nonPortable} { string tolower [list [catch {file lstat _bogus_ stat} msg] \ $msg $errorCode] } {1 {could not read "_bogus_": no such file or directory} {posix enoent {no such file or directory}}} test cmdAH-23.6 {Tcl_FileObjCmd: lstat errors} { catch {unset x} set x 44 list [catch {file lstat $gorpfile x} msg] $msg $errorCode } {1 {can't set "x(dev)": variable isn't array} NONE} catch {unset stat} # mkdir set dirA [file join [temporaryDirectory] a] set dirB [file join [temporaryDirectory] a] test cmdAH-23.7 {Tcl_FileObjCmd: mkdir} { catch {file delete -force $dirA} file mkdir $dirA set res [file isdirectory $dirA] file delete $dirA set res } {1} test cmdAH-23.8 {Tcl_FileObjCmd: mkdir} { catch {file delete -force $dirA} file mkdir $dirA/b set res [file isdirectory $dirA/b] file delete -force $dirA set res } {1} test cmdAH-23.9 {Tcl_FileObjCmd: mkdir} { catch {file delete -force $dirA} file mkdir $dirA/b/c set res [file isdirectory $dirA/b/c] file delete -force $dirA set res } {1} test cmdAH-23.10 {Tcl_FileObjCmd: mkdir} { catch {file delete -force $dirA} catch {file delete -force $dirB} file mkdir $dirA/b $dirB/a/c set res [list [file isdirectory $dirA/b] [file isdirectory $dirB/a/c]] file delete -force $dirA file delete -force $dirB set res } {1 1} # mtime proc waitForEvenSecondForFAT {} { # Windows 9x uses filesystems (the FAT* family of FSes) without # enough data in its timestamps for even per-second-accurate # timings. :^( # This procedure based on work by Helmut Giese global tcl_platform if {$tcl_platform(platform) ne "windows"} {return} if {[lindex [file system [temporaryDirectory]] 1] == "NTFS"} {return} # Assume non-NTFS means FAT{12,16,32} and hence in need of special help set start [clock seconds] while {1} { set now [clock seconds] if {$now!=$start && !($now & 1)} { return } after 50 } } set file [makeFile "data" touch.me] test cmdAH-24.1 {Tcl_FileObjCmd: mtime} { list [catch {file mtime a b c} msg] $msg } {1 {wrong # args: should be "file mtime name ?time?"}} # Check (allowing for clock-skew and OS interrupts as best we can) # that the change in mtime on a file being written is the time elapsed # between writes. Note that this can still fail on very busy systems # if there are long preemptions between the writes and the reading of # the clock, but there's not much you can do about that other than the # completely horrible "keep on trying to write until you managed to do # it all in less than a second." - DKF test cmdAH-24.2 {Tcl_FileObjCmd: mtime} { waitForEvenSecondForFAT set f [open $gorpfile w] puts $f "More text" close $f set clockOld [clock seconds] set fileOld [file mtime $gorpfile] after 2000 set f [open $gorpfile w] puts $f "More text" close $f set clockNew [clock seconds] set fileNew [file mtime $gorpfile] expr { (($fileNew > $fileOld) && ($clockNew > $clockOld) && (abs(($fileNew-$fileOld) - ($clockNew-$clockOld)) <= 1)) ? "1" : "file:($fileOld=>$fileNew) clock:($clockOld=>$clockNew)" } } {1} test cmdAH-24.3 {Tcl_FileObjCmd: mtime} { catch {unset stat} file stat $gorpfile stat list [expr {[file mtime $gorpfile] == $stat(mtime)}] \ [expr {[file atime $gorpfile] == $stat(atime)}] } {1 1} test cmdAH-24.4 {Tcl_FileObjCmd: mtime} { string tolower [list [catch {file mtime _bogus_} msg] $msg \ $errorCode] } {1 {could not read "_bogus_": no such file or directory} {posix enoent {no such file or directory}}} test cmdAH-24.5 {Tcl_FileObjCmd: mtime} { # Under Unix, use a file in /tmp to avoid clock skew due to NFS. # On other platforms, just use a file in the local directory. if {[string equal $tcl_platform(platform) "unix"]} { set name /tmp/tcl.test.[pid] } else { set name [file join [temporaryDirectory] tf] } # Make sure that a new file's time is correct. 10 seconds variance # is allowed used due to slow networks or clock skew on a network drive. file delete -force $name close [open $name w] set a [expr abs([clock seconds]-[file mtime $name])<10] file delete $name set a } {1} test cmdAH-24.7 {Tcl_FileObjCmd: mtime} { list [catch {file mtime $file notint} msg] $msg } {1 {expected integer but got "notint"}} test cmdAH-24.8 {Tcl_FileObjCmd: mtime touch} macOrUnix { set mtime [file mtime $file] after 1100; # pause a sec to notice change in mtime set newmtime [clock seconds] set modmtime [file mtime $file $newmtime] expr {$newmtime == $modmtime ? 1 : "$newmtime != $modmtime"} } 1 test cmdAH-24.9 {Tcl_FileObjCmd: mtime touch with non-ascii chars} macOrUnix { set oldfile $file # introduce some non-ascii characters. append file \u2022 file delete -force $file file rename $oldfile $file set mtime [file mtime $file] after 1100; # pause a sec to notice change in mtime set newmtime [clock seconds] set err [catch {file mtime $file $newmtime} modmtime] file rename $file $oldfile if {$err} { error $modmtime } expr {$newmtime == $modmtime ? 1 : "$newmtime != $modmtime"} } 1 test cmdAH-24.10 {Tcl_FileObjCmd: mtime touch} winOnly { waitForEvenSecondForFAT set mtime [file mtime $file] after 2100; # pause two secs to notice change in mtime on FAT fs'es set newmtime [clock seconds] set modmtime [file mtime $file $newmtime] expr {$newmtime == $modmtime ? 1 : "$newmtime != $modmtime"} } 1 test cmdAH-24.11 {Tcl_FileObjCmd: mtime touch with non-ascii chars} winOnly { waitForEvenSecondForFAT set oldfile $file # introduce some non-ascii characters. append file \u2022 file delete -force $file file rename $oldfile $file set mtime [file mtime $file] after 2100; # pause two secs to notice change in mtime on FAT fs'es set newmtime [clock seconds] set err [catch {file mtime $file $newmtime} modmtime] file rename $file $oldfile if {$err} { error $modmtime } expr {$newmtime == $modmtime ? 1 : "$newmtime != $modmtime"} } 1 removeFile touch.me rename waitForEvenSecondForFAT {} test cmdAH-24.12 {Tcl_FileObjCmd: mtime and daylight savings} { set name [file join [temporaryDirectory] clockchange] file delete -force $name close [open $name w] set time [clock scan "21:00:00 October 30 2004 GMT"] file mtime $name $time set newmtime [file mtime $name] file delete $name expr {$newmtime == $time ? 1 : "$newmtime != $time"} } {1} # bug 1420432: setting mtime fails for directories on windows. test cmdAH-24.13 {Tcl_FileObjCmd: directory mtime} { set dirname [file join [temporaryDirectory] tmp[pid]] file delete -force $dirname file mkdir $dirname set res [catch { set old [file mtime $dirname] file mtime $dirname 0 set new [file mtime $dirname] list $new [expr {$old != $new}] } err] file delete -force $dirname list $res $err } {0 {0 1}} # owned test cmdAH-25.1 {Tcl_FileObjCmd: owned} { list [catch {file owned a b} msg] $msg } {1 {wrong # args: should be "file owned name"}} test cmdAH-25.2 {Tcl_FileObjCmd: owned} { file owned $gorpfile } 1 test cmdAH-25.3 {Tcl_FileObjCmd: owned} {unixOnly notRoot} { file owned / } 0 # readlink test cmdAH-26.1 {Tcl_FileObjCmd: readlink} { list [catch {file readlink a b} msg] $msg } {1 {wrong # args: should be "file readlink name"}} test cmdAH-26.2 {Tcl_FileObjCmd: readlink} {unixOnly nonPortable} { file readlink $linkfile } $gorpfile test cmdAH-26.3 {Tcl_FileObjCmd: readlink errors} {unixOnly nonPortable} { list [catch {file readlink _bogus_} msg] [string tolower $msg] \ [string tolower $errorCode] } {1 {could not readlink "_bogus_": no such file or directory} {posix enoent {no such file or directory}}} test cmdAH-26.5 {Tcl_FileObjCmd: readlink errors} {winOnly nonPortable} { list [catch {file readlink _bogus_} msg] [string tolower $msg] \ [string tolower $errorCode] } {1 {could not readlink "_bogus_": invalid argument} {posix einval {invalid argument}}} # size test cmdAH-27.1 {Tcl_FileObjCmd: size} { list [catch {file size a b} msg] $msg } {1 {wrong # args: should be "file size name"}} test cmdAH-27.2 {Tcl_FileObjCmd: size} { set oldsize [file size $gorpfile] set f [open $gorpfile a] fconfigure $f -translation lf -eofchar {} puts $f "More text" close $f expr {[file size $gorpfile] - $oldsize} } {10} test cmdAH-27.3 {Tcl_FileObjCmd: size} { string tolower [list [catch {file size _bogus_} msg] $msg \ $errorCode] } {1 {could not read "_bogus_": no such file or directory} {posix enoent {no such file or directory}}} # stat catch {testsetplatform $platform} removeFile $gorpfile set gorpfile [makeFile "Test string" gorp.file] catch {file attributes $gorpfile -permissions 0765} test cmdAH-28.1 {Tcl_FileObjCmd: stat} { list [catch {file stat _bogus_} msg] $msg $errorCode } {1 {wrong # args: should be "file stat name varName"} NONE} test cmdAH-28.2 {Tcl_FileObjCmd: stat} { list [catch {file stat _bogus_ a b} msg] $msg $errorCode } {1 {wrong # args: should be "file stat name varName"} NONE} test cmdAH-28.3 {Tcl_FileObjCmd: stat} { catch {unset stat} file stat $gorpfile stat lsort [array names stat] } {atime ctime dev gid ino mode mtime nlink size type uid} test cmdAH-28.4 {Tcl_FileObjCmd: stat} { catch {unset stat} file stat $gorpfile stat list $stat(nlink) $stat(size) $stat(type) } {1 12 file} test cmdAH-28.5 {Tcl_FileObjCmd: stat} {unixOnly} { catch {unset stat} file stat $gorpfile stat expr $stat(mode)&0777 } {501} test cmdAH-28.6 {Tcl_FileObjCmd: stat} { string tolower [list [catch {file stat _bogus_ stat} msg] \ $msg $errorCode] } {1 {could not read "_bogus_": no such file or directory} {posix enoent {no such file or directory}}} test cmdAH-28.7 {Tcl_FileObjCmd: stat} { catch {unset x} set x 44 list [catch {file stat $gorpfile x} msg] $msg $errorCode } {1 {can't set "x(dev)": variable isn't array} NONE} test cmdAH-28.8 {Tcl_FileObjCmd: stat} { # Sign extension of purported unsigned short to int. set filename [makeFile "" foo.text] file stat $filename stat set x [expr {$stat(mode) > 0}] removeFile $filename set x } 1 test cmdAH-28.9 {Tcl_FileObjCmd: stat} winOnly { # stat of root directory was failing. # don't care about answer, just that test runs. # relative paths that resolve to root set old [pwd] cd c:/ file stat c: stat file stat c:. stat file stat . stat cd $old file stat / stat file stat c:/ stat file stat c:/. stat } {} test cmdAH-28.10 {Tcl_FileObjCmd: stat} {winOnly nonPortable} { # stat of root directory was failing. # don't care about answer, just that test runs. file stat //pop/$env(USERNAME) stat file stat //pop/$env(USERNAME)/ stat file stat //pop/$env(USERNAME)/. stat } {} test cmdAH-28.11 {Tcl_FileObjCmd: stat} {winOnly nonPortable} { # stat of network directory was returning id of current local drive. set old [pwd] cd c:/ file stat //pop/$env(USERNAME) stat cd $old expr {$stat(dev) == 2} } 0 test cmdAH-28.12 {Tcl_FileObjCmd: stat} { # stat(mode) with S_IFREG flag was returned as a negative number # if mode_t was a short instead of an unsigned short. set filename [makeFile "" foo.test] file stat $filename stat removeFile $filename expr {$stat(mode) > 0} } 1 catch {unset stat} # type test cmdAH-29.1 {Tcl_FileObjCmd: type} { list [catch {file size a b} msg] $msg } {1 {wrong # args: should be "file size name"}} test cmdAH-29.2 {Tcl_FileObjCmd: type} { file type $dirfile } directory test cmdAH-29.3.0 {Tcl_FileObjCmd: delete removes link not file} {unixOnly nonPortable} { set exists [list [file exists $linkfile] [file exists $gorpfile]] file delete $linkfile set exists2 [list [file exists $linkfile] [file exists $gorpfile]] list $exists $exists2 } {{1 1} {0 1}} test cmdAH-29.3 {Tcl_FileObjCmd: type} { file type $gorpfile } file test cmdAH-29.4 {Tcl_FileObjCmd: type} {unixOnly} { catch {file delete $linkfile} # Unlike [exec ln -s], [file link] requires an existing target file link -symbolic $linkfile $gorpfile set result [file type $linkfile] file delete $linkfile set result } link if {[string equal $tcl_platform(platform) "windows"]} { if {[string index $tcl_platform(osVersion) 0] >= 5 \ && ([lindex [file system [temporaryDirectory]] 1] == "NTFS")} { tcltest::testConstraint linkDirectory 1 } else { tcltest::testConstraint linkDirectory 0 } } else { tcltest::testConstraint linkDirectory 1 } test cmdAH-29.4.1 {Tcl_FileObjCmd: type} {linkDirectory} { set tempdir [makeDirectory temp] set linkdir [file join [temporaryDirectory] link.dir] file link -symbolic $linkdir $tempdir set result [file type $linkdir] file delete $linkdir removeDirectory $tempdir set result } link test cmdAH-29.5 {Tcl_FileObjCmd: type} { string tolower [list [catch {file type _bogus_} msg] $msg $errorCode] } {1 {could not read "_bogus_": no such file or directory} {posix enoent {no such file or directory}}} # Error conditions test cmdAH-30.1 {Tcl_FileObjCmd: error conditions} { list [catch {file gorp x} msg] $msg } {1 {bad option "gorp": must be atime, attributes, channels, copy, delete, dirname, executable, exists, extension, isdirectory, isfile, join, link, lstat, mtime, mkdir, nativename, normalize, owned, pathtype, readable, readlink, rename, rootname, separator, size, split, stat, system, tail, type, volumes, or writable}} test cmdAH-30.2 {Tcl_FileObjCmd: error conditions} { list [catch {file ex x} msg] $msg } {1 {ambiguous option "ex": must be atime, attributes, channels, copy, delete, dirname, executable, exists, extension, isdirectory, isfile, join, link, lstat, mtime, mkdir, nativename, normalize, owned, pathtype, readable, readlink, rename, rootname, separator, size, split, stat, system, tail, type, volumes, or writable}} test cmdAH-30.3 {Tcl_FileObjCmd: error conditions} { list [catch {file is x} msg] $msg } {1 {ambiguous option "is": must be atime, attributes, channels, copy, delete, dirname, executable, exists, extension, isdirectory, isfile, join, link, lstat, mtime, mkdir, nativename, normalize, owned, pathtype, readable, readlink, rename, rootname, separator, size, split, stat, system, tail, type, volumes, or writable}} test cmdAH-30.4 {Tcl_FileObjCmd: error conditions} { list [catch {file z x} msg] $msg } {1 {bad option "z": must be atime, attributes, channels, copy, delete, dirname, executable, exists, extension, isdirectory, isfile, join, link, lstat, mtime, mkdir, nativename, normalize, owned, pathtype, readable, readlink, rename, rootname, separator, size, split, stat, system, tail, type, volumes, or writable}} test cmdAH-30.5 {Tcl_FileObjCmd: error conditions} { list [catch {file read x} msg] $msg } {1 {ambiguous option "read": must be atime, attributes, channels, copy, delete, dirname, executable, exists, extension, isdirectory, isfile, join, link, lstat, mtime, mkdir, nativename, normalize, owned, pathtype, readable, readlink, rename, rootname, separator, size, split, stat, system, tail, type, volumes, or writable}} test cmdAH-30.6 {Tcl_FileObjCmd: error conditions} { list [catch {file s x} msg] $msg } {1 {ambiguous option "s": must be atime, attributes, channels, copy, delete, dirname, executable, exists, extension, isdirectory, isfile, join, link, lstat, mtime, mkdir, nativename, normalize, owned, pathtype, readable, readlink, rename, rootname, separator, size, split, stat, system, tail, type, volumes, or writable}} test cmdAH-30.7 {Tcl_FileObjCmd: error conditions} { list [catch {file t x} msg] $msg } {1 {ambiguous option "t": must be atime, attributes, channels, copy, delete, dirname, executable, exists, extension, isdirectory, isfile, join, link, lstat, mtime, mkdir, nativename, normalize, owned, pathtype, readable, readlink, rename, rootname, separator, size, split, stat, system, tail, type, volumes, or writable}} test cmdAH-30.8 {Tcl_FileObjCmd: error conditions} { list [catch {file dirname ~woohgy} msg] $msg } {1 {user "woohgy" doesn't exist}} # channels # In testing 'file channels', we need to make sure that a channel # created in one interp isn't visible in another. interp create simpleInterp interp create -safe safeInterp interp c safeInterp expose file file test cmdAH-31.1 {Tcl_FileObjCmd: channels, too many args} { list [catch {file channels a b} msg] $msg } {1 {wrong # args: should be "file channels ?pattern?"}} test cmdAH-31.2 {Tcl_FileObjCmd: channels, too many args} { # Normal interps start out with only the standard channels lsort [simpleInterp eval [list file chan]] } [lsort {stderr stdout stdin}] test cmdAH-31.3 {Tcl_FileObjCmd: channels, globbing} { string equal [file channels] [file channels *] } {1} test cmdAH-31.4 {Tcl_FileObjCmd: channels, globbing} { lsort [file channels std*] } [lsort {stdout stderr stdin}] set newFileId [open $gorpfile w] test cmdAH-31.5 {Tcl_FileObjCmd: channels} { set res [file channels $newFileId] string equal $newFileId $res } {1} test cmdAH-31.6 {Tcl_FileObjCmd: channels in other interp} { # Safe interps start out with no channels safeInterp eval [list file channels] } {} test cmdAH-31.7 {Tcl_FileObjCmd: channels in other interp} { list [catch {safeInterp eval [list puts $newFileId "hello"]} msg] $msg } [list 1 "can not find channel named \"$newFileId\""] interp share {} $newFileId safeInterp interp share {} stdout safeInterp test cmdAH-31.8 {Tcl_FileObjCmd: channels in other interp} { # $newFileId should now be visible in both interps list [file channels $newFileId] \ [safeInterp eval [list file channels $newFileId]] } [list $newFileId $newFileId] test cmdAH-31.9 {Tcl_FileObjCmd: channels in other interp} { lsort [safeInterp eval [list file channels]] } [lsort [list stdout $newFileId]] test cmdAH-31.10 {Tcl_FileObjCmd: channels in other interp} { # we can now write to $newFileId from slave safeInterp eval [list puts $newFileId "hello"] } {} interp transfer {} $newFileId safeInterp test cmdAH-31.11 {Tcl_FileObjCmd: channels in other interp} { # $newFileId should now be visible only in safeInterp list [file channels $newFileId] \ [safeInterp eval [list file channels $newFileId]] } [list {} $newFileId] test cmdAH-31.12 {Tcl_FileObjCmd: channels in other interp} { lsort [safeInterp eval [list file channels]] } [lsort [list stdout $newFileId]] test cmdAH-31.13 {Tcl_FileObjCmd: channels in other interp} { safeInterp eval [list close $newFileId] safeInterp eval [list file channels] } {stdout} # This shouldn't work, but just in case a test above failed... catch {close $newFileId} interp delete safeInterp interp delete simpleInterp # cleanup catch {testsetplatform $platform} catch {unset platform} # Tcl_ForObjCmd is tested in for.test catch {file attributes $dirfile -permissions 0777} removeDirectory $dirfile removeFile $gorpfile # No idea how well [removeFile] copes with links... file delete $linkfile cd $cmdAHwd ::tcltest::cleanupTests return tcl8.4.20/tests/misc.test0000644003604700454610000000370311737050674013720 0ustar dgp771div# Commands covered: various # # This file contains a collection of miscellaneous Tcl tests that # don't fit naturally in any of the other test files. Many of these # tests are pathological cases that caused bugs in earlier Tcl # releases. # # Copyright (c) 1992-1993 The Regents of the University of California. # Copyright (c) 1994-1996 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } test misc-1.1 {error in variable ref. in command in array reference} { proc tstProc {} { global a set tst $a([winfo name $zz]) # this is a bogus comment # this is a bogus comment # this is a bogus comment # this is a bogus comment # this is a bogus comment # this is a bogus comment # this is a bogus comment # this is a bogus comment } set msg {} list [catch tstProc msg] $msg } {1 {can't read "zz": no such variable}} test misc-1.2 {error in variable ref. in command in array reference} { proc tstProc {} " global a set tst \$a(\[winfo name \$\{zz) # this is a bogus comment # this is a bogus comment # this is a bogus comment # this is a bogus comment # this is a bogus comment # this is a bogus comment # this is a bogus comment # this is a bogus comment " set msg {} join [list [catch tstProc msg] $msg $errorInfo] \n } [subst -novariables -nocommands {1 missing close-brace for variable name missing close-brace for variable name while compiling "set tst $a([winfo name $\{zz) # this is a bogus comment # this is a bogus comment # this is a bogus comment # this is a bogus comment # this is a ..." (compiling body of proc "tstProc", line 4) invoked from within "tstProc"}] # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/encoding.test0000644003604700454610000004307711737050674014563 0ustar dgp771div# This file contains a collection of tests for tclEncoding.c # Sourcing this file into Tcl runs the tests and generates output for # errors. No output means no errors were found. # # Copyright (c) 1997 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. package require tcltest 2 namespace import -force ::tcltest::* proc toutf {args} { global x lappend x "toutf $args" } proc fromutf {args} { global x lappend x "fromutf $args" } # Some tests require the testencoding command testConstraint testencoding [llength [info commands testencoding]] testConstraint exec [llength [info commands exec]] # TclInitEncodingSubsystem is tested by the rest of this file # TclFinalizeEncodingSubsystem is not currently tested test encoding-1.1 {Tcl_GetEncoding: system encoding} {testencoding} { testencoding create foo toutf fromutf set old [encoding system] encoding system foo set x {} encoding convertto abcd encoding system $old testencoding delete foo set x } {{fromutf }} test encoding-1.2 {Tcl_GetEncoding: existing encoding} {testencoding} { testencoding create foo toutf fromutf set x {} encoding convertto foo abcd testencoding delete foo set x } {{fromutf }} test encoding-1.3 {Tcl_GetEncoding: load encoding} { list [encoding convertto jis0208 \u4e4e] \ [encoding convertfrom jis0208 8C] } "8C \u4e4e" test encoding-2.1 {Tcl_FreeEncoding: refcount == 0} { encoding convertto jis0208 \u4e4e } {8C} test encoding-2.2 {Tcl_FreeEncoding: refcount != 0} {testencoding} { set system [encoding system] set path [testencoding path] encoding system shiftjis ;# incr ref count testencoding path [list [pwd]] set x [encoding convertto shiftjis \u4e4e] ;# old one found encoding system identity lappend x [catch {encoding convertto shiftjis \u4e4e} msg] $msg encoding system identity testencoding path $path encoding system $system set x } "\u008c\u00c1 1 {unknown encoding \"shiftjis\"}" test encoding-3.1 {Tcl_GetEncodingName, NULL} { set old [encoding system] encoding system shiftjis set x [encoding system] encoding system $old set x } {shiftjis} test encoding-3.2 {Tcl_GetEncodingName, non-null} { set old [fconfigure stdout -encoding] fconfigure stdout -encoding jis0208 set x [fconfigure stdout -encoding] fconfigure stdout -encoding $old set x } {jis0208} test encoding-4.1 {Tcl_GetEncodingNames} {testencoding} { cd [makeDirectory tmp] makeDirectory [file join tmp encoding] makeFile {} [file join tmp encoding junk.enc] makeFile {} [file join tmp encoding junk2.enc] set path [testencoding path] testencoding path {} catch {unset encodings} catch {unset x} foreach encoding [encoding names] { set encodings($encoding) 1 } testencoding path [list [pwd]] foreach encoding [encoding names] { if {![info exists encodings($encoding)]} { lappend x $encoding } } testencoding path $path cd [workingDirectory] removeFile [file join tmp encoding junk2.enc] removeFile [file join tmp encoding junk.enc] removeDirectory [file join tmp encoding] removeDirectory tmp lsort $x } {junk junk2} test encoding-5.1 {Tcl_SetSystemEncoding} { set old [encoding system] encoding system jis0208 set x [encoding convertto \u4e4e] encoding system identity encoding system $old set x } {8C} test encoding-5.2 {Tcl_SetSystemEncoding: test ref count} { set old [encoding system] encoding system $old string compare $old [encoding system] } {0} test encoding-6.1 {Tcl_CreateEncoding: new} {testencoding} { testencoding create foo {toutf 1} {fromutf 2} set x {} encoding convertfrom foo abcd encoding convertto foo abcd testencoding delete foo set x } {{toutf 1} {fromutf 2}} test encoding-6.2 {Tcl_CreateEncoding: replace encoding} {testencoding} { testencoding create foo {toutf a} {fromutf b} set x {} encoding convertfrom foo abcd encoding convertto foo abcd testencoding delete foo set x } {{toutf a} {fromutf b}} test encoding-7.1 {Tcl_ExternalToUtfDString: small buffer} { encoding convertfrom jis0208 8c8c8c8c } "\u543e\u543e\u543e\u543e" test encoding-7.2 {Tcl_UtfToExternalDString: big buffer} { set a 8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C append a $a append a $a append a $a append a $a set x [encoding convertfrom jis0208 $a] list [string length $x] [string index $x 0] } "512 \u4e4e" test encoding-8.1 {Tcl_ExternalToUtf} { set f [open [file join [temporaryDirectory] dummy] w] fconfigure $f -translation binary -encoding iso8859-1 puts -nonewline $f "ab\x8c\xc1g" close $f set f [open [file join [temporaryDirectory] dummy] r] fconfigure $f -translation binary -encoding shiftjis set x [read $f] close $f file delete [file join [temporaryDirectory] dummy] set x } "ab\u4e4eg" test encoding-9.1 {Tcl_UtfToExternalDString: small buffer} { encoding convertto jis0208 "\u543e\u543e\u543e\u543e" } {8c8c8c8c} test encoding-9.2 {Tcl_UtfToExternalDString: big buffer} { set a \u4e4e\u4e4e\u4e4e\u4e4e\u4e4e\u4e4e\u4e4e\u4e4e append a $a append a $a append a $a append a $a append a $a append a $a set x [encoding convertto jis0208 $a] list [string length $x] [string range $x 0 1] } "1024 8C" test encoding-10.1 {Tcl_UtfToExternal} { set f [open [file join [temporaryDirectory] dummy] w] fconfigure $f -translation binary -encoding shiftjis puts -nonewline $f "ab\u4e4eg" close $f set f [open [file join [temporaryDirectory] dummy] r] fconfigure $f -translation binary -encoding iso8859-1 set x [read $f] close $f file delete [file join [temporaryDirectory] dummy] set x } "ab\x8c\xc1g" proc viewable {str} { set res "" foreach c [split $str {}] { if {[string is print $c] && [string is ascii $c]} { append res $c } else { append res "\\u[format %4.4x [scan $c %c]]" } } return "$str ($res)" } test encoding-11.1 {LoadEncodingFile: unknown encoding} {testencoding} { set system [encoding system] set path [testencoding path] encoding system iso8859-1 testencoding path {} set x [list [catch {encoding convertto jis0208 \u4e4e} msg] $msg] testencoding path $path encoding system $system lappend x [encoding convertto jis0208 \u4e4e] } {1 {unknown encoding "jis0208"} 8C} test encoding-11.2 {LoadEncodingFile: single-byte} { encoding convertfrom jis0201 \xa1 } "\uff61" test encoding-11.3 {LoadEncodingFile: double-byte} { encoding convertfrom jis0208 8C } "\u4e4e" test encoding-11.4 {LoadEncodingFile: multi-byte} { encoding convertfrom shiftjis \x8c\xc1 } "\u4e4e" test encoding-11.5 {LoadEncodingFile: escape file} { viewable [encoding convertto iso2022 \u4e4e] } [viewable "\x1b\$B8C\x1b(B"] test encoding-11.5.1 {LoadEncodingFile: escape file} { viewable [encoding convertto iso2022-jp \u4e4e] } [viewable "\x1b\$B8C\x1b(B"] test encoding-11.6 {LoadEncodingFile: invalid file} {testencoding} { set system [encoding system] set path [testencoding path] encoding system identity cd [temporaryDirectory] testencoding path tmp makeDirectory tmp makeDirectory [file join tmp encoding] set f [open [file join tmp encoding splat.enc] w] fconfigure $f -translation binary puts $f "abcdefghijklmnop" close $f set x [list [catch {encoding convertto splat \u4e4e} msg] $msg] file delete [file join [temporaryDirectory] tmp encoding splat.enc] removeDirectory [file join tmp encoding] removeDirectory tmp cd [workingDirectory] testencoding path $path encoding system $system set x } {1 {invalid encoding file "splat"}} # OpenEncodingFile is fully tested by the rest of the tests in this file. test encoding-12.1 {LoadTableEncoding: normal encoding} { set x [encoding convertto iso8859-3 \u120] append x [encoding convertto iso8859-3 \ud5] append x [encoding convertfrom iso8859-3 \xd5] } "\xd5?\u120" test encoding-12.2 {LoadTableEncoding: single-byte encoding} { set x [encoding convertto iso8859-3 ab\u0120g] append x [encoding convertfrom iso8859-3 ab\xd5g] } "ab\xd5gab\u120g" test encoding-12.3 {LoadTableEncoding: multi-byte encoding} { set x [encoding convertto shiftjis ab\u4e4eg] append x [encoding convertfrom shiftjis ab\x8c\xc1g] } "ab\x8c\xc1gab\u4e4eg" test encoding-12.4 {LoadTableEncoding: double-byte encoding} { set x [encoding convertto jis0208 \u4e4e\u3b1] append x [encoding convertfrom jis0208 8C&A] } "8C&A\u4e4e\u3b1" test encoding-12.5 {LoadTableEncoding: symbol encoding} { set x [encoding convertto symbol \u3b3] append x [encoding convertto symbol \u67] append x [encoding convertfrom symbol \x67] } "\x67\x67\u3b3" test encoding-13.1 {LoadEscapeTable} { viewable [set x [encoding convertto iso2022 ab\u4e4e\u68d9g]] } [viewable "ab\x1b\$B8C\x1b\$\(DD%\x1b(Bg"] test encoding-14.1 {BinaryProc} { encoding convertto identity \x12\x34\x56\xff\x69 } "\x12\x34\x56\xc3\xbf\x69" test encoding-15.1 {UtfToUtfProc} { encoding convertto utf-8 \xa3 } "\xc2\xa3" test encoding-15.2 {UtfToUtfProc null character output} { set x \u0000 set y [encoding convertto utf-8 \u0000] set y [encoding convertfrom identity $y] binary scan $y H* z list [string bytelength $x] [string bytelength $y] $z } {2 1 00} test encoding-15.3 {UtfToUtfProc null character input} { set x [encoding convertfrom identity \x00] set y [encoding convertfrom utf-8 $x] binary scan [encoding convertto identity $y] H* z list [string bytelength $x] [string bytelength $y] $z } {1 2 c080} test encoding-16.1 {UnicodeToUtfProc} { set val [encoding convertfrom unicode NN] list $val [format %x [scan $val %c]] } "\u4e4e 4e4e" test encoding-17.1 {UtfToUnicodeProc} { } {} test encoding-18.1 {TableToUtfProc} { } {} test encoding-19.1 {TableFromUtfProc} { } {} test encoding-20.1 {TableFreefProc} { } {} test encoding-21.1 {EscapeToUtfProc} { } {} test encoding-22.1 {EscapeFromUtfProc} { } {} set ::iso2022encData "\u001b\$B;d\$I\$b\$G\$O!\"%A%C%W\$49XF~;~\$K\$4EPO?\$\$\$?\$@\$\$\$?\$4=;=j\$r%-%c%C%7%e%\"%&%H\$N:]\$N\u001b(B \u001b\$B>.@Z= 0} { if {$count} { incr count 1 ; # account for newline append out \n } append out $line incr count $num } close $fid if {[string compare $::iso2022uniData $out]} { return -code error "iso2022-jp read in doesn't match original" } list $count $out } [list [string length $::iso2022uniData] $::iso2022uniData] test encoding-23.3 {iso2022-jp escape encoding test} { # read $fis reads size in chars, not raw bytes. set fid [open iso2022.txt r] fconfigure $fid -encoding iso2022-jp set data [read $fid 50] close $fid set data } [string range $::iso2022uniData 0 49] ; # 0 .. 49 inclusive == 50 cd [workingDirectory] test encoding-24.1 {EscapeFreeProc on open channels} -constraints { exec } -setup { # Bug #524674 input set file [makeFile { set f [open [file join [file dirname [info script]] iso2022.txt]] fconfigure $f -encoding iso2022-jp gets $f } iso2022.tcl] } -body { exec [interpreter] $file } -cleanup { removeFile iso2022.tcl } -result {} test encoding-24.2 {EscapeFreeProc on open channels} -constraints { exec } -setup { # Bug #524674 output set file [makeFile { encoding system cp1252; # Bug #2891556 crash revelator fconfigure stdout -encoding iso2022-jp puts ab\u4e4e\u68d9g exit } iso2022.tcl] } -body { viewable [exec [interpreter] $file] } -cleanup { removeFile iso2022.tcl } -result "ab\x1b\$B8C\x1b\$(DD%\x1b(Bg (ab\\u001b\$B8C\\u001b\$(DD%\\u001b(Bg)" test encoding-24.3 {EscapeFreeProc on open channels} {stdio} { # Bug #219314 - if we don't free escape encodings correctly on # channel closure, we go boom set file [makeFile { encoding system iso2022-jp set a "\u4e4e\u4e5e\u4e5f"; # 3 Japanese Kanji letters puts $a } iso2022.tcl] set f [open "|[list [interpreter] $file]"] fconfigure $f -encoding iso2022-jp set count [gets $f line] close $f removeFile iso2022.tcl list $count [viewable $line] } [list 3 "\u4e4e\u4e5e\u4e5f (\\u4e4e\\u4e5e\\u4e5f)"] file delete [file join [temporaryDirectory] iso2022.txt] # # Begin jajp encoding round-trip conformity tests # proc foreach-jisx0208 {varName command} { upvar 1 $varName code foreach range { {2121 217E} {2221 222E} {223A 2241} {224A 2250} {225C 226A} {2272 2279} {227E 227E} {2330 2339} {2421 2473} {2521 2576} {2821 2821} {282C 282C} {2837 2837} {30 21 4E 7E} {4F21 4F53} {50 21 73 7E} {7421 7426} } { if {[llength $range] == 2} { # for adhoc range. simple {first last}. inclusive. set first [scan [lindex $range 0] %x] set last [scan [lindex $range 1] %x] for {set i $first} {$i <= $last} {incr i} { set code $i uplevel 1 $command } } elseif {[llength $range] == 4} { # for uniform range. set h0 [scan [lindex $range 0] %x] set l0 [scan [lindex $range 1] %x] set hend [scan [lindex $range 2] %x] set lend [scan [lindex $range 3] %x] for {set hi $h0} {$hi <= $hend} {incr hi} { for {set lo $l0} {$lo <= $lend} {incr lo} { set code [expr {$hi << 8 | ($lo & 0xff)}] uplevel 1 $command } } } else { error "really?" } } } proc gen-jisx0208-euc-jp {code} { binary format cc \ [expr {($code >> 8) | 0x80}] [expr {($code & 0xff) | 0x80}] } proc gen-jisx0208-iso2022-jp {code} { binary format a3cca3 \ "\x1b\$B" [expr {$code >> 8}] [expr {$code & 0xff}] "\x1b(B" } proc gen-jisx0208-cp932 {code} { set c1 [expr {($code >> 8) | 0x80}] set c2 [expr {($code & 0xff)| 0x80}] if {$c1 % 2} { set c1 [expr {($c1 >> 1) + ($c1 < 0xdf ? 0x31 : 0x71)}] incr c2 [expr {- (0x60 + ($c2 < 0xe0))}] } else { set c1 [expr {($c1 >> 1) + ($c1 < 0xdf ? 0x30 : 0x70)}] incr c2 -2 } binary format cc $c1 $c2 } proc channel-diff {fa fb} { set diff {} while {[gets $fa la] >= 0 && [gets $fb lb] >= 0} { if {[string compare $la $lb] == 0} continue # lappend diff $la $lb # For more readable (easy to analyze) output. set code [lindex $la 0] binary scan [lindex $la 1] H* expected binary scan [lindex $lb 1] H* got lappend diff [list $code $expected $got] } set diff } # Create char tables. cd [temporaryDirectory] foreach enc {cp932 euc-jp iso2022-jp} { set f [open $enc.chars w] fconfigure $f -encoding binary foreach-jisx0208 code { puts $f [format "%04X %s" $code [gen-jisx0208-$enc $code]] } close $f } # shiftjis == cp932 for jisx0208. file copy -force cp932.chars shiftjis.chars set NUM 0 foreach from {cp932 shiftjis euc-jp iso2022-jp} { foreach to {cp932 shiftjis euc-jp iso2022-jp} { test encoding-25.[incr NUM] "jisx0208 $from => $to" { cd [temporaryDirectory] set f [open $from.chars] fconfigure $f -encoding $from set out [open $from.$to.out w] fconfigure $out -encoding $to puts -nonewline $out [read $f] close $out close $f # then compare $to.chars <=> $from.to.out as binary. set fa [open $to.chars] fconfigure $fa -encoding binary set fb [open $from.$to.out] fconfigure $fb -encoding binary set diff [channel-diff $fa $fb] close $fa close $fb # Difference should be empty. set diff } {} } } eval [list file delete] [glob -directory [temporaryDirectory] *.chars *.out] # ===> Cut here <=== # EscapeFreeProc, GetTableEncoding, unilen # are fully tested by the rest of this file # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/switch.test0000644003604700454610000001533311737050674014270 0ustar dgp771div# Commands covered: switch # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1993 The Regents of the University of California. # Copyright (c) 1994 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } test switch-1.1 {simple patterns} { switch a a {format 1} b {format 2} c {format 3} default {format 4} } 1 test switch-1.2 {simple patterns} { switch b a {format 1} b {format 2} c {format 3} default {format 4} } 2 test switch-1.3 {simple patterns} { switch x a {format 1} b {format 2} c {format 3} default {format 4} } 4 test switch-1.4 {simple patterns} { switch x a {format 1} b {format 2} c {format 3} } {} test switch-1.5 {simple pattern matches many times} { switch b a {format 1} b {format 2} b {format 3} b {format 4} } 2 test switch-1.6 {simple patterns} { switch default a {format 1} default {format 2} c {format 3} default {format 4} } 2 test switch-1.7 {simple patterns} { switch x a {format 1} default {format 2} c {format 3} default {format 4} } 4 test switch-2.1 {single-argument form for pattern/command pairs} { switch b { a {format 1} b {format 2} default {format 6} } } {2} test switch-2.2 {single-argument form for pattern/command pairs} { list [catch {switch z {a 2 b}} msg] $msg } {1 {extra switch pattern with no body}} test switch-3.1 {-exact vs. -glob vs. -regexp} { switch -exact aaaab { ^a*b$ {concat regexp} *b {concat glob} aaaab {concat exact} default {concat none} } } exact test switch-3.2 {-exact vs. -glob vs. -regexp} { switch -regexp aaaab { ^a*b$ {concat regexp} *b {concat glob} aaaab {concat exact} default {concat none} } } regexp test switch-3.3 {-exact vs. -glob vs. -regexp} { switch -glob aaaab { ^a*b$ {concat regexp} *b {concat glob} aaaab {concat exact} default {concat none} } } glob test switch-3.4 {-exact vs. -glob vs. -regexp} { switch aaaab {^a*b$} {concat regexp} *b {concat glob} \ aaaab {concat exact} default {concat none} } exact test switch-3.5 {-exact vs. -glob vs. -regexp} { switch -- -glob { ^g.*b$ {concat regexp} -* {concat glob} -glob {concat exact} default {concat none} } } exact test switch-3.6 {-exact vs. -glob vs. -regexp} { list [catch {switch -foo a b c} msg] $msg } {1 {bad option "-foo": must be -exact, -glob, -regexp, or --}} test switch-4.1 {error in executed command} { list [catch {switch a a {error "Just a test"} default {format 1}} msg] \ $msg $errorInfo } {1 {Just a test} {Just a test while executing "error "Just a test"" ("a" arm line 1) invoked from within "switch a a {error "Just a test"} default {format 1}"}} test switch-4.2 {error: not enough args} { list [catch {switch} msg] $msg } {1 {wrong # args: should be "switch ?switches? string pattern body ... ?default body?"}} test switch-4.3 {error: pattern with no body} { list [catch {switch a b} msg] $msg } {1 {extra switch pattern with no body}} test switch-4.4 {error: pattern with no body} { list [catch {switch a b {format 1} c} msg] $msg } {1 {extra switch pattern with no body}} test switch-4.5 {error in default command} { list [catch {switch foo a {error switch1} b {error switch 3} \ default {error switch2}} msg] $msg $errorInfo } {1 switch2 {switch2 while executing "error switch2" ("default" arm line 1) invoked from within "switch foo a {error switch1} b {error switch 3} default {error switch2}"}} test switch-5.1 {errors in -regexp matching} { list [catch {switch -regexp aaaab { *b {concat glob} aaaab {concat exact} default {concat none} }} msg] $msg } {1 {couldn't compile regular expression pattern: quantifier operand invalid}} test switch-6.1 {backslashes in patterns} { switch -exact {\a\$\.\[} { \a\$\.\[ {concat first} \a\\$\.\\[ {concat second} \\a\\$\\.\\[ {concat third} {\a\\$\.\\[} {concat fourth} {\\a\\$\\.\\[} {concat fifth} default {concat none} } } third test switch-6.2 {backslashes in patterns} { switch -exact {\a\$\.\[} { \a\$\.\[ {concat first} {\a\$\.\[} {concat second} {{\a\$\.\[}} {concat third} default {concat none} } } second test switch-7.1 {"-" bodies} { switch a { a - b - c {concat 1} default {concat 2} } } 1 test switch-7.2 {"-" bodies} { list [catch { switch a { a - b - c - } } msg] $msg } {1 {no body specified for pattern "c"}} test switch-7.3 {"-" bodies} { list [catch { switch a { a - b -foo c - } } msg] $msg } {1 {no body specified for pattern "c"}} test switch-8.1 {empty body} { set msg {} switch {2} { 1 {set msg 1} 2 {} default {set msg 2} } } {} test switch-9.1 {empty pattern/body list} { list [catch {switch x} msg] $msg } {1 {wrong # args: should be "switch ?switches? string pattern body ... ?default body?"}} test switch-9.2 {empty pattern/body list} { list [catch {switch -- x} msg] $msg } {1 {wrong # args: should be "switch ?switches? string pattern body ... ?default body?"}} test switch-9.3 {empty pattern/body list} { list [catch {switch x {}} msg] $msg } {1 {wrong # args: should be "switch ?switches? string {pattern body ... ?default body?}"}} test switch-9.4 {empty pattern/body list} { list [catch {switch -- x {}} msg] $msg } {1 {wrong # args: should be "switch ?switches? string {pattern body ... ?default body?}"}} test switch-9.5 {unpaired pattern} { list [catch {switch x a {} b} msg] $msg } {1 {extra switch pattern with no body}} test switch-9.6 {unpaired pattern} { list [catch {switch x {a {} b}} msg] $msg } {1 {extra switch pattern with no body}} test switch-9.7 {unpaired pattern} { list [catch {switch x a {} # comment b} msg] $msg } {1 {extra switch pattern with no body}} test switch-9.8 {unpaired pattern} { list [catch {switch x {a {} # comment b}} msg] $msg } {1 {extra switch pattern with no body, this may be due to a comment incorrectly placed outside of a switch body - see the "switch" documentation}} test switch-9.9 {unpaired pattern} { list [catch {switch x a {} x {} # comment b} msg] $msg } {1 {extra switch pattern with no body}} test switch-9.10 {unpaired pattern} { list [catch {switch x {a {} x {} # comment b}} msg] $msg } {1 {extra switch pattern with no body, this may be due to a comment incorrectly placed outside of a switch body - see the "switch" documentation}} # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/assocd.test0000644003604700454610000000354711737050674014247 0ustar dgp771div# This file tests the AssocData facility of Tcl # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1994 The Regents of the University of California. # Copyright (c) 1994 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } if {[string compare testsetassocdata [info commands testsetassocdata]] != 0} { puts "This application hasn't been compiled with the tests for assocData," puts "therefore I am skipping all of these tests." ::tcltest::cleanupTests return } test assocd-1.1 {testing setting assoc data} { testsetassocdata a 1 } "" test assocd-1.2 {testing setting assoc data} { testsetassocdata a 2 } "" test assocd-1.3 {testing setting assoc data} { testsetassocdata 123 456 } "" test assocd-1.4 {testing setting assoc data} { testsetassocdata abc "abc d e f" } "" test assocd-2.1 {testing getting assoc data} { testgetassocdata a } 2 test assocd-2.2 {testing getting assoc data} { testgetassocdata 123 } 456 test assocd-2.3 {testing getting assoc data} { testgetassocdata abc } {abc d e f} test assocd-2.4 {testing getting assoc data} { testgetassocdata xxx } "" test assocd-3.1 {testing deleting assoc data} { testdelassocdata a } "" test assocd-3.2 {testing deleting assoc data} { testdelassocdata 123 } "" test assocd-3.3 {testing deleting assoc data} { list [catch {testdelassocdata nonexistent} msg] $msg } {0 {}} # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/iogt.test0000644003604700454610000005167111737050674013736 0ustar dgp771div# -*- tcl -*- # Commands covered: transform, and stacking in general # # This file contains a collection of tests for Giot # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # Copyright (c) 2000 Ajuba Solutions. # Copyright (c) 2000 Andreas Kupries. # All rights reserved. if {[catch {package require tcltest 2.1}]} { puts stderr "Skipping tests in [info script]. tcltest 2.1 required." return } namespace eval ::tcl::test::iogt { namespace import ::tcltest::cleanupTests namespace import ::tcltest::makeFile namespace import ::tcltest::removeFile namespace import ::tcltest::test namespace import ::tcltest::testConstraint testConstraint testchannel [llength [info commands testchannel]] set path(dummy) [makeFile {abcdefghijklmnopqrstuvwxyz0123456789,./?><;'\|":[]\}\{`~!@#$%^&*()_+-= } dummy] # " capture coloring of quotes set path(dummyout) [makeFile {} dummyout] set path(__echo_srv__.tcl) [makeFile { #!/usr/local/bin/tclsh # -*- tcl -*- # echo server # # arguments, options: port to listen on for connections. # delay till echo of first block # delay between blocks # blocksize ... set port [lindex $argv 0] set fdelay [lindex $argv 1] set idelay [lindex $argv 2] set bsizes [lrange $argv 3 end] set c 0 proc newconn {sock rhost rport} { variable fdelay variable c incr c variable c$c #puts stdout "C $sock $rhost $rport / $fdelay" ; flush stdout upvar 0 c$c conn set conn(after) {} set conn(state) 0 set conn(size) 0 set conn(data) "" set conn(delay) $fdelay fileevent $sock readable [list echoGet $c $sock] fconfigure $sock -translation binary -buffering none -blocking 0 } proc echoGet {c sock} { variable fdelay variable c$c upvar 0 c$c conn if {[eof $sock]} { # one-shot echo exit } append conn(data) [read $sock] #puts stdout "G $c $sock $conn(data) <<$conn(data)>>" ; flush stdout if {$conn(after) == {}} { set conn(after) [after $conn(delay) [list echoPut $c $sock]] } } proc echoPut {c sock} { variable idelay variable fdelay variable bsizes variable c$c upvar 0 c$c conn if {[string length $conn(data)] == 0} { #puts stdout "C $c $sock" ; flush stdout # auto terminate close $sock exit #set conn(delay) $fdelay return } set conn(delay) $idelay set n [lindex $bsizes $conn(size)] #puts stdout "P $c $sock $n >>" ; flush stdout #puts __________________________________________ #parray conn #puts n=<$n> if {[string length $conn(data)] >= $n} { puts -nonewline $sock [string range $conn(data) 0 $n] set conn(data) [string range $conn(data) [incr n] end] } incr conn(size) if {$conn(size) >= [llength $bsizes]} { set conn(size) [expr {[llength $bsizes]-1}] } set conn(after) [after $conn(delay) [list echoPut $c $sock]] } #fileevent stdin readable {exit ;#cut} # main socket -server newconn $port vwait forever } __echo_srv__.tcl] ######################################################################## proc fevent {fdelay idelay blocks script data} { # start and initialize an echo server, prepare data # transmission, then hand over to the test script. # this has to start real transmission via 'flush'. # The server is stopped after completion of the test. # fixed port, not so good. lets hope for the best, for now. set port 4000 eval exec tclsh __echo_srv__.tcl \ $port $fdelay $idelay $blocks >@stdout & after 500 #puts stdout "> $port" ; flush stdout set sk [socket localhost $port] fconfigure $sk \ -blocking 0 \ -buffering full \ -buffersize [expr {10+[llength $data]}] puts -nonewline $sk $data # The channel is prepared to go off. #puts stdout ">>>>>" ; flush stdout uplevel #0 set sock $sk set res [uplevel #0 $script] catch {close $sk} return $res } # -------------------------------------------------------------- # utility transformations ... proc id {op data} { switch -- $op { create/write - create/read - delete/write - delete/read - clear_read {;#ignore} flush/write - flush/read - write - read { return $data } query/maxRead {return -1} } } proc id_optrail {var op data} { variable $var upvar 0 $var trail lappend trail $op switch -- $op { create/write - create/read - delete/write - delete/read - flush/read - clear/read { #ignore } flush/write - write - read { return $data } query/maxRead { return -1 } default { lappend trail "error $op" error $op } } } proc id_fulltrail {var op data} { variable $var upvar 0 $var trail #puts stdout ">> $var $op $data" ; flush stdout switch -- $op { create/write - create/read - delete/write - delete/read - clear_read { set res *ignored* } flush/write - flush/read - write - read { set res $data } query/maxRead { set res -1 } } #catch {puts stdout "\t>* $res" ; flush stdout} #catch {puts stdout "x$res"} msg lappend trail [list $op $data $res] return $res } proc counter {var op data} { variable $var upvar 0 $var n switch -- $op { create/write - create/read - delete/write - delete/read - clear_read {;#ignore} flush/write - flush/read {return {}} write { return $data } read { if {$n > 0} { incr n -[string length $data] if {$n < 0} { set n 0 } } return $data } query/maxRead { return $n } } } proc counter_audit {var vtrail op data} { variable $var variable $vtrail upvar 0 $var n $vtrail trail switch -- $op { create/write - create/read - delete/write - delete/read - clear_read { set res {} } flush/write - flush/read { set res {} } write { set res $data } read { if {$n > 0} { incr n -[string length $data] if {$n < 0} { set n 0 } } set res $data } query/maxRead { set res $n } } lappend trail [list counter:$op $data $res] return $res } proc rblocks {var vtrail n op data} { variable $var variable $vtrail upvar 0 $var buf $vtrail trail set res {} switch -- $op { create/write - create/read - delete/write - delete/read - clear_read { set buf {} } flush/write { } flush/read { set res $buf set buf {} } write { set data } read { append buf $data set b [expr {$n * ([string length $buf] / $n)}] append op " $n [string length $buf] :- $b" set res [string range $buf 0 [incr b -1]] set buf [string range $buf [incr b] end] #return $res } query/maxRead { set res -1 } } lappend trail [list rblock | $op $data $res | $buf] return $res } # -------------------------------------------------------------- # ... and convenience procedures to stack them proc identity {-attach channel} { testchannel transform $channel -command [namespace code id] } proc audit_ops {var -attach channel} { testchannel transform $channel -command [namespace code [list id_optrail $var]] } proc audit_flow {var -attach channel} { testchannel transform $channel -command [namespace code [list id_fulltrail $var]] } proc stopafter {var n -attach channel} { variable $var upvar 0 $var vn set vn $n testchannel transform $channel -command [namespace code [list counter $var]] } proc stopafter_audit {var trail n -attach channel} { variable $var upvar 0 $var vn set vn $n testchannel transform $channel -command [namespace code [list counter_audit $var $trail]] } proc rblocks_t {var trail n -attach channel} { testchannel transform $channel -command [namespace code [list rblocks $var $trail $n]] } # -------------------------------------------------------------- # serialize an array, with keys in sorted order. proc array_sget {v} { upvar $v a set res [list] foreach n [lsort [array names a]] { lappend res $n $a($n) } set res } proc asort {alist} { # sort a list of key/value pairs by key, removes duplicates too. array set a $alist array_sget a } ######################################################################## test iogt-1.1 {stack/unstack} testchannel { set fh [open $path(dummy) r] identity -attach $fh testchannel unstack $fh close $fh } {} test iogt-1.2 {stack/close} testchannel { set fh [open $path(dummy) r] identity -attach $fh close $fh } {} test iogt-1.3 {stack/unstack, configuration, options} testchannel { set fh [open $path(dummy) r] set ca [asort [fconfigure $fh]] identity -attach $fh set cb [asort [fconfigure $fh]] testchannel unstack $fh set cc [asort [fconfigure $fh]] close $fh # With this system none of the buffering, translation and # encoding option may change their values with channels # stacked upon each other or not. # cb == ca == cc list [string equal $ca $cb] [string equal $cb $cc] [string equal $ca $cc] } {1 1 1} test iogt-1.4 {stack/unstack, configuration} testchannel { set fh [open $path(dummy) r] set ca [asort [fconfigure $fh]] identity -attach $fh fconfigure $fh \ -buffering line \ -translation cr \ -encoding shiftjis testchannel unstack $fh set cc [asort [fconfigure $fh]] set res [list \ [string equal $ca $cc] \ [fconfigure $fh -buffering] \ [fconfigure $fh -translation] \ [fconfigure $fh -encoding] \ ] close $fh set res } {0 line cr shiftjis} test iogt-2.0 {basic I/O going through transform} testchannel { set fin [open $path(dummy) r] set fout [open $path(dummyout) w] identity -attach $fin identity -attach $fout fcopy $fin $fout close $fin close $fout set fin [open $path(dummy) r] set fout [open $path(dummyout) r] set res [string equal [set in [read $fin]] [set out [read $fout]]] lappend res [string length $in] [string length $out] close $fin close $fout set res } {1 71 71} test iogt-2.1 {basic I/O, operation trail} {testchannel unixOnly} { set fin [open $path(dummy) r] set fout [open $path(dummyout) w] set ain [list] ; set aout [list] audit_ops ain -attach $fin audit_ops aout -attach $fout fconfigure $fin -buffersize 10 fconfigure $fout -buffersize 10 fcopy $fin $fout close $fin close $fout set res "[join $ain \n]\n--------\n[join $aout \n]" } {create/read query/maxRead read query/maxRead read query/maxRead read query/maxRead read query/maxRead read query/maxRead read query/maxRead read query/maxRead read query/maxRead flush/read delete/read -------- create/write write write write write write write write write flush/write delete/write} test iogt-2.2 {basic I/O, data trail} {testchannel unixOnly} { set fin [open $path(dummy) r] set fout [open $path(dummyout) w] set ain [list] ; set aout [list] audit_flow ain -attach $fin audit_flow aout -attach $fout fconfigure $fin -buffersize 10 fconfigure $fout -buffersize 10 fcopy $fin $fout close $fin close $fout set res "[join $ain \n]\n--------\n[join $aout \n]" } {create/read {} *ignored* query/maxRead {} -1 read abcdefghij abcdefghij query/maxRead {} -1 read klmnopqrst klmnopqrst query/maxRead {} -1 read uvwxyz0123 uvwxyz0123 query/maxRead {} -1 read 456789,./? 456789,./? query/maxRead {} -1 read {><;'\|":[]} {><;'\|":[]} query/maxRead {} -1 read {\}\{`~!@#$} {\}\{`~!@#$} query/maxRead {} -1 read %^&*()_+-= %^&*()_+-= query/maxRead {} -1 read { } { } query/maxRead {} -1 flush/read {} {} delete/read {} *ignored* -------- create/write {} *ignored* write abcdefghij abcdefghij write klmnopqrst klmnopqrst write uvwxyz0123 uvwxyz0123 write 456789,./? 456789,./? write {><;'\|":[]} {><;'\|":[]} write {\}\{`~!@#$} {\}\{`~!@#$} write %^&*()_+-= %^&*()_+-= write { } { } flush/write {} {} delete/write {} *ignored*} test iogt-2.3 {basic I/O, mixed trail} {testchannel unixOnly} { set fin [open $path(dummy) r] set fout [open $path(dummyout) w] set trail [list] audit_flow trail -attach $fin audit_flow trail -attach $fout fconfigure $fin -buffersize 20 fconfigure $fout -buffersize 10 fcopy $fin $fout close $fin close $fout join $trail \n } {create/read {} *ignored* create/write {} *ignored* query/maxRead {} -1 read abcdefghijklmnopqrst abcdefghijklmnopqrst write abcdefghij abcdefghij write klmnopqrst klmnopqrst query/maxRead {} -1 read uvwxyz0123456789,./? uvwxyz0123456789,./? write uvwxyz0123 uvwxyz0123 write 456789,./? 456789,./? query/maxRead {} -1 read {><;'\|":[]\}\{`~!@#$} {><;'\|":[]\}\{`~!@#$} write {><;'\|":[]} {><;'\|":[]} write {\}\{`~!@#$} {\}\{`~!@#$} query/maxRead {} -1 read {%^&*()_+-= } {%^&*()_+-= } query/maxRead {} -1 flush/read {} {} write %^&*()_+-= %^&*()_+-= write { } { } delete/read {} *ignored* flush/write {} {} delete/write {} *ignored*} test iogt-3.0 {Tcl_Channel valid after stack/unstack, fevent handling} \ {testchannel unknownFailure} { # This test to check the validity of aquired Tcl_Channel references is # not possible because even a backgrounded fcopy will immediately start # to copy data, without waiting for the event loop. This is done only in # case of an underflow on the read size!. So stacking transforms after the # fcopy will miss information, or are not used at all. # # I was able to circumvent this by using the echo.tcl server with a big # delay, causing the fcopy to underflow immediately. proc DoneCopy {n {err {}}} { variable copy ; set copy 1 } set fin [open $path(dummy) r] fevent 1000 500 {20 20 20 10 1 1} { close $fin set fout [open dummyout w] flush $sock ; # now, or fcopy will error us out # But the 1 second delay should be enough to # initialize everything else here. fcopy $sock $fout -command [namespace code DoneCopy] # transform after fcopy got its handles ! # They should be still valid for fcopy. set trail [list] audit_ops trail -attach $fout vwait [namespace which -variable copy] } [read $fin] ; # {} close $fout rename DoneCopy {} # Check result of copy. set fin [open $path(dummy) r] set fout [open $path(dummyout) r] set res [string equal [read $fin] [read $fout]] close $fin close $fout list $res $trail } {1 {create/write create/read write flush/write flush/read delete/write delete/read}} test iogt-4.0 {fileevent readable, after transform} {testchannel unknownFailure} { set fin [open $path(dummy) r] set data [read $fin] close $fin set trail [list] set got [list] proc Done {args} { variable stop set stop 1 } proc Get {sock} { variable trail variable got if {[eof $sock]} { Done lappend trail "xxxxxxxxxxxxx" close $sock return } lappend trail "vvvvvvvvvvvvv" lappend trail "\tgot: [lappend got "\[\[[read $sock]\]\]"]" lappend trail "=============" #puts stdout $__ ; flush stdout #read $sock } fevent 1000 500 {20 20 20 10 1} { audit_flow trail -attach $sock rblocks_t rbuf trail 23 -attach $sock fileevent $sock readable [list Get $sock] flush $sock ; # now, or fcopy will error us out # But the 1 second delay should be enough to # initialize everything else here. vwait [namespace which -variable stop] } $data rename Done {} rename Get {} join [list [join $got \n] ~~~~~~~~ [join $trail \n]] \n } {[[]] [[abcdefghijklmnopqrstuvw]] [[xyz0123456789,./?><;'\|]] [[]] [[]] [[":[]\}\{`~!@#$%^&*()]] [[]] ~~~~~~~~ create/write {} *ignored* create/read {} *ignored* rblock | create/write {} {} | {} rblock | create/read {} {} | {} vvvvvvvvvvvvv rblock | query/maxRead {} -1 | {} query/maxRead {} -1 read abcdefghijklmnopqrstu abcdefghijklmnopqrstu query/maxRead {} -1 rblock | {read 23 21 :- 0} abcdefghijklmnopqrstu {} | abcdefghijklmnopqrstu rblock | query/maxRead {} -1 | abcdefghijklmnopqrstu query/maxRead {} -1 got: {[[]]} ============= vvvvvvvvvvvvv rblock | query/maxRead {} -1 | abcdefghijklmnopqrstu query/maxRead {} -1 read vwxyz0123456789,./?>< vwxyz0123456789,./?>< query/maxRead {} -1 rblock | {read 23 42 :- 23} vwxyz0123456789,./?>< abcdefghijklmnopqrstuvw | xyz0123456789,./?>< rblock | query/maxRead {} -1 | xyz0123456789,./?>< query/maxRead {} -1 got: {[[]]} {[[abcdefghijklmnopqrstuvw]]} ============= vvvvvvvvvvvvv rblock | query/maxRead {} -1 | xyz0123456789,./?>< query/maxRead {} -1 read {;'\|":[]\}\{`~!@#$%^&} {;'\|":[]\}\{`~!@#$%^&} query/maxRead {} -1 rblock | {read 23 40 :- 23} {;'\|":[]\}\{`~!@#$%^&} {xyz0123456789,./?><;'\|} | {":[]\}\{`~!@#$%^&} rblock | query/maxRead {} -1 | {":[]\}\{`~!@#$%^&} query/maxRead {} -1 got: {[[]]} {[[abcdefghijklmnopqrstuvw]]} {[[xyz0123456789,./?><;'\|]]} ============= vvvvvvvvvvvvv rblock | query/maxRead {} -1 | {":[]\}\{`~!@#$%^&} query/maxRead {} -1 read *( *( query/maxRead {} -1 rblock | {read 23 19 :- 0} *( {} | {":[]\}\{`~!@#$%^&*(} rblock | query/maxRead {} -1 | {":[]\}\{`~!@#$%^&*(} query/maxRead {} -1 got: {[[]]} {[[abcdefghijklmnopqrstuvw]]} {[[xyz0123456789,./?><;'\|]]} {[[]]} ============= vvvvvvvvvvvvv rblock | query/maxRead {} -1 | {":[]\}\{`~!@#$%^&*(} query/maxRead {} -1 read ) ) query/maxRead {} -1 rblock | {read 23 20 :- 0} ) {} | {":[]\}\{`~!@#$%^&*()} rblock | query/maxRead {} -1 | {":[]\}\{`~!@#$%^&*()} query/maxRead {} -1 got: {[[]]} {[[abcdefghijklmnopqrstuvw]]} {[[xyz0123456789,./?><;'\|]]} {[[]]} {[[]]} ============= vvvvvvvvvvvvv rblock | query/maxRead {} -1 | {":[]\}\{`~!@#$%^&*()} query/maxRead {} -1 flush/read {} {} rblock | flush/read {} {":[]\}\{`~!@#$%^&*()} | {} rblock | query/maxRead {} -1 | {} query/maxRead {} -1 got: {[[]]} {[[abcdefghijklmnopqrstuvw]]} {[[xyz0123456789,./?><;'\|]]} {[[]]} {[[]]} {[[":[]\}\{`~!@#$%^&*()]]} ============= vvvvvvvvvvvvv rblock | query/maxRead {} -1 | {} query/maxRead {} -1 got: {[[]]} {[[abcdefghijklmnopqrstuvw]]} {[[xyz0123456789,./?><;'\|]]} {[[]]} {[[]]} {[[":[]\}\{`~!@#$%^&*()]]} {[[]]} xxxxxxxxxxxxx rblock | flush/write {} {} | {} rblock | delete/write {} {} | {} rblock | delete/read {} {} | {} flush/write {} {} delete/write {} *ignored* delete/read {} *ignored*} ; # catch unescaped quote " test iogt-5.0 {EOF simulation} {testchannel unknownFailure} { set fin [open $path(dummy) r] set fout [open $path(dummyout) w] set trail [list] audit_flow trail -attach $fin stopafter_audit d trail 20 -attach $fin audit_flow trail -attach $fout fconfigure $fin -buffersize 20 fconfigure $fout -buffersize 10 fcopy $fin $fout testchannel unstack $fin # now copy the rest in the channel lappend trail {**after unstack**} fcopy $fin $fout close $fin close $fout join $trail \n } {create/read {} *ignored* counter:create/read {} {} create/write {} *ignored* counter:query/maxRead {} 20 query/maxRead {} -1 read {abcdefghijklmnopqrstuvwxyz0123456789,./?><;'\|":[]\}\{`~!@#$%^&*()_+-= } {abcdefghijklmnopqrstuvwxyz0123456789,./?><;'\|":[]\}\{`~!@#$%^&*()_+-= } query/maxRead {} -1 flush/read {} {} counter:read abcdefghijklmnopqrst abcdefghijklmnopqrst write abcdefghij abcdefghij write klmnopqrst klmnopqrst counter:query/maxRead {} 0 counter:flush/read {} {} counter:delete/read {} {} **after unstack** query/maxRead {} -1 write uvwxyz0123 uvwxyz0123 write 456789,./? 456789,./? write {><;'\|":[]} {><;'\|":[]} write {\}\{`~!@#$} {\}\{`~!@#$} write %^&*()_+-= %^&*()_+-= write { } { } query/maxRead {} -1 delete/read {} *ignored* flush/write {} {} delete/write {} *ignored*} proc constX {op data} { # replace anything coming in with a same-length string of x'es. switch -- $op { create/write - create/read - delete/write - delete/read - clear_read {;#ignore} flush/write - flush/read - write - read { return [string repeat x [string length $data]] } query/maxRead {return -1} } } proc constx {-attach channel} { testchannel transform $channel -command [namespace code constX] } test iogt-6.0 {Push back} testchannel { set f [open $path(dummy) r] # contents of dummy = "abcdefghi..." read $f 3 ; # skip behind "abc" constx -attach $f # expect to get "xxx" from the transform because # of unread "def" input to transform which returns "xxx". # # Actually the IO layer pre-read the whole file and will # read "def" directly from the buffer without bothering # to consult the newly stacked transformation. This is # wrong. set res [read $f 3] close $f set res } {xxx} test iogt-6.1 {Push back and up} {testchannel knownBug} { set f [open $path(dummy) r] # contents of dummy = "abcdefghi..." read $f 3 ; # skip behind "abc" constx -attach $f set res [read $f 3] testchannel unstack $f append res [read $f 3] close $f set res } {xxxghi} # cleanup foreach file [list dummy dummyout __echo_srv__.tcl] { removeFile $file } cleanupTests } namespace delete ::tcl::test::iogt return tcl8.4.20/tests/case.test0000644003604700454610000000562111737050674013701 0ustar dgp771div# Commands covered: case # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } test case-1.1 {simple pattern} { case a in a {format 1} b {format 2} c {format 3} default {format 4} } 1 test case-1.2 {simple pattern} { case b a {format 1} b {format 2} c {format 3} default {format 4} } 2 test case-1.3 {simple pattern} { case x in a {format 1} b {format 2} c {format 3} default {format 4} } 4 test case-1.4 {simple pattern} { case x a {format 1} b {format 2} c {format 3} } {} test case-1.5 {simple pattern matches many times} { case b a {format 1} b {format 2} b {format 3} b {format 4} } 2 test case-1.6 {fancier pattern} { case cx a {format 1} *c {format 2} *x {format 3} default {format 4} } 3 test case-1.7 {list of patterns} { case abc in {a b c} {format 1} {def abc ghi} {format 2} } 2 test case-2.1 {error in executed command} { list [catch {case a in a {error "Just a test"} default {format 1}} msg] \ $msg $errorInfo } {1 {Just a test} {Just a test while executing "error "Just a test"" ("a" arm line 1) invoked from within "case a in a {error "Just a test"} default {format 1}"}} test case-2.2 {error: not enough args} { list [catch {case} msg] $msg } {1 {wrong # args: should be "case string ?in? patList body ... ?default body?"}} test case-2.3 {error: pattern with no body} { list [catch {case a b} msg] $msg } {1 {extra case pattern with no body}} test case-2.4 {error: pattern with no body} { list [catch {case a in b {format 1} c} msg] $msg } {1 {extra case pattern with no body}} test case-2.5 {error in default command} { list [catch {case foo in a {error case1} default {error case2} \ b {error case 3}} msg] $msg $errorInfo } {1 case2 {case2 while executing "error case2" ("default" arm line 1) invoked from within "case foo in a {error case1} default {error case2} b {error case 3}"}} test case-3.1 {single-argument form for pattern/command pairs} { case b in { a {format 1} b {format 2} default {format 6} } } {2} test case-3.2 {single-argument form for pattern/command pairs} { case b { a {format 1} b {format 2} default {format 6} } } {2} test case-3.3 {single-argument form for pattern/command pairs} { list [catch {case z in {a 2 b}} msg] $msg } {1 {extra case pattern with no body}} # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/trace.test0000644003604700454610000022517112133546540014061 0ustar dgp771div# Commands covered: trace # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } # Used for constraining memory leak tests testConstraint memory [llength [info commands memory]] testConstraint testevalobjv [llength [info commands testevalobjv]] proc getbytes {} { set lines [split [memory info] "\n"] lindex [lindex $lines 3] 3 } proc traceScalar {name1 name2 op} { global info set info [list $name1 $name2 $op [catch {uplevel set $name1} msg] $msg] } proc traceScalarAppend {name1 name2 op} { global info lappend info $name1 $name2 $op [catch {uplevel set $name1} msg] $msg } proc traceArray {name1 name2 op} { global info set info [list $name1 $name2 $op [catch {uplevel set [set name1]($name2)} msg] $msg] } proc traceArray2 {name1 name2 op} { global info set info [list $name1 $name2 $op] } proc traceProc {name1 name2 op} { global info set info [concat $info [list $name1 $name2 $op]] } proc traceTag {tag args} { global info set info [concat $info $tag] } proc traceError {args} { error "trace returned error" } proc traceCheck {cmd args} { global info set info [list [catch $cmd msg] $msg] } proc traceCrtElement {value name1 name2 op} { uplevel set ${name1}($name2) $value } proc traceCommand {oldName newName op} { global info set info [list $oldName $newName $op] } test trace-0.0 {memory corruption in trace (Tcl Bug 484339)} { # You may need Purify or Electric Fence to reliably # see this one fail. catch {unset z} trace add variable z array {set z(foo) 1 ;#} set res "names: [array names z]" catch {unset ::z} trace variable ::z w {unset ::z; error "memory corruption";#} list [catch {set ::z 1} msg] $msg } {1 {can't set "::z": memory corruption}} # Read-tracing on variables test trace-1.1 {trace variable reads} { catch {unset x} set info {} trace add variable x read traceScalar list [catch {set x} msg] $msg $info } {1 {can't read "x": no such variable} {x {} read 1 {can't read "x": no such variable}}} test trace-1.2 {trace variable reads} { catch {unset x} set x 123 set info {} trace add variable x read traceScalar list [catch {set x} msg] $msg $info } {0 123 {x {} read 0 123}} test trace-1.3 {trace variable reads} { catch {unset x} set info {} trace add variable x read traceScalar set x 123 set info } {} test trace-1.4 {trace array element reads} { catch {unset x} set info {} trace add variable x(2) read traceArray list [catch {set x(2)} msg] $msg $info } {1 {can't read "x(2)": no such element in array} {x 2 read 1 {can't read "x(2)": no such element in array}}} test trace-1.5 {trace array element reads} { catch {unset x} set x(2) zzz set info {} trace add variable x(2) read traceArray list [catch {set x(2)} msg] $msg $info } {0 zzz {x 2 read 0 zzz}} test trace-1.6 {trace array element reads} { catch {unset x} set info {} trace add variable x read traceArray2 proc p {} { global x set x(2) willi return $x(2) } list [catch {p} msg] $msg $info } {0 willi {x 2 read}} test trace-1.7 {trace array element reads, create element undefined if nonexistant} { catch {unset x} set info {} trace add variable x read q proc q {name1 name2 op} { global info set info [list $name1 $name2 $op] global $name1 set ${name1}($name2) wolf } proc p {} { global x set x(X) willi return $x(Y) } list [catch {p} msg] $msg $info } {0 wolf {x Y read}} test trace-1.8 {trace reads on whole arrays} { catch {unset x} set info {} trace add variable x read traceArray list [catch {set x(2)} msg] $msg $info } {1 {can't read "x(2)": no such variable} {}} test trace-1.9 {trace reads on whole arrays} { catch {unset x} set x(2) zzz set info {} trace add variable x read traceArray list [catch {set x(2)} msg] $msg $info } {0 zzz {x 2 read 0 zzz}} test trace-1.10 {trace variable reads} { catch {unset x} set x 444 set info {} trace add variable x read traceScalar unset x set info } {} test trace-1.11 {read traces that modify the array structure} { catch {unset x} set x(bar) 0 trace variable x r {set x(foo) 1 ;#} trace variable x r {unset -nocomplain x(bar) ;#} array get x } {} test trace-1.12 {read traces that modify the array structure} { catch {unset x} set x(bar) 0 trace variable x r {unset -nocomplain x(bar) ;#} trace variable x r {set x(foo) 1 ;#} array get x } {} test trace-1.13 {read traces that modify the array structure} { catch {unset x} set x(bar) 0 trace variable x r {set x(foo) 1 ;#} trace variable x r {unset -nocomplain x;#} list [catch {array get x} res] $res } {1 {can't read "x(bar)": no such variable}} test trace-1.14 {read traces that modify the array structure} { catch {unset x} set x(bar) 0 trace variable x r {unset -nocomplain x;#} trace variable x r {set x(foo) 1 ;#} list [catch {array get x} res] $res } {1 {can't read "x(bar)": no such variable}} # Basic write-tracing on variables test trace-2.1 {trace variable writes} { catch {unset x} set info {} trace add variable x write traceScalar set x 123 set info } {x {} write 0 123} test trace-2.2 {trace writes to array elements} { catch {unset x} set info {} trace add variable x(33) write traceArray set x(33) 444 set info } {x 33 write 0 444} test trace-2.3 {trace writes on whole arrays} { catch {unset x} set info {} trace add variable x write traceArray set x(abc) qq set info } {x abc write 0 qq} test trace-2.4 {trace variable writes} { catch {unset x} set x 1234 set info {} trace add variable x write traceScalar set x set info } {} test trace-2.5 {trace variable writes} { catch {unset x} set x 1234 set info {} trace add variable x write traceScalar unset x set info } {} test trace-2.6 {trace variable writes on compiled local} { # # Check correct function of whole array traces on compiled local # arrays [Bug 1770591]. The corresponding function for read traces is # already indirectly tested in trace-1.7 # catch {unset x} set info {} proc p {} { trace add variable x write traceArray set x(X) willy } p set info } {x X write 0 willy} test trace-2.7 {trace variable writes on errorInfo} -body { # # Check correct behaviour of write traces on errorInfo. # [Bug 1773040] trace add variable ::errorInfo write traceScalar catch {set dne} lrange [set info] 0 2 } -cleanup { # always remove trace on errorInfo otherwise further tests will fail unset ::errorInfo } -result {::errorInfo {} write} # append no longer triggers read traces when fetching the old values of # variables before doing the append operation. However, lappend _does_ # still trigger these read traces. Also lappend triggers only one write # trace: after appending all arguments to the list. test trace-3.1 {trace variable read-modify-writes} { catch {unset x} set info {} trace add variable x read traceScalarAppend append x 123 append x 456 lappend x 789 set info } {x {} read 0 123456} test trace-3.2 {trace variable read-modify-writes} { catch {unset x} set info {} trace add variable x {read write} traceScalarAppend append x 123 lappend x 456 set info } {x {} write 0 123 x {} read 0 123 x {} write 0 {123 456}} # Basic unset-tracing on variables test trace-4.1 {trace variable unsets} { catch {unset x} set info {} trace add variable x unset traceScalar catch {unset x} set info } {x {} unset 1 {can't read "x": no such variable}} test trace-4.2 {variable mustn't exist during unset trace} { catch {unset x} set x 1234 set info {} trace add variable x unset traceScalar unset x set info } {x {} unset 1 {can't read "x": no such variable}} test trace-4.3 {unset traces mustn't be called during reads and writes} { catch {unset x} set info {} trace add variable x unset traceScalar set x 44 set x set info } {} test trace-4.4 {trace unsets on array elements} { catch {unset x} set x(0) 18 set info {} trace add variable x(1) unset traceArray catch {unset x(1)} set info } {x 1 unset 1 {can't read "x(1)": no such element in array}} test trace-4.5 {trace unsets on array elements} { catch {unset x} set x(1) 18 set info {} trace add variable x(1) unset traceArray unset x(1) set info } {x 1 unset 1 {can't read "x(1)": no such element in array}} test trace-4.6 {trace unsets on array elements} { catch {unset x} set x(1) 18 set info {} trace add variable x(1) unset traceArray unset x set info } {x 1 unset 1 {can't read "x(1)": no such variable}} test trace-4.7 {trace unsets on whole arrays} { catch {unset x} set x(1) 18 set info {} trace add variable x unset traceProc catch {unset x(0)} set info } {} test trace-4.8 {trace unsets on whole arrays} { catch {unset x} set x(1) 18 set x(2) 144 set x(3) 14 set info {} trace add variable x unset traceProc unset x(1) set info } {x 1 unset} test trace-4.9 {trace unsets on whole arrays} { catch {unset x} set x(1) 18 set x(2) 144 set x(3) 14 set info {} trace add variable x unset traceProc unset x set info } {x {} unset} # Array tracing on variables test trace-5.1 {array traces fire on accesses via [array]} { catch {unset x} set x(b) 2 trace add variable x array traceArray2 set ::info {} array set x {a 1} set ::info } {x {} array} test trace-5.2 {array traces do not fire on normal accesses} { catch {unset x} set x(b) 2 trace add variable x array traceArray2 set ::info {} set x(a) 1 set x(b) $x(a) set ::info } {} test trace-5.3 {array traces do not outlive variable} { catch {unset x} trace add variable x array traceArray2 set ::info {} set x(a) 1 unset x array set x {a 1} set ::info } {} test trace-5.4 {array traces properly listed in trace information} { catch {unset x} trace add variable x array traceArray2 set result [trace info variable x] set result } [list [list array traceArray2]] test trace-5.5 {array traces properly listed in trace information} { catch {unset x} trace variable x a traceArray2 set result [trace vinfo x] set result } [list [list a traceArray2]] test trace-5.6 {array traces don't fire on scalar variables} { catch {unset x} set x foo trace add variable x array traceArray2 set ::info {} catch {array set x {a 1}} set ::info } {} test trace-5.7 {array traces fire for undefined variables} { catch {unset x} trace add variable x array traceArray2 set ::info {} array set x {a 1} set ::info } {x {} array} test trace-5.8 {array traces fire for undefined variables} { catch {unset x} trace add variable x array {set x(foo) 1 ;#} set res "names: [array names x]" } {names: foo} # Trace multiple trace types at once. test trace-6.1 {multiple ops traced at once} { catch {unset x} set info {} trace add variable x {read write unset} traceProc catch {set x} set x 22 set x set x 33 unset x set info } {x {} read x {} write x {} read x {} write x {} unset} test trace-6.2 {multiple ops traced on array element} { catch {unset x} set info {} trace add variable x(0) {read write unset} traceProc catch {set x(0)} set x(0) 22 set x(0) set x(0) 33 unset x(0) unset x set info } {x 0 read x 0 write x 0 read x 0 write x 0 unset} test trace-6.3 {multiple ops traced on whole array} { catch {unset x} set info {} trace add variable x {read write unset} traceProc catch {set x(0)} set x(0) 22 set x(0) set x(0) 33 unset x(0) unset x set info } {x 0 write x 0 read x 0 write x 0 unset x {} unset} # Check order of invocation of traces test trace-7.1 {order of invocation of traces} { catch {unset x} set info {} trace add variable x read "traceTag 1" trace add variable x read "traceTag 2" trace add variable x read "traceTag 3" catch {set x} set x 22 set x set info } {3 2 1 3 2 1} test trace-7.2 {order of invocation of traces} { catch {unset x} set x(0) 44 set info {} trace add variable x(0) read "traceTag 1" trace add variable x(0) read "traceTag 2" trace add variable x(0) read "traceTag 3" set x(0) set info } {3 2 1} test trace-7.3 {order of invocation of traces} { catch {unset x} set x(0) 44 set info {} trace add variable x(0) read "traceTag 1" trace add variable x read "traceTag A1" trace add variable x(0) read "traceTag 2" trace add variable x read "traceTag A2" trace add variable x(0) read "traceTag 3" trace add variable x read "traceTag A3" set x(0) set info } {A3 A2 A1 3 2 1} # Check effects of errors in trace procedures test trace-8.1 {error returns from traces} { catch {unset x} set x 123 set info {} trace add variable x read "traceTag 1" trace add variable x read traceError list [catch {set x} msg] $msg $info } {1 {can't read "x": trace returned error} {}} test trace-8.2 {error returns from traces} { catch {unset x} set x 123 set info {} trace add variable x write "traceTag 1" trace add variable x write traceError list [catch {set x 44} msg] $msg $info } {1 {can't set "x": trace returned error} {}} test trace-8.3 {error returns from traces} { catch {unset x} set x 123 set info {} trace add variable x write traceError list [catch {append x 44} msg] $msg $info } {1 {can't set "x": trace returned error} {}} test trace-8.4 {error returns from traces} { catch {unset x} set x 123 set info {} trace add variable x unset "traceTag 1" trace add variable x unset traceError list [catch {unset x} msg] $msg $info } {0 {} 1} test trace-8.5 {error returns from traces} { catch {unset x} set x(0) 123 set info {} trace add variable x(0) read "traceTag 1" trace add variable x read "traceTag 2" trace add variable x read traceError trace add variable x read "traceTag 3" list [catch {set x(0)} msg] $msg $info } {1 {can't read "x(0)": trace returned error} 3} test trace-8.6 {error returns from traces} { catch {unset x} set x 123 trace add variable x unset traceError list [catch {unset x} msg] $msg } {0 {}} test trace-8.7 {error returns from traces} { # This test just makes sure that the memory for the error message # gets deallocated correctly when the trace is invoked again or # when the trace is deleted. catch {unset x} set x 123 trace add variable x read traceError catch {set x} catch {set x} trace remove variable x read traceError } {} test trace-8.8 {error returns from traces} { # Yet more elaborate memory corruption testing that checks nothing # bad happens when the trace deletes itself and installs something # new. Alas, there is no neat way to guarantee that this test will # fail if there is a problem, but that's life and with the new code # it should *never* fail. # # Adapted from Bug #219393 reported by Don Porter. catch {rename ::foo {}} proc foo {old args} { trace remove variable ::x write [list foo $old] trace add variable ::x write [list foo $::x] error "foo" } catch {unset ::x ::y} set x junk trace add variable ::x write [list foo $x] for {set y 0} {$y<100} {incr y} { catch {set x junk} } unset x } {} # Check to see that variables are expunged before trace # procedures are invoked, so trace procedure can even manipulate # a new copy of the variables. test trace-9.1 {be sure variable is unset before trace is called} { catch {unset x} set x 33 set info {} trace add variable x unset {traceCheck {uplevel set x}} unset x set info } {1 {can't read "x": no such variable}} test trace-9.2 {be sure variable is unset before trace is called} { catch {unset x} set x 33 set info {} trace add variable x unset {traceCheck {uplevel set x 22}} unset x concat $info [list [catch {set x} msg] $msg] } {0 22 0 22} test trace-9.3 {be sure traces are cleared before unset trace called} { catch {unset x} set x 33 set info {} trace add variable x unset {traceCheck {uplevel trace info variable x}} unset x set info } {0 {}} test trace-9.4 {set new trace during unset trace} { catch {unset x} set x 33 set info {} trace add variable x unset {traceCheck {global x; trace add variable x unset traceProc}} unset x concat $info [trace info variable x] } {0 {} {unset traceProc}} test trace-10.1 {make sure array elements are unset before traces are called} { catch {unset x} set x(0) 33 set info {} trace add variable x(0) unset {traceCheck {uplevel set x(0)}} unset x(0) set info } {1 {can't read "x(0)": no such element in array}} test trace-10.2 {make sure array elements are unset before traces are called} { catch {unset x} set x(0) 33 set info {} trace add variable x(0) unset {traceCheck {uplevel set x(0) zzz}} unset x(0) concat $info [list [catch {set x(0)} msg] $msg] } {0 zzz 0 zzz} test trace-10.3 {array elements are unset before traces are called} { catch {unset x} set x(0) 33 set info {} trace add variable x(0) unset {traceCheck {global x; trace info variable x(0)}} unset x(0) set info } {0 {}} test trace-10.4 {set new array element trace during unset trace} { catch {unset x} set x(0) 33 set info {} trace add variable x(0) unset {traceCheck {uplevel {trace add variable x(0) read {}}}} catch {unset x(0)} concat $info [trace info variable x(0)] } {0 {} {read {}}} test trace-11.1 {make sure arrays are unset before traces are called} { catch {unset x} set x(0) 33 set info {} trace add variable x unset {traceCheck {uplevel set x(0)}} unset x set info } {1 {can't read "x(0)": no such variable}} test trace-11.2 {make sure arrays are unset before traces are called} { catch {unset x} set x(y) 33 set info {} trace add variable x unset {traceCheck {uplevel set x(y) 22}} unset x concat $info [list [catch {set x(y)} msg] $msg] } {0 22 0 22} test trace-11.3 {make sure arrays are unset before traces are called} { catch {unset x} set x(y) 33 set info {} trace add variable x unset {traceCheck {uplevel array exists x}} unset x set info } {0 0} test trace-11.4 {make sure arrays are unset before traces are called} { catch {unset x} set x(y) 33 set info {} set cmd {traceCheck {uplevel {trace info variable x}}} trace add variable x unset $cmd unset x set info } {0 {}} test trace-11.5 {set new array trace during unset trace} { catch {unset x} set x(y) 33 set info {} trace add variable x unset {traceCheck {global x; trace add variable x read {}}} unset x concat $info [trace info variable x] } {0 {} {read {}}} test trace-11.6 {create scalar during array unset trace} { catch {unset x} set x(y) 33 set info {} trace add variable x unset {traceCheck {global x; set x 44}} unset x concat $info [list [catch {set x} msg] $msg] } {0 44 0 44} # Check special conditions (e.g. errors) in Tcl_TraceVar2. test trace-12.1 {creating array when setting variable traces} { catch {unset x} set info {} trace add variable x(0) write traceProc list [catch {set x 22} msg] $msg } {1 {can't set "x": variable is array}} test trace-12.2 {creating array when setting variable traces} { catch {unset x} set info {} trace add variable x(0) write traceProc list [catch {set x(0)} msg] $msg } {1 {can't read "x(0)": no such element in array}} test trace-12.3 {creating array when setting variable traces} { catch {unset x} set info {} trace add variable x(0) write traceProc set x(0) 22 set info } {x 0 write} test trace-12.4 {creating variable when setting variable traces} { catch {unset x} set info {} trace add variable x write traceProc list [catch {set x} msg] $msg } {1 {can't read "x": no such variable}} test trace-12.5 {creating variable when setting variable traces} { catch {unset x} set info {} trace add variable x write traceProc set x 22 set info } {x {} write} test trace-12.6 {creating variable when setting variable traces} { catch {unset x} set info {} trace add variable x write traceProc set x(0) 22 set info } {x 0 write} test trace-12.7 {create array element during read trace} { catch {unset x} set x(2) zzz trace add variable x read {traceCrtElement xyzzy} list [catch {set x(3)} msg] $msg } {0 xyzzy} test trace-12.8 {errors when setting variable traces} { catch {unset x} set x 44 list [catch {trace add variable x(0) write traceProc} msg] $msg } {1 {can't trace "x(0)": variable isn't array}} # Check trace deletion test trace-13.1 {delete one trace from another} { proc delTraces {args} { global x trace remove variable x read {traceTag 2} trace remove variable x read {traceTag 3} trace remove variable x read {traceTag 4} } catch {unset x} set x 44 set info {} trace add variable x read {traceTag 1} trace add variable x read {traceTag 2} trace add variable x read {traceTag 3} trace add variable x read {traceTag 4} trace add variable x read delTraces trace add variable x read {traceTag 5} set x set info } {5 1} test trace-13.2 {leak when unsetting traced variable} \ -constraints memory -body { set end [getbytes] proc f args {} for {set i 0} {$i < 5} {incr i} { trace add variable bepa write f set bepa a unset bepa set tmp $end set end [getbytes] } expr {$end - $tmp} } -cleanup { unset -nocomplain end i tmp } -result 0 test trace-13.3 {leak when removing traces} \ -constraints memory -body { set end [getbytes] proc f args {} for {set i 0} {$i < 5} {incr i} { trace add variable bepa write f set bepa a trace remove variable bepa write f set tmp $end set end [getbytes] } expr {$end - $tmp} } -cleanup { unset -nocomplain end i tmp } -result 0 test trace-13.4 {leaks in error returns from traces} \ -constraints memory -body { set end [getbytes] for {set i 0} {$i < 5} {incr i} { set apa {a 1 b 2} set bepa [lrange $apa 0 end] trace add variable bepa write {error hej} catch {set bepa a} unset bepa set tmp $end set end [getbytes] } expr {$end - $tmp} } -cleanup { unset -nocomplain end i tmp } -result 0 # Check operation and syntax of "trace" command. # Syntax for adding/removing variable and command traces is basically the # same: # trace add variable name opList command # trace remove variable name opList command # # The following loops just get all the common "wrong # args" tests done. set i 0 set start "wrong # args:" foreach type {variable command} { foreach op {add remove} { test trace-14.0.[incr i] "trace command, wrong # args errors" { list [catch {trace $op $type} msg] $msg } [list 1 "$start should be \"trace $op $type name opList command\""] test trace-14.0.[incr i] "trace command wrong # args errors" { list [catch {trace $op $type foo} msg] $msg } [list 1 "$start should be \"trace $op $type name opList command\""] test trace-14.0.[incr i] "trace command, wrong # args errors" { list [catch {trace $op $type foo bar} msg] $msg } [list 1 "$start should be \"trace $op $type name opList command\""] test trace-14.0.[incr i] "trace command, wrong # args errors" { list [catch {trace $op $type foo bar baz boo} msg] $msg } [list 1 "$start should be \"trace $op $type name opList command\""] } test trace-14.0.[incr i] "trace command, wrong # args errors" { list [catch {trace info $type foo bar} msg] $msg } [list 1 "$start should be \"trace info $type name\""] test trace-14.0.[incr i] "trace command, wrong # args errors" { list [catch {trace info $type} msg] $msg } [list 1 "$start should be \"trace info $type name\""] } test trace-14.1 "trace command, wrong # args errors" { list [catch {trace} msg] $msg } [list 1 "wrong # args: should be \"trace option ?arg arg ...?\""] test trace-14.2 "trace command, wrong # args errors" { list [catch {trace add} msg] $msg } [list 1 "wrong # args: should be \"trace add type ?arg arg ...?\""] test trace-14.3 "trace command, wrong # args errors" { list [catch {trace remove} msg] $msg } [list 1 "wrong # args: should be \"trace remove type ?arg arg ...?\""] test trace-14.4 "trace command, wrong # args errors" { list [catch {trace info} msg] $msg } [list 1 "wrong # args: should be \"trace info type ?arg arg ...?\""] test trace-14.5 {trace command, invalid option} { list [catch {trace gorp} msg] $msg } [list 1 "bad option \"gorp\": must be add, info, remove, variable, vdelete, or vinfo"] # Again, [trace ... command] and [trace ... variable] share syntax and # error message styles for their opList options; these loops test those # error messages. set i 0 set errs [list "array, read, unset, or write" "delete or rename" "enter, leave, enterstep, or leavestep"] set abbvs [list {a r u w} {d r} {}] proc x {} {} foreach type {variable command execution} err $errs abbvlist $abbvs { foreach op {add remove} { test trace-14.6.[incr i] "trace $op $type errors" { list [catch {trace $op $type x {y z w} a} msg] $msg } [list 1 "bad operation \"y\": must be $err"] foreach abbv $abbvlist { test trace-14.6.[incr i] "trace $op $type rejects abbreviations" { list [catch {trace $op $type x $abbv a} msg] $msg } [list 1 "bad operation \"$abbv\": must be $err"] } test trace-14.6.[incr i] "trace $op $type rejects null opList" { list [catch {trace $op $type x {} a} msg] $msg } [list 1 "bad operation list \"\": must be one or more of $err"] } } rename x {} test trace-14.7 {trace command, "trace variable" errors} { list [catch {trace variable} msg] $msg } [list 1 "wrong # args: should be \"trace variable name ops command\""] test trace-14.8 {trace command, "trace variable" errors} { list [catch {trace variable x} msg] $msg } [list 1 "wrong # args: should be \"trace variable name ops command\""] test trace-14.9 {trace command, "trace variable" errors} { list [catch {trace variable x y} msg] $msg } [list 1 "wrong # args: should be \"trace variable name ops command\""] test trace-14.10 {trace command, "trace variable" errors} { list [catch {trace variable x y z w} msg] $msg } [list 1 "wrong # args: should be \"trace variable name ops command\""] test trace-14.11 {trace command, "trace variable" errors} { list [catch {trace variable x y z} msg] $msg } [list 1 "bad operations \"y\": should be one or more of rwua"] test trace-14.12 {trace command ("remove variable" option)} { catch {unset x} set info {} trace add variable x write traceProc trace remove variable x write traceProc } {} test trace-14.13 {trace command ("remove variable" option)} { catch {unset x} set info {} trace add variable x write traceProc trace remove variable x write traceProc set x 12345 set info } {} test trace-14.14 {trace command ("remove variable" option)} { catch {unset x} set info {} trace add variable x write {traceTag 1} trace add variable x write traceProc trace add variable x write {traceTag 2} set x yy trace remove variable x write traceProc set x 12345 trace remove variable x write {traceTag 1} set x foo trace remove variable x write {traceTag 2} set x gorp set info } {2 x {} write 1 2 1 2} test trace-14.15 {trace command ("remove variable" option)} { catch {unset x} set info {} trace add variable x write {traceTag 1} trace remove variable x write non_existent set x 12345 set info } {1} test trace-14.16 {trace command ("info variable" option)} { catch {unset x} trace add variable x write {traceTag 1} trace add variable x write traceProc trace add variable x write {traceTag 2} trace info variable x } {{write {traceTag 2}} {write traceProc} {write {traceTag 1}}} test trace-14.17 {trace command ("info variable" option)} { catch {unset x} trace info variable x } {} test trace-14.18 {trace command ("info variable" option)} { catch {unset x} trace info variable x(0) } {} test trace-14.19 {trace command ("info variable" option)} { catch {unset x} set x 44 trace info variable x(0) } {} test trace-14.20 {trace command ("info variable" option)} { catch {unset x} set x 44 trace add variable x write {traceTag 1} proc check {} {global x; trace info variable x} check } {{write {traceTag 1}}} # Check fancy trace commands (long ones, weird arguments, etc.) test trace-15.1 {long trace command} { catch {unset x} set info {} trace add variable x write {traceTag {This is a very very long argument. It's \ designed to test out the facilities of TraceVarProc for dealing \ with such long arguments by malloc-ing space. One possibility \ is that space doesn't get freed properly. If this happens, then \ invoking this test over and over again will eventually leak memory.}} set x 44 set info } {This is a very very long argument. It's \ designed to test out the facilities of TraceVarProc for dealing \ with such long arguments by malloc-ing space. One possibility \ is that space doesn't get freed properly. If this happens, then \ invoking this test over and over again will eventually leak memory.} test trace-15.2 {long trace command result to ignore} { proc longResult {args} {return "quite a bit of text, designed to generate a core leak if this command file is invoked over and over again and memory isn't being recycled correctly"} catch {unset x} trace add variable x write longResult set x 44 set x 5 set x abcde } abcde test trace-15.3 {special list-handling in trace commands} { catch {unset "x y z"} set "x y z(a\n\{)" 44 set info {} trace add variable "x y z(a\n\{)" write traceProc set "x y z(a\n\{)" 33 set info } "{x y z} a\\n\\\{ write" # Check for proper handling of unsets during traces. proc traceUnset {unsetName args} { global info upvar $unsetName x lappend info [catch {unset x} msg] $msg [catch {set x} msg] $msg } proc traceReset {unsetName resetName args} { global info upvar $unsetName x $resetName y lappend info [catch {unset x} msg] $msg [catch {set y xyzzy} msg] $msg } proc traceReset2 {unsetName resetName args} { global info lappend info [catch {uplevel unset $unsetName} msg] $msg \ [catch {uplevel set $resetName xyzzy} msg] $msg } proc traceAppend {string name1 name2 op} { global info lappend info $string } test trace-16.1 {unsets during read traces} { catch {unset y} set y 1234 set info {} trace add variable y read {traceUnset y} trace add variable y unset {traceAppend unset} lappend info [catch {set y} msg] $msg } {unset 0 {} 1 {can't read "x": no such variable} 1 {can't read "y": no such variable}} test trace-16.2 {unsets during read traces} { catch {unset y} set y(0) 1234 set info {} trace add variable y(0) read {traceUnset y(0)} lappend info [catch {set y(0)} msg] $msg } {0 {} 1 {can't read "x": no such variable} 1 {can't read "y(0)": no such element in array}} test trace-16.3 {unsets during read traces} { catch {unset y} set y(0) 1234 set info {} trace add variable y(0) read {traceUnset y} lappend info [catch {set y(0)} msg] $msg } {0 {} 1 {can't read "x": no such variable} 1 {can't read "y(0)": no such variable}} test trace-16.4 {unsets during read traces} { catch {unset y} set y 1234 set info {} trace add variable y read {traceReset y y} lappend info [catch {set y} msg] $msg } {0 {} 0 xyzzy 0 xyzzy} test trace-16.5 {unsets during read traces} { catch {unset y} set y(0) 1234 set info {} trace add variable y(0) read {traceReset y(0) y(0)} lappend info [catch {set y(0)} msg] $msg } {0 {} 0 xyzzy 0 xyzzy} test trace-16.6 {unsets during read traces} { catch {unset y} set y(0) 1234 set info {} trace add variable y(0) read {traceReset y y(0)} lappend info [catch {set y(0)} msg] $msg [catch {set y(0)} msg] $msg } {0 {} 1 {can't set "y": upvar refers to element in deleted array} 1 {can't read "y(0)": no such variable} 1 {can't read "y(0)": no such variable}} test trace-16.7 {unsets during read traces} { catch {unset y} set y(0) 1234 set info {} trace add variable y(0) read {traceReset2 y y(0)} lappend info [catch {set y(0)} msg] $msg [catch {set y(0)} msg] $msg } {0 {} 0 xyzzy 1 {can't read "y(0)": no such element in array} 0 xyzzy} test trace-16.8 {unsets during write traces} { catch {unset y} set y 1234 set info {} trace add variable y write {traceUnset y} trace add variable y unset {traceAppend unset} lappend info [catch {set y xxx} msg] $msg } {unset 0 {} 1 {can't read "x": no such variable} 0 {}} test trace-16.9 {unsets during write traces} { catch {unset y} set y(0) 1234 set info {} trace add variable y(0) write {traceUnset y(0)} lappend info [catch {set y(0) xxx} msg] $msg } {0 {} 1 {can't read "x": no such variable} 0 {}} test trace-16.10 {unsets during write traces} { catch {unset y} set y(0) 1234 set info {} trace add variable y(0) write {traceUnset y} lappend info [catch {set y(0) xxx} msg] $msg } {0 {} 1 {can't read "x": no such variable} 0 {}} test trace-16.11 {unsets during write traces} { catch {unset y} set y 1234 set info {} trace add variable y write {traceReset y y} lappend info [catch {set y xxx} msg] $msg } {0 {} 0 xyzzy 0 xyzzy} test trace-16.12 {unsets during write traces} { catch {unset y} set y(0) 1234 set info {} trace add variable y(0) write {traceReset y(0) y(0)} lappend info [catch {set y(0) xxx} msg] $msg } {0 {} 0 xyzzy 0 xyzzy} test trace-16.13 {unsets during write traces} { catch {unset y} set y(0) 1234 set info {} trace add variable y(0) write {traceReset y y(0)} lappend info [catch {set y(0) xxx} msg] $msg [catch {set y(0)} msg] $msg } {0 {} 1 {can't set "y": upvar refers to element in deleted array} 0 {} 1 {can't read "y(0)": no such variable}} test trace-16.14 {unsets during write traces} { catch {unset y} set y(0) 1234 set info {} trace add variable y(0) write {traceReset2 y y(0)} lappend info [catch {set y(0) xxx} msg] $msg [catch {set y(0)} msg] $msg } {0 {} 0 xyzzy 0 {} 0 xyzzy} test trace-16.15 {unsets during unset traces} { catch {unset y} set y 1234 set info {} trace add variable y unset {traceUnset y} lappend info [catch {unset y} msg] $msg [catch {set y} msg] $msg } {1 {can't unset "x": no such variable} 1 {can't read "x": no such variable} 0 {} 1 {can't read "y": no such variable}} test trace-16.16 {unsets during unset traces} { catch {unset y} set y(0) 1234 set info {} trace add variable y(0) unset {traceUnset y(0)} lappend info [catch {unset y(0)} msg] $msg [catch {set y(0)} msg] $msg } {1 {can't unset "x": no such variable} 1 {can't read "x": no such variable} 0 {} 1 {can't read "y(0)": no such element in array}} test trace-16.17 {unsets during unset traces} { catch {unset y} set y(0) 1234 set info {} trace add variable y(0) unset {traceUnset y} lappend info [catch {unset y(0)} msg] $msg [catch {set y(0)} msg] $msg } {0 {} 1 {can't read "x": no such variable} 0 {} 1 {can't read "y(0)": no such variable}} test trace-16.18 {unsets during unset traces} { catch {unset y} set y 1234 set info {} trace add variable y unset {traceReset2 y y} lappend info [catch {unset y} msg] $msg [catch {set y} msg] $msg } {1 {can't unset "y": no such variable} 0 xyzzy 0 {} 0 xyzzy} test trace-16.19 {unsets during unset traces} { catch {unset y} set y(0) 1234 set info {} trace add variable y(0) unset {traceReset2 y(0) y(0)} lappend info [catch {unset y(0)} msg] $msg [catch {set y(0)} msg] $msg } {1 {can't unset "y(0)": no such element in array} 0 xyzzy 0 {} 0 xyzzy} test trace-16.20 {unsets during unset traces} { catch {unset y} set y(0) 1234 set info {} trace add variable y(0) unset {traceReset2 y y(0)} lappend info [catch {unset y(0)} msg] $msg [catch {set y(0)} msg] $msg } {0 {} 0 xyzzy 0 {} 0 xyzzy} test trace-16.21 {unsets cancelling traces} { catch {unset y} set y 1234 set info {} trace add variable y read {traceAppend first} trace add variable y read {traceUnset y} trace add variable y read {traceAppend third} trace add variable y unset {traceAppend unset} lappend info [catch {set y} msg] $msg } {third unset 0 {} 1 {can't read "x": no such variable} 1 {can't read "y": no such variable}} test trace-16.22 {unsets cancelling traces} { catch {unset y} set y(0) 1234 set info {} trace add variable y(0) read {traceAppend first} trace add variable y(0) read {traceUnset y} trace add variable y(0) read {traceAppend third} trace add variable y(0) unset {traceAppend unset} lappend info [catch {set y(0)} msg] $msg } {third unset 0 {} 1 {can't read "x": no such variable} 1 {can't read "y(0)": no such variable}} # Check various non-interference between traces and other things. test trace-17.1 {trace doesn't prevent unset errors} { catch {unset x} set info {} trace add variable x unset {traceProc} list [catch {unset x} msg] $msg $info } {1 {can't unset "x": no such variable} {x {} unset}} test trace-17.2 {traced variables must survive procedure exits} { catch {unset x} proc p1 {} {global x; trace add variable x write traceProc} p1 trace info variable x } {{write traceProc}} test trace-17.3 {traced variables must survive procedure exits} { catch {unset x} set info {} proc p1 {} {global x; trace add variable x write traceProc} p1 set x 44 set info } {x {} write} # Be sure that procedure frames are released before unset traces # are invoked. test trace-18.1 {unset traces on procedure returns} { proc p1 {x y} {set a 44; p2 14} proc p2 {z} {trace add variable z unset {traceCheck {lsort [uplevel {info vars}]}}} set info {} p1 foo bar set info } {0 {a x y}} test trace-18.2 {namespace delete / trace vdelete combo} { namespace eval ::foo { variable x 123 } proc p1 args { trace vdelete ::foo::x u p1 } trace variable ::foo::x u p1 namespace delete ::foo info exists ::foo::x } 0 test trace-18.3 {namespace delete / trace vdelete combo, Bug \#1337229} { namespace eval ::ns {} trace add variable ::ns::var unset {unset ::ns::var ;#} namespace delete ::ns } {} test trace-18.4 {namespace delete / trace vdelete combo, Bug \#1338280} { namespace eval ::ref {} set ::ref::var1 AAA trace add variable ::ref::var1 unset doTrace set ::ref::var2 BBB trace add variable ::ref::var2 {unset} doTrace proc doTrace {vtraced vidx op} { global info append info [catch {set ::$vtraced}][llength [info vars ::ref::*]] } set info {} namespace delete ::ref rename doTrace {} set info } 1110 # Delete arrays when done, so they can be re-used as scalars # elsewhere. catch {unset x} catch {unset y} test trace-19.0.1 {trace add command (command existence)} { # Just in case! catch {rename nosuchname ""} list [catch {trace add command nosuchname rename traceCommand} msg] $msg } {1 {unknown command "nosuchname"}} test trace-19.0.2 {trace add command (command existence in ns)} { list [catch {trace add command nosuchns::nosuchname rename traceCommand} msg] $msg } {1 {unknown command "nosuchns::nosuchname"}} test trace-19.1 {trace add command (rename option)} { proc foo {} {} catch {rename bar {}} trace add command foo rename traceCommand rename foo bar set info } {::foo ::bar rename} test trace-19.2 {traces stick with renamed commands} { proc foo {} {} catch {rename bar {}} trace add command foo rename traceCommand rename foo bar rename bar foo set info } {::bar ::foo rename} test trace-19.2.1 {trace add command rename trace exists} { proc foo {} {} trace add command foo rename traceCommand trace info command foo } {{rename traceCommand}} test trace-19.3 {command rename traces don't fire on command deletion} { proc foo {} {} set info {} trace add command foo rename traceCommand rename foo {} set info } {} test trace-19.4 {trace add command rename doesn't trace recreated commands} { proc foo {} {} catch {rename bar {}} trace add command foo rename traceCommand proc foo {} {} rename foo bar set info } {} test trace-19.5 {trace add command deleted removes traces} { proc foo {} {} trace add command foo rename traceCommand proc foo {} {} trace info command foo } {} namespace eval tc {} proc tc::tcfoo {} {} test trace-19.6 {trace add command rename in namespace} { trace add command tc::tcfoo rename traceCommand rename tc::tcfoo tc::tcbar set info } {::tc::tcfoo ::tc::tcbar rename} test trace-19.7 {trace add command rename in namespace back again} { rename tc::tcbar tc::tcfoo set info } {::tc::tcbar ::tc::tcfoo rename} test trace-19.8 {trace add command rename in namespace to out of namespace} { rename tc::tcfoo tcbar set info } {::tc::tcfoo ::tcbar rename} test trace-19.9 {trace add command rename back into namespace} { rename tcbar tc::tcfoo set info } {::tcbar ::tc::tcfoo rename} test trace-19.10 {trace add command failed rename doesn't trigger trace} { set info {} proc foo {} {} proc bar {} {} trace add command foo {rename delete} traceCommand catch {rename foo bar} set info } {} catch {rename foo {}} catch {rename bar {}} test trace-19.11 {trace add command qualifies when renamed in namespace} { set info {} namespace eval tc {rename tcfoo tcbar} set info } {::tc::tcfoo ::tc::tcbar rename} # Make sure it exists again proc foo {} {} test trace-20.1 {trace add command (delete option)} { trace add command foo delete traceCommand rename foo "" set info } {::foo {} delete} test trace-20.2 {trace add command delete doesn't trace recreated commands} { set info {} proc foo {} {} rename foo "" set info } {} test trace-20.2.1 {trace add command delete trace info} { proc foo {} {} trace add command foo delete traceCommand trace info command foo } {{delete traceCommand}} test trace-20.3 {trace add command implicit delete} { proc foo {} {} trace add command foo delete traceCommand proc foo {} {} set info } {::foo {} delete} test trace-20.3.1 {trace add command delete trace info} { proc foo {} {} trace info command foo } {} test trace-20.4 {trace add command rename followed by delete} { set infotemp {} proc foo {} {} trace add command foo {rename delete} traceCommand rename foo bar lappend infotemp $info rename bar {} lappend infotemp $info set info $infotemp unset infotemp set info } {{::foo ::bar rename} {::bar {} delete}} catch {rename foo {}} catch {rename bar {}} test trace-20.5 {trace add command rename and delete} { set infotemp {} set info {} proc foo {} {} trace add command foo {rename delete} traceCommand rename foo bar lappend infotemp $info rename bar {} lappend infotemp $info set info $infotemp unset infotemp set info } {{::foo ::bar rename} {::bar {} delete}} test trace-20.6 {trace add command rename and delete in subinterp} { set tc [interp create] foreach p {traceCommand} { $tc eval [list proc $p [info args $p] [info body $p]] } $tc eval [list set infotemp {}] $tc eval [list set info {}] $tc eval [list proc foo {} {}] $tc eval [list trace add command foo {rename delete} traceCommand] $tc eval [list rename foo bar] $tc eval {lappend infotemp $info} $tc eval [list rename bar {}] $tc eval {lappend infotemp $info} $tc eval {set info $infotemp} $tc eval [list unset infotemp] set info [$tc eval [list set info]] interp delete $tc set info } {{::foo ::bar rename} {::bar {} delete}} # I'd like it if this test could give 'foo {} d' as a result, # but interp deletion means there is no interp to evaluate # the trace in. test trace-20.7 {trace add command delete in subinterp while being deleted} { set info {} set tc [interp create] interp alias $tc traceCommand {} traceCommand $tc eval [list proc foo {} {}] $tc eval [list trace add command foo {rename delete} traceCommand] interp delete $tc set info } {} proc traceDelete {cmd old new op} { eval trace remove command $cmd [lindex [trace info command $cmd] 0] global info set info [list $old $new $op] } proc traceCmdrename {cmd old new op} { rename $old someothername } proc traceCmddelete {cmd old new op} { rename $old "" } test trace-20.8 {trace delete while trace is active} { set info {} proc foo {} {} catch {rename bar {}} trace add command foo {rename delete} [list traceDelete foo] rename foo bar list [set info] [trace info command bar] } {{::foo ::bar rename} {}} test trace-20.9 {rename trace deletes command} { set info {} proc foo {} {} catch {rename bar {}} catch {rename someothername {}} trace add command foo rename [list traceCmddelete foo] rename foo bar list [info commands foo] [info commands bar] [info commands someothername] } {{} {} {}} test trace-20.10 {rename trace renames command} { set info {} proc foo {} {} catch {rename bar {}} catch {rename someothername {}} trace add command foo rename [list traceCmdrename foo] rename foo bar set info [list [info commands foo] [info commands bar] [info commands someothername]] rename someothername {} set info } {{} {} someothername} test trace-20.11 {delete trace deletes command} { set info {} proc foo {} {} catch {rename bar {}} catch {rename someothername {}} trace add command foo delete [list traceCmddelete foo] rename foo {} list [info commands foo] [info commands bar] [info commands someothername] } {{} {} {}} test trace-20.12 {delete trace renames command} { set info {} proc foo {} {} catch {rename bar {}} catch {rename someothername {}} trace add command foo delete [list traceCmdrename foo] rename foo bar rename bar {} # None of these should exist. list [info commands foo] [info commands bar] [info commands someothername] } {{} {} {}} test trace-20.13 {rename trace discards result [Bug 1355342]} { proc foo {} {} trace add command foo rename {set w Aha!;#} list [rename foo bar] [rename bar {}] } {{} {}} test trace-20.14 {rename trace discards error result [Bug 1355342]} { proc foo {} {} trace add command foo rename {error} list [rename foo bar] [rename bar {}] } {{} {}} test trace-20.15 {delete trace discards result [Bug 1355342]} { proc foo {} {} trace add command foo delete {set w Aha!;#} rename foo {} } {} test trace-20.16 {delete trace discards error result [Bug 1355342]} { proc foo {} {} trace add command foo delete {error} rename foo {} } {} proc foo {b} { set a $b } # Delete arrays when done, so they can be re-used as scalars # elsewhere. catch {unset x} catch {unset y} # Delete procedures when done, so we don't clash with other tests # (e.g. foobar will clash with 'unknown' tests). catch {rename foobar {}} catch {rename foo {}} catch {rename bar {}} proc foo {a} { set b $a } proc traceExecute {args} { global info lappend info $args } test trace-21.1 {trace execution: enter} { set info {} trace add execution foo enter [list traceExecute foo] foo 1 trace remove execution foo enter [list traceExecute foo] set info } {{foo {foo 1} enter}} test trace-21.2 {trace exeuction: leave} { set info {} trace add execution foo leave [list traceExecute foo] foo 2 trace remove execution foo leave [list traceExecute foo] set info } {{foo {foo 2} 0 2 leave}} test trace-21.3 {trace exeuction: enter, leave} { set info {} trace add execution foo {enter leave} [list traceExecute foo] foo 3 trace remove execution foo {enter leave} [list traceExecute foo] set info } {{foo {foo 3} enter} {foo {foo 3} 0 3 leave}} test trace-21.4 {trace execution: enter, leave, enterstep} { set info {} trace add execution foo {enter leave enterstep} [list traceExecute foo] foo 3 trace remove execution foo {enter leave enterstep} [list traceExecute foo] set info } {{foo {foo 3} enter} {foo {set b 3} enterstep} {foo {foo 3} 0 3 leave}} test trace-21.5 {trace execution: enter, leave, enterstep, leavestep} { set info {} trace add execution foo {enter leave enterstep leavestep} [list traceExecute foo] foo 3 trace remove execution foo {enter leave enterstep leavestep} [list traceExecute foo] set info } {{foo {foo 3} enter} {foo {set b 3} enterstep} {foo {set b 3} 0 3 leavestep} {foo {foo 3} 0 3 leave}} test trace-21.6 {trace execution: enterstep, leavestep} { set info {} trace add execution foo {enterstep leavestep} [list traceExecute foo] foo 3 trace remove execution foo {enterstep leavestep} [list traceExecute foo] set info } {{foo {set b 3} enterstep} {foo {set b 3} 0 3 leavestep}} test trace-21.7 {trace execution: enterstep} { set info {} trace add execution foo {enterstep} [list traceExecute foo] foo 3 trace remove execution foo {enterstep} [list traceExecute foo] set info } {{foo {set b 3} enterstep}} test trace-21.8 {trace execution: leavestep} { set info {} trace add execution foo {leavestep} [list traceExecute foo] foo 3 trace remove execution foo {leavestep} [list traceExecute foo] set info } {{foo {set b 3} 0 3 leavestep}} test trace-21.9 {trace execution: TCL_EVAL_GLOBAL} testevalobjv { trace add execution foo enter soom proc ::soom args {lappend ::info SUCCESS [info level]} set ::info {} namespace eval test_ns_1 { proc soom args {lappend ::info FAIL [info level]} # [testevalobjv 1 ...] ought to produce the same # results as [uplevel #0 ...]. testevalobjv 1 foo x uplevel #0 foo x } namespace delete test_ns_1 trace remove execution foo enter soom set ::info } {SUCCESS 1 SUCCESS 1} test trace-21.10 {trace execution: TCL_EVAL_GLOBAL} testevalobjv { trace add execution foo leave soom proc ::soom args {lappend ::info SUCCESS [info level]} set ::info {} namespace eval test_ns_1 { proc soom args {lappend ::info FAIL [info level]} # [testevalobjv 1 ...] ought to produce the same # results as [uplevel #0 ...]. testevalobjv 1 foo x uplevel #0 foo x } namespace delete test_ns_1 trace remove execution foo leave soom set ::info } {SUCCESS 1 SUCCESS 1} test trace-21.11 {trace execution and alias} -setup { set res {} proc ::x {} {return ::} namespace eval a {} proc ::a::x {} {return ::a} interp alias {} y {} x } -body { lappend res [namespace eval ::a y] trace add execution ::x enter { rename ::x {} proc ::x {} {return ::} #} lappend res [namespace eval ::a y] } -cleanup { namespace delete a rename ::x {} } -result {:: ::} proc set2 args { set {*}$args } test trace-21.12 {bug 2438181} -setup { trace add execution set2 leave {puts one two three #;} } -body { set2 a hello } -returnCodes error -result {wrong # args: should be "puts ?-nonewline? ?channelId? string"} proc factorial {n} { if {$n != 1} { return [expr {$n * [factorial [expr {$n -1 }]]}] } return 1 } test trace-22.1 {recursive(1) trace execution: enter} { set info {} trace add execution factorial {enter} [list traceExecute factorial] factorial 1 trace remove execution factorial {enter} [list traceExecute factorial] set info } {{factorial {factorial 1} enter}} test trace-22.2 {recursive(2) trace execution: enter} { set info {} trace add execution factorial {enter} [list traceExecute factorial] factorial 2 trace remove execution factorial {enter} [list traceExecute factorial] set info } {{factorial {factorial 2} enter} {factorial {factorial 1} enter}} test trace-22.3 {recursive(3) trace execution: enter} { set info {} trace add execution factorial {enter} [list traceExecute factorial] factorial 3 trace remove execution factorial {enter} [list traceExecute factorial] set info } {{factorial {factorial 3} enter} {factorial {factorial 2} enter} {factorial {factorial 1} enter}} test trace-23.1 {recursive(1) trace execution: enter, leave, enterstep, leavestep} { set info {} trace add execution factorial {enter leave enterstep leavestep} [list traceExecute] factorial 1 trace remove execution factorial {enter leave enterstep leavestep} [list traceExecute] join $info "\n" } {{factorial 1} enter {if {$n != 1} { return [expr {$n * [factorial [expr {$n -1 }]]}] }} enterstep {if {$n != 1} { return [expr {$n * [factorial [expr {$n -1 }]]}] }} 0 {} leavestep {return 1} enterstep {return 1} 2 1 leavestep {factorial 1} 0 1 leave} test trace-23.2 {recursive(2) trace execution: enter, leave, enterstep, leavestep} { set info {} trace add execution factorial {enter leave enterstep leavestep} [list traceExecute] factorial 2 trace remove execution factorial {enter leave enterstep leavestep} [list traceExecute] join $info "\n" } {{factorial 2} enter {if {$n != 1} { return [expr {$n * [factorial [expr {$n -1 }]]}] }} enterstep {expr {$n * [factorial [expr {$n -1 }]]}} enterstep {expr {$n -1 }} enterstep {expr {$n -1 }} 0 1 leavestep {factorial 1} enterstep {factorial 1} enter {if {$n != 1} { return [expr {$n * [factorial [expr {$n -1 }]]}] }} enterstep {if {$n != 1} { return [expr {$n * [factorial [expr {$n -1 }]]}] }} 0 {} leavestep {return 1} enterstep {return 1} 2 1 leavestep {factorial 1} 0 1 leave {factorial 1} 0 1 leavestep {expr {$n * [factorial [expr {$n -1 }]]}} 0 2 leavestep {return 2} enterstep {return 2} 2 2 leavestep {if {$n != 1} { return [expr {$n * [factorial [expr {$n -1 }]]}] }} 2 2 leavestep {factorial 2} 0 2 leave} test trace-23.3 {recursive(3) trace execution: enter, leave, enterstep, leavestep} { set info {} trace add execution factorial {enter leave enterstep leavestep} [list traceExecute] factorial 3 trace remove execution factorial {enter leave enterstep leavestep} [list traceExecute] join $info "\n" } {{factorial 3} enter {if {$n != 1} { return [expr {$n * [factorial [expr {$n -1 }]]}] }} enterstep {expr {$n * [factorial [expr {$n -1 }]]}} enterstep {expr {$n -1 }} enterstep {expr {$n -1 }} 0 2 leavestep {factorial 2} enterstep {factorial 2} enter {if {$n != 1} { return [expr {$n * [factorial [expr {$n -1 }]]}] }} enterstep {expr {$n * [factorial [expr {$n -1 }]]}} enterstep {expr {$n -1 }} enterstep {expr {$n -1 }} 0 1 leavestep {factorial 1} enterstep {factorial 1} enter {if {$n != 1} { return [expr {$n * [factorial [expr {$n -1 }]]}] }} enterstep {if {$n != 1} { return [expr {$n * [factorial [expr {$n -1 }]]}] }} 0 {} leavestep {return 1} enterstep {return 1} 2 1 leavestep {factorial 1} 0 1 leave {factorial 1} 0 1 leavestep {expr {$n * [factorial [expr {$n -1 }]]}} 0 2 leavestep {return 2} enterstep {return 2} 2 2 leavestep {if {$n != 1} { return [expr {$n * [factorial [expr {$n -1 }]]}] }} 2 2 leavestep {factorial 2} 0 2 leave {factorial 2} 0 2 leavestep {expr {$n * [factorial [expr {$n -1 }]]}} 0 6 leavestep {return 6} enterstep {return 6} 2 6 leavestep {if {$n != 1} { return [expr {$n * [factorial [expr {$n -1 }]]}] }} 2 6 leavestep {factorial 3} 0 6 leave} proc traceDelete {cmd args} { eval trace remove execution $cmd [lindex [trace info execution $cmd] 0] global info set info $args } test trace-24.1 {delete trace during enter trace} { set info {} trace add execution foo enter [list traceDelete foo] foo 1 list $info [catch {trace info execution foo} res] $res } {{{foo 1} enter} 0 {}} test trace-24.2 {delete trace during leave trace} { set info {} trace add execution foo leave [list traceDelete foo] foo 1 list $info [catch {trace info execution foo} res] $res } {{{foo 1} 0 1 leave} 0 {}} test trace-24.3 {delete trace during enter-leave trace} { set info {} trace add execution foo {enter leave} [list traceDelete foo] foo 1 list $info [catch {trace info execution foo} res] $res } {{{foo 1} enter} 0 {}} test trace-24.4 {delete trace during all exec traces} { set info {} trace add execution foo {enter leave enterstep leavestep} [list traceDelete foo] foo 1 list $info [catch {trace info execution foo} res] $res } {{{foo 1} enter} 0 {}} test trace-24.5 {delete trace during all exec traces except enter} { set info {} trace add execution foo {leave enterstep leavestep} [list traceDelete foo] foo 1 list $info [catch {trace info execution foo} res] $res } {{{set b 1} enterstep} 0 {}} proc traceDelete {cmd args} { rename $cmd {} global info set info $args } proc foo {a} { set b $a } test trace-25.1 {delete command during enter trace} { set info {} trace add execution foo enter [list traceDelete foo] catch {foo 1} err list $err $info [catch {trace info execution foo} res] $res } {{invalid command name "foo"} {{foo 1} enter} 1 {unknown command "foo"}} proc foo {a} { set b $a } test trace-25.2 {delete command during leave trace} { set info {} trace add execution foo leave [list traceDelete foo] foo 1 list $info [catch {trace info execution foo} res] $res } {{{foo 1} 0 1 leave} 1 {unknown command "foo"}} proc foo {a} { set b $a } test trace-25.3 {delete command during enter then leave trace} { set info {} trace add execution foo enter [list traceDelete foo] trace add execution foo leave [list traceDelete foo] catch {foo 1} err list $err $info [catch {trace info execution foo} res] $res } {{invalid command name "foo"} {{foo 1} enter} 1 {unknown command "foo"}} proc foo {a} { set b $a } proc traceExecute2 {args} { global info lappend info $args } # This shows the peculiar consequences of having two traces # at the same time: as well as tracing the procedure you want test trace-25.4 {order dependencies of two enter traces} { set info {} trace add execution foo enter [list traceExecute traceExecute] trace add execution foo enter [list traceExecute2 traceExecute2] catch {foo 1} err trace remove execution foo enter [list traceExecute traceExecute] trace remove execution foo enter [list traceExecute2 traceExecute2] join [list $err [join $info \n] [trace info execution foo]] "\n" } {1 traceExecute2 {foo 1} enter traceExecute {foo 1} enter } test trace-25.5 {order dependencies of two step traces} { set info {} trace add execution foo enterstep [list traceExecute traceExecute] trace add execution foo enterstep [list traceExecute2 traceExecute2] catch {foo 1} err trace remove execution foo enterstep [list traceExecute traceExecute] trace remove execution foo enterstep [list traceExecute2 traceExecute2] join [list $err [join $info \n] [trace info execution foo]] "\n" } {1 traceExecute2 {set b 1} enterstep traceExecute {set b 1} enterstep } # We don't want the result string (5th argument), or the results # will get unmanageable. proc tracePostExecute {args} { global info lappend info [concat [lrange $args 0 2] [lindex $args 4]] } proc tracePostExecute2 {args} { global info lappend info [concat [lrange $args 0 2] [lindex $args 4]] } test trace-25.6 {order dependencies of two leave traces} { set info {} trace add execution foo leave [list tracePostExecute tracePostExecute] trace add execution foo leave [list tracePostExecute2 tracePostExecute2] catch {foo 1} err trace remove execution foo leave [list tracePostExecute tracePostExecute] trace remove execution foo leave [list tracePostExecute2 tracePostExecute2] join [list $err [join $info \n] [trace info execution foo]] "\n" } {1 tracePostExecute {foo 1} 0 leave tracePostExecute2 {foo 1} 0 leave } test trace-25.7 {order dependencies of two leavestep traces} { set info {} trace add execution foo leavestep [list tracePostExecute tracePostExecute] trace add execution foo leavestep [list tracePostExecute2 tracePostExecute2] catch {foo 1} err trace remove execution foo leavestep [list tracePostExecute tracePostExecute] trace remove execution foo leavestep [list tracePostExecute2 tracePostExecute2] join [list $err [join $info \n] [trace info execution foo]] "\n" } {1 tracePostExecute {set b 1} 0 leavestep tracePostExecute2 {set b 1} 0 leavestep } proc foo {a} { set b $a } proc traceDelete {cmd args} { rename $cmd {} global info set info $args } test trace-25.8 {delete command during enter leave and enter/leave-step traces} { set info {} trace add execution foo enter [list traceDelete foo] trace add execution foo leave [list traceDelete foo] trace add execution foo enterstep [list traceDelete foo] trace add execution foo leavestep [list traceDelete foo] catch {foo 1} err list $err $info [catch {trace info execution foo} res] $res } {{invalid command name "foo"} {{foo 1} enter} 1 {unknown command "foo"}} proc foo {a} { set b $a } test trace-25.9 {delete command during enter leave and leavestep traces} { set info {} trace add execution foo enter [list traceDelete foo] trace add execution foo leave [list traceDelete foo] trace add execution foo leavestep [list traceDelete foo] catch {foo 1} err list $err $info [catch {trace info execution foo} res] $res } {{invalid command name "foo"} {{foo 1} enter} 1 {unknown command "foo"}} proc foo {a} { set b $a } test trace-25.10 {delete command during leave and leavestep traces} { set info {} trace add execution foo leave [list traceDelete foo] trace add execution foo leavestep [list traceDelete foo] catch {foo 1} err list $err $info [catch {trace info execution foo} res] $res } {1 {{set b 1} 0 1 leavestep} 1 {unknown command "foo"}} proc foo {a} { set b $a } test trace-25.11 {delete command during enter and enterstep traces} { set info {} trace add execution foo enter [list traceDelete foo] trace add execution foo enterstep [list traceDelete foo] catch {foo 1} err list $err $info [catch {trace info execution foo} res] $res } {{invalid command name "foo"} {{foo 1} enter} 1 {unknown command "foo"}} test trace-26.1 {trace targetCmd when invoked through an alias} { proc foo {args} { set b $args } set info {} trace add execution foo enter [list traceExecute foo] interp alias {} bar {} foo 1 bar 2 trace remove execution foo enter [list traceExecute foo] set info } {{foo {foo 1 2} enter}} test trace-26.2 {trace targetCmd when invoked through an alias} { proc foo {args} { set b $args } set info {} trace add execution foo enter [list traceExecute foo] interp create child interp alias child bar {} foo 1 child eval bar 2 interp delete child trace remove execution foo enter [list traceExecute foo] set info } {{foo {foo 1 2} enter}} test trace-27.1 {memory leak in rename trace (604609)} { catch {rename bar {}} proc foo {} {error foo} trace add command foo rename {rename foo "" ;#} rename foo bar info commands foo } {} test trace-27.2 {command trace remove nonsense} { list [catch {trace remove command thisdoesntexist \ {delete rename} bar} res] $res } {1 {unknown command "thisdoesntexist"}} test trace-27.3 {command trace info nonsense} { list [catch {trace info command thisdoesntexist} res] $res } {1 {unknown command "thisdoesntexist"}} test trace-28.1 {enterstep and leavestep traces with update idletasks (615043)} { catch {rename foo {}} proc foo {} { set a 1 update idletasks set b 1 } set info {} trace add execution foo {enter enterstep leavestep leave} \ [list traceExecute foo] update after idle {set a "idle"} foo trace remove execution foo {enter enterstep leavestep leave} \ [list traceExecute foo] rename foo {} catch {unset a} join $info "\n" } {foo foo enter foo {set a 1} enterstep foo {set a 1} 0 1 leavestep foo {update idletasks} enterstep foo {set a idle} enterstep foo {set a idle} 0 idle leavestep foo {update idletasks} 0 {} leavestep foo {set b 1} enterstep foo {set b 1} 0 1 leavestep foo foo 0 1 leave} test trace-28.2 {exec traces with 'error'} { set info {} set res {} proc foo {} { if {[catch {bar}]} { return "error" } else { return "ok" } } proc bar {} { error "msg" } lappend res [foo] trace add execution foo {enter enterstep leave leavestep} \ [list traceExecute foo] # With the trace active lappend res [foo] trace remove execution foo {enter enterstep leave leavestep} \ [list traceExecute foo] list $res [join $info \n] } {{error error} {foo foo enter foo {if {[catch {bar}]} { return "error" } else { return "ok" }} enterstep foo {catch bar} enterstep foo bar enterstep foo {error msg} enterstep foo {error msg} 1 msg leavestep foo bar 1 msg leavestep foo {catch bar} 0 1 leavestep foo {return error} enterstep foo {return error} 2 error leavestep foo {if {[catch {bar}]} { return "error" } else { return "ok" }} 2 error leavestep foo foo 0 error leave}} test trace-28.3 {exec traces with 'return -code error'} { set info {} set res {} proc foo {} { if {[catch {bar}]} { return "error" } else { return "ok" } } proc bar {} { return -code error "msg" } lappend res [foo] trace add execution foo {enter enterstep leave leavestep} \ [list traceExecute foo] # With the trace active lappend res [foo] trace remove execution foo {enter enterstep leave leavestep} \ [list traceExecute foo] list $res [join $info \n] } {{error error} {foo foo enter foo {if {[catch {bar}]} { return "error" } else { return "ok" }} enterstep foo {catch bar} enterstep foo bar enterstep foo {return -code error msg} enterstep foo {return -code error msg} 2 msg leavestep foo bar 1 msg leavestep foo {catch bar} 0 1 leavestep foo {return error} enterstep foo {return error} 2 error leavestep foo {if {[catch {bar}]} { return "error" } else { return "ok" }} 2 error leavestep foo foo 0 error leave}} test trace-28.4 {exec traces in slave with 'return -code error'} { interp create slave interp alias slave traceExecute {} traceExecute set info {} set res [interp eval slave { set info {} set res {} proc foo {} { if {[catch {bar}]} { return "error" } else { return "ok" } } proc bar {} { return -code error "msg" } lappend res [foo] trace add execution foo {enter enterstep leave leavestep} \ [list traceExecute foo] # With the trace active lappend res [foo] trace remove execution foo {enter enterstep leave leavestep} \ [list traceExecute foo] list $res }] interp delete slave lappend res [join $info \n] } {{error error} {foo foo enter foo {if {[catch {bar}]} { return "error" } else { return "ok" }} enterstep foo {catch bar} enterstep foo bar enterstep foo {return -code error msg} enterstep foo {return -code error msg} 2 msg leavestep foo bar 1 msg leavestep foo {catch bar} 0 1 leavestep foo {return error} enterstep foo {return error} 2 error leavestep foo {if {[catch {bar}]} { return "error" } else { return "ok" }} 2 error leavestep foo foo 0 error leave}} test trace-28.5 {exec traces} { set info {} proc foo {args} { set a 1 } trace add execution foo {enter enterstep leave leavestep} \ [list traceExecute foo] after idle [list foo test-28.4] update # Complicated way of removing traces set ti [lindex [eval [list trace info execution ::foo]] 0] if {[llength $ti]} { eval [concat [list trace remove execution foo] $ti] } join $info \n } {foo {foo test-28.4} enter foo {set a 1} enterstep foo {set a 1} 0 1 leavestep foo {foo test-28.4} 0 1 leave} test trace-28.6 {exec traces firing order} { set info {} proc enterStep {cmd op} {lappend ::info "enter $cmd/$op"} proc leaveStep {cmd code result op} {lappend ::info "leave $cmd/$code/$result/$op"} proc foo x { set b x=$x incr x } trace add execution foo enterstep enterStep trace add execution foo leavestep leaveStep foo 42 rename foo {} join $info \n } {enter set b x=42/enterstep leave set b x=42/0/x=42/leavestep enter incr x/enterstep leave incr x/0/43/leavestep} test trace-28.7 {exec trace information} { set info {} proc foo x { incr x } proc bar {args} {} trace add execution foo {enter leave enterstep leavestep} bar set info [trace info execution foo] trace remove execution foo {enter leave enterstep leavestep} bar } {} test trace-28.8 {exec trace remove nonsense} { list [catch {trace remove execution thisdoesntexist \ {enter leave enterstep leavestep} bar} res] $res } {1 {unknown command "thisdoesntexist"}} test trace-28.9 {exec trace info nonsense} { list [catch {trace info execution thisdoesntexist} res] $res } {1 {unknown command "thisdoesntexist"}} test trace-28.10 {exec trace info nonsense} { list [catch {trace remove execution} res] $res } {1 {wrong # args: should be "trace remove execution name opList command"}} # Missing test number to keep in sync with the 8.5 branch # (want to backport those tests?) test trace-31.1 {command and execution traces shared struct} { # Tcl Bug 807243 proc foo {} {} trace add command foo delete foo trace add execution foo enter foo set result [trace info command foo] trace remove command foo delete foo trace remove execution foo enter foo rename foo {} set result } [list [list delete foo]] test trace-31.2 {command and execution traces shared struct} { # Tcl Bug 807243 proc foo {} {} trace add command foo delete foo trace add execution foo enter foo set result [trace info execution foo] trace remove command foo delete foo trace remove execution foo enter foo rename foo {} set result } [list [list enter foo]] test trace-32.1 { TraceCommandInfo refcount decr in TraceCommandProc w/o loss of reference } { # Tcl Bug 811483 proc foo {} {} trace add command foo delete foo trace add execution foo enter foo set result [trace info command foo] rename foo {} set result } [list [list delete foo]] test trace-33.1 {variable match with remove variable} { unset -nocomplain x trace variable x w foo trace remove variable x write foo llength [trace info variable x] } 0 test trace-34.1 {Bug 1201035} { set ::x [list] proc foo {} {lappend ::x foo} proc bar args { lappend ::x $args trace remove execution foo leavestep bar trace remove execution foo enterstep bar trace add execution foo leavestep bar trace add execution foo enterstep bar lappend ::x done } trace add execution foo leavestep bar trace add execution foo enterstep bar foo set ::x } {{{lappend ::x foo} enterstep} done foo} test trace-34.2 {Bug 1224585} { proc foo {} {} proc bar args {trace remove execution foo leave soom} trace add execution foo leave bar trace add execution foo leave soom foo } {} test trace-34.3 {Bug 1224585} { proc foo {} {set x {}} proc bar args {trace remove execution foo enterstep soom} trace add execution foo enterstep soom trace add execution foo enterstep bar foo } {} # We test here for the half-documented and currently valid interplay between # delete traces and namespace deletion. test trace-34.4 {Bug 1047286} { variable x notrace proc callback {old - -} { variable x "$old exists: [namespace which -command $old]" } namespace eval ::foo {proc bar {} {}} trace add command ::foo::bar delete [namespace code callback] namespace delete ::foo set x } {::foo::bar exists: ::foo::bar} test trace-34.5 {Bug 1047286} { variable x notrace proc callback {old - -} { variable x "$old exists: [namespace which -command $old]" } namespace eval ::foo {proc bar {} {}} trace add command ::foo::bar delete [namespace code callback] namespace eval ::foo namespace delete ::foo set x } {::foo::bar exists: } test trace-34.6 {Bug 1458266} -setup { proc dummy {} {} proc stepTraceHandler {cmdString args} { variable log append log "[expr {[info level] - 1}]: [lindex [split $cmdString] 0]\n" dummy isTracedInside_2 } proc cmdTraceHandler {cmdString args} { # silent } proc isTracedInside_1 {} { isTracedInside_2 } proc isTracedInside_2 {} { set x 2 } } -body { variable log {} trace add execution isTracedInside_1 enterstep stepTraceHandler trace add execution isTracedInside_2 enterstep stepTraceHandler isTracedInside_1 variable first $log set log {} trace add execution dummy enter cmdTraceHandler isTracedInside_1 variable second $log expr {($first eq $second) ? "ok" : "\n$first\nand\n\n$second\ndiffer"} } -cleanup { unset -nocomplain log first second rename dummy {} rename stepTraceHandler {} rename cmdTraceHandler {} rename isTracedInside_1 {} rename isTracedInside_2 {} } -result ok test trace-39 {bug #3484621: tracing Bc'ed commands} -setup { set ::traceLog 0 set ::traceCalls 0 set ::bar [list 0 1 2 3] set res {} proc dotrace args { incr ::traceLog } proc foo {} { incr ::traceCalls # choose a BC'ed command that is 'unlikely' to interfere with tcltest's # internals lset ::bar 1 2 } } -body { foo lappend res $::traceLog trace add execution lset enter dotrace foo lappend res $::traceLog trace remove execution lset enter dotrace foo lappend res $::traceLog linsert $res 0 $::traceCalls | } -cleanup { unset ::traceLog ::traceCalls ::bar res rename dotrace {} rename foo {} } -result {3 | 0 1 1} # Delete procedures when done, so we don't clash with other tests # (e.g. foobar will clash with 'unknown' tests). catch {rename foobar {}} catch {rename foo {}} catch {rename bar {}} # Unset the varaible when done catch {unset info} # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/rename.test0000644003604700454610000001247511737050674014242 0ustar dgp771div# Commands covered: rename # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } # Must eliminate the "unknown" command while the test is running, # especially if the test is being run in a program with its # own special-purpose unknown command. catch {rename unknown unknown.old} catch {rename r2 {}} proc r1 {} {return "procedure r1"} rename r1 r2 test rename-1.1 {simple renaming} { r2 } {procedure r1} test rename-1.2 {simple renaming} { list [catch r1 msg] $msg } {1 {invalid command name "r1"}} rename r2 {} test rename-1.3 {simple renaming} { list [catch r2 msg] $msg } {1 {invalid command name "r2"}} # The test below is tricky because it renames a built-in command. # It's possible that the test procedure uses this command, so must # restore the command before calling test again. rename list l.new set a [catch list msg1] set b [l.new a b c] rename l.new list set c [catch l.new msg2] set d [list 111 222] test rename-2.1 {renaming built-in command} { list $a $msg1 $b $c $msg2 $d } {1 {invalid command name "list"} {a b c} 1 {invalid command name "l.new"} {111 222}} test rename-3.1 {error conditions} { list [catch {rename r1} msg] $msg $errorCode } {1 {wrong # args: should be "rename oldName newName"} NONE} test rename-3.2 {error conditions} { list [catch {rename r1 r2 r3} msg] $msg $errorCode } {1 {wrong # args: should be "rename oldName newName"} NONE} test rename-3.3 {error conditions} { proc r1 {} {} proc r2 {} {} list [catch {rename r1 r2} msg] $msg } {1 {can't rename to "r2": command already exists}} test rename-3.4 {error conditions} { catch {rename r1 {}} catch {rename r2 {}} list [catch {rename r1 r2} msg] $msg } {1 {can't rename "r1": command doesn't exist}} test rename-3.5 {error conditions} { catch {rename _non_existent_command {}} list [catch {rename _non_existent_command {}} msg] $msg } {1 {can't delete "_non_existent_command": command doesn't exist}} catch {rename unknown {}} catch {rename unknown.old unknown} catch {rename bar {}} if {[info command testdel] == "testdel"} { test rename-4.1 {reentrancy issues with command deletion and renaming} { set x {} testdel {} foo {lappend x deleted; rename bar {}; lappend x [info command bar]} rename foo bar lappend x | rename bar {} set x } {| deleted {}} test rename-4.2 {reentrancy issues with command deletion and renaming} { set x {} testdel {} foo {lappend x deleted; rename foo bar} rename foo {} set x } {deleted} test rename-4.3 {reentrancy issues with command deletion and renaming} { set x {} testdel {} foo {lappend x deleted; testdel {} foo {lappend x deleted2}} rename foo {} lappend x | rename foo {} set x } {deleted | deleted2} test rename-4.4 {reentrancy issues with command deletion and renaming} { set x {} testdel {} foo {lappend x deleted; rename foo bar} rename foo {} lappend x | [info command bar] } {deleted | {}} test rename-4.5 {reentrancy issues with command deletion and renaming} { set env(value) before interp create foo testdel foo cmd {set env(value) deleted} interp delete foo set env(value) } {deleted} test rename-4.6 {reentrancy issues with command deletion and renaming} { proc kill args { interp delete foo } set env(value) before interp create foo foo alias kill kill testdel foo cmd {set env(value) deleted; kill} list [catch {foo eval {rename cmd {}}} msg] $msg $env(value) } {0 {} deleted} test rename-4.7 {reentrancy issues with command deletion and renaming} { proc kill args { interp delete foo } set env(value) before interp create foo foo alias kill kill testdel foo cmd {set env(value) deleted; kill} list [catch {interp delete foo} msg] $msg $env(value) } {0 {} deleted} if {[info exists env(value)]} { unset env(value) } } # Save the unknown procedure which is modified by the following test. catch {rename unknown unknown.old} test rename-5.1 {repeated rename deletion and redefinition of same command} { set SAVED_UNKNOWN "proc unknown " append SAVED_UNKNOWN "\{[info args unknown.old]\} " append SAVED_UNKNOWN "\{[info body unknown.old]\}" for {set i 0} {$i < 10} {incr i} { eval $SAVED_UNKNOWN tcl_wordBreakBefore "" 0 rename tcl_wordBreakBefore {} rename unknown {} } } {} catch {rename unknown {}} catch {rename unknown.old unknown} test rename-6.1 {old code invalidated (epoch incremented) when cmd with compile proc is renamed } { proc x {} { set a 123 set b [incr a] } x rename incr incr.old proc incr {} {puts "new incr called!"} catch {x} msg set msg } {wrong # args: should be "incr"} if {[info commands incr.old] != {}} { catch {rename incr {}} catch {rename incr.old incr} } ::tcltest::cleanupTests return tcl8.4.20/tests/unixFile.test0000644003604700454610000000361611737050674014553 0ustar dgp771div# This file contains tests for the routines in the file tclUnixFile.c # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } if {[info commands testobj] == {}} { puts "This application hasn't been compiled with the \"testfindexecutable\"" puts "command, so I can't test the Tcl_FindExecutable function" ::tcltest::cleanupTests return } set oldpwd [pwd] cd [temporaryDirectory] catch { set oldPath $env(PATH) file attributes [makeFile "" junk] -perm 0777 } set absPath [file join [temporaryDirectory] junk] test unixFile-1.1 {Tcl_FindExecutable} {unixOnly} { set env(PATH) "" testfindexecutable junk } $absPath test unixFile-1.2 {Tcl_FindExecutable} {unixOnly} { set env(PATH) "/dummy" testfindexecutable junk } {} test unixFile-1.3 {Tcl_FindExecutable} {unixOnly} { set env(PATH) "/dummy:[pwd]" testfindexecutable junk } $absPath test unixFile-1.4 {Tcl_FindExecutable} {unixOnly} { set env(PATH) "/dummy:" testfindexecutable junk } $absPath test unixFile-1.5 {Tcl_FindExecutable} {unixOnly} { set env(PATH) "/dummy:/dummy" testfindexecutable junk } {} test unixFile-1.6 {Tcl_FindExecutable} {unixOnly} { set env(PATH) "/dummy::/dummy" testfindexecutable junk } $absPath test unixFile-1.7 {Tcl_FindExecutable} {unixOnly} { set env(PATH) ":/dummy" testfindexecutable junk } $absPath # cleanup catch {set env(PATH) $oldPath} removeFile junk cd $oldpwd ::tcltest::cleanupTests return tcl8.4.20/tests/opt.test0000644003604700454610000001642111737050674013570 0ustar dgp771div# Package covered: opt1.0/optparse.tcl # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994-1997 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } # the package we are going to test package require opt 0.4.1 # we are using implementation specifics to test the package #### functions tests ##### set n $::tcl::OptDescN test opt-1.1 {OptKeyRegister / check that auto allocation is skipping existing keys} { list [::tcl::OptKeyRegister {} $n] [::tcl::OptKeyRegister {} [expr $n+1]] [::tcl::OptKeyRegister {}] } "$n [expr $n+1] [expr $n+2]" test opt-2.1 {OptKeyDelete} { list [::tcl::OptKeyRegister {} testkey] \ [info exists ::tcl::OptDesc(testkey)] \ [::tcl::OptKeyDelete testkey] \ [info exists ::tcl::OptDesc(testkey)] } {testkey 1 {} 0} test opt-3.1 {OptParse / temp key is removed} { set n $::tcl::OptDescN set prev [array names ::tcl::OptDesc] ::tcl::OptKeyRegister {} $n list [info exists ::tcl::OptDesc($n)]\ [::tcl::OptKeyDelete $n]\ [::tcl::OptParse {{-foo}} {}]\ [info exists ::tcl::OptDesc($n)]\ [expr {"[lsort $prev]"=="[lsort [array names ::tcl::OptDesc]]"}] } {1 {} {} 0 1} test opt-3.2 {OptParse / temp key is removed even on errors} { set n $::tcl::OptDescN catch {::tcl::OptKeyDelete $n} list [catch {::tcl::OptParse {{-foo}} {-blah}}] \ [info exists ::tcl::OptDesc($n)] } {1 0} test opt-4.1 {OptProc} { ::tcl::OptProc optTest {} {} optTest ; ::tcl::OptKeyDelete optTest } {} test opt-5.1 {OptProcArgGiven} { ::tcl::OptProc optTest {{-foo}} { if {[::tcl::OptProcArgGiven "-foo"]} { return 1 } else { return 0 } } list [optTest] [optTest -f] [optTest -F] [optTest -fOO] } {0 1 1 1} test opt-6.1 {OptKeyParse} { ::tcl::OptKeyRegister {} test; list [catch {::tcl::OptKeyParse test {-help}} msg] $msg } {1 {Usage information: Var/FlagName Type Value Help ------------ ---- ----- ---- ( -help gives this help )}} test opt-7.1 {OptCheckType} { list \ [::tcl::OptCheckType 23 int] \ [::tcl::OptCheckType 23 float] \ [::tcl::OptCheckType true boolean] \ [::tcl::OptCheckType "-blah" any] \ [::tcl::OptCheckType {a b c} list] \ [::tcl::OptCheckType maYbe choice {yes maYbe no}] \ [catch {::tcl::OptCheckType "-blah" string}] \ [catch {::tcl::OptCheckType 6 boolean}] \ [catch {::tcl::OptCheckType x float}] \ [catch {::tcl::OptCheckType "a \{ c" list}] \ [catch {::tcl::OptCheckType 2.3 int}] \ [catch {::tcl::OptCheckType foo choice {x y Foo z}}] } {23 23.0 1 -blah {a b c} maYbe 1 1 1 1 1 1} test opt-8.1 {List utilities} { ::tcl::Lempty {} } 1 test opt-8.2 {List utilities} { ::tcl::Lempty {a b c} } 0 test opt-8.3 {List utilities} { ::tcl::Lget {a {b c d} e} {1 2} } d test opt-8.4 {List utilities} { set l {a {b c d e} f} ::tcl::Lvarset l {1 2} D set l } {a {b c D e} f} test opt-8.5 {List utilities} { set l {a b c} ::tcl::Lvarset1 l 6 X set l } {a b c {} {} {} X} test opt-8.6 {List utilities} { set l {a {b c 7 e} f} ::tcl::Lvarincr l {1 2} set l } {a {b c 8 e} f} test opt-8.7 {List utilities} { set l {a {b c 7 e} f} ::tcl::Lvarincr l {1 2} -9 set l } {a {b c -2 e} f} test opt-8.10 {List utilities} { set l {a {b c 7 e} f} ::tcl::Lvarpop l set l } {{b c 7 e} f} test opt-8.11 {List utilities} { catch {unset x} set l {a {b c 7 e} f} list [::tcl::Lassign $l u v w x] \ $u $v $w [info exists x] } {3 a {b c 7 e} f 0} test opt-9.1 {Misc utilities} { catch {unset v} ::tcl::SetMax v 3 ::tcl::SetMax v 7 ::tcl::SetMax v 6 set v } 7 test opt-9.2 {Misc utilities} { catch {unset v} ::tcl::SetMin v 3 ::tcl::SetMin v -7 ::tcl::SetMin v 1 set v } -7 #### behaviour tests ##### test opt-10.1 {ambigous flags} { ::tcl::OptProc optTest {{-fla} {-other} {-flag2xyz} {-flag3xyz}} {} catch {optTest -fL} msg set msg } {ambigous option "-fL", choose from: -fla boolflag (false) -flag2xyz boolflag (false) -flag3xyz boolflag (false) } test opt-10.2 {non ambigous flags} { ::tcl::OptProc optTest {{-flag1xyz} {-other} {-flag2xyz} {-flag3xyz}} { return $flag2xyz } optTest -fLaG2 } 1 test opt-10.3 {non ambigous flags because of exact match} { ::tcl::OptProc optTest {{-flag1x} {-other} {-flag1} {-flag1xy}} { return $flag1 } optTest -flAg1 } 1 test opt-10.4 {ambigous flags, not exact match} { ::tcl::OptProc optTest {{-flag1xy} {-other} {-flag1} {-flag1xyz}} { return $flag1 } catch {optTest -fLag1X} msg set msg } {ambigous option "-fLag1X", choose from: -flag1xy boolflag (false) -flag1xyz boolflag (false) } # medium size overall test example: (defined once) ::tcl::OptProc optTest { {cmd -choice {print save delete} "sub command to choose"} {-allowBoing -boolean true} {arg2 -string "this is help"} {?arg3? 7 "optional number"} {-moreflags} } { list $cmd $allowBoing $arg2 $arg3 $moreflags } test opt-10.5 {medium size overall test} { list [catch {optTest} msg] $msg } {1 {no value given for parameter "cmd" (use -help for full usage) : cmd choice (print save delete) sub command to choose}} test opt-10.6 {medium size overall test} { list [catch {optTest -help} msg] $msg } {1 {Usage information: Var/FlagName Type Value Help ------------ ---- ----- ---- ( -help gives this help ) cmd choice (print save delete) sub command to choose -allowBoing boolean (true) arg2 string () this is help ?arg3? int (7) optional number -moreflags boolflag (false) }} test opt-10.7 {medium size overall test} { optTest save tst } {save 1 tst 7 0} test opt-10.8 {medium size overall test} { optTest save -allowBoing false -- 8 } {save 0 8 7 0} test opt-10.9 {medium size overall test} { optTest save tst -m -- } {save 1 tst 7 1} test opt-10.10 {medium size overall test} { list [catch {optTest save tst foo} msg] [lindex [split $msg "\n"] 0] } {1 {too many arguments (unexpected argument(s): foo), usage:}} test opt-11.1 {too many args test 2} { set key [::tcl::OptKeyRegister {-foo}] list [catch {::tcl::OptKeyParse $key {-foo blah}} msg] $msg\ [::tcl::OptKeyDelete $key] } {1 {too many arguments (unexpected argument(s): blah), usage: Var/FlagName Type Value Help ------------ ---- ----- ---- ( -help gives this help ) -foo boolflag (false) } {}} test opt-11.2 {default value for args} { set args {} set key [::tcl::OptKeyRegister {{args -list {a b c} "args..."}}] ::tcl::OptKeyParse $key {} ::tcl::OptKeyDelete $key set args } {a b c} # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/stringComp.test0000644003604700454610000005176011737050674015120 0ustar dgp771div# Commands covered: string # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # This differs from the original string tests in that the tests call # things in procs, which uses the compiled string code instead of # the runtime parse string code. The tests of import should match # their equivalent number in string.test. # # Copyright (c) 2001 by ActiveState Corporation. # Copyright (c) 2001 by Kevin B. Kenny. All rights reserved. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } # Some tests require the testobj command set ::tcltest::testConstraints(testobj) \ [expr {[info commands testobj] != {}}] test stringComp-1.1 {error conditions} { proc foo {} {string gorp a b} list [catch {foo} msg] $msg } {1 {bad option "gorp": must be bytelength, compare, equal, first, index, is, last, length, map, match, range, repeat, replace, tolower, toupper, totitle, trim, trimleft, trimright, wordend, or wordstart}} test stringComp-1.2 {error conditions} { proc foo {} {string} list [catch {foo} msg] $msg } {1 {wrong # args: should be "string option arg ?arg ...?"}} test stringComp-1.3 {error condition - undefined method during compile} { # We don't want this to complain about 'never' because it may never # be called, or string may get redefined. This must compile OK. proc foo {str i} { if {"yes" == "no"} { string never called but complains here } string index $str $i } foo abc 0 } a test stringComp-2.1 {string compare, too few args} { proc foo {} {string compare a} list [catch {foo} msg] $msg } {1 {wrong # args: should be "string compare ?-nocase? ?-length int? string1 string2"}} test stringComp-2.2 {string compare, bad args} { proc foo {} {string compare a b c} list [catch {foo} msg] $msg } {1 {bad option "a": must be -nocase or -length}} test stringComp-2.3 {string compare, bad args} { list [catch {string compare -length -nocase str1 str2} msg] $msg } {1 {expected integer but got "-nocase"}} test stringComp-2.4 {string compare, too many args} { list [catch {string compare -length 10 -nocase str1 str2 str3} msg] $msg } {1 {wrong # args: should be "string compare ?-nocase? ?-length int? string1 string2"}} test stringComp-2.5 {string compare with length unspecified} { list [catch {string compare -length 10 10} msg] $msg } {1 {wrong # args: should be "string compare ?-nocase? ?-length int? string1 string2"}} test stringComp-2.6 {string compare} { proc foo {} {string compare abcde abdef} foo } -1 test stringComp-2.7 {string compare, shortest method name} { proc foo {} {string c abcde ABCDE} foo } 1 test stringComp-2.8 {string compare} { proc foo {} {string compare abcde abcde} foo } 0 test stringComp-2.9 {string compare with length} { proc foo {} {string compare -length 2 abcde abxyz} foo } 0 test stringComp-2.10 {string compare with special index} { proc foo {} {string compare -length end-3 abcde abxyz} list [catch {foo} msg] $msg } {1 {expected integer but got "end-3"}} test stringComp-2.11 {string compare, unicode} { proc foo {} {string compare ab\u7266 ab\u7267} foo } -1 test stringComp-2.12 {string compare, high bit} { # This test will fail if the underlying comparaison # is using signed chars instead of unsigned chars. # (like SunOS's default memcmp thus the compat/memcmp.c) proc foo {} {string compare "\x80" "@"} foo # Nb this tests works also in utf8 space because \x80 is # translated into a 2 or more bytelength but whose first byte has # the high bit set. } 1 test stringComp-2.13 {string compare -nocase} { proc foo {} {string compare -nocase abcde abdef} foo } -1 test stringComp-2.14 {string compare -nocase} { proc foo {} {string c -nocase abcde ABCDE} foo } 0 test stringComp-2.15 {string compare -nocase} { proc foo {} {string compare -nocase abcde abcde} foo } 0 test stringComp-2.16 {string compare -nocase with length} { proc foo {} {string compare -length 2 -nocase abcde Abxyz} foo } 0 test stringComp-2.17 {string compare -nocase with length} { proc foo {} {string compare -nocase -length 3 abcde Abxyz} foo } -1 test stringComp-2.18 {string compare -nocase with length <= 0} { proc foo {} {string compare -nocase -length -1 abcde AbCdEf} foo } -1 test stringComp-2.19 {string compare -nocase with excessive length} { proc foo {} {string compare -nocase -length 50 AbCdEf abcde} foo } 1 test stringComp-2.20 {string compare -len unicode} { # These are strings that are 6 BYTELENGTH long, but the length # shouldn't make a different because there are actually 3 CHARS long proc foo {} {string compare -len 5 \334\334\334 \334\334\374} foo } -1 test stringComp-2.21 {string compare -nocase with special index} { proc foo {} {string compare -nocase -length end-3 Abcde abxyz} list [catch {foo} msg] $msg } {1 {expected integer but got "end-3"}} test stringComp-2.22 {string compare, null strings} { proc foo {} {string compare "" ""} foo } 0 test stringComp-2.23 {string compare, null strings} { proc foo {} {string compare "" foo} foo } -1 test stringComp-2.24 {string compare, null strings} { proc foo {} {string compare foo ""} foo } 1 test stringComp-2.25 {string compare -nocase, null strings} { proc foo {} {string compare -nocase "" ""} foo } 0 test stringComp-2.26 {string compare -nocase, null strings} { proc foo {} {string compare -nocase "" foo} foo } -1 test stringComp-2.27 {string compare -nocase, null strings} { proc foo {} {string compare -nocase foo ""} foo } 1 test stringComp-2.28 {string compare with length, unequal strings} { proc foo {} {string compare -length 2 abc abde} foo } 0 test stringComp-2.29 {string compare with length, unequal strings} { proc foo {} {string compare -length 2 ab abde} foo } 0 test stringComp-2.30 {string compare with NUL character vs. other ASCII} { # Be careful here, since UTF-8 rep comparison with memcmp() of # these puts chars in the wrong order proc foo {} {string compare \x00 \x01} foo } -1 test stringComp-2.31 {string compare, high bit} { proc foo {} {string compare "a\x80" "a@"} foo } 1 test stringComp-2.32 {string compare, high bit} { proc foo {} {string compare "a\x00" "a\x01"} foo } -1 test stringComp-2.33 {string compare, high bit} { proc foo {} {string compare "\x00\x00" "\x00\x01"} foo } -1 # only need a few tests on equal, since it uses the same code as # string compare, but just modifies the return output test stringComp-3.1 {string equal} { proc foo {} {string equal abcde abdef} foo } 0 test stringComp-3.2 {string equal} { proc foo {} {string eq abcde ABCDE} foo } 0 test stringComp-3.3 {string equal} { proc foo {} {string equal abcde abcde} foo } 1 test stringComp-3.4 {string equal -nocase} { proc foo {} {string equal -nocase \334\334\334\334\374\374\374\374 \334\334\334\334\334\334\334\334} foo } 1 test stringComp-3.5 {string equal -nocase} { proc foo {} {string equal -nocase abcde abdef} foo } 0 test stringComp-3.6 {string equal -nocase} { proc foo {} {string eq -nocase abcde ABCDE} foo } 1 test stringComp-3.7 {string equal -nocase} { proc foo {} {string equal -nocase abcde abcde} foo } 1 test stringComp-3.8 {string equal with length, unequal strings} { proc foo {} {string equal -length 2 abc abde} foo } 1 test stringComp-4.1 {string first, too few args} { proc foo {} {string first a} list [catch {foo} msg] $msg } {1 {wrong # args: should be "string first subString string ?startIndex?"}} test stringComp-4.2 {string first, bad args} { proc foo {} {string first a b c} list [catch {foo} msg] $msg } {1 {bad index "c": must be integer or end?-integer?}} test stringComp-4.3 {string first, too many args} { proc foo {} {string first a b 5 d} list [catch {foo} msg] $msg } {1 {wrong # args: should be "string first subString string ?startIndex?"}} test stringComp-4.4 {string first} { proc foo {} {string first bq abcdefgbcefgbqrs} foo } 12 test stringComp-4.5 {string first} { proc foo {} {string fir bcd abcdefgbcefgbqrs} foo } 1 test stringComp-4.6 {string first} { proc foo {} {string f b abcdefgbcefgbqrs} foo } 1 test stringComp-4.7 {string first} { proc foo {} {string first xxx x123xx345xxx789xxx012} foo } 9 test stringComp-4.8 {string first} { proc foo {} {string first "" x123xx345xxx789xxx012} foo } -1 test stringComp-4.9 {string first, unicode} { proc foo {} {string first x abc\u7266x} foo } 4 test stringComp-4.10 {string first, unicode} { proc foo {} {string first \u7266 abc\u7266x} foo } 3 test stringComp-4.11 {string first, start index} { proc foo {} {string first \u7266 abc\u7266x 3} foo } 3 test stringComp-4.12 {string first, start index} { proc foo {} {string first \u7266 abc\u7266x 4} foo } -1 test stringComp-4.13 {string first, start index} { proc foo {} {string first \u7266 abc\u7266x end-2} foo } 3 test stringComp-4.14 {string first, negative start index} { proc foo {} {string first b abc -1} foo } 1 test stringComp-5.1 {string index} { proc foo {} {string index} list [catch {foo} msg] $msg } {1 {wrong # args: should be "string index string charIndex"}} test stringComp-5.2 {string index} { proc foo {} {string index a b c} list [catch {foo} msg] $msg } {1 {wrong # args: should be "string index string charIndex"}} test stringComp-5.3 {string index} { proc foo {} {string index abcde 0} foo } a test stringComp-5.4 {string index} { proc foo {} {string in abcde 4} foo } e test stringComp-5.5 {string index} { proc foo {} {string index abcde 5} foo } {} test stringComp-5.6 {string index} { proc foo {} {string index abcde -10} list [catch {foo} msg] $msg } {0 {}} test stringComp-5.7 {string index} { proc foo {} {string index a xyz} list [catch {foo} msg] $msg } {1 {bad index "xyz": must be integer or end?-integer?}} test stringComp-5.8 {string index} { proc foo {} {string index abc end} foo } c test stringComp-5.9 {string index} { proc foo {} {string index abc end-1} foo } b test stringComp-5.10 {string index, unicode} { proc foo {} {string index abc\u7266d 4} foo } d test stringComp-5.11 {string index, unicode} { proc foo {} {string index abc\u7266d 3} foo } \u7266 test stringComp-5.12 {string index, unicode over char length, under byte length} { proc foo {} {string index \334\374\334\374 6} foo } {} test stringComp-5.13 {string index, bytearray object} { proc foo {} {string index [binary format a5 fuz] 0} foo } f test stringComp-5.14 {string index, bytearray object} { proc foo {} {string index [binary format I* {0x50515253 0x52}] 3} foo } S test stringComp-5.15 {string index, bytearray object} { proc foo {} { set b [binary format I* {0x50515253 0x52}] set i1 [string index $b end-6] set i2 [string index $b 1] string compare $i1 $i2 } foo } 0 test stringComp-5.16 {string index, bytearray object with string obj shimmering} { proc foo {} { set str "0123456789\x00 abcdedfghi" binary scan $str H* dump string compare [string index $str 10] \x00 } foo } 0 test stringComp-5.17 {string index, bad integer} { proc foo {} {string index "abc" 08} list [catch {foo} msg] $msg } {1 {bad index "08": must be integer or end?-integer? (looks like invalid octal number)}} test stringComp-5.18 {string index, bad integer} { proc foo {} {string index "abc" end-00289} list [catch {foo} msg] $msg } {1 {bad index "end-00289": must be integer or end?-integer? (looks like invalid octal number)}} test stringComp-5.19 {string index, bytearray object out of bounds} { proc foo {} {string index [binary format I* {0x50515253 0x52}] -1} foo } {} test stringComp-5.20 {string index, bytearray object out of bounds} { proc foo {} {string index [binary format I* {0x50515253 0x52}] 20} foo } {} proc largest_int {} { # This will give us what the largest valid int on this machine is, # so we can test for overflow properly below on >32 bit systems set int 1 set exp 7; # assume we get at least 8 bits while {$int > 0} { set int [expr {1 << [incr exp]}] } return [expr {$int-1}] } ## string is ## not yet bc catch {rename largest_int {}} ## string last ## not yet bc ## string length ## not yet bc test stringComp-8.1 {string bytelength} { proc foo {} {string bytelength} list [catch {foo} msg] $msg } {1 {wrong # args: should be "string bytelength string"}} test stringComp-8.2 {string bytelength} { proc foo {} {string bytelength a b} list [catch {foo} msg] $msg } {1 {wrong # args: should be "string bytelength string"}} test stringComp-8.3 {string bytelength} { proc foo {} {string bytelength "\u00c7"} foo } 2 test stringComp-8.4 {string bytelength} { proc foo {} {string b ""} foo } 0 ## string length ## test stringComp-9.1 {string length} { proc foo {} {string length} list [catch {foo} msg] $msg } {1 {wrong # args: should be "string length string"}} test stringComp-9.2 {string length} { proc foo {} {string length a b} list [catch {foo} msg] $msg } {1 {wrong # args: should be "string length string"}} test stringComp-9.3 {string length} { proc foo {} {string length "a little string"} foo } 15 test stringComp-9.4 {string length} { proc foo {} {string le ""} foo } 0 test stringComp-9.5 {string length, unicode} { proc foo {} {string le "abcd\u7266"} foo } 5 test stringComp-9.6 {string length, bytearray object} { proc foo {} {string length [binary format a5 foo]} foo } 5 test stringComp-9.7 {string length, bytearray object} { proc foo {} {string length [binary format I* {0x50515253 0x52}]} foo } 8 ## string map ## not yet bc ## string match ## test stringComp-11.1 {string match, too few args} { proc foo {} {string match a} list [catch {foo} msg] $msg } {1 {wrong # args: should be "string match ?-nocase? pattern string"}} test stringComp-11.2 {string match, too many args} { proc foo {} {string match a b c d} list [catch {foo} msg] $msg } {1 {wrong # args: should be "string match ?-nocase? pattern string"}} test stringComp-11.3 {string match} { proc foo {} {string match abc abc} foo } 1 test stringComp-11.4 {string match} { proc foo {} {string mat abc abd} foo } 0 test stringComp-11.5 {string match} { proc foo {} {string match ab*c abc} foo } 1 test stringComp-11.6 {string match} { proc foo {} {string match ab**c abc} foo } 1 test stringComp-11.7 {string match} { proc foo {} {string match ab* abcdef} foo } 1 test stringComp-11.8 {string match} { proc foo {} {string match *c abc} foo } 1 test stringComp-11.9 {string match} { proc foo {} {string match *3*6*9 0123456789} foo } 1 test stringComp-11.10 {string match} { proc foo {} {string match *3*6*9 01234567890} foo } 0 test stringComp-11.11 {string match} { proc foo {} {string match a?c abc} foo } 1 test stringComp-11.12 {string match} { proc foo {} {string match a??c abc} foo } 0 test stringComp-11.13 {string match} { proc foo {} {string match ?1??4???8? 0123456789} foo } 1 test stringComp-11.14 {string match} { proc foo {} {string match {[abc]bc} abc} foo } 1 test stringComp-11.15 {string match} { proc foo {} {string match {a[abc]c} abc} foo } 1 test stringComp-11.16 {string match} { proc foo {} {string match {a[xyz]c} abc} foo } 0 test stringComp-11.17 {string match} { proc foo {} {string match {12[2-7]45} 12345} foo } 1 test stringComp-11.18 {string match} { proc foo {} {string match {12[ab2-4cd]45} 12345} foo } 1 test stringComp-11.19 {string match} { proc foo {} {string match {12[ab2-4cd]45} 12b45} foo } 1 test stringComp-11.20 {string match} { proc foo {} {string match {12[ab2-4cd]45} 12d45} foo } 1 test stringComp-11.21 {string match} { proc foo {} {string match {12[ab2-4cd]45} 12145} foo } 0 test stringComp-11.22 {string match} { proc foo {} {string match {12[ab2-4cd]45} 12545} foo } 0 test stringComp-11.23 {string match} { proc foo {} {string match {a\*b} a*b} foo } 1 test stringComp-11.24 {string match} { proc foo {} {string match {a\*b} ab} foo } 0 test stringComp-11.25 {string match} { proc foo {} {string match {a\*\?\[\]\\\x} "a*?\[\]\\x"} foo } 1 test stringComp-11.26 {string match} { proc foo {} {string match ** ""} foo } 1 test stringComp-11.27 {string match} { proc foo {} {string match *. ""} foo } 0 test stringComp-11.28 {string match} { proc foo {} {string match "" ""} foo } 1 test stringComp-11.29 {string match} { proc foo {} {string match \[a a} foo } 1 test stringComp-11.30 {string match, bad args} { proc foo {} {string match - b c} list [catch {foo} msg] $msg } {1 {bad option "-": must be -nocase}} test stringComp-11.31 {string match case} { proc foo {} {string match a A} foo } 0 test stringComp-11.32 {string match nocase} { proc foo {} {string match -n a A} foo } 1 test stringComp-11.33 {string match nocase} { proc foo {} {string match -nocase a\334 A\374} foo } 1 test stringComp-11.34 {string match nocase} { proc foo {} {string match -nocase a*f ABCDEf} foo } 1 test stringComp-11.35 {string match case, false hope} { # This is true because '_' lies between the A-Z and a-z ranges proc foo {} {string match {[A-z]} _} foo } 1 test stringComp-11.36 {string match nocase range} { # This is false because although '_' lies between the A-Z and a-z ranges, # we lower case the end points before checking the ranges. proc foo {} {string match -nocase {[A-z]} _} foo } 0 test stringComp-11.37 {string match nocase} { proc foo {} {string match -nocase {[A-fh-Z]} g} foo } 0 test stringComp-11.38 {string match case, reverse range} { proc foo {} {string match {[A-fh-Z]} g} foo } 1 test stringComp-11.39 {string match, *\ case} { proc foo {} {string match {*\abc} abc} foo } 1 test stringComp-11.40 {string match, *special case} { proc foo {} {string match {*[ab]} abc} foo } 0 test stringComp-11.41 {string match, *special case} { proc foo {} {string match {*[ab]*} abc} foo } 1 test stringComp-11.42 {string match, *special case} { proc foo {} {string match "*\\" "\\"} foo } 0 test stringComp-11.43 {string match, *special case} { proc foo {} {string match "*\\\\" "\\"} foo } 1 test stringComp-11.44 {string match, *special case} { proc foo {} {string match "*???" "12345"} foo } 1 test stringComp-11.45 {string match, *special case} { proc foo {} {string match "*???" "12"} foo } 0 test stringComp-11.46 {string match, *special case} { proc foo {} {string match "*\\*" "abc*"} foo } 1 test stringComp-11.47 {string match, *special case} { proc foo {} {string match "*\\*" "*"} foo } 1 test stringComp-11.48 {string match, *special case} { proc foo {} {string match "*\\*" "*abc"} foo } 0 test stringComp-11.49 {string match, *special case} { proc foo {} {string match "?\\*" "a*"} foo } 1 test stringComp-11.50 {string match, *special case} { proc foo {} {string match "\\" "\\"} foo } 0 test stringComp-11.51 {string match; *, -nocase and UTF-8} { proc foo {} {string match -nocase [binary format I 717316707] \ [binary format I 2028036707]} foo } 1 test stringComp-11.52 {string match, null char in string} { proc foo {} { set ptn "*abc*" foreach elem [list "\u0000@abc" "@abc" "\u0000@abc\u0000" "blahabcblah"] { lappend out [string match $ptn $elem] } set out } foo } {1 1 1 1} test stringComp-11.53 {string match, null char in pattern} { proc foo {} { set out "" foreach {ptn elem} [list \ "*\u0000abc\u0000" "\u0000abc\u0000" \ "*\u0000abc\u0000" "\u0000abc\u0000ef" \ "*\u0000abc\u0000*" "\u0000abc\u0000ef" \ "*\u0000abc\u0000" "@\u0000abc\u0000ef" \ "*\u0000abc\u0000*" "@\u0000abc\u0000ef" \ ] { lappend out [string match $ptn $elem] } set out } foo } {1 0 1 0 1} test stringComp-11.54 {string match, failure} { proc foo {} { set longString "" for {set i 0} {$i < 10} {incr i} { append longString "abcdefghijklmnopqrstuvwxy\u0000z01234567890123" } list [string match *cba* $longString] \ [string match *a*l*\u0000* $longString] \ [string match *a*l*\u0000*123 $longString] \ [string match *a*l*\u0000*123* $longString] \ [string match *a*l*\u0000*cba* $longString] \ [string match *===* $longString] } foo } {0 1 1 1 0 0} ## string range ## not yet bc ## string repeat ## not yet bc ## string replace ## not yet bc ## string tolower ## not yet bc ## string toupper ## not yet bc ## string totitle ## not yet bc ## string trim* ## not yet bc ## string word* ## not yet bc # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/registry.test0000644003604700454610000007001311737050674014633 0ustar dgp771div# registry.test -- # # This file contains a collection of tests for the registry command. # Sourcing this file into Tcl runs the tests and generates output for # errors. No output means no errors were found. # # In order for these tests to run, the registry package must be on the # auto_path or the registry package must have been loaded already. # # Copyright (c) 1997 by Sun Microsystems, Inc. All rights reserved. # Copyright (c) 1998-1999 by Scriptics Corporation. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import -force ::tcltest::* } if {$tcl_platform(platform) == "windows"} { if [catch { set lib [lindex [glob -directory [file join [pwd] [file dirname \ [info nameofexecutable]]] tclreg*.dll] 0] load $lib registry }] { puts "Unable to find the registry package. Skipping registry tests." return } } # determine the current locale testConstraint english [expr {[llength [info commands testlocale]] && [string equal [testlocale all ""] "English_United States.1252"] }] set hostname [info hostname] test registry-1.1 {argument parsing for registry command} {pcOnly} { list [catch {registry} msg] $msg } {1 {wrong # args: should be "registry option ?arg arg ...?"}} test registry-1.2 {argument parsing for registry command} {pcOnly} { list [catch {registry foo} msg] $msg } {1 {bad option "foo": must be broadcast, delete, get, keys, set, type, or values}} test registry-1.3 {argument parsing for registry command} {pcOnly} { list [catch {registry d} msg] $msg } {1 {wrong # args: should be "registry delete keyName ?valueName?"}} test registry-1.4 {argument parsing for registry command} {pcOnly} { list [catch {registry delete} msg] $msg } {1 {wrong # args: should be "registry delete keyName ?valueName?"}} test registry-1.5 {argument parsing for registry command} {pcOnly} { list [catch {registry delete foo bar baz} msg] $msg } {1 {wrong # args: should be "registry delete keyName ?valueName?"}} test registry-1.6 {argument parsing for registry command} {pcOnly} { list [catch {registry g} msg] $msg } {1 {wrong # args: should be "registry get keyName valueName"}} test registry-1.7 {argument parsing for registry command} {pcOnly} { list [catch {registry get} msg] $msg } {1 {wrong # args: should be "registry get keyName valueName"}} test registry-1.8 {argument parsing for registry command} {pcOnly} { list [catch {registry get foo} msg] $msg } {1 {wrong # args: should be "registry get keyName valueName"}} test registry-1.9 {argument parsing for registry command} {pcOnly} { list [catch {registry get foo bar baz} msg] $msg } {1 {wrong # args: should be "registry get keyName valueName"}} test registry-1.10 {argument parsing for registry command} {pcOnly} { list [catch {registry k} msg] $msg } {1 {wrong # args: should be "registry keys keyName ?pattern?"}} test registry-1.11 {argument parsing for registry command} {pcOnly} { list [catch {registry keys} msg] $msg } {1 {wrong # args: should be "registry keys keyName ?pattern?"}} test registry-1.12 {argument parsing for registry command} {pcOnly} { list [catch {registry keys foo bar baz} msg] $msg } {1 {wrong # args: should be "registry keys keyName ?pattern?"}} test registry-1.13 {argument parsing for registry command} {pcOnly} { list [catch {registry s} msg] $msg } {1 {wrong # args: should be "registry set keyName ?valueName data ?type??"}} test registry-1.14 {argument parsing for registry command} {pcOnly} { list [catch {registry set} msg] $msg } {1 {wrong # args: should be "registry set keyName ?valueName data ?type??"}} test registry-1.15 {argument parsing for registry command} {pcOnly} { list [catch {registry set foo bar} msg] $msg } {1 {wrong # args: should be "registry set keyName ?valueName data ?type??"}} test registry-1.16 {argument parsing for registry command} {pcOnly} { list [catch {registry set foo bar baz blat gorp} msg] $msg } {1 {wrong # args: should be "registry set keyName ?valueName data ?type??"}} test registry-1.17 {argument parsing for registry command} {pcOnly} { list [catch {registry t} msg] $msg } {1 {wrong # args: should be "registry type keyName valueName"}} test registry-1.18 {argument parsing for registry command} {pcOnly} { list [catch {registry type} msg] $msg } {1 {wrong # args: should be "registry type keyName valueName"}} test registry-1.19 {argument parsing for registry command} {pcOnly} { list [catch {registry type foo} msg] $msg } {1 {wrong # args: should be "registry type keyName valueName"}} test registry-1.20 {argument parsing for registry command} {pcOnly} { list [catch {registry type foo bar baz} msg] $msg } {1 {wrong # args: should be "registry type keyName valueName"}} test registry-1.21 {argument parsing for registry command} {pcOnly} { list [catch {registry v} msg] $msg } {1 {wrong # args: should be "registry values keyName ?pattern?"}} test registry-1.22 {argument parsing for registry command} {pcOnly} { list [catch {registry values} msg] $msg } {1 {wrong # args: should be "registry values keyName ?pattern?"}} test registry-1.23 {argument parsing for registry command} {pcOnly} { list [catch {registry values foo bar baz} msg] $msg } {1 {wrong # args: should be "registry values keyName ?pattern?"}} test registry-2.1 {DeleteKey: bad key} {pcOnly} { list [catch {registry delete foo} msg] $msg } {1 {bad root name "foo": must be HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, HKEY_CURRENT_CONFIG, HKEY_PERFORMANCE_DATA, or HKEY_DYN_DATA}} test registry-2.2 {DeleteKey: bad key} {pcOnly} { list [catch {registry delete HKEY_CLASSES_ROOT} msg] $msg } {1 {bad key: cannot delete root keys}} test registry-2.3 {DeleteKey: bad key} {pcOnly} { list [catch {registry delete HKEY_CLASSES_ROOT\\} msg] $msg } {1 {bad key: cannot delete root keys}} test registry-2.4 {DeleteKey: subkey at root level} {pcOnly} { registry set HKEY_CURRENT_USER\\TclFoobar registry delete HKEY_CURRENT_USER\\TclFoobar registry keys HKEY_CURRENT_USER TclFoobar } {} test registry-2.5 {DeleteKey: subkey below root level} {pcOnly} { registry set HKEY_CURRENT_USER\\TclFoobar\\test registry delete HKEY_CURRENT_USER\\TclFoobar\\test set result [registry keys HKEY_CURRENT_USER TclFoobar\\test] registry delete HKEY_CURRENT_USER\\TclFoobar set result } {} test registry-2.6 {DeleteKey: recursive delete} {pcOnly} { registry set HKEY_CURRENT_USER\\TclFoobar\\test1 registry set HKEY_CURRENT_USER\\TclFoobar\\test2\\test3 registry delete HKEY_CURRENT_USER\\TclFoobar set result [registry keys HKEY_CURRENT_USER TclFoobar] set result } {} test registry-2.7 {DeleteKey: trailing backslashes} {pcOnly english} { registry set HKEY_CURRENT_USER\\TclFoobar\\baz list [catch {registry delete HKEY_CURRENT_USER\\TclFoobar\\} msg] $msg } {1 {unable to delete key: The configuration registry key is invalid.}} test registry-2.8 {DeleteKey: failure} {pcOnly} { registry delete HKEY_CURRENT_USER\\TclFoobar registry delete HKEY_CURRENT_USER\\TclFoobar } {} test registry-2.9 {DeleteKey: unicode} {pcOnly} { registry delete HKEY_CURRENT_USER\\TclFoobar registry set HKEY_CURRENT_USER\\TclFoobar\\test\u00c7bar\\a registry set HKEY_CURRENT_USER\\TclFoobar\\test\u00c7bar\\b registry delete HKEY_CURRENT_USER\\TclFoobar\\test\u00c7bar set result [registry keys HKEY_CURRENT_USER\\TclFoobar] registry delete HKEY_CURRENT_USER\\TclFoobar set result } {} test registry-3.1 {DeleteValue} {pcOnly} { registry delete HKEY_CURRENT_USER\\TclFoobar registry set HKEY_CURRENT_USER\\TclFoobar\\baz test1 blort registry set HKEY_CURRENT_USER\\TclFoobar\\baz test2 blat registry delete HKEY_CURRENT_USER\\TclFoobar\\baz test1 set result [registry values HKEY_CURRENT_USER\\TclFoobar\\baz] registry delete HKEY_CURRENT_USER\\TclFoobar set result } test2 test registry-3.2 {DeleteValue: bad key} {pcOnly english} { registry delete HKEY_CURRENT_USER\\TclFoobar list [catch {registry delete HKEY_CURRENT_USER\\TclFoobar test} msg] $msg } {1 {unable to open key: The system cannot find the file specified.}} test registry-3.3 {DeleteValue: bad value} {pcOnly english} { registry delete HKEY_CURRENT_USER\\TclFoobar registry set HKEY_CURRENT_USER\\TclFoobar\\baz test2 blort set result [list [catch {registry delete HKEY_CURRENT_USER\\TclFoobar test1} msg] $msg] registry delete HKEY_CURRENT_USER\\TclFoobar set result } {1 {unable to delete value "test1" from key "HKEY_CURRENT_USER\TclFoobar": The system cannot find the file specified.}} test registry-3.4 {DeleteValue: Unicode} {pcOnly} { registry delete HKEY_CURRENT_USER\\TclFoobar registry set HKEY_CURRENT_USER\\TclFoobar\\\u00c7baz \u00c7test1 blort registry set HKEY_CURRENT_USER\\TclFoobar\\\u00c7baz test2 blat registry delete HKEY_CURRENT_USER\\TclFoobar\\\u00c7baz \u00c7test1 set result [registry values HKEY_CURRENT_USER\\TclFoobar\\\u00c7baz] registry delete HKEY_CURRENT_USER\\TclFoobar set result } test2 test registry-4.1 {GetKeyNames: bad key} {pcOnly english} { registry delete HKEY_CURRENT_USER\\TclFoobar list [catch {registry keys HKEY_CURRENT_USER\\TclFoobar} msg] $msg } {1 {unable to open key: The system cannot find the file specified.}} test registry-4.2 {GetKeyNames} {pcOnly} { registry delete HKEY_CURRENT_USER\\TclFoobar registry set HKEY_CURRENT_USER\\TclFoobar\\baz set result [registry keys HKEY_CURRENT_USER\\TclFoobar] registry delete HKEY_CURRENT_USER\\TclFoobar set result } {baz} test registry-4.3 {GetKeyNames: remote key} {pcOnly nonPortable english} { registry set \\\\$hostname\\HKEY_CURRENT_USER\\TclFoobar\\baz set result [registry keys \\\\gaspode\\HKEY_CURRENT_USER\\TclFoobar] registry delete \\\\$hostname\\HKEY_CURRENT_USER\\TclFoobar set result } {baz} test registry-4.4 {GetKeyNames: empty key} {pcOnly} { registry delete HKEY_CURRENT_USER\\TclFoobar registry set HKEY_CURRENT_USER\\TclFoobar set result [registry keys HKEY_CURRENT_USER\\TclFoobar] registry delete HKEY_CURRENT_USER\\TclFoobar set result } {} test registry-4.5 {GetKeyNames: patterns} {pcOnly} { registry delete HKEY_CURRENT_USER\\TclFoobar registry set HKEY_CURRENT_USER\\TclFoobar\\baz registry set HKEY_CURRENT_USER\\TclFoobar\\blat registry set HKEY_CURRENT_USER\\TclFoobar\\foo set result [lsort [registry keys HKEY_CURRENT_USER\\TclFoobar b*]] registry delete HKEY_CURRENT_USER\\TclFoobar set result } {baz blat} test registry-4.6 {GetKeyNames: names with spaces} {pcOnly} { registry delete HKEY_CURRENT_USER\\TclFoobar registry set HKEY_CURRENT_USER\\TclFoobar\\baz\ bar registry set HKEY_CURRENT_USER\\TclFoobar\\blat registry set HKEY_CURRENT_USER\\TclFoobar\\foo set result [lsort [registry keys HKEY_CURRENT_USER\\TclFoobar b*]] registry delete HKEY_CURRENT_USER\\TclFoobar set result } {{baz bar} blat} test registry-4.7 {GetKeyNames: Unicode} {pcOnly english} { registry delete HKEY_CURRENT_USER\\TclFoobar registry set HKEY_CURRENT_USER\\TclFoobar\\baz\u00c7bar registry set HKEY_CURRENT_USER\\TclFoobar\\blat registry set HKEY_CURRENT_USER\\TclFoobar\\foo set result [lsort [registry keys HKEY_CURRENT_USER\\TclFoobar b*]] registry delete HKEY_CURRENT_USER\\TclFoobar set result } "baz\u00c7bar blat" test registry-4.8 {GetKeyNames: Unicode} {pcOnly} { registry delete HKEY_CURRENT_USER\\TclFoobar registry set HKEY_CURRENT_USER\\TclFoobar\\baz\u30b7bar registry set HKEY_CURRENT_USER\\TclFoobar\\blat registry set HKEY_CURRENT_USER\\TclFoobar\\foo set result [lsort [registry keys HKEY_CURRENT_USER\\TclFoobar b*]] registry delete HKEY_CURRENT_USER\\TclFoobar set result } "baz\u30b7bar blat" test registry-4.9 {GetKeyNames: very long key [Bug 1682211]} \ -constraints {pcOnly} \ -setup { registry set HKEY_CURRENT_USER\\TclFoobar\\a registry set HKEY_CURRENT_USER\\TclFoobar\\b[string repeat x 254] registry set HKEY_CURRENT_USER\\TclFoobar\\c } \ -body { lsort [registry keys HKEY_CURRENT_USER\\TclFoobar] } \ -cleanup { registry delete HKEY_CURRENT_USER\\TclFoobar } \ -result [list a b[string repeat x 254] c] test registry-5.1 {GetType} {pcOnly english} { registry delete HKEY_CURRENT_USER\\TclFoobar list [catch {registry type HKEY_CURRENT_USER\\TclFoobar val1} msg] $msg } {1 {unable to open key: The system cannot find the file specified.}} test registry-5.2 {GetType} {pcOnly english} { registry set HKEY_CURRENT_USER\\TclFoobar list [catch {registry type HKEY_CURRENT_USER\\TclFoobar val1} msg] $msg } {1 {unable to get type of value "val1" from key "HKEY_CURRENT_USER\TclFoobar": The system cannot find the file specified.}} test registry-5.3 {GetType} {pcOnly} { registry set HKEY_CURRENT_USER\\TclFoobar val1 foobar none set result [registry type HKEY_CURRENT_USER\\TclFoobar val1] registry delete HKEY_CURRENT_USER\\TclFoobar set result } none test registry-5.4 {GetType} {pcOnly} { registry set HKEY_CURRENT_USER\\TclFoobar val1 foobar set result [registry type HKEY_CURRENT_USER\\TclFoobar val1] registry delete HKEY_CURRENT_USER\\TclFoobar set result } sz test registry-5.5 {GetType} {pcOnly} { registry set HKEY_CURRENT_USER\\TclFoobar val1 foobar sz set result [registry type HKEY_CURRENT_USER\\TclFoobar val1] registry delete HKEY_CURRENT_USER\\TclFoobar set result } sz test registry-5.6 {GetType} {pcOnly} { registry set HKEY_CURRENT_USER\\TclFoobar val1 foobar expand_sz set result [registry type HKEY_CURRENT_USER\\TclFoobar val1] registry delete HKEY_CURRENT_USER\\TclFoobar set result } expand_sz test registry-5.7 {GetType} {pcOnly} { registry set HKEY_CURRENT_USER\\TclFoobar val1 1 binary set result [registry type HKEY_CURRENT_USER\\TclFoobar val1] registry delete HKEY_CURRENT_USER\\TclFoobar set result } binary test registry-5.8 {GetType} {pcOnly} { registry set HKEY_CURRENT_USER\\TclFoobar val1 1 dword set result [registry type HKEY_CURRENT_USER\\TclFoobar val1] registry delete HKEY_CURRENT_USER\\TclFoobar set result } dword test registry-5.9 {GetType} {pcOnly} { registry set HKEY_CURRENT_USER\\TclFoobar val1 1 dword_big_endian set result [registry type HKEY_CURRENT_USER\\TclFoobar val1] registry delete HKEY_CURRENT_USER\\TclFoobar set result } dword_big_endian test registry-5.10 {GetType} {pcOnly} { registry set HKEY_CURRENT_USER\\TclFoobar val1 1 link set result [registry type HKEY_CURRENT_USER\\TclFoobar val1] registry delete HKEY_CURRENT_USER\\TclFoobar set result } link test registry-5.11 {GetType} {pcOnly} { registry set HKEY_CURRENT_USER\\TclFoobar val1 foobar multi_sz set result [registry type HKEY_CURRENT_USER\\TclFoobar val1] registry delete HKEY_CURRENT_USER\\TclFoobar set result } multi_sz test registry-5.12 {GetType} {pcOnly} { registry set HKEY_CURRENT_USER\\TclFoobar val1 1 resource_list set result [registry type HKEY_CURRENT_USER\\TclFoobar val1] registry delete HKEY_CURRENT_USER\\TclFoobar set result } resource_list test registry-5.13 {GetType: unknown types} {pcOnly} { registry set HKEY_CURRENT_USER\\TclFoobar val1 1 24 set result [registry type HKEY_CURRENT_USER\\TclFoobar val1] registry delete HKEY_CURRENT_USER\\TclFoobar set result } 24 test registry-5.14 {GetType: Unicode} {pcOnly} { registry set HKEY_CURRENT_USER\\TclFoobar va\u00c7l1 1 24 set result [registry type HKEY_CURRENT_USER\\TclFoobar va\u00c7l1] registry delete HKEY_CURRENT_USER\\TclFoobar set result } 24 test registry-6.1 {GetValue} {pcOnly english} { registry delete HKEY_CURRENT_USER\\TclFoobar list [catch {registry get HKEY_CURRENT_USER\\TclFoobar val1} msg] $msg } {1 {unable to open key: The system cannot find the file specified.}} test registry-6.2 {GetValue} {pcOnly english} { registry set HKEY_CURRENT_USER\\TclFoobar list [catch {registry get HKEY_CURRENT_USER\\TclFoobar val1} msg] $msg } {1 {unable to get value "val1" from key "HKEY_CURRENT_USER\TclFoobar": The system cannot find the file specified.}} test registry-6.3 {GetValue} {pcOnly} { registry set HKEY_CURRENT_USER\\TclFoobar val1 foobar none set result [registry get HKEY_CURRENT_USER\\TclFoobar val1] registry delete HKEY_CURRENT_USER\\TclFoobar set result } foobar test registry-6.4 {GetValue} {pcOnly} { registry set HKEY_CURRENT_USER\\TclFoobar val1 foobar set result [registry get HKEY_CURRENT_USER\\TclFoobar val1] registry delete HKEY_CURRENT_USER\\TclFoobar set result } foobar test registry-6.5 {GetValue} {pcOnly} { registry set HKEY_CURRENT_USER\\TclFoobar val1 foobar sz set result [registry get HKEY_CURRENT_USER\\TclFoobar val1] registry delete HKEY_CURRENT_USER\\TclFoobar set result } foobar test registry-6.6 {GetValue} {pcOnly} { registry set HKEY_CURRENT_USER\\TclFoobar val1 foobar expand_sz set result [registry get HKEY_CURRENT_USER\\TclFoobar val1] registry delete HKEY_CURRENT_USER\\TclFoobar set result } foobar test registry-6.7 {GetValue} {pcOnly} { registry set HKEY_CURRENT_USER\\TclFoobar val1 1 binary set result [registry get HKEY_CURRENT_USER\\TclFoobar val1] registry delete HKEY_CURRENT_USER\\TclFoobar set result } 1 test registry-6.8 {GetValue} {pcOnly} { registry set HKEY_CURRENT_USER\\TclFoobar val1 0x20 dword set result [registry get HKEY_CURRENT_USER\\TclFoobar val1] registry delete HKEY_CURRENT_USER\\TclFoobar set result } 32 test registry-6.9 {GetValue} {pcOnly} { registry set HKEY_CURRENT_USER\\TclFoobar val1 0x20 dword_big_endian set result [registry get HKEY_CURRENT_USER\\TclFoobar val1] registry delete HKEY_CURRENT_USER\\TclFoobar set result } 32 test registry-6.10 {GetValue} {pcOnly} { registry set HKEY_CURRENT_USER\\TclFoobar val1 1 link set result [registry get HKEY_CURRENT_USER\\TclFoobar val1] registry delete HKEY_CURRENT_USER\\TclFoobar set result } 1 test registry-6.11 {GetValue} {pcOnly} { registry set HKEY_CURRENT_USER\\TclFoobar val1 foobar multi_sz set result [registry get HKEY_CURRENT_USER\\TclFoobar val1] registry delete HKEY_CURRENT_USER\\TclFoobar set result } foobar test registry-6.12 {GetValue} {pcOnly} { registry set HKEY_CURRENT_USER\\TclFoobar val1 {foo\ bar baz} multi_sz set result [registry get HKEY_CURRENT_USER\\TclFoobar val1] registry delete HKEY_CURRENT_USER\\TclFoobar set result } {{foo bar} baz} test registry-6.13 {GetValue} {pcOnly} { registry set HKEY_CURRENT_USER\\TclFoobar val1 {} multi_sz set result [registry get HKEY_CURRENT_USER\\TclFoobar val1] registry delete HKEY_CURRENT_USER\\TclFoobar set result } {} test registry-6.14 {GetValue: truncation of multivalues with null elements} \ {pcOnly} { registry set HKEY_CURRENT_USER\\TclFoobar val1 {a {} b} multi_sz set result [registry get HKEY_CURRENT_USER\\TclFoobar val1] registry delete HKEY_CURRENT_USER\\TclFoobar set result } a test registry-6.15 {GetValue} {pcOnly} { registry set HKEY_CURRENT_USER\\TclFoobar val1 1 resource_list set result [registry get HKEY_CURRENT_USER\\TclFoobar val1] registry delete HKEY_CURRENT_USER\\TclFoobar set result } 1 test registry-6.16 {GetValue: unknown types} {pcOnly} { registry set HKEY_CURRENT_USER\\TclFoobar val1 1 24 set result [registry get HKEY_CURRENT_USER\\TclFoobar val1] registry delete HKEY_CURRENT_USER\\TclFoobar set result } 1 test registry-6.17 {GetValue: Unicode value names} {pcOnly} { registry set HKEY_CURRENT_USER\\TclFoobar val\u00c71 foobar multi_sz set result [registry get HKEY_CURRENT_USER\\TclFoobar val\u00c71] registry delete HKEY_CURRENT_USER\\TclFoobar set result } foobar test registry-6.18 {GetValue: values with Unicode strings} {pcOnly} { registry set HKEY_CURRENT_USER\\TclFoobar val1 {foo ba\u30b7r baz} multi_sz set result [registry get HKEY_CURRENT_USER\\TclFoobar val1] registry delete HKEY_CURRENT_USER\\TclFoobar set result } "foo ba\u30b7r baz" test registry-6.19 {GetValue: values with Unicode strings} {pcOnly english} { registry set HKEY_CURRENT_USER\\TclFoobar val1 {foo ba\u00c7r baz} multi_sz set result [registry get HKEY_CURRENT_USER\\TclFoobar val1] registry delete HKEY_CURRENT_USER\\TclFoobar set result } "foo ba\u00c7r baz" test registry-6.20 {GetValue: values with Unicode strings with embedded nulls} {pcOnly} { registry set HKEY_CURRENT_USER\\TclFoobar val1 {foo ba\u0000r baz} multi_sz set result [registry get HKEY_CURRENT_USER\\TclFoobar val1] registry delete HKEY_CURRENT_USER\\TclFoobar set result } "foo ba r baz" test registry-7.1 {GetValueNames: bad key} {pcOnly english} { registry delete HKEY_CURRENT_USER\\TclFoobar list [catch {registry values HKEY_CURRENT_USER\\TclFoobar} msg] $msg } {1 {unable to open key: The system cannot find the file specified.}} test registry-7.2 {GetValueNames} {pcOnly} { registry delete HKEY_CURRENT_USER\\TclFoobar registry set HKEY_CURRENT_USER\\TclFoobar baz foobar set result [registry values HKEY_CURRENT_USER\\TclFoobar] registry delete HKEY_CURRENT_USER\\TclFoobar set result } baz test registry-7.3 {GetValueNames} {pcOnly} { registry delete HKEY_CURRENT_USER\\TclFoobar registry set HKEY_CURRENT_USER\\TclFoobar baz foobar1 registry set HKEY_CURRENT_USER\\TclFoobar blat foobar2 registry set HKEY_CURRENT_USER\\TclFoobar {} foobar3 set result [lsort [registry values HKEY_CURRENT_USER\\TclFoobar]] registry delete HKEY_CURRENT_USER\\TclFoobar set result } {{} baz blat} test registry-7.4 {GetValueNames: remote key} {pcOnly nonPortable english} { registry set \\\\$hostname\\HKEY_CURRENT_USER\\TclFoobar baz blat set result [registry values \\\\$hostname\\HKEY_CURRENT_USER\\TclFoobar] registry delete \\\\$hostname\\HKEY_CURRENT_USER\\TclFoobar set result } baz test registry-7.5 {GetValueNames: empty key} {pcOnly} { registry delete HKEY_CURRENT_USER\\TclFoobar registry set HKEY_CURRENT_USER\\TclFoobar set result [registry values HKEY_CURRENT_USER\\TclFoobar] registry delete HKEY_CURRENT_USER\\TclFoobar set result } {} test registry-7.6 {GetValueNames: patterns} {pcOnly} { registry delete HKEY_CURRENT_USER\\TclFoobar registry set HKEY_CURRENT_USER\\TclFoobar baz foobar1 registry set HKEY_CURRENT_USER\\TclFoobar blat foobar2 registry set HKEY_CURRENT_USER\\TclFoobar foo foobar3 set result [lsort [registry values HKEY_CURRENT_USER\\TclFoobar b*]] registry delete HKEY_CURRENT_USER\\TclFoobar set result } {baz blat} test registry-7.7 {GetValueNames: names with spaces} {pcOnly} { registry delete HKEY_CURRENT_USER\\TclFoobar registry set HKEY_CURRENT_USER\\TclFoobar baz\ bar foobar1 registry set HKEY_CURRENT_USER\\TclFoobar blat foobar2 registry set HKEY_CURRENT_USER\\TclFoobar foo foobar3 set result [lsort [registry values HKEY_CURRENT_USER\\TclFoobar b*]] registry delete HKEY_CURRENT_USER\\TclFoobar set result } {{baz bar} blat} test registry-8.1 {OpenSubKey} {pcOnly nonPortable english} { # This test will only succeed if the current user does not have registry # access on the specified machine. list [catch {registry keys {\\mom\HKEY_LOCAL_MACHINE}} msg] $msg } {1 {unable to open key: Access is denied.}} test registry-8.2 {OpenSubKey} {pcOnly} { registry delete HKEY_CURRENT_USER\\TclFoobar registry set HKEY_CURRENT_USER\\TclFoobar set result [registry keys HKEY_CURRENT_USER TclFoobar] registry delete HKEY_CURRENT_USER\\TclFoobar set result } TclFoobar test registry-8.3 {OpenSubKey} {pcOnly english} { registry delete HKEY_CURRENT_USER\\TclFoobar list [catch {registry keys HKEY_CURRENT_USER\\TclFoobar} msg] $msg } {1 {unable to open key: The system cannot find the file specified.}} test registry-9.1 {ParseKeyName: bad keys} {pcOnly} { list [catch {registry values \\} msg] $msg } "1 {bad key \"\\\": must start with a valid root}" test registry-9.2 {ParseKeyName: bad keys} {pcOnly} { list [catch {registry values \\foobar} msg] $msg } {1 {bad key "\foobar": must start with a valid root}} test registry-9.3 {ParseKeyName: bad keys} {pcOnly} { list [catch {registry values \\\\} msg] $msg } {1 {bad root name "": must be HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, HKEY_CURRENT_CONFIG, HKEY_PERFORMANCE_DATA, or HKEY_DYN_DATA}} test registry-9.4 {ParseKeyName: bad keys} {pcOnly} { list [catch {registry values \\\\\\} msg] $msg } {1 {bad root name "": must be HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, HKEY_CURRENT_CONFIG, HKEY_PERFORMANCE_DATA, or HKEY_DYN_DATA}} test registry-9.5 {ParseKeyName: bad keys} {pcOnly english} { list [catch {registry values \\\\\\HKEY_CLASSES_ROOT} msg] $msg } {1 {unable to open key: The network address is invalid.}} test registry-9.6 {ParseKeyName: bad keys} {pcOnly} { list [catch {registry values \\\\gaspode} msg] $msg } {1 {bad root name "": must be HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, HKEY_CURRENT_CONFIG, HKEY_PERFORMANCE_DATA, or HKEY_DYN_DATA}} test registry-9.7 {ParseKeyName: bad keys} {pcOnly} { list [catch {registry values foobar} msg] $msg } {1 {bad root name "foobar": must be HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, HKEY_CURRENT_CONFIG, HKEY_PERFORMANCE_DATA, or HKEY_DYN_DATA}} test registry-9.8 {ParseKeyName: null keys} {pcOnly} { list [catch {registry delete HKEY_CURRENT_USER\\} msg] $msg } {1 {bad key: cannot delete root keys}} test registry-9.9 {ParseKeyName: null keys} {pcOnly english} { list [catch {registry keys HKEY_CURRENT_USER\\TclFoobar\\baz} msg] $msg } {1 {unable to open key: The system cannot find the file specified.}} test registry-10.1 {RecursiveDeleteKey} {pcOnly} { registry delete HKEY_CURRENT_USER\\TclFoobar registry set HKEY_CURRENT_USER\\TclFoobar\\test1 registry set HKEY_CURRENT_USER\\TclFoobar\\test2\\test3 registry delete HKEY_CURRENT_USER\\TclFoobar set result [registry keys HKEY_CURRENT_USER TclFoobar] set result } {} test registry-10.2 {RecursiveDeleteKey} {pcOnly} { registry delete HKEY_CURRENT_USER\\TclFoobar registry set HKEY_CURRENT_USER\\TclFoobar\\test1 registry set HKEY_CURRENT_USER\\TclFoobar\\test2\\test3 set result [registry delete HKEY_CURRENT_USER\\TclFoobar\\test2\\test4] registry delete HKEY_CURRENT_USER\\TclFoobar set result } {} test registry-11.1 {SetValue: recursive creation} {pcOnly} { registry delete HKEY_CURRENT_USER\\TclFoobar registry set HKEY_CURRENT_USER\\TclFoobar\\baz blat foobar set result [registry get HKEY_CURRENT_USER\\TclFoobar\\baz blat] } foobar test registry-11.2 {SetValue: modification} {pcOnly} { registry delete HKEY_CURRENT_USER\\TclFoobar registry set HKEY_CURRENT_USER\\TclFoobar\\baz blat foobar registry set HKEY_CURRENT_USER\\TclFoobar\\baz blat frob set result [registry get HKEY_CURRENT_USER\\TclFoobar\\baz blat] } frob test registry-11.3 {SetValue: failure} {pcOnly nonPortable english} { # This test will only succeed if the current user does not have registry # access on the specified machine. list [catch {registry set {\\mom\HKEY_CURRENT_USER\TclFoobar} bar foobar} msg] $msg } {1 {unable to open key: Access is denied.}} test registry-12.1 {BroadcastValue} {pcOnly} { list [catch {registry broadcast} msg] $msg } {1 {wrong # args: should be "registry broadcast keyName ?-timeout millisecs?"}} test registry-12.2 {BroadcastValue} {pcOnly} { list [catch {registry broadcast "" -time} msg] $msg } {1 {wrong # args: should be "registry broadcast keyName ?-timeout millisecs?"}} test registry-12.3 {BroadcastValue} {pcOnly} { list [catch {registry broadcast "" - 500} msg] $msg } {1 {wrong # args: should be "registry broadcast keyName ?-timeout millisecs?"}} test registry-12.4 {BroadcastValue} {pcOnly} { list [catch {registry broadcast {Environment}} msg] $msg } {0 {1 0}} test registry-12.5 {BroadcastValue} {pcOnly} { list [catch {registry b {}} msg] $msg } {0 {1 0}} # cleanup unset hostname ::tcltest::cleanupTests return # Local Variables: # mode: tcl # tcl-indent-level: 4 # fill-column: 78 # End: tcl8.4.20/tests/lset.test0000644003604700454610000003175211737050674013741 0ustar dgp771div# This file is a -*- tcl -*- test script # Commands covered: lset # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 2001 by Kevin B. Kenny. All rights reserved. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } proc failTrace {name1 name2 op} { error "trace failed" } set lset lset set noRead {} trace add variable noRead read failTrace set noWrite {a b c} trace add variable noWrite write failTrace test lset-1.1 {lset, not compiled, arg count} { list [catch {eval $lset} msg] $msg } "1 {wrong \# args: should be \"lset listVar index ?index...? value\"}" test lset-1.2 {lset, not compiled, no such var} { list [catch {eval [list $lset noSuchVar 0 {}]} msg] $msg } "1 {can't read \"noSuchVar\": no such variable}" test lset-1.3 {lset, not compiled, var not readable} { list [catch {eval [list $lset noRead 0 {}]} msg] $msg } "1 {can't read \"noRead\": trace failed}" test lset-2.1 {lset, not compiled, 3 args, second arg a plain index} { set x {0 1 2} list [eval [list $lset x 0 3]] $x } {{3 1 2} {3 1 2}} test lset-2.2 {lset, not compiled, 3 args, second arg neither index nor list} { set x {0 1 2} list [catch { eval [list $lset x {{bad}1} 3] } msg] $msg } "1 {bad index \"{bad}1\": must be integer or end?-integer?}" test lset-3.1 {lset, not compiled, 3 args, data duplicated} { set x {0 1 2} list [eval [list $lset x 0 $x]] $x } {{{0 1 2} 1 2} {{0 1 2} 1 2}} test lset-3.2 {lset, not compiled, 3 args, data duplicated} { set x {0 1} set y $x list [eval [list $lset x 0 2]] $x $y } {{2 1} {2 1} {0 1}} test lset-3.3 {lset, not compiled, 3 args, data duplicated} { set x {0 1} set y $x list [eval [list $lset x 0 $x]] $x $y } {{{0 1} 1} {{0 1} 1} {0 1}} test lset-3.4 {lset, not compiled, 3 args, data duplicated} { set x {0 1 2} list [eval [list $lset x [list 0] $x]] $x } {{{0 1 2} 1 2} {{0 1 2} 1 2}} test lset-3.5 {lset, not compiled, 3 args, data duplicated} { set x {0 1} set y $x list [eval [list $lset x [list 0] 2]] $x $y } {{2 1} {2 1} {0 1}} test lset-3.6 {lset, not compiled, 3 args, data duplicated} { set x {0 1} set y $x list [eval [list $lset x [list 0] $x]] $x $y } {{{0 1} 1} {{0 1} 1} {0 1}} test lset-4.1 {lset, not compiled, 3 args, not a list} { set a "x \{" list [catch { eval [list $lset a [list 0] y] } msg] $msg } {1 {unmatched open brace in list}} test lset-4.2 {lset, not compiled, 3 args, bad index} { set a {x y z} list [catch { eval [list $lset a [list 2a2] w] } msg] $msg } {1 {bad index "2a2": must be integer or end?-integer?}} test lset-4.3 {lset, not compiled, 3 args, index out of range} { set a {x y z} list [catch { eval [list $lset a [list -1] w] } msg] $msg } {1 {list index out of range}} test lset-4.4 {lset, not compiled, 3 args, index out of range} { set a {x y z} list [catch { eval [list $lset a [list 3] w] } msg] $msg } {1 {list index out of range}} test lset-4.5 {lset, not compiled, 3 args, index out of range} { set a {x y z} list [catch { eval [list $lset a [list end--1] w] } msg] $msg } {1 {list index out of range}} test lset-4.6 {lset, not compiled, 3 args, index out of range} { set a {x y z} list [catch { eval [list $lset a [list end-3] w] } msg] $msg } {1 {list index out of range}} test lset-4.7 {lset, not compiled, 3 args, not a list} { set a "x \{" list [catch { eval [list $lset a 0 y] } msg] $msg } {1 {unmatched open brace in list}} test lset-4.8 {lset, not compiled, 3 args, bad index} { set a {x y z} list [catch { eval [list $lset a 2a2 w] } msg] $msg } {1 {bad index "2a2": must be integer or end?-integer?}} test lset-4.9 {lset, not compiled, 3 args, index out of range} { set a {x y z} list [catch { eval [list $lset a -1 w] } msg] $msg } {1 {list index out of range}} test lset-4.10 {lset, not compiled, 3 args, index out of range} { set a {x y z} list [catch { eval [list $lset a 3 w] } msg] $msg } {1 {list index out of range}} test lset-4.11 {lset, not compiled, 3 args, index out of range} { set a {x y z} list [catch { eval [list $lset a end--1 w] } msg] $msg } {1 {list index out of range}} test lset-4.12 {lset, not compiled, 3 args, index out of range} { set a {x y z} list [catch { eval [list $lset a end-3 w] } msg] $msg } {1 {list index out of range}} test lset-5.1 {lset, not compiled, 3 args, can't set variable} { list [catch { eval [list $lset noWrite 0 d] } msg] $msg $noWrite } {1 {can't set "noWrite": trace failed} {d b c}} test lset-5.2 {lset, not compiled, 3 args, can't set variable} { list [catch { eval [list $lset noWrite [list 0] d] } msg] $msg $noWrite } {1 {can't set "noWrite": trace failed} {d b c}} test lset-6.1 {lset, not compiled, 3 args, 1-d list basics} { set a {x y z} list [eval [list $lset a 0 a]] $a } {{a y z} {a y z}} test lset-6.2 {lset, not compiled, 3 args, 1-d list basics} { set a {x y z} list [eval [list $lset a [list 0] a]] $a } {{a y z} {a y z}} test lset-6.3 {lset, not compiled, 1-d list basics} { set a {x y z} list [eval [list $lset a 2 a]] $a } {{x y a} {x y a}} test lset-6.4 {lset, not compiled, 1-d list basics} { set a {x y z} list [eval [list $lset a [list 2] a]] $a } {{x y a} {x y a}} test lset-6.5 {lset, not compiled, 1-d list basics} { set a {x y z} list [eval [list $lset a end a]] $a } {{x y a} {x y a}} test lset-6.6 {lset, not compiled, 1-d list basics} { set a {x y z} list [eval [list $lset a [list end] a]] $a } {{x y a} {x y a}} test lset-6.7 {lset, not compiled, 1-d list basics} { set a {x y z} list [eval [list $lset a end-0 a]] $a } {{x y a} {x y a}} test lset-6.8 {lset, not compiled, 1-d list basics} { set a {x y z} list [eval [list $lset a [list end-0] a]] $a } {{x y a} {x y a}} test lset-6.9 {lset, not compiled, 1-d list basics} { set a {x y z} list [eval [list $lset a end-2 a]] $a } {{a y z} {a y z}} test lset-6.10 {lset, not compiled, 1-d list basics} { set a {x y z} list [eval [list $lset a [list end-2] a]] $a } {{a y z} {a y z}} test lset-7.1 {lset, not compiled, data sharing} { set a 0 list [eval [list $lset a $a {gag me}]] $a } {{{gag me}} {{gag me}}} test lset-7.2 {lset, not compiled, data sharing} { set a [list 0] list [eval [list $lset a $a {gag me}]] $a } {{{gag me}} {{gag me}}} test lset-7.3 {lset, not compiled, data sharing} { set a {x y} list [eval [list $lset a 0 $a]] $a } {{{x y} y} {{x y} y}} test lset-7.4 {lset, not compiled, data sharing} { set a {x y} list [eval [list $lset a [list 0] $a]] $a } {{{x y} y} {{x y} y}} test lset-7.5 {lset, not compiled, data sharing} { set n 0 set a {x y} list [eval [list $lset a $n $n]] $a $n } {{0 y} {0 y} 0} test lset-7.6 {lset, not compiled, data sharing} { set n [list 0] set a {x y} list [eval [list $lset a $n $n]] $a $n } {{0 y} {0 y} 0} test lset-7.7 {lset, not compiled, data sharing} { set n 0 set a [list $n $n] list [eval [list $lset a $n 1]] $a $n } {{1 0} {1 0} 0} test lset-7.8 {lset, not compiled, data sharing} { set n [list 0] set a [list $n $n] list [eval [list $lset a $n 1]] $a $n } {{1 0} {1 0} 0} test lset-7.9 {lset, not compiled, data sharing} { set a 0 list [eval [list $lset a $a $a]] $a } {0 0} test lset-7.10 {lset, not compiled, data sharing} { set a [list 0] list [eval [list $lset a $a $a]] $a } {0 0} test lset-8.1 {lset, not compiled, malformed sublist} { set a [list "a \{" b] list [catch {eval [list $lset a 0 1 c]} msg] $msg } {1 {unmatched open brace in list}} test lset-8.2 {lset, not compiled, malformed sublist} { set a [list "a \{" b] list [catch {eval [list $lset a {0 1} c]} msg] $msg } {1 {unmatched open brace in list}} test lset-8.3 {lset, not compiled, bad second index} { set a {{b c} {d e}} list [catch {eval [list $lset a 0 2a2 f]} msg] $msg } {1 {bad index "2a2": must be integer or end?-integer?}} test lset-8.4 {lset, not compiled, bad second index} { set a {{b c} {d e}} list [catch {eval [list $lset a {0 2a2} f]} msg] $msg } {1 {bad index "2a2": must be integer or end?-integer?}} test lset-8.5 {lset, not compiled, second index out of range} { set a {{b c} {d e} {f g}} list [catch {eval [list $lset a 2 -1 h]} msg] $msg } {1 {list index out of range}} test lset-8.6 {lset, not compiled, second index out of range} { set a {{b c} {d e} {f g}} list [catch {eval [list $lset a {2 -1} h]} msg] $msg } {1 {list index out of range}} test lset-8.7 {lset, not compiled, second index out of range} { set a {{b c} {d e} {f g}} list [catch {eval [list $lset a 2 2 h]} msg] $msg } {1 {list index out of range}} test lset-8.8 {lset, not compiled, second index out of range} { set a {{b c} {d e} {f g}} list [catch {eval [list $lset a {2 2} h]} msg] $msg } {1 {list index out of range}} test lset-8.9 {lset, not compiled, second index out of range} { set a {{b c} {d e} {f g}} list [catch {eval [list $lset a 2 end--1 h]} msg] $msg } {1 {list index out of range}} test lset-8.10 {lset, not compiled, second index out of range} { set a {{b c} {d e} {f g}} list [catch {eval [list $lset a {2 end--1} h]} msg] $msg } {1 {list index out of range}} test lset-8.11 {lset, not compiled, second index out of range} { set a {{b c} {d e} {f g}} list [catch {eval [list $lset a 2 end-2 h]} msg] $msg } {1 {list index out of range}} test lset-8.12 {lset, not compiled, second index out of range} { set a {{b c} {d e} {f g}} list [catch {eval [list $lset a {2 end-2} h]} msg] $msg } {1 {list index out of range}} test lset-9.1 {lset, not compiled, entire variable} { set a x list [eval [list $lset a y]] $a } {y y} test lset-9.2 {lset, not compiled, entire variable} { set a x list [eval [list $lset a {} y]] $a } {y y} test lset-10.1 {lset, not compiled, shared data} { set row {p q} set a [list $row $row] list [eval [list $lset a 0 0 x]] $a } {{{x q} {p q}} {{x q} {p q}}} test lset-10.2 {lset, not compiled, shared data} { set row {p q} set a [list $row $row] list [eval [list $lset a {0 0} x]] $a } {{{x q} {p q}} {{x q} {p q}}} test lset-11.1 {lset, not compiled, 2-d basics} { set a {{b c} {d e}} list [eval [list $lset a 0 0 f]] $a } {{{f c} {d e}} {{f c} {d e}}} test lset-11.2 {lset, not compiled, 2-d basics} { set a {{b c} {d e}} list [eval [list $lset a {0 0} f]] $a } {{{f c} {d e}} {{f c} {d e}}} test lset-11.3 {lset, not compiled, 2-d basics} { set a {{b c} {d e}} list [eval [list $lset a 0 1 f]] $a } {{{b f} {d e}} {{b f} {d e}}} test lset-11.4 {lset, not compiled, 2-d basics} { set a {{b c} {d e}} list [eval [list $lset a {0 1} f]] $a } {{{b f} {d e}} {{b f} {d e}}} test lset-11.5 {lset, not compiled, 2-d basics} { set a {{b c} {d e}} list [eval [list $lset a 1 0 f]] $a } {{{b c} {f e}} {{b c} {f e}}} test lset-11.6 {lset, not compiled, 2-d basics} { set a {{b c} {d e}} list [eval [list $lset a {1 0} f]] $a } {{{b c} {f e}} {{b c} {f e}}} test lset-11.7 {lset, not compiled, 2-d basics} { set a {{b c} {d e}} list [eval [list $lset a 1 1 f]] $a } {{{b c} {d f}} {{b c} {d f}}} test lset-11.8 {lset, not compiled, 2-d basics} { set a {{b c} {d e}} list [eval [list $lset a {1 1} f]] $a } {{{b c} {d f}} {{b c} {d f}}} test lset-12.0 {lset, not compiled, typical sharing pattern} { set zero 0 set row [list $zero $zero $zero $zero] set ident [list $row $row $row $row] for { set i 0 } { $i < 4 } { incr i } { eval [list $lset ident $i $i 1] } set ident } {{1 0 0 0} {0 1 0 0} {0 0 1 0} {0 0 0 1}} test lset-13.0 {lset, not compiled, shimmering hell} { set a 0 list [eval [list $lset a $a $a $a $a {gag me}]] $a } {{{{{{gag me}}}}} {{{{{gag me}}}}}} test lset-13.1 {lset, not compiled, shimmering hell} { set a [list 0] list [eval [list $lset a $a $a $a $a {gag me}]] $a } {{{{{{gag me}}}}} {{{{{gag me}}}}}} test lset-13.2 {lset, not compiled, shimmering hell} { set a [list 0 0 0 0] list [eval [list $lset a $a {gag me}]] $a } {{{{{{gag me}}}} 0 0 0} {{{{{gag me}}}} 0 0 0}} test lset-14.1 {lset, not compiled, list args, is string rep preserved?} { set a { { 1 2 } { 3 4 } } catch { eval [list $lset a {1 5} 5] } list $a [lindex $a 1] } "{ { 1 2 } { 3 4 } } { 3 4 }" test lset-14.2 {lset, not compiled, flat args, is string rep preserved?} { set a { { 1 2 } { 3 4 } } catch { eval [list $lset a 1 5 5] } list $a [lindex $a 1] } "{ { 1 2 } { 3 4 } } { 3 4 }" catch {unset noRead} catch {unset noWrite} catch {rename failTrace {}} catch {unset ::x} catch {unset ::y} # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/concat.test0000644003604700454610000000302311737050674014227 0ustar dgp771div# Commands covered: concat # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994-1996 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } test concat-1.1 {simple concatenation} { concat a b c d e f g } {a b c d e f g} test concat-1.2 {merging lists together} { concat a {b c d} {e f g h} } {a b c d e f g h} test concat-1.3 {merge lists, retain sub-lists} { concat a {b {c d}} {{e f}} g h } {a b {c d} {e f} g h} test concat-1.4 {special characters} { concat a\{ {b \{c d} \{d } "a{ b \\{c d {d" test concat-2.1 {error: one empty argument} { concat {} } {} test concat-3.1 {error: no arguments} { list [catch concat msg] $msg } {0 {}} test concat-4.1 {pruning off extra white space} { concat {} {a b c} } {a b c} test concat-4.2 {pruning off extra white space} { concat x y " a b c \n\t " " " " def " } {x y a b c def} test concat-4.3 {pruning off extra white space sets length correctly} { llength [concat { {{a}} }] } 1 # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/pwd.test0000644003604700454610000000147311737050674013561 0ustar dgp771div# Commands covered: pwd # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994-1997 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } test pwd-1.1 {simple pwd} { catch pwd } 0 test pwd-1.2 {simple pwd} { expr [string length pwd]>0 } 1 # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/scan.test0000644003604700454610000005724611737050674013724 0ustar dgp771div# Commands covered: scan # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1994 The Regents of the University of California. # Copyright (c) 1994-1997 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import -force ::tcltest::* } ::tcltest::testConstraint 64bitInts [expr {0x80000000 > 0}] test scan-1.1 {BuildCharSet, CharInSet} { list [scan foo {%[^o]} x] $x } {1 f} test scan-1.2 {BuildCharSet, CharInSet} { list [scan \]foo {%[]f]} x] $x } {1 \]f} test scan-1.3 {BuildCharSet, CharInSet} { list [scan abc-def {%[a-c]} x] $x } {1 abc} test scan-1.4 {BuildCharSet, CharInSet} { list [scan abc-def {%[a-c]} x] $x } {1 abc} test scan-1.5 {BuildCharSet, CharInSet} { list [scan -abc-def {%[-ac]} x] $x } {1 -a} test scan-1.6 {BuildCharSet, CharInSet} { list [scan -abc-def {%[ac-]} x] $x } {1 -a} test scan-1.7 {BuildCharSet, CharInSet} { list [scan abc-def {%[c-a]} x] $x } {1 abc} test scan-1.8 {BuildCharSet, CharInSet} { list [scan def-abc {%[^c-a]} x] $x } {1 def-} test scan-1.9 {BuildCharSet, CharInSet no match} { catch {unset x} list [scan {= f} {= %[TF]} x] [info exists x] } {0 0} test scan-2.1 {ReleaseCharSet} { list [scan abcde {%[abc]} x] $x } {1 abc} test scan-2.2 {ReleaseCharSet} { list [scan abcde {%[a-c]} x] $x } {1 abc} test scan-3.1 {ValidateFormat} { list [catch {scan {} {%d%1$d} x} msg] $msg } {1 {cannot mix "%" and "%n$" conversion specifiers}} test scan-3.2 {ValidateFormat} { list [catch {scan {} {%d%1$d} x} msg] $msg } {1 {cannot mix "%" and "%n$" conversion specifiers}} test scan-3.3 {ValidateFormat} { list [catch {scan {} {%2$d%d} x} msg] $msg } {1 {"%n$" argument index out of range}} test scan-3.4 {ValidateFormat} { # degenerate case, before changed from 8.2 to 8.3 list [catch {scan {} %d} msg] $msg } {0 {}} test scan-3.5 {ValidateFormat} { list [catch {scan {} {%10c} a} msg] $msg } {1 {field width may not be specified in %c conversion}} test scan-3.6 {ValidateFormat} { list [catch {scan {} {%*1$d} a} msg] $msg } {1 {bad scan conversion character "$"}} test scan-3.7 {ValidateFormat} { list [catch {scan {} {%1$d%1$d} a} msg] $msg } {1 {variable is assigned by multiple "%n$" conversion specifiers}} test scan-3.8 {ValidateFormat} { list [catch {scan {} a x} msg] $msg } {1 {variable is not assigned by any conversion specifiers}} test scan-3.9 {ValidateFormat} { list [catch {scan {} {%2$s} x y} msg] $msg } {1 {variable is not assigned by any conversion specifiers}} test scan-3.10 {ValidateFormat} { list [catch {scan {} {%[a} x} msg] $msg } {1 {unmatched [ in format string}} test scan-3.11 {ValidateFormat} { list [catch {scan {} {%[^a} x} msg] $msg } {1 {unmatched [ in format string}} test scan-3.12 {ValidateFormat} { list [catch {scan {} {%[]a} x} msg] $msg } {1 {unmatched [ in format string}} test scan-3.13 {ValidateFormat} { list [catch {scan {} {%[^]a} x} msg] $msg } {1 {unmatched [ in format string}} test scan-4.1 {Tcl_ScanObjCmd, argument checks} { list [catch {scan} msg] $msg } {1 {wrong # args: should be "scan string format ?varName varName ...?"}} test scan-4.2 {Tcl_ScanObjCmd, argument checks} { list [catch {scan string} msg] $msg } {1 {wrong # args: should be "scan string format ?varName varName ...?"}} test scan-4.3 {Tcl_ScanObjCmd, argument checks} { # degenerate case, before changed from 8.2 to 8.3 list [catch {scan string format} msg] $msg } {0 {}} test scan-4.4 {Tcl_ScanObjCmd, whitespace} { list [scan { abc def } {%s%s} x y] $x $y } {2 abc def} test scan-4.5 {Tcl_ScanObjCmd, whitespace} { list [scan { abc def } { %s %s } x y] $x $y } {2 abc def} test scan-4.6 {Tcl_ScanObjCmd, whitespace} { list [scan { abc def } { %s %s } x y] $x $y } {2 abc def} test scan-4.7 {Tcl_ScanObjCmd, literals} { # degenerate case, before changed from 8.2 to 8.3 scan { abc def } { abc def } } {} test scan-4.8 {Tcl_ScanObjCmd, literals} { set x {} list [scan { abcg} { abc def %1s} x] $x } {0 {}} test scan-4.9 {Tcl_ScanObjCmd, literals} { list [scan { abc%defghi} { abc %% def%n } x] $x } {1 10} test scan-4.10 {Tcl_ScanObjCmd, assignment suppression} { list [scan { abc def } { %*c%s def } x] $x } {1 bc} test scan-4.11 {Tcl_ScanObjCmd, XPG3-style} { list [scan { abc def } {%2$s %1$s} x y] $x $y } {2 def abc} test scan-4.12 {Tcl_ScanObjCmd, width specifiers} { list [scan {abc123456789012} {%3s%3d%3f%3[0-9]%s} a b c d e] $a $b $c $d $e } {5 abc 123 456.0 789 012} test scan-4.13 {Tcl_ScanObjCmd, width specifiers} { list [scan {abc123456789012} {%3s%3d%3f%3[0-9]%s} a b c d e] $a $b $c $d $e } {5 abc 123 456.0 789 012} test scan-4.14 {Tcl_ScanObjCmd, underflow} { set x {} list [scan {a} {a%d} x] $x } {-1 {}} test scan-4.15 {Tcl_ScanObjCmd, underflow} { set x {} list [scan {} {a%d} x] $x } {-1 {}} test scan-4.16 {Tcl_ScanObjCmd, underflow} { set x {} list [scan {ab} {a%d} x] $x } {0 {}} test scan-4.17 {Tcl_ScanObjCmd, underflow} { set x {} list [scan {a } {a%d} x] $x } {-1 {}} test scan-4.18 {Tcl_ScanObjCmd, skipping whitespace} { list [scan { b} {%c%s} x y] $x $y } {2 32 b} test scan-4.19 {Tcl_ScanObjCmd, skipping whitespace} { list [scan { b} {%[^b]%s} x y] $x $y } {2 { } b} test scan-4.20 {Tcl_ScanObjCmd, string scanning} { list [scan {abc def} {%s} x] $x } {1 abc} test scan-4.21 {Tcl_ScanObjCmd, string scanning} { list [scan {abc def} {%0s} x] $x } {1 abc} test scan-4.22 {Tcl_ScanObjCmd, string scanning} { list [scan {abc def} {%2s} x] $x } {1 ab} test scan-4.23 {Tcl_ScanObjCmd, string scanning} { list [scan {abc def} {%*s%n} x] $x } {1 3} test scan-4.24 {Tcl_ScanObjCmd, charset scanning} { list [scan {abcdef} {%[a-c]} x] $x } {1 abc} test scan-4.25 {Tcl_ScanObjCmd, charset scanning} { list [scan {abcdef} {%0[a-c]} x] $x } {1 abc} test scan-4.26 {Tcl_ScanObjCmd, charset scanning} { list [scan {abcdef} {%2[a-c]} x] $x } {1 ab} test scan-4.27 {Tcl_ScanObjCmd, charset scanning} { list [scan {abcdef} {%*[a-c]%n} x] $x } {1 3} test scan-4.28 {Tcl_ScanObjCmd, character scanning} { list [scan {abcdef} {%c} x] $x } {1 97} test scan-4.29 {Tcl_ScanObjCmd, character scanning} { list [scan {abcdef} {%*c%n} x] $x } {1 1} test scan-4.30 {Tcl_ScanObjCmd, base-10 integer scanning} { set x {} list [scan {1234567890a} {%3d} x] $x } {1 123} test scan-4.31 {Tcl_ScanObjCmd, base-10 integer scanning} { set x {} list [scan {1234567890a} {%d} x] $x } {1 1234567890} test scan-4.32 {Tcl_ScanObjCmd, base-10 integer scanning} { set x {} list [scan {01234567890a} {%d} x] $x } {1 1234567890} test scan-4.33 {Tcl_ScanObjCmd, base-10 integer scanning} { set x {} list [scan {+01234} {%d} x] $x } {1 1234} test scan-4.34 {Tcl_ScanObjCmd, base-10 integer scanning} { set x {} list [scan {-01234} {%d} x] $x } {1 -1234} test scan-4.35 {Tcl_ScanObjCmd, base-10 integer scanning} { set x {} list [scan {a01234} {%d} x] $x } {0 {}} test scan-4.36 {Tcl_ScanObjCmd, base-10 integer scanning} { set x {} list [scan {0x10} {%d} x] $x } {1 0} test scan-4.37 {Tcl_ScanObjCmd, base-8 integer scanning} { set x {} list [scan {012345678} {%o} x] $x } {1 342391} test scan-4.38 {Tcl_ScanObjCmd, base-8 integer scanning} { set x {} list [scan {+1238 -1239 123a} {%o%*s%o%*s%o} x y z] $x $y $z } {3 83 -83 83} test scan-4.39 {Tcl_ScanObjCmd, base-16 integer scanning} { set x {} list [scan {+1238 -123a 0123} {%x%x%x} x y z] $x $y $z } {3 4664 -4666 291} test scan-4.40 {Tcl_ScanObjCmd, base-16 integer scanning} { # The behavior changed in 8.4a4/8.3.4cvs (6 Feb) to correctly # return '1' for 0x1 scanned via %x, to comply with 8.0 and C scanf. # Bug #495213 set x {} list [scan {aBcDeF AbCdEf 0x1} {%x%x%x} x y z] $x $y $z } {3 11259375 11259375 1} test scan-4.40.1 {Tcl_ScanObjCmd, base-16 integer scanning} { set x {} list [scan {0xF 0x00A0B 0X0XF} {%x %x %x} x y z] $x $y $z } {3 15 2571 0} test scan-4.40.2 {Tcl_ScanObjCmd, base-16 integer scanning} { catch {unset x} list [scan {xF} {%x} x] [info exists x] } {0 0} test scan-4.41 {Tcl_ScanObjCmd, base-unknown integer scanning} { set x {} list [scan {10 010 0x10} {%i%i%i} x y z] $x $y $z } {3 10 8 16} test scan-4.42 {Tcl_ScanObjCmd, base-unknown integer scanning} { set x {} list [scan {10 010 0X10} {%i%i%i} x y z] $x $y $z } {3 10 8 16} test scan-4.43 {Tcl_ScanObjCmd, integer scanning, odd cases} { set x {} list [scan {+ } {%i} x] $x } {0 {}} test scan-4.44 {Tcl_ScanObjCmd, integer scanning, odd cases} { set x {} list [scan {+} {%i} x] $x } {-1 {}} test scan-4.45 {Tcl_ScanObjCmd, integer scanning, odd cases} { set x {} list [scan {0x} {%i%s} x y] $x $y } {2 0 x} test scan-4.46 {Tcl_ScanObjCmd, integer scanning, odd cases} { set x {} list [scan {0X} {%i%s} x y] $x $y } {2 0 X} test scan-4.47 {Tcl_ScanObjCmd, integer scanning, suppressed} { set x {} list [scan {123def} {%*i%s} x] $x } {1 def} test scan-4.48 {Tcl_ScanObjCmd, float scanning} { list [scan {1 2 3} {%e %f %g} x y z] $x $y $z } {3 1.0 2.0 3.0} test scan-4.49 {Tcl_ScanObjCmd, float scanning} { list [scan {.1 0.2 3.} {%e %f %g} x y z] $x $y $z } {3 0.1 0.2 3.0} test scan-4.50 {Tcl_ScanObjCmd, float scanning} { list [scan {1234567890a} %f x] $x } {1 1234567890.0} test scan-4.51 {Tcl_ScanObjCmd, float scanning} { list [scan {+123+45} %f x] $x } {1 123.0} test scan-4.52 {Tcl_ScanObjCmd, float scanning} { list [scan {-123+45} %f x] $x } {1 -123.0} test scan-4.53 {Tcl_ScanObjCmd, float scanning} { list [scan {1.0e1} %f x] $x } {1 10.0} test scan-4.54 {Tcl_ScanObjCmd, float scanning} { list [scan {1.0e-1} %f x] $x } {1 0.1} test scan-4.55 {Tcl_ScanObjCmd, odd cases} { set x {} list [scan {+} %f x] $x } {-1 {}} test scan-4.56 {Tcl_ScanObjCmd, odd cases} { set x {} list [scan {1.0e} %f%s x y] $x $y } {2 1.0 e} test scan-4.57 {Tcl_ScanObjCmd, odd cases} { set x {} list [scan {1.0e+} %f%s x y] $x $y } {2 1.0 e+} test scan-4.58 {Tcl_ScanObjCmd, odd cases} { set x {} set y {} list [scan {e1} %f%s x y] $x $y } {0 {} {}} test scan-4.59 {Tcl_ScanObjCmd, float scanning} { list [scan {1.0e-1x} %*f%n x] $x } {1 6} test scan-4.60 {Tcl_ScanObjCmd, set errors} { set x {} set y {} catch {unset z}; array set z {} set result [list [catch {scan {abc def ghi} {%s%s%s} x z y} msg] \ $msg $x $y] unset z set result } {1 {couldn't set variable "z"} abc ghi} test scan-4.61 {Tcl_ScanObjCmd, set errors} { set x {} catch {unset y}; array set y {} catch {unset z}; array set z {} set result [list [catch {scan {abc def ghi} {%s%s%s} x z y} msg] \ $msg $x] unset y unset z set result } {1 {couldn't set variable "z"couldn't set variable "y"} abc} # procedure that returns the range of integers proc int_range {} { for { set MIN_INT 1 } { $MIN_INT > 0 } {} { set MIN_INT [expr { $MIN_INT << 1 }] } set MAX_INT [expr { ~ $MIN_INT }] return [list $MIN_INT $MAX_INT] } test scan-4.62 {scanning of large and negative octal integers} { foreach { MIN_INT MAX_INT } [int_range] {} set scanstring [format {%o %o %o} -1 $MIN_INT $MAX_INT] list [scan $scanstring {%o %o %o} a b c] \ [expr { $a == -1 }] [expr { $b == $MIN_INT }] [expr { $c == $MAX_INT }] } {3 1 1 1} test scan-4.63 {scanning of large and negative hex integers} { foreach { MIN_INT MAX_INT } [int_range] {} set scanstring [format {%x %x %x} -1 $MIN_INT $MAX_INT] list [scan $scanstring {%x %x %x} a b c] \ [expr { $a == -1 }] [expr { $b == $MIN_INT }] [expr { $c == $MAX_INT }] } {3 1 1 1} # clean up from last two tests catch { rename int_range {} } test scan-5.1 {integer scanning} { set a {}; set b {}; set c {}; set d {} list [scan "-20 1476 \n33 0" "%d %d %d %d" a b c d] $a $b $c $d } {4 -20 1476 33 0} test scan-5.2 {integer scanning} { set a {}; set b {}; set c {} list [scan "-45 16 7890 +10" "%2d %*d %10d %d" a b c] $a $b $c } {3 -4 16 7890} test scan-5.3 {integer scanning} { set a {}; set b {}; set c {}; set d {} list [scan "-45 16 +10 987" "%ld %d %ld %d" a b c d] $a $b $c $d } {4 -45 16 10 987} test scan-5.4 {integer scanning} { set a {}; set b {}; set c {}; set d {} list [scan "14 1ab 62 10" "%d %x %lo %x" a b c d] $a $b $c $d } {4 14 427 50 16} test scan-5.5 {integer scanning} { set a {}; set b {}; set c {}; set d {} list [scan "12345670 1234567890ab cdefg" "%o %o %x %lx" a b c d] \ $a $b $c $d } {4 2739128 342391 561323 52719} test scan-5.6 {integer scanning} { set a {}; set b {}; set c {}; set d {} list [scan "ab123-24642" "%2x %3x %3o %2o" a b c d] $a $b $c $d } {4 171 291 -20 52} test scan-5.7 {integer scanning} { set a {}; set b {} list [scan "1234567 234 567 " "%*3x %x %*o %4o" a b] $a $b } {2 17767 375} test scan-5.8 {integer scanning} { set a {}; set b {} list [scan "a 1234" "%d %d" a b] $a $b } {0 {} {}} test scan-5.9 {integer scanning} { set a {}; set b {}; set c {}; set d {}; list [scan "12345678" "%2d %2d %2ld %2d" a b c d] $a $b $c $d } {4 12 34 56 78} test scan-5.10 {integer scanning} { set a {}; set b {}; set c {}; set d {} list [scan "1 2 " "%hd %d %d %d" a b c d] $a $b $c $d } {2 1 2 {} {}} # # The behavior for scaning intergers larger than MAX_INT is # not defined by the ANSI spec. Some implementations wrap the # input (-16) some return MAX_INT. # test scan-5.11 {integer scanning} {nonPortable} { set a {}; set b {}; list [scan "4294967280 4294967280" "%u %d" a b] $a \ [expr {$b == -16 || $b == 0x7fffffff}] } {2 4294967280 1} test scan-5.12 {integer scanning} {64bitInts} { set a {}; set b {}; set c {} list [scan "7810179016327718216,6c63546f6c6c6548,661432506755433062510" \ %ld,%lx,%lo a b c] $a $b $c } {3 7810179016327718216 7810179016327718216 7810179016327718216} test scan-5.13 {integer scanning and overflow} { # This test used to fail on some 64-bit systems. [Bug 1011860] scan {300000000 3000000000 30000000000} {%ld %ld %ld} } {300000000 3000000000 30000000000} test scan-6.1 {floating-point scanning} { set a {}; set b {}; set c {}; set d {} list [scan "2.1 -3.0e8 .99962 a" "%f%g%e%f" a b c d] $a $b $c $d } {3 2.1 -300000000.0 0.99962 {}} test scan-6.2 {floating-point scanning} { set a {}; set b {}; set c {}; set d {} list [scan "-1.2345 +8.2 9" "%3e %3lf %f %f" a b c d] $a $b $c $d } {4 -1.0 234.0 5.0 8.2} test scan-6.3 {floating-point scanning} { set a {}; set b {}; set c {} list [scan "1e00004 332E-4 3e+4" "%Lf %*2e %f %f" a b c] $a $c } {3 10000.0 30000.0} # # Some libc implementations consider 3.e- bad input. The ANSI # spec states that digits must follow the - sign. # test scan-6.4 {floating-point scanning} { set a {}; set b {}; set c {} list [scan "1. 47.6 2.e2 3.e-" "%f %*f %f %f" a b c] $a $b $c } {3 1.0 200.0 3.0} test scan-6.5 {floating-point scanning} { set a {}; set b {}; set c {}; set d {} list [scan "4.6 99999.7 876.43e-1 118" "%f %f %f %e" a b c d] $a $b $c $d } {4 4.6 99999.7 87.643 118.0} test scan-6.6 {floating-point scanning} {eformat} { set a {}; set b {}; set c {}; set d {} list [scan "1.2345 697.0e-3 124 .00005" "%f %e %f %e" a b c d] $a $b $c $d } {4 1.2345 0.697 124.0 5e-05} test scan-6.7 {floating-point scanning} { set a {}; set b {}; set c {}; set d {} list [scan "4.6abc" "%f %f %f %f" a b c d] $a $b $c $d } {1 4.6 {} {} {}} test scan-6.8 {floating-point scanning} { set a {}; set b {}; set c {}; set d {} list [scan "4.6 5.2" "%f %f %f %f" a b c d] $a $b $c $d } {2 4.6 5.2 {} {}} test scan-7.1 {string and character scanning} { set a {}; set b {}; set c {}; set d {} list [scan "abc defghijk dum " "%s %3s %20s %s" a b c d] $a $b $c $d } {4 abc def ghijk dum} test scan-7.2 {string and character scanning} { set a {}; set b {}; set c {}; set d {} list [scan "a bcdef" "%c%c%1s %s" a b c d] $a $b $c $d } {4 97 32 b cdef} test scan-7.3 {string and character scanning} { set a {}; set b {}; set c {} list [scan "123456 test " "%*c%*s %s %s %s" a b c] $a $b $c } {1 test {} {}} test scan-7.4 {string and character scanning} { set a {}; set b {}; set c {}; set d list [scan "ababcd01234 f 123450" {%4[abcd] %4[abcd] %[^abcdef] %[^0]} a b c d] $a $b $c $d } {4 abab cd {01234 } {f 12345}} test scan-7.5 {string and character scanning} { set a {}; set b {}; set c {} list [scan "aaaaaabc aaabcdefg + + XYZQR" {%*4[a] %s %*4[a]%s%*4[ +]%c} a b c] $a $b $c } {3 aabc bcdefg 43} test scan-7.6 {string and character scanning, unicode} { set a {}; set b {}; set c {}; set d {} list [scan "abc d\u00c7fghijk dum " "%s %3s %20s %s" a b c d] $a $b $c $d } "4 abc d\u00c7f ghijk dum" test scan-7.7 {string and character scanning, unicode} { set a {}; set b {} list [scan "ab\u00c7cdef" "ab%c%c" a b] $a $b } "2 199 99" test scan-7.8 {string and character scanning, unicode} { set a {}; set b {} list [scan "ab\ufeffdef" "%\[ab\ufeff\]" a] $a } "1 ab\ufeff" test scan-8.1 {error conditions} { catch {scan a} } 1 test scan-8.2 {error conditions} { catch {scan a} msg set msg } {wrong # args: should be "scan string format ?varName varName ...?"} test scan-8.3 {error conditions} { list [catch {scan a %D x} msg] $msg } {1 {bad scan conversion character "D"}} test scan-8.4 {error conditions} { list [catch {scan a %O x} msg] $msg } {1 {bad scan conversion character "O"}} test scan-8.5 {error conditions} { list [catch {scan a %X x} msg] $msg } {1 {bad scan conversion character "X"}} test scan-8.6 {error conditions} { list [catch {scan a %F x} msg] $msg } {1 {bad scan conversion character "F"}} test scan-8.7 {error conditions} { list [catch {scan a %E x} msg] $msg } {1 {bad scan conversion character "E"}} test scan-8.8 {error conditions} { list [catch {scan a "%d %d" a} msg] $msg } {1 {different numbers of variable names and field specifiers}} test scan-8.9 {error conditions} { list [catch {scan a "%d %d" a b c} msg] $msg } {1 {variable is not assigned by any conversion specifiers}} test scan-8.10 {error conditions} { set a {}; set b {}; set c {}; set d {} list [expr {[scan " a" " a %d %d %d %d" a b c d] <= 0}] $a $b $c $d } {1 {} {} {} {}} test scan-8.11 {error conditions} { set a {}; set b {}; set c {}; set d {} list [scan "1 2" "%d %d %d %d" a b c d] $a $b $c $d } {2 1 2 {} {}} test scan-8.12 {error conditions} { catch {unset a} set a(0) 44 list [catch {scan 44 %d a} msg] $msg } {1 {couldn't set variable "a"}} test scan-8.13 {error conditions} { catch {unset a} set a(0) 44 list [catch {scan 44 %c a} msg] $msg } {1 {couldn't set variable "a"}} test scan-8.14 {error conditions} { catch {unset a} set a(0) 44 list [catch {scan 44 %s a} msg] $msg } {1 {couldn't set variable "a"}} test scan-8.15 {error conditions} { catch {unset a} set a(0) 44 list [catch {scan 44 %f a} msg] $msg } {1 {couldn't set variable "a"}} test scan-8.16 {error conditions} { catch {unset a} set a(0) 44 list [catch {scan 44 %f a} msg] $msg } {1 {couldn't set variable "a"}} catch {unset a} test scan-8.17 {error conditions} { list [catch {scan 44 %2c a} msg] $msg } {1 {field width may not be specified in %c conversion}} test scan-8.18 {error conditions} { list [catch {scan abc {%[} x} msg] $msg } {1 {unmatched [ in format string}} test scan-8.19 {error conditions} { list [catch {scan abc {%[^a} x} msg] $msg } {1 {unmatched [ in format string}} test scan-8.20 {error conditions} { list [catch {scan abc {%[^]a} x} msg] $msg } {1 {unmatched [ in format string}} test scan-8.21 {error conditions} { list [catch {scan abc {%[]a} x} msg] $msg } {1 {unmatched [ in format string}} test scan-9.1 {lots of arguments} { scan "10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 170 180 190 200" "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d" a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a18 a19 a20 } 20 test scan-9.2 {lots of arguments} { scan "10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 170 180 190 200" "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d" a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a18 a19 a20 set a20 } 200 test scan-10.1 {miscellaneous tests} { set a {} list [scan ab16c ab%dc a] $a } {1 16} test scan-10.2 {miscellaneous tests} { set a {} list [scan ax16c ab%dc a] $a } {0 {}} test scan-10.3 {miscellaneous tests} { set a {} list [catch {scan ab%c114 ab%%c%d a} msg] $msg $a } {0 1 114} test scan-10.4 {miscellaneous tests} { set a {} list [catch {scan ab%c14 ab%%c%d a} msg] $msg $a } {0 1 14} test scan-10.5 {miscellaneous tests} { catch {unset arr} set arr(2) {} list [catch {scan ab%c14 ab%%c%d arr(2)} msg] $msg $arr(2) } {0 1 14} test scan-11.1 {alignment in results array (TCL_ALIGN)} { scan "123 13.6" "%s %f" a b set b } 13.6 test scan-11.2 {alignment in results array (TCL_ALIGN)} { scan "1234567 13.6" "%s %f" a b set b } 13.6 test scan-11.3 {alignment in results array (TCL_ALIGN)} { scan "12345678901 13.6" "%s %f" a b set b } 13.6 test scan-11.4 {alignment in results array (TCL_ALIGN)} { scan "123456789012345 13.6" "%s %f" a b set b } 13.6 test scan-11.5 {alignment in results array (TCL_ALIGN)} { scan "1234567890123456789 13.6" "%s %f" a b set b } 13.6 test scan-12.1 {Tcl_ScanObjCmd, inline case} { scan a %c } 97 test scan-12.2 {Tcl_ScanObjCmd, inline case} { scan abc %c%c%c%c } {97 98 99 {}} test scan-12.3 {Tcl_ScanObjCmd, inline case} { scan abc %s%c } {abc {}} test scan-12.4 {Tcl_ScanObjCmd, inline case, underflow} { scan abc abc%c } {} test scan-12.5 {Tcl_ScanObjCmd, inline case} { scan abc bogus%c%c%c } {{} {} {}} test scan-12.6 {Tcl_ScanObjCmd, inline case} { # degenerate case, behavior changed from 8.2 to 8.3 list [catch {scan foo foobar} msg] $msg } {0 {}} test scan-12.7 {Tcl_ScanObjCmd, inline case lots of arguments} { scan "10 20 30 40 50 60 70 80 90 100 110 120 130 140\ 150 160 170 180 190 200" \ "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d" } {10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 170 180 190 200 {}} test scan-13.1 {Tcl_ScanObjCmd, inline XPG case} { scan a {%1$c} } 97 test scan-13.2 {Tcl_ScanObjCmd, inline XPG case} { scan abc {%1$c%2$c%3$c%4$c} } {97 98 99 {}} test scan-13.3 {Tcl_ScanObjCmd, inline XPG case} { list [catch {scan abc {%1$c%1$c}} msg] $msg } {1 {variable is assigned by multiple "%n$" conversion specifiers}} test scan-13.4 {Tcl_ScanObjCmd, inline XPG case} { scan abc {%2$s%1$c} } {{} abc} test scan-13.5 {Tcl_ScanObjCmd, inline XPG case, underflow} { scan abc {abc%5$c} } {} test scan-13.6 {Tcl_ScanObjCmd, inline XPG case} { catch {scan abc {bogus%1$c%5$c%10$c}} msg list [llength $msg] $msg } {10 {{} {} {} {} {} {} {} {} {} {}}} test scan-13.7 {Tcl_ScanObjCmd, inline XPG case lots of arguments} { scan "10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 170 180 190 200" {%20$d %18$d %17$d %16$d %15$d %14$d %13$d %12$d %11$d %10$d %9$d %8$d %7$d %6$d %5$d %4$d %3$d %2$d %1$d} } {190 180 170 160 150 140 130 120 110 100 90 80 70 60 50 40 30 20 {} 10} test scan-13.8 {Tcl_ScanObjCmd, inline XPG case lots of arguments} { set msg [scan "10 20 30" {%100$d %5$d %200$d}] list [llength $msg] [lindex $msg 99] [lindex $msg 4] [lindex $msg 199] } {200 10 20 30} # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/if-old.test0000644003604700454610000001124111737050674014133 0ustar dgp771div# Commands covered: if # # This file contains the original set of tests for Tcl's if command. # Since the if command is now compiled, a new set of tests covering # the new implementation is in the file "if.test". Sourcing this file # into Tcl runs the tests and generates output for errors. # No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994-1996 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } test if-old-1.1 {taking proper branch} { set a {} if 0 {set a 1} else {set a 2} set a } 2 test if-old-1.2 {taking proper branch} { set a {} if 1 {set a 1} else {set a 2} set a } 1 test if-old-1.3 {taking proper branch} { set a {} if 1<2 {set a 1} set a } 1 test if-old-1.4 {taking proper branch} { set a {} if 1>2 {set a 1} set a } {} test if-old-1.5 {taking proper branch} { set a {} if 0 {set a 1} else {} set a } {} test if-old-1.6 {taking proper branch} { set a {} if 0 {set a 1} elseif 1 {set a 2} elseif 1 {set a 3} else {set a 4} set a } {2} test if-old-1.7 {taking proper branch} { set a {} if 0 {set a 1} elseif 0 {set a 2} elseif 1 {set a 3} else {set a 4} set a } {3} test if-old-1.8 {taking proper branch} { set a {} if 0 {set a 1} elseif 0 {set a 2} elseif 0 {set a 3} else {set a 4} set a } {4} test if-old-1.9 {taking proper branch, multiline test expr} { set a {} if {($tcl_platform(platform) != "foobar1") && \ ($tcl_platform(platform) != "foobar2")} {set a 3} else {set a 4} set a } {3} test if-old-2.1 {optional then-else args} { set a 44 if 0 then {set a 1} elseif 0 then {set a 3} else {set a 2} set a } 2 test if-old-2.2 {optional then-else args} { set a 44 if 1 then {set a 1} else {set a 2} set a } 1 test if-old-2.3 {optional then-else args} { set a 44 if 0 {set a 1} else {set a 2} set a } 2 test if-old-2.4 {optional then-else args} { set a 44 if 1 {set a 1} else {set a 2} set a } 1 test if-old-2.5 {optional then-else args} { set a 44 if 0 then {set a 1} {set a 2} set a } 2 test if-old-2.6 {optional then-else args} { set a 44 if 1 then {set a 1} {set a 2} set a } 1 test if-old-2.7 {optional then-else args} { set a 44 if 0 then {set a 1} else {set a 2} set a } 2 test if-old-2.8 {optional then-else args} { set a 44 if 0 then {set a 1} elseif 0 {set a 2} elseif 0 {set a 3} {set a 4} set a } 4 test if-old-3.1 {return value} { if 1 then {set a 22; concat abc} } abc test if-old-3.2 {return value} { if 0 then {set a 22; concat abc} elseif 1 {concat def} {concat ghi} } def test if-old-3.3 {return value} { if 0 then {set a 22; concat abc} else {concat def} } def test if-old-3.4 {return value} { if 0 then {set a 22; concat abc} } {} test if-old-3.5 {return value} { if 0 then {set a 22; concat abc} elseif 0 {concat def} } {} test if-old-4.1 {error conditions} { list [catch {if} msg] $msg } {1 {wrong # args: no expression after "if" argument}} test if-old-4.2 {error conditions} { list [catch {if {[error "error in condition"]} foo} msg] $msg } {1 {error in condition}} test if-old-4.3 {error conditions} { list [catch {if 2} msg] $msg } {1 {wrong # args: no script following "2" argument}} test if-old-4.4 {error conditions} { list [catch {if 2 then} msg] $msg } {1 {wrong # args: no script following "then" argument}} test if-old-4.5 {error conditions} { list [catch {if 2 the} msg] $msg } {1 {invalid command name "the"}} test if-old-4.6 {error conditions} { list [catch {if 2 then {[error "error in then clause"]}} msg] $msg } {1 {error in then clause}} test if-old-4.7 {error conditions} { list [catch {if 0 then foo elseif} msg] $msg } {1 {wrong # args: no expression after "elseif" argument}} test if-old-4.8 {error conditions} { list [catch {if 0 then foo elsei} msg] $msg } {1 {invalid command name "elsei"}} test if-old-4.9 {error conditions} { list [catch {if 0 then foo elseif 0 bar else} msg] $msg } {1 {wrong # args: no script following "else" argument}} test if-old-4.10 {error conditions} { list [catch {if 0 then foo elseif 0 bar els} msg] $msg } {1 {invalid command name "els"}} test if-old-4.11 {error conditions} { list [catch {if 0 then foo elseif 0 bar else {[error "error in else clause"]}} msg] $msg } {1 {error in else clause}} # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/README0000644003604700454610000001047311737050674012746 0ustar dgp771divREADME -- Tcl test suite design document. Contents: --------- 1. Introduction 2. Running tests 3. Adding tests 4. Incompatibilities with prior Tcl versions 1. Introduction: ---------------- This directory contains a set of validation tests for the Tcl commands and C Library procedures for Tcl. Each of the files whose name ends in ".test" is intended to fully exercise the functions in the C source file that corresponds to the file prefix. The C functions and/or Tcl commands tested by a given file are listed in the first line of the file. 2. Running tests: ----------------- We recommend that you use the "test" target of Tcl's Makefile to run the test suite. From the directory in which you build Tcl, simply type "make test". This will create a special executable named tcltest in which the testing scripts will be evaluated. To create the tcltest executable without running the test suite, simple type "make tcltest". All the configuration options of the tcltest package are available during a "make test" by defining the TESTFLAGS environment variable. For example,if you wish to run only those tests in the file append.test, you can type: make test TESTFLAGS="-file append.test" For interactive testing, the Tcl Makefile provides the "runtest" target. Type "make runtest" in your build directory, and the tcltest executable will be created, if necessary, then it will run interactively. At the command prompt, you may type any Tcl commands. If you type "source ../tests/all.tcl", the test suite will run. You may use the tcltest::configure command to configure the test suite run as an alternative to command line options via TESTFLAGS. You might also wish to use the tcltest::testConstraint command to select the constraints that govern which tests are run. See the documentation for the tcltest package for details. 3. Adding tests: ---------------- Please see the tcltest man page for more information regarding how to write and run tests. Please note that the all.tcl file will source your new test file if the filename matches the tests/*.test pattern (as it should). The names of test files that contain regression (or glass-box) tests should correspond to the Tcl or C code file that they are testing. For example, the test file for the C file "tclCmdAH.c" is "cmdAH.test". Test files that contain black-box tests may not correspond to any Tcl or C code file so they should match the pattern "*_bb.test". Be sure your new test file can be run from any working directory. Be sure no temporary files are left behind by your test file. Use [tcltest::makeFile], [tcltest::removeFile], and [tcltest::cleanupTests] properly to be sure of this. Be sure your tests can run cross-platform in both a build environment as well as an installation environment. If your test file contains tests that should not be run in one or more of those cases, please use the constraints mechanism to skip those tests. 4. Incompatibilities of package tcltest 2.1 with testing machinery of very old versions of Tcl: ------------------------------------------------ 1) Global variables such as VERBOSE, TESTS, and testConfig of the old machinery correspond to the [configure -verbose], [configure -match], and [testConstraint] commands of tcltest 2.1, respectively. 2) VERBOSE values were longer numeric. [configure -verbose] values are lists of keywords. 3) When you run "make test", the working dir for the test suite is now the one from which you called "make test", rather than the "tests" directory. This change allows for both unix and windows test suites to be run simultaneously without interference with each other or with existing files. All tests must now run independently of their working directory. 4) The "all" file is now called "all.tcl" 5) The "defs" and "defs.tcl" files no longer exist. 6) Instead of creating a doAllTests file in the tests directory, to run all nonPortable tests, just use the "-constraints nonPortable" command line flag. If you are running interactively, you can run [tcltest::testConstraint nonPortable 1] (after loading the tcltest package). 7) Direct evaluation of the *.test files by the "source" command is no longer recommended. Instead, "source all.tcl" and use the "-file" and "-notfile" options of tcltest::configure to control which *.test files are evaluated. tcl8.4.20/tests/result.test0000644003604700454610000001016211737050674014300 0ustar dgp771div# This file tests the routines in tclResult.c. # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1997 by Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import -force ::tcltest::* } # Some tests require the testsaveresult command ::tcltest::testConstraint testsaveresult \ [expr {[info commands testsaveresult] != {}}] test result-1.1 {Tcl_SaveInterpResult} {testsaveresult} { testsaveresult small {set x 42} 0 } {small result} test result-1.2 {Tcl_SaveInterpResult} {testsaveresult} { testsaveresult append {set x 42} 0 } {append result} test result-1.3 {Tcl_SaveInterpResult} {testsaveresult} { testsaveresult dynamic {set x 42} 0 } {dynamic result notCalled present} test result-1.4 {Tcl_SaveInterpResult} {testsaveresult} { testsaveresult object {set x 42} 0 } {object result same} test result-1.5 {Tcl_SaveInterpResult} {testsaveresult} { testsaveresult small {set x 42} 1 } {42} test result-1.6 {Tcl_SaveInterpResult} {testsaveresult} { testsaveresult append {set x 42} 1 } {42} test result-1.7 {Tcl_SaveInterpResult} {testsaveresult} { testsaveresult dynamic {set x 42} 1 } {42 called missing} test result-1.8 {Tcl_SaveInterpResult} {testsaveresult} { testsaveresult object {set x 42} 1 } {42 different} # Tcl_RestoreInterpResult is mostly tested by the previous tests except # for the following case test result-2.1 {Tcl_RestoreInterpResult} {testsaveresult} { testsaveresult append {cd _foobar} 0 } {append result} # Tcl_DiscardInterpResult is mostly tested by the previous tests except # for the following cases test result-3.1 {Tcl_DiscardInterpResult} {testsaveresult} { list [catch {testsaveresult append {cd _foobar} 1} msg] $msg } {1 {couldn't change working directory to "_foobar": no such file or directory}} test result-3.2 {Tcl_DiscardInterpResult} {testsaveresult} { testsaveresult free {set x 42} 1 } {42} ::tcltest::testConstraint testsetobjerrorcode \ [expr {[info commands testsetobjerrorcode] != {}}] test result-4.1 {Tcl_SetObjErrorCode - one arg} {testsetobjerrorcode} { catch {testsetobjerrorcode 1} list [set errorCode] } {1} test result-4.2 {Tcl_SetObjErrorCode - two args} {testsetobjerrorcode} { catch {testsetobjerrorcode 1 2} list [set errorCode] } {{1 2}} test result-4.3 {Tcl_SetObjErrorCode - three args} {testsetobjerrorcode} { catch {testsetobjerrorcode 1 2 3} list [set errorCode] } {{1 2 3}} test result-4.4 {Tcl_SetObjErrorCode - four args} {testsetobjerrorcode} { catch {testsetobjerrorcode 1 2 3 4} list [set errorCode] } {{1 2 3 4}} test result-4.5 {Tcl_SetObjErrorCode - five args} {testsetobjerrorcode} { catch {testsetobjerrorcode 1 2 3 4 5} list [set errorCode] } {{1 2 3 4 5}} ::tcltest::testConstraint testseterrorcode \ [expr {[info commands testseterrorcode] != {}}] test result-5.1 {Tcl_SetErrorCode - one arg} testseterrorcode { catch {testseterrorcode 1} set errorCode } 1 test result-5.2 {Tcl_SetErrorCode - one arg, list quoting} testseterrorcode { catch {testseterrorcode {a b}} set errorCode } {{a b}} test result-5.3 {Tcl_SetErrorCode - one arg, list quoting} testseterrorcode { catch {testseterrorcode \{} llength $errorCode } 1 test result-5.4 {Tcl_SetErrorCode - two args, list quoting} testseterrorcode { catch {testseterrorcode {a b} c} set errorCode } {{a b} c} test result-6.2 {Bug 1649062} -setup { proc foo {} { if {[catch { return -code error -errorinfo custom -errorcode CUSTOM foo } err]} { return [list $err $::errorCode $::errorInfo] } } set ::errorInfo {} set ::errorCode {} } -body { foo } -cleanup { rename foo {} } -result {foo {} {}} # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/fileSystem.test0000644003604700454610000004324011737050674015111 0ustar dgp771div# This file tests the filesystem and vfs internals. # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 2002 Vincent Darley. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. package require tcltest 2 namespace eval ::tcl::test::fileSystem { catch { namespace import ::tcltest::cleanupTests namespace import ::tcltest::makeDirectory namespace import ::tcltest::makeFile namespace import ::tcltest::removeDirectory namespace import ::tcltest::removeFile namespace import ::tcltest::test } catch { file delete -force link.file file delete -force dir.link file delete -force [file join dir.file linkinside.file] } cd [tcltest::temporaryDirectory] makeFile "test file" gorp.file makeDirectory dir.file makeFile "test file in directory" [file join dir.file inside.file] if {[catch { file link link.file gorp.file file link \ [file join dir.file linkinside.file] \ [file join dir.file inside.file] file link dir.link dir.file }]} { tcltest::testConstraint hasLinks 0 } else { tcltest::testConstraint hasLinks 1 } tcltest::testConstraint testsimplefilesystem \ [string equal testsimplefilesystem [info commands testsimplefilesystem]] test filesystem-1.0 {link normalisation} {hasLinks} { string equal [file normalize gorp.file] [file normalize link.file] } {0} test filesystem-1.1 {link normalisation} {hasLinks} { string equal [file normalize dir.file] [file normalize dir.link] } {0} test filesystem-1.2 {link normalisation} {hasLinks macOrUnix} { string equal [file normalize [file join gorp.file foo]] \ [file normalize [file join link.file foo]] } {1} test filesystem-1.3 {link normalisation} {hasLinks} { string equal [file normalize [file join dir.file foo]] \ [file normalize [file join dir.link foo]] } {1} test filesystem-1.4 {link normalisation} {hasLinks} { string equal [file normalize [file join dir.file inside.file]] \ [file normalize [file join dir.link inside.file]] } {1} test filesystem-1.5 {link normalisation} {hasLinks} { string equal [file normalize [file join dir.file linkinside.file]] \ [file normalize [file join dir.file linkinside.file]] } {1} test filesystem-1.6 {link normalisation} {hasLinks} { string equal [file normalize [file join dir.file linkinside.file]] \ [file normalize [file join dir.link inside.file]] } {0} test filesystem-1.7 {link normalisation} {hasLinks macOrUnix} { string equal [file normalize [file join dir.link linkinside.file foo]] \ [file normalize [file join dir.file inside.file foo]] } {1} test filesystem-1.8 {link normalisation} {hasLinks} { string equal [file normalize [file join dir.file linkinside.filefoo]] \ [file normalize [file join dir.link inside.filefoo]] } {0} test filesystem-1.9 {link normalisation} {macOrUnix hasLinks} { file delete -force dir.link file link dir.link [file nativename dir.file] string equal [file normalize [file join dir.file linkinside.file foo]] \ [file normalize [file join dir.link inside.file foo]] } {1} test filesystem-1.10 {link normalisation: double link} {macOrUnix hasLinks} { file link dir2.link dir.link string equal [file normalize [file join dir.file linkinside.file foo]] \ [file normalize [file join dir2.link inside.file foo]] } {1} makeDirectory dir2.file test filesystem-1.11 {link normalisation: double link, back in tree} {macOrUnix hasLinks} { file link [file join dir2.file dir2.link] dir2.link string equal [file normalize [file join dir.file linkinside.file foo]] \ [file normalize [file join dir2.file dir2.link inside.file foo]] } {1} test filesystem-1.12 {file new native path} {} { for {set i 0} {$i < 10} {incr i} { foreach f [lsort [glob -nocomplain -type l *]] { catch {file readlink $f} } } # If we reach here we've succeeded. We used to crash above. expr 1 } {1} test filesystem-1.13 {file normalisation} {winOnly} { # This used to be broken file normalize C:/thislongnamedoesntexist } {C:/thislongnamedoesntexist} test filesystem-1.14 {file normalisation} {winOnly} { # This used to be broken file normalize c:/ } {C:/} file delete -force dir2.file file delete -force dir2.link file delete -force link.file dir.link removeFile [file join dir.file inside.file] removeDirectory dir.file test filesystem-2.0 {new native path} {unixOnly} { foreach f [lsort [glob -nocomplain /usr/bin/c*]] { catch {file readlink $f} } # If we reach here we've succeeded. We used to crash above. expr 1 } {1} if {[catch {package require tcltest 2}]} { puts stderr "Skipping tests filesystem-{3,4}.*: tcltest 2 required." } else { namespace import ::tcltest::testConstraint # Is the Tcltest package loaded? # - that is, the special C-coded testing commands in tclTest.c # - tests use testing commands introduced in Tcltest 8.4 testConstraint Tcltest [expr { [llength [package provide Tcltest]] && [package vsatisfies [package provide Tcltest] 8.4]}] # Make sure the testfilesystem hasn't been registered. while {![catch {testfilesystem 0}]} {} test filesystem-3.0 {Tcl_FSRegister} Tcltest { testfilesystem 1 } {registered} test filesystem-3.1 {Tcl_FSUnregister} Tcltest { testfilesystem 0 } {unregistered} test filesystem-3.2 {Tcl_FSUnregister} Tcltest { list [catch {testfilesystem 0} err] $err } {1 failed} test filesystem-3.3 {Tcl_FSRegister} Tcltest { testfilesystem 1 testfilesystem 1 testfilesystem 0 testfilesystem 0 } {unregistered} test filesystem-3.4 {Tcl_FSRegister} Tcltest { testfilesystem 1 file system bar } {reporting} test filesystem-3.5 {Tcl_FSUnregister} Tcltest { testfilesystem 0 lindex [file system bar] 0 } {native} test filesystem-4.0 {testfilesystem} { -constraints Tcltest -match glob -body { testfilesystem 1 set filesystemReport {} file exists foo testfilesystem 0 set filesystemReport } -result {* {access foo}} } test filesystem-4.1 {testfilesystem} { -constraints Tcltest -match glob -body { testfilesystem 1 set filesystemReport {} catch {file stat foo bar} testfilesystem 0 set filesystemReport } -result {* {stat foo}} } test filesystem-4.2 {testfilesystem} { -constraints Tcltest -match glob -body { testfilesystem 1 set filesystemReport {} catch {file lstat foo bar} testfilesystem 0 set filesystemReport } -result {* {lstat foo}} } test filesystem-4.3 {testfilesystem} { -constraints Tcltest -match glob -body { testfilesystem 1 set filesystemReport {} catch {glob *} testfilesystem 0 set filesystemReport } -result {* {matchindirectory *}*} } test filesystem-5.1 {cache and ~} { -constraints Tcltest -match regexp -body { set orig $env(HOME) set ::env(HOME) /foo/bar/blah set testdir ~ set res1 "Parent of ~ (/foo/bar/blah) is [file dirname $testdir]" set ::env(HOME) /a/b/c set res2 "Parent of ~ (/a/b/c) is [file dirname $testdir]" set ::env(HOME) $orig list $res1 $res2 } -result {{Parent of ~ \(/foo/bar/blah\) is (/foo/bar|foo:bar)} {Parent of ~ \(/a/b/c\) is (/a/b|a:b)}} } test filesystem-6.1 {empty file name} { list [catch {open ""} msg] $msg } {1 {couldn't open "": no such file or directory}} test filesystem-6.2 {empty file name} { list [catch {file stat "" arr} msg] $msg } {1 {could not read "": no such file or directory}} test filesystem-6.3 {empty file name} { list [catch {file atime ""} msg] $msg } {1 {could not read "": no such file or directory}} test filesystem-6.4 {empty file name} { list [catch {file attributes ""} msg] $msg } {1 {could not read "": no such file or directory}} test filesystem-6.5 {empty file name} { list [catch {file copy "" ""} msg] $msg } {1 {error copying "": no such file or directory}} test filesystem-6.6 {empty file name} { list [catch {file delete ""} msg] $msg } {0 {}} test filesystem-6.7 {empty file name} { list [catch {file dirname ""} msg] $msg } {0 .} test filesystem-6.8 {empty file name} { list [catch {file executable ""} msg] $msg } {0 0} test filesystem-6.9 {empty file name} { list [catch {file exists ""} msg] $msg } {0 0} test filesystem-6.10 {empty file name} { list [catch {file extension ""} msg] $msg } {0 {}} test filesystem-6.11 {empty file name} { list [catch {file isdirectory ""} msg] $msg } {0 0} test filesystem-6.12 {empty file name} { list [catch {file isfile ""} msg] $msg } {0 0} test filesystem-6.13 {empty file name} { list [catch {file join ""} msg] $msg } {0 {}} test filesystem-6.14 {empty file name} { list [catch {file link ""} msg] $msg } {1 {could not read link "": no such file or directory}} test filesystem-6.15 {empty file name} { list [catch {file lstat "" arr} msg] $msg } {1 {could not read "": no such file or directory}} test filesystem-6.16 {empty file name} { list [catch {file mtime ""} msg] $msg } {1 {could not read "": no such file or directory}} test filesystem-6.17 {empty file name} { list [catch {file mtime "" 0} msg] $msg } {1 {could not read "": no such file or directory}} test filesystem-6.18 {empty file name} { list [catch {file mkdir ""} msg] $msg } {1 {can't create directory "": no such file or directory}} test filesystem-6.19 {empty file name} { list [catch {file nativename ""} msg] $msg } {0 {}} test filesystem-6.20 {empty file name} { list [catch {file normalize ""} msg] $msg } {0 {}} test filesystem-6.21 {empty file name} { list [catch {file owned ""} msg] $msg } {0 0} test filesystem-6.22 {empty file name} { list [catch {file pathtype ""} msg] $msg } {0 relative} test filesystem-6.23 {empty file name} { list [catch {file readable ""} msg] $msg } {0 0} test filesystem-6.24 {empty file name} { list [catch {file readlink ""} msg] $msg } {1 {could not readlink "": no such file or directory}} test filesystem-6.25 {empty file name} { list [catch {file rename "" ""} msg] $msg } {1 {error renaming "": no such file or directory}} test filesystem-6.26 {empty file name} { list [catch {file rootname ""} msg] $msg } {0 {}} test filesystem-6.27 {empty file name} { list [catch {file separator ""} msg] $msg } {1 {Unrecognised path}} test filesystem-6.28 {empty file name} { list [catch {file size ""} msg] $msg } {1 {could not read "": no such file or directory}} test filesystem-6.29 {empty file name} { list [catch {file split ""} msg] $msg } {0 {}} test filesystem-6.30 {empty file name} { list [catch {file system ""} msg] $msg } {1 {Unrecognised path}} test filesystem-6.31 {empty file name} { list [catch {file tail ""} msg] $msg } {0 {}} test filesystem-6.32 {empty file name} { list [catch {file type ""} msg] $msg } {1 {could not read "": no such file or directory}} test filesystem-6.33 {empty file name} { list [catch {file writable ""} msg] $msg } {0 0} # Make sure the testfilesystem hasn't been registered. while {![catch {testfilesystem 0}]} {} } test filesystem-7.1 {load from vfs} {win testsimplefilesystem} { # This may cause a crash on exit set dir [pwd] cd [file dirname [info nameof]] set dde [lindex [glob *dde*[info sharedlib]] 0] testsimplefilesystem 1 # This loads dde via a complex copy-to-temp operation load simplefs:/$dde dde testsimplefilesystem 0 cd $dir set res "ok" # The real result of this test is what happens when Tcl exits. } {ok} test filesystem-7.2 {cross-filesystem copy from vfs maintains mtime} \ {testsimplefilesystem} { set dir [pwd] cd [tcltest::temporaryDirectory] # We created this file several tests ago. set origtime [file mtime gorp.file] testsimplefilesystem 1 file delete -force theCopy file copy simplefs:/gorp.file theCopy testsimplefilesystem 0 set newtime [file mtime theCopy] file delete theCopy cd $dir expr {$origtime == $newtime} } {1} removeFile gorp.file test filesystem-8.1 {relative path objects and caching of pwd} { set dir [pwd] cd [tcltest::temporaryDirectory] makeDirectory abc makeDirectory def makeFile "contents" [file join abc foo] cd abc set f "foo" set res {} lappend res [file exists $f] lappend res [file exists $f] cd .. cd def # If we haven't cleared the object's cwd cache, Tcl # will think it still exists. lappend res [file exists $f] lappend res [file exists $f] removeFile [file join abc foo] removeDirectory abc removeDirectory def cd $dir set res } {1 1 0 0} test filesystem-8.2 {relative path objects and use of pwd} { set origdir [pwd] cd [tcltest::temporaryDirectory] set dir "abc" makeDirectory $dir makeFile "contents" [file join abc foo] cd $dir set res [file exists [lindex [glob *] 0]] cd .. removeFile [file join abc foo] removeDirectory abc cd $origdir set res } {1} test filesystem-8.3 {path objects and empty string} { set anchor "" set dst foo set res $dst set yyy [file split $anchor] set dst [file join $anchor $dst] lappend res $dst $yyy } {foo foo {}} proc TestFind1 {d f} { set r1 [file exists [file join $d $f]] lappend res "[file join $d $f] found: $r1" lappend res "is dir a dir? [file isdirectory $d]" set r2 [file exists [file join $d $f]] lappend res "[file join $d $f] found: $r2" set res } proc TestFind2 {d f} { set r1 [file exists [file join $d $f]] lappend res "[file join $d $f] found: $r1" lappend res "is dir a dir? [file isdirectory [file join $d]]" set r2 [file exists [file join $d $f]] lappend res "[file join $d $f] found: $r2" set res } test filesystem-9.1 {path objects and join and object rep} { set origdir [pwd] cd [tcltest::temporaryDirectory] file mkdir [file join a b c] set res [TestFind1 a [file join b . c]] file delete -force a cd $origdir set res } {{a/b/./c found: 1} {is dir a dir? 1} {a/b/./c found: 1}} test filesystem-9.2 {path objects and join and object rep} { set origdir [pwd] cd [tcltest::temporaryDirectory] file mkdir [file join a b c] set res [TestFind2 a [file join b . c]] file delete -force a cd $origdir set res } {{a/b/./c found: 1} {is dir a dir? 1} {a/b/./c found: 1}} test filesystem-9.2.1 {path objects and join and object rep} { set origdir [pwd] cd [tcltest::temporaryDirectory] file mkdir [file join a b c] set res [TestFind2 a [file join b .]] file delete -force a cd $origdir set res } {{a/b/. found: 1} {is dir a dir? 1} {a/b/. found: 1}} test filesystem-9.3 {path objects and join and object rep} { set origdir [pwd] cd [tcltest::temporaryDirectory] file mkdir [file join a b c] set res [TestFind1 a [file join b .. b c]] file delete -force a cd $origdir set res } {{a/b/../b/c found: 1} {is dir a dir? 1} {a/b/../b/c found: 1}} test filesystem-9.4 {path objects and join and object rep} { set origdir [pwd] cd [tcltest::temporaryDirectory] file mkdir [file join a b c] set res [TestFind2 a [file join b .. b c]] file delete -force a cd $origdir set res } {{a/b/../b/c found: 1} {is dir a dir? 1} {a/b/../b/c found: 1}} test filesystem-9.5 {path objects and file tail and object rep} { set origdir [pwd] cd [tcltest::temporaryDirectory] file mkdir dgp close [open dgp/test w] foreach relative [glob -nocomplain [file join * test]] { set absolute [file join [pwd] $relative] set res [list [file tail $absolute] "test"] } file delete -force dgp cd $origdir set res } {test test} test filesystem-9.6 {path objects and file join and object rep} {winOnly} { set res {} set p "C:\\toto" lappend res [file join $p toto] file isdirectory $p lappend res [file join $p toto] } {C:/toto/toto C:/toto/toto} test filesystem-9.7 {path objects and glob and file tail and tilde} { set res {} set origdir [pwd] cd [tcltest::temporaryDirectory] file mkdir tilde close [open tilde/~testNotExist w] cd tilde set file [lindex [glob *test*] 0] lappend res [file exists $file] [catch {file tail $file} r] $r lappend res $file lappend res [file exists $file] [catch {file tail $file} r] $r lappend res [catch {file tail $file} r] $r cd .. file delete -force tilde cd $origdir set res } {0 1 {user "testNotExist" doesn't exist} ~testNotExist 0 1 {user "testNotExist" doesn't exist} 1 {user "testNotExist" doesn't exist}} test filesystem-9.8 {path objects and glob and file tail and tilde} { set res {} set origdir [pwd] cd [tcltest::temporaryDirectory] file mkdir tilde close [open tilde/~testNotExist w] cd tilde set file1 [lindex [glob *test*] 0] set file2 "~testNotExist" lappend res $file1 $file2 lappend res [catch {file tail $file1} r] $r lappend res [catch {file tail $file2} r] $r cd .. file delete -force tilde cd $origdir set res } {~testNotExist ~testNotExist 1 {user "testNotExist" doesn't exist} 1 {user "testNotExist" doesn't exist}} test filesystem-9.9 {path objects and glob and file tail and tilde} { set res {} set origdir [pwd] cd [tcltest::temporaryDirectory] file mkdir tilde close [open tilde/~testNotExist w] cd tilde set file1 [lindex [glob *test*] 0] set file2 "~testNotExist" lappend res [catch {file exists $file1} r] $r lappend res [catch {file exists $file2} r] $r lappend res [string equal $file1 $file2] cd .. file delete -force tilde cd $origdir set res } {0 0 0 0 1} cleanupTests } namespace delete ::tcl::test::fileSystem return tcl8.4.20/tests/compExpr-old.test0000644003604700454610000011044411737050674015337 0ustar dgp771div# Commands covered: expr # # This file contains the original set of tests for the compilation (and # indirectly execution) of Tcl's expr command. A new set of tests covering # the new implementation are in the files "parseExpr.test" and # "compExpr.test". Sourcing this file into Tcl runs the tests and generates # output for errors. No output means no errors were found. # # Copyright (c) 1996-1997 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } if {([catch {expr T1()} msg] == 1) && ($msg == {unknown math function "T1"})} { set gotT1 0 puts "This application hasn't been compiled with the \"T1\" and" puts "\"T2\" math functions, so I'll skip some of the expr tests." } else { set gotT1 1 } # procedures used below proc put_hello_char {c} { global a append a [format %c $c] return $c } proc hello_world {} { global a set a "" set L1 [set l0 [set h_1 [set q 0]]] for {put_hello_char [expr [put_hello_char [expr [set h 7]*10+2]]+29]} {$l0?[put_hello_char $l0] :!$h_1} {put_hello_char $ll;expr {$L1==2?[set ll [expr 32+0-0+[set bar 0]]]:0}} {expr {[incr L1]==[expr 1+([string length "abc"]-[string length "abc"])] ?[set ll [set l0 [expr 54<<1]]]:$ll==108&&$L1<3? [incr ll [expr 1|1<<1]; set ll $ll; set ll $ll; set ll $ll; set ll $ll; set l0 [expr ([string length "abc"]-[string length "abc"])+([string length "abc"]-[string length "abc"])-([string length "abc"]-[string length "abc"])+([string length "abc"]-[string length "abc"])]; set l0; set l0 $l0; set l0; set l0]:$L1==4&&$ll==32?[set ll [expr 19+$h1+([string length "abc"]-[string length "abc"])-([string length "abc"]-[string length "abc"])+([string length "abc"]-[string length "abc"])-([string length "abc"]-[string length "abc"])+[set foo [expr ([string length "abc"]-[string length "abc"])+([string length "abc"]-[string length "abc"])+([string length "abc"]-[string length "abc"])]]]] :[set q [expr $q-$h1+([string length "abc"]-[string length "abc"])-([string length "abc"]-[string length "abc"])]]};expr {$L1==5?[incr ll -8; set ll $ll; set ll]:$q&&$h1&&1};expr {$L1==4+2 ?[incr ll 3]:[expr ([string length "abc"]-[string length "abc"])+1]};expr {$ll==($h<<4)+2+0&&$L1!=6?[incr ll -6]:[set h1 [expr 100+([string length "abc"]-[string length "abc"])-([string length "abc"]-[string length "abc"])]]} expr {$L1!=1<<3?[incr q [expr ([string length "abc"]-[string length "abc"])-1]]:[set h_1 [set ll $h1]]} } set a } proc 12days {a b c} { global xxx expr {1<$a?[expr {$a<3?[12days -79 -13 [string range $c [12days -87 \ [expr 1-$b] [string range $c [12days -86 0 [string range $c 1 end]] \ end]] end]]:1};expr {$a<$b?[12days [expr $a+1] $b $c]:3};expr {[12days \ -94 [expr $a-27] $c]&&$a==2?$b<13?[12days 2 [expr $b+1] "%s %d %d\n"]:9 :16}]:$a<0?$a<-72?[12days $b $a "@n'+,#'/*\{\}w+/w#cdnr/+,\{\}r/*de\}+,/*\{*+,/w\{%+,/w#q#n+,/#\{l+,/n\{n+,/+#n+,/#;#q#n+,/+k#;*+,/'r :'d*'3,\}\{w+K w'K:'+\}e#';dq#'l q#'+d'K#!/+k#;q#'r\}eKK#\}w'r\}eKK\{nl\]'/#;#q#n')\{)#\}w')\{)\{nl\]'/+#n';d\}rw' i;# )\{nl\]!/n\{n#'; r\{#w'r nc\{nl\]'/#\{l,+'K \{rw' iK\{;\[\{nl\]'/w#q#n'wk nw' iwk\{KK\{nl\]!/w\{%'l##w#' i; :\{nl\]'/*\{q#'ld;r'\}\{nlwb!/*de\}'c ;;\{nl'-\{\}rw\]'/+,\}##'*\}#nc,',#nw\]'/+kd'+e\}+;#'rdq#w! nr'/ ') \}+\}\{rl#'\{n' ')# \}'+\}##(!!/"] :$a<-50?[string compare [format %c $b] [string index $c 0]]==0?[append \ xxx [string index $c 31];scan [string index $c 31] %c x;set x] :[12days -65 $b [string range $c 1 end]]:[12days [expr ([string compare \ [string index $c 0] "/"]==0)+$a] $b [string range $c 1 end]]:0<$a ?[12days 2 2 "%s"]:[string compare [string index $c 0] "/"]==0|| [12days 0 [12days -61 [scan [string index $c 0] %c x; set x] \ "!ek;dc i@bK'(q)-\[w\]*%n+r3#l,\{\}:\nuwloca-O;m .vpbks,fxntdCeghiry"] \ [string range $c 1 end]]} } proc do_twelve_days {} { global xxx set xxx "" 12days 1 1 1 string length $xxx } # start of tests catch {unset a b i x} test compExpr-old-1.1 {TclCompileExprCmd: no expression} { list [catch {expr } msg] $msg } {1 {wrong # args: should be "expr arg ?arg ...?"}} test compExpr-old-1.2 {TclCompileExprCmd: one expression word} { expr -25 } -25 test compExpr-old-1.3 {TclCompileExprCmd: two expression words} { expr -8.2 -6 } -14.2 test compExpr-old-1.4 {TclCompileExprCmd: five expression words} { expr 20 - 5 +10 -7 } 18 test compExpr-old-1.5 {TclCompileExprCmd: quoted expression word} { expr "0005" } 5 test compExpr-old-1.6 {TclCompileExprCmd: quoted expression word} { catch {expr "0005"zxy} msg set msg } {extra characters after close-quote} test compExpr-old-1.7 {TclCompileExprCmd: expression word in braces} { expr {-0005} } -5 test compExpr-old-1.8 {TclCompileExprCmd: expression word in braces} { expr {{-0x1234}} } -4660 test compExpr-old-1.9 {TclCompileExprCmd: expression word in braces} { catch {expr {-0005}foo} msg set msg } {extra characters after close-brace} test compExpr-old-1.10 {TclCompileExprCmd: other expression word in braces} { expr 4*[llength "6 2"] } 8 test compExpr-old-1.11 {TclCompileExprCmd: expression word terminated by ;} { expr 4*[llength "6 2"]; } 8 test compExpr-old-1.12 {TclCompileExprCmd: inlined expr (in "catch") inside other catch} { set a xxx catch { # Might not be a number set a [expr 10*$a] } } 1 test compExpr-old-1.13 {TclCompileExprCmd: second level of substitutions in expr not in braces with single var reference} { set a xxx set x 27; set bool {$x}; if $bool {set a foo} set a } foo test compExpr-old-1.14 {TclCompileExprCmd: second level of substitutions in expr with comparison as top-level operator} { set a xxx set x 2; set b {$x}; set a [expr $b == 2] set a } 1 test compExpr-old-2.1 {TclCompileExpr: are builtin functions registered?} { expr double(5*[llength "6 2"]) } 10.0 test compExpr-old-2.2 {TclCompileExpr: error in expr} { catch {expr 2**3} msg set msg } {syntax error in expression "2**3": unexpected operator *} test compExpr-old-2.3 {TclCompileExpr: junk after legal expr} { catch {expr 7*[llength "a b"]foo} msg set msg } {syntax error in expression "7*2foo": extra tokens at end of expression} test compExpr-old-2.4 {TclCompileExpr: numeric expr string rep == formatted int rep} { expr {0001} } 1 test compExpr-old-3.1 {CompileCondExpr: just lor expr} {expr 3||0} 1 test compExpr-old-3.2 {CompileCondExpr: error in lor expr} { catch {expr x||3} msg set msg } {syntax error in expression "x||3": variable references require preceding $} test compExpr-old-3.3 {CompileCondExpr: test true arm} {expr 3>2?44:66} 44 test compExpr-old-3.4 {CompileCondExpr: error compiling true arm} { catch {expr 3>2?2**3:66} msg set msg } {syntax error in expression "3>2?2**3:66": unexpected operator *} test compExpr-old-3.5 {CompileCondExpr: test false arm} {expr 2>3?44:66} 66 test compExpr-old-3.6 {CompileCondExpr: error compiling false arm} { catch {expr 2>3?44:2**3} msg set msg } {syntax error in expression "2>3?44:2**3": unexpected operator *} test compExpr-old-3.7 {CompileCondExpr: long arms & nested cond exprs} {nonPortable} { puts "Note: doing test compExpr-old-3.7 which can take several minutes to run" hello_world } {Hello world} catch {unset xxx} test compExpr-old-3.8 {CompileCondExpr: long arms & nested cond exprs} {nonPortable} { puts "Note: doing test compExpr-old-3.8 which can take several minutes to run" do_twelve_days } 2358 catch {unset xxx} test compExpr-old-4.1 {CompileLorExpr: just land expr} {expr 1.3&&3.3} 1 test compExpr-old-4.2 {CompileLorExpr: error in land expr} { catch {expr x&&3} msg set msg } {syntax error in expression "x&&3": variable references require preceding $} test compExpr-old-4.3 {CompileLorExpr: simple lor exprs} {expr 0||1.0} 1 test compExpr-old-4.4 {CompileLorExpr: simple lor exprs} {expr 3.0||0.0} 1 test compExpr-old-4.5 {CompileLorExpr: simple lor exprs} {expr 0||0||1} 1 test compExpr-old-4.6 {CompileLorExpr: error compiling lor arm} { catch {expr 2**3||4.0} msg set msg } {syntax error in expression "2**3||4.0": unexpected operator *} test compExpr-old-4.7 {CompileLorExpr: error compiling lor arm} { catch {expr 1.3||2**3} msg set msg } {syntax error in expression "1.3||2**3": unexpected operator *} test compExpr-old-4.8 {CompileLorExpr: error compiling lor arms} { list [catch {expr {"a"||"b"}} msg] $msg } {1 {expected boolean value but got "a"}} test compExpr-old-4.9 {CompileLorExpr: long lor arm} { set a "abcdefghijkl" set i 7 expr {[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]] || [string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]] || [string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]] || [string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]} } 1 test compExpr-old-5.1 {CompileLandExpr: just bitor expr} {expr 7|0x13} 23 test compExpr-old-5.2 {CompileLandExpr: error in bitor expr} { catch {expr x|3} msg set msg } {syntax error in expression "x|3": variable references require preceding $} test compExpr-old-5.3 {CompileLandExpr: simple land exprs} {expr 0&&1.0} 0 test compExpr-old-5.4 {CompileLandExpr: simple land exprs} {expr 0&&0} 0 test compExpr-old-5.5 {CompileLandExpr: simple land exprs} {expr 3.0&&1.2} 1 test compExpr-old-5.6 {CompileLandExpr: simple land exprs} {expr 1&&1&&2} 1 test compExpr-old-5.7 {CompileLandExpr: error compiling land arm} { catch {expr 2**3&&4.0} msg set msg } {syntax error in expression "2**3&&4.0": unexpected operator *} test compExpr-old-5.8 {CompileLandExpr: error compiling land arm} { catch {expr 1.3&&2**3} msg set msg } {syntax error in expression "1.3&&2**3": unexpected operator *} test compExpr-old-5.9 {CompileLandExpr: error compiling land arm} { list [catch {expr {"a"&&"b"}} msg] $msg } {1 {expected boolean value but got "a"}} test compExpr-old-5.10 {CompileLandExpr: long land arms} { set a "abcdefghijkl" set i 7 expr {[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]] && [string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]] && [string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]] && [string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]} } 1 test compExpr-old-6.1 {CompileBitXorExpr: just bitand expr} {expr 7&0x13} 3 test compExpr-old-6.2 {CompileBitXorExpr: error in bitand expr} { catch {expr x|3} msg set msg } {syntax error in expression "x|3": variable references require preceding $} test compExpr-old-6.3 {CompileBitXorExpr: simple bitxor exprs} {expr 7^0x13} 20 test compExpr-old-6.4 {CompileBitXorExpr: simple bitxor exprs} {expr 3^0x10} 19 test compExpr-old-6.5 {CompileBitXorExpr: simple bitxor exprs} {expr 0^7} 7 test compExpr-old-6.6 {CompileBitXorExpr: simple bitxor exprs} {expr -1^7} -8 test compExpr-old-6.7 {CompileBitXorExpr: error compiling bitxor arm} { catch {expr 2**3|6} msg set msg } {syntax error in expression "2**3|6": unexpected operator *} test compExpr-old-6.8 {CompileBitXorExpr: error compiling bitxor arm} { catch {expr 2^x} msg set msg } {syntax error in expression "2^x": variable references require preceding $} test compExpr-old-6.9 {CompileBitXorExpr: runtime error in bitxor arm} { list [catch {expr {24.0^3}} msg] $msg } {1 {can't use floating-point value as operand of "^"}} test compExpr-old-6.10 {CompileBitXorExpr: runtime error in bitxor arm} { list [catch {expr {"a"^"b"}} msg] $msg } {1 {can't use non-numeric string as operand of "^"}} test compExpr-old-7.1 {CompileBitAndExpr: just equality expr} {expr 3==2} 0 test compExpr-old-7.2 {CompileBitAndExpr: just equality expr} {expr 2.0==2} 1 test compExpr-old-7.3 {CompileBitAndExpr: just equality expr} {expr 3.2!=2.2} 1 test compExpr-old-7.4 {CompileBitAndExpr: just equality expr} {expr {"abc" == "abd"}} 0 test compExpr-old-7.5 {CompileBitAndExpr: error in equality expr} { catch {expr x==3} msg set msg } {syntax error in expression "x==3": variable references require preceding $} test compExpr-old-7.6 {CompileBitAndExpr: simple bitand exprs} {expr 7&0x13} 3 test compExpr-old-7.7 {CompileBitAndExpr: simple bitand exprs} {expr 0xf2&0x53} 82 test compExpr-old-7.8 {CompileBitAndExpr: simple bitand exprs} {expr 3&6} 2 test compExpr-old-7.9 {CompileBitAndExpr: simple bitand exprs} {expr -1&-7} -7 test compExpr-old-7.10 {CompileBitAndExpr: error compiling bitand arm} { catch {expr 2**3&6} msg set msg } {syntax error in expression "2**3&6": unexpected operator *} test compExpr-old-7.11 {CompileBitAndExpr: error compiling bitand arm} { catch {expr 2&x} msg set msg } {syntax error in expression "2&x": variable references require preceding $} test compExpr-old-7.12 {CompileBitAndExpr: runtime error in bitand arm} { list [catch {expr {24.0&3}} msg] $msg } {1 {can't use floating-point value as operand of "&"}} test compExpr-old-7.13 {CompileBitAndExpr: runtime error in bitand arm} { list [catch {expr {"a"&"b"}} msg] $msg } {1 {can't use non-numeric string as operand of "&"}} test compExpr-old-8.1 {CompileEqualityExpr: just relational expr} {expr 3>=2} 1 test compExpr-old-8.2 {CompileEqualityExpr: just relational expr} {expr 2<=2.1} 1 test compExpr-old-8.3 {CompileEqualityExpr: just relational expr} {expr 3.2>"2.2"} 1 test compExpr-old-8.4 {CompileEqualityExpr: just relational expr} {expr {"0y"<"0x12"}} 0 test compExpr-old-8.5 {CompileEqualityExpr: error in relational expr} { catch {expr x>3} msg set msg } {syntax error in expression "x>3": variable references require preceding $} test compExpr-old-8.6 {CompileEqualityExpr: simple equality exprs} {expr 7==0x13} 0 test compExpr-old-8.7 {CompileEqualityExpr: simple equality exprs} {expr -0xf2!=0x53} 1 test compExpr-old-8.8 {CompileEqualityExpr: simple equality exprs} {expr {"12398712938788234-1298379" != ""}} 1 test compExpr-old-8.9 {CompileEqualityExpr: simple equality exprs} {expr -1!="abc"} 1 test compExpr-old-8.10 {CompileEqualityExpr: error compiling equality arm} { catch {expr 2**3==6} msg set msg } {syntax error in expression "2**3==6": unexpected operator *} test compExpr-old-8.11 {CompileEqualityExpr: error compiling equality arm} { catch {expr 2!=x} msg set msg } {syntax error in expression "2!=x": variable references require preceding $} test compExpr-old-9.1 {CompileRelationalExpr: just shift expr} {expr 3<<2} 12 test compExpr-old-9.2 {CompileRelationalExpr: just shift expr} {expr 0xff>>2} 63 test compExpr-old-9.3 {CompileRelationalExpr: just shift expr} {expr -1>>2} -1 test compExpr-old-9.4 {CompileRelationalExpr: just shift expr} {expr {1<<3}} 8 # The following test is different for 32-bit versus 64-bit # architectures because LONG_MIN is different if {0x80000000 > 0} { test compExpr-old-9.5 {CompileRelationalExpr: shift expr producing LONG_MIN} {nonPortable} { expr {1<<63} } -9223372036854775808 } else { test compExpr-old-9.5 {CompileRelationalExpr: shift expr producing LONG_MIN} {nonPortable} { expr {1<<31} } -2147483648 } test compExpr-old-9.6 {CompileRelationalExpr: error in shift expr} { catch {expr x>>3} msg set msg } {syntax error in expression "x>>3": variable references require preceding $} test compExpr-old-9.7 {CompileRelationalExpr: simple relational exprs} {expr 0xff>=+0x3} 1 test compExpr-old-9.8 {CompileRelationalExpr: simple relational exprs} {expr -0xf2<0x3} 1 test compExpr-old-9.9 {CompileRelationalExpr: error compiling relational arm} { catch {expr 2**3>6} msg set msg } {syntax error in expression "2**3>6": unexpected operator *} test compExpr-old-9.10 {CompileRelationalExpr: error compiling relational arm} { catch {expr 2>0x3} 31 test compExpr-old-10.7 {CompileShiftExpr: simple shift exprs} {expr -0xf2<<0x3} -1936 test compExpr-old-10.8 {CompileShiftExpr: error compiling shift arm} { catch {expr 2**3>>6} msg set msg } {syntax error in expression "2**3>>6": unexpected operator *} test compExpr-old-10.9 {CompileShiftExpr: error compiling shift arm} { catch {expr 2<>43}} msg] $msg } {1 {can't use floating-point value as operand of ">>"}} test compExpr-old-10.11 {CompileShiftExpr: runtime error} { list [catch {expr {"a"<<"b"}} msg] $msg } {1 {can't use non-numeric string as operand of "<<"}} test compExpr-old-11.1 {CompileAddExpr: just multiply expr} {expr 4*-2} -8 test compExpr-old-11.2 {CompileAddExpr: just multiply expr} {expr 0xff%2} 1 test compExpr-old-11.3 {CompileAddExpr: just multiply expr} {expr -1/2} -1 test compExpr-old-11.4 {CompileAddExpr: just multiply expr} {expr 7891%0123} 6 test compExpr-old-11.5 {CompileAddExpr: error in multiply expr} { catch {expr x*3} msg set msg } {syntax error in expression "x*3": variable references require preceding $} test compExpr-old-11.6 {CompileAddExpr: simple add exprs} {expr 0xff++0x3} 258 test compExpr-old-11.7 {CompileAddExpr: simple add exprs} {expr -0xf2--0x3} -239 test compExpr-old-11.8 {CompileAddExpr: error compiling add arm} { catch {expr 2**3+6} msg set msg } {syntax error in expression "2**3+6": unexpected operator *} test compExpr-old-11.9 {CompileAddExpr: error compiling add arm} { catch {expr 2-x} msg set msg } {syntax error in expression "2-x": variable references require preceding $} test compExpr-old-11.10 {CompileAddExpr: runtime error} { list [catch {expr {24.0+"xx"}} msg] $msg } {1 {can't use non-numeric string as operand of "+"}} test compExpr-old-11.11 {CompileAddExpr: runtime error} { list [catch {expr {"a"-"b"}} msg] $msg } {1 {can't use non-numeric string as operand of "-"}} test compExpr-old-11.12 {CompileAddExpr: runtime error} { list [catch {expr {3/0}} msg] $msg } {1 {divide by zero}} test compExpr-old-11.13 {CompileAddExpr: runtime error} { list [catch {expr {2.3/0.0}} msg] $msg } {1 {divide by zero}} test compExpr-old-12.1 {CompileMultiplyExpr: just unary expr} {expr ~4} -5 test compExpr-old-12.2 {CompileMultiplyExpr: just unary expr} {expr --5} 5 test compExpr-old-12.3 {CompileMultiplyExpr: just unary expr} {expr !27} 0 test compExpr-old-12.4 {CompileMultiplyExpr: just unary expr} {expr ~0xff00ff} -16711936 test compExpr-old-12.5 {CompileMultiplyExpr: error in unary expr} { catch {expr ~x} msg set msg } {syntax error in expression "~x": variable references require preceding $} test compExpr-old-12.6 {CompileMultiplyExpr: simple multiply exprs} {expr 0xff*0x3} 765 test compExpr-old-12.7 {CompileMultiplyExpr: simple multiply exprs} {expr -0xf2%-0x3} -2 test compExpr-old-12.8 {CompileMultiplyExpr: error compiling multiply arm} { catch {expr 2*3%%6} msg set msg } {syntax error in expression "2*3%%6": unexpected operator %} test compExpr-old-12.9 {CompileMultiplyExpr: error compiling multiply arm} { catch {expr 2*x} msg set msg } {syntax error in expression "2*x": variable references require preceding $} test compExpr-old-12.10 {CompileMultiplyExpr: runtime error} { list [catch {expr {24.0*"xx"}} msg] $msg } {1 {can't use non-numeric string as operand of "*"}} test compExpr-old-12.11 {CompileMultiplyExpr: runtime error} { list [catch {expr {"a"/"b"}} msg] $msg } {1 {can't use non-numeric string as operand of "/"}} test compExpr-old-13.1 {CompileUnaryExpr: unary exprs} {expr -0xff} -255 test compExpr-old-13.2 {CompileUnaryExpr: unary exprs} {expr +000123} 83 test compExpr-old-13.3 {CompileUnaryExpr: unary exprs} {expr +--++36} 36 test compExpr-old-13.4 {CompileUnaryExpr: unary exprs} {expr !2} 0 test compExpr-old-13.5 {CompileUnaryExpr: unary exprs} {expr +--+-62.0} -62.0 test compExpr-old-13.6 {CompileUnaryExpr: unary exprs} {expr !0.0} 1 test compExpr-old-13.7 {CompileUnaryExpr: unary exprs} {expr !0xef} 0 test compExpr-old-13.8 {CompileUnaryExpr: error compiling unary expr} { catch {expr ~x} msg set msg } {syntax error in expression "~x": variable references require preceding $} test compExpr-old-13.9 {CompileUnaryExpr: error compiling unary expr} { catch {expr !1.x} msg set msg } {syntax error in expression "!1.x": extra tokens at end of expression} test compExpr-old-13.10 {CompileUnaryExpr: runtime error} { list [catch {expr {~"xx"}} msg] $msg } {1 {can't use non-numeric string as operand of "~"}} test compExpr-old-13.11 {CompileUnaryExpr: runtime error} { list [catch {expr ~4.0} msg] $msg } {1 {can't use floating-point value as operand of "~"}} test compExpr-old-13.12 {CompileUnaryExpr: just primary expr} {expr 0x123} 291 test compExpr-old-13.13 {CompileUnaryExpr: just primary expr} { set a 27 expr $a } 27 test compExpr-old-13.14 {CompileUnaryExpr: just primary expr} { expr double(27) } 27.0 test compExpr-old-13.15 {CompileUnaryExpr: just primary expr} {expr "123"} 123 test compExpr-old-13.16 {CompileUnaryExpr: error in primary expr} { catch {expr [set]} msg set msg } {wrong # args: should be "set varName ?newValue?"} test compExpr-old-14.1 {CompilePrimaryExpr: literal primary} {expr 1} 1 test compExpr-old-14.2 {CompilePrimaryExpr: literal primary} {expr 123} 123 test compExpr-old-14.3 {CompilePrimaryExpr: literal primary} {expr 0xff} 255 test compExpr-old-14.4 {CompilePrimaryExpr: literal primary} {expr 00010} 8 test compExpr-old-14.5 {CompilePrimaryExpr: literal primary} {expr 62.0} 62.0 test compExpr-old-14.6 {CompilePrimaryExpr: literal primary} { expr 3.1400000 } 3.14 test compExpr-old-14.7 {CompilePrimaryExpr: literal primary} {expr {{abcde}<{abcdef}}} 1 test compExpr-old-14.8 {CompilePrimaryExpr: literal primary} {expr {{abc\ def} < {abcdef}}} 1 test compExpr-old-14.9 {CompilePrimaryExpr: literal primary} {expr {{abc\tde} > {abc\tdef}}} 0 test compExpr-old-14.10 {CompilePrimaryExpr: literal primary} {expr {{123}}} 123 test compExpr-old-14.11 {CompilePrimaryExpr: var reference primary} { set i 789 list [expr {$i}] [expr $i] } {789 789} test compExpr-old-14.12 {CompilePrimaryExpr: var reference primary} { set i {789} ;# test expr's aggressive conversion to numeric semantics list [expr {$i}] [expr $i] } {789 789} test compExpr-old-14.13 {CompilePrimaryExpr: var reference primary} { catch {unset a} set a(foo) foo set a(bar) bar set a(123) 123 set result "" lappend result [expr $a(123)] [expr {$a(bar)<$a(foo)}] catch {unset a} set result } {123 1} test compExpr-old-14.14 {CompilePrimaryExpr: var reference primary} { set i 123 ;# test "$var.0" floating point conversion hack list [expr $i] [expr $i.0] [expr $i.0/12.0] } {123 123.0 10.25} test compExpr-old-14.15 {CompilePrimaryExpr: var reference primary} { set i 123 catch {expr $i.2} msg set msg } 123.2 test compExpr-old-14.16 {CompilePrimaryExpr: error compiling var reference primary} { catch {expr {$a(foo}} msg set errorInfo } {missing ) while compiling "expr {$a(foo}"} test compExpr-old-14.17 {CompilePrimaryExpr: string primary that looks like var ref} { expr $ } $ test compExpr-old-14.18 {CompilePrimaryExpr: quoted string primary} { expr "21" } 21 test compExpr-old-14.19 {CompilePrimaryExpr: quoted string primary} { set i 123 set x 456 expr "$i+$x" } 579 test compExpr-old-14.20 {CompilePrimaryExpr: quoted string primary} { set i 3 set x 6 expr 2+"$i.$x" } 5.6 test compExpr-old-14.21 {CompilePrimaryExpr: error in quoted string primary} { catch {expr "[set]"} msg set msg } {wrong # args: should be "set varName ?newValue?"} test compExpr-old-14.22 {CompilePrimaryExpr: subcommand primary} { expr {[set i 123; set i]} } 123 test compExpr-old-14.23 {CompilePrimaryExpr: error in subcommand primary} { catch {expr {[set]}} msg set errorInfo } {wrong # args: should be "set varName ?newValue?" while compiling "set" while compiling "expr {[set]}"} test compExpr-old-14.24 {CompilePrimaryExpr: error in subcommand primary} { catch {expr {[set i}} msg set errorInfo } {missing close-bracket while compiling "expr {[set i}"} test compExpr-old-14.25 {CompilePrimaryExpr: math function primary} { format %.6g [expr exp(1.0)] } 2.71828 test compExpr-old-14.26 {CompilePrimaryExpr: math function primary} { format %.6g [expr pow(2.0+0.1,3.0+0.1)] } 9.97424 test compExpr-old-14.27 {CompilePrimaryExpr: error in math function primary} { catch {expr sinh::(2.0)} msg set errorInfo } {syntax error in expression "sinh::(2.0)": expected parenthesis enclosing function arguments while compiling "expr sinh::(2.0)"} test compExpr-old-14.28 {CompilePrimaryExpr: subexpression primary} { expr 2+(3*4) } 14 test compExpr-old-14.29 {CompilePrimaryExpr: error in subexpression primary} { catch {expr 2+(3*[set])} msg set errorInfo } {wrong # args: should be "set varName ?newValue?" while compiling "set" while compiling "expr 2+(3*[set])"} test compExpr-old-14.30 {CompilePrimaryExpr: missing paren in subexpression primary} { catch {expr 2+(3*(4+5)} msg set errorInfo } {syntax error in expression "2+(3*(4+5)": looking for close parenthesis while compiling "expr 2+(3*(4+5)"} test compExpr-old-14.31 {CompilePrimaryExpr: just var ref in subexpression primary} { set i "5+10" list "[expr $i] == 15" "[expr ($i)] == 15" "[eval expr ($i)] == 15" } {{15 == 15} {15 == 15} {15 == 15}} test compExpr-old-14.32 {CompilePrimaryExpr: unexpected token} { catch {expr @} msg set errorInfo } {syntax error in expression "@": character not legal in expressions while compiling "expr @"} test compExpr-old-15.1 {CompileMathFuncCall: missing parenthesis} { catch {expr sinh2.0)} msg set errorInfo } {syntax error in expression "sinh2.0)": variable references require preceding $ while compiling "expr sinh2.0)"} test compExpr-old-15.2 {CompileMathFuncCall: unknown math function} { catch {expr whazzathuh(1)} msg set errorInfo } {unknown math function "whazzathuh" while compiling "expr whazzathuh(1)"} test compExpr-old-15.3 {CompileMathFuncCall: too many arguments} { catch {expr sin(1,2,3)} msg set errorInfo } {too many arguments for math function while compiling "expr sin(1,2,3)"} test compExpr-old-15.4 {CompileMathFuncCall: ')' found before last required arg} { catch {expr sin()} msg set errorInfo } {too few arguments for math function while compiling "expr sin()"} test compExpr-old-15.5 {CompileMathFuncCall: too few arguments} { catch {expr pow(1)} msg set errorInfo } {too few arguments for math function while compiling "expr pow(1)"} test compExpr-old-15.6 {CompileMathFuncCall: missing ')'} { catch {expr sin(1} msg set errorInfo } {syntax error in expression "sin(1": missing close parenthesis at end of function call while compiling "expr sin(1"} if $gotT1 { test compExpr-old-15.7 {CompileMathFuncCall: call registered math function} { expr 2*T1() } 246 test compExpr-old-15.8 {CompileMathFuncCall: call registered math function} { expr T2()*3 } 1035 test compExpr-old-15.9 {CompileMathFuncCall: call registered math function} { expr T3(21, 37) } 37 test compExpr-old-15.10 {CompileMathFuncCall: call registered math function} { expr T3(21.2, 37) } 37.0 test compExpr-old-15.11 {CompileMathFuncCall: call registered math function} { expr T3(-21.2, -17.5) } -17.5 } test compExpr-old-16.1 {GetToken: checks whether integer token starting with "0x" (e.g., "0x$") is invalid} { catch {unset a} set a(VALUE) ff15 set i 123 if {[expr 0x$a(VALUE)] & 16} { set i {} } set i } {} test compExpr-old-16.2 {GetToken: check for string literal in braces} { expr {{1}} } {1} # Check "expr" and computed command names. test compExpr-old-17.1 {expr and computed command names} { set i 0 set z expr $z 1+2 } 3 # Check correct conversion of operands to numbers: If the string looks like # an integer, convert to integer. Otherwise, if the string looks like a # double, convert to double. test compExpr-old-18.1 {expr and conversion of operands to numbers} { set x [lindex 11 0] catch {expr int($x)} expr {$x} } 11 # Check "expr" and interpreter result object resetting before appending # an error msg during evaluation of exprs not in {}s test compExpr-old-19.1 {expr and interpreter result object resetting} { proc p {} { set t 10.0 set x 2.0 set dx 0.2 set f {$dx-$x/10} set g {-$x/5} set center 1.0 set x [expr $x-$center] set dx [expr $dx+$g] set x [expr $x+$f+$center] set x [expr $x+$f+$center] set y [expr round($x)] } p } 3 # cleanup if {[info exists a]} { unset a } ::tcltest::cleanupTests return tcl8.4.20/tests/upvar.test0000644003604700454610000002325611737050674014127 0ustar dgp771div# Commands covered: upvar # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } test upvar-1.1 {reading variables with upvar} { proc p1 {a b} {set c 22; set d 33; p2} proc p2 {} {upvar a x1 b x2 c x3 d x4; set a abc; list $x1 $x2 $x3 $x4 $a} p1 foo bar } {foo bar 22 33 abc} test upvar-1.2 {reading variables with upvar} { proc p1 {a b} {set c 22; set d 33; p2} proc p2 {} {p3} proc p3 {} {upvar 2 a x1 b x2 c x3 d x4; set a abc; list $x1 $x2 $x3 $x4 $a} p1 foo bar } {foo bar 22 33 abc} test upvar-1.3 {reading variables with upvar} { proc p1 {a b} {set c 22; set d 33; p2} proc p2 {} {p3} proc p3 {} { upvar #1 a x1 b x2 c x3 d x4 set a abc list $x1 $x2 $x3 $x4 $a } p1 foo bar } {foo bar 22 33 abc} test upvar-1.4 {reading variables with upvar} { set x1 44 set x2 55 proc p1 {} {p2} proc p2 {} { upvar 2 x1 x1 x2 a upvar #0 x1 b set c $b incr b 3 list $x1 $a $b } p1 } {47 55 47} test upvar-1.5 {reading array elements with upvar} { proc p1 {} {set a(0) zeroth; set a(1) first; p2} proc p2 {} {upvar a(0) x; set x} p1 } {zeroth} test upvar-2.1 {writing variables with upvar} { proc p1 {a b} {set c 22; set d 33; p2; list $a $b $c $d} proc p2 {} { upvar a x1 b x2 c x3 d x4 set x1 14 set x4 88 } p1 foo bar } {14 bar 22 88} test upvar-2.2 {writing variables with upvar} { set x1 44 set x2 55 proc p1 {x1 x2} { upvar #0 x1 a upvar x2 b set a $x1 set b $x2 } p1 newbits morebits list $x1 $x2 } {newbits morebits} test upvar-2.3 {writing variables with upvar} { catch {unset x1} catch {unset x2} proc p1 {x1 x2} { upvar #0 x1 a upvar x2 b set a $x1 set b $x2 } p1 newbits morebits list [catch {set x1} msg] $msg [catch {set x2} msg] $msg } {0 newbits 0 morebits} test upvar-2.4 {writing array elements with upvar} { proc p1 {} {set a(0) zeroth; set a(1) first; list [p2] $a(0)} proc p2 {} {upvar a(0) x; set x xyzzy} p1 } {xyzzy xyzzy} test upvar-3.1 {unsetting variables with upvar} { proc p1 {a b} {set c 22; set d 33; p2; lsort [info vars]} proc p2 {} { upvar 1 a x1 d x2 unset x1 x2 } p1 foo bar } {b c} test upvar-3.2 {unsetting variables with upvar} { proc p1 {a b} {set c 22; set d 33; p2; lsort [info vars]} proc p2 {} { upvar 1 a x1 d x2 unset x1 x2 set x2 28 } p1 foo bar } {b c d} test upvar-3.3 {unsetting variables with upvar} { set x1 44 set x2 55 proc p1 {} {p2} proc p2 {} { upvar 2 x1 a upvar #0 x2 b unset a b } p1 list [info exists x1] [info exists x2] } {0 0} test upvar-3.4 {unsetting variables with upvar} { set x1 44 set x2 55 proc p1 {} { upvar x1 a x2 b unset a b set b 118 } p1 list [info exists x1] [catch {set x2} msg] $msg } {0 0 118} test upvar-3.5 {unsetting array elements with upvar} { proc p1 {} { set a(0) zeroth set a(1) first set a(2) second p2 array names a } proc p2 {} {upvar a(0) x; unset x} p1 } {1 2} test upvar-3.6 {unsetting then resetting array elements with upvar} { proc p1 {} { set a(0) zeroth set a(1) first set a(2) second p2 list [array names a] [catch {set a(0)} msg] $msg } proc p2 {} {upvar a(0) x; unset x; set x 12345} p1 } {{0 1 2} 0 12345} test upvar-4.1 {nested upvars} { set x1 88 proc p1 {a b} {set c 22; set d 33; p2} proc p2 {} {global x1; upvar c x2; p3} proc p3 {} { upvar x1 a x2 b list $a $b } p1 14 15 } {88 22} test upvar-4.2 {nested upvars} { set x1 88 proc p1 {a b} {set c 22; set d 33; p2; list $a $b $c $d} proc p2 {} {global x1; upvar c x2; p3} proc p3 {} { upvar x1 a x2 b set a foo set b bar } list [p1 14 15] $x1 } {{14 15 bar 33} foo} proc tproc {args} {global x; set x [list $args [uplevel info vars]]} test upvar-5.1 {traces involving upvars} { proc p1 {a b} {set c 22; set d 33; trace var c rw tproc; p2} proc p2 {} {upvar c x1; set x1 22} set x --- p1 foo bar set x } {{x1 {} w} x1} test upvar-5.2 {traces involving upvars} { proc p1 {a b} {set c 22; set d 33; trace var c rw tproc; p2} proc p2 {} {upvar c x1; set x1} set x --- p1 foo bar set x } {{x1 {} r} x1} test upvar-5.3 {traces involving upvars} { proc p1 {a b} {set c 22; set d 33; trace var c rwu tproc; p2} proc p2 {} {upvar c x1; unset x1} set x --- p1 foo bar set x } {{x1 {} u} x1} test upvar-6.1 {retargeting an upvar} { proc p1 {} { set a(0) zeroth set a(1) first set a(2) second p2 } proc p2 {} { upvar a x set result {} foreach i [array names x] { upvar a($i) x lappend result $x } lsort $result } p1 } {first second zeroth} test upvar-6.2 {retargeting an upvar} { set x 44 set y abcde proc p1 {} { global x set result $x upvar y x lappend result $x } p1 } {44 abcde} test upvar-6.3 {retargeting an upvar} { set x 44 set y abcde proc p1 {} { upvar y x lappend result $x global x lappend result $x } p1 } {abcde 44} test upvar-7.1 {upvar to same level} { set x 44 set y 55 catch {unset uv} upvar #0 x uv set uv abc upvar 0 y uv set uv xyzzy list $x $y } {abc xyzzy} test upvar-7.2 {upvar to same level} { set x 1234 set y 4567 proc p1 {x y} { upvar 0 x uv set uv $y return "$x $y" } p1 44 89 } {89 89} test upvar-7.3 {upvar to same level} { set x 1234 set y 4567 proc p1 {x y} { upvar #1 x uv set uv $y return "$x $y" } p1 xyz abc } {abc abc} test upvar-7.4 {upvar to same level: tricky problems when deleting variable table} { proc tt {} {upvar #1 toto loc; return $loc} list [catch tt msg] $msg } {1 {can't read "loc": no such variable}} test upvar-7.5 {potential memory leak when deleting variable table} { proc leak {} { array set foo {1 2 3 4} upvar 0 foo(1) bar } leak } {} test upvar-8.1 {errors in upvar command} { list [catch upvar msg] $msg } {1 {wrong # args: should be "upvar ?level? otherVar localVar ?otherVar localVar ...?"}} test upvar-8.2 {errors in upvar command} { list [catch {upvar 1} msg] $msg } {1 {wrong # args: should be "upvar ?level? otherVar localVar ?otherVar localVar ...?"}} test upvar-8.3 {errors in upvar command} { proc p1 {} {upvar a b c} list [catch p1 msg] $msg } {1 {wrong # args: should be "upvar ?level? otherVar localVar ?otherVar localVar ...?"}} test upvar-8.4 {errors in upvar command} { proc p1 {} {upvar 0 b b} list [catch p1 msg] $msg } {1 {can't upvar from variable to itself}} test upvar-8.5 {errors in upvar command} { proc p1 {} {upvar 0 a b; upvar 0 b a} list [catch p1 msg] $msg } {1 {can't upvar from variable to itself}} test upvar-8.6 {errors in upvar command} { proc p1 {} {set a 33; upvar b a} list [catch p1 msg] $msg } {1 {variable "a" already exists}} test upvar-8.7 {errors in upvar command} { proc p1 {} {trace variable a w foo; upvar b a} list [catch p1 msg] $msg } {1 {variable "a" has traces: can't use for upvar}} test upvar-8.8 {create nested array with upvar} { proc p1 {} {upvar x(a) b; set b(2) 44} catch {unset x} list [catch p1 msg] $msg } {1 {can't set "b(2)": variable isn't array}} test upvar-8.9 {upvar won't create namespace variable that refers to procedure variable} { catch {eval namespace delete [namespace children :: test_ns_*]} catch {rename MakeLink ""} namespace eval ::test_ns_1 {} proc MakeLink {a} { namespace eval ::test_ns_1 { upvar a a } unset ::test_ns_1::a } list [catch {MakeLink 1} msg] $msg } {1 {bad variable name "a": upvar won't create namespace variable that refers to procedure variable}} test upvar-8.10 {upvar will create element alias for new array element} { catch {unset upvarArray} array set upvarArray {} catch {upvar 0 upvarArray(elem) upvarArrayElemAlias} } {0} if {[info commands testupvar] != {}} { test upvar-9.1 {Tcl_UpVar2 procedure} { list [catch {testupvar xyz a {} x global} msg] $msg } {1 {bad level "xyz"}} test upvar-9.2 {Tcl_UpVar2 procedure} { catch {unset a} catch {unset x} set a 44 list [catch {testupvar #0 a 1 x global} msg] $msg } {1 {can't access "a(1)": variable isn't array}} test upvar-9.3 {Tcl_UpVar2 procedure} { proc foo {} { testupvar 1 a {} x local set x } catch {unset a} catch {unset x} set a 44 foo } {44} test upvar-9.4 {Tcl_UpVar2 procedure} { proc foo {} { testupvar 1 a {} _up_ global list [catch {set x} msg] $msg } catch {unset a} catch {unset _up_} set a 44 concat [foo] $_up_ } {1 {can't read "x": no such variable} 44} test upvar-9.5 {Tcl_UpVar2 procedure} { proc foo {} { testupvar 1 a b x local set x } catch {unset a} catch {unset x} set a(b) 1234 foo } {1234} test upvar-9.6 {Tcl_UpVar procedure} { proc foo {} { testupvar 1 a x local set x } catch {unset a} catch {unset x} set a xyzzy foo } {xyzzy} test upvar-9.7 {Tcl_UpVar procedure} { proc foo {} { testupvar #0 a(b) x local set x } catch {unset a} catch {unset x} set a(b) 1234 foo } {1234} } catch {unset a} # cleanup ::tcltest::cleanupTests return tcl8.4.20/tests/cmdInfo.test0000644003604700454610000000703711737050674014350 0ustar dgp771div# Commands covered: none # # This file contains a collection of tests for Tcl_GetCommandInfo, # Tcl_SetCommandInfo, Tcl_CreateCommand, Tcl_DeleteCommand, and # Tcl_NameOfCommand. Sourcing this file into Tcl runs the tests # and generates output for errors. No output means no errors were # found. # # Copyright (c) 1993 The Regents of the University of California. # Copyright (c) 1994-1996 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import -force ::tcltest::* } ::tcltest::testConstraint testcmdinfo \ [llength [info commands testcmdinfo]] ::tcltest::testConstraint testcmdtoken \ [llength [info commands testcmdtoken]] test cmdinfo-1.1 {command procedure and clientData} {testcmdinfo} { testcmdinfo create x1 testcmdinfo get x1 } {CmdProc1 original CmdDelProc1 original :: stringProc} test cmdinfo-1.2 {command procedure and clientData} {testcmdinfo} { testcmdinfo create x1 x1 } {CmdProc1 original} test cmdinfo-1.3 {command procedure and clientData} {testcmdinfo} { testcmdinfo create x1 testcmdinfo modify x1 testcmdinfo get x1 } {CmdProc2 new_command_data CmdDelProc2 new_delete_data :: stringProc} test cmdinfo-1.4 {command procedure and clientData} {testcmdinfo} { testcmdinfo create x1 testcmdinfo modify x1 x1 } {CmdProc2 new_command_data} test cmdinfo-2.1 {command deletion callbacks} {testcmdinfo} { testcmdinfo create x1 testcmdinfo delete x1 } {CmdDelProc1 original} test cmdinfo-2.2 {command deletion callbacks} {testcmdinfo} { testcmdinfo create x1 testcmdinfo modify x1 testcmdinfo delete x1 } {CmdDelProc2 new_delete_data} test cmdinfo-3.1 {Tcl_Get/SetCommandInfo return values} {testcmdinfo} { testcmdinfo get non_existent } {??} test cmdinfo-3.2 {Tcl_Get/SetCommandInfo return values} {testcmdinfo} { testcmdinfo create x1 testcmdinfo modify x1 } 1 test cmdinfo-3.3 {Tcl_Get/SetCommandInfo return values} {testcmdinfo} { testcmdinfo modify non_existent } 0 test cmdinfo-4.1 {Tcl_GetCommandName/Tcl_GetCommandFullName procedures} \ {testcmdtoken} { set x [testcmdtoken create x1] rename x1 newName set y [testcmdtoken name $x] rename newName x1 eval lappend y [testcmdtoken name $x] } {newName ::newName x1 ::x1} catch {rename newTestCmd {}} catch {rename newTestCmd2 {}} test cmdinfo-5.1 {Names for commands created when inside namespaces} \ {testcmdtoken} { # create namespace cmdInfoNs1 namespace eval cmdInfoNs1 {} ;# creates namespace cmdInfoNs1 # create namespace cmdInfoNs1::cmdInfoNs2 and execute a script in it set x [namespace eval cmdInfoNs1::cmdInfoNs2 { # the following creates a cmd in the global namespace testcmdtoken create testCmd }] set y [testcmdtoken name $x] rename ::testCmd newTestCmd eval lappend y [testcmdtoken name $x] } {testCmd ::testCmd newTestCmd ::newTestCmd} test cmdinfo-6.1 {Names for commands created when outside namespaces} \ {testcmdtoken} { set x [testcmdtoken create cmdInfoNs1::cmdInfoNs2::testCmd] set y [testcmdtoken name $x] rename cmdInfoNs1::cmdInfoNs2::testCmd newTestCmd2 eval lappend y [testcmdtoken name $x] } {testCmd ::cmdInfoNs1::cmdInfoNs2::testCmd newTestCmd2 ::newTestCmd2} # cleanup catch {namespace delete cmdInfoNs1::cmdInfoNs2 cmdInfoNs1} catch {rename x1 ""} ::tcltest::cleanupTests return tcl8.4.20/tests/set.test0000644003604700454610000004153211737050674013562 0ustar dgp771div# Commands covered: set # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1996 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import -force ::tcltest::* } catch {unset x} catch {unset i} test set-1.1 {TclCompileSetCmd: missing variable name} { list [catch {set} msg] $msg } {1 {wrong # args: should be "set varName ?newValue?"}} test set-1.2 {TclCompileSetCmd: simple variable name} { set i 10 list [set i] $i } {10 10} test set-1.3 {TclCompileSetCmd: error compiling variable name} { set i 10 catch {set "i"xxx} msg set msg } {extra characters after close-quote} test set-1.4 {TclCompileSetCmd: simple variable name in quotes} { set i 17 list [set "i"] $i } {17 17} test set-1.5 {TclCompileSetCmd: simple variable name in braces} { catch {unset {a simple var}} set {a simple var} 27 list [set {a simple var}] ${a simple var} } {27 27} test set-1.6 {TclCompileSetCmd: simple array variable name} { catch {unset a} set a(foo) 37 list [set a(foo)] $a(foo) } {37 37} test set-1.7 {TclCompileSetCmd: non-simple (computed) variable name} { set x "i" set i 77 list [set $x] $i } {77 77} test set-1.8 {TclCompileSetCmd: non-simple (computed) variable name} { set x "i" set i 77 list [set [set x] 2] $i } {2 2} test set-1.9 {TclCompileSetCmd: 3rd arg => assignment} { set i "abcdef" list [set i] $i } {abcdef abcdef} test set-1.10 {TclCompileSetCmd: only two args => just getting value} { set i {one two} set i } {one two} test set-1.11 {TclCompileSetCmd: simple global name} { proc p {} { global i set i 54 set i } p } {54} test set-1.12 {TclCompileSetCmd: simple local name} { proc p {bar} { set foo $bar set foo } p 999 } {999} test set-1.13 {TclCompileSetCmd: simple but new (unknown) local name} { proc p {} { set bar } catch {p} msg set msg } {can't read "bar": no such variable} test set-1.14 {TclCompileSetCmd: simple local name, >255 locals} { proc 260locals {} { # create 260 locals (the last ones with index > 255) set a0 0; set a1 0; set a2 0; set a3 0; set a4 0 set a5 0; set a6 0; set a7 0; set a8 0; set a9 0 set b0 0; set b1 0; set b2 0; set b3 0; set b4 0 set b5 0; set b6 0; set b7 0; set b8 0; set b9 0 set c0 0; set c1 0; set c2 0; set c3 0; set c4 0 set c5 0; set c6 0; set c7 0; set c8 0; set c9 0 set d0 0; set d1 0; set d2 0; set d3 0; set d4 0 set d5 0; set d6 0; set d7 0; set d8 0; set d9 0 set e0 0; set e1 0; set e2 0; set e3 0; set e4 0 set e5 0; set e6 0; set e7 0; set e8 0; set e9 0 set f0 0; set f1 0; set f2 0; set f3 0; set f4 0 set f5 0; set f6 0; set f7 0; set f8 0; set f9 0 set g0 0; set g1 0; set g2 0; set g3 0; set g4 0 set g5 0; set g6 0; set g7 0; set g8 0; set g9 0 set h0 0; set h1 0; set h2 0; set h3 0; set h4 0 set h5 0; set h6 0; set h7 0; set h8 0; set h9 0 set i0 0; set i1 0; set i2 0; set i3 0; set i4 0 set i5 0; set i6 0; set i7 0; set i8 0; set i9 0 set j0 0; set j1 0; set j2 0; set j3 0; set j4 0 set j5 0; set j6 0; set j7 0; set j8 0; set j9 0 set k0 0; set k1 0; set k2 0; set k3 0; set k4 0 set k5 0; set k6 0; set k7 0; set k8 0; set k9 0 set l0 0; set l1 0; set l2 0; set l3 0; set l4 0 set l5 0; set l6 0; set l7 0; set l8 0; set l9 0 set m0 0; set m1 0; set m2 0; set m3 0; set m4 0 set m5 0; set m6 0; set m7 0; set m8 0; set m9 0 set n0 0; set n1 0; set n2 0; set n3 0; set n4 0 set n5 0; set n6 0; set n7 0; set n8 0; set n9 0 set o0 0; set o1 0; set o2 0; set o3 0; set o4 0 set o5 0; set o6 0; set o7 0; set o8 0; set o9 0 set p0 0; set p1 0; set p2 0; set p3 0; set p4 0 set p5 0; set p6 0; set p7 0; set p8 0; set p9 0 set q0 0; set q1 0; set q2 0; set q3 0; set q4 0 set q5 0; set q6 0; set q7 0; set q8 0; set q9 0 set r0 0; set r1 0; set r2 0; set r3 0; set r4 0 set r5 0; set r6 0; set r7 0; set r8 0; set r9 0 set s0 0; set s1 0; set s2 0; set s3 0; set s4 0 set s5 0; set s6 0; set s7 0; set s8 0; set s9 0 set t0 0; set t1 0; set t2 0; set t3 0; set t4 0 set t5 0; set t6 0; set t7 0; set t8 0; set t9 0 set u0 0; set u1 0; set u2 0; set u3 0; set u4 0 set u5 0; set u6 0; set u7 0; set u8 0; set u9 0 set v0 0; set v1 0; set v2 0; set v3 0; set v4 0 set v5 0; set v6 0; set v7 0; set v8 0; set v9 0 set w0 0; set w1 0; set w2 0; set w3 0; set w4 0 set w5 0; set w6 0; set w7 0; set w8 0; set w9 0 set x0 0; set x1 0; set x2 0; set x3 0; set x4 0 set x5 0; set x6 0; set x7 0; set x8 0; set x9 0 set y0 0; set y1 0; set y2 0; set y3 0; set y4 0 set y5 0; set y6 0; set y7 0; set y8 0; set y9 0 set z0 0; set z1 0; set z2 0; set z3 0; set z4 0 set z5 0; set z6 0; set z7 0; set z8 0; set z9 1234 } 260locals } {1234} test set-1.15 {TclCompileSetCmd: variable is array} { catch {unset a} set x 27 set x [set a(foo) 11] catch {unset a} set x } 11 test set-1.16 {TclCompileSetCmd: variable is array, elem substitutions} { catch {unset a} set i 5 set x 789 set a(foo5) 27 set x [set a(foo$i)] catch {unset a} set x } 27 test set-1.17 {TclCompileSetCmd: doing assignment, simple int} { set i 5 set i 123 } 123 test set-1.18 {TclCompileSetCmd: doing assignment, simple int} { set i 5 set i -100 } -100 test set-1.19 {TclCompileSetCmd: doing assignment, simple but not int} { set i 5 set i 0x12MNOP set i } {0x12MNOP} test set-1.20 {TclCompileSetCmd: doing assignment, in quotes} { set i 25 set i "-100" } -100 test set-1.21 {TclCompileSetCmd: doing assignment, in braces} { set i 24 set i {126} } 126 test set-1.22 {TclCompileSetCmd: doing assignment, large int} { set i 5 set i 200000 } 200000 test set-1.23 {TclCompileSetCmd: doing assignment, formatted int != int} { set i 25 set i 000012345 ;# an octal literal == 5349 decimal list $i [incr i] } {000012345 5350} test set-1.24 {TclCompileSetCmd: too many arguments} { set i 10 catch {set i 20 30} msg set msg } {wrong # args: should be "set varName ?newValue?"} test set-1.25 {TclCompileSetCmd: var is array, braced (no subs)} { # This was a known error in 8.1a* - 8.2.1 catch {unset array} set {array($foo)} 5 } 5 test set-1.26 {TclCompileSetCmd: various array constructs} { # Test all kinds of array constructs that TclCompileSetCmd # may feel inclined to tamper with. proc p {} { set a x set be(hej) 1 ; # hej set be($a) 1 ; # x set {be($a)} 1 ; # $a set be($a,hej) 1 ; # x,hej set be($a,$a) 5 ; # x,x set be(c($a) 1 ; # c(x set be(\w\w) 1 ; # ww set be(a:$a) [set be(x,$a)] ; # a:x set be(hej,$be($a,hej),hej) 1 ; # hej,1,hej set be([string range hugge 0 2]) 1 ; # hug set be(a\ a) 1 ; # a a set be($a\ ,[string range hugge 1 3],hej) 1 ; # x ,ugg,hej set be($a,h"ej) 1 ; # x,h"ej set be([string range "a b c" 2 end]) 1 ; # b c set [string range bet 0 1](foo) 1 ; # foo set be([set be(a:$a)][set b\e($a)]) 1 ; # 51 return [lsort [array names be]] } p } [lsort {hej x $a x,hej x,x c(x ww a:x hej,1,hej hug {a a} {x ,ugg,hej} x,h"ej {b c} foo 51}]; # " just a matching end quote test set-2.1 {set command: runtime error, bad variable name} { list [catch {set {"foo}} msg] $msg $errorInfo } {1 {can't read ""foo": no such variable} {can't read ""foo": no such variable while executing "set {"foo}"}} test set-2.2 {set command: runtime error, not array variable} { catch {unset b} set b 44 list [catch {set b(123)} msg] $msg } {1 {can't read "b(123)": variable isn't array}} test set-2.3 {set command: runtime error, errors in reading variables} { catch {unset a} set a(6) 44 list [catch {set a(18)} msg] $msg } {1 {can't read "a(18)": no such element in array}} test set-2.4 {set command: runtime error, readonly variable} { proc readonly args {error "variable is read-only"} set x 123 trace var x w readonly list [catch {set x 1} msg] $msg $errorInfo } {1 {can't set "x": variable is read-only} {can't set "x": variable is read-only while executing "set x 1"}} test set-2.5 {set command: runtime error, basic array operations} { list [catch {set a(other)} msg] $msg } {1 {can't read "a(other)": no such element in array}} test set-2.6 {set command: runtime error, basic array operations} { list [catch {set a} msg] $msg } {1 {can't read "a": variable is array}} # Test the uncompiled version of set catch {unset a} catch {unset b} catch {unset i} catch {unset x} test set-3.1 {uncompiled set command: missing variable name} { set z set list [catch {$z} msg] $msg } {1 {wrong # args: should be "set varName ?newValue?"}} test set-3.2 {uncompiled set command: simple variable name} { set z set $z i 10 list [$z i] $i } {10 10} test set-3.3 {uncompiled set command: error compiling variable name} { set z set $z i 10 catch {$z "i"xxx} msg $z msg } {extra characters after close-quote} test set-3.4 {uncompiled set command: simple variable name in quotes} { set z set $z i 17 list [$z "i"] $i } {17 17} test set-3.5 {uncompiled set command: simple variable name in braces} { set z set catch {unset {a simple var}} $z {a simple var} 27 list [$z {a simple var}] ${a simple var} } {27 27} test set-3.6 {uncompiled set command: simple array variable name} { set z set catch {unset a} $z a(foo) 37 list [$z a(foo)] $a(foo) } {37 37} test set-3.7 {uncompiled set command: non-simple (computed) variable name} { set z set $z x "i" $z i 77 list [$z $x] $i } {77 77} test set-3.8 {uncompiled set command: non-simple (computed) variable name} { set z set $z x "i" $z i 77 list [$z [$z x] 2] $i } {2 2} test set-3.9 {uncompiled set command: 3rd arg => assignment} { set z set $z i "abcdef" list [$z i] $i } {abcdef abcdef} test set-3.10 {uncompiled set command: only two args => just getting value} { set z set $z i {one two} $z i } {one two} test set-3.11 {uncompiled set command: simple global name} { proc p {} { set z set global i $z i 54 $z i } p } {54} test set-3.12 {uncompiled set command: simple local name} { proc p {bar} { set z set $z foo $bar $z foo } p 999 } {999} test set-3.13 {uncompiled set command: simple but new (unknown) local name} { set z set proc p {} { set z set $z bar } catch {p} msg $z msg } {can't read "bar": no such variable} test set-3.14 {uncompiled set command: simple local name, >255 locals} { proc 260locals {} { set z set # create 260 locals (the last ones with index > 255) $z a0 0; $z a1 0; $z a2 0; $z a3 0; $z a4 0 $z a5 0; $z a6 0; $z a7 0; $z a8 0; $z a9 0 $z b0 0; $z b1 0; $z b2 0; $z b3 0; $z b4 0 $z b5 0; $z b6 0; $z b7 0; $z b8 0; $z b9 0 $z c0 0; $z c1 0; $z c2 0; $z c3 0; $z c4 0 $z c5 0; $z c6 0; $z c7 0; $z c8 0; $z c9 0 $z d0 0; $z d1 0; $z d2 0; $z d3 0; $z d4 0 $z d5 0; $z d6 0; $z d7 0; $z d8 0; $z d9 0 $z e0 0; $z e1 0; $z e2 0; $z e3 0; $z e4 0 $z e5 0; $z e6 0; $z e7 0; $z e8 0; $z e9 0 $z f0 0; $z f1 0; $z f2 0; $z f3 0; $z f4 0 $z f5 0; $z f6 0; $z f7 0; $z f8 0; $z f9 0 $z g0 0; $z g1 0; $z g2 0; $z g3 0; $z g4 0 $z g5 0; $z g6 0; $z g7 0; $z g8 0; $z g9 0 $z h0 0; $z h1 0; $z h2 0; $z h3 0; $z h4 0 $z h5 0; $z h6 0; $z h7 0; $z h8 0; $z h9 0 $z i0 0; $z i1 0; $z i2 0; $z i3 0; $z i4 0 $z i5 0; $z i6 0; $z i7 0; $z i8 0; $z i9 0 $z j0 0; $z j1 0; $z j2 0; $z j3 0; $z j4 0 $z j5 0; $z j6 0; $z j7 0; $z j8 0; $z j9 0 $z k0 0; $z k1 0; $z k2 0; $z k3 0; $z k4 0 $z k5 0; $z k6 0; $z k7 0; $z k8 0; $z k9 0 $z l0 0; $z l1 0; $z l2 0; $z l3 0; $z l4 0 $z l5 0; $z l6 0; $z l7 0; $z l8 0; $z l9 0 $z m0 0; $z m1 0; $z m2 0; $z m3 0; $z m4 0 $z m5 0; $z m6 0; $z m7 0; $z m8 0; $z m9 0 $z n0 0; $z n1 0; $z n2 0; $z n3 0; $z n4 0 $z n5 0; $z n6 0; $z n7 0; $z n8 0; $z n9 0 $z o0 0; $z o1 0; $z o2 0; $z o3 0; $z o4 0 $z o5 0; $z o6 0; $z o7 0; $z o8 0; $z o9 0 $z p0 0; $z p1 0; $z p2 0; $z p3 0; $z p4 0 $z p5 0; $z p6 0; $z p7 0; $z p8 0; $z p9 0 $z q0 0; $z q1 0; $z q2 0; $z q3 0; $z q4 0 $z q5 0; $z q6 0; $z q7 0; $z q8 0; $z q9 0 $z r0 0; $z r1 0; $z r2 0; $z r3 0; $z r4 0 $z r5 0; $z r6 0; $z r7 0; $z r8 0; $z r9 0 $z s0 0; $z s1 0; $z s2 0; $z s3 0; $z s4 0 $z s5 0; $z s6 0; $z s7 0; $z s8 0; $z s9 0 $z t0 0; $z t1 0; $z t2 0; $z t3 0; $z t4 0 $z t5 0; $z t6 0; $z t7 0; $z t8 0; $z t9 0 $z u0 0; $z u1 0; $z u2 0; $z u3 0; $z u4 0 $z u5 0; $z u6 0; $z u7 0; $z u8 0; $z u9 0 $z v0 0; $z v1 0; $z v2 0; $z v3 0; $z v4 0 $z v5 0; $z v6 0; $z v7 0; $z v8 0; $z v9 0 $z w0 0; $z w1 0; $z w2 0; $z w3 0; $z w4 0 $z w5 0; $z w6 0; $z w7 0; $z w8 0; $z w9 0 $z x0 0; $z x1 0; $z x2 0; $z x3 0; $z x4 0 $z x5 0; $z x6 0; $z x7 0; $z x8 0; $z x9 0 $z y0 0; $z y1 0; $z y2 0; $z y3 0; $z y4 0 $z y5 0; $z y6 0; $z y7 0; $z y8 0; $z y9 0 $z z0 0; $z z1 0; $z z2 0; $z z3 0; $z z4 0 $z z5 0; $z z6 0; $z z7 0; $z z8 0; $z z9 1234 } 260locals } {1234} test set-3.15 {uncompiled set command: variable is array} { set z set catch {unset a} $z x 27 $z x [$z a(foo) 11] catch {unset a} $z x } 11 test set-3.16 {uncompiled set command: variable is array, elem substitutions} { set z set catch {unset a} $z i 5 $z x 789 $z a(foo5) 27 $z x [$z a(foo$i)] catch {unset a} $z x } 27 test set-3.17 {uncompiled set command: doing assignment, simple int} { set z set $z i 5 $z i 123 } 123 test set-3.18 {uncompiled set command: doing assignment, simple int} { set z set $z i 5 $z i -100 } -100 test set-3.19 {uncompiled set command: doing assignment, simple but not int} { set z set $z i 5 $z i 0x12MNOP $z i } {0x12MNOP} test set-3.20 {uncompiled set command: doing assignment, in quotes} { set z set $z i 25 $z i "-100" } -100 test set-3.21 {uncompiled set command: doing assignment, in braces} { set z set $z i 24 $z i {126} } 126 test set-3.22 {uncompiled set command: doing assignment, large int} { set z set $z i 5 $z i 200000 } 200000 test set-3.23 {uncompiled set command: doing assignment, formatted int != int} { set z set $z i 25 $z i 000012345 ;# an octal literal == 5349 decimal list $i [incr i] } {000012345 5350} test set-3.24 {uncompiled set command: too many arguments} { set z set $z i 10 catch {$z i 20 30} msg $z msg } {wrong # args: should be "set varName ?newValue?"} test set-4.1 {uncompiled set command: runtime error, bad variable name} { set z set list [catch {$z {"foo}} msg] $msg $errorInfo } {1 {can't read ""foo": no such variable} {can't read ""foo": no such variable while executing "$z {"foo}"}} test set-4.2 {uncompiled set command: runtime error, not array variable} { set z set catch {unset b} $z b 44 list [catch {$z b(123)} msg] $msg } {1 {can't read "b(123)": variable isn't array}} test set-4.3 {uncompiled set command: runtime error, errors in reading variables} { set z set catch {unset a} $z a(6) 44 list [catch {$z a(18)} msg] $msg } {1 {can't read "a(18)": no such element in array}} test set-4.4 {uncompiled set command: runtime error, readonly variable} { set z set proc readonly args {error "variable is read-only"} $z x 123 trace var x w readonly list [catch {$z x 1} msg] $msg $errorInfo } {1 {can't set "x": variable is read-only} {can't set "x": variable is read-only while executing "$z x 1"}} test set-4.5 {uncompiled set command: runtime error, basic array operations} { set z set list [catch {$z a(other)} msg] $msg } {1 {can't read "a(other)": no such element in array}} test set-4.6 {set command: runtime error, basic array operations} { set z set list [catch {$z a} msg] $msg } {1 {can't read "a": variable is array}} # cleanup catch {unset a} catch {unset b} catch {unset i} catch {unset x} catch {unset z} ::tcltest::cleanupTests return tcl8.4.20/tests/tcltest.test0000755003604700454610000014200211737050674014446 0ustar dgp771div# This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1998-1999 by Scriptics Corporation. # Copyright (c) 2000 by Ajuba Solutions # All rights reserved. # Note that there are several places where the value of # tcltest::currentFailure is stored/reset in the -setup/-cleanup # of a test that has a body that runs [test] that will fail. # This is a workaround of using the same tcltest code that we are # testing to run the test itself. Ditto on things like [verbose]. # # It would be better to have the -body of the tests run the tcltest # commands in a slave interp so the [test] being tested would not # interfere with the [test] doing the testing. # if {[catch {package require tcltest 2.1}]} { puts stderr "Skipping tests in [info script]. tcltest 2.1 required." return } namespace eval ::tcltest::test { namespace import ::tcltest::* makeFile { package require tcltest namespace import ::tcltest::test test a-1.0 {test a} { list 0 } {0} test b-1.0 {test b} { list 1 } {0} test c-1.0 {test c} {knownBug} { } {} test d-1.0 {test d} { error "foo" foo 9 } {} tcltest::cleanupTests exit } test.tcl cd [temporaryDirectory] testConstraint exec [llength [info commands exec]] # test -help # Child processes because -help [exit]s. test tcltest-1.1 {tcltest -help} {exec} { set result [catch {exec [interpreter] test.tcl -help} msg] list $result [regexp Usage $msg] } {1 1} test tcltest-1.2 {tcltest -help -something} {exec} { set result [catch {exec [interpreter] test.tcl -help -something} msg] list $result [regexp Usage $msg] } {1 1} test tcltest-1.3 {tcltest -h} {exec} { set result [catch {exec [interpreter] test.tcl -h} msg] list $result [regexp Usage $msg] } {1 0} # -verbose, implicit & explicit testing of [verbose] proc slave {msgVar args} { upvar 1 $msgVar msg interp create [namespace current]::i # Fake the slave interp into dumping output to a file i eval {namespace eval ::tcltest {}} i eval "set tcltest::outputChannel\ \[[list open [set of [makeFile {} output]] w]]" i eval "set tcltest::errorChannel\ \[[list open [set ef [makeFile {} error]] w]]" i eval [list set argv0 [lindex $args 0]] i eval [list set argv [lrange $args 1 end]] i eval [list package ifneeded tcltest [package provide tcltest] \ [package ifneeded tcltest [package provide tcltest]]] i eval {proc exit args {}} # Need to capture output in msg set code [catch {i eval {source $argv0}} foo] if $code { #puts "$code: $foo\n$::errorInfo" } i eval {close $tcltest::outputChannel} interp delete [namespace current]::i set f [open $of] set msg [read -nonewline $f] close $f set f [open $ef] set err [read -nonewline $f] close $f removeFile output removeFile error if {[string length $err]} { set code 1 append msg \n$err } return $code # return [catch {uplevel 1 [linsert $args 0 exec [interpreter]]} msg] } test tcltest-2.0 {tcltest (verbose default - 'b')} {unixOrPc} { set result [slave msg test.tcl] list $result [regexp "Contents of test case" $msg] [regexp a-1.0 $msg] \ [regexp c-1.0 $msg] \ [regexp "Total.+4.+Passed.+1.+Skipped.+1.+Failed.+2" $msg] } {0 1 0 0 1} test tcltest-2.1 {tcltest -verbose 'b'} {unixOrPc} { set result [slave msg test.tcl -verbose 'b'] list $result [regexp "Contents of test case" $msg] [regexp a-1.0 $msg] \ [regexp c-1.0 $msg] \ [regexp "Total.+4.+Passed.+1.+Skipped.+1.+Failed.+2" $msg] } {0 1 0 0 1} test tcltest-2.2 {tcltest -verbose 'p'} {unixOrPc} { set result [slave msg test.tcl -verbose 'p'] list $result [regexp "Contents of test case" $msg] [regexp a-1.0 $msg] \ [regexp c-1.0 $msg] \ [regexp "Total.+4.+Passed.+1.+Skipped.+1.+Failed.+2" $msg] } {0 0 1 0 1} test tcltest-2.3 {tcltest -verbose 's'} {unixOrPc} { set result [slave msg test.tcl -verbose 's'] list $result [regexp "Contents of test case" $msg] [regexp a-1.0 $msg] \ [regexp c-1.0 $msg] \ [regexp "Total.+4.+Passed.+1.+Skipped.+1.+Failed.+2" $msg] } {0 0 0 1 1} test tcltest-2.4 {tcltest -verbose 'ps'} {unixOrPc} { set result [slave msg test.tcl -verbose 'ps'] list $result [regexp "Contents of test case" $msg] [regexp a-1.0 $msg] \ [regexp c-1.0 $msg] \ [regexp "Total.+4.+Passed.+1.+Skipped.+1.+Failed.+2" $msg] } {0 0 1 1 1} test tcltest-2.5 {tcltest -verbose 'psb'} {unixOrPc} { set result [slave msg test.tcl -verbose 'psb'] list $result [regexp "Contents of test case" $msg] [regexp a-1.0 $msg] \ [regexp c-1.0 $msg] \ [regexp "Total.+4.+Passed.+1.+Skipped.+1.+Failed.+2" $msg] } {0 1 1 1 1} test tcltest-2.5a {tcltest -verbose 'pass skip body'} {unixOrPc} { set result [slave msg test.tcl -verbose "pass skip body"] list $result [regexp "Contents of test case" $msg] [regexp a-1.0 $msg] \ [regexp c-1.0 $msg] \ [regexp "Total.+4.+Passed.+1.+Skipped.+1.+Failed.+2" $msg] } {0 1 1 1 1} test tcltest-2.6 {tcltest -verbose 't'} { -constraints {unixOrPc} -body { set result [slave msg test.tcl -verbose 't'] list $result $msg } -result {^0 .*a-1.0 start.*b-1.0 start} -match regexp } test tcltest-2.6a {tcltest -verbose 'start'} { -constraints {unixOrPc} -body { set result [slave msg test.tcl -verbose start] list $result $msg } -result {^0 .*a-1.0 start.*b-1.0 start} -match regexp } test tcltest-2.7 {tcltest::verbose} { -body { set oldVerbosity [verbose] verbose bar set currentVerbosity [verbose] verbose foo set newVerbosity [verbose] verbose $oldVerbosity list $currentVerbosity $newVerbosity } -result {body {}} } test tcltest-2.8 {tcltest -verbose 'error'} { -constraints {unixOrPc} -body { set result [slave msg test.tcl -verbose error] list $result $msg } -result {errorInfo: foo.*errorCode: 9} -match regexp } # -match, [match] test tcltest-3.1 {tcltest -match 'a*'} {unixOrPc} { set result [slave msg test.tcl -match a* -verbose 'ps'] list $result [regexp a-1.0 $msg] [regexp b-1.0 $msg] [regexp c-1.0 $msg] \ [regexp "Total.+4.+Passed.+1.+Skipped.+3.+Failed.+0" $msg] } {0 1 0 0 1} test tcltest-3.2 {tcltest -match 'b*'} {unixOrPc} { set result [slave msg test.tcl -match b* -verbose 'ps'] list $result [regexp a-1.0 $msg] [regexp b-1.0 $msg] [regexp c-1.0 $msg] \ [regexp "Total.+4.+Passed.+0.+Skipped.+3.+Failed.+1" $msg] } {0 0 1 0 1} test tcltest-3.3 {tcltest -match 'c*'} {unixOrPc} { set result [slave msg test.tcl -match c* -verbose 'ps'] list $result [regexp a-1.0 $msg] [regexp b-1.0 $msg] [regexp c-1.0 $msg] \ [regexp "Total.+4.+Passed.+0.+Skipped.+4.+Failed.+0" $msg] } {0 0 0 1 1} test tcltest-3.4 {tcltest -match 'a* b*'} {unixOrPc} { set result [slave msg test.tcl -match {a* b*} -verbose 'ps'] list $result [regexp a-1.0 $msg] [regexp b-1.0 $msg] [regexp c-1.0 $msg] \ [regexp "Total.+4.+Passed.+1.+Skipped.+2.+Failed.+1" $msg] } {0 1 1 0 1} test tcltest-3.5 {tcltest::match} { -body { set oldMatch [match] match foo set currentMatch [match] match bar set newMatch [match] match $oldMatch list $currentMatch $newMatch } -result {foo bar} } # -skip, [skip] test tcltest-4.1 {tcltest -skip 'a*'} {unixOrPc} { set result [slave msg test.tcl -skip a* -verbose 'ps'] list $result [regexp a-1.0 $msg] [regexp b-1.0 $msg] [regexp c-1.0 $msg] \ [regexp "Total.+4.+Passed.+0.+Skipped.+2.+Failed.+1" $msg] } {0 0 1 1 1} test tcltest-4.2 {tcltest -skip 'b*'} {unixOrPc} { set result [slave msg test.tcl -skip b* -verbose 'ps'] list $result [regexp a-1.0 $msg] [regexp b-1.0 $msg] [regexp c-1.0 $msg] \ [regexp "Total.+4.+Passed.+1.+Skipped.+2.+Failed.+1" $msg] } {0 1 0 1 1} test tcltest-4.3 {tcltest -skip 'c*'} {unixOrPc} { set result [slave msg test.tcl -skip c* -verbose 'ps'] list $result [regexp a-1.0 $msg] [regexp b-1.0 $msg] [regexp c-1.0 $msg] \ [regexp "Total.+4.+Passed.+1.+Skipped.+1.+Failed.+2" $msg] } {0 1 1 0 1} test tcltest-4.4 {tcltest -skip 'a* b*'} {unixOrPc} { set result [slave msg test.tcl -skip {a* b*} -verbose 'ps'] list $result [regexp a-1.0 $msg] [regexp b-1.0 $msg] [regexp c-1.0 $msg] \ [regexp "Total.+4.+Passed.+0.+Skipped.+3.+Failed.+1" $msg] } {0 0 0 1 1} test tcltest-4.5 {tcltest -match 'a* b*' -skip 'b*'} {unixOrPc} { set result [slave msg test.tcl -match {a* b*} -skip b* -verbose 'ps'] list $result [regexp a-1.0 $msg] [regexp b-1.0 $msg] [regexp c-1.0 $msg] \ [regexp "Total.+4.+Passed.+1.+Skipped.+3.+Failed.+0" $msg] } {0 1 0 0 1} test tcltest-4.6 {tcltest::skip} { -body { set oldSkip [skip] skip foo set currentSkip [skip] skip bar set newSkip [skip] skip $oldSkip list $currentSkip $newSkip } -result {foo bar} } # -constraints, -limitconstraints, [testConstraint], # $constraintsSpecified, [limitConstraints] test tcltest-5.1 {tcltest -constraints 'knownBug'} {unixOrPc} { set result [slave msg test.tcl -constraints knownBug -verbose 'ps'] list $result [regexp a-1.0 $msg] [regexp b-1.0 $msg] [regexp c-1.0 $msg] \ [regexp "Total.+4.+Passed.+2.+Skipped.+0.+Failed.+2" $msg] } {0 1 1 1 1} test tcltest-5.2 {tcltest -constraints 'knownBug' -limitconstraints 1} {unixOrPc} { set result [slave msg test.tcl -constraints knownBug -verbose 'p' -limitconstraints 1] list $result [regexp a-1.0 $msg] [regexp b-1.0 $msg] [regexp c-1.0 $msg] \ [regexp "Total.+4.+Passed.+1.+Skipped.+3.+Failed.+0" $msg] } {0 0 0 1 1} test tcltest-5.3 {testConstraint - constraint empty (tcltest::safeFetch)} { -body { set r1 [testConstraint tcltestFakeConstraint] set r2 [testConstraint tcltestFakeConstraint 4] set r3 [testConstraint tcltestFakeConstraint] list $r1 $r2 $r3 } -result {0 4 4} -cleanup {unset ::tcltest::testConstraints(tcltestFakeConstraint)} } # Removed this test of internals of tcltest. Those internals have changed. #test tcltest-5.4 {tcltest::constraintsSpecified} { # -setup { # set constraintlist $::tcltest::constraintsSpecified # set ::tcltest::constraintsSpecified {} # } # -body { # set r1 $::tcltest::constraintsSpecified # testConstraint tcltestFakeConstraint1 1 # set r2 $::tcltest::constraintsSpecified # testConstraint tcltestFakeConstraint2 1 # set r3 $::tcltest::constraintsSpecified # list $r1 $r2 $r3 # } # -result {{} tcltestFakeConstraint1 {tcltestFakeConstraint1 tcltestFakeConstraint2}} # -cleanup { # set ::tcltest::constraintsSpecified $constraintlist # unset ::tcltest::testConstraints(tcltestFakeConstraint1) # unset ::tcltest::testConstraints(tcltestFakeConstraint2) # } #} test tcltest-5.5 {InitConstraints: list of built-in constraints} \ -constraints {!singleTestInterp} \ -setup {tcltest::InitConstraints} \ -body { lsort [array names ::tcltest::testConstraints] } \ -result [lsort { 95 98 asyncPipeClose eformat emptyTest exec hasIsoLocale interactive knownBug mac macCrash macOnly macOrPc macOrUnix macOrWin nonBlockFiles nonPortable notRoot nt pc pcCrash pcOnly root singleTestInterp socket stdio tempNotMac tempNotPc tempNotUnix tempNotWin unix unixCrash unixExecs unixOnly unixOrPc unixOrWin userInteraction win winCrash winOnly }] # Removed this broken test. Its usage of [limitConstraints] was not # in agreement with the documentation. [limitConstraints] is supposed # to take an optional boolean argument, and "knownBug" ain't no boolean! #test tcltest-5.6 {tcltest::limitConstraints} { # -setup { # set keeplc $::tcltest::limitConstraints # set keepkb [testConstraint knownBug] # } # -body { # set r1 [limitConstraints] # set r2 [limitConstraints knownBug] # set r3 [limitConstraints] # list $r1 $r2 $r3 # } # -cleanup { # limitConstraints $keeplc # testConstraint knownBug $keepkb # } # -result {false knownBug knownBug} #} # -outfile, -errfile, [outputChannel], [outputFile], [errorChannel], [errorFile] set printerror [makeFile { package require tcltest namespace import ::tcltest::* puts [outputChannel] "a test" ::tcltest::PrintError "a really short string" ::tcltest::PrintError "a really really really really really really long \ string containing \"quotes\" and other bad bad stuff" ::tcltest::PrintError "a really really long string containing a \ \"Path/that/is/really/long/and/contains/no/spaces\"" ::tcltest::PrintError "a really really long string containing a \ \"Really/Long/Path/that/contains/no/spaces/and/is/longer/than/eighty/characters/to/see/what/happens\"" ::tcltest::PrintError "Problem renaming file: error renaming \"Z:/ws/tcl8.2/win32-ix86/tests/core\" to \"Z:/ws/tcl8.2/win32-ix86/tests/movecore-core\"" exit } printerror.tcl] test tcltest-6.1 {tcltest -outfile, -errfile defaults} { -constraints unixOrPc -body { slave msg $printerror return $msg } -result {a test.*a really} -match regexp } test tcltest-6.2 {tcltest -outfile a.tmp} {unixOrPc unixExecs} { slave msg $printerror -outfile a.tmp set result1 [catch {exec grep "a test" a.tmp}] set result2 [catch {exec grep "a really" a.tmp}] list [regexp "a test" $msg] [regexp "a really" $msg] \ $result1 $result2 [file exists a.tmp] [file delete a.tmp] } {0 1 0 1 1 {}} test tcltest-6.3 {tcltest -errfile a.tmp} {unixOrPc unixExecs} { slave msg $printerror -errfile a.tmp set result1 [catch {exec grep "a test" a.tmp}] set result2 [catch {exec grep "a really" a.tmp}] list [regexp "a test" $msg] [regexp "a really" $msg] \ $result1 $result2 [file exists a.tmp] [file delete a.tmp] } {1 0 1 0 1 {}} test tcltest-6.4 {tcltest -outfile a.tmp -errfile b.tmp} {unixOrPc unixExecs} { slave msg $printerror -outfile a.tmp -errfile b.tmp set result1 [catch {exec grep "a test" a.tmp}] set result2 [catch {exec grep "a really" b.tmp}] list [regexp "a test" $msg] [regexp "a really" $msg] \ $result1 $result2 \ [file exists a.tmp] [file delete a.tmp] \ [file exists b.tmp] [file delete b.tmp] } {0 0 0 0 1 {} 1 {}} test tcltest-6.5 {tcltest::errorChannel - retrieval} { -setup { set of [errorChannel] set ::tcltest::errorChannel stderr } -body { errorChannel } -result {stderr} -cleanup { set ::tcltest::errorChannel $of } } test tcltest-6.6 {tcltest::errorFile (implicit errorChannel)} { -setup { set ef [makeFile {} efile] set of [errorFile] set ::tcltest::errorChannel stderr set ::tcltest::errorFile stderr } -body { set f0 [errorChannel] set f1 [errorFile] set f2 [errorFile $ef] set f3 [errorChannel] set f4 [errorFile] subst {$f0;$f1;$f2;$f3;$f4} } -result {stderr;stderr;.*efile;file[0-9a-f]+;.*efile} -match regexp -cleanup { errorFile $of removeFile efile } } test tcltest-6.7 {tcltest::outputChannel - retrieval} { -setup { set of [outputChannel] set ::tcltest::outputChannel stdout } -body { outputChannel } -result {stdout} -cleanup { set tcltest::outputChannel $of } } test tcltest-6.8 {tcltest::outputFile (implicit outputFile)} { -setup { set ef [makeFile {} efile] set of [outputFile] set ::tcltest::outputChannel stdout set ::tcltest::outputFile stdout } -body { set f0 [outputChannel] set f1 [outputFile] set f2 [outputFile $ef] set f3 [outputChannel] set f4 [outputFile] subst {$f0;$f1;$f2;$f3;$f4} } -result {stdout;stdout;.*efile;file[0-9a-f]+;.*efile} -match regexp -cleanup { outputFile $of removeFile efile } } # -debug, [debug] # Must use child processes to test -debug because it always writes # messages to stdout, and we have no way to capture stdout of a # slave interp test tcltest-7.1 {tcltest test.tcl -debug 0} {unixOrPc} { catch {exec [interpreter] test.tcl -debug 0} msg regexp "Flags passed into tcltest" $msg } {0} test tcltest-7.2 {tcltest test.tcl -debug 1} {unixOrPc} { catch {exec [interpreter] test.tcl -debug 1 -skip b*} msg list [regexp userSpecifiedSkip $msg] \ [regexp "Flags passed into tcltest" $msg] } {1 0} test tcltest-7.3 {tcltest test.tcl -debug 1} {unixOrPc} { catch {exec [interpreter] test.tcl -debug 1 -match b*} msg list [regexp userSpecifiedNonMatch $msg] \ [regexp "Flags passed into tcltest" $msg] } {1 0} test tcltest-7.4 {tcltest test.tcl -debug 2} {unixOrPc} { catch {exec [interpreter] test.tcl -debug 2} msg list [regexp "Flags passed into tcltest" $msg] [regexp "Running" $msg] } {1 0} test tcltest-7.5 {tcltest test.tcl -debug 3} {unixOrPc} { catch {exec [interpreter] test.tcl -debug 3} msg list [regexp "Flags passed into tcltest" $msg] [regexp "Running" $msg] } {1 1} test tcltest-7.6 {tcltest::debug} { -setup { set old $::tcltest::debug set ::tcltest::debug 0 } -body { set f1 [debug] set f2 [debug 1] set f3 [debug] set f4 [debug 2] set f5 [debug] list $f1 $f2 $f3 $f4 $f5 } -result {0 1 1 2 2} -cleanup { set ::tcltest::debug $old } } removeFile test.tcl # directory tests set a [makeFile { package require tcltest tcltest::makeFile {} a.tmp puts [tcltest::outputChannel] "testdir: [tcltest::testsDirectory]" exit } a.tcl] set tdiaf [makeFile {} thisdirectoryisafile] set normaldirectory [makeDirectory normaldirectory] normalizePath normaldirectory # -tmpdir, [temporaryDirectory] test tcltest-8.1 {tcltest a.tcl -tmpdir a} {unixOrPc} { file delete -force thisdirectorydoesnotexist slave msg $a -tmpdir thisdirectorydoesnotexist list [file exists [file join thisdirectorydoesnotexist a.tmp]] \ [file delete -force thisdirectorydoesnotexist] } {1 {}} test tcltest-8.2 {tcltest a.tcl -tmpdir thisdirectoryisafile} { -constraints unixOrPc -body { slave msg $a -tmpdir $tdiaf set msg } -result {*not a directory*} -match glob } # Test non-writeable directories, non-readable directories with directory flags set notReadableDir [file join [temporaryDirectory] notreadable] set notWriteableDir [file join [temporaryDirectory] notwriteable] makeDirectory notreadable makeDirectory notwriteable switch $tcl_platform(platform) { "unix" { file attributes $notReadableDir -permissions 00333 file attributes $notWriteableDir -permissions 00555 } default { catch {file attributes $notWriteableDir -readonly 1} catch {testchmod 000 $notWriteableDir} } } test tcltest-8.3 {tcltest a.tcl -tmpdir notReadableDir} {unix notRoot} { slave msg $a -tmpdir $notReadableDir string match {*not readable*} $msg } {1} test tcltest-8.4 {tcltest a.tcl -tmpdir notWriteableDir} {unixOrPc notRoot} { slave msg $a -tmpdir $notWriteableDir string match {*not writeable*} $msg } {1} test tcltest-8.5 {tcltest a.tcl -tmpdir normaldirectory} {unixOrPc} { slave msg $a -tmpdir $normaldirectory # The join is necessary because the message can be split on multiple lines list [file exists [file join $normaldirectory a.tmp]] \ [file delete [file join $normaldirectory a.tmp]] } {1 {}} cd [workingDirectory] test tcltest-8.6 {temporaryDirectory} { -setup { set old $::tcltest::temporaryDirectory set ::tcltest::temporaryDirectory $normaldirectory } -body { set f1 [temporaryDirectory] set f2 [temporaryDirectory [workingDirectory]] set f3 [temporaryDirectory] list $f1 $f2 $f3 } -result "[list $normaldirectory [workingDirectory] [workingDirectory]]" -cleanup { set ::tcltest::temporaryDirectory $old } } test tcltest-8.6a {temporaryDirectory - test format 2} -setup { set old $::tcltest::temporaryDirectory set ::tcltest::temporaryDirectory $normaldirectory } -body { set f1 [temporaryDirectory] set f2 [temporaryDirectory [workingDirectory]] set f3 [temporaryDirectory] list $f1 $f2 $f3 } -cleanup { set ::tcltest::temporaryDirectory $old } -result [list $normaldirectory [workingDirectory] [workingDirectory]] cd [temporaryDirectory] # -testdir, [testsDirectory] test tcltest-8.10 {tcltest a.tcl -testdir thisdirectorydoesnotexist} {unixOrPc} { file delete -force thisdirectorydoesnotexist slave msg $a -testdir thisdirectorydoesnotexist string match "*does not exist*" $msg } {1} test tcltest-8.11 {tcltest a.tcl -testdir thisdirectoryisafile} {unixOrPc} { slave msg $a -testdir $tdiaf string match "*not a directory*" $msg } {1} test tcltest-8.12 {tcltest a.tcl -testdir notReadableDir} {unix notRoot} { slave msg $a -testdir $notReadableDir string match {*not readable*} $msg } {1} test tcltest-8.13 {tcltest a.tcl -testdir normaldirectory} {unixOrPc} { slave msg $a -testdir $normaldirectory # The join is necessary because the message can be split on multiple lines list [string first "testdir: $normaldirectory" [join $msg]] \ [file exists [file join [temporaryDirectory] a.tmp]] \ [file delete [file join [temporaryDirectory] a.tmp]] } {0 1 {}} cd [workingDirectory] set current [pwd] test tcltest-8.14 {testsDirectory} { -setup { set old $::tcltest::testsDirectory set ::tcltest::testsDirectory $normaldirectory } -body { set f1 [testsDirectory] set f2 [testsDirectory $current] set f3 [testsDirectory] list $f1 $f2 $f3 } -result "[list $normaldirectory $current $current]" -cleanup { set ::tcltest::testsDirectory $old } } # [workingDirectory] test tcltest-8.60 {::workingDirectory} { -setup { set old $::tcltest::workingDirectory set current [pwd] set ::tcltest::workingDirectory $normaldirectory cd $normaldirectory } -body { set f1 [workingDirectory] set f2 [pwd] set f3 [workingDirectory $current] set f4 [pwd] set f5 [workingDirectory] list $f1 $f2 $f3 $f4 $f5 } -result "[list $normaldirectory \ $normaldirectory \ $current \ $current \ $current]" -cleanup { set ::tcltest::workingDirectory $old cd $current } } # clean up from directory testing switch $tcl_platform(platform) { "unix" { file attributes $notReadableDir -permissions 777 file attributes $notWriteableDir -permissions 777 } default { catch {testchmod 777 $notWriteableDir} catch {file attributes $notWriteableDir -readonly 0} } } file delete -force $notReadableDir $notWriteableDir removeFile a.tcl removeFile thisdirectoryisafile removeDirectory normaldirectory # -file, -notfile, [matchFiles], [skipFiles] test tcltest-9.1 {-file d*.tcl} -constraints {unixOrPc} -setup { set old [testsDirectory] testsDirectory [file dirname [info script]] } -body { slave msg [file join [testsDirectory] all.tcl] -file d*.test set msg } -cleanup { testsDirectory $old } -match regexp -result {dstring\.test} test tcltest-9.2 {-file d*.tcl} -constraints {unixOrPc} -setup { set old [testsDirectory] testsDirectory [file dirname [info script]] } -body { slave msg [file join [testsDirectory] all.tcl] \ -file d*.test -notfile dstring* regexp {dstring\.test} $msg } -cleanup { testsDirectory $old } -result 0 test tcltest-9.3 {matchFiles} { -body { set old [matchFiles] matchFiles foo set current [matchFiles] matchFiles bar set new [matchFiles] matchFiles $old list $current $new } -result {foo bar} } test tcltest-9.4 {skipFiles} { -body { set old [skipFiles] skipFiles foo set current [skipFiles] skipFiles bar set new [skipFiles] skipFiles $old list $current $new } -result {foo bar} } test tcltest-9.5 {GetMatchingFiles: Bug 1119798} -setup { set d [makeDirectory tmp] makeDirectory foo $d makeFile {} fee $d file copy [file join [file dirname [info script]] all.tcl] $d } -body { slave msg [file join [temporaryDirectory] all.tcl] -file f* regexp {exiting with errors:} $msg } -cleanup { file delete [file join $d all.tcl] removeFile fee $d removeDirectory foo $d removeDirectory tmp } -result 0 # -preservecore, [preserveCore] set mc [makeFile { package require tcltest namespace import ::tcltest::test test makecore {make a core file} { set f [open core w] close $f } {} ::tcltest::cleanupTests return } makecore.tcl] cd [temporaryDirectory] test tcltest-10.1 {-preservecore 0} {unixOrPc} { slave msg $mc -preservecore 0 file delete core regexp "Core file produced" $msg } {0} test tcltest-10.2 {-preservecore 1} {unixOrPc} { slave msg $mc -preservecore 1 file delete core regexp "Core file produced" $msg } {1} test tcltest-10.3 {-preservecore 2} {unixOrPc} { slave msg $mc -preservecore 2 file delete core list [regexp "Core file produced" $msg] [regexp "Moving file to" $msg] \ [regexp "core-" $msg] [file delete core-makecore] } {1 1 1 {}} test tcltest-10.4 {-preservecore 3} {unixOrPc} { slave msg $mc -preservecore 3 file delete core list [regexp "Core file produced" $msg] [regexp "Moving file to" $msg] \ [regexp "core-" $msg] [file delete core-makecore] } {1 1 1 {}} # Removing this test. It makes no sense to test the ability of # [preserveCore] to accept an invalid value that will cause errors # in other parts of tcltest's operation. #test tcltest-10.5 {preserveCore} { # -body { # set old [preserveCore] # set result [preserveCore foo] # set result2 [preserveCore] # preserveCore $old # list $result $result2 # } # -result {foo foo} #} removeFile makecore.tcl # -load, -loadfile, [loadScript], [loadFile] set contents { package require tcltest namespace import tcltest::* puts [outputChannel] $::tcltest::loadScript exit } set loadfile [makeFile $contents load.tcl] test tcltest-12.1 {-load xxx} {unixOrPc} { slave msg $loadfile -load xxx set msg } {xxx} # Using child process because of -debug usage. test tcltest-12.2 {-loadfile load.tcl} {unixOrPc} { catch {exec [interpreter] $loadfile -debug 2 -loadfile $loadfile} msg list \ [regexp {tcltest} [join [list $msg] [split $msg \n]]] \ [regexp {loadScript} [join [list $msg] [split $msg \n]]] } {1 1} test tcltest-12.3 {loadScript} { -setup { set old $::tcltest::loadScript set ::tcltest::loadScript {} } -body { set f1 [loadScript] set f2 [loadScript xxx] set f3 [loadScript] list $f1 $f2 $f3 } -result {{} xxx xxx} -cleanup { set ::tcltest::loadScript $old } } test tcltest-12.4 {loadFile} { -setup { set olds $::tcltest::loadScript set ::tcltest::loadScript {} set oldf $::tcltest::loadFile set ::tcltest::loadFile {} } -body { set f1 [loadScript] set f2 [loadFile] set f3 [loadFile $loadfile] set f4 [loadScript] set f5 [loadFile] list $f1 $f2 $f3 $f4 $f5 } -result "[list {} {} $loadfile $contents $loadfile]\n" -cleanup { set ::tcltest::loadScript $olds set ::tcltest::loadFile $oldf } } removeFile load.tcl # [interpreter] test tcltest-13.1 {interpreter} { -setup { set old $::tcltest::tcltest set ::tcltest::tcltest tcltest } -body { set f1 [interpreter] set f2 [interpreter tclsh] set f3 [interpreter] list $f1 $f2 $f3 } -result {tcltest tclsh tclsh} -cleanup { set ::tcltest::tcltest $old } } # -singleproc, [singleProcess] set spd [makeDirectory singleprocdir] makeFile { set foo 1 } single1.test $spd makeFile { unset foo } single2.test $spd set allfile [makeFile { package require tcltest namespace import tcltest::* testsDirectory [file join [temporaryDirectory] singleprocdir] runAllTests } all-single.tcl $spd] cd [workingDirectory] test tcltest-14.1 {-singleproc - single process} { -constraints {unixOrPc} -body { slave msg $allfile -singleproc 0 -tmpdir [temporaryDirectory] set msg } -result {Test file error: can't unset .foo.: no such variable} -match regexp } test tcltest-14.2 {-singleproc - multiple process} { -constraints {unixOrPc} -body { slave msg $allfile -singleproc 1 -tmpdir [temporaryDirectory] set msg } -result {single1.test.*single2.test.*all\-single.tcl:.*Total.*0.*Passed.*0.*Skipped.*0.*Failed.*0} -match regexp } test tcltest-14.3 {singleProcess} { -setup { set old $::tcltest::singleProcess set ::tcltest::singleProcess 0 } -body { set f1 [singleProcess] set f2 [singleProcess 1] set f3 [singleProcess] list $f1 $f2 $f3 } -result {0 1 1} -cleanup { set ::tcltest::singleProcess $old } } removeFile single1.test $spd removeFile single2.test $spd removeDirectory singleprocdir # -asidefromdir, -relateddir, [matchDirectories], [skipDirectories] # Before running these tests, need to set up test subdirectories with their own # all.tcl files. set dtd [makeDirectory dirtestdir] set dtd1 [makeDirectory dirtestdir2.1 $dtd] set dtd2 [makeDirectory dirtestdir2.2 $dtd] set dtd3 [makeDirectory dirtestdir2.3 $dtd] makeFile { package require tcltest namespace import -force tcltest::* testsDirectory [file join [temporaryDirectory] dirtestdir] runAllTests } all.tcl $dtd makeFile { package require tcltest namespace import -force tcltest::* testsDirectory [file join [temporaryDirectory] dirtestdir dirtestdir2.1] runAllTests } all.tcl $dtd1 makeFile { package require tcltest namespace import -force tcltest::* testsDirectory [file join [temporaryDirectory] dirtestdir dirtestdir2.2] runAllTests } all.tcl $dtd2 makeFile { package require tcltest namespace import -force tcltest::* testsDirectory [file join [temporaryDirectory] dirtestdir dirtestdir2.3] runAllTests } all.tcl $dtd3 test tcltest-15.1 {basic directory walking} { -constraints {unixOrPc} -body { if {[slave msg \ [file join $dtd all.tcl] \ -tmpdir [temporaryDirectory]] == 1} { error $msg } } -match regexp -returnCodes 1 -result {Tests located in:.*dirtestdir.*Tests located in:.*dirtestdir2.[123].*Tests located in:.*dirtestdir2.[123].*Tests located in:.*dirtestdir2.[123]} } test tcltest-15.2 {-asidefromdir} { -constraints {unixOrPc} -body { if {[slave msg \ [file join $dtd all.tcl] \ -asidefromdir dirtestdir2.3 \ -tmpdir [temporaryDirectory]] == 1} { error $msg } } -match regexp -returnCodes 1 -result {Tests located in:.*dirtestdir.*Tests located in:.*dirtestdir2.[12].*Tests located in:.*dirtestdir2.[12].*dirtestdir2.[12] test ended at .*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Error: No test files remain after applying your match and skip patterns! Error: No test files remain after applying your match and skip patterns! Error: No test files remain after applying your match and skip patterns!$} } test tcltest-15.3 {-relateddir, non-existent dir} { -constraints {unixOrPc} -body { if {[slave msg \ [file join $dtd all.tcl] \ -relateddir [file join [temporaryDirectory] dirtestdir0] \ -tmpdir [temporaryDirectory]] == 1} { error $msg } } -returnCodes 1 -match regexp -result {[^~]|dirtestdir[^2]} } test tcltest-15.4 {-relateddir, subdir} { -constraints {unixOrPc} -body { if {[slave msg \ [file join $dtd all.tcl] \ -relateddir dirtestdir2.1 -tmpdir [temporaryDirectory]] == 1} { error $msg } } -returnCodes 1 -match regexp -result {Tests located in:.*dirtestdir2.[^23]} } test tcltest-15.5 {-relateddir, -asidefromdir} { -constraints {unixOrPc} -body { if {[slave msg \ [file join $dtd all.tcl] \ -relateddir "dirtestdir2.1 dirtestdir2.2" \ -asidefromdir dirtestdir2.2 \ -tmpdir [temporaryDirectory]] == 1} { error $msg } } -match regexp -returnCodes 1 -result {Tests located in:.*dirtestdir2.[^23]} } test tcltest-15.6 {matchDirectories} { -setup { set old [matchDirectories] set ::tcltest::matchDirectories {} } -body { set r1 [matchDirectories] set r2 [matchDirectories foo] set r3 [matchDirectories] list $r1 $r2 $r3 } -cleanup { set ::tcltest::matchDirectories $old } -result {{} foo foo} } test tcltest-15.7 {skipDirectories} { -setup { set old [skipDirectories] set ::tcltest::skipDirectories {} } -body { set r1 [skipDirectories] set r2 [skipDirectories foo] set r3 [skipDirectories] list $r1 $r2 $r3 } -cleanup { set ::tcltest::skipDirectories $old } -result {{} foo foo} } removeDirectory dirtestdir2.3 $dtd removeDirectory dirtestdir2.2 $dtd removeDirectory dirtestdir2.1 $dtd removeDirectory dirtestdir # TCLTEST_OPTIONS test tcltest-19.1 {TCLTEST_OPTIONS default} -setup { if {[info exists ::env(TCLTEST_OPTIONS)]} { set oldoptions $::env(TCLTEST_OPTIONS) } else { set oldoptions none } # set this to { } instead of just {} to get around quirk in # Windows env handling that removes empty elements from env array. set ::env(TCLTEST_OPTIONS) { } interp create slave1 slave1 eval [list set argv {-debug 2}] slave1 alias puts puts interp create slave2 slave2 alias puts puts } -cleanup { interp delete slave2 interp delete slave1 if {$oldoptions == "none"} { unset ::env(TCLTEST_OPTIONS) } else { set ::env(TCLTEST_OPTIONS) $oldoptions } } -body { slave1 eval [package ifneeded tcltest [package provide tcltest]] slave1 eval tcltest::debug set ::env(TCLTEST_OPTIONS) "-debug 3" slave2 eval [package ifneeded tcltest [package provide tcltest]] slave2 eval tcltest::debug } -result {^3$} -match regexp -output\ {tcltest::debug\s+= 2.*tcltest::debug\s+= 3} # Begin testing of tcltest procs ... cd [temporaryDirectory] # PrintError test tcltest-20.1 {PrintError} {unixOrPc} { set result [slave msg $printerror] list $result [regexp "Error: a really short string" $msg] \ [regexp " \"quotes\"" $msg] [regexp " \"Path" $msg] \ [regexp " \"Really" $msg] [regexp Problem $msg] } {1 1 1 1 1 1} cd [workingDirectory] removeFile printerror.tcl # test::test test tcltest-21.0 {name and desc but no args specified} -setup { set v [verbose] } -cleanup { verbose $v } -body { verbose {} test tcltest-21.0.0 bar } -result {} test tcltest-21.1 {expect with glob} { -body { list a b c d e } -match glob -result {[ab] b c d e} } test tcltest-21.2 {force a test command failure} { -body { test tcltest-21.2.0 { return 2 } {1} } -returnCodes 1 -result {bad option "1": must be -body, -cleanup, -constraints, -errorOutput, -match, -output, -result, -returnCodes, or -setup} } test tcltest-21.3 {test command with setup} { -setup { set foo 1 } -body { set foo } -cleanup {unset foo} -result {1} } test tcltest-21.4 {test command with cleanup failure} { -setup { if {[info exists foo]} { unset foo } set fail $::tcltest::currentFailure set v [verbose] } -body { verbose {} test tcltest-21.4.0 {foo-1} { -cleanup {unset foo} } } -result {^$} -match regexp -cleanup {verbose $v; set ::tcltest::currentFailure $fail} -output "Test cleanup failed:.*can't unset \"foo\": no such variable" } test tcltest-21.5 {test command with setup failure} { -setup { if {[info exists foo]} { unset foo } set fail $::tcltest::currentFailure } -body { test tcltest-21.5.0 {foo-2} { -setup {unset foo} } } -result {^$} -match regexp -cleanup {set ::tcltest::currentFailure $fail} -output "Test setup failed:.*can't unset \"foo\": no such variable" } test tcltest-21.6 {test command - setup occurs before cleanup & before script} { -setup {set v [verbose]; set fail $::tcltest::currentFailure} -body { verbose {} test tcltest-21.6.0 {foo-3} { -setup { if {[info exists foo]} { unset foo } set foo 1 set expected 2 } -body { incr foo set foo } -cleanup { if {$foo != 2} { puts [outputChannel] "foo is wrong" } else { puts [outputChannel] "foo is 2" } } -result {$expected} } } -cleanup {verbose $v; set ::tcltest::currentFailure $fail} -result {^$} -match regexp -output "foo is 2" } test tcltest-21.7 {test command - bad flag} { -setup {set fail $::tcltest::currentFailure} -cleanup {set ::tcltest::currentFailure $fail} -body { test tcltest-21.7.0 {foo-4} { -foobar {} } } -returnCodes 1 -result {bad option "-foobar": must be -body, -cleanup, -constraints, -errorOutput, -match, -output, -result, -returnCodes, or -setup} } # alternate test command format (these are the same as 21.1-21.6, with the # exception of being in the all-inline format) test tcltest-21.7a {expect with glob} \ -body {list a b c d e} \ -result {[ab] b c d e} \ -match glob test tcltest-21.8 {force a test command failure} \ -setup {set fail $::tcltest::currentFailure} \ -body { test tcltest-21.8.0 { return 2 } {1} } \ -returnCodes 1 \ -cleanup {set ::tcltest::currentFailure $fail} \ -result {bad option "1": must be -body, -cleanup, -constraints, -errorOutput, -match, -output, -result, -returnCodes, or -setup} test tcltest-21.9 {test command with setup} \ -setup {set foo 1} \ -body {set foo} \ -cleanup {unset foo} \ -result {1} test tcltest-21.10 {test command with cleanup failure} -setup { if {[info exists foo]} { unset foo } set fail $::tcltest::currentFailure set v [verbose] } -cleanup { verbose $v set ::tcltest::currentFailure $fail } -body { verbose {} test tcltest-21.10.0 {foo-1} -cleanup {unset foo} } -result {^$} -match regexp \ -output {Test cleanup failed:.*can't unset \"foo\": no such variable} test tcltest-21.11 {test command with setup failure} -setup { if {[info exists foo]} { unset foo } set fail $::tcltest::currentFailure } -cleanup {set ::tcltest::currentFailure $fail} -body { test tcltest-21.11.0 {foo-2} -setup {unset foo} } -result {^$} -output {Test setup failed:.*can't unset \"foo\": no such variable} -match regexp test tcltest-21.12 { test command - setup occurs before cleanup & before script } -setup { set fail $::tcltest::currentFailure set v [verbose] } -cleanup { verbose $v set ::tcltest::currentFailure $fail } -body { verbose {} test tcltest-21.12.0 {foo-3} -setup { if {[info exists foo]} { unset foo } set foo 1 set expected 2 } -body { incr foo set foo } -cleanup { if {$foo != 2} { puts [outputChannel] "foo is wrong" } else { puts [outputChannel] "foo is 2" } } -result {$expected} } -result {^$} -output {foo is 2} -match regexp # test all.tcl usage (runAllTests); simulate .test file failure, as well as # crashes to determine whether or not these errors are logged. set atd [makeDirectory alltestdir] makeFile { package require tcltest namespace import -force tcltest::* testsDirectory [file join [temporaryDirectory] alltestdir] runAllTests } all.tcl $atd makeFile { exit 1 } exit.test $atd makeFile { error "throw an error" } error.test $atd makeFile { package require tcltest namespace import -force tcltest::* test foo-1.1 {foo} { -body { return 1 } -result {1} } cleanupTests } test.test $atd # Must use a child process because stdout/stderr parsing can't be # duplicated in slave interp. test tcltest-22.1 {runAllTests} { -constraints {unixOrPc} -body { exec [interpreter] \ [file join $atd all.tcl] \ -verbose t -tmpdir [temporaryDirectory] } -match regexp -result "Test files exiting with errors:.*error.test.*exit.test" } removeDirectory alltestdir # makeFile, removeFile, makeDirectory, removeDirectory, viewFile test tcltest-23.1 {makeFile} { -setup { set mfdir [file join [temporaryDirectory] mfdir] file mkdir $mfdir } -body { makeFile {} t1.tmp makeFile {} et1.tmp $mfdir list [file exists [file join [temporaryDirectory] t1.tmp]] \ [file exists [file join $mfdir et1.tmp]] } -cleanup { file delete -force $mfdir \ [file join [temporaryDirectory] t1.tmp] } -result {1 1} } test tcltest-23.2 {removeFile} { -setup { set mfdir [file join [temporaryDirectory] mfdir] file mkdir $mfdir makeFile {} t1.tmp makeFile {} et1.tmp $mfdir if {![file exists [file join [temporaryDirectory] t1.tmp]] || \ ![file exists [file join $mfdir et1.tmp]]} { error "file creation didn't work" } } -body { removeFile t1.tmp removeFile et1.tmp $mfdir list [file exists [file join [temporaryDirectory] t1.tmp]] \ [file exists [file join $mfdir et1.tmp]] } -cleanup { file delete -force $mfdir \ [file join [temporaryDirectory] t1.tmp] } -result {0 0} } test tcltest-23.3 {makeDirectory} { -body { set mfdir [file join [temporaryDirectory] mfdir] file mkdir $mfdir makeDirectory d1 makeDirectory d2 $mfdir list [file exists [file join [temporaryDirectory] d1]] \ [file exists [file join $mfdir d2]] } -cleanup { file delete -force [file join [temporaryDirectory] d1] $mfdir } -result {1 1} } test tcltest-23.4 {removeDirectory} { -setup { set mfdir [makeDirectory mfdir] makeDirectory t1 makeDirectory t2 $mfdir if {![file exists $mfdir] || \ ![file exists [file join [temporaryDirectory] $mfdir t2]]} { error "setup failed - directory not created" } } -body { removeDirectory t1 removeDirectory t2 $mfdir list [file exists [file join [temporaryDirectory] t1]] \ [file exists [file join $mfdir t2]] } -result {0 0} } test tcltest-23.5 {viewFile} { -body { set mfdir [file join [temporaryDirectory] mfdir] file mkdir $mfdir makeFile {foobar} t1.tmp makeFile {foobarbaz} t2.tmp $mfdir list [viewFile t1.tmp] [viewFile t2.tmp $mfdir] } -result {foobar foobarbaz} -cleanup { file delete -force $mfdir removeFile t1.tmp } } # customMatch proc matchNegative { expected actual } { set match 0 foreach a $actual e $expected { if { $a != $e } { set match 1 break } } return $match } test tcltest-24.0 { customMatch: syntax } -body { list [catch {customMatch} result] $result } -result [list 1 "wrong # args: should be \"customMatch mode script\""] test tcltest-24.1 { customMatch: syntax } -body { list [catch {customMatch foo} result] $result } -result [list 1 "wrong # args: should be \"customMatch mode script\""] test tcltest-24.2 { customMatch: syntax } -body { list [catch {customMatch foo bar baz} result] $result } -result [list 1 "wrong # args: should be \"customMatch mode script\""] test tcltest-24.3 { customMatch: argument checking } -body { list [catch {customMatch bad "a \{ b"} result] $result } -result [list 1 "invalid customMatch script; can't evaluate after completion"] test tcltest-24.4 { test: valid -match values } -body { list [catch { test tcltest-24.4.0 {} \ -match [namespace current]::noSuchMode } result] $result } -match glob -result {1 *bad -match value*} test tcltest-24.5 { test: valid -match values } -setup { customMatch [namespace current]::alwaysMatch "format 1 ;#" } -body { list [catch { test tcltest-24.5.0 {} \ -match [namespace current]::noSuchMode } result] $result } -match glob -result {1 *bad -match value*: must be *alwaysMatch,*} test tcltest-24.6 { customMatch: -match script that always matches } -setup { customMatch [namespace current]::alwaysMatch "format 1 ;#" set v [verbose] } -body { verbose {} test tcltest-24.6.0 {} -match [namespace current]::alwaysMatch \ -body {format 1} -result 0 } -cleanup { verbose $v } -result {} -output {} -errorOutput {} test tcltest-24.7 { customMatch: replace default -exact matching } -setup { set saveExactMatchScript $::tcltest::CustomMatch(exact) customMatch exact "format 1 ;#" set v [verbose] } -body { verbose {} test tcltest-24.7.0 {} -body {format 1} -result 0 } -cleanup { verbose $v customMatch exact $saveExactMatchScript unset saveExactMatchScript } -result {} -output {} test tcltest-24.9 { customMatch: error during match } -setup { proc errorDuringMatch args {return -code error "match returned error"} customMatch [namespace current]::errorDuringMatch \ [namespace code errorDuringMatch] set v [verbose] set fail $::tcltest::currentFailure } -body { verbose {} test tcltest-24.9.0 {} -match [namespace current]::errorDuringMatch } -cleanup { verbose $v set ::tcltest::currentFailure $fail } -match glob -result {} -output {*FAILED*match returned error*} test tcltest-24.10 { customMatch: bad return from match command } -setup { proc nonBooleanReturn args {return foo} customMatch nonBooleanReturn [namespace code nonBooleanReturn] set v [verbose] set fail $::tcltest::currentFailure } -body { verbose {} test tcltest-24.10.0 {} -match nonBooleanReturn } -cleanup { verbose $v set ::tcltest::currentFailure $fail } -match glob -result {} -output {*FAILED*expected boolean value*} test tcltest-24.11 { test: -match exact } -body { set result {A B C} } -match exact -result {A B C} test tcltest-24.12 { test: -match exact match command eval in ::, not caller namespace } -setup { set saveExactMatchScript $::tcltest::CustomMatch(exact) customMatch exact [list string equal] set v [verbose] proc string args {error {called [string] in caller namespace}} } -body { verbose {} test tcltest-24.12.0 {} -body {format 1} -result 1 } -cleanup { rename string {} verbose $v customMatch exact $saveExactMatchScript unset saveExactMatchScript } -match exact -result {} -output {} test tcltest-24.13 { test: -match exact failure } -setup { set saveExactMatchScript $::tcltest::CustomMatch(exact) customMatch exact [list string equal] set v [verbose] set fail $::tcltest::currentFailure } -body { verbose {} test tcltest-24.13.0 {} -body {format 1} -result 0 } -cleanup { set ::tcltest::currentFailure $fail verbose $v customMatch exact $saveExactMatchScript unset saveExactMatchScript } -match glob -result {} -output {*FAILED*Result was: 1*(exact matching): 0*} test tcltest-24.14 { test: -match glob } -body { set result {A B C} } -match glob -result {A B*} test tcltest-24.15 { test: -match glob failure } -setup { set v [verbose] set fail $::tcltest::currentFailure } -body { verbose {} test tcltest-24.15.0 {} -match glob -body {format {A B C}} \ -result {A B* } } -cleanup { set ::tcltest::currentFailure $fail verbose $v } -match glob -result {} -output {*FAILED*Result was: *(glob matching): *} test tcltest-24.16 { test: -match regexp } -body { set result {A B C} } -match regexp -result {A B.*} test tcltest-24.17 { test: -match regexp failure } -setup { set fail $::tcltest::currentFailure set v [verbose] } -body { verbose {} test tcltest-24.17.0 {} -match regexp -body {format {A B C}} \ -result {A B.* X} } -cleanup { set ::tcltest::currentFailure $fail verbose $v } -match glob -result {} -output {*FAILED*Result was: *(regexp matching): *} test tcltest-24.18 { test: -match custom forget namespace qualification } -setup { set fail $::tcltest::currentFailure set v [verbose] customMatch negative matchNegative } -body { verbose {} test tcltest-24.18.0 {} -match negative -body {format {A B C}} \ -result {A B X} } -cleanup { set ::tcltest::currentFailure $fail verbose $v } -match glob -result {} -output {*FAILED*Error testing result:*} test tcltest-24.19 { test: -match custom } -setup { set v [verbose] customMatch negative [namespace code matchNegative] } -body { verbose {} test tcltest-24.19.0 {} -match negative -body {format {A B C}} \ -result {A B X} } -cleanup { verbose $v } -match exact -result {} -output {} test tcltest-24.20 { test: -match custom failure } -setup { set fail $::tcltest::currentFailure set v [verbose] customMatch negative [namespace code matchNegative] } -body { verbose {} test tcltest-24.20.0 {} -match negative -body {format {A B C}} \ -result {A B C} } -cleanup { set ::tcltest::currentFailure $fail verbose $v } -match glob -result {} -output {*FAILED*Result was: *(negative matching): *} test tcltest-25.1 { constraint of setup/cleanup (Bug 589859) } -setup { set foo 0 } -body { # Buggy tcltest will generate result of 2 test tcltest-25.1.0 {} -constraints knownBug -setup { incr foo } -body { incr foo } -cleanup { incr foo } -match glob -result * set foo } -cleanup { unset foo } -result 0 test tcltest-25.2 { puts -nonewline (Bug 612786) } -body { puts -nonewline stdout bla puts -nonewline stdout bla } -output {blabla} test tcltest-25.3 { reported return code (Bug 611922) } -setup { set fail $::tcltest::currentFailure set v [verbose] } -body { verbose {} test tcltest-25.3.0 {} -body { error foo } } -cleanup { set ::tcltest::currentFailure $fail verbose $v } -match glob -output {*generated error; Return code was: 1*} test tcltest-26.1 {Bug/RFE 1017151} -setup { makeFile { package require tcltest set errorInfo "Should never see this" tcltest::test tcltest-26.1.0 { no errorInfo when only return code mismatch } -body { set x 1 } -returnCodes error -result 1 tcltest::cleanupTests } test.tcl } -body { slave msg [file join [temporaryDirectory] test.tcl] set msg } -cleanup { removeFile test.tcl } -match glob -result {* ---- Return code should have been one of: 1 ==== tcltest-26.1.0 FAILED*} test tcltest-26.2 {Bug/RFE 1017151} -setup { makeFile { package require tcltest set errorInfo "Should never see this" tcltest::test tcltest-26.2.0 {do not mask body errorInfo} -body { error "body error" } -cleanup { error "cleanup error" } -result 1 tcltest::cleanupTests } test.tcl } -body { slave msg [file join [temporaryDirectory] test.tcl] set msg } -cleanup { removeFile test.tcl } -match glob -result {* ---- errorInfo: body error * ---- errorInfo(cleanup): cleanup error*} cleanupTests } namespace delete ::tcltest::test return tcl8.4.20/tests/pkg.test0000644003604700454610000012577611737050674013565 0ustar dgp771div# Commands covered: pkg # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1995-1996 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import -force ::tcltest::* } # Do all this in a slave interp to avoid garbaging the # package list set i [interp create] interp eval $i [list set argv $argv] interp eval $i [list package require tcltest 2] interp eval $i [list namespace import -force ::tcltest::*] interp eval $i { eval package forget [package names] set oldPkgUnknown [package unknown] package unknown {} set oldPath $auto_path set auto_path "" testConstraint tip268 [info exists tcl_platform(tip,268)] testConstraint !tip268 [expr {![info exists tcl_platform(tip,268)]}] test pkg-1.1 {Tcl_PkgProvide procedure} { package forget t package provide t 2.3 } {} test pkg-1.2 {Tcl_PkgProvide procedure} { package forget t package provide t 2.3 list [catch {package provide t 2.2} msg] $msg } {1 {conflicting versions provided for package "t": 2.3, then 2.2}} test pkg-1.3 {Tcl_PkgProvide procedure} { package forget t package provide t 2.3 list [catch {package provide t 2.4} msg] $msg } {1 {conflicting versions provided for package "t": 2.3, then 2.4}} test pkg-1.4 {Tcl_PkgProvide procedure} { package forget t package provide t 2.3 list [catch {package provide t 3.3} msg] $msg } {1 {conflicting versions provided for package "t": 2.3, then 3.3}} test pkg-1.5 {Tcl_PkgProvide procedure} { package forget t package provide t 2.3 package provide t 2.3 } {} test pkg-1.6 {Tcl_PkgProvide procedure} tip268 { package forget t package provide t 2.3a1 } {} set n 0 foreach v { 2.3k1 2a3a2 2ab3 2.a4 2.b4 2b.4 2a.4 2ba4 2a4b1 2b4a1 2b3b2 } { test pkg-1.7.$n {Tcl_PkgProvide procedure} tip268 { package forget t list [catch {package provide t $v} msg] $msg } [list 1 "expected version number but got \"$v\""] incr n } test pkg-2.1 {Tcl_PkgRequire procedure, picking best version} { package forget t foreach i {1.4 3.4 2.3 2.4 2.2} { package ifneeded t $i "set x $i; package provide t $i" } set x xxx package require t set x } {3.4} test pkg-2.2 {Tcl_PkgRequire procedure, picking best version} { package forget t foreach i {1.4 3.4 2.3 2.4 2.2 3.5 3.2} { package ifneeded t $i "set x $i; package provide t $i" } set x xxx package require t set x } {3.5} test pkg-2.3 {Tcl_PkgRequire procedure, picking best version} { package forget t foreach i {3.5 2.1 2.3} { package ifneeded t $i "set x $i; package provide t $i" } set x xxx package require t 2.2 set x } {2.3} test pkg-2.4 {Tcl_PkgRequire procedure, picking best version} { package forget t foreach i {1.4 3.4 2.3 2.4 2.2} { package ifneeded t $i "set x $i; package provide t $i" } set x xxx package require -exact t 2.3 set x } {2.3} test pkg-2.5 {Tcl_PkgRequire procedure, picking best version} { package forget t foreach i {1.4 3.4 2.3 2.4 2.2} { package ifneeded t $i "set x $i; package provide t $i" } set x xxx package require t 2.1 set x } {2.4} test pkg-2.6 {Tcl_PkgRequire procedure, can't find suitable version} { package forget t package unknown {} foreach i {1.4 3.4 2.3 2.4 2.2} { package ifneeded t $i "set x $i" } list [catch {package require t 2.5} msg] $msg } {1 {can't find package t 2.5}} test pkg-2.7 {Tcl_PkgRequire procedure, can't find suitable version} { package forget t package unknown {} foreach i {1.4 3.4 2.3 2.4 2.2} { package ifneeded t $i "set x $i" } list [catch {package require t 4.1} msg] $msg } {1 {can't find package t 4.1}} test pkg-2.8 {Tcl_PkgRequire procedure, can't find suitable version} !tip268 { package forget t package unknown {} foreach i {1.4 3.4 2.3 2.4 2.2} { package ifneeded t $i "set x $i" } list [catch {package require -exact t 1.3} msg] $msg } {1 {can't find package t 1.3}} test pkg-2.8-268 {Tcl_PkgRequire procedure, can't find suitable version} tip268 { package forget t package unknown {} foreach i {1.4 3.4 2.3 2.4 2.2} { package ifneeded t $i "set x $i" } list [catch {package require -exact t 1.3} msg] $msg } {1 {can't find package t 1.3}} test pkg-2.9 {Tcl_PkgRequire procedure, can't find suitable version} { package forget t package unknown {} list [catch {package require t} msg] $msg } {1 {can't find package t}} test pkg-2.10 {Tcl_PkgRequire procedure, error in ifneeded script} -body { package forget t package ifneeded t 2.1 {package provide t 2.1; error "ifneeded test"} list [catch {package require t 2.1} msg] $msg $errorInfo } -match glob -result {1 {ifneeded test} {ifneeded test while executing "error "ifneeded test"" ("package ifneeded*" script) invoked from within "package require t 2.1"}} test pkg-2.11 {Tcl_PkgRequire procedure, ifneeded script doesn't provide package} -body { package forget t package ifneeded t 2.1 "set x invoked" set x xxx list [catch {package require t 2.1} msg] $msg $x } -match glob -result {1 * invoked} test pkg-2.12 {Tcl_PkgRequire procedure, self-deleting script} { package forget t package ifneeded t 1.2 "package forget t; set x 1.2; package provide t 1.2" set x xxx package require t 1.2 set x } {1.2} test pkg-2.13-!268 {Tcl_PkgRequire procedure, "package unknown" support} !tip268 { proc pkgUnknown args { global x set x $args package provide [lindex $args 0] [lindex $args 1] } package forget t foreach i {1.4 3.4 2.3 2.4 2.2} { package ifneeded t $i "set x $i" } package unknown pkgUnknown set x xxx package require -exact t 1.5 package unknown {} set x } {t 1.5 -exact} test pkg-2.13-268 {Tcl_PkgRequire procedure, "package unknown" support} tip268 { proc pkgUnknown args { # args = name requirement # requirement = v-v (for exact version) global x set x $args package provide [lindex $args 0] [lindex [split [lindex $args 1] -] 0] } package forget t foreach i {1.4 3.4 2.3 2.4 2.2} { package ifneeded t $i "set x $i" } package unknown pkgUnknown set x xxx package require -exact t 1.5 package unknown {} set x } {t 1.5-1.5} test pkg-2.14 {Tcl_PkgRequire procedure, "package unknown" support} { proc pkgUnknown args { package ifneeded t 1.2 "set x loaded; package provide t 1.2" } package forget t package unknown pkgUnknown set x xxx set result [list [package require t] $x] package unknown {} set result } {1.2 loaded} test pkg-2.15 {Tcl_PkgRequire procedure, "package unknown" support} !tip268 { proc pkgUnknown args { global x set x $args package provide [lindex $args 0] 2.0 } package forget {a b} package unknown pkgUnknown set x xxx package require {a b} package unknown {} set x } {{a b} {}} test pkg-2.15-268 {Tcl_PkgRequire procedure, "package unknown" support} tip268 { proc pkgUnknown args { global x set x $args package provide [lindex $args 0] 2.0 } package forget {a b} package unknown pkgUnknown set x xxx package require {a b} package unknown {} set x } {{a b} 0-} test pkg-2.16 {Tcl_PkgRequire procedure, "package unknown" error} !tip268 { proc pkgUnknown args { error "testing package unknown" } package forget t package unknown pkgUnknown set result [list [catch {package require t} msg] $msg $errorInfo] package unknown {} set result } {1 {testing package unknown} {testing package unknown while executing "error "testing package unknown"" (procedure "pkgUnknown" line 2) invoked from within "pkgUnknown t {}" ("package unknown" script) invoked from within "package require t"}} test pkg-2.16-268 {Tcl_PkgRequire procedure, "package unknown" error} tip268 { proc pkgUnknown args { error "testing package unknown" } package forget t package unknown pkgUnknown set result [list [catch {package require t} msg] $msg $errorInfo] package unknown {} set result } {1 {testing package unknown} {testing package unknown while executing "error "testing package unknown"" (procedure "pkgUnknown" line 2) invoked from within "pkgUnknown t 0-" ("package unknown" script) invoked from within "package require t"}} test pkg-2.17 {Tcl_PkgRequire procedure, "package unknown" doesn't load package} !tip268 { proc pkgUnknown args { global x set x $args } package forget t foreach i {1.4 3.4 2.3 2.4 2.2} { package ifneeded t $i "set x $i" } package unknown pkgUnknown set x xxx set result [list [catch {package require -exact t 1.5} msg] $msg $x] package unknown {} set result } {1 {can't find package t 1.5} {t 1.5 -exact}} test pkg-2.17-268 {Tcl_PkgRequire procedure, "package unknown" doesn't load package} tip268 { proc pkgUnknown args { global x set x $args } package forget t foreach i {1.4 3.4 2.3 2.4 2.2} { package ifneeded t $i "set x $i" } package unknown pkgUnknown set x xxx set result [list [catch {package require -exact t 1.5} msg] $msg $x] package unknown {} set result } {1 {can't find package t 1.5} {t 1.5-1.5}} test pkg-2.18 {Tcl_PkgRequire procedure, version checks} { package forget t package provide t 2.3 package require t } {2.3} test pkg-2.19 {Tcl_PkgRequire procedure, version checks} { package forget t package provide t 2.3 package require t 2.1 } {2.3} test pkg-2.20 {Tcl_PkgRequire procedure, version checks} { package forget t package provide t 2.3 package require t 2.3 } {2.3} test pkg-2.21 {Tcl_PkgRequire procedure, version checks} { package forget t package provide t 2.3 list [catch {package require t 2.4} msg] $msg } {1 {version conflict for package "t": have 2.3, need 2.4}} test pkg-2.22 {Tcl_PkgRequire procedure, version checks} { package forget t package provide t 2.3 list [catch {package require t 1.2} msg] $msg } {1 {version conflict for package "t": have 2.3, need 1.2}} test pkg-2.23 {Tcl_PkgRequire procedure, version checks} { package forget t package provide t 2.3 package require -exact t 2.3 } {2.3} test pkg-2.24 {Tcl_PkgRequire procedure, version checks} !tip268 { package forget t package provide t 2.3 list [catch {package require -exact t 2.2} msg] $msg } {1 {version conflict for package "t": have 2.3, need 2.2}} test pkg-2.24-268 {Tcl_PkgRequire procedure, version checks} tip268 { package forget t package provide t 2.3 list [catch {package require -exact t 2.2} msg] $msg } {1 {version conflict for package "t": have 2.3, need 2.2}} test pkg-2.25 {Tcl_PkgRequire procedure, error in ifneeded script} -body { package forget t package ifneeded t 2.1 {package provide t 2.1; error "ifneeded test" EI} list [catch {package require t 2.1} msg] $msg $errorInfo } -match glob -result {1 {ifneeded test} {EI ("package ifneeded*" script) invoked from within "package require t 2.1"}} -constraints knownBug test pkg-2.26 {Tcl_PkgRequire procedure, error in ifneeded script} -body { package forget t package ifneeded t 2.1 {package provide t 2.1; foreach x 1 {error "ifneeded test" EI}} list [catch {package require t 2.1} msg] $msg $errorInfo } -match glob -result {1 {ifneeded test} {EI ("foreach" body line 1) invoked from within "foreach x 1 {error "ifneeded test" EI}" ("package ifneeded*" script) invoked from within "package require t 2.1"}} test pkg-2.27 {Tcl_PkgRequire: circular dependency} -setup { package forget foo } -body { package ifneeded foo 1 {package require foo 1} package require foo 1 } -cleanup { package forget foo } -returnCodes error -match glob -result {circular package dependency:*} test pkg-2.28 {Tcl_PkgRequire: circular dependency} -setup { package forget foo } -body { package ifneeded foo 1 {package require foo 2} package require foo 1 } -cleanup { package forget foo } -returnCodes error -match glob -result {circular package dependency:*} test pkg-2.29 {Tcl_PkgRequire: circular dependency} -setup { package forget foo package forget bar } -body { package ifneeded foo 1 {package require bar 1; package provide foo 1} package ifneeded bar 1 {package require foo 1; package provide bar 1} package require foo 1 } -cleanup { package forget foo package forget bar } -returnCodes error -match glob -result {circular package dependency:*} test pkg-2.30 {Tcl_PkgRequire: circular dependency} -setup { package forget foo package forget bar } -body { package ifneeded foo 1 {package require bar 1; package provide foo 1} package ifneeded foo 2 {package provide foo 2} package ifneeded bar 1 {package require foo 2; package provide bar 1} package require foo 1 } -cleanup { package forget foo package forget bar } -returnCodes error -match glob -result {circular package dependency:*} test pkg-2.31 {Tcl_PkgRequire: consistent return values (1162286)} -setup { package forget foo } -body { package ifneeded foo 1 {package provide foo 1; error foo} package require foo 1 } -cleanup { package forget foo } -returnCodes error -match glob -result foo test pkg-2.32 {Tcl_PkgRequire: consistent return values (1162286)} -setup { package forget foo } -body { package ifneeded foo 1 {package provide foo 1; error foo} catch {package require foo 1} package provide foo } -cleanup { package forget foo } -result {} test pkg-2.33 {Tcl_PkgRequire: consistent return values (1162286)} -setup { package forget foo } -body { package ifneeded foo 1 {package provide foo 2} package require foo 1 } -cleanup { package forget foo } -returnCodes error -match glob -result {attempt to provide package * failed:*} test pkg-2.34 {Tcl_PkgRequire: consistent return values (1162286)} -setup { package forget foo } -body { package ifneeded foo 1 {package provide foo 1.1} package require foo 1 } -cleanup { package forget foo } -result 1.1 test pkg-2.34.1 {Tcl_PkgRequire: consistent return values (1162286)} -setup { package forget foo } -body { package ifneeded foo 1.1 {package provide foo 1} package require foo 1 } -cleanup { package forget foo } -result 1 test pkg-2.34.2 {Tcl_PkgRequire: consistent return values (1162286)} -setup { package forget foo } -body { package ifneeded foo 1.1 {package provide foo 1} package require foo 1.1 } -cleanup { package forget foo } -returnCodes error -match glob -result {attempt to provide package * failed:*} test pkg-2.35 {Tcl_PkgRequire: consistent return values (1162286)} -setup { package forget foo } -body { package ifneeded foo 1 {} package require foo 1 } -cleanup { package forget foo } -returnCodes error -match glob -result {attempt to provide package * failed:*} test pkg-2.35.1 {Tcl_PkgRequire: consistent return values (1162286)} -setup { package forget foo } -body { package ifneeded foo 1 {break} package require foo 1 } -cleanup { package forget foo } -returnCodes error -match glob \ -result {attempt to provide package * failed: bad return code:*} test pkg-2.36 {Tcl_PkgRequire: consistent return values (1162286)} -setup { package forget foo } -body { package ifneeded foo 1 {continue} package require foo 1 } -cleanup { package forget foo } -returnCodes error -match glob \ -result {attempt to provide package * failed: bad return code:*} test pkg-2.37 {Tcl_PkgRequire: consistent return values (1162286)} -setup { package forget foo } -body { package ifneeded foo 1 {return} package require foo 1 } -cleanup { package forget foo } -returnCodes error -match glob \ -result {attempt to provide package * failed: bad return code:*} test pkg-2.38 {Tcl_PkgRequire: consistent return values (1162286)} -setup { package forget foo } -body { package ifneeded foo 1 {proc x {} {return -code 10}; x} package require foo 1 } -cleanup { rename x {} package forget foo } -returnCodes error -match glob \ -result {attempt to provide package * failed: bad return code:*} test pkg-2.39 {Tcl_PkgRequire: consistent return values (1162286)} -setup { package forget foo set saveUnknown [package unknown] package unknown {package provide foo 2 ;#} } -body { package require foo 1 } -cleanup { package forget foo package unknown $saveUnknown } -returnCodes error -match glob -result * test pkg-2.40 {Tcl_PkgRequire: consistent return values (1162286)} -setup { package forget foo set saveUnknown [package unknown] package unknown {break ;#} } -body { package require foo 1 } -cleanup { package forget foo package unknown $saveUnknown } -returnCodes error -match glob -result {bad return code:*} test pkg-2.41 {Tcl_PkgRequire: consistent return values (1162286)} -setup { package forget foo set saveUnknown [package unknown] package unknown {continue ;#} } -body { package require foo 1 } -cleanup { package forget foo package unknown $saveUnknown } -returnCodes error -match glob -result {bad return code:*} test pkg-2.42 {Tcl_PkgRequire: consistent return values (1162286)} -setup { package forget foo set saveUnknown [package unknown] package unknown {return ;#} } -body { package require foo 1 } -cleanup { package forget foo package unknown $saveUnknown } -returnCodes error -match glob -result {bad return code:*} test pkg-2.43 {Tcl_PkgRequire: consistent return values (1162286)} -setup { package forget foo set saveUnknown [package unknown] proc x args {return -code 10} package unknown x } -body { package require foo 1 } -cleanup { rename x {} package forget foo package unknown $saveUnknown } -returnCodes error -match glob -result {bad return code:*} test pkg-2.50 {Tcl_PkgRequire procedure, picking best stable version} tip268 { package forget t foreach i {1.4 3.4 4.0a1 2.3 2.4 2.2} { package ifneeded t $i "set x $i; package provide t $i" } set x xxx package require t set x } {3.4} test pkg-2.51 {Tcl_PkgRequire procedure, picking best stable version} tip268 { package forget t foreach i {1.2b1 1.2 1.3a2 1.3} { package ifneeded t $i "set x $i; package provide t $i" } set x xxx package require t set x } {1.3} test pkg-2.52 {Tcl_PkgRequire procedure, picking best stable version} tip268 { package forget t foreach i {1.2b1 1.2 1.3 1.3a2} { package ifneeded t $i "set x $i; package provide t $i" } set x xxx package require t set x } {1.3} test pkg-3.1 {Tcl_PackageCmd procedure} { list [catch {package} msg] $msg } {1 {wrong # args: should be "package option ?arg arg ...?"}} test pkg-3.2 {Tcl_PackageCmd procedure, "forget" option} { foreach i [package names] { package forget $i } package names } {} test pkg-3.3 {Tcl_PackageCmd procedure, "forget" option} { foreach i [package names] { package forget $i } package forget foo } {} test pkg-3.4 {Tcl_PackageCmd procedure, "forget" option} { foreach i [package names] { package forget $i } package ifneeded t 1.1 {first script} package ifneeded t 2.3 {second script} package ifneeded x 1.4 {x's script} set result {} lappend result [lsort [package names]] [package versions t] package forget t lappend result [lsort [package names]] [package versions t] } {{t x} {1.1 2.3} x {}} test pkg-3.5 {Tcl_PackageCmd procedure, "forget" option} { foreach i [package names] { package forget $i } package ifneeded a 1.1 {first script} package ifneeded b 2.3 {second script} package ifneeded c 1.4 {third script} package forget set result [list [lsort [package names]]] package forget a c lappend result [lsort [package names]] } {{a b c} b} test pkg-3.5.1 {Tcl_PackageCmd procedure, "forget" option} { # Test for Bug 415273 package ifneeded a 1 "I should have been forgotten" package forget no-such-package a set x [package ifneeded a 1] package forget a set x } {} test pkg-3.6 {Tcl_PackageCmd procedure, "ifneeded" option} { list [catch {package ifneeded a} msg] $msg } {1 {wrong # args: should be "package ifneeded package version ?script?"}} test pkg-3.7 {Tcl_PackageCmd procedure, "ifneeded" option} { list [catch {package ifneeded a b c d} msg] $msg } {1 {wrong # args: should be "package ifneeded package version ?script?"}} test pkg-3.8 {Tcl_PackageCmd procedure, "ifneeded" option} { list [catch {package ifneeded t xyz} msg] $msg } {1 {expected version number but got "xyz"}} test pkg-3.9 {Tcl_PackageCmd procedure, "ifneeded" option} { foreach i [package names] { package forget $i } list [package ifneeded foo 1.1] [package names] } {{} {}} test pkg-3.10 {Tcl_PackageCmd procedure, "ifneeded" option} { package forget t package ifneeded t 1.4 "script for t 1.4" list [package names] [package ifneeded t 1.4] [package versions t] } {t {script for t 1.4} 1.4} test pkg-3.11 {Tcl_PackageCmd procedure, "ifneeded" option} { package forget t package ifneeded t 1.4 "script for t 1.4" list [package ifneeded t 1.5] [package names] [package versions t] } {{} t 1.4} test pkg-3.12 {Tcl_PackageCmd procedure, "ifneeded" option} { package forget t package ifneeded t 1.4 "script for t 1.4" package ifneeded t 1.4 "second script for t 1.4" list [package ifneeded t 1.4] [package names] [package versions t] } {{second script for t 1.4} t 1.4} test pkg-3.13 {Tcl_PackageCmd procedure, "ifneeded" option} { package forget t package ifneeded t 1.4 "script for t 1.4" package ifneeded t 1.2 "second script" package ifneeded t 3.1 "last script" list [package ifneeded t 1.2] [package versions t] } {{second script} {1.4 1.2 3.1}} test pkg-3.14 {Tcl_PackageCmd procedure, "names" option} { list [catch {package names a} msg] $msg } {1 {wrong # args: should be "package names"}} test pkg-3.15 {Tcl_PackageCmd procedure, "names" option} { foreach i [package names] { package forget $i } package names } {} test pkg-3.16 {Tcl_PackageCmd procedure, "names" option} { foreach i [package names] { package forget $i } package ifneeded x 1.2 {dummy} package provide x 1.3 package provide y 2.4 catch {package require z 47.16} lsort [package names] } {x y} test pkg-3.17 {Tcl_PackageCmd procedure, "provide" option} { list [catch {package provide} msg] $msg } {1 {wrong # args: should be "package provide package ?version?"}} test pkg-3.18 {Tcl_PackageCmd procedure, "provide" option} { list [catch {package provide a b c} msg] $msg } {1 {wrong # args: should be "package provide package ?version?"}} test pkg-3.19 {Tcl_PackageCmd procedure, "provide" option} { package forget t package provide t } {} test pkg-3.20 {Tcl_PackageCmd procedure, "provide" option} { package forget t package provide t 2.3 package provide t } {2.3} test pkg-3.21 {Tcl_PackageCmd procedure, "provide" option} { package forget t list [catch {package provide t a.b} msg] $msg } {1 {expected version number but got "a.b"}} test pkg-3.22 {Tcl_PackageCmd procedure, "require" option} !tip268 { list [catch {package require} msg] $msg } {1 {wrong # args: should be "package require ?-exact? package ?version?"}} test pkg-3.22-268 {Tcl_PackageCmd procedure, "require" option} tip268 { list [catch {package require} msg] $msg } {1 {wrong # args: should be "package require ?-exact? package ?requirement...?"}} test pkg-3.23 {Tcl_PackageCmd procedure, "require" option} !tip268 { list [catch {package require a b c} msg] $msg } {1 {wrong # args: should be "package require ?-exact? package ?version?"}} test pkg-3.24 {Tcl_PackageCmd procedure, "require" option} !tip268 { list [catch {package require -exact a b c} msg] $msg } {1 {wrong # args: should be "package require ?-exact? package ?version?"}} test pkg-3.24-268 {Tcl_PackageCmd procedure, "require" option} tip268 { list [catch {package require -exact a b c} msg] $msg # Exact syntax: -exact name version # name ?requirement...? } {1 {wrong # args: should be "package require ?-exact? package ?requirement...?"}} test pkg-3.25 {Tcl_PackageCmd procedure, "require" option} !tip268 { list [catch {package require -bs a b} msg] $msg } {1 {wrong # args: should be "package require ?-exact? package ?version?"}} test pkg-3.26 {Tcl_PackageCmd procedure, "require" option} { list [catch {package require x a.b} msg] $msg } {1 {expected version number but got "a.b"}} test pkg-3.27 {Tcl_PackageCmd procedure, "require" option} { list [catch {package require -exact x a.b} msg] $msg } {1 {expected version number but got "a.b"}} test pkg-3.28 {Tcl_PackageCmd procedure, "require" option} !tip268 { list [catch {package require -exact x} msg] $msg } {1 {wrong # args: should be "package require ?-exact? package ?version?"}} test pkg-3.28-268 {Tcl_PackageCmd procedure, "require" option} tip268 { list [catch {package require -exact x} msg] $msg } {1 {wrong # args: should be "package require ?-exact? package ?requirement...?"}} test pkg-3.29 {Tcl_PackageCmd procedure, "require" option} !tip268 { list [catch {package require -exact} msg] $msg } {1 {wrong # args: should be "package require ?-exact? package ?version?"}} test pkg-3.29-268 {Tcl_PackageCmd procedure, "require" option} tip268 { list [catch {package require -exact} msg] $msg } {1 {wrong # args: should be "package require ?-exact? package ?requirement...?"}} test pkg-3.30 {Tcl_PackageCmd procedure, "require" option} { package forget t package provide t 2.3 package require t 2.1 } {2.3} test pkg-3.31 {Tcl_PackageCmd procedure, "require" option} { package forget t list [catch {package require t} msg] $msg } {1 {can't find package t}} test pkg-3.32 {Tcl_PackageCmd procedure, "require" option} { package forget t package ifneeded t 2.3 "error {synthetic error}" list [catch {package require t 2.3} msg] $msg } {1 {synthetic error}} test pkg-3.33 {Tcl_PackageCmd procedure, "unknown" option} { list [catch {package unknown a b} msg] $msg } {1 {wrong # args: should be "package unknown ?command?"}} test pkg-3.34 {Tcl_PackageCmd procedure, "unknown" option} { package unknown "test script" package unknown } {test script} test pkg-3.35 {Tcl_PackageCmd procedure, "unknown" option} { package unknown "test script" package unknown {} package unknown } {} test pkg-3.36 {Tcl_PackageCmd procedure, "vcompare" option} { list [catch {package vcompare a} msg] $msg } {1 {wrong # args: should be "package vcompare version1 version2"}} test pkg-3.37 {Tcl_PackageCmd procedure, "vcompare" option} { list [catch {package vcompare a b c} msg] $msg } {1 {wrong # args: should be "package vcompare version1 version2"}} test pkg-3.38 {Tcl_PackageCmd procedure, "vcompare" option} { list [catch {package vcompare x.y 3.4} msg] $msg } {1 {expected version number but got "x.y"}} test pkg-3.39 {Tcl_PackageCmd procedure, "vcompare" option} { list [catch {package vcompare 2.1 a.b} msg] $msg } {1 {expected version number but got "a.b"}} test pkg-3.40 {Tcl_PackageCmd procedure, "vcompare" option} { package vc 2.1 2.3 } {-1} test pkg-3.41 {Tcl_PackageCmd procedure, "vcompare" option} { package vc 2.2.4 2.2.4 } {0} test pkg-3.42 {Tcl_PackageCmd procedure, "versions" option} { list [catch {package versions} msg] $msg } {1 {wrong # args: should be "package versions package"}} test pkg-3.43 {Tcl_PackageCmd procedure, "versions" option} { list [catch {package versions a b} msg] $msg } {1 {wrong # args: should be "package versions package"}} test pkg-3.44 {Tcl_PackageCmd procedure, "versions" option} { package forget t package versions t } {} test pkg-3.45 {Tcl_PackageCmd procedure, "versions" option} { package forget t package provide t 2.3 package versions t } {} test pkg-3.46 {Tcl_PackageCmd procedure, "versions" option} { package forget t package ifneeded t 2.3 x package ifneeded t 2.4 y package versions t } {2.3 2.4} test pkg-3.47 {Tcl_PackageCmd procedure, "vsatisfies" option} !tip268 { list [catch {package vsatisfies a} msg] $msg } {1 {wrong # args: should be "package vsatisfies version1 version2"}} test pkg-3.47-268 {Tcl_PackageCmd procedure, "vsatisfies" option} tip268 { list [catch {package vsatisfies a} msg] $msg } {1 {wrong # args: should be "package vsatisfies version requirement requirement..."}} test pkg-3.48 {Tcl_PackageCmd procedure, "vsatisfies" option} !tip268 { list [catch {package vsatisfies a b c} msg] $msg } {1 {wrong # args: should be "package vsatisfies version1 version2"}} test pkg-3.49 {Tcl_PackageCmd procedure, "vsatisfies" option} { list [catch {package vsatisfies x.y 3.4} msg] $msg } {1 {expected version number but got "x.y"}} test pkg-3.50 {Tcl_PackageCmd procedure, "vsatisfies" option} { list [catch {package vcompare 2.1 a.b} msg] $msg } {1 {expected version number but got "a.b"}} test pkg-3.51 {Tcl_PackageCmd procedure, "vsatisfies" option} { package vs 2.3 2.1 } {1} test pkg-3.52 {Tcl_PackageCmd procedure, "vsatisfies" option} { package vs 2.3 1.2 } {0} test pkg-3.53 {Tcl_PackageCmd procedure, "versions" option} !tip268 { list [catch {package foo} msg] $msg } {1 {bad option "foo": must be forget, ifneeded, names, present, provide, require, unknown, vcompare, versions, or vsatisfies}} test pkg-3.53-268 {Tcl_PackageCmd procedure, "versions" option} tip268 { list [catch {package foo} msg] $msg } {1 {bad option "foo": must be forget, ifneeded, names, prefer, present, provide, require, unknown, vcompare, versions, or vsatisfies}} test pkg-3.54 {Tcl_PackageCmd procedure, "vsatisfies" option} tip268 { list [catch {package vsatisfies 2.1 2.1-3.2-4.5} msg] $msg } {1 {expected versionMin-versionMax but got "2.1-3.2-4.5"}} test pkg-3.55 {Tcl_PackageCmd procedure, "vsatisfies" option} tip268 { list [catch {package vsatisfies 2.1 3.2-x.y} msg] $msg } {1 {expected version number but got "x.y"}} test pkg-3.56 {Tcl_PackageCmd procedure, "vsatisfies" option} tip268 { list [catch {package vsatisfies 2.1 x.y-3.2} msg] $msg } {1 {expected version number but got "x.y"}} # No tests for FindPackage; can't think up anything detectable # errors. test pkg-4.1 {TclFreePackageInfo procedure} { interp create foo foo eval { package ifneeded t 2.3 x package ifneeded t 2.4 y package ifneeded x 3.1 z package provide q 4.3 package unknown "will this get freed?" } interp delete foo } {} test pkg-4.2 {TclFreePackageInfo procedure} -body { interp create foo foo eval { package ifneeded t 2.3 x package ifneeded t 2.4 y package ifneeded x 3.1 z package provide q 4.3 } foo alias z kill proc kill {} { interp delete foo } foo eval package require x 3.1 } -returnCodes error -match glob -result * test pkg-5.1 {CheckVersion procedure} { list [catch {package vcompare 1 2.1} msg] $msg } {0 -1} test pkg-5.2 {CheckVersion procedure} { list [catch {package vcompare .1 2.1} msg] $msg } {1 {expected version number but got ".1"}} test pkg-5.3 {CheckVersion procedure} { list [catch {package vcompare 111.2a.3 2.1} msg] $msg } {1 {expected version number but got "111.2a.3"}} test pkg-5.4 {CheckVersion procedure} { list [catch {package vcompare 1.2.3. 2.1} msg] $msg } {1 {expected version number but got "1.2.3."}} test pkg-5.5 {CheckVersion procedure} { list [catch {package vcompare 1.2..3 2.1} msg] $msg } {1 {expected version number but got "1.2..3"}} test pkg-6.1 {ComparePkgVersions procedure} { package vcompare 1.23 1.22 } {1} test pkg-6.2 {ComparePkgVersions procedure} { package vcompare 1.22.1.2.3 1.22.1.2.3 } {0} test pkg-6.3 {ComparePkgVersions procedure} { package vcompare 1.21 1.22 } {-1} test pkg-6.4 {ComparePkgVersions procedure} { package vcompare 1.21 1.21.2 } {-1} test pkg-6.5 {ComparePkgVersions procedure} { package vcompare 1.21.1 1.21 } {1} test pkg-6.6 {ComparePkgVersions procedure} { package vsatisfies 1.21.1 1.21 } {1} test pkg-6.7 {ComparePkgVersions procedure} { package vsatisfies 2.22.3 1.21 } {0} test pkg-6.8 {ComparePkgVersions procedure} { package vsatisfies 1 1 } {1} test pkg-6.9 {ComparePkgVersions procedure} { package vsatisfies 2 1 } {0} test pkg-7.1 {Tcl_PkgPresent procedure, any version} { package forget t package provide t 2.4 package present t } {2.4} test pkg-7.2 {Tcl_PkgPresent procedure, correct version} { package forget t package provide t 2.4 package present t 2.4 } {2.4} test pkg-7.3 {Tcl_PkgPresent procedure, satisfying version} { package forget t package provide t 2.4 package present t 2.0 } {2.4} test pkg-7.4 {Tcl_PkgPresent procedure, not satisfying version} { package forget t package provide t 2.4 list [catch {package present t 2.6} msg] $msg } {1 {version conflict for package "t": have 2.4, need 2.6}} test pkg-7.5 {Tcl_PkgPresent procedure, not satisfying version} { package forget t package provide t 2.4 list [catch {package present t 1.0} msg] $msg } {1 {version conflict for package "t": have 2.4, need 1.0}} test pkg-7.6 {Tcl_PkgPresent procedure, exact version} { package forget t package provide t 2.4 package present -exact t 2.4 } {2.4} test pkg-7.7 {Tcl_PkgPresent procedure, not exact version} { package forget t package provide t 2.4 list [catch {package present -exact t 2.3} msg] $msg } {1 {version conflict for package "t": have 2.4, need 2.3}} test pkg-7.8 {Tcl_PkgPresent procedure, unknown package} { package forget t list [catch {package present t} msg] $msg } {1 {package t is not present}} test pkg-7.9 {Tcl_PkgPresent procedure, unknown package} { package forget t list [catch {package present t 2.4} msg] $msg } {1 {package t 2.4 is not present}} test pkg-7.10 {Tcl_PkgPresent procedure, unknown package} { package forget t list [catch {package present -exact t 2.4} msg] $msg } {1 {package t 2.4 is not present}} test pkg-7.11 {Tcl_PackageCmd procedure, "present" option} !tip268 { list [catch {package present} msg] $msg } {1 {wrong # args: should be "package present ?-exact? package ?version?"}} test pkg-7.12 {Tcl_PackageCmd procedure, "present" option} !tip268 { list [catch {package present a b c} msg] $msg } {1 {wrong # args: should be "package present ?-exact? package ?version?"}} test pkg-7.13 {Tcl_PackageCmd procedure, "present" option} !tip268 { list [catch {package present -exact a b c} msg] $msg } {1 {wrong # args: should be "package present ?-exact? package ?version?"}} test pkg-7.14 {Tcl_PackageCmd procedure, "present" option} !tip268 { list [catch {package present -bs a b} msg] $msg } {1 {wrong # args: should be "package present ?-exact? package ?version?"}} test pkg-7.15 {Tcl_PackageCmd procedure, "present" option} { list [catch {package present x a.b} msg] $msg } {1 {expected version number but got "a.b"}} test pkg-7.16 {Tcl_PackageCmd procedure, "present" option} { list [catch {package present -exact x a.b} msg] $msg } {1 {expected version number but got "a.b"}} test pkg-7.17 {Tcl_PackageCmd procedure, "present" option} !tip268 { list [catch {package present -exact x} msg] $msg } {1 {wrong # args: should be "package present ?-exact? package ?version?"}} test pkg-7.18 {Tcl_PackageCmd procedure, "present" option} !tip268 { list [catch {package present -exact} msg] $msg } {1 {wrong # args: should be "package present ?-exact? package ?version?"}} # Note: It is correct that the result of the very first test, # i.e. "5.0 5.0a0" is 1, i.e. that version 5.0a0 satisfies a 5.0 # requirement. # The requirement "5.0" internally translates first to "5.0-6", and # then to its final form of "5.0a0-6a0". These translations are # explicitly specified by the TIP (Search for "padded/extended # internally with 'a0'"). This was done intentionally for exactly the # tested case, that an alpha package can satisfy a requirement for the # regular package. An example would be a package FOO requiring Tcl 8.X # for its operation. It can be used with Tcl 8.Xa0. Without our # translation that would not be possible. set n 0 foreach {r p vs vc} { 5.0 5.0a0 1 1 5.0a0 5.0 1 -1 8.5a0 8.5a5 1 -1 8.5a0 8.5b1 1 -1 8.5a0 8.5.1 1 -1 8.5a0 8.6a0 1 -1 8.5a0 8.6b0 1 -1 8.5a0 8.6.0 1 -1 8.5a6 8.5a5 0 1 8.5a6 8.5b1 1 -1 8.5a6 8.5.1 1 -1 8.5a6 8.6a0 1 -1 8.5a6 8.6b0 1 -1 8.5a6 8.6.0 1 -1 8.5b0 8.5a5 0 1 8.5b0 8.5b1 1 -1 8.5b0 8.5.1 1 -1 8.5b0 8.6a0 1 -1 8.5b0 8.6b0 1 -1 8.5b0 8.6.0 1 -1 8.5b2 8.5a5 0 1 8.5b2 8.5b1 0 1 8.5b2 8.5.1 1 -1 8.5b2 8.6a0 1 -1 8.5b2 8.6b0 1 -1 8.5b2 8.6.0 1 -1 8.5 8.5a5 1 1 8.5 8.5b1 1 1 8.5 8.5.1 1 -1 8.5 8.6a0 1 -1 8.5 8.6b0 1 -1 8.5 8.6.0 1 -1 8.5.0 8.5a5 0 1 8.5.0 8.5b1 0 1 8.5.0 8.5.1 1 -1 8.5.0 8.6a0 1 -1 8.5.0 8.6b0 1 -1 8.5.0 8.6.0 1 -1 } { test package-vsatisfies-1.$n {package vsatisfies} tip268 { package vsatisfies $p $r } $vs test package-vcompare-1.$n {package vcompare} tip268 { package vcompare $r $p } $vc incr n } set n 0 foreach {required provided satisfied} { 8.5a0- 8.5a5 1 8.5a0- 8.5b1 1 8.5a0- 8.5.1 1 8.5a0- 8.6a0 1 8.5a0- 8.6b0 1 8.5a0- 8.6.0 1 8.5a6- 8.5a5 0 8.5a6- 8.5b1 1 8.5a6- 8.5.1 1 8.5a6- 8.6a0 1 8.5a6- 8.6b0 1 8.5a6- 8.6.0 1 8.5b0- 8.5a5 0 8.5b0- 8.5b1 1 8.5b0- 8.5.1 1 8.5b0- 8.6a0 1 8.5b0- 8.6b0 1 8.5b0- 8.6.0 1 8.5b2- 8.5a5 0 8.5b2- 8.5b1 0 8.5b2- 8.5.1 1 8.5b2- 8.6a0 1 8.5b2- 8.6b0 1 8.5b2- 8.6.0 1 8.5- 8.5a5 1 8.5- 8.5b1 1 8.5- 8.5.1 1 8.5- 8.6a0 1 8.5- 8.6b0 1 8.5- 8.6.0 1 8.5.0- 8.5a5 0 8.5.0- 8.5b1 0 8.5.0- 8.5.1 1 8.5.0- 8.6a0 1 8.5.0- 8.6b0 1 8.5.0- 8.6.0 1 8.5a0-7 8.5a5 0 8.5a0-7 8.5b1 0 8.5a0-7 8.5.1 0 8.5a0-7 8.6a0 0 8.5a0-7 8.6b0 0 8.5a0-7 8.6.0 0 8.5a6-7 8.5a5 0 8.5a6-7 8.5b1 0 8.5a6-7 8.5.1 0 8.5a6-7 8.6a0 0 8.5a6-7 8.6b0 0 8.5a6-7 8.6.0 0 8.5b0-7 8.5a5 0 8.5b0-7 8.5b1 0 8.5b0-7 8.5.1 0 8.5b0-7 8.6a0 0 8.5b0-7 8.6b0 0 8.5b0-7 8.6.0 0 8.5b2-7 8.5a5 0 8.5b2-7 8.5b1 0 8.5b2-7 8.5.1 0 8.5b2-7 8.6a0 0 8.5b2-7 8.6b0 0 8.5b2-7 8.6.0 0 8.5-7 8.5a5 0 8.5-7 8.5b1 0 8.5-7 8.5.1 0 8.5-7 8.6a0 0 8.5-7 8.6b0 0 8.5-7 8.6.0 0 8.5.0-7 8.5a5 0 8.5.0-7 8.5b1 0 8.5.0-7 8.5.1 0 8.5.0-7 8.6a0 0 8.5.0-7 8.6b0 0 8.5.0-7 8.6.0 0 8.5a0-8.6.1 8.5a5 1 8.5a0-8.6.1 8.5b1 1 8.5a0-8.6.1 8.5.1 1 8.5a0-8.6.1 8.6a0 1 8.5a0-8.6.1 8.6b0 1 8.5a0-8.6.1 8.6.0 1 8.5a6-8.6.1 8.5a5 0 8.5a6-8.6.1 8.5b1 1 8.5a6-8.6.1 8.5.1 1 8.5a6-8.6.1 8.6a0 1 8.5a6-8.6.1 8.6b0 1 8.5a6-8.6.1 8.6.0 1 8.5b0-8.6.1 8.5a5 0 8.5b0-8.6.1 8.5b1 1 8.5b0-8.6.1 8.5.1 1 8.5b0-8.6.1 8.6a0 1 8.5b0-8.6.1 8.6b0 1 8.5b0-8.6.1 8.6.0 1 8.5b2-8.6.1 8.5a5 0 8.5b2-8.6.1 8.5b1 0 8.5b2-8.6.1 8.5.1 1 8.5b2-8.6.1 8.6a0 1 8.5b2-8.6.1 8.6b0 1 8.5b2-8.6.1 8.6.0 1 8.5-8.6.1 8.5a5 1 8.5-8.6.1 8.5b1 1 8.5-8.6.1 8.5.1 1 8.5-8.6.1 8.6a0 1 8.5-8.6.1 8.6b0 1 8.5-8.6.1 8.6.0 1 8.5.0-8.6.1 8.5a5 0 8.5.0-8.6.1 8.5b1 0 8.5.0-8.6.1 8.5.1 1 8.5.0-8.6.1 8.6a0 1 8.5.0-8.6.1 8.6b0 1 8.5.0-8.6.1 8.6.0 1 8.5a0-8.5a0 8.5a0 1 8.5a0-8.5a0 8.5b1 0 8.5a0-8.5a0 8.4 0 8.5b0-8.5b0 8.5a5 0 8.5b0-8.5b0 8.5b0 1 8.5b0-8.5b0 8.5.1 0 8.5-8.5 8.5a5 0 8.5-8.5 8.5b1 0 8.5-8.5 8.5 1 8.5-8.5 8.5.1 0 8.5.0-8.5.0 8.5a5 0 8.5.0-8.5.0 8.5b1 0 8.5.0-8.5.0 8.5.0 1 8.5.0-8.5.0 8.5.1 0 8.5.0-8.5.0 8.6a0 0 8.5.0-8.5.0 8.6b0 0 8.5.0-8.5.0 8.6.0 0 8.2 9 0 8.2- 9 1 8.2-8.5 9 0 8.2-9.1 9 1 8.5-8.5 8.5b1 0 8.5a0-8.5 8.5b1 0 8.5a0-8.5.1 8.5b1 1 8.5-8.5 8.5 1 8.5.0-8.5.0 8.5 1 8.5a0-8.5.0 8.5 0 } { test package-vsatisfies-2.$n "package vsatisfies $provided $required" tip268 { package vsatisfies $provided $required } $satisfied incr n } test package-vsatisfies-3.0 "package vsatisfies multiple" tip268 { # yes no package vsatisfies 8.4 8.4 7.3 } 1 test package-vsatisfies-3.1 "package vsatisfies multiple" tip268 { # no yes package vsatisfies 8.4 7.3 8.4 } 1 test package-vsatisfies-3.2 "package vsatisfies multiple" tip268 { # yes yes package vsatisfies 8.4.2 8.4 8.4.1 } 1 test package-vsatisfies-3.3 "package vsatisfies multiple" tip268 { # no no package vsatisfies 8.4 7.3 6.1 } 0 proc prefer {args} { set ip [interp create] lappend res [$ip eval {package prefer}] foreach mode $args { lappend res [$ip eval [list package prefer $mode]] } interp delete $ip return $res } test package-prefer-1.0 {default} tip268 { prefer } stable test package-prefer-1.1 {default} tip268 { set ::env(TCL_PKG_PREFER_LATEST) stable ; # value not relevant! set res [prefer] unset ::env(TCL_PKG_PREFER_LATEST) set res } latest test package-prefer-2.0 {wrong\#args} tip268 { catch {package prefer foo bar} msg set msg } {wrong # args: should be "package prefer ?latest|stable?"} test package-prefer-2.1 {bogus argument} tip268 { catch {package prefer foo} msg set msg } {bad preference "foo": must be latest or stable} test package-prefer-3.0 {set, keep} tip268 { package prefer stable } stable test package-prefer-3.1 {set stable, keep} tip268 { prefer stable } {stable stable} test package-prefer-3.2 {set latest, change} tip268 { prefer latest } {stable latest} test package-prefer-3.3 {set latest, keep} tip268 { prefer latest latest } {stable latest latest} test package-prefer-3.4 {set stable, rejected} tip268 { prefer latest stable } {stable latest latest} rename prefer {} set auto_path $oldPath package unknown $oldPkgUnknown concat cleanupTests } # cleanup interp delete $i ::tcltest::cleanupTests return tcl8.4.20/library/0000755003604700454610000000000012153151142012344 5ustar dgp771divtcl8.4.20/library/parray.tcl0000644003604700454610000000145411737050674014371 0ustar dgp771div# parray: # Print the contents of a global array on stdout. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994 Sun Microsystems, Inc. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # proc parray {a {pattern *}} { upvar 1 $a array if {![array exists array]} { error "\"$a\" isn't an array" } set maxl 0 foreach name [lsort [array names array $pattern]] { if {[string length $name] > $maxl} { set maxl [string length $name] } } set maxl [expr {$maxl + [string length $a] + 2}] foreach name [lsort [array names array $pattern]] { set nameString [format %s(%s) $a $name] puts stdout [format "%-*s = %s" $maxl $nameString $array($name)] } } tcl8.4.20/library/safe.tcl0000644003604700454610000006570711737050674014024 0ustar dgp771div# safe.tcl -- # # This file provide a safe loading/sourcing mechanism for safe interpreters. # It implements a virtual path mecanism to hide the real pathnames from the # slave. It runs in a master interpreter and sets up data structure and # aliases that will be invoked when used from a slave interpreter. # # See the safe.n man page for details. # # Copyright (c) 1996-1997 Sun Microsystems, Inc. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # The implementation is based on namespaces. These naming conventions # are followed: # Private procs starts with uppercase. # Public procs are exported and starts with lowercase # # Needed utilities package package require opt 0.4.1; # Create the safe namespace namespace eval ::safe { # Exported API: namespace export interpCreate interpInit interpConfigure interpDelete \ interpAddToAccessPath interpFindInAccessPath setLogCmd #### # # Setup the arguments parsing # #### # Make sure that our temporary variable is local to this # namespace. [Bug 981733] variable temp # Share the descriptions set temp [::tcl::OptKeyRegister { {-accessPath -list {} "access path for the slave"} {-noStatics "prevent loading of statically linked pkgs"} {-statics true "loading of statically linked pkgs"} {-nestedLoadOk "allow nested loading"} {-nested false "nested loading"} {-deleteHook -script {} "delete hook"} }] # create case (slave is optional) ::tcl::OptKeyRegister { {?slave? -name {} "name of the slave (optional)"} } ::safe::interpCreate # adding the flags sub programs to the command program # (relying on Opt's internal implementation details) lappend ::tcl::OptDesc(::safe::interpCreate) $::tcl::OptDesc($temp) # init and configure (slave is needed) ::tcl::OptKeyRegister { {slave -name {} "name of the slave"} } ::safe::interpIC # adding the flags sub programs to the command program # (relying on Opt's internal implementation details) lappend ::tcl::OptDesc(::safe::interpIC) $::tcl::OptDesc($temp) # temp not needed anymore ::tcl::OptKeyDelete $temp # Helper function to resolve the dual way of specifying staticsok # (either by -noStatics or -statics 0) proc InterpStatics {} { foreach v {Args statics noStatics} { upvar $v $v } set flag [::tcl::OptProcArgGiven -noStatics]; if {$flag && (!$noStatics == !$statics) && ([::tcl::OptProcArgGiven -statics])} { return -code error\ "conflicting values given for -statics and -noStatics" } if {$flag} { return [expr {!$noStatics}] } else { return $statics } } # Helper function to resolve the dual way of specifying nested loading # (either by -nestedLoadOk or -nested 1) proc InterpNested {} { foreach v {Args nested nestedLoadOk} { upvar $v $v } set flag [::tcl::OptProcArgGiven -nestedLoadOk]; # note that the test here is the opposite of the "InterpStatics" # one (it is not -noNested... because of the wanted default value) if {$flag && (!$nestedLoadOk != !$nested) && ([::tcl::OptProcArgGiven -nested])} { return -code error\ "conflicting values given for -nested and -nestedLoadOk" } if {$flag} { # another difference with "InterpStatics" return $nestedLoadOk } else { return $nested } } #### # # API entry points that needs argument parsing : # #### # Interface/entry point function and front end for "Create" proc interpCreate {args} { set Args [::tcl::OptKeyParse ::safe::interpCreate $args] InterpCreate $slave $accessPath \ [InterpStatics] [InterpNested] $deleteHook } proc interpInit {args} { set Args [::tcl::OptKeyParse ::safe::interpIC $args] if {![::interp exists $slave]} { return -code error "\"$slave\" is not an interpreter" } InterpInit $slave $accessPath \ [InterpStatics] [InterpNested] $deleteHook; } proc CheckInterp {slave} { if {![IsInterp $slave]} { return -code error \ "\"$slave\" is not an interpreter managed by ::safe::" } } # Interface/entry point function and front end for "Configure" # This code is awfully pedestrian because it would need # more coupling and support between the way we store the # configuration values in safe::interp's and the Opt package # Obviously we would like an OptConfigure # to avoid duplicating all this code everywhere. -> TODO # (the app should share or access easily the program/value # stored by opt) # This is even more complicated by the boolean flags with no values # that we had the bad idea to support for the sake of user simplicity # in create/init but which makes life hard in configure... # So this will be hopefully written and some integrated with opt1.0 # (hopefully for tcl8.1 ?) proc interpConfigure {args} { switch [llength $args] { 1 { # If we have exactly 1 argument # the semantic is to return all the current configuration # We still call OptKeyParse though we know that "slave" # is our given argument because it also checks # for the "-help" option. set Args [::tcl::OptKeyParse ::safe::interpIC $args] CheckInterp $slave set res {} lappend res [list -accessPath [Set [PathListName $slave]]] lappend res [list -statics [Set [StaticsOkName $slave]]] lappend res [list -nested [Set [NestedOkName $slave]]] lappend res [list -deleteHook [Set [DeleteHookName $slave]]] join $res } 2 { # If we have exactly 2 arguments # the semantic is a "configure get" ::tcl::Lassign $args slave arg # get the flag sub program (we 'know' about Opt's internal # representation of data) set desc [lindex [::tcl::OptKeyGetDesc ::safe::interpIC] 2] set hits [::tcl::OptHits desc $arg] if {$hits > 1} { return -code error [::tcl::OptAmbigous $desc $arg] } elseif {$hits == 0} { return -code error [::tcl::OptFlagUsage $desc $arg] } CheckInterp $slave set item [::tcl::OptCurDesc $desc] set name [::tcl::OptName $item] switch -exact -- $name { -accessPath { return [list -accessPath [Set [PathListName $slave]]] } -statics { return [list -statics [Set [StaticsOkName $slave]]] } -nested { return [list -nested [Set [NestedOkName $slave]]] } -deleteHook { return [list -deleteHook [Set [DeleteHookName $slave]]] } -noStatics { # it is most probably a set in fact # but we would need then to jump to the set part # and it is not *sure* that it is a set action # that the user want, so force it to use the # unambigous -statics ?value? instead: return -code error\ "ambigous query (get or set -noStatics ?)\ use -statics instead" } -nestedLoadOk { return -code error\ "ambigous query (get or set -nestedLoadOk ?)\ use -nested instead" } default { return -code error "unknown flag $name (bug)" } } } default { # Otherwise we want to parse the arguments like init and create # did set Args [::tcl::OptKeyParse ::safe::interpIC $args] CheckInterp $slave # Get the current (and not the default) values of # whatever has not been given: if {![::tcl::OptProcArgGiven -accessPath]} { set doreset 1 set accessPath [Set [PathListName $slave]] } else { set doreset 0 } if {(![::tcl::OptProcArgGiven -statics]) \ && (![::tcl::OptProcArgGiven -noStatics]) } { set statics [Set [StaticsOkName $slave]] } else { set statics [InterpStatics] } if {([::tcl::OptProcArgGiven -nested]) \ || ([::tcl::OptProcArgGiven -nestedLoadOk]) } { set nested [InterpNested] } else { set nested [Set [NestedOkName $slave]] } if {![::tcl::OptProcArgGiven -deleteHook]} { set deleteHook [Set [DeleteHookName $slave]] } # we can now reconfigure : InterpSetConfig $slave $accessPath $statics $nested $deleteHook # auto_reset the slave (to completly synch the new access_path) if {$doreset} { if {[catch {::interp eval $slave {auto_reset}} msg]} { Log $slave "auto_reset failed: $msg" } else { Log $slave "successful auto_reset" NOTICE } } } } } #### # # Functions that actually implements the exported APIs # #### # # safe::InterpCreate : doing the real job # # This procedure creates a safe slave and initializes it with the # safe base aliases. # NB: slave name must be simple alphanumeric string, no spaces, # no (), no {},... {because the state array is stored as part of the name} # # Returns the slave name. # # Optional Arguments : # + slave name : if empty, generated name will be used # + access_path: path list controlling where load/source can occur, # if empty: the master auto_path will be used. # + staticsok : flag, if 0 :no static package can be loaded (load {} Xxx) # if 1 :static packages are ok. # + nestedok: flag, if 0 :no loading to sub-sub interps (load xx xx sub) # if 1 : multiple levels are ok. # use the full name and no indent so auto_mkIndex can find us proc ::safe::InterpCreate { slave access_path staticsok nestedok deletehook } { # Create the slave. if {$slave ne ""} { ::interp create -safe $slave } else { # empty argument: generate slave name set slave [::interp create -safe] } Log $slave "Created" NOTICE # Initialize it. (returns slave name) InterpInit $slave $access_path $staticsok $nestedok $deletehook } # # InterpSetConfig (was setAccessPath) : # Sets up slave virtual auto_path and corresponding structure # within the master. Also sets the tcl_library in the slave # to be the first directory in the path. # Nb: If you change the path after the slave has been initialized # you probably need to call "auto_reset" in the slave in order that it # gets the right auto_index() array values. proc ::safe::InterpSetConfig {slave access_path staticsok\ nestedok deletehook} { # determine and store the access path if empty if {$access_path eq ""} { set access_path [uplevel \#0 set auto_path] # Make sure that tcl_library is in auto_path # and at the first position (needed by setAccessPath) set where [lsearch -exact $access_path [info library]] if {$where == -1} { # not found, add it. set access_path [concat [list [info library]] $access_path] Log $slave "tcl_library was not in auto_path,\ added it to slave's access_path" NOTICE } elseif {$where != 0} { # not first, move it first set access_path [concat [list [info library]]\ [lreplace $access_path $where $where]] Log $slave "tcl_libray was not in first in auto_path,\ moved it to front of slave's access_path" NOTICE } # Add 1st level sub dirs (will searched by auto loading from tcl # code in the slave using glob and thus fail, so we add them # here so by default it works the same). set access_path [AddSubDirs $access_path] } Log $slave "Setting accessPath=($access_path) staticsok=$staticsok\ nestedok=$nestedok deletehook=($deletehook)" NOTICE # clear old autopath if it existed set nname [PathNumberName $slave] if {[Exists $nname]} { set n [Set $nname] for {set i 0} {$i<$n} {incr i} { Unset [PathToken $i $slave] } } # build new one set slave_auto_path {} set i 0 foreach dir $access_path { Set [PathToken $i $slave] $dir lappend slave_auto_path "\$[PathToken $i]" incr i } Set $nname $i Set [PathListName $slave] $access_path Set [VirtualPathListName $slave] $slave_auto_path Set [StaticsOkName $slave] $staticsok Set [NestedOkName $slave] $nestedok Set [DeleteHookName $slave] $deletehook SyncAccessPath $slave } # # # FindInAccessPath: # Search for a real directory and returns its virtual Id # (including the "$") proc ::safe::interpFindInAccessPath {slave path} { set access_path [GetAccessPath $slave] set where [lsearch -exact $access_path $path] if {$where == -1} { return -code error "$path not found in access path $access_path" } return "\$[PathToken $where]" } # # addToAccessPath: # add (if needed) a real directory to access path # and return its virtual token (including the "$"). proc ::safe::interpAddToAccessPath {slave path} { # first check if the directory is already in there if {![catch {interpFindInAccessPath $slave $path} res]} { return $res } # new one, add it: set nname [PathNumberName $slave] set n [Set $nname] Set [PathToken $n $slave] $path set token "\$[PathToken $n]" Lappend [VirtualPathListName $slave] $token Lappend [PathListName $slave] $path Set $nname [expr {$n+1}] SyncAccessPath $slave return $token } # This procedure applies the initializations to an already existing # interpreter. It is useful when you want to install the safe base # aliases into a preexisting safe interpreter. proc ::safe::InterpInit { slave access_path staticsok nestedok deletehook } { # Configure will generate an access_path when access_path is # empty. InterpSetConfig $slave $access_path $staticsok $nestedok $deletehook # These aliases let the slave load files to define new commands # NB we need to add [namespace current], aliases are always # absolute paths. ::interp alias $slave source {} [namespace current]::AliasSource $slave ::interp alias $slave load {} [namespace current]::AliasLoad $slave # This alias lets the slave use the encoding names, convertfrom, # convertto, and system, but not "encoding system " to set # the system encoding. ::interp alias $slave encoding {} [namespace current]::AliasEncoding \ $slave # This alias lets the slave have access to a subset of the 'file' # command functionality. AliasSubset $slave file file dir.* join root.* ext.* tail \ path.* split # This alias interposes on the 'exit' command and cleanly terminates # the slave. ::interp alias $slave exit {} [namespace current]::interpDelete $slave # The allowed slave variables already have been set # by Tcl_MakeSafe(3) # Source init.tcl into the slave, to get auto_load and other # procedures defined: # We don't try to use the -rsrc on the mac because it would get # confusing if you would want to customize init.tcl # for a given set of safe slaves, on all the platforms # you just need to give a specific access_path and # the mac should be no exception. As there is no # obvious full "safe ressources" design nor implementation # for the mac, safe interps there will just don't # have that ability. (A specific app can still reenable # that using custom aliases if they want to). # It would also make the security analysis and the Safe Tcl security # model platform dependant and thus more error prone. if {[catch {::interp eval $slave\ {source [file join $tcl_library init.tcl]}} msg]} { Log $slave "can't source init.tcl ($msg)" error "can't source init.tcl into slave $slave ($msg)" } return $slave } # Add (only if needed, avoid duplicates) 1 level of # sub directories to an existing path list. # Also removes non directories from the returned list. proc AddSubDirs {pathList} { set res {} foreach dir $pathList { if {[file isdirectory $dir]} { # check that we don't have it yet as a children # of a previous dir if {[lsearch -exact $res $dir]<0} { lappend res $dir } foreach sub [glob -directory $dir -nocomplain *] { if {([file isdirectory $sub]) \ && ([lsearch -exact $res $sub]<0) } { # new sub dir, add it ! lappend res $sub } } } } return $res } # This procedure deletes a safe slave managed by Safe Tcl and # cleans up associated state: proc ::safe::interpDelete {slave} { Log $slave "About to delete" NOTICE # If the slave has a cleanup hook registered, call it. # check the existance because we might be called to delete an interp # which has not been registered with us at all set hookname [DeleteHookName $slave] if {[Exists $hookname]} { set hook [Set $hookname] if {![::tcl::Lempty $hook]} { # remove the hook now, otherwise if the hook # calls us somehow, we'll loop Unset $hookname if {[catch {eval $hook [list $slave]} err]} { Log $slave "Delete hook error ($err)" } } } # Discard the global array of state associated with the slave, and # delete the interpreter. set statename [InterpStateName $slave] if {[Exists $statename]} { Unset $statename } # if we have been called twice, the interp might have been deleted # already if {[::interp exists $slave]} { ::interp delete $slave Log $slave "Deleted" NOTICE } return } # Set (or get) the loging mecanism proc ::safe::setLogCmd {args} { variable Log if {[llength $args] == 0} { return $Log } else { if {[llength $args] == 1} { set Log [lindex $args 0] } else { set Log $args } } } # internal variable variable Log {} # ------------------- END OF PUBLIC METHODS ------------ # # sets the slave auto_path to the master recorded value. # also sets tcl_library to the first token of the virtual path. # proc SyncAccessPath {slave} { set slave_auto_path [Set [VirtualPathListName $slave]] ::interp eval $slave [list set auto_path $slave_auto_path] Log $slave "auto_path in $slave has been set to $slave_auto_path"\ NOTICE ::interp eval $slave [list set tcl_library [lindex $slave_auto_path 0]] } # base name for storing all the slave states # the array variable name for slave foo is thus "Sfoo" # and for sub slave {foo bar} "Sfoo bar" (spaces are handled # ok everywhere (or should)) # We add the S prefix to avoid that a slave interp called "Log" # would smash our "Log" variable. proc InterpStateName {slave} { return "S$slave" } # Check that the given slave is "one of us" proc IsInterp {slave} { expr {[Exists [InterpStateName $slave]] && [::interp exists $slave]} } # returns the virtual token for directory number N # if the slave argument is given, # it will return the corresponding master global variable name proc PathToken {n {slave ""}} { if {$slave ne ""} { return "[InterpStateName $slave](access_path,$n)" } else { # We need to have a ":" in the token string so # [file join] on the mac won't turn it into a relative # path. return "p(:$n:)" } } # returns the variable name of the complete path list proc PathListName {slave} { return "[InterpStateName $slave](access_path)" } # returns the variable name of the complete path list proc VirtualPathListName {slave} { return "[InterpStateName $slave](access_path_slave)" } # returns the variable name of the number of items proc PathNumberName {slave} { return "[InterpStateName $slave](access_path,n)" } # returns the staticsok flag var name proc StaticsOkName {slave} { return "[InterpStateName $slave](staticsok)" } # returns the nestedok flag var name proc NestedOkName {slave} { return "[InterpStateName $slave](nestedok)" } # Run some code at the namespace toplevel proc Toplevel {args} { namespace eval [namespace current] $args } # set/get values proc Set {args} { eval [linsert $args 0 Toplevel set] } # lappend on toplevel vars proc Lappend {args} { eval [linsert $args 0 Toplevel lappend] } # unset a var/token (currently just an global level eval) proc Unset {args} { eval [linsert $args 0 Toplevel unset] } # test existance proc Exists {varname} { Toplevel info exists $varname } # short cut for access path getting proc GetAccessPath {slave} { Set [PathListName $slave] } # short cut for statics ok flag getting proc StaticsOk {slave} { Set [StaticsOkName $slave] } # short cut for getting the multiples interps sub loading ok flag proc NestedOk {slave} { Set [NestedOkName $slave] } # interp deletion storing hook name proc DeleteHookName {slave} { return [InterpStateName $slave](cleanupHook) } # # translate virtual path into real path # proc TranslatePath {slave path} { # somehow strip the namespaces 'functionality' out (the danger # is that we would strip valid macintosh "../" queries... : if {[regexp {(::)|(\.\.)} $path]} { error "invalid characters in path $path" } set n [expr {[Set [PathNumberName $slave]]-1}] for {} {$n>=0} {incr n -1} { # fill the token virtual names with their real value set [PathToken $n] [Set [PathToken $n $slave]] } # replaces the token by their value subst -nobackslashes -nocommands $path } # Log eventually log an error # to enable error logging, set Log to {puts stderr} for instance proc Log {slave msg {type ERROR}} { variable Log if {[info exists Log] && [llength $Log]} { eval $Log [list "$type for slave $slave : $msg"] } } # file name control (limit access to files/ressources that should be # a valid tcl source file) proc CheckFileName {slave file} { # This used to limit what can be sourced to ".tcl" and forbid files # with more than 1 dot and longer than 14 chars, but I changed that # for 8.4 as a safe interp has enough internal protection already # to allow sourcing anything. - hobbs if {![file exists $file]} { # don't tell the file path error "no such file or directory" } if {![file readable $file]} { # don't tell the file path error "not readable" } } # AliasSource is the target of the "source" alias in safe interpreters. proc AliasSource {slave args} { set argc [llength $args] # Allow only "source filename" # (and not mac specific -rsrc for instance - see comment in ::init # for current rationale) if {$argc != 1} { set msg "wrong # args: should be \"source fileName\"" Log $slave "$msg ($args)" return -code error $msg } set file [lindex $args 0] # get the real path from the virtual one. if {[catch {set file [TranslatePath $slave $file]} msg]} { Log $slave $msg return -code error "permission denied" } # check that the path is in the access path of that slave if {[catch {FileInAccessPath $slave $file} msg]} { Log $slave $msg return -code error "permission denied" } # do the checks on the filename : if {[catch {CheckFileName $slave $file} msg]} { Log $slave "$file:$msg" return -code error $msg } # passed all the tests , lets source it: if {[catch {::interp invokehidden $slave source $file} msg]} { Log $slave $msg return -code error "script error" } return $msg } # AliasLoad is the target of the "load" alias in safe interpreters. proc AliasLoad {slave file args} { set argc [llength $args] if {$argc > 2} { set msg "load error: too many arguments" Log $slave "$msg ($argc) {$file $args}" return -code error $msg } # package name (can be empty if file is not). set package [lindex $args 0] # Determine where to load. load use a relative interp path # and {} means self, so we can directly and safely use passed arg. set target [lindex $args 1] if {$target ne ""} { # we will try to load into a sub sub interp # check that we want to authorize that. if {![NestedOk $slave]} { Log $slave "loading to a sub interp (nestedok)\ disabled (trying to load $package to $target)" return -code error "permission denied (nested load)" } } # Determine what kind of load is requested if {$file eq ""} { # static package loading if {$package eq ""} { set msg "load error: empty filename and no package name" Log $slave $msg return -code error $msg } if {![StaticsOk $slave]} { Log $slave "static packages loading disabled\ (trying to load $package to $target)" return -code error "permission denied (static package)" } } else { # file loading # get the real path from the virtual one. if {[catch {set file [TranslatePath $slave $file]} msg]} { Log $slave $msg return -code error "permission denied" } # check the translated path if {[catch {FileInAccessPath $slave $file} msg]} { Log $slave $msg return -code error "permission denied (path)" } } if {[catch {::interp invokehidden\ $slave load $file $package $target} msg]} { Log $slave $msg return -code error $msg } return $msg } # FileInAccessPath raises an error if the file is not found in # the list of directories contained in the (master side recorded) slave's # access path. # the security here relies on "file dirname" answering the proper # result.... needs checking ? proc FileInAccessPath {slave file} { set access_path [GetAccessPath $slave] if {[file isdirectory $file]} { error "\"$file\": is a directory" } set parent [file dirname $file] # Normalize paths for comparison since lsearch knows nothing of # potential pathname anomalies. set norm_parent [file normalize $parent] foreach path $access_path { lappend norm_access_path [file normalize $path] } if {[lsearch -exact $norm_access_path $norm_parent] == -1} { error "\"$file\": not in access_path" } } # This procedure enables access from a safe interpreter to only a subset of # the subcommands of a command: proc Subset {slave command okpat args} { set subcommand [lindex $args 0] if {[regexp $okpat $subcommand]} { return [eval [linsert $args 0 $command]] } set msg "not allowed to invoke subcommand $subcommand of $command" Log $slave $msg error $msg } # This procedure installs an alias in a slave that invokes "safesubset" # in the master to execute allowed subcommands. It precomputes the pattern # of allowed subcommands; you can use wildcards in the pattern if you wish # to allow subcommand abbreviation. # # Syntax is: AliasSubset slave alias target subcommand1 subcommand2... proc AliasSubset {slave alias target args} { set pat ^(; set sep "" foreach sub $args { append pat $sep$sub set sep | } append pat )\$ ::interp alias $slave $alias {}\ [namespace current]::Subset $slave $target $pat } # AliasEncoding is the target of the "encoding" alias in safe interpreters. proc AliasEncoding {slave args} { set argc [llength $args] set okpat "^(name.*|convert.*)\$" set subcommand [lindex $args 0] if {[regexp $okpat $subcommand]} { return [eval [linsert $args 0 \ ::interp invokehidden $slave encoding]] } if {[string first $subcommand system] == 0} { if {$argc == 1} { # passed all the tests , lets source it: if {[catch {::interp invokehidden \ $slave encoding system} msg]} { Log $slave $msg return -code error "script error" } } else { set msg "wrong # args: should be \"encoding system\"" Log $slave $msg error $msg } } else { set msg "wrong # args: should be \"encoding option ?arg ...?\"" Log $slave $msg error $msg } return $msg } } tcl8.4.20/library/opt/0000755003604700454610000000000012153151142013146 5ustar dgp771divtcl8.4.20/library/opt/pkgIndex.tcl0000644003604700454610000000114111737050674015437 0ustar dgp771div# Tcl package index file, version 1.1 # This file is generated by the "pkg_mkIndex -direct" command # and sourced either when an application starts up or # by a "package unknown" script. It invokes the # "package ifneeded" command to set up package-related # information so that packages will be loaded automatically # in response to "package require" commands. When this # script is sourced, the variable $dir must contain the # full path name of this file's directory. if {![package vsatisfies [package provide Tcl] 8.2]} {return} package ifneeded opt 0.4.4.1 [list source [file join $dir optparse.tcl]] tcl8.4.20/library/opt/optparse.tcl0000644003604700454610000010026611737050674015533 0ustar dgp771div# optparse.tcl -- # # (private) Option parsing package # Primarily used internally by the safe:: code. # # WARNING: This code will go away in a future release # of Tcl. It is NOT supported and you should not rely # on it. If your code does rely on this package you # may directly incorporate this code into your application. package require Tcl 8.2 # When this version number changes, update the pkgIndex.tcl file # and the install directory in the Makefiles. package provide opt 0.4.4.1 namespace eval ::tcl { # Exported APIs namespace export OptKeyRegister OptKeyDelete OptKeyError OptKeyParse \ OptProc OptProcArgGiven OptParse \ Lempty Lget \ Lassign Lvarpop Lvarpop1 Lvarset Lvarincr \ SetMax SetMin ################# Example of use / 'user documentation' ################### proc OptCreateTestProc {} { # Defines ::tcl::OptParseTest as a test proc with parsed arguments # (can't be defined before the code below is loaded (before "OptProc")) # Every OptProc give usage information on "procname -help". # Try "tcl::OptParseTest -help" and "tcl::OptParseTest -a" and # then other arguments. # # example of 'valid' call: # ::tcl::OptParseTest save -4 -pr 23 -libsok SybTcl\ # -nostatics false ch1 OptProc OptParseTest { {subcommand -choice {save print} "sub command"} {arg1 3 "some number"} {-aflag} {-intflag 7} {-weirdflag "help string"} {-noStatics "Not ok to load static packages"} {-nestedloading1 true "OK to load into nested slaves"} {-nestedloading2 -boolean true "OK to load into nested slaves"} {-libsOK -choice {Tk SybTcl} "List of packages that can be loaded"} {-precision -int 12 "Number of digits of precision"} {-intval 7 "An integer"} {-scale -float 1.0 "Scale factor"} {-zoom 1.0 "Zoom factor"} {-arbitrary foobar "Arbitrary string"} {-random -string 12 "Random string"} {-listval -list {} "List value"} {-blahflag -blah abc "Funny type"} {arg2 -boolean "a boolean"} {arg3 -choice "ch1 ch2"} {?optarg? -list {} "optional argument"} } { foreach v [info locals] { puts stderr [format "%14s : %s" $v [set $v]] } } } ################### No User serviceable part below ! ############### # Array storing the parsed descriptions variable OptDesc; array set OptDesc {}; # Next potentially free key id (numeric) variable OptDescN 0; # Inside algorithm/mechanism description: # (not for the faint hearted ;-) # # The argument description is parsed into a "program tree" # It is called a "program" because it is the program used by # the state machine interpreter that use that program to # actually parse the arguments at run time. # # The general structure of a "program" is # notation (pseudo bnf like) # name :== definition defines "name" as being "definition" # { x y z } means list of x, y, and z # x* means x repeated 0 or more time # x+ means "x x*" # x? means optionally x # x | y means x or y # "cccc" means the literal string # # program :== { programCounter programStep* } # # programStep :== program | singleStep # # programCounter :== {"P" integer+ } # # singleStep :== { instruction parameters* } # # instruction :== single element list # # (the difference between singleStep and program is that \ # llength [lindex $program 0] >= 2 # while # llength [lindex $singleStep 0] == 1 # ) # # And for this application: # # singleStep :== { instruction varname {hasBeenSet currentValue} type # typeArgs help } # instruction :== "flags" | "value" # type :== knowType | anyword # knowType :== "string" | "int" | "boolean" | "boolflag" | "float" # | "choice" # # for type "choice" typeArgs is a list of possible choices, the first one # is the default value. for all other types the typeArgs is the default value # # a "boolflag" is the type for a flag whose presence or absence, without # additional arguments means respectively true or false (default flag type). # # programCounter is the index in the list of the currently processed # programStep (thus starting at 1 (0 is {"P" prgCounterValue}). # If it is a list it points toward each currently selected programStep. # (like for "flags", as they are optional, form a set and programStep). # Performance/Implementation issues # --------------------------------- # We use tcl lists instead of arrays because with tcl8.0 # they should start to be much faster. # But this code use a lot of helper procs (like Lvarset) # which are quite slow and would be helpfully optimized # for instance by being written in C. Also our struture # is complex and there is maybe some places where the # string rep might be calculated at great exense. to be checked. # # Parse a given description and saves it here under the given key # generate a unused keyid if not given # proc ::tcl::OptKeyRegister {desc {key ""}} { variable OptDesc; variable OptDescN; if {[string equal $key ""]} { # in case a key given to us as a parameter was a number while {[info exists OptDesc($OptDescN)]} {incr OptDescN} set key $OptDescN; incr OptDescN; } # program counter set program [list [list "P" 1]]; # are we processing flags (which makes a single program step) set inflags 0; set state {}; # flag used to detect that we just have a single (flags set) subprogram. set empty 1; foreach item $desc { if {$state == "args"} { # more items after 'args'... return -code error "'args' special argument must be the last one"; } set res [OptNormalizeOne $item]; set state [lindex $res 0]; if {$inflags} { if {$state == "flags"} { # add to 'subprogram' lappend flagsprg $res; } else { # put in the flags # structure for flag programs items is a list of # {subprgcounter {prg flag 1} {prg flag 2} {...}} lappend program $flagsprg; # put the other regular stuff lappend program $res; set inflags 0; set empty 0; } } else { if {$state == "flags"} { set inflags 1; # sub program counter + first sub program set flagsprg [list [list "P" 1] $res]; } else { lappend program $res; set empty 0; } } } if {$inflags} { if {$empty} { # We just have the subprogram, optimize and remove # unneeded level: set program $flagsprg; } else { lappend program $flagsprg; } } set OptDesc($key) $program; return $key; } # # Free the storage for that given key # proc ::tcl::OptKeyDelete {key} { variable OptDesc; unset OptDesc($key); } # Get the parsed description stored under the given key. proc OptKeyGetDesc {descKey} { variable OptDesc; if {![info exists OptDesc($descKey)]} { return -code error "Unknown option description key \"$descKey\""; } set OptDesc($descKey); } # Parse entry point for ppl who don't want to register with a key, # for instance because the description changes dynamically. # (otherwise one should really use OptKeyRegister once + OptKeyParse # as it is way faster or simply OptProc which does it all) # Assign a temporary key, call OptKeyParse and then free the storage proc ::tcl::OptParse {desc arglist} { set tempkey [OptKeyRegister $desc]; set ret [catch {uplevel 1 [list ::tcl::OptKeyParse $tempkey $arglist]} res]; OptKeyDelete $tempkey; return -code $ret $res; } # Helper function, replacement for proc that both # register the description under a key which is the name of the proc # (and thus unique to that code) # and add a first line to the code to call the OptKeyParse proc # Stores the list of variables that have been actually given by the user # (the other will be sets to their default value) # into local variable named "Args". proc ::tcl::OptProc {name desc body} { set namespace [uplevel 1 [list ::namespace current]]; if {[string match "::*" $name] || [string equal $namespace "::"]} { # absolute name or global namespace, name is the key set key $name; } else { # we are relative to some non top level namespace: set key "${namespace}::${name}"; } OptKeyRegister $desc $key; uplevel 1 [list ::proc $name args "set Args \[::tcl::OptKeyParse $key \$args\]\n$body"]; return $key; } # Check that a argument has been given # assumes that "OptProc" has been used as it will check in "Args" list proc ::tcl::OptProcArgGiven {argname} { upvar Args alist; expr {[lsearch $alist $argname] >=0} } ####### # Programs/Descriptions manipulation # Return the instruction word/list of a given step/(sub)program proc OptInstr {lst} { lindex $lst 0; } # Is a (sub) program or a plain instruction ? proc OptIsPrg {lst} { expr {[llength [OptInstr $lst]]>=2} } # Is this instruction a program counter or a real instr proc OptIsCounter {item} { expr {[lindex $item 0]=="P"} } # Current program counter (2nd word of first word) proc OptGetPrgCounter {lst} { Lget $lst {0 1} } # Current program counter (2nd word of first word) proc OptSetPrgCounter {lstName newValue} { upvar $lstName lst; set lst [lreplace $lst 0 0 [concat "P" $newValue]]; } # returns a list of currently selected items. proc OptSelection {lst} { set res {}; foreach idx [lrange [lindex $lst 0] 1 end] { lappend res [Lget $lst $idx]; } return $res; } # Advance to next description proc OptNextDesc {descName} { uplevel 1 [list Lvarincr $descName {0 1}]; } # Get the current description, eventually descend proc OptCurDesc {descriptions} { lindex $descriptions [OptGetPrgCounter $descriptions]; } # get the current description, eventually descend # through sub programs as needed. proc OptCurDescFinal {descriptions} { set item [OptCurDesc $descriptions]; # Descend untill we get the actual item and not a sub program while {[OptIsPrg $item]} { set item [OptCurDesc $item]; } return $item; } # Current final instruction adress proc OptCurAddr {descriptions {start {}}} { set adress [OptGetPrgCounter $descriptions]; lappend start $adress; set item [lindex $descriptions $adress]; if {[OptIsPrg $item]} { return [OptCurAddr $item $start]; } else { return $start; } } # Set the value field of the current instruction proc OptCurSetValue {descriptionsName value} { upvar $descriptionsName descriptions # get the current item full adress set adress [OptCurAddr $descriptions]; # use the 3th field of the item (see OptValue / OptNewInst) lappend adress 2 Lvarset descriptions $adress [list 1 $value]; # ^hasBeenSet flag } # empty state means done/paste the end of the program proc OptState {item} { lindex $item 0 } # current state proc OptCurState {descriptions} { OptState [OptCurDesc $descriptions]; } ####### # Arguments manipulation # Returns the argument that has to be processed now proc OptCurrentArg {lst} { lindex $lst 0; } # Advance to next argument proc OptNextArg {argsName} { uplevel 1 [list Lvarpop1 $argsName]; } ####### # Loop over all descriptions, calling OptDoOne which will # eventually eat all the arguments. proc OptDoAll {descriptionsName argumentsName} { upvar $descriptionsName descriptions upvar $argumentsName arguments; # puts "entered DoAll"; # Nb: the places where "state" can be set are tricky to figure # because DoOne sets the state to flagsValue and return -continue # when needed... set state [OptCurState $descriptions]; # We'll exit the loop in "OptDoOne" or when state is empty. while 1 { set curitem [OptCurDesc $descriptions]; # Do subprograms if needed, call ourselves on the sub branch while {[OptIsPrg $curitem]} { OptDoAll curitem arguments # puts "done DoAll sub"; # Insert back the results in current tree; Lvarset1nc descriptions [OptGetPrgCounter $descriptions]\ $curitem; OptNextDesc descriptions; set curitem [OptCurDesc $descriptions]; set state [OptCurState $descriptions]; } # puts "state = \"$state\" - arguments=($arguments)"; if {[Lempty $state]} { # Nothing left to do, we are done in this branch: break; } # The following statement can make us terminate/continue # as it use return -code {break, continue, return and error} # codes OptDoOne descriptions state arguments; # If we are here, no special return code where issued, # we'll step to next instruction : # puts "new state = \"$state\""; OptNextDesc descriptions; set state [OptCurState $descriptions]; } } # Process one step for the state machine, # eventually consuming the current argument. proc OptDoOne {descriptionsName stateName argumentsName} { upvar $argumentsName arguments; upvar $descriptionsName descriptions; upvar $stateName state; # the special state/instruction "args" eats all # the remaining args (if any) if {($state == "args")} { if {![Lempty $arguments]} { # If there is no additional arguments, leave the default value # in. OptCurSetValue descriptions $arguments; set arguments {}; } # puts "breaking out ('args' state: consuming every reminding args)" return -code break; } if {[Lempty $arguments]} { if {$state == "flags"} { # no argument and no flags : we're done # puts "returning to previous (sub)prg (no more args)"; return -code return; } elseif {$state == "optValue"} { set state next; # not used, for debug only # go to next state return ; } else { return -code error [OptMissingValue $descriptions]; } } else { set arg [OptCurrentArg $arguments]; } switch $state { flags { # A non-dash argument terminates the options, as does -- # Still a flag ? if {![OptIsFlag $arg]} { # don't consume the argument, return to previous prg return -code return; } # consume the flag OptNextArg arguments; if {[string equal "--" $arg]} { # return from 'flags' state return -code return; } set hits [OptHits descriptions $arg]; if {$hits > 1} { return -code error [OptAmbigous $descriptions $arg] } elseif {$hits == 0} { return -code error [OptFlagUsage $descriptions $arg] } set item [OptCurDesc $descriptions]; if {[OptNeedValue $item]} { # we need a value, next state is set state flagValue; } else { OptCurSetValue descriptions 1; } # continue return -code continue; } flagValue - value { set item [OptCurDesc $descriptions]; # Test the values against their required type if {[catch {OptCheckType $arg\ [OptType $item] [OptTypeArgs $item]} val]} { return -code error [OptBadValue $item $arg $val] } # consume the value OptNextArg arguments; # set the value OptCurSetValue descriptions $val; # go to next state if {$state == "flagValue"} { set state flags return -code continue; } else { set state next; # not used, for debug only return ; # will go on next step } } optValue { set item [OptCurDesc $descriptions]; # Test the values against their required type if {![catch {OptCheckType $arg\ [OptType $item] [OptTypeArgs $item]} val]} { # right type, so : # consume the value OptNextArg arguments; # set the value OptCurSetValue descriptions $val; } # go to next state set state next; # not used, for debug only return ; # will go on next step } } # If we reach this point: an unknown # state as been entered ! return -code error "Bug! unknown state in DoOne \"$state\"\ (prg counter [OptGetPrgCounter $descriptions]:\ [OptCurDesc $descriptions])"; } # Parse the options given the key to previously registered description # and arguments list proc ::tcl::OptKeyParse {descKey arglist} { set desc [OptKeyGetDesc $descKey]; # make sure -help always give usage if {[string equal -nocase "-help" $arglist]} { return -code error [OptError "Usage information:" $desc 1]; } OptDoAll desc arglist; if {![Lempty $arglist]} { return -code error [OptTooManyArgs $desc $arglist]; } # Analyse the result # Walk through the tree: OptTreeVars $desc "#[expr {[info level]-1}]" ; } # determine string length for nice tabulated output proc OptTreeVars {desc level {vnamesLst {}}} { foreach item $desc { if {[OptIsCounter $item]} continue; if {[OptIsPrg $item]} { set vnamesLst [OptTreeVars $item $level $vnamesLst]; } else { set vname [OptVarName $item]; upvar $level $vname var if {[OptHasBeenSet $item]} { # puts "adding $vname" # lets use the input name for the returned list # it is more usefull, for instance you can check that # no flags at all was given with expr # {![string match "*-*" $Args]} lappend vnamesLst [OptName $item]; set var [OptValue $item]; } else { set var [OptDefaultValue $item]; } } } return $vnamesLst } # Check the type of a value # and emit an error if arg is not of the correct type # otherwise returns the canonical value of that arg (ie 0/1 for booleans) proc ::tcl::OptCheckType {arg type {typeArgs ""}} { # puts "checking '$arg' against '$type' ($typeArgs)"; # only types "any", "choice", and numbers can have leading "-" switch -exact -- $type { int { if {![string is integer -strict $arg]} { error "not an integer" } return $arg; } float { return [expr {double($arg)}] } script - list { # if llength fail : malformed list if {[llength $arg]==0 && [OptIsFlag $arg]} { error "no values with leading -" } return $arg; } boolean { if {![string is boolean -strict $arg]} { error "non canonic boolean" } # convert true/false because expr/if is broken with "!,... return [expr {$arg ? 1 : 0}] } choice { if {[lsearch -exact $typeArgs $arg] < 0} { error "invalid choice" } return $arg; } any { return $arg; } string - default { if {[OptIsFlag $arg]} { error "no values with leading -" } return $arg } } return neverReached; } # internal utilities # returns the number of flags matching the given arg # sets the (local) prg counter to the list of matches proc OptHits {descName arg} { upvar $descName desc; set hits 0 set hitems {} set i 1; set larg [string tolower $arg]; set len [string length $larg]; set last [expr {$len-1}]; foreach item [lrange $desc 1 end] { set flag [OptName $item] # lets try to match case insensitively # (string length ought to be cheap) set lflag [string tolower $flag]; if {$len == [string length $lflag]} { if {[string equal $larg $lflag]} { # Exact match case OptSetPrgCounter desc $i; return 1; } } elseif {[string equal $larg [string range $lflag 0 $last]]} { lappend hitems $i; incr hits; } incr i; } if {$hits} { OptSetPrgCounter desc $hitems; } return $hits } # Extract fields from the list structure: proc OptName {item} { lindex $item 1; } proc OptHasBeenSet {item} { Lget $item {2 0}; } proc OptValue {item} { Lget $item {2 1}; } proc OptIsFlag {name} { string match "-*" $name; } proc OptIsOpt {name} { string match {\?*} $name; } proc OptVarName {item} { set name [OptName $item]; if {[OptIsFlag $name]} { return [string range $name 1 end]; } elseif {[OptIsOpt $name]} { return [string trim $name "?"]; } else { return $name; } } proc OptType {item} { lindex $item 3 } proc OptTypeArgs {item} { lindex $item 4 } proc OptHelp {item} { lindex $item 5 } proc OptNeedValue {item} { expr {![string equal [OptType $item] boolflag]} } proc OptDefaultValue {item} { set val [OptTypeArgs $item] switch -exact -- [OptType $item] { choice {return [lindex $val 0]} boolean - boolflag { # convert back false/true to 0/1 because expr !$bool # is broken.. if {$val} { return 1 } else { return 0 } } } return $val } # Description format error helper proc OptOptUsage {item {what ""}} { return -code error "invalid description format$what: $item\n\ should be a list of {varname|-flagname ?-type? ?defaultvalue?\ ?helpstring?}"; } # Generate a canonical form single instruction proc OptNewInst {state varname type typeArgs help} { list $state $varname [list 0 {}] $type $typeArgs $help; # ^ ^ # | | # hasBeenSet=+ +=currentValue } # Translate one item to canonical form proc OptNormalizeOne {item} { set lg [Lassign $item varname arg1 arg2 arg3]; # puts "called optnormalizeone '$item' v=($varname), lg=$lg"; set isflag [OptIsFlag $varname]; set isopt [OptIsOpt $varname]; if {$isflag} { set state "flags"; } elseif {$isopt} { set state "optValue"; } elseif {![string equal $varname "args"]} { set state "value"; } else { set state "args"; } # apply 'smart' 'fuzzy' logic to try to make # description writer's life easy, and our's difficult : # let's guess the missing arguments :-) switch $lg { 1 { if {$isflag} { return [OptNewInst $state $varname boolflag false ""]; } else { return [OptNewInst $state $varname any "" ""]; } } 2 { # varname default # varname help set type [OptGuessType $arg1] if {[string equal $type "string"]} { if {$isflag} { set type boolflag set def false } else { set type any set def "" } set help $arg1 } else { set help "" set def $arg1 } return [OptNewInst $state $varname $type $def $help]; } 3 { # varname type value # varname value comment if {[regexp {^-(.+)$} $arg1 x type]} { # flags/optValue as they are optional, need a "value", # on the contrary, for a variable (non optional), # default value is pointless, 'cept for choices : if {$isflag || $isopt || ($type == "choice")} { return [OptNewInst $state $varname $type $arg2 ""]; } else { return [OptNewInst $state $varname $type "" $arg2]; } } else { return [OptNewInst $state $varname\ [OptGuessType $arg1] $arg1 $arg2] } } 4 { if {[regexp {^-(.+)$} $arg1 x type]} { return [OptNewInst $state $varname $type $arg2 $arg3]; } else { return -code error [OptOptUsage $item]; } } default { return -code error [OptOptUsage $item]; } } } # Auto magic lasy type determination proc OptGuessType {arg} { if {[regexp -nocase {^(true|false)$} $arg]} { return boolean } if {[regexp {^(-+)?[0-9]+$} $arg]} { return int } if {![catch {expr {double($arg)}}]} { return float } return string } # Error messages front ends proc OptAmbigous {desc arg} { OptError "ambigous option \"$arg\", choose from:" [OptSelection $desc] } proc OptFlagUsage {desc arg} { OptError "bad flag \"$arg\", must be one of" $desc; } proc OptTooManyArgs {desc arguments} { OptError "too many arguments (unexpected argument(s): $arguments),\ usage:"\ $desc 1 } proc OptParamType {item} { if {[OptIsFlag $item]} { return "flag"; } else { return "parameter"; } } proc OptBadValue {item arg {err {}}} { # puts "bad val err = \"$err\""; OptError "bad value \"$arg\" for [OptParamType $item]"\ [list $item] } proc OptMissingValue {descriptions} { # set item [OptCurDescFinal $descriptions]; set item [OptCurDesc $descriptions]; OptError "no value given for [OptParamType $item] \"[OptName $item]\"\ (use -help for full usage) :"\ [list $item] } proc ::tcl::OptKeyError {prefix descKey {header 0}} { OptError $prefix [OptKeyGetDesc $descKey] $header; } # determine string length for nice tabulated output proc OptLengths {desc nlName tlName dlName} { upvar $nlName nl; upvar $tlName tl; upvar $dlName dl; foreach item $desc { if {[OptIsCounter $item]} continue; if {[OptIsPrg $item]} { OptLengths $item nl tl dl } else { SetMax nl [string length [OptName $item]] SetMax tl [string length [OptType $item]] set dv [OptTypeArgs $item]; if {[OptState $item] != "header"} { set dv "($dv)"; } set l [string length $dv]; # limit the space allocated to potentially big "choices" if {([OptType $item] != "choice") || ($l<=12)} { SetMax dl $l } else { if {![info exists dl]} { set dl 0 } } } } } # output the tree proc OptTree {desc nl tl dl} { set res ""; foreach item $desc { if {[OptIsCounter $item]} continue; if {[OptIsPrg $item]} { append res [OptTree $item $nl $tl $dl]; } else { set dv [OptTypeArgs $item]; if {[OptState $item] != "header"} { set dv "($dv)"; } append res [format "\n %-*s %-*s %-*s %s" \ $nl [OptName $item] $tl [OptType $item] \ $dl $dv [OptHelp $item]] } } return $res; } # Give nice usage string proc ::tcl::OptError {prefix desc {header 0}} { # determine length if {$header} { # add faked instruction set h [list [OptNewInst header Var/FlagName Type Value Help]]; lappend h [OptNewInst header ------------ ---- ----- ----]; lappend h [OptNewInst header {( -help} "" "" {gives this help )}] set desc [concat $h $desc] } OptLengths $desc nl tl dl # actually output return "$prefix[OptTree $desc $nl $tl $dl]" } ################ General Utility functions ####################### # # List utility functions # Naming convention: # "Lvarxxx" take the list VARiable name as argument # "Lxxxx" take the list value as argument # (which is not costly with Tcl8 objects system # as it's still a reference and not a copy of the values) # # Is that list empty ? proc ::tcl::Lempty {list} { expr {[llength $list]==0} } # Gets the value of one leaf of a lists tree proc ::tcl::Lget {list indexLst} { if {[llength $indexLst] <= 1} { return [lindex $list $indexLst]; } Lget [lindex $list [lindex $indexLst 0]] [lrange $indexLst 1 end]; } # Sets the value of one leaf of a lists tree # (we use the version that does not create the elements because # it would be even slower... needs to be written in C !) # (nb: there is a non trivial recursive problem with indexes 0, # which appear because there is no difference between a list # of 1 element and 1 element alone : [list "a"] == "a" while # it should be {a} and [listp a] should be 0 while [listp {a b}] would be 1 # and [listp "a b"] maybe 0. listp does not exist either...) proc ::tcl::Lvarset {listName indexLst newValue} { upvar $listName list; if {[llength $indexLst] <= 1} { Lvarset1nc list $indexLst $newValue; } else { set idx [lindex $indexLst 0]; set targetList [lindex $list $idx]; # reduce refcount on targetList (not really usefull now, # could be with optimizing compiler) # Lvarset1 list $idx {}; # recursively replace in targetList Lvarset targetList [lrange $indexLst 1 end] $newValue; # put updated sub list back in the tree Lvarset1nc list $idx $targetList; } } # Set one cell to a value, eventually create all the needed elements # (on level-1 of lists) variable emptyList {} proc ::tcl::Lvarset1 {listName index newValue} { upvar $listName list; if {$index < 0} {return -code error "invalid negative index"} set lg [llength $list]; if {$index >= $lg} { variable emptyList; for {set i $lg} {$i<$index} {incr i} { lappend list $emptyList; } lappend list $newValue; } else { set list [lreplace $list $index $index $newValue]; } } # same as Lvarset1 but no bound checking / creation proc ::tcl::Lvarset1nc {listName index newValue} { upvar $listName list; set list [lreplace $list $index $index $newValue]; } # Increments the value of one leaf of a lists tree # (which must exists) proc ::tcl::Lvarincr {listName indexLst {howMuch 1}} { upvar $listName list; if {[llength $indexLst] <= 1} { Lvarincr1 list $indexLst $howMuch; } else { set idx [lindex $indexLst 0]; set targetList [lindex $list $idx]; # reduce refcount on targetList Lvarset1nc list $idx {}; # recursively replace in targetList Lvarincr targetList [lrange $indexLst 1 end] $howMuch; # put updated sub list back in the tree Lvarset1nc list $idx $targetList; } } # Increments the value of one cell of a list proc ::tcl::Lvarincr1 {listName index {howMuch 1}} { upvar $listName list; set newValue [expr {[lindex $list $index]+$howMuch}]; set list [lreplace $list $index $index $newValue]; return $newValue; } # Removes the first element of a list # and returns the new list value proc ::tcl::Lvarpop1 {listName} { upvar $listName list; set list [lrange $list 1 end]; } # Same but returns the removed element # (Like the tclX version) proc ::tcl::Lvarpop {listName} { upvar $listName list; set el [lindex $list 0]; set list [lrange $list 1 end]; return $el; } # Assign list elements to variables and return the length of the list proc ::tcl::Lassign {list args} { # faster than direct blown foreach (which does not byte compile) set i 0; set lg [llength $list]; foreach vname $args { if {$i>=$lg} break uplevel 1 [list ::set $vname [lindex $list $i]]; incr i; } return $lg; } # Misc utilities # Set the varname to value if value is greater than varname's current value # or if varname is undefined proc ::tcl::SetMax {varname value} { upvar 1 $varname var if {![info exists var] || $value > $var} { set var $value } } # Set the varname to value if value is smaller than varname's current value # or if varname is undefined proc ::tcl::SetMin {varname value} { upvar 1 $varname var if {![info exists var] || $value < $var} { set var $value } } # everything loaded fine, lets create the test proc: # OptCreateTestProc # Don't need the create temp proc anymore: # rename OptCreateTestProc {} } tcl8.4.20/library/http/0000755003604700454610000000000012153151142013323 5ustar dgp771divtcl8.4.20/library/http/pkgIndex.tcl0000644003604700454610000000134712133546540015615 0ustar dgp771div# Tcl package index file, version 1.1 # This file is generated by the "pkg_mkIndex" command # and sourced either when an application starts up or # by a "package unknown" script. It invokes the # "package ifneeded" command to set up package-related # information so that packages will be loaded automatically # in response to "package require" commands. When this # script is sourced, the variable $dir must contain the # full path name of this file's directory. if {![package vsatisfies [package provide Tcl] 8.4]} {return} package ifneeded http 2.5.8 [list tclPkgSetup $dir http 2.5.8 {{http.tcl source {::http::config ::http::formatQuery ::http::geturl ::http::reset ::http::wait ::http::register ::http::unregister ::http::mapReply}}}] tcl8.4.20/library/http/http.tcl0000644003604700454610000007063012133546540015024 0ustar dgp771div# http.tcl -- # # Client-side HTTP for GET, POST, and HEAD commands. These routines can # be used in untrusted code that uses the Safesock security policy. These # procedures use a callback interface to avoid using vwait, which is not # defined in the safe base. # # See the file "license.terms" for information on usage and redistribution of # this file, and for a DISCLAIMER OF ALL WARRANTIES. # Rough version history: # 1.0 Old http_get interface. # 2.0 http:: namespace and http::geturl. # 2.1 Added callbacks to handle arriving data, and timeouts. # 2.2 Added ability to fetch into a channel. # 2.3 Added SSL support, and ability to post from a channel. This version # also cleans up error cases and eliminates the "ioerror" status in # favor of raising an error # 2.4 Added -binary option to http::geturl and charset element to the state # array. package require Tcl 8.4 # Keep this in sync with pkgIndex.tcl and with the install directories # in Makefiles package provide http 2.5.8 namespace eval http { variable http array set http { -accept */* -proxyhost {} -proxyport {} -proxyfilter http::ProxyRequired -urlencoding utf-8 } set http(-useragent) "Tcl http client package [package provide http]" proc init {} { # Set up the map for quoting chars. RFC3986 Section 2.3 say percent # encode all except: "... percent-encoded octets in the ranges of ALPHA # (%41-%5A and %61-%7A), DIGIT (%30-%39), hyphen (%2D), period (%2E), # underscore (%5F), or tilde (%7E) should not be created by URI # producers ..." for {set i 0} {$i <= 256} {incr i} { set c [format %c $i] if {![string match {[-._~a-zA-Z0-9]} $c]} { set map($c) %[format %.2X $i] } } # These are handled specially set map(\n) %0D%0A variable formMap [array get map] } init variable urlTypes array set urlTypes { http {80 ::socket} } variable encodings [string tolower [encoding names]] # This can be changed, but iso8859-1 is the RFC standard. variable defaultCharset "iso8859-1" # Force RFC 3986 strictness in geturl url verification? Not for 8.4.x variable strict 0 namespace export geturl config reset wait formatQuery register unregister # Useful, but not exported: data size status code } # http::register -- # # See documentation for details. # # Arguments: # proto URL protocol prefix, e.g. https # port Default port for protocol # command Command to use to create socket # Results: # list of port and command that was registered. proc http::register {proto port command} { variable urlTypes set urlTypes($proto) [list $port $command] } # http::unregister -- # # Unregisters URL protocol handler # # Arguments: # proto URL protocol prefix, e.g. https # Results: # list of port and command that was unregistered. proc http::unregister {proto} { variable urlTypes if {![info exists urlTypes($proto)]} { return -code error "unsupported url type \"$proto\"" } set old $urlTypes($proto) unset urlTypes($proto) return $old } # http::config -- # # See documentation for details. # # Arguments: # args Options parsed by the procedure. # Results: # TODO proc http::config {args} { variable http set options [lsort [array names http -*]] set usage [join $options ", "] if {[llength $args] == 0} { set result {} foreach name $options { lappend result $name $http($name) } return $result } set options [string map {- ""} $options] set pat ^-([join $options |])$ if {[llength $args] == 1} { set flag [lindex $args 0] if {[regexp -- $pat $flag]} { return $http($flag) } else { return -code error "Unknown option $flag, must be: $usage" } } else { foreach {flag value} $args { if {[regexp -- $pat $flag]} { set http($flag) $value } else { return -code error "Unknown option $flag, must be: $usage" } } } } # http::Finish -- # # Clean up the socket and eval close time callbacks # # Arguments: # token Connection token. # errormsg (optional) If set, forces status to error. # skipCB (optional) If set, don't call the -command callback. This # is useful when geturl wants to throw an exception instead # of calling the callback. That way, the same error isn't # reported to two places. # # Side Effects: # Closes the socket proc http::Finish { token {errormsg ""} {skipCB 0}} { variable $token upvar 0 $token state global errorInfo errorCode if {[string length $errormsg] != 0} { set state(error) [list $errormsg $errorInfo $errorCode] set state(status) error } catch {close $state(sock)} catch {after cancel $state(after)} if {[info exists state(-command)] && !$skipCB} { if {[catch {eval $state(-command) {$token}} err]} { if {[string length $errormsg] == 0} { set state(error) [list $err $errorInfo $errorCode] set state(status) error } } if {[info exists state(-command)]} { # Command callback may already have unset our state unset state(-command) } } } # http::reset -- # # See documentation for details. # # Arguments: # token Connection token. # why Status info. # # Side Effects: # See Finish proc http::reset { token {why reset} } { variable $token upvar 0 $token state set state(status) $why catch {fileevent $state(sock) readable {}} catch {fileevent $state(sock) writable {}} Finish $token if {[info exists state(error)]} { set errorlist $state(error) unset state eval ::error $errorlist } } # http::geturl -- # # Establishes a connection to a remote url via http. # # Arguments: # url The http URL to goget. # args Option value pairs. Valid options include: # -blocksize, -validate, -headers, -timeout # Results: # Returns a token for this connection. This token is the name of an array # that the caller should unset to garbage collect the state. proc http::geturl { url args } { variable http variable urlTypes variable defaultCharset variable strict # Initialize the state variable, an array. We'll return the name of this # array as the token for the transaction. if {![info exists http(uid)]} { set http(uid) 0 } set token [namespace current]::[incr http(uid)] variable $token upvar 0 $token state reset $token # Process command options. array set state { -binary false -blocksize 8192 -queryblocksize 8192 -validate 0 -headers {} -timeout 0 -type application/x-www-form-urlencoded -queryprogress {} state header meta {} coding {} currentsize 0 totalsize 0 querylength 0 queryoffset 0 type text/html body {} status "" http "" } # These flags have their types verified [Bug 811170] array set type { -binary boolean -blocksize integer -queryblocksize integer -validate boolean -timeout integer } set state(charset) $defaultCharset set options {-binary -blocksize -channel -command -handler -headers \ -progress -query -queryblocksize -querychannel -queryprogress\ -validate -timeout -type} set usage [join $options ", "] set options [string map {- ""} $options] set pat ^-([join $options |])$ foreach {flag value} $args { if {[regexp $pat $flag]} { # Validate numbers if {[info exists type($flag)] && \ ![string is $type($flag) -strict $value]} { unset $token return -code error "Bad value for $flag ($value), must be $type($flag)" } set state($flag) $value } else { unset $token return -code error "Unknown option $flag, can be: $usage" } } # Make sure -query and -querychannel aren't both specified set isQueryChannel [info exists state(-querychannel)] set isQuery [info exists state(-query)] if {$isQuery && $isQueryChannel} { unset $token return -code error "Can't combine -query and -querychannel options!" } # Validate URL, determine the server host and port, and check proxy case # Recognize user:pass@host URLs also, although we do not do anything with # that info yet. # URLs have basically four parts. # First, before the colon, is the protocol scheme (e.g. http) # Second, for HTTP-like protocols, is the authority # The authority is preceded by // and lasts up to (but not including) # the following / and it identifies up to four parts, of which only one, # the host, is required (if an authority is present at all). All other # parts of the authority (user name, password, port number) are optional. # Third is the resource name, which is split into two parts at a ? # The first part (from the single "/" up to "?") is the path, and the # second part (from that "?" up to "#") is the query. *HOWEVER*, we do # not need to separate them; we send the whole lot to the server. # Fourth is the fragment identifier, which is everything after the first # "#" in the URL. The fragment identifier MUST NOT be sent to the server # and indeed, we don't bother to validate it (it could be an error to # pass it in here, but it's cheap to strip). # # An example of a URL that has all the parts: # http://jschmoe:xyzzy@www.bogus.net:8000/foo/bar.tml?q=foo#changes # The "http" is the protocol, the user is "jschmoe", the password is # "xyzzy", the host is "www.bogus.net", the port is "8000", the path is # "/foo/bar.tml", the query is "q=foo", and the fragment is "changes". # # Note that the RE actually combines the user and password parts, as # recommended in RFC 3986. Indeed, that RFC states that putting passwords # in URLs is a Really Bad Idea, something with which I would agree utterly. # Also note that we do not currently support IPv6 addresses. # # From a validation perspective, we need to ensure that the parts of the # URL that are going to the server are correctly encoded. # This is only done if $::http::strict is true (default 0 for compat). set URLmatcher {(?x) # this is _expanded_ syntax ^ (?: (\w+) : ) ? # (?: // (?: ( [^@/\#?]+ # ) @ )? ( [^/:\#?]+ ) # (?: : (\d+) )? # )? ( [/\?] [^\#]*)? # (including query) (?: \# (.*) )? # $ } # Phase one: parse if {![regexp -- $URLmatcher $url -> proto user host port srvurl]} { unset $token return -code error "Unsupported URL: $url" } # Phase two: validate if {$host eq ""} { # Caller has to provide a host name; we do not have a "default host" # that would enable us to handle relative URLs. unset $token return -code error "Missing host part: $url" # Note that we don't check the hostname for validity here; if it's # invalid, we'll simply fail to resolve it later on. } if {$port ne "" && $port>65535} { unset $token return -code error "Invalid port number: $port" } # The user identification and resource identification parts of the URL can # have encoded characters in them; take care! if {$user ne ""} { # Check for validity according to RFC 3986, Appendix A set validityRE {(?xi) ^ (?: [-\w.~!$&'()*+,;=:] | %[0-9a-f][0-9a-f] )+ $ } if {$strict && ![regexp -- $validityRE $user]} { unset $token # Provide a better error message in this error case if {[regexp {(?i)%(?![0-9a-f][0-9a-f]).?.?} $user bad]} { return -code error \ "Illegal encoding character usage \"$bad\" in URL user" } return -code error "Illegal characters in URL user" } } if {$srvurl ne ""} { # RFC 3986 allows empty paths (not even a /), but servers # return 400 if the path in the HTTP request doesn't start # with / , so add it here if needed. if {[string index $srvurl 0] ne "/"} { set srvurl /$srvurl } # Check for validity according to RFC 3986, Appendix A set validityRE {(?xi) ^ # Path part (already must start with / character) (?: [-\w.~!$&'()*+,;=:@/] | %[0-9a-f][0-9a-f] )* # Query part (optional, permits ? characters) (?: \? (?: [-\w.~!$&'()*+,;=:@/?] | %[0-9a-f][0-9a-f] )* )? $ } if {$strict && ![regexp -- $validityRE $srvurl]} { unset $token # Provide a better error message in this error case if {[regexp {(?i)%(?![0-9a-f][0-9a-f])..} $srvurl bad]} { return -code error \ "Illegal encoding character usage \"$bad\" in URL path" } return -code error "Illegal characters in URL path" } } else { set srvurl / } if {[string length $proto] == 0} { set proto http } if {![info exists urlTypes($proto)]} { unset $token return -code error "Unsupported URL type \"$proto\"" } set defport [lindex $urlTypes($proto) 0] set defcmd [lindex $urlTypes($proto) 1] if {[string length $port] == 0} { set port $defport } if {![catch {$http(-proxyfilter) $host} proxy]} { set phost [lindex $proxy 0] set pport [lindex $proxy 1] } # OK, now reassemble into a full URL set url ${proto}:// if {$user ne ""} { append url $user append url @ } append url $host if {$port != $defport} { append url : $port } append url $srvurl # Don't append the fragment! set state(url) $url # If a timeout is specified we set up the after event and arrange for an # asynchronous socket connection. if {$state(-timeout) > 0} { set state(after) [after $state(-timeout) \ [list http::reset $token timeout]] set async -async } else { set async "" } # If we are using the proxy, we must pass in the full URL that includes # the server name. if {[info exists phost] && [string length $phost]} { set srvurl $url set conStat [catch {eval $defcmd $async {$phost $pport}} s] } else { set conStat [catch {eval $defcmd $async {$host $port}} s] } if {$conStat} { # Something went wrong while trying to establish the connection. Clean # up after events and such, but DON'T call the command callback (if # available) because we're going to throw an exception from here # instead. Finish $token "" 1 cleanup $token return -code error $s } set state(sock) $s # Wait for the connection to complete. if {$state(-timeout) > 0} { fileevent $s writable [list http::Connect $token] http::wait $token if {![info exists state]} { # If we timed out then Finish has been called and the users # command callback may have cleaned up the token. If so # we end up here with nothing left to do. return $token } else { if {$state(status) eq "error"} { # Something went wrong while trying to establish the connection. # Clean up after events and such, but DON'T call the command # callback (if available) because we're going to throw an # exception from here instead. set err [lindex $state(error) 0] cleanup $token return -code error $err } elseif {$state(status) ne "connect"} { # Likely to be connection timeout return $token } set state(status) "" } } # Send data in cr-lf format, but accept any line terminators fconfigure $s -translation {auto crlf} -buffersize $state(-blocksize) # The following is disallowed in safe interpreters, but the socket is # already in non-blocking mode in that case. catch {fconfigure $s -blocking off} set how GET if {$isQuery} { set state(querylength) [string length $state(-query)] if {$state(querylength) > 0} { set how POST set contDone 0 } else { # There's no query data. unset state(-query) set isQuery 0 } } elseif {$state(-validate)} { set how HEAD } elseif {$isQueryChannel} { set how POST # The query channel must be blocking for the async Write to # work properly. fconfigure $state(-querychannel) -blocking 1 -translation binary set contDone 0 } if {[catch { puts $s "$how $srvurl HTTP/1.0" puts $s "Accept: $http(-accept)" if {$port == $defport} { # Don't add port in this case, to handle broken servers. [Bug # 504508] puts $s "Host: $host" } else { puts $s "Host: $host:$port" } puts $s "User-Agent: $http(-useragent)" foreach {key value} $state(-headers) { set value [string map [list \n "" \r ""] $value] set key [string trim $key] if {$key eq "Content-Length"} { set contDone 1 set state(querylength) $value } if {[string length $key]} { puts $s "$key: $value" } } if {$isQueryChannel && $state(querylength) == 0} { # Try to determine size of data in channel. If we cannot seek, the # surrounding catch will trap us set start [tell $state(-querychannel)] seek $state(-querychannel) 0 end set state(querylength) \ [expr {[tell $state(-querychannel)] - $start}] seek $state(-querychannel) $start } # Flush the request header and set up the fileevent that will either # push the POST data or read the response. # # fileevent note: # # It is possible to have both the read and write fileevents active at # this point. The only scenario it seems to affect is a server that # closes the connection without reading the POST data. (e.g., early # versions TclHttpd in various error cases). Depending on the platform, # the client may or may not be able to get the response from the server # because of the error it will get trying to write the post data. # Having both fileevents active changes the timing and the behavior, # but no two platforms (among Solaris, Linux, and NT) behave the same, # and none behave all that well in any case. Servers should always read # their POST data if they expect the client to read their response. if {$isQuery || $isQueryChannel} { puts $s "Content-Type: $state(-type)" if {!$contDone} { puts $s "Content-Length: $state(querylength)" } puts $s "" fconfigure $s -translation {auto binary} fileevent $s writable [list http::Write $token] } else { puts $s "" flush $s fileevent $s readable [list http::Event $token] } if {! [info exists state(-command)]} { # geturl does EVERYTHING asynchronously, so if the user calls it # synchronously, we just do a wait here. wait $token if {$state(status) eq "error"} { # Something went wrong, so throw the exception, and the # enclosing catch will do cleanup. return -code error [lindex $state(error) 0] } } } err]} { # The socket probably was never connected, or the connection dropped # later. # Clean up after events and such, but DON'T call the command callback # (if available) because we're going to throw an exception from here # instead. # if state(status) is error, it means someone's already called Finish # to do the above-described clean up. if {$state(status) ne "error"} { Finish $token $err 1 } cleanup $token return -code error $err } return $token } # Data access functions: # Data - the URL data # Status - the transaction status: ok, reset, eof, timeout # Code - the HTTP transaction code, e.g., 200 # Size - the size of the URL data proc http::data {token} { variable $token upvar 0 $token state return $state(body) } proc http::status {token} { if {![info exists $token]} { return "error" } variable $token upvar 0 $token state return $state(status) } proc http::code {token} { variable $token upvar 0 $token state return $state(http) } proc http::ncode {token} { variable $token upvar 0 $token state if {[regexp {[0-9]{3}} $state(http) numeric_code]} { return $numeric_code } else { return $state(http) } } proc http::size {token} { variable $token upvar 0 $token state return $state(currentsize) } proc http::meta {token} { variable $token upvar 0 $token state return $state(meta) } proc http::error {token} { variable $token upvar 0 $token state if {[info exists state(error)]} { return $state(error) } return "" } # http::cleanup # # Garbage collect the state associated with a transaction # # Arguments # token The token returned from http::geturl # # Side Effects # unsets the state array proc http::cleanup {token} { variable $token upvar 0 $token state if {[info exists state]} { unset state } } # http::Connect # # This callback is made when an asyncronous connection completes. # # Arguments # token The token returned from http::geturl # # Side Effects # Sets the status of the connection, which unblocks # the waiting geturl call proc http::Connect {token} { variable $token upvar 0 $token state set err "due to unexpected EOF" if {[eof $state(sock)] || [string length [set err [fconfigure $state(sock) -error]]]} { Finish $token "connect failed $err" 1 } else { set state(status) connect fileevent $state(sock) writable {} } return } # http::Write # # Write POST query data to the socket # # Arguments # token The token for the connection # # Side Effects # Write the socket and handle callbacks. proc http::Write {token} { variable $token upvar 0 $token state set s $state(sock) # Output a block. Tcl will buffer this if the socket blocks set done 0 if {[catch { # Catch I/O errors on dead sockets if {[info exists state(-query)]} { # Chop up large query strings so queryprogress callback can give # smooth feedback. puts -nonewline $s \ [string range $state(-query) $state(queryoffset) \ [expr {$state(queryoffset) + $state(-queryblocksize) - 1}]] incr state(queryoffset) $state(-queryblocksize) if {$state(queryoffset) >= $state(querylength)} { set state(queryoffset) $state(querylength) set done 1 } } else { # Copy blocks from the query channel set outStr [read $state(-querychannel) $state(-queryblocksize)] puts -nonewline $s $outStr incr state(queryoffset) [string length $outStr] if {[eof $state(-querychannel)]} { set done 1 } } } err]} { # Do not call Finish here, but instead let the read half of the socket # process whatever server reply there is to get. set state(posterror) $err set done 1 } if {$done} { catch {flush $s} fileevent $s writable {} fileevent $s readable [list http::Event $token] } # Callback to the client after we've completely handled everything. if {[string length $state(-queryprogress)]} { eval $state(-queryprogress) [list $token $state(querylength)\ $state(queryoffset)] } } # http::Event # # Handle input on the socket # # Arguments # token The token returned from http::geturl # # Side Effects # Read the socket and handle callbacks. proc http::Event {token} { variable $token upvar 0 $token state set s $state(sock) if {$state(state) eq "header"} { if {[catch {gets $s line} n]} { return [Finish $token $n] } elseif {$n == 0} { variable encodings set state(state) body if {$state(-binary) || ![string match -nocase text* $state(type)] || [string match *gzip* $state(coding)] || [string match *compress* $state(coding)]} { # Turn off conversions for non-text data fconfigure $s -translation binary if {[info exists state(-channel)]} { fconfigure $state(-channel) -translation binary } } else { # If we are getting text, set the incoming channel's encoding # correctly. iso8859-1 is the RFC default, but this could be # any IANA charset. However, we only know how to convert what # we have encodings for. set idx [lsearch -exact $encodings \ [string tolower $state(charset)]] if {$idx >= 0} { fconfigure $s -encoding [lindex $encodings $idx] } } if {[info exists state(-channel)] && \ ![info exists state(-handler)]} { # Initiate a sequence of background fcopies fileevent $s readable {} CopyStart $s $token return } } elseif {$n > 0} { if {[regexp -nocase {^content-type:(.+)$} $line x type]} { set state(type) [string trim $type] # grab the optional charset information regexp -nocase {charset\s*=\s*(\S+)} $type x state(charset) } if {[regexp -nocase {^content-length:(.+)$} $line x length]} { set state(totalsize) [string trim $length] } if {[regexp -nocase {^content-encoding:(.+)$} $line x coding]} { set state(coding) [string trim $coding] } if {[regexp -nocase {^([^:]+):(.+)$} $line x key value]} { lappend state(meta) $key [string trim $value] } elseif {[string match HTTP* $line]} { set state(http) $line } } } else { if {[catch { if {[info exists state(-handler)]} { set n [eval $state(-handler) {$s $token}] } else { set block [read $s $state(-blocksize)] set n [string length $block] if {$n >= 0} { append state(body) $block } } if {$n >= 0} { incr state(currentsize) $n } } err]} { return [Finish $token $err] } else { if {[info exists state(-progress)]} { eval $state(-progress) \ {$token $state(totalsize) $state(currentsize)} } } } if {[eof $s]} { Eof $token return } } # http::CopyStart # # Error handling wrapper around fcopy # # Arguments # s The socket to copy from # token The token returned from http::geturl # # Side Effects # This closes the connection upon error proc http::CopyStart {s token} { variable $token upvar 0 $token state if {[catch { fcopy $s $state(-channel) -size $state(-blocksize) -command \ [list http::CopyDone $token] } err]} { Finish $token $err } } # http::CopyDone # # fcopy completion callback # # Arguments # token The token returned from http::geturl # count The amount transfered # # Side Effects # Invokes callbacks proc http::CopyDone {token count {error {}}} { variable $token upvar 0 $token state set s $state(sock) incr state(currentsize) $count if {[info exists state(-progress)]} { eval $state(-progress) {$token $state(totalsize) $state(currentsize)} } # At this point the token may have been reset if {[string length $error]} { Finish $token $error } elseif {[catch {eof $s} iseof] || $iseof} { Eof $token } else { CopyStart $s $token } } # http::Eof # # Handle eof on the socket # # Arguments # token The token returned from http::geturl # # Side Effects # Clean up the socket proc http::Eof {token} { variable $token upvar 0 $token state if {$state(state) eq "header"} { # Premature eof set state(status) eof } else { set state(status) ok } set state(state) eof Finish $token } # http::wait -- # # See documentation for details. # # Arguments: # token Connection token. # # Results: # The status after the wait. proc http::wait {token} { variable $token upvar 0 $token state if {![info exists state(status)] || [string length $state(status)] == 0} { # We must wait on the original variable name, not the upvar alias vwait $token\(status) } return [status $token] } # http::formatQuery -- # # See documentation for details. Call http::formatQuery with an even # number of arguments, where the first is a name, the second is a value, # the third is another name, and so on. # # Arguments: # args A list of name-value pairs. # # Results: # TODO proc http::formatQuery {args} { set result "" set sep "" foreach i $args { append result $sep [mapReply $i] if {$sep eq "="} { set sep & } else { set sep = } } return $result } # http::mapReply -- # # Do x-www-urlencoded character mapping # # Arguments: # string The string the needs to be encoded # # Results: # The encoded string proc http::mapReply {string} { variable http variable formMap # The spec says: "non-alphanumeric characters are replaced by '%HH'". Use # a pre-computed map and [string map] to do the conversion (much faster # than [regsub]/[subst]). [Bug 1020491] if {$http(-urlencoding) ne ""} { set string [encoding convertto $http(-urlencoding) $string] return [string map $formMap $string] } set converted [string map $formMap $string] if {[string match "*\[\u0100-\uffff\]*" $converted]} { regexp {[\u0100-\uffff]} $converted badChar # Return this error message for maximum compatability... :^/ return -code error \ "can't read \"formMap($badChar)\": no such element in array" } return $converted } # http::ProxyRequired -- # Default proxy filter. # # Arguments: # host The destination host # # Results: # The current proxy settings proc http::ProxyRequired {host} { variable http if {[info exists http(-proxyhost)] && [string length $http(-proxyhost)]} { if {![info exists http(-proxyport)] || \ ![string length $http(-proxyport)]} { set http(-proxyport) 8080 } return [list $http(-proxyhost) $http(-proxyport)] } } # Local variables: # indent-tabs-mode: t # End: tcl8.4.20/library/tcltest/0000755003604700454610000000000012153151142014026 5ustar dgp771divtcl8.4.20/library/tcltest/pkgIndex.tcl0000644003604700454610000000114312133546540016312 0ustar dgp771div# Tcl package index file, version 1.1 # This file is generated by the "pkg_mkIndex -direct" command # and sourced either when an application starts up or # by a "package unknown" script. It invokes the # "package ifneeded" command to set up package-related # information so that packages will be loaded automatically # in response to "package require" commands. When this # script is sourced, the variable $dir must contain the # full path name of this file's directory. if {![package vsatisfies [package provide Tcl] 8.3]} {return} package ifneeded tcltest 2.2.11 [list source [file join $dir tcltest.tcl]] tcl8.4.20/library/tcltest/tcltest.tcl0000644003604700454610000030121012133546540016221 0ustar dgp771div# tcltest.tcl -- # # This file contains support code for the Tcl test suite. It # defines the tcltest namespace and finds and defines the output # directory, constraints available, output and error channels, # etc. used by Tcl tests. See the tcltest man page for more # details. # # This design was based on the Tcl testing approach designed and # initially implemented by Mary Ann May-Pumphrey of Sun # Microsystems. # # Copyright (c) 1994-1997 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # Copyright (c) 2000 by Ajuba Solutions # Contributions from Don Porter, NIST, 2002. (not subject to US copyright) # All rights reserved. package require Tcl 8.3 ;# uses [glob -directory] namespace eval tcltest { # When the version number changes, be sure to update the pkgIndex.tcl file, # and the install directory in the Makefiles. When the minor version # changes (new feature) be sure to update the man page as well. variable Version 2.2.11 # Compatibility support for dumb variables defined in tcltest 1 # Do not use these. Call [package provide Tcl] and [info patchlevel] # yourself. You don't need tcltest to wrap it for you. variable version [package provide Tcl] variable patchLevel [info patchlevel] ##### Export the public tcltest procs; several categories # # Export the main functional commands that do useful things namespace export cleanupTests loadTestedCommands makeDirectory \ makeFile removeDirectory removeFile runAllTests test # Export configuration commands that control the functional commands namespace export configure customMatch errorChannel interpreter \ outputChannel testConstraint # Export commands that are duplication (candidates for deprecation) namespace export bytestring ;# dups [encoding convertfrom identity] namespace export debug ;# [configure -debug] namespace export errorFile ;# [configure -errfile] namespace export limitConstraints ;# [configure -limitconstraints] namespace export loadFile ;# [configure -loadfile] namespace export loadScript ;# [configure -load] namespace export match ;# [configure -match] namespace export matchFiles ;# [configure -file] namespace export matchDirectories ;# [configure -relateddir] namespace export normalizeMsg ;# application of [customMatch] namespace export normalizePath ;# [file normalize] (8.4) namespace export outputFile ;# [configure -outfile] namespace export preserveCore ;# [configure -preservecore] namespace export singleProcess ;# [configure -singleproc] namespace export skip ;# [configure -skip] namespace export skipFiles ;# [configure -notfile] namespace export skipDirectories ;# [configure -asidefromdir] namespace export temporaryDirectory ;# [configure -tmpdir] namespace export testsDirectory ;# [configure -testdir] namespace export verbose ;# [configure -verbose] namespace export viewFile ;# binary encoding [read] namespace export workingDirectory ;# [cd] [pwd] # Export deprecated commands for tcltest 1 compatibility namespace export getMatchingFiles mainThread restoreState saveState \ threadReap # tcltest::normalizePath -- # # This procedure resolves any symlinks in the path thus creating # a path without internal redirection. It assumes that the # incoming path is absolute. # # Arguments # pathVar - name of variable containing path to modify. # # Results # The path is modified in place. # # Side Effects: # None. # proc normalizePath {pathVar} { upvar $pathVar path set oldpwd [pwd] catch {cd $path} set path [pwd] cd $oldpwd return $path } ##### Verification commands used to test values of variables and options # # Verification command that accepts everything proc AcceptAll {value} { return $value } # Verification command that accepts valid Tcl lists proc AcceptList { list } { return [lrange $list 0 end] } # Verification command that accepts a glob pattern proc AcceptPattern { pattern } { return [AcceptAll $pattern] } # Verification command that accepts integers proc AcceptInteger { level } { return [incr level 0] } # Verification command that accepts boolean values proc AcceptBoolean { boolean } { return [expr {$boolean && $boolean}] } # Verification command that accepts (syntactically) valid Tcl scripts proc AcceptScript { script } { if {![info complete $script]} { return -code error "invalid Tcl script: $script" } return $script } # Verification command that accepts (converts to) absolute pathnames proc AcceptAbsolutePath { path } { return [file join [pwd] $path] } # Verification command that accepts existing readable directories proc AcceptReadable { path } { if {![file readable $path]} { return -code error "\"$path\" is not readable" } return $path } proc AcceptDirectory { directory } { set directory [AcceptAbsolutePath $directory] if {![file exists $directory]} { return -code error "\"$directory\" does not exist" } if {![file isdir $directory]} { return -code error "\"$directory\" is not a directory" } return [AcceptReadable $directory] } ##### Initialize internal arrays of tcltest, but only if the caller # has not already pre-initialized them. This is done to support # compatibility with older tests that directly access internals # rather than go through command interfaces. # proc ArrayDefault {varName value} { variable $varName if {[array exists $varName]} { return } if {[info exists $varName]} { # Pre-initialized value is a scalar: destroy it! unset $varName } array set $varName $value } # save the original environment so that it can be restored later ArrayDefault originalEnv [array get ::env] # initialize numTests array to keep track of the number of tests # that pass, fail, and are skipped. ArrayDefault numTests [list Total 0 Passed 0 Skipped 0 Failed 0] # createdNewFiles will store test files as indices and the list of # files (that should not have been) left behind by the test files # as values. ArrayDefault createdNewFiles {} # initialize skippedBecause array to keep track of constraints that # kept tests from running; a constraint name of "userSpecifiedSkip" # means that the test appeared on the list of tests that matched the # -skip value given to the flag; "userSpecifiedNonMatch" means that # the test didn't match the argument given to the -match flag; both # of these constraints are counted only if tcltest::debug is set to # true. ArrayDefault skippedBecause {} # initialize the testConstraints array to keep track of valid # predefined constraints (see the explanation for the # InitConstraints proc for more details). ArrayDefault testConstraints {} ##### Initialize internal variables of tcltest, but only if the caller # has not already pre-initialized them. This is done to support # compatibility with older tests that directly access internals # rather than go through command interfaces. # proc Default {varName value {verify AcceptAll}} { variable $varName if {![info exists $varName]} { variable $varName [$verify $value] } else { variable $varName [$verify [set $varName]] } } # Save any arguments that we might want to pass through to other # programs. This is used by the -args flag. # FINDUSER Default parameters {} # Count the number of files tested (0 if runAllTests wasn't called). # runAllTests will set testSingleFile to false, so stats will # not be printed until runAllTests calls the cleanupTests proc. # The currentFailure var stores the boolean value of whether the # current test file has had any failures. The failFiles list # stores the names of test files that had failures. Default numTestFiles 0 AcceptInteger Default testSingleFile true AcceptBoolean Default currentFailure false AcceptBoolean Default failFiles {} AcceptList # Tests should remove all files they create. The test suite will # check the current working dir for files created by the tests. # filesMade keeps track of such files created using the makeFile and # makeDirectory procedures. filesExisted stores the names of # pre-existing files. # # Note that $filesExisted lists only those files that exist in # the original [temporaryDirectory]. Default filesMade {} AcceptList Default filesExisted {} AcceptList proc FillFilesExisted {} { variable filesExisted # Save the names of files that already exist in the scratch directory. foreach file [glob -nocomplain -directory [temporaryDirectory] *] { lappend filesExisted [file tail $file] } # After successful filling, turn this into a no-op. proc FillFilesExisted args {} } # Kept only for compatibility Default constraintsSpecified {} AcceptList trace variable constraintsSpecified r {set ::tcltest::constraintsSpecified \ [array names ::tcltest::testConstraints] ;# } # tests that use threads need to know which is the main thread Default mainThread 1 variable mainThread if {[info commands thread::id] != {}} { set mainThread [thread::id] } elseif {[info commands testthread] != {}} { set mainThread [testthread id] } # Set workingDirectory to [pwd]. The default output directory for # Tcl tests is the working directory. Whenever this value changes # change to that directory. variable workingDirectory trace variable workingDirectory w \ [namespace code {cd $workingDirectory ;#}] Default workingDirectory [pwd] AcceptAbsolutePath proc workingDirectory { {dir ""} } { variable workingDirectory if {[llength [info level 0]] == 1} { return $workingDirectory } set workingDirectory [AcceptAbsolutePath $dir] } # Set the location of the execuatble Default tcltest [info nameofexecutable] trace variable tcltest w [namespace code {testConstraint stdio \ [eval [ConstraintInitializer stdio]] ;#}] # save the platform information so it can be restored later Default originalTclPlatform [array get ::tcl_platform] # If a core file exists, save its modification time. if {[file exists [file join [workingDirectory] core]]} { Default coreModTime \ [file mtime [file join [workingDirectory] core]] } # stdout and stderr buffers for use when we want to store them Default outData {} Default errData {} # keep track of test level for nested test commands variable testLevel 0 # the variables and procs that existed when saveState was called are # stored in a variable of the same name Default saveState {} # Internationalization support -- used in [SetIso8859_1_Locale] and # [RestoreLocale]. Those commands are used in cmdIL.test. if {![info exists [namespace current]::isoLocale]} { variable isoLocale fr switch -- $::tcl_platform(platform) { "unix" { # Try some 'known' values for some platforms: switch -exact -- $::tcl_platform(os) { "FreeBSD" { set isoLocale fr_FR.ISO_8859-1 } HP-UX { set isoLocale fr_FR.iso88591 } Linux - IRIX { set isoLocale fr } default { # Works on SunOS 4 and Solaris, and maybe # others... Define it to something else on your # system if you want to test those. set isoLocale iso_8859_1 } } } "windows" { set isoLocale French } } } variable ChannelsWeOpened; array set ChannelsWeOpened {} # output goes to stdout by default Default outputChannel stdout proc outputChannel { {filename ""} } { variable outputChannel variable ChannelsWeOpened # This is very subtle and tricky, so let me try to explain. # (Hopefully this longer comment will be clear when I come # back in a few months, unlike its predecessor :) ) # # The [outputChannel] command (and underlying variable) have to # be kept in sync with the [configure -outfile] configuration # option ( and underlying variable Option(-outfile) ). This is # accomplished with a write trace on Option(-outfile) that will # update [outputChannel] whenver a new value is written. That # much is easy. # # The trick is that in order to maintain compatibility with # version 1 of tcltest, we must allow every configuration option # to get its inital value from command line arguments. This is # accomplished by setting initial read traces on all the # configuration options to parse the command line option the first # time they are read. These traces are cancelled whenever the # program itself calls [configure]. # # OK, then so to support tcltest 1 compatibility, it seems we want # to get the return from [outputFile] to trigger the read traces, # just in case. # # BUT! A little known feature of Tcl variable traces is that # traces are disabled during the handling of other traces. So, # if we trigger read traces on Option(-outfile) and that triggers # command line parsing which turns around and sets an initial # value for Option(-outfile) -- -- the write trace that # would keep [outputChannel] in sync with that new initial value # would not fire! # # SO, finally, as a workaround, instead of triggering read traces # by invoking [outputFile], we instead trigger the same set of # read traces by invoking [debug]. Any command that reads a # configuration option would do. [debug] is just a handy one. # The end result is that we support tcltest 1 compatibility and # keep outputChannel and -outfile in sync in all cases. debug if {[llength [info level 0]] == 1} { return $outputChannel } if {[info exists ChannelsWeOpened($outputChannel)]} { close $outputChannel unset ChannelsWeOpened($outputChannel) } switch -exact -- $filename { stderr - stdout { set outputChannel $filename } default { set outputChannel [open $filename a] set ChannelsWeOpened($outputChannel) 1 # If we created the file in [temporaryDirectory], then # [cleanupTests] will delete it, unless we claim it was # already there. set outdir [normalizePath [file dirname \ [file join [pwd] $filename]]] if {[string equal $outdir [temporaryDirectory]]} { variable filesExisted FillFilesExisted set filename [file tail $filename] if {[lsearch -exact $filesExisted $filename] == -1} { lappend filesExisted $filename } } } } return $outputChannel } # errors go to stderr by default Default errorChannel stderr proc errorChannel { {filename ""} } { variable errorChannel variable ChannelsWeOpened # This is subtle and tricky. See the comment above in # [outputChannel] for a detailed explanation. debug if {[llength [info level 0]] == 1} { return $errorChannel } if {[info exists ChannelsWeOpened($errorChannel)]} { close $errorChannel unset ChannelsWeOpened($errorChannel) } switch -exact -- $filename { stderr - stdout { set errorChannel $filename } default { set errorChannel [open $filename a] set ChannelsWeOpened($errorChannel) 1 # If we created the file in [temporaryDirectory], then # [cleanupTests] will delete it, unless we claim it was # already there. set outdir [normalizePath [file dirname \ [file join [pwd] $filename]]] if {[string equal $outdir [temporaryDirectory]]} { variable filesExisted FillFilesExisted set filename [file tail $filename] if {[lsearch -exact $filesExisted $filename] == -1} { lappend filesExisted $filename } } } } return $errorChannel } ##### Set up the configurable options # # The configurable options of the package variable Option; array set Option {} # Usage strings for those options variable Usage; array set Usage {} # Verification commands for those options variable Verify; array set Verify {} # Initialize the default values of the configurable options that are # historically associated with an exported variable. If that variable # is already set, support compatibility by accepting its pre-set value. # Use [trace] to establish ongoing connection between the deprecated # exported variable and the modern option kept as a true internal var. # Also set up usage string and value testing for the option. proc Option {option value usage {verify AcceptAll} {varName {}}} { variable Option variable Verify variable Usage variable OptionControlledVariables variable DefaultValue set Usage($option) $usage set Verify($option) $verify set DefaultValue($option) $value if {[catch {$verify $value} msg]} { return -code error $msg } else { set Option($option) $msg } if {[string length $varName]} { variable $varName if {[info exists $varName]} { if {[catch {$verify [set $varName]} msg]} { return -code error $msg } else { set Option($option) $msg } unset $varName } namespace eval [namespace current] \ [list upvar 0 Option($option) $varName] # Workaround for Bug (now Feature Request) 572889. Grrrr.... # Track all the variables tied to options lappend OptionControlledVariables $varName # Later, set auto-configure read traces on all # of them, since a single trace on Option does not work. proc $varName {{value {}}} [subst -nocommands { if {[llength [info level 0]] == 2} { Configure $option [set value] } return [Configure $option] }] } } proc MatchingOption {option} { variable Option set match [array names Option $option*] switch -- [llength $match] { 0 { set sorted [lsort [array names Option]] set values [join [lrange $sorted 0 end-1] ", "] append values ", or [lindex $sorted end]" return -code error "unknown option $option: should be\ one of $values" } 1 { return [lindex $match 0] } default { # Exact match trumps ambiguity if {[lsearch -exact $match $option] >= 0} { return $option } set values [join [lrange $match 0 end-1] ", "] append values ", or [lindex $match end]" return -code error "ambiguous option $option:\ could match $values" } } } proc EstablishAutoConfigureTraces {} { variable OptionControlledVariables foreach varName [concat $OptionControlledVariables Option] { variable $varName trace variable $varName r [namespace code {ProcessCmdLineArgs ;#}] } } proc RemoveAutoConfigureTraces {} { variable OptionControlledVariables foreach varName [concat $OptionControlledVariables Option] { variable $varName foreach pair [trace vinfo $varName] { foreach {op cmd} $pair break if {[string equal r $op] && [string match *ProcessCmdLineArgs* $cmd]} { trace vdelete $varName $op $cmd } } } # Once the traces are removed, this can become a no-op proc RemoveAutoConfigureTraces {} {} } proc Configure args { variable Option variable Verify set n [llength $args] if {$n == 0} { return [lsort [array names Option]] } if {$n == 1} { if {[catch {MatchingOption [lindex $args 0]} option]} { return -code error $option } return $Option($option) } while {[llength $args] > 1} { if {[catch {MatchingOption [lindex $args 0]} option]} { return -code error $option } if {[catch {$Verify($option) [lindex $args 1]} value]} { return -code error "invalid $option\ value \"[lindex $args 1]\": $value" } set Option($option) $value set args [lrange $args 2 end] } if {[llength $args]} { if {[catch {MatchingOption [lindex $args 0]} option]} { return -code error $option } return -code error "missing value for option $option" } } proc configure args { if {[llength $args] > 1} { RemoveAutoConfigureTraces } set code [catch {eval Configure $args} msg] return -code $code $msg } proc AcceptVerbose { level } { set level [AcceptList $level] if {[llength $level] == 1} { if {![regexp {^(pass|body|skip|start|error)$} $level]} { # translate single characters abbreviations to expanded list set level [string map {p pass b body s skip t start e error} \ [split $level {}]] } } set valid [list] foreach v $level { if {[regexp {^(pass|body|skip|start|error)$} $v]} { lappend valid $v } } return $valid } proc IsVerbose {level} { variable Option return [expr {[lsearch -exact $Option(-verbose) $level] != -1}] } # Default verbosity is to show bodies of failed tests Option -verbose {body error} { Takes any combination of the values 'p', 's', 'b', 't' and 'e'. Test suite will display all passed tests if 'p' is specified, all skipped tests if 's' is specified, the bodies of failed tests if 'b' is specified, and when tests start if 't' is specified. ErrorInfo is displayed if 'e' is specified. } AcceptVerbose verbose # Match and skip patterns default to the empty list, except for # matchFiles, which defaults to all .test files in the # testsDirectory and matchDirectories, which defaults to all # directories. Option -match * { Run all tests within the specified files that match one of the list of glob patterns given. } AcceptList match Option -skip {} { Skip all tests within the specified tests (via -match) and files that match one of the list of glob patterns given. } AcceptList skip Option -file *.test { Run tests in all test files that match the glob pattern given. } AcceptPattern matchFiles # By default, skip files that appear to be SCCS lock files. Option -notfile l.*.test { Skip all test files that match the glob pattern given. } AcceptPattern skipFiles Option -relateddir * { Run tests in directories that match the glob pattern given. } AcceptPattern matchDirectories Option -asidefromdir {} { Skip tests in directories that match the glob pattern given. } AcceptPattern skipDirectories # By default, don't save core files Option -preservecore 0 { If 2, save any core files produced during testing in the directory specified by -tmpdir. If 1, notify the user if core files are created. } AcceptInteger preserveCore # debug output doesn't get printed by default; debug level 1 spits # up only the tests that were skipped because they didn't match or # were specifically skipped. A debug level of 2 would spit up the # tcltest variables and flags provided; a debug level of 3 causes # some additional output regarding operations of the test harness. # The tcltest package currently implements only up to debug level 3. Option -debug 0 { Internal debug level } AcceptInteger debug proc SetSelectedConstraints args { variable Option foreach c $Option(-constraints) { testConstraint $c 1 } } Option -constraints {} { Do not skip the listed constraints listed in -constraints. } AcceptList trace variable Option(-constraints) w \ [namespace code {SetSelectedConstraints ;#}] # Don't run only the "-constraint" specified tests by default proc ClearUnselectedConstraints args { variable Option variable testConstraints if {!$Option(-limitconstraints)} {return} foreach c [array names testConstraints] { if {[lsearch -exact $Option(-constraints) $c] == -1} { testConstraint $c 0 } } } Option -limitconstraints 0 { whether to run only tests with the constraints } AcceptBoolean limitConstraints trace variable Option(-limitconstraints) w \ [namespace code {ClearUnselectedConstraints ;#}] # A test application has to know how to load the tested commands # into the interpreter. Option -load {} { Specifies the script to load the tested commands. } AcceptScript loadScript # Default is to run each test file in a separate process Option -singleproc 0 { whether to run all tests in one process } AcceptBoolean singleProcess proc AcceptTemporaryDirectory { directory } { set directory [AcceptAbsolutePath $directory] if {![file exists $directory]} { file mkdir $directory } set directory [AcceptDirectory $directory] if {![file writable $directory]} { if {[string equal [workingDirectory] $directory]} { # Special exception: accept the default value # even if the directory is not writable return $directory } return -code error "\"$directory\" is not writeable" } return $directory } # Directory where files should be created Option -tmpdir [workingDirectory] { Save temporary files in the specified directory. } AcceptTemporaryDirectory temporaryDirectory trace variable Option(-tmpdir) w \ [namespace code {normalizePath Option(-tmpdir) ;#}] # Tests should not rely on the current working directory. # Files that are part of the test suite should be accessed relative # to [testsDirectory] Option -testdir [workingDirectory] { Search tests in the specified directory. } AcceptDirectory testsDirectory trace variable Option(-testdir) w \ [namespace code {normalizePath Option(-testdir) ;#}] proc AcceptLoadFile { file } { if {[string equal "" $file]} {return $file} set file [file join [temporaryDirectory] $file] return [AcceptReadable $file] } proc ReadLoadScript {args} { variable Option if {[string equal "" $Option(-loadfile)]} {return} set tmp [open $Option(-loadfile) r] loadScript [read $tmp] close $tmp } Option -loadfile {} { Read the script to load the tested commands from the specified file. } AcceptLoadFile loadFile trace variable Option(-loadfile) w [namespace code ReadLoadScript] proc AcceptOutFile { file } { if {[string equal stderr $file]} {return $file} if {[string equal stdout $file]} {return $file} return [file join [temporaryDirectory] $file] } # output goes to stdout by default Option -outfile stdout { Send output from test runs to the specified file. } AcceptOutFile outputFile trace variable Option(-outfile) w \ [namespace code {outputChannel $Option(-outfile) ;#}] # errors go to stderr by default Option -errfile stderr { Send errors from test runs to the specified file. } AcceptOutFile errorFile trace variable Option(-errfile) w \ [namespace code {errorChannel $Option(-errfile) ;#}] } ##################################################################### # tcltest::Debug* -- # # Internal helper procedures to write out debug information # dependent on the chosen level. A test shell may overide # them, f.e. to redirect the output into a different # channel, or even into a GUI. # tcltest::DebugPuts -- # # Prints the specified string if the current debug level is # higher than the provided level argument. # # Arguments: # level The lowest debug level triggering the output # string The string to print out. # # Results: # Prints the string. Nothing else is allowed. # # Side Effects: # None. # proc tcltest::DebugPuts {level string} { variable debug if {$debug >= $level} { puts $string } return } # tcltest::DebugPArray -- # # Prints the contents of the specified array if the current # debug level is higher than the provided level argument # # Arguments: # level The lowest debug level triggering the output # arrayvar The name of the array to print out. # # Results: # Prints the contents of the array. Nothing else is allowed. # # Side Effects: # None. # proc tcltest::DebugPArray {level arrayvar} { variable debug if {$debug >= $level} { catch {upvar $arrayvar $arrayvar} parray $arrayvar } return } # Define our own [parray] in ::tcltest that will inherit use of the [puts] # defined in ::tcltest. NOTE: Ought to construct with [info args] and # [info default], but can't be bothered now. If [parray] changes, then # this will need changing too. auto_load ::parray proc tcltest::parray {a {pattern *}} [info body ::parray] # tcltest::DebugDo -- # # Executes the script if the current debug level is greater than # the provided level argument # # Arguments: # level The lowest debug level triggering the execution. # script The tcl script executed upon a debug level high enough. # # Results: # Arbitrary side effects, dependent on the executed script. # # Side Effects: # None. # proc tcltest::DebugDo {level script} { variable debug if {$debug >= $level} { uplevel 1 $script } return } ##################################################################### proc tcltest::Warn {msg} { puts [outputChannel] "WARNING: $msg" } # tcltest::mainThread # # Accessor command for tcltest variable mainThread. # proc tcltest::mainThread { {new ""} } { variable mainThread if {[llength [info level 0]] == 1} { return $mainThread } set mainThread $new } # tcltest::testConstraint -- # # sets a test constraint to a value; to do multiple constraints, # call this proc multiple times. also returns the value of the # named constraint if no value was supplied. # # Arguments: # constraint - name of the constraint # value - new value for constraint (should be boolean) - if not # supplied, this is a query # # Results: # content of tcltest::testConstraints($constraint) # # Side effects: # none proc tcltest::testConstraint {constraint {value ""}} { variable testConstraints variable Option DebugPuts 3 "entering testConstraint $constraint $value" if {[llength [info level 0]] == 2} { return $testConstraints($constraint) } # Check for boolean values if {[catch {expr {$value && $value}} msg]} { return -code error $msg } if {[limitConstraints] && [lsearch -exact $Option(-constraints) $constraint] == -1} { set value 0 } set testConstraints($constraint) $value } # tcltest::interpreter -- # # the interpreter name stored in tcltest::tcltest # # Arguments: # executable name # # Results: # content of tcltest::tcltest # # Side effects: # None. proc tcltest::interpreter { {interp ""} } { variable tcltest if {[llength [info level 0]] == 1} { return $tcltest } if {[string equal {} $interp]} { set tcltest {} } else { set tcltest $interp } } ##################################################################### # tcltest::AddToSkippedBecause -- # # Increments the variable used to track how many tests were # skipped because of a particular constraint. # # Arguments: # constraint The name of the constraint to be modified # # Results: # Modifies tcltest::skippedBecause; sets the variable to 1 if # didn't previously exist - otherwise, it just increments it. # # Side effects: # None. proc tcltest::AddToSkippedBecause { constraint {value 1}} { # add the constraint to the list of constraints that kept tests # from running variable skippedBecause if {[info exists skippedBecause($constraint)]} { incr skippedBecause($constraint) $value } else { set skippedBecause($constraint) $value } return } # tcltest::PrintError -- # # Prints errors to tcltest::errorChannel and then flushes that # channel, making sure that all messages are < 80 characters per # line. # # Arguments: # errorMsg String containing the error to be printed # # Results: # None. # # Side effects: # None. proc tcltest::PrintError {errorMsg} { set InitialMessage "Error: " set InitialMsgLen [string length $InitialMessage] puts -nonewline [errorChannel] $InitialMessage # Keep track of where the end of the string is. set endingIndex [string length $errorMsg] if {$endingIndex < (80 - $InitialMsgLen)} { puts [errorChannel] $errorMsg } else { # Print up to 80 characters on the first line, including the # InitialMessage. set beginningIndex [string last " " [string range $errorMsg 0 \ [expr {80 - $InitialMsgLen}]]] puts [errorChannel] [string range $errorMsg 0 $beginningIndex] while {![string equal end $beginningIndex]} { puts -nonewline [errorChannel] \ [string repeat " " $InitialMsgLen] if {($endingIndex - $beginningIndex) < (80 - $InitialMsgLen)} { puts [errorChannel] [string trim \ [string range $errorMsg $beginningIndex end]] break } else { set newEndingIndex [expr {[string last " " \ [string range $errorMsg $beginningIndex \ [expr {$beginningIndex + (80 - $InitialMsgLen)}] ]] + $beginningIndex}] if {($newEndingIndex <= 0) || ($newEndingIndex <= $beginningIndex)} { set newEndingIndex end } puts [errorChannel] [string trim \ [string range $errorMsg \ $beginningIndex $newEndingIndex]] set beginningIndex $newEndingIndex } } } flush [errorChannel] return } # tcltest::SafeFetch -- # # The following trace procedure makes it so that we can safely # refer to non-existent members of the testConstraints array # without causing an error. Instead, reading a non-existent # member will return 0. This is necessary because tests are # allowed to use constraint "X" without ensuring that # testConstraints("X") is defined. # # Arguments: # n1 - name of the array (testConstraints) # n2 - array key value (constraint name) # op - operation performed on testConstraints (generally r) # # Results: # none # # Side effects: # sets testConstraints($n2) to 0 if it's referenced but never # before used proc tcltest::SafeFetch {n1 n2 op} { variable testConstraints DebugPuts 3 "entering SafeFetch $n1 $n2 $op" if {[string equal {} $n2]} {return} if {![info exists testConstraints($n2)]} { if {[catch {testConstraint $n2 [eval [ConstraintInitializer $n2]]}]} { testConstraint $n2 0 } } } # tcltest::ConstraintInitializer -- # # Get or set a script that when evaluated in the tcltest namespace # will return a boolean value with which to initialize the # associated constraint. # # Arguments: # constraint - name of the constraint initialized by the script # script - the initializer script # # Results # boolean value of the constraint - enabled or disabled # # Side effects: # Constraint is initialized for future reference by [test] proc tcltest::ConstraintInitializer {constraint {script ""}} { variable ConstraintInitializer DebugPuts 3 "entering ConstraintInitializer $constraint $script" if {[llength [info level 0]] == 2} { return $ConstraintInitializer($constraint) } # Check for boolean values if {![info complete $script]} { return -code error "ConstraintInitializer must be complete script" } set ConstraintInitializer($constraint) $script } # tcltest::InitConstraints -- # # Call all registered constraint initializers to force initialization # of all known constraints. # See the tcltest man page for the list of built-in constraints defined # in this procedure. # # Arguments: # none # # Results: # The testConstraints array is reset to have an index for each # built-in test constraint. # # Side Effects: # None. # proc tcltest::InitConstraints {} { variable ConstraintInitializer initConstraintsHook foreach constraint [array names ConstraintInitializer] { testConstraint $constraint } } proc tcltest::DefineConstraintInitializers {} { ConstraintInitializer singleTestInterp {singleProcess} # All the 'pc' constraints are here for backward compatibility and # are not documented. They have been replaced with equivalent 'win' # constraints. ConstraintInitializer unixOnly \ {string equal $::tcl_platform(platform) unix} ConstraintInitializer macOnly \ {string equal $::tcl_platform(platform) macintosh} ConstraintInitializer pcOnly \ {string equal $::tcl_platform(platform) windows} ConstraintInitializer winOnly \ {string equal $::tcl_platform(platform) windows} ConstraintInitializer unix {testConstraint unixOnly} ConstraintInitializer mac {testConstraint macOnly} ConstraintInitializer pc {testConstraint pcOnly} ConstraintInitializer win {testConstraint winOnly} ConstraintInitializer unixOrPc \ {expr {[testConstraint unix] || [testConstraint pc]}} ConstraintInitializer macOrPc \ {expr {[testConstraint mac] || [testConstraint pc]}} ConstraintInitializer unixOrWin \ {expr {[testConstraint unix] || [testConstraint win]}} ConstraintInitializer macOrWin \ {expr {[testConstraint mac] || [testConstraint win]}} ConstraintInitializer macOrUnix \ {expr {[testConstraint mac] || [testConstraint unix]}} ConstraintInitializer nt {string equal $::tcl_platform(os) "Windows NT"} ConstraintInitializer 95 {string equal $::tcl_platform(os) "Windows 95"} ConstraintInitializer 98 {string equal $::tcl_platform(os) "Windows 98"} # The following Constraints switches are used to mark tests that # should work, but have been temporarily disabled on certain # platforms because they don't and we haven't gotten around to # fixing the underlying problem. ConstraintInitializer tempNotPc {expr {![testConstraint pc]}} ConstraintInitializer tempNotWin {expr {![testConstraint win]}} ConstraintInitializer tempNotMac {expr {![testConstraint mac]}} ConstraintInitializer tempNotUnix {expr {![testConstraint unix]}} # The following Constraints switches are used to mark tests that # crash on certain platforms, so that they can be reactivated again # when the underlying problem is fixed. ConstraintInitializer pcCrash {expr {![testConstraint pc]}} ConstraintInitializer winCrash {expr {![testConstraint win]}} ConstraintInitializer macCrash {expr {![testConstraint mac]}} ConstraintInitializer unixCrash {expr {![testConstraint unix]}} # Skip empty tests ConstraintInitializer emptyTest {format 0} # By default, tests that expose known bugs are skipped. ConstraintInitializer knownBug {format 0} # By default, non-portable tests are skipped. ConstraintInitializer nonPortable {format 0} # Some tests require user interaction. ConstraintInitializer userInteraction {format 0} # Some tests must be skipped if the interpreter is not in # interactive mode ConstraintInitializer interactive \ {expr {[info exists ::tcl_interactive] && $::tcl_interactive}} # Some tests can only be run if the installation came from a CD # image instead of a web image. Some tests must be skipped if you # are running as root on Unix. Other tests can only be run if you # are running as root on Unix. ConstraintInitializer root {expr \ {[string equal unix $::tcl_platform(platform)] && ([string equal root $::tcl_platform(user)] || [string equal "" $::tcl_platform(user)])}} ConstraintInitializer notRoot {expr {![testConstraint root]}} # Set nonBlockFiles constraint: 1 means this platform supports # setting files into nonblocking mode. ConstraintInitializer nonBlockFiles { set code [expr {[catch {set f [open defs r]}] || [catch {fconfigure $f -blocking off}]}] catch {close $f} set code } # Set asyncPipeClose constraint: 1 means this platform supports # async flush and async close on a pipe. # # Test for SCO Unix - cannot run async flushing tests because a # potential problem with select is apparently interfering. # (Mark Diekhans). ConstraintInitializer asyncPipeClose {expr { !([string equal unix $::tcl_platform(platform)] && ([catch {exec uname -X | fgrep {Release = 3.2v}}] == 0))}} # Test to see if we have a broken version of sprintf with respect # to the "e" format of floating-point numbers. ConstraintInitializer eformat {string equal [format %g 5e-5] 5e-05} # Test to see if execed commands such as cat, echo, rm and so forth # are present on this machine. ConstraintInitializer unixExecs { set code 1 if {[string equal macintosh $::tcl_platform(platform)]} { set code 0 } if {[string equal windows $::tcl_platform(platform)]} { if {[catch { set file _tcl_test_remove_me.txt makeFile {hello} $file }]} { set code 0 } elseif { [catch {exec cat $file}] || [catch {exec echo hello}] || [catch {exec sh -c echo hello}] || [catch {exec wc $file}] || [catch {exec sleep 1}] || [catch {exec echo abc > $file}] || [catch {exec chmod 644 $file}] || [catch {exec rm $file}] || [llength [auto_execok mkdir]] == 0 || [llength [auto_execok fgrep]] == 0 || [llength [auto_execok grep]] == 0 || [llength [auto_execok ps]] == 0 } { set code 0 } removeFile $file } set code } ConstraintInitializer stdio { set code 0 if {![catch {set f [open "|[list [interpreter]]" w]}]} { if {![catch {puts $f exit}]} { if {![catch {close $f}]} { set code 1 } } } set code } # Deliberately call socket with the wrong number of arguments. The # error message you get will indicate whether sockets are available # on this system. ConstraintInitializer socket { catch {socket} msg string compare $msg "sockets are not available on this system" } # Check for internationalization ConstraintInitializer hasIsoLocale { if {[llength [info commands testlocale]] == 0} { set code 0 } else { set code [string length [SetIso8859_1_Locale]] RestoreLocale } set code } } ##################################################################### # Usage and command line arguments processing. # tcltest::PrintUsageInfo # # Prints out the usage information for package tcltest. This can # be customized with the redefinition of [PrintUsageInfoHook]. # # Arguments: # none # # Results: # none # # Side Effects: # none proc tcltest::PrintUsageInfo {} { puts [Usage] PrintUsageInfoHook } proc tcltest::Usage { {option ""} } { variable Usage variable Verify if {[llength [info level 0]] == 1} { set msg "Usage: [file tail [info nameofexecutable]] script " append msg "?-help? ?flag value? ... \n" append msg "Available flags (and valid input values) are:" set max 0 set allOpts [concat -help [Configure]] foreach opt $allOpts { set foo [Usage $opt] foreach [list x type($opt) usage($opt)] $foo break set line($opt) " $opt $type($opt) " set length($opt) [string length $line($opt)] if {$length($opt) > $max} {set max $length($opt)} } set rest [expr {72 - $max}] foreach opt $allOpts { append msg \n$line($opt) append msg [string repeat " " [expr {$max - $length($opt)}]] set u [string trim $usage($opt)] catch {append u " (default: \[[Configure $opt]])"} regsub -all {\s*\n\s*} $u " " u while {[string length $u] > $rest} { set break [string wordstart $u $rest] if {$break == 0} { set break [string wordend $u 0] } append msg [string range $u 0 [expr {$break - 1}]] set u [string trim [string range $u $break end]] append msg \n[string repeat " " $max] } append msg $u } return $msg\n } elseif {[string equal -help $option]} { return [list -help "" "Display this usage information."] } else { set type [lindex [info args $Verify($option)] 0] return [list $option $type $Usage($option)] } } # tcltest::ProcessFlags -- # # process command line arguments supplied in the flagArray - this # is called by processCmdLineArgs. Modifies tcltest variables # according to the content of the flagArray. # # Arguments: # flagArray - array containing name/value pairs of flags # # Results: # sets tcltest variables according to their values as defined by # flagArray # # Side effects: # None. proc tcltest::ProcessFlags {flagArray} { # Process -help first if {[lsearch -exact $flagArray {-help}] != -1} { PrintUsageInfo exit 1 } if {[llength $flagArray] == 0} { RemoveAutoConfigureTraces } else { set args $flagArray while {[llength $args]>1 && [catch {eval [linsert $args 0 configure]} msg]} { # Something went wrong parsing $args for tcltest options # Check whether the problem is "unknown option" if {[regexp {^unknown option (\S+):} $msg -> option]} { # Could be this is an option the Hook knows about set moreOptions [processCmdLineArgsAddFlagsHook] if {[lsearch -exact $moreOptions $option] == -1} { # Nope. Report the error, including additional options, # but keep going if {[llength $moreOptions]} { append msg ", " append msg [join [lrange $moreOptions 0 end-1] ", "] append msg "or [lindex $moreOptions end]" } Warn $msg } } else { # error is something other than "unknown option" # notify user of the error; and exit puts [errorChannel] $msg exit 1 } # To recover, find that unknown option and remove up to it. # then retry while {![string equal [lindex $args 0] $option]} { set args [lrange $args 2 end] } set args [lrange $args 2 end] } if {[llength $args] == 1} { puts [errorChannel] \ "missing value for option [lindex $args 0]" exit 1 } } # Call the hook catch { array set flag $flagArray processCmdLineArgsHook [array get flag] } return } # tcltest::ProcessCmdLineArgs -- # # This procedure must be run after constraint initialization is # set up (by [DefineConstraintInitializers]) because some constraints # can be overridden. # # Perform configuration according to the command-line options. # # Arguments: # none # # Results: # Sets the above-named variables in the tcltest namespace. # # Side Effects: # None. # proc tcltest::ProcessCmdLineArgs {} { variable originalEnv variable testConstraints # The "argv" var doesn't exist in some cases, so use {}. if {![info exists ::argv]} { ProcessFlags {} } else { ProcessFlags $::argv } # Spit out everything you know if we're at a debug level 2 or # greater DebugPuts 2 "Flags passed into tcltest:" if {[info exists ::env(TCLTEST_OPTIONS)]} { DebugPuts 2 \ " ::env(TCLTEST_OPTIONS): $::env(TCLTEST_OPTIONS)" } if {[info exists ::argv]} { DebugPuts 2 " argv: $::argv" } DebugPuts 2 "tcltest::debug = [debug]" DebugPuts 2 "tcltest::testsDirectory = [testsDirectory]" DebugPuts 2 "tcltest::workingDirectory = [workingDirectory]" DebugPuts 2 "tcltest::temporaryDirectory = [temporaryDirectory]" DebugPuts 2 "tcltest::outputChannel = [outputChannel]" DebugPuts 2 "tcltest::errorChannel = [errorChannel]" DebugPuts 2 "Original environment (tcltest::originalEnv):" DebugPArray 2 originalEnv DebugPuts 2 "Constraints:" DebugPArray 2 testConstraints } ##################################################################### # Code to run the tests goes here. # tcltest::TestPuts -- # # Used to redefine puts in test environment. Stores whatever goes # out on stdout in tcltest::outData and stderr in errData before # sending it on to the regular puts. # # Arguments: # same as standard puts # # Results: # none # # Side effects: # Intercepts puts; data that would otherwise go to stdout, stderr, # or file channels specified in outputChannel and errorChannel # does not get sent to the normal puts function. namespace eval tcltest::Replace { namespace export puts } proc tcltest::Replace::puts {args} { variable [namespace parent]::outData variable [namespace parent]::errData switch [llength $args] { 1 { # Only the string to be printed is specified append outData [lindex $args 0]\n return # return [Puts [lindex $args 0]] } 2 { # Either -nonewline or channelId has been specified if {[string equal -nonewline [lindex $args 0]]} { append outData [lindex $args end] return # return [Puts -nonewline [lindex $args end]] } else { set channel [lindex $args 0] set newline \n } } 3 { if {[string equal -nonewline [lindex $args 0]]} { # Both -nonewline and channelId are specified, unless # it's an error. -nonewline is supposed to be argv[0]. set channel [lindex $args 1] set newline "" } } } if {[info exists channel]} { if {[string equal $channel [[namespace parent]::outputChannel]] || [string equal $channel stdout]} { append outData [lindex $args end]$newline return } elseif {[string equal $channel [[namespace parent]::errorChannel]] || [string equal $channel stderr]} { append errData [lindex $args end]$newline return } } # If we haven't returned by now, we don't know how to handle the # input. Let puts handle it. return [eval Puts $args] } # tcltest::Eval -- # # Evaluate the script in the test environment. If ignoreOutput is # false, store data sent to stderr and stdout in outData and # errData. Otherwise, ignore this output altogether. # # Arguments: # script Script to evaluate # ?ignoreOutput? Indicates whether or not to ignore output # sent to stdout & stderr # # Results: # result from running the script # # Side effects: # Empties the contents of outData and errData before running a # test if ignoreOutput is set to 0. proc tcltest::Eval {script {ignoreOutput 1}} { variable outData variable errData DebugPuts 3 "[lindex [info level 0] 0] called" if {!$ignoreOutput} { set outData {} set errData {} rename ::puts [namespace current]::Replace::Puts namespace eval :: \ [list namespace import [namespace origin Replace::puts]] namespace import Replace::puts } set result [uplevel 1 $script] if {!$ignoreOutput} { namespace forget puts namespace eval :: namespace forget puts rename [namespace current]::Replace::Puts ::puts } return $result } # tcltest::CompareStrings -- # # compares the expected answer to the actual answer, depending on # the mode provided. Mode determines whether a regexp, exact, # glob or custom comparison is done. # # Arguments: # actual - string containing the actual result # expected - pattern to be matched against # mode - type of comparison to be done # # Results: # result of the match # # Side effects: # None. proc tcltest::CompareStrings {actual expected mode} { variable CustomMatch if {![info exists CustomMatch($mode)]} { return -code error "No matching command registered for `-match $mode'" } set match [namespace eval :: $CustomMatch($mode) [list $expected $actual]] if {[catch {expr {$match && $match}} result]} { return -code error "Invalid result from `-match $mode' command: $result" } return $match } # tcltest::customMatch -- # # registers a command to be called when a particular type of # matching is required. # # Arguments: # nickname - Keyword for the type of matching # cmd - Incomplete command that implements that type of matching # when completed with expected string and actual string # and then evaluated. # # Results: # None. # # Side effects: # Sets the variable tcltest::CustomMatch proc tcltest::customMatch {mode script} { variable CustomMatch if {![info complete $script]} { return -code error \ "invalid customMatch script; can't evaluate after completion" } set CustomMatch($mode) $script } # tcltest::SubstArguments list # # This helper function takes in a list of words, then perform a # substitution on the list as though each word in the list is a separate # argument to the Tcl function. For example, if this function is # invoked as: # # SubstArguments {$a {$a}} # # Then it is as though the function is invoked as: # # SubstArguments $a {$a} # # This code is adapted from Paul Duffin's function "SplitIntoWords". # The original function can be found on: # # http://purl.org/thecliff/tcl/wiki/858.html # # Results: # a list containing the result of the substitution # # Exceptions: # An error may occur if the list containing unbalanced quote or # unknown variable. # # Side Effects: # None. # proc tcltest::SubstArguments {argList} { # We need to split the argList up into tokens but cannot use list # operations as they throw away some significant quoting, and # [split] ignores braces as it should. Therefore what we do is # gradually build up a string out of whitespace seperated strings. # We cannot use [split] to split the argList into whitespace # separated strings as it throws away the whitespace which maybe # important so we have to do it all by hand. set result {} set token "" while {[string length $argList]} { # Look for the next word containing a quote: " { } if {[regexp -indices {[^ \t\n]*[\"\{\}]+[^ \t\n]*} \ $argList all]} { # Get the text leading up to this word, but not including # this word, from the argList. set text [string range $argList 0 \ [expr {[lindex $all 0] - 1}]] # Get the word with the quote set word [string range $argList \ [lindex $all 0] [lindex $all 1]] # Remove all text up to and including the word from the # argList. set argList [string range $argList \ [expr {[lindex $all 1] + 1}] end] } else { # Take everything up to the end of the argList. set text $argList set word {} set argList {} } if {$token != {}} { # If we saw a word with quote before, then there is a # multi-word token starting with that word. In this case, # add the text and the current word to this token. append token $text $word } else { # Add the text to the result. There is no need to parse # the text because it couldn't be a part of any multi-word # token. Then start a new multi-word token with the word # because we need to pass this token to the Tcl parser to # check for balancing quotes append result $text set token $word } if { [catch {llength $token} length] == 0 && $length == 1} { # The token is a valid list so add it to the result. # lappend result [string trim $token] append result \{$token\} set token {} } } # If the last token has not been added to the list then there # is a problem. if { [string length $token] } { error "incomplete token \"$token\"" } return $result } # tcltest::test -- # # This procedure runs a test and prints an error message if the test # fails. If verbose has been set, it also prints a message even if the # test succeeds. The test will be skipped if it doesn't match the # match variable, if it matches an element in skip, or if one of the # elements of "constraints" turns out not to be true. # # If testLevel is 1, then this is a top level test, and we record # pass/fail information; otherwise, this information is not logged and # is not added to running totals. # # Attributes: # Only description is a required attribute. All others are optional. # Default values are indicated. # # constraints - A list of one or more keywords, each of which # must be the name of an element in the array # "testConstraints". If any of these elements is # zero, the test is skipped. This attribute is # optional; default is {} # body - Script to run to carry out the test. It must # return a result that can be checked for # correctness. This attribute is optional; # default is {} # result - Expected result from script. This attribute is # optional; default is {}. # output - Expected output sent to stdout. This attribute # is optional; default is {}. # errorOutput - Expected output sent to stderr. This attribute # is optional; default is {}. # returnCodes - Expected return codes. This attribute is # optional; default is {0 2}. # setup - Code to run before $script (above). This # attribute is optional; default is {}. # cleanup - Code to run after $script (above). This # attribute is optional; default is {}. # match - specifies type of matching to do on result, # output, errorOutput; this must be a string # previously registered by a call to [customMatch]. # The strings exact, glob, and regexp are pre-registered # by the tcltest package. Default value is exact. # # Arguments: # name - Name of test, in the form foo-1.2. # description - Short textual description of the test, to # help humans understand what it does. # # Results: # None. # # Side effects: # Just about anything is possible depending on the test. # proc tcltest::test {name description args} { global tcl_platform variable testLevel variable coreModTime DebugPuts 3 "test $name $args" DebugDo 1 { variable TestNames catch { puts "test name '$name' re-used; prior use in $TestNames($name)" } set TestNames($name) [info script] } FillFilesExisted incr testLevel # Pre-define everything to null except output and errorOutput. We # determine whether or not to trap output based on whether or not # these variables (output & errorOutput) are defined. foreach item {constraints setup cleanup body result returnCodes match} { set $item {} } # Set the default match mode set match exact # Set the default match values for return codes (0 is the standard # expected return value if everything went well; 2 represents # 'return' being used in the test script). set returnCodes [list 0 2] # The old test format can't have a 3rd argument (constraints or # script) that starts with '-'. if {[string match -* [lindex $args 0]] || ([llength $args] <= 1)} { if {[llength $args] == 1} { set list [SubstArguments [lindex $args 0]] foreach {element value} $list { set testAttributes($element) $value } foreach item {constraints match setup body cleanup \ result returnCodes output errorOutput} { if {[info exists testAttributes(-$item)]} { set testAttributes(-$item) [uplevel 1 \ ::concat $testAttributes(-$item)] } } } else { array set testAttributes $args } set validFlags {-setup -cleanup -body -result -returnCodes \ -match -output -errorOutput -constraints} foreach flag [array names testAttributes] { if {[lsearch -exact $validFlags $flag] == -1} { incr testLevel -1 set sorted [lsort $validFlags] set options [join [lrange $sorted 0 end-1] ", "] append options ", or [lindex $sorted end]" return -code error "bad option \"$flag\": must be $options" } } # store whatever the user gave us foreach item [array names testAttributes] { set [string trimleft $item "-"] $testAttributes($item) } # Check the values supplied for -match variable CustomMatch if {[lsearch [array names CustomMatch] $match] == -1} { incr testLevel -1 set sorted [lsort [array names CustomMatch]] set values [join [lrange $sorted 0 end-1] ", "] append values ", or [lindex $sorted end]" return -code error "bad -match value \"$match\":\ must be $values" } # Replace symbolic valies supplied for -returnCodes foreach {strcode numcode} {ok 0 normal 0 error 1 return 2 break 3 continue 4} { set returnCodes [string map -nocase [list $strcode $numcode] $returnCodes] } } else { # This is parsing for the old test command format; it is here # for backward compatibility. set result [lindex $args end] if {[llength $args] == 2} { set body [lindex $args 0] } elseif {[llength $args] == 3} { set constraints [lindex $args 0] set body [lindex $args 1] } else { incr testLevel -1 return -code error "wrong # args:\ should be \"test name desc ?options?\"" } } if {[Skipped $name $constraints]} { incr testLevel -1 return } # Save information about the core file. if {[preserveCore]} { if {[file exists [file join [workingDirectory] core]]} { set coreModTime [file mtime [file join [workingDirectory] core]] } } # First, run the setup script set code [catch {uplevel 1 $setup} setupMsg] if {$code == 1} { set errorInfo(setup) $::errorInfo set errorCode(setup) $::errorCode } set setupFailure [expr {$code != 0}] # Only run the test body if the setup was successful if {!$setupFailure} { # Verbose notification of $body start if {[IsVerbose start]} { puts [outputChannel] "---- $name start" flush [outputChannel] } set command [list [namespace origin RunTest] $name $body] if {[info exists output] || [info exists errorOutput]} { set testResult [uplevel 1 [list [namespace origin Eval] $command 0]] } else { set testResult [uplevel 1 [list [namespace origin Eval] $command 1]] } foreach {actualAnswer returnCode} $testResult break if {$returnCode == 1} { set errorInfo(body) $::errorInfo set errorCode(body) $::errorCode } } # Always run the cleanup script set code [catch {uplevel 1 $cleanup} cleanupMsg] if {$code == 1} { set errorInfo(cleanup) $::errorInfo set errorCode(cleanup) $::errorCode } set cleanupFailure [expr {$code != 0}] set coreFailure 0 set coreMsg "" # check for a core file first - if one was created by the test, # then the test failed if {[preserveCore]} { if {[file exists [file join [workingDirectory] core]]} { # There's only a test failure if there is a core file # and (1) there previously wasn't one or (2) the new # one is different from the old one. if {[info exists coreModTime]} { if {$coreModTime != [file mtime \ [file join [workingDirectory] core]]} { set coreFailure 1 } } else { set coreFailure 1 } if {([preserveCore] > 1) && ($coreFailure)} { append coreMsg "\nMoving file to:\ [file join [temporaryDirectory] core-$name]" catch {file rename -force \ [file join [workingDirectory] core] \ [file join [temporaryDirectory] core-$name] } msg if {[string length $msg] > 0} { append coreMsg "\nError:\ Problem renaming core file: $msg" } } } } # check if the return code matched the expected return code set codeFailure 0 if {!$setupFailure && [lsearch -exact $returnCodes $returnCode] == -1} { set codeFailure 1 } # If expected output/error strings exist, we have to compare # them. If the comparison fails, then so did the test. set outputFailure 0 variable outData if {[info exists output] && !$codeFailure} { if {[set outputCompare [catch { CompareStrings $outData $output $match } outputMatch]] == 0} { set outputFailure [expr {!$outputMatch}] } else { set outputFailure 1 } } set errorFailure 0 variable errData if {[info exists errorOutput] && !$codeFailure} { if {[set errorCompare [catch { CompareStrings $errData $errorOutput $match } errorMatch]] == 0} { set errorFailure [expr {!$errorMatch}] } else { set errorFailure 1 } } # check if the answer matched the expected answer # Only check if we ran the body of the test (no setup failure) if {$setupFailure || $codeFailure} { set scriptFailure 0 } elseif {[set scriptCompare [catch { CompareStrings $actualAnswer $result $match } scriptMatch]] == 0} { set scriptFailure [expr {!$scriptMatch}] } else { set scriptFailure 1 } # if we didn't experience any failures, then we passed variable numTests if {!($setupFailure || $cleanupFailure || $coreFailure || $outputFailure || $errorFailure || $codeFailure || $scriptFailure)} { if {$testLevel == 1} { incr numTests(Passed) if {[IsVerbose pass]} { puts [outputChannel] "++++ $name PASSED" } } incr testLevel -1 return } # We know the test failed, tally it... if {$testLevel == 1} { incr numTests(Failed) } # ... then report according to the type of failure variable currentFailure true if {![IsVerbose body]} { set body "" } puts [outputChannel] "\n==== $name\ [string trim $description] FAILED" if {[string length $body]} { puts [outputChannel] "==== Contents of test case:" puts [outputChannel] $body } if {$setupFailure} { puts [outputChannel] "---- Test setup\ failed:\n$setupMsg" if {[info exists errorInfo(setup)]} { puts [outputChannel] "---- errorInfo(setup): $errorInfo(setup)" puts [outputChannel] "---- errorCode(setup): $errorCode(setup)" } } if {$scriptFailure} { if {$scriptCompare} { puts [outputChannel] "---- Error testing result: $scriptMatch" } else { puts [outputChannel] "---- Result was:\n$actualAnswer" puts [outputChannel] "---- Result should have been\ ($match matching):\n$result" } } if {$codeFailure} { switch -- $returnCode { 0 { set msg "Test completed normally" } 1 { set msg "Test generated error" } 2 { set msg "Test generated return exception" } 3 { set msg "Test generated break exception" } 4 { set msg "Test generated continue exception" } default { set msg "Test generated exception" } } puts [outputChannel] "---- $msg; Return code was: $returnCode" puts [outputChannel] "---- Return code should have been\ one of: $returnCodes" if {[IsVerbose error]} { if {[info exists errorInfo(body)] && ([lsearch $returnCodes 1]<0)} { puts [outputChannel] "---- errorInfo: $errorInfo(body)" puts [outputChannel] "---- errorCode: $errorCode(body)" } } } if {$outputFailure} { if {$outputCompare} { puts [outputChannel] "---- Error testing output: $outputMatch" } else { puts [outputChannel] "---- Output was:\n$outData" puts [outputChannel] "---- Output should have been\ ($match matching):\n$output" } } if {$errorFailure} { if {$errorCompare} { puts [outputChannel] "---- Error testing errorOutput: $errorMatch" } else { puts [outputChannel] "---- Error output was:\n$errData" puts [outputChannel] "---- Error output should have\ been ($match matching):\n$errorOutput" } } if {$cleanupFailure} { puts [outputChannel] "---- Test cleanup failed:\n$cleanupMsg" if {[info exists errorInfo(cleanup)]} { puts [outputChannel] "---- errorInfo(cleanup): $errorInfo(cleanup)" puts [outputChannel] "---- errorCode(cleanup): $errorCode(cleanup)" } } if {$coreFailure} { puts [outputChannel] "---- Core file produced while running\ test! $coreMsg" } puts [outputChannel] "==== $name FAILED\n" incr testLevel -1 return } # Skipped -- # # Given a test name and it constraints, returns a boolean indicating # whether the current configuration says the test should be skipped. # # Side Effects: Maintains tally of total tests seen and tests skipped. # proc tcltest::Skipped {name constraints} { variable testLevel variable numTests variable testConstraints if {$testLevel == 1} { incr numTests(Total) } # skip the test if it's name matches an element of skip foreach pattern [skip] { if {[string match $pattern $name]} { if {$testLevel == 1} { incr numTests(Skipped) DebugDo 1 {AddToSkippedBecause userSpecifiedSkip} } return 1 } } # skip the test if it's name doesn't match any element of match set ok 0 foreach pattern [match] { if {[string match $pattern $name]} { set ok 1 break } } if {!$ok} { if {$testLevel == 1} { incr numTests(Skipped) DebugDo 1 {AddToSkippedBecause userSpecifiedNonMatch} } return 1 } if {[string equal {} $constraints]} { # If we're limited to the listed constraints and there aren't # any listed, then we shouldn't run the test. if {[limitConstraints]} { AddToSkippedBecause userSpecifiedLimitConstraint if {$testLevel == 1} { incr numTests(Skipped) } return 1 } } else { # "constraints" argument exists; # make sure that the constraints are satisfied. set doTest 0 if {[string match {*[$\[]*} $constraints] != 0} { # full expression, e.g. {$foo > [info tclversion]} catch {set doTest [uplevel #0 [list expr $constraints]]} } elseif {[regexp {[^.:_a-zA-Z0-9 \n\r\t]+} $constraints] != 0} { # something like {a || b} should be turned into # $testConstraints(a) || $testConstraints(b). regsub -all {[.\w]+} $constraints {$testConstraints(&)} c catch {set doTest [eval [list expr $c]]} } elseif {![catch {llength $constraints}]} { # just simple constraints such as {unixOnly fonts}. set doTest 1 foreach constraint $constraints { if {(![info exists testConstraints($constraint)]) \ || (!$testConstraints($constraint))} { set doTest 0 # store the constraint that kept the test from # running set constraints $constraint break } } } if {!$doTest} { if {[IsVerbose skip]} { puts [outputChannel] "++++ $name SKIPPED: $constraints" } if {$testLevel == 1} { incr numTests(Skipped) AddToSkippedBecause $constraints } return 1 } } return 0 } # RunTest -- # # This is where the body of a test is evaluated. The combination of # [RunTest] and [Eval] allows the output and error output of the test # body to be captured for comparison against the expected values. proc tcltest::RunTest {name script} { DebugPuts 3 "Running $name {$script}" # If there is no "memory" command (because memory debugging isn't # enabled), then don't attempt to use the command. if {[llength [info commands memory]] == 1} { memory tag $name } set code [catch {uplevel 1 $script} actualAnswer] return [list $actualAnswer $code] } ##################################################################### # tcltest::cleanupTestsHook -- # # This hook allows a harness that builds upon tcltest to specify # additional things that should be done at cleanup. # if {[llength [info commands tcltest::cleanupTestsHook]] == 0} { proc tcltest::cleanupTestsHook {} {} } # tcltest::cleanupTests -- # # Remove files and dirs created using the makeFile and makeDirectory # commands since the last time this proc was invoked. # # Print the names of the files created without the makeFile command # since the tests were invoked. # # Print the number tests (total, passed, failed, and skipped) since the # tests were invoked. # # Restore original environment (as reported by special variable env). # # Arguments: # calledFromAllFile - if 0, behave as if we are running a single # test file within an entire suite of tests. if we aren't running # a single test file, then don't report status. check for new # files created during the test run and report on them. if 1, # report collated status from all the test file runs. # # Results: # None. # # Side Effects: # None # proc tcltest::cleanupTests {{calledFromAllFile 0}} { variable filesMade variable filesExisted variable createdNewFiles variable testSingleFile variable numTests variable numTestFiles variable failFiles variable skippedBecause variable currentFailure variable originalEnv variable originalTclPlatform variable coreModTime FillFilesExisted set testFileName [file tail [info script]] # Call the cleanup hook cleanupTestsHook # Remove files and directories created by the makeFile and # makeDirectory procedures. Record the names of files in # workingDirectory that were not pre-existing, and associate them # with the test file that created them. if {!$calledFromAllFile} { foreach file $filesMade { if {[file exists $file]} { DebugDo 1 {Warn "cleanupTests deleting $file..."} catch {file delete -force $file} } } set currentFiles {} foreach file [glob -nocomplain \ -directory [temporaryDirectory] *] { lappend currentFiles [file tail $file] } set newFiles {} foreach file $currentFiles { if {[lsearch -exact $filesExisted $file] == -1} { lappend newFiles $file } } set filesExisted $currentFiles if {[llength $newFiles] > 0} { set createdNewFiles($testFileName) $newFiles } } if {$calledFromAllFile || $testSingleFile} { # print stats puts -nonewline [outputChannel] "$testFileName:" foreach index [list "Total" "Passed" "Skipped" "Failed"] { puts -nonewline [outputChannel] \ "\t$index\t$numTests($index)" } puts [outputChannel] "" # print number test files sourced # print names of files that ran tests which failed if {$calledFromAllFile} { puts [outputChannel] \ "Sourced $numTestFiles Test Files." set numTestFiles 0 if {[llength $failFiles] > 0} { puts [outputChannel] \ "Files with failing tests: $failFiles" set failFiles {} } } # if any tests were skipped, print the constraints that kept # them from running. set constraintList [array names skippedBecause] if {[llength $constraintList] > 0} { puts [outputChannel] \ "Number of tests skipped for each constraint:" foreach constraint [lsort $constraintList] { puts [outputChannel] \ "\t$skippedBecause($constraint)\t$constraint" unset skippedBecause($constraint) } } # report the names of test files in createdNewFiles, and reset # the array to be empty. set testFilesThatTurded [lsort [array names createdNewFiles]] if {[llength $testFilesThatTurded] > 0} { puts [outputChannel] "Warning: files left behind:" foreach testFile $testFilesThatTurded { puts [outputChannel] \ "\t$testFile:\t$createdNewFiles($testFile)" unset createdNewFiles($testFile) } } # reset filesMade, filesExisted, and numTests set filesMade {} foreach index [list "Total" "Passed" "Skipped" "Failed"] { set numTests($index) 0 } # exit only if running Tk in non-interactive mode # This should be changed to determine if an event # loop is running, which is the real issue. # Actually, this doesn't belong here at all. A package # really has no business [exit]-ing an application. if {![catch {package present Tk}] && ![testConstraint interactive]} { exit } } else { # if we're deferring stat-reporting until all files are sourced, # then add current file to failFile list if any tests in this # file failed if {$currentFailure \ && ([lsearch -exact $failFiles $testFileName] == -1)} { lappend failFiles $testFileName } set currentFailure false # restore the environment to the state it was in before this package # was loaded set newEnv {} set changedEnv {} set removedEnv {} foreach index [array names ::env] { if {![info exists originalEnv($index)]} { lappend newEnv $index unset ::env($index) } else { if {$::env($index) != $originalEnv($index)} { lappend changedEnv $index set ::env($index) $originalEnv($index) } } } foreach index [array names originalEnv] { if {![info exists ::env($index)]} { lappend removedEnv $index set ::env($index) $originalEnv($index) } } if {[llength $newEnv] > 0} { puts [outputChannel] \ "env array elements created:\t$newEnv" } if {[llength $changedEnv] > 0} { puts [outputChannel] \ "env array elements changed:\t$changedEnv" } if {[llength $removedEnv] > 0} { puts [outputChannel] \ "env array elements removed:\t$removedEnv" } set changedTclPlatform {} foreach index [array names originalTclPlatform] { if {$::tcl_platform($index) \ != $originalTclPlatform($index)} { lappend changedTclPlatform $index set ::tcl_platform($index) $originalTclPlatform($index) } } if {[llength $changedTclPlatform] > 0} { puts [outputChannel] "tcl_platform array elements\ changed:\t$changedTclPlatform" } if {[file exists [file join [workingDirectory] core]]} { if {[preserveCore] > 1} { puts "rename core file (> 1)" puts [outputChannel] "produced core file! \ Moving file to: \ [file join [temporaryDirectory] core-$testFileName]" catch {file rename -force \ [file join [workingDirectory] core] \ [file join [temporaryDirectory] core-$testFileName] } msg if {[string length $msg] > 0} { PrintError "Problem renaming file: $msg" } } else { # Print a message if there is a core file and (1) there # previously wasn't one or (2) the new one is different # from the old one. if {[info exists coreModTime]} { if {$coreModTime != [file mtime \ [file join [workingDirectory] core]]} { puts [outputChannel] "A core file was created!" } } else { puts [outputChannel] "A core file was created!" } } } } flush [outputChannel] flush [errorChannel] return } ##################################################################### # Procs that determine which tests/test files to run # tcltest::GetMatchingFiles # # Looks at the patterns given to match and skip files and uses # them to put together a list of the tests that will be run. # # Arguments: # directory to search # # Results: # The constructed list is returned to the user. This will # primarily be used in 'all.tcl' files. It is used in # runAllTests. # # Side Effects: # None # a lower case version is needed for compatibility with tcltest 1.0 proc tcltest::getMatchingFiles args {eval GetMatchingFiles $args} proc tcltest::GetMatchingFiles { args } { if {[llength $args]} { set dirList $args } else { # Finding tests only in [testsDirectory] is normal operation. # This procedure is written to accept multiple directory arguments # only to satisfy version 1 compatibility. set dirList [list [testsDirectory]] } set matchingFiles [list] foreach directory $dirList { # List files in $directory that match patterns to run. set matchFileList [list] foreach match [matchFiles] { set matchFileList [concat $matchFileList \ [glob -directory $directory -types {b c f p s} \ -nocomplain -- $match]] } # List files in $directory that match patterns to skip. set skipFileList [list] foreach skip [skipFiles] { set skipFileList [concat $skipFileList \ [glob -directory $directory -types {b c f p s} \ -nocomplain -- $skip]] } # Add to result list all files in match list and not in skip list foreach file $matchFileList { if {[lsearch -exact $skipFileList $file] == -1} { lappend matchingFiles $file } } } if {[llength $matchingFiles] == 0} { PrintError "No test files remain after applying your match and\ skip patterns!" } return $matchingFiles } # tcltest::GetMatchingDirectories -- # # Looks at the patterns given to match and skip directories and # uses them to put together a list of the test directories that we # should attempt to run. (Only subdirectories containing an # "all.tcl" file are put into the list.) # # Arguments: # root directory from which to search # # Results: # The constructed list is returned to the user. This is used in # the primary all.tcl file. # # Side Effects: # None. proc tcltest::GetMatchingDirectories {rootdir} { # Determine the skip list first, to avoid [glob]-ing over subdirectories # we're going to throw away anyway. Be sure we skip the $rootdir if it # comes up to avoid infinite loops. set skipDirs [list $rootdir] foreach pattern [skipDirectories] { set skipDirs [concat $skipDirs [glob -directory $rootdir -types d \ -nocomplain -- $pattern]] } # Now step through the matching directories, prune out the skipped ones # as you go. set matchDirs [list] foreach pattern [matchDirectories] { foreach path [glob -directory $rootdir -types d -nocomplain -- \ $pattern] { if {[lsearch -exact $skipDirs $path] == -1} { set matchDirs [concat $matchDirs [GetMatchingDirectories $path]] if {[file exists [file join $path all.tcl]]} { lappend matchDirs $path } } } } if {[llength $matchDirs] == 0} { DebugPuts 1 "No test directories remain after applying match\ and skip patterns!" } return $matchDirs } # tcltest::runAllTests -- # # prints output and sources test files according to the match and # skip patterns provided. after sourcing test files, it goes on # to source all.tcl files in matching test subdirectories. # # Arguments: # shell being tested # # Results: # None. # # Side effects: # None. proc tcltest::runAllTests { {shell ""} } { variable testSingleFile variable numTestFiles variable numTests variable failFiles variable DefaultValue FillFilesExisted if {[llength [info level 0]] == 1} { set shell [interpreter] } set testSingleFile false puts [outputChannel] "Tests running in interp: $shell" puts [outputChannel] "Tests located in: [testsDirectory]" puts [outputChannel] "Tests running in: [workingDirectory]" puts [outputChannel] "Temporary files stored in\ [temporaryDirectory]" # [file system] first available in Tcl 8.4 if {![catch {file system [testsDirectory]} result] && ![string equal native [lindex $result 0]]} { # If we aren't running in the native filesystem, then we must # run the tests in a single process (via 'source'), because # trying to run then via a pipe will fail since the files don't # really exist. singleProcess 1 } if {[singleProcess]} { puts [outputChannel] \ "Test files sourced into current interpreter" } else { puts [outputChannel] \ "Test files run in separate interpreters" } if {[llength [skip]] > 0} { puts [outputChannel] "Skipping tests that match: [skip]" } puts [outputChannel] "Running tests that match: [match]" if {[llength [skipFiles]] > 0} { puts [outputChannel] \ "Skipping test files that match: [skipFiles]" } if {[llength [matchFiles]] > 0} { puts [outputChannel] \ "Only running test files that match: [matchFiles]" } set timeCmd {clock format [clock seconds]} puts [outputChannel] "Tests began at [eval $timeCmd]" # Run each of the specified tests foreach file [lsort [GetMatchingFiles]] { set tail [file tail $file] puts [outputChannel] $tail flush [outputChannel] if {[singleProcess]} { incr numTestFiles uplevel 1 [list ::source $file] } else { # Pass along our configuration to the child processes. # EXCEPT for the -outfile, because the parent process # needs to read and process output of children. set childargv [list] foreach opt [Configure] { if {[string equal $opt -outfile]} {continue} set value [Configure $opt] # Don't bother passing default configuration options if {[string equal $value $DefaultValue($opt)]} { continue } lappend childargv $opt $value } set cmd [linsert $childargv 0 | $shell $file] if {[catch { incr numTestFiles set pipeFd [open $cmd "r"] while {[gets $pipeFd line] >= 0} { if {[regexp [join { {^([^:]+):\t} {Total\t([0-9]+)\t} {Passed\t([0-9]+)\t} {Skipped\t([0-9]+)\t} {Failed\t([0-9]+)} } ""] $line null testFile \ Total Passed Skipped Failed]} { foreach index {Total Passed Skipped Failed} { incr numTests($index) [set $index] } if {$Failed > 0} { lappend failFiles $testFile } } elseif {[regexp [join { {^Number of tests skipped } {for each constraint:} {|^\t(\d+)\t(.+)$} } ""] $line match skipped constraint]} { if {[string match \t* $match]} { AddToSkippedBecause $constraint $skipped } } else { puts [outputChannel] $line } } close $pipeFd } msg]} { puts [outputChannel] "Test file error: $msg" # append the name of the test to a list to be reported # later lappend testFileFailures $file } } } # cleanup puts [outputChannel] "\nTests ended at [eval $timeCmd]" cleanupTests 1 if {[info exists testFileFailures]} { puts [outputChannel] "\nTest files exiting with errors: \n" foreach file $testFileFailures { puts [outputChannel] " [file tail $file]\n" } } # Checking for subdirectories in which to run tests foreach directory [GetMatchingDirectories [testsDirectory]] { set dir [file tail $directory] puts [outputChannel] [string repeat ~ 44] puts [outputChannel] "$dir test began at [eval $timeCmd]\n" uplevel 1 [list ::source [file join $directory all.tcl]] set endTime [eval $timeCmd] puts [outputChannel] "\n$dir test ended at $endTime" puts [outputChannel] "" puts [outputChannel] [string repeat ~ 44] } return } ##################################################################### # Test utility procs - not used in tcltest, but may be useful for # testing. # tcltest::loadTestedCommands -- # # Uses the specified script to load the commands to test. Allowed to # be empty, as the tested commands could have been compiled into the # interpreter. # # Arguments # none # # Results # none # # Side Effects: # none. proc tcltest::loadTestedCommands {} { variable l if {[string equal {} [loadScript]]} { return } return [uplevel 1 [loadScript]] } # tcltest::saveState -- # # Save information regarding what procs and variables exist. # # Arguments: # none # # Results: # Modifies the variable saveState # # Side effects: # None. proc tcltest::saveState {} { variable saveState uplevel 1 [list ::set [namespace which -variable saveState]] \ {[::list [::info procs] [::info vars]]} DebugPuts 2 "[lindex [info level 0] 0]: $saveState" return } # tcltest::restoreState -- # # Remove procs and variables that didn't exist before the call to # [saveState]. # # Arguments: # none # # Results: # Removes procs and variables from your environment if they don't # exist in the saveState variable. # # Side effects: # None. proc tcltest::restoreState {} { variable saveState foreach p [uplevel 1 {::info procs}] { if {([lsearch [lindex $saveState 0] $p] < 0) && ![string equal [namespace current]::$p \ [uplevel 1 [list ::namespace origin $p]]]} { DebugPuts 2 "[lindex [info level 0] 0]: Removing proc $p" uplevel 1 [list ::catch [list ::rename $p {}]] } } foreach p [uplevel 1 {::info vars}] { if {[lsearch [lindex $saveState 1] $p] < 0} { DebugPuts 2 "[lindex [info level 0] 0]:\ Removing variable $p" uplevel 1 [list ::catch [list ::unset $p]] } } return } # tcltest::normalizeMsg -- # # Removes "extra" newlines from a string. # # Arguments: # msg String to be modified # # Results: # string with extra newlines removed # # Side effects: # None. proc tcltest::normalizeMsg {msg} { regsub "\n$" [string tolower $msg] "" msg set msg [string map [list "\n\n" "\n"] $msg] return [string map [list "\n\}" "\}"] $msg] } # tcltest::makeFile -- # # Create a new file with the name , and write to it. # # If this file hasn't been created via makeFile since the last time # cleanupTests was called, add it to the $filesMade list, so it will be # removed by the next call to cleanupTests. # # Arguments: # contents content of the new file # name name of the new file # directory directory name for new file # # Results: # absolute path to the file created # # Side effects: # None. proc tcltest::makeFile {contents name {directory ""}} { variable filesMade FillFilesExisted if {[llength [info level 0]] == 3} { set directory [temporaryDirectory] } set fullName [file join $directory $name] DebugPuts 3 "[lindex [info level 0] 0]:\ putting ``$contents'' into $fullName" set fd [open $fullName w] fconfigure $fd -translation lf if {[string equal [string index $contents end] \n]} { puts -nonewline $fd $contents } else { puts $fd $contents } close $fd if {[lsearch -exact $filesMade $fullName] == -1} { lappend filesMade $fullName } return $fullName } # tcltest::removeFile -- # # Removes the named file from the filesystem # # Arguments: # name file to be removed # directory directory from which to remove file # # Results: # return value from [file delete] # # Side effects: # None. proc tcltest::removeFile {name {directory ""}} { variable filesMade FillFilesExisted if {[llength [info level 0]] == 2} { set directory [temporaryDirectory] } set fullName [file join $directory $name] DebugPuts 3 "[lindex [info level 0] 0]: removing $fullName" set idx [lsearch -exact $filesMade $fullName] set filesMade [lreplace $filesMade $idx $idx] if {$idx == -1} { DebugDo 1 { Warn "removeFile removing \"$fullName\":\n not created by makeFile" } } if {![file isfile $fullName]} { DebugDo 1 { Warn "removeFile removing \"$fullName\":\n not a file" } } return [file delete $fullName] } # tcltest::makeDirectory -- # # Create a new dir with the name . # # If this dir hasn't been created via makeDirectory since the last time # cleanupTests was called, add it to the $directoriesMade list, so it # will be removed by the next call to cleanupTests. # # Arguments: # name name of the new directory # directory directory in which to create new dir # # Results: # absolute path to the directory created # # Side effects: # None. proc tcltest::makeDirectory {name {directory ""}} { variable filesMade FillFilesExisted if {[llength [info level 0]] == 2} { set directory [temporaryDirectory] } set fullName [file join $directory $name] DebugPuts 3 "[lindex [info level 0] 0]: creating $fullName" file mkdir $fullName if {[lsearch -exact $filesMade $fullName] == -1} { lappend filesMade $fullName } return $fullName } # tcltest::removeDirectory -- # # Removes a named directory from the file system. # # Arguments: # name Name of the directory to remove # directory Directory from which to remove # # Results: # return value from [file delete] # # Side effects: # None proc tcltest::removeDirectory {name {directory ""}} { variable filesMade FillFilesExisted if {[llength [info level 0]] == 2} { set directory [temporaryDirectory] } set fullName [file join $directory $name] DebugPuts 3 "[lindex [info level 0] 0]: deleting $fullName" set idx [lsearch -exact $filesMade $fullName] set filesMade [lreplace $filesMade $idx $idx] if {$idx == -1} { DebugDo 1 { Warn "removeDirectory removing \"$fullName\":\n not created\ by makeDirectory" } } if {![file isdirectory $fullName]} { DebugDo 1 { Warn "removeDirectory removing \"$fullName\":\n not a directory" } } return [file delete -force $fullName] } # tcltest::viewFile -- # # reads the content of a file and returns it # # Arguments: # name of the file to read # directory in which file is located # # Results: # content of the named file # # Side effects: # None. proc tcltest::viewFile {name {directory ""}} { FillFilesExisted if {[llength [info level 0]] == 2} { set directory [temporaryDirectory] } set fullName [file join $directory $name] set f [open $fullName] set data [read -nonewline $f] close $f return $data } # tcltest::bytestring -- # # Construct a string that consists of the requested sequence of bytes, # as opposed to a string of properly formed UTF-8 characters. # This allows the tester to # 1. Create denormalized or improperly formed strings to pass to C # procedures that are supposed to accept strings with embedded NULL # bytes. # 2. Confirm that a string result has a certain pattern of bytes, for # instance to confirm that "\xe0\0" in a Tcl script is stored # internally in UTF-8 as the sequence of bytes "\xc3\xa0\xc0\x80". # # Generally, it's a bad idea to examine the bytes in a Tcl string or to # construct improperly formed strings in this manner, because it involves # exposing that Tcl uses UTF-8 internally. # # Arguments: # string being converted # # Results: # result fom encoding # # Side effects: # None proc tcltest::bytestring {string} { return [encoding convertfrom identity $string] } # tcltest::OpenFiles -- # # used in io tests, uses testchannel # # Arguments: # None. # # Results: # ??? # # Side effects: # None. proc tcltest::OpenFiles {} { if {[catch {testchannel open} result]} { return {} } return $result } # tcltest::LeakFiles -- # # used in io tests, uses testchannel # # Arguments: # None. # # Results: # ??? # # Side effects: # None. proc tcltest::LeakFiles {old} { if {[catch {testchannel open} new]} { return {} } set leak {} foreach p $new { if {[lsearch $old $p] < 0} { lappend leak $p } } return $leak } # # Internationalization / ISO support procs -- dl # # tcltest::SetIso8859_1_Locale -- # # used in cmdIL.test, uses testlocale # # Arguments: # None. # # Results: # None. # # Side effects: # None. proc tcltest::SetIso8859_1_Locale {} { variable previousLocale variable isoLocale if {[info commands testlocale] != ""} { set previousLocale [testlocale ctype] testlocale ctype $isoLocale } return } # tcltest::RestoreLocale -- # # used in cmdIL.test, uses testlocale # # Arguments: # None. # # Results: # None. # # Side effects: # None. proc tcltest::RestoreLocale {} { variable previousLocale if {[info commands testlocale] != ""} { testlocale ctype $previousLocale } return } # tcltest::threadReap -- # # Kill all threads except for the main thread. # Do nothing if testthread is not defined. # # Arguments: # none. # # Results: # Returns the number of existing threads. # # Side Effects: # none. # proc tcltest::threadReap {} { if {[info commands testthread] != {}} { # testthread built into tcltest testthread errorproc ThreadNullError while {[llength [testthread names]] > 1} { foreach tid [testthread names] { if {$tid != [mainThread]} { catch { testthread send -async $tid {testthread exit} } } } ## Enter a bit a sleep to give the threads enough breathing ## room to kill themselves off, otherwise the end up with a ## massive queue of repeated events after 1 } testthread errorproc ThreadError return [llength [testthread names]] } elseif {[info commands thread::id] != {}} { # Thread extension thread::errorproc ThreadNullError while {[llength [thread::names]] > 1} { foreach tid [thread::names] { if {$tid != [mainThread]} { catch {thread::send -async $tid {thread::exit}} } } ## Enter a bit a sleep to give the threads enough breathing ## room to kill themselves off, otherwise the end up with a ## massive queue of repeated events after 1 } thread::errorproc ThreadError return [llength [thread::names]] } else { return 1 } return 0 } # Initialize the constraints and set up command line arguments namespace eval tcltest { # Define initializers for all the built-in contraint definitions DefineConstraintInitializers # Set up the constraints in the testConstraints array to be lazily # initialized by a registered initializer, or by "false" if no # initializer is registered. trace variable testConstraints r [namespace code SafeFetch] # Only initialize constraints at package load time if an # [initConstraintsHook] has been pre-defined. This is only # for compatibility support. The modern way to add a custom # test constraint is to just call the [testConstraint] command # straight away, without all this "hook" nonsense. if {[string equal [namespace current] \ [namespace qualifiers [namespace which initConstraintsHook]]]} { InitConstraints } else { proc initConstraintsHook {} {} } # Define the standard match commands customMatch exact [list string equal] customMatch glob [list string match] customMatch regexp [list regexp --] # If the TCLTEST_OPTIONS environment variable exists, configure # tcltest according to the option values it specifies. This has # the effect of resetting tcltest's default configuration. proc ConfigureFromEnvironment {} { upvar #0 env(TCLTEST_OPTIONS) options if {[catch {llength $options} msg]} { Warn "invalid TCLTEST_OPTIONS \"$options\":\n invalid\ Tcl list: $msg" return } if {[llength $options] % 2} { Warn "invalid TCLTEST_OPTIONS: \"$options\":\n should be\ -option value ?-option value ...?" return } if {[catch {eval [linsert $options 0 Configure]} msg]} { Warn "invalid TCLTEST_OPTIONS: \"$options\":\n $msg" return } } if {[info exists ::env(TCLTEST_OPTIONS)]} { ConfigureFromEnvironment } proc LoadTimeCmdLineArgParsingRequired {} { set required false if {[info exists ::argv] && [lsearch -exact $::argv -help] != -1} { # The command line asks for -help, so give it (and exit) # right now. ([configure] does not process -help) set required true } foreach hook { PrintUsageInfoHook processCmdLineArgsHook processCmdLineArgsAddFlagsHook } { if {[string equal [namespace current] [namespace qualifiers \ [namespace which $hook]]]} { set required true } else { proc $hook args {} } } return $required } # Only initialize configurable options from the command line arguments # at package load time if necessary for backward compatibility. This # lets the tcltest user call [configure] for themselves if they wish. # Traces are established for auto-configuration from the command line # if any configurable options are accessed before the user calls # [configure]. if {[LoadTimeCmdLineArgParsingRequired]} { ProcessCmdLineArgs } else { EstablishAutoConfigureTraces } package provide [namespace tail [namespace current]] $Version } tcl8.4.20/library/package.tcl0000644003604700454610000006173012052456744014470 0ustar dgp771div# package.tcl -- # # utility procs formerly in init.tcl which can be loaded on demand # for package management. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994-1998 Sun Microsystems, Inc. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # Create the package namespace namespace eval ::pkg { } # pkg_compareExtension -- # # Used internally by pkg_mkIndex to compare the extension of a file to # a given extension. On Windows, it uses a case-insensitive comparison # because the file system can be file insensitive. # # Arguments: # fileName name of a file whose extension is compared # ext (optional) The extension to compare against; you must # provide the starting dot. # Defaults to [info sharedlibextension] # # Results: # Returns 1 if the extension matches, 0 otherwise proc pkg_compareExtension { fileName {ext {}} } { global tcl_platform if {$ext eq ""} {set ext [info sharedlibextension]} if {$tcl_platform(platform) eq "windows"} { return [string equal -nocase [file extension $fileName] $ext] } else { # Some unices add trailing numbers after the .so, so # we could have something like '.so.1.2'. set root $fileName while {1} { set currExt [file extension $root] if {$currExt eq $ext} { return 1 } # The current extension does not match; if it is not a numeric # value, quit, as we are only looking to ignore version number # extensions. Otherwise we might return 1 in this case: # pkg_compareExtension foo.so.bar .so # which should not match. if { ![string is integer -strict [string range $currExt 1 end]] } { return 0 } set root [file rootname $root] } } } # pkg_mkIndex -- # This procedure creates a package index in a given directory. The # package index consists of a "pkgIndex.tcl" file whose contents are # a Tcl script that sets up package information with "package require" # commands. The commands describe all of the packages defined by the # files given as arguments. # # Arguments: # -direct (optional) If this flag is present, the generated # code in pkgMkIndex.tcl will cause the package to be # loaded when "package require" is executed, rather # than lazily when the first reference to an exported # procedure in the package is made. # -verbose (optional) Verbose output; the name of each file that # was successfully rocessed is printed out. Additionally, # if processing of a file failed a message is printed. # -load pat (optional) Preload any packages whose names match # the pattern. Used to handle DLLs that depend on # other packages during their Init procedure. # dir - Name of the directory in which to create the index. # args - Any number of additional arguments, each giving # a glob pattern that matches the names of one or # more shared libraries or Tcl script files in # dir. proc pkg_mkIndex {args} { global errorCode errorInfo set usage {"pkg_mkIndex ?-direct? ?-lazy? ?-load pattern? ?-verbose? ?--? dir ?pattern ...?"}; set argCount [llength $args] if {$argCount < 1} { return -code error "wrong # args: should be\n$usage" } set more "" set direct 1 set doVerbose 0 set loadPat "" for {set idx 0} {$idx < $argCount} {incr idx} { set flag [lindex $args $idx] switch -glob -- $flag { -- { # done with the flags incr idx break } -verbose { set doVerbose 1 } -lazy { set direct 0 append more " -lazy" } -direct { append more " -direct" } -load { incr idx set loadPat [lindex $args $idx] append more " -load $loadPat" } -* { return -code error "unknown flag $flag: should be\n$usage" } default { # done with the flags break } } } set dir [lindex $args $idx] set patternList [lrange $args [expr {$idx + 1}] end] if {[llength $patternList] == 0} { set patternList [list "*.tcl" "*[info sharedlibextension]"] } set oldDir [pwd] cd $dir if {[catch {eval [linsert $patternList 0 glob --]} fileList]} { global errorCode errorInfo cd $oldDir return -code error -errorcode $errorCode -errorinfo $errorInfo $fileList } foreach file $fileList { # For each file, figure out what commands and packages it provides. # To do this, create a child interpreter, load the file into the # interpreter, and get a list of the new commands and packages # that are defined. if {$file eq "pkgIndex.tcl"} { continue } # Changed back to the original directory before initializing the # slave in case TCL_LIBRARY is a relative path (e.g. in the test # suite). cd $oldDir set c [interp create] # Load into the child any packages currently loaded in the parent # interpreter that match the -load pattern. if {$loadPat ne ""} { if {$doVerbose} { tclLog "currently loaded packages: '[info loaded]'" tclLog "trying to load all packages matching $loadPat" } if {![llength [info loaded]]} { tclLog "warning: no packages are currently loaded, nothing" tclLog "can possibly match '$loadPat'" } } foreach pkg [info loaded] { if {! [string match -nocase $loadPat [lindex $pkg 1]]} { continue } if {$doVerbose} { tclLog "package [lindex $pkg 1] matches '$loadPat'" } if {[catch { load [lindex $pkg 0] [lindex $pkg 1] $c } err]} { if {$doVerbose} { tclLog "warning: load [lindex $pkg 0] [lindex $pkg 1]\nfailed with: $err" } } elseif {$doVerbose} { tclLog "loaded [lindex $pkg 0] [lindex $pkg 1]" } if {[lindex $pkg 1] eq "Tk"} { # Withdraw . if Tk was loaded, to avoid showing a window. $c eval [list wm withdraw .] } } cd $dir $c eval { # Stub out the package command so packages can # require other packages. rename package __package_orig proc package {what args} { switch -- $what { require { return ; # ignore transitive requires } default { uplevel 1 [linsert $args 0 __package_orig $what] } } } proc tclPkgUnknown args {} package unknown tclPkgUnknown # Stub out the unknown command so package can call # into each other during their initialilzation. proc unknown {args} {} # Stub out the auto_import mechanism proc auto_import {args} {} # reserve the ::tcl namespace for support procs # and temporary variables. This might make it awkward # to generate a pkgIndex.tcl file for the ::tcl namespace. namespace eval ::tcl { variable file ;# Current file being processed variable direct ;# -direct flag value variable x ;# Loop variable variable debug ;# For debugging variable type ;# "load" or "source", for -direct variable namespaces ;# Existing namespaces (e.g., ::tcl) variable packages ;# Existing packages (e.g., Tcl) variable origCmds ;# Existing commands variable newCmds ;# Newly created commands variable newPkgs {} ;# Newly created packages } } $c eval [list set ::tcl::file $file] $c eval [list set ::tcl::direct $direct] # Download needed procedures into the slave because we've # just deleted the unknown procedure. This doesn't handle # procedures with default arguments. foreach p {pkg_compareExtension} { $c eval [list proc $p [info args $p] [info body $p]] } if {[catch { $c eval { set ::tcl::debug "loading or sourcing" # we need to track command defined by each package even in # the -direct case, because they are needed internally by # the "partial pkgIndex.tcl" step above. proc ::tcl::GetAllNamespaces {{root ::}} { set list $root foreach ns [namespace children $root] { eval [linsert [::tcl::GetAllNamespaces $ns] 0 \ lappend list] } return $list } # init the list of existing namespaces, packages, commands foreach ::tcl::x [::tcl::GetAllNamespaces] { set ::tcl::namespaces($::tcl::x) 1 } foreach ::tcl::x [package names] { if {[package provide $::tcl::x] ne ""} { set ::tcl::packages($::tcl::x) 1 } } set ::tcl::origCmds [info commands] # Try to load the file if it has the shared library # extension, otherwise source it. It's important not to # try to load files that aren't shared libraries, because # on some systems (like SunOS) the loader will abort the # whole application when it gets an error. if {[pkg_compareExtension $::tcl::file [info sharedlibextension]]} { # The "file join ." command below is necessary. # Without it, if the file name has no \'s and we're # on UNIX, the load command will invoke the # LD_LIBRARY_PATH search mechanism, which could cause # the wrong file to be used. set ::tcl::debug loading load [file join . $::tcl::file] set ::tcl::type load } else { set ::tcl::debug sourcing source $::tcl::file set ::tcl::type source } # As a performance optimization, if we are creating # direct load packages, don't bother figuring out the # set of commands created by the new packages. We # only need that list for setting up the autoloading # used in the non-direct case. if { !$::tcl::direct } { # See what new namespaces appeared, and import commands # from them. Only exported commands go into the index. foreach ::tcl::x [::tcl::GetAllNamespaces] { if {! [info exists ::tcl::namespaces($::tcl::x)]} { namespace import -force ${::tcl::x}::* } # Figure out what commands appeared foreach ::tcl::x [info commands] { set ::tcl::newCmds($::tcl::x) 1 } foreach ::tcl::x $::tcl::origCmds { unset -nocomplain ::tcl::newCmds($::tcl::x) } foreach ::tcl::x [array names ::tcl::newCmds] { # determine which namespace a command comes from set ::tcl::abs [namespace origin $::tcl::x] # special case so that global names have no leading # ::, this is required by the unknown command set ::tcl::abs \ [lindex [auto_qualify $::tcl::abs ::] 0] if {$::tcl::x ne $::tcl::abs} { # Name changed during qualification set ::tcl::newCmds($::tcl::abs) 1 unset ::tcl::newCmds($::tcl::x) } } } } # Look through the packages that appeared, and if there is # a version provided, then record it foreach ::tcl::x [package names] { if {[package provide $::tcl::x] ne "" && ![info exists ::tcl::packages($::tcl::x)]} { lappend ::tcl::newPkgs \ [list $::tcl::x [package provide $::tcl::x]] } } } } msg] == 1} { set what [$c eval set ::tcl::debug] if {$doVerbose} { tclLog "warning: error while $what $file: $msg" } } else { set what [$c eval set ::tcl::debug] if {$doVerbose} { tclLog "successful $what of $file" } set type [$c eval set ::tcl::type] set cmds [lsort [$c eval array names ::tcl::newCmds]] set pkgs [$c eval set ::tcl::newPkgs] if {$doVerbose} { if { !$direct } { tclLog "commands provided were $cmds" } tclLog "packages provided were $pkgs" } if {[llength $pkgs] > 1} { tclLog "warning: \"$file\" provides more than one package ($pkgs)" } foreach pkg $pkgs { # cmds is empty/not used in the direct case lappend files($pkg) [list $file $type $cmds] } if {$doVerbose} { tclLog "processed $file" } } interp delete $c } append index "# Tcl package index file, version 1.1\n" append index "# This file is generated by the \"pkg_mkIndex$more\" command\n" append index "# and sourced either when an application starts up or\n" append index "# by a \"package unknown\" script. It invokes the\n" append index "# \"package ifneeded\" command to set up package-related\n" append index "# information so that packages will be loaded automatically\n" append index "# in response to \"package require\" commands. When this\n" append index "# script is sourced, the variable \$dir must contain the\n" append index "# full path name of this file's directory.\n" foreach pkg [lsort [array names files]] { set cmd {} foreach {name version} $pkg { break } lappend cmd ::pkg::create -name $name -version $version foreach spec $files($pkg) { foreach {file type procs} $spec { if { $direct } { set procs {} } lappend cmd "-$type" [list $file $procs] } } append index "\n[eval $cmd]" } set f [open pkgIndex.tcl w] puts $f $index close $f cd $oldDir } # tclPkgSetup -- # This is a utility procedure use by pkgIndex.tcl files. It is invoked # as part of a "package ifneeded" script. It calls "package provide" # to indicate that a package is available, then sets entries in the # auto_index array so that the package's files will be auto-loaded when # the commands are used. # # Arguments: # dir - Directory containing all the files for this package. # pkg - Name of the package (no version number). # version - Version number for the package, such as 2.1.3. # files - List of files that constitute the package. Each # element is a sub-list with three elements. The first # is the name of a file relative to $dir, the second is # "load" or "source", indicating whether the file is a # loadable binary or a script to source, and the third # is a list of commands defined by this file. proc tclPkgSetup {dir pkg version files} { global auto_index package provide $pkg $version foreach fileInfo $files { set f [lindex $fileInfo 0] set type [lindex $fileInfo 1] foreach cmd [lindex $fileInfo 2] { if {$type eq "load"} { set auto_index($cmd) [list load [file join $dir $f] $pkg] } else { set auto_index($cmd) [list source [file join $dir $f]] } } } } # tclPkgUnknown -- # This procedure provides the default for the "package unknown" function. # It is invoked when a package that's needed can't be found. It scans # the auto_path directories and their immediate children looking for # pkgIndex.tcl files and sources any such files that are found to setup # the package database. As it searches, it will recognize changes # to the auto_path and scan any new directories. # # Arguments: # name - Name of desired package. Not used. # version - Version of desired package. Not used. # exact - Either "-exact" or omitted. Not used. proc tclPkgUnknown [expr { [info exists tcl_platform(tip,268)] ? "name args" : "name version {exact {}}" }] { global auto_path env if {![info exists auto_path]} { return } # Cache the auto_path, because it may change while we run through # the first set of pkgIndex.tcl files set old_path [set use_path $auto_path] while {[llength $use_path]} { set dir [lindex $use_path end] # Make sure we only scan each directory one time. if {[info exists tclSeenPath($dir)]} { set use_path [lrange $use_path 0 end-1] continue } set tclSeenPath($dir) 1 # we can't use glob in safe interps, so enclose the following # in a catch statement, where we get the pkgIndex files out # of the subdirectories catch { foreach file [glob -directory $dir -join -nocomplain \ * pkgIndex.tcl] { set dir [file dirname $file] if {![info exists procdDirs($dir)]} { set code [catch {source $file} msg] if {$code == 1 && [lindex $::errorCode 0] eq "POSIX" && [lindex $::errorCode 1] eq "EACCES"} { # $file was not readable; silently ignore continue } if {$code} { tclLog "error reading package index file $file: $msg" } else { set procdDirs($dir) 1 } } } } set dir [lindex $use_path end] if {![info exists procdDirs($dir)]} { set file [file join $dir pkgIndex.tcl] # safe interps usually don't have "file exists", if {([interp issafe] || [file exists $file])} { set code [catch {source $file} msg] if {$code == 1 && [lindex $::errorCode 0] eq "POSIX" && [lindex $::errorCode 1] eq "EACCES"} { # $file was not readable; silently ignore continue } if {$code} { tclLog "error reading package index file $file: $msg" } else { set procdDirs($dir) 1 } } } set use_path [lrange $use_path 0 end-1] # Check whether any of the index scripts we [source]d above # set a new value for $::auto_path. If so, then find any # new directories on the $::auto_path, and lappend them to # the $use_path we are working from. This gives index scripts # the (arguably unwise) power to expand the index script search # path while the search is in progress. set index 0 if {[llength $old_path] == [llength $auto_path]} { foreach dir $auto_path old $old_path { if {$dir ne $old} { # This entry in $::auto_path has changed. break } incr index } } # $index now points to the first element of $auto_path that # has changed, or the beginning if $auto_path has changed length # Scan the new elements of $auto_path for directories to add to # $use_path. Don't add directories we've already seen, or ones # already on the $use_path. foreach dir [lrange $auto_path $index end] { if {![info exists tclSeenPath($dir)] && ([lsearch -exact $use_path $dir] == -1) } { lappend use_path $dir } } set old_path $auto_path } } # tcl::MacOSXPkgUnknown -- # This procedure extends the "package unknown" function for MacOSX. # It scans the Resources/Scripts directories of the immediate children # of the auto_path directories for pkgIndex files. # # Arguments: # original - original [package unknown] procedure # name - Name of desired package. Not used. #ifndef TCL_TIP268 # version - Version of desired package. Not used. # exact - Either "-exact" or omitted. Not used. #else # args - List of requirements. Not used. #endif if {[info exists tcl_platform(tip,268)]} { proc tcl::MacOSXPkgUnknown {original name args} { # First do the cross-platform default search uplevel 1 $original [linsert $args 0 $name] # Now do MacOSX specific searching global auto_path if {![info exists auto_path]} { return } # Cache the auto_path, because it may change while we run through # the first set of pkgIndex.tcl files set old_path [set use_path $auto_path] while {[llength $use_path]} { set dir [lindex $use_path end] # get the pkgIndex files out of the subdirectories foreach file [glob -directory $dir -join -nocomplain \ * Resources Scripts pkgIndex.tcl] { set dir [file dirname $file] if {![info exists procdDirs($dir)]} { set code [catch {source $file} msg] if {$code == 1 && [lindex $::errorCode 0] eq "POSIX" && [lindex $::errorCode 1] eq "EACCES"} { # $file was not readable; silently ignore continue } if {$code} { tclLog "error reading package index file $file: $msg" } else { set procdDirs($dir) 1 } } } set use_path [lrange $use_path 0 end-1] if {$old_path ne $auto_path} { foreach dir $auto_path { lappend use_path $dir } set old_path $auto_path } } } } else { proc tcl::MacOSXPkgUnknown {original name version {exact {}}} { # First do the cross-platform default search uplevel 1 $original [list $name $version $exact] # Now do MacOSX specific searching global auto_path if {![info exists auto_path]} { return } # Cache the auto_path, because it may change while we run through # the first set of pkgIndex.tcl files set old_path [set use_path $auto_path] while {[llength $use_path]} { set dir [lindex $use_path end] # get the pkgIndex files out of the subdirectories foreach file [glob -directory $dir -join -nocomplain \ * Resources Scripts pkgIndex.tcl] { set dir [file dirname $file] if {![info exists procdDirs($dir)]} { set code [catch {source $file} msg] if {$code == 1 && [lindex $::errorCode 0] eq "POSIX" && [lindex $::errorCode 1] eq "EACCES"} { # $file was not readable; silently ignore continue } if {$code} { tclLog "error reading package index file $file: $msg" } else { set procdDirs($dir) 1 } } } set use_path [lrange $use_path 0 end-1] if {$old_path ne $auto_path} { foreach dir $auto_path { lappend use_path $dir } set old_path $auto_path } } } } # tcl::MacPkgUnknown -- # This procedure extends the "package unknown" function for Mac. # It searches for pkgIndex TEXT resources in all files # Only installed in interps that are not safe so we don't check # for [interp issafe] as in tclPkgUnknown. # # Arguments: # original - original [package unknown] procedure # name - Name of desired package. Not used. # version - Version of desired package. Not used. # exact - Either "-exact" or omitted. Not used. proc tcl::MacPkgUnknown {original name version {exact {}}} { # First do the cross-platform default search uplevel 1 $original [list $name $version $exact] # Now do Mac specific searching global auto_path if {![info exists auto_path]} { return } # Cache the auto_path, because it may change while we run through # the first set of pkgIndex.tcl files set old_path [set use_path $auto_path] while {[llength $use_path]} { # We look for pkgIndex TEXT resources in the resource fork of shared libraries set dir [lindex $use_path end] foreach x [concat [list $dir] [glob -directory $dir -nocomplain *] ] { if {[file isdirectory $x] && ![info exists procdDirs($x)]} { set dir $x foreach x [glob -directory $dir -nocomplain *.shlb] { if {[file isfile $x]} { set res [resource open $x] foreach y [resource list TEXT $res] { if {$y eq "pkgIndex"} {source -rsrc pkgIndex} } catch {resource close $res} } } set procdDirs($dir) 1 } } set use_path [lrange $use_path 0 end-1] if {$old_path ne $auto_path} { foreach dir $auto_path { lappend use_path $dir } set old_path $auto_path } } } # ::pkg::create -- # # Given a package specification generate a "package ifneeded" statement # for the package, suitable for inclusion in a pkgIndex.tcl file. # # Arguments: # args arguments used by the create function: # -name packageName # -version packageVersion # -load {filename ?{procs}?} # ... # -source {filename ?{procs}?} # ... # # Any number of -load and -source parameters may be # specified, so long as there is at least one -load or # -source parameter. If the procs component of a # module specifier is left off, that module will be # set up for direct loading; otherwise, it will be # set up for lazy loading. If both -source and -load # are specified, the -load'ed files will be loaded # first, followed by the -source'd files. # # Results: # An appropriate "package ifneeded" statement for the package. proc ::pkg::create {args} { append err(usage) "[lindex [info level 0] 0] " append err(usage) "-name packageName -version packageVersion" append err(usage) "?-load {filename ?{procs}?}? ... " append err(usage) "?-source {filename ?{procs}?}? ..." set err(wrongNumArgs) "wrong # args: should be \"$err(usage)\"" set err(valueMissing) "value for \"%s\" missing: should be \"$err(usage)\"" set err(unknownOpt) "unknown option \"%s\": should be \"$err(usage)\"" set err(noLoadOrSource) "at least one of -load and -source must be given" # process arguments set len [llength $args] if { $len < 6 } { error $err(wrongNumArgs) } # Initialize parameters set opts(-name) {} set opts(-version) {} set opts(-source) {} set opts(-load) {} # process parameters for {set i 0} {$i < $len} {incr i} { set flag [lindex $args $i] incr i switch -glob -- $flag { "-name" - "-version" { if { $i >= $len } { error [format $err(valueMissing) $flag] } set opts($flag) [lindex $args $i] } "-source" - "-load" { if { $i >= $len } { error [format $err(valueMissing) $flag] } lappend opts($flag) [lindex $args $i] } default { error [format $err(unknownOpt) [lindex $args $i]] } } } # Validate the parameters if { [llength $opts(-name)] == 0 } { error [format $err(valueMissing) "-name"] } if { [llength $opts(-version)] == 0 } { error [format $err(valueMissing) "-version"] } if { [llength $opts(-source)] == 0 && [llength $opts(-load)] == 0 } { error $err(noLoadOrSource) } # OK, now everything is good. Generate the package ifneeded statment. set cmdline "package ifneeded $opts(-name) $opts(-version) " set cmdList {} set lazyFileList {} # Handle -load and -source specs foreach key {load source} { foreach filespec $opts(-$key) { foreach {filename proclist} {{} {}} { break } foreach {filename proclist} $filespec { break } if { [llength $proclist] == 0 } { set cmd "\[list $key \[file join \$dir [list $filename]\]\]" lappend cmdList $cmd } else { lappend lazyFileList [list $filename $key $proclist] } } } if { [llength $lazyFileList] > 0 } { lappend cmdList "\[list tclPkgSetup \$dir $opts(-name)\ $opts(-version) [list $lazyFileList]\]" } append cmdline [join $cmdList "\\n"] return $cmdline } tcl8.4.20/library/ldAout.tcl0000644003604700454610000001512011737050674014316 0ustar dgp771div# ldAout.tcl -- # # This "tclldAout" procedure in this script acts as a replacement # for the "ld" command when linking an object file that will be # loaded dynamically into Tcl or Tk using pseudo-static linking. # # Parameters: # The arguments to the script are the command line options for # an "ld" command. # # Results: # The "ld" command is parsed, and the "-o" option determines the # module name. ".a" and ".o" options are accumulated. # The input archives and object files are examined with the "nm" # command to determine whether the modules initialization # entry and safe initialization entry are present. A trivial # C function that locates the entries is composed, compiled, and # its .o file placed before all others in the command; then # "ld" is executed to bind the objects together. # # Copyright (c) 1995, by General Electric Company. All rights reserved. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # This work was supported in part by the ARPA Manufacturing Automation # and Design Engineering (MADE) Initiative through ARPA contract # F33615-94-C-4400. proc tclLdAout {{cc {}} {shlib_suffix {}} {shlib_cflags none}} { global env global argv if {[string equal $cc ""]} { set cc $env(CC) } # if only two parameters are supplied there is assumed that the # only shlib_suffix is missing. This parameter is anyway available # as "info sharedlibextension" too, so there is no need to transfer # 3 parameters to the function tclLdAout. For compatibility, this # function now accepts both 2 and 3 parameters. if {[string equal $shlib_suffix ""]} { set shlib_cflags $env(SHLIB_CFLAGS) } elseif {[string equal $shlib_cflags "none"]} { set shlib_cflags $shlib_suffix } # seenDotO is nonzero if a .o or .a file has been seen set seenDotO 0 # minusO is nonzero if the last command line argument was "-o". set minusO 0 # head has command line arguments up to but not including the first # .o or .a file. tail has the rest of the arguments. set head {} set tail {} # nmCommand is the "nm" command that lists global symbols from the # object files. set nmCommand {|nm -g} # entryProtos is the table of _Init and _SafeInit prototypes found in the # module. set entryProtos {} # entryPoints is the table of _Init and _SafeInit entries found in the # module. set entryPoints {} # libraries is the list of -L and -l flags to the linker. set libraries {} set libdirs {} # Process command line arguments foreach a $argv { if {!$minusO && [regexp {\.[ao]$} $a]} { set seenDotO 1 lappend nmCommand $a } if {$minusO} { set outputFile $a set minusO 0 } elseif {![string compare $a -o]} { set minusO 1 } if {[regexp {^-[lL]} $a]} { lappend libraries $a if {[regexp {^-L} $a]} { lappend libdirs [string range $a 2 end] } } elseif {$seenDotO} { lappend tail $a } else { lappend head $a } } lappend libdirs /lib /usr/lib # MIPS -- If there are corresponding G0 libraries, replace the # ordinary ones with the G0 ones. set libs {} foreach lib $libraries { if {[regexp {^-l} $lib]} { set lname [string range $lib 2 end] foreach dir $libdirs { if {[file exists [file join $dir lib${lname}_G0.a]]} { set lname ${lname}_G0 break } } lappend libs -l$lname } else { lappend libs $lib } } set libraries $libs # Extract the module name from the "-o" option if {![info exists outputFile]} { error "-o option must be supplied to link a Tcl load module" } set m [file tail $outputFile] if {[regexp {\.a$} $outputFile]} { set shlib_suffix .a } else { set shlib_suffix "" } if {[regexp {\..*$} $outputFile match]} { set l [expr {[string length $m] - [string length $match]}] } else { error "Output file does not appear to have a suffix" } set modName [string tolower $m 0 [expr {$l-1}]] if {[regexp {^lib} $modName]} { set modName [string range $modName 3 end] } if {[regexp {[0-9\.]*(_g0)?$} $modName match]} { set modName [string range $modName 0 [expr {[string length $modName]-[string length $match]-1}]] } set modName [string totitle $modName] # Catalog initialization entry points found in the module set f [open $nmCommand r] while {[gets $f l] >= 0} { if {[regexp {T[ ]*_?([A-Z][a-z0-9_]*_(Safe)?Init(__FP10Tcl_Interp)?)$} $l trash symbol]} { if {![regexp {_?([A-Z][a-z0-9_]*_(Safe)?Init)} $symbol trash s]} { set s $symbol } append entryProtos {extern int } $symbol { (); } \n append entryPoints { } \{ { "} $s {", } $symbol { } \} , \n } } close $f if {[string equal $entryPoints ""]} { error "No entry point found in objects" } # Compose a C function that resolves the initialization entry points and # embeds the required libraries in the object code. set C {#include } append C \n append C {char TclLoadLibraries_} $modName { [] =} \n append C { "@LIBS: } $libraries {";} \n append C $entryProtos append C {static struct } \{ \n append C { char * name;} \n append C { int (*value)();} \n append C \} {dictionary [] = } \{ \n append C $entryPoints append C { 0, 0 } \n \} \; \n append C {typedef struct Tcl_Interp Tcl_Interp;} \n append C {typedef int Tcl_PackageInitProc (Tcl_Interp *);} \n append C {Tcl_PackageInitProc *} \n append C TclLoadDictionary_ $modName { (symbol)} \n append C { CONST char * symbol;} \n append C { { int i; for (i = 0; dictionary [i] . name != 0; ++i) { if (!strcmp (symbol, dictionary [i] . name)) { return dictionary [i].value; } } return 0; } } append C \n # Write the C module and compile it set cFile tcl$modName.c set f [open $cFile w] puts -nonewline $f $C close $f set ccCommand "$cc -c $shlib_cflags $cFile" puts stderr $ccCommand eval exec $ccCommand # Now compose and execute the ld command that packages the module if {[string equal $shlib_suffix ".a"]} { set ldCommand "ar cr $outputFile" regsub { -o} $tail {} tail } else { set ldCommand ld foreach item $head { lappend ldCommand $item } } lappend ldCommand tcl$modName.o foreach item $tail { lappend ldCommand $item } puts stderr $ldCommand eval exec $ldCommand if {[string equal $shlib_suffix ".a"]} { exec ranlib $outputFile } # Clean up working files exec /bin/rm $cFile [file rootname $cFile].o } tcl8.4.20/library/history.tcl0000644003604700454610000002137611737050674014601 0ustar dgp771div# history.tcl -- # # Implementation of the history command. # # Copyright (c) 1997 Sun Microsystems, Inc. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # The tcl::history array holds the history list and # some additional bookkeeping variables. # # nextid the index used for the next history list item. # keep the max size of the history list # oldest the index of the oldest item in the history. namespace eval tcl { variable history if {![info exists history]} { array set history { nextid 0 keep 20 oldest -20 } } } # history -- # # This is the main history command. See the man page for its interface. # This does argument checking and calls helper procedures in the # history namespace. proc history {args} { set len [llength $args] if {$len == 0} { return [tcl::HistInfo] } set key [lindex $args 0] set options "add, change, clear, event, info, keep, nextid, or redo" switch -glob -- $key { a* { # history add if {$len > 3} { return -code error "wrong # args: should be \"history add event ?exec?\"" } if {![string match $key* add]} { return -code error "bad option \"$key\": must be $options" } if {$len == 3} { set arg [lindex $args 2] if {! ([string match e* $arg] && [string match $arg* exec])} { return -code error "bad argument \"$arg\": should be \"exec\"" } } return [tcl::HistAdd [lindex $args 1] [lindex $args 2]] } ch* { # history change if {($len > 3) || ($len < 2)} { return -code error "wrong # args: should be \"history change newValue ?event?\"" } if {![string match $key* change]} { return -code error "bad option \"$key\": must be $options" } if {$len == 2} { set event 0 } else { set event [lindex $args 2] } return [tcl::HistChange [lindex $args 1] $event] } cl* { # history clear if {($len > 1)} { return -code error "wrong # args: should be \"history clear\"" } if {![string match $key* clear]} { return -code error "bad option \"$key\": must be $options" } return [tcl::HistClear] } e* { # history event if {$len > 2} { return -code error "wrong # args: should be \"history event ?event?\"" } if {![string match $key* event]} { return -code error "bad option \"$key\": must be $options" } if {$len == 1} { set event -1 } else { set event [lindex $args 1] } return [tcl::HistEvent $event] } i* { # history info if {$len > 2} { return -code error "wrong # args: should be \"history info ?count?\"" } if {![string match $key* info]} { return -code error "bad option \"$key\": must be $options" } return [tcl::HistInfo [lindex $args 1]] } k* { # history keep if {$len > 2} { return -code error "wrong # args: should be \"history keep ?count?\"" } if {$len == 1} { return [tcl::HistKeep] } else { set limit [lindex $args 1] if {[catch {expr {~$limit}}] || ($limit < 0)} { return -code error "illegal keep count \"$limit\"" } return [tcl::HistKeep $limit] } } n* { # history nextid if {$len > 1} { return -code error "wrong # args: should be \"history nextid\"" } if {![string match $key* nextid]} { return -code error "bad option \"$key\": must be $options" } return [expr {$tcl::history(nextid) + 1}] } r* { # history redo if {$len > 2} { return -code error "wrong # args: should be \"history redo ?event?\"" } if {![string match $key* redo]} { return -code error "bad option \"$key\": must be $options" } return [tcl::HistRedo [lindex $args 1]] } default { return -code error "bad option \"$key\": must be $options" } } } # tcl::HistAdd -- # # Add an item to the history, and optionally eval it at the global scope # # Parameters: # command the command to add # exec (optional) a substring of "exec" causes the # command to be evaled. # Results: # If executing, then the results of the command are returned # # Side Effects: # Adds to the history list proc tcl::HistAdd {command {exec {}}} { variable history # Do not add empty commands to the history if {[string trim $command] eq ""} { return "" } set i [incr history(nextid)] set history($i) $command set j [incr history(oldest)] unset -nocomplain history($j) if {[string match e* $exec]} { return [uplevel #0 $command] } else { return {} } } # tcl::HistKeep -- # # Set or query the limit on the length of the history list # # Parameters: # limit (optional) the length of the history list # # Results: # If no limit is specified, the current limit is returned # # Side Effects: # Updates history(keep) if a limit is specified proc tcl::HistKeep {{limit {}}} { variable history if {$limit eq ""} { return $history(keep) } else { set oldold $history(oldest) set history(oldest) [expr {$history(nextid) - $limit}] for {} {$oldold <= $history(oldest)} {incr oldold} { unset -nocomplain history($oldold) } set history(keep) $limit } } # tcl::HistClear -- # # Erase the history list # # Parameters: # none # # Results: # none # # Side Effects: # Resets the history array, except for the keep limit proc tcl::HistClear {} { variable history set keep $history(keep) unset history array set history [list \ nextid 0 \ keep $keep \ oldest -$keep \ ] } # tcl::HistInfo -- # # Return a pretty-printed version of the history list # # Parameters: # num (optional) the length of the history list to return # # Results: # A formatted history list proc tcl::HistInfo {{num {}}} { variable history if {$num eq ""} { set num [expr {$history(keep) + 1}] } set result {} set newline "" for {set i [expr {$history(nextid) - $num + 1}]} \ {$i <= $history(nextid)} {incr i} { if {![info exists history($i)]} { continue } set cmd [string map [list \n \n\t] [string trimright $history($i) \ \n]] append result $newline[format "%6d %s" $i $cmd] set newline \n } return $result } # tcl::HistRedo -- # # Fetch the previous or specified event, execute it, and then # replace the current history item with that event. # # Parameters: # event (optional) index of history item to redo. Defaults to -1, # which means the previous event. # # Results: # Those of the command being redone. # # Side Effects: # Replaces the current history list item with the one being redone. proc tcl::HistRedo {{event -1}} { variable history if {$event eq ""} { set event -1 } set i [HistIndex $event] if {$i == $history(nextid)} { return -code error "cannot redo the current event" } set cmd $history($i) HistChange $cmd 0 uplevel #0 $cmd } # tcl::HistIndex -- # # Map from an event specifier to an index in the history list. # # Parameters: # event index of history item to redo. # If this is a positive number, it is used directly. # If it is a negative number, then it counts back to a previous # event, where -1 is the most recent event. # A string can be matched, either by being the prefix of # a command or by matching a command with string match. # # Results: # The index into history, or an error if the index didn't match. proc tcl::HistIndex {event} { variable history if {[catch {expr {~$event}}]} { for {set i [expr {$history(nextid)-1}]} {[info exists history($i)]} \ {incr i -1} { if {[string match $event* $history($i)]} { return $i; } if {[string match $event $history($i)]} { return $i; } } return -code error "no event matches \"$event\"" } elseif {$event <= 0} { set i [expr {$history(nextid) + $event}] } else { set i $event } if {$i <= $history(oldest)} { return -code error "event \"$event\" is too far in the past" } if {$i > $history(nextid)} { return -code error "event \"$event\" hasn't occured yet" } return $i } # tcl::HistEvent -- # # Map from an event specifier to the value in the history list. # # Parameters: # event index of history item to redo. See index for a # description of possible event patterns. # # Results: # The value from the history list. proc tcl::HistEvent {event} { variable history set i [HistIndex $event] if {[info exists history($i)]} { return [string trimright $history($i) \ \n] } else { return ""; } } # tcl::HistChange -- # # Replace a value in the history list. # # Parameters: # cmd The new value to put into the history list. # event (optional) index of history item to redo. See index for a # description of possible event patterns. This defaults # to 0, which specifies the current event. # # Side Effects: # Changes the history list. proc tcl::HistChange {cmd {event 0}} { variable history set i [HistIndex $event] set history($i) $cmd } tcl8.4.20/library/encoding/0000755003604700454610000000000012153151142014132 5ustar dgp771divtcl8.4.20/library/encoding/gb12345.enc0000644003604700454610000025113311737050674015634 0ustar dgp771div# Encoding file: gb12345, double-byte D 233F 0 83 21 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000030003001300230FB02C902C700A8300330052015FF5E2225202620182019 201C201D3014301530083009300A300B300C300D300E300F3016301730103011 00B100D700F72236222722282211220F222A222922082237221A22A522252220 23122299222B222E2261224C2248223D221D2260226E226F22642265221E2235 22342642264000B0203220332103FF0400A4FFE0FFE1203000A7211626062605 25CB25CF25CE25C725C625A125A025B325B2203B219221902191219330130000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 22 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000024882489248A248B248C248D248E248F2490249124922493249424952496 249724982499249A249B247424752476247724782479247A247B247C247D247E 247F248024812482248324842485248624872460246124622463246424652466 2467246824690000000032203221322232233224322532263227322832290000 00002160216121622163216421652166216721682169216A216B000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 23 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FF01FF02FF03FFE5FF05FF06FF07FF08FF09FF0AFF0BFF0CFF0DFF0EFF0F FF10FF11FF12FF13FF14FF15FF16FF17FF18FF19FF1AFF1BFF1CFF1DFF1EFF1F FF20FF21FF22FF23FF24FF25FF26FF27FF28FF29FF2AFF2BFF2CFF2DFF2EFF2F FF30FF31FF32FF33FF34FF35FF36FF37FF38FF39FF3AFF3BFF3CFF3DFF3EFF3F FF40FF41FF42FF43FF44FF45FF46FF47FF48FF49FF4AFF4BFF4CFF4DFF4EFF4F FF50FF51FF52FF53FF54FF55FF56FF57FF58FF59FF5AFF5BFF5CFF5DFFE30000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 24 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000304130423043304430453046304730483049304A304B304C304D304E304F 3050305130523053305430553056305730583059305A305B305C305D305E305F 3060306130623063306430653066306730683069306A306B306C306D306E306F 3070307130723073307430753076307730783079307A307B307C307D307E307F 3080308130823083308430853086308730883089308A308B308C308D308E308F 3090309130923093000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 25 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000030A130A230A330A430A530A630A730A830A930AA30AB30AC30AD30AE30AF 30B030B130B230B330B430B530B630B730B830B930BA30BB30BC30BD30BE30BF 30C030C130C230C330C430C530C630C730C830C930CA30CB30CC30CD30CE30CF 30D030D130D230D330D430D530D630D730D830D930DA30DB30DC30DD30DE30DF 30E030E130E230E330E430E530E630E730E830E930EA30EB30EC30ED30EE30EF 30F030F130F230F330F430F530F6000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 26 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000039103920393039403950396039703980399039A039B039C039D039E039F 03A003A103A303A403A503A603A703A803A90000000000000000000000000000 000003B103B203B303B403B503B603B703B803B903BA03BB03BC03BD03BE03BF 03C003C103C303C403C503C603C703C803C90000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 27 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000004100411041204130414041504010416041704180419041A041B041C041D 041E041F0420042104220423042404250426042704280429042A042B042C042D 042E042F00000000000000000000000000000000000000000000000000000000 000004300431043204330434043504510436043704380439043A043B043C043D 043E043F0440044104420443044404450446044704480449044A044B044C044D 044E044F00000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 28 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000010100E101CE00E0011300E9011B00E8012B00ED01D000EC014D00F301D2 00F2016B00FA01D400F901D601D801DA01DC00FC00EA00000000000000000000 0000000000000000000031053106310731083109310A310B310C310D310E310F 3110311131123113311431153116311731183119311A311B311C311D311E311F 3120312131223123312431253126312731283129000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 29 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000002500250125022503250425052506250725082509250A250B 250C250D250E250F2510251125122513251425152516251725182519251A251B 251C251D251E251F2520252125222523252425252526252725282529252A252B 252C252D252E252F2530253125322533253425352536253725382539253A253B 253C253D253E253F2540254125422543254425452546254725482549254A254B 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 30 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000554A963F57C3632854CE550954C0769A764C85F977EE827E7919611B9698 978D6C285B894FFA630966975CB880FA68489AAF660276CE51F9655671AC7FF1 895650B2596561CA6FB382AD634C625253ED54277B06516B75A45DF462D48DCB 9776628A801958E997387F777238767D67CF767E64FA4F70655762DC7A176591 73ED642C6273822C9812677F7248626E62CC4F3474E3534A8FA67D4690A65E6B 6886699C81807D8168D278C5868C938A508D8B1782DE80DE5305891252650000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 31 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000858496F94FDD582198FD5BF662B1583166B48C799B917206676F789160B2 535153178F2980CC8C9D92C7500D72FD5099618A711988AB595482EF672C7B28 5D297DB3752D6CF58E668FF8903C9F3B6BD491197B465F7C78A784D6853D7562 65836BD65E635E8775F99589655D5F0A5FC58F9F58C181C2907F965B97AD908A 7DE88CB662414FBF8B8A535E8FA88FAF8FAE904D6A195F6A819888689C49618B 522B765F5F6C658C70156FF18CD364EF517551B067C44E1979C9990570B30000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 32 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000075C55E7673BB83E064AD64A592626CE2535A52C3640F92517B944F2F5E1B 82368116818A6E246CCA99C16355535C54FA88DC57E04E0D5E036B657C3F90E8 601664E6731C88C16750624D8CA1776C8E2991C75F6983DC8521991053C38836 6B98615A615871E684BC825950096EC485CF64CD7CD969FD66F9834953A07B56 5074518C6E2C5C648E6D63D253C9832C833667E578B4643D5BDF5C945DEE8A6B 62C667F48C7A6519647B87EC995E8B927E8F93DF752395E1986B660C73160000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 33 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000583456175E389577511F81785EE0655E66A2553150218D8562849214671D 56326F6E5DE2543570928ECA626F64A463A35FB96F8890F481E38FB058756668 5FF16C8996738D81896F64917A3157CE6A59621054484E587A0B61F26F848AA0 627F901E9A0179E4540375F4630153196C6090725F1B99B3803B9F524F885C3A 8D647FC565A571BE5145885D87F25D075BF562BD916C75878E8A7A2061017C4C 4EC77DA27785919C81ED521D51FA6A7153A88E8792E496DB6EC19664695A0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 34 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000790E513277D7641089F8865563E35DDD7A7F693D50B3823955984E327621 7A975E625E8A95D652755439708A6376931857826625693F918755076DF37D14 882262337DBD75B5832878C196CC8FAD614874F78A5E6B64523A8CDC6B218070 847156F153065F9E53E251D17C97918B7C074FC38EA57BE17AC464675D1450AC 810676017CB96DEC7FE067515B585BF878CB64AE641363AA632B932F642D9054 7B5476296253592754466B7950A362345E366B864EE38CB8888B5F85902E0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 35 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006020803D64D44E3955AE913264A381BD65E66C2E4F46619A6DE18A955F48 86CB757664CB9EE885696A94520064178E4850125CF679B15C0E52307A3B60BC 905376D75FB75F9776848E6C71C8767B7B4977AA51F3912758244F4E6EF48FEA 65757B1B72C46ECC7FDF5AE162B55E95573084827B2C5E1D5F1F905E7DE0985B 63826EC778989EDE5178975B588A96FB4F4375385E9760E659606FB16BBF7889 53FC96D551CB52016389540A91E38ABF8DCC7239789F87768FED8ADC758A0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 36 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00004E0176EF53EE91D898029F0E93205B9A8A024E22677151AC846361C252D5 68DF4F97606B51CD6D1E515C62969B2596618C46901775D890FD77636BD272A2 73688B80583577798CED675C934D809A5EA66E2159927AEF77ED935B6BB565B7 7DDE58065151968A5C0D58A956788E726566981356E4920D76FE9041638754C6 591A596A579B8EB267358DFA8235524160F058AE86FE5CE89D5D4FC4984D8A1B 5A2560E15384627C904F910299136069800C51528033723E990C6D314E8C0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 37 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008CB3767C7F707B4F4F104E4F95A56CD573D085E95E06756A7FFB6A0A792C 91E97E4151E1716953CD8FD47BC48CA972AF98EF6CDB574A82B365B980AA623F 963259A84EFF8A2A7D21653E83F2975E556198DB80A5532A8AB9542080BA5EE2 6CB88CBB82AC915A54296C1B52067D1B58B3711A6C7E7C89596E4EFD5FFF61A4 7CDE8C505C01695387025CF092D298A8760B70FD902299AE7E2B8AF759499CF3 4F5B5426592B6577819A5B75627662C28F3B5E456C1F7B264F0F4FD8670D0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 38 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006D6E6DAA798F88B15F17752B64AB8F144FEF91DC65A7812F81515E9C8150 8D74526F89868CE65FA950854ED8961C723681798CA05BCC8A0396445A667E1B 54905676560E8A7265396982922384CB6E895E797518674667D17AFF809D8D95 611F79C665628D1B5CA1525B92FC7F38809B7DB15D176E2F67607BD9768B9AD8 818F7F947CD5641E93AC7A3F544A54E56B4C64F162089D3F80F3759952729769 845B683C86E495A39694927B500B54047D6668398DDF801566F45E9A7FB90000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 39 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000057C2803F68975DE5653B529F606D9F944F9B8EAC516C5BAB5F13978F6C5E 62F18CA25171920E52FE6E9D82DF72D757A269CB8CFC591F8F9C83C754957B8D 4F306CBD5B6459D19F1353E488319AA88C3780A16545986756FA96C7522E74DC 526E5BE1630289024E5662D0602A68FA95DC5B9851A089C07BA199287F506163 704C8CAB51495EE3901B7470898F572D78456B789F9C95A88ECC9B3C8A6D7678 68426AC38DEA8CB4528A8F256EDA68CD934B90ED570B679C88F9904E54C80000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 3A 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009AB85B696D776C264EA55BB399ED916361A890AF97D3542B6DB55BD251FD 558A7F557FF064BC634D65F161BE608D710A6C576F22592F676D822A58D5568E 8C6A6BEB90DD597D8017865F6D695475559D837783CF683879BE548C4F555408 76D28C8995A16CB36DB88D6B89109DB48CC0563F9ED175D55F8872E0606854FC 4EA86A2A886160528F5F54C470D886799D3B6D2A5B8F5F187D0555894FAF7334 543C539A50195F8C547C4E4E5FFD745A58FA846B80E1877472D07CCA6E560000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 3B 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005F27864E552C8B774E926EEC623782B1562983EF733E6ED1756B52835316 8A7169D05F8A61F76DEE58DE6B6174B0685390847DE963DB60A3559A76138C62 71656E195BA65E7B8352614C9EC478FA87577C27768751F060F6714C66435E4C 604D8B0A707063EE8F1D5FBD606286D456DE6BC160946167534960E066668CC4 7A62670371F4532F8AF18AA87E6A8477660F5A5A9B426E3E6DF78C416D3B4F19 706B7372621660D1970D8CA8798D64CA573E57FA6A5F75787A3D7A4D7B950000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 3C 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000808C99518FF96FC08B4F9DC459EC7E3E7DDD5409697568D88F2F7C4D96C6 53CA602575BE6C7253735AC97D1A64E05E7E810A5DF1858A628051805B634F0E 796D529160B86FDF5BC45BC28A088A1865E25FCC969B59937E7C7D00560967B7 593E4F735BB652A083A298308CC87532924050477A3C50F967B699D55AC16BB2 76E358055C167B8B9593714E517C80A9827159787DD87E6D6AA267EC78B19E7C 63C064BF7C215109526A51CF85A66ABB94528E108CE4898B93757BAD4EF60000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 3D 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000050658266528D991E6F386FFA6F975EFA50F559DC5C076F3F6C5F75868523 69F3596C8B1B532091AC964D854969127901712681A04EA490CA6F869A555B0C 56BC652A927877EF50E5811A72E189D299037E737D5E527F655991758F4E8F03 53EB7A9663ED63A5768679F88857968E622A52AB7BC0685467706377776B7AED 6F547D5089E359D0621285C982A5754C501F4ECB75A58AA15C4A5DFE7B4B65A4 91D14ECA6D25895F7DCA932650C58B3990329773664979818FD171FC6D780000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 3E 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000076E152C1834651628396775B66769BE84EAC9A5A7CBE7CB37D934E958B66 666F9838975C5883656C93E15F9175D997567ADF7AF651C870AF7A9863EA7A76 7CFE739697ED4E4570784E5D915253A96551820A81FC8205548E5C31759A97A0 62D872D975BD5C4599D283CA5C40548077E982096CAE805A62D264DA5DE85177 8DDD8E1E92F84FF153E561FC70AC528763509D515A1F5026773753777D796485 652B628963985014723589BA51B38A237D76574783CC921E8ECD541B5CFB0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 3F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00004FCA7AE36D5A90E199FF55805496536154AF958B63E9697751F16168520A 582A52D8574E780D770B5EB761777CE0625B62974EA27095800362F770E49760 577782DB67EF68F578D5984679D16BBB54B353EF6E34514B523B5BA28AB280AF 554358BE61C75751542D7A7A60505B5463A7647353E362635BC767AF54ED7A9F 82E691775EAB89328A8757AE630E8DE880EF584A7B7751085FEB5BEC6B3E5321 7B5072C268467926773666E051B5866776D45DCB7ABA8475594E9B4150800000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 40 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000994B61276F7057646606634656F062EC64F45ED395CA578362C95587881F 81D88FA35566840A4F868CF485CD5A6A6B0465147C4395CC862D703E8B95652C 89BD61F67E9C721B6FEB7405699472FC5ECA90CE67176D6A648852DE72628001 4F6C59E5916A70D96F8752D26A0296F79433857E78CA7D2F512158D864C2808B 985E6CEA68F1695E51B7539868A872819ECE7C6C72F896E270557406674E88CF 9BC979AE83898354540F68179E9753B252F5792B6B77522950884F8B4FD00000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 41 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000075E27ACB7C92701D96B8529B748354E95006806F84EE9023942E5EC96190 6F237C3E658281C993C8620071497DF47CE751C968817CB1826F51698F1B91CF 667E4EAE8AD264A9804A50DA764271CE5BE5907C6F664E86648294105ED66599 521788C270C852A373757433679778F7971681E891309C576DCB51DB8CC3541D 62CE73B283F196F69F6192344F367F9A51CC974896755DBA981853E64EE46E9C 740969B4786B993E7559528976246D4167F3516D9F8D807E56A87C607ABF0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 42 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000968658DF650F96B46A135A41645F7C0D6F0F964B860676E798715EEC7210 64C46EF7865C9B6F9E93788C97328DEF8CC29E7F6F5E798493329678622E9A62 541592C14FA365C55C655C627E37616E6C2F5F8B73876FFE7DD15DD265235B7F 706453754E8263A0756563848F2A502B4F966DEA7DB88AD6863F87BA7F85908F 947C7C6E9A3E88F8843D6D1B99F17D615ABD9EBB746A78BC879E99AC99E1561B 55CE57CB8CB79EA58CE390818109779E9945883B6EFF851366FC61626F2B0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 43 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008B3E8292832B76F26C135FD983BD732B830593286BDB77DB925A536F8302 51925E3D8C8C8CBF9EBD73AB679A68859176970971646CA177095A9293826BCF 7F8E66275BD059B95A9A958060B65011840C84996AAC76DF9333731B59225B5F 772F919A97617CDC8FF78B0E5F4C7C7379D889936CCC871C5BC65E4268C97720 7DBF5195514D52C95A297DEC976282D763CF778485D079D26E3A5EDF59998511 6EC56C1162BF76BF654F61AB95A9660E879F9CF49298540D547D8B2C64780000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 44 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000647986116A21819C78E864699B5462B9672B83AB58A89ED86CAB6F205BDE 964C8B00725F67D062C77261755D59C66BCD589366AE5E5552DF6155672876EE 776672677A4662FF54EA5450920990A35A1C7D0D6C164E435976801059485357 753796E356CA6493816660F19B276DD65462991251855AE980FD59AE9713502A 6CE55C3C64EC4F60533F81A990066EBA852B62C85E7478BE6506637B5FF55A18 91C09CE55C3F634F80765B7D5699947793B36D8560A86AB8737051DD5BE70000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 45 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000064F06FD8725B626D92157D1081BF6FC38FB25F04597452AA601259736696 86507627632A61E67CEF8AFE54E66B509DD76BC685D5561450766F1A556A8DB4 722C5E156015743662CD6392724C5F986E436D3E65006F5876E478D076FC7554 522453DB4E539F9065C1802A80D6629B5486522870AE888D8DD16CE1547880DA 57F988F48CE0966A914D4F696C9B567476C6783062A870F96F8E5F6D84EC68DA 787C7BF781A8670B9D6C636778B0576F78129739627962AB528874356BD70000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 46 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005564813E75B276AE533975DE50FB5C418B6C7BC7504F72479A1998C46F02 74E27968648777A562FC983B8CA754C180584E52576A860B840D5E73619174F6 8A555C4F57616F5198175A4678349B448FEB7C95525664B292EA50D583868461 83E984B257D46A385703666E6D668B5C66DD7011671F6B3A68F2621A59BB4E03 51C46F0667D26C8F517668CB59476B6775665D0E81CD9F4A65D7794879419A0E 8D778C484E5E4F0155535951780C56686C238FC468C46C7D6CE38A1663900000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 47 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000060706D3D727D626691FA925B534390777C3D4EDF8B194E7E9ED493229257 524D6F5B90636DFA8B7458795D4C6B206B4969CD55C681547F8C58BB85945F3A 64366A47936C657260846A4B77A755AC50D15DE7979864AC7FF95CED4FCF7AC5 520783044E14602F7ACA6B3D4FB589AA79E6743452E482B964D279BD5BE26C81 97528F156C2B50BE537F6E0564CE66746C3060C598038ACB617674CA7AAE79CB 4E1890B174036C4256DA914B6CC58DA8534086C666F28EC05C489A456E200000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 48 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000053D65A369F728DA353BB570898746B0A919B6CC9516875CA62F372AC5238 52F87F3A7094763853749D7269B778BA96C088D97FA4713671C3518967D374E4 58E4651856B78B93995264FE7E5E60F971B158EC4EC14EBA5FCD97CC4EFB8A8D 5203598A7D0962544ECD65E5620E833884C969AE878D71946EB65BB97D685197 63C967D480898339881551125B7A59828FB14E736C5D516589258EDF962E854A 745E92ED958F6F6482E55F316492705185A9816E9C13585E8CFD4E0953C10000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 49 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000050986563685155D355AA64149A3763835AC2745F82726F8068EE50E7838E 78026BBA52396C997D1750BB5565715E7BE966EC73CA82EB67495C715220717D 886B9583965D64C58D0D81B355846C5562477E55589250B755468CDE664C4E0A 5C1A88F368A2634E7A0D71D2828D52FA97F65C1154E890B57D3959628CD286C7 820C63688D66651D5C0461FE6D89793E8A2D78377533547B4F388EAB6DF15A20 7D33795E6C885BE95B38751A814E614E6EF28072751F7525727253477E690000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 4A 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000770176DB526952DD80565E2B5931734565BD6FD58A695C388671534177F3 62FE66424EC098DF87555BE68B5853F277E24F7F5C4E99DB59CB5F0F793A58EB 4E1667FF4E8B62ED8A93901D52E2662F55DC566C90694ED54F8D91CB98FE6C0F 5E0260435BA489968A666536624B99965B8858FD6388552E53D776267378852C 6A1E68B36B8A62928F3853D482126DD1758F66F88D165B70719F85AF669166D9 7F7287009ECD9F205C6C88538FF06A39675F620D7AEA58855EB665786F310000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 4B 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000060555237800D6454887075295E25681362F4971C96D9723D8AB06C347761 7A0E542E77AC9806821C8AAC78A96714720D65AF64955636601D79C153F87D72 6B7B80865BFA55E356DB4F3A4F3C98FC5DF39B068073616B980C90015B8B8A1F 8AA6641C825864FB55FD860791654FD77D20901F7C9F50F358516EAF5BBF8A34 80859178849C7B9796D6968B96A87D8F9AD3788E6B727A57904296A7795F5B6B 640D7B0B84D168AD55067E2E74637D2293966240584C4ED65B83597958540000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 4C 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000737A64BB8E4B8E0F80CE82D462AC81FA6CF0915E592A614B6C70574D6524 8CAA7671705858C76A8075F06F6D8B5A8AC757666BEF889278B363A2560670AD 6E6F5858642A580268E0819B55107CD650188EBA6DCC8D9F71D9638F6FE46ED4 7E278404684390036DD896768A0E5957727985E49A3075BC8B0468AF52548E22 92BB63D0984C8E44557C9AD466FF568F60D56D9552435C4959296DFB586B7530 751C606C821481466311689D8FE2773A8DF38CBC94355E165EF3807D70F40000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 4D 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006C405EF7505C4EAD5EAD633A8247901A6850916E77B3540C92855F647AE5 687663457B527D7175DB50776295982D900F51F879C37A8157165F9290145857 5C60571F541051546E4D571863A8983D817F8715892A9000541E5C6F81C062D6 625881319D15964099B199DD6A6259A562D3553E631654C786D97AAA5A0374E6 896A6B6A59168C4C5F4E706373A998114E3870F75B8C7897633D665A769660CB 5B9B5A49842C81556C6A738B4EA167897DB25F8065FA671B5FD859845A010000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 4E 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005DCD5FAE537197CB90556845570D552F60DF72326FF07DAD8466840E59D4 504950DE5C3E7DEF672A851A5473754F80C355829B4F4F4D6E2D8B025C096170 885B761F6E29868A6587805E7D0B543B7A697D0A554F55E17FC174EE64BE8778 6E267AA9621165A1536763E16C835DEB55DA93A270CF6C618AA35C4B7121856A 68A7543E54346BCB6B664E9463425348821E4F0D4FAE5862620A972766647269 52FF52D9609F8AA4661471996790897F785277FD6670563B5438932B72A70000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 4F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007A00606F5E0C6089819D591560DC718470EF6EAA6C5072806A8489725E2D 7FD25AB3559C92916D177CFB969962327D30778E87665323971E8F4466875CFD 4FE072F94E0B53A6590F56876380934151484ED99BAE7E9654B88CE2929C8237 95916D8E5F265ACC986F96AA73FE737B7E23817A99217FA161B2967796507DAB 76F853A2947299997BB189446E5891097FD479658A7360F397FF4EAB98055DF7 6A6150CF54118C61856D785D9704524A54EE56C292B76D885BB56DC666C90000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 50 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005C0F5B5D68218096562F7B11654869544E9B6B47874E978B5354633E643A 90AA659C81058AE75BEB68B0537887F961C86CC470098B1D5C5185AA82AF92C5 6B238F9B65B05FFB5FC34FE191C1661F8165732960FA82085211578B5F6290A2 884C91925E78674F602759D3514451F680F853086C7996C4718A4F114FEE7F9E 673D55C592B979C088967D89589F620C9700865A561898085F908A3184C49157 53D965ED5E8F755C60647D6E5A7F7DD27E8C8ED255A75BA361F865CB73840000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 51 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009078766C77297D629774859B5B787A7496EA884052DB718F5FAA65EC8A62 5C0B99B45DE16B896C5B8A138A0A905C8FC558D362BC9D099D2854404E2B82BD 7259869C5D1688596DAF96C5555E4E9E8A1D710954BD95B970DF6DF99E7D56B4 781487125CA95EF68A00985495BB708E6CBF594463A9773C884D6F1482775830 71D553AD786F96C155015F6671305BB48AFA9A576B83592E9D2679E7694A63DA 4F6F760D7F8A6D0B967D6C274EF07662990A6A236F3E90808170599674760000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 52 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006447582F90657A918B2159DA54AC820085E5898180006930564E8036723A 91CE51B64E5F98016396696D844966F3814B591C6DB24E0058F991AB63D692A5 4F9D4F0A886398245937907A79FB510080F075916C825B9C59E85F5D690587FB 501A5DF24E5977E34EE585DD6291661390915C7951045F7981C69038808475AB 4EA688D4610F6BC561B67FA976CA6EA28A638B708ABC8B6F5F027FFC7FCC7E79 8335852D56E06BB797F3967059FB541F92806DEB5BC598F25C395F1596B10000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 53 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000537082F16AFB5B309DF961C97E93746987A271DF719288058FCE8D0F76C8 5F717A4E786C662055B264C150AD81C376705EB896CD8E3486F9548F6CF36D8C 6C38607F52C775285E7D512A60A061825C24753190F5923E73366CB96E389149 670953CB53F34F5191C98A9853C85E7C8FC26DE44E8E76C26986865E611A8F3F 99184FDE903E9B5A61096E1D6F0196854E885A3196E882075DBC79B95B878A9E 7FBD738957DF828B9B315401904755BB5CEA5FA161086B32734480B28B7D0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 54 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006D745BD388D598108C6B99AD9D1B6DF551A4514357A38881539F63F48F45 571254E15713733F6E907DE3906082D198586028966266F07D048D8A8E8D9470 5CB37CA4670860A695B2801896F29116530096955141904B85F49196668897F5 5B55531D783896DC683D54C9707E5BB08F09518D572854B1652266AB8D0A8D1C 81DF846C906D7CDF947F85FB68D765E96FA186A48E81566A902076827AC871E5 8CAC64C752476FA48CCA600E589E618E66FE8D08624E55B36E23672D8ECB0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 55 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000935895987728680569A8548B4E4D70B88A5064589F4B5B857A8450B55BE8 77BB6C088A797C986CBE76DE65AC8F3E5D845C55863868E7536062307AD96E5B 7DBB6A1F7AE05F706F335F35638C6F3267564E085E338CEC4ED781397634969C 62DB662D627E6CBC8D9971677F695146808753EC906E629854F287C48F4D8005 937A851790196D5973CD659F771F7504782781FB8C9E91DD5075679575B98A3A 9707632F93AE966384B86399775C5F817319722D6014657462EF6B63653F0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 56 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005E407665912D8B49829D679D652F5431871877E580A281026C414E4B7E54 807776F4690D6B9657F7503C4F84574063076B628DBE887965E87D195FD7646F 64F281F381F47F6E5E5F5CD95236667A79E97A1A8CEA709975D46EEF6CBB7A92 4E2D76C55FE0941888777D427A2E816B91CD4EF28846821F54685DDE6D328B05 7CA58EF880985E1A549276BA5B99665D9A5F73E0682A86DB6731732A8AF88A85 90107AF971ED716E62C477DA56D14E3B845767F152A986C08CAF94447BC90000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 57 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00004F4F6CE8795D99D06293722A62FD5C0878DA8F4964B08CFA7BC66A01838A 88DD599D649E58EF72C0690E93108FFD8D05589C7DB48AC46E96634962D95353 684C74228301914C55447740707C6FC1517954A88CC759FF6ECB6DC45B5C7D2B 4ED47C7D6ED35B5081EA6F2C5B579B0368D58E2A5B977D9C7E3D7E3191128D70 594F63CD79DF8DB3535265CF79568A5B963B7D44947D7E825634918967007F6A 5C0A907566285DE64F5067DE505A4F5C57505EA7000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 58 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00004E8D4E0C51404E105EFF53454E154E984E1E9B325B6C56694E2879BA4E3F 53154E47592D723B536E6C1056DF80E499976BD3777E9F174E364E9F9F104E5C 4E694E9382885B5B55C7560F4EC45399539D53B453A553AE97688D0B531A53F5 532D5331533E8CFE5366536352025208520E52445233528C5274524C525E5261 525C84AF527D528252815290529351827F544EBB4EC34EC94EC24EE84EE14EEB 4EDE50B44EF34F224F644EF5500050964F094F474F5E4F6765384F5A4F5D0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 59 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00004F5F4F574F324F3D4F764F744F914F894F834F8F4F7E4F7B51154F7C5102 4F945114513C51374FC54FDA4FE34FDC4FD14FDF4FF85029504C4FF3502C500F 502E502D4FFE501C500C5025502850E8504350555048504E506C50C2513B5110 513A50BA50D6510650ED50EC50E650EE5107510B4EDD6C3D4F5850C94FCE9FA0 6C467CF4516E5DFD9ECC999856C5591452F9530D8A0753109CEC591951554EA0 51564EB3886E88A4893B81E088D279805B3488037FB851AB51B151BD51BC0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5A 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000051C7519651A251A58A018A108A0C8A158B338A4E8A258A418A368A468A54 8A588A528A868A848A7F8A708A7C8A758A6C8A6E8ACD8AE28A618A9A8AA58A91 8A928ACF8AD18AC98ADB8AD78AC28AB68AF68AEB8B148B018AE48AED8AFC8AF3 8AE68AEE8ADE8B288B9C8B168B1A8B108B2B8B2D8B568B598B4E8B9E8B6B8B96 5369537A961D962296219631962A963D963C964296589654965F9689966C9672 96749688968D969796B09097909B913A9099911490A190B490B390B691340000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5B 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000090B890B090DF90C590BE913690C490C79106914890E290DC90D790DB90EB 90EF90FE91049122911E91239131912F91399143914682BB595052F152AC52AD 52BE54FF52D052D652F053DF71EE77CD5EF451F551FC9B2F53B65F01755A5DF0 574C580A57A1587E58BC58C558D15729572C572A573358D9572E572F58E2573B 5742576958E0576B58DA577C577B5768576D5776577357E157A4578C584F57CF 57A75816579357A057D55852581D586457D257B857F457EF57F857E457DD0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5C 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000580B580D57FD57ED5800581E5819584458205865586C58815889589A5880 99A89F1961FF8279827D827F828F828A82A88284828E8291858C829982AB8553 82BE82B085F682CA82E3829882B782AE83A7840784EF82A982B482A182AA829F 82C482E782A482E1830982F782E48622830782DC82F482D282D8830C82FB82D3 8526831A8306584B716282E082D5831C8351855884FD83088392833C83348331 839B854E832F834F8347834385888340831785BA832D833A833372966ECE0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5D 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008541831B85CE855284C08452846483B083788494843583A083AA8393839C 8385837C859F83A9837D8555837B8398839E83A89DAF849383C1840183E583D8 58078418840B83DD83FD83D6841C84388411840683D483DF840F840383F883F9 83EA83C583C07E0883F083E1845C8451845A8459847385468488847A85628478 843C844684698476851E848E8431846D84C184CD84D09A4084BD84D384CA84BF 84BA863A84A184B984B4849793A38577850C750D853884F0861E851F85FA0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5E 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008556853B84FF84FC8559854885688564855E857A77A285438604857B85A4 85A88587858F857985EA859C858585B985B785B0861A85C185DC85FF86278605 86298616863C5EFE5F08593C596980375955595A5958530F5C225C255C2C5C37 624C636B647662BB62CA62DA62D762EE649F62F66339634B634363AD63F66371 637A638E6451636D63AC638A636963AE645C63F263F863E064B363C463DE63CE 645263C663BE65046441640B641B6420640C64266421645E6516646D64960000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000647A64F764FC6499651B64C064D064D764E464E265096525652E5F0B5FD2 75195F11535F53F1563053E953E853FB541254165406544B563856C8545456A6 54435421550454BC5423543254825494547754715464549A5680548454765466 565D54D054AD54C254B4566054A754A6563555F6547254A3566654BB54BF54CC 567254DA568C54A954AA54A4566554CF54DE561C54E7562E54FD551454F355E9 5523550F55115527552A5616558F55B5554956C055415555553F5550553C0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 60 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005537555655755576557755335530555C558B55D2558355B155B955885581 559F557E55D65591557B55DF560D56B35594559955EA55F755C9561F55D156C1 55EC55D455E655DD55C455EF55E555F2566F55CC55CD55E855F555E48F61561E 5608560C560156B6562355FE56005627562D565856395657562C564D56625659 5695564C5654568656645671566B567B567C5685569356AF56D456D756DD56E1 570756EB56F956FF5704570A5709571C5E435E195E145E115E6C5E585E570000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 61 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005E375E445E545E5B5E5E5E615C8C5C7A5C8D5C905D875C885CF45C995C91 5D505C9C5CB55CA25D2C5CAC5CAB5CB15CA35CC15CB75DA75CD25DA05CCB5D22 5D975D0D5D275D265D2E5D245D1E5D065D1B5DB85D3E5D345D3D5D6C5D5B5D6F 5D815D6B5D4B5D4A5D695D745D825D995D9D8C735DB75DD45F735F775F825F87 5F89540E5FA05F995F9C5FA85FAD5FB55FBC88625F6172AD72B072B473777341 72C372C172CE72CD72D272E8736A72E9733B72F472F7730172F3736B72FA0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 62 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000072FB731773137380730A731E731D737C732273397325732C733873317350 734D73577360736C736F737E821B592598E75924590298E0993398E9993C98EA 98EB98ED98F4990999114F59991B9937993F994399489949994A994C99625E80 5EE15E8B5E965EA55EA05EB95EB55EBE5EB38CE15ED25ED15EDB5EE85EEA81BA 5FC45FC95FD661FA61AE5FEE616A5FE15FE4613E60B561345FEA5FED5FF86019 60356026601B600F600D6029602B600A61CC6021615F61E860FB613760420000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 63 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000606A60F26096609A6173609D60836092608C609B611C60BB60B160DD60D8 60C660DA60B4612061926115612360F46100610E612B614A617561AC619461A7 61B761D461F55FDD96B39582958695C8958E9594958C95E595AD95AB9B2E95AC 95BE95B69B2995BF95BD95BC95C395CB95D495D095D595DE4E2C723F62156C35 6C546C5C6C4A70436C856C906C946C8C6C686C696C746C766C866F596CD06CD4 6CAD702770186CF16CD76CB26CE06CD66FFC6CEB6CEE6CB16CD36CEF6D870000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 64 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006D396D276D0C6D796E5E6D076D046D196D0E6D2B6FAE6D2E6D356D1A700F 6EF86F6F6D336D916D6F6DF66F7F6D5E6D936D946D5C6D606D7C6D636E1A6DC7 6DC56DDE70066DBF6DE06FA06DE66DDD6DD9700B6DAB6E0C6DAE6E2B6E6E6E4E 6E6B6EB26E5F6E866E536E546E326E256E4470676EB16E9870446F2D70056EA5 6EA76EBD6EBB6EB76F776EB46ECF6E8F6EC26E9F6F627020701F6F246F156EF9 6F2F6F3670326F746F2A6F096F296F896F8D6F8C6F786F726F7C6F7A70280000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 65 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006FC96FA76FB96FB66FC26FE16FEE6FDE6FE06FEF701A7023701B70397035 705D705E5B805B845B955B935BA55BB8752F9A2B64345BE45BEE89305BF08E47 8B078FB68FD38FD58FE58FEE8FE490878FE690158FE890059004900B90909011 900D9016902190359036902D902F9044905190529050906890589062905B66B9 9074907D908290889083908B5F505F575F565F585C3B54AB5C505C595B715C63 5C687FBC5F335F295F2D82745F3C9B3B5C6E59815983598D5AF55AD759A30000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 66 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000599759CA5B00599E59A459D259B259AF59D759BE5A6D5B0859DD5B4C59E3 59D859F95A0C5A095AA75AFB5A115A235A135A405A675A4A5A555A3C5A625B0B 80EC5AAA5A9B5A775A7A5ABE5AEB5AB25B215B2A5AB85AE05AE35B195AD65AE6 5AD85ADC5B095B175B165B325B375B405C155C1C5B5A5B655B735B515B535B62 99D499DF99D99A369A5B99D199D89A4D9A4A99E29A6A9A0F9A0D9A059A429A2D 9A169A419A2E9A389A439A449A4F9A659A647CF97D067D027D077D087E8A0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 67 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007D1C7D157D137D3A7D327D317E107D3C7D407D3F7D5D7D4E7D737D867D83 7D887DBE7DBA7DCB7DD47DC47D9E7DAC7DB97DA37DB07DC77DD97DD77DF97DF2 7E627DE67DF67DF17E0B7DE17E097E1D7E1F7E1E7E2D7E0A7E117E7D7E397E35 7E327E467E457E887E5A7E527E6E7E7E7E707E6F7E985E7A757F5DDB753E9095 738E74A3744B73A2739F73CF73C274CF73B773B373C073C973C873E573D9980A 740A73E973E773DE74BD743F7489742A745B7426742574287430742E742C0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 68 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000741B741A7441745C74577455745974A6746D747E749C74D4748074817487 748B749E74A874A9749074A774DA74BA97D997DE97DC674C6753675E674869AA 6AEA6787676A677367986898677568D66A05689F678B6777677C67F06ADB67D8 6AF367E967B06AE867D967B567DA67B367DD680067C367B867E26ADF67C16A89 68326833690F6A48684E6968684469BF6883681D68556A3A68416A9C68406B12 684A6849682968B5688F687468776893686B6B1E696E68FC6ADD69E768F90000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 69 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006B0F68F0690B6901695768E369106971693969606942695D6B16696B6980 69986978693469CC6AEC6ADA69CE6AF8696669636979699B69A769BB69AB69AD 69D469B169C169CA6AB369956AE7698D69FF6AA369ED6A176A186A6569F26A44 6A3E6AA06A506A5B6A356A8E6AD36A3D6A286A586ADE6A916A906AA96A976AAB 733773526B816B826BA46B846B9E6BAE6B8D6BAB6B9B6BAF6BAA8ED48EDB8EF2 8EFB8F648EF98EFC8EEB8EE48F628EFA8EFE8F0A8F078F058F128F268F1E0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6A 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008F1F8F1C8F338F468F548ECE62146227621B621F62226221622562246229 81E7750C74F474FF750F75117513653465EE65EF65F0660A66C7677266036615 6600708566F7661D66346631663666358006665F66C46641664F668966616657 66776684668C66D6669D66BE66DB66DC66E666E98CC18CB08CBA8CBD8D048CB2 8CC58D108CD18CDA8CD58CEB8CE78CFB899889AC89A189BF89A689AF89B289B7 726E729F725D7266726F727E727F7284728B728D728F72926308633263B00000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6B 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000643F64D880046BEA6BF36BFD6BFF6BF96C056C0C6C066C0D6C156C186C19 6C1A6C216C2C6C246C2A6C3265356555656B725872527256723086625216809F 809C809380BC670A80BD80B180AB80AD80B480B76727815680E981DA80DB80C2 80C480D980CD80D7671080DD811B80F180F480ED81BE810E80F280FC67158112 8C5A8161811E812C811881328148814C815381748159815A817181608169817C 817D816D8167584D5AB58188818281CF6ED581A381AA81CC672681CA81BB0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6C 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000081C181A66B5F6B376B396B436B466B5998AE98AF98B698BC98C698C86BB3 5F408F4289F365909F4F659565BC65C665C465C365CC65CE65D265D6716C7152 7096719770BB70C070B770AB70B171C170CA7110711371DC712F71317173715C 716871457172714A7178717A719871B371B571A871A071E071D471E771F9721D 7228706C71FE716671B9623E623D624362486249793B794079467949795B795C 7953795A79B079577960798E7967797A79AA798A799A79A779B35FD15FD00000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6D 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000061DF605D605A606760416059606361646106610D615D61A9619D61CB61E3 62078080807F6C936FA96DFC78EF77F878AD780978687818781165AB782D78B8 781D7839792A7931781F783C7825782C78237829784E786D786478FD78267850 7847784C786A78E77893789A788778E378A178A378B278B978A578D478D978C9 78EC78F2790578F479137924791E79349F959EF99EFB9EFC76F17704779876F9 77077708771A77227719772D772677357738775E77BC77477743775A77680000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6E 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000077627765777F778D777D7780778C7791779F77A077B077B577BD753A7540 754E754B7548755B7572757975837F587F617F5F8A487F687F867F717F797F88 7F7E76CD76E5883291D291D391D491D991D791D591F791E791E4934691F591F9 9208922692459211921092019227920492259200923A9266923792339255923D 9238925E926C926D923F9460923092499248924D922E9239943892AC92A0927A 92AA92EE92CF940392E3943A92B192A693A7929692CC92A993F59293927F0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000093A9929A931A92AB9283940B92A892A39412933892F193D792E592F092EF 92E892BC92DD92F69426942792C392DF92E6931293069369931B934093019315 932E934393079308931F93199365934793769354936493AA9370938493E493D8 9428938793CC939893B893BF93A693B093B5944C93E293DC93DD93CD93DE93C3 93C793D19414941D93F794659413946D9420947993F99419944A9432943F9454 9463937E77E777EC96C979D579ED79E379EB7A065D477A037A027A1E7A140000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 70 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007A397A377A619ECF99A57A707688768E7693769976A474DE74E0752C9CE9 9CF69D079D069D239D879E159D1D9D1F9DE59D2F9DD99D309D429E1E9D539E1D 9D609D529DF39D5C9D619D939D6A9D6F9D899D989D9A9DC09DA59DA99DC29DBC 9E1A9DD39DDA9DEF9DE69DF29DF89E0C9DFA9E1B7592759476647658759D7667 75A375B375B475B875C475B175B075C375C2760275CD75E3764675E675E47647 75E7760375F175FC75FF761076007649760C761E760A7625763B761576190000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 71 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000761B763C762276207640762D7630766D76357643766E7633764D76697654 765C76567672766F7FCA7AE67A787A797A807A867A887A957AC77AA07AAC7AA8 7AB67AB3886488698872887D887F888288A2896088B788BC88C9893388CE895D 894788F1891A88FC88E888FE88F08921891989138938890A8964892B89368941 8966897B758B80E576B876B477DC801280148016801C8020802E80258026802C 802980288031800B803580438046807980528075807189839807980E980F0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 72 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009821981C6F4198269837984E98539873986298599865986C9870864D8654 866C87E38806867A867C867B86A8868D868B8706869D86A786A386AA869386A9 86B686C486B5882386B086BA86B186AF86C987F686B486E986FA87EF86ED8784 86D0871386DE881086DF86D886D18703870786F88708870A870D87098723873B 871E8725872E871A873E87C88734873187298737873F87828722877D8811877B 87608770874C876E878B8753876387BB876487598765879387AF87CE87D20000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 73 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000087C68788878587AD8797878387AB87E587AC87B587B387CB87D387BD87D1 87C087CA87DB87EA87E087EE8816881387FE880A881B88218839883C7F367F4C 7F447F4582107AFA7AFD7B087BE47B047B677B0A7B2B7B0F7B477B387B2A7B19 7B2E7B317B207B257B247B337C697B1E7B587BF37B457B757B4C7B8F7B607B6E 7B7B7B627B727B717B907C007BCB7BB87BAC7B9D7C5C7B857C1E7B9C7BA27C2B 7BB47C237BC17BCC7BDD7BDA7BE57BE67BEA7C0C7BFE7BFC7C0F7C6A7C0B0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 74 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007C1F7C2A7C267C387C5F7C4081FE82018202820481EC8844822182228264 822D822F8228822B8238826B82338234823E82448249824B824F825A825F8268 887E88CA888888D888DF895E7F9D7FA57FA77FAF7FB07FB27C7C65497C917CF2 7CF67C9E7CA27CB27CBC7CBD7CDD7CC77CCC7CCD7CC87CC57CD77CE8826E66A8 7FBF7FCE7FD57FE57FE17FE67FE97FEE7FF37CF87E367DA67DAE7E477E9B9EA9 9EB48D738D848D948D918DB28D678D6D8C478C49914A9150914E914F91640000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 75 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009162916191709169916F91C591C3917291749179918C91859190918D9191 91A291A391AA91AD91AE91AF91B591B491BA8C559E7A8E898DEB8E058E598E69 8DB58DBF8DBC8DBA8E4C8DD68DD78DDA8E928DCE8DCF8DDB8DC68DEC8E7A8E55 8DE38E9A8E8B8DE48E098DFD8E148E1D8E1F8E938E2E8E238E918E3A8E408E39 8E358E3D8E318E498E418E428EA18E638E4A8E708E768E7C8E6F8E748E858EAA 8E948E908EA68E9E8C788C828C8A8C858C988C94659B89D689F489DA89DC0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 76 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000089E589EB89F68A3E8B26975A96E9974296EF9706973D9708970F970E972A 97449730973E9F549F5F9F599F609F5C9F669F6C9F6A9F779EFD9EFF9F0996B9 96BC96BD96CE96D277BF8B8E928E947E92C893E8936A93CA938F943E946B9B77 9B749B819B839B8E9C787A4C9B929C5F9B909BAD9B9A9BAA9B9E9C6D9BAB9B9D 9C589BC19C7A9C319C399C239C379BC09BCA9BC79BFD9BD69BEA9BEB9BE19BE4 9BE79BDD9BE29BF09BDB9BF49BD49C5D9C089C109C0D9C129C099BFF9C200000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 77 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009C329C2D9C289C259C299C339C3E9C489C3B9C359C459C569C549C529C67 977C978597C397BD979497C997AB97A397B297B49AB19AB09AB79DBB9AB69ABA 9ABC9AC19AC09ACF9AC29AD69AD59AD19B459B439B589B4E9B489B4D9B519957 995C992E995599549ADF9AE19AE69AEF9AEB9AFB9AED9AF99B089B0F9B229B1F 9B234E489EBE7E3B9E829E879E889E8B9E9293D69E9D9E9F9EDB9EDC9EDD9EE0 9EDF9EE29EF79EE79EE59EF29EEF9F229F2C9F2F9F399F379F3D9F3E9F440000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 78 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000896C95C693365F4685147E94538251B24E119F635679515A6DC09F156597 56419AEE83034E3089075E727A4098B35E7F95A49B0D52128FF45F597A6B98E2 51E050A24EF7835085915118636E6372524B5938774F8721814A7E8D91CC66C6 5E1877AD9E7556C99EF46FDB61DE77C770309EB5884A95E282F951ED62514EC6 673497C67C647E3497A69EAF786E820D672F677E56CC53F098B16AAF7F4E6D82 7CF04E074FC27E6B9E7956AE9B1A846F53F690C179A67C72613F4E919AD20000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 79 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000075C796BB53EA7DFB88FD79CD78437B5151C6000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 tcl8.4.20/library/encoding/tis-620.enc0000755003604700454610000000210311737050674015743 0ustar dgp771div# Encoding file: tis-620, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000E010E020E030E040E050E060E070E080E090E0A0E0B0E0C0E0D0E0E0E0F 0E100E110E120E130E140E150E160E170E180E190E1A0E1B0E1C0E1D0E1E0E1F 0E200E210E220E230E240E250E260E270E280E290E2A0E2B0E2C0E2D0E2E0E2F 0E300E310E320E330E340E350E360E370E380E390E3A00000000000000000E3F 0E400E410E420E430E440E450E460E470E480E490E4A0E4B0E4C0E4D0E4E0E4F 0E500E510E520E530E540E550E560E570E580E590E5A0E5B0000000000000000tcl8.4.20/library/encoding/cp852.enc0000644003604700454610000000210211737050674015474 0ustar dgp771div# Encoding file: cp852, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 00C700FC00E900E200E4016F010700E7014200EB0150015100EE017900C40106 00C90139013A00F400F6013D013E015A015B00D600DC01640165014100D7010D 00E100ED00F300FA01040105017D017E0118011900AC017A010C015F00AB00BB 2591259225932502252400C100C2011A015E256325512557255D017B017C2510 25142534252C251C2500253C01020103255A25542569256625602550256C00A4 01110110010E00CB010F014700CD00CE011B2518250C258825840162016E2580 00D300DF00D401430144014801600161015400DA0155017000FD00DD016300B4 00AD02DD02DB02C702D800A700F700B800B000A802D901710158015925A000A0 tcl8.4.20/library/encoding/cp1258.enc0000644003604700454610000000210311737050674015556 0ustar dgp771div# Encoding file: cp1258, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 20AC0081201A0192201E20262020202102C62030008A20390152008D008E008F 009020182019201C201D20222013201402DC2122009A203A0153009D009E0178 00A000A100A200A300A400A500A600A700A800A900AA00AB00AC00AD00AE00AF 00B000B100B200B300B400B500B600B700B800B900BA00BB00BC00BD00BE00BF 00C000C100C2010200C400C500C600C700C800C900CA00CB030000CD00CE00CF 011000D1030900D300D401A000D600D700D800D900DA00DB00DC01AF030300DF 00E000E100E2010300E400E500E600E700E800E900EA00EB030100ED00EE00EF 011100F1032300F300F401A100F600F700F800F900FA00FB00FC01B020AB00FF tcl8.4.20/library/encoding/cp437.enc0000644003604700454610000000210211737050674015473 0ustar dgp771div# Encoding file: cp437, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 00C700FC00E900E200E400E000E500E700EA00EB00E800EF00EE00EC00C400C5 00C900E600C600F400F600F200FB00F900FF00D600DC00A200A300A520A70192 00E100ED00F300FA00F100D100AA00BA00BF231000AC00BD00BC00A100AB00BB 259125922593250225242561256225562555256325512557255D255C255B2510 25142534252C251C2500253C255E255F255A25542569256625602550256C2567 2568256425652559255825522553256B256A2518250C25882584258C25902580 03B100DF039303C003A303C300B503C403A6039803A903B4221E03C603B52229 226100B1226522642320232100F7224800B0221900B7221A207F00B225A000A0 tcl8.4.20/library/encoding/cp1255.enc0000644003604700454610000000210311737050674015553 0ustar dgp771div# Encoding file: cp1255, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 20AC0081201A0192201E20262020202102C62030008A2039008C008D008E008F 009020182019201C201D20222013201402DC2122009A203A009C009D009E009F 00A000A100A200A320AA00A500A600A700A800A900D700AB00AC00AD00AE00AF 00B000B100B200B300B400B500B600B700B800B900F700BB00BC00BD00BE00BF 05B005B105B205B305B405B505B605B705B805B9000005BB05BC05BD05BE05BF 05C005C105C205C305F005F105F205F305F40000000000000000000000000000 05D005D105D205D305D405D505D605D705D805D905DA05DB05DC05DD05DE05DF 05E005E105E205E305E405E505E605E705E805E905EA00000000200E200F0000 tcl8.4.20/library/encoding/iso8859-1.enc0000644003604700454610000000210611737050674016125 0ustar dgp771div# Encoding file: iso8859-1, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 0080008100820083008400850086008700880089008A008B008C008D008E008F 0090009100920093009400950096009700980099009A009B009C009D009E009F 00A000A100A200A300A400A500A600A700A800A900AA00AB00AC00AD00AE00AF 00B000B100B200B300B400B500B600B700B800B900BA00BB00BC00BD00BE00BF 00C000C100C200C300C400C500C600C700C800C900CA00CB00CC00CD00CE00CF 00D000D100D200D300D400D500D600D700D800D900DA00DB00DC00DD00DE00DF 00E000E100E200E300E400E500E600E700E800E900EA00EB00EC00ED00EE00EF 00F000F100F200F300F400F500F600F700F800F900FA00FB00FC00FD00FE00FF tcl8.4.20/library/encoding/cp949.enc0000644003604700454610000037656711737050674015540 0ustar dgp771div# Encoding file: cp949, multi-byte M 003F 0 125 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 0080000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 81 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000AC02AC03AC05AC06AC0BAC0CAC0DAC0EAC0FAC18AC1EAC1FAC21AC22AC23 AC25AC26AC27AC28AC29AC2AAC2BAC2EAC32AC33AC3400000000000000000000 0000AC35AC36AC37AC3AAC3BAC3DAC3EAC3FAC41AC42AC43AC44AC45AC46AC47 AC48AC49AC4AAC4CAC4EAC4FAC50AC51AC52AC53AC5500000000000000000000 0000AC56AC57AC59AC5AAC5BAC5DAC5EAC5FAC60AC61AC62AC63AC64AC65AC66 AC67AC68AC69AC6AAC6BAC6CAC6DAC6EAC6FAC72AC73AC75AC76AC79AC7BAC7C AC7DAC7EAC7FAC82AC87AC88AC8DAC8EAC8FAC91AC92AC93AC95AC96AC97AC98 AC99AC9AAC9BAC9EACA2ACA3ACA4ACA5ACA6ACA7ACABACADACAEACB1ACB2ACB3 ACB4ACB5ACB6ACB7ACBAACBEACBFACC0ACC2ACC3ACC5ACC6ACC7ACC9ACCAACCB ACCDACCEACCFACD0ACD1ACD2ACD3ACD4ACD6ACD8ACD9ACDAACDBACDCACDDACDE ACDFACE2ACE3ACE5ACE6ACE9ACEBACEDACEEACF2ACF4ACF7ACF8ACF9ACFAACFB ACFEACFFAD01AD02AD03AD05AD07AD08AD09AD0AAD0BAD0EAD10AD12AD130000 82 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000AD14AD15AD16AD17AD19AD1AAD1BAD1DAD1EAD1FAD21AD22AD23AD24AD25 AD26AD27AD28AD2AAD2BAD2EAD2FAD30AD31AD32AD3300000000000000000000 0000AD36AD37AD39AD3AAD3BAD3DAD3EAD3FAD40AD41AD42AD43AD46AD48AD4A AD4BAD4CAD4DAD4EAD4FAD51AD52AD53AD55AD56AD5700000000000000000000 0000AD59AD5AAD5BAD5CAD5DAD5EAD5FAD60AD62AD64AD65AD66AD67AD68AD69 AD6AAD6BAD6EAD6FAD71AD72AD77AD78AD79AD7AAD7EAD80AD83AD84AD85AD86 AD87AD8AAD8BAD8DAD8EAD8FAD91AD92AD93AD94AD95AD96AD97AD98AD99AD9A AD9BAD9EAD9FADA0ADA1ADA2ADA3ADA5ADA6ADA7ADA8ADA9ADAAADABADACADAD ADAEADAFADB0ADB1ADB2ADB3ADB4ADB5ADB6ADB8ADB9ADBAADBBADBCADBDADBE ADBFADC2ADC3ADC5ADC6ADC7ADC9ADCAADCBADCCADCDADCEADCFADD2ADD4ADD5 ADD6ADD7ADD8ADD9ADDAADDBADDDADDEADDFADE1ADE2ADE3ADE5ADE6ADE7ADE8 ADE9ADEAADEBADECADEDADEEADEFADF0ADF1ADF2ADF3ADF4ADF5ADF6ADF70000 83 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000ADFAADFBADFDADFEAE02AE03AE04AE05AE06AE07AE0AAE0CAE0EAE0FAE10 AE11AE12AE13AE15AE16AE17AE18AE19AE1AAE1BAE1C00000000000000000000 0000AE1DAE1EAE1FAE20AE21AE22AE23AE24AE25AE26AE27AE28AE29AE2AAE2B AE2CAE2DAE2EAE2FAE32AE33AE35AE36AE39AE3BAE3C00000000000000000000 0000AE3DAE3EAE3FAE42AE44AE47AE48AE49AE4BAE4FAE51AE52AE53AE55AE57 AE58AE59AE5AAE5BAE5EAE62AE63AE64AE66AE67AE6AAE6BAE6DAE6EAE6FAE71 AE72AE73AE74AE75AE76AE77AE7AAE7EAE7FAE80AE81AE82AE83AE86AE87AE88 AE89AE8AAE8BAE8DAE8EAE8FAE90AE91AE92AE93AE94AE95AE96AE97AE98AE99 AE9AAE9BAE9CAE9DAE9EAE9FAEA0AEA1AEA2AEA3AEA4AEA5AEA6AEA7AEA8AEA9 AEAAAEABAEACAEADAEAEAEAFAEB0AEB1AEB2AEB3AEB4AEB5AEB6AEB7AEB8AEB9 AEBAAEBBAEBFAEC1AEC2AEC3AEC5AEC6AEC7AEC8AEC9AECAAECBAECEAED2AED3 AED4AED5AED6AED7AEDAAEDBAEDDAEDEAEDFAEE0AEE1AEE2AEE3AEE4AEE50000 84 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000AEE6AEE7AEE9AEEAAEECAEEEAEEFAEF0AEF1AEF2AEF3AEF5AEF6AEF7AEF9 AEFAAEFBAEFDAEFEAEFFAF00AF01AF02AF03AF04AF0500000000000000000000 0000AF06AF09AF0AAF0BAF0CAF0EAF0FAF11AF12AF13AF14AF15AF16AF17AF18 AF19AF1AAF1BAF1CAF1DAF1EAF1FAF20AF21AF22AF2300000000000000000000 0000AF24AF25AF26AF27AF28AF29AF2AAF2BAF2EAF2FAF31AF33AF35AF36AF37 AF38AF39AF3AAF3BAF3EAF40AF44AF45AF46AF47AF4AAF4BAF4CAF4DAF4EAF4F AF51AF52AF53AF54AF55AF56AF57AF58AF59AF5AAF5BAF5EAF5FAF60AF61AF62 AF63AF66AF67AF68AF69AF6AAF6BAF6CAF6DAF6EAF6FAF70AF71AF72AF73AF74 AF75AF76AF77AF78AF7AAF7BAF7CAF7DAF7EAF7FAF81AF82AF83AF85AF86AF87 AF89AF8AAF8BAF8CAF8DAF8EAF8FAF92AF93AF94AF96AF97AF98AF99AF9AAF9B AF9DAF9EAF9FAFA0AFA1AFA2AFA3AFA4AFA5AFA6AFA7AFA8AFA9AFAAAFABAFAC AFADAFAEAFAFAFB0AFB1AFB2AFB3AFB4AFB5AFB6AFB7AFBAAFBBAFBDAFBE0000 85 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000AFBFAFC1AFC2AFC3AFC4AFC5AFC6AFCAAFCCAFCFAFD0AFD1AFD2AFD3AFD5 AFD6AFD7AFD8AFD9AFDAAFDBAFDDAFDEAFDFAFE0AFE100000000000000000000 0000AFE2AFE3AFE4AFE5AFE6AFE7AFEAAFEBAFECAFEDAFEEAFEFAFF2AFF3AFF5 AFF6AFF7AFF9AFFAAFFBAFFCAFFDAFFEAFFFB002B00300000000000000000000 0000B005B006B007B008B009B00AB00BB00DB00EB00FB011B012B013B015B016 B017B018B019B01AB01BB01EB01FB020B021B022B023B024B025B026B027B029 B02AB02BB02CB02DB02EB02FB030B031B032B033B034B035B036B037B038B039 B03AB03BB03CB03DB03EB03FB040B041B042B043B046B047B049B04BB04DB04F B050B051B052B056B058B05AB05BB05CB05EB05FB060B061B062B063B064B065 B066B067B068B069B06AB06BB06CB06DB06EB06FB070B071B072B073B074B075 B076B077B078B079B07AB07BB07EB07FB081B082B083B085B086B087B088B089 B08AB08BB08EB090B092B093B094B095B096B097B09BB09DB09EB0A3B0A40000 86 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000B0A5B0A6B0A7B0AAB0B0B0B2B0B6B0B7B0B9B0BAB0BBB0BDB0BEB0BFB0C0 B0C1B0C2B0C3B0C6B0CAB0CBB0CCB0CDB0CEB0CFB0D200000000000000000000 0000B0D3B0D5B0D6B0D7B0D9B0DAB0DBB0DCB0DDB0DEB0DFB0E1B0E2B0E3B0E4 B0E6B0E7B0E8B0E9B0EAB0EBB0ECB0EDB0EEB0EFB0F000000000000000000000 0000B0F1B0F2B0F3B0F4B0F5B0F6B0F7B0F8B0F9B0FAB0FBB0FCB0FDB0FEB0FF B100B101B102B103B104B105B106B107B10AB10DB10EB10FB111B114B115B116 B117B11AB11EB11FB120B121B122B126B127B129B12AB12BB12DB12EB12FB130 B131B132B133B136B13AB13BB13CB13DB13EB13FB142B143B145B146B147B149 B14AB14BB14CB14DB14EB14FB152B153B156B157B159B15AB15BB15DB15EB15F B161B162B163B164B165B166B167B168B169B16AB16BB16CB16DB16EB16FB170 B171B172B173B174B175B176B177B17AB17BB17DB17EB17FB181B183B184B185 B186B187B18AB18CB18EB18FB190B191B195B196B197B199B19AB19BB19D0000 87 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000B19EB19FB1A0B1A1B1A2B1A3B1A4B1A5B1A6B1A7B1A9B1AAB1ABB1ACB1AD B1AEB1AFB1B0B1B1B1B2B1B3B1B4B1B5B1B6B1B7B1B800000000000000000000 0000B1B9B1BAB1BBB1BCB1BDB1BEB1BFB1C0B1C1B1C2B1C3B1C4B1C5B1C6B1C7 B1C8B1C9B1CAB1CBB1CDB1CEB1CFB1D1B1D2B1D3B1D500000000000000000000 0000B1D6B1D7B1D8B1D9B1DAB1DBB1DEB1E0B1E1B1E2B1E3B1E4B1E5B1E6B1E7 B1EAB1EBB1EDB1EEB1EFB1F1B1F2B1F3B1F4B1F5B1F6B1F7B1F8B1FAB1FCB1FE B1FFB200B201B202B203B206B207B209B20AB20DB20EB20FB210B211B212B213 B216B218B21AB21BB21CB21DB21EB21FB221B222B223B224B225B226B227B228 B229B22AB22BB22CB22DB22EB22FB230B231B232B233B235B236B237B238B239 B23AB23BB23DB23EB23FB240B241B242B243B244B245B246B247B248B249B24A B24BB24CB24DB24EB24FB250B251B252B253B254B255B256B257B259B25AB25B B25DB25EB25FB261B262B263B264B265B266B267B26AB26BB26CB26DB26E0000 88 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000B26FB270B271B272B273B276B277B278B279B27AB27BB27DB27EB27FB280 B281B282B283B286B287B288B28AB28BB28CB28DB28E00000000000000000000 0000B28FB292B293B295B296B297B29BB29CB29DB29EB29FB2A2B2A4B2A7B2A8 B2A9B2ABB2ADB2AEB2AFB2B1B2B2B2B3B2B5B2B6B2B700000000000000000000 0000B2B8B2B9B2BAB2BBB2BCB2BDB2BEB2BFB2C0B2C1B2C2B2C3B2C4B2C5B2C6 B2C7B2CAB2CBB2CDB2CEB2CFB2D1B2D3B2D4B2D5B2D6B2D7B2DAB2DCB2DEB2DF B2E0B2E1B2E3B2E7B2E9B2EAB2F0B2F1B2F2B2F6B2FCB2FDB2FEB302B303B305 B306B307B309B30AB30BB30CB30DB30EB30FB312B316B317B318B319B31AB31B B31DB31EB31FB320B321B322B323B324B325B326B327B328B329B32AB32BB32C B32DB32EB32FB330B331B332B333B334B335B336B337B338B339B33AB33BB33C B33DB33EB33FB340B341B342B343B344B345B346B347B348B349B34AB34BB34C B34DB34EB34FB350B351B352B353B357B359B35AB35DB360B361B362B3630000 89 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000B366B368B36AB36CB36DB36FB372B373B375B376B377B379B37AB37BB37C B37DB37EB37FB382B386B387B388B389B38AB38BB38D00000000000000000000 0000B38EB38FB391B392B393B395B396B397B398B399B39AB39BB39CB39DB39E B39FB3A2B3A3B3A4B3A5B3A6B3A7B3A9B3AAB3ABB3AD00000000000000000000 0000B3AEB3AFB3B0B3B1B3B2B3B3B3B4B3B5B3B6B3B7B3B8B3B9B3BAB3BBB3BC B3BDB3BEB3BFB3C0B3C1B3C2B3C3B3C6B3C7B3C9B3CAB3CDB3CFB3D1B3D2B3D3 B3D6B3D8B3DAB3DCB3DEB3DFB3E1B3E2B3E3B3E5B3E6B3E7B3E9B3EAB3EBB3EC B3EDB3EEB3EFB3F0B3F1B3F2B3F3B3F4B3F5B3F6B3F7B3F8B3F9B3FAB3FBB3FD B3FEB3FFB400B401B402B403B404B405B406B407B408B409B40AB40BB40CB40D B40EB40FB411B412B413B414B415B416B417B419B41AB41BB41DB41EB41FB421 B422B423B424B425B426B427B42AB42CB42DB42EB42FB430B431B432B433B435 B436B437B438B439B43AB43BB43CB43DB43EB43FB440B441B442B443B4440000 8A 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000B445B446B447B448B449B44AB44BB44CB44DB44EB44FB452B453B455B456 B457B459B45AB45BB45CB45DB45EB45FB462B464B46600000000000000000000 0000B467B468B469B46AB46BB46DB46EB46FB470B471B472B473B474B475B476 B477B478B479B47AB47BB47CB47DB47EB47FB481B48200000000000000000000 0000B483B484B485B486B487B489B48AB48BB48CB48DB48EB48FB490B491B492 B493B494B495B496B497B498B499B49AB49BB49CB49EB49FB4A0B4A1B4A2B4A3 B4A5B4A6B4A7B4A9B4AAB4ABB4ADB4AEB4AFB4B0B4B1B4B2B4B3B4B4B4B6B4B8 B4BAB4BBB4BCB4BDB4BEB4BFB4C1B4C2B4C3B4C5B4C6B4C7B4C9B4CAB4CBB4CC B4CDB4CEB4CFB4D1B4D2B4D3B4D4B4D6B4D7B4D8B4D9B4DAB4DBB4DEB4DFB4E1 B4E2B4E5B4E7B4E8B4E9B4EAB4EBB4EEB4F0B4F2B4F3B4F4B4F5B4F6B4F7B4F9 B4FAB4FBB4FCB4FDB4FEB4FFB500B501B502B503B504B505B506B507B508B509 B50AB50BB50CB50DB50EB50FB510B511B512B513B516B517B519B51AB51D0000 8B 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000B51EB51FB520B521B522B523B526B52BB52CB52DB52EB52FB532B533B535 B536B537B539B53AB53BB53CB53DB53EB53FB542B54600000000000000000000 0000B547B548B549B54AB54EB54FB551B552B553B555B556B557B558B559B55A B55BB55EB562B563B564B565B566B567B568B569B56A00000000000000000000 0000B56BB56CB56DB56EB56FB570B571B572B573B574B575B576B577B578B579 B57AB57BB57CB57DB57EB57FB580B581B582B583B584B585B586B587B588B589 B58AB58BB58CB58DB58EB58FB590B591B592B593B594B595B596B597B598B599 B59AB59BB59CB59DB59EB59FB5A2B5A3B5A5B5A6B5A7B5A9B5ACB5ADB5AEB5AF B5B2B5B6B5B7B5B8B5B9B5BAB5BEB5BFB5C1B5C2B5C3B5C5B5C6B5C7B5C8B5C9 B5CAB5CBB5CEB5D2B5D3B5D4B5D5B5D6B5D7B5D9B5DAB5DBB5DCB5DDB5DEB5DF B5E0B5E1B5E2B5E3B5E4B5E5B5E6B5E7B5E8B5E9B5EAB5EBB5EDB5EEB5EFB5F0 B5F1B5F2B5F3B5F4B5F5B5F6B5F7B5F8B5F9B5FAB5FBB5FCB5FDB5FEB5FF0000 8C 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000B600B601B602B603B604B605B606B607B608B609B60AB60BB60CB60DB60E B60FB612B613B615B616B617B619B61AB61BB61CB61D00000000000000000000 0000B61EB61FB620B621B622B623B624B626B627B628B629B62AB62BB62DB62E B62FB630B631B632B633B635B636B637B638B639B63A00000000000000000000 0000B63BB63CB63DB63EB63FB640B641B642B643B644B645B646B647B649B64A B64BB64CB64DB64EB64FB650B651B652B653B654B655B656B657B658B659B65A B65BB65CB65DB65EB65FB660B661B662B663B665B666B667B669B66AB66BB66C B66DB66EB66FB670B671B672B673B674B675B676B677B678B679B67AB67BB67C B67DB67EB67FB680B681B682B683B684B685B686B687B688B689B68AB68BB68C B68DB68EB68FB690B691B692B693B694B695B696B697B698B699B69AB69BB69E B69FB6A1B6A2B6A3B6A5B6A6B6A7B6A8B6A9B6AAB6ADB6AEB6AFB6B0B6B2B6B3 B6B4B6B5B6B6B6B7B6B8B6B9B6BAB6BBB6BCB6BDB6BEB6BFB6C0B6C1B6C20000 8D 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000B6C3B6C4B6C5B6C6B6C7B6C8B6C9B6CAB6CBB6CCB6CDB6CEB6CFB6D0B6D1 B6D2B6D3B6D5B6D6B6D7B6D8B6D9B6DAB6DBB6DCB6DD00000000000000000000 0000B6DEB6DFB6E0B6E1B6E2B6E3B6E4B6E5B6E6B6E7B6E8B6E9B6EAB6EBB6EC B6EDB6EEB6EFB6F1B6F2B6F3B6F5B6F6B6F7B6F9B6FA00000000000000000000 0000B6FBB6FCB6FDB6FEB6FFB702B703B704B706B707B708B709B70AB70BB70C B70DB70EB70FB710B711B712B713B714B715B716B717B718B719B71AB71BB71C B71DB71EB71FB720B721B722B723B724B725B726B727B72AB72BB72DB72EB731 B732B733B734B735B736B737B73AB73CB73DB73EB73FB740B741B742B743B745 B746B747B749B74AB74BB74DB74EB74FB750B751B752B753B756B757B758B759 B75AB75BB75CB75DB75EB75FB761B762B763B765B766B767B769B76AB76BB76C B76DB76EB76FB772B774B776B777B778B779B77AB77BB77EB77FB781B782B783 B785B786B787B788B789B78AB78BB78EB793B794B795B79AB79BB79DB79E0000 8E 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000B79FB7A1B7A2B7A3B7A4B7A5B7A6B7A7B7AAB7AEB7AFB7B0B7B1B7B2B7B3 B7B6B7B7B7B9B7BAB7BBB7BCB7BDB7BEB7BFB7C0B7C100000000000000000000 0000B7C2B7C3B7C4B7C5B7C6B7C8B7CAB7CBB7CCB7CDB7CEB7CFB7D0B7D1B7D2 B7D3B7D4B7D5B7D6B7D7B7D8B7D9B7DAB7DBB7DCB7DD00000000000000000000 0000B7DEB7DFB7E0B7E1B7E2B7E3B7E4B7E5B7E6B7E7B7E8B7E9B7EAB7EBB7EE B7EFB7F1B7F2B7F3B7F5B7F6B7F7B7F8B7F9B7FAB7FBB7FEB802B803B804B805 B806B80AB80BB80DB80EB80FB811B812B813B814B815B816B817B81AB81CB81E B81FB820B821B822B823B826B827B829B82AB82BB82DB82EB82FB830B831B832 B833B836B83AB83BB83CB83DB83EB83FB841B842B843B845B846B847B848B849 B84AB84BB84CB84DB84EB84FB850B852B854B855B856B857B858B859B85AB85B B85EB85FB861B862B863B865B866B867B868B869B86AB86BB86EB870B872B873 B874B875B876B877B879B87AB87BB87DB87EB87FB880B881B882B883B8840000 8F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000B885B886B887B888B889B88AB88BB88CB88EB88FB890B891B892B893B894 B895B896B897B898B899B89AB89BB89CB89DB89EB89F00000000000000000000 0000B8A0B8A1B8A2B8A3B8A4B8A5B8A6B8A7B8A9B8AAB8ABB8ACB8ADB8AEB8AF B8B1B8B2B8B3B8B5B8B6B8B7B8B9B8BAB8BBB8BCB8BD00000000000000000000 0000B8BEB8BFB8C2B8C4B8C6B8C7B8C8B8C9B8CAB8CBB8CDB8CEB8CFB8D1B8D2 B8D3B8D5B8D6B8D7B8D8B8D9B8DAB8DBB8DCB8DEB8E0B8E2B8E3B8E4B8E5B8E6 B8E7B8EAB8EBB8EDB8EEB8EFB8F1B8F2B8F3B8F4B8F5B8F6B8F7B8FAB8FCB8FE B8FFB900B901B902B903B905B906B907B908B909B90AB90BB90CB90DB90EB90F B910B911B912B913B914B915B916B917B919B91AB91BB91CB91DB91EB91FB921 B922B923B924B925B926B927B928B929B92AB92BB92CB92DB92EB92FB930B931 B932B933B934B935B936B937B938B939B93AB93BB93EB93FB941B942B943B945 B946B947B948B949B94AB94BB94DB94EB950B952B953B954B955B956B9570000 90 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000B95AB95BB95DB95EB95FB961B962B963B964B965B966B967B96AB96CB96E B96FB970B971B972B973B976B977B979B97AB97BB97D00000000000000000000 0000B97EB97FB980B981B982B983B986B988B98BB98CB98FB990B991B992B993 B994B995B996B997B998B999B99AB99BB99CB99DB99E00000000000000000000 0000B99FB9A0B9A1B9A2B9A3B9A4B9A5B9A6B9A7B9A8B9A9B9AAB9ABB9AEB9AF B9B1B9B2B9B3B9B5B9B6B9B7B9B8B9B9B9BAB9BBB9BEB9C0B9C2B9C3B9C4B9C5 B9C6B9C7B9CAB9CBB9CDB9D3B9D4B9D5B9D6B9D7B9DAB9DCB9DFB9E0B9E2B9E6 B9E7B9E9B9EAB9EBB9EDB9EEB9EFB9F0B9F1B9F2B9F3B9F6B9FBB9FCB9FDB9FE B9FFBA02BA03BA04BA05BA06BA07BA09BA0ABA0BBA0CBA0DBA0EBA0FBA10BA11 BA12BA13BA14BA16BA17BA18BA19BA1ABA1BBA1CBA1DBA1EBA1FBA20BA21BA22 BA23BA24BA25BA26BA27BA28BA29BA2ABA2BBA2CBA2DBA2EBA2FBA30BA31BA32 BA33BA34BA35BA36BA37BA3ABA3BBA3DBA3EBA3FBA41BA43BA44BA45BA460000 91 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000BA47BA4ABA4CBA4FBA50BA51BA52BA56BA57BA59BA5ABA5BBA5DBA5EBA5F BA60BA61BA62BA63BA66BA6ABA6BBA6CBA6DBA6EBA6F00000000000000000000 0000BA72BA73BA75BA76BA77BA79BA7ABA7BBA7CBA7DBA7EBA7FBA80BA81BA82 BA86BA88BA89BA8ABA8BBA8DBA8EBA8FBA90BA91BA9200000000000000000000 0000BA93BA94BA95BA96BA97BA98BA99BA9ABA9BBA9CBA9DBA9EBA9FBAA0BAA1 BAA2BAA3BAA4BAA5BAA6BAA7BAAABAADBAAEBAAFBAB1BAB3BAB4BAB5BAB6BAB7 BABABABCBABEBABFBAC0BAC1BAC2BAC3BAC5BAC6BAC7BAC9BACABACBBACCBACD BACEBACFBAD0BAD1BAD2BAD3BAD4BAD5BAD6BAD7BADABADBBADCBADDBADEBADF BAE0BAE1BAE2BAE3BAE4BAE5BAE6BAE7BAE8BAE9BAEABAEBBAECBAEDBAEEBAEF BAF0BAF1BAF2BAF3BAF4BAF5BAF6BAF7BAF8BAF9BAFABAFBBAFDBAFEBAFFBB01 BB02BB03BB05BB06BB07BB08BB09BB0ABB0BBB0CBB0EBB10BB12BB13BB14BB15 BB16BB17BB19BB1ABB1BBB1DBB1EBB1FBB21BB22BB23BB24BB25BB26BB270000 92 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000BB28BB2ABB2CBB2DBB2EBB2FBB30BB31BB32BB33BB37BB39BB3ABB3FBB40 BB41BB42BB43BB46BB48BB4ABB4BBB4CBB4EBB51BB5200000000000000000000 0000BB53BB55BB56BB57BB59BB5ABB5BBB5CBB5DBB5EBB5FBB60BB62BB64BB65 BB66BB67BB68BB69BB6ABB6BBB6DBB6EBB6FBB70BB7100000000000000000000 0000BB72BB73BB74BB75BB76BB77BB78BB79BB7ABB7BBB7CBB7DBB7EBB7FBB80 BB81BB82BB83BB84BB85BB86BB87BB89BB8ABB8BBB8DBB8EBB8FBB91BB92BB93 BB94BB95BB96BB97BB98BB99BB9ABB9BBB9CBB9DBB9EBB9FBBA0BBA1BBA2BBA3 BBA5BBA6BBA7BBA9BBAABBABBBADBBAEBBAFBBB0BBB1BBB2BBB3BBB5BBB6BBB8 BBB9BBBABBBBBBBCBBBDBBBEBBBFBBC1BBC2BBC3BBC5BBC6BBC7BBC9BBCABBCB BBCCBBCDBBCEBBCFBBD1BBD2BBD4BBD5BBD6BBD7BBD8BBD9BBDABBDBBBDCBBDD BBDEBBDFBBE0BBE1BBE2BBE3BBE4BBE5BBE6BBE7BBE8BBE9BBEABBEBBBECBBED BBEEBBEFBBF0BBF1BBF2BBF3BBF4BBF5BBF6BBF7BBFABBFBBBFDBBFEBC010000 93 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000BC03BC04BC05BC06BC07BC0ABC0EBC10BC12BC13BC19BC1ABC20BC21BC22 BC23BC26BC28BC2ABC2BBC2CBC2EBC2FBC32BC33BC3500000000000000000000 0000BC36BC37BC39BC3ABC3BBC3CBC3DBC3EBC3FBC42BC46BC47BC48BC4ABC4B BC4EBC4FBC51BC52BC53BC54BC55BC56BC57BC58BC5900000000000000000000 0000BC5ABC5BBC5CBC5EBC5FBC60BC61BC62BC63BC64BC65BC66BC67BC68BC69 BC6ABC6BBC6CBC6DBC6EBC6FBC70BC71BC72BC73BC74BC75BC76BC77BC78BC79 BC7ABC7BBC7CBC7DBC7EBC7FBC80BC81BC82BC83BC86BC87BC89BC8ABC8DBC8F BC90BC91BC92BC93BC96BC98BC9BBC9CBC9DBC9EBC9FBCA2BCA3BCA5BCA6BCA9 BCAABCABBCACBCADBCAEBCAFBCB2BCB6BCB7BCB8BCB9BCBABCBBBCBEBCBFBCC1 BCC2BCC3BCC5BCC6BCC7BCC8BCC9BCCABCCBBCCCBCCEBCD2BCD3BCD4BCD6BCD7 BCD9BCDABCDBBCDDBCDEBCDFBCE0BCE1BCE2BCE3BCE4BCE5BCE6BCE7BCE8BCE9 BCEABCEBBCECBCEDBCEEBCEFBCF0BCF1BCF2BCF3BCF7BCF9BCFABCFBBCFD0000 94 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000BCFEBCFFBD00BD01BD02BD03BD06BD08BD0ABD0BBD0CBD0DBD0EBD0FBD11 BD12BD13BD15BD16BD17BD18BD19BD1ABD1BBD1CBD1D00000000000000000000 0000BD1EBD1FBD20BD21BD22BD23BD25BD26BD27BD28BD29BD2ABD2BBD2DBD2E BD2FBD30BD31BD32BD33BD34BD35BD36BD37BD38BD3900000000000000000000 0000BD3ABD3BBD3CBD3DBD3EBD3FBD41BD42BD43BD44BD45BD46BD47BD4ABD4B BD4DBD4EBD4FBD51BD52BD53BD54BD55BD56BD57BD5ABD5BBD5CBD5DBD5EBD5F BD60BD61BD62BD63BD65BD66BD67BD69BD6ABD6BBD6CBD6DBD6EBD6FBD70BD71 BD72BD73BD74BD75BD76BD77BD78BD79BD7ABD7BBD7CBD7DBD7EBD7FBD82BD83 BD85BD86BD8BBD8CBD8DBD8EBD8FBD92BD94BD96BD97BD98BD9BBD9DBD9EBD9F BDA0BDA1BDA2BDA3BDA5BDA6BDA7BDA8BDA9BDAABDABBDACBDADBDAEBDAFBDB1 BDB2BDB3BDB4BDB5BDB6BDB7BDB9BDBABDBBBDBCBDBDBDBEBDBFBDC0BDC1BDC2 BDC3BDC4BDC5BDC6BDC7BDC8BDC9BDCABDCBBDCCBDCDBDCEBDCFBDD0BDD10000 95 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000BDD2BDD3BDD6BDD7BDD9BDDABDDBBDDDBDDEBDDFBDE0BDE1BDE2BDE3BDE4 BDE5BDE6BDE7BDE8BDEABDEBBDECBDEDBDEEBDEFBDF100000000000000000000 0000BDF2BDF3BDF5BDF6BDF7BDF9BDFABDFBBDFCBDFDBDFEBDFFBE01BE02BE04 BE06BE07BE08BE09BE0ABE0BBE0EBE0FBE11BE12BE1300000000000000000000 0000BE15BE16BE17BE18BE19BE1ABE1BBE1EBE20BE21BE22BE23BE24BE25BE26 BE27BE28BE29BE2ABE2BBE2CBE2DBE2EBE2FBE30BE31BE32BE33BE34BE35BE36 BE37BE38BE39BE3ABE3BBE3CBE3DBE3EBE3FBE40BE41BE42BE43BE46BE47BE49 BE4ABE4BBE4DBE4FBE50BE51BE52BE53BE56BE58BE5CBE5DBE5EBE5FBE62BE63 BE65BE66BE67BE69BE6BBE6CBE6DBE6EBE6FBE72BE76BE77BE78BE79BE7ABE7E BE7FBE81BE82BE83BE85BE86BE87BE88BE89BE8ABE8BBE8EBE92BE93BE94BE95 BE96BE97BE9ABE9BBE9CBE9DBE9EBE9FBEA0BEA1BEA2BEA3BEA4BEA5BEA6BEA7 BEA9BEAABEABBEACBEADBEAEBEAFBEB0BEB1BEB2BEB3BEB4BEB5BEB6BEB70000 96 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000BEB8BEB9BEBABEBBBEBCBEBDBEBEBEBFBEC0BEC1BEC2BEC3BEC4BEC5BEC6 BEC7BEC8BEC9BECABECBBECCBECDBECEBECFBED2BED300000000000000000000 0000BED5BED6BED9BEDABEDBBEDCBEDDBEDEBEDFBEE1BEE2BEE6BEE7BEE8BEE9 BEEABEEBBEEDBEEEBEEFBEF0BEF1BEF2BEF3BEF4BEF500000000000000000000 0000BEF6BEF7BEF8BEF9BEFABEFBBEFCBEFDBEFEBEFFBF00BF02BF03BF04BF05 BF06BF07BF0ABF0BBF0CBF0DBF0EBF0FBF10BF11BF12BF13BF14BF15BF16BF17 BF1ABF1EBF1FBF20BF21BF22BF23BF24BF25BF26BF27BF28BF29BF2ABF2BBF2C BF2DBF2EBF2FBF30BF31BF32BF33BF34BF35BF36BF37BF38BF39BF3ABF3BBF3C BF3DBF3EBF3FBF42BF43BF45BF46BF47BF49BF4ABF4BBF4CBF4DBF4EBF4FBF52 BF53BF54BF56BF57BF58BF59BF5ABF5BBF5CBF5DBF5EBF5FBF60BF61BF62BF63 BF64BF65BF66BF67BF68BF69BF6ABF6BBF6CBF6DBF6EBF6FBF70BF71BF72BF73 BF74BF75BF76BF77BF78BF79BF7ABF7BBF7CBF7DBF7EBF7FBF80BF81BF820000 97 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000BF83BF84BF85BF86BF87BF88BF89BF8ABF8BBF8CBF8DBF8EBF8FBF90BF91 BF92BF93BF95BF96BF97BF98BF99BF9ABF9BBF9CBF9D00000000000000000000 0000BF9EBF9FBFA0BFA1BFA2BFA3BFA4BFA5BFA6BFA7BFA8BFA9BFAABFABBFAC BFADBFAEBFAFBFB1BFB2BFB3BFB4BFB5BFB6BFB7BFB800000000000000000000 0000BFB9BFBABFBBBFBCBFBDBFBEBFBFBFC0BFC1BFC2BFC3BFC4BFC6BFC7BFC8 BFC9BFCABFCBBFCEBFCFBFD1BFD2BFD3BFD5BFD6BFD7BFD8BFD9BFDABFDBBFDD BFDEBFE0BFE2BFE3BFE4BFE5BFE6BFE7BFE8BFE9BFEABFEBBFECBFEDBFEEBFEF BFF0BFF1BFF2BFF3BFF4BFF5BFF6BFF7BFF8BFF9BFFABFFBBFFCBFFDBFFEBFFF C000C001C002C003C004C005C006C007C008C009C00AC00BC00CC00DC00EC00F C010C011C012C013C014C015C016C017C018C019C01AC01BC01CC01DC01EC01F C020C021C022C023C024C025C026C027C028C029C02AC02BC02CC02DC02EC02F C030C031C032C033C034C035C036C037C038C039C03AC03BC03DC03EC03F0000 98 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000C040C041C042C043C044C045C046C047C048C049C04AC04BC04CC04DC04E C04FC050C052C053C054C055C056C057C059C05AC05B00000000000000000000 0000C05DC05EC05FC061C062C063C064C065C066C067C06AC06BC06CC06DC06E C06FC070C071C072C073C074C075C076C077C078C07900000000000000000000 0000C07AC07BC07CC07DC07EC07FC080C081C082C083C084C085C086C087C088 C089C08AC08BC08CC08DC08EC08FC092C093C095C096C097C099C09AC09BC09C C09DC09EC09FC0A2C0A4C0A6C0A7C0A8C0A9C0AAC0ABC0AEC0B1C0B2C0B7C0B8 C0B9C0BAC0BBC0BEC0C2C0C3C0C4C0C6C0C7C0CAC0CBC0CDC0CEC0CFC0D1C0D2 C0D3C0D4C0D5C0D6C0D7C0DAC0DEC0DFC0E0C0E1C0E2C0E3C0E6C0E7C0E9C0EA C0EBC0EDC0EEC0EFC0F0C0F1C0F2C0F3C0F6C0F8C0FAC0FBC0FCC0FDC0FEC0FF C101C102C103C105C106C107C109C10AC10BC10CC10DC10EC10FC111C112C113 C114C116C117C118C119C11AC11BC121C122C125C128C129C12AC12BC12E0000 99 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000C132C133C134C135C137C13AC13BC13DC13EC13FC141C142C143C144C145 C146C147C14AC14EC14FC150C151C152C153C156C15700000000000000000000 0000C159C15AC15BC15DC15EC15FC160C161C162C163C166C16AC16BC16CC16D C16EC16FC171C172C173C175C176C177C179C17AC17B00000000000000000000 0000C17CC17DC17EC17FC180C181C182C183C184C186C187C188C189C18AC18B C18FC191C192C193C195C197C198C199C19AC19BC19EC1A0C1A2C1A3C1A4C1A6 C1A7C1AAC1ABC1ADC1AEC1AFC1B1C1B2C1B3C1B4C1B5C1B6C1B7C1B8C1B9C1BA C1BBC1BCC1BEC1BFC1C0C1C1C1C2C1C3C1C5C1C6C1C7C1C9C1CAC1CBC1CDC1CE C1CFC1D0C1D1C1D2C1D3C1D5C1D6C1D9C1DAC1DBC1DCC1DDC1DEC1DFC1E1C1E2 C1E3C1E5C1E6C1E7C1E9C1EAC1EBC1ECC1EDC1EEC1EFC1F2C1F4C1F5C1F6C1F7 C1F8C1F9C1FAC1FBC1FEC1FFC201C202C203C205C206C207C208C209C20AC20B C20EC210C212C213C214C215C216C217C21AC21BC21DC21EC221C222C2230000 9A 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000C224C225C226C227C22AC22CC22EC230C233C235C236C237C238C239C23A C23BC23CC23DC23EC23FC240C241C242C243C244C24500000000000000000000 0000C246C247C249C24AC24BC24CC24DC24EC24FC252C253C255C256C257C259 C25AC25BC25CC25DC25EC25FC261C262C263C264C26600000000000000000000 0000C267C268C269C26AC26BC26EC26FC271C272C273C275C276C277C278C279 C27AC27BC27EC280C282C283C284C285C286C287C28AC28BC28CC28DC28EC28F C291C292C293C294C295C296C297C299C29AC29CC29EC29FC2A0C2A1C2A2C2A3 C2A6C2A7C2A9C2AAC2ABC2AEC2AFC2B0C2B1C2B2C2B3C2B6C2B8C2BAC2BBC2BC C2BDC2BEC2BFC2C0C2C1C2C2C2C3C2C4C2C5C2C6C2C7C2C8C2C9C2CAC2CBC2CC C2CDC2CEC2CFC2D0C2D1C2D2C2D3C2D4C2D5C2D6C2D7C2D8C2D9C2DAC2DBC2DE C2DFC2E1C2E2C2E5C2E6C2E7C2E8C2E9C2EAC2EEC2F0C2F2C2F3C2F4C2F5C2F7 C2FAC2FDC2FEC2FFC301C302C303C304C305C306C307C30AC30BC30EC30F0000 9B 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000C310C311C312C316C317C319C31AC31BC31DC31EC31FC320C321C322C323 C326C327C32AC32BC32CC32DC32EC32FC330C331C33200000000000000000000 0000C333C334C335C336C337C338C339C33AC33BC33CC33DC33EC33FC340C341 C342C343C344C346C347C348C349C34AC34BC34CC34D00000000000000000000 0000C34EC34FC350C351C352C353C354C355C356C357C358C359C35AC35BC35C C35DC35EC35FC360C361C362C363C364C365C366C367C36AC36BC36DC36EC36F C371C373C374C375C376C377C37AC37BC37EC37FC380C381C382C383C385C386 C387C389C38AC38BC38DC38EC38FC390C391C392C393C394C395C396C397C398 C399C39AC39BC39CC39DC39EC39FC3A0C3A1C3A2C3A3C3A4C3A5C3A6C3A7C3A8 C3A9C3AAC3ABC3ACC3ADC3AEC3AFC3B0C3B1C3B2C3B3C3B4C3B5C3B6C3B7C3B8 C3B9C3BAC3BBC3BCC3BDC3BEC3BFC3C1C3C2C3C3C3C4C3C5C3C6C3C7C3C8C3C9 C3CAC3CBC3CCC3CDC3CEC3CFC3D0C3D1C3D2C3D3C3D4C3D5C3D6C3D7C3DA0000 9C 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000C3DBC3DDC3DEC3E1C3E3C3E4C3E5C3E6C3E7C3EAC3EBC3ECC3EEC3EFC3F0 C3F1C3F2C3F3C3F6C3F7C3F9C3FAC3FBC3FCC3FDC3FE00000000000000000000 0000C3FFC400C401C402C403C404C405C406C407C409C40AC40BC40CC40DC40E C40FC411C412C413C414C415C416C417C418C419C41A00000000000000000000 0000C41BC41CC41DC41EC41FC420C421C422C423C425C426C427C428C429C42A C42BC42DC42EC42FC431C432C433C435C436C437C438C439C43AC43BC43EC43F C440C441C442C443C444C445C446C447C449C44AC44BC44CC44DC44EC44FC450 C451C452C453C454C455C456C457C458C459C45AC45BC45CC45DC45EC45FC460 C461C462C463C466C467C469C46AC46BC46DC46EC46FC470C471C472C473C476 C477C478C47AC47BC47CC47DC47EC47FC481C482C483C484C485C486C487C488 C489C48AC48BC48CC48DC48EC48FC490C491C492C493C495C496C497C498C499 C49AC49BC49DC49EC49FC4A0C4A1C4A2C4A3C4A4C4A5C4A6C4A7C4A8C4A90000 9D 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000C4AAC4ABC4ACC4ADC4AEC4AFC4B0C4B1C4B2C4B3C4B4C4B5C4B6C4B7C4B9 C4BAC4BBC4BDC4BEC4BFC4C0C4C1C4C2C4C3C4C4C4C500000000000000000000 0000C4C6C4C7C4C8C4C9C4CAC4CBC4CCC4CDC4CEC4CFC4D0C4D1C4D2C4D3C4D4 C4D5C4D6C4D7C4D8C4D9C4DAC4DBC4DCC4DDC4DEC4DF00000000000000000000 0000C4E0C4E1C4E2C4E3C4E4C4E5C4E6C4E7C4E8C4EAC4EBC4ECC4EDC4EEC4EF C4F2C4F3C4F5C4F6C4F7C4F9C4FBC4FCC4FDC4FEC502C503C504C505C506C507 C508C509C50AC50BC50DC50EC50FC511C512C513C515C516C517C518C519C51A C51BC51DC51EC51FC520C521C522C523C524C525C526C527C52AC52BC52DC52E C52FC531C532C533C534C535C536C537C53AC53CC53EC53FC540C541C542C543 C546C547C54BC54FC550C551C552C556C55AC55BC55CC55FC562C563C565C566 C567C569C56AC56BC56CC56DC56EC56FC572C576C577C578C579C57AC57BC57E C57FC581C582C583C585C586C588C589C58AC58BC58EC590C592C593C5940000 9E 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000C596C599C59AC59BC59DC59EC59FC5A1C5A2C5A3C5A4C5A5C5A6C5A7C5A8 C5AAC5ABC5ACC5ADC5AEC5AFC5B0C5B1C5B2C5B3C5B600000000000000000000 0000C5B7C5BAC5BFC5C0C5C1C5C2C5C3C5CBC5CDC5CFC5D2C5D3C5D5C5D6C5D7 C5D9C5DAC5DBC5DCC5DDC5DEC5DFC5E2C5E4C5E6C5E700000000000000000000 0000C5E8C5E9C5EAC5EBC5EFC5F1C5F2C5F3C5F5C5F8C5F9C5FAC5FBC602C603 C604C609C60AC60BC60DC60EC60FC611C612C613C614C615C616C617C61AC61D C61EC61FC620C621C622C623C626C627C629C62AC62BC62FC631C632C636C638 C63AC63CC63DC63EC63FC642C643C645C646C647C649C64AC64BC64CC64DC64E C64FC652C656C657C658C659C65AC65BC65EC65FC661C662C663C664C665C666 C667C668C669C66AC66BC66DC66EC670C672C673C674C675C676C677C67AC67B C67DC67EC67FC681C682C683C684C685C686C687C68AC68CC68EC68FC690C691 C692C693C696C697C699C69AC69BC69DC69EC69FC6A0C6A1C6A2C6A3C6A60000 9F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000C6A8C6AAC6ABC6ACC6ADC6AEC6AFC6B2C6B3C6B5C6B6C6B7C6BBC6BCC6BD C6BEC6BFC6C2C6C4C6C6C6C7C6C8C6C9C6CAC6CBC6CE00000000000000000000 0000C6CFC6D1C6D2C6D3C6D5C6D6C6D7C6D8C6D9C6DAC6DBC6DEC6DFC6E2C6E3 C6E4C6E5C6E6C6E7C6EAC6EBC6EDC6EEC6EFC6F1C6F200000000000000000000 0000C6F3C6F4C6F5C6F6C6F7C6FAC6FBC6FCC6FEC6FFC700C701C702C703C706 C707C709C70AC70BC70DC70EC70FC710C711C712C713C716C718C71AC71BC71C C71DC71EC71FC722C723C725C726C727C729C72AC72BC72CC72DC72EC72FC732 C734C736C738C739C73AC73BC73EC73FC741C742C743C745C746C747C748C749 C74BC74EC750C759C75AC75BC75DC75EC75FC761C762C763C764C765C766C767 C769C76AC76CC76DC76EC76FC770C771C772C773C776C777C779C77AC77BC77F C780C781C782C786C78BC78CC78DC78FC792C793C795C799C79BC79CC79DC79E C79FC7A2C7A7C7A8C7A9C7AAC7ABC7AEC7AFC7B1C7B2C7B3C7B5C7B6C7B70000 A0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000C7B8C7B9C7BAC7BBC7BEC7C2C7C3C7C4C7C5C7C6C7C7C7CAC7CBC7CDC7CF C7D1C7D2C7D3C7D4C7D5C7D6C7D7C7D9C7DAC7DBC7DC00000000000000000000 0000C7DEC7DFC7E0C7E1C7E2C7E3C7E5C7E6C7E7C7E9C7EAC7EBC7EDC7EEC7EF C7F0C7F1C7F2C7F3C7F4C7F5C7F6C7F7C7F8C7F9C7FA00000000000000000000 0000C7FBC7FCC7FDC7FEC7FFC802C803C805C806C807C809C80BC80CC80DC80E C80FC812C814C817C818C819C81AC81BC81EC81FC821C822C823C825C826C827 C828C829C82AC82BC82EC830C832C833C834C835C836C837C839C83AC83BC83D C83EC83FC841C842C843C844C845C846C847C84AC84BC84EC84FC850C851C852 C853C855C856C857C858C859C85AC85BC85CC85DC85EC85FC860C861C862C863 C864C865C866C867C868C869C86AC86BC86CC86DC86EC86FC872C873C875C876 C877C879C87BC87CC87DC87EC87FC882C884C888C889C88AC88EC88FC890C891 C892C893C895C896C897C898C899C89AC89BC89CC89EC8A0C8A2C8A3C8A40000 A1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000C8A5C8A6C8A7C8A9C8AAC8ABC8ACC8ADC8AEC8AFC8B0C8B1C8B2C8B3C8B4 C8B5C8B6C8B7C8B8C8B9C8BAC8BBC8BEC8BFC8C0C8C100000000000000000000 0000C8C2C8C3C8C5C8C6C8C7C8C9C8CAC8CBC8CDC8CEC8CFC8D0C8D1C8D2C8D3 C8D6C8D8C8DAC8DBC8DCC8DDC8DEC8DFC8E2C8E3C8E500000000000000000000 0000C8E6C8E7C8E8C8E9C8EAC8EBC8ECC8EDC8EEC8EFC8F0C8F1C8F2C8F3C8F4 C8F6C8F7C8F8C8F9C8FAC8FBC8FEC8FFC901C902C903C907C908C909C90AC90B C90E30003001300200B72025202600A8300300AD20152225FF3C223C20182019 201C201D3014301530083009300A300B300C300D300E300F3010301100B100D7 00F7226022642265221E223400B0203220332103212BFFE0FFE1FFE526422640 222022A52312220222072261225200A7203B2606260525CB25CF25CE25C725C6 25A125A025B325B225BD25BC219221902191219321943013226A226B221A223D 221D2235222B222C2208220B2286228722822283222A222922272228FFE20000 A2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000C910C912C913C914C915C916C917C919C91AC91BC91CC91DC91EC91FC920 C921C922C923C924C925C926C927C928C929C92AC92B00000000000000000000 0000C92DC92EC92FC930C931C932C933C935C936C937C938C939C93AC93BC93C C93DC93EC93FC940C941C942C943C944C945C946C94700000000000000000000 0000C948C949C94AC94BC94CC94DC94EC94FC952C953C955C956C957C959C95A C95BC95CC95DC95EC95FC962C964C965C966C967C968C969C96AC96BC96DC96E C96F21D221D42200220300B4FF5E02C702D802DD02DA02D900B802DB00A100BF 02D0222E2211220F00A42109203025C125C025B725B626642660266126652667 2663229925C825A325D025D1259225A425A525A825A725A625A92668260F260E 261C261E00B62020202121952197219921962198266D2669266A266C327F321C 211633C7212233C233D8212120AC00AE00000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 A3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000C971C972C973C975C976C977C978C979C97AC97BC97DC97EC97FC980C981 C982C983C984C985C986C987C98AC98BC98DC98EC98F00000000000000000000 0000C991C992C993C994C995C996C997C99AC99CC99EC99FC9A0C9A1C9A2C9A3 C9A4C9A5C9A6C9A7C9A8C9A9C9AAC9ABC9ACC9ADC9AE00000000000000000000 0000C9AFC9B0C9B1C9B2C9B3C9B4C9B5C9B6C9B7C9B8C9B9C9BAC9BBC9BCC9BD C9BEC9BFC9C2C9C3C9C5C9C6C9C9C9CBC9CCC9CDC9CEC9CFC9D2C9D4C9D7C9D8 C9DBFF01FF02FF03FF04FF05FF06FF07FF08FF09FF0AFF0BFF0CFF0DFF0EFF0F FF10FF11FF12FF13FF14FF15FF16FF17FF18FF19FF1AFF1BFF1CFF1DFF1EFF1F FF20FF21FF22FF23FF24FF25FF26FF27FF28FF29FF2AFF2BFF2CFF2DFF2EFF2F FF30FF31FF32FF33FF34FF35FF36FF37FF38FF39FF3AFF3BFFE6FF3DFF3EFF3F FF40FF41FF42FF43FF44FF45FF46FF47FF48FF49FF4AFF4BFF4CFF4DFF4EFF4F FF50FF51FF52FF53FF54FF55FF56FF57FF58FF59FF5AFF5BFF5CFF5DFFE30000 A4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000C9DEC9DFC9E1C9E3C9E5C9E6C9E8C9E9C9EAC9EBC9EEC9F2C9F3C9F4C9F5 C9F6C9F7C9FAC9FBC9FDC9FEC9FFCA01CA02CA03CA0400000000000000000000 0000CA05CA06CA07CA0ACA0ECA0FCA10CA11CA12CA13CA15CA16CA17CA19CA1A CA1BCA1CCA1DCA1ECA1FCA20CA21CA22CA23CA24CA2500000000000000000000 0000CA26CA27CA28CA2ACA2BCA2CCA2DCA2ECA2FCA30CA31CA32CA33CA34CA35 CA36CA37CA38CA39CA3ACA3BCA3CCA3DCA3ECA3FCA40CA41CA42CA43CA44CA45 CA46313131323133313431353136313731383139313A313B313C313D313E313F 3140314131423143314431453146314731483149314A314B314C314D314E314F 3150315131523153315431553156315731583159315A315B315C315D315E315F 3160316131623163316431653166316731683169316A316B316C316D316E316F 3170317131723173317431753176317731783179317A317B317C317D317E317F 3180318131823183318431853186318731883189318A318B318C318D318E0000 A5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000CA47CA48CA49CA4ACA4BCA4ECA4FCA51CA52CA53CA55CA56CA57CA58CA59 CA5ACA5BCA5ECA62CA63CA64CA65CA66CA67CA69CA6A00000000000000000000 0000CA6BCA6CCA6DCA6ECA6FCA70CA71CA72CA73CA74CA75CA76CA77CA78CA79 CA7ACA7BCA7CCA7ECA7FCA80CA81CA82CA83CA85CA8600000000000000000000 0000CA87CA88CA89CA8ACA8BCA8CCA8DCA8ECA8FCA90CA91CA92CA93CA94CA95 CA96CA97CA99CA9ACA9BCA9CCA9DCA9ECA9FCAA0CAA1CAA2CAA3CAA4CAA5CAA6 CAA7217021712172217321742175217621772178217900000000000000000000 2160216121622163216421652166216721682169000000000000000000000000 0000039103920393039403950396039703980399039A039B039C039D039E039F 03A003A103A303A403A503A603A703A803A90000000000000000000000000000 000003B103B203B303B403B503B603B703B803B903BA03BB03BC03BD03BE03BF 03C003C103C303C403C503C603C703C803C90000000000000000000000000000 A6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000CAA8CAA9CAAACAABCAACCAADCAAECAAFCAB0CAB1CAB2CAB3CAB4CAB5CAB6 CAB7CAB8CAB9CABACABBCABECABFCAC1CAC2CAC3CAC500000000000000000000 0000CAC6CAC7CAC8CAC9CACACACBCACECAD0CAD2CAD4CAD5CAD6CAD7CADACADB CADCCADDCADECADFCAE1CAE2CAE3CAE4CAE5CAE6CAE700000000000000000000 0000CAE8CAE9CAEACAEBCAEDCAEECAEFCAF0CAF1CAF2CAF3CAF5CAF6CAF7CAF8 CAF9CAFACAFBCAFCCAFDCAFECAFFCB00CB01CB02CB03CB04CB05CB06CB07CB09 CB0A25002502250C251025182514251C252C25242534253C25012503250F2513 251B251725232533252B253B254B2520252F25282537253F251D253025252538 254225122511251A251925162515250E250D251E251F25212522252625272529 252A252D252E25312532253525362539253A253D253E25402541254325442545 2546254725482549254A00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 A7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000CB0BCB0CCB0DCB0ECB0FCB11CB12CB13CB15CB16CB17CB19CB1ACB1BCB1C CB1DCB1ECB1FCB22CB23CB24CB25CB26CB27CB28CB2900000000000000000000 0000CB2ACB2BCB2CCB2DCB2ECB2FCB30CB31CB32CB33CB34CB35CB36CB37CB38 CB39CB3ACB3BCB3CCB3DCB3ECB3FCB40CB42CB43CB4400000000000000000000 0000CB45CB46CB47CB4ACB4BCB4DCB4ECB4FCB51CB52CB53CB54CB55CB56CB57 CB5ACB5BCB5CCB5ECB5FCB60CB61CB62CB63CB65CB66CB67CB68CB69CB6ACB6B CB6C3395339633972113339833C433A333A433A533A63399339A339B339C339D 339E339F33A033A133A233CA338D338E338F33CF3388338933C833A733A833B0 33B133B233B333B433B533B633B733B833B93380338133823383338433BA33BB 33BC33BD33BE33BF33903391339233933394212633C033C1338A338B338C33D6 33C533AD33AE33AF33DB33A933AA33AB33AC33DD33D033D333C333C933DC33C6 0000000000000000000000000000000000000000000000000000000000000000 A8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000CB6DCB6ECB6FCB70CB71CB72CB73CB74CB75CB76CB77CB7ACB7BCB7CCB7D CB7ECB7FCB80CB81CB82CB83CB84CB85CB86CB87CB8800000000000000000000 0000CB89CB8ACB8BCB8CCB8DCB8ECB8FCB90CB91CB92CB93CB94CB95CB96CB97 CB98CB99CB9ACB9BCB9DCB9ECB9FCBA0CBA1CBA2CBA300000000000000000000 0000CBA4CBA5CBA6CBA7CBA8CBA9CBAACBABCBACCBADCBAECBAFCBB0CBB1CBB2 CBB3CBB4CBB5CBB6CBB7CBB9CBBACBBBCBBCCBBDCBBECBBFCBC0CBC1CBC2CBC3 CBC400C600D000AA0126000001320000013F014100D8015200BA00DE0166014A 00003260326132623263326432653266326732683269326A326B326C326D326E 326F3270327132723273327432753276327732783279327A327B24D024D124D2 24D324D424D524D624D724D824D924DA24DB24DC24DD24DE24DF24E024E124E2 24E324E424E524E624E724E824E9246024612462246324642465246624672468 2469246A246B246C246D246E00BD2153215400BC00BE215B215C215D215E0000 A9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000CBC5CBC6CBC7CBC8CBC9CBCACBCBCBCCCBCDCBCECBCFCBD0CBD1CBD2CBD3 CBD5CBD6CBD7CBD8CBD9CBDACBDBCBDCCBDDCBDECBDF00000000000000000000 0000CBE0CBE1CBE2CBE3CBE5CBE6CBE8CBEACBEBCBECCBEDCBEECBEFCBF0CBF1 CBF2CBF3CBF4CBF5CBF6CBF7CBF8CBF9CBFACBFBCBFC00000000000000000000 0000CBFDCBFECBFFCC00CC01CC02CC03CC04CC05CC06CC07CC08CC09CC0ACC0B CC0ECC0FCC11CC12CC13CC15CC16CC17CC18CC19CC1ACC1BCC1ECC1FCC20CC23 CC2400E6011100F001270131013301380140014200F8015300DF00FE0167014B 01493200320132023203320432053206320732083209320A320B320C320D320E 320F3210321132123213321432153216321732183219321A321B249C249D249E 249F24A024A124A224A324A424A524A624A724A824A924AA24AB24AC24AD24AE 24AF24B024B124B224B324B424B5247424752476247724782479247A247B247C 247D247E247F24802481248200B900B200B32074207F20812082208320840000 AA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000CC25CC26CC2ACC2BCC2DCC2FCC31CC32CC33CC34CC35CC36CC37CC3ACC3F CC40CC41CC42CC43CC46CC47CC49CC4ACC4BCC4DCC4E00000000000000000000 0000CC4FCC50CC51CC52CC53CC56CC5ACC5BCC5CCC5DCC5ECC5FCC61CC62CC63 CC65CC67CC69CC6ACC6BCC6CCC6DCC6ECC6FCC71CC7200000000000000000000 0000CC73CC74CC76CC77CC78CC79CC7ACC7BCC7CCC7DCC7ECC7FCC80CC81CC82 CC83CC84CC85CC86CC87CC88CC89CC8ACC8BCC8CCC8DCC8ECC8FCC90CC91CC92 CC93304130423043304430453046304730483049304A304B304C304D304E304F 3050305130523053305430553056305730583059305A305B305C305D305E305F 3060306130623063306430653066306730683069306A306B306C306D306E306F 3070307130723073307430753076307730783079307A307B307C307D307E307F 3080308130823083308430853086308730883089308A308B308C308D308E308F 3090309130923093000000000000000000000000000000000000000000000000 AB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000CC94CC95CC96CC97CC9ACC9BCC9DCC9ECC9FCCA1CCA2CCA3CCA4CCA5CCA6 CCA7CCAACCAECCAFCCB0CCB1CCB2CCB3CCB6CCB7CCB900000000000000000000 0000CCBACCBBCCBDCCBECCBFCCC0CCC1CCC2CCC3CCC6CCC8CCCACCCBCCCCCCCD CCCECCCFCCD1CCD2CCD3CCD5CCD6CCD7CCD8CCD9CCDA00000000000000000000 0000CCDBCCDCCCDDCCDECCDFCCE0CCE1CCE2CCE3CCE5CCE6CCE7CCE8CCE9CCEA CCEBCCEDCCEECCEFCCF1CCF2CCF3CCF4CCF5CCF6CCF7CCF8CCF9CCFACCFBCCFC CCFD30A130A230A330A430A530A630A730A830A930AA30AB30AC30AD30AE30AF 30B030B130B230B330B430B530B630B730B830B930BA30BB30BC30BD30BE30BF 30C030C130C230C330C430C530C630C730C830C930CA30CB30CC30CD30CE30CF 30D030D130D230D330D430D530D630D730D830D930DA30DB30DC30DD30DE30DF 30E030E130E230E330E430E530E630E730E830E930EA30EB30EC30ED30EE30EF 30F030F130F230F330F430F530F6000000000000000000000000000000000000 AC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000CCFECCFFCD00CD02CD03CD04CD05CD06CD07CD0ACD0BCD0DCD0ECD0FCD11 CD12CD13CD14CD15CD16CD17CD1ACD1CCD1ECD1FCD2000000000000000000000 0000CD21CD22CD23CD25CD26CD27CD29CD2ACD2BCD2DCD2ECD2FCD30CD31CD32 CD33CD34CD35CD36CD37CD38CD3ACD3BCD3CCD3DCD3E00000000000000000000 0000CD3FCD40CD41CD42CD43CD44CD45CD46CD47CD48CD49CD4ACD4BCD4CCD4D CD4ECD4FCD50CD51CD52CD53CD54CD55CD56CD57CD58CD59CD5ACD5BCD5DCD5E CD5F04100411041204130414041504010416041704180419041A041B041C041D 041E041F0420042104220423042404250426042704280429042A042B042C042D 042E042F00000000000000000000000000000000000000000000000000000000 000004300431043204330434043504510436043704380439043A043B043C043D 043E043F0440044104420443044404450446044704480449044A044B044C044D 044E044F00000000000000000000000000000000000000000000000000000000 AD 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000CD61CD62CD63CD65CD66CD67CD68CD69CD6ACD6BCD6ECD70CD72CD73CD74 CD75CD76CD77CD79CD7ACD7BCD7CCD7DCD7ECD7FCD8000000000000000000000 0000CD81CD82CD83CD84CD85CD86CD87CD89CD8ACD8BCD8CCD8DCD8ECD8FCD90 CD91CD92CD93CD96CD97CD99CD9ACD9BCD9DCD9ECD9F00000000000000000000 0000CDA0CDA1CDA2CDA3CDA6CDA8CDAACDABCDACCDADCDAECDAFCDB1CDB2CDB3 CDB4CDB5CDB6CDB7CDB8CDB9CDBACDBBCDBCCDBDCDBECDBFCDC0CDC1CDC2CDC3 CDC5000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 AE 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000CDC6CDC7CDC8CDC9CDCACDCBCDCDCDCECDCFCDD1CDD2CDD3CDD4CDD5CDD6 CDD7CDD8CDD9CDDACDDBCDDCCDDDCDDECDDFCDE0CDE100000000000000000000 0000CDE2CDE3CDE4CDE5CDE6CDE7CDE9CDEACDEBCDEDCDEECDEFCDF1CDF2CDF3 CDF4CDF5CDF6CDF7CDFACDFCCDFECDFFCE00CE01CE0200000000000000000000 0000CE03CE05CE06CE07CE09CE0ACE0BCE0DCE0ECE0FCE10CE11CE12CE13CE15 CE16CE17CE18CE1ACE1BCE1CCE1DCE1ECE1FCE22CE23CE25CE26CE27CE29CE2A CE2B000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 AF 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000CE2CCE2DCE2ECE2FCE32CE34CE36CE37CE38CE39CE3ACE3BCE3CCE3DCE3E CE3FCE40CE41CE42CE43CE44CE45CE46CE47CE48CE4900000000000000000000 0000CE4ACE4BCE4CCE4DCE4ECE4FCE50CE51CE52CE53CE54CE55CE56CE57CE5A CE5BCE5DCE5ECE62CE63CE64CE65CE66CE67CE6ACE6C00000000000000000000 0000CE6ECE6FCE70CE71CE72CE73CE76CE77CE79CE7ACE7BCE7DCE7ECE7FCE80 CE81CE82CE83CE86CE88CE8ACE8BCE8CCE8DCE8ECE8FCE92CE93CE95CE96CE97 CE99000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 B0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000CE9ACE9BCE9CCE9DCE9ECE9FCEA2CEA6CEA7CEA8CEA9CEAACEABCEAECEAF CEB0CEB1CEB2CEB3CEB4CEB5CEB6CEB7CEB8CEB9CEBA00000000000000000000 0000CEBBCEBCCEBDCEBECEBFCEC0CEC2CEC3CEC4CEC5CEC6CEC7CEC8CEC9CECA CECBCECCCECDCECECECFCED0CED1CED2CED3CED4CED500000000000000000000 0000CED6CED7CED8CED9CEDACEDBCEDCCEDDCEDECEDFCEE0CEE1CEE2CEE3CEE6 CEE7CEE9CEEACEEDCEEECEEFCEF0CEF1CEF2CEF3CEF6CEFACEFBCEFCCEFDCEFE CEFFAC00AC01AC04AC07AC08AC09AC0AAC10AC11AC12AC13AC14AC15AC16AC17 AC19AC1AAC1BAC1CAC1DAC20AC24AC2CAC2DAC2FAC30AC31AC38AC39AC3CAC40 AC4BAC4DAC54AC58AC5CAC70AC71AC74AC77AC78AC7AAC80AC81AC83AC84AC85 AC86AC89AC8AAC8BAC8CAC90AC94AC9CAC9DAC9FACA0ACA1ACA8ACA9ACAAACAC ACAFACB0ACB8ACB9ACBBACBCACBDACC1ACC4ACC8ACCCACD5ACD7ACE0ACE1ACE4 ACE7ACE8ACEAACECACEFACF0ACF1ACF3ACF5ACF6ACFCACFDAD00AD04AD060000 B1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000CF02CF03CF05CF06CF07CF09CF0ACF0BCF0CCF0DCF0ECF0FCF12CF14CF16 CF17CF18CF19CF1ACF1BCF1DCF1ECF1FCF21CF22CF2300000000000000000000 0000CF25CF26CF27CF28CF29CF2ACF2BCF2ECF32CF33CF34CF35CF36CF37CF39 CF3ACF3BCF3CCF3DCF3ECF3FCF40CF41CF42CF43CF4400000000000000000000 0000CF45CF46CF47CF48CF49CF4ACF4BCF4CCF4DCF4ECF4FCF50CF51CF52CF53 CF56CF57CF59CF5ACF5BCF5DCF5ECF5FCF60CF61CF62CF63CF66CF68CF6ACF6B CF6CAD0CAD0DAD0FAD11AD18AD1CAD20AD29AD2CAD2DAD34AD35AD38AD3CAD44 AD45AD47AD49AD50AD54AD58AD61AD63AD6CAD6DAD70AD73AD74AD75AD76AD7B AD7CAD7DAD7FAD81AD82AD88AD89AD8CAD90AD9CAD9DADA4ADB7ADC0ADC1ADC4 ADC8ADD0ADD1ADD3ADDCADE0ADE4ADF8ADF9ADFCADFFAE00AE01AE08AE09AE0B AE0DAE14AE30AE31AE34AE37AE38AE3AAE40AE41AE43AE45AE46AE4AAE4CAE4D AE4EAE50AE54AE56AE5CAE5DAE5FAE60AE61AE65AE68AE69AE6CAE70AE780000 B2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000CF6DCF6ECF6FCF72CF73CF75CF76CF77CF79CF7ACF7BCF7CCF7DCF7ECF7F CF81CF82CF83CF84CF86CF87CF88CF89CF8ACF8BCF8D00000000000000000000 0000CF8ECF8FCF90CF91CF92CF93CF94CF95CF96CF97CF98CF99CF9ACF9BCF9C CF9DCF9ECF9FCFA0CFA2CFA3CFA4CFA5CFA6CFA7CFA900000000000000000000 0000CFAACFABCFACCFADCFAECFAFCFB1CFB2CFB3CFB4CFB5CFB6CFB7CFB8CFB9 CFBACFBBCFBCCFBDCFBECFBFCFC0CFC1CFC2CFC3CFC5CFC6CFC7CFC8CFC9CFCA CFCBAE79AE7BAE7CAE7DAE84AE85AE8CAEBCAEBDAEBEAEC0AEC4AECCAECDAECF AED0AED1AED8AED9AEDCAEE8AEEBAEEDAEF4AEF8AEFCAF07AF08AF0DAF10AF2C AF2DAF30AF32AF34AF3CAF3DAF3FAF41AF42AF43AF48AF49AF50AF5CAF5DAF64 AF65AF79AF80AF84AF88AF90AF91AF95AF9CAFB8AFB9AFBCAFC0AFC7AFC8AFC9 AFCBAFCDAFCEAFD4AFDCAFE8AFE9AFF0AFF1AFF4AFF8B000B001B004B00CB010 B014B01CB01DB028B044B045B048B04AB04CB04EB053B054B055B057B0590000 B3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000CFCCCFCDCFCECFCFCFD0CFD1CFD2CFD3CFD4CFD5CFD6CFD7CFD8CFD9CFDA CFDBCFDCCFDDCFDECFDFCFE2CFE3CFE5CFE6CFE7CFE900000000000000000000 0000CFEACFEBCFECCFEDCFEECFEFCFF2CFF4CFF6CFF7CFF8CFF9CFFACFFBCFFD CFFECFFFD001D002D003D005D006D007D008D009D00A00000000000000000000 0000D00BD00CD00DD00ED00FD010D012D013D014D015D016D017D019D01AD01B D01CD01DD01ED01FD020D021D022D023D024D025D026D027D028D029D02AD02B D02CB05DB07CB07DB080B084B08CB08DB08FB091B098B099B09AB09CB09FB0A0 B0A1B0A2B0A8B0A9B0ABB0ACB0ADB0AEB0AFB0B1B0B3B0B4B0B5B0B8B0BCB0C4 B0C5B0C7B0C8B0C9B0D0B0D1B0D4B0D8B0E0B0E5B108B109B10BB10CB110B112 B113B118B119B11BB11CB11DB123B124B125B128B12CB134B135B137B138B139 B140B141B144B148B150B151B154B155B158B15CB160B178B179B17CB180B182 B188B189B18BB18DB192B193B194B198B19CB1A8B1CCB1D0B1D4B1DCB1DD0000 B4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D02ED02FD030D031D032D033D036D037D039D03AD03BD03DD03ED03FD040 D041D042D043D046D048D04AD04BD04CD04DD04ED04F00000000000000000000 0000D051D052D053D055D056D057D059D05AD05BD05CD05DD05ED05FD061D062 D063D064D065D066D067D068D069D06AD06BD06ED06F00000000000000000000 0000D071D072D073D075D076D077D078D079D07AD07BD07ED07FD080D082D083 D084D085D086D087D088D089D08AD08BD08CD08DD08ED08FD090D091D092D093 D094B1DFB1E8B1E9B1ECB1F0B1F9B1FBB1FDB204B205B208B20BB20CB214B215 B217B219B220B234B23CB258B25CB260B268B269B274B275B27CB284B285B289 B290B291B294B298B299B29AB2A0B2A1B2A3B2A5B2A6B2AAB2ACB2B0B2B4B2C8 B2C9B2CCB2D0B2D2B2D8B2D9B2DBB2DDB2E2B2E4B2E5B2E6B2E8B2EBB2ECB2ED B2EEB2EFB2F3B2F4B2F5B2F7B2F8B2F9B2FAB2FBB2FFB300B301B304B308B310 B311B313B314B315B31CB354B355B356B358B35BB35CB35EB35FB364B3650000 B5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D095D096D097D098D099D09AD09BD09CD09DD09ED09FD0A0D0A1D0A2D0A3 D0A6D0A7D0A9D0AAD0ABD0ADD0AED0AFD0B0D0B1D0B200000000000000000000 0000D0B3D0B6D0B8D0BAD0BBD0BCD0BDD0BED0BFD0C2D0C3D0C5D0C6D0C7D0CA D0CBD0CCD0CDD0CED0CFD0D2D0D6D0D7D0D8D0D9D0DA00000000000000000000 0000D0DBD0DED0DFD0E1D0E2D0E3D0E5D0E6D0E7D0E8D0E9D0EAD0EBD0EED0F2 D0F3D0F4D0F5D0F6D0F7D0F9D0FAD0FBD0FCD0FDD0FED0FFD100D101D102D103 D104B367B369B36BB36EB370B371B374B378B380B381B383B384B385B38CB390 B394B3A0B3A1B3A8B3ACB3C4B3C5B3C8B3CBB3CCB3CEB3D0B3D4B3D5B3D7B3D9 B3DBB3DDB3E0B3E4B3E8B3FCB410B418B41CB420B428B429B42BB434B450B451 B454B458B460B461B463B465B46CB480B488B49DB4A4B4A8B4ACB4B5B4B7B4B9 B4C0B4C4B4C8B4D0B4D5B4DCB4DDB4E0B4E3B4E4B4E6B4ECB4EDB4EFB4F1B4F8 B514B515B518B51BB51CB524B525B527B528B529B52AB530B531B534B5380000 B6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D105D106D107D108D109D10AD10BD10CD10ED10FD110D111D112D113D114 D115D116D117D118D119D11AD11BD11CD11DD11ED11F00000000000000000000 0000D120D121D122D123D124D125D126D127D128D129D12AD12BD12CD12DD12E D12FD132D133D135D136D137D139D13BD13CD13DD13E00000000000000000000 0000D13FD142D146D147D148D149D14AD14BD14ED14FD151D152D153D155D156 D157D158D159D15AD15BD15ED160D162D163D164D165D166D167D169D16AD16B D16DB540B541B543B544B545B54BB54CB54DB550B554B55CB55DB55FB560B561 B5A0B5A1B5A4B5A8B5AAB5ABB5B0B5B1B5B3B5B4B5B5B5BBB5BCB5BDB5C0B5C4 B5CCB5CDB5CFB5D0B5D1B5D8B5ECB610B611B614B618B625B62CB634B648B664 B668B69CB69DB6A0B6A4B6ABB6ACB6B1B6D4B6F0B6F4B6F8B700B701B705B728 B729B72CB72FB730B738B739B73BB744B748B74CB754B755B760B764B768B770 B771B773B775B77CB77DB780B784B78CB78DB78FB790B791B792B796B7970000 B7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D16ED16FD170D171D172D173D174D175D176D177D178D179D17AD17BD17D D17ED17FD180D181D182D183D185D186D187D189D18A00000000000000000000 0000D18BD18CD18DD18ED18FD190D191D192D193D194D195D196D197D198D199 D19AD19BD19CD19DD19ED19FD1A2D1A3D1A5D1A6D1A700000000000000000000 0000D1A9D1AAD1ABD1ACD1ADD1AED1AFD1B2D1B4D1B6D1B7D1B8D1B9D1BBD1BD D1BED1BFD1C1D1C2D1C3D1C4D1C5D1C6D1C7D1C8D1C9D1CAD1CBD1CCD1CDD1CE D1CFB798B799B79CB7A0B7A8B7A9B7ABB7ACB7ADB7B4B7B5B7B8B7C7B7C9B7EC B7EDB7F0B7F4B7FCB7FDB7FFB800B801B807B808B809B80CB810B818B819B81B B81DB824B825B828B82CB834B835B837B838B839B840B844B851B853B85CB85D B860B864B86CB86DB86FB871B878B87CB88DB8A8B8B0B8B4B8B8B8C0B8C1B8C3 B8C5B8CCB8D0B8D4B8DDB8DFB8E1B8E8B8E9B8ECB8F0B8F8B8F9B8FBB8FDB904 B918B920B93CB93DB940B944B94CB94FB951B958B959B95CB960B968B9690000 B8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D1D0D1D1D1D2D1D3D1D4D1D5D1D6D1D7D1D9D1DAD1DBD1DCD1DDD1DED1DF D1E0D1E1D1E2D1E3D1E4D1E5D1E6D1E7D1E8D1E9D1EA00000000000000000000 0000D1EBD1ECD1EDD1EED1EFD1F0D1F1D1F2D1F3D1F5D1F6D1F7D1F9D1FAD1FB D1FCD1FDD1FED1FFD200D201D202D203D204D205D20600000000000000000000 0000D208D20AD20BD20CD20DD20ED20FD211D212D213D214D215D216D217D218 D219D21AD21BD21CD21DD21ED21FD220D221D222D223D224D225D226D227D228 D229B96BB96DB974B975B978B97CB984B985B987B989B98AB98DB98EB9ACB9AD B9B0B9B4B9BCB9BDB9BFB9C1B9C8B9C9B9CCB9CEB9CFB9D0B9D1B9D2B9D8B9D9 B9DBB9DDB9DEB9E1B9E3B9E4B9E5B9E8B9ECB9F4B9F5B9F7B9F8B9F9B9FABA00 BA01BA08BA15BA38BA39BA3CBA40BA42BA48BA49BA4BBA4DBA4EBA53BA54BA55 BA58BA5CBA64BA65BA67BA68BA69BA70BA71BA74BA78BA83BA84BA85BA87BA8C BAA8BAA9BAABBAACBAB0BAB2BAB8BAB9BABBBABDBAC4BAC8BAD8BAD9BAFC0000 B9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D22AD22BD22ED22FD231D232D233D235D236D237D238D239D23AD23BD23E D240D242D243D244D245D246D247D249D24AD24BD24C00000000000000000000 0000D24DD24ED24FD250D251D252D253D254D255D256D257D258D259D25AD25B D25DD25ED25FD260D261D262D263D265D266D267D26800000000000000000000 0000D269D26AD26BD26CD26DD26ED26FD270D271D272D273D274D275D276D277 D278D279D27AD27BD27CD27DD27ED27FD282D283D285D286D287D289D28AD28B D28CBB00BB04BB0DBB0FBB11BB18BB1CBB20BB29BB2BBB34BB35BB36BB38BB3B BB3CBB3DBB3EBB44BB45BB47BB49BB4DBB4FBB50BB54BB58BB61BB63BB6CBB88 BB8CBB90BBA4BBA8BBACBBB4BBB7BBC0BBC4BBC8BBD0BBD3BBF8BBF9BBFCBBFF BC00BC02BC08BC09BC0BBC0CBC0DBC0FBC11BC14BC15BC16BC17BC18BC1BBC1C BC1DBC1EBC1FBC24BC25BC27BC29BC2DBC30BC31BC34BC38BC40BC41BC43BC44 BC45BC49BC4CBC4DBC50BC5DBC84BC85BC88BC8BBC8CBC8EBC94BC95BC970000 BA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D28DD28ED28FD292D293D294D296D297D298D299D29AD29BD29DD29ED29F D2A1D2A2D2A3D2A5D2A6D2A7D2A8D2A9D2AAD2ABD2AD00000000000000000000 0000D2AED2AFD2B0D2B2D2B3D2B4D2B5D2B6D2B7D2BAD2BBD2BDD2BED2C1D2C3 D2C4D2C5D2C6D2C7D2CAD2CCD2CDD2CED2CFD2D0D2D100000000000000000000 0000D2D2D2D3D2D5D2D6D2D7D2D9D2DAD2DBD2DDD2DED2DFD2E0D2E1D2E2D2E3 D2E6D2E7D2E8D2E9D2EAD2EBD2ECD2EDD2EED2EFD2F2D2F3D2F5D2F6D2F7D2F9 D2FABC99BC9ABCA0BCA1BCA4BCA7BCA8BCB0BCB1BCB3BCB4BCB5BCBCBCBDBCC0 BCC4BCCDBCCFBCD0BCD1BCD5BCD8BCDCBCF4BCF5BCF6BCF8BCFCBD04BD05BD07 BD09BD10BD14BD24BD2CBD40BD48BD49BD4CBD50BD58BD59BD64BD68BD80BD81 BD84BD87BD88BD89BD8ABD90BD91BD93BD95BD99BD9ABD9CBDA4BDB0BDB8BDD4 BDD5BDD8BDDCBDE9BDF0BDF4BDF8BE00BE03BE05BE0CBE0DBE10BE14BE1CBE1D BE1FBE44BE45BE48BE4CBE4EBE54BE55BE57BE59BE5ABE5BBE60BE61BE640000 BB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D2FBD2FCD2FDD2FED2FFD302D304D306D307D308D309D30AD30BD30FD311 D312D313D315D317D318D319D31AD31BD31ED322D32300000000000000000000 0000D324D326D327D32AD32BD32DD32ED32FD331D332D333D334D335D336D337 D33AD33ED33FD340D341D342D343D346D347D348D34900000000000000000000 0000D34AD34BD34CD34DD34ED34FD350D351D352D353D354D355D356D357D358 D359D35AD35BD35CD35DD35ED35FD360D361D362D363D364D365D366D367D368 D369BE68BE6ABE70BE71BE73BE74BE75BE7BBE7CBE7DBE80BE84BE8CBE8DBE8F BE90BE91BE98BE99BEA8BED0BED1BED4BED7BED8BEE0BEE3BEE4BEE5BEECBF01 BF08BF09BF18BF19BF1BBF1CBF1DBF40BF41BF44BF48BF50BF51BF55BF94BFB0 BFC5BFCCBFCDBFD0BFD4BFDCBFDFBFE1C03CC051C058C05CC060C068C069C090 C091C094C098C0A0C0A1C0A3C0A5C0ACC0ADC0AFC0B0C0B3C0B4C0B5C0B6C0BC C0BDC0BFC0C0C0C1C0C5C0C8C0C9C0CCC0D0C0D8C0D9C0DBC0DCC0DDC0E40000 BC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D36AD36BD36CD36DD36ED36FD370D371D372D373D374D375D376D377D378 D379D37AD37BD37ED37FD381D382D383D385D386D38700000000000000000000 0000D388D389D38AD38BD38ED392D393D394D395D396D397D39AD39BD39DD39E D39FD3A1D3A2D3A3D3A4D3A5D3A6D3A7D3AAD3ACD3AE00000000000000000000 0000D3AFD3B0D3B1D3B2D3B3D3B5D3B6D3B7D3B9D3BAD3BBD3BDD3BED3BFD3C0 D3C1D3C2D3C3D3C6D3C7D3CAD3CBD3CCD3CDD3CED3CFD3D1D3D2D3D3D3D4D3D5 D3D6C0E5C0E8C0ECC0F4C0F5C0F7C0F9C100C104C108C110C115C11CC11DC11E C11FC120C123C124C126C127C12CC12DC12FC130C131C136C138C139C13CC140 C148C149C14BC14CC14DC154C155C158C15CC164C165C167C168C169C170C174 C178C185C18CC18DC18EC190C194C196C19CC19DC19FC1A1C1A5C1A8C1A9C1AC C1B0C1BDC1C4C1C8C1CCC1D4C1D7C1D8C1E0C1E4C1E8C1F0C1F1C1F3C1FCC1FD C200C204C20CC20DC20FC211C218C219C21CC21FC220C228C229C22BC22D0000 BD 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D3D7D3D9D3DAD3DBD3DCD3DDD3DED3DFD3E0D3E2D3E4D3E5D3E6D3E7D3E8 D3E9D3EAD3EBD3EED3EFD3F1D3F2D3F3D3F5D3F6D3F700000000000000000000 0000D3F8D3F9D3FAD3FBD3FED400D402D403D404D405D406D407D409D40AD40B D40CD40DD40ED40FD410D411D412D413D414D415D41600000000000000000000 0000D417D418D419D41AD41BD41CD41ED41FD420D421D422D423D424D425D426 D427D428D429D42AD42BD42CD42DD42ED42FD430D431D432D433D434D435D436 D437C22FC231C232C234C248C250C251C254C258C260C265C26CC26DC270C274 C27CC27DC27FC281C288C289C290C298C29BC29DC2A4C2A5C2A8C2ACC2ADC2B4 C2B5C2B7C2B9C2DCC2DDC2E0C2E3C2E4C2EBC2ECC2EDC2EFC2F1C2F6C2F8C2F9 C2FBC2FCC300C308C309C30CC30DC313C314C315C318C31CC324C325C328C329 C345C368C369C36CC370C372C378C379C37CC37DC384C388C38CC3C0C3D8C3D9 C3DCC3DFC3E0C3E2C3E8C3E9C3EDC3F4C3F5C3F8C408C410C424C42CC4300000 BE 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D438D439D43AD43BD43CD43DD43ED43FD441D442D443D445D446D447D448 D449D44AD44BD44CD44DD44ED44FD450D451D452D45300000000000000000000 0000D454D455D456D457D458D459D45AD45BD45DD45ED45FD461D462D463D465 D466D467D468D469D46AD46BD46CD46ED470D471D47200000000000000000000 0000D473D474D475D476D477D47AD47BD47DD47ED481D483D484D485D486D487 D48AD48CD48ED48FD490D491D492D493D495D496D497D498D499D49AD49BD49C D49DC434C43CC43DC448C464C465C468C46CC474C475C479C480C494C49CC4B8 C4BCC4E9C4F0C4F1C4F4C4F8C4FAC4FFC500C501C50CC510C514C51CC528C529 C52CC530C538C539C53BC53DC544C545C548C549C54AC54CC54DC54EC553C554 C555C557C558C559C55DC55EC560C561C564C568C570C571C573C574C575C57C C57DC580C584C587C58CC58DC58FC591C595C597C598C59CC5A0C5A9C5B4C5B5 C5B8C5B9C5BBC5BCC5BDC5BEC5C4C5C5C5C6C5C7C5C8C5C9C5CAC5CCC5CE0000 BF 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D49ED49FD4A0D4A1D4A2D4A3D4A4D4A5D4A6D4A7D4A8D4AAD4ABD4ACD4AD D4AED4AFD4B0D4B1D4B2D4B3D4B4D4B5D4B6D4B7D4B800000000000000000000 0000D4B9D4BAD4BBD4BCD4BDD4BED4BFD4C0D4C1D4C2D4C3D4C4D4C5D4C6D4C7 D4C8D4C9D4CAD4CBD4CDD4CED4CFD4D1D4D2D4D3D4D500000000000000000000 0000D4D6D4D7D4D8D4D9D4DAD4DBD4DDD4DED4E0D4E1D4E2D4E3D4E4D4E5D4E6 D4E7D4E9D4EAD4EBD4EDD4EED4EFD4F1D4F2D4F3D4F4D4F5D4F6D4F7D4F9D4FA D4FCC5D0C5D1C5D4C5D8C5E0C5E1C5E3C5E5C5ECC5EDC5EEC5F0C5F4C5F6C5F7 C5FCC5FDC5FEC5FFC600C601C605C606C607C608C60CC610C618C619C61BC61C C624C625C628C62CC62DC62EC630C633C634C635C637C639C63BC640C641C644 C648C650C651C653C654C655C65CC65DC660C66CC66FC671C678C679C67CC680 C688C689C68BC68DC694C695C698C69CC6A4C6A5C6A7C6A9C6B0C6B1C6B4C6B8 C6B9C6BAC6C0C6C1C6C3C6C5C6CCC6CDC6D0C6D4C6DCC6DDC6E0C6E1C6E80000 C0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D4FED4FFD500D501D502D503D505D506D507D509D50AD50BD50DD50ED50F D510D511D512D513D516D518D519D51AD51BD51CD51D00000000000000000000 0000D51ED51FD520D521D522D523D524D525D526D527D528D529D52AD52BD52C D52DD52ED52FD530D531D532D533D534D535D536D53700000000000000000000 0000D538D539D53AD53BD53ED53FD541D542D543D545D546D547D548D549D54A D54BD54ED550D552D553D554D555D556D557D55AD55BD55DD55ED55FD561D562 D563C6E9C6ECC6F0C6F8C6F9C6FDC704C705C708C70CC714C715C717C719C720 C721C724C728C730C731C733C735C737C73CC73DC740C744C74AC74CC74DC74F C751C752C753C754C755C756C757C758C75CC760C768C76BC774C775C778C77C C77DC77EC783C784C785C787C788C789C78AC78EC790C791C794C796C797C798 C79AC7A0C7A1C7A3C7A4C7A5C7A6C7ACC7ADC7B0C7B4C7BCC7BDC7BFC7C0C7C1 C7C8C7C9C7CCC7CEC7D0C7D8C7DDC7E4C7E8C7ECC800C801C804C808C80A0000 C1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D564D566D567D56AD56CD56ED56FD570D571D572D573D576D577D579D57A D57BD57DD57ED57FD580D581D582D583D586D58AD58B00000000000000000000 0000D58CD58DD58ED58FD591D592D593D594D595D596D597D598D599D59AD59B D59CD59DD59ED59FD5A0D5A1D5A2D5A3D5A4D5A6D5A700000000000000000000 0000D5A8D5A9D5AAD5ABD5ACD5ADD5AED5AFD5B0D5B1D5B2D5B3D5B4D5B5D5B6 D5B7D5B8D5B9D5BAD5BBD5BCD5BDD5BED5BFD5C0D5C1D5C2D5C3D5C4D5C5D5C6 D5C7C810C811C813C815C816C81CC81DC820C824C82CC82DC82FC831C838C83C C840C848C849C84CC84DC854C870C871C874C878C87AC880C881C883C885C886 C887C88BC88CC88DC894C89DC89FC8A1C8A8C8BCC8BDC8C4C8C8C8CCC8D4C8D5 C8D7C8D9C8E0C8E1C8E4C8F5C8FCC8FDC900C904C905C906C90CC90DC90FC911 C918C92CC934C950C951C954C958C960C961C963C96CC970C974C97CC988C989 C98CC990C998C999C99BC99DC9C0C9C1C9C4C9C7C9C8C9CAC9D0C9D1C9D30000 C2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D5CAD5CBD5CDD5CED5CFD5D1D5D3D5D4D5D5D5D6D5D7D5DAD5DCD5DED5DF D5E0D5E1D5E2D5E3D5E6D5E7D5E9D5EAD5EBD5EDD5EE00000000000000000000 0000D5EFD5F0D5F1D5F2D5F3D5F6D5F8D5FAD5FBD5FCD5FDD5FED5FFD602D603 D605D606D607D609D60AD60BD60CD60DD60ED60FD61200000000000000000000 0000D616D617D618D619D61AD61BD61DD61ED61FD621D622D623D625D626D627 D628D629D62AD62BD62CD62ED62FD630D631D632D633D634D635D636D637D63A D63BC9D5C9D6C9D9C9DAC9DCC9DDC9E0C9E2C9E4C9E7C9ECC9EDC9EFC9F0C9F1 C9F8C9F9C9FCCA00CA08CA09CA0BCA0CCA0DCA14CA18CA29CA4CCA4DCA50CA54 CA5CCA5DCA5FCA60CA61CA68CA7DCA84CA98CABCCABDCAC0CAC4CACCCACDCACF CAD1CAD3CAD8CAD9CAE0CAECCAF4CB08CB10CB14CB18CB20CB21CB41CB48CB49 CB4CCB50CB58CB59CB5DCB64CB78CB79CB9CCBB8CBD4CBE4CBE7CBE9CC0CCC0D CC10CC14CC1CCC1DCC21CC22CC27CC28CC29CC2CCC2ECC30CC38CC39CC3B0000 C3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D63DD63ED63FD641D642D643D644D646D647D64AD64CD64ED64FD650D652 D653D656D657D659D65AD65BD65DD65ED65FD660D66100000000000000000000 0000D662D663D664D665D666D668D66AD66BD66CD66DD66ED66FD672D673D675 D676D677D678D679D67AD67BD67CD67DD67ED67FD68000000000000000000000 0000D681D682D684D686D687D688D689D68AD68BD68ED68FD691D692D693D695 D696D697D698D699D69AD69BD69CD69ED6A0D6A2D6A3D6A4D6A5D6A6D6A7D6A9 D6AACC3CCC3DCC3ECC44CC45CC48CC4CCC54CC55CC57CC58CC59CC60CC64CC66 CC68CC70CC75CC98CC99CC9CCCA0CCA8CCA9CCABCCACCCADCCB4CCB5CCB8CCBC CCC4CCC5CCC7CCC9CCD0CCD4CCE4CCECCCF0CD01CD08CD09CD0CCD10CD18CD19 CD1BCD1DCD24CD28CD2CCD39CD5CCD60CD64CD6CCD6DCD6FCD71CD78CD88CD94 CD95CD98CD9CCDA4CDA5CDA7CDA9CDB0CDC4CDCCCDD0CDE8CDECCDF0CDF8CDF9 CDFBCDFDCE04CE08CE0CCE14CE19CE20CE21CE24CE28CE30CE31CE33CE350000 C4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D6ABD6ADD6AED6AFD6B1D6B2D6B3D6B4D6B5D6B6D6B7D6B8D6BAD6BCD6BD D6BED6BFD6C0D6C1D6C2D6C3D6C6D6C7D6C9D6CAD6CB00000000000000000000 0000D6CDD6CED6CFD6D0D6D2D6D3D6D5D6D6D6D8D6DAD6DBD6DCD6DDD6DED6DF D6E1D6E2D6E3D6E5D6E6D6E7D6E9D6EAD6EBD6ECD6ED00000000000000000000 0000D6EED6EFD6F1D6F2D6F3D6F4D6F6D6F7D6F8D6F9D6FAD6FBD6FED6FFD701 D702D703D705D706D707D708D709D70AD70BD70CD70DD70ED70FD710D712D713 D714CE58CE59CE5CCE5FCE60CE61CE68CE69CE6BCE6DCE74CE75CE78CE7CCE84 CE85CE87CE89CE90CE91CE94CE98CEA0CEA1CEA3CEA4CEA5CEACCEADCEC1CEE4 CEE5CEE8CEEBCEECCEF4CEF5CEF7CEF8CEF9CF00CF01CF04CF08CF10CF11CF13 CF15CF1CCF20CF24CF2CCF2DCF2FCF30CF31CF38CF54CF55CF58CF5CCF64CF65 CF67CF69CF70CF71CF74CF78CF80CF85CF8CCFA1CFA8CFB0CFC4CFE0CFE1CFE4 CFE8CFF0CFF1CFF3CFF5CFFCD000D004D011D018D02DD034D035D038D03C0000 C5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D715D716D717D71AD71BD71DD71ED71FD721D722D723D724D725D726D727 D72AD72CD72ED72FD730D731D732D733D736D737D73900000000000000000000 0000D73AD73BD73DD73ED73FD740D741D742D743D745D746D748D74AD74BD74C D74DD74ED74FD752D753D755D75AD75BD75CD75DD75E00000000000000000000 0000D75FD762D764D766D767D768D76AD76BD76DD76ED76FD771D772D773D775 D776D777D778D779D77AD77BD77ED77FD780D782D783D784D785D786D787D78A D78BD044D045D047D049D050D054D058D060D06CD06DD070D074D07CD07DD081 D0A4D0A5D0A8D0ACD0B4D0B5D0B7D0B9D0C0D0C1D0C4D0C8D0C9D0D0D0D1D0D3 D0D4D0D5D0DCD0DDD0E0D0E4D0ECD0EDD0EFD0F0D0F1D0F8D10DD130D131D134 D138D13AD140D141D143D144D145D14CD14DD150D154D15CD15DD15FD161D168 D16CD17CD184D188D1A0D1A1D1A4D1A8D1B0D1B1D1B3D1B5D1BAD1BCD1C0D1D8 D1F4D1F8D207D209D210D22CD22DD230D234D23CD23DD23FD241D248D25C0000 C6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D78DD78ED78FD791D792D793D794D795D796D797D79AD79CD79ED79FD7A0 D7A1D7A2D7A30000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D264D280D281D284D288D290D291D295D29CD2A0D2A4D2ACD2B1D2B8D2B9 D2BCD2BFD2C0D2C2D2C8D2C9D2CBD2D4D2D8D2DCD2E4D2E5D2F0D2F1D2F4D2F8 D300D301D303D305D30CD30DD30ED310D314D316D31CD31DD31FD320D321D325 D328D329D32CD330D338D339D33BD33CD33DD344D345D37CD37DD380D384D38C D38DD38FD390D391D398D399D39CD3A0D3A8D3A9D3ABD3ADD3B4D3B8D3BCD3C4 D3C5D3C8D3C9D3D0D3D8D3E1D3E3D3ECD3EDD3F0D3F4D3FCD3FDD3FFD4010000 C7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D408D41DD440D444D45CD460D464D46DD46FD478D479D47CD47FD480D482 D488D489D48BD48DD494D4A9D4CCD4D0D4D4D4DCD4DFD4E8D4ECD4F0D4F8D4FB D4FDD504D508D50CD514D515D517D53CD53DD540D544D54CD54DD54FD551D558 D559D55CD560D565D568D569D56BD56DD574D575D578D57CD584D585D587D588 D589D590D5A5D5C8D5C9D5CCD5D0D5D2D5D8D5D9D5DBD5DDD5E4D5E5D5E8D5EC D5F4D5F5D5F7D5F9D600D601D604D608D610D611D613D614D615D61CD6200000 C8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D624D62DD638D639D63CD640D645D648D649D64BD64DD651D654D655D658 D65CD667D669D670D671D674D683D685D68CD68DD690D694D69DD69FD6A1D6A8 D6ACD6B0D6B9D6BBD6C4D6C5D6C8D6CCD6D1D6D4D6D7D6D9D6E0D6E4D6E8D6F0 D6F5D6FCD6FDD700D704D711D718D719D71CD720D728D729D72BD72DD734D735 D738D73CD744D747D749D750D751D754D756D757D758D759D760D761D763D765 D769D76CD770D774D77CD77DD781D788D789D78CD790D798D799D79BD79D0000 CA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00004F3D4F73504750F952A053EF547554E556095AC15BB6668767B667B767EF 6B4C73C275C27A3C82DB8304885788888A368CC88DCF8EFB8FE699D5523B5374 5404606A61646BBC73CF811A89BA89D295A34F83520A58BE597859E65E725E79 61C763C0674667EC687F6F97764E770B78F57A087AFF7C21809D826E82718AEB 95934E6B559D66F76E3478A37AED845B8910874E97A852D8574E582A5D4C611F 61BE6221656267D16A446E1B751875B376E377B07D3A90AF945194529F950000 CB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000053235CAC753280DB92409598525B580859DC5CA15D175EB75F3A5F4A6177 6C5F757A75867CE07D737DB17F8C81548221859189418B1B92FC964D9C474ECB 4EF7500B51F1584F6137613E6168653969EA6F1175A5768676D67B8782A584CB F90093A7958B55805BA25751F9017CB37FB991B5502853BB5C455DE862D2636E 64DA64E76E2070AC795B8DDD8E1EF902907D924592F84E7E4EF650655DFE5EFA 61066957817186548E4793759A2B4E5E5091677068405109528D52926AA20000 CC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000077BC92109ED452AB602F8FF2504861A963ED64CA683C6A846FC0818889A1 96945805727D72AC75047D797E6D80A9898B8B7490639D5162896C7A6F547D50 7F3A8A23517C614A7B9D8B199257938C4EAC4FD3501E50BE510652C152CD537F 577058835E9A5F91617661AC64CE656C666F66BB66F468976D87708570F1749F 74A574CA75D9786C78EC7ADF7AF67D457D938015803F811B83968B668F159015 93E1980398389A5A9BE84FC25553583A59515B635C4660B86212684268B00000 CD 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000068E86EAA754C767878CE7A3D7CFB7E6B7E7C8A088AA18C3F968E9DC453E4 53E9544A547156FA59D15B645C3B5EAB62F765376545657266A067AF69C16CBD 75FC7690777E7A3F7F94800380A1818F82E682FD83F085C1883188B48AA5F903 8F9C932E96C798679AD89F1354ED659B66F2688F7A408C379D6056F057645D11 660668B168CD6EFE7428889E9BE46C68F9049AA84F9B516C5171529F5B545DE5 6050606D62F163A7653B73D97A7A86A38CA2978F4E325BE16208679C74DC0000 CE 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000079D183D38A878AB28DE8904E934B98465ED369E885FF90EDF90551A05B98 5BEC616368FA6B3E704C742F74D87BA17F5083C589C08CAB95DC9928522E605D 62EC90024F8A5149532158D95EE366E06D38709A72C273D67B5080F1945B5366 639B7F6B4E565080584A58DE602A612762D069D09B415B8F7D1880B18F5F4EA4 50D154AC55AC5B0C5DA05DE7652A654E68216A4B72E1768E77EF7D5E7FF981A0 854E86DF8F038F4E90CA99039A559BAB4E184E454E5D4EC74FF1517752FE0000 CF 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000534053E353E5548E5614577557A25BC75D875ED061FC62D8655167B867E9 69CB6B506BC66BEC6C426E9D707872D77396740377BF77E97A767D7F800981FC 8205820A82DF88628B338CFC8EC0901190B1926492B699D29A459CE99DD79F9C 570B5C4083CA97A097AB9EB4541B7A987FA488D98ECD90E158005C4863987A9F 5BAE5F137A797AAE828E8EAC5026523852F85377570862F363726B0A6DC37737 53A5735785688E7695D5673A6AC36F708A6D8ECC994BF90666776B788CB40000 D0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009B3CF90753EB572D594E63C669FB73EA78457ABA7AC57CFE8475898F8D73 903595A852FB574775477B6083CC921EF9086A58514B524B5287621F68D86975 969950C552A452E461C365A4683969FF747E7B4B82B983EB89B28B398FD19949 F9094ECA599764D266116A8E7434798179BD82A9887E887F895FF90A93264F0B 53CA602562716C727D1A7D664E98516277DC80AF4F014F0E5176518055DC5668 573B57FA57FC5914594759935BC45C905D0E5DF15E7E5FCC628065D765E30000 D1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000671E671F675E68CB68C46A5F6B3A6C236C7D6C826DC773987426742A7482 74A37578757F788178EF794179477948797A7B957D007DBA7F888006802D808C 8A188B4F8C488D779321932498E299519A0E9A0F9A659E927DCA4F76540962EE 685491D155AB513AF90BF90C5A1C61E6F90D62CF62FFF90EF90FF910F911F912 F91390A3F914F915F916F917F9188AFEF919F91AF91BF91C6696F91D7156F91E F91F96E3F920634F637A5357F921678F69606E73F9227537F923F924F9250000 D2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007D0DF926F927887256CA5A18F928F929F92AF92BF92C4E43F92D51675948 67F08010F92E59735E74649A79CA5FF5606C62C8637B5BE75BD752AAF92F5974 5F296012F930F931F9327459F933F934F935F936F937F93899D1F939F93AF93B F93CF93DF93EF93FF940F941F942F9436FC3F944F94581BF8FB260F1F946F947 8166F948F9495C3FF94AF94BF94CF94DF94EF94FF950F9515AE98A25677B7D10 F952F953F954F955F956F95780FDF958F9595C3C6CE5533F6EBA591A83360000 D3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00004E394EB64F4655AE571858C75F5665B765E66A806BB56E4D77ED7AEF7C1E 7DDE86CB88929132935B64BB6FBE737A75B890545556574D61BA64D466C76DE1 6E5B6F6D6FB975F0804381BD854189838AC78B5A931F6C9375537B548E0F905D 5510580258585E626207649E68E075767CD687B39EE84EE35788576E59275C0D 5CB15E365F85623464E173B381FA888B8CB8968A9EDB5B855FB760B350125200 52305716583558575C0E5C605CF65D8B5EA65F9260BC63116389641768430000 D4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000068F96AC26DD86E216ED46FE471FE76DC777979B17A3B840489A98CED8DF3 8E4890039014905390FD934D967697DC6BD27006725872A27368776379BF7BE4 7E9B8B8058A960C7656665FD66BE6C8C711E71C98C5A98134E6D7A814EDD51AC 51CD52D5540C61A76771685068DF6D1E6F7C75BC77B37AE580F484639285515C 6597675C679375D87AC78373F95A8C469017982D5C6F81C0829A9041906F920D 5F975D9D6A5971C8767B7B4985E48B0491279A30558761F6F95B76697F850000 D5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000863F87BA88F8908FF95C6D1B70D973DE7D61843DF95D916A99F1F95E4E82 53756B046B12703E721B862D9E1E524C8FA35D5064E5652C6B166FEB7C437E9C 85CD896489BD62C981D8881F5ECA67176D6A72FC7405746F878290DE4F865D0D 5FA0840A51B763A075654EAE5006516951C968816A117CAE7CB17CE7826F8AD2 8F1B91CF4FB6513752F554425EEC616E623E65C56ADA6FFE792A85DC882395AD 9A629A6A9E979ECE529B66C66B77701D792B8F6297426190620065236F230000 D6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000714974897DF4806F84EE8F269023934A51BD521752A36D0C70C888C25EC9 65826BAE6FC27C3E73754EE44F3656F9F95F5CBA5DBA601C73B27B2D7F9A7FCE 8046901E923496F6974898189F614F8B6FA779AE91B496B752DEF960648864C4 6AD36F5E7018721076E780018606865C8DEF8F0597329B6F9DFA9E75788C797F 7DA083C993049E7F9E938AD658DF5F046727702774CF7C60807E512170287262 78CA8CC28CDA8CF496F74E8650DA5BEE5ED6659971CE764277AD804A84FC0000 D7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000907C9B279F8D58D85A415C626A136DDA6F0F763B7D2F7E37851E893893E4 964B528965D267F369B46D416E9C700F7409746075597624786B8B2C985E516D 622E96784F96502B5D196DEA7DB88F2A5F8B61446817F961968652D2808B51DC 51CC695E7A1C7DBE83F196754FDA52295398540F550E5C6560A7674E68A86D6C 728172F874067483F96275E27C6C7F797FB8838988CF88E191CC91D096E29BC9 541D6F7E71D0749885FA8EAA96A39C579E9F67976DCB743381E89716782C0000 D8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007ACB7B207C926469746A75F278BC78E899AC9B549EBB5BDE5E556F20819C 83AB90884E07534D5A295DD25F4E6162633D666966FC6EFF6F2B7063779E842C 8513883B8F1399459C3B551C62B9672B6CAB8309896A977A4EA159845FD85FD9 671B7DB27F548292832B83BD8F1E909957CB59B95A925BD06627679A68856BCF 71647F758CB78CE390819B4581088C8A964C9A409EA55B5F6C13731B76F276DF 840C51AA8993514D519552C968C96C94770477207DBF7DEC97629EB56EC50000 D9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000851151A5540D547D660E669D69276E9F76BF7791831784C2879F91699298 9CF488824FAE519252DF59C65E3D61556478647966AE67D06A216BCD6BDB725F 72617441773877DB801782BC83058B008B288C8C67286C90726776EE77667A46 9DA96B7F6C92592267268499536F589359995EDF63CF663467736E3A732B7AD7 82D7932852D95DEB61AE61CB620A62C764AB65E069596B666BCB712173F7755D 7E46821E8302856A8AA38CBF97279D6158A89ED85011520E543B554F65870000 DA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006C767D0A7D0B805E868A958096EF52FF6C95726954735A9A5C3E5D4B5F4C 5FAE672A68B669636E3C6E4477097C737F8E85878B0E8FF797619EF45CB760B6 610D61AB654F65FB65FC6C116CEF739F73C97DE195945BC6871C8B10525D535A 62CD640F64B267346A386CCA73C0749E7B947C957E1B818A823685848FEB96F9 99C14F34534A53CD53DB62CC642C6500659169C36CEE6F5873ED7554762276E4 76FC78D078FB792C7D46822C87E08FD4981298EF52C362D464A56E246F510000 DB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000767C8DCB91B192629AEE9B435023508D574A59A85C285E475F77623F653E 65B965C16609678B699C6EC278C57D2180AA8180822B82B384A1868C8A2A8B17 90A696329F90500D4FF3F96357F95F9862DC6392676F6E43711976C380CC80DA 88F488F589198CE08F29914D966A4F2F4F705E1B67CF6822767D767E9B445E61 6A0A716971D4756AF9647E41854385E998DC4F107B4F7F7095A551E15E0668B5 6C3E6C4E6CDB72AF7BC483036CD5743A50FB528858C164D86A9774A776560000 DC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000078A7861795E29739F965535E5F018B8A8FA88FAF908A522577A59C499F08 4E19500251755C5B5E77661E663A67C468C570B3750175C579C97ADD8F279920 9A084FDD582158315BF6666E6B656D116E7A6F7D73E4752B83E988DC89138B5C 8F144F0F50D55310535C5B935FA9670D798F8179832F8514890789868F398F3B 99A59C12672C4E764FF859495C015CEF5CF0636768D270FD71A2742B7E2B84EC 8702902292D29CF34E0D4ED84FEF50855256526F5426549057E0592B5A660000 DD 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005B5A5B755BCC5E9CF9666276657765A76D6E6EA572367B267C3F7F368150 8151819A8240829983A98A038CA08CE68CFB8D748DBA90E891DC961C964499D9 9CE7531752065429567458B35954596E5FFF61A4626E66106C7E711A76C67C89 7CDE7D1B82AC8CC196F0F9674F5B5F175F7F62C25D29670B68DA787C7E439D6C 4E1550995315532A535159835A625E8760B2618A624962796590678769A76BD4 6BD66BD76BD86CB8F968743575FA7812789179D579D87C837DCB7FE180A50000 DE 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000813E81C283F2871A88E88AB98B6C8CBB9119975E98DB9F3B56AC5B2A5F6C 658C6AB36BAF6D5C6FF17015725D73AD8CA78CD3983B61916C3780589A014E4D 4E8B4E9B4ED54F3A4F3C4F7F4FDF50FF53F253F8550655E356DB58EB59625A11 5BEB5BFA5C045DF35E2B5F99601D6368659C65AF67F667FB68AD6B7B6C996CD7 6E23700973457802793E7940796079C17BE97D177D728086820D838E84D186C7 88DF8A508A5E8B1D8CDC8D668FAD90AA98FC99DF9E9D524AF9696714F96A0000 DF 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005098522A5C7165636C5573CA7523759D7B97849C917897304E7764926BBA 715E85A94E09F96B674968EE6E17829F8518886B63F76F81921298AF4E0A50B7 50CF511F554655AA56175B405C195CE05E385E8A5EA05EC260F368516A616E58 723D724072C076F879657BB17FD488F389F48A738C618CDE971C585E74BD8CFD 55C7F96C7A617D2282727272751F7525F96D7B19588558FB5DBC5E8F5EB65F90 60556292637F654D669166D966F8681668F27280745E7B6E7D6E7DD67F720000 E0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000080E5821285AF897F8A93901D92E49ECD9F205915596D5E2D60DC66146673 67906C506DC56F5F77F378A984C691CB932B4ED950CA514855845B0B5BA36247 657E65CB6E32717D74017444748774BF766C79AA7DDA7E557FA8817A81B38239 861A87EC8A758DE3907892919425994D9BAE53685C5169546CC46D296E2B820C 859B893B8A2D8AAA96EA9F67526166B96BB27E9687FE8D0D9583965D651D6D89 71EEF96E57CE59D35BAC602760FA6210661F665F732973F976DB77017B6C0000 E1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008056807281658AA091924E1652E26B726D177A057B397D30F96F8CB053EC 562F58515BB55C0F5C115DE2624063836414662D68B36CBC6D886EAF701F70A4 71D27526758F758E76197B117BE07C2B7D207D39852C856D86078A34900D9061 90B592B797F69A374FD75C6C675F6D917C9F7E8C8B168D16901F5B6B5DFD640D 84C0905C98E173875B8B609A677E6DDE8A1F8AA69001980C5237F9707051788E 9396887091D74FEE53D755FD56DA578258FD5AC25B885CAB5CC05E2561010000 E2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000620D624B6388641C653665786A396B8A6C346D196F3171E772E973787407 74B27626776179C07A577AEA7CB97D8F7DAC7E617F9E81298331849084DA85EA 88968AB08B908F3890429083916C929692B9968B96A796A896D6970098089996 9AD39B1A53D4587E59195B705BBF6DD16F5A719F742174B9808583FD5DE15F87 5FAA604265EC6812696F6A536B896D356DF373E376FE77AC7B4D7D148123821C 834084F485638A628AC49187931E980699B4620C88538FF092655D075D270000 E3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005D69745F819D87686FD562FE7FD2893689724E1E4E5850E752DD5347627F 66077E698805965E4F8D5319563659CB5AA45C385C4E5C4D5E025F11604365BD 662F664267BE67F4731C77E2793A7FC5849484CD89968A668A698AE18C558C7A 57F45BD45F0F606F62ED690D6B966E5C71847BD287558B588EFE98DF98FE4F38 4F814FE1547B5A205BB8613C65B0666871FC7533795E7D33814E81E3839885AA 85CE87038A0A8EAB8F9BF9718FC559315BA45BE660895BE95C0B5FC36C810000 E4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000F9726DF1700B751A82AF8AF64EC05341F97396D96C0F4E9E4FC45152555E 5A255CE86211725982BD83AA86FE88598A1D963F96C599139D099D5D580A5CB3 5DBD5E4460E1611563E16A026E2591029354984E9C109F775B895CB86309664F 6848773C96C1978D98549B9F65A18B018ECB95BC55355CA95DD65EB56697764C 83F495C758D362BC72CE9D284EF0592E600F663B6B8379E79D26539354C057C3 5D16611B66D66DAF788D827E969897445384627C63966DB27E0A814B984D0000 E5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006AFB7F4C9DAF9E1A4E5F503B51B6591C60F963F66930723A8036F97491CE 5F31F975F9767D0482E5846F84BB85E58E8DF9774F6FF978F97958E45B436059 63DA6518656D6698F97A694A6A236D0B7001716C75D2760D79B37A70F97B7F8A F97C8944F97D8B9391C0967DF97E990A57045FA165BC6F01760079A68A9E99AD 9B5A9F6C510461B662916A8D81C6504358305F6671098A008AFA5B7C86164FFA 513C56B4594463A96DF95DAA696D51864E884F59F97FF980F9815982F9820000 E6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000F9836B5F6C5DF98474B57916F9858207824583398F3F8F5DF9869918F987 F988F9894EA6F98A57DF5F796613F98BF98C75AB7E798B6FF98D90069A5B56A5 582759F85A1F5BB4F98E5EF6F98FF9906350633BF991693D6C876CBF6D8E6D93 6DF56F14F99270DF71367159F99371C371D5F994784F786FF9957B757DE3F996 7E2FF997884D8EDFF998F999F99A925BF99B9CF6F99CF99DF99E60856D85F99F 71B1F9A0F9A195B153ADF9A2F9A3F9A467D3F9A5708E71307430827682D20000 E7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000F9A695BB9AE59E7D66C4F9A771C18449F9A8F9A9584BF9AAF9AB5DB85F71 F9AC6620668E697969AE6C386CF36E366F416FDA701B702F715071DF7370F9AD 745BF9AE74D476C87A4E7E93F9AFF9B082F18A608FCEF9B19348F9B29719F9B3 F9B44E42502AF9B5520853E166F36C6D6FCA730A777F7A6282AE85DD8602F9B6 88D48A638B7D8C6BF9B792B3F9B8971398104E944F0D4FC950B25348543E5433 55DA586258BA59675A1B5BE4609FF9B961CA655665FF666468A76C5A6FB30000 E8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000070CF71AC73527B7D87088AA49C329F075C4B6C8373447389923A6EAB7465 761F7A697E15860A514058C564C174EE751576707FC1909596CD99546E2674E6 7AA97AAA81E586D987788A1B5A495B8C5B9B68A169006D6373A97413742C7897 7DE97FEB81188155839E8C4C962E981166F05F8065FA67896C6A738B502D5A03 6B6A77EE59165D6C5DCD7325754FF9BAF9BB50E551F9582F592D599659DA5BE5 F9BCF9BD5DA262D76416649364FEF9BE66DCF9BF6A48F9C071FF7464F9C10000 E9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007A887AAF7E477E5E80008170F9C287EF89818B209059F9C390809952617E 6B326D747E1F89258FB14FD150AD519752C757C758895BB95EB8614269956D8C 6E676EB6719474627528752C8073833884C98E0A939493DEF9C44E8E4F515076 512A53C853CB53F35B875BD35C24611A618265F4725B7397744076C279507991 79B97D067FBD828B85D5865E8FC2904790F591EA968596E896E952D65F6765ED 6631682F715C7A3690C1980A4E91F9C56A526B9E6F907189801882B885530000 EA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000904B969596F297FB851A9B314E90718A96C45143539F54E15713571257A3 5A9B5AC45BC36028613F63F46C856D396E726E907230733F745782D188818F45 9060F9C6966298589D1B67088D8A925E4F4D504950DE5371570D59D45A015C09 617066906E2D7232744B7DEF80C3840E8466853F875F885B89188B02905597CB 9B4F4E734F915112516AF9C7552F55A95B7A5BA55E7C5E7D5EBE60A060DF6108 610963C465386709F9C867D467DAF9C9696169626CB96D27F9CA6E38F9CB0000 EB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006FE173367337F9CC745C7531F9CD7652F9CEF9CF7DAD81FE843888D58A98 8ADB8AED8E308E42904A903E907A914991C9936EF9D0F9D15809F9D26BD38089 80B2F9D3F9D45141596B5C39F9D5F9D66F6473A780E48D07F9D79217958FF9D8 F9D9F9DAF9DB807F620E701C7D68878DF9DC57A0606961476BB78ABE928096B1 4E59541F6DEB852D967097F398EE63D66CE3909151DD61C981BA9DF94F9D501A 51005B9C610F61FF64EC69056BC5759177E37FA98264858F87FB88638ABC0000 EC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008B7091AB4E8C4EE54F0AF9DDF9DE593759E8F9DF5DF25F1B5F5B6021F9E0 F9E1F9E2F9E3723E73E5F9E4757075CDF9E579FBF9E6800C8033808482E18351 F9E7F9E88CBD8CB39087F9E9F9EA98F4990CF9EBF9EC703776CA7FCA7FCC7FFC 8B1A4EBA4EC152035370F9ED54BD56E059FB5BC55F155FCD6E6EF9EEF9EF7D6A 8335F9F086938A8DF9F1976D9777F9F2F9F34E004F5A4F7E58F965E56EA29038 93B099B94EFB58EC598A59D96041F9F4F9F57A14F9F6834F8CC3516553440000 ED 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000F9F7F9F8F9F94ECD52695B5582BF4ED4523A54A859C959FF5B505B575B5C 606361486ECB7099716E738674F775B578C17D2B800581EA8328851785C98AEE 8CC796CC4F5C52FA56BC65AB6628707C70B872357DBD828D914C96C09D725B71 68E76B986F7A76DE5C9166AB6F5B7BB47C2A883696DC4E084ED75320583458BB 58EF596C5C075E335E845F35638C66B267566A1F6AA36B0C6F3F7246F9FA7350 748B7AE07CA7817881DF81E7838A846C8523859485CF88DD8D1391AC95770000 EE 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000969C518D54C957285BB0624D6750683D68936E3D6ED3707D7E2188C18CA1 8F099F4B9F4E722D7B8F8ACD931A4F474F4E5132548059D05E9562B56775696E 6A176CAE6E1A72D9732A75BD7BB87D3582E783F9845785F78A5B8CAF8E879019 90B896CE9F5F52E3540A5AE15BC2645865756EF472C4F9FB76847A4D7B1B7C4D 7E3E7FDF837B8B2B8CCA8D648DE18E5F8FEA8FF9906993D14F434F7A50B35168 5178524D526A5861587C59605C085C555EDB609B623068136BBF6C086FB10000 EF 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000714E742075307538755176727B4C7B8B7BAD7BC67E8F8A6E8F3E8F49923F 92939322942B96FB985A986B991E5207622A62986D5976647ACA7BC07D765360 5CBE5E976F3870B97C9897119B8E9EDE63A5647A87764E014E954EAD505C5075 544859C35B9A5E405EAD5EF75F8160C5633A653F657465CC6676667867FE6968 6A896B636C406DC06DE86E1F6E5E701E70A1738E73FD753A775B7887798E7A0B 7A7D7CBE7D8E82478A028AEA8C9E912D914A91D8926692CC9320970697560000 F0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000975C98029F0E52365291557C58245E1D5F1F608C63D068AF6FDF796D7B2C 81CD85BA88FD8AF88E44918D9664969B973D984C9F4A4FCE514651CB52A95632 5F145F6B63AA64CD65E9664166FA66F9671D689D68D769FD6F156F6E716771E5 722A74AA773A7956795A79DF7A207A957C977CDF7D447E70808785FB86A48A54 8ABF8D998E819020906D91E3963B96D59CE565CF7C078DB393C35B585C0A5352 62D9731D50275B975F9E60B0616B68D56DD9742E7A2E7D427D9C7E31816B0000 F1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008E2A8E35937E94184F5057505DE65EA7632B7F6A4E3B4F4F4F8F505A59DD 80C4546A546855FE594F5B995DDE5EDA665D673167F1682A6CE86D326E4A6F8D 70B773E075877C4C7D027D2C7DA2821F86DB8A3B8A858D708E8A8F339031914E 9152944499D07AF97CA54FCA510151C657C85BEF5CFB66596A3D6D5A6E966FEC 710C756F7AE388229021907596CB99FF83014E2D4EF2884691CD537D6ADB696B 6C41847A589E618E66FE62EF70DD751175C77E5284B88B498D084E4B53EA0000 F2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000054AB573057405FD763016307646F652F65E8667A679D67B36B626C606C9A 6F2C77E57825794979577D1980A2810281F3829D82B787188A8CF9FC8D048DBE 907276F47A197A377E548077550755D45875632F64226649664B686D699B6B84 6D256EB173CD746874A1755B75B976E1771E778B79E67E097E1D81FB852F8897 8A3A8CD18EEB8FB0903293AD9663967397074F8453F159EA5AC95E19684E74C6 75BE79E97A9281A386ED8CEA8DCC8FED659F6715F9FD57F76F577DDD8F2F0000 F3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000093F696C65FB561F26F844E144F98501F53C955DF5D6F5DEE6B216B6478CB 7B9AF9FE8E498ECA906E6349643E77407A84932F947F9F6A64B06FAF71E674A8 74DA7AC47C127E827CB27E988B9A8D0A947D9910994C52395BDF64E6672D7D2E 50ED53C358796158615961FA65AC7AD98B928B9650095021527555315A3C5EE0 5F706134655E660C663666A269CD6EC46F32731676217A938139825983D684BC 50B557F05BC05BE85F6963A178267DB583DC852191C791F5518A67F57B560000 F4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008CAC51C459BB60BD8655501CF9FF52545C3A617D621A62D364F265A56ECC 7620810A8E60965F96BB4EDF5343559859295DDD64C56CC96DFA73947A7F821B 85A68CE48E10907791E795E1962197C651F854F255865FB964A46F887DB48F1F 8F4D943550C95C166CBE6DFB751B77BB7C3D7C648A798AC2581E59BE5E166377 7252758A776B8ADC8CBC8F125EF366746DF8807D83C18ACB97519BD6FA005243 66FF6D956EEF7DE08AE6902E905E9AD4521D527F54E86194628462DB68A20000 F5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006912695A6A3570927126785D7901790E79D27A0D8096827882D583498549 8C828D859162918B91AE4FC356D171ED77D7870089F85BF85FD6675190A853E2 585A5BF560A4618164607E3D80708525928364AE50AC5D146700589C62BD63A8 690E69786A1E6E6B76BA79CB82BB84298ACF8DA88FFD9112914B919C93109318 939A96DB9A369C0D4E11755C795D7AFA7B517BC97E2E84C48E598E748EF89010 6625693F744351FA672E9EDC51455FE06C9687F2885D887760B481B584030000 F6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008D0553D6543956345A365C31708A7FE0805A810681ED8DA391899A5F9DF2 50744EC453A060FB6E2C5C644F88502455E45CD95E5F606568946CBB6DC471BE 75D475F476617A1A7A497DC77DFB7F6E81F486A98F1C96C999B39F52524752C5 98ED89AA4E0367D26F064FB55BE267956C886D78741B782791DD937C87C479E4 7A315FEB4ED654A4553E58AE59A560F0625362D6673669558235964099B199DD 502C53535544577CFA016258FA0264E2666B67DD6FC16FEF742274388A170000 F7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000094385451560657665F48619A6B4E705870AD7DBB8A95596A812B63A27708 803D8CAA5854642D69BB5B955E116E6FFA038569514C53F0592A6020614B6B86 6C706CF07B1E80CE82D48DC690B098B1FA0464C76FA464916504514E5410571F 8A0E615F6876FA0575DB7B527D71901A580669CC817F892A9000983950785957 59AC6295900F9B2A615D727995D657615A465DF4628A64AD64FA67776CE26D3E 722C743678347F7782AD8DDB981752245742677F724874E38CA98FA692110000 F8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000962A516B53ED634C4F695504609665576C9B6D7F724C72FD7A1789878C9D 5F6D6F8E70F981A8610E4FBF504F624172477BC77DE87FE9904D97AD9A198CB6 576A5E7367B0840D8A5554205B165E635EE25F0A658380BA853D9589965B4F48 5305530D530F548654FA57035E036016629B62B16355FA066CE16D6675B17832 80DE812F82DE846184B2888D8912900B92EA98FD9B915E4566B466DD70117206 FA074FF5527D5F6A615367536A196F0274E2796888688C7998C798C49A430000 F9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000054C17A1F69538AF78C4A98A899AE5F7C62AB75B276AE88AB907F96425339 5F3C5FC56CCC73CC7562758B7B4682FE999D4E4F903C4E0B4F5553A6590F5EC8 66306CB37455837787668CC09050971E9C1558D15B7886508B149DB45BD26068 608D65F16C576F226FA3701A7F557FF095919592965097D352728F4451FD542B 54B85563558A6ABB6DB57DD88266929C96779E79540854C876D286E495A495D4 965C4EA24F0959EE5AE65DF760526297676D68416C866E2F7F38809B822A0000 FA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FA08FA0998054EA5505554B35793595A5B695BB361C869776D77702387F9 89E38A728AE7908299ED9AB852BE683850165E78674F8347884C4EAB541156AE 73E6911597FF9909995799995653589F865B8A3161B26AF6737B8ED26B4796AA 9A57595572008D6B97694FD45CF45F2661F8665B6CEB70AB738473B973FE7729 774D7D437D627E2382378852FA0A8CE29249986F5B517A74884098015ACC4FE0 5354593E5CFD633E6D7972F98105810783A292CF98304EA851445211578B0000 FB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005F626CC26ECE7005705070AF719273E97469834A87A28861900890A293A3 99A8516E5F5760E0616766B385598E4A91AF978B4E4E4E92547C58D558FA597D 5CB55F2762366248660A66676BEB6D696DCF6E566EF86F946FE06FE9705D72D0 7425745A74E07693795C7CCA7E1E80E182A6846B84BF864E865F87748B778C6A 93AC9800986560D1621691775A5A660F6DF76E3E743F9B425FFD60DA7B0F54C4 5F186C5E6CD36D2A70D87D0586798A0C9D3B5316548C5B056A3A706B75750000 FC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000798D79BE82B183EF8A718B418CA89774FA0B64F4652B78BA78BB7A6B4E38 559A59505BA65E7B60A363DB6B61666568536E19716574B07D0890849A699C25 6D3B6ED1733E8C4195CA51F05E4C5FA8604D60F66130614C6643664469A56CC1 6E5F6EC96F62714C749C76877BC17C27835287579051968D9EC3532F56DE5EFB 5F8A6062609461F7666667036A9C6DEE6FAE7070736A7E6A81BE833486D48AA8 8CC4528373725B966A6B940454EE56865B5D6548658566C9689F6D8D6DC60000 FD 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000723B80B491759A4D4FAF5019539A540E543C558955C55E3F5F8C673D7166 73DD900552DB52F3586458CE7104718F71FB85B08A13668885A855A76684714A 8431534955996BC15F595FBD63EE668971478AF18F1D9EBE4F11643A70CB7566 866760648B4E9DF8514751F653086D3680F89ED166156B23709875D554035C79 7D078A166B206B3D6B46543860706D3D7FD5820850D651DE559C566B56CD59EC 5B095E0C619961986231665E66E6719971B971BA72A779A77A007FB28A700000 tcl8.4.20/library/encoding/macJapan.enc0000644003604700454610000013563411737050674016366 0ustar dgp771div# Encoding file: macJapan, multi-byte M 003F 0 46 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 0080000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00A0FF61FF62FF63FF64FF65FF66FF67FF68FF69FF6AFF6BFF6CFF6DFF6EFF6F FF70FF71FF72FF73FF74FF75FF76FF77FF78FF79FF7AFF7BFF7CFF7DFF7EFF7F FF80FF81FF82FF83FF84FF85FF86FF87FF88FF89FF8AFF8BFF8CFF8DFF8EFF8F FF90FF91FF92FF93FF94FF95FF96FF97FF98FF99FF9AFF9BFF9CFF9DFF9EFF9F 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000A921222026 81 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 300030013002FF0CFF0E30FBFF1AFF1BFF1FFF01309B309C00B4FF4000A8FF3E 203EFF3F30FD30FE309D309E30034EDD30053006300730FC20142010FF0FFF3C 301C2016FF5C22EF202520182019201C201DFF08FF0930143015FF3BFF3DFF5B FF5D30083009300A300B300C300D300E300F30103011FF0B221200B100D70000 00F7FF1D2260FF1CFF1E22662267221E22342642264000B0203220332103FFE5 FF0400A200A3FF05FF03FF06FF0AFF2000A72606260525CB25CF25CE25C725C6 25A125A025B325B225BD25BC203B301221922190219121933013000000000000 000000000000000000000000000000002208220B2286228722822283222A2229 000000000000000000000000000000002227222800AC21D221D4220022030000 0000000000000000000000000000000000000000222022A52312220222072261 2252226A226B221A223D221D2235222B222C0000000000000000000000000000 212B2030266F266D266A2020202100B6000000000000000025EF000000000000 82 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000FF10 FF11FF12FF13FF14FF15FF16FF17FF18FF190000000000000000000000000000 FF21FF22FF23FF24FF25FF26FF27FF28FF29FF2AFF2BFF2CFF2DFF2EFF2FFF30 FF31FF32FF33FF34FF35FF36FF37FF38FF39FF3A000000000000000000000000 0000FF41FF42FF43FF44FF45FF46FF47FF48FF49FF4AFF4BFF4CFF4DFF4EFF4F FF50FF51FF52FF53FF54FF55FF56FF57FF58FF59FF5A00000000000000003041 30423043304430453046304730483049304A304B304C304D304E304F30503051 30523053305430553056305730583059305A305B305C305D305E305F30603061 30623063306430653066306730683069306A306B306C306D306E306F30703071 30723073307430753076307730783079307A307B307C307D307E307F30803081 30823083308430853086308730883089308A308B308C308D308E308F30903091 3092309300000000000000000000000000000000000000000000000000000000 83 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 30A130A230A330A430A530A630A730A830A930AA30AB30AC30AD30AE30AF30B0 30B130B230B330B430B530B630B730B830B930BA30BB30BC30BD30BE30BF30C0 30C130C230C330C430C530C630C730C830C930CA30CB30CC30CD30CE30CF30D0 30D130D230D330D430D530D630D730D830D930DA30DB30DC30DD30DE30DF0000 30E030E130E230E330E430E530E630E730E830E930EA30EB30EC30ED30EE30EF 30F030F130F230F330F430F530F6000000000000000000000000000000000391 03920393039403950396039703980399039A039B039C039D039E039F03A003A1 03A303A403A503A603A703A803A90000000000000000000000000000000003B1 03B203B303B403B503B603B703B803B903BA03BB03BC03BD03BE03BF03C003C1 03C303C403C503C603C703C803C9000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 84 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 04100411041204130414041504010416041704180419041A041B041C041D041E 041F0420042104220423042404250426042704280429042A042B042C042D042E 042F000000000000000000000000000000000000000000000000000000000000 04300431043204330434043504510436043704380439043A043B043C043D0000 043E043F0440044104420443044404450446044704480449044A044B044C044D 044E044F00000000000000000000000000000000000000000000000000002500 2502250C251025182514251C252C25242534253C25012503250F2513251B2517 25232533252B253B254B2520252F25282537253F251D25302525253825420000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 85 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 2460246124622463246424652466246724682469246A246B246C246D246E246F 2470247124722473000000000000000000000000000000000000000024742475 2476247724782479247A247B247C247D247E247F248024812482248324842485 2486248700000000000000000000000000000000000000002776277727780000 2779277A277B277C277D277E0000000000000000000000000000000000000000 0000F8A124882489248A248B248C248D248E248F249000000000000000002160 216121622163216421652166216721682169216A216BF8A2F8A3F8A400000000 0000000000002170217121722173217421752176217721782179217A217BF8A5 F8A6F8A700000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000249C249D249E249F24A0 24A124A224A324A424A524A624A724A824A924AA24AB24AC24AD24AE24AF24B0 24B124B224B324B424B500000000000000000000000000000000000000000000 86 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 339C339F339D33A033A4F8A833A133A5339E33A2338EF8A9338F33C433963397 F8AA339833B333B233B133B0210933D433CB3390338533863387F8AB00000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000211633CD2121F8AC2664 2667266126622660266326652666000000000000000000000000000000000000 0000000000003020260E30040000000000000000000000000000000000000000 0000000000000000000000000000261E261C261D261F21C621C421C5F8AD21E8 21E621E721E9F8AEF8AFF8B0F8B1000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 87 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 3230322A322B322C322D322E322F32403237324232433239323A3231323E3234 3232323B323632333235323C323D323F32380000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000059275C0F32A432A532A632A732A832A93296329D3298329E63A732993349 3322334D3314331633053333334E330333363318331533273351334A33393357 330D334233233326333B332B00000000000000000000000000003300331E332A 3331334700000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000337E337D337C337B0000000000000000000000000000 0000000000000000000000000000000000000000337FF8B2F8B3000000000000 88 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 222E221F22BF0000000000000000000000000000000000000000000000000000 0000000000000000301DF8B40000000000000000000000000000000000000000 000000000000000000000000000000003094000030F730F830F930FA00000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000004E9C 55165A03963F54C0611B632859F690228475831C7A5060AA63E16E2565ED8466 82A69BF56893572765A162715B9B59D0867B98F47D627DBE9B8E62167C9F88B7 5B895EB563096697684895C7978D674F4EE54F0A4F4D4F9D504956F2593759D4 5A015C0960DF610F61706613690570BA754F757079FB7DAD7DEF80C3840E8863 8B029055907A533B4E954EA557DF80B290C178EF4E0058F16EA290387A328328 828B9C2F5141537054BD54E156E059FB5F1598F26DEB80E4852D000000000000 89 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 9662967096A097FB540B53F35B8770CF7FBD8FC296E8536F9D5C7ABA4E117893 81FC6E26561855046B1D851A9C3B59E553A96D6674DC958F56424E91904B96F2 834F990C53E155B65B305F71662066F368046C386CF36D29745B76C87A4E9834 82F1885B8A6092ED6DB275AB76CA99C560A68B018D8A95B2698E53AD51860000 5712583059445BB45EF6602863A963F46CBF6F14708E7114715971D5733F7E01 827682D185979060925B9D1B586965BC6C5A752551F9592E59655F805FDC62BC 65FA6A2A6B276BB4738B7FC189569D2C9D0E9EC45CA16C96837B51045C4B61B6 81C6687672614E594FFA537860696E297A4F97F34E0B53164EEE4F554F3D4FA1 4F7352A053EF5609590F5AC15BB65BE179D16687679C67B66B4C6CB3706B73C2 798D79BE7A3C7B8782B182DB8304837783EF83D387668AB256298CA88FE6904E 971E868A4FC45CE862117259753B81E582BD86FE8CC096C5991399D54ECB4F1A 89E356DE584A58CA5EFB5FEB602A6094606261D0621262D06539000000000000 8A 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 9B41666668B06D777070754C76867D7582A587F9958B968E8C9D51F152BE5916 54B35BB35D16616869826DAF788D84CB88578A7293A79AB86D6C99A886D957A3 67FF86CE920E5283568754045ED362E164B9683C68386BBB737278BA7A6B899A 89D28D6B8F0390ED95A3969497695B665CB3697D984D984E639B7B206A2B0000 6A7F68B69C0D6F5F5272559D607062EC6D3B6E076ED1845B89108F444E149C39 53F6691B6A3A9784682A515C7AC384B291DC938C565B9D286822830584317CA5 520882C574E64E7E4F8351A05BD2520A52D852E75DFB559A582A59E65B8C5B98 5BDB5E725E7960A3611F616361BE63DB656267D1685368FA6B3E6B536C576F22 6F976F4574B0751876E3770B7AFF7BA17C217DE97F367FF0809D8266839E89B3 8ACC8CAB908494519593959195A2966597D3992882184E38542B5CB85DCC73A9 764C773C5CA97FEB8D0B96C19811985498584F014F0E5371559C566857FA5947 5B095BC45C905E0C5E7E5FCC63EE673A65D765E2671F68CB68C4000000000000 8B 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6A5F5E306BC56C176C7D757F79485B637A007D005FBD898F8A188CB48D778ECC 8F1D98E29A0E9B3C4E80507D510059935B9C622F628064EC6B3A72A075917947 7FA987FB8ABC8B7063AC83CA97A05409540355AB68546A588A70782767759ECD 53745BA2811A865090064E184E454EC74F1153CA54385BAE5F13602565510000 673D6C426C726CE3707874037A767AAE7B087D1A7CFE7D6665E7725B53BB5C45 5DE862D262E063196E20865A8A318DDD92F86F0179A69B5A4EA84EAB4EAC4F9B 4FA050D151477AF6517151F653545321537F53EB55AC58835CE15F375F4A602F 6050606D631F65596A4B6CC172C272ED77EF80F881058208854E90F793E197FF 99579A5A4EF051DD5C2D6681696D5C4066F26975738968507C8150C552E45747 5DFE932665A46B236B3D7434798179BD7B4B7DCA82B983CC887F895F8B398FD1 91D1541F92804E5D503653E5533A72D7739677E982E68EAF99C699C899D25177 611A865E55B07A7A50765BD3904796854E326ADB91E75C515C48000000000000 8C 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 63987A9F6C9397748F617AAA718A96887C8268177E706851936C52F2541B85AB 8A137FA48ECD90E15366888879414FC250BE521151445553572D73EA578B5951 5F625F8460756176616761A963B2643A656C666F68426E1375667A3D7CFB7D4C 7D997E4B7F6B830E834A86CD8A088A638B668EFD981A9D8F82B88FCE9BE80000 5287621F64836FC09699684150916B206C7A6F547A747D5088408A2367084EF6 503950265065517C5238526355A7570F58055ACC5EFA61B261F862F36372691C 6A29727D72AC732E7814786F7D79770C80A9898B8B198CE28ED290639375967A 98559A139E785143539F53B35E7B5F266E1B6E90738473FE7D4382378A008AFA 96504E4E500B53E4547C56FA59D15B645DF15EAB5F276238654567AF6E5672D0 7CCA88B480A180E183F0864E8A878DE8923796C798679F134E944E924F0D5348 5449543E5A2F5F8C5FA1609F68A76A8E745A78818A9E8AA48B7791904E5E9BC9 4EA44F7C4FAF501950165149516C529F52B952FE539A53E35411000000000000 8D 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 540E5589575157A2597D5B545B5D5B8F5DE55DE75DF75E785E835E9A5EB75F18 6052614C629762D863A7653B6602664366F4676D6821689769CB6C5F6D2A6D69 6E2F6E9D75327687786C7A3F7CE07D057D187D5E7DB18015800380AF80B18154 818F822A8352884C88618B1B8CA28CFC90CA91759271783F92FC95A4964D0000 980599999AD89D3B525B52AB53F7540858D562F76FE08C6A8F5F9EB9514B523B 544A56FD7A4091779D609ED273446F09817075115FFD60DA9AA872DB8FBC6B64 98034ECA56F0576458BE5A5A606861C7660F6606683968B16DF775D57D3A826E 9B424E9B4F5053C955065D6F5DE65DEE67FB6C99747378028A50939688DF5750 5EA7632B50B550AC518D670054C9585E59BB5BB05F69624D63A1683D6B736E08 707D91C7728078157826796D658E7D3083DC88C18F09969B5264572867507F6A 8CA151B45742962A583A698A80B454B25D0E57FC78959DFA4F5C524A548B643E 6628671467F57A847B567D22932F685C9BAD7B395319518A5237000000000000 8E 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5BDF62F664AE64E6672D6BBA85A996D176909BD6634C93069BAB76BF66524E09 509853C25C7160E864926563685F71E673CA75237B977E8286958B838CDB9178 991065AC66AB6B8B4ED54ED44F3A4F7F523A53F853F255E356DB58EB59CB59C9 59FF5B505C4D5E025E2B5FD7601D6307652F5B5C65AF65BD65E8679D6B620000 6B7B6C0F7345794979C17CF87D197D2B80A2810281F389968A5E8A698A668A8C 8AEE8CC78CDC96CC98FC6B6F4E8B4F3C4F8D51505B575BFA6148630166426B21 6ECB6CBB723E74BD75D478C1793A800C803381EA84948F9E6C509E7F5F0F8B58 9D2B7AFA8EF85B8D96EB4E0353F157F759315AC95BA460896E7F6F0675BE8CEA 5B9F85007BE0507267F4829D5C61854A7E1E820E51995C0463688D66659C716E 793E7D1780058B1D8ECA906E86C790AA501F52FA5C3A6753707C7235914C91C8 932B82E55BC25F3160F94E3B53D65B88624B67316B8A72E973E07A2E816B8DA3 91529996511253D7546A5BFF63886A397DAC970056DA53CE5468000000000000 8F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5B975C315DDE4FEE610162FE6D3279C079CB7D427E4D7FD281ED821F84908846 89728B908E748F2F9031914B916C96C6919C4EC04F4F514553415F93620E67D4 6C416E0B73637E2691CD928353D459195BBF6DD1795D7E2E7C9B587E719F51FA 88538FF04FCA5CFB662577AC7AE3821C99FF51C65FAA65EC696F6B896DF30000 6E966F6476FE7D145DE190759187980651E6521D6240669166D96E1A5EB67DD2 7F7266F885AF85F78AF852A953D959735E8F5F90605592E4966450B7511F52DD 5320534753EC54E8554655315617596859BE5A3C5BB55C065C0F5C115C1A5E84 5E8A5EE05F70627F628462DB638C63776607660C662D6676677E68A26A1F6A35 6CBC6D886E096E58713C7126716775C77701785D7901796579F07AE07B117CA7 7D39809683D6848B8549885D88F38A1F8A3C8A548A738C618CDE91A49266937E 9418969C97984E0A4E084E1E4E575197527057CE583458CC5B225E3860C564FE 676167566D4472B675737A6384B88B7291B89320563157F498FE000000000000 90 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 62ED690D6B9671ED7E548077827289E698DF87558FB15C3B4F384FE14FB55507 5A205BDD5BE95FC3614E632F65B0664B68EE699B6D786DF1753375B9771F795E 79E67D3381E382AF85AA89AA8A3A8EAB8F9B903291DD97074EBA4EC152035875 58EC5C0B751A5C3D814E8A0A8FC59663976D7B258ACF9808916256F353A80000 9017543957825E2563A86C34708A77617C8B7FE088709042915493109318968F 745E9AC45D075D69657067A28DA896DB636E6749691983C5981796C088FE6F84 647A5BF84E16702C755D662F51C4523652E259D35F8160276210653F6574661F 667468F268166B636E057272751F76DB7CBE805658F088FD897F8AA08A938ACB 901D91929752975965897A0E810696BB5E2D60DC621A65A56614679077F37A4D 7C4D7E3E810A8CAC8D648DE18E5F78A9520762D963A5644262988A2D7A837BC0 8AAC96EA7D76820C87494ED95148534353605BA35C025C165DDD6226624764B0 681368346CC96D456D1767D36F5C714E717D65CB7A7F7BAD7DDA000000000000 91 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7E4A7FA8817A821B823985A68A6E8CCE8DF59078907792AD929195839BAE524D 55846F387136516879857E5581B37CCE564C58515CA863AA66FE66FD695A72D9 758F758E790E795679DF7C977D207D4486078A34963B90619F2050E7527553CC 53E2500955AA58EE594F723D5B8B5C64531D60E360F3635C6383633F63BB0000 64CD65E966F95DE369CD69FD6F1571E54E8975E976F87A937CDF7DCF7D9C8061 83498358846C84BC85FB88C58D709001906D9397971C9A1250CF5897618E81D3 85358D0890204FC3507452475373606F6349675F6E2C8DB3901F4FD75C5E8CCA 65CF7D9A53528896517663C35B585B6B5C0A640D6751905C4ED6591A592A6C70 8A51553E581559A560F0625367C182356955964099C49A284F5358065BFE8010 5CB15E2F5F856020614B623466FF6CF06EDE80CE817F82D4888B8CB89000902E 968A9EDB9BDB4EE353F059277B2C918D984C9DF96EDD7027535355445B856258 629E62D36CA26FEF74228A1794386FC18AFE833851E786F853EA000000000000 92 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 53E94F4690548FB0596A81315DFD7AEA8FBF68DA8C3772F89C486A3D8AB04E39 53585606576662C563A265E66B4E6DE16E5B70AD77ED7AEF7BAA7DBB803D80C6 86CB8A95935B56E358C75F3E65AD66966A806BB575378AC7502477E557305F1B 6065667A6C6075F47A1A7F6E81F48718904599B37BC9755C7AF97B5184C40000 901079E97A9283365AE177404E2D4EF25B995FE062BD663C67F16CE8866B8877 8A3B914E92F399D06A177026732A82E784578CAF4E01514651CB558B5BF55E16 5E335E815F145F355F6B5FB461F2631166A2671D6F6E7252753A773A80748139 817887768ABF8ADC8D858DF3929A957798029CE552C5635776F467156C8873CD 8CC393AE96736D25589C690E69CC8FFD939A75DB901A585A680263B469FB4F43 6F2C67D88FBB85267DB49354693F6F70576A58F75B2C7D2C722A540A91E39DB4 4EAD4F4E505C507552438C9E544858245B9A5E1D5E955EAD5EF75F1F608C62B5 633A63D068AF6C407887798E7A0B7DE082478A028AE68E449013000000000000 93 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 90B8912D91D89F0E6CE5645864E265756EF476847B1B906993D16EBA54F25FB9 64A48F4D8FED92445178586B59295C555E976DFB7E8F751C8CBC8EE2985B70B9 4F1D6BBF6FB1753096FB514E54105835585759AC5C605F926597675C6E21767B 83DF8CED901490FD934D7825783A52AA5EA6571F597460125012515A51AC0000 51CD520055105854585859575B955CF65D8B60BC6295642D6771684368BC68DF 76D76DD86E6F6D9B706F71C85F5375D879777B497B547B527CD67D7152308463 856985E48A0E8B048C468E0F9003900F94199676982D9A3095D850CD52D5540C 58025C0E61A7649E6D1E77B37AE580F48404905392855CE09D07533F5F975FB3 6D9C7279776379BF7BE46BD272EC8AAD68036A6151F87A8169345C4A9CF682EB 5BC59149701E56785C6F60C765666C8C8C5A90419813545166C7920D594890A3 51854E4D51EA85998B0E7058637A934B696299B47E047577535769608EDF96E3 6C5D4E8C5C3C5F108FE953028CD1808986795EFF65E54E735165000000000000 94 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 59825C3F97EE4EFB598A5FCD8A8D6FE179B079625BE78471732B71B15E745FF5 637B649A71C37C984E435EFC4E4B57DC56A260A96FC37D0D80FD813381BF8FB2 899786A45DF4628A64AD898767776CE26D3E743678345A467F7582AD99AC4FF3 5EC362DD63926557676F76C3724C80CC80BA8F29914D500D57F95A9268850000 6973716472FD8CB758F28CE0966A9019877F79E477E784294F2F5265535A62CD 67CF6CCA767D7B947C95823685848FEB66DD6F2072067E1B83AB99C19EA651FD 7BB178727BB880877B486AE85E61808C75517560516B92626E8C767A91979AEA 4F107F70629C7B4F95A59CE9567A585986E496BC4F345224534A53CD53DB5E06 642C6591677F6C3E6C4E724872AF73ED75547E41822C85E98CA97BC491C67169 981298EF633D6669756A76E478D0854386EE532A5351542659835E875F7C60B2 6249627962AB65906BD46CCC75B276AE789179D87DCB7F7780A588AB8AB98CBB 907F975E98DB6A0B7C3850995C3E5FAE67876BD8743577097F8E000000000000 95 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 9F3B67CA7A175339758B9AED5F66819D83F180985F3C5FC575627B46903C6867 59EB5A9B7D10767E8B2C4FF55F6A6A196C376F0274E2796888688A558C795EDF 63CF75C579D282D7932892F2849C86ED9C2D54C15F6C658C6D5C70158CA78CD3 983B654F74F64E0D4ED857E0592B5A665BCC51A85E035E9C6016627665770000 65A7666E6D6E72367B268150819A82998B5C8CA08CE68D74961C96444FAE64AB 6B66821E8461856A90E85C01695398A8847A85574F0F526F5FA95E45670D798F 8179890789866DF55F1762556CB84ECF72699B925206543B567458B361A4626E 711A596E7C897CDE7D1B96F06587805E4E194F75517558405E635E735F0A67C4 4E26853D9589965B7C73980150FB58C1765678A7522577A585117B86504F5909 72477BC77DE88FBA8FD4904D4FBF52C95A295F0197AD4FDD821792EA57036355 6B69752B88DC8F147A4252DF58936155620A66AE6BCD7C3F83E950234FF85305 5446583159495B9D5CF05CEF5D295E9662B16367653E65B9670B000000000000 96 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6CD56CE170F978327E2B80DE82B3840C84EC870289128A2A8C4A90A692D298FD 9CF39D6C4E4F4EA1508D5256574A59A85E3D5FD85FD9623F66B4671B67D068D2 51927D2180AA81A88B008C8C8CBF927E96325420982C531750D5535C58A864B2 6734726777667A4691E652C36CA16B8658005E4C5954672C7FFB51E176C60000 646978E89B549EBB57CB59B96627679A6BCE54E969D95E55819C67959BAA67FE 9C52685D4EA64FE353C862B9672B6CAB8FC44FAD7E6D9EBF4E0761626E806F2B 85135473672A9B455DF37B955CAC5BC6871C6E4A84D17A14810859997C8D6C11 772052D959227121725F77DB97279D61690B5A7F5A1851A5540D547D660E76DF 8FF792989CF459EA725D6EC5514D68C97DBF7DEC97629EBA64786A2183025984 5B5F6BDB731B76F27DB280178499513267289ED976EE676252FF99055C24623B 7C7E8CB0554F60B67D0B958053014E5F51B6591C723A803691CE5F2577E25384 5F797D0485AC8A338E8D975667F385AE9453610961086CB97652000000000000 97 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8AED8F38552F4F51512A52C753CB5BA55E7D60A0618263D6670967DA6E676D8C 733673377531795088D58A98904A909190F596C4878D59154E884F594E0E8A89 8F3F981050AD5E7C59965BB95EB863DA63FA64C166DC694A69D86D0B6EB67194 75287AAF7F8A8000844984C989818B218E0A9065967D990A617E62916B320000 6C836D747FCC7FFC6DC07F8587BA88F8676583B1983C96F76D1B7D61843D916A 4E7153755D506B046FEB85CD862D89A75229540F5C65674E68A87406748375E2 88CF88E191CC96E296785F8B73877ACB844E63A0756552896D416E9C74097559 786B7C9296867ADC9F8D4FB6616E65C5865C4E864EAE50DA4E2151CC5BEE6599 68816DBC731F764277AD7A1C7CE7826F8AD2907C91CF96759818529B7DD1502B 539867976DCB71D0743381E88F2A96A39C579E9F746058416D997D2F985E4EE4 4F364F8B51B752B15DBA601C73B2793C82D3923496B796F6970A9E979F6266A6 6B74521752A370C888C25EC9604B61906F2371497C3E7DF4806F000000000000 98 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 84EE9023932C54429B6F6AD370898CC28DEF973252B45A415ECA5F046717697C 69946D6A6F0F726272FC7BED8001807E874B90CE516D9E937984808B93328AD6 502D548C8A716B6A8CC4810760D167A09DF24E994E989C108A6B85C185686900 6E7E789781550000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000005F0C 4E104E154E2A4E314E364E3C4E3F4E424E564E584E824E858C6B4E8A82125F0D 4E8E4E9E4E9F4EA04EA24EB04EB34EB64ECE4ECD4EC44EC64EC24ED74EDE4EED 4EDF4EF74F094F5A4F304F5B4F5D4F574F474F764F884F8F4F984F7B4F694F70 4F914F6F4F864F9651184FD44FDF4FCE4FD84FDB4FD14FDA4FD04FE44FE5501A 50285014502A502550054F1C4FF650215029502C4FFE4FEF5011500650435047 6703505550505048505A5056506C50785080509A508550B450B2000000000000 99 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 50C950CA50B350C250D650DE50E550ED50E350EE50F950F55109510151025116 51155114511A5121513A5137513C513B513F51405152514C515451627AF85169 516A516E5180518256D8518C5189518F519151935195519651A451A651A251A9 51AA51AB51B351B151B251B051B551BD51C551C951DB51E0865551E951ED0000 51F051F551FE5204520B5214520E5227522A522E52335239524F5244524B524C 525E5254526A527452695273527F527D528D529452925271528852918FA88FA7 52AC52AD52BC52B552C152CD52D752DE52E352E698ED52E052F352F552F852F9 530653087538530D5310530F5315531A5323532F533153335338534053465345 4E175349534D51D6535E5369536E5918537B53775382539653A053A653A553AE 53B053B653C37C1296D953DF66FC71EE53EE53E853ED53FA5401543D5440542C 542D543C542E54365429541D544E548F5475548E545F5471547754705492547B 5480547654845490548654C754A254B854A554AC54C454C854A8000000000000 9A 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 54AB54C254A454BE54BC54D854E554E6550F551454FD54EE54ED54FA54E25539 55405563554C552E555C55455556555755385533555D5599558054AF558A559F 557B557E5598559E55AE557C558355A9558755A855DA55C555DF55C455DC55E4 55D4561455F7561655FE55FD561B55F9564E565071DF56345636563256380000 566B5664562F566C566A56865680568A56A05694568F56A556AE56B656B456C2 56BC56C156C356C056C856CE56D156D356D756EE56F9570056FF570457095708 570B570D57135718571655C7571C572657375738574E573B5740574F576957C0 57885761577F5789579357A057B357A457AA57B057C357C657D457D257D3580A 57D657E3580B5819581D587258215862584B58706BC05852583D5879588558B9 589F58AB58BA58DE58BB58B858AE58C558D358D158D758D958D858E558DC58E4 58DF58EF58FA58F958FB58FC58FD5902590A5910591B68A65925592C592D5932 5938593E7AD259555950594E595A5958596259605967596C5969000000000000 9B 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 59785981599D4F5E4FAB59A359B259C659E859DC598D59D959DA5A255A1F5A11 5A1C5A095A1A5A405A6C5A495A355A365A625A6A5A9A5ABC5ABE5ACB5AC25ABD 5AE35AD75AE65AE95AD65AFA5AFB5B0C5B0B5B165B325AD05B2A5B365B3E5B43 5B455B405B515B555B5A5B5B5B655B695B705B735B755B7865885B7A5B800000 5B835BA65BB85BC35BC75BC95BD45BD05BE45BE65BE25BDE5BE55BEB5BF05BF6 5BF35C055C075C085C0D5C135C205C225C285C385C395C415C465C4E5C535C50 5C4F5B715C6C5C6E4E625C765C795C8C5C915C94599B5CAB5CBB5CB65CBC5CB7 5CC55CBE5CC75CD95CE95CFD5CFA5CED5D8C5CEA5D0B5D155D175D5C5D1F5D1B 5D115D145D225D1A5D195D185D4C5D525D4E5D4B5D6C5D735D765D875D845D82 5DA25D9D5DAC5DAE5DBD5D905DB75DBC5DC95DCD5DD35DD25DD65DDB5DEB5DF2 5DF55E0B5E1A5E195E115E1B5E365E375E445E435E405E4E5E575E545E5F5E62 5E645E475E755E765E7A9EBC5E7F5EA05EC15EC25EC85ED05ECF000000000000 9C 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5ED65EE35EDD5EDA5EDB5EE25EE15EE85EE95EEC5EF15EF35EF05EF45EF85EFE 5F035F095F5D5F5C5F0B5F115F165F295F2D5F385F415F485F4C5F4E5F2F5F51 5F565F575F595F615F6D5F735F775F835F825F7F5F8A5F885F915F875F9E5F99 5F985FA05FA85FAD5FBC5FD65FFB5FE45FF85FF15FDD60B35FFF602160600000 601960106029600E6031601B6015602B6026600F603A605A6041606A6077605F 604A6046604D6063604360646042606C606B60596081608D60E76083609A6084 609B60966097609260A7608B60E160B860E060D360B45FF060BD60C660B560D8 614D6115610660F660F7610060F460FA6103612160FB60F1610D610E6147613E 61286127614A613F613C612C6134613D614261446173617761586159615A616B 6174616F61656171615F615D6153617561996196618761AC6194619A618A6191 61AB61AE61CC61CA61C961F761C861C361C661BA61CB7F7961CD61E661E361F6 61FA61F461FF61FD61FC61FE620062086209620D620C6214621B000000000000 9D 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 621E6221622A622E6230623262336241624E625E6263625B62606268627C6282 6289627E62926293629662D46283629462D762D162BB62CF62FF62C664D462C8 62DC62CC62CA62C262C7629B62C9630C62EE62F163276302630862EF62F56350 633E634D641C634F6396638E638063AB637663A3638F6389639F63B5636B0000 636963BE63E963C063C663E363C963D263F663C4641664346406641364266436 651D64176428640F6467646F6476644E652A6495649364A564A9648864BC64DA 64D264C564C764BB64D864C264F164E7820964E064E162AC64E364EF652C64F6 64F464F264FA650064FD6518651C650565246523652B65346535653765366538 754B654865566555654D6558655E655D65726578658265838B8A659B659F65AB 65B765C365C665C165C465CC65D265DB65D965E065E165F16772660A660365FB 6773663566366634661C664F664466496641665E665D666466676668665F6662 667066836688668E668966846698669D66C166B966C966BE66BC000000000000 9E 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 66C466B866D666DA66E0663F66E666E966F066F566F7670F6716671E67266727 9738672E673F67366741673867376746675E67606759676367646789677067A9 677C676A678C678B67A667A1678567B767EF67B467EC67B367E967B867E467DE 67DD67E267EE67B967CE67C667E76A9C681E684668296840684D6832684E0000 68B3682B685968636877687F689F688F68AD6894689D689B68836AAE68B96874 68B568A068BA690F688D687E690168CA690868D86922692668E1690C68CD68D4 68E768D569366912690468D768E3692568F968E068EF6928692A691A69236921 68C669796977695C6978696B6954697E696E69396974693D695969306961695E 695D6981696A69B269AE69D069BF69C169D369BE69CE5BE869CA69DD69BB69C3 69A76A2E699169A0699C699569B469DE69E86A026A1B69FF6B0A69F969F269E7 6A0569B16A1E69ED6A1469EB6A0A6A126AC16A236A136A446A0C6A726A366A78 6A476A626A596A666A486A386A226A906A8D6AA06A846AA26AA3000000000000 9F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6A9786176ABB6AC36AC26AB86AB36AAC6ADE6AD16ADF6AAA6ADA6AEA6AFB6B05 86166AFA6B126B169B316B1F6B386B3776DC6B3998EE6B476B436B496B506B59 6B546B5B6B5F6B616B786B796B7F6B806B846B836B8D6B986B956B9E6BA46BAA 6BAB6BAF6BB26BB16BB36BB76BBC6BC66BCB6BD36BDF6BEC6BEB6BF36BEF0000 9EBE6C086C136C146C1B6C246C236C5E6C556C626C6A6C826C8D6C9A6C816C9B 6C7E6C686C736C926C906CC46CF16CD36CBD6CD76CC56CDD6CAE6CB16CBE6CBA 6CDB6CEF6CD96CEA6D1F884D6D366D2B6D3D6D386D196D356D336D126D0C6D63 6D936D646D5A6D796D596D8E6D956FE46D856DF96E156E0A6DB56DC76DE66DB8 6DC66DEC6DDE6DCC6DE86DD26DC56DFA6DD96DE46DD56DEA6DEE6E2D6E6E6E2E 6E196E726E5F6E3E6E236E6B6E2B6E766E4D6E1F6E436E3A6E4E6E246EFF6E1D 6E386E826EAA6E986EC96EB76ED36EBD6EAF6EC46EB26ED46ED56E8F6EA56EC2 6E9F6F416F11704C6EEC6EF86EFE6F3F6EF26F316EEF6F326ECC000000000000 E0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6F3E6F136EF76F866F7A6F786F816F806F6F6F5B6FF36F6D6F826F7C6F586F8E 6F916FC26F666FB36FA36FA16FA46FB96FC66FAA6FDF6FD56FEC6FD46FD86FF1 6FEE6FDB7009700B6FFA70117001700F6FFE701B701A6F74701D7018701F7030 703E7032705170637099709270AF70F170AC70B870B370AE70DF70CB70DD0000 70D9710970FD711C711971657155718871667162714C7156716C718F71FB7184 719571A871AC71D771B971BE71D271C971D471CE71E071EC71E771F571FC71F9 71FF720D7210721B7228722D722C72307232723B723C723F72407246724B7258 7274727E7282728172877292729672A272A772B972B272C372C672C472CE72D2 72E272E072E172F972F7500F7317730A731C7316731D7334732F73297325733E 734E734F9ED87357736A7368737073787375737B737A73C873B373CE73BB73C0 73E573EE73DE74A27405746F742573F87432743A7455743F745F74597441745C 746974707463746A7476747E748B749E74A774CA74CF74D473F1000000000000 E1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 74E074E374E774E974EE74F274F074F174F874F7750475037505750C750E750D 75157513751E7526752C753C7544754D754A7549755B7546755A756975647567 756B756D75787576758675877574758A758975827594759A759D75A575A375C2 75B375C375B575BD75B875BC75B175CD75CA75D275D975E375DE75FE75FF0000 75FC760175F075FA75F275F3760B760D7609761F762776207621762276247634 7630763B764776487646765C76587661766276687669766A7667766C76707672 76767678767C768076837688768B768E769676937699769A76B076B476B876B9 76BA76C276CD76D676D276DE76E176E576E776EA862F76FB7708770777047729 7724771E77257726771B773777387747775A7768776B775B7765777F777E7779 778E778B779177A0779E77B077B677B977BF77BC77BD77BB77C777CD77D777DA 77DC77E377EE77FC780C781279267820792A7845788E78747886787C789A788C 78A378B578AA78AF78D178C678CB78D478BE78BC78C578CA78EC000000000000 E2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 78E778DA78FD78F47907791279117919792C792B794079607957795F795A7955 7953797A797F798A799D79A79F4B79AA79AE79B379B979BA79C979D579E779EC 79E179E37A087A0D7A187A197A207A1F79807A317A3B7A3E7A377A437A577A49 7A617A627A699F9D7A707A797A7D7A887A977A957A987A967AA97AC87AB00000 7AB67AC57AC47ABF90837AC77ACA7ACD7ACF7AD57AD37AD97ADA7ADD7AE17AE2 7AE67AED7AF07B027B0F7B0A7B067B337B187B197B1E7B357B287B367B507B7A 7B047B4D7B0B7B4C7B457B757B657B747B677B707B717B6C7B6E7B9D7B987B9F 7B8D7B9C7B9A7B8B7B927B8F7B5D7B997BCB7BC17BCC7BCF7BB47BC67BDD7BE9 7C117C147BE67BE57C607C007C077C137BF37BF77C177C0D7BF67C237C277C2A 7C1F7C377C2B7C3D7C4C7C437C547C4F7C407C507C587C5F7C647C567C657C6C 7C757C837C907CA47CAD7CA27CAB7CA17CA87CB37CB27CB17CAE7CB97CBD7CC0 7CC57CC27CD87CD27CDC7CE29B3B7CEF7CF27CF47CF67CFA7D06000000000000 E3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7D027D1C7D157D0A7D457D4B7D2E7D327D3F7D357D467D737D567D4E7D727D68 7D6E7D4F7D637D937D897D5B7D8F7D7D7D9B7DBA7DAE7DA37DB57DC77DBD7DAB 7E3D7DA27DAF7DDC7DB87D9F7DB07DD87DDD7DE47DDE7DFB7DF27DE17E057E0A 7E237E217E127E317E1F7E097E0B7E227E467E667E3B7E357E397E437E370000 7E327E3A7E677E5D7E567E5E7E597E5A7E797E6A7E697E7C7E7B7E837DD57E7D 8FAE7E7F7E887E897E8C7E927E907E937E947E967E8E7E9B7E9C7F387F3A7F45 7F4C7F4D7F4E7F507F517F557F547F587F5F7F607F687F697F677F787F827F86 7F837F887F877F8C7F947F9E7F9D7F9A7FA37FAF7FB27FB97FAE7FB67FB88B71 7FC57FC67FCA7FD57FD47FE17FE67FE97FF37FF998DC80068004800B80128018 8019801C80218028803F803B804A804680528058805A805F8062806880738072 807080768079807D807F808480868085809B8093809A80AD519080AC80DB80E5 80D980DD80C480DA80D6810980EF80F1811B81298123812F814B000000000000 E4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 968B8146813E8153815180FC8171816E81658166817481838188818A81808182 81A0819581A481A3815F819381A981B081B581BE81B881BD81C081C281BA81C9 81CD81D181D981D881C881DA81DF81E081E781FA81FB81FE8201820282058207 820A820D821082168229822B82388233824082598258825D825A825F82640000 82628268826A826B822E827182778278827E828D829282AB829F82BB82AC82E1 82E382DF82D282F482F382FA8393830382FB82F982DE830682DC830982D98335 83348316833283318340833983508345832F832B831783188385839A83AA839F 83A283968323838E8387838A837C83B58373837583A0838983A883F4841383EB 83CE83FD840383D8840B83C183F7840783E083F2840D8422842083BD84388506 83FB846D842A843C855A84848477846B84AD846E848284698446842C846F8479 843584CA846284B984BF849F84D984CD84BB84DA84D084C184C684D684A18521 84FF84F485178518852C851F8515851484FC8540856385588548000000000000 E5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 85418602854B8555858085A485888591858A85A8856D8594859B85EA8587859C 8577857E859085C985BA85CF85B985D085D585DD85E585DC85F9860A8613860B 85FE85FA86068622861A8630863F864D4E558654865F86678671869386A386A9 86AA868B868C86B686AF86C486C686B086C9882386AB86D486DE86E986EC0000 86DF86DB86EF8712870687088700870386FB87118709870D86F9870A8734873F 8737873B87258729871A8760875F8778874C874E877487578768876E87598753 8763876A880587A2879F878287AF87CB87BD87C087D096D687AB87C487B387C7 87C687BB87EF87F287E0880F880D87FE87F687F7880E87D28811881688158822 88218831883688398827883B8844884288528859885E8862886B8881887E889E 8875887D88B5887288828897889288AE889988A2888D88A488B088BF88B188C3 88C488D488D888D988DD88F9890288FC88F488E888F28904890C890A89138943 891E8925892A892B89418944893B89368938894C891D8960895E000000000000 E6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 89668964896D896A896F89748977897E89838988898A8993899889A189A989A6 89AC89AF89B289BA89BD89BF89C089DA89DC89DD89E789F489F88A038A168A10 8A0C8A1B8A1D8A258A368A418A5B8A528A468A488A7C8A6D8A6C8A628A858A82 8A848AA88AA18A918AA58AA68A9A8AA38AC48ACD8AC28ADA8AEB8AF38AE70000 8AE48AF18B148AE08AE28AF78ADE8ADB8B0C8B078B1A8AE18B168B108B178B20 8B3397AB8B268B2B8B3E8B288B418B4C8B4F8B4E8B498B568B5B8B5A8B6B8B5F 8B6C8B6F8B748B7D8B808B8C8B8E8B928B938B968B998B9A8C3A8C418C3F8C48 8C4C8C4E8C508C558C628C6C8C788C7A8C828C898C858C8A8C8D8C8E8C948C7C 8C98621D8CAD8CAA8CBD8CB28CB38CAE8CB68CC88CC18CE48CE38CDA8CFD8CFA 8CFB8D048D058D0A8D078D0F8D0D8D109F4E8D138CCD8D148D168D678D6D8D71 8D738D818D998DC28DBE8DBA8DCF8DDA8DD68DCC8DDB8DCB8DEA8DEB8DDF8DE3 8DFC8E088E098DFF8E1D8E1E8E108E1F8E428E358E308E348E4A000000000000 E7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8E478E498E4C8E508E488E598E648E608E2A8E638E558E768E728E7C8E818E87 8E858E848E8B8E8A8E938E918E948E998EAA8EA18EAC8EB08EC68EB18EBE8EC5 8EC88ECB8EDB8EE38EFC8EFB8EEB8EFE8F0A8F058F158F128F198F138F1C8F1F 8F1B8F0C8F268F338F3B8F398F458F428F3E8F4C8F498F468F4E8F578F5C0000 8F628F638F648F9C8F9F8FA38FAD8FAF8FB78FDA8FE58FE28FEA8FEF90878FF4 90058FF98FFA901190159021900D901E9016900B90279036903590398FF8904F 905090519052900E9049903E90569058905E9068906F907696A890729082907D 90819080908A9089908F90A890AF90B190B590E290E4624890DB910291129119 91329130914A9156915891639165916991739172918B9189918291A291AB91AF 91AA91B591B491BA91C091C191C991CB91D091D691DF91E191DB91FC91F591F6 921E91FF9214922C92159211925E925792459249926492489295923F924B9250 929C92969293929B925A92CF92B992B792E9930F92FA9344932E000000000000 E8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 93199322931A9323933A9335933B935C9360937C936E935693B093AC93AD9394 93B993D693D793E893E593D893C393DD93D093C893E4941A9414941394039407 94109436942B94359421943A944194529444945B94609462945E946A92299470 94759477947D945A947C947E9481947F95829587958A95949596959895990000 95A095A895A795AD95BC95BB95B995BE95CA6FF695C395CD95CC95D595D495D6 95DC95E195E595E296219628962E962F9642964C964F964B9677965C965E965D 965F96669672966C968D96989695969796AA96A796B196B296B096B496B696B8 96B996CE96CB96C996CD894D96DC970D96D596F99704970697089713970E9711 970F971697199724972A97309739973D973E97449746974897429749975C9760 97649766976852D2976B977197799785977C9781977A9786978B978F9790979C 97A897A697A397B397B497C397C697C897CB97DC97ED9F4F97F27ADF97F697F5 980F980C9838982498219837983D9846984F984B986B986F9870000000000000 E9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 98719874987398AA98AF98B198B698C498C398C698E998EB9903990999129914 99189921991D991E99249920992C992E993D993E9942994999459950994B9951 9952994C99559997999899A599AD99AE99BC99DF99DB99DD99D899D199ED99EE 99F199F299FB99F89A019A0F9A0599E29A199A2B9A379A459A429A409A430000 9A3E9A559A4D9A5B9A579A5F9A629A659A649A699A6B9A6A9AAD9AB09ABC9AC0 9ACF9AD19AD39AD49ADE9ADF9AE29AE39AE69AEF9AEB9AEE9AF49AF19AF79AFB 9B069B189B1A9B1F9B229B239B259B279B289B299B2A9B2E9B2F9B329B449B43 9B4F9B4D9B4E9B519B589B749B939B839B919B969B979B9F9BA09BA89BB49BC0 9BCA9BB99BC69BCF9BD19BD29BE39BE29BE49BD49BE19C3A9BF29BF19BF09C15 9C149C099C139C0C9C069C089C129C0A9C049C2E9C1B9C259C249C219C309C47 9C329C469C3E9C5A9C609C679C769C789CE79CEC9CF09D099D089CEB9D039D06 9D2A9D269DAF9D239D1F9D449D159D129D419D3F9D3E9D469D48000000000000 EA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 9D5D9D5E9D649D519D509D599D729D899D879DAB9D6F9D7A9D9A9DA49DA99DB2 9DC49DC19DBB9DB89DBA9DC69DCF9DC29DD99DD39DF89DE69DED9DEF9DFD9E1A 9E1B9E1E9E759E799E7D9E819E889E8B9E8C9E929E959E919E9D9EA59EA99EB8 9EAA9EAD97619ECC9ECE9ECF9ED09ED49EDC9EDE9EDD9EE09EE59EE89EEF0000 9EF49EF69EF79EF99EFB9EFC9EFD9F079F0876B79F159F219F2C9F3E9F4A9F52 9F549F639F5F9F609F619F669F679F6C9F6A9F779F729F769F959F9C9FA0582F 69C79059746451DC719900000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 EB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000F8B5F8B60000000000000000000000000000000000000000000000000000 F8B7FE33000000000000000000000000000000000000F8B8FE31F8B900000000 F8BAF8BBF8BCF8BDFE300000000000000000FE35FE36FE39FE3AF8BEF8BFFE37 FE38FE3FFE40FE3DFE3EFE41FE42FE43FE44FE3BFE3C00000000000000000000 0000F8C000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 EC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000F8C1 0000F8C20000F8C30000F8C40000F8C500000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000F8C600000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000F8C70000F8C80000F8C9000000000000000000000000F8CA000000000000 0000000000000000000000000000000000000000000000000000000000000000 ED 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 F8CB0000F8CC0000F8CD0000F8CE0000F8CF0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000F8D00000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000F8D10000F8D20000F8D3000000000000000000000000F8D40000 00000000000000000000F8D5F8D6000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 tcl8.4.20/library/encoding/big5.enc0000644003604700454610000026531111737050674015476 0ustar dgp771div# Encoding file: big5, multi-byte M 003F 0 89 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 0080008100820083008400850086008700880089008A008B008C008D008E008F 0090009100920093009400950096009700980099009A009B009C009D009E009F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 A1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 3000FF0C30013002FF0E2022FF1BFF1AFF1FFF01FE3020262025FE50FF64FE52 00B7FE54FE55FE56FE57FF5C2013FE312014FE33FFFDFE34FE4FFF08FF09FE35 FE36FF5BFF5DFE37FE3830143015FE39FE3A30103011FE3BFE3C300A300BFE3D FE3E30083009FE3FFE40300C300DFE41FE42300E300FFE43FE44FE59FE5A0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FE5BFE5CFE5DFE5E20182019201C201D301D301E20352032FF03FF06FF0A 203B00A7300325CB25CF25B325B225CE2606260525C725C625A125A025BD25BC 32A32105203EFFFDFF3FFFFDFE49FE4AFE4DFE4EFE4BFE4CFE5FFE60FE61FF0B FF0D00D700F700B1221AFF1CFF1EFF1D226622672260221E22522261FE62FE63 FE64FE65FE66223C2229222A22A52220221F22BF33D233D1222B222E22352234 26402642264126092191219321902192219621972199219822252223FFFD0000 A2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 FFFDFF0FFF3CFF0400A5301200A200A3FF05FF2021032109FE69FE6AFE6B33D5 339C339D339E33CE33A1338E338F33C400B05159515B515E515D5161516355E7 74E97CCE25812582258325842585258625872588258F258E258D258C258B258A 2589253C2534252C2524251C2594250025022595250C251025142518256D0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000256E2570256F2550255E256A256125E225E325E525E4257125722573FF10 FF11FF12FF13FF14FF15FF16FF17FF18FF192160216121622163216421652166 216721682169302130223023302430253026302730283029FFFD5344FFFDFF21 FF22FF23FF24FF25FF26FF27FF28FF29FF2AFF2BFF2CFF2DFF2EFF2FFF30FF31 FF32FF33FF34FF35FF36FF37FF38FF39FF3AFF41FF42FF43FF44FF45FF46FF47 FF48FF49FF4AFF4BFF4CFF4DFF4EFF4FFF50FF51FF52FF53FF54FF55FF560000 A3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 FF57FF58FF59FF5A039103920393039403950396039703980399039A039B039C 039D039E039F03A003A103A303A403A503A603A703A803A903B103B203B303B4 03B503B603B703B803B903BA03BB03BC03BD03BE03BF03C003C103C303C403C5 03C603C703C803C931053106310731083109310A310B310C310D310E310F0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00003110311131123113311431153116311731183119311A311B311C311D311E 311F312031213122312331243125312631273128312902D902C902CA02C702CB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 A4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 4E004E594E014E034E434E5D4E864E8C4EBA513F5165516B51E052005201529B 53155341535C53C84E094E0B4E084E0A4E2B4E3851E14E454E484E5F4E5E4E8E 4EA15140520352FA534353C953E3571F58EB5915592759735B505B515B535BF8 5C0F5C225C385C715DDD5DE55DF15DF25DF35DFE5E725EFE5F0B5F13624D0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00004E114E104E0D4E2D4E304E394E4B5C394E884E914E954E924E944EA24EC1 4EC04EC34EC64EC74ECD4ECA4ECB4EC4514351415167516D516E516C519751F6 52065207520852FB52FE52FF53165339534853475345535E538453CB53CA53CD 58EC5929592B592A592D5B545C115C245C3A5C6F5DF45E7B5EFF5F145F155FC3 62086236624B624E652F6587659765A465B965E566F0670867286B206B626B79 6BCB6BD46BDB6C0F6C34706B722A7236723B72477259725B72AC738B4E190000 A5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 4E164E154E144E184E3B4E4D4E4F4E4E4EE54ED84ED44ED54ED64ED74EE34EE4 4ED94EDE514551445189518A51AC51F951FA51F8520A52A0529F530553065317 531D4EDF534A534953615360536F536E53BB53EF53E453F353EC53EE53E953E8 53FC53F853F553EB53E653EA53F253F153F053E553ED53FB56DB56DA59160000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000592E5931597459765B555B835C3C5DE85DE75DE65E025E035E735E7C5F01 5F185F175FC5620A625362546252625165A565E6672E672C672A672B672D6B63 6BCD6C116C106C386C416C406C3E72AF7384738974DC74E67518751F75287529 7530753175327533758B767D76AE76BF76EE77DB77E277F3793A79BE7A747ACB 4E1E4E1F4E524E534E694E994EA44EA64EA54EFF4F094F194F0A4F154F0D4F10 4F114F0F4EF24EF64EFB4EF04EF34EFD4F014F0B514951475146514851680000 A6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5171518D51B0521752115212520E521652A3530853215320537053715409540F 540C540A54105401540B54045411540D54085403540E5406541256E056DE56DD 573357305728572D572C572F57295919591A59375938598459785983597D5979 598259815B575B585B875B885B855B895BFA5C165C795DDE5E065E765E740000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005F0F5F1B5FD95FD6620E620C620D62106263625B6258653665E965E865EC 65ED66F266F36709673D6734673167356B216B646B7B6C166C5D6C576C596C5F 6C606C506C556C616C5B6C4D6C4E7070725F725D767E7AF97C737CF87F367F8A 7FBD80018003800C80128033807F8089808B808C81E381EA81F381FC820C821B 821F826E8272827E866B8840884C8863897F96214E324EA84F4D4F4F4F474F57 4F5E4F344F5B4F554F304F504F514F3D4F3A4F384F434F544F3C4F464F630000 A7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 4F5C4F604F2F4F4E4F364F594F5D4F484F5A514C514B514D517551B651B75225 52245229522A522852AB52A952AA52AC532353735375541D542D541E543E5426 544E542754465443543354485442541B5429544A5439543B5438542E54355436 5420543C54405431542B541F542C56EA56F056E456EB574A57515740574D0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005747574E573E5750574F573B58EF593E599D599259A8599E59A359995996 598D59A45993598A59A55B5D5B5C5B5A5B5B5B8C5B8B5B8F5C2C5C405C415C3F 5C3E5C905C915C945C8C5DEB5E0C5E8F5E875E8A5EF75F045F1F5F645F625F77 5F795FD85FCC5FD75FCD5FF15FEB5FF85FEA6212621162846297629662806276 6289626D628A627C627E627962736292626F6298626E62956293629162866539 653B653865F166F4675F674E674F67506751675C6756675E6749674667600000 A8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 675367576B656BCF6C426C5E6C996C816C886C896C856C9B6C6A6C7A6C906C70 6C8C6C686C966C926C7D6C836C726C7E6C746C866C766C8D6C946C986C827076 707C707D707872627261726072C472C27396752C752B75377538768276EF77E3 79C179C079BF7A767CFB7F5580968093809D8098809B809A80B2826F82920000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000828B828D898B89D28A008C378C468C558C9D8D648D708DB38EAB8ECA8F9B 8FB08FC28FC68FC58FC45DE1909190A290AA90A690A3914991C691CC9632962E 9631962A962C4E264E564E734E8B4E9B4E9E4EAB4EAC4F6F4F9D4F8D4F734F7F 4F6C4F9B4F8B4F864F834F704F754F884F694F7B4F964F7E4F8F4F914F7A5154 51525155516951775176517851BD51FD523B52385237523A5230522E52365241 52BE52BB5352535453535351536653775378537953D653D453D7547354750000 A9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5496547854955480547B5477548454925486547C549054715476548C549A5462 5468548B547D548E56FA57835777576A5769576157665764577C591C59495947 59485944595459BE59BB59D459B959AE59D159C659D059CD59CB59D359CA59AF 59B359D259C55B5F5B645B635B975B9A5B985B9C5B995B9B5C1A5C485C450000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005C465CB75CA15CB85CA95CAB5CB15CB35E185E1A5E165E155E1B5E115E78 5E9A5E975E9C5E955E965EF65F265F275F295F805F815F7F5F7C5FDD5FE05FFD 5FF55FFF600F6014602F60356016602A6015602160276029602B601B62166215 623F623E6240627F62C962CC62C462BF62C262B962D262DB62AB62D362D462CB 62C862A862BD62BC62D062D962C762CD62B562DA62B162D862D662D762C662AC 62CE653E65A765BC65FA66146613660C66066602660E6600660F6615660A0000 AA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6607670D670B676D678B67956771679C677367776787679D6797676F6770677F 6789677E67906775679A6793677C676A67726B236B666B676B7F6C136C1B6CE3 6CE86CF36CB16CCC6CE56CB36CBD6CBE6CBC6CE26CAB6CD56CD36CB86CC46CB9 6CC16CAE6CD76CC56CF16CBF6CBB6CE16CDB6CCA6CAC6CEF6CDC6CD66CE00000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007095708E7092708A7099722C722D723872487267726972C072CE72D972D7 72D073A973A8739F73AB73A5753D759D7599759A768476C276F276F477E577FD 793E7940794179C979C87A7A7A797AFA7CFE7F547F8C7F8B800580BA80A580A2 80B180A180AB80A980B480AA80AF81E581FE820D82B3829D829982AD82BD829F 82B982B182AC82A582AF82B882A382B082BE82B7864E8671521D88688ECB8FCE 8FD48FD190B590B890B190B691C791D195779580961C9640963F963B96440000 AB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 964296B996E89752975E4E9F4EAD4EAE4FE14FB54FAF4FBF4FE04FD14FCF4FDD 4FC34FB64FD84FDF4FCA4FD74FAE4FD04FC44FC24FDA4FCE4FDE4FB751575192 519151A0524E5243524A524D524C524B524752C752C952C352C1530D5357537B 539A53DB54AC54C054A854CE54C954B854A654B354C754C254BD54AA54C10000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000054C454C854AF54AB54B154BB54A954A754BF56FF5782578B57A057A357A2 57CE57AE579359555951594F594E595059DC59D859FF59E359E85A0359E559EA 59DA59E65A0159FB5B695BA35BA65BA45BA25BA55C015C4E5C4F5C4D5C4B5CD9 5CD25DF75E1D5E255E1F5E7D5EA05EA65EFA5F085F2D5F655F885F855F8A5F8B 5F875F8C5F896012601D60206025600E6028604D60706068606260466043606C 606B606A6064624162DC6316630962FC62ED630162EE62FD630762F162F70000 AC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 62EF62EC62FE62F463116302653F654565AB65BD65E26625662D66206627662F 661F66286631662466F767FF67D367F167D467D067EC67B667AF67F567E967EF 67C467D167B467DA67E567B867CF67DE67F367B067D967E267DD67D26B6A6B83 6B866BB56BD26BD76C1F6CC96D0B6D326D2A6D416D256D0C6D316D1E6D170000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006D3B6D3D6D3E6D366D1B6CF56D396D276D386D296D2E6D356D0E6D2B70AB 70BA70B370AC70AF70AD70B870AE70A472307272726F727472E972E072E173B7 73CA73BB73B273CD73C073B3751A752D754F754C754E754B75AB75A475A575A2 75A3767876867687768876C876C676C376C5770176F976F87709770B76FE76FC 770777DC78027814780C780D794679497948794779B979BA79D179D279CB7A7F 7A817AFF7AFD7C7D7D027D057D007D097D077D047D067F387F8E7FBF80040000 AD 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8010800D8011803680D680E580DA80C380C480CC80E180DB80CE80DE80E480DD 81F4822282E78303830582E382DB82E6830482E58302830982D282D782F18301 82DC82D482D182DE82D382DF82EF830686508679867B867A884D886B898189D4 8A088A028A038C9E8CA08D748D738DB48ECD8ECC8FF08FE68FE28FEA8FE50000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008FED8FEB8FE48FE890CA90CE90C190C3914B914A91CD95829650964B964C 964D9762976997CB97ED97F3980198A898DB98DF999699994E584EB3500C500D 50234FEF502650254FF8502950165006503C501F501A501250114FFA50005014 50284FF15021500B501950184FF34FEE502D502A4FFE502B5009517C51A451A5 51A251CD51CC51C651CB5256525C5254525B525D532A537F539F539D53DF54E8 55105501553754FC54E554F2550654FA551454E954ED54E1550954EE54EA0000 AE 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 54E65527550754FD550F5703570457C257D457CB57C35809590F59575958595A 5A115A185A1C5A1F5A1B5A1359EC5A205A235A295A255A0C5A095B6B5C585BB0 5BB35BB65BB45BAE5BB55BB95BB85C045C515C555C505CED5CFD5CFB5CEA5CE8 5CF05CF65D015CF45DEE5E2D5E2B5EAB5EAD5EA75F315F925F915F9060590000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006063606560506055606D6069606F6084609F609A608D6094608C60856096 624762F3630862FF634E633E632F635563426346634F6349633A6350633D632A 632B6328634D634C65486549659965C165C566426649664F66436652664C6645 664166F867146715671768216838684868466853683968426854682968B36817 684C6851683D67F468506840683C6843682A68456813681868416B8A6B896BB7 6C236C276C286C266C246CF06D6A6D956D886D876D666D786D776D596D930000 AF 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6D6C6D896D6E6D5A6D746D696D8C6D8A6D796D856D656D9470CA70D870E470D9 70C870CF7239727972FC72F972FD72F872F7738673ED740973EE73E073EA73DE 7554755D755C755A755975BE75C575C775B275B375BD75BC75B975C275B8768B 76B076CA76CD76CE7729771F7720772877E9783078277838781D783478370000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007825782D7820781F7832795579507960795F7956795E795D7957795A79E4 79E379E779DF79E679E979D87A847A887AD97B067B117C897D217D177D0B7D0A 7D207D227D147D107D157D1A7D1C7D0D7D197D1B7F3A7F5F7F947FC57FC18006 8018801580198017803D803F80F1810280F0810580ED80F4810680F880F38108 80FD810A80FC80EF81ED81EC82008210822A822B8228822C82BB832B83528354 834A83388350834983358334834F833283398336831783408331832883430000 B0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8654868A86AA869386A486A9868C86A3869C8870887788818882887D88798A18 8A108A0E8A0C8A158A0A8A178A138A168A0F8A118C488C7A8C798CA18CA28D77 8EAC8ED28ED48ECF8FB1900190068FF790008FFA8FF490038FFD90058FF89095 90E190DD90E29152914D914C91D891DD91D791DC91D995839662966396610000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000965B965D96649658965E96BB98E299AC9AA89AD89B259B329B3C4E7E507A 507D505C50475043504C505A504950655076504E5055507550745077504F500F 506F506D515C519551F0526A526F52D252D952D852D55310530F5319533F5340 533E53C366FC5546556A55665544555E55615543554A55315556554F5555552F 55645538552E555C552C55635533554155575708570B570957DF5805580A5806 57E057E457FA5802583557F757F9592059625A365A415A495A665A6A5A400000 B1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5A3C5A625A5A5A465A4A5B705BC75BC55BC45BC25BBF5BC65C095C085C075C60 5C5C5C5D5D075D065D0E5D1B5D165D225D115D295D145D195D245D275D175DE2 5E385E365E335E375EB75EB85EB65EB55EBE5F355F375F575F6C5F695F6B5F97 5F995F9E5F985FA15FA05F9C607F60A3608960A060A860CB60B460E660BD0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000060C560BB60B560DC60BC60D860D560C660DF60B860DA60C7621A621B6248 63A063A76372639663A263A563776367639863AA637163A963896383639B636B 63A863846388639963A163AC6392638F6380637B63696368637A655D65566551 65596557555F654F655865556554659C659B65AC65CF65CB65CC65CE665D665A 666466686666665E66F952D7671B688168AF68A2689368B5687F687668B168A7 689768B0688368C468AD688668856894689D68A8689F68A168826B326BBA0000 B2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6BEB6BEC6C2B6D8E6DBC6DF36DD96DB26DE16DCC6DE46DFB6DFA6E056DC76DCB 6DAF6DD16DAE6DDE6DF96DB86DF76DF56DC56DD26E1A6DB56DDA6DEB6DD86DEA 6DF16DEE6DE86DC66DC46DAA6DEC6DBF6DE670F97109710A70FD70EF723D727D 7281731C731B73167313731973877405740A7403740673FE740D74E074F60000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000074F7751C75227565756675627570758F75D475D575B575CA75CD768E76D4 76D276DB7737773E773C77367738773A786B7843784E79657968796D79FB7A92 7A957B207B287B1B7B2C7B267B197B1E7B2E7C927C977C957D467D437D717D2E 7D397D3C7D407D307D337D447D2F7D427D327D317F3D7F9E7F9A7FCC7FCE7FD2 801C804A8046812F81168123812B81298130812482028235823782368239838E 839E8398837883A2839683BD83AB8392838A8393838983A08377837B837C0000 B3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 838683A786555F6A86C786C086B686C486B586C686CB86B186AF86C98853889E 888888AB88928896888D888B8993898F8A2A8A1D8A238A258A318A2D8A1F8A1B 8A228C498C5A8CA98CAC8CAB8CA88CAA8CA78D678D668DBE8DBA8EDB8EDF9019 900D901A90179023901F901D90109015901E9020900F90229016901B90140000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000090E890ED90FD915791CE91F591E691E391E791ED91E99589966A96759673 96789670967496769677966C96C096EA96E97AE07ADF980298039B5A9CE59E75 9E7F9EA59EBB50A2508D508550995091508050965098509A670051F152725274 5275526952DE52DD52DB535A53A5557B558055A7557C558A559D55985582559C 55AA55945587558B558355B355AE559F553E55B2559A55BB55AC55B1557E5589 55AB5599570D582F582A58345824583058315821581D582058F958FA59600000 B4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5A775A9A5A7F5A925A9B5AA75B735B715BD25BCC5BD35BD05C0A5C0B5C315D4C 5D505D345D475DFD5E455E3D5E405E435E7E5ECA5EC15EC25EC45F3C5F6D5FA9 5FAA5FA860D160E160B260B660E0611C612360FA611560F060FB60F4616860F1 610E60F6610961006112621F624963A3638C63CF63C063E963C963C663CD0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000063D263E363D063E163D663ED63EE637663F463EA63DB645263DA63F9655E 6566656265636591659065AF666E667066746676666F6691667A667E667766FE 66FF671F671D68FA68D568E068D868D7690568DF68F568EE68E768F968D268F2 68E368CB68CD690D6912690E68C968DA696E68FB6B3E6B3A6B3D6B986B966BBC 6BEF6C2E6C2F6C2C6E2F6E386E546E216E326E676E4A6E206E256E236E1B6E5B 6E586E246E566E6E6E2D6E266E6F6E346E4D6E3A6E2C6E436E1D6E3E6ECB0000 B5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6E896E196E4E6E636E446E726E696E5F7119711A7126713071217136716E711C 724C728472807336732573347329743A742A743374227425743574367434742F 741B7426742875257526756B756A75E275DB75E375D975D875DE75E0767B767C 7696769376B476DC774F77ED785D786C786F7A0D7A087A0B7A057A007A980000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007A977A967AE57AE37B497B567B467B507B527B547B4D7B4B7B4F7B517C9F 7CA57D5E7D507D687D557D2B7D6E7D727D617D667D627D707D7355847FD47FD5 800B8052808581558154814B8151814E81398146813E814C815381748212821C 83E9840383F8840D83E083C5840B83C183EF83F183F48457840A83F0840C83CC 83FD83F283CA8438840E840483DC840783D483DF865B86DF86D986ED86D486DB 86E486D086DE885788C188C288B1898389968A3B8A608A558A5E8A3C8A410000 B6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8A548A5B8A508A468A348A3A8A368A568C618C828CAF8CBC8CB38CBD8CC18CBB 8CC08CB48CB78CB68CBF8CB88D8A8D858D818DCE8DDD8DCB8DDA8DD18DCC8DDB 8DC68EFB8EF88EFC8F9C902E90359031903890329036910290F5910990FE9163 916591CF9214921592239209921E920D9210920792119594958F958B95910000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000095939592958E968A968E968B967D96859686968D9672968496C196C596C4 96C696C796EF96F297CC98059806980898E798EA98EF98E998F298ED99AE99AD 9EC39ECD9ED14E8250AD50B550B250B350C550BE50AC50B750BB50AF50C7527F 5277527D52DF52E652E452E252E3532F55DF55E855D355E655CE55DC55C755D1 55E355E455EF55DA55E155C555C655E555C957125713585E585158585857585A 5854586B584C586D584A58625852584B59675AC15AC95ACC5ABE5ABD5ABC0000 B7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5AB35AC25AB25D695D6F5E4C5E795EC95EC85F125F595FAC5FAE611A610F6148 611F60F3611B60F961016108614E614C6144614D613E61346127610D61066137 622162226413643E641E642A642D643D642C640F641C6414640D643664166417 6406656C659F65B06697668966876688669666846698668D67036994696D0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000695A697769606954697569306982694A6968696B695E695369796986695D 6963695B6B476B726BC06BBF6BD36BFD6EA26EAF6ED36EB66EC26E906E9D6EC7 6EC56EA56E986EBC6EBA6EAB6ED16E966E9C6EC46ED46EAA6EA76EB4714E7159 7169716471497167715C716C7166714C7165715E714671687156723A72527337 7345733F733E746F745A7455745F745E7441743F7459745B745C757675787600 75F0760175F275F175FA75FF75F475F376DE76DF775B776B7766775E77630000 B8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7779776A776C775C77657768776277EE788E78B078977898788C7889787C7891 7893787F797A797F7981842C79BD7A1C7A1A7A207A147A1F7A1E7A9F7AA07B77 7BC07B607B6E7B677CB17CB37CB57D937D797D917D817D8F7D5B7F6E7F697F6A 7F727FA97FA87FA480568058808680848171817081788165816E8173816B0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008179817A81668205824784828477843D843184758466846B8449846C845B 843C8435846184638469846D8446865E865C865F86F9871387088707870086FE 86FB870287038706870A885988DF88D488D988DC88D888DD88E188CA88D588D2 899C89E38A6B8A728A738A668A698A708A878A7C8A638AA08A718A858A6D8A62 8A6E8A6C8A798A7B8A3E8A688C628C8A8C898CCA8CC78CC88CC48CB28CC38CC2 8CC58DE18DDF8DE88DEF8DF38DFA8DEA8DE48DE68EB28F038F098EFE8F0A0000 B9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8F9F8FB2904B904A905390429054903C905590509047904F904E904D9051903E 904191129117916C916A916991C9923792579238923D9240923E925B924B9264 925192349249924D92459239923F925A959896989694969596CD96CB96C996CA 96F796FB96F996F6975697749776981098119813980A9812980C98FC98F40000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000098FD98FE99B399B199B49AE19CE99E829F0E9F139F2050E750EE50E550D6 50ED50DA50D550CF50D150F150CE50E9516251F352835282533153AD55FE5600 561B561755FD561456065609560D560E55F75616561F5608561055F657185716 5875587E58835893588A58795885587D58FD592559225924596A59695AE15AE6 5AE95AD75AD65AD85AE35B755BDE5BE75BE15BE55BE65BE85BE25BE45BDF5C0D 5C625D845D875E5B5E635E555E575E545ED35ED65F0A5F465F705FB961470000 BA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 613F614B617761626163615F615A61586175622A64876458645464A46478645F 647A645164676434646D647B657265A165D765D666A266A8669D699C69A86995 69C169AE69D369CB699B69B769BB69AB69B469D069CD69AD69CC69A669C369A3 6B496B4C6C336F336F146EFE6F136EF46F296F3E6F206F2C6F0F6F026F220000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006EFF6EEF6F066F316F386F326F236F156F2B6F2F6F886F2A6EEC6F016EF2 6ECC6EF771947199717D718A71847192723E729272967344735074647463746A 7470746D750475917627760D760B7609761376E176E37784777D777F776178C1 789F78A778B378A978A3798E798F798D7A2E7A317AAA7AA97AED7AEF7BA17B95 7B8B7B757B977B9D7B947B8F7BB87B877B847CB97CBD7CBE7DBB7DB07D9C7DBD 7DBE7DA07DCA7DB47DB27DB17DBA7DA27DBF7DB57DB87DAD7DD27DC77DAC0000 BB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7F707FE07FE17FDF805E805A808781508180818F8188818A817F818281E781FA 82078214821E824B84C984BF84C684C48499849E84B2849C84CB84B884C084D3 849084BC84D184CA873F871C873B872287258734871887558737872988F38902 88F488F988F888FD88E8891A88EF8AA68A8C8A9E8AA38A8D8AA18A938AA40000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008AAA8AA58AA88A988A918A9A8AA78C6A8C8D8C8C8CD38CD18CD28D6B8D99 8D958DFC8F148F128F158F138FA390609058905C90639059905E9062905D905B 91199118911E917591789177917492789280928592989296927B9293929C92A8 927C929195A195A895A995A395A595A49699969C969B96CC96D29700977C9785 97F69817981898AF98B199039905990C990999C19AAF9AB09AE69B419B429CF4 9CF69CF39EBC9F3B9F4A5104510050FB50F550F9510251085109510551DC0000 BC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 528752885289528D528A52F053B2562E563B56395632563F563456295653564E 565756745636562F56305880589F589E58B3589C58AE58A958A6596D5B095AFB 5B0B5AF55B0C5B085BEE5BEC5BE95BEB5C645C655D9D5D945E625E5F5E615EE2 5EDA5EDF5EDD5EE35EE05F485F715FB75FB561766167616E615D615561820000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000617C6170616B617E61A7619061AB618E61AC619A61A4619461AE622E6469 646F6479649E64B26488649064B064A56493649564A9649264AE64AD64AB649A 64AC649964A264B365756577657866AE66AB66B466B16A236A1F69E86A016A1E 6A1969FD6A216A136A0A69F36A026A0569ED6A116B506B4E6BA46BC56BC66F3F 6F7C6F846F516F666F546F866F6D6F5B6F786F6E6F8E6F7A6F706F646F976F58 6ED56F6F6F606F5F719F71AC71B171A87256729B734E73577469748B74830000 BD 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 747E7480757F76207629761F7624762676217622769A76BA76E4778E7787778C 7791778B78CB78C578BA78CA78BE78D578BC78D07A3F7A3C7A407A3D7A377A3B 7AAF7AAE7BAD7BB17BC47BB47BC67BC77BC17BA07BCC7CCA7DE07DF47DEF7DFB 7DD87DEC7DDD7DE87DE37DDA7DDE7DE97D9E7DD97DF27DF97F757F777FAF0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007FE98026819B819C819D81A0819A81988517853D851A84EE852C852D8513 851185238521851484EC852584FF850687828774877687608766877887688759 8757874C8753885B885D89108907891289138915890A8ABC8AD28AC78AC48A95 8ACB8AF88AB28AC98AC28ABF8AB08AD68ACD8AB68AB98ADB8C4C8C4E8C6C8CE0 8CDE8CE68CE48CEC8CED8CE28CE38CDC8CEA8CE18D6D8D9F8DA38E2B8E108E1D 8E228E0F8E298E1F8E218E1E8EBA8F1D8F1B8F1F8F298F268F2A8F1C8F1E0000 BE 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8F259069906E9068906D90779130912D9127913191879189918B918392C592BB 92B792EA92AC92E492C192B392BC92D292C792F092B295AD95B1970497069707 97099760978D978B978F9821982B981C98B3990A99139912991899DD99D099DF 99DB99D199D599D299D99AB79AEE9AEF9B279B459B449B779B6F9D069D090000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009D039EA99EBE9ECE58A89F5251125118511451105115518051AA51DD5291 529352F35659566B5679566956645678566A566856655671566F566C56625676 58C158BE58C758C5596E5B1D5B345B785BF05C0E5F4A61B2619161A9618A61CD 61B661BE61CA61C8623064C564C164CB64BB64BC64DA64C464C764C264CD64BF 64D264D464BE657466C666C966B966C466C766B86A3D6A386A3A6A596A6B6A58 6A396A446A626A616A4B6A476A356A5F6A486B596B776C056FC26FB16FA10000 BF 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6FC36FA46FC16FA76FB36FC06FB96FB66FA66FA06FB471BE71C971D071D271C8 71D571B971CE71D971DC71C371C47368749C74A37498749F749E74E2750C750D 76347638763A76E776E577A0779E779F77A578E878DA78EC78E779A67A4D7A4E 7A467A4C7A4B7ABA7BD97C117BC97BE47BDB7BE17BE97BE67CD57CD67E0A0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007E117E087E1B7E237E1E7E1D7E097E107F797FB27FF07FF17FEE802881B3 81A981A881FB820882588259854A855985488568856985438549856D856A855E 8783879F879E87A2878D8861892A89328925892B892189AA89A68AE68AFA8AEB 8AF18B008ADC8AE78AEE8AFE8B018B028AF78AED8AF38AF68AFC8C6B8C6D8C93 8CF48E448E318E348E428E398E358F3B8F2F8F388F338FA88FA6907590749078 9072907C907A913491929320933692F89333932F932292FC932B9304931A0000 C0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 9310932693219315932E931995BB96A796A896AA96D5970E97119716970D9713 970F975B975C9766979898309838983B9837982D9839982499109928991E991B 9921991A99ED99E299F19AB89ABC9AFB9AED9B289B919D159D239D269D289D12 9D1B9ED89ED49F8D9F9C512A511F5121513252F5568E56805690568556870000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000568F58D558D358D158CE5B305B2A5B245B7A5C375C685DBC5DBA5DBD5DB8 5E6B5F4C5FBD61C961C261C761E661CB6232623464CE64CA64D864E064F064E6 64EC64F164E264ED6582658366D966D66A806A946A846AA26A9C6ADB6AA36A7E 6A976A906AA06B5C6BAE6BDA6C086FD86FF16FDF6FE06FDB6FE46FEB6FEF6F80 6FEC6FE16FE96FD56FEE6FF071E771DF71EE71E671E571ED71EC71F471E07235 72467370737274A974B074A674A876467642764C76EA77B377AA77B077AC0000 C1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 77A777AD77EF78F778FA78F478EF790179A779AA7A577ABF7C077C0D7BFE7BF7 7C0C7BE07CE07CDC7CDE7CE27CDF7CD97CDD7E2E7E3E7E467E377E327E437E2B 7E3D7E317E457E417E347E397E487E357E3F7E2F7F447FF37FFC807180728070 806F807381C681C381BA81C281C081BF81BD81C981BE81E88209827185AA0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008584857E859C8591859485AF859B858785A8858A866787C087D187B387D2 87C687AB87BB87BA87C887CB893B893689448938893D89AC8B0E8B178B198B1B 8B0A8B208B1D8B048B108C418C3F8C738CFA8CFD8CFC8CF88CFB8DA88E498E4B 8E488E4A8F448F3E8F428F458F3F907F907D9084908190829080913991A3919E 919C934D938293289375934A9365934B9318937E936C935B9370935A935495CA 95CB95CC95C895C696B196B896D6971C971E97A097D3984698B699359A010000 C2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 99FF9BAE9BAB9BAA9BAD9D3B9D3F9E8B9ECF9EDE9EDC9EDD9EDB9F3E9F4B53E2 569556AE58D958D85B385F5D61E3623364F464F264FE650664FA64FB64F765B7 66DC67266AB36AAC6AC36ABB6AB86AC26AAE6AAF6B5F6B786BAF7009700B6FFE 70066FFA7011700F71FB71FC71FE71F87377737574A774BF7515765676580000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000765277BD77BF77BB77BC790E79AE7A617A627A607AC47AC57C2B7C277C2A 7C1E7C237C217CE77E547E557E5E7E5A7E617E527E597F487FF97FFB80778076 81CD81CF820A85CF85A985CD85D085C985B085BA85B985A687EF87EC87F287E0 898689B289F48B288B398B2C8B2B8C508D058E598E638E668E648E5F8E558EC0 8F498F4D90879083908891AB91AC91D09394938A939693A293B393AE93AC93B0 9398939A939795D495D695D095D596E296DC96D996DB96DE972497A397A60000 C3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 97AD97F9984D984F984C984E985398BA993E993F993D992E99A59A0E9AC19B03 9B069B4F9B4E9B4D9BCA9BC99BFD9BC89BC09D519D5D9D609EE09F159F2C5133 56A558DE58DF58E25BF59F905EEC61F261F761F661F56500650F66E066DD6AE5 6ADD6ADA6AD3701B701F7028701A701D701570187206720D725872A273780000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000737A74BD74CA74E375877586765F766177C7791979B17A6B7A697C3E7C3F 7C387C3D7C377C407E6B7E6D7E797E697E6A7F857E737FB67FB97FB881D885E9 85DD85EA85D585E485E585F787FB8805880D87F987FE8960895F8956895E8B41 8B5C8B588B498B5A8B4E8B4F8B468B598D088D0A8E7C8E728E878E768E6C8E7A 8E748F548F4E8FAD908A908B91B191AE93E193D193DF93C393C893DC93DD93D6 93E293CD93D893E493D793E895DC96B496E3972A9727976197DC97FB985E0000 C4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 9858985B98BC994599499A169A199B0D9BE89BE79BD69BDB9D899D619D729D6A 9D6C9E929E979E939EB452F856A856B756B656B456BC58E45B405B435B7D5BF6 5DC961F861FA65186514651966E667276AEC703E703070327210737B74CF7662 76657926792A792C792B7AC77AF67C4C7C437C4D7CEF7CF08FAE7E7D7E7C0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007E827F4C800081DA826685FB85F9861185FA8606860B8607860A88148815 896489BA89F88B708B6C8B668B6F8B5F8B6B8D0F8D0D8E898E818E858E8291B4 91CB9418940393FD95E1973098C49952995199A89A2B9A309A379A359C139C0D 9E799EB59EE89F2F9F5F9F639F615137513856C156C056C259145C6C5DCD61FC 61FE651D651C659566E96AFB6B046AFA6BB2704C721B72A774D674D4766977D3 7C507E8F7E8C7FBC8617862D861A882388228821881F896A896C89BD8B740000 C5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8B778B7D8D138E8A8E8D8E8B8F5F8FAF91BA942E94339435943A94389432942B 95E297389739973297FF9867986599579A459A439A409A3E9ACF9B549B519C2D 9C259DAF9DB49DC29DB89E9D9EEF9F199F5C9F669F67513C513B56C856CA56C9 5B7F5DD45DD25F4E61FF65246B0A6B6170517058738074E4758A766E766C0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000079B37C607C5F807E807D81DF8972896F89FC8B808D168D178E918E938F61 9148944494519452973D973E97C397C1986B99559A559A4D9AD29B1A9C499C31 9C3E9C3B9DD39DD79F349F6C9F6A9F9456CC5DD662006523652B652A66EC6B10 74DA7ACA7C647C637C657E937E967E9481E28638863F88318B8A9090908F9463 946094649768986F995C9A5A9A5B9A579AD39AD49AD19C549C579C569DE59E9F 9EF456D158E9652C705E7671767277D77F507F888836883988628B938B920000 C6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8B9682778D1B91C0946A97429748974497C698709A5F9B229B589C5F9DF99DFA 9E7C9E7D9F079F779F725EF36B1670637C6C7C6E883B89C08EA191C194729470 9871995E9AD69B239ECC706477DA8B9A947797C99A629A657E9C8B9C8EAA91C5 947D947E947C9C779C789EF78C54947F9E1A72289A6A9B319E1B9E1E7C720000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000030FE309D309E3005304130423043304430453046304730483049304A304B 304C304D304E304F3050305130523053305430553056305730583059305A305B 305C305D305E305F3060306130623063306430653066306730683069306A306B 306C306D306E306F3070307130723073307430753076307730783079307A307B 307C307D307E307F3080308130823083308430853086308730883089308A308B 308C308D308E308F309030913092309330A130A230A330A430A530A630A70000 C7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 30A830A930AA30AB30AC30AD30AE30AF30B030B130B230B330B430B530B630B7 30B830B930BA30BB30BC30BD30BE30BF30C030C130C230C330C430C530C630C7 30C830C930CA30CB30CC30CD30CE30CF30D030D130D230D330D430D530D630D7 30D830D930DA30DB30DC30DD30DE30DF30E030E130E230E330E430E530E60000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000030E730E830E930EA30EB30EC30ED30EE30EF30F030F130F230F330F430F5 30F60414041504010416041704180419041A041B041C04230424042504260427 04280429042A042B042C042D042E042F04300431043204330434043504510436 043704380439043A043B043C043D043E043F0440044104420443044404450446 044704480449044A044B044C044D044E044F2460246124622463246424652466 246724682469247424752476247724782479247A247B247C247D000000000000 C9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 4E424E5C51F5531A53824E074E0C4E474E8D56D7FA0C5C6E5F734E0F51874E0E 4E2E4E934EC24EC94EC8519852FC536C53B957205903592C5C105DFF65E16BB3 6BCC6C14723F4E314E3C4EE84EDC4EE94EE14EDD4EDA520C531C534C57225723 5917592F5B815B845C125C3B5C745C735E045E805E825FC9620962506C150000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006C366C436C3F6C3B72AE72B0738A79B8808A961E4F0E4F184F2C4EF54F14 4EF14F004EF74F084F1D4F024F054F224F134F044EF44F1251B1521352095210 52A65322531F534D538A540756E156DF572E572A5734593C5980597C5985597B 597E5977597F5B565C155C255C7C5C7A5C7B5C7E5DDF5E755E845F025F1A5F74 5FD55FD45FCF625C625E626462616266626262596260625A626565EF65EE673E 67396738673B673A673F673C67336C186C466C526C5C6C4F6C4A6C546C4B0000 CA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6C4C7071725E72B472B5738E752A767F7A757F518278827C8280827D827F864D 897E909990979098909B909496229624962096234F564F3B4F624F494F534F64 4F3E4F674F524F5F4F414F584F2D4F334F3F4F61518F51B9521C521E522152AD 52AE530953635372538E538F54305437542A545454455419541C542554180000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000543D544F544154285424544756EE56E756E557415745574C5749574B5752 5906594059A6599859A05997598E59A25990598F59A759A15B8E5B925C285C2A 5C8D5C8F5C885C8B5C895C925C8A5C865C935C955DE05E0A5E0E5E8B5E895E8C 5E885E8D5F055F1D5F785F765FD25FD15FD05FED5FE85FEE5FF35FE15FE45FE3 5FFA5FEF5FF75FFB60005FF4623A6283628C628E628F629462876271627B627A 6270628162886277627D62726274653765F065F465F365F265F5674567470000 CB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 67596755674C6748675D674D675A674B6BD06C196C1A6C786C676C6B6C846C8B 6C8F6C716C6F6C696C9A6C6D6C876C956C9C6C666C736C656C7B6C8E7074707A 726372BF72BD72C372C672C172BA72C573957397739373947392753A75397594 75957681793D80348095809980908092809C8290828F8285828E829182930000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000828A828382848C788FC98FBF909F90A190A5909E90A790A096309628962F 962D4E334F984F7C4F854F7D4F804F874F764F744F894F844F774F4C4F974F6A 4F9A4F794F814F784F904F9C4F944F9E4F924F824F954F6B4F6E519E51BC51BE 5235523252335246523152BC530A530B533C539253945487547F548154915482 5488546B547A547E5465546C54745466548D546F546154605498546354675464 56F756F9576F5772576D576B57715770577657805775577B5773577457620000 CC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5768577D590C594559B559BA59CF59CE59B259CC59C159B659BC59C359D659B1 59BD59C059C859B459C75B625B655B935B955C445C475CAE5CA45CA05CB55CAF 5CA85CAC5C9F5CA35CAD5CA25CAA5CA75C9D5CA55CB65CB05CA65E175E145E19 5F285F225F235F245F545F825F7E5F7D5FDE5FE5602D602660196032600B0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006034600A60176033601A601E602C6022600D6010602E60136011600C6009 601C6214623D62AD62B462D162BE62AA62B662CA62AE62B362AF62BB62A962B0 62B8653D65A865BB660965FC66046612660865FB6603660B660D660565FD6611 661066F6670A6785676C678E67926776677B6798678667846774678D678C677A 679F679167996783677D67816778677967946B256B806B7E6BDE6C1D6C936CEC 6CEB6CEE6CD96CB66CD46CAD6CE76CB76CD06CC26CBA6CC36CC66CED6CF20000 CD 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6CD26CDD6CB46C8A6C9D6C806CDE6CC06D306CCD6CC76CB06CF96CCF6CE96CD1 709470987085709370867084709170967082709A7083726A72D672CB72D872C9 72DC72D272D472DA72CC72D173A473A173AD73A673A273A073AC739D74DD74E8 753F7540753E758C759876AF76F376F176F076F577F877FC77F977FB77FA0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000077F77942793F79C57A787A7B7AFB7C757CFD8035808F80AE80A380B880B5 80AD822082A082C082AB829A8298829B82B582A782AE82BC829E82BA82B482A8 82A182A982C282A482C382B682A28670866F866D866E8C568FD28FCB8FD38FCD 8FD68FD58FD790B290B490AF90B390B09639963D963C963A96434FCD4FC54FD3 4FB24FC94FCB4FC14FD44FDC4FD94FBB4FB34FDB4FC74FD64FBA4FC04FB94FEC 5244524952C052C2533D537C539753965399539854BA54A154AD54A554CF0000 CE 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 54C3830D54B754AE54D654B654C554C654A0547054BC54A254BE547254DE54B0 57B5579E579F57A4578C5797579D579B57945798578F579957A5579A579558F4 590D595359E159DE59EE5A0059F159DD59FA59FD59FC59F659E459F259F759DB 59E959F359F559E059FE59F459ED5BA85C4C5CD05CD85CCC5CD75CCB5CDB0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005CDE5CDA5CC95CC75CCA5CD65CD35CD45CCF5CC85CC65CCE5CDF5CF85DF9 5E215E225E235E205E245EB05EA45EA25E9B5EA35EA55F075F2E5F565F866037 603960546072605E6045605360476049605B604C60406042605F602460446058 6066606E6242624362CF630D630B62F5630E630362EB62F9630F630C62F862F6 63006313631462FA631562FB62F06541654365AA65BF6636662166326635661C 662666226633662B663A661D66346639662E670F671067C167F267C867BA0000 CF 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 67DC67BB67F867D867C067B767C567EB67E467DF67B567CD67B367F767F667EE 67E367C267B967CE67E767F067B267FC67C667ED67CC67AE67E667DB67FA67C9 67CA67C367EA67CB6B286B826B846BB66BD66BD86BE06C206C216D286D346D2D 6D1F6D3C6D3F6D126D0A6CDA6D336D046D196D3A6D1A6D116D006D1D6D420000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006D016D186D376D036D0F6D406D076D206D2C6D086D226D096D1070B7709F 70BE70B170B070A170B470B570A972417249724A726C72707273726E72CA72E4 72E872EB72DF72EA72E672E3738573CC73C273C873C573B973B673B573B473EB 73BF73C773BE73C373C673B873CB74EC74EE752E7547754875A775AA767976C4 7708770377047705770A76F776FB76FA77E777E878067811781278057810780F 780E780978037813794A794C794B7945794479D579CD79CF79D679CE7A800000 D0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7A7E7AD17B007B017C7A7C787C797C7F7C807C817D037D087D017F587F917F8D 7FBE8007800E800F8014803780D880C780E080D180C880C280D080C580E380D9 80DC80CA80D580C980CF80D780E680CD81FF8221829482D982FE82F9830782E8 830082D5833A82EB82D682F482EC82E182F282F5830C82FB82F682F082EA0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000082E482E082FA82F382ED86778674867C86738841884E8867886A886989D3 8A048A078D728FE38FE18FEE8FE090F190BD90BF90D590C590BE90C790CB90C8 91D491D39654964F96519653964A964E501E50055007501350225030501B4FF5 4FF450335037502C4FF64FF75017501C502050275035502F5031500E515A5194 519351CA51C451C551C851CE5261525A5252525E525F5255526252CD530E539E 552654E25517551254E754F354E4551A54FF5504550854EB5511550554F10000 D1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 550A54FB54F754F854E0550E5503550B5701570257CC583257D557D257BA57C6 57BD57BC57B857B657BF57C757D057B957C1590E594A5A195A165A2D5A2E5A15 5A0F5A175A0A5A1E5A335B6C5BA75BAD5BAC5C035C565C545CEC5CFF5CEE5CF1 5CF75D005CF95E295E285EA85EAE5EAA5EAC5F335F305F67605D605A60670000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000604160A26088608060926081609D60836095609B60976087609C608E6219 624662F263106356632C634463456336634363E46339634B634A633C63296341 6334635863546359632D63476333635A63516338635763406348654A654665C6 65C365C465C2664A665F6647665167126713681F681A684968326833683B684B 684F68166831681C6835682B682D682F684E68446834681D6812681468266828 682E684D683A682568206B2C6B2F6B2D6B316B346B6D80826B886BE66BE40000 D2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6BE86BE36BE26BE76C256D7A6D636D646D766D0D6D616D926D586D626D6D6D6F 6D916D8D6DEF6D7F6D866D5E6D676D606D976D706D7C6D5F6D826D986D2F6D68 6D8B6D7E6D806D846D166D836D7B6D7D6D756D9070DC70D370D170DD70CB7F39 70E270D770D270DE70E070D470CD70C570C670C770DA70CE70E1724272780000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000072777276730072FA72F472FE72F672F372FB730173D373D973E573D673BC 73E773E373E973DC73D273DB73D473DD73DA73D773D873E874DE74DF74F474F5 7521755B755F75B075C175BB75C475C075BF75B675BA768A76C9771D771B7710 771377127723771177157719771A772277277823782C78227835782F7828782E 782B782178297833782A78317954795B794F795C79537952795179EB79EC79E0 79EE79ED79EA79DC79DE79DD7A867A897A857A8B7A8C7A8A7A877AD87B100000 D3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7B047B137B057B0F7B087B0A7B0E7B097B127C847C917C8A7C8C7C887C8D7C85 7D1E7D1D7D117D0E7D187D167D137D1F7D127D0F7D0C7F5C7F617F5E7F607F5D 7F5B7F967F927FC37FC27FC08016803E803980FA80F280F980F5810180FB8100 8201822F82258333832D83448319835183258356833F83418326831C83220000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008342834E831B832A8308833C834D8316832483208337832F832983478345 834C8353831E832C834B832783488653865286A286A88696868D8691869E8687 86978686868B869A868586A5869986A186A786958698868E869D869086948843 8844886D88758876887288808871887F886F8883887E8874887C8A128C478C57 8C7B8CA48CA38D768D788DB58DB78DB68ED18ED38FFE8FF590028FFF8FFB9004 8FFC8FF690D690E090D990DA90E390DF90E590D890DB90D790DC90E491500000 D4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 914E914F91D591E291DA965C965F96BC98E39ADF9B2F4E7F5070506A5061505E 50605053504B505D50725048504D5041505B504A506250155045505F5069506B 5063506450465040506E50735057505151D0526B526D526C526E52D652D3532D 539C55755576553C554D55505534552A55515562553655355530555255450000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000550C55325565554E55395548552D553B5540554B570A570757FB581457E2 57F657DC57F4580057ED57FD580857F8580B57F357CF580757EE57E357F257E5 57EC57E1580E57FC581057E75801580C57F157E957F0580D5804595C5A605A58 5A555A675A5E5A385A355A6D5A505A5F5A655A6C5A535A645A575A435A5D5A52 5A445A5B5A485A8E5A3E5A4D5A395A4C5A705A695A475A515A565A425A5C5B72 5B6E5BC15BC05C595D1E5D0B5D1D5D1A5D205D0C5D285D0D5D265D255D0F0000 D5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5D305D125D235D1F5D2E5E3E5E345EB15EB45EB95EB25EB35F365F385F9B5F96 5F9F608A6090608660BE60B060BA60D360D460CF60E460D960DD60C860B160DB 60B760CA60BF60C360CD60C063326365638A6382637D63BD639E63AD639D6397 63AB638E636F63876390636E63AF6375639C636D63AE637C63A4633B639F0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006378638563816391638D6370655365CD66656661665B6659665C66626718 687968876890689C686D686E68AE68AB6956686F68A368AC68A96875687468B2 688F68776892687C686B687268AA68806871687E689B6896688B68A0688968A4 6878687B6891688C688A687D6B366B336B376B386B916B8F6B8D6B8E6B8C6C2A 6DC06DAB6DB46DB36E746DAC6DE96DE26DB76DF66DD46E006DC86DE06DDF6DD6 6DBE6DE56DDC6DDD6DDB6DF46DCA6DBD6DED6DF06DBA6DD56DC26DCF6DC90000 D6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6DD06DF26DD36DFD6DD76DCD6DE36DBB70FA710D70F7711770F4710C70F07104 70F3711070FC70FF71067113710070F870F6710B7102710E727E727B727C727F 731D7317730773117318730A730872FF730F731E738873F673F873F574047401 73FD7407740073FA73FC73FF740C740B73F474087564756375CE75D275CF0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000075CB75CC75D175D0768F768976D37739772F772D7731773277347733773D 7725773B7735784878527849784D784A784C782678457850796479677969796A 7963796B796179BB79FA79F879F679F77A8F7A947A907B357B477B347B257B30 7B227B247B337B187B2A7B1D7B317B2B7B2D7B2F7B327B387B1A7B237C947C98 7C967CA37D357D3D7D387D367D3A7D457D2C7D297D417D477D3E7D3F7D4A7D3B 7D287F637F957F9C7F9D7F9B7FCA7FCB7FCD7FD07FD17FC77FCF7FC9801F0000 D7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 801E801B804780438048811881258119811B812D811F812C811E812181158127 811D8122821182388233823A823482328274839083A383A8838D837A837383A4 8374838F8381839583998375839483A9837D8383838C839D839B83AA838B837E 83A583AF8388839783B0837F83A6838783AE8376839A8659865686BF86B70000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000086C286C186C586BA86B086C886B986B386B886CC86B486BB86BC86C386BD 86BE88528889889588A888A288AA889A889188A1889F889888A78899889B8897 88A488AC888C8893888E898289D689D989D58A308A278A2C8A1E8C398C3B8C5C 8C5D8C7D8CA58D7D8D7B8D798DBC8DC28DB98DBF8DC18ED88EDE8EDD8EDC8ED7 8EE08EE19024900B9011901C900C902190EF90EA90F090F490F290F390D490EB 90EC90E991569158915A9153915591EC91F491F191F391F891E491F991EA0000 D8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 91EB91F791E891EE957A95869588967C966D966B9671966F96BF976A980498E5 9997509B50955094509E508B50A35083508C508E509D5068509C509250825087 515F51D45312531153A453A7559155A855A555AD5577564555A255935588558F 55B5558155A3559255A4557D558C55A6557F559555A1558E570C582958370000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005819581E58275823582857F558485825581C581B5833583F5836582E5839 5838582D582C583B59615AAF5A945A9F5A7A5AA25A9E5A785AA65A7C5AA55AAC 5A955AAE5A375A845A8A5A975A835A8B5AA95A7B5A7D5A8C5A9C5A8F5A935A9D 5BEA5BCD5BCB5BD45BD15BCA5BCE5C0C5C305D375D435D6B5D415D4B5D3F5D35 5D515D4E5D555D335D3A5D525D3D5D315D595D425D395D495D385D3C5D325D36 5D405D455E445E415F585FA65FA55FAB60C960B960CC60E260CE60C461140000 D9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 60F2610A6116610560F5611360F860FC60FE60C161036118611D611060FF6104 610B624A639463B163B063CE63E563E863EF63C3649D63F363CA63E063F663D5 63F263F5646163DF63BE63DD63DC63C463D863D363C263C763CC63CB63C863F0 63D763D965326567656A6564655C65686565658C659D659E65AE65D065D20000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000667C666C667B668066716679666A66726701690C68D3690468DC692A68EC 68EA68F1690F68D668F768EB68E468F66913691068F368E1690768CC69086970 68B4691168EF68C6691468F868D068FD68FC68E8690B690A691768CE68C868DD 68DE68E668F468D1690668D468E96915692568C76B396B3B6B3F6B3C6B946B97 6B996B956BBD6BF06BF26BF36C306DFC6E466E476E1F6E496E886E3C6E3D6E45 6E626E2B6E3F6E416E5D6E736E1C6E336E4B6E406E516E3B6E036E2E6E5E0000 DA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6E686E5C6E616E316E286E606E716E6B6E396E226E306E536E656E276E786E64 6E776E556E796E526E666E356E366E5A7120711E712F70FB712E713171237125 71227132711F7128713A711B724B725A7288728972867285728B7312730B7330 73227331733373277332732D732673237335730C742E742C7430742B74160000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000741A7421742D743174247423741D74297420743274FB752F756F756C75E7 75DA75E175E675DD75DF75E475D77695769276DA774677477744774D7745774A 774E774B774C77DE77EC786078647865785C786D7871786A786E787078697868 785E786279747973797279707A027A0A7A037A0C7A047A997AE67AE47B4A7B3B 7B447B487B4C7B4E7B407B587B457CA27C9E7CA87CA17D587D6F7D637D537D56 7D677D6A7D4F7D6D7D5C7D6B7D527D547D697D517D5F7D4E7F3E7F3F7F650000 DB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7F667FA27FA07FA17FD78051804F805080FE80D48143814A8152814F8147813D 814D813A81E681EE81F781F881F98204823C823D823F8275833B83CF83F98423 83C083E8841283E783E483FC83F6841083C683C883EB83E383BF840183DD83E5 83D883FF83E183CB83CE83D683F583C98409840F83DE8411840683C283F30000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000083D583FA83C783D183EA841383C383EC83EE83C483FB83D783E2841B83DB 83FE86D886E286E686D386E386DA86EA86DD86EB86DC86EC86E986D786E886D1 88488856885588BA88D788B988B888C088BE88B688BC88B788BD88B2890188C9 89958998899789DD89DA89DB8A4E8A4D8A398A598A408A578A588A448A458A52 8A488A518A4A8A4C8A4F8C5F8C818C808CBA8CBE8CB08CB98CB58D848D808D89 8DD88DD38DCD8DC78DD68DDC8DCF8DD58DD98DC88DD78DC58EEF8EF78EFA0000 DC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8EF98EE68EEE8EE58EF58EE78EE88EF68EEB8EF18EEC8EF48EE9902D9034902F 9106912C910490FF90FC910890F990FB9101910091079105910391619164915F 916291609201920A92259203921A9226920F920C9200921291FF91FD92069204 92279202921C92249219921792059216957B958D958C95909687967E96880000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000096899683968096C296C896C396F196F0976C9770976E980798A998EB9CE6 9EF94E834E844EB650BD50BF50C650AE50C450CA50B450C850C250B050C150BA 50B150CB50C950B650B851D7527A5278527B527C55C355DB55CC55D055CB55CA 55DD55C055D455C455E955BF55D2558D55CF55D555E255D655C855F255CD55D9 55C25714585358685864584F584D5849586F5855584E585D58595865585B583D 5863587158FC5AC75AC45ACB5ABA5AB85AB15AB55AB05ABF5AC85ABB5AC60000 DD 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5AB75AC05ACA5AB45AB65ACD5AB95A905BD65BD85BD95C1F5C335D715D635D4A 5D655D725D6C5D5E5D685D675D625DF05E4F5E4E5E4A5E4D5E4B5EC55ECC5EC6 5ECB5EC75F405FAF5FAD60F76149614A612B614561366132612E6146612F614F 612961406220916862236225622463C563F163EB641064126409642064240000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000064336443641F641564186439643764226423640C64266430642864416435 642F640A641A644064256427640B63E7641B642E6421640E656F659265D36686 668C66956690668B668A66996694667867206966695F6938694E69626971693F 6945696A6939694269576959697A694869496935696C6933693D696568F06978 693469696940696F69446976695869416974694C693B694B6937695C694F6951 69326952692F697B693C6B466B456B436B426B486B416B9BFA0D6BFB6BFC0000 DE 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6BF96BF76BF86E9B6ED66EC86E8F6EC06E9F6E936E946EA06EB16EB96EC66ED2 6EBD6EC16E9E6EC96EB76EB06ECD6EA66ECF6EB26EBE6EC36EDC6ED86E996E92 6E8E6E8D6EA46EA16EBF6EB36ED06ECA6E976EAE6EA371477154715271637160 7141715D716271727178716A7161714271587143714B7170715F715071530000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007144714D715A724F728D728C72917290728E733C7342733B733A7340734A 73497444744A744B7452745174577440744F7450744E74427446744D745474E1 74FF74FE74FD751D75797577698375EF760F760375F775FE75FC75F975F87610 75FB75F675ED75F575FD769976B576DD7755775F776077527756775A77697767 77547759776D77E07887789A7894788F788478957885788678A1788378797899 78807896787B797C7982797D79797A117A187A197A127A177A157A227A130000 DF 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7A1B7A107AA37AA27A9E7AEB7B667B647B6D7B747B697B727B657B737B717B70 7B617B787B767B637CB27CB47CAF7D887D867D807D8D7D7F7D857D7A7D8E7D7B 7D837D7C7D8C7D947D847D7D7D927F6D7F6B7F677F687F6C7FA67FA57FA77FDB 7FDC8021816481608177815C8169815B816281726721815E81768167816F0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000081448161821D8249824482408242824584F1843F845684768479848F848D 846584518440848684678430844D847D845A845984748473845D8507845E8437 843A8434847A8443847884328445842983D9844B842F8442842D845F84708439 844E844C8452846F84C5848E843B8447843684338468847E8444842B84608454 846E8450870B870486F7870C86FA86D686F5874D86F8870E8709870186F6870D 870588D688CB88CD88CE88DE88DB88DA88CC88D08985899B89DF89E589E40000 E0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 89E189E089E289DC89E68A768A868A7F8A618A3F8A778A828A848A758A838A81 8A748A7A8C3C8C4B8C4A8C658C648C668C868C848C858CCC8D688D698D918D8C 8D8E8D8F8D8D8D938D948D908D928DF08DE08DEC8DF18DEE8DD08DE98DE38DE2 8DE78DF28DEB8DF48F068EFF8F018F008F058F078F088F028F0B9052903F0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000090449049903D9110910D910F911191169114910B910E916E916F92489252 9230923A926692339265925E9283922E924A9246926D926C924F92609267926F 92369261927092319254926392509272924E9253924C92569232959F959C959E 959B969296939691969796CE96FA96FD96F896F59773977797789772980F980D 980E98AC98F698F999AF99B299B099B59AAD9AAB9B5B9CEA9CED9CE79E809EFD 50E650D450D750E850F350DB50EA50DD50E450D350EC50F050EF50E350E00000 E1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 51D85280528152E952EB533053AC56275615560C561255FC560F561C56015613 560255FA561D560455FF55F95889587C5890589858865881587F5874588B587A 58875891588E587658825888587B5894588F58FE596B5ADC5AEE5AE55AD55AEA 5ADA5AED5AEB5AF35AE25AE05ADB5AEC5ADE5ADD5AD95AE85ADF5B775BE00000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005BE35C635D825D805D7D5D865D7A5D815D775D8A5D895D885D7E5D7C5D8D 5D795D7F5E585E595E535ED85ED15ED75ECE5EDC5ED55ED95ED25ED45F445F43 5F6F5FB6612C61286141615E61716173615261536172616C618061746154617A 615B6165613B616A6161615662296227622B642B644D645B645D647464766472 6473647D6475646664A6644E6482645E645C644B645364606450647F643F646C 646B645964656477657365A066A166A0669F67056704672269B169B669C90000 E2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 69A069CE699669B069AC69BC69916999698E69A7698D69A969BE69AF69BF69C4 69BD69A469D469B969CA699A69CF69B3699369AA69A1699E69D96997699069C2 69B569A569C66B4A6B4D6B4B6B9E6B9F6BA06BC36BC46BFE6ECE6EF56EF16F03 6F256EF86F376EFB6F2E6F096F4E6F196F1A6F276F186F3B6F126EED6F0A0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006F366F736EF96EEE6F2D6F406F306F3C6F356EEB6F076F0E6F436F056EFD 6EF66F396F1C6EFC6F3A6F1F6F0D6F1E6F086F21718771907189718071857182 718F717B718671817197724472537297729572937343734D7351734C74627473 7471747574727467746E750075027503757D759076167608760C76157611760A 761476B87781777C77857782776E7780776F777E778378B278AA78B478AD78A8 787E78AB789E78A578A078AC78A278A47998798A798B79967995799479930000 E3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 79977988799279907A2B7A4A7A307A2F7A287A267AA87AAB7AAC7AEE7B887B9C 7B8A7B917B907B967B8D7B8C7B9B7B8E7B857B9852847B997BA47B827CBB7CBF 7CBC7CBA7DA77DB77DC27DA37DAA7DC17DC07DC57D9D7DCE7DC47DC67DCB7DCC 7DAF7DB97D967DBC7D9F7DA67DAE7DA97DA17DC97F737FE27FE37FE57FDE0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008024805D805C8189818681838187818D818C818B8215849784A484A1849F 84BA84CE84C284AC84AE84AB84B984B484C184CD84AA849A84B184D0849D84A7 84BB84A2849484C784CC849B84A984AF84A884D6849884B684CF84A084D784D4 84D284DB84B084918661873387238728876B8740872E871E87218719871B8743 872C8741873E874687208732872A872D873C8712873A87318735874287268727 87388724871A8730871188F788E788F188F288FA88FE88EE88FC88F688FB0000 E4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 88F088EC88EB899D89A1899F899E89E989EB89E88AAB8A998A8B8A928A8F8A96 8C3D8C688C698CD58CCF8CD78D968E098E028DFF8E0D8DFD8E0A8E038E078E06 8E058DFE8E008E048F108F118F0E8F0D9123911C91209122911F911D911A9124 9121911B917A91729179917392A592A49276929B927A92A0929492AA928D0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000092A6929A92AB92799297927F92A392EE928E9282929592A2927D928892A1 928A9286928C929992A7927E928792A9929D928B922D969E96A196FF9758977D 977A977E978397809782977B97849781977F97CE97CD981698AD98AE99029900 9907999D999C99C399B999BB99BA99C299BD99C79AB19AE39AE79B3E9B3F9B60 9B619B5F9CF19CF29CF59EA750FF5103513050F85106510750F650FE510B510C 50FD510A528B528C52F152EF56485642564C56355641564A5649564656580000 E5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 565A56405633563D562C563E5638562A563A571A58AB589D58B158A058A358AF 58AC58A558A158FF5AFF5AF45AFD5AF75AF65B035AF85B025AF95B015B075B05 5B0F5C675D995D975D9F5D925DA25D935D955DA05D9C5DA15D9A5D9E5E695E5D 5E605E5C7DF35EDB5EDE5EE15F495FB2618B6183617961B161B061A261890000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000619B619361AF61AD619F619261AA61A1618D616661B3622D646E64706496 64A064856497649C648F648B648A648C64A3649F646864B164986576657A6579 657B65B265B366B566B066A966B266B766AA66AF6A006A066A1769E569F86A15 69F169E46A2069FF69EC69E26A1B6A1D69FE6A2769F269EE6A1469F769E76A40 6A0869E669FB6A0D69FC69EB6A096A046A186A256A0F69F66A266A0769F46A16 6B516BA56BA36BA26BA66C016C006BFF6C026F416F266F7E6F876FC66F920000 E6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6F8D6F896F8C6F626F4F6F856F5A6F966F766F6C6F826F556F726F526F506F57 6F946F936F5D6F006F616F6B6F7D6F676F906F536F8B6F696F7F6F956F636F77 6F6A6F7B71B271AF719B71B071A0719A71A971B5719D71A5719E71A471A171AA 719C71A771B37298729A73587352735E735F7360735D735B7361735A73590000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000736274877489748A74867481747D74857488747C747975087507757E7625 761E7619761D761C7623761A7628761B769C769D769E769B778D778F77897788 78CD78BB78CF78CC78D178CE78D478C878C378C478C9799A79A179A0799C79A2 799B6B767A397AB27AB47AB37BB77BCB7BBE7BAC7BCE7BAF7BB97BCA7BB57CC5 7CC87CCC7CCB7DF77DDB7DEA7DE77DD77DE17E037DFA7DE67DF67DF17DF07DEE 7DDF7F767FAC7FB07FAD7FED7FEB7FEA7FEC7FE67FE88064806781A3819F0000 E7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 819E819581A2819981978216824F825382528250824E82518524853B850F8500 8529850E8509850D851F850A8527851C84FB852B84FA8508850C84F4852A84F2 851584F784EB84F384FC851284EA84E9851684FE8528851D852E850284FD851E 84F68531852684E784E884F084EF84F9851885208530850B8519852F86620000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000875687638764877787E1877387588754875B87528761875A8751875E876D 876A8750874E875F875D876F876C877A876E875C8765874F877B877587628767 8769885A8905890C8914890B891789188919890689168911890E890989A289A4 89A389ED89F089EC8ACF8AC68AB88AD38AD18AD48AD58ABB8AD78ABE8AC08AC5 8AD88AC38ABA8ABD8AD98C3E8C4D8C8F8CE58CDF8CD98CE88CDA8CDD8CE78DA0 8D9C8DA18D9B8E208E238E258E248E2E8E158E1B8E168E118E198E268E270000 E8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8E148E128E188E138E1C8E178E1A8F2C8F248F188F1A8F208F238F168F179073 9070906F9067906B912F912B9129912A91329126912E91859186918A91819182 9184918092D092C392C492C092D992B692CF92F192DF92D892E992D792DD92CC 92EF92C292E892CA92C892CE92E692CD92D592C992E092DE92E792D192D30000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000092B592E192C692B4957C95AC95AB95AE95B096A496A296D3970597089702 975A978A978E978897D097CF981E981D9826982998289820981B982798B29908 98FA9911991499169917991599DC99CD99CF99D399D499CE99C999D699D899CB 99D799CC9AB39AEC9AEB9AF39AF29AF19B469B439B679B749B719B669B769B75 9B709B689B649B6C9CFC9CFA9CFD9CFF9CF79D079D009CF99CFB9D089D059D04 9E839ED39F0F9F10511C51135117511A511151DE533453E156705660566E0000 E9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 567356665663566D5672565E5677571C571B58C858BD58C958BF58BA58C258BC 58C65B175B195B1B5B215B145B135B105B165B285B1A5B205B1E5BEF5DAC5DB1 5DA95DA75DB55DB05DAE5DAA5DA85DB25DAD5DAF5DB45E675E685E665E6F5EE9 5EE75EE65EE85EE55F4B5FBC619D61A8619661C561B461C661C161CC61BA0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000061BF61B8618C64D764D664D064CF64C964BD648964C364DB64F364D96533 657F657C65A266C866BE66C066CA66CB66CF66BD66BB66BA66CC67236A346A66 6A496A676A326A686A3E6A5D6A6D6A766A5B6A516A286A5A6A3B6A3F6A416A6A 6A646A506A4F6A546A6F6A696A606A3C6A5E6A566A556A4D6A4E6A466B556B54 6B566BA76BAA6BAB6BC86BC76C046C036C066FAD6FCB6FA36FC76FBC6FCE6FC8 6F5E6FC46FBD6F9E6FCA6FA870046FA56FAE6FBA6FAC6FAA6FCF6FBF6FB80000 EA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6FA26FC96FAB6FCD6FAF6FB26FB071C571C271BF71B871D671C071C171CB71D4 71CA71C771CF71BD71D871BC71C671DA71DB729D729E736973667367736C7365 736B736A747F749A74A074947492749574A1750B7580762F762D7631763D7633 763C76357632763076BB76E6779A779D77A1779C779B77A277A3779577990000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000779778DD78E978E578EA78DE78E378DB78E178E278ED78DF78E079A47A44 7A487A477AB67AB87AB57AB17AB77BDE7BE37BE77BDD7BD57BE57BDA7BE87BF9 7BD47BEA7BE27BDC7BEB7BD87BDF7CD27CD47CD77CD07CD17E127E217E177E0C 7E1F7E207E137E0E7E1C7E157E1A7E227E0B7E0F7E167E0D7E147E257E247F43 7F7B7F7C7F7A7FB17FEF802A8029806C81B181A681AE81B981B581AB81B081AC 81B481B281B781A781F282558256825785568545856B854D8553856185580000 EB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 854085468564854185628544855185478563853E855B8571854E856E85758555 85678560858C8566855D85548565856C866386658664879B878F879787938792 87888781879687988779878787A3878587908791879D87848794879C879A8789 891E89268930892D892E89278931892289298923892F892C891F89F18AE00000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008AE28AF28AF48AF58ADD8B148AE48ADF8AF08AC88ADE8AE18AE88AFF8AEF 8AFB8C918C928C908CF58CEE8CF18CF08CF38D6C8D6E8DA58DA78E338E3E8E38 8E408E458E368E3C8E3D8E418E308E3F8EBD8F368F2E8F358F328F398F378F34 90769079907B908690FA913391359136919391909191918D918F9327931E9308 931F9306930F937A9338933C931B9323931293019346932D930E930D92CB931D 92FA9325931392F992F793349302932492FF932993399335932A9314930C0000 EC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 930B92FE9309930092FB931695BC95CD95BE95B995BA95B695BF95B595BD96A9 96D4970B9712971097999797979497F097F89835982F98329924991F99279929 999E99EE99EC99E599E499F099E399EA99E999E79AB99ABF9AB49ABB9AF69AFA 9AF99AF79B339B809B859B879B7C9B7E9B7B9B829B939B929B909B7A9B950000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009B7D9B889D259D179D209D1E9D149D299D1D9D189D229D109D199D1F9E88 9E869E879EAE9EAD9ED59ED69EFA9F129F3D51265125512251245120512952F4 5693568C568D568656845683567E5682567F568158D658D458CF58D25B2D5B25 5B325B235B2C5B275B265B2F5B2E5B7B5BF15BF25DB75E6C5E6A5FBE5FBB61C3 61B561BC61E761E061E561E461E861DE64EF64E964E364EB64E464E865816580 65B665DA66D26A8D6A966A816AA56A896A9F6A9B6AA16A9E6A876A936A8E0000 ED 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6A956A836AA86AA46A916A7F6AA66A9A6A856A8C6A926B5B6BAD6C096FCC6FA9 6FF46FD46FE36FDC6FED6FE76FE66FDE6FF26FDD6FE26FE871E171F171E871F2 71E471F071E27373736E736F749774B274AB749074AA74AD74B174A574AF7510 75117512750F7584764376487649764776A476E977B577AB77B277B777B60000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000077B477B177A877F078F378FD790278FB78FC78F2790578F978FE790479AB 79A87A5C7A5B7A567A587A547A5A7ABE7AC07AC17C057C0F7BF27C007BFF7BFB 7C0E7BF47C0B7BF37C027C097C037C017BF87BFD7C067BF07BF17C107C0A7CE8 7E2D7E3C7E427E3398487E387E2A7E497E407E477E297E4C7E307E3B7E367E44 7E3A7F457F7F7F7E7F7D7FF47FF2802C81BB81C481CC81CA81C581C781BC81E9 825B825A825C85838580858F85A7859585A0858B85A3857B85A4859A859E0000 EE 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8577857C858985A1857A85788557858E85968586858D8599859D858185A28582 858885858579857685988590859F866887BE87AA87AD87C587B087AC87B987B5 87BC87AE87C987C387C287CC87B787AF87C487CA87B487B687BF87B887BD87DE 87B289358933893C893E894189528937894289AD89AF89AE89F289F38B1E0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008B188B168B118B058B0B8B228B0F8B128B158B078B0D8B088B068B1C8B13 8B1A8C4F8C708C728C718C6F8C958C948CF98D6F8E4E8E4D8E538E508E4C8E47 8F438F409085907E9138919A91A2919B9199919F91A1919D91A093A1938393AF 936493569347937C9358935C93769349935093519360936D938F934C936A9379 935793559352934F93719377937B9361935E936393679380934E935995C795C0 95C995C395C595B796AE96B096AC9720971F9718971D9719979A97A1979C0000 EF 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 979E979D97D597D497F198419844984A9849984598439925992B992C992A9933 9932992F992D99319930999899A399A19A0299FA99F499F799F999F899F699FB 99FD99FE99FC9A039ABE9AFE9AFD9B019AFC9B489B9A9BA89B9E9B9B9BA69BA1 9BA59BA49B869BA29BA09BAF9D339D419D679D369D2E9D2F9D319D389D300000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009D459D429D439D3E9D379D409D3D7FF59D2D9E8A9E899E8D9EB09EC89EDA 9EFB9EFF9F249F239F229F549FA05131512D512E5698569C5697569A569D5699 59705B3C5C695C6A5DC05E6D5E6E61D861DF61ED61EE61F161EA61F061EB61D6 61E964FF650464FD64F86501650364FC659465DB66DA66DB66D86AC56AB96ABD 6AE16AC66ABA6AB66AB76AC76AB46AAD6B5E6BC96C0B7007700C700D70017005 7014700E6FFF70006FFB70266FFC6FF7700A720171FF71F9720371FD73760000 F0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 74B874C074B574C174BE74B674BB74C275147513765C76647659765076537657 765A76A676BD76EC77C277BA78FF790C79137914790979107912791179AD79AC 7A5F7C1C7C297C197C207C1F7C2D7C1D7C267C287C227C257C307E5C7E507E56 7E637E587E627E5F7E517E607E577E537FB57FB37FF77FF8807581D181D20000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000081D0825F825E85B485C685C085C385C285B385B585BD85C785C485BF85CB 85CE85C885C585B185B685D2862485B885B785BE866987E787E687E287DB87EB 87EA87E587DF87F387E487D487DC87D387ED87D887E387A487D787D9880187F4 87E887DD8953894B894F894C89468950895189498B2A8B278B238B338B308B35 8B478B2F8B3C8B3E8B318B258B378B268B368B2E8B248B3B8B3D8B3A8C428C75 8C998C988C978CFE8D048D028D008E5C8E628E608E578E568E5E8E658E670000 F1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8E5B8E5A8E618E5D8E698E548F468F478F488F4B9128913A913B913E91A891A5 91A791AF91AA93B5938C939293B7939B939D938993A7938E93AA939E93A69395 93889399939F938D93B1939193B293A493A893B493A393A595D295D395D196B3 96D796DA5DC296DF96D896DD97239722972597AC97AE97A897AB97A497AA0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000097A297A597D797D997D697D897FA98509851985298B89941993C993A9A0F 9A0B9A099A0D9A049A119A0A9A059A079A069AC09ADC9B089B049B059B299B35 9B4A9B4C9B4B9BC79BC69BC39BBF9BC19BB59BB89BD39BB69BC49BB99BBD9D5C 9D539D4F9D4A9D5B9D4B9D599D569D4C9D579D529D549D5F9D589D5A9E8E9E8C 9EDF9F019F009F169F259F2B9F2A9F299F289F4C9F5551345135529652F753B4 56AB56AD56A656A756AA56AC58DA58DD58DB59125B3D5B3E5B3F5DC35E700000 F2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5FBF61FB65076510650D6509650C650E658465DE65DD66DE6AE76AE06ACC6AD1 6AD96ACB6ADF6ADC6AD06AEB6ACF6ACD6ADE6B606BB06C0C7019702770207016 702B702170227023702970177024701C702A720C720A72077202720572A572A6 72A472A372A174CB74C574B774C37516766077C977CA77C477F1791D791B0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007921791C7917791E79B07A677A687C337C3C7C397C2C7C3B7CEC7CEA7E76 7E757E787E707E777E6F7E7A7E727E747E687F4B7F4A7F837F867FB77FFD7FFE 807881D781D582648261826385EB85F185ED85D985E185E885DA85D785EC85F2 85F885D885DF85E385DC85D185F085E685EF85DE85E2880087FA880387F687F7 8809880C880B880687FC880887FF880A88028962895A895B89578961895C8958 895D8959898889B789B689F68B508B488B4A8B408B538B568B548B4B8B550000 F3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8B518B428B528B578C438C778C768C9A8D068D078D098DAC8DAA8DAD8DAB8E6D 8E788E738E6A8E6F8E7B8EC28F528F518F4F8F508F538FB49140913F91B091AD 93DE93C793CF93C293DA93D093F993EC93CC93D993A993E693CA93D493EE93E3 93D593C493CE93C093D293E7957D95DA95DB96E19729972B972C972897260000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000097B397B797B697DD97DE97DF985C9859985D985798BF98BD98BB98BE9948 9947994399A699A79A1A9A159A259A1D9A249A1B9A229A209A279A239A1E9A1C 9A149AC29B0B9B0A9B0E9B0C9B379BEA9BEB9BE09BDE9BE49BE69BE29BF09BD4 9BD79BEC9BDC9BD99BE59BD59BE19BDA9D779D819D8A9D849D889D719D809D78 9D869D8B9D8C9D7D9D6B9D749D759D709D699D859D739D7B9D829D6F9D799D7F 9D879D689E949E919EC09EFC9F2D9F409F419F4D9F569F579F58533756B20000 F4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 56B556B358E35B455DC65DC75EEE5EEF5FC05FC161F9651765166515651365DF 66E866E366E46AF36AF06AEA6AE86AF96AF16AEE6AEF703C7035702F70377034 703170427038703F703A70397040703B703370417213721472A8737D737C74BA 76AB76AA76BE76ED77CC77CE77CF77CD77F27925792379277928792479290000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000079B27A6E7A6C7A6D7AF77C497C487C4A7C477C457CEE7E7B7E7E7E817E80 7FBA7FFF807981DB81D9820B82688269862285FF860185FE861B860085F68604 86098605860C85FD8819881088118817881388168963896689B989F78B608B6A 8B5D8B688B638B658B678B6D8DAE8E868E888E848F598F568F578F558F588F5A 908D9143914191B791B591B291B3940B941393FB9420940F941493FE94159410 94289419940D93F5940093F79407940E9416941293FA940993F8940A93FF0000 F5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 93FC940C93F69411940695DE95E095DF972E972F97B997BB97FD97FE98609862 9863985F98C198C29950994E9959994C994B99539A329A349A319A2C9A2A9A36 9A299A2E9A389A2D9AC79ACA9AC69B109B129B119C0B9C089BF79C059C129BF8 9C409C079C0E9C069C179C149C099D9F9D999DA49D9D9D929D989D909D9B0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009DA09D949D9C9DAA9D979DA19D9A9DA29DA89D9E9DA39DBF9DA99D969DA6 9DA79E999E9B9E9A9EE59EE49EE79EE69F309F2E9F5B9F609F5E9F5D9F599F91 513A51395298529756C356BD56BE5B485B475DCB5DCF5EF161FD651B6B026AFC 6B036AF86B0070437044704A7048704970457046721D721A7219737E7517766A 77D0792D7931792F7C547C537CF27E8A7E877E887E8B7E867E8D7F4D7FBB8030 81DD8618862A8626861F8623861C86198627862E862186208629861E86250000 F6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8829881D881B88208824881C882B884A896D8969896E896B89FA8B798B788B45 8B7A8B7B8D108D148DAF8E8E8E8C8F5E8F5B8F5D91469144914591B9943F943B 94369429943D943C94309439942A9437942C9440943195E595E495E39735973A 97BF97E1986498C998C698C0995899569A399A3D9A469A449A429A419A3A0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009A3F9ACD9B159B179B189B169B3A9B529C2B9C1D9C1C9C2C9C239C289C29 9C249C219DB79DB69DBC9DC19DC79DCA9DCF9DBE9DC59DC39DBB9DB59DCE9DB9 9DBA9DAC9DC89DB19DAD9DCC9DB39DCD9DB29E7A9E9C9EEB9EEE9EED9F1B9F18 9F1A9F319F4E9F659F649F924EB956C656C556CB59715B4B5B4C5DD55DD15EF2 65216520652665226B0B6B086B096C0D7055705670577052721E721F72A9737F 74D874D574D974D7766D76AD793579B47A707A717C577C5C7C597C5B7C5A0000 F7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7CF47CF17E917F4F7F8781DE826B863486358633862C86328636882C88288826 882A8825897189BF89BE89FB8B7E8B848B828B868B858B7F8D158E958E948E9A 8E928E908E968E978F608F629147944C9450944A944B944F9447944594489449 9446973F97E3986A986998CB9954995B9A4E9A539A549A4C9A4F9A489A4A0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009A499A529A509AD09B199B2B9B3B9B569B559C469C489C3F9C449C399C33 9C419C3C9C379C349C329C3D9C369DDB9DD29DDE9DDA9DCB9DD09DDC9DD19DDF 9DE99DD99DD89DD69DF59DD59DDD9EB69EF09F359F339F329F429F6B9F959FA2 513D529958E858E759725B4D5DD8882F5F4F62016203620465296525659666EB 6B116B126B0F6BCA705B705A7222738273817383767077D47C677C667E95826C 863A86408639863C8631863B863E88308832882E883389768974897389FE0000 F8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8B8C8B8E8B8B8B888C458D198E988F648F6391BC94629455945D9457945E97C4 97C598009A569A599B1E9B1F9B209C529C589C509C4A9C4D9C4B9C559C599C4C 9C4E9DFB9DF79DEF9DE39DEB9DF89DE49DF69DE19DEE9DE69DF29DF09DE29DEC 9DF49DF39DE89DED9EC29ED09EF29EF39F069F1C9F389F379F369F439F4F0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009F719F709F6E9F6F56D356CD5B4E5C6D652D66ED66EE6B13705F7061705D 7060722374DB74E577D5793879B779B67C6A7E977F89826D8643883888378835 884B8B948B958E9E8E9F8EA08E9D91BE91BD91C2946B9468946996E597469743 974797C797E59A5E9AD59B599C639C679C669C629C5E9C609E029DFE9E079E03 9E069E059E009E019E099DFF9DFD9E049EA09F1E9F469F749F759F7656D4652E 65B86B186B196B176B1A7062722672AA77D877D979397C697C6B7CF67E9A0000 F9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7E987E9B7E9981E081E18646864786488979897A897C897B89FF8B988B998EA5 8EA48EA3946E946D946F9471947397499872995F9C689C6E9C6D9E0B9E0D9E10 9E0F9E129E119EA19EF59F099F479F789F7B9F7A9F79571E70667C6F883C8DB2 8EA691C394749478947694759A609C749C739C719C759E149E139EF69F0A0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009FA4706870657CF7866A883E883D883F8B9E8C9C8EA98EC9974B98739874 98CC996199AB9A649A669A679B249E159E179F4862076B1E7227864C8EA89482 948094819A699A689B2E9E197229864B8B9F94839C799EB776759A6B9C7A9E1D 7069706A9EA49F7E9F499F980000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 tcl8.4.20/library/encoding/euc-jp.enc0000644003604700454610000024115111737050674016027 0ustar dgp771div# Encoding file: euc-jp, multi-byte M 003F 0 79 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 0080008100820083008400850086008700880089008A008B008C008D0000008F 0090009100920093009400950096009700980099009A009B009C009D009E009F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8E 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FF61FF62FF63FF64FF65FF66FF67FF68FF69FF6AFF6BFF6CFF6DFF6EFF6F FF70FF71FF72FF73FF74FF75FF76FF77FF78FF79FF7AFF7BFF7CFF7DFF7EFF7F FF80FF81FF82FF83FF84FF85FF86FF87FF88FF89FF8AFF8BFF8CFF8DFF8EFF8F FF90FF91FF92FF93FF94FF95FF96FF97FF98FF99FF9AFF9BFF9CFF9DFF9EFF9F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 A1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000300030013002FF0CFF0E30FBFF1AFF1BFF1FFF01309B309C00B4FF4000A8 FF3EFFE3FF3F30FD30FE309D309E30034EDD30053006300730FC20152010FF0F FF3C301C2016FF5C2026202520182019201C201DFF08FF0930143015FF3BFF3D FF5BFF5D30083009300A300B300C300D300E300F30103011FF0B221200B100D7 00F7FF1D2260FF1CFF1E22662267221E22342642264000B0203220332103FFE5 FF0400A200A3FF05FF03FF06FF0AFF2000A72606260525CB25CF25CE25C70000 A2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000025C625A125A025B325B225BD25BC203B3012219221902191219330130000 00000000000000000000000000000000000000002208220B2286228722822283 222A2229000000000000000000000000000000002227222800AC21D221D42200 220300000000000000000000000000000000000000000000222022A523122202 220722612252226A226B221A223D221D2235222B222C00000000000000000000 00000000212B2030266F266D266A2020202100B6000000000000000025EF0000 A3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 FF10FF11FF12FF13FF14FF15FF16FF17FF18FF19000000000000000000000000 0000FF21FF22FF23FF24FF25FF26FF27FF28FF29FF2AFF2BFF2CFF2DFF2EFF2F FF30FF31FF32FF33FF34FF35FF36FF37FF38FF39FF3A00000000000000000000 0000FF41FF42FF43FF44FF45FF46FF47FF48FF49FF4AFF4BFF4CFF4DFF4EFF4F FF50FF51FF52FF53FF54FF55FF56FF57FF58FF59FF5A00000000000000000000 A4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000304130423043304430453046304730483049304A304B304C304D304E304F 3050305130523053305430553056305730583059305A305B305C305D305E305F 3060306130623063306430653066306730683069306A306B306C306D306E306F 3070307130723073307430753076307730783079307A307B307C307D307E307F 3080308130823083308430853086308730883089308A308B308C308D308E308F 3090309130923093000000000000000000000000000000000000000000000000 A5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000030A130A230A330A430A530A630A730A830A930AA30AB30AC30AD30AE30AF 30B030B130B230B330B430B530B630B730B830B930BA30BB30BC30BD30BE30BF 30C030C130C230C330C430C530C630C730C830C930CA30CB30CC30CD30CE30CF 30D030D130D230D330D430D530D630D730D830D930DA30DB30DC30DD30DE30DF 30E030E130E230E330E430E530E630E730E830E930EA30EB30EC30ED30EE30EF 30F030F130F230F330F430F530F6000000000000000000000000000000000000 A6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000039103920393039403950396039703980399039A039B039C039D039E039F 03A003A103A303A403A503A603A703A803A90000000000000000000000000000 000003B103B203B303B403B503B603B703B803B903BA03BB03BC03BD03BE03BF 03C003C103C303C403C503C603C703C803C90000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 A7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000004100411041204130414041504010416041704180419041A041B041C041D 041E041F0420042104220423042404250426042704280429042A042B042C042D 042E042F00000000000000000000000000000000000000000000000000000000 000004300431043204330434043504510436043704380439043A043B043C043D 043E043F0440044104420443044404450446044704480449044A044B044C044D 044E044F00000000000000000000000000000000000000000000000000000000 A8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000025002502250C251025182514251C252C25242534253C25012503250F2513 251B251725232533252B253B254B2520252F25282537253F251D253025252538 2542000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 B0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00004E9C55165A03963F54C0611B632859F690228475831C7A5060AA63E16E25 65ED846682A69BF56893572765A162715B9B59D0867B98F47D627DBE9B8E6216 7C9F88B75B895EB563096697684895C7978D674F4EE54F0A4F4D4F9D504956F2 593759D45A015C0960DF610F61706613690570BA754F757079FB7DAD7DEF80C3 840E88638B029055907A533B4E954EA557DF80B290C178EF4E0058F16EA29038 7A328328828B9C2F5141537054BD54E156E059FB5F1598F26DEB80E4852D0000 B1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009662967096A097FB540B53F35B8770CF7FBD8FC296E8536F9D5C7ABA4E11 789381FC6E26561855046B1D851A9C3B59E553A96D6674DC958F56424E91904B 96F2834F990C53E155B65B305F71662066F368046C386CF36D29745B76C87A4E 983482F1885B8A6092ED6DB275AB76CA99C560A68B018D8A95B2698E53AD5186 5712583059445BB45EF6602863A963F46CBF6F14708E7114715971D5733F7E01 827682D185979060925B9D1B586965BC6C5A752551F9592E59655F805FDC0000 B2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000062BC65FA6A2A6B276BB4738B7FC189569D2C9D0E9EC45CA16C96837B5104 5C4B61B681C6687672614E594FFA537860696E297A4F97F34E0B53164EEE4F55 4F3D4FA14F7352A053EF5609590F5AC15BB65BE179D16687679C67B66B4C6CB3 706B73C2798D79BE7A3C7B8782B182DB8304837783EF83D387668AB256298CA8 8FE6904E971E868A4FC45CE862117259753B81E582BD86FE8CC096C5991399D5 4ECB4F1A89E356DE584A58CA5EFB5FEB602A6094606261D0621262D065390000 B3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009B41666668B06D777070754C76867D7582A587F9958B968E8C9D51F152BE 591654B35BB35D16616869826DAF788D84CB88578A7293A79AB86D6C99A886D9 57A367FF86CE920E5283568754045ED362E164B9683C68386BBB737278BA7A6B 899A89D28D6B8F0390ED95A3969497695B665CB3697D984D984E639B7B206A2B 6A7F68B69C0D6F5F5272559D607062EC6D3B6E076ED1845B89108F444E149C39 53F6691B6A3A9784682A515C7AC384B291DC938C565B9D286822830584310000 B4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007CA5520882C574E64E7E4F8351A05BD2520A52D852E75DFB559A582A59E6 5B8C5B985BDB5E725E7960A3611F616361BE63DB656267D1685368FA6B3E6B53 6C576F226F976F4574B0751876E3770B7AFF7BA17C217DE97F367FF0809D8266 839E89B38ACC8CAB908494519593959195A2966597D3992882184E38542B5CB8 5DCC73A9764C773C5CA97FEB8D0B96C19811985498584F014F0E5371559C5668 57FA59475B095BC45C905E0C5E7E5FCC63EE673A65D765E2671F68CB68C40000 B5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006A5F5E306BC56C176C7D757F79485B637A007D005FBD898F8A188CB48D77 8ECC8F1D98E29A0E9B3C4E80507D510059935B9C622F628064EC6B3A72A07591 79477FA987FB8ABC8B7063AC83CA97A05409540355AB68546A588A7078276775 9ECD53745BA2811A865090064E184E454EC74F1153CA54385BAE5F1360256551 673D6C426C726CE3707874037A767AAE7B087D1A7CFE7D6665E7725B53BB5C45 5DE862D262E063196E20865A8A318DDD92F86F0179A69B5A4EA84EAB4EAC0000 B6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00004F9B4FA050D151477AF6517151F653545321537F53EB55AC58835CE15F37 5F4A602F6050606D631F65596A4B6CC172C272ED77EF80F881058208854E90F7 93E197FF99579A5A4EF051DD5C2D6681696D5C4066F26975738968507C8150C5 52E457475DFE932665A46B236B3D7434798179BD7B4B7DCA82B983CC887F895F 8B398FD191D1541F92804E5D503653E5533A72D7739677E982E68EAF99C699C8 99D25177611A865E55B07A7A50765BD3904796854E326ADB91E75C515C480000 B7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000063987A9F6C9397748F617AAA718A96887C8268177E706851936C52F2541B 85AB8A137FA48ECD90E15366888879414FC250BE521151445553572D73EA578B 59515F625F8460756176616761A963B2643A656C666F68426E1375667A3D7CFB 7D4C7D997E4B7F6B830E834A86CD8A088A638B668EFD981A9D8F82B88FCE9BE8 5287621F64836FC09699684150916B206C7A6F547A747D5088408A2367084EF6 503950265065517C5238526355A7570F58055ACC5EFA61B261F862F363720000 B8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000691C6A29727D72AC732E7814786F7D79770C80A9898B8B198CE28ED29063 9375967A98559A139E785143539F53B35E7B5F266E1B6E90738473FE7D438237 8A008AFA96504E4E500B53E4547C56FA59D15B645DF15EAB5F276238654567AF 6E5672D07CCA88B480A180E183F0864E8A878DE8923796C798679F134E944E92 4F0D53485449543E5A2F5F8C5FA1609F68A76A8E745A78818A9E8AA48B779190 4E5E9BC94EA44F7C4FAF501950165149516C529F52B952FE539A53E354110000 B9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000540E5589575157A2597D5B545B5D5B8F5DE55DE75DF75E785E835E9A5EB7 5F186052614C629762D863A7653B6602664366F4676D6821689769CB6C5F6D2A 6D696E2F6E9D75327687786C7A3F7CE07D057D187D5E7DB18015800380AF80B1 8154818F822A8352884C88618B1B8CA28CFC90CA91759271783F92FC95A4964D 980599999AD89D3B525B52AB53F7540858D562F76FE08C6A8F5F9EB9514B523B 544A56FD7A4091779D609ED273446F09817075115FFD60DA9AA872DB8FBC0000 BA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006B6498034ECA56F0576458BE5A5A606861C7660F6606683968B16DF775D5 7D3A826E9B424E9B4F5053C955065D6F5DE65DEE67FB6C99747378028A509396 88DF57505EA7632B50B550AC518D670054C9585E59BB5BB05F69624D63A1683D 6B736E08707D91C7728078157826796D658E7D3083DC88C18F09969B52645728 67507F6A8CA151B45742962A583A698A80B454B25D0E57FC78959DFA4F5C524A 548B643E6628671467F57A847B567D22932F685C9BAD7B395319518A52370000 BB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005BDF62F664AE64E6672D6BBA85A996D176909BD6634C93069BAB76BF6652 4E09509853C25C7160E864926563685F71E673CA75237B977E8286958B838CDB 9178991065AC66AB6B8B4ED54ED44F3A4F7F523A53F853F255E356DB58EB59CB 59C959FF5B505C4D5E025E2B5FD7601D6307652F5B5C65AF65BD65E8679D6B62 6B7B6C0F7345794979C17CF87D197D2B80A2810281F389968A5E8A698A668A8C 8AEE8CC78CDC96CC98FC6B6F4E8B4F3C4F8D51505B575BFA6148630166420000 BC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006B216ECB6CBB723E74BD75D478C1793A800C803381EA84948F9E6C509E7F 5F0F8B589D2B7AFA8EF85B8D96EB4E0353F157F759315AC95BA460896E7F6F06 75BE8CEA5B9F85007BE0507267F4829D5C61854A7E1E820E51995C0463688D66 659C716E793E7D1780058B1D8ECA906E86C790AA501F52FA5C3A6753707C7235 914C91C8932B82E55BC25F3160F94E3B53D65B88624B67316B8A72E973E07A2E 816B8DA391529996511253D7546A5BFF63886A397DAC970056DA53CE54680000 BD 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005B975C315DDE4FEE610162FE6D3279C079CB7D427E4D7FD281ED821F8490 884689728B908E748F2F9031914B916C96C6919C4EC04F4F514553415F93620E 67D46C416E0B73637E2691CD928353D459195BBF6DD1795D7E2E7C9B587E719F 51FA88538FF04FCA5CFB662577AC7AE3821C99FF51C65FAA65EC696F6B896DF3 6E966F6476FE7D145DE190759187980651E6521D6240669166D96E1A5EB67DD2 7F7266F885AF85F78AF852A953D959735E8F5F90605592E4966450B7511F0000 BE 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000052DD5320534753EC54E8554655315617596859BE5A3C5BB55C065C0F5C11 5C1A5E845E8A5EE05F70627F628462DB638C63776607660C662D6676677E68A2 6A1F6A356CBC6D886E096E58713C7126716775C77701785D7901796579F07AE0 7B117CA77D39809683D6848B8549885D88F38A1F8A3C8A548A738C618CDE91A4 9266937E9418969C97984E0A4E084E1E4E575197527057CE583458CC5B225E38 60C564FE676167566D4472B675737A6384B88B7291B89320563157F498FE0000 BF 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000062ED690D6B9671ED7E548077827289E698DF87558FB15C3B4F384FE14FB5 55075A205BDD5BE95FC3614E632F65B0664B68EE699B6D786DF1753375B9771F 795E79E67D3381E382AF85AA89AA8A3A8EAB8F9B903291DD97074EBA4EC15203 587558EC5C0B751A5C3D814E8A0A8FC59663976D7B258ACF9808916256F353A8 9017543957825E2563A86C34708A77617C8B7FE088709042915493109318968F 745E9AC45D075D69657067A28DA896DB636E6749691983C5981796C088FE0000 C0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006F84647A5BF84E16702C755D662F51C4523652E259D35F8160276210653F 6574661F667468F268166B636E057272751F76DB7CBE805658F088FD897F8AA0 8A938ACB901D91929752975965897A0E810696BB5E2D60DC621A65A566146790 77F37A4D7C4D7E3E810A8CAC8D648DE18E5F78A9520762D963A5644262988A2D 7A837BC08AAC96EA7D76820C87494ED95148534353605BA35C025C165DDD6226 624764B0681368346CC96D456D1767D36F5C714E717D65CB7A7F7BAD7DDA0000 C1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007E4A7FA8817A821B823985A68A6E8CCE8DF59078907792AD929195839BAE 524D55846F387136516879857E5581B37CCE564C58515CA863AA66FE66FD695A 72D9758F758E790E795679DF7C977D207D4486078A34963B90619F2050E75275 53CC53E2500955AA58EE594F723D5B8B5C64531D60E360F3635C6383633F63BB 64CD65E966F95DE369CD69FD6F1571E54E8975E976F87A937CDF7DCF7D9C8061 83498358846C84BC85FB88C58D709001906D9397971C9A1250CF5897618E0000 C2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000081D385358D0890204FC3507452475373606F6349675F6E2C8DB3901F4FD7 5C5E8CCA65CF7D9A53528896517663C35B585B6B5C0A640D6751905C4ED6591A 592A6C708A51553E581559A560F0625367C182356955964099C49A284F535806 5BFE80105CB15E2F5F856020614B623466FF6CF06EDE80CE817F82D4888B8CB8 9000902E968A9EDB9BDB4EE353F059277B2C918D984C9DF96EDD702753535544 5B856258629E62D36CA26FEF74228A1794386FC18AFE833851E786F853EA0000 C3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000053E94F4690548FB0596A81315DFD7AEA8FBF68DA8C3772F89C486A3D8AB0 4E3953585606576662C563A265E66B4E6DE16E5B70AD77ED7AEF7BAA7DBB803D 80C686CB8A95935B56E358C75F3E65AD66966A806BB575378AC7502477E55730 5F1B6065667A6C6075F47A1A7F6E81F48718904599B37BC9755C7AF97B5184C4 901079E97A9283365AE177404E2D4EF25B995FE062BD663C67F16CE8866B8877 8A3B914E92F399D06A177026732A82E784578CAF4E01514651CB558B5BF50000 C4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005E165E335E815F145F355F6B5FB461F2631166A2671D6F6E7252753A773A 80748139817887768ABF8ADC8D858DF3929A957798029CE552C5635776F46715 6C8873CD8CC393AE96736D25589C690E69CC8FFD939A75DB901A585A680263B4 69FB4F436F2C67D88FBB85267DB49354693F6F70576A58F75B2C7D2C722A540A 91E39DB44EAD4F4E505C507552438C9E544858245B9A5E1D5E955EAD5EF75F1F 608C62B5633A63D068AF6C407887798E7A0B7DE082478A028AE68E4490130000 C5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000090B8912D91D89F0E6CE5645864E265756EF476847B1B906993D16EBA54F2 5FB964A48F4D8FED92445178586B59295C555E976DFB7E8F751C8CBC8EE2985B 70B94F1D6BBF6FB1753096FB514E54105835585759AC5C605F926597675C6E21 767B83DF8CED901490FD934D7825783A52AA5EA6571F597460125012515A51AC 51CD520055105854585859575B955CF65D8B60BC6295642D6771684368BC68DF 76D76DD86E6F6D9B706F71C85F5375D879777B497B547B527CD67D7152300000 C6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008463856985E48A0E8B048C468E0F9003900F94199676982D9A3095D850CD 52D5540C58025C0E61A7649E6D1E77B37AE580F48404905392855CE09D07533F 5F975FB36D9C7279776379BF7BE46BD272EC8AAD68036A6151F87A8169345C4A 9CF682EB5BC59149701E56785C6F60C765666C8C8C5A90419813545166C7920D 594890A351854E4D51EA85998B0E7058637A934B696299B47E04757753576960 8EDF96E36C5D4E8C5C3C5F108FE953028CD1808986795EFF65E54E7351650000 C7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000059825C3F97EE4EFB598A5FCD8A8D6FE179B079625BE78471732B71B15E74 5FF5637B649A71C37C984E435EFC4E4B57DC56A260A96FC37D0D80FD813381BF 8FB2899786A45DF4628A64AD898767776CE26D3E743678345A467F7582AD99AC 4FF35EC362DD63926557676F76C3724C80CC80BA8F29914D500D57F95A926885 6973716472FD8CB758F28CE0966A9019877F79E477E784294F2F5265535A62CD 67CF6CCA767D7B947C95823685848FEB66DD6F2072067E1B83AB99C19EA60000 C8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000051FD7BB178727BB880877B486AE85E61808C75517560516B92626E8C767A 91979AEA4F107F70629C7B4F95A59CE9567A585986E496BC4F345224534A53CD 53DB5E06642C6591677F6C3E6C4E724872AF73ED75547E41822C85E98CA97BC4 91C67169981298EF633D6669756A76E478D0854386EE532A5351542659835E87 5F7C60B26249627962AB65906BD46CCC75B276AE789179D87DCB7F7780A588AB 8AB98CBB907F975E98DB6A0B7C3850995C3E5FAE67876BD8743577097F8E0000 C9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009F3B67CA7A175339758B9AED5F66819D83F180985F3C5FC575627B46903C 686759EB5A9B7D10767E8B2C4FF55F6A6A196C376F0274E2796888688A558C79 5EDF63CF75C579D282D7932892F2849C86ED9C2D54C15F6C658C6D5C70158CA7 8CD3983B654F74F64E0D4ED857E0592B5A665BCC51A85E035E9C601662766577 65A7666E6D6E72367B268150819A82998B5C8CA08CE68D74961C96444FAE64AB 6B66821E8461856A90E85C01695398A8847A85574F0F526F5FA95E45670D0000 CA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000798F8179890789866DF55F1762556CB84ECF72699B925206543B567458B3 61A4626E711A596E7C897CDE7D1B96F06587805E4E194F75517558405E635E73 5F0A67C44E26853D9589965B7C73980150FB58C1765678A7522577A585117B86 504F590972477BC77DE88FBA8FD4904D4FBF52C95A295F0197AD4FDD821792EA 570363556B69752B88DC8F147A4252DF58936155620A66AE6BCD7C3F83E95023 4FF853055446583159495B9D5CF05CEF5D295E9662B16367653E65B9670B0000 CB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006CD56CE170F978327E2B80DE82B3840C84EC870289128A2A8C4A90A692D2 98FD9CF39D6C4E4F4EA1508D5256574A59A85E3D5FD85FD9623F66B4671B67D0 68D251927D2180AA81A88B008C8C8CBF927E96325420982C531750D5535C58A8 64B26734726777667A4691E652C36CA16B8658005E4C5954672C7FFB51E176C6 646978E89B549EBB57CB59B96627679A6BCE54E969D95E55819C67959BAA67FE 9C52685D4EA64FE353C862B9672B6CAB8FC44FAD7E6D9EBF4E0761626E800000 CC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006F2B85135473672A9B455DF37B955CAC5BC6871C6E4A84D17A1481085999 7C8D6C11772052D959227121725F77DB97279D61690B5A7F5A1851A5540D547D 660E76DF8FF792989CF459EA725D6EC5514D68C97DBF7DEC97629EBA64786A21 830259845B5F6BDB731B76F27DB280178499513267289ED976EE676252FF9905 5C24623B7C7E8CB0554F60B67D0B958053014E5F51B6591C723A803691CE5F25 77E253845F797D0485AC8A338E8D975667F385AE9453610961086CB976520000 CD 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008AED8F38552F4F51512A52C753CB5BA55E7D60A0618263D6670967DA6E67 6D8C733673377531795088D58A98904A909190F596C4878D59154E884F594E0E 8A898F3F981050AD5E7C59965BB95EB863DA63FA64C166DC694A69D86D0B6EB6 719475287AAF7F8A8000844984C989818B218E0A9065967D990A617E62916B32 6C836D747FCC7FFC6DC07F8587BA88F8676583B1983C96F76D1B7D61843D916A 4E7153755D506B046FEB85CD862D89A75229540F5C65674E68A8740674830000 CE 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000075E288CF88E191CC96E296785F8B73877ACB844E63A0756552896D416E9C 74097559786B7C9296867ADC9F8D4FB6616E65C5865C4E864EAE50DA4E2151CC 5BEE659968816DBC731F764277AD7A1C7CE7826F8AD2907C91CF96759818529B 7DD1502B539867976DCB71D0743381E88F2A96A39C579E9F746058416D997D2F 985E4EE44F364F8B51B752B15DBA601C73B2793C82D3923496B796F6970A9E97 9F6266A66B74521752A370C888C25EC9604B61906F2371497C3E7DF4806F0000 CF 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000084EE9023932C54429B6F6AD370898CC28DEF973252B45A415ECA5F046717 697C69946D6A6F0F726272FC7BED8001807E874B90CE516D9E937984808B9332 8AD6502D548C8A716B6A8CC4810760D167A09DF24E994E989C108A6B85C18568 69006E7E78978155000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 D0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005F0C4E104E154E2A4E314E364E3C4E3F4E424E564E584E824E858C6B4E8A 82125F0D4E8E4E9E4E9F4EA04EA24EB04EB34EB64ECE4ECD4EC44EC64EC24ED7 4EDE4EED4EDF4EF74F094F5A4F304F5B4F5D4F574F474F764F884F8F4F984F7B 4F694F704F914F6F4F864F9651184FD44FDF4FCE4FD84FDB4FD14FDA4FD04FE4 4FE5501A50285014502A502550054F1C4FF650215029502C4FFE4FEF50115006 504350476703505550505048505A5056506C50785080509A508550B450B20000 D1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000050C950CA50B350C250D650DE50E550ED50E350EE50F950F5510951015102 511651155114511A5121513A5137513C513B513F51405152514C515451627AF8 5169516A516E5180518256D8518C5189518F519151935195519651A451A651A2 51A951AA51AB51B351B151B251B051B551BD51C551C951DB51E0865551E951ED 51F051F551FE5204520B5214520E5227522A522E52335239524F5244524B524C 525E5254526A527452695273527F527D528D529452925271528852918FA80000 D2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008FA752AC52AD52BC52B552C152CD52D752DE52E352E698ED52E052F352F5 52F852F9530653087538530D5310530F5315531A5323532F5331533353385340 534653454E175349534D51D6535E5369536E5918537B53775382539653A053A6 53A553AE53B053B653C37C1296D953DF66FC71EE53EE53E853ED53FA5401543D 5440542C542D543C542E54365429541D544E548F5475548E545F547154775470 5492547B5480547654845490548654C754A254B854A554AC54C454C854A80000 D3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000054AB54C254A454BE54BC54D854E554E6550F551454FD54EE54ED54FA54E2 553955405563554C552E555C55455556555755385533555D5599558054AF558A 559F557B557E5598559E55AE557C558355A9558755A855DA55C555DF55C455DC 55E455D4561455F7561655FE55FD561B55F9564E565071DF5634563656325638 566B5664562F566C566A56865680568A56A05694568F56A556AE56B656B456C2 56BC56C156C356C056C856CE56D156D356D756EE56F9570056FF570457090000 D4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005708570B570D57135718571655C7571C572657375738574E573B5740574F 576957C057885761577F5789579357A057B357A457AA57B057C357C657D457D2 57D3580A57D657E3580B5819581D587258215862584B58706BC05852583D5879 588558B9589F58AB58BA58DE58BB58B858AE58C558D358D158D758D958D858E5 58DC58E458DF58EF58FA58F958FB58FC58FD5902590A5910591B68A65925592C 592D59325938593E7AD259555950594E595A5958596259605967596C59690000 D5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000059785981599D4F5E4FAB59A359B259C659E859DC598D59D959DA5A255A1F 5A115A1C5A095A1A5A405A6C5A495A355A365A625A6A5A9A5ABC5ABE5ACB5AC2 5ABD5AE35AD75AE65AE95AD65AFA5AFB5B0C5B0B5B165B325AD05B2A5B365B3E 5B435B455B405B515B555B5A5B5B5B655B695B705B735B755B7865885B7A5B80 5B835BA65BB85BC35BC75BC95BD45BD05BE45BE65BE25BDE5BE55BEB5BF05BF6 5BF35C055C075C085C0D5C135C205C225C285C385C395C415C465C4E5C530000 D6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005C505C4F5B715C6C5C6E4E625C765C795C8C5C915C94599B5CAB5CBB5CB6 5CBC5CB75CC55CBE5CC75CD95CE95CFD5CFA5CED5D8C5CEA5D0B5D155D175D5C 5D1F5D1B5D115D145D225D1A5D195D185D4C5D525D4E5D4B5D6C5D735D765D87 5D845D825DA25D9D5DAC5DAE5DBD5D905DB75DBC5DC95DCD5DD35DD25DD65DDB 5DEB5DF25DF55E0B5E1A5E195E115E1B5E365E375E445E435E405E4E5E575E54 5E5F5E625E645E475E755E765E7A9EBC5E7F5EA05EC15EC25EC85ED05ECF0000 D7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005ED65EE35EDD5EDA5EDB5EE25EE15EE85EE95EEC5EF15EF35EF05EF45EF8 5EFE5F035F095F5D5F5C5F0B5F115F165F295F2D5F385F415F485F4C5F4E5F2F 5F515F565F575F595F615F6D5F735F775F835F825F7F5F8A5F885F915F875F9E 5F995F985FA05FA85FAD5FBC5FD65FFB5FE45FF85FF15FDD60B35FFF60216060 601960106029600E6031601B6015602B6026600F603A605A6041606A6077605F 604A6046604D6063604360646042606C606B60596081608D60E76083609A0000 D8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006084609B60966097609260A7608B60E160B860E060D360B45FF060BD60C6 60B560D8614D6115610660F660F7610060F460FA6103612160FB60F1610D610E 6147613E61286127614A613F613C612C6134613D614261446173617761586159 615A616B6174616F61656171615F615D6153617561996196618761AC6194619A 618A619161AB61AE61CC61CA61C961F761C861C361C661BA61CB7F7961CD61E6 61E361F661FA61F461FF61FD61FC61FE620062086209620D620C6214621B0000 D9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000621E6221622A622E6230623262336241624E625E6263625B62606268627C 62826289627E62926293629662D46283629462D762D162BB62CF62FF62C664D4 62C862DC62CC62CA62C262C7629B62C9630C62EE62F163276302630862EF62F5 6350633E634D641C634F6396638E638063AB637663A3638F6389639F63B5636B 636963BE63E963C063C663E363C963D263F663C4641664346406641364266436 651D64176428640F6467646F6476644E652A6495649364A564A9648864BC0000 DA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000064DA64D264C564C764BB64D864C264F164E7820964E064E162AC64E364EF 652C64F664F464F264FA650064FD6518651C650565246523652B653465356537 65366538754B654865566555654D6558655E655D65726578658265838B8A659B 659F65AB65B765C365C665C165C465CC65D265DB65D965E065E165F16772660A 660365FB6773663566366634661C664F664466496641665E665D666466676668 665F6662667066836688668E668966846698669D66C166B966C966BE66BC0000 DB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000066C466B866D666DA66E0663F66E666E966F066F566F7670F6716671E6726 67279738672E673F67366741673867376746675E676067596763676467896770 67A9677C676A678C678B67A667A1678567B767EF67B467EC67B367E967B867E4 67DE67DD67E267EE67B967CE67C667E76A9C681E684668296840684D6832684E 68B3682B685968636877687F689F688F68AD6894689D689B68836AAE68B96874 68B568A068BA690F688D687E690168CA690868D86922692668E1690C68CD0000 DC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000068D468E768D569366912690468D768E3692568F968E068EF6928692A691A 6923692168C669796977695C6978696B6954697E696E69396974693D69596930 6961695E695D6981696A69B269AE69D069BF69C169D369BE69CE5BE869CA69DD 69BB69C369A76A2E699169A0699C699569B469DE69E86A026A1B69FF6B0A69F9 69F269E76A0569B16A1E69ED6A1469EB6A0A6A126AC16A236A136A446A0C6A72 6A366A786A476A626A596A666A486A386A226A906A8D6AA06A846AA26AA30000 DD 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006A9786176ABB6AC36AC26AB86AB36AAC6ADE6AD16ADF6AAA6ADA6AEA6AFB 6B0586166AFA6B126B169B316B1F6B386B3776DC6B3998EE6B476B436B496B50 6B596B546B5B6B5F6B616B786B796B7F6B806B846B836B8D6B986B956B9E6BA4 6BAA6BAB6BAF6BB26BB16BB36BB76BBC6BC66BCB6BD36BDF6BEC6BEB6BF36BEF 9EBE6C086C136C146C1B6C246C236C5E6C556C626C6A6C826C8D6C9A6C816C9B 6C7E6C686C736C926C906CC46CF16CD36CBD6CD76CC56CDD6CAE6CB16CBE0000 DE 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006CBA6CDB6CEF6CD96CEA6D1F884D6D366D2B6D3D6D386D196D356D336D12 6D0C6D636D936D646D5A6D796D596D8E6D956FE46D856DF96E156E0A6DB56DC7 6DE66DB86DC66DEC6DDE6DCC6DE86DD26DC56DFA6DD96DE46DD56DEA6DEE6E2D 6E6E6E2E6E196E726E5F6E3E6E236E6B6E2B6E766E4D6E1F6E436E3A6E4E6E24 6EFF6E1D6E386E826EAA6E986EC96EB76ED36EBD6EAF6EC46EB26ED46ED56E8F 6EA56EC26E9F6F416F11704C6EEC6EF86EFE6F3F6EF26F316EEF6F326ECC0000 DF 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006F3E6F136EF76F866F7A6F786F816F806F6F6F5B6FF36F6D6F826F7C6F58 6F8E6F916FC26F666FB36FA36FA16FA46FB96FC66FAA6FDF6FD56FEC6FD46FD8 6FF16FEE6FDB7009700B6FFA70117001700F6FFE701B701A6F74701D7018701F 7030703E7032705170637099709270AF70F170AC70B870B370AE70DF70CB70DD 70D9710970FD711C711971657155718871667162714C7156716C718F71FB7184 719571A871AC71D771B971BE71D271C971D471CE71E071EC71E771F571FC0000 E0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000071F971FF720D7210721B7228722D722C72307232723B723C723F72407246 724B72587274727E7282728172877292729672A272A772B972B272C372C672C4 72CE72D272E272E072E172F972F7500F7317730A731C7316731D7334732F7329 7325733E734E734F9ED87357736A7368737073787375737B737A73C873B373CE 73BB73C073E573EE73DE74A27405746F742573F87432743A7455743F745F7459 7441745C746974707463746A7476747E748B749E74A774CA74CF74D473F10000 E1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000074E074E374E774E974EE74F274F074F174F874F7750475037505750C750E 750D75157513751E7526752C753C7544754D754A7549755B7546755A75697564 7567756B756D75787576758675877574758A758975827594759A759D75A575A3 75C275B375C375B575BD75B875BC75B175CD75CA75D275D975E375DE75FE75FF 75FC760175F075FA75F275F3760B760D7609761F762776207621762276247634 7630763B764776487646765C76587661766276687669766A7667766C76700000 E2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000767276767678767C768076837688768B768E769676937699769A76B076B4 76B876B976BA76C276CD76D676D276DE76E176E576E776EA862F76FB77087707 770477297724771E77257726771B773777387747775A7768776B775B7765777F 777E7779778E778B779177A0779E77B077B677B977BF77BC77BD77BB77C777CD 77D777DA77DC77E377EE77FC780C781279267820792A7845788E78747886787C 789A788C78A378B578AA78AF78D178C678CB78D478BE78BC78C578CA78EC0000 E3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000078E778DA78FD78F47907791279117919792C792B794079607957795F795A 79557953797A797F798A799D79A79F4B79AA79AE79B379B979BA79C979D579E7 79EC79E179E37A087A0D7A187A197A207A1F79807A317A3B7A3E7A377A437A57 7A497A617A627A699F9D7A707A797A7D7A887A977A957A987A967AA97AC87AB0 7AB67AC57AC47ABF90837AC77ACA7ACD7ACF7AD57AD37AD97ADA7ADD7AE17AE2 7AE67AED7AF07B027B0F7B0A7B067B337B187B197B1E7B357B287B367B500000 E4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007B7A7B047B4D7B0B7B4C7B457B757B657B747B677B707B717B6C7B6E7B9D 7B987B9F7B8D7B9C7B9A7B8B7B927B8F7B5D7B997BCB7BC17BCC7BCF7BB47BC6 7BDD7BE97C117C147BE67BE57C607C007C077C137BF37BF77C177C0D7BF67C23 7C277C2A7C1F7C377C2B7C3D7C4C7C437C547C4F7C407C507C587C5F7C647C56 7C657C6C7C757C837C907CA47CAD7CA27CAB7CA17CA87CB37CB27CB17CAE7CB9 7CBD7CC07CC57CC27CD87CD27CDC7CE29B3B7CEF7CF27CF47CF67CFA7D060000 E5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007D027D1C7D157D0A7D457D4B7D2E7D327D3F7D357D467D737D567D4E7D72 7D687D6E7D4F7D637D937D897D5B7D8F7D7D7D9B7DBA7DAE7DA37DB57DC77DBD 7DAB7E3D7DA27DAF7DDC7DB87D9F7DB07DD87DDD7DE47DDE7DFB7DF27DE17E05 7E0A7E237E217E127E317E1F7E097E0B7E227E467E667E3B7E357E397E437E37 7E327E3A7E677E5D7E567E5E7E597E5A7E797E6A7E697E7C7E7B7E837DD57E7D 8FAE7E7F7E887E897E8C7E927E907E937E947E967E8E7E9B7E9C7F387F3A0000 E6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007F457F4C7F4D7F4E7F507F517F557F547F587F5F7F607F687F697F677F78 7F827F867F837F887F877F8C7F947F9E7F9D7F9A7FA37FAF7FB27FB97FAE7FB6 7FB88B717FC57FC67FCA7FD57FD47FE17FE67FE97FF37FF998DC80068004800B 801280188019801C80218028803F803B804A804680528058805A805F80628068 80738072807080768079807D807F808480868085809B8093809A80AD519080AC 80DB80E580D980DD80C480DA80D6810980EF80F1811B81298123812F814B0000 E7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000968B8146813E8153815180FC8171816E81658166817481838188818A8180 818281A0819581A481A3815F819381A981B081B581BE81B881BD81C081C281BA 81C981CD81D181D981D881C881DA81DF81E081E781FA81FB81FE820182028205 8207820A820D821082168229822B82388233824082598258825D825A825F8264 82628268826A826B822E827182778278827E828D829282AB829F82BB82AC82E1 82E382DF82D282F482F382FA8393830382FB82F982DE830682DC830982D90000 E8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000833583348316833283318340833983508345832F832B831783188385839A 83AA839F83A283968323838E8387838A837C83B58373837583A0838983A883F4 841383EB83CE83FD840383D8840B83C183F7840783E083F2840D8422842083BD 8438850683FB846D842A843C855A84848477846B84AD846E848284698446842C 846F8479843584CA846284B984BF849F84D984CD84BB84DA84D084C184C684D6 84A1852184FF84F485178518852C851F8515851484FC85408563855885480000 E9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000085418602854B8555858085A485888591858A85A8856D8594859B85EA8587 859C8577857E859085C985BA85CF85B985D085D585DD85E585DC85F9860A8613 860B85FE85FA86068622861A8630863F864D4E558654865F86678671869386A3 86A986AA868B868C86B686AF86C486C686B086C9882386AB86D486DE86E986EC 86DF86DB86EF8712870687088700870386FB87118709870D86F9870A8734873F 8737873B87258729871A8760875F8778874C874E877487578768876E87590000 EA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000087538763876A880587A2879F878287AF87CB87BD87C087D096D687AB87C4 87B387C787C687BB87EF87F287E0880F880D87FE87F687F7880E87D288118816 8815882288218831883688398827883B8844884288528859885E8862886B8881 887E889E8875887D88B5887288828897889288AE889988A2888D88A488B088BF 88B188C388C488D488D888D988DD88F9890288FC88F488E888F28904890C890A 89138943891E8925892A892B89418944893B89368938894C891D8960895E0000 EB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000089668964896D896A896F89748977897E89838988898A8993899889A189A9 89A689AC89AF89B289BA89BD89BF89C089DA89DC89DD89E789F489F88A038A16 8A108A0C8A1B8A1D8A258A368A418A5B8A528A468A488A7C8A6D8A6C8A628A85 8A828A848AA88AA18A918AA58AA68A9A8AA38AC48ACD8AC28ADA8AEB8AF38AE7 8AE48AF18B148AE08AE28AF78ADE8ADB8B0C8B078B1A8AE18B168B108B178B20 8B3397AB8B268B2B8B3E8B288B418B4C8B4F8B4E8B498B568B5B8B5A8B6B0000 EC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008B5F8B6C8B6F8B748B7D8B808B8C8B8E8B928B938B968B998B9A8C3A8C41 8C3F8C488C4C8C4E8C508C558C628C6C8C788C7A8C828C898C858C8A8C8D8C8E 8C948C7C8C98621D8CAD8CAA8CBD8CB28CB38CAE8CB68CC88CC18CE48CE38CDA 8CFD8CFA8CFB8D048D058D0A8D078D0F8D0D8D109F4E8D138CCD8D148D168D67 8D6D8D718D738D818D998DC28DBE8DBA8DCF8DDA8DD68DCC8DDB8DCB8DEA8DEB 8DDF8DE38DFC8E088E098DFF8E1D8E1E8E108E1F8E428E358E308E348E4A0000 ED 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008E478E498E4C8E508E488E598E648E608E2A8E638E558E768E728E7C8E81 8E878E858E848E8B8E8A8E938E918E948E998EAA8EA18EAC8EB08EC68EB18EBE 8EC58EC88ECB8EDB8EE38EFC8EFB8EEB8EFE8F0A8F058F158F128F198F138F1C 8F1F8F1B8F0C8F268F338F3B8F398F458F428F3E8F4C8F498F468F4E8F578F5C 8F628F638F648F9C8F9F8FA38FAD8FAF8FB78FDA8FE58FE28FEA8FEF90878FF4 90058FF98FFA901190159021900D901E9016900B90279036903590398FF80000 EE 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000904F905090519052900E9049903E90569058905E9068906F907696A89072 9082907D90819080908A9089908F90A890AF90B190B590E290E4624890DB9102 9112911991329130914A9156915891639165916991739172918B9189918291A2 91AB91AF91AA91B591B491BA91C091C191C991CB91D091D691DF91E191DB91FC 91F591F6921E91FF9214922C92159211925E925792459249926492489295923F 924B9250929C92969293929B925A92CF92B992B792E9930F92FA9344932E0000 EF 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000093199322931A9323933A9335933B935C9360937C936E935693B093AC93AD 939493B993D693D793E893E593D893C393DD93D093C893E4941A941494139403 940794109436942B94359421943A944194529444945B94609462945E946A9229 947094759477947D945A947C947E9481947F95829587958A9594959695989599 95A095A895A795AD95BC95BB95B995BE95CA6FF695C395CD95CC95D595D495D6 95DC95E195E595E296219628962E962F9642964C964F964B9677965C965E0000 F0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000965D965F96669672966C968D96989695969796AA96A796B196B296B096B4 96B696B896B996CE96CB96C996CD894D96DC970D96D596F99704970697089713 970E9711970F971697199724972A97309739973D973E97449746974897429749 975C976097649766976852D2976B977197799785977C9781977A9786978B978F 9790979C97A897A697A397B397B497C397C697C897CB97DC97ED9F4F97F27ADF 97F697F5980F980C9838982498219837983D9846984F984B986B986F98700000 F1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000098719874987398AA98AF98B198B698C498C398C698E998EB990399099912 991499189921991D991E99249920992C992E993D993E9942994999459950994B 99519952994C99559997999899A599AD99AE99BC99DF99DB99DD99D899D199ED 99EE99F199F299FB99F89A019A0F9A0599E29A199A2B9A379A459A429A409A43 9A3E9A559A4D9A5B9A579A5F9A629A659A649A699A6B9A6A9AAD9AB09ABC9AC0 9ACF9AD19AD39AD49ADE9ADF9AE29AE39AE69AEF9AEB9AEE9AF49AF19AF70000 F2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009AFB9B069B189B1A9B1F9B229B239B259B279B289B299B2A9B2E9B2F9B32 9B449B439B4F9B4D9B4E9B519B589B749B939B839B919B969B979B9F9BA09BA8 9BB49BC09BCA9BB99BC69BCF9BD19BD29BE39BE29BE49BD49BE19C3A9BF29BF1 9BF09C159C149C099C139C0C9C069C089C129C0A9C049C2E9C1B9C259C249C21 9C309C479C329C469C3E9C5A9C609C679C769C789CE79CEC9CF09D099D089CEB 9D039D069D2A9D269DAF9D239D1F9D449D159D129D419D3F9D3E9D469D480000 F3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009D5D9D5E9D649D519D509D599D729D899D879DAB9D6F9D7A9D9A9DA49DA9 9DB29DC49DC19DBB9DB89DBA9DC69DCF9DC29DD99DD39DF89DE69DED9DEF9DFD 9E1A9E1B9E1E9E759E799E7D9E819E889E8B9E8C9E929E959E919E9D9EA59EA9 9EB89EAA9EAD97619ECC9ECE9ECF9ED09ED49EDC9EDE9EDD9EE09EE59EE89EEF 9EF49EF69EF79EF99EFB9EFC9EFD9F079F0876B79F159F219F2C9F3E9F4A9F52 9F549F639F5F9F609F619F669F679F6C9F6A9F779F729F769F959F9C9FA00000 F4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000582F69C79059746451DC7199000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 R A1C1 301C FF5E A1C2 2016 2225 A1DD 2212 FF0D A1F1 00A2 FFE0 A1F2 00A3 FFE1 A2CC 00AC FFE2 tcl8.4.20/library/encoding/macTurkish.enc0000644003604700454610000000210711737050674016752 0ustar dgp771div# Encoding file: macTurkish, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 00C400C500C700C900D100D600DC00E100E000E200E400E300E500E700E900E8 00EA00EB00ED00EC00EE00EF00F100F300F200F400F600F500FA00F900FB00FC 202000B000A200A300A7202200B600DF00AE00A9212200B400A8226000C600D8 221E00B12264226500A500B522022211220F03C0222B00AA00BA03A900E600F8 00BF00A100AC221A01922248220600AB00BB202600A000C000C300D501520153 20132014201C201D2018201900F725CA00FF0178011E011F01300131015E015F 202100B7201A201E203000C200CA00C100CB00C800CD00CE00CF00CC00D300D4 F8FF00D200DA00DB00D9F8A002C602DC00AF02D802D902DA00B802DD02DB02C7 tcl8.4.20/library/encoding/iso8859-6.enc0000644003604700454610000000210611737050674016132 0ustar dgp771div# Encoding file: iso8859-6, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 0080008100820083008400850086008700880089008A008B008C008D008E008F 0090009100920093009400950096009700980099009A009B009C009D009E009F 00A000000000000000A40000000000000000000000000000060C00AD00000000 00000000000000000000000000000000000000000000061B000000000000061F 0000062106220623062406250626062706280629062A062B062C062D062E062F 0630063106320633063406350636063706380639063A00000000000000000000 0640064106420643064406450646064706480649064A064B064C064D064E064F 0650065106520000000000000000000000000000000000000000000000000000 tcl8.4.20/library/encoding/iso8859-9.enc0000644003604700454610000000210611737050674016135 0ustar dgp771div# Encoding file: iso8859-9, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 0080008100820083008400850086008700880089008A008B008C008D008E008F 0090009100920093009400950096009700980099009A009B009C009D009E009F 00A000A100A200A300A400A500A600A700A800A900AA00AB00AC00AD00AE00AF 00B000B100B200B300B400B500B600B700B800B900BA00BB00BC00BD00BE00BF 00C000C100C200C300C400C500C600C700C800C900CA00CB00CC00CD00CE00CF 011E00D100D200D300D400D500D600D700D800D900DA00DB00DC0130015E00DF 00E000E100E200E300E400E500E600E700E800E900EA00EB00EC00ED00EE00EF 011F00F100F200F300F400F500F600F700F800F900FA00FB00FC0131015F00FF tcl8.4.20/library/encoding/gb2312-raw.enc0000644003604700454610000024506411737050674016342 0ustar dgp771div# Encoding file: gb2312, double-byte D 233F 0 81 21 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000030003001300230FB02C902C700A8300330052015FF5E2225202620182019 201C201D3014301530083009300A300B300C300D300E300F3016301730103011 00B100D700F72236222722282211220F222A222922082237221A22A522252220 23122299222B222E2261224C2248223D221D2260226E226F22642265221E2235 22342642264000B0203220332103FF0400A4FFE0FFE1203000A7211626062605 25CB25CF25CE25C725C625A125A025B325B2203B219221902191219330130000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 22 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000024882489248A248B248C248D248E248F2490249124922493249424952496 249724982499249A249B247424752476247724782479247A247B247C247D247E 247F248024812482248324842485248624872460246124622463246424652466 2467246824690000000032203221322232233224322532263227322832290000 00002160216121622163216421652166216721682169216A216B000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 23 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FF01FF02FF03FFE5FF05FF06FF07FF08FF09FF0AFF0BFF0CFF0DFF0EFF0F FF10FF11FF12FF13FF14FF15FF16FF17FF18FF19FF1AFF1BFF1CFF1DFF1EFF1F FF20FF21FF22FF23FF24FF25FF26FF27FF28FF29FF2AFF2BFF2CFF2DFF2EFF2F FF30FF31FF32FF33FF34FF35FF36FF37FF38FF39FF3AFF3BFF3CFF3DFF3EFF3F FF40FF41FF42FF43FF44FF45FF46FF47FF48FF49FF4AFF4BFF4CFF4DFF4EFF4F FF50FF51FF52FF53FF54FF55FF56FF57FF58FF59FF5AFF5BFF5CFF5DFFE30000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 24 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000304130423043304430453046304730483049304A304B304C304D304E304F 3050305130523053305430553056305730583059305A305B305C305D305E305F 3060306130623063306430653066306730683069306A306B306C306D306E306F 3070307130723073307430753076307730783079307A307B307C307D307E307F 3080308130823083308430853086308730883089308A308B308C308D308E308F 3090309130923093000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 25 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000030A130A230A330A430A530A630A730A830A930AA30AB30AC30AD30AE30AF 30B030B130B230B330B430B530B630B730B830B930BA30BB30BC30BD30BE30BF 30C030C130C230C330C430C530C630C730C830C930CA30CB30CC30CD30CE30CF 30D030D130D230D330D430D530D630D730D830D930DA30DB30DC30DD30DE30DF 30E030E130E230E330E430E530E630E730E830E930EA30EB30EC30ED30EE30EF 30F030F130F230F330F430F530F6000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 26 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000039103920393039403950396039703980399039A039B039C039D039E039F 03A003A103A303A403A503A603A703A803A90000000000000000000000000000 000003B103B203B303B403B503B603B703B803B903BA03BB03BC03BD03BE03BF 03C003C103C303C403C503C603C703C803C90000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 27 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000004100411041204130414041504010416041704180419041A041B041C041D 041E041F0420042104220423042404250426042704280429042A042B042C042D 042E042F00000000000000000000000000000000000000000000000000000000 000004300431043204330434043504510436043704380439043A043B043C043D 043E043F0440044104420443044404450446044704480449044A044B044C044D 044E044F00000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 28 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000010100E101CE00E0011300E9011B00E8012B00ED01D000EC014D00F301D2 00F2016B00FA01D400F901D601D801DA01DC00FC00EA00000000000000000000 0000000000000000000031053106310731083109310A310B310C310D310E310F 3110311131123113311431153116311731183119311A311B311C311D311E311F 3120312131223123312431253126312731283129000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 29 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000002500250125022503250425052506250725082509250A250B 250C250D250E250F2510251125122513251425152516251725182519251A251B 251C251D251E251F2520252125222523252425252526252725282529252A252B 252C252D252E252F2530253125322533253425352536253725382539253A253B 253C253D253E253F2540254125422543254425452546254725482549254A254B 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 30 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000554A963F57C3632854CE550954C07691764C853C77EE827E788D72319698 978D6C285B894FFA630966975CB880FA684880AE660276CE51F9655671AC7FF1 888450B2596561CA6FB382AD634C625253ED54277B06516B75A45DF462D48DCB 9776628A8019575D97387F627238767D67CF767E64464F708D2562DC7A176591 73ED642C6273822C9881677F7248626E62CC4F3474E3534A529E7ECA90A65E2E 6886699C81807ED168D278C5868C9551508D8C2482DE80DE5305891252650000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 31 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000858496F94FDD582199715B9D62B162A566B48C799C8D7206676F789160B2 535153178F8880CC8D1D94A1500D72C8590760EB711988AB595482EF672C7B28 5D297EF7752D6CF58E668FF8903C9F3B6BD491197B145F7C78A784D6853D6BD5 6BD96BD65E015E8775F995ED655D5F0A5FC58F9F58C181C2907F965B97AD8FB9 7F168D2C62414FBF53D8535E8FA88FA98FAB904D68075F6A819888689CD6618B 522B762A5F6C658C6FD26EE85BBE6448517551B067C44E1979C9997C70B30000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 32 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000075C55E7673BB83E064AD62E894B56CE2535A52C3640F94C27B944F2F5E1B 82368116818A6E246CCA9A736355535C54FA886557E04E0D5E036B657C3F90E8 601664E6731C88C16750624D8D22776C8E2991C75F6983DC8521991053C28695 6B8B60ED60E8707F82CD82314ED36CA785CF64CD7CD969FD66F9834953957B56 4FA7518C6D4B5C428E6D63D253C9832C833667E578B4643D5BDF5C945DEE8BE7 62C667F48C7A640063BA8749998B8C177F2094F24EA7961098A4660C73160000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 33 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000573A5C1D5E38957F507F80A05382655E7545553150218D856284949E671D 56326F6E5DE2543570928F66626F64A463A35F7B6F8890F481E38FB05C186668 5FF16C8996488D81886C649179F057CE6A59621054484E587A0B60E96F848BDA 627F901E9A8B79E4540375F4630153196C608FDF5F1B9A70803B9F7F4F885C3A 8D647FC565A570BD514551B2866B5D075BA062BD916C75748E0C7A2061017B79 4EC77EF877854E1181ED521D51FA6A7153A88E87950496CF6EC19664695A0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 34 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000784050A877D7641089E6590463E35DDD7A7F693D4F20823955984E3275AE 7A975E625E8A95EF521B5439708A6376952457826625693F918755076DF37EAF 882262337EF075B5832878C196CC8F9E614874F78BCD6B64523A8D506B21806A 847156F153064ECE4E1B51D17C97918B7C074FC38E7F7BE17A9C64675D1450AC 810676017CB96DEC7FE067515B585BF878CB64AE641363AA632B9519642D8FBE 7B5476296253592754466B7950A362345E266B864EE38D37888B5F85902E0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 35 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006020803D62C54E39535590F863B880C665E66C2E4F4660EE6DE18BDE5F39 86CB5F536321515A83616863520063638E4850125C9B79775BFC52307A3B60BC 905376D75FB75F9776848E6C706F767B7B4977AA51F3909358244F4E6EF48FEA 654C7B1B72C46DA47FDF5AE162B55E95573084827B2C5E1D5F1F90127F1498A0 63826EC7789870B95178975B57AB75354F4375385E9760E659606DC06BBF7889 53FC96D551CB52016389540A94938C038DCC7239789F87768FED8C0D53E00000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 36 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00004E0176EF53EE948998769F0E952D5B9A8BA24E224E1C51AC846361C252A8 680B4F97606B51BB6D1E515C6296659796618C46901775D890FD77636BD2728A 72EC8BFB583577798D4C675C9540809A5EA66E2159927AEF77ED953B6BB565AD 7F0E58065151961F5BF958A954288E726566987F56E4949D76FE9041638754C6 591A593A579B8EB267358DFA8235524160F0581586FE5CE89E454FC4989D8BB9 5A2560765384627C904F9102997F6069800C513F80335C1499756D314E8C0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 37 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008D3053D17F5A7B4F4F104E4F96006CD573D085E95E06756A7FFB6A0A77FE 94927E4151E170E653CD8FD483038D2972AF996D6CDB574A82B365B980AA623F 963259A84EFF8BBF7EBA653E83F2975E556198DE80A5532A8BFD542080BA5E9F 6CB88D3982AC915A54296C1B52067EB7575F711A6C7E7C89594B4EFD5FFF6124 7CAA4E305C0167AB87025CF0950B98CE75AF70FD902251AF7F1D8BBD594951E4 4F5B5426592B657780A45B75627662C28F905E456C1F7B264F0F4FD8670D0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 38 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006D6E6DAA798F88B15F17752B629A8F854FEF91DC65A7812F81515E9C8150 8D74526F89868D4B590D50854ED8961C723681798D1F5BCC8BA3964459877F1A 54905676560E8BE565396982949976D66E895E727518674667D17AFF809D8D76 611F79C665628D635188521A94A27F38809B7EB25C976E2F67607BD9768B9AD8 818F7F947CD5641E95507A3F544A54E56B4C640162089E3D80F3759952729769 845B683C86E49601969494EC4E2A54047ED968398DDF801566F45E9A7FB90000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 39 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000057C2803F68975DE5653B529F606D9F9A4F9B8EAC516C5BAB5F135DE96C5E 62F18D21517194A952FE6C9F82DF72D757A267848D2D591F8F9C83C754957B8D 4F306CBD5B6459D19F1353E486CA9AA88C3780A16545987E56FA96C7522E74DC 52505BE1630289024E5662D0602A68FA51735B9851A089C27BA199867F5060EF 704C8D2F51495E7F901B747089C4572D78455F529F9F95FA8F689B3C8BE17678 684267DC8DEA8D35523D8F8A6EDA68CD950590ED56FD679C88F98FC754C80000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 3A 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009AB85B696D776C264EA55BB39A87916361A890AF97E9542B6DB55BD251FD 558A7F557FF064BC634D65F161BE608D710A6C576C49592F676D822A58D5568E 8C6A6BEB90DD597D801753F76D695475559D837783CF683879BE548C4F555408 76D28C8996026CB36DB88D6B89109E648D3A563F9ED175D55F8872E0606854FC 4EA86A2A886160528F7054C470D886799E3F6D2A5B8F5F187EA255894FAF7334 543C539A5019540E547C4E4E5FFD745A58F6846B80E1877472D07CCA6E560000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 3B 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005F27864E552C62A44E926CAA623782B154D7534E733E6ED1753B52125316 8BDD69D05F8A60006DEE574F6B2273AF68538FD87F13636260A3552475EA8C62 71156DA35BA65E7B8352614C9EC478FA87577C27768751F060F6714C66435E4C 604D8C0E707063258F895FBD606286D456DE6BC160946167534960E066668D3F 79FD4F1A70E96C478BB38BF27ED88364660F5A5A9B426D516DF78C416D3B4F19 706B83B7621660D1970D8D27797851FB573E57FA673A75787A3D79EF7B950000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 3C 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000808C99658FF96FC08BA59E2159EC7EE97F095409678168D88F917C4D96C6 53CA602575BE6C7253735AC97EA7632451E0810A5DF184DF628051805B634F0E 796D524260B86D4E5BC45BC28BA18BB065E25FCC964559937EE77EAA560967B7 59394F735BB652A0835A988A8D3E753294BE50477A3C4EF767B69A7E5AC16B7C 76D1575A5C167B3A95F4714E517C80A9827059787F04832768C067EC78B17877 62E363617B804FED526A51CF835069DB92748DF58D3189C1952E7BAD4EF60000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 3D 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000506582305251996F6E106E856DA75EFA50F559DC5C066D466C5F7586848B 686859568BB253209171964D854969127901712680F64EA490CA6D479A845A07 56BC640594F077EB4FA5811A72E189D2997A7F347EDE527F655991758F7F8F83 53EB7A9663ED63A5768679F888579636622A52AB8282685467706377776B7AED 6D017ED389E359D0621285C982A5754C501F4ECB75A58BEB5C4A5DFE7B4B65A4 91D14ECA6D25895F7D2795264EC58C288FDB9773664B79818FD170EC6D780000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 3E 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005C3D52B283465162830E775B66769CB84EAC60CA7CBE7CB37ECF4E958B66 666F988897595883656C955C5F8475C997567ADF7ADE51C070AF7A9863EA7A76 7EA0739697ED4E4570784E5D915253A9655165E781FC8205548E5C31759A97A0 62D872D975BD5C459A7983CA5C40548077E94E3E6CAE805A62D2636E5DE85177 8DDD8E1E952F4FF153E560E770AC526763509E435A1F5026773753777EE26485 652B628963985014723589C951B38BC07EDD574783CC94A7519B541B5CFB0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 3F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00004FCA7AE36D5A90E19A8F55805496536154AF5F0063E9697751EF6168520A 582A52D8574E780D770B5EB761777CE0625B62974EA27095800362F770E49760 577782DB67EF68F578D5989779D158F354B353EF6E34514B523B5BA28BFE80AF 554357A660735751542D7A7A60505B5463A762A053E362635BC767AF54ED7A9F 82E691775E9388E4593857AE630E8DE880EF57577B774FA95FEB5BBD6B3E5321 7B5072C2684677FF773665F751B54E8F76D45CBF7AA58475594E9B4150800000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 40 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000998861276E8357646606634656F062EC62695ED39614578362C955878721 814A8FA3556683B167658D5684DD5A6A680F62E67BEE961151706F9C8C3063FD 89C861D27F0670C26EE57405699472FC5ECA90CE67176D6A635E52B372628001 4F6C59E5916A70D96D9D52D24E5096F7956D857E78CA7D2F5121579264C2808B 7C7B6CEA68F1695E51B7539868A872819ECE7BF172F879BB6F137406674E91CC 9CA4793C83898354540F68174E3D538952B1783E5386522950884F8B4FD00000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 41 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000075E27ACB7C926CA596B6529B748354E94FE9805483B28FDE95705EC9601C 6D9F5E18655B813894FE604B70BC7EC37CAE51C968817CB1826F4E248F8691CF 667E4EAE8C0564A9804A50DA759771CE5BE58FBD6F664E86648295635ED66599 521788C270C852A3730E7433679778F797164E3490BB9CDE6DCB51DB8D41541D 62CE73B283F196F69F8494C34F367F9A51CC707596755CAD988653E64EE46E9C 740969B4786B998F7559521876246D4167F3516D9F99804B54997B3C7ABF0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 42 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009686578462E29647697C5A0464027BD36F0F964B82A6536298855E907089 63B35364864F9C819E93788C97328DEF8D429E7F6F5E79845F559646622E9A74 541594DD4FA365C55C655C617F1586516C2F5F8B73876EE47EFF5CE6631B5B6A 6EE653754E7163A0756562A18F6E4F264ED16CA67EB68BBA841D87BA7F57903B 95237BA99AA188F8843D6D1B9A867EDC59889EBB739B780186829A6C9A82561B 541757CB4E709EA653568FC881097792999286EE6EE1851366FC61626F2B0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 43 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008C298292832B76F26C135FD983BD732B8305951A6BDB77DB94C6536F8302 51925E3D8C8C8D384E4873AB679A68859176970971646CA177095A9295416BCF 7F8E66275BD059B95A9A95E895F74EEC840C84996AAC76DF9530731B68A65B5F 772F919A97617CDC8FF78C1C5F257C7379D889C56CCC871C5BC65E4268C97720 7EF55195514D52C95A297F05976282D763CF778485D079D26E3A5E9959998511 706D6C1162BF76BF654F60AF95FD660E879F9E2394ED540D547D8C2C64780000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 44 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000647986116A21819C78E864699B5462B9672B83AB58A89ED86CAB6F205BDE 964C8C0B725F67D062C772614EA959C66BCD589366AE5E5552DF6155672876EE 776672677A4662FF54EA545094A090A35A1C7EB36C164E435976801059485357 753796BE56CA63208111607C95F96DD65462998151855AE980FD59AE9713502A 6CE55C3C62DF4F60533F817B90066EBA852B62C85E7478BE64B5637B5FF55A18 917F9E1F5C3F634F80425B7D556E954A954D6D8560A867E072DE51DD5B810000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 45 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000062E76CDE725B626D94AE7EBD81136D53519C5F04597452AA601259736696 8650759F632A61E67CEF8BFA54E66B279E256BB485D5545550766CA4556A8DB4 722C5E156015743662CD6392724C5F986E436D3E65006F5876D878D076FC7554 522453DB4E535E9E65C1802A80D6629B5486522870AE888D8DD16CE1547880DA 57F988F48D54966A914D4F696C9B55B776C6783062A870F96F8E5F6D84EC68DA 787C7BF781A8670B9E4F636778B0576F78129739627962AB528874356BD70000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 46 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005564813E75B276AE533975DE50FB5C418B6C7BC7504F72479A9798D86F02 74E27968648777A562FC98918D2B54C180584E52576A82F9840D5E7351ED74F6 8BC45C4F57616CFC98875A4678349B448FEB7C955256625194FA4EC683868461 83E984B257D467345703666E6D668C3166DD7011671F6B3A6816621A59BB4E03 51C46F0667D26C8F517668CB59476B6775665D0E81109F5065D7794879419A91 8D775C824E5E4F01542F5951780C56686C148FC45F036C7D6CE38BAB63900000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 47 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000060706D3D72756266948E94C553438FC17B7E4EDF8C264E7E9ED494B194B3 524D6F5C90636D458C3458115D4C6B206B4967AA545B81547F8C589985375F3A 62A26A47953965726084686577A74E544FA85DE7979864AC7FD85CED4FCF7A8D 520783044E14602F7A8394A64FB54EB279E6743452E482B964D279BD5BDD6C81 97528F7B6C22503E537F6E0564CE66746C3060C598778BF75E86743C7A7779CB 4E1890B174036C4256DA914B6CC58D8B533A86C666F28EAF5C489A716E200000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 48 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000053D65A369F8B8DA353BB570898A76743919B6CC9516875CA62F372AC5238 529D7F3A7094763853749E4A69B7786E96C088D97FA4713671C3518967D374E4 58E4651856B78BA9997662707ED560F970ED58EC4EC14EBA5FCD97E74EFB8BA4 5203598A7EAB62544ECD65E5620E833884C98363878D71946EB65BB97ED25197 63C967D480898339881551125B7A59828FB14E736C5D516589258F6F962E854A 745E951095F06DA682E55F3164926D128428816E9CC3585E8D5B4E0953C10000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 49 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00004F1E6563685155D34E2764149A9A626B5AC2745F82726DA968EE50E7838E 7802674052396C997EB150BB5565715E7B5B665273CA82EB67495C715220717D 886B95EA965564C58D6181B355846C5562477F2E58924F2455468D4F664C4E0A 5C1A88F368A2634E7A0D70E7828D52FA97F65C1154E890B57ECD59628D4A86C7 820C820D8D6664445C0461516D89793E8BBE78377533547B4F388EAB6DF15A20 7EC5795E6C885BA15A76751A80BE614E6E1758F0751F7525727253477EF30000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 4A 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000770176DB526980DC57235E08593172EE65BD6E7F8BD75C388671534177F3 62FE65F64EC098DF86805B9E8BC653F277E24F7F5C4E9A7659CB5F0F793A58EB 4E1667FF4E8B62ED8A93901D52BF662F55DC566C90024ED54F8D91CA99706C0F 5E0260435BA489C68BD56536624B99965B885BFF6388552E53D77626517D852C 67A268B36B8A62928F9353D482126DD1758F4E668D4E5B70719F85AF669166D9 7F7287009ECD9F205C5E672F8FF06811675F620D7AD658855EB665706F310000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 4B 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000060555237800D6454887075295E05681362F4971C53CC723D8C016C347761 7A0E542E77AC987A821C8BF47855671470C165AF64955636601D79C153F84E1D 6B7B80865BFA55E356DB4F3A4F3C99725DF3677E80386002988290015B8B8BBC 8BF5641C825864DE55FD82CF91654FD77D20901F7C9F50F358516EAF5BBF8BC9 80839178849C7B97867D968B968F7EE59AD3788E5C817A57904296A7795F5B59 635F7B0B84D168AD55067F2974107D2295016240584C4ED65B83597958540000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 4C 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000736D631E8E4B8E0F80CE82D462AC53F06CF0915E592A60016C70574D644A 8D2A762B6EE9575B6A8075F06F6D8C2D8C0857666BEF889278B363A253F970AD 6C645858642A580268E0819B55107CD650188EBA6DCC8D9F70EB638F6D9B6ED4 7EE68404684390036DD896768BA85957727985E4817E75BC8A8A68AF52548E22 951163D098988E44557C4F5366FF568F60D56D9552435C4959296DFB586B7530 751C606C82148146631167618FE2773A8DF38D3494C15E165385542C70C30000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 4D 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006C405EF7505C4EAD5EAD633A8247901A6850916E77B3540C94DC5F647AE5 687663457B527EDF75DB507762955934900F51F879C37A8156FE5F9290146D82 5C60571F541051546E4D56E263A89893817F8715892A9000541E5C6F81C062D6 625881319E3596409A6E9A7C692D59A562D3553E631654C786D96D3C5A0374E6 889C6B6A59168C4C5F2F6E7E73A9987D4E3870F75B8C7897633D665A769660CB 5B9B5A494E0781556C6A738B4EA167897F515F8065FA671B5FD859845A010000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 4E 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005DCD5FAE537197E68FDD684556F4552F60DF4E3A6F4D7EF482C7840E59D4 4F1F4F2A5C3E7EAC672A851A5473754F80C355829B4F4F4D6E2D8C135C096170 536B761F6E29868A658795FB7EB9543B7A337D0A95EE55E17FC174EE631D8717 6DA17A9D621165A1536763E16C835DEB545C94A84E4C6C618BEC5C4B65E0829C 68A7543E54346BCB6B664E9463425348821E4F0D4FAE575E620A96FE66647269 52FF52A1609F8BEF661471996790897F785277FD6670563B54389521727A0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 4F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007A00606F5E0C6089819D591560DC718470EF6EAA6C5072806A8488AD5E2D 4E605AB3559C94E36D177CFB9699620F7EC6778E867E5323971E8F9666875CE1 4FA072ED4E0B53A6590F54136380952851484ED99C9C7EA454B88D2488548237 95F26D8E5F265ACC663E966973B0732E53BF817A99857FA15BAA967796507EBF 76F853A2957699997BB189446E584E617FD479658BE660F354CD4EAB98795DF7 6A6150CF54118C618427785D9704524A54EE56A395006D885BB56DC666530000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 50 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005C0F5B5D6821809655787B11654869544E9B6B47874E978B534F631F643A 90AA659C80C18C10519968B0537887F961C86CC46CFB8C225C5185AA82AF950C 6B238F9B65B05FFB5FC34FE18845661F8165732960FA51745211578B5F6290A2 884C91925E78674F602759D3514451F680F853086C7996C4718A4F114FEE7F9E 673D55C5950879C088967EE3589F620C9700865A5618987B5F908BB884C49157 53D965ED5E8F755C60647D6E5A7F7EEA7EED8F6955A75BA360AC65CB73840000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 51 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009009766377297EDA9774859B5B667A7496EA884052CB718F5FAA65EC8BE2 5BFB9A6F5DE16B896C5B8BAD8BAF900A8FC5538B62BC9E269E2D54404E2B82BD 7259869C5D1688596DAF96C554D14E9A8BB6710954BD960970DF6DF976D04E25 781487125CA95EF68A00989C960E708E6CBF594463A9773C884D6F1482735830 71D5538C781A96C155015F6671305BB48C1A9A8C6B83592E9E2F79E76768626C 4F6F75A17F8A6D0B96336C274EF075D2517B68376F3E90808170599674760000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 52 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000064475C2790657A918C2359DA54AC8200836F898180006930564E80367237 91CE51B64E5F987563964E1A53F666F3814B591C6DB24E0058F9533B63D694F1 4F9D4F0A886398905937905779FB4EEA80F075916C825B9C59E85F5D69058681 501A5DF24E5977E34EE5827A6291661390915C794EBF5F7981C69038808475AB 4EA688D4610F6BC55FC64E4976CA6EA28BE38BAE8C0A8BD15F027FFC7FCC7ECE 8335836B56E06BB797F3963459FB541F94F66DEB5BC5996E5C395F1596900000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 53 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000537082F16A315A749E705E947F2883B984248425836787478FCE8D6276C8 5F719896786C662054DF62E54F6381C375C85EB896CD8E0A86F9548F6CF36D8C 6C38607F52C775285E7D4F1860A05FE75C24753190AE94C072B96CB96E389149 670953CB53F34F5191C98BF153C85E7C8FC26DE44E8E76C26986865E611A8206 4F594FDE903E9C7C61096E1D6E1496854E885A3196E84E0E5C7F79B95B878BED 7FBD738957DF828B90C15401904755BB5CEA5FA161086B3272F180B28A890000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 54 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006D745BD388D598848C6B9A6D9E336E0A51A4514357A38881539F63F48F95 56ED54585706733F6E907F188FDC82D1613F6028966266F07EA68D8A8DC394A5 5CB37CA4670860A6960580184E9190E75300966851418FD08574915D665597F5 5B55531D78386742683D54C9707E5BB08F7D518D572854B1651266828D5E8D43 810F846C906D7CDF51FF85FB67A365E96FA186A48E81566A90207682707671E5 8D2362E952196CFD8D3C600E589E618E66FE8D60624E55B36E23672D8F670000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 55 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000094E195F87728680569A8548B4E4D70B88BC86458658B5B857A84503A5BE8 77BB6BE18A797C986CBE76CF65A98F975D2D5C5586386808536062187AD96E5B 7EFD6A1F7AE05F706F335F20638C6DA867564E085E108D264ED780C07634969C 62DB662D627E6CBC8D7571677F695146808753EC906E629854F286F08F998005 951785178FD96D5973CD659F771F7504782781FB8D1E94884FA6679575B98BCA 9707632F9547963584B8632377415F8172F04E896014657462EF6B63653F0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 56 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005E2775C790D18BC1829D679D652F5431871877E580A281026C414E4B7EC7 804C76F4690D6B966267503C4F84574063076B628DBE53EA65E87EB85FD7631A 63B781F381F47F6E5E1C5CD95236667A79E97A1A8D28709975D46EDE6CBB7A92 4E2D76C55FE0949F88777EC879CD80BF91CD4EF24F17821F54685DDE6D328BCC 7CA58F7480985E1A549276B15B99663C9AA473E0682A86DB6731732A8BF88BDB 90107AF970DB716E62C477A956314E3B845767F152A986C08D2E94F87B510000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 57 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00004F4F6CE8795D9A7B6293722A62FD4E1378168F6C64B08D5A7BC668695E84 88C55986649E58EE72B6690E95258FFD8D5857607F008C0651C6634962D95353 684C74228301914C55447740707C6D4A517954A88D4459FF6ECB6DC45B5C7D2B 4ED47C7D6ED35B5081EA6E0D5B579B0368D58E2A5B977EFC603B7EB590B98D70 594F63CD79DF8DB3535265CF79568BC5963B7EC494BB7E825634918967007F6A 5C0A907566285DE64F5067DE505A4F5C57505EA7000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 58 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00004E8D4E0C51404E105EFF53454E154E984E1E9B325B6C56694E2879BA4E3F 53154E47592D723B536E6C1056DF80E499976BD3777E9F174E364E9F9F104E5C 4E694E9382885B5B556C560F4EC4538D539D53A353A553AE97658D5D531A53F5 5326532E533E8D5C5366536352025208520E522D5233523F5240524C525E5261 525C84AF527D528252815290529351827F544EBB4EC34EC94EC24EE84EE14EEB 4EDE4F1B4EF34F224F644EF54F254F274F094F2B4F5E4F6765384F5A4F5D0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 59 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00004F5F4F574F324F3D4F764F744F914F894F834F8F4F7E4F7B4FAA4F7C4FAC 4F944FE64FE84FEA4FC54FDA4FE34FDC4FD14FDF4FF85029504C4FF3502C500F 502E502D4FFE501C500C50255028507E504350555048504E506C507B50A550A7 50A950BA50D6510650ED50EC50E650EE5107510B4EDD6C3D4F584F654FCE9FA0 6C467C74516E5DFD9EC999985181591452F9530D8A07531051EB591951554EA0 51564EB3886E88A44EB5811488D279805B3488037FB851AB51B151BD51BC0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5A 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000051C7519651A251A58BA08BA68BA78BAA8BB48BB58BB78BC28BC38BCB8BCF 8BCE8BD28BD38BD48BD68BD88BD98BDC8BDF8BE08BE48BE88BE98BEE8BF08BF3 8BF68BF98BFC8BFF8C008C028C048C078C0C8C0F8C118C128C148C158C168C19 8C1B8C188C1D8C1F8C208C218C258C278C2A8C2B8C2E8C2F8C328C338C358C36 5369537A961D962296219631962A963D963C964296499654965F9667966C9672 96749688968D969796B09097909B909D909990AC90A190B490B390B690BA0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5B 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000090B890B090CF90C590BE90D090C490C790D390E690E290DC90D790DB90EB 90EF90FE91049122911E91239131912F913991439146520D594252A252AC52AD 52BE54FF52D052D652F053DF71EE77CD5EF451F551FC9B2F53B65F01755A5DEF 574C57A957A1587E58BC58C558D15729572C572A57335739572E572F575C573B 574257695785576B5786577C577B5768576D5776577357AD57A4578C57B257CF 57A757B4579357A057D557D857DA57D957D257B857F457EF57F857E457DD0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5C 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000580B580D57FD57ED5800581E5819584458205865586C58815889589A5880 99A89F1961FF8279827D827F828F828A82A88284828E82918297829982AB82B8 82BE82B082C882CA82E3829882B782AE82CB82CC82C182A982B482A182AA829F 82C482CE82A482E1830982F782E4830F830782DC82F482D282D8830C82FB82D3 8311831A83068314831582E082D5831C8351835B835C83088392833C83348331 839B835E832F834F83478343835F834083178360832D833A8333836683650000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5D 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008368831B8369836C836A836D836E83B0837883B383B483A083AA8393839C 8385837C83B683A9837D83B8837B8398839E83A883BA83BC83C1840183E583D8 58078418840B83DD83FD83D6841C84388411840683D483DF840F840383F883F9 83EA83C583C0842683F083E1845C8451845A8459847384878488847A84898478 843C844684698476848C848E8431846D84C184CD84D084E684BD84D384CA84BF 84BA84E084A184B984B4849784E584E3850C750D853884F08539851F853A0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5E 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008556853B84FF84FC8559854885688564855E857A77A285438572857B85A4 85A88587858F857985AE859C858585B985B785B085D385C185DC85FF86278605 86298616863C5EFE5F08593C594180375955595A5958530F5C225C255C2C5C34 624C626A629F62BB62CA62DA62D762EE632262F66339634B634363AD63F66371 637A638E63B4636D63AC638A636963AE63BC63F263F863E063FF63C463DE63CE 645263C663BE64456441640B641B6420640C64266421645E6484646D64960000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000647A64B764B8649964BA64C064D064D764E464E265096525652E5F0B5FD2 75195F11535F53F153FD53E953E853FB541254165406544B5452545354545456 54435421545754595423543254825494547754715464549A549B548454765466 549D54D054AD54C254B454D254A754A654D354D4547254A354D554BB54BF54CC 54D954DA54DC54A954AA54A454DD54CF54DE551B54E7552054FD551454F35522 5523550F55115527552A5567558F55B55549556D55415555553F5550553C0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 60 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005537555655755576557755335530555C558B55D2558355B155B955885581 559F557E55D65591557B55DF55BD55BE5594559955EA55F755C9561F55D155EB 55EC55D455E655DD55C455EF55E555F255F355CC55CD55E855F555E48F94561E 5608560C56015624562355FE56005627562D565856395657562C564D56625659 565C564C5654568656645671566B567B567C5685569356AF56D456D756DD56E1 56F556EB56F956FF5704570A5709571C5E0F5E195E145E115E315E3B5E3C0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 61 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005E375E445E545E5B5E5E5E615C8C5C7A5C8D5C905C965C885C985C995C91 5C9A5C9C5CB55CA25CBD5CAC5CAB5CB15CA35CC15CB75CC45CD25CE45CCB5CE5 5D025D035D275D265D2E5D245D1E5D065D1B5D585D3E5D345D3D5D6C5D5B5D6F 5D5D5D6B5D4B5D4A5D695D745D825D995D9D8C735DB75DC55F735F775F825F87 5F895F8C5F955F995F9C5FA85FAD5FB55FBC88625F6172AD72B072B472B772B8 72C372C172CE72CD72D272E872EF72E972F272F472F7730172F3730372FA0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 62 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000072FB731773137321730A731E731D7315732273397325732C733873317350 734D73577360736C736F737E821B592598E7592459029963996799689969996A 996B996C99749977997D998099849987998A998D999099919993999499955E80 5E915E8B5E965EA55EA05EB95EB55EBE5EB38D535ED25ED15EDB5EE85EEA81BA 5FC45FC95FD65FCF60035FEE60045FE15FE45FFE600560065FEA5FED5FF86019 60356026601B600F600D6029602B600A603F602160786079607B607A60420000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 63 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000606A607D6096609A60AD609D60836092608C609B60EC60BB60B160DD60D8 60C660DA60B4612061266115612360F46100610E612B614A617561AC619461A7 61B761D461F55FDD96B395E995EB95F195F395F595F695FC95FE960396049606 9608960A960B960C960D960F96129615961696179619961A4E2C723F62156C35 6C546C5C6C4A6CA36C856C906C946C8C6C686C696C746C766C866CA96CD06CD4 6CAD6CF76CF86CF16CD76CB26CE06CD66CFA6CEB6CEE6CB16CD36CEF6CFE0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 64 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006D396D276D0C6D436D486D076D046D196D0E6D2B6D4D6D2E6D356D1A6D4F 6D526D546D336D916D6F6D9E6DA06D5E6D936D946D5C6D606D7C6D636E1A6DC7 6DC56DDE6E0E6DBF6DE06E116DE66DDD6DD96E166DAB6E0C6DAE6E2B6E6E6E4E 6E6B6EB26E5F6E866E536E546E326E256E446EDF6EB16E986EE06F2D6EE26EA5 6EA76EBD6EBB6EB76ED76EB46ECF6E8F6EC26E9F6F626F466F476F246F156EF9 6F2F6F366F4B6F746F2A6F096F296F896F8D6F8C6F786F726F7C6F7A6FD10000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 65 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006FC96FA76FB96FB66FC26FE16FEE6FDE6FE06FEF701A7023701B70397035 704F705E5B805B845B955B935BA55BB8752F9A9E64345BE45BEE89305BF08E47 8B078FB68FD38FD58FE58FEE8FE48FE98FE68FF38FE890059004900B90269011 900D9016902190359036902D902F9044905190529050906890589062905B66B9 9074907D908290889083908B5F505F575F565F585C3B54AB5C505C595B715C63 5C667FBC5F2A5F295F2D82745F3C9B3B5C6E59815983598D59A959AA59A30000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 66 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000599759CA59AB599E59A459D259B259AF59D759BE5A055A0659DD5A0859E3 59D859F95A0C5A095A325A345A115A235A135A405A675A4A5A555A3C5A625A75 80EC5AAA5A9B5A775A7A5ABE5AEB5AB25AD25AD45AB85AE05AE35AF15AD65AE6 5AD85ADC5B095B175B165B325B375B405C155C1C5B5A5B655B735B515B535B62 9A759A779A789A7A9A7F9A7D9A809A819A859A889A8A9A909A929A939A969A98 9A9B9A9C9A9D9A9F9AA09AA29AA39AA59AA77E9F7EA17EA37EA57EA87EA90000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 67 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007EAD7EB07EBE7EC07EC17EC27EC97ECB7ECC7ED07ED47ED77EDB7EE07EE1 7EE87EEB7EEE7EEF7EF17EF27F0D7EF67EFA7EFB7EFE7F017F027F037F077F08 7F0B7F0C7F0F7F117F127F177F197F1C7F1B7F1F7F217F227F237F247F257F26 7F277F2A7F2B7F2C7F2D7F2F7F307F317F327F337F355E7A757F5DDB753E9095 738E739173AE73A2739F73CF73C273D173B773B373C073C973C873E573D9987C 740A73E973E773DE73BA73F2740F742A745B7426742574287430742E742C0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 68 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000741B741A7441745C7457745574597477746D747E749C748E748074817487 748B749E74A874A9749074A774D274BA97EA97EB97EC674C6753675E67486769 67A56787676A6773679867A7677567A8679E67AD678B6777677C67F0680967D8 680A67E967B0680C67D967B567DA67B367DD680067C367B867E2680E67C167FD 6832683368606861684E6862684468646883681D68556866684168676840683E 684A6849682968B5688F687468776893686B68C2696E68FC691F692068F90000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 69 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000692468F0690B6901695768E369106971693969606942695D6984696B6980 69986978693469CC6987698869CE6989696669636979699B69A769BB69AB69AD 69D469B169C169CA69DF699569E0698D69FF6A2F69ED6A176A186A6569F26A44 6A3E6AA06A506A5B6A356A8E6A796A3D6A286A586A7C6A916A906AA96A976AAB 733773526B816B826B876B846B926B936B8D6B9A6B9B6BA16BAA8F6B8F6D8F71 8F728F738F758F768F788F778F798F7A8F7C8F7E8F818F828F848F878F8B0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6A 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008F8D8F8E8F8F8F988F9A8ECE620B6217621B621F6222622162256224622C 81E774EF74F474FF750F75117513653465EE65EF65F0660A6619677266036615 6600708566F7661D66346631663666358006665F66546641664F665666616657 66776684668C66A7669D66BE66DB66DC66E666E98D328D338D368D3B8D3D8D40 8D458D468D488D498D478D4D8D558D5989C789CA89CB89CC89CE89CF89D089D1 726E729F725D7266726F727E727F7284728B728D728F72926308633263B00000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6B 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000643F64D880046BEA6BF36BFD6BF56BF96C056C076C066C0D6C156C186C19 6C1A6C216C296C246C2A6C3265356555656B724D72527256723086625216809F 809C809380BC670A80BD80B180AB80AD80B480B780E780E880E980EA80DB80C2 80C480D980CD80D7671080DD80EB80F180F480ED810D810E80F280FC67158112 8C5A8136811E812C811881328148814C815381748159815A817181608169817C 817D816D8167584D5AB58188818281916ED581A381AA81CC672681CA81BB0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6C 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000081C181A66B246B376B396B436B466B5998D198D298D398D598D998DA6BB3 5F406BC289F365909F51659365BC65C665C465C365CC65CE65D265D67080709C 7096709D70BB70C070B770AB70B170E870CA711071137116712F71317173715C 716871457172714A7178717A719871B371B571A871A071E071D471E771F9721D 7228706C7118716671B9623E623D624362486249793B794079467949795B795C 7953795A796279577960796F7967797A7985798A799A79A779B35FD15FD00000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6D 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000603C605D605A606760416059606360AB6106610D615D61A9619D61CB61D1 62068080807F6C936CF66DFC77F677F87800780978177818781165AB782D781C 781D7839783A783B781F783C7825782C78237829784E786D7856785778267850 7847784C786A789B7893789A7887789C78A178A378B278B978A578D478D978C9 78EC78F2790578F479137924791E79349F9B9EF99EFB9EFC76F17704770D76F9 77077708771A77227719772D7726773577387750775177477743775A77680000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6E 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000077627765777F778D777D7780778C7791779F77A077B077B577BD753A7540 754E754B7548755B7572757975837F587F617F5F8A487F687F747F717F797F81 7F7E76CD76E58832948594869487948B948A948C948D948F9490949494979495 949A949B949C94A394A494AB94AA94AD94AC94AF94B094B294B494B694B794B8 94B994BA94BC94BD94BF94C494C894C994CA94CB94CC94CD94CE94D094D194D2 94D594D694D794D994D894DB94DE94DF94E094E294E494E594E794E894EA0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000094E994EB94EE94EF94F394F494F594F794F994FC94FD94FF950395029506 95079509950A950D950E950F951295139514951595169518951B951D951E951F 9522952A952B9529952C953195329534953695379538953C953E953F95429535 9544954595469549954C954E954F9552955395549556955795589559955B955E 955F955D95619562956495659566956795689569956A956B956C956F95719572 9573953A77E777EC96C979D579ED79E379EB7A065D477A037A027A1E7A140000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 70 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007A397A377A519ECF99A57A707688768E7693769976A474DE74E0752C9E20 9E229E289E299E2A9E2B9E2C9E329E319E369E389E379E399E3A9E3E9E419E42 9E449E469E479E489E499E4B9E4C9E4E9E519E559E579E5A9E5B9E5C9E5E9E63 9E669E679E689E699E6A9E6B9E6C9E719E6D9E7375927594759675A0759D75AC 75A375B375B475B875C475B175B075C375C275D675CD75E375E875E675E475EB 75E7760375F175FC75FF761076007605760C7617760A76257618761576190000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 71 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000761B763C762276207640762D7630763F76357643763E7633764D765E7654 765C7656766B766F7FCA7AE67A787A797A807A867A887A957AA67AA07AAC7AA8 7AAD7AB3886488698872887D887F888288A288C688B788BC88C988E288CE88E3 88E588F1891A88FC88E888FE88F0892189198913891B890A8934892B89368941 8966897B758B80E576B276B477DC801280148016801C80208022802580268027 802980288031800B803580438046804D80528069807189839878988098830000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 72 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009889988C988D988F9894989A989B989E989F98A198A298A598A6864D8654 866C866E867F867A867C867B86A8868D868B86AC869D86A786A386AA869386A9 86B686C486B586CE86B086BA86B186AF86C986CF86B486E986F186F286ED86F3 86D0871386DE86F486DF86D886D18703870786F88708870A870D87098723873B 871E8725872E871A873E87488734873187298737873F87828722877D877E877B 87608770874C876E878B87538763877C876487598765879387AF87A887D20000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 73 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000087C68788878587AD8797878387AB87E587AC87B587B387CB87D387BD87D1 87C087CA87DB87EA87E087EE8816881387FE880A881B88218839883C7F367F42 7F447F4582107AFA7AFD7B087B037B047B157B0A7B2B7B0F7B477B387B2A7B19 7B2E7B317B207B257B247B337B3E7B1E7B587B5A7B457B757B4C7B5D7B607B6E 7B7B7B627B727B717B907BA67BA77BB87BAC7B9D7BA87B857BAA7B9C7BA27BAB 7BB47BD17BC17BCC7BDD7BDA7BE57BE67BEA7C0C7BFE7BFC7C0F7C167C0B0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 74 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007C1F7C2A7C267C387C417C4081FE82018202820481EC8844822182228223 822D822F8228822B8238823B82338234823E82448249824B824F825A825F8268 887E8885888888D888DF895E7F9D7F9F7FA77FAF7FB07FB27C7C65497C917C9D 7C9C7C9E7CA27CB27CBC7CBD7CC17CC77CCC7CCD7CC87CC57CD77CE8826E66A8 7FBF7FCE7FD57FE57FE17FE67FE97FEE7FF37CF87D777DA67DAE7E477E9B9EB8 9EB48D738D848D948D918DB18D678D6D8C478C49914A9150914E914F91640000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 75 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009162916191709169916F917D917E917291749179918C91859190918D9191 91A291A391AA91AD91AE91AF91B591B491BA8C559E7E8DB88DEB8E058E598E69 8DB58DBF8DBC8DBA8DC48DD68DD78DDA8DDE8DCE8DCF8DDB8DC68DEC8DF78DF8 8DE38DF98DFB8DE48E098DFD8E148E1D8E1F8E2C8E2E8E238E2F8E3A8E408E39 8E358E3D8E318E498E418E428E518E528E4A8E708E768E7C8E6F8E748E858E8F 8E948E908E9C8E9E8C788C828C8A8C858C988C94659B89D689DE89DA89DC0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 76 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000089E589EB89EF8A3E8B26975396E996F396EF970697019708970F970E972A 972D9730973E9F809F839F859F869F879F889F899F8A9F8C9EFE9F0B9F0D96B9 96BC96BD96CE96D277BF96E0928E92AE92C8933E936A93CA938F943E946B9C7F 9C829C859C869C879C887A239C8B9C8E9C909C919C929C949C959C9A9C9B9C9E 9C9F9CA09CA19CA29CA39CA59CA69CA79CA89CA99CAB9CAD9CAE9CB09CB19CB2 9CB39CB49CB59CB69CB79CBA9CBB9CBC9CBD9CC49CC59CC69CC79CCA9CCB0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 77 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009CCC9CCD9CCE9CCF9CD09CD39CD49CD59CD79CD89CD99CDC9CDD9CDF9CE2 977C978597919792979497AF97AB97A397B297B49AB19AB09AB79E589AB69ABA 9ABC9AC19AC09AC59AC29ACB9ACC9AD19B459B439B479B499B489B4D9B5198E8 990D992E995599549ADF9AE19AE69AEF9AEB9AFB9AED9AF99B089B0F9B139B1F 9B239EBD9EBE7E3B9E829E879E889E8B9E9293D69E9D9E9F9EDB9EDC9EDD9EE0 9EDF9EE29EE99EE79EE59EEA9EEF9F229F2C9F2F9F399F379F3D9F3E9F440000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 tcl8.4.20/library/encoding/cp857.enc0000644003604700454610000000210211737050674015501 0ustar dgp771div# Encoding file: cp857, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 00C700FC00E900E200E400E000E500E700EA00EB00E800EF00EE013100C400C5 00C900E600C600F400F600F200FB00F9013000D600DC00F800A300D8015E015F 00E100ED00F300FA00F100D1011E011F00BF00AE00AC00BD00BC00A100AB00BB 2591259225932502252400C100C200C000A9256325512557255D00A200A52510 25142534252C251C2500253C00E300C3255A25542569256625602550256C00A4 00BA00AA00CA00CB00C8000000CD00CE00CF2518250C2588258400A600CC2580 00D300DF00D400D200F500D500B5000000D700DA00DB00D900EC00FF00AF00B4 00AD00B1000000BE00B600A700F700B800B000A800B700B900B300B225A000A0 tcl8.4.20/library/encoding/ksc5601.enc0000644003604700454610000026531511737050674015750 0ustar dgp771div# Encoding file: ksc5601, double-byte D 233F 0 89 21 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000030003001300200B72025202600A8300300AD20152225FF3C223C20182019 201C201D3014301530083009300A300B300C300D300E300F3010301100B100D7 00F7226022642265221E223400B0203220332103212BFFE0FFE1FFE526422640 222022A52312220222072261225200A7203B2606260525CB25CF25CE25C725C6 25A125A025B325B225BD25BC219221902191219321943013226A226B221A223D 221D2235222B222C2208220B2286228722822283222A222922272228FFE20000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 22 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000021D221D42200220300B4FF5E02C702D802DD02DA02D900B802DB00A100BF 02D0222E2211220F00A42109203025C125C025B725B626642660266126652667 2663229925C825A325D025D1259225A425A525A825A725A625A92668260F260E 261C261E00B62020202121952197219921962198266D2669266A266C327F321C 211633C7212233C233D821210000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 23 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FF01FF02FF03FF04FF05FF06FF07FF08FF09FF0AFF0BFF0CFF0DFF0EFF0F FF10FF11FF12FF13FF14FF15FF16FF17FF18FF19FF1AFF1BFF1CFF1DFF1EFF1F FF20FF21FF22FF23FF24FF25FF26FF27FF28FF29FF2AFF2BFF2CFF2DFF2EFF2F FF30FF31FF32FF33FF34FF35FF36FF37FF38FF39FF3AFF3BFFE6FF3DFF3EFF3F FF40FF41FF42FF43FF44FF45FF46FF47FF48FF49FF4AFF4BFF4CFF4DFF4EFF4F FF50FF51FF52FF53FF54FF55FF56FF57FF58FF59FF5AFF5BFF5CFF5DFFE30000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 24 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000313131323133313431353136313731383139313A313B313C313D313E313F 3140314131423143314431453146314731483149314A314B314C314D314E314F 3150315131523153315431553156315731583159315A315B315C315D315E315F 3160316131623163316431653166316731683169316A316B316C316D316E316F 3170317131723173317431753176317731783179317A317B317C317D317E317F 3180318131823183318431853186318731883189318A318B318C318D318E0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 25 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000217021712172217321742175217621772178217900000000000000000000 2160216121622163216421652166216721682169000000000000000000000000 0000039103920393039403950396039703980399039A039B039C039D039E039F 03A003A103A303A403A503A603A703A803A90000000000000000000000000000 000003B103B203B303B403B503B603B703B803B903BA03BB03BC03BD03BE03BF 03C003C103C303C403C503C603C703C803C90000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 26 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000025002502250C251025182514251C252C25242534253C25012503250F2513 251B251725232533252B253B254B2520252F25282537253F251D253025252538 254225122511251A251925162515250E250D251E251F25212522252625272529 252A252D252E25312532253525362539253A253D253E25402541254325442545 2546254725482549254A00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 27 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00003395339633972113339833C433A333A433A533A63399339A339B339C339D 339E339F33A033A133A233CA338D338E338F33CF3388338933C833A733A833B0 33B133B233B333B433B533B633B733B833B93380338133823383338433BA33BB 33BC33BD33BE33BF33903391339233933394212633C033C1338A338B338C33D6 33C533AD33AE33AF33DB33A933AA33AB33AC33DD33D033D333C333C933DC33C6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 28 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000C600D000AA0126000001320000013F014100D8015200BA00DE0166014A 00003260326132623263326432653266326732683269326A326B326C326D326E 326F3270327132723273327432753276327732783279327A327B24D024D124D2 24D324D424D524D624D724D824D924DA24DB24DC24DD24DE24DF24E024E124E2 24E324E424E524E624E724E824E9246024612462246324642465246624672468 2469246A246B246C246D246E00BD2153215400BC00BE215B215C215D215E0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 29 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000E6011100F001270131013301380140014200F8015300DF00FE0167014B 01493200320132023203320432053206320732083209320A320B320C320D320E 320F3210321132123213321432153216321732183219321A321B249C249D249E 249F24A024A124A224A324A424A524A624A724A824A924AA24AB24AC24AD24AE 24AF24B024B124B224B324B424B5247424752476247724782479247A247B247C 247D247E247F24802481248200B900B200B32074207F20812082208320840000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 2A 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000304130423043304430453046304730483049304A304B304C304D304E304F 3050305130523053305430553056305730583059305A305B305C305D305E305F 3060306130623063306430653066306730683069306A306B306C306D306E306F 3070307130723073307430753076307730783079307A307B307C307D307E307F 3080308130823083308430853086308730883089308A308B308C308D308E308F 3090309130923093000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 2B 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000030A130A230A330A430A530A630A730A830A930AA30AB30AC30AD30AE30AF 30B030B130B230B330B430B530B630B730B830B930BA30BB30BC30BD30BE30BF 30C030C130C230C330C430C530C630C730C830C930CA30CB30CC30CD30CE30CF 30D030D130D230D330D430D530D630D730D830D930DA30DB30DC30DD30DE30DF 30E030E130E230E330E430E530E630E730E830E930EA30EB30EC30ED30EE30EF 30F030F130F230F330F430F530F6000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 2C 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000004100411041204130414041504010416041704180419041A041B041C041D 041E041F0420042104220423042404250426042704280429042A042B042C042D 042E042F00000000000000000000000000000000000000000000000000000000 000004300431043204330434043504510436043704380439043A043B043C043D 043E043F0440044104420443044404450446044704480449044A044B044C044D 044E044F00000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 30 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000AC00AC01AC04AC07AC08AC09AC0AAC10AC11AC12AC13AC14AC15AC16AC17 AC19AC1AAC1BAC1CAC1DAC20AC24AC2CAC2DAC2FAC30AC31AC38AC39AC3CAC40 AC4BAC4DAC54AC58AC5CAC70AC71AC74AC77AC78AC7AAC80AC81AC83AC84AC85 AC86AC89AC8AAC8BAC8CAC90AC94AC9CAC9DAC9FACA0ACA1ACA8ACA9ACAAACAC ACAFACB0ACB8ACB9ACBBACBCACBDACC1ACC4ACC8ACCCACD5ACD7ACE0ACE1ACE4 ACE7ACE8ACEAACECACEFACF0ACF1ACF3ACF5ACF6ACFCACFDAD00AD04AD060000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 31 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000AD0CAD0DAD0FAD11AD18AD1CAD20AD29AD2CAD2DAD34AD35AD38AD3CAD44 AD45AD47AD49AD50AD54AD58AD61AD63AD6CAD6DAD70AD73AD74AD75AD76AD7B AD7CAD7DAD7FAD81AD82AD88AD89AD8CAD90AD9CAD9DADA4ADB7ADC0ADC1ADC4 ADC8ADD0ADD1ADD3ADDCADE0ADE4ADF8ADF9ADFCADFFAE00AE01AE08AE09AE0B AE0DAE14AE30AE31AE34AE37AE38AE3AAE40AE41AE43AE45AE46AE4AAE4CAE4D AE4EAE50AE54AE56AE5CAE5DAE5FAE60AE61AE65AE68AE69AE6CAE70AE780000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 32 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000AE79AE7BAE7CAE7DAE84AE85AE8CAEBCAEBDAEBEAEC0AEC4AECCAECDAECF AED0AED1AED8AED9AEDCAEE8AEEBAEEDAEF4AEF8AEFCAF07AF08AF0DAF10AF2C AF2DAF30AF32AF34AF3CAF3DAF3FAF41AF42AF43AF48AF49AF50AF5CAF5DAF64 AF65AF79AF80AF84AF88AF90AF91AF95AF9CAFB8AFB9AFBCAFC0AFC7AFC8AFC9 AFCBAFCDAFCEAFD4AFDCAFE8AFE9AFF0AFF1AFF4AFF8B000B001B004B00CB010 B014B01CB01DB028B044B045B048B04AB04CB04EB053B054B055B057B0590000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 33 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000B05DB07CB07DB080B084B08CB08DB08FB091B098B099B09AB09CB09FB0A0 B0A1B0A2B0A8B0A9B0ABB0ACB0ADB0AEB0AFB0B1B0B3B0B4B0B5B0B8B0BCB0C4 B0C5B0C7B0C8B0C9B0D0B0D1B0D4B0D8B0E0B0E5B108B109B10BB10CB110B112 B113B118B119B11BB11CB11DB123B124B125B128B12CB134B135B137B138B139 B140B141B144B148B150B151B154B155B158B15CB160B178B179B17CB180B182 B188B189B18BB18DB192B193B194B198B19CB1A8B1CCB1D0B1D4B1DCB1DD0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 34 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000B1DFB1E8B1E9B1ECB1F0B1F9B1FBB1FDB204B205B208B20BB20CB214B215 B217B219B220B234B23CB258B25CB260B268B269B274B275B27CB284B285B289 B290B291B294B298B299B29AB2A0B2A1B2A3B2A5B2A6B2AAB2ACB2B0B2B4B2C8 B2C9B2CCB2D0B2D2B2D8B2D9B2DBB2DDB2E2B2E4B2E5B2E6B2E8B2EBB2ECB2ED B2EEB2EFB2F3B2F4B2F5B2F7B2F8B2F9B2FAB2FBB2FFB300B301B304B308B310 B311B313B314B315B31CB354B355B356B358B35BB35CB35EB35FB364B3650000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 35 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000B367B369B36BB36EB370B371B374B378B380B381B383B384B385B38CB390 B394B3A0B3A1B3A8B3ACB3C4B3C5B3C8B3CBB3CCB3CEB3D0B3D4B3D5B3D7B3D9 B3DBB3DDB3E0B3E4B3E8B3FCB410B418B41CB420B428B429B42BB434B450B451 B454B458B460B461B463B465B46CB480B488B49DB4A4B4A8B4ACB4B5B4B7B4B9 B4C0B4C4B4C8B4D0B4D5B4DCB4DDB4E0B4E3B4E4B4E6B4ECB4EDB4EFB4F1B4F8 B514B515B518B51BB51CB524B525B527B528B529B52AB530B531B534B5380000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 36 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000B540B541B543B544B545B54BB54CB54DB550B554B55CB55DB55FB560B561 B5A0B5A1B5A4B5A8B5AAB5ABB5B0B5B1B5B3B5B4B5B5B5BBB5BCB5BDB5C0B5C4 B5CCB5CDB5CFB5D0B5D1B5D8B5ECB610B611B614B618B625B62CB634B648B664 B668B69CB69DB6A0B6A4B6ABB6ACB6B1B6D4B6F0B6F4B6F8B700B701B705B728 B729B72CB72FB730B738B739B73BB744B748B74CB754B755B760B764B768B770 B771B773B775B77CB77DB780B784B78CB78DB78FB790B791B792B796B7970000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 37 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000B798B799B79CB7A0B7A8B7A9B7ABB7ACB7ADB7B4B7B5B7B8B7C7B7C9B7EC B7EDB7F0B7F4B7FCB7FDB7FFB800B801B807B808B809B80CB810B818B819B81B B81DB824B825B828B82CB834B835B837B838B839B840B844B851B853B85CB85D B860B864B86CB86DB86FB871B878B87CB88DB8A8B8B0B8B4B8B8B8C0B8C1B8C3 B8C5B8CCB8D0B8D4B8DDB8DFB8E1B8E8B8E9B8ECB8F0B8F8B8F9B8FBB8FDB904 B918B920B93CB93DB940B944B94CB94FB951B958B959B95CB960B968B9690000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 38 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000B96BB96DB974B975B978B97CB984B985B987B989B98AB98DB98EB9ACB9AD B9B0B9B4B9BCB9BDB9BFB9C1B9C8B9C9B9CCB9CEB9CFB9D0B9D1B9D2B9D8B9D9 B9DBB9DDB9DEB9E1B9E3B9E4B9E5B9E8B9ECB9F4B9F5B9F7B9F8B9F9B9FABA00 BA01BA08BA15BA38BA39BA3CBA40BA42BA48BA49BA4BBA4DBA4EBA53BA54BA55 BA58BA5CBA64BA65BA67BA68BA69BA70BA71BA74BA78BA83BA84BA85BA87BA8C BAA8BAA9BAABBAACBAB0BAB2BAB8BAB9BABBBABDBAC4BAC8BAD8BAD9BAFC0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 39 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000BB00BB04BB0DBB0FBB11BB18BB1CBB20BB29BB2BBB34BB35BB36BB38BB3B BB3CBB3DBB3EBB44BB45BB47BB49BB4DBB4FBB50BB54BB58BB61BB63BB6CBB88 BB8CBB90BBA4BBA8BBACBBB4BBB7BBC0BBC4BBC8BBD0BBD3BBF8BBF9BBFCBBFF BC00BC02BC08BC09BC0BBC0CBC0DBC0FBC11BC14BC15BC16BC17BC18BC1BBC1C BC1DBC1EBC1FBC24BC25BC27BC29BC2DBC30BC31BC34BC38BC40BC41BC43BC44 BC45BC49BC4CBC4DBC50BC5DBC84BC85BC88BC8BBC8CBC8EBC94BC95BC970000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 3A 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000BC99BC9ABCA0BCA1BCA4BCA7BCA8BCB0BCB1BCB3BCB4BCB5BCBCBCBDBCC0 BCC4BCCDBCCFBCD0BCD1BCD5BCD8BCDCBCF4BCF5BCF6BCF8BCFCBD04BD05BD07 BD09BD10BD14BD24BD2CBD40BD48BD49BD4CBD50BD58BD59BD64BD68BD80BD81 BD84BD87BD88BD89BD8ABD90BD91BD93BD95BD99BD9ABD9CBDA4BDB0BDB8BDD4 BDD5BDD8BDDCBDE9BDF0BDF4BDF8BE00BE03BE05BE0CBE0DBE10BE14BE1CBE1D BE1FBE44BE45BE48BE4CBE4EBE54BE55BE57BE59BE5ABE5BBE60BE61BE640000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 3B 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000BE68BE6ABE70BE71BE73BE74BE75BE7BBE7CBE7DBE80BE84BE8CBE8DBE8F BE90BE91BE98BE99BEA8BED0BED1BED4BED7BED8BEE0BEE3BEE4BEE5BEECBF01 BF08BF09BF18BF19BF1BBF1CBF1DBF40BF41BF44BF48BF50BF51BF55BF94BFB0 BFC5BFCCBFCDBFD0BFD4BFDCBFDFBFE1C03CC051C058C05CC060C068C069C090 C091C094C098C0A0C0A1C0A3C0A5C0ACC0ADC0AFC0B0C0B3C0B4C0B5C0B6C0BC C0BDC0BFC0C0C0C1C0C5C0C8C0C9C0CCC0D0C0D8C0D9C0DBC0DCC0DDC0E40000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 3C 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000C0E5C0E8C0ECC0F4C0F5C0F7C0F9C100C104C108C110C115C11CC11DC11E C11FC120C123C124C126C127C12CC12DC12FC130C131C136C138C139C13CC140 C148C149C14BC14CC14DC154C155C158C15CC164C165C167C168C169C170C174 C178C185C18CC18DC18EC190C194C196C19CC19DC19FC1A1C1A5C1A8C1A9C1AC C1B0C1BDC1C4C1C8C1CCC1D4C1D7C1D8C1E0C1E4C1E8C1F0C1F1C1F3C1FCC1FD C200C204C20CC20DC20FC211C218C219C21CC21FC220C228C229C22BC22D0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 3D 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000C22FC231C232C234C248C250C251C254C258C260C265C26CC26DC270C274 C27CC27DC27FC281C288C289C290C298C29BC29DC2A4C2A5C2A8C2ACC2ADC2B4 C2B5C2B7C2B9C2DCC2DDC2E0C2E3C2E4C2EBC2ECC2EDC2EFC2F1C2F6C2F8C2F9 C2FBC2FCC300C308C309C30CC30DC313C314C315C318C31CC324C325C328C329 C345C368C369C36CC370C372C378C379C37CC37DC384C388C38CC3C0C3D8C3D9 C3DCC3DFC3E0C3E2C3E8C3E9C3EDC3F4C3F5C3F8C408C410C424C42CC4300000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 3E 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000C434C43CC43DC448C464C465C468C46CC474C475C479C480C494C49CC4B8 C4BCC4E9C4F0C4F1C4F4C4F8C4FAC4FFC500C501C50CC510C514C51CC528C529 C52CC530C538C539C53BC53DC544C545C548C549C54AC54CC54DC54EC553C554 C555C557C558C559C55DC55EC560C561C564C568C570C571C573C574C575C57C C57DC580C584C587C58CC58DC58FC591C595C597C598C59CC5A0C5A9C5B4C5B5 C5B8C5B9C5BBC5BCC5BDC5BEC5C4C5C5C5C6C5C7C5C8C5C9C5CAC5CCC5CE0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 3F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000C5D0C5D1C5D4C5D8C5E0C5E1C5E3C5E5C5ECC5EDC5EEC5F0C5F4C5F6C5F7 C5FCC5FDC5FEC5FFC600C601C605C606C607C608C60CC610C618C619C61BC61C C624C625C628C62CC62DC62EC630C633C634C635C637C639C63BC640C641C644 C648C650C651C653C654C655C65CC65DC660C66CC66FC671C678C679C67CC680 C688C689C68BC68DC694C695C698C69CC6A4C6A5C6A7C6A9C6B0C6B1C6B4C6B8 C6B9C6BAC6C0C6C1C6C3C6C5C6CCC6CDC6D0C6D4C6DCC6DDC6E0C6E1C6E80000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 40 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000C6E9C6ECC6F0C6F8C6F9C6FDC704C705C708C70CC714C715C717C719C720 C721C724C728C730C731C733C735C737C73CC73DC740C744C74AC74CC74DC74F C751C752C753C754C755C756C757C758C75CC760C768C76BC774C775C778C77C C77DC77EC783C784C785C787C788C789C78AC78EC790C791C794C796C797C798 C79AC7A0C7A1C7A3C7A4C7A5C7A6C7ACC7ADC7B0C7B4C7BCC7BDC7BFC7C0C7C1 C7C8C7C9C7CCC7CEC7D0C7D8C7DDC7E4C7E8C7ECC800C801C804C808C80A0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 41 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000C810C811C813C815C816C81CC81DC820C824C82CC82DC82FC831C838C83C C840C848C849C84CC84DC854C870C871C874C878C87AC880C881C883C885C886 C887C88BC88CC88DC894C89DC89FC8A1C8A8C8BCC8BDC8C4C8C8C8CCC8D4C8D5 C8D7C8D9C8E0C8E1C8E4C8F5C8FCC8FDC900C904C905C906C90CC90DC90FC911 C918C92CC934C950C951C954C958C960C961C963C96CC970C974C97CC988C989 C98CC990C998C999C99BC99DC9C0C9C1C9C4C9C7C9C8C9CAC9D0C9D1C9D30000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 42 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000C9D5C9D6C9D9C9DAC9DCC9DDC9E0C9E2C9E4C9E7C9ECC9EDC9EFC9F0C9F1 C9F8C9F9C9FCCA00CA08CA09CA0BCA0CCA0DCA14CA18CA29CA4CCA4DCA50CA54 CA5CCA5DCA5FCA60CA61CA68CA7DCA84CA98CABCCABDCAC0CAC4CACCCACDCACF CAD1CAD3CAD8CAD9CAE0CAECCAF4CB08CB10CB14CB18CB20CB21CB41CB48CB49 CB4CCB50CB58CB59CB5DCB64CB78CB79CB9CCBB8CBD4CBE4CBE7CBE9CC0CCC0D CC10CC14CC1CCC1DCC21CC22CC27CC28CC29CC2CCC2ECC30CC38CC39CC3B0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 43 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000CC3CCC3DCC3ECC44CC45CC48CC4CCC54CC55CC57CC58CC59CC60CC64CC66 CC68CC70CC75CC98CC99CC9CCCA0CCA8CCA9CCABCCACCCADCCB4CCB5CCB8CCBC CCC4CCC5CCC7CCC9CCD0CCD4CCE4CCECCCF0CD01CD08CD09CD0CCD10CD18CD19 CD1BCD1DCD24CD28CD2CCD39CD5CCD60CD64CD6CCD6DCD6FCD71CD78CD88CD94 CD95CD98CD9CCDA4CDA5CDA7CDA9CDB0CDC4CDCCCDD0CDE8CDECCDF0CDF8CDF9 CDFBCDFDCE04CE08CE0CCE14CE19CE20CE21CE24CE28CE30CE31CE33CE350000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 44 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000CE58CE59CE5CCE5FCE60CE61CE68CE69CE6BCE6DCE74CE75CE78CE7CCE84 CE85CE87CE89CE90CE91CE94CE98CEA0CEA1CEA3CEA4CEA5CEACCEADCEC1CEE4 CEE5CEE8CEEBCEECCEF4CEF5CEF7CEF8CEF9CF00CF01CF04CF08CF10CF11CF13 CF15CF1CCF20CF24CF2CCF2DCF2FCF30CF31CF38CF54CF55CF58CF5CCF64CF65 CF67CF69CF70CF71CF74CF78CF80CF85CF8CCFA1CFA8CFB0CFC4CFE0CFE1CFE4 CFE8CFF0CFF1CFF3CFF5CFFCD000D004D011D018D02DD034D035D038D03C0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 45 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D044D045D047D049D050D054D058D060D06CD06DD070D074D07CD07DD081 D0A4D0A5D0A8D0ACD0B4D0B5D0B7D0B9D0C0D0C1D0C4D0C8D0C9D0D0D0D1D0D3 D0D4D0D5D0DCD0DDD0E0D0E4D0ECD0EDD0EFD0F0D0F1D0F8D10DD130D131D134 D138D13AD140D141D143D144D145D14CD14DD150D154D15CD15DD15FD161D168 D16CD17CD184D188D1A0D1A1D1A4D1A8D1B0D1B1D1B3D1B5D1BAD1BCD1C0D1D8 D1F4D1F8D207D209D210D22CD22DD230D234D23CD23DD23FD241D248D25C0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 46 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D264D280D281D284D288D290D291D295D29CD2A0D2A4D2ACD2B1D2B8D2B9 D2BCD2BFD2C0D2C2D2C8D2C9D2CBD2D4D2D8D2DCD2E4D2E5D2F0D2F1D2F4D2F8 D300D301D303D305D30CD30DD30ED310D314D316D31CD31DD31FD320D321D325 D328D329D32CD330D338D339D33BD33CD33DD344D345D37CD37DD380D384D38C D38DD38FD390D391D398D399D39CD3A0D3A8D3A9D3ABD3ADD3B4D3B8D3BCD3C4 D3C5D3C8D3C9D3D0D3D8D3E1D3E3D3ECD3EDD3F0D3F4D3FCD3FDD3FFD4010000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 47 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D408D41DD440D444D45CD460D464D46DD46FD478D479D47CD47FD480D482 D488D489D48BD48DD494D4A9D4CCD4D0D4D4D4DCD4DFD4E8D4ECD4F0D4F8D4FB D4FDD504D508D50CD514D515D517D53CD53DD540D544D54CD54DD54FD551D558 D559D55CD560D565D568D569D56BD56DD574D575D578D57CD584D585D587D588 D589D590D5A5D5C8D5C9D5CCD5D0D5D2D5D8D5D9D5DBD5DDD5E4D5E5D5E8D5EC D5F4D5F5D5F7D5F9D600D601D604D608D610D611D613D614D615D61CD6200000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 48 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D624D62DD638D639D63CD640D645D648D649D64BD64DD651D654D655D658 D65CD667D669D670D671D674D683D685D68CD68DD690D694D69DD69FD6A1D6A8 D6ACD6B0D6B9D6BBD6C4D6C5D6C8D6CCD6D1D6D4D6D7D6D9D6E0D6E4D6E8D6F0 D6F5D6FCD6FDD700D704D711D718D719D71CD720D728D729D72BD72DD734D735 D738D73CD744D747D749D750D751D754D756D757D758D759D760D761D763D765 D769D76CD770D774D77CD77DD781D788D789D78CD790D798D799D79BD79D0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 4A 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00004F3D4F73504750F952A053EF547554E556095AC15BB6668767B667B767EF 6B4C73C275C27A3C82DB8304885788888A368CC88DCF8EFB8FE699D5523B5374 5404606A61646BBC73CF811A89BA89D295A34F83520A58BE597859E65E725E79 61C763C0674667EC687F6F97764E770B78F57A087AFF7C21809D826E82718AEB 95934E6B559D66F76E3478A37AED845B8910874E97A852D8574E582A5D4C611F 61BE6221656267D16A446E1B751875B376E377B07D3A90AF945194529F950000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 4B 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000053235CAC753280DB92409598525B580859DC5CA15D175EB75F3A5F4A6177 6C5F757A75867CE07D737DB17F8C81548221859189418B1B92FC964D9C474ECB 4EF7500B51F1584F6137613E6168653969EA6F1175A5768676D67B8782A584CB F90093A7958B55805BA25751F9017CB37FB991B5502853BB5C455DE862D2636E 64DA64E76E2070AC795B8DDD8E1EF902907D924592F84E7E4EF650655DFE5EFA 61066957817186548E4793759A2B4E5E5091677068405109528D52926AA20000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 4C 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000077BC92109ED452AB602F8FF2504861A963ED64CA683C6A846FC0818889A1 96945805727D72AC75047D797E6D80A9898B8B7490639D5162896C7A6F547D50 7F3A8A23517C614A7B9D8B199257938C4EAC4FD3501E50BE510652C152CD537F 577058835E9A5F91617661AC64CE656C666F66BB66F468976D87708570F1749F 74A574CA75D9786C78EC7ADF7AF67D457D938015803F811B83968B668F159015 93E1980398389A5A9BE84FC25553583A59515B635C4660B86212684268B00000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 4D 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000068E86EAA754C767878CE7A3D7CFB7E6B7E7C8A088AA18C3F968E9DC453E4 53E9544A547156FA59D15B645C3B5EAB62F765376545657266A067AF69C16CBD 75FC7690777E7A3F7F94800380A1818F82E682FD83F085C1883188B48AA5F903 8F9C932E96C798679AD89F1354ED659B66F2688F7A408C379D6056F057645D11 660668B168CD6EFE7428889E9BE46C68F9049AA84F9B516C5171529F5B545DE5 6050606D62F163A7653B73D97A7A86A38CA2978F4E325BE16208679C74DC0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 4E 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000079D183D38A878AB28DE8904E934B98465ED369E885FF90EDF90551A05B98 5BEC616368FA6B3E704C742F74D87BA17F5083C589C08CAB95DC9928522E605D 62EC90024F8A5149532158D95EE366E06D38709A72C273D67B5080F1945B5366 639B7F6B4E565080584A58DE602A612762D069D09B415B8F7D1880B18F5F4EA4 50D154AC55AC5B0C5DA05DE7652A654E68216A4B72E1768E77EF7D5E7FF981A0 854E86DF8F038F4E90CA99039A559BAB4E184E454E5D4EC74FF1517752FE0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 4F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000534053E353E5548E5614577557A25BC75D875ED061FC62D8655167B867E9 69CB6B506BC66BEC6C426E9D707872D77396740377BF77E97A767D7F800981FC 8205820A82DF88628B338CFC8EC0901190B1926492B699D29A459CE99DD79F9C 570B5C4083CA97A097AB9EB4541B7A987FA488D98ECD90E158005C4863987A9F 5BAE5F137A797AAE828E8EAC5026523852F85377570862F363726B0A6DC37737 53A5735785688E7695D5673A6AC36F708A6D8ECC994BF90666776B788CB40000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 50 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009B3CF90753EB572D594E63C669FB73EA78457ABA7AC57CFE8475898F8D73 903595A852FB574775477B6083CC921EF9086A58514B524B5287621F68D86975 969950C552A452E461C365A4683969FF747E7B4B82B983EB89B28B398FD19949 F9094ECA599764D266116A8E7434798179BD82A9887E887F895FF90A93264F0B 53CA602562716C727D1A7D664E98516277DC80AF4F014F0E5176518055DC5668 573B57FA57FC5914594759935BC45C905D0E5DF15E7E5FCC628065D765E30000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 51 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000671E671F675E68CB68C46A5F6B3A6C236C7D6C826DC773987426742A7482 74A37578757F788178EF794179477948797A7B957D007DBA7F888006802D808C 8A188B4F8C488D779321932498E299519A0E9A0F9A659E927DCA4F76540962EE 685491D155AB513AF90BF90C5A1C61E6F90D62CF62FFF90EF90FF910F911F912 F91390A3F914F915F916F917F9188AFEF919F91AF91BF91C6696F91D7156F91E F91F96E3F920634F637A5357F921678F69606E73F9227537F923F924F9250000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 52 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007D0DF926F927887256CA5A18F928F929F92AF92BF92C4E43F92D51675948 67F08010F92E59735E74649A79CA5FF5606C62C8637B5BE75BD752AAF92F5974 5F296012F930F931F9327459F933F934F935F936F937F93899D1F939F93AF93B F93CF93DF93EF93FF940F941F942F9436FC3F944F94581BF8FB260F1F946F947 8166F948F9495C3FF94AF94BF94CF94DF94EF94FF950F9515AE98A25677B7D10 F952F953F954F955F956F95780FDF958F9595C3C6CE5533F6EBA591A83360000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 53 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00004E394EB64F4655AE571858C75F5665B765E66A806BB56E4D77ED7AEF7C1E 7DDE86CB88929132935B64BB6FBE737A75B890545556574D61BA64D466C76DE1 6E5B6F6D6FB975F0804381BD854189838AC78B5A931F6C9375537B548E0F905D 5510580258585E626207649E68E075767CD687B39EE84EE35788576E59275C0D 5CB15E365F85623464E173B381FA888B8CB8968A9EDB5B855FB760B350125200 52305716583558575C0E5C605CF65D8B5EA65F9260BC63116389641768430000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 54 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000068F96AC26DD86E216ED46FE471FE76DC777979B17A3B840489A98CED8DF3 8E4890039014905390FD934D967697DC6BD27006725872A27368776379BF7BE4 7E9B8B8058A960C7656665FD66BE6C8C711E71C98C5A98134E6D7A814EDD51AC 51CD52D5540C61A76771685068DF6D1E6F7C75BC77B37AE580F484639285515C 6597675C679375D87AC78373F95A8C469017982D5C6F81C0829A9041906F920D 5F975D9D6A5971C8767B7B4985E48B0491279A30558761F6F95B76697F850000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 55 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000863F87BA88F8908FF95C6D1B70D973DE7D61843DF95D916A99F1F95E4E82 53756B046B12703E721B862D9E1E524C8FA35D5064E5652C6B166FEB7C437E9C 85CD896489BD62C981D8881F5ECA67176D6A72FC7405746F878290DE4F865D0D 5FA0840A51B763A075654EAE5006516951C968816A117CAE7CB17CE7826F8AD2 8F1B91CF4FB6513752F554425EEC616E623E65C56ADA6FFE792A85DC882395AD 9A629A6A9E979ECE529B66C66B77701D792B8F6297426190620065236F230000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 56 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000714974897DF4806F84EE8F269023934A51BD521752A36D0C70C888C25EC9 65826BAE6FC27C3E73754EE44F3656F9F95F5CBA5DBA601C73B27B2D7F9A7FCE 8046901E923496F6974898189F614F8B6FA779AE91B496B752DEF960648864C4 6AD36F5E7018721076E780018606865C8DEF8F0597329B6F9DFA9E75788C797F 7DA083C993049E7F9E938AD658DF5F046727702774CF7C60807E512170287262 78CA8CC28CDA8CF496F74E8650DA5BEE5ED6659971CE764277AD804A84FC0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 57 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000907C9B279F8D58D85A415C626A136DDA6F0F763B7D2F7E37851E893893E4 964B528965D267F369B46D416E9C700F7409746075597624786B8B2C985E516D 622E96784F96502B5D196DEA7DB88F2A5F8B61446817F961968652D2808B51DC 51CC695E7A1C7DBE83F196754FDA52295398540F550E5C6560A7674E68A86D6C 728172F874067483F96275E27C6C7F797FB8838988CF88E191CC91D096E29BC9 541D6F7E71D0749885FA8EAA96A39C579E9F67976DCB743381E89716782C0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 58 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007ACB7B207C926469746A75F278BC78E899AC9B549EBB5BDE5E556F20819C 83AB90884E07534D5A295DD25F4E6162633D666966FC6EFF6F2B7063779E842C 8513883B8F1399459C3B551C62B9672B6CAB8309896A977A4EA159845FD85FD9 671B7DB27F548292832B83BD8F1E909957CB59B95A925BD06627679A68856BCF 71647F758CB78CE390819B4581088C8A964C9A409EA55B5F6C13731B76F276DF 840C51AA8993514D519552C968C96C94770477207DBF7DEC97629EB56EC50000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 59 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000851151A5540D547D660E669D69276E9F76BF7791831784C2879F91699298 9CF488824FAE519252DF59C65E3D61556478647966AE67D06A216BCD6BDB725F 72617441773877DB801782BC83058B008B288C8C67286C90726776EE77667A46 9DA96B7F6C92592267268499536F589359995EDF63CF663467736E3A732B7AD7 82D7932852D95DEB61AE61CB620A62C764AB65E069596B666BCB712173F7755D 7E46821E8302856A8AA38CBF97279D6158A89ED85011520E543B554F65870000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5A 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006C767D0A7D0B805E868A958096EF52FF6C95726954735A9A5C3E5D4B5F4C 5FAE672A68B669636E3C6E4477097C737F8E85878B0E8FF797619EF45CB760B6 610D61AB654F65FB65FC6C116CEF739F73C97DE195945BC6871C8B10525D535A 62CD640F64B267346A386CCA73C0749E7B947C957E1B818A823685848FEB96F9 99C14F34534A53CD53DB62CC642C6500659169C36CEE6F5873ED7554762276E4 76FC78D078FB792C7D46822C87E08FD4981298EF52C362D464A56E246F510000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5B 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000767C8DCB91B192629AEE9B435023508D574A59A85C285E475F77623F653E 65B965C16609678B699C6EC278C57D2180AA8180822B82B384A1868C8A2A8B17 90A696329F90500D4FF3F96357F95F9862DC6392676F6E43711976C380CC80DA 88F488F589198CE08F29914D966A4F2F4F705E1B67CF6822767D767E9B445E61 6A0A716971D4756AF9647E41854385E998DC4F107B4F7F7095A551E15E0668B5 6C3E6C4E6CDB72AF7BC483036CD5743A50FB528858C164D86A9774A776560000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5C 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000078A7861795E29739F965535E5F018B8A8FA88FAF908A522577A59C499F08 4E19500251755C5B5E77661E663A67C468C570B3750175C579C97ADD8F279920 9A084FDD582158315BF6666E6B656D116E7A6F7D73E4752B83E988DC89138B5C 8F144F0F50D55310535C5B935FA9670D798F8179832F8514890789868F398F3B 99A59C12672C4E764FF859495C015CEF5CF0636768D270FD71A2742B7E2B84EC 8702902292D29CF34E0D4ED84FEF50855256526F5426549057E0592B5A660000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5D 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005B5A5B755BCC5E9CF9666276657765A76D6E6EA572367B267C3F7F368150 8151819A8240829983A98A038CA08CE68CFB8D748DBA90E891DC961C964499D9 9CE7531752065429567458B35954596E5FFF61A4626E66106C7E711A76C67C89 7CDE7D1B82AC8CC196F0F9674F5B5F175F7F62C25D29670B68DA787C7E439D6C 4E1550995315532A535159835A625E8760B2618A624962796590678769A76BD4 6BD66BD76BD86CB8F968743575FA7812789179D579D87C837DCB7FE180A50000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5E 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000813E81C283F2871A88E88AB98B6C8CBB9119975E98DB9F3B56AC5B2A5F6C 658C6AB36BAF6D5C6FF17015725D73AD8CA78CD3983B61916C3780589A014E4D 4E8B4E9B4ED54F3A4F3C4F7F4FDF50FF53F253F8550655E356DB58EB59625A11 5BEB5BFA5C045DF35E2B5F99601D6368659C65AF67F667FB68AD6B7B6C996CD7 6E23700973457802793E7940796079C17BE97D177D728086820D838E84D186C7 88DF8A508A5E8B1D8CDC8D668FAD90AA98FC99DF9E9D524AF9696714F96A0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005098522A5C7165636C5573CA7523759D7B97849C917897304E7764926BBA 715E85A94E09F96B674968EE6E17829F8518886B63F76F81921298AF4E0A50B7 50CF511F554655AA56175B405C195CE05E385E8A5EA05EC260F368516A616E58 723D724072C076F879657BB17FD488F389F48A738C618CDE971C585E74BD8CFD 55C7F96C7A617D2282727272751F7525F96D7B19588558FB5DBC5E8F5EB65F90 60556292637F654D669166D966F8681668F27280745E7B6E7D6E7DD67F720000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 60 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000080E5821285AF897F8A93901D92E49ECD9F205915596D5E2D60DC66146673 67906C506DC56F5F77F378A984C691CB932B4ED950CA514855845B0B5BA36247 657E65CB6E32717D74017444748774BF766C79AA7DDA7E557FA8817A81B38239 861A87EC8A758DE3907892919425994D9BAE53685C5169546CC46D296E2B820C 859B893B8A2D8AAA96EA9F67526166B96BB27E9687FE8D0D9583965D651D6D89 71EEF96E57CE59D35BAC602760FA6210661F665F732973F976DB77017B6C0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 61 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008056807281658AA091924E1652E26B726D177A057B397D30F96F8CB053EC 562F58515BB55C0F5C115DE2624063836414662D68B36CBC6D886EAF701F70A4 71D27526758F758E76197B117BE07C2B7D207D39852C856D86078A34900D9061 90B592B797F69A374FD75C6C675F6D917C9F7E8C8B168D16901F5B6B5DFD640D 84C0905C98E173875B8B609A677E6DDE8A1F8AA69001980C5237F9707051788E 9396887091D74FEE53D755FD56DA578258FD5AC25B885CAB5CC05E2561010000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 62 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000620D624B6388641C653665786A396B8A6C346D196F3171E772E973787407 74B27626776179C07A577AEA7CB97D8F7DAC7E617F9E81298331849084DA85EA 88968AB08B908F3890429083916C929692B9968B96A796A896D6970098089996 9AD39B1A53D4587E59195B705BBF6DD16F5A719F742174B9808583FD5DE15F87 5FAA604265EC6812696F6A536B896D356DF373E376FE77AC7B4D7D148123821C 834084F485638A628AC49187931E980699B4620C88538FF092655D075D270000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 63 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005D69745F819D87686FD562FE7FD2893689724E1E4E5850E752DD5347627F 66077E698805965E4F8D5319563659CB5AA45C385C4E5C4D5E025F11604365BD 662F664267BE67F4731C77E2793A7FC5849484CD89968A668A698AE18C558C7A 57F45BD45F0F606F62ED690D6B966E5C71847BD287558B588EFE98DF98FE4F38 4F814FE1547B5A205BB8613C65B0666871FC7533795E7D33814E81E3839885AA 85CE87038A0A8EAB8F9BF9718FC559315BA45BE660895BE95C0B5FC36C810000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 64 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000F9726DF1700B751A82AF8AF64EC05341F97396D96C0F4E9E4FC45152555E 5A255CE86211725982BD83AA86FE88598A1D963F96C599139D099D5D580A5CB3 5DBD5E4460E1611563E16A026E2591029354984E9C109F775B895CB86309664F 6848773C96C1978D98549B9F65A18B018ECB95BC55355CA95DD65EB56697764C 83F495C758D362BC72CE9D284EF0592E600F663B6B8379E79D26539354C057C3 5D16611B66D66DAF788D827E969897445384627C63966DB27E0A814B984D0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 65 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006AFB7F4C9DAF9E1A4E5F503B51B6591C60F963F66930723A8036F97491CE 5F31F975F9767D0482E5846F84BB85E58E8DF9774F6FF978F97958E45B436059 63DA6518656D6698F97A694A6A236D0B7001716C75D2760D79B37A70F97B7F8A F97C8944F97D8B9391C0967DF97E990A57045FA165BC6F01760079A68A9E99AD 9B5A9F6C510461B662916A8D81C6504358305F6671098A008AFA5B7C86164FFA 513C56B4594463A96DF95DAA696D51864E884F59F97FF980F9815982F9820000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 66 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000F9836B5F6C5DF98474B57916F9858207824583398F3F8F5DF9869918F987 F988F9894EA6F98A57DF5F796613F98BF98C75AB7E798B6FF98D90069A5B56A5 582759F85A1F5BB4F98E5EF6F98FF9906350633BF991693D6C876CBF6D8E6D93 6DF56F14F99270DF71367159F99371C371D5F994784F786FF9957B757DE3F996 7E2FF997884D8EDFF998F999F99A925BF99B9CF6F99CF99DF99E60856D85F99F 71B1F9A0F9A195B153ADF9A2F9A3F9A467D3F9A5708E71307430827682D20000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 67 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000F9A695BB9AE59E7D66C4F9A771C18449F9A8F9A9584BF9AAF9AB5DB85F71 F9AC6620668E697969AE6C386CF36E366F416FDA701B702F715071DF7370F9AD 745BF9AE74D476C87A4E7E93F9AFF9B082F18A608FCEF9B19348F9B29719F9B3 F9B44E42502AF9B5520853E166F36C6D6FCA730A777F7A6282AE85DD8602F9B6 88D48A638B7D8C6BF9B792B3F9B8971398104E944F0D4FC950B25348543E5433 55DA586258BA59675A1B5BE4609FF9B961CA655665FF666468A76C5A6FB30000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 68 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000070CF71AC73527B7D87088AA49C329F075C4B6C8373447389923A6EAB7465 761F7A697E15860A514058C564C174EE751576707FC1909596CD99546E2674E6 7AA97AAA81E586D987788A1B5A495B8C5B9B68A169006D6373A97413742C7897 7DE97FEB81188155839E8C4C962E981166F05F8065FA67896C6A738B502D5A03 6B6A77EE59165D6C5DCD7325754FF9BAF9BB50E551F9582F592D599659DA5BE5 F9BCF9BD5DA262D76416649364FEF9BE66DCF9BF6A48F9C071FF7464F9C10000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 69 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007A887AAF7E477E5E80008170F9C287EF89818B209059F9C390809952617E 6B326D747E1F89258FB14FD150AD519752C757C758895BB95EB8614269956D8C 6E676EB6719474627528752C8073833884C98E0A939493DEF9C44E8E4F515076 512A53C853CB53F35B875BD35C24611A618265F4725B7397744076C279507991 79B97D067FBD828B85D5865E8FC2904790F591EA968596E896E952D65F6765ED 6631682F715C7A3690C1980A4E91F9C56A526B9E6F907189801882B885530000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6A 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000904B969596F297FB851A9B314E90718A96C45143539F54E15713571257A3 5A9B5AC45BC36028613F63F46C856D396E726E907230733F745782D188818F45 9060F9C6966298589D1B67088D8A925E4F4D504950DE5371570D59D45A015C09 617066906E2D7232744B7DEF80C3840E8466853F875F885B89188B02905597CB 9B4F4E734F915112516AF9C7552F55A95B7A5BA55E7C5E7D5EBE60A060DF6108 610963C465386709F9C867D467DAF9C9696169626CB96D27F9CA6E38F9CB0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6B 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006FE173367337F9CC745C7531F9CD7652F9CEF9CF7DAD81FE843888D58A98 8ADB8AED8E308E42904A903E907A914991C9936EF9D0F9D15809F9D26BD38089 80B2F9D3F9D45141596B5C39F9D5F9D66F6473A780E48D07F9D79217958FF9D8 F9D9F9DAF9DB807F620E701C7D68878DF9DC57A0606961476BB78ABE928096B1 4E59541F6DEB852D967097F398EE63D66CE3909151DD61C981BA9DF94F9D501A 51005B9C610F61FF64EC69056BC5759177E37FA98264858F87FB88638ABC0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6C 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008B7091AB4E8C4EE54F0AF9DDF9DE593759E8F9DF5DF25F1B5F5B6021F9E0 F9E1F9E2F9E3723E73E5F9E4757075CDF9E579FBF9E6800C8033808482E18351 F9E7F9E88CBD8CB39087F9E9F9EA98F4990CF9EBF9EC703776CA7FCA7FCC7FFC 8B1A4EBA4EC152035370F9ED54BD56E059FB5BC55F155FCD6E6EF9EEF9EF7D6A 8335F9F086938A8DF9F1976D9777F9F2F9F34E004F5A4F7E58F965E56EA29038 93B099B94EFB58EC598A59D96041F9F4F9F57A14F9F6834F8CC3516553440000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6D 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000F9F7F9F8F9F94ECD52695B5582BF4ED4523A54A859C959FF5B505B575B5C 606361486ECB7099716E738674F775B578C17D2B800581EA8328851785C98AEE 8CC796CC4F5C52FA56BC65AB6628707C70B872357DBD828D914C96C09D725B71 68E76B986F7A76DE5C9166AB6F5B7BB47C2A883696DC4E084ED75320583458BB 58EF596C5C075E335E845F35638C66B267566A1F6AA36B0C6F3F7246F9FA7350 748B7AE07CA7817881DF81E7838A846C8523859485CF88DD8D1391AC95770000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6E 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000969C518D54C957285BB0624D6750683D68936E3D6ED3707D7E2188C18CA1 8F099F4B9F4E722D7B8F8ACD931A4F474F4E5132548059D05E9562B56775696E 6A176CAE6E1A72D9732A75BD7BB87D3582E783F9845785F78A5B8CAF8E879019 90B896CE9F5F52E3540A5AE15BC2645865756EF472C4F9FB76847A4D7B1B7C4D 7E3E7FDF837B8B2B8CCA8D648DE18E5F8FEA8FF9906993D14F434F7A50B35168 5178524D526A5861587C59605C085C555EDB609B623068136BBF6C086FB10000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000714E742075307538755176727B4C7B8B7BAD7BC67E8F8A6E8F3E8F49923F 92939322942B96FB985A986B991E5207622A62986D5976647ACA7BC07D765360 5CBE5E976F3870B97C9897119B8E9EDE63A5647A87764E014E954EAD505C5075 544859C35B9A5E405EAD5EF75F8160C5633A653F657465CC6676667867FE6968 6A896B636C406DC06DE86E1F6E5E701E70A1738E73FD753A775B7887798E7A0B 7A7D7CBE7D8E82478A028AEA8C9E912D914A91D8926692CC9320970697560000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 70 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000975C98029F0E52365291557C58245E1D5F1F608C63D068AF6FDF796D7B2C 81CD85BA88FD8AF88E44918D9664969B973D984C9F4A4FCE514651CB52A95632 5F145F6B63AA64CD65E9664166FA66F9671D689D68D769FD6F156F6E716771E5 722A74AA773A7956795A79DF7A207A957C977CDF7D447E70808785FB86A48A54 8ABF8D998E819020906D91E3963B96D59CE565CF7C078DB393C35B585C0A5352 62D9731D50275B975F9E60B0616B68D56DD9742E7A2E7D427D9C7E31816B0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 71 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008E2A8E35937E94184F5057505DE65EA7632B7F6A4E3B4F4F4F8F505A59DD 80C4546A546855FE594F5B995DDE5EDA665D673167F1682A6CE86D326E4A6F8D 70B773E075877C4C7D027D2C7DA2821F86DB8A3B8A858D708E8A8F339031914E 9152944499D07AF97CA54FCA510151C657C85BEF5CFB66596A3D6D5A6E966FEC 710C756F7AE388229021907596CB99FF83014E2D4EF2884691CD537D6ADB696B 6C41847A589E618E66FE62EF70DD751175C77E5284B88B498D084E4B53EA0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 72 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000054AB573057405FD763016307646F652F65E8667A679D67B36B626C606C9A 6F2C77E57825794979577D1980A2810281F3829D82B787188A8CF9FC8D048DBE 907276F47A197A377E548077550755D45875632F64226649664B686D699B6B84 6D256EB173CD746874A1755B75B976E1771E778B79E67E097E1D81FB852F8897 8A3A8CD18EEB8FB0903293AD9663967397074F8453F159EA5AC95E19684E74C6 75BE79E97A9281A386ED8CEA8DCC8FED659F6715F9FD57F76F577DDD8F2F0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 73 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000093F696C65FB561F26F844E144F98501F53C955DF5D6F5DEE6B216B6478CB 7B9AF9FE8E498ECA906E6349643E77407A84932F947F9F6A64B06FAF71E674A8 74DA7AC47C127E827CB27E988B9A8D0A947D9910994C52395BDF64E6672D7D2E 50ED53C358796158615961FA65AC7AD98B928B9650095021527555315A3C5EE0 5F706134655E660C663666A269CD6EC46F32731676217A938139825983D684BC 50B557F05BC05BE85F6963A178267DB583DC852191C791F5518A67F57B560000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 74 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008CAC51C459BB60BD8655501CF9FF52545C3A617D621A62D364F265A56ECC 7620810A8E60965F96BB4EDF5343559859295DDD64C56CC96DFA73947A7F821B 85A68CE48E10907791E795E1962197C651F854F255865FB964A46F887DB48F1F 8F4D943550C95C166CBE6DFB751B77BB7C3D7C648A798AC2581E59BE5E166377 7252758A776B8ADC8CBC8F125EF366746DF8807D83C18ACB97519BD6FA005243 66FF6D956EEF7DE08AE6902E905E9AD4521D527F54E86194628462DB68A20000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 75 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006912695A6A3570927126785D7901790E79D27A0D8096827882D583498549 8C828D859162918B91AE4FC356D171ED77D7870089F85BF85FD6675190A853E2 585A5BF560A4618164607E3D80708525928364AE50AC5D146700589C62BD63A8 690E69786A1E6E6B76BA79CB82BB84298ACF8DA88FFD9112914B919C93109318 939A96DB9A369C0D4E11755C795D7AFA7B517BC97E2E84C48E598E748EF89010 6625693F744351FA672E9EDC51455FE06C9687F2885D887760B481B584030000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 76 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008D0553D6543956345A365C31708A7FE0805A810681ED8DA391899A5F9DF2 50744EC453A060FB6E2C5C644F88502455E45CD95E5F606568946CBB6DC471BE 75D475F476617A1A7A497DC77DFB7F6E81F486A98F1C96C999B39F52524752C5 98ED89AA4E0367D26F064FB55BE267956C886D78741B782791DD937C87C479E4 7A315FEB4ED654A4553E58AE59A560F0625362D6673669558235964099B199DD 502C53535544577CFA016258FA0264E2666B67DD6FC16FEF742274388A170000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 77 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000094385451560657665F48619A6B4E705870AD7DBB8A95596A812B63A27708 803D8CAA5854642D69BB5B955E116E6FFA038569514C53F0592A6020614B6B86 6C706CF07B1E80CE82D48DC690B098B1FA0464C76FA464916504514E5410571F 8A0E615F6876FA0575DB7B527D71901A580669CC817F892A9000983950785957 59AC6295900F9B2A615D727995D657615A465DF4628A64AD64FA67776CE26D3E 722C743678347F7782AD8DDB981752245742677F724874E38CA98FA692110000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 78 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000962A516B53ED634C4F695504609665576C9B6D7F724C72FD7A1789878C9D 5F6D6F8E70F981A8610E4FBF504F624172477BC77DE87FE9904D97AD9A198CB6 576A5E7367B0840D8A5554205B165E635EE25F0A658380BA853D9589965B4F48 5305530D530F548654FA57035E036016629B62B16355FA066CE16D6675B17832 80DE812F82DE846184B2888D8912900B92EA98FD9B915E4566B466DD70117206 FA074FF5527D5F6A615367536A196F0274E2796888688C7998C798C49A430000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 79 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000054C17A1F69538AF78C4A98A899AE5F7C62AB75B276AE88AB907F96425339 5F3C5FC56CCC73CC7562758B7B4682FE999D4E4F903C4E0B4F5553A6590F5EC8 66306CB37455837787668CC09050971E9C1558D15B7886508B149DB45BD26068 608D65F16C576F226FA3701A7F557FF095919592965097D352728F4451FD542B 54B85563558A6ABB6DB57DD88266929C96779E79540854C876D286E495A495D4 965C4EA24F0959EE5AE65DF760526297676D68416C866E2F7F38809B822A0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7A 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FA08FA0998054EA5505554B35793595A5B695BB361C869776D77702387F9 89E38A728AE7908299ED9AB852BE683850165E78674F8347884C4EAB541156AE 73E6911597FF9909995799995653589F865B8A3161B26AF6737B8ED26B4796AA 9A57595572008D6B97694FD45CF45F2661F8665B6CEB70AB738473B973FE7729 774D7D437D627E2382378852FA0A8CE29249986F5B517A74884098015ACC4FE0 5354593E5CFD633E6D7972F98105810783A292CF98304EA851445211578B0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7B 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005F626CC26ECE7005705070AF719273E97469834A87A28861900890A293A3 99A8516E5F5760E0616766B385598E4A91AF978B4E4E4E92547C58D558FA597D 5CB55F2762366248660A66676BEB6D696DCF6E566EF86F946FE06FE9705D72D0 7425745A74E07693795C7CCA7E1E80E182A6846B84BF864E865F87748B778C6A 93AC9800986560D1621691775A5A660F6DF76E3E743F9B425FFD60DA7B0F54C4 5F186C5E6CD36D2A70D87D0586798A0C9D3B5316548C5B056A3A706B75750000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7C 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000798D79BE82B183EF8A718B418CA89774FA0B64F4652B78BA78BB7A6B4E38 559A59505BA65E7B60A363DB6B61666568536E19716574B07D0890849A699C25 6D3B6ED1733E8C4195CA51F05E4C5FA8604D60F66130614C6643664469A56CC1 6E5F6EC96F62714C749C76877BC17C27835287579051968D9EC3532F56DE5EFB 5F8A6062609461F7666667036A9C6DEE6FAE7070736A7E6A81BE833486D48AA8 8CC4528373725B966A6B940454EE56865B5D6548658566C9689F6D8D6DC60000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7D 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000723B80B491759A4D4FAF5019539A540E543C558955C55E3F5F8C673D7166 73DD900552DB52F3586458CE7104718F71FB85B08A13668885A855A76684714A 8431534955996BC15F595FBD63EE668971478AF18F1D9EBE4F11643A70CB7566 866760648B4E9DF8514751F653086D3680F89ED166156B23709875D554035C79 7D078A166B206B3D6B46543860706D3D7FD5820850D651DE559C566B56CD59EC 5B095E0C619961986231665E66E6719971B971BA72A779A77A007FB28A700000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 tcl8.4.20/library/encoding/macDingbats.enc0000644003604700454610000000211011737050674017046 0ustar dgp771div# Encoding file: macDingbats, single-byte S 003F 1 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 00202701270227032704260E2706270727082709261B261E270C270D270E270F 2710271127122713271427152716271727182719271A271B271C271D271E271F 2720272127222723272427252726272726052729272A272B272C272D272E272F 2730273127322733273427352736273727382739273A273B273C273D273E273F 2740274127422743274427452746274727482749274A274B25CF274D25A0274F 27502751275225B225BC25C6275625D727582759275A275B275C275D275E007F F8D7F8D8F8D9F8DAF8DBF8DCF8DDF8DEF8DFF8E0F8E1F8E2F8E3F8E4008E008F 0090009100920093009400950096009700980099009A009B009C009D009E009F 0000276127622763276427652766276726632666266526602460246124622463 2464246524662467246824692776277727782779277A277B277C277D277E277F 2780278127822783278427852786278727882789278A278B278C278D278E278F 2790279127922793279421922194219527982799279A279B279C279D279E279F 27A027A127A227A327A427A527A627A727A827A927AA27AB27AC27AD27AE27AF 000027B127B227B327B427B527B627B727B827B927BA27BB27BC27BD27BE0000 tcl8.4.20/library/encoding/ebcdic.enc0000644003604700454610000000203611737050674016052 0ustar dgp771divS 006F 0 1 00 0000000100020003008500090086007F0087008D008E000B000C000D000E000F 0010001100120013008F000A0008009700180019009C009D001C001D001E001F 0080008100820083008400920017001B00880089008A008B008C000500060007 0090009100160093009400950096000400980099009A009B00140015009E001A 002000A000E200E400E000E100E300E500E700F10060002E003C0028002B007C 002600E900EA00EB00E800ED00EE00EF00EC00DF00210024002A0029003B009F 002D002F00C200C400C000C100C300C500C700D1005E002C0025005F003E003F 00F800C900CA00CB00C800CD00CE00CF00CC00A8003A002300400027003D0022 00D800610062006300640065006600670068006900AB00BB00F000FD00FE00B1 00B0006A006B006C006D006E006F00700071007200AA00BA00E600B800C600A4 00B500AF0073007400750076007700780079007A00A100BF00D000DD00DE00AE 00A200A300A500B700A900A700B600BC00BD00BE00AC005B005C005D00B400D7 00F900410042004300440045004600470048004900AD00F400F600F200F300F5 00A6004A004B004C004D004E004F00500051005200B900FB00FC00DB00FA00FF 00D900F70053005400550056005700580059005A00B200D400D600D200D300D5 003000310032003300340035003600370038003900B3007B00DC007D00DA007E tcl8.4.20/library/encoding/ascii.enc0000644003604700454610000000210211737050674015723 0ustar dgp771div# Encoding file: ascii, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 tcl8.4.20/library/encoding/iso8859-7.enc0000644003604700454610000000210611737050674016133 0ustar dgp771div# Encoding file: iso8859-7, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 0080008100820083008400850086008700880089008A008B008C008D008E008F 0090009100920093009400950096009700980099009A009B009C009D009E009F 00A02018201900A30000000000A600A700A800A9000000AB00AC00AD00002015 00B000B100B200B303840385038600B703880389038A00BB038C00BD038E038F 0390039103920393039403950396039703980399039A039B039C039D039E039F 03A003A1000003A303A403A503A603A703A803A903AA03AB03AC03AD03AE03AF 03B003B103B203B303B403B503B603B703B803B903BA03BB03BC03BD03BE03BF 03C003C103C203C303C403C503C603C703C803C903CA03CB03CC03CD03CE0000 tcl8.4.20/library/encoding/iso2022.enc0000644003604700454610000000034211737050674015737 0ustar dgp771div# Encoding file: iso2022, escape-driven E name iso2022 init {} final {} iso8859-1 \x1b(B jis0201 \x1b(J gb1988 \x1b(T jis0208 \x1b$B jis0208 \x1b$@ jis0212 \x1b$(D gb2312 \x1b$A ksc5601 \x1b$(C jis0208 \x1b&@\x1b$B tcl8.4.20/library/encoding/gb1988.enc0000644003604700454610000000210311737050674015556 0ustar dgp771div# Encoding file: gb1988, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 002000210022002300A500250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D203E007F 0080008100820083008400850086008700880089008A008B008C008D008E008F 0090009100920093009400950096009700980099009A009B009C009D009E009F 0000FF61FF62FF63FF64FF65FF66FF67FF68FF69FF6AFF6BFF6CFF6DFF6EFF6F FF70FF71FF72FF73FF74FF75FF76FF77FF78FF79FF7AFF7BFF7CFF7DFF7EFF7F FF80FF81FF82FF83FF84FF85FF86FF87FF88FF89FF8AFF8BFF8CFF8DFF8EFF8F FF90FF91FF92FF93FF94FF95FF96FF97FF98FF99FF9AFF9BFF9CFF9DFF9EFF9F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 tcl8.4.20/library/encoding/cp865.enc0000644003604700454610000000210211737050674015500 0ustar dgp771div# Encoding file: cp865, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 00C700FC00E900E200E400E000E500E700EA00EB00E800EF00EE00EC00C400C5 00C900E600C600F400F600F200FB00F900FF00D600DC00F800A300D820A70192 00E100ED00F300FA00F100D100AA00BA00BF231000AC00BD00BC00A100AB00A4 259125922593250225242561256225562555256325512557255D255C255B2510 25142534252C251C2500253C255E255F255A25542569256625602550256C2567 2568256425652559255825522553256B256A2518250C25882584258C25902580 03B100DF039303C003A303C300B503C403A6039803A903B4221E03C603B52229 226100B1226522642320232100F7224800B0221900B7221A207F00B225A000A0 tcl8.4.20/library/encoding/macRoman.enc0000644003604700454610000000210511737050674016373 0ustar dgp771div# Encoding file: macRoman, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 00C400C500C700C900D100D600DC00E100E000E200E400E300E500E700E900E8 00EA00EB00ED00EC00EE00EF00F100F300F200F400F600F500FA00F900FB00FC 202000B000A200A300A7202200B600DF00AE00A9212200B400A8226000C600D8 221E00B12264226500A500B522022211220F03C0222B00AA00BA03A900E600F8 00BF00A100AC221A01922248220600AB00BB202600A000C000C300D501520153 20132014201C201D2018201900F725CA00FF0178204420AC2039203AFB01FB02 202100B7201A201E203000C200CA00C100CB00C800CD00CE00CF00CC00D300D4 F8FF00D200DA00DB00D9013102C602DC00AF02D802D902DA00B802DD02DB02C7 tcl8.4.20/library/encoding/cp1254.enc0000644003604700454610000000210311737050674015552 0ustar dgp771div# Encoding file: cp1254, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 20AC0081201A0192201E20262020202102C62030016020390152008D008E008F 009020182019201C201D20222013201402DC21220161203A0153009D009E0178 00A000A100A200A300A400A500A600A700A800A900AA00AB00AC00AD00AE00AF 00B000B100B200B300B400B500B600B700B800B900BA00BB00BC00BD00BE00BF 00C000C100C200C300C400C500C600C700C800C900CA00CB00CC00CD00CE00CF 011E00D100D200D300D400D500D600D700D800D900DA00DB00DC0130015E00DF 00E000E100E200E300E400E500E600E700E800E900EA00EB00EC00ED00EE00EF 011F00F100F200F300F400F500F600F700F800F900FA00FB00FC0131015F00FF tcl8.4.20/library/encoding/macCroatian.enc0000644003604700454610000000211011737050674017053 0ustar dgp771div# Encoding file: macCroatian, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 00C400C500C700C900D100D600DC00E100E000E200E400E300E500E700E900E8 00EA00EB00ED00EC00EE00EF00F100F300F200F400F600F500FA00F900FB00FC 202000B000A200A300A7202200B600DF00AE0160212200B400A82260017D00D8 221E00B122642265220600B522022211220F0161222B00AA00BA03A9017E00F8 00BF00A100AC221A01922248010600AB010C202600A000C000C300D501520153 01102014201C201D2018201900F725CAF8FF00A9204420AC2039203A00C600BB 201300B7201A201E203000C2010700C1010D00C800CD00CE00CF00CC00D300D4 011100D200DA00DB00D9013102C602DC00AF03C000CB02DA00B800CA00E602C7 tcl8.4.20/library/encoding/cp866.enc0000644003604700454610000000210211737050674015501 0ustar dgp771div# Encoding file: cp866, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 0410041104120413041404150416041704180419041A041B041C041D041E041F 0420042104220423042404250426042704280429042A042B042C042D042E042F 0430043104320433043404350436043704380439043A043B043C043D043E043F 259125922593250225242561256225562555256325512557255D255C255B2510 25142534252C251C2500253C255E255F255A25542569256625602550256C2567 2568256425652559255825522553256B256A2518250C25882584258C25902580 0440044104420443044404450446044704480449044A044B044C044D044E044F 040104510404045404070457040E045E00B0221900B7221A211600A425A000A0 tcl8.4.20/library/encoding/cp775.enc0000644003604700454610000000210211737050674015500 0ustar dgp771div# Encoding file: cp775, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 010600FC00E9010100E4012300E501070142011301560157012B017900C400C5 00C900E600C6014D00F6012200A2015A015B00D600DC00F800A300D800D700A4 0100012A00F3017B017C017A201D00A600A900AE00AC00BD00BC014100AB00BB 259125922593250225240104010C01180116256325512557255D012E01602510 25142534252C251C2500253C0172016A255A25542569256625602550256C017D 0105010D01190117012F01610173016B017E2518250C25882584258C25902580 00D300DF014C014300F500D500B5014401360137013B013C0146011201452019 00AD00B1201C00BE00B600A700F7201E00B0221900B700B900B300B225A000A0 tcl8.4.20/library/encoding/macIceland.enc0000644003604700454610000000210711737050674016660 0ustar dgp771div# Encoding file: macIceland, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 00C400C500C700C900D100D600DC00E100E000E200E400E300E500E700E900E8 00EA00EB00ED00EC00EE00EF00F100F300F200F400F600F500FA00F900FB00FC 00DD00B000A200A300A7202200B600DF00AE00A9212200B400A8226000C600D8 221E00B12264226500A500B522022211220F03C0222B00AA00BA03A900E600F8 00BF00A100AC221A01922248220600AB00BB202600A000C000C300D501520153 20132014201C201D2018201900F725CA00FF0178204420AC00D000F000DE00FE 00FD00B7201A201E203000C200CA00C100CB00C800CD00CE00CF00CC00D300D4 F8FF00D200DA00DB00D9013102C602DC00AF02D802D902DA00B802DD02DB02C7 tcl8.4.20/library/encoding/iso8859-15.enc0000644003604700454610000000210711737050674016213 0ustar dgp771div# Encoding file: iso8859-15, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 0080008100820083008400850086008700880089008A008B008C008D008E008F 0090009100920093009400950096009700980099009A009B009C009D009E009F 00A000A100A200A320AC00A5016000A7016100A900AA00AB00AC00AD00AE00AF 00B000B100B200B3017D00B500B600B7017E00B900BA00BB01520153017800BF 00C000C100C200C300C400C500C600C700C800C900CA00CB00CC00CD00CE00CF 00D000D100D200D300D400D500D600D700D800D900DA00DB00DC00DD00DE00DF 00E000E100E200E300E400E500E600E700E800E900EA00EB00EC00ED00EE00EF 00F000F100F200F300F400F500F600F700F800F900FA00FB00FC00FD00FE00FF tcl8.4.20/library/encoding/cp869.enc0000644003604700454610000000210211737050674015504 0ustar dgp771div# Encoding file: cp869, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 0080008100820083008400850386008700B700AC00A620182019038820150389 038A03AA038C00930094038E03AB00A9038F00B200B303AC00A303AD03AE03AF 03CA039003CC03CD039103920393039403950396039700BD0398039900AB00BB 25912592259325022524039A039B039C039D256325512557255D039E039F2510 25142534252C251C2500253C03A003A1255A25542569256625602550256C03A3 03A403A503A603A703A803A903B103B203B32518250C2588258403B403B52580 03B603B703B803B903BA03BB03BC03BD03BE03BF03C003C103C303C203C40384 00AD00B103C503C603C700A703C8038500B000A803C903CB03B003CE25A000A0 tcl8.4.20/library/encoding/shiftjis.enc0000644003604700454610000012160611737050674016471 0ustar dgp771div# Encoding file: shiftjis, multi-byte M 003F 0 40 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 0080000000000000000000850086008700000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FF61FF62FF63FF64FF65FF66FF67FF68FF69FF6AFF6BFF6CFF6DFF6EFF6F FF70FF71FF72FF73FF74FF75FF76FF77FF78FF79FF7AFF7BFF7CFF7DFF7EFF7F FF80FF81FF82FF83FF84FF85FF86FF87FF88FF89FF8AFF8BFF8CFF8DFF8EFF8F FF90FF91FF92FF93FF94FF95FF96FF97FF98FF99FF9AFF9BFF9CFF9DFF9EFF9F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 81 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 300030013002FF0CFF0E30FBFF1AFF1BFF1FFF01309B309C00B4FF4000A8FF3E FFE3FF3F30FD30FE309D309E30034EDD30053006300730FC20152010FF0FFF3C 301C2016FF5C2026202520182019201C201DFF08FF0930143015FF3BFF3DFF5B FF5D30083009300A300B300C300D300E300F30103011FF0B221200B100D70000 00F7FF1D2260FF1CFF1E22662267221E22342642264000B0203220332103FFE5 FF0400A200A3FF05FF03FF06FF0AFF2000A72606260525CB25CF25CE25C725C6 25A125A025B325B225BD25BC203B301221922190219121933013000000000000 000000000000000000000000000000002208220B2286228722822283222A2229 000000000000000000000000000000002227222800AC21D221D4220022030000 0000000000000000000000000000000000000000222022A52312220222072261 2252226A226B221A223D221D2235222B222C0000000000000000000000000000 212B2030266F266D266A2020202100B6000000000000000025EF000000000000 82 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000FF10 FF11FF12FF13FF14FF15FF16FF17FF18FF190000000000000000000000000000 FF21FF22FF23FF24FF25FF26FF27FF28FF29FF2AFF2BFF2CFF2DFF2EFF2FFF30 FF31FF32FF33FF34FF35FF36FF37FF38FF39FF3A000000000000000000000000 0000FF41FF42FF43FF44FF45FF46FF47FF48FF49FF4AFF4BFF4CFF4DFF4EFF4F FF50FF51FF52FF53FF54FF55FF56FF57FF58FF59FF5A00000000000000003041 30423043304430453046304730483049304A304B304C304D304E304F30503051 30523053305430553056305730583059305A305B305C305D305E305F30603061 30623063306430653066306730683069306A306B306C306D306E306F30703071 30723073307430753076307730783079307A307B307C307D307E307F30803081 30823083308430853086308730883089308A308B308C308D308E308F30903091 3092309300000000000000000000000000000000000000000000000000000000 83 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 30A130A230A330A430A530A630A730A830A930AA30AB30AC30AD30AE30AF30B0 30B130B230B330B430B530B630B730B830B930BA30BB30BC30BD30BE30BF30C0 30C130C230C330C430C530C630C730C830C930CA30CB30CC30CD30CE30CF30D0 30D130D230D330D430D530D630D730D830D930DA30DB30DC30DD30DE30DF0000 30E030E130E230E330E430E530E630E730E830E930EA30EB30EC30ED30EE30EF 30F030F130F230F330F430F530F6000000000000000000000000000000000391 03920393039403950396039703980399039A039B039C039D039E039F03A003A1 03A303A403A503A603A703A803A90000000000000000000000000000000003B1 03B203B303B403B503B603B703B803B903BA03BB03BC03BD03BE03BF03C003C1 03C303C403C503C603C703C803C9000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 84 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 04100411041204130414041504010416041704180419041A041B041C041D041E 041F0420042104220423042404250426042704280429042A042B042C042D042E 042F000000000000000000000000000000000000000000000000000000000000 04300431043204330434043504510436043704380439043A043B043C043D0000 043E043F0440044104420443044404450446044704480449044A044B044C044D 044E044F00000000000000000000000000000000000000000000000000002500 2502250C251025182514251C252C25242534253C25012503250F2513251B2517 25232533252B253B254B2520252F25282537253F251D25302525253825420000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 88 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000004E9C 55165A03963F54C0611B632859F690228475831C7A5060AA63E16E2565ED8466 82A69BF56893572765A162715B9B59D0867B98F47D627DBE9B8E62167C9F88B7 5B895EB563096697684895C7978D674F4EE54F0A4F4D4F9D504956F2593759D4 5A015C0960DF610F61706613690570BA754F757079FB7DAD7DEF80C3840E8863 8B029055907A533B4E954EA557DF80B290C178EF4E0058F16EA290387A328328 828B9C2F5141537054BD54E156E059FB5F1598F26DEB80E4852D000000000000 89 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 9662967096A097FB540B53F35B8770CF7FBD8FC296E8536F9D5C7ABA4E117893 81FC6E26561855046B1D851A9C3B59E553A96D6674DC958F56424E91904B96F2 834F990C53E155B65B305F71662066F368046C386CF36D29745B76C87A4E9834 82F1885B8A6092ED6DB275AB76CA99C560A68B018D8A95B2698E53AD51860000 5712583059445BB45EF6602863A963F46CBF6F14708E7114715971D5733F7E01 827682D185979060925B9D1B586965BC6C5A752551F9592E59655F805FDC62BC 65FA6A2A6B276BB4738B7FC189569D2C9D0E9EC45CA16C96837B51045C4B61B6 81C6687672614E594FFA537860696E297A4F97F34E0B53164EEE4F554F3D4FA1 4F7352A053EF5609590F5AC15BB65BE179D16687679C67B66B4C6CB3706B73C2 798D79BE7A3C7B8782B182DB8304837783EF83D387668AB256298CA88FE6904E 971E868A4FC45CE862117259753B81E582BD86FE8CC096C5991399D54ECB4F1A 89E356DE584A58CA5EFB5FEB602A6094606261D0621262D06539000000000000 8A 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 9B41666668B06D777070754C76867D7582A587F9958B968E8C9D51F152BE5916 54B35BB35D16616869826DAF788D84CB88578A7293A79AB86D6C99A886D957A3 67FF86CE920E5283568754045ED362E164B9683C68386BBB737278BA7A6B899A 89D28D6B8F0390ED95A3969497695B665CB3697D984D984E639B7B206A2B0000 6A7F68B69C0D6F5F5272559D607062EC6D3B6E076ED1845B89108F444E149C39 53F6691B6A3A9784682A515C7AC384B291DC938C565B9D286822830584317CA5 520882C574E64E7E4F8351A05BD2520A52D852E75DFB559A582A59E65B8C5B98 5BDB5E725E7960A3611F616361BE63DB656267D1685368FA6B3E6B536C576F22 6F976F4574B0751876E3770B7AFF7BA17C217DE97F367FF0809D8266839E89B3 8ACC8CAB908494519593959195A2966597D3992882184E38542B5CB85DCC73A9 764C773C5CA97FEB8D0B96C19811985498584F014F0E5371559C566857FA5947 5B095BC45C905E0C5E7E5FCC63EE673A65D765E2671F68CB68C4000000000000 8B 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6A5F5E306BC56C176C7D757F79485B637A007D005FBD898F8A188CB48D778ECC 8F1D98E29A0E9B3C4E80507D510059935B9C622F628064EC6B3A72A075917947 7FA987FB8ABC8B7063AC83CA97A05409540355AB68546A588A70782767759ECD 53745BA2811A865090064E184E454EC74F1153CA54385BAE5F13602565510000 673D6C426C726CE3707874037A767AAE7B087D1A7CFE7D6665E7725B53BB5C45 5DE862D262E063196E20865A8A318DDD92F86F0179A69B5A4EA84EAB4EAC4F9B 4FA050D151477AF6517151F653545321537F53EB55AC58835CE15F375F4A602F 6050606D631F65596A4B6CC172C272ED77EF80F881058208854E90F793E197FF 99579A5A4EF051DD5C2D6681696D5C4066F26975738968507C8150C552E45747 5DFE932665A46B236B3D7434798179BD7B4B7DCA82B983CC887F895F8B398FD1 91D1541F92804E5D503653E5533A72D7739677E982E68EAF99C699C899D25177 611A865E55B07A7A50765BD3904796854E326ADB91E75C515C48000000000000 8C 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 63987A9F6C9397748F617AAA718A96887C8268177E706851936C52F2541B85AB 8A137FA48ECD90E15366888879414FC250BE521151445553572D73EA578B5951 5F625F8460756176616761A963B2643A656C666F68426E1375667A3D7CFB7D4C 7D997E4B7F6B830E834A86CD8A088A638B668EFD981A9D8F82B88FCE9BE80000 5287621F64836FC09699684150916B206C7A6F547A747D5088408A2367084EF6 503950265065517C5238526355A7570F58055ACC5EFA61B261F862F36372691C 6A29727D72AC732E7814786F7D79770C80A9898B8B198CE28ED290639375967A 98559A139E785143539F53B35E7B5F266E1B6E90738473FE7D4382378A008AFA 96504E4E500B53E4547C56FA59D15B645DF15EAB5F276238654567AF6E5672D0 7CCA88B480A180E183F0864E8A878DE8923796C798679F134E944E924F0D5348 5449543E5A2F5F8C5FA1609F68A76A8E745A78818A9E8AA48B7791904E5E9BC9 4EA44F7C4FAF501950165149516C529F52B952FE539A53E35411000000000000 8D 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 540E5589575157A2597D5B545B5D5B8F5DE55DE75DF75E785E835E9A5EB75F18 6052614C629762D863A7653B6602664366F4676D6821689769CB6C5F6D2A6D69 6E2F6E9D75327687786C7A3F7CE07D057D187D5E7DB18015800380AF80B18154 818F822A8352884C88618B1B8CA28CFC90CA91759271783F92FC95A4964D0000 980599999AD89D3B525B52AB53F7540858D562F76FE08C6A8F5F9EB9514B523B 544A56FD7A4091779D609ED273446F09817075115FFD60DA9AA872DB8FBC6B64 98034ECA56F0576458BE5A5A606861C7660F6606683968B16DF775D57D3A826E 9B424E9B4F5053C955065D6F5DE65DEE67FB6C99747378028A50939688DF5750 5EA7632B50B550AC518D670054C9585E59BB5BB05F69624D63A1683D6B736E08 707D91C7728078157826796D658E7D3083DC88C18F09969B5264572867507F6A 8CA151B45742962A583A698A80B454B25D0E57FC78959DFA4F5C524A548B643E 6628671467F57A847B567D22932F685C9BAD7B395319518A5237000000000000 8E 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5BDF62F664AE64E6672D6BBA85A996D176909BD6634C93069BAB76BF66524E09 509853C25C7160E864926563685F71E673CA75237B977E8286958B838CDB9178 991065AC66AB6B8B4ED54ED44F3A4F7F523A53F853F255E356DB58EB59CB59C9 59FF5B505C4D5E025E2B5FD7601D6307652F5B5C65AF65BD65E8679D6B620000 6B7B6C0F7345794979C17CF87D197D2B80A2810281F389968A5E8A698A668A8C 8AEE8CC78CDC96CC98FC6B6F4E8B4F3C4F8D51505B575BFA6148630166426B21 6ECB6CBB723E74BD75D478C1793A800C803381EA84948F9E6C509E7F5F0F8B58 9D2B7AFA8EF85B8D96EB4E0353F157F759315AC95BA460896E7F6F0675BE8CEA 5B9F85007BE0507267F4829D5C61854A7E1E820E51995C0463688D66659C716E 793E7D1780058B1D8ECA906E86C790AA501F52FA5C3A6753707C7235914C91C8 932B82E55BC25F3160F94E3B53D65B88624B67316B8A72E973E07A2E816B8DA3 91529996511253D7546A5BFF63886A397DAC970056DA53CE5468000000000000 8F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5B975C315DDE4FEE610162FE6D3279C079CB7D427E4D7FD281ED821F84908846 89728B908E748F2F9031914B916C96C6919C4EC04F4F514553415F93620E67D4 6C416E0B73637E2691CD928353D459195BBF6DD1795D7E2E7C9B587E719F51FA 88538FF04FCA5CFB662577AC7AE3821C99FF51C65FAA65EC696F6B896DF30000 6E966F6476FE7D145DE190759187980651E6521D6240669166D96E1A5EB67DD2 7F7266F885AF85F78AF852A953D959735E8F5F90605592E4966450B7511F52DD 5320534753EC54E8554655315617596859BE5A3C5BB55C065C0F5C115C1A5E84 5E8A5EE05F70627F628462DB638C63776607660C662D6676677E68A26A1F6A35 6CBC6D886E096E58713C7126716775C77701785D7901796579F07AE07B117CA7 7D39809683D6848B8549885D88F38A1F8A3C8A548A738C618CDE91A49266937E 9418969C97984E0A4E084E1E4E575197527057CE583458CC5B225E3860C564FE 676167566D4472B675737A6384B88B7291B89320563157F498FE000000000000 90 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 62ED690D6B9671ED7E548077827289E698DF87558FB15C3B4F384FE14FB55507 5A205BDD5BE95FC3614E632F65B0664B68EE699B6D786DF1753375B9771F795E 79E67D3381E382AF85AA89AA8A3A8EAB8F9B903291DD97074EBA4EC152035875 58EC5C0B751A5C3D814E8A0A8FC59663976D7B258ACF9808916256F353A80000 9017543957825E2563A86C34708A77617C8B7FE088709042915493109318968F 745E9AC45D075D69657067A28DA896DB636E6749691983C5981796C088FE6F84 647A5BF84E16702C755D662F51C4523652E259D35F8160276210653F6574661F 667468F268166B636E057272751F76DB7CBE805658F088FD897F8AA08A938ACB 901D91929752975965897A0E810696BB5E2D60DC621A65A56614679077F37A4D 7C4D7E3E810A8CAC8D648DE18E5F78A9520762D963A5644262988A2D7A837BC0 8AAC96EA7D76820C87494ED95148534353605BA35C025C165DDD6226624764B0 681368346CC96D456D1767D36F5C714E717D65CB7A7F7BAD7DDA000000000000 91 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7E4A7FA8817A821B823985A68A6E8CCE8DF59078907792AD929195839BAE524D 55846F387136516879857E5581B37CCE564C58515CA863AA66FE66FD695A72D9 758F758E790E795679DF7C977D207D4486078A34963B90619F2050E7527553CC 53E2500955AA58EE594F723D5B8B5C64531D60E360F3635C6383633F63BB0000 64CD65E966F95DE369CD69FD6F1571E54E8975E976F87A937CDF7DCF7D9C8061 83498358846C84BC85FB88C58D709001906D9397971C9A1250CF5897618E81D3 85358D0890204FC3507452475373606F6349675F6E2C8DB3901F4FD75C5E8CCA 65CF7D9A53528896517663C35B585B6B5C0A640D6751905C4ED6591A592A6C70 8A51553E581559A560F0625367C182356955964099C49A284F5358065BFE8010 5CB15E2F5F856020614B623466FF6CF06EDE80CE817F82D4888B8CB89000902E 968A9EDB9BDB4EE353F059277B2C918D984C9DF96EDD7027535355445B856258 629E62D36CA26FEF74228A1794386FC18AFE833851E786F853EA000000000000 92 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 53E94F4690548FB0596A81315DFD7AEA8FBF68DA8C3772F89C486A3D8AB04E39 53585606576662C563A265E66B4E6DE16E5B70AD77ED7AEF7BAA7DBB803D80C6 86CB8A95935B56E358C75F3E65AD66966A806BB575378AC7502477E557305F1B 6065667A6C6075F47A1A7F6E81F48718904599B37BC9755C7AF97B5184C40000 901079E97A9283365AE177404E2D4EF25B995FE062BD663C67F16CE8866B8877 8A3B914E92F399D06A177026732A82E784578CAF4E01514651CB558B5BF55E16 5E335E815F145F355F6B5FB461F2631166A2671D6F6E7252753A773A80748139 817887768ABF8ADC8D858DF3929A957798029CE552C5635776F467156C8873CD 8CC393AE96736D25589C690E69CC8FFD939A75DB901A585A680263B469FB4F43 6F2C67D88FBB85267DB49354693F6F70576A58F75B2C7D2C722A540A91E39DB4 4EAD4F4E505C507552438C9E544858245B9A5E1D5E955EAD5EF75F1F608C62B5 633A63D068AF6C407887798E7A0B7DE082478A028AE68E449013000000000000 93 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 90B8912D91D89F0E6CE5645864E265756EF476847B1B906993D16EBA54F25FB9 64A48F4D8FED92445178586B59295C555E976DFB7E8F751C8CBC8EE2985B70B9 4F1D6BBF6FB1753096FB514E54105835585759AC5C605F926597675C6E21767B 83DF8CED901490FD934D7825783A52AA5EA6571F597460125012515A51AC0000 51CD520055105854585859575B955CF65D8B60BC6295642D6771684368BC68DF 76D76DD86E6F6D9B706F71C85F5375D879777B497B547B527CD67D7152308463 856985E48A0E8B048C468E0F9003900F94199676982D9A3095D850CD52D5540C 58025C0E61A7649E6D1E77B37AE580F48404905392855CE09D07533F5F975FB3 6D9C7279776379BF7BE46BD272EC8AAD68036A6151F87A8169345C4A9CF682EB 5BC59149701E56785C6F60C765666C8C8C5A90419813545166C7920D594890A3 51854E4D51EA85998B0E7058637A934B696299B47E047577535769608EDF96E3 6C5D4E8C5C3C5F108FE953028CD1808986795EFF65E54E735165000000000000 94 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 59825C3F97EE4EFB598A5FCD8A8D6FE179B079625BE78471732B71B15E745FF5 637B649A71C37C984E435EFC4E4B57DC56A260A96FC37D0D80FD813381BF8FB2 899786A45DF4628A64AD898767776CE26D3E743678345A467F7582AD99AC4FF3 5EC362DD63926557676F76C3724C80CC80BA8F29914D500D57F95A9268850000 6973716472FD8CB758F28CE0966A9019877F79E477E784294F2F5265535A62CD 67CF6CCA767D7B947C95823685848FEB66DD6F2072067E1B83AB99C19EA651FD 7BB178727BB880877B486AE85E61808C75517560516B92626E8C767A91979AEA 4F107F70629C7B4F95A59CE9567A585986E496BC4F345224534A53CD53DB5E06 642C6591677F6C3E6C4E724872AF73ED75547E41822C85E98CA97BC491C67169 981298EF633D6669756A76E478D0854386EE532A5351542659835E875F7C60B2 6249627962AB65906BD46CCC75B276AE789179D87DCB7F7780A588AB8AB98CBB 907F975E98DB6A0B7C3850995C3E5FAE67876BD8743577097F8E000000000000 95 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 9F3B67CA7A175339758B9AED5F66819D83F180985F3C5FC575627B46903C6867 59EB5A9B7D10767E8B2C4FF55F6A6A196C376F0274E2796888688A558C795EDF 63CF75C579D282D7932892F2849C86ED9C2D54C15F6C658C6D5C70158CA78CD3 983B654F74F64E0D4ED857E0592B5A665BCC51A85E035E9C6016627665770000 65A7666E6D6E72367B268150819A82998B5C8CA08CE68D74961C96444FAE64AB 6B66821E8461856A90E85C01695398A8847A85574F0F526F5FA95E45670D798F 8179890789866DF55F1762556CB84ECF72699B925206543B567458B361A4626E 711A596E7C897CDE7D1B96F06587805E4E194F75517558405E635E735F0A67C4 4E26853D9589965B7C73980150FB58C1765678A7522577A585117B86504F5909 72477BC77DE88FBA8FD4904D4FBF52C95A295F0197AD4FDD821792EA57036355 6B69752B88DC8F147A4252DF58936155620A66AE6BCD7C3F83E950234FF85305 5446583159495B9D5CF05CEF5D295E9662B16367653E65B9670B000000000000 96 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6CD56CE170F978327E2B80DE82B3840C84EC870289128A2A8C4A90A692D298FD 9CF39D6C4E4F4EA1508D5256574A59A85E3D5FD85FD9623F66B4671B67D068D2 51927D2180AA81A88B008C8C8CBF927E96325420982C531750D5535C58A864B2 6734726777667A4691E652C36CA16B8658005E4C5954672C7FFB51E176C60000 646978E89B549EBB57CB59B96627679A6BCE54E969D95E55819C67959BAA67FE 9C52685D4EA64FE353C862B9672B6CAB8FC44FAD7E6D9EBF4E0761626E806F2B 85135473672A9B455DF37B955CAC5BC6871C6E4A84D17A14810859997C8D6C11 772052D959227121725F77DB97279D61690B5A7F5A1851A5540D547D660E76DF 8FF792989CF459EA725D6EC5514D68C97DBF7DEC97629EBA64786A2183025984 5B5F6BDB731B76F27DB280178499513267289ED976EE676252FF99055C24623B 7C7E8CB0554F60B67D0B958053014E5F51B6591C723A803691CE5F2577E25384 5F797D0485AC8A338E8D975667F385AE9453610961086CB9765200000000FF5E 97 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8AED8F38552F4F51512A52C753CB5BA55E7D60A0618263D6670967DA6E676D8C 733673377531795088D58A98904A909190F596C4878D59154E884F594E0E8A89 8F3F981050AD5E7C59965BB95EB863DA63FA64C166DC694A69D86D0B6EB67194 75287AAF7F8A8000844984C989818B218E0A9065967D990A617E62916B320000 6C836D747FCC7FFC6DC07F8587BA88F8676583B1983C96F76D1B7D61843D916A 4E7153755D506B046FEB85CD862D89A75229540F5C65674E68A87406748375E2 88CF88E191CC96E296785F8B73877ACB844E63A0756552896D416E9C74097559 786B7C9296867ADC9F8D4FB6616E65C5865C4E864EAE50DA4E2151CC5BEE6599 68816DBC731F764277AD7A1C7CE7826F8AD2907C91CF96759818529B7DD1502B 539867976DCB71D0743381E88F2A96A39C579E9F746058416D997D2F985E4EE4 4F364F8B51B752B15DBA601C73B2793C82D3923496B796F6970A9E979F6266A6 6B74521752A370C888C25EC9604B61906F2371497C3E7DF4806F000000000000 98 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 84EE9023932C54429B6F6AD370898CC28DEF973252B45A415ECA5F046717697C 69946D6A6F0F726272FC7BED8001807E874B90CE516D9E937984808B93328AD6 502D548C8A716B6A8CC4810760D167A09DF24E994E989C108A6B85C185686900 6E7E789781550000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000005F0C 4E104E154E2A4E314E364E3C4E3F4E424E564E584E824E858C6B4E8A82125F0D 4E8E4E9E4E9F4EA04EA24EB04EB34EB64ECE4ECD4EC44EC64EC24ED74EDE4EED 4EDF4EF74F094F5A4F304F5B4F5D4F574F474F764F884F8F4F984F7B4F694F70 4F914F6F4F864F9651184FD44FDF4FCE4FD84FDB4FD14FDA4FD04FE44FE5501A 50285014502A502550054F1C4FF650215029502C4FFE4FEF5011500650435047 6703505550505048505A5056506C50785080509A508550B450B2000000000000 99 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 50C950CA50B350C250D650DE50E550ED50E350EE50F950F55109510151025116 51155114511A5121513A5137513C513B513F51405152514C515451627AF85169 516A516E5180518256D8518C5189518F519151935195519651A451A651A251A9 51AA51AB51B351B151B251B051B551BD51C551C951DB51E0865551E951ED0000 51F051F551FE5204520B5214520E5227522A522E52335239524F5244524B524C 525E5254526A527452695273527F527D528D529452925271528852918FA88FA7 52AC52AD52BC52B552C152CD52D752DE52E352E698ED52E052F352F552F852F9 530653087538530D5310530F5315531A5323532F533153335338534053465345 4E175349534D51D6535E5369536E5918537B53775382539653A053A653A553AE 53B053B653C37C1296D953DF66FC71EE53EE53E853ED53FA5401543D5440542C 542D543C542E54365429541D544E548F5475548E545F5471547754705492547B 5480547654845490548654C754A254B854A554AC54C454C854A8000000000000 9A 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 54AB54C254A454BE54BC54D854E554E6550F551454FD54EE54ED54FA54E25539 55405563554C552E555C55455556555755385533555D5599558054AF558A559F 557B557E5598559E55AE557C558355A9558755A855DA55C555DF55C455DC55E4 55D4561455F7561655FE55FD561B55F9564E565071DF56345636563256380000 566B5664562F566C566A56865680568A56A05694568F56A556AE56B656B456C2 56BC56C156C356C056C856CE56D156D356D756EE56F9570056FF570457095708 570B570D57135718571655C7571C572657375738574E573B5740574F576957C0 57885761577F5789579357A057B357A457AA57B057C357C657D457D257D3580A 57D657E3580B5819581D587258215862584B58706BC05852583D5879588558B9 589F58AB58BA58DE58BB58B858AE58C558D358D158D758D958D858E558DC58E4 58DF58EF58FA58F958FB58FC58FD5902590A5910591B68A65925592C592D5932 5938593E7AD259555950594E595A5958596259605967596C5969000000000000 9B 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 59785981599D4F5E4FAB59A359B259C659E859DC598D59D959DA5A255A1F5A11 5A1C5A095A1A5A405A6C5A495A355A365A625A6A5A9A5ABC5ABE5ACB5AC25ABD 5AE35AD75AE65AE95AD65AFA5AFB5B0C5B0B5B165B325AD05B2A5B365B3E5B43 5B455B405B515B555B5A5B5B5B655B695B705B735B755B7865885B7A5B800000 5B835BA65BB85BC35BC75BC95BD45BD05BE45BE65BE25BDE5BE55BEB5BF05BF6 5BF35C055C075C085C0D5C135C205C225C285C385C395C415C465C4E5C535C50 5C4F5B715C6C5C6E4E625C765C795C8C5C915C94599B5CAB5CBB5CB65CBC5CB7 5CC55CBE5CC75CD95CE95CFD5CFA5CED5D8C5CEA5D0B5D155D175D5C5D1F5D1B 5D115D145D225D1A5D195D185D4C5D525D4E5D4B5D6C5D735D765D875D845D82 5DA25D9D5DAC5DAE5DBD5D905DB75DBC5DC95DCD5DD35DD25DD65DDB5DEB5DF2 5DF55E0B5E1A5E195E115E1B5E365E375E445E435E405E4E5E575E545E5F5E62 5E645E475E755E765E7A9EBC5E7F5EA05EC15EC25EC85ED05ECF000000000000 9C 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5ED65EE35EDD5EDA5EDB5EE25EE15EE85EE95EEC5EF15EF35EF05EF45EF85EFE 5F035F095F5D5F5C5F0B5F115F165F295F2D5F385F415F485F4C5F4E5F2F5F51 5F565F575F595F615F6D5F735F775F835F825F7F5F8A5F885F915F875F9E5F99 5F985FA05FA85FAD5FBC5FD65FFB5FE45FF85FF15FDD60B35FFF602160600000 601960106029600E6031601B6015602B6026600F603A605A6041606A6077605F 604A6046604D6063604360646042606C606B60596081608D60E76083609A6084 609B60966097609260A7608B60E160B860E060D360B45FF060BD60C660B560D8 614D6115610660F660F7610060F460FA6103612160FB60F1610D610E6147613E 61286127614A613F613C612C6134613D614261446173617761586159615A616B 6174616F61656171615F615D6153617561996196618761AC6194619A618A6191 61AB61AE61CC61CA61C961F761C861C361C661BA61CB7F7961CD61E661E361F6 61FA61F461FF61FD61FC61FE620062086209620D620C6214621B000000000000 9D 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 621E6221622A622E6230623262336241624E625E6263625B62606268627C6282 6289627E62926293629662D46283629462D762D162BB62CF62FF62C664D462C8 62DC62CC62CA62C262C7629B62C9630C62EE62F163276302630862EF62F56350 633E634D641C634F6396638E638063AB637663A3638F6389639F63B5636B0000 636963BE63E963C063C663E363C963D263F663C4641664346406641364266436 651D64176428640F6467646F6476644E652A6495649364A564A9648864BC64DA 64D264C564C764BB64D864C264F164E7820964E064E162AC64E364EF652C64F6 64F464F264FA650064FD6518651C650565246523652B65346535653765366538 754B654865566555654D6558655E655D65726578658265838B8A659B659F65AB 65B765C365C665C165C465CC65D265DB65D965E065E165F16772660A660365FB 6773663566366634661C664F664466496641665E665D666466676668665F6662 667066836688668E668966846698669D66C166B966C966BE66BC000000000000 9E 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 66C466B866D666DA66E0663F66E666E966F066F566F7670F6716671E67266727 9738672E673F67366741673867376746675E67606759676367646789677067A9 677C676A678C678B67A667A1678567B767EF67B467EC67B367E967B867E467DE 67DD67E267EE67B967CE67C667E76A9C681E684668296840684D6832684E0000 68B3682B685968636877687F689F688F68AD6894689D689B68836AAE68B96874 68B568A068BA690F688D687E690168CA690868D86922692668E1690C68CD68D4 68E768D569366912690468D768E3692568F968E068EF6928692A691A69236921 68C669796977695C6978696B6954697E696E69396974693D695969306961695E 695D6981696A69B269AE69D069BF69C169D369BE69CE5BE869CA69DD69BB69C3 69A76A2E699169A0699C699569B469DE69E86A026A1B69FF6B0A69F969F269E7 6A0569B16A1E69ED6A1469EB6A0A6A126AC16A236A136A446A0C6A726A366A78 6A476A626A596A666A486A386A226A906A8D6AA06A846AA26AA3000000000000 9F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6A9786176ABB6AC36AC26AB86AB36AAC6ADE6AD16ADF6AAA6ADA6AEA6AFB6B05 86166AFA6B126B169B316B1F6B386B3776DC6B3998EE6B476B436B496B506B59 6B546B5B6B5F6B616B786B796B7F6B806B846B836B8D6B986B956B9E6BA46BAA 6BAB6BAF6BB26BB16BB36BB76BBC6BC66BCB6BD36BDF6BEC6BEB6BF36BEF0000 9EBE6C086C136C146C1B6C246C236C5E6C556C626C6A6C826C8D6C9A6C816C9B 6C7E6C686C736C926C906CC46CF16CD36CBD6CD76CC56CDD6CAE6CB16CBE6CBA 6CDB6CEF6CD96CEA6D1F884D6D366D2B6D3D6D386D196D356D336D126D0C6D63 6D936D646D5A6D796D596D8E6D956FE46D856DF96E156E0A6DB56DC76DE66DB8 6DC66DEC6DDE6DCC6DE86DD26DC56DFA6DD96DE46DD56DEA6DEE6E2D6E6E6E2E 6E196E726E5F6E3E6E236E6B6E2B6E766E4D6E1F6E436E3A6E4E6E246EFF6E1D 6E386E826EAA6E986EC96EB76ED36EBD6EAF6EC46EB26ED46ED56E8F6EA56EC2 6E9F6F416F11704C6EEC6EF86EFE6F3F6EF26F316EEF6F326ECC000000000000 E0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6F3E6F136EF76F866F7A6F786F816F806F6F6F5B6FF36F6D6F826F7C6F586F8E 6F916FC26F666FB36FA36FA16FA46FB96FC66FAA6FDF6FD56FEC6FD46FD86FF1 6FEE6FDB7009700B6FFA70117001700F6FFE701B701A6F74701D7018701F7030 703E7032705170637099709270AF70F170AC70B870B370AE70DF70CB70DD0000 70D9710970FD711C711971657155718871667162714C7156716C718F71FB7184 719571A871AC71D771B971BE71D271C971D471CE71E071EC71E771F571FC71F9 71FF720D7210721B7228722D722C72307232723B723C723F72407246724B7258 7274727E7282728172877292729672A272A772B972B272C372C672C472CE72D2 72E272E072E172F972F7500F7317730A731C7316731D7334732F73297325733E 734E734F9ED87357736A7368737073787375737B737A73C873B373CE73BB73C0 73E573EE73DE74A27405746F742573F87432743A7455743F745F74597441745C 746974707463746A7476747E748B749E74A774CA74CF74D473F1000000000000 E1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 74E074E374E774E974EE74F274F074F174F874F7750475037505750C750E750D 75157513751E7526752C753C7544754D754A7549755B7546755A756975647567 756B756D75787576758675877574758A758975827594759A759D75A575A375C2 75B375C375B575BD75B875BC75B175CD75CA75D275D975E375DE75FE75FF0000 75FC760175F075FA75F275F3760B760D7609761F762776207621762276247634 7630763B764776487646765C76587661766276687669766A7667766C76707672 76767678767C768076837688768B768E769676937699769A76B076B476B876B9 76BA76C276CD76D676D276DE76E176E576E776EA862F76FB7708770777047729 7724771E77257726771B773777387747775A7768776B775B7765777F777E7779 778E778B779177A0779E77B077B677B977BF77BC77BD77BB77C777CD77D777DA 77DC77E377EE77FC780C781279267820792A7845788E78747886787C789A788C 78A378B578AA78AF78D178C678CB78D478BE78BC78C578CA78EC000000000000 E2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 78E778DA78FD78F47907791279117919792C792B794079607957795F795A7955 7953797A797F798A799D79A79F4B79AA79AE79B379B979BA79C979D579E779EC 79E179E37A087A0D7A187A197A207A1F79807A317A3B7A3E7A377A437A577A49 7A617A627A699F9D7A707A797A7D7A887A977A957A987A967AA97AC87AB00000 7AB67AC57AC47ABF90837AC77ACA7ACD7ACF7AD57AD37AD97ADA7ADD7AE17AE2 7AE67AED7AF07B027B0F7B0A7B067B337B187B197B1E7B357B287B367B507B7A 7B047B4D7B0B7B4C7B457B757B657B747B677B707B717B6C7B6E7B9D7B987B9F 7B8D7B9C7B9A7B8B7B927B8F7B5D7B997BCB7BC17BCC7BCF7BB47BC67BDD7BE9 7C117C147BE67BE57C607C007C077C137BF37BF77C177C0D7BF67C237C277C2A 7C1F7C377C2B7C3D7C4C7C437C547C4F7C407C507C587C5F7C647C567C657C6C 7C757C837C907CA47CAD7CA27CAB7CA17CA87CB37CB27CB17CAE7CB97CBD7CC0 7CC57CC27CD87CD27CDC7CE29B3B7CEF7CF27CF47CF67CFA7D06000000000000 E3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7D027D1C7D157D0A7D457D4B7D2E7D327D3F7D357D467D737D567D4E7D727D68 7D6E7D4F7D637D937D897D5B7D8F7D7D7D9B7DBA7DAE7DA37DB57DC77DBD7DAB 7E3D7DA27DAF7DDC7DB87D9F7DB07DD87DDD7DE47DDE7DFB7DF27DE17E057E0A 7E237E217E127E317E1F7E097E0B7E227E467E667E3B7E357E397E437E370000 7E327E3A7E677E5D7E567E5E7E597E5A7E797E6A7E697E7C7E7B7E837DD57E7D 8FAE7E7F7E887E897E8C7E927E907E937E947E967E8E7E9B7E9C7F387F3A7F45 7F4C7F4D7F4E7F507F517F557F547F587F5F7F607F687F697F677F787F827F86 7F837F887F877F8C7F947F9E7F9D7F9A7FA37FAF7FB27FB97FAE7FB67FB88B71 7FC57FC67FCA7FD57FD47FE17FE67FE97FF37FF998DC80068004800B80128018 8019801C80218028803F803B804A804680528058805A805F8062806880738072 807080768079807D807F808480868085809B8093809A80AD519080AC80DB80E5 80D980DD80C480DA80D6810980EF80F1811B81298123812F814B000000000000 E4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 968B8146813E8153815180FC8171816E81658166817481838188818A81808182 81A0819581A481A3815F819381A981B081B581BE81B881BD81C081C281BA81C9 81CD81D181D981D881C881DA81DF81E081E781FA81FB81FE8201820282058207 820A820D821082168229822B82388233824082598258825D825A825F82640000 82628268826A826B822E827182778278827E828D829282AB829F82BB82AC82E1 82E382DF82D282F482F382FA8393830382FB82F982DE830682DC830982D98335 83348316833283318340833983508345832F832B831783188385839A83AA839F 83A283968323838E8387838A837C83B58373837583A0838983A883F4841383EB 83CE83FD840383D8840B83C183F7840783E083F2840D8422842083BD84388506 83FB846D842A843C855A84848477846B84AD846E848284698446842C846F8479 843584CA846284B984BF849F84D984CD84BB84DA84D084C184C684D684A18521 84FF84F485178518852C851F8515851484FC8540856385588548000000000000 E5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 85418602854B8555858085A485888591858A85A8856D8594859B85EA8587859C 8577857E859085C985BA85CF85B985D085D585DD85E585DC85F9860A8613860B 85FE85FA86068622861A8630863F864D4E558654865F86678671869386A386A9 86AA868B868C86B686AF86C486C686B086C9882386AB86D486DE86E986EC0000 86DF86DB86EF8712870687088700870386FB87118709870D86F9870A8734873F 8737873B87258729871A8760875F8778874C874E877487578768876E87598753 8763876A880587A2879F878287AF87CB87BD87C087D096D687AB87C487B387C7 87C687BB87EF87F287E0880F880D87FE87F687F7880E87D28811881688158822 88218831883688398827883B8844884288528859885E8862886B8881887E889E 8875887D88B5887288828897889288AE889988A2888D88A488B088BF88B188C3 88C488D488D888D988DD88F9890288FC88F488E888F28904890C890A89138943 891E8925892A892B89418944893B89368938894C891D8960895E000000000000 E6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 89668964896D896A896F89748977897E89838988898A8993899889A189A989A6 89AC89AF89B289BA89BD89BF89C089DA89DC89DD89E789F489F88A038A168A10 8A0C8A1B8A1D8A258A368A418A5B8A528A468A488A7C8A6D8A6C8A628A858A82 8A848AA88AA18A918AA58AA68A9A8AA38AC48ACD8AC28ADA8AEB8AF38AE70000 8AE48AF18B148AE08AE28AF78ADE8ADB8B0C8B078B1A8AE18B168B108B178B20 8B3397AB8B268B2B8B3E8B288B418B4C8B4F8B4E8B498B568B5B8B5A8B6B8B5F 8B6C8B6F8B748B7D8B808B8C8B8E8B928B938B968B998B9A8C3A8C418C3F8C48 8C4C8C4E8C508C558C628C6C8C788C7A8C828C898C858C8A8C8D8C8E8C948C7C 8C98621D8CAD8CAA8CBD8CB28CB38CAE8CB68CC88CC18CE48CE38CDA8CFD8CFA 8CFB8D048D058D0A8D078D0F8D0D8D109F4E8D138CCD8D148D168D678D6D8D71 8D738D818D998DC28DBE8DBA8DCF8DDA8DD68DCC8DDB8DCB8DEA8DEB8DDF8DE3 8DFC8E088E098DFF8E1D8E1E8E108E1F8E428E358E308E348E4A000000000000 E7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8E478E498E4C8E508E488E598E648E608E2A8E638E558E768E728E7C8E818E87 8E858E848E8B8E8A8E938E918E948E998EAA8EA18EAC8EB08EC68EB18EBE8EC5 8EC88ECB8EDB8EE38EFC8EFB8EEB8EFE8F0A8F058F158F128F198F138F1C8F1F 8F1B8F0C8F268F338F3B8F398F458F428F3E8F4C8F498F468F4E8F578F5C0000 8F628F638F648F9C8F9F8FA38FAD8FAF8FB78FDA8FE58FE28FEA8FEF90878FF4 90058FF98FFA901190159021900D901E9016900B90279036903590398FF8904F 905090519052900E9049903E90569058905E9068906F907696A890729082907D 90819080908A9089908F90A890AF90B190B590E290E4624890DB910291129119 91329130914A9156915891639165916991739172918B9189918291A291AB91AF 91AA91B591B491BA91C091C191C991CB91D091D691DF91E191DB91FC91F591F6 921E91FF9214922C92159211925E925792459249926492489295923F924B9250 929C92969293929B925A92CF92B992B792E9930F92FA9344932E000000000000 E8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 93199322931A9323933A9335933B935C9360937C936E935693B093AC93AD9394 93B993D693D793E893E593D893C393DD93D093C893E4941A9414941394039407 94109436942B94359421943A944194529444945B94609462945E946A92299470 94759477947D945A947C947E9481947F95829587958A95949596959895990000 95A095A895A795AD95BC95BB95B995BE95CA6FF695C395CD95CC95D595D495D6 95DC95E195E595E296219628962E962F9642964C964F964B9677965C965E965D 965F96669672966C968D96989695969796AA96A796B196B296B096B496B696B8 96B996CE96CB96C996CD894D96DC970D96D596F99704970697089713970E9711 970F971697199724972A97309739973D973E97449746974897429749975C9760 97649766976852D2976B977197799785977C9781977A9786978B978F9790979C 97A897A697A397B397B497C397C697C897CB97DC97ED9F4F97F27ADF97F697F5 980F980C9838982498219837983D9846984F984B986B986F9870000000000000 E9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 98719874987398AA98AF98B198B698C498C398C698E998EB9903990999129914 99189921991D991E99249920992C992E993D993E9942994999459950994B9951 9952994C99559997999899A599AD99AE99BC99DF99DB99DD99D899D199ED99EE 99F199F299FB99F89A019A0F9A0599E29A199A2B9A379A459A429A409A430000 9A3E9A559A4D9A5B9A579A5F9A629A659A649A699A6B9A6A9AAD9AB09ABC9AC0 9ACF9AD19AD39AD49ADE9ADF9AE29AE39AE69AEF9AEB9AEE9AF49AF19AF79AFB 9B069B189B1A9B1F9B229B239B259B279B289B299B2A9B2E9B2F9B329B449B43 9B4F9B4D9B4E9B519B589B749B939B839B919B969B979B9F9BA09BA89BB49BC0 9BCA9BB99BC69BCF9BD19BD29BE39BE29BE49BD49BE19C3A9BF29BF19BF09C15 9C149C099C139C0C9C069C089C129C0A9C049C2E9C1B9C259C249C219C309C47 9C329C469C3E9C5A9C609C679C769C789CE79CEC9CF09D099D089CEB9D039D06 9D2A9D269DAF9D239D1F9D449D159D129D419D3F9D3E9D469D48000000000000 EA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 9D5D9D5E9D649D519D509D599D729D899D879DAB9D6F9D7A9D9A9DA49DA99DB2 9DC49DC19DBB9DB89DBA9DC69DCF9DC29DD99DD39DF89DE69DED9DEF9DFD9E1A 9E1B9E1E9E759E799E7D9E819E889E8B9E8C9E929E959E919E9D9EA59EA99EB8 9EAA9EAD97619ECC9ECE9ECF9ED09ED49EDC9EDE9EDD9EE09EE59EE89EEF0000 9EF49EF69EF79EF99EFB9EFC9EFD9F079F0876B79F159F219F2C9F3E9F4A9F52 9F549F639F5F9F609F619F669F679F6C9F6A9F779F729F769F959F9C9FA0582F 69C79059746451DC719900000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 R 8160 301C FF5E 8161 2016 2225 817C 2212 FF0D 8191 00A2 FFE0 8192 00A3 FFE1 81CA 00AC FFE2 tcl8.4.20/library/encoding/cp1251.enc0000644003604700454610000000210311737050674015547 0ustar dgp771div# Encoding file: cp1251, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 04020403201A0453201E20262020202120AC203004092039040A040C040B040F 045220182019201C201D202220132014009821220459203A045A045C045B045F 00A0040E045E040800A4049000A600A7040100A9040400AB00AC00AD00AE0407 00B000B104060456049100B500B600B704512116045400BB0458040504550457 0410041104120413041404150416041704180419041A041B041C041D041E041F 0420042104220423042404250426042704280429042A042B042C042D042E042F 0430043104320433043404350436043704380439043A043B043C043D043E043F 0440044104420443044404450446044704480449044A044B044C044D044E044F tcl8.4.20/library/encoding/iso2022-kr.enc0000644003604700454610000000016311737050674016352 0ustar dgp771div# Encoding file: iso2022-kr, escape-driven E name iso2022-kr init \x1b$)C final {} iso8859-1 \x0f ksc5601 \x0e tcl8.4.20/library/encoding/cp737.enc0000644003604700454610000000210211737050674015476 0ustar dgp771div# Encoding file: cp737, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 039103920393039403950396039703980399039A039B039C039D039E039F03A0 03A103A303A403A503A603A703A803A903B103B203B303B403B503B603B703B8 03B903BA03BB03BC03BD03BE03BF03C003C103C303C203C403C503C603C703C8 259125922593250225242561256225562555256325512557255D255C255B2510 25142534252C251C2500253C255E255F255A25542569256625602550256C2567 2568256425652559255825522553256B256A2518250C25882584258C25902580 03C903AC03AD03AE03CA03AF03CC03CD03CB03CE038603880389038A038C038E 038F00B12265226403AA03AB00F7224800B0221900B7221A207F00B225A000A0 tcl8.4.20/library/encoding/euc-kr.enc0000644003604700454610000026733611737050674016047 0ustar dgp771div# Encoding file: euc-kr, multi-byte M 003F 0 90 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 0080008100820083008400850086008700880089008A008B008C008D008E008F 0090009100920093009400950096009700980099009A009B009C009D009E009F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 A1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000030003001300200B72025202600A8300300AD20152225FF3C223C20182019 201C201D3014301530083009300A300B300C300D300E300F3010301100B100D7 00F7226022642265221E223400B0203220332103212BFFE0FFE1FFE526422640 222022A52312220222072261225200A7203B2606260525CB25CF25CE25C725C6 25A125A025B325B225BD25BC219221902191219321943013226A226B221A223D 221D2235222B222C2208220B2286228722822283222A222922272228FFE20000 A2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000021D221D42200220300B4FF5E02C702D802DD02DA02D900B802DB00A100BF 02D0222E2211220F00A42109203025C125C025B725B626642660266126652667 2663229925C825A325D025D1259225A425A525A825A725A625A92668260F260E 261C261E00B62020202121952197219921962198266D2669266A266C327F321C 211633C7212233C233D821210000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 A3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FF01FF02FF03FF04FF05FF06FF07FF08FF09FF0AFF0BFF0CFF0DFF0EFF0F FF10FF11FF12FF13FF14FF15FF16FF17FF18FF19FF1AFF1BFF1CFF1DFF1EFF1F FF20FF21FF22FF23FF24FF25FF26FF27FF28FF29FF2AFF2BFF2CFF2DFF2EFF2F FF30FF31FF32FF33FF34FF35FF36FF37FF38FF39FF3AFF3BFFE6FF3DFF3EFF3F FF40FF41FF42FF43FF44FF45FF46FF47FF48FF49FF4AFF4BFF4CFF4DFF4EFF4F FF50FF51FF52FF53FF54FF55FF56FF57FF58FF59FF5AFF5BFF5CFF5DFFE30000 A4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000313131323133313431353136313731383139313A313B313C313D313E313F 3140314131423143314431453146314731483149314A314B314C314D314E314F 3150315131523153315431553156315731583159315A315B315C315D315E315F 3160316131623163316431653166316731683169316A316B316C316D316E316F 3170317131723173317431753176317731783179317A317B317C317D317E317F 3180318131823183318431853186318731883189318A318B318C318D318E0000 A5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000217021712172217321742175217621772178217900000000000000000000 2160216121622163216421652166216721682169000000000000000000000000 0000039103920393039403950396039703980399039A039B039C039D039E039F 03A003A103A303A403A503A603A703A803A90000000000000000000000000000 000003B103B203B303B403B503B603B703B803B903BA03BB03BC03BD03BE03BF 03C003C103C303C403C503C603C703C803C90000000000000000000000000000 A6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000025002502250C251025182514251C252C25242534253C25012503250F2513 251B251725232533252B253B254B2520252F25282537253F251D253025252538 254225122511251A251925162515250E250D251E251F25212522252625272529 252A252D252E25312532253525362539253A253D253E25402541254325442545 2546254725482549254A00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 A7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00003395339633972113339833C433A333A433A533A63399339A339B339C339D 339E339F33A033A133A233CA338D338E338F33CF3388338933C833A733A833B0 33B133B233B333B433B533B633B733B833B93380338133823383338433BA33BB 33BC33BD33BE33BF33903391339233933394212633C033C1338A338B338C33D6 33C533AD33AE33AF33DB33A933AA33AB33AC33DD33D033D333C333C933DC33C6 0000000000000000000000000000000000000000000000000000000000000000 A8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000C600D000AA0126000001320000013F014100D8015200BA00DE0166014A 00003260326132623263326432653266326732683269326A326B326C326D326E 326F3270327132723273327432753276327732783279327A327B24D024D124D2 24D324D424D524D624D724D824D924DA24DB24DC24DD24DE24DF24E024E124E2 24E324E424E524E624E724E824E9246024612462246324642465246624672468 2469246A246B246C246D246E00BD2153215400BC00BE215B215C215D215E0000 A9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000E6011100F001270131013301380140014200F8015300DF00FE0167014B 01493200320132023203320432053206320732083209320A320B320C320D320E 320F3210321132123213321432153216321732183219321A321B249C249D249E 249F24A024A124A224A324A424A524A624A724A824A924AA24AB24AC24AD24AE 24AF24B024B124B224B324B424B5247424752476247724782479247A247B247C 247D247E247F24802481248200B900B200B32074207F20812082208320840000 AA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000304130423043304430453046304730483049304A304B304C304D304E304F 3050305130523053305430553056305730583059305A305B305C305D305E305F 3060306130623063306430653066306730683069306A306B306C306D306E306F 3070307130723073307430753076307730783079307A307B307C307D307E307F 3080308130823083308430853086308730883089308A308B308C308D308E308F 3090309130923093000000000000000000000000000000000000000000000000 AB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000030A130A230A330A430A530A630A730A830A930AA30AB30AC30AD30AE30AF 30B030B130B230B330B430B530B630B730B830B930BA30BB30BC30BD30BE30BF 30C030C130C230C330C430C530C630C730C830C930CA30CB30CC30CD30CE30CF 30D030D130D230D330D430D530D630D730D830D930DA30DB30DC30DD30DE30DF 30E030E130E230E330E430E530E630E730E830E930EA30EB30EC30ED30EE30EF 30F030F130F230F330F430F530F6000000000000000000000000000000000000 AC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000004100411041204130414041504010416041704180419041A041B041C041D 041E041F0420042104220423042404250426042704280429042A042B042C042D 042E042F00000000000000000000000000000000000000000000000000000000 000004300431043204330434043504510436043704380439043A043B043C043D 043E043F0440044104420443044404450446044704480449044A044B044C044D 044E044F00000000000000000000000000000000000000000000000000000000 B0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000AC00AC01AC04AC07AC08AC09AC0AAC10AC11AC12AC13AC14AC15AC16AC17 AC19AC1AAC1BAC1CAC1DAC20AC24AC2CAC2DAC2FAC30AC31AC38AC39AC3CAC40 AC4BAC4DAC54AC58AC5CAC70AC71AC74AC77AC78AC7AAC80AC81AC83AC84AC85 AC86AC89AC8AAC8BAC8CAC90AC94AC9CAC9DAC9FACA0ACA1ACA8ACA9ACAAACAC ACAFACB0ACB8ACB9ACBBACBCACBDACC1ACC4ACC8ACCCACD5ACD7ACE0ACE1ACE4 ACE7ACE8ACEAACECACEFACF0ACF1ACF3ACF5ACF6ACFCACFDAD00AD04AD060000 B1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000AD0CAD0DAD0FAD11AD18AD1CAD20AD29AD2CAD2DAD34AD35AD38AD3CAD44 AD45AD47AD49AD50AD54AD58AD61AD63AD6CAD6DAD70AD73AD74AD75AD76AD7B AD7CAD7DAD7FAD81AD82AD88AD89AD8CAD90AD9CAD9DADA4ADB7ADC0ADC1ADC4 ADC8ADD0ADD1ADD3ADDCADE0ADE4ADF8ADF9ADFCADFFAE00AE01AE08AE09AE0B AE0DAE14AE30AE31AE34AE37AE38AE3AAE40AE41AE43AE45AE46AE4AAE4CAE4D AE4EAE50AE54AE56AE5CAE5DAE5FAE60AE61AE65AE68AE69AE6CAE70AE780000 B2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000AE79AE7BAE7CAE7DAE84AE85AE8CAEBCAEBDAEBEAEC0AEC4AECCAECDAECF AED0AED1AED8AED9AEDCAEE8AEEBAEEDAEF4AEF8AEFCAF07AF08AF0DAF10AF2C AF2DAF30AF32AF34AF3CAF3DAF3FAF41AF42AF43AF48AF49AF50AF5CAF5DAF64 AF65AF79AF80AF84AF88AF90AF91AF95AF9CAFB8AFB9AFBCAFC0AFC7AFC8AFC9 AFCBAFCDAFCEAFD4AFDCAFE8AFE9AFF0AFF1AFF4AFF8B000B001B004B00CB010 B014B01CB01DB028B044B045B048B04AB04CB04EB053B054B055B057B0590000 B3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000B05DB07CB07DB080B084B08CB08DB08FB091B098B099B09AB09CB09FB0A0 B0A1B0A2B0A8B0A9B0ABB0ACB0ADB0AEB0AFB0B1B0B3B0B4B0B5B0B8B0BCB0C4 B0C5B0C7B0C8B0C9B0D0B0D1B0D4B0D8B0E0B0E5B108B109B10BB10CB110B112 B113B118B119B11BB11CB11DB123B124B125B128B12CB134B135B137B138B139 B140B141B144B148B150B151B154B155B158B15CB160B178B179B17CB180B182 B188B189B18BB18DB192B193B194B198B19CB1A8B1CCB1D0B1D4B1DCB1DD0000 B4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000B1DFB1E8B1E9B1ECB1F0B1F9B1FBB1FDB204B205B208B20BB20CB214B215 B217B219B220B234B23CB258B25CB260B268B269B274B275B27CB284B285B289 B290B291B294B298B299B29AB2A0B2A1B2A3B2A5B2A6B2AAB2ACB2B0B2B4B2C8 B2C9B2CCB2D0B2D2B2D8B2D9B2DBB2DDB2E2B2E4B2E5B2E6B2E8B2EBB2ECB2ED B2EEB2EFB2F3B2F4B2F5B2F7B2F8B2F9B2FAB2FBB2FFB300B301B304B308B310 B311B313B314B315B31CB354B355B356B358B35BB35CB35EB35FB364B3650000 B5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000B367B369B36BB36EB370B371B374B378B380B381B383B384B385B38CB390 B394B3A0B3A1B3A8B3ACB3C4B3C5B3C8B3CBB3CCB3CEB3D0B3D4B3D5B3D7B3D9 B3DBB3DDB3E0B3E4B3E8B3FCB410B418B41CB420B428B429B42BB434B450B451 B454B458B460B461B463B465B46CB480B488B49DB4A4B4A8B4ACB4B5B4B7B4B9 B4C0B4C4B4C8B4D0B4D5B4DCB4DDB4E0B4E3B4E4B4E6B4ECB4EDB4EFB4F1B4F8 B514B515B518B51BB51CB524B525B527B528B529B52AB530B531B534B5380000 B6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000B540B541B543B544B545B54BB54CB54DB550B554B55CB55DB55FB560B561 B5A0B5A1B5A4B5A8B5AAB5ABB5B0B5B1B5B3B5B4B5B5B5BBB5BCB5BDB5C0B5C4 B5CCB5CDB5CFB5D0B5D1B5D8B5ECB610B611B614B618B625B62CB634B648B664 B668B69CB69DB6A0B6A4B6ABB6ACB6B1B6D4B6F0B6F4B6F8B700B701B705B728 B729B72CB72FB730B738B739B73BB744B748B74CB754B755B760B764B768B770 B771B773B775B77CB77DB780B784B78CB78DB78FB790B791B792B796B7970000 B7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000B798B799B79CB7A0B7A8B7A9B7ABB7ACB7ADB7B4B7B5B7B8B7C7B7C9B7EC B7EDB7F0B7F4B7FCB7FDB7FFB800B801B807B808B809B80CB810B818B819B81B B81DB824B825B828B82CB834B835B837B838B839B840B844B851B853B85CB85D B860B864B86CB86DB86FB871B878B87CB88DB8A8B8B0B8B4B8B8B8C0B8C1B8C3 B8C5B8CCB8D0B8D4B8DDB8DFB8E1B8E8B8E9B8ECB8F0B8F8B8F9B8FBB8FDB904 B918B920B93CB93DB940B944B94CB94FB951B958B959B95CB960B968B9690000 B8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000B96BB96DB974B975B978B97CB984B985B987B989B98AB98DB98EB9ACB9AD B9B0B9B4B9BCB9BDB9BFB9C1B9C8B9C9B9CCB9CEB9CFB9D0B9D1B9D2B9D8B9D9 B9DBB9DDB9DEB9E1B9E3B9E4B9E5B9E8B9ECB9F4B9F5B9F7B9F8B9F9B9FABA00 BA01BA08BA15BA38BA39BA3CBA40BA42BA48BA49BA4BBA4DBA4EBA53BA54BA55 BA58BA5CBA64BA65BA67BA68BA69BA70BA71BA74BA78BA83BA84BA85BA87BA8C BAA8BAA9BAABBAACBAB0BAB2BAB8BAB9BABBBABDBAC4BAC8BAD8BAD9BAFC0000 B9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000BB00BB04BB0DBB0FBB11BB18BB1CBB20BB29BB2BBB34BB35BB36BB38BB3B BB3CBB3DBB3EBB44BB45BB47BB49BB4DBB4FBB50BB54BB58BB61BB63BB6CBB88 BB8CBB90BBA4BBA8BBACBBB4BBB7BBC0BBC4BBC8BBD0BBD3BBF8BBF9BBFCBBFF BC00BC02BC08BC09BC0BBC0CBC0DBC0FBC11BC14BC15BC16BC17BC18BC1BBC1C BC1DBC1EBC1FBC24BC25BC27BC29BC2DBC30BC31BC34BC38BC40BC41BC43BC44 BC45BC49BC4CBC4DBC50BC5DBC84BC85BC88BC8BBC8CBC8EBC94BC95BC970000 BA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000BC99BC9ABCA0BCA1BCA4BCA7BCA8BCB0BCB1BCB3BCB4BCB5BCBCBCBDBCC0 BCC4BCCDBCCFBCD0BCD1BCD5BCD8BCDCBCF4BCF5BCF6BCF8BCFCBD04BD05BD07 BD09BD10BD14BD24BD2CBD40BD48BD49BD4CBD50BD58BD59BD64BD68BD80BD81 BD84BD87BD88BD89BD8ABD90BD91BD93BD95BD99BD9ABD9CBDA4BDB0BDB8BDD4 BDD5BDD8BDDCBDE9BDF0BDF4BDF8BE00BE03BE05BE0CBE0DBE10BE14BE1CBE1D BE1FBE44BE45BE48BE4CBE4EBE54BE55BE57BE59BE5ABE5BBE60BE61BE640000 BB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000BE68BE6ABE70BE71BE73BE74BE75BE7BBE7CBE7DBE80BE84BE8CBE8DBE8F BE90BE91BE98BE99BEA8BED0BED1BED4BED7BED8BEE0BEE3BEE4BEE5BEECBF01 BF08BF09BF18BF19BF1BBF1CBF1DBF40BF41BF44BF48BF50BF51BF55BF94BFB0 BFC5BFCCBFCDBFD0BFD4BFDCBFDFBFE1C03CC051C058C05CC060C068C069C090 C091C094C098C0A0C0A1C0A3C0A5C0ACC0ADC0AFC0B0C0B3C0B4C0B5C0B6C0BC C0BDC0BFC0C0C0C1C0C5C0C8C0C9C0CCC0D0C0D8C0D9C0DBC0DCC0DDC0E40000 BC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000C0E5C0E8C0ECC0F4C0F5C0F7C0F9C100C104C108C110C115C11CC11DC11E C11FC120C123C124C126C127C12CC12DC12FC130C131C136C138C139C13CC140 C148C149C14BC14CC14DC154C155C158C15CC164C165C167C168C169C170C174 C178C185C18CC18DC18EC190C194C196C19CC19DC19FC1A1C1A5C1A8C1A9C1AC C1B0C1BDC1C4C1C8C1CCC1D4C1D7C1D8C1E0C1E4C1E8C1F0C1F1C1F3C1FCC1FD C200C204C20CC20DC20FC211C218C219C21CC21FC220C228C229C22BC22D0000 BD 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000C22FC231C232C234C248C250C251C254C258C260C265C26CC26DC270C274 C27CC27DC27FC281C288C289C290C298C29BC29DC2A4C2A5C2A8C2ACC2ADC2B4 C2B5C2B7C2B9C2DCC2DDC2E0C2E3C2E4C2EBC2ECC2EDC2EFC2F1C2F6C2F8C2F9 C2FBC2FCC300C308C309C30CC30DC313C314C315C318C31CC324C325C328C329 C345C368C369C36CC370C372C378C379C37CC37DC384C388C38CC3C0C3D8C3D9 C3DCC3DFC3E0C3E2C3E8C3E9C3EDC3F4C3F5C3F8C408C410C424C42CC4300000 BE 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000C434C43CC43DC448C464C465C468C46CC474C475C479C480C494C49CC4B8 C4BCC4E9C4F0C4F1C4F4C4F8C4FAC4FFC500C501C50CC510C514C51CC528C529 C52CC530C538C539C53BC53DC544C545C548C549C54AC54CC54DC54EC553C554 C555C557C558C559C55DC55EC560C561C564C568C570C571C573C574C575C57C C57DC580C584C587C58CC58DC58FC591C595C597C598C59CC5A0C5A9C5B4C5B5 C5B8C5B9C5BBC5BCC5BDC5BEC5C4C5C5C5C6C5C7C5C8C5C9C5CAC5CCC5CE0000 BF 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000C5D0C5D1C5D4C5D8C5E0C5E1C5E3C5E5C5ECC5EDC5EEC5F0C5F4C5F6C5F7 C5FCC5FDC5FEC5FFC600C601C605C606C607C608C60CC610C618C619C61BC61C C624C625C628C62CC62DC62EC630C633C634C635C637C639C63BC640C641C644 C648C650C651C653C654C655C65CC65DC660C66CC66FC671C678C679C67CC680 C688C689C68BC68DC694C695C698C69CC6A4C6A5C6A7C6A9C6B0C6B1C6B4C6B8 C6B9C6BAC6C0C6C1C6C3C6C5C6CCC6CDC6D0C6D4C6DCC6DDC6E0C6E1C6E80000 C0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000C6E9C6ECC6F0C6F8C6F9C6FDC704C705C708C70CC714C715C717C719C720 C721C724C728C730C731C733C735C737C73CC73DC740C744C74AC74CC74DC74F C751C752C753C754C755C756C757C758C75CC760C768C76BC774C775C778C77C C77DC77EC783C784C785C787C788C789C78AC78EC790C791C794C796C797C798 C79AC7A0C7A1C7A3C7A4C7A5C7A6C7ACC7ADC7B0C7B4C7BCC7BDC7BFC7C0C7C1 C7C8C7C9C7CCC7CEC7D0C7D8C7DDC7E4C7E8C7ECC800C801C804C808C80A0000 C1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000C810C811C813C815C816C81CC81DC820C824C82CC82DC82FC831C838C83C C840C848C849C84CC84DC854C870C871C874C878C87AC880C881C883C885C886 C887C88BC88CC88DC894C89DC89FC8A1C8A8C8BCC8BDC8C4C8C8C8CCC8D4C8D5 C8D7C8D9C8E0C8E1C8E4C8F5C8FCC8FDC900C904C905C906C90CC90DC90FC911 C918C92CC934C950C951C954C958C960C961C963C96CC970C974C97CC988C989 C98CC990C998C999C99BC99DC9C0C9C1C9C4C9C7C9C8C9CAC9D0C9D1C9D30000 C2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000C9D5C9D6C9D9C9DAC9DCC9DDC9E0C9E2C9E4C9E7C9ECC9EDC9EFC9F0C9F1 C9F8C9F9C9FCCA00CA08CA09CA0BCA0CCA0DCA14CA18CA29CA4CCA4DCA50CA54 CA5CCA5DCA5FCA60CA61CA68CA7DCA84CA98CABCCABDCAC0CAC4CACCCACDCACF CAD1CAD3CAD8CAD9CAE0CAECCAF4CB08CB10CB14CB18CB20CB21CB41CB48CB49 CB4CCB50CB58CB59CB5DCB64CB78CB79CB9CCBB8CBD4CBE4CBE7CBE9CC0CCC0D CC10CC14CC1CCC1DCC21CC22CC27CC28CC29CC2CCC2ECC30CC38CC39CC3B0000 C3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000CC3CCC3DCC3ECC44CC45CC48CC4CCC54CC55CC57CC58CC59CC60CC64CC66 CC68CC70CC75CC98CC99CC9CCCA0CCA8CCA9CCABCCACCCADCCB4CCB5CCB8CCBC CCC4CCC5CCC7CCC9CCD0CCD4CCE4CCECCCF0CD01CD08CD09CD0CCD10CD18CD19 CD1BCD1DCD24CD28CD2CCD39CD5CCD60CD64CD6CCD6DCD6FCD71CD78CD88CD94 CD95CD98CD9CCDA4CDA5CDA7CDA9CDB0CDC4CDCCCDD0CDE8CDECCDF0CDF8CDF9 CDFBCDFDCE04CE08CE0CCE14CE19CE20CE21CE24CE28CE30CE31CE33CE350000 C4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000CE58CE59CE5CCE5FCE60CE61CE68CE69CE6BCE6DCE74CE75CE78CE7CCE84 CE85CE87CE89CE90CE91CE94CE98CEA0CEA1CEA3CEA4CEA5CEACCEADCEC1CEE4 CEE5CEE8CEEBCEECCEF4CEF5CEF7CEF8CEF9CF00CF01CF04CF08CF10CF11CF13 CF15CF1CCF20CF24CF2CCF2DCF2FCF30CF31CF38CF54CF55CF58CF5CCF64CF65 CF67CF69CF70CF71CF74CF78CF80CF85CF8CCFA1CFA8CFB0CFC4CFE0CFE1CFE4 CFE8CFF0CFF1CFF3CFF5CFFCD000D004D011D018D02DD034D035D038D03C0000 C5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D044D045D047D049D050D054D058D060D06CD06DD070D074D07CD07DD081 D0A4D0A5D0A8D0ACD0B4D0B5D0B7D0B9D0C0D0C1D0C4D0C8D0C9D0D0D0D1D0D3 D0D4D0D5D0DCD0DDD0E0D0E4D0ECD0EDD0EFD0F0D0F1D0F8D10DD130D131D134 D138D13AD140D141D143D144D145D14CD14DD150D154D15CD15DD15FD161D168 D16CD17CD184D188D1A0D1A1D1A4D1A8D1B0D1B1D1B3D1B5D1BAD1BCD1C0D1D8 D1F4D1F8D207D209D210D22CD22DD230D234D23CD23DD23FD241D248D25C0000 C6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D264D280D281D284D288D290D291D295D29CD2A0D2A4D2ACD2B1D2B8D2B9 D2BCD2BFD2C0D2C2D2C8D2C9D2CBD2D4D2D8D2DCD2E4D2E5D2F0D2F1D2F4D2F8 D300D301D303D305D30CD30DD30ED310D314D316D31CD31DD31FD320D321D325 D328D329D32CD330D338D339D33BD33CD33DD344D345D37CD37DD380D384D38C D38DD38FD390D391D398D399D39CD3A0D3A8D3A9D3ABD3ADD3B4D3B8D3BCD3C4 D3C5D3C8D3C9D3D0D3D8D3E1D3E3D3ECD3EDD3F0D3F4D3FCD3FDD3FFD4010000 C7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D408D41DD440D444D45CD460D464D46DD46FD478D479D47CD47FD480D482 D488D489D48BD48DD494D4A9D4CCD4D0D4D4D4DCD4DFD4E8D4ECD4F0D4F8D4FB D4FDD504D508D50CD514D515D517D53CD53DD540D544D54CD54DD54FD551D558 D559D55CD560D565D568D569D56BD56DD574D575D578D57CD584D585D587D588 D589D590D5A5D5C8D5C9D5CCD5D0D5D2D5D8D5D9D5DBD5DDD5E4D5E5D5E8D5EC D5F4D5F5D5F7D5F9D600D601D604D608D610D611D613D614D615D61CD6200000 C8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D624D62DD638D639D63CD640D645D648D649D64BD64DD651D654D655D658 D65CD667D669D670D671D674D683D685D68CD68DD690D694D69DD69FD6A1D6A8 D6ACD6B0D6B9D6BBD6C4D6C5D6C8D6CCD6D1D6D4D6D7D6D9D6E0D6E4D6E8D6F0 D6F5D6FCD6FDD700D704D711D718D719D71CD720D728D729D72BD72DD734D735 D738D73CD744D747D749D750D751D754D756D757D758D759D760D761D763D765 D769D76CD770D774D77CD77DD781D788D789D78CD790D798D799D79BD79D0000 CA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00004F3D4F73504750F952A053EF547554E556095AC15BB6668767B667B767EF 6B4C73C275C27A3C82DB8304885788888A368CC88DCF8EFB8FE699D5523B5374 5404606A61646BBC73CF811A89BA89D295A34F83520A58BE597859E65E725E79 61C763C0674667EC687F6F97764E770B78F57A087AFF7C21809D826E82718AEB 95934E6B559D66F76E3478A37AED845B8910874E97A852D8574E582A5D4C611F 61BE6221656267D16A446E1B751875B376E377B07D3A90AF945194529F950000 CB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000053235CAC753280DB92409598525B580859DC5CA15D175EB75F3A5F4A6177 6C5F757A75867CE07D737DB17F8C81548221859189418B1B92FC964D9C474ECB 4EF7500B51F1584F6137613E6168653969EA6F1175A5768676D67B8782A584CB F90093A7958B55805BA25751F9017CB37FB991B5502853BB5C455DE862D2636E 64DA64E76E2070AC795B8DDD8E1EF902907D924592F84E7E4EF650655DFE5EFA 61066957817186548E4793759A2B4E5E5091677068405109528D52926AA20000 CC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000077BC92109ED452AB602F8FF2504861A963ED64CA683C6A846FC0818889A1 96945805727D72AC75047D797E6D80A9898B8B7490639D5162896C7A6F547D50 7F3A8A23517C614A7B9D8B199257938C4EAC4FD3501E50BE510652C152CD537F 577058835E9A5F91617661AC64CE656C666F66BB66F468976D87708570F1749F 74A574CA75D9786C78EC7ADF7AF67D457D938015803F811B83968B668F159015 93E1980398389A5A9BE84FC25553583A59515B635C4660B86212684268B00000 CD 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000068E86EAA754C767878CE7A3D7CFB7E6B7E7C8A088AA18C3F968E9DC453E4 53E9544A547156FA59D15B645C3B5EAB62F765376545657266A067AF69C16CBD 75FC7690777E7A3F7F94800380A1818F82E682FD83F085C1883188B48AA5F903 8F9C932E96C798679AD89F1354ED659B66F2688F7A408C379D6056F057645D11 660668B168CD6EFE7428889E9BE46C68F9049AA84F9B516C5171529F5B545DE5 6050606D62F163A7653B73D97A7A86A38CA2978F4E325BE16208679C74DC0000 CE 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000079D183D38A878AB28DE8904E934B98465ED369E885FF90EDF90551A05B98 5BEC616368FA6B3E704C742F74D87BA17F5083C589C08CAB95DC9928522E605D 62EC90024F8A5149532158D95EE366E06D38709A72C273D67B5080F1945B5366 639B7F6B4E565080584A58DE602A612762D069D09B415B8F7D1880B18F5F4EA4 50D154AC55AC5B0C5DA05DE7652A654E68216A4B72E1768E77EF7D5E7FF981A0 854E86DF8F038F4E90CA99039A559BAB4E184E454E5D4EC74FF1517752FE0000 CF 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000534053E353E5548E5614577557A25BC75D875ED061FC62D8655167B867E9 69CB6B506BC66BEC6C426E9D707872D77396740377BF77E97A767D7F800981FC 8205820A82DF88628B338CFC8EC0901190B1926492B699D29A459CE99DD79F9C 570B5C4083CA97A097AB9EB4541B7A987FA488D98ECD90E158005C4863987A9F 5BAE5F137A797AAE828E8EAC5026523852F85377570862F363726B0A6DC37737 53A5735785688E7695D5673A6AC36F708A6D8ECC994BF90666776B788CB40000 D0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009B3CF90753EB572D594E63C669FB73EA78457ABA7AC57CFE8475898F8D73 903595A852FB574775477B6083CC921EF9086A58514B524B5287621F68D86975 969950C552A452E461C365A4683969FF747E7B4B82B983EB89B28B398FD19949 F9094ECA599764D266116A8E7434798179BD82A9887E887F895FF90A93264F0B 53CA602562716C727D1A7D664E98516277DC80AF4F014F0E5176518055DC5668 573B57FA57FC5914594759935BC45C905D0E5DF15E7E5FCC628065D765E30000 D1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000671E671F675E68CB68C46A5F6B3A6C236C7D6C826DC773987426742A7482 74A37578757F788178EF794179477948797A7B957D007DBA7F888006802D808C 8A188B4F8C488D779321932498E299519A0E9A0F9A659E927DCA4F76540962EE 685491D155AB513AF90BF90C5A1C61E6F90D62CF62FFF90EF90FF910F911F912 F91390A3F914F915F916F917F9188AFEF919F91AF91BF91C6696F91D7156F91E F91F96E3F920634F637A5357F921678F69606E73F9227537F923F924F9250000 D2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007D0DF926F927887256CA5A18F928F929F92AF92BF92C4E43F92D51675948 67F08010F92E59735E74649A79CA5FF5606C62C8637B5BE75BD752AAF92F5974 5F296012F930F931F9327459F933F934F935F936F937F93899D1F939F93AF93B F93CF93DF93EF93FF940F941F942F9436FC3F944F94581BF8FB260F1F946F947 8166F948F9495C3FF94AF94BF94CF94DF94EF94FF950F9515AE98A25677B7D10 F952F953F954F955F956F95780FDF958F9595C3C6CE5533F6EBA591A83360000 D3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00004E394EB64F4655AE571858C75F5665B765E66A806BB56E4D77ED7AEF7C1E 7DDE86CB88929132935B64BB6FBE737A75B890545556574D61BA64D466C76DE1 6E5B6F6D6FB975F0804381BD854189838AC78B5A931F6C9375537B548E0F905D 5510580258585E626207649E68E075767CD687B39EE84EE35788576E59275C0D 5CB15E365F85623464E173B381FA888B8CB8968A9EDB5B855FB760B350125200 52305716583558575C0E5C605CF65D8B5EA65F9260BC63116389641768430000 D4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000068F96AC26DD86E216ED46FE471FE76DC777979B17A3B840489A98CED8DF3 8E4890039014905390FD934D967697DC6BD27006725872A27368776379BF7BE4 7E9B8B8058A960C7656665FD66BE6C8C711E71C98C5A98134E6D7A814EDD51AC 51CD52D5540C61A76771685068DF6D1E6F7C75BC77B37AE580F484639285515C 6597675C679375D87AC78373F95A8C469017982D5C6F81C0829A9041906F920D 5F975D9D6A5971C8767B7B4985E48B0491279A30558761F6F95B76697F850000 D5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000863F87BA88F8908FF95C6D1B70D973DE7D61843DF95D916A99F1F95E4E82 53756B046B12703E721B862D9E1E524C8FA35D5064E5652C6B166FEB7C437E9C 85CD896489BD62C981D8881F5ECA67176D6A72FC7405746F878290DE4F865D0D 5FA0840A51B763A075654EAE5006516951C968816A117CAE7CB17CE7826F8AD2 8F1B91CF4FB6513752F554425EEC616E623E65C56ADA6FFE792A85DC882395AD 9A629A6A9E979ECE529B66C66B77701D792B8F6297426190620065236F230000 D6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000714974897DF4806F84EE8F269023934A51BD521752A36D0C70C888C25EC9 65826BAE6FC27C3E73754EE44F3656F9F95F5CBA5DBA601C73B27B2D7F9A7FCE 8046901E923496F6974898189F614F8B6FA779AE91B496B752DEF960648864C4 6AD36F5E7018721076E780018606865C8DEF8F0597329B6F9DFA9E75788C797F 7DA083C993049E7F9E938AD658DF5F046727702774CF7C60807E512170287262 78CA8CC28CDA8CF496F74E8650DA5BEE5ED6659971CE764277AD804A84FC0000 D7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000907C9B279F8D58D85A415C626A136DDA6F0F763B7D2F7E37851E893893E4 964B528965D267F369B46D416E9C700F7409746075597624786B8B2C985E516D 622E96784F96502B5D196DEA7DB88F2A5F8B61446817F961968652D2808B51DC 51CC695E7A1C7DBE83F196754FDA52295398540F550E5C6560A7674E68A86D6C 728172F874067483F96275E27C6C7F797FB8838988CF88E191CC91D096E29BC9 541D6F7E71D0749885FA8EAA96A39C579E9F67976DCB743381E89716782C0000 D8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007ACB7B207C926469746A75F278BC78E899AC9B549EBB5BDE5E556F20819C 83AB90884E07534D5A295DD25F4E6162633D666966FC6EFF6F2B7063779E842C 8513883B8F1399459C3B551C62B9672B6CAB8309896A977A4EA159845FD85FD9 671B7DB27F548292832B83BD8F1E909957CB59B95A925BD06627679A68856BCF 71647F758CB78CE390819B4581088C8A964C9A409EA55B5F6C13731B76F276DF 840C51AA8993514D519552C968C96C94770477207DBF7DEC97629EB56EC50000 D9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000851151A5540D547D660E669D69276E9F76BF7791831784C2879F91699298 9CF488824FAE519252DF59C65E3D61556478647966AE67D06A216BCD6BDB725F 72617441773877DB801782BC83058B008B288C8C67286C90726776EE77667A46 9DA96B7F6C92592267268499536F589359995EDF63CF663467736E3A732B7AD7 82D7932852D95DEB61AE61CB620A62C764AB65E069596B666BCB712173F7755D 7E46821E8302856A8AA38CBF97279D6158A89ED85011520E543B554F65870000 DA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006C767D0A7D0B805E868A958096EF52FF6C95726954735A9A5C3E5D4B5F4C 5FAE672A68B669636E3C6E4477097C737F8E85878B0E8FF797619EF45CB760B6 610D61AB654F65FB65FC6C116CEF739F73C97DE195945BC6871C8B10525D535A 62CD640F64B267346A386CCA73C0749E7B947C957E1B818A823685848FEB96F9 99C14F34534A53CD53DB62CC642C6500659169C36CEE6F5873ED7554762276E4 76FC78D078FB792C7D46822C87E08FD4981298EF52C362D464A56E246F510000 DB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000767C8DCB91B192629AEE9B435023508D574A59A85C285E475F77623F653E 65B965C16609678B699C6EC278C57D2180AA8180822B82B384A1868C8A2A8B17 90A696329F90500D4FF3F96357F95F9862DC6392676F6E43711976C380CC80DA 88F488F589198CE08F29914D966A4F2F4F705E1B67CF6822767D767E9B445E61 6A0A716971D4756AF9647E41854385E998DC4F107B4F7F7095A551E15E0668B5 6C3E6C4E6CDB72AF7BC483036CD5743A50FB528858C164D86A9774A776560000 DC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000078A7861795E29739F965535E5F018B8A8FA88FAF908A522577A59C499F08 4E19500251755C5B5E77661E663A67C468C570B3750175C579C97ADD8F279920 9A084FDD582158315BF6666E6B656D116E7A6F7D73E4752B83E988DC89138B5C 8F144F0F50D55310535C5B935FA9670D798F8179832F8514890789868F398F3B 99A59C12672C4E764FF859495C015CEF5CF0636768D270FD71A2742B7E2B84EC 8702902292D29CF34E0D4ED84FEF50855256526F5426549057E0592B5A660000 DD 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005B5A5B755BCC5E9CF9666276657765A76D6E6EA572367B267C3F7F368150 8151819A8240829983A98A038CA08CE68CFB8D748DBA90E891DC961C964499D9 9CE7531752065429567458B35954596E5FFF61A4626E66106C7E711A76C67C89 7CDE7D1B82AC8CC196F0F9674F5B5F175F7F62C25D29670B68DA787C7E439D6C 4E1550995315532A535159835A625E8760B2618A624962796590678769A76BD4 6BD66BD76BD86CB8F968743575FA7812789179D579D87C837DCB7FE180A50000 DE 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000813E81C283F2871A88E88AB98B6C8CBB9119975E98DB9F3B56AC5B2A5F6C 658C6AB36BAF6D5C6FF17015725D73AD8CA78CD3983B61916C3780589A014E4D 4E8B4E9B4ED54F3A4F3C4F7F4FDF50FF53F253F8550655E356DB58EB59625A11 5BEB5BFA5C045DF35E2B5F99601D6368659C65AF67F667FB68AD6B7B6C996CD7 6E23700973457802793E7940796079C17BE97D177D728086820D838E84D186C7 88DF8A508A5E8B1D8CDC8D668FAD90AA98FC99DF9E9D524AF9696714F96A0000 DF 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005098522A5C7165636C5573CA7523759D7B97849C917897304E7764926BBA 715E85A94E09F96B674968EE6E17829F8518886B63F76F81921298AF4E0A50B7 50CF511F554655AA56175B405C195CE05E385E8A5EA05EC260F368516A616E58 723D724072C076F879657BB17FD488F389F48A738C618CDE971C585E74BD8CFD 55C7F96C7A617D2282727272751F7525F96D7B19588558FB5DBC5E8F5EB65F90 60556292637F654D669166D966F8681668F27280745E7B6E7D6E7DD67F720000 E0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000080E5821285AF897F8A93901D92E49ECD9F205915596D5E2D60DC66146673 67906C506DC56F5F77F378A984C691CB932B4ED950CA514855845B0B5BA36247 657E65CB6E32717D74017444748774BF766C79AA7DDA7E557FA8817A81B38239 861A87EC8A758DE3907892919425994D9BAE53685C5169546CC46D296E2B820C 859B893B8A2D8AAA96EA9F67526166B96BB27E9687FE8D0D9583965D651D6D89 71EEF96E57CE59D35BAC602760FA6210661F665F732973F976DB77017B6C0000 E1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008056807281658AA091924E1652E26B726D177A057B397D30F96F8CB053EC 562F58515BB55C0F5C115DE2624063836414662D68B36CBC6D886EAF701F70A4 71D27526758F758E76197B117BE07C2B7D207D39852C856D86078A34900D9061 90B592B797F69A374FD75C6C675F6D917C9F7E8C8B168D16901F5B6B5DFD640D 84C0905C98E173875B8B609A677E6DDE8A1F8AA69001980C5237F9707051788E 9396887091D74FEE53D755FD56DA578258FD5AC25B885CAB5CC05E2561010000 E2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000620D624B6388641C653665786A396B8A6C346D196F3171E772E973787407 74B27626776179C07A577AEA7CB97D8F7DAC7E617F9E81298331849084DA85EA 88968AB08B908F3890429083916C929692B9968B96A796A896D6970098089996 9AD39B1A53D4587E59195B705BBF6DD16F5A719F742174B9808583FD5DE15F87 5FAA604265EC6812696F6A536B896D356DF373E376FE77AC7B4D7D148123821C 834084F485638A628AC49187931E980699B4620C88538FF092655D075D270000 E3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005D69745F819D87686FD562FE7FD2893689724E1E4E5850E752DD5347627F 66077E698805965E4F8D5319563659CB5AA45C385C4E5C4D5E025F11604365BD 662F664267BE67F4731C77E2793A7FC5849484CD89968A668A698AE18C558C7A 57F45BD45F0F606F62ED690D6B966E5C71847BD287558B588EFE98DF98FE4F38 4F814FE1547B5A205BB8613C65B0666871FC7533795E7D33814E81E3839885AA 85CE87038A0A8EAB8F9BF9718FC559315BA45BE660895BE95C0B5FC36C810000 E4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000F9726DF1700B751A82AF8AF64EC05341F97396D96C0F4E9E4FC45152555E 5A255CE86211725982BD83AA86FE88598A1D963F96C599139D099D5D580A5CB3 5DBD5E4460E1611563E16A026E2591029354984E9C109F775B895CB86309664F 6848773C96C1978D98549B9F65A18B018ECB95BC55355CA95DD65EB56697764C 83F495C758D362BC72CE9D284EF0592E600F663B6B8379E79D26539354C057C3 5D16611B66D66DAF788D827E969897445384627C63966DB27E0A814B984D0000 E5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006AFB7F4C9DAF9E1A4E5F503B51B6591C60F963F66930723A8036F97491CE 5F31F975F9767D0482E5846F84BB85E58E8DF9774F6FF978F97958E45B436059 63DA6518656D6698F97A694A6A236D0B7001716C75D2760D79B37A70F97B7F8A F97C8944F97D8B9391C0967DF97E990A57045FA165BC6F01760079A68A9E99AD 9B5A9F6C510461B662916A8D81C6504358305F6671098A008AFA5B7C86164FFA 513C56B4594463A96DF95DAA696D51864E884F59F97FF980F9815982F9820000 E6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000F9836B5F6C5DF98474B57916F9858207824583398F3F8F5DF9869918F987 F988F9894EA6F98A57DF5F796613F98BF98C75AB7E798B6FF98D90069A5B56A5 582759F85A1F5BB4F98E5EF6F98FF9906350633BF991693D6C876CBF6D8E6D93 6DF56F14F99270DF71367159F99371C371D5F994784F786FF9957B757DE3F996 7E2FF997884D8EDFF998F999F99A925BF99B9CF6F99CF99DF99E60856D85F99F 71B1F9A0F9A195B153ADF9A2F9A3F9A467D3F9A5708E71307430827682D20000 E7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000F9A695BB9AE59E7D66C4F9A771C18449F9A8F9A9584BF9AAF9AB5DB85F71 F9AC6620668E697969AE6C386CF36E366F416FDA701B702F715071DF7370F9AD 745BF9AE74D476C87A4E7E93F9AFF9B082F18A608FCEF9B19348F9B29719F9B3 F9B44E42502AF9B5520853E166F36C6D6FCA730A777F7A6282AE85DD8602F9B6 88D48A638B7D8C6BF9B792B3F9B8971398104E944F0D4FC950B25348543E5433 55DA586258BA59675A1B5BE4609FF9B961CA655665FF666468A76C5A6FB30000 E8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000070CF71AC73527B7D87088AA49C329F075C4B6C8373447389923A6EAB7465 761F7A697E15860A514058C564C174EE751576707FC1909596CD99546E2674E6 7AA97AAA81E586D987788A1B5A495B8C5B9B68A169006D6373A97413742C7897 7DE97FEB81188155839E8C4C962E981166F05F8065FA67896C6A738B502D5A03 6B6A77EE59165D6C5DCD7325754FF9BAF9BB50E551F9582F592D599659DA5BE5 F9BCF9BD5DA262D76416649364FEF9BE66DCF9BF6A48F9C071FF7464F9C10000 E9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007A887AAF7E477E5E80008170F9C287EF89818B209059F9C390809952617E 6B326D747E1F89258FB14FD150AD519752C757C758895BB95EB8614269956D8C 6E676EB6719474627528752C8073833884C98E0A939493DEF9C44E8E4F515076 512A53C853CB53F35B875BD35C24611A618265F4725B7397744076C279507991 79B97D067FBD828B85D5865E8FC2904790F591EA968596E896E952D65F6765ED 6631682F715C7A3690C1980A4E91F9C56A526B9E6F907189801882B885530000 EA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000904B969596F297FB851A9B314E90718A96C45143539F54E15713571257A3 5A9B5AC45BC36028613F63F46C856D396E726E907230733F745782D188818F45 9060F9C6966298589D1B67088D8A925E4F4D504950DE5371570D59D45A015C09 617066906E2D7232744B7DEF80C3840E8466853F875F885B89188B02905597CB 9B4F4E734F915112516AF9C7552F55A95B7A5BA55E7C5E7D5EBE60A060DF6108 610963C465386709F9C867D467DAF9C9696169626CB96D27F9CA6E38F9CB0000 EB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006FE173367337F9CC745C7531F9CD7652F9CEF9CF7DAD81FE843888D58A98 8ADB8AED8E308E42904A903E907A914991C9936EF9D0F9D15809F9D26BD38089 80B2F9D3F9D45141596B5C39F9D5F9D66F6473A780E48D07F9D79217958FF9D8 F9D9F9DAF9DB807F620E701C7D68878DF9DC57A0606961476BB78ABE928096B1 4E59541F6DEB852D967097F398EE63D66CE3909151DD61C981BA9DF94F9D501A 51005B9C610F61FF64EC69056BC5759177E37FA98264858F87FB88638ABC0000 EC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008B7091AB4E8C4EE54F0AF9DDF9DE593759E8F9DF5DF25F1B5F5B6021F9E0 F9E1F9E2F9E3723E73E5F9E4757075CDF9E579FBF9E6800C8033808482E18351 F9E7F9E88CBD8CB39087F9E9F9EA98F4990CF9EBF9EC703776CA7FCA7FCC7FFC 8B1A4EBA4EC152035370F9ED54BD56E059FB5BC55F155FCD6E6EF9EEF9EF7D6A 8335F9F086938A8DF9F1976D9777F9F2F9F34E004F5A4F7E58F965E56EA29038 93B099B94EFB58EC598A59D96041F9F4F9F57A14F9F6834F8CC3516553440000 ED 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000F9F7F9F8F9F94ECD52695B5582BF4ED4523A54A859C959FF5B505B575B5C 606361486ECB7099716E738674F775B578C17D2B800581EA8328851785C98AEE 8CC796CC4F5C52FA56BC65AB6628707C70B872357DBD828D914C96C09D725B71 68E76B986F7A76DE5C9166AB6F5B7BB47C2A883696DC4E084ED75320583458BB 58EF596C5C075E335E845F35638C66B267566A1F6AA36B0C6F3F7246F9FA7350 748B7AE07CA7817881DF81E7838A846C8523859485CF88DD8D1391AC95770000 EE 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000969C518D54C957285BB0624D6750683D68936E3D6ED3707D7E2188C18CA1 8F099F4B9F4E722D7B8F8ACD931A4F474F4E5132548059D05E9562B56775696E 6A176CAE6E1A72D9732A75BD7BB87D3582E783F9845785F78A5B8CAF8E879019 90B896CE9F5F52E3540A5AE15BC2645865756EF472C4F9FB76847A4D7B1B7C4D 7E3E7FDF837B8B2B8CCA8D648DE18E5F8FEA8FF9906993D14F434F7A50B35168 5178524D526A5861587C59605C085C555EDB609B623068136BBF6C086FB10000 EF 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000714E742075307538755176727B4C7B8B7BAD7BC67E8F8A6E8F3E8F49923F 92939322942B96FB985A986B991E5207622A62986D5976647ACA7BC07D765360 5CBE5E976F3870B97C9897119B8E9EDE63A5647A87764E014E954EAD505C5075 544859C35B9A5E405EAD5EF75F8160C5633A653F657465CC6676667867FE6968 6A896B636C406DC06DE86E1F6E5E701E70A1738E73FD753A775B7887798E7A0B 7A7D7CBE7D8E82478A028AEA8C9E912D914A91D8926692CC9320970697560000 F0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000975C98029F0E52365291557C58245E1D5F1F608C63D068AF6FDF796D7B2C 81CD85BA88FD8AF88E44918D9664969B973D984C9F4A4FCE514651CB52A95632 5F145F6B63AA64CD65E9664166FA66F9671D689D68D769FD6F156F6E716771E5 722A74AA773A7956795A79DF7A207A957C977CDF7D447E70808785FB86A48A54 8ABF8D998E819020906D91E3963B96D59CE565CF7C078DB393C35B585C0A5352 62D9731D50275B975F9E60B0616B68D56DD9742E7A2E7D427D9C7E31816B0000 F1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008E2A8E35937E94184F5057505DE65EA7632B7F6A4E3B4F4F4F8F505A59DD 80C4546A546855FE594F5B995DDE5EDA665D673167F1682A6CE86D326E4A6F8D 70B773E075877C4C7D027D2C7DA2821F86DB8A3B8A858D708E8A8F339031914E 9152944499D07AF97CA54FCA510151C657C85BEF5CFB66596A3D6D5A6E966FEC 710C756F7AE388229021907596CB99FF83014E2D4EF2884691CD537D6ADB696B 6C41847A589E618E66FE62EF70DD751175C77E5284B88B498D084E4B53EA0000 F2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000054AB573057405FD763016307646F652F65E8667A679D67B36B626C606C9A 6F2C77E57825794979577D1980A2810281F3829D82B787188A8CF9FC8D048DBE 907276F47A197A377E548077550755D45875632F64226649664B686D699B6B84 6D256EB173CD746874A1755B75B976E1771E778B79E67E097E1D81FB852F8897 8A3A8CD18EEB8FB0903293AD9663967397074F8453F159EA5AC95E19684E74C6 75BE79E97A9281A386ED8CEA8DCC8FED659F6715F9FD57F76F577DDD8F2F0000 F3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000093F696C65FB561F26F844E144F98501F53C955DF5D6F5DEE6B216B6478CB 7B9AF9FE8E498ECA906E6349643E77407A84932F947F9F6A64B06FAF71E674A8 74DA7AC47C127E827CB27E988B9A8D0A947D9910994C52395BDF64E6672D7D2E 50ED53C358796158615961FA65AC7AD98B928B9650095021527555315A3C5EE0 5F706134655E660C663666A269CD6EC46F32731676217A938139825983D684BC 50B557F05BC05BE85F6963A178267DB583DC852191C791F5518A67F57B560000 F4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008CAC51C459BB60BD8655501CF9FF52545C3A617D621A62D364F265A56ECC 7620810A8E60965F96BB4EDF5343559859295DDD64C56CC96DFA73947A7F821B 85A68CE48E10907791E795E1962197C651F854F255865FB964A46F887DB48F1F 8F4D943550C95C166CBE6DFB751B77BB7C3D7C648A798AC2581E59BE5E166377 7252758A776B8ADC8CBC8F125EF366746DF8807D83C18ACB97519BD6FA005243 66FF6D956EEF7DE08AE6902E905E9AD4521D527F54E86194628462DB68A20000 F5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006912695A6A3570927126785D7901790E79D27A0D8096827882D583498549 8C828D859162918B91AE4FC356D171ED77D7870089F85BF85FD6675190A853E2 585A5BF560A4618164607E3D80708525928364AE50AC5D146700589C62BD63A8 690E69786A1E6E6B76BA79CB82BB84298ACF8DA88FFD9112914B919C93109318 939A96DB9A369C0D4E11755C795D7AFA7B517BC97E2E84C48E598E748EF89010 6625693F744351FA672E9EDC51455FE06C9687F2885D887760B481B584030000 F6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008D0553D6543956345A365C31708A7FE0805A810681ED8DA391899A5F9DF2 50744EC453A060FB6E2C5C644F88502455E45CD95E5F606568946CBB6DC471BE 75D475F476617A1A7A497DC77DFB7F6E81F486A98F1C96C999B39F52524752C5 98ED89AA4E0367D26F064FB55BE267956C886D78741B782791DD937C87C479E4 7A315FEB4ED654A4553E58AE59A560F0625362D6673669558235964099B199DD 502C53535544577CFA016258FA0264E2666B67DD6FC16FEF742274388A170000 F7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000094385451560657665F48619A6B4E705870AD7DBB8A95596A812B63A27708 803D8CAA5854642D69BB5B955E116E6FFA038569514C53F0592A6020614B6B86 6C706CF07B1E80CE82D48DC690B098B1FA0464C76FA464916504514E5410571F 8A0E615F6876FA0575DB7B527D71901A580669CC817F892A9000983950785957 59AC6295900F9B2A615D727995D657615A465DF4628A64AD64FA67776CE26D3E 722C743678347F7782AD8DDB981752245742677F724874E38CA98FA692110000 F8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000962A516B53ED634C4F695504609665576C9B6D7F724C72FD7A1789878C9D 5F6D6F8E70F981A8610E4FBF504F624172477BC77DE87FE9904D97AD9A198CB6 576A5E7367B0840D8A5554205B165E635EE25F0A658380BA853D9589965B4F48 5305530D530F548654FA57035E036016629B62B16355FA066CE16D6675B17832 80DE812F82DE846184B2888D8912900B92EA98FD9B915E4566B466DD70117206 FA074FF5527D5F6A615367536A196F0274E2796888688C7998C798C49A430000 F9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000054C17A1F69538AF78C4A98A899AE5F7C62AB75B276AE88AB907F96425339 5F3C5FC56CCC73CC7562758B7B4682FE999D4E4F903C4E0B4F5553A6590F5EC8 66306CB37455837787668CC09050971E9C1558D15B7886508B149DB45BD26068 608D65F16C576F226FA3701A7F557FF095919592965097D352728F4451FD542B 54B85563558A6ABB6DB57DD88266929C96779E79540854C876D286E495A495D4 965C4EA24F0959EE5AE65DF760526297676D68416C866E2F7F38809B822A0000 FA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FA08FA0998054EA5505554B35793595A5B695BB361C869776D77702387F9 89E38A728AE7908299ED9AB852BE683850165E78674F8347884C4EAB541156AE 73E6911597FF9909995799995653589F865B8A3161B26AF6737B8ED26B4796AA 9A57595572008D6B97694FD45CF45F2661F8665B6CEB70AB738473B973FE7729 774D7D437D627E2382378852FA0A8CE29249986F5B517A74884098015ACC4FE0 5354593E5CFD633E6D7972F98105810783A292CF98304EA851445211578B0000 FB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005F626CC26ECE7005705070AF719273E97469834A87A28861900890A293A3 99A8516E5F5760E0616766B385598E4A91AF978B4E4E4E92547C58D558FA597D 5CB55F2762366248660A66676BEB6D696DCF6E566EF86F946FE06FE9705D72D0 7425745A74E07693795C7CCA7E1E80E182A6846B84BF864E865F87748B778C6A 93AC9800986560D1621691775A5A660F6DF76E3E743F9B425FFD60DA7B0F54C4 5F186C5E6CD36D2A70D87D0586798A0C9D3B5316548C5B056A3A706B75750000 FC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000798D79BE82B183EF8A718B418CA89774FA0B64F4652B78BA78BB7A6B4E38 559A59505BA65E7B60A363DB6B61666568536E19716574B07D0890849A699C25 6D3B6ED1733E8C4195CA51F05E4C5FA8604D60F66130614C6643664469A56CC1 6E5F6EC96F62714C749C76877BC17C27835287579051968D9EC3532F56DE5EFB 5F8A6062609461F7666667036A9C6DEE6FAE7070736A7E6A81BE833486D48AA8 8CC4528373725B966A6B940454EE56865B5D6548658566C9689F6D8D6DC60000 FD 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000723B80B491759A4D4FAF5019539A540E543C558955C55E3F5F8C673D7166 73DD900552DB52F3586458CE7104718F71FB85B08A13668885A855A76684714A 8431534955996BC15F595FBD63EE668971478AF18F1D9EBE4F11643A70CB7566 866760648B4E9DF8514751F653086D3680F89ED166156B23709875D554035C79 7D078A166B206B3D6B46543860706D3D7FD5820850D651DE559C566B56CD59EC 5B095E0C619961986231665E66E6719971B971BA72A779A77A007FB28A700000 tcl8.4.20/library/encoding/cp860.enc0000644003604700454610000000210211737050674015473 0ustar dgp771div# Encoding file: cp860, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 00C700FC00E900E200E300E000C100E700EA00CA00E800CD00D400EC00C300C2 00C900C000C800F400F500F200DA00F900CC00D500DC00A200A300D920A700D3 00E100ED00F300FA00F100D100AA00BA00BF00D200AC00BD00BC00A100AB00BB 259125922593250225242561256225562555256325512557255D255C255B2510 25142534252C251C2500253C255E255F255A25542569256625602550256C2567 2568256425652559255825522553256B256A2518250C25882584258C25902580 03B100DF039303C003A303C300B503C403A6039803A903B4221E03C603B52229 226100B1226522642320232100F7224800B0221900B7221A207F00B225A000A0 tcl8.4.20/library/encoding/macRomania.enc0000644003604700454610000000210711737050674016707 0ustar dgp771div# Encoding file: macRomania, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 00C400C500C700C900D100D600DC00E100E000E200E400E300E500E700E900E8 00EA00EB00ED00EC00EE00EF00F100F300F200F400F600F500FA00F900FB00FC 202000B000A200A300A7202200B600DF00AE00A9212200B400A822600102015E 221E00B12264226500A500B522022211220F03C0222B00AA00BA21260103015F 00BF00A100AC221A01922248220600AB00BB202600A000C000C300D501520153 20132014201C201D2018201900F725CA00FF0178204400A42039203A01620163 202100B7201A201E203000C200CA00C100CB00C800CD00CE00CF00CC00D300D4 F8FF00D200DA00DB00D9013102C602DC00AF02D802D902DA00B802DD02DB02C7 tcl8.4.20/library/encoding/macGreek.enc0000644003604700454610000000210511737050674016354 0ustar dgp771div# Encoding file: macGreek, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 00C400B900B200C900B300D600DC038500E000E200E4038400A800E700E900E8 00EA00EB00A3212200EE00EF202200BD203000F400F600A600AD00F900FB00FC 2020039303940398039B039E03A000DF00AE00A903A303AA00A7226000B000B7 039100B12264226500A503920395039603970399039A039C03A603AB03A803A9 03AC039D00AC039F03A1224803A400AB00BB202600A003A503A7038603880153 20132015201C201D2018201900F70389038A038C038E03AD03AE03AF03CC038F 03CD03B103B203C803B403B503C603B303B703B903BE03BA03BB03BC03BD03BF 03C003CE03C103C303C403B803C903C203C703C503B603CA03CB039003B0F8A0 tcl8.4.20/library/encoding/cp1256.enc0000644003604700454610000000210311737050674015554 0ustar dgp771div# Encoding file: cp1256, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 20AC067E201A0192201E20262020202102C62030067920390152068606980688 06AF20182019201C201D20222013201406A921220691203A0153200C200D06BA 00A0060C00A200A300A400A500A600A700A800A906BE00AB00AC00AD00AE00AF 00B000B100B200B300B400B500B600B700B800B9061B00BB00BC00BD00BE061F 06C1062106220623062406250626062706280629062A062B062C062D062E062F 063006310632063306340635063600D7063706380639063A0640064106420643 00E0064400E2064506460647064800E700E800E900EA00EB0649064A00EE00EF 064B064C064D064E00F4064F065000F7065100F9065200FB00FC200E200F06D2 tcl8.4.20/library/encoding/gb2312.enc0000644003604700454610000024710611737050674015552 0ustar dgp771div# Encoding file: euc-cn, multi-byte M 003F 0 82 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 0080008100820083008400850086008700880089008A008B008C008D008E008F 0090009100920093009400950096009700980099009A009B009C009D009E009F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 A1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000030003001300230FB02C902C700A8300330052015FF5E2225202620182019 201C201D3014301530083009300A300B300C300D300E300F3016301730103011 00B100D700F72236222722282211220F222A222922082237221A22A522252220 23122299222B222E2261224C2248223D221D2260226E226F22642265221E2235 22342642264000B0203220332103FF0400A4FFE0FFE1203000A7211626062605 25CB25CF25CE25C725C625A125A025B325B2203B219221902191219330130000 A2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000024882489248A248B248C248D248E248F2490249124922493249424952496 249724982499249A249B247424752476247724782479247A247B247C247D247E 247F248024812482248324842485248624872460246124622463246424652466 2467246824690000000032203221322232233224322532263227322832290000 00002160216121622163216421652166216721682169216A216B000000000000 A3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FF01FF02FF03FFE5FF05FF06FF07FF08FF09FF0AFF0BFF0CFF0DFF0EFF0F FF10FF11FF12FF13FF14FF15FF16FF17FF18FF19FF1AFF1BFF1CFF1DFF1EFF1F FF20FF21FF22FF23FF24FF25FF26FF27FF28FF29FF2AFF2BFF2CFF2DFF2EFF2F FF30FF31FF32FF33FF34FF35FF36FF37FF38FF39FF3AFF3BFF3CFF3DFF3EFF3F FF40FF41FF42FF43FF44FF45FF46FF47FF48FF49FF4AFF4BFF4CFF4DFF4EFF4F FF50FF51FF52FF53FF54FF55FF56FF57FF58FF59FF5AFF5BFF5CFF5DFFE30000 A4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000304130423043304430453046304730483049304A304B304C304D304E304F 3050305130523053305430553056305730583059305A305B305C305D305E305F 3060306130623063306430653066306730683069306A306B306C306D306E306F 3070307130723073307430753076307730783079307A307B307C307D307E307F 3080308130823083308430853086308730883089308A308B308C308D308E308F 3090309130923093000000000000000000000000000000000000000000000000 A5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000030A130A230A330A430A530A630A730A830A930AA30AB30AC30AD30AE30AF 30B030B130B230B330B430B530B630B730B830B930BA30BB30BC30BD30BE30BF 30C030C130C230C330C430C530C630C730C830C930CA30CB30CC30CD30CE30CF 30D030D130D230D330D430D530D630D730D830D930DA30DB30DC30DD30DE30DF 30E030E130E230E330E430E530E630E730E830E930EA30EB30EC30ED30EE30EF 30F030F130F230F330F430F530F6000000000000000000000000000000000000 A6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000039103920393039403950396039703980399039A039B039C039D039E039F 03A003A103A303A403A503A603A703A803A90000000000000000000000000000 000003B103B203B303B403B503B603B703B803B903BA03BB03BC03BD03BE03BF 03C003C103C303C403C503C603C703C803C90000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 A7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000004100411041204130414041504010416041704180419041A041B041C041D 041E041F0420042104220423042404250426042704280429042A042B042C042D 042E042F00000000000000000000000000000000000000000000000000000000 000004300431043204330434043504510436043704380439043A043B043C043D 043E043F0440044104420443044404450446044704480449044A044B044C044D 044E044F00000000000000000000000000000000000000000000000000000000 A8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000010100E101CE00E0011300E9011B00E8012B00ED01D000EC014D00F301D2 00F2016B00FA01D400F901D601D801DA01DC00FC00EA00000000000000000000 0000000000000000000031053106310731083109310A310B310C310D310E310F 3110311131123113311431153116311731183119311A311B311C311D311E311F 3120312131223123312431253126312731283129000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 A9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000002500250125022503250425052506250725082509250A250B 250C250D250E250F2510251125122513251425152516251725182519251A251B 251C251D251E251F2520252125222523252425252526252725282529252A252B 252C252D252E252F2530253125322533253425352536253725382539253A253B 253C253D253E253F2540254125422543254425452546254725482549254A254B 0000000000000000000000000000000000000000000000000000000000000000 B0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000554A963F57C3632854CE550954C07691764C853C77EE827E788D72319698 978D6C285B894FFA630966975CB880FA684880AE660276CE51F9655671AC7FF1 888450B2596561CA6FB382AD634C625253ED54277B06516B75A45DF462D48DCB 9776628A8019575D97387F627238767D67CF767E64464F708D2562DC7A176591 73ED642C6273822C9881677F7248626E62CC4F3474E3534A529E7ECA90A65E2E 6886699C81807ED168D278C5868C9551508D8C2482DE80DE5305891252650000 B1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000858496F94FDD582199715B9D62B162A566B48C799C8D7206676F789160B2 535153178F8880CC8D1D94A1500D72C8590760EB711988AB595482EF672C7B28 5D297EF7752D6CF58E668FF8903C9F3B6BD491197B145F7C78A784D6853D6BD5 6BD96BD65E015E8775F995ED655D5F0A5FC58F9F58C181C2907F965B97AD8FB9 7F168D2C62414FBF53D8535E8FA88FA98FAB904D68075F6A819888689CD6618B 522B762A5F6C658C6FD26EE85BBE6448517551B067C44E1979C9997C70B30000 B2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000075C55E7673BB83E064AD62E894B56CE2535A52C3640F94C27B944F2F5E1B 82368116818A6E246CCA9A736355535C54FA886557E04E0D5E036B657C3F90E8 601664E6731C88C16750624D8D22776C8E2991C75F6983DC8521991053C28695 6B8B60ED60E8707F82CD82314ED36CA785CF64CD7CD969FD66F9834953957B56 4FA7518C6D4B5C428E6D63D253C9832C833667E578B4643D5BDF5C945DEE8BE7 62C667F48C7A640063BA8749998B8C177F2094F24EA7961098A4660C73160000 B3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000573A5C1D5E38957F507F80A05382655E7545553150218D856284949E671D 56326F6E5DE2543570928F66626F64A463A35F7B6F8890F481E38FB05C186668 5FF16C8996488D81886C649179F057CE6A59621054484E587A0B60E96F848BDA 627F901E9A8B79E4540375F4630153196C608FDF5F1B9A70803B9F7F4F885C3A 8D647FC565A570BD514551B2866B5D075BA062BD916C75748E0C7A2061017B79 4EC77EF877854E1181ED521D51FA6A7153A88E87950496CF6EC19664695A0000 B4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000784050A877D7641089E6590463E35DDD7A7F693D4F20823955984E3275AE 7A975E625E8A95EF521B5439708A6376952457826625693F918755076DF37EAF 882262337EF075B5832878C196CC8F9E614874F78BCD6B64523A8D506B21806A 847156F153064ECE4E1B51D17C97918B7C074FC38E7F7BE17A9C64675D1450AC 810676017CB96DEC7FE067515B585BF878CB64AE641363AA632B9519642D8FBE 7B5476296253592754466B7950A362345E266B864EE38D37888B5F85902E0000 B5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006020803D62C54E39535590F863B880C665E66C2E4F4660EE6DE18BDE5F39 86CB5F536321515A83616863520063638E4850125C9B79775BFC52307A3B60BC 905376D75FB75F9776848E6C706F767B7B4977AA51F3909358244F4E6EF48FEA 654C7B1B72C46DA47FDF5AE162B55E95573084827B2C5E1D5F1F90127F1498A0 63826EC7789870B95178975B57AB75354F4375385E9760E659606DC06BBF7889 53FC96D551CB52016389540A94938C038DCC7239789F87768FED8C0D53E00000 B6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00004E0176EF53EE948998769F0E952D5B9A8BA24E224E1C51AC846361C252A8 680B4F97606B51BB6D1E515C6296659796618C46901775D890FD77636BD2728A 72EC8BFB583577798D4C675C9540809A5EA66E2159927AEF77ED953B6BB565AD 7F0E58065151961F5BF958A954288E726566987F56E4949D76FE9041638754C6 591A593A579B8EB267358DFA8235524160F0581586FE5CE89E454FC4989D8BB9 5A2560765384627C904F9102997F6069800C513F80335C1499756D314E8C0000 B7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008D3053D17F5A7B4F4F104E4F96006CD573D085E95E06756A7FFB6A0A77FE 94927E4151E170E653CD8FD483038D2972AF996D6CDB574A82B365B980AA623F 963259A84EFF8BBF7EBA653E83F2975E556198DE80A5532A8BFD542080BA5E9F 6CB88D3982AC915A54296C1B52067EB7575F711A6C7E7C89594B4EFD5FFF6124 7CAA4E305C0167AB87025CF0950B98CE75AF70FD902251AF7F1D8BBD594951E4 4F5B5426592B657780A45B75627662C28F905E456C1F7B264F0F4FD8670D0000 B8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006D6E6DAA798F88B15F17752B629A8F854FEF91DC65A7812F81515E9C8150 8D74526F89868D4B590D50854ED8961C723681798D1F5BCC8BA3964459877F1A 54905676560E8BE565396982949976D66E895E727518674667D17AFF809D8D76 611F79C665628D635188521A94A27F38809B7EB25C976E2F67607BD9768B9AD8 818F7F947CD5641E95507A3F544A54E56B4C640162089E3D80F3759952729769 845B683C86E49601969494EC4E2A54047ED968398DDF801566F45E9A7FB90000 B9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000057C2803F68975DE5653B529F606D9F9A4F9B8EAC516C5BAB5F135DE96C5E 62F18D21517194A952FE6C9F82DF72D757A267848D2D591F8F9C83C754957B8D 4F306CBD5B6459D19F1353E486CA9AA88C3780A16545987E56FA96C7522E74DC 52505BE1630289024E5662D0602A68FA51735B9851A089C27BA199867F5060EF 704C8D2F51495E7F901B747089C4572D78455F529F9F95FA8F689B3C8BE17678 684267DC8DEA8D35523D8F8A6EDA68CD950590ED56FD679C88F98FC754C80000 BA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009AB85B696D776C264EA55BB39A87916361A890AF97E9542B6DB55BD251FD 558A7F557FF064BC634D65F161BE608D710A6C576C49592F676D822A58D5568E 8C6A6BEB90DD597D801753F76D695475559D837783CF683879BE548C4F555408 76D28C8996026CB36DB88D6B89109E648D3A563F9ED175D55F8872E0606854FC 4EA86A2A886160528F7054C470D886799E3F6D2A5B8F5F187EA255894FAF7334 543C539A5019540E547C4E4E5FFD745A58F6846B80E1877472D07CCA6E560000 BB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005F27864E552C62A44E926CAA623782B154D7534E733E6ED1753B52125316 8BDD69D05F8A60006DEE574F6B2273AF68538FD87F13636260A3552475EA8C62 71156DA35BA65E7B8352614C9EC478FA87577C27768751F060F6714C66435E4C 604D8C0E707063258F895FBD606286D456DE6BC160946167534960E066668D3F 79FD4F1A70E96C478BB38BF27ED88364660F5A5A9B426D516DF78C416D3B4F19 706B83B7621660D1970D8D27797851FB573E57FA673A75787A3D79EF7B950000 BC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000808C99658FF96FC08BA59E2159EC7EE97F095409678168D88F917C4D96C6 53CA602575BE6C7253735AC97EA7632451E0810A5DF184DF628051805B634F0E 796D524260B86D4E5BC45BC28BA18BB065E25FCC964559937EE77EAA560967B7 59394F735BB652A0835A988A8D3E753294BE50477A3C4EF767B69A7E5AC16B7C 76D1575A5C167B3A95F4714E517C80A9827059787F04832768C067EC78B17877 62E363617B804FED526A51CF835069DB92748DF58D3189C1952E7BAD4EF60000 BD 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000506582305251996F6E106E856DA75EFA50F559DC5C066D466C5F7586848B 686859568BB253209171964D854969127901712680F64EA490CA6D479A845A07 56BC640594F077EB4FA5811A72E189D2997A7F347EDE527F655991758F7F8F83 53EB7A9663ED63A5768679F888579636622A52AB8282685467706377776B7AED 6D017ED389E359D0621285C982A5754C501F4ECB75A58BEB5C4A5DFE7B4B65A4 91D14ECA6D25895F7D2795264EC58C288FDB9773664B79818FD170EC6D780000 BE 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005C3D52B283465162830E775B66769CB84EAC60CA7CBE7CB37ECF4E958B66 666F988897595883656C955C5F8475C997567ADF7ADE51C070AF7A9863EA7A76 7EA0739697ED4E4570784E5D915253A9655165E781FC8205548E5C31759A97A0 62D872D975BD5C459A7983CA5C40548077E94E3E6CAE805A62D2636E5DE85177 8DDD8E1E952F4FF153E560E770AC526763509E435A1F5026773753777EE26485 652B628963985014723589C951B38BC07EDD574783CC94A7519B541B5CFB0000 BF 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00004FCA7AE36D5A90E19A8F55805496536154AF5F0063E9697751EF6168520A 582A52D8574E780D770B5EB761777CE0625B62974EA27095800362F770E49760 577782DB67EF68F578D5989779D158F354B353EF6E34514B523B5BA28BFE80AF 554357A660735751542D7A7A60505B5463A762A053E362635BC767AF54ED7A9F 82E691775E9388E4593857AE630E8DE880EF57577B774FA95FEB5BBD6B3E5321 7B5072C2684677FF773665F751B54E8F76D45CBF7AA58475594E9B4150800000 C0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000998861276E8357646606634656F062EC62695ED39614578362C955878721 814A8FA3556683B167658D5684DD5A6A680F62E67BEE961151706F9C8C3063FD 89C861D27F0670C26EE57405699472FC5ECA90CE67176D6A635E52B372628001 4F6C59E5916A70D96D9D52D24E5096F7956D857E78CA7D2F5121579264C2808B 7C7B6CEA68F1695E51B7539868A872819ECE7BF172F879BB6F137406674E91CC 9CA4793C83898354540F68174E3D538952B1783E5386522950884F8B4FD00000 C1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000075E27ACB7C926CA596B6529B748354E94FE9805483B28FDE95705EC9601C 6D9F5E18655B813894FE604B70BC7EC37CAE51C968817CB1826F4E248F8691CF 667E4EAE8C0564A9804A50DA759771CE5BE58FBD6F664E86648295635ED66599 521788C270C852A3730E7433679778F797164E3490BB9CDE6DCB51DB8D41541D 62CE73B283F196F69F8494C34F367F9A51CC707596755CAD988653E64EE46E9C 740969B4786B998F7559521876246D4167F3516D9F99804B54997B3C7ABF0000 C2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009686578462E29647697C5A0464027BD36F0F964B82A6536298855E907089 63B35364864F9C819E93788C97328DEF8D429E7F6F5E79845F559646622E9A74 541594DD4FA365C55C655C617F1586516C2F5F8B73876EE47EFF5CE6631B5B6A 6EE653754E7163A0756562A18F6E4F264ED16CA67EB68BBA841D87BA7F57903B 95237BA99AA188F8843D6D1B9A867EDC59889EBB739B780186829A6C9A82561B 541757CB4E709EA653568FC881097792999286EE6EE1851366FC61626F2B0000 C3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008C298292832B76F26C135FD983BD732B8305951A6BDB77DB94C6536F8302 51925E3D8C8C8D384E4873AB679A68859176970971646CA177095A9295416BCF 7F8E66275BD059B95A9A95E895F74EEC840C84996AAC76DF9530731B68A65B5F 772F919A97617CDC8FF78C1C5F257C7379D889C56CCC871C5BC65E4268C97720 7EF55195514D52C95A297F05976282D763CF778485D079D26E3A5E9959998511 706D6C1162BF76BF654F60AF95FD660E879F9E2394ED540D547D8C2C64780000 C4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000647986116A21819C78E864699B5462B9672B83AB58A89ED86CAB6F205BDE 964C8C0B725F67D062C772614EA959C66BCD589366AE5E5552DF6155672876EE 776672677A4662FF54EA545094A090A35A1C7EB36C164E435976801059485357 753796BE56CA63208111607C95F96DD65462998151855AE980FD59AE9713502A 6CE55C3C62DF4F60533F817B90066EBA852B62C85E7478BE64B5637B5FF55A18 917F9E1F5C3F634F80425B7D556E954A954D6D8560A867E072DE51DD5B810000 C5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000062E76CDE725B626D94AE7EBD81136D53519C5F04597452AA601259736696 8650759F632A61E67CEF8BFA54E66B279E256BB485D5545550766CA4556A8DB4 722C5E156015743662CD6392724C5F986E436D3E65006F5876D878D076FC7554 522453DB4E535E9E65C1802A80D6629B5486522870AE888D8DD16CE1547880DA 57F988F48D54966A914D4F696C9B55B776C6783062A870F96F8E5F6D84EC68DA 787C7BF781A8670B9E4F636778B0576F78129739627962AB528874356BD70000 C6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005564813E75B276AE533975DE50FB5C418B6C7BC7504F72479A9798D86F02 74E27968648777A562FC98918D2B54C180584E52576A82F9840D5E7351ED74F6 8BC45C4F57616CFC98875A4678349B448FEB7C955256625194FA4EC683868461 83E984B257D467345703666E6D668C3166DD7011671F6B3A6816621A59BB4E03 51C46F0667D26C8F517668CB59476B6775665D0E81109F5065D7794879419A91 8D775C824E5E4F01542F5951780C56686C148FC45F036C7D6CE38BAB63900000 C7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000060706D3D72756266948E94C553438FC17B7E4EDF8C264E7E9ED494B194B3 524D6F5C90636D458C3458115D4C6B206B4967AA545B81547F8C589985375F3A 62A26A47953965726084686577A74E544FA85DE7979864AC7FD85CED4FCF7A8D 520783044E14602F7A8394A64FB54EB279E6743452E482B964D279BD5BDD6C81 97528F7B6C22503E537F6E0564CE66746C3060C598778BF75E86743C7A7779CB 4E1890B174036C4256DA914B6CC58D8B533A86C666F28EAF5C489A716E200000 C8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000053D65A369F8B8DA353BB570898A76743919B6CC9516875CA62F372AC5238 529D7F3A7094763853749E4A69B7786E96C088D97FA4713671C3518967D374E4 58E4651856B78BA9997662707ED560F970ED58EC4EC14EBA5FCD97E74EFB8BA4 5203598A7EAB62544ECD65E5620E833884C98363878D71946EB65BB97ED25197 63C967D480898339881551125B7A59828FB14E736C5D516589258F6F962E854A 745E951095F06DA682E55F3164926D128428816E9CC3585E8D5B4E0953C10000 C9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00004F1E6563685155D34E2764149A9A626B5AC2745F82726DA968EE50E7838E 7802674052396C997EB150BB5565715E7B5B665273CA82EB67495C715220717D 886B95EA965564C58D6181B355846C5562477F2E58924F2455468D4F664C4E0A 5C1A88F368A2634E7A0D70E7828D52FA97F65C1154E890B57ECD59628D4A86C7 820C820D8D6664445C0461516D89793E8BBE78377533547B4F388EAB6DF15A20 7EC5795E6C885BA15A76751A80BE614E6E1758F0751F7525727253477EF30000 CA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000770176DB526980DC57235E08593172EE65BD6E7F8BD75C388671534177F3 62FE65F64EC098DF86805B9E8BC653F277E24F7F5C4E9A7659CB5F0F793A58EB 4E1667FF4E8B62ED8A93901D52BF662F55DC566C90024ED54F8D91CA99706C0F 5E0260435BA489C68BD56536624B99965B885BFF6388552E53D77626517D852C 67A268B36B8A62928F9353D482126DD1758F4E668D4E5B70719F85AF669166D9 7F7287009ECD9F205C5E672F8FF06811675F620D7AD658855EB665706F310000 CB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000060555237800D6454887075295E05681362F4971C53CC723D8C016C347761 7A0E542E77AC987A821C8BF47855671470C165AF64955636601D79C153F84E1D 6B7B80865BFA55E356DB4F3A4F3C99725DF3677E80386002988290015B8B8BBC 8BF5641C825864DE55FD82CF91654FD77D20901F7C9F50F358516EAF5BBF8BC9 80839178849C7B97867D968B968F7EE59AD3788E5C817A57904296A7795F5B59 635F7B0B84D168AD55067F2974107D2295016240584C4ED65B83597958540000 CC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000736D631E8E4B8E0F80CE82D462AC53F06CF0915E592A60016C70574D644A 8D2A762B6EE9575B6A8075F06F6D8C2D8C0857666BEF889278B363A253F970AD 6C645858642A580268E0819B55107CD650188EBA6DCC8D9F70EB638F6D9B6ED4 7EE68404684390036DD896768BA85957727985E4817E75BC8A8A68AF52548E22 951163D098988E44557C4F5366FF568F60D56D9552435C4959296DFB586B7530 751C606C82148146631167618FE2773A8DF38D3494C15E165385542C70C30000 CD 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006C405EF7505C4EAD5EAD633A8247901A6850916E77B3540C94DC5F647AE5 687663457B527EDF75DB507762955934900F51F879C37A8156FE5F9290146D82 5C60571F541051546E4D56E263A89893817F8715892A9000541E5C6F81C062D6 625881319E3596409A6E9A7C692D59A562D3553E631654C786D96D3C5A0374E6 889C6B6A59168C4C5F2F6E7E73A9987D4E3870F75B8C7897633D665A769660CB 5B9B5A494E0781556C6A738B4EA167897F515F8065FA671B5FD859845A010000 CE 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005DCD5FAE537197E68FDD684556F4552F60DF4E3A6F4D7EF482C7840E59D4 4F1F4F2A5C3E7EAC672A851A5473754F80C355829B4F4F4D6E2D8C135C096170 536B761F6E29868A658795FB7EB9543B7A337D0A95EE55E17FC174EE631D8717 6DA17A9D621165A1536763E16C835DEB545C94A84E4C6C618BEC5C4B65E0829C 68A7543E54346BCB6B664E9463425348821E4F0D4FAE575E620A96FE66647269 52FF52A1609F8BEF661471996790897F785277FD6670563B54389521727A0000 CF 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007A00606F5E0C6089819D591560DC718470EF6EAA6C5072806A8488AD5E2D 4E605AB3559C94E36D177CFB9699620F7EC6778E867E5323971E8F9666875CE1 4FA072ED4E0B53A6590F54136380952851484ED99C9C7EA454B88D2488548237 95F26D8E5F265ACC663E966973B0732E53BF817A99857FA15BAA967796507EBF 76F853A2957699997BB189446E584E617FD479658BE660F354CD4EAB98795DF7 6A6150CF54118C618427785D9704524A54EE56A395006D885BB56DC666530000 D0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005C0F5B5D6821809655787B11654869544E9B6B47874E978B534F631F643A 90AA659C80C18C10519968B0537887F961C86CC46CFB8C225C5185AA82AF950C 6B238F9B65B05FFB5FC34FE18845661F8165732960FA51745211578B5F6290A2 884C91925E78674F602759D3514451F680F853086C7996C4718A4F114FEE7F9E 673D55C5950879C088967EE3589F620C9700865A5618987B5F908BB884C49157 53D965ED5E8F755C60647D6E5A7F7EEA7EED8F6955A75BA360AC65CB73840000 D1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009009766377297EDA9774859B5B667A7496EA884052CB718F5FAA65EC8BE2 5BFB9A6F5DE16B896C5B8BAD8BAF900A8FC5538B62BC9E269E2D54404E2B82BD 7259869C5D1688596DAF96C554D14E9A8BB6710954BD960970DF6DF976D04E25 781487125CA95EF68A00989C960E708E6CBF594463A9773C884D6F1482735830 71D5538C781A96C155015F6671305BB48C1A9A8C6B83592E9E2F79E76768626C 4F6F75A17F8A6D0B96336C274EF075D2517B68376F3E90808170599674760000 D2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000064475C2790657A918C2359DA54AC8200836F898180006930564E80367237 91CE51B64E5F987563964E1A53F666F3814B591C6DB24E0058F9533B63D694F1 4F9D4F0A886398905937905779FB4EEA80F075916C825B9C59E85F5D69058681 501A5DF24E5977E34EE5827A6291661390915C794EBF5F7981C69038808475AB 4EA688D4610F6BC55FC64E4976CA6EA28BE38BAE8C0A8BD15F027FFC7FCC7ECE 8335836B56E06BB797F3963459FB541F94F66DEB5BC5996E5C395F1596900000 D3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000537082F16A315A749E705E947F2883B984248425836787478FCE8D6276C8 5F719896786C662054DF62E54F6381C375C85EB896CD8E0A86F9548F6CF36D8C 6C38607F52C775285E7D4F1860A05FE75C24753190AE94C072B96CB96E389149 670953CB53F34F5191C98BF153C85E7C8FC26DE44E8E76C26986865E611A8206 4F594FDE903E9C7C61096E1D6E1496854E885A3196E84E0E5C7F79B95B878BED 7FBD738957DF828B90C15401904755BB5CEA5FA161086B3272F180B28A890000 D4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006D745BD388D598848C6B9A6D9E336E0A51A4514357A38881539F63F48F95 56ED54585706733F6E907F188FDC82D1613F6028966266F07EA68D8A8DC394A5 5CB37CA4670860A6960580184E9190E75300966851418FD08574915D665597F5 5B55531D78386742683D54C9707E5BB08F7D518D572854B1651266828D5E8D43 810F846C906D7CDF51FF85FB67A365E96FA186A48E81566A90207682707671E5 8D2362E952196CFD8D3C600E589E618E66FE8D60624E55B36E23672D8F670000 D5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000094E195F87728680569A8548B4E4D70B88BC86458658B5B857A84503A5BE8 77BB6BE18A797C986CBE76CF65A98F975D2D5C5586386808536062187AD96E5B 7EFD6A1F7AE05F706F335F20638C6DA867564E085E108D264ED780C07634969C 62DB662D627E6CBC8D7571677F695146808753EC906E629854F286F08F998005 951785178FD96D5973CD659F771F7504782781FB8D1E94884FA6679575B98BCA 9707632F9547963584B8632377415F8172F04E896014657462EF6B63653F0000 D6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005E2775C790D18BC1829D679D652F5431871877E580A281026C414E4B7EC7 804C76F4690D6B966267503C4F84574063076B628DBE53EA65E87EB85FD7631A 63B781F381F47F6E5E1C5CD95236667A79E97A1A8D28709975D46EDE6CBB7A92 4E2D76C55FE0949F88777EC879CD80BF91CD4EF24F17821F54685DDE6D328BCC 7CA58F7480985E1A549276B15B99663C9AA473E0682A86DB6731732A8BF88BDB 90107AF970DB716E62C477A956314E3B845767F152A986C08D2E94F87B510000 D7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00004F4F6CE8795D9A7B6293722A62FD4E1378168F6C64B08D5A7BC668695E84 88C55986649E58EE72B6690E95258FFD8D5857607F008C0651C6634962D95353 684C74228301914C55447740707C6D4A517954A88D4459FF6ECB6DC45B5C7D2B 4ED47C7D6ED35B5081EA6E0D5B579B0368D58E2A5B977EFC603B7EB590B98D70 594F63CD79DF8DB3535265CF79568BC5963B7EC494BB7E825634918967007F6A 5C0A907566285DE64F5067DE505A4F5C57505EA7000000000000000000000000 D8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00004E8D4E0C51404E105EFF53454E154E984E1E9B325B6C56694E2879BA4E3F 53154E47592D723B536E6C1056DF80E499976BD3777E9F174E364E9F9F104E5C 4E694E9382885B5B556C560F4EC4538D539D53A353A553AE97658D5D531A53F5 5326532E533E8D5C5366536352025208520E522D5233523F5240524C525E5261 525C84AF527D528252815290529351827F544EBB4EC34EC94EC24EE84EE14EEB 4EDE4F1B4EF34F224F644EF54F254F274F094F2B4F5E4F6765384F5A4F5D0000 D9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00004F5F4F574F324F3D4F764F744F914F894F834F8F4F7E4F7B4FAA4F7C4FAC 4F944FE64FE84FEA4FC54FDA4FE34FDC4FD14FDF4FF85029504C4FF3502C500F 502E502D4FFE501C500C50255028507E504350555048504E506C507B50A550A7 50A950BA50D6510650ED50EC50E650EE5107510B4EDD6C3D4F584F654FCE9FA0 6C467C74516E5DFD9EC999985181591452F9530D8A07531051EB591951554EA0 51564EB3886E88A44EB5811488D279805B3488037FB851AB51B151BD51BC0000 DA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000051C7519651A251A58BA08BA68BA78BAA8BB48BB58BB78BC28BC38BCB8BCF 8BCE8BD28BD38BD48BD68BD88BD98BDC8BDF8BE08BE48BE88BE98BEE8BF08BF3 8BF68BF98BFC8BFF8C008C028C048C078C0C8C0F8C118C128C148C158C168C19 8C1B8C188C1D8C1F8C208C218C258C278C2A8C2B8C2E8C2F8C328C338C358C36 5369537A961D962296219631962A963D963C964296499654965F9667966C9672 96749688968D969796B09097909B909D909990AC90A190B490B390B690BA0000 DB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000090B890B090CF90C590BE90D090C490C790D390E690E290DC90D790DB90EB 90EF90FE91049122911E91239131912F913991439146520D594252A252AC52AD 52BE54FF52D052D652F053DF71EE77CD5EF451F551FC9B2F53B65F01755A5DEF 574C57A957A1587E58BC58C558D15729572C572A57335739572E572F575C573B 574257695785576B5786577C577B5768576D5776577357AD57A4578C57B257CF 57A757B4579357A057D557D857DA57D957D257B857F457EF57F857E457DD0000 DC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000580B580D57FD57ED5800581E5819584458205865586C58815889589A5880 99A89F1961FF8279827D827F828F828A82A88284828E82918297829982AB82B8 82BE82B082C882CA82E3829882B782AE82CB82CC82C182A982B482A182AA829F 82C482CE82A482E1830982F782E4830F830782DC82F482D282D8830C82FB82D3 8311831A83068314831582E082D5831C8351835B835C83088392833C83348331 839B835E832F834F83478343835F834083178360832D833A8333836683650000 DD 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008368831B8369836C836A836D836E83B0837883B383B483A083AA8393839C 8385837C83B683A9837D83B8837B8398839E83A883BA83BC83C1840183E583D8 58078418840B83DD83FD83D6841C84388411840683D483DF840F840383F883F9 83EA83C583C0842683F083E1845C8451845A8459847384878488847A84898478 843C844684698476848C848E8431846D84C184CD84D084E684BD84D384CA84BF 84BA84E084A184B984B4849784E584E3850C750D853884F08539851F853A0000 DE 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008556853B84FF84FC8559854885688564855E857A77A285438572857B85A4 85A88587858F857985AE859C858585B985B785B085D385C185DC85FF86278605 86298616863C5EFE5F08593C594180375955595A5958530F5C225C255C2C5C34 624C626A629F62BB62CA62DA62D762EE632262F66339634B634363AD63F66371 637A638E63B4636D63AC638A636963AE63BC63F263F863E063FF63C463DE63CE 645263C663BE64456441640B641B6420640C64266421645E6484646D64960000 DF 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000647A64B764B8649964BA64C064D064D764E464E265096525652E5F0B5FD2 75195F11535F53F153FD53E953E853FB541254165406544B5452545354545456 54435421545754595423543254825494547754715464549A549B548454765466 549D54D054AD54C254B454D254A754A654D354D4547254A354D554BB54BF54CC 54D954DA54DC54A954AA54A454DD54CF54DE551B54E7552054FD551454F35522 5523550F55115527552A5567558F55B55549556D55415555553F5550553C0000 E0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005537555655755576557755335530555C558B55D2558355B155B955885581 559F557E55D65591557B55DF55BD55BE5594559955EA55F755C9561F55D155EB 55EC55D455E655DD55C455EF55E555F255F355CC55CD55E855F555E48F94561E 5608560C56015624562355FE56005627562D565856395657562C564D56625659 565C564C5654568656645671566B567B567C5685569356AF56D456D756DD56E1 56F556EB56F956FF5704570A5709571C5E0F5E195E145E115E315E3B5E3C0000 E1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005E375E445E545E5B5E5E5E615C8C5C7A5C8D5C905C965C885C985C995C91 5C9A5C9C5CB55CA25CBD5CAC5CAB5CB15CA35CC15CB75CC45CD25CE45CCB5CE5 5D025D035D275D265D2E5D245D1E5D065D1B5D585D3E5D345D3D5D6C5D5B5D6F 5D5D5D6B5D4B5D4A5D695D745D825D995D9D8C735DB75DC55F735F775F825F87 5F895F8C5F955F995F9C5FA85FAD5FB55FBC88625F6172AD72B072B472B772B8 72C372C172CE72CD72D272E872EF72E972F272F472F7730172F3730372FA0000 E2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000072FB731773137321730A731E731D7315732273397325732C733873317350 734D73577360736C736F737E821B592598E7592459029963996799689969996A 996B996C99749977997D998099849987998A998D999099919993999499955E80 5E915E8B5E965EA55EA05EB95EB55EBE5EB38D535ED25ED15EDB5EE85EEA81BA 5FC45FC95FD65FCF60035FEE60045FE15FE45FFE600560065FEA5FED5FF86019 60356026601B600F600D6029602B600A603F602160786079607B607A60420000 E3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000606A607D6096609A60AD609D60836092608C609B60EC60BB60B160DD60D8 60C660DA60B4612061266115612360F46100610E612B614A617561AC619461A7 61B761D461F55FDD96B395E995EB95F195F395F595F695FC95FE960396049606 9608960A960B960C960D960F96129615961696179619961A4E2C723F62156C35 6C546C5C6C4A6CA36C856C906C946C8C6C686C696C746C766C866CA96CD06CD4 6CAD6CF76CF86CF16CD76CB26CE06CD66CFA6CEB6CEE6CB16CD36CEF6CFE0000 E4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006D396D276D0C6D436D486D076D046D196D0E6D2B6D4D6D2E6D356D1A6D4F 6D526D546D336D916D6F6D9E6DA06D5E6D936D946D5C6D606D7C6D636E1A6DC7 6DC56DDE6E0E6DBF6DE06E116DE66DDD6DD96E166DAB6E0C6DAE6E2B6E6E6E4E 6E6B6EB26E5F6E866E536E546E326E256E446EDF6EB16E986EE06F2D6EE26EA5 6EA76EBD6EBB6EB76ED76EB46ECF6E8F6EC26E9F6F626F466F476F246F156EF9 6F2F6F366F4B6F746F2A6F096F296F896F8D6F8C6F786F726F7C6F7A6FD10000 E5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006FC96FA76FB96FB66FC26FE16FEE6FDE6FE06FEF701A7023701B70397035 704F705E5B805B845B955B935BA55BB8752F9A9E64345BE45BEE89305BF08E47 8B078FB68FD38FD58FE58FEE8FE48FE98FE68FF38FE890059004900B90269011 900D9016902190359036902D902F9044905190529050906890589062905B66B9 9074907D908290889083908B5F505F575F565F585C3B54AB5C505C595B715C63 5C667FBC5F2A5F295F2D82745F3C9B3B5C6E59815983598D59A959AA59A30000 E6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000599759CA59AB599E59A459D259B259AF59D759BE5A055A0659DD5A0859E3 59D859F95A0C5A095A325A345A115A235A135A405A675A4A5A555A3C5A625A75 80EC5AAA5A9B5A775A7A5ABE5AEB5AB25AD25AD45AB85AE05AE35AF15AD65AE6 5AD85ADC5B095B175B165B325B375B405C155C1C5B5A5B655B735B515B535B62 9A759A779A789A7A9A7F9A7D9A809A819A859A889A8A9A909A929A939A969A98 9A9B9A9C9A9D9A9F9AA09AA29AA39AA59AA77E9F7EA17EA37EA57EA87EA90000 E7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007EAD7EB07EBE7EC07EC17EC27EC97ECB7ECC7ED07ED47ED77EDB7EE07EE1 7EE87EEB7EEE7EEF7EF17EF27F0D7EF67EFA7EFB7EFE7F017F027F037F077F08 7F0B7F0C7F0F7F117F127F177F197F1C7F1B7F1F7F217F227F237F247F257F26 7F277F2A7F2B7F2C7F2D7F2F7F307F317F327F337F355E7A757F5DDB753E9095 738E739173AE73A2739F73CF73C273D173B773B373C073C973C873E573D9987C 740A73E973E773DE73BA73F2740F742A745B7426742574287430742E742C0000 E8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000741B741A7441745C7457745574597477746D747E749C748E748074817487 748B749E74A874A9749074A774D274BA97EA97EB97EC674C6753675E67486769 67A56787676A6773679867A7677567A8679E67AD678B6777677C67F0680967D8 680A67E967B0680C67D967B567DA67B367DD680067C367B867E2680E67C167FD 6832683368606861684E6862684468646883681D68556866684168676840683E 684A6849682968B5688F687468776893686B68C2696E68FC691F692068F90000 E9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000692468F0690B6901695768E369106971693969606942695D6984696B6980 69986978693469CC6987698869CE6989696669636979699B69A769BB69AB69AD 69D469B169C169CA69DF699569E0698D69FF6A2F69ED6A176A186A6569F26A44 6A3E6AA06A506A5B6A356A8E6A796A3D6A286A586A7C6A916A906AA96A976AAB 733773526B816B826B876B846B926B936B8D6B9A6B9B6BA16BAA8F6B8F6D8F71 8F728F738F758F768F788F778F798F7A8F7C8F7E8F818F828F848F878F8B0000 EA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008F8D8F8E8F8F8F988F9A8ECE620B6217621B621F6222622162256224622C 81E774EF74F474FF750F75117513653465EE65EF65F0660A6619677266036615 6600708566F7661D66346631663666358006665F66546641664F665666616657 66776684668C66A7669D66BE66DB66DC66E666E98D328D338D368D3B8D3D8D40 8D458D468D488D498D478D4D8D558D5989C789CA89CB89CC89CE89CF89D089D1 726E729F725D7266726F727E727F7284728B728D728F72926308633263B00000 EB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000643F64D880046BEA6BF36BFD6BF56BF96C056C076C066C0D6C156C186C19 6C1A6C216C296C246C2A6C3265356555656B724D72527256723086625216809F 809C809380BC670A80BD80B180AB80AD80B480B780E780E880E980EA80DB80C2 80C480D980CD80D7671080DD80EB80F180F480ED810D810E80F280FC67158112 8C5A8136811E812C811881328148814C815381748159815A817181608169817C 817D816D8167584D5AB58188818281916ED581A381AA81CC672681CA81BB0000 EC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000081C181A66B246B376B396B436B466B5998D198D298D398D598D998DA6BB3 5F406BC289F365909F51659365BC65C665C465C365CC65CE65D265D67080709C 7096709D70BB70C070B770AB70B170E870CA711071137116712F71317173715C 716871457172714A7178717A719871B371B571A871A071E071D471E771F9721D 7228706C7118716671B9623E623D624362486249793B794079467949795B795C 7953795A796279577960796F7967797A7985798A799A79A779B35FD15FD00000 ED 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000603C605D605A606760416059606360AB6106610D615D61A9619D61CB61D1 62068080807F6C936CF66DFC77F677F87800780978177818781165AB782D781C 781D7839783A783B781F783C7825782C78237829784E786D7856785778267850 7847784C786A789B7893789A7887789C78A178A378B278B978A578D478D978C9 78EC78F2790578F479137924791E79349F9B9EF99EFB9EFC76F17704770D76F9 77077708771A77227719772D7726773577387750775177477743775A77680000 EE 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000077627765777F778D777D7780778C7791779F77A077B077B577BD753A7540 754E754B7548755B7572757975837F587F617F5F8A487F687F747F717F797F81 7F7E76CD76E58832948594869487948B948A948C948D948F9490949494979495 949A949B949C94A394A494AB94AA94AD94AC94AF94B094B294B494B694B794B8 94B994BA94BC94BD94BF94C494C894C994CA94CB94CC94CD94CE94D094D194D2 94D594D694D794D994D894DB94DE94DF94E094E294E494E594E794E894EA0000 EF 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000094E994EB94EE94EF94F394F494F594F794F994FC94FD94FF950395029506 95079509950A950D950E950F951295139514951595169518951B951D951E951F 9522952A952B9529952C953195329534953695379538953C953E953F95429535 9544954595469549954C954E954F9552955395549556955795589559955B955E 955F955D95619562956495659566956795689569956A956B956C956F95719572 9573953A77E777EC96C979D579ED79E379EB7A065D477A037A027A1E7A140000 F0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007A397A377A519ECF99A57A707688768E7693769976A474DE74E0752C9E20 9E229E289E299E2A9E2B9E2C9E329E319E369E389E379E399E3A9E3E9E419E42 9E449E469E479E489E499E4B9E4C9E4E9E519E559E579E5A9E5B9E5C9E5E9E63 9E669E679E689E699E6A9E6B9E6C9E719E6D9E7375927594759675A0759D75AC 75A375B375B475B875C475B175B075C375C275D675CD75E375E875E675E475EB 75E7760375F175FC75FF761076007605760C7617760A76257618761576190000 F1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000761B763C762276207640762D7630763F76357643763E7633764D765E7654 765C7656766B766F7FCA7AE67A787A797A807A867A887A957AA67AA07AAC7AA8 7AAD7AB3886488698872887D887F888288A288C688B788BC88C988E288CE88E3 88E588F1891A88FC88E888FE88F0892189198913891B890A8934892B89368941 8966897B758B80E576B276B477DC801280148016801C80208022802580268027 802980288031800B803580438046804D80528069807189839878988098830000 F2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009889988C988D988F9894989A989B989E989F98A198A298A598A6864D8654 866C866E867F867A867C867B86A8868D868B86AC869D86A786A386AA869386A9 86B686C486B586CE86B086BA86B186AF86C986CF86B486E986F186F286ED86F3 86D0871386DE86F486DF86D886D18703870786F88708870A870D87098723873B 871E8725872E871A873E87488734873187298737873F87828722877D877E877B 87608770874C876E878B87538763877C876487598765879387AF87A887D20000 F3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000087C68788878587AD8797878387AB87E587AC87B587B387CB87D387BD87D1 87C087CA87DB87EA87E087EE8816881387FE880A881B88218839883C7F367F42 7F447F4582107AFA7AFD7B087B037B047B157B0A7B2B7B0F7B477B387B2A7B19 7B2E7B317B207B257B247B337B3E7B1E7B587B5A7B457B757B4C7B5D7B607B6E 7B7B7B627B727B717B907BA67BA77BB87BAC7B9D7BA87B857BAA7B9C7BA27BAB 7BB47BD17BC17BCC7BDD7BDA7BE57BE67BEA7C0C7BFE7BFC7C0F7C167C0B0000 F4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007C1F7C2A7C267C387C417C4081FE82018202820481EC8844822182228223 822D822F8228822B8238823B82338234823E82448249824B824F825A825F8268 887E8885888888D888DF895E7F9D7F9F7FA77FAF7FB07FB27C7C65497C917C9D 7C9C7C9E7CA27CB27CBC7CBD7CC17CC77CCC7CCD7CC87CC57CD77CE8826E66A8 7FBF7FCE7FD57FE57FE17FE67FE97FEE7FF37CF87D777DA67DAE7E477E9B9EB8 9EB48D738D848D948D918DB18D678D6D8C478C49914A9150914E914F91640000 F5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009162916191709169916F917D917E917291749179918C91859190918D9191 91A291A391AA91AD91AE91AF91B591B491BA8C559E7E8DB88DEB8E058E598E69 8DB58DBF8DBC8DBA8DC48DD68DD78DDA8DDE8DCE8DCF8DDB8DC68DEC8DF78DF8 8DE38DF98DFB8DE48E098DFD8E148E1D8E1F8E2C8E2E8E238E2F8E3A8E408E39 8E358E3D8E318E498E418E428E518E528E4A8E708E768E7C8E6F8E748E858E8F 8E948E908E9C8E9E8C788C828C8A8C858C988C94659B89D689DE89DA89DC0000 F6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000089E589EB89EF8A3E8B26975396E996F396EF970697019708970F970E972A 972D9730973E9F809F839F859F869F879F889F899F8A9F8C9EFE9F0B9F0D96B9 96BC96BD96CE96D277BF96E0928E92AE92C8933E936A93CA938F943E946B9C7F 9C829C859C869C879C887A239C8B9C8E9C909C919C929C949C959C9A9C9B9C9E 9C9F9CA09CA19CA29CA39CA59CA69CA79CA89CA99CAB9CAD9CAE9CB09CB19CB2 9CB39CB49CB59CB69CB79CBA9CBB9CBC9CBD9CC49CC59CC69CC79CCA9CCB0000 F7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009CCC9CCD9CCE9CCF9CD09CD39CD49CD59CD79CD89CD99CDC9CDD9CDF9CE2 977C978597919792979497AF97AB97A397B297B49AB19AB09AB79E589AB69ABA 9ABC9AC19AC09AC59AC29ACB9ACC9AD19B459B439B479B499B489B4D9B5198E8 990D992E995599549ADF9AE19AE69AEF9AEB9AFB9AED9AF99B089B0F9B139B1F 9B239EBD9EBE7E3B9E829E879E889E8B9E9293D69E9D9E9F9EDB9EDC9EDD9EE0 9EDF9EE29EE99EE79EE59EEA9EEF9F229F2C9F2F9F399F379F3D9F3E9F440000 tcl8.4.20/library/encoding/iso2022-jp.enc0000644003604700454610000000030011737050674016340 0ustar dgp771div# Encoding file: iso2022-jp, escape-driven E name iso2022-jp init {} final {} ascii \x1b(B jis0201 \x1b(J jis0208 \x1b$B jis0208 \x1b$@ jis0212 \x1b$(D gb2312 \x1b$A ksc5601 \x1b$(C tcl8.4.20/library/encoding/cp1257.enc0000644003604700454610000000210311737050674015555 0ustar dgp771div# Encoding file: cp1257, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 20AC0081201A0083201E20262020202100882030008A2039008C00A802C700B8 009020182019201C201D20222013201400982122009A203A009C00AF02DB009F 00A0000000A200A300A4000000A600A700D800A9015600AB00AC00AD00AE00C6 00B000B100B200B300B400B500B600B700F800B9015700BB00BC00BD00BE00E6 0104012E0100010600C400C501180112010C00C90179011601220136012A013B 01600143014500D3014C00D500D600D701720141015A016A00DC017B017D00DF 0105012F0101010700E400E501190113010D00E9017A011701230137012B013C 01610144014600F3014D00F500F600F701730142015B016B00FC017C017E02D9 tcl8.4.20/library/encoding/koi8-u.enc0000644003604700454610000000210311737050674015750 0ustar dgp771div# Encoding file: koi8-u, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 25002502250C251025142518251C2524252C2534253C258025842588258C2590 259125922593232025A02219221A22482264226500A0232100B000B200B700F7 25502551255204510454255404560457255725582559255A255B0491255D255E 255F25602561040104032563040604072566256725682569256A0490256C00A9 044E0430043104460434043504440433044504380439043A043B043C043D043E 043F044F044004410442044304360432044C044B04370448044D04490447044A 042E0410041104260414041504240413042504180419041A041B041C041D041E 041F042F042004210422042304160412042C042B04170428042D04290427042A tcl8.4.20/library/encoding/iso8859-8.enc0000644003604700454610000000210611737050674016134 0ustar dgp771div# Encoding file: iso8859-8, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 0080008100820083008400850086008700880089008A008B008C008D008E008F 0090009100920093009400950096009700980099009A009B009C009D009E009F 00A0000000A200A300A400A500A600A700A800A900D700AB00AC00AD00AE00AF 00B000B100B200B300B400B500B600B700B800B900F700BB00BC00BD00BE0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000002017 05D005D105D205D305D405D505D605D705D805D905DA05DB05DC05DD05DE05DF 05E005E105E205E305E405E505E605E705E805E905EA00000000200E200F0000 tcl8.4.20/library/encoding/cp1252.enc0000644003604700454610000000210311737050674015550 0ustar dgp771div# Encoding file: cp1252, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 20AC0081201A0192201E20262020202102C62030016020390152008D017D008F 009020182019201C201D20222013201402DC21220161203A0153009D017E0178 00A000A100A200A300A400A500A600A700A800A900AA00AB00AC00AD00AE00AF 00B000B100B200B300B400B500B600B700B800B900BA00BB00BC00BD00BE00BF 00C000C100C200C300C400C500C600C700C800C900CA00CB00CC00CD00CE00CF 00D000D100D200D300D400D500D600D700D800D900DA00DB00DC00DD00DE00DF 00E000E100E200E300E400E500E600E700E800E900EA00EB00EC00ED00EE00EF 00F000F100F200F300F400F500F600F700F800F900FA00FB00FC00FD00FE00FF tcl8.4.20/library/encoding/jis0212.enc0000644003604700454610000021247611737050674015746 0ustar dgp771div# Encoding file: jis0212, double-byte D 2244 0 68 22 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000002D8 02C700B802D902DD00AF02DB02DA007E03840385000000000000000000000000 0000000000A100A600BF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000BA00AA00A900AE2122 00A4211600000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 26 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000038603880389038A03AA0000038C0000038E03AB0000038F000000000000 000003AC03AD03AE03AF03CA039003CC03C203CD03CB03B003CE000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 27 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000004020403040404050406040704080409040A040B040C040E040F0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000004520453045404550456045704580459045A045B045C045E045F0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 29 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000C60110000001260000013200000141013F0000014A00D8015200000166 00DE000000000000000000000000000000000000000000000000000000000000 000000E6011100F00127013101330138014201400149014B00F8015300DF0167 00FE000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 2A 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000C100C000C400C2010201CD0100010400C500C301060108010C00C7010A 010E00C900C800CB00CA011A0116011201180000011C011E01220120012400CD 00CC00CF00CE01CF0130012A012E0128013401360139013D013B014301470145 00D100D300D200D600D401D10150014C00D5015401580156015A015C0160015E 0164016200DA00D900DC00DB016C01D30170016A0172016E016801D701DB01D9 01D5017400DD017801760179017D017B00000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 2B 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000E100E000E400E2010301CE0101010500E500E301070109010D00E7010B 010F00E900E800EB00EA011B01170113011901F5011D011F00000121012500ED 00EC00EF00EE01D00000012B012F012901350137013A013E013C014401480146 00F100F300F200F600F401D20151014D00F5015501590157015B015D0161015F 0165016300FA00F900FC00FB016D01D40171016B0173016F016901D801DC01DA 01D6017500FD00FF0177017A017E017C00000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 30 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00004E024E044E054E0C4E124E1F4E234E244E284E2B4E2E4E2F4E304E354E40 4E414E444E474E514E5A4E5C4E634E684E694E744E754E794E7F4E8D4E964E97 4E9D4EAF4EB94EC34ED04EDA4EDB4EE04EE14EE24EE84EEF4EF14EF34EF54EFD 4EFE4EFF4F004F024F034F084F0B4F0C4F124F154F164F174F194F2E4F314F60 4F334F354F374F394F3B4F3E4F404F424F484F494F4B4F4C4F524F544F564F58 4F5F4F634F6A4F6C4F6E4F714F774F784F794F7A4F7D4F7E4F814F824F840000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 31 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00004F854F894F8A4F8C4F8E4F904F924F934F944F974F994F9A4F9E4F9F4FB2 4FB74FB94FBB4FBC4FBD4FBE4FC04FC14FC54FC64FC84FC94FCB4FCC4FCD4FCF 4FD24FDC4FE04FE24FF04FF24FFC4FFD4FFF5000500150045007500A500C500E 5010501350175018501B501C501D501E50225027502E50305032503350355040 5041504250455046504A504C504E50515052505350575059505F506050625063 50665067506A506D50705071503B5081508350845086508A508E508F50900000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 32 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005092509350945096509B509C509E509F50A050A150A250AA50AF50B050B9 50BA50BD50C050C350C450C750CC50CE50D050D350D450D850DC50DD50DF50E2 50E450E650E850E950EF50F150F650FA50FE5103510651075108510B510C510D 510E50F2511051175119511B511C511D511E512351275128512C512D512F5131 513351345135513851395142514A514F5153515551575158515F51645166517E 51835184518B518E5198519D51A151A351AD51B851BA51BC51BE51BF51C20000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 33 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000051C851CF51D151D251D351D551D851DE51E251E551EE51F251F351F451F7 5201520252055212521352155216521852225228523152325235523C52455249 525552575258525A525C525F526052615266526E527752785279528052825285 528A528C52935295529652975298529A529C52A452A552A652A752AF52B052B6 52B752B852BA52BB52BD52C052C452C652C852CC52CF52D152D452D652DB52DC 52E152E552E852E952EA52EC52F052F152F452F652F753005303530A530B0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 34 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000530C531153135318531B531C531E531F5325532753285329532B532C532D 533053325335533C533D533E5342534C534B5359535B536153635365536C536D 53725379537E538353875388538E539353945399539D53A153A453AA53AB53AF 53B253B453B553B753B853BA53BD53C053C553CF53D253D353D553DA53DD53DE 53E053E653E753F554025413541A542154275428542A542F5431543454355443 54445447544D544F545E54625464546654675469546B546D546E5474547F0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 35 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000054815483548554885489548D549154955496549C549F54A154A654A754A9 54AA54AD54AE54B154B754B954BA54BB54BF54C654CA54CD54CE54E054EA54EC 54EF54F654FC54FE54FF55005501550555085509550C550D550E5515552A552B 553255355536553B553C553D554155475549554A554D555055515558555A555B 555E5560556155645566557F5581558255865588558E558F5591559255935594 559755A355A455AD55B255BF55C155C355C655C955CB55CC55CE55D155D20000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 36 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000055D355D755D855DB55DE55E255E955F655FF56055608560A560D560E560F 5610561156125619562C56305633563556375639563B563C563D563F56405641 5643564456465649564B564D564F5654565E566056615662566356665669566D 566F567156725675568456855688568B568C56955699569A569D569E569F56A6 56A756A856A956AB56AC56AD56B156B356B756BE56C556C956CA56CB56CF56D0 56CC56CD56D956DC56DD56DF56E156E456E556E656E756E856F156EB56ED0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 37 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000056F656F7570157025707570A570C57115715571A571B571D572057225723 572457255729572A572C572E572F57335734573D573E573F57455746574C574D 57525762576557675768576B576D576E576F5770577157735774577557775779 577A577B577C577E57815783578C579457975799579A579C579D579E579F57A1 579557A757A857A957AC57B857BD57C757C857CC57CF57D557DD57DE57E457E6 57E757E957ED57F057F557F657F857FD57FE57FF580358045808580957E10000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 38 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000580C580D581B581E581F582058265827582D58325839583F5849584C584D 584F58505855585F58615864586758685878587C587F58805881588758885889 588A588C588D588F589058945896589D58A058A158A258A658A958B158B258C4 58BC58C258C858CD58CE58D058D258D458D658DA58DD58E158E258E958F35905 5906590B590C5912591359148641591D5921592359245928592F593059335935 5936593F59435946595259535959595B595D595E595F59615963596B596D0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 39 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000596F5972597559765979597B597C598B598C598E599259955997599F59A4 59A759AD59AE59AF59B059B359B759BA59BC59C159C359C459C859CA59CD59D2 59DD59DE59DF59E359E459E759EE59EF59F159F259F459F75A005A045A0C5A0D 5A0E5A125A135A1E5A235A245A275A285A2A5A2D5A305A445A455A475A485A4C 5A505A555A5E5A635A655A675A6D5A775A7A5A7B5A7E5A8B5A905A935A965A99 5A9C5A9E5A9F5AA05AA25AA75AAC5AB15AB25AB35AB55AB85ABA5ABB5ABF0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 3A 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005AC45AC65AC85ACF5ADA5ADC5AE05AE55AEA5AEE5AF55AF65AFD5B005B01 5B085B175B345B195B1B5B1D5B215B255B2D5B385B415B4B5B4C5B525B565B5E 5B685B6E5B6F5B7C5B7D5B7E5B7F5B815B845B865B8A5B8E5B905B915B935B94 5B965BA85BA95BAC5BAD5BAF5BB15BB25BB75BBA5BBC5BC05BC15BCD5BCF5BD6 5BD75BD85BD95BDA5BE05BEF5BF15BF45BFD5C0C5C175C1E5C1F5C235C265C29 5C2B5C2C5C2E5C305C325C355C365C595C5A5C5C5C625C635C675C685C690000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 3B 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005C6D5C705C745C755C7A5C7B5C7C5C7D5C875C885C8A5C8F5C925C9D5C9F 5CA05CA25CA35CA65CAA5CB25CB45CB55CBA5CC95CCB5CD25CDD5CD75CEE5CF1 5CF25CF45D015D065D0D5D125D2B5D235D245D265D275D315D345D395D3D5D3F 5D425D435D465D485D555D515D595D4A5D5F5D605D615D625D645D6A5D6D5D70 5D795D7A5D7E5D7F5D815D835D885D8A5D925D935D945D955D995D9B5D9F5DA0 5DA75DAB5DB05DB45DB85DB95DC35DC75DCB5DD05DCE5DD85DD95DE05DE40000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 3C 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005DE95DF85DF95E005E075E0D5E125E145E155E185E1F5E205E2E5E285E32 5E355E3E5E4B5E505E495E515E565E585E5B5E5C5E5E5E685E6A5E6B5E6C5E6D 5E6E5E705E805E8B5E8E5EA25EA45EA55EA85EAA5EAC5EB15EB35EBD5EBE5EBF 5EC65ECC5ECB5ECE5ED15ED25ED45ED55EDC5EDE5EE55EEB5F025F065F075F08 5F0E5F195F1C5F1D5F215F225F235F245F285F2B5F2C5F2E5F305F345F365F3B 5F3D5F3F5F405F445F455F475F4D5F505F545F585F5B5F605F635F645F670000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 3D 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005F6F5F725F745F755F785F7A5F7D5F7E5F895F8D5F8F5F965F9C5F9D5FA2 5FA75FAB5FA45FAC5FAF5FB05FB15FB85FC45FC75FC85FC95FCB5FD05FD15FD2 5FD35FD45FDE5FE15FE25FE85FE95FEA5FEC5FED5FEE5FEF5FF25FF35FF65FFA 5FFC6007600A600D6013601460176018601A601F6024602D6033603560406047 60486049604C6051605460566057605D606160676071607E607F608260866088 608A608E6091609360956098609D609E60A260A460A560A860B060B160B70000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 3E 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000060BB60BE60C260C460C860C960CA60CB60CE60CF60D460D560D960DB60DD 60DE60E260E560F260F560F860FC60FD61026107610A610C6110611161126113 6114611661176119611C611E6122612A612B6130613161356136613761396141 614561466149615E6160616C61726178617B617C617F6180618161836184618B 618D6192619361976198619C619D619F61A061A561A861AA61AD61B861B961BC 61C061C161C261CE61CF61D561DC61DD61DE61DF61E161E261E761E961E50000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 3F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000061EC61ED61EF620162036204620762136215621C62206222622362276229 622B6239623D6242624362446246624C62506251625262546256625A625C6264 626D626F6273627A627D628D628E628F629062A662A862B362B662B762BA62BE 62BF62C462CE62D562D662DA62EA62F262F462FC62FD63036304630A630B630D 63106313631663186329632A632D633563366339633C63416342634363446346 634A634B634E6352635363546358635B63656366636C636D6371637463750000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 40 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006378637C637D637F638263846387638A6390639463956399639A639E63A4 63A663AD63AE63AF63BD63C163C563C863CE63D163D363D463D563DC63E063E5 63EA63EC63F263F363F563F863F96409640A6410641264146418641E64206422 642464256429642A642F64306435643D643F644B644F6451645264536454645A 645B645C645D645F646064616463646D64736474647B647D64856487648F6490 649164986499649B649D649F64A164A364A664A864AC64B364BD64BE64BF0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 41 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000064C464C964CA64CB64CC64CE64D064D164D564D764E464E564E964EA64ED 64F064F564F764FB64FF6501650465086509650A650F6513651465166519651B 651E651F652265266529652E6531653A653C653D654365476549655065526554 655F65606567656B657A657D65816585658A659265956598659D65A065A365A6 65AE65B265B365B465BF65C265C865C965CE65D065D465D665D865DF65F065F2 65F465F565F965FE65FF6600660466086609660D6611661266156616661D0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 42 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000661E662166226623662466266629662A662B662C662E6630663166336639 6637664066456646664A664C6651664E665766586659665B665C6660666166FB 666A666B666C667E66736675667F667766786679667B6680667C668B668C668D 669066926699669A669B669C669F66A066A466AD66B166B266B566BB66BF66C0 66C266C366C866CC66CE66CF66D466DB66DF66E866EB66EC66EE66FA67056707 670E67136719671C672067226733673E674567476748674C67546755675D0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 43 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006766676C676E67746776677B67816784678E678F67916793679667986799 679B67B067B167B267B567BB67BC67BD67F967C067C267C367C567C867C967D2 67D767D967DC67E167E667F067F267F667F7685268146819681D681F68286827 682C682D682F683068316833683B683F68446845684A684C685568576858685B 686B686E686F68706871687268756879687A687B687C68826884688668886896 6898689A689C68A168A368A568A968AA68AE68B268BB68C568C868CC68CF0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 44 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000068D068D168D368D668D968DC68DD68E568E868EA68EB68EC68ED68F068F1 68F568F668FB68FC68FD69066909690A69106911691369166917693169336935 6938693B694269456949694E6957695B696369646965696669686969696C6970 69716972697A697B697F6980698D69926996699869A169A569A669A869AB69AD 69AF69B769B869BA69BC69C569C869D169D669D769E269E569EE69EF69F169F3 69F569FE6A006A016A036A0F6A116A156A1A6A1D6A206A246A286A306A320000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 45 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006A346A376A3B6A3E6A3F6A456A466A496A4A6A4E6A506A516A526A556A56 6A5B6A646A676A6A6A716A736A7E6A816A836A866A876A896A8B6A916A9B6A9D 6A9E6A9F6AA56AAB6AAF6AB06AB16AB46ABD6ABE6ABF6AC66AC96AC86ACC6AD0 6AD46AD56AD66ADC6ADD6AE46AE76AEC6AF06AF16AF26AFC6AFD6B026B036B06 6B076B096B0F6B106B116B176B1B6B1E6B246B286B2B6B2C6B2F6B356B366B3B 6B3F6B466B4A6B4D6B526B566B586B5D6B606B676B6B6B6E6B706B756B7D0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 46 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006B7E6B826B856B976B9B6B9F6BA06BA26BA36BA86BA96BAC6BAD6BAE6BB0 6BB86BB96BBD6BBE6BC36BC46BC96BCC6BD66BDA6BE16BE36BE66BE76BEE6BF1 6BF76BF96BFF6C026C046C056C096C0D6C0E6C106C126C196C1F6C266C276C28 6C2C6C2E6C336C356C366C3A6C3B6C3F6C4A6C4B6C4D6C4F6C526C546C596C5B 6C5C6C6B6C6D6C6F6C746C766C786C796C7B6C856C866C876C896C946C956C97 6C986C9C6C9F6CB06CB26CB46CC26CC66CCD6CCF6CD06CD16CD26CD46CD60000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 47 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006CDA6CDC6CE06CE76CE96CEB6CEC6CEE6CF26CF46D046D076D0A6D0E6D0F 6D116D136D1A6D266D276D286C676D2E6D2F6D316D396D3C6D3F6D576D5E6D5F 6D616D656D676D6F6D706D7C6D826D876D916D926D946D966D976D986DAA6DAC 6DB46DB76DB96DBD6DBF6DC46DC86DCA6DCE6DCF6DD66DDB6DDD6DDF6DE06DE2 6DE56DE96DEF6DF06DF46DF66DFC6E006E046E1E6E226E276E326E366E396E3B 6E3C6E446E456E486E496E4B6E4F6E516E526E536E546E576E5C6E5D6E5E0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 48 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006E626E636E686E736E7B6E7D6E8D6E936E996EA06EA76EAD6EAE6EB16EB3 6EBB6EBF6EC06EC16EC36EC76EC86ECA6ECD6ECE6ECF6EEB6EED6EEE6EF96EFB 6EFD6F046F086F0A6F0C6F0D6F166F186F1A6F1B6F266F296F2A6F2F6F306F33 6F366F3B6F3C6F2D6F4F6F516F526F536F576F596F5A6F5D6F5E6F616F626F68 6F6C6F7D6F7E6F836F876F886F8B6F8C6F8D6F906F926F936F946F966F9A6F9F 6FA06FA56FA66FA76FA86FAE6FAF6FB06FB56FB66FBC6FC56FC76FC86FCA0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 49 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006FDA6FDE6FE86FE96FF06FF56FF96FFC6FFD7000700570067007700D7017 70207023702F703470377039703C7043704470487049704A704B70547055705D 705E704E70647065706C706E70757076707E7081708570867094709570967097 7098709B70A470AB70B070B170B470B770CA70D170D370D470D570D670D870DC 70E470FA71037104710571067107710B710C710F711E7120712B712D712F7130 713171387141714571467147714A714B715071527157715A715C715E71600000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 4A 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000071687179718071857187718C7192719A719B71A071A271AF71B071B271B3 71BA71BF71C071C171C471CB71CC71D371D671D971DA71DC71F871FE72007207 7208720972137217721A721D721F7224722B722F723472387239724172427243 7245724E724F7250725372557256725A725C725E726072637268726B726E726F 727172777278727B727C727F72847289728D728E7293729B72A872AD72AE72B1 72B472BE72C172C772C972CC72D572D672D872DF72E572F372F472FA72FB0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 4B 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000072FE7302730473057307730B730D7312731373187319731E732273247327 7328732C733173327335733A733B733D7343734D7350735273567358735D735E 735F7360736673677369736B736C736E736F737173777379737C738073817383 73857386738E73907393739573977398739C739E739F73A073A273A573A673AA 73AB73AD73B573B773B973BC73BD73BF73C573C673C973CB73CC73CF73D273D3 73D673D973DD73E173E373E673E773E973F473F573F773F973FA73FB73FD0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 4C 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000073FF7400740174047407740A7411741A741B7424742674287429742A742B 742C742D742E742F74307431743974407443744474467447744B744D74517452 7457745D7462746674677468746B746D746E7471747274807481748574867487 7489748F74907491749274987499749A749C749F74A074A174A374A674A874A9 74AA74AB74AE74AF74B174B274B574B974BB74BF74C874C974CC74D074D374D8 74DA74DB74DE74DF74E474E874EA74EB74EF74F474FA74FB74FC74FF75060000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 4D 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000075127516751775207521752475277529752A752F75367539753D753E753F 7540754375477548754E755075527557755E755F7561756F75717579757A757B 757C757D757E7581758575907592759375957599759C75A275A475B475BA75BF 75C075C175C475C675CC75CE75CF75D775DC75DF75E075E175E475E775EC75EE 75EF75F175F9760076027603760476077608760A760C760F7612761376157616 7619761B761C761D761E7623762576267629762D763276337635763876390000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 4E 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000763A763C764A764076417643764476457649764B76557659765F76647665 766D766E766F7671767476817685768C768D7695769B769C769D769F76A076A2 76A376A476A576A676A776A876AA76AD76BD76C176C576C976CB76CC76CE76D4 76D976E076E676E876EC76F076F176F676F976FC77007706770A770E77127714 771577177719771A771C77227728772D772E772F7734773577367739773D773E 774277457746774A774D774E774F775277567757775C775E775F776077620000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 4F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000077647767776A776C7770777277737774777A777D77807784778C778D7794 77957796779A779F77A277A777AA77AE77AF77B177B577BE77C377C977D177D2 77D577D977DE77DF77E077E477E677EA77EC77F077F177F477F877FB78057806 7809780D780E7811781D782178227823782D782E783078357837784378447847 7848784C784E7852785C785E78607861786378647868786A786E787A787E788A 788F7894789878A1789D789E789F78A478A878AC78AD78B078B178B278B30000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 50 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000078BB78BD78BF78C778C878C978CC78CE78D278D378D578D678E478DB78DF 78E078E178E678EA78F278F3790078F678F778FA78FB78FF7906790C7910791A 791C791E791F7920792579277929792D793179347935793B793D793F79447945 7946794A794B794F795179547958795B795C79677969796B79727979797B797C 797E798B798C799179937994799579967998799B799C79A179A879A979AB79AF 79B179B479B879BB79C279C479C779C879CA79CF79D479D679DA79DD79DE0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 51 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000079E079E279E579EA79EB79ED79F179F879FC7A027A037A077A097A0A7A0C 7A117A157A1B7A1E7A217A277A2B7A2D7A2F7A307A347A357A387A397A3A7A44 7A457A477A487A4C7A557A567A597A5C7A5D7A5F7A607A657A677A6A7A6D7A75 7A787A7E7A807A827A857A867A8A7A8B7A907A917A947A9E7AA07AA37AAC7AB3 7AB57AB97ABB7ABC7AC67AC97ACC7ACE7AD17ADB7AE87AE97AEB7AEC7AF17AF4 7AFB7AFD7AFE7B077B147B1F7B237B277B297B2A7B2B7B2D7B2E7B2F7B300000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 52 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007B317B347B3D7B3F7B407B417B477B4E7B557B607B647B667B697B6A7B6D 7B6F7B727B737B777B847B897B8E7B907B917B967B9B7B9E7BA07BA57BAC7BAF 7BB07BB27BB57BB67BBA7BBB7BBC7BBD7BC27BC57BC87BCA7BD47BD67BD77BD9 7BDA7BDB7BE87BEA7BF27BF47BF57BF87BF97BFA7BFC7BFE7C017C027C037C04 7C067C097C0B7C0C7C0E7C0F7C197C1B7C207C257C267C287C2C7C317C337C34 7C367C397C3A7C467C4A7C557C517C527C537C597C5A7C5B7C5C7C5D7C5E0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 53 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007C617C637C677C697C6D7C6E7C707C727C797C7C7C7D7C867C877C8F7C94 7C9E7CA07CA67CB07CB67CB77CBA7CBB7CBC7CBF7CC47CC77CC87CC97CCD7CCF 7CD37CD47CD57CD77CD97CDA7CDD7CE67CE97CEB7CF57D037D077D087D097D0F 7D117D127D137D167D1D7D1E7D237D267D2A7D2D7D317D3C7D3D7D3E7D407D41 7D477D487D4D7D517D537D577D597D5A7D5C7D5D7D657D677D6A7D707D787D7A 7D7B7D7F7D817D827D837D857D867D887D8B7D8C7D8D7D917D967D977D9D0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 54 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007D9E7DA67DA77DAA7DB37DB67DB77DB97DC27DC37DC47DC57DC67DCC7DCD 7DCE7DD77DD97E007DE27DE57DE67DEA7DEB7DED7DF17DF57DF67DF97DFA7E08 7E107E117E157E177E1C7E1D7E207E277E287E2C7E2D7E2F7E337E367E3F7E44 7E457E477E4E7E507E527E587E5F7E617E627E657E6B7E6E7E6F7E737E787E7E 7E817E867E877E8A7E8D7E917E957E987E9A7E9D7E9E7F3C7F3B7F3D7F3E7F3F 7F437F447F477F4F7F527F537F5B7F5C7F5D7F617F637F647F657F667F6D0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 55 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007F717F7D7F7E7F7F7F807F8B7F8D7F8F7F907F917F967F977F9C7FA17FA2 7FA67FAA7FAD7FB47FBC7FBF7FC07FC37FC87FCE7FCF7FDB7FDF7FE37FE57FE8 7FEC7FEE7FEF7FF27FFA7FFD7FFE7FFF80078008800A800D800E800F80118013 80148016801D801E801F802080248026802C802E80308034803580378039803A 803C803E80408044806080648066806D8071807580818088808E809C809E80A6 80A780AB80B880B980C880CD80CF80D280D480D580D780D880E080ED80EE0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 56 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000080F080F280F380F680F980FA80FE8103810B811681178118811C811E8120 81248127812C81308135813A813C81458147814A814C81528157816081618167 81688169816D816F817781818190818481858186818B818E81968198819B819E 81A281AE81B281B481BB81CB81C381C581CA81CE81CF81D581D781DB81DD81DE 81E181E481EB81EC81F081F181F281F581F681F881F981FD81FF82008203820F 821382148219821A821D82218222822882328234823A82438244824582460000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 57 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000824B824E824F82518256825C826082638267826D8274827B827D827F8280 82818283828482878289828A828E8291829482968298829A829B82A082A182A3 82A482A782A882A982AA82AE82B082B282B482B782BA82BC82BE82BF82C682D0 82D582DA82E082E282E482E882EA82ED82EF82F682F782FD82FE830083018307 8308830A830B8354831B831D831E831F83218322832C832D832E833083338337 833A833C833D8342834383448347834D834E8351835583568357837083780000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 58 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000837D837F8380838283848386838D83928394839583988399839B839C839D 83A683A783A983AC83BE83BF83C083C783C983CF83D083D183D483DD835383E8 83EA83F683F883F983FC84018406840A840F84118415841983AD842F84398445 84478448844A844D844F84518452845684588459845A845C8460846484658467 846A84708473847484768478847C847D84818485849284938495849E84A684A8 84A984AA84AF84B184B484BA84BD84BE84C084C284C784C884CC84CF84D30000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 59 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000084DC84E784EA84EF84F084F184F284F7853284FA84FB84FD850285038507 850C850E8510851C851E85228523852485258527852A852B852F853385348536 853F8546854F855085518552855385568559855C855D855E855F856085618562 8564856B856F8579857A857B857D857F8581858585868589858B858C858F8593 8598859D859F85A085A285A585A785B485B685B785B885BC85BD85BE85BF85C2 85C785CA85CB85CE85AD85D885DA85DF85E085E685E885ED85F385F685FC0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5A 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000085FF860086048605860D860E86108611861286188619861B861E86218627 862986368638863A863C863D864086428646865286538656865786588659865D 866086618662866386648669866C866F867586768677867A868D869186968698 869A869C86A186A686A786A886AD86B186B386B486B586B786B886B986BF86C0 86C186C386C586D186D286D586D786DA86DC86E086E386E586E7868886FA86FC 86FD870487058707870B870E870F8710871387148719871E871F872187230000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5B 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008728872E872F873187328739873A873C873D873E874087438745874D8758 875D876187648765876F87718772877B8783878487858786878787888789878B 878C879087938795879787988799879E87A087A387A787AC87AD87AE87B187B5 87BE87BF87C187C887C987CA87CE87D587D687D987DA87DC87DF87E287E387E4 87EA87EB87ED87F187F387F887FA87FF8801880388068809880A880B88108819 8812881388148818881A881B881C881E881F8828882D882E8830883288350000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5C 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000883A883C88418843884588488849884A884B884E8851885588568858885A 885C885F88608864886988718879887B88808898889A889B889C889F88A088A8 88AA88BA88BD88BE88C088CA88CB88CC88CD88CE88D188D288D388DB88DE88E7 88EF88F088F188F588F789018906890D890E890F8915891689188919891A891C 892089268927892889308931893289358939893A893E89408942894589468949 894F89528957895A895B895C896189628963896B896E897089738975897A0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5D 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000897B897C897D8989898D899089948995899B899C899F89A089A589B089B4 89B589B689B789BC89D489D589D689D789D889E589E989EB89ED89F189F389F6 89F989FD89FF8A048A058A078A0F8A118A128A148A158A1E8A208A228A248A26 8A2B8A2C8A2F8A358A378A3D8A3E8A408A438A458A478A498A4D8A4E8A538A56 8A578A588A5C8A5D8A618A658A678A758A768A778A798A7A8A7B8A7E8A7F8A80 8A838A868A8B8A8F8A908A928A968A978A998A9F8AA78AA98AAE8AAF8AB30000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5E 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008AB68AB78ABB8ABE8AC38AC68AC88AC98ACA8AD18AD38AD48AD58AD78ADD 8ADF8AEC8AF08AF48AF58AF68AFC8AFF8B058B068B0B8B118B1C8B1E8B1F8B0A 8B2D8B308B378B3C8B428B438B448B458B468B488B528B538B548B598B4D8B5E 8B638B6D8B768B788B798B7C8B7E8B818B848B858B8B8B8D8B8F8B948B958B9C 8B9E8B9F8C388C398C3D8C3E8C458C478C498C4B8C4F8C518C538C548C578C58 8C5B8C5D8C598C638C648C668C688C698C6D8C738C758C768C7B8C7E8C860000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008C878C8B8C908C928C938C998C9B8C9C8CA48CB98CBA8CC58CC68CC98CCB 8CCF8CD68CD58CD98CDD8CE18CE88CEC8CEF8CF08CF28CF58CF78CF88CFE8CFF 8D018D038D098D128D178D1B8D658D698D6C8D6E8D7F8D828D848D888D8D8D90 8D918D958D9E8D9F8DA08DA68DAB8DAC8DAF8DB28DB58DB78DB98DBB8DC08DC5 8DC68DC78DC88DCA8DCE8DD18DD48DD58DD78DD98DE48DE58DE78DEC8DF08DBC 8DF18DF28DF48DFD8E018E048E058E068E0B8E118E148E168E208E218E220000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 60 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008E238E268E278E318E338E368E378E388E398E3D8E408E418E4B8E4D8E4E 8E4F8E548E5B8E5C8E5D8E5E8E618E628E698E6C8E6D8E6F8E708E718E798E7A 8E7B8E828E838E898E908E928E958E9A8E9B8E9D8E9E8EA28EA78EA98EAD8EAE 8EB38EB58EBA8EBB8EC08EC18EC38EC48EC78ECF8ED18ED48EDC8EE88EEE8EF0 8EF18EF78EF98EFA8EED8F008F028F078F088F0F8F108F168F178F188F1E8F20 8F218F238F258F278F288F2C8F2D8F2E8F348F358F368F378F3A8F408F410000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 61 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008F438F478F4F8F518F528F538F548F558F588F5D8F5E8F658F9D8FA08FA1 8FA48FA58FA68FB58FB68FB88FBE8FC08FC18FC68FCA8FCB8FCD8FD08FD28FD3 8FD58FE08FE38FE48FE88FEE8FF18FF58FF68FFB8FFE900290049008900C9018 901B90289029902F902A902C902D903390349037903F90439044904C905B905D 906290669067906C90709074907990859088908B908C908E9090909590979098 9099909B90A090A190A290A590B090B290B390B490B690BD90CC90BE90C30000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 62 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000090C490C590C790C890D590D790D890D990DC90DD90DF90E590D290F690EB 90EF90F090F490FE90FF91009104910591069108910D91109114911691179118 911A911C911E912091259122912391279129912E912F91319134913691379139 913A913C913D914391479148914F915391579159915A915B916191649167916D 91749179917A917B9181918391859186918A918E91919193919491959198919E 91A191A691A891AC91AD91AE91B091B191B291B391B691BB91BC91BD91BF0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 63 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000091C291C391C591D391D491D791D991DA91DE91E491E591E991EA91EC91ED 91EE91EF91F091F191F791F991FB91FD9200920192049205920692079209920A 920C92109212921392169218921C921D92239224922592269228922E922F9230 92339235923692389239923A923C923E92409242924392469247924A924D924E 924F925192589259925C925D926092619265926792689269926E926F92709275 9276927792789279927B927C927D927F92889289928A928D928E929292970000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 64 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009299929F92A092A492A592A792A892AB92AF92B292B692B892BA92BB92BC 92BD92BF92C092C192C292C392C592C692C792C892CB92CC92CD92CE92D092D3 92D592D792D892D992DC92DD92DF92E092E192E392E592E792E892EC92EE92F0 92F992FB92FF930093029308930D931193149315931C931D931E931F93219324 932593279329932A933393349336933793479348934993509351935293559357 9358935A935E9364936593679369936A936D936F937093719373937493760000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 65 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000937A937D937F9380938193829388938A938B938D938F939293959398939B 939E93A193A393A493A693A893AB93B493B593B693BA93A993C193C493C593C6 93C793C993CA93CB93CC93CD93D393D993DC93DE93DF93E293E693E793F993F7 93F893FA93FB93FD94019402940494089409940D940E940F941594169417941F 942E942F9431943294339434943B943F943D944394459448944A944C94559459 945C945F946194639468946B946D946E946F9471947294849483957895790000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 66 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000957E95849588958C958D958E959D959E959F95A195A695A995AB95AC95B4 95B695BA95BD95BF95C695C895C995CB95D095D195D295D395D995DA95DD95DE 95DF95E095E495E6961D961E9622962496259626962C96319633963796389639 963A963C963D9641965296549656965796589661966E9674967B967C967E967F 9681968296839684968996919696969A969D969F96A496A596A696A996AE96AF 96B396BA96CA96D25DB296D896DA96DD96DE96DF96E996EF96F196FA97020000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 67 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000970397059709971A971B971D97219722972397289731973397419743974A 974E974F975597579758975A975B97639767976A976E9773977697779778977B 977D977F978097899795979697979799979A979E979F97A297AC97AE97B197B2 97B597B697B897B997BA97BC97BE97BF97C197C497C597C797C997CA97CC97CD 97CE97D097D197D497D797D897D997DD97DE97E097DB97E197E497EF97F197F4 97F797F897FA9807980A9819980D980E98149816981C981E9820982398260000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 68 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000982B982E982F98309832983398359825983E98449847984A985198529853 985698579859985A9862986398659866986A986C98AB98AD98AE98B098B498B7 98B898BA98BB98BF98C298C598C898CC98E198E398E598E698E798EA98F398F6 9902990799089911991599169917991A991B991C991F992299269927992B9931 99329933993499359939993A993B993C99409941994699479948994D994E9954 99589959995B995C995E995F9960999B999D999F99A699B099B199B299B50000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 69 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000099B999BA99BD99BF99C399C999D399D499D999DA99DC99DE99E799EA99EB 99EC99F099F499F599F999FD99FE9A029A039A049A0B9A0C9A109A119A169A1E 9A209A229A239A249A279A2D9A2E9A339A359A369A389A479A419A449A4A9A4B 9A4C9A4E9A519A549A569A5D9AAA9AAC9AAE9AAF9AB29AB49AB59AB69AB99ABB 9ABE9ABF9AC19AC39AC69AC89ACE9AD09AD29AD59AD69AD79ADB9ADC9AE09AE4 9AE59AE79AE99AEC9AF29AF39AF59AF99AFA9AFD9AFF9B009B019B029B030000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6A 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009B049B059B089B099B0B9B0C9B0D9B0E9B109B129B169B199B1B9B1C9B20 9B269B2B9B2D9B339B349B359B379B399B3A9B3D9B489B4B9B4C9B559B569B57 9B5B9B5E9B619B639B659B669B689B6A9B6B9B6C9B6D9B6E9B739B759B779B78 9B799B7F9B809B849B859B869B879B899B8A9B8B9B8D9B8F9B909B949B9A9B9D 9B9E9BA69BA79BA99BAC9BB09BB19BB29BB79BB89BBB9BBC9BBE9BBF9BC19BC7 9BC89BCE9BD09BD79BD89BDD9BDF9BE59BE79BEA9BEB9BEF9BF39BF79BF80000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6B 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009BF99BFA9BFD9BFF9C009C029C0B9C0F9C119C169C189C199C1A9C1C9C1E 9C229C239C269C279C289C299C2A9C319C359C369C379C3D9C419C439C449C45 9C499C4A9C4E9C4F9C509C539C549C569C589C5B9C5D9C5E9C5F9C639C699C6A 9C5C9C6B9C689C6E9C709C729C759C779C7B9CE69CF29CF79CF99D0B9D029D11 9D179D189D1C9D1D9D1E9D2F9D309D329D339D349D3A9D3C9D459D3D9D429D43 9D479D4A9D539D549D5F9D639D629D659D699D6A9D6B9D709D769D779D7B0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6C 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009D7C9D7E9D839D849D869D8A9D8D9D8E9D929D939D959D969D979D989DA1 9DAA9DAC9DAE9DB19DB59DB99DBC9DBF9DC39DC79DC99DCA9DD49DD59DD69DD7 9DDA9DDE9DDF9DE09DE59DE79DE99DEB9DEE9DF09DF39DF49DFE9E0A9E029E07 9E0E9E109E119E129E159E169E199E1C9E1D9E7A9E7B9E7C9E809E829E839E84 9E859E879E8E9E8F9E969E989E9B9E9E9EA49EA89EAC9EAE9EAF9EB09EB39EB4 9EB59EC69EC89ECB9ED59EDF9EE49EE79EEC9EED9EEE9EF09EF19EF29EF50000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6D 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009EF89EFF9F029F039F099F0F9F109F119F129F149F169F179F199F1A9F1B 9F1F9F229F269F2A9F2B9F2F9F319F329F349F379F399F3A9F3C9F3D9F3F9F41 9F439F449F459F469F479F539F559F569F579F589F5A9F5D9F5E9F689F699F6D 9F6E9F6F9F709F719F739F759F7A9F7D9F8F9F909F919F929F949F969F979F9E 9FA19FA29FA39FA5000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 tcl8.4.20/library/encoding/iso8859-16.enc0000644003604700454610000000210711737050674016214 0ustar dgp771div# Encoding file: iso8859-16, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 0080008100820083008400850086008700880089008A008B008C008D008E008F 0090009100920093009400950096009700980099009A009B009C009D009E009F 00A001040105014120AC201E016000A7016100A9021800AB017900AD017A017B 00B000B1010C0142017D201D00B600B7017E010D021900BB015201530178017C 00C000C100C2010200C4010600C600C700C800C900CA00CB00CC00CD00CE00CF 0110014300D200D300D4015000D6015A017000D900DA00DB00DC0118021A00DF 00E000E100E2010300E4010700E600E700E800E900EA00EB00EC00ED00EE00EF 0111014400F200F300F4015100F6015B017100F900FA00FB00FC0119021B00FF tcl8.4.20/library/encoding/iso8859-4.enc0000644003604700454610000000210611737050674016130 0ustar dgp771div# Encoding file: iso8859-4, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 0080008100820083008400850086008700880089008A008B008C008D008E008F 0090009100920093009400950096009700980099009A009B009C009D009E009F 00A001040138015600A40128013B00A700A8016001120122016600AD017D00AF 00B0010502DB015700B40129013C02C700B80161011301230167014A017E014B 010000C100C200C300C400C500C6012E010C00C9011800CB011600CD00CE012A 01100145014C013600D400D500D600D700D8017200DA00DB00DC0168016A00DF 010100E100E200E300E400E500E6012F010D00E9011900EB011700ED00EE012B 01110146014D013700F400F500F600F700F8017300FA00FB00FC0169016B02D9 tcl8.4.20/library/encoding/iso8859-3.enc0000644003604700454610000000210611737050674016127 0ustar dgp771div# Encoding file: iso8859-3, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 0080008100820083008400850086008700880089008A008B008C008D008E008F 0090009100920093009400950096009700980099009A009B009C009D009E009F 00A0012602D800A300A40000012400A700A80130015E011E013400AD0000017B 00B0012700B200B300B400B5012500B700B80131015F011F013500BD0000017C 00C000C100C2000000C4010A010800C700C800C900CA00CB00CC00CD00CE00CF 000000D100D200D300D4012000D600D7011C00D900DA00DB00DC016C015C00DF 00E000E100E2000000E4010B010900E700E800E900EA00EB00EC00ED00EE00EF 000000F100F200F300F4012100F600F7011D00F900FA00FB00FC016D015D02D9 tcl8.4.20/library/encoding/cp850.enc0000644003604700454610000000210211737050674015472 0ustar dgp771div# Encoding file: cp850, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 00C700FC00E900E200E400E000E500E700EA00EB00E800EF00EE00EC00C400C5 00C900E600C600F400F600F200FB00F900FF00D600DC00F800A300D800D70192 00E100ED00F300FA00F100D100AA00BA00BF00AE00AC00BD00BC00A100AB00BB 2591259225932502252400C100C200C000A9256325512557255D00A200A52510 25142534252C251C2500253C00E300C3255A25542569256625602550256C00A4 00F000D000CA00CB00C8013100CD00CE00CF2518250C2588258400A600CC2580 00D300DF00D400D200F500D500B500FE00DE00DA00DB00D900FD00DD00AF00B4 00AD00B1201700BE00B600A700F700B800B000A800B700B900B300B225A000A0 tcl8.4.20/library/encoding/iso8859-5.enc0000644003604700454610000000210611737050674016131 0ustar dgp771div# Encoding file: iso8859-5, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 0080008100820083008400850086008700880089008A008B008C008D008E008F 0090009100920093009400950096009700980099009A009B009C009D009E009F 00A0040104020403040404050406040704080409040A040B040C00AD040E040F 0410041104120413041404150416041704180419041A041B041C041D041E041F 0420042104220423042404250426042704280429042A042B042C042D042E042F 0430043104320433043404350436043704380439043A043B043C043D043E043F 0440044104420443044404450446044704480449044A044B044C044D044E044F 2116045104520453045404550456045704580459045A045B045C00A7045E045F tcl8.4.20/library/encoding/macThai.enc0000644003604700454610000000210411737050674016203 0ustar dgp771div# Encoding file: macThai, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 00AB00BB2026F88CF88FF892F895F898F88BF88EF891F894F897201C201DF899 FFFD2022F884F889F885F886F887F888F88AF88DF890F893F89620182019FFFD 00A00E010E020E030E040E050E060E070E080E090E0A0E0B0E0C0E0D0E0E0E0F 0E100E110E120E130E140E150E160E170E180E190E1A0E1B0E1C0E1D0E1E0E1F 0E200E210E220E230E240E250E260E270E280E290E2A0E2B0E2C0E2D0E2E0E2F 0E300E310E320E330E340E350E360E370E380E390E3AFEFF200B201320140E3F 0E400E410E420E430E440E450E460E470E480E490E4A0E4B0E4C0E4D21220E4F 0E500E510E520E530E540E550E560E570E580E5900AE00A9FFFDFFFDFFFDFFFD tcl8.4.20/library/encoding/macCyrillic.enc0000644003604700454610000000211011737050674017065 0ustar dgp771div# Encoding file: macCyrillic, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 0410041104120413041404150416041704180419041A041B041C041D041E041F 0420042104220423042404250426042704280429042A042B042C042D042E042F 202000B0049000A300A7202200B6040600AE00A9212204020452226004030453 221E00B122642265045600B504910408040404540407045704090459040A045A 0458040500AC221A01922248220600AB00BB202600A0040B045B040C045C0455 20132014201C201D2018201900F7201E040E045E040F045F211604010451044F 0430043104320433043404350436043704380439043A043B043C043D043E043F 0440044104420443044404450446044704480449044A044B044C044D044E20AC tcl8.4.20/library/encoding/cp874.enc0000644003604700454610000000210211737050674015500 0ustar dgp771div# Encoding file: cp874, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 20AC008100820083008420260086008700880089008A008B008C008D008E008F 009020182019201C201D20222013201400980099009A009B009C009D009E009F 00A00E010E020E030E040E050E060E070E080E090E0A0E0B0E0C0E0D0E0E0E0F 0E100E110E120E130E140E150E160E170E180E190E1A0E1B0E1C0E1D0E1E0E1F 0E200E210E220E230E240E250E260E270E280E290E2A0E2B0E2C0E2D0E2E0E2F 0E300E310E320E330E340E350E360E370E380E390E3A00000000000000000E3F 0E400E410E420E430E440E450E460E470E480E490E4A0E4B0E4C0E4D0E4E0E4F 0E500E510E520E530E540E550E560E570E580E590E5A0E5B0000000000000000 tcl8.4.20/library/encoding/cp862.enc0000644003604700454610000000210211737050674015475 0ustar dgp771div# Encoding file: cp862, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 05D005D105D205D305D405D505D605D705D805D905DA05DB05DC05DD05DE05DF 05E005E105E205E305E405E505E605E705E805E905EA00A200A300A520A70192 00E100ED00F300FA00F100D100AA00BA00BF231000AC00BD00BC00A100AB00BB 259125922593250225242561256225562555256325512557255D255C255B2510 25142534252C251C2500253C255E255F255A25542569256625602550256C2567 2568256425652559255825522553256B256A2518250C25882584258C25902580 03B100DF039303C003A303C300B503C403A6039803A903B4221E03C603B52229 226100B1226522642320232100F7224800B0221900B7221A207F00B225A000A0 tcl8.4.20/library/encoding/macUkraine.enc0000644003604700454610000000210711737050674016717 0ustar dgp771div# Encoding file: macUkraine, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 0410041104120413041404150416041704180419041A041B041C041D041E041F 0420042104220423042404250426042704280429042A042B042C042D042E042F 202000B0049000A300A7202200B6040600AE00A9212204020452226004030453 221E00B122642265045600B504910408040404540407045704090459040A045A 0458040500AC221A01922248220600AB00BB202600A0040B045B040C045C0455 20132014201C201D2018201900F7201E040E045E040F045F211604010451044F 0430043104320433043404350436043704380439043A043B043C043D043E043F 0440044104420443044404450446044704480449044A044B044C044D044E00A4 tcl8.4.20/library/encoding/cp936.enc0000644003604700454610000040263511737050674015516 0ustar dgp771div# Encoding file: cp936, multi-byte M 003F 0 127 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 20AC000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 81 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 4E024E044E054E064E0F4E124E174E1F4E204E214E234E264E294E2E4E2F4E31 4E334E354E374E3C4E404E414E424E444E464E4A4E514E554E574E5A4E5B4E62 4E634E644E654E674E684E6A4E6B4E6C4E6D4E6E4E6F4E724E744E754E764E77 4E784E794E7A4E7B4E7C4E7D4E7F4E804E814E824E834E844E854E874E8A0000 4E904E964E974E994E9C4E9D4E9E4EA34EAA4EAF4EB04EB14EB44EB64EB74EB8 4EB94EBC4EBD4EBE4EC84ECC4ECF4ED04ED24EDA4EDB4EDC4EE04EE24EE64EE7 4EE94EED4EEE4EEF4EF14EF44EF84EF94EFA4EFC4EFE4F004F024F034F044F05 4F064F074F084F0B4F0C4F124F134F144F154F164F1C4F1D4F214F234F284F29 4F2C4F2D4F2E4F314F334F354F374F394F3B4F3E4F3F4F404F414F424F444F45 4F474F484F494F4A4F4B4F4C4F524F544F564F614F624F664F684F6A4F6B4F6D 4F6E4F714F724F754F774F784F794F7A4F7D4F804F814F824F854F864F874F8A 4F8C4F8E4F904F924F934F954F964F984F994F9A4F9C4F9E4F9F4FA14FA20000 82 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 4FA44FAB4FAD4FB04FB14FB24FB34FB44FB64FB74FB84FB94FBA4FBB4FBC4FBD 4FBE4FC04FC14FC24FC64FC74FC84FC94FCB4FCC4FCD4FD24FD34FD44FD54FD6 4FD94FDB4FE04FE24FE44FE54FE74FEB4FEC4FF04FF24FF44FF54FF64FF74FF9 4FFB4FFC4FFD4FFF5000500150025003500450055006500750085009500A0000 500B500E501050115013501550165017501B501D501E50205022502350245027 502B502F5030503150325033503450355036503750385039503B503D503F5040 504150425044504550465049504A504B504D5050505150525053505450565057 50585059505B505D505E505F506050615062506350645066506750685069506A 506B506D506E506F50705071507250735074507550785079507A507C507D5081 508250835084508650875089508A508B508C508E508F50905091509250935094 50955096509750985099509A509B509C509D509E509F50A050A150A250A450A6 50AA50AB50AD50AE50AF50B050B150B350B450B550B650B750B850B950BC0000 83 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 50BD50BE50BF50C050C150C250C350C450C550C650C750C850C950CA50CB50CC 50CD50CE50D050D150D250D350D450D550D750D850D950DB50DC50DD50DE50DF 50E050E150E250E350E450E550E850E950EA50EB50EF50F050F150F250F450F6 50F750F850F950FA50FC50FD50FE50FF51005101510251035104510551080000 5109510A510C510D510E510F511051115113511451155116511751185119511A 511B511C511D511E511F512051225123512451255126512751285129512A512B 512C512D512E512F5130513151325133513451355136513751385139513A513B 513C513D513E51425147514A514C514E514F515051525153515751585159515B 515D515E515F5160516151635164516651675169516A516F5172517A517E517F 5183518451865187518A518B518E518F51905191519351945198519A519D519E 519F51A151A351A651A751A851A951AA51AD51AE51B451B851B951BA51BE51BF 51C151C251C351C551C851CA51CD51CE51D051D251D351D451D551D651D70000 84 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 51D851D951DA51DC51DE51DF51E251E351E551E651E751E851E951EA51EC51EE 51F151F251F451F751FE520452055209520B520C520F5210521352145215521C 521E521F522152225223522552265227522A522C522F5231523252345235523C 523E524452455246524752485249524B524E524F525252535255525752580000 5259525A525B525D525F526052625263526452665268526B526C526D526E5270 52715273527452755276527752785279527A527B527C527E5280528352845285 528652875289528A528B528C528D528E528F5291529252945295529652975298 5299529A529C52A452A552A652A752AE52AF52B052B452B552B652B752B852B9 52BA52BB52BC52BD52C052C152C252C452C552C652C852CA52CC52CD52CE52CF 52D152D352D452D552D752D952DA52DB52DC52DD52DE52E052E152E252E352E5 52E652E752E852E952EA52EB52EC52ED52EE52EF52F152F252F352F452F552F6 52F752F852FB52FC52FD530153025303530453075309530A530B530C530E0000 85 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 53115312531353145318531B531C531E531F532253245325532753285329532B 532C532D532F533053315332533353345335533653375338533C533D53405342 53445346534B534C534D5350535453585359535B535D53655368536A536C536D 537253765379537B537C537D537E53805381538353875388538A538E538F0000 53905391539253935394539653975399539B539C539E53A053A153A453A753AA 53AB53AC53AD53AF53B053B153B253B353B453B553B753B853B953BA53BC53BD 53BE53C053C353C453C553C653C753CE53CF53D053D253D353D553DA53DC53DD 53DE53E153E253E753F453FA53FE53FF5400540254055407540B541454185419 541A541C542254245425542A5430543354365437543A543D543F544154425444 544554475449544C544D544E544F5451545A545D545E545F5460546154635465 54675469546A546B546C546D546E546F547054745479547A547E547F54815483 5485548754885489548A548D5491549354975498549C549E549F54A054A10000 86 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 54A254A554AE54B054B254B554B654B754B954BA54BC54BE54C354C554CA54CB 54D654D854DB54E054E154E254E354E454EB54EC54EF54F054F154F454F554F6 54F754F854F954FB54FE550055025503550455055508550A550B550C550D550E 5512551355155516551755185519551A551C551D551E551F5521552555260000 55285529552B552D553255345535553655385539553A553B553D554055425545 55475548554B554C554D554E554F5551555255535554555755585559555A555B 555D555E555F55605562556355685569556B556F557055715572557355745579 557A557D557F55855586558C558D558E559055925593559555965597559A559B 559E55A055A155A255A355A455A555A655A855A955AA55AB55AC55AD55AE55AF 55B055B255B455B655B855BA55BC55BF55C055C155C255C355C655C755C855CA 55CB55CE55CF55D055D555D755D855D955DA55DB55DE55E055E255E755E955ED 55EE55F055F155F455F655F855F955FA55FB55FC55FF56025603560456050000 87 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 56065607560A560B560D561056115612561356145615561656175619561A561C 561D5620562156225625562656285629562A562B562E562F5630563356355637 5638563A563C563D563E5640564156425643564456455646564756485649564A 564B564F565056515652565356555656565A565B565D565E565F566056610000 5663566556665667566D566E566F56705672567356745675567756785679567A 567D567E567F56805681568256835684568756885689568A568B568C568D5690 56915692569456955696569756985699569A569B569C569D569E569F56A056A1 56A256A456A556A656A756A856A956AA56AB56AC56AD56AE56B056B156B256B3 56B456B556B656B856B956BA56BB56BD56BE56BF56C056C156C256C356C456C5 56C656C756C856C956CB56CC56CD56CE56CF56D056D156D256D356D556D656D8 56D956DC56E356E556E656E756E856E956EA56EC56EE56EF56F256F356F656F7 56F856FB56FC57005701570257055707570B570C570D570E570F571057110000 88 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 57125713571457155716571757185719571A571B571D571E5720572157225724 572557265727572B5731573257345735573657375738573C573D573F57415743 57445745574657485749574B5752575357545755575657585759576257635765 5767576C576E5770577157725774577557785779577A577D577E577F57800000 5781578757885789578A578D578E578F57905791579457955796579757985799 579A579C579D579E579F57A557A857AA57AC57AF57B057B157B357B557B657B7 57B957BA57BB57BC57BD57BE57BF57C057C157C457C557C657C757C857C957CA 57CC57CD57D057D157D357D657D757DB57DC57DE57E157E257E357E557E657E7 57E857E957EA57EB57EC57EE57F057F157F257F357F557F657F757FB57FC57FE 57FF580158035804580558085809580A580C580E580F58105812581358145816 58175818581A581B581C581D581F5822582358255826582758285829582B582C 582D582E582F58315832583358345836583758385839583A583B583C583D0000 89 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 583E583F584058415842584358455846584758485849584A584B584E584F5850 585258535855585658575859585A585B585C585D585F58605861586258635864 5866586758685869586A586D586E586F58705871587258735874587558765877 58785879587A587B587C587D587F58825884588658875888588A588B588C0000 588D588E588F5890589158945895589658975898589B589C589D58A058A158A2 58A358A458A558A658A758AA58AB58AC58AD58AE58AF58B058B158B258B358B4 58B558B658B758B858B958BA58BB58BD58BE58BF58C058C258C358C458C658C7 58C858C958CA58CB58CC58CD58CE58CF58D058D258D358D458D658D758D858D9 58DA58DB58DC58DD58DE58DF58E058E158E258E358E558E658E758E858E958EA 58ED58EF58F158F258F458F558F758F858FA58FB58FC58FD58FE58FF59005901 59035905590659085909590A590B590C590E591059115912591359175918591B 591D591E592059215922592359265928592C59305932593359355936593B0000 8A 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 593D593E593F5940594359455946594A594C594D5950595259535959595B595C 595D595E595F5961596359645966596759685969596A596B596C596D596E596F 59705971597259755977597A597B597C597E597F598059855989598B598C598E 598F59905991599459955998599A599B599C599D599F59A059A159A259A60000 59A759AC59AD59B059B159B359B459B559B659B759B859BA59BC59BD59BF59C0 59C159C259C359C459C559C759C859C959CC59CD59CE59CF59D559D659D959DB 59DE59DF59E059E159E259E459E659E759E959EA59EB59ED59EE59EF59F059F1 59F259F359F459F559F659F759F859FA59FC59FD59FE5A005A025A0A5A0B5A0D 5A0E5A0F5A105A125A145A155A165A175A195A1A5A1B5A1D5A1E5A215A225A24 5A265A275A285A2A5A2B5A2C5A2D5A2E5A2F5A305A335A355A375A385A395A3A 5A3B5A3D5A3E5A3F5A415A425A435A445A455A475A485A4B5A4C5A4D5A4E5A4F 5A505A515A525A535A545A565A575A585A595A5B5A5C5A5D5A5E5A5F5A600000 8B 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5A615A635A645A655A665A685A695A6B5A6C5A6D5A6E5A6F5A705A715A725A73 5A785A795A7B5A7C5A7D5A7E5A805A815A825A835A845A855A865A875A885A89 5A8A5A8B5A8C5A8D5A8E5A8F5A905A915A935A945A955A965A975A985A995A9C 5A9D5A9E5A9F5AA05AA15AA25AA35AA45AA55AA65AA75AA85AA95AAB5AAC0000 5AAD5AAE5AAF5AB05AB15AB45AB65AB75AB95ABA5ABB5ABC5ABD5ABF5AC05AC3 5AC45AC55AC65AC75AC85ACA5ACB5ACD5ACE5ACF5AD05AD15AD35AD55AD75AD9 5ADA5ADB5ADD5ADE5ADF5AE25AE45AE55AE75AE85AEA5AEC5AED5AEE5AEF5AF0 5AF25AF35AF45AF55AF65AF75AF85AF95AFA5AFB5AFC5AFD5AFE5AFF5B005B01 5B025B035B045B055B065B075B085B0A5B0B5B0C5B0D5B0E5B0F5B105B115B12 5B135B145B155B185B195B1A5B1B5B1C5B1D5B1E5B1F5B205B215B225B235B24 5B255B265B275B285B295B2A5B2B5B2C5B2D5B2E5B2F5B305B315B335B355B36 5B385B395B3A5B3B5B3C5B3D5B3E5B3F5B415B425B435B445B455B465B470000 8C 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5B485B495B4A5B4B5B4C5B4D5B4E5B4F5B525B565B5E5B605B615B675B685B6B 5B6D5B6E5B6F5B725B745B765B775B785B795B7B5B7C5B7E5B7F5B825B865B8A 5B8D5B8E5B905B915B925B945B965B9F5BA75BA85BA95BAC5BAD5BAE5BAF5BB1 5BB25BB75BBA5BBB5BBC5BC05BC15BC35BC85BC95BCA5BCB5BCD5BCE5BCF0000 5BD15BD45BD55BD65BD75BD85BD95BDA5BDB5BDC5BE05BE25BE35BE65BE75BE9 5BEA5BEB5BEC5BED5BEF5BF15BF25BF35BF45BF55BF65BF75BFD5BFE5C005C02 5C035C055C075C085C0B5C0C5C0D5C0E5C105C125C135C175C195C1B5C1E5C1F 5C205C215C235C265C285C295C2A5C2B5C2D5C2E5C2F5C305C325C335C355C36 5C375C435C445C465C475C4C5C4D5C525C535C545C565C575C585C5A5C5B5C5C 5C5D5C5F5C625C645C675C685C695C6A5C6B5C6C5C6D5C705C725C735C745C75 5C765C775C785C7B5C7C5C7D5C7E5C805C835C845C855C865C875C895C8A5C8B 5C8E5C8F5C925C935C955C9D5C9E5C9F5CA05CA15CA45CA55CA65CA75CA80000 8D 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5CAA5CAE5CAF5CB05CB25CB45CB65CB95CBA5CBB5CBC5CBE5CC05CC25CC35CC5 5CC65CC75CC85CC95CCA5CCC5CCD5CCE5CCF5CD05CD15CD35CD45CD55CD65CD7 5CD85CDA5CDB5CDC5CDD5CDE5CDF5CE05CE25CE35CE75CE95CEB5CEC5CEE5CEF 5CF15CF25CF35CF45CF55CF65CF75CF85CF95CFA5CFC5CFD5CFE5CFF5D000000 5D015D045D055D085D095D0A5D0B5D0C5D0D5D0F5D105D115D125D135D155D17 5D185D195D1A5D1C5D1D5D1F5D205D215D225D235D255D285D2A5D2B5D2C5D2F 5D305D315D325D335D355D365D375D385D395D3A5D3B5D3C5D3F5D405D415D42 5D435D445D455D465D485D495D4D5D4E5D4F5D505D515D525D535D545D555D56 5D575D595D5A5D5C5D5E5D5F5D605D615D625D635D645D655D665D675D685D6A 5D6D5D6E5D705D715D725D735D755D765D775D785D795D7A5D7B5D7C5D7D5D7E 5D7F5D805D815D835D845D855D865D875D885D895D8A5D8B5D8C5D8D5D8E5D8F 5D905D915D925D935D945D955D965D975D985D9A5D9B5D9C5D9E5D9F5DA00000 8E 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5DA15DA25DA35DA45DA55DA65DA75DA85DA95DAA5DAB5DAC5DAD5DAE5DAF5DB0 5DB15DB25DB35DB45DB55DB65DB85DB95DBA5DBB5DBC5DBD5DBE5DBF5DC05DC1 5DC25DC35DC45DC65DC75DC85DC95DCA5DCB5DCC5DCE5DCF5DD05DD15DD25DD3 5DD45DD55DD65DD75DD85DD95DDA5DDC5DDF5DE05DE35DE45DEA5DEC5DED0000 5DF05DF55DF65DF85DF95DFA5DFB5DFC5DFF5E005E045E075E095E0A5E0B5E0D 5E0E5E125E135E175E1E5E1F5E205E215E225E235E245E255E285E295E2A5E2B 5E2C5E2F5E305E325E335E345E355E365E395E3A5E3E5E3F5E405E415E435E46 5E475E485E495E4A5E4B5E4D5E4E5E4F5E505E515E525E535E565E575E585E59 5E5A5E5C5E5D5E5F5E605E635E645E655E665E675E685E695E6A5E6B5E6C5E6D 5E6E5E6F5E705E715E755E775E795E7E5E815E825E835E855E885E895E8C5E8D 5E8E5E925E985E9B5E9D5EA15EA25EA35EA45EA85EA95EAA5EAB5EAC5EAE5EAF 5EB05EB15EB25EB45EBA5EBB5EBC5EBD5EBF5EC05EC15EC25EC35EC45EC50000 8F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5EC65EC75EC85ECB5ECC5ECD5ECE5ECF5ED05ED45ED55ED75ED85ED95EDA5EDC 5EDD5EDE5EDF5EE05EE15EE25EE35EE45EE55EE65EE75EE95EEB5EEC5EED5EEE 5EEF5EF05EF15EF25EF35EF55EF85EF95EFB5EFC5EFD5F055F065F075F095F0C 5F0D5F0E5F105F125F145F165F195F1A5F1C5F1D5F1E5F215F225F235F240000 5F285F2B5F2C5F2E5F305F325F335F345F355F365F375F385F3B5F3D5F3E5F3F 5F415F425F435F445F455F465F475F485F495F4A5F4B5F4C5F4D5F4E5F4F5F51 5F545F595F5A5F5B5F5C5F5E5F5F5F605F635F655F675F685F6B5F6E5F6F5F72 5F745F755F765F785F7A5F7D5F7E5F7F5F835F865F8D5F8E5F8F5F915F935F94 5F965F9A5F9B5F9D5F9E5F9F5FA05FA25FA35FA45FA55FA65FA75FA95FAB5FAC 5FAF5FB05FB15FB25FB35FB45FB65FB85FB95FBA5FBB5FBE5FBF5FC05FC15FC2 5FC75FC85FCA5FCB5FCE5FD35FD45FD55FDA5FDB5FDC5FDE5FDF5FE25FE35FE5 5FE65FE85FE95FEC5FEF5FF05FF25FF35FF45FF65FF75FF95FFA5FFC60070000 90 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 60086009600B600C60106011601360176018601A601E601F602260236024602C 602D602E603060316032603360346036603760386039603A603D603E60406044 60456046604760486049604A604C604E604F605160536054605660576058605B 605C605E605F6060606160656066606E60716072607460756077607E60800000 608160826085608660876088608A608B608E608F609060916093609560976098 6099609C609E60A160A260A460A560A760A960AA60AE60B060B360B560B660B7 60B960BA60BD60BE60BF60C060C160C260C360C460C760C860C960CC60CD60CE 60CF60D060D260D360D460D660D760D960DB60DE60E160E260E360E460E560EA 60F160F260F560F760F860FB60FC60FD60FE60FF61026103610461056107610A 610B610C611061116112611361146116611761186119611B611C611D611E6121 6122612561286129612A612C612D612E612F6130613161326133613461356136 613761386139613A613B613C613D613E61406141614261436144614561460000 91 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 61476149614B614D614F61506152615361546156615761586159615A615B615C 615E615F6160616161636164616561666169616A616B616C616D616E616F6171 617261736174617661786179617A617B617C617D617E617F6180618161826183 618461856186618761886189618A618C618D618F619061916192619361950000 6196619761986199619A619B619C619E619F61A061A161A261A361A461A561A6 61AA61AB61AD61AE61AF61B061B161B261B361B461B561B661B861B961BA61BB 61BC61BD61BF61C061C161C361C461C561C661C761C961CC61CD61CE61CF61D0 61D361D561D661D761D861D961DA61DB61DC61DD61DE61DF61E061E161E261E3 61E461E561E761E861E961EA61EB61EC61ED61EE61EF61F061F161F261F361F4 61F661F761F861F961FA61FB61FC61FD61FE6200620162026203620462056207 6209621362146219621C621D621E622062236226622762286229622B622D622F 6230623162326235623662386239623A623B623C6242624462456246624A0000 92 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 624F62506255625662576259625A625C625D625E625F62606261626262646265 6268627162726274627562776278627A627B627D628162826283628562866287 6288628B628C628D628E628F629062946299629C629D629E62A362A662A762A9 62AA62AD62AE62AF62B062B262B362B462B662B762B862BA62BE62C062C10000 62C362CB62CF62D162D562DD62DE62E062E162E462EA62EB62F062F262F562F8 62F962FA62FB63006303630463056306630A630B630C630D630F631063126313 63146315631763186319631C632663276329632C632D632E6330633163336334 6335633663376338633B633C633E633F63406341634463476348634A63516352 635363546356635763586359635A635B635C635D63606364636563666368636A 636B636C636F6370637263736374637563786379637C637D637E637F63816383 638463856386638B638D639163936394639563976399639A639B639C639D639E 639F63A163A463A663AB63AF63B163B263B563B663B963BB63BD63BF63C00000 93 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 63C163C263C363C563C763C863CA63CB63CC63D163D363D463D563D763D863D9 63DA63DB63DC63DD63DF63E263E463E563E663E763E863EB63EC63EE63EF63F0 63F163F363F563F763F963FA63FB63FC63FE640364046406640764086409640A 640D640E6411641264156416641764186419641A641D641F6422642364240000 6425642764286429642B642E642F643064316432643364356436643764386439 643B643C643E6440644264436449644B644C644D644E644F6450645164536455 645664576459645A645B645C645D645F64606461646264636464646564666468 646A646B646C646E646F64706471647264736474647564766477647B647C647D 647E647F648064816483648664886489648A648B648C648D648E648F64906493 649464976498649A649B649C649D649F64A064A164A264A364A564A664A764A8 64AA64AB64AF64B164B264B364B464B664B964BB64BD64BE64BF64C164C364C4 64C664C764C864C964CA64CB64CC64CF64D164D364D464D564D664D964DA0000 94 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 64DB64DC64DD64DF64E064E164E364E564E764E864E964EA64EB64EC64ED64EE 64EF64F064F164F264F364F464F564F664F764F864F964FA64FB64FC64FD64FE 64FF65016502650365046505650665076508650A650B650C650D650E650F6510 6511651365146515651665176519651A651B651C651D651E651F652065210000 6522652365246526652765286529652A652C652D65306531653265336537653A 653C653D6540654165426543654465466547654A654B654D654E655065526553 655465576558655A655C655F6560656165646565656765686569656A656D656E 656F657165736575657665786579657A657B657C657D657E657F658065816582 658365846585658665886589658A658D658E658F65926594659565966598659A 659D659E65A065A265A365A665A865AA65AC65AE65B165B265B365B465B565B6 65B765B865BA65BB65BE65BF65C065C265C765C865C965CA65CD65D065D165D3 65D465D565D865D965DA65DB65DC65DD65DE65DF65E165E365E465EA65EB0000 95 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 65F265F365F465F565F865F965FB65FC65FD65FE65FF66016604660566076608 6609660B660D661066116612661666176618661A661B661C661E662166226623 662466266629662A662B662C662E663066326633663766386639663A663B663D 663F66406642664466456646664766486649664A664D664E6650665166580000 6659665B665C665D665E666066626663666566676669666A666B666C666D6671 66726673667566786679667B667C667D667F6680668166836685668666886689 668A668B668D668E668F6690669266936694669566986699669A669B669C669E 669F66A066A166A266A366A466A566A666A966AA66AB66AC66AD66AF66B066B1 66B266B366B566B666B766B866BA66BB66BC66BD66BF66C066C166C266C366C4 66C566C666C766C866C966CA66CB66CC66CD66CE66CF66D066D166D266D366D4 66D566D666D766D866DA66DE66DF66E066E166E266E366E466E566E766E866EA 66EB66EC66ED66EE66EF66F166F566F666F866FA66FB66FD6701670267030000 96 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6704670567066707670C670E670F671167126713671667186719671A671C671E 67206721672267236724672567276729672E6730673267336736673767386739 673B673C673E673F6741674467456747674A674B674D67526754675567576758 6759675A675B675D67626763676467666767676B676C676E6771677467760000 67786779677A677B677D678067826783678567866788678A678C678D678E678F 679167926793679467966799679B679F67A067A167A467A667A967AC67AE67B1 67B267B467B967BA67BB67BC67BD67BE67BF67C067C267C567C667C767C867C9 67CA67CB67CC67CD67CE67D567D667D767DB67DF67E167E367E467E667E767E8 67EA67EB67ED67EE67F267F567F667F767F867F967FA67FB67FC67FE68016802 680368046806680D681068126814681568186819681A681B681C681E681F6820 6822682368246825682668276828682B682C682D682E682F6830683168346835 6836683A683B683F6847684B684D684F68526856685768586859685A685B0000 97 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 685C685D685E685F686A686C686D686E686F6870687168726873687568786879 687A687B687C687D687E687F688068826884688768886889688A688B688C688D 688E68906891689268946895689668986899689A689B689C689D689E689F68A0 68A168A368A468A568A968AA68AB68AC68AE68B168B268B468B668B768B80000 68B968BA68BB68BC68BD68BE68BF68C168C368C468C568C668C768C868CA68CC 68CE68CF68D068D168D368D468D668D768D968DB68DC68DD68DE68DF68E168E2 68E468E568E668E768E868E968EA68EB68EC68ED68EF68F268F368F468F668F7 68F868FB68FD68FE68FF69006902690369046906690769086909690A690C690F 69116913691469156916691769186919691A691B691C691D691E692169226923 69256926692769286929692A692B692C692E692F693169326933693569366937 6938693A693B693C693E694069416943694469456946694769486949694A694B 694C694D694E694F69506951695269536955695669586959695B695C695F0000 98 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6961696269646965696769686969696A696C696D696F69706972697369746975 6976697A697B697D697E697F698169836985698A698B698C698E698F69906991 69926993699669976999699A699D699E699F69A069A169A269A369A469A569A6 69A969AA69AC69AE69AF69B069B269B369B569B669B869B969BA69BC69BD0000 69BE69BF69C069C269C369C469C569C669C769C869C969CB69CD69CF69D169D2 69D369D569D669D769D869D969DA69DC69DD69DE69E169E269E369E469E569E6 69E769E869E969EA69EB69EC69EE69EF69F069F169F369F469F569F669F769F8 69F969FA69FB69FC69FE6A006A016A026A036A046A056A066A076A086A096A0B 6A0C6A0D6A0E6A0F6A106A116A126A136A146A156A166A196A1A6A1B6A1C6A1D 6A1E6A206A226A236A246A256A266A276A296A2B6A2C6A2D6A2E6A306A326A33 6A346A366A376A386A396A3A6A3B6A3C6A3F6A406A416A426A436A456A466A48 6A496A4A6A4B6A4C6A4D6A4E6A4F6A516A526A536A546A556A566A576A5A0000 99 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6A5C6A5D6A5E6A5F6A606A626A636A646A666A676A686A696A6A6A6B6A6C6A6D 6A6E6A6F6A706A726A736A746A756A766A776A786A7A6A7B6A7D6A7E6A7F6A81 6A826A836A856A866A876A886A896A8A6A8B6A8C6A8D6A8F6A926A936A946A95 6A966A986A996A9A6A9B6A9C6A9D6A9E6A9F6AA16AA26AA36AA46AA56AA60000 6AA76AA86AAA6AAD6AAE6AAF6AB06AB16AB26AB36AB46AB56AB66AB76AB86AB9 6ABA6ABB6ABC6ABD6ABE6ABF6AC06AC16AC26AC36AC46AC56AC66AC76AC86AC9 6ACA6ACB6ACC6ACD6ACE6ACF6AD06AD16AD26AD36AD46AD56AD66AD76AD86AD9 6ADA6ADB6ADC6ADD6ADE6ADF6AE06AE16AE26AE36AE46AE56AE66AE76AE86AE9 6AEA6AEB6AEC6AED6AEE6AEF6AF06AF16AF26AF36AF46AF56AF66AF76AF86AF9 6AFA6AFB6AFC6AFD6AFE6AFF6B006B016B026B036B046B056B066B076B086B09 6B0A6B0B6B0C6B0D6B0E6B0F6B106B116B126B136B146B156B166B176B186B19 6B1A6B1B6B1C6B1D6B1E6B1F6B256B266B286B296B2A6B2B6B2C6B2D6B2E0000 9A 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6B2F6B306B316B336B346B356B366B386B3B6B3C6B3D6B3F6B406B416B426B44 6B456B486B4A6B4B6B4D6B4E6B4F6B506B516B526B536B546B556B566B576B58 6B5A6B5B6B5C6B5D6B5E6B5F6B606B616B686B696B6B6B6C6B6D6B6E6B6F6B70 6B716B726B736B746B756B766B776B786B7A6B7D6B7E6B7F6B806B856B880000 6B8C6B8E6B8F6B906B916B946B956B976B986B996B9C6B9D6B9E6B9F6BA06BA2 6BA36BA46BA56BA66BA76BA86BA96BAB6BAC6BAD6BAE6BAF6BB06BB16BB26BB6 6BB86BB96BBA6BBB6BBC6BBD6BBE6BC06BC36BC46BC66BC76BC86BC96BCA6BCC 6BCE6BD06BD16BD86BDA6BDC6BDD6BDE6BDF6BE06BE26BE36BE46BE56BE66BE7 6BE86BE96BEC6BED6BEE6BF06BF16BF26BF46BF66BF76BF86BFA6BFB6BFC6BFE 6BFF6C006C016C026C036C046C086C096C0A6C0B6C0C6C0E6C126C176C1C6C1D 6C1E6C206C236C256C2B6C2C6C2D6C316C336C366C376C396C3A6C3B6C3C6C3E 6C3F6C436C446C456C486C4B6C4C6C4D6C4E6C4F6C516C526C536C566C580000 9B 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6C596C5A6C626C636C656C666C676C6B6C6C6C6D6C6E6C6F6C716C736C756C77 6C786C7A6C7B6C7C6C7F6C806C846C876C8A6C8B6C8D6C8E6C916C926C956C96 6C976C986C9A6C9C6C9D6C9E6CA06CA26CA86CAC6CAF6CB06CB46CB56CB66CB7 6CBA6CC06CC16CC26CC36CC66CC76CC86CCB6CCD6CCE6CCF6CD16CD26CD80000 6CD96CDA6CDC6CDD6CDF6CE46CE66CE76CE96CEC6CED6CF26CF46CF96CFF6D00 6D026D036D056D066D086D096D0A6D0D6D0F6D106D116D136D146D156D166D18 6D1C6D1D6D1F6D206D216D226D236D246D266D286D296D2C6D2D6D2F6D306D34 6D366D376D386D3A6D3F6D406D426D446D496D4C6D506D556D566D576D586D5B 6D5D6D5F6D616D626D646D656D676D686D6B6D6C6D6D6D706D716D726D736D75 6D766D796D7A6D7B6D7D6D7E6D7F6D806D816D836D846D866D876D8A6D8B6D8D 6D8F6D906D926D966D976D986D996D9A6D9C6DA26DA56DAC6DAD6DB06DB16DB3 6DB46DB66DB76DB96DBA6DBB6DBC6DBD6DBE6DC16DC26DC36DC86DC96DCA0000 9C 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6DCD6DCE6DCF6DD06DD26DD36DD46DD56DD76DDA6DDB6DDC6DDF6DE26DE36DE5 6DE76DE86DE96DEA6DED6DEF6DF06DF26DF46DF56DF66DF86DFA6DFD6DFE6DFF 6E006E016E026E036E046E066E076E086E096E0B6E0F6E126E136E156E186E19 6E1B6E1C6E1E6E1F6E226E266E276E286E2A6E2C6E2E6E306E316E336E350000 6E366E376E396E3B6E3C6E3D6E3E6E3F6E406E416E426E456E466E476E486E49 6E4A6E4B6E4C6E4F6E506E516E526E556E576E596E5A6E5C6E5D6E5E6E606E61 6E626E636E646E656E666E676E686E696E6A6E6C6E6D6E6F6E706E716E726E73 6E746E756E766E776E786E796E7A6E7B6E7C6E7D6E806E816E826E846E876E88 6E8A6E8B6E8C6E8D6E8E6E916E926E936E946E956E966E976E996E9A6E9B6E9D 6E9E6EA06EA16EA36EA46EA66EA86EA96EAB6EAC6EAD6EAE6EB06EB36EB56EB8 6EB96EBC6EBE6EBF6EC06EC36EC46EC56EC66EC86EC96ECA6ECC6ECD6ECE6ED0 6ED26ED66ED86ED96EDB6EDC6EDD6EE36EE76EEA6EEB6EEC6EED6EEE6EEF0000 9D 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6EF06EF16EF26EF36EF56EF66EF76EF86EFA6EFB6EFC6EFD6EFE6EFF6F006F01 6F036F046F056F076F086F0A6F0B6F0C6F0D6F0E6F106F116F126F166F176F18 6F196F1A6F1B6F1C6F1D6F1E6F1F6F216F226F236F256F266F276F286F2C6F2E 6F306F326F346F356F376F386F396F3A6F3B6F3C6F3D6F3F6F406F416F420000 6F436F446F456F486F496F4A6F4C6F4E6F4F6F506F516F526F536F546F556F56 6F576F596F5A6F5B6F5D6F5F6F606F616F636F646F656F676F686F696F6A6F6B 6F6C6F6F6F706F716F736F756F766F776F796F7B6F7D6F7E6F7F6F806F816F82 6F836F856F866F876F8A6F8B6F8F6F906F916F926F936F946F956F966F976F98 6F996F9A6F9B6F9D6F9E6F9F6FA06FA26FA36FA46FA56FA66FA86FA96FAA6FAB 6FAC6FAD6FAE6FAF6FB06FB16FB26FB46FB56FB76FB86FBA6FBB6FBC6FBD6FBE 6FBF6FC16FC36FC46FC56FC66FC76FC86FCA6FCB6FCC6FCD6FCE6FCF6FD06FD3 6FD46FD56FD66FD76FD86FD96FDA6FDB6FDC6FDD6FDF6FE26FE36FE46FE50000 9E 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6FE66FE76FE86FE96FEA6FEB6FEC6FED6FF06FF16FF26FF36FF46FF56FF66FF7 6FF86FF96FFA6FFB6FFC6FFD6FFE6FFF70007001700270037004700570067007 70087009700A700B700C700D700E700F70107012701370147015701670177018 7019701C701D701E701F702070217022702470257026702770287029702A0000 702B702C702D702E702F70307031703270337034703670377038703A703B703C 703D703E703F7040704170427043704470457046704770487049704A704B704D 704E7050705170527053705470557056705770587059705A705B705C705D705F 7060706170627063706470657066706770687069706A706E7071707270737074 70777079707A707B707D7081708270837084708670877088708B708C708D708F 70907091709370977098709A709B709E709F70A070A170A270A370A470A570A6 70A770A870A970AA70B070B270B470B570B670BA70BE70BF70C470C570C670C7 70C970CB70CC70CD70CE70CF70D070D170D270D370D470D570D670D770DA0000 9F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 70DC70DD70DE70E070E170E270E370E570EA70EE70F070F170F270F370F470F5 70F670F870FA70FB70FC70FE70FF710071017102710371047105710671077108 710B710C710D710E710F7111711271147117711B711C711D711E711F71207121 7122712371247125712771287129712A712B712C712D712E7132713371340000 7135713771387139713A713B713C713D713E713F714071417142714371447146 714771487149714B714D714F7150715171527153715471557156715771587159 715A715B715D715F716071617162716371657169716A716B716C716D716F7170 717171747175717671777179717B717C717E717F718071817182718371857186 718771887189718B718C718D718E7190719171927193719571967197719A719B 719C719D719E71A171A271A371A471A571A671A771A971AA71AB71AD71AE71AF 71B071B171B271B471B671B771B871BA71BB71BC71BD71BE71BF71C071C171C2 71C471C571C671C771C871C971CA71CB71CC71CD71CF71D071D171D271D30000 A0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 71D671D771D871D971DA71DB71DC71DD71DE71DF71E171E271E371E471E671E8 71E971EA71EB71EC71ED71EF71F071F171F271F371F471F571F671F771F871FA 71FB71FC71FD71FE71FF720072017202720372047205720772087209720A720B 720C720D720E720F7210721172127213721472157216721772187219721A0000 721B721C721E721F722072217222722372247225722672277229722B722D722E 722F723272337234723A723C723E72407241724272437244724572467249724A 724B724E724F7250725172537254725572577258725A725C725E726072637264 72657268726A726B726C726D7270727172737274727672777278727B727C727D 7282728372857286728772887289728C728E7290729172937294729572967297 72987299729A729B729C729D729E72A072A172A272A372A472A572A672A772A8 72A972AA72AB72AE72B172B272B372B572BA72BB72BC72BD72BE72BF72C072C5 72C672C772C972CA72CB72CC72CF72D172D372D472D572D672D872DA72DB0000 A1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000030003001300200B702C902C700A8300330052014FF5E2016202620182019 201C201D3014301530083009300A300B300C300D300E300F3016301730103011 00B100D700F72236222722282211220F222A222922082237221A22A522252220 23122299222B222E2261224C2248223D221D2260226E226F22642265221E2235 22342642264000B0203220332103FF0400A4FFE0FFE1203000A7211626062605 25CB25CF25CE25C725C625A125A025B325B2203B219221902191219330130000 A2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000217021712172217321742175217621772178217900000000000000000000 000024882489248A248B248C248D248E248F2490249124922493249424952496 249724982499249A249B247424752476247724782479247A247B247C247D247E 247F248024812482248324842485248624872460246124622463246424652466 2467246824690000000032203221322232233224322532263227322832290000 00002160216121622163216421652166216721682169216A216B000000000000 A3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FF01FF02FF03FFE5FF05FF06FF07FF08FF09FF0AFF0BFF0CFF0DFF0EFF0F FF10FF11FF12FF13FF14FF15FF16FF17FF18FF19FF1AFF1BFF1CFF1DFF1EFF1F FF20FF21FF22FF23FF24FF25FF26FF27FF28FF29FF2AFF2BFF2CFF2DFF2EFF2F FF30FF31FF32FF33FF34FF35FF36FF37FF38FF39FF3AFF3BFF3CFF3DFF3EFF3F FF40FF41FF42FF43FF44FF45FF46FF47FF48FF49FF4AFF4BFF4CFF4DFF4EFF4F FF50FF51FF52FF53FF54FF55FF56FF57FF58FF59FF5AFF5BFF5CFF5DFFE30000 A4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000304130423043304430453046304730483049304A304B304C304D304E304F 3050305130523053305430553056305730583059305A305B305C305D305E305F 3060306130623063306430653066306730683069306A306B306C306D306E306F 3070307130723073307430753076307730783079307A307B307C307D307E307F 3080308130823083308430853086308730883089308A308B308C308D308E308F 3090309130923093000000000000000000000000000000000000000000000000 A5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000030A130A230A330A430A530A630A730A830A930AA30AB30AC30AD30AE30AF 30B030B130B230B330B430B530B630B730B830B930BA30BB30BC30BD30BE30BF 30C030C130C230C330C430C530C630C730C830C930CA30CB30CC30CD30CE30CF 30D030D130D230D330D430D530D630D730D830D930DA30DB30DC30DD30DE30DF 30E030E130E230E330E430E530E630E730E830E930EA30EB30EC30ED30EE30EF 30F030F130F230F330F430F530F6000000000000000000000000000000000000 A6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000039103920393039403950396039703980399039A039B039C039D039E039F 03A003A103A303A403A503A603A703A803A90000000000000000000000000000 000003B103B203B303B403B503B603B703B803B903BA03BB03BC03BD03BE03BF 03C003C103C303C403C503C603C703C803C90000000000000000000000000000 FE35FE36FE39FE3AFE3FFE40FE3DFE3EFE41FE42FE43FE4400000000FE3BFE3C FE37FE38FE310000FE33FE340000000000000000000000000000000000000000 A7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000004100411041204130414041504010416041704180419041A041B041C041D 041E041F0420042104220423042404250426042704280429042A042B042C042D 042E042F00000000000000000000000000000000000000000000000000000000 000004300431043204330434043504510436043704380439043A043B043C043D 043E043F0440044104420443044404450446044704480449044A044B044C044D 044E044F00000000000000000000000000000000000000000000000000000000 A8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 02CA02CB02D920132015202520352105210921962197219821992215221F2223 22522266226722BF2550255125522553255425552556255725582559255A255B 255C255D255E255F2560256125622563256425652566256725682569256A256B 256C256D256E256F257025712572257325812582258325842585258625870000 25882589258A258B258C258D258E258F25932594259525BC25BD25E225E325E4 25E5260922953012301D301E0000000000000000000000000000000000000000 0000010100E101CE00E0011300E9011B00E8012B00ED01D000EC014D00F301D2 00F2016B00FA01D400F901D601D801DA01DC00FC00EA02510000014401480000 0261000000000000000031053106310731083109310A310B310C310D310E310F 3110311131123113311431153116311731183119311A311B311C311D311E311F 3120312131223123312431253126312731283129000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 A9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 30213022302330243025302630273028302932A3338E338F339C339D339E33A1 33C433CE33D133D233D5FE30FFE2FFE400002121323100002010000000000000 30FC309B309C30FD30FE3006309D309EFE49FE4AFE4BFE4CFE4DFE4EFE4FFE50 FE51FE52FE54FE55FE56FE57FE59FE5AFE5BFE5CFE5DFE5EFE5FFE60FE610000 FE62FE63FE64FE65FE66FE68FE69FE6AFE6B0000000000000000000000000000 0000000000000000000000003007000000000000000000000000000000000000 00000000000000002500250125022503250425052506250725082509250A250B 250C250D250E250F2510251125122513251425152516251725182519251A251B 251C251D251E251F2520252125222523252425252526252725282529252A252B 252C252D252E252F2530253125322533253425352536253725382539253A253B 253C253D253E253F2540254125422543254425452546254725482549254A254B 0000000000000000000000000000000000000000000000000000000000000000 AA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 72DC72DD72DF72E272E372E472E572E672E772EA72EB72F572F672F972FD72FE 72FF73007302730473057306730773087309730B730C730D730F731073117312 731473187319731A731F732073237324732673277328732D732F733073327333 73357336733A733B733C733D7340734173427343734473457346734773480000 7349734A734B734C734E734F7351735373547355735673587359735A735B735C 735D735E735F736173627363736473657366736773687369736A736B736E7370 7371000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 AB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 73727373737473757376737773787379737A737B737C737D737F738073817382 7383738573867388738A738C738D738F73907392739373947395739773987399 739A739C739D739E73A073A173A373A473A573A673A773A873AA73AC73AD73B1 73B473B573B673B873B973BC73BD73BE73BF73C173C373C473C573C673C70000 73CB73CC73CE73D273D373D473D573D673D773D873DA73DB73DC73DD73DF73E1 73E273E373E473E673E873EA73EB73EC73EE73EF73F073F173F373F473F573F6 73F7000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 AC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 73F873F973FA73FB73FC73FD73FE73FF740074017402740474077408740B740C 740D740E741174127413741474157416741774187419741C741D741E741F7420 74217423742474277429742B742D742F74317432743774387439743A743B743D 743E743F744074427443744474457446744774487449744A744B744C744D0000 744E744F7450745174527453745474567458745D746074617462746374647465 7466746774687469746A746B746C746E746F7471747274737474747574787479 747A000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 AD 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 747B747C747D747F748274847485748674887489748A748C748D748F74917492 7493749474957496749774987499749A749B749D749F74A074A174A274A374A4 74A574A674AA74AB74AC74AD74AE74AF74B074B174B274B374B474B574B674B7 74B874B974BB74BC74BD74BE74BF74C074C174C274C374C474C574C674C70000 74C874C974CA74CB74CC74CD74CE74CF74D074D174D374D474D574D674D774D8 74D974DA74DB74DD74DF74E174E574E774E874E974EA74EB74EC74ED74F074F1 74F2000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 AE 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 74F374F574F874F974FA74FB74FC74FD74FE7500750175027503750575067507 75087509750A750B750C750E751075127514751575167517751B751D751E7520 752175227523752475267527752A752E753475367539753C753D753F75417542 75437544754675477549754A754D755075517552755375557556755775580000 755D755E755F75607561756275637564756775687569756B756C756D756E756F 757075717573757575767577757A757B757C757D757E75807581758275847585 7587000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 AF 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 75887589758A758C758D758E7590759375957598759B759C759E75A275A675A7 75A875A975AA75AD75B675B775BA75BB75BF75C075C175C675CB75CC75CE75CF 75D075D175D375D775D975DA75DC75DD75DF75E075E175E575E975EC75ED75EE 75EF75F275F375F575F675F775F875FA75FB75FD75FE76027604760676070000 76087609760B760D760E760F76117612761376147616761A761C761D761E7621 762376277628762C762E762F76317632763676377639763A763B763D76417642 7644000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 B0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 76457646764776487649764A764B764E764F7650765176527653765576577658 7659765A765B765D765F766076617662766476657666766776687669766A766C 766D766E767076717672767376747675767676777679767A767C767F76807681 768376857689768A768C768D768F769076927694769576977698769A769B0000 769C769D769E769F76A076A176A276A376A576A676A776A876A976AA76AB76AC 76AD76AF76B076B376B576B676B776B876B976BA76BB76BC76BD76BE76C076C1 76C3554A963F57C3632854CE550954C07691764C853C77EE827E788D72319698 978D6C285B894FFA630966975CB880FA684880AE660276CE51F9655671AC7FF1 888450B2596561CA6FB382AD634C625253ED54277B06516B75A45DF462D48DCB 9776628A8019575D97387F627238767D67CF767E64464F708D2562DC7A176591 73ED642C6273822C9881677F7248626E62CC4F3474E3534A529E7ECA90A65E2E 6886699C81807ED168D278C5868C9551508D8C2482DE80DE5305891252650000 B1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 76C476C776C976CB76CC76D376D576D976DA76DC76DD76DE76E076E176E276E3 76E476E676E776E876E976EA76EB76EC76ED76F076F376F576F676F776FA76FB 76FD76FF77007702770377057706770A770C770E770F77107711771277137714 7715771677177718771B771C771D771E77217723772477257727772A772B0000 772C772E773077317732773377347739773B773D773E773F7742774477457746 77487749774A774B774C774D774E774F77527753775477557756775777587759 775C858496F94FDD582199715B9D62B162A566B48C799C8D7206676F789160B2 535153178F8880CC8D1D94A1500D72C8590760EB711988AB595482EF672C7B28 5D297EF7752D6CF58E668FF8903C9F3B6BD491197B145F7C78A784D6853D6BD5 6BD96BD65E015E8775F995ED655D5F0A5FC58F9F58C181C2907F965B97AD8FB9 7F168D2C62414FBF53D8535E8FA88FA98FAB904D68075F6A819888689CD6618B 522B762A5F6C658C6FD26EE85BBE6448517551B067C44E1979C9997C70B30000 B2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 775D775E775F7760776477677769776A776D776E776F77707771777277737774 7775777677777778777A777B777C7781778277837786778777887789778A778B 778F77907793779477957796779777987799779A779B779C779D779E77A177A3 77A477A677A877AB77AD77AE77AF77B177B277B477B677B777B877B977BA0000 77BC77BE77C077C177C277C377C477C577C677C777C877C977CA77CB77CC77CE 77CF77D077D177D277D377D477D577D677D877D977DA77DD77DE77DF77E077E1 77E475C55E7673BB83E064AD62E894B56CE2535A52C3640F94C27B944F2F5E1B 82368116818A6E246CCA9A736355535C54FA886557E04E0D5E036B657C3F90E8 601664E6731C88C16750624D8D22776C8E2991C75F6983DC8521991053C28695 6B8B60ED60E8707F82CD82314ED36CA785CF64CD7CD969FD66F9834953957B56 4FA7518C6D4B5C428E6D63D253C9832C833667E578B4643D5BDF5C945DEE8BE7 62C667F48C7A640063BA8749998B8C177F2094F24EA7961098A4660C73160000 B3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 77E677E877EA77EF77F077F177F277F477F577F777F977FA77FB77FC78037804 7805780678077808780A780B780E780F7810781378157819781B781E78207821 782278247828782A782B782E782F78317832783378357836783D783F78417842 78437844784678487849784A784B784D784F78517853785478587859785A0000 785B785C785E785F7860786178627863786478657866786778687869786F7870 78717872787378747875787678787879787A787B787D787E787F788078817882 7883573A5C1D5E38957F507F80A05382655E7545553150218D856284949E671D 56326F6E5DE2543570928F66626F64A463A35F7B6F8890F481E38FB05C186668 5FF16C8996488D81886C649179F057CE6A59621054484E587A0B60E96F848BDA 627F901E9A8B79E4540375F4630153196C608FDF5F1B9A70803B9F7F4F885C3A 8D647FC565A570BD514551B2866B5D075BA062BD916C75748E0C7A2061017B79 4EC77EF877854E1181ED521D51FA6A7153A88E87950496CF6EC19664695A0000 B4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7884788578867888788A788B788F789078927894789578967899789D789E78A0 78A278A478A678A878A978AA78AB78AC78AD78AE78AF78B578B678B778B878BA 78BB78BC78BD78BF78C078C278C378C478C678C778C878CC78CD78CE78CF78D1 78D278D378D678D778D878DA78DB78DC78DD78DE78DF78E078E178E278E30000 78E478E578E678E778E978EA78EB78ED78EE78EF78F078F178F378F578F678F8 78F978FB78FC78FD78FE78FF79007902790379047906790779087909790A790B 790C784050A877D7641089E6590463E35DDD7A7F693D4F20823955984E3275AE 7A975E625E8A95EF521B5439708A6376952457826625693F918755076DF37EAF 882262337EF075B5832878C196CC8F9E614874F78BCD6B64523A8D506B21806A 847156F153064ECE4E1B51D17C97918B7C074FC38E7F7BE17A9C64675D1450AC 810676017CB96DEC7FE067515B585BF878CB64AE641363AA632B9519642D8FBE 7B5476296253592754466B7950A362345E266B864EE38D37888B5F85902E0000 B5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 790D790E790F791079117912791479157916791779187919791A791B791C791D 791F792079217922792379257926792779287929792A792B792C792D792E792F 793079317932793379357936793779387939793D793F79427943794479457947 794A794B794C794D794E794F7950795179527954795579587959796179630000 796479667969796A796B796C796E79707971797279737974797579767979797B 797C797D797E797F798279837986798779887989798B798C798D798E79907991 79926020803D62C54E39535590F863B880C665E66C2E4F4660EE6DE18BDE5F39 86CB5F536321515A83616863520063638E4850125C9B79775BFC52307A3B60BC 905376D75FB75F9776848E6C706F767B7B4977AA51F3909358244F4E6EF48FEA 654C7B1B72C46DA47FDF5AE162B55E95573084827B2C5E1D5F1F90127F1498A0 63826EC7789870B95178975B57AB75354F4375385E9760E659606DC06BBF7889 53FC96D551CB52016389540A94938C038DCC7239789F87768FED8C0D53E00000 B6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7993799479957996799779987999799B799C799D799E799F79A079A179A279A3 79A479A579A679A879A979AA79AB79AC79AD79AE79AF79B079B179B279B479B5 79B679B779B879BC79BF79C279C479C579C779C879CA79CC79CE79CF79D079D3 79D479D679D779D979DA79DB79DC79DD79DE79E079E179E279E579E879EA0000 79EC79EE79F179F279F379F479F579F679F779F979FA79FC79FE79FF7A017A04 7A057A077A087A097A0A7A0C7A0F7A107A117A127A137A157A167A187A197A1B 7A1C4E0176EF53EE948998769F0E952D5B9A8BA24E224E1C51AC846361C252A8 680B4F97606B51BB6D1E515C6296659796618C46901775D890FD77636BD2728A 72EC8BFB583577798D4C675C9540809A5EA66E2159927AEF77ED953B6BB565AD 7F0E58065151961F5BF958A954288E726566987F56E4949D76FE9041638754C6 591A593A579B8EB267358DFA8235524160F0581586FE5CE89E454FC4989D8BB9 5A2560765384627C904F9102997F6069800C513F80335C1499756D314E8C0000 B7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7A1D7A1F7A217A227A247A257A267A277A287A297A2A7A2B7A2C7A2D7A2E7A2F 7A307A317A327A347A357A367A387A3A7A3E7A407A417A427A437A447A457A47 7A487A497A4A7A4B7A4C7A4D7A4E7A4F7A507A527A537A547A557A567A587A59 7A5A7A5B7A5C7A5D7A5E7A5F7A607A617A627A637A647A657A667A677A680000 7A697A6A7A6B7A6C7A6D7A6E7A6F7A717A727A737A757A7B7A7C7A7D7A7E7A82 7A857A877A897A8A7A8B7A8C7A8E7A8F7A907A937A947A997A9A7A9B7A9E7AA1 7AA28D3053D17F5A7B4F4F104E4F96006CD573D085E95E06756A7FFB6A0A77FE 94927E4151E170E653CD8FD483038D2972AF996D6CDB574A82B365B980AA623F 963259A84EFF8BBF7EBA653E83F2975E556198DE80A5532A8BFD542080BA5E9F 6CB88D3982AC915A54296C1B52067EB7575F711A6C7E7C89594B4EFD5FFF6124 7CAA4E305C0167AB87025CF0950B98CE75AF70FD902251AF7F1D8BBD594951E4 4F5B5426592B657780A45B75627662C28F905E456C1F7B264F0F4FD8670D0000 B8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7AA37AA47AA77AA97AAA7AAB7AAE7AAF7AB07AB17AB27AB47AB57AB67AB77AB8 7AB97ABA7ABB7ABC7ABD7ABE7AC07AC17AC27AC37AC47AC57AC67AC77AC87AC9 7ACA7ACC7ACD7ACE7ACF7AD07AD17AD27AD37AD47AD57AD77AD87ADA7ADB7ADC 7ADD7AE17AE27AE47AE77AE87AE97AEA7AEB7AEC7AEE7AF07AF17AF27AF30000 7AF47AF57AF67AF77AF87AFB7AFC7AFE7B007B017B027B057B077B097B0C7B0D 7B0E7B107B127B137B167B177B187B1A7B1C7B1D7B1F7B217B227B237B277B29 7B2D6D6E6DAA798F88B15F17752B629A8F854FEF91DC65A7812F81515E9C8150 8D74526F89868D4B590D50854ED8961C723681798D1F5BCC8BA3964459877F1A 54905676560E8BE565396982949976D66E895E727518674667D17AFF809D8D76 611F79C665628D635188521A94A27F38809B7EB25C976E2F67607BD9768B9AD8 818F7F947CD5641E95507A3F544A54E56B4C640162089E3D80F3759952729769 845B683C86E49601969494EC4E2A54047ED968398DDF801566F45E9A7FB90000 B9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7B2F7B307B327B347B357B367B377B397B3B7B3D7B3F7B407B417B427B437B44 7B467B487B4A7B4D7B4E7B537B557B577B597B5C7B5E7B5F7B617B637B647B65 7B667B677B687B697B6A7B6B7B6C7B6D7B6F7B707B737B747B767B787B7A7B7C 7B7D7B7F7B817B827B837B847B867B877B887B897B8A7B8B7B8C7B8E7B8F0000 7B917B927B937B967B987B997B9A7B9B7B9E7B9F7BA07BA37BA47BA57BAE7BAF 7BB07BB27BB37BB57BB67BB77BB97BBA7BBB7BBC7BBD7BBE7BBF7BC07BC27BC3 7BC457C2803F68975DE5653B529F606D9F9A4F9B8EAC516C5BAB5F135DE96C5E 62F18D21517194A952FE6C9F82DF72D757A267848D2D591F8F9C83C754957B8D 4F306CBD5B6459D19F1353E486CA9AA88C3780A16545987E56FA96C7522E74DC 52505BE1630289024E5662D0602A68FA51735B9851A089C27BA199867F5060EF 704C8D2F51495E7F901B747089C4572D78455F529F9F95FA8F689B3C8BE17678 684267DC8DEA8D35523D8F8A6EDA68CD950590ED56FD679C88F98FC754C80000 BA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7BC57BC87BC97BCA7BCB7BCD7BCE7BCF7BD07BD27BD47BD57BD67BD77BD87BDB 7BDC7BDE7BDF7BE07BE27BE37BE47BE77BE87BE97BEB7BEC7BED7BEF7BF07BF2 7BF37BF47BF57BF67BF87BF97BFA7BFB7BFD7BFF7C007C017C027C037C047C05 7C067C087C097C0A7C0D7C0E7C107C117C127C137C147C157C177C187C190000 7C1A7C1B7C1C7C1D7C1E7C207C217C227C237C247C257C287C297C2B7C2C7C2D 7C2E7C2F7C307C317C327C337C347C357C367C377C397C3A7C3B7C3C7C3D7C3E 7C429AB85B696D776C264EA55BB39A87916361A890AF97E9542B6DB55BD251FD 558A7F557FF064BC634D65F161BE608D710A6C576C49592F676D822A58D5568E 8C6A6BEB90DD597D801753F76D695475559D837783CF683879BE548C4F555408 76D28C8996026CB36DB88D6B89109E648D3A563F9ED175D55F8872E0606854FC 4EA86A2A886160528F7054C470D886799E3F6D2A5B8F5F187EA255894FAF7334 543C539A5019540E547C4E4E5FFD745A58F6846B80E1877472D07CCA6E560000 BB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7C437C447C457C467C477C487C497C4A7C4B7C4C7C4E7C4F7C507C517C527C53 7C547C557C567C577C587C597C5A7C5B7C5C7C5D7C5E7C5F7C607C617C627C63 7C647C657C667C677C687C697C6A7C6B7C6C7C6D7C6E7C6F7C707C717C727C75 7C767C777C787C797C7A7C7E7C7F7C807C817C827C837C847C857C867C870000 7C887C8A7C8B7C8C7C8D7C8E7C8F7C907C937C947C967C997C9A7C9B7CA07CA1 7CA37CA67CA77CA87CA97CAB7CAC7CAD7CAF7CB07CB47CB57CB67CB77CB87CBA 7CBB5F27864E552C62A44E926CAA623782B154D7534E733E6ED1753B52125316 8BDD69D05F8A60006DEE574F6B2273AF68538FD87F13636260A3552475EA8C62 71156DA35BA65E7B8352614C9EC478FA87577C27768751F060F6714C66435E4C 604D8C0E707063258F895FBD606286D456DE6BC160946167534960E066668D3F 79FD4F1A70E96C478BB38BF27ED88364660F5A5A9B426D516DF78C416D3B4F19 706B83B7621660D1970D8D27797851FB573E57FA673A75787A3D79EF7B950000 BC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7CBF7CC07CC27CC37CC47CC67CC97CCB7CCE7CCF7CD07CD17CD27CD37CD47CD8 7CDA7CDB7CDD7CDE7CE17CE27CE37CE47CE57CE67CE77CE97CEA7CEB7CEC7CED 7CEE7CF07CF17CF27CF37CF47CF57CF67CF77CF97CFA7CFC7CFD7CFE7CFF7D00 7D017D027D037D047D057D067D077D087D097D0B7D0C7D0D7D0E7D0F7D100000 7D117D127D137D147D157D167D177D187D197D1A7D1B7D1C7D1D7D1E7D1F7D21 7D237D247D257D267D287D297D2A7D2C7D2D7D2E7D307D317D327D337D347D35 7D36808C99658FF96FC08BA59E2159EC7EE97F095409678168D88F917C4D96C6 53CA602575BE6C7253735AC97EA7632451E0810A5DF184DF628051805B634F0E 796D524260B86D4E5BC45BC28BA18BB065E25FCC964559937EE77EAA560967B7 59394F735BB652A0835A988A8D3E753294BE50477A3C4EF767B69A7E5AC16B7C 76D1575A5C167B3A95F4714E517C80A9827059787F04832768C067EC78B17877 62E363617B804FED526A51CF835069DB92748DF58D3189C1952E7BAD4EF60000 BD 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7D377D387D397D3A7D3B7D3C7D3D7D3E7D3F7D407D417D427D437D447D457D46 7D477D487D497D4A7D4B7D4C7D4D7D4E7D4F7D507D517D527D537D547D557D56 7D577D587D597D5A7D5B7D5C7D5D7D5E7D5F7D607D617D627D637D647D657D66 7D677D687D697D6A7D6B7D6C7D6D7D6F7D707D717D727D737D747D757D760000 7D787D797D7A7D7B7D7C7D7D7D7E7D7F7D807D817D827D837D847D857D867D87 7D887D897D8A7D8B7D8C7D8D7D8E7D8F7D907D917D927D937D947D957D967D97 7D98506582305251996F6E106E856DA75EFA50F559DC5C066D466C5F7586848B 686859568BB253209171964D854969127901712680F64EA490CA6D479A845A07 56BC640594F077EB4FA5811A72E189D2997A7F347EDE527F655991758F7F8F83 53EB7A9663ED63A5768679F888579636622A52AB8282685467706377776B7AED 6D017ED389E359D0621285C982A5754C501F4ECB75A58BEB5C4A5DFE7B4B65A4 91D14ECA6D25895F7D2795264EC58C288FDB9773664B79818FD170EC6D780000 BE 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7D997D9A7D9B7D9C7D9D7D9E7D9F7DA07DA17DA27DA37DA47DA57DA77DA87DA9 7DAA7DAB7DAC7DAD7DAF7DB07DB17DB27DB37DB47DB57DB67DB77DB87DB97DBA 7DBB7DBC7DBD7DBE7DBF7DC07DC17DC27DC37DC47DC57DC67DC77DC87DC97DCA 7DCB7DCC7DCD7DCE7DCF7DD07DD17DD27DD37DD47DD57DD67DD77DD87DD90000 7DDA7DDB7DDC7DDD7DDE7DDF7DE07DE17DE27DE37DE47DE57DE67DE77DE87DE9 7DEA7DEB7DEC7DED7DEE7DEF7DF07DF17DF27DF37DF47DF57DF67DF77DF87DF9 7DFA5C3D52B283465162830E775B66769CB84EAC60CA7CBE7CB37ECF4E958B66 666F988897595883656C955C5F8475C997567ADF7ADE51C070AF7A9863EA7A76 7EA0739697ED4E4570784E5D915253A9655165E781FC8205548E5C31759A97A0 62D872D975BD5C459A7983CA5C40548077E94E3E6CAE805A62D2636E5DE85177 8DDD8E1E952F4FF153E560E770AC526763509E435A1F5026773753777EE26485 652B628963985014723589C951B38BC07EDD574783CC94A7519B541B5CFB0000 BF 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7DFB7DFC7DFD7DFE7DFF7E007E017E027E037E047E057E067E077E087E097E0A 7E0B7E0C7E0D7E0E7E0F7E107E117E127E137E147E157E167E177E187E197E1A 7E1B7E1C7E1D7E1E7E1F7E207E217E227E237E247E257E267E277E287E297E2A 7E2B7E2C7E2D7E2E7E2F7E307E317E327E337E347E357E367E377E387E390000 7E3A7E3C7E3D7E3E7E3F7E407E427E437E447E457E467E487E497E4A7E4B7E4C 7E4D7E4E7E4F7E507E517E527E537E547E557E567E577E587E597E5A7E5B7E5C 7E5D4FCA7AE36D5A90E19A8F55805496536154AF5F0063E9697751EF6168520A 582A52D8574E780D770B5EB761777CE0625B62974EA27095800362F770E49760 577782DB67EF68F578D5989779D158F354B353EF6E34514B523B5BA28BFE80AF 554357A660735751542D7A7A60505B5463A762A053E362635BC767AF54ED7A9F 82E691775E9388E4593857AE630E8DE880EF57577B774FA95FEB5BBD6B3E5321 7B5072C2684677FF773665F751B54E8F76D45CBF7AA58475594E9B4150800000 C0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7E5E7E5F7E607E617E627E637E647E657E667E677E687E697E6A7E6B7E6C7E6D 7E6E7E6F7E707E717E727E737E747E757E767E777E787E797E7A7E7B7E7C7E7D 7E7E7E7F7E807E817E837E847E857E867E877E887E897E8A7E8B7E8C7E8D7E8E 7E8F7E907E917E927E937E947E957E967E977E987E997E9A7E9C7E9D7E9E0000 7EAE7EB47EBB7EBC7ED67EE47EEC7EF97F0A7F107F1E7F377F397F3B7F3C7F3D 7F3E7F3F7F407F417F437F467F477F487F497F4A7F4B7F4C7F4D7F4E7F4F7F52 7F53998861276E8357646606634656F062EC62695ED39614578362C955878721 814A8FA3556683B167658D5684DD5A6A680F62E67BEE961151706F9C8C3063FD 89C861D27F0670C26EE57405699472FC5ECA90CE67176D6A635E52B372628001 4F6C59E5916A70D96D9D52D24E5096F7956D857E78CA7D2F5121579264C2808B 7C7B6CEA68F1695E51B7539868A872819ECE7BF172F879BB6F137406674E91CC 9CA4793C83898354540F68174E3D538952B1783E5386522950884F8B4FD00000 C1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7F567F597F5B7F5C7F5D7F5E7F607F637F647F657F667F677F6B7F6C7F6D7F6F 7F707F737F757F767F777F787F7A7F7B7F7C7F7D7F7F7F807F827F837F847F85 7F867F877F887F897F8B7F8D7F8F7F907F917F927F937F957F967F977F987F99 7F9B7F9C7FA07FA27FA37FA57FA67FA87FA97FAA7FAB7FAC7FAD7FAE7FB10000 7FB37FB47FB57FB67FB77FBA7FBB7FBE7FC07FC27FC37FC47FC67FC77FC87FC9 7FCB7FCD7FCF7FD07FD17FD27FD37FD67FD77FD97FDA7FDB7FDC7FDD7FDE7FE2 7FE375E27ACB7C926CA596B6529B748354E94FE9805483B28FDE95705EC9601C 6D9F5E18655B813894FE604B70BC7EC37CAE51C968817CB1826F4E248F8691CF 667E4EAE8C0564A9804A50DA759771CE5BE58FBD6F664E86648295635ED66599 521788C270C852A3730E7433679778F797164E3490BB9CDE6DCB51DB8D41541D 62CE73B283F196F69F8494C34F367F9A51CC707596755CAD988653E64EE46E9C 740969B4786B998F7559521876246D4167F3516D9F99804B54997B3C7ABF0000 C2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7FE47FE77FE87FEA7FEB7FEC7FED7FEF7FF27FF47FF57FF67FF77FF87FF97FFA 7FFD7FFE7FFF8002800780088009800A800E800F80118013801A801B801D801E 801F802180238024802B802C802D802E802F8030803280348039803A803C803E 8040804180448045804780488049804E804F8050805180538055805680570000 8059805B805C805D805E805F806080618062806380648065806680678068806B 806C806D806E806F807080728073807480758076807780788079807A807B807C 807D9686578462E29647697C5A0464027BD36F0F964B82A6536298855E907089 63B35364864F9C819E93788C97328DEF8D429E7F6F5E79845F559646622E9A74 541594DD4FA365C55C655C617F1586516C2F5F8B73876EE47EFF5CE6631B5B6A 6EE653754E7163A0756562A18F6E4F264ED16CA67EB68BBA841D87BA7F57903B 95237BA99AA188F8843D6D1B9A867EDC59889EBB739B780186829A6C9A82561B 541757CB4E709EA653568FC881097792999286EE6EE1851366FC61626F2B0000 C3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 807E8081808280858088808A808D808E808F8090809180928094809580978099 809E80A380A680A780A880AC80B080B380B580B680B880B980BB80C580C780C8 80C980CA80CB80CF80D080D180D280D380D480D580D880DF80E080E280E380E6 80EE80F580F780F980FB80FE80FF8100810181038104810581078108810B0000 810C811581178119811B811C811D811F81208121812281238124812581268127 81288129812A812B812D812E813081338134813581378139813A813B813C813D 813F8C298292832B76F26C135FD983BD732B8305951A6BDB77DB94C6536F8302 51925E3D8C8C8D384E4873AB679A68859176970971646CA177095A9295416BCF 7F8E66275BD059B95A9A95E895F74EEC840C84996AAC76DF9530731B68A65B5F 772F919A97617CDC8FF78C1C5F257C7379D889C56CCC871C5BC65E4268C97720 7EF55195514D52C95A297F05976282D763CF778485D079D26E3A5E9959998511 706D6C1162BF76BF654F60AF95FD660E879F9E2394ED540D547D8C2C64780000 C4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 81408141814281438144814581478149814D814E814F8152815681578158815B 815C815D815E815F816181628163816481668168816A816B816C816F81728173 81758176817781788181818381848185818681878189818B818C818D818E8190 8192819381948195819681978199819A819E819F81A081A181A281A481A50000 81A781A981AB81AC81AD81AE81AF81B081B181B281B481B581B681B781B881B9 81BC81BD81BE81BF81C481C581C781C881C981CB81CD81CE81CF81D081D181D2 81D3647986116A21819C78E864699B5462B9672B83AB58A89ED86CAB6F205BDE 964C8C0B725F67D062C772614EA959C66BCD589366AE5E5552DF6155672876EE 776672677A4662FF54EA545094A090A35A1C7EB36C164E435976801059485357 753796BE56CA63208111607C95F96DD65462998151855AE980FD59AE9713502A 6CE55C3C62DF4F60533F817B90066EBA852B62C85E7478BE64B5637B5FF55A18 917F9E1F5C3F634F80425B7D556E954A954D6D8560A867E072DE51DD5B810000 C5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 81D481D581D681D781D881D981DA81DB81DC81DD81DE81DF81E081E181E281E4 81E581E681E881E981EB81EE81EF81F081F181F281F581F681F781F881F981FA 81FD81FF8203820782088209820A820B820E820F821182138215821682178218 8219821A821D822082248225822682278229822E8232823A823C823D823F0000 8240824182428243824582468248824A824C824D824E82508251825282538254 8255825682578259825B825C825D825E82608261826282638264826582668267 826962E76CDE725B626D94AE7EBD81136D53519C5F04597452AA601259736696 8650759F632A61E67CEF8BFA54E66B279E256BB485D5545550766CA4556A8DB4 722C5E156015743662CD6392724C5F986E436D3E65006F5876D878D076FC7554 522453DB4E535E9E65C1802A80D6629B5486522870AE888D8DD16CE1547880DA 57F988F48D54966A914D4F696C9B55B776C6783062A870F96F8E5F6D84EC68DA 787C7BF781A8670B9E4F636778B0576F78129739627962AB528874356BD70000 C6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 826A826B826C826D82718275827682778278827B827C82808281828382858286 82878289828C82908293829482958296829A829B829E82A082A282A382A782B2 82B582B682BA82BB82BC82BF82C082C282C382C582C682C982D082D682D982DA 82DD82E282E782E882E982EA82EC82ED82EE82F082F282F382F582F682F80000 82FA82FC82FD82FE82FF8300830A830B830D831083128313831683188319831D 831E831F83208321832283238324832583268329832A832E833083328337833B 833D5564813E75B276AE533975DE50FB5C418B6C7BC7504F72479A9798D86F02 74E27968648777A562FC98918D2B54C180584E52576A82F9840D5E7351ED74F6 8BC45C4F57616CFC98875A4678349B448FEB7C955256625194FA4EC683868461 83E984B257D467345703666E6D668C3166DD7011671F6B3A6816621A59BB4E03 51C46F0667D26C8F517668CB59476B6775665D0E81109F5065D7794879419A91 8D775C824E5E4F01542F5951780C56686C148FC45F036C7D6CE38BAB63900000 C7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 833E833F83418342834483458348834A834B834C834D834E8353835583568357 83588359835D836283708371837283738374837583768379837A837E837F8380 838183828383838483878388838A838B838C838D838F83908391839483958396 83978399839A839D839F83A183A283A383A483A583A683A783AC83AD83AE0000 83AF83B583BB83BE83BF83C283C383C483C683C883C983CB83CD83CE83D083D1 83D283D383D583D783D983DA83DB83DE83E283E383E483E683E783E883EB83EC 83ED60706D3D72756266948E94C553438FC17B7E4EDF8C264E7E9ED494B194B3 524D6F5C90636D458C3458115D4C6B206B4967AA545B81547F8C589985375F3A 62A26A47953965726084686577A74E544FA85DE7979864AC7FD85CED4FCF7A8D 520783044E14602F7A8394A64FB54EB279E6743452E482B964D279BD5BDD6C81 97528F7B6C22503E537F6E0564CE66746C3060C598778BF75E86743C7A7779CB 4E1890B174036C4256DA914B6CC58D8B533A86C666F28EAF5C489A716E200000 C8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 83EE83EF83F383F483F583F683F783FA83FB83FC83FE83FF8400840284058407 84088409840A84108412841384148415841684178419841A841B841E841F8420 8421842284238429842A842B842C842D842E842F843084328433843484358436 84378439843A843B843E843F8440844184428443844484458447844884490000 844A844B844C844D844E844F8450845284538454845584568458845D845E845F 8460846284648465846684678468846A846E846F84708472847484778479847B 847C53D65A369F8B8DA353BB570898A76743919B6CC9516875CA62F372AC5238 529D7F3A7094763853749E4A69B7786E96C088D97FA4713671C3518967D374E4 58E4651856B78BA9997662707ED560F970ED58EC4EC14EBA5FCD97E74EFB8BA4 5203598A7EAB62544ECD65E5620E833884C98363878D71946EB65BB97ED25197 63C967D480898339881551125B7A59828FB14E736C5D516589258F6F962E854A 745E951095F06DA682E55F3164926D128428816E9CC3585E8D5B4E0953C10000 C9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 847D847E847F848084818483848484858486848A848D848F8490849184928493 8494849584968498849A849B849D849E849F84A084A284A384A484A584A684A7 84A884A984AA84AB84AC84AD84AE84B084B184B384B584B684B784BB84BC84BE 84C084C284C384C584C684C784C884CB84CC84CE84CF84D284D484D584D70000 84D884D984DA84DB84DC84DE84E184E284E484E784E884E984EA84EB84ED84EE 84EF84F184F284F384F484F584F684F784F884F984FA84FB84FD84FE85008501 85024F1E6563685155D34E2764149A9A626B5AC2745F82726DA968EE50E7838E 7802674052396C997EB150BB5565715E7B5B665273CA82EB67495C715220717D 886B95EA965564C58D6181B355846C5562477F2E58924F2455468D4F664C4E0A 5C1A88F368A2634E7A0D70E7828D52FA97F65C1154E890B57ECD59628D4A86C7 820C820D8D6664445C0461516D89793E8BBE78377533547B4F388EAB6DF15A20 7EC5795E6C885BA15A76751A80BE614E6E1758F0751F7525727253477EF30000 CA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8503850485058506850785088509850A850B850D850E850F8510851285148515 851685188519851B851C851D851E852085228523852485258526852785288529 852A852D852E852F8530853185328533853485358536853E853F854085418542 8544854585468547854B854C854D854E854F8550855185528553855485550000 85578558855A855B855C855D855F85608561856285638565856685678569856A 856B856C856D856E856F8570857185738575857685778578857C857D857F8580 8581770176DB526980DC57235E08593172EE65BD6E7F8BD75C388671534177F3 62FE65F64EC098DF86805B9E8BC653F277E24F7F5C4E9A7659CB5F0F793A58EB 4E1667FF4E8B62ED8A93901D52BF662F55DC566C90024ED54F8D91CA99706C0F 5E0260435BA489C68BD56536624B99965B885BFF6388552E53D77626517D852C 67A268B36B8A62928F9353D482126DD1758F4E668D4E5B70719F85AF669166D9 7F7287009ECD9F205C5E672F8FF06811675F620D7AD658855EB665706F310000 CB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 85828583858685888589858A858B858C858D858E859085918592859385948595 8596859785988599859A859D859E859F85A085A185A285A385A585A685A785A9 85AB85AC85AD85B185B285B385B485B585B685B885BA85BB85BC85BD85BE85BF 85C085C285C385C485C585C685C785C885CA85CB85CC85CD85CE85D185D20000 85D485D685D785D885D985DA85DB85DD85DE85DF85E085E185E285E385E585E6 85E785E885EA85EB85EC85ED85EE85EF85F085F185F285F385F485F585F685F7 85F860555237800D6454887075295E05681362F4971C53CC723D8C016C347761 7A0E542E77AC987A821C8BF47855671470C165AF64955636601D79C153F84E1D 6B7B80865BFA55E356DB4F3A4F3C99725DF3677E80386002988290015B8B8BBC 8BF5641C825864DE55FD82CF91654FD77D20901F7C9F50F358516EAF5BBF8BC9 80839178849C7B97867D968B968F7EE59AD3788E5C817A57904296A7795F5B59 635F7B0B84D168AD55067F2974107D2295016240584C4ED65B83597958540000 CC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 85F985FA85FC85FD85FE860086018602860386048606860786088609860A860B 860C860D860E860F86108612861386148615861786188619861A861B861C861D 861E861F86208621862286238624862586268628862A862B862C862D862E862F 863086318632863386348635863686378639863A863B863D863E863F86400000 864186428643864486458646864786488649864A864B864C8652865386558656 865786588659865B865C865D865F866086618663866486658666866786688669 866A736D631E8E4B8E0F80CE82D462AC53F06CF0915E592A60016C70574D644A 8D2A762B6EE9575B6A8075F06F6D8C2D8C0857666BEF889278B363A253F970AD 6C645858642A580268E0819B55107CD650188EBA6DCC8D9F70EB638F6D9B6ED4 7EE68404684390036DD896768BA85957727985E4817E75BC8A8A68AF52548E22 951163D098988E44557C4F5366FF568F60D56D9552435C4959296DFB586B7530 751C606C82148146631167618FE2773A8DF38D3494C15E165385542C70C30000 CD 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 866D866F86708672867386748675867686778678868386848685868686878688 8689868E868F86908691869286948696869786988699869A869B869E869F86A0 86A186A286A586A686AB86AD86AE86B286B386B786B886B986BB86BC86BD86BE 86BF86C186C286C386C586C886CC86CD86D286D386D586D686D786DA86DC0000 86DD86E086E186E286E386E586E686E786E886EA86EB86EC86EF86F586F686F7 86FA86FB86FC86FD86FF8701870487058706870B870C870E870F871087118714 87166C405EF7505C4EAD5EAD633A8247901A6850916E77B3540C94DC5F647AE5 687663457B527EDF75DB507762955934900F51F879C37A8156FE5F9290146D82 5C60571F541051546E4D56E263A89893817F8715892A9000541E5C6F81C062D6 625881319E3596409A6E9A7C692D59A562D3553E631654C786D96D3C5A0374E6 889C6B6A59168C4C5F2F6E7E73A9987D4E3870F75B8C7897633D665A769660CB 5B9B5A494E0781556C6A738B4EA167897F515F8065FA671B5FD859845A010000 CE 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8719871B871D871F87208724872687278728872A872B872C872D872F87308732 87338735873687388739873A873C873D8740874187428743874487458746874A 874B874D874F8750875187528754875587568758875A875B875C875D875E875F 876187628766876787688769876A876B876C876D876F87718772877387750000 877787788779877A877F878087818784878687878789878A878C878E878F8790 8791879287948795879687988799879A879B879C879D879E87A087A187A287A3 87A45DCD5FAE537197E68FDD684556F4552F60DF4E3A6F4D7EF482C7840E59D4 4F1F4F2A5C3E7EAC672A851A5473754F80C355829B4F4F4D6E2D8C135C096170 536B761F6E29868A658795FB7EB9543B7A337D0A95EE55E17FC174EE631D8717 6DA17A9D621165A1536763E16C835DEB545C94A84E4C6C618BEC5C4B65E0829C 68A7543E54346BCB6B664E9463425348821E4F0D4FAE575E620A96FE66647269 52FF52A1609F8BEF661471996790897F785277FD6670563B54389521727A0000 CF 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 87A587A687A787A987AA87AE87B087B187B287B487B687B787B887B987BB87BC 87BE87BF87C187C287C387C487C587C787C887C987CC87CD87CE87CF87D087D4 87D587D687D787D887D987DA87DC87DD87DE87DF87E187E287E387E487E687E7 87E887E987EB87EC87ED87EF87F087F187F287F387F487F587F687F787F80000 87FA87FB87FC87FD87FF880088018802880488058806880788088809880B880C 880D880E880F8810881188128814881788188819881A881C881D881E881F8820 88237A00606F5E0C6089819D591560DC718470EF6EAA6C5072806A8488AD5E2D 4E605AB3559C94E36D177CFB9699620F7EC6778E867E5323971E8F9666875CE1 4FA072ED4E0B53A6590F54136380952851484ED99C9C7EA454B88D2488548237 95F26D8E5F265ACC663E966973B0732E53BF817A99857FA15BAA967796507EBF 76F853A2957699997BB189446E584E617FD479658BE660F354CD4EAB98795DF7 6A6150CF54118C618427785D9704524A54EE56A395006D885BB56DC666530000 D0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 882488258826882788288829882A882B882C882D882E882F8830883188338834 8835883688378838883A883B883D883E883F8841884288438846884788488849 884A884B884E884F8850885188528853885588568858885A885B885C885D885E 885F886088668867886A886D886F8871887388748875887688788879887A0000 887B887C88808883888688878889888A888C888E888F88908891889388948895 889788988899889A889B889D889E889F88A088A188A388A588A688A788A888A9 88AA5C0F5B5D6821809655787B11654869544E9B6B47874E978B534F631F643A 90AA659C80C18C10519968B0537887F961C86CC46CFB8C225C5185AA82AF950C 6B238F9B65B05FFB5FC34FE18845661F8165732960FA51745211578B5F6290A2 884C91925E78674F602759D3514451F680F853086C7996C4718A4F114FEE7F9E 673D55C5950879C088967EE3589F620C9700865A5618987B5F908BB884C49157 53D965ED5E8F755C60647D6E5A7F7EEA7EED8F6955A75BA360AC65CB73840000 D1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 88AC88AE88AF88B088B288B388B488B588B688B888B988BA88BB88BD88BE88BF 88C088C388C488C788C888CA88CB88CC88CD88CF88D088D188D388D688D788DA 88DB88DC88DD88DE88E088E188E688E788E988EA88EB88EC88ED88EE88EF88F2 88F588F688F788FA88FB88FD88FF890089018903890489058906890789080000 8909890B890C890D890E890F891189148915891689178918891C891D891E891F 89208922892389248926892789288929892C892D892E892F8931893289338935 89379009766377297EDA9774859B5B667A7496EA884052CB718F5FAA65EC8BE2 5BFB9A6F5DE16B896C5B8BAD8BAF900A8FC5538B62BC9E269E2D54404E2B82BD 7259869C5D1688596DAF96C554D14E9A8BB6710954BD960970DF6DF976D04E25 781487125CA95EF68A00989C960E708E6CBF594463A9773C884D6F1482735830 71D5538C781A96C155015F6671305BB48C1A9A8C6B83592E9E2F79E76768626C 4F6F75A17F8A6D0B96336C274EF075D2517B68376F3E90808170599674760000 D2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 89388939893A893B893C893D893E893F89408942894389458946894789488949 894A894B894C894D894E894F8950895189528953895489558956895789588959 895A895B895C895D896089618962896389648965896789688969896A896B896C 896D896E896F8970897189728973897489758976897789788979897A897C0000 897D897E8980898289848985898789888989898A898B898C898D898E898F8990 899189928993899489958996899789988999899A899B899C899D899E899F89A0 89A164475C2790657A918C2359DA54AC8200836F898180006930564E80367237 91CE51B64E5F987563964E1A53F666F3814B591C6DB24E0058F9533B63D694F1 4F9D4F0A886398905937905779FB4EEA80F075916C825B9C59E85F5D69058681 501A5DF24E5977E34EE5827A6291661390915C794EBF5F7981C69038808475AB 4EA688D4610F6BC55FC64E4976CA6EA28BE38BAE8C0A8BD15F027FFC7FCC7ECE 8335836B56E06BB797F3963459FB541F94F66DEB5BC5996E5C395F1596900000 D3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 89A289A389A489A589A689A789A889A989AA89AB89AC89AD89AE89AF89B089B1 89B289B389B489B589B689B789B889B989BA89BB89BC89BD89BE89BF89C089C3 89CD89D389D489D589D789D889D989DB89DD89DF89E089E189E289E489E789E8 89E989EA89EC89ED89EE89F089F189F289F489F589F689F789F889F989FA0000 89FB89FC89FD89FE89FF8A018A028A038A048A058A068A088A098A0A8A0B8A0C 8A0D8A0E8A0F8A108A118A128A138A148A158A168A178A188A198A1A8A1B8A1C 8A1D537082F16A315A749E705E947F2883B984248425836787478FCE8D6276C8 5F719896786C662054DF62E54F6381C375C85EB896CD8E0A86F9548F6CF36D8C 6C38607F52C775285E7D4F1860A05FE75C24753190AE94C072B96CB96E389149 670953CB53F34F5191C98BF153C85E7C8FC26DE44E8E76C26986865E611A8206 4F594FDE903E9C7C61096E1D6E1496854E885A3196E84E0E5C7F79B95B878BED 7FBD738957DF828B90C15401904755BB5CEA5FA161086B3272F180B28A890000 D4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8A1E8A1F8A208A218A228A238A248A258A268A278A288A298A2A8A2B8A2C8A2D 8A2E8A2F8A308A318A328A338A348A358A368A378A388A398A3A8A3B8A3C8A3D 8A3F8A408A418A428A438A448A458A468A478A498A4A8A4B8A4C8A4D8A4E8A4F 8A508A518A528A538A548A558A568A578A588A598A5A8A5B8A5C8A5D8A5E0000 8A5F8A608A618A628A638A648A658A668A678A688A698A6A8A6B8A6C8A6D8A6E 8A6F8A708A718A728A738A748A758A768A778A788A7A8A7B8A7C8A7D8A7E8A7F 8A806D745BD388D598848C6B9A6D9E336E0A51A4514357A38881539F63F48F95 56ED54585706733F6E907F188FDC82D1613F6028966266F07EA68D8A8DC394A5 5CB37CA4670860A6960580184E9190E75300966851418FD08574915D665597F5 5B55531D78386742683D54C9707E5BB08F7D518D572854B1651266828D5E8D43 810F846C906D7CDF51FF85FB67A365E96FA186A48E81566A90207682707671E5 8D2362E952196CFD8D3C600E589E618E66FE8D60624E55B36E23672D8F670000 D5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8A818A828A838A848A858A868A878A888A8B8A8C8A8D8A8E8A8F8A908A918A92 8A948A958A968A978A988A998A9A8A9B8A9C8A9D8A9E8A9F8AA08AA18AA28AA3 8AA48AA58AA68AA78AA88AA98AAA8AAB8AAC8AAD8AAE8AAF8AB08AB18AB28AB3 8AB48AB58AB68AB78AB88AB98ABA8ABB8ABC8ABD8ABE8ABF8AC08AC18AC20000 8AC38AC48AC58AC68AC78AC88AC98ACA8ACB8ACC8ACD8ACE8ACF8AD08AD18AD2 8AD38AD48AD58AD68AD78AD88AD98ADA8ADB8ADC8ADD8ADE8ADF8AE08AE18AE2 8AE394E195F87728680569A8548B4E4D70B88BC86458658B5B857A84503A5BE8 77BB6BE18A797C986CBE76CF65A98F975D2D5C5586386808536062187AD96E5B 7EFD6A1F7AE05F706F335F20638C6DA867564E085E108D264ED780C07634969C 62DB662D627E6CBC8D7571677F695146808753EC906E629854F286F08F998005 951785178FD96D5973CD659F771F7504782781FB8D1E94884FA6679575B98BCA 9707632F9547963584B8632377415F8172F04E896014657462EF6B63653F0000 D6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8AE48AE58AE68AE78AE88AE98AEA8AEB8AEC8AED8AEE8AEF8AF08AF18AF28AF3 8AF48AF58AF68AF78AF88AF98AFA8AFB8AFC8AFD8AFE8AFF8B008B018B028B03 8B048B058B068B088B098B0A8B0B8B0C8B0D8B0E8B0F8B108B118B128B138B14 8B158B168B178B188B198B1A8B1B8B1C8B1D8B1E8B1F8B208B218B228B230000 8B248B258B278B288B298B2A8B2B8B2C8B2D8B2E8B2F8B308B318B328B338B34 8B358B368B378B388B398B3A8B3B8B3C8B3D8B3E8B3F8B408B418B428B438B44 8B455E2775C790D18BC1829D679D652F5431871877E580A281026C414E4B7EC7 804C76F4690D6B966267503C4F84574063076B628DBE53EA65E87EB85FD7631A 63B781F381F47F6E5E1C5CD95236667A79E97A1A8D28709975D46EDE6CBB7A92 4E2D76C55FE0949F88777EC879CD80BF91CD4EF24F17821F54685DDE6D328BCC 7CA58F7480985E1A549276B15B99663C9AA473E0682A86DB6731732A8BF88BDB 90107AF970DB716E62C477A956314E3B845767F152A986C08D2E94F87B510000 D7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8B468B478B488B498B4A8B4B8B4C8B4D8B4E8B4F8B508B518B528B538B548B55 8B568B578B588B598B5A8B5B8B5C8B5D8B5E8B5F8B608B618B628B638B648B65 8B678B688B698B6A8B6B8B6D8B6E8B6F8B708B718B728B738B748B758B768B77 8B788B798B7A8B7B8B7C8B7D8B7E8B7F8B808B818B828B838B848B858B860000 8B878B888B898B8A8B8B8B8C8B8D8B8E8B8F8B908B918B928B938B948B958B96 8B978B988B998B9A8B9B8B9C8B9D8B9E8B9F8BAC8BB18BBB8BC78BD08BEA8C09 8C1E4F4F6CE8795D9A7B6293722A62FD4E1378168F6C64B08D5A7BC668695E84 88C55986649E58EE72B6690E95258FFD8D5857607F008C0651C6634962D95353 684C74228301914C55447740707C6D4A517954A88D4459FF6ECB6DC45B5C7D2B 4ED47C7D6ED35B5081EA6E0D5B579B0368D58E2A5B977EFC603B7EB590B98D70 594F63CD79DF8DB3535265CF79568BC5963B7EC494BB7E825634918967007F6A 5C0A907566285DE64F5067DE505A4F5C57505EA7000000000000000000000000 D8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8C388C398C3A8C3B8C3C8C3D8C3E8C3F8C408C428C438C448C458C488C4A8C4B 8C4D8C4E8C4F8C508C518C528C538C548C568C578C588C598C5B8C5C8C5D8C5E 8C5F8C608C638C648C658C668C678C688C698C6C8C6D8C6E8C6F8C708C718C72 8C748C758C768C778C7B8C7C8C7D8C7E8C7F8C808C818C838C848C868C870000 8C888C8B8C8D8C8E8C8F8C908C918C928C938C958C968C978C998C9A8C9B8C9C 8C9D8C9E8C9F8CA08CA18CA28CA38CA48CA58CA68CA78CA88CA98CAA8CAB8CAC 8CAD4E8D4E0C51404E105EFF53454E154E984E1E9B325B6C56694E2879BA4E3F 53154E47592D723B536E6C1056DF80E499976BD3777E9F174E364E9F9F104E5C 4E694E9382885B5B556C560F4EC4538D539D53A353A553AE97658D5D531A53F5 5326532E533E8D5C5366536352025208520E522D5233523F5240524C525E5261 525C84AF527D528252815290529351827F544EBB4EC34EC94EC24EE84EE14EEB 4EDE4F1B4EF34F224F644EF54F254F274F094F2B4F5E4F6765384F5A4F5D0000 D9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8CAE8CAF8CB08CB18CB28CB38CB48CB58CB68CB78CB88CB98CBA8CBB8CBC8CBD 8CBE8CBF8CC08CC18CC28CC38CC48CC58CC68CC78CC88CC98CCA8CCB8CCC8CCD 8CCE8CCF8CD08CD18CD28CD38CD48CD58CD68CD78CD88CD98CDA8CDB8CDC8CDD 8CDE8CDF8CE08CE18CE28CE38CE48CE58CE68CE78CE88CE98CEA8CEB8CEC0000 8CED8CEE8CEF8CF08CF18CF28CF38CF48CF58CF68CF78CF88CF98CFA8CFB8CFC 8CFD8CFE8CFF8D008D018D028D038D048D058D068D078D088D098D0A8D0B8D0C 8D0D4F5F4F574F324F3D4F764F744F914F894F834F8F4F7E4F7B4FAA4F7C4FAC 4F944FE64FE84FEA4FC54FDA4FE34FDC4FD14FDF4FF85029504C4FF3502C500F 502E502D4FFE501C500C50255028507E504350555048504E506C507B50A550A7 50A950BA50D6510650ED50EC50E650EE5107510B4EDD6C3D4F584F654FCE9FA0 6C467C74516E5DFD9EC999985181591452F9530D8A07531051EB591951554EA0 51564EB3886E88A44EB5811488D279805B3488037FB851AB51B151BD51BC0000 DA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8D0E8D0F8D108D118D128D138D148D158D168D178D188D198D1A8D1B8D1C8D20 8D518D528D578D5F8D658D688D698D6A8D6C8D6E8D6F8D718D728D788D798D7A 8D7B8D7C8D7D8D7E8D7F8D808D828D838D868D878D888D898D8C8D8D8D8E8D8F 8D908D928D938D958D968D978D988D998D9A8D9B8D9C8D9D8D9E8DA08DA10000 8DA28DA48DA58DA68DA78DA88DA98DAA8DAB8DAC8DAD8DAE8DAF8DB08DB28DB6 8DB78DB98DBB8DBD8DC08DC18DC28DC58DC78DC88DC98DCA8DCD8DD08DD28DD3 8DD451C7519651A251A58BA08BA68BA78BAA8BB48BB58BB78BC28BC38BCB8BCF 8BCE8BD28BD38BD48BD68BD88BD98BDC8BDF8BE08BE48BE88BE98BEE8BF08BF3 8BF68BF98BFC8BFF8C008C028C048C078C0C8C0F8C118C128C148C158C168C19 8C1B8C188C1D8C1F8C208C218C258C278C2A8C2B8C2E8C2F8C328C338C358C36 5369537A961D962296219631962A963D963C964296499654965F9667966C9672 96749688968D969796B09097909B909D909990AC90A190B490B390B690BA0000 DB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8DD58DD88DD98DDC8DE08DE18DE28DE58DE68DE78DE98DED8DEE8DF08DF18DF2 8DF48DF68DFC8DFE8DFF8E008E018E028E038E048E068E078E088E0B8E0D8E0E 8E108E118E128E138E158E168E178E188E198E1A8E1B8E1C8E208E218E248E25 8E268E278E288E2B8E2D8E308E328E338E348E368E378E388E3B8E3C8E3E0000 8E3F8E438E458E468E4C8E4D8E4E8E4F8E508E538E548E558E568E578E588E5A 8E5B8E5C8E5D8E5E8E5F8E608E618E628E638E648E658E678E688E6A8E6B8E6E 8E7190B890B090CF90C590BE90D090C490C790D390E690E290DC90D790DB90EB 90EF90FE91049122911E91239131912F913991439146520D594252A252AC52AD 52BE54FF52D052D652F053DF71EE77CD5EF451F551FC9B2F53B65F01755A5DEF 574C57A957A1587E58BC58C558D15729572C572A57335739572E572F575C573B 574257695785576B5786577C577B5768576D5776577357AD57A4578C57B257CF 57A757B4579357A057D557D857DA57D957D257B857F457EF57F857E457DD0000 DC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8E738E758E778E788E798E7A8E7B8E7D8E7E8E808E828E838E848E868E888E89 8E8A8E8B8E8C8E8D8E8E8E918E928E938E958E968E978E988E998E9A8E9B8E9D 8E9F8EA08EA18EA28EA38EA48EA58EA68EA78EA88EA98EAA8EAD8EAE8EB08EB1 8EB38EB48EB58EB68EB78EB88EB98EBB8EBC8EBD8EBE8EBF8EC08EC18EC20000 8EC38EC48EC58EC68EC78EC88EC98ECA8ECB8ECC8ECD8ECF8ED08ED18ED28ED3 8ED48ED58ED68ED78ED88ED98EDA8EDB8EDC8EDD8EDE8EDF8EE08EE18EE28EE3 8EE4580B580D57FD57ED5800581E5819584458205865586C58815889589A5880 99A89F1961FF8279827D827F828F828A82A88284828E82918297829982AB82B8 82BE82B082C882CA82E3829882B782AE82CB82CC82C182A982B482A182AA829F 82C482CE82A482E1830982F782E4830F830782DC82F482D282D8830C82FB82D3 8311831A83068314831582E082D5831C8351835B835C83088392833C83348331 839B835E832F834F83478343835F834083178360832D833A8333836683650000 DD 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8EE58EE68EE78EE88EE98EEA8EEB8EEC8EED8EEE8EEF8EF08EF18EF28EF38EF4 8EF58EF68EF78EF88EF98EFA8EFB8EFC8EFD8EFE8EFF8F008F018F028F038F04 8F058F068F078F088F098F0A8F0B8F0C8F0D8F0E8F0F8F108F118F128F138F14 8F158F168F178F188F198F1A8F1B8F1C8F1D8F1E8F1F8F208F218F228F230000 8F248F258F268F278F288F298F2A8F2B8F2C8F2D8F2E8F2F8F308F318F328F33 8F348F358F368F378F388F398F3A8F3B8F3C8F3D8F3E8F3F8F408F418F428F43 8F448368831B8369836C836A836D836E83B0837883B383B483A083AA8393839C 8385837C83B683A9837D83B8837B8398839E83A883BA83BC83C1840183E583D8 58078418840B83DD83FD83D6841C84388411840683D483DF840F840383F883F9 83EA83C583C0842683F083E1845C8451845A8459847384878488847A84898478 843C844684698476848C848E8431846D84C184CD84D084E684BD84D384CA84BF 84BA84E084A184B984B4849784E584E3850C750D853884F08539851F853A0000 DE 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8F458F468F478F488F498F4A8F4B8F4C8F4D8F4E8F4F8F508F518F528F538F54 8F558F568F578F588F598F5A8F5B8F5C8F5D8F5E8F5F8F608F618F628F638F64 8F658F6A8F808F8C8F928F9D8FA08FA18FA28FA48FA58FA68FA78FAA8FAC8FAD 8FAE8FAF8FB28FB38FB48FB58FB78FB88FBA8FBB8FBC8FBF8FC08FC38FC60000 8FC98FCA8FCB8FCC8FCD8FCF8FD28FD68FD78FDA8FE08FE18FE38FE78FEC8FEF 8FF18FF28FF48FF58FF68FFA8FFB8FFC8FFE8FFF90079008900C900E90139015 90188556853B84FF84FC8559854885688564855E857A77A285438572857B85A4 85A88587858F857985AE859C858585B985B785B085D385C185DC85FF86278605 86298616863C5EFE5F08593C594180375955595A5958530F5C225C255C2C5C34 624C626A629F62BB62CA62DA62D762EE632262F66339634B634363AD63F66371 637A638E63B4636D63AC638A636963AE63BC63F263F863E063FF63C463DE63CE 645263C663BE64456441640B641B6420640C64266421645E6484646D64960000 DF 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 9019901C902390249025902790289029902A902B902C90309031903290339034 90379039903A903D903F904090439045904690489049904A904B904C904E9054 905590569059905A905C905D905E905F906090619064906690679069906A906B 906C906F90709071907290739076907790789079907A907B907C907E90810000 90849085908690879089908A908C908D908E908F90909092909490969098909A 909C909E909F90A090A490A590A790A890A990AB90AD90B290B790BC90BD90BF 90C0647A64B764B8649964BA64C064D064D764E464E265096525652E5F0B5FD2 75195F11535F53F153FD53E953E853FB541254165406544B5452545354545456 54435421545754595423543254825494547754715464549A549B548454765466 549D54D054AD54C254B454D254A754A654D354D4547254A354D554BB54BF54CC 54D954DA54DC54A954AA54A454DD54CF54DE551B54E7552054FD551454F35522 5523550F55115527552A5567558F55B55549556D55415555553F5550553C0000 E0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 90C290C390C690C890C990CB90CC90CD90D290D490D590D690D890D990DA90DE 90DF90E090E390E490E590E990EA90EC90EE90F090F190F290F390F590F690F7 90F990FA90FB90FC90FF91009101910391059106910791089109910A910B910C 910D910E910F911091119112911391149115911691179118911A911B911C0000 911D911F91209121912491259126912791289129912A912B912C912D912E9130 9132913391349135913691379138913A913B913C913D913E913F914091419142 91445537555655755576557755335530555C558B55D2558355B155B955885581 559F557E55D65591557B55DF55BD55BE5594559955EA55F755C9561F55D155EB 55EC55D455E655DD55C455EF55E555F255F355CC55CD55E855F555E48F94561E 5608560C56015624562355FE56005627562D565856395657562C564D56625659 565C564C5654568656645671566B567B567C5685569356AF56D456D756DD56E1 56F556EB56F956FF5704570A5709571C5E0F5E195E145E115E315E3B5E3C0000 E1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 9145914791489151915391549155915691589159915B915C915F916091669167 9168916B916D9173917A917B917C9180918191829183918491869188918A918E 918F9193919491959196919791989199919C919D919E919F91A091A191A491A5 91A691A791A891A991AB91AC91B091B191B291B391B691B791B891B991BB0000 91BC91BD91BE91BF91C091C191C291C391C491C591C691C891CB91D091D291D3 91D491D591D691D791D891D991DA91DB91DD91DE91DF91E091E191E291E391E4 91E55E375E445E545E5B5E5E5E615C8C5C7A5C8D5C905C965C885C985C995C91 5C9A5C9C5CB55CA25CBD5CAC5CAB5CB15CA35CC15CB75CC45CD25CE45CCB5CE5 5D025D035D275D265D2E5D245D1E5D065D1B5D585D3E5D345D3D5D6C5D5B5D6F 5D5D5D6B5D4B5D4A5D695D745D825D995D9D8C735DB75DC55F735F775F825F87 5F895F8C5F955F995F9C5FA85FAD5FB55FBC88625F6172AD72B072B472B772B8 72C372C172CE72CD72D272E872EF72E972F272F472F7730172F3730372FA0000 E2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 91E691E791E891E991EA91EB91EC91ED91EE91EF91F091F191F291F391F491F5 91F691F791F891F991FA91FB91FC91FD91FE91FF920092019202920392049205 9206920792089209920A920B920C920D920E920F921092119212921392149215 9216921792189219921A921B921C921D921E921F922092219222922392240000 92259226922792289229922A922B922C922D922E922F92309231923292339234 92359236923792389239923A923B923C923D923E923F92409241924292439244 924572FB731773137321730A731E731D7315732273397325732C733873317350 734D73577360736C736F737E821B592598E7592459029963996799689969996A 996B996C99749977997D998099849987998A998D999099919993999499955E80 5E915E8B5E965EA55EA05EB95EB55EBE5EB38D535ED25ED15EDB5EE85EEA81BA 5FC45FC95FD65FCF60035FEE60045FE15FE45FFE600560065FEA5FED5FF86019 60356026601B600F600D6029602B600A603F602160786079607B607A60420000 E3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 9246924792489249924A924B924C924D924E924F925092519252925392549255 9256925792589259925A925B925C925D925E925F926092619262926392649265 9266926792689269926A926B926C926D926E926F927092719272927392759276 927792789279927A927B927C927D927E927F9280928192829283928492850000 9286928792889289928A928B928C928D928F9290929192929293929492959296 929792989299929A929B929C929D929E929F92A092A192A292A392A492A592A6 92A7606A607D6096609A60AD609D60836092608C609B60EC60BB60B160DD60D8 60C660DA60B4612061266115612360F46100610E612B614A617561AC619461A7 61B761D461F55FDD96B395E995EB95F195F395F595F695FC95FE960396049606 9608960A960B960C960D960F96129615961696179619961A4E2C723F62156C35 6C546C5C6C4A6CA36C856C906C946C8C6C686C696C746C766C866CA96CD06CD4 6CAD6CF76CF86CF16CD76CB26CE06CD66CFA6CEB6CEE6CB16CD36CEF6CFE0000 E4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 92A892A992AA92AB92AC92AD92AF92B092B192B292B392B492B592B692B792B8 92B992BA92BB92BC92BD92BE92BF92C092C192C292C392C492C592C692C792C9 92CA92CB92CC92CD92CE92CF92D092D192D292D392D492D592D692D792D892D9 92DA92DB92DC92DD92DE92DF92E092E192E292E392E492E592E692E792E80000 92E992EA92EB92EC92ED92EE92EF92F092F192F292F392F492F592F692F792F8 92F992FA92FB92FC92FD92FE92FF930093019302930393049305930693079308 93096D396D276D0C6D436D486D076D046D196D0E6D2B6D4D6D2E6D356D1A6D4F 6D526D546D336D916D6F6D9E6DA06D5E6D936D946D5C6D606D7C6D636E1A6DC7 6DC56DDE6E0E6DBF6DE06E116DE66DDD6DD96E166DAB6E0C6DAE6E2B6E6E6E4E 6E6B6EB26E5F6E866E536E546E326E256E446EDF6EB16E986EE06F2D6EE26EA5 6EA76EBD6EBB6EB76ED76EB46ECF6E8F6EC26E9F6F626F466F476F246F156EF9 6F2F6F366F4B6F746F2A6F096F296F896F8D6F8C6F786F726F7C6F7A6FD10000 E5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 930A930B930C930D930E930F9310931193129313931493159316931793189319 931A931B931C931D931E931F9320932193229323932493259326932793289329 932A932B932C932D932E932F9330933193329333933493359336933793389339 933A933B933C933D933F93409341934293439344934593469347934893490000 934A934B934C934D934E934F9350935193529353935493559356935793589359 935A935B935C935D935E935F9360936193629363936493659366936793689369 936B6FC96FA76FB96FB66FC26FE16FEE6FDE6FE06FEF701A7023701B70397035 704F705E5B805B845B955B935BA55BB8752F9A9E64345BE45BEE89305BF08E47 8B078FB68FD38FD58FE58FEE8FE48FE98FE68FF38FE890059004900B90269011 900D9016902190359036902D902F9044905190529050906890589062905B66B9 9074907D908290889083908B5F505F575F565F585C3B54AB5C505C595B715C63 5C667FBC5F2A5F295F2D82745F3C9B3B5C6E59815983598D59A959AA59A30000 E6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 936C936D936E936F9370937193729373937493759376937793789379937A937B 937C937D937E937F9380938193829383938493859386938793889389938A938B 938C938D938E9390939193929393939493959396939793989399939A939B939C 939D939E939F93A093A193A293A393A493A593A693A793A893A993AA93AB0000 93AC93AD93AE93AF93B093B193B293B393B493B593B693B793B893B993BA93BB 93BC93BD93BE93BF93C093C193C293C393C493C593C693C793C893C993CB93CC 93CD599759CA59AB599E59A459D259B259AF59D759BE5A055A0659DD5A0859E3 59D859F95A0C5A095A325A345A115A235A135A405A675A4A5A555A3C5A625A75 80EC5AAA5A9B5A775A7A5ABE5AEB5AB25AD25AD45AB85AE05AE35AF15AD65AE6 5AD85ADC5B095B175B165B325B375B405C155C1C5B5A5B655B735B515B535B62 9A759A779A789A7A9A7F9A7D9A809A819A859A889A8A9A909A929A939A969A98 9A9B9A9C9A9D9A9F9AA09AA29AA39AA59AA77E9F7EA17EA37EA57EA87EA90000 E7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 93CE93CF93D093D193D293D393D493D593D793D893D993DA93DB93DC93DD93DE 93DF93E093E193E293E393E493E593E693E793E893E993EA93EB93EC93ED93EE 93EF93F093F193F293F393F493F593F693F793F893F993FA93FB93FC93FD93FE 93FF9400940194029403940494059406940794089409940A940B940C940D0000 940E940F9410941194129413941494159416941794189419941A941B941C941D 941E941F9420942194229423942494259426942794289429942A942B942C942D 942E7EAD7EB07EBE7EC07EC17EC27EC97ECB7ECC7ED07ED47ED77EDB7EE07EE1 7EE87EEB7EEE7EEF7EF17EF27F0D7EF67EFA7EFB7EFE7F017F027F037F077F08 7F0B7F0C7F0F7F117F127F177F197F1C7F1B7F1F7F217F227F237F247F257F26 7F277F2A7F2B7F2C7F2D7F2F7F307F317F327F337F355E7A757F5DDB753E9095 738E739173AE73A2739F73CF73C273D173B773B373C073C973C873E573D9987C 740A73E973E773DE73BA73F2740F742A745B7426742574287430742E742C0000 E8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 942F9430943194329433943494359436943794389439943A943B943C943D943F 9440944194429443944494459446944794489449944A944B944C944D944E944F 9450945194529453945494559456945794589459945A945B945C945D945E945F 9460946194629463946494659466946794689469946A946C946D946E946F0000 9470947194729473947494759476947794789479947A947B947C947D947E947F 9480948194829483948494919496949894C794CF94D394D494DA94E694FB951C 9520741B741A7441745C7457745574597477746D747E749C748E748074817487 748B749E74A874A9749074A774D274BA97EA97EB97EC674C6753675E67486769 67A56787676A6773679867A7677567A8679E67AD678B6777677C67F0680967D8 680A67E967B0680C67D967B567DA67B367DD680067C367B867E2680E67C167FD 6832683368606861684E6862684468646883681D68556866684168676840683E 684A6849682968B5688F687468776893686B68C2696E68FC691F692068F90000 E9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 95279533953D95439548954B9555955A9560956E95749575957795789579957A 957B957C957D957E9580958195829583958495859586958795889589958A958B 958C958D958E958F9590959195929593959495959596959795989599959A959B 959C959D959E959F95A095A195A295A395A495A595A695A795A895A995AA0000 95AB95AC95AD95AE95AF95B095B195B295B395B495B595B695B795B895B995BA 95BB95BC95BD95BE95BF95C095C195C295C395C495C595C695C795C895C995CA 95CB692468F0690B6901695768E369106971693969606942695D6984696B6980 69986978693469CC6987698869CE6989696669636979699B69A769BB69AB69AD 69D469B169C169CA69DF699569E0698D69FF6A2F69ED6A176A186A6569F26A44 6A3E6AA06A506A5B6A356A8E6A796A3D6A286A586A7C6A916A906AA96A976AAB 733773526B816B826B876B846B926B936B8D6B9A6B9B6BA16BAA8F6B8F6D8F71 8F728F738F758F768F788F778F798F7A8F7C8F7E8F818F828F848F878F8B0000 EA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 95CC95CD95CE95CF95D095D195D295D395D495D595D695D795D895D995DA95DB 95DC95DD95DE95DF95E095E195E295E395E495E595E695E795EC95FF96079613 9618961B961E96209623962496259626962796289629962B962C962D962F9630 963796389639963A963E96419643964A964E964F965196529653965696570000 96589659965A965C965D965E9660966396659666966B966D966E966F96709671 967396789679967A967B967C967D967E967F9680968196829683968496879689 968A8F8D8F8E8F8F8F988F9A8ECE620B6217621B621F6222622162256224622C 81E774EF74F474FF750F75117513653465EE65EF65F0660A6619677266036615 6600708566F7661D66346631663666358006665F66546641664F665666616657 66776684668C66A7669D66BE66DB66DC66E666E98D328D338D368D3B8D3D8D40 8D458D468D488D498D478D4D8D558D5989C789CA89CB89CC89CE89CF89D089D1 726E729F725D7266726F727E727F7284728B728D728F72926308633263B00000 EB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 968C968E96919692969396959696969A969B969D969E969F96A096A196A296A3 96A496A596A696A896A996AA96AB96AC96AD96AE96AF96B196B296B496B596B7 96B896BA96BB96BF96C296C396C896CA96CB96D096D196D396D496D696D796D8 96D996DA96DB96DC96DD96DE96DF96E196E296E396E496E596E696E796EB0000 96EC96ED96EE96F096F196F296F496F596F896FA96FB96FC96FD96FF97029703 9705970A970B970C97109711971297149715971797189719971A971B971D971F 9720643F64D880046BEA6BF36BFD6BF56BF96C056C076C066C0D6C156C186C19 6C1A6C216C296C246C2A6C3265356555656B724D72527256723086625216809F 809C809380BC670A80BD80B180AB80AD80B480B780E780E880E980EA80DB80C2 80C480D980CD80D7671080DD80EB80F180F480ED810D810E80F280FC67158112 8C5A8136811E812C811881328148814C815381748159815A817181608169817C 817D816D8167584D5AB58188818281916ED581A381AA81CC672681CA81BB0000 EC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 972197229723972497259726972797289729972B972C972E972F973197339734 973597369737973A973B973C973D973F97409741974297439744974597469747 97489749974A974B974C974D974E974F975097519754975597579758975A975C 975D975F97639764976697679768976A976B976C976D976E976F977097710000 97729775977797789779977A977B977D977E977F978097819782978397849786 978797889789978A978C978E978F979097939795979697979799979A979B979C 979D81C181A66B246B376B396B436B466B5998D198D298D398D598D998DA6BB3 5F406BC289F365909F51659365BC65C665C465C365CC65CE65D265D67080709C 7096709D70BB70C070B770AB70B170E870CA711071137116712F71317173715C 716871457172714A7178717A719871B371B571A871A071E071D471E771F9721D 7228706C7118716671B9623E623D624362486249793B794079467949795B795C 7953795A796279577960796F7967797A7985798A799A79A779B35FD15FD00000 ED 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 979E979F97A197A297A497A597A697A797A897A997AA97AC97AE97B097B197B3 97B597B697B797B897B997BA97BB97BC97BD97BE97BF97C097C197C297C397C4 97C597C697C797C897C997CA97CB97CC97CD97CE97CF97D097D197D297D397D4 97D597D697D797D897D997DA97DB97DC97DD97DE97DF97E097E197E297E30000 97E497E597E897EE97EF97F097F197F297F497F797F897F997FA97FB97FC97FD 97FE97FF9800980198029803980498059806980798089809980A980B980C980D 980E603C605D605A606760416059606360AB6106610D615D61A9619D61CB61D1 62068080807F6C936CF66DFC77F677F87800780978177818781165AB782D781C 781D7839783A783B781F783C7825782C78237829784E786D7856785778267850 7847784C786A789B7893789A7887789C78A178A378B278B978A578D478D978C9 78EC78F2790578F479137924791E79349F9B9EF99EFB9EFC76F17704770D76F9 77077708771A77227719772D7726773577387750775177477743775A77680000 EE 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 980F9810981198129813981498159816981798189819981A981B981C981D981E 981F9820982198229823982498259826982798289829982A982B982C982D982E 982F9830983198329833983498359836983798389839983A983B983C983D983E 983F9840984198429843984498459846984798489849984A984B984C984D0000 984E984F9850985198529853985498559856985798589859985A985B985C985D 985E985F9860986198629863986498659866986798689869986A986B986C986D 986E77627765777F778D777D7780778C7791779F77A077B077B577BD753A7540 754E754B7548755B7572757975837F587F617F5F8A487F687F747F717F797F81 7F7E76CD76E58832948594869487948B948A948C948D948F9490949494979495 949A949B949C94A394A494AB94AA94AD94AC94AF94B094B294B494B694B794B8 94B994BA94BC94BD94BF94C494C894C994CA94CB94CC94CD94CE94D094D194D2 94D594D694D794D994D894DB94DE94DF94E094E294E494E594E794E894EA0000 EF 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 986F98709871987298739874988B988E98929895989998A398A898A998AA98AB 98AC98AD98AE98AF98B098B198B298B398B498B598B698B798B898B998BA98BB 98BC98BD98BE98BF98C098C198C298C398C498C598C698C798C898C998CA98CB 98CC98CD98CF98D098D498D698D798DB98DC98DD98E098E198E298E398E40000 98E598E698E998EA98EB98EC98ED98EE98EF98F098F198F298F398F498F598F6 98F798F898F998FA98FB98FC98FD98FE98FF9900990199029903990499059906 990794E994EB94EE94EF94F394F494F594F794F994FC94FD94FF950395029506 95079509950A950D950E950F951295139514951595169518951B951D951E951F 9522952A952B9529952C953195329534953695379538953C953E953F95429535 9544954595469549954C954E954F9552955395549556955795589559955B955E 955F955D95619562956495659566956795689569956A956B956C956F95719572 9573953A77E777EC96C979D579ED79E379EB7A065D477A037A027A1E7A140000 F0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 99089909990A990B990C990E990F991199129913991499159916991799189919 991A991B991C991D991E991F9920992199229923992499259926992799289929 992A992B992C992D992F9930993199329933993499359936993799389939993A 993B993C993D993E993F99409941994299439944994599469947994899490000 994A994B994C994D994E994F99509951995299539956995799589959995A995B 995C995D995E995F99609961996299649966997399789979997B997E99829983 99897A397A377A519ECF99A57A707688768E7693769976A474DE74E0752C9E20 9E229E289E299E2A9E2B9E2C9E329E319E369E389E379E399E3A9E3E9E419E42 9E449E469E479E489E499E4B9E4C9E4E9E519E559E579E5A9E5B9E5C9E5E9E63 9E669E679E689E699E6A9E6B9E6C9E719E6D9E7375927594759675A0759D75AC 75A375B375B475B875C475B175B075C375C275D675CD75E375E875E675E475EB 75E7760375F175FC75FF761076007605760C7617760A76257618761576190000 F1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 998C998E999A999B999C999D999E999F99A099A199A299A399A499A699A799A9 99AA99AB99AC99AD99AE99AF99B099B199B299B399B499B599B699B799B899B9 99BA99BB99BC99BD99BE99BF99C099C199C299C399C499C599C699C799C899C9 99CA99CB99CC99CD99CE99CF99D099D199D299D399D499D599D699D799D80000 99D999DA99DB99DC99DD99DE99DF99E099E199E299E399E499E599E699E799E8 99E999EA99EB99EC99ED99EE99EF99F099F199F299F399F499F599F699F799F8 99F9761B763C762276207640762D7630763F76357643763E7633764D765E7654 765C7656766B766F7FCA7AE67A787A797A807A867A887A957AA67AA07AAC7AA8 7AAD7AB3886488698872887D887F888288A288C688B788BC88C988E288CE88E3 88E588F1891A88FC88E888FE88F0892189198913891B890A8934892B89368941 8966897B758B80E576B276B477DC801280148016801C80208022802580268027 802980288031800B803580438046804D80528069807189839878988098830000 F2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 99FA99FB99FC99FD99FE99FF9A009A019A029A039A049A059A069A079A089A09 9A0A9A0B9A0C9A0D9A0E9A0F9A109A119A129A139A149A159A169A179A189A19 9A1A9A1B9A1C9A1D9A1E9A1F9A209A219A229A239A249A259A269A279A289A29 9A2A9A2B9A2C9A2D9A2E9A2F9A309A319A329A339A349A359A369A379A380000 9A399A3A9A3B9A3C9A3D9A3E9A3F9A409A419A429A439A449A459A469A479A48 9A499A4A9A4B9A4C9A4D9A4E9A4F9A509A519A529A539A549A559A569A579A58 9A599889988C988D988F9894989A989B989E989F98A198A298A598A6864D8654 866C866E867F867A867C867B86A8868D868B86AC869D86A786A386AA869386A9 86B686C486B586CE86B086BA86B186AF86C986CF86B486E986F186F286ED86F3 86D0871386DE86F486DF86D886D18703870786F88708870A870D87098723873B 871E8725872E871A873E87488734873187298737873F87828722877D877E877B 87608770874C876E878B87538763877C876487598765879387AF87A887D20000 F3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 9A5A9A5B9A5C9A5D9A5E9A5F9A609A619A629A639A649A659A669A679A689A69 9A6A9A6B9A729A839A899A8D9A8E9A949A959A999AA69AA99AAA9AAB9AAC9AAD 9AAE9AAF9AB29AB39AB49AB59AB99ABB9ABD9ABE9ABF9AC39AC49AC69AC79AC8 9AC99ACA9ACD9ACE9ACF9AD09AD29AD49AD59AD69AD79AD99ADA9ADB9ADC0000 9ADD9ADE9AE09AE29AE39AE49AE59AE79AE89AE99AEA9AEC9AEE9AF09AF19AF2 9AF39AF49AF59AF69AF79AF89AFA9AFC9AFD9AFE9AFF9B009B019B029B049B05 9B0687C68788878587AD8797878387AB87E587AC87B587B387CB87D387BD87D1 87C087CA87DB87EA87E087EE8816881387FE880A881B88218839883C7F367F42 7F447F4582107AFA7AFD7B087B037B047B157B0A7B2B7B0F7B477B387B2A7B19 7B2E7B317B207B257B247B337B3E7B1E7B587B5A7B457B757B4C7B5D7B607B6E 7B7B7B627B727B717B907BA67BA77BB87BAC7B9D7BA87B857BAA7B9C7BA27BAB 7BB47BD17BC17BCC7BDD7BDA7BE57BE67BEA7C0C7BFE7BFC7C0F7C167C0B0000 F4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 9B079B099B0A9B0B9B0C9B0D9B0E9B109B119B129B149B159B169B179B189B19 9B1A9B1B9B1C9B1D9B1E9B209B219B229B249B259B269B279B289B299B2A9B2B 9B2C9B2D9B2E9B309B319B339B349B359B369B379B389B399B3A9B3D9B3E9B3F 9B409B469B4A9B4B9B4C9B4E9B509B529B539B559B569B579B589B599B5A0000 9B5B9B5C9B5D9B5E9B5F9B609B619B629B639B649B659B669B679B689B699B6A 9B6B9B6C9B6D9B6E9B6F9B709B719B729B739B749B759B769B779B789B799B7A 9B7B7C1F7C2A7C267C387C417C4081FE82018202820481EC8844822182228223 822D822F8228822B8238823B82338234823E82448249824B824F825A825F8268 887E8885888888D888DF895E7F9D7F9F7FA77FAF7FB07FB27C7C65497C917C9D 7C9C7C9E7CA27CB27CBC7CBD7CC17CC77CCC7CCD7CC87CC57CD77CE8826E66A8 7FBF7FCE7FD57FE57FE17FE67FE97FEE7FF37CF87D777DA67DAE7E477E9B9EB8 9EB48D738D848D948D918DB18D678D6D8C478C49914A9150914E914F91640000 F5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 9B7C9B7D9B7E9B7F9B809B819B829B839B849B859B869B879B889B899B8A9B8B 9B8C9B8D9B8E9B8F9B909B919B929B939B949B959B969B979B989B999B9A9B9B 9B9C9B9D9B9E9B9F9BA09BA19BA29BA39BA49BA59BA69BA79BA89BA99BAA9BAB 9BAC9BAD9BAE9BAF9BB09BB19BB29BB39BB49BB59BB69BB79BB89BB99BBA0000 9BBB9BBC9BBD9BBE9BBF9BC09BC19BC29BC39BC49BC59BC69BC79BC89BC99BCA 9BCB9BCC9BCD9BCE9BCF9BD09BD19BD29BD39BD49BD59BD69BD79BD89BD99BDA 9BDB9162916191709169916F917D917E917291749179918C91859190918D9191 91A291A391AA91AD91AE91AF91B591B491BA8C559E7E8DB88DEB8E058E598E69 8DB58DBF8DBC8DBA8DC48DD68DD78DDA8DDE8DCE8DCF8DDB8DC68DEC8DF78DF8 8DE38DF98DFB8DE48E098DFD8E148E1D8E1F8E2C8E2E8E238E2F8E3A8E408E39 8E358E3D8E318E498E418E428E518E528E4A8E708E768E7C8E6F8E748E858E8F 8E948E908E9C8E9E8C788C828C8A8C858C988C94659B89D689DE89DA89DC0000 F6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 9BDC9BDD9BDE9BDF9BE09BE19BE29BE39BE49BE59BE69BE79BE89BE99BEA9BEB 9BEC9BED9BEE9BEF9BF09BF19BF29BF39BF49BF59BF69BF79BF89BF99BFA9BFB 9BFC9BFD9BFE9BFF9C009C019C029C039C049C059C069C079C089C099C0A9C0B 9C0C9C0D9C0E9C0F9C109C119C129C139C149C159C169C179C189C199C1A0000 9C1B9C1C9C1D9C1E9C1F9C209C219C229C239C249C259C269C279C289C299C2A 9C2B9C2C9C2D9C2E9C2F9C309C319C329C339C349C359C369C379C389C399C3A 9C3B89E589EB89EF8A3E8B26975396E996F396EF970697019708970F970E972A 972D9730973E9F809F839F859F869F879F889F899F8A9F8C9EFE9F0B9F0D96B9 96BC96BD96CE96D277BF96E0928E92AE92C8933E936A93CA938F943E946B9C7F 9C829C859C869C879C887A239C8B9C8E9C909C919C929C949C959C9A9C9B9C9E 9C9F9CA09CA19CA29CA39CA59CA69CA79CA89CA99CAB9CAD9CAE9CB09CB19CB2 9CB39CB49CB59CB69CB79CBA9CBB9CBC9CBD9CC49CC59CC69CC79CCA9CCB0000 F7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 9C3C9C3D9C3E9C3F9C409C419C429C439C449C459C469C479C489C499C4A9C4B 9C4C9C4D9C4E9C4F9C509C519C529C539C549C559C569C579C589C599C5A9C5B 9C5C9C5D9C5E9C5F9C609C619C629C639C649C659C669C679C689C699C6A9C6B 9C6C9C6D9C6E9C6F9C709C719C729C739C749C759C769C779C789C799C7A0000 9C7B9C7D9C7E9C809C839C849C899C8A9C8C9C8F9C939C969C979C989C999C9D 9CAA9CAC9CAF9CB99CBE9CBF9CC09CC19CC29CC89CC99CD19CD29CDA9CDB9CE0 9CE19CCC9CCD9CCE9CCF9CD09CD39CD49CD59CD79CD89CD99CDC9CDD9CDF9CE2 977C978597919792979497AF97AB97A397B297B49AB19AB09AB79E589AB69ABA 9ABC9AC19AC09AC59AC29ACB9ACC9AD19B459B439B479B499B489B4D9B5198E8 990D992E995599549ADF9AE19AE69AEF9AEB9AFB9AED9AF99B089B0F9B139B1F 9B239EBD9EBE7E3B9E829E879E889E8B9E9293D69E9D9E9F9EDB9EDC9EDD9EE0 9EDF9EE29EE99EE79EE59EEA9EEF9F229F2C9F2F9F399F379F3D9F3E9F440000 F8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 9CE39CE49CE59CE69CE79CE89CE99CEA9CEB9CEC9CED9CEE9CEF9CF09CF19CF2 9CF39CF49CF59CF69CF79CF89CF99CFA9CFB9CFC9CFD9CFE9CFF9D009D019D02 9D039D049D059D069D079D089D099D0A9D0B9D0C9D0D9D0E9D0F9D109D119D12 9D139D149D159D169D179D189D199D1A9D1B9D1C9D1D9D1E9D1F9D209D210000 9D229D239D249D259D269D279D289D299D2A9D2B9D2C9D2D9D2E9D2F9D309D31 9D329D339D349D359D369D379D389D399D3A9D3B9D3C9D3D9D3E9D3F9D409D41 9D42000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 F9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 9D439D449D459D469D479D489D499D4A9D4B9D4C9D4D9D4E9D4F9D509D519D52 9D539D549D559D569D579D589D599D5A9D5B9D5C9D5D9D5E9D5F9D609D619D62 9D639D649D659D669D679D689D699D6A9D6B9D6C9D6D9D6E9D6F9D709D719D72 9D739D749D759D769D779D789D799D7A9D7B9D7C9D7D9D7E9D7F9D809D810000 9D829D839D849D859D869D879D889D899D8A9D8B9D8C9D8D9D8E9D8F9D909D91 9D929D939D949D959D969D979D989D999D9A9D9B9D9C9D9D9D9E9D9F9DA09DA1 9DA2000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 FA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 9DA39DA49DA59DA69DA79DA89DA99DAA9DAB9DAC9DAD9DAE9DAF9DB09DB19DB2 9DB39DB49DB59DB69DB79DB89DB99DBA9DBB9DBC9DBD9DBE9DBF9DC09DC19DC2 9DC39DC49DC59DC69DC79DC89DC99DCA9DCB9DCC9DCD9DCE9DCF9DD09DD19DD2 9DD39DD49DD59DD69DD79DD89DD99DDA9DDB9DDC9DDD9DDE9DDF9DE09DE10000 9DE29DE39DE49DE59DE69DE79DE89DE99DEA9DEB9DEC9DED9DEE9DEF9DF09DF1 9DF29DF39DF49DF59DF69DF79DF89DF99DFA9DFB9DFC9DFD9DFE9DFF9E009E01 9E02000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 FB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 9E039E049E059E069E079E089E099E0A9E0B9E0C9E0D9E0E9E0F9E109E119E12 9E139E149E159E169E179E189E199E1A9E1B9E1C9E1D9E1E9E249E279E2E9E30 9E349E3B9E3C9E409E4D9E509E529E539E549E569E599E5D9E5F9E609E619E62 9E659E6E9E6F9E729E749E759E769E779E789E799E7A9E7B9E7C9E7D9E800000 9E819E839E849E859E869E899E8A9E8C9E8D9E8E9E8F9E909E919E949E959E96 9E979E989E999E9A9E9B9E9C9E9E9EA09EA19EA29EA39EA49EA59EA79EA89EA9 9EAA000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 FC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 9EAB9EAC9EAD9EAE9EAF9EB09EB19EB29EB39EB59EB69EB79EB99EBA9EBC9EBF 9EC09EC19EC29EC39EC59EC69EC79EC89ECA9ECB9ECC9ED09ED29ED39ED59ED6 9ED79ED99EDA9EDE9EE19EE39EE49EE69EE89EEB9EEC9EED9EEE9EF09EF19EF2 9EF39EF49EF59EF69EF79EF89EFA9EFD9EFF9F009F019F029F039F049F050000 9F069F079F089F099F0A9F0C9F0F9F119F129F149F159F169F189F1A9F1B9F1C 9F1D9F1E9F1F9F219F239F249F259F269F279F289F299F2A9F2B9F2D9F2E9F30 9F31000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 FD 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 9F329F339F349F359F369F389F3A9F3C9F3F9F409F419F429F439F459F469F47 9F489F499F4A9F4B9F4C9F4D9F4E9F4F9F529F539F549F559F569F579F589F59 9F5A9F5B9F5C9F5D9F5E9F5F9F609F619F629F639F649F659F669F679F689F69 9F6A9F6B9F6C9F6D9F6E9F6F9F709F719F729F739F749F759F769F779F780000 9F799F7A9F7B9F7C9F7D9F7E9F819F829F8D9F8E9F8F9F909F919F929F939F94 9F959F969F979F989F9C9F9D9F9E9FA19FA29FA39FA49FA5F92CF979F995F9E7 F9F1000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 FE 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 FA0CFA0DFA0EFA0FFA11FA13FA14FA18FA1FFA20FA21FA23FA24FA27FA28FA29 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 tcl8.4.20/library/encoding/cp950.enc0000644003604700454610000026326711737050674015520 0ustar dgp771div# Encoding file: cp950, multi-byte M 003F 0 88 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 0080008100820083008400850086008700880089008A008B008C008D008E008F 0090009100920093009400950096009700980099009A009B009C009D009E009F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 A1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 3000FF0C30013002FF0E2027FF1BFF1AFF1FFF01FE3020262025FE50FE51FE52 00B7FE54FE55FE56FE57FF5C2013FE312014FE332574FE34FE4FFF08FF09FE35 FE36FF5BFF5DFE37FE3830143015FE39FE3A30103011FE3BFE3C300A300BFE3D FE3E30083009FE3FFE40300C300DFE41FE42300E300FFE43FE44FE59FE5A0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FE5BFE5CFE5DFE5E20182019201C201D301D301E20352032FF03FF06FF0A 203B00A7300325CB25CF25B325B225CE2606260525C725C625A125A025BD25BC 32A3210500AFFFE3FF3F02CDFE49FE4AFE4DFE4EFE4BFE4CFE5FFE60FE61FF0B FF0D00D700F700B1221AFF1CFF1EFF1D226622672260221E22522261FE62FE63 FE64FE65FE66FF5E2229222A22A52220221F22BF33D233D1222B222E22352234 26402642229522992191219321902192219621972199219822252223FF0F0000 A2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 FF3C2215FE68FF04FFE53012FFE0FFE1FF05FF2021032109FE69FE6AFE6B33D5 339C339D339E33CE33A1338E338F33C400B05159515B515E515D5161516355E7 74E97CCE25812582258325842585258625872588258F258E258D258C258B258A 2589253C2534252C2524251C2594250025022595250C251025142518256D0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000256E2570256F2550255E256A256125E225E325E525E4257125722573FF10 FF11FF12FF13FF14FF15FF16FF17FF18FF192160216121622163216421652166 216721682169302130223023302430253026302730283029534153445345FF21 FF22FF23FF24FF25FF26FF27FF28FF29FF2AFF2BFF2CFF2DFF2EFF2FFF30FF31 FF32FF33FF34FF35FF36FF37FF38FF39FF3AFF41FF42FF43FF44FF45FF46FF47 FF48FF49FF4AFF4BFF4CFF4DFF4EFF4FFF50FF51FF52FF53FF54FF55FF560000 A3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 FF57FF58FF59FF5A039103920393039403950396039703980399039A039B039C 039D039E039F03A003A103A303A403A503A603A703A803A903B103B203B303B4 03B503B603B703B803B903BA03BB03BC03BD03BE03BF03C003C103C303C403C5 03C603C703C803C931053106310731083109310A310B310C310D310E310F0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00003110311131123113311431153116311731183119311A311B311C311D311E 311F312031213122312331243125312631273128312902D902C902CA02C702CB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000020AC00000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 A4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 4E004E594E014E034E434E5D4E864E8C4EBA513F5165516B51E052005201529B 53155341535C53C84E094E0B4E084E0A4E2B4E3851E14E454E484E5F4E5E4E8E 4EA15140520352FA534353C953E3571F58EB5915592759735B505B515B535BF8 5C0F5C225C385C715DDD5DE55DF15DF25DF35DFE5E725EFE5F0B5F13624D0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00004E114E104E0D4E2D4E304E394E4B5C394E884E914E954E924E944EA24EC1 4EC04EC34EC64EC74ECD4ECA4ECB4EC4514351415167516D516E516C519751F6 52065207520852FB52FE52FF53165339534853475345535E538453CB53CA53CD 58EC5929592B592A592D5B545C115C245C3A5C6F5DF45E7B5EFF5F145F155FC3 62086236624B624E652F6587659765A465B965E566F0670867286B206B626B79 6BCB6BD46BDB6C0F6C34706B722A7236723B72477259725B72AC738B4E190000 A5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 4E164E154E144E184E3B4E4D4E4F4E4E4EE54ED84ED44ED54ED64ED74EE34EE4 4ED94EDE514551445189518A51AC51F951FA51F8520A52A0529F530553065317 531D4EDF534A534953615360536F536E53BB53EF53E453F353EC53EE53E953E8 53FC53F853F553EB53E653EA53F253F153F053E553ED53FB56DB56DA59160000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000592E5931597459765B555B835C3C5DE85DE75DE65E025E035E735E7C5F01 5F185F175FC5620A625362546252625165A565E6672E672C672A672B672D6B63 6BCD6C116C106C386C416C406C3E72AF7384738974DC74E67518751F75287529 7530753175327533758B767D76AE76BF76EE77DB77E277F3793A79BE7A747ACB 4E1E4E1F4E524E534E694E994EA44EA64EA54EFF4F094F194F0A4F154F0D4F10 4F114F0F4EF24EF64EFB4EF04EF34EFD4F014F0B514951475146514851680000 A6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5171518D51B0521752115212520E521652A3530853215320537053715409540F 540C540A54105401540B54045411540D54085403540E5406541256E056DE56DD 573357305728572D572C572F57295919591A59375938598459785983597D5979 598259815B575B585B875B885B855B895BFA5C165C795DDE5E065E765E740000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005F0F5F1B5FD95FD6620E620C620D62106263625B6258653665E965E865EC 65ED66F266F36709673D6734673167356B216B646B7B6C166C5D6C576C596C5F 6C606C506C556C616C5B6C4D6C4E7070725F725D767E7AF97C737CF87F367F8A 7FBD80018003800C80128033807F8089808B808C81E381EA81F381FC820C821B 821F826E8272827E866B8840884C8863897F96214E324EA84F4D4F4F4F474F57 4F5E4F344F5B4F554F304F504F514F3D4F3A4F384F434F544F3C4F464F630000 A7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 4F5C4F604F2F4F4E4F364F594F5D4F484F5A514C514B514D517551B651B75225 52245229522A522852AB52A952AA52AC532353735375541D542D541E543E5426 544E542754465443543354485442541B5429544A5439543B5438542E54355436 5420543C54405431542B541F542C56EA56F056E456EB574A57515740574D0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005747574E573E5750574F573B58EF593E599D599259A8599E59A359995996 598D59A45993598A59A55B5D5B5C5B5A5B5B5B8C5B8B5B8F5C2C5C405C415C3F 5C3E5C905C915C945C8C5DEB5E0C5E8F5E875E8A5EF75F045F1F5F645F625F77 5F795FD85FCC5FD75FCD5FF15FEB5FF85FEA6212621162846297629662806276 6289626D628A627C627E627962736292626F6298626E62956293629162866539 653B653865F166F4675F674E674F67506751675C6756675E6749674667600000 A8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 675367576B656BCF6C426C5E6C996C816C886C896C856C9B6C6A6C7A6C906C70 6C8C6C686C966C926C7D6C836C726C7E6C746C866C766C8D6C946C986C827076 707C707D707872627261726072C472C27396752C752B75377538768276EF77E3 79C179C079BF7A767CFB7F5580968093809D8098809B809A80B2826F82920000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000828B828D898B89D28A008C378C468C558C9D8D648D708DB38EAB8ECA8F9B 8FB08FC28FC68FC58FC45DE1909190A290AA90A690A3914991C691CC9632962E 9631962A962C4E264E564E734E8B4E9B4E9E4EAB4EAC4F6F4F9D4F8D4F734F7F 4F6C4F9B4F8B4F864F834F704F754F884F694F7B4F964F7E4F8F4F914F7A5154 51525155516951775176517851BD51FD523B52385237523A5230522E52365241 52BE52BB5352535453535351536653775378537953D653D453D7547354750000 A9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5496547854955480547B5477548454925486547C549054715476548C549A5462 5468548B547D548E56FA57835777576A5769576157665764577C591C59495947 59485944595459BE59BB59D459B959AE59D159C659D059CD59CB59D359CA59AF 59B359D259C55B5F5B645B635B975B9A5B985B9C5B995B9B5C1A5C485C450000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005C465CB75CA15CB85CA95CAB5CB15CB35E185E1A5E165E155E1B5E115E78 5E9A5E975E9C5E955E965EF65F265F275F295F805F815F7F5F7C5FDD5FE05FFD 5FF55FFF600F6014602F60356016602A6015602160276029602B601B62166215 623F623E6240627F62C962CC62C462BF62C262B962D262DB62AB62D362D462CB 62C862A862BD62BC62D062D962C762CD62B562DA62B162D862D662D762C662AC 62CE653E65A765BC65FA66146613660C66066602660E6600660F6615660A0000 AA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6607670D670B676D678B67956771679C677367776787679D6797676F6770677F 6789677E67906775679A6793677C676A67726B236B666B676B7F6C136C1B6CE3 6CE86CF36CB16CCC6CE56CB36CBD6CBE6CBC6CE26CAB6CD56CD36CB86CC46CB9 6CC16CAE6CD76CC56CF16CBF6CBB6CE16CDB6CCA6CAC6CEF6CDC6CD66CE00000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007095708E7092708A7099722C722D723872487267726972C072CE72D972D7 72D073A973A8739F73AB73A5753D759D7599759A768476C276F276F477E577FD 793E7940794179C979C87A7A7A797AFA7CFE7F547F8C7F8B800580BA80A580A2 80B180A180AB80A980B480AA80AF81E581FE820D82B3829D829982AD82BD829F 82B982B182AC82A582AF82B882A382B082BE82B7864E8671521D88688ECB8FCE 8FD48FD190B590B890B190B691C791D195779580961C9640963F963B96440000 AB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 964296B996E89752975E4E9F4EAD4EAE4FE14FB54FAF4FBF4FE04FD14FCF4FDD 4FC34FB64FD84FDF4FCA4FD74FAE4FD04FC44FC24FDA4FCE4FDE4FB751575192 519151A0524E5243524A524D524C524B524752C752C952C352C1530D5357537B 539A53DB54AC54C054A854CE54C954B854A654B354C754C254BD54AA54C10000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000054C454C854AF54AB54B154BB54A954A754BF56FF5782578B57A057A357A2 57CE57AE579359555951594F594E595059DC59D859FF59E359E85A0359E559EA 59DA59E65A0159FB5B695BA35BA65BA45BA25BA55C015C4E5C4F5C4D5C4B5CD9 5CD25DF75E1D5E255E1F5E7D5EA05EA65EFA5F085F2D5F655F885F855F8A5F8B 5F875F8C5F896012601D60206025600E6028604D60706068606260466043606C 606B606A6064624162DC6316630962FC62ED630162EE62FD630762F162F70000 AC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 62EF62EC62FE62F463116302653F654565AB65BD65E26625662D66206627662F 661F66286631662466F767FF67D367F167D467D067EC67B667AF67F567E967EF 67C467D167B467DA67E567B867CF67DE67F367B067D967E267DD67D26B6A6B83 6B866BB56BD26BD76C1F6CC96D0B6D326D2A6D416D256D0C6D316D1E6D170000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006D3B6D3D6D3E6D366D1B6CF56D396D276D386D296D2E6D356D0E6D2B70AB 70BA70B370AC70AF70AD70B870AE70A472307272726F727472E972E072E173B7 73CA73BB73B273CD73C073B3751A752D754F754C754E754B75AB75A475A575A2 75A3767876867687768876C876C676C376C5770176F976F87709770B76FE76FC 770777DC78027814780C780D794679497948794779B979BA79D179D279CB7A7F 7A817AFF7AFD7C7D7D027D057D007D097D077D047D067F387F8E7FBF80040000 AD 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8010800D8011803680D680E580DA80C380C480CC80E180DB80CE80DE80E480DD 81F4822282E78303830582E382DB82E6830482E58302830982D282D782F18301 82DC82D482D182DE82D382DF82EF830686508679867B867A884D886B898189D4 8A088A028A038C9E8CA08D748D738DB48ECD8ECC8FF08FE68FE28FEA8FE50000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008FED8FEB8FE48FE890CA90CE90C190C3914B914A91CD95829650964B964C 964D9762976997CB97ED97F3980198A898DB98DF999699994E584EB3500C500D 50234FEF502650254FF8502950165006503C501F501A501250114FFA50005014 50284FF15021500B501950184FF34FEE502D502A4FFE502B5009517C51A451A5 51A251CD51CC51C651CB5256525C5254525B525D532A537F539F539D53DF54E8 55105501553754FC54E554F2550654FA551454E954ED54E1550954EE54EA0000 AE 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 54E65527550754FD550F5703570457C257D457CB57C35809590F59575958595A 5A115A185A1C5A1F5A1B5A1359EC5A205A235A295A255A0C5A095B6B5C585BB0 5BB35BB65BB45BAE5BB55BB95BB85C045C515C555C505CED5CFD5CFB5CEA5CE8 5CF05CF65D015CF45DEE5E2D5E2B5EAB5EAD5EA75F315F925F915F9060590000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006063606560506055606D6069606F6084609F609A608D6094608C60856096 624762F3630862FF634E633E632F635563426346634F6349633A6350633D632A 632B6328634D634C65486549659965C165C566426649664F66436652664C6645 664166F867146715671768216838684868466853683968426854682968B36817 684C6851683D67F468506840683C6843682A68456813681868416B8A6B896BB7 6C236C276C286C266C246CF06D6A6D956D886D876D666D786D776D596D930000 AF 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6D6C6D896D6E6D5A6D746D696D8C6D8A6D796D856D656D9470CA70D870E470D9 70C870CF7239727972FC72F972FD72F872F7738673ED740973EE73E073EA73DE 7554755D755C755A755975BE75C575C775B275B375BD75BC75B975C275B8768B 76B076CA76CD76CE7729771F7720772877E9783078277838781D783478370000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007825782D7820781F7832795579507960795F7956795E795D7957795A79E4 79E379E779DF79E679E979D87A847A887AD97B067B117C897D217D177D0B7D0A 7D207D227D147D107D157D1A7D1C7D0D7D197D1B7F3A7F5F7F947FC57FC18006 8018801580198017803D803F80F1810280F0810580ED80F4810680F880F38108 80FD810A80FC80EF81ED81EC82008210822A822B8228822C82BB832B83528354 834A83388350834983358334834F833283398336831783408331832883430000 B0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8654868A86AA869386A486A9868C86A3869C8870887788818882887D88798A18 8A108A0E8A0C8A158A0A8A178A138A168A0F8A118C488C7A8C798CA18CA28D77 8EAC8ED28ED48ECF8FB1900190068FF790008FFA8FF490038FFD90058FF89095 90E190DD90E29152914D914C91D891DD91D791DC91D995839662966396610000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000965B965D96649658965E96BB98E299AC9AA89AD89B259B329B3C4E7E507A 507D505C50475043504C505A504950655076504E5055507550745077504F500F 506F506D515C519551F0526A526F52D252D952D852D55310530F5319533F5340 533E53C366FC5546556A55665544555E55615543554A55315556554F5555552F 55645538552E555C552C55635533554155575708570B570957DF5805580A5806 57E057E457FA5802583557F757F9592059625A365A415A495A665A6A5A400000 B1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5A3C5A625A5A5A465A4A5B705BC75BC55BC45BC25BBF5BC65C095C085C075C60 5C5C5C5D5D075D065D0E5D1B5D165D225D115D295D145D195D245D275D175DE2 5E385E365E335E375EB75EB85EB65EB55EBE5F355F375F575F6C5F695F6B5F97 5F995F9E5F985FA15FA05F9C607F60A3608960A060A860CB60B460E660BD0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000060C560BB60B560DC60BC60D860D560C660DF60B860DA60C7621A621B6248 63A063A76372639663A263A563776367639863AA637163A963896383639B636B 63A863846388639963A163AC6392638F6380637B63696368637A655D65566551 65596557555F654F655865556554659C659B65AC65CF65CB65CC65CE665D665A 666466686666665E66F952D7671B688168AF68A2689368B5687F687668B168A7 689768B0688368C468AD688668856894689D68A8689F68A168826B326BBA0000 B2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6BEB6BEC6C2B6D8E6DBC6DF36DD96DB26DE16DCC6DE46DFB6DFA6E056DC76DCB 6DAF6DD16DAE6DDE6DF96DB86DF76DF56DC56DD26E1A6DB56DDA6DEB6DD86DEA 6DF16DEE6DE86DC66DC46DAA6DEC6DBF6DE670F97109710A70FD70EF723D727D 7281731C731B73167313731973877405740A7403740673FE740D74E074F60000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000074F7751C75227565756675627570758F75D475D575B575CA75CD768E76D4 76D276DB7737773E773C77367738773A786B7843784E79657968796D79FB7A92 7A957B207B287B1B7B2C7B267B197B1E7B2E7C927C977C957D467D437D717D2E 7D397D3C7D407D307D337D447D2F7D427D327D317F3D7F9E7F9A7FCC7FCE7FD2 801C804A8046812F81168123812B81298130812482028235823782368239838E 839E8398837883A2839683BD83AB8392838A8393838983A08377837B837C0000 B3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 838683A786555F6A86C786C086B686C486B586C686CB86B186AF86C98853889E 888888AB88928896888D888B8993898F8A2A8A1D8A238A258A318A2D8A1F8A1B 8A228C498C5A8CA98CAC8CAB8CA88CAA8CA78D678D668DBE8DBA8EDB8EDF9019 900D901A90179023901F901D90109015901E9020900F90229016901B90140000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000090E890ED90FD915791CE91F591E691E391E791ED91E99589966A96759673 96789670967496769677966C96C096EA96E97AE07ADF980298039B5A9CE59E75 9E7F9EA59EBB50A2508D508550995091508050965098509A670051F152725274 5275526952DE52DD52DB535A53A5557B558055A7557C558A559D55985582559C 55AA55945587558B558355B355AE559F553E55B2559A55BB55AC55B1557E5589 55AB5599570D582F582A58345824583058315821581D582058F958FA59600000 B4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5A775A9A5A7F5A925A9B5AA75B735B715BD25BCC5BD35BD05C0A5C0B5C315D4C 5D505D345D475DFD5E455E3D5E405E435E7E5ECA5EC15EC25EC45F3C5F6D5FA9 5FAA5FA860D160E160B260B660E0611C612360FA611560F060FB60F4616860F1 610E60F6610961006112621F624963A3638C63CF63C063E963C963C663CD0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000063D263E363D063E163D663ED63EE637663F463EA63DB645263DA63F9655E 6566656265636591659065AF666E667066746676666F6691667A667E667766FE 66FF671F671D68FA68D568E068D868D7690568DF68F568EE68E768F968D268F2 68E368CB68CD690D6912690E68C968DA696E68FB6B3E6B3A6B3D6B986B966BBC 6BEF6C2E6C2F6C2C6E2F6E386E546E216E326E676E4A6E206E256E236E1B6E5B 6E586E246E566E6E6E2D6E266E6F6E346E4D6E3A6E2C6E436E1D6E3E6ECB0000 B5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6E896E196E4E6E636E446E726E696E5F7119711A7126713071217136716E711C 724C728472807336732573347329743A742A743374227425743574367434742F 741B7426742875257526756B756A75E275DB75E375D975D875DE75E0767B767C 7696769376B476DC774F77ED785D786C786F7A0D7A087A0B7A057A007A980000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007A977A967AE57AE37B497B567B467B507B527B547B4D7B4B7B4F7B517C9F 7CA57D5E7D507D687D557D2B7D6E7D727D617D667D627D707D7355847FD47FD5 800B8052808581558154814B8151814E81398146813E814C815381748212821C 83E9840383F8840D83E083C5840B83C183EF83F183F48457840A83F0840C83CC 83FD83F283CA8438840E840483DC840783D483DF865B86DF86D986ED86D486DB 86E486D086DE885788C188C288B1898389968A3B8A608A558A5E8A3C8A410000 B6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8A548A5B8A508A468A348A3A8A368A568C618C828CAF8CBC8CB38CBD8CC18CBB 8CC08CB48CB78CB68CBF8CB88D8A8D858D818DCE8DDD8DCB8DDA8DD18DCC8DDB 8DC68EFB8EF88EFC8F9C902E90359031903890329036910290F5910990FE9163 916591CF9214921592239209921E920D9210920792119594958F958B95910000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000095939592958E968A968E968B967D96859686968D9672968496C196C596C4 96C696C796EF96F297CC98059806980898E798EA98EF98E998F298ED99AE99AD 9EC39ECD9ED14E8250AD50B550B250B350C550BE50AC50B750BB50AF50C7527F 5277527D52DF52E652E452E252E3532F55DF55E855D355E655CE55DC55C755D1 55E355E455EF55DA55E155C555C655E555C957125713585E585158585857585A 5854586B584C586D584A58625852584B59675AC15AC95ACC5ABE5ABD5ABC0000 B7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5AB35AC25AB25D695D6F5E4C5E795EC95EC85F125F595FAC5FAE611A610F6148 611F60F3611B60F961016108614E614C6144614D613E61346127610D61066137 622162226413643E641E642A642D643D642C640F641C6414640D643664166417 6406656C659F65B06697668966876688669666846698668D67036994696D0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000695A697769606954697569306982694A6968696B695E695369796986695D 6963695B6B476B726BC06BBF6BD36BFD6EA26EAF6ED36EB66EC26E906E9D6EC7 6EC56EA56E986EBC6EBA6EAB6ED16E966E9C6EC46ED46EAA6EA76EB4714E7159 7169716471497167715C716C7166714C7165715E714671687156723A72527337 7345733F733E746F745A7455745F745E7441743F7459745B745C757675787600 75F0760175F275F175FA75FF75F475F376DE76DF775B776B7766775E77630000 B8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7779776A776C775C77657768776277EE788E78B078977898788C7889787C7891 7893787F797A797F7981842C79BD7A1C7A1A7A207A147A1F7A1E7A9F7AA07B77 7BC07B607B6E7B677CB17CB37CB57D937D797D917D817D8F7D5B7F6E7F697F6A 7F727FA97FA87FA480568058808680848171817081788165816E8173816B0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008179817A81668205824784828477843D843184758466846B8449846C845B 843C8435846184638469846D8446865E865C865F86F9871387088707870086FE 86FB870287038706870A885988DF88D488D988DC88D888DD88E188CA88D588D2 899C89E38A6B8A728A738A668A698A708A878A7C8A638AA08A718A858A6D8A62 8A6E8A6C8A798A7B8A3E8A688C628C8A8C898CCA8CC78CC88CC48CB28CC38CC2 8CC58DE18DDF8DE88DEF8DF38DFA8DEA8DE48DE68EB28F038F098EFE8F0A0000 B9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8F9F8FB2904B904A905390429054903C905590509047904F904E904D9051903E 904191129117916C916A916991C9923792579238923D9240923E925B924B9264 925192349249924D92459239923F925A959896989694969596CD96CB96C996CA 96F796FB96F996F6975697749776981098119813980A9812980C98FC98F40000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000098FD98FE99B399B199B49AE19CE99E829F0E9F139F2050E750EE50E550D6 50ED50DA50D550CF50D150F150CE50E9516251F352835282533153AD55FE5600 561B561755FD561456065609560D560E55F75616561F5608561055F657185716 5875587E58835893588A58795885587D58FD592559225924596A59695AE15AE6 5AE95AD75AD65AD85AE35B755BDE5BE75BE15BE55BE65BE85BE25BE45BDF5C0D 5C625D845D875E5B5E635E555E575E545ED35ED65F0A5F465F705FB961470000 BA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 613F614B617761626163615F615A61586175622A64876458645464A46478645F 647A645164676434646D647B657265A165D765D666A266A8669D699C69A86995 69C169AE69D369CB699B69B769BB69AB69B469D069CD69AD69CC69A669C369A3 6B496B4C6C336F336F146EFE6F136EF46F296F3E6F206F2C6F0F6F026F220000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006EFF6EEF6F066F316F386F326F236F156F2B6F2F6F886F2A6EEC6F016EF2 6ECC6EF771947199717D718A71847192723E729272967344735074647463746A 7470746D750475917627760D760B7609761376E176E37784777D777F776178C1 789F78A778B378A978A3798E798F798D7A2E7A317AAA7AA97AED7AEF7BA17B95 7B8B7B757B977B9D7B947B8F7BB87B877B847CB97CBD7CBE7DBB7DB07D9C7DBD 7DBE7DA07DCA7DB47DB27DB17DBA7DA27DBF7DB57DB87DAD7DD27DC77DAC0000 BB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7F707FE07FE17FDF805E805A808781508180818F8188818A817F818281E781FA 82078214821E824B84C984BF84C684C48499849E84B2849C84CB84B884C084D3 849084BC84D184CA873F871C873B872287258734871887558737872988F38902 88F488F988F888FD88E8891A88EF8AA68A8C8A9E8AA38A8D8AA18A938AA40000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008AAA8AA58AA88A988A918A9A8AA78C6A8C8D8C8C8CD38CD18CD28D6B8D99 8D958DFC8F148F128F158F138FA390609058905C90639059905E9062905D905B 91199118911E917591789177917492789280928592989296927B9293929C92A8 927C929195A195A895A995A395A595A49699969C969B96CC96D29700977C9785 97F69817981898AF98B199039905990C990999C19AAF9AB09AE69B419B429CF4 9CF69CF39EBC9F3B9F4A5104510050FB50F550F9510251085109510551DC0000 BC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 528752885289528D528A52F053B2562E563B56395632563F563456295653564E 565756745636562F56305880589F589E58B3589C58AE58A958A6596D5B095AFB 5B0B5AF55B0C5B085BEE5BEC5BE95BEB5C645C655D9D5D945E625E5F5E615EE2 5EDA5EDF5EDD5EE35EE05F485F715FB75FB561766167616E615D615561820000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000617C6170616B617E61A7619061AB618E61AC619A61A4619461AE622E6469 646F6479649E64B26488649064B064A56493649564A9649264AE64AD64AB649A 64AC649964A264B365756577657866AE66AB66B466B16A236A1F69E86A016A1E 6A1969FD6A216A136A0A69F36A026A0569ED6A116B506B4E6BA46BC56BC66F3F 6F7C6F846F516F666F546F866F6D6F5B6F786F6E6F8E6F7A6F706F646F976F58 6ED56F6F6F606F5F719F71AC71B171A87256729B734E73577469748B74830000 BD 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 747E7480757F76207629761F7624762676217622769A76BA76E4778E7787778C 7791778B78CB78C578BA78CA78BE78D578BC78D07A3F7A3C7A407A3D7A377A3B 7AAF7AAE7BAD7BB17BC47BB47BC67BC77BC17BA07BCC7CCA7DE07DF47DEF7DFB 7DD87DEC7DDD7DE87DE37DDA7DDE7DE97D9E7DD97DF27DF97F757F777FAF0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007FE98026819B819C819D81A0819A81988517853D851A84EE852C852D8513 851185238521851484EC852584FF850687828774877687608766877887688759 8757874C8753885B885D89108907891289138915890A8ABC8AD28AC78AC48A95 8ACB8AF88AB28AC98AC28ABF8AB08AD68ACD8AB68AB98ADB8C4C8C4E8C6C8CE0 8CDE8CE68CE48CEC8CED8CE28CE38CDC8CEA8CE18D6D8D9F8DA38E2B8E108E1D 8E228E0F8E298E1F8E218E1E8EBA8F1D8F1B8F1F8F298F268F2A8F1C8F1E0000 BE 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8F259069906E9068906D90779130912D9127913191879189918B918392C592BB 92B792EA92AC92E492C192B392BC92D292C792F092B295AD95B1970497069707 97099760978D978B978F9821982B981C98B3990A99139912991899DD99D099DF 99DB99D199D599D299D99AB79AEE9AEF9B279B459B449B779B6F9D069D090000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009D039EA99EBE9ECE58A89F5251125118511451105115518051AA51DD5291 529352F35659566B5679566956645678566A566856655671566F566C56625676 58C158BE58C758C5596E5B1D5B345B785BF05C0E5F4A61B2619161A9618A61CD 61B661BE61CA61C8623064C564C164CB64BB64BC64DA64C464C764C264CD64BF 64D264D464BE657466C666C966B966C466C766B86A3D6A386A3A6A596A6B6A58 6A396A446A626A616A4B6A476A356A5F6A486B596B776C056FC26FB16FA10000 BF 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6FC36FA46FC16FA76FB36FC06FB96FB66FA66FA06FB471BE71C971D071D271C8 71D571B971CE71D971DC71C371C47368749C74A37498749F749E74E2750C750D 76347638763A76E776E577A0779E779F77A578E878DA78EC78E779A67A4D7A4E 7A467A4C7A4B7ABA7BD97C117BC97BE47BDB7BE17BE97BE67CD57CD67E0A0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007E117E087E1B7E237E1E7E1D7E097E107F797FB27FF07FF17FEE802881B3 81A981A881FB820882588259854A855985488568856985438549856D856A855E 8783879F879E87A2878D8861892A89328925892B892189AA89A68AE68AFA8AEB 8AF18B008ADC8AE78AEE8AFE8B018B028AF78AED8AF38AF68AFC8C6B8C6D8C93 8CF48E448E318E348E428E398E358F3B8F2F8F388F338FA88FA6907590749078 9072907C907A913491929320933692F89333932F932292FC932B9304931A0000 C0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 9310932693219315932E931995BB96A796A896AA96D5970E97119716970D9713 970F975B975C9766979898309838983B9837982D9839982499109928991E991B 9921991A99ED99E299F19AB89ABC9AFB9AED9B289B919D159D239D269D289D12 9D1B9ED89ED49F8D9F9C512A511F5121513252F5568E56805690568556870000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000568F58D558D358D158CE5B305B2A5B245B7A5C375C685DBC5DBA5DBD5DB8 5E6B5F4C5FBD61C961C261C761E661CB6232623464CE64CA64D864E064F064E6 64EC64F164E264ED6582658366D966D66A806A946A846AA26A9C6ADB6AA36A7E 6A976A906AA06B5C6BAE6BDA6C086FD86FF16FDF6FE06FDB6FE46FEB6FEF6F80 6FEC6FE16FE96FD56FEE6FF071E771DF71EE71E671E571ED71EC71F471E07235 72467370737274A974B074A674A876467642764C76EA77B377AA77B077AC0000 C1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 77A777AD77EF78F778FA78F478EF790179A779AA7A577ABF7C077C0D7BFE7BF7 7C0C7BE07CE07CDC7CDE7CE27CDF7CD97CDD7E2E7E3E7E467E377E327E437E2B 7E3D7E317E457E417E347E397E487E357E3F7E2F7F447FF37FFC807180728070 806F807381C681C381BA81C281C081BF81BD81C981BE81E88209827185AA0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008584857E859C8591859485AF859B858785A8858A866787C087D187B387D2 87C687AB87BB87BA87C887CB893B893689448938893D89AC8B0E8B178B198B1B 8B0A8B208B1D8B048B108C418C3F8C738CFA8CFD8CFC8CF88CFB8DA88E498E4B 8E488E4A8F448F3E8F428F458F3F907F907D9084908190829080913991A3919E 919C934D938293289375934A9365934B9318937E936C935B9370935A935495CA 95CB95CC95C895C696B196B896D6971C971E97A097D3984698B699359A010000 C2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 99FF9BAE9BAB9BAA9BAD9D3B9D3F9E8B9ECF9EDE9EDC9EDD9EDB9F3E9F4B53E2 569556AE58D958D85B385F5D61E3623364F464F264FE650664FA64FB64F765B7 66DC67266AB36AAC6AC36ABB6AB86AC26AAE6AAF6B5F6B786BAF7009700B6FFE 70066FFA7011700F71FB71FC71FE71F87377737574A774BF7515765676580000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000765277BD77BF77BB77BC790E79AE7A617A627A607AC47AC57C2B7C277C2A 7C1E7C237C217CE77E547E557E5E7E5A7E617E527E597F487FF97FFB80778076 81CD81CF820A85CF85A985CD85D085C985B085BA85B985A687EF87EC87F287E0 898689B289F48B288B398B2C8B2B8C508D058E598E638E668E648E5F8E558EC0 8F498F4D90879083908891AB91AC91D09394938A939693A293B393AE93AC93B0 9398939A939795D495D695D095D596E296DC96D996DB96DE972497A397A60000 C3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 97AD97F9984D984F984C984E985398BA993E993F993D992E99A59A0E9AC19B03 9B069B4F9B4E9B4D9BCA9BC99BFD9BC89BC09D519D5D9D609EE09F159F2C5133 56A558DE58DF58E25BF59F905EEC61F261F761F661F56500650F66E066DD6AE5 6ADD6ADA6AD3701B701F7028701A701D701570187206720D725872A273780000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000737A74BD74CA74E375877586765F766177C7791979B17A6B7A697C3E7C3F 7C387C3D7C377C407E6B7E6D7E797E697E6A7F857E737FB67FB97FB881D885E9 85DD85EA85D585E485E585F787FB8805880D87F987FE8960895F8956895E8B41 8B5C8B588B498B5A8B4E8B4F8B468B598D088D0A8E7C8E728E878E768E6C8E7A 8E748F548F4E8FAD908A908B91B191AE93E193D193DF93C393C893DC93DD93D6 93E293CD93D893E493D793E895DC96B496E3972A9727976197DC97FB985E0000 C4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 9858985B98BC994599499A169A199B0D9BE89BE79BD69BDB9D899D619D729D6A 9D6C9E929E979E939EB452F856A856B756B656B456BC58E45B405B435B7D5BF6 5DC961F861FA65186514651966E667276AEC703E703070327210737B74CF7662 76657926792A792C792B7AC77AF67C4C7C437C4D7CEF7CF08FAE7E7D7E7C0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007E827F4C800081DA826685FB85F9861185FA8606860B8607860A88148815 896489BA89F88B708B6C8B668B6F8B5F8B6B8D0F8D0D8E898E818E858E8291B4 91CB9418940393FD95E1973098C49952995199A89A2B9A309A379A359C139C0D 9E799EB59EE89F2F9F5F9F639F615137513856C156C056C259145C6C5DCD61FC 61FE651D651C659566E96AFB6B046AFA6BB2704C721B72A774D674D4766977D3 7C507E8F7E8C7FBC8617862D861A882388228821881F896A896C89BD8B740000 C5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8B778B7D8D138E8A8E8D8E8B8F5F8FAF91BA942E94339435943A94389432942B 95E297389739973297FF9867986599579A459A439A409A3E9ACF9B549B519C2D 9C259DAF9DB49DC29DB89E9D9EEF9F199F5C9F669F67513C513B56C856CA56C9 5B7F5DD45DD25F4E61FF65246B0A6B6170517058738074E4758A766E766C0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000079B37C607C5F807E807D81DF8972896F89FC8B808D168D178E918E938F61 9148944494519452973D973E97C397C1986B99559A559A4D9AD29B1A9C499C31 9C3E9C3B9DD39DD79F349F6C9F6A9F9456CC5DD662006523652B652A66EC6B10 74DA7ACA7C647C637C657E937E967E9481E28638863F88318B8A9090908F9463 946094649768986F995C9A5A9A5B9A579AD39AD49AD19C549C579C569DE59E9F 9EF456D158E9652C705E7671767277D77F507F888836883988628B938B920000 C6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8B9682778D1B91C0946A97429748974497C698709A5F9B229B589C5F9DF99DFA 9E7C9E7D9F079F779F725EF36B1670637C6C7C6E883B89C08EA191C194729470 9871995E9AD69B239ECC706477DA8B9A947797C99A629A657E9C8B9C8EAA91C5 947D947E947C9C779C789EF78C54947F9E1A72289A6A9B319E1B9E1E7C720000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 C9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 4E424E5C51F5531A53824E074E0C4E474E8D56D7FA0C5C6E5F734E0F51874E0E 4E2E4E934EC24EC94EC8519852FC536C53B957205903592C5C105DFF65E16BB3 6BCC6C14723F4E314E3C4EE84EDC4EE94EE14EDD4EDA520C531C534C57225723 5917592F5B815B845C125C3B5C745C735E045E805E825FC9620962506C150000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006C366C436C3F6C3B72AE72B0738A79B8808A961E4F0E4F184F2C4EF54F14 4EF14F004EF74F084F1D4F024F054F224F134F044EF44F1251B1521352095210 52A65322531F534D538A540756E156DF572E572A5734593C5980597C5985597B 597E5977597F5B565C155C255C7C5C7A5C7B5C7E5DDF5E755E845F025F1A5F74 5FD55FD45FCF625C625E626462616266626262596260625A626565EF65EE673E 67396738673B673A673F673C67336C186C466C526C5C6C4F6C4A6C546C4B0000 CA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6C4C7071725E72B472B5738E752A767F7A757F518278827C8280827D827F864D 897E909990979098909B909496229624962096234F564F3B4F624F494F534F64 4F3E4F674F524F5F4F414F584F2D4F334F3F4F61518F51B9521C521E522152AD 52AE530953635372538E538F54305437542A545454455419541C542554180000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000543D544F544154285424544756EE56E756E557415745574C5749574B5752 5906594059A6599859A05997598E59A25990598F59A759A15B8E5B925C285C2A 5C8D5C8F5C885C8B5C895C925C8A5C865C935C955DE05E0A5E0E5E8B5E895E8C 5E885E8D5F055F1D5F785F765FD25FD15FD05FED5FE85FEE5FF35FE15FE45FE3 5FFA5FEF5FF75FFB60005FF4623A6283628C628E628F629462876271627B627A 6270628162886277627D62726274653765F065F465F365F265F5674567470000 CB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 67596755674C6748675D674D675A674B6BD06C196C1A6C786C676C6B6C846C8B 6C8F6C716C6F6C696C9A6C6D6C876C956C9C6C666C736C656C7B6C8E7074707A 726372BF72BD72C372C672C172BA72C573957397739373947392753A75397594 75957681793D80348095809980908092809C8290828F8285828E829182930000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000828A828382848C788FC98FBF909F90A190A5909E90A790A096309628962F 962D4E334F984F7C4F854F7D4F804F874F764F744F894F844F774F4C4F974F6A 4F9A4F794F814F784F904F9C4F944F9E4F924F824F954F6B4F6E519E51BC51BE 5235523252335246523152BC530A530B533C539253945487547F548154915482 5488546B547A547E5465546C54745466548D546F546154605498546354675464 56F756F9576F5772576D576B57715770577657805775577B5773577457620000 CC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5768577D590C594559B559BA59CF59CE59B259CC59C159B659BC59C359D659B1 59BD59C059C859B459C75B625B655B935B955C445C475CAE5CA45CA05CB55CAF 5CA85CAC5C9F5CA35CAD5CA25CAA5CA75C9D5CA55CB65CB05CA65E175E145E19 5F285F225F235F245F545F825F7E5F7D5FDE5FE5602D602660196032600B0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006034600A60176033601A601E602C6022600D6010602E60136011600C6009 601C6214623D62AD62B462D162BE62AA62B662CA62AE62B362AF62BB62A962B0 62B8653D65A865BB660965FC66046612660865FB6603660B660D660565FD6611 661066F6670A6785676C678E67926776677B6798678667846774678D678C677A 679F679167996783677D67816778677967946B256B806B7E6BDE6C1D6C936CEC 6CEB6CEE6CD96CB66CD46CAD6CE76CB76CD06CC26CBA6CC36CC66CED6CF20000 CD 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6CD26CDD6CB46C8A6C9D6C806CDE6CC06D306CCD6CC76CB06CF96CCF6CE96CD1 709470987085709370867084709170967082709A7083726A72D672CB72D872C9 72DC72D272D472DA72CC72D173A473A173AD73A673A273A073AC739D74DD74E8 753F7540753E758C759876AF76F376F176F076F577F877FC77F977FB77FA0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000077F77942793F79C57A787A7B7AFB7C757CFD8035808F80AE80A380B880B5 80AD822082A082C082AB829A8298829B82B582A782AE82BC829E82BA82B482A8 82A182A982C282A482C382B682A28670866F866D866E8C568FD28FCB8FD38FCD 8FD68FD58FD790B290B490AF90B390B09639963D963C963A96434FCD4FC54FD3 4FB24FC94FCB4FC14FD44FDC4FD94FBB4FB34FDB4FC74FD64FBA4FC04FB94FEC 5244524952C052C2533D537C539753965399539854BA54A154AD54A554CF0000 CE 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 54C3830D54B754AE54D654B654C554C654A0547054BC54A254BE547254DE54B0 57B5579E579F57A4578C5797579D579B57945798578F579957A5579A579558F4 590D595359E159DE59EE5A0059F159DD59FA59FD59FC59F659E459F259F759DB 59E959F359F559E059FE59F459ED5BA85C4C5CD05CD85CCC5CD75CCB5CDB0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005CDE5CDA5CC95CC75CCA5CD65CD35CD45CCF5CC85CC65CCE5CDF5CF85DF9 5E215E225E235E205E245EB05EA45EA25E9B5EA35EA55F075F2E5F565F866037 603960546072605E6045605360476049605B604C60406042605F602460446058 6066606E6242624362CF630D630B62F5630E630362EB62F9630F630C62F862F6 63006313631462FA631562FB62F06541654365AA65BF6636662166326635661C 662666226633662B663A661D66346639662E670F671067C167F267C867BA0000 CF 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 67DC67BB67F867D867C067B767C567EB67E467DF67B567CD67B367F767F667EE 67E367C267B967CE67E767F067B267FC67C667ED67CC67AE67E667DB67FA67C9 67CA67C367EA67CB6B286B826B846BB66BD66BD86BE06C206C216D286D346D2D 6D1F6D3C6D3F6D126D0A6CDA6D336D046D196D3A6D1A6D116D006D1D6D420000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006D016D186D376D036D0F6D406D076D206D2C6D086D226D096D1070B7709F 70BE70B170B070A170B470B570A972417249724A726C72707273726E72CA72E4 72E872EB72DF72EA72E672E3738573CC73C273C873C573B973B673B573B473EB 73BF73C773BE73C373C673B873CB74EC74EE752E7547754875A775AA767976C4 7708770377047705770A76F776FB76FA77E777E878067811781278057810780F 780E780978037813794A794C794B7945794479D579CD79CF79D679CE7A800000 D0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7A7E7AD17B007B017C7A7C787C797C7F7C807C817D037D087D017F587F917F8D 7FBE8007800E800F8014803780D880C780E080D180C880C280D080C580E380D9 80DC80CA80D580C980CF80D780E680CD81FF8221829482D982FE82F9830782E8 830082D5833A82EB82D682F482EC82E182F282F5830C82FB82F682F082EA0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000082E482E082FA82F382ED86778674867C86738841884E8867886A886989D3 8A048A078D728FE38FE18FEE8FE090F190BD90BF90D590C590BE90C790CB90C8 91D491D39654964F96519653964A964E501E50055007501350225030501B4FF5 4FF450335037502C4FF64FF75017501C502050275035502F5031500E515A5194 519351CA51C451C551C851CE5261525A5252525E525F5255526252CD530E539E 552654E25517551254E754F354E4551A54FF5504550854EB5511550554F10000 D1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 550A54FB54F754F854E0550E5503550B5701570257CC583257D557D257BA57C6 57BD57BC57B857B657BF57C757D057B957C1590E594A5A195A165A2D5A2E5A15 5A0F5A175A0A5A1E5A335B6C5BA75BAD5BAC5C035C565C545CEC5CFF5CEE5CF1 5CF75D005CF95E295E285EA85EAE5EAA5EAC5F335F305F67605D605A60670000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000604160A26088608060926081609D60836095609B60976087609C608E6219 624662F263106356632C634463456336634363E46339634B634A633C63296341 6334635863546359632D63476333635A63516338635763406348654A654665C6 65C365C465C2664A665F6647665167126713681F681A684968326833683B684B 684F68166831681C6835682B682D682F684E68446834681D6812681468266828 682E684D683A682568206B2C6B2F6B2D6B316B346B6D80826B886BE66BE40000 D2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6BE86BE36BE26BE76C256D7A6D636D646D766D0D6D616D926D586D626D6D6D6F 6D916D8D6DEF6D7F6D866D5E6D676D606D976D706D7C6D5F6D826D986D2F6D68 6D8B6D7E6D806D846D166D836D7B6D7D6D756D9070DC70D370D170DD70CB7F39 70E270D770D270DE70E070D470CD70C570C670C770DA70CE70E1724272780000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000072777276730072FA72F472FE72F672F372FB730173D373D973E573D673BC 73E773E373E973DC73D273DB73D473DD73DA73D773D873E874DE74DF74F474F5 7521755B755F75B075C175BB75C475C075BF75B675BA768A76C9771D771B7710 771377127723771177157719771A772277277823782C78227835782F7828782E 782B782178297833782A78317954795B794F795C79537952795179EB79EC79E0 79EE79ED79EA79DC79DE79DD7A867A897A857A8B7A8C7A8A7A877AD87B100000 D3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7B047B137B057B0F7B087B0A7B0E7B097B127C847C917C8A7C8C7C887C8D7C85 7D1E7D1D7D117D0E7D187D167D137D1F7D127D0F7D0C7F5C7F617F5E7F607F5D 7F5B7F967F927FC37FC27FC08016803E803980FA80F280F980F5810180FB8100 8201822F82258333832D83448319835183258356833F83418326831C83220000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008342834E831B832A8308833C834D8316832483208337832F832983478345 834C8353831E832C834B832783488653865286A286A88696868D8691869E8687 86978686868B869A868586A5869986A186A786958698868E869D869086948843 8844886D88758876887288808871887F886F8883887E8874887C8A128C478C57 8C7B8CA48CA38D768D788DB58DB78DB68ED18ED38FFE8FF590028FFF8FFB9004 8FFC8FF690D690E090D990DA90E390DF90E590D890DB90D790DC90E491500000 D4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 914E914F91D591E291DA965C965F96BC98E39ADF9B2F4E7F5070506A5061505E 50605053504B505D50725048504D5041505B504A506250155045505F5069506B 5063506450465040506E50735057505151D0526B526D526C526E52D652D3532D 539C55755576553C554D55505534552A55515562553655355530555255450000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000550C55325565554E55395548552D553B5540554B570A570757FB581457E2 57F657DC57F4580057ED57FD580857F8580B57F357CF580757EE57E357F257E5 57EC57E1580E57FC581057E75801580C57F157E957F0580D5804595C5A605A58 5A555A675A5E5A385A355A6D5A505A5F5A655A6C5A535A645A575A435A5D5A52 5A445A5B5A485A8E5A3E5A4D5A395A4C5A705A695A475A515A565A425A5C5B72 5B6E5BC15BC05C595D1E5D0B5D1D5D1A5D205D0C5D285D0D5D265D255D0F0000 D5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5D305D125D235D1F5D2E5E3E5E345EB15EB45EB95EB25EB35F365F385F9B5F96 5F9F608A6090608660BE60B060BA60D360D460CF60E460D960DD60C860B160DB 60B760CA60BF60C360CD60C063326365638A6382637D63BD639E63AD639D6397 63AB638E636F63876390636E63AF6375639C636D63AE637C63A4633B639F0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006378638563816391638D6370655365CD66656661665B6659665C66626718 687968876890689C686D686E68AE68AB6956686F68A368AC68A96875687468B2 688F68776892687C686B687268AA68806871687E689B6896688B68A0688968A4 6878687B6891688C688A687D6B366B336B376B386B916B8F6B8D6B8E6B8C6C2A 6DC06DAB6DB46DB36E746DAC6DE96DE26DB76DF66DD46E006DC86DE06DDF6DD6 6DBE6DE56DDC6DDD6DDB6DF46DCA6DBD6DED6DF06DBA6DD56DC26DCF6DC90000 D6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6DD06DF26DD36DFD6DD76DCD6DE36DBB70FA710D70F7711770F4710C70F07104 70F3711070FC70FF71067113710070F870F6710B7102710E727E727B727C727F 731D7317730773117318730A730872FF730F731E738873F673F873F574047401 73FD7407740073FA73FC73FF740C740B73F474087564756375CE75D275CF0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000075CB75CC75D175D0768F768976D37739772F772D7731773277347733773D 7725773B7735784878527849784D784A784C782678457850796479677969796A 7963796B796179BB79FA79F879F679F77A8F7A947A907B357B477B347B257B30 7B227B247B337B187B2A7B1D7B317B2B7B2D7B2F7B327B387B1A7B237C947C98 7C967CA37D357D3D7D387D367D3A7D457D2C7D297D417D477D3E7D3F7D4A7D3B 7D287F637F957F9C7F9D7F9B7FCA7FCB7FCD7FD07FD17FC77FCF7FC9801F0000 D7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 801E801B804780438048811881258119811B812D811F812C811E812181158127 811D8122821182388233823A823482328274839083A383A8838D837A837383A4 8374838F8381839583998375839483A9837D8383838C839D839B83AA838B837E 83A583AF8388839783B0837F83A6838783AE8376839A8659865686BF86B70000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000086C286C186C586BA86B086C886B986B386B886CC86B486BB86BC86C386BD 86BE88528889889588A888A288AA889A889188A1889F889888A78899889B8897 88A488AC888C8893888E898289D689D989D58A308A278A2C8A1E8C398C3B8C5C 8C5D8C7D8CA58D7D8D7B8D798DBC8DC28DB98DBF8DC18ED88EDE8EDD8EDC8ED7 8EE08EE19024900B9011901C900C902190EF90EA90F090F490F290F390D490EB 90EC90E991569158915A9153915591EC91F491F191F391F891E491F991EA0000 D8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 91EB91F791E891EE957A95869588967C966D966B9671966F96BF976A980498E5 9997509B50955094509E508B50A35083508C508E509D5068509C509250825087 515F51D45312531153A453A7559155A855A555AD5577564555A255935588558F 55B5558155A3559255A4557D558C55A6557F559555A1558E570C582958370000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005819581E58275823582857F558485825581C581B5833583F5836582E5839 5838582D582C583B59615AAF5A945A9F5A7A5AA25A9E5A785AA65A7C5AA55AAC 5A955AAE5A375A845A8A5A975A835A8B5AA95A7B5A7D5A8C5A9C5A8F5A935A9D 5BEA5BCD5BCB5BD45BD15BCA5BCE5C0C5C305D375D435D6B5D415D4B5D3F5D35 5D515D4E5D555D335D3A5D525D3D5D315D595D425D395D495D385D3C5D325D36 5D405D455E445E415F585FA65FA55FAB60C960B960CC60E260CE60C461140000 D9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 60F2610A6116610560F5611360F860FC60FE60C161036118611D611060FF6104 610B624A639463B163B063CE63E563E863EF63C3649D63F363CA63E063F663D5 63F263F5646163DF63BE63DD63DC63C463D863D363C263C763CC63CB63C863F0 63D763D965326567656A6564655C65686565658C659D659E65AE65D065D20000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000667C666C667B668066716679666A66726701690C68D3690468DC692A68EC 68EA68F1690F68D668F768EB68E468F66913691068F368E1690768CC69086970 68B4691168EF68C6691468F868D068FD68FC68E8690B690A691768CE68C868DD 68DE68E668F468D1690668D468E96915692568C76B396B3B6B3F6B3C6B946B97 6B996B956BBD6BF06BF26BF36C306DFC6E466E476E1F6E496E886E3C6E3D6E45 6E626E2B6E3F6E416E5D6E736E1C6E336E4B6E406E516E3B6E036E2E6E5E0000 DA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6E686E5C6E616E316E286E606E716E6B6E396E226E306E536E656E276E786E64 6E776E556E796E526E666E356E366E5A7120711E712F70FB712E713171237125 71227132711F7128713A711B724B725A7288728972867285728B7312730B7330 73227331733373277332732D732673237335730C742E742C7430742B74160000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000741A7421742D743174247423741D74297420743274FB752F756F756C75E7 75DA75E175E675DD75DF75E475D77695769276DA774677477744774D7745774A 774E774B774C77DE77EC786078647865785C786D7871786A786E787078697868 785E786279747973797279707A027A0A7A037A0C7A047A997AE67AE47B4A7B3B 7B447B487B4C7B4E7B407B587B457CA27C9E7CA87CA17D587D6F7D637D537D56 7D677D6A7D4F7D6D7D5C7D6B7D527D547D697D517D5F7D4E7F3E7F3F7F650000 DB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7F667FA27FA07FA17FD78051804F805080FE80D48143814A8152814F8147813D 814D813A81E681EE81F781F881F98204823C823D823F8275833B83CF83F98423 83C083E8841283E783E483FC83F6841083C683C883EB83E383BF840183DD83E5 83D883FF83E183CB83CE83D683F583C98409840F83DE8411840683C283F30000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000083D583FA83C783D183EA841383C383EC83EE83C483FB83D783E2841B83DB 83FE86D886E286E686D386E386DA86EA86DD86EB86DC86EC86E986D786E886D1 88488856885588BA88D788B988B888C088BE88B688BC88B788BD88B2890188C9 89958998899789DD89DA89DB8A4E8A4D8A398A598A408A578A588A448A458A52 8A488A518A4A8A4C8A4F8C5F8C818C808CBA8CBE8CB08CB98CB58D848D808D89 8DD88DD38DCD8DC78DD68DDC8DCF8DD58DD98DC88DD78DC58EEF8EF78EFA0000 DC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8EF98EE68EEE8EE58EF58EE78EE88EF68EEB8EF18EEC8EF48EE9902D9034902F 9106912C910490FF90FC910890F990FB9101910091079105910391619164915F 916291609201920A92259203921A9226920F920C9200921291FF91FD92069204 92279202921C92249219921792059216957B958D958C95909687967E96880000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000096899683968096C296C896C396F196F0976C9770976E980798A998EB9CE6 9EF94E834E844EB650BD50BF50C650AE50C450CA50B450C850C250B050C150BA 50B150CB50C950B650B851D7527A5278527B527C55C355DB55CC55D055CB55CA 55DD55C055D455C455E955BF55D2558D55CF55D555E255D655C855F255CD55D9 55C25714585358685864584F584D5849586F5855584E585D58595865585B583D 5863587158FC5AC75AC45ACB5ABA5AB85AB15AB55AB05ABF5AC85ABB5AC60000 DD 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5AB75AC05ACA5AB45AB65ACD5AB95A905BD65BD85BD95C1F5C335D715D635D4A 5D655D725D6C5D5E5D685D675D625DF05E4F5E4E5E4A5E4D5E4B5EC55ECC5EC6 5ECB5EC75F405FAF5FAD60F76149614A612B614561366132612E6146612F614F 612961406220916862236225622463C563F163EB641064126409642064240000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000064336443641F641564186439643764226423640C64266430642864416435 642F640A641A644064256427640B63E7641B642E6421640E656F659265D36686 668C66956690668B668A66996694667867206966695F6938694E69626971693F 6945696A6939694269576959697A694869496935696C6933693D696568F06978 693469696940696F69446976695869416974694C693B694B6937695C694F6951 69326952692F697B693C6B466B456B436B426B486B416B9BFA0D6BFB6BFC0000 DE 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6BF96BF76BF86E9B6ED66EC86E8F6EC06E9F6E936E946EA06EB16EB96EC66ED2 6EBD6EC16E9E6EC96EB76EB06ECD6EA66ECF6EB26EBE6EC36EDC6ED86E996E92 6E8E6E8D6EA46EA16EBF6EB36ED06ECA6E976EAE6EA371477154715271637160 7141715D716271727178716A7161714271587143714B7170715F715071530000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007144714D715A724F728D728C72917290728E733C7342733B733A7340734A 73497444744A744B7452745174577440744F7450744E74427446744D745474E1 74FF74FE74FD751D75797577698375EF760F760375F775FE75FC75F975F87610 75FB75F675ED75F575FD769976B576DD7755775F776077527756775A77697767 77547759776D77E07887789A7894788F788478957885788678A1788378797899 78807896787B797C7982797D79797A117A187A197A127A177A157A227A130000 DF 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7A1B7A107AA37AA27A9E7AEB7B667B647B6D7B747B697B727B657B737B717B70 7B617B787B767B637CB27CB47CAF7D887D867D807D8D7D7F7D857D7A7D8E7D7B 7D837D7C7D8C7D947D847D7D7D927F6D7F6B7F677F687F6C7FA67FA57FA77FDB 7FDC8021816481608177815C8169815B816281726721815E81768167816F0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000081448161821D8249824482408242824584F1843F845684768479848F848D 846584518440848684678430844D847D845A845984748473845D8507845E8437 843A8434847A8443847884328445842983D9844B842F8442842D845F84708439 844E844C8452846F84C5848E843B8447843684338468847E8444842B84608454 846E8450870B870486F7870C86FA86D686F5874D86F8870E8709870186F6870D 870588D688CB88CD88CE88DE88DB88DA88CC88D08985899B89DF89E589E40000 E0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 89E189E089E289DC89E68A768A868A7F8A618A3F8A778A828A848A758A838A81 8A748A7A8C3C8C4B8C4A8C658C648C668C868C848C858CCC8D688D698D918D8C 8D8E8D8F8D8D8D938D948D908D928DF08DE08DEC8DF18DEE8DD08DE98DE38DE2 8DE78DF28DEB8DF48F068EFF8F018F008F058F078F088F028F0B9052903F0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000090449049903D9110910D910F911191169114910B910E916E916F92489252 9230923A926692339265925E9283922E924A9246926D926C924F92609267926F 92369261927092319254926392509272924E9253924C92569232959F959C959E 959B969296939691969796CE96FA96FD96F896F59773977797789772980F980D 980E98AC98F698F999AF99B299B099B59AAD9AAB9B5B9CEA9CED9CE79E809EFD 50E650D450D750E850F350DB50EA50DD50E450D350EC50F050EF50E350E00000 E1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 51D85280528152E952EB533053AC56275615560C561255FC560F561C56015613 560255FA561D560455FF55F95889587C5890589858865881587F5874588B587A 58875891588E587658825888587B5894588F58FE596B5ADC5AEE5AE55AD55AEA 5ADA5AED5AEB5AF35AE25AE05ADB5AEC5ADE5ADD5AD95AE85ADF5B775BE00000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005BE35C635D825D805D7D5D865D7A5D815D775D8A5D895D885D7E5D7C5D8D 5D795D7F5E585E595E535ED85ED15ED75ECE5EDC5ED55ED95ED25ED45F445F43 5F6F5FB6612C61286141615E61716173615261536172616C618061746154617A 615B6165613B616A6161615662296227622B642B644D645B645D647464766472 6473647D6475646664A6644E6482645E645C644B645364606450647F643F646C 646B645964656477657365A066A166A0669F67056704672269B169B669C90000 E2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 69A069CE699669B069AC69BC69916999698E69A7698D69A969BE69AF69BF69C4 69BD69A469D469B969CA699A69CF69B3699369AA69A1699E69D96997699069C2 69B569A569C66B4A6B4D6B4B6B9E6B9F6BA06BC36BC46BFE6ECE6EF56EF16F03 6F256EF86F376EFB6F2E6F096F4E6F196F1A6F276F186F3B6F126EED6F0A0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006F366F736EF96EEE6F2D6F406F306F3C6F356EEB6F076F0E6F436F056EFD 6EF66F396F1C6EFC6F3A6F1F6F0D6F1E6F086F21718771907189718071857182 718F717B718671817197724472537297729572937343734D7351734C74627473 7471747574727467746E750075027503757D759076167608760C76157611760A 761476B87781777C77857782776E7780776F777E778378B278AA78B478AD78A8 787E78AB789E78A578A078AC78A278A47998798A798B79967995799479930000 E3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 79977988799279907A2B7A4A7A307A2F7A287A267AA87AAB7AAC7AEE7B887B9C 7B8A7B917B907B967B8D7B8C7B9B7B8E7B857B9852847B997BA47B827CBB7CBF 7CBC7CBA7DA77DB77DC27DA37DAA7DC17DC07DC57D9D7DCE7DC47DC67DCB7DCC 7DAF7DB97D967DBC7D9F7DA67DAE7DA97DA17DC97F737FE27FE37FE57FDE0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008024805D805C8189818681838187818D818C818B8215849784A484A1849F 84BA84CE84C284AC84AE84AB84B984B484C184CD84AA849A84B184D0849D84A7 84BB84A2849484C784CC849B84A984AF84A884D6849884B684CF84A084D784D4 84D284DB84B084918661873387238728876B8740872E871E87218719871B8743 872C8741873E874687208732872A872D873C8712873A87318735874287268727 87388724871A8730871188F788E788F188F288FA88FE88EE88FC88F688FB0000 E4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 88F088EC88EB899D89A1899F899E89E989EB89E88AAB8A998A8B8A928A8F8A96 8C3D8C688C698CD58CCF8CD78D968E098E028DFF8E0D8DFD8E0A8E038E078E06 8E058DFE8E008E048F108F118F0E8F0D9123911C91209122911F911D911A9124 9121911B917A91729179917392A592A49276929B927A92A0929492AA928D0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000092A6929A92AB92799297927F92A392EE928E9282929592A2927D928892A1 928A9286928C929992A7927E928792A9929D928B922D969E96A196FF9758977D 977A977E978397809782977B97849781977F97CE97CD981698AD98AE99029900 9907999D999C99C399B999BB99BA99C299BD99C79AB19AE39AE79B3E9B3F9B60 9B619B5F9CF19CF29CF59EA750FF5103513050F85106510750F650FE510B510C 50FD510A528B528C52F152EF56485642564C56355641564A5649564656580000 E5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 565A56405633563D562C563E5638562A563A571A58AB589D58B158A058A358AF 58AC58A558A158FF5AFF5AF45AFD5AF75AF65B035AF85B025AF95B015B075B05 5B0F5C675D995D975D9F5D925DA25D935D955DA05D9C5DA15D9A5D9E5E695E5D 5E605E5C7DF35EDB5EDE5EE15F495FB2618B6183617961B161B061A261890000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000619B619361AF61AD619F619261AA61A1618D616661B3622D646E64706496 64A064856497649C648F648B648A648C64A3649F646864B164986576657A6579 657B65B265B366B566B066A966B266B766AA66AF6A006A066A1769E569F86A15 69F169E46A2069FF69EC69E26A1B6A1D69FE6A2769F269EE6A1469F769E76A40 6A0869E669FB6A0D69FC69EB6A096A046A186A256A0F69F66A266A0769F46A16 6B516BA56BA36BA26BA66C016C006BFF6C026F416F266F7E6F876FC66F920000 E6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6F8D6F896F8C6F626F4F6F856F5A6F966F766F6C6F826F556F726F526F506F57 6F946F936F5D6F006F616F6B6F7D6F676F906F536F8B6F696F7F6F956F636F77 6F6A6F7B71B271AF719B71B071A0719A71A971B5719D71A5719E71A471A171AA 719C71A771B37298729A73587352735E735F7360735D735B7361735A73590000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000736274877489748A74867481747D74857488747C747975087507757E7625 761E7619761D761C7623761A7628761B769C769D769E769B778D778F77897788 78CD78BB78CF78CC78D178CE78D478C878C378C478C9799A79A179A0799C79A2 799B6B767A397AB27AB47AB37BB77BCB7BBE7BAC7BCE7BAF7BB97BCA7BB57CC5 7CC87CCC7CCB7DF77DDB7DEA7DE77DD77DE17E037DFA7DE67DF67DF17DF07DEE 7DDF7F767FAC7FB07FAD7FED7FEB7FEA7FEC7FE67FE88064806781A3819F0000 E7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 819E819581A2819981978216824F825382528250824E82518524853B850F8500 8529850E8509850D851F850A8527851C84FB852B84FA8508850C84F4852A84F2 851584F784EB84F384FC851284EA84E9851684FE8528851D852E850284FD851E 84F68531852684E784E884F084EF84F9851885208530850B8519852F86620000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000875687638764877787E1877387588754875B87528761875A8751875E876D 876A8750874E875F875D876F876C877A876E875C8765874F877B877587628767 8769885A8905890C8914890B891789188919890689168911890E890989A289A4 89A389ED89F089EC8ACF8AC68AB88AD38AD18AD48AD58ABB8AD78ABE8AC08AC5 8AD88AC38ABA8ABD8AD98C3E8C4D8C8F8CE58CDF8CD98CE88CDA8CDD8CE78DA0 8D9C8DA18D9B8E208E238E258E248E2E8E158E1B8E168E118E198E268E270000 E8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8E148E128E188E138E1C8E178E1A8F2C8F248F188F1A8F208F238F168F179073 9070906F9067906B912F912B9129912A91329126912E91859186918A91819182 9184918092D092C392C492C092D992B692CF92F192DF92D892E992D792DD92CC 92EF92C292E892CA92C892CE92E692CD92D592C992E092DE92E792D192D30000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000092B592E192C692B4957C95AC95AB95AE95B096A496A296D3970597089702 975A978A978E978897D097CF981E981D9826982998289820981B982798B29908 98FA9911991499169917991599DC99CD99CF99D399D499CE99C999D699D899CB 99D799CC9AB39AEC9AEB9AF39AF29AF19B469B439B679B749B719B669B769B75 9B709B689B649B6C9CFC9CFA9CFD9CFF9CF79D079D009CF99CFB9D089D059D04 9E839ED39F0F9F10511C51135117511A511151DE533453E156705660566E0000 E9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 567356665663566D5672565E5677571C571B58C858BD58C958BF58BA58C258BC 58C65B175B195B1B5B215B145B135B105B165B285B1A5B205B1E5BEF5DAC5DB1 5DA95DA75DB55DB05DAE5DAA5DA85DB25DAD5DAF5DB45E675E685E665E6F5EE9 5EE75EE65EE85EE55F4B5FBC619D61A8619661C561B461C661C161CC61BA0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000061BF61B8618C64D764D664D064CF64C964BD648964C364DB64F364D96533 657F657C65A266C866BE66C066CA66CB66CF66BD66BB66BA66CC67236A346A66 6A496A676A326A686A3E6A5D6A6D6A766A5B6A516A286A5A6A3B6A3F6A416A6A 6A646A506A4F6A546A6F6A696A606A3C6A5E6A566A556A4D6A4E6A466B556B54 6B566BA76BAA6BAB6BC86BC76C046C036C066FAD6FCB6FA36FC76FBC6FCE6FC8 6F5E6FC46FBD6F9E6FCA6FA870046FA56FAE6FBA6FAC6FAA6FCF6FBF6FB80000 EA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6FA26FC96FAB6FCD6FAF6FB26FB071C571C271BF71B871D671C071C171CB71D4 71CA71C771CF71BD71D871BC71C671DA71DB729D729E736973667367736C7365 736B736A747F749A74A074947492749574A1750B7580762F762D7631763D7633 763C76357632763076BB76E6779A779D77A1779C779B77A277A3779577990000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000779778DD78E978E578EA78DE78E378DB78E178E278ED78DF78E079A47A44 7A487A477AB67AB87AB57AB17AB77BDE7BE37BE77BDD7BD57BE57BDA7BE87BF9 7BD47BEA7BE27BDC7BEB7BD87BDF7CD27CD47CD77CD07CD17E127E217E177E0C 7E1F7E207E137E0E7E1C7E157E1A7E227E0B7E0F7E167E0D7E147E257E247F43 7F7B7F7C7F7A7FB17FEF802A8029806C81B181A681AE81B981B581AB81B081AC 81B481B281B781A781F282558256825785568545856B854D8553856185580000 EB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 854085468564854185628544855185478563853E855B8571854E856E85758555 85678560858C8566855D85548565856C866386658664879B878F879787938792 87888781879687988779878787A3878587908791879D87848794879C879A8789 891E89268930892D892E89278931892289298923892F892C891F89F18AE00000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008AE28AF28AF48AF58ADD8B148AE48ADF8AF08AC88ADE8AE18AE88AFF8AEF 8AFB8C918C928C908CF58CEE8CF18CF08CF38D6C8D6E8DA58DA78E338E3E8E38 8E408E458E368E3C8E3D8E418E308E3F8EBD8F368F2E8F358F328F398F378F34 90769079907B908690FA913391359136919391909191918D918F9327931E9308 931F9306930F937A9338933C931B9323931293019346932D930E930D92CB931D 92FA9325931392F992F793349302932492FF932993399335932A9314930C0000 EC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 930B92FE9309930092FB931695BC95CD95BE95B995BA95B695BF95B595BD96A9 96D4970B9712971097999797979497F097F89835982F98329924991F99279929 999E99EE99EC99E599E499F099E399EA99E999E79AB99ABF9AB49ABB9AF69AFA 9AF99AF79B339B809B859B879B7C9B7E9B7B9B829B939B929B909B7A9B950000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009B7D9B889D259D179D209D1E9D149D299D1D9D189D229D109D199D1F9E88 9E869E879EAE9EAD9ED59ED69EFA9F129F3D51265125512251245120512952F4 5693568C568D568656845683567E5682567F568158D658D458CF58D25B2D5B25 5B325B235B2C5B275B265B2F5B2E5B7B5BF15BF25DB75E6C5E6A5FBE5FBB61C3 61B561BC61E761E061E561E461E861DE64EF64E964E364EB64E464E865816580 65B665DA66D26A8D6A966A816AA56A896A9F6A9B6AA16A9E6A876A936A8E0000 ED 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6A956A836AA86AA46A916A7F6AA66A9A6A856A8C6A926B5B6BAD6C096FCC6FA9 6FF46FD46FE36FDC6FED6FE76FE66FDE6FF26FDD6FE26FE871E171F171E871F2 71E471F071E27373736E736F749774B274AB749074AA74AD74B174A574AF7510 75117512750F7584764376487649764776A476E977B577AB77B277B777B60000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000077B477B177A877F078F378FD790278FB78FC78F2790578F978FE790479AB 79A87A5C7A5B7A567A587A547A5A7ABE7AC07AC17C057C0F7BF27C007BFF7BFB 7C0E7BF47C0B7BF37C027C097C037C017BF87BFD7C067BF07BF17C107C0A7CE8 7E2D7E3C7E427E3398487E387E2A7E497E407E477E297E4C7E307E3B7E367E44 7E3A7F457F7F7F7E7F7D7FF47FF2802C81BB81C481CC81CA81C581C781BC81E9 825B825A825C85838580858F85A7859585A0858B85A3857B85A4859A859E0000 EE 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8577857C858985A1857A85788557858E85968586858D8599859D858185A28582 858885858579857685988590859F866887BE87AA87AD87C587B087AC87B987B5 87BC87AE87C987C387C287CC87B787AF87C487CA87B487B687BF87B887BD87DE 87B289358933893C893E894189528937894289AD89AF89AE89F289F38B1E0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008B188B168B118B058B0B8B228B0F8B128B158B078B0D8B088B068B1C8B13 8B1A8C4F8C708C728C718C6F8C958C948CF98D6F8E4E8E4D8E538E508E4C8E47 8F438F409085907E9138919A91A2919B9199919F91A1919D91A093A1938393AF 936493569347937C9358935C93769349935093519360936D938F934C936A9379 935793559352934F93719377937B9361935E936393679380934E935995C795C0 95C995C395C595B796AE96B096AC9720971F9718971D9719979A97A1979C0000 EF 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 979E979D97D597D497F198419844984A9849984598439925992B992C992A9933 9932992F992D99319930999899A399A19A0299FA99F499F799F999F899F699FB 99FD99FE99FC9A039ABE9AFE9AFD9B019AFC9B489B9A9BA89B9E9B9B9BA69BA1 9BA59BA49B869BA29BA09BAF9D339D419D679D369D2E9D2F9D319D389D300000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009D459D429D439D3E9D379D409D3D7FF59D2D9E8A9E899E8D9EB09EC89EDA 9EFB9EFF9F249F239F229F549FA05131512D512E5698569C5697569A569D5699 59705B3C5C695C6A5DC05E6D5E6E61D861DF61ED61EE61F161EA61F061EB61D6 61E964FF650464FD64F86501650364FC659465DB66DA66DB66D86AC56AB96ABD 6AE16AC66ABA6AB66AB76AC76AB46AAD6B5E6BC96C0B7007700C700D70017005 7014700E6FFF70006FFB70266FFC6FF7700A720171FF71F9720371FD73760000 F0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 74B874C074B574C174BE74B674BB74C275147513765C76647659765076537657 765A76A676BD76EC77C277BA78FF790C79137914790979107912791179AD79AC 7A5F7C1C7C297C197C207C1F7C2D7C1D7C267C287C227C257C307E5C7E507E56 7E637E587E627E5F7E517E607E577E537FB57FB37FF77FF8807581D181D20000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000081D0825F825E85B485C685C085C385C285B385B585BD85C785C485BF85CB 85CE85C885C585B185B685D2862485B885B785BE866987E787E687E287DB87EB 87EA87E587DF87F387E487D487DC87D387ED87D887E387A487D787D9880187F4 87E887DD8953894B894F894C89468950895189498B2A8B278B238B338B308B35 8B478B2F8B3C8B3E8B318B258B378B268B368B2E8B248B3B8B3D8B3A8C428C75 8C998C988C978CFE8D048D028D008E5C8E628E608E578E568E5E8E658E670000 F1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8E5B8E5A8E618E5D8E698E548F468F478F488F4B9128913A913B913E91A891A5 91A791AF91AA93B5938C939293B7939B939D938993A7938E93AA939E93A69395 93889399939F938D93B1939193B293A493A893B493A393A595D295D395D196B3 96D796DA5DC296DF96D896DD97239722972597AC97AE97A897AB97A497AA0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000097A297A597D797D997D697D897FA98509851985298B89941993C993A9A0F 9A0B9A099A0D9A049A119A0A9A059A079A069AC09ADC9B089B049B059B299B35 9B4A9B4C9B4B9BC79BC69BC39BBF9BC19BB59BB89BD39BB69BC49BB99BBD9D5C 9D539D4F9D4A9D5B9D4B9D599D569D4C9D579D529D549D5F9D589D5A9E8E9E8C 9EDF9F019F009F169F259F2B9F2A9F299F289F4C9F5551345135529652F753B4 56AB56AD56A656A756AA56AC58DA58DD58DB59125B3D5B3E5B3F5DC35E700000 F2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5FBF61FB65076510650D6509650C650E658465DE65DD66DE6AE76AE06ACC6AD1 6AD96ACB6ADF6ADC6AD06AEB6ACF6ACD6ADE6B606BB06C0C7019702770207016 702B702170227023702970177024701C702A720C720A72077202720572A572A6 72A472A372A174CB74C574B774C37516766077C977CA77C477F1791D791B0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007921791C7917791E79B07A677A687C337C3C7C397C2C7C3B7CEC7CEA7E76 7E757E787E707E777E6F7E7A7E727E747E687F4B7F4A7F837F867FB77FFD7FFE 807881D781D582648261826385EB85F185ED85D985E185E885DA85D785EC85F2 85F885D885DF85E385DC85D185F085E685EF85DE85E2880087FA880387F687F7 8809880C880B880687FC880887FF880A88028962895A895B89578961895C8958 895D8959898889B789B689F68B508B488B4A8B408B538B568B548B4B8B550000 F3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8B518B428B528B578C438C778C768C9A8D068D078D098DAC8DAA8DAD8DAB8E6D 8E788E738E6A8E6F8E7B8EC28F528F518F4F8F508F538FB49140913F91B091AD 93DE93C793CF93C293DA93D093F993EC93CC93D993A993E693CA93D493EE93E3 93D593C493CE93C093D293E7957D95DA95DB96E19729972B972C972897260000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000097B397B797B697DD97DE97DF985C9859985D985798BF98BD98BB98BE9948 9947994399A699A79A1A9A159A259A1D9A249A1B9A229A209A279A239A1E9A1C 9A149AC29B0B9B0A9B0E9B0C9B379BEA9BEB9BE09BDE9BE49BE69BE29BF09BD4 9BD79BEC9BDC9BD99BE59BD59BE19BDA9D779D819D8A9D849D889D719D809D78 9D869D8B9D8C9D7D9D6B9D749D759D709D699D859D739D7B9D829D6F9D799D7F 9D879D689E949E919EC09EFC9F2D9F409F419F4D9F569F579F58533756B20000 F4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 56B556B358E35B455DC65DC75EEE5EEF5FC05FC161F9651765166515651365DF 66E866E366E46AF36AF06AEA6AE86AF96AF16AEE6AEF703C7035702F70377034 703170427038703F703A70397040703B703370417213721472A8737D737C74BA 76AB76AA76BE76ED77CC77CE77CF77CD77F27925792379277928792479290000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000079B27A6E7A6C7A6D7AF77C497C487C4A7C477C457CEE7E7B7E7E7E817E80 7FBA7FFF807981DB81D9820B82688269862285FF860185FE861B860085F68604 86098605860C85FD8819881088118817881388168963896689B989F78B608B6A 8B5D8B688B638B658B678B6D8DAE8E868E888E848F598F568F578F558F588F5A 908D9143914191B791B591B291B3940B941393FB9420940F941493FE94159410 94289419940D93F5940093F79407940E9416941293FA940993F8940A93FF0000 F5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 93FC940C93F69411940695DE95E095DF972E972F97B997BB97FD97FE98609862 9863985F98C198C29950994E9959994C994B99539A329A349A319A2C9A2A9A36 9A299A2E9A389A2D9AC79ACA9AC69B109B129B119C0B9C089BF79C059C129BF8 9C409C079C0E9C069C179C149C099D9F9D999DA49D9D9D929D989D909D9B0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009DA09D949D9C9DAA9D979DA19D9A9DA29DA89D9E9DA39DBF9DA99D969DA6 9DA79E999E9B9E9A9EE59EE49EE79EE69F309F2E9F5B9F609F5E9F5D9F599F91 513A51395298529756C356BD56BE5B485B475DCB5DCF5EF161FD651B6B026AFC 6B036AF86B0070437044704A7048704970457046721D721A7219737E7517766A 77D0792D7931792F7C547C537CF27E8A7E877E887E8B7E867E8D7F4D7FBB8030 81DD8618862A8626861F8623861C86198627862E862186208629861E86250000 F6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8829881D881B88208824881C882B884A896D8969896E896B89FA8B798B788B45 8B7A8B7B8D108D148DAF8E8E8E8C8F5E8F5B8F5D91469144914591B9943F943B 94369429943D943C94309439942A9437942C9440943195E595E495E39735973A 97BF97E1986498C998C698C0995899569A399A3D9A469A449A429A419A3A0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009A3F9ACD9B159B179B189B169B3A9B529C2B9C1D9C1C9C2C9C239C289C29 9C249C219DB79DB69DBC9DC19DC79DCA9DCF9DBE9DC59DC39DBB9DB59DCE9DB9 9DBA9DAC9DC89DB19DAD9DCC9DB39DCD9DB29E7A9E9C9EEB9EEE9EED9F1B9F18 9F1A9F319F4E9F659F649F924EB956C656C556CB59715B4B5B4C5DD55DD15EF2 65216520652665226B0B6B086B096C0D7055705670577052721E721F72A9737F 74D874D574D974D7766D76AD793579B47A707A717C577C5C7C597C5B7C5A0000 F7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7CF47CF17E917F4F7F8781DE826B863486358633862C86328636882C88288826 882A8825897189BF89BE89FB8B7E8B848B828B868B858B7F8D158E958E948E9A 8E928E908E968E978F608F629147944C9450944A944B944F9447944594489449 9446973F97E3986A986998CB9954995B9A4E9A539A549A4C9A4F9A489A4A0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009A499A529A509AD09B199B2B9B3B9B569B559C469C489C3F9C449C399C33 9C419C3C9C379C349C329C3D9C369DDB9DD29DDE9DDA9DCB9DD09DDC9DD19DDF 9DE99DD99DD89DD69DF59DD59DDD9EB69EF09F359F339F329F429F6B9F959FA2 513D529958E858E759725B4D5DD8882F5F4F62016203620465296525659666EB 6B116B126B0F6BCA705B705A7222738273817383767077D47C677C667E95826C 863A86408639863C8631863B863E88308832882E883389768974897389FE0000 F8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8B8C8B8E8B8B8B888C458D198E988F648F6391BC94629455945D9457945E97C4 97C598009A569A599B1E9B1F9B209C529C589C509C4A9C4D9C4B9C559C599C4C 9C4E9DFB9DF79DEF9DE39DEB9DF89DE49DF69DE19DEE9DE69DF29DF09DE29DEC 9DF49DF39DE89DED9EC29ED09EF29EF39F069F1C9F389F379F369F439F4F0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009F719F709F6E9F6F56D356CD5B4E5C6D652D66ED66EE6B13705F7061705D 7060722374DB74E577D5793879B779B67C6A7E977F89826D8643883888378835 884B8B948B958E9E8E9F8EA08E9D91BE91BD91C2946B9468946996E597469743 974797C797E59A5E9AD59B599C639C679C669C629C5E9C609E029DFE9E079E03 9E069E059E009E019E099DFF9DFD9E049EA09F1E9F469F749F759F7656D4652E 65B86B186B196B176B1A7062722672AA77D877D979397C697C6B7CF67E9A0000 F9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7E987E9B7E9981E081E18646864786488979897A897C897B89FF8B988B998EA5 8EA48EA3946E946D946F9471947397499872995F9C689C6E9C6D9E0B9E0D9E10 9E0F9E129E119EA19EF59F099F479F789F7B9F7A9F79571E70667C6F883C8DB2 8EA691C394749478947694759A609C749C739C719C759E149E139EF69F0A0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009FA4706870657CF7866A883E883D883F8B9E8C9C8EA98EC9974B98739874 98CC996199AB9A649A669A679B249E159E179F4862076B1E7227864C8EA89482 948094819A699A689B2E9E197229864B8B9F94839C799EB776759A6B9C7A9E1D 7069706A9EA49F7E9F499F98788192B988CF58BB60527CA75AFA255425662557 2560256C2563255A2569255D255225642555255E256A256125582567255B2553 25652556255F256B256225592568255C25512550256D256E2570256F25930000 tcl8.4.20/library/encoding/euc-cn.enc0000644003604700454610000024710611737050674016024 0ustar dgp771div# Encoding file: euc-cn, multi-byte M 003F 0 82 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 0080008100820083008400850086008700880089008A008B008C008D008E008F 0090009100920093009400950096009700980099009A009B009C009D009E009F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 A1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000030003001300230FB02C902C700A8300330052015FF5E2225202620182019 201C201D3014301530083009300A300B300C300D300E300F3016301730103011 00B100D700F72236222722282211220F222A222922082237221A22A522252220 23122299222B222E2261224C2248223D221D2260226E226F22642265221E2235 22342642264000B0203220332103FF0400A4FFE0FFE1203000A7211626062605 25CB25CF25CE25C725C625A125A025B325B2203B219221902191219330130000 A2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000024882489248A248B248C248D248E248F2490249124922493249424952496 249724982499249A249B247424752476247724782479247A247B247C247D247E 247F248024812482248324842485248624872460246124622463246424652466 2467246824690000000032203221322232233224322532263227322832290000 00002160216121622163216421652166216721682169216A216B000000000000 A3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FF01FF02FF03FFE5FF05FF06FF07FF08FF09FF0AFF0BFF0CFF0DFF0EFF0F FF10FF11FF12FF13FF14FF15FF16FF17FF18FF19FF1AFF1BFF1CFF1DFF1EFF1F FF20FF21FF22FF23FF24FF25FF26FF27FF28FF29FF2AFF2BFF2CFF2DFF2EFF2F FF30FF31FF32FF33FF34FF35FF36FF37FF38FF39FF3AFF3BFF3CFF3DFF3EFF3F FF40FF41FF42FF43FF44FF45FF46FF47FF48FF49FF4AFF4BFF4CFF4DFF4EFF4F FF50FF51FF52FF53FF54FF55FF56FF57FF58FF59FF5AFF5BFF5CFF5DFFE30000 A4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000304130423043304430453046304730483049304A304B304C304D304E304F 3050305130523053305430553056305730583059305A305B305C305D305E305F 3060306130623063306430653066306730683069306A306B306C306D306E306F 3070307130723073307430753076307730783079307A307B307C307D307E307F 3080308130823083308430853086308730883089308A308B308C308D308E308F 3090309130923093000000000000000000000000000000000000000000000000 A5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000030A130A230A330A430A530A630A730A830A930AA30AB30AC30AD30AE30AF 30B030B130B230B330B430B530B630B730B830B930BA30BB30BC30BD30BE30BF 30C030C130C230C330C430C530C630C730C830C930CA30CB30CC30CD30CE30CF 30D030D130D230D330D430D530D630D730D830D930DA30DB30DC30DD30DE30DF 30E030E130E230E330E430E530E630E730E830E930EA30EB30EC30ED30EE30EF 30F030F130F230F330F430F530F6000000000000000000000000000000000000 A6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000039103920393039403950396039703980399039A039B039C039D039E039F 03A003A103A303A403A503A603A703A803A90000000000000000000000000000 000003B103B203B303B403B503B603B703B803B903BA03BB03BC03BD03BE03BF 03C003C103C303C403C503C603C703C803C90000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 A7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000004100411041204130414041504010416041704180419041A041B041C041D 041E041F0420042104220423042404250426042704280429042A042B042C042D 042E042F00000000000000000000000000000000000000000000000000000000 000004300431043204330434043504510436043704380439043A043B043C043D 043E043F0440044104420443044404450446044704480449044A044B044C044D 044E044F00000000000000000000000000000000000000000000000000000000 A8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000010100E101CE00E0011300E9011B00E8012B00ED01D000EC014D00F301D2 00F2016B00FA01D400F901D601D801DA01DC00FC00EA00000000000000000000 0000000000000000000031053106310731083109310A310B310C310D310E310F 3110311131123113311431153116311731183119311A311B311C311D311E311F 3120312131223123312431253126312731283129000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 A9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000002500250125022503250425052506250725082509250A250B 250C250D250E250F2510251125122513251425152516251725182519251A251B 251C251D251E251F2520252125222523252425252526252725282529252A252B 252C252D252E252F2530253125322533253425352536253725382539253A253B 253C253D253E253F2540254125422543254425452546254725482549254A254B 0000000000000000000000000000000000000000000000000000000000000000 B0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000554A963F57C3632854CE550954C07691764C853C77EE827E788D72319698 978D6C285B894FFA630966975CB880FA684880AE660276CE51F9655671AC7FF1 888450B2596561CA6FB382AD634C625253ED54277B06516B75A45DF462D48DCB 9776628A8019575D97387F627238767D67CF767E64464F708D2562DC7A176591 73ED642C6273822C9881677F7248626E62CC4F3474E3534A529E7ECA90A65E2E 6886699C81807ED168D278C5868C9551508D8C2482DE80DE5305891252650000 B1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000858496F94FDD582199715B9D62B162A566B48C799C8D7206676F789160B2 535153178F8880CC8D1D94A1500D72C8590760EB711988AB595482EF672C7B28 5D297EF7752D6CF58E668FF8903C9F3B6BD491197B145F7C78A784D6853D6BD5 6BD96BD65E015E8775F995ED655D5F0A5FC58F9F58C181C2907F965B97AD8FB9 7F168D2C62414FBF53D8535E8FA88FA98FAB904D68075F6A819888689CD6618B 522B762A5F6C658C6FD26EE85BBE6448517551B067C44E1979C9997C70B30000 B2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000075C55E7673BB83E064AD62E894B56CE2535A52C3640F94C27B944F2F5E1B 82368116818A6E246CCA9A736355535C54FA886557E04E0D5E036B657C3F90E8 601664E6731C88C16750624D8D22776C8E2991C75F6983DC8521991053C28695 6B8B60ED60E8707F82CD82314ED36CA785CF64CD7CD969FD66F9834953957B56 4FA7518C6D4B5C428E6D63D253C9832C833667E578B4643D5BDF5C945DEE8BE7 62C667F48C7A640063BA8749998B8C177F2094F24EA7961098A4660C73160000 B3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000573A5C1D5E38957F507F80A05382655E7545553150218D856284949E671D 56326F6E5DE2543570928F66626F64A463A35F7B6F8890F481E38FB05C186668 5FF16C8996488D81886C649179F057CE6A59621054484E587A0B60E96F848BDA 627F901E9A8B79E4540375F4630153196C608FDF5F1B9A70803B9F7F4F885C3A 8D647FC565A570BD514551B2866B5D075BA062BD916C75748E0C7A2061017B79 4EC77EF877854E1181ED521D51FA6A7153A88E87950496CF6EC19664695A0000 B4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000784050A877D7641089E6590463E35DDD7A7F693D4F20823955984E3275AE 7A975E625E8A95EF521B5439708A6376952457826625693F918755076DF37EAF 882262337EF075B5832878C196CC8F9E614874F78BCD6B64523A8D506B21806A 847156F153064ECE4E1B51D17C97918B7C074FC38E7F7BE17A9C64675D1450AC 810676017CB96DEC7FE067515B585BF878CB64AE641363AA632B9519642D8FBE 7B5476296253592754466B7950A362345E266B864EE38D37888B5F85902E0000 B5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006020803D62C54E39535590F863B880C665E66C2E4F4660EE6DE18BDE5F39 86CB5F536321515A83616863520063638E4850125C9B79775BFC52307A3B60BC 905376D75FB75F9776848E6C706F767B7B4977AA51F3909358244F4E6EF48FEA 654C7B1B72C46DA47FDF5AE162B55E95573084827B2C5E1D5F1F90127F1498A0 63826EC7789870B95178975B57AB75354F4375385E9760E659606DC06BBF7889 53FC96D551CB52016389540A94938C038DCC7239789F87768FED8C0D53E00000 B6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00004E0176EF53EE948998769F0E952D5B9A8BA24E224E1C51AC846361C252A8 680B4F97606B51BB6D1E515C6296659796618C46901775D890FD77636BD2728A 72EC8BFB583577798D4C675C9540809A5EA66E2159927AEF77ED953B6BB565AD 7F0E58065151961F5BF958A954288E726566987F56E4949D76FE9041638754C6 591A593A579B8EB267358DFA8235524160F0581586FE5CE89E454FC4989D8BB9 5A2560765384627C904F9102997F6069800C513F80335C1499756D314E8C0000 B7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008D3053D17F5A7B4F4F104E4F96006CD573D085E95E06756A7FFB6A0A77FE 94927E4151E170E653CD8FD483038D2972AF996D6CDB574A82B365B980AA623F 963259A84EFF8BBF7EBA653E83F2975E556198DE80A5532A8BFD542080BA5E9F 6CB88D3982AC915A54296C1B52067EB7575F711A6C7E7C89594B4EFD5FFF6124 7CAA4E305C0167AB87025CF0950B98CE75AF70FD902251AF7F1D8BBD594951E4 4F5B5426592B657780A45B75627662C28F905E456C1F7B264F0F4FD8670D0000 B8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006D6E6DAA798F88B15F17752B629A8F854FEF91DC65A7812F81515E9C8150 8D74526F89868D4B590D50854ED8961C723681798D1F5BCC8BA3964459877F1A 54905676560E8BE565396982949976D66E895E727518674667D17AFF809D8D76 611F79C665628D635188521A94A27F38809B7EB25C976E2F67607BD9768B9AD8 818F7F947CD5641E95507A3F544A54E56B4C640162089E3D80F3759952729769 845B683C86E49601969494EC4E2A54047ED968398DDF801566F45E9A7FB90000 B9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000057C2803F68975DE5653B529F606D9F9A4F9B8EAC516C5BAB5F135DE96C5E 62F18D21517194A952FE6C9F82DF72D757A267848D2D591F8F9C83C754957B8D 4F306CBD5B6459D19F1353E486CA9AA88C3780A16545987E56FA96C7522E74DC 52505BE1630289024E5662D0602A68FA51735B9851A089C27BA199867F5060EF 704C8D2F51495E7F901B747089C4572D78455F529F9F95FA8F689B3C8BE17678 684267DC8DEA8D35523D8F8A6EDA68CD950590ED56FD679C88F98FC754C80000 BA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009AB85B696D776C264EA55BB39A87916361A890AF97E9542B6DB55BD251FD 558A7F557FF064BC634D65F161BE608D710A6C576C49592F676D822A58D5568E 8C6A6BEB90DD597D801753F76D695475559D837783CF683879BE548C4F555408 76D28C8996026CB36DB88D6B89109E648D3A563F9ED175D55F8872E0606854FC 4EA86A2A886160528F7054C470D886799E3F6D2A5B8F5F187EA255894FAF7334 543C539A5019540E547C4E4E5FFD745A58F6846B80E1877472D07CCA6E560000 BB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005F27864E552C62A44E926CAA623782B154D7534E733E6ED1753B52125316 8BDD69D05F8A60006DEE574F6B2273AF68538FD87F13636260A3552475EA8C62 71156DA35BA65E7B8352614C9EC478FA87577C27768751F060F6714C66435E4C 604D8C0E707063258F895FBD606286D456DE6BC160946167534960E066668D3F 79FD4F1A70E96C478BB38BF27ED88364660F5A5A9B426D516DF78C416D3B4F19 706B83B7621660D1970D8D27797851FB573E57FA673A75787A3D79EF7B950000 BC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000808C99658FF96FC08BA59E2159EC7EE97F095409678168D88F917C4D96C6 53CA602575BE6C7253735AC97EA7632451E0810A5DF184DF628051805B634F0E 796D524260B86D4E5BC45BC28BA18BB065E25FCC964559937EE77EAA560967B7 59394F735BB652A0835A988A8D3E753294BE50477A3C4EF767B69A7E5AC16B7C 76D1575A5C167B3A95F4714E517C80A9827059787F04832768C067EC78B17877 62E363617B804FED526A51CF835069DB92748DF58D3189C1952E7BAD4EF60000 BD 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000506582305251996F6E106E856DA75EFA50F559DC5C066D466C5F7586848B 686859568BB253209171964D854969127901712680F64EA490CA6D479A845A07 56BC640594F077EB4FA5811A72E189D2997A7F347EDE527F655991758F7F8F83 53EB7A9663ED63A5768679F888579636622A52AB8282685467706377776B7AED 6D017ED389E359D0621285C982A5754C501F4ECB75A58BEB5C4A5DFE7B4B65A4 91D14ECA6D25895F7D2795264EC58C288FDB9773664B79818FD170EC6D780000 BE 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005C3D52B283465162830E775B66769CB84EAC60CA7CBE7CB37ECF4E958B66 666F988897595883656C955C5F8475C997567ADF7ADE51C070AF7A9863EA7A76 7EA0739697ED4E4570784E5D915253A9655165E781FC8205548E5C31759A97A0 62D872D975BD5C459A7983CA5C40548077E94E3E6CAE805A62D2636E5DE85177 8DDD8E1E952F4FF153E560E770AC526763509E435A1F5026773753777EE26485 652B628963985014723589C951B38BC07EDD574783CC94A7519B541B5CFB0000 BF 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00004FCA7AE36D5A90E19A8F55805496536154AF5F0063E9697751EF6168520A 582A52D8574E780D770B5EB761777CE0625B62974EA27095800362F770E49760 577782DB67EF68F578D5989779D158F354B353EF6E34514B523B5BA28BFE80AF 554357A660735751542D7A7A60505B5463A762A053E362635BC767AF54ED7A9F 82E691775E9388E4593857AE630E8DE880EF57577B774FA95FEB5BBD6B3E5321 7B5072C2684677FF773665F751B54E8F76D45CBF7AA58475594E9B4150800000 C0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000998861276E8357646606634656F062EC62695ED39614578362C955878721 814A8FA3556683B167658D5684DD5A6A680F62E67BEE961151706F9C8C3063FD 89C861D27F0670C26EE57405699472FC5ECA90CE67176D6A635E52B372628001 4F6C59E5916A70D96D9D52D24E5096F7956D857E78CA7D2F5121579264C2808B 7C7B6CEA68F1695E51B7539868A872819ECE7BF172F879BB6F137406674E91CC 9CA4793C83898354540F68174E3D538952B1783E5386522950884F8B4FD00000 C1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000075E27ACB7C926CA596B6529B748354E94FE9805483B28FDE95705EC9601C 6D9F5E18655B813894FE604B70BC7EC37CAE51C968817CB1826F4E248F8691CF 667E4EAE8C0564A9804A50DA759771CE5BE58FBD6F664E86648295635ED66599 521788C270C852A3730E7433679778F797164E3490BB9CDE6DCB51DB8D41541D 62CE73B283F196F69F8494C34F367F9A51CC707596755CAD988653E64EE46E9C 740969B4786B998F7559521876246D4167F3516D9F99804B54997B3C7ABF0000 C2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009686578462E29647697C5A0464027BD36F0F964B82A6536298855E907089 63B35364864F9C819E93788C97328DEF8D429E7F6F5E79845F559646622E9A74 541594DD4FA365C55C655C617F1586516C2F5F8B73876EE47EFF5CE6631B5B6A 6EE653754E7163A0756562A18F6E4F264ED16CA67EB68BBA841D87BA7F57903B 95237BA99AA188F8843D6D1B9A867EDC59889EBB739B780186829A6C9A82561B 541757CB4E709EA653568FC881097792999286EE6EE1851366FC61626F2B0000 C3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008C298292832B76F26C135FD983BD732B8305951A6BDB77DB94C6536F8302 51925E3D8C8C8D384E4873AB679A68859176970971646CA177095A9295416BCF 7F8E66275BD059B95A9A95E895F74EEC840C84996AAC76DF9530731B68A65B5F 772F919A97617CDC8FF78C1C5F257C7379D889C56CCC871C5BC65E4268C97720 7EF55195514D52C95A297F05976282D763CF778485D079D26E3A5E9959998511 706D6C1162BF76BF654F60AF95FD660E879F9E2394ED540D547D8C2C64780000 C4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000647986116A21819C78E864699B5462B9672B83AB58A89ED86CAB6F205BDE 964C8C0B725F67D062C772614EA959C66BCD589366AE5E5552DF6155672876EE 776672677A4662FF54EA545094A090A35A1C7EB36C164E435976801059485357 753796BE56CA63208111607C95F96DD65462998151855AE980FD59AE9713502A 6CE55C3C62DF4F60533F817B90066EBA852B62C85E7478BE64B5637B5FF55A18 917F9E1F5C3F634F80425B7D556E954A954D6D8560A867E072DE51DD5B810000 C5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000062E76CDE725B626D94AE7EBD81136D53519C5F04597452AA601259736696 8650759F632A61E67CEF8BFA54E66B279E256BB485D5545550766CA4556A8DB4 722C5E156015743662CD6392724C5F986E436D3E65006F5876D878D076FC7554 522453DB4E535E9E65C1802A80D6629B5486522870AE888D8DD16CE1547880DA 57F988F48D54966A914D4F696C9B55B776C6783062A870F96F8E5F6D84EC68DA 787C7BF781A8670B9E4F636778B0576F78129739627962AB528874356BD70000 C6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005564813E75B276AE533975DE50FB5C418B6C7BC7504F72479A9798D86F02 74E27968648777A562FC98918D2B54C180584E52576A82F9840D5E7351ED74F6 8BC45C4F57616CFC98875A4678349B448FEB7C955256625194FA4EC683868461 83E984B257D467345703666E6D668C3166DD7011671F6B3A6816621A59BB4E03 51C46F0667D26C8F517668CB59476B6775665D0E81109F5065D7794879419A91 8D775C824E5E4F01542F5951780C56686C148FC45F036C7D6CE38BAB63900000 C7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000060706D3D72756266948E94C553438FC17B7E4EDF8C264E7E9ED494B194B3 524D6F5C90636D458C3458115D4C6B206B4967AA545B81547F8C589985375F3A 62A26A47953965726084686577A74E544FA85DE7979864AC7FD85CED4FCF7A8D 520783044E14602F7A8394A64FB54EB279E6743452E482B964D279BD5BDD6C81 97528F7B6C22503E537F6E0564CE66746C3060C598778BF75E86743C7A7779CB 4E1890B174036C4256DA914B6CC58D8B533A86C666F28EAF5C489A716E200000 C8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000053D65A369F8B8DA353BB570898A76743919B6CC9516875CA62F372AC5238 529D7F3A7094763853749E4A69B7786E96C088D97FA4713671C3518967D374E4 58E4651856B78BA9997662707ED560F970ED58EC4EC14EBA5FCD97E74EFB8BA4 5203598A7EAB62544ECD65E5620E833884C98363878D71946EB65BB97ED25197 63C967D480898339881551125B7A59828FB14E736C5D516589258F6F962E854A 745E951095F06DA682E55F3164926D128428816E9CC3585E8D5B4E0953C10000 C9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00004F1E6563685155D34E2764149A9A626B5AC2745F82726DA968EE50E7838E 7802674052396C997EB150BB5565715E7B5B665273CA82EB67495C715220717D 886B95EA965564C58D6181B355846C5562477F2E58924F2455468D4F664C4E0A 5C1A88F368A2634E7A0D70E7828D52FA97F65C1154E890B57ECD59628D4A86C7 820C820D8D6664445C0461516D89793E8BBE78377533547B4F388EAB6DF15A20 7EC5795E6C885BA15A76751A80BE614E6E1758F0751F7525727253477EF30000 CA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000770176DB526980DC57235E08593172EE65BD6E7F8BD75C388671534177F3 62FE65F64EC098DF86805B9E8BC653F277E24F7F5C4E9A7659CB5F0F793A58EB 4E1667FF4E8B62ED8A93901D52BF662F55DC566C90024ED54F8D91CA99706C0F 5E0260435BA489C68BD56536624B99965B885BFF6388552E53D77626517D852C 67A268B36B8A62928F9353D482126DD1758F4E668D4E5B70719F85AF669166D9 7F7287009ECD9F205C5E672F8FF06811675F620D7AD658855EB665706F310000 CB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000060555237800D6454887075295E05681362F4971C53CC723D8C016C347761 7A0E542E77AC987A821C8BF47855671470C165AF64955636601D79C153F84E1D 6B7B80865BFA55E356DB4F3A4F3C99725DF3677E80386002988290015B8B8BBC 8BF5641C825864DE55FD82CF91654FD77D20901F7C9F50F358516EAF5BBF8BC9 80839178849C7B97867D968B968F7EE59AD3788E5C817A57904296A7795F5B59 635F7B0B84D168AD55067F2974107D2295016240584C4ED65B83597958540000 CC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000736D631E8E4B8E0F80CE82D462AC53F06CF0915E592A60016C70574D644A 8D2A762B6EE9575B6A8075F06F6D8C2D8C0857666BEF889278B363A253F970AD 6C645858642A580268E0819B55107CD650188EBA6DCC8D9F70EB638F6D9B6ED4 7EE68404684390036DD896768BA85957727985E4817E75BC8A8A68AF52548E22 951163D098988E44557C4F5366FF568F60D56D9552435C4959296DFB586B7530 751C606C82148146631167618FE2773A8DF38D3494C15E165385542C70C30000 CD 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006C405EF7505C4EAD5EAD633A8247901A6850916E77B3540C94DC5F647AE5 687663457B527EDF75DB507762955934900F51F879C37A8156FE5F9290146D82 5C60571F541051546E4D56E263A89893817F8715892A9000541E5C6F81C062D6 625881319E3596409A6E9A7C692D59A562D3553E631654C786D96D3C5A0374E6 889C6B6A59168C4C5F2F6E7E73A9987D4E3870F75B8C7897633D665A769660CB 5B9B5A494E0781556C6A738B4EA167897F515F8065FA671B5FD859845A010000 CE 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005DCD5FAE537197E68FDD684556F4552F60DF4E3A6F4D7EF482C7840E59D4 4F1F4F2A5C3E7EAC672A851A5473754F80C355829B4F4F4D6E2D8C135C096170 536B761F6E29868A658795FB7EB9543B7A337D0A95EE55E17FC174EE631D8717 6DA17A9D621165A1536763E16C835DEB545C94A84E4C6C618BEC5C4B65E0829C 68A7543E54346BCB6B664E9463425348821E4F0D4FAE575E620A96FE66647269 52FF52A1609F8BEF661471996790897F785277FD6670563B54389521727A0000 CF 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007A00606F5E0C6089819D591560DC718470EF6EAA6C5072806A8488AD5E2D 4E605AB3559C94E36D177CFB9699620F7EC6778E867E5323971E8F9666875CE1 4FA072ED4E0B53A6590F54136380952851484ED99C9C7EA454B88D2488548237 95F26D8E5F265ACC663E966973B0732E53BF817A99857FA15BAA967796507EBF 76F853A2957699997BB189446E584E617FD479658BE660F354CD4EAB98795DF7 6A6150CF54118C618427785D9704524A54EE56A395006D885BB56DC666530000 D0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005C0F5B5D6821809655787B11654869544E9B6B47874E978B534F631F643A 90AA659C80C18C10519968B0537887F961C86CC46CFB8C225C5185AA82AF950C 6B238F9B65B05FFB5FC34FE18845661F8165732960FA51745211578B5F6290A2 884C91925E78674F602759D3514451F680F853086C7996C4718A4F114FEE7F9E 673D55C5950879C088967EE3589F620C9700865A5618987B5F908BB884C49157 53D965ED5E8F755C60647D6E5A7F7EEA7EED8F6955A75BA360AC65CB73840000 D1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009009766377297EDA9774859B5B667A7496EA884052CB718F5FAA65EC8BE2 5BFB9A6F5DE16B896C5B8BAD8BAF900A8FC5538B62BC9E269E2D54404E2B82BD 7259869C5D1688596DAF96C554D14E9A8BB6710954BD960970DF6DF976D04E25 781487125CA95EF68A00989C960E708E6CBF594463A9773C884D6F1482735830 71D5538C781A96C155015F6671305BB48C1A9A8C6B83592E9E2F79E76768626C 4F6F75A17F8A6D0B96336C274EF075D2517B68376F3E90808170599674760000 D2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000064475C2790657A918C2359DA54AC8200836F898180006930564E80367237 91CE51B64E5F987563964E1A53F666F3814B591C6DB24E0058F9533B63D694F1 4F9D4F0A886398905937905779FB4EEA80F075916C825B9C59E85F5D69058681 501A5DF24E5977E34EE5827A6291661390915C794EBF5F7981C69038808475AB 4EA688D4610F6BC55FC64E4976CA6EA28BE38BAE8C0A8BD15F027FFC7FCC7ECE 8335836B56E06BB797F3963459FB541F94F66DEB5BC5996E5C395F1596900000 D3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000537082F16A315A749E705E947F2883B984248425836787478FCE8D6276C8 5F719896786C662054DF62E54F6381C375C85EB896CD8E0A86F9548F6CF36D8C 6C38607F52C775285E7D4F1860A05FE75C24753190AE94C072B96CB96E389149 670953CB53F34F5191C98BF153C85E7C8FC26DE44E8E76C26986865E611A8206 4F594FDE903E9C7C61096E1D6E1496854E885A3196E84E0E5C7F79B95B878BED 7FBD738957DF828B90C15401904755BB5CEA5FA161086B3272F180B28A890000 D4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006D745BD388D598848C6B9A6D9E336E0A51A4514357A38881539F63F48F95 56ED54585706733F6E907F188FDC82D1613F6028966266F07EA68D8A8DC394A5 5CB37CA4670860A6960580184E9190E75300966851418FD08574915D665597F5 5B55531D78386742683D54C9707E5BB08F7D518D572854B1651266828D5E8D43 810F846C906D7CDF51FF85FB67A365E96FA186A48E81566A90207682707671E5 8D2362E952196CFD8D3C600E589E618E66FE8D60624E55B36E23672D8F670000 D5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000094E195F87728680569A8548B4E4D70B88BC86458658B5B857A84503A5BE8 77BB6BE18A797C986CBE76CF65A98F975D2D5C5586386808536062187AD96E5B 7EFD6A1F7AE05F706F335F20638C6DA867564E085E108D264ED780C07634969C 62DB662D627E6CBC8D7571677F695146808753EC906E629854F286F08F998005 951785178FD96D5973CD659F771F7504782781FB8D1E94884FA6679575B98BCA 9707632F9547963584B8632377415F8172F04E896014657462EF6B63653F0000 D6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005E2775C790D18BC1829D679D652F5431871877E580A281026C414E4B7EC7 804C76F4690D6B966267503C4F84574063076B628DBE53EA65E87EB85FD7631A 63B781F381F47F6E5E1C5CD95236667A79E97A1A8D28709975D46EDE6CBB7A92 4E2D76C55FE0949F88777EC879CD80BF91CD4EF24F17821F54685DDE6D328BCC 7CA58F7480985E1A549276B15B99663C9AA473E0682A86DB6731732A8BF88BDB 90107AF970DB716E62C477A956314E3B845767F152A986C08D2E94F87B510000 D7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00004F4F6CE8795D9A7B6293722A62FD4E1378168F6C64B08D5A7BC668695E84 88C55986649E58EE72B6690E95258FFD8D5857607F008C0651C6634962D95353 684C74228301914C55447740707C6D4A517954A88D4459FF6ECB6DC45B5C7D2B 4ED47C7D6ED35B5081EA6E0D5B579B0368D58E2A5B977EFC603B7EB590B98D70 594F63CD79DF8DB3535265CF79568BC5963B7EC494BB7E825634918967007F6A 5C0A907566285DE64F5067DE505A4F5C57505EA7000000000000000000000000 D8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00004E8D4E0C51404E105EFF53454E154E984E1E9B325B6C56694E2879BA4E3F 53154E47592D723B536E6C1056DF80E499976BD3777E9F174E364E9F9F104E5C 4E694E9382885B5B556C560F4EC4538D539D53A353A553AE97658D5D531A53F5 5326532E533E8D5C5366536352025208520E522D5233523F5240524C525E5261 525C84AF527D528252815290529351827F544EBB4EC34EC94EC24EE84EE14EEB 4EDE4F1B4EF34F224F644EF54F254F274F094F2B4F5E4F6765384F5A4F5D0000 D9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00004F5F4F574F324F3D4F764F744F914F894F834F8F4F7E4F7B4FAA4F7C4FAC 4F944FE64FE84FEA4FC54FDA4FE34FDC4FD14FDF4FF85029504C4FF3502C500F 502E502D4FFE501C500C50255028507E504350555048504E506C507B50A550A7 50A950BA50D6510650ED50EC50E650EE5107510B4EDD6C3D4F584F654FCE9FA0 6C467C74516E5DFD9EC999985181591452F9530D8A07531051EB591951554EA0 51564EB3886E88A44EB5811488D279805B3488037FB851AB51B151BD51BC0000 DA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000051C7519651A251A58BA08BA68BA78BAA8BB48BB58BB78BC28BC38BCB8BCF 8BCE8BD28BD38BD48BD68BD88BD98BDC8BDF8BE08BE48BE88BE98BEE8BF08BF3 8BF68BF98BFC8BFF8C008C028C048C078C0C8C0F8C118C128C148C158C168C19 8C1B8C188C1D8C1F8C208C218C258C278C2A8C2B8C2E8C2F8C328C338C358C36 5369537A961D962296219631962A963D963C964296499654965F9667966C9672 96749688968D969796B09097909B909D909990AC90A190B490B390B690BA0000 DB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000090B890B090CF90C590BE90D090C490C790D390E690E290DC90D790DB90EB 90EF90FE91049122911E91239131912F913991439146520D594252A252AC52AD 52BE54FF52D052D652F053DF71EE77CD5EF451F551FC9B2F53B65F01755A5DEF 574C57A957A1587E58BC58C558D15729572C572A57335739572E572F575C573B 574257695785576B5786577C577B5768576D5776577357AD57A4578C57B257CF 57A757B4579357A057D557D857DA57D957D257B857F457EF57F857E457DD0000 DC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000580B580D57FD57ED5800581E5819584458205865586C58815889589A5880 99A89F1961FF8279827D827F828F828A82A88284828E82918297829982AB82B8 82BE82B082C882CA82E3829882B782AE82CB82CC82C182A982B482A182AA829F 82C482CE82A482E1830982F782E4830F830782DC82F482D282D8830C82FB82D3 8311831A83068314831582E082D5831C8351835B835C83088392833C83348331 839B835E832F834F83478343835F834083178360832D833A8333836683650000 DD 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008368831B8369836C836A836D836E83B0837883B383B483A083AA8393839C 8385837C83B683A9837D83B8837B8398839E83A883BA83BC83C1840183E583D8 58078418840B83DD83FD83D6841C84388411840683D483DF840F840383F883F9 83EA83C583C0842683F083E1845C8451845A8459847384878488847A84898478 843C844684698476848C848E8431846D84C184CD84D084E684BD84D384CA84BF 84BA84E084A184B984B4849784E584E3850C750D853884F08539851F853A0000 DE 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008556853B84FF84FC8559854885688564855E857A77A285438572857B85A4 85A88587858F857985AE859C858585B985B785B085D385C185DC85FF86278605 86298616863C5EFE5F08593C594180375955595A5958530F5C225C255C2C5C34 624C626A629F62BB62CA62DA62D762EE632262F66339634B634363AD63F66371 637A638E63B4636D63AC638A636963AE63BC63F263F863E063FF63C463DE63CE 645263C663BE64456441640B641B6420640C64266421645E6484646D64960000 DF 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000647A64B764B8649964BA64C064D064D764E464E265096525652E5F0B5FD2 75195F11535F53F153FD53E953E853FB541254165406544B5452545354545456 54435421545754595423543254825494547754715464549A549B548454765466 549D54D054AD54C254B454D254A754A654D354D4547254A354D554BB54BF54CC 54D954DA54DC54A954AA54A454DD54CF54DE551B54E7552054FD551454F35522 5523550F55115527552A5567558F55B55549556D55415555553F5550553C0000 E0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005537555655755576557755335530555C558B55D2558355B155B955885581 559F557E55D65591557B55DF55BD55BE5594559955EA55F755C9561F55D155EB 55EC55D455E655DD55C455EF55E555F255F355CC55CD55E855F555E48F94561E 5608560C56015624562355FE56005627562D565856395657562C564D56625659 565C564C5654568656645671566B567B567C5685569356AF56D456D756DD56E1 56F556EB56F956FF5704570A5709571C5E0F5E195E145E115E315E3B5E3C0000 E1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005E375E445E545E5B5E5E5E615C8C5C7A5C8D5C905C965C885C985C995C91 5C9A5C9C5CB55CA25CBD5CAC5CAB5CB15CA35CC15CB75CC45CD25CE45CCB5CE5 5D025D035D275D265D2E5D245D1E5D065D1B5D585D3E5D345D3D5D6C5D5B5D6F 5D5D5D6B5D4B5D4A5D695D745D825D995D9D8C735DB75DC55F735F775F825F87 5F895F8C5F955F995F9C5FA85FAD5FB55FBC88625F6172AD72B072B472B772B8 72C372C172CE72CD72D272E872EF72E972F272F472F7730172F3730372FA0000 E2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000072FB731773137321730A731E731D7315732273397325732C733873317350 734D73577360736C736F737E821B592598E7592459029963996799689969996A 996B996C99749977997D998099849987998A998D999099919993999499955E80 5E915E8B5E965EA55EA05EB95EB55EBE5EB38D535ED25ED15EDB5EE85EEA81BA 5FC45FC95FD65FCF60035FEE60045FE15FE45FFE600560065FEA5FED5FF86019 60356026601B600F600D6029602B600A603F602160786079607B607A60420000 E3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000606A607D6096609A60AD609D60836092608C609B60EC60BB60B160DD60D8 60C660DA60B4612061266115612360F46100610E612B614A617561AC619461A7 61B761D461F55FDD96B395E995EB95F195F395F595F695FC95FE960396049606 9608960A960B960C960D960F96129615961696179619961A4E2C723F62156C35 6C546C5C6C4A6CA36C856C906C946C8C6C686C696C746C766C866CA96CD06CD4 6CAD6CF76CF86CF16CD76CB26CE06CD66CFA6CEB6CEE6CB16CD36CEF6CFE0000 E4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006D396D276D0C6D436D486D076D046D196D0E6D2B6D4D6D2E6D356D1A6D4F 6D526D546D336D916D6F6D9E6DA06D5E6D936D946D5C6D606D7C6D636E1A6DC7 6DC56DDE6E0E6DBF6DE06E116DE66DDD6DD96E166DAB6E0C6DAE6E2B6E6E6E4E 6E6B6EB26E5F6E866E536E546E326E256E446EDF6EB16E986EE06F2D6EE26EA5 6EA76EBD6EBB6EB76ED76EB46ECF6E8F6EC26E9F6F626F466F476F246F156EF9 6F2F6F366F4B6F746F2A6F096F296F896F8D6F8C6F786F726F7C6F7A6FD10000 E5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006FC96FA76FB96FB66FC26FE16FEE6FDE6FE06FEF701A7023701B70397035 704F705E5B805B845B955B935BA55BB8752F9A9E64345BE45BEE89305BF08E47 8B078FB68FD38FD58FE58FEE8FE48FE98FE68FF38FE890059004900B90269011 900D9016902190359036902D902F9044905190529050906890589062905B66B9 9074907D908290889083908B5F505F575F565F585C3B54AB5C505C595B715C63 5C667FBC5F2A5F295F2D82745F3C9B3B5C6E59815983598D59A959AA59A30000 E6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000599759CA59AB599E59A459D259B259AF59D759BE5A055A0659DD5A0859E3 59D859F95A0C5A095A325A345A115A235A135A405A675A4A5A555A3C5A625A75 80EC5AAA5A9B5A775A7A5ABE5AEB5AB25AD25AD45AB85AE05AE35AF15AD65AE6 5AD85ADC5B095B175B165B325B375B405C155C1C5B5A5B655B735B515B535B62 9A759A779A789A7A9A7F9A7D9A809A819A859A889A8A9A909A929A939A969A98 9A9B9A9C9A9D9A9F9AA09AA29AA39AA59AA77E9F7EA17EA37EA57EA87EA90000 E7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007EAD7EB07EBE7EC07EC17EC27EC97ECB7ECC7ED07ED47ED77EDB7EE07EE1 7EE87EEB7EEE7EEF7EF17EF27F0D7EF67EFA7EFB7EFE7F017F027F037F077F08 7F0B7F0C7F0F7F117F127F177F197F1C7F1B7F1F7F217F227F237F247F257F26 7F277F2A7F2B7F2C7F2D7F2F7F307F317F327F337F355E7A757F5DDB753E9095 738E739173AE73A2739F73CF73C273D173B773B373C073C973C873E573D9987C 740A73E973E773DE73BA73F2740F742A745B7426742574287430742E742C0000 E8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000741B741A7441745C7457745574597477746D747E749C748E748074817487 748B749E74A874A9749074A774D274BA97EA97EB97EC674C6753675E67486769 67A56787676A6773679867A7677567A8679E67AD678B6777677C67F0680967D8 680A67E967B0680C67D967B567DA67B367DD680067C367B867E2680E67C167FD 6832683368606861684E6862684468646883681D68556866684168676840683E 684A6849682968B5688F687468776893686B68C2696E68FC691F692068F90000 E9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000692468F0690B6901695768E369106971693969606942695D6984696B6980 69986978693469CC6987698869CE6989696669636979699B69A769BB69AB69AD 69D469B169C169CA69DF699569E0698D69FF6A2F69ED6A176A186A6569F26A44 6A3E6AA06A506A5B6A356A8E6A796A3D6A286A586A7C6A916A906AA96A976AAB 733773526B816B826B876B846B926B936B8D6B9A6B9B6BA16BAA8F6B8F6D8F71 8F728F738F758F768F788F778F798F7A8F7C8F7E8F818F828F848F878F8B0000 EA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008F8D8F8E8F8F8F988F9A8ECE620B6217621B621F6222622162256224622C 81E774EF74F474FF750F75117513653465EE65EF65F0660A6619677266036615 6600708566F7661D66346631663666358006665F66546641664F665666616657 66776684668C66A7669D66BE66DB66DC66E666E98D328D338D368D3B8D3D8D40 8D458D468D488D498D478D4D8D558D5989C789CA89CB89CC89CE89CF89D089D1 726E729F725D7266726F727E727F7284728B728D728F72926308633263B00000 EB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000643F64D880046BEA6BF36BFD6BF56BF96C056C076C066C0D6C156C186C19 6C1A6C216C296C246C2A6C3265356555656B724D72527256723086625216809F 809C809380BC670A80BD80B180AB80AD80B480B780E780E880E980EA80DB80C2 80C480D980CD80D7671080DD80EB80F180F480ED810D810E80F280FC67158112 8C5A8136811E812C811881328148814C815381748159815A817181608169817C 817D816D8167584D5AB58188818281916ED581A381AA81CC672681CA81BB0000 EC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000081C181A66B246B376B396B436B466B5998D198D298D398D598D998DA6BB3 5F406BC289F365909F51659365BC65C665C465C365CC65CE65D265D67080709C 7096709D70BB70C070B770AB70B170E870CA711071137116712F71317173715C 716871457172714A7178717A719871B371B571A871A071E071D471E771F9721D 7228706C7118716671B9623E623D624362486249793B794079467949795B795C 7953795A796279577960796F7967797A7985798A799A79A779B35FD15FD00000 ED 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000603C605D605A606760416059606360AB6106610D615D61A9619D61CB61D1 62068080807F6C936CF66DFC77F677F87800780978177818781165AB782D781C 781D7839783A783B781F783C7825782C78237829784E786D7856785778267850 7847784C786A789B7893789A7887789C78A178A378B278B978A578D478D978C9 78EC78F2790578F479137924791E79349F9B9EF99EFB9EFC76F17704770D76F9 77077708771A77227719772D7726773577387750775177477743775A77680000 EE 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000077627765777F778D777D7780778C7791779F77A077B077B577BD753A7540 754E754B7548755B7572757975837F587F617F5F8A487F687F747F717F797F81 7F7E76CD76E58832948594869487948B948A948C948D948F9490949494979495 949A949B949C94A394A494AB94AA94AD94AC94AF94B094B294B494B694B794B8 94B994BA94BC94BD94BF94C494C894C994CA94CB94CC94CD94CE94D094D194D2 94D594D694D794D994D894DB94DE94DF94E094E294E494E594E794E894EA0000 EF 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000094E994EB94EE94EF94F394F494F594F794F994FC94FD94FF950395029506 95079509950A950D950E950F951295139514951595169518951B951D951E951F 9522952A952B9529952C953195329534953695379538953C953E953F95429535 9544954595469549954C954E954F9552955395549556955795589559955B955E 955F955D95619562956495659566956795689569956A956B956C956F95719572 9573953A77E777EC96C979D579ED79E379EB7A065D477A037A027A1E7A140000 F0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007A397A377A519ECF99A57A707688768E7693769976A474DE74E0752C9E20 9E229E289E299E2A9E2B9E2C9E329E319E369E389E379E399E3A9E3E9E419E42 9E449E469E479E489E499E4B9E4C9E4E9E519E559E579E5A9E5B9E5C9E5E9E63 9E669E679E689E699E6A9E6B9E6C9E719E6D9E7375927594759675A0759D75AC 75A375B375B475B875C475B175B075C375C275D675CD75E375E875E675E475EB 75E7760375F175FC75FF761076007605760C7617760A76257618761576190000 F1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000761B763C762276207640762D7630763F76357643763E7633764D765E7654 765C7656766B766F7FCA7AE67A787A797A807A867A887A957AA67AA07AAC7AA8 7AAD7AB3886488698872887D887F888288A288C688B788BC88C988E288CE88E3 88E588F1891A88FC88E888FE88F0892189198913891B890A8934892B89368941 8966897B758B80E576B276B477DC801280148016801C80208022802580268027 802980288031800B803580438046804D80528069807189839878988098830000 F2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009889988C988D988F9894989A989B989E989F98A198A298A598A6864D8654 866C866E867F867A867C867B86A8868D868B86AC869D86A786A386AA869386A9 86B686C486B586CE86B086BA86B186AF86C986CF86B486E986F186F286ED86F3 86D0871386DE86F486DF86D886D18703870786F88708870A870D87098723873B 871E8725872E871A873E87488734873187298737873F87828722877D877E877B 87608770874C876E878B87538763877C876487598765879387AF87A887D20000 F3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000087C68788878587AD8797878387AB87E587AC87B587B387CB87D387BD87D1 87C087CA87DB87EA87E087EE8816881387FE880A881B88218839883C7F367F42 7F447F4582107AFA7AFD7B087B037B047B157B0A7B2B7B0F7B477B387B2A7B19 7B2E7B317B207B257B247B337B3E7B1E7B587B5A7B457B757B4C7B5D7B607B6E 7B7B7B627B727B717B907BA67BA77BB87BAC7B9D7BA87B857BAA7B9C7BA27BAB 7BB47BD17BC17BCC7BDD7BDA7BE57BE67BEA7C0C7BFE7BFC7C0F7C167C0B0000 F4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007C1F7C2A7C267C387C417C4081FE82018202820481EC8844822182228223 822D822F8228822B8238823B82338234823E82448249824B824F825A825F8268 887E8885888888D888DF895E7F9D7F9F7FA77FAF7FB07FB27C7C65497C917C9D 7C9C7C9E7CA27CB27CBC7CBD7CC17CC77CCC7CCD7CC87CC57CD77CE8826E66A8 7FBF7FCE7FD57FE57FE17FE67FE97FEE7FF37CF87D777DA67DAE7E477E9B9EB8 9EB48D738D848D948D918DB18D678D6D8C478C49914A9150914E914F91640000 F5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009162916191709169916F917D917E917291749179918C91859190918D9191 91A291A391AA91AD91AE91AF91B591B491BA8C559E7E8DB88DEB8E058E598E69 8DB58DBF8DBC8DBA8DC48DD68DD78DDA8DDE8DCE8DCF8DDB8DC68DEC8DF78DF8 8DE38DF98DFB8DE48E098DFD8E148E1D8E1F8E2C8E2E8E238E2F8E3A8E408E39 8E358E3D8E318E498E418E428E518E528E4A8E708E768E7C8E6F8E748E858E8F 8E948E908E9C8E9E8C788C828C8A8C858C988C94659B89D689DE89DA89DC0000 F6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000089E589EB89EF8A3E8B26975396E996F396EF970697019708970F970E972A 972D9730973E9F809F839F859F869F879F889F899F8A9F8C9EFE9F0B9F0D96B9 96BC96BD96CE96D277BF96E0928E92AE92C8933E936A93CA938F943E946B9C7F 9C829C859C869C879C887A239C8B9C8E9C909C919C929C949C959C9A9C9B9C9E 9C9F9CA09CA19CA29CA39CA59CA69CA79CA89CA99CAB9CAD9CAE9CB09CB19CB2 9CB39CB49CB59CB69CB79CBA9CBB9CBC9CBD9CC49CC59CC69CC79CCA9CCB0000 F7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009CCC9CCD9CCE9CCF9CD09CD39CD49CD59CD79CD89CD99CDC9CDD9CDF9CE2 977C978597919792979497AF97AB97A397B297B49AB19AB09AB79E589AB69ABA 9ABC9AC19AC09AC59AC29ACB9ACC9AD19B459B439B479B499B489B4D9B5198E8 990D992E995599549ADF9AE19AE69AEF9AEB9AFB9AED9AF99B089B0F9B139B1F 9B239EBD9EBE7E3B9E829E879E889E8B9E9293D69E9D9E9F9EDB9EDC9EDD9EE0 9EDF9EE29EE99EE79EE59EEA9EEF9F229F2C9F2F9F399F379F3D9F3E9F440000 tcl8.4.20/library/encoding/cp863.enc0000644003604700454610000000210211737050674015476 0ustar dgp771div# Encoding file: cp863, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 00C700FC00E900E200C200E000B600E700EA00EB00E800EF00EE201700C000A7 00C900C800CA00F400CB00CF00FB00F900A400D400DC00A200A300D900DB0192 00A600B400F300FA00A800B800B300AF00CE231000AC00BD00BC00BE00AB00BB 259125922593250225242561256225562555256325512557255D255C255B2510 25142534252C251C2500253C255E255F255A25542569256625602550256C2567 2568256425652559255825522553256B256A2518250C25882584258C25902580 03B100DF039303C003A303C300B503C403A6039803A903B4221E03C603B52229 226100B1226522642320232100F7224800B0221900B7221A207F00B225A000A0 tcl8.4.20/library/encoding/dingbats.enc0000644003604700454610000000210511737050674016431 0ustar dgp771div# Encoding file: dingbats, single-byte S 003F 1 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 00202701270227032704260E2706270727082709261B261E270C270D270E270F 2710271127122713271427152716271727182719271A271B271C271D271E271F 2720272127222723272427252726272726052729272A272B272C272D272E272F 2730273127322733273427352736273727382739273A273B273C273D273E273F 2740274127422743274427452746274727482749274A274B25CF274D25A0274F 27502751275225B225BC25C6275625D727582759275A275B275C275D275E007F 0080008100820083008400850086008700880089008A008B008C008D008E008F 0090009100920093009400950096009700980099009A009B009C009D009E009F 0000276127622763276427652766276726632666266526602460246124622463 2464246524662467246824692776277727782779277A277B277C277D277E277F 2780278127822783278427852786278727882789278A278B278C278D278E278F 2790279127922793279421922194219527982799279A279B279C279D279E279F 27A027A127A227A327A427A527A627A727A827A927AA27AB27AC27AD27AE27AF 000027B127B227B327B427B527B627B727B827B927BA27BB27BC27BD27BE0000 tcl8.4.20/library/encoding/cp932.enc0000644003604700454610000013611711737050674015511 0ustar dgp771div# Encoding file: cp932, multi-byte M 003F 0 46 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 0080000000000000000000850086000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FF61FF62FF63FF64FF65FF66FF67FF68FF69FF6AFF6BFF6CFF6DFF6EFF6F FF70FF71FF72FF73FF74FF75FF76FF77FF78FF79FF7AFF7BFF7CFF7DFF7EFF7F FF80FF81FF82FF83FF84FF85FF86FF87FF88FF89FF8AFF8BFF8CFF8DFF8EFF8F FF90FF91FF92FF93FF94FF95FF96FF97FF98FF99FF9AFF9BFF9CFF9DFF9EFF9F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 81 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 300030013002FF0CFF0E30FBFF1AFF1BFF1FFF01309B309C00B4FF4000A8FF3E FFE3FF3F30FD30FE309D309E30034EDD30053006300730FC20152010FF0FFF3C FF5E2225FF5C2026202520182019201C201DFF08FF0930143015FF3BFF3DFF5B FF5D30083009300A300B300C300D300E300F30103011FF0BFF0D00B100D70000 00F7FF1D2260FF1CFF1E22662267221E22342642264000B0203220332103FFE5 FF04FFE0FFE1FF05FF03FF06FF0AFF2000A72606260525CB25CF25CE25C725C6 25A125A025B325B225BD25BC203B301221922190219121933013000000000000 000000000000000000000000000000002208220B2286228722822283222A2229 0000000000000000000000000000000022272228FFE221D221D4220022030000 0000000000000000000000000000000000000000222022A52312220222072261 2252226A226B221A223D221D2235222B222C0000000000000000000000000000 212B2030266F266D266A2020202100B6000000000000000025EF000000000000 82 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000FF10 FF11FF12FF13FF14FF15FF16FF17FF18FF190000000000000000000000000000 FF21FF22FF23FF24FF25FF26FF27FF28FF29FF2AFF2BFF2CFF2DFF2EFF2FFF30 FF31FF32FF33FF34FF35FF36FF37FF38FF39FF3A000000000000000000000000 0000FF41FF42FF43FF44FF45FF46FF47FF48FF49FF4AFF4BFF4CFF4DFF4EFF4F FF50FF51FF52FF53FF54FF55FF56FF57FF58FF59FF5A00000000000000003041 30423043304430453046304730483049304A304B304C304D304E304F30503051 30523053305430553056305730583059305A305B305C305D305E305F30603061 30623063306430653066306730683069306A306B306C306D306E306F30703071 30723073307430753076307730783079307A307B307C307D307E307F30803081 30823083308430853086308730883089308A308B308C308D308E308F30903091 3092309300000000000000000000000000000000000000000000000000000000 83 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 30A130A230A330A430A530A630A730A830A930AA30AB30AC30AD30AE30AF30B0 30B130B230B330B430B530B630B730B830B930BA30BB30BC30BD30BE30BF30C0 30C130C230C330C430C530C630C730C830C930CA30CB30CC30CD30CE30CF30D0 30D130D230D330D430D530D630D730D830D930DA30DB30DC30DD30DE30DF0000 30E030E130E230E330E430E530E630E730E830E930EA30EB30EC30ED30EE30EF 30F030F130F230F330F430F530F6000000000000000000000000000000000391 03920393039403950396039703980399039A039B039C039D039E039F03A003A1 03A303A403A503A603A703A803A90000000000000000000000000000000003B1 03B203B303B403B503B603B703B803B903BA03BB03BC03BD03BE03BF03C003C1 03C303C403C503C603C703C803C9000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 84 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 04100411041204130414041504010416041704180419041A041B041C041D041E 041F0420042104220423042404250426042704280429042A042B042C042D042E 042F000000000000000000000000000000000000000000000000000000000000 04300431043204330434043504510436043704380439043A043B043C043D0000 043E043F0440044104420443044404450446044704480449044A044B044C044D 044E044F00000000000000000000000000000000000000000000000000002500 2502250C251025182514251C252C25242534253C25012503250F2513251B2517 25232533252B253B254B2520252F25282537253F251D25302525253825420000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 87 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 2460246124622463246424652466246724682469246A246B246C246D246E246F 2470247124722473216021612162216321642165216621672168216900003349 33143322334D331833273303333633513357330D33263323332B334A333B339C 339D339E338E338F33C433A100000000000000000000000000000000337B0000 301D301F211633CD212132A432A532A632A732A8323132323239337E337D337C 22522261222B222E2211221A22A52220221F22BF22352229222A000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 88 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000004E9C 55165A03963F54C0611B632859F690228475831C7A5060AA63E16E2565ED8466 82A69BF56893572765A162715B9B59D0867B98F47D627DBE9B8E62167C9F88B7 5B895EB563096697684895C7978D674F4EE54F0A4F4D4F9D504956F2593759D4 5A015C0960DF610F61706613690570BA754F757079FB7DAD7DEF80C3840E8863 8B029055907A533B4E954EA557DF80B290C178EF4E0058F16EA290387A328328 828B9C2F5141537054BD54E156E059FB5F1598F26DEB80E4852D000000000000 89 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 9662967096A097FB540B53F35B8770CF7FBD8FC296E8536F9D5C7ABA4E117893 81FC6E26561855046B1D851A9C3B59E553A96D6674DC958F56424E91904B96F2 834F990C53E155B65B305F71662066F368046C386CF36D29745B76C87A4E9834 82F1885B8A6092ED6DB275AB76CA99C560A68B018D8A95B2698E53AD51860000 5712583059445BB45EF6602863A963F46CBF6F14708E7114715971D5733F7E01 827682D185979060925B9D1B586965BC6C5A752551F9592E59655F805FDC62BC 65FA6A2A6B276BB4738B7FC189569D2C9D0E9EC45CA16C96837B51045C4B61B6 81C6687672614E594FFA537860696E297A4F97F34E0B53164EEE4F554F3D4FA1 4F7352A053EF5609590F5AC15BB65BE179D16687679C67B66B4C6CB3706B73C2 798D79BE7A3C7B8782B182DB8304837783EF83D387668AB256298CA88FE6904E 971E868A4FC45CE862117259753B81E582BD86FE8CC096C5991399D54ECB4F1A 89E356DE584A58CA5EFB5FEB602A6094606261D0621262D06539000000000000 8A 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 9B41666668B06D777070754C76867D7582A587F9958B968E8C9D51F152BE5916 54B35BB35D16616869826DAF788D84CB88578A7293A79AB86D6C99A886D957A3 67FF86CE920E5283568754045ED362E164B9683C68386BBB737278BA7A6B899A 89D28D6B8F0390ED95A3969497695B665CB3697D984D984E639B7B206A2B0000 6A7F68B69C0D6F5F5272559D607062EC6D3B6E076ED1845B89108F444E149C39 53F6691B6A3A9784682A515C7AC384B291DC938C565B9D286822830584317CA5 520882C574E64E7E4F8351A05BD2520A52D852E75DFB559A582A59E65B8C5B98 5BDB5E725E7960A3611F616361BE63DB656267D1685368FA6B3E6B536C576F22 6F976F4574B0751876E3770B7AFF7BA17C217DE97F367FF0809D8266839E89B3 8ACC8CAB908494519593959195A2966597D3992882184E38542B5CB85DCC73A9 764C773C5CA97FEB8D0B96C19811985498584F014F0E5371559C566857FA5947 5B095BC45C905E0C5E7E5FCC63EE673A65D765E2671F68CB68C4000000000000 8B 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6A5F5E306BC56C176C7D757F79485B637A007D005FBD898F8A188CB48D778ECC 8F1D98E29A0E9B3C4E80507D510059935B9C622F628064EC6B3A72A075917947 7FA987FB8ABC8B7063AC83CA97A05409540355AB68546A588A70782767759ECD 53745BA2811A865090064E184E454EC74F1153CA54385BAE5F13602565510000 673D6C426C726CE3707874037A767AAE7B087D1A7CFE7D6665E7725B53BB5C45 5DE862D262E063196E20865A8A318DDD92F86F0179A69B5A4EA84EAB4EAC4F9B 4FA050D151477AF6517151F653545321537F53EB55AC58835CE15F375F4A602F 6050606D631F65596A4B6CC172C272ED77EF80F881058208854E90F793E197FF 99579A5A4EF051DD5C2D6681696D5C4066F26975738968507C8150C552E45747 5DFE932665A46B236B3D7434798179BD7B4B7DCA82B983CC887F895F8B398FD1 91D1541F92804E5D503653E5533A72D7739677E982E68EAF99C699C899D25177 611A865E55B07A7A50765BD3904796854E326ADB91E75C515C48000000000000 8C 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 63987A9F6C9397748F617AAA718A96887C8268177E706851936C52F2541B85AB 8A137FA48ECD90E15366888879414FC250BE521151445553572D73EA578B5951 5F625F8460756176616761A963B2643A656C666F68426E1375667A3D7CFB7D4C 7D997E4B7F6B830E834A86CD8A088A638B668EFD981A9D8F82B88FCE9BE80000 5287621F64836FC09699684150916B206C7A6F547A747D5088408A2367084EF6 503950265065517C5238526355A7570F58055ACC5EFA61B261F862F36372691C 6A29727D72AC732E7814786F7D79770C80A9898B8B198CE28ED290639375967A 98559A139E785143539F53B35E7B5F266E1B6E90738473FE7D4382378A008AFA 96504E4E500B53E4547C56FA59D15B645DF15EAB5F276238654567AF6E5672D0 7CCA88B480A180E183F0864E8A878DE8923796C798679F134E944E924F0D5348 5449543E5A2F5F8C5FA1609F68A76A8E745A78818A9E8AA48B7791904E5E9BC9 4EA44F7C4FAF501950165149516C529F52B952FE539A53E35411000000000000 8D 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 540E5589575157A2597D5B545B5D5B8F5DE55DE75DF75E785E835E9A5EB75F18 6052614C629762D863A7653B6602664366F4676D6821689769CB6C5F6D2A6D69 6E2F6E9D75327687786C7A3F7CE07D057D187D5E7DB18015800380AF80B18154 818F822A8352884C88618B1B8CA28CFC90CA91759271783F92FC95A4964D0000 980599999AD89D3B525B52AB53F7540858D562F76FE08C6A8F5F9EB9514B523B 544A56FD7A4091779D609ED273446F09817075115FFD60DA9AA872DB8FBC6B64 98034ECA56F0576458BE5A5A606861C7660F6606683968B16DF775D57D3A826E 9B424E9B4F5053C955065D6F5DE65DEE67FB6C99747378028A50939688DF5750 5EA7632B50B550AC518D670054C9585E59BB5BB05F69624D63A1683D6B736E08 707D91C7728078157826796D658E7D3083DC88C18F09969B5264572867507F6A 8CA151B45742962A583A698A80B454B25D0E57FC78959DFA4F5C524A548B643E 6628671467F57A847B567D22932F685C9BAD7B395319518A5237000000000000 8E 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5BDF62F664AE64E6672D6BBA85A996D176909BD6634C93069BAB76BF66524E09 509853C25C7160E864926563685F71E673CA75237B977E8286958B838CDB9178 991065AC66AB6B8B4ED54ED44F3A4F7F523A53F853F255E356DB58EB59CB59C9 59FF5B505C4D5E025E2B5FD7601D6307652F5B5C65AF65BD65E8679D6B620000 6B7B6C0F7345794979C17CF87D197D2B80A2810281F389968A5E8A698A668A8C 8AEE8CC78CDC96CC98FC6B6F4E8B4F3C4F8D51505B575BFA6148630166426B21 6ECB6CBB723E74BD75D478C1793A800C803381EA84948F9E6C509E7F5F0F8B58 9D2B7AFA8EF85B8D96EB4E0353F157F759315AC95BA460896E7F6F0675BE8CEA 5B9F85007BE0507267F4829D5C61854A7E1E820E51995C0463688D66659C716E 793E7D1780058B1D8ECA906E86C790AA501F52FA5C3A6753707C7235914C91C8 932B82E55BC25F3160F94E3B53D65B88624B67316B8A72E973E07A2E816B8DA3 91529996511253D7546A5BFF63886A397DAC970056DA53CE5468000000000000 8F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5B975C315DDE4FEE610162FE6D3279C079CB7D427E4D7FD281ED821F84908846 89728B908E748F2F9031914B916C96C6919C4EC04F4F514553415F93620E67D4 6C416E0B73637E2691CD928353D459195BBF6DD1795D7E2E7C9B587E719F51FA 88538FF04FCA5CFB662577AC7AE3821C99FF51C65FAA65EC696F6B896DF30000 6E966F6476FE7D145DE190759187980651E6521D6240669166D96E1A5EB67DD2 7F7266F885AF85F78AF852A953D959735E8F5F90605592E4966450B7511F52DD 5320534753EC54E8554655315617596859BE5A3C5BB55C065C0F5C115C1A5E84 5E8A5EE05F70627F628462DB638C63776607660C662D6676677E68A26A1F6A35 6CBC6D886E096E58713C7126716775C77701785D7901796579F07AE07B117CA7 7D39809683D6848B8549885D88F38A1F8A3C8A548A738C618CDE91A49266937E 9418969C97984E0A4E084E1E4E575197527057CE583458CC5B225E3860C564FE 676167566D4472B675737A6384B88B7291B89320563157F498FE000000000000 90 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 62ED690D6B9671ED7E548077827289E698DF87558FB15C3B4F384FE14FB55507 5A205BDD5BE95FC3614E632F65B0664B68EE699B6D786DF1753375B9771F795E 79E67D3381E382AF85AA89AA8A3A8EAB8F9B903291DD97074EBA4EC152035875 58EC5C0B751A5C3D814E8A0A8FC59663976D7B258ACF9808916256F353A80000 9017543957825E2563A86C34708A77617C8B7FE088709042915493109318968F 745E9AC45D075D69657067A28DA896DB636E6749691983C5981796C088FE6F84 647A5BF84E16702C755D662F51C4523652E259D35F8160276210653F6574661F 667468F268166B636E057272751F76DB7CBE805658F088FD897F8AA08A938ACB 901D91929752975965897A0E810696BB5E2D60DC621A65A56614679077F37A4D 7C4D7E3E810A8CAC8D648DE18E5F78A9520762D963A5644262988A2D7A837BC0 8AAC96EA7D76820C87494ED95148534353605BA35C025C165DDD6226624764B0 681368346CC96D456D1767D36F5C714E717D65CB7A7F7BAD7DDA000000000000 91 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7E4A7FA8817A821B823985A68A6E8CCE8DF59078907792AD929195839BAE524D 55846F387136516879857E5581B37CCE564C58515CA863AA66FE66FD695A72D9 758F758E790E795679DF7C977D207D4486078A34963B90619F2050E7527553CC 53E2500955AA58EE594F723D5B8B5C64531D60E360F3635C6383633F63BB0000 64CD65E966F95DE369CD69FD6F1571E54E8975E976F87A937CDF7DCF7D9C8061 83498358846C84BC85FB88C58D709001906D9397971C9A1250CF5897618E81D3 85358D0890204FC3507452475373606F6349675F6E2C8DB3901F4FD75C5E8CCA 65CF7D9A53528896517663C35B585B6B5C0A640D6751905C4ED6591A592A6C70 8A51553E581559A560F0625367C182356955964099C49A284F5358065BFE8010 5CB15E2F5F856020614B623466FF6CF06EDE80CE817F82D4888B8CB89000902E 968A9EDB9BDB4EE353F059277B2C918D984C9DF96EDD7027535355445B856258 629E62D36CA26FEF74228A1794386FC18AFE833851E786F853EA000000000000 92 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 53E94F4690548FB0596A81315DFD7AEA8FBF68DA8C3772F89C486A3D8AB04E39 53585606576662C563A265E66B4E6DE16E5B70AD77ED7AEF7BAA7DBB803D80C6 86CB8A95935B56E358C75F3E65AD66966A806BB575378AC7502477E557305F1B 6065667A6C6075F47A1A7F6E81F48718904599B37BC9755C7AF97B5184C40000 901079E97A9283365AE177404E2D4EF25B995FE062BD663C67F16CE8866B8877 8A3B914E92F399D06A177026732A82E784578CAF4E01514651CB558B5BF55E16 5E335E815F145F355F6B5FB461F2631166A2671D6F6E7252753A773A80748139 817887768ABF8ADC8D858DF3929A957798029CE552C5635776F467156C8873CD 8CC393AE96736D25589C690E69CC8FFD939A75DB901A585A680263B469FB4F43 6F2C67D88FBB85267DB49354693F6F70576A58F75B2C7D2C722A540A91E39DB4 4EAD4F4E505C507552438C9E544858245B9A5E1D5E955EAD5EF75F1F608C62B5 633A63D068AF6C407887798E7A0B7DE082478A028AE68E449013000000000000 93 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 90B8912D91D89F0E6CE5645864E265756EF476847B1B906993D16EBA54F25FB9 64A48F4D8FED92445178586B59295C555E976DFB7E8F751C8CBC8EE2985B70B9 4F1D6BBF6FB1753096FB514E54105835585759AC5C605F926597675C6E21767B 83DF8CED901490FD934D7825783A52AA5EA6571F597460125012515A51AC0000 51CD520055105854585859575B955CF65D8B60BC6295642D6771684368BC68DF 76D76DD86E6F6D9B706F71C85F5375D879777B497B547B527CD67D7152308463 856985E48A0E8B048C468E0F9003900F94199676982D9A3095D850CD52D5540C 58025C0E61A7649E6D1E77B37AE580F48404905392855CE09D07533F5F975FB3 6D9C7279776379BF7BE46BD272EC8AAD68036A6151F87A8169345C4A9CF682EB 5BC59149701E56785C6F60C765666C8C8C5A90419813545166C7920D594890A3 51854E4D51EA85998B0E7058637A934B696299B47E047577535769608EDF96E3 6C5D4E8C5C3C5F108FE953028CD1808986795EFF65E54E735165000000000000 94 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 59825C3F97EE4EFB598A5FCD8A8D6FE179B079625BE78471732B71B15E745FF5 637B649A71C37C984E435EFC4E4B57DC56A260A96FC37D0D80FD813381BF8FB2 899786A45DF4628A64AD898767776CE26D3E743678345A467F7582AD99AC4FF3 5EC362DD63926557676F76C3724C80CC80BA8F29914D500D57F95A9268850000 6973716472FD8CB758F28CE0966A9019877F79E477E784294F2F5265535A62CD 67CF6CCA767D7B947C95823685848FEB66DD6F2072067E1B83AB99C19EA651FD 7BB178727BB880877B486AE85E61808C75517560516B92626E8C767A91979AEA 4F107F70629C7B4F95A59CE9567A585986E496BC4F345224534A53CD53DB5E06 642C6591677F6C3E6C4E724872AF73ED75547E41822C85E98CA97BC491C67169 981298EF633D6669756A76E478D0854386EE532A5351542659835E875F7C60B2 6249627962AB65906BD46CCC75B276AE789179D87DCB7F7780A588AB8AB98CBB 907F975E98DB6A0B7C3850995C3E5FAE67876BD8743577097F8E000000000000 95 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 9F3B67CA7A175339758B9AED5F66819D83F180985F3C5FC575627B46903C6867 59EB5A9B7D10767E8B2C4FF55F6A6A196C376F0274E2796888688A558C795EDF 63CF75C579D282D7932892F2849C86ED9C2D54C15F6C658C6D5C70158CA78CD3 983B654F74F64E0D4ED857E0592B5A665BCC51A85E035E9C6016627665770000 65A7666E6D6E72367B268150819A82998B5C8CA08CE68D74961C96444FAE64AB 6B66821E8461856A90E85C01695398A8847A85574F0F526F5FA95E45670D798F 8179890789866DF55F1762556CB84ECF72699B925206543B567458B361A4626E 711A596E7C897CDE7D1B96F06587805E4E194F75517558405E635E735F0A67C4 4E26853D9589965B7C73980150FB58C1765678A7522577A585117B86504F5909 72477BC77DE88FBA8FD4904D4FBF52C95A295F0197AD4FDD821792EA57036355 6B69752B88DC8F147A4252DF58936155620A66AE6BCD7C3F83E950234FF85305 5446583159495B9D5CF05CEF5D295E9662B16367653E65B9670B000000000000 96 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6CD56CE170F978327E2B80DE82B3840C84EC870289128A2A8C4A90A692D298FD 9CF39D6C4E4F4EA1508D5256574A59A85E3D5FD85FD9623F66B4671B67D068D2 51927D2180AA81A88B008C8C8CBF927E96325420982C531750D5535C58A864B2 6734726777667A4691E652C36CA16B8658005E4C5954672C7FFB51E176C60000 646978E89B549EBB57CB59B96627679A6BCE54E969D95E55819C67959BAA67FE 9C52685D4EA64FE353C862B9672B6CAB8FC44FAD7E6D9EBF4E0761626E806F2B 85135473672A9B455DF37B955CAC5BC6871C6E4A84D17A14810859997C8D6C11 772052D959227121725F77DB97279D61690B5A7F5A1851A5540D547D660E76DF 8FF792989CF459EA725D6EC5514D68C97DBF7DEC97629EBA64786A2183025984 5B5F6BDB731B76F27DB280178499513267289ED976EE676252FF99055C24623B 7C7E8CB0554F60B67D0B958053014E5F51B6591C723A803691CE5F2577E25384 5F797D0485AC8A338E8D975667F385AE9453610961086CB97652000000000000 97 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8AED8F38552F4F51512A52C753CB5BA55E7D60A0618263D6670967DA6E676D8C 733673377531795088D58A98904A909190F596C4878D59154E884F594E0E8A89 8F3F981050AD5E7C59965BB95EB863DA63FA64C166DC694A69D86D0B6EB67194 75287AAF7F8A8000844984C989818B218E0A9065967D990A617E62916B320000 6C836D747FCC7FFC6DC07F8587BA88F8676583B1983C96F76D1B7D61843D916A 4E7153755D506B046FEB85CD862D89A75229540F5C65674E68A87406748375E2 88CF88E191CC96E296785F8B73877ACB844E63A0756552896D416E9C74097559 786B7C9296867ADC9F8D4FB6616E65C5865C4E864EAE50DA4E2151CC5BEE6599 68816DBC731F764277AD7A1C7CE7826F8AD2907C91CF96759818529B7DD1502B 539867976DCB71D0743381E88F2A96A39C579E9F746058416D997D2F985E4EE4 4F364F8B51B752B15DBA601C73B2793C82D3923496B796F6970A9E979F6266A6 6B74521752A370C888C25EC9604B61906F2371497C3E7DF4806F000000000000 98 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 84EE9023932C54429B6F6AD370898CC28DEF973252B45A415ECA5F046717697C 69946D6A6F0F726272FC7BED8001807E874B90CE516D9E937984808B93328AD6 502D548C8A716B6A8CC4810760D167A09DF24E994E989C108A6B85C185686900 6E7E789781550000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000005F0C 4E104E154E2A4E314E364E3C4E3F4E424E564E584E824E858C6B4E8A82125F0D 4E8E4E9E4E9F4EA04EA24EB04EB34EB64ECE4ECD4EC44EC64EC24ED74EDE4EED 4EDF4EF74F094F5A4F304F5B4F5D4F574F474F764F884F8F4F984F7B4F694F70 4F914F6F4F864F9651184FD44FDF4FCE4FD84FDB4FD14FDA4FD04FE44FE5501A 50285014502A502550054F1C4FF650215029502C4FFE4FEF5011500650435047 6703505550505048505A5056506C50785080509A508550B450B2000000000000 99 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 50C950CA50B350C250D650DE50E550ED50E350EE50F950F55109510151025116 51155114511A5121513A5137513C513B513F51405152514C515451627AF85169 516A516E5180518256D8518C5189518F519151935195519651A451A651A251A9 51AA51AB51B351B151B251B051B551BD51C551C951DB51E0865551E951ED0000 51F051F551FE5204520B5214520E5227522A522E52335239524F5244524B524C 525E5254526A527452695273527F527D528D529452925271528852918FA88FA7 52AC52AD52BC52B552C152CD52D752DE52E352E698ED52E052F352F552F852F9 530653087538530D5310530F5315531A5323532F533153335338534053465345 4E175349534D51D6535E5369536E5918537B53775382539653A053A653A553AE 53B053B653C37C1296D953DF66FC71EE53EE53E853ED53FA5401543D5440542C 542D543C542E54365429541D544E548F5475548E545F5471547754705492547B 5480547654845490548654C754A254B854A554AC54C454C854A8000000000000 9A 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 54AB54C254A454BE54BC54D854E554E6550F551454FD54EE54ED54FA54E25539 55405563554C552E555C55455556555755385533555D5599558054AF558A559F 557B557E5598559E55AE557C558355A9558755A855DA55C555DF55C455DC55E4 55D4561455F7561655FE55FD561B55F9564E565071DF56345636563256380000 566B5664562F566C566A56865680568A56A05694568F56A556AE56B656B456C2 56BC56C156C356C056C856CE56D156D356D756EE56F9570056FF570457095708 570B570D57135718571655C7571C572657375738574E573B5740574F576957C0 57885761577F5789579357A057B357A457AA57B057C357C657D457D257D3580A 57D657E3580B5819581D587258215862584B58706BC05852583D5879588558B9 589F58AB58BA58DE58BB58B858AE58C558D358D158D758D958D858E558DC58E4 58DF58EF58FA58F958FB58FC58FD5902590A5910591B68A65925592C592D5932 5938593E7AD259555950594E595A5958596259605967596C5969000000000000 9B 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 59785981599D4F5E4FAB59A359B259C659E859DC598D59D959DA5A255A1F5A11 5A1C5A095A1A5A405A6C5A495A355A365A625A6A5A9A5ABC5ABE5ACB5AC25ABD 5AE35AD75AE65AE95AD65AFA5AFB5B0C5B0B5B165B325AD05B2A5B365B3E5B43 5B455B405B515B555B5A5B5B5B655B695B705B735B755B7865885B7A5B800000 5B835BA65BB85BC35BC75BC95BD45BD05BE45BE65BE25BDE5BE55BEB5BF05BF6 5BF35C055C075C085C0D5C135C205C225C285C385C395C415C465C4E5C535C50 5C4F5B715C6C5C6E4E625C765C795C8C5C915C94599B5CAB5CBB5CB65CBC5CB7 5CC55CBE5CC75CD95CE95CFD5CFA5CED5D8C5CEA5D0B5D155D175D5C5D1F5D1B 5D115D145D225D1A5D195D185D4C5D525D4E5D4B5D6C5D735D765D875D845D82 5DA25D9D5DAC5DAE5DBD5D905DB75DBC5DC95DCD5DD35DD25DD65DDB5DEB5DF2 5DF55E0B5E1A5E195E115E1B5E365E375E445E435E405E4E5E575E545E5F5E62 5E645E475E755E765E7A9EBC5E7F5EA05EC15EC25EC85ED05ECF000000000000 9C 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5ED65EE35EDD5EDA5EDB5EE25EE15EE85EE95EEC5EF15EF35EF05EF45EF85EFE 5F035F095F5D5F5C5F0B5F115F165F295F2D5F385F415F485F4C5F4E5F2F5F51 5F565F575F595F615F6D5F735F775F835F825F7F5F8A5F885F915F875F9E5F99 5F985FA05FA85FAD5FBC5FD65FFB5FE45FF85FF15FDD60B35FFF602160600000 601960106029600E6031601B6015602B6026600F603A605A6041606A6077605F 604A6046604D6063604360646042606C606B60596081608D60E76083609A6084 609B60966097609260A7608B60E160B860E060D360B45FF060BD60C660B560D8 614D6115610660F660F7610060F460FA6103612160FB60F1610D610E6147613E 61286127614A613F613C612C6134613D614261446173617761586159615A616B 6174616F61656171615F615D6153617561996196618761AC6194619A618A6191 61AB61AE61CC61CA61C961F761C861C361C661BA61CB7F7961CD61E661E361F6 61FA61F461FF61FD61FC61FE620062086209620D620C6214621B000000000000 9D 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 621E6221622A622E6230623262336241624E625E6263625B62606268627C6282 6289627E62926293629662D46283629462D762D162BB62CF62FF62C664D462C8 62DC62CC62CA62C262C7629B62C9630C62EE62F163276302630862EF62F56350 633E634D641C634F6396638E638063AB637663A3638F6389639F63B5636B0000 636963BE63E963C063C663E363C963D263F663C4641664346406641364266436 651D64176428640F6467646F6476644E652A6495649364A564A9648864BC64DA 64D264C564C764BB64D864C264F164E7820964E064E162AC64E364EF652C64F6 64F464F264FA650064FD6518651C650565246523652B65346535653765366538 754B654865566555654D6558655E655D65726578658265838B8A659B659F65AB 65B765C365C665C165C465CC65D265DB65D965E065E165F16772660A660365FB 6773663566366634661C664F664466496641665E665D666466676668665F6662 667066836688668E668966846698669D66C166B966C966BE66BC000000000000 9E 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 66C466B866D666DA66E0663F66E666E966F066F566F7670F6716671E67266727 9738672E673F67366741673867376746675E67606759676367646789677067A9 677C676A678C678B67A667A1678567B767EF67B467EC67B367E967B867E467DE 67DD67E267EE67B967CE67C667E76A9C681E684668296840684D6832684E0000 68B3682B685968636877687F689F688F68AD6894689D689B68836AAE68B96874 68B568A068BA690F688D687E690168CA690868D86922692668E1690C68CD68D4 68E768D569366912690468D768E3692568F968E068EF6928692A691A69236921 68C669796977695C6978696B6954697E696E69396974693D695969306961695E 695D6981696A69B269AE69D069BF69C169D369BE69CE5BE869CA69DD69BB69C3 69A76A2E699169A0699C699569B469DE69E86A026A1B69FF6B0A69F969F269E7 6A0569B16A1E69ED6A1469EB6A0A6A126AC16A236A136A446A0C6A726A366A78 6A476A626A596A666A486A386A226A906A8D6AA06A846AA26AA3000000000000 9F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6A9786176ABB6AC36AC26AB86AB36AAC6ADE6AD16ADF6AAA6ADA6AEA6AFB6B05 86166AFA6B126B169B316B1F6B386B3776DC6B3998EE6B476B436B496B506B59 6B546B5B6B5F6B616B786B796B7F6B806B846B836B8D6B986B956B9E6BA46BAA 6BAB6BAF6BB26BB16BB36BB76BBC6BC66BCB6BD36BDF6BEC6BEB6BF36BEF0000 9EBE6C086C136C146C1B6C246C236C5E6C556C626C6A6C826C8D6C9A6C816C9B 6C7E6C686C736C926C906CC46CF16CD36CBD6CD76CC56CDD6CAE6CB16CBE6CBA 6CDB6CEF6CD96CEA6D1F884D6D366D2B6D3D6D386D196D356D336D126D0C6D63 6D936D646D5A6D796D596D8E6D956FE46D856DF96E156E0A6DB56DC76DE66DB8 6DC66DEC6DDE6DCC6DE86DD26DC56DFA6DD96DE46DD56DEA6DEE6E2D6E6E6E2E 6E196E726E5F6E3E6E236E6B6E2B6E766E4D6E1F6E436E3A6E4E6E246EFF6E1D 6E386E826EAA6E986EC96EB76ED36EBD6EAF6EC46EB26ED46ED56E8F6EA56EC2 6E9F6F416F11704C6EEC6EF86EFE6F3F6EF26F316EEF6F326ECC000000000000 E0 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6F3E6F136EF76F866F7A6F786F816F806F6F6F5B6FF36F6D6F826F7C6F586F8E 6F916FC26F666FB36FA36FA16FA46FB96FC66FAA6FDF6FD56FEC6FD46FD86FF1 6FEE6FDB7009700B6FFA70117001700F6FFE701B701A6F74701D7018701F7030 703E7032705170637099709270AF70F170AC70B870B370AE70DF70CB70DD0000 70D9710970FD711C711971657155718871667162714C7156716C718F71FB7184 719571A871AC71D771B971BE71D271C971D471CE71E071EC71E771F571FC71F9 71FF720D7210721B7228722D722C72307232723B723C723F72407246724B7258 7274727E7282728172877292729672A272A772B972B272C372C672C472CE72D2 72E272E072E172F972F7500F7317730A731C7316731D7334732F73297325733E 734E734F9ED87357736A7368737073787375737B737A73C873B373CE73BB73C0 73E573EE73DE74A27405746F742573F87432743A7455743F745F74597441745C 746974707463746A7476747E748B749E74A774CA74CF74D473F1000000000000 E1 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 74E074E374E774E974EE74F274F074F174F874F7750475037505750C750E750D 75157513751E7526752C753C7544754D754A7549755B7546755A756975647567 756B756D75787576758675877574758A758975827594759A759D75A575A375C2 75B375C375B575BD75B875BC75B175CD75CA75D275D975E375DE75FE75FF0000 75FC760175F075FA75F275F3760B760D7609761F762776207621762276247634 7630763B764776487646765C76587661766276687669766A7667766C76707672 76767678767C768076837688768B768E769676937699769A76B076B476B876B9 76BA76C276CD76D676D276DE76E176E576E776EA862F76FB7708770777047729 7724771E77257726771B773777387747775A7768776B775B7765777F777E7779 778E778B779177A0779E77B077B677B977BF77BC77BD77BB77C777CD77D777DA 77DC77E377EE77FC780C781279267820792A7845788E78747886787C789A788C 78A378B578AA78AF78D178C678CB78D478BE78BC78C578CA78EC000000000000 E2 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 78E778DA78FD78F47907791279117919792C792B794079607957795F795A7955 7953797A797F798A799D79A79F4B79AA79AE79B379B979BA79C979D579E779EC 79E179E37A087A0D7A187A197A207A1F79807A317A3B7A3E7A377A437A577A49 7A617A627A699F9D7A707A797A7D7A887A977A957A987A967AA97AC87AB00000 7AB67AC57AC47ABF90837AC77ACA7ACD7ACF7AD57AD37AD97ADA7ADD7AE17AE2 7AE67AED7AF07B027B0F7B0A7B067B337B187B197B1E7B357B287B367B507B7A 7B047B4D7B0B7B4C7B457B757B657B747B677B707B717B6C7B6E7B9D7B987B9F 7B8D7B9C7B9A7B8B7B927B8F7B5D7B997BCB7BC17BCC7BCF7BB47BC67BDD7BE9 7C117C147BE67BE57C607C007C077C137BF37BF77C177C0D7BF67C237C277C2A 7C1F7C377C2B7C3D7C4C7C437C547C4F7C407C507C587C5F7C647C567C657C6C 7C757C837C907CA47CAD7CA27CAB7CA17CA87CB37CB27CB17CAE7CB97CBD7CC0 7CC57CC27CD87CD27CDC7CE29B3B7CEF7CF27CF47CF67CFA7D06000000000000 E3 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7D027D1C7D157D0A7D457D4B7D2E7D327D3F7D357D467D737D567D4E7D727D68 7D6E7D4F7D637D937D897D5B7D8F7D7D7D9B7DBA7DAE7DA37DB57DC77DBD7DAB 7E3D7DA27DAF7DDC7DB87D9F7DB07DD87DDD7DE47DDE7DFB7DF27DE17E057E0A 7E237E217E127E317E1F7E097E0B7E227E467E667E3B7E357E397E437E370000 7E327E3A7E677E5D7E567E5E7E597E5A7E797E6A7E697E7C7E7B7E837DD57E7D 8FAE7E7F7E887E897E8C7E927E907E937E947E967E8E7E9B7E9C7F387F3A7F45 7F4C7F4D7F4E7F507F517F557F547F587F5F7F607F687F697F677F787F827F86 7F837F887F877F8C7F947F9E7F9D7F9A7FA37FAF7FB27FB97FAE7FB67FB88B71 7FC57FC67FCA7FD57FD47FE17FE67FE97FF37FF998DC80068004800B80128018 8019801C80218028803F803B804A804680528058805A805F8062806880738072 807080768079807D807F808480868085809B8093809A80AD519080AC80DB80E5 80D980DD80C480DA80D6810980EF80F1811B81298123812F814B000000000000 E4 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 968B8146813E8153815180FC8171816E81658166817481838188818A81808182 81A0819581A481A3815F819381A981B081B581BE81B881BD81C081C281BA81C9 81CD81D181D981D881C881DA81DF81E081E781FA81FB81FE8201820282058207 820A820D821082168229822B82388233824082598258825D825A825F82640000 82628268826A826B822E827182778278827E828D829282AB829F82BB82AC82E1 82E382DF82D282F482F382FA8393830382FB82F982DE830682DC830982D98335 83348316833283318340833983508345832F832B831783188385839A83AA839F 83A283968323838E8387838A837C83B58373837583A0838983A883F4841383EB 83CE83FD840383D8840B83C183F7840783E083F2840D8422842083BD84388506 83FB846D842A843C855A84848477846B84AD846E848284698446842C846F8479 843584CA846284B984BF849F84D984CD84BB84DA84D084C184C684D684A18521 84FF84F485178518852C851F8515851484FC8540856385588548000000000000 E5 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 85418602854B8555858085A485888591858A85A8856D8594859B85EA8587859C 8577857E859085C985BA85CF85B985D085D585DD85E585DC85F9860A8613860B 85FE85FA86068622861A8630863F864D4E558654865F86678671869386A386A9 86AA868B868C86B686AF86C486C686B086C9882386AB86D486DE86E986EC0000 86DF86DB86EF8712870687088700870386FB87118709870D86F9870A8734873F 8737873B87258729871A8760875F8778874C874E877487578768876E87598753 8763876A880587A2879F878287AF87CB87BD87C087D096D687AB87C487B387C7 87C687BB87EF87F287E0880F880D87FE87F687F7880E87D28811881688158822 88218831883688398827883B8844884288528859885E8862886B8881887E889E 8875887D88B5887288828897889288AE889988A2888D88A488B088BF88B188C3 88C488D488D888D988DD88F9890288FC88F488E888F28904890C890A89138943 891E8925892A892B89418944893B89368938894C891D8960895E000000000000 E6 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 89668964896D896A896F89748977897E89838988898A8993899889A189A989A6 89AC89AF89B289BA89BD89BF89C089DA89DC89DD89E789F489F88A038A168A10 8A0C8A1B8A1D8A258A368A418A5B8A528A468A488A7C8A6D8A6C8A628A858A82 8A848AA88AA18A918AA58AA68A9A8AA38AC48ACD8AC28ADA8AEB8AF38AE70000 8AE48AF18B148AE08AE28AF78ADE8ADB8B0C8B078B1A8AE18B168B108B178B20 8B3397AB8B268B2B8B3E8B288B418B4C8B4F8B4E8B498B568B5B8B5A8B6B8B5F 8B6C8B6F8B748B7D8B808B8C8B8E8B928B938B968B998B9A8C3A8C418C3F8C48 8C4C8C4E8C508C558C628C6C8C788C7A8C828C898C858C8A8C8D8C8E8C948C7C 8C98621D8CAD8CAA8CBD8CB28CB38CAE8CB68CC88CC18CE48CE38CDA8CFD8CFA 8CFB8D048D058D0A8D078D0F8D0D8D109F4E8D138CCD8D148D168D678D6D8D71 8D738D818D998DC28DBE8DBA8DCF8DDA8DD68DCC8DDB8DCB8DEA8DEB8DDF8DE3 8DFC8E088E098DFF8E1D8E1E8E108E1F8E428E358E308E348E4A000000000000 E7 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 8E478E498E4C8E508E488E598E648E608E2A8E638E558E768E728E7C8E818E87 8E858E848E8B8E8A8E938E918E948E998EAA8EA18EAC8EB08EC68EB18EBE8EC5 8EC88ECB8EDB8EE38EFC8EFB8EEB8EFE8F0A8F058F158F128F198F138F1C8F1F 8F1B8F0C8F268F338F3B8F398F458F428F3E8F4C8F498F468F4E8F578F5C0000 8F628F638F648F9C8F9F8FA38FAD8FAF8FB78FDA8FE58FE28FEA8FEF90878FF4 90058FF98FFA901190159021900D901E9016900B90279036903590398FF8904F 905090519052900E9049903E90569058905E9068906F907696A890729082907D 90819080908A9089908F90A890AF90B190B590E290E4624890DB910291129119 91329130914A9156915891639165916991739172918B9189918291A291AB91AF 91AA91B591B491BA91C091C191C991CB91D091D691DF91E191DB91FC91F591F6 921E91FF9214922C92159211925E925792459249926492489295923F924B9250 929C92969293929B925A92CF92B992B792E9930F92FA9344932E000000000000 E8 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 93199322931A9323933A9335933B935C9360937C936E935693B093AC93AD9394 93B993D693D793E893E593D893C393DD93D093C893E4941A9414941394039407 94109436942B94359421943A944194529444945B94609462945E946A92299470 94759477947D945A947C947E9481947F95829587958A95949596959895990000 95A095A895A795AD95BC95BB95B995BE95CA6FF695C395CD95CC95D595D495D6 95DC95E195E595E296219628962E962F9642964C964F964B9677965C965E965D 965F96669672966C968D96989695969796AA96A796B196B296B096B496B696B8 96B996CE96CB96C996CD894D96DC970D96D596F99704970697089713970E9711 970F971697199724972A97309739973D973E97449746974897429749975C9760 97649766976852D2976B977197799785977C9781977A9786978B978F9790979C 97A897A697A397B397B497C397C697C897CB97DC97ED9F4F97F27ADF97F697F5 980F980C9838982498219837983D9846984F984B986B986F9870000000000000 E9 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 98719874987398AA98AF98B198B698C498C398C698E998EB9903990999129914 99189921991D991E99249920992C992E993D993E9942994999459950994B9951 9952994C99559997999899A599AD99AE99BC99DF99DB99DD99D899D199ED99EE 99F199F299FB99F89A019A0F9A0599E29A199A2B9A379A459A429A409A430000 9A3E9A559A4D9A5B9A579A5F9A629A659A649A699A6B9A6A9AAD9AB09ABC9AC0 9ACF9AD19AD39AD49ADE9ADF9AE29AE39AE69AEF9AEB9AEE9AF49AF19AF79AFB 9B069B189B1A9B1F9B229B239B259B279B289B299B2A9B2E9B2F9B329B449B43 9B4F9B4D9B4E9B519B589B749B939B839B919B969B979B9F9BA09BA89BB49BC0 9BCA9BB99BC69BCF9BD19BD29BE39BE29BE49BD49BE19C3A9BF29BF19BF09C15 9C149C099C139C0C9C069C089C129C0A9C049C2E9C1B9C259C249C219C309C47 9C329C469C3E9C5A9C609C679C769C789CE79CEC9CF09D099D089CEB9D039D06 9D2A9D269DAF9D239D1F9D449D159D129D419D3F9D3E9D469D48000000000000 EA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 9D5D9D5E9D649D519D509D599D729D899D879DAB9D6F9D7A9D9A9DA49DA99DB2 9DC49DC19DBB9DB89DBA9DC69DCF9DC29DD99DD39DF89DE69DED9DEF9DFD9E1A 9E1B9E1E9E759E799E7D9E819E889E8B9E8C9E929E959E919E9D9EA59EA99EB8 9EAA9EAD97619ECC9ECE9ECF9ED09ED49EDC9EDE9EDD9EE09EE59EE89EEF0000 9EF49EF69EF79EF99EFB9EFC9EFD9F079F0876B79F159F219F2C9F3E9F4A9F52 9F549F639F5F9F609F619F669F679F6C9F6A9F779F729F769F959F9C9FA0582F 69C79059746451DC719900000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 ED 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 7E8A891C9348928884DC4FC970BB663168C892F966FB5F454E284EE14EFC4F00 4F034F394F564F924F8A4F9A4F944FCD504050224FFF501E5046507050425094 50F450D8514A5164519D51BE51EC5215529C52A652C052DB5300530753245372 539353B253DDFA0E549C548A54A954FF55865759576557AC57C857C7FA0F0000 FA10589E58B2590B5953595B595D596359A459BA5B565BC0752F5BD85BEC5C1E 5CA65CBA5CF55D275D53FA115D425D6D5DB85DB95DD05F215F345F675FB75FDE 605D6085608A60DE60D5612060F26111613761306198621362A663F56460649D 64CE654E66006615663B6609662E661E6624666566576659FA126673669966A0 66B266BF66FA670EF929676667BB685267C06801684468CFFA136968FA146998 69E26A306A6B6A466A736A7E6AE26AE46BD66C3F6C5C6C866C6F6CDA6D046D87 6D6F6D966DAC6DCF6DF86DF26DFC6E396E5C6E276E3C6EBF6F886FB56FF57005 70077028708570AB710F7104715C71467147FA1571C171FE72B1000000000000 EE 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 72BE7324FA16737773BD73C973D673E373D2740773F57426742A7429742E7462 7489749F7501756F7682769C769E769B76A6FA17774652AF7821784E7864787A 7930FA18FA19FA1A7994FA1B799B7AD17AE7FA1C7AEB7B9EFA1D7D487D5C7DB7 7DA07DD67E527F477FA1FA1E83018362837F83C783F6844884B4855385590000 856BFA1F85B0FA20FA21880788F58A128A378A798AA78ABE8ADFFA228AF68B53 8B7F8CF08CF48D128D76FA238ECFFA24FA25906790DEFA269115912791DA91D7 91DE91ED91EE91E491E592069210920A923A9240923C924E9259925192399267 92A79277927892E792D792D992D0FA2792D592E092D39325932192FBFA28931E 92FF931D93029370935793A493C693DE93F89431944594489592F9DCFA29969D 96AF9733973B9743974D974F9751975598579865FA2AFA2B9927FA2C999E9A4E 9AD99ADC9B759B729B8F9BB19BBB9C009D709D6BFA2D9E199ED1000000002170 217121722173217421752176217721782179FFE2FFE4FF07FF02000000000000 FA 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 2170217121722173217421752176217721782179216021612162216321642165 2166216721682169FFE2FFE4FF07FF0232312116212122357E8A891C93489288 84DC4FC970BB663168C892F966FB5F454E284EE14EFC4F004F034F394F564F92 4F8A4F9A4F944FCD504050224FFF501E504650705042509450F450D8514A0000 5164519D51BE51EC5215529C52A652C052DB5300530753245372539353B253DD FA0E549C548A54A954FF55865759576557AC57C857C7FA0FFA10589E58B2590B 5953595B595D596359A459BA5B565BC0752F5BD85BEC5C1E5CA65CBA5CF55D27 5D53FA115D425D6D5DB85DB95DD05F215F345F675FB75FDE605D6085608A60DE 60D5612060F26111613761306198621362A663F56460649D64CE654E66006615 663B6609662E661E6624666566576659FA126673669966A066B266BF66FA670E F929676667BB685267C06801684468CFFA136968FA14699869E26A306A6B6A46 6A736A7E6AE26AE46BD66C3F6C5C6C866C6F6CDA6D046D876D6F000000000000 FB 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6D966DAC6DCF6DF86DF26DFC6E396E5C6E276E3C6EBF6F886FB56FF570057007 7028708570AB710F7104715C71467147FA1571C171FE72B172BE7324FA167377 73BD73C973D673E373D2740773F57426742A7429742E74627489749F7501756F 7682769C769E769B76A6FA17774652AF7821784E7864787A7930FA18FA190000 FA1A7994FA1B799B7AD17AE7FA1C7AEB7B9EFA1D7D487D5C7DB77DA07DD67E52 7F477FA1FA1E83018362837F83C783F6844884B485538559856BFA1F85B0FA20 FA21880788F58A128A378A798AA78ABE8ADFFA228AF68B538B7F8CF08CF48D12 8D76FA238ECFFA24FA25906790DEFA269115912791DA91D791DE91ED91EE91E4 91E592069210920A923A9240923C924E925992519239926792A79277927892E7 92D792D992D0FA2792D592E092D39325932192FBFA28931E92FF931D93029370 935793A493C693DE93F89431944594489592F9DCFA29969D96AF9733973B9743 974D974F9751975598579865FA2AFA2B9927FA2C999E9A4E9AD9000000000000 FC 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 9ADC9B759B729B8F9BB19BBB9C009D709D6BFA2D9E199ED10000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 R 8160 301C FF5E 8161 2016 2225 817C 2212 FF0D 8191 00A2 FFE0 8192 00A3 FFE1 81CA 00AC FFE2 81BE 222a 81BF 2229 81DA 2220 81DB 22a5 81DF 2261 81E0 2252 81E3 221a 81E6 2235 81E7 222b tcl8.4.20/library/encoding/jis0201.enc0000644003604700454610000000210411737050674015725 0ustar dgp771div# Encoding file: jis0201, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D203E007F 0080008100820083008400850086008700880089008A008B008C008D008E008F 0090009100920093009400950096009700980099009A009B009C009D009E009F 0000FF61FF62FF63FF64FF65FF66FF67FF68FF69FF6AFF6BFF6CFF6DFF6EFF6F FF70FF71FF72FF73FF74FF75FF76FF77FF78FF79FF7AFF7BFF7CFF7DFF7EFF7F FF80FF81FF82FF83FF84FF85FF86FF87FF88FF89FF8AFF8BFF8CFF8DFF8EFF8F FF90FF91FF92FF93FF94FF95FF96FF97FF98FF99FF9AFF9BFF9CFF9DFF9EFF9F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 tcl8.4.20/library/encoding/cp1250.enc0000644003604700454610000000210311737050674015546 0ustar dgp771div# Encoding file: cp1250, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 20AC0081201A0083201E2026202020210088203001602039015A0164017D0179 009020182019201C201D202220132014009821220161203A015B0165017E017A 00A002C702D8014100A4010400A600A700A800A9015E00AB00AC00AD00AE017B 00B000B102DB014200B400B500B600B700B80105015F00BB013D02DD013E017C 015400C100C2010200C40139010600C7010C00C9011800CB011A00CD00CE010E 01100143014700D300D4015000D600D70158016E00DA017000DC00DD016200DF 015500E100E2010300E4013A010700E7010D00E9011900EB011B00ED00EE010F 01110144014800F300F4015100F600F70159016F00FA017100FC00FD016302D9 tcl8.4.20/library/encoding/iso8859-13.enc0000644003604700454610000000210711737050674016211 0ustar dgp771div# Encoding file: iso8859-13, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 0080008100820083008400850086008700880089008A008B008C008D008E008F 0090009100920093009400950096009700980099009A009B009C009D009E009F 00A0201D00A200A300A4201E00A600A700D800A9015600AB00AC00AD00AE00C6 00B000B100B200B3201C00B500B600B700F800B9015700BB00BC00BD00BE00E6 0104012E0100010600C400C501180112010C00C90179011601220136012A013B 01600143014500D3014C00D500D600D701720141015A016A00DC017B017D00DF 0105012F0101010700E400E501190113010D00E9017A011701230137012B013C 01610144014600F3014D00F500F600F701730142015B016B00FC017C017E2019 tcl8.4.20/library/encoding/koi8-r.enc0000644003604700454610000000210311737050674015745 0ustar dgp771div# Encoding file: koi8-r, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 25002502250C251025142518251C2524252C2534253C258025842588258C2590 259125922593232025A02219221A22482264226500A0232100B000B200B700F7 25502551255204512553255425552556255725582559255A255B255C255D255E 255F25602561040125622563256425652566256725682569256A256B256C00A9 044E0430043104460434043504440433044504380439043A043B043C043D043E 043F044F044004410442044304360432044C044B04370448044D04490447044A 042E0410041104260414041504240413042504180419041A041B041C041D041E 041F042F042004210422042304160412042C042B04170428042D04290427042A tcl8.4.20/library/encoding/symbol.enc0000644003604700454610000000210311737050674016141 0ustar dgp771div# Encoding file: symbol, single-byte S 003F 1 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002122000023220300250026220D002800292217002B002C2212002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 22450391039203A70394039503A603930397039903D1039A039B039C039D039F 03A0039803A103A303A403A503C203A9039E03A80396005B2234005D22A5005F F8E503B103B203C703B403B503C603B303B703B903D503BA03BB03BC03BD03BF 03C003B803C103C303C403C503D603C903BE03C803B6007B007C007D223C007F 0080008100820083008400850086008700880089008A008B008C008D008E008F 0090009100920093009400950096009700980099009A009B009C009D009E009F 000003D2203222642044221E0192266326662665266021942190219121922193 00B000B12033226500D7221D2202202200F72260226122482026F8E6F8E721B5 21352111211C21182297229522052229222A2283228722842282228622082209 2220220700AE00A92122220F221A22C500AC2227222821D421D021D121D221D3 22C42329F8E8F8E9F8EA2211F8EBF8ECF8EDF8EEF8EFF8F0F8F1F8F2F8F3F8F4 F8FF232A222B2320F8F52321F8F6F8F7F8F8F8F9F8FAF8FBF8FCF8FDF8FE0000 tcl8.4.20/library/encoding/cp1253.enc0000644003604700454610000000210311737050674015551 0ustar dgp771div# Encoding file: cp1253, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 20AC0081201A0192201E20262020202100882030008A2039008C008D008E008F 009020182019201C201D20222013201400982122009A203A009C009D009E009F 00A00385038600A300A400A500A600A700A800A9000000AB00AC00AD00AE2015 00B000B100B200B3038400B500B600B703880389038A00BB038C00BD038E038F 0390039103920393039403950396039703980399039A039B039C039D039E039F 03A003A1000003A303A403A503A603A703A803A903AA03AB03AC03AD03AE03AF 03B003B103B203B303B403B503B603B703B803B903BA03BB03BC03BD03BE03BF 03C003C103C203C303C403C503C603C703C803C903CA03CB03CC03CD03CE0000 tcl8.4.20/library/encoding/jis0208.enc0000644003604700454610000023511311737050674015744 0ustar dgp771div# Encoding file: jis0208, double-byte D 2129 0 77 21 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000300030013002FF0CFF0E30FBFF1AFF1BFF1FFF01309B309C00B4FF4000A8 FF3EFFE3FF3F30FD30FE309D309E30034EDD30053006300730FC20152010FF0F FF3C301C2016FF5C2026202520182019201C201DFF08FF0930143015FF3BFF3D FF5BFF5D30083009300A300B300C300D300E300F30103011FF0B221200B100D7 00F7FF1D2260FF1CFF1E22662267221E22342642264000B0203220332103FFE5 FF0400A200A3FF05FF03FF06FF0AFF2000A72606260525CB25CF25CE25C70000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 22 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000025C625A125A025B325B225BD25BC203B3012219221902191219330130000 00000000000000000000000000000000000000002208220B2286228722822283 222A2229000000000000000000000000000000002227222800AC21D221D42200 220300000000000000000000000000000000000000000000222022A523122202 220722612252226A226B221A223D221D2235222B222C00000000000000000000 00000000212B2030266F266D266A2020202100B6000000000000000025EF0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 23 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 FF10FF11FF12FF13FF14FF15FF16FF17FF18FF19000000000000000000000000 0000FF21FF22FF23FF24FF25FF26FF27FF28FF29FF2AFF2BFF2CFF2DFF2EFF2F FF30FF31FF32FF33FF34FF35FF36FF37FF38FF39FF3A00000000000000000000 0000FF41FF42FF43FF44FF45FF46FF47FF48FF49FF4AFF4BFF4CFF4DFF4EFF4F FF50FF51FF52FF53FF54FF55FF56FF57FF58FF59FF5A00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 24 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000304130423043304430453046304730483049304A304B304C304D304E304F 3050305130523053305430553056305730583059305A305B305C305D305E305F 3060306130623063306430653066306730683069306A306B306C306D306E306F 3070307130723073307430753076307730783079307A307B307C307D307E307F 3080308130823083308430853086308730883089308A308B308C308D308E308F 3090309130923093000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 25 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000030A130A230A330A430A530A630A730A830A930AA30AB30AC30AD30AE30AF 30B030B130B230B330B430B530B630B730B830B930BA30BB30BC30BD30BE30BF 30C030C130C230C330C430C530C630C730C830C930CA30CB30CC30CD30CE30CF 30D030D130D230D330D430D530D630D730D830D930DA30DB30DC30DD30DE30DF 30E030E130E230E330E430E530E630E730E830E930EA30EB30EC30ED30EE30EF 30F030F130F230F330F430F530F6000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 26 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000039103920393039403950396039703980399039A039B039C039D039E039F 03A003A103A303A403A503A603A703A803A90000000000000000000000000000 000003B103B203B303B403B503B603B703B803B903BA03BB03BC03BD03BE03BF 03C003C103C303C403C503C603C703C803C90000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 27 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000004100411041204130414041504010416041704180419041A041B041C041D 041E041F0420042104220423042404250426042704280429042A042B042C042D 042E042F00000000000000000000000000000000000000000000000000000000 000004300431043204330434043504510436043704380439043A043B043C043D 043E043F0440044104420443044404450446044704480449044A044B044C044D 044E044F00000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 28 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000025002502250C251025182514251C252C25242534253C25012503250F2513 251B251725232533252B253B254B2520252F25282537253F251D253025252538 2542000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 30 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00004E9C55165A03963F54C0611B632859F690228475831C7A5060AA63E16E25 65ED846682A69BF56893572765A162715B9B59D0867B98F47D627DBE9B8E6216 7C9F88B75B895EB563096697684895C7978D674F4EE54F0A4F4D4F9D504956F2 593759D45A015C0960DF610F61706613690570BA754F757079FB7DAD7DEF80C3 840E88638B029055907A533B4E954EA557DF80B290C178EF4E0058F16EA29038 7A328328828B9C2F5141537054BD54E156E059FB5F1598F26DEB80E4852D0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 31 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009662967096A097FB540B53F35B8770CF7FBD8FC296E8536F9D5C7ABA4E11 789381FC6E26561855046B1D851A9C3B59E553A96D6674DC958F56424E91904B 96F2834F990C53E155B65B305F71662066F368046C386CF36D29745B76C87A4E 983482F1885B8A6092ED6DB275AB76CA99C560A68B018D8A95B2698E53AD5186 5712583059445BB45EF6602863A963F46CBF6F14708E7114715971D5733F7E01 827682D185979060925B9D1B586965BC6C5A752551F9592E59655F805FDC0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 32 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000062BC65FA6A2A6B276BB4738B7FC189569D2C9D0E9EC45CA16C96837B5104 5C4B61B681C6687672614E594FFA537860696E297A4F97F34E0B53164EEE4F55 4F3D4FA14F7352A053EF5609590F5AC15BB65BE179D16687679C67B66B4C6CB3 706B73C2798D79BE7A3C7B8782B182DB8304837783EF83D387668AB256298CA8 8FE6904E971E868A4FC45CE862117259753B81E582BD86FE8CC096C5991399D5 4ECB4F1A89E356DE584A58CA5EFB5FEB602A6094606261D0621262D065390000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 33 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009B41666668B06D777070754C76867D7582A587F9958B968E8C9D51F152BE 591654B35BB35D16616869826DAF788D84CB88578A7293A79AB86D6C99A886D9 57A367FF86CE920E5283568754045ED362E164B9683C68386BBB737278BA7A6B 899A89D28D6B8F0390ED95A3969497695B665CB3697D984D984E639B7B206A2B 6A7F68B69C0D6F5F5272559D607062EC6D3B6E076ED1845B89108F444E149C39 53F6691B6A3A9784682A515C7AC384B291DC938C565B9D286822830584310000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 34 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007CA5520882C574E64E7E4F8351A05BD2520A52D852E75DFB559A582A59E6 5B8C5B985BDB5E725E7960A3611F616361BE63DB656267D1685368FA6B3E6B53 6C576F226F976F4574B0751876E3770B7AFF7BA17C217DE97F367FF0809D8266 839E89B38ACC8CAB908494519593959195A2966597D3992882184E38542B5CB8 5DCC73A9764C773C5CA97FEB8D0B96C19811985498584F014F0E5371559C5668 57FA59475B095BC45C905E0C5E7E5FCC63EE673A65D765E2671F68CB68C40000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 35 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006A5F5E306BC56C176C7D757F79485B637A007D005FBD898F8A188CB48D77 8ECC8F1D98E29A0E9B3C4E80507D510059935B9C622F628064EC6B3A72A07591 79477FA987FB8ABC8B7063AC83CA97A05409540355AB68546A588A7078276775 9ECD53745BA2811A865090064E184E454EC74F1153CA54385BAE5F1360256551 673D6C426C726CE3707874037A767AAE7B087D1A7CFE7D6665E7725B53BB5C45 5DE862D262E063196E20865A8A318DDD92F86F0179A69B5A4EA84EAB4EAC0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 36 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00004F9B4FA050D151477AF6517151F653545321537F53EB55AC58835CE15F37 5F4A602F6050606D631F65596A4B6CC172C272ED77EF80F881058208854E90F7 93E197FF99579A5A4EF051DD5C2D6681696D5C4066F26975738968507C8150C5 52E457475DFE932665A46B236B3D7434798179BD7B4B7DCA82B983CC887F895F 8B398FD191D1541F92804E5D503653E5533A72D7739677E982E68EAF99C699C8 99D25177611A865E55B07A7A50765BD3904796854E326ADB91E75C515C480000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 37 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000063987A9F6C9397748F617AAA718A96887C8268177E706851936C52F2541B 85AB8A137FA48ECD90E15366888879414FC250BE521151445553572D73EA578B 59515F625F8460756176616761A963B2643A656C666F68426E1375667A3D7CFB 7D4C7D997E4B7F6B830E834A86CD8A088A638B668EFD981A9D8F82B88FCE9BE8 5287621F64836FC09699684150916B206C7A6F547A747D5088408A2367084EF6 503950265065517C5238526355A7570F58055ACC5EFA61B261F862F363720000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 38 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000691C6A29727D72AC732E7814786F7D79770C80A9898B8B198CE28ED29063 9375967A98559A139E785143539F53B35E7B5F266E1B6E90738473FE7D438237 8A008AFA96504E4E500B53E4547C56FA59D15B645DF15EAB5F276238654567AF 6E5672D07CCA88B480A180E183F0864E8A878DE8923796C798679F134E944E92 4F0D53485449543E5A2F5F8C5FA1609F68A76A8E745A78818A9E8AA48B779190 4E5E9BC94EA44F7C4FAF501950165149516C529F52B952FE539A53E354110000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 39 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000540E5589575157A2597D5B545B5D5B8F5DE55DE75DF75E785E835E9A5EB7 5F186052614C629762D863A7653B6602664366F4676D6821689769CB6C5F6D2A 6D696E2F6E9D75327687786C7A3F7CE07D057D187D5E7DB18015800380AF80B1 8154818F822A8352884C88618B1B8CA28CFC90CA91759271783F92FC95A4964D 980599999AD89D3B525B52AB53F7540858D562F76FE08C6A8F5F9EB9514B523B 544A56FD7A4091779D609ED273446F09817075115FFD60DA9AA872DB8FBC0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 3A 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006B6498034ECA56F0576458BE5A5A606861C7660F6606683968B16DF775D5 7D3A826E9B424E9B4F5053C955065D6F5DE65DEE67FB6C99747378028A509396 88DF57505EA7632B50B550AC518D670054C9585E59BB5BB05F69624D63A1683D 6B736E08707D91C7728078157826796D658E7D3083DC88C18F09969B52645728 67507F6A8CA151B45742962A583A698A80B454B25D0E57FC78959DFA4F5C524A 548B643E6628671467F57A847B567D22932F685C9BAD7B395319518A52370000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 3B 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005BDF62F664AE64E6672D6BBA85A996D176909BD6634C93069BAB76BF6652 4E09509853C25C7160E864926563685F71E673CA75237B977E8286958B838CDB 9178991065AC66AB6B8B4ED54ED44F3A4F7F523A53F853F255E356DB58EB59CB 59C959FF5B505C4D5E025E2B5FD7601D6307652F5B5C65AF65BD65E8679D6B62 6B7B6C0F7345794979C17CF87D197D2B80A2810281F389968A5E8A698A668A8C 8AEE8CC78CDC96CC98FC6B6F4E8B4F3C4F8D51505B575BFA6148630166420000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 3C 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006B216ECB6CBB723E74BD75D478C1793A800C803381EA84948F9E6C509E7F 5F0F8B589D2B7AFA8EF85B8D96EB4E0353F157F759315AC95BA460896E7F6F06 75BE8CEA5B9F85007BE0507267F4829D5C61854A7E1E820E51995C0463688D66 659C716E793E7D1780058B1D8ECA906E86C790AA501F52FA5C3A6753707C7235 914C91C8932B82E55BC25F3160F94E3B53D65B88624B67316B8A72E973E07A2E 816B8DA391529996511253D7546A5BFF63886A397DAC970056DA53CE54680000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 3D 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005B975C315DDE4FEE610162FE6D3279C079CB7D427E4D7FD281ED821F8490 884689728B908E748F2F9031914B916C96C6919C4EC04F4F514553415F93620E 67D46C416E0B73637E2691CD928353D459195BBF6DD1795D7E2E7C9B587E719F 51FA88538FF04FCA5CFB662577AC7AE3821C99FF51C65FAA65EC696F6B896DF3 6E966F6476FE7D145DE190759187980651E6521D6240669166D96E1A5EB67DD2 7F7266F885AF85F78AF852A953D959735E8F5F90605592E4966450B7511F0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 3E 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000052DD5320534753EC54E8554655315617596859BE5A3C5BB55C065C0F5C11 5C1A5E845E8A5EE05F70627F628462DB638C63776607660C662D6676677E68A2 6A1F6A356CBC6D886E096E58713C7126716775C77701785D7901796579F07AE0 7B117CA77D39809683D6848B8549885D88F38A1F8A3C8A548A738C618CDE91A4 9266937E9418969C97984E0A4E084E1E4E575197527057CE583458CC5B225E38 60C564FE676167566D4472B675737A6384B88B7291B89320563157F498FE0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 3F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000062ED690D6B9671ED7E548077827289E698DF87558FB15C3B4F384FE14FB5 55075A205BDD5BE95FC3614E632F65B0664B68EE699B6D786DF1753375B9771F 795E79E67D3381E382AF85AA89AA8A3A8EAB8F9B903291DD97074EBA4EC15203 587558EC5C0B751A5C3D814E8A0A8FC59663976D7B258ACF9808916256F353A8 9017543957825E2563A86C34708A77617C8B7FE088709042915493109318968F 745E9AC45D075D69657067A28DA896DB636E6749691983C5981796C088FE0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 40 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006F84647A5BF84E16702C755D662F51C4523652E259D35F8160276210653F 6574661F667468F268166B636E057272751F76DB7CBE805658F088FD897F8AA0 8A938ACB901D91929752975965897A0E810696BB5E2D60DC621A65A566146790 77F37A4D7C4D7E3E810A8CAC8D648DE18E5F78A9520762D963A5644262988A2D 7A837BC08AAC96EA7D76820C87494ED95148534353605BA35C025C165DDD6226 624764B0681368346CC96D456D1767D36F5C714E717D65CB7A7F7BAD7DDA0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 41 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007E4A7FA8817A821B823985A68A6E8CCE8DF59078907792AD929195839BAE 524D55846F387136516879857E5581B37CCE564C58515CA863AA66FE66FD695A 72D9758F758E790E795679DF7C977D207D4486078A34963B90619F2050E75275 53CC53E2500955AA58EE594F723D5B8B5C64531D60E360F3635C6383633F63BB 64CD65E966F95DE369CD69FD6F1571E54E8975E976F87A937CDF7DCF7D9C8061 83498358846C84BC85FB88C58D709001906D9397971C9A1250CF5897618E0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 42 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000081D385358D0890204FC3507452475373606F6349675F6E2C8DB3901F4FD7 5C5E8CCA65CF7D9A53528896517663C35B585B6B5C0A640D6751905C4ED6591A 592A6C708A51553E581559A560F0625367C182356955964099C49A284F535806 5BFE80105CB15E2F5F856020614B623466FF6CF06EDE80CE817F82D4888B8CB8 9000902E968A9EDB9BDB4EE353F059277B2C918D984C9DF96EDD702753535544 5B856258629E62D36CA26FEF74228A1794386FC18AFE833851E786F853EA0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 43 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000053E94F4690548FB0596A81315DFD7AEA8FBF68DA8C3772F89C486A3D8AB0 4E3953585606576662C563A265E66B4E6DE16E5B70AD77ED7AEF7BAA7DBB803D 80C686CB8A95935B56E358C75F3E65AD66966A806BB575378AC7502477E55730 5F1B6065667A6C6075F47A1A7F6E81F48718904599B37BC9755C7AF97B5184C4 901079E97A9283365AE177404E2D4EF25B995FE062BD663C67F16CE8866B8877 8A3B914E92F399D06A177026732A82E784578CAF4E01514651CB558B5BF50000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 44 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005E165E335E815F145F355F6B5FB461F2631166A2671D6F6E7252753A773A 80748139817887768ABF8ADC8D858DF3929A957798029CE552C5635776F46715 6C8873CD8CC393AE96736D25589C690E69CC8FFD939A75DB901A585A680263B4 69FB4F436F2C67D88FBB85267DB49354693F6F70576A58F75B2C7D2C722A540A 91E39DB44EAD4F4E505C507552438C9E544858245B9A5E1D5E955EAD5EF75F1F 608C62B5633A63D068AF6C407887798E7A0B7DE082478A028AE68E4490130000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 45 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000090B8912D91D89F0E6CE5645864E265756EF476847B1B906993D16EBA54F2 5FB964A48F4D8FED92445178586B59295C555E976DFB7E8F751C8CBC8EE2985B 70B94F1D6BBF6FB1753096FB514E54105835585759AC5C605F926597675C6E21 767B83DF8CED901490FD934D7825783A52AA5EA6571F597460125012515A51AC 51CD520055105854585859575B955CF65D8B60BC6295642D6771684368BC68DF 76D76DD86E6F6D9B706F71C85F5375D879777B497B547B527CD67D7152300000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 46 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008463856985E48A0E8B048C468E0F9003900F94199676982D9A3095D850CD 52D5540C58025C0E61A7649E6D1E77B37AE580F48404905392855CE09D07533F 5F975FB36D9C7279776379BF7BE46BD272EC8AAD68036A6151F87A8169345C4A 9CF682EB5BC59149701E56785C6F60C765666C8C8C5A90419813545166C7920D 594890A351854E4D51EA85998B0E7058637A934B696299B47E04757753576960 8EDF96E36C5D4E8C5C3C5F108FE953028CD1808986795EFF65E54E7351650000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 47 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000059825C3F97EE4EFB598A5FCD8A8D6FE179B079625BE78471732B71B15E74 5FF5637B649A71C37C984E435EFC4E4B57DC56A260A96FC37D0D80FD813381BF 8FB2899786A45DF4628A64AD898767776CE26D3E743678345A467F7582AD99AC 4FF35EC362DD63926557676F76C3724C80CC80BA8F29914D500D57F95A926885 6973716472FD8CB758F28CE0966A9019877F79E477E784294F2F5265535A62CD 67CF6CCA767D7B947C95823685848FEB66DD6F2072067E1B83AB99C19EA60000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 48 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000051FD7BB178727BB880877B486AE85E61808C75517560516B92626E8C767A 91979AEA4F107F70629C7B4F95A59CE9567A585986E496BC4F345224534A53CD 53DB5E06642C6591677F6C3E6C4E724872AF73ED75547E41822C85E98CA97BC4 91C67169981298EF633D6669756A76E478D0854386EE532A5351542659835E87 5F7C60B26249627962AB65906BD46CCC75B276AE789179D87DCB7F7780A588AB 8AB98CBB907F975E98DB6A0B7C3850995C3E5FAE67876BD8743577097F8E0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 49 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009F3B67CA7A175339758B9AED5F66819D83F180985F3C5FC575627B46903C 686759EB5A9B7D10767E8B2C4FF55F6A6A196C376F0274E2796888688A558C79 5EDF63CF75C579D282D7932892F2849C86ED9C2D54C15F6C658C6D5C70158CA7 8CD3983B654F74F64E0D4ED857E0592B5A665BCC51A85E035E9C601662766577 65A7666E6D6E72367B268150819A82998B5C8CA08CE68D74961C96444FAE64AB 6B66821E8461856A90E85C01695398A8847A85574F0F526F5FA95E45670D0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 4A 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000798F8179890789866DF55F1762556CB84ECF72699B925206543B567458B3 61A4626E711A596E7C897CDE7D1B96F06587805E4E194F75517558405E635E73 5F0A67C44E26853D9589965B7C73980150FB58C1765678A7522577A585117B86 504F590972477BC77DE88FBA8FD4904D4FBF52C95A295F0197AD4FDD821792EA 570363556B69752B88DC8F147A4252DF58936155620A66AE6BCD7C3F83E95023 4FF853055446583159495B9D5CF05CEF5D295E9662B16367653E65B9670B0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 4B 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006CD56CE170F978327E2B80DE82B3840C84EC870289128A2A8C4A90A692D2 98FD9CF39D6C4E4F4EA1508D5256574A59A85E3D5FD85FD9623F66B4671B67D0 68D251927D2180AA81A88B008C8C8CBF927E96325420982C531750D5535C58A8 64B26734726777667A4691E652C36CA16B8658005E4C5954672C7FFB51E176C6 646978E89B549EBB57CB59B96627679A6BCE54E969D95E55819C67959BAA67FE 9C52685D4EA64FE353C862B9672B6CAB8FC44FAD7E6D9EBF4E0761626E800000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 4C 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006F2B85135473672A9B455DF37B955CAC5BC6871C6E4A84D17A1481085999 7C8D6C11772052D959227121725F77DB97279D61690B5A7F5A1851A5540D547D 660E76DF8FF792989CF459EA725D6EC5514D68C97DBF7DEC97629EBA64786A21 830259845B5F6BDB731B76F27DB280178499513267289ED976EE676252FF9905 5C24623B7C7E8CB0554F60B67D0B958053014E5F51B6591C723A803691CE5F25 77E253845F797D0485AC8A338E8D975667F385AE9453610961086CB976520000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 4D 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008AED8F38552F4F51512A52C753CB5BA55E7D60A0618263D6670967DA6E67 6D8C733673377531795088D58A98904A909190F596C4878D59154E884F594E0E 8A898F3F981050AD5E7C59965BB95EB863DA63FA64C166DC694A69D86D0B6EB6 719475287AAF7F8A8000844984C989818B218E0A9065967D990A617E62916B32 6C836D747FCC7FFC6DC07F8587BA88F8676583B1983C96F76D1B7D61843D916A 4E7153755D506B046FEB85CD862D89A75229540F5C65674E68A8740674830000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 4E 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000075E288CF88E191CC96E296785F8B73877ACB844E63A0756552896D416E9C 74097559786B7C9296867ADC9F8D4FB6616E65C5865C4E864EAE50DA4E2151CC 5BEE659968816DBC731F764277AD7A1C7CE7826F8AD2907C91CF96759818529B 7DD1502B539867976DCB71D0743381E88F2A96A39C579E9F746058416D997D2F 985E4EE44F364F8B51B752B15DBA601C73B2793C82D3923496B796F6970A9E97 9F6266A66B74521752A370C888C25EC9604B61906F2371497C3E7DF4806F0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 4F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000084EE9023932C54429B6F6AD370898CC28DEF973252B45A415ECA5F046717 697C69946D6A6F0F726272FC7BED8001807E874B90CE516D9E937984808B9332 8AD6502D548C8A716B6A8CC4810760D167A09DF24E994E989C108A6B85C18568 69006E7E78978155000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 50 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005F0C4E104E154E2A4E314E364E3C4E3F4E424E564E584E824E858C6B4E8A 82125F0D4E8E4E9E4E9F4EA04EA24EB04EB34EB64ECE4ECD4EC44EC64EC24ED7 4EDE4EED4EDF4EF74F094F5A4F304F5B4F5D4F574F474F764F884F8F4F984F7B 4F694F704F914F6F4F864F9651184FD44FDF4FCE4FD84FDB4FD14FDA4FD04FE4 4FE5501A50285014502A502550054F1C4FF650215029502C4FFE4FEF50115006 504350476703505550505048505A5056506C50785080509A508550B450B20000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 51 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000050C950CA50B350C250D650DE50E550ED50E350EE50F950F5510951015102 511651155114511A5121513A5137513C513B513F51405152514C515451627AF8 5169516A516E5180518256D8518C5189518F519151935195519651A451A651A2 51A951AA51AB51B351B151B251B051B551BD51C551C951DB51E0865551E951ED 51F051F551FE5204520B5214520E5227522A522E52335239524F5244524B524C 525E5254526A527452695273527F527D528D529452925271528852918FA80000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 52 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008FA752AC52AD52BC52B552C152CD52D752DE52E352E698ED52E052F352F5 52F852F9530653087538530D5310530F5315531A5323532F5331533353385340 534653454E175349534D51D6535E5369536E5918537B53775382539653A053A6 53A553AE53B053B653C37C1296D953DF66FC71EE53EE53E853ED53FA5401543D 5440542C542D543C542E54365429541D544E548F5475548E545F547154775470 5492547B5480547654845490548654C754A254B854A554AC54C454C854A80000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 53 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000054AB54C254A454BE54BC54D854E554E6550F551454FD54EE54ED54FA54E2 553955405563554C552E555C55455556555755385533555D5599558054AF558A 559F557B557E5598559E55AE557C558355A9558755A855DA55C555DF55C455DC 55E455D4561455F7561655FE55FD561B55F9564E565071DF5634563656325638 566B5664562F566C566A56865680568A56A05694568F56A556AE56B656B456C2 56BC56C156C356C056C856CE56D156D356D756EE56F9570056FF570457090000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 54 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005708570B570D57135718571655C7571C572657375738574E573B5740574F 576957C057885761577F5789579357A057B357A457AA57B057C357C657D457D2 57D3580A57D657E3580B5819581D587258215862584B58706BC05852583D5879 588558B9589F58AB58BA58DE58BB58B858AE58C558D358D158D758D958D858E5 58DC58E458DF58EF58FA58F958FB58FC58FD5902590A5910591B68A65925592C 592D59325938593E7AD259555950594E595A5958596259605967596C59690000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 55 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000059785981599D4F5E4FAB59A359B259C659E859DC598D59D959DA5A255A1F 5A115A1C5A095A1A5A405A6C5A495A355A365A625A6A5A9A5ABC5ABE5ACB5AC2 5ABD5AE35AD75AE65AE95AD65AFA5AFB5B0C5B0B5B165B325AD05B2A5B365B3E 5B435B455B405B515B555B5A5B5B5B655B695B705B735B755B7865885B7A5B80 5B835BA65BB85BC35BC75BC95BD45BD05BE45BE65BE25BDE5BE55BEB5BF05BF6 5BF35C055C075C085C0D5C135C205C225C285C385C395C415C465C4E5C530000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 56 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005C505C4F5B715C6C5C6E4E625C765C795C8C5C915C94599B5CAB5CBB5CB6 5CBC5CB75CC55CBE5CC75CD95CE95CFD5CFA5CED5D8C5CEA5D0B5D155D175D5C 5D1F5D1B5D115D145D225D1A5D195D185D4C5D525D4E5D4B5D6C5D735D765D87 5D845D825DA25D9D5DAC5DAE5DBD5D905DB75DBC5DC95DCD5DD35DD25DD65DDB 5DEB5DF25DF55E0B5E1A5E195E115E1B5E365E375E445E435E405E4E5E575E54 5E5F5E625E645E475E755E765E7A9EBC5E7F5EA05EC15EC25EC85ED05ECF0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 57 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00005ED65EE35EDD5EDA5EDB5EE25EE15EE85EE95EEC5EF15EF35EF05EF45EF8 5EFE5F035F095F5D5F5C5F0B5F115F165F295F2D5F385F415F485F4C5F4E5F2F 5F515F565F575F595F615F6D5F735F775F835F825F7F5F8A5F885F915F875F9E 5F995F985FA05FA85FAD5FBC5FD65FFB5FE45FF85FF15FDD60B35FFF60216060 601960106029600E6031601B6015602B6026600F603A605A6041606A6077605F 604A6046604D6063604360646042606C606B60596081608D60E76083609A0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 58 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006084609B60966097609260A7608B60E160B860E060D360B45FF060BD60C6 60B560D8614D6115610660F660F7610060F460FA6103612160FB60F1610D610E 6147613E61286127614A613F613C612C6134613D614261446173617761586159 615A616B6174616F61656171615F615D6153617561996196618761AC6194619A 618A619161AB61AE61CC61CA61C961F761C861C361C661BA61CB7F7961CD61E6 61E361F661FA61F461FF61FD61FC61FE620062086209620D620C6214621B0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 59 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000621E6221622A622E6230623262336241624E625E6263625B62606268627C 62826289627E62926293629662D46283629462D762D162BB62CF62FF62C664D4 62C862DC62CC62CA62C262C7629B62C9630C62EE62F163276302630862EF62F5 6350633E634D641C634F6396638E638063AB637663A3638F6389639F63B5636B 636963BE63E963C063C663E363C963D263F663C4641664346406641364266436 651D64176428640F6467646F6476644E652A6495649364A564A9648864BC0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5A 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000064DA64D264C564C764BB64D864C264F164E7820964E064E162AC64E364EF 652C64F664F464F264FA650064FD6518651C650565246523652B653465356537 65366538754B654865566555654D6558655E655D65726578658265838B8A659B 659F65AB65B765C365C665C165C465CC65D265DB65D965E065E165F16772660A 660365FB6773663566366634661C664F664466496641665E665D666466676668 665F6662667066836688668E668966846698669D66C166B966C966BE66BC0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5B 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000066C466B866D666DA66E0663F66E666E966F066F566F7670F6716671E6726 67279738672E673F67366741673867376746675E676067596763676467896770 67A9677C676A678C678B67A667A1678567B767EF67B467EC67B367E967B867E4 67DE67DD67E267EE67B967CE67C667E76A9C681E684668296840684D6832684E 68B3682B685968636877687F689F688F68AD6894689D689B68836AAE68B96874 68B568A068BA690F688D687E690168CA690868D86922692668E1690C68CD0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5C 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000068D468E768D569366912690468D768E3692568F968E068EF6928692A691A 6923692168C669796977695C6978696B6954697E696E69396974693D69596930 6961695E695D6981696A69B269AE69D069BF69C169D369BE69CE5BE869CA69DD 69BB69C369A76A2E699169A0699C699569B469DE69E86A026A1B69FF6B0A69F9 69F269E76A0569B16A1E69ED6A1469EB6A0A6A126AC16A236A136A446A0C6A72 6A366A786A476A626A596A666A486A386A226A906A8D6AA06A846AA26AA30000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5D 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006A9786176ABB6AC36AC26AB86AB36AAC6ADE6AD16ADF6AAA6ADA6AEA6AFB 6B0586166AFA6B126B169B316B1F6B386B3776DC6B3998EE6B476B436B496B50 6B596B546B5B6B5F6B616B786B796B7F6B806B846B836B8D6B986B956B9E6BA4 6BAA6BAB6BAF6BB26BB16BB36BB76BBC6BC66BCB6BD36BDF6BEC6BEB6BF36BEF 9EBE6C086C136C146C1B6C246C236C5E6C556C626C6A6C826C8D6C9A6C816C9B 6C7E6C686C736C926C906CC46CF16CD36CBD6CD76CC56CDD6CAE6CB16CBE0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5E 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006CBA6CDB6CEF6CD96CEA6D1F884D6D366D2B6D3D6D386D196D356D336D12 6D0C6D636D936D646D5A6D796D596D8E6D956FE46D856DF96E156E0A6DB56DC7 6DE66DB86DC66DEC6DDE6DCC6DE86DD26DC56DFA6DD96DE46DD56DEA6DEE6E2D 6E6E6E2E6E196E726E5F6E3E6E236E6B6E2B6E766E4D6E1F6E436E3A6E4E6E24 6EFF6E1D6E386E826EAA6E986EC96EB76ED36EBD6EAF6EC46EB26ED46ED56E8F 6EA56EC26E9F6F416F11704C6EEC6EF86EFE6F3F6EF26F316EEF6F326ECC0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 5F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006F3E6F136EF76F866F7A6F786F816F806F6F6F5B6FF36F6D6F826F7C6F58 6F8E6F916FC26F666FB36FA36FA16FA46FB96FC66FAA6FDF6FD56FEC6FD46FD8 6FF16FEE6FDB7009700B6FFA70117001700F6FFE701B701A6F74701D7018701F 7030703E7032705170637099709270AF70F170AC70B870B370AE70DF70CB70DD 70D9710970FD711C711971657155718871667162714C7156716C718F71FB7184 719571A871AC71D771B971BE71D271C971D471CE71E071EC71E771F571FC0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 60 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000071F971FF720D7210721B7228722D722C72307232723B723C723F72407246 724B72587274727E7282728172877292729672A272A772B972B272C372C672C4 72CE72D272E272E072E172F972F7500F7317730A731C7316731D7334732F7329 7325733E734E734F9ED87357736A7368737073787375737B737A73C873B373CE 73BB73C073E573EE73DE74A27405746F742573F87432743A7455743F745F7459 7441745C746974707463746A7476747E748B749E74A774CA74CF74D473F10000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 61 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000074E074E374E774E974EE74F274F074F174F874F7750475037505750C750E 750D75157513751E7526752C753C7544754D754A7549755B7546755A75697564 7567756B756D75787576758675877574758A758975827594759A759D75A575A3 75C275B375C375B575BD75B875BC75B175CD75CA75D275D975E375DE75FE75FF 75FC760175F075FA75F275F3760B760D7609761F762776207621762276247634 7630763B764776487646765C76587661766276687669766A7667766C76700000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 62 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000767276767678767C768076837688768B768E769676937699769A76B076B4 76B876B976BA76C276CD76D676D276DE76E176E576E776EA862F76FB77087707 770477297724771E77257726771B773777387747775A7768776B775B7765777F 777E7779778E778B779177A0779E77B077B677B977BF77BC77BD77BB77C777CD 77D777DA77DC77E377EE77FC780C781279267820792A7845788E78747886787C 789A788C78A378B578AA78AF78D178C678CB78D478BE78BC78C578CA78EC0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 63 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000078E778DA78FD78F47907791279117919792C792B794079607957795F795A 79557953797A797F798A799D79A79F4B79AA79AE79B379B979BA79C979D579E7 79EC79E179E37A087A0D7A187A197A207A1F79807A317A3B7A3E7A377A437A57 7A497A617A627A699F9D7A707A797A7D7A887A977A957A987A967AA97AC87AB0 7AB67AC57AC47ABF90837AC77ACA7ACD7ACF7AD57AD37AD97ADA7ADD7AE17AE2 7AE67AED7AF07B027B0F7B0A7B067B337B187B197B1E7B357B287B367B500000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 64 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007B7A7B047B4D7B0B7B4C7B457B757B657B747B677B707B717B6C7B6E7B9D 7B987B9F7B8D7B9C7B9A7B8B7B927B8F7B5D7B997BCB7BC17BCC7BCF7BB47BC6 7BDD7BE97C117C147BE67BE57C607C007C077C137BF37BF77C177C0D7BF67C23 7C277C2A7C1F7C377C2B7C3D7C4C7C437C547C4F7C407C507C587C5F7C647C56 7C657C6C7C757C837C907CA47CAD7CA27CAB7CA17CA87CB37CB27CB17CAE7CB9 7CBD7CC07CC57CC27CD87CD27CDC7CE29B3B7CEF7CF27CF47CF67CFA7D060000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 65 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007D027D1C7D157D0A7D457D4B7D2E7D327D3F7D357D467D737D567D4E7D72 7D687D6E7D4F7D637D937D897D5B7D8F7D7D7D9B7DBA7DAE7DA37DB57DC77DBD 7DAB7E3D7DA27DAF7DDC7DB87D9F7DB07DD87DDD7DE47DDE7DFB7DF27DE17E05 7E0A7E237E217E127E317E1F7E097E0B7E227E467E667E3B7E357E397E437E37 7E327E3A7E677E5D7E567E5E7E597E5A7E797E6A7E697E7C7E7B7E837DD57E7D 8FAE7E7F7E887E897E8C7E927E907E937E947E967E8E7E9B7E9C7F387F3A0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 66 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007F457F4C7F4D7F4E7F507F517F557F547F587F5F7F607F687F697F677F78 7F827F867F837F887F877F8C7F947F9E7F9D7F9A7FA37FAF7FB27FB97FAE7FB6 7FB88B717FC57FC67FCA7FD57FD47FE17FE67FE97FF37FF998DC80068004800B 801280188019801C80218028803F803B804A804680528058805A805F80628068 80738072807080768079807D807F808480868085809B8093809A80AD519080AC 80DB80E580D980DD80C480DA80D6810980EF80F1811B81298123812F814B0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 67 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000968B8146813E8153815180FC8171816E81658166817481838188818A8180 818281A0819581A481A3815F819381A981B081B581BE81B881BD81C081C281BA 81C981CD81D181D981D881C881DA81DF81E081E781FA81FB81FE820182028205 8207820A820D821082168229822B82388233824082598258825D825A825F8264 82628268826A826B822E827182778278827E828D829282AB829F82BB82AC82E1 82E382DF82D282F482F382FA8393830382FB82F982DE830682DC830982D90000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 68 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000833583348316833283318340833983508345832F832B831783188385839A 83AA839F83A283968323838E8387838A837C83B58373837583A0838983A883F4 841383EB83CE83FD840383D8840B83C183F7840783E083F2840D8422842083BD 8438850683FB846D842A843C855A84848477846B84AD846E848284698446842C 846F8479843584CA846284B984BF849F84D984CD84BB84DA84D084C184C684D6 84A1852184FF84F485178518852C851F8515851484FC85408563855885480000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 69 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000085418602854B8555858085A485888591858A85A8856D8594859B85EA8587 859C8577857E859085C985BA85CF85B985D085D585DD85E585DC85F9860A8613 860B85FE85FA86068622861A8630863F864D4E558654865F86678671869386A3 86A986AA868B868C86B686AF86C486C686B086C9882386AB86D486DE86E986EC 86DF86DB86EF8712870687088700870386FB87118709870D86F9870A8734873F 8737873B87258729871A8760875F8778874C874E877487578768876E87590000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6A 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000087538763876A880587A2879F878287AF87CB87BD87C087D096D687AB87C4 87B387C787C687BB87EF87F287E0880F880D87FE87F687F7880E87D288118816 8815882288218831883688398827883B8844884288528859885E8862886B8881 887E889E8875887D88B5887288828897889288AE889988A2888D88A488B088BF 88B188C388C488D488D888D988DD88F9890288FC88F488E888F28904890C890A 89138943891E8925892A892B89418944893B89368938894C891D8960895E0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6B 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000089668964896D896A896F89748977897E89838988898A8993899889A189A9 89A689AC89AF89B289BA89BD89BF89C089DA89DC89DD89E789F489F88A038A16 8A108A0C8A1B8A1D8A258A368A418A5B8A528A468A488A7C8A6D8A6C8A628A85 8A828A848AA88AA18A918AA58AA68A9A8AA38AC48ACD8AC28ADA8AEB8AF38AE7 8AE48AF18B148AE08AE28AF78ADE8ADB8B0C8B078B1A8AE18B168B108B178B20 8B3397AB8B268B2B8B3E8B288B418B4C8B4F8B4E8B498B568B5B8B5A8B6B0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6C 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008B5F8B6C8B6F8B748B7D8B808B8C8B8E8B928B938B968B998B9A8C3A8C41 8C3F8C488C4C8C4E8C508C558C628C6C8C788C7A8C828C898C858C8A8C8D8C8E 8C948C7C8C98621D8CAD8CAA8CBD8CB28CB38CAE8CB68CC88CC18CE48CE38CDA 8CFD8CFA8CFB8D048D058D0A8D078D0F8D0D8D109F4E8D138CCD8D148D168D67 8D6D8D718D738D818D998DC28DBE8DBA8DCF8DDA8DD68DCC8DDB8DCB8DEA8DEB 8DDF8DE38DFC8E088E098DFF8E1D8E1E8E108E1F8E428E358E308E348E4A0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6D 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008E478E498E4C8E508E488E598E648E608E2A8E638E558E768E728E7C8E81 8E878E858E848E8B8E8A8E938E918E948E998EAA8EA18EAC8EB08EC68EB18EBE 8EC58EC88ECB8EDB8EE38EFC8EFB8EEB8EFE8F0A8F058F158F128F198F138F1C 8F1F8F1B8F0C8F268F338F3B8F398F458F428F3E8F4C8F498F468F4E8F578F5C 8F628F638F648F9C8F9F8FA38FAD8FAF8FB78FDA8FE58FE28FEA8FEF90878FF4 90058FF98FFA901190159021900D901E9016900B90279036903590398FF80000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6E 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000904F905090519052900E9049903E90569058905E9068906F907696A89072 9082907D90819080908A9089908F90A890AF90B190B590E290E4624890DB9102 9112911991329130914A9156915891639165916991739172918B9189918291A2 91AB91AF91AA91B591B491BA91C091C191C991CB91D091D691DF91E191DB91FC 91F591F6921E91FF9214922C92159211925E925792459249926492489295923F 924B9250929C92969293929B925A92CF92B992B792E9930F92FA9344932E0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 6F 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000093199322931A9323933A9335933B935C9360937C936E935693B093AC93AD 939493B993D693D793E893E593D893C393DD93D093C893E4941A941494139403 940794109436942B94359421943A944194529444945B94609462945E946A9229 947094759477947D945A947C947E9481947F95829587958A9594959695989599 95A095A895A795AD95BC95BB95B995BE95CA6FF695C395CD95CC95D595D495D6 95DC95E195E595E296219628962E962F9642964C964F964B9677965C965E0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 70 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000965D965F96669672966C968D96989695969796AA96A796B196B296B096B4 96B696B896B996CE96CB96C996CD894D96DC970D96D596F99704970697089713 970E9711970F971697199724972A97309739973D973E97449746974897429749 975C976097649766976852D2976B977197799785977C9781977A9786978B978F 9790979C97A897A697A397B397B497C397C697C897CB97DC97ED9F4F97F27ADF 97F697F5980F980C9838982498219837983D9846984F984B986B986F98700000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 71 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000098719874987398AA98AF98B198B698C498C398C698E998EB990399099912 991499189921991D991E99249920992C992E993D993E9942994999459950994B 99519952994C99559997999899A599AD99AE99BC99DF99DB99DD99D899D199ED 99EE99F199F299FB99F89A019A0F9A0599E29A199A2B9A379A459A429A409A43 9A3E9A559A4D9A5B9A579A5F9A629A659A649A699A6B9A6A9AAD9AB09ABC9AC0 9ACF9AD19AD39AD49ADE9ADF9AE29AE39AE69AEF9AEB9AEE9AF49AF19AF70000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 72 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009AFB9B069B189B1A9B1F9B229B239B259B279B289B299B2A9B2E9B2F9B32 9B449B439B4F9B4D9B4E9B519B589B749B939B839B919B969B979B9F9BA09BA8 9BB49BC09BCA9BB99BC69BCF9BD19BD29BE39BE29BE49BD49BE19C3A9BF29BF1 9BF09C159C149C099C139C0C9C069C089C129C0A9C049C2E9C1B9C259C249C21 9C309C479C329C469C3E9C5A9C609C679C769C789CE79CEC9CF09D099D089CEB 9D039D069D2A9D269DAF9D239D1F9D449D159D129D419D3F9D3E9D469D480000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 73 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009D5D9D5E9D649D519D509D599D729D899D879DAB9D6F9D7A9D9A9DA49DA9 9DB29DC49DC19DBB9DB89DBA9DC69DCF9DC29DD99DD39DF89DE69DED9DEF9DFD 9E1A9E1B9E1E9E759E799E7D9E819E889E8B9E8C9E929E959E919E9D9EA59EA9 9EB89EAA9EAD97619ECC9ECE9ECF9ED09ED49EDC9EDE9EDD9EE09EE59EE89EEF 9EF49EF69EF79EF99EFB9EFC9EFD9F079F0876B79F159F219F2C9F3E9F4A9F52 9F549F639F5F9F609F619F669F679F6C9F6A9F779F729F769F959F9C9FA00000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 74 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000582F69C79059746451DC7199000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 R 2141 301C FF5E 2142 2016 2225 215D 2212 FF0D 2171 00A2 FFE0 2172 00A3 FFE1 224C 00AC FFE2 tcl8.4.20/library/encoding/iso8859-14.enc0000644003604700454610000000210711737050674016212 0ustar dgp771div# Encoding file: iso8859-14, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 0080008100820083008400850086008700880089008A008B008C008D008E008F 0090009100920093009400950096009700980099009A009B009C009D009E009F 00A01E021E0300A3010A010B1E0A00A71E8000A91E821E0B1EF200AD00AE0178 1E1E1E1F012001211E401E4100B61E561E811E571E831E601EF31E841E851E61 00C000C100C200C300C400C500C600C700C800C900CA00CB00CC00CD00CE00CF 017400D100D200D300D400D500D61E6A00D800D900DA00DB00DC00DD017600DF 00E000E100E200E300E400E500E600E700E800E900EA00EB00EC00ED00EE00EF 017500F100F200F300F400F500F61E6B00F800F900FA00FB00FC00FD017700FF tcl8.4.20/library/encoding/cp855.enc0000644003604700454610000000210211737050674015477 0ustar dgp771div# Encoding file: cp855, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 0452040204530403045104010454040404550405045604060457040704580408 04590409045A040A045B040B045C040C045E040E045F040F044E042E044A042A 0430041004310411044604260434041404350415044404240433041300AB00BB 259125922593250225240445042504380418256325512557255D043904192510 25142534252C251C2500253C043A041A255A25542569256625602550256C00A4 043B041B043C041C043D041D043E041E043F2518250C25882584041F044F2580 042F044004200441042104420422044304230436041604320412044C042C2116 00AD044B042B0437041704480428044D042D044904290447042700A725A000A0 tcl8.4.20/library/encoding/iso8859-10.enc0000644003604700454610000000210711737050674016206 0ustar dgp771div# Encoding file: iso8859-10, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 0080008100820083008400850086008700880089008A008B008C008D008E008F 0090009100920093009400950096009700980099009A009B009C009D009E009F 00A0010401120122012A0128013600A7013B011001600166017D00AD016A014A 00B0010501130123012B0129013700B7013C011101610167017E2015016B014B 010000C100C200C300C400C500C6012E010C00C9011800CB011600CD00CE00CF 00D00145014C00D300D400D500D6016800D8017200DA00DB00DC00DD00DE00DF 010100E100E200E300E400E500E6012F010D00E9011900EB011700ED00EE00EF 00F00146014D00F300F400F500F6016900F8017300FA00FB00FC00FD00FE0138 tcl8.4.20/library/encoding/cp864.enc0000644003604700454610000000210211737050674015477 0ustar dgp771div# Encoding file: cp864, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 00200021002200230024066A0026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 00B000B72219221A259225002502253C2524252C251C25342510250C25142518 03B2221E03C600B100BD00BC224800AB00BBFEF7FEF8009B009CFEFBFEFC009F 00A000ADFE8200A300A4FE8400000000FE8EFE8FFE95FE99060CFE9DFEA1FEA5 0660066106620663066406650666066706680669FED1061BFEB1FEB5FEB9061F 00A2FE80FE81FE83FE85FECAFE8BFE8DFE91FE93FE97FE9BFE9FFEA3FEA7FEA9 FEABFEADFEAFFEB3FEB7FEBBFEBFFEC1FEC5FECBFECF00A600AC00F700D7FEC9 0640FED3FED7FEDBFEDFFEE3FEE7FEEBFEEDFEEFFEF3FEBDFECCFECEFECDFEE1 FE7D0651FEE5FEE9FEECFEF0FEF2FED0FED5FEF5FEF6FEDDFED9FEF125A00000 tcl8.4.20/library/encoding/cp861.enc0000644003604700454610000000210211737050674015474 0ustar dgp771div# Encoding file: cp861, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 00C700FC00E900E200E400E000E500E700EA00EB00E800D000F000DE00C400C5 00C900E600C600F400F600FE00FB00DD00FD00D600DC00F800A300D820A70192 00E100ED00F300FA00C100CD00D300DA00BF231000AC00BD00BC00A100AB00BB 259125922593250225242561256225562555256325512557255D255C255B2510 25142534252C251C2500253C255E255F255A25542569256625602550256C2567 2568256425652559255825522553256B256A2518250C25882584258C25902580 03B100DF039303C003A303C300B503C403A6039803A903B4221E03C603B52229 226100B1226522642320232100F7224800B0221900B7221A207F00B225A000A0 tcl8.4.20/library/encoding/macCentEuro.enc0000644003604700454610000000211011737050674017037 0ustar dgp771div# Encoding file: macCentEuro, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 00C40100010100C9010400D600DC00E10105010C00E4010D0106010700E90179 017A010E00ED010F01120113011600F3011700F400F600F500FA011A011B00FC 202000B0011800A300A7202200B600DF00AE00A92122011900A822600123012E 012F012A22642265012B0136220222110142013B013C013D013E0139013A0145 0146014300AC221A01440147220600AB00BB202600A00148015000D50151014C 20132014201C201D2018201900F725CA014D0154015501582039203A01590156 01570160201A201E0161015A015B00C10164016500CD017D017E016A00D300D4 016B016E00DA016F017001710172017300DD00FD0137017B0141017C012202C7 tcl8.4.20/library/encoding/iso8859-2.enc0000644003604700454610000000210611737050674016126 0ustar dgp771div# Encoding file: iso8859-2, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F 0010001100120013001400150016001700180019001A001B001C001D001E001F 0020002100220023002400250026002700280029002A002B002C002D002E002F 0030003100320033003400350036003700380039003A003B003C003D003E003F 0040004100420043004400450046004700480049004A004B004C004D004E004F 0050005100520053005400550056005700580059005A005B005C005D005E005F 0060006100620063006400650066006700680069006A006B006C006D006E006F 0070007100720073007400750076007700780079007A007B007C007D007E007F 0080008100820083008400850086008700880089008A008B008C008D008E008F 0090009100920093009400950096009700980099009A009B009C009D009E009F 00A0010402D8014100A4013D015A00A700A80160015E0164017900AD017D017B 00B0010502DB014200B4013E015B02C700B80161015F0165017A02DD017E017C 015400C100C2010200C40139010600C7010C00C9011800CB011A00CD00CE010E 01100143014700D300D4015000D600D70158016E00DA017000DC00DD016200DF 015500E100E2010300E4013A010700E7010D00E9011900EB011B00ED00EE010F 01110144014800F300F4015100F600F70159016F00FA017100FC00FD016302D9 tcl8.4.20/library/dde/0000755003604700454610000000000012153151142013100 5ustar dgp771divtcl8.4.20/library/dde/pkgIndex.tcl0000644003604700454610000000047312144442333015366 0ustar dgp771divif {![package vsatisfies [package provide Tcl] 8]} return if {[info sharedlibextension] != ".dll"} return if {[info exists ::tcl_platform(debug)]} { package ifneeded dde 1.3.3 [list load [file join $dir tcldde13g.dll] dde] } else { package ifneeded dde 1.3.3 [list load [file join $dir tcldde13.dll] dde] } tcl8.4.20/library/license.terms0000644003604700454610000000432111737050674015061 0ustar dgp771divThis software is copyrighted by the Regents of the University of California, Sun Microsystems, Inc., Scriptics Corporation, ActiveState Corporation and other parties. The following terms apply to all files associated with the software unless explicitly disclaimed in individual files. The authors hereby grant permission to use, copy, modify, distribute, and license this software and its documentation for any purpose, provided that existing copyright notices are retained in all copies and that this notice is included verbatim in any distributions. No written agreement, license, or royalty fee is required for any of the authorized uses. Modifications to this software may be copyrighted by their authors and need not follow the licensing terms described here, provided that the new terms are clearly indicated on the first page of each file where they apply. IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. GOVERNMENT USE: If you are acquiring this software on behalf of the U.S. government, the Government shall have only "Restricted Rights" in the software and related documentation as defined in the Federal Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are acquiring the software on behalf of the Department of Defense, the software shall be classified as "Commercial Computer Software" and the Government shall have only "Restricted Rights" as defined in Clause 252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the authors grant the U.S. Government and others acting in its behalf permission to use and distribute the software in accordance with the terms specified in this license. tcl8.4.20/library/reg/0000755003604700454610000000000012153151142013121 5ustar dgp771divtcl8.4.20/library/reg/pkgIndex.tcl0000755003604700454610000000055312144442333015411 0ustar dgp771divif {![package vsatisfies [package provide Tcl] 8]} return if {[info sharedlibextension] != ".dll"} return if {[info exists ::tcl_platform(debug)]} { package ifneeded registry 1.2.2 \ [list load [file join $dir tclreg12g.dll] registry] } else { package ifneeded registry 1.2.2 \ [list load [file join $dir tclreg12.dll] registry] } tcl8.4.20/library/auto.tcl0000644003604700454610000005055111737050674014045 0ustar dgp771div# auto.tcl -- # # utility procs formerly in init.tcl dealing with auto execution # of commands and can be auto loaded themselves. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994-1998 Sun Microsystems, Inc. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # auto_reset -- # # Destroy all cached information for auto-loading and auto-execution, # so that the information gets recomputed the next time it's needed. # Also delete any procedures that are listed in the auto-load index # except those defined in this file. # # Arguments: # None. proc auto_reset {} { global auto_execs auto_index auto_oldpath foreach p [info procs] { if {[info exists auto_index($p)] && ![string match auto_* $p] && ([lsearch -exact {unknown pkg_mkIndex tclPkgSetup tcl_findLibrary pkg_compareExtension tclPkgUnknown tcl::MacOSXPkgUnknown tcl::MacPkgUnknown} $p] < 0)} { rename $p {} } } unset -nocomplain auto_execs auto_index auto_oldpath } # tcl_findLibrary -- # # This is a utility for extensions that searches for a library directory # using a canonical searching algorithm. A side effect is to source # the initialization script and set a global library variable. # # Arguments: # basename Prefix of the directory name, (e.g., "tk") # version Version number of the package, (e.g., "8.0") # patch Patchlevel of the package, (e.g., "8.0.3") # initScript Initialization script to source (e.g., tk.tcl) # enVarName environment variable to honor (e.g., TK_LIBRARY) # varName Global variable to set when done (e.g., tk_library) proc tcl_findLibrary {basename version patch initScript enVarName varName} { upvar #0 $varName the_library global env errorInfo set dirs {} set errors {} # The C application may have hardwired a path, which we honor if {[info exists the_library] && $the_library ne ""} { lappend dirs $the_library } else { # Do the canonical search # 1. From an environment variable, if it exists. # Placing this first gives the end-user ultimate control # to work-around any bugs, or to customize. if {[info exists env($enVarName)]} { lappend dirs $env($enVarName) } # 2. In the package script directory registered within # the configuration of the package itself. # # Only do this for Tcl 8.5+, when Tcl_RegsiterConfig() is available. #if {[catch { # ::${basename}::pkgconfig get scriptdir,runtime #} value] == 0} { # lappend dirs $value #} # 3. Relative to auto_path directories. This checks relative to the # Tcl library as well as allowing loading of libraries added to the # auto_path that is not relative to the core library or binary paths. foreach d $::auto_path { lappend dirs [file join $d $basename$version] if {$::tcl_platform(platform) eq "unix" && $::tcl_platform(os) eq "Darwin"} { # 4. On MacOSX, check the Resources/Scripts subdir too lappend dirs [file join $d $basename$version Resources Scripts] } } # 3. Various locations relative to the executable # ../lib/foo1.0 (From bin directory in install hierarchy) # ../../lib/foo1.0 (From bin/arch directory in install hierarchy) # ../library (From unix directory in build hierarchy) set parentDir [file dirname [file dirname [info nameofexecutable]]] set grandParentDir [file dirname $parentDir] lappend dirs [file join $parentDir lib $basename$version] lappend dirs [file join $grandParentDir lib $basename$version] lappend dirs [file join $parentDir library] # Remaining locations are out of date (when relevant, they ought # to be covered by the $::auto_path seach above). # # ../../library (From unix/arch directory in build hierarchy) # ../../foo1.0.1/library # (From unix directory in parallel build hierarchy) # ../../../foo1.0.1/library # (From unix/arch directory in parallel build hierarchy) # # For the sake of extra compatibility safety, we keep adding these # paths during the 8.4.* release series. if {1} { lappend dirs [file join $grandParentDir library] lappend dirs [file join $grandParentDir $basename$patch library] lappend dirs [file join [file dirname $grandParentDir] \ $basename$patch library] } } # uniquify $dirs in order array set seen {} foreach i $dirs { # For Tcl 8.4.9, we've disabled the use of [file normalize] here. # This means that two different path names that are the same path # in normalized form, will both remain on the search path. There # should be no harm in that, just a bit more file system access # than is strictly necessary. # # [file normalize] has been disabled because of reports it has # caused difficulties with the freewrap utility. To keep # compatibility with freewrap's needs, we'll keep this disabled # throughout the 8.4.x (x >= 9) releases. See Bug 1072136. if {1 || [interp issafe]} { set norm $i } else { set norm [file normalize $i] } if {[info exists seen($norm)]} { continue } set seen($norm) "" lappend uniqdirs $i } set dirs $uniqdirs foreach i $dirs { set the_library $i set file [file join $i $initScript] # source everything when in a safe interpreter because # we have a source command, but no file exists command if {[interp issafe] || [file exists $file]} { if {![catch {uplevel #0 [list source $file]} msg]} { return } else { append errors "$file: $msg\n$errorInfo\n" } } } unset -nocomplain the_library set msg "Can't find a usable $initScript in the following directories: \n" append msg " $dirs\n\n" append msg "$errors\n\n" append msg "This probably means that $basename wasn't installed properly.\n" error $msg } # ---------------------------------------------------------------------- # auto_mkindex # ---------------------------------------------------------------------- # The following procedures are used to generate the tclIndex file # from Tcl source files. They use a special safe interpreter to # parse Tcl source files, writing out index entries as "proc" # commands are encountered. This implementation won't work in a # safe interpreter, since a safe interpreter can't create the # special parser and mess with its commands. if {[interp issafe]} { return ;# Stop sourcing the file here } # auto_mkindex -- # Regenerate a tclIndex file from Tcl source files. Takes as argument # the name of the directory in which the tclIndex file is to be placed, # followed by any number of glob patterns to use in that directory to # locate all of the relevant files. # # Arguments: # dir - Name of the directory in which to create an index. # args - Any number of additional arguments giving the # names of files within dir. If no additional # are given auto_mkindex will look for *.tcl. proc auto_mkindex {dir args} { global errorCode errorInfo if {[interp issafe]} { error "can't generate index within safe interpreter" } set oldDir [pwd] cd $dir set dir [pwd] append index "# Tcl autoload index file, version 2.0\n" append index "# This file is generated by the \"auto_mkindex\" command\n" append index "# and sourced to set up indexing information for one or\n" append index "# more commands. Typically each line is a command that\n" append index "# sets an element in the auto_index array, where the\n" append index "# element name is the name of a command and the value is\n" append index "# a script that loads the command.\n\n" if {[llength $args] == 0} { set args *.tcl } auto_mkindex_parser::init foreach file [eval [linsert $args 0 glob --]] { if {[catch {auto_mkindex_parser::mkindex $file} msg] == 0} { append index $msg } else { set code $errorCode set info $errorInfo cd $oldDir error $msg $info $code } } auto_mkindex_parser::cleanup set fid [open "tclIndex" w] puts -nonewline $fid $index close $fid cd $oldDir } # Original version of auto_mkindex that just searches the source # code for "proc" at the beginning of the line. proc auto_mkindex_old {dir args} { global errorCode errorInfo set oldDir [pwd] cd $dir set dir [pwd] append index "# Tcl autoload index file, version 2.0\n" append index "# This file is generated by the \"auto_mkindex\" command\n" append index "# and sourced to set up indexing information for one or\n" append index "# more commands. Typically each line is a command that\n" append index "# sets an element in the auto_index array, where the\n" append index "# element name is the name of a command and the value is\n" append index "# a script that loads the command.\n\n" if {[llength $args] == 0} { set args *.tcl } foreach file [eval [linsert $args 0 glob --]] { set f "" set error [catch { set f [open $file] while {[gets $f line] >= 0} { if {[regexp {^proc[ ]+([^ ]*)} $line match procName]} { set procName [lindex [auto_qualify $procName "::"] 0] append index "set [list auto_index($procName)]" append index " \[list source \[file join \$dir [list $file]\]\]\n" } } close $f } msg] if {$error} { set code $errorCode set info $errorInfo catch {close $f} cd $oldDir error $msg $info $code } } set f "" set error [catch { set f [open tclIndex w] puts -nonewline $f $index close $f cd $oldDir } msg] if {$error} { set code $errorCode set info $errorInfo catch {close $f} cd $oldDir error $msg $info $code } } # Create a safe interpreter that can be used to parse Tcl source files # generate a tclIndex file for autoloading. This interp contains # commands for things that need index entries. Each time a command # is executed, it writes an entry out to the index file. namespace eval auto_mkindex_parser { variable parser "" ;# parser used to build index variable index "" ;# maintains index as it is built variable scriptFile "" ;# name of file being processed variable contextStack "" ;# stack of namespace scopes variable imports "" ;# keeps track of all imported cmds variable initCommands "" ;# list of commands that create aliases proc init {} { variable parser variable initCommands if {![interp issafe]} { set parser [interp create -safe] $parser hide info $parser hide rename $parser hide proc $parser hide namespace $parser hide eval $parser hide puts $parser invokehidden namespace delete :: $parser invokehidden proc unknown {args} {} # We'll need access to the "namespace" command within the # interp. Put it back, but move it out of the way. $parser expose namespace $parser invokehidden rename namespace _%@namespace $parser expose eval $parser invokehidden rename eval _%@eval # Install all the registered psuedo-command implementations foreach cmd $initCommands { eval $cmd } } } proc cleanup {} { variable parser interp delete $parser unset parser } } # auto_mkindex_parser::mkindex -- # # Used by the "auto_mkindex" command to create a "tclIndex" file for # the given Tcl source file. Executes the commands in the file, and # handles things like the "proc" command by adding an entry for the # index file. Returns a string that represents the index file. # # Arguments: # file Name of Tcl source file to be indexed. proc auto_mkindex_parser::mkindex {file} { variable parser variable index variable scriptFile variable contextStack variable imports set scriptFile $file set fid [open $file] set contents [read $fid] close $fid # There is one problem with sourcing files into the safe # interpreter: references like "$x" will fail since code is not # really being executed and variables do not really exist. # To avoid this, we replace all $ with \0 (literally, the null char) # later, when getting proc names we will have to reverse this replacement, # in case there were any $ in the proc name. This will cause a problem # if somebody actually tries to have a \0 in their proc name. Too bad # for them. set contents [string map "$ \u0000" $contents] set index "" set contextStack "" set imports "" $parser eval $contents foreach name $imports { catch {$parser eval [list _%@namespace forget $name]} } return $index } # auto_mkindex_parser::hook command # # Registers a Tcl command to evaluate when initializing the # slave interpreter used by the mkindex parser. # The command is evaluated in the master interpreter, and can # use the variable auto_mkindex_parser::parser to get to the slave proc auto_mkindex_parser::hook {cmd} { variable initCommands lappend initCommands $cmd } # auto_mkindex_parser::slavehook command # # Registers a Tcl command to evaluate when initializing the # slave interpreter used by the mkindex parser. # The command is evaluated in the slave interpreter. proc auto_mkindex_parser::slavehook {cmd} { variable initCommands # The $parser variable is defined to be the name of the # slave interpreter when this command is used later. lappend initCommands "\$parser eval [list $cmd]" } # auto_mkindex_parser::command -- # # Registers a new command with the "auto_mkindex_parser" interpreter # that parses Tcl files. These commands are fake versions of things # like the "proc" command. When you execute them, they simply write # out an entry to a "tclIndex" file for auto-loading. # # This procedure allows extensions to register their own commands # with the auto_mkindex facility. For example, a package like # [incr Tcl] might register a "class" command so that class definitions # could be added to a "tclIndex" file for auto-loading. # # Arguments: # name Name of command recognized in Tcl files. # arglist Argument list for command. # body Implementation of command to handle indexing. proc auto_mkindex_parser::command {name arglist body} { hook [list auto_mkindex_parser::commandInit $name $arglist $body] } # auto_mkindex_parser::commandInit -- # # This does the actual work set up by auto_mkindex_parser::command # This is called when the interpreter used by the parser is created. # # Arguments: # name Name of command recognized in Tcl files. # arglist Argument list for command. # body Implementation of command to handle indexing. proc auto_mkindex_parser::commandInit {name arglist body} { variable parser set ns [namespace qualifiers $name] set tail [namespace tail $name] if {$ns eq ""} { set fakeName [namespace current]::_%@fake_$tail } else { set fakeName [namespace current]::[string map {:: _} _%@fake_$name] } proc $fakeName $arglist $body # YUK! Tcl won't let us alias fully qualified command names, # so we can't handle names like "::itcl::class". Instead, # we have to build procs with the fully qualified names, and # have the procs point to the aliases. if {[string match *::* $name]} { set exportCmd [list _%@namespace export [namespace tail $name]] $parser eval [list _%@namespace eval $ns $exportCmd] # The following proc definition does not work if you # want to tolerate space or something else diabolical # in the procedure name, (i.e., space in $alias) # The following does not work: # "_%@eval {$alias} \$args" # because $alias gets concat'ed to $args. # The following does not work because $cmd is somehow undefined # "set cmd {$alias} \; _%@eval {\$cmd} \$args" # A gold star to someone that can make test # autoMkindex-3.3 work properly set alias [namespace tail $fakeName] $parser invokehidden proc $name {args} "_%@eval {$alias} \$args" $parser alias $alias $fakeName } else { $parser alias $name $fakeName } return } # auto_mkindex_parser::fullname -- # Used by commands like "proc" within the auto_mkindex parser. # Returns the qualified namespace name for the "name" argument. # If the "name" does not start with "::", elements are added from # the current namespace stack to produce a qualified name. Then, # the name is examined to see whether or not it should really be # qualified. If the name has more than the leading "::", it is # returned as a fully qualified name. Otherwise, it is returned # as a simple name. That way, the Tcl autoloader will recognize # it properly. # # Arguments: # name - Name that is being added to index. proc auto_mkindex_parser::fullname {name} { variable contextStack if {![string match ::* $name]} { foreach ns $contextStack { set name "${ns}::$name" if {[string match ::* $name]} { break } } } if {[namespace qualifiers $name] eq ""} { set name [namespace tail $name] } elseif {![string match ::* $name]} { set name "::$name" } # Earlier, mkindex replaced all $'s with \0. Now, we have to reverse # that replacement. return [string map "\u0000 $" $name] } # Register all of the procedures for the auto_mkindex parser that # will build the "tclIndex" file. # AUTO MKINDEX: proc name arglist body # Adds an entry to the auto index list for the given procedure name. auto_mkindex_parser::command proc {name args} { variable index variable scriptFile # Do some fancy reformatting on the "source" call to handle platform # differences with respect to pathnames. Use format just so that the # command is a little easier to read (otherwise it'd be full of # backslashed dollar signs, etc. append index [list set auto_index([fullname $name])] \ [format { [list source [file join $dir %s]]} \ [file split $scriptFile]] "\n" } # Conditionally add support for Tcl byte code files. There are some # tricky details here. First, we need to get the tbcload library # initialized in the current interpreter. We cannot load tbcload into the # slave until we have done so because it needs access to the tcl_patchLevel # variable. Second, because the package index file may defer loading the # library until we invoke a command, we need to explicitly invoke auto_load # to force it to be loaded. This should be a noop if the package has # already been loaded auto_mkindex_parser::hook { if {![catch {package require tbcload}]} { if {[namespace which -command tbcload::bcproc] eq ""} { auto_load tbcload::bcproc } load {} tbcload $auto_mkindex_parser::parser # AUTO MKINDEX: tbcload::bcproc name arglist body # Adds an entry to the auto index list for the given pre-compiled # procedure name. auto_mkindex_parser::commandInit tbcload::bcproc {name args} { variable index variable scriptFile # Do some nice reformatting of the "source" call, to get around # path differences on different platforms. We use the format # command just so that the code is a little easier to read. append index [list set auto_index([fullname $name])] \ [format { [list source [file join $dir %s]]} \ [file split $scriptFile]] "\n" } } } # AUTO MKINDEX: namespace eval name command ?arg arg...? # Adds the namespace name onto the context stack and evaluates the # associated body of commands. # # AUTO MKINDEX: namespace import ?-force? pattern ?pattern...? # Performs the "import" action in the parser interpreter. This is # important for any commands contained in a namespace that affect # the index. For example, a script may say "itcl::class ...", # or it may import "itcl::*" and then say "class ...". This # procedure does the import operation, but keeps track of imported # patterns so we can remove the imports later. auto_mkindex_parser::command namespace {op args} { switch -- $op { eval { variable parser variable contextStack set name [lindex $args 0] set args [lrange $args 1 end] set contextStack [linsert $contextStack 0 $name] $parser eval [list _%@namespace eval $name] $args set contextStack [lrange $contextStack 1 end] } import { variable parser variable imports foreach pattern $args { if {$pattern ne "-force"} { lappend imports $pattern } } catch {$parser eval "_%@namespace import $args"} } } } return tcl8.4.20/library/tclIndex0000644003604700454610000001372111737050674014064 0ustar dgp771div# Tcl autoload index file, version 2.0 # This file is generated by the "auto_mkindex" command # and sourced to set up indexing information for one or # more commands. Typically each line is a command that # sets an element in the auto_index array, where the # element name is the name of a command and the value is # a script that loads the command. set auto_index(auto_reset) [list source [file join $dir auto.tcl]] set auto_index(tcl_findLibrary) [list source [file join $dir auto.tcl]] set auto_index(auto_mkindex) [list source [file join $dir auto.tcl]] set auto_index(auto_mkindex_old) [list source [file join $dir auto.tcl]] set auto_index(::auto_mkindex_parser::init) [list source [file join $dir auto.tcl]] set auto_index(::auto_mkindex_parser::cleanup) [list source [file join $dir auto.tcl]] set auto_index(::auto_mkindex_parser::mkindex) [list source [file join $dir auto.tcl]] set auto_index(::auto_mkindex_parser::hook) [list source [file join $dir auto.tcl]] set auto_index(::auto_mkindex_parser::slavehook) [list source [file join $dir auto.tcl]] set auto_index(::auto_mkindex_parser::command) [list source [file join $dir auto.tcl]] set auto_index(::auto_mkindex_parser::commandInit) [list source [file join $dir auto.tcl]] set auto_index(::auto_mkindex_parser::fullname) [list source [file join $dir auto.tcl]] set auto_index(history) [list source [file join $dir history.tcl]] set auto_index(::tcl::HistAdd) [list source [file join $dir history.tcl]] set auto_index(::tcl::HistKeep) [list source [file join $dir history.tcl]] set auto_index(::tcl::HistClear) [list source [file join $dir history.tcl]] set auto_index(::tcl::HistInfo) [list source [file join $dir history.tcl]] set auto_index(::tcl::HistRedo) [list source [file join $dir history.tcl]] set auto_index(::tcl::HistIndex) [list source [file join $dir history.tcl]] set auto_index(::tcl::HistEvent) [list source [file join $dir history.tcl]] set auto_index(::tcl::HistChange) [list source [file join $dir history.tcl]] set auto_index(tclLdAout) [list source [file join $dir ldAout.tcl]] set auto_index(pkg_compareExtension) [list source [file join $dir package.tcl]] set auto_index(pkg_mkIndex) [list source [file join $dir package.tcl]] set auto_index(tclPkgSetup) [list source [file join $dir package.tcl]] set auto_index(tclPkgUnknown) [list source [file join $dir package.tcl]] set auto_index(::tcl::MacOSXPkgUnknown) [list source [file join $dir package.tcl]] set auto_index(::tcl::MacPkgUnknown) [list source [file join $dir package.tcl]] set auto_index(::pkg::create) [list source [file join $dir package.tcl]] set auto_index(parray) [list source [file join $dir parray.tcl]] set auto_index(::safe::InterpStatics) [list source [file join $dir safe.tcl]] set auto_index(::safe::InterpNested) [list source [file join $dir safe.tcl]] set auto_index(::safe::interpCreate) [list source [file join $dir safe.tcl]] set auto_index(::safe::interpInit) [list source [file join $dir safe.tcl]] set auto_index(::safe::CheckInterp) [list source [file join $dir safe.tcl]] set auto_index(::safe::interpConfigure) [list source [file join $dir safe.tcl]] set auto_index(::safe::InterpCreate) [list source [file join $dir safe.tcl]] set auto_index(::safe::InterpSetConfig) [list source [file join $dir safe.tcl]] set auto_index(::safe::interpFindInAccessPath) [list source [file join $dir safe.tcl]] set auto_index(::safe::interpAddToAccessPath) [list source [file join $dir safe.tcl]] set auto_index(::safe::InterpInit) [list source [file join $dir safe.tcl]] set auto_index(::safe::AddSubDirs) [list source [file join $dir safe.tcl]] set auto_index(::safe::interpDelete) [list source [file join $dir safe.tcl]] set auto_index(::safe::setLogCmd) [list source [file join $dir safe.tcl]] set auto_index(::safe::SyncAccessPath) [list source [file join $dir safe.tcl]] set auto_index(::safe::InterpStateName) [list source [file join $dir safe.tcl]] set auto_index(::safe::IsInterp) [list source [file join $dir safe.tcl]] set auto_index(::safe::PathToken) [list source [file join $dir safe.tcl]] set auto_index(::safe::PathListName) [list source [file join $dir safe.tcl]] set auto_index(::safe::VirtualPathListName) [list source [file join $dir safe.tcl]] set auto_index(::safe::PathNumberName) [list source [file join $dir safe.tcl]] set auto_index(::safe::StaticsOkName) [list source [file join $dir safe.tcl]] set auto_index(::safe::NestedOkName) [list source [file join $dir safe.tcl]] set auto_index(::safe::Toplevel) [list source [file join $dir safe.tcl]] set auto_index(::safe::Set) [list source [file join $dir safe.tcl]] set auto_index(::safe::Lappend) [list source [file join $dir safe.tcl]] set auto_index(::safe::Unset) [list source [file join $dir safe.tcl]] set auto_index(::safe::Exists) [list source [file join $dir safe.tcl]] set auto_index(::safe::GetAccessPath) [list source [file join $dir safe.tcl]] set auto_index(::safe::StaticsOk) [list source [file join $dir safe.tcl]] set auto_index(::safe::NestedOk) [list source [file join $dir safe.tcl]] set auto_index(::safe::DeleteHookName) [list source [file join $dir safe.tcl]] set auto_index(::safe::TranslatePath) [list source [file join $dir safe.tcl]] set auto_index(::safe::Log) [list source [file join $dir safe.tcl]] set auto_index(::safe::CheckFileName) [list source [file join $dir safe.tcl]] set auto_index(::safe::AliasSource) [list source [file join $dir safe.tcl]] set auto_index(::safe::AliasLoad) [list source [file join $dir safe.tcl]] set auto_index(::safe::FileInAccessPath) [list source [file join $dir safe.tcl]] set auto_index(::safe::Subset) [list source [file join $dir safe.tcl]] set auto_index(::safe::AliasSubset) [list source [file join $dir safe.tcl]] set auto_index(tcl_wordBreakAfter) [list source [file join $dir word.tcl]] set auto_index(tcl_wordBreakBefore) [list source [file join $dir word.tcl]] set auto_index(tcl_endOfWord) [list source [file join $dir word.tcl]] set auto_index(tcl_startOfNextWord) [list source [file join $dir word.tcl]] set auto_index(tcl_startOfPreviousWord) [list source [file join $dir word.tcl]] tcl8.4.20/library/init.tcl0000644003604700454610000005364212052456744014043 0ustar dgp771div# init.tcl -- # # Default system startup file for Tcl-based applications. Defines # "unknown" procedure and auto-load facilities. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994-1996 Sun Microsystems, Inc. # Copyright (c) 1998-1999 Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # if {[info commands package] == ""} { error "version mismatch: library\nscripts expect Tcl version 7.5b1 or later but the loaded version is\nonly [info patchlevel]" } package require -exact Tcl 8.4 # Compute the auto path to use in this interpreter. # The values on the path come from several locations: # # The environment variable TCLLIBPATH # # tcl_library, which is the directory containing this init.tcl script. # tclInitScript.h searches around for the directory containing this # init.tcl and defines tcl_library to that location before sourcing it. # # The parent directory of tcl_library. Adding the parent # means that packages in peer directories will be found automatically. # # Also add the directory ../lib relative to the directory where the # executable is located. This is meant to find binary packages for the # same architecture as the current executable. # # tcl_pkgPath, which is set by the platform-specific initialization routines # On UNIX it is compiled in # On Windows, it is not used if {![info exists auto_path]} { if {[info exists env(TCLLIBPATH)]} { set auto_path $env(TCLLIBPATH) } else { set auto_path "" } } namespace eval tcl { variable Dir if {[info library] ne ""} { foreach Dir [list [info library] [file dirname [info library]]] { if {[lsearch -exact $::auto_path $Dir] < 0} { lappend ::auto_path $Dir } } } set Dir [file join [file dirname [file dirname \ [info nameofexecutable]]] lib] if {[lsearch -exact $::auto_path $Dir] < 0} { lappend ::auto_path $Dir } if {[info exists ::tcl_pkgPath]} { foreach Dir $::tcl_pkgPath { if {[lsearch -exact $::auto_path $Dir] < 0} { lappend ::auto_path $Dir } } } } # Windows specific end of initialization if {(![interp issafe]) && $tcl_platform(platform) eq "windows"} { namespace eval tcl { proc EnvTraceProc {lo n1 n2 op} { set x $::env($n2) set ::env($lo) $x set ::env([string toupper $lo]) $x } proc InitWinEnv {} { global env tcl_platform foreach p [array names env] { set u [string toupper $p] if {$u ne $p} { switch -- $u { COMSPEC - PATH { if {![info exists env($u)]} { set env($u) $env($p) } trace add variable env($p) write \ [namespace code [list EnvTraceProc $p]] trace add variable env($u) write \ [namespace code [list EnvTraceProc $p]] } } } } if {![info exists env(COMSPEC)]} { if {$tcl_platform(os) eq "Windows NT"} { set env(COMSPEC) cmd.exe } else { set env(COMSPEC) command.com } } } InitWinEnv } } # Setup the unknown package handler package unknown tclPkgUnknown if {![interp issafe]} { # setup platform specific unknown package handlers if {$::tcl_platform(platform) eq "unix" && $::tcl_platform(os) eq "Darwin"} { package unknown [list tcl::MacOSXPkgUnknown [package unknown]] } } # Conditionalize for presence of exec. if {[namespace which -command exec] eq ""} { set auto_noexec 1 } set errorCode "" set errorInfo "" # Define a log command (which can be overwitten to log errors # differently, specially when stderr is not available) if {[namespace which -command tclLog] eq ""} { proc tclLog {string} { catch {puts stderr $string} } } # unknown -- # This procedure is called when a Tcl command is invoked that doesn't # exist in the interpreter. It takes the following steps to make the # command available: # # 1. See if the command has the form "namespace inscope ns cmd" and # if so, concatenate its arguments onto the end and evaluate it. # 2. See if the autoload facility can locate the command in a # Tcl script file. If so, load it and execute it. # 3. If the command was invoked interactively at top-level: # (a) see if the command exists as an executable UNIX program. # If so, "exec" the command. # (b) see if the command requests csh-like history substitution # in one of the common forms !!, !, or ^old^new. If # so, emulate csh's history substitution. # (c) see if the command is a unique abbreviation for another # command. If so, invoke the command. # # Arguments: # args - A list whose elements are the words of the original # command, including the command name. proc unknown args { global auto_noexec auto_noload env unknown_pending tcl_interactive global errorCode errorInfo # If the command word has the form "namespace inscope ns cmd" # then concatenate its arguments onto the end and evaluate it. set cmd [lindex $args 0] if {[regexp "^:*namespace\[ \t\n\]+inscope" $cmd] && [llength $cmd] == 4} { set arglist [lrange $args 1 end] set ret [catch {uplevel 1 ::$cmd $arglist} result] if {$ret == 0} { return $result } else { return -code $ret -errorcode $errorCode $result } } # Save the values of errorCode and errorInfo variables, since they # may get modified if caught errors occur below. The variables will # be restored just before re-executing the missing command. # Safety check in case something unsets the variables # ::errorInfo or ::errorCode. [Bug 1063707] if {![info exists errorCode]} { set errorCode "" } if {![info exists errorInfo]} { set errorInfo "" } set savedErrorCode $errorCode set savedErrorInfo $errorInfo set name $cmd if {![info exists auto_noload]} { # # Make sure we're not trying to load the same proc twice. # if {[info exists unknown_pending($name)]} { return -code error "self-referential recursion in \"unknown\" for command \"$name\""; } set unknown_pending($name) pending; set ret [catch {auto_load $name [uplevel 1 {::namespace current}]} msg] unset unknown_pending($name); if {$ret != 0} { append errorInfo "\n (autoloading \"$name\")" return -code $ret -errorcode $errorCode -errorinfo $errorInfo $msg } if {![array size unknown_pending]} { unset unknown_pending } if {$msg} { set errorCode $savedErrorCode set errorInfo $savedErrorInfo set code [catch {uplevel 1 $args} msg] if {$code == 1} { # # Compute stack trace contribution from the [uplevel]. # Note the dependence on how Tcl_AddErrorInfo, etc. # construct the stack trace. # set cinfo $args set ellipsis "" while {[string bytelength $cinfo] > 150} { set cinfo [string range $cinfo 0 end-1] set ellipsis "..." } append cinfo $ellipsis "\"\n (\"uplevel\" body line 1)" append cinfo "\n invoked from within" append cinfo "\n\"uplevel 1 \$args\"" # # Try each possible form of the stack trace # and trim the extra contribution from the matching case # set expect "$msg\n while executing\n\"$cinfo" if {$errorInfo eq $expect} { # # The stack has only the eval from the expanded command # Do not generate any stack trace here. # return -code error -errorcode $errorCode $msg } # # Stack trace is nested, trim off just the contribution # from the extra "eval" of $args due to the "catch" above. # set expect "\n invoked from within\n\"$cinfo" set exlen [string length $expect] set eilen [string length $errorInfo] set i [expr {$eilen - $exlen - 1}] set einfo [string range $errorInfo 0 $i] # # For now verify that $errorInfo consists of what we are about # to return plus what we expected to trim off. # if {$errorInfo ne "$einfo$expect"} { error "Tcl bug: unexpected stack trace in \"unknown\"" {} \ [list CORE UNKNOWN BADTRACE $expect $errorInfo] } return -code error -errorcode $errorCode \ -errorinfo $einfo $msg } else { return -code $code $msg } } } if {([info level] == 1) && [info script] eq "" \ && [info exists tcl_interactive] && $tcl_interactive} { if {![info exists auto_noexec]} { set new [auto_execok $name] if {$new ne ""} { set errorCode $savedErrorCode set errorInfo $savedErrorInfo set redir "" if {[namespace which -command console] eq ""} { set redir ">&@stdout <@stdin" } return [uplevel 1 exec $redir $new [lrange $args 1 end]] } } set errorCode $savedErrorCode set errorInfo $savedErrorInfo if {$name eq "!!"} { set newcmd [history event] } elseif {[regexp {^!(.+)$} $name -> event]} { set newcmd [history event $event] } elseif {[regexp {^\^([^^]*)\^([^^]*)\^?$} $name -> old new]} { set newcmd [history event -1] catch {regsub -all -- $old $newcmd $new newcmd} } if {[info exists newcmd]} { tclLog $newcmd history change $newcmd 0 return [uplevel 1 $newcmd] } set ret [catch {set candidates [info commands $name*]} msg] if {$name eq "::"} { set name "" } if {$ret != 0} { return -code $ret -errorcode $errorCode \ "error in unknown while checking if \"$name\" is\ a unique command abbreviation:\n$msg" } # Filter out bogus matches when $name contained # a glob-special char [Bug 946952] if {$name eq ""} { # Handle empty $name separately due to strangeness # in [string first] (See RFE 1243354) set cmds $candidates } else { set cmds [list] foreach x $candidates { if {[string first $name $x] == 0} { lappend cmds $x } } } if {[llength $cmds] == 1} { return [uplevel 1 [lreplace $args 0 0 [lindex $cmds 0]]] } if {[llength $cmds]} { return -code error "ambiguous command name \"$name\": [lsort $cmds]" } } return -code error "invalid command name \"$name\"" } # auto_load -- # Checks a collection of library directories to see if a procedure # is defined in one of them. If so, it sources the appropriate # library file to create the procedure. Returns 1 if it successfully # loaded the procedure, 0 otherwise. # # Arguments: # cmd - Name of the command to find and load. # namespace (optional) The namespace where the command is being used - must be # a canonical namespace as returned [namespace current] # for instance. If not given, namespace current is used. proc auto_load {cmd {namespace {}}} { global auto_index auto_oldpath auto_path if {$namespace eq ""} { set namespace [uplevel 1 [list ::namespace current]] } set nameList [auto_qualify $cmd $namespace] # workaround non canonical auto_index entries that might be around # from older auto_mkindex versions lappend nameList $cmd foreach name $nameList { if {[info exists auto_index($name)]} { namespace eval :: $auto_index($name) # There's a couple of ways to look for a command of a given # name. One is to use # info commands $name # Unfortunately, if the name has glob-magic chars in it like * # or [], it may not match. For our purposes here, a better # route is to use # namespace which -command $name if {[namespace which -command $name] ne ""} { return 1 } } } if {![info exists auto_path]} { return 0 } if {![auto_load_index]} { return 0 } foreach name $nameList { if {[info exists auto_index($name)]} { namespace eval :: $auto_index($name) if {[namespace which -command $name] ne ""} { return 1 } } } return 0 } # auto_load_index -- # Loads the contents of tclIndex files on the auto_path directory # list. This is usually invoked within auto_load to load the index # of available commands. Returns 1 if the index is loaded, and 0 if # the index is already loaded and up to date. # # Arguments: # None. proc auto_load_index {} { global auto_index auto_oldpath auto_path errorInfo errorCode if {[info exists auto_oldpath] && $auto_oldpath eq $auto_path} { return 0 } set auto_oldpath $auto_path # Check if we are a safe interpreter. In that case, we support only # newer format tclIndex files. set issafe [interp issafe] for {set i [expr {[llength $auto_path] - 1}]} {$i >= 0} {incr i -1} { set dir [lindex $auto_path $i] set f "" if {$issafe} { catch {source [file join $dir tclIndex]} } elseif {[catch {set f [open [file join $dir tclIndex]]}]} { continue } else { set error [catch { set id [gets $f] if {$id eq "# Tcl autoload index file, version 2.0"} { eval [read $f] } elseif {$id eq "# Tcl autoload index file: each line identifies a Tcl"} { while {[gets $f line] >= 0} { if {[string index $line 0] eq "#" || ([llength $line] != 2)} { continue } set name [lindex $line 0] set auto_index($name) \ "source [file join $dir [lindex $line 1]]" } } else { error "[file join $dir tclIndex] isn't a proper Tcl index file" } } msg] if {$f ne ""} { close $f } if {$error} { error $msg $errorInfo $errorCode } } } return 1 } # auto_qualify -- # # Compute a fully qualified names list for use in the auto_index array. # For historical reasons, commands in the global namespace do not have leading # :: in the index key. The list has two elements when the command name is # relative (no leading ::) and the namespace is not the global one. Otherwise # only one name is returned (and searched in the auto_index). # # Arguments - # cmd The command name. Can be any name accepted for command # invocations (Like "foo::::bar"). # namespace The namespace where the command is being used - must be # a canonical namespace as returned by [namespace current] # for instance. proc auto_qualify {cmd namespace} { # count separators and clean them up # (making sure that foo:::::bar will be treated as foo::bar) set n [regsub -all {::+} $cmd :: cmd] # Ignore namespace if the name starts with :: # Handle special case of only leading :: # Before each return case we give an example of which category it is # with the following form : # ( inputCmd, inputNameSpace) -> output if {[string match ::* $cmd]} { if {$n > 1} { # ( ::foo::bar , * ) -> ::foo::bar return [list $cmd] } else { # ( ::global , * ) -> global return [list [string range $cmd 2 end]] } } # Potentially returning 2 elements to try : # (if the current namespace is not the global one) if {$n == 0} { if {$namespace eq "::"} { # ( nocolons , :: ) -> nocolons return [list $cmd] } else { # ( nocolons , ::sub ) -> ::sub::nocolons nocolons return [list ${namespace}::$cmd $cmd] } } elseif {$namespace eq "::"} { # ( foo::bar , :: ) -> ::foo::bar return [list ::$cmd] } else { # ( foo::bar , ::sub ) -> ::sub::foo::bar ::foo::bar return [list ${namespace}::$cmd ::$cmd] } } # auto_import -- # # Invoked during "namespace import" to make see if the imported commands # reside in an autoloaded library. If so, the commands are loaded so # that they will be available for the import links. If not, then this # procedure does nothing. # # Arguments - # pattern The pattern of commands being imported (like "foo::*") # a canonical namespace as returned by [namespace current] proc auto_import {pattern} { global auto_index # If no namespace is specified, this will be an error case if {![string match *::* $pattern]} { return } set ns [uplevel 1 [list ::namespace current]] set patternList [auto_qualify $pattern $ns] auto_load_index foreach pattern $patternList { foreach name [array names auto_index $pattern] { if {([namespace which -command $name] eq "") && ([namespace qualifiers $pattern] eq [namespace qualifiers $name])} { namespace eval :: $auto_index($name) } } } } # auto_execok -- # # Returns string that indicates name of program to execute if # name corresponds to a shell builtin or an executable in the # Windows search path, or "" otherwise. Builds an associative # array auto_execs that caches information about previous checks, # for speed. # # Arguments: # name - Name of a command. if {$tcl_platform(platform) eq "windows"} { # Windows version. # # Note that info executable doesn't work under Windows, so we have to # look for files with .exe, .com, or .bat extensions. Also, the path # may be in the Path or PATH environment variables, and path # components are separated with semicolons, not colons as under Unix. # proc auto_execok name { global auto_execs env tcl_platform if {[info exists auto_execs($name)]} { return $auto_execs($name) } set auto_execs($name) "" set shellBuiltins [list cls copy date del erase dir echo mkdir \ md rename ren rmdir rd time type ver vol] if {$tcl_platform(os) eq "Windows NT"} { # NT includes the 'start' built-in lappend shellBuiltins "start" } if {[info exists env(PATHEXT)]} { # Add an initial ; to have the {} extension check first. set execExtensions [split ";$env(PATHEXT)" ";"] } else { set execExtensions [list {} .com .exe .bat] } if {[lsearch -exact $shellBuiltins [string tolower $name]] != -1} { # When this is command.com for some reason on Win2K, Tcl won't # exec it unless the case is right, which this corrects. COMSPEC # may not point to a real file, so do the check. set cmd $env(COMSPEC) if {[file exists $cmd]} { set cmd [file attributes $cmd -shortname] } return [set auto_execs($name) [list $cmd /c $name]] } if {[llength [file split $name]] != 1} { foreach ext $execExtensions { set file ${name}${ext} if {[file exists $file] && ![file isdirectory $file]} { return [set auto_execs($name) [list $file]] } } return "" } set path "[file dirname [info nameof]];.;" if {[info exists env(WINDIR)]} { set windir $env(WINDIR) } if {[info exists windir]} { if {$tcl_platform(os) eq "Windows NT"} { append path "$windir/system32;" } append path "$windir/system;$windir;" } foreach var {PATH Path path} { if {[info exists env($var)]} { append path ";$env($var)" } } foreach ext $execExtensions { unset -nocomplain checked foreach dir [split $path {;}] { # Skip already checked directories if {[info exists checked($dir)] || $dir eq {}} { continue } set checked($dir) {} set file [file join $dir ${name}${ext}] if {[file exists $file] && ![file isdirectory $file]} { return [set auto_execs($name) [list $file]] } } } return "" } } else { # Unix version. # proc auto_execok name { global auto_execs env if {[info exists auto_execs($name)]} { return $auto_execs($name) } set auto_execs($name) "" if {[llength [file split $name]] != 1} { if {[file executable $name] && ![file isdirectory $name]} { set auto_execs($name) [list $name] } return $auto_execs($name) } foreach dir [split $env(PATH) :] { if {$dir eq ""} { set dir . } set file [file join $dir $name] if {[file executable $file] && ![file isdirectory $file]} { set auto_execs($name) [list $file] return $auto_execs($name) } } return "" } } # ::tcl::CopyDirectory -- # # This procedure is called by Tcl's core when attempts to call the # filesystem's copydirectory function fail. The semantics of the call # are that 'dest' does not yet exist, i.e. dest should become the exact # image of src. If dest does exist, we throw an error. # # Note that making changes to this procedure can change the results # of running Tcl's tests. # # Arguments: # action - "renaming" or "copying" # src - source directory # dest - destination directory proc tcl::CopyDirectory {action src dest} { set nsrc [file normalize $src] set ndest [file normalize $dest] if {$action eq "renaming"} { # Can't rename volumes. We could give a more precise # error message here, but that would break the test suite. if {[lsearch -exact [file volumes] $nsrc] != -1} { return -code error "error $action \"$src\" to\ \"$dest\": trying to rename a volume or move a directory\ into itself" } } if {[file exists $dest]} { if {$nsrc eq $ndest} { return -code error "error $action \"$src\" to\ \"$dest\": trying to rename a volume or move a directory\ into itself" } if {$action eq "copying"} { return -code error "error $action \"$src\" to\ \"$dest\": file already exists" } else { # Depending on the platform, and on the current # working directory, the directories '.', '..' # can be returned in various combinations. Anyway, # if any other file is returned, we must signal an error. set existing [glob -nocomplain -directory $dest * .*] eval [linsert \ [glob -nocomplain -directory $dest -type hidden * .*] 0 \ lappend existing] foreach s $existing { if {([file tail $s] ne ".") && ([file tail $s] ne "..")} { return -code error "error $action \"$src\" to\ \"$dest\": file already exists" } } } } else { if {[string first $nsrc $ndest] != -1} { set srclen [expr {[llength [file split $nsrc]] -1}] set ndest [lindex [file split $ndest] $srclen] if {$ndest eq [file tail $nsrc]} { return -code error "error $action \"$src\" to\ \"$dest\": trying to rename a volume or move a directory\ into itself" } } file mkdir $dest } # Have to be careful to capture both visible and hidden files. # We will also be more generous to the file system and not # assume the hidden and non-hidden lists are non-overlapping. # # On Unix 'hidden' files begin with '.'. On other platforms # or filesystems hidden files may have other interpretations. set filelist [concat [glob -nocomplain -directory $src *] \ [glob -nocomplain -directory $src -types hidden *]] foreach s [lsort -unique $filelist] { if {([file tail $s] ne ".") && ([file tail $s] ne "..")} { file copy $s [file join $dest [file tail $s]] } } return } tcl8.4.20/library/word.tcl0000644003604700454610000001025211737050674014042 0ustar dgp771div# word.tcl -- # # This file defines various procedures for computing word boundaries # in strings. This file is primarily needed so Tk text and entry # widgets behave properly for different platforms. # # Copyright (c) 1996 by Sun Microsystems, Inc. # Copyright (c) 1998 by Scritpics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # The following variables are used to determine which characters are # interpreted as white space. if {$::tcl_platform(platform) eq "windows"} { # Windows style - any but a unicode space char set tcl_wordchars "\\S" set tcl_nonwordchars "\\s" } else { # Motif style - any unicode word char (number, letter, or underscore) set tcl_wordchars "\\w" set tcl_nonwordchars "\\W" } # tcl_wordBreakAfter -- # # This procedure returns the index of the first word boundary # after the starting point in the given string, or -1 if there # are no more boundaries in the given string. The index returned refers # to the first character of the pair that comprises a boundary. # # Arguments: # str - String to search. # start - Index into string specifying starting point. proc tcl_wordBreakAfter {str start} { global tcl_nonwordchars tcl_wordchars set str [string range $str $start end] if {[regexp -indices "$tcl_wordchars$tcl_nonwordchars|$tcl_nonwordchars$tcl_wordchars" $str result]} { return [expr {[lindex $result 1] + $start}] } return -1 } # tcl_wordBreakBefore -- # # This procedure returns the index of the first word boundary # before the starting point in the given string, or -1 if there # are no more boundaries in the given string. The index returned # refers to the second character of the pair that comprises a boundary. # # Arguments: # str - String to search. # start - Index into string specifying starting point. proc tcl_wordBreakBefore {str start} { global tcl_nonwordchars tcl_wordchars if {$start eq "end"} { set start [string length $str] } if {[regexp -indices "^.*($tcl_wordchars$tcl_nonwordchars|$tcl_nonwordchars$tcl_wordchars)" [string range $str 0 $start] result]} { return [lindex $result 1] } return -1 } # tcl_endOfWord -- # # This procedure returns the index of the first end-of-word location # after a starting index in the given string. An end-of-word location # is defined to be the first whitespace character following the first # non-whitespace character after the starting point. Returns -1 if # there are no more words after the starting point. # # Arguments: # str - String to search. # start - Index into string specifying starting point. proc tcl_endOfWord {str start} { global tcl_nonwordchars tcl_wordchars if {[regexp -indices "$tcl_nonwordchars*$tcl_wordchars+$tcl_nonwordchars" \ [string range $str $start end] result]} { return [expr {[lindex $result 1] + $start}] } return -1 } # tcl_startOfNextWord -- # # This procedure returns the index of the first start-of-word location # after a starting index in the given string. A start-of-word # location is defined to be a non-whitespace character following a # whitespace character. Returns -1 if there are no more start-of-word # locations after the starting point. # # Arguments: # str - String to search. # start - Index into string specifying starting point. proc tcl_startOfNextWord {str start} { global tcl_nonwordchars tcl_wordchars if {[regexp -indices "$tcl_wordchars*$tcl_nonwordchars+$tcl_wordchars" \ [string range $str $start end] result]} { return [expr {[lindex $result 1] + $start}] } return -1 } # tcl_startOfPreviousWord -- # # This procedure returns the index of the first start-of-word location # before a starting index in the given string. # # Arguments: # str - String to search. # start - Index into string specifying starting point. proc tcl_startOfPreviousWord {str start} { global tcl_nonwordchars tcl_wordchars if {$start eq "end"} { set start [string length $str] } if {[regexp -indices \ "$tcl_nonwordchars*($tcl_wordchars+)$tcl_nonwordchars*\$" \ [string range $str 0 [expr {$start - 1}]] result word]} { return [lindex $word 0] } return -1 } tcl8.4.20/library/platform/0000755003604700454610000000000012153151142014170 5ustar dgp771divtcl8.4.20/library/platform/pkgIndex.tcl0000644003604700454610000000024512151137515016454 0ustar dgp771divpackage ifneeded platform 1.0.12 [list source [file join $dir platform.tcl]] package ifneeded platform::shell 1.1.4 [list source [file join $dir shell.tcl]] tcl8.4.20/library/platform/platform.tcl0000644003604700454610000002320712144442333016531 0ustar dgp771div# -*- tcl -*- # ### ### ### ######### ######### ######### ## Overview # Heuristics to assemble a platform identifier from publicly available # information. The identifier describes the platform of the currently # running tcl shell. This is a mixture of the runtime environment and # of build-time properties of the executable itself. # # Examples: # <1> A tcl shell executing on a x86_64 processor, but having a # wordsize of 4 was compiled for the x86 environment, i.e. 32 # bit, and loaded packages have to match that, and not the # actual cpu. # # <2> The hp/solaris 32/64 bit builds of the core cannot be # distinguished by looking at tcl_platform. As packages have to # match the 32/64 information we have to look in more places. In # this case we inspect the executable itself (magic numbers, # i.e. fileutil::magic::filetype). # # The basic information used comes out of the 'os' and 'machine' # entries of the 'tcl_platform' array. A number of general and # os/machine specific transformation are applied to get a canonical # result. # # General # Only the first element of 'os' is used - we don't care whether we # are on "Windows NT" or "Windows XP" or whatever. # # Machine specific # % arm* -> arm # % sun4* -> sparc # % intel -> ix86 # % i*86* -> ix86 # % Power* -> powerpc # % x86_64 + wordSize 4 => x86 code # # OS specific # % AIX are always powerpc machines # % HP-UX 9000/800 etc means parisc # % linux has to take glibc version into account # % sunos -> solaris, and keep version number # # NOTE: A platform like linux glibc 2.3, which can use glibc 2.2 stuff # has to provide all possible allowed platform identifiers when # searching search. Ditto a solaris 2.8 platform can use solaris 2.6 # packages. Etc. This is handled by the other procedure, see below. # ### ### ### ######### ######### ######### ## Requirements namespace eval ::platform {} # ### ### ### ######### ######### ######### ## Implementation # -- platform::generic # # Assembles an identifier for the generic platform. It leaves out # details like kernel version, libc version, etc. proc ::platform::generic {} { global tcl_platform set plat [string tolower [lindex $tcl_platform(os) 0]] set cpu $tcl_platform(machine) switch -glob -- $cpu { sun4* { set cpu sparc } intel - i*86* { set cpu ix86 } x86_64 { if {$tcl_platform(wordSize) == 4} { # See Example <1> at the top of this file. set cpu ix86 } } "Power*" { set cpu powerpc } "arm*" { set cpu arm } ia64 { if {$tcl_platform(wordSize) == 4} { append cpu _32 } } } switch -- $plat { windows { set plat win32 if {$cpu eq "amd64"} { # Do not check wordSize, win32-x64 is an IL32P64 platform. set cpu x86_64 } } sunos { set plat solaris if {[string match "ix86" $cpu]} { if {$tcl_platform(wordSize) == 8} { set cpu x86_64 } } elseif {![string match "ia64*" $cpu]} { # sparc if {$tcl_platform(wordSize) == 8} { append cpu 64 } } } darwin { set plat macosx # Correctly identify the cpu when running as a 64bit # process on a machine with a 32bit kernel if {$cpu eq "ix86"} { if {$tcl_platform(wordSize) == 8} { set cpu x86_64 } } } aix { set cpu powerpc if {$tcl_platform(wordSize) == 8} { append cpu 64 } } hp-ux { set plat hpux if {![string match "ia64*" $cpu]} { set cpu parisc if {$tcl_platform(wordSize) == 8} { append cpu 64 } } } osf1 { set plat tru64 } } return "${plat}-${cpu}" } # -- platform::identify # # Assembles an identifier for the exact platform, by extending the # generic identifier. I.e. it adds in details like kernel version, # libc version, etc., if they are relevant for the loading of # packages on the platform. proc ::platform::identify {} { global tcl_platform set id [generic] regexp {^([^-]+)-([^-]+)$} $id -> plat cpu switch -- $plat { solaris { regsub {^5} $tcl_platform(osVersion) 2 text append plat $text return "${plat}-${cpu}" } macosx { set major [lindex [split $tcl_platform(osVersion) .] 0] if {$major > 8} { incr major -4 append plat 10.$major return "${plat}-${cpu}" } } linux { # Look for the libc*.so and determine its version # (libc5/6, libc6 further glibc 2.X) set v unknown # Determine in which directory to look. /lib, or /lib64. # For that we use the tcl_platform(wordSize). # # We could use the 'cpu' info, per the equivalence below, # that however would be restricted to intel. And this may # be a arm, mips, etc. system. The wordsize is more # fundamental. # # ix86 <=> (wordSize == 4) <=> 32 bit ==> /lib # x86_64 <=> (wordSize == 8) <=> 64 bit ==> /lib64 # # Do not look into /lib64 even if present, if the cpu # doesn't fit. # TODO: Determine the prefixes (i386, x86_64, ...) for # other cpus. The path after the generic one is utterly # specific to intel right now. Ok, on Ubuntu, possibly # other Debian systems we may apparently be able to query # the necessary CPU code. If we can't we simply use the # hardwired fallback. switch -exact -- $tcl_platform(wordSize) { 4 { lappend bases /lib if {[catch { exec dpkg-architecture -qDEB_HOST_MULTIARCH } res]} { lappend bases /lib/i386-linux-gnu } else { # dpkg-arch returns the full tripled, not just cpu. lappend bases /lib/$res } } 8 { lappend bases /lib64 if {[catch { exec dpkg-architecture -qDEB_HOST_MULTIARCH } res]} { lappend bases /lib/x86_64-linux-gnu } else { # dpkg-arch returns the full tripled, not just cpu. lappend bases /lib/$res } } default { return -code error "Bad wordSize $tcl_platform(wordSize), expected 4 or 8" } } foreach base $bases { if {[LibcVersion $base -> v]} break } append plat -$v return "${plat}-${cpu}" } } return $id } proc ::platform::LibcVersion {base _->_ vv} { upvar 1 $vv v set libclist [lsort [glob -nocomplain -directory $base libc*]] if {![llength $libclist]} { return 0 } set libc [lindex $libclist 0] # Try executing the library first. This should suceed # for a glibc library, and return the version # information. if {![catch { set vdata [lindex [split [exec $libc] \n] 0] }]} { regexp {version ([0-9]+(\.[0-9]+)*)} $vdata -> v foreach {major minor} [split $v .] break set v glibc${major}.${minor} return 1 } else { # We had trouble executing the library. We are now # inspecting its name to determine the version # number. This code by Larry McVoy. if {[regexp -- {libc-([0-9]+)\.([0-9]+)} $libc -> major minor]} { set v glibc${major}.${minor} return 1 } } return 0 } # -- platform::patterns # # Given an exact platform identifier, i.e. _not_ the generic # identifier it assembles a list of exact platform identifier # describing platform which should be compatible with the # input. # # I.e. packages for all platforms in the result list should be # loadable on the specified platform. # << Should we add the generic identifier to the list as well ? In # general it is not compatible I believe. So better not. In many # cases the exact identifier is identical to the generic one # anyway. # >> proc ::platform::patterns {id} { set res [list $id] if {$id eq "tcl"} {return $res} switch -glob -- $id { solaris*-* { if {[regexp {solaris([^-]*)-(.*)} $id -> v cpu]} { if {$v eq ""} {return $id} foreach {major minor} [split $v .] break incr minor -1 for {set j $minor} {$j >= 6} {incr j -1} { lappend res solaris${major}.${j}-${cpu} } } } linux*-* { if {[regexp {linux-glibc([^-]*)-(.*)} $id -> v cpu]} { foreach {major minor} [split $v .] break incr minor -1 for {set j $minor} {$j >= 0} {incr j -1} { lappend res linux-glibc${major}.${j}-${cpu} } } } macosx*-* { # 10.5+ if {[regexp {macosx([^-]*)-(.*)} $id -> v cpu]} { switch -exact -- $cpu { ix86 - x86_64 { set alt i386-x86_64 } default { set alt {} } } if {$v ne ""} { foreach {major minor} [split $v .] break # Add 10.5 to 10.minor to patterns. set res {} for {set j $minor} {$j >= 5} {incr j -1} { lappend res macosx${major}.${j}-${cpu} lappend res macosx${major}.${j}-universal if {$alt ne {}} { lappend res macosx${major}.${j}-$alt } } # Add unversioned patterns for 10.3/10.4 builds. lappend res macosx-${cpu} lappend res macosx-universal if {$alt ne {}} { lappend res macosx-$alt } } else { lappend res macosx-universal if {$alt ne {}} { lappend res macosx-$alt } } } else { lappend res macosx-universal } } macosx-powerpc { lappend res macosx-universal } macosx-x86_64 - macosx-ix86 { lappend res macosx-universal macosx-i386-x86_64 } } lappend res tcl ; # Pure tcl packages are always compatible. return $res } # ### ### ### ######### ######### ######### ## Ready package provide platform 1.0.12 # ### ### ### ######### ######### ######### ## Demo application if {[info exists argv0] && ($argv0 eq [info script])} { puts ==================================== parray tcl_platform puts ==================================== puts Generic\ identification:\ [::platform::generic] puts Exact\ identification:\ \ \ [::platform::identify] puts ==================================== puts Search\ patterns: puts *\ [join [::platform::patterns [::platform::identify]] \n*\ ] puts ==================================== exit 0 } tcl8.4.20/library/platform/shell.tcl0000644003604700454610000001353112052456744016024 0ustar dgp771div # -*- tcl -*- # ### ### ### ######### ######### ######### ## Overview # Higher-level commands which invoke the functionality of this package # for an arbitrary tcl shell (tclsh, wish, ...). This is required by a # repository as while the tcl shell executing packages uses the same # platform in general as a repository application there can be # differences in detail (i.e. 32/64 bit builds). # ### ### ### ######### ######### ######### ## Requirements package require platform namespace eval ::platform::shell {} # ### ### ### ######### ######### ######### ## Implementation # -- platform::shell::generic proc ::platform::shell::generic {shell} { # Argument is the path to a tcl shell. CHECK $shell LOCATE base out set code {} # Forget any pre-existing platform package, it might be in # conflict with this one. lappend code {package forget platform} # Inject our platform package lappend code [list source $base] # Query and print the architecture lappend code {puts [platform::generic]} # And done lappend code {exit 0} set arch [RUN $shell [join $code \n]] if {$out} {file delete -force $base} return $arch } # -- platform::shell::identify proc ::platform::shell::identify {shell} { # Argument is the path to a tcl shell. CHECK $shell LOCATE base out set code {} # Forget any pre-existing platform package, it might be in # conflict with this one. lappend code {package forget platform} # Inject our platform package lappend code [list source $base] # Query and print the architecture lappend code {puts [platform::identify]} # And done lappend code {exit 0} set arch [RUN $shell [join $code \n]] if {$out} {file delete -force $base} return $arch } # -- platform::shell::platform proc ::platform::shell::platform {shell} { # Argument is the path to a tcl shell. CHECK $shell set code {} lappend code {puts $tcl_platform(platform)} lappend code {exit 0} return [RUN $shell [join $code \n]] } # ### ### ### ######### ######### ######### ## Internal helper commands. proc ::platform::shell::CHECK {shell} { if {![file exists $shell]} { return -code error "Shell \"$shell\" does not exist" } if {![file executable $shell]} { return -code error "Shell \"$shell\" is not executable (permissions)" } return } proc ::platform::shell::LOCATE {bv ov} { upvar 1 $bv base $ov out # Locate the platform package for injection into the specified # shell. We are using package management to find it, whereever it # is, instead of using hardwired relative paths. This allows us to # install the two packages as TMs without breaking the code # here. If the found package is wrapped we copy the code somewhere # where the spawned shell will be able to read it. # This code is brittle, it needs has to adapt to whatever changes # are made to the TM code, i.e. the provide statement generated by # tm.tcl set pl [package ifneeded platform [package require platform]] set base [lindex $pl end] set out 0 if {[lindex [file system $base]] ne "native"} { set temp [TEMP] file copy -force $base $temp set base $temp set out 1 } return } proc ::platform::shell::RUN {shell code} { set c [TEMP] set cc [open $c w] puts $cc $code close $cc set e [TEMP] set code [catch { exec $shell $c 2> $e } res] file delete $c if {$code} { append res \n[read [set chan [open $e r]]][close $chan] file delete $e return -code error "Shell \"$shell\" is not executable ($res)" } file delete $e return $res } proc ::platform::shell::TEMP {} { set prefix platform # This code is copied out of Tcllib's fileutil package. # (TempFile/tempfile) set tmpdir [DIR] set chars "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" set nrand_chars 10 set maxtries 10 set access [list RDWR CREAT EXCL TRUNC] set permission 0600 set channel "" set checked_dir_writable 0 set mypid [pid] for {set i 0} {$i < $maxtries} {incr i} { set newname $prefix for {set j 0} {$j < $nrand_chars} {incr j} { append newname [string index $chars \ [expr {int(rand()*62)}]] } set newname [file join $tmpdir $newname] if {[file exists $newname]} { after 1 } else { if {[catch {open $newname $access $permission} channel]} { if {!$checked_dir_writable} { set dirname [file dirname $newname] if {![file writable $dirname]} { return -code error "Directory $dirname is not writable" } set checked_dir_writable 1 } } else { # Success close $channel return [file normalize $newname] } } } if {$channel != ""} { return -code error "Failed to open a temporary file: $channel" } else { return -code error "Failed to find an unused temporary file name" } } proc ::platform::shell::DIR {} { # This code is copied out of Tcllib's fileutil package. # (TempDir/tempdir) global tcl_platform env set attempdirs [list] foreach tmp {TMPDIR TEMP TMP} { if { [info exists env($tmp)] } { lappend attempdirs $env($tmp) } } switch $tcl_platform(platform) { windows { lappend attempdirs "C:\\TEMP" "C:\\TMP" "\\TEMP" "\\TMP" } macintosh { set tmpdir $env(TRASH_FOLDER) ;# a better place? } default { lappend attempdirs \ [file join / tmp] \ [file join / var tmp] \ [file join / usr tmp] } } lappend attempdirs [pwd] foreach tmp $attempdirs { if { [file isdirectory $tmp] && [file writable $tmp] } { return [file normalize $tmp] } } # Fail if nothing worked. return -code error "Unable to determine a proper directory for temporary files" } # ### ### ### ######### ######### ######### ## Ready package provide platform::shell 1.1.4 tcl8.4.20/library/http1.0/0000755003604700454610000000000012153151142013542 5ustar dgp771divtcl8.4.20/library/http1.0/pkgIndex.tcl0000644003604700454610000000133711737050674016042 0ustar dgp771div# Tcl package index file, version 1.0 # This file is generated by the "pkg_mkIndex" command # and sourced either when an application starts up or # by a "package unknown" script. It invokes the # "package ifneeded" command to set up package-related # information so that packages will be loaded automatically # in response to "package require" commands. When this # script is sourced, the variable $dir must contain the # full path name of this file's directory. package ifneeded http 1.0 [list tclPkgSetup $dir http 1.0 {{http.tcl source {httpCopyDone httpCopyStart httpEof httpEvent httpFinish httpMapReply httpProxyRequired http_code http_config http_data http_formatQuery http_get http_reset http_size http_status http_wait}}}] tcl8.4.20/library/http1.0/http.tcl0000644003604700454610000002273511737050674015255 0ustar dgp771div# http.tcl # Client-side HTTP for GET, POST, and HEAD commands. # These routines can be used in untrusted code that uses the Safesock # security policy. # These procedures use a callback interface to avoid using vwait, # which is not defined in the safe base. # # See the http.n man page for documentation package provide http 1.0 array set http { -accept */* -proxyhost {} -proxyport {} -useragent {Tcl http client package 1.0} -proxyfilter httpProxyRequired } proc http_config {args} { global http set options [lsort [array names http -*]] set usage [join $options ", "] if {[llength $args] == 0} { set result {} foreach name $options { lappend result $name $http($name) } return $result } regsub -all -- - $options {} options set pat ^-([join $options |])$ if {[llength $args] == 1} { set flag [lindex $args 0] if {[regexp -- $pat $flag]} { return $http($flag) } else { return -code error "Unknown option $flag, must be: $usage" } } else { foreach {flag value} $args { if {[regexp -- $pat $flag]} { set http($flag) $value } else { return -code error "Unknown option $flag, must be: $usage" } } } } proc httpFinish { token {errormsg ""} } { upvar #0 $token state global errorInfo errorCode if {[string length $errormsg] != 0} { set state(error) [list $errormsg $errorInfo $errorCode] set state(status) error } catch {close $state(sock)} catch {after cancel $state(after)} if {[info exists state(-command)]} { if {[catch {eval $state(-command) {$token}} err]} { if {[string length $errormsg] == 0} { set state(error) [list $err $errorInfo $errorCode] set state(status) error } } unset state(-command) } } proc http_reset { token {why reset} } { upvar #0 $token state set state(status) $why catch {fileevent $state(sock) readable {}} httpFinish $token if {[info exists state(error)]} { set errorlist $state(error) unset state(error) eval error $errorlist } } proc http_get { url args } { global http if {![info exists http(uid)]} { set http(uid) 0 } set token http#[incr http(uid)] upvar #0 $token state http_reset $token array set state { -blocksize 8192 -validate 0 -headers {} -timeout 0 state header meta {} currentsize 0 totalsize 0 type text/html body {} status "" } set options {-blocksize -channel -command -handler -headers \ -progress -query -validate -timeout} set usage [join $options ", "] regsub -all -- - $options {} options set pat ^-([join $options |])$ foreach {flag value} $args { if {[regexp $pat $flag]} { # Validate numbers if {[info exists state($flag)] && \ [regexp {^[0-9]+$} $state($flag)] && \ ![regexp {^[0-9]+$} $value]} { return -code error "Bad value for $flag ($value), must be integer" } set state($flag) $value } else { return -code error "Unknown option $flag, can be: $usage" } } if {! [regexp -nocase {^(http://)?([^/:]+)(:([0-9]+))?(/.*)?$} $url \ x proto host y port srvurl]} { error "Unsupported URL: $url" } if {[string length $port] == 0} { set port 80 } if {[string length $srvurl] == 0} { set srvurl / } if {[string length $proto] == 0} { set url http://$url } set state(url) $url if {![catch {$http(-proxyfilter) $host} proxy]} { set phost [lindex $proxy 0] set pport [lindex $proxy 1] } if {$state(-timeout) > 0} { set state(after) [after $state(-timeout) [list http_reset $token timeout]] } if {[info exists phost] && [string length $phost]} { set srvurl $url set s [socket $phost $pport] } else { set s [socket $host $port] } set state(sock) $s # Send data in cr-lf format, but accept any line terminators fconfigure $s -translation {auto crlf} -buffersize $state(-blocksize) # The following is disallowed in safe interpreters, but the socket # is already in non-blocking mode in that case. catch {fconfigure $s -blocking off} set len 0 set how GET if {[info exists state(-query)]} { set len [string length $state(-query)] if {$len > 0} { set how POST } } elseif {$state(-validate)} { set how HEAD } puts $s "$how $srvurl HTTP/1.0" puts $s "Accept: $http(-accept)" puts $s "Host: $host" puts $s "User-Agent: $http(-useragent)" foreach {key value} $state(-headers) { regsub -all \[\n\r\] $value {} value set key [string trim $key] if {[string length $key]} { puts $s "$key: $value" } } if {$len > 0} { puts $s "Content-Length: $len" puts $s "Content-Type: application/x-www-form-urlencoded" puts $s "" fconfigure $s -translation {auto binary} puts -nonewline $s $state(-query) } else { puts $s "" } flush $s fileevent $s readable [list httpEvent $token] if {! [info exists state(-command)]} { http_wait $token } return $token } proc http_data {token} { upvar #0 $token state return $state(body) } proc http_status {token} { upvar #0 $token state return $state(status) } proc http_code {token} { upvar #0 $token state return $state(http) } proc http_size {token} { upvar #0 $token state return $state(currentsize) } proc httpEvent {token} { upvar #0 $token state set s $state(sock) if {[eof $s]} { httpEof $token return } if {$state(state) == "header"} { set n [gets $s line] if {$n == 0} { set state(state) body if {![regexp -nocase ^text $state(type)]} { # Turn off conversions for non-text data fconfigure $s -translation binary if {[info exists state(-channel)]} { fconfigure $state(-channel) -translation binary } } if {[info exists state(-channel)] && ![info exists state(-handler)]} { # Initiate a sequence of background fcopies fileevent $s readable {} httpCopyStart $s $token } } elseif {$n > 0} { if {[regexp -nocase {^content-type:(.+)$} $line x type]} { set state(type) [string trim $type] } if {[regexp -nocase {^content-length:(.+)$} $line x length]} { set state(totalsize) [string trim $length] } if {[regexp -nocase {^([^:]+):(.+)$} $line x key value]} { lappend state(meta) $key $value } elseif {[regexp ^HTTP $line]} { set state(http) $line } } } else { if {[catch { if {[info exists state(-handler)]} { set n [eval $state(-handler) {$s $token}] } else { set block [read $s $state(-blocksize)] set n [string length $block] if {$n >= 0} { append state(body) $block } } if {$n >= 0} { incr state(currentsize) $n } } err]} { httpFinish $token $err } else { if {[info exists state(-progress)]} { eval $state(-progress) {$token $state(totalsize) $state(currentsize)} } } } } proc httpCopyStart {s token} { upvar #0 $token state if {[catch { fcopy $s $state(-channel) -size $state(-blocksize) -command \ [list httpCopyDone $token] } err]} { httpFinish $token $err } } proc httpCopyDone {token count {error {}}} { upvar #0 $token state set s $state(sock) incr state(currentsize) $count if {[info exists state(-progress)]} { eval $state(-progress) {$token $state(totalsize) $state(currentsize)} } if {([string length $error] != 0)} { httpFinish $token $error } elseif {[eof $s]} { httpEof $token } else { httpCopyStart $s $token } } proc httpEof {token} { upvar #0 $token state if {$state(state) == "header"} { # Premature eof set state(status) eof } else { set state(status) ok } set state(state) eof httpFinish $token } proc http_wait {token} { upvar #0 $token state if {![info exists state(status)] || [string length $state(status)] == 0} { vwait $token\(status) } if {[info exists state(error)]} { set errorlist $state(error) unset state(error) eval error $errorlist } return $state(status) } # Call http_formatQuery with an even number of arguments, where the first is # a name, the second is a value, the third is another name, and so on. proc http_formatQuery {args} { set result "" set sep "" foreach i $args { append result $sep [httpMapReply $i] if {$sep != "="} { set sep = } else { set sep & } } return $result } # do x-www-urlencoded character mapping # The spec says: "non-alphanumeric characters are replaced by '%HH'" # 1 leave alphanumerics characters alone # 2 Convert every other character to an array lookup # 3 Escape constructs that are "special" to the tcl parser # 4 "subst" the result, doing all the array substitutions proc httpMapReply {string} { global httpFormMap set alphanumeric a-zA-Z0-9 if {![info exists httpFormMap]} { for {set i 1} {$i <= 256} {incr i} { set c [format %c $i] if {![string match \[$alphanumeric\] $c]} { set httpFormMap($c) %[format %.2x $i] } } # These are handled specially array set httpFormMap { " " + \n %0d%0a } } regsub -all \[^$alphanumeric\] $string {$httpFormMap(&)} string regsub -all \n $string {\\n} string regsub -all \t $string {\\t} string regsub -all {[][{})\\]\)} $string {\\&} string return [subst $string] } # Default proxy filter. proc httpProxyRequired {host} { global http if {[info exists http(-proxyhost)] && [string length $http(-proxyhost)]} { if {![info exists http(-proxyport)] || ![string length $http(-proxyport)]} { set http(-proxyport) 8080 } return [list $http(-proxyhost) $http(-proxyport)] } else { return {} } } tcl8.4.20/library/msgcat/0000755003604700454610000000000012153151142013622 5ustar dgp771divtcl8.4.20/library/msgcat/pkgIndex.tcl0000644003604700454610000000020612052456744016113 0ustar dgp771divif {![package vsatisfies [package provide Tcl] 8.2]} {return} package ifneeded msgcat 1.3.5 [list source [file join $dir msgcat.tcl]] tcl8.4.20/library/msgcat/msgcat.tcl0000644003604700454610000003130012052456744015617 0ustar dgp771div# msgcat.tcl -- # # This file defines various procedures which implement a # message catalog facility for Tcl programs. It should be # loaded with the command "package require msgcat". # # Copyright (c) 1998-2000 by Ajuba Solutions. # Copyright (c) 1998 by Mark Harrison. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. package require Tcl 8.2 # When the version number changes, be sure to update the pkgIndex.tcl file, # and the installation directory in the Makefiles. package provide msgcat 1.3.5 namespace eval msgcat { namespace export mc mcload mclocale mcmax mcmset mcpreferences mcset \ mcunknown # Records the current locale as passed to mclocale variable Locale "" # Records the list of locales to search variable Loclist {} # Records the mapping between source strings and translated strings. The # array key is of the form ",," and the value is # the translated string. array set Msgs {} # Map of language codes used in Windows registry to those of ISO-639 if {[info sharedlibextension] eq ".dll"} { array set WinRegToISO639 { 01 ar 0401 ar_SA 0801 ar_IQ 0c01 ar_EG 1001 ar_LY 1401 ar_DZ 1801 ar_MA 1c01 ar_TN 2001 ar_OM 2401 ar_YE 2801 ar_SY 2c01 ar_JO 3001 ar_LB 3401 ar_KW 3801 ar_AE 3c01 ar_BH 4001 ar_QA 02 bg 0402 bg_BG 03 ca 0403 ca_ES 04 zh 0404 zh_TW 0804 zh_CN 0c04 zh_HK 1004 zh_SG 1404 zh_MO 05 cs 0405 cs_CZ 06 da 0406 da_DK 07 de 0407 de_DE 0807 de_CH 0c07 de_AT 1007 de_LU 1407 de_LI 08 el 0408 el_GR 09 en 0409 en_US 0809 en_GB 0c09 en_AU 1009 en_CA 1409 en_NZ 1809 en_IE 1c09 en_ZA 2009 en_JM 2409 en_GD 2809 en_BZ 2c09 en_TT 3009 en_ZW 3409 en_PH 0a es 040a es_ES 080a es_MX 0c0a es_ES@modern 100a es_GT 140a es_CR 180a es_PA 1c0a es_DO 200a es_VE 240a es_CO 280a es_PE 2c0a es_AR 300a es_EC 340a es_CL 380a es_UY 3c0a es_PY 400a es_BO 440a es_SV 480a es_HN 4c0a es_NI 500a es_PR 0b fi 040b fi_FI 0c fr 040c fr_FR 080c fr_BE 0c0c fr_CA 100c fr_CH 140c fr_LU 180c fr_MC 0d he 040d he_IL 0e hu 040e hu_HU 0f is 040f is_IS 10 it 0410 it_IT 0810 it_CH 11 ja 0411 ja_JP 12 ko 0412 ko_KR 13 nl 0413 nl_NL 0813 nl_BE 14 no 0414 no_NO 0814 nn_NO 15 pl 0415 pl_PL 16 pt 0416 pt_BR 0816 pt_PT 17 rm 0417 rm_CH 18 ro 0418 ro_RO 0818 ro_MO 19 ru 0819 ru_MO 1a hr 041a hr_HR 081a sr_YU 0c1a sr_YU@cyrillic 1b sk 041b sk_SK 1c sq 041c sq_AL 1d sv 041d sv_SE 081d sv_FI 1e th 041e th_TH 1f tr 041f tr_TR 20 ur 0420 ur_PK 0820 ur_IN 21 id 0421 id_ID 22 uk 0422 uk_UA 23 be 0423 be_BY 24 sl 0424 sl_SI 25 et 0425 et_EE 26 lv 0426 lv_LV 27 lt 0427 lt_LT 28 tg 0428 tg_TJ 29 fa 0429 fa_IR 2a vi 042a vi_VN 2b hy 042b hy_AM 2c az 042c az_AZ@latin 082c az_AZ@cyrillic 2d eu 2e wen 042e wen_DE 2f mk 042f mk_MK 30 bnt 0430 bnt_TZ 31 ts 0431 ts_ZA 32 tn 33 ven 0433 ven_ZA 34 xh 0434 xh_ZA 35 zu 0435 zu_ZA 36 af 0436 af_ZA 37 ka 0437 ka_GE 38 fo 0438 fo_FO 39 hi 0439 hi_IN 3a mt 043a mt_MT 3b se 043b se_NO 043c gd_UK 083c ga_IE 3d yi 043d yi_IL 3e ms 043e ms_MY 083e ms_BN 3f kk 043f kk_KZ 40 ky 0440 ky_KG 41 sw 0441 sw_KE 42 tk 0442 tk_TM 43 uz 0443 uz_UZ@latin 0843 uz_UZ@cyrillic 44 tt 0444 tt_RU 45 bn 0445 bn_IN 46 pa 0446 pa_IN 47 gu 0447 gu_IN 48 or 0448 or_IN 49 ta 4a te 044a te_IN 4b kn 044b kn_IN 4c ml 044c ml_IN 4d as 044d as_IN 4e mr 044e mr_IN 4f sa 044f sa_IN 50 mn 51 bo 0451 bo_CN 52 cy 0452 cy_GB 53 km 0453 km_KH 54 lo 0454 lo_LA 55 my 0455 my_MM 56 gl 0456 gl_ES 57 kok 0457 kok_IN 58 mni 0458 mni_IN 59 sd 5a syr 045a syr_TR 5b si 045b si_LK 5c chr 045c chr_US 5d iu 045d iu_CA 5e am 045e am_ET 5f ber 045f ber_MA 60 ks 0460 ks_PK 0860 ks_IN 61 ne 0461 ne_NP 0861 ne_IN 62 fy 0462 fy_NL 63 ps 64 tl 0464 tl_PH 65 div 0465 div_MV 66 bin 0466 bin_NG 67 ful 0467 ful_NG 68 ha 0468 ha_NG 69 nic 0469 nic_NG 6a yo 046a yo_NG 70 ibo 0470 ibo_NG 71 kau 0471 kau_NG 72 om 0472 om_ET 73 ti 0473 ti_ET 74 gn 0474 gn_PY 75 cpe 0475 cpe_US 76 la 0476 la_VA 77 so 0477 so_SO 78 sit 0478 sit_CN 79 pap 0479 pap_AN } } } # msgcat::mc -- # # Find the translation for the given string based on the current # locale setting. Check the local namespace first, then look in each # parent namespace until the source is found. If additional args are # specified, use the format command to work them into the traslated # string. # # Arguments: # src The string to translate. # args Args to pass to the format command # # Results: # Returns the translated string. Propagates errors thrown by the # format command. proc msgcat::mc {src args} { # Check for the src in each namespace starting from the local and # ending in the global. variable Msgs variable Loclist variable Locale set ns [uplevel 1 [list ::namespace current]] while {$ns != ""} { foreach loc $Loclist { if {[info exists Msgs($loc,$ns,$src)]} { if {[llength $args] == 0} { return $Msgs($loc,$ns,$src) } else { return [uplevel 1 \ [linsert $args 0 ::format $Msgs($loc,$ns,$src)]] } } } set ns [namespace parent $ns] } # we have not found the translation return [uplevel 1 \ [linsert $args 0 [::namespace origin mcunknown] $Locale $src]] } # msgcat::mclocale -- # # Query or set the current locale. # # Arguments: # newLocale (Optional) The new locale string. Locale strings # should be composed of one or more sublocale parts # separated by underscores (e.g. en_US). # # Results: # Returns the current locale. proc msgcat::mclocale {args} { variable Loclist variable Locale set len [llength $args] if {$len > 1} { error {wrong # args: should be "mclocale ?newLocale?"} } if {$len == 1} { set newLocale [lindex $args 0] if {$newLocale ne [file tail $newLocale]} { return -code error "invalid newLocale value \"$newLocale\":\ could be path to unsafe code." } set Locale [string tolower $newLocale] set Loclist {} set word "" foreach part [split $Locale _] { set word [string trimleft "${word}_${part}" _] set Loclist [linsert $Loclist 0 $word] } } return $Locale } # msgcat::mcpreferences -- # # Fetch the list of locales used to look up strings, ordered from # most preferred to least preferred. # # Arguments: # None. # # Results: # Returns an ordered list of the locales preferred by the user. proc msgcat::mcpreferences {} { variable Loclist return $Loclist } # msgcat::mcload -- # # Attempt to load message catalogs for each locale in the # preference list from the specified directory. # # Arguments: # langdir The directory to search. # # Results: # Returns the number of message catalogs that were loaded. proc msgcat::mcload {langdir} { set x 0 foreach p [mcpreferences] { set langfile [file join $langdir $p.msg] if {[file exists $langfile]} { incr x set fid [open $langfile "r"] fconfigure $fid -encoding utf-8 uplevel 1 [read $fid] close $fid } } return $x } # msgcat::mcset -- # # Set the translation for a given string in a specified locale. # # Arguments: # locale The locale to use. # src The source string. # dest (Optional) The translated string. If omitted, # the source string is used. # # Results: # Returns the new locale. proc msgcat::mcset {locale src {dest ""}} { variable Msgs if {[llength [info level 0]] == 3} { ;# dest not specified set dest $src } set ns [uplevel 1 [list ::namespace current]] set Msgs([string tolower $locale],$ns,$src) $dest return $dest } # msgcat::mcmset -- # # Set the translation for multiple strings in a specified locale. # # Arguments: # locale The locale to use. # pairs One or more src/dest pairs (must be even length) # # Results: # Returns the number of pairs processed proc msgcat::mcmset {locale pairs } { variable Msgs set length [llength $pairs] if {$length % 2} { error {bad translation list: should be "mcmset locale {src dest ...}"} } set locale [string tolower $locale] set ns [uplevel 1 [list ::namespace current]] foreach {src dest} $pairs { set Msgs($locale,$ns,$src) $dest } return $length } # msgcat::mcunknown -- # # This routine is called by msgcat::mc if a translation cannot # be found for a string. This routine is intended to be replaced # by an application specific routine for error reporting # purposes. The default behavior is to return the source string. # If additional args are specified, the format command will be used # to work them into the traslated string. # # Arguments: # locale The current locale. # src The string to be translated. # args Args to pass to the format command # # Results: # Returns the translated value. proc msgcat::mcunknown {locale src args} { if {[llength $args]} { return [uplevel 1 [linsert $args 0 ::format $src]] } else { return $src } } # msgcat::mcmax -- # # Calculates the maximum length of the translated strings of the given # list. # # Arguments: # args strings to translate. # # Results: # Returns the length of the longest translated string. proc msgcat::mcmax {args} { set max 0 foreach string $args { set translated [uplevel 1 [list [namespace origin mc] $string]] set len [string length $translated] if {$len>$max} { set max $len } } return $max } # Convert the locale values stored in environment variables to a form # suitable for passing to [mclocale] proc msgcat::ConvertLocale {value} { # Assume $value is of form: $language[_$territory][.$codeset][@modifier] # Convert to form: $language[_$territory][_$modifier] # # Comment out expanded RE version -- bugs alleged # regexp -expanded { # ^ # Match all the way to the beginning # ([^_.@]*) # Match "lanugage"; ends with _, ., or @ # (_([^.@]*))? # Match (optional) "territory"; starts with _ # ([.]([^@]*))? # Match (optional) "codeset"; starts with . # (@(.*))? # Match (optional) "modifier"; starts with @ # $ # Match all the way to the end # } $value -> language _ territory _ codeset _ modifier if {![regexp {^([^_.@]+)(_([^.@]*))?([.]([^@]*))?(@(.*))?$} $value \ -> language _ territory _ codeset _ modifier]} { return -code error "invalid locale '$value': empty language part" } set ret $language if {[string length $territory]} { append ret _$territory } if {[string length $modifier]} { append ret _$modifier } return $ret } # Initialize the default locale proc msgcat::Init {} { global env # # set default locale, try to get from environment # foreach varName {LC_ALL LC_MESSAGES LANG} { if {[info exists env($varName)] && ![string equal "" $env($varName)]} { if {![catch {mclocale [ConvertLocale $env($varName)]}]} { return } } } # # On Darwin, fallback to current CFLocale identifier if available. # if {[string equal $::tcl_platform(os) Darwin] && [string equal $::tcl_platform(platform) unix] && [info exists ::tcl::mac::locale] && ![string equal $::tcl::mac::locale ""]} { if {![catch {mclocale [ConvertLocale $::tcl::mac::locale]}]} { return } } # # The rest of this routine is special processing for Windows; # all other platforms, get out now. # if {![string equal [info sharedlibextension] .dll]} { mclocale C return } # # On Windows or Cygwin, try to set locale depending on registry # settings, or fall back on locale of "C". # set key {HKEY_CURRENT_USER\Control Panel\International} if {[catch {package require registry}] \ || [catch {registry get $key "locale"} locale]} { mclocale C return } # # Keep trying to match against smaller and smaller suffixes # of the registry value, since the latter hexadigits appear # to determine general language and earlier hexadigits determine # more precise information, such as territory. For example, # 0409 - English - United States # 0809 - English - United Kingdom # Add more translations to the WinRegToISO639 array above. # variable WinRegToISO639 set locale [string tolower $locale] while {[string length $locale]} { if {![catch {mclocale [ConvertLocale $WinRegToISO639($locale)]}]} { return } set locale [string range $locale 1 end] } # # No translation known. Fall back on "C" locale # mclocale C } msgcat::Init tcl8.4.20/changes0000644003604700454610000106703412144477352012264 0ustar dgp771divRecent user-visible changes to Tcl: 1. No more [command1] [command2] construct for grouping multiple commands on a single command line. 2. Semi-colon now available for grouping commands on a line. 3. For a command to span multiple lines, must now use backslash-return at the end of each line but the last. 4. "Var" command has been changed to "set". 5. Double-quotes now available as an argument grouping character. 6. "Return" may be used at top-level. 7. More backslash sequences available now. In particular, backslash-newline may be used to join lines in command files. 8. New or modified built-in commands: case, return, for, glob, info, print, return, set, source, string, uplevel. 9. After an error, the variable "errorInfo" is filled with a stack trace showing what was being executed when the error occurred. 10. Command abbreviations are accepted when parsing commands, but are not recommended except for purely-interactive commands. 11. $, set, and expr all complain now if a non-existent variable is referenced. 12. History facilities exist now. See Tcl.man and Tcl_RecordAndEval.man. 13. Changed to distinguish between empty variables and those that don't exist at all. Interfaces to Tcl_GetVar and Tcl_ParseVar have changed (NULL return value is now possible). *** POTENTIAL INCOMPATIBILITY *** 14. Changed meaning of "level" argument to "uplevel" command (1 now means "go up one level", not "go to level 1"; "#1" means "go to level 1"). *** POTENTIAL INCOMPATIBILITY *** 15. 3/19/90 Added "info exists" option to see if variable exists. 16. 3/19/90 Added "noAbbrev" variable to prohibit command abbreviations. 17. 3/19/90 Added extra errorInfo option to "error" command. 18. 3/21/90 Double-quotes now only affect space: command, variable, and backslash substitutions still occur inside double-quotes. *** POTENTIAL INCOMPATIBILITY *** 19. 3/21/90 Added support for \r. 20. 3/21/90 List, concat, eval, and glob commands all expect at least one argument now. *** POTENTIAL INCOMPATIBILITY *** 21. 3/22/90 Added "?:" operators to expressions. 22. 3/25/90 Fixed bug in Tcl_Result that caused memory to get trashed. ------------------- Released version 3.1 --------------------- 23. 3/29/90 Fixed bug that caused "file a.b/c ext" to return ".b/c". 24. 3/29/90 Semi-colon is not treated specially when enclosed in double-quotes. ------------------- Released version 3.2 --------------------- 25. 4/16/90 Rewrote "exec" not to use select or signals anymore. Should be more Sys-V compatible, and no slower in the normal case. 26. 4/18/90 Rewrote "glob" to eliminate GNU code (there's no GNU code left in Tcl, now), and added Tcl_TildeSubst procedure. Added automatic tilde-substitution in many commands, including "glob". ------------------- Released version 3.3 --------------------- 27. 7/11/90 Added "Tcl_AppendResult" procedure. 28. 7/20/90 "History" with no options now defaults to "history info" rather than to "history redo". Although this is a backward incompatibility, it should only be used interactively and thus shouldn't present any compatibility problems with scripts. 29. 7/20/90 Added "Tcl_GetInteger", "Tcl_GetDouble", and "Tcl_GetBoolean" procedures. 30. 7/22/90 Removed "Tcl_WatchInterp" procedure: doesn't seem to be necessary, since the same effect can be achieved with the deletion callbacks on individual commands. *** POTENTIAL INCOMPATIBILITY *** 31. 7/23/90 Added variable tracing: Tcl_TraceVar, Tcl_UnTraceVar, and Tcl_VarTraceInfo procedures, "trace" command. 32. 8/9/90 Mailed out list of all bug fixes since 3.3 release. 33. 8/29/90 Fixed bugs in Tcl_Merge relating to backslashes and semi-colons. Mailed out patch. 34. 9/3/90 Fixed bug in tclBasic.c: quotes weren't quoting ]'s. Mailed out patch. 35. 9/19/90 Rewrote exec to always use files both for input and output to the process. The old pipe-based version didn't work if the exec'ed process forked a child and then exited: Tcl waited around for stdout to get closed, which didn't happen until the grandchild exited. 36. 11/5/90 ERR_IN_PROGRESS flag wasn't being cleared soon enough in Tcl_Eval, allowing error messages from different commands to pile up in $errorInfo. Fixed by re-arranging code in Tcl_Eval that re-initializes result and ERR_IN_PROGRESS flag. Didn't mail out patch: changes too complicated to describe. 37. 12/19/90 Added Tcl_VarEval procedure as a convenience for assembling and executing Tcl commands. 38. 1/29/91 Fixed core leak in Tcl_AddErrorInfo. Also changed procedure and Tcl_Eval so that first call to Tcl_AddErrorInfo need not come from Tcl_Eval. ----------------- Released version 5.0 with Tk ------------------ 39. 4/3/91 Removed change bars from manual entries, leaving only those that came after version 3.3 was released. 40. 5/17/91 Changed tests to conform to Mary Ann May-Pumphrey's approach. 41. 5/23/91 Massive revision to Tcl parser to simplify the implementation of string and floating-point support in expressions. Newlines inside [] are now treated as command separators rather than word separators (this makes newline treatment consistent throughout Tcl). *** POTENTIAL INCOMPATIBILITY *** 42. 5/23/91 Massive rewrite of expression code to support floating-point values and simple string comparisons. The C interfaces to expression routines have changed (Tcl_Expr is replaced by Tcl_ExprLong, Tcl_ExprDouble, etc.), but all old Tcl expression strings should be accepted by the new expression code. *** POTENTIAL INCOMPATIBILITY *** 43. 5/23/91 Modified tclHistory.c to check for negative "keep" value. 44. 5/23/91 Modified Tcl_Backslash to handle backslash-newline. It now returns 0 to indicate that a backslash sequence should be replaced by no character at all. *** POTENTIAL INCOMPATIBILITY *** 45. 5/29/91 Modified to use ANSI C function prototypes. Must set "USE_ANSI" switch when compiling to get prototypes. 46. 5/29/91 Completed test suite by providing tests for all of the built-in Tcl commands. 47. 5/29/91 Changed Tcl_Concat to eliminate leading and trailing white-space in each of the things it concatenates and to ignore elements that are empty or have only white space in them. This produces cleaner output from the "concat" command. *** POTENTIAL INCOMPATIBILITY *** 48. 5/31/91 Changed "set" command and Tcl_SetVar procedure to return new value of variable. 49. 6/1/91 Added "while" and "cd" commands. 50. 6/1/91 Changed "exec" to delete the last character of program output if it is a newline. In most cases this makes it easier to process program-generated output. *** POTENTIAL INCOMPATIBILITY *** 51. 6/1/91 Made sure that pointers are never used after freeing them. 52. 6/1/91 Fixed bug in TclWordEnd where it wasn't dealing with [] inside quotes correctly. 53. 6/8/91 Fixed exec.test to accept return values of either 1 or 255 from "false" command. 54. 7/6/91 Massive overhaul of variable management. Associative arrays now available, along with "unset" command (and Tcl_UnsetVar procedure). Variable traces have been completely reworked: interfaces different both from Tcl and C, and multiple traces may exist on same variable. Can no longer redefine existing local variable to be global. Calling sequences have changed slightly for Tcl_GetVar and Tcl_SetVar ("global" is now "flags"). Tcl_SetVar can fail and return a NULL result. New forms of variable-manipulation procedures: Tcl_GetVar2, Tcl_SetVar2, etc. Syntax of variable $-notation changed to support array indexing. *** POTENTIAL INCOMPATIBILITY *** 55. 7/6/91 Added new list-manipulation procedures: Tcl_ScanElement, Tcl_ConvertElement, Tcl_AppendElement. 56. 7/12/91 Created new procedure Tcl_EvalFile, which does most of the work of the "source" command. 57. 7/20/91 Major reworking of "exec" command to allow pipelines, more redirection, background. Added new procedures Tcl_Fork, Tcl_WaitPids, Tcl_DetachPids, and Tcl_CreatePipeline. The old "< input" notation has been replaced by "<< input" ("<" is for redirection from a file). Also handles error returns and abnormal terminations (e.g. signals) differently. *** POTENTIAL INCOMPATIBILITY *** 58. 7/21/91 Added "append" and "lappend" commands. 59. 7/22/91 Reworked error messages and manual entries to use ?x? as the notation for an optional argument x, instead of [x]. The bracket notation was often confused with the use of brackets for command substitution. Also modified error messages to be more consistent. 60. 7/23/91 Tcl_DeleteCommand now returns an indication of whether or not the command actually existed, and the "rename" command uses this information to return an error if an attempt is made to delete a non-existent command. *** POTENTIAL INCOMPATIBILITY *** 61. 7/25/91 Added new "errorCode" mechanism, along with procedures Tcl_SetErrorCode, Tcl_UnixError, and Tcl_ResetResult. Renamed Tcl_Return to Tcl_SetResult, but left a #define for Tcl_Return to avoid compatibility problems. 62. 7/26/91 Extended "case" command with alternate syntax where all patterns and commands are together in a single list argument: makes it easier to write multi-line case statements. 63. 7/27/91 Changed "print" command to perform tilde-substitution on the file name. 64. 7/27/91 Added "tolower", "toupper", "trim", "trimleft", and "trimright" options to "string" command. 65. 7/29/91 Added "atime", "mtime", "size", and "stat" options to "file" command. 66. 8/1/91 Added "split" and "join" commands. 67. 8/11/91 Added commands for file I/O, including "open", "close", "read", "gets", "puts", "flush", "eof", "seek", and "tell". 68. 8/14/91 Switched to use a hash table for command lookups. Command abbreviations no longer have direct support in the Tcl interpreter, but it should be possible to simulate them with the auto-load features described below. The "noAbbrev" variable is no longer used by Tcl. *** POTENTIAL INCOMPATIBILITY *** 68.5 8/15/91 Added support for "unknown" command, which can be used to complete abbreviations, auto-load library files, auto-exec shell commands, etc. 69. 8/15/91 Added -nocomplain switch to "glob" command. 70. 8/20/91 Added "info library" option and TCL_LIBRARY #define. Also added "info script" option. 71. 8/20/91 Changed "file" command to take "option" argument as first argument (before file name), for consistency with other Tcl commands. *** POTENTIAL INCOMPATIBILITY *** 72. 8/20/91 Changed format of information in $errorInfo variable: comments such as ("while" body line 1) are now on separate lines from commands being executed. *** POTENTIAL INCOMPATIBILITY *** 73. 8/20/91 Changed Tcl_AppendResult so that it (eventually) frees large buffers that it allocates. 74. 8/21/91 Added "linsert", "lreplace", "lsearch", and "lsort" commands. 75. 8/28/91 Added "incr" and "exit" commands. 76. 8/30/91 Added "regexp" and "regsub" commands. 77. 9/4/91 Changed "dynamic" field in interpreters to "freeProc" (procedure address). This allows for alternative storage managers. *** POTENTIAL INCOMPATIBILITY *** 78. 9/6/91 Added "index", "length", and "range" options to "string" command. Added "lindex", "llength", and "lrange" commands. 79. 9/8/91 Removed "index", "length", "print" and "range" commands. "Print" is redundant with "puts", but less general, and the other commands are replaced with the new commands described in change 78 above. *** POTENTIAL INCOMPATIBILITY *** 80. 9/8/91 Changed history revision to occur even when history command is nested; needed in order to allow "history" to be invoked from "unknown" procedure. 81. 9/13/91 Changed "panic" not to use vfprintf (it's uglier and less general now, but makes it easier to run Tcl on systems that don't have vfprintf). Also changed "strerror" not to redeclare sys_errlist. 82. 9/19/91 Lots of changes to improve portability to different UNIX systems, including addition of "config" script to adapt Tcl to the configuration of the system it's being compiled on. 83. 9/22/91 Added "pwd" command. 84. 9/22/91 Renamed manual pages so that their filenames are no more than 14 characters in length, moved to "doc" subdirectory. 85. 9/24/91 Redid manual entries so they contain the supplemental macros that they need; can just print with "troff -man" or "man" now. 86. 9/26/91 Created initial version of script library, including a version of "unknown" that does auto-loading, auto-execution, and abbreviation expansion. This library is used by tclTest automatically. See the "library" manual entry for details. ----------------- Released version 6.0, 9/26/91 ------------------ 87. 9/30/91 Made "string tolower" and "string toupper" check case before converting: on some systems, "tolower" and "toupper" assume that character already has particular case. 88. 9/30/91 Fixed bug in Tcl_SetResult: wasn't always setting freeProc correctly when called with NULL value. This tended to cause memory allocation errors later. 89. 10/3/91 Added "upvar" command. 90. 10/4/91 Changed "format" so that internally it converts %D to %ld, %U to %lu, %O to %lo, and %F to %f. This eliminates some compatibility problems on some machines without affecting behavior. 91. 10/10/91 Fixed bug in "regsub" that caused core dumps with the -all option when the last match wasn't at the end of the string. 92. 10/17/91 Fixed problems with backslash sequences: \r support was incomplete and \f and \v weren't supported at all. 93. 10/24/91 Added Tcl_InitHistory procedure. 94. 10/24/91 Changed "regexp" to store "-1 -1" in subMatchVars that don't match, rather than returning an error. 95. 10/27/91 Modified "regexp" to return actual strings in matchVar and subMatchVars instead of indices. Added "-indices" switch to cause indices to be returned. *** POTENTIAL INCOMPATIBILITY *** 96. 10/27/91 Fixed bug in "scan" where it used hardwired constants for sizes of floats and doubles instead of using "sizeof". 97. 10/31/91 Fixed bug in tclParse.c where parse-related error messages weren't being storage-managed correctly, causing spurious free's. 98. 10/31/91 Form feed and vertical tab characters are now considered to be space characters by the parser. 99. 10/31/91 Added TCL_LEAVE_ERR_MSG flag to procedures like Tcl_SetVar. 100. 11/7/91 Fixed bug in "case" where "in" argument couldn't be omitted if all case branches were embedded in a single list. 101. 11/7/91 Switched to use "pid_t" and "uid_t" and other official POSIC types and function prototypes. ----------------- Released version 6.1, 11/7/91 ------------------ 102. 12/2/91 Modified Tcl_ScanElement and Tcl_ConvertElement in several ways. First, allowed caller to request that only backslashes be used (no braces). Second, made Tcl_ConvertElement more aggressive in using backslashes for braces and quotes. 103. 12/5/91 Added "type", "lstat", and "readlink" options to "file" command, plus added new "type" element to output of "stat" and "lstat" options. 104. 12/10/91 Manual entries had first lines that caused "man" program to try weird preprocessor. Added blank comment lines to fix problem. 105. 12/16/91 Fixed a few bugs in auto_mkindex proc: wasn't handling errors properly, and hadn't been upgraded for new "regexp" syntax. 106. 1/2/92 Fixed bug in "file" command where it didn't properly handle a file names containing tildes where the indicated user doesn't exist. 107. 1/2/92 Fixed lots of cases in tclUnixStr.c where two different errno symbols (e.g. EWOULDBLOCK and EAGAIN) have the same number; Tcl will only use one of them. 108. 1/2/92 Lots of changes to configuration script to handle many more systems more gracefully. E.g. should now detect the bogus strtoul that comes with AIX and substitute Tcl's own version instead. ----------------- Released version 6.2, 1/10/92 ------------------ 109. 1/20/92 Config didn't have code to actually use "uid_t" variable to set TCL_UIT_T #define. 110. 2/10/92 Tcl_Eval didn't properly reset "numLevels" variable when too-deep recursion occurred. 111. 2/29/92 Added "on" and "off" to keywords accepted by Tcl_GetBoolean. 112. 3/19/92 Config wasn't installing default version of strtod.c for systems that don't have one in libc.a. 113. 3/23/92 Fixed bug in tclExpr.c where numbers with leading "."s, like 0.75, couldn't be properly substituted into expressions with variable or command substitution. 114. 3/25/92 Fixed bug in tclUnixAZ.c where "gets" command wasn't checking to make sure that it was able to write the variable OK. 115. 4/16/92 Fixed bug in tclUnixAZ.c where "read" command didn't compute file size right for device files. 116. 4/23/92 Fixed but in tclCmdMZ.c where "trace vinfo" was overwriting the trace command. ----------------- Released version 6.3, 5/1/92 ------------------ 117. 5/1/92 Added Tcl_GlobalEval. 118. 6/1/92 Changed auto-load facility to source files at global level. 119. 6/8/92 Tcl_ParseVar wasn't always setting termPtr after errors, which sometimes caused core dumps. 120. 6/21/92 Fixed bug in initialization of regexp pattern cache. This bug caused segmentation violations in regexp commands under some conditions. 121. 6/22/92 Changed implementation of "glob" command to eliminate trailing slashes on directory names: they confuse some systems. There shouldn't be any user-visible changes in functionality except for names in error messages not having trailing slashes. 122. 7/2/92 Fixed bug that caused 'string match ** ""' to return 0. 123. 7/2/92 Fixed bug in Tcl_CreateCmdBuf where it wasn't initializing the buffer to an empty string. 124. 7/6/92 Fixed bug in "case" command where it used NULL pattern string after errors in the "default" clause. 125. 7/25/92 Speeded up auto_load procedure: don't reread all the index files unless the path has changed. 126. 8/3/92 Changed tclUnix.h to define MAXPATHLEN from PATH_MAX, not _POSIX_PATH_MAX. ----------------- Released version 6.4, 8/7/92 ------------------ 127. 8/10/92 Changed tclBasic.c so that comment lines can be continued by putting a backslash before the newline. 128. 8/21/92 Modified "unknown" to allow the source-ing of a file for an auto-load to trigger other nested auto-loads, as long as there isn't any recursion on the same command name. 129. 8/25/92 Modified "format" command to allow " " and "+" flags, and allow flags in any order. 130. 9/14/92 Modified Tcl_ParseVar so that it doesn't actually attempt to look up the variable if "noEval" mode is in effect in the interpreter (it just parses the name). This avoids the errors that used to occur in statements like "expr {[info exists foo] && $foo}". 131. 9/14/92 Fixed bug in "uplevel" command where it didn't output the correct error message if a level was specified but no command. 132. 9/14/92 Renamed manual entries to have extensions like .3 and .n, and added "install" target to Makefile. 133. 9/18/92 Modified "unknown" command to emulate !!, !, and ^^ csh history substitutions. 134. 9/21/92 Made the config script cleverer about figuring out which switches to pass to "nm". 135. 9/23/92 Fixed tclVar.c to be sure to copy flags when growing variables. Used to forget about traces in progress and make extra recursive calls on trace procs. 136. 9/28/92 Fixed bug in auto_reset where it was unsetting variables that might not exist. 137. 10/7/92 Changed "parray" library procedure to print any array accessible to caller, local or global. 138. 10/15/92 Fixed bug where propagation of new environment variable values among interpreters took N! time if there exist N interpreters. 139. 10/16/92 Changed auto_reset procedure so that it also deletes any existing procedures that are in the auto_load index (the assumption is that they should be re-loaded to get the latest versions). 140. 10/21/92 Fixed bug that caused lists to be incorrectly generated for elements that contained backslash-newline sequences. 141. 12/9/92 Added support for TCL_LIBRARY environment variable: use it as library location if it's present. 142. 12/9/92 Added "info complete" command, Tcl_CommandComplete procedure. 143. 12/16/92 Changed the Makefile to check to make sure "config" has been run (can't run config directly from the Makefile because it modifies the Makefile; thus make has to be run again after running config). ----------------- Released version 6.5, 12/17/92 ------------------ 144. 12/21/92 Changed config to look in several places for libc file. 145. 12/23/92 Added "elseif" support to if. Also, "then", "else", and "elseif" may no longer be abbreviated. *** POTENTIAL INCOMPATIBILITY *** 146. 12/28/92 Changed "puts" and "read" to support initial "-nonewline" switch instead of additional "nonewline" argument. The old form is still supported, but it is discouraged and is no longer documented. Also changed "puts" to make the file argument default to stdout: e.g. "puts foo" will print foo on standard output. 147. 1/6/93 Fixed bug whereby backslash-newline wasn't working when typed interactively, or in "info complete". 148. 1/22/93 Fixed bugs in "lreplace" and "linsert" where close quotes were being lost from last element before replacement or insertion. 149. 1/29/93 Fixed bug in Tcl_AssembleCmd where it wasn't requiring a newline at the end of a line before considering a command to be complete. The bug caused some very long lines in script files to be processed as multiple separate commands. 150. 1/29/93 Various changes in Makefile to add more configuration options, simplify installation, fix bugs (e.g. don't use -f switch for cp), etc. 151. 1/29/93 Changed "name1" and "name2" identifiers to "part1" and "part2" to avoid name conflicts with stupid C++ implementations that use "name1" and "name2" in a reserved way. 152. 2/1/93 Added "putenv" procedure to replace the standard system version so that it will work correctly with Tcl's environment handling. ----------------- Released version 6.6, 2/5/93 ------------------ 153. 2/10/93 Fixed bugs in config script: missing "endif" in libc loop, and tried to use strncasecmp.c instead of strcasecmp.c. 154. 2/10/93 Makefile improvements: added RANLIB variable for easier Sys-V configuration, added SHELL variable for SGI systems. ----------------- Released version 6.7, 2/11/93 ------------------ 153. 2/6/93 Changes in backslash processing: - \Cx, \Mx, \CMx, \e sequences no longer special - \ also eats up any space after the newline, replacing the whole sequence with a single space character - Hex sequences like \x24 are now supported, along with ANSI C's \a. - "format" no longer does backslash processing on its format string - there is no longer any special meaning to a 0 return value from Tcl_Backslash - unknown backslash sequences, like (e.g. \*), are replaced with the following character (e.g. *), instead of just treating the backslash as an ordinary character. *** POTENTIAL INCOMPATIBILITY *** 154. 2/6/93 Updated all copyright notices. The meaning hasn't changed at all but the wording does a better job of protecting U.C. from liability (according to U.C. lawyers, anyway). 155. 2/6/93 Changed "regsub" so that it overwrites the result variable in all cases, even if there is no match. *** POTENTIAL INCOMPATIBILITY *** 156. 2/8/93 Added support for XPG3 %n$ conversion specifiers to "format" command. 157. 2/17/93 Fixed bug in Tcl_Eval where errors due to infinite recursion could result in core dumps. 158. 2/17/93 Improved the auto-load mechanism to deal gracefully (i.e. return an error) with a situation where a library file that supposedly defines a procedure doesn't actually define it. 159. 2/17/93 Renamed Tcl_UnixError procedure to Tcl_PosixError, and changed errorCode variable usage to use POSIX as keyword instead of UNIX. *** POTENTIAL INCOMPATIBILITY *** 160. 2/19/93 Changes to exec and process control: - Added support for >>, >&, >>&, |&, <@, >@, and >&@ forms of redirection. - When exec puts processes into background, it returns a list of their pids as result. - Added support for file, etc. (i.e. no space between ">" and file name. - Added -keepnewline option. - Deleted Tcl_Fork and Tcl_WaitPids procedures (just use fork and waitpid instead). - Added waitpid compatibility procedure for systems that don't have it. - Added Tcl_ReapDetachedProcs procedure. - Changed "exec" to return an error if there is stderr output, even if the command returns a 0 exit status (it's always been documented this way, but the implementation wasn't correct). - If a process returns a non-zero exit status but doesn't generate any diagnostic output, then Tcl generates an error message for it. *** POTENTIAL INCOMPATIBILITY *** 161. 2/25/93 Fixed two memory-management problems having to do with managing the old result during variable trace callbacks. 162. 3/1/93 Added dynamic string library: Tcl_DStringInit, Tcl_DStringAppend, Tcl_DStringFree, Tcl_DStringResult, etc. 163. 3/1/93 Modified glob command to only return the names of files that exist, and to only return names ending in "/" if the file is a directory. *** POTENTIAL INCOMPATIBILITY *** 164. 3/19/93 Modified not to use system calls like "read" directly, but instead to use special Tcl procedures that retry automatically if interrupted by signals. 165. 4/3/93 Eliminated "noSep" argument to Tcl_AppendElement, plus TCL_NO_SPACE flag for Tcl_SetVar and Tcl_SetVar2. *** POTENTIAL INCOMPATIBILITY *** 166. 4/3/93 Eliminated "flags" and "termPtr" arguments to Tcl_Eval. *** POTENTIAL INCOMPATIBILITY *** 167. 4/3/93 Changes to expressions: - The "expr" command now accepts multiple arguments, which are concatenated together with space separators. - Integers aren't automatically promoted to floating-point if they overflow the word size: errors are generated instead. - Tcl can now handle "NaN" and other special values if the underlying library procedures handle them. - When printing floating-point numbers, Tcl ensures that there is a "." or "e" in the number, so it can't be treated as an integer accidentally. The procedure Tcl_PrintDouble is available to provide this function in other contexts. Also, the variable "tcl_precision" can be used to set the precision for printing (must be a decimal number giving digits of precision). - Expressions now support transcendental and other functions, e.g. sin, acos, hypot, ceil, and round. Can add new math functions with Tcl_CreateMathFunc(). - Boolean expressions can now have any of the string values accepted by Tcl_GetBoolean, such as "yes" or "no". *** POTENTIAL INCOMPATIBILITY *** 168. 4/5/93 Changed Tcl_UnsetVar and Tcl_UnsetVar2 to return TCL_OK or TCL_ERROR instead of 0 or -1. *** POTENTIAL INCOMPATIBILITY *** 169. 4/5/93 Eliminated Tcl_CmdBuf structure and associated procedures; can use Tcl_DStrings instead. *** POTENTIAL INCOMPATIBILITY *** 170. 4/8/93 Changed interface to Tcl_TildeSubst to use a dynamic string for buffer space. This makes the procedure re-entrant and thread-safe, whereas it wasn't before. *** POTENTIAL INCOMPATIBILITY *** 171. 4/14/93 Eliminated tclHash.h, and moved everything from it to tcl.h *** POTENTIAL INCOMPATIBILITY *** 172. 4/15/93 Eliminated Tcl_InitHistory, made "history" command always be part of interpreter. *** POTENTIAL INCOMPATIBILITY *** 173. 4/16/93 Modified "file" command so that "readable" option always exists, even on machines that don't support symbolic links (always returns same error as if the file wasn't a symbolic link). 174. 4/26/93 Fixed bugs in "regsub" where ^ patterns didn't get handled right (pretended not to match when it really did, and looped infinitely if -all was specified). 175. 4/29/93 Various improvements in the handling of variables: - Can create variables and array elements during a read trace. - Can delete variables during traces (note: unset traces will be invoked when this happens). - Can upvar to array elements. - Can retarget an upvar to another variable by re-issuing the upvar command with a different "other" variable. 176. 5/3/93 Added Tcl_GetCommandInfo, which returns info about a Tcl command such as whether it exists and its ClientData. Also added Tcl_SetCommandInfo, which allows any of this information to be modified and also allows a command's delete procedure to have a different ClientData value than its command procedure. 177. 5/5/93 Added Tcl_RegExpMatch procedure. 178. 5/6/93 Fixed bug in "scan" where it didn't properly handle %% conversion specifiers. Also changed "scan" to use Tcl_PrintDouble for printing real values. 179. 5/7/93 Added "-exact", "-glob", and "-regexp" options to "lsearch" command to allow different kinds of pattern matching. 180. 5/7/93 Added many new switches to "lsort" to control the sorting process: "-ascii", "-integer", "-real", "-command", "-increasing", and "-decreasing". 181. 5/10/93 Changes to file I/O: - Modified "open" command to support a list of POSIX access flags like {WRONLY CREAT TRUNC} in addition to current fopen-style access modes. Also added "permissions" argument to set permissions of newly-created files. - Fixed Scott Bolte's bug (can close stdin etc. in application and then re-open them with Tcl commands). - Exported access to Tcl's file table with new procedures Tcl_EnterFile and Tcl_GetOpenFile. 182. 5/15/93 Added new "pid" command, which can be used to retrieve either the current process id or a list of the process ids in a pipeline opened with "open |..." 183. 6/3/93 Changed to use GNU autoconfig for configuration instead of the home-brew "config" script. Also made many other configuration-related changes, such as using instead of explicitly declaring system calls in tclUnix.h. 184. 6/4/93 Fixed bug where core-dumps could occur if a procedure redefined itself (the memory for the procedure's body could get reallocated in the middle of evaluating the body); implemented simple reference count mechanism. 185. 6/5/93 Changed tclIndex file format in two ways: (a) it's now eval-ed instead of parsed, which makes it 3-4x faster; (b) the entries in auto_index are now commands to evaluate, which allows commands to be loaded in different ways such as dynamic-loading of C code. The old tclIndex file format is still supported. 186. 6/7/93 Eliminated tclTest program, added new "tclsh" program that is more like wish (allows script files to be invoked automatically using "#!/usr/local/bin/tclsh", makes arguments available to script, etc.). Added support for Tcl_AppInit plus default version; this allows new Tcl applications to be created without modifying the main program for tclsh. 187. 6/7/93 Fixed bug in TclWordEnd that kept backslash-newline from working correctly in some cases during interactive input. 188. 6/9/93 Added Tcl_LinkVar and related procedures, which automatically keep a Tcl variable in sync with a C variable. 189. 6/16/93 Increased maximum nesting depth from 100 to 1000. 190. 6/16/93 Modified "trace var" command so that error messages from within traces are returned properly as the result of the variable access, instead of the generic "access disallowed by trace command" message. 191. 6/16/93 Added Tcl_CallWhenDeleted to provide callbacks when an interpreter is deleted (same functionality as Tcl_WatchInterp, which used to exist in versions before 6.0). 193. 6/16/93 Added "-code" argument to "return" command; it's there primarily for completeness, so that procedures implementing control constructs can reflect exceptional conditions back to their callers. 194. 6/16/93 Split up Tcl.n to make separate manual entries for each Tcl command. Tcl.n now contains a summary of the language syntax. 195. 6/17/93 Added new "switch" command to replace "case": allows alternate forms of pattern matching (exact, glob, regexp), replaces pattern lists with single patterns (but you can use "-" bodies to share one body among several patterns), eliminates "in" noise word. "Case" command is now obsolete. 196. 6/17/93 Changed the "exec", "glob", "regexp", and "regsub" commands to include a "--" switch. All initial arguments starting with "-" are now treated as switches unless a "--" switch is present to end the list. *** POTENTIAL INCOMPATIBILITY *** 197. 6/17/93 Changed auto-exec so that the subprocess gets stdin, stdout, and stderr from the parent. This allows truly interactive sub-processes (e.g. vi) to be auto-exec'ed from a tcl shell command line. 198. 6/18/93 Added patchlevel.h, for use in coordinating future patch releases, and also added "info patchlevel" command to make the patch level available to Tcl scripts. 199. 6/19/93 Modified "glob" command so that a leading "//" in a name gets left as is (this is needed for systems like Apollos where "//" is the super-root; Tcl used to collapse the two slashes into a single slash). 200. 7/7/93 Added Tcl_SetRecursionLimit procedure so that the maximum allowable nesting depth can be controlled for an interpreter from C. ----------------- Released version 7.0 Beta 1, 7/9/93 ------------------ 201. 7/12/93 Modified Tcl_GetInt and tclExpr.c so that full-precision unsigned integers can be specified without overflow errors. 202. 7/12/93 Configuration changes: eliminate leading blank line in configure script; provide separate targets in Makefile for installing binary and non-binary information; check for size_t and a few other potentially missing typedefs; don't put tclAppInit.o into libtcl.a; better checks for matherr support. 203. 7/14/93 Changed tclExpr.c to check the termination pointer before errno after strtod calls, to avoid problems with some versions of strtod that set errno in unexpected ways. 204. 7/16/93 Changed "scan" command to be more ANSI-conformant: eliminated %F, %D, etc., added code to ignore "l", "h", and "L" modifiers but always convert %e, %f, and %g with implicit "l"; also added support for %u and %i. Also changed "format" command to eliminate %D, %U, %O, and add %i. *** POTENTIAL INCOMPATIBILITY *** 205. 7/17/93 Changed "uplevel" and "upvar" so that they can be used from global level to global level: this used to generate an error. 206. 7/19/93 Renamed "setenv", "putenv", and "unsetenv" procedures to avoid conflicts with system procedures with the same names. If you want Tcl's procedures to override the system procedures, do it in the Makefile (instructions are in the Makefile). *** POTENTIAL INCOMPATIBILITY *** ----------------- Released version 7.0 Beta 2, 7/21/93 ------------------ 207. 7/21/93 Fixed bug in tclVar.c where freed memory was accidentally used if a procedure returned an element of a local array. 208. 7/22/93 Fixed bug in "unknown" where it didn't properly handle errors occurring in the "auto_load" procedure, leaving its state inconsistent. 209. 7/23/93 Changed exec's ">2" redirection operator to "2>" for consistency with sh. This is incompatible with earlier beta releases of 7.0 but not with pre-7.0 releases, which didn't support either operator. 210. 7/28/93 Changed backslash-newline handling so that the resulting space character *is* treated as a word separator unless the backslash sequence is in quotes or braces. This is incompatible with 7.0b1 and 7.0b2 but is more compatible with pre-7.0 versions that the b1 and b2 releases were. 211. 7/28/93 Eliminated Tcl_LinkedVarWritable, added TCL_LINK_READ_ONLY to Tcl_LinkVar to accomplish same purpose. This change is incompatible with earlier beta releases, but not with releases before Tcl 7.0. 212. 7/29/93 Renamed regexp C functions so they won't clash with POSIX regexp functions that use the same name. 213. 8/3/93 Added "-errorinfo" and "-errorcode" options to "return" command: these allow for much better handling of the errorInfo and errorCode variables in some cases. 214. 8/12/93 Changed "expr" so that % always returns a remainder with the same sign as the divisor and absolute value smaller than the divisor. 215. 8/14/93 Turned off auto-exec in "unknown" unless the command was typed interactively. This means you must use "exec" when invoking subprocesses, unless it's a command that's typed interactively. *** POTENTIAL INCOMPATIBILITY *** 216. 8/14/93 Added support for tcl_prompt1 and tcl_prompt2 variables to tclMain.c: makes prompts user-settable. 217. 8/14/93 Added asynchronous handlers (Tcl_AsyncCreate etc.) so that signals can be taken cleanly by Tcl applications. 218. 8/16/93 Moved information about open files from the interpreter structure to global variables so that a file can be opened in one interpreter and read or written in another. 219. 8/16/93 Removed ENV_FLAGS from Makefile, so that there's no official support for overriding setenv, unsetenv, and putenv. 220. 8/20/93 Various configuration improvements: coerce chars to unsigned chars before using macros like isspace; source ~/.tclshrc file during initialization if it exists and program is running interactively; allow there to be directories in auto_path that don't exist or don't have tclIndex files (ignore them); added Tcl_Init procedure and changed Tcl_AppInit to call it. 221. 8/21/93 Fixed bug in expr where "+", "-", and " " were all getting treated as integers with value 0. 222. 8/26/93 Added "tcl_interactive" variable to tclsh. 223. 8/27/93 Added procedure Tcl_FilePermissions to return whether a given file can be read or written or both. Modified Tcl_EnterFile to take a permissions mask rather than separate read and write arguments. 224. 8/28/93 Fixed performance bug in "glob" command (unnecessary call to "access" for each file caused a 5-10x slow-down for big directories). ----------------- Released version 7.0 Beta 3, 8/28/93 ------------------ 225. 9/9/93 Renamed regexp.h to tclRegexp.h to avoid conflicts with system include file by same name. 226. 9/9/93 Added Tcl_DontCallWhenDeleted. 227. 9/16/93 Changed not to call exit C procedure directly; instead always invoke "exit" Tcl command so that application can redefine the command to do additional cleanup. 228. 9/17/93 Changed auto-exec to handle names that contain slashes (i.e. don't use PATH for them). 229. 9/23/93 Fixed bug in "read" and "gets" commands where they didn't clear EOF conditions. ----------------- Released version 7.0, 9/29/93 ------------------ 230. 10/7/93 "Scan" command wasn't properly aligning things in memory, so segmentation faults could arise under some circumstances. 231. 10/7/93 Fixed bug in Tcl_ConvertElement where it forgot to backslash leading curly brace when creating lists. 232. 10/7/93 Eliminated dependency of tclMain.c on tclInt.h and tclUnix.h, so that people can copy the file out of the Tcl source directory to make modified private versions. 233. 10/8/93 Fixed bug in auto-loader that reversed the priority order of entries in auto_path for new-style index files. Now things are back to the way they were before 3.0: first in auto_path is always highest priority. 234. 10/13/93 Fixed bug where Tcl_CommandComplete didn't recognize comments and treat them as such. Thus if you typed the line # { interactively, Tcl would think that the command wasn't complete and wait for more input before evaluating the script. 235. 10/14/93 Fixed bug where "regsub" didn't set the output variable if the input string was empty. 236. 10/23/93 Fixed bug where Tcl_CreatePipeline didn't close off enough file descriptors in child processes, causing children not to exit properly in some cases. 237. 10/28/93 Changed "list" and "concat" commands not to generate errors if given zero arguments, but instead to just return an empty string. ----------------- Released version 7.1, 11/4/93 ------------------ Note: there is no 7.2 release. It was flawed and was thus withdrawn shortly after it was released. 238. 11/10/93 TclMain.c didn't compile on some systems because of R_OK in call to "access". Changed to eliminate call to "access". ----------------- Released version 7.3, 11/26/93 ------------------ 239. 11/6/93 Modified "lindex", "linsert", "lrange", and "lreplace" so that "end" can be specified as an index. 240. 11/6/93 Modified "append" and "lappend" to allow only two words total (i.e., nothing to append) without generating an error. 241. 12/2/93 Changed to use EAGAIN as the errno for non-blocking I/O instead of EWOULDBLOCK: this should fix problem where non-blocking I/O didn't work correctly on System-V systems. 242. 12/22/93 Fixed bug in expressions where cancelled evaluation wasn't always working correctly (e.g. "set one 1; eval {1 || 1/$one}" failed with a divide by zero error). 243. 1/6/94 Changed TCL_VOLATILE definition from -1 to the address of a dummy procedure Tcl_Volatile, since -1 causes portability problems on some machines (e.g., Crays). 244. 2/4/94 Added support for unary plus. 245. 2/17/94 Changed Tcl_RecordAndEval and "history" command to call Tcl_GlobalEval instead of Tcl_Eval. Otherwise, invocation of these facilities in nested procedures can cause unwanted results. 246. 2/17/94 Fixed bug in tclExpr.c where an expression such as "expr {"12398712938788234-1298379" != ""}" triggers an integer overflow error for the number in quotes, even though it isn't really a proper integer anyway. 247. 2/19/94 Added new procedure Tcl_DStringGetResult to move result from interpreter to a dynamic string. 248. 2/19/94 Fixed bug in Tcl_DStringResult that caused it to overwrite the contents of a static result in some situations. This can cause bizarre errors such as variables suddenly having empty values. 249. 2/21/94 Fixed bug in Tcl_AppendElement, Tcl_DStringAppendElement, and the "lappend" command that caused improper omission of a separator space in some cases. For example, the script set x "abc{"; lappend x "def" used to return the result "abc{def" instead of "abc{ def". 250. 3/3/94 Tcl_ConvertElement was outputting empty elements as \0 if TCL_DONT_USE_BRACES was set. This depends on old pre-7.0 meaning of \0, which is no longer in effect, so it didn't really work. Changed to output empty elements as {} always. 251. 3/3/94 Renamed Tcl_DStringTrunc to Tcl_DStringSetLength and extended it so that it can be used to lengthen a string as well as shorten it. Tcl_DStringTrunc is defined as a macro for backward compatibility, but it is deprecated. 252. 3/3/94 Added Tcl_AllowExceptions procedure. 253. 3/13/94 Fixed bug in Tcl_FormatCmd that could cause "format" to mis-behave on 64-bit Big-Endian machines. 254. 3/13/94 Changed to use vfork instead of fork on systems where vfork exists. 255. 3/23/94 Fixed bug in expressions where ?: didn't associate right-to-left as they should. 256. 4/3/94 Fixed "exec" to flush any files used in >@ or >&@ redirection in exec, so that data buffered for them is written before any new data added by the subprocess. 257. 4/3/94 Added "subst" command. 258. 5/20/94 The tclsh main program is now called Tcl_Main; tclAppInit.c has a "main" procedure that calls Tcl_Main. This makes it easier to use Tcl with C++ programs, which need their own main programs, and it also allows an application to prefilter the argument list before calling Tcl_Main. *** POTENTIAL INCOMPATIBILITY *** 259. 6/6/94 Fixed bug in procedure returns where the errorInfo variable could get truncated if an unset trace was invoked as part of returning from the procedure. 260. 6/13/94 Added "wordstart" and "wordend" options to "string" command. 261. 6/27/94 Fixed bug in expressions where they didn't properly cancel the evaluation of math functions in &&, ||, and ?:. 262. 7/11/94 Incorrect boolean values, like "ogle", weren't being handled properly. 263. 7/15/94 Added Tcl_RegExpCompile, Tcl_RegExpExec, and Tcl_RegExpRange, which provide lower-level access to regular expression pattern matching. 264. 7/22/94 Fixed bug in "glob" command where "glob -nocomplain ~bad_user" would complain about a missing user. Now it doesn't complain anymore. 265. 8/4/94 Fixed bug with linked variables where they didn't behave correctly when accessed via upvars. 266. 8/17/94 Fixed bug in Tcl_EvalFile where it didn't clear interp->result. 267. 8/31/94 Modified "open" command so that errors in exec-ing subprocesses are returned by the open immediately, rather than being delayed until the "close" is executed. 268. 9/9/94 Modified "expr" command to generate errors for integer overflow (includes addition, subtraction, negation, multiplication, division). 269. 9/23/94 Modified "regsub" to return a count of the number of matches and replacements, rather than 0/1. 279. 10/4/94 Added new features to "array" command: - added "get" and "set" commands for easy conversion between arrays and lists. - added "exists" command to see if a variable is an array, changed "names" and "size" commands to treat a non-existent array (or scalar variable) just like an empty one. - added pattern option to "names" command. 280. 10/6/94 Modified Tcl_SetVar2 so that read traces on variables get called during append operations. 281. 10/20/94 Fixed bug in "read" command where reading from stdin required two control-D's to stop the reading. 282. 11/3/94 Changed "expr" command to use longs for division just like all other expr operators; it previously used ints for division. 283. 11/4/94 Fixed bugs in "unknown" procedure: it wasn't properly handling exception returns from commands that were executed after being auto-loaded. ----------------- Released version 7.4b1, 12/23/94 ------------------ 284. 12/26/94 Fixed "install" target in Makefile (couldn't always find install program). 285. 12/26/94 Added strcncasecmp procedure to compat directory. 286. 1/3/95 Fixed all procedure calls to explicitly cast arguments: implicit conversions from prototypes (especially integer->double) don't work when compiling under non-ANSI compilers. Tcl is now clean under gcc -Wconversion. 287. 1/4/95 Fixed problem in Tcl_ArrayCmd where same name was used for both a label and a variable; caused problems on several older compilers, making array command misbehave and causing many errors in Tcl test suite. ----------------- Released version 7.4b2, 1/12/95 ------------------ 288. 2/9/95 Modified Tcl_CreateCommand to return a token, and added Tcl_GetCommandName procedure. Together, these procedures make it possible to track renames of a command. 289. 2/13/95 Fixed bug in expr where "089" was interpreted as a floating-point number rather than a bogus octal number. *** POTENTIAL INCOMPATIBILITY *** 290. 2/14/95 Added code to Tcl_GetInt and Tcl_GetDouble to check for overflows when reading in numbers. 291. 2/18/95 Changed "array set" to stop after first error, rather than continuing after error. 292. 2/20/95 Upgraded to use autoconf version 2.2. 293. 2/20/95 Fixed core dump that could occur in "scan" command if a close bracket was omitted. 294. 2/27/95 Changed Makefile to always use install-sh for installations: there's just too much variation among "install" system programs, which makes installation flakey. ----------------- Released version 7.4b3, 3/24/95 ------------------ 3/25/95 (bug fix) Changed "install" to "./install" in Makefile so that "make install" will work even when "." isn't in the search path. 3/29/95 (bug fix) Fixed bug where the auto-loading mechanism wasn't protecting the values of the errorCode and errorInfo variables. 3/29/95 (new feature) Added optional pattern argument to "parray" procedure. 3/29/95 (bug fix) Made the full functionality of "return -code ... -errorcode ..." work not just inside procedures, but also in sourced files and at top level. 4/6/95 (new feature) Added "pattern" option to "array names" command. 4/18/95 (bug fix) Fixed bug in parser where it didn't allow backslash-newline immediately after an argument in braces or quotes. 4/19/95 (new feature) Added tcl_library variable, which application can set to override default library directory. 4/30/95 (bug fix) During trace callbacks for array elements, the variable name used in the original reference would be temporarily modified to separate the array name and element name; if the trace callback used the same name string, it would get the wrong name (the array name without element). Fixed to restore the variable name before making trace callbacks. 4/30/95 (new feature) Added -nobackslashes, -nocommands, and -novariables switches to "subst" command. 5/4/95 (new feature) Added TCL_EVAL_GLOBAL flag to Tcl_RecordAndEval. 5/5/95 (bug fix) Format command would overrun memory when printing integers with very large precision, as in "format %.1000d 0". 5/5/95 (portability improvement) Changed to use BSDgettimeofday on IRIX machines, to avoid compilation problems with the gettimeofday declaration. 5/6/95 (bug fix) Changed manual entries to use the standard .TH macro instead of a custom .HS macro; the .HS macro confuses index generators like makewhatis. 5/9/95 (bug fix) Modified configure script to check for Solaris bug that makes vfork unreliable (core dumps result if vforked child changes a signal handler); will use fork instead of vfork if the bug is present. 6/5/95 (bug fix) Modified "lsort" command to disallow recursive calls to lsort from a comparison function. This is needed because qsort is not reentrant. 6/5/95 (bug fix) Undid change 243 above: changed TCL_VOLATILE and TCL_DYNAMIC back to integer constants rather than procedure addresses. This was needed because procedure addresses can have multiple values under some dynamic loading systems (e.g. SunOS 4.1 and Windows). 6/8/95 (feature change) Modified interface to Tcl_Main to pass in the address of the application-specific initialization procedure. Tcl_AppInit is no longer hardwired into Tcl_Main. This is needed in order to make Tcl a shared library. 6/8/95 (feature change) Modified Makefile so that the installed versions of tclsh and libtcl.a have version number in them (e.g. tclsh7.4 and libtcl7.4.a) and the library directory name also has an embedded version number (e.g., /usr/local/lib/tcl7.4). This should make it easier for Tcl 7.4 to coexist with earlier versions. ----------------- Released version 7.4b4, 6/16/95 ------------------ 6/19/95 (bug fix) Fixed bugs in tclCkalloc.c that caused core dumps if TCL_MEM_DEBUG was enabled on word-addressed machines such as Crays. 6/21/95 (feature removal) Removed overflow checks for integer arithmetic: they just cause too much trouble (e.g. for random number generators). 6/28/95 (new features) Added tcl_patchLevel and tcl_version variables, for consistency with Tk. 6/29/95 (bug fix) Fixed problem in Tcl_Eval where it didn't record the right termination character if a script ended with a comment. This caused erroneous output for the following command, among others: puts "[ expr 1+1 # duh! ]" 6/29/95 (message change) Changed the error message for ECHILD slightly to provide a hint about why the problem is occurring. ----------------- Released version 7.4, 7/1/95 ------------------ 7/18/95 (bug fix) Changed "lreplace" so that nothing is deleted if the last index is less than the first index or if the last index is < 0. 7/18/95 (bug fix) Fixed bugs with backslashes in comments: Tcl_CommandComplete (and "info complete") didn't properly handle strings ending in backslash-newline, and neither Tcl_CommandComplete nor the Tcl parser handled other backslash sequences right, such as two backslashes before a newline. 7/19/95 (bug fix) Modified Tcl_DeleteCommand to delete the hash table entry for the command before invoking its callback. This is needed in order to deal with reentrancy. 7/22/95 (bug fix) "exec" wasn't reaping processes correctly after certain errors (e.g. if the name of the executable was bogus, as in "exec foobar"). 7/27/95 (bug fix) Makefile.in wasn't using the LIBS variable provided by the "configure" script. This caused problems on some SCO systems. 7/27/95 (bug fix) The version of strtod in fixstrtod.c didn't properly handle the case where endPtr == NULL. ----------------- Released patch 7.4p1, 7/29/95 ----------------------- 8/4/95 (bug fix) C-level trace callbacks for variables were sometimes receiving the PART1_NOT_PARSED flag, which could cause errors in subsequent Tcl library calls using the flags. (JO) 8/4/95 (bug fix) Calls to toupper and tolower weren't using the UCHAR macros, which caused trouble in non-U.S. locales. (JO) 8/10/95 (new feature) Added the "load" command for dynamic loading of binary packages, and the Tcl_PackageInitProc prototype for package initialization procedures. (JO) 8/23/95 (new features) Added "info sharedlibextension" and "info nameofexecutable" commands, plus Tcl_FindExtension procedure. (JO) 8/25/95 (bug fix) If the target of an "upvar" was non-existent but had traces set, the traces were silently lost. Change to generate an error instead. (JO) 8/25/95 (bug fix) Undid change from 7/19, so that commands can stay around while their deletion callbacks execute. Added lots of code to handle all of the reentrancy problems that this opens up. (JO) 8/25/95 (bug fix) Fixed core dump that could occur in TclDeleteVars if there was an upvar from one entry in the table to the next entry in the same table. (JO) 8/28/95 (bug fix) Exec wasn't handling bad user names properly, as in "exec ~bogus_user/foo". (JO) 8/29/95 (bug fixes) Changed backslash-newline handling to correct two problems: - Only spaces and tabs following the backslash-newline are now absorbed as part of the backslash-newline. Newlinew are no longer absorbed (add another backslash if you want to absorb another newline). - TclWordEnd returns the character just before the backslash in the sequence as the end of the sequence; it used to not consider the backslash-newline as a word separator. (JO) 8/31/95 (new feature) Changed man page installation (with "mkLinks" script) to create additional links for manual pages corresponding to each of the procedure and command names described in the pages. (JO) 9/10/95 Reorganized Tcl sources for Windows and Mac ports. All sources are now in subdirectories: "generic" contains sources that work on all platforms, "windows", "mac", and "unix" directories contain platform- specific sources. Some UNIX sources are also used on other platforms. (SS) 9/10/95 (feature change) Eliminated exported global variables (they don't work with Windows DLLs). Replaced tcl_AsyncReady and tcl_FileCloseProc with procedures Tcl_AsyncReady() and Tcl_SetFileCloseProc(). Replaced C variable tcl_RcFileName with a Tcl variable tcl_rcFileName. (SS) *** POTENTIAL INCOMPATIBILITY *** 9/11/95 (new feature) Added procedure Tcl_SetPanicProc to override the default implementation of "panic". (SS) 9/11/95 (new feature) Added "interp" command to allow creation of new interpreters and execution of untrusted scripts. Added many new procedures, such as Tcl_CreateSlave, Tcl_CreateAlias,and Tcl_MakeSafe, to provide C-level access to the interpreter facility. This mechanism now provides almost all of the generic functions of Borenstein's and Rose's Safe-Tcl (but not any Tk or email-related stuff). (JL) 9/11/95 (feature change) Changed file management so that files are no longer shared between interpreters: a file cannot normally be referenced in one interpreter if it was opened in another. This feature is needed to support safe interpreters. Added Tcl_ShareHandle() procedure for allowing files to be shared, and added "interp" argument to Tcl_FilePermissions procedure. (JL) *** POTENTIAL INCOMPATIBILITY *** 9/11/95 (new feature) Added "AssocData" mechanism, whereby extensions can associate their own data with an interpreter and get called back when the interpreter is deleted. This is visible at C level via the procedures Tcl_SetAssocData and Tcl_GetAssocData. (JL) 9/11/95 (new feature) Added Tcl_ErrnoMsg to translate an errno value into a human-readable string. This is now used instead of calling strerror because strerror mesages vary dramatically from platform to platform, which messes up Tcl tests. Tcl_ErrnoMsg uses the standard POSIX messages for all the common signals, and calls strerror for signals it doesn't understand. ----------------- Released patch 7.4p2, 9/15/95 ----------------------- ----------------- Released 7.5a1, 9/15/95 ----------------------- 9/22/95 (bug fix) Changed auto_mkindex to create tclIndex files that handle directories whose paths might contain spaces. (RJ) 9/27/95 (bug fix) The "format" command didn't check for huge or negative width specifiers, which could cause core dumps. (JO) 9/27/95 (bug fix) Core dumps could occur if an interactive command typed to tclsh returned a very long result for tclsh to print out. The bug is actually in printf (in Solaris 2.3 and 2.4, at least); switched to use puts instead. (JO) 9/28/95 (bug fix) Changed makefile.bc to eliminate a false dependency for tcl1675.dll on the Borland run time library. (SS) 9/28/95 (bug fix) Fixed tcl75.dll so it looks for tcl1675.dll instead of tcl16.dll. (SS) 9/28/95 (bug fix) Tcl was not correctly detecting the difference between Win32s and Windows '95. (SS) 9/28/95 (bug fix) "exec" was not passing environment changes to child processes under Windows. (SS) 9/28/95 (bug fix) Changed Tcl to ensure that open files are not passed to child processes under Windows. (SS) 9/28/95 (bug fix) Fixed Windows '95 and NT versions of exec so it can handle both console and windows apps. (SS) 9/28/95 (bug fix) Fixed Windows version of exec so it no longer leaves temp files lying around. Also changed it so the temp files are created in the appropriate system dependent temp directory. (SS) 9/28/95 (bug fix) Eliminated source dependency on the Win32s Universal Thunk header file, since it is not bundled with VC++. (SS) 9/28/95 (bug fix) Under Windows, Tcl now constructs the HOME environment variable from HOMEPATH and HOMEDRIVE when HOME is not already set. (SS) 9/28/95 (bug fix) Added support for "info nameofexecutable" and "info sharedlibextension" to the Windows version. (SS) 9/28/95 (bug fix) Changed tclsh to correctly parse command line arguments so that backslashes are preserved under Windows. (SS) 9/29/95 (bug fix) Tcl 7.5a1 treated either return or newline as end of line in "gets", which caused lines ending in CRLF to be treated as two separate lines. Changed to allow only character as end-of-line: carriage return on Macs, newline elsewhere. (JO) 9/29/95 (new feature) Changed to install "configInfo" file in same directory as library scripts. It didn't used to get installed. (JO) 9/29/95 (bug fix) Tcl was not converting Win32 errors into POSIX errors under some circumstances. (SS) 10/2/95 (bug fix) Safe interpreters no longer get initialized with a call to Tcl_Init(). (JL) 10/1/95 (new feature) Added "tcl_platform" global variable to provide environment information such as the instruction set and operating system. (JO) 10/1/95 (bug fix) "exec" command wasn't always generating the "child process exited abnormally" message when it should have. (JO) 10/2/95 (bug fix) Changed "mkLinks.tcl" so that the scripts it generates won't create links that overwrite original manual entries (there was a problem where pack-old.n was overwriting pack.n). (JO) 10/2/95 (feature change) Changed to use -ldl for dynamic loading under Linux if it is available, but fall back to -ldld if it isn't. (JO) 10/2/95 (bug fix) File sharing was causing refcounts to reach 0 prematurely for stdin, stdout and stderr, under some circumstances. (JL) 10/2/95 (platform support) Added support for Visual C++ compiler on Windows, Windows '95 and Windows NT, code donated by Gordon Chaffee. (JL) 10/3/95 (bug fix) Tcl now frees any libraries that it loads before it exits. (SS) 10/03/95 (bug fix) Fixed bug in Macintosh ls command where the -l and -C options would fail in anything but the HOME directory. (RJ) ----------------- Released 7.5a2, 10/6/95 ----------------------- 10/10/95 (bug fix) "file dirnam /." was returning ":" on UNIX instead of "/". (JO) 10/13/95 (bug fix) Eliminated dependency on MKS toolkit for generating the tcl.def file from Borland object files. (SS) 10/17/95 (new features) Moved the event loop from Tcl to Tk, made major revisions along the way: - New Tcl commands: after, update, vwait (replaces "tkwait variable"). - "tkerror" is now replaced with "bgerror". - The following procedures are similar to their old Tk counterparts: Tcl_DoOneEvent, Tcl_Sleep, Tcl_DoWhenIdle, Tcl_CancelIdleCall, Tcl_CreateFileHandler, Tcl_DeleteFileHandler, Tcl_CreateTimerHandler, Tcl_DeleteTimerHandler, Tcl_BackgroundError. - Revised notifier, add new concept of "event source" with the following procedures: Tcl_CreateEventSource, Tcl_DeleteEventSource, Tcl_WatchFile, Tcl_SetMaxBlockTime, Tcl_FileReady, Tcl_QueueEvent, Tcl_WaitForEvent. (JO) 10/31/95 (new features) Implemented cross platform file name support to make it easier to write cross platform scripts. Tcl now understands 4 file naming conventions: Windows (both DOS and UNC), Mac, Unix, and Network. The network convention is a new naming mechanism that can be used to paths in a platform independent fashion. See the "file" command manual page for more details. The primary interfaces changes are: - All Tcl commands that expect a file name now accept both network and native form. - Two new "file" subcommands, "nativename" and "networkname", provide a way to convert between network and native form. - Renamed Tcl_TildeSubst to Tcl_TranslateFileName, and changed it so that it always returns a filename in native form. Tcl_TildeSubst is defined as a macro for backward compatibility, but it is deprecated. (SS) 11/5/95 (new feature) Made "tkerror" and "bgerror" synonyms, so that either name can be used to manipulate the command (provides temporary backward compatibility for existing scripts that use tkerror). (JO) 11/5/95 (new feature) Added exit handlers and new C procedures Tcl_CreateExitHandler, Tcl_DeleteExitHandler, and Tcl_Exit. (JO) 11/6/95 (new feature) Added pid command for Macintosh version of Tcl (it didn't previously exist on the Mac). (RJ) 11/7/95 (new feature) New generic IO facility and support for IO to files, pipes and sockets based on a common buffering scheme. Support for asynchronous (non-blocking) IO and for event driver IO. Support for automatic (background) asynchronous flushing and asynchronous closing of channels. (JL) 11/7/95 (new feature) Added new commands "fconfigure" and "fblocked" to support new I/O features such as nonblocking I/O. Added "socket" command for creating TCP client and server sockets. (JL). 11/7/95 (new feature) Complete set of C APIs to the new generic IO facility: - Opening channels: Tcl_OpenFileChannel, Tcl_OpenCommandChannel, Tcl_OpenTcpClient, Tcl_OpenTcpServer. - I/O procedures on channels, which roughly mirror the ANSI C stdio library: Tcl_Read, Tcl_Gets, Tcl_Write, Tcl_Flush, Tcl_Seek, Tcl_Tell, Tcl_Close, Tcl_Eof, Tcl_InputBlocked, Tcl_GetChannelOption, Tcl_SetChannelOption. - Extension mechanism for creating new kinds of channels: Tcl_CreateChannel, Tcl_GetChannelInstanceData, Tcl_GetChannelType, Tcl_GetChannelName, Tcl_GetChannelFile, Tcl_RegisterChannel, Tcl_UnregisterChannel, Tcl_GetChannel. - Event-driven I/O on channels: Tcl_CreateChannelHandler, Tcl_DeleteChannelHandler. (JL) 11/7/95 (new feature) Channel driver interface specification to allow new types of channels to be added easily to Tcl. Currently being used in three drivers - for files, pipes and TCP-based sockets. (JL). 11/7/95 (new feature) interp delete now takes any number of path names of interpreters to delete, including zero. (JL). 11/8/95 (new feature) implemented 'info hostname' and Tcl_GetHostName command to get host name of machine on which the Tcl process is running. (JL) 11/9/95 (new feature) Implemented file APIs for access to low level files on each system. The APIs are: Tcl_CloseFile, Tcl_OpenFile, Tcl_ReadFile, Tcl_WriteFile and Tcl_SeekFile. Also implemented Tcl_WaitPid which waits in a system dependent manner for a child process. (JL) 11/9/95 (new feature) Added Tcl_UpdateLinkedVar procedure to force a Tcl variable to be updated after its C variable changes. (JO) 11/9/95 (bug fix) The glob command has been totally reimplemented so that it can support different file name conventions. It now handles Windows file names (both UNC and drive-relative) properly. It also supports nested braces correctly now. (SS) 11/13/95 (bug fix) Fixed Makefile.in so that configure can be run from a clean directory separate from the Tcl source tree, and compilations can be performed there. (JO) 11/14/95 (bug fix) Fixed file sharing between interpreters and file transferring between interpreters to correctly manage the refcount so that files are closed when the last reference to them is discarded. (JL) 11/14/95 (bug fix) Fixed gettimeofday implementation for the Macintosh. This fixes several timing related bugs. (RJ) 11/17/95 (new feature) Added missing support for info nameofexecutable on the Macintosh. (RJ) 11/17/95 (bug fix) The Tcl variables argc argv and argv0 now return something reasonable on the Mac. (RJ) 11/22/95 (new feature) Implemented "auto-detect" mode for end of line translations. On input, standalone "\r" mean MAC mode, standalone "\n" mean Unix mode and "\r\n" means Windows mode. On output, the mode is modified to whatever the platform specific mode for that platform is. (JL) 11/24/95 (feature change) Replaced "configInfo" file with tclConfig.sh, which is more complete and uses slightly different names. Also arranged for tclConfig.sh to be installed in the platform-specific library directory instead of Tcl's script library directory. (JO) *** POTENTIAL INCOMPATIBILITY with Tcl 7.5a2, but not with Tcl 7.4 *** ----------------- Released patch 7.4p3, 11/28/95 ----------------------- 12/5/95 (new feature) Added Tcl_File facility to support platform- independent file handles. Changed all interfaces that used Unix- style integer fd's to use Tcl_File's instead. (SS) *** POTENTIAL INCOMPATIBILITY *** 12/5/95 (new feature) Added a new "clock" command to Tcl. The command allows you to get the current "clicks" or seconds & allows you to format or scan human readable time/date strings. (RJ) 12/18/95 (new feature) Moved Tk_Preserve, Tk_Release, and Tk_EventuallyFree to Tcl, renamed to Tcl_Preserve, Tcl_Release, and Tcl_EventuallyFree. (JO) 12/18/95 (new feature) Added new "package" command and associated procedures Tcl_PkgRequire and Tcl_PkgProvide. Also wrote pkg_mkIndex library procedure to create index files from binaries and scripts. (JO) 12/20/95 (new feature) Added Tcl_WaitForFile procedure. (JO) 12/21/95 (new features) Made package name argument to "load" optional (Tcl will now attempt to guess the package name if necessary). Also added Tcl_StaticPackage and support in "load" for statically linked packages. (JO) 12/22/95 (new feature) Upgraded the foreach command to accept multiple loop variables and multiple value lists. This lets you iterate over multiple lists in parallel, and/or assign multiple loop variables from one value list during each iteration. The only potential compatibility problem is with scripts that used loop variables with a name that could be construed to be a list of variable names (i.e. contained spaces). (BW) 1/5/96 (new feature) Changed tclsh so it builds as a console mode application under Windows. Now tclsh can be used from the command line with pipes or interactively. Note that this only works under Windows 95 or NT. (SS) 1/17/96 (new feature) Modified Makefile and configure script to allow Tcl to be compiled as a shared library: use the --enable-shared option when configuing. (JO) 1/17/96 (removed obsolete features) Removed the procedures Tcl_EnterFile and Tcl_GetOpenFile: these no longer make sense with the new I/O system. (JL) *** POTENTIAL INCOMPATIBILITY *** 1/19/96 (bug fixes) Prevented formation of circular aliases, through the Tcl 'interp alias' command and through the 'rename' command, as well as through the C API Tcl_CreateAlias. (JL) 1/19/96 (bug fixes) Fixed several bugs in direct deletion of interpreters with Tcl_DeleteInterp when the interpreter is a slave; fixes based on a patch received from Viktor Dukhovni of ESM. (JL) 1/19/96 (new feature) Implemented on-close handlers for channels; added the C APIs Tcl_CreateCloseHandler and Tcl_DeleteCloseHandler. (JL) 1/19/96 (new feature) Implemented portable error reporting mechanism; added the C APIs Tcl_SetErrno and Tcl_GetErrno. (JL) 1/24/96 (bug fix) Unknown command processing properly invokes external commands under Windows NT and Windows '95 now. (SS) 1/23/96 (bug fix) Eliminated extremely long startup times under Windows '95. The problem was a result of the option database initialization code that concatenated $HOME with /.Xdefaults, resulting in a // in the middle of the file name. Under Windows '95, this is incorrectly interpreted as a UNC path. They delays came from the network timeouts needed to determine that the file name was invalid. Tcl_TranslateFileName now suppresses duplicate slashes that aren't at the beginning of the file name. (SS) 1/25/96 (bug fix) Changed exec and open to create children so they are attached to the application's console if it exists. (SS) 1/31/96 (bug fix) Fixed command line parsing to handle embedded spaces under Windows. (SS) ----------------- Released 7.5b1, 2/1/96 ----------------------- 2/7/96 (bug fix) Fixed off by one error in argument parsing code under Windows. (SS) 2/7/96 (bug fix) Fixed bugs in VC++ makefile that improperly initialized the tcl75.dll. Fixed bugs in Borland makefile that caused build failures under Windows NT. (SS) 2/9/96 (bug fix) Fixed deadlock problem in AUTO end of line translation mode which would cause a socket server with several concurrent clients writing in CRLF mode to hang. (JL) 2/9/96 (API change) Replaced -linemode option to fconfigure with a new -buffering option, added "none" setting to enable immediate write. (JL) *** INCOMPATIBILITY with b1 *** 2/9/96 (new feature) Added C API Tcl_InputBuffered which returns the count of bytes currently buffered in the input buffer of a channel, and o for output only channels. (JL) 2/9/96 (new feature) Implemented asynchronous connect for sockets. (JL) 2/9/96 (new feature) Added C API Tcl_SetDefaultTranslation to set (per channel) the default end of line translation mode. This is the mode that will be installed if an output operation is done on the channel while it is still in AUTO mode. (JL) 2/9/96 (bug fix) Changed Tcl_OpenCommandChannel interface to properly handle all of the combinations of stdio inheritance in background pipelines. See the Tcl_OpenFileChannel(3) man page for more info. This change fixes the bug where exec of a background pipeline was not getting passed the stdio handles properly. (SS) 2/9/96 (bug fix) Removed the new Tcl_CreatePipeline interface, and restored the old version for Unix platforms only. All new code should use Tcl_CreateCommandChannel instead. (SS) 2/9/96 (bug fix) Changed Makefile.in to use -L and -ltcl7.5 for Tcl library so that shared libraries are more likely to be found correctly on more platforms. (JO) 2/13/96 (new feature) Added C API Tcl_SetNotifierData and Tcl_GetNotifierData to allow notifier and channel driver writers to associate data with a Tcl_File. The result of this change is that Tcl_GetFileInfo now always returns an OS file handle, and Tcl_GetFile can be used to construct a Tcl_File for an externally constructed OS handle. (SS) 2/13/96 (bug fix) Changed Windows socket implementation so it doesn't set SO_REUSEADDR on server sockets. Now attempts to create a server socket on a port that is already in use will be properly identified and an error will be generated. (SS) 2/13/96 (bug fix) Fixed problems with DLL initialization under Visual C++ that left the C run time library uninitialized. (SS) 2/13/96 (bug fix) Fixed Windows socket initialization so it loads winsock the first time it is used, rather than at the time tcl75.dll is loaded. This should fix the bug where the modem immediately starts trying to connect to a service provider when wish or tclsh are started. (SS) 2/13/96 (new feature) Added C APIs Tcl_MakeFileChannel and Tcl_MakeTcpClientChannel to wrap up existing fds and sockets into channels. Provided implementations on Unix and Windows. (JL) 2/13/96 (bug fix) Fixed bug with seek leaving EOF and BLOCKING set. (JL) 2/14/96 (bug fix) Fixed reentrancy problem in fileevent handling and made it more robust in the face of errors. (JL) 2/14/96 (feature change) Made generic IO level emulate blocking mode if the channel driver is unable to provide it, e.g. if the low level device is always nonblocking. Thus, now blocking behavior is an advisory setting for channel drivers and can be ignored safely if the channel driver is unable to provide it. (JL) 2/15/96 (new feature) Added "binary" end of line translation mode, which is a synonym of "lf" mode. (JL) 2/15/96 (bug fix) Fixed reentrancy problem in fileevent handling vs deletion of channel event handlers. (JL) 2/15/96 (bug fix) Fixed bug in event handling which would cause a nonblocking channel to not see further readable events after the first readable event that had insufficient input. (JL) 2/17/96 (bug fix) "info complete" didn't properly handle comments in nested commands. (JO) 2/21/96 (bug fix) "exec" under Windows NT/95 did not properly handle very long command lines (>200 chars). (SS) 2/21/96 (bug fix) Sockets could get into an infinite loop if a read event arrived after all of the available data had been read. (SS) 2/22/96 (bug fix) Added cast of st_size elements to (long) before sprintf-ing in "file size" command. This is needed to handle systems like NetBSD with 64-bit file offsets. (JO) ----------------- Released 7.5b2, 2/23/96 ----------------------- 2/23/96 (bug fix) TCL_VARARGS macro in tcl.h wasn't defined properly when compiling with C++. (JO) 2/24/96 (bug fix) Removed dependencies on Makefile in the UNIX Makefile: this caused problems on some platforms (like Linux?). (JO) 2/24/96 (bug fix) Fixed configuration bug that made Tcl not compile correctly on Linux machines with neither -ldl or -ldld. (JO) 2/24/96 (new feature) Added a block of comments and definitions to Makefile.in to make it easier to have Tcl's TclSetEnv etc. replace the library procedures setenv etc, so that calls to setenv etc. in the application automatically update the Tcl "env" variable. (JO) 2/27/96 (feature change) Added optional Tcl_Interp * argument (may be NULL) to C API Tcl_Close and simplified closing of command channels. (JL) *** INCOMPATIBILITY with Tcl 7.5b2, but not with Tcl 7.4 *** 2/27/96 (feature change) Added optional Tcl_Interp * argument (may be NULL) to C type definition Tcl_DriverCloseProc; modified all channel drivers to implement close procedures that accept the additional argument. (JL) *** INCOMPATIBILITY with Tcl 7.5b2, but not with Tcl 7.4 *** 2/28/96 (bug fix) Fixed memory leak that could occur if an upvar referred to an element of an array in the same stack frame as the upvar. (JO) 2/29/96 (feature change) Modified both Tcl_DoOneEvent and Tcl_WaitForEvent so that they return immediately in cases where they would otherwise block forever (e.g. if there are no event handlers of any sort). (JO) 2/29/96 (new feature) Added C APIs Tcl_GetChannelBufferSize and Tcl_SetChannelBufferSize to set and retrieve the size, in bytes, for buffers allocated to store input or output in a channel. (JL) 2/29/96 (new feature) Added option -buffersize to Tcl fconfigure command to allow Tcl scripts to query and set the size of channel buffers. (JL) 2/29/96 (feature removed) Removed channel driver function to specify the buffer size to use when allocating a buffer. Removed the C typedef for Tcl_DriverBufferSizeProc. Channels are now created with a default buffer size of 4K. (JL) *** INCOMPATIBILITY with Tcl 7.5b2, but not with Tcl 7.4 *** 2/29/96 (feature change) The channel driver function for setting blocking mode on the device may now be NULL. If the generic code detects that the function is NULL, operations that set the blocking mode on the channel simply succeed. (JL) 3/2/96 (bug fix) Fixed core dump that could occur if a syntax error (such as missing close paren) occurred in an array reference with a very long array name. (JO) 3/4/96 (bug fix) Removed code in the "auto_load" procedure that deletes all existing auto-load information whenever the "auto_path" variable is changed. Instead, new information adds to what was already there. Otherwise, changing the "auto_path" variable causes all package- related information to be lost. If you really want to get rid of existing auto-load information, use auto_reset before setting auto_path. (JO) 3/5/96 (new feature) Added version suffix to shared library names so that Tcl will compile under NetBSD and FreeBSD (I hope). (JO) 3/6/96 (bug fix) Cleaned up error messages in new I/O system to correspond more closely to old I/O system. (JO) 3/6/96 (new feature) Added -myaddr and -myport options to the socket command, removed -tcp and -- options. This lets clients and servers choose a particular interface. Also changed the default server address from the hostname to INADDR_ANY. The server accept callback now gets passed the client's port as well as IP address. The C interfaces for Tcl_OpenTcpClient and Tcl_OpenTcpServer have changed to support the above changes. (BW) *** POTENTIAL INCOMPATIBILITY with Tcl 7.5b2, but not with Tcl 7.4 *** 3/6/96 (changed feature) The library function auto_mkindex will now default to using the pattern "*.tcl" if no pattern is given. (RJ) 3/6/96 (bug fix) The socket channel code for the Macintosh has been rewritten to use native MacTcp. (RJ) 3/7/96 (new feature) Added Tcl_SetStdChannel and Tcl_GetStdChannel interfaces to allow applications to explicitly set and get the global standard channels. (SS) 3/7/96 (bug fix) Tcl did close not the file descriptors associated with "stdout", etc. when the corresponding channels were closed. (SS) 3/7/96 (bug fix) Reworked shared library and dynamic loading stuff to try to get it working under AIX. Added new @SHLIB_LD_LIBS@ autoconf symbol as part of this. AIX probably doesn't work yet, but it should be a lot closer. (JO) 3/7/96 (feature change) Added Tcl_ChannelProc typedef and changed the signature of Tcl_CreateChannelHandler and Tcl_DeleteChannelHandler to take Tcl_ChannelProc arguments instead of Tcl_FileProc arguments. This change should not affect any code outside Tcl because the signatures of Tcl_ChannelProc and Tcl_FileProc are compatible. (JL) 3/7/96 (API change) Modified signature of Tcl_GetChannelOption to return an int instead of char *, and to take a Tcl_DString * argument. Modified the implementation so that the option name can be NULL, to mean that the call should retrieve a list of alternating option names and values. (JL) *** INCOMPATIBILITY with Tcl 7.5b2, but not with Tcl 7.4 *** 3/7/96 (API change) Added Tcl_DriverSetOptionProc, Tcl_DriverGetOptionProc typedefs, added two slots setOptionProc and getOptionProc to the channel type structure. These may be NULL to indicate that the channel type does not support any options. (JL) *** INCOMPATIBILITY with Tcl 7.5b2, but not with Tcl 7.4 *** 3/7/96 (feature change) stdin, stdout and stderr can now be put into nonblocking mode. (JL) 3/8/96 (feature change) Eliminated dependence on the registry for finding the Tcl library files. (SS) ----------------- Released 7.5b3, 3/8/96 ----------------------- 3/12/96 (feature improvement) Modified startup script to look in several different places for the Tcl library directory. This should allow Tcl to find the libraries under all but the weirdest conditions, even without the TCL_LIBRARY environment variable being set. (JO) 3/13/96 (bug fix) Eliminated use of the "linger" option from the Windows socket implementation. (JL) 3/13/96 (new feature) Added -peername and -sockname options for fconfigure for socket channels. Code contributed by John Haxby of HP. (JL) 3/13/96 (bug fix) Fixed panic and core dump that would occur if the accept callback script on a server socket encountered an error. (JL) 3/13/96 (feature change) Added -async option to the Tcl socket command. If the command is creating a client socket and the flag is present, the client is connected asynchronously. If the option is absent (the default), the client socket is connected synchronously, and the command returns only when the connection has been completed or failed. This change was suggested by Mark Diekhans. (JL) 3/13/96 (feature change) Modified the signature of Tcl_OpenTcpClient to take an additional int argument, async. If nonzero, the client is connected to the server asynchronously. If the value is zero, the connection is made synchronously, and the call to Tcl_OpenTcpClient returns only when the connection fails or succeeds. This change was suggested by Mark Diekhans. (JL) *** INCOMPATIBILITY with Tcl 7.5b3, but not with Tcl 7.4 *** 3/14/96 (bug fix) "tclsh bogus_file_name" didn't print an error message. (JO) 3/14/96 (bug fix) Added new procedures to tclCkalloc.c so that libraries and applications can be compiled with TCL_MEM_DEBUG even if Tcl isn't (however, the converse is still not true). Patches provided by Jan Nijtmans. (JO) 3/15/96 (bug fix) Marked standard IO handles of a process as close-on-exec to fix bug in Ultrix where exec was not sharing standard IO handles with subprocesses. Fix suggested by Mark Diekhans. (JL) 3/15/96 (bug fix) Fixed asynchronous close mechanism so that it closes the channel instead of leaking system resources. The manifestation was that Tcl would eventually run out of file descriptors if it was handling a large number of nonblocking sockets or pipes with high congestion. (JL) 3/15/96 (bug fix) Fixed tests so that they no longer leak file descriptors. The manifestation was that Tcl would eventually run out of file descriptors if the tests were rerun many times (> a hundred times on Solaris). (JL) 3/15/96 (bug fix) Fixed channel creation code so that it never creates unnamed channels. This would cause a panic and core dump when the channel was closed. (JL) 3/16/96 (bug fixes) Made lots of changes in configuration stuff to get Tcl working under AIX (finally). Tcl should now support the "load" command under AIX and should work either with or without shared libraries for Tcl and Tk. (JO) 3/21/96 (configuration improvement) Changed configure script so it doesn't use version numbers (as in -ltcl7.5 and libtcl7.5.so) under SunOS 4.1, where they don't work anyway. (JO) 3/22/96 (new feature) Added C API Tcl_InterpDeleted that allows extension writers to discover when an interpreter is being deleted. (JL) 3/22/96 (bug fix) The standard IO channels are now added to each trusted interpreter as soon as the interpreter is created. This ensures against the bug where a child would do IO before the master had done any, and then the child is destroyed - the standard IO channels would be then closed and the master would be unable to do any IO. (JL) 3/22/96 (bug fix) Made Tcl more robust against interpreter deletion, by using Tcl_Preserve, Tcl_Release and Tcl_EventuallyFree to split the process of interpreter deletion into two distinct phases. Also went through all of Tcl and added calls to Tcl_Preserve and Tcl_Delete where needed. (JL) 3/22/96 (bug fix) Fixed several places where C code was reading and writing into freed memory, especially during interpreter deletion. (JL) 3/22/96 (bug fix) Fixed very deep bug in Tcl_Release that caused memory to be freed twice if the release callback did Tcl_Preserve and Tcl_Release on the same memory as the chunk currently being freed. (JL) 3/22/96 (bug fix) Removed several memory leaks that would cause memory buildup on half-K chunks in the generic IO level. (JL) 3/22/96 (bug fix) Fixed several core dumps which occurred when new AssocData was being created during the cleanups in interpreter deletion. The solution implemented now is to loop repeatedly over the AssocData until none is left to clean up. (JL) 3/22/96 (bug fix) Fixed a bug in event handling which caused an infinite loop if there were no files being watched and no timer. Fix suggested by Jan Nijtmans. (JL) 3/22/96 (bug fix) Fixed Tcl_CreateCommand, Tcl_DeleteCommand to be more robust if the interpreter is being deleted. Also fixed several order dependency bugs in Tcl_DeleteCommand which kicked in when an interpreter was being deleted. (JL) 3/26/96 (bug fix) Upon a "short read", the generic code no longer calls the driver for more input. Doing this caused blocking on some platforms even on nonblocking channels. Bug and fix courtesy Mark Roseman. (JL) 3/26/96 (new feature) Added 'package Tcltest' which is present only in test versions of Tcl; this allows the testing commands to be loaded into new interpreters besides the main one. (JL) 3/26/96 (restored feature) Recreated the Tcl_GetOpenFile C API. You can now get a FILE * from a registered channel; Unix only. (JL) 3/27/96 (bug fix) The regular expression code did not support more than 9 subexpressions. It now supports up to 20. (SS) 4/1/96 (bug fixes) The CHANNEL_BLOCKED bit was being left on on a short read, so that fileevents wouldn't fire correctly. Bug reported by Mark Roseman.(JL, RJ) 4/1/96 (bug fix) Moved Tcl_Release to match Tcl_Preserve exactly, in tclInterp.c; previously interpreters were being freed only conditionally and sometimes not at all. (JL) 4/1/96 (bug fix) Fixed error reporting in slave interpreters when the error message was being generated directly by C code. Fix suggested by Viktor Dukhovni of ESM. (JL) 4/2/96 (bug fixes) Fixed a series of bugs in Windows sockets that caused events to variously get lost, to get sent multiple times, or to be ignored by the driver. The manifestation was blocking if the channel is blocking, and either getting EAGAIN or infinite loops if the channel is nonblocking. This series of bugs was found by Ian Wallis of Cisco. Now all tests (also those that were previously commented out) in socket.test pass. (JL, SS) 4/2/96 (feature change/bug fix) Eliminated network name support in favor of better native name support. Added "file split", "file join", and "file pathtype" commands. See the "file" man page for more details. (SS) *** INCOMPATIBILITY with Tcl 7.5b3, but not with Tcl 7.4 *** 4/2/96 (bug fix) Changed implementation of auto_mkindex so tclIndex files will properly handle path names in a cross platform context. (SS) 4/5/96 (bug fix) Fixed Tcl_ReadCmd to use the channel buffer size as the chunk size it reads, instead of a fixed 4K size. Thus, on large reads, the user can set the channel buffer size to a large size and the read will occur orders of magnitude faster. For example, on a 2MB file, reading in 4K chunks took 34 seconds, while reading in 1MB chunks took 1.5 seconds (on a SS-20). Problem identified and fix suggested by John Haxby of HP. (JL) 4/5/96 (bug fix) Fixed socket creation code to invoke gethostbyname only if inet_addr failed (very unlikely). Before this change the order was reversed and this made things much slower than they needed to be (gethostbyname generally requires an RPC, which is slow). Problem identified and fix suggested by John Loverso of OSF. (JL) 4/9/96 (feature change) Modified "auto" translation mode so that it recognizes any of "\n", "\r" and "\r\n" in input as end of line, so that a file can have mixed end-of-line sequences. It now outputs the platform specific end of line sequence on each platform for files and pipes, and for sockets it produces crlf in output on all platforms. (JL) *** INCOMPATIBILITY with Tcl 7.5b3, but not with Tcl 7.4 *** 4/11/96 (new feature) Added -eofchar option to Tcl_SetChannelOption to allow setting of an end of file character for input and output. If an input eof char is set, it is recognized as EOF and further input from the channel is not presented to the caller. If an output eof char is set, on output, that byte is appended to the channel when it is closed. On Unix and Macintosh, all channels start with no eof char set for input or output. On Windows, files and pipes start with input and output eof chars set to Crlt-Z (ascii 26), and sockets start with no input or output eof char. (JL) *** INCOMPATIBILITY with Tcl 7.5b3, but not with Tcl 7.4 *** 4/17/96 (bug fix) Fixed series of bugs with handling of crlf sequence split across buffer boundaries in input, in AUTO mode. (JL, BW) 4/17/96 (test suite improvement) Fixed test suite so that tests that depend on the availability of Unix commands such as echo, cat and others are not run if these commands are not present. (JL) 4/17/96 (test suite improvement) The socket test now automatically starts, on platformst that support exec, a separate process for remote testsing. (JL) ----------------- Released 7.5, 4/21/96 ----------------------- 5/1/96 (bug fix) "file tail ~" did not correctly return the tail portion of the user's home directory. (SS) 5/1/96 (bug fix) Fixed bug in TclGetEnv where it didn't lookup environment variables correctly: could confuse "H" and "HOME", for example. (JO) 5/1/96 (bug fix) Changed to install tclConfig.sh under "make install-binaries", not "make install-libraries". (JO) 5/2/96 (bug fix) Changed pkg_mkIndex not to attempt to "load" a file unless it has the standard shared library extension. On SunOS, attempts to load Tcl scripts cause the whole application to be aborted (there's no way to get the error back into Tcl). (JO) 5/7/96 (bug fix) Moved initScript in tclUnixInit.c to writable memory to avoid potential core dumps. (JO) 5/7/96 (bug fix) Auto_reset procedure was removing procedure from init.tcl, such as pkg_mkIndex. (JO) 5/7/96 (bug fix) Fixed cast on socket address resolution code that would cause a failure to connect on Dec Alphas. (JL) 5/7/96 (bug fix) Added "time", "subst" and "fileevent" commands to set of commands available in a safe interpreter. (JL) 5/13/96 (bug fix) Preventing OS level handles for stdin, stdout and stderr from being implicitly closed when the last reference to the standard channel containing that handle is discarded when an interpreter is deleted. Explicitly closing standard channels by using "close" still works. (JL) 5/21/96 (bug fix) Do not create channels for stdin, stdout and stderr on Unix if the devices are closed. This prevents a duplicate channel name panic later on when the fd is used to open a channel and the channel is registered in an interpreter. (JL) 5/23/96 (bug fix) Fixed bug that prevented the use of standard channels in interpreters created after the last interpreter was destroyed. In the sequence interp = Tcl_CreateInterp(); Tcl_DeleteInterp(interp); interp = Tcl_CreateInterp(); channels for stdio would not be available in the second interpreter. (JL) 5/23/96 (bug fix) Fixed bug that allowed Tcl_MakeFileChannel to create new channels with Tcl_Files in them that are already used by another channel. This would cause core dumps when the Tcl_Files were being freed twice. (JL) 5/23/96 (bug fix) Fixed a logical timing bug that caused a standard channel to be removed from the standard channel table too early when the channel was being closed. If the channel was being flushed asynchronously, it could get recreated before being actually destroyed, and the recreated channel would contain the same Tcl_File as the one being closed, leading to dangling pointers and core dumps. (JL) 5/27/96 (bug fix) Fixed a bug in Tcl_GetChannelOption which caused it to always return a list of one element, a list of the settings, for -translation and -eofchar options. Now correctly returns the value described by the documentation (Mark Diekhans found this, thanks!). (JL) 5/30/96 (bug fix) Fixed a couple of syntax errors in io.test. (JL) 5/30/96 (bug fix) If a fileevent scripts gets an error, delete it before causing a background error. This is to allow the error handler to reinstall the fileevent and to prevent infinite loops if the event loop is reentered in the error handler. (JL) 5/31/96 (bug fix) Channels now will get properly flushed on exit. (JL) 6/5/96 (bug fix) Changed Tcl_Ckalloc, Tcl_Ckfree, and Tcl_Ckrealloc to Tcl_Alloc, Tcl_Free, and Tcl_Realloc. Added documentation for these routines now that they are officially supported. Extension writers should use these routines instead of free() and malloc(). (SS) 6/10/96 (bug fix) Changes the Tcl close command so that it no longer waits on nonblocking pipes for the piped processes to exit; instead it reaps them in the background. (JL) 6/11/96 (bug fix) Increased the length of the listen queue for server sockets on Unix from 5 to 100. Some OSes will disregard this and reset it to 5, but we should try to get as long a queue as we can, for performance reasons. (JL) 6/11/96 (bug fix) Fixed windows sockets bug that caused a cascade of events if the fileevent script read less than was available. Now reading less than is available does not cause a flood of Tcl events. (JL, SS) 6/11/96 (bug fix) Fixed bug in background flushing on closed channels that would prevent the last buffer from getting flushed. (JL) 6/13/96 (bug fix) Fixed bug in Windows sockets that caused a core dump if a DLL linked with tcl.dll and referred to e.g. ntohs() without opening a Tcl socket. The problem was that the indirection table was not being initialized. (JL) 6/13/96 (bug fix) Fixed OS level resource leak that would occur when a Tcl channel was still registered in some interpreter when the process exits. Previously the channel was not being closed and the OS level handles were not being released; the output was being flushed but the device was not being closed. Now the device is properly closed. This was only a problem on Win3.1 and MacOS. (JL, SS) 6/28/96 (bug fix) Fixed bug where transient errors were leaving an error code around, so that it would erroneously get reported later. This bug was exercised intermittently by closing a channel to a file on a very loaded NFS server, or to a socket whose other end blocked. (JL, BW) 7/3/96 (bug fix) Fileevents declared in an interpreter are now deleted when the channel is closed in that interpreter. Before this fix, the fileevent would hang around until the channel is completely closed, and would cause errors if events happened before the channel was closed. This could happen in two cases: first if the channel is shared between several interpreters, and second if an async flush is in progress that prevents the channel from being closed until the flush finishes. (JL) 7/10/96 (bug fix) Fixed bugs in both "lrange" and "lreplace" commands where too much white space was being removed. For example, the command lreplace {\}\ hello} end end was returning "\}\", losing the significant space in the first list element and corrupting the list. (JO) 7/20/96 (bug fix) The procedure pkg_mkIndex didn't work properly for extensions that depend on Tk, because it didn't load Tk into the child interpreter before loading the extension. Now it loads Tk if Tk is present in the parent. (JO) 7/23/96 (bug fix) Added compat version of strftime to fix crashes resulting from bad implementations under Windows. (SS) 7/23/96 (bug fix) Standard implementations of gmtime() and localtime() under Windows did not handle dates before 1970, so they were replaced with a revised implementation. (SS) 7/23/96 (bug fix) Tcl would crash on exit under Borland 5.0 because the global environ pointer was left pointing to freed memory. (SS) 7/29/96 (bug fix) Fixed memory leak in Tcl_LoadCmd that could occur if a package's AppInit procedure called Tcl_StaticPackage to register static packages. (JO) 8/1/96 (bug fix) Fixed a series of bugs in Windows sockets so that async writebehind in the presence of read event handlers now works, and so that async writebehind also works on sockets for which a read event handler was declared and whose channels were then closed before the async write finished. The bug was reported by John Loverso and Steven Wahl, independently, test case supplied by John Loverso. (JL) ----------------- Released patch 7.5p1, 8/2/96 ----------------------- 5/8/96 (new feature) Added Tcl_GetChannelMode C API for retrieving whether a channel is open for reading and writing. (JL) 5/8/96 (API changes) Revised C APIs for channel drivers: - Removed all Tcl_Files from channel driver interface; you can now have channels that are not based on Tcl_Files. - Added channelReadyProc and watchChannelProc procedures to interface; these are used to implement event notification for channels. - Added getFileProc to channel driver, to allow the generic IO code to retrieve a Tcl_File from a channel (presumably if the channel uses Tcl_Files they will be stored inside its instanceData). (JL) *** INCOMPATIBILITY with Tcl 7.5 *** 5/8/96 (API change) The Tcl_CreateChannel C API was modified to not take Tcl_File arguments, and instead to take a mask specifying whether the channel is readable and/or writable. (JL) *** INCOMPATIBILITY with Tcl 7.5 *** 6/3/96 (bug fix) Made Tcl_SetVar2 robust against the case where the value of the variable is a NULL pointer instead of "". (JL) 6/17/96 (bug fix) Fixed "reading uninitialized memory" error reported by Purify, in Tcl_Preserve/Tcl_Release. (JL) 8/9/96 (bug fix) Fixed bug in init.tcl that caused incorrect error message if the act of autoloading a procedure caused the procedure to be invoked again. (JO) 8/9/96 (bug fix) Configure script produced bad library names and extensions under SunOS and a few other platforms if the --disable-load switch was used. (JO) 8/9/96 (bug fix) Tcl_UpdateLinkedVar generated an error if the variable being updated was read-only. (JO) 8/14/96 (bug fix) The macintosh now supports synchronous socket connections. Other minor bugs were also fixed. (RJ) 8/15/96 (configuration improvement) Changed the file patchlevel.h to be tclPatch.h. This avoids conflict with the Tk file and is now in 8.3 format on the Windows platform. (RJ) 8/20/96 (bug fix) Fixed core dump in interp alias command for interpreters created with Tcl_CreateInterp (as opposed to with Tcl_CreateSlave). (JL) 8/20/96 (bug fix) No longer masking ECONNRESET on Windows sockets so that the higher level of the IO mechanism sees the error instead of entering an infinite loop. (JL) 8/20/96 (bug fix) Destroying the last interpreter no longer closes the standard channels. (JL) 8/20/96 (bug fix) Closing one of the stdin, stdout or stderr channels and then opening a new channel now correctly assigns the new channel as the standard channel that was closed. (JL) 8/20/96 (bug fix) Added code to unix/tclUnixChan.c for using ioctl with FIONBIO instead of fcntl with O_NONBLOCK, for those versions of Unix where either O_NONBLOCK is not supported or implemented incorrectly. (JL) 8/21/96 (bug fix) Fixed "file extension" so it correctly returns the extension on files like "foo..c" as "..c" instead of ".c". (SS) 8/22/96 (bug fix) If environ[] contains static strings, Tcl would core dump in TclSetupEnv because it was trying to write NULLs into the actual data in environ[]. Now we instead copy as appropriate. (JL) 8/22/96 (added impl) Added missing implementation of Tcl_MakeTcpClientChannel for Windows platform. Code contributed by Mark Diekhans. (JL) 8/22/96 (new feature) Added a new memory allocator for the Macintosh version of Tcl. It's quite a bit faster than MetroWerk's version. (RJ) 8/26/96 (documentation update) Removed old change bars (for all changes in Tcl 7.5 and earlier releases) from manual entries. (JO) 8/27/96 (enhancement) The exec and open commands behave better and work in more situations under Windows NT and Windows 95. Documentation describes what is still lacking. (CS) 8/27/96 (enhancement) The Windows makefiles will now compile even if the compiler is not in the path and/or the compiler's environment variables have not been set up. (CS) 8/27/96 (configuration improvement) The Windows resource files are automatically updated when the version/patch level changes. The header file now has a comment that reminds the user which other files must be manually updated when the version/patch level changes. (CS) 8/28/96 (new feature) Added file manipulation features (copy, rename, delete, mkdir) that are supported on all platforms. They are implemented as subcommands to the "file" command. See the documentation for the "file" command for more information. (JH) ----------------- Released 7.6b1, 8/30/96 ----------------------- 9/3/96 (bug fix) Simplified code so that standard channels are created lazily, they are added to an interpreter lazily, and they are never added to a safe interpreter. (JL) 9/3/96 (bug fix) Closing a channel after closing a standard channel, e.g. stdout, would cause the implicit recreation of that standard channel. (JL) 9/3/96 (new feature) Now calling Tcl_RegisterChannel with a NULL interpreter increments the refcount so that code outside any interpreter can use channels that are also registered in interpreters, without worrying that the channel may turn into a dangling pointer at any time. Calling Tcl_UnregisterChannel with a NULL interpreter only decrements the recount so that code outside any interpreter can safely declare it is no longer interested in a channel. (JL) 9/4/96 (new features) Two changes to dynamic loading: - If the file name is empty in the "load" command and there is no statically loaded version of the package, a dynamically loaded version will be used if there is one. - Tcl_StaticPackage ignores redundant calls for the same package. (JO) 9/6/96 (bug fix) Platform specific procedures for manipulating files are no longer macros and have been prefixed with "Tclp", such as TclpRenameFile. Unix file code now handles symbolic links and other special files correctly. The semantics of file copy and file rename has been changed so that if a target directory exists, the source files will NOT be merged with the existing files. (JH) 9/6/96 (bug fix) If standard channel is NULL, because Tcl cannot connect to the standard channel, do not increment the refcount. The channel can be NULL if there is for example no standard input. (JL) 9/6/96 (portability improvement) Changed parsing of backslash sequences like \n to translate directly to absolute values like 0xa instead of letting the compiler do the translation. This guarantees that the translation is done the same everywhere. (JO) 9/9/96 (bug fix) If channel is opened and not associated with any interpreter, but Tcl decides to use it as one of the standard channels, it became impossible to close the channel with Tcl_Close -- instead you had to call Tcl_UnregisterChannel. Fixed now so that it's safe to call Tcl_Close even when Tcl is using the channel as one of the standard ones. (JL) 9/11/96 (feature change) The Tcl library is now placed in the Tcl shared libraries resource. You no longer need to place the Tcl files in your applications explicitly. (RJ) 9/11/96 (feature change) Extensions no longer automatically have the resource fork of the extension opened for it. Instead you need to use the tclMacLibrary.c file in your extension. (RJ) *** POTENTIAL INCOMPATIBILITY *** 9/12/96 (bug fix) The extension loading mechanism on the Macintosh now looks at the 'cfrg' resource to determine where to load the code fragment from. This means FAT fragments should now work. (RJ) 9/18/96 (enhancement) The exec and open commands behave better and work in more situations under Windows 3.X. Documentation describes what is still lacking. (CS) 9/19/96 (bug fix) Fixed a panic which would occur if you delete a non-existent alias before any aliases are created. Now instead correctly returns an error that the alias is not found. (JL) 9/19/96 (bug fix) Slave interpreters could rename aliases and they would not get deleted when the alias was being redefined. This led to dangling pointers etc. (JL) 9/19/96 (bug fix) Fixed a panic where a hash table entry was being deleted twice during alias management operations. (JL) 9/19/96 (bug fix) Fixed bug in event loop that could cause the input focus in Tk to get confused during menu traversal, among other problems. The problem was related to handling of the "marker" when its event was deleted. (JO) 9/26/96 (bug fix) Windows was losing EOF on a socket if the FD_CLOSE event happened to precede any left over FD_READ events. Now correctly remembers seeing FD_CLOSE, so that trailing FD_READ events are not discarded if they do not contain any data. This allows Tcl to correctly get a zero read and notice EOF. (JL) 9/26/96 (bug fix) Was not resetting READABLE state properly on sockets under Windows if the driver discarded an FD_READ event because no data was present. Now correctly resets the state. (JL) 9/30/96 (bug fix) Made EOF sticky on Windows sockets, so that fileevent readable will fire repeatedly until the socket is closed. Previously the fileevent fired only once. This could lead to never-closed connections if the Tcl script in the fileevent wasn't closing the socket immediately. (JL) 10/2/96 (new feature) Improved the package loader: - Added new variable tcl_pkgPath, which holds the default directories under which packages are normally installed (each package goes in a separate subdirectory of a directory in $tcl_pkgPath). These directories are included in auto_path by default. - Changed the package auto-loader to look for pkgIndex.tcl files not only in the auto_path directories but also in their immediate children. This should make it easier to install and uninstall packages (don't have to change auto_path or merge pkgIndex.tcl files). (JO) 10/3/96 (bug fix) Changed tclsh to look for tclshrc.tcl instead of tclsh.rc on startup under Windows. This is more consistent with wish and uses the right extension. (SS) *** POTENTIAL INCOMPATIBILITY *** 10/8/96 (bug fix) Convertclock does not parse 24-hour times of the form "hhmm" correctly when hour = 00. In the parse code, hour must be >= 100 for minutes to be non-zero. Thanks to Lint LaCour for this bug fix. (RJ) 10/11/96 (bug fix) Under Windows, the pid command returned the process handle instead of the process id. (SS) ----------------- Released 7.6, 10/16/96 ----------------------- 10/29/96 (bug fix) Under Windows, sockets would consume 100% CPU time after the first accept(), due to a typo. (JL) 10/29/96 (bug fix) Incorrect refcount management caused standard channels not to get deleted at process exit or DLL unload time, causing a memory leak of upwards of 20K each time. (JL) 11/7/96 (bug fix) Auto-exec didn't work on file names that contained spaces. (JO) 11/8/96 (bug fix) Fixed core dump that would occur if more than one call to Tcl_DeleteChannelHandler was made to delete a given channel handler. (JL) 11/8/96 (bug fix) Fixed test for return value in Tcl_Seek and Tcl_SeekCmd to only treat -1 as error, instead of all negative numbers. (JL) 11/12/96 (bug fix) Do not blocking waiting for processes at the end of a pipe during exit cleanup. (JL) 11/12/96 (bug fix) If we are in exit cleanup, do not close the system level file descriptors 0, 1 and 2. Previously they were being closed which is incorrect, in the embedded case. This led to weird behavior for programs that want to interpose on I/O through the standard file descriptors (e.g. Netscape Navigator). (JL) 11/15/96 (bug fix) Fixed core dump on Windows sockets due to dependency on deletion order at exit. Now all socket functions check to see if sockets are (still) initialized, before calling through function pointers. Before, they would call and might end up calling unloaded object code. (JL) 11/15/96 (bug fix) Fixed core dump in Windows socket initialization routine if sockets were not installed on the system. Before, it was not properly checking the result of attempting to load the socket DLL, so it would call through uninitialized function pointers. (JL) 11/15/96 (bug fix) Fixed memory leak in Windows sockets which left socket DLL handle open and could hold the socket DLL in memory uneccessarily, until a reboot. (JL) 12/4/96 (bug fix) Fixed bug in Macintosh socket code that could result in lost data if a client was closed too soon after sending data. (RJ) 12/17/96 (bug fix) Fixed deadlock bug in Windows sockets due to losing an event. This was happening because of an interaction between buffering and nonblocking mode on sockets. Now switched to sockets being blocking by default, so we are also no longer emulating blocking through a private event loop. (JL) 1/21/97 (performance bug fix) Client TCP connections were slow to create because getservbyname was always called on the port. Now this is only done if Tcl_GetInt fails. (BW) 1/21/97 (configuration fix) Made it possible to override TCL_PACKAGE_PATH during make. Previously it was only set during autoconf process. 1/29/97 (bug fix) Fixed some problems with the clock command that impacted how dates were scaned after the year 2000. (RJ) ----------------- Released 7.6p2, 1/31/97 ----------------------- 2/5/97 (bug fix) Fixed a bug where in CR-LF translation mode, \r bytes in the input stream were not being handled correctly. (JL) 2/24/97 (bug fix) Fix bug with exec under Win32s not being able to create stderr file which caused all execs to fail. Fixed temp file leak under Win32s. Fixed optional parameter bug with SearchPath that only happened under Win32s 1.25. (CCS) ---------------------------------------------------------- Changes for Tcl 7.6 go above this line. Changes for Tcl 7.7 go below this line. ---------------------------------------------------------- 5/8/96 (new feature) Added Tcl_Ungets C API for putting a sequence of bytes into a channel's input buffer. This can be used for "push" model channels where the input is obtained via callbacks instead of by request of the generic IO code. No Tcl procedure yet. (JL) 11/15/96 (new feature) Implemented hidden commands. New C APIs: Tcl_HideCommand -- hides an existing exposed command. Tcl_ExposeCommand -- exposes an existing hidden command. New tcl APIs: interp invokehidden -- invokes a hidden command in a slave. interp hide -- hides an existing exposed command. interp expose -- exposes an existing hidden command. interp hidden -- returns a list of hidden commands. The implementation of Safe Tcl now uses the new hidden commands facility to implement the safe base, instead of deleting the commands from a safe interpreter. (JL) 11/15/96 (new feature) Implemented the safe base, a mechanism for installing and requesting security policies, purely in Tcl code. Overloads the package command to also allow an interpreter to "require" a policy. The following new library commands are provided: tcl_safeCreateInterp -- creates a slave an initializes the policy mechanism. tcl_safeInitInterp -- initializes an existing slave with the policy mechanism. tcl_safeDeleteInterp -- deletes a slave and deinitializes the policy mechanism. Added a new file to the library, safeinit.tcl, to hold implementation. (JL) On 7/9/97, removed the policy loading mechanism from the Safe Base. Left only the Safe Base aliases dealing with auto-loading and source. (JL) 12/6/96 (new feature) Implemented Tcl_Finalize, an API that should be called by a process when it is done using Tcl. This API runs all the exit handlers to allow them to clean up resources etc. (JL) 12/17/96 (new feature) Add an http Tcl script package to the Tcl library. This package implements the client side of HTTP/1.0; the GET, HEAD, and POST requests. (BW) 1/21/97 (new feature) Added a "marktrusted" subcommand to the "interp" and to the interpreter object command. It removes the "safe" mark on an interpreter and disables hard-wired checks for safety in the C sources. (JL) 1/21/97 (removed feature) Removed "vwait" from set of commands available in a safe interpreter. (JL) 2/11/97 (new feature, bug fix) http package. Added -accept to http_config so you can set the Accept header. Added -handler option to http_get so you can supply your own data handler. Also fixed POST operation to set the correct MIME type on the request. (BW) ---------------------------------------------------------- Changes for Tcl 7.7 go above this line. Changes for Tcl 8.0 go below this line. ---------------------------------------------------------- 9/17/96 (bug fix) Using "upvar" it was possible to turn an array element into an array itself. Changed to disallow this; it was quirky and didn't really work correctly anyway. (JO) 10/21/96 (new feature) The core of the Tcl interpreter has been replaced with an on-the-fly compiler that translates Tcl scripts to bytecoded instructions; a new interpreter then executes the bytecodes. The compiler introduces only a few minor changes at the level of Tcl scripts. The biggest changes are to expressions and lists. - A second level of substitutions is no longer done for expressions. This substantially improves their execution time. This means that the expression "$x*4" produces a different result than in the past if x is "$y+2". Fortunately, not much code depends on the old two-level semantics. Some expressions that do, such as "expr [join $list +]" can be recoded to work in Tcl8.0 by adding an eval: e.g., "eval expr [join $list +]". - Lists are now completely parsed on the first list operation to create a faster internal representation. In the past, if you had a misformed list but the erroneous part was after the point you inserted or extracted an element, then you never saw an error. In Tcl8.0 an error will be reported. This should only effect incorrect programs that took advantage of behavior of the old implementation that was not documented in the man pages. Other changes to Tcl scripts are discussed in the web page at http://www.scriptics.com/doc/compiler.html. (BL) *** POTENTIAL INCOMPATIBILITY *** 10/21/96 (new feature) In earlier versions of Tcl, strings were used as a universal representation; in Tcl 8.0 strings are replaced with Tcl_Obj structures ("objects") that can hold both a string value and an internal form such as a binary integer or compiled bytecodes. The new objects make it possible to store information in efficient internal forms and avoid the constant translations to and from strings that occurred with the old interpreter. There are new many new C APIs for managing objects. Some of the new library procedures for objects (such as Tcl_EvalObj) resemble existing string-based procedures (such as Tcl_Eval) but take advantage of the internal form stored in Tcl objects for greater speed. Other new procedures manage objects and allow extension writers to define new kinds of objects. See the manual entries doc/*Obj*.3 (BL) 10/24/96 (bug fix) Fixed memory leak on exit caused by some IO related data structures not being deallocated on exit because their refcount was artificially boosted. (JL) 10/24/96 (bug fix) Fixed core dump in Tcl_Close if called with NULL Tcl_Channel. (JL) 11/19/96 (new feature) Added library procedures for finding word breaks in strings in a platform specific manner. See the library.n manual entry for more information. (SS) 11/22/96 (feature improvements) Added support for different levels of tracing during bytecode compilation and execution. This should help in tracking down suspected problems with the compiler or with converting existing code to use Tcl8.0. Two global Tcl variables, traceCompile and traceExec, can be set to generate tracing information in stdout: - traceCompile: 0 no tracing (default) 1 trace compilations of top level commands and procs 2 trace and display instructions for all compilations - traceExec: 0 no tracing 1 trace only calls to Tcl procs 2 trace invocations of all commands including procs 3 detailed trace showing the result of each instruction traceExec >= 2 provides a one line summary of each called command and its arguments. Commands that have been "compiled away" such as set are not shown. (BL) 11/30/96 (bug fix) The command "info nameofexecutable" could sometimes return the name of a directory. (JO) 11/30/96 (feature improvements) Changed the code in library/init.tcl that reads in pkgIndex.tcl so that (a) it reads the files from child directories before those in the parent, so that the parent gets precedence, and (b) it doesn't quit if there is an error in a pkgIndex.tcl file; instead, it prints an error message on standard error and continues. (JO) 10/5/96 (feature improvements) Partial implementation of binary string support: the ability for Tcl string values to contain embedded null bytes. Changed the Tcl object-based APIs to take a byte pointer and length pair instead of a null-terminated C string. Modified several object type managers to support binary strings but not, for example, the list type manager. Existing string-based C APIs are unchanged and will truncate binary strings. Compiled scripts containing nulls are also truncated. (BL) 12/12/96 (feature change) Removed the commands "cp", "mkdir", "mv", "rm", and "rmdir" from the Macintosh version of Tcl. They were never officially supported and their functionality is now available via the file command. (RJ) ----------------- Released 8.0a1, 12/20/96 ----------------------- 1/7/97 (bug fix) Under Windows, "file stat c:" was returning error instead of stat for current dir on c: drive. 1/10/97 (new feature) Added Tcl_GetIndexFromObj procedure for quick lookups of keyword arguments. (JO) 1/12/97 (new feature) Serial IO channel drivers for Windows and Unix, available by using Tcl open command to open pseudo-files like "com1:" or "/dev/ttya". New option to Tcl fconfigure command for serial files: "-mode baud,parity,data,stop" to specify baud rate, parity, data bits, and stop bits. Serial IO is not yet available on Mac. 1/16/97 (feature change) Restored the Tcl7.x "two level substitution semantics" for expressions. Expressions not enclosed in braces are implemented, in general, by calling the expr command procedure (Tcl_ExprObjCmd) at runtime after the Tcl interpreter has already done a first round of substitutions. This is slow (about Tcl7.x speed) because new code for the expression is generally compiled each time. However, if the expression has only variable substitutions (and not command substitutions), "optimistic" fast code is generated inline. This inline code will fail if a second round of substitutions is needed (i.e., if the value of a substituted variable itself requires more substitutions). The optimistic code will catch the error and back off to call the slower but guaranteed correct expr command procedure. (BL) 1/16/97 (feature improvements) Added Tcl_ExprLongObj and Tcl_ExprDoubleObj to round out expression-related procedures. (BL) 1/16/97 (feature change) Under Windows, at startup the environment variables "path", "comspec", and "windir" in any capitalization are converted automatically to upper case. The PATH variable could be spelled as path, Path, PaTh, etc. and it makes programming rather annoying. All other environment variables are left alone. (CS) 1/20/97 (new features) Rewrote the "lsort" command: - The new version is based on reentrant merge sort code provided by Richard Hipp, so it eliminates the reentrancy and stability problems with the old qsort-based implementation. - The new version supports a -dictionary option for sorting, and it also supports a -index option for sorting lists using one element for comparison. - The new version is an object command, so it works well with the Tcl compiler, especially in conjunction with the new -index option. When the -index option is used, this version of lsort is more than 100 times faster than the Tcl 7.6 lsort, which had to use the -command option to get the same effect. (JO) 1/20/97 (feature improvements) Added the improved debugging support for Tcl objects prototyped by Karl Lehenbauer . If TCL_MEM_DEBUG is defined, the object creation calls use Tcl_DbCkalloc directly in order to record the caller's source file name and line number. (BL) 1/21/97 (removed feature) Desupported the tcl_precision variable: if set, it is ignored. Tcl now uses the full 17 digits of precision when converting real numbers to strings (with the new object system real numbers are rarely converted to strings so there is no efficiency disadvantage to printing all 17 digits; the new scheme improves accuracy and simplifies several APIs). (JO) *** POTENTIAL INCOMPATIBILITY *** 1/21/97 (feature change) Removed the "interp" argument for the procedures Tcl_GetStringFromObj, Tcl_StringObjAppend, and Tcl_StringObjAppendObj. Also removed the "interp" argument for the updateStringProc procedure in Tcl_ObjType structures. With the tcl_precision changes above, these are no longer needed. (JO) *** POTENTIAL INCOMPATIBILITY with Tcl 8.0a1, but not with Tcl 7.6 *** 1/22/97 (bug fix) Fixed http.tcl so that http_reset does not result in an extra call to the command callback. In addition, if the transaction gets a premature eof, the state(status) is "eof", not "ok". (BW) ----------------- Released 8.0a2, 1/24/97 ----------------------- 1/29/97 (feature change) Changed how two digit years are parsed in the clock command. The old interface just added 1900 which will seem broken by the year 2000. The new scheme follows the POSIX standard and treats dates 70-99 as 1970-1999 and dates 00-38 as 2000-2038. All other two digit dates are undefined. (RJ) *** POTENTIAL INCOMPATIBILITY *** 2/4/97 (bug fix) Fixed bug in clock code that dealt with relative dates. Using the relative month code you could get an invalid date because it jumped into a non-existant day. (For example, Jan 31 to Feb 31.) The code now will return the last valid day of the month in these situations. Thanks to Hume Smith for sending in this bug fix. (RJ) 2/10/97 (feature change) Eliminated Tcl_StringObjAppend and Tcl_StringObjAppendObj procedures, replaced them with Tcl_AppendToObj and Tcl_AppendStringsToObj procedures. Added new procedure Tcl_SetObjLength. (JO) *** POTENTIAL INCOMPATIBILITY with Tcl 8.0a2, but not with Tcl 7.6 *** 2/10/97 (new feature) Added Tcl_WrongNumArgs procedure for generating error messages about incorrect number of arguments. (JO) 2/11/97 (new feature, bug fix) http package. Added -accept to http_config so you can set the Accept header. Added -handler option to http_get so you can supply your own data handler. Also fixed POST operation to set the correct MIME type on the request. (BW) 2/22/97 (bug fix) Fixed bug that caused $tcl_platform(osVersion) to be computed incorrectly under AIX. (JO) 2/25/97 (new feature, feature change) Added support for both int and long integer objects. Added Tcl_NewLongObj/Tcl_GetLongFromObj/Tcl_SetLongFromObj procedures and renamed the Tcl_Obj internalRep intValue member to longValue. Tcl_GetIntFromObj now checks for integer values too large to represent as non-long integers. Changed Tcl_GetAllObjTypes to Tcl_AppendAllObjTypes. (BL) 3/5/97 (new feature) Added new Tcl_SetListObj procedure to round out collection of procedures that set the type and value of existing Tcl objects. (BL) 3/6/97 (new feature) Added -global flag for interp invokehidden. (JL) 3/6/97 (new feature, feature change) Added isNativeObjectProc field to the Tcl_CmdInfo structure to indicate (when 1) if the command has an object-based command procedure. Removed the nameLength arg from Tcl_CreateObjCommand since command names can't contain null characters. (BL) 3/6/97 (bug fix) Fixed bug in "unknown" procedure that caused auto- loading to fail on commands whose names begin with digits. (JO) 3/7/97 (bug fix) Auto-loading now works in Safe Base. Safe interpreters only accept the Version 2 and onwards tclIndex files. (JL) 3/13/97 (bug fix) Fixed core dump due to interaction between aliases and hidden commands. Bug found by Lindsay Marshall. (JL) 3/14/97 (bug fix) Fixed mac bugs relating to time. The -gmt option now adjusts the time in the correct direction. (Thanks to Ed Hume for reporting a fix to this problem.) Also fixed file "mtime" etc. to return times from GMT rather than local time zone. (RJ) 3/18/97 (feature change) Declaration of objv in Tcl_ObjCmdProc function changed from "Tcl_Obj *objv[]" to "Tcl_Obj *CONST objv[]". All Tcl object commands changed to use new declaration of objv. Naive translation of string-based command procs to object-based command procs could very easily have yielded code where the contents of the objv array were changed. This is not a problem with string-based command procs, but doing something as simple as objv[2] = objv[3] would corrupt the runtime stack and cause Tcl to crash. Introduced CONST in declaration of objv so that attempted assignment of new pointer values to elements of the objv array will be caught by the compiler. (CCS) *** POTENTIAL INCOMPATIBILITY with Tcl 8.0a2 *** 3/19/97 (bug fix) Fixed panic due to object sharing. The root cause was that old code was using Tcl_ResetResult instead of Tcl_ResetObjResult. (JL) 3/20/97 (new feature) Added a new subcommand for the file command. file attributes filename can give a list of platform-specific options (such as file/creator type on the Mac, permissions on Unix) or set the values of them. Added a new subcommand for the file command. file nativename name gives back the platform-specific form for the file. This is useful when the filename is needed to pass to the OS, such as exec under Windows 95 or AppleScript on the Mac. For more info, see file.n. (SRP) 3/24/97 (removed feature) Removed the tcl_safePolicyPath procedure. Now the policy path is computed from the auto_path by appending the directory 'policies' to each element. Also fixed several bugs in automatic tracking of auto_path by computed policy path. (JL) *** POTENTIAL INCOMPATIBILITY with Tcl 8.0a2 but not with Tcl 7.6 *** 4/8/97 (new feature) If the variable whose name is passed to lappend doesn't already exist, and there are no value arguments, lappend now creates the variable with an empty value instead of returning an error. Change suggested by Tom Tromey. (BL) 4/9/97 (feature change) Changed the name of the TCL_PART1_NOT_PARSED flag to TCL_PARSE_PART1. (BL) *** POTENTIAL INCOMPATIBILITY with Tcl 8.0a2 but not with Tcl 7.6 *** 4/10/97 (bug fixes) Fixed various compilation-related bugs: - "UpdateStringOfCmdName should never be invoked" panic. - Bad code generated for expressions not in {}'s inside catch commands. - Segmentation fault in some command procedures when two argument object pointers refer to the same object. - Second level of substitutions were never done for expressions not in {}'s that consist of a single variable reference: e.g., "set x 27; set bool {$x}; if $bool {puts foo}" would fail with error. - Bad code generated when code storage was grown while compiling some expressions: ones with compilation errors or consisting of only a variable reference. - Bugs involving multiple interpreters: wasn't checking that a procedure's code was compiled for the same interpreter as the one executing it, and didn't invalidate code on hidden-exposed command transitions. - "Bad stack top" panic when executing scripts that require a huge amount of stack space. - Incorrect sharing of code for procedure bodies, and procedure code deallocated before last execution of the procedure finished. - Fixed compilation of expression words in quotes. For example, if "0 < 3" {puts foo}. - Fixed performance bug in array set command with large assignments. - Tcl_SetObjLength segmentation fault setting length of empty object. - If Tcl_SetObjectResult was passed the same object as the interpreter's result object, it freed the object instead of doing nothing. Bug fix by Michael J. McLennan. - Tcl_ListObjAppendList inserted elements from the wrong list. Bug fix by Michael J. McLennan. - Segmentation fault if empty variable list was specified in a foreach command. Bug fix by Jan Nijtmans. - NULL command name was always passed to Tcl_CreateTrace callback procedure. - Wrong string representation generated for the value LONG_MIN. For example, expr 1<<31 printed incorrectly on a 32 bit machine. - "set {a($x)} 1" stored value in wrong variable. - Tcl_GetBooleanFromObj was not checking for garbage after a numeric value. - Garbled "bad operand type" error message when evaluating expressions not surrounded by {}'s. (BL) 4/16/97 (new feature) The expr command now has the "rand()" and "srand()" functions for getting random numbers in expr. (RJ) 4/23/97 (bug fix) Fixed core dump in bgerror when the error handler command deletes the current interpreter. Found by Juergen Schoenwald. (JL) 4/23/97 (feature change) The notifier interfaces have been redesigned to make embedding in applications with external event loops possible. A number of interfaces in the notifier and the channel drivers have changed. Refer to the Notifier.3 and CrtChannel.3 manual entries for more details. (SS) *** POTENTIAL INCOMPATIBILITY *** 4/23/97 (removed feature) The Tcl_File interfaces have been removed. The Tcl_CreateFileHandler/Tcl_DeleteFileHandler interfaces now take Unix fd's and are only supported on the Unix platform. Tcl_GetChannelFile has been replaced with Tcl_GetChannelHandle. Tcl_MakeFileChannel now takes a platform specific file handle. (SS) *** POTENTIAL INCOMPATIBILITY *** 4/23/97 (removed feature) The modal timeout interface has been removed (Tcl_CreateModalTimeout/Tcl_DeleteModalTimeout) (SS) *** POTENTIAL INCOMPATIBILITY *** 4/23/97 (feature change) Channel drivers are now required to correctly implement blocking behavior when they are in blocking mode. (SS) *** POTENTIAL INCOMPATIBILITY *** 4/23/97 (new feature) Added the "binary" command for manipulating binary strings. Also, changed the "puts", "gets", and "read" commands to preserve embedded nulls. (SS) 4/23/97 (new feature) Added tcl_platform(byteOrder) element to the tcl_platform array to identify the native byte order for the current host. (SS) 4/23/97 (bug fix) Fixed bug in date parsing around year boundaries. (SS) 4/24/97 (bug fix) In the process of copying a file owned by another user, Tcl was changing the owner of the copy back to the owner of the original file, therefore causing further file operations to fail because the current user didn't own the copy anymore. The owner of the copy is now left as the current user. (CCS) 4/24/97 (feature change) Under Windows, don't automatically uppercase the environment variable "windir" -- it's supposed to be lower case. (CCS) 4/29/97 (new feature) Added namespace support based on a namespace implementation by Michael J. McLennan of Lucent Technologies. A namespace encapsulates a collection of commands and variables to ensure that they won't interfere the commands and variables of other namespaces. The global namespace holds all global variables and commands. Additional namespaces are created with the new namespace command. The new variable command lets you create Tcl variables inside a namespace. The names of Tcl variables and commands may now be qualified by the name of the namespace containing them. The key namespace-related commands are summarized below: - namespace ?eval? name arg ?arg...? Used to define the commands and variables in a namespace. Optionally creates the namespace. - namespace export ?-clear? ?pattern pattern...? Specifies which commands are exported from a namespace. These are the ones that can be imported into another namespace. - namespace import ?-force? ?pattern pattern...? Makes the specified commands accessible in the current namespace. - namespace current Returns the name of the current namespace. - variable name ?value? ?name ?value?...? Creates one or more namespace variables. (BTL) 5/1/97 (bug fix) Under Windows, file times were reported in GMT. Should be reported in local time. (CCS) 5/2/97 (feature change) Changed the name of the two Tcl variables used for tracing bytecode compilation and execution to tcl_traceCompile and tcl_traceExec respectively. These variables are now documented in the tclvars man page. (BL) 5/5/97 (new feature) Support "end" as the index for "lsort -index". (BW) 5/5/97 (bug fixes) Cleaned up the way the http package resets connections (BW) 5/8/97 (feature change) Newly created Tcl objects now have a reference count of zero instead of one. This simplifies C code that stores newly created objects in Tcl variables or in data structures such as list objects. That C code must increment the new object's reference count since the variable or data structure will contain a long-term reference to the object. Formerly, when new objects started out with reference count one, it was necessary to decrement the new object's reference count after the store to make sure it was left with the correct value; this is no longer necessary. (BL) 5/9/97 (new feature) Added the Tcl_GetsObj interface that takes an object reference instead of a dynamic string (as in Tcl_Gets). (SS) 5/12/97 (new feature) Added Tcl_CreateAliasObj and Tcl_GetAliasObj C APIs to allow an alias command to be created with a vector of Tcl_Obj structures and to get the vector back later. (JL) 5/12/97 (feature change) Changed Tcl_ExposeCommand and Tcl_HideCommand to leave an object result instead of a string result. (JL) 5/14/97 (feature change) Improved the handling of the interpreter result. This is still either an object or a string, but the two values are now kept consistent unless some C code reads or writes interp->result directly. See the SetResult man page for details. Removed the Tcl_ResetObjResult procedure. (BL) *** POTENTIAL INCOMPATIBILITY with Tcl 8.0a2 *** 5/16/97 (new feature) Added "fcopy" command to move data between channels. Refer to the manual page for more information. Removed the "unsupported0" command since it is obsolete now. (SS) 5/16/97 (new feature) Added Tcl_GetStringResult procedure to allow programs to get an interpreter's result as a string. If the result was previously set to an object, this procedure will convert the object to a string. Use of Tcl_GetStringResult is intended to replace direct access to interp->result, which is not safe. (BL) 5/20/97 (new features) Fixed "fcopy" to return the number of bytes transferred in the blocking case. Updated the http package to use fcopy instead of unsupported0. Added -timeout and -handler options to http_get. http_get is now blocking by default. It is only non-blocking if you supply a -command argument. (BW) 5/22/97 (bug fix) Fixed several bugs in the "lsort" command having to do with the -dictionary option and the presence of numbers embedded in the strings. (JO) ----------------- Released 8.0b1, 5/27/97 ----------------------- 6/2/97 (bug fix) Fixed bug in startup code that caused a problem in finding the library files when they are installed in a directory containing a space in the name. (SS) 6/2/97 (bug fix) Fixed bug in Unix notifier where the select mask was not being cleared under some circumstances. (SS) 6/4/97 (bug fix) Fixed bug that prevented creation of Tk widgets in namespaces. Tcl_CreateObjCommand and Tcl_CreateCommand now always create commands in the global namespace unless the command names are qualified. Tcl procedures continue to be created in the current namespace by default. (BL) 6/6/97 (new features) Added new namespace API procedures Tcl_AppendExportList and Tcl_Export to allow C code to get and set a namespace's export list. (BL) 6/11/97 (new feature) Added Tcl_ConcatObj. This object-based routine parallels the string-based routine Tcl_Concat. (SRP) 6/11/97 (new feature) Added Tcl_SetObjErrorCode. This object-based routines parallels the string-based routine Tcl_SetErrorCode. (SRP) 6/12/97 (bug fix) Fix the "unknown" procedure so that wish under Windows will exec an external program, instead of always complaining "console1 not opened for writing". (CCS) 6/12/97 (bug fix) Fixed core dump experienced by the following simple script: interp create x x alias exec exec interp delete x This panic was caused by not installing the new CmdDeleteProc when exec got redefined by the alias creation step. Reported by Lindsay Marshal (JL) 6/13/97 (new features) Tcl objects newly created by Tcl_NewObj now have a string representation that points to a shared heap string of length 1. (They used to have NULL bytes and typePtr fields. This was treated as a special case to indicate an empty string, but made type manager implementations complex and error prone.) The new procedure Tcl_InvalidateStringRep is used to mark an object's string representation invalid and to free any storage associated with the old string representation. (BL) *** POTENTIAL INCOMPATIBILITY with Tcl 8.0b1, but not with Tcl7.6 *** 6/16/97 (bug fix) Tcl_ScanCountedElement could leave braces unmatched if the string ended with a backslash. (JO) 6/17/97 (bug fix) Fixed channel event bug where readable events would be lost during recursive events loops if the input buffers contained data. (SS) 6/17/97 (bug fix) Fixed bug in Windows socket code that didn't reenable read events in the case where an external entity is also reading from the socket. (SS) 6/18/97 (bug fix) Changed initial setting of the notifier service mode to TCL_SERVICE_NONE to avoid unexpected event handling during initialization. (SS) 6/19/97 (bug fix/feature change) The command callback to fcopy is now called in case of errors during the background copy. This adds a second, optional argument to the callback that is the error string. The callback in case of errors is required for proper cleanup by the user of fcopy. (BW) *** POTENTIAL INCOMPATIBILITY with Tcl 8.0b1, but not with Tcl 7.6 *** 6/19/97 (bug fix) Fixed a panic due to the following four line script: interp create x x alias foo bar x eval rename foo blotz x alias foo {} The problem was that the interp code was not using the actual current name of the command to be deleted as a result of un-aliasing foo. (JL) 6/19/97 (feature change) Pass interp down to the ChannelOption and driver specific calls so system errors can be differentiated from syntax ones. Changed Tcl_DriverGetOptionProc type. Affects Tcl_GetChannelOption, TcpGetOptionProc, TtyGetOptionProc, etc. (DL) *** POTENTIAL INCOMPATIBILITY *** 6/19/97 (new feature) Added Tcl_BadChannelOption for use by by driver specific option procedures (Set and Get) to return a complete and meaningful error message. (DL) 6/19/97 (bug fixes) If a system call error occurs while doing an fconfigure on tcp or tty/com channel: return the appropriate error message (instead of the syntax error one or none). (Fixed for Unix and most of the Win and Mac drivers). (DL) 6/20/97 (feature change) Eval is no longer assumed as the subcommand name in namespace commands: you must now write "namespace eval nsName {...}". Abbreviations of namespace subcommand names are now allowed. (BL) *** POTENTIAL INCOMPATIBILITY with Tcl 8.0b1, but not with Tcl7.6 *** 6/20/97 (feature change) Changed the errorInfo traceback message for compilation errors from "invoked from within" to "while compiling". (BL) 6/20/97 (bug fixes) Fixed various compilation-related bugs: - "UpdateStringOfCmdName should never be called" and "UpdateStringOfByteCode should never be called" panics. - Segfault in TclObjInterpProc getting procedure name after evaluation stack is reallocated (grown). - Could not use ":" at end of variable and command names. - Bad code generated for while and for commands with test expressions enclosed in quotes: e.g., "set i 0; while "$i > 5" {}". - Command trace procedures would crash if they did a Tcl_EvalObj that reallocated the evaluation stack. - Break and continue commands did not reset the interpreter result. - The Tcl_ExprXXX routines, both string- or object-based, always modified the interpreter result even if there was no error. - The argument parsing procedure used by several compile procedures always treated "]" as end of a command: e.g., "set a ]" would fail. - Changed errorInfo traceback message for compilation errors from "invoked from within" to "while compiling". - Problem initializing Tcl object managers during interpreter creation. - Added check and error message if formal parameter to a procedure is an array element. (BL) 6/23/97 (new feature) Added "registry" package to allow manipulation of the Windows system registry. See manual entry for details. (SS) 6/24/97 (feature change) Converted http to a package and added the http1.0 subdirectory of the Tcl script library. This means you have to do a "package require http" to use this, as advertised in the man page. (BW) *** POTENTIAL INCOMPATIBILITY with Tcl 8.0b1, but not with Tcl 7.6 *** 6/24/97 (bug fix) Ensure that Tcl_Set/GetVar C APIs, when called without TCL_LEAVE_ERR_MSG, don't touch the interp result. (DL) 6/26/97 (feature change) Changed name of Tcl_ExprStringObj to Tcl_ExprObj. (BL) *** POTENTIAL INCOMPATIBILITY with Tcl 8.0b1, but not with Tcl 7.6 *** ----------------- Released 8.0b2, 6/30/97 ----------------------- 7/1/97 (new feature) TCL_BUILD_SHARED flag set in tclConfig.sh when Tcl has been built with --enable-shared. A new tclLibObjs make target, echoing the list of the .o's needed to build a tcl library, is now provided. (DL) 7/1/97 (feature change) compat/getcwd.c removed and changed the only place where getcwd is used so a new USEGETWD flag selects the use of the replacement "getwd". Adding this flag is recommended for SunOS 4 (because getcwd on SunOS 4 uses a pipe to pwd(1)!). (DL) 7/7/97 (feature change) The split command now supports binary data (i.e., null characters in strings). (BL) 7/7/97 (bug fix) string first returned the wrong result if the first argument string was empty. (BL) 7/8/97 (bug fix) Fixed core dump in fcopy that could occur when a command callback was supplied and an error or eof condition caused no background activity. A refcount bug triggered a panic in Tcl_ListObjAppendElement. (BW) 7/8/97 (bug fix) Relaxed the pattern matching on http_get so you do not need a trailing path component. You can now get away with just http_get www.scriptics.com (BW) 7/9/97 (bug fix) Creating anonymous interpreters no longer smashes existing commands with names similar to the generated name. Previously creating an anonymous interpreter could smash an existing command, now it skips until it finds a command name that isn't being used. (JL) 7/9/97 (feature change) Removed the policy management mechanism from the Safe Base; left the aliases to source and load modules, and to do a limited form of the "file" command. See entry of 11/15/96. (JL) 7/9/97 (bug fixes) Fixed various compilation-related bugs: - Line numbers in errorInfo now are the same as those in Tcl7.6 unless there are compilation errors. Compilation error messages now include the entire command in error. - Trailing ::s after namespace names weren't being ignored. - Could not refer to an namespace variable with an empty name using a name of the form "n::". (BL) 7/9/97 (bug fix) Fixed bug in Tcl_Export that prevented you from exporting from other than the current namespace. (BL) 7/9/97 (bug fix) env.test was removing env var needed for proper finding of libraries in child process. (DL) 7/10/97 (bug fixes/new feature) Cleanup in Tcl_MakeSafe. Less information is leaked to safe interps. Error message fixes for interp sub commands. Likewise changes in safealias.tcl; tcl_safeCreateInterp can now be called without argument to generate the slave name (like in interp create). (DL) 7/10/97 (bug fixes) Bytecode compiler now generates more detailed command location information: subcommands as well as commands now have location information. This means command trace procedures now get the correct source string for each command in their command parameter. (BL) 7/22/97 (bug fixes) Performance improvement in Safe interpreters handling. Added new mask value to (tclInt.h) Interp.flags record. (DL) 7/22/97 (bug fix) Fixed panic in 'interp target {} foo'. This bug was present since Tcl 7.6. (JL) 7/22/97 (bug fix) Fixed bug in compilation of procedures in namespaces: the procedure's namespace must be used to look up compile procedures, not the current namespace. (BL) 7/22/97 (bug fix) Use of the -channel option of http_get was not setting the end of line translations mode on the channel, so copying binary data with the -channel option was corrupting the result on non-unix platforms. (BW) 7/22/97 (bug fixes) file commands and ~user (seg fault and other improper returns). (DL) 7/23/97 (feature change) Reenabled "vwait" in Safe Base. (JL) 7/23/97 (bug fixes) Fixed two bugs involving read traces on array variables in procedures: trace procedures were sometimes not called, and reading nonexistant array elements didn't create undefined element variables that could later be defined by trace procedures. (BL) 7/24/97 (bug fix) Windows memory allocation performance was superlinear in some cases. Made the Mac allocator generic and changed both the Mac and Windows platforms to use the new allocator instead of malloc and free. (SS) 7/24/97 - 8/12/97 (bug fixes/change of features) Completely revamped safe sourcing/loading (see safe.n) to hide pathnames, use virtual paths tokens instead, improved security in several respects and made it more tunable. Multi level interp loading can work too now. Package auto loading now works in safe interps as long as the package directory is in the auto_path (no deep crawling allowed in safe interps). (DL) *** POTENTIAL INCOMPATIBILITY with previous alpha and beta releases *** 7/24/97 (bug fixes) Made Tcl_SetVar* and Tcl_NewString* treat a NULL value as an empty string. (This fixes hairy crash case where you would crash because load command for other interps assumed presence of errorInfo...). (DL) 7/28/97 (bug fix) Fixed pkg_mkIndex to understand namespaces. It will use the export list of a namespace and create auto_index entries for all export commands. Those names are in their fully qualified form in the auto_index. Therefore, I tweaked unknown to try both $cmd and ::$cmd. Also fixed pkg_mkIndex so you can have "package require" commands inside your packages. These commands are ignored, which is mostly ok except when you must load another package before loading yours because of linking dependencies. (BW) 7/28/97 (bug fix) A variable created by the variable command now persists until the namespace is destroyed or the variable is unset. This is true even if the variable has not been initialized; these variables used to be destroyed if an error occurred when accessing them. In addition, the "info vars" command lists uninitialized namespace variables, while the "info exists" command returns 0 for them. (BL) 7/29/97 (feature change) Changed the http package to use the ::http namespace. http_get renamed to http::geturl, http_config renamed to http::config, http_formatQuery renamed to http::formatQuery. It now provides the 2.0 version of the package. The 1.0 version is still available with the old names. *** POTENTIAL INCOMPATIBILITY with Tcl 8.0b2 but not with Tcl 7.6 *** 7/29/97 (bug fix, new feature) Tcl_Main now uses Tcl objects internally to preserve NULLs in commands and command output. Added new API procedure Tcl_RecordAndEvalObj that resembles Tcl_RecordAndEval but takes an object containing a command. (BL) 7/30/97 (bug fix) Tcl freed strings in the environ array even if it did not allocate them. (SS) 7/30/97 (bug fix) If a procedure is renamed into a different namespace, it now executes in the context of that namespace. (BL) 7/30/97 (bug fix) Prevent renaming of commands into and from namespaces as part of hiding them. (JL) 7/31/97 (feature change) Moved the history command from C to tcl. This uses the ::history namespace. The "words" and "substitute" options are no longer supported. In addition, the "keep" option without a value returns the current keep limit. There is a new "clear" option. The unknown command now supports !! again. (BW) *** POTENTIAL INCOMPATIBILTY *** 7/30/97 (bug fix) Made sure that a slave can not fool the master into hiding the wrong command. Made sure we don't crash in hiding + namespaces issues. (DL) 8/4/97 (bug fix) Concat, eval, uplevel, and similar commands were incorrectly trimming trailing space characters from their arguments even when the space characters were preceded by a backslash. (JO) 8/4/97 (bug fix) Removed the hard link between bgerror and tkerror. Only bgerror is supported in tcl core. Tk will still look for a tkerror but using regular tcl code for that feature. (DL) *** POTENTIAL INCOMPATIBILTY with code relying on the hard link *** 8/6/97 (bug fix) Reduced size required for compiled bytecodes by using a more compact encoding for the command pc-to-source map. (BL) 8/6/97 (new feature) Added support for additional compilation and execution statistics when Tcl is compiled with the TCL_COMPILE_STATS flag. (BL) 8/7/97 (bug fix) Expressions not in {}s that have a comparison operator as the topmost operator must be compiled out-of-line (call the expr cmd at runtime) to properly support expr's two-level substitution semantics. An example is "set a 2; set b {$a}; puts [expr $b == 2]". (BL) 8/11/97 (bug fix) The catch command would sometimes crash if a variable name was given and the bytecode evaluation stack was grown when executing the argument script. (BL) 8/12/97 (feature change) Reinstated the variable tcl_precision to control the number of digits used when floating-point values are converted to strings, with default of 12 digits. However, had to make tcl_precision shared among all interpreters (except that safe interpreters can't modify it). This makes the Tcl 8.0 behavior almost identical to 7.6 except that the default precision is 12 instead of 6. (JO) *** POTENTIAL INCOMPATIBILITY *** ----------------- Released 8.0, 8/18/97 ----------------------- 8/19/97 (bug fix) Minimal fix for glob -nocomplain bugs: "glob -nocomplain unreadableDir/*" was generating an anonymous error. More in depth fixes will come with 8.1. (DL). 8/20/97 (bug fix) Removed check for FLT_MIN in binary command so underflow conditions are handled by the compiler automatic conversions. (SS) 8/20/97 (bug fixes) Fixed several compilation-related bugs: - Array cmd wasn't detecting arrays that, while compiled, do not yet exist (e.g., are marked undefined since they haven't been assigned to yet). - The GetToken procedure in tclCompExpr.c wasn't recognizing properly whether an integer token was invalid. For example, "0x$" is not a valid integer. - Performance bug in TclExecuteByteCode: the size of its stack frame was reduced by over 20% by moving errorInfo code elsewhere. - Uninitialized memory read error in tclCompile.c. (BL) 8/21/97 (bug fix) safe::interpConfigure now behave like Tk widget's configure : it changes only the options you provide and you can get the current value of any single option. New ?-nested boolean? and ?-statics boolean? for all safe::interp* commands but we still accept (upward compatibility) the previously defined non valued flags ?-noStatics? and ?-nestedLoadOk?. Improved the documentation. (DL). 8/22/97 (bug fix) Updated PrintDbl.3 to reflect the fact that the tcl_precision variable is still used and that it is now shared by all interpreters. (BL) 8/25/97 (bug fix) Fixed array access bug in IllegalExprOperandType procedure in tclExecute.c: it was not properly supporting the || and && operators. (BL) 8/27/97 (bug fix) In cases where a channel handler was created with an empty event mask while data was still buffered in the channel, the channel code would get stuck spinning on a timer that would starve idle handlers. This mostly happened in Tk when reading from stdin. (SS) 9/4/97 (bug fix) Slave interps now inherit the maximum recursion limit of their parent instead of starting back at the default. {nb: this still does not prevent stack overflow by multi-interps recursion or aliasing} (DL) 9/11/97 (bug fix) An uninitialized variable in Tcl_WaitPid caused pipes to fail to report eof properly under Windows. (SS) 9/12/97 (bug fix) "exec" was misidentifying some DOS executables as not executable. (CCS) 9/14/97 (bug fix) Was using the wrong structure in sizeof operation in tclUnixChan.c. (JL) 9/15/97 (bug fix) Fixed notifier to break out of do-one-event loop if Tcl_WaitForEvent returns 1, so that callers of Tcl_DoOneEvent will get a chance to check whether the event just handled is significant. This affected mainly recursive calls to Tcl_VWaitCmd; these did not get a chance to notice that the variable they were waiting for has been set and thus they didn't terminate the vwait. (JL, DL, SS) 9/15/97 (bug fix) Alignment problems in "binary format" would cause a crash on some platforms when formatting floating point numbers. (SS) 9/15/97 (bug fix) Fixed bug in Macintosh socket code. Now passes all tests in socket.test that are not platform specific. (Thanks to Mark Roseman for the pointer on the fix.) (RJ) 9/18/97 (bug fix) Fixed bug -dictionary option of lsort that could cause the compare function to run off the end of an array if the number only contained 0's. (Thanks to Greg Couch for the report.) (RJ) 9/18/97 (bug fix) TclFinalizeEnvironment was not cleaning up properly. (DL, JI) 9/18/97 (bug fix) Fixed long-standing bug where an "array get" command did not trigger traces on the array or its elements. (BL) 9/18/97 (bug fixes) Fixed compilation-related bugs: - Fixed errorInfo traceback information for toplevel coomands that contain nested commands. - In the expr command, && and || now accept boolean operands as well as numeric ones. (BL) 9/22/97 (bug fix) Fixed bug that prevented translation modes from being set independently for input and output on sockets if input was "auto". (JL) 9/24/97 (bug fix) Tcl_EvalFile(3) and thus source(n) now works fine on files containing NUL chars. (DL) 9/26/97 (bug fix) Fixed use of uninitialized memory in the environ array that later could cause random core dumps. Applies to all platforms. (JL) 9/26/97 (bug fix) Fixed use of uninitialized memory in socket address data structure under some circumstances. This could cause random core dumps. This applies only to Unix. (JL) 9/26/97 (bug fix) Opening files on PC-NFS volumes would cause a hang until the system timed after the file was closed. (SS) 10/6/97 (bug fix) The join(n) command, though objectified, was loosing NULs in the joinString and in list elements after the 2nd one. Now you can "join $list \0" for instance. (DL) 10/9/97 (bug fix) Under windows, if env(TMP) or env(TEMP) referred to a non-existent directory, exec would fail when trying to create its temporary files. (CCS) 10/9/97 (bug fix) Under mac and windows, "info hostname" would crash if sockets were installed but the hostname could not be determined anyhow. Tcl_GetHostName() was returning NULL when it should have been returning an empty string. (CCS) 10/10/97 (bug fix) "file attribute /" returned error on windows. (CCS) 10/10/97 (bug fix) Fixed the auto_load procedure to handle procedures defined in namespaces better. Also fixed pgk_mkIndex so it sees procedures defined in nested namespaces. Index entries are still only made for exported procedures. (BW) 10/13/97 (bug fix) On unix, for files with unknown group or owner attributes, querying the "file attributes" would return an error rather than returning the group's or owner's id number, although tha command accepts numbers when setting the file's group or owner. (CCS) 10/22/97 (bug fix) "fcopy" did not eval the callback script at the global scope. (SS) 10/22/97 (bug fix) Fixed the signature of the CopyDone callback used in the http package(s) so they can handle error cases properly. (BW) 10/28/97 (bug fixes) Fixed a problem where lappend would free the Tcl object in a variable if a Tcl_ObjSetVar2 failed because of an error calling a trace on the variable. (BL) 10/28/97 (bug fix) Changed binary scan to properly handle sign extension of integers on 64-bit or larger machines. (SS) 11/3/97 (bug fixes) Fixed several bugs: - expressions such as "expr ($x)" must be compiled out-of-line (call the expr command procedure at runtime) to ensure the correct behavior when "$x" is an expression such as "5+10". - "array set a {}" now creates a new array var with an empty array value if the var didn't already exist. - "lreplace $foo end end" no longer returns an error (just an empty list) if foo is empty. - upvar will no longer create a variable in a namespace that refers to a variable in a procedure. - deleting a command trace within a command trace callback would make the code that calls traces to reference freed memory. - significantly sped up "string first" and "string last" (fix from darrel@gemstone.com). - seg fault in Tcl_NewStringObj() when a NULL is passed as the byte pointer argument and Tcl is compiled with -DTCL_MEM_DEBUG. - documentation and error msg fixes. (BL) 11/3/97 (bug fix) Fixed a number of I/O bugs related to word sizes on 64-bit machines. (SS) 11/6/97 (bug fix) The exit code of the first process created by Tcl on Windows was not properly reported due to an initialization problem. (SS) ----------------- Released 8.0p1, 11/7/97 ----------------------- 11/19/97 (bug fix) Fixed bug in linsert where it sometimes accidently cleared out a shared argument list object. (BL). 11/19/97 (bug fix) Autoloading in namespaces was not working properly. auto_mkindex is still not really namespace aware but most common cases should now be handled properly (see init.test). (BW, DL) 11/20/97 (enhancement) Made the changes required by the new Apple Universal Headers V.3.0, so that Tcl will compile with CW Pro 2. 11/24/97 (bug fix) Fixed tests in clock test suite that needed the -gmt flag set. Thanks to Jan Nijtmans for reporting the problem. (RJ) ----------------- Released 8.0p2, 11/25/97 ----------------------- 12/3/97 (bug fix/optimization) Removed uneeded and potentially dangerous instances of double evaluations if "if" and "expr" statements from the library files. It is recommended that unless you need a double evaluation you always use "expr {...}" instead of "expr ..." and "if {...} ..." instead of "if ... ...". It will also be faster thanks to the byte compiler. (DL) ---- Shipped as part of the plugin2.0b5 as 8.0p2Plugin1, Dec 8th 97 ---- 12/8/97 (bug fix) Need to protect the newly accepted channel in an accept callback on a socket, otherwise the callback may close it and cause an error, which would cause the C code to attempt to close the now deleted channel. Bumping the refcount assures that the channel sticks around to be really closed in this case. (JL) 12/8/97 (bug fix) Need to protect the channel in a fileevent so that it is not deleted before the fileevent handler returns. (CS, JL) 12/18/97 (bug fix) In the opt argument parsing package: if the description had only flags, the "too many arguments" case was not detected. The default value was not used for the special "args" ending argument. (DL) 1/15/98 (improvement) Moved common part of initScript in common file. Moved windows specific initialization to init.tcl so you can initialize Tcl in windows without having to call Tcl_Init which is now only searching for init.tcl {back ported from 8.1}. (DL) ---- Shipped as part of the plugin as 8.0p2Plugin2, Jan 15th 98 ---- 5/27/98 (bug fix) Windows socket driver did not notice new data arriving on nonblocking sockets until the event loop was entered. (SS) 5/27/98 (bug fix) Windows socket driver used FIONREAD, which is not supported correctly by WinSock. (SS) 6/9/98 (bug fix) Generic channel code failed to report readable file events on buffered data that was left behind by a gets or read that did not consume all available data. (SS) 6/18/98 (bug fix) Compilation of loop expressions was too aggressive and incorrectly inlined non-literal expressions. (SS) 6/18/98 (bug fix) "info var" and "info locals" incorrectly reported the existence of compiler temporary variables. (SS) 6/18/98 (bug fix) Dictionary sorting used signed character comparisons. (SS) 6/18/98 (bug fix) Compile procs corrupted the exception stack in some cases. (SS) 6/18/98 (bug fix) Array set had erratic behavior when initializing a variable from an empty value list. (SS) 6/18/98 (bug fix) The Windows registry package had a bad bounds check that could lead to a crash. (SS) 6/18/98 (bug fix) The foreach compile proc did not correctly handle non-local variable references. (SS) 6/25/98 (new features) Added name resolution hooks to support [incr Tcl]. There are new internal Tcl_*Resolver* APIs to add, query and remove the hooks. With this changes it should be possible to dynamically load [incr Tcl] as an extension. (MM) 7/1/97 (bug fix) The commands "info args, body, default, procs" did not correctly handle imported procedures. (RJ) 7/6/98 (improvement) pkg_mkIndex now implements the "package require" command. This makes it possible to create index files for packages that require another package and then execute code from that package in their file. Previously, this would throw an error because the required package had not been loaded. The -nopkgrequied flag is provided to revert back to the old functionality. (EMS) 7/6/98 (improvement) back-ported the -direct flag from 8.1 into pkg_mkIndex. This results in pkgIndex.tcl files that contain direct source or load commands instead of tclPkgSetup commands. (EMS) 7/6/98 (improvement) made changes to the AuxData items structures to support storage of compiled scripts on disk. Also some related minor changes in the compilation and execution engine. (EMS) 6/4/98 (enhancement) Added new internal routines to support inserting and deleting from the stat, access, and open-file-channel mechanisms. TclAccessInsertProc, TclStatInsertProc, & TclOpenFileChannelInsertProc insert pointers to such routines; TclAccessDeleteProc, TclStatDeleteProc, & TclOpenFileChannelDeleteProc delete pointers to such routines. See the file generic/tclIOUtils.c for more details. (SKS) 7/1/98 (enhancement) Added a new internal C variable tclPreInitScript. This is a pointer to a string that may hold an initialization script; If this pointer is non-NULL it is evaluated in Tcl_Init() prior to the built-in initialization script defined in the file generic/tclInitScript.h. (SKS) 7/6/98 (bug fix) Removed dead code in PlatformInitExitHandler so that the TCL_LIBRARY value can be safely patched in binaries. (BW) 7/24/98 (enhancement) Incorporated a new version of auto_mkindex that can support the [incr Tcl] class structures. This version will index all procedures in a source file, not just those where "proc" starts at the beginning of the line. If you want the old behavior, use the auto_mkindex_old procedure. (MM) 7/24/98 (feature change) Changed the Windows registry key to be HKEY_LOCAL_MACHINE\Software\Scriptics\Tcl\8.0, and to store the path in the default value instead of "Root". Also, this key can be specified at compile time in case Tcl is being used in a different context where it needs an alternate library path from the standard Tcl installation. (SS) 7/24/98 (feature change) Changed the search order for init.tcl. The tcl_library variable can now be set before calling Tcl_Init to avoid doing any searches. If it isn't set, then Tcl checks env(TCL_LIBRARY), the static value set at compile time, an install directory relative to the executable, a source directory relative to the executable, and a tcl directory relative to the source heirarchy containing the executable. See the comment at the top of generic/tclInitScript.h for more details. (SS) 7/27/98 (config change) Changed the use of the DBGX flag in configure.in and the makefile to be TCL_DBGX. Users of tclConfig.sh may need to pass this through their configure files with AC_SUBST. (BW) 729/98 (bug fix) Changed [info body] to return a copy of the body of a compiled procedure instead of the body itself, to avoid invalidation of the internal rep and loss of the byte-codes. (EMS) 8/5/98 (bug fix) The platform init code could walk off the end of a buffer when reading the PkgPath registry value on Windows. (SS) 8/5/98 (Windows makefile change) Introduced a set of macros to deal with exporting symbols when compiling DLLS on Windows. See win/README for details. (EMS) 8/5/98 (addendum) Added a second Windows registry key under HKEY_LOCAL_MACHINE\Software\Scriptics\Tcl\8.0, named "pkgPath". This is a multi-string value used to initialize the tcl_pkgPath variable. This is required if extension DLLs are in architecture specific subdirectories. (SS) 8/6/98 (new feature) Added tcl_findLibrary to init.tcl for use by extensions, including Tk. This searches in a canonical way for an extensions library directory and initialization file. (BW) 8/10/98 (bug fix) Imported commands used to get lost if the target of the import was redefined. Tcl_CreateCommand and Tcl_CreateObjCommand were updated to restore import links. (Note that if you rename a command, the import links move to the new name, and if you delete a command then the import links get lost. These semantics have not changed.) (MC) -------- Released 8.0.3 to the Tcl Consortium CD-ROM project, 8/10/98 ------ 9/3/98 (bug fix) Tcl_Realloc was failing under Windows because the GlobalReAlloc API was not correctly re-allocating blocks that were 32k+. The fix was to use newer Win32 APIs (HeapAlloc, HeapFree, and HeapReAlloc.) (BS) 10/5/98 (bug fix) Fixed bug in pkg_mkIndex that caused some files that do a "package require" of packages in the Tcl libraries to give a warning like warning: "xx.tcl" provides more than one package ({xx 2.0} {yy 0.3}) and generate a broken pkgIndex.tcl file. (EMS) 10/5/98 (bug fix) Pkg_mkIndex was not doing a case-insensitive comparison of extensions to determine whether to load or source a file. Thus, under Windows, MYDLLNAME.DLL was sourced, and mydllname.dll loaded. (EMS) 10/5/98 (new feature) Created a new Tcl_Obj type, "procbody". This object's internal representation holds a pointer to a Proc structure. Extended TclCreateProc to take both strings and "procbody". (EMS) 10/13/98 (bug fix) The "info complete" command can now handle strings with NULLs embedded. Thanks to colin@field.medicine.adelaide.edu.au for providing this fix. (RJ) 10/13/98 (bug fix) The "lsort -dictionary" command did not properly handle some numbers starting with 0. Thanks to Richard Hipp for submitting the fix to Scriptics. (RJ) 10/13/98 (bug fix) The function Tcl_SetListObj was creating an invalid Tcl_Obj if the list had zero elements (despite what the comments said it would do). Thanks to Sebastian Wangnick for reporting the problem. (RJ) 10/20/98 (new feature) Added tcl_platform(debug) element to the tcl_platform array on Windows platform. The existence of the debug element of the tcl_platform array indicates that the particular Tcl shell has been compiled with debug information. Using "info exists tcl_platform(debug)" a Tcl script can direct the interpreter to load debug versions of DLLs with the load command. (SKS) 10/20/98 (feature change) The Makefile and configure scripts have been changed for IRIX to build n32 binaries instead of the old 32 abi format. If you have extensions built with the o32 abi's you will need to update them to n32 for them to work with Tcl. (RJ) *** POTENTIAL INCOMPATIBILITY *** 10/23/98 (bug fix) tcl_findLibrary had a stray ] in one of the pathnames it searched for the initialization script. tclInitScript.h was incorrectly adding the parent of tcl_library to tcl_pkgPath. This logic was moved into init.tcl, and the initialization of auto_path was documented. Thanks to Donald Porter and Tom Silva for related patches. (BW) 10/29/98 (bug fix) Fixed Tcl_NotifyChannel to use Tcl_Preserve instead of Tcl_RegisterChannel so that 1) unregistered channels do not get closed after their first fileevent, and 2) errors that occur during close in a fileevent script are actually reflected by the close command. (BW) 10/30/98 (bug fix) Overhaul of pkg_mkIndex to deal with transitive package requires and packages split among scripts and binary files. Also fixed ommision of global for errorInfo in tcl_findLibrary. (BW) 11/08/98 (bug fix) Fixed the resource command to always detect the case where a file is opened a second time with the same permissions. IM claims that this will always cause the same FileRef to be returned, but in MacOS 8.1+, this is no longer the case, so we have to test for this explicitly. (JI) 11/10/98 (feature change) When compiling with Metrowerk's MSL, use the exit function from MSL rather than ExitToShell. This allows MSL to clean up its temporary files. Thanks to Vince Darley for this improvement. (JI) ----------------- Released 8.0.4, 11/19/98 ------------------------- 11/20/98 (bug fix) Handle possible NULL return in TclGetStdFiles. (RJ) 11/20/98 (bug fix) The dltests would not build on SGI. They reported that you could not mix n32 with 032 binaries. The configure script has been modified to get the EXTRA_CFLAGS from the tcl configure script. [Bug id: 840] (RJ) 12/3/98 (bug fix) Windows NT creates sockets so they are inheritable by default. Fixed socket code so it turns off this bit right after creation so sockets aren't kept open by exec'ed processes. [Bug: 892] Thanks to Kevin Kenny for this fix. (SS) 1/11/98 (bug fix) On HP, "info sharedlibextension" was returning empty string on static apps. It now always returns ".sl". (RJ) 1/28/99 (configure change) Now support -pipe option on gcc. (RJ) 2/2/99 (bug fix) Fixed initialization problem on Windows where no searching for init.tcl would be performed if the registry keys were missing. (stanton) 2/2/99 (bug fix) Added support for HKEY_PERFORMANCE_DATA and HKEY_DYN_DATA keys in the "registry" command. (stanton) 2/2/99 (bug fix) ENOTSUP and EOPNOTSUPP clashed on some Linux variants. (stanton) 2/2/99 (enhancement) The "open" command has been changed to use the object interfaces. (stanton) 2/2/99 (bug fix) In some cases Tcl would crash due to an overflow of the exception stack resulting from a missing byte code in some expressions. (stanton) 2/2/99 (bug fix) Changed configure so Linux and IRIX shared libraries are linked with the system libraries. (stanton) 2/2/99 (bug fix) Added support for BSDI 4.x (BSD/OS-4*) to the configure script. (stanton) 2/2/99 (bug fix) Fixed bug where upvar could resurrect a namespace variable after the namespace had been deleted. (stanton) 2/2/99 (bug fix) In some cases when creating variables, the interpreter result was being modified even if the TCL_LEAVE_ERR_MSG flag was set. (stanton) 2/2/99 (bug fix & new feature) Changed the socket drivers to properly handle failures during an async socket connection. Added a new fconfigure option "-error" to retrieve the failure message. See the socket.n manual entry for details. (stanton) 2/2/99 (bug fix) Deleting a renamed interp alias could result in a panic. (stanton) 2/2/99 (feature change/bug fix) Changed the behavior of "file extension" so that it splits at the last period. Now the extension of a file like "foo..o" is ".o" instead of "..o" as in previous versions. *** POTENTIAL INCOMPATIBILITY *** ----------------- Released 8.0.5, 3/9/99 ------------------------- ======== Changes for 8.0 go above this line ======== ======== Changes for 8.1 go below this line ======== 6/18/97 (new feature) Tcl now supports international character sets: - All C APIs now accept UTF-8 strings instead of iso8859-1 strings, wherever you see "char *", unless explicitly noted otherwise. - All Tcl strings represented in UTF-8, which is a convenient multi-byte encoding of Unicode. Variable names, procedure names, and all other values in Tcl may include arbitrary Unicode characters. For example, the Tcl command "string length" returns how many Unicode characters are in the argument string. - For Java compatibility, embedded null bytes in C strings are represented as \xC080 in UTF-8 strings, but the null byte at the end of a UTF-8 string remains \0. Thus Tcl strings once again do not contain null bytes, except for termination bytes. - For Java compatibility, "\uXXXX" is used in Tcl to enter a Unicode character. "\u0000" through "\uffff" are acceptable Unicode characters. - "\xXX" is used to enter a small Unicode character (between 0 and 255) in Tcl. - Tcl automatically translates between UTF-8 and the normal encoding for the platform during interactions with the system. - The fconfigure command now supports a -encoding option for specifying the encoding of an open file or socket. Tcl will automatically translate between the specified encoding and UTF-8 during I/O. See the directory library/encoding to find out what encodings are supported (eventually there will be an "encoding" command that makes this information more accessible). - There are several new C APIs that support UTF-8 and various encodings. See Utf.3 for procedures that translate between Unicode and UTF-8 and manipulate UTF-8 strings. See Encoding.3 for procedures that create new encodings and translate between encodings. See ToUpper.3 for procedures that perform case conversions on UTF-8 strings. 9/18/97 (enhancement) Literal objects are now shared by the ByteCode structures created when compiled different scripts. This saves up to 45% of the total memory needed for all literals. (BL) 9/24/97 (bug fixes) Fixed Tcl_ParseCommand parsing of backslash-newline sequences at start of command words. Suppressed Tcl_EvalDirect error logging if non-TCL_OK result wasn't an error. (BL) 10/17/97 (feature enhancement) "~username" now refers to the users' home directory on Windows (previously always returned failure). (CCS) 10/20/97 (implementation change) The Tcl parser has been completely rewritten to make it more modular. It can now be used to parse a script without actually executing it. The APIs for the new parser are not correctly exported, but they will eventually be exported and augmented with Tcl commands so that Tcl scripts can parse other Tcl scripts. (JO) 10/21/97 (API change) Added "flags" argument to Tcl_EvalObj, removed Tcl_GlobalEvalObj procedure. Added new procedures Tcl_Eval2 and Tcl_EvalObjv. (JO) *** POTENTIAL INCOMPATIBILITY *** 10/22/97 (API change) Renamed Tcl_ObjSetVar2 and Tcl_ObjGetVar2 to Tcl_SetObjVar2 and Tcl_GetObjVar2 (for consistency with other C APIs) and changed the name arguments to be strings instead of objects. (JO) *** POTENTIAL INCOMPATIBILITY *** 10/27/97 (enhancement) Bytecode compiler rewritten to use the new Tcl parser. (BL) 11/3/97 (New routines) Added Tcl_AppendObjToObj, which appends the string rep of one Tcl_Obj to another. Added Tcl_GetIndexFromObjStruct, which is similar to Tcl_GetIndexFromObj, except that you can give an offset between strings. This allows Tcl_GetIndexFromObjStruct to be called with a table of records which have strings in them. (SRP) 12/4/97 (enhancement) New Tcl expression parser added. Added new procedure Tcl_ParseExpr and new token types TCL_TOKEN_SUB_EXPR and TCL_TOKEN_OPERATOR. Expression compiler is reimplemented to use this parser. (BL) 12/9/97 (bug fix) Tcl_EvalObj() increments/decrements the refcount of the script object to prevent the object from deleting itself while in the middle of being evaluated. (CCS) 12/9/97 (bug fix) Memory leak in Tcl_GetsObjCmd(). (CCS) 12/11/97 (bug fix) Environment array leaked memory when compiled with Visual C++. (SS) 12/11/97 (bug fix) File events and non-blocking I/O did not work on pipes under Windows. Changed to use threads to achieve non-blocking behavior. (SS) 12/18/97 (bug fixes) Fixed segfault in "namespace import"; importing a procedure that causes a cycle now returns an error. Modified "info procs", "info args", "info body", and "info default" to return information about imported procedures as well as procedures defined in a namespace. (BL) 12/19/97 (enhancement) Added new Tcl_GetString() procedure that can be used in place of Tcl_GetStringFromObj() if the string representation's length isn't needed. (BL) 12/18/97 (bug fix) In the opt argument parsing package: if the description had only flags, the "too many arguments" case was not detected. The default value was not used for the special "args" ending argument. (DL) 1/7/98 (clean up) Moved everything not absolutly necessary out of init.tcl procs now in auto.tcl and package.tcl can be autoloaded if needed. (DL) 1/7/98 (enhancement) tcltest made at install time will search for it's init.tcl where it is, even when using virtual path compilation. (DL) 1/8/98 (os bug workaround) when needed, using a replacement for memcmp so string compare "char with high bit set" "char w/o high bit set" returns the expected value on all platforms. (DL) 1/8/98 (unix portability/configure) building from .../unix/targetName/ subdirectories and simply using "../configure" should now work fine. (DL) 1/14/98 (enhancement) Added new regular expression package that supports AREs, EREs, and BREs. The new package includes new escape characters, meta-syntax, and character classes inside brackets. Regexps involving backslashes may behave differently. (MH) *** POTENTIAL INCOMPATIBILITY *** 1/16/98 (os workaround) Under windows, "file volume" was causing chatter and/or several seconds of hanging when querying empty floppy drives. Changed implementation to call an empirically-derived function that doesn't cause this. (CCS) 1/16/98 (enhancement) Converted regular expressions to a Tcl_Obj type so their compiled form gets cached automatically. Reduced NSUBEXP from 100 to 20. (BW) 1/16/98 (documentation) Change unclear documentation and comments for functions like Tcl_TranslateFileName() and Tcl_ExternalToUtfDString(). Now it explicitly says they take an uninitialized or free DString. A DString that is "empty" or "not holding anything" could have been interpreted as one currently with a zero length, but with a large dynamically allocated buffer. (CCS) ----------------- Released 8.1a1, 1/22/98 ----------------------- 1/28/98 (new feature) Added a "-direct" optional flag to pkg_mkIndex to generate direct loading package indexes (such those you need if you use namespaces and plan on using namespace import just after package require). pkg_mkIndex still has limitations regarding package dependencies but errors are now ignored and with -direct, correct package indexes can be generated even if there are dependencies as long as the "package provide" are done early enough in the files. (DL) 1/28/98 (enhancement) Performance tuning of regexp and regsub. (CCS) 1/28/98 (bug fix) regexp and regsub with "-indices" returned the byte-offsets of the characters in the UTF-8 representation, not the character offsets themselves. (CCS) 1/28/98 (bug fix) "clock format 0 -format %Z -gmt 1" would return the local timezone string instead of "GMT" on Solaris and Windows. 1/28/98 (bug fix) Restore tty settings when closing serial device on Unix. This is good behavior when closing real serial devices, essential when closing the pseudo-device /dev/tty because the user's terminal settings would be left useless, in raw mode, when tcl quit. (CCS) 1/28/98 (bug fix) Tcl_OpenCommandChannel() was modifying the contents of the argv array passed to it, causing problems for any caller that wanted to continue to use the argv array after calling Tcl_OpenCommandChannel(). (CCS) 2/1/98 (bug fix) More bugs with %Z in format string argument to strftime(): 1. Borland always returned empty string. 2. MSVC always returned the timezone string for the current time, not the timezone string for the specified time. 3. With MSVC, "clock format 0 -format %Z -gmt 1" would return "GMT" the first time it was called, but would return the current timezone string on all subsequent calls. (CCS) 2/1/98 (bug fix) "file stat" was broken on Windows. 1. "file stat" of a root directory (local or network) or a relative path that resolved to a root directory (c:. when in pwd was c:/) was returning error. 2. "file stat" on a regular file (S_IFREG), the st_mode was sign extended to a negative int if the platform-dependant type "mode_t" was declared as a short instead of an unsigned short. 3. "file stat" of a network directory, the st_dev was incorrectly reported as the id of the last accessed local drive rather than the id of the network drive. (CCS) 2/1/98 (bug fix) "file attributes" of a relative path that resolved to a root directory was returning error. (CCS) 2/1/98 (bug fix) Change error message when "file attribute" could not determine the attributes for a file. Previously it would return different error messages on Unix vs. Windows vs. Mac. (CCS) 2/4/98 (bug fixes) Fixed several instances of bugs where the parser/compiler would reach outside the range of allocated memory. Improved the array lookup algorithm in set compilation. (DL) 2/5/98 (change) The TCL_PARSE_PART1 flag for Set/Get(Obj)Var2 C APIs is now deprecated and ignored. The part1 is always parsed when the part2 argument is NULL. This is to avoid a pattern of errors for extension writers converting from string based Tcl_SetVar() to new Tcl_SetObjVar2() and who could easily forget to provide the flag and thus get code working for normal variables but not for array elements. The performance hit is minimal. A side effect of that change is that is is no longer possible to create scalar variables that can't be accessed by tcl scripts because of their invalid name (ending with parenthesis). Likewise it is also parsed and checked to ensure that you don't create array elements of array whose name is a valid array element because they would not be accessible from scripts anyway. Note: There is still duplicate array elements parsing code. (DL) *** POTENTIAL INCOMPATIBILITY *** 2/11/98 (bug fix) Sharing objects between interps, such as by "interp eval" or "send" could cause a crash later when dereferencing an interp that had been deleted, given code such as: set a {set x y} interp create foo interp eval foo $a interp delete foo unset a Interp "foo" was gone, but "a" had a internal rep consisting of bytecodes containing a dangling pointer to "foo". Unsetting "a" would attempt to return resources back to "foo", causing a crash as random memory was accessed. The lesson is that that if an object's internal rep depends on an interp (or any other data structure) it must preserve that data in some fashion. (CCS) 2/11/98 (enhancement) The "interp" command was returning inconsistent error messages when the specified slave interp could not be found. (CCS) 2/11/98 (bug fix) Result codes like TCL_BREAK and TCL_CONTINUE were not propagating through the master/slave interp boundaries, such as "interp eval" and "interp alias". TCL_OK, TCL_ERROR, and non-standard codes like teh integer 57 work. There is still a question as to whether TCL_RETURN can/should propagate. (CCS) 2/11/98 (bug fix) TclCompileScript() was derefering memory 1 byte before start of the string to compile, looking for ']'. (CCS,DL) 2/11/98 (bug fix) Tcl_Eval2() was derefering memory 1 byte before start of the string to eval, looking for ']'. (CCS,DL) 2/11/98 (bug fix) Compiling "set a(b" was running off end of string. (CCS,DL) 2/11/98 (bug fix) Windows initialization code was dereferencing uninitialized memory if TCL_LIBRARY environment didn't exist. (CCS) 2/11/98 (bug fix) Windows "registry" command was dereferencing uninitialized memory when constructing the $errorCode for a failed registry call. (CCS) 2/11/98 (enhancement) Eliminate the TCL_USE_TIMEZONE_VAR definition from configure.in, because it was the same information as the already existing HAVE_TM_ZONE definition. The lack of HAVE_TM_ZONE is used to work around a Solaris and Windows bug where "clock format [clock sec] -format %Z -gmt 1" produces the local timezone string instead of "GMT". (CCS) 2/11/98 (bug fix) Memleaks and dereferencing of uninitialized memory in regexp if an error occurred while compiling a regular expression. (CCS). 2/18/98 (new feature) Added mutexes and thread local storage in order to make Tcl thread safe. For testing purposes, there is a testthread command that creates a new thread and an interpreter inside it. See thread.test for examples, but this script-level interface is not fixed. Each thread has its own notifier instance to manage its own events, and threads can post messages to each other's message queue. This uses pthreads on UNIX, and native thread support on other platforms. You enable this by configuring with --enable-threads. Note that at this time *Tk* is still not thread safe. Special thanks to Richard Hipp: his earlier implementation inspired this work. (BW, SS, JI) 2/18/98 (hidden feature change) The way the env() array is shared among interpreters changed. Updates to env used to trigger write traces in other interpreters. This undocumented feature is no longer implemented. Instead, variable tracing is used to keep the C-level environ array in sync with the Tcl-level env array. This required adding TCL_TRACE_ARRAY support to Tcl_TraceVar2 so that array names works properly. (BW) *** POTENTIAL INCOMPATIBILITY *** 2/18/98 (enhancement) Conditional compilation for unix systems (e.g., IRIX, SCO) that use f_bsize instead of st_blksize to determine disk block size. (CCS) 2/23/98 (bug fix) Fixed the emulation of polling selects in the threaded version of the Unix notifier. The bug was showing up on a multiprocessor as starvation of the notifier thread. (BW) ----------------- Released 8.1a2, Feb 23 1998 ----------------------- 9/22/98 (bug fix) Changed the value of TCL_TRACE_ARRAY so it no longer conflicts with the deprecated TCL_PARSE_PART1 flag. This should improve portability of C code. (stanton) 10/6/98 (bug fix) The compile procedure for "if" incorrectly attempted to match against the literal string "if", resulting in a stack overflow when "::if" was compiled. It also would incorrectly accept "if" instead of "elsif" in later clauses. (stanton) 10/15/98 (new feature) Added a "totitle" subcommand to the "string" command to convert strings to capitalize the first character of a string and lowercase all of the other characters. (stanton) 10/15/98 (bug fix) Changed regexp and string commands to properly handle case folding according to the Unicode character tables. (stanton) 10/21/98 (new feature) Added an "encoding" command to facilitate translations of strings between different character encodings. See the encoding.n manual entry for more details. (stanton) 11/3/98 (bug fix) The regular expression character classification syntax now includes Unicode characters in the supported classes. (stanton) 11/6/98 (bug fix) Variable traces were causing crashes when upvar variables went out of scope. [Bug: 796] (stanton) 11/9/98 (bug fix) "format" now correctly handles multibyte characters in %s format strings. (stanton) 11/10/98 (new feature) "regexp" now accepts three new switches ("-line", "-lineanchor", and "-linestop") that control how regular expressions treat line breaks. See the regexp manual entry for more details. (stanton) 11/17/98 (bug fix) "scan" now correctly handles Unicode characters. (stanton) 11/17/98 (new feature) "scan" now supports XPG3 position specifiers and the "%n" conversion character. See the "scan" manual entry for more details. (stanton) 11/17/98 (bug fix) The Tcl memory allocator now returns 8-byte aligned chunks of memory which improves performance on Windows and avoids crashes on other platforms. [Bug: 834] (stanton) 11/23/98 (bug fix) Applied various regular expression performance bug fixes supplied by Henry Spencer. (stanton) 11/30/98 (bug fix) Fixed various thread related race conditions. [Bug: 880 & 607] (stanton) 11/30/98 (bug fix) Fixed a number of memory overflow and leak bugs. [Bug: 584] (stanton) 12/1/98 (new feaure) Added support for Korean encodings. (stanton) 12/1/98 (feature change) Changed the Tcl_EvalObjv interface to remove the string and length arguments. *** POTENTIAL INCOMPATIBILITY with previous alpha releases *** 12/2/98 (bug fix) Fixed various bugs related to line feed translation. [Bug: 887] (stanton) 12/4/98 (new feature) Added a message catalog facility to help with localizing Tcl scripts. Thanks to Mark Harrison for contributing the initial implementation of the "msgcat" package. (stanton) 12/7/98 (bug fix) The memory allocator was failing to update the block list for large memory blocks that were reallocated into a different address. [Bug: 933] (stanton) ----------------- Released 8.1b1, Dec 10 1998 ----------------------- 12/22/98 (performance improvement) Improved the -command option of the lsort command to better use the object system for improved performance (about 5x speed up). Thanks to Syd Polk for suppling the patch. [RFE: 726] (rjohnson) 2/10/99 (bug fix) Restored the Tcl_ObjSetVar2/Tcl_ObjGetVar2 interfaces from 8.0 and renamed the Tcl_GetObjVar2/Tcl_SetObjVar2 interfaces to Tcl_GetVar2Ex and Tcl_SetVar2Ex. This should provide better compatibility with 8.0. (stanton) *** POTENTIAL INCOMPATIBILITY with previous alpha/beta releases *** 2/10/99 (bug fix) Made the eval interfaces compatible with 8.0 by renaming Tcl_EvalObj to Tcl_EvalObjEx, renaming Tcl_Eval2 to Tcl_EvalEx and restoring Tcl_EvalObj and Tcl_GlobalEvalObj interfaces so they match Tcl 8.0. (stanton) *** POTENTIAL INCOMPATIBILITY with previous alpha/beta releases *** 2/25/99 (bug fix/new feature) On Windows, the channel drivers for consoles and serial ports now completely support file events. (redman) 3/5/99 (bug fix) Integrated patches to fix various configure problems that affected HP-UX-11, 64-bit IRIX, Linux, and Solaris. (stanton) 3/9/99 (bug fix) Integrated various AIX related patches to improve support for shared libraries. (stanton) 3/9/99 (new feature) Added tcl_platform(user) to provide a portable way to get the name of the current user. (welch) 3/9/99 (new feature) Integrated the stub library mechanism contributed by Jan Nijtmans, Paul Duffin, and Jean-Claude Wippler. This feature should make it possible to write extensions that support multiple versions of Tcl simultaneously. It also makes it possible to dynamically load extensions into statically linked interpreters. This patch includes the following changes: - Added a Tcl_InitStubs() interface - Added Tcl_PkgProvideEx, Tcl_PkgRequireEx, Tcl_PkgPresentEx, and Tcl_PkgPresent. - Added va_list versions of all VARARGS functions so they can be invoked from wrapper functions. See the manual for more information. (stanton) 3/10/99 (feature change) Replaced Tcl_AlertNotifier with Tcl_ThreadAlert since the Tcl_AlertNotifier function relied on passing internal data structures. (stanton) *** POTENTIAL INCOMPATIBILITY with previous alpha/beta releases *** 3/10/99 (new feature) Added a Tcl_GetVersion API to make it easier to check the Tcl version and patch level from C. (redman) 3/14/99 (feature change) Tried to unify the TclpInitLibrary path routines to look in similar places from Windows to UNIX. The new library search path is: TCL_LIBRARY, TCL_LIBRARY/../tcl8.1, relative to DLL (Windows Only) relative to installed executable, relative to develop executable, and relative to compiled-in in location (UNIX Only.) This fix included: - Defining a TclpFindExecutable - Moving Tcl_FindExecutable to a common area in tclEncoding.c - Modifying the TclpInitLibraryPath routines. (surles) 3/14/99 (feature change) Added hooks for TclPro Wrapper to initialize the location of the encoding files and libraries. This fix included: - Adding the TclSetPerInitScript routine. - Modifying the Tcl_Init routines to evaluate the non-NULL pre-init script. - Adding the Tcl_SetdefaultEncodingDir and Tcl_GetDefaultEncodingDir routines. - Modifying the TclpInitLibrary routines to append the default encoding dir. (surles) 3/14/99 (feature change) Test suite now uses "test" namespace to define the test procedure and other auxiliary procedures as well as global variables. - Global array testConfige is now called ::test::testConfig. - Global variable VERBOSE is now called ::test::verbose, and ::test::verbose no longer works with numerical values. We've switched to a bitwise character string. You can set ::test::verbose by using the -verbose option on the Tcl command line. - Global variable TESTS is now called ::test::matchingTests, and can be set on the Tcl command line via the -match option. - There is now a ::test::skipTests variable (works similarly to ::test::matchTests) that can be set on the Tcl command line via the -match option. - The test suite can now be run in any working directory. When you run "make test", the working directory is nolonger switched to ../tests. (hirschl) *** POTENTIAL INCOMPATIBILITY *** --------------- Released 8.1b2, March 16, 1999 ---------------------- 3/18/99 (bug fix) Fixed missing/incorrect characters in shift-jis table (stanton) 3/18/99 (feature change) The glob command ignores the FS_CASE_IS_PRESERVED bit on file systesm and always returns exactly what it gets from the system. (stanton) *** POTENTIAL INCOMPATIBILITY *** 3/19/99 (new feature) Added support for --enable-64bit. For now, this is only supported on Solaris 7 64bit (SunOS 5.7) using the Sun compiler. (redman) 3/23/99 (bug fix) Fixed fileevents and gets on Windows consoles and serial devices so that non-blocking channels do not block on partial input lines. (redman) 3/23/99 (bug fix) Added a new Tcl_ServiceModeHook interface. This is used on Windows to avoid the various problems that people have been seeing where the system hangs when tclsh is running outside of the event loop. As part of this, renamed TcapAlertNotifier back to Tcl_AlertNotifier since it is public. (stanton) 3/23/99 (feature change) Test suite now uses "tcltest" namespace to define the test procedure and other auxiliary procedures as well as global variables. The previously chosen "test" namespace was thought to be too generic and likely to create conflits. (hirschl) *** POTENTIAL INCOMPATIBILITY *** 3/24/99 (bug fix) Make sockets thread safe on Windows. (redman) 3/24/99 (bug fix) Fix cases where expr would incorrect return a floating point value instead of an integer. (stanton) 3/25/99 (bug fix) Added ASCII to big5 and gb2312 encodings. (stanton) 3/25/99 (feature change) Changed so aliases are invoked at current scope in the target interpreter instead of at the global scope. This was an incompatibility introduced in 8.1 that is being removed. (stanton) *** POTENTIAL INCOMPATIBILITY with previous beta releases *** 3/26/99 (feature change) --enable-shared is now the default and build Tcl as a shared library; specify --disable-shared to build a static Tcl library and shell. *** POTENTIAL INCOMPATIBILITY *** 3/29/99 (bug fix) Removed the stub functions and changed the stub macros to just use the name without params. Pass &tclStubs into the interp (don't use tclStubsPtr because of collisions with the stubs on Solaris). (redman) 3/30/99 (bug fix) Loadable modules are now unloaded at the last possible moment during Tcl_Finalize to fix various exit-time crashes. (welch) 3/30/99 (bug fix) Tcl no longer calls setlocale(). It looks at env(LANG) and env(LC_TYPE) instead. (stanton) 4/1/99 (bug fix) Fixed the Ultrix multiple symbol definition problem. Now, even Tcl includes a copy of the Tcl stub library. (redman) 4/1/99 (bug fix) Internationalized the registry package. 4/1/99 (bug fix) Changed the implemenation of Tcl_ConditionWait and Tcl_ConditionNotify on Windows. The new algorithm eliminates a race condition and was suggested by Jim Davidson. (welch) 4/2/99 (new apis) Made various Unicode utility functions public. Tcl_UtfToUniCharDString, Tcl_UniCharToUtfDString, Tcl_UniCharLen, Tcl_UniCharNcmp, Tcl_UniCharIsAlnum, Tcl_UniCharIsAlpha, Tcl_UniCharIsDigit, Tcl_UniCharIsLower, Tcl_UniCharIsSpace, Tcl_UniCharIsUpper, Tcl_UniCharIsWordChar, Tcl_WinUtfToTChar, Tcl_WinTCharToUtf (stanton) 4/2/99 (feature change) Add new DDE package and removed the Tk send command from the Windows version. Changed DDE-based send code into "dde eval" command. The DDE package can be loaded into tclsh, not just wish. Windows only. (redman) 4/5/99 (bug fix) Changed safe-tcl so that the encoding command is an alias that masks out the "encoding system" subcommand. (redman) 4/5/99 (bug fix) Configure patches to improve support for OS/390 and BSD/OS 4.*. (stanton) 4/5/99 (bug fix) Fixed crash in the clock command that occurred with negative time values in timezones east of GMT. (stanton) 4/6/99 (bug fix) Moved the "array set" C level code into a common routine (TclArraySet). The TclSetupEnv routine now uses this API to create an env array w/ no elements. This fixes the bug caused when every environ varaible is removed, and the Tcl env variable is synched. If no environ vars existed, the Tcl env var would never be created. (surles) 4/6/99 (bug fix) Made the Env module I18N compliant. (surles) 4/6/99 (bug fix) Changed the FindVariable routine to TclpFindVariable, that now does a case insensitive string comparison on Windows, and not on UNIX. (surles) --------------- Released 8.1b3, April 6, 1999 ---------------------- 4/9/99 (bug fix) Fixed notifier deadlock situation when the pipe used to talk back notifier thread is filled with data. Found as a result of the focus.test for Tk hanging. (redman) 4/13/99 (bug fix) Fixed bug where socket -async combined with fileevent for writing did not work under Windows NT. (redman) 4/13/99 (encoding fix) Restored the double byte definition of GB2312 and added the EUC-CN encoding. EUC-CN is a variant of GB2312 that shifts the characters into bytes with the high bit set and includes ASCII as a subset. (stanton) 4/27/99 (bug fix) Added 'extern "C" {}' block around the stub table pointer declaration so the stub library can be used from C++. (stanton) --------------- Released 8.1 final, April 29, 1999 ---------------------- 4/22/99 (bug fix) Changed Windows NT socket implementation to avoid creating a communication window. This avoids the problem where the system hangs waiting for tclsh to respond to a system-wide synchronous broadcast (e.g. if you change system colors). (redman) 4/22/99 (bug fix) Added call to TclWinInit from TclpInitPlatform when building a static library since DllMain will not be invoked. This could break old code that explicitly called TclWinInit, but should be simpler in the long run. (stanton) *** POTENTIAL INCOMPATIBILITY *** 4/23/99 (bug fix) Added support for the koi8-r Cyrillic encoding. [Bug: 1771] (stanton) 4/28/99 (bug fix) Changed internal Tcl_Obj usage to avoid freeing the internal representation after the string representation has been freed. This makes it easier to debug extensions. (stanton) 4/30/99 (bug fix) Fixed a memory leak in CommandComplete. (stanton) 5/3/99 (bug fix) Fixed a bug where the Tcl_ObjType was not being set in a duplicated Tcl_Obj. [Bug: 1975, 2047] (stanton) 5/3/99 (bug fix) Changed Tcl_ParseCommand to avoid modifying eval'ed strings that are already null terminated. [Bug: 1793] (stanton) 5/3/99 (new feature) Applied Jeff Hobbs's string patch which includes the following changes: - added new subcommands: equal, repeat, map, is, replace - added -length option to "string compare|equal" - added -nocase option to "string compare|equal|match" - string and list indices can be an integer or end?-integer?. - added optional first and last index args to string toupper, et al. See the string.n manual entry for more details about the new string features. [Bug: 1845] (stanton) 5/6/99 (new feature) Added Tcl_UtfNcmp and Tcl_UtfNcasecmp to make Utf string comparision easier. (stanton) 5/7/99 (bug fix) Improved OS/390 support. [Bug: 1976, 1997] (stanton) 5/12/99 (bug fix) Changed Windows initialization code to avoid using GetUserName system call in favor of the env(USERNAME) variable. This provides a significant startup speed improvement. (stanton) 5/12/99 (bug fix) Replaced the per-interpreter regexp cache with a per-thread cache. Changed the Regexp object to take advantage of this extra cache. Added a reference count to the TclRegexp type so regexps can be shared by multiple objects. Removed the per-interp regexp cache from the interpreter. Now regexps can be used with no need for an interpreter. This set of changes should provide significant speed improvements for many Tcl scripts. [Bug: 1063] (stanton) 5/14/99 (bug fix) Durining initialization on Unix, Tcl now extracts the encoding subfield from the LANG/LC_ALL environment variables in cases where the locale is not found in the built-in locale table. It also attempts to initialize the locale subsystem so X11 is happy. [Bug: 1989] (stanton) 5/14/99 (bug fix) Applied the patch to fix 100-year and 400-year boundaries in leap year code, from Isaac Hollander. [Bug: 2066] (redman) 5/14/99 (bug fix) Fixed a crash caused by a failure to reset the result before evaluating the test expression in an uncompiled for statement. (stanton) 5/18/99 (bug fix) Modified initialization code on Windows to avoid inherenting closed or invalid channels. If the standard input is anything other than a console, file, serial port, or pipe, then we fall back to the standard Tk window console. (stanton) 5/19/99 (bug fix) Added an extern "C" block around the entire tcl.h header file to avoid C++ linkage issues. (redman) 5/19/99 (new feature) Applied Jeff Hobb's patch to add Tcl_StringCaseMatch to support case insensitive glob style matching and Tcl_UniCharIs* character classification functions. (stanton) 5/20/99 (bug fix) Added the directory containing the executuble and the ../lib directory relative to that to the auto_path variable. (redman) --------------- Released 8.1.1, May 25, 1999 ---------------------- 5/21/99 (bug fix) Fixed launching command.com on Win95/98, no longer hangs. [Bug: 2105] (redman) 5/28/99 (bug fix) Fixed bug where dde calls were being passed an invalid dde handle. [Bug: 2124] (stanton) 6/1/99 (bug fix) Small configure.in patches. [Bug: 2121] (stanton) 6/1/99 (bug fix) Applied latest regular expression patches to fix an infinite loop bug and add support for testing whether a string could match with additional input. [Bug: 2117] (stanton) 6/2/99 (bug fix) Fixed incorrect computation of relative ordering in Utf case-insensitive comparison. [Bug: 2135] (stanton) 6/3/99 (bug fix) Fxied bug where string equal/compare -nocase reported wrong result on null strings. [Bug: 2138] (stanton) 6/4/99 (new feature) Windows build now uses Cygwin tools plus GNU make and autoconf to build static/dynamic and debug/nodebug. (stanton) 6/7/99 (new feature) Optimized string index, length, range, and append commands. Added a new Unicode object type. (hershey) 6/8/99 (bug fix) Rolled back Windows socket driver to 8.1.0 version. (stanton) 6/9/99 (new feature) Added Tcl_RegExpMatchObj and Tcl_RegExpGetInfo to public Tcl API, these functions are needed by Expect. Changed tools/genStubs.tcl to always write output in LF mode. (stanton) 6/14/99 (new feature) Merged string and Unicode object types. Added new public Tcl API functions: Tcl_NewUnicodeObj, Tcl_SetUnicodeObj, Tcl_GetUnicode, Tcl_GetUniChar, Tcl_GetCharLength, Tcl_GetRange, Tcl_AppendUnicodeToObj. (hershey) 6/16/99 (new feature) Changed to conform to TEA specification, added tcl.m4 and aclocal.m4 macro libraries for configure. (wart) 6/17/99 (new feature) Added new regexp interfaces: -expanded, -line, -linestop, and -lineanchor switches. Renamed Tcl_RegExpMatchObj to Tcl_RegExpExecObj and added new Tcl_RegExpMatchObj that is equivalent to Tcl_RegExpMatch. Added public macros for regexp flags. Added REG_BOSONLY flag to allow Expect to iterate through a string and only find matches that start at the current position within the string. (stanton) 6/21/99 (bug fix) Fixed memory leak in TclpThreadCreate where thread attributes were not being released. [Bug: 2254] (stanton) 6/23/99 (new feature) Updated Unicode character tables to reflect Unicode 2.1 data. (stanton) 6/25/99 (new feature) Fixed bugs in non-greedy quantifiers for regular expression code. (stanton) 6/25/99 (new feature) Added initial implementation of new Tcl test harness package. Modified test files to use new tcltest package. (jenn) 6/26/99 (new feature) Applied patch from Peter Hardie to add poke command to dde and changed the dde package version number to 1.1. (redman) 6/28/99 (bug fix) Applied patch from Peter Hardie to fix problem in Tcl_GetIndexFromObj() when the key being passed is the empty string. [Bug: 1738] (redman) 6/29/99 (new feature) Added options to tcltest package: -preservecore, -limitconstraints, -help, -file, -notfile, and flags. (jenn) 7/3/99 (new feature) Changed parsing of variable names to allow empty array names. Now "$(foo)" is a variable reference. Previously you had to use something line $::(foo), which is slower. This change was requested by Jean-Luc Fontaine for his STOOOP package. (welch) 7/3/99 (new feature) Added Tcl_SetNotifier (public API) and associated hook points in the notifiers to be able to replace the notifier calls at runtime. The Xt notifier and test program use this hook. (welch) 7/3/99 (new feature) Added a new variant of the "Trf core patch" from Andreas Kupries that adds new C APIs Tcl_StackChannel, Tcl_UnstackChannel, and Tcl_GetStackedChannel. This allows the Trf extension to work without applying patches to the Tcl core. (welch) 7/6/99 (new feature) Added -timeout option to http.tcl to handle timeouts that occur during connection attempts to hosts that are down. (welch) 7/6/99 (bug fix) Applied new implementation of the Windows serial port driver from Rolf Schroedter that fixes reading only one byte from the port at a time. Uses polling every 10ms to implement fileevents. [Bug: 1980 2217] (redman) 7/8/99 (bug fix) Applied fix for bug in DFA state caching under lookahead conditions (regular expressions). [Bug: 2318] (stanton) 7/8/99 (bug fix) Fixed bug in string range bounds checking code. (stanton) --------------- Released 8.2b1, July 14, 1999 ---------------------- 7/16/99 (bug fix) Added Tcl_SetNotifier to stub table. [Bug: 2364] Added check for Alpha/Linux to correct the IEEE floating point flag, patch from Don Porter. (redman) 7/20/99 (bug fix) Merged 8.0.5 code to handle tcl_library properly, also fixed a bug that caused TCL_LIBRARY to be ignored. (hershey) 7/21/99 (bug fix) Implemented modified socket driver for Windows that uses a thread to manage the socket event window. Code works the same on all supported versions of Windows and was based on original 8.1.0 code. [Bug: 2178 2256 2259 2329 2323 2355] (redman) 7/21/99 (new feature) Applied patch from Rolf Schroedter to add -pollinterval option to fconfigure for Windows serial ports. Allows the maxblocktime to be modified to control how often serial ports are checked for fileevents. Also added documentation for \\.\comX notation for opening serial ports on Windows. (redman) 7/21/99 (bug fix) Changed APIs in stub tables to use "unsigned long" instead of the platform-specific "size_t", primarily after SunOS 4 users could no longer compile. (redman) 7/22/99 (bug fix) Fixed crashing during "array set a(b) {}". [Bug: 2427] (redman) 7/22/99 (bug fix) The install-sh script must be given execute permissions prior to running. [Bug: 2413] (redman) 7/22/99 (bug fix) Applied patch from Ulrich Ring to remove ANSI-style prototypes in the code. [Bug: 2391] (redman) 7/22/99 (bug fix) Added #if blocks around #includes of sys/*.h header files, to allow an extension author on Windows to use the MetroWerks compiler. [Bug: 2385] (redman) 7/22/99 (bug fix) Fixed running the safe.test test suite, one change to the Windows Makefile.in to fix paths and another in safe.test to check for the tcl_platform(threaded) variable properly. (redman) 7/22/99 (bug fix) Fixed hanging in new Win32 socket driver with threads enabled. (redman) 7/26/99 (bug fix) Fixed terminating of helper threads by holding any mutexes from the primary thread while waiting for the helper thread to terminate. Fixes dual-CPU WinNT hangs, only one rare sporadic hang that still exists with dual-CPU WinNT. Also fixed test cases so that they would not depend as much on timing for dual-CPU WinNT. (redman) 7/27/99 (bug fix) Some test suite cleanup. (jenn) 7/29/99 (bug fix) Applied patch to fix typo in .SH NAME line in doc/Encoding.n [Bug: 2451]. Applied patch to avoid linking pack.n to pack-old.n [Bug: 2469]. Patches from Don Porter. (redman) 7/29/99 (bug fix) Allow tcl to open CON and NUL, even for redirection of std channels. [Bug: 2393 2392 2209 2458] (redman) 7/30/99 (bug fix) Applied fixed Trf patch from Andreas Kupries. [Bug: 2386] (hobbs) 7/30/99 (bug fix) Fixed bug in info complete. [Bug: 2383 2466] (hobbs) 7/30/99 (bug fix) Applied patch to fix threading on Irix 6.5, patch provided by James Dennett. [Bug: 2450] (redman) 7/30/99 (bug fix) Fixed launching of 16bit applications on Win9x from wish. The command line was being primed with tclpip82.dll, but it was ignored later. 7/30/99 (bug fix) Added functions to stub table, patch provided by Jan Nijtmans. [Bug: 2445] (hobbs) 8/1/99 (bug fix) Changed Windows socket driver to terminate threads by sending a message to the window rather than calling TerminateThread(), which seems to leak about 4k from the helper thread's stack space. (redman) --------------- Released 8.2b2, August 5, 1999 ---------------------- 8/4/99 (bug fix) Applied patches supplied by Henry Spencer to greatly enhance performance of certain classes of regular expressions. [Bug: 2440 2447] (stanton) 8/5/99 (doc change) Made it clear that tcl_pkgPath was not set for Windows. [Bug: 2455] (hobbs) 8/5/99 (bug fix) Fixed reference to bytes that might not be null terminated in tclLiteral.c. [Bug: 2496] (hobbs) 8/5/99 (bug fix) Fixed typo in http.tcl. [Bug: 2502] (hobbs) 8/9/99 (bug fix) Fixed test suite to handle larger integers (64bit). Patch from Don Porter. (hobbs) 8/9/99 (documentation fix) Clarified Tcl_DecrRefCount docs [Bug: 1952]. Clarified array pattern docs [Bug: 1330]. Fixed clock docs [Bug: 693]. Fixed formatting errors [Bug: 2188 2189]. Fixed doc error in tclvars.n [Bug: 2042]. (hobbs) 8/9/99 (bug fix) Fixed path handling in auto_execok [Bug: 1276] (hobbs) 8/9/99 (internal api change) Removed the TclpMutexLock and TclpMutexUnlock APIs and added a new exported api, Tcl_GetAllocMutex. These APIs are all for the mutex used in the simple memory allocators. By making this change we are able to substitute different implementations of the thread-related APIs without having to recompile the Tcl core. (welch) 8/9/99 (new C API) Tcl_GetChannelNames returns a list of open channel names in the interpreter result. Still no Tcl-level version of this, but server-like applications can use this to clean up files without deleting interpreters. (welch) 8/9/99 (bug fix) Traces were not firing on "info exists", which used to happen in Tcl 7.6 and earlier. An "info exists" now fires a read trace, if defined. This makes it possible to fully implement variables that are defined via traces. (welch) 8/10/99 (bug fix) Fixed Brent's changes so that they work on Windows. (redman) --------------- Released 8.2b3, August 11, 1999 ---------------------- 8/12/99 (Mac) Rearrange projects in tclMacProjects.sea.hqx so that the build directory is separate from the sources. (Jim Ingham) 8/12/99 (bug fix) Fixed bug in Tcl_EvalEx where the termOffset was not being updated in cases where the evaluation returned a non TCL_OK error code. [Bug: 2535] (stanton) --------------- Released 8.2.0, August 17, 1999 ---------------------- 9/21/99 (config fixes) fixed several AIX configuration issues. gcc and threading may still cause problems on AIX. (hobbs) 9/21/99 (bug fix) fixed expr double-eval problem. [Bug: 732] (hobbs) 9/21/99 (bug fix) fixed static buffer overflow problem. [Bug: 2483] (hobbs) 9/21/99 (bug fix) fixed end-int linsert interpretation. [Bug: 2693] (hobbs) 9/21/99 (bug fix) fixed bug when setting array in non-existent namespace. [Bug: 2613] (hobbs) --- Released 8.2.1, October 04, 1999 --- See ChangeLog for details --- 10/30/99 (feature enhancement) new regexp engine from Henry Spencer was patched in - should greatly reduce stack space usage. (spencer) 10/30/99 (bug fix) fixed Purify reported memory leaks in findexecutable test command, TclpCreateProcess on Unix, in handling of C environ array, and in testthread code. No more known (reported) mem leaks for Tcl built using gcc on Solaris 2.5.1. Also none reported for Tcl on NT (using Purify 6.0). (hobbs) 10/30/99 (bug fix) fixed improper bytecode handling of 'eval {set array($unknownvar) 5}' (also for incr) (hobbs) 10/30/99 (bug fix) fixed event/io threading problems by making triggerPipe non-blocking (nick kisserbeth) 10/30/99 (bug fix) fixed Tcl_AppendStringsToObjVA and Tcl_AppendResultVA to only iterates once over the va_list (avoiding non-portable memcpy). (joe english, hobbs) 10/30/99 (bug fix) removed savedChar trick in tclCompile.c that appeared to be causing a segv when the literal table was released. [Bug: 2459, 2515] (David Whitehouse) 10/30/99 (bug fix) fixed [string index] to return ByteArrayObj when indexing into one (test case string-5.16) [Bug: 2871] (hobbs) 10/30/99 (bug fix) fixes for mac UTF filename handling (ingham) --- Released 8.2.2, November 04, 1999 --- See ChangeLog for details --- 11/19/99 (feature enhancement) bug fixes for http package as well as patch required by TLS (SSL) extension that adds http::(un)register and -type to http::geturl. Up'd http pkg version to 2.2. 11/19/99 (bug fix) removed extra decr of numLevels in Tcl_EvalObjEx that could cause seg fault (mjansen@wendt.de) 11/19/99 (bug fixes) numerous minor big fixes, including correcting the installation of the koi8-r encoding and tcltest1.0 on Windows. 11/30/99 (bug fix) fixes scan where %[..] didn't match anything 11/30/99 (bug fix) fixed setting of isNonBlocking flag in PipeBlockModeProc so you can now close a non-blocking channel without waiting. 11/30/99 (bug work-around) prevented the unloading of DLLs for Unix in TclFinalizeLoad. This stops the seg fault on exit that some users would see (ie with oratcl) when using DLLs that do nasty things like register atexit handlers. 12/07/99 (bug fix) fixes for 'expr + {[incr]}' and 'expr + {[error]}' cases (different causes). --- Released 8.2.3, December 16, 1999 --- See ChangeLog for details --- 1999-09-14 (feature enhancement) added -start switch to regexp and regsub. 1999-09-15 (feature enhancement) add 'array unset' command. 1999-09-15 (feature enhancement) rewrote runtime libraries to use new string functions 1999-08-18 (feature enhancement) added 'file channels' command, along with Tcl_GetChannelNames(Ex) public C APIs. 1999-10-19 (feature enhancement) enhanced tcltest package 1999-09-16 (feature enhancement) added -milliseconds switch to 'clock clicks' 1999-10-28 (feature enhancement) added support for inline 'scan' 1999-10-28 (feature enhancement) added support for touch functionality by extendeding 'file atime' and 'file mtime' to take an optional time argument 1999-11-24 (feature enhancement) added 'fconfigure $sock -lasterror' command to Windows to query the last error received on a serial socket. 1999-11-30 (bug fix) fixed handling of %Z on NT for timezones that don't have DST 1999-12-03 (feature enhancement) improved error message in bad octal cases and improper use of comments. (hobbs) 1999-12-07 (bug fix) fixed Tcl_ScanCountedElement to not step beyond the end of the counted string 1999-12-09 (feature enhancement) removed all references to 16 bit compatibility code for Windows (hobbs) 1999-12-10 (bug fix) removed check for vfork - Tcl now uses only fork in exec. (hobbs) 1999-12-10 (optimization) changed Tcl_ConcatObj to return a list object when it receives all pure list objects as input (used by 'concat'), added optimizations in Tcl_EvalObjEx for pure list case, and optimized INST_TRY_CVT_TO_NUMERIC in TclExecuteByteCode for boolean objects. (oakley, hobbs) 1999-12-12 (feature enhancement) enhanced glob command with -type, -path, -directory and -join switches. (darley, hobbs) 1999-12-21 (bug fix) changed CreateThread to _beginthreadex and ExitThread to _endthreadex to prevent 4K mem leak (gravereaux) 1999-12-21 (bug fix) fixed applescript for I18N 1999-12-21 (feature enhancement) added -unique option to lsort (hobbs) 1999-12-21 (bug fix) changed thread ids to longs (for 64bit systems) --- Released 8.3b1, December 22, 1999 --- See ChangeLog for details --- 2000-01-10 (feature enhancement) clock scan now supports the common ISO 8601 date/time formats. See docs for details. (melski) 2000-01-10 (bug fix) prevented \ooo substitution from accepting non-octal digits [Bug: 3975] (hobbs) 2000-01-11 (bug fix) fixed improper handling of DST by clock when using relative times (like "1 month" or "tomorrow"). (melski) 2000-01-12 (bug fix) improved build support for Tru64 v5, NetBSD and Reliant Unix (hobbs) 2000-01-12 (bug fix) made imported commands also import their compile procedure (duffin) 2000-01-12 (bug fix) fixed 'info procs ::namesp::*' behavior to return procs in a namespace (dejong) 2000-01-12 (feature enhancement) added support for setting permissions symbolicly (like chmod) in [file attributes $file -permissions ...] (schoebel) 2000-01-13 (bug fix) fixed lsort -dictionary problem when sorting characters between 'Z' and 'a' (flawed upper/lower comparison logic) (melski) --- Released 8.3b2, January 13, 2000 --- See ChangeLog for details --- 2000-01-14 (feature enhancement) clock format %Q added, clock scan updated 2000-01-20 (bug fix) corrected complex array elem compiling (Spjuth) 2000-01-20 (bug fix) made [info body] always return a string type arg, to prevent possible misuse of bytecodes in the wrong context (hobbs) 2000-01-20 (bug fixes) several fixes to variable handling to prevent possible crashes, and further definition of correct behavior (melski) 2000-01-25 (bug fixes) improved QNX, Ultrix and OSF1 (Tru64) config and compatibility (edge, furukawa) 2000-01-25 (bug fix) fixed mem leak when calling lsort with a bad -command argument (hobbs) 2000-01-27 (feature enhancement) package mechanism overhaul: changed behavior of pkg_mkIndex to do -direct by default, added -lazy option. Fixed pkg_mkIndex to handle odd proc names and auto_mkIndex to use platform independent file paths. Other fixes for odd package quirks. Added ::pkg namespace and ::pkg::create helper function. (melski) 2000-02-01 (bug fix) fixed problem where http POST would send one extra newline (vasiljevic) 2000-02-02 (feature enhancement) added docs for new regexp -inline and -all switches. (hobbs) 2000-02-08 (bug fix) corrected handling of "next monthname" in clock scan (melski) 2000-02-09 (bug fix) restored Mac source to build readiness and prevented mac panic from an error when closing an async socket (steffen, ingham) 2000-02-10 (feature enhancement) improved error reporting for failed loads on Windows (dejong, hobbs) --- Released 8.3.0, February 10, 2000 --- See ChangeLog for details --- 2000-03 (bug fixes, feature enhancement) overhaul of http package for proper handling of async callbacks (new options), version is now at 2.3 (tamhankar, welch) 2000-03 (performance enhancement) speedup in Windows filename handling (newman) and ==/!= empty string in exprs. (hobbs) 2000-03-27 (bug fix) added uniq'ing test to namespace export list to prevent unnecessary mem growth (hobbs) 2000-03-29 (bug fix) fixed mem leak when repeatedly sourcing the same bytecompiled (tbc) code repeatedly across different interpreters (hobbs) 2000-03-29 (config enhancement) improved build support for gcc/mingw on Windows (nijtmans, hobbs) and added RPM target (melski) 2000-03-31 (bug fix) corrected data encoding problem when using "exec << $data" construct (melski) 2000-04 (feature enhancement) overhaul of threading mechanism to better support tcl level thread command (new APIs Tcl_ConditionFinalize, Tcl_MutexFinalize, Tcl_CreateThread, etc, all docs in Thread.3). (kupries, graveraux) This enables the tcl level thread extension. (welch) 2000-04-10 (bug fix) fixed infinite loop case in regexp -all (melski) 2000-04-13 (config enhancement) added support for --enable-64bit-vis Sparc target. (hobbs) 2000-04-18 (bug fix) moved tclLibraryPath to thread-local storage to fix possible race condition on MP machines (hobbs) 2000-04-18 (config enhancement) added MacOS X build target and tclLoadDyld.c dl type. (sanchez) 2000-04-23 (bug fix) several Mac socket fixes (ingham) 2000-04-24 (bug fix) fixed hang in threaded Unix case when backgrounded exec process was running (dejong) --- Released 8.3.1, April 26, 2000 --- See ChangeLog for details --- 2000-04-26 (doc fix) updated/added documentation for many API's and commands (melski) 2000-05-02 (feature enhancement) added support for joinable threads; extended API's for channels to allow channels to move between threads (kupries) 2000-05-02 (feature enhancement) changed error return for procedures with incorrect args to be like the Tcl_WrongNumArgs API, with a "wrong # args: ..." message printed, with an args list (hobbs) 2000-05-08 (feature enhancement) added [array statistics] command 2000-05-08 (performance enhancement) rewrote Tcl_StringCaseMatch algorithm for better performance; this affects the [string match] command; added "eq" and "ne" operands to expr, for testing string equality and inequality (hobbs) 2000-05-09 (feature enhancement) extended [lsearch] to support sorted list searches and typed list searches (melski) 2000-05-10 (feature enhancement) added [namespace exists] command (darley) 2000-05-18 (build enhancement) added support for mingw compile env and cross-compiling (dejong) 2000-05-18 (bug fix) corrected clock grammar to properly handle the "ago" keyword when it follows multiple relative unit specifiers (melski) 2000-05-22 (compile fix) type cast cleanups (dejong) 2000-05-23 (performance enhancement) added byte-compiled implementation of [return] command and [string] command (melski) 2000-05-26 (performance enhancement) extended byte-compiled [string] command with support for [string compare/index/match] (hobbs) 2000-05-27 (feature enhancement) added ability to set [info script] return value ([info script ?newFileName?]) (welch) 2000-05-31 (feature enhancement) added support for regexp and exact pattern matching for [array names] (gazetta) 2000-05-31 (feature enhancement) added -nocomplain and -- flags to [unset] to allow for silent unset operation (hobbs) --- Released 8.4a1, June 6, 2000 --- See ChangeLog for details --- 2000-05-29 (bug fix) corrected resource cleanup in http error cases. Improved handling of error cases in http. (tamhankar) 2000-07 (feature rewrite) complete rewrite of the Tcl IO channel subsystem to correct problems (hangs, core dumps) with the initial stacked channel implementation. The new system has many more tests for robustness and scalability. There are new C APIs (see Tcl_CreateChannel), but only stacked channel drivers are affected (ie: TLS, Trf, iogt). The iogt extension has been added to the core test code to test the system. (hobbs, kupries) **** POTENTIAL INCOMPATABILITY **** 2000-07 (build improvements) cleanup of the makefiles and configure scripts to correct support for building under gcc for Windows. (dejong) 2000-08-07 (bug fix) corrected sizeof error in Tcl_GetIndexFromObjStruct. (perkins) 2000-08-07 (bug fix) correct off-by-one error in HistIndex, which was causing [history redo] to start its search at the wrong event index. (melski) 2000-08-07 (bug fix) corrected setlocale calls for XIM support and locale issues in startup. (takahashi) 2000-08-07 (bug fix) correct code to handle locale specific return values from strftime, if any. (wagner) 2000-08-07 (bug fix) tweaked grammar to properly handle the "ago" keyword when it follows multiple relative unit specifiers, as in "2 days 2 hours ago". (melski) 2000-08-07 (doc fixes) numerous doc fixes to correct SEE ALSO and NAME sections. (english) 2000-08-07 (bug fix) new man pages memory.n, TCL_MEM_DEBUG.3, Init.3 and DumpActiveMemory.3. (melski) --- Released 8.3.2, August 9, 2000 --- See ChangeLog for details --- 2000-06 thru 2000-11 (build improvements) Added support for mingw (gcc on Windows), AIX-5 and Win64 builds (dejong, hobbs) 2000-06-23 (feature enhancement) ability to use Tcl_Obj *s as hash keys (duffin) 2000-06-29 (new features) added [mcmax] and [mcmset] and extended [unknown] in msgcat package (duperval, krone, nelson) => msgcat 1.1 2000-08 thru 2000-09 added tclPlatDecls.h to default install (melski, hobbs) 2000-08-24 (new feature) Enhanced trace syntax to add: trace {add|remove|list} {variable|command} name ops command (darley, melski) 2000-09-06 (cross-platform feature) Set ^Z (\32) as default EOF char. (hobbs) 2000-09-07 partial fix for bug 2460 to prevent exec mem leak on Windows for the common case (gravereaux) 2000-09-14 Improved string allocation growth for large strings (hintermayer, melski) 2000-09-14 New non-panic'ing mem allocation functions Tcl_AttemptAlloc, Tcl_AttemptRealloc, Tcl_AttemptSetObjLength (melski) 2000-09-20 (new features) completely new, enhanced syntax in tcltest package. Backwards compatable with tcltest v1. (hom) => tcltest 2.0 2000-09-27 (bug fix) fixed a bug introduced by a partial fix in 8.3.2 that didn't set nonBlocking correctly when resetting the flags for the write side (mem leak) Correct mem leak in channels when statePtr was released (hobbs) 2000-09-29 (bug fix) corrected reporting of space parity on Windows (Eason) 2000-10-06 (bug fix) corrected [file channels] to only return channels in the current interpreter (hobbs) 2000-10-20 (performance enhancement) call stat only when necessary in 'glob' to speed up command significantly in base cases (hobbs) 2000-10-27 Fixed mem leak in Tcl_CreateChannel. Re-purified core via test suites. (hobbs) 2000-10-30 (new feature) add "ja_JP.eucJP" map to "euc-jp" encoding (takahashi) 2000-11-01 (mem leak) Corrected excessive mem use of info exists on a non-existent array element (hobbs) 2000-11-02 (bug fix) Corrected sharing of tclLibraryPath in threaded environment (gravereaux) 2000-11-03 (new feature) Tcl_SetMainLoop enables defining an event loop for tclsh. This enables Tk as a truly loadable package. (hobbs) --- Released 8.4a2, November 3, 2000 --- See ChangeLog for details --- 2000-09-27 (bug fix) fixed a bug introduced by a partial fix in 8.3.2 that didn't set nonBlocking correctly when resetting the flags for the write side (mem leak) Correct mem leak in channels when statePtr was released (hobbs) 2000-09-29 (bug fix) corrected reporting of space parity on Windows (Eason) 2000-10-06 (bug fix) corrected [file channels] to only return channels in the current interpreter (hobbs) 2000-10-20 (performance enhancement) call stat only when necessary in 'glob' to speed up command significantly in base cases (hobbs) 2000-11-01 (mem leak) Corrected excessive mem use of info exists on a non-existent array element (hobbs) 2000-11-02 (bug fix) Corrected sharing of tclLibraryPath in threaded environment (gravereaux) 2000-11-23 (mem leak) fixed potential memory leak in error case of lsort (fellows) 2000-12-09 (feature enhancement) changed %o and %x to use strtoul instead of strtol to correctly preserve scan<>format conversion of large integers (hobbs) Fixed handling of {!} in expressions (hobbs, fellows) 2000-12-14 (feature enhancement) improved (s)rand for 64-bit platforms (porter) 2001-01-04 (bug fix) corrected parsing of $tcl_libPath at startup on Windows (porter) 2001-01-30 (bug fix) Fixed possible hangs in fcopy. (porter) 2001-02-15 (performance enhancement) improved efficiency of [string split] (fellows) 2001-03-13 (bug fix) Correctly possible memory corruption in string map {} $str (fellows) 2001-03-29 (bug fix) prevent potential race condition and security leak in tmp filename creation on Unix. (max) Fixed handling of timeout for threads (corrects excessive CPU usage issue for Tk on Unix in threaded Tcl environment). (ruppert) 2001-03-30 (bug fix) corrected Windows memory error on exit (wu) Fixed race condition in readability of socket on Windows. 2001-04-03 (doc fixes) numerous doc corrections and clarifications. Update of READMEs. 2001-04-04 (build improvements) redid Mac build structure (steffen) Corrected IRIX-5* configure (english). Added support for AIX-5 (hobbs). Added support for Win64 (hobbs). --- Released 8.3.3, April 6, 2001 --- See ChangeLog for details --- 2000-11-23 (new feature)[TIP 7] higher resolution timer on Windows (kenny) 2001-01-18 (new feature) Tcl_InitHashTableEx renamed to Tcl_InitCustomHashTable (kupries) 2001-03-30 (new feature)[TIP 10] support for thread-aware/hot channels (kupries) 2001-04-06 (new feature)[219280] auto-loading hidden in ::errorInfo (porter) 2001-04-07 (bug fix)[406709] corrected panic when extra items left on the byte compiler execution stack (sofer) 2001-04-09 (bug fix)[219136,232558] improved use of thread-safe functions in unix time commands (kenny) 2001-04-24 (new feature)[TIP 27] started CONST-ification of the Tcl APIs (kenny) 2001-05-03 (new feature) [auto_import] now matches patterns like [namespace import], not like [string match] (porter) **** POTENTIAL INCOMPATABILITY **** 2001-05-07 (new feature)[416643] distinct srand() seed per interp (sofer) 2001-05-15 (new feature) new Tcl_GetUnicodeFromObj API (hobbs) 2001-05-16 (performance enhancement) byte-compiled versions of [lappend], [append] simple cases (hobbs) 2001-05-23 (new feature) added ISO-8859-15 and koi8-u encodings, updated other encoding tables based on http://www.unicode.org/Public/MAPPINGS/ (kuhn) 2001-05-27 (new feature) updated to Unicode 3.1.0 data set (still using 16 bits for Tcl_UniChar though) (hobbs) 2001-05-30 (new feature)[TIP 15] Tcl_GetMathFuncInfo, Tcl_ListMathFuncs, Tcl_InfoObjCmd, InfoFunctionsCmd APIs (fellows) 2001-06-08 (bug fix,feature enhancement)[219170,414936] all Tcl_Panic definitions brought into agreement (porter) 2001-06-12 (bug fix)[219232] regexp returned non-matching sub-pairs to have index pair {-1 -1} (fellows) 2001-06-27 (bug fix)[217987] corrected backslash substitution of non-ASCII characters. (hobbs, riefenstahl) 2001-06-28 (bug fix)[231259] failure to re-compile after cmd shadowing (sofer) 2001-07-02 (bug fix)[227512] corrected [concat] treatment of UTF-8 strings (hobbs, barras) 2001-07-12 (new feature)[TIP 36] Tcl_SubstObj API (fellows) 2001-07-16 (bug fix) corrected thread-enabled pipe closing on Windows (hobbs, jsmith) 2001-07-18 (bug fix)[427196] corrected memory overwrite error when buffer size of a channel is changed after channel use has already begun (kupries, porter) 2001-07-31 (new feature)[TIP 17] TclFS* APIs provide new virtual file system. This includes the addition of 'file normalize', 'file system', 'file separator' and 'glob -tails' (darley) 2001-08-06 (bug fix) removed use of tmpnam in TclpCreateTempFile on Unix (lim) * improved build support for IRIX, GNU HURD, Mac OS 9 and OS X * configure scripts revamped for better support of cygwin and gcc on Windows (mdejong) * corrected several minor errors noted by Purify (hobbs) --- Released 8.4a3, August 6, 2001 --- See ChangeLog for details --- 2001-06-27 (bug fix)[217987] corrected backslash substitution of non-ASCII characters. (hobbs, riefenstahl) 2001-06-28 (bug fix)[231259] failure to re-compile after cmd shadowing (sofer) 2001-07-02 (bug fix)[227512] corrected [concat] treatment of UTF-8 strings (hobbs, barras) 2001-07-16 (bug fix) corrected thread-enabled pipe closing on Windows (hobbs, jsmith) 2001-07-18 (bug fix)[427196] corrected memory overwrite error when buffer size of a channel is changed after channel use has already begun (kupries, porter) 2001-08-06 (bug fix)[442665] corrected object reference counting in [gets] (jikamens) 2001-08-06 (new feature) added GNU (HURD) configuration target. (brinkmann) 2001-08-07 (bug fix)[406709] corrected panic when extra items left on the byte compiler execution stack (see test foreach-5.5) (sofer, tallneil, jstrot) 2001-08-08 (new features) updated packages msgcat 1.1.1, opt 0.4.3, tcltest 1.0.1, dependencies checked (porter) 2001-08-20 (new feature)[452217] http 2.3.2: include port number in Host: header to comply with HTTP/1.1 spec (RFC 2068) (hobbs, tils) 2001-08-23 (new feature) added QNX-6 build support (loverso) 2001-08-23 (bug fix) corrected handling of spaces in path name passed to [exec] on Windows (kenpoole) 2001-08-24 (bug fix) corrected [package forget] stopping on non-existent package (porter) 2001-08-24 (bug fix) corrected construction of script library search path relative to executable (porter) 2001-08-24 (bug fix) [auto_import] now matches patterns like [namespace import], not like [string match] (porter) **** POTENTIAL INCOMPATABILITY **** 2001-08-27 (new feature) added Tcl_SetMainLoop() to enable loading Tk as a true package (hobbs) 2001-08-30 (bug fix) build support for Crays (andreasen) 2001-09-01 (bug fix) rewrite of Tcl_Async* APIs to better manage thread cleanup (gravereaux) 2001-09-06 (new feature) http 2.4: honor the Content-encoding and charset parameters; add -binary switch for forcing the issue (hobbs, saoukhi, orwell) => http 2.4 2001-09-06 (performance enhancement) rewrite of file I/O flush management on Windows. Approximately 100x speedup for some operations. (kupries, traum) 2001-09-10 (bug fix) corrected finalization error in TclInExit (darley) 2001-09-10 (bug fix) protect against alias loops (hobbs) 2001-09-12 (bug fix) added missing #include in tclLoadShl.c (techentin) 2001-09-12 (bug fix) script library path construction on Windows no longer uses registry, nor adds the current working directory to the path (porter) 2001-09-12 (bug fix) correct bugs in compatibility strtod() (porter) 2001-09-13 (bug fix) Tcl_UtfPrev now returns the proper location when the middle of a UTF-8 byte is passed in (hobbs) 2001-09-19 (bug fix) [format] and [scan] corrected for 64-bit machines (rmax) 2001-09-19 (new feature) --enable-64-bit support for HP-11. (hobbs) 2001-09-19 (new feature) native memory allocator now default on Windows (hobbs) 2001-09-20 (new feature) WIN64 support and extra processor definitions (hobbs, mstacy) 2001-09-26 (bug fix) corrected potential deadlock in channels that do not provide a BlockModeProc (kupries, kogorman) 2001-10-03 (new feature) WIN64 build support (hobbs) 2001-10-03 (bug fix) correction in thread finalization (rbrunner) 2001-10-04 (new feature) updated encodings with latest mappings from www.unicode.org (hobbs) 2001-10-11 (bug fix) corrected cleanup of self-referential bytecodes at interpreter deletion (sofer, rbrunner) 2001-10-16 (new feature) config support for MacOSX / Darwin (steffen) 2001-10-16 (new feature, Mac) change in binary extension format from MachO bundles to standard .dylib dynamic libraries like on other unices. *** POTENTIAL INCOMPATIBILITY *** 2001-10-18 (bug fix) corrected off-by-one-day error in clock scan with relative months and years during swing hours. (lavana) --- Released 8.3.4, October 19, 2001 --- See ChangeLog for details --- 2001-08-21 (bug fix)[219184] overagressive compilation of [catch] (sofer) 2001-08-22 (new feature)[227482] [dde request -binary] (hobbs) => dde 1.2 2001-08-30 (performance enhancement)[456668] fully qualified command names use cached Command for all namespaces, avoiding repeated lookups (sofer) 2001-08-31 (performance enhancement) bytecompiled [list] (hobbs) 2001-09-02 (bug fix)[403553] Add -Zl to VC++ compile line for tclStubLib to avoid any specific C-runtime library dependence. (gravereaux) 2001-09-05 (new feature) restored support for Borland compiler (gravereaux) 2001-09-05 (new feature)[TIP 49] Tcl_OutputBuffered API (schroedter, fellows) 2001-09-07 (new feature) restored VC++ 5.0 compatibility (gravereaux) 2001-09-10 (performance enhancement)[TIP 53,451441] [proc foo args {}] now compiles to 0 bytecodes (sofer) 2001-09-13 (new feature)[TIP 56] Tcl_EvalTokensStandard API (sofer) 2001-09-13 (new feature) Old ChangeLog entries => ChangeLog.1999 (hobbs) 2001-09-17 (new feature) compiling with TCL_COMPILE_DEBUG now required to enable all compile and execution tracing (sofer) *** POTENTIAL INCOMPATIBILITY *** 2001-09-19 (bug fix)[411825] made TclNeedSpace UTF-8 aware (fellows) 2001-09-19 (bug fix)[219166] overagressive compilation of "quoted" bodies of [for], [foreach], [if], and [while] (sofer) 2001-09-19 (performance enhancement) bytecompiled [string match] (hobbs) 2001-10-15 (new feature)[TIP 35] serial channel configuration: Win (schroedter) 2001-11-06 (bug fix)[478856] loss of fileevents due to short reads (kupries) 2001-11-06 (new feature) revitalized makefile.vc (gravereaux) 2001-11-07 (new feature) Cygwin gcc support dropped. Use mingw (dejong) *** POTENTIAL INCOMPATIBILITY *** 2001-11-07 (new feature) Support --include-dir= and --libdir= options to configure. Store in tclConfig.sh as TCL_INCLUDE_SPEC and TCL_LIB_SPEC. (dejong) *** POTENTIAL INCOMPATIBILITY *** 2001-11-08 (new feature) Enable --enable-threads on FreeBSD (dejong) 2001-11-08 (new feature) New make target 'make gdb' (dejong) 2001-11-09 (bug fix)[480176] [global] mishandled varnames matching :* (porter) 2001-11-12 (new feature)[TIP 22,33,45] new command [lset], [lindex] extended to accept multiple indices. (kenny, hobbs) 2001-11-16 (new feature) new configure option --enable-langinfo=no. By default, nl_langinfo() is used on Unix to determine system encoding. Tcl's built-in system is used only if that fails, or configured with --enable-langinfo=no. (hobbs, wagner) 2001-11-19 (new feature)[TIP 62] A Tcl_VarTraceProc can now return Tcl_Obj * or a dynamic string as well as a static string to indicate an error (fellows) 2001-11-19 (new feature)[TIP 73] Tcl_GetTime API (kenny) 2001-11-19 (bug fix)[478847] overflows in [time] of >2**31 microseconds (kenny) 2001-11-29 (performance enhancement) caching scheme added to [binary scan] (fellows) 2001-12-05 (new feature) new algorithm for [array get] adds safety when read traces modify the array. (sofer) *** POTENTIAL INCOMPATIBILITY *** 2001-12-10 (bug fix)[490514] doc fixes (porter,english) 2001-12-18 (new feature) removed unix/dltest/configure; unix/configure does all (dejong) 2001-12-19 (new feature) New make target 'make shell' (dejong) 2001-12-21 (new feature) MaxOSX / Darwin support (steffen) 2001-12-28 (new feature) new command [memory onexit] replaces [checkmem] when compiled with TCL_MEM_DEBUG. Added documentation. (porter) *** POTENTIAL INCOMPATIBILITY *** 2001-12-28 (bug fix) proper case in [auto_execok] use of $env(COMPSPEC) (hobbs) 2002-01-05 (feature rewrite) Tcl_Main() rewritten and documentation improved. Interactive operation and event loop operation (via Tcl_SetMainLoop) now interleave cleanly. Also more robust against strange happenings. (porter) 2002-01-17 (bug fix)[504642] Tcl_Obj refCounts in [gets] (griffen,kupries) 2002-01-21 (bug fix)[506297] infinite loop writing in iso2022-jap encoding (forssen,kupries) 2002-01-24 (HTTP server bug workaround)[504508] leave the default port out of the Host: header value => http 2.4.1 (hobbs) 2002-01-25 (new feature)[496733] socket options -eofchar and -translation return read-only values (dejong) 2002-01-28 (new feature) Old ChangeLog entries => ChangeLog.20900 (hobbs) 2002-01-28 (performance enhancement) bytecompiled [regexp] for trivial cases that amount to string matching. Also -nocase and --. (hobbs) 2002-02-05 (bug fix) [http::error] called when [::error] intended => http 2.4.2 (porter) 2002-02-05 (bug fix)[465765] avoid zero-byte writes to STREAMs (talcott,kupries) 2002-02-06 (performance enhancement) [regsub] special cases that map to [string map] detected. (hobbs) 2002-02-06 (bug fix)[495213] [scan] accept 0x as prefix of base 16 value (hobbs) 2002-02-10 (new feature)[TIP 32,79] Tcl_CreateObjTrace API (kenny) 2002-02-12 (new feature) partial support for DJGPP Tcl on DOS (gravereaux) 2002-02-14 (mem leak) Fixed leaking an empty Tcl_Obj when [gets $chan] errored out. (kupries, sofer) 2002-02-15 (new feature)[TIP 72] support for 64-bit integer values on 32-bit platforms and ability to work with >2GiB files. Extends many commands. See ChangeLog and TIP for details. *** POTENTIAL INCOMPATIBILITY *** 2002-02-22 (bug fix)[476537] Fix panic when loading shared library without proper use of stubs on platform without backlinking (porter) 2002-02-22 (new feature) 64-bit support for xlc compiler on AIX-4 (hobbs) 2002-02-22 (new feature)[521560] Removed limits on filename length and format [source]able through the Safe Base (hobbs) 2002-02-22 (performance enhancement) optimized bytecodes for [if], [for], [while] and constant conditions (sofer) 2002-02-22 (new feature)[TIP 76] [regsub] can now return result (fellows) 2002-02-25 (bug fix)[495207] buffer overrun when closing ] left out of argument to [subst] (sofer, english) 2002-02-25 (bug fix)[514392] [load] updated for Mac OS X 10.1 (steffen) 2002-02-26 (bug fix) [info hostname] choked on names >31 characters (hobbs) 2002-02-26 (new feature)[TIP 35] serial channel configuration: Unix (schroedter, hobbs) 2002-02-25 (bug fix)[483575] [fconfigure ... -error] now no-op on Mac (kupries) 2002-02-28 (performance enhancement)[458872] fully qualified command names use cached Command for all namespaces, avoiding repeated lookups (sofer) * (new feature)[TIP 27] completed CONST-ification of TCL APIs. Added compiler macro USE_NON_CONST to keep using those old API prototypes that present irreconcilable source incompatibilities with header files of prior Tcl releases. Others will need to be reconciled. *** POTENTIAL INCOMPATIBILITY *** 2002-03-04 (bug fix)[474358, 218099, 219314, 524674] fixed several problems related to the handling of iso2022 text and finalization of escape-based encodings. (taguchi, takahashi, hobbs) --- Released 8.4a4, March 5, 2002 --- See ChangeLog for details --- 2002-03-06 (new feature)[TIP 80] expanded [lsearch] options (wilkason, fellows) 2002-03-07 (new feature)[TIP 87] [interp recursionlimit] (trier) 2002-03-08 (platform feature) mingw 1.1 build favored (dejong) 2002-03-20 (new feature)[TIP 27] CONST-ified variable access functions (porter) 2002-03-24 (bug fix)[511666,511658,523217,530960] expanded Tcl_FSMatchInDirectory to handle assorted [glob] bugs in VFS. (darley) *** POTENTIAL INCOMPATIBILITY with prior 8.4a releases *** 2002-03-25 (bug fix)[495726] stopped tcltest disabling of auto-loading (porter) 2002-03-25 (bug fix)[495977] allow \n in test constraints (porter) 2002-03-27 (platform support)[527941,533862] VC/winhelp/W9X (spjuth, gravereaux) 2002-03-28 (bug fix)[219181] exception at level 0 issues (sofer) 2002-03-28 (bug fix)[219362] command termination; Tcl_CreateTrace (knoll,sofer) 2002-04-05 (bug fix)[536879] exceptions during variable subst (porter) 2002-04-15 (bug fix)[497446,513983] tcltest syntax errors now raised (porter) ***POTENTIAL INCOMPATIBILITY with prior tcltest 2.0.* (8.4aX)*** 2002-04-17 (bug fix)[495660] [(save|restore)state] deprecated (porter) 2002-04-17 (bug fix)[526524] escape-based encodings corrected (yamamoto, hobbs) 2002-04-18 (bug fix)[542588] [expr] error msgs improved (ehrens, sofer) 2002-04-18 (bug fix)[545325] [info level $level] now returns [namespace eval] as documented (suchenwirth,sofer) 2002-04-19 (bug fix)[544727] export [mcload]; ns context of [mcmax] (porter) => msgcat 1.2.3 2002-04-22 (performance enhancement) threaded memory allocator (AOL, hobbs) 2002-04-24 (new feature) TCLTK_NO_LIBRARY_TEXT_RESOURCES #define disables inclusion of tcl library code in resource fork on Mac. (steffen) 2002-05-21 (platform support) static libs on OSF (dejong) 2002-05-24 (bug fix)[557878] set encoding on listening socket (staplin, kupries) 2002-05-24 (new feature)[TIP 91] Tcl_Seek compatibility (fellows) 2002-05-28 (bug fix)[545579] VFS [load] left temp file (darley) 2002-05-28 (bug fix)[559376] plug timezone env leak on Windows (hobbs) 2002-05-29 (performance enhancement) [string compare] optimized (hobbs,fellows) 2002-05-31 (bug fix)[550534] plug interp leak in [pkg_mkIndex] (helmut) 2002-05-31 (dead code)[474335,555635] removed all use of matherr() (english) *** POTENTIAL INCOMPATIBILITY *** 2002-06-04 (new feature)[TIP 85,521362] custom result match in tcltest (markus, porter) => tcltest 2.1 2002-06-06 (bug fix)[524352] encoding, threading, and environment issues on MacOSX (steffen) 2002-06-06 (bug fix)[512214,558742,512214,461000] lazy initialization of tcltest constraints (porter) 2002-06-07 (bug fix)[563122,564595] EOVERFLOW definitions (fellows) 2002-06-11 (bug fix)[567386] [info locals] corrections (sofer) 2002-06-14 (new feature)[TIP 102] [trace list] renamed [trace info] (fellows) 2002-06-17 (new feature)[525522,525525] msgcat support for XPG4 locales; examination of LC_ALL, LC_MESSAGES environment variables (haible, porter) => msgcat 1.3 2002-06-17 (new feature)[565088] header files assume modern C compiler by default; older compilers may need configuration (english) *** POTENTIAL INCOMPATIBILITY *** 2002-06-17 (bug fix)[554068] [exec] argument quoting on Windows (darley) 2002-06-17 (new feature)[TIP 62,462580] command execution traces (lavana) 2002-06-19 (bug fix)[558324] regexp sets a linked variable (watson) * (performance enhancment) optimizations of bytecode execution (sofer) 2002-06-21 (new feature)[TIP 99,562970] new [file link] command (darley) 2002-06-24 (new feature)[TIP 101] new [tcltest::configure] command (porter) => tcltest 2.2 2002-06-25 (new feature) --enable-man-symlinks and --enable-man-compression options to configure (max) 2002-06-26 (bug fix)[565880] [clock format] now respects locale (max) *** POTENTIAL INCOMPATIBILITY *** 2002-07-03 (bug fix)[577015] [catch] catches even compile errors (sofer) --- Released 8.4b1, July 5, 2002 --- See ChangeLog for details --- 2002-07-08 (bug fix) restored compatibility of [viewFile] in tcltest (porter) 2002-07-11 (bug fix) [file normalize] returns long form on Win 95/98/ME (darley) 2002-07-15 (performance enhancment) variable operations rewritten to store and use cached Var pointers (sofer) 2002-07-22 (bug fix)[218000] Inf and Nan are floating-point values (fellows) 2002-07-23 (platform support)[219220] 64-bit compile on IRIX (dejong) 2002-07-25 (bug fix)[219218] return codes in background errors (english) 2002-07-28 (bug fix)[582522] alias fires exec traces (sofer) 2002-07-29 (bug fix)[578363] regexp (fellows,pvgoran) 2002-07-30 (bug fix)[584603] WriteChars infinite loop non-UTF-8 string (kupries) 2002-08-04 (new feature)[584051,580433,585105,582429][TIP 27] Tcl interfaces are now fully CONST-ified. Use the symbols USE_NON_CONST or USE_COMPAT_CONST to select interfaces with fewer changes. *** POTENTIAL INCOMPATIBILITY *** 2002-08-05 (bug fix)[589859] tcltest setup and cleanup scripts skipped when test body is skipped (porter) => tcltest 2.2 2002-08-07 (bug fix)[587488] mem leak with USE_THREAD_ALLOC (sofer,sass) 2002-08-07 (feature enhancement)[584794,584650,472576] boolean values are no longer always re-parsed from string. (sofer) Many internal bugs fixed. Considerable cleanup of the test suite. --- Released 8.4b2, August 9, 2002 --- See ChangeLog for details --- 2002-08-20 (new feature) --enable-memdebug configure option (kupries) 2002-08-23 (bug fix)[597936] mem leak with USE_THREAD_ALLOC (sofer,zoran) 2002-08-26 (bug fix)[599788] segfault in compiler (sofer,wilkason) 2002-08-28 (bug fix)[414910] avoid mem leaks accessing environment variables on Windows (welton,gravereaux) 2002-08-31 (platform support)[TIP 108] Mac OS X port (steffen,ingham) 2002-09-02 (platfrom support) 64-bit compile on HP-11 (martin) --- Released 8.4.0, September 10, 2002 --- See ChangeLog for details --- 2002-09-18 (platform support) Updated support for compiling with Cygwin and either mingw or gcc. (khan, howell, dejong) 2002-09-22 (bug fix)[612786, 611922] Corrected [puts -nonewline] within test bodies. Also corrected reporting of body return code. Updated tcltest to v2.2.1. 2002-09-24 (bug fix)[613117] More robust 64-bit wide integer value detection (fellows) 2002-09-26 (bug fix) correct overeager optimization of noop proc to handle the precompiled case. (sofer, hobbs) 2002-09-26 (bug fix)[615115] removed extraneous spaces in koi8-u.enc that confused encoding reader. 2002-09-29 (bug fix)[219355] Added proper exiting conditions using Win32 console signals. This handles the existing lack of a Ctrl+C exit to call exit handlers when built for thread support. Also, properly handles exits from other conditions such as CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT, and CTRL_SHUTDOWN_EVENT signals. In all cases, exit handlers will be called. (gravereaux) 2002-09-30 (bug fix) improve the checking for bad regular expressions during regexp compilation. Resultant compiles were correct, but much slower than necessary. (hobbs) 2002-10-01 (bug fix) fix precompiled locals to support 8.3 precompiled code. (hobbs) 2002-10-09 (bug fix)[620735] Added code to set an exit handler on Windows that terminates the thread that calibrates the performance counter, so that the thread won't outlive unloading the Tcl DLL. (kenny) 2002-10-09 (build support) all --enable-symbols to take the enhanced options yes|no|mem|compile|all. (hobbs) 2002-10-10 (build support) enable USE_THREAD_ALLOC (new threaded allocator) by default on Windows. (hobbs, gravereaux) 2002-10-14 (bug fix)[623269] correct possible mem leak in Tcl_PutEnv. (brouwers) 2002-10-15 (bug fix)[615043] fix in execution traces with idle tasks firing. (lavana) 2002-10-15 (platform support) Correct AIX-5 ppc and 4/5 64-bit build flags. Correct HP 11 64-bit gcc building. (martin, hobbs) 2002-10-17 (bug fix)[624755] Fixed code that check for proper # of args to [array names] (porter) 2002-10-18 (feature enhancement)[625453] Added support for broadcasting changes to the registry Environment on Windows. Updated registry package to v1.1. (hobbs) 2002-10-22 (platform support)[624509] On macosx, add embedded framework dirs to tcl_pkgPath: @executable_path/../Frameworks and @executable_path/../PrivateFrameworks (if they exist), as well as the dirs in DYLD_FRAMEWORK_PATH (if set). (steffen) --- Released 8.4.1, October 22, 2002 --- See ChangeLog for details --- 2002-10-28 (bug fix)[627660] [package unknown] chaining for platform specifics 2002-10-29 (bug fix)[627546] verbose [load] (dyld) error mesages on MacOSX 2002-11-01 (bug fix) [package provide registry] consistent versions. 2002-11-06 (bug fix)[582039] missing ar program -> configuration error 2002-11-06 (feature enhancement) added new TclInThreadExit function to test for thread exit vs whole process exit condition. The TclInExit function now correctly returns 1 during Tcl_Finalize processing. *** POTENTIAL INCOMPATIBILITY *** 2002-11-13 (bug fix)[615043] some execution traces were not firing 2002-11-18 (bug fix)[634856] multiple signs no longer accepted as valid integer [string is integer ++1] => 0 *** POTENTIAL INCOMPATIBILITY *** 2002-11-26 (bug fix)[593810,597924] clean exit of channel worker threads on Win 2002-11-28 (new feature) `make valgrind` target 2002-12-03 (bug fix)[615304] repeated load/unload of Tcl now possible 2002-12-11 (bug fix)[647307] negative return codes now propagated by procs 2002-12-11 (bug fix)[648441] syntax error in [expr 0x] now detected. 2003-01-07 (bug fix)[633204] [catch {return}] => 2 (not 0) 2003-01-09 (bug fix)[634151] [file (a|m)time $nonASCIIpath $time] now works 2003-01-16 (bug fix) dde eval with {} service name does not crash. => dde 1.2.1 2003-01-16 (bug fix)[635200,655645,615043,571385] many command trace fixes 2003-01-31 (bug fix)[675614,678415,676978] tcltest conflicts in cleanup and -outfile; also failure in space-containing path; also missing [close] => tcltest 2.2.2 2003-02-01 (bug fix)[670042] corrected [info loaded {}] for static packages in multiple interps. 2003-02-01 (bug fix)[675356] [clock clicks {}]; [clock clicks -] - syntax errs 2003-02-01 (bug fix)[656660] MT-safety for [clock format] 2003-02-03 (bug fix)[651271] command rename traces get fully-qualified names *** POTENTIAL INCOMPATIBILITY *** 2003-02-07 (performance improvement) [glob] on Windows is 2.5 times faster 2003-02-07 (feature change) lack of Cygwin support indicated by config error 2003-02-11 (bug fix)[684744] [info complete] stopped by \x00 2003-02-11 (bug fix)[685445] [glob -types l] missed broken symlinks on Unix 2003-02-11 (bug fix) [lsearch -regexp $a $a] doesn't crash 2003-02-13 (bug fix)[685926] accept non-ASCII7 for tcl_platform(user) on Win 2003-02-15 (bug fix)[673714] stop crash when Tcl_DeleteEvents deletes last 2003-02-15 (bug fix)[681841] parser missed some missing ] syntax errors 2003-02-17 (bug fix)[684756] memory leak during command rename plugged 2003-02-18 (bug fix)[689100] reduced per-thread memory overhead 2003-02-18 (platform support)[651811] use xnet library on HP 11 (64 bit). 2003-02-20 (bug fix)[Patch 689341] correct jis round-trip encoding 2003-02-20 (bug fix)[689835] stop MacOSX hang trying to read a write-only pipe 2003-02-07 (performance improvement) [tclPkgUnknown]: fewer vfs calls 2003-02-18 (platform support) cut and splice procs for file channels on Mac 2003-02-21 (bug fix)[690774] [binary scan] failed on some wide ints 2003-02-22 (bug fix)[571002] plugged data leak during thread exit 2003-02-25 (feature change) [pkg_mkIndex -load]: case-insensitive match *** POTENTIAL INCOMPATIBILITY *** 2003-02-27 (bug fix)[694232] stop [lsearch -start 0 {} x] segfault --- Released 8.4.2, March 3, 2003 --- See ChangeLog for details --- 2003-03-06 (bug fix)[699042] Correct case-insensitive unicode string comparison in Tcl_UniCharNcasecmp 2003-03-11 (bug fix) Corrected loading of tclpip8x.dll on Win9x 2003-03-12 (bug fix)[702383] Corrected parsing of interp create -- 2003-03-12 (bug fix)[685106] Correct Tcl_SubstObj handling of \x00 bytes 2003-03-14 (bug fix)[702622 699060] Correct wide int issues in 'format' 2003-03-14 (bug fix)[698146] Remove assumption that file times and longs are the same size. 2003-03-18 (bug fix)[697862] Allow Tcl to differentiate between reparse points which are symlinks and mounted drives on Windows 2003-03-19 (bug fix)[705406] Bad command count on TCL_OUT_LINE_COMPILE 2003-03-20 (bug fix)[707174] Store pointers to notifier funcs in a struct to work around some platform linker issues 2003-03-22 (bug fix)[708218] Load correct (non-)debug dll for dde or registry 2003-03-24 (bug fix)[631741 696893] Fixing ObjMakeUpvar's lookup algorithm for the created local variable 2003-04-07 (bug fix)[713562] Make sure that tclWideIntType is defined and somewhat sensible everywhere 2003-04-07 (bug fix)[711371] Corrected string limits of arguments interpolated in error messages for 'if' 2003-04-11 (bug fix)[718878] Corrected inconsistent results of [string is integer] observed on systems where sizeof(long) != sizeof(int) 2003-04-12 (bug fix) Substantial changes to the Windows clock synch phase-locked loop in a quest for improved loop stability 2003-04-16 [713562] Made changes so that the "wideInt" Tcl_ObjType is defined on all platforms, even those where TCL_WIDE_INT_IS_LONG is defined. Also made the Tcl_Value struct have a wideValue field on all platforms. Potential incompatibility for TCL_WIDE_INT_IS_LONG platforms because that struct changes size. *** POTENTIAL INCOMPATIBILITY *** 2003-04-25 (bug fix)[727271] Catch any errors returned by the Windows functions handling TLS ASAP instead of waiting to get some mysterious crash later on due to bogus pointers. 2003-04-29 (bug fix) Correct 'glob -path {[tcl]} *', where leading special character instead lists files in '/'. Bug only occurs on Windows where '\' is also a directory separator. 2003-05-09 (bug fix)[731754] Fixed memory leak in threaded allocator on Windows caused by treating cachePtr as a TLS index 2003-05-10 (bug fix)[710642] Ensure cd is thread-safe 2003-05-10 (bug fix)[718002] Correct mem leak on closing a Windows serial port 2003-05-10 (bug fix)[714106] Prevent string repeat crash when overflow sizes were given (throws error). 2003-05-13 (feature enhancement)[736774] Use new versioned bundle resource API to get tcl runtime library for TCL_VERSION on Mac OS X. 2003-05-13 (bug fix)[711232] Worked around the issue of realpath() not being thread-safe on Mac OS X by defining NO_REALPATH for threaded builds on Mac OS X. 2003-05-14 (bug fix)[557030] Correct handling of the gb2312 encoding by making it an alias of the euc-cn encoding and creating a gb2312-raw encoding for the original. Most uses of gb2312 really mean euc-cn. 2003-05-14 (bug fix)[736421] Corrected another putenv() copy behavior problem when compiling on Windows and using Microsoft's runtime. --- Released 8.4.3, May 20, 2003 --- See ChangeLog for details --- 2003-05-23 (bug fix)[726018] reverted internals change to the 'cmdName' Tcl_ObjType that broke several extensions (TclBlend, e4graph...) in the 8.4.3 release. 2003-06-10 (bug fix)[495830] stop eval of bytecode in deleted interp. 2003-06-17 (bug fix) corrections to regexp when matching emtpy string. 2003-06-25 (bug fix)[748957] -*ieee compiler flags for Tru64 builds. 2003-07-11 (bug fix) [pkg_mkIndex] indexes provided packages, not indexed ones. 2003-07-15 (feature enhancement) MacOSX build system rewrite. 2003-07-15 (bug fix)[771613] corrected segfault in [if] (buffer overflow) 2003-07-16 (bug fix)[756791] corrected assumption that Tcl_Free == free 2003-07-16 (feature enhancement) -DTCL_UTF_MAX=6 compile option forces internal UCS-4 representation of Unicode (default is recommended UCS-2). 2003-07-16 (bug fix)[767578] 64-bit corrections in thread notifier. 2003-07-16 (bug fix)[759607] Safe Base tests normalized paths. 2003-07-16 (feature enhancement)[Patch 679315] improved Cygwin path support 2003-07-18 (bug fix)[706359] corrected broken -output option of [tcltest::test] => tcltest 2.4.4 2003-07-18 (bug fix)[753315] MT-safety of VFS records. 2003-07-18 (bug fix)[759888] support for user:pass in URL by [http::geturl] => http 2.4.4 Improved documentation, new tests, and some code cleanup. [655300, 720634, 735364, 748700, 756112, 756744, 756951, 758488, 760768, 763312, 769895, 771539, 771840, 771947, 771949, 772333] --- Released 8.4.4, July 22, 2003 --- See ChangeLog for details --- 2003-07-23 (bug fix)[775976] fix registry compilation for VC7. 2003-08-05 (enhancement)[781585] Use Tcl_ResetResult in bytecodes to prevent potential costly Tcl_Obj duplication. 2003-08-06 (bug fix)[781609] prevent non-Windows platforms from trying to use the registry package inside msgcat. 2003-08-27 (bug fix)[411825] Fix TclNeedSpace to handle non-breaking space (\u00A0) and backslash escapes correctly. 2003-09-01 (bug fix)[788780] Fix thread-safety issues in filesystem records. 2003-09-19 (bug fix)[804681] Protect ::errorInfo and ::errorCode traces from corrupting stack. 2003-09-23 (bug fix)[218871] Fix handling of glob-sensitive chars in auto_load and auto_import. 2003-10-03 (bug fix)[811483] Fixed refcount management for command and execution traces. 2003-10-04 (bug fix)[789040] Fixed exec command.com error for Win9x. 2003-10-06 (bug fix)[767834, 813273] Fixed volumerelative file normalization and 'file join' inconsistencies. 2003-10-08 (bug fix)[769812] Fix Tcl_NumUtfChars string length calculation when negative parameter is given. 2003-10-22 (bug fix)[800106] Handle VFS mountpoints inside glob'd dirs. 2003-10-22 (bug fix)[599468] Watch for FD_CLOSE too on Windows when asked for writable events by the generic layer. 2003-10-23 (bug fix)[813606] Detect OS X pipes correctly. 2003-11-05 (bug fix)[832657] Allow .. in libpath initialization. 2003-11-11 (bug fix) Improve AIX-64 build configuration. 2003-11-17 (bug fix)[230589, 504785, 505048, 703709, 840258] fixes to various odd regexp "can't happen" bugs. --- Released 8.4.5, November 20, 2003 --- See ChangeLog for details --- 2003-12-02 (bug fix)[851747] object sharing fix in [binary scan] 2003-12-09 (platform support)[852369] update errno usage for recent glibc 2003-12-12 (bug fix)[858937] fix for [file normalize ~nobody] 2003-12-17 (bug fix)[839519] fixed two memory leaks (vasiljevic) 2004-01-09 (bug fix)[873311] fixed infinite loop in TclFinalizeFilesystem 2004-02-02 (bug fix)[405995] Tcl_Ungets buffer filling fix 2004-02-04 (bug fix)[833910] tcltest command line option parsing error => tcltest 2.4.5 2004-02-04 (bug fix)[833637] code error in tcltest -preservecore operation 2004-02-12 (feature enhancement) update HP-11 build libs setup 2004-02-17 (bug fix)[849514,859251] corrected [file normailze] of $link/.. 2004-02-17 (bug fix)[772288] Unix std channels forced to exist at startup. 2004-02-17 (new default) tcltest::configure -verbose {body error} 2004-02-19 (bug fix) init.tcl search path with unusual --libdir (samson) 2004-02-25 (bug fix)[554068] stopped broken [exec] quoting of { (gravereaux) 2004-02-25 (bug fix)[888777] plugged memory leak with long host names (cassoff) 2004-03-01 (bug fix)[462580] corrected level interpretation of Tcl_CreateTrace 2004-03-01 (platform support)[218561] Allow 64-bit configure on IRIX64-6.5* --- Released 8.4.6, March 1, 2004 --- See ChangeLog for details --- 2004-03-08 (bug fix)[910525] [glob -path] in root directory (darley) 2004-03-15 (bug fix)[916795] syntax error -> compiler segfault (sofer,porter) 2004-03-29 (bug fix)[920667] install into any Unicode path on Win (hobbs) 2004-03-31 (bug fix)[811457] support translation to "" (porter) 2004-03-31 (bug fix)[811461] ignore locales with no "language" part (porter) => msgcat 1.3.2 2004-04-07 (platform support) properly substitute more values in Windows tclConfig.sh (hobbs) 2004-04-23 (bug fix)[930851] reset channel EOF when eofchar changes (kupries) 2004-05-03 (bug fix)[947070] stack overflow prevention on Win (kenny) 2004-05-03 (bug fix)[868853] fix leak in [fconfigure $serial -xchar] (cassoff) 2004-04-05 (bug fix)[928353,929892,928808,947440,948177] test fixes: OSX (abner) 2004-05-04 (bug fix) crash: [cd] w/ volumerelative $HOME (hobbs) 2004-05-05 (bug fix)[794839] socket connect error -> r/w fileevents (gravereaux) 2004-05-14 (bug fix)[940278,922848] [clock] notices $::env(TZ) changes, gmt works on all platforms. (kenny, welton, glessner) 2004-05-18 (bug fix)[500285,500389,852944] [clock %G %V] ISO8601 week numbers (kenny) 2004-05-22 (bug fix)[735335,736729] variable name resolution error (sofer) 2004-05-24 (bug fix) support for non-WIDE_INT aware math functions (hobbs) 2004-05-25 (new feature) [http::config -urlencoding] (hobbs) => http 2.5.0 2004-05-26 (bug fix)[960926] file count doubled when -singleproc 1 (porter) => tcltest 2.2.6 2004-05-27 (bug fix)[949905] corrected utf-8 encoding of \u0000 on I/O (max) 2004-06-05 (bug fix)[976722] hi-res clock fixes: Win (godfrey, suchenwirth, kenny) 2004-06-10 (bug fix)[932314] bad return values from Tcl_FSChdir() (vasiljevic) 2004-06-14 (bug fix) correct dde hangs w/non-responsive apps (thoyts) => dde 1.2.3 2004-06-21 (platform support) exceptions w/ gcc -O3 on Win (dejong) 2004-06-29 (bug fix)[981733] SafeBase global pollution (fellows) 2004-07-02 (new feature)[TIP 202] pipe redirection 2>@1 (hobbs) 2004-07-03 (bug fix)[908375] round() wide integer support (lavana, sofer) 2004-07-15 (bug fix)[770053] crash in thread finalize of notifier (vasiljevic) 2004-07-15 (bug fix)[990453] plug mutex leaks on reinit (mistachkin, vasiljevic) 2004-07-16 (bug fix)[990500] clean exit of notifier thread (mistachkin, kupries) 2004-07-19 (bug fix)[987967] improved self-init of mutexes on Win (vasiljevic) 2004-07-19 (bug fix)[874058] improved build configuration on 64-bit systems. Corrects Tcl_StatBuf definition issues. (hobbs) 2004-07-20 (bug fix) pure Darwin/CFLite support (steffen) 2004-07-20 (bug fix)[736426] plug leaky allocator reinit (mistachkin, kenny) --- Released 8.4.7, July 26, 2004 --- See ChangeLog for details --- 2004-07-28 (bug fix)[999084] no deadlock in re-entrant Tcl_Finalize (porter) 2004-08-10 (bug fix) thread IDs on 64-bit systems (ratcliff,vasiljevic) 2004-08-13 (bug fix) avoid malicious code acceptance by [mclocale] (porter) => msgcat 1.3.3 2004-08-16 (bug fix)[1008314] Tcl_SetVar TCL_LIST_ELEMENT (sofer,porter) 2004-08-19 (bug fix)[1011860] [scan %ld] fix on LP64 (fellows,porter) 2004-08-30 (bug fix) [string map $x $x] crash (fellows) 2004-09-01 (bug fix)[1020445] WIN64 support (hobbs) 2004-09-07 (bug fix)[1016167] [after] overwrites its imports (kenny) 2004-09-08 (bug fix) fixed [clock format 0 -format %k] (kenny) 2004-09-09 (bug fix)[560297] fixed broken [namespace forget] logic (porter) 2004-09-09 (bug fix)[1017299] fixed [namespace import] cycle prevention (porter) 2004-09-10 (performance) $x[set x {}] is now fast [K $x [set x {}]] (sofer) 2004-09-10 (bug fix)[868489] better control over int <-> wideInt (fellows,kenny) 2004-09-10 (bug fix)[1025359] POSIX errorCode from wide seeks (kupries,fellows) 2004-09-18 (bug fix)[868467] fix [expr 5>>32] => 0, not 5 (hintermayer,fellows) 2004-09-23 (bug fix)[1016726] fix `make clean` in static config (leitgeb,dejong) 2004-09-29 (bug fix)[1036649] syntax error in [subst] => buffer overflow (sofer) 2004-09-30 (bug fix)[1038021] save/restore error state: var traces (porter) 2004-10-08 (bug fix)[954263] case insensitive [file exec] for Win (hobbs,darley) 2004-10-14 (performance) [info commands/globals/procs/vars $pattern] faster when $pattern is trivial (fellows) 2004-10-28 (bug fix)[1030548] restore the --enable-symbols --enable-threads build on Win (mistachkin,kenny,kupries) 2004-10-29 (bug fix)[1055673] fix command line syntax error message (porter) => tcltest 2.2.7 2004-10-31 (bug fix)[1057461] fix [info globals ::varName] (fellows) 2004-11-02 (bug fix)[761471] fix [expr {NaN == NaN}] (sofer) 2004-11-02 (bug fix)[1017151] misleading errorInfo after tests (seeger,porter) 2004-11-11 (bug fix)[1034337] recursive file delete, MacOSX (steffen) 2004-11-12 (bug fix)[1004065] stop crash when TCL_UTF_MAX==6 (hobbs,porter) 2004-11-15 (bug fix)[10653678] [trace variable],[trace remove] interop (porter) 2004-11-16 (bug fix)[695441] [tcl_findLibrary] search $::auto_path too (porter) 2004-11-16 (bug fix)[1067709] crash in [fconfigure -ttycontrol] (hobbs) 2004-11-18 (new feature) configure options --enable-man-suffix (max) Documentation improvements [759545,1058446,1062647,1065732,etc.] Test suite expansion [1036649,1001997,etc.] --- Released 8.4.8, November 18, 2004 --- See ChangeLog for details --- 2004-11-22 (bug fix)[1030465] Improve HAVE_TYPE_OFF64_T check (dejong) 2004-11-23 (bug fix)[1072654] Fixed segfault in info vars trivial matching branch (new in 8.4.8) (porter) 2004-11-23 (bug fix)[1043129] Fixed the treatment of backslashes in file join on Windows (darley) 2004-11-24 (bug fix)[1001325, 1071701] Fixed readdir_r detection and usage (dejong, kenny, porter) 2004-11-24 (bug fix)[1071807] Fixed all uses of 'select' to use standard macros rather than older bit-whacking style (kenny) 2004-11-26 (bug fix)[1072136] Remove file normalize on tcl_findLibrary search path uniqification added in 8.4.8 (porter) 2004-12-02 (bug fix)[1074671] Ensure tilde paths are not returned specially by 'glob' (darley) --- Released 8.4.9, December 6, 2004 --- See ChangeLog for details --- 2004-12-29 (platform support)[1092952,1091967] MSVC7, gcc OPT compiles (hobbs) 2005-01-05 (bug fix)[1084595] encoding maps for some Chinese locales (fellows) 2005-01-06 (performance)[1020491] [http::mapReply] (fellows) => http 2.5.1 2005-01-25 (bug fix)[1101670] [auto_reset] update for [namespace] (porter) 2005-01-27 (new feature)[TIP 218] Tcl_Channel API update for threads (kupries) 2005-01-27 (bug fix)[1109484] Tcl_Expr* updates for Tcl_WideInt (hobbs) 2005-01-28 (platform support)[1021871] Solaris gcc 64-bit support (hobbs) 2005-02-10 (bug fix)[1119369] Tcl_EvalObjEx: avoid shimmer loss of List intrep (sofer,macdonald) 2005-02-10 (platform support) correct gcc builds for AIX-4+, HP-UX-11 (hobbs) 2005-02-24 (bug fix)[1119798] prevent [source $directory] (porter,mpettigr) => tcltest 2.2.8 2005-03-10 (bug fix)[1153871] bad ClientData cast (porter,victorovich) 2005-03-15 (platform support) OpenBSD ports patch (thoyts) 2005-03-15 (platform support)[1163422] time_t wider than long (kenny) 2005-03-18 (bug fix)[1115904] restore recursion limit in direct eval (porter) 2005-03-29 (platform support) allow msys builds without cygwin (hobbs) 2005-04-06 (bug fix)[1178445] fix memory waste at thread exit (vasiljevic) 2005-04-13 (bug fix) min buffer size dropped from 10 to 1 byte (gravereaux) 2005-04-19 (bug fix)[947693] Windows pipes honor -blocking during close (gravereaux) ***POTENTIAL INCOMPATIBILITY*** async pipes on windows, set -blocking 1 before [close] to receive exit status 2005-04-20 (bug fix)[1090869] Tcl_GetInt accept 0x80000000, 64-bit (porter,singh) 2005-04-22 (bug fix)[1187123] [string is boolean] respect EIAS (porter) 2005-04-25 (platform support) builds on Mac OS X 10.1 (steffen) 2005-05-06 (platform support) x86_64 Solarix cc and Solaris 10 builds (hobbs) 2005-05-14 (platform support) Mac OSX: configurable CoreFoundation API (steffen) 2005-05-14 (platform support) Mac OSX: use realpath when threadsafe (steffen) 2005-05-20 (bug fix)[1201589] boolean literal prefix in expressions (porter) 2005-05-24 (platform support) Darwin build support merged into unix (steffen) 2005-05-24 (new feature)[1202209] Mac OSX: support [load] of .bundle binaries Can support [load] from memory as well (steffen) 2005-05-24 (new feature)[1202178] [time] returns non-integer result (steffen) 2005-05-31 (bug fix)[1082283] Unix: notifier thread now joinable (vasiljevic) Documentation improvements [1075433,1085127,1117017,1124160,1149605,etc.] --- Released 8.4.10, June 4, 2005 --- See ChangeLog for details --- 2005-06-06 (bug fix)[1213678] Windows/gcc: crash in stack.test (kenny) 2005-06-07 (bug fix) Unix: --enable-threads compile failure (fellows) 2005-06-18 (bug fix)[1154163] [format %h] on 64-bit OS's (kraft,fellows) 2005-06-21 (bug fix)[1201035,1224585] execution trace crashes (porter) 2005-06-21 (bug fix)[1194458] Windows: [file split] (kenny,porter) 2005-06-22 (bug fix)[1225727] Windows: pipe finalization crash (kenny) 2005-06-22 (bug fix)[1225571] Windows: [file pathtype] buffer overflow (thoyts) 2005-06-22 (bug fix)[1225044] Windows: UMR in pipe close (kenny) 2005-06-23 (bug fix)[1225957] Windows/gcc: crashes in assembler code (kenny) 2005-06-27 (revert)[1101670] [auto_reset] disabled in non-global namespace. Restores Tcl 8.4.9 behavior (porter) --- Released 8.4.11, June 28, 2005 --- See ChangeLog for details --- 2005-07-01 (bug fix)[1222872] notifier spurious wake-up protection (vasiljevic) 2005-07-05 (bug fix)[1077262] improved Tcl_Encoding lifetimes (porter) 2005-07-05 (bug fix)[1230597] allow idempotent [namespace import] (porter) 2005-07-07 (bug fix)[1095909] readdir_r usage purged (hobbs) 2005-07-22 (enhancement)[1237755] 8.4 features in script library (fradin,porter) 2005-07-24 (new feature) configure macros SC_PROG_TCLSH, SC_BUILD_TCLSH (dejong) 2005-07-26 (bug fix)[1047286] cmd delete traces during namespace delete (porter) 2005-07-26 (new unix feature)[1231015] ${prefix}/share on ::tcl_pkgPath (dejong) 2005-07-28 (unix bug fix)[1245953] O_APPEND for >> redirection (fellows) 2005-07-29 (bug fix)[1247135] [info globals] return only existing vars (fellows) 2005-07-30 (new Darwin feature) TCL_LOAD_FROM_MEMORY configuration (steffen) 2005-08-05 (bug fix)[1241572] correct [expr abs($LONG_MIN)] (kenny) 2005-08-05 (Solaris bug fix)[1252475] recognize cp1251 encoding (wagner,fellows) 2005-08-17 (bug fix)[1217375] [file mkdir] race (diekhans,darley) 2005-08-25 (bug fix)[1267380] [lrepeat] buffer overflow prevention (fellows) 2005-08-29 (bug fix)[1275043] restore round() away from zero (kenny) 2005-09-07 (bug fix)[1283976] invalid [format %c -1] result (porter) 2005-09-15 (RHEL bug fix)[1287638] support open >2GB files RHEL 3 (palan) 2005-09-30 (bug fix)[1306162] $argv encoding and list formatting (porter) 2005-10-04 (bug fix)[1067708] [fconfigure -ttycontrol] leak (hobbs) 2005-10-04 (bug fix)[1182373] [http::mapReply] update to RFC 3986 (aho,hobbs) => http 2.5.2 2005-10-04 (HPUX bug fix)[1204237] shl_load() and DYNAMIC_PATH (collins,hobbs) 2005-10-05 (bug fix)[979640] buffer overrun mixing putenv(), ::env (bold,hobbs) 2005-10-13 (bug fix)[1284178] [format] accept all integer values (porter) 2005-10-22 (bug fix)[1251791] optimization exposed wide/int difference(sofer) 2005-10-23 (bug fix)[1334947] value refcount error in var setting (sofer) 2005-11-01 (bug fix)[1337941] Tcl_TraceCommand() -> crash (devilliers,porter) 2005-11-03 (new Win NT/XP feature) Unicode console support (kovalenko,thoyts) 2005-11-03 (bug fix)[1201171] [encoding system] in Tclkit (schekin,porter) 2005-11-04 (bug fix)[1337229,1338280] [namespace delete] / unset traces (porter) 2005-11-04 (enhancement) Korean timezone abbreviations (kenny) 2005-11-04 (bug fix)[1317477] double encoding of time zone (kenny) 2005-11-04 (Win enhancement)[1267871] extended exit codes (newman,thoyts) 2005-11-04 (platform support)[1163896] LynxOS [load] (heidibr) 2005-11-08 (bug fix)[1348775] unset trace memory leak (sofer) 2005-11-08 (bug fix)[1162286] [package ifneeded] warns reported (lavana,porter) *** POTENTIAL INCOMPATIBILITY *** 2005-11-09 (bug fix)[1350293] [after $negative $script] fixed (kenny) 2005-11-15 (Win bug fix)[926016,1353840] correct [file mtime] (kenny) 2005-11-18 (bug fix)[1358369] URL parsing standards compliance (wu,fellows) 2005-11-18 (bug fix)[1359094] Tclkit crash (thoyts, kupries) 2005-11-18 (bug fix)[1355942,1355342] cmd delete trace/ namespace delete (sofer) 2005-11-20 (bug fix)[1091431] Tcl_InitStubs failure crashes wish (english) 2005-11-29 (bug fix)[1366683] [lsearch -regexp] backrefs (cleverly,fellows) 2005-11-29 (enhancement)[1369597] Win 64: --enable-64bit=amd64|ia64 (hobbs) 2005-12-05 (Darwin bug fix)[1034337] NFS recursive file delete (steffen) --- Released 8.4.12, December 3, 2005 --- See ChangeLog for details --- 2005-12-09 (bug fix)[1374778] [lsearch -start $pastEnd] => -1 (fellows) 2005-12-12 (bug fix)[1241572] correct [expr abs($LONG_MIN)] again (max) 2005-12-12 (bug fix)[1377619] configure syntax error exposed in bash-3.1 (hobbs) 2006-01-09 (bug fix)[1400572] [info level $l] => "namespace inscope" (porter) 2006-01-23 (bug fix)[1410553] Tcl_GetRange Unicode confusion (twylite,spjuth) 2006-03-06 (bug fix)[1439836,1444291] fix TCL_EVAL_{GLOBAL,INVOKE} handling when auto-loading or exec traces are present (porter) 2006-03-10 (bug fix)[1437595] Win socket finalize with threads (vasiljevic) 2005-03-13 (revert 2005-07-26 change) ${prefix}/share on ::tcl_pkgPath (porter) 2006-03-14 (bug fix)[1381436,859820] threadsafe Tcl_WaitPid (gravereaux,kupries) 2006-03-14 (bug fix)[768659] pipeline error when last command missing (kupries) 2006-03-18 (bug fix)[1193497] Win porting of [file writable] (darley,vogel) 2006-03-28 (bug fix)[1064247] BSD: path normalization with realpath() (steffen) 2006-03-28 (revert 2005-11-03 feature) Unicode console support (hobbs) *** POTENTIAL INCOMPATIBILITY *** 2006-04-03 (bug fix)[1462248] crash reading utf-8 chars spanning multiple buffers at end of file (kraft,kupries) 2006-04-04 (revert 2005-11-08)[1162286] [package ifneeded] warns (porter) *** POTENTIAL INCOMPATIBILITY *** 2006-04-05 (bug fix)[1464039] Tcl_GetIndexFromObj: empty key (fellows) 2006-04-05 (bug fix) overdue dde, registry patchelevel increments (porter) => dde 1.2.4 => registry 1.1.4 2006-04-06 (bug fix)[1457515] TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING removed (steffen) 2006-04-11 (bug fix)[1458266] enter/enterstep trace interference (leunissen) --- Released 8.4.13, April 19, 2006 --- See ChangeLog for details --- 2006-05-04 (bug fix)[1480509] srand() accept wide input (porter,afredd) 2006-05-05 (bug fix)[1481986] interactive Tcl_Main blocks main loop (porter,lin) 2006-05-13 (bug fix)[1482718] proc re-compile: preserve the previous bytecode while references still on the stack (porter,ryazanov) 2006-05-13 (bug fix)[943995] fixed [glob] on VFS (porter) 2006-05-27 (bug fix)[923072] Darwin: made unthreaded CoreFoundation notifier naked-fork safe on Tiger (steffen) 2006-05-31 (revert 2006-01-09)[1400572] namespace inscope & info level (porter) *** POTENTIAL INCOMPATIBILITY *** 2006-06-14 (platform support)[1424909] MS VS2005 support (thoyts) 2006-07-20 (platform support) Mac OS X weak linking (steffen) 2006-07-20 (bug fix) Darwin: execve() works iff event loop not yet run (steffen) 2006-08-18 (bug fix) intermittent failures in TclUnixWaitForFile() (steffen) 2006-08-18 (platform support) Darwin x86_64 (steffen) 2006-08-21 (bug fix)[1457797] Darwin 64-bit notifier hang (steffen) 2006-08-21 (bug fix) Darwin: recursively called event loop (steffen) 2006-08-30 (bug fix)[1548263] filesystem segfaults (hobbs,mccormack) 2006-09-06 (bug fix)[999544] use of MT-safe system calls (vasiljevic) 2006-09-10 (platform support) Darwin: msgcat use CFLocale (steffen) => msgcat 1.3.4 2006-09-22 (bug fix)[1562528] NULL terminates variadic calls (fellows,ryazanov) 2006-09-26 (platform support) MSVC8 AMD64 support (thoyts) 2006-10-05 (bug fix)[1570718] make [lappend $nonList] complain (sofer,virden) 2006-10-05 (bug fix)[1122671] alignment fixes in unicode encoding routines (hobbs,staplin) 2006-10-05 (new feature) [set ::http::strict 1] (default value is 0) to enable URL validity checking against RFC 2986 (hobbs) => http 2.5.3 --- Released 8.4.14, October 19, 2006 --- See ChangeLog for details --- 2006-10-31 (platform support)[1582769] Fix build with VC2003 (thoyts) 2006-11-07 (bug fix)[1586470] [file copy] on afs (kupries,dionizio) 2006-11-26 (platform support)[1230558] --enable-64bit on more systems (steffen) 2006-11-27 (bug fix)[1602208] use > 32 async sockets on 64bit system (fontaine) 2007-01-25 (configure change) ensure CPPFLAGS env var used when set (steffen) 2007-01-30 (enhancement) new target: `install-private-headers` (hobbs, steffen) 2007-02-12 (bug fix)[1516109] escape encodings crossing chan buffers (dejong) 2007-03-01 (bug fix)[1671138] compiled [foreach {} x {}] hangs (fellows) 2007-03-10 (bug fix)[1675116] list shimmer crash in [lsort] (fellows) 2007-03-13 (bug fix)[1671087] list shimmer crash in [foreach] (porter) 2007-03-13 (bug fix)[1669489] list shimmer crash in [array set] (porter) 2007-03-17 (bug fix)[1682211] buffer overflow in [registry keys] (kenny) => registry 1.1.5 2007-04-29 (bug fix) fts_open() crash on 64bit Darwin 8 or earlier (steffen) --- Released 8.4.15, May 25, 2007 --- See ChangeLog for details --- 2007-05-29 (bug fix)[1712723] Joinable thread death on 64-bit (virden,hobbs) 2007-06-06 (platform support) Darwin: add plist to tclsh (steffen) 2007-06-23 (bug fix) Darwin: prevent post-fork() abort() (steffen) 2007-06-27 (bug fix)[1743941] Infinite loop in Tcl_CreateTrace traces (porter) 2007-06-29 (enhancement) Tcl_Alloc alignment on Darwin (steffen) 2007-06-30 (bug fix)[1726873] crash in thread sync objects (vasiljevic,twylite) 2007-07-05 (bug fix)[1743676] no command named "" error message (porter,virden) 2007-08-14 (platform support) Darwin [load] from VFS on intel & 64bit (steffen) 2007-08-25 (bug fix)[1751117] [clock format ... %c] buffer overrun (kenny) 2007-09-10 (bug fix)[1740631] Linked variable unlink prevention (maros,hobbs) 2007-09-11 (platform support) Windows AMD64 support (thoyts) 2007-09-11 (bug fix)[1772989,1071322] Support _, : in test constraints (porter) => tcltest 2.2.9 2007-09-14 (enhancement)[1793984] DTrace provider for Tcl (steffen) 2007-09-15 (platform support) SunOS-5.1x link with cc, not ld (steffen) --- Released 8.4.16, September 21, 2007 --- See ChangeLog for details --- 2007-10-03 (bug fix) Corrected find of deleted command (sofer,neumann) 2007-10-15 (bug fix)[1813528] Tcl_ParseBraces read past buffer (mistachkin) 2007-10-30 (bug fix)[1810264] stop panic in RE lexer (fellows) 2007-11-15 (bug fix)[1810038] infinite loop in RE compiler (lane,porter) 2007-11-27 (bug fix)[1823552] encoding conversion for [info hostname] (porter) 2007-12-05 (bug fix)[1844789] fix [lsearch -exact -integer] crash (fellows) 2007-12-13 (bug fix)[1773127] corrected open mode "a+" (rottman,fellows) 2007-12-18 (bug fix)[1810264] revised regexp engine to prevent debilitating over-consumption of resources (drewry,lane,ormandy,fellows) --- Released 8.4.17, January 4, 2008 --- See ChangeLog for details --- 2008-01-13 (bug fix)[1353846] crash in read-only serial (hobbs,newman) 2008-01-30 (bug fix)[1882373] fix Tcl_GetAlias pointer code (an00na) --- Released 8.4.18, February 8, 2008 --- See ChangeLog for details --- 2008-02-22 (bug fix)[1818565] missing state array in http::status (thoyts) => http 2.5.4 2008-02-26 (bug fix) possible crash in [gets] (hobbs) 2008-02-26 (new feature) [http::meta] command (thoyts) => http 2.5.5 2008-03-07 (bug fix)[1899164] Avoid expr and script bytecode confusion (porter) 2008-03-24 (bug fix)[1923966] crash in [binary format x0s] (thoyts) 2008-03-27 (platform support)[1921166] Solaris 64bit build fixes (steffen) 2008-04-04 (bug fix)[780533] [fcopy -size -command] callback failure (ferrieux) 2008-04-07 (new feature)[1350564] eased fileevent constraints during [fcopy] (ferrieux) 2008-04-10 (bug fix)[1557855] crash on some [fcopy -size] values (ferrieux) --- Released 8.4.19, April 18, 2008 --- See ChangeLog for details --- 2008-05-23 (bug fix)[1965787] 32-bit overflow in [tell] result (ferrieux) 2008-06-12 (platform support) Solaris static build with DTrace (steffen) 2008-06-12 (platform support) Solaris/amd64 gcc 64bit support (steffen) 2008-06-23 (bug fix)[1972879] bad path intrep caching (porter) 2008-07-03 (bug fix)[1969717] fix package finding on Samba shares (jos) 2008-12-02 (bug fix)[2270477] hang in channel finalization (ferrieux,kupries) 2008-12-04 (bug fix)[2385549] [file normalize] failed on some paths (porter) 2009-02-20 (bug fix)[2571597] [file pathtype /a] wrong result (nadkarni,porter) 2009-03-18 (bug fix)[2688184] memleak in [file normalize] (mistachkin) 2009-03-20 (bug fix)[2597185] crash in Tcl_AppendStringToObj (porter) 2009-03-27 (bug fix)[2710920] [file dirname|tail /foo/] errors (epler,porter) 2009-03-30 (bug fix)[2603158] Tcl_AppendObjToObj: append to self crash (porter) 2009-04-07 (bug fix)[2494093,2553906] string overflow (porter) 2009-04-08 (bug fix)[2570363] unsafe [eval]s in tcltest (bron,porter) => tcltest 2.2.10 2009-04-27 (bug fix)[2446662] uniformly declare EOF on RST on sockets (ferrieux) 2009-04-27 (bug fix)[1028264] delay WSACleanup() from under our feet (ferrieux) 2009-06-13 (bug fix)[2802881] corrected compile env context (tasada,porter) 2009-07-23 (bug fix)[2820349] plug event leak in notifier (mistachkin) 2009-08-21 (bug fix)[2837800] [glob */foo] return ./~x/foo (porter) 2009-10-04 (bug fix)[2569449] Core Foundation memory bug in Tiger (steffen) 2009-10-21 (bug fix)[2882561] Haiku OS signal support (morrison,fellows) 2009-11-12 (bug fix)[2895565] [fcopy -size] miscounts when converting encodings (kupries) 2009-11-16 (bug fix)[2891556] encoding finalization crash (mistachkin,ferrieux) 2010-02-01 (bug fix)[2942697] faster match: some pathological regexp patterns (lane,fellows) 2010-02-11 (bug fix)[2954959] get sign of abs($zero) right (nijtmans) 2010-06-28 (bug fix)[3019634] support errno.h changes in MSVC++ 2010 (nijtmans) 2010-09-01 (bug fix)[3057639] no read traces [lappend arr(elem) ...] (hobbs) *** POTENTIAL INCOMPATIBILITY *** 2010-09-24 (bug fix)[3056775] race condition in Win sockets (twylite,kupries) 2010-10-23 (update)[3085863] Update Unicode data to 6.0 (nijtmans) 2010-11-03 (enhancement) Win [load] use LOAD_WITH_ALTERED_SEARCH_PATH (hobbs) *** POTENTIAL INCOMPATIBILITY *** 2011-03-06 (bug fix)[3200987,3192636] parser buffer overruns (porter) 2011-04-13 (bug fix)[2662380] crash when variable append trace unsets (sofer) 2011-08-15 (bug fix)[3390272] leak of [info script] value (porter) 2011-08-18 (bug fix)[3393714] [string toupper] overflow (nijtmans) 2011-09-13 (bug fix)[3390638] solaris studio cc workaround (kechel,porter) 2011-09-13 (bug fix)[3405652] DTrace workaround (michelson,porter) 2011-10-11 (bug fix)[2935503] [file stat] returns bad mode (nadkarni,nijtmans) 2011-11-22 (bug fix)[3354324] Win: [file mtime] sets wrong time (nijtmans) 2011-12-07 (bug fix)[3444754] fix [string tolower \u01C5] (nijtmans) 2011-12-24 (bug fix)[3464428] fix [string is graph \u0120] (nijtmans) 2012-01-13 (bug fix)[3472316] fix retrieval of socket error (fellows) => http 2.5.6 2012-01-21 (bug fix)[3475667] [regexp] buffer read overflow (sebres) 2012-02-02 (bug fix)[2974459,2879351,1951574,1852572,1661378,1613456] Fix problems where [file *able] would return false results on Win/Samba (porter) 2012-02-02 (update)[3464401] Support Unicode 6.1 (nijtmans) 2012-02-06 (bug fix)[3484621] bump bytecode epoch on exec traces (kuhn,sofer) 2012-02-09 (bug fix)[3484402] mem corrupt OBOE in unicode append (porter) 2012-02-29 (bug fix)[3466099] BOM in Unicode (nijtmans) 2012-03-07 (bug fix)[3498327] RFC 3986 compliance (kupries) 2012-05-10 (bug fix)[473946] correct send of special characters (nijtmans) => dde 1.2.5 2012-06-29 (enhancement) Add tn, ro_MO, ru_MO to msgcat (nijtmans) => msgcat 1.3.5 2012-07-05 (bug fix)[1189293] make "<<" redirect binary safe (porter) 2012-07-25 (bug fix)[3546275] [auto_execok] search match [exec] (danckaert) 2012-07-27 (update)[3464401] Support Unicode 6.2 (nijtmans) 2012-10-03 (bug fix) exit panic on stacked std channel (griffin,porter) 2012-11-07 (bug fix)[3574493] hang in Windows socket finalization (fassel) 2012-11-13 (enhancement)[360894] Threads inherit floating point from creator. 2012-11-14 (enhancement)[2933003] compile setting: TCL_TEMPORARY_FILE_DIRECTORY 2012-12-03 (bug fix) tcltest: Correct legacy auto-init fom $::argv (porter) => tcltest 2.2.11 2012-12-27 (bug fix)[3598580] Tcl_ListObjReplace() refcount fix (nijtmans) 2013-01-08 (bug fix)[3092089,3587096] [file normalize] on junction points 2013-02-05 (bug fix)[3603434] [file normalize a:/] flaw in VFS (porter,griffin) 2013-02-19 (bug fix)[2438181] report errors in trace handlers (yorick) 2013-02-21 (bug fix)[3605447] unbreak [namespace export -clear] (porter) 2013-02-27 (bug fix)[3606139] stop crash in [regexp] (lane) 2013-03-06 (bug fix)[3606683] [regexp (((((a)*)*)*)*)* {}] hangs (grathwohl,lane,porter) 2013-03-12 (enhancement) better build support for Debian arch (shadura) 2013-03-19 (bug fix)[2893771] [file stat] on locked files (thoyts,nijtmans) 2013-04-08 (bug fix)[3610026] regexp surplus colors crash (linnakangas) 2013-04-09 (bug fix) Allow http://example.com?foo=bar (max) => http 2.5.8 Updated packages: dde 1.3.3, registry 1.2.2. New package: platform 1.0.12 --- Released 8.4.20, June 1, 2013 --- See ChangeLog for details --- tcl8.4.20/ChangeLog0000644003604700454610000161115412151137576012500 0ustar dgp771div2013-06-01 Don Porter *** 8.4.20 TAGGED FOR RELEASE *** * README: Bump version number to 8.4.20 * generic/tcl.h: * tools/tcl.wse.in: * unix/configure.in: * unix/tcl.spec: * win/README.binary: * win/configure.in: * unix/configure: autoconf-2.13 * win/configure: * changes: updates for 8.4.20 release. 2013-05-19 Jan Nijtmans * unix/tcl.m4: Fix for FreeBSD, and remove support for older * unix/configure: FreeBSD versions. Patch by Pietro Cerutti. 2013-05-16 Jan Nijtmans * generic/tclBasic.c: Add panic in order to detect incompatible mingw32 sys/stat.h and sys/time.h headers, 2013-05-06 Jan Nijtmans * generic/tclStubInit.c: Add support for Cygwin64, which has a 64-bit * generic/tclDecls.h: "long" type. Binary compatibility with win64 requires that all stub entries use 32-bit long's, therefore the need for various wrapper functions/macros. For Tcl 9 a better solution is needed, but that cannot be done without introducing binary incompatibility. 2013-04-30 Andreas Kupries * library/platform/platform.tcl (::platform::LibcVersion): * library/platform/pkgIndex.tcl: Followup to the 2013-01-30 change. The RE become too restrictive again. SuSe added a timestamp after the version. Loosened up a bit. Bumped package to version 1.0.12. 2013-04-25 Jan Nijtmans * win/tclWinDde.c: Update dde to version 1.3.3. * library/dde/pkgIndex.tcl: * win/tclWinReg.c: Update registry to version 1.2.2. * library/reg/pkgIndex.tcl: 2013-04-18 Jan Nijtmans * generic/tclDecls.h: Implement Tcl_Pkg* functions as (faster/stack-saving) macros around Tcl_Pkg*Ex functions. The same for many Tcl_*Var* functions around their Tcl_*Var*2 equivalent and Tcl_GetIndexFromObj around Tcl_GetIndexFromObjStruct. 2013-04-09 Reinhard Max * library/http/http.tcl (http::geturl): Allow URLs that don't have a path, but a query query, e.g. http://example.com?foo=bar . * Bump the http package to 2.5.8. 2013-04-08 Don Porter * generic/regc_color.c: [Bug 3610026] Stop crash when the number of * generic/regerrs.h: "colors" in a regular expression overflows * generic/regex.h: a short int. Thanks to Heikki Linnakangas * generic/regguts.h: for the report and the patch. * tests/regexp.test: 2013-03-19 Don Porter * generic/tclFCmd.c: [Bug 3597000] Consistent [file copy] result. 2013-03-19 Jan Nijtmans * win/tclWinFile.c: [Bug 2893771]: file stat fails on locked files on win32. 2013-03-18 Donal K. Fellows * tests/cmdAH.test (cmdAH-19.12): [Bug 3608360]: Added test to ensure that we never ever allow [file exists] to do globbing. 2013-03-12 Jan Nijtmans * unix/tcl.m4: Patch by Andrew Shadura, providing better support for three architectures they have in Debian. 2013-03-06 Don Porter * generic/regc_nfa.c: [Bugs 3604074,3606683] Rewrite of the * generic/regcomp.c: fixempties() routine (and supporting routines) to completely eliminate the infinite loop hazard. Thanks to Tom Lane for the much improved solution. 2013-03-04 Don Porter * generic/tclUtil.c: New scheme for keeping the per-process tcl_precision value in sync without the need for mutex locks on every read. Uses adapted ProcessGlobalValue machinery backported from Tcl 8.5 where it's been working without reported problems. Thanks to Phil Brooks for reporting on tests which highlight the thread performance problems raised by the old scheme, and to Clif Flynt for further testing pointing the finger at tcl_precision locks as the main culprit. 2013-02-27 Jan Nijtmans * generic/regcomp.c: [Bug 3606139]: missing error check allows * tests/regexp.test: regexp to crash Tcl. Thanks to Tom Lane for providing the test-case and the patch. 2013-02-22 Don Porter * generic/tclCompile.c: Shift more burden of smart cleanup onto the * generic/tclExecute.c: TclFreeCompileEnv() routine. Stop crashes when the hookProc raises an error. 2013-02-20 Don Porter * generic/tclNamesp.c: [Bug 3605447] Make sure the -clear option * tests/namespace.test: to [namespace export] always clears, whether or not new export patterns are specified. 2013-02-15 Don Porter * generic/regc_nfa.c: [Bug 3604074] Fix regexp optimization to * tests/regexp.test: stop hanging on the expression ((((((((a)*)*)*)*)*)*)*)* . Thanks to BjУИrn Grathwohl for discovery. 2013-02-05 Don Porter * win/tclWinFile.c: [Bug 3603434] Make sure TclpObjNormalizePath() properly declares "a:/" to be normalized, even when no "A:" drive is present on the system. 2013-01-30 Andreas Kupries * library/platform/platform.tcl (::platform::LibcVersion): See * library/platform/pkgIndex.tcl: [Bug 3599098]: Fixed the RE extracting the version to avoid issues with recent changes to the glibc banner. Now targeting a less variable part of the string. Bumped package to version 1.0.11. 2013-01-26 Jan Nijtmans * unix/tclUnixCompat.c: [Bug 3601804]: platformCPUID segmentation fault on Darwin. 2013-01-16 Jan Nijtmans * Makefile.in: Enable win32 build with -DTCL_NO_DEPRECATED, just * generic/tcl.h: as the UNIX build. Define Tcl_EvalObj and * generic/tclDecls.h: Tcl_GlobalEvalObj as macros, even when * generic/tclBasic.c: TCL_NO_DEPRECATED is defined, so Tk can benefit from it too. 2013-01-08 Jan Nijtmans * win/tclWinFile.c: [Bug 3092089]: [file normalize] can remove path components. [Bug 3587096] win vista/7: "can't find init.tcl" when called via junction. 2013-01-07 Jan Nijtmans * generic/tcl.decls: Extend the public and private stub tables with * generic/tclInt.decls: dummy NULL entries, up to the size of the Tcl 8.6 stub tables. This makes it easier to debug extensions which use Tcl 8.5/8.6 features but (erroneously) are attempted to be loaded in Tcl 8.4. 2012-12-31 Donal K. Fellows * doc/string.n: Noted the obsolescence of the 'bytelength', 'wordstart' and 'wordend' subcommands, and moved them to later in the file. 2012-12-27 Jan Nijtmans * generic/tclListObj.c: [Bug 3598580]: Tcl_ListObjReplace may release deleted elements too early 2012-12-21 Jan Nijtmans * unix/dltest/pkgb.c: Turn pkgb.so into a Tcl9 interoperability test library: Whatever Tcl9 looks like, loading pkgb.so in Tcl 9 should either result in an error-message, either succeed, but never crash. * generic/tclStubLib.c: Eliminate unnessarcy static HasStubSupport() and isDigit() functions, just do the same inline. 2012-12-13 Jan Nijtmans * generic/tcl.h: Fix Tcl_DecrRefCount macro such that it doesn't access its objPtr parameter twice any more. 2012-11-14 Donal K. Fellows * unix/tclUnixPipe.c (DefaultTempDir): [Bug 2933003]: Allow overriding of the back-stop default temporary file location at compile time by setting the TCL_TEMPORARY_FILE_DIRECTORY #def to a string containing the directory name (defaults to "/tmp" as that is the most common default). 2012-11-07 Don Porter * win/tclWinSock.c: [Bug 3574493] Avoid hanging on exit due to use of synchronization calls in routines called by DllMain(). 2012-10-03 Don Porter * generic/tclIO.c: When checking for std channels being closed, compare the channel state, not the channel itself so that stacked channels do not cause trouble. 2012-08-17 Jan Nijtmans * win/nmakehlp.c: Add "-V" option, in order to be able to detect partial version numbers. 2012-07-31 Jan Nijtmans * win/nmakehlp.c: Backport from Tcl 8.6, but add -Q option from sampleextension. 2012-07-27 Jan Nijtmans * generic/tclUniData.c: Support Unicode 6.2 (Add Turkish lira sign) * generic/regc_locale.c: 2012-07-17 Jan Nijtmans * win/makefile.vc: [Bug 3544932]: Visual studio compiler check fails 2012-07-05 Don Porter * unix/tclUnixPipe.c: [Bug 1189293] Make "<<" binary safe. * win/tclWinPipe.c: 2012-06-29 Jan Nijtmans * library/msgcat/msgcat.tcl: Add tn, ro_MO and ru_MO to msgcat. Make it * library/msgcat/pkgIndex.tcl: work on cygwin. Bump to 1.3.5 2012-06-29 Donal K. Fellows * doc/GetIndex.3: Reinforced the description of the requirement for the tables of names to index over to be static, following posting to tcl-core by Brian Griffin about a bug caused by Tktreectrl not obeying this rule correctly. This does not represent a functionality change, merely a clearer documentation of a long-standing constraint. 2012-06-23 Jan Nijtmans * unix/tclUnixNotfy.c: [Bug 3508771]: Cygwin notifier for handling win32 events. 2012-06-19 Jan Nijtmans * win/tclWinReg.c: Plug memory leak, part of [Bug #3362446] 2012-06-08 Don Porter * unix/configure.in: Update autogoo for gettimeofday(). * unix/tclUnixPort.h: Thanks Joe English. * unix/configure: autoconf 2.13 2012-06-06 Jan Nijtmans * unix/tclUnixInit.c: On Cygwin, use win32 API in stead of uname() to determine the tcl_platform variables. 2012-05-25 Jan Nijtmans * win/tclWinDde.c: [Bug 473946]: special characters not correctly sent, now for XTYP_EXECUTE as well as XTYP_REQUEST. * win/Makefile.in: Fix "make genstubs" when cross-compiling on UNIX 2012-05-24 Jan Nijtmans * tools/genStubs.tcl: Take cygwin handling of X11 into account. * generic/tcl*Decls.h: re-generated * generic/tclStubInit.c: Implement TclpIsAtty, Cygwin only. * doc/dde.n: Doc fix: "dde execute iexplore" doesn't work without -async, because iexplore doesn't return a value 2012-05-22 Jan Nijtmans * tools/genStubs.tcl: Let cygwin share stub table with win32 * win/Makefile.in: Don't hardcode dde and reg dll version numbers * win/tclWinSock.c: implement TclpInetNtoa for win32 * generic/tclInt.decls: Revert most of [ae92de6078], since when we let cygwin share the win32 stub table this is no longer necessary * generic/tcl*Decls.h: re-generated 2012-05-21 Don Porter * generic/tclFileName.c: When using Tcl_SetObjLength() calls to grow * generic/tclIOUtil.c: and shrink the objPtr->bytes buffer, care must be taken that the value cannot possibly become pure Unicode. Calling Tcl_AppendToObj() has the possibility of making such a conversion. Bug found while valgrinding the trunk. 2012-05-17 Donal K. Fellows * doc/expr.n: [Bug 3525462]: Corrected statement about what happens when comparing "0y" and "0x12"; the previously documented behavior was actually a subtle bug (now long-corrected). 2012-05-13 Jan Nijtmans * win/tclWinDde.c: Protect against receiving strings without ending \0, as external applications (or Tcl with TIP #106) could generate that. 2012-05-10 Jan Nijtmans * win/tclWinDde.c: [Bug 473946]: special characters not correctly sent * library/dde/pkgIndex.tcl Increase version to 1.2.5 2012-05-02 Jan Nijtmans * generic/configure.in: Better detection and implementation for cpuid * generic/configure: instruction on Intel-derived processors, both * generic/tclUnixCompat.c: 32-bit and 64-bit. * generic/tclTest.c: Move cpuid testcase from win-specific to generic * win/tclWinTest.c: tests, as it should work on all Intel-related * tests/platform.test: platforms now * generic/tcl.decls: Simplify stub tables for functions which work on * generic/tclInt.decls: both UNIX and windows, as in Tcl 8.5 and 8.6 * generic/tcl*Decls.h: 2012-04-27 Donal K. Fellows * library/init.tcl (auto_execok): Allow shell builtins to be detected even if they are upper-cased. 2012-04-24 Jan Nijtmans * generic/tclInt.decls: [Bug 3508771] load tclreg.dll in cygwin tclsh * generic/tclIntPlatDecls.h: Implement TclWinGetSockOpt, TclWinGetServByName * generic/tclStubInit.c: and TclWinCPUID for Cygwin * generic/tclUnixCompat.c: * unix/configure.in: * unix/configure: * unix/tclUnixCompat.c: 2012-04-16 Donal K. Fellows * doc/FileSystem.3 (Tcl_FSOpenFileChannelProc): [Bug 3518244]: Fixed documentation of this filesystem callback function; it must not register its created channel - that's the responsibility of the caller of Tcl_FSOpenFileChannel - as that leads to reference leaks. 2012-04-11 Jan Nijtmans * win/tclWinInit.c: [Bug 3448512]: clock scan "1958-01-01" fails only * win/tcl.m4: in debug compilation. * win/configure: * unix/tcl.m4: Use NDEBUG consistantly meaning: no debugging. * unix/configure: 2012-04-04 Jan Nijtmans * win/tclWinSock.c: [Bug 510001]: TclSockMinimumBuffers needs plat imp * generic/tclIOSock.c: * generic/tclInt.decls: * generic/tclIntDecls.h: * generic/ttclStubInit.c: 2012-04-03 Jan Nijtmans * tools/genStubs.tcl: Let genStubs.tcl do the void -> VOID and const -> CONST translations, so we cannot forget it in the *.decls file * generic/tcl.decls: VOID -> void and CONST -> const, so depend * generic/tclInt.decls: on genStubs.tcl to generate the correct form form in the *Decls.h file. This brings tclInt.decls in the same form as Tcl 8.5/8.6, so a diff can show us the real signature differences. (Backported from Tcl 8.5, no change in any function signature) * generic/tclStubInit.c Remove the TclpGetTZName implementation for * generic/tclIntDecls.h: Cygwin (from previous commit) , re-generated * generic/tclIntPlatDecls.h: * generic/tclDecls.h 2012-03-30 Jan Nijtmans * generic/tclInt.decls: [Bug 3508771] load tclreg.dll in cygwin tclsh * generic/tclIntPlatDecls.h: Implement TclWinGetTclInstance, TclpGetTZName, * generic/tclStubInit.c: and various more win32-specific internal functions for Cygwin, so win32 extensions using those can be loaded in the cygwin version of tclsh. 2012-03-29 Jan Nijtmans * unix/tcl.m4: [Bug 3511806] Compiler checks too early * unix/configure.in: This change allows to build the cygwin * unix/configure: and mingw32 ports of Tcl/Tk to build * win/tcl.m4: out-of-the-box using a native or cross- * win/configure.in: compiler. * win/configure: 2012-03-27 Jan Nijtmans * generic/tcl.h: [Bug 3508771] Wrong Tcl_StatBuf used on MinGW * generic/tclFCmd.c: [Bug 2015723] duplicate inodes from file stat on windows 2012-03-24 Jan Nijtmans * generic/tclInt.decls: [Bug 3508771] load tclreg.dll in cygwin tclsh * generic/tclIntPlatDecls.h: Implement TclWinConvertError, TclWinConvertWSAError, * generic/tclStubInit.c: and various more win32-specific internal functions for * unix/Makefile.in: Cygwin, so win32 extensions using those can be * unix/tcl.m4: loaded in the cygwin version of tclsh. * unix/configure: * win/tclWinError.c: 2012-03-20 Jan Nijtmans * generic/tcl.h: [Bug 3288345] Wrong Tcl_StatBuf used on Cygwin * unix/tclUnixFile.c * unix/tclUnixPort.h * win/tclWinFile.c Remove cygwin stuff no longer needed * win/tclWinPort.h * generic/tcl.decls: [Bug 3508771] load tclreg.dll in cygwin tclsh * generic/tclInt.decls: Implement TclWinGetPlatformId, Tcl_WinUtfToTChar, * generic/tclIntPlatDecls.h: Tcl_WinTCharToUtf (and a dummy TclWinCPUID) for * generic/tclPlatDecls.h: Cygwin, so win32 extensions using those can be * generic/tclStubInit.c: loaded in the cygwin version of tclsh. * unix/tclUnixCompat.c: 2012-03-12 Jan Nijtmans * win/tclWinFile.c: [Bug 3388350] mingw64 compiler warnings 2012-03-07 Andreas Kupries * library/http/http.tcl: [Bug 3498327]: Generate upper-case * library/http/pkgIndex.tcl: hexadecimal output for compliance * tests/http.test: with RFC 3986. Bumped version to 2.5.7. 2012-03-06 Jan Nijtmans * win/tclWinPort.h: Compatibility with older Visual Studio versions. 2012-03-04 Alexandre Ferrieux * unix/tclUnixChan.c: TclUnixWaitForFile(): use FD_* macros * macosx/tclMacOSXNotify.c: to manipulate select masks (Cassoff). [Bug 3486554]. Backport of das' checkin [e496f9ef50]. Allows Tcl8.4 to have sane fileevents on x86_64 at last. 2012-03-04 Jan Nijtmans * generic/tclLoad.c: Patch from the cygwin folks * unix/tcl.m4: * unix/configure: (re-generated) 2012-02-29 Jan Nijtmans * generic/tclIOUtil.c: [Bug 3466099] BOM in Unicode * generic/tclEncoding.c: * tests/source.test 2012-02-09 Don Porter * generic/tclStringObj.c: [Bug 3484402] Correct Off-By-One error appending unicode. Thanks to Poor Yorick. Also corrected test for when growth is needed. 2012-02-06 Don Porter * generic/tclCmdMZ.c: [Bug 3484621] Invalidate bytecode when exec * tests/trace.test: traces are added/removed from compiled cmd. 2012-02-02 Jan Nijtmans * generic/tclUniData.c: [Frq 3464401] Support Unicode 6.1 * generic/regc_locale.c: 2012-02-02 Don Porter * win/tclWinFile.c: [Bugs 2974459,2879351,1951574,1852572, 1661378,1613456]: Revisions to the NativeAccess() routine that queries file permissions on Windows native filesystems. Meant to fix numerous bugs where [file writable|readable|executable] "lies" about what operations are possible, especially when the file resides on a Samba share. Patch cherrypicked off the fix-win-native-access branch. 2012-01-22 Jan Nijtmans * tools/uniClass.tcl: [Frq 3473670]: Various Unicode-related * tools/uniParse.tcl: speedups/robustness. Enhanced tools to * generic/tclUniData.c: be able to handle characters > 0xffff * generic/tclUtf.c: Done in all branches in order to simplify * generic/regc_locale.c: merges for new Unicode versions (such as 6.1) 2012-01-19 Jan Nijtmans * generic/tcl.h: [Bug-3474726]: Eliminate detection of struct * generic/tclWinPort.h: _stat32i64, just use _stati64 in combination * generic/tclFCmd.c: with _USE_32BIT_TIME_T, which is the same then. * generic/tclTest.c: Only keep _stat32i64 usage for cygwin, so it * win/configure.in: will not conflict with cygwin's own struct stat. * win/configure: 2012-01-19 Don Porter * generic/tclCmdMZ.c: [Bug 3475667] Prevent buffer read overflow. Thanks to "sebres" for the report and fix. 2012-01-17 Don Porter * library/http/http.tcl: Bump to 2.5.6. * library/http/pkgIndex.tcl: 2012-01-13 Donal K. Fellows * library/http/http.tcl (http::Connect): [Bug 3472316]: Ensure that we only try to read the socket error exactly once. 2012-01-09 Jan Nijtmans * generic/tclUtf.c: [Bug 3464428] string is graph \u0120 is wrong * generic/regcomp.c: Remove some unused code * generic/regc_locale.c: Add table for Unicode [:cntrl:] class * tools/uniClass.tcl: Generate Unicode [:cntrl:] class table * tests/utf.test: * doc/re_syntax: Fix [:print:] class description 2011-12-23 Jan Nijtmans * generic/tclUtf.c: [Bug 3464428] string is graph \u0120 is wrong * generic/tclUniData.c: * generic/regc_locale.c: * tests/utf.test: * tools/uniParse.tcl: clean up some unused stuff, and be more robust against changes in UnicodeData.txt syntax 2011-12-07 Jan Nijtmans * tools/uniParse.tcl: [Bug 3444754] string tolower \u01c5 is wrong * generic/tclUniData.c: * tests/utf.test: 2011-11-30 Jan Nijtmans * library/tcltest/tcltest.tcl: [Bug 967195]: Make tcltest work when tclsh is compiled without using the setargv() function on mingw. (no need to incr the version, since 2.2.10 is never released) 2011-11-29 Jan Nijtmans * doc/tclsh.1: Use the same shebang comment everywhere. * tools/str2c * tools/tcltk-man2html.tcl 2011-11-22 Jan Nijtmans * generic/tclCmdAH.c: [Bug 3354324] Windows: file mtime * generic/tclIOUtil.c: sets wrong time 2011-10-11 Jan Nijtmans * win/tclWinFile.c: [Bug 2935503] Incorrect mode field returned by file stat command 2011-10-07 Jan Nijtmans * win/tclWinChan.c: Fix various gcc warnings * win/tclWinConsole.c: (discovered with latest * win/tclWinNotify.c: mingw, based on gcc 4.6.1) * win/tclWinReg.c: * tests/env.test: Fix env.test, when running under wine 1.3 (partly backported from Tcl 8.6) 2011-09-26 Jan Nijtmans * win/rules.vc: Support Visual Studio 11 2011-09-16 Jan Nijtmans * generic/tcl.h: Don't change Tcl_UniChar type when * generic/regcustom.h: TCL_UTF_MAX == 4 (not supported anyway) 2011-09-13 Don Porter * generic/tclUtil.c: [Bug 3390638] Workaround broken solaris studio cc optimizer. Thanks to Wolfgang S. Kechel. * generic/tclDTrace.d: [Bug 3405652] Portability workaround for broken system DTrace support. Thanks to Dagobert Michelson. 2011-09-12 Jan Nijtmans * win/tclWinPort.h: [Bug 3407070] tclPosixStr.c won't build with EOVERFLOW==E2BIG 2011-09-06 Jan Nijtmans * generic/tcl.decls: Tcl_HashStats does not return a CONST * generic/tclDecls.h: (Backported from Tcl 8.5) * generic/tclHash.c: * generic/tclVar.c: * unix/tcl.m4: Add --disable-rpath option to configure * unix/configure: script (backported from Tcl 8.5) 2011-08-30 Jan Nijtmans * unix/tcl.m4: Make SHLIB_LD_LIBS='${LIBS}' the default and * unix/configure: set to "" on per-platform necessary basis. Add Haiku support and better NetBSD/FreeBSD support. All of this backported from TEA resp. Tcl8.5, but kept all original platform code which was removed from TEA. 2011-08-22 Andreas Kupries * win/tclWinDde.c (Tcl_DdeObjCmd): Fixed use of the C99 feature (Variable declaration within statement block) rejected by MSVC6. Moved the declaration to the beginning of the block. 2011-08-18 Jan Nijtmans * generic/tclUniData.c: [Bug 3393714] overflow in toupper delta * tools/uniParse.tcl * tests/utf.test 2011-08-16 Jan Nijtmans * generic/tclCmdAH.c: [Bug 3388350] mingw64 compiler warnings * generic/tclFCmd.c In mingw, sys/stat.h must be included * generic/tclFileName.c before winsock2.h, so make sure of that. * generic/tclIOUtil.c * generic/tclTest.c * win/tclWin32Dll.c * win/tclWinChan.c * win/tclWinDde.c * win/tclWinFCmd.c 2011-08-15 Don Porter * generic/tclBasic.c: [Bug 3390272] Leak of [info script] value. 2011-08-15 Jan Nijtmans * win/tcl.m4: [Bug 3388350] mingw64 compiler warnings * win/configure.in * win/configure * win/tclMtherr.c * win/tclWinPort.h * win/tclWinChan.c * win/tclWinDde.c * win/tclWinFCmd.c * win/tclWinPipe.c * win/tclWinReg.c * win/tclWinSerial.c * win/tclWinSock.c * win/tclWinTest.c * win/tclWinTime.c * generic/tclPosixStr.c * unix/tcl.m4: Quoting and AC_DEFINE fixes (All backported from * unix/configure Tcl 8.5 2011-07-21 Jan Nijtmans * win/tclWinPort.h: [Bug 3372130] Fix hypot math function with MSVC10 2011-07-15 Don Porter * generic/tclCompile.c: Avoid segfaults when RecordByteCodeStats() is called in a deleted interp. 2011-07-13 Don Porter * generic/tclProc.c: [Bug 3366265] Buffer for storing the command * tests/indexObj.test: name formatted as a list element is allocated * tests/proc.test: one byte too small, causing buffer overflow when the proc with the empty name raises a "wrong num args" error. 2011-07-03 Donal K. Fellows * doc/FileSystem.3: Corrected statements about ctime field of 'struct stat'; that was always the time of the last metadata change, not the time of creation. 2011-06-22 Andreas Kupries * library/platform/pkgIndex.tcl: Updated to platform 1.0.10. Added * library/platform/platform.tcl: handling of the DEB_HOST_MULTIARCH location change for libc. 2011-05-07 Miguel Sofer * generic/tclInt.h: fix USE_TCLALLOC so that it can be enabled * unix/Makefile.in: without editing the Makefile 2011-04-21 Don Porter * generic/tclCompile.c: Make sure SetFooFromAny routines react * generic/tclIndexObj.c: reasonably when passed a NULL interp. * generic/tclNamesp.c: * generic/tclObj.c: 2011-04-21 Jan Nijtmans * generic/tcl.h: fix for [Bug 3288345]: Wrong Tcl_StatBuf * generic/tclInt.h: used on MinGW. Make sure that all _WIN32 * generic/tclIOUtil.c: compilers use exactly the same layout * win/tclWinFile.c: for Tcl_StatBuf - the one used by MSVC6 - * win/configure.in: in all situations. * win/configure: 2011-04-20 Andreas Kupries * tests/info.test: Fixed the shift in line numbers used for testing 'info frame' introduced by checkin [79367df0f0] (Mar 2, 2011). 2011-04-13 Miguel Sofer * generic/tclVar.c: fix for [Bug 2662380], crash caused by appending to a variable with a write trace that unsets it. 2011-04-04 Don Porter * README: Updated README files, repairing broken URLs and * macosx/README: removing other bits that were clearly wrong. * unix/README: Still could use more eyeballs on the detailed build * win/README: advice on various plaforms. [Bug 3202030] 2011-03-25 Jan Nijtmans * generic/tclHash.c: [Bug 3007895]: Tcl_(Find|Create)HashEntry stub entries can never be called. They still cannot be called (no change in functionality), but at least they now do exactly the same as the Tcl_(Find|Create)HashEntry macro's, so the confusion addressed in this Bug report is gone. Merged --cherrypick from Tcl8.5 (2010-12-31,e75735ef76) 2011-03-24 Donal K. Fellows * generic/tclFCmd.c (TclFileAttrsCmd): Ensure that any reference to temporary index tables is squelched immediately rather than hanging around to trip us up in the future. 2011-03-16 Jan Nijtmans * unix/configure, unix/tcl.m4: SHLIB_LD_LIBS='${LIBS}' for OSF1-V*. Add /usr/lib64 to set of auto-search dirs. [Bug 1230554] (SC_PATH_X): Correct syntax error when xincludes not found. Backported from Tcl 8.5 * generic/tclCkalloc.c: [Bug #3197864] pointer truncation on Win64 TCL_MEM_DEBUG builds 2010-03-11 Jan Nijtmans * win/tclWin32Dll.c: #ifdef protections to permit builds with * win/tclWinChan.c: mingw on amd64 systems. Thanks to "mescalinum" * win/tclWinFCmd.c: for reporting and testing. Merged --cherrypick from Tcl8.5 (2010-09-08,48191d3979) 2011-03-11 Jan Nijtmans * win/tcl.m4: handle --enable-64bit=ia64 for gcc. * win/configure: (autoconf-2.13) * win/tclWin32Dll.c: [Patch 3059922]: fixes for mingw64 - gcc4.5.1 Merged --cherrypick from Tcl8.5 (2011-01-17, 6e410a115b) 2011-03-08 Jan Nijtmans * generic/tclBasic.c: Fix gcc warnings: variable set but not used 2011-03-06 Don Porter * generic/tclBasic.c: More replacements of Tcl_UtfBackslash() calls * generic/tclCmdMZ.c: with TclParseBackslash() where possible. * generic/tclCompExpr.c: * generic/tclCompile.c: * generic/tclUtil.c (TclFindElement): Guard escape sequence scans to not overrun the string end. [Bug 3192636] 2011-03-05 Don Porter * generic/tclParse.c (TclParseBackslash): Correct trunction checks in * tests/parse.test: \x and \u substitutions. [Bug 3200987] 2011-01-25 Jan Nijtmans * generic/tclCkalloc.c: [Bug 3129448]: Possible over-allocation on 64-bit * generic/tclHash.c: platforms, part 2, backported strcpy->memcpy * generic/tclProc.c change but not change in any struct. 2011-01-14 Jan Nijtmans * win/tclWinDde.c: Fix gcc-4.5.2 error: lvalue required as ... * win/tclWinReg.c: (backported from 8.5/8.6) 2010-12-05 Jan Nijtmans * generic/tclCmdMZ.c: [Bug 3127687] Triggers FORTIFY_SOURCE buffer overflow detection 2010-11-03 Jeff Hobbs Backported from 8.6 (see 2010-08-04). * win/tclWin32Dll.c (asciiProcs, unicodeProcs): * win/tclWinLoad.c (TclpDlopen): 'load' use LoadLibraryEx with * win/tclWinInt.h (TclWinProcs): LOAD_WITH_ALTERED_SEARCH_PATH to prefer dependent DLLs in same dir as loaded DLL. 2010-10-31 Jan Nijtmans * win/tcl.m4 Add -D_CRT_SECURE_NO_DEPRECATE and -D_CRT_NONSTDC_NO_DEPRECATE, reducing the number of deprecation warnings on later VC++ versions. * win/rules.vc Better VCVERSION determination * win/configure (regenerated with autoconf 2.13) All changes backported from Tcl8.5/8.6 2010-10-23 Jan Nijtmans * tools/uniParse.tcl: [Bug 3085863]: tclUniData 9 years old * tools/uniClass.tcl: Upgrade everything to Unicode 6.0, except * tests/utf.test: non-BMP characters > 0xFFFF * generic/tclUniData.c: (re-generated) * generic/regc_locale.c:(re-generated) * generic/regcomp.c: fix comment/signatures referencing regc_locale * win/rules.vc Update for VS10 2010-09-24 Andreas Kupries * tclWinsock.c: [Bug 3056775]: Fixed race condition between thread and internal co-thread access of a socket's structure because of the thread not using the socketListLock in TcpAccept(). Added documentation on how the module works to the top. 2010-09-01 Andreas Kupries * generic/tclExecute.c: [Bug 3057639]. Applied patch by Jeff to * generic/tclVar.c: make the behaviour of lappend in bytecompiled * tests/append.test: mode consistent with direct-eval and 'append' * tests/appendComp.test: generally. Added tests (append*-9.*) showing the difference. 2010-07-25 Jan Nijtmans * generic/tclInt.h: [Bug 3030870] make itcl 3.x built with pre-8.6 * generic/tclBasic.c: work in 8.6 revert tclInt.h to what it was before, and relax the relation between Tcl_CallFrame and CallFrame. 2010-07-18 Jan Nijtmans * generic/tcl.h: [Bug 3031278] fixed merge problem in previous commit. 2010-07-17 Jan Nijtmans * generic/tcl.h: [Bug 3030870] make itcl 3.x built with pre-8.6 * generic/tclInt.h: work in 8.6 2010-07-16 Jan Nijtmans * generic/tcl.h: (Backport) take over definitions of _WIN32, DLLIMPORT, DLLEXPORT and TCL_LL_MODIFIER macros from Tcl8.5/8.6 2010-06-28 Jan Nijtmans * generic/tclPosixStr.c: [Bug 3019634] errno.h and tclWinPort.h have conflicting definitions. 2010-06-09 Andreas Kupries * library/platform/platform.tcl: Added OSX Intel 64bit * library/platform/pkgIndex.tcl: Package updated to version 1.0.9. 2010-05-07 Andreas Kupries * library/platform/platform.tcl: Fix cpu name for Solaris/Intel 64bit. * library/platform/pkgIndex.tcl: Package updated to version 1.0.8. 2010-04-29 Andreas Kupries * library/platform/platform.tcl: Another stab at getting the /lib, * library/platform/pkgIndex.tcl: /lib64 difference right for linux. Package updated to version 1.0.7. 2010-04-18 Donal K. Fellows * doc/unset.n: [Bug 2988940]: Fix typo. 2010-04-14 Andreas Kupries * library/platform/platform.tcl: Linux platform identification: * library/platform/pkgIndex.tcl: Check /lib64 for existence of files matching libc* before accepting it as base directory. This can happen on weirdly installed 32bit systems which have an empty or partially filled /lib64 without an actual libc. Bumped to version 1.0.6. 2010-04-06 Zoran Vasiljevic * generic/tclCmdMZ.c (Tcl_RegexpObjCmd): fixed object leak. 2010-04-02 Zoran Vasiljevic * generic/tclStringObj.c: (SetStringFromAny): avoid trampling over the tclEmptyStringRep->bytes as it is thread-shared (thx to Gustaf Neumann for the (hard) work of locating this one). 2010-03-01 Alexandre Ferrieux * unix/tclUnixChan.c: [backported] Refrain from a possibly lengthy reverse-DNS lookup on 0.0.0.0 when calling [fconfigure -sockname] on an universally-bound (default) server socket. 2010-02-22 Jan Nijtmans * generic/tclExecute.c: Fix [Bug 2954959] expr abs(-0.0) is -0.0 * tests/expr.test Added some test cases, backported from 8.5 2010-02-11 Andreas Kupries * generic/tclCompile.c: [Bug 2949302]: Fixed leak of support structures for [info frame] which occured when bytecode compilation fails. 2010-02-01 Donal K. Fellows * generic/regexec.c (ccondissect, crevdissect): [Bug 2942697]: Rework these functions so that certain pathological patterns are matched much more rapidly. Many thanks to Tom Lane for dianosing this issue and providing an initial patch. 2009-11-16 Alexandre Ferrieux * generic/tclEncoding.c: (Backport) Fix [Bug 2891556] and improve * tests/econding.test: test to detect similar manifestations in the future. 2009-11-12 Andreas Kupries * generic/tclIO.c (CopyData): [Bug 2895565]. Dropped bogosity * tests/io.test: which used the number of _written_ bytes or character to update the counters for the read bytes/characters. New test io-53.11. This is a backward port from the 8.5 branch. 2009-11-10 Pat Thoyts * tests/fCmd.test: Fixed a number of issues for Vista * tests/registry.test: and Win7 that are due to restricted * tests/tcltest.test: permissions under UAC. * tests/winFCmd.test: 2009-11-10 Stuart Cassoff * win/README: [bug 2459744]: Removed outdated Msys + Mingw info. 2009-11-10 Andreas Kupries * generic/tclObj.c: Plug memory leak in TclContinuationsEnter(). [Bug 2895323]. Backport from Tcl 8.5 branch, change by Don Porter. 2009-11-09 Andreas Kupries * generic/tclBasic.c (TclEvalObjEx): Moved the #280 decrement of refCount for the file path out of the branch after the whole conditional, closing a memory leak. Added clause on structure type to prevent seg.faulting. Backport from valgrinding the Tcl 8.5 branch. * tests/info.test: Resolve ambiguous resolution of variable "res". Backport from 8.5 2009-10-23 Andreas Kupries * generic/tclCompCmds.c: [Bug 2881263] (TclCompileForeachCmd, TclCompileLindexCmd): Fixed. Moved the use of DefineLineInformation after all regular variable declarations, so that an empty statement (-UTIP_280) doesn't confuse c89 compilers. * library/platform/pkgIndex.tcl: Backported the platform packages * library/platform/platform.tcl: from head and8.5 into the 8.4 * library/platform/shell.tcl: branch. Updated makefiles to install * unix/Makfile.in: the packages. * win/Makefile.in: * generic/tclIO.c (FlushChannel): Skip OutputProc for low-level 0-length writes. When closing pipes which have already been closed not skipping leads to spurious SIG_PIPE signals. Reported by Mikhail Teterin . 2009-10-21 Donal K. Fellows * generic/tclPosixStr.c: [Bug 2882561]: Work around oddity on Haiku OS where SIGSEGV and SIGBUS are the same value. 2009-10-18 Joe Mistachkin * tests/thread.test (thread-4.[345]): [Bug 1565466]: Correct tests to save their error state before the final call to threadReap just in case it triggers an "invalid thread id" error. This error can occur if one or more of the target threads has exited prior to the attempt to send it an asynchronous exit command. 2009-10-04 Daniel Steffen * macosx/tclMacOSXBundle.c: Workaround CF memory managment bug in * unix/tclUnixInit.c: Mac OS X 10.4 & earlier. [Bug 2569449] 2009-09-28 Don Porter * generic/tclAlloc.c: Cleaned up various routines in the * generic/tclCkalloc.c: call stacks for memory allocation to * generic/tclParse.c: guarantee that any size values computed * generic/tclThreadAlloc.c: are within the domains of the routines they get passed to. [Bugs 2557696 and 2557796]. 2009-09-18 Don Porter * generic/tclCmdMZ.c (Tcl_SubstObj): Pass 'length' values to recursive parsing calls to convert O(N^2) operations of [subst] to O(N). 2009-08-25 Andreas Kupries * generic/tclBasic.c (Tcl_CreateInterp, Tcl_EvalTokensStandard, (EvalTokensStandard, Tcl_EvalEx, EvalEx, TclAdvanceContinuations, (TclEvalObjEx): * generic/tclCmdMZ.c (Tcl_SwitchObjCmd, ListLines): * generic/tclCompCmds.c (*): * generic/tclCompile.c (TclSetByteCodeFromAny, TclInitCompileEnv, (TclFreeCompileEnv, TclCompileScript): * generic/tclCompile.h (CompileEnv): * generic/tclInt.h (ContLineLoc, Interp): * generic/tclObj.c (ThreadSpecificData, ContLineLocFree, (TclThreadFinalizeObjects, TclInitObjSubsystem, (TclContinuationsEnter, TclContinuationsEnterDerived, (TclContinuationsCopy, TclContinuationsGet, TclFreeObj): * generic/tclProc.c (TclCreateProc): * generic/tclVar.c (TclPtrSetVar): * tests/info.test (info-30.0-22): Extended parser, compiler, and execution with code and attendant data structures tracking the positions of continuation lines which are not visible in script's, to properly account for them while counting lines for #280, during direct and compiled execution. 2009-08-17 Don Porter * generic/tclFileName.c: Correct result from [glob */test] when * * tests/fileName.test: matches something like ~foo. [Bug 2837800] 2009-07-23 Joe Mistachkin * generic/tclNotify.c: Fix for [Bug 2820349]. 2009-07-14 Andreas Kupries * generic/tclBasic.c (DeleteInterpProc,TclArgumentBCEnter, (TclArgumentBCRelease, TclArgumentGet): * generic/tclCompile.c (EnterCmdWordIndex, TclCleanupByteCode, (TclInitCompileEnv, TclCompileScript): * generic/tclCompile.h (ExtCmdLoc): * generic/tclExecute.c (TclExecuteByteCode): * generic/tclInt.h (ExtIndex, CFWordBC): * tests/info.test (info-39.0): Backport of some changes made to the Tcl head, to handle literal sharing better. The code here is much simpler (trimmed down) compared to the head as the 8.4 branch is not bytecode compiling whole files, and doesn't compile eval'd code either. Reworked the handling of literal command arguments in bytecode to be saved (compiler) and used (execution) per command (See the TCL_INVOKE_STK* instructions), and not per the whole bytecode. This removes the problems with location data caused by literal sharing in proc bodies. Simplified the associated datastructures (ExtIndex is gone, as is the function EnterCmdWordIndex). 2009-06-13 Don Porter * generic/tclCompile.c: The value stashed in iPtr->compiledProcPtr * generic/tclProc.c: when compiling a proc survives too long. We * tests/execute.test: only need it there long enough for the right TclInitCompileEnv() call to re-stash it into envPtr->procPtr. Once that is done, the CompileEnv controls. If we let the value of iPtr->compiledProcPtr linger, though, then any other bytecode compile operation that takes place will also have its CompileEnv initialized with it, and that's not correct. The value is meant to control the compile of the proc body only, not other compile tasks that happen along. Thanks to Carlos Tasada for discovering and reporting the problem. [Bug 2802881]. 2009-04-28 Jeff Hobbs * unix/tcl.m4, unix/configure (SC_CONFIG_CFLAGS): harden the check to add _r to CC on AIX with threads. 2009-04-27 Alexandre Ferrieux * generic/tclInt.h: Backport fix for [Bug 1028264]: WSACleanup() too * generic/tclEvent.c: early. The fix introduces "late exit handlers" * win/tclWinSock.c: for similar late process-wide cleanups. 2009-04-27 Alexandre Ferrieux * win/tclWinSock.c: Backport fix for [Bug 2446662]: resync Win behavior on RST with that of unix (EOF). 2009-04-22 Andreas Kupries * generic/tclStringObj.c (UpdateStringOfString): Added cast to fix signed/unsigned mismatch breaking win32 symbol/debug build. 2009-04-15 Don Porter * generic/tclStringObj.c: AppendUnicodeToUnicodeRep failed to set stringPtr->allocated to 0, leading to crashes. 2009-04-14 Stuart Cassoff * unix/tcl.m4: Removed -Wno-implicit-int from CFLAGS_WARNING. 2009-04-08 Don Porter * library/tcltest/tcltest.tcl: Fixed unsafe [eval]s in the tcltest * library/tcltest/pkgIndex.tcl: package. [Bug 2570363] 2009-04-07 Don Porter * generic/tclStringObj.c: Completed backports of fixes for [Bug 2494093] and [Bug 2553906]. 2009-03-30 Don Porter * doc/Alloc.3: Size argument is "unsigned int". [Bug 2556263] * generic/tclStringObj.c: Added protections from invalid memory * generic/tclTestObj.c: accesses when we append (some part of) * tests/stringObj.test: a Tcl_Obj to itself. Added the appendself and appendself2 subcommands to the [teststringobj] testing command and added tests to the test suite. [Bug 2603158] 2009-03-27 Don Porter * tests/fileName.test: Tests for [Bug 2710920] to guard against its appearance. 2009-03-20 Don Porter * generic/tclStringObj.c: Test stringObj-6.9 checks that * tests/stringObj.test: Tcl_AppendStringsToObj() no longer crashes when operating on a pure unicode value. [Bug 2597185] * generic/tclExecute.c (INST_CONCAT1): Panic when appends overflow the max length of a Tcl value. [Bug 2669109] 2009-03-18 Don Porter * win/tclWinFile.c (TclpObjNormalizePath): Corrected Tcl_Obj leak. Thanks to Joe Mistachkin for detection and patch. [Bug 2688184]. 2009-02-20 Don Porter * generic/tclPathObj.c: Fixed mistaken logic in TclFSGetPathType() * tests/fileName.test: that assumed (not "absolute" => "relative"). This is a false assumption on Windows, where "volumerelative" is another possibility. [Bug 2571597]. 2008-02-06 Daniel Steffen * generic/tcl.h (Darwin): workaround conflict between deprecated tcl panic macro and panic() function declaration in header. 2009-02-05 Don Porter * generic/tclStringObj.c: Added overflow protections to the AppendUtfToUtfRep routine to either avoid invalid arguments and crashes, or to replace them with controlled panics. [Bug 2561794] 2009-02-04 Don Porter * generic/tclStringObj.c (SetUnicodeObj): Corrected failure of Tcl_SetUnicodeObj() to panic on a shared object. [Bug 2561488]. Also factored out common code to reduce duplication. 2009-01-09 Don Porter * generic/tclStringObj.c (STRING_SIZE): Corrected failure to limit memory allocation requests to the sizes that can be supported by Tcl's memory allocation routines. [Bug 2494093]. 2009-01-08 Don Porter * generic/tclStringObj.c (STRING_UALLOC): Added missing parens required to get correct results out of things like STRING_UALLOC(num + append). [Bug 2494093]. 2008-12-04 Don Porter * generic/tclIOUtil.c (Tcl_FSGetNormalizedPath): Added another flag value TCLPATH_NEEDNORM to mark those intreps which need more complete normalization attention for correct results. [Bug 2385549] 2008-12-03 Don Porter * generic/tclFileName.c (TclDoGlob): One of the Tcl_FSMatchInDirectory() calls did not have its return code checked. Some VFS drivers can return TCL_ERROR, and when that's not checked, the error message gets converted into a list of matching files returned by [glob], with ridiculous results. 2008-12-01 Don Porter * generic/tclIO.c (TclFinalizeIOSubsystem): Revised latest commit to something that doesn't crash the test suite. 2008-11-25 Andreas Kupries * generic/tclIO.c (TclFinalizeIOSubsystem): Applied backport of Alexandre Ferrieux's patch for [Bug 2270477] to prevent infinite looping during finalization of channels not bound to interpreters. 2008-11-23 Andreas Kupries * generic/tclIO.c: Backport of fix for [Bug 2333466]. 2008-11-04 Jeff Hobbs * generic/tclPort.h: remove the ../{win,unix}/ header dirs as the build system already has it, and it confuses builds when used with private headers installed. 2008-09-25 Don Porter * doc/global.n: Correct false claim about [info locals]. 2008-08-14 Don Porter * tests/fileName.test: Revise new tests for portability to case insensitive filesystems. 2008-08-14 Daniel Steffen * generic/tclCompile.h: add support for debug logging of DTrace * generic/tclBasic.c: 'proc', 'cmd' and 'inst' probes (does _not_ require a platform with DTrace). * unix/Makefile.in: ensure Makefile shell is /bin/bash for * unix/configure.in (SunOS): DTrace-enabled build on Solaris. (followup to 2008-06-12) [Bug 2016584] * unix/tcl.m4 (SC_PATH_X): check for libX11.dylib in addition to libX11.so et al. * unix/configure: autoconf-2.13 2008-08-13 Don Porter * generic/tclFileName.c: Fix for errors handling -types {} * tests/fileName.test: option to [glob]. [Bug 1750300] Thanks to Matthias Kraft and George Peter Staplin. 2008-08-11 Andreas Kupries * generic/tclProc.c (Tcl_ProcObjCmd): Fixed memory leak triggered * tests/proc.test: by procbody::test::proc. See [Bug 2043636]. Added a test case demonstrating the leak before the fix. Fixed a few spelling errors in test descriptions as well. 2008-07-28 Andreas Kupries * generic/tclBasic.c: Added missing release of extended command word index when deleting an interpreter (DeleteInterpProc). Added missing ref count when creating an empty string as path (EvalEx). * generic/tclCompile.c (TclInitCompileEnv): Made same change to control flow as in TclEvalObjEx. Not needed while uplevel and siblings go through the eval-direct code path, however if that changes (like it did in 8.5+) better to have this in place instead of re-searching why certain places are without absolute locations. * tests/info.test: Added tests 38.*, exactly testing the tracking of location for uplevel scripts, and made the testsuite fully usable with and without -singleproc 1. 2008-07-25 Daniel Steffen * tests/info.test: Add !singleTestInterp constraint to various tests; (info-22.8, info-23.0): switch to glob matching to avoid sensitivity to tcltest.tcl line number changes. [Bug 1605269] 2008-07-24 Andreas Kupries * tests/info.test: Tests 38.* added, exactly testing the tracking of location for uplevel scripts. 2008-07-23 Andreas Kupries * generic/tclBasic.c: Modified TclArgumentGet to reject pure lists * generic/tclCmdIL.c: immediately, without search. Reworked setup * generic/tclCompile.c: of eoFramePtr, doesn't need the line * tests/info.test: information, more sensible to have everything on line 1 when eval'ing a pure list. Updated the users of the line information to special case this based on the frame type (i.e. TCL_LOCATION_EVAL_LIST). Added a testcase demonstrating the new behaviour. 2008-07-22 Andreas Kupries * generic/tclBasic.c: Added missing function comments. * generic/tclCompile.c: Made the new TclEnterCmdWordIndex * generic/tclCompile.h: static. * generic/tclBasic.c: Reworked the handling of bytecode literals * generic/tclCompile.c: for #280 to fix the abysmal performance * generic/tclCompile.h: for deep recursion, replaced the linear * generic/tclExecute.c: search through the whole stack with * generic/tclInt.h: another hashtable and simplified the data structure used by the compiler (array instead of hashtable). Incidentially this also fixes the memory leak reported via [Bug 2024937]. 2008-07-21 Andreas Kupries * generic/tclBasic.c: Extended the existing TIP #280 system (info * generic/tclCmdAH.c: frame), added the ability to track the * generic/tclCompCmds.c: absolute location of literal procedure * generic/tclCompile.c: arguments, and making this information * generic/tclCompile.h: available to uplevel, eval, and * generic/tclInterp.c: siblings. This allows proper tracking of * generic/tclInt.h: absolute location through custom (Tcl-coded) * generic/tclNamesp.c: control structures based on uplevel, etc. * generic/tclProc.c: 2008-07-07 Andreas Kupries * generic/tclCmdIL.c (InfoFrameCmd): Fixed unsafe idiom of setting the interp result found by Don Porter. 2008-07-04 Joe English * generic/tclEncoding.c(UtfToUtfProc): Avoid unwanted sign extension when converting incomplete UTF-8 sequences. See [Bug 1908443] for details. 2008-07-03 Don Porter * library/package.tcl: Removed [file readable] testing from [tclPkgUnknown] and friends. We find out soon enough whether a file is readable when we try to [source] it, and not testing before allows us to workaround the bugs on some common filesystems where [file readable] lies to us. [Patch 1969717] 2008-06-28 Don Porter * generic/tclIOUtil.c: Plug memory leak in latest commit. Thanks Rolf Ade for detecting and Dan Steffen for the fix [Bug 2004654]. 2008-06-23 Don Porter * generic/tclIOUtil.c: Fixed bug in Tcl_GetTranslatedPath() when operating on the "Special path" variant of the "path" Tcl_ObjType intrep. A full normalization was getting done, in particular, coercing relative paths to absolute, contrary to what the function of producing the "translated path" is supposed to do. [Bug 1972879]. 2008-06-20 Don Porter * tests/binary.test: Corrected flawed tests revealed by a -debug 1 * tests/io.test: -singleproc 1 test suite run. 2008-06-18 Don Porter * generic/tclParseExpr.c: Disabled attempts to support [expr] functions named eq(...) or ne(...). Any attempts to use such functions were panicking. [Bug 1971879]. 2008-06-16 Andreas Kupries * generic/tclCmdIL.c (InfoFrameCmd): Backport of fix made on the * tests/info.test: head branch :: Moved the code looking up the information for key 'proc' out of the TCL_LOCATION_BC branch to after the switch, this is common to all frame types. Updated the testsuite to match. This was exposed by the 2008-06-08 commit (Miguel), switching uplevel from direct eval to compilation. Fixes [Bug 1987851]. 2008-06-12 Andreas Kupries * generic/tclCmdIL.c (InfoFrameCmd): TIP #280 conditional feature. Added checks to validate HashEntry and HashTable information gotten from Command structures. This seems to be needed to handle structures managed by Itcl. 2008-06-12 Daniel Steffen * unix/Makefile.in: add complete deps on tclDTrace.h. * unix/Makefile.in: clean generated tclDTrace.h file. * unix/configure.in (SunOS): fix static DTrace-enabled build. * unix/tcl.m4 (SunOS-5.11): fix 64bit amd64 support with gcc & Sun cc. * unix/configure: autoconf-2.13 2008-05-26 Jeff Hobbs * tests/io.test (io-53.9): need to close chan before removing file. 2008-05-23 Andreas Kupries * win/tclWinChan.c (FileWideSeekProc): Accepted a patch by Alexandre Ferrieux to fix the [Bug 1965787]. 'tell' now works for locations > 2 GB as well instead of going negative. * generic/tclIO.c (Tcl_SetChannelBufferSize): Accepted a patch by * tests/io.test: Alexandre Ferrieux to fix the [Bug 1969953]. Buffersize outside of the supported range are now clipped to nearest boundary instead of ignored. 2008-04-26 Zoran Vasiljevic * generic/tclAsync.c: Tcl_AsyncDelete(): panic if attempt to locate handler token fails. Happens when some other thread attempts to delete somebody else's token. Also, panic early if we find out the wrong thread attempting to delete the async handler (common trap). As, only the one that created the handler is allowed to delete it. 2008-04-17 Andreas Kupries *** 8.4.19 TAGGED FOR RELEASE *** * generic/tclCompExpr.c (CompileMathFuncCall): Added * tests/compExpr.test (compExpr-5.10): Tcl_ResetResult before appending error message, to clear out possible sharing. Added test case demonstrating the crash (abort on shared object) without the fix. 2008-04-15 Andreas Kupries * generic/tclIO.c (CopyData): Applied another patch by Alexandre * io.test (io-53.8a): Ferrieux , to shift EOF handling to the async part of the command if a callback is specified, should the channel be at EOF already when fcopy is called. Testcase by myself. 2008-04-14 Kevin B. Kenny * unix/tclUnixTime.c (TclpGetClicks, Tcl_GetTime): Removed obsolete use of 'struct timezone' in the call to 'gettimeofday'. [Bug 1942197]. 2008-04-14 Don Porter * generic/tclExecute.c: Plug memory leak introduced in the 2008-03-07 commit. [Bug 1940433] 2008-04-11 Don Porter * README: Bump version number to 8.4.19 * generic/tcl.h: * tools/tcl.wse.in: * unix/configure.in: * unix/tcl.spec: * win/README.binary: * win/configure.in: * unix/configure: autoconf-2.13 * win/configure: * changes: updates for 8.4.19 release. 2008-04-10 Andreas Kupries * generic/tclIOCmd.c (Tcl_FcopyObjCmd): Keeping check for negative values, changed to not be an error, but behave like the special value -1 (copy all, default). * tests/iocmd.test (iocmd-15.{12,13}): Removed. * tests/io.test (io-52.5{,a,b}): Reverted last change, added comment regarding the meaning of -1, added two more testcases for other negative values, and input wrapped to negative. 2008-04-09 Andreas Kupries * tests/io.test (io-52.5): Removed '-size -1' from test, does not seem to have any bearing, and was an illegal value. Test case is not affected by the value of -size, test flag restoration and that everything was properly copied. * generic/tclIOCmd.c (Tcl_FcopyObjCmd): Added checking of -size * tests/ioCmd.test (iocmd-15.{13,14}): value to reject negative values, and values overflowing 32-bit signed. [Bug 1557855]. Basic patch by Alexandre Ferrieux , with modifications from me to separate overflow from true negative value. Extended testsuite. 2008-04-08 Andreas Kupries * tests/io.test (io-53.8,53.9,53.10): Backported das' fix of typo and quoting for spaces in builddir path. 2008-04-07 Andreas Kupries * tests/io.test (io-53.10): Testcase for bi-directionaly fcopy. * generic/tclIO.c: Additional changes to data structures for fcopy * generic/tclIO.h: and channels to perform proper cleanup in case of a channel having two background copy operations running as is now possible. * generic/tclIO.c (BUSY_STATE, CheckChannelErrors, TclCopyChannel): New macro, and the places using it. This change allows for bi-directional fcopy on channels. [Bug 1350564]. Thanks to Alexandre Ferrieux for the patch. * tests/io.test (io-53.9): Made test cleanup robust against the possibility of slow process shutdown on Windows. Backported from Kevin Kenny's change to the same test on the 8.5 and head branches. 2008-04-04 Andreas Kupries * tests/io.test (io-53.9): Added testcase for [Bug 780533], based on Alexandre's test script. Also fixed problem with timer in preceding test, was not canceled properly in the ok case. 2008-04-03 Andreas Kupries * generic/tclIO.c (CopyData): Applied patch [Bug 1932639] to * tests/io.test: prevent fcopy from calling -command synchronously the first time. Thanks to Alexandre Ferrieux for report and patch. 2008-04-02 Andreas Kupries * generic/tclIO.c (CopyData): Applied patch for the fcopy problem [Bug 780533], with many thanks to Alexandre Ferrieux for tracking it down and providing a solution. Still have to convert his test script into a proper test case. 2008-03-27 Daniel Steffen * unix/tcl.m4 (SunOS-5.1x): fix 64bit support for Sun cc. [Bug 1921166] * unix/dltest/Makefile.in: support use of LDFLAGS in SHLIB_LD. * unix/configure: autoconf-2.13 2008-03-24 Pat Thoyts * generic/tclBinary.c: bug #1923966 - crash in binary format * tests/binary.test: Added tests for the above crash condition. 2008-03-11 Daniel Steffen * macosx/tclMacOSXNotify.c: avoid using CoreFoundation after fork() on Darwin 9 even when TclpCreateProcess() uses vfork(). 2008-03-07 Don Porter * generic/tclExecute.c (Tcl_ExprObj): Revised expression bytecode compiling so that bytecodes invalid due to changing context or due to the difference between expressions and scripts are not reused. [Bug 1899164]. * generic/tclTest.c: Backport the [testexprlongobj] testing command. * tests/execute.test (execute-6.8): Added tests checking that bytecode is invalidates in the right situations. 2008-03-03 Reinhard Max * unix/tclUnixChan.c: Fix mark and space parity on Linux, which uses CMSPAR instead of PAREXT. 2008-02-27 Pat Thoyts * library/http/pkgIndex.tcl: Backported 2.5.5 changes from * library/http/http.tcl: 8.5 version. * doc/http.n: Document the meta accessor. 2008-02-26 Jeff Hobbs * generic/tclIOCmd.c (Tcl_GetsObjCmd): do not reuse resultObj as it may be shared (crash condition). 2008-02-22 Pat Thoyts * library/http/pkgIndex.tcl: Set version 2.5.4 * library/http/http.tcl: Fix for bug #1818565. Always check that the state array exists in the http::status command. 2008-02-06 Don Porter *** 8.4.18 TAGGED FOR RELEASE *** * README: Bump version number to 8.4.18 * generic/tcl.h: * tools/tcl.wse.in: * unix/configure.in: * unix/tcl.spec: * win/README.binary: * win/configure.in: * unix/configure: autoconf-2.13 * win/configure: * changes: updates for 8.4.18 release. 2008-02-02 Daniel Steffen * unix/configure.in (Darwin): correct Info.plist year substitution in non-framework builds. * unix/configure: autoconf-2.13 2008-01-30 Miguel Sofer * generic/tclInterp.c (Tcl_GetAlias): fix for [Bug 1882373] 2008-01-13 Jeff Hobbs * win/tclWinSerial.c (SerialCloseProc, TclWinOpenSerialChannel): use critical section for read & write side. [Bug 1353846] (newman) 2007-12-31 Don Porter *** 8.4.17 TAGGED FOR RELEASE *** * changes: updates for 8.4.17 release. * doc/filename.n: Typo 2007-12-18 Donal K. Fellows * generic/regguts.h, generic/regc_color.c, generic/regc_nfa.c: Fixes for problems created when processing regular expressions that generate very large automata. An enormous number of thanks to Will Drewry , Tavis Ormandy , and Tom Lane from the Postgresql crowd for their help in tracking these problems down. [Bug 1810264] 2007-12-14 Jeff Hobbs * win/README: updated notes 2007-12-14 Zoran Vasiljevic * unix/tclUnixCompat.c (TclpGetHostByName): Really applied the change noted on 2007-11-13 by dkf below. 2007-12-13 Jeff Hobbs * generic/tclIOUtil.c (TclGetOpenMode): Only set the O_APPEND flag * tests/ioUtil.test (ioUtil-4.1): on a channel for the 'a' mode and not for 'a+'. [Bug 1773127] (backport from HEAD) 2007-12-05 Donal K. Fellows * generic/tclCmdIL.c (Tcl_LsearchObjCmd): Prevent shimmering crash when -exact and -integer/-real are mixed. [Bug 1844789] 2007-11-28 Jeff Hobbs * win/tclWinSock.c (Tcl_GetHostName): update to previous fix to set hostname length appropriately, clean up check overall. 2007-11-27 Don Porter * win/tclWinSock.c: Add missing encoding conversion of the [info hostname] value from the system encoding to Tcl's internal encoding. This is important now that ICANN no longer limits host names to ASCII. [Bug 1823552] 2007-11-26 Zoran Vasiljevic * generic/tclThread.c: Back-port locking changes from Tcl8.5 in Tcl_Mutex/ConditionFinlize. Now we properly master-lock the finalization of sync primitives. 2007-11-15 Don Porter * generic/regc_nfa.c: Fixed infinite loop in the regexp compiler * generic/regcomp.c: [Bug 1810038]. Corrected looping logic in * tests/regexp.test: fixempties() to avoid wasting time walking a list of dead states [Bug 1832612]. Convert optst() from expensive no-op to a cheap no-op. Improve newline usage in debug output. 2007-11-13 Donal K. Fellows * unix/tclUnixCompat.c (TclpGetHostByName): The six-argument form of getaddressbyname_r() uses the fifth argument to indicate whether the lookup succeeded or not on at least one platform. [Bug 1618235] 2007-10-30 Donal K. Fellows * generic/regc_lex.c (lexescape): Ensure that backreference numbers can't overflow a signed int in a way that breaks things. [Bug 1810264] 2007-10-15 Miguel Sofer * generic/tclParse.c (Tcl_ParseBraces): fix for possible read after the end of buffer, [Bug 1813528] (Joe Mistachkin). 2007-10-03 Miguel Sofer * generic/tclObj.c (Tcl_FindCommandFromObj): fix finding a deleted command; cannot trigger this from Tcl itself, but crash reported on xotcl. This check is new to 8.4 but exists in 8.5, so this is a backport or something. Thanks Gustaf Neumann. 2007-10-02 Jeff Hobbs * generic/tcl.h (Tcl_DecrRefCount): Update change from 2006-05-29 to make macro more warning-robust in unbraced if code. 2007-10-02 Don Porter * README: Bump version number to 8.4.17 * generic/tcl.h: * tools/tcl.wse.in: * unix/configure.in: * unix/tcl.spec: * win/README.binary: * win/configure.in: * unix/configure: autoconf-2.13 * win/configure: 2007-09-20 Don Porter *** 8.4.16 TAGGED FOR RELEASE *** * doc/load.n: Backport corrected example. 2007-09-19 Don Porter * unix/Makefile.in: Update `make dist` so that tclDTrace.d is included in the source code distribution. * generic/tclPkg.c: Backport fix for [1573844] to the * tests/pkg.test: TCL_TIP268 sections. 2007-09-18 Don Porter * changes: updates for 8.4.16 release. 2007-09-15 Daniel Steffen * unix/tcl.m4 (SunOS-5.1x): replace direct use of '/usr/ccs/bin/ld' in SHLIB_LD by 'cc' compiler driver. * unix/configure: autoconf-2.13 2007-09-14 Daniel Steffen * generic/tclDTrace.d (new file): add DTrace provider for Tcl; allows * generic/tclCompile.h: tracing of proc and command entry & * generic/tclBasic.c: return, bytecode execution, object * generic/tclExecute.c: allocation and more; with essentially * generic/tclInt.h: zero cost when tracing is inactive; * generic/tclObj.c: enable with --enable-dtrace configure * generic/tclProc.c: arg (disabled by default, will only * unix/Makefile.in: enable if DTrace is present). * unix/configure.in: [Patch 1793984] * macosx/Makefile: enable DTrace support. * unix/configure: autoconf-2.13 2007-09-11 Don Porter * library/tcltest/tcltest.tcl: Accept underscores and colons in * library/tcltest/pkgIndex.tcl: constraint names. Properly handle constraint expressions that return non-numeric boolean results like "false". Bump to tcltest 2.2.9. [Bug 1772989; RFE 1071322] 2007-09-11 Pat Thoyts * win/makefile.vc: AMD64 target fixes for symbols builds. * win/rules.vc: 2007-09-10 Jeff Hobbs * generic/tclLink.c (Tcl_UpdateLinkedVar): guard against var being unlinked. [Bug 1740631] (maros) 2007-08-25 Kevin Kenny * generic/tclClock.c (FormatClock): Claimed additional space for the %c format code to avoid a buffer overrun when formatting (for example) a Friday in February in the Portuguese locale. [Bug 1751117] 2007-08-24 Miguel Sofer * generic/tclCompile.c: replaced copy loop that tripped some compilers with memmove [Bug 1780870] 2007-08-14 Don Porter * tests/trace.test: Backport some tests. 2007-08-14 Daniel Steffen * unix/tclLoadDyld.c: use dlfcn API on Mac OS X 10.4 and later; fix issues with loading from memory on intel and 64bit; add debug messages. * tests/load.test: add test load-10.1 for loading from vfs. 2007-08-07 Daniel Steffen * generic/tclEnv.c: improve environ handling on Mac OS X (adapted * unix/tclUnixPort.h: from Apple changes in Darwin tcl-64). * unix/Makefile.in: add support for compile flags specific to object files linked directly into executables. * unix/configure.in (Darwin): only use -seg1addr flag when prebinding; use -mdynamic-no-pic flag for object files linked directly into exes; support overriding TCL_PACKAGE_PATH in environment. * unix/configure: autoconf-2.13 2007-07-19 Don Porter * generic/tclParse.c: In contexts where interp and parsePtr->interp might be different, be sure to use the latter for error reporting. 2007-07-05 Don Porter * library/init.tcl (unknown): Corrected inconsistent error message in interactive [unknown] when empty command is invoked. [Bug 1743676] 2007-06-30 Donal K. Fellows * generic/tclBinary.c (Tcl_BinaryObjCmd): De-fang an instance of the shared-result anti-pattern. [Bug 1716704] 2007-06-30 Zoran Vasiljevic * generic/tclThread.c: Prevent RemeberSyncObj() from growing the sync object lists by reusing already free'd slots, if possible. See discussion on Bug 1726873 for more information. 2007-06-29 Daniel Steffen * generic/tclAlloc.c: on Darwin, ensure memory allocated by * generic/tclThreadAlloc.c: the custom TclpAlloc()s is aligned to 16 byte boundaries (as is the case with the Darwin system malloc). 2007-06-27 Don Porter * generic/tclCmdMZ.c: Corrected broken trace reversal logic in * generic/tclTest.c: TclCheckInterpTraces that led to infinite loop * tests/basic.test: when multiple Tcl_CreateTrace traces were set and one of them did not fire due to level restrictions. [Bug 1743941]. 2007-06-23 Daniel Steffen * macosx/tclMacOSXNotify.c (AtForkChild): don't call CoreFoundation APIs after fork() on systems where that would lead to an abort(). 2007-06-10 Jeff Hobbs * README: updated links. [Bug 1715081] 2007-06-06 Daniel Steffen * unix/configure.in (Darwin): add plist for tclsh; link the * unix/Makefile.in (Darwin): Tcl and tclsh plists into their * macosx/Tclsh-Info.plist.in (new): binaries in all cases. * unix/tcl.m4 (Darwin): fix CF checks in fat 32&64bit builds. * unix/configure: autoconf-2.13 2007-06-05 Don Porter * tests/result.test (result-6.2): Add test for [Bug 1649062] so that 8.4 and 8.5 both test the same outcome and we verify compatibility. 2007-05-30 Don Porter * README: Bump version number to 8.4.16 * generic/tcl.h: * tools/tcl.wse.in: * unix/configure.in: * unix/tcl.spec: * win/README.binary: * win/configure.in: * unix/configure: autoconf-2.13 * win/configure: 2007-05-29 Jeff Hobbs * unix/tclUnixThrd.c (Tcl_JoinThread): fix for 64-bit handling of pthread_join exit return code storage. [Bug 1712723] 2007-05-24 Don Porter *** 8.4.15 TAGGED FOR RELEASE *** * generic/tclIO.c: Backport memleak fix in TclFinalizeIOSubsystem. 2007-05-17 Don Porter * tests/fCmd.test: Backport the notNetworkFilesystem constraint. 2007-05-15 Don Porter * generic/tclNamesp.c: Plugged memory leak related to [namespace delete ::]. [Bug 1716782] * changes: updates for 8.4.15 release. * win/tclWinReg.c: Bump to registry 1.1.5 to account * library/reg/pkgIndex.tcl: for [Bug 1682211] fix. 2007-05-10 Don Porter * generic/tclInt.h: TclFinalizeThreadAlloc() is always defined, so make sure it is also always declared. [Tcl Bug 1706140] * generic/tclCmdMZ.c (Trace*Proc): Update Tcl_VarTraceProcs so * generic/tclLink.c (LinkTraceProc): that they call * generic/tclUtil.c (TclPrecTraceProc): Tcl_InterpDeleted() for themselves, and do not rely on (frequently buggy) setting of the TCL_INTERP_DESTROYED flag by the trace core. * generic/tclVar.c: Update callers of CallVarTraces to not pass in the TCL_INTERP_DESTROYED flag. Also apply filters so that public routines only pass documented flag values down to lower level routines. * generic/tclVar.c (CallVarTraces): The setting of the TCL_INTERP_DESTROYED flag is now done entirely within the CallVarTraces routine, the only place it can be done right. 2007-04-30 Daniel Steffen * unix/Makefile.in: add 'tclsh' dependency to install targets that rely on tclsh, fixes parallel 'make install' from empty build dir. 2007-04-29 Daniel Steffen * unix/tclUnixFCmd.c: add workaround for crashing bug in fts_open() * unix/tclUnixInit.c: without FTS_NOSTAT on 64bit Darwin 8 or earlier. * unix/tclLoadDyld.c (TclpLoadMemory): fix (void*) arithmetic. * macosx/tclMacOSXNotify.c: fix warnings. * macosx/README: sync whitespace/formatting with HEAD. * macosx/tclMacOSXBundle.c: * macosx/tclMacOSXNotify.c: * unix/tclLoadDyld.c: * macosx/Makefile: fix/add copyright and license refs. * macosx/tclMacOSXBundle.c: * macosx/Tcl-Info.plist.in: * unix/Makefile.in (dist): copy license.terms to dist macosx dir. * unix/configure.in: install license.terms into Tcl.framework. * unix/configure: autoconf-2.13 2007-04-21 Kevin B. Kenny * generic/tclClock.c: Restored Cygwin buildability [Bug 1387154] * generic/tclInt.decls: Yet another round of attempting * generic/tclInt.h: to get the correct type signature * unix/tclUnixPort.h: for TclpLocaltime and TclpGmtime. * unix/tclUnixTime.c: CONST TclpTime_t is a 'time_t *CONST' * win/tclWinTime.c: and not a 'CONST time_t*' [Bug 1677275] * generic/tclIntDecls.h: * generic/tclIntPlatDecls.h: Regenerated. 2007-03-24 Zoran Vasiljevic * win/tclWinThrd.c: Thread exit handler marks the current thread as un-initialized. This allows exit handlers that are registered later to re-initialize this subsystem in case they need to use some sync primitives (cond variables) from this file again. 2007-03-19 Don Porter * generic/tclEvent.c (Tcl_CreateThread): Replaced some calls to * generic/tclPkg.c (CheckVersion): Tcl_Alloc() with calls to * unix/tclUnixTime.c (SetTZIfNecessary): ckalloc(), which better * win/tclAppInit.c (setargv): supports memory debugging. 2007-03-17 Kevin Kenny * win/tclWinReg.c (GetKeyNames): Size the buffer for enumerating key names correctly, so that Unicode names exceeding 127 chars can be retrieved without crashing. [Bug 1682211] * tests/registry.test (registry-4.9): Added test case for the above bug. 2007-03-13 Don Porter * generic/tclExecute.c (INST_FOREACH_STEP4): Re-fetch pointers for * tests/foreach.test (foreach-10.1): the value list each iteration of the loop as defense against shimmers. [Bug 1671087] * generic/tclVar.c (TclArraySet): Re-fetch pointers for the list * tests/var.test (var-17.1): argument of [array set] each time through the loop as defense against possible shimmer issues. [Bug 1669489]. 2007-03-10 Donal K. Fellows * generic/tclCmdIL.c (Tcl_LsortObjCmd): Handle tricky case with loss * tests/cmdIL.test (cmdIL-1.29):of list rep during sorting due to shimmering. [Bug 1675116] 2007-03-07 Daniel Steffen * macosx/tclMacOSXNotify.c: add spinlock debugging and sanity checks. * unix/tcl.m4 (Darwin): s/CFLAGS/CPPFLAGS/ in macosx-version-min check. * unix/configure: autoconf-2.13 2007-03-01 Donal K. Fellows * generic/tclCompCmds.c (TclCompileForeachCmd): Prevent an unexpected * tests/foreach.test (foreach-9.1): infinite loop when the variable list is empty and the foreach is compiled. [Bug 1671138] 2007-02-22 Andreas Kupries * tests/pkg.test: Added tests for the case of an alpha package satisfying a require for the regular package, demonstrating a corner case specified in TIP#280. More notes in the comments to the test. 2007-02-20 Don Porter * doc/tcltest.n: Typo fix. [Bug 1663539] 2007-02-19 Jeff Hobbs * generic/tclIOUtil.c (Tcl_FSEvalFile): safe incr of objPtr ref. * unix/tcl.m4: use SHLIB_SUFFIX=".so" on HP-UX ia64 arch. * unix/configure: autoconf-2.13 2007-02-12 Andreas Kupries * generic/tclEncoding.c (EscapeFromUtfProc): Applied patch supplied by Mo DeJong to fix [Bug 1516109]. Backport from Tcl 8.5. Mo's description: Clear the TCL_ENCODING_END flag when end bytes are written. This fix keep this method from writing escape bytes for an encoding like iso2022-jp multiple times when the escape byte overlap with the end of the IO buffer. * tests/io.test: Add test case for escape byte overlap case. 2007-02-04 Daniel Steffen * unix/configure.in: add caching to -pipe check. * unix/configure: autoconf-2.13 2007-01-30 Jeff Hobbs * win/Makefile.in (install-private-headers): added target 2007-01-29 Don Porter * doc/fcopy.n: Typo fix. [Bug 1630627] 2007-01-25 Daniel Steffen * unix/tcl.m4: integrate CPPFLAGS into CFLAGS as late as possible * unix/configure.in: and move (rather than duplicate) -isysroot flags from CFLAGS to CPPFLAGS to avoid errors about multiple -isysroot flags from some older gcc builds. * unix/configure: autoconf-2.13 2007-01-22 Andreas Kupries * compat/memcmp.c (memcmp): Fixed the VOID / CONST typo introduced by the last checkin. 2007-01-22 Donal K. Fellows * compat/memcmp.c (memcmp): Reworked so that arithmetic is never performed upon void pointers, since that is illegal. [Bug 1631017] 2006-01-19 Daniel Steffen * macosx/tclMacOSXNotify.c: accommodate changes to prototypes of OSSpinLock(Un)Lock API. * tests/env.test: add extra system env vars that need to be preserved on some Mac OS X versions for testsuite to work. * unix/tcl.m4: ensure CPPFLAGS env var is used when set. [Bug 1586861] (Darwin): add -isysroot and -mmacosx-version-min flags to CPPFLAGS when present in CFLAGS to avoid discrepancies between what headers configure sees during preprocessing tests and compiling tests. * unix/configure: autoconf-2.13 2006-12-19 Daniel Steffen * unix/tclUnixThrd.c (TclpInetNtoa): fix for 64 bit. * unix/tcl.m4 (Darwin): --enable-64bit: verify linking with 64bit -arch flag succeeds before enabling 64bit build. * unix/configure: autoconf-2.13 2006-12-14 Donal K. Fellows * doc/string.n: Fix example. [Bug 1615277] 2006-12-05 Andreas Kupries * tests/pkg.test: Backport to 8.4 (Don Porter's work): * generic/tclPkg.c: When no requirements are supplied to a [package require $pkg] and [package unknown] is invoked to find a satisfying package, pass the requirement argument "0-" (which means all versions are acceptable). This permits a registered [package unknown] command to call [package vsatisfies $testVersion {*}$args] without any special handling of the empty $args case. This fixes/avoids a bug in [::tcl::tm::UnknownHandler] that was causing old TM versions to be provided in preference to newer TM versions. Thanks to Julian Noble for discovering the issue. 2006-12-04 Donal K. Fellows * doc/file.n: Fix confusing wording for [file pathtype]. [Bug 1606454] 2006-11-28 Andreas Kupries * generic/tclBasic.c: TIP #280 implementation, conditional on the * generic/tclCmdAH.c: define TCL_TIP280. * generic/tclCmdIL.c: * generic/tclCmdMZ.c: * generic/tclCompCmds.c: * generic/tclCompExpr.c: * generic/tclCompile.c: * generic/tclCompile.h: * generic/tclExecute.c: * generic/tclIOUtil.c: * generic/tclInt.h: * generic/tclInterp.c: * generic/tclNamesp.c: * generic/tclObj.c: * generic/tclProc.c: * tests/compile.test: * tests/info.test: * tests/platform.test: * tests/safe.test: 2006-11-27 Kevin Kenny * unix/tclUnixChan.c (TclUnixWaitForFile): * tests/event.test (event-14.*): Corrected a bug where TclUnixWaitForFile would present select() with the wrong mask on an LP64 machine if a fd number exceeds 32. Thanks to Jean-Luc Fontaine for reporting and diagnosing [Bug 1602208] 2006-11-26 Daniel Steffen * unix/tcl.m4 (Linux): --enable-64bit support. [Patch 1597389] * unix/configure: autoconf-2.13 [Bug 1230558] 2006-11-07 Andreas Kupries * unix/tclUnixFCmd.c (CopyFile): Added code to fall back to a hardwired default block size should the filesystem report a bogus value. [Bug 1586470] 2006-11-03 Miguel Sofer * generic/tclBasic.c (TEOVI): fix for possible leak of a Command in the presence of execution traces that delete it. * generic/tclBasic.c (TEOVI): * tests/trace.test (trace-21.11): fix for [Bug 1590232], execution traces may cause a second command resolution in the wrong namespace. 2006-11-01 Daniel Steffen * generic/tclEnv.c (Darwin): mark _environ symbol as unexported. 2006-10-31 Pat Thoyts * rules.vc: Fix [Bug 1582769] build with VC2003 and correct i386 arch 2006-10-23 Don Porter * README: Bump version number to 8.4.15 * generic/tcl.h: * tools/tcl.wse.in: * unix/configure.in: * unix/tcl.spec: * win/README.binary: * win/configure.in: * unix/configure: autoconf-2.13 * win/configure: 2006-10-18 Pat Thoyts *** 8.4.14 TAGGED FOR RELEASE *** * win/nmakehlp.c: Ensure builds with VC6 without Platform SDK. * win/rules.vc: Pickup MACHINE from environment. 2006-10-17 Don Porter * generic/tclIOUtil.c: Cleaned up some code flagged by a * generic/tclInt.h: `make checkexports` test. * win/tclWin32Dll.c: * win/tclWinFile.c: 2006-10-16 Daniel Steffen * changes: updates for 8.4.14 release. * macosx/Makefile: don't redo prebinding of non-prebound binaires. 2006-10-11 Andreas Kupries * generic/tclPkg.c (Tcl_PkgRequireEx): Corrected crash when argument version==NULL passed in. Backport of the fix for the same problem in 8.5. 2006-10-10 Don Porter * changes: changes updated for 8.4.14 release. 2006-10-06 Jeff Hobbs * tests/http.test: update tests to handle strictness change. 2006-10-06 Pat Thoyts * win/rules.vc: avoid /RTCc flag with MSVC8. [Bug 1571954] 2006-10-05 Jeff Hobbs * library/http/http.tcl (http::geturl): only do geturl url rfc 3986 validity checking if $::http::strict is true (default false for 8.4). [Bug 1560506] * generic/tcl.h: note limitation on changing Tcl_UniChar size * generic/tclEncoding.c (UtfToUnicodeProc, UnicodeToUtfProc): * tests/encoding.test (encoding-16.1): fix alignment issues in unicode <> utf conversion procs. [Bug 1122671] 2006-10-05 Miguel Sofer * generic/tclVar.c (Tcl_LappendObjCmd): * tests/append.test(4.21-22): fix for longstanding [Bug 1570718], lappending nothing to non-list. Reported by lvirden 2006-10-02 Don Porter * generic/tclFileName.c (TclGlob): Prevent doubling of directory separators by [glob]. [Bug 1569042] 2006-10-01 Pat Thoyts * win/tclWinFile.c: Handle possible missing define. * win/tclWinFile.c: Backported fix for [Bug 1420432] (cannot set * tests/cmdAH.test: mtime for directories on windows). 2006-09-30 Miguel Sofer * generic/tclUtil.c (Tcl_SplitList): optimisation, [Patch 1344747] by dgp. 2006-09-26 Pat Thoyts * win/makefile.vc: Updated MSVC build to properly deal with * win/nmakehlp.c: MSVC8 and AMD64 target. Backport from 8.5 * win/rules.vc: * generic/tcl.h: Fixed stat definition for MSVC8 AMD64. * win/tclWinSock.c: Casting type police. * win/tclWinTime.c: 2006-09-26 Don Porter * generic/tcl.h: As 2006-09-22 commit from Donal K. Fellows demonstrates, "#define NULL 0" is just wrong, and as a quotable chat figure observed, "If NULL isn't defined, we're not using a C compiler." Improper fallback definition of NULL removed. 2006-09-25 Andreas Kupries * generic/tclIO.c (Tcl_StackChannel): Fixed [SF Tcl Bug 1564642], aka coverity #51. Extended loop condition, added checking for NULL to prevent seg.fault. 2006-09-25 Andreas Kupries * generic/tclBasic.c: Reverted exposure of patchlevel in registered core version when TIP#268 features are activated. Better compatibility with existing packages. Like Tk. 2006-09-24 Miguel Sofer * generic/tclParse.c (Tcl_ParseCommand): also return an error if start==NULL and numBytes<0. This is coverity's bug #20 * generic/tclStringObj.c (STRING_SIZE): fix allocation for 0-length strings. This is coverity's bugs #54-5 2006-09-22 Andreas Kupries * generic/tclInt.h: Moved TIP#268's field 'packagePrefer' to the end of the structure, for better backward compatibility. 2006-09-22 Andreas Kupries * generic/tclPkg.c (Tcl_PkgRequireEx): Changes handling of the return information from 'Tcl_PkgRequireProc'. Keep the interpreter result empty. Backport of fix for problem found while testing #268 under 8.5. More details in the comments. 2006-09-22 Donal K. Fellows * generic/tclThreadTest.c (TclCreateThread): Use NULL instead of 0 as end-of-strings marker to Tcl_AppendResult; the difference matters on 64-bit machines. [Bug 1562528] 2006-09-21 Andreas Kupries * generic/tcl.decls: Implemented TIP #268, conditionally. * generic/tclBasic.c: Define TCL_TIP268 to activate the new * generic/tclDecls.h: features. * generic/tclInt.h: * generic/tclPkg.c: * generic/tclStubInit.c: * generic/tclTest.c: * library/init.tcl * library/package.tcl: * tests/pkg.test: * tests/platform.test: * tests/safe.test: * doc/PkgRequire.3: 2006-09-15 Jeff Hobbs * library/http/http.tcl: Change " " -> "+" url encoding mapping * library/http/pkgIndex.tcl: to " " -> "%20" as per RFC 3986. * tests/http.test (http-5.1): bump http to 2.5.3 for 8.4.14 2006-09-12 Andreas Kupries * unix/configure.in (HAVE_MTSAFE_GETHOST*): Modified to recognize HP-UX 11.00 and beyond as having mt-safe implementations of the gethost functions. * unix/configure: Regenerated, using autoconf 2.13 * unix/tclUnixCompat.c (PadBuffer): Fixed bug in calculation of the increment needed to align the pointer, and added documentation explaining why the macro is implemented as it is. 2006-09-11 Andreas Kupries * tests/msgcat.test: Bumped version in auxiliary files as well. * doc/msgcat.n: 2006-09-11 Daniel Steffen * unix/tclUnixCompat.c: make compatLock static and only declare it when it will actually be used; #ifdef parts of TSD that are not always needed; adjust #ifdefs to cover all possible cases; fix whitespace. 2006-09-10 Don Porter * library/msgcat/msgcat.tcl: Bump to version msgcat 1.3.4 to account * library/msgcat/pkgIndex.tcl: for modifications. 2006-09-10 Daniel Steffen * library/msgcat/msgcat.tcl (msgcat::Init): on Darwin, add fallback of * tests/msgcat.test: default msgcat locale to * unix/tclUnixInit.c (TclpSetVariables): current CFLocale identifier if available (via private ::tcl::mac::locale global, set at interp init when on Mac OS X 10.3 or later with CoreFoundation). * unix/tcl.m4: add caching to new SC_TCL_* macros for MT-safe wrappers * unix/configure: autoconf-2.13 2006-09-08 Andreas Kupries * unix/tclUnixCompat.c: Fixed conditions for CopyArray/CopyString, and CopyHostent. Also fixed bad var names in TclpGetHostByName. 2006-09-08 Zoran Vasiljevic * unix/tclUnixCompat.c: Added fallback to gethostbyname() and gethostbyaddr() if the implementation is known to be MT-safe (currently for Darwin 6 or later only). * unix/configure.in: Assume gethostbyname() and gethostbyaddr() are MT-safe starting with Darwin 6 (Mac OSX 10.2). * unix/configure: Regenerated with autoconf V2.13 2006-09-07 Zoran Vasiljevic * unix/tclUnixFCmd.c: Removed some false tests added (and left by mistake) by fixing [Bug 999544] * unix/tclUnixCompat.c: Added fallback to MT-unsafe library calls if TCL_THREADS is not defined. Fixed alignment of arrays copied by CopyArrayi() to be on the sizeof(char *) boundary. 2006-09-07 Andreas Kupries * unix/configure: Regenerated using autoconf 2.13. 2006-09-07 Zoran Vasiljevic * unix/tclUnixChan.c Rewritten MT-safe wrappers to * unix/tclUnixCompat.c return ptrs to TSD storage * unix/tclUnixFCmd.c making them all look like their * unix/tclUnixPort.h MT-unsafe pendants API-wise. * unix/tclUnixSock.c 2006-09-06 Zoran Vasiljevic * unix/tclUnixChan.c: Added TCL_THREADS ifdef'ed usage * unix/tclUnixFCmd.c: of MT-safe calls like: * unix/tclUnixSock.c: getpwuid, getpwnam, getgrgid, getgrnam, * unix/tclUnixPort.h: gethostbyname and gethostbyaddr. * unix/Makefile.in: See Tcl Bug: 999544 * unix/configure.in: * unix/tcl.m4: * unix/configure: Regenerated. * unix/tclUnixCompat.c: New file containing MT-safe implementation of some library calls. 2006-09-04 Don Porter * tests/main.text (Tcl_Main-4.4): Test corrected to not be timing sensitive to the Bug 1481986 fix. [Bug 1550858] 2006-09-04 Jeff Hobbs * doc/package.n: correct package example 2006-08-30 Jeff Hobbs * win/tclWinChan.c: [Bug 819667] Improve logic for identifying COM ports. * win/tclWinFCmd.c: [Bug 1548263] Added test for NULL return * generic/tclIOUtil.c: from Tcl_FSGetNormalizedPath which was causing segv's * generic/tclFileName.c (TclDoGlob): match incr with existing decr. * unix/Makefile.in: add valgrindshell target and update default VALGRINDARGS. User can override, or add to it with VALGRIND_OPTS env var. * generic/tclBasic.c (Tcl_CreateInterp): init iPtr->threadId * generic/tclIOGT.c (ExecuteCallback): * generic/tclPkg.c (Tcl_PkgRequireEx): replace Tcl_GlobalEval(Obj) with more efficient Tcl_Eval(Obj)Ex 2006-08-22 Andreas Kupries * unix/tclUnixNotfy.c (Tcl_WaitForEvent): Fixed broken if syntax committed 2006-08-21 by Daniel. The broken syntax is visible to all unix platforms, but not on OSX for machines which HAVE_COREFOUNDATION. 2006-08-21 Don Porter * generic/tclIOUtil.c: Revisions to complete the thread finalization of the cwdPathPtr. [Bug 1536142] 2006-08-21 Daniel Steffen * macosx/tclMacOSXNotify.c (Tcl_WaitForEvent): if the run loop is already running (e.g. if Tcl_WaitForEvent was called recursively), re-run it in a custom run loop mode containing only the source for the notifier thread, otherwise wakeups from other sources added to the common run loop modes might get lost; sync panic msg changes from HEAD. * unix/tclUnixNotfy.c (Tcl_WaitForEvent): on 64-bit Darwin, pthread_cond_timedwait() appears to have a bug that causes it to wait forever when passed an absolute time which has already been exceeded by the system time; as a workaround, when given a very brief timeout, just do a poll on that platform. [Bug 1457797] * unix/tclUnixPort.h (Darwin): override potentially faulty configure detection of termios availability in all cases, since termios is known to be present on all Mac OS X releases since 10.0. [Bug 497147] 2006-08-18 Daniel Steffen * unix/tcl.m4 (Darwin): add support for --enable-64bit on x86_64, for universal builds including x86_64, for 64-bit CoreFoundation on Leopard and for use of -mmacosx-version-min instead of MACOSX_DEPLOYMENT_TARGET. * unix/configure: autoconf-2.13 * generic/tcl.h: add fixes for building on Leopard and support * unix/tclUnixPort.h: for 64-bit CoreFoundation on Leopard. * unix/tclUnixPort.h: on Darwin x86_64, disable use of vfork as it causes execve to fail intermittently. (rdar://4685553) * macosx/README: updates for x86_64 support and Xcode 2.4. * unix/tclUnixChan.c (TclUnixWaitForFile): with timeout < 0, if select() returns early (e.g. due to a signal), call it again instead of returning a timeout result. Fixes intermittent event-13.8 failures. 2006-08-09 Don Porter * generic/tclEncoding.c: Replace buffer copy in for loop with call to memcpy(). Thanks to afredd. [Patch 1530262] 2006-08-03 Daniel Steffen * unix/tclUnixPipe.c (TclpCreateProcess): for USE_VFORK: ensure standard channels are initialized before vfork() so that the child doesn't potentially corrupt global state in the parent's address space. 2006-07-30 Kevin Kenny * tests/clock.test: Allowed UTC as a synonym for GMT in two tests that indirectly invoke 'strftime' with the result of 'gmtime' to fix a bogus test failure on FreeBSD systems. [Bug 1513489] 2006-07-30 Joe English * doc/AppInit.3: Fix typo [Bug 1496886] 2006-07-20 Daniel Steffen * macosx/tclMacOSXNotify.c (Tcl_InitNotifier, Tcl_WaitForEvent): create notifier thread lazily upon first call to Tcl_WaitForEvent() rather than in Tcl_InitNotifier(). Allows calling exeve() in processes where the event loop has not yet been run (Darwin's execve() fails in processes with more than one thread), in particular allows embedders to call fork() followed by execve(), previously the pthread_atfork() child handler's call to Tcl_InitNotifier() would immediately recreate the notifier thread in the child after a fork. * macosx/tclMacOSXNotify.c (Tcl_InitNotifier): add support for * unix/tclUnixFCmd.c (DoRenameFile, CopyFileAtts): weakly importing * unix/tclUnixInit.c (TclpSetInitialEncodings): symbols not available on OSX 10.2 or 10.3, enables binaires built on later OSX versions to run on earlier ones. * macosx/README: document how to enable weak-linking; cleanup. * unix/tclUnixPort.h: add support for weak-linking; conditionalize AvailabilityMacros.h inclusion; only disable realpath on 10.2 or earlier when threads are enabled. * unix/tclLoadDyld.c (TclpLoadMemoryGetBuffer): change runtime Darwin * unix/tclUnixInit.c (TclpInitPlatform): release check to use global initialized once * unix/tclUnixFCmd.c (DoRenameFile, TclpObjNormalizePath): add runtime Darwin release check to determine if realpath is threadsafe. * unix/configure.in: add check on Darwin for compiler support of weak * unix/tcl.m4: import and for AvailabilityMacros.h header; move Darwin specific checks & defines that are only relevant to the tcl build out of tcl.m4; restrict framework option to Darwin; cleanup quoting. * unix/configure: autoconf-2.13 * unix/tclLoadDyld.c (TclpLoadMemory): * unix/tclUnixPipe.c (TclpCreateProcess): fix signed-with-unsigned comparison and other warnings from gcc4 -Wextra. 2006-07-13 Andreas Kupries * unix/tclUnixPort.h: Added the inclusion of . The missing header caused the upcoming #if conditions to wrongly exclude realpath, causing file normalize to ignore symbolic links in the path. 2006-07-11 Zoran Vasiljevic * generic/tclAsync.c: Made Tcl_AsyncDelete() more tolerant when called after all thread TSD has been garbage-collected. 2006-07-10 Jeff Hobbs * generic/tclIO.c (Tcl_CreateChannel): allow Tcl std channel inheritance to be #defined out (default remains in). 2006-06-15 Don Porter * changes: changes to start prep for an 8.4.14 release. 2006-06-14 Daniel Steffen * unix/tclUnixPort.h (Darwin): support for MAC_OS_X_VERSION_MAX_ALLOWED define from AvailabilityMacros.h: override configure detection and only use API available in the indicated OS version or earlier. 2006-06-14 Pat Thoyts * generic/regerror.c: Enable building Tcl with Microsoft's latest * generic/tcl.h: compiler offering (VS2005). We have to handle * generic/tclDate.c: a number of oddities as they have deprecated * tests/env.test: most of the standard C library and now * win/makefile.vc: generate manifest files to be linked into the * win/nmakehlp.c: binaries. [Bug 1424909] * win/rules.vc: * win/tclWinTime.c: 2006-06-13 Donal K. Fellows * unix/tclLoadDl.c (TclpDlopen): Workaround for a compiler bug in Sun Forte 6. [Bug 1503729] 2006-06-06 Don Porter * doc/GetStdChan.3: Added recommendation that each call to Tcl_SetStdChannel() be accompanied by a call to Tcl_RegisterChannel(). 2006-05-31 Jeff Hobbs * generic/tclNamesp.c (NamespaceInscopeCmd): revert [Bug 1400572] fix of 2006-01-09 for [namespace inscope] as it seems to mess with itcl scope decoding. Leaving namespace-29.6 test failure until final cause it determined. 2006-05-29 Jeff Hobbs * generic/tcl.h (Tcl_DecrRefCount): use if/else construct to allow placement in unbraced outer if/else conditions. (jcw) 2006-05-27 Daniel Steffen * macosx/tclMacOSXNotify.c: implemented pthread_atfork() handler that * unix/tcl.m4 (Darwin): recreates CoreFoundation state and notifier thread in the child after a fork(). Note that pthread_atfork() is available starting with Tiger only. Because vfork() is used by the core on Darwin, [exec]/[open] are not affected by this fix, only extensions or embedders that call fork() directly (such as TclX). However, this only makes fork() safe from corefoundation tcl with --disable-threads; as on all platforms, forked children may deadlock in threaded tcl due to the potential for stale locked mutexes in the child. [Patch 923072] * unix/configure: autoconf-2.59 2006-05-24 Donal K. Fellows * unix/tcl.m4 (SC_CONFIG_SYSTEM): Fixed quoting of command script to awk; it was a rarely used branch, but it was wrong. [Bug 1494160] 2006-05-13 Don Porter * generic/tclFileName.c (TclDoGlob): Disabled the partial normalization done by the recursive glob routine, since changing the precise string of the pathname broke [glob] on some Tcl_Filesystems. [Bug 943995] * generic/tclProc.c (ProcCompileProc): When a bump of the compile epoch forces the re-compile of a proc body, take care not to overwrite any Proc struct that may be referred to on the active call stack. This fixes [Bug 1482718]. Note that the fix will not be effective for code that calls the private routine TclProcCompileProc() directly. 2006-05-05 Don Porter * generic/tclMain.c (Tcl_Main): Corrected flaw that required * tests/main.test: (Tcl_Main-4.5): processing of one interactive command before passing control to the loop routine registered with Tcl_SetMainLoop() [Bug 1481986] 2006-05-04 Don Porter * README: Bump version number to 8.4.14 * generic/tcl.h: * tools/tcl.wse.in: * unix/configure.in: * unix/tcl.spec: * win/README.binary: * win/configure.in: * unix/configure: autoconf-2.13 * win/configure: * generic/tclExecute.c (ExprSrandFunc): Restore acceptance of wide * tests/expr-old.test: integer values by srand() [Bug 1480509] 2006-04-12 Don Porter *** 8.4.13 TAGGED FOR RELEASE *** * changes: updates for another RC. 2006-04-11 Don Porter * generic/tclCmdMZ.c: Stop some interference between enter traces * tests/trace.test: and enterstep traces. [Bug 1458266] 2006-04-10 Don Porter * changes: updates for another RC. 2006-04-06 Jeff Hobbs * generic/tclRegexp.c (FinalizeRegexp): full reset data to indicate readiness for reinitialization. 2006-04-06 Don Porter * generic/tclIndexObj.c (Tcl_GetIndexFromObjStruct): It seems there * tests/indexObj.test: are extensions that rely on the prior behavior * doc/GetIndex.3: that the empty string cannot succeed as a unique prefix matcher, so I'm restoring Donal Fellows's solution. Added mention of this detail to the documentation. [Bug 1464039] 2006-04-06 Daniel Steffen * unix/tcl.m4: removed TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING define on Darwin. [Bug 1457515] * unix/configure: autoconf-2.13 2006-04-05 Don Porter * library/reg/pkgIndex.tcl: Long overlooked bump to registry * win/tclWinReg.c: package version 1.1.4 (should have been done for the Tcl 8.4.8 release!) * library/dde/pkgIndex.tcl: Long overlooked bump to dde package * win/tclWinDde.c: version 1.2.4 (should have been done for the Tcl 8.4.8 release!) 2006-04-05 Donal K. Fellows * generic/tclIndexObj.c (Tcl_GetIndexFromObjStruct): Allow empty strings to be matched by the Tcl_GetIndexFromObj machinery, in the same manner as any other key. [Bug 1464039] 2006-04-04 Don Porter * generic/tclPkg.c: Revised Bug 1162286 fix from 2005-11-08 to be * tests/pkg.test: even more forgiving of package version mismatch errors in [package ifneeded] commands, not even logging any warning messages. This further reduces the ***POTENTIAL INCOMPATIBILITY*** noted for that change. 2006-04-03 Andreas Kupries * generic/tclIO.c (ReadChars): Added check, panic and commentary to a piece of code which relies on BUFFER_PADDING to create enough space at the beginning of each buffer for the insertion of partial multibyte data at the beginning of a buffer. Commentary explains why this code is OK, and the panic is as a precaution if someone twiddled the BUFFER_PADDING into uselessness. * generic/tclIO.c (ReadChars): Temporarily suppress the use of TCL_ENCODING_END set when EOF was reached while the buffer we are converting is not truly the last buffer in the queue. Together with the Utf bug below it was possible to completely wreck the buffer data structures, eventually crashing Tcl. [Bug 1462248] * generic/tclEncoding.c (UtfToUtfProc): Stop accessing memory beyond the end of the input buffer when TCL_ENCODING_END is set and the last bytes of the buffer start a multi-byte sequence. This bug contributed to [Bug 1462248]. 2006-03-28 Jeff Hobbs * win/configure, win/tcl.m4: define MACHINE for gcc builds as well. Needed by Tk for manifest generation. * win/tclWinConsole.c: revert 2005-11-03 [Patch 1256872] change to add win32 unicode console support as it broke the ability to modify the encoding to the console. 2006-03-28 Daniel Steffen * unix/tclUnixFCmd.c (TclpObjNormalizePath): deal with *BSD/Darwin realpath() converting relative paths into absolute paths. [Bug 1064247] 2006-03-28 Vince Darley * generic/tclIOUtil.c: fix to nativeFilesystemRecord comparisons (lesser part of [Bug 1064247]) 2006-03-27 Pat Thoyts * win/tclWinTest.c: Fixes for [Bug 1456373] (mingw-gcc issue) 2006-03-23 Don Porter * tests/expr.test: Nan self-inquality test silenced. [Bug 761471] 2006-03-22 Don Porter * changes: updates for another RC. 2006-03-18 Vince Darley * generic/tclTest.c: * win/tclWinFile.c: * win/tclWinTest.c: * tests/fCmd.test: * tests/winFCmd.test: * tests/tcltest.test: Backport of [file writable] fixes for Windows from HEAD. [Bug 1193497] 2006-03-16 Andreas Kupries * doc/open.n: Documented the changed behaviour of 'a'ppend mode. * tests/io.test (io-43.1 io-44.[1234]): Rewritten to be self-contained with regard to setup and cleanup. [Bug 681793] * generic/tclIOUtil.c (TclGetOpenMode): Added the flag O_APPEND to the list of POSIX modes used when opening a file for 'a'ppend. This enables the proper automatic seek-to-end-on-write by the OS. See [Bug 680143] for longer discussion. * tests/ioCmd.test (iocmd-13.7.*): Extended the testsuite to check the new handling of 'a'. 2006-03-15 Andreas Kupries * tests/socket.test: Extended the timeout in socket-11.11 from 10 to 40 seconds to allow for really slow machines. Also extended actual/expected results with value of variable 'done' to make it clearer when a test fails due to a timeout. [Bug 792159] 2006-03-14 Andreas Kupries * generic/tclPipe.c (TclCreatePipeline): Modified the processing of pipebars to fail if the last bar is followed only by redirections. [Bug 768659] 2006-03-14 Andreas Kupries * doc/fconfigure.n: Clarified that -translation is binary is reported as lf when queried, because it is identical to lf, except for the special additional behaviour when setting it. [Bug 666770] 2006-03-14 Andreas Kupries * win/tclWinPipe.c (Tcl_WaitPid): Backport of fix made to the head by David Gravereaux in 2004. See ChangeLog entry 2004-01-19. [Bug 1381436] Fixed a thread-safety problem with the process list. The delayed cut operation after the wait was going stale by being outside the list lock. It now cuts within the lock and does a locked splice for when it needs to instead. [Bug 859820] 2006-03-13 Don Porter * generic/tclEncoding.c: Report error when an escape encoding is missing one of its sub-encodings [Bug 506653] * unix/configure.in: Revert change from 2005-07-26 that sometimes * unix/configure: added $prefix/share to the tcl_pkgPath. See [Patch 1231015]. autoconf-2.13. 2006-03-10 Zoran Vasiljevic -- Summary of changes fixing [Bug 1437595] -- * generic/tclEvent.c: Cosmetic touches and identation * generic/tclInt.h: Added TclpFinalizeSockets() call. * generic/tclIO.c: Calls TclpFinalizeSockets() as part of the TclFinalizeIOSubsystem(). * unix/tclUnixSock: Added no-op TclpFinalizeSockets(). * mac/tclMacSock.c: * win/tclWinPipe.c * win/tclWinSock.c: Finalization of the sockets/pipes is now solely done in TclpFinalizeSockets() and TclpFinalizePipes() and not over the thread-exit handler, because the order of actions the Tcl generic core will impose may result in cores/hangs if the thread exit handler tears down corresponding subsystem(s) too early. 2006-03-10 Vince Darley * win/tclWin32Dll.c: * win/tclWinInt.h: * win/tclWinFile.c: backported some fixes from HEAD relating to 'file readable' and 'file writable', but main 'file writable' bug still outstanding. 2006-03-07 Don Porter * README: Bump version number to 8.4.13 and update * changes: changes to start prep for an 8.4.13 release. * generic/tcl.h: * tools/tcl.wse.in: * unix/configure{.in}: * unix/tcl.spec: * win/README.binary: * win/configure{.in}: * tests/parse.test: Missing constraint 2006-03-06 Don Porter * generic/tclBasic.c: Revised handling of TCL_EVAL_* flags to * tests/parse.test: simplify TclEvalObjvInternal and to correct the auto-loading of alias targets (parse-8.12). [Bug 1444291] 2006-03-02 Jeff Hobbs * win/Makefile.in: convert _NATIVE paths to use / to avoid ".\" path-as-escape issue. * unix/tcl.m4, win/tcl.m4: []-quote ac_defun functions. 2006-03-02 Pat Thoyts * unix/tcl.m4: Fix for [Tk Bug 1334613] to sort out shared library * unix/configure: issues on NetBSD. Regenerated configure script. 2006-02-28 Don Porter * generic/tclBasic.c: Corrections to be sure that TCL_EVAL_GLOBAL * tests/parse.test: evaluations act the same as [uplevel #0] * tests/trace.test: evaluations, even when execution traces or invocations of [::unknown] are present. [Bug 1439836] 2006-02-16 Don Porter * generic/tclIndexObj.c: Disallow the "ambiguous" error message * tests/indexObj.test: when TCL_EXACT matching is requested. 2006-02-15 Don Porter * generic/tclIO.c: Made several routines tolerant of * generic/tclIOUtil.c: interp == NULL arguments. [Bug 1380662] 2006-02-09 Don Porter * tests/main.test (Tcl_Main-6.7): Improved robustness of command auto-completion test. [Bug 1422736] 2006-01-25 Donal K. Fellows * unix/tclUnixInit.c (TclpInitPlatform): Improved conditions on when to update the FP rounding mode on FreeBSD, taken from FreeBSD port. 2006-01-23 Miguel Sofer * generic/tclStringObj.c (Tcl_GetRange): * tests/stringTest (string-12.21):fixed incorrect handling of internal rep in Tcl_GetRange. Thanks to twylite and Peter Spjuth. [Bug 1410553] 2006-01-16 Reinhard Max * generic/tclPipe.c (FileForRedirect): Prevent nameString from being freed without having been initialized. * tests/exec.test: Added a test for the above. 2006-01-12 Zoran Vasiljevic * generic/tclIOUtil.c (Tcl_FSGetInternalRep): fixed potential overwriting of already freed memory which caused all kinds of (rare but reproducible) coredumps all over the place. 2006-01-11 Don Porter * tests/error.test (error-7.0): Test the timing of write traces on ::errorInfo. [Bug 1397843] 2006-01-10 Daniel Steffen * unix/configure: add caching, use AC_CACHE_CHECK instead of * unix/configure.in: AC_CACHE_VAL where possible, consistent message * unix/tcl.m4: quoting, sync relevant tclconfig/tcl.m4 and HEAD changes and gratuitous formatting differences, fix SC_CONFIG_MANPAGES with default argument, Darwin improvements to SC_LOAD_*CONFIG. 2006-01-09 Don Porter * generic/tclNamesp.c (NamespaceInscopeCmd): [namespace inscope] * tests/namespace.test: commands were not reported by [info level]. [Bug 1400572] 2005-12-20 Donal K. Fellows * generic/tclThreadAlloc.c (Tcl_GetMemoryInfo): Format values as longs and not ints, so they are less likely to wrap on 64-bit machines. 2005-12-19 Donal K. Fellows * doc/Tcl.n: Clarify what is going on in variable substitution following thread on comp.lang.tcl. 2005-12-14 Daniel Steffen * generic/tclIOUtil.c: workaround gcc warning "comparison is always * generic/tclTest.c: false due to limited range of data type". * unix/configure.in: run check for fts API on all platforms, since Linux glibc2 and *BSDs also have this and using fts is more efficient than recursive opendir/readdir (sync with HEAD). * unix/configure: regen. 2005-12-12 Jeff Hobbs * unix/tcl.m4, unix/configure: Fix sh quoting error reported in bash-3.1+ [Bug 1377619] (schafer) 2005-12-12 Reinhard Max * generic/tclExecute.c (ExprAbsFunc): fixed the abs(MIN_INT) case so that it doesn't break on compilers that don't assume integers to wrap around (e.g. gcc-4.1.0). 2005-12-09 Donal K. Fellows * tests/lsearch.test (lsearch-10.8..10): If the -start is off the end, * generic/tclCmdIL.c (Tcl_LsearchObjCmd): searching should find nothing at all. [Bug 1374778] 2005-12-05 Daniel Steffen *** 8.4.12 TAGGED FOR RELEASE *** * unix/tclUnixPort.h (Darwin): fix incorrect __DARWIN_UNIX03 configure overrides that were originally copied from Darwin CVS (rdar://3693001). 2005-12-05 Don Porter * unix/configure.in: Revised fix for [Bug 1034337] from Daniel * unix/tclUnixFCmd.c: Steffen. Uses fts_*() routines. * unix/configure: autoconf-2.13 * changes: Update changes for 8.4.12 release 2005-12-04 Daniel Steffen * README: refer to macosx/README instead of mac/README. * mac/README: add note that mac classic port is no longer supported. 2005-12-03 Jeff Hobbs * README: correct 2 urls 2005-12-01 Don Porter * changes: Update changes for 8.4.12 release 2005-12-01 Daniel Steffen * unix/tcl.m4 (Darwin): fixed error when MACOSX_DEPLOYMENT_TARGET unset * unix/configure: regen. 2005-11-29 Jeff Hobbs * win/tcl.m4: Add build support for Windows-x64 builds. * win/configure: --enable-64bit now accepts =amd64|ia64 for * win/Makefile.in: Windows 64-bit build variants (default: amd64) * win/makefile.vc: [Bug 1369597] 2005-11-29 Donal K. Fellows * generic/tclObj.c (Tcl_GetWideIntFromObj): Add more efficient conversion to wides from normal ints. [Bug 1310081] * generic/tclCmdIL.c (Tcl_LsearchObjCmd): Allow [lsearch -regexp] to process REs that contain backreferences. This expensive mode of operation is only used if the RE would otherwise cause a compilation failure. [Bug 1366683] 2005-11-28 Donal K. Fellows * win/tclWinSock.c (CreateSocket): Applied [Patch 1353853] to prevent reads of uninitialized variables during cleanup. 2005-11-27 Daniel Steffen * unix/tcl.m4 (Darwin): add 64bit support, check for Tiger copyfile(), add CFLAGS to SHLIB_LD to support passing -isysroot in env(CFLAGS) to configure (flag can't be present twice, so can't be in both CFLAGS and LDFLAGS during configure), don't use -prebind when deploying on 10.4, define TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING (rdar://3171542). (SC_ENABLE_LANGINFO, SC_TIME_HANDLER): add/fix caching, fix obsolete autoconf macros. Sync with tk/unix/tcl.m4, sync whitespace with HEAD. * unix/configure.in: fix obsolete autoconf macros, sync gratuitous formatting/ordering differences with tk/unix/configure.in. * unix/Makefile.in: add CFLAGS to tclsh/tcltest link to make executable linking the same as during configure (needed to avoid loosing any linker relevant flags in CFLAGS, in particular flags that can't be in LDFLAGS). Avoid concurrent linking of tclsh and compiling of tclTestInit.o or xtTestInit.o during parallel make. (checkstubs, checkdoc, checkexports): dependency and Darwin fixes * unix/tclLoadDyld.c (TclpDlopen): [Bug 1204237] use NSADDIMAGE_OPTION_WITH_SEARCHING on second NSAddImage only. (TclGuessPackageName): should not be MODULE_SCOPE. (TclpLoadMemory): ppc64 and endian (i386) fixes, add support for loading universal (fat) bundles from memory. * unix/tclUnixPort.h: * unix/tclUnixFCmd.c: add support for new Tiger copyfile() API to enable copying of xattrs & ACLs by [file copy]. * generic/tcl.h: add Darwin specifc configure overrides for TCL_WIDE defines to support fat compiles of ppc and ppc64 at the same time, (replaces Darwin CVS fix by emoy, rdar://3693001). add/correct location of version numbers in macosx files. * generic/tclInt.h: clarify fat compile comment. * unix/tclUnixPort.h: add Darwin specifc configure overrides to support fat compiles, where configure runs only once for multiple architectures (replaces Darwin CVS fix by emoy, rdar://3693001). * macosx/tclMacOSXBundle.c: * macosx/tclMacOSXNotify.c: * unix/tclUnixNotfy.c: fix #include order to support compile time * unix/tclUnixPort.h: override of HAVE_COREFOUNDATION in tclUnixPort.h when building for ppc64 * macosx/Tcl.pbproj/default.pbxuser (new file): * macosx/Tcl.pbproj/jingham.pbxuser: * macosx/Tcl.pbproj/project.pbxproj: sync with HEAD. * macosx/README: clarification/cleanup, sync with HEAD, document universal (fat) builds via CFLAGS (i.e. all of ppc ppc64 i386 at once). * macosx/Makefile: add support for reusing configure cache, build target fixes, remove GENERIC_FLAGS override now handled by tcl.m4. * generic/tclIOUtil.c: * generic/tclRegexp.c: * generic/tclVar.c: declare globals used only in own file as static (sync with HEAD). * generic/rege_dfa.c (getvacant): * generic/regexec.c (cfind): * generic/tclCompExpr.c (CompileSubExpr): * unix/tclUnixChan.c (TclUnixWaitForFile): initialise variables to silence gcc 4 warnings. * generic/regguts.h: only #define NDEBUG if not already #defined. * macosx/tclMacOSXNotify.c: sync whitespace & comments with HEAD * unix/configure: regen. 2005-11-20 Joe English * generic/tclStubLib.c: Don't set tclStubsPtr to 0 when Tcl_PkgRequireEx() fails [Fix for [Bug 1091431] "Tcl_InitStubs failure crashes wish"] 2005-11-18 Miguel Sofer * tests/trace.test (trace-34.5): [Bug 1047286], added a second test illustrating the role of "ns in callStack" in the ns's visibility during deletion traces. * generic/tclBasic.c (Tcl_DeleteCommandFromToken): * generic/tclCmdMZ.c (TraceCommandProc): * generic/tclInt.h (NS_KILLED): * generic/tclNamesp.c (Tcl_DeleteNamespace * tests/namespace.test (namespace-7.3-6): * tests/trace.test (trace-20.13-16): fix [Bugs 1355942/1355342]. 2005-11-18 Jeff Hobbs * generic/tclIO.c (TclFinalizeIOSubsystem): preserve statePtr until we netrieve next statePtr from it. 2005-11-18 Don Porter * generic/tclPkg.c: Revised Bug 1162286 fix from 2005-11-08 to be * tests/pkg.test: more forgiving of package version mismatch errors in [package ifneeded] commands. This reduces the ***POTENTIAL INCOMPATIBILITY*** noted for that change. 2005-11-18 Andreas Kupries * generic/tclIO.c (TclFinalizeIOSubsystem): Applied Pat Thoyts' patch for [Bug 1359094]. This moves the retrieval of the next channel state to the end of the loop, as the called closeproc may close other channels, i.e., modify the list we are iterating, invalidating any pointer retrieved earlier. 2005-11-18 Donal K. Fellows * library/http/http.tcl (http::geturl): Improved syntactic validation of URLs, and better error messages in some cases. [Bug 1358369] 2005-11-16 Don Porter * README: Bump version number to 8.4.12 * generic/tcl.h: * tools/tcl.wse.in: * unix/configure.in: * unix/tcl.spec: * win/README.binary: * win/configure.in: * unix/configure: autoconf-2.13 * win/configure: 2005-11-15 Don Porter * changes: Update changes for 8.4.12 release 2005-11-15 Kevin B. Kenny * tests/cmdAH.test: Backported the fix for [Bug 926016] because of * win/tclWinFile.c: a repeated bug report in 8.4 [Bug 1353840]. Windows [file mtime] will now return seconds from the Posix epoch correctly (except for FAT32 file systems after a DST change without a reboot - for which there is no help). A side effect is that file times will appear different in Tcl from the way they do in Windows Explorer or a 'dir' listing, because the Microsoft tools get the DST state wrong in the listings. 2005-11-09 Kevin B. Kenny * generic/tclTimer.c: Changed [after] so that it behaves correctly * tests/timer.test: with negative arguments. [Bug 1350293] 2005-11-08 Jeff Hobbs * unix/tclUnixFCmd.c (MAX_READDIR_UNLINK_THRESHOLD): reduce to 130 based on errors seen on OS X 10.3 with lots of links in a dir. [Bug 1034337 followup] 2005-11-08 Don Porter * tests/expr.test: Portable tests expr-46.13-18 [Bug 1341368] * generic/tclPkg.c: Corrected inconsistencies in the value returned * tests/pkg.test: by Tcl_PkgRequire(Ex) so that the returned values will always agree with what is stored in the package database. This way repeated calls to Tcl_PkgRequire(Ex) have the same results. Thanks to Hemang Lavana. [Bug 1162286] ***POTENTIAL INCOMPATIBILITY***: Incompatible with those existing packages that are accustomed to the [package] command forgiving their bugs. * tests/namespace.test (25.7,8): Backport test of knownBug. 2005-11-08 Donal K. Fellows * generic/tclCmdMZ.c (TclTraceVariableObjCmd, TraceVarProc): Applied Miguel's fix for [Bug 1348775]. It is not quite as elegant as the one applied to the HEAD, but it is easier to use it rather than fully backporting. 2005-11-07 Miguel Sofer * tests/trace.test (trace-13.2-4): added tests to detect leak, see [Bug 1348775]. 2005-11-04 Don Porter * unix/tcl.m4: Added code to enable [load] on LynxOS. Thanks to heidibr@users.sf.net for the patch. [Bug 1163896] * unix/configure: autoconf-2.13. 2005-11-04 Pat Thoyts * win/tclWinPipe.c: Applied [Patch 1267871] by Matt Newman which * win/tclWinPort.h: provides extended error code support. * tests/exec.test: Wrote some tests for this feature. 2005-11-04 Kevin Kenny * generic/tclGetDate.y: Added abbreviations for the Korean timezone. * generic/tclDate.c: Regenerated. * compat/strftime.c: Fixed a problem where the name of the time zone was double-converted from system encoding to UTF-8. Thanks to the anonymous submitter of [Bug 1317477] for the report and the patch. 2005-11-04 Miguel Sofer * generic/tclInt.h: * generic/tclNamesp.c: * generic/tclVar.c: fix for [Bugs 1338280/1337229]. Thanks Don. * tests/trace.test: fix duplicate test numbers 2005-11-03 Don Porter * generic/tclUnixInit.c (TclpSetInitialEncodings): Modified so that multiple calls can continue to atttempt to properly set the system encoding. Needed for Tclkit to properly support non-default encodings. Thanks to Yaroslav Schekin. [Bug 1201171] 2005-11-03 Pat Thoyts * win/tclWin32Dll.c: Backported Anton Kovalenko's [Patch 1256872] * win/tclWinConsole.c: to give unicode console support on * win/tclWinInt.h: suitable systems (eg: NT/XP) 2005-11-01 Don Porter * generic/tclCmdMZ.c (TclCheckExecutionTraces): Corrected mistaken assumption that all command traces are set at the script level. Report/fix from Jacques H. de Villiers. [Bug 1337941] * tests/expr-old.test (expr-32.52): Use int(.) to restrict result of left shift to the C long range. 2005-10-29 Mo DeJong * tests/expr.test: Fix problems in new round() tests that lead to correct result only on 32 bit long systems. [Bug 1341368] 2005-10-29 Miguel Sofer * generic/tclCmdMZ.c (TraceVarProc): [Bug 1337229], partial fix. Ensure that a second call with TCL_TRACE_DESTROYED does not lead to a second call to Tcl_EventuallyFree(). It is still true that that second call should not happen, so the bug is not completely fixed. * tests/trace.test (test-18.3-4): added tests for [Bugs 1337229 and 1338280]. 2005-10-27 Mo DeJong * generic/tclExecute.c (ExprRoundFunc): Fix typo where number before rounding is compared with smallest integer instead of number after rounding. This fix does not change the results of any tests. * tests/expr.test: Add round() tests for cases near the min and max int values. * tests/util.test: Remove pointless warning code about testobj command 2005-10-23 Miguel Sofer * generic/tclBasic.c: * generic/tclBinary.c: * generic/tclCmdAH.c: * generic/tclCmdIL.c: * generic/tclCmdMZ.c: * generic/tclExecute.c: * generic/tclLink.c: * generic/tclMain.c: * generic/tclProc.c: * generic/tclScan.c: * generic/tclTest.c: * generic/tclVar.c: * mac/tclMacInit.c: * unix/tclUnixInit.c: * win/tclWinInit.c: Ensure that the core never calls TclPtrSetVar, Tcl_SetVar2Ex, Tcl_ObjSetVar2 or Tcl_SetObjErrorCode with a 0-ref new value. It is not possible to handle error returns correctly in that case [Bug 1334947], one has the choice of leaking the object in some cases, or else risk crashing in some others. 2005-10-22 Miguel Sofer * generic/tclExecute.c (INST_CONCAT): disable the optimisation for wide integers. [Bug 1251791] 2005-10-14 Zoran Vasiljevic * generic/tclIO.c (Tcl_ClearChannelHandlers): removed change dated 2005-10-04 below. Look into [Bug 1323992] for detailed discussion. 2005-10-13 Donal K. Fellows * generic/tclCmdAH.c (Tcl_FormatObjCmd): Stop [format] from seeing the difference between ints and wides. [Bug 1284178] 2005-10-13 Zoran Vasiljevic * generic/tclIO.c (Tcl_ClearChannelHandlers): temporary ifdef TCL_THREADS changes done to de-activate pending event processing when channel is being closed/cutted. 2005-10-10 Jeff Hobbs * generic/tclInt.h: ensure MODULE_SCOPE decl 2005-10-07 Jeff Hobbs * unix/tclUnixFCmd.c (TraverseUnixTree): Adjust 2004-11-11 change to * tests/fCmd.test (fCmd-20.2): account for NFS special files with a readdir rewind threshold. [Bug 1034337] 2005-10-05 Andreas Kupries * generic/tclPipe.c (TclCreatePipeline): Fixed [Bug 1109294]. Applied the patch provided by David Gravereaux. * doc/CrtChannel.3: Fixed [Bug 1104682], by application of David Welton's patch for it, and added a note about wideSeekProc. 2005-10-05 Jeff Hobbs * tests/env.test (env-6.1): * win/tclWinPort.h: define USE_PUTENV_FOR_UNSET 1 * generic/tclEnv.c (TclSetEnv, TclUnsetEnv): add USE_PUTENV_FOR_UNSET to existing USE_PUTENV define to account for various systems that have putenv(), but can't unset env vars with it. Note difference between Windows and Linux for actually unsetting the env var (use of '='). Correct the resizing of the environ array. We assume that we are in full ownership, but that's not correct. [Bug 979640] 2005-10-04 Jeff Hobbs * win/tclWinSerial.c (SerialSetOptionProc): free argv [Bug 1067708] * tests/http.test: Do not URI encode -._~ according to * library/http/http.tcl (init): RFC3986. [Bug 1182373] (aho) * generic/tclIOUtil.c (TclFSNormalizeAbsolutePath): make static * generic/tclEncoding.c (TclFindEncodings): make static * unix/tclLoadShl.c (TclpDlopen): use DYNAMIC_PATH on second shl_load only. [Bug 1204237] 2005-10-04 Zoran Vasiljevic * generic/tclIO.c (Tcl_ClearChannelHandlers): now deletes any outstanding timer for the channel. Also, prevents events still in the event queue from triggering on the current channel. * generic/tclTimer.c (Tcl_DeleteTimerHandler): bail out early if passed NULL argument. 2005-09-30 Don Porter * generic/tclMain.c: Separate encoding conversion of command line arguments from list formatting. [Bug 1306162] 2005-09-27 Donal K. Fellows * generic/tclBinary.c (FormatNumber): Factorize out copying of double values to a helper to work around ugly broken compiler problems. [Bug 1116542] 2005-09-15 Miguel Sofer * doc/ParseCmd.3: copy/paste fix [Bug 1292427] 2005-09-15 Donal K. Fellows * unix/tcl.m4 (SC_TCL_EARLY_FLAGS): Added extra hack to allow Tcl to transparently open large files on RHEL 3. [Bug 1287638] * unix/configure: autoconf-2.13 2005-09-07 Don Porter * generic/tclUtf.c (Tcl_UniCharToUtf): Corrected handling of negative * tests/utf.test (utf-1.5): Tcl_UniChar input value. Incorrect handling was producing byte sequences outside of Tcl's legal internal encoding. [Bug 1283976] 2005-08-29 Kevin Kenny * generic/tclBasic.c (ExprMathFunc): Restored "round away from zero" * tests/expr.test (expr-46.*): behaviour to the "round" function. Added test cases for the behavior, including the awkward case of a number whose fractional part is 1/2-1/2ulp. [Bug 1275043] 2005-08-25 Donal K. Fellows * generic/tclListObj.c (UpdateStringOfList): Stop uncontrolled and unsafe crashes from happening when working with very large string representations. [Bug 1267380] 2005-08-17 Jeff Hobbs * generic/tclFCmd.c (TclFileMakeDirsCmd): fix to race condition in file mkdir (backport from head 2005-06-13) [Bug 1217375] 2005-08-16 Kevin Kenny * generic/tclEvent.c (Tcl_Finalize): Pushed Tcl_FinalizeLoad and Tcl_ResetFilesystem down after Tcl_FinalizeThreadAlloc because unloading DLLs can't happen while they still own TSD keys. (This is a backport of changes made in the HEAD on 2005-08-10.) 2005-08-05 Donal K. Fellows * unix/tclUnixInit.c (localeTable): Solaris uses a non-standard name for the cp1251 charset. Thanks to Victor Wagner for reporting this. [Bug 1252475] 2005-08-05 Kevin Kenny * generic/tclExecute.c (TclExecuteByteCode): Fixed a corner case * tests/expr.test (expr-38.1): where applying abs to MIN_INT failed to promote the result to a wide integer. [Bug 1241572] 2005-08-04 Don Porter * generic/tclObj.c: Simplified routines that manage the typeTable. 2005-08-03 Don Porter * generic/tclCompExpr.c: Untangled some dependencies in the * generic/tclEvent.c: order of finalization routines. * generic/tclInt.h: [Bug 1251399] * generic/tclObj.c: 2005-07-30 Daniel Steffen * unix/configure, unix/tcl.m4: revert 2005-07-28 change. * unix/tclLoadDyld.c (TclpDlopen, TclpLoadMemory): workarounds for bugs/changes in behaviour in Mac OS X 10.4 Tiger, sync formatting changes from HEAD. 2005-07-29 Donal K. Fellows * generic/tclCmdIL.c (InfoGlobalsCmd): Even in high-speed mode, still have to take care with non-existant variables. [Bug 1247135] 2005-07-28 Mo DeJong * win/README: Update link to msys_mingw8.zip. Remove old Cygwin + Mingw info, people should just build with the msys + mingw configuration. 2005-07-28 Jeff Hobbs * unix/configure, unix/tcl.m4: defined TCL_LOAD_FROM_MEMORY on Darwin only for SHARED_BUILD 2005-07-28 Donal K. Fellows * generic/tclPipe.c (TclCreatePipeline): Arrange for POSIX systems to * unix/tclUnixPipe.c (TclpOpenFile): use the O_APPEND flag for * tests/exec.test (exec-19.1): files opened in a pipeline like ">>this". Note that Windows cannot support such access; there is no equivalent flag on the handle that can be set at the kernel-call level. The test is unix-specific in every way. [Bug 1245953] 2005-07-26 Mo DeJong * unix/configure: Regen. * unix/configure.in: Check for a $prefix/share directory and add it the the package if found. This will check for Tcl packages in /usr/local/share when Tcl is configured with the default dist install. [Patch 1231015] 2005-07-26 Don Porter * doc/tclvars.n: Improved $errorCode documentation. [RFE 776921] * generic/tclBasic.c (Tcl_CallWhenDeleted): Converted to use per-thread counter, rather than a process global one that required mutex protection. [RFE 1077194] * generic/tclNamesp.c (TclTeardownNamespace): Re-ordering so that * tests/trace.test (trace-34.4): command delete traces fire while the command still exists. [Bug 1047286] 2005-07-24 Mo DeJong * unix/tcl.m4 (SC_PROG_TCLSH, SC_BUILD_TCLSH): * win/tcl.m4 (SC_PROG_TCLSH, SC_BUILD_TCLSH): Split confused search for tclsh on PATH and build and install locations into two macros. SC_PROG_TCLSH searches just the PATH. SC_BUILD_TCLSH determines the name of the tclsh executable in the Tcl build directory. [Bug 1160114], [Patch 1244153] 2005-07-22 Don Porter * library/auto.tcl: Updates to the Tcl script library to make * library/history.tcl: use of Tcl 8.4 feautures. Thanks to * library/init.tcl: Patrick Fradin for prompting on this. * library/package.tcl: [Patch 1237755] * library/safe.tcl: * library/word.tcl: 2005-07-07 Jeff Hobbs * unix/tcl.m4, unix/configure: Backported [Bug 1095909], removing * unix/tclUnixPort.h: any use of readdir_r as it is not * unix/tclUnixThrd.c: necessary and just confuses things. 2005-07-05 Don Porter * generic/tclCmdAH.c: New "encoding" Tcl_ObjType (not registered) * generic/tclEncoding.c: that permits longer lifetimes of the * generic/tclInt.h: Tcl_Encoding values kept as intreps of Tcl_Obj's. Reduces the need for repeated reading of encoding definition files from the filesystem. [Bug 1077262] * generic/tclNamesp.c: Allow for [namespace import] of a command * tests/namespace.test: over a previous [namespace import] of itself without throwing an error. [RFE 1230597] 2005-07-01 Zoran Vasiljevic * unix/tclUnixNotfy.c: protect against spurious wake-ups while waiting on the condition variable when tearing down the notifier thread. [Bug 1222872] 2005-06-27 Don Porter *** 8.4.11 TAGGED FOR RELEASE *** * library/auto.tcl: Reverted to Revision 1.12.2.3 (Tcl 8.4.9). Restores the (buggy) behavior of [auto_reset] that fails to clear away auto-loaded commands from non-global namespaces. Fixing this bug exposed an unknown number of buggy files out there (including at least portions of the Tk script library) that cannot tolerate double [source]-ing. The burden of fixing these exposed bugs will not be forced on package/extension/application authors until Tcl 8.5. 2005-06-24 Kevin Kenny * generic/tclEvent.c (Tcl_Finalize): * generic/tclInt.h: * generic/tclPreserve.c (TclFinalizePreserve): Changed the finalization logic so that Tcl_Preserve finalizes after exit handlers run; a lot of code called from Tk's exit handlers presumes tha Tcl_Preserve will still work even from an exit handler. Also, made the assertion check that no exit handlers are created in Tcl_Finalize conditional on TCL_MEM_DEBUG to avoid spurious panics in the "stable" release. 2005-06-24 Don Porter * library/auto.tcl: Make file safe to re-[source] without destroying registered auto_mkindex_parser hooks. 2005-06-23 Daniel Steffen * tools/tcltk-man2html.tcl: fixed useversion glob pattern to accept multi-digit patchlevels. 2005-06-23 Kevin Kenny * win/tclWinChan.c: More rewriting of __asm__ blocks that * win/tclWinFCmd.c: implement SEH in GCC, because mingw's gcc 3.4.2 is not as forgiving of violations committed by the old code and caused panics. [Bug 1225957] 2005-06-23 Daniel Steffen * unix/Makefile.in (install-private-headers): rewrite tclPort.h when installing private headers to remove ../unix relative #include path to tclUnixPort.h (which is incorrect at the installed location). 2005-06-22 Kevin Kenny * generic/tclInt.h: Changed the finalization * generic/tclEvent.c (Tcl_Finalize): logic to defer the * generic/tclIO.c (TclFinalizeIOSubsystem): shutdown of the pipe * unix/tclUnixPipe.c (TclFinalizePipes): management until after * win/tclWinPipe.c (TclFinalizePipes): all channels have been closed, in order to avoid a situation where the Windows PipeCloseProc2 would re-establish the exit handler after exit handlers had already run, corrupting the heap. [Bug 1225727] Corrected a read of uninitialized memory in PipeCloseProc2, which (at least on certain configurations) caused a great number of tests to either fail or hang. [Bug 1225044] 2005-06-22 Andreas Kupries * generic/tclInt.h: Followup to change made on 2005-06-18 by Daniel Steffen. There are compilers (*) who error out on the redefinition of WORDS_BIGENDIAN. We have to undef the previous definition (on the command line) first to make this acceptable. (*): AIX native. 2005-06-22 Don Porter * win/tclWinFile.c: Potential buffer overflow. [Bug 1225571] Thanks to Pat Thoyts for discovery and fix. * tests/safe.test: Backport performance improvement from reduced $::auto_path. 2005-06-21 Pat Thoyts * tests/winDde.test: Added some waits to the dde server script to let event processing run after we create the dde server and before we exit the server process. This avoids 'server did not respond' errors. 2005-06-21 Kevin Kenny * generic/tclFileName.c: Corrected a problem where a directory name containing a colon can crash the process on Windows [Bug 1194458] * tests/fileName.test: Added test for [file split] and [file join] with a name containing a colon. * win/tclWinPipe.c: Reverted davygrvy's changes of 2005-04-19; they cause multiple failures in io.test. [Bug 1225044, still open] 2005-06-21 Don Porter * generic/tclBasic.c: Made the walk of the active trace list aware * generic/tclCmdMZ.c: of the direction of trace scanning, so the * generic/tclInt.h: proper correction can be made. [Bug 1224585] * tests/trace.test (trace-34.2,3): * generic/tclBasic.c (Tcl_DeleteTrace): Added missing walk of the * tests/trace.test (trace-34.1): list of active traces to cleanup references to traces being deleted. [Bug 1201035] 2005-06-20 Don Porter * doc/FileSystem.3: added missing Tcl_GlobTypeData documentation [Bug 935853] 2005-06-18 Daniel Steffen * generic/tclInt.h: ensure WORDS_BIGENDIAN is defined correctly with fat compiles on Darwin (i.e. ppc and i386 at the same time), the configure AC_C_BIGENDIAN check is not sufficient in this case because a single run of the compiler builds for two architectures with different endianness. * unix/tcl.m4 (Darwin): add -headerpad_max_install_names to LDFLAGS to ensure we can always relocate binaries with install_name_tool. * unix/configure: autoconf-2.13 2005-06-18 Don Porter * changes: Update changes for 8.4.11 release * README: Bump version number to 8.4.11 * generic/tcl.h: * tools/tcl.wse.in: * unix/configure.in: * unix/tcl.spec: * win/README.binary: * win/configure.in: * unix/configure: autoconf * win/configure: 2005-06-18 Donal K. Fellows * generic/tclCmdAH.c (Tcl_FormatObjCmd): Fix for [Bug 1154163]; only * tests/format.test: insert 'l' modifier when it is needed. 2005-06-07 Donal K. Fellows * unix/tclUnixNotfy.c (Tcl_FinalizeNotifier): Add dummy variable so threaded build compiles. 2005-06-06 Kevin B. Kenny * win/tclWin32Dll.c: Corrected another buglet in the assembly code for stack probing on Win32/gcc. [Bug 1213678] 2005-06-03 Daniel Steffen *** 8.4.10 TAGGED FOR RELEASE *** * unix/tclLoadDyld.c: fixed header conflict when building this file with USE_TCL_STUBS. * macosx/Makefile: fixed 'embedded' target. 2005-06-02 Jeff Hobbs * unix/Makefile.in (html): add BUILD_HTML_FLAGS optional var * tools/tcltk-man2html.tcl: add a --useversion to prevent confusion when multiple Tcl source dirs exist. * changes: updated for 8.4.10 release (porter) 2005-05-31 Zoran Vasiljevic * unix/tclUnixNotfy.c: the notifier thread is now created as joinable thread and it is properly joined in Tcl_FinalizeNotifier. This is an attempt to fix [Bug 1082283] 2005-05-29 Jeff Hobbs * win/tclWinThrd.c (TclpFinalizeThreadData): move tlsKey defn to top of file and clarify name (was 'key'). [Bug 1204064] 2005-05-27 Jeff Hobbs * README: Bumped patchlevel to 8.4.10 * generic/tcl.h: * tools/tcl.wse.in: * unix/tcl.spec, unix/configure, unix/configure.in: * win/configure, win/configure.in: 2005-05-26 Daniel Steffen * macosx/Makefile: moved & corrected EMBEDDED_BUILD check. * unix/configure.in: corrected framework finalization to softlink stub library to Versions/8.x subdir instead of Versions/Current. * unix/configure: autoconf-2.13 2005-05-25 Jeff Hobbs * generic/tclCmdMZ.c (Tcl_TimeObjCmd): add necessary cast * unix/configure, unix/configure.in: ensure false Tcl.framework is only created with --enable-framework 2005-05-24 Daniel Steffen * tests/env.test: added DYLD_FRAMEWORK_PATH to the list of env vars that need to be handled specially. * macosx/Makefile: * macosx/README: * macosx/Tcl-Info.plist.in (new file): * unix/Makefile.in: * unix/configure.in: * unix/tcl.m4: * unix/tclUnixInit.c: moved all Darwin framework build support from macosx/Makefile into the standard unix configure/make buildsystem, the macosx/Makefile is no longer required to build Tcl.framework (but its functionality is still available for backwards compatibility). * unix/configure: autoconf-2.13 * generic/tclIOUtil.c (TclLoadFile): * generic/tclInt.h: * unix/tcl.m4: * unix/tclLoadDyld.c: added support for [load]ing .bundle binaries in addition to .dylib's: .bundle's can be [unload]ed (unlike .dylib's), and can be [load]ed from memory, e.g. directly from VFS without needing to be written out to a temporary location first. [Bug 1202209] * unix/configure: autoconf-2.13 * generic/tclCmdMZ.c (Tcl_TimeObjCmd): change [time] called with a count > 1 to return a string with a float value instead of a rounded off integer. [Bug 1202178] 2005-05-20 Zoran Vasiljevic * generic/tclParseExpr.c: removed unreferenced stack variable "errMsg" probably included by fixing [Bug 1201589] (see below). 2005-05-20 Don Porter * generic/tclParseExpr.c: Corrected parser to recognize all boolean literals accepted by Tcl_GetBoolean, including prefixes like "y" and "f", and to allow "eq" and "ne" as function names in the proper context. [Bug 1201589] 2005-05-19 Daniel Steffen * macosx/tclMacOSXNotify.c (Tcl_InitNotifier): fixed crashing CFRelease of runLoopSource in Tcl_InitNotifier (reported by Zoran): CFRunLoopAddSource doesn't CFRetain, so can only CFRelease the runLoopSource in Tcl_FinalizeNotifier. 2005-05-14 Daniel Steffen * macosx/tclMacOSXBundle.c: * unix/tclUnixInit.c: * unix/tcl.m4 (Darwin): made use of CoreFoundation API configurable and added test of CoreFoundation availablility to allow building on ppc64, replaced HAVE_CFBUNDLE by HAVE_COREFOUNDATION; test for availability of Tiger or later OSSpinLockLock API. * unix/tclUnixNotfy.c: * unix/Makefile.in: * macosx/tclMacOSXNotify.c (new file): when CoreFoundation is available, use new CFRunLoop based notifier: allows easy integration with other event loops on Mac OS X, in particular the TkAqua Carbon event loop is now integrated via a standard tcl event source (instead of TkAqua upon loading having to finalize the exsting notifier and replace it with its custom version). [Patch 1202052] * tests/unixNotfy.test: don't run unthreaded tests on Darwin since notifier may be using threads even in unthreaded core. * unix/tclUnixPort.h: * unix/tcl.m4 (Darwin): test for thread-unsafe realpath durning configure, as Darwin 7 and later realpath is threadsafe. * macosx/tclMacOSXBundle.c: * unix/tclLoadDyld.c: * unix/tclUnixInit.c: fixed gcc 4.0 warnings. * unix/configure: autoconf-2.13 2005-05-10 Jeff Hobbs * tests/string.test: string-10.[21-30] * generic/tclCmdMZ.c (Tcl_StringObjCmd): add extra checks to prevent possible UMR in unichar cmp function for string map. 2005-05-06 Jeff Hobbs * unix/tcl.m4, unix/configure: correct Solaris 10 (5.10) check and add support for x86_64 Solaris cc builds. 2005-04-29 Donal K. Fellows * doc/FileSystem.3: Backport of doc fix. [Bug 1172401] 2005-04-27 Don Porter * library/init.tcl: Corrected flaw in interactive command * tests/main.test: auto-completion. [Bug 1191409] * tests/unixInit.test (7.1): Alternative fix for the 2005-04-22 commit. 2005-04-25 Daniel Steffen * compat/string.h: fixed memchr() protoype for __APPLE__ so that we build on Mac OS X 10.1 again. * generic/tclNotify.c (TclFinalizeNotifier): fixed notifier not being finalized in unthreaded core (was testing for notifier initialization in current thread by checking thread id != 0 but thread id is always 0 in untreaded core). * unix/tclUnixNotfy.c (Tcl_WaitForEvent): sync with HEAD: only declare and use timeout var in unthreaded core. * unix/Makefile.in: added @PLAT_SRCS@ to SRCS and split out NOTIFY_SRCS from UNIX_SRCS for parity with UNIX_OBJS & NOTIFY_OBJS. * unix/configure.in: only run check for broken strstr implementation if AC_REPLACE_FUNCS(strstr) hasn't already determined that strstr is unavailable, otherwise compat/strstr.o will be used twice (resulting in duplicate symbol link errors on Mac OS X 10.1) * unix/tcl.m4 (Darwin): added configure checks for recently added linker flags -single_module and -search_paths_first to allow building with older tools (and on Mac OS X 10.1), use -single_module in SHLIB_LD and not just T{CL,K}_SHLIB_LD_EXTRAS, added unexporting from Tk of symbols from libtclstub to avoid duplicate symbol warnings, added PLAT_SRCS definition for Mac OS X. (SC_MISSING_POSIX_HEADERS): added caching of dirent.h check. (SC_TCL_64BIT_FLAGS): fixed 'checking for off64_t' message output. * unix/configure: autoconf-2.13 2005-04-22 Don Porter * generic/tclCmdMZ.c: Corrected intrep-dependence of * tests/string.test: [string is boolean] [Bug 1187123] 2005-04-22 Daniel Steffen * tests/unixInit.test (7.1): fixed failure when running tests with -tmpdir arg not set to working dir. 2005-04-20 Don Porter * generic/tclGet.c (Tcl_GetInt): Corrected error that did not * generic/tclObj.c (Tcl_GetIntFromObj): permit 0x80000000 to be recognized as an integer on TCL_WIDE_INT_IS_LONG systems [Bug 1090869] 2005-04-19 Jeff Hobbs * tests/winPipe.test (winpipe-6.2): remove -blocking 1 as this one can truly block. 2005-04-19 David Gravereaux * win/tclWinPipe.c: The pipe channel driver now respects the -blocking option when closing. The windows pipe driver now has the same behavior as the UNIX side. This change is to avoid a hung shell when exiting due to open pipes that refuse to close in a graceful manner. * doc/open.n: Added a note about -blocking 0 and lack of exit status as it had never been documented. [Bug 947693] ***POTENTIAL INCOMPATIBILITY*** Scripts that use async pipes on windows, must (like the UNIX side) set -blocking to 1 before calling [close] to receive the exit status. * tests/winPipe.test (winpipe-6.1/2): added 'fconfigure $f -blocking 1' so the exit status can be acquired. 2005-04-13 David Gravereaux * generic/tclIO.c (Tcl_SetChannelBufferSize): Lowest size limit * tests/io.test: changed from ten bytes to one byte. Need for * tests/iogt.test: this change was proven by Ross Cartlidge where [read stdin 1] was grabbing 10 bytes followed by starting a child process that was intended to continue reading from stdin. Even with -buffersize set to one, nine chars were getting lost by the buffersize over reading for the native read() caused by [read]. 2005-04-12 Kevin B. Kenny * compat/strstr.c: Added default definition of NULL to accommodate building on systems with badly broken headers. [Bug 1175161] 2005-04-09 Daniel Steffen * macosx/README: updated requirements for OS & developer tool versions + other small fixes/cleanup. * unix/tcl.m4 (Darwin): added -single_module linker flag to TCL_SHLIB_LD_EXTRAS and TK_SHLIB_LD_EXTRAS. * unix/configure: autoconf-2.13 2005-04-05 Zoran Vasiljevic Set of changes correcting huge memory waste (not a leak) when a thread exits. This has been introduced in 8.4.7 within an attempt to correctly cleanup after ourselves when Tcl library is being unloaded with the Tcl_Finalize() call. This fixes the [Bug 1178445]. * generic/tclInt.h: added prototypes for TclpFreeAllocCache() and TclFreeAllocCache() * generic/tclThreadAlloc.c: modified TclFinalizeThreadAlloc() to explicitly call TclpFreeAllocCache with the NULL-ptr as argument signalling cleanup of private tsd key used only by the threading allocator. * unix/tclUnixThrd.c: fixed TclpFreeAllocCache() to recognize when being called with NULL argument. This is a signal for it to clean up the tsd key associated with the threading allocator. * win/tclWinThrd.c: renamed TclWinFreeAllocCache to TclpFreeAllocCache and fixed to recognize when being called with NULL argument. This is a signal for it to clean up the tsd key associated with the threading allocator. 2005-04-05 Don Porter * generic/tclExecute.c (ExprSrandFunc): Replaced incursions into the * generic/tclUtil.c (TclGetIntForIndex): intreps of numeric types with simpler calls of Tcl_GetIntFromObj and Tcl_GetLongFromObj, now that those routines are better behaved wrt shimmering. [Patch 1177129] 2005-03-29 Jeff Hobbs * win/tcl.m4, win/configure: do not require cygpath in macros to allow msys alone as an alternative. * win/tclWinTime.c (TclpGetDate): use time_t for 'time' [Bug 1163422] 2005-03-18 Don Porter * generic/tclCompCmds.c (TclCompileIncrCmd): Corrected checks for immediate operand usage to permit leading space and sign characters. Restores more efficient bytecode for [incr x -1] that got lost in the CONST string reforms of Tcl 8.4. [Bug 1165671] * generic/tclBasic.c (Tcl_EvalEx,TclEvalTokensStandard): * generic/tclCmdMZ.c (Tcl_SubstObj): * tests/basic.test (basic-46.4): Restored recursion limit * tests/parse.test (parse-19.*): testing in nested command substitutions within direct script evaluation (Tcl_EvalEx) that got lost in the parser reforms of Tcl 8.1. Added tests for correct behavior. [Bug 1115904] 2005-03-15 Vince Darley * generic/tclFileName.c: * win/tclWinFile.c: * tests/winFCMd.test: fix to 'file pathtype' and 'file norm' failures on reserved filenames like 'COM1:', etc. 2005-03-15 Kevin B. Kenny * generic/tclClock.c: * generic/tclDate.c: * generic/tclGetDate.y: * generic/tclInt.decls: * unix/tclUnixTime.c: * win/tclWinTime.c: Replaced 'unsigned long' variable holding times with 'Tcl_WideInt', to cope with systems on which a time_t is wider than a long (Win64) [Bug 1163422] * generic/tclIntDecls.h: Regen 2005-03-15 Pat Thoyts * unix/tcl.m4: Make it work on OpenBSD again. Imported patch from the OpenBSD ports tree. 2005-03-10 Don Porter * generic/tclCmdMZ.c (TclCheckInterpTraces): Corrected mistaken cast of ClientData to (TraceCommandInfo *) when not warranted. Thanks to Yuri Victorovich for the report. [Bug 1153871] 2005-03-08 Jeff Hobbs * win/makefile.vc: clarify necessary defined vars that can come from MSVC or the Platform SDK. 2005-02-24 Don Porter * library/tcltest/tcltest.tcl: Better use of [glob -types] to avoid * tests/tcltest.test: failed attempts to [source] a directory, and similar matters. Thanks to "mpettigr". [Bug 1119798] * library/tcltest/pkgIndex.tcl: Bump to tcltest 2.2.8 2005-02-23 Donal K. Fellows * doc/CrtChannel.3 (THREADACTIONPROC): Formatting fix. [Bug 1149605] 2005-02-17 Jeff Hobbs * win/tclWinFCmd.c (TraverseWinTree): use wcslen on wchar, not Tcl_UniCharLen. 2005-02-16 Miguel Sofer * doc/variable.n: fix for [Bug 1124160], variables are detected by [info vars] but not by [info locals]. 2005-02-10 Jeff Hobbs * unix/Makefile.in: remove SHLIB_LD_FLAGS (only for AIX, inlined * unix/tcl.m4: into SHLIB_LD). Combine AIX-* and AIX-5 * unix/configure: branches in SC_CONFIG_CFLAGS. Correct gcc builds for AIX-4+ and HP-UX-11. 2005-02-10 Miguel Sofer * generic/tclBasic.c (Tcl_EvalObjEx): * tests/basic.test (basic-26.2): preserve the arguments passed to TEOV in the pure-list branch, in case the list shimmers away. Fix for [Bug 1119369], reported by Peter MacDonald. 2005-02-10 Donal K. Fellows * doc/binary.n: Made the documentation of sign bit masking and [binary scan] consistent. [Bug 1117017] 2005-02-01 Don Porter * generic/tclExecute.c (TclCompEvalObj): Removed stray statement left behind in prior code reorganization. 2005-01-28 Jeff Hobbs * unix/configure, unix/tcl.m4: add solaris 64-bit gcc build support. [Bug 1021871] 2005-01-27 Jeff Hobbs * generic/tclBasic.c (Tcl_ExprBoolean, Tcl_ExprDouble) (Tcl_ExprLong): Fix to recognize Tcl_WideInt type. [Bug 1109484] 2005-01-27 Andreas Kupries TIP#218 IMPLEMENTATION * generic/tclDecls.h: Regenerated from tcl.decls. * generic/tclStubInit.c: * doc/CrtChannel.3: Documentation of extended API, * generic/tcl.decls: extended testsuite, and * generic/tcl.h: implementation. Removal of old * generic/tclIO.c: driver-specific TclpCut/Splice * generic/tclInt.h: functions. Replaced with generic * tests/io.test: thread-action calls through the * unix/tclUnixChan.c: new hooks. Update of all builtin * unix/tclUnixPipe.c: channel drivers to version 4. * unix/tclUnixSock.c: Windows drivers extended to * win/tclWinChan.c: manage thread state in a thread * win/tclWinConsole.c: action handler. * win/tclWinPipe.c: * win/tclWinSerial.c: * win/tclWinSock.c: * mac/tclMacChan.c: 2005-01-25 Don Porter * library/auto.tcl: Updated [auto_reset] to clear auto-loaded procs in namespaces other than :: [Bug 1101670]. 2005-01-25 Daniel Steffen * unix/tcl.m4 (Darwin): fixed bug with static build linking to dynamic library in /usr/lib etc instead of linking to static library earlier in search path. [Bug 956908] Removed obsolete references to Rhapsody. * unix/configure: autoconf-2.13 2005-01-19 Mo DeJong * win/tclWinChan.c (FileCloseProc): Invoke TclpCutFileChannel() to remove a FileInfo from the thread local list before deallocating it. This should have been done via an earlier call to Tcl_CutChannel, but I was running into a crash in the next call to Tcl_CutChannel during the IO finalization stage. 2005-01-17 Vince Darley * tests/winFCmd.test: made test independent of current drive. [Bug 1066528] 2005-01-10 Donal K. Fellows * unix/tclUnixFCmd.c (CopyFile): Convert u_int to unsigned to make clashes with types in standard C headers less of a problem. [Bug 1098829] 2005-01-06 Donal K. Fellows * library/http/http.tcl (http::mapReply): Significant performance enhancement by using [string map] instead of [regsub]/[subst], and update version requirement to Tcl8.4. [Bug 1020491] 2005-01-05 Donal K. Fellows * unix/tclUnixInit.c (localeTable): Add encoding mappings for some Chinese locales. [Bug 1084595] * doc/lsearch.n: Convert to other form of emacs mode control comment to prevent problems with old versions of man. [Bug 1085127] 2004-12-29 Jeff Hobbs * win/tcl.m4, win/configure: update MSVC CFLAGS_OPT to -O2, remove -Gs (included in -O2) and -GD (outdated). Use "link -lib" instead of "lib" binary and remove -YX for MSVC7 portability. Add -fomit-frame-pointer for gcc OPT compiles. [Bug 1092952, 1091967] 2004-12-13 Kevin B. Kenny * doc/clock.n: Clarify that the [clock scan] command does not accept the full range of ISO8601 point-in-time formats. [Bug 1075433] 2004-12-09 Donal K. Fellows * doc/Async.3: Reword for better grammar, better nroff and get the flag name right. (Reported by David Welton.) 2004-12-06 Jeff Hobbs *** 8.4.9 TAGGED FOR RELEASE *** * unix/tclUnixNotfy.c (NotifierThreadProc): init numFdBits [Bug 1079286] 2004-12-02 Jeff Hobbs * changes: updated for 8.4.9 release 2004-12-02 Vince Darley * generic/tclIOUtil.c: fix and new tests for [Bug 1074671] to * tests/fileSystem.test: ensure tilde paths are not returned specially by 'glob'. 2004-12-01 Don Porter * library/auto.tcl (tcl_findLibrary): Disabled use of [file normalize] that caused trouble with freewrap. [Bug 1072136] 2004-11-26 Don Porter * tests/reg.test (reg-32.*): Added missing testregexp constraints. * library/auto.tcl (tcl_findLibrary): Made sure the uniquifying operations on the search path does not also normalize. [Bug 1072136] 2004-11-26 Donal K. Fellows * doc/dde.n: Resynchonized the documentation with itself and fixed some formatting errors. 2004-11-25 Zoran Vasiljevic * doc/Notify.3: * doc/Thread.3: Added doc fixes and hints from [Bug 1068077]. 2004-11-25 Reinhard Max * tests/tcltest.test: The order in which [glob] returns the file names * tests/fCmd.test: is undefined, so tests should not depend on it. 2004-11-24 Don Porter * unix/tcl.m4 (SC_ENABLE_THREADS): Corrected failure to determine the number of arguments for readdir_r on SunOS systems. [Bug 1071701] * unix/configure: autoconf-2.13 2004-11-24 Jeff Hobbs * README: Bumped patchlevel to 8.4.9 * generic/tcl.h: * tools/tcl.wse.in: * unix/tcl.spec, unix/configure, unix/configure.in: * win/configure, win/configure.in: 2004-11-24 Kevin B. Kenny * unix/tcl.m4 (SC_ENABLE_THREADS): Corrected bad check for 3-argument readdir_r(). [Bug 1001325] * unix/configure: Regenerated. * unix/tclUnixNotfy.c: Corrected all uses of 'select' to manage their masks using the FD_CLR, FD_ISSET, FD_SET, and FD_ZERO macros rather than bit-whacking that failed under Solaris-Sparc-64. [Bug 1071807] 2004-11-23 Don Porter * generic/tclCmdIL.c (InfoVarsCmd): Corrected segfault in new * tests/info.test (info-19.6): trivial matching branch [Bug 1072654] 2004-11-23 Vince Darley * generic/tclPathObj.c: fix and new test for [Bug 1043129] in * tests/fileSystem.test: the treatment of backslashes in file join on Windows. 2004-11-22 Mo DeJong * unix/configure: Regen. * unix/tcl.m4 (SC_TCL_64BIT_FLAGS): Define HAVE_TYPE_OFF64_T only when off64_t, open64(), and lseek64() are defined. IRIX 5.3 is known to not include an open64 function. [Bug 1030465] 2004-11-22 Mo DeJong * unix/configure: Regen. * unix/tcl.m4 (SC_ENABLE_THREADS): Check for a 2 argument version of readdir_r that is known to exists under IRIX 5.3. * unix/tclUnixThrd.c (TclpReaddir): Use either 2 arg or 3 arg version of readdir_r. [Bug 1001325] 2004-11-19 Reinhard Max *** 8.4.8 TAGGED FOR RELEASE *** * unix/installManPage: Classic sed doesn't support | in REs. 2004-11-19 Daniel Steffen * macosx/Makefile: * unix/configure.in: * unix/tclUnixInit.c (MacOSXGetLibraryPath): changed detection of tcl framework build when determining tclLibPath from overloaded TCL_LIBRARY to configuration define TCL_FRAMEWORK. [Bug 1068088] * unix/configure: autoconf-2.13 * tests/unixInit.test (7.1): fixed failure when running tests with -tmpdir arg not set to working dir. 2004-11-18 Don Porter * changes: Final updates for Tcl 8.4.8 release. 2004-11-18 Reinhard Max * unix/tcl.m4 (SC_CONFIG_MANPAGES): Applied an improved version of * unix/configure.in: [Patch 996085], that introduces * unix/Makefile.in: --enable-man-suffix. * unix/installManPage: added * unix/mkLinks.tcl: removed * unix/mkLinks: removed 2004-11-16 Jeff Hobbs * unix/tclUnixChan.c (TtySetOptionProc): fixed crash configuring -ttycontrol on a channel. [Bug 1067708] 2004-11-16 Andreas Kupries * win/makefile.vc: Fixed bug in installation of http 2.5. * win/makefile.bc: Was installed into directory http2.4. * win/Makefile.in: This has been corrected. * unix/Makefile.in: * tools/tcl.wse.in: * tools/tclmin.wse: 2004-11-16 Don Porter * library/auto.tcl: Updated [tcl_findLibrary] search path to include the $::auto_path. [RFE 695441] 2004-11-16 Donal K. Fellows * doc/tclvars.n: Mention global variables set by tclsh and wish so they are easier to find. [Patch 1065732] 2004-11-15 Don Porter * generic/tclCmdMZ.c (Tcl_TraceObjCmd): Fixed Bug 1065378 which failed * tests/trace.test (trace-33.1): to permit a variable trace created with [trace variable] to be destroyed with [trace remove]. Thanks to Keith Vetter for the report. 2004-11-12 Don Porter * library/init.tcl: Made [unknown] robust in the case that either of the variables ::errorInfo or ::errorCode gets unset. [Bug 1063707] 2004-11-12 Jeff Hobbs * generic/tclEncoding.c (TableFromUtfProc): correct crash condition when TCL_UTF_MAX == 6. [Bug 1004065] 2004-11-12 Daniel Steffen * doc/clock.n: * doc/registry.n: * doc/upvar.n: fixed *roff errors uncovered by running 'make html'. * tools/tcltk-man2html.tcl: added faked support for bullet point lists, i.e. *nroff ".IP \(bu" syntax. Synced other changes from HEAD. 2004-11-11 Daniel Steffen * tests/fCmd.test: * unix/tclUnixFCmd.c (TraverseUnixTree): added option to rewind() the readdir() loop whenever the source hierarchy has been modified by traverseProc (e.g. by deleting files); this is required to ensure complete traversal of the source hierarchy on certain filesystems like HFS+. Added test for failing recursive delete on Mac OS X that was due to this. [Bug 1034337] * generic/tclListObj.c (Tcl_ListObjReplace): use memmove() instead of manual copy loop to shift list elements. Decreases time spent in Tcl_ListObjReplace() from 5.2% to 1.7% of overall runtime of tclbench on a ppc 7455 (i.e. 200% speed increase). [Patch 1064243] * generic/tclHash.c: hoisted some constant pointer dereferences out of loops to eliminate redundant loads that the gcc optimizer didn't deal with. Decreases time spend in Tcl_FindHashEntry() by 10% over a full run of the tcl testuite on a ppc 7455. [Patch 1064243] * tests/fileName.test: * tests/fileSystem.test: * tests/io.test: * tests/tcltest.test: fixed bugs causing failures when running tests with -tmpdir arg not set to working dir. * macosx/Makefile: corrected path to html help inside framework. Prevent parallel make from building several targets at the same time. 2004-11-09 Donal K. Fellows * doc/catch.n: Clarify documentation on return codes. [Bug 1062647] 2004-11-02 Don Porter * changes: Updates for Tcl 8.4.8 release. 2004-11-02 Don Porter * library/tcltest/tcltest.tcl: Corrected some misleading * tests/tcltest.test (tcltest-26.1,2): displays of ::errorInfo and ::errorCode information when the -setup, -body, and/or -cleanup scripts return an unexpected return code. Thanks to Robert Seeger for the fix. [RFE 1017151] 2004-11-02 Donal K. Fellows * generic/tclExecute.c (TclExecuteByteCode): NaN-equality fix from Miguel Sofer. [Bug 761471] * doc/CrtChannel.3 (Tcl_GetChannelMode): Add synopsis. [Bug 1058446] 2004-10-31 Donal K. Fellows * generic/tclCmdIL.c (InfoGlobalsCmd): * tests/info.test (info-8.4): Strip leading global-namespace specifiers from the pattern argument. [Bug 1057461] 2004-10-30 Miguel Sofer * generic/tclCmdAH.c (Tcl_CatchObjCmd): removed erroneous comment [Bug 1029518] 2004-10-29 Don Porter * library/tcltest/tcltest.tcl: Correct reaction to errors in the obsolete processCmdLineArgsHook. [Bug 1055673] * library/tcltest/pkgIndex.tcl: Bump to tcltest 2.2.7 2004-10-28 Andreas Kupries * generic/tclAlloc.c: Fixed [Bug 1030548], a threaded debug * generic/tclThreadAlloc.c: build on Windows now works again. Had to * win/tclWinThrd.c: touch Unix as well. Basic patch by Kevin, * unix/tclUnixThrd.c: with modifications by myself. 2004-10-28 Don Porter * README: Bumped patch level to 8.4.8 to prepare for * generic/tcl.h: next patch release. * tools/tcl.wse.in: * unix/configure.in: * unix/tcl.spec: * win/README.binary: * win/configure.in: * unix/configure: autoconf (2.13) * win/configure: 2004-10-28 Kevin B. Kenny * generic/tclInt.decls: * unix/tclUnixTime.c (TclpGmtime, TclpLocaltime): * win/tclWinTime.c (TclpGmtime, TclpLocaltime): Changed type signatures of TclpGmtime and TclpLocaltime to accept CONST TclpTime_t throughout, to avoid any possible confusion in pedantic compilers. [Bug 1001319] * generic/tclIntDecls.h: * generic/tclIntPlatDecls.h: Regenerated. 2004-10-27 Don Porter * generic/tclCmdAH.c (Tcl_FormatObjCmd): Restored missing line from yesterday's 868489 backport that caused failed alloc's on LP64 systems. * tests/appendComp.test: Backport test suite fixes of errors * tests/autoMkindex.test: revealed by -singleproc 1 -debug 1 * tests/exec.test: options to make test. * tests/execute.test: * tests/interp.test: * tests/io.test: * tests/namespace.test: * tests/regexpComp.test: * tests/stringComp.test: * tests/unixInit.test: * tests/winPipe.test: 2004-10-26 Kevin B. Kenny * generic/tclCmdAH.c (Tcl_FormatObjCmd): Backport a missing bit of the [Bug 868489] fix. * generic/tclObj.c (SetBooleanFromAny): Backport fix for [Bug 1026125] * tests/format.test (format-19.1): Additional regression test for [Bug 868489]. 2004-10-26 Donal K. Fellows * doc/*.n: Backporting of documentation updates. 2004-10-26 Don Porter * tests/subst.test (subst-12.3-5): More tests for [Bug 1036649] * tests/compile.test (compile-12.4): Backport test for [Bug 1001997] * tests/timer.test (timer-10.1): Backport test for [Bug 1016167] * tests/tcltest.test (tcltest-12.3,4): Backport setup corrections. * tests/error.test (error-6.3,4,7,9): Backport of some tests. * tests/basic.test (basic-49.*): * tests/namespace.test (namespace-8.7): * tests/init.test (init-2.8): Updated to not rely on http package. * generic/tclThreadTest.c (ThreadEventProc): Corrected subtle bug where the returned (char *) from Tcl_GetStringResult(interp) continued to be used without copying or refcounting, while activity on the interp continued. 2004-10-14 Donal K. Fellows * generic/tclUtil.c (TclMatchIsTrivial): Detect degenerate cases of glob matching that let us avoid scanning through hash tables. * generic/tclCmdIL.c (InfoCommandsCmd, InfoGlobalsCmd, InfoProcsCmd): (InfoVarsCmd): Use this to speed up some [info] subcommands. 2004-10-08 Jeff Hobbs * win/tclWinFile.c (NativeIsExec): correct result of 'file executable' to not be case sensitive. [Bug 954263] 2004-10-05 Don Porter * generic/tclNamesp.c (Tcl_PopCallFrame): Removed Bug 1038021 workaround. That bug is now fixed. 2004-09-30 Don Porter * generic/tclNamespace.c (TclTeardownNamespace): Tcl_Obj-ified the * tests/namespace.test (namespace-8.5,6): save/restore of ::errorInfo and ::errorCode during global namespace teardown. Revised the comment to clarify why this is done, and added tests that will fail if this is not done. * generic/tclResult.c (TclTransferResult): Added safety checks so that unexpected undefined ::errorInfo or ::errorCode will not lead to a segfault. * generic/tclVar.c (CallVarTraces): Save/restore the flag values * tests/var.test (var-16.1): that define part of the interpreter state during variable traces. [Bug 1038021] 2004-09-30 Miguel Sofer * tests/subst.test (12.2): test correction. 2004-09-29 Miguel Sofer * generic/tclBasic.c (Tcl_EvalEx): * tests/subst.test (12.1-2): fix for buffer overflow in [subst], [Bug 1036649] 2004-09-23 Mo DeJong * unix/dltest/Makefile.in (clean): Fixup make clean rule so that it does not delete all files when SHLIB_SUFFIX is set to the empty string in a static build. [Bug 1016726] 2004-09-18 Donal K. Fellows * generic/tclExecute.c (TEBC-INST_LSHIFT,INST_RSHIFT): Ensure that large shifts end up shifting correctly. [Bug 868467] 2004-09-15 Daniel Steffen * tests/load.test (load-2.3): adopted fix for failure on darwin from HEAD. 2004-09-14 Don Porter * generic/tclObj.c (Tcl_GetIntFromObj): Corrected flaw in returning the int value of a wideInteger. [Bug 1027690] 2004-09-10 Donal K. Fellows * generic/tclObj.c (SetIntOrWideFromAny): Rewritten integral value parsing code so that values do not flip so easily between numeric representations. Thanks to KBK for this! [Bug 868489] * generic/tclIO.c (Tcl_Seek): Make sure wide seeks do not fail to set ::errorCode on error. [Bug 1025359] 2004-09-10 Andreas Kupries * generic/tcl.h: Micro formatting fixes. * generic/tclIOGT.c: Channel version fixed, must be 3, to have wideseekProc. Thanks to David Graveraux . 2004-09-11 Don Porter * generic/tclNamespace.c (TclGetNamespaceForQualName): Resolved longstanding inconsistency in the treatment of the TCL_NAMESPACE_ONLY flag revealed by testing the 2004-09-09 commits against Itcl. TCL_NAMESPACE_ONLY now acts as specified in the pre-function comment, forcing resolution in the passed in context namespace. It has been incorrectly forcing resolution in the interp's current namespace. 2004-09-10 Miguel Sofer * generic/tclExecute.c (INST_CONCAT1): added a peephole optimisation for concatting an empty string. This enables replacing the idiom 'K $x [set x {}]' by '$x[set x {}]' for fastest execution. 2004-09-09 Don Porter * generic/tclNamesp.c (Tcl_ForgetImport): Corrected faulty logic that * tests/namespace.test: relied exclusively on string matching and failed in the presence of [rename]s. [Bug 560297] Also corrected faulty prevention of [namespace import] cycles. [Bug 1017299] 2004-09-08 Kevin B. Kenny * compat/strftime.c (_conv): Corrected a problem where hour 0 would format as a blank format group with %k. * tests/clock.test (clock-41.1): Added regression test case for %k at the zero hour. 2004-09-07 Kevin B. Kenny * generic/tclTimer.c: Removed a premature optimisation that attempted to store the assoc data in the client data; the optimisation caused a bug that [after] would overwrite its imports. [Bug 1016167] 2004-09-02 Donal K. Fellows * doc/lsearch.n: Clarified meaning of -dictionary. [Bug 759545] 2004-09-01 Jeff Hobbs * win/tclWinReg.c (BroadcastValue): WIN64 cast corrections * win/tclWinDde.c (DdeClientWindowProc): (DdeServicesOnAck, DdeEnumWindowsCallback): WIN64 corrections * win/tclWin32Dll.c (TclWinCPUID): need _asm for WIN64 (Itanium), until we have it, just return unknown. [Bug 1020445] 2004-08-30 Donal K. Fellows * generic/tclCmdMZ.c (Tcl_StringObjCmd): Stop [string map] from crashing when its map and input string are the same object. 2004-08-27 Daniel Steffen * tests/env.test: macosx fixes. 2004-08-19 Donal K. Fellows * generic/tclScan.c (Tcl_ScanObjCmd, ValidateFormat): Ensure that the %ld conversion works correctly on 64-bit platforms. [Bug 1011860] 2004-08-16 Miguel Sofer * doc/SetVar.3: * generic/tclTest.c (TestseterrorcodeCmd): * generic/tclVar.c (TclPtrSetVar): * tests/result.test (result-4.*, result-5.*): [Bug 1008314] detected and fixed by dgp. 2004-08-13 Don Porter * library/msgcat/msgcat.tcl: Added checks to prevent [mclocale] * tests/msgcat.test: from registering filesystem paths to possibly malicious code to be evaluated by a later [mcload]. * library/msgcat/pkgIndex.tcl: Bump to msgcat 1.3.3 2004-08-10 Zoran Vasiljevic * unix/tclUnixThrd.c (TclpThreadCreate): changed handling of the returned thread ID since broken on 64-bit systems (Cray). Thanks to Rob Ratcliff for reporting the bug. 2004-07-30 Don Porter * generic/tclEvent.c (Tcl_Finalize): Re-organized Tcl_Finalize so that Tcl_ExitProc's that call Tcl_Finalize recursively do not cause deadlock. [Patch 999084, fixes Tk Bug 714956] 2004-07-30 Daniel Steffen * unix/configure: * unix/tcl.m4 (SC_CONFIG_CFLAGS): Darwin: instead of setting PLAT_OBJS to explict object files in tcl.m4, refer to MAC_OSX_OBJS makefile var. * unix/Makefile.in: added MAC_OSX_OBJS variable. 2004-07-28 Don Porter * generic/tclMain.c (Tcl_Main, StdinProc): Append newline only to * tests/basic.test (basic-46.1): incomplete scripts as part of multi-line script construction. Do not add an extra trailing newline to the complete script. [Bug 833150] 2004-07-26 Jeff Hobbs *** 8.4.7 TAGGED FOR RELEASE *** * tests/io.test (io-61.1): create file in binary mode for x-plat. 2004-07-25 Pat Thoyts * generic/tclThreadAlloc.c: Moved the tclInt.h include to provide Tcl_Panic which is now required for non-threaded build. 2004-07-22 Don Porter * tests/eofchar.data (removed): Test io-61.1 now generates its own * tests/io.test: file of test data as needed. 2004-07-21 Don Porter * win/tclWinDde.c: Bump to dde 1.2.3 to cover changes * library/dde/pkgIndex.tcl: committed on 2004-06-14. * changes: Updated for Tcl 8.4.7 release. 2004-07-20 Jeff Hobbs * generic/tclEvent.c: Correct threaded obj allocator to * generic/tclInt.h: fully cleanup on exit and allow for * generic/tclThreadAlloc.c: reinitialization. [Bug 736426] * unix/tclUnixThrd.c: (mistachkin, kenny) * win/tclWinThrd.c: 2004-07-20 Daniel Steffen * unix/tcl.m4: fixed Darwin autoconf breakage caused by recent CFLAGS reordering. * unix/configure: regen * unix/tclConfig.sh.in: replaced EXTRA_CFLAGS with CFLAGS. * unix/dltest/Makefile.in: replaced EXTRA_CFLAGS with DEFS. * macosx/tclMacOSXBundle.c: dynamically acquire address for CFBundleOpenBundleResourceMap symbol, since it is only present in full CoreFoundation on Mac OS X and not in CFLite on pure Darwin. 2004-07-19 Jeff Hobbs * unix/Makefile.in, unix/tcl.m4: move (C|LD)FLAGS after their * unix/configure.in, unix/configure: _DEFAULT to allow for env setting to override m4 switches. Consolidate header checks to limit redundancy in configure. (CFLAGS_WARNING): Remove -Wconversion, add -fno-strict-aliasing for gcc builds (need to suppress 3.x type puning warnings). (SC_ENABLE_THREADS): Set m4 to force threaded build when built against a threaded Tcl core. Reorder configure.in for better 64-bit build configuration, replacing EXTRA_CFLAGS with CFLAGS. [Bug 874058] 2004-07-19 Zoran Vasiljevic * win/tclwinThrd.c: redefined MASTER_LOCK to call TclpMasterLock. Fixes [Bug 987967] 2004-07-16 Andreas Kupries * generic/tclIOCmd.c (Tcl_FcopyObjCmd): Corrected a typo in the generation of error messages and simplified by reusing data in a variable instead of retrieving the string again. Fixes [Bug 835289] * doc/OpenFileChnl.3: Added description of the behaviour of Tcl_ReadChars when its 'charsToRead' argument is set to -1. Fixes [Bug 934511] * doc/CrtCommand.3: Added note that the arguments given to the command proc of a Tcl_CreateCommand are in utf8 since Tcl 8.1. Closing [Patch 414778] * doc/ChnlStack.3: Removed the declaration that the interp argument to Tcl_(un)StackChannel can be NULL. This fixes [Bug 881220], reported by Marco Maggi . * tests/socket.test: Accepted two new testcases by Stuart Casoff checking that -server and -async don't go together [Bug 796534] * unix/tclUnixNotfy.c (NotifierThreadProc): Accepted Joe Mistachkin's patch for [Bug 990500], properly closing the notifier thread when its exits. 2004-07-15 Andreas Kupries * unix/tclUnixThrd.c (TclpFinalizeMutex): Accepted Joe Mistachkin's patch for [Bug 990453], closing leakage of mutexes. They were not destroyed properly upon finalization. 2004-07-15 Zoran Vasiljevic * generic/tclEvent.c (NewThreadProc): Backout of changes to fix [Bug 770053]. See SF bugreport for more info. * generic/tclNotify.c (TclFinalizeNotifier): Added conditional notifier finalization based on the fact that an TclInitNotifier has been called for the current thread. This fixes [Bug 770053] again. Hopefully this time w/o unwanted side-effects. 2004-07-14 Andreas Kupries * generic/tclIO.h (CHANNEL_INCLOSE): New flag. Set in Tcl_Close * generic/tclIO.c (Tcl_UnregisterChannel): while the close callbacks * generic/tclIO.c (Tcl_Close): are run. Checked in Tcl_Close and Tcl_Unregister to prevent recursive call of [close] in the close-callbacks. This is a possible error made by implementors of virtual filesystems based on 'tclvfs', thinking that they have to close the channel in the close handler for the filesystem. 2004-07-14 Andreas Kupries * generic/tclIO.c: * generic/tclIO.h: Not reverting, but #ifdef'ing the changes from May 19, 2004 out of the core. This removes the ***POTENTIAL INCOMPATIBILITY*** for channel drivers it introduced. This has become possible due to Expect gaining a BlockModeProc and now handling blockingg and non-blocking modes correctly. Thus [Bug 943274] is still fixed if a recent enough version of Expect is used. * doc/CrtChannel.3: Added warning about usage of a channel without a BlockModeProc. 2004-07-15 Andreas Kupries * generic/tclIOCmd.c (Tcl_PutsObjCmd): Added length check to the old depreceated newline syntax, to ensure that only "nonewline" is accepted. [Bug 985869] (mistachkin) 2004-07-13 Jeff Hobbs * README, generic/tcl.h, tools/tcl.wse.in: bumped to * unix/configure, unix/configure.in, unix/tcl.spec: patchlevel * win/README.binary, win/configure, win/configure.in: 8.4.7 2004-07-13 Zoran Vasiljevic * generic/tclEvent.c (NewThreadProc): Fixed broken build on Windows caused by missing TCL_THREAD_CREATE_RETURN. This is backported from HEAD. Thnx to Kevin Kenny for spotting this. 2004-07-03 Miguel Sofer * generic/tclExecute.c (ExprRoundFunc): * tests/expr-old.test (39.1): added support for wide integers to round(); [Bug 908375], reported by Hemang Lavana. 2004-07-02 Jeff Hobbs * generic/regcomp.c (stid): correct minor pointer size error * generic/tclPipe.c (TclCreatePipeline): Add 2>@1 as a special * tests/exec.test: case redir of stderr to the result output. 2004-07-02 Vince Darley * tests/fileSystem.test: new tests backported * win/tclWin32Dll.c: compilation fix for VC++5.2 2004-06-29 Donal K. Fellows * library/safe.tcl: Make sure that the temporary variable is local to the namespace and not inadvertently global. [Bug 981733] 2004-06-22 Zoran Vasiljevic * generic/tclEvent.c: * generic/tclInt.h: * unix/tclUnixNotfy.c: * unix/tclUnixThrd.c: * win/tclWinThrd.c: See bug report for more information about what it does. [Bug 770053] * tests/unixNotfy.test: rewritten to use tcltest::threadReap to gracefully wait for the test thread to exit. Otherwise we got a race condition with main thread exiting before the test thread. This exposed the long-standing Tcl lib issue with resource garbage-collection on application exit. 2004-06-21 Mo DeJong * win/tclWin32Dll.c (DllMain, _except_dllmain_detach_handler) (TclpCheckStackSpace, _except_checkstackspace_handler, TclWinCPUID) (_except_TclWinCPUID_detach_handler): * win/tclWinChan.c (Tcl_MakeFileChannel) (_except_makefilechannel_handler): * win/tclWinFCmd.c (DoRenameFile, _except_dorenamefile_handler) (DoCopyFile, _except_docopyfile_handler): Rework pushing of exception handler function pointer so that compiling with gcc -O3 works. Remove empty function call to avoid compiler warning. Mark the DllMain function as noinline to avoid compiler error from duplicated asm labels in generated code. 2004-06-14 Pat Thoyts * tests/winDde.test: Fixed -async test * win/tclWinDde.c: Backported the fix from 8.5 to avoid hanging in the presence of applications that do not process Window messages. 2004-06-10 Andreas Kupries * generic/tclDecls.h: Regenerated on a unix box. The Win/DOS * generic/tclIntDecls.h: EOLs from the last regen screwed up * generic/tclIntPlatDecls.h: compilation with an older gcc. * generic/tclPlatDecls.h: * generic/tclStubInit.c: 2004-06-10 Zoran Vasiljevic * generic/tclIOUtil.c: partially corrected [Bug 932314]. Also, corrected return values of Tcl_FSChdir() to reflect those of the underlying platform-specific call. Originally, return codes were mixed with those of Tcl. 2004-06-08 Miguel Sofer * generic/tclCompile.c: handle warning [Bug 969066] 2004-06-05 Kevin B. Kenny * generic/tcl.h: Corrected Tcl_WideInt declarations so that the mingw build works again. * generic/tclDecls.h: Changes to the tests for * generic/tclInt.decls: clock frequency in Tcl_WinTime * generic/tclIntDecls.h: so that any clock frequency is * generic/tclIntPlatDecls.h: accepted provided that all * generic/tclPlatDecls.h: CPU's in the system share a * generic/tclStubInit.c: common chip, and hence, * tests/platform.test (platform-1.3): presumably, a common clock. * win/tclWin32Dll.c (TclWinCPUID): This change necessitated a * win/tclWinTest.c (TestwincpuidCmd) small burst of assembly code * win/tclWinTime.c (Tcl_GetTime): to read CPU ID information, which was added as TclWinCPUID in the internal Stubs. To test this code in the common case of a single-processor machine, a 'testwincpuid' command was added to tclWinTest.c, and a test case in platform.test. Thanks to Jeff Godfrey and Richard Suchenwirth for reporting this bug. [Bug 976722] 2004-05-27 Kevin B. Kenny * tests/clock.test: Added a single test for the presence of %G in [clock format], and conditioned out the clock-10.x series if they're all going to fail because of a broken strftime() call. [Bug 961714] 2004-05-27 Reinhard Max * generic/tclEncoding.c: * tests/encoding.test: added support and tests for translating embedded null characters between real nullbytes and the internal representation on input/output. [Bug 949905] 2004-05-26 Don Porter * library/tcltest/tcltest.tcl: Correction to debug prints and testing * library/tcltest/pkgIndex.tcl: if TCLTEST_OPTIONS value. Corrected * tests/tcltest.test: double increment of numTestFiles in -singleproc 1 configurations. Updated tcltest-19.1 to tcltest 2.1 behavior. Corrected tcltest-25.3 to not falsely report a failure in tcltest.test. Bumped to tcltest 2.2.6. [Bugs 960560, 960926] 2004-05-25 Jeff Hobbs * doc/http.n (http::config): add -urlencoding option (default utf-8) * library/http/http.tcl: that specifies encoding conversion of * library/http/pkgIndex.tcl: args for http::formatQuery. Previously * tests/http.test: undefined, RFC 2718 says it should be utf-8. 'http::config -urlencoding {}' returns previous behavior, which will throw errors processing non-latin-1 chars. Bumped http package to 2.5.0. 2004-05-25 Kevin Kenny * tests/winFCmd.test: Correct test for the presence of a CD-ROM so that it doesn't misdetect some other sort of filesystem with a write-protected root as being a CD-ROM drive. [Bug 918267] 2004-05-24 Jeff Hobbs * generic/tclExecute.c (VerifyExprObjType): use GET_WIDE_OR_INT to properly have tclIntType used for smaller values. This corrects TclX bug 896727 and any other 3rd party extension that created math functions but was not yet WIDE_INT aware in them. 2004-05-24 Miguel Sofer * doc/set.n: accurate description of name resolution process, referring to namespace.n for details [Bug 959180] 2004-05-22 Miguel Sofer * generic/tclVar.c (TclObjUnsetVar2): backported fix [Bug 735335] and new (in tcl8.4) exteriorisations of [Bug 736729] due to the use of tclNsVarNameType obj types. The consequences of [Bug 736729] should be the same as in tcl8.3 and previous versions. The use of tclNsVarNameType objs is still disabled, pending a decision by the release manager. 2004-05-19 Donal K. Fellows * win/tclWinFile.c (TclpMatchInDirectory): fix for an issue where there was a sneak path from Tcl_DStringFree to SetErrorCode(0). The result was that the error code could be reset between a call to FindFirstFile and the check of its status return, leading to a bizarre error return of {POSIX unknown {No error}}. (Found in unplanned test - no incident logged at SourceForge.) 2004-05-19 Andreas Kupries * generic/tclIO.c: Fixed [SF Tcl Bug 943274]. This is the same problem * generic/tclIO.h: as [SF Tcl Bug 462317], see ChangeLog entry 2001-09-26. The fix done at that time is incomplete. It is possible to get around it if the actual read operation is defered and not executed in the event handler itself. Instead of tracking if we are in an read caused by a synthesized fileevent we now track if the OS has delivered a true event = actual data and bypass the driver if a read finds that there is no actual data waiting. The flag is cleared by a short or full read. [[this bug amended 2004-07-14]] 2004-05-18 Kevin B. Kenny * compat/strftime.c (_fmt, ISO8601Week): * doc/clock.n: * tests/clock.test: Major rework to the handling of ISO8601 week numbers. Now passes all the %G and %V test cases on Windows, Linux and Solaris [Bugs 500285, 500389, and 852944] 2004-05-17 Kevin B. Kenny * generic/tclInt.decls: Restored TclpTime_t kludge to all places * generic/tclIntPlatDecls.h: where it appeared before the changes of * unix/tclUnixPort.h 14 May, because use of native time_t in * unix/tclUnixTime.h its place requires the 8.5 header * win/tclWinTime.h: reforms. [Bug 955146] 2004-05-17 Donal K. Fellows * doc/OpenFileChnl.3: Documented type of 'offset' argument to Tcl_Seek was wrong. [Bug 953374] 2004-05-14 Kevin B. Kenny * generic/tclInt.decls: Promoted TclpLocaltime and TclpGmtime * generic/tclIntDecls.h: from Unix-specific stubs to the generic * generic/tclIntPlatDecls.h: internal Stubs table. Reran 'genstubs' * generic/tclStubInit.c: * unix/tclUnixPort.h: * generic/tclClock.c: Changed a buggy 'GMT' timezone specification to the correct 'GMT0'. [Bug 922848] * unix/tclUnixThrd.c: Moved TclpGmtime and TclpLocaltime to unix/tclUnixTime.c where they belong. * unix/tclUnixTime.c (TclpGmtime, TclpLocaltime, TclpGetTimeZone, (ThreadSafeGMTime[removed], ThreadSafeLocalTime[removed], (SetTZIfNecessary, CleanupMemory): Restructured to make sure that the same mutex protects all calls to localtime, gmtime, and tzset. Added a check in front of those calls to make sure that the TZ env var hasn't changed since the last call to tzset, and repeat tzset if necessary. [Bug 940278] Removed a buggy test of the Daylight Saving Time information in 'gettimeofday' in favor of applying 'localtime' to a known value. [Bug 922848] * tests/clock.test (clock-3.14): Added test to make sure that changes to $env(TZ) take effect immediately. * win/tclWinTime.c (TclpLocaltime, TclpGmtime): Added porting layer for 'localtime' and 'gmtime' calls. 2004-05-10 David Gravereaux * win/tclWinPipe.c (BuildCommandLine): Append a space when the path got primed. (TclpCreateProcess): When under NT, with no console, and executing a DOS application, the path priming does not need an ending space as BuildCommandLine() will append one for us. 2004-05-07 Miguel Sofer * doc/unset.n: added upvar.n to the "see also" list 2004-05-05 David Gravereaux * generic/tclEvent.c: TclSetLibraryPath's use of caching the stringrep of the pathPtr object to TclGetLibraryPath called from another thread was ineffective if the original's stringrep had been invalidated as what happens when it gets muted to a list. * generic/tclEncoding.c: Added FreeEncoding(systemEncoding) in TclFinalizeEncodingSubsystem because its ref count was incremented in TclInitEncodingSubsystem. * win/tclWin32Dll.c: Structured Exception Handling added around Tcl_Finalize called from DllMain's DLL_PROCESS_DETACH. We can't be 100% assured that Tcl is being unloaded by the OS in a stable condition and we need to protect the exit handlers should the stack be in a hosed state. AT&T style assembly for SEH under MinGW included, too. [Patch 858493] Also added DisableThreadLibraryCalls() for the DLL_PROCESS_ATTACH case. We're not interested in knowing about DLL_THREAD_ATTACH, so disable the notices. * generic/tclInt.h: * generic/tclThread.c: * generic/tclEvent.c: * unix/tclUnixThrd.c: * win/tclWinThrd.c: Provisions made so masterLock, initLock, allocLock and joinLock mutexes can be recovered during Tcl_Finalize. * win/tclWinSock.c: (SocketThreadExitHandler): Don't call TerminateThread when WaitForSingleObject returns a timeout. Tcl_Finalize called from DllMain will pause all threads. Trust that the thread will get the close notice at a later time if it does ever wake up before being cleaned up by the system anyway. (SocketEventProc): connect errors should fire both the readable and writable handlers because this is how it works on UNIX. [Bug 794839] * win/coffbase.txt: Added the tls extension to the list of preferred load addresses. 2004-05-05 Don Porter * tests/unixInit.test (unixInit-2.10): Test correction for Mac OSX. Be sure to consistently compare normalized path names. Thanks to Steven Abner (tauvan). [Bug 948177] 2004-05-05 Donal K. Fellows * doc/CrtObjCmd.3: Remove reference to Tcl_RenameCommand; there is no such API. [Bug 848440] 2004-05-04 Jeff Hobbs * generic/tclIOUtil.c (Tcl_FSChdir): Work-around crash condition * tests/winFCmd.test (winFCmd-16.12): triggered when $HOME is volumerelative (ie 'C:'). * tests/fileName.test (filename-12.9): use C:/ instead of the first item in file volumes - that's usually A:/, which for most will have nothing in it. 2004-05-04 Don Porter * tests/tcltest.test: Test corrections for Mac OSX. Thanks to Steven Abner (tauvan). [Bug 947440] 2004-05-03 Andreas Kupries Applied [SF Tcl Patch 868853], fixing a mem leak in TtySetOptionProc. Report and Patch provided by Stuart Cassoff . 2004-05-03 Kevin Kenny * win/tclWin32Dll.c (TclpCheckStackSpace): * tests/stack.test (stack-3.1): Fix for undetected stack overflow in TclReExec on Windows. [Bug 947070] 2004-05-03 Don Porter * library/init.tcl: Corrected unique prefix matching of interactive command completion in [unknown]. [Bug 946952] 2004-05-02 Miguel Sofer * generic/tclProc.c (TclObjInvokeProc): * tests/proc.test (proc-3.6): fix for bad quoting of multi-word proc names in error messages [Bug 942757] 2004-04-23 Andreas Kupries * generic/tclIO.c (Tcl_SetChannelOption): Fixed [Bug 930851]. When changing the eofchar we have to zap the related flags to prevent them from prematurely aborting the next read. 2004-04-07 Jeff Hobbs * win/configure: * win/configure.in: define TCL_LIB_FLAG, TCL_BUILD_LIB_SPEC, TCL_LIB_SPEC and TCL_PACKAGE_PATH in tclConfig.sh. 2004-04-06 Don Porter * tests/unixInit.test (unixInit-3.1): Default encoding on Darwin systems is utf-8. Thanks to Steven Abner (tauvan). [Bug 928808] 2004-04-06 Donal K. Fellows * tests/cmdAH.test (cmdAH-18.2): Added constraint because access(...,X_OK) is defined to be permitted to be meaningless when running as root, and OSX exhibits this. [Bug 929892] 2004-04-02 Don Porter * tests/tcltest.test: Corrected constraint typos: "nonRoot" -> "notRoot". Thanks to Steven Abner (tauvan). [Bug 928353] 2004-03-31 Don Porter * doc/msgcat.n: Clarified message catalog file encodings. [Bug 811457] * library/msgcat/msgcat.tcl ([mcset], [ConvertLocale], [Init]): Corrected [mcset] to be able to successfully set a translation to the empty string. [mcset $loc $src {}] was incorrectly set the $loc translation of $src back to $src. Also changed [ConvertLocale] to minimally require a non-empty "language" part in the locale value. If not, an error raised prompts [Init] to keep looking for a valid locale value, or ultimately fall back on the "C" locale. [Bug 811461] * library/msgcat/pkgIndex.tcl: Bump to msgcat 1.3.2. 2004-03-31 Donal K. Fellows * generic/tclObj.c (HashObjKey): Make sure this hashes the whole string rep of the object, instead of missing the last character. 2004-03-29 Jeff Hobbs * generic/tclInt.h: * generic/tclEncoding.c (TclFindEncodings, Tcl_FindExecutable): * mac/tclMacInit.c (TclpInitLibraryPath): Correct handling of UTF * unix/tclUnixInit.c (TclpInitLibraryPath): data that is actually * win/tclWinFile.c (TclpFindExecutable): "clean", allowing the * win/tclWinInit.c (TclpInitLibraryPath): loading of Tcl from paths that contain multi-byte chars on Windows [Bug 920667] 2004-03-28 Miguel Sofer * generic/tclCompile.c (TclCompileScript): corrected possible segfault when a compilation returns TCL_OUTLINE_COMPILE after having grown the compile environment. [Bug 925121] 2004-03-21 Jeff Hobbs * win/tclWinInt.h: define VER_PLATFORM_WIN32_CE if not already set. * win/tclWinInit.c (TclpSetInitialEncodings): recognize WIN32_CE as a unicode (WCHAR) platform. 2004-03-15 Miguel Sofer * generic/tclCompile.c (TclCompileScript): * tests/compile.test (compile-3.5): corrected wrong test and behaviour in the earlier fix for [Bug 705406]; Don Porter reported this as [Bug 735055], and provided the solution. Fixed in HEAD on 2003-05-09, but backport to 8-4-branch was wrongly omitted; re-reported as [Bug 916795] by Roy Terry, diagnosed by dgp. 2004-03-08 Vince Darley * generic/tclFileName.c: Fix to 'glob -path' near the root * tests/fileName.test: of the filesystem. [Bug 910525] 2004-03-01 Don Porter *** 8.4.6 TAGGED FOR RELEASE *** * unix/tcl.m4 (SC_CONFIG_CFLAGS): Allow 64-bit enabling on IRIX64-6.5* systems. [Bug 218561] * unix/configure: autoconf-2.13 * generic/tclCmdMZ.c (TclCheckInterpTraces): The TIP 62 * generic/tclTest.c (TestcmdtraceCmd): implementation introduced a * tests/basic.test (basic-39.10): bug by testing the CallFrame level instead of the iPtr->numLevels level when deciding what traces created by Tcl_Create(Obj)Trace to call. Added test to expose the error, and made fix. [Request 462580] 2004-02-26 Daniel Steffen * macosx/Makefile: fixed copyright year in Tcl.framework Info.plist 2004-02-25 Don Porter * tests/basic.test: Made several tests more robust to the * tests/cmdMZ.test: list-quoting of path names that might * tests/exec.test: contain Tcl-special chars like { or [. * tests/io.test: Should help us sort out Tcl Bug 554068. * tests/pid.test: * tests/socket.test: * tests/source.test: * tests/unixInit.test: 2004-02-25 Donal K. Fellows * unix/tclUnixChan.c (TcpGetOptionProc): Stop memory leak with very long hostnames. [Bug 888777] 2004-02-25 David Gravereaux * tests/winPipe.test: * win/tclWinPipe.c: backport of BuildCommandLine changes to mirror msvcrt's parse_cmdline() rules of quoting. 2004-02-19 Mo DeJong * win/tclWinInit.c (AppendEnvironment): Use the tail component of the passed in lib path instead of just blindly using lib+4. That worked when lib was "lib/..." but fails for other values. Thanks go to Patrick Samson for pointing this out. 2004-02-17 Don Porter * doc/tcltest.n: * library/tcltest/tcltest.tcl: Changed -verbose default value to {body error} so that detailed information on unexpected errors in tests is provided by default, even after the fix for [Bug 725253] 2004-02-17 Jeff Hobbs (reverted due to test failures on Solaris, but not Win/Lin :/) * generic/tclIOUtil.c: backport of rewrite of generic file normalization code to cope with links followed by '..'. [Bug 849514], and parts of [859251] * tests/unixInit.test: unixInit-7.1 * unix/tclUnixInit.c (TclpInitPlatform): ensure the std fds exist to prevent crash condition [Bug 772288] 2004-02-16 Jeff Hobbs * generic/tclCmdMZ.c (TclTraceExecutionObjCmd) (TclTraceCommandObjCmd): fix possible mem leak in trace info. 2004-02-12 Jeff Hobbs * README: update patchlevel to 8.4.6 * generic/tcl.h: * tools/tcl.wse.in: * unix/configure, unix/configure.in, unix/tcl.spec: * win/README.binary, win/configure, win/configure.in: * unix/tcl.m4: update HP-11 build libs setup 2004-02-06 Don Porter * doc/clock.n: Removed reference to non-existent [file ctime]. 2004-02-04 Don Porter * library/tcltest/tcltest.tcl: Corrected references to non-existent $name variable in [cleanupTests]. [Bug 833637] 2004-02-03 Don Porter * library/tcltest/tcltest.tcl: Corrected parsing of single command line argument (option with missing value) [Bug 833910] * library/tcltest/pkgIndex.tcl: Bump to version 2.2.5. 2004-02-02 David Gravereaux * generic/tclIO.c (Tcl_Ungets): fixes improper filling of the channel buffer. [Bug 405995] 2004-01-13 Don Porter * generic/tclFileName.c (Tcl_GlobObjCmd): Latest changes to management of the interp result by Tcl_GetIndexFromObj() exposed improper interp result management in the [glob] command procedure. Corrected by adopting the Tcl_SetObjResult(Tcl_NewStringObj) pattern. This stopped a segfault in test filename-11.36. 2004-01-13 Donal K. Fellows * generic/tclIndexObj.c (Tcl_GetIndexFromObjStruct, Tcl_WrongNumArgs): Create fresh objects instead of using the one currently in the interpreter, which isn't guaranteed to be fresh and unshared. The cost for the core will be minimal because of the object cache, and this fixes. [Bug 875395] 2004-01-09 Vince Darley * generic/tclIOUtil.c: fix to infinite loop in TclFinalizeFilesystem. [Bug 873311] 2003-12-17 Daniel Steffen * generic/tclBinary.c (DeleteScanNumberCache): fixed crashing bug when numeric scan-value cache contains NULL value. 2003-12-17 Zoran Vasiljevic * generic/tclIOUtil.c: fixed 2 memory (object) leaks. This fixes [Bug 839519] 2003-12-12 Vince Darley * generic/tclCmdAH.c: fix to normalization of non-existent user name ('file normalize ~nobody') [Bug 858937] 2003-12-09 Donal K. Fellows * unix/tclUnixPort.h: #ifdef'd out declarations of errno which * tools/man2tcl.c: are known to cause problems with recent glibc. [Bug 852369] 2003-12-03 Don Porter * generic/tcl.h: Bumped patch level to 8.4.5.1 to distinguish * unix/configure.in: CVS snapshots from 8.4.5 release. * unix/tcl.spec: * win/configure.in: * unix/configure: autoconf (2.13) * win/configure: 2003-12-02 Donal K. Fellows * generic/tclBinary.c (DeleteScanNumberCache, ScanNumber): Made the numeric scan-value cache have proper references to the objects within it so strange patterns of writes won't cause references to freed objects. Thanks to Paul Obermeier for the report. [Bug 851747] 2003-12-01 Miguel Sofer * doc/lset.n: fix typo [Bug 852224] 2003-11-21 Don Porter *** 8.4.5 TAGGED FOR RELEASE *** * tests/windFCmd.test (winFCmd-16.10): Corrected failure to initialize variable $dd that caused test suite failure. 2003-11-20 Miguel Sofer * generic/tclVar.c: fix flag bit collision between LOOKUP_FOR_UPVAR and TCL_PARSE_PART1 (deprecated) [Bug 835020] 2003-11-20 Vince Darley * generic/tclIOUtil.c: * tests/winFCmd.test: fix to [Bug 845778] - Infinite recursion on [cd] (Windows only bug). 2003-11-18 Jeff Hobbs * changes: updated for 8.4.5 release 2003-11-17 Don Porter * generic/regcomp.c: Backported regexp bug fixes and tests. Thanks * generic/tclTest.c: to Pavel Goran and Vince Darley. * tests/reg.test: [Bugs 230589, 504785, 505048, 703709, 840258] 2003-11-12 Jeff Hobbs * tests/cmdMZ.test (cmdMZ-1.4): change to nonPortable as more systems are using permissions caching, and this isn't really a Tcl controlled issue. 2003-11-11 Jeff Hobbs * unix/configure: * unix/tcl.m4: improve AIX --enable-64bit handling 2003-11-10 Don Porter * tests/unixInit.test (unixInit-2.10): re-enabled. * unix/tclUnixInit.c (TclpInitLibraryPath): Alternative fix * win/tclWinInit.c (TclpInitLibraryPath): for [Bug 832657] that should not run afoul of startup constraints. * library/dde/pkgIndex.tcl: Added safeguards so that registry * library/reg/pkgIndex.tcl: and dde packages are not offered * win/tclWinDde.c: on non-Windows platforms. Bumped to * win/tclWinReg.c: registry 1.1.3 and dde 1.2.2. 2003-11-06 Jeff Hobbs * tests/unixInit.test (unixInit-2.10): mark as knownBug * generic/tclEncoding.c (TclFindEncodings): revert patch from 2003-11-05. It wasn't valid in the sensitive startup init phase and broke Windows from working at all. 2003-11-07 Daniel Steffen * macosx/Makefile: optimized builds define NDEBUG to turn off ThreadAlloc range checking. 2003-11-05 Don Porter * generic/tclEncoding.c (TclFindEncodings): Normalize the path of the executable before passing to TclpInitLibraryPath() to avoid buggy handling of paths containing "..". [Bug 832657] * tests/unixInit.test (unixInit-2.10): New test for fixed bug. 2003-11-04 Daniel Steffen * macosx/Makefile: added 'test' target. 2003-10-31 Vince Darley * generic/tclTest.c: fix test suite memory leak (backport error) * unix/tclUnixFile.c: ensure translated path (required for correct error messages) is freed in both code paths. 2003-10-23 Andreas Kupries * unix/tclUnixChan.c (Tcl_MakeFileChannel): Applied [Patch 813606] fixing [Bug 813087]. Detection of sockets was off for Mac OS X which implements pipes as local sockets. The new code ensures that only IP sockets are detected as such. 2003-10-22 Andreas Kupries * win/tclWinSock.c (TcpWatchProc): Watch for FD_CLOSE too when asked for writable events by the generic layer. (SocketEventProc): Generate a writable event too when a close is detected. Together the changes fix [Bug 599468]. 2003-10-22 Andreas Kupries * generic/tclIOUtil.c (FsListMounts, FsAddMountsToGlobResult): New functions. See below for context. (Tcl_FSMatchInDirectory): Modified to call on the new functions (above) to handle the mountpoints in the glob'bed directory correctly. Part of the patch by Vincent Darley to solve the [Bug 800106] for the 8.4.x series. * generic/tcl.h (TCL_GLOB_TYPE_MOUNT): New definition. Part of the patch by Vincent Darley to solve [Bug 800106] for the 8.4.x series. 2003-10-22 Donal K. Fellows * generic/tclCmdAH.c (Tcl_FileObjCmd): Changed FILE_ prefix for option enumeration to FCMD_ to prevent collision with symbols defined by Cygwin/Mingw32 on NT. [Bug 822528] 2003-10-21 Daniel Steffen * tools/tcltk-man2html.tcl: fixed incorrect html generated for .IP/.TP lists, now use
...
...

...
...
instead of illegal

...
...

...
...
. Added skipping of directives directly after .TP to avoid them being used as item descriptions, e.g. .TP\n.VS in clock.n. 2003-10-21 Andreas Kupries * win/tclWinPipe.c (BuildCommandLine): Applied the patch coming with [Bug 805605] to the code, fixing the incorrect use of ispace noted by Ronald Dauster . 2003-10-14 David Gravereaux * win/tclAppInit.c (sigHandler): Punt gracefully if exitToken has already been destroyed. 2003-10-13 Vince Darley * generic/tclCmdMZ.c: * tests/regexp.test: fix to [Bug 823524] in regsub; added three new tests. 2003-10-12 Jeff Hobbs * unix/tclUnixTest.c (TestalarmCmd): don't bother checking return value of alarm. [Bug 664755] (english) 2003-10-08 Don Porter * generic/tclBasic.c: Save and restore the iPtr->flag bits that control the state of errorCode and errorInfo management when calling "leave" execution traces, so that all error information of the traced command is still available whether traced or not. Thanks to Yahalom Emet. [Bug 760947] 2003-10-08 Donal K. Fellows * generic/tclTest.c (TestNumUtfCharsCmd): Command to allow finer access to Tcl_NumUtfChars for testing. * generic/tclUtf.c (Tcl_NumUtfChars): Corrected string length determining when the length parameter is negative; the terminator is a zero byte, not (necessarily) a \u0000 character. [Bug 769812] 2003-10-07 Don Porter * tests/exec.test: Corrected temporary file management * tests/fileSystem.test: issues uncovered by -debug 1 test * tests/io.test: operations. Also backported some * tests/ioCmd.test: other fixes from the HEAD. * tests/pid.test: [Bugs 675605, 675655, 675659] * tests/socket.test: * tests/source.test: * tests/fCmd.test: Run tests with the [temporaryDirectory] as the current directory, so that tests can depend on ability to write files. [Bug 575837] * doc/OpenFileChnl.3: Updated Tcl_Tell and Tcl_Seek documentation to reflect that they now return Tcl_WideInt (TIP 72) [Bug 787537] * tests/io.test: Corrected several tests that failed when paths * tests/ioCmd.test: included regexp-special chars. [Bug 775394] 2003-10-06 Don Porter * tests/regexp.test: Matched [makeFile] with [removeFile]. * tests/regexpComp.test: [Bug 675652] * tests/fCmd.test (fCmd-8.2): Test only that tilde-substitution happens, not for any particular result. [Bug 685991] * unix/tcl.m4 (SC_PATH_TCLCONFIG): Corrected search path so that alpha and beta releases of Tcl are not favored. [Bug 608698] * tests/reg.test: Corrected duplicate test names. * tests/resource.test: [Bugs 710370, 710358] * tests/cmdMZ.test: Updated [package require tcltest] lines to * tests/fileSystem.test: indiciate that these test files * tests/notify.test: use features of tcltest 2. [Bug 706114] * tests/parseExpr.test: * tests/unixNotfy.test: 2003-10-06 Vince Darley * generic/tclFileName.c: * generic/tclIOUtil.c: backport of volumerelative file normalization and 'file join' inconsistency fixes [Bug 767834, 813273]. 2003-10-04 Chengye Mao * win/tclWinPipe.c: fixed a bug in BuildCommandLine. This bug built a command line with a missing space between tclpipe.dll and the following arguments. It caused error in Windows 98 when exec command.com (e.g. dir) [Bug 789040] 2003-10-03 Don Porter * generic/tclBasic.c: Fixed error in ref count management of command * generic/tclCmdMZ.c: and execution traces that caused access to freed memory in trace-32.1. [Bug 811483] 2003-10-03 Vince Darley * tests/fileName.test: * tests/winFCmd.test: * doc/FileSystem.3: backported various test and documentation changes from HEAD. Backport of actual code fixes to follow. 2003-10-02 Don Porter * README: Bumped patch level to 8.4.5 to prepare * generic/tcl.h: for next patch release. * tools/tcl.wse.in: * unix/configure.in: * unix/tcl.spec: * win/README.binary: * win/configure.in: * unix/configure: autoconf (2.13) * win/configure: * library/http/http.tcl: Bumped to http 2.4.5 * library/http/pkgIndex.tcl: 2003-10-01 Daniel Steffen * macosx/Makefile: fixed redo prebinding bug when DESTDIR="". * mac/tclMacResource.c: fixed possible NULL dereference (bdesgraupes). 2003-09-29 Don Porter * generic/tclBasic.c (CallCommandTraces): Added safety bit * tests/trace.test: masking to prevent any of the bit values TCL_TRACE_*_EXEC from leaking into the flags field of any Command struct. This does not fix [Bug 811483] but helps to contain some of its worst symptoms. Also backported the corrections to test trace-28.4 from Vince Darley. 2003-09-29 Donal K. Fellows * library/http/http.tcl (geturl): Correctly check the type of boolean-valued options. [Bug 811170] * unix/tcl.m4 (SC_ENABLE_FRAMEWORK): Added note to make it clearer that this is an OSX feature, not a general Unix feature. [Bug 619440] 2003-09-28 David Gravereaux * win/tclWinPipe.c: The windows port of expect can call TclWinAddProcess before any of the other pipe functions. Added a missing PipeInit() call to make sure the initialization happens. 2003-09-25 Daniel Steffen * macosx/Makefile: ensure SYMROOT exists if OBJROOT is overridden on command line. Replaced explict use of /usr/bin by ${BINDIR}. 2003-09-23 Don Porter * generic/tclCmdMZ.c: Fixed [Bug 807243] where * tests/trace.test (trace-31,32.*): the introspection results of both [trace info command] and [trace info execution] were getting co-mingled. Thanks to Mark Saye for the report. * library/init.tcl (auto_load, auto_import): Expanded Eric Melski's 2000-01-28 fix for [Bug 218871] to all potentially troubled uses of [info commands] on input data, where glob-special characters could cause problems. 2003-09-19 Miguel Sofer * generic/tclExecute.c: adding (DE)CACHE_STACK_INFO() pairs to protect all calls that may cause traces on ::errorInfo or ::errorCode to corrupt the stack [Bug 804681] 2003-09-10 Don Porter * library/opt/optparse.tcl: Overlooked dependence of opt 0.4.4 * library/opt/pkgIndex.tcl: on Tcl 8.2. Bumped to opt 0.4.4.1. 2003-09-01 Zoran Vasiljevic * generic/tclIOUtil.c: backported fix from HEAD [Bug 788780] 2003-08-27 Don Porter * generic/tclUtil.c: Corrected [Bug 411825] and other bugs in TclNeedSpace() where non-breaking space (\u00A0) and backslash-escaped spaces were handled incorrectly. * tests/util.test: Added new tests util-8.[2-6]. 2003-08-06 Jeff Hobbs * win/tclWinInit.c: recognize amd64 and ia32_on_win64 cpus and Windows CE platform. 2003-08-06 Don Porter * library/msgcat/msgcat.tcl: Added escape so that non-Windows * library/msgcat/pkgIndex.tcl: platforms do not try to use the registry package. This can save a costly and pointless package search. Bumped to 1.3.1. Thanks to Dave Bodenstab. [Bug 781609] 2003-08-05 Miguel Sofer * generic/tclExecute.c (INST_INVOKE, INST_EVAL, INST_PUSH_RESULT): added a Tcl_ResetResult(interp) at each point where the interp's result is pushed onto the stack, to avoid keeping an extra reference that may cause costly Tcl_Obj duplication. Detected by Franco Violi, analyzed by Peter Spjuth and Donal Fellows. [Bug 781585] 2003-07-24 Reinhard Max * library/package.tcl: Fixed a typo that broke pkg_mkIndex -verbose. * tests/pkgMkIndex.test: Added a test for [pkg_mkIndex -verbose]. 2003-07-23 Daniel Steffen * unix/Makefile.in: changes to html-tcl & html-tk targets for compatibility with non-gnu makes. * unix/Makefile.in: added macosx/README to dist target. 2003-07-23 Pat Thoyts * win/tclWinReg.c (OpenSubKey): Backported fix for [Bug 775976] which causes the registry set command to fail when built with VC7. * library/reg/pkgIndex.tcl: Incremented the version to 1.1.2. 2003-07-21 Jeff Hobbs *** 8.4.4 TAGGED FOR RELEASE *** * changes: updated for 8.4.4 release 2003-07-18 Daniel Steffen * macosx/Makefile: added option to allow installing manpages in addition to default html help. 2003-07-18 Donal K. Fellows * doc/Utf.3: Tightened up documentation of Tcl_UtfNext and Tcl_UtfPrev to better match the behaviour. [Bug 769895] 2003-07-18 Jeff Hobbs * generic/tclIOUtil.c: correct MT-safety issues with filesystem records. [Bug 753315] (vasiljevic) * library/http/pkgIndex.tcl: merged to v2.4.4 from head * library/http/http.tcl: add support for user:pass info in URL. * tests/http.test: [Bug 759888] (shiobara) 2003-07-18 Don Porter * generic/tclBasic.c: Corrected several instances of unsafe * generic/tclCompile.c: truncation of UTF-8 strings that might break * generic/tclProc.c: apart a multi-byte character. [Bug 760872] * library/init.tcl: * tests/init.test: * doc/tcltest.n: Restored the [Eval] proc to replace * library/tcltest/tcltest.tcl: the [::puts] command when either the -output or -error option for [test] is in use, in order to capture data written to the output or error channels for comparison against what is expected. This is easier to document and agrees better with most user expectations than the previous attempt to replace [puts] only in the caller's namespace. Documentation made more precise on the subject. [Bug 706359] * doc/AddErrInfo.3: Improved consistency of documentation by using * doc/CrtTrace.3: "null" everywhere to refer to the character * doc/Encoding.3: '\0', and using "NULL" everywhere to refer to * doc/Eval.3: the value of a pointer that points to nowhere. * doc/GetIndex.3: Also dropped references to ASCII that are no * doc/Hash.3: longer true, and standardized on the * doc/LinkVar.3: hyphenated spelling of "null-terminated". * doc/Macintosh.3: * doc/OpenFileChnl.3: * doc/SetVar.3: * doc/StringObj.3: * doc/Utf.3: * doc/CrtSlave.3 (Tcl_MakeSafe): Removed warning about possible deprecation (no TIP on that). 2003-07-17 Daniel Steffen * macosx/Makefile: added var to allow overriding of tclsh used during html help building (Landon Fuller). 2003-07-16 Mumit Khan * generic/tclIOUtil.c (SetFsPathFromAny): Add Cygwin specific code to convert POSIX filename to native format. * generic/tclFileName.c (Tcl_TranslateFileName): And remove from here. (TclDoGlob): Adjust for cygwin and append / for dirs instead of \ * win/tclWinFile.c (TclpObjChdir): Use chdir on Cygwin. [Patch 679315] 2003-07-16 Jeff Hobbs * library/safe.tcl (FileInAccessPath): normalize paths before comparison. [Bug 759607] (myers) * unix/tclUnixNotfy.c (NotifierThreadProc): correct size of found and word vars from int to long. [Bug 767578] (hgo) 2003-07-16 Donal K. Fellows * doc/CrtSlave.3 (Tcl_MakeSafe): Updated documentation to strongly discourage use. IMHO code outside the core that uses this function is a bug... [Bug 655300] 2003-07-16 Jeff Hobbs * generic/tcl.h: Add recognition of -DTCL_UTF_MAX=6 on the * generic/regcustom.h: make line to support UCS-4 mode. No config arg at this time, as it is not the recommended build mode. * generic/tclPreserve.c: In Result and Preserve'd routines, do not * generic/tclUtil.c: assume that ckfree == free, as that is not * generic/tclResult.c: always true. [Bug 756791] (fuller) 2003-07-16 Mo DeJong * win/Makefile.in: Don't define TCL_DBGX symbol for every compile. Instead, define TCL_PIPE_DLL only when compiling tclWinPipe.c. This will break other build systems, so they will need to remove the TCL_DBGX define and replace it with a define for TCL_PIPE_DLL. * win/makefile.vc: Ditto. * win/tclWinPipe.c (TclpCreateProcess): Remove PREFIX_IDENT and DEBUG_IDENT from top of file. Use TCL_PIPE_DLL passed in from build env instead of trying to construct the dll name from already defined symbols. This approach is more flexible and better in the long run. 2003-07-16 Don Porter * generic/tclFileName.c (Tcl_GlobObjCmd): [Bug 771840] * generic/tclIOUtil.c (Tcl_FSConvertToPathType):[Bug 771947] * unix/tclUnixFCmd.c (GetModeFromPermString): [Bug 771949] Silence compiler warnings about unreached lines. * library/tcltest/tcltest.tcl (ProcessFlags): Corrected broken call * library/tcltest/pkgIndex.tcl: to [lrange]. Bumped to version 2.2.4. [Bug 772333] 2003-07-15 Mo DeJong * unix/dltest/pkga.c (Pkga_EqObjCmd): Fix typo that was causing a crash in load.test. 2003-07-15 Donal K. Fellows * doc/array.n: Added some examples from David Welton [Patch 763312] 2003-07-15 Don Porter * doc/http.n: Updated SYNOPSIS to match actual syntax of commands. [Bug 756112] * unix/dltest/pkga.c: Updated to not use Tcl_UtfNcmp and counted strings instead of strcmp (not defined in any #include'd header) and presumed NULL-terminated strings. * README: Bumped patch level to 8.4.4 in anticipation * generic/tcl.h: of another patch release. * tools/tcl.wse.in: * unix/configure.in: * unix/tcl.spec: * win/README.binary: * win/configure.in: * unix/configure: autoconf (2.13) * win/configure: * generic/tclCompCmds.c (TclCompileIfCmd): Prior fix of Bug 711371 on 2003-04-07 introduced a buffer overflow. Corrected. [Bug 771613] 2003-07-15 Donal K. Fellows * generic/tclCmdIL.c (SortCompare): Cleared up confusing error message. [Bug 771539] 2003-07-15 Daniel Steffen * macosx/Makefile: Rewrote buildsystem for Mac OS X framework build to be purely make driven; in order to become independent of Apple's closed-source IDE and build tool. The changes are intended to be transparent to the Makefile user, all existing make targets and cmd line variable overrides should continue to work. Changed build to only include tcl specific html help in Tcl.framework, the tk specific html help is now included in Tk.framework. * macosx/Tcl.pbproj/project.pbxproj: * macosx/Tcl.pbproj/jingham.pbxuser: Changed to purely call through to the make driven buildsystem; Tcl.framework is no longer assembled by ProjectBuilder. Set default SYMROOT in target options to simplify setting up PB (manually setting common build folder for tcl & tk no longer needed). * tools/tcltk-man2html.tcl: Added options to allow building only the tcl or tk html help files; the default behaviour with none of the new options is to build both, as before. * unix/Makefile.in: Added targets for building only the tcl or tk help. * macosx/README (new): Tcl specific excerpts of tk/macosx/README. * generic/tcl.h: Updated reminder comment about editing macosx/Tcl.pbproj/project.pbxproj when version number changes. 2003-07-11 Donal K. Fellows * tests/binary.test (binary-46.*): Tests to help enforce the current behaviour. * doc/binary.n: Documented that [binary format a] and [binary scan a] do encoding conversion by dropping high bytes, unlike the rest of the core. [Bug 735364] 2003-07-11 Don Porter * library/package.tcl: Corrected [pkg_mkIndex] bug reported on comp.lang.tcl. The indexer was searching for newly indexed packages instead of newly provided packages. 2003-07-04 Donal K. Fellows * doc/expr.n: Tighten up the wording of some operations. [Bug 758488] * tests/cmdAH.test: Made tests of [file mtime] work better on FAT filesystems. [Patch 760768] Also a little general cleanup. 2003-06-25 Mo DeJong * unix/configure: Regen. * unix/tcl.m4 (SC_CONFIG_CFLAGS): Add -ieee when compiling with cc and add -mieee when compiling with gcc under OSF1-V5 "Tru64" systems. [Bug 748957] 2003-06-24 Donal K. Fellows * doc/encoding.n: Corrected the docs to say that [source] uses the system encoding, which it always did anyway (since 8.1) [Bug 742100] 2003-06-23 Vince Darley * generic/tclFCmd.c: fix to bad error message when trying to do 'file copy foo ""'. [Bug 756951] * tests/fCmd.test: added two new tests for the bug. * doc/FileSystem.3: documentation fix [Bug 720634] 2003-06-18 Miguel Sofer * generic/tclNamesp.c (Tcl_Export): removed erroneous comments [Bug 756744] 2003-06-17 Vince Darley * generic/tclCmdMZ.c: * tests/regexp.test: fixing of bugs related to regexp and regsub matching of empty strings. Addition of a number of new tests. 2003-06-10 Miguel Sofer * generic/tclBasic.c: * generic/tclExecute.c: let TclEvalObjvInternal call TclInterpReady instead of relying on its callers to do so; fix for the part of [Bug 495830] that is new in 8.4. * tests/interp.test: Added tests 18.9 (knownbug) and 18.10 2003-06-09 Don Porter * tests/string.test (string-4.15): Added test for [string first] bug reported in Tcl 8.3, where test for all-single-byte-encoded strings was not reliable. 2003-06-04 Joe Mistachkin * tools/man2help.tcl: Added duplicate help section checking and * tools/index.tcl: corrected a comment typo for the getTopics proc in index.tcl. [Bug 748700] 2003-05-23 Don Porter * generic/tclObj.c (tclCmdNameType): Converted internal rep management of the cmdName Tcl_ObjType the opposite way, to always use the twoPtrValue instead of always using the otherValuePtr. Previous fix on 2003-05-12 broke several extensions that wanted to poke around with the twoPtrValue.ptr2 value of a cmdName Tcl_Obj, like TclBlend and e4graph. [Bug 726018] Thanks to George Petasis for the bug report and Jacob Levy for testing assistance. 2003-05-22 Daniel Steffen *** 8.4.3 TAGGED FOR RELEASE *** * macosx/tclMacOSXBundle.c: fixed a problem that caused only the first call to Tcl_MacOSXOpenVersionedBundleResources() for a given bundle identifier to succeed. This caused the tcl runtime library not to be found in all interps created after the inital one. 2003-05-20 Jeff Hobbs * changes: updated for 8.4.3 * unix/Makefile.in: do not run autoconf during 'make dist' as the configure is now a CVS-maintained file and should be up-to-date. 2003-05-19 Daniel Steffen * macosx/Tcl.pbproj/project.pbxproj: changed tclConfig.sh location in versioned framework subdirectories to be identical to location in framework toplevel; fixed stub library symbolic links to be Tcl version specific. 2003-05-16 Daniel Steffen * macosx/Tcl.pbproj/project.pbxproj: updated copyright year. 2003-05-15 Jeff Hobbs * win/tclWinFile.c (TclpMatchInDirectory): revert glob code to r1.44 as 2003-04-14 optimizations broke Windows98 glob'ing. * README: bumped version to 8.4.3 * generic/tcl.h: * macosx/Tcl.pbproj/project.pbxproj: * tools/tcl.wse.in: * unix/configure: * unix/configure.in: * unix/tcl.spec: * win/README.binary: * win/configure: * win/configure.in: * doc/socket.n: nroff font handling correction. * library/encoding/gb2312-raw.enc (new): This is the original gb2312.enc renamed to allow for it to still be used. This is needed by Tk (unix) because X fonts with gb2312* charsets really do want the original gb2312 encoding. [Bug 557030] 2003-05-14 Donal K. Fellows * generic/tclCmdAH.c (Tcl_FormatObjCmd): Values which can't be anything but wide shouldn't be demoted to long. [consequence of HEAD fixes for Bug 699060] 2003-05-14 Jeff Hobbs * library/encoding/gb2312.enc: copy euc-cn.enc over original gb2312.enc. gb2312.enc appeared to not work as expected, and most uses of gb2312 really mean euc-cn (which may be the cause of the problem). [Bug 557030] * generic/tclEnv.c (TclUnsetEnv): Another putenv() copy behavior problem repaired when compiling on windows and using microsoft's runtime. [Bug 736421] (gravereaux) 2003-05-13 Jeff Hobbs * generic/tclIOUtil.c: add decl for FsThrExitProc to suppress warnings 2003-05-13 Donal K. Fellows * generic/tclEvent.c (Tcl_Finalize): Removed unused variable to reduce compiler warnings. [Bug 664745] 2003-05-13 Joe Mistachkin * generic/tcl.decls: Changed Tcl_JoinThread parameter name from "id" * generic/tclDecls.h: to "threadId". [Bug 732477] * unix/tclUnixThrd.c: * win/tclWinThrd.c: * mac/tclMacThrd.c: 2003-05-13 Daniel Steffen * generic/tcl.decls: * macosx/tclMacOSXBundle.c: added extended version of the Tcl_MacOSXOpenBundleResources() API taking an extra version number argument: Tcl_MacOSXOpenVersionedBundleResources(). This is needed to be able to access bundle resources in versioned frameworks such as Tcl and Tk, otherwise if multiple versions were installed, only the latest version's resources could be accessed. [Bug 736774] * unix/tclUnixInit.c (Tcl_MacOSXGetLibraryPath): use new versioned bundle resource API to get tcl runtime library for TCL_VERSION. [Bug 736774] * generic/tclPlatDecls.h: * generic/tclStubInit.c: regen. * unix/tclUnixPort.h: worked around the issue of realpath() not being thread-safe on Mac OS X by defining NO_REALPATH for threaded builds on Mac OS X. [Bug 711232] 2003-05-12 Don Porter * generic/tclInterp.c: (AliasObjCmd): Added refCounting of the words * tests/interp.test (interp-33.1): of the target of an interp alias during its execution. Also added test. [Bug 730244]. * generic/tclBasic.c (TclInvokeObjectCommand): objv[argc] is no longer set to NULL (Tcl_CreateObjCommand docs already say that it should not be accessed). * generic/tclObj.c (tclCmdNameType): Corrected variable use of the otherValuePtr or the twoPtrValue.ptr1 fields to store a (ResolvedCmdName *) as the internal rep. [Bug 726018]. * doc/Eval.3: Corrected prototype for Tcl_GlobalEvalObj [Bug 727622]. 2003-05-12 Miguel Sofer * generic/tclVar.c (TclObjLookupVar): [Bug 735335] temporary fix, disabling usage of tclNsVarNameType. * tests/var.test (var-15.1): test for [Bug 735335] 2003-05-10 Zoran Vasiljevic * unix/tclUnixThrd.c: corrected [Bug 723502] 2003-05-10 Jeff Hobbs * generic/tclIOUtil.c: ensure cd is thread-safe. [Bug 710642] (vasiljevic) * win/tclWinSerial.c (SerialCloseProc): correct mem leak on closing a Windows serial port [Bug 718002] (schroedter) * generic/tclCmdMZ.c (Tcl_StringObjCmd): prevent string repeat crash when overflow sizes were given (throws error). [Bug 714106] 2003-05-09 Joe Mistachkin * generic/tclThreadAlloc.c (TclFreeAllocCache): Fixed memory leak caused by treating cachePtr as a TLS index [Bug 731754]. * win/tclAppInit.c (Tcl_AppInit): Fixed memory leaks caused by not freeing the memory allocated by setargv and the async handler created by Tcl_AppInit. An exit handler has been created that takes care of both leaks. In addition, Tcl_AppInit now uses ckalloc instead of Tcl_Alloc to allow for easier leak tracking and to be more consistent with the rest of the Tcl core [Bugs 733156, 733221]. * tools/encoding/txt2enc.c (main): Fixed memory leak caused by failing to free the memory used by the toUnicode array of strings [Bug 733221] 2003-05-05 Don Porter * library/tcltest/tcltest.tcl: The -returnCodes option to [test] failed to recognize the symbolic name "ok" for return code 0. 2003-05-05 Donal K. Fellows * generic/tclBasic.c (Tcl_HideCommand): Fixed error message grammar and spelling. 2003-04-29 Vince Darley * generic/tclFileName.c: fix to bug reported privately by Jeff where, for example, 'glob -path {[tcl]} *' gets confused by the leading special character (which is escaped internally), and instead lists files in '/'. Bug only occurs on Windows where '\' is also a directory separator. (Bug has been around at least since Tcl 8.3.) * tests/fileName.test: added test for the above bug. 2003-04-25 Don Porter * generic/tclBasic.c: Tcl_EvalObjv() failed to honor the TCL_EVAL_GLOBAL flag when resolving command names. Tcl_EvalEx passed a string rep including leading whitespace and comments to TclEvalObjvInternal(). 2003-04-25 Andreas Kupries * win/tclWinThrd.c: Applied [Patch 727271]. This patch changes the code to catch any errors returned by the windows functions handling TLS ASAP instead of waiting to get some mysterious crash later on due to bogus pointers. Patch provided by Joe Mistachkin. This is a stop-gap measure to deal with the low number of ?TLS slots provided by some of the variants of Windows (60-80). 2003-04-21 Don Porter * library/tcltest/tcltest.tcl: When the return code of a test does not meet expectations, report that as the reason for test failure, and do not attempt to check the test result for correctness. [Bug 725253] 2003-04-18 Jeff Hobbs * generic/tclExecute.c (ExprCallMathFunc): remove incorrect extraneous cast from Tcl_WideAsDouble. 2003-04-18 Donal K. Fellows * doc/open.n: Moved serial port options from [fconfigure] * doc/fconfigure.n: to [open] as it is up to the creator of a channel to describe the channel's special config options. [Bug 679010] 2003-04-16 Don Porter * generic/tcl.h Made changes so that the "wideInt" Tcl_ObjType * generic/tclObj.c is defined on all platforms, even those where * generic/tclPort.h TCL_WIDE_INT_IS_LONG is defined. Also made the Tcl_Value struct have a wideValue field on all platforms. This is a ***POTENTIAL INCOMPATIBILITY*** for TCL_WIDE_INT_IS_LONG platforms because that struct changes size. This is the same TIP 72 incompatibility that was seen on other platforms at the 8.4.0 release, when this change should have happened as well. [Bug 713562] * generic/tclInt.h: New internal macros TclGetWide() and TclGetLongFromWide() to deal with both forms of the "wideInt" Tcl_ObjType, so that conditional TCL_WIDE_INT_IS_LONG code is confined to the header file. * generic/tclCmdAH.c: Replaced most coding that was conditional * generic/tclCmdIL.c: on TCL_WIDE_INT_IS_LONG with code that * generic/tclExecute.c: works across platforms, sometimes using * generic/tclTest.c: the new macros above to do it. * generic/tclUtil.c: * generic/tclVar.c: 2003-04-17 Donal K. Fellows * doc/socket.n: Added a paragraph to remind people to specify their encodings when using sockets. [Bug 630621] 2003-04-16 Donal K. Fellows * doc/CrtMathFnc.3: Functions also have to deal with wide ints, but this was not documented. [Bug 709720] 2003-04-15 Kevin Kenny * win/tclWinTime.c: Corrected use of types to make compilation compatible with VC++5. 2003-04-14 Kevin Kenny * win/tclWinFile.c: added conditionals to restore compilation on VC++6, which was broken by recent changes. 2003-04-14 Vince Darley Merged various bug fixes from current cvs head: * tests/cmdAH.test: better fix to test suite problem if /home is a symlink [Bug 703264] * generic/tclIOUtil.c: fix bad error message with 'cd ""' [Bug 704917] * win/tclWinFile.c: * win/tclWin32Dll.c: * win/tclWinInt.h: allow Tcl to differentiate between reparse points which are symlinks and mounted volumes, and correctly handle the latter. This involves some elaborate code to find the actual drive letter (if possible) corresponding to a mounted volume. [Bug 697862] * tests/fileSystem.test: add constraints to stop tests running in ordinary tcl interpreter. [Bug 705675] * generic/tclIOUtil.c: Some re-arrangement of code to bring it closer to CVS HEAD. No functional changes. * tests/fCmd.test: * win/tclWinFile.c: added some filesystem optimisation to the 'glob' implementation, and some new tests. * tests/winFile.test: * tests/ioUtil.test: * tests/unixFCmd.test: renumbered tests with duplicate numbers. [Bug 710361] 2003-04-12 Kevin Kenny * tests/clock.test: Renumbered test cases to avoid duplicates [Bug 710310]. * tests/winTime.test: * win/tclWinTest.c (TestwinclockCmd, TestwinsleepCmd): * win/tclWinTime.c (Tcl_WinTime, UpdateTimeEachSecond, (ResetCounterSamples, AccumulateSample, SAMPLES, TimeInfo): Made substantial changes to the phase-locked loop (replaced an IIR filter with an FIR one) in a quest for improved loop stability (Bug not logged at SF, but cited in private communication from Jeff Hobbs). 2003-04-11 Don Porter * generic/tclCmdMZ.c (Tcl_StringObjCmd,STR_IS_INT): Corrected inconsistent results of [string is integer] observed on systems where sizeof(long) != sizeof(int). [Bug 718878] * tests/string.test: Added tests for Bug 718878. * doc/string.n: Clarified that [string is integer] accepts 32-bit integers. 2003-04-11 Andreas Kupries * generic/tclIO.c (UpdateInterest): When dropping interest in TCL_READABLE now dropping interest in TCL_EXCEPTION too. This fixes a bug where Expect detects eof on a file prematurely on Solaris 2.6 and higher. A much more complete explanation is in the code itself (40 lines of comments for a one-line change :) 2003-04-10 Donal K. Fellows * doc/binary.n: Fixed typo in [binary format w] desc. [Bug 718543] 2003-04-08 Donal K. Fellows * generic/tclCmdAH.c (Tcl_ErrorObjCmd): Strings are only empty if they have zero length, not if their first byte is zero, so fix test guarding Tcl_AddObjErrorInfo to take this into account. [Bug reported by Don Porter; no bug-id.] 2003-04-07 Don Porter * generic/tclCompCmds.c (TclCompileIfCmd): Corrected string limits of arguments interpolated in error messages. [Bug 711371] * generic/tclCmdMZ.c (TraceExecutionProc): Added missing Tcl_DiscardResult() call to avoid memory leak. 2003-04-07 Donal K. Fellows * generic/tclObj.c (tclWideIntType, TclInitObjSubsystem): (SetBooleanFromAny): Make sure that tclWideIntType is defined and somewhat sensible everywhere. [Bug 713562] 2003-04-02 Mo DeJong * win/configure: Regen. * win/configure.in: Set stub lib flag based on new LIBFLAGSUFFIX variable. * win/tcl.m4 (SC_CONFIG_CFLAGS): Set new LIBFLAGSUFFIX that works like LIBSUFFIX, it is used when creating library names. The previous implementation would generate -ltclstub85 instead of -ltclstub85s when configured with --disable-shared. 2003-04-01 Don Porter * tests/README: Direct [source] of *.test files is no longer recommended. The tests/*.test files should only be evaluated under the control of the [runAllTests] command in tests/all.tcl. 2003-03-27 Miguel Sofer * tests/encoding.test: * tests/proc-old.test: * tests/set-old.test: Altered test numers to eliminate duplicates, [Bugs 710313, 710320, 710352] 2003-03-27 Donal K. Fellows * tests/parseOld.test: Altered test numers to eliminate duplicates. * tests/parse.test: [Bugs 710365, 710369] * tests/expr-old.test: * tests/expr.test: * tests/utf.test: Altered test numers to eliminate duplicates. * tests/trace.test: [Bugs 710322, 710327, 710349, 710363] * tests/lsearch.test: * tests/list.test: * tests/info.test: * tests/incr-old.test: * tests/if-old.test: * tests/format.test: * tests/foreach.test: 2003-03-26 Don Porter * doc/tcltest.n: * library/tcltest/tcltest.tcl: Added reporting during [configure -debug 1] operations to warn about multiple uses of the same test name. [FR 576693] Replaced [regexp] and [regsub] with [string map] where possible. Thanks to David Welton. [Bugs 667456,667558] * library/tcltest/pkgIndex.tcl: Bumped to tcltest 2.2.3 * tests/msgcat.test (msgcat-2.2.1): changed test name to avoid duplication. [Bug 710356] * unix/dltest/pkg?.c: Changed all Tcl_InitStubs calls to pass argument exact = 0, so that rebuilds are not required when Tcl bumps to a new version. [Bug 701926] 2003-03-24 Miguel Sofer * generic/tclVar.c: * tests/var.test: fixing ObjMakeUpvar's lookup algorithm for the created local variable, [Bugs 631741] (Chris Darroch) and [696893] (David Hilker). 2003-03-22 Kevin Kenny * library/dde/pkgIndex.tcl: * library/reg/pkgIndex.tcl: Fixed a bug where [package require dde] or [package require registry] attempted to load the release version of the DLL into a debug build. [Bug 708218] Thanks to Joe Mistachkin for the patch. * win/makefile.vc: Added quoting around the script name in the 'test' target; Joe Mistachkin insists that he has a configuration that fails to launch tcltest without it, and it appears harmless otherwise. 2003-03-20 Don Porter * generic/tclInt.h (tclOriginalNotifier): * generic/tclStubInit.c (tclOriginalNotifier): * mac/tclMacNotify.c (Tcl_SetTimer,Tcl_WaitForEvent): * unix/tclUnixNotfy.c (Tcl_SetTimer,Tcl_WaitForEvent, (Tcl_CreateFileHandler,Tcl_DeleteFileHandler): * win/tclWinNotify.c (Tcl_SetTimer,Tcl_WaitForEvent): Some linkers apparently use a different representation for a pointer to a function within the same compilation unit and a pointer to a function in a different compilation unit. This causes checks like those in the original notifier procedures to fall into infinite loops. The fix is to store pointers to the original notifier procedures in a struct defined in the same compilation unit as the stubs tables, and compare against those values. [Bug 707174] * generic/tclInt.h: Removed definition of ParseValue struct that is no longer used. 2003-03-19 Miguel Sofer * generic/tclCompile.c: * tests/compile.test: bad command count on TCL_OUT_LINE_COMPILE [Bug 705406] (Don Porter). 2003-03-19 Don Porter * doc/Eval.3 (Tcl_EvalObjEx): Corrected CONST and * doc/ParseCmd.3 (Tcl_EvalTokensStandard): return type errors in documentation. [Bug 683994] 2003-03-18 Kevin Kenny * tests/registry.test: Changed the conditionals to avoid an abort if [testlocale] is missing, as when running the test in tclsh rather than tcltest. [Bug 705677] 2003-03-18 Daniel Steffen * tools/tcltk-man2html.tcl: added support for building 'make html' from inside distribution directories named with 8.x.x version numbers. tcltk-man2html now uses the latest tcl8.x.x resp. tk8.x.x directories found inside its --srcdir argument. 2003-03-18 Vince Darley * tests/cmdAH.test: fix test suite problem if /home is a symlink * generic/tclIOUtil.c: fix bad error message with 'cd ""' * win/tclWinFile.c: allow Tcl to differentiate between reparse points which are symlinks and mounted drives. These changes fix [Bugs 703264, 704917, 697862] respectively. 2003-03-17 Donal K. Fellows * doc/lsearch.n: Altered documentation of -ascii options so * doc/lsort.n: they don't specify that they operate on ASCII strings, which they never did anyway. [Bug 703807] 2003-03-14 Donal K. Fellows * generic/tclCmdAH.c (Tcl_FileObjCmd): Remove assumption that file times and longs are the same size. [Bug 698146] (Tcl_FormatObjCmd): Stop surprising type conversions from happening when working with integer and wide values. [Bug 699060] * generic/tclCmdAH.c (Tcl_FormatObjCmd): Only add the modifier that indicates we've got a wide int when we're formatting in an integer style. Stops some libc's from going mad. [Bug 702622] Also tidied whitespace. 2003-03-13 Kevin Kenny * win/makefile.vc: Backed the version to 8.4 on the 8.4 branch. (I just loathe sticky tags). 2003-03-12 Don Porter * generic/tcl.h: Removed TCL_PREFIX_IDENT and TCL_DEBUG_IDENT * win/tclWinPipe.c: from tcl.h -- they are not part of Tcl's public interface. Put them in win/tclWinPipe.c where they are used. * generic/tclCmdMZ.c (Tcl_SubstObj): Corrected and added test for * tests/subst.test (subst-2.4): Tcl_SubstObj's incorrect halting of substitution at the first \x00 byte. [Bug 685106] * generic/tclInterp.c (Tcl_InterpObjCmd): Corrected and added * tests/interp.test (interp-2.13): test for option parsing beyond objc for [interp create --]. Thanks to Marco Maggi. [Bug 702383] 2003-03-11 Kevin Kenny * win/makefile.vc: Added two missing uses of $(DBGX) so that tclpip8x.dll loads without panicking on Win9x. 2003-03-08 Don Porter * doc/tcltest.n: Added missing "-body" to example. Thanks to Helmut Giese. [Bug 700011] 2003-03-06 Don Porter * generic/TclUtf.c (Tcl_UniCharNcasecmp): Corrected failure to * tests/utf.test (utf-25.*): properly compare Unicode strings of different case in a case insensitive manner. [Bug 699042] 2003-03-03 Jeff Hobbs *** 8.4.2 TAGGED FOR RELEASE *** 2003-03-03 Daniel Steffen Mac OS Classic specific fixes: * generic/tclIOUtil.c (TclNewFSPathObj): on TCL_PLATFORM_MAC, skip potential directory separator at the beginning of addStrRep. * mac/tclMacChan.c (OpenFileChannel, CommonWatch): followup fixes to cut and splice implementation for file channels. * mac/tclMacFile.c (TclpUtime): pass native path to utime(). * mac/tclMacFile.c (TclpObjLink): correctly implemented creation of alias files via new static proc CreateAliasFile(). * mac/tclMacPort.h: define S_ISLNK macro to fix stat'ing of links. * mac/tclMacUtil.c (FSpLocationFromPathAlias): fix to enable stat'ing of broken links. 2003-03-03 Kevin Kenny * win/Makefile.vc: corrected bug introduced by 'g' for debug builds. 2003-03-03 Don Porter * library/dde/pkgIndex.tcl: dde bumped to version 1.2.1 for * win/tclWinDde.c: bundled release with Tcl 8.4.2 * library/reg/pkgIndex.tcl: registry bumped to version 1.1.1 for * win/tclWinReg.c: bundled release with Tcl 8.4.2 * library/opt/pkgIndex.tcl: updated package index to version 0.4.4 2003-02-28 Jeff Hobbs * win/configure: * win/configure.in: check for 'g' for debug build type, not 'd'. * win/rules.vc (DBGX): correct to use 'g' for nmake win makefile to match the cygwin makefile for debug builds. [Bug 635107] 2003-02-28 Vince Darley * doc/file.n: subcommand is 'file volumes' not 'file volume' 2003-02-27 Jeff Hobbs * generic/tclIOUtil.c (MakeFsPathFromRelative): removed dead code check of typePtr (darley). * tests/winTime.test: added note about PCI hardware dependency issues with high performance clock. 2003-02-27 Donal K. Fellows * tests/lsearch.test (lsearch-10.7): * generic/tclCmdIL.c (Tcl_LsearchObjCmd): Stopped -start option from causing an option when used with an empty list. [Bug 694232] 2003-02-26 Chengye Mao * win/tclWinInit.c: fixed a bug in TclpSetVariables by initializing dwUserNameLen with the sizeof(szUserName) before calling GetUserName. Don't know if this bug has been recorded: it caused crash in starting Tcl or wish in Windows. 2003-02-26 Jeff Hobbs * generic/tclCmdMZ.c (TraceCommandProc): Fix mem leak when deleting a command that had trace on it. [Bug 693564] (sofer) 2003-02-25 Don Porter * doc/pkgMkIndex.n: Modified [pkg_mkIndex] to use -nocase matching * library/package.tcl: of -load patterns, to better accomodate common user errors due to confusion between [package names] names and [info loaded] names. 2003-02-25 Andreas Kupries * tests/pid.test: See below [Bug 678412]. * tests/io.test: Made more robust against spaces in paths [Bug 678400] 2003-02-25 Miguel Sofer * tests/execute.test: cleaning up testobj's at the end, to avoid leak warning by valgrind. 2003-02-22 Zoran Vasiljevic * generic/tclEvent.c (Tcl_FinalizeThread): Fix [Bug 571002] 2003-02-21 Donal K. Fellows * tests/binary.test (binary-44.[34]): * generic/tclBinary.c (ScanNumber): Fixed problem with unwanted sign-bit propagation when scanning wide ints. [Bug 690774] 2003-02-21 Daniel Steffen * mac/tclMacChan.c (TclpCutFileChannel, TclpSpliceFileChannel): Implemented missing cut and splice procs for file channels. 2003-02-21 Don Porter * library/package.tcl (tclPkgUnknown): Minor performance tweaks to reduce the number of [file] invocations. Meant to improve startup times, at least a little bit. [Patch 687906] 2003-02-20 Daniel Steffen * unix/tcl.m4: * unix/tclUnixPipe.c: (macosx) use vfork() instead of fork() to create new processes, as recommended by Apple (vfork can be up to 100 times faster thank fork on macosx). * unix/configure: regen. 2003-02-20 Jeff Hobbs * generic/tclEncoding.c (LoadTableEncoding): * library/encoding/cp932.enc: Correct jis round-trip encoding * library/encoding/euc-jp.enc: by adding 'R' type to .enc files. * library/encoding/iso2022-jp.enc: [Patch 689341] (koboyasi, taguchi) * library/encoding/jis0208.enc: * library/encoding/shiftjis.enc: * tests/encoding.test: * unix/tclUnixChan.c (Tcl_MakeTcpClientChannel): add MakeTcpClientChannelMode that takes actual mode flags to avoid hang on OS X (may be OS X bug, but patch works x-plat). [Bug 689835] (steffen) 2003-02-20 Donal K. Fellows * doc/regsub.n: Typo fix [Bug 688943] 2003-02-19 Jeff Hobbs * unix/tclUnixThrd.c (TclpReaddir): * unix/tclUnixPort.h: update to Bug 689100 patch to ensure that there is a defined value of MAXNAMLEN (aka NAME_MAX in POSIX) and that we have some buffer allocated. 2003-02-19 Daniel Steffen * generic/tclStringObj.c: restored Tcl_SetObjLength() side-effect of always invalidating unicode rep (if the obj has a string rep). Added hasUnicode flag to String struct, allows decoupling of validity of unicode rep from buffer size allocated to it (improves memory allocation efficiency). [Bugs 686782, 671138, 635200] * macosx/Tcl.pbproj/project.pbxproj: * macosx/Makefile: reworked embedded build to no longer require relinking but to use install_name_tool instead to change the install_names for embedded frameworks. [Bug 644510] * macosx/Tcl.pbproj/project.pbxproj: preserve mod dates when running 'make install' to build framework (avoids bogus rebuilds of dependent frameworks because tcl headers appear changed). * tests/ioCmd.test (iocmd-1.8): fix failure when system encoding is utf-8: use iso8859-1 encoding explicitly. 2003-02-18 Miguel Sofer * generic/tclCompile.c (TclCompileExprWords): remove unused variable "range" [Bug 664743] * generic/tclExecute.c (ExprSrandFunc): remove unused variable "result" [Bug 664743] * generic/tclStringObj.c (UpdateStringOfString): remove unused variable "length" [Bug 664751] * tests/execute.test (execute-7.30): fix for [Bug 664775] 2003-02-18 Andreas Kupries * unix/tcl.m4: [Bug 651811] Added definition of _XOPEN_SOURCE and linkage of 'xnet' library to HP 11 branch. This kills a lot of socket-related failures in the testsuite when Tcl was compiled in 64 bit mode (both PA-RISC 2.0W, and IA 64). * unix/configure: Regenerated. 2003-02-18 Jeff Hobbs * generic/tclIO.c (HaveVersion): correctly decl static * unix/tclUnixThrd.c (TclpReaddir): reduce size of name string in tsd to NAME_MAX instead of PATH_MAX. [Bug 689100] (waters) 2003-02-18 Mo DeJong * unix/configure: Regen. * unix/tcl.m4 (SC_ENABLE_THREADS): Make sure -lpthread gets passed on the link line when checking for the pthread_attr_setstacksize symbol. 2003-02-18 Vince Darley * generic/tclTest.c: cleanup of new 'simplefs' test code, and better documentation. 2003-02-17 Miguel Sofer * generic/tclBasic.c (TclRenameCommand): fixing error in previous commit. 2003-02-17 Jeff Hobbs * generic/tclExecute.c (TclExecuteByteCode INST_STR_MATCH): * generic/tclCmdMZ.c (Tcl_StringObjCmd STR_MATCH): * generic/tclUtf.c (TclUniCharMatch): * generic/tclInt.decls: add private TclUniCharMatch function that * generic/tclIntDecls.h: does string match on counted unicode * generic/tclStubInit.c: strings. Tcl_UniCharCaseMatch has the * tests/string.test: failing that it can't handle strings or * tests/stringComp.test: patterns with embedded NULLs. Added tests that actually try strings/pats with NULLs. TclUniCharMatch should be TIPed and made public in the next minor version rev. 2003-02-17 Miguel Sofer * generic/tclBasic.c (TclRenameCommand): 'oldFullName' object was not being freed on all function exits, causing a memory leak. [Bug 684756] 2003-02-17 Mo DeJong * generic/tclIO.c (Tcl_GetsObj): Minor change so that eol is only assigned at the top of the TCL_TRANSLATE_AUTO case block. The other cases assign eol so this does not change any functionality. 2003-02-17 Kevin Kenny * tests/notify.test: Removed Windows line terminators. [Bug 687913]. 2003-02-15 Miguel Sofer * generic/tclBasic.c (Tcl_EvalEx): * generic/tclCompExpr.c (CompileSubExpr): * generic/tclCompile.c (TclCompileScript): * generic/tclParse.c (Tcl_ParseCommand, ParseTokens): * generic/tclParseExpr.c (ParsePrimaryExpr): * tests/basic.test (47.1): * tests/main.test (3.4): * tests/misc.test (1.2): * tests/parse.test (6.18): * tests/parseExpr.test (15.35): * tests/subst.test (8.6): Don Porter's fix for bad parsing of nested scripts [Bug 681841]. 2003-02-15 Kevin Kenny * tests/notify.test (new-file): * generic/tclTest.c (TclTest_Init, EventtestObjCmd, EventtestProc, (EventTestDeleteProc): * generic/tclNotify.c (Tcl_DeleteEvents): Fixed Tcl_DeleteEvents not to get a pointer smash when deleting the last event in the queue. Added test code in 'tcltest' and a new file of test cases 'notify.test' to exercise this functionality; several of the new test cases fail for the original code and pass for the corrected code. [Bug 673714] * unix/tclUnixTest.c (TestfilehandlerCmd): Corrected a couple of typos in error messages. [Bug 596027] 2003-02-14 Jeff Hobbs * README: Bumped to version 8.4.2. * generic/tcl.h: * tools/tcl.wse.in: * unix/configure: * unix/configure.in: * unix/tcl.m4: * unix/tcl.spec: * win/README.binary: * win/configure: * win/configure.in: * macosx/Tcl.pbproj/project.pbxproj: * generic/tclStringObj.c (Tcl_GetCharLength): perf tweak * unix/tcl.m4: correct HP-UX ia64 --enable-64bit build flags 2003-02-14 Kevin Kenny * win/tclWinTime.c: Added code to test and compensate for forward leaps of the performance counter. See the MSDN Knowledge Base article Q274323 for the hardware problem that makes this necessary on certain machines. * tests/winTime.test: Revised winTime-2.1 - it had a tolerance of thousands of seconds, rather than milliseconds. (What's six orders of magnitude among friends? Both the above changes are triggered by a problem reported at http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/1536811 although the developers find it difficult to believe that it accounts for the observed behavior and suspect a fault in the RTC chip. 2003-02-13 Kevin Kenny * win/tclWinInit.c: Added conversion from the system encoding to tcl_platform(user), so that it works with non-ASCII7 user names. [Bug 685926] * doc/tclsh.1: Added language to describe the handling of the end-of-file character \u001a embedded in a script file. [Bug 685485] 2003-02-11 Vince Darley * tests/fileName.test: * unix/tclUnixFile.c: fix for [Bug 685445] when using 'glob -l' on broken symbolic links. Added two new tests for this bug. 2003-02-11 Kevin Kenny * tests/http.test: Corrected a problem where http-4.14 would fail when run in an environment with a proxy server. Replaced references to scriptics.com by tcl.tk. 2003-02-11 Jeff Hobbs * tests/lsearch.test: * generic/tclCmdIL.c (Tcl_LsearchObjCmd): protect against the case that lsearch -regepx list and pattern objects are equal. * tests/stringObj.test: * generic/tclStringObj.c (Tcl_GetCharLength): correct ascii char opt of 2002-11-11 to not stop early on \x00. [Bug 684699] * tests.parse.test: remove excess EOF whitespace * generic/tclParse.c (CommandComplete): more paranoid check to break on (p >= end) instead of just (p == end). 2003-02-11 Miguel Sofer * generic/tclParse.c (CommandComplete): * tests/parse.test: fix for [Bug 684744], by Don Porter. 2003-02-11 Jeff Hobbs * generic/tclIOUtil.c (Tcl_FSJoinPath, Tcl_FSGetNormalizedPath): (UpdateStringOfFsPath): revert the cwdLen == 0 check and instead follow a different code path in Tcl_FSJoinPath. (Tcl_FSConvertToPathType, Tcl_FSGetNormalizedPath): (Tcl_FSGetFileSystemForPath): Update string rep of path objects before freeing the internal object. (darley) * tests/fileSystem.test: added test 8.3 * generic/tclIOUtil.c (Tcl_FSGetNormalizedPath): (UpdateStringOfFsPath): handle the cwdLen == 0 case * unix/tclUnixFile.c (TclpMatchInDirectory): simplify the hidden file match check. 2003-02-10 Mo DeJong * win/configure: * win/configure.in: Generate error when attempting to build under Cygwin. The Cygwin port of Tcl/Tk does not build and people are filing bug reports under the mistaken impression that someone is actually maintaining the Cygwin port. A post to comp.lang.tcl asking someone to volunteer as an area maintainer has generated no results. Closing [Bugs 680840, 630199, 634772] and marking as "Won't fix". 2003-02-10 Donal K. Fellows * doc/append.n: Return value was not documented. [Bug 683188] 2003-02-10 Vince Darley * doc/FileSystem.3: * generic/tclIOUtil.c: * generic/tclInt.h: * tests/fileSystem.test: * unix/tclUnixFCmd.c: * unix/tclUnixFile.c: * win/tclWinFile.c: further filesystem optimization, applying [Patch 682500]. In particular, these code examples are faster now: foreach f $flist { if {[file exists $f]} {file stat $f arr;...}} foreach f [glob -dir $dir *] { # action and/or recursion on $f } cd $dir foreach f [glob *] { # action and/or recursion on $f } cd .. * generic/tclTest.c: Fix for [Bug 683181] where test suite left files in 'tmp'. 2003-02-08 Jeff Hobbs * library/safe.tcl: code cleanup of eval and string comp use. 2003-02-07 Vince Darley * win/tclWinFCmd.c: cleanup long lines * win/tclWinFile.c: sped up pure 'glob' by a factor of 2.5 ('foreach f [glob *] { file exists $f }' is still slow) * tests/fileSystem.text: * tests/fileName.test: added new tests to ensure correct behaviour in optimized filesystem code. 2003-02-07 Vince Darley * generic/tclTest.c: * tests/fileSystem.text: fixed test 7.2 to avoid a possible crash, and not change the pwd. * tests/http.text: added comment to test 4.15, that it may fail if you use a proxy server. 2003-02-06 Mo DeJong * generic/tclCompCmds.c (TclCompileIncrCmd): * tests/incr.test: Don't include the text "(increment expression)" in the errorInfo generated by the compiled version of the incr command since it does not match the message generated by the non-compiled version of incr. It is also not possible to match this error output under Jacl, which does not support a compiler. 2003-02-06 Mo DeJong * generic/tclExecute.c (TclExecuteByteCode): When an error is encountered reading the increment value during a compiled call to incr, add a "(reading increment)" error string to the errorInfo variable. This makes the errorInfo variable set by the compiled incr command match the value set by the non-compiled version. * tests/incr-old.test: Change errorInfo result for the compiled incr command case to match the modified implementation. * tests/incr.test: Add tests to make sure the compiled and non-compiled errorInfo messages are the same. 2003-02-06 Don Porter * library/tcltest/tcltest.tcl: Filename arguments to [outputChannel] and [errorChannel] (also -outfile and -errfile) were [open]ed but never [closed]. Also, [cleanupTests] could remove output or error files. [Bug 676978]. * library/tcltest/pkgIndex.tcl: Bumped to version 2.2.2. 2003-02-05 Mo DeJong * tests/interp.test: * tests/set-old.test: Run test cases that depend on hash order through lsort so that the tests also pass under Jacl. Does not change test results under Tcl. 2003-02-04 Vince Darley * generic/tclIOUtil.c: * generic/tclEvent.c: * generic/tclInt.h: * mac/tclMacFCmd.c: * unix/tclUnixFCmd.c: * win/tclWin32Dll.c: * win/tclWinFCmd.c: * win/tclWinInit.c: * win/tclWinInt.h: * tests/fileSystem.test: fix to finalization/unloading/encoding issues to make filesystem much less dependent on encodings for its cleanup, and therefore allow it to be finalized later in the exit process. This fixes fileSystem.test-7.1. Also fixed one more bug in setting of modification dates of files which have undergone cross-platform copies. [Patch 676271] * tests/basic.test: * tests/exec.test: * tests/fileName.test: * tests/io.test: fixed some test failures when tests are run from a directory containing spaces. * tests/fileSystem.test: * generic/tclTest.c: added regression test for the modification date setting of cross-platform file copies. 2003-02-03 Kevin Kenny * generic/tclBasic.c: Changed [trace add command] so that 'rename' callbacks get fully qualified names of the command. [Bug 651271]. ***POTENTIAL INCOMPATIBILITY*** * tests/trace.test: Modified the test cases for [trace add command] to expect fully qualified names on the 'rename' callbacks. Added a case for renaming a proc within a namespace. * doc/trace.n: Added language about use of fully qualified names in trace callbacks. 2003-02-01 Kevin Kenny * generic/tclCompCmds.c: Removed an unused variable that caused compiler warnings on SGI. [Bug 664379] * generic/tclLoad.c: Changed the code so that if Tcl_StaticPackage is called to report the same package as being loaded in two interps, it shows up in [info loaded {}] in both of them (previously, it didn't appear in the static package list in the second. * tests/load.test Added regression test for the above bug. [Bug 670042] * generic/tclClock.c: Fixed a bug that incorrectly allowed [clock clicks {}] and [clock clicks -] to be accepted as if they were [clock clicks -milliseconds]. * tests/clock.test: Added regression tests for the above bug. [Bug 675356] * tests/unixNotfy.test: Added cleanup of working files [Bug 675609] * doc/Tcl.n: Added headings to the eleven paragraphs, to improve formatting in the tools that attempt to extract tables of contents from the manual pages. [Bug 627455] * generic/tclClock.c: Expanded mutex protection around the setting of env(TZ) and the thread-unsafe call to tzset(). [Bug 656660] 2003-01-31 Don Porter * tests/tcltest.test: Cleaned up management of file/directory creation/deletion to improve "-debug 1" output. [Bug 675614] The utility [slave] command failed to properly [list]-quote a constructed [open] command, causing failure when the pathname contained whitespace. [Bug 678415] * tests/main.test: Stopped main.test from deleting existing file. Test suite should not delete files that already exist. [Bug 675660] 2003-01-28 Don Porter * tests/main.test: Constrain tests that do not work on Windows. [Bug 674387] 2003-01-28 Vince Darley * generic/tclIOUtil.c: fix to setting modification date in TclCrossFilesystemCopy. Also added 'panic' in Tcl_FSGetFileSystemForPath under illegal calling circumstances which lead to hard-to-track-down bugs. * generic/tclTest.c: added test suite code to allow exercising a vfs-crash-on-exit bug in Tcl's finalization caused by the encodings being cleaned up before unloading occurs. * tests/fileSystem.test: added new 'knownBug' test 7.1 to demonstrate the crash on exit. 2003-01-28 Mo DeJong * generic/tcl.h: Add TCL_PREFIX_IDENT and TCL_DEBUG_IDENT, used only by TclpCreateProcess. * unix/Makefile.in: Define TCL_DBGX. * win/Makefile.in: Define TCL_DBGX. * win/tclWinPipe.c (TclpCreateProcess): Check that the Tcl pipe dll actually exists in the Tcl bin directory and panic if it is not found. Incorporate TCL_DBGX into the Tcl pipe dll name. This fixes a really mysterious error that would show up when exec'ing a 16 bit application under Win95 or Win98 when Tcl was compiled with symbols. The error seemed to indicate that the executable could not be found, but it was actually the Tcl pipe dll that could not be found. 2003-01-26 Mo DeJong * win/README: Update msys+mingw URL to release 6. This version bundles gcc 3. 2003-01-26 Mo DeJong * win/configure: Regen. * win/configure.in: Add test that checks to see if the compiler can cast to a union type. * win/tclWinTime.c: Squelch compiler warning about union initializer by casting to union type when compiling with gcc. 2003-01-25 Mo DeJong * generic/tclIO.c (Tcl_CutChannel, Tcl_SpliceChannel): Invoke TclpCutFileChannel and TclpSpliceFileChannel. * generic/tclInt.h: Declare TclpCutFileChannel and TclpSpliceFileChannel. * unix/tclUnixChan.c (FileCloseProc, TclpOpenFileChannel, (Tcl_MakeFileChannel, TclpCutFileChannel, (TclpSpliceFileChannel): Implement thread load data cut and splice for file channels. This avoids an invalid memory ref when compiled with -DDEPRECATED. * win/tclWinChan.c (FileCloseProc, TclpCutFileChannel, (TclpSpliceFileChannel): Implement thread load data cut and splice for file channels. This avoids an invalid memory ref that was showing up in the thread extension. 2003-01-25 Mo DeJong * win/tclWin32Dll.c (TclpCheckStackSpace, squelch_warnings): * win/tclWinChan.c (Tcl_MakeFileChannel, squelch_warnings): * win/tclWinFCmd.c (DoRenameFile, DoCopyFile, squelch_warnings): Re-implement inline ASM SEH handlers for gcc. The esp and ebp registers are now saved on the stack instead of in global variables so that the code is thread safe. Add additional checks when TCL_MEM_DEBUG is defined to be sure the values were recovered from the stack properly. Remove squelch_warnings functions and add a dummy call in the handler methods to squelch compiler warnings. 2003-01-25 Mo DeJong * win/configure: * win/configure.in: Define HAVE_ALLOCA_GCC_INLINE when we detect that no alloca function is found in malloc.h and we are compiling with GCC. Remove HAVE_NO_ALLOC_DECL define. * win/tclWin32Dll.c (TclpCheckStackSpace): Don't define alloca as a cdecl function. Doing this caused a tricky runtime bug because the _alloca function expects the size argument to be passed in a register and not on the stack. To fix this problem, we use inline ASM when compiling with gcc to invoke _alloca with the size argument loaded into a register. 2003-01-24 Jeff Hobbs * win/tclWinDde.c (Dde_Init): clarified use of tsdPtr. (DdeServerProc): better refcount handling of returnPackagePtr. * generic/tclEvent.c (Tcl_Finalize): revert finalize change on 2002-12-04 to correct the issue with extensions that have TSD needing to finalize that before they are unloaded. This issue needs further clarification. * tests/unixFCmd.test: only do groups check on unix 2003-01-24 Vince Darley * generic/tclStringObj.c: proper fixes for Tcl_SetObjLength and Tcl_AttemptSetObjectLength dealing with string objects with both pure-unicode and normal internal representations. Previous fix didn't handle all cases correctly. * generic/tclIO.c: Add 'Tcl_GetString()' to ensure the object has a valid 'objPtr->bytes' field before manipulating it directly. This fixes [Bug 635200] and [Bug 671138], but may reduce performance of Unicode string handling in some cases. A further patch will be applied to address this, once the code is known to be correct. 2003-01-24 Mo DeJong * win/configure: Regen. * win/configure.in: Add test to see if alloca is undefined in malloc.h. * win/tclWin32Dll.c (TclpCheckStackSpace): Rework the SEH exception handler logic to avoid using the stack since alloca will modify the stack. This was causing a nasty bug that would set the exception handler to 0 because it tried to pop the previous exception handler off the top of the stack. 2003-01-23 Donal K. Fellows * doc/lset.n: Fixed fault in return values from lset in documentation examples [Bug 658463] and tidied up a bit at the same time. 2003-01-21 Joe English * doc/namespace.n (namespace inscope): Clarified documentation [Patch 670110] 2003-01-21 Mo DeJong * win/configure: Regen. * win/tcl.m4 (SC_CONFIG_CFLAGS): Set SHLIB_SUFFIX so that TCL_SHLIB_SUFFIX will be set to a useful value in the generated tclConfig.sh. Set SHLIB_LD_LIBS to "" or '${LIBS}' based on the --enable-shared flag. This matches the UNIX implementation. 2003-01-18 Jeff Hobbs * generic/tclCkalloc.c: change %ud to %u as appropriate. 2003-01-17 Mo DeJong * win/tclWinDde.c (DdeServerProc): Deallocate the Tcl_Obj returned by ExecuteRemoteObject if it was not saved in a connection object. 2003-01-17 Mo DeJong * generic/tcl.h: Revert earlier change that defined TCL_WIDE_INT_TYPE as long long and TCL_LL_MODIFIER as L when compiling with mingw. This change ended up causing some test case failures when compiling with mingw. * generic/tclObj.c (UpdateStringOfWideInt): Describe the warning generated by mingw and why it needs to be ignored so that someone is not tempted to "fix" this problem again in the future. 2003-01-16 Vince Darley * generic/tclStringObj.c: Tcl_SetObjLength fix for when the object has a unicode string rep. Fixes [Bug 635200] * tests/stringObj.test: removed 'knownBug' constraint from test 14.1 now that this bug is fixed. * generic/tclInt.h: * generic/tclBasic.c: * generic/tclCmdMZ.z: * tests/trace.test: execution and command tracing bug fixes and cleanup. In particular fixed [Bugs 655645, 615043, 571385] - fixed some subtle cleanup problems with tracing. This required replacing Tcl_Preserve/Tcl_Release with a more robust refCount approach. Solves at least one known crash caused by memory corruption. - fixed some confusion in the code between new style traces (Tcl 8.4) and the very limited 'Tcl_CreateTrace' which existed before. - made behaviour consistent with documentation (several tests even contradicted the documentation before). - fixed some minor error message details - added a number of new tests 2003-01-16 Jeff Hobbs * win/tclWinSerial.c (SerialOutputProc): add casts for bytesWritten to allow strict compilation (no warnings). * tests/winDde.test: * win/tclWinDde.c (Tcl_DdeObjCmd): Prevent crash when empty service name is passed to 'dde eval' and goto errorNoResult in request and poke error cases to free up any allocated data. 2003-01-16 Mo DeJong * win/tclWin32Dll.c (squelch_warnings): Squelch compiler warnings from SEH ASM code. * win/tclWinChan.c (squelch_warnings): Squelch compiler warnings from SEH ASM code. * win/tclWinDde.c: Add casts to avoid compiler warnings. Pass pointer to DWORD instead of int to avoid compiler warnings. * win/tclWinFCmd.c (squelch_warnings): Add casts and fixup decls to avoid compiler warnings. Squelch compiler warnings from SEH ASM code. * win/tclWinFile.c: Add casts and fixup decls to avoid compiler warnings. Remove unused variable. * win/tclWinNotify.c: Declare as DWORD instead of int to avoid compiler warning. * win/tclWinReg.c: Add casts to avoid compiler warning. Fix assignment in if expression bug. * win/tclWinSerial.c: Add casts to avoid compiler warnings. Remove unused variable. * win/tclWinSock.c: Add casts and fixup decls to avoid compiler warnings. 2003-01-14 Jeff Hobbs * generic/tclClock.c (FormatClock): corrected typo that incorrectly conditionally defined savedTZEnv and savedTimeZone. 2003-01-13 Mo DeJong Fix mingw build problems and compiler warnings. * generic/tcl.h: Add if defined(__MINGW32__) check to code that sets the TCL_WIDE_INT_TYPE and TCL_LL_MODIFIER. * generic/tclClock.c (FormatClock): Don't define savedTimeZone and savedTZEnv if we are not going to use them. * generic/tclEnv.c: Add cast to avoid warning. * win/tclWinChan.c: Use DWORD instead of int to avoid compiler warning * win/tclWinThrd.c: Only define allocLock, allocLockPtr, and dataKey when TCL_THREADS is defined. This avoid a compiler warning about unused variables. 2003-01-12 Mo DeJong * win/README: Update msys + mingw URL, the new release includes the released 1.0.8 version of msys which includes a number of bug fixes. 2003-01-12 Mo DeJong * win/configure: Regen. * win/tcl.m4 (SC_CONFIG_CFLAGS): Pull in addition of shell32.lib to LIBS_GUI that was added to the Tk tcl.m4 but never made it back into the Tcl version. 2003-01-12 Mo DeJong * generic/tcl.h: Skip Tcl's define of CHAR, SHORT, and LONG when HAVE_WINNT_IGNORE_VOID is defined. This avoids a bunch of compiler warnings when building with Cygwin or Mingw. * win/configure: Regen. * win/configure.in: Define HAVE_WINNT_IGNORE_VOID when we detect a winnt.h that still defines CHAR, SHORT, and LONG when VOID has already been defined. * win/tcl.m4 (SC_LOAD_TCLCONFIG): Subst the TCL_DEFS loaded from tclConfig.sh so that Tcl defines can make it into the Tk Makefile. 2003-01-12 Mo DeJong * win/configure: Regen. * win/configure.in: Check for typedefs like LPFN_ACCEPT in winsock2.h and define HAVE_NO_LPFN_DECLS if not found. * win/tclWinSock.c: Define LPFN_* typedefs if HAVE_NO_LPFN_DECLS is defined. This fixes the build under Mingw and Cygwin, it was broken by the changes made on 2002-11-26. 2003-01-10 Vince Darley * generic/tclIOUtil.c: * win/tclWinInt.h: * win/tclWinInit.c: fix to new WinTcl crash on exit with vfs, introduced on 2002-12-06. Encodings must be cleaned up after the filesystem. * win/makefile.vc: fix to minor VC++ 5.2 syntax problem 2003-01-09 Don Porter * generic/tclCompCmds.c (TclCompilerReturnCmd): Corrected off-by-one problem with recent commit. [Bug 633204] 2003-01-09 Vince Darley * generic/tclFileName.c: remove unused variable 'macSpecialCase' [Bug 664749] * generic/tclIOUtil.c: * generic/tclInt.h: * unix/tclUnixFile.c: * mac/tclMacFile.c: * win/tclWinFile.c: * win/tclWinInt.h: * win/tclWin32Dll.c: * tests/cmdAH.test: fix to non-ascii chars in paths when setting mtime and atime through 'file (a|m)time $path $time'. [Bug 634151] 2003-01-08 Don Porter * generic/tclExecute.c (TclExprFloatError): Use the IS_NAN macro for greater clarity of code. 2003-01-07 Don Porter * generic/tclCompCmds.c (TclCompileReturnCmd): * tests/compile.test: Corrects failure of bytecompiled [catch {return}] to have result TCL_RETURN (not TCL_OK) [Bug 633204]. This patch is a workaround for 8.4.X. A new opcode INST_RETURN is a better long term solution for 8.5 and later. 2003-01-04 David Gravereaux * win/makefile.vc: * win/rules.vc: Fixed INSTALLDIR macro problem that blanked itself by accident causing the install target to put the tree at the root of the drive built on. Whoops.. Renamed the 'linkexten' option to be 'staticpkg'. Added 'thrdalloc' to allow the switching _on_ of the thread allocator. Under testing, I found it not to be benificial under windows for the purpose of the application I was using it for. It was more important for this app that resources for tcl threads be returned to the system rather than saved/moved to the global recycler. Be extra clean or extra fast for the default threaded build? Let's move to clean and allow it to be switched on for users who find it benificial for their use of threads. 2002-12-18 David Gravereaux * win/makefile.vc: some uses of xcopy swapped to the @$(CPY) macro. Reported by Joe Mistachkin . 2002-12-17 Jeff Hobbs * generic/tclNotify.c (TclFinalizeNotifier, Tcl_SetServiceMode): (Tcl_ThreadAlert): Check that the stub functions are non-NULL before calling them. They could be set to NULL by Tcl_SetNotifier. 2002-12-16 David Gravereaux * generic/tclPipe.c (TclCleanupChildren): * tests/winPipe.test: * win/tclWinPipe.c (Tcl_WaitPid): * win/tclWinTest.c: Gave Tcl_WaitPid the ability to return a Win32 exception code translated into a posix style SIG*. This allows [close] to report "CHILDKILLED" without the meaning getting lost in a truncated exit code. In TclCleanupChildren(), TclpGetPid() had to get moved to before Tcl_WaitPid() as the the handle is removed from the list taking away the ability to get the process id after the wait is done. This shouldn't effect the unix implimentaion unless waitpid is called with a pid of zero, meaning "any". I don't think it is.. 2002-12-13 Don Porter * unix/configure.in: Updated configure of CVS snapshots to reflect * win/configure.in: the 8.4.1.1 patchlevel. * unix/configure: autoconf * win/configure autoconf 2002-12-11 Don Porter * generic/tclProc.c (ProcessProcResultCode): Fix failure to propagate negative return codes up the call stack. [Bug 647307] * tests/proc.test (proc-6.1): Test for Bug 647307 * generic/tclParseExpr.c (TclParseInteger): Return 1 for the string "0x" (recognize leading "0" as an integer). [Bug 648441]. * tests/parseExpr.test (parseExpr-19.1): Test for Bug 648441. 2002-12-09 Jeff Hobbs * win/tclWinThrd.c (TclpMasterUnlock): * generic/tclThread.c (TclFinalizeThreadData): TclpMasterUnlock must exist and be called unconditional of TCL_THREADS. [Bug 651139] 2002-12-08 David Gravereaux * win/tclWinSock.c (SocketThreadExitHandler, InitSockets): Check that the tsdPtr is valid before dereferencing as we call it from the exit handler, too [Bug 650353]. Another WSAStartup() loaded version comparison byte swap issue fixed. Although 0x0101 byte swapped is still 0x0101, properly claiming which is major/minor is more correct. 2002-12-06 Jeff Hobbs * generic/tclStubInit.c: regen * generic/tclIntPlatDecls.h: regen * generic/tclInt.decls: added TclWinResetInterface * win/tclWin32Dll.c (TclWinResetInterfaces): * win/tclWinInit.c (TclpSetInitialEncodings, WinEncodingsCleanup): add exit handler that resets the encoding information to a state where we can reuse Tcl. Following these changes, it is possible to reuse Tcl (following Tcl_FindExecutable or Tcl_CreateInterp) following a Tcl_Finalize. * generic/tclIOUtil.c (TclFinalizeFilesystem): reset statics to their original values on finalize to allow reuse of the library. 2002-12-04 David Gravereaux * win/tclWinPipe.c: reverted back to -r1.27 due to numerous test failures that need to be resolved first. The idea was good, but the details aren't. 2002-12-04 David Gravereaux * win/tclWinPipe.c (Tcl_WaitPid): When a process exits with an exception, pass this notice on to the caller with a SIG* code rather than truncating the exit code and missing the meaning. This allows TclCleanupChildren() to report "CHILDKILLED". This has a different behavior than unix in that closing the read pipe to a process sends the SIGPIPE signal which is returned as a SIGPIPE exit status. On windows, we send the process a CTRL_BREAK_EVENT and get back a CONTROL_C_EXIT which is documented to mean a SIGINT which seems wrong as a system, but is the correct exit status. 2002-12-04 Vince Darley * generic/tclIOUtil.c: fix to redirected 'load' in virtual filesystem for some Unix systems. * generic/tclEvent.c: the filesystem must be cleaned up before the encoding subsystem because it needs access to encodings. Fixes crash on exit observed in embedded applications. * generic/tclTestObj.c: patch omitted from previous change of 2002-11-13 2002-12-03 Jeff Hobbs * generic/tclStubLib.c (Tcl_InitStubs): prevent the cached check of tclStubsPtr to allow for repeated load/unload of the Tcl dll by hosting apps. [Bug 615304] 2002-12-03 David Gravereaux * win/tclAppInit.c (sigHandler): Protect from trying to close a NULL handle. * win/tclWinPipe.c (PipeClose2Proc, TclpCreateProcess): Send a real Win32 signal (CTRL_C_EVENT) when the read channel is brought down to alert the child to close on its side. Start the process with CREATE_NEW_PROCESS_GROUP to allow the ability to send these signals. The following test case now brings down the child without the use of an external [kill] command. % set p [open "|[info name]" w+] file8d5380 % pid $p 2876 % close $p <- now doesn't block in Tcl_WaitPid() % * win/tclWinPipe.c (PipeClose2Proc): Changed CTRL_C_EVENT to CTRL_BREAK_EVENT as it can't be ignored by the child and proved to work on [open "|netstat 1" w+] where CTRL_C_EVENT didn't. 2002-11-27 David Gravereaux * win/tclWinPort.h: Don't turn off winsock prototypes! TclX didn't like it. Even though the core doesn't use the prototypes, do offer them. * win/tclWinSock.c: Removed shutdown() from the function table as it wasn't referenced anywhere and cleaned-up some casting that that wasn't needed. * win/tclWinSock.c: WSAStartup() loaded version comparison error which resulted in 2.0 looking less than 1.1. * win/tclWinChan.c (Tcl_MakeFileChannel): return of DuplicateHandle() incorrectly used [Bug 618852]. 2002-11-26 Jeff Hobbs * generic/tclEncoding.c (TclFinalizeEncodingSubsystem): properly cleanup all encodings by using Tcl_FirstHashEntry in the while loop. * unix/Makefile.in (valgrind): add simple valgrind target * tests/exec.test: unset path var to allow singleproc testing * generic/tclInterp.c (AliasCreate): preserve/release interps to prevent possible FMR error in bad alias cases. 2002-11-26 David Gravereaux * win/tclWinPort.h: * win/tclWinSock.c: This patch does two things: 1) Cleans-up the winsock typedefs by using the typedefs provided by winsock2.h. This has no effect on how winsock is initialized; just makes the source code easier to read. [Patch 561305, 561301] 2) Revamps how the socket message handler thread is brought up and down to allow for cleaner exits without the use of TerminateThread(). TerminateThread is evil. No attempt has been made to resolve [Bug 593810] which may need a new channel driver version for adding a registering function within the transfered thread to init the handler thread. IOW, initialization of the TSD structure is getting bypassed through the thread extension's [thread::transfer] command. 2002-11-26 David Gravereaux * win/tclWinConsole.c: * win/tclWinPipe.c: * win/tclWinSerial.c: * win/tclWinSock.c: * win/tclWinThrd.c: * win/tclWinTime.c: General cleanup of all worker threads used by the channel drivers. Eliminates the normal case where the worker thread is terminated ('cept the winsock one). Instead, use kernel events to signal a clean exit. Only when the worker thread is blocked on an I/O call is the thread terminated. Essentially, this makes all other channel worker threads behave like the PipeReaderThread() function for it's cleaner exit behavior. This appears to fix [Bug 597924] but needs 3rd party confirmation to close the issue. 2002-11-26 Mo DeJong * win/README: Update msys build env URL. This release #4 build both tcl and tk without problems. 2002-11-22 Jeff Hobbs * library/init.tcl: code cleanup to reduce use of * library/opt/optparse.tcl: string compare * tests/interp.test: interp-14.4 * generic/tclInterp.c (TclPreventAliasLoop): prevent seg fault when creating an alias command over the interp name. [Bug 641195] 2002-11-18 Jeff Hobbs * generic/tclUtil.c (SetEndOffsetFromAny): handle integer offset after the "end-" prefix. * generic/get.test: * generic/string.test: * generic/tclObj.c (SetIntFromAny, SetWideIntFromAny): * generic/tclGet.c (TclGetLong, Tcl_GetInt): simplify sign handling before calling strtoul(l). [Bug 634856] 2002-11-18 David Gravereaux * win/tclWinThrd.c (Tcl_CreateThread/TclpThreadExit): Fixed improper compiler macros that missed the VC++ compiler. This resulted in VC++ builds using CreateThread()/ExitThread() in place of the proper _beginthreadex()/_endthreadex(). This was a large error and am surprised I missed seeing it earlier. 2002-11-13 Jeff Hobbs * generic/regexpComp.test: added tests 22.* * generic/tclCompCmds.c (TclCompileRegexpCmd): add left and right anchoring (^ and $) recognition and check starting or ending .* to extend the number of REs that can be compiled to string match or string equal. 2002-11-13 Vince Darley * generic/tclCmdMZ.c: * tests/trace.test: applied patch from Hemang Levana to fix [Bug 615043] in execution traces with 'return -code error'. * generic/tclTestObj.c: * tests/stringObj.test: added 'knownBug' test for [Bug 635200] * generic/tclStringObj.c: corrected typos in comments * generic/tclFileName.c: * tests/fileName.test: applied patch for bug reported against tclvfs concerning handling of Windows serial ports like 'com1', 'lpt3' by the virtual filesystem code. * doc/RegExp.3: clarification of the 'extendMatch' return values. 2002-11-11 Jeff Hobbs * generic/tclUtil.c (Tcl_Backslash): use TclUtfToUniChar. (Tcl_StringCaseMatch): use TclUtfToUniChar and add further optimizations for the one-byte/char case. * generic/tclUtf.c: make use of TclUtfToUniChar macro throughout the functions, and add extra optimization to Tcl_NumUtfChars for one-byte/char case. * generic/tclVar.c (DisposeTraceResult, CallVarTraces): add proper static declarations. * generic/tclStringObj.c (Tcl_GetCharLength): optimize for the ascii char case. (Tcl_GetUniChar): remove unnecessary use of Tcl_UtfToUniChar. (FillUnicodeRep): Use TclUtfToUniChar. * generic/tclHash.c (HashStringKey): move string++ lower to save an instruction. * generic/tclExecute.c (TclExecuteByteCode): improve INST_STR_CMP to use memcmp in the one-byte/char case, also use direct index for INST_STR_INDEX in that case. * generic/tclEncoding.c (UtfToUtfProc, UtfToUnicodeProc): (TableFromUtfProc, EscapeFromUtfProc): Use TclUtfToUniChar. (UnicodeToUtfProc, TableToUtfProc): add 1-byte char optimizations for Tcl_UniCharToUtf call. These improve encoded channel conversion speeds by up to 20%. * tests/split.test: added 1-char string split tests * generic/tclCmdMZ.c (Tcl_SplitObjCmd): Use TclUtfToUniChar. Also added a special case for single-ascii-char splits. (Tcl_StringObjCmd): Use TclUtfToUniChar. For STR_RANGE, support getting ranges of ByteArrays (reverts change from 2000-05-26). (TraceExecutionProc) add proper static declaration. * generic/tclInt.h: add macro version of Tcl_UtfToUniChar (TclUtfToUniChar) that does the one-byte utf-char check without calling Tcl_UtfToUniChar, for use by the core. This brings notable speedups for primarily ascii string handling. * generic/tcl.h (TCL_PATCH_LEVEL): bump to 8.4.1.1 for patchlevel only. This interim number will only be reflected by [info patchlevel] 2002-11-11 Kevin Kenny * doc/Tcl.n: Corrected indentation of the new language. Oops. 2002-11-10 Kevin Kenny * doc/Tcl.n: Added language to the Endekalogue to make it clear that substitutions always take place from left to right. [Bug 635644] 2002-11-06 Mo DeJong * changes: Note TclInExit TclInThreadExit changes. * generic/tclEvent.c (TclInExit, TclInThreadExit): Split out functionality of TclInExit to make it clear which one should be called in each situation. * generic/tclInt.decls: Declare TclInThreadExit. * generic/tclIntDecls.h: Regen. * generic/tclStubInit.c: Regen. * mac/tclMacChan.c (StdIOClose): * unix/tclUnixChan.c (FileCloseProc): * win/tclWinChan.c (FileCloseProc): * win/tclWinConsole.c (ConsoleCloseProc): * win/tclWinPipe.c (TclpCloseFile): * win/tclWinSerial.c (SerialCloseProc): Invoke the new TclInThreadExit method instead of TclInExit. 2002-11-06 Mo DeJong * unix/configure: Regen. * unix/tcl.m4 (SC_CONFIG_CFLAGS): Generate a fatal configure error if no ar program can be found on the path. [Bug 582039] * win/configure: Regen. * win/configure.in: Check that AR, RANLIB, and RC are found on the path when building with gcc. 2002-11-03 David Gravereaux * win/tclAppInit.c: Calls Registry_Init() and Dde_Init() when STATIC_BUILD and TCL_USE_STATIC_PACKAGES macros are set. * win/makefile.vc: * win/rules.vc: linkexten option now sets the TCL_USE_STATIC_PACKAGES macro which also adds the registry and dde object files to the link of the shell. [Patch 479697] Also factored some additional macros that will be helpful for extension authors. Version grepping of tcl.h will need to be added to complete this. * win/buildall.vc.bat: Added more descriptive commentary. 2002-11-01 David Gravereaux * win/tclWinReg.c: Changed the Tcl_PkgProvide() line to declare the registry extension at version 1.1 from 1.0. 2002-10-31 Andreas Kupries * library/word.tcl: Changed $tcl_platform to $::tcl_platform to avoid possible scope trouble. 2002-10-29 Vince Darley * win/tclWinInt.h: * win/tclWin32Dll.c: added comments about certain NULL function pointers which will be filled in when Tcl_FindExecutable is called, so that users don't report invalid bugs on this topic. (No code changes at all). 2002-10-29 Daniel Steffen * unix/tclLoadDyld.c (TclpFindSymbol): pass all dyld error messages upstream [Bug 627546]. 2002-10-28 Andreas Kupries * library/dde/pkgIndex.tcl: * library/reg/pkgIndex.tcl: Changed the hardwired debug suffix (d) to the correct suffix (g). 2002-10-28 Don Porter * library/auto.tcl: Converted the Mac-specific [package unknown] * library/init.tcl: behavior to use a chaining mechanism to extend * library/package.tcl: the default [tclPkgUnknown]. [Bug 627660] * library/tclIndex: [Patch 624509] (steffen) 2002-10-26 David Gravereaux * win/makefile.vc: xcopy on NT 4.0 doesn't support the /Y switch (overwrite). Added logic to handle this. [Bug 618019] 2002-10-23 Donal K. Fellows * generic/tclInt.h: Removed definitions of obsolete HistoryEvent and HistoryRev structures (the history mechanism has been written in Tcl for some time now). 2002-10-22 Jeff Hobbs *** 8.4.1 TAGGED FOR RELEASE *** * changes: updated for 8.4.1 release * win/Makefile.in: removed @MEM_DEBUG_FLAGS@ subst. * win/configure: regen * win/configure.in: removed SC_ENABLE_MEMDEBUG call * win/tcl.m4: replaced SC_ENABLE_MEMDEBUG with a more intelligent SC_ENABLE_SYMBOLS that takes yes|no|mem|compile|all as options now. 2002-10-22 Daniel Steffen * library/auto.tcl (tcl_findLibrary): * library/package.tcl (tclPkgUnknown): on macosx, search inside the Resources/Scripts subdirectory of any potential package directory * macosx/Tcl.pbproj/project.pbxproj: add standard Frameworks dirs to TCL_PACKAGE_PATH make argument. * unix/tclUnixInit.c (TclpSetVariables): on macosx, add embedded framework dirs to tcl_pkgPath: @executable_path/../Frameworks and @executable_path/../PrivateFrameworks (if they exist), as well as the dirs in DYLD_FRAMEWORK_PATH (if set). [Patch 624509] use standard MAXPATHLEN instead of literal 1024 2002-10-22 Donal K. Fellows * doc/StringObj.3, doc/Object.3: Documented that Tcl_Obj's standard string form is a modified UTF-8; apparently, this was not mentioned anywhere in the main docs, and lead to [Bug 624919]. 2002-10-21 Daniel Steffen * macosx/Tcl.pbproj/project.pbxproj: bumped version to 8.4.1 * generic/tcl.h: Added reminder comment to edit macosx/Tcl.pbproj/project.pbxproj when version number changes. 2002-10-18 Jeff Hobbs * library/reg/pkgIndex.tcl: * win/configure: * win/configure.in: * win/Makefile.in: * win/makefile.vc: * win/makefile.bc: Updated to reg1.1 * doc/registry.n: Added support for broadcasting changes to the * tests/registry.test: registry Environment. Noted proper code in ths * win/tclWinReg.c: docs. [Patch 625453] * unix/Makefile.in (dist): add any mac/tcl*.sea.hqx files 2002-10-17 Don Porter * generic/tclVar.c: Fixed code that check for proper # of args to * tests/var.test: [array names]. Added test. [Bug 624755] 2002-10-16 Jeff Hobbs * win/configure: add workaround for cygwin windres * win/tcl.m4 (SC_CONFIG_CFLAGS): problem. [Patch 624010] (howell) 2002-10-15 Jeff Hobbs * README: added archives.tcl.tk note * unix/configure: * unix/tcl.m4: Correct AIX-5 ppc build flags. Correct HP 11 64-bit gcc building. [Patch 601051] (martin) 2002-10-15 Vince Darley * generic/tclCmdMZ.c: * tests/trace.test: applied patch from Hemang Levana to fix [Bug 615043] in execution traces with idle tasks firing. 2002-10-14 Jeff Hobbs * generic/tclEnv.c (Tcl_PutEnv): correct possible mem leak. [Patch 623269] (brouwers) 2002-10-11 Donal K. Fellows * generic/tcl.h: Need a different strategy through the maze of #defines to let people building with Cygwin build correctly. Also made some comments less misleading... 2002-10-10 Jeff Hobbs * README: fixed minor nits [Bug 607776] (virden) * win/configure: * win/tcl.m4: enable USE_THREAD_ALLOC (new threaded allocator) by default in cygwin configure on Windows. 2002-10-10 Don Porter * doc/Tcl.n: Clarified that namespace separators are legal in the variable names during $-subtitution. [Bug 615139] * doc/regexp.n: Typo correction. Thanks Ronnie Brunner. [Bug 606826] 2002-10-10 Vince Darley * unix/tclLoadAout.c * unix/tclLoadDl.c * unix/tclLoadDld.c * unix/tclLoadDyld.c * unix/tclLoadNext.c * unix/tclLoadOSF.c * unix/tclLoadShl.c * win/tclWinLoad.c: allow either full paths or simply dll names to be specified when loading files (the latter will be looked up by the OS on your PATH/LD_LIBRARY_PATH as appropriate). Fixes [Bug 611108] 2002-10-09 Jeff Hobbs * unix/README: doc'ed --enable-symbols options. * unix/Makefile.in: removed @MEM_DEBUG_FLAGS@ subst. * unix/configure: regen * unix/configure.in: removed SC_ENABLE_MEMDEBUG call * unix/tcl.m4: replaced SC_ENABLE_MEMDEBUG with a more intelligent SC_ENABLE_SYMBOLS that takes yes|no|mem|compile|all as options now. 2002-10-09 Kevin B. Kenny * win/tclWinTime.c: Added code to set an exit handler that terminates the thread that calibrates the performance counter, so that the thread won't outlive unloading the Tcl DLL. [Bug 620735]. 2002-10-09 Donal K. Fellows * doc/binary.n: More clarification of [binary scan]'s behaviour. 2002-10-09 Daniel Steffen * generic/tclIntDecls.h: fixed botched regen. 2002-10-09 Daniel Steffen * generic/tclInt.decls: made TclSetPreInitScript() declaration generic as it is used on mac & aqua as well. * generic/tclIntDecls.h: * generic/tclStubInit.c: regen. * generic/tclCompile.h: added prototype for TclCompileVariableCmd. * mac/tclMacPort.h: removed incorrect definitions and obsolete definitions. * mac/tclMacChan.c: removed obsolete GetOpenMode() and replaced associated constants with the analogues (they existing defs were inconsistent with which was causing havoc when Tcl_GetOpenMode was used instead of private GetOpenMode). * mac/tclMacFCmd.c: removed GenerateUniqueName(), use equivalent (and identically named) routine from MoreFiles instead. * mac/tclMacLoad.c: CONSTification, fixes to Vince's last changes. * mac/tclMacFile.c: * mac/tclMacTest.c: * mac/tclMacUnix.c: CONSTification. * mac/tclMacOSA.c: CONSTification, sprintf fixes, UH 3.4.x changes; fix for missing autoname token from TclOSACompileCmd. (bdesgraupes) * mac/AppleScript.html(AppleScript delete): doc fix. (bdesgraupes) * mac/tcltkMacBuildSupport.sea.hqx: updated MoreFiles to 1.5.3, updated build instructions for 8.4. * mac/tclMacProjects.sea.hqx: rebuilt archive. 2002-10-09 Donal K. Fellows * doc/Alloc.3: Added a note to mention that attempting to allocate a zero-length block can return NULL. [Tk Bug 619544] 2002-10-04 Donal K. Fellows * doc/binary.n: Doc improvements [Patch 616480] * tests/fCmd.test, tests/winFCmd.test: * tools/eolFix.tcl, tools/genStubs.tcl: [file exist] -> [file exists] Thanks to David Welton. 2002-10-03 Don Porter * doc/tcltest.n: fixed typo [Bug 618018]. Thanks to "JJM". 2002-10-03 Donal K. Fellows * tools/man2help2.tcl: * tests/http.test, tests/httpd, tests/httpold.test: * tests/env.test, tests/binary.test, tests/autoMkindex.test: * library/init.tcl, library/http/http.tcl: [info exist] should really be [info exists]. [Bug 602566] * doc/lsearch.n: Better specification of what happens when -sorted is mixed with other options. [Bug 617816] 2002-10-01 Jeff Hobbs * generic/tclProc.c (TclCreateProc): mask out VAR_UNDEFINED for precompiled locals to support 8.3 precompiled code. (Tcl_ProcObjCmd): correct 2002-09-26 fix to look for tclProcBodyType. 2002-10-01 Donal K. Fellows * doc/socket.n: Mentioned that ports may be specified as serivce names as well as integers. [Bug 616843] 2002-09-30 Jeff Hobbs * generic/tclCompCmds.c (TclCompileRegexpCmd): correct the checking for bad re's that didn't terminate the re string. Resultant compiles were correct, but much slower than necessary. 2002-09-29 David Gravereaux * win/tclAppInit.c: Added proper exiting conditions using Win32 console signals. This handles the existing lack of a Ctrl+C exit to call exit handlers when built for thread support. Also, properly handles exits from other conditions such as CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT, and CTRL_SHUTDOWN_EVENT signals. In all cases, exit handlers will be called. [Bug 219355] * win/makefile.vc: Added missing tclThreadAlloc.c to the build rules and defines USE_THREAD_ALLOC when TCL_THREADS is defined to get the new behavior by default. 2002-09-27 Don Porter * README: Bumped to version 8.4.1 to avoid confusion * generic/tcl.h: of CVS snapshots with the actual 8.4.0 * tools/tcl.wse.in: release. * unix/configure.in: * unix/tcl.spec: * win/configure.in: * unix/configure: autoconf * win/configure: 2002-09-26 Jeff Hobbs * unix/configure: regen. * unix/tcl.m4: improve AIX-4/5 64bit compilation support. * generic/tclProc.c (Tcl_ProcObjCmd): correct overeager optimization of noop proc to handle the precompiled case. (sofer) * unix/ldAix (nmopts): add -X32_64 to make it work for 32 or 64bit mode compilation. * library/encoding/koi8-u.enc: removed extraneous spaces that confused encoding reader. [Bug 615115] * unix/Makefile.in: generate source dists with -src designator and do not generate .Z anymore (just .gz and .zip). 2002-09-18 Mumit Khan Added basic Cygwin support. * win/tcl.m4 (SC_PATH_TCLCONFIG): Support one-tree build. (SC_PATH_TKCONFIG): Likewise. (SC_PROG_TCLSH): Likewise. (SC_CONFIG_CFLAGS): Assume real Cygwin port and remove -mno-cygwin flags. Add -mwin32 to extra_cflags and extra_ldflags. Remove ``-e _WinMain@16'' from LDFLAGS_WINDOW. * win/configure.in: Allow Cygwin build. (SEH test): Define to be 1 instead of empty value. (EXCEPTION_DISPOSITION): Add test. * win/configure: Regenerate. * generic/tcl.h: Don't explicitly define __WIN32__ for Cygwin, let the user decide whether to use Windows or POSIX personality. (TCL_WIDE_INT_TYPE, TCL_LL_MODIFIER, struct Tcl_StatBuf): Define for Cygwin. * generic/tclEnv.c (Tcl_CygwinPutenv): putenv replacement for Cygwin. * generic/tclFileName.c (Tcl_TranslateFileName): Convert POSIX to native format. (TclDoGlob): Likewise. * generic/tclPlatDecls.h (TCHAR): Define for Cygwin. * win/tclWinPort.h (putenv, TclpSysAlloc, TclpSysFree) (TclpSysRealloc): Define for Cygwin. 2002-09-26 Daniel Steffen * macosx/Makefile: preserve environment value of INSTALL_ROOT. When embedding only use deployment build. Force relink before embedded build to ensure new linker flags are picked up. * macosx/Tcl.pbproj/project.pbxproj: add symbolic links to debug lib, stub libs and tclConfig.sh in framework toplevel. Configure target dependency fix. Fix to 'clean' action. Added private tcl headers to framework. Install tclsh symbolic link. Html doc build works when no installed tclsh available. Made html doc structure in framework more like in Apple frameworks. 2002-09-24 Donal K. Fellows * unix/tcl.m4 (SC_TCL_64BIT_FLAGS): Yet more robust 64-bit value detection to close [Bug 613117] on more systems. * generic/tclCompile.c (TclPrintSource): More CONSTifying. * generic/tclExecute.c (EvalStatsCmd): Object-ify to reduce warnings. Thanks to 'CoderX2' on the chat for bringing this to my attention... * unix/tcl.m4: Forgot to define TCL_WIDE_INT_IS_LONG at the appropriate moment. I believe this is the cause of [Bug 613117] * doc/lset.n: Changed 'list' to 'varName' for consistency with lappend documentation. Thanks to Glenn Jackman [Bug 611719] 2002-09-22 Don Porter * library/tcltest/tcltest.tcl: Corrected [puts -nonewline] within test bodies. Thanks to Harald Kirsch. [Bug 612786, Patch 612788] Also corrected reporting of body return code. Thanks to David Taback [Bug 611922] * library/tcltest/pkgIndex.tcl: Bump to version 2.2.1. * tests/tcltest.test: added tests for these bugs. 2002-09-15 Mo DeJong * unix/configure: Regen. * unix/tcl.m4 (SC_CONFIG_CFLAGS): Add PEEK_XCLOSEIM define under Linux. This is used by Tk to double check that an X input context is cleaned up before it is closed. 2002-09-12 David Gravereaux * win/coffbase.txt: Added BLT to the virtual base address listings table should BLT's build tools decide to use it. 2002-09-12 Daniel Steffen * generic/tcl.h: * mac/tclMacApplication.r: * mac/tclMacLibrary.r: * mac/tclMacResource.r: unified use of the two equivalent resource compiler header inclusion defines RC_INVOKED and RESOURCE_INCLUDED, now use RC_INVOKED throughout. 2002-09-10 Mo DeJong * unix/README: Add note about building extensions with the same compiler Tcl was built with. [Tk Bug 592096] 2002-09-10 Daniel Steffen * macosx/Tcl.pbproj/project.pbxproj: disabled building html documentation during embedded build. 2002-09-10 Daniel Steffen * unix/Makefile.in: added DYLIB_INSTALL_DIR variable for macosx and set it to default value ${LIB_RUNTIME_DIR} * unix/tcl.m4 (Darwin): use DYLIB_INSTALL_DIR instead of LIB_RUNTIME_DIR in the -install_name argument to ld. * unix/configure: regen. * macosx/Tcl.pbproj/project.pbxproj: * macosx/Makefile: added support for building Tcl as an embedded framework, i.e. using an dyld install_name containing @executable_path/../Frameworks via the new DYLIB_INSTALL_DIR unix/Makefile variable. 2002-09-10 Jeff Hobbs *** 8.4.0 TAGGED FOR RELEASE *** 2002-09-06 Don Porter * doc/file.n: Format correction, and clarified [file normalize] returns an absolute path. * doc/tcltest.n: Added examples section, as long promised. 2002-09-06 Reinhard Max * tests/tcltest.test: Added nonRoot flag to tests 8.3, 8.4, and 8.12. 2002-09-05 Don Porter * doc/tcltest.n: Clarified phrasing. * generic/tclBasic.c (TclRenameCommand,CallCommandTraces): * tests/trace.test (trace-27.1): Corrected memory leak when a rename trace deleted the command being traced. Test added. Thanks to Hemang Lavana for the fix. [Bug 604609] * generic/tclVar.c (TclDeleteVars): Corrected logic for setting the TCL_INTERP_DESTROYED flag when calling variable traces. [Tk Bug 605121] 2002-09-04 Miguel Sofer * generic/tclVar.c (DeleteArray): leak plug [Bug 604239]. Thanks to dkf and dgp for the long and difficult discussion in the chat. 2002-09-03 Jeff Hobbs * generic/tclVar.c (Tcl_UpVar2): code cleanup to not use goto * unix/configure: remove -pthread from LIBS on FreeBSD in thread * unix/tcl.m4: enabled build. [Bug 602849] 2002-09-03 Miguel Sofer * generic/tclInterp.c (AliasCreate): a Tcl_Obj was leaked on error return from TclPreventAliasLoop. 2002-09-03 Daniel Steffen * macosx/Tcl.pbproj/project.pbxproj: Bumped version number to 8.4.0 and updated copyright info. 2002-09-03 Miguel Sofer * generic/tclVar.c (Tcl_UpVar2): a Tcl_Obj was being leaked on error return from TclGetFrame. 2002-09-03 Don Porter * changes: Updated changes for 8.4.0 release. 2002-09-02 Jeff Hobbs * unix/tclUnixFile.c (TclpObjLink): removed unnecessary/unfreed extra native char*. * unix/tclUnixChan.c (Tcl_MakeTcpClientChannel): make sure to init flags field of TcpState ptr to 0. * unix/configure: * unix/tcl.m4: added 64-bit gcc compilation support on HP-11. [Patch 601051] (martin) * README: Bumped version number to 8.4.0 * generic/tcl.h: * tools/tcl.wse.in: * unix/configure: * unix/configure.in: * unix/tcl.spec: * win/README.binary: * win/configure: * win/configure.in: * generic/tclInterp.c (SlaveCreate): make sure that the memory and checkmem commands are initialized in non-safe slave interpreters when TCL_MEM_DEBUG is used. [Bug 583445] * win/tclWinConsole.c (ConsoleCloseProc): only wait on writable pipe if there was something to write. This may prevent infinite wait on exit. * tests/exec.test: marked exec-18.1 unixOnly until the Windows incompatability (in the test, not the core) can be resolved. * tests/http.test (http-3.11): added close $fp that was causing an error on Windows because the file was not closed before deleting. * unix/tclUnixInit.c (Tcl_MacOSXGetLibraryPath): made this static function only appear when HAVE_CFBUNDLE is defined. 2002-08-31 Daniel Steffen * unix/tcl.m4: added TK_SHLIB_LD_EXTRAS analogue of existing TCL_SHLIB_LD_EXTRAS for linker settings only used when linking Tk. * unix/configure: regen 2002-08-31 Daniel Steffen *** macosx-8-4-branch merged into the mainline [Patch 602770] *** * generic/tcl.decls: added new macosx specific entry to stubs table. * tools/genStubs.tcl: added generation of platform guards for macosx. This is a little more complex than it seems, because MacOS X IS "unix" plus a little bit, for the purposes of Tcl. BUT unfortunately, Tk uses "unix" to mean X11. So added platform keys for macosx (the little added to "unix"), "aqua" and "x11" to distinguish these for Tk. * generic/tcl.h: added a #ifnded RESOURCE_INCLUDED so that tcl.h can be passed to the resource compiler. * generic/tcl.h: * generic/tclNotify.c: added a few Notifier procs, to be able to modify more bits of the Tcl notifier dynamically. Required to get Mac OS X Tk to live on top of the Tcl Unix threaded notifier. Changes the size of the Tcl_NotifierProcs structure, but doesn't move any elements around. * unix/tclUnixNotfy.c: moved the call to Tcl_ConditionNotify till AFTER we are done mucking with the pointer swap. Fixes cases where the thread waiting on the condition wakes & accesses the waitingListPtr before it gets reset, causing a hang. * library/auto.tcl (tcl_findLibrary): added checking the directories in the tcl_pkgPath for library files on macosx to enable support of the standard Mac OSX library locations * unix/Makefile.in: * unix/configure.in: * unix/tcl.m4: added MAC_OSX_DIR. Added PLAT_OBJS to the OBJS: there are some MacOS X specific files now for Tcl, and when I get he resource & applescript stuff ported over, and restore support for FindFiles, etc, there will be a few more. Added LD_LIBRARY_PATH_VAR configure variable to avoid having to set all possible LD_LIBRARY_PATH analogues on all platforms. LD_LIBRARY_PATH_VAR is "LD_LIBRARY_PATH" by default, "LIBPATH" on AIX, "SHLIB_PATH" on HPUX and "DYLD_LIBRARY_PATH" on Mac OSX. Added configure option to package Tcl as a framework on Mac OSX. * macosx/tclMacOSXBundle.c (new): support for finding Tcl extension packaged as 'bundles' in the standard Mac OSX library locations. * unix/tclUnixInit.c: added support for findig the tcl script library inside Tcl packaged as a framework on Mac OSX. * macosx/Tcl.pbproj/jingham.pbxuser (new): * macosx/Tcl.pbproj/project.pbxproj (new): project for Apple's ProjectBuilder IDE. * macosx/Makefile (new): simple makefile for building the project from the command line via the ProjectBuilder tool 'pbxbuild'. * unix/configure: * generic/tclStubInit.c: * generic/tclPlatDecls.h: regen 2002-08-29 Andreas Kupries * win/tclWinThrd.c (TclpFinalizeThreadData, TclWinFreeAllocCache): Applied patch for [Bug 599428] (sofer) 2002-08-28 David Gravereaux * generic/tclEnv.c: * unix/configure.in: * win/tclWinPort.h: putenv() on some systems copies the buffer rather than taking reference to it. This causes memory leaks and is know to effect mswindows (msvcrt) and NetBSD 1.5.2. This patch tests for this behavior and turns on -DHAVE_PUTENV_THAT_COPIES=1 when approriate. Thanks to David Welton for assistance. [Bug 414910] * unix/configure: regen'd 2002-08-28 Donal K. Fellows * doc/eval.n: Added mention of list command and corrected "SEE ALSO". * unix/configure.in: Cache handling of ac_cv_type_socklen_t was wrong. [Bug 600931] reported by John Ellson. Fixed by putting the brackets where they belong. 2002-08-26 Miguel Sofer * generic/tclCompCmds.c: fix for [Bug 599788] (error in element name causing segfault), reported by Tom Wilkason. Fixed by copying the tokens instead of the source string. 2002-08-26 Miguel Sofer * generic/tclThreadAlloc.c: small optimisation, reducing the new allocator's overhead. 2002-08-23 Miguel Sofer * generic/tclObj.c (USE_THREAD_ALLOC): fixed leak [Bug 597936]. Thanks to Zoran Vasiljevic. 2002-08-23 Miguel Sofer * generic/tclThreadAlloc.c (USE_THREAD_ALLOC): moving objects between caches as a block, instead of one-by-one. 2002-08-22 Miguel Sofer * generic/tclBasic.c: * generic/tclCmdMZ.c: fix for freed memory r/w in delete traces [Bug 589863], patch by Hemang Lavana. 2002-08-20 Andreas Kupries * win/Makefile.in (CFLAGS): * unix/Makefile.in (MEM_DEBUG_FLAGS): Added usage of @MEM_DEBUG_FLAGS@. * win/configure.in: * unix/configure.in: Added usage of SC_ENABLE_MEMDEBUG. * win/tcl.m4: * unix/tcl.m4: Added macro SC_ENABLE_MEMDEBUG. Allows a user of configure to (de)activate memory validation and debugging (TCL_MEM_DEBUG). No need to modify the makefile anymore. 2002-08-20 Don Porter * generic/tclCkalloc.c: CONSTified MemoryCmd and CheckmemCmd. * README: Bumped version number to 8.4b3 to distinguish * generic/tcl.h: HEAD from the 8.4b2 release. * tools/tcl.wse.in: * unix/configure.in: * unix/tcl.spec: * win/README.binary: * win/configure.in: * unix/configure: autoconf * win/configure: * library/http/http.tcl: Corrected installation directory of * library/msgcat/msgcat.tcl: the package tcltest 2.2. Added * library/opt/optparse.tcl: comments in other packages to remind * library/tcltest/tcltest.tcl: that installation directories need * unix/Makefile.in: updates to match increasing version * win/Makefile.in: numbers. [Bug 597450] * win/makefile.bc: * win/makefile.vc: 2002-08-19 Andreas Kupries * unix/tclUnixTest.c (TestfilehandlerCmd): Changed readable/writable to the more common readable|writable. Fixes [Bug 596034] (lvirden) 2002-08-16 Donal K. Fellows * tests/fCmd.test: Added test to make sure that the cause of the problem is detectable with an unpatched Tcl. * doc/ObjectType.3: Added note on the root cause of this problem to the documentation, since it is possible for user code to trigger this sort of behaviour too. * generic/tclIOUtil.c (SetFsPathFromAny): Objects should only have their old representation deleted when we know that we are about to install a new one. This stops a weird TclX bug under Linux with certain kinds of memory debugging enabled which essentally came down to a double-free of a string. 2002-08-14 Miguel Sofer * generic/tclInt.h: * generic/tclObj.c: (code cleanup) factored the parts in the macros TclNewObj() / TclDecrRefCount() into a common part for all memory allocators and two new macros TclAllocObjStorage() / TclFreeObjStorage() that are specific to each allocator and fully describe the differences. Removed allocator-specific code from tclObj.c by using the macros. 2002-08-12 Miguel Sofer * generic/tclCmdMZ.c: fixing UMR in delete traces, [Bug 589863]. 2002-08-08 David Gravereaux * tools/man2help.tcl: Fixed $argv handling bug where if -bitmap wasn't specified $argc was off by one. 2002-08-08 Miguel Sofer * tests/uplevel.test: added 6.1 to test [uplevel] with shadowed commands [Bug 524383] * tests/subst.test: added 5.8-10 as further tests for [Bug 495207] 2002-08-08 Don Porter * tests/README: Noted removal of defs.tcl. 2002-08-08 Jeff Hobbs * doc/lsearch.n: corrected lsearch docs to use -inline in examples. *** 8.4b2 TAGGED FOR RELEASE *** * tests/fCmd.test: * tests/unixFCmd.test: updated tests for new link copy behavior. * generic/tclFCmd.c (CopyRenameOneFile): changed the behavior to follow links to endpoints and copy that file/directory instead of just copying the surface link. This means that trying to copy a link that has no endpoint (danling link) is an error. [Patch 591647] (darley) (CopyRenameOneFile): this is currently disabled by default until further issues with such behavior (like relative links) can be handled correctly. * tests/README: slight wording improvements 2002-08-07 Miguel Sofer * docs/BoolObj.3: added description of valid string reps for a boolean object [Bug 584794] * generic/tclObj.c: optimised Tcl_GetBooleanFromObj and SetBooleanFromAny to avoid parsing the string rep when it can be avoided [Bugs 584650, 472576] 2002-08-07 Miguel Sofer * generic/tclCompile.h: * generic/tclObj.c: making tclCmdNameType static [Bug 584567] (dgp) 2002-08-07 Miguel Sofer * generic/tclObj.c (Tcl_NewObj): added conditional code for USE_THREAD_ALLOC; objects allocated through Tcl_NewObj() were otherwise being leaked. [Bug 587488] reported by Sven Sass. 2002-08-06 Daniel Steffen * generic/tclInt.decls: * unix/tclUnixThrd.c: Added stubs and implementations for non-threaded build for the tclUnixThrd.c procs TclpReaddir, TclpLocaltime, TclpGmtime and TclpInetNtoa. Fixes link errors in stubbed & threaded extensions that include tclUnixPort.h and use any of the procs readdir, localtime, gmtime or inet_ntoa (e.g. TclX 8.4) [Bug 589526] * generic/tclIntPlatDecls.h: * generic/tclStubInit.c: Regen. 2002-08-05 Don Porter * library/tcltest/tcltest.tcl: The setup and cleanup scripts are now * library/tcltest/pkgIndex.tcl: skipped when a test is skipped, fixing * tests/tcltest.test: [Bug 589859]. Test for bug added, and corrected tcltest package bumped to version 2.2. * generic/tcl.decls: Restored Tcl_Concat to return (char *). Like * generic/tclDecls.h: Tcl_Merge, it transfers ownership of a dynamic * generic/tclUtil.c: allocated string to the caller. 2002-08-04 Don Porter * doc/CmdCmplt.3: Applied Patch 585105 to fully CONST-ify * doc/Concat.3: all remaining public interfaces of Tcl. * doc/CrtCommand.3: Notably, the parser no longer writes on * doc/CrtSlave.3: the string it is parsing, so it is no * doc/CrtTrace.3: longer necessary for Tcl_Eval() to be * doc/Eval.3: given a writable string. Also, the * doc/ExprLong.3: refactoring of the Tcl_*Var* routines * doc/LinkVar.3: by Miguel Sofer is included, so that the * doc/ParseCmd.3: "part1" argument for them no longer needs * doc/SetVar.3: to be writable either. * doc/TraceVar.3: * doc/UpVar.3: Compatibility support has been enhanced so * generic/tcl.decls: that a #define of USE_NON_CONST will remove * generic/tcl.h: all possible source incompatibilities with * generic/tclBasic.c: the 8.3 version of the header file(s). * generic/tclCmdMZ.c: The new #define of USE_COMPAT_CONST now does * generic/tclCompCmds.c:what USE_NON_CONST used to do -- disable * generic/tclCompExpr.c:only those new CONST's that introduce * generic/tclCompile.c: irreconcilable incompatibilities. * generic/tclCompile.h: * generic/tclDecls.h: Several bugs are also fixed by this patch. * generic/tclEnv.c: [Bugs 584051,580433] [Patches 585105,582429] * generic/tclEvent.c: * generic/tclInt.decls: * generic/tclInt.h: * generic/tclIntDecls.h: * generic/tclInterp.c: * generic/tclLink.c: * generic/tclObj.c: * generic/tclParse.c: * generic/tclParseExpr.c: * generic/tclProc.c: * generic/tclTest.c: * generic/tclUtf.c: * generic/tclUtil.c: * generic/tclVar.c: * mac/tclMacTest.c: * tests/expr-old.test: * tests/parseExpr.test: * unix/tclUnixTest.c: * unix/tclXtTest.c: * win/tclWinTest.c: 2002-08-01 Miguel Sofer * generic/tclExecute.c: bugfix (reading freed memory). Testsuite passed on linux/i386, compile-13.1 hung on linux/alpha. 2002-08-01 Miguel Sofer * generic/tclExecute.c: added a reference count for the complete execution stack, instead of Tcl_Preserve/Tcl_Release. 2002-08-01 Mo DeJong * generic/tclCkalloc.c (TclFinalizeMemorySubsystem): Don't lock the ckalloc mutex before invoking the Tcl_DumpActiveMemory function since it also locks the same mutex. This code is only executed when "memory onexit filename" has been executed and Tcl is compiled with -DTCL_MEM_DEBUG. 2002-08-01 Reinhard Max * win/tclWinPort.h: The windows headers don't provide socklen_t, so we have to do it. 2002-07-31 Miguel Sofer * generic/tclInt.h (USE_THREAD_ALLOC): for unshared objects, TclDecrRefCount now frees the internal rep before the string rep - just like the non-macro Tcl_DecrRefCount/TclFreeObj [Bug 524802]. For the other allocators the fix was done on 2002-03-06. 2002-07-31 Miguel Sofer * generic/tclInterp.c: signed/unsigned comparison warning fixed (Vince Darley). 2002-07-31 Donal K. Fellows * unix/tcl.m4 (SC_BUGGY_STRTOD): Enabled caching of test results. * unix/tcl.m4 (SC_BUGGY_STRTOD): Solaris 2.8 still has a buggy strtod() implementation; make sure we detect it. * tests/expr.test (expr-22.*): Marked as non-portable because it seems that these tests have an annoying tendency to fail in unexpected ways. [Bugs 584825, 584950, 585986] 2002-07-30 Andreas Kupries * tests/io.test: * generic/tclIO.c (WriteChars): Added flag to break out of loop if nothing of the input is consumed at all, to prevent infinite looping of called with a non-UTF-8 string. Fixes [Bug 584603] partially. Added new test "io-60.1". Might need additional changes to Tcl_Main so that unprintable results are printed as binary data. 2002-07-29 Mo DeJong * unix/Makefile.in: Use CC_SEARCH_FLAGS instead of LD_SEARCH_FLAGS when linking with ${CC}. * unix/configure: Regen. * unix/configure.in: Don't subst CC_SEARCH_FLAGS or LD_SEARCH_FLAGS since this is now done in tcl.m4. * unix/tcl.m4 (SC_CONFIG_CFLAGS): Document and set CC_SEARCH_FLAGS whenever LD_SEARCH_FLAGS is set. [Patch 588290] 2002-07-29 Reinhard Max * unix/tcl.m4 (SC_SERIAL_PORT): Fixed detection for cases when configure's stdin is not a tty. * unix/tclUnixPort.h: * generic/tclIOSock.c: Changed size_t to socklen_t in socket-related function calls. * unix/configure.in: Added test and fallback definition for socklen_t. * unix/configure: generated. 2002-07-29 Miguel Sofer * generic/tclObj.c: fixed a comment * generic/tcl.h: * generic/tclBasic.c: * generic/tclInterp.c: added the new flag TCL_EVAL_INVOKE to the interface of the Tcl_Eval* functions, removing the TCL_EVAL_NO_TRACEBACK added yesterday: alias invocations not only require no tracebacks, but also look up the command name in the global scope - see new test interp-9.4 * tests/interp.test: added 9.3 to test for safety of aliases to hidden commands, 9.4 to test for correct command lookup scope. 2002-07-29 Donal K. Fellows * generic/regc_locale.c (cclass): [[:xdigit:]] is only a defined concept on western characters, so should not allow any unicode digit, and hence number of ranges in [[:xdigit:]] is fixed. * tests/reg.test: Added test to detect the bug. * generic/regc_cvec.c (newcvec): Corrected initial size value in character vector structure. [Bug 578363] Many thanks to pvgoran@users.sf.net for tracking this down. 2002-07-28 Miguel Sofer * generic/tcl.h: * generic/tclBasic.c: added the new flag TCL_EVAL_NO_TRACEBACK to the interface of the Tcl_Eval* functions. Modified the error message for too many nested evaluations. * generic/tclInterp.h: changed the Alias struct to be of variable length and store the prefix arguments directly (instead of a pointer to a Tcl_Obj list). Made AliasObjCmd call Tcl_EvalObjv instead of TclObjInvoke - thus making aliases trigger execution traces. [Bug 582522] * tests/interp.test: * tests/stack.test: adapted to the new error message. * tests/trace.test: added tests for aliases firing the exec traces. 2002-07-27 Mo DeJong * unix/Makefile.in: Revert fix for Tcl bug 529801 since it was incorrect and broke the build on other systems. Fix [Bug 587299]. Add MAJOR_VERSION, MINOR_VERSION, PATCH_LEVEL, SHLIB_LD_FLAGS, SHLIB_LD_LIBS, CC_SEARCH_FLAGS, LD_SEARCH_FLAGS, and LIB_FILE variables to support more generic library build/install rules. * unix/configure: Regen. * unix/configure.in: Move AC_PROG_RANLIB into tcl.m4. Move shared build test and setting of MAKE_LIB and MAKE_STUB_LIB into tcl.m4. Move subst of a number of variables into tcl.m4 where they are defined. * unix/tcl.m4 (SC_ENABLE_SYMBOLS, SC_CONFIG_CFLAGS): Subst vars where they are defined. Add MAKE_LIB, MAKE_STUB_LIB, INSTALL_LIB, and INSTALL_STUB_LIB rules to deal with the ugly details of running ranlib on static libs at build and install time. Replace TCL_SHLIB_LD_EXTRAS with SHLIB_LD_FLAGS and use it when building a shared library. * unix/tclConfig.sh.in: Add TCL_CC_SEARCH_FLAGS. 2002-07-26 Miguel Sofer * generic/tclExecute.c: fixed Tcl_Obj leak in code corresponding to the macro NEXT_INST_V(x, 0, 1). [Bug 587495] 2002-07-26 Miguel Sofer * generic/tclVar.c (TclObjLookupVar): leak fix and improved comments. 2002-07-26 Jeff Hobbs * generic/tclVar.c (TclLookupVar): removed early returns that prevented the parens from being restored. also removed goto label as it was not necessary. 2002-07-24 Miguel Sofer * generic/tclExecute.c: * tests/expr-old.test: fix for erroneous error messages in [expr], [Bug 587140] reported by Martin Lemburg. 2002-07-25 Joe English * generic/tclProc.c: fix for [Tk Bug 219218] "error handling with bgerror in Tk" 2002-07-24 Miguel Sofer * generic/tclExecute.c: restoring full TCL_COMPILE_DEBUG functionality. 2002-07-24 Don Porter * tests/unixInit.test: relaxed unixInit-3.1 to accept iso8859-15 as a valid C encoding. [Bug 575336] 2002-07-24 Miguel Sofer * generic/tclExecute.c: restoring the tcl_traceCompile functionality while I repair tcl_traceExec. The core now compiles and runs also under TCL_COMPILE_DEBUG, but execution in the bytecode engine can still not be traced. 2002-07-24 Daniel Steffen * unix/Makefile.in: * unix/configure.in: corrected fix for [Bug 529801]: ranlib only needed for static builds on Mac OS X. * unix/configure: Regen. * unix/tclLoadDyld.c: fixed small bugs introduced by Vince, implemented library unloading correctly (needs OS X 10.2). 2002-07-23 Joe English * doc/OpenFileChnl.3: (Updates from Larry Virden) * doc/open.n: * doc/tclsh.1: Fix section numbers in Unix man page references. * doc/lset.n: In EXAMPLES section, include command to set the initial value used in subsequent examples. * doc/http.n: Package version updated to 2.4. 2002-07-23 Mo DeJong * unix/configure: Regen. * unix/tcl.m4 (SC_CONFIG_CFLAGS): Enable 64 bit compilation when using the native compiler on a 64 bit version of IRIX. [Bug 219220] 2002-07-23 Mo DeJong * unix/Makefile.in: Combine ranlib tests and avoid printing unless ranlib is actually run. 2002-07-23 Mo DeJong * unix/tcl.m4 (SC_PATH_X): Set XINCLUDES to "" instead of "# no special path needed" or "# no include files found" when x headers cannot be located. 2002-07-22 Vince Darley * generic/tclIOUtil.c: made tclNativeFilesystem static (since 07-19 changes removed its usage elsewhere), and added comments about its usage. * generic/tclLoad.c: * generic/tcl.h: * generic/tcl.decls: * doc/FileSystem.3: converted last load-related ClientData parameter to Tcl_LoadHandle opaque structure, removing a couple of casts in the process. * generic/tclInt.h: removed tclNativeFilesystem declaration since it is now static again. 2002-07-22 Donal K. Fellows * tests/expr.test (expr-22.*): Added tests to help detect the corrected handling. * generic/tclExecute.c (IllegalExprOperandType): Improved error message generated when attempting to manipulate Inf and NaN values. * generic/tclParseExpr.c (GetLexeme): Allowed parser to recognise 'Inf' as a floating-point number. [Bug 218000] 2002-07-21 Don Porter * tclIOUtil.c: Silence compiler warning. [Bug 584408]. 2002-07-19 Vince Darley * generic/tclIOUtil.c: fix to GetFilesystemRecord * win/tclWinFile.c: * unix/tclUnixFile.c: fix to subtle problem with links shown up by latest tclkit builds. 2002-07-19 Mo DeJong * unix/configure: * unix/configure.in: * win/configure: * win/configure.in: Add AC_PREREQ(2.13) in an attempt to make it more clear that the configure scripts must be generated with autoconf version 2.13. [Bug 583573] 2002-07-19 Vince Darley * unix/Makefile.in: fix to build on MacOS X [Bug 529801], bug report and fix from jcw. 2002-07-19 Donal K. Fellows * win/tclWinSerial.c (no_timeout): Made this variable static. * generic/tclExecute.c, generic/tclCompile.c, generic/tclBasic.c: * generic/tclCompile.h (builtinFuncTable, instructionTable): Added prefix to these symbols because they are visible outside the Tcl library. * generic/tclCompExpr.c (operatorTable): * unix/tclUnixTime.c (tmKey): * generic/tclIOUtil.c (theFilesystemEpoch, filesystemWantToModify, (filesystemIteratorsInProgress, filesystemOkToModify): Made these variables static. * unix/tclUnixFile.c: Renamed nativeFilesystem to * win/tclWinFile.c: tclNativeFilesystem and declared * generic/tclIOUtil.c: it properly in tclInt.h * generic/tclInt.h: * generic/tclUtf.c (totalBytes): Made this array static and const. * generic/tclParse.c (typeTable): Made this array static and const. (Tcl_ParseBraces): Simplified error handling case so that scans are only performed when needed, and flags are simpler too. * license.terms: Added AS to list of copyright holders; it's only fair for the current gatekeepers to be listed here! * tests/cmdMZ.test: Renamed constraint for clarity. [Bug 583427] Added tests for the [time] command, which was previously only indirectly tested! 2002-07-18 Vince Darley * generic/tclInt.h: * generic/tcl.h: * */*Load*.c: added comments on changes of 07/17 and replaced clientData with Tcl_LoadHandle in all locations. * generic/tclFCmd.c: * tests/fileSystem.test: fixed a 'knownBug' with 'file attributes ""' * tests/winFCmd.test: * tests/winPipe.test: * tests/fCmd.test: * tessts/winFile.test: added 'pcOnly' constraint to some tests to make for more useful 'tests skipped' log from running all tests on non-Windows platforms. 2002-07-17 Miguel Sofer * generic/tclBasic.c (CallCommandTraces): delete traces now receive the FQ old name of the command. [Bug 582532] (Don Porter) 2002-07-18 Vince Darley * tests/ioUtil.test: added constraints to 1.4,2.4 so they don't run outside of tcltest. [Bugs 583276,583277] 2002-07-17 Miguel Sofer * generic/tclVar.c (DupParsedVarName): nasty bug fixed, reported by Vince Darley. 2002-07-17 Miguel Sofer * generic/tclVar.c (TclPtrIncrVar): missing CONST in declarations, inconsistent with tclInt.h. Thanks to Vince Darley for reporting, boo to gcc for not complaining. 2002-07-17 Vince Darley * generic/tclInt.h: * generic/tclIOUtil.c: * generic/tclLoadNone.c: * unix/tclLoadAout.c: * unix/tclLoadDl.c: * unix/tclLoadDld.c: * unix/tclLoadDyld.c: * unix/tclLoadNext.c: * unix/tclLoadOSF.c: * unix/tclLoadShl.c: * mac/tclMacLoad.c: * win/tclWinLoad.c: modified to move more functionality to the generic code and avoid duplication. Partial replacement of internal uses of clientData with opaque Tcl_LoadHandle. A little further work still needed, but significant changes are done. 2002-07-17 D. Richard Hipp * library/msgcat/msgcat.tcl: fix a comment that was causing problems for programs (ex: mktclapp) that embed the initialization scripts in strings. 2002-07-17 Miguel Sofer * generic/tclInt.decls: * generic/tclIntDecls.h: * generic/tclStubInit.c: * generic/tclVar.c: removing the now redundant functions to access indexed variables: Tcl(Get|Set|Incr)IndexedScalar() and Tcl(Get|Set|Incr)ElementOfIndexedArray(). 2002-07-17 Donal K. Fellows * generic/tclExecute.c (TclExecuteByteCode): Minor fixes to make this file compile with SunPro CC... 2002-07-17 Miguel Sofer * generic/tclExecute.c: modified to do variable lookup explicitly, and then either inlining the variable access or else calling the new TclPtr(Set|Get|Incr)Var functions in tclVar.c * generic/tclInt.h: declare some functions previously local to tclVar.c for usage by TEBC. * generic/tclVar.c: removed local declarations; moved all special accessor functions for indexed variables to the end of the file - they are unused and ready for removal, but left there for the time being as they are in the internal stubs table. ** WARNING FOR BYTECODE MAINTAINERS ** TCL_COMPILE_DEBUG is currently not functional; will be fixed ASAP. 2002-07-16 Mo DeJong * unix/Makefile.in: * win/Makefile.in: Add a more descriptive warning in the event `make genstubs` needs to be rerun. 2002-07-16 Mo DeJong * unix/Makefile.in: Use dltest.marker file to keep track of when the dltest package is up to date. This fixes [Bug 575768] since tcltest is no longer linked every time. * unix/dltest/Makefile.in: Create ../dltest.marker after a successful `make all` run in dltest. 2002-07-16 Mo DeJong * unix/configure: Regen. * unix/configure.in: Remove useless subst of TCL_BIN_DIR. 2002-07-15 Miguel Sofer * generic/tclVar.c: inaccurate comment fixed 2002-07-15 Miguel Sofer * generic/tclBasic.c (Tcl_AddObjErrorInfo): * generic/tclExecute.c (TclUpdateReturnInfo): * generic/tclInt.h: * generic/tclProc.c: Added two Tcl_Obj to the ExecEnv structure to hold the fully qualified names "::errorInfo" and "::errorCode" to cache the addresses of the corresponding variables. The two most frequent setters of these variables now profit from the new variable name caching. 2002-07-15 Miguel Sofer * generic/tclVar.c: refactorisation to reuse already looked-up Var pointers; definition of three new Tcl_Obj types to cache variable name parsing and lookup for later reuse; modification of internal functions to profit from the caching. * generic/tclInt.decls: * generic/tclInt.h: * generic/tclIntDecls.h: * generic/tclNamesp.c: adding CONST qualifiers to variable names passed to Tcl_FindNamespaceVar and to variable resolvers; adding CONST qualifier to the 'msg' argument to TclLookupVar. Needed to avoid code duplication in the new tclVar.c code. * tests/set-old.test: * tests/var.test: slight modification of error messages due to the modifications in the tclVar.c code. 2002-07-15 Don Porter * tests/unixInit.test: Improved constraints to protect /tmp. [Bug 581403] 2002-07-15 Vince Darley * tests/winFCmd.test: renamed 'win2000' and 'notWin2000' to more appropriate constraint names. * win/tclWinFile.c: updated comments to reflect 07-11 changes. * win/tclWinFCmd.c: made ConvertFileNameFormat static again, since no longer used in tclWinFile.c * mac/tclMacFile.c: completed TclpObjLink implementation which was previously lacking. * generic/tclIOUtil.c: comment cleanup and code speedup. 2002-07-14 Don Porter * generic/tclInt.h: Removed declarations that duplicated entries in the (internal) stub table. * library/tcltest/tcltest.tcl: Corrected errors in handling of configuration options -constraints and -limitconstraints. * README: Bumped HEAD to version 8.4b2 so we can * generic/tcl.h: distinguish it from the 8.4b1 release. * tools/tcl.wse.in: * unix/configure*: * unix/tcl.spec: * win/README.binary: * win/configure*: 2002-07-11 Vince Darley * doc/file.n: * win/tclWinFile.c: on Win 95/98/ME the long form of the path is used as a normalized form. This is required because short forms are not a robust representation. The file normalization function has been sped up, but more performance gains might be possible, if speed is still an issue on these platforms. 2002-07-11 Don Porter * library/tcltest/tcltest.tcl: Corrected reaction to existing but false ::tcl_interactive. * doc/Hash.3: Overlooked CONST documentation update. 2002-07-11 Donal K. Fellows * generic/tclCkalloc.c: ckalloc() and friends take the block size as an unsigned, so we should use %ud when reporting it in fprintf() and panic(). 2002-07-11 Miguel Sofer * generic/tclCompile.c: now setting local vars undefined at compile time, instead of waiting until the proc is initialized. * generic/tclProc.c: use macro TclSetVarUndefined instead of directly setting the flag. 2002-07-11 Donal K. Fellows * tests/cmdAH.test: [file attr -perm] is Unix-only, so add [catch] when not inside a suitably-protected test. 2002-07-10 Donal K. Fellows * tests/unixFCmd.test, tests/fileName.test: * tests/fCmd.test: Removed [exec] of Unix utilities that have equivalents in standard Tcl. [Bug 579268] Also simplified some of unixFCmd.test while I was at it. 2002-07-10 Don Porter * tests/tcltest.test: Greatly reduced the number of [exec]s, using slave interps instead. * library/tcltest/tcltest.tcl: Fixed bug uncovered in the conversion where a message was written to stdout instead of [outputChannel]. * tests/basic.test: Cleaned up, constrained, and reduced the * tests/compile.test: amount of [exec] usage in the test suite. * tests/encoding.test: * tests/env.test: * tests/event.test: * tests/exec.test: * tests/io.test: * tests/ioCmd.test: * tests/regexp.test: * tests/regexpComp.test: * tests/socket.test: * tests/tcltest.test: * tests/unixInit.test: * tests/winDde.test: * tests/winPipe.test: 2002-07-10 Donal K. Fellows * tests/cmdAH.test: Removed [exec] of Unix utilities. [Bug 579211] * tests/expr.test: Added tests to make sure that this works. * generic/tclExecute.c (ExprCallMathFunc): Functions should also be able to return wide-ints. [Bug 579284] 2002-07-08 Andreas Kupries * tests/socket.test: Fixed [Bug 578164]. The original reason for the was a DNS outage while running the testsuite. Changed [info hostname] to 127.0.0.1 to bypass DNS, knowing that we operate on the local host. 2002-07-08 Don Porter * doc/tcltest.n: Fixed incompatibility in [viewFile]. * library/tcltest/tcltest.tcl: Corrected docs. Bumped to 2.2.1. * library/tcltest/pkgIndex.tcl: [Bug 578163] 2002-07-08 Vince Darley * tests/cmdAH.test: * tests/fCmd.test: * tests/fileName.test: tests which rely on 'file link' need a constraint so they don't run on older Windows OS. [Bug 578158] * generic/tclIOUtil.c: * generic/tcl.h: * generic/tclInt.h: * generic/tclTest.c: * mac/tclMacChan.c: * unix/tclUnixChan.c: * win/tclWinChan.c: * doc/FileSystem.3: cleaned up internal handling of Tcl_FSOpenFileChannel to remove duplicate code, and make writing external vfs's clearer and easier. No functionality change. Also clarify that objects with refCount zero should not be passed in to the Tcl_FS API, and prevent segfaults from occuring on such user errors. [Bug 578617] 2002-07-06 Don Porter * tests/pkgMkIndex.test: Constrained tests of [load] package indexing to those platforms where the testing shared libraries have been built. [Bug 578166]. 2002-07-05 Don Porter * changes: added recent changes 2002-07-05 Reinhard Max * generic/tclClock.c (FormatClock): Convert the format string to UTF8 before calling TclpStrftime, so that non-ASCII characters don't get mangled when the result string is being converted back. * tests/clock.test: Added a test for that. 2002-07-05 Donal K. Fellows * unix/Makefile.in (ro-test,ddd,GDB,DDD): Created new targets to allow running the test suite with a read-only current directory, running under ddd instead of gdb, and factored out some executable names for broken sites (like mine) where gdb and ddd are installed with non-standard names... * tests/httpold.test: Altered test names to httpold-* to avoid clashes with http.test, and stopped tests from failing when the current directory is not writable... * tests/event.test: Stop these tests from failing * tests/ioUtil.test: when the current directory is * tests/regexp.test: not writable... * tests/regexpComp.test: * tests/source.test: * tests/unixFile.test: * tests/unixNotfy.test: * tests/unixFCmd.test: Trying to make these test-files * tests/macFCmd.test: not bomb out with an error when * tests/http.test: the current directory is not * tests/fileName.test: writable... * tests/env.test: 2002-07-05 Jeff Hobbs *** 8.4b1 TAGGED FOR RELEASE *** 2002-07-04 Donal K. Fellows * tests/cmdMZ.test (cmdMZ-1.4): * tests/cmdAH.test: More fixing of writable-current-dir assumption. [Bug 575824] 2002-07-04 Miguel Sofer * tests/basic.test: Same issue as below; fixed [Bug 575817] 2002-07-04 Andreas Kupries * tests/socket.test: * tests/winPipe.test: * tests/pid.test: Fixed [Bug 575848]. See below for a description the general problem. All the bugs below are instances of the same problem: The testsuite assumes [pwd] = [temporaryDirectory] and writable. * tests/iogt.test: Fixed [Bug 575860] * tests/io.test: Fixed [Bug 575862] * tests/exec.test: * tests/ioCmd.test: Fixed [Bug 575836] 2002-07-03 Don Porter * tests/pkg1/direct1.tcl: removed * tests/pkg1/pkgIndex.tcl: removed * tests/pkgMkIndex.test: Imported auxilliary files from tests/pkg1 into the test file pkgMkIndex.test itself. Formatting fixes. * unix/Makefile.in: removed tests/pkg/* from `make dist` * tests/pkg/circ1.tcl: removed * tests/pkg/circ2.tcl: removed * tests/pkg/circ3.tcl: removed * tests/pkg/global.tcl: removed * tests/pkg/import.tcl: removed * tests/pkg/pkg1.tcl: removed * tests/pkg/pkg2_a.tcl: removed * tests/pkg/pkg2_b.tcl: removed * tests/pkg/pkg3.tcl: removed * tests/pkg/pkg4.tcl: removed * tests/pkg/pkg5.tcl: removed * tests/pkg/pkga.tcl: removed * tests/pkg/samename.tcl: removed * tests/pkg/simple.tcl: removed * tests/pkg/spacename.tcl: removed * tests/pkg/std.tcl: removed * tests/pkgMkIndex.test: Fixed [Bug 575857] where this test file expected to be able to write to [file join [testsDirectory] pkg]. Part of the fix was to import several auxilliary files into the test file itself. * tests/main.test: Cheap fix for [Bugs 575851, 575858]. Avoid * tests/tcltest.test: non-writable . by [cd [temporaryDirectory]]. * library/auto.tcl: Fix [tcl_findLibrary] to be sure it sets $varName only if a successful library script is found. [Bug 577033] 2002-07-03 Miguel Sofer * generic/tclCompCmds.c (TclCompileCatchCmd): return TCL_OUT_LINE_COMPILE instead of TCL_ERROR: let the failure happen at runtime so that it can be caught [Bug 577015]. 2002-07-02 Joe English * doc/tcltest.n: Markup fixes, spellcheck. 2002-07-02 Don Porter * doc/tcltest.n: more refinements of the documentation. * library/tcltest/tcltest.tcl: Added trace to be sure the stdio constraint is updated whenever the [interpreter] changes. * doc/tcltest.n: Reverted [makeFile] and [viewFile] to * library/tcltest/tcltest.tcl: their former behavior, and documented * tests/cmdAH.test: it. Corrected misspelling of hook * tests/event.test: procedure. Restored tests. * tests/http.test: * tests/io.test: * library/tcltest/tcltest.tcl: Simplified logic of [GetMatchingFiles] and [GetMatchingDirectories], removing special case processing. * doc/tcltest.n: More documentation updates. Reference sections are complete. Only examples need adding. 2002-07-02 Vince Darley * tests/fCmd.test: * generic/tclCmdAH.c: clearer error msgs for 'file link', as per the man page. 2002-07-01 Joe English * doc/Access.3: * doc/AddErrInfo.3: * doc/Alloc.3: * doc/Backslash.3: * doc/CrtChannel.3: * doc/CrtSlave.3: * doc/Encoding.3: * doc/Eval.3: * doc/FileSystem.3: * doc/Notifier.3: * doc/OpenFileChnl.3: * doc/ParseCmd.3: * doc/RegExp.3: * doc/Tcl_Main.3: * doc/Thread.3: * doc/TraceCmd.3: * doc/Utf.3: * doc/WrongNumArgs.3: * doc/binary.n: * doc/clock.n: * doc/expr.n: * doc/fconfigure.n: * doc/glob.n: * doc/http.n: * doc/interp.n: * doc/lsearch.n: * doc/lset.n: * doc/msgcat.n: * doc/packagens.n: * doc/pkgMkIndex.n: * doc/registry.n: * doc/resource.n: * doc/safe.n: * doc/scan.n: * doc/tclvars.n: Spell-check, fixed typos (Updates from Larry Virden) 2002-07-01 Donal K. Fellows * unix/tcl.m4 (SC_CONFIG_CFLAGS): Made Solaris use gcc for linking when building with gcc to resolve problems with undefined symbols being present when tcl library used with non-gcc linker at later stage. Symbols were compiler-generated, so it is the compiler's business to define them. [Bug 541181] 2002-07-01 Don Porter * doc/tcltest.n: more work in progress updating tcltest docs. * library/tcltest/tcltest.tcl: Change [configure -match] to stop treating an empty list as a list of the single pattern "*". Changed the default value to [list *] so default operation remains the same. * tests/pkg/samename.tcl: restored. Needed by pkgMkIndex.test. * library/tcltest/tcltest.tcl: restored writeability testing of -tmpdir, augmented by a special exception for the deafault value. 2002-07-01 Donal K. Fellows * doc/concat.n: Documented the *real* behaviour of [concat]! 2002-06-30 Don Porter * doc/tcltest.n: more work in progress updating tcltest docs. * tests/README: Updated the instructions on running and * tests/cmdMZ.test: adding to the test suite. Also updated * tests/encoding.test: several tests, mostly to correctly create * tests/fCmd.test: and destroy any temporary files in the * tests/info.test: [temporaryDirectory] of tcltest. * tests/interp.test: * library/tcltest/tcltest.tcl: Stopped checking for writeability of -tmpdir value because no default directory can be guaranteed to be writeable. * tests/autoMkindex.tcl: removed. * tests/pkg/samename.tcl: removed. * tests/pkg/magicchar.tcl: removed. * tests/pkg/magicchar2.tcl: removed. * tests/autoMkindex.test: Updated auto_mkIndex tests to use [makeFile] and [removeFile] so tests are done in [temporaryDirecotry] where write access is guaranteed. * library/tcltest/tcltest.tcl: Fixed [makeFile] and [viewFile] to * tests/cmdAH.test: accurately reflect a file's contents. * tests/event.test: Updated tests that depended on buggy * tests/http.test: behavior. Also added warning messages * tests/io.test: to "-debug 1" operations to debug test * tests/iogt.test: calls to (make|remove)(File|Directory). * unix/mkLinks: `make mklinks` on 6-27 commits. 2002-06-28 Miguel Sofer * generic/tclCompile.h: modified the macro TclEmitPush to not call its first argument repeatedly or pass it to other macros, [Bug 575194] reported by Peter Spjuth. 2002-06-28 Don Porter * docs/tcltest.n: Doc revisions in progress. * library/tcltest/tcltest.tcl: Corrected -testdir default value. Was not reliable, and disagreed with docs! Thanks to Hemang Lavana. [Bug 575150] 2002-06-28 Donal K. Fellows * unix/tclUnixThrd.c: Renamed the Tcl_Platform* #defines to * unix/tclUnixPipe.c: TclOS* because they are only used * unix/tclUnixFile.c: internally. Also stopped double-#def * unix/tclUnixFCmd.c: of TclOSlstat [Bug 566099, post-rename] * unix/tclUnixChan.c: * unix/tclUnixPort.h: * doc/string.n: Improved documentation for [string last] along lines described in [Bug 574799] so it indicates that the supplied index marks the end of the search space. 2002-06-27 Don Porter * doc/dde.n: Work in progress updating the documentation * doc/http.n: of the packages that come bundled with * doc/msgcat.n: the Tcl source distribution, notably tcltest. * doc/registry.n: * doc/tcltest.n: * library/tcltest/tcltest.tcl: Made sure that the TCLTEST_OPTIONS environment variablle configures tcltest at package load time. 2002-06-26 Vince Darley * tests/fileSystem.test: * generic/tclIOUtil.c: fix to handling of empty paths "" which are not claimed by any filesystem [Bug 573758]. Ensure good error messages are given in all cases. * tests/cmdAH.test: * unix/tclUnixFCmd.c: fix to bug reported as part of [Patch 566669]. Thanks to Taguchi, Takeshi for the report. 2002-06-26 Reinhard Max * unix/tclUnixTime.c: Make [clock format] respect locale settings. * tests/clock.test: [Bug 565880]. ***POTENTIAL INCOMPATIBILITY*** 2002-06-26 Miguel Sofer * doc/CrtInterp.3: * doc/StringObj.3: clarifications by Don Porter, [Bugs 493995, 500930] 2002-06-24 Don Porter * library/tcltest/tcltest.tcl: Corrected suppression of -verbose skip * tests/tcltest.test: and start by [test -output]. Also corrected test suite errors exposed by corrected code. [Bug 564656] 2002-06-25 Reinhard Max * unix/tcl.m4: New macro SC_CONFIG_MANPAGES. * unix/configure.in: Added support for symlinks and compression * unix/Makefile.in: when installing the manpages. [Patch 518052] * unix/mkLinks.tcl: Default is still hardlinks and no compression. * unix/mkLinks: generated * unix/configure: * unix/README: Added documentation for the new features. * unix/tcl.m4 (SC_PATH_TCLCONFIG): Replaced ${exec_prefix}/lib by ${libdir}. 2002-06-25 Donal K. Fellows * generic/tclUtil.c (TclGetIntForIndex): Fix of critical [Bug 533364] generated when the index is bad and the result is a shared object. The T_ASTO(T_GOR, ...) idiom likely exists elsewhere though. Also removed some cruft that just complicated things to no advantage. (SetEndOffsetFromAny): Same fix, though this wasn't on the path excited by the bug. 2002-06-24 Don Porter * library/tcltest/tcltest.tcl: Implementation of TIP 101. Adds * tests/parseOld.test: and exports a [configure] command * tests/tcltest.test: from tcltest. 2002-06-22 Don Porter * changes: updated changes file for 8.4b1 release. * library/tcltest/tcltest.tcl: Corrections to tcltest and the * tests/basic.test: Tcl test suite so that a test * tests/cmdInfo.test: with options -constraints knownBug * tests/compile.test: -limitConstraints 1 only tests the * tests/encoding.test: knownBug tests. Mostly involves * tests/env.test: replacing direct access to the * tests/event.test: testConstraints array with calls * tests/exec.test: to the testConstraint command * tests/execute.test: (which requires tcltest version 2) * tests/fCmd.test: * tests/format.test: * tests/http.test: * tests/httpold.test: * tests/ioUtil.test: * tests/link.test: * tests/load.test: * tests/namespace.test: * tests/pkgMkIndex.test: * tests/reg.test: * tests/result.test: * tests/scan.test: * tests/stack.test: 2002-06-22 Donal K. Fellows * tools/tcl.wse.in (Disk Label), unix/tcl.spec (version): * win/README.binary, README, win/configure.in, unix/configure.in: * generic/tcl.h (TCL_RELEASE_*, TCL_PATCH_LEVEL): Bump to beta1. 2002-06-21 Joe English * generic/tclCompExpr.c: * generic/tclParseExpr.c: LogSyntaxError() should reset the interpreter result [Bug 550142 "Tcl_ExprObj -> abort"] 2002-06-21 Don Porter * unix/Makefile.in: Updated all package install directories to * win/Makefile.in: match current Major.minor versions of the * win/makefile.bc: packages. Added tcltest package to * win/makefile.vc: installation on Windows. * library/init.tcl: Corrected comments and namespace style issues. Thanks to Bruce Stephens. [Bug 572025] 2002-06-21 Vince Darley * tests/cmdAH.test: Added TIP#99 implementation of 'file * tests/fCmd.test: link'. Supports creation of symbolic and * tests/fileName.test: hard links in the native filesystems and * tests/fileSystem.test: in vfs's, when the individual filesystem * generic/tclTest.c: supports the concept. * generic/tclCmdAH.c: * generic/tclIOUtil.c: * generic/tcl.h: * generic/tcl.decls: * doc/FileSystem.3: * doc/file.n: * mac/tclMacFile.c: * unix/tclUnixFile.c: * win/tclWinFile.c: Also enhanced speed of 'file normalize' on Windows 2002-06-20 Miguel Sofer * generic/tclBasic.c (TclEvalObjvInternal): fix for [Bug 571385] in the implementation of TIP#62 (command tracing). Vince Darley, Hemang Lavana & Don Porter: thanks. 2002-06-20 Miguel Sofer * generic/tclExecute.c (TclCompEvalObj): clarified and simplified the logic for compilation/recompilation. 2002-06-19 Joe English * doc/file.n: Fixed indentation. No substantive changes. 2002-06-19 Jeff Hobbs * generic/tclCmdMZ.c (Tcl_RegexpObjCmd): get the resultPtr again as the Tcl_ObjSetVar2 may cause the result to change. [Patch 558324] (watson) 2002-06-19 Miguel Sofer * generic/tclExecute.c (TEBC): removing unused "for(;;)" loop; improved comments; re-indentation. 2002-06-18 Miguel Sofer * generic/tclExecute.c (TEBC): - elimination of duplicated code in the non-immediate INST_INCR instructions. - elimination of 103 (!) TclDecrRefCount macros. The different instructions now jump back to a common "DecrRefCount zone" at the top of the loop. The macro "ADJUST_PC" was replaced by two macros "NEXT_INST_F" and "NEXT_INST_V" that take three params (pcAdjustment, # of stack objects to discard, resultObjPtr handling flag). The only instructions that retain a TclDecrRefCount are INST_POP (for speed), the common code for the non-immediate INST_INCR, INST_FOREACH_STEP and the two INST_LSET. The object size of tclExecute.o was reduced by approx 20% since the start of the consolidation drive, while making room for some peep-hole optimisation at runtime. 2002-06-18 Miguel Sofer * generic/tclExecute.c (TEBC, INST_DONE): small bug in the panic code for tcl-stack corruption. 2002-06-17 David Gravereaux Trims to support the removal of RESOURCE_INCLUDED from rc scripts from [FRQ 565088]. * generic/tcl.h: moved the #ifndef RC_INVOKED start block up in the file. rc scripts don't need to know thread mutexes. * win/tcl.rc: * win/tclsh.rc: removed the #define RESOURCE_INCLUDED to let the built-in -DRC_INVOKED to the work. 2002-06-17 Jeff Hobbs * doc/CrtTrace.3: Added TIP#62 implementation of command * doc/trace.n: execution tracing [FRQ 462580] (lavana). * generic/tcl.h: This includes enter/leave tracing as well * generic/tclBasic.c: as inter-procedure stepping. * generic/tclCmdMZ.c: * generic/tclCompile.c: * generic/tclExecute.c: * generic/tclInt.decls: * generic/tclInt.h: * generic/tclIntDecls.h: * generic/tclStubInit.c: * generic/tclVar.c: * tests/trace.test: 2002-06-17 Andreas Kupries * win/tclWinPipe.c (BuildCommandLine): Fixed [bug 554068] ([exec] on windows did not treat { in filenames well.). Bug reported by Vince Darley , patch provided by Vince too. 2002-06-17 Joe English * generic/tcl.h: #ifdef logic for K&R C backwards compatibility changed to assume modern C by default. See [FRQ 565088] for full details. 2002-06-17 Don Porter * doc/msgcat.n: Corrected en_UK references to en_GB. UK is not a country designation recognized in ISO 3166. * library/msgcat/msgcat.tcl: More Windows Registry locale codes from Bruno Haible. * doc/msgcat.n: * library/msgcat/msgcat.tcl: * library/msgcat/pkgIndex.tcl: * tests/msgcat.test: Revised locale initialization to interpret environment variable locale values according to XPG4, and to recognize the LC_ALL and LC_MESSAGES values over that of LANG. Also added many Windows Registry locale values to those recognized by msgcat. Revised tests and docs. Bumped to version 1.3. Thanks to Bruno Haible for the report and assistance crafting the solution. [Bug 525522, 525525] 2002-06-16 Miguel Sofer * generic/tclCompile.c (TclCompileTokens): a better algorithm for the previous bug fix. 2002-06-16 Miguel Sofer * generic/tclCompile.c (TclCompileTokens): * tests/compile.test: [Bug 569438] in the processing of dollar variables; report by Georgios Petasis. 2002-06-16 Miguel Sofer * generic/tclExecute.c: bug in the consolidation of the INCR_..._STK instructions; the bug could not be exercised as the (faulty) instruction INST_INCR_ARRAY_STK was never compiled-in (related to [Bug 569438]). 2002-06-14 Miguel Sofer * generic/tclExecute.c (TclExecuteByteCode): runtime peep-hole optimisation of variables (INST_STORE, INST_INCR) and commands (INST_INVOKE); faster check for the existence of a catch. (TclExecuteByteCode): runtime peep-hole optimisation of comparisons. (TclExecuteByteCode): runtime peep-hole optimisation of INST_FOREACH - relies on peculiarities of the code produced by the bytecode compiler. 2002-06-14 David Gravereaux * win/rules.vc: The test for compiler optimizations was in error. Thanks goes to Roy Terry for his assistance with this. 2002-06-14 Donal K. Fellows * doc/trace.n, tests/trace.test: * generic/tclCmdMZ.c (Tcl_TraceObjCmd,TclTraceCommandObjCmd) (TclTraceVariableObjCmd): Changed references to "trace list" to "trace info" as mandated by TIP#102. 2002-06-13 Miguel Sofer * generic/tclExecute.c (TclExecuteByteCode): consolidated code for the conditional branch instructions. 2002-06-13 Miguel Sofer * generic/tclExecute.c (TclExecuteByteCode): fixed the previous patch - wouldn't compile with TCL_COMPILE_DEBUG set. 2002-06-13 Miguel Sofer * generic/tclExecute.c (TclExecuteByteCode): consolidated the handling of exception returns to INST_INVOKE and INST_EVAL, as well as most of the code for INST_CONTINUE and INST_BREAK, in the new jump target "processExceptionReturn". 2002-06-13 Miguel Sofer * generic/tclExecute.c (TclExecuteByteCode): consolidated variable handling opcodes, replaced redundant code with some 'goto'. All store/append/lappend opcodes on the same data type now share the main code; same with incr opcodes. * generic/tclVar.c: added the bit TCL_TRACE_READS to the possible flags to Tcl_SetVar2Ex - it causes read traces to be fired prior to setting the variable. This is used in the core for [lappend]. ***NOTE*** the usage of TCL_TRACE_READS in Tcl_(Obj)?GetVar.* is not documented; there, it causes the call to create the variable if it does not exist. The new usage in Tcl_(Obj)?SetVar.* remains undocumented too ... 2002-06-13 Vince Darley * tests/fCmd.test: * tests/winFile.test: * tests/fileSystem.test: * generic/tclTest.c: * generic/tclCmdAH.c: * generic/tclIOUtil.c: * doc/FileSystem.3: * mac/tclMacFile.c: * unix/tclUnixFile.c: * win/tclWinFile.c: fixed up further so both compiles and actually works with VC++ 5 or 6. * win/tclWinInt.h: * win/tclWin32Dll.c: cleaned up code and vfs tests and added tests for the internal changes of 2002-06-12, to see whether WinTcl on NTFS can coexist peacefully with links in the filesystem. Added new test command 'testfilelink' to enable the newer code to be tested. * tests/fCmd.test: (made certain tests of 'testfilelink' not run on unix). 2002-06-12 Miguel Sofer * tclBasic.c (Tcl_DeleteTrace): fixed [Bug 568123] (thanks to Hemang Lavana) 2002-06-12 Jeff Hobbs * win/tclWinFile.c: corrected the symbolic link handling code to allow it to compile. Added real definition of REPARSE_DATA_BUFFER (found in winnt.h). Most of the added definitions appear to have correct, cross-Win-version equivalents in winnt.h and should be removed, but just making things "work" for now. 2002-06-12 Vince Darley * generic/tclIOUtil.c: * generic/tcl.decls: * generic/tclDecls.h: made code for Tcl_FSNewNativePath agree with man pages. * doc/FileSystem.3: clarified the circumstances under which certain functions are called in the presence of symlinks. * win/tclWinFile.c: * win/tclWinPort.h: * win/tclWinInt.h: * win/tclWinFCmd.c: Fix for Windows to allow 'file lstat', 'file type', 'glob -type l', 'file copy', 'file delete', 'file normalize', and all VFS code to work correctly in the presence of symlinks (previously Tcl's behaviour was not very well defined). This also fixes possible serious problems in all versions of WinTcl where 'file delete' on a NTFS symlink could delete the original, not the symlink. Note: symlinks cannot yet be created in pure Tcl. 2002-06-11 Miguel Sofer * generic/tclBasic.c: * generic/tclCompCmds.c: * generic/tclInt.h: reverted the new compilation functions; replaced by a more general approach described below. * generic/tclCompCmds.c: * generic/tclCompile.c: made *all* compiled variable access attempts create an indexed variable - even get or incr without previous set. This allows indexed access to local variables that are created and set at runtime, for example by [global], [upvar], [variable], [regexp], [regsub]. 2002-06-11 Miguel Sofer * doc/global.n: * doc/info.n: * test/info.test: * generic/tclCmdIL.c: fix for [Bug 567386], [info locals] was reporting some linked variables. * generic/tclBasic.c: * generic/tclCompCmds.c: * generic/tclInt.h: added compile functions for [global], [variable] and [upvar]. They just declare the new local variables, the commands themselves are not compiled-in. This gives a notably faster read access to these linked variables. 2002-06-11 Miguel Sofer * generic/tclExecute.c: optimised algorithm for exception range lookup; part of [Patch 453709]. 2002-06-10 Vince Darley * unix/tclUnixFCmd.c: fixed [Bug 566669] * generic/tclIOUtil.c: improved and sped up handling of native paths (duplication and conversion to normalized paths), particularly on Windows. * modified part of above commit, due to problems on Linux. Will re-examine bug report and evaluate more closely. 2002-06-07 Don Porter * tests/tcltest.test: More corrections to test suite so that tests of failing [test]s don't show up themselves as failing tests. 2002-06-07 Donal K. Fellows * generic/tclExecute.c: Tidied up headers in relation to float.h to cut the cruft and ensure DBL_MAX is defined since doubles seem to be the same size everywhere; if the assumption isn't true, the variant platforms had better have run configure... * unix/tclUnixPort.h (EOVERFLOW): Added code to define it if it wasn't previously defined. Also some other general tidying and adding of comments. [Bugs 563122, 564595] * compat/tclErrno.h: Added definition for EOVERFLOW copied from Solaris headers; I've been unable to find any uses of EFTYPE, which was the error code previously occupying the slot, in Tcl, or any definition of it in the Solaris headers. 2002-06-06 Mo DeJong * unix/dltest/Makefile.in: Remove hard coded CFLAGS=-g and add CFLAGS_DEBUG, CFLAGS_OPTIMIZE, and CFLAGS_DEFAULT varaibles. [Bug 565488] 2002-06-06 Don Porter * tests/tcltest.test: Corrections to test suite so that tests of failing [test]s don't show up themselves as failing tests. * tests/io.test: Fixed up namespace variable resolution issues revealed by running test suite with "-singleproc 1". * doc/tcltest.n: * library/tcltest/tcltest.tcl: * tests/tcltest.test: Several updates to tcltest. 1) changed to lazy initialization of test constraints 2) deprecated [initConstraintsHook] 3) repaired badly broken [limitConstraints]. 4) deprecated [threadReap] and [mainThread] [Patch 512214, Bug 558742, Bug 461000, Bug 534903] 2002-06-06 Daniel Steffen * unix/tclUnixThrd.c (TclpReaddir, TclpLocaltime, TclpGmtime): added mutex wrapped calls to readdir, localtime & gmtime in case their thread-safe *_r counterparts are not available. * unix/tcl.m4: added configure check for readdir_r * unix/tcl.m4 (Darwin): set TCL_DEFAULT_ENCODING to utf-8 on MacOSX (where posix file apis expect utf-8, not iso8859-1). * unix/configure: regen * unix/Makefile.in: set DYLD_LIBRARY_PATH in parallel to LD_LIBRARY_PATH for MacOSX dynamic linker. * generic/tclEnv.c (TclSetEnv): fix env var setting on MacOSX. Adapted from [Patch 524352] (jkbonfield). 2002-06-05 Don Porter * doc/Tcl_Main.3: Documented $tcl_rcFileName and added more clarifications about the intended use of Tcl_Main(). [Bug 505651] 2002-06-05 Daniel Steffen * generic/tclFileName.c (TclGlob): mac specific fix to recent changes in 'glob -tails' handling. * mac/tclMacPort.h: * mac/tclMacChan.c: fixed TIP#91 bustage. * mac/tclMacResource.c (Tcl_MacConvertTextResource): added utf conversion of text resource contents. * tests/macFCmd.test (macFCmd-1.2): allow CWIE creator. 2002-06-04 Don Porter * library/tcltest/tcltest.tcl: * tests/init.test: * tests/tcltest.test: Added more TIP 85 tests from Arjen Markus. Converted tcltest.test to use a private namespace. Fixed bugs in [tcltest::Eval] revealed by calling [tcltest::test] from a non-global namespace, and namespace errors in init.test. 2002-06-04 Mo DeJong * win/README: Update msys+mingw URL. 2002-06-03 Don Porter * doc/tcltest.n: * library/tcltest/tcltest.tcl: * library/tcltest/pkgIndex.tcl: * tests/tcltest.test: Implementation of TIP 85. Allows tcltest users to add new legal values of the -match option to [test], associating each with a Tcl command that does the matching of expected results with actual results of tests. Thanks to Arjen Markus. => tcltest 2.1 [Patch 521362] 2002-06-03 Miguel Sofer * doc/namespace.n: added description of [namepace forget] behaviour for unqualified patterns [Bug 559268] 2002-06-03 Miguel Sofer * generic/tclExecute.c: reverting an accidental modification in the last commit. 2002-06-03 Miguel Sofer * doc/Tcl.n: clarify the empty variable name issue ([Bug 549285] reported by Tom Krehbiel, patch by Don Porter). 2002-05-31 Don Porter * library/package.tcl: Fixed leak of slave interp in [pkg_mkIndex]. Thanks to Helmut for report. [Bug 550534] * tests/io.test: * tests/main.test: Use the "stdio" constraint to control whether an [open "|[interpreter]"] is attempted. * generic/tclExecute.c (TclMathInProgress,TclExecuteByteCode (ExprCallMathFunc): * generic/tclInt.h (TclMathInProgress): * unix/Makefile.in (tclMtherr.*): * unix/configure.in (NEED_MATHERR): * unix/tclAppInit.c (matherr): * unix/tclMtherr.c (removed file): * win/tclWinMtherr.c (_matherr): Removed internal routine TclMathInProgress and Unix implementation of matherr(). These are now obsolete, dealing with very old versions of the C math library. Windows version is retained in case Borland compilers require it, but it is inactive. Thanks to Joe English. [Bug 474335, Patch 555635] * unix/configure: regen 2002-05-30 Miguel Sofer * generic/tclCompExpr.c: * generic/tclCompile.c: * generic/tclCompile.h: removed exprIsJustVarRef and exprIsComparison from the ExprInfo and CompileEnv structs. These were set, but not used since dec 1999 [Bug 562383]. 2002-05-30 Vince Darley * generic/tclFileName.c (TclGlob): fix to longstanding 'knownBug' in fileName tests 15.2-15.4, and fix to a new Tcl 8.4 bug in certain uses of 'glob -tails'. * tests/fileName.test: removed 'knownBug' flag from some tests, added some new tests for above bugs. 2002-05-29 Jeff Hobbs * unix/configure: regen'ed * unix/configure.in: replaced bigendian check with autoconf standard AC_C_BIG_ENDIAN, which defined WORDS_BIGENDIAN on bigendian systems. * generic/tclUtf.c (Tcl_UniCharNcmp): * generic/tclInt.h (TclUniCharNcmp): use WORDS_BIGENDIAN instead of TCL_OPTIMIZE_UNICODE_COMPARE to enable memcmp alternative. * generic/tclExecute.c (TclExecuteByteCode INST_STR_CMP): * generic/tclCmdMZ.c (Tcl_StringObjCmd): changed the case for choosing the Tcl_UniCharNcmp compare to when both objs are of StringType, as benchmarks show that is the optimal check (both bigendian and littleendian systems). 2002-05-29 Don Porter * generic/tclMain.c: Removed "dummy" reference to Tcl_LinkVar. It is no longer needed since Tcl_Main() now actually calls Tcl_LinkVar(). Thanks to Joe English for pointing that out. 2002-05-29 Donal K. Fellows * generic/tclExecute.c (TclExecuteByteCode): * generic/tclCmdMZ.c (Tcl_StringObjCmd): Use the macro version. * generic/tclInt.h (TclUniCharNcmp): Optimised still further with a macro for use in sensitive places like tclExecute.c * generic/tclUtf.c (Tcl_UniCharNcmp): Use new flag to figure out when we can use an optimal comparison scheme, and default to the old scheme in other cases which is at least safe. * unix/configure.in (TCL_OPTIMIZE_UNICODE_COMPARE): New optional flag that indicates when we can use memcmp() to compare Unicode strings (i.e. when the high-byte of a Tcl_UniChar precedes the low-byte.) 2002-05-29 Jeff Hobbs * generic/tclInt.decls: * generic/tclIntDecls.h: * generic/tclStubInit.c: * generic/tclUtf.c: added TclpUtfNcmp2 private command that mirrors Tcl_UtfNcmp, but takes n in bytes, not utf-8 chars. This provides a faster alternative for comparing utf strings internally. (Tcl_UniCharNcmp, Tcl_UniCharNcasecmp): removed the explicit end of string check as it wasn't correct for the function (by doc and logic). * generic/tclCmdMZ.c (Tcl_StringObjCmd): reworked the string equal comparison code to use TclpUtfNcmp2 as well as short-circuit for equal objects or unequal length strings in the equal case. Removed the use of goto and streamlined the other parts. * generic/tclExecute.c (TclExecuteByteCode): added check for object equality in the comparison instructions. Added short-circuit for != length strings in INST_EQ, INST_NEQ and INST_STR_CMP. Reworked INST_STR_CMP to use TclpUtfNcmp2 where appropriate, and only use Tcl_UniCharNcmp when at least one of the objects is a Unicode obj with no utf bytes. * generic/tclCompCmds.c (TclCompileStringCmd): removed error creation in code that no longer throws an error. * tests/string.test: * tests/stringComp.test: added more string comparison checks. * tests/clock.test: better qualified 9.1 constraint check for %s. 2002-05-28 Jeff Hobbs * generic/tclThreadAlloc.c (TclpRealloc, TclpFree): protect against the case when NULL is based. * tests/clock.test: added clock-9.1 * compat/strftime.c: * generic/tclClock.c: * generic/tclInt.decls: * generic/tclIntDecls.h: * unix/tclUnixTime.c: fix for Windows msvcrt mem leak caused by using an env(TZ) setting trick for in clock format -gmt 1. This also makes %s seem to work correctly with -gmt 1 as well as making it a lot faster by avoid the env(TZ) hack. TclpStrftime now takes useGMT as an arg. [Bug 559376] 2002-05-28 Vince Darley * generic/tclIOUtil.c: fixes to Tcl_FSLoadFile when called on a file inside a vfs. This should avoid leaving temporary files sitting around on exit. [Bug 545579] 2002-05-27 Donal K. Fellows * win/tclWinError.c: Added comment on conversion of ERROR_NEGATIVE_SEEK because that is a mapping that really belongs, and not a catch-all case. * win/tclWinPort.h (EOVERFLOW): Should be either EFBIG or EINVAL * generic/tclPosixStr.c (Tcl_ErrnoId, Tcl_ErrnoMsg): EOVERFLOW can potentially be a synonym for EINVAL. 2002-05-24 Donal K. Fellows === Changes due to TIP#91 === * win/tclWinPort.h: Added declaration of EOVERFLOW. * doc/CrtChannel.3: Added documentation of wideSeekProc. * generic/tclIOGT.c (TransformSeekProc, TransformWideSeekProc): Adapted to use the new channel mechanism. * unix/tclUnixChan.c (FileSeekProc, FileWideSeekProc): Renamed FileSeekProc to FileWideSeekProc and created new FileSeekProc which has the old-style interface and which errors out with EOVERFLOW when the returned file position can't fit into the return type (int for historical reasons.) * win/tclWinChan.c (FileSeekProc, FileWideSeekProc): Renamed FileSeekProc to FileWideSeekProc and created new FileSeekProc which has the old-style interface and which errors out with EOVERFLOW when the returned file position can't fit into the return type (int for historical reasons.) * mac/tclMacChan.c (FileSeek): Reverted to old interface; Macs lack large-file support because I can't see how to add it. * generic/tclIO.c (Tcl_Seek, Tcl_Tell): Given these functions knowledge of the new arrangement of channel types. (Tcl_ChannelVersion): Added recognition of new version code. (HaveVersion): New function to do version checking. (Tcl_ChannelBlockModeProc, Tcl_ChannelFlushProc) (Tcl_ChannelHandlerProc): Made these functions use HaveVersion for ease of future maintainability. (Tcl_ChannelBlockModeProc): Obvious lookup function. * generic/tcl.h (Tcl_ChannelType): New wideSeekProc field, and seekProc type restored to old interpretation. (TCL_CHANNEL_VERSION_3): New channel version. 2002-05-24 Andreas Kupries * tests/winPipe.test: Applied patch for [Bug 549617]. Patch and bug report by Kevin Kenny . * win/tclWinSock.c (TcpWatchProc): Fixed [Bug 557878]. We are not allowed to mess with the watch mask if the socket is a server socket. I believe that the original reporter is George Peter Staplin. 2002-05-21 Mo DeJong * unix/configure: Regen. * unix/configure.in: Invoke SC_ENABLE_SHARED before calling SC_CONFIG_CFLAGS so that the SHARED_BUILD variable can be checked inside SC_CONFIG_CFLAGS. * unix/tcl.m4 (SC_CONFIG_CFLAGS): Pass -non_shared instead of -shared to ld when configured with --disable-shared under OSF. [Bug 540390] 2002-05-20 Daniel Steffen * generic/tclInt.h: added prototype for TclpFilesystemPathType(). * mac/tclMacChan.c: use MSL provided creator type if available instead of the default 'MPW '. 2002-05-16 Joe English * doc/CrtObjCmd.3: Added Tcl_GetCommandFromObj, Tcl_GetCommandFullName [Bugs 547987, 414921] 2002-05-14 Donal K. Fellows * unix/tclUnixChan.c (TtyOutputProc): #if/#endif-ed this function out to stop compiler warnings. Also much general tidying of comments in this file and removal of whitespace from blank lines. 2002-05-13 Donal K. Fellows * unix/tclUnixChan.c (SETBREAK): Solaris thinks ioctl() takes a signed second argument, and Linux thinks ioctl() takes an unsigned second argument. So need a longer definition of this macro to get neither to spew warnings... 2002-05-13 Vince Darley * generic/tclEvent.c: * generic/tclIOUtil.c: * generic/tclInt.h: clean up all memory allocated by the filesystem, via introduction of 'TclFinalizeFilesystem'. Move TclFinalizeLoad into TclFinalizeFilesystem so we can be sure it is called at just the right time. Fix bad comment also. [Bug 555078 and 'fs' part of 543549] * win/tclWinChan.c: fix comment referring to wrong function. 2002-05-10 Don Porter * tests/load.test: * tests/safe.test: * tests/tcltest.test: Corrected some list-quoting issues and other matters that cause tests to fail when the patch includes special characters. Report from Vince Darley. [Bug 554068]. 2002-05-08 David Gravereaux * doc/file.n: * tools/man2tcl.c: * tools/man2help2.tcl: Thanks to Peter Spjuth , again. My prior fix for single-quote macro mis-understanding was wrong. Reverted to reimpliment the 'macro2' proc which handles single-quote macros and restored file.n text arrangement to avoid single-quotes on the first line. Sorry for all the confusion. 2002-05-08 David Gravereaux * tools/man2tcl.c: * tools/man2help2.tcl: Proper source of macro error mis-understanding single-quote as the leading macro command found and repaired. * doc/file.n: Reverted to prior state before I messed with it. 2002-05-08 Don Porter * library/tcltest/tcltest.tcl: Corrected [uplevel] quoting when [source]-ing test script in subdirectories. * tests/fileName.test: * tests/load.test: * tests/main.test: * tests/tcltest.test: * tests/unixInit.test: Fixes to test suite when there's a space in the working path. Thanks to Kevin Kenny. 2002-05-07 David Gravereaux -- Changes from Peter Spjuth * tools/man2tcl.c: Increased line buffer size and a bail-out if that should ever be over-run. * tools/man2help.tcl: Include Courier New font in rtf header. * tools/man2help2.tcl: Improved handling of CS/CE fields. Use Courier New for code samples and indent better. * doc/file.n: * doc/TraceCmd.3: winhelp conversion tools where understanding a ' as the first character on a line to be an unknown macro. Not knowing how to repair tools/man2tcl.c, I decided to rearrange the text in the docs instead. 2002-05-07 Vince Darley * generic/tclFileName.c: fix to similar segfault when using 'glob -types nonsense -dir dirname -join * *'. [Bug 553320] * doc/FileSystem.3: further documentation on vfs. * tests/cmdAH.test: * tests/fileSystem.test: * tests/pkgMkindex.test: Fix to testsuite bugs when running out of directory whose name contains '{' or '['. 2002-05-07 Miguel Sofer * tests/basic.test: Fix for [Bug 549607] * tests/encoding.test: Fix for [Bug 549610] These are testsuite bugs that caused failures when the filename contained spaces. Report & fix by Kevin Kenny. 2002-05-02 Vince Darley * generic/tclFileName.c: fix to freeing a bad object (i.e. segfault) when using 'glob -types nonsense -dir dirname'. * generic/tclWinFile.c: fix to [Bug 551306], also wrapped some long lines. * tests/fileName.test: added several tests for the above bugs. * doc/FileSystem.3: clarified documentation on refCount requirements of the object returned by the path type function. * generic/tclIOUtil.c: * win/tclWinFile.c: * unix/tclUnixFile.c: * mac/tclMacFile.c: moved TclpFilesystemPathType to the platform specific directories, so we can add missing platform-specific implementations. On Windows, 'file system' now returns useful results like "native NTFS", "native FAT" for that system. Unix and MacOS still only return "native". * doc/file.n: clarified documentation. * tests/winFile.test: test for 'file system' returning correct values. * tests/fileSystem.test: test for 'file system' returning correct values. Clean up after failed previous test run. 2002-04-26 Jeff Hobbs * unix/configure: * unix/tcl.m4: change HP-11 SHLIB_LD_LIBS from "" to ${LIBS} so that the .sl knows its dependent libs. 2002-04-26 Donal K. Fellows * tests/obj.test (obj-11.[56]): Test conversion to boolean more thoroughly. * generic/tclObj.c (SetBooleanFromAny): Was not calling an integer parsing function on native 64-bit platforms! [Bug 548686] 2002-04-24 Jeff Hobbs * generic/tclInt.h: corrected TclRememberJoinableThread decl to use VOID instead of void. * generic/tclThreadJoin.c: noted that this code isn't needed on Unix. 2002-04-23 Jeff Hobbs * doc/exec.n: * doc/tclvars.n: doc updates [Patch 509426] (gravereaux) 2002-04-24 Daniel Steffen * mac/tclMacResource.r: added check of TCLTK_NO_LIBRARY_TEXT_RESOURCES #define to allow disabling the inclusion of the tcl library code in the resource fork of Tcl executables and shared libraries. 2002-04-23 Donal K. Fellows * doc/TraceCmd.3: New file that documents Tcl_CommandTraceInfo, Tcl_TraceCommand and Tcl_UntraceCommand [Bug 414927] 2002-04-22 Jeff Hobbs * generic/tclAlloc.c: * generic/tclInt.h: * generic/tclThreadAlloc.c (new): * unix/Makefile.in: * unix/tclUnixThrd.c: * win/Makefile.in: * win/tclWinInt.h: * win/tclWinThrd.c: added new threaded allocator contributed by AOL that significantly reduces lock contention when multiple threads are in use. Only Windows and Unix implementations are ready, and the Windows one may need work. It is only used by default on Unix for now, and requires that USE_THREAD_ALLOC be defined (--enable-threads on Unix will define this). * generic/tclIOUtil.c (Tcl_FSRegister, Tcl_FSUnregister): corrected calling of Tcl_ConditionWait to ensure that there would be a condition to wait upon. * generic/tclCmdAH.c (Tcl_FileObjCmd): added cast in FILE_SIZE. * win/tclWinFCmd.c (DoDeleteFile): check return of setattr API calls in file deletion for correct Win32 API handling. * win/Makefile.in: correct dependencies for shell, gdb, runtest targets. * doc/clock.n: * compat/strftime.c (_fmt): change strftime to correctly handle localized %c, %x and %X on Windows. Added some notes about how the other values could be further localized. 2002-04-19 Don Porter * generic/tclMain.c (Tcl_Main): Free the memory allocated for the startup script path. [Bug 543549] * library/msgcat/msgcat.tcl: [mcmax] wasn't using the caller's namespace when determining the max translated length. Also made revisions for better use of namespace variables and more efficient [uplevel]s. * doc/msgcat.n: * library/msgcat/msgcat.tcl: * library/msgcat/pkgIndex.tcl: Added [mcload] to the export list of msgcat; bumped to 1.2.3. [Bug 544727] 2002-04-20 Daniel Steffen * generic/tclInt.decls: * generic/tclIntPlatDecls.h: * generic/tclStubInit.c: * mac/tclMacFCmd.c: * mac/tclMacFile.c: * mac/tclMacUtil.c: Modified TclpObjNormalizePath to be alias file aware, and replaced various calls to FSpLocationFrom*Path by calls to new alias file aware versions FSpLLocationFrom*Path. The alias file aware routines don't resolve the last component of a path if it is an alias. This allows [file copy/delete] etc. to act correctly on alias files. (c.f. discussion in [Bug 511666]) 2002-04-19 Donal K. Fellows * tests/lindex.test (lindex-3.7): * generic/tclUtil.c (TclGetIntForIndex): Stopped indexes from hitting wide ints. [Bug 526717] 2002-04-18 Miguel Sofer * generic/tclNamesp.c: * tests/info.test: [Bug 545325] info level didn't report namespace eval, bug report by Richard Suchenwirth. 2002-04-18 Don Porter * doc/subst.n: Clarified documentation on handling unusual return codes during substitution, and on variable substitutions implied by command substitution, and vice versa. [Bug 536838] 2002-04-18 Donal K. Fellows * generic/tclCmdIL.c (InfoBodyCmd): * tests/info.test (info-2.6): Proc bodies without string reps would report as empty [Bug 545644] * generic/tclCmdMZ.c (Tcl_SubstObj): More clarification for comment on behaviour when substitutions are not well-formed, prompted by [Bug 536831]; alas, removing the ill-defined behaviour is a lot of work. 2002-04-18 Miguel Sofer * generic/tclExecute.c: * tests/expr-old.test: fix for [Bug 542588] (Phil Ehrens), where "too large integers" were reported as "floating-point value" in [expr] error messages. 2002-04-17 Jeff Hobbs * generic/tclEncoding.c (EscapeFromUtfProc): * generic/tclIO.c (WriteChars, Tcl_Close): corrected the handling of outputting end escapes for escape-based encodings. [Bug 526524] (yamamoto) 2002-04-17 Don Porter * doc/tcltest.n: Removed [saveState] and [restoreState] from tcltest 2 documentation, effectively deprecating them. [Bug 495660] * library/tcltest/tcltest.tcl: Made separate export for commands kept only for tcltest 1 compatibility. * tests/iogt.test: Revised to run tests in a namespace, rather than use the useless and buggy [saveState] and [restoreState] commands of tcltest. Updated to use tcltest 2 as well. [Patch 544911] 2002-04-16 Don Porter * tests/io.test: Revised to run tests in a namespace, rather than use the useless and buggy [saveState] and [restoreState] commands of tcltest. Updated to use tcltest 2 as well. [Patch 544546] 2002-04-15 Miguel Sofer * generic/tclProc.c: * tests/proc-old.test: Improved stack trace for TCL_BREAK and TCL_CONTINUE returns from procs. [Bug 536955] (dgp) * generic/tclExecute.c: * tests/compile.test: made bytecodes check for a catch before returning; the compiled [return] is otherwise non-catchable. [Bug 542142] reported by Andreas Kupries. 2002-04-15 Don Porter * tests/socket.test: Increased timeout values so that tests have time to successfully complete even on slow/busy machines. [Bug 523470] * doc/tcltest.n: * library/tcltest/tcltest.tcl: * tests/tcltest.test: Revised [tcltest::test] to return errors when called with invalid syntax and to accept exactly two arguments as documented. Improved error messages. [Bug 497446, Patch 513983] ***POTENTIAL INCOMPATIBILITY***: Incompatible with previous tcltest 2.* releases, found only in alpha releases of Tcl 8.4. 2002-04-11 Jeff Hobbs * generic/tclNotify.c (TclFinalizeNotifier): remove remaining unserviced events on finalization. * win/tcl.m4: Enabled COFF as well as CV style debug info with --enable-symbols to allow Dr. Watson users to see function info. More info on debugging levels can be obtained at: http://msdn.microsoft.com/library/en-us/dnvc60/html/gendepdebug.asp * tests/ioCmd.test: fixed iocmd-8.15 to have mac and unixPc variants. * generic/tclParse.c (Tcl_ParseVar): conditionally incr obj refcount to prevent possible mem leak. 2002-04-08 Daniel Steffen * generic/tcl.h: no on mac. * mac/tclMacFile.c: minor fixes to Vince's changes from 03-24. * mac/tclMacOSA.c: * mac/tclMacResource.c: added missing Tcl_UtfToExternalDString conversions of resource file names. * mac/tclMacSock.c (TcpGetOptionProc): fixed bug introduced by Andreas on 02-25; changed strcmp's to strncmp's so that option comparison behaves like on other platforms. * mac/tcltkMacBuildSupport.sea.hqx (CW Pro6 changes): added support to allow Tk to hookup C library stderr/stdout to TkConsole. * tests/basic.test: * tests/cmdAH.test: * tests/encoding.test: * tests/fileSystem.test: * tests/ioCmd.test: fixed tests failing on mac: check for existence of [exec], changed some result strings. 2002-04-06 Jeff Hobbs * unix/tclUnixFCmd.c (Realpath): added a little extra code to initialize a realpath arg when compiling in PURIFY mode in order to prevent spurious purify warnings. We should really create our own realpath implementation, but this will at least quiet purify for now. 2002-04-05 Don Porter * generic/tclCmdMZ.c (Tcl_SubstObj): * tests/subst.test: Corrected [subst] so that return codes TCL_BREAK and TCL_CONTINUE returned by variable substitution have the same effect as when those codes are returned by command substitution. [Bug 536879] 2002-04-03 Jeff Hobbs * library/tcltest/tcltest.tcl: added getMatchingFiles back (alias to GetMatchingFiles), which was a public function in tcltest 1.0. 2002-04-01 Vince Darley * generic/tclEnv.c: * generic/tclIOUtil.c: invalidate filesystem cache when the user changes env(HOME). Fixes [Bug 535621]. Also cleaned up some of the documentation. * tests/fileSystem.test: added test for bug just fixed. 2002-04-01 Kevin Kenny * win/tclWinTime.c (Tcl_GetTime): made the checks of clock frequency more permissive to cope with the fact that Win98SE is observed to return 1.19318 in place of 1.193182 for the performance counter frequency. 2002-03-29 Jeff Hobbs * generic/tclCmdMZ.c (Tcl_TraceObjCmd, TraceVarProc) (TraceCommandProc, TclTraceCommandObjCmd): corrected potential double-free of traces on variables by flagging in Trace*Proc that it will free the var in case the eval wants to delete the var trace as well. [Bug 536937] Also converted Tcl_UntraceVar -> Tcl_UntraceVar2 and Tcl_Eval to Tcl_EvalEx in Trace*Proc for slight efficiency improvement. 2002-03-29 Don Porter * doc/AllowExc.3: * generic/tclBasic.c (Tcl_EvalObjv,Tcl_EvalEx,Tcl_EvalObjEx): * generic/tclCompile.h (TclCompEvalObj): * generic/tclExecute.c (TclCompEvalObj,TclExecuteByteCode): * tests/basic.test: Corrected problems with Tcl_AllowExceptions having influence over the wrong scope of Tcl_*Eval* calls. Patch from Miguel Sofer. Report from Jean-Claude Wippler. [Bug 219181] 2002-03-28 Don Porter * generic/tclVar.c: Refactored CallTraces to collect repeated handling of its returned value into CallTraces itself. 2002-03-28 David Gravereaux * tools/feather.bmp: * tools/man2help.tcl: * tools/man2help2.tcl: * win/makefile.vc: More winhelp target fixups. Added a feather bitmap to the non-scrollable area and changed the color to be yellow from a plain white. The colors can be whatever we want them to be, but thought I would start with something bold. [Bug 527941] * doc/SetVar.3: * doc/TraceVar.3: * doc/UpVar.3: .AP macro syntax repair. 2002-03-27 David Gravereaux * tools/man2help.tcl: * win/makefile.vc: winhelp target now copies all needed files from tools/ to a workarea under $(OUT_DIR) and builds it from there. No build cruft is left in tools/ anymore. All paths used in man2help.tcl are now relative to where the script is. [Bug 527941] 2002-03-27 David Gravereaux * win/.cvsignore: * win/buildall.vc.bat: * win/coffbase.txt: * win/makefile.vc: * win/nmakehlp.c (new): * win/rules.vc: First draft fix for [Bug 527941]. More changes need to done to the makehelp target to get to stop leaving build files in the tools/ directory. This does not address the syntax errors in the man files. Having the contents of tcl.hpj(.in) inside makefile.vc allows for version numbers to be replaced with macros. The new nmakehlp.c is built by rules.vc in preprocessing and removes the need to use tricky shell syntax that wasn't compatible on Win9x systems. Clean targets made Win9x complient. This is a first draft repair for [Bug 533862]. 2002-03-28 Miguel Sofer * generic/tclBasic.c (Tcl_EvalEx): passing the correct commandSize to TclEvalObjvInternal. [Bug 219362], fix by David Knoll. 2002-03-28 Miguel Sofer * generic/tclBasic.c (Tcl_EvalEx): * tests/basic.test: avoid exceptional returns at level 0 [Bug 219181] 2002-03-27 Don Porter * doc/tcltest.n ([mainThread]): * library/tcltest/tcltest.tcl: * tests/tcltest.test: Major code cleanup to deal with whitespace, coding conventions, and namespace issues, with several minor bugs fixed in the process. * tests/main.test: Added missing [after cancel]s. 2002-03-25 Don Porter * tests/main.test: Removed workarounds for Bug 495977. * library/tcltest/tcltest.tcl: Keep the value of $::auto_path unchanged, so that the tcltest package can test code that depends on auto-loading. If a testing application needs $::auto_path pruned, it should do that itself. [Bug 495726] Improve the processing of the -constraints option to [test] so that constraint lists can have arbitrary whitespace, and non-lists don't blow things up. [Bug 495977] Corrected faulty variable initialization. [Bug 534845] 2002-03-25 Miguel Sofer * doc/CrtTrace.3: small doc correction * generic/tclBasic.c (Tcl_DeleteTrace): Allow NULL callback on trace deletions [Bug 534728] (Hemang Lavana). 2002-03-24 Miguel Sofer * generic/tclBasic.c (Tcl_EvalObjv): replaced obscure, incorrect code as described in [Bug 533907] (Don Porter). 2002-03-24 Don Porter * library/tcltest/tcltest.tcl: Use [interpreter] to set/query the executable currently running the tcltest package. [Bug 454050] * library/tcltest/tcltest.tcl: Allow non-proc commands to be used as the customization hooks. [Bug 495662] 2002-03-24 Vince Darley * generic/tclFilename.c: * generic/tclFCmd.c: * generic/tclTest.c: * generic/tcl.h: * generic/tclIOUtil.c: * win/tclWinFile.c: * win/tclWinFCmd.c: * win/tclWinPipe.c: * unix/tclUnixFile.c: * unix/tclUnixFCmd.c: * mac/tclMacFile.c: * doc/FileSystem.3: * doc/file.n: * tests/cmdAH.test: * tests/fileName.test: * tests/fileSystem.test: (new file) * tests/winFCmd.test: fix [Bug 511666] and [Bug 511658], and improved documentation of some aspects of the filesystem, particularly 'Tcl_FSMatchInDirectory' which now might match a single file/directory only, and 'file normalize' which wasn't very clear before. Removed inconsistency betweens docs and the Tcl_Filesystem structure. Also fixed [Bug 523217] and corrected file normalization on Unix so that it expands symbolic links. Added some new tests of the filesystem code (in the new file 'fileSystem.test'), and some extra tests for correct handling of symbolic links. Fix to [Bug 530960] which shows up on Win98. Made comparison with ".com" case insensitive in tclWinPipe.c ***POTENTIAL INCOMPATIBILITY***: But only between alpha releases (users of the new Tcl_Filesystem lookup table in Tcl 8.4a4 need to handle the new way in which Tcl may call Tcl_FSMatchInDirectory, and 'file normalize' on unix now behaves correctly). Only known impact is with the 'tclvfs' extension. 2002-03-22 Miguel Sofer * tests/basic.test (basic-46.1): adding test for [Bug 533758], fixed earlier today. 2002-03-22 Jeff Hobbs * win/tclWinInt.h: moved undef of TCL_STORAGE_CLASS. [Bug 478579] 2002-03-22 Miguel Sofer * generic/tclBasic.c (Tcl_EvalObjEx): * generic/tclExecute.c (TclCompEvalObj): fixed the errorInfo for return codes other than (TCL_OK, TCL_ERROR) to runLevel 0 [Bug 533758]. Removed the static RecordTracebackInfo(), as its functionality is easily replicated by Tcl_LogCommandInfo. Bug and redundancy noted by Don Porter. 2002-03-21 Donal K. Fellows * doc/expr.n: Improved documentation for ceil and floor [Bug 530535] 2002-03-20 Don Porter * doc/SetVar.3: * doc/TraceVar.3: * doc/UpVar.3: * generic/tcl.h (Tcl_VarTraceProc): * generic/tcl.decls (Tcl_GetVar2, Tcl_SetVar2, Tcl_TraceVar2) (Tcl_UnsetVar2, Tcl_UntraceVar2, Tcl_UpVar2, Tcl_VarTraceInfo2) (Tcl_GetVar2Ex, TclSetVar2Ex): * generic/tclCmdMZ.c (TraceVarProc): * generic/tclEnv.c (EnvTraceProc): * generic/tclEvent.c (VwaitVarProc): * generic/tclInt.decls (TclLookupVar,TclPrecTraceProc): * generic/tclLink.c (LinkTraceProc): * generic/tclUtil.c (TclPrecTraceProc): * generic/tclVar.c (CallTraces, MakeUpvar, VarErrMsg, TclLookupVar, (Tcl_GetVar2, Tcl_SetVar2, Tcl_TraceVar2, Tcl_UnsetVar2) (Tcl_UntraceVar2, Tcl_UpVar2, Tcl_VarTraceInfo2, Tcl_GetVar2Ex) (TclSetVar2Ex): Updated interfaces of generic/tclVar.c according to TIP 27. In particular, the "part2" arguments were CONSTified. [Patch 532642] * generic/tclDecls.h: * generic/tclIntDecls.h: make genstubs 2002-03-15 Donal K. Fellows * tests/compile.test (compile-12.3): Test to detect bug 530320. * generic/tclCompile.c (TclCompileTokens): Fixed buffer overrun reported in bug 530320. 2002-03-14 Mo DeJong * win/configure: Regen. * win/configure.in: Add configure time test for SEH support in the compiler. * win/tclWin32Dll.c (ESP, EBP, TclpCheckStackSpace, (_except_checkstackspace_handler): * win/tclWinChan.c (ESP, EBP, Tcl_MakeFileChannel, (_except_makefilechannel_handler): * win/tclWinFCmd.c (ESP, EBP, DoRenameFile, DoCopyFile, (_except_dorenamefile_handler, _except_docopyfile_handler): Implement SEH support under gcc using inline asm. Tcl and Tk should now compile with Mingw 1.1. [Patch 525746] 2002-03-14 Mo DeJong * win/tclWinFCmd.c (DoRenameFile, DoCopyFile): Handle an SEH exception with EXCEPTION_EXECUTE_HANDLER instead of restarting the faulting instruction with EXCEPTION_CONTINUE_EXECUTION. Bug 466102 provides an example of how restarting could send Tcl into an infinite loop. [Patch 525746] 2002-03-11 Mo DeJong * win/tclWinFCmd.c (DoRenameFile, DoCopyFile, DoDeleteFile, (DoRemoveJustDirectory): Make sure we don't pass NULL or "" as a path name to Win32 API functions since this was crashing under Windows 98. 2002-03-11 Don Porter * library/tcltest/tcltest.tcl: * library/tcltest/pkgIndex.tcl: Bumped tcltest package to 2.0.2. 2002-03-11 Mo DeJong * library/tcltest/tcltest.tcl (getMatchingFiles): Pass a proper list to foreach to avoid munging a Windows patch like D:\Foo\Bar into D:FooBar before the glob. 2002-03-11 Mo DeJong * generic/tclEncoding.c: Fix typo in comment. * generic/tclIO.c (DoReadChars, ReadBytes, ReadChars): Use NULL value instead of pointer set to NULL to make things more clear. Reorder arguments so that they match the function signatures. Cleanup little typos and add more descriptive comment. 2002-03-08 Mo DeJong * win/README: Update to indicate that Mingw 1.1 is required to build Tcl. Add section describing new msys based build process. Update Cygwin build instructions so users know where to find Mingw 1.1. 2002-03-08 Jeff Hobbs * win/tclWinFCmd.c (DoCopyFile): correctly set retval to TCL_OK. 2002-03-07 Mo DeJong * win/tclWin32Dll.c (TclpCheckStackSpace): * win/tclWinFCmd.c (DoRenameFile, DoCopyFile): Replace hard coded constants with Win32 symbolic names. Move control flow statements out of __try blocks since the documentation indicates it is frowned upon. 2002-03-07 Don Porter * doc/interp.n: * generic/tclInterp.c (Tcl_InterpObjCmd,SlaveObjCmd, (SlaveRecursionLimit): * generic/tclTest.c: * tests/interp.test: Added the [interp recursionlimit] command to set/query the recursion limit of an interpreter. Proposal and implementation from Stephen Trier. [TIP 87, Patch 522849] 2002-03-06 Donal K. Fellows * generic/tcl.h, tools/tcl.wse.in, unix/configure.in, * unix/tcl.spec, win/README.binary, win/configure.in, README: Bumped patchlevel; this might need to change in the future, but it will help us distinguish between the CVS version and the most recent released version. 2002-03-06 Miguel Sofer * generic/tclInt.h: for unshared objects, TclDecrRefCount now frees the internal rep before the string rep - just like the non-macro Tcl_DecrRefCount/TclFreeObj [Bug 524802]. 2002-03-06 Donal K. Fellows * doc/lsearch.n: Documentation of new features, plus examples. * tests/lsearch.test: Tests of new features. * generic/tclCmdIL.c (Tcl_LsearchObjCmd): TIP#80 support. See http://purl.org/tcl/tip/80 for details. 2002-03-05 Jeff Hobbs *** 8.4a4 TAGGED FOR RELEASE *** * unix/tclUnixChan.c: initial remedy for [Bug 525783] flush problem introduced by TIP #35. This may not satisfy true serial channels, but it restores the correct flushing of std* channels on exit. * unix/README: added --enable-langinfo doc. * unix/tcl.spec: * tools/tcl.wse.in: fixed URL refs to use www.tcl.tk or SF. 2002-03-04 Jeff Hobbs * README: * mac/README: * unix/Makefile.in: * unix/README: * win/README: * win/README.binary: updated to use www.tcl.tk URL. * unix/Makefile.in: added older ChangeLogs to dist target. * tests/io.test: * tests/encoding.test: corrected iso2022 encoding results. added encoding-24.* * generic/tclEncoding.c (EscapeFromUtfProc): corrected output of escape codes as per RFC 1468. [Patch 474358] (taguchi) (TclFinalizeEncodingSubsystem): corrected potential double-free when encodings were finalized on exit. [Bug 219314, 524674] 2002-03-01 Jeff Hobbs * library/encoding/iso2022-jp.enc: * library/encoding/iso2022.enc: * tools/encoding/iso2022-jp.esc: * tools/encoding/iso2022.esc: gave $B precedence over $@, based on comments (point 1) in [Bug 219283] (RFC 1468) * tests/encoding.test: added encoding-23.* tests * generic/tclIO.c (FilterInputBytes): reset the TCL_ENCODING_START flags in the ChannelState when using 'gets'. [Bug 523988] Also reduced the value of ENCODING_LINESIZE from 30 to 20 as this seems to improve the performance of 'gets' according to tclbench. 2002-02-28 Jeff Hobbs * generic/tclCmdMZ.c (TraceCommandProc): ensure that TraceCommandInfo structure was also deleted when a command was deleted to prevent a mem leak. * generic/tclBasic.c (Tcl_CreateObjTrace): set tracePtr->flags correctly. * generic/tclTimer.c (TimerExitProc): remove remaining events in tls on thread exit. 2002-02-28 Miguel Sofer * generic/tclNamesp.c: allow cached fully-qualified namespace names to be usable from different namespaces within the same interpreter without forcing a new lookup [Patch 458872]. 2002-02-28 Miguel Sofer * generic/tclExecute.c: Replaced a few direct stack accesses with the POP_OBJECT() macro [Bug 507181] (Don Porter). 2002-02-27 Don Porter * doc/GetIndex.3: * generic/tcl.decls (Tcl_GetIndexFromObjStruct): * generic/tclIndexObj.c (Tcl_GetIndexFromObjStruct): Revised the prototype of the Tcl_GetIndexFromObjStruct to take its struct table as a (CONST VOID *) argument, better describing what it is, maintaining source compatibility, and adding CONST correctness according to TIP 27. Thanks to Joe English for an elegant solution. [Bug 520304] * generic/tclDecls.h: make genstubs * generic/tclMain.c (Tcl_Main,StdinProc): Corrected some reference count management errors on the interactive command Tcl_Obj found by Purify. Thanks to Jeff Hobbs for the report and assistance. 2002-02-27 Jeff Hobbs * generic/tclBasic.c (Tcl_EvalTokensStandard): corrected mem leak in error case. * generic/tclTest.c (TestStatProc[123]): correct harmless UMRs. * generic/tclLink.c (Tcl_LinkVar): correct mem leak in error case. 2002-02-27 Andreas Kupries * tests/socket.test (2.7): Accepted and applied patch for [Bug 523470] provided by Don Porter to avoid timing problems in that test. * unix/tclUnixChan.c (TclpOpenFileChannel): Added code to regonize "/dev/tty" (by name) and to not handle it as tty / serial line. This is the controlling terminal and is special. Setting it into raw mode as is done for other tty's is a bad idea. This is a hackish fix for expect [Bug 520624]. The fix has limitation: Tcl_MakeFileChannel handles tty's specially too, but is unable to recognize /dev/tty as it only gets a file descriptor, and no name for it. 2002-02-26 Jeff Hobbs * generic/tclCmdAH.c (StoreStatData): corrected mem leak. * generic/tclCmdMZ.c (Tcl_RegsubObjCmd): prevent obj leak in remedial regsub case. * generic/tclFileName.c (Tcl_TranslateFileName): decr refcount for error case to prevent mem leak. * generic/tclVar.c (Tcl_ArrayObjCmd): removed extra obj allocation. * unix/tclUnixSock.c (Tcl_GetHostName): added an extra gethostbyname check to guard against failure with truncated names returned by uname. * unix/configure: * unix/tcl.m4 (SC_SERIAL_PORT): added sys/modem.h check and defined _XOPEN_SOURCE_EXTENDED for HP-11 to get updated header decls. * unix/tclUnixChan.c: added Unix implementation of TIP #35, serial port support. [Patch 438509] (schroedter) 2002-02-26 Miguel Sofer * generic/tclCmpCmds.c: (bugfix to the bugfix, hopefully the last) Bugfix to the new [for] compiling code: was setting a exceptArray parameter using another param which wasn't yet initialised, thus filling it with noise. 2002-02-25 Andreas Kupries * mac/tclMacSock.c (TcpGetOptionProc): Changed to recognize the option "-error". Essentially ignores the option, always returning an empty string. 2002-02-25 Jeff Hobbs * doc/Alloc.3: * doc/LinkVar.3: * doc/ObjectType.3: * doc/PkgRequire.3: * doc/Preserve.3: * doc/TCL_MEM_DEBUG.3: Updated documentation to describe the ckalloc, ckfree, ckrealloc, attemptckalloc, and attemptckrealloc macros, and to accurately describe when and how they are used. [Bug 497459] (dgp) * generic/tclHash.c (AllocArrayEntry, AllocStringEntry): Before invoking ckalloc when creating a Tcl_HashEntry, check that the amount of memory being allocated is at least as large as sizeof(Tcl_HashEntry). The previous code was allocating memory regions that were one or two bytes short. [Bug 521950] (dejong) 2002-02-25 Miguel Sofer * generic/tclBasic.c (Tcl_EvalEx): avoiding a buffer overrun reported by Joe English, and restoring tcl7.6 behaviour for [subst]: badly terminated nested scripts will raise an error and not be evaluated. [Bug 495207] 2002-02-25 Don Porter * unix/tclUnixPort.h: corrected strtoll prototype mismatch on Tru64. * compat/strtod.c (strtod): simplified #includes * compat/strtol.c (strtol): gather result in a long before returning as a long: necessary on platforms where sizeof(int) != sizeof(long). 2002-02-25 Daniel Steffen * unix/tclLoadDyld.c: updated to use Mac OS X 10.1 dyld APIs that have more libdl-like semantics. [Bug 514392] 2002-02-25 Miguel Sofer * generic/tclCompCmds: fixing a bug in patch dated 2002-02-22, in the code for [for] and [while]. Under certain conditions, for long bodies, the exception range parameters were badly computed. Tests forthcoming: I still can't reproduce the conditions in the testsuite (!), although the bug (with assorted segfault or panic!) can be triggered from the console or with the new parse.bench in tclbench. 2002-02-25 Donal K. Fellows * compat/strtoul.c, compat/strtol.c, compat/strtod.c: Added UCHAR, CONST and #includes to clean up GCC output. 2002-02-23 Don Porter * compat/strtoull.c (strtoull): * compat/strtoll.c (strtoll): * compat/strtoul.c (strtoul): Fixed failure to handle leading sign symbols '+' and '-' and '0X' and raise overflow errors. [Bug 440916] Also corrects prototype and errno problems. 2002-02-23 Mo DeJong * configure: Regen. * unix/tcl.m4 (SC_CONFIG_CFLAGS): Link with -n32 instead of -32 when building on IRIX64-6.* system. [Bug 521707] 2002-02-22 Don Porter * generic/tclInt.h: * generic/tclObj.c: renamed global variable emptyString -> tclEmptyString because it is no longer static. * generic/tclPkg.c: Fix for panic when library is loaded on a platform without backlinking without proper use of stubs. [Bug 476537] 2002-02-22 Jeff Hobbs * tests/regexpComp.test: updated regexp-11.[1-4] to match changes in regexp.test for new regsub syntax * unix/configure: * unix/tcl.m4: added --enable-64bit support for AIX-4 (using -q64 flag) when using IBM's xlc compiler. * tests/safe.test: updated safe-8.5 and safe-8.7 * library/safe.tcl (CheckFileName): removed the limit on sourceable file names (was only *.tcl or tclIndex files with no more than one dot and 14 chars). There is enough internal protection in a safe interpreter already. Fixes [Tk Bug 521560]. 2002-02-22 Miguel Sofer * generic/tclCompCmds: [FR 465811]. Optimising [if], [for] and [while] for constant conditions; in addition, [for] and [while] are now compiled with the "loop rotation" optimisation (thanks to Kevin Kenny). 2002-02-22 Donal K. Fellows --- TIP#76 CHANGES --- * generic/tclCmdMZ.c (Tcl_RegsubObjCmd): Final-argument-less [regsub] returns the modified string. * doc/regsub.n: Updated docs. * tests/regexp.test: Updated and added tests. * compat/strtoll.c (strtoll): * compat/strtoull.c (strtoull): * unix/tclUnixPort.h: * win/tclWinPort.h: Const-ing 64-bit compatability declarations. Note that the return pointer is non-const because it is entirely legal for the functions to be called from somewhere that owns the string being passed. Fixes problem reported by Larry Virden. 2002-02-21 David Gravereaux * win/mkd.bat (removed): * win/coffbase.txt (new): * win/makefile.bc: * win/makefile.vc: Changed the 'setup' target to stop using the mkd.bat file and just make the directory right in the rule. Same change to makefile.bc. configure.in nor Makefile.in use it. coffbase.txt will be the master list for our "prefered base addresses" set by the linker. This should improve load-time (NT only) by avoiding relocations. Submissions to the list by extension authors are encouraged. Added a 'tidy' target to compliment 'clean' and 'hose' to remove just the outputs. Also removed the $(winlibs) macro as it wasn't being used. Stuff left to do: 1) get the winhelp target to stop building in the tools/ directory. 2) stop using rmd.bat 3) add more dependacy rules. * win/tclAppInit.c: Reverted back to -r1.6, as the header file change to tclPort.h won't allow for easy embedded support outside of the source dist. Thanks to Don Porter for pointing this out to me. 2002-02-21 David Gravereaux * win/makefile.vc: * win/rules.vc: Added a new "loimpact" option that sets the -ws:aggressive linker option. Off by default. It's said to keep the heap use low at the expense of alloc speed. * win/tclAppInit.c: Changed #include "tcl.h" to be tclPort.h to remove the raw windows.h include. tclPort.h brings in windows.h already and lessens the pre-compiled-header mush and the randomly useless #pragma comment (lib,...) references throughout the big windows.h tree (as observed at high linker warning levels). 2002-02-21 Donal K. Fellows * generic/tcl.h: Better guessing of LP64/ILP32 architecture, but now sensitive to presence of (suitable) 2002-02-20 Don Porter * generic/tcl.decls (Tcl_RegExpRange,Tcl_GetIndexFromObjStruct): Overlooked a few source incompatibilities. Now using CONST84. * generic/tclDecls.h: make genstubs * generic/tcl.h (Tcl_CmdObjTraceProc): silence warning from Sun Workshop compiler. 2002-02-20 David Gravereaux * win/buildall.vc.bat: * win/makefile.vc: * win/rules.vc: General clean-ups. Added compiler and linker tests for a) the pentium 0x0F errata, b) optimizing (not all have this), and c) linker v6 section alignment confusion. All these are tested first to make sure any D4002 or LNK1117 warnings aren't displayed. The pentium 0x0F errata is a recommended switch. The v5 linker's section alignment default is 512, but the v6 linker was changed to 4096 in an attempt to speed loading on Win98. I changed the default to always be 512 across both linkers, unless linking statically, then 4096 is used for the claimed speed effect. Using a 512 alignment saves 12k bytes of dead space in the DLL. Added IA64 B-stepping errata switch when the compiler supports it. Added profiling to $(lflags) when requested and also removed the explict -entry option as the default works fine as is. Removed win/tclWinInit.c from the special case section to let it use the common implicit rule as the $(EXTFLAGS) macro it had was never referenced anywhere. 2002-02-20 Donal K. Fellows * generic/tcl.h: Added code to guess the correct settings for TCL_WIDE_INT_IS_LONG and TCL_WIDE_INT_TYPE when configure doesn't tell us them, as can happen with extensions. 2002-02-19 Donal K. Fellows * doc/format.n: Updated docs to list the specification. * generic/tclCmdAH.c (Tcl_FormatObjCmd): Made behaviour on 64-bit platforms correctly meet the specification, that %d works with the native word-sized integer, instead of trying to guess (wrongly) from the value being passed. 2002-02-19 Don Porter * changes: First draft of updated changes for 8.4a4 release. 2002-02-15 Jeff Hobbs * unix/tclUnixPort.h: add strtoll/strtoull declarations for platforms that do not define them. * generic/tclIndexObj.c (STRING_AT): removed ptrdiff_t cast and use of VOID* in default case (GNU-ism). 2002-02-15 Kevin Kenny * compat/strtoll.c: * compat/strtoul.c: * compat/strtoull.c: * generic/tclIOUtil.c: * generic/tclPosixStr.c: * generic/tclTest.c: * generic/tclTestObj.c: * tests/get.test: * win/Makefile.vc: Further tweaks to the TIP 72 patch to make it compile under VC++. 2002-02-15 Andreas Kupries * tclExecute.c: * tclIOGT.c: * tclIndexObj.c: Touchups to the TIP 72 patch to make it compileable under Windows again. The changes are not complete, there is one nasty regarding _stati64 2002-02-15 Donal K. Fellows +----------------------+ | TIP #72 IMPLEMENTED. | +----------------------+ There are a lot of changes from this TIP, so please see http://tip.tcl.tk/72.html for discussion of backward-compatability issues, but the main ones modifications are in: * generic/tcl.h: New types. * generic/tcl.decls: New public functions. * generic/tclExecute.c: 64-bit aware bytecode engine. * generic/tclBinary.c: 64-bit handling in [binary] command. * generic/tclScan.c: 64-bit handling in [scan] command. * generic/tclCmdAH.c: 64-bit handling in [file] and [format] commands. * generic/tclBasic.c: New "wordSize" entry in ::tcl_platform. * generic/tclFCmd.c: Large-file support (with many consequences.) * generic/tclIO.c: Large-file support (with many consequences.) * compat/strtoll.c, compat/strtoull.c: New support functions. * unix/tcl.m4, unix/configure: 64-bit support and greatly enhanced cacheing. Most other changes, including all those in doc/* and test/* as well as the majority in the platform directories, follow on from these. Also coming out of the woodwork: * generic/tclIndex.c: Better support for Cray PVP. * win/tclWinMtherr.c: Better Borland support. Note that, in a number of places through the Unix part of the platform support, there are Tcl_Platform* references. These are expanded into the correct way to call that particular underlying function, i.e. with or without a '64' suffix, and should be used by people working on the core in preference to the API functions they overlay so that the code remains portable depending on the presence or absence of 64-bit support on the underlying platform. ***POTENTIAL INCOMPATIBILITY***: Extracted from the TIP SUMMARY OF INCOMPATIBILITIES AND FIXES ====================================== The behaviour of expressions containing constants that appear positive but which have a negative internal representation will change, as these will now usually be interpreted as wide integers. This is always fixable by replacing the constant with int(constant). Extensions creating new channel types will need to be altered as different types are now in use in those areas. The change to the declaration of Tcl_FSStat and Tcl_FSLstat (which are the new preferred API in any case) are less serious as no non-alpha releases have been made yet with those API functions. Scripts that are lax about the use of the l modifier in format and scan will probably need to be rewritten. This should be very uncommon though as previously it had absolutely no effect. Extensions that create new math functions that take more than one argument will need to be recompiled (the size of Tcl_Value changes), and functions that accept arguments of any type (TCL_EITHER) will need to be rewritten to handle wide integer values. (I do not expect this to affect many extensions at all.) 2002-02-14 Andreas Kupries * generic/tclIOCmd.c (Tcl_GetsObjCmd): Trivial fix for [Bug 517503], a memory leak reported by Miguel Sofer . The leak happens if an error occurs for "set var [gets $chan]" and leak one empty object. 2002-02-12 David Gravereaux * djgpp/ (new directory) * djgpp/Makefile (new): * unix/tclAppInit.c: * unix/tclMtherr.c: * unix/tclUnixFCmd.c: * unix/tclUnixFile.c: * unix/tclUnixInit.c: * unix/tclUnixPort.h: Early stage of DJGPP support for building Tcl on DOS. Dynamic loading isn't working, yet. Requires watt32 for the TCP/IP stack. No autoconf, yet. Barely tested, but makes a working exe that runs Tcl in protected-mode, flat memory. [exec] and pipes will need the most work as multi-tasking on DOS has to be carefully. 2002-02-10 Kevin Kenny * doc/CrtObjCmd.3: * doc/CrtTrace.3: * generic/tcl.decls: * generic/tcl.h: * generic/tclBasic.c: * generic/tclInt.h: * generic/tclTest.c: * tests/basic.test: Added Tcl_CreateObjTrace, Tcl_GetCommandInfoFromToken and Tcl_SetCommandInfoFromToken. (TIPs #32 and #79.) * generic/tclDecls.h: * generic/tclStubInit.c: Regenerated Stubs tables. 2002-02-08 Jeff Hobbs * unix/configure: * unix/tcl.m4: added -pthread for FreeBSD to EXTRA_CFLAGS and LDFLAGS. Also triggered nodots only for FreeBSD-3. Added AC_DEFINE(_POSIX_PTHREAD_SEMANTICS) for Solaris. * unix/tclUnixPort.h: * unix/tclUnixThrd.c: added thread-safe versions of readdir, localtime, gmtime and inet_ntoa for threaded build. (jgdavidson) * generic/tclScan.c (Tcl_ScanObjCmd): prevented ckfree being called on a pointer to NULL. 2002-02-07 Don Porter * doc/DString.3: * doc/Encoding.3: * doc/GetCwd.3: * doc/SplitPath.3: * doc/Translate.3: * doc/Utf.3: * generic/tcl.decls: * generic/tcl.h: * generic/tclEncoding.c: * generic/tclEnv.c: * generic/tclFileName.c: * generic/tclIOUtil.c: * generic/tclUtf.c: * generic/tclUtil.c: * mac/tclMacInit.c: * unix/tclUnixFile.c: * unix/tclUnixInit.c: * unix/tclUnixPipe.c: * win/tclWin32Dll.c: * win/tclWinFCmd.c: * win/tclWinFile.c: * win/tclWinInit.c: Partial TIP 27 rollback. Following routines restored to return (char *): Tcl_DStringAppend, Tcl_DStringAppendElement, Tcl_JoinPath, Tcl_TranslateFileName, Tcl_ExternalToUtfDString, Tcl_UtfToExternalDString, Tcl_UniCharToUtfDString, Tcl_GetCwd, Tcl_WinTCharToUtf. Also restored Tcl_WinUtfToTChar to return (TCHAR *) and Tcl_UtfToUniCharDString to return (Tcl_UniChar *). Modified some callers. This change recognizes that Tcl_DStrings are de-facto white-box objects. * generic/tclDecls.h: * generic/tclPlatDecls.h: make genstubs * generic/tclCmdMZ.c: corrected use of C++-style comment. 2002-02-06 Jeff Hobbs * tests/scan.test: * generic/tclScan.c (Tcl_ScanObjCmd): corrected scan 0x... %x handling that didn't accept the 0x as a prelude to a base 16 number. [Bug 495213] * generic/tclCompCmds.c (TclCompileRegexpCmd): made early check for bad RE to stop checking further. * generic/tclCmdMZ.c (Tcl_RegsubObjCmd): added special case to search for simple 'string map' style regsub calls. Delayed creation of resultPtr object until an initial match is made, as the input string object can then be reused for no matches. (Tcl_StringObjCmd): optimization improvements to the STR_MAP algorithm for zero-length and nocase cases. * tests/regexp.test: * tests/regexpComp.test: extra code coverage tests. * tests/string.test: added 10.18 and 10.19 extra tests. * generic/regc_locale.c (casecmp): slight performance improvement. 2002-02-05 Don Porter * library/http/http.tcl: * library/http/pkgIndex.tcl: Corrected use of http::error when ::error was intended. Bump to http 2.4.2. 2002-02-04 Andreas Kupries * unix/tclUnixChan.c (FileOutputProc): Fixed [bug 465765] reported by Dale Talcott . Avoid writing nothing into a file as STREAM based implementations will consider this a EOF (if the file is a pipe). Not done in the generic layer as this type of writing is actually useful to check the state of a socket. * doc/open.n: Fixed [Bug 511540], added cross-reference to 'pid' as the command to use to retrieve the pid of a command pipeline created via 'open'. 2002-02-01 Jeff Hobbs * generic/tclCmdMZ.c (Tcl_RegexpObjCmd): handle quirky about case earlier to avoid shimmering problem. 2002-02-01 Andreas Kupries * tests/io.test: io-39.22 split into two tests, one platform dependent, the other not. -eofchar is not empty on the windows platform. 2002-02-01 Vince Darley * generic/tclTest.c: fix to picky windows compiler problem with the 'MainLoop' function declaration. 2002-01-31 Andreas Kupries * win/tclWinFCmd.c: TIP 27: Applied patch fixing CONST warnings on behalf of Don Porter . 2002-01-30 Don Porter * generic/tcl.decls: * generic/tcl.h: * generic/tclInt.h: For each interface identified in the TIP 27 changes below as a POTENTIAL INCOMPATIBILITY, the source of the incompatibility has been parameterized so that it can be removed. When compiling extension code against the Tcl header files, use the compiler flag -DUSE_NON_CONST to remove the irresolvable source incompatibilities introduced by the TIP 27 changes. Resolvable changes are left for extension authors to resolve. * generic/tclDecls.h: make genstubs 2002-01-30 Vince Darley * doc/FileSystem.3: added documentation for 3 public functions which had been overlooked. Fixes [Bug 507701] * unix/mkLinks: make mklinks 2002-01-29 Jeff Hobbs * tests/regexpComp.test: * generic/tclCompCmds.c (TclCompileRegexpCmd): enhanced to support -nocase and -- options. 2002-01-28 Mo DeJong * unix/tcl.m4 (SC_LOAD_TCLCONFIG): * win/tcl.m4 (SC_LOAD_TCLCONFIG): Set TCL_LIB_SPEC, TCL_STUB_LIB_SPEC, and TCL_STUB_LIB_PATH to the values of TCL_BUILD_LIB_SPEC, TCL_BUILD_STUB_LIB_SPEC, and TCL_BUILD_STUB_LIB_PATH when tclConfig.sh is loaded from the build directory. A Tcl extension should make use of the non-build versions of these variables since they will work in both cases. This modification was described in TIP #34. 2002-01-28 Jeff Hobbs * win/tclWinReg.c (regConnectRegistryProc,RecursiveDeleteKey) (DeleteKey,GetKeyNames,GetType,GetValue,OpenSubKey,SetValue): redid the CONSTification as previous changes caused failing tests. * tests/regexpComp.test (new): * generic/tclInt.h: * generic/tclBasic.c: added TclCompileRegexpCmd entry * generic/tclCompCmds.c (TclCompileStringCmd): corrected to return TCL_OUT_LINE_COMPILE instead of TCL_ERROR for parsing errors, so it only throws the error for runtime compile, in case the user modifies 'string'. (TclCompileRegexpCmd): first try at a byte-compiled regexp command. It handles static strings and ^$ bounded static strings. (TclCompileAppendCmd): made TclPushVarName call always use TCL_CREATE_VAR as numWords is always > 2 at that point. * generic/tclExecute.c (TclExecuteByteCode:INST_LIST): correct possibly dangerous decr in macro call. * win/tclWinInit.c (TclpFindVariable): CONSTification touch-up * win/tclWinReg.c (OpenSubKey): corrected bug introduced in CONSTification that dropped pointer reference. * ChangeLog.2000 (new file): * ChangeLog: broke changes from 2000 into ChangeLog.2000 to reduce size of the main ChangeLog. 2002-01-28 David Gravereaux * generic/tclPlatDecls.h: Added preprocessor logic to force a typedef of TCHAR when __STDC__ is defined when using the uncommon -Za compiler switch with the microsoft compiler. 2002-01-27 Don Porter * doc/package.n: Documented global namespace context for script evaluation by [package require]. 2002-01-27 Daniel Steffen * generic/tclInt.decls: * generic/tclIntPlatDecls.h: * mac/tclMacChan.c: * mac/tclMacFCmd.c: * mac/tclMacFile.c: * mac/tclMacInit.c: * mac/tclMacLoad.c: * mac/tclMacResource.c: * mac/tclMacSock.c: TIP 27 CONSTification induced changes * tests/event.test: * tests/main.test: added catches/constraints to test that use features that don't exist on the mac. 2002-01-25 Mo DeJong Make -eofchar and -translation options read only for server sockets. [Bug 496733] * generic/tclIO.c (Tcl_GetChannelOption, Tcl_SetChannelOption): Instead of returning nothing for the -translation option on a server socket, always return "auto". Return the empty string enclosed in quotes for the -eofchar option on a server socket. Fixup -eofchar usage message so that it matches the implementation. * tests/io.test: Add -eofchar tests and -translation tests to ensure options are read only on server sockets. * tests/socket.test: Update tests to account for -eofchar and -translation option changes. 2002-01-25 Don Porter * compat/strstr.c (strstr): * generic/tclCmdAH.c (Tcl_FormatObjCmd): * generic/tclCmdIL.c (InfoNameOfExecutableCmd): * generic/tclEnv.c (ReplaceString): * generic/tclFileName.c (ExtractWinRoot): * generic/tclIO.c (FlushChannel,Tcl_BadChannelOption): * generic/tclStringObj.c (AppendUnicodeToUtfRep): * generic/tclThreadTest.c (TclCreateThread): * generic/tclUtf.c (Tcl_UtfPrev): * mac/tclMacFCmd.c (TclpObjListVolumes): * mac/tclMacResource.c (TclMacRegisterResourceFork) (BuildResourceForkList): * win/tclWinInit.c (AppendEnvironment): Sought out and eliminated instances of CONST-casting that are no longer needed after the TIP 27 effort. * Following is [Patch 501006] * generic/tclInt.decls (Tcl_AddInterpResolvers, Tcl_Export) (Tcl_FindNamespace, Tcl_GetInterpResolvers, Tcl_ForgetImport) (Tcl_Import, Tcl_RemoveInterpResolvers): * generic/tclNamesp.c (Tcl_Export, Tcl_Import, Tcl_ForgetImport) (Tcl_FindNamespace): * generic/tclResolve.c (Tcl_AddInterpResolvers,Tcl_GetInterpResolvers, (Tcl_RemoveInterpResolvers): Updated APIs in generic/tclResolve.c and generic/tclNamesp.c according to the guidelines of TIP 27. * generic/tclIntDecls.h: make genstubs * Following is [Patch 505630] * doc/AddErrorInfo.3: * generic/tcl.decls (Tcl_LogCommandInfo): * generic/tclBasic.c (Tcl_LogCommandInfo): Updated interfaces of generic/tclBasic.cc according to TIP 27. * generic/tclDecls.h: make genstubs * Following is [Patch 506818] * doc/Hash.3: * generic/tcl.decls (Tcl_HashStats): * generic/tclHash.c (Tcl_HashStats): Updated APIs of generic/tclHash.c according to guidelines of TIP 27. * generic/tclDecls.h: make genstubs * generic/tclVar.c (Tcl_ArrayObjCmd): Updated callers. * Following is [Patch 506807] * doc/ObjectType.3: * generic/tcl.decls (Tcl_GetObjType): * generic/tclObj.c (Tcl_GetObjType): Updated APIs of generic/tclObj.c according to guidelines of TIP 27. * generic/tclDecls.h: make genstubs * Following is [Patch 507304] * doc/Encoding.3: * generic/tcl.decls (Tcl_WinUtfToTChar,Tcl_WinTCharToUtf): * win/tclWin32Dll.c (Tcl_WinUtfToTChar,Tcl_WinTCharToUtf): Updated interfaces in win/tclWin32Dll.c according to TIP 27. * generic/tclPlatDecls.h: make genstubs * generic/tclIOUtil.c (TclpNativeToNormalized): * win/tclWinFCmd.c (TclpObjNormalizePath): * win/tclWinFile.c (TclpFindExecutable,TclpMatchInDirectory) (NativeIsExec,NativeStat): * win/tclWinLoad.c (TclpLoadFile): * win/tclWinPipe.c (TclpOpenFile,ApplicationType): * win/tclWinReg.c (regConnectRegistryProc,RecursiveDeleteKey,DeleteKey) (GetKeyNames,GetType,GetValue,OpenSubKey,SetValue): * win/tclWinSerial.c (SerialSetOptionProc): Update callers. * Following is [Patch 505072] * doc/Concat.3: * doc/Encoding.3: * doc/Filesystem.3: * doc/Macintosh.3: * doc/OpenFileChnl.3 * doc/SetResult.3: * doc/SetVar.3: * doc/SplitList.3: * doc/SplitPath.3: * doc/Translate.3: * generic/tcl.h (Tcl_FSMatchInDirectoryProc): * generic/tclInt.h (TclpMatchInDirectory): * generic/tcl.decls (Tcl_Concat,Tcl_GetStringResult,Tcl_GetVar, (Tcl_GetVar2,Tcl_JoinPath,Tcl_Merge,Tcl_OpenCommandChannel,Tcl_SetVar) (Tcl_SetVar2,Tcl_SplitList,Tcl_SplitPath,Tcl_TranslateFileName) (Tcl_ExternalToUtfDString,Tcl_GetEncodingName,Tcl_UtfToExternalDString) (Tcl_GetDefaultEncodingDir,Tcl_SetDefaultEncodingDir) (Tcl_FSMatchInDirectory,Tcl_MacEvalResource,Tcl_MacFindResource): * generic/tclInt.decls (TclCreatePipeline,TclGetEnv,TclpGetCwd, (TclpCreateProcess): * mac/tclMacFile.c (TclpGetCwd): * generic/tclEncoding.c (Tcl_GetDefaultEncodingDir) (Tcl_SetDefaultEncodingDir,Tcl_GetEncodingName) (Tcl_ExternalToUtfDString,Tcl_UtfToExternalDString, OpenEncodingFile) (LoadEscapeEncoding): * generic/tclFileName.c (DoTildeSubst,Tcl_JoinPath,Tcl_SplitPath, (Tcl_TranslateFileName): * generic/tclIOUtil.c (Tcl_FSMatchInDirectory): * generic/tclPipe.c (FileForRedirect,TclCreatePipeline) (Tcl_OpenCommandChannel): * generic/tclResult.c (Tcl_GetStringResult): * generic/tclUtil.c (Tcl_Concat,Tcl_SplitList,Tcl_Merge): * generic/tclVar.c (Tcl_GetVar,Tcl_GetVar2,Tcl_SetVar,Tcl_SetVar2): * mac/tclMacResource.c (Tcl_MacEvalResource,Tcl_MacFindResource): Updated interfaces of generic/tclEncoding, generic/tclFilename.c, generic/tclIOUtil.c, generic/tclPipe.c, generic/tclResult.c, generic/tclUtil.c, generic/tclVar.c and mac/tclMacResource.c according to TIP 27. Tcl_TranslateFileName rewritten as wrapper around VFS-aware version. ***POTENTIAL INCOMPATIBILITY*** Includes source incompatibilities: argv arguments of Tcl_Concat, Tcl_JoinPath, Tcl_OpenCommandChannel, Tcl_Merge; argvPtr arguments of Tcl_SplitList and Tcl_SplitPath. * generic/tclDecls.h: * generic/tclIntDecls.h: make genstubs * generic/tclCkalloc.c (MemoryCmd): * generic/tclClock.c (FormatClock): * generic/tclCmdAH.c (Tcl_CaseObjCmd,Tcl_EncodingObjCmd,Tcl_FileObjCmd): * generic/tclCmdIL.c (InfoLibraryCmd,InfoPatchLevelCmd, (InfoTclVersionCmd): * generic/tclCompCmds.c (TclCompileForeachCmd): * generic/tclCompCmds.h (TclCompileForeachCmd): * generic/tclCompile.c (TclFindCompiledLocal): * generic/tclEnv.c (TclSetupEnv,TclSetEnv,Tcl_PutEnv,TclGetEnv, (EnvTraceProc): * generic/tclEvent.c (Tcl_BackgroundError): * generic/tclIO.c (Tcl_BadChannelOption,Tcl_SetChannelOption): * generic/tclIOCmd.c (Tcl_ExecObjCmd,Tcl_OpenObjCmd): * generic/tclIOSock.c (TclSockGetPort): * generic/tclIOUtil.c (SetFsPathFromAny): * generic/tclLink.c (LinkTraceProc): * generic/tclMain.c (Tcl_Main): * generic/tclNamesp.c (TclTeardownNamespace): * generic/tclProc.c (TclCreateProc): * generic/tclTest.c (TestregexpObjCmd,TesttranslatefilenameCmd, (TestchmodCmd,GetTimesCmd,TestsetCmd,TestOpenFileChannelProc1, (TestOpenFileChannelProc2,TestOpenFileChannelProc3,AsyncHandlerProc, (TestpanicCmd): * generic/tclThreadTest.c (ThreadErrorProc,ThreadEventProc): * generic/tclUtil.c (TclPrecTraceProc): * mac/tclMacFCmd.c (GetFileSpecs): * mac/tclMacFile.c (TclpMatchInDirectory): * mac/tclMacInit.c (TclpInitLibraryPath,Tcl_SourceRCFile): * mac/tclMacOSA.c (tclOSAStore,tclOSALoad): * mac/tclMacResource.c (Tcl_MacEvalResource): * unix/tclUnixFCmd.c (TclpObjNormalizePath): * unix/tclUnixFile.c (TclpMatchInDirectory,TclpGetUserHome,TclpGetCwd, (TclpReadLink): * unix/tclUnixInit.c (TclpInitLibraryPath,TclpSetVariables, (Tcl_SourceRCFile): * unix/tclUnixPipe.c (TclpOpenFile,TclpCreateTempFile, (TclpCreateProcess): * win/tclWinFile.c (TclpGetCwd,TclpMatchInDirectory): * win/tclWinInit.c (TclpInitLibraryPath,Tcl_SourceRCFile, (TclpSetVariables): * win/tclWinPipe.c (TclpCreateProcess): Updated callers. 2002-01-24 Don Porter * generic/tclIOUtil.c (SetFsPathFromAny): Corrected tilde-substitution of pathnames where > 1 separator follows the ~. [Bug 504950] 2002-01-24 Jeff Hobbs * library/http/pkgIndex.tcl: * library/http/http.tcl: don't add port in default case to handle broken servers. http bumped to 2.4.1 [Bug 504508] 2002-01-23 Andreas Kupries * unix/mkLinks: Regenerated. * doc/CrtChannel.3: * doc/ChnlStack.3: Moved documentation for 'Tcl_GetTopChannel' from 'CrtChannel' to 'ChnlStack'. Added documentation of 'Tcl_GetStackedChannel'. [Bug 506147] reported by Mark Patton 2002-01-23 Don Porter * win/tclWinFile.c (NativeAccess,NativeStat,NativeIsExec, (TclpGetUserHome): * win/tclWinPort.h (TclWinSerialReopen): * win/tclWinSerial.c (TclWinSerialReopen): * win/tclWinSock.c (Tcl_OpenTcpServer): Corrections to earlier TIP #27 changes. Thanks to Andreas Kupries for the feedback. * generic/tclPlatDecls.h: make genstubs * doc/GetHostName.3: * doc/GetOpnFl.3: * doc/OpenTcp.3: * tcl.decls (Tcl_GetHostName,Tcl_GetOpenFile,Tcl_OpenTcpClient, (Tcl_OpenTclServer): * mac/tclMacSock.c (CreateSocket,Tcl_OpenTcpClient,Tcl_OpenTcpServer, (Tcl_GetHostName,GetHostFromString): * unix/tclUnixChan.c (CreateSocket,CreateSocketAddress, (Tcl_OpenTcpClient,Tcl_OpenTcpServer,Tcl_GetOpenFile): * unix/tclUnixSock.c (Tcl_GetHostName): * win/tclWinSock.c (CreateSocket,CreateSocketAddress, (Tcl_OpenTcpClient,Tcl_OpenTcpServer,Tcl_GetHostName): Updated socket interfaces according to TIP 27. * generic/tclCmdIL.c (InfoHostnameCmd): Updated callers. * generic/tclDecls.h: make genstubs 2002-01-21 David Gravereaux * generic/tclLoadNone.c: TclpLoadFile() didn't match proto of typedef Tcl_FSLoadFileProc. OK'd by vincentdarley. [Patch 502488] 2002-01-21 Andreas Kupries * generic/tclIO.c (WriteChars): Fix for [Bug 506297], reported by Martin Forssen . The encoding chosen in the script exposing the bug writes out three intro characters when TCL_ENCODING_START is set, but does not consume any input as TCL_ENCODING_END is cleared. As some output was generated the enclosing loop calls UtfToExternal again, again with START set. Three more characters in the out and still no use of input ... To break this infinite loop we remove TCL_ENCODING_START from the set of flags after the first call (no condition is required, the later calls remove an unset flag, which is a no-op). This causes the subsequent calls to UtfToExternal to consume and convert the actual input. 2002-01-21 Don Porter * generic/tclTest.c: Converted declarations of TestReport file system to more portable form. [Bug 501417]. * generic/tcl.decls (Tcl_TraceCommand,Tcl_UntraceCommand, (Tcl_CommandTraceInfo): * generic/tclCmdMZ.c (Tcl_TraceCommand,Tcl_UntraceCommand, (Tcl_CommandTraceInfo): Updated APIs in generic/tclCmdMZ.c according to the guidelines of TIP 27. * generic/tclDecls.h: make genstubs 2002-01-18 Don Porter * win/tclWinChan.c: * win/tclWinFCmd.c: * win/tclWinFile.c: Overlooked callers of Tcl_FSGetNativePath * win/tclWinDde.c: * win/tclWinReg.c: Overlooked callers of Tcl_GetIndexFromObj 2002-01-18 Daniel Steffen * generic/tclThreadTest.c: * mac/tclMacChan.c: * mac/tclMacFCmd.c: * mac/tclMacFile.c: * mac/tclMacLoad.c: * mac/tclMacResource.c: TIP 27 CONSTification broke the mac build in a number of places. 2002-01-17 Andreas Kupries * generic/tclIOCmd.c (Tcl_GetsObjCmd): Fixed [Bug 504642] as reported by Brian Griffin , using his patch. Before the patch the generic I/O layer held an unannounced reference to the interp result to store the read line into. This unfortunately has disastrous results if the channel driver executes a Tcl script to perform its operation, this freeing the interp result. In that case we are dereferencing essentially a dangling reference. It is not truly dangling because the object is in the free list, but this only causes us to smash the free list and have the error occur later somewhere else. The patch simply creates a new object for the line and later sets it into the interp result when we are done with reading. 2002-01-16 Mo DeJong * unix/tcl.m4 (SC_LOAD_TCLCONFIG): * win/tcl.m4 (SC_LOAD_TCLCONFIG): Subst TCL_DBGX into TCL_STUB_LIB_FILE and TCL_STUB_LIB_FLAG variables so that an extension does not need to subst TCL_DBGX into its makefile. [Tk Bug 504356] 2002-01-16 Don Porter * doc/FileSystem.3: * doc/GetCwd.3: * doc/GetIndex.3: * generic/tcl.decls (Tcl_GetIndexFromObj, Tcl_GetIndexFromObjStruct, (Tcl_GetCwd, Tcl_FSFileAttrStrings, Tcl_FSGetNativePath, (Tcl_FSGetTranslatedStringPath): * generic/tcl.h (Tcl_FSFileAttrStringsProc): * generic/tclFCmd.c (TclFileAttrsCmd): * generic/tclIOUtil.c (Tcl_GetCwd,NativeFileAttrStrings, (Tcl_FSFileAttrStrings,Tcl_FSGetTranslatedStringPath, (Tcl_FSGetNativePath): * generic/tclIndexObj.c (Tcl_GetIndexFromObj,Tcl_GetIndexFromObjStruct): More TIP 27 updates in tclIOUtil.c and tclIndexObj.c that were overlooked before. [Patch 504671] ***POTENTIAL INCOMPATIBILITY*** Includes a source incompatibility in the tablePtr arguments of the Tcl_GetIndexFromObj* routines. * generic/tclDecls.h: make genstubs * generic/tclBinary.c (Tcl_BinaryObjCmd): * generic/tclClock.c (Tcl_ClockObjCmd): * generic/tclCmdAH.c (Tcl_EncodingObjCmd, Tcl_FileObjCmd): * generic/tclCmdIL.c (Tcl_InfoObjCmd,Tcl_LsearchObjCmd,Tcl_LsortObjCmd): * generic/tclCmdMZ.c (Tcl_TraceObjCmd,Tcl_RegexpObjCmd,Tcl_RegsubObjCmd, (Tcl_StringObjCmd,Tcl_SubstObjCmd,Tcl_SwitchObjCmd, (TclTraceCommandObjCmd,TclTraceVariableObjCmd): * generic/tclCompCmds.c (TclCompileStringCmd): * generic/tclEvent.c (Tcl_UpdateObjCmd): * generic/tclFileName.c (Tcl_GlobObjCmd): * generic/tclIO.c (Tcl_FileEventObjCmd): * generic/tclIOCmd.c (Tcl_SeekObjCmd,Tcl_ExecObjCmd,Tcl_SocketObjCmd, (Tcl_FcopyObjCmd): * generic/tclInterp.c (Tcl_InterpObjCmd,SlaveObjCmd): * generic/tclNamesp.c (Tcl_NamespaceObjCmd): * generic/tclPkg.c (Tcl_PackageObjCmd): * generic/tclTest.c (Tcltest_Init,TestencodingObjCmd,TestgetplatformCmd, (TestlocaleCmd,TestregexpObjCmd,TestsaveresultCmd, (TestGetIndexFromObjStructObjCmd,TestReportFileAttrStrings): * generic/tclTestObj.c (TestindexObjCmd,TeststringObjCmd): * generic/tclTimer.c (Tcl_AfterObjCmd): * generic/tclVar.c (Tcl_ArrayObjCmd): * mac/tclMacFCmd.c (SetFileFinderAttributes): * unix/tclUnixChan.c (TclpOpenFileChannel): * unix/tclUnixFCmd.c (tclpFileAttrStrings): * unix/tclUnixFile.c (TclpObjAccess,TclpObjChdir,TclpObjStat, (TclpObjLstat): * win/tclWinFCmd.c (tclpFileAttrStrings): Updated callers. * doc/RegExp.3: * doc/Utf.3: * generic/tcl.decls: * generic/tclInt.decls: * generic/tclRegexp.c: * generic/tclUtf.c: Updated APIs in generic/tclUtf.c and generic/tclRegexp.c according to the guidelines of TIP 27. [Patch 471509] * generic/regc_locale.c (element,cclass): * generic/tclCmdMZ.c (Tcl_StringObjCmd): * generic/tclFileName.c (TclpGetNativePathType,SplitMacPath): * generic/tclIO.c (ReadChars): * mac/tclMacLoad.c (TclpLoadFile): * win/tclWinFile.c (TclpGetUserHome): Updated callers. * generic/tclDecls.h: * generic/tclIntDecls.h: make genstubs * doc/ParseCmd.3 (Tcl_ParseVar): * generic/tcl.decls (Tcl_ParseVar): * generic/tclParse.c (Tcl_ParseVar): * generic/tclTest.c (TestparsevarObjCmd): Updated APIs in generic/tclParse.c according to the guidelines of TIP 27. Updated callers. [Patch 501046] * generic/tclDecls.h: make genstubs * generic/tcl.decls (Tcl_RecordAndEval): * generic/tclDecls.h: make genstubs * generic/tclHistory.c (Tcl_RecordAndEval): Updated APIs in generic/tclHistory.c according to the guidelines of TIP 27. [Patch 504091] * doc/CrtSlave.3: * generic/tcl.decls (Tcl_CreateAlias, Tcl_CreateAliasObj, (Tcl_CreateSlave, Tcl_GetAlias, Tcl_GetAliasObj, Tcl_GetSlave): * generic/tclInterp.c (Tcl_CreateAlias, Tcl_CreateAliasObj, (Tcl_CreateSlave, Tcl_GetAlias, Tcl_GetAliasObj, Tcl_GetSlave): Updated APIs in the file generic/tclInterp.c according to the guidelines of TIP 27. [Patch 501371] ***POTENTIAL INCOMPATIBILITY*** Includes a source incompatibility in the targetCmdPtr arguments of the Tcl_GetAlias* routines. * generic/tclDecls.h: make genstubs 2002-01-15 Don Porter * doc/SetErrno.3 (Tcl_ErrnoMsg): Corrected documentation for Tcl_ErrnoMsg; it takes an integer argument. Thanks to Georgios Petasis. [Bug 468183] * doc/AddErrInfo.3 (Tcl_PosixError): * doc/Eval.3 (Tcl_EvalFile): * doc/FileSystem.c (Tcl_FSOpenFileChannel,Tcl_FSOpenFileChannelProc): * doc/OpenFileChnl.3 (Tcl_OpenFileChannel): * doc/SetErrno.3 (Tcl_ErrnoId,Tcl_ErrnoMsg): * doc/Signal.3 (Tcl_SignalId,Tcl_SignalMsg): * generic/tcl.decls (Tcl_ErrnoId,TclErrnoMsg,Tcl_EvalFile, (Tcl_OpenFileChannel,Tcl_PosixError,Tcl_SignalId,Tcl_SignalMsg, (Tcl_FSOpenFileChannel): * generic/tcl.h (Tcl_FSOpenFileChannelProc): * generic/tclIO.c (FlushChannel): * generic/tclIOUtil.c (Tcl_OpenFileChannel,Tcl_EvalFile,TclGetOpenMode, (Tcl_PosixError,Tcl_FSOpenFileChannel): * generic/tclInt.decls (TclGetOpenMode): * generic/tclInt.h (TclOpenFileChannelProc_,TclGetOpenMode, (TclpOpenFileChannel): * generic/tclPipe.c (TclCleanupChildren): * generic/tclPosixStr.c (Tcl_ErrnoId,Tcl_ErrnoMsg,Tcl_SignalId, (Tcl_SignalMsg): * generic.tclTest.c (PretendTclpOpenFileChannel, (TestOpenFileChannelProc1,TestOpenFileChannelProc2, (TestOpenFileChannelProc3,TestReportOpenFileChannel): * mac/tclMacChan.c (TclpOpenFileChannel): * unix/tclUnixChan.c (TclpOpenFileChannel): * win/tclWinChan.c (TclpOpenFileChannel): Updated APIs in generic/tclIOUtil.c and generic/tclPosixStr.c according to the guidelines of TIP 27. Updated callers. [Patch 499196] * generic/tclDecls.h: * generic/tclIntDecls.h: make genstubs * doc/CrtChannel.3: * doc/OpenFileChnl.3: * generic/tcl.decls: * generic/tclIO.h: * generic/tclIO.c (DoWrite, Tcl_RegisterChannel, Tcl_GetChannel, (Tcl_CreateChannel, Tcl_GetChannelName, CloseChannel, Tcl_Write, (Tcl_WriteRaw, Tcl_Ungets, Tcl_BadChannelOption, Tcl_GetChannelOption, (Tcl_SetChannelOption, Tcl_GetChannelNamesEx, Tcl_ChannelName): Updated APIs in the file generic/tclIO.c according to the guidelines of TIP 27. Several minor documentation corrections as well. [Patch 503565] * generic/tclDecls.h: make genstubs * generic/tcl.h (Tcl_DriverOutputProc, Tcl_DriverGetOptionProc, (Tcl_DriverSetOptionProc): * generic/tclIOGT.c (TransformOutputProc, TransformGetOptionProc, (TransformSetOptionProc): * mac/tclMacChan.c (FileOutput, StdIOOutput): * man/tclMacSock.c (TcpGetOptionProc, TcpOutput): * unix/tclUnixChan.c (FileOutputProc, TcpGetOptionProc, TcpOutputProc, (TtyGetOptionProc, TtySetOptionProc): * unix/tclUnixPipe.c (PipeOuputProc): * win/tclWinChan.c (FileOutputProc): * win/tclWinConsole.c (ConsleOutputProc): * win/tclWinPipe.c (PipeOuputProc): * win/tclWinSerial.c (SerialOutputProc, SerialGetOptionProc, (SerialSetOptionProc): * win/tclWinSock.c (TcpGetOptionProc, TcpOutput): Updated channel driver interface according to the guidelines of TIP 27. See also [Bug 500348]. * doc/CrtChannel.3: * generic/tcl.h: * generic/tclIO.c: * generic/tclIO.h: * generic/tclInt.h: * tools/checkLibraryDoc.tcl: Moved Tcl_EolTranslation enum declaration from generic/tcl.h to generic/tclInt.h (renamed to TclEolTranslation). It is not used anywhere in Tcl's public interface. 2002-01-14 Don Porter * doc/GetIndex.3: * doc/WrongNumArgs.3: * generic/tcl.decls (Tcl_GetIndexFromObj, Tcl_GetIndexFromObjStruct, (Tcl_WrongNumArgs): * generic/tclIndexObj.c (Tcl_GetIndexFromObj, Tcl_GetIndexFromObjStruct, (Tcl_WrongNumArgs): Updated APIs in the file generic/tclIndexObj.c according to the guidelines of TIP 27. [Patch 501491] * generic/tclDecls.h: make genstubs 2002-01-11 Mo DeJong * unix/configure: Regen. * unix/configure.in: * win/configure: Regen. * win/configure.in: Use ${libdir} instead of ${exec_prefix}/lib to properly support the --libdir option to configure. [Bug 489370] 2002-01-11 Andreas Kupries * win/tclWinSerial.c (SerialSetOptionProc): Applied patch for [Bug 500348] supplied by Rolf Schroedter . The function modified the contents of the the 'value' string and now does not do this anymore. This is a followup to the change made on 2001-12-17. 2002-01-11 David Gravereaux * win/makefile.vc: Removed -GD compiler option. It was intended for future use, but MS is again changing the future at their whim. The D4002 warning was harmless though, but someone using VC .NET logged it as a concern. [Bug 501565] 2002-01-11 Mo DeJong * unix/Makefile.in: Burn Tcl build directory into tcltest executable to avoid crashes caused by ld loading a previously installed version of the tcl shared library. [Bug 218110] 2002-01-10 Don Porter , Kevin Kenny * unix/tclLoadDld.c (TclpLoadFile): syntax error: unbalanced parens. Kevin notes that it's far from clear that this file is ever included in an actual build; Linux without dlopen appears to be a nonexistent configuration. 2002-01-08 Don Porter , Kevin Kenny * doc/StaticPkg.3 (Tcl_StaticPackage): * generic/tcl.decls (Tcl_StaticPackage): * generic/tclDecls.h (Tcl_StaticPackage): * generic/tclInt.decls (TclGuessPackageName): * generic/tclInt.h (TclGuessPackageName): * generic/tclLoad.c (Tcl_StaticPackage): * generic/tclLoadNone.c (TclGuessPackageName): * mac/tclMacLoad.c (TclGuessPackageName): * unix/tclLoadAout.c (TclGuessPackageName): * unix/tclLoadDl.c (TclGuessPackageName): * unix/tclLoadDld.c (TclGuessPackageName): * unix/tclLoadDyld.c (TclGuessPackageName): * unix/tclLoadNext.c (TclGuessPackageName): * unix/tclLoadOSF.c (TclGuessPackageName): * unix/tclLoadShl.c (TclGuessPackageName): * win/tclWinLoad.c (TclGuessPackageName): Updated APIs in the files */tcl*Load*.c according to the guidelines of TIP 27. [Patch 501096] 2002-01-09 Don Porter * generic/tclTest.c (MainLoop): * tests/main.test (Tcl_Main-1.{3,4,5,6}): Corrected some non-portable tests from the new Tcl_Main changes. Thanks to Kevin Kenny. 2002-01-07 Don Porter * generic/tclEvent.c (TclInExit): * generic/tclIOUtil.c (SetFsPathFromAbsoluteNormalized, (SetFsPathFromAny,Tcl_FSNewNativePath,DupFsPathInternalRep): * generic/tclListObj.c (TclLsetList,TclLsetFlat): Added some type casts to satisfy picky compilers. * generic/tclMain.c: Bug fix: neglected the NULL case in TclGetStartupScriptFileName(). Broke Tk/wish. 2002-01-05 Don Porter * doc/Tcl_Main.3: * generic/tclMain.c: Substantial rewrite and expanded documentation of Tcl_Main to correct a number of bugs and flaws: * Interactive Tcl_Main can now enter a main loop, exit that loop and continue interactive operations. The loop may even exit in the midst of interactive command typing without loss of the partial command. [Bugs 486453, 474131] * Tcl_Main now gracefully handles deletion of its master interpreter. * Interactive Tcl_Main can now operate with non-blocking stdin * Interactive Tcl_Main can now detect EOF on stdin even in mid-command. [Bug 491341] * Added VFS-aware internal routines for managing the startup script selection. * Tcl variable 'tcl_interactive' is now linked to C variable 'tty' so that one can disable/enable interactive prompts at the script level when there is no startup script. This is meant for use by the test suite. * Consistent use of the Tcl libraries standard channels as returned by Tcl_GetStdChannel(); as opposed to the channels named 'stdin', 'stdout', and 'stderr' in the master interp, which can be different or unavailable. * Tcl_Main now calls Tcl_Exit() if evaluation of [exit] in the master interpreter returns, assuring Tcl_Main does not return. * Documented Tcl_Main's absence from public stub table * Documented that Tcl_Main does not return. * Documented Tcl variables set by Tcl_Main. * All prompts are done from a single procedure, Prompt. * Use of Tcl_Obj-enabled interfaces everywhere. * generic/tclInt.decls (TclGetStartupScriptPath, (TclSetStartupScriptPath): New internal VFS-aware routines for managing the startup script of Tcl_Main. * generic/tclIntDecls.h: * generic/tclStubInit.c: make genstubs * generic/tclTest.c (TestsetmainloopCmd,TestexitmainloopCmd, (Tcltest_Init,TestinterpdeleteCmd): * tests/main.test (new): Added new file to test suite that thoroughly tests generic/tclMain.c; added some new test commands for testing Tcl_SetMainLoop(). 2002-01-04 Don Porter * doc/Alloc.3: * doc/Concat.3: * doc/CrtMathFnc.3: * doc/Hash.3: * doc/Interp.3: * doc/LinkVar.3: * doc/ObjectType.3: * doc/PkgRequire.3: * doc/Preserve.3: * doc/SetResult.3: * doc/SplitList.3: * doc/SplitPath.3: * doc/TCL_MEM_DEBUG.3: Updated documentation to describe the ckalloc, ckfree, ckrealloc, attemptckalloc, and attemptckrealloc macros, and to accurately describe when and how they are used. [Bug 497459] * generic/tclThreadJoin.c (TclRememberJoinableThread,TclJoinThread): Replaced Tcl_Alloc and Tcl_Free calls with ckalloc and ckfree so that memory debugging is supported. 2002-01-04 Daniel Steffen * mac/tclMacTime.c (TclpGetTZName): fix for daylight savings TZName bug 2002-01-03 Don Porter * doc/FileSystem.3: * generic/tclIOUtil.c: Updated some old uses of "fileName" to new VFS terminology, "pathPtr". 2002-01-03 Donal K. Fellows * tests/basic.test (basic-39.4): Greatly simplified test while still leaving it so that it crashes when run without the fix to the [foreach] implementation. * generic/tclCmdAH.c (Tcl_ForeachObjCmd): Stopped [Bug 494348] from happening by not trying to be so clever with cacheing; if nothing untoward is happening anyway, the less efficient technique will only add a few instruction cycles (one function call and a few derefs/assigns per list per iteration, with no change in the number of tests) and if something odd *is* going on, the code is now far more robust. * tests/basic.test (basic-39.4): Reproducable script from [Bug 494348] 2002-01-02 Donal K. Fellows * tests/util.test (Wrapper_Tcl_StringMatch,util-5.*): Rewrote so the test is performed with the right internal function since [string match] no longer uses Tcl_StringCaseMatch internally. * tests/string.test (string-11.51): * generic/tclUtf.c (Tcl_UniCharCaseMatch): * generic/tclUtil.c (Tcl_StringCaseMatch): Fault with matching case-insensitive non-ASCII patterns containing upper case characters. [Bug 233257] ****************************************************************** *** CHANGELOG ENTRIES FOR 2001 IN "ChangeLog.2001" *** *** CHANGELOG ENTRIES FOR 2000 IN "ChangeLog.2000" *** *** CHANGELOG ENTRIES FOR 1999 AND EARLIER IN "ChangeLog.1999" *** ****************************************************************** tcl8.4.20/ChangeLog.19990000644003604700454610000026106311737050674013113 0ustar dgp771div1999-12-22 Jeff Hobbs * changes: updated changes file * tools/tclSplash.bmp: updated to show 8.3 1999-12-21 Jeff Hobbs * README: * generic/tcl.h: * mac/README: * unix/configure.in: * tools/tcl.wse.in: * win/README.binary: * win/configure.in: updated to patch level 8.3b1 * unix/Makefile.in: added -srcdir=... for 'make html' * doc/Hash.3: fixed reference to ckfree [Bug: 3912] * doc/RegExp.3: fixed calling params for Tcl_RegExecFromObj * doc/open.n: fixed minor formatting errors * doc/string.n: fixed minor formatting errors * doc/lsort.n: added -unique docs * tests/cmdIL.test: * generic/tclCmdIL.c: added -unique option to lsort * generic/tclThreadTest.c: changed thread ids to longs [Bug: 3902] * mac/tclMacOSA.c: fixed applescript for I18N [Bug: 3644] * win/mkd.bat: * win/rmd.bat: removed necessity of tag.txt [Bug: 3874] * win/tclWinThrd.c: changed CreateThread to _beginthreadex and ExitThread to _endthreadex 1999-12-12 Jeff Hobbs * doc/glob.n: * tests/fileName.test: * generic/tclInt.decls: * generic/tclInt.h: * generic/tclIntDecls.h: * generic/tclStubInit.c: * generic/tclEncoding.c: * generic/tclFileName.c: * mac/tclMacFile.c: * unix/tclUnixFile.c: * win/tclWinFile.c: enhanced the glob command with the new options -types -path -directory and -join. Deprecated TclpMatchFiles with TclpMatchFilesTypes, extended TclGlob and TclDoGlob and added GlobTypeData structure. [Bug: 2363] 1999-12-10 Jeff Hobbs * tests/var.test: * generic/tclCompile.c: fixed problem where setting to {} array would intermittently not work. (Fontaine) [Bug: 3339] * generic/tclCmdMZ.c: * generic/tclExecute.c: optimized INST_TRY_CVT_TO_NUMERIC to recognize boolean objects. (Spjuth) [Bug: 2815] * tests/info.test: * tests/parseOld.test: * generic/tclCmdAH.c: * generic/tclProc.c: changed Tcl_UplevelObjCmd (uplevel) and Tcl_EvalObjCmd (eval) to use TCL_EVAL_DIRECT in the single arg case as well, to take advantage of potential pure list input optimization. This means that it won't get byte compiled though, which should be acceptable. * generic/tclBasic.c: made Tcl_EvalObjEx pure list object aware in the TCL_EVAL_DIRECT case for efficiency. * generic/tclUtil.c: made Tcl_ConcatObj pure list object aware, and return a list object in that case [Bug: 2098 2257] * generic/tclMain.c: changed Tcl_Main to not constantly reuse the commandPtr object (interactive case) as it could be shared. (Fellows) * unix/configure.in: * unix/tcl.m4: * unix/tclUnixPipe.c: removed checking for compatible vfork function and use of the vfork function. Modern VM systems rarely suffer any performance degradation when fork is used, and it solves multiple problems with vfork. Users that still want vfork can add -Dfork=vfork to the compile flags. [Bug: 942 2228 1312] 1999-12-09 Jeff Hobbs * win/aclocal.m4: made it just include tcl.m4 * doc/exec.n: * doc/open.n: * win/tclWin32Dll.c: * win/tclWinChan.c: * win/tclWinFCmd.c: * win/tclWinInit.c: * win/tclWinPipe.c: * win/tclWinSock.c: removed all code that supported Win32s. It was no longer officially supported, and likely didn't work anyway. * win/makefile.vc: removed 16 bit stuff, cleaned up. * win/tcl16.rc: * win/tclWin16.c: * win/winDumpExts.c: these files have been removed from the source tree (no longer necessary to build) 1999-12-07 Jeff Hobbs * tests/io.test: removed 'knownBug' tests that were for unsupported0, which is now fcopy (that already has tests) * mac/tclMacPort.h: added utime.h include * generic/tclDate.c: * unix/Makefile.in: fixed make gendate to swap const with CONST so it uses the Tcl defined CONST type [Bug: 3521] * generic/tclIO.c: removed panic that could occur in FlushChannel when a "blocking" channel would receive EAGAIN, instead treating it the same as non-blocking. [Bug: 3773] * generic/tclUtil.c: fixed Tcl_ScanCountedElement to not step beyond the end of the counted string [Bug: 3336] 1999-12-03 Jeff Hobbs * doc/load.n: added note about NT's buggy handling of './' with LoadLibrary * library/http2.1/http.tcl: fixed error handling in http::Event [Bug: 3752] * tests/env.test: removed knownBug limitation from working test * tests/all.tcl: ensured that ::tcltest::testsDirectory would be set to an absolute path * tests/expr-old.test: * tests/parseExpr.test: * tests/string.test: * generic/tclGet.c: * generic/tclInt.h: * generic/tclObj.c: * generic/tclParseExpr.c: * generic/tclUtil.c: * generic/tclExecute.c: added TclCheckBadOctal routine to enhance error message checking for when users use invalid octal numbers (like 08), as well as replumbed the Expr*Funcs with a new VerifyExprObjType to simplify type handling. [Bug: 2467] * tests/expr.test: * generic/tclCompile.c: fixed 'bad code length' error for 'expr + {[incr]}' case, with new test case [Bug: 3736] and seg fault on 'expr + {[error]}' (different cause) that was caused by a correct optimization that didn't correctly track how it was modifying the source string in the opt. The optimization was removed, which means that: expr 1 + {[string length abc]} will be not be compiled inline as before, but this should be written: expr {1 + [string length abc]} which will be compiled inline for speed. This prevents expr 1 + {[mindless error]} from seg faulting, and only affects optimizations for degenerate cases [Bug: 3737] 1999-12-01 Scott Redman * generic/tcl.decls : * generic/tclMain.c : * unix/tclAppInit.c: * win/tclAppInit.c: Added two new internal functions, TclSetStartupScriptFileName() and TclGetStartupScriptFileName() and added hooks into the main() code for supporting TclPro and other "big" shells more easily without requiring a copy of the main() code. * generic/tclEncoding.c: * generic/tclEvent.c: Moved encoding-related startup code from tclEvent.c into the more appropriate tclEncoding.c. 1999-11-30 Jeff Hobbs * generic/tclIO.c: fix from Kupries for Tcl_UnstackChannel that correctly handles resetting translation and encoding. * generic/tclLoad.c: #def'd out the unloading of DLLs at finalize time for Unix in TclFinalizeLoad. [Bug: 2560 3373] Should be parametrized to allow for user to specify unload or not. * win/tclWinTime.c: fixed handling of %Z on NT for time zones that don't have DST. 1999-11-29 Jeff Hobbs * library/dde1.1/pkgIndex.tcl: * library/reg1.0/pkgIndex.tcl: added supported for debugged versions of the libraries * unix/tclUnixPipe.c: fixed PipeBlockModeProc to properly set isNonBlocking flag on pipe. [Bug: 1356 710] removed spurious fcntl call from PipeBlockModeProc * tests/scan.test: * generic/tclScan.c: fixed scan where %[..] didn't match anything and added test case [Bug: 3700] 1999-11-24 Jeff Hobbs * doc/open.n: * win/tclWinSerial.c: adopted patch from Schroedter to handle fconfigure $sock -lasterror on Windows. [RFE: 3368] * generic/tclCmdIL.c: made SORTMODE_INTEGER work with Longs [Bug: 3652] 1999-11-23 Scott Stanton * library/tcltest1.0/tcltest.tcl: Fixed bug where tcltest output went to stdout instead of the specified output file in some cases. 1999-11-19 Jeff Hobbs * generic/tclProc.c: backed out change from 1999-11-18 as it could affect return string from upvar as well. * tools/tcl.wse.in: added tcltest1.0 library to distribution list * doc/http.n: * library/http2.1/http.tcl: * library/http2.1/pkgIndex.tcl: updated http package to 2.2 1999-11-18 Jeff Hobbs * unix/tcl.m4: added defined for _THREAD_SAFE in --enable-threads case; added check for pthread_mutex_init in libc; in AIX case, with --enable-threads ${CC}_r is used; fixed flags when using gcc on SCO * generic/tclProc.c: corrected error reporting for default case at the global level for uplevel command. * generic/tclIOSock.c: changed int to size_t type for len in TclSockMinimumBuffers. * generic/tclCkalloc.c: fixed Tcl_DbCkfree to return a value on NULL input. [Bug: 3400] * generic/tclStringObj.c: fixed support for passing in negative length to Tcl_SetUnicodeObj, et al handling routines. [Bug: 3380] * doc/scan.n: * tests/scan.test: * generic/tclScan.c: finished support for inline scan by supporting XPG identifiers. * doc/http.n: * library/http2.1/http.tcl: added register and unregister commands to http:: package (better support for tls/SSL), as well as -type argument to http::geturl. [RFE: 2617] * generic/tclBasic.c: removed extra decr of numLevels in Tcl_EvalObjEx that could cause seg fault. (mjansen@wendt.de) * generic/tclEvent.c: fixed possible lack of MutexUnlock in Tcl_DeleteExitHandler [Bug: 3545] * unix/tcl.m4: Added better pthreads library check and inclusion of _THREAD_SAFE in --enable-threads case Added support for gcc config on SCO * doc/glob.n: added note about ..../ glob behavior on Win9* * doc/tcltest.n: fixed minor example errors [Bug: 3551] 1999-11-17 Brent Welch * library/http2.1/http.tcl: Correctly fixed the -timeout problem mentioned in the 10-29 change. Also added error handling for failed writes on the socket during the protocol. 1999-11-09 Jeff Hobbs * doc/open.n: corrected docs for 'a' open mode. * generic/tclIOUtil.c: changed Tcl_Alloc to ckalloc * generic/tclInt.h: * generic/tclObj.c: rolled back changes from 1999-10-29 Purify noted new leaks with that code * generic/tclParse.c: added code in Tcl_ParseBraces to test for possible unbalanced open brace in a comment * library/init.tcl: removed the installed binary directory from the auto_path variable * tools/tcl.wse.in: updated to 8.3a1, fixed install of twind.tcl and koi8-r.enc files * unix/tcl.m4: added recognition of pthreads library for AIX 1999-10-29 Brent Welch * generic/tclInt.h: Modified the TclNewObj and TclDecrRefCount in two ways. First, in the case of TCL_THREADS, we do not use the special Tcl_Obj allocator because that is a source of lock contention. Second, general code cleanup to eliminate duplicated code. In particular, TclDecrRefCount now uses TclFreeObj instead of duplicating that code, so it is now identical to Tcl_DecrRefCount. * generic/tclObj.c: Changed Tcl_NewObj so it uses the TclNewObj macro instead of duplicating the code. Adjusted TclFreeObj so it understands the TCL_THREADS case described above. * library/http2.1/http.tcl: Fixed a bug in the handling of the state(status) variable when the -timeout flag is specified. Previously it was possible to leave the status undefined instead of empty, which caused errors in http::status 1999-10-28 Jeff Hobbs * unix/aclocal.m4: made it just include tcl.m4 * library/tcltest1.0/tcltest.tcl: updated makeFile to return full pathname of file created * generic/tclStringObj.c: fixed Tcl_AppendStringsToObjVA so it only iterates once over the va_list (avoiding a memcpy of it, which is not portable). * generic/tclEnv.c: fixed possible ABR error in environ array * tests/scan.test: * generic/tclScan.c: added support for use of inline scan, XPG3 currently not included * tests/incr.test: * tests/set.test: * generic/tclCompCmds.c: fixed improper bytecode handling of 'eval {set array($unknownvar) 5}' (also for incr) [Bug: 3184] * win/tclWinTest.c: added testvolumetype command, as atime is completely ignored for Windows FAT file systems * win/tclWinPort.h: added sys/utime.h to includes * unix/tclUnixPort.h: added utime.h to includes * doc/file.n: * tests/cmdAH.test: * generic/tclCmdAH.c: added time arguments to atime and mtime file command methods (support 'touch' functionality) 1999-10-20 Jeff Hobbs * unix/tclUnixNotfy.c: fixed event/io threading problems by making triggerPipe non-blocking [Bug: 2792] * library/tcltest1.0/tcltest.tcl: * generic/tclThreadTest.c: fixed mem leaks in threads * generic/tclResult.c: fixed Tcl_AppendResultVA so it only iterates once over the va_list (avoiding a memcpy of it, which is not portable). * generic/regc_color.c: fixed mem leak and assertion, from HS * generic/tclCompile.c: removed savedChar trick that appeared to be causing a segv when the literal table was released * tests/string.test: * generic/tclCmdMZ.c: fixed [string index] to return ByteArrayObj when indexing into one (test case string-5.16) [Bug: 2871] * library/http2.1/http.tcl: protected gets with catch [Bug: 2665] 1999-10-19 Jennifer Hom * tests/tcltest.test: * doc/tcltest.n: * library/tcltest1.0/tcltest.tcl: Removed the extra return at the end of the tcltest.tcl file, added version information about tcl. Applied patches sent in by Andreas Kupries to add helper procs for debug output, add 3 new flags (-testsdir, -load, -loadfile), and internally refactors common code for dealing with paths into separate procedures. [Bug: 2838, 2842] Merged code from core-8-2-1 branch that changes the checks for the value of tcl_interactive to also incorporate a check for the existence of the variable. * tests/autoMkindex.test: * tests/pkgMkIndex.test: Explicitly cd to ::tcltest::testsDirectory at the beginning of the test run * tests/basic.test: Use version information defined in tcltest instead of hardcoded version number * tests/socket.test: package require tcltest before attempting to use variable defined in tcltest namespace * tests/unixInit.test: * tests/unixNotfy.test: Added explicit exits needed to avoid problems when the tests area run in wish. 1999-10-12 Jim Ingham * mac/tclMacLoad.c: Stupid bug - we converted the filename to external, but used the unconverted version. * mac/tclMacFCmd.c: Fix a merge error in the bug fix for [Bug: 2869] 1999-10-12 Jeff Hobbs * generic/regc_color.c: * generic/regc_cvec.c: * generic/regc_lex.c: * generic/regc_locale.c: * generic/regcomp.c: * generic/regcustom.h: * generic/regerrs.h: * generic/regex.h: * generic/regexec.c: * generic/regguts.h: * generic/tclRegexp.c: * generic/tclTest.c: * tests/reg.test: updated to Henry Spencer's new regexp engine (mid-Sept 99). Should greatly reduce stack space reqs. * library/tcltest1.0/pkgIndex.tcl: fixed procs in pkgIndex.tcl file * generic/tclEnv.c: fixed mem leak with putenv and DStrings * doc/Encoding.3: corrected docs * tests/basic.test: updated test cases for 8.3 * tests/encoding.test: fixed test case that change system encoding to a double-byte one (this causes a bogus mem read error for purify) * unix/Makefile.in: purify has to use -best-effort to instrument * unix/tclAppInit.c: identified potential mem leak when compiling tcltest (not critical) * unix/tclUnixPipe.c: fixed mem leak in TclpCreateProcess when doing alloc between vfork and execvp. * unix/tclUnixTest.c: fixed mem leak in findexecutable test command 1999-10-05 Jeff Hobbs * {win,mac,unix,tools,}/README: * win/README.binary: * win/makefile.vc: * {win,unix}/configure.in: * generic/tcl.h: * library/init.tcl: updated to 8.3a1 from 8.2.0. * library/http2.1/http.tcl: fixed possible use of global c var. * win/tclWinReg.c: fixed registry command to properly 'get' HKEY_PERFORMANCE_DATA root key data. Needs more work. * generic/tclNamesp.c: * generic/tclVar.c: * generic/tclCmdIL.c: fixed comment typos * mac/tclMacFCmd.c: fixed filename stuff to support UTF-8 [Bug: 2869] * win/tclWinSerial.c: changed SerialSetOptionProc to return TCL_OK by default. (patch from Rolf Schroedter) 1999-09-21 Jennifer Hom * library/tcltest1.0/tcltest.tcl: Applied patches sent in by Andreas Kupries to fix typos in comments and ::tcltest::grep, fix hook redefinition problems, and change "string compare" to "string equal." [Bug: 2836, 2837, 2839, 2840] 1999-09-20 Jeff Hobbs * tests/env.test: * unix/Makefile.in: added support for AIX LIBPATH env var [Bug: 2793] removed second definition of INCLUDE_INSTALL_DIR (the one that referenced @includedir@) [Bug: 2805] * unix/dltest/Makefile.in: added -lc to LIBS [Bug: 2794] 1999-09-16 Jeff Hobbs * tests/timer.test: changed after delay in timer test 6.29 from 1 to 10. [Bug: 2796] * tests/pkg.test: * generic/tclPkg.c: fixed package version check to disallow 1.2..3 [Bug: 2539] * unix/Makefile.in: fixed gendate target - this never worked since RCS was intro'd. * generic/tclGetDate.y: updated to reflect previous changes to tclDate.c (leap year calc) and added CEST and UCT time zone recognition. Fixed 4 missing UCHAR() casts. [Bug: 2717, 954, 1245, 1249] * generic/tclCkalloc.c: changed Tcl_DumpActiveMemory to really dump to stderr and close it [Bug: 725] and changed Tcl_Ckrealloc and Tcl_Ckfree to not bomb when NULL was passed in [Bug: 1719] and changed Tcl_Alloc, et al to not panic when a alloc request for zero came through and NULL was returned (valid on AIX, Tru64) [Bug: 2795, etc] * tests/clock.test: * doc/clock.n: * generic/tclClock.c: added -milliseconds switch to clock clicks to guarantee that the return value of clicks is in the millisecs granularity [Bug: 2682, 1332] 1999-09-15 Jeff Hobbs * generic/tclIOCmd.c: fixed potential core dump in conjunction with stacked channels with result obj manipulation in Tcl_ReadChars [Bug: 2623] * tests/format.test: * generic/tclCmdAH.c: fixed translation of %0#s in format [Bug: 2605] * doc/msgcat.n: fixed \\ bug in example [Bug: 2548] * unix/tcl.m4: * unix/aclocal.m4: added fix for FreeBSD-[1-2] recognition [Bug: 2070] and fix for IRIX SHLIB_LB_LIBS. [Bug: 2610] * doc/array.n: * tests/var.test: * tests/set.test: * generic/tclVar.c: added an array unset operation, with docs and tests. Variation of [Bug: 1775]. Added fix in TclArraySet to check when trying to set in a non-existent namespace. [Bug: 2613] 1999-09-14 Jeff Hobbs * tests/linsert.test: * doc/linsert.n: * generic/tclCmdIL.c: fixed end-int interpretation of linsert to correctly calculate value for end, added test and docs [Bug: 2693] * doc/regexp.n: * doc/regsub.n: * tests/regexp.test: * generic/tclCmdMZ.c: add -start switch to regexp and regsub with docs and tests * doc/switch.n: added proper use of comments to example. * generic/tclCmdMZ.c: changed switch to complain when an error occurs that seems to be due to a misplaced comment. * generic/tclCmdMZ.c: fixed illegal ref for \[0-9] substitutions in regsub [Bug: 2723] * generic/tclCmdMZ.c: changed [string equal] to return an Int type object (was a Boolean) 1999-09-01 Jennifer Hom * library/tcltest1.0/tcltest.tcl: Process command-line arguments only ::tcltest doesn't have a child namespace (requires that command-line args are processed in that namespace) 1999-09-01 Jeff Hobbs * generic/tclParseExpr.c: changed '"' to '\"' to make FreeBSD happy [Bug: 2625] * generic/tclProc.c: moved static buf to better location and changed static msg that would overflow in ProcessProcResultCode [Bug: 2483] and added Tcl_DStringFree to Tcl_ProcObjCmd. Also reworked size of static buffers. * tests/stringObj.test: added test 9.11 * generic/tclStringObj.c: changed Tcl_AppendObjToObj to properly handle the 1-byte dest and mixed src case where both had had Unicode string len checks made on them. [Bug: 2678] * unix/aclocal.m4: * unix/tcl.m4: adjusted fix from 8-21 to add -bnoentry to the AIX-* case and readjusted the range 1999-08-31 Jennifer Hom * library/tcltest1.0/tcltest.tcl: * doc/tcltest.n: * tests/README: Modified testConstraints variable so that it isn't unset every time ::tcltest::initConstraints is called and cleaned up documentation in the README file and the man page. 1999-08-27 Jennifer Hom * tests/env.test: * tests/exec.test: * tests/io.test: * tests/event.test: * tests/tcltest.test: Added 'exit' calls to scripts that the tests themselves write, and removed accidental checkin of knownBugThreaded constraints for Solaris and Linux. * library/tcltest1.0/tcltest.tcl: Modified tcltest so that variables are only initialized to their default values if they did not previously exist. 1999-08-26 Jennifer Hom * tests/tcltest.test: * library/tcltest1.0/tcltest.tcl: Added a -args flag that sets a variable named ::tcltest::parameters based on whatever's being sent in as the argument to the -args flag. 1999-08-23 Jennifer Hom * tests/tcltest.test: Added additional tests for -tmpdir, marked all tests that use exec as unixOrPc. * tests/encoding.test: * tests/interp.test: * tests/macFCmd.test: * tests/parseOld.test: * tests/regexp.test: Applied patches from Jim Ingham to add encoding to a Mac only interp test, change an error message in macFCmd.tet, put a comment in parseOld.test, fix tests using the testencoding path command, and put unixOrPc constraints on tests that use exec. 1999-08-21 Jeff Hobbs * unix/aclocal.m4: Changed AIX-4.[2-9] check to AIX-4.[1-9] [Bug: 1909] 1999-08-20 Jeff Hobbs * generic/tclPosixStr.c: fixed typo [Bug: 2592] * doc/*: fixed various nroff bugs in man pages [Bug: 2503 2588] 1999-08-19 Jeff Hobbs * win/README.binary: fixed version info and some typos [Bug: 2561] * doc/interp.n: updated list of commands available in a safe interpreter [Bug: 2526] * generic/tclIO.c: changed Tcl_GetChannelNames* to use style guide headers (pleases HP cc) 1999-08-18 Jeff Hobbs * doc/Eval.3: fixed doc on input args [Bug: 2114] * doc/OpenFileChnl.3: * doc/file.n: * tests/cmdAH.test: * tclIO.c: * tclCmdAH.c: added "file channels ?pattern?" tcl command, with associated Tcl_GetChannelNames and Tcl_GetChannelNamesEx public C APIs (added to tcl.decls as well), with docs and tests. * tests/expr.test: * generic/tclCompile.c: add TCL_TOKEN_VARIABLE to the part types that cause differed compilation for exprs, to correct the expr double-evaluation problem for vars. Added test cases. Related to [Bug: 732] * unix/Makefile.in: changed the dependency structure so that install-* is dependent on * (ie - install-binaries is dependent on binaries). * library/auto.tcl: * library/init.tcl: * library/ldAout.tcl: * library/package.tcl: * library/safe.tcl: * library/word.tcl: * library/http2.1/http.tcl: * library/msgcat1.0/msgcat.tcl: updated libraries to better Tcl style guide (no more string comparisons with == or !=, spacing changes). 1999-08-05 Jim Ingham * mac/tclMacProjects.sea.hqx: Rearrange the projects so that the build directory is separate from the sources. Much more convenient! 1999-08-13 Scott Redman * /: 8.2.0 tagged for final release 1999-08-12 Scott Stanton * win/Makefile.in: Added COMPILE_DEBUG_FLAGS macro to make it easier to turn on compiler tracing. * tests/parse.test: * generic/tclParse.c: Fixed bug in Tcl_EvalEx where the termOffset was not being updated in cases where the evaluation returned a non TCL_OK error code. [Bug: 2535] 1999-08-12 Scott Redman * win/tclWinSerial.c: Applied patch from Petteri Kettunen to remove compiler warning. 1999-08-10 Scott Redman * generic/tclAlloc.c: * generic/tclCmdIL.c: * generic/tclIO.c: * generic/tclThread.c: * win/tclWinThrd.c: * unix/tclUnixThrd.c: Fixed Brent's changes so that they work on Windows (and he fixed the bug in the Unix thread implementation). 1999-08-09 Brent Welch * generic/tcl.decls: * generic/tclAlloc.c: * generic/tclCkalloc.c: * generic/tclCmdIL.c: * generic/tclDecls.h: * generic/tclIO.c: * generic/tclInt.decls: * generic/tclIntDecls.h: * generic/tclStubInit.c: * generic/tclVar.c: * mac/tclMacThrd.c: * unix/tclUnixThrd.c: * win/tclWinThrd.c: Added use of Tcl_GetAllocMutex to tclAlloc.c and tclCkalloc.c so they can be linked against alternate thread packages. Added Tcl_GetChannelNames to tclIO.c. Added TclVarTraceExists hook so "info exists" triggers read traces exactly like it did in Tcl 7.6. Stubs table changes to reflect new internal and external APIs. 1999-08-09 Jeff Hobbs * tests/string.test: added largest_int proc to adapt for >32 bit machines and int overflow testing. * tests/tcltest.test: fixed minor error in 8.2 result (from dgp) * doc/Object.3: clarified Tcl_DecrRefCount docs [Bug: 1952] * doc/array.n: clarified array pattern docs [Bug: 1330] * doc/clock.n: fixed clock docs [Bug: 693] * doc/lindex.n: clarified to account for new end-int behavior. * doc/string.n: fixed formatting errors [Bug: 2188 2189] * doc/tclvars.n: fixed doc error [Bug: 2042] * library/init.tcl: fixed path handling in auto_execok (it could miss including the normal path on some Windows machines) [Bug: 1276] 1999-08-05 Jeff Hobbs * doc/tclvars.n: Made it clear that tcl_pkgPath was not set for Windows (already mentioned in init.tcl) [Bug: 2455] * generic/tclLiteral.c: fixed reference to bytes that might not be null terminated (using objPtr->bytes, which is) [Bug: 2496] * library/http2.1/http.tcl: Made use of "i" in init section use local var and start at 0 (was 1). [Bug: 2502] 1999-08-04 Scott Stanton * tests/reg.test: Added test for REG_EXPECT bug fixed by Henry's patch. * generic/regc_nfa.c: * generic/regcomp.c: * generic/rege_dfa.c: * generic/regexec.c: * generic/regguts.h: Applied patches supplied by Henry Spencer to greatly enhance the performance of certain classes of regular expressions. [Bug: 2440, 2447] 1999-08-03 Scott Redman * win/tclWinInt.h: Remove function declarations in header that was moved to tclInt.decls file in previous changes. 1999-08-02 Scott Redman * unix/configure.in: * win/configure.in: Change beta level to b2. * generic/tcl.h: * generic/tcl.decls: * generic/tclDecls.h: * generic/tclInt.h: * generic/tclInt.decls: * generic/tclIntDecls.h: * generic/tclRegexp.h: * generic/tclStubInit.c: Move some exported public and internal functions to the stub tables. Removed functions that are in the stub tables (from this and previous changes) from the original header files. 1999-08-01 Scott Redman * win/tclWinSock.c: Added comment block to SocketThread() function. Added code to avoid calling TerminateThread(), but instead to send a message to the socket event window to tell it to terminate its thread. 1999-07-30 Jennifer Hom * tests/tcltest.test: * library/tcltest1.0/tcltest.tcl: Exit with non-zero status if there were problems with the way the test suite was started (e.g. wrong # arguments). 1999-07-30 Jeff Hobbs * generic/tclInt.decls: added declaractions necessary for the Tcl test code to work wth stubs [Bug: 2445] 1999-07-30 * win/tclWinPipe.c: * win/Makefile.in: Fixing launching of 16-bit apps on Win9x from wish. The command line was primed with tclpip82.dll, but it was ignored. Fixed that, then fixed the gmake makefile to build tclpip82.dll as an executable. * win/tclWinSock.c: Applied small patch to get thread-specific data after initializing the socket driver. * unix/tclUnixThrd.c: Applied patch to fix threads on Irix 6.5. Patch from James Dennett. [Bug: 2450] * tests/info.test: Enable test for tclParse.c change (info complete). 1999-07-30 * tclIO.c: added fix for Kupries' trf patch [Bug: 2386] * tclParse.c: fixed bug in info complete regarding nested square brackets [Bug: 2382, 2466] 1999-07-29 * win/tclWinChan.c: Allow tcl to open CON and NUL, even for std channels. Checking for bad/unusable std channels was moved to Tk since its only purpose was to check whether to use the Tk Console Window for the std channels. [Bug: 2393 2392 2209 2458] * unix/mkLinks.tcl: Applied patch to avoid linking pack.n to pack-old.n. Patch from Don Porter. [Bug: 2469] * doc/Encoding.n: Applied patch to fix typo in .SH NAME line. Patch from Don Porter. [Bug: 2451] * win/tclWinSock.c: Free Win32 Event handles when destroying the socket helper thread. 1999-07-28 * tests/tcltest.test: * library/tcltest1.0/tcltest.tcl: Fixed the condition under which ::tcltest::PrintError had an infinite loop problem and added a test case for it. Added an optional argument to ::tcltest::getMatchingFiles telling it where to search for test files. 1999-07-27 * tools/tclSplash.bmp: Updated Windows installer bitmap to ready Tcl/Tk Version 8.2. 1999-07-26 * tests/tcltest.test: Need to close the new core file, there seems to be a hang in threaded WinNT if the file isn't closed. Open issue, need to fix that hang. * tests/httpold.test: Add time delay in response from Http server so that test cases can properly detect timeout conditions with threads enabled on multi-CPU WinNT. * tests/winFCmd.test: Test case winFcmd-1.33 was looking for c:\windows, which may not exist. Instead, create a new directory on c:\ and use it for the test. * win/tclWinConsole.c: * win/tclWinPipe.c: * win/tclWinSock.c: Fix terminating helper threads by holding any mutexes from the primary thread while waiting for the helper thread to terminate. Without these changes, the test suite hangs on WinNT with 2 CPUs and threads enabled. Open issue, seems to be a sporadic hang on dual CPU systems still (very rare). 1999-07-26 Jennifer Hom * tests/tcltest.test: * library/tcltest1.0/tcltest.tcl: * doc/tcltest.n: Cleaned up code in ::tcltest::PrintError, revised documentation, and added tests for the tcltest package. 1999-07-23 * tests/info.test: * generic/tclParse.c: Removed patch for info command, breaks test cases on Unix. Patch was bad and needs to be redone properly. [Bug: 2382] 1999-07-22 * Changed version to 8.2b2. * win/tclWinSock.c: Fixed hang with threads enabled, fixed semaphores with threads disabled. * win/safe.test: Fixed safe-6.3 with threads enabled. * win/Makefile.in: Fixed calling of tcltest to fix safe.test failures due to path TCL_LIBRARY path. * win/tclWinPort.h: Block out include of sys/*.h in order to build extensions with MetroWerks compiler for Win32. [Bug: 2385] * generic/tclCmdMZ.c: * generic/tclIO.c: Fix ANSI-style prototypes based on patch from Ulrich Ring. [Bug: 2391] * unix/Makefile.in: Need to make install-sh executable before calling (with chmod +x). [Bug: 2413] * tests/var.test: * generic/tclVar.c: Fixed bug that caused a seg. fault when using "array set a(b) {}", which is a bad array name anyway. Now the "array set" command will return an error in this case. Added test case and fixed existing test. [Bug: 2427] 1999-07-21 * tests/info.test: * generic/tclParse.c: Applied patch to fix "info complete" for the string {[a [b]}. Patch from Peter Spjuth. [Bug: 2382] * doc/Utf.3: * generic/tcl.decls: * generic/tclDecls.h: * generic/tclUtf.c: Changed function declarations in non-platform-specific public APIs to use "unsigned long" instead of "size_t", which may not be defined on certain compilers (rather than include sys/types.h, which may not exist). * unix/Makefile.in: Added the Windows configure script to the distribution file list, already shipping configure.in and the .m4 files, but needed the configure script itself. * win/makefile.vc: Changed version number of DDE package in VC++ makefile to use 1.1 instead of 1.0. * doc/open.n: Added documentation of \\.\comX notation for opening serial ports on Windows (alternative to comX:). * tests/ioCmd.test: * doc/open.n: * win/tclWinSerial.c: Applied patch from Rolf Schroedter to add -pollinterval option to fconfigure to modify the maxblocktime used in the fileevent polling. Added documentation and fixed the test case as well. * win/tclWinSock.c: Modified 8.1.0 version of the Win32 socket driver to move the handling of the socket event window in a separate thread. It also turned out that Win95 & Win98 were, in some cases, getting multiple FD_ACCEPTs but only handling one. Added a count for the FD_ACCEPT to take care of this. Tested on NT4 SP3, NT4 SP4, Win95, and Win98. [Bug: 2178 2256 2259 2329 2323 2355] 1999-07-21 * README: Small tweaks to clean up typos and wording. 1999-07-20 Melissa Hirschl * generic/tclInitScript.h: * unix/tclUnixInit.c: merged code with 8.0.5. We now use an intermediate global tcl var "tclDefaultLibrary" to keep the "tcl_library" var from being set by the default value in the Makefile. Also fixed a bug in which caused the value of TCL_LIBRARY env var to be ignored. * unix/tclWinInit.c: just updated some comments. 1999-07-19 Melissa Hirschl * library/http2.1/http.tcl: updated -useragent text to say version 2.1. 1999-07-16 * generic/tcl.decls: * generic/tclDecls.h: * generic/tclStubInit.c: Add Tcl_SetNotifier to stub table. [Bug: 2364] * unix/aclocal.m4: * unix/tcl.m4: Add check for Alpha/Linux to correct the IEEE floating flag to the compiler, should be -mieee. Patch from Don Porter. * tools/tcl.hpj.in: Change version number of .cnt file referenced in .HPJ file. 1999-07-15 * tools/tcl.wse.in: Fixed naming of target files for Windows. 1999-07-14 * doc/re_syntax.n: Deleted sentence as suggested by Scott S. 1999-07-12 * doc/re_syntax.n: Removed two notes to myself (oops), cleaned up wording, fixed changebars, made two examples easier to read. 1999-07-11 * win/makefile.vc: Since the makefile.vc should continue to work while we're working out bugs/issues in the new TEA-style autoconf/configure/gmake build mechanism for Windows, the version numbers of the Tcl libraries need to remain in sync. Modified the version numbers in the makefile to reflect the change to 8.2b1. 1999-07-09 * win/configure.in: Eval DLLSUFFIX, LIBSUFFIX, and EXESUFFIX in the configure script so that substitutions get expanded before being placed in the Makefile. The "d" portion for debug libraries and DLLs was not being set properly. 1999-07-08 * tests/string.test: * generic/tclCmdMZ.c: Fixed bug in string range bounds checking code. 1999-07-08 Jennifer Hom * doc/tcltest.n: * library/tcltest1.0/tcltest.tcl: Removed -asidefromdir and -relateddir flags, removed unused ::tcltest::dotests proc, cleaned up implementation of core file checking, and fixed the code that checks for 1-letter flag abbreviations. 1999-07-08 * win/Makefile.in: Added tcltest target so runtest works properly. Added missing names to the clean/distclean targets. * tests/reg.test: * generic/rege_dfa.c: Applied fix supplied by Henry Spencer for bug in DFA state caching under lookahead conditions. [Bug: 2318] 1999-07-07 * doc/fconfigure.n: Clarified default buffering behavior for the standard channels. [Bug: 2335] 1999-07-06 * win/tclWinSerial.c: New implementation of serial port driver from Rolf Shroedter (Rolf.Schroedter@dlr.de) that allows more than one byte to be read from the port. Implemented using polling instead of threads, there is a max. 10ms latency between checking the port for file events. [Bug: 1980 2217] 1999-07-06 * library/http2.0/http.tcl: Fixed the -timeout option so it handles timeouts that occur during connection attempts to hosts that are down (the only case that really matters!) 1999-07-03 * doc/ChnlStack.3: * generic/tcl.decls: * generic/tclIO.c: Added a new variant of the "Trf patch" from Andreas Kupres that adds new C APIs Tcl_StackChannel, Tcl_UnstackChannel, and Tcl_GetStackedChannel. 1999-07-03 * generic/tclNotify.c: * unix/tclUnixNotfy.c: * unix/tclXtTest.c: * unix/tclXtNotify.c: * win/tclWinNotify.c: * mac/tclMacNotify.c: Added Tcl_SetNotifier and the associated hook points in the notifiers to be able to replace the notifier calls at runtime The Xt notifier and test program use this hook. 1999-07-03 * generic/tclParse.c: Changed parsing of variable names to allow empty array names. Now "$(foo)" is a variable reference! Previous you had to use something like $::(foo), which is slower. This change is requested by Jean-Luc Fontaine for his STOOOP package. 1999-07-01 * generic/tclCmdAH.c: * generic/tclFCmd.c: Call TclStat instead of TclpStat in order to allow Tcl_Stat hooks to work properly. 1999-06-29 Jennifer Hom * library/tcltest1.0/pkgIndex.tcl: * library/tcltest1.0/tcltest.tcl: * doc/tcltest.n: * tests/all.tcl: Added -preservecore, -limitconstraints, -help, -file, -notfile, -relateddir and -asidefromdir flags to the tcltest package along with exported proc ::tcltest::getMatchingFiles. The documentation was modified to match and all.tcl was modified to use the new functionality instead of implementing -file itself. 1999-06-28 * generic/tclIndexObj.c: * doc/GetIndex.3: * tests/binary.test: * tests/winDde.test: Applied patch from Peter Hardie (with changes) to fix problem with Tcl_GetIndexFromObj() when the key being passed is the empty string. It used to match "" and return TCL_OK, but it should have returned TCL_ERROR instead. Added test case to "binary" and "dde" commands to check the behavior. Added documentation note as well. 1999-06-26 * win/tclWinDde.c: Applied patch from Peter Hardie to add poke command to dde. Also rev'd version of dde package to 1.1. [Bug: 1738] 1999-06-25 Jennifer Hom * unix/Makefile.in: * win/Makefile.in: * library/tcltest1.0/pkgIndex.tcl: * library/tcltest1.0/tcltest.tcl: * library/tcltest1.0: Added initial implementation of the Tcl test harness package. This package was based on the defs.tcl file that was part of the tests directory. Reversed the way that tests were evaluated to fix a problem with false passes. * doc/tcltest.n: Added documentation for the tcltest package. * tests/README: * tests/defs.tcl: * tests/all.tcl: Modified all test files (tests/*.test) and all.tcl to use the new tcltest package and removed references to the defs.tcl file. Modified the README file to point to the man page for tcltest. 1999-06-25 * tests/reg.test: * generic/regexec.c: Fixed bugs in non-greedy quantifiers. 1999-06-23 * doc/re_syntax.n: * doc/switch.n: * doc/lsearch.n: * doc/RegExp.3: * doc/regexp.n: * doc/regsub.n: Moved information about syntax of 8.1 regular expressions from regexp(n) manpage into new re_syntax(n) page. Added pointers from other manpages to new re_syntax(n) page. 1999-06-23 * unix/Makefile.in: Changed install-doc to install-man. * tools/uniParse.tcl: * tools/uniClass.tcl: * tools/README: * tests/string.test: * generic/regc_locale.c: * generic/tclUniData.c: * generic/tclUtf.c: * doc/string.n: Updated Unicode character tables to reflect latest Unicode 2.1 data. Also rationalized "regexp" and "string is" definitions of character classes. 1999-06-21 * unix/tclUnixThrd.c (TclpThreadCreate): Fixed memory leak where thread attributes were not being released. [Bug: 2254] 1999-06-17 * tests/regexp.test: * generic/tclCmdMZ.c: * generic/tclCmdIL.c: Changed to use new regexp interfaces. Added -expanded, -line, -linestop, and -lineanchor switches to regsub. * doc/RegExp.3: Documented the new regexp interfaces and the compile/execute flags. * generic/tclTest.c: * generic/tclRegexp.h: * generic/tclRegexp.c: * generic/tcl.h: * generic/tcl.decls: Renamed Tcl_RegExpMatchObj to Tcl_RegExpExecObj and added a new Tcl_RegExpMatchObj that is equivalent to Tcl_RegExpMatch. Added public macros for the regexp compile/execute flags. Changed to store either an object pointer or a string pointer in the TclRegexp structure. Changed to avoid adding a reference to the object or copying the string. * generic/regcomp.c: lint * tests/reg.test: * generic/regex.h: * generic/regc_lex.c: Added REG_BOSONLY flag to allow Expect to iterate through a string an only find matches that start at the current position within the string. 1999-06-16 * unix/configure.in: * unix/Makefile.in: * unix/tcl.m4: * unix/aclocal.m4: Numerous build changes to make Tcl conform to the proposed TEA spec 1999-06-16 Melissa Hirschl * generic/tclVar.c (Tcl_VariableObjCmd): fixed premature increment in loop that was causing out-of-bounds reads on array "varName". 1999-06-16 * tests/execute.test: * generic/tclExecute.c (TclExecuteByteCode): Fixed crash caused by a bug in INST_LOAD_SCALAR1 where the scalar index was read as a signed 1 byte value instead of unsigned. [Bug: 2243] 1999-06-14 Melissa Hirschl * doc/StringObj.3 * test/stringObj.test * unix/Makefile.in * win/Makefile.in * win/makefile.vc * generic/tclStringObj.c: Merged String and Unicode object types. Added new functions to the puplic API: Tcl_NewUnicodeObj, Tcl_SetUnicodeObj, Tcl_GetUnicode, Tcl_GetUniChar, Tcl_GetCharLength, Tcl_GetRange, Tcl_AppendUnicodeToObj. 1999-06-09 * generic/tclUnicodeObj.c: Lots of cleanup and simplification. Fixed several memory bugs. Added TclAppendUnicodeToObj. * generic/tclInt.h: Added declarations for various Unicode string functions. * generic/tclRegexp.c: * generic/tclCmdMZ.c: Changed to use new Unicode string interfaces for better performance. * generic/tclRegexp.h: * generic/tclRegexp.c: * generic/tcl.h: * generic/tcl.decls: Added Tcl_RegExpMatchObj and Tcl_RegExpGetInfo calls to access lower level regexp API. These features are needed by Expect. This is a preliminary implementation pending final review and cleanup. * generic/tclCmdMZ.c: * tests/string.test: Fixed bug where string map failed on null strings. * generic/regexec.c: * unix/tclUnixNotfy.c: lint * tools/genStubs.tcl: Changed to always write output in LF mode. 1999-06-08 * win/tclWinSock.c: Rolled back to the 8.1.0 implementation because of serious problems with the new driver. Basically no incoming socket connections would be reported to a server port. The 8.1.1 code needs to be redesigned and fixed correctly. 1999-06-07 Melissa Hirschl * tests/string.test: * generic/tclVar.c (Tcl_SetVar2Ex): * generic/tclStringObj.c (Tcl_AppendObjToObj): * generic/tclCmdMZ.c (Tcl_StringObjCmd): optimized the string index, string length, string range, and append command in cases where the object's internal rep is a bytearray. Objects with other internal reps are converted to have the new unicode internal rep. * unix/Makefile.in: * win/Makefile.in: * win/Makefile.vc: * tests/unicode.test: * generic/tclInt.h: * generic/tclObj.c: * generic/tclUnicodeObj.c: added a new object type to store the unicode representation of a string. * generic/tclTestObj.c: added the objtype option to the testobj command. This option returns the name of the type of internal rep an object has. 1999-06-04 * win/configure.in: * win/Makefile.in: Windows build now handles static/dynamic debug/nodebug builds and supports the standard targets using Cygwin user tools plus GNU make and autoconf. 1999-06-03 * generic/tclCmdMZ.c (Tcl_StringObjCmd): * tests/string.test: Fixed bug where string equal/compare -nocase reported wrong result on null strings. [Bug: 2138] 1999-06-02 * generic/tclUtf.c (Tcl_UtfNcasecmp): Fixed incorrect computation of relative ordering. [Bug: 2135] 1999-06-01 * unix/configure.in: Fixed various small configure.in patches submitted by Jan Nijtmans. [Bug: 2121] * tests/reg.test: * generic/regc_color.c: * generic/regc_cvec.c: * generic/regc_lex.c: * generic/regc_locale.c: * generic/regc_nfa.c: * generic/regcomp.c: * generic/regcustom.h: * generic/rege_dfa.c: * generic/regerror.c: * generic/regerrs.h: * generic/regex.h: * generic/regexec.c: * generic/regfree.c: * generic/regfronts.c: * generic/regguts.h: * generic/tclCmdMZ.c: * generic/tclRegexp.c: * generic/tclRegexp.h: * generic/tclTest.c: Applied Henry Spencer's latest regexp patches that fix an infinite loop bug and add support for testing whether a string could match with additional input. [Bug: 2117] 1999-05-28 * generic/tclObj.c: Changed to eliminate use of isupper/tolower in favor of the Unicode versions. * win/Makefile.in: * win/configure.in: Added preliminary TEA implementation. * win/tclWinDde.c: Fixed bug where dde calls were being passed an invalid dde handle because Initialize had not been called. [Bug: 2124] 1999-05-26 * generic/tclThreadTest.c: Fixed race condition in testthread code that showed up in the WinNT test suite intermittently. * win/tclWinSock.c: Fixed a hang in the WinNT socket driver, wake up the socket thread every 100ms to check for events on the sockets that did not wake up the thread (race condition). 1999-05-24 * tools/genStubs.tcl: Changed to allow a list of platforms instead of just one at a time. * generic/tcl.decls: * generic/tclCmdMZ.c: * generic/tclDecls.h: * generic/tclInt.decls: * generic/tclIntDecls.h: * generic/tclPort.h: * generic/tclStubInit.c: * generic/tclStubLib.c: Various header file related changes and other lint to try to get the Mac builds working. 1999-05-21 * win/tclWinPipe.c: Fix bug when launching command.com on Win95/98. Need to wait for the procInfo.hProcess of the process that was created, not the hProcess of the current process. [Bug: 2105] 1999-05-20 * library/init.tcl: Add the directory where the executable is, and the ../lib directory relative to that, to the auto_path variable. 1999-05-19 Merged in various changes submitted by Jeff Hobbs: * generic/tcl.decls: * generic/tclUtf.c: Added Tcl_UniCharIs* functions for control, graph, print, and punct classes. * generic/tclUtil.c: * doc/StrMatch.3: Added Tcl_StringCaseMatch() implementation to support case-insensitive globbing. * doc/string.n: * unix/mkLinks: * tests/string.test: * generic/tclCmdMZ.c: Added additional character class tests, added -nocase switch to "string match", changed string first/last to use offsets. 1999-05-19 * generic/tcl.h: Add extern "C" block around entire header file for C++ compilers to fix linkage issues. Submitted by Don Porter and Paul Duffin. * generic/tclRegexp.c: Fix bug when the regexp cache is empty and an empty pattern is used in regexp ( such as {} or "" ). 1999-05-18 * win/tclWinChan.c: Modified initialization code to avoid inherenting closed or invalid channels. If the standard input is anything other than a console, file, serial port, or pipe, then we fall back to the standard Tk window console. 1999-05-14 * generic/tclCmdAH.c (Tcl_ForObjCmd): Fixed crash caused by failure to reset the result before evaluating the test expression. 1999-05-14 * generic/tclBasic.c (Tcl_CreateInterp): Added introspection variable for threaded interps. If the interp was compiled with threads enabled, the tcl_platform(threaded) variable will exist. 1999-05-14 * generic/tclDate.c: Applied patch to fix 100-year and 400-year boundaries in leap year code, from Isaac Hollander. [Bug: 2066] 1999-05-13 * unix/Makefile.in: * unix/tclAppInit.c: Minor cleanup related to Xt notifier. * unix/tclUnixInit.c (TclpSetInitialEncodings): Tcl now looks for an encoding subfield in the LANG/LC_ALL variables in cases where the locale is not found in the locale table. Ensure that setlocale() is called at least once so X11 will initialize properly. Also, forces the LC_NUMERIC locale to be "C" so numeric processing in scripts is not affected by the current locale setting. [Bug: 1989] * generic/tclRegexp.c: Increased per-thread regexp cache to 30 slots. This seems to be about the right number for larger applications like exmh. [Bug: 1063] 1999-05-12 * doc/tclsh.1: Updated references to rc script names to accurately reflect the platform differences on Windows. * tests/regexp.test: * generic/tclInt.h: * generic/tclBasic.c: * generic/tclRegexp.h: * generic/tclRegexp.c: Replaced the per-interpreter regexp cache with a per-thread cache. Changed the Regexp object to take advantage of this extra cache. Added a reference count to the TclRegexp type so regexps can be shared by multiple objects. Removed the per-interp regexp cache from the interpreter. Now regexps can be used with no need for an interpreter. [Bug: 1063] * win/tclWinInit.c (TclpSetVariables): Avoid calling GetUserName if the value can be determined from the USERNAME environment variable. GetUserName is very slow. 1999-05-07 * win/winDumpExts.c: * win/makefile.vc: Removed incorrect patch. [Bug: 1998] * generic/tcl.decls: Replaced const with CONST. * generic/tclResult.c (Tcl_AppendResultVA): * generic/tclStringObj.c (Tcl_AppendStringsToObjVA): Fixed to copy arglist using memcpy instead of assignment so it works properly on OS/390. [Bug: 1997] * generic/tclLoadNone.c: Updated to use current interfaces, added TclpUnloadFile. [Bug: 2003] * win/winDumpExts.c: * win/makefile.vc: Changed to emit library name in defs file. [Bug: 1998] * unix/configure.in: Added fix for OS/390. [Bug: 1976] 1999-05-06 * tests/string.test: * generic/tclCmdMZ.c: * doc/string.n: Fixed bug in string equal/compare code when using -length option. Cleaned up docs a bit more. * tests/http.test: Unset "data" array before running tests to avoid failures due to previous tests. * doc/string.n: * tests/cmdIL.test: * tests/cmdMZ.test: * tests/error.test: * tests/ioCmd.test: * tests/lindex.test: * tests/linsert.test: * tests/lrange.test: * tests/lreplace.test: * tests/string.test: * tests/cmdIL.test: * generic/tclUtil.c: * generic/tclCmdMZ.c: Replaced "string icompare/iequal" with -nocase and -length switches to "string compare/equal". Added a -nocase option to "string map". Changed index syntax to allow integer or end?-integer? instead of a full expression. This is much simpler with safeTcl scripts since it avoids double substitution issues. * doc/Utf.3: * generic/tclStubInit.c: * generic/tclDecls.h: * generic/tclUtf.c: * generic/tcl.decls: Added Tcl_UtfNcmp and Tcl_UtfNcasecmp. 1999-05-05 * win/makefile.vc: Added encoding directory to install-libraries target. 1999-05-03 * doc/string.n: * tests/cmdMZ.test: * tests/string.test: * generic/tclCmdMZ.c (Tcl_StringObjCmd): Changed "string length" to avoid regenerating the string rep of a ByteArray object. * tests/cmdIL.test: * tests/cmdMZ.test: * tests/error.test: * tests/lindex.test: * tests/linsert.test: * tests/lrange.test: * tests/lreplace.test: * tests/string.test: * generic/tclCmdMZ.c (Tcl_StringObjCmd): * generic/tclUtil.c (TclGetIntForIndex): Applied Jeff Hobbs's string patch which includes the following changes [Bug: 1845]: - string compare now takes optional length arg (for strncmp behavior) - added string equal (just a few lines of code blended in with string compare) - added string icompare/iequal for case-insensitive comparisons - string index's index can now be ?end[+-]?expression I made this change in the private TclGetIntForIndex, which means that the list commands also benefit, as well as string range, et al. - added [string repeat string count] Repeats given string number of times - added string replace, string equiv to lreplace (quasi opposite of string range): string replace first last ?string? Example of use, replacing end of string with ... should the string be more than 16 chars long: string replace $string 16 end "..." This just returns the string len < 16, so it will only affect the long strings. - added optional first and last args to string to* This allows you to just affect certain regions of a string with the command (like just capping the first letter). I found the original totitle to be too draconian to be useful. - added [string map charMap string] where charMap is a {from to from to} list that equates to what one might get from [array get]. Each and can be multiple chars (or none at all). For Tcl/CGI users, this is a MAJOR speed booster. * generic/tclParse.c (Tcl_ParseCommand): Changed to avoid modifying eval'ed strings that are already null terminated. [Bug: 1793] * tests/binary.test: * generic/tclBinary.c (DupByteArrayInternalRep): Fixed bug where type was not being set in duplicated object. [Bug: 1975, 2047] 1999-04-30 * Changed version to 8.1.1. 1999-04-30 * Merged changes from 8.1.0 branch: * generic/tclParse.c: Fixed memory leak in CommandComplete. * generic/tclPlatDecls.h: * generic/tclIntPlatDecls.h: * generic/tclIntDecls.h: * generic/tclDecls.h: * tools/genStubs.tcl: Added 'extern "C" {}' block around the stub table pointer declaration so the stub library can be used from C++. [Bug: 1934] * Lots of documentation and other release engineering fixes. 1999-04-28 * mac/tclMacResource.c: * generic/tclListObj.c: * generic/tclObj.c: * generic/tclStringObj.c: Changed to avoid freeing the string representation before freeing the internal rep. This helps with debugging since the string rep will still be valid when the free proc is invoked. 1999-04-27 * generic/tclLiteral.c (TclHideLiteral): Fixed so hidden literals get duplicated to avoid accidental sharing in the global object table. 1999-04-23 * generic/tclStubInit.c: * tools/genStubs.tcl: Changed to avoid the need for forward declarations in stub initializers. 1999-04-23 * library/encoding/koi8-r.enc: * tools/encoding/koi8-r.txt: Added support for the koi8-r Cyrillic encoding. [Bug: 1771] 1999-04-22 * win/tclWinFCmd.c: * win/tclWin32Dll.c: Changed uses of "try" to "__try", since that is the actual keyword. This eliminates the need for some -D flags from the makefile. * generic/tclPort.h: Added include of tcl.h since it defines various Windows macros that are needed before deciding which platform porting file to use. * generic/tclEvent.c: lint * win/tclWinInit.c (TclpInitPlatform): Added call to TclWinInit when building a static library since DllMain will not be invoked. This could break old code that explicitly called TclWinInit, but should be simpler in the long run. 1999-04-22 Scott Stanton * generic/tclInt.h: * generic/tclInt.decls: * generic/tclCompile.c: Added TclSetByteCodeFromAny that takes a hook procedure to invoke after compilation but before the byte codes are emitted. This makes it possible to do postprocessing on the compiled byte codes before the ByteCode is generated. * generic/tclLiteral.c: Added TclHideLiteral and TclAddLiteralObj to make it possible to create local unshared literal objects. * win/tclWinInit.c: * unix/tclUnixInit.c: Changed initial search path to match that found used by tcl_findLibrary. 1999-04-22 * win/tclWinPort.h: * win/tclWinSock.c: Added code to use WinSock 2.0 API on NT to avoid creating a window to handle sockets. API not available on Win95 and needs to be fixed on Win98, until then continue to use the older (window-based) scheme on those two OSes. 1999-04-15 * Merged 8.1 back into the main trunk 1999-04-13 * library/encoding/gb2312.enc: * library/encoding/euc-cn.enc: * tools/encoding/gb2312.txt: * tools/encoding/cp950.txt: * tools/encoding/Makefile: Restored the double byte definition of GB2312 and added the EUC-CN encoding. EUC-CN is a variant of GB2312 that shifts the characters into bytes with the high bit set and includes ASCII as a subset. [Bug: 632] 1999-04-13 * win/tclWinSock.c: Apply patch to allow write access to a socket if FD_WRITE is sent but FD_CONNECT is not. Some strange problem with either Win32 or a socket driver. [Bug: 1664 1776] 1999-04-09 * unix/tclUnixNotfy.c: Fixed notifier deadlock situation when the pipe used to talk back notifier thread is filled with data. When calling the write() function to feed data down that pipe, unlock the notifierMutex to allow the notifier to wake up again. Found as a result of the focus.test for Tk hanging. [Bug: 1700] 1999-04-06 * tests/unixNotfy.test: Fixed hang in tests when built with thread support. * tests/httpold.test: Fixed broken test that didn't wait long enough for events to arrive. * tests/unixInit.test: Fixed race condition in test. * tests/unixInit.test: * tests/fileName.test: Minor test nits. * unix/tclUnixInit.c (TclpSetInitialEncodings): Fixed bad initial encoding string. 1999-04-06 * generic/tclVar.c: * generic/tclEnv.c: Moved the "array set" C level code into a common routine (TclArraySet). The TclSetupEnv routine now uses this API to create an env array w/ no elements. * generic/tclEnv.c: * generic/tclWinInit.h: * generic/tclUnixInit.h: * generic/tclInt.h: Made the Env module I18N compliant. Changed the FindVariable routine to TclpFindVariable, that now does a case insensitive string comparison on Windows, and not on UNIX. [Bug: 1299, 1500] 1999-04-05 * tests/io.test: Minor test cleanup. * generic/tclEncoding.c (Tcl_CreateEncoding): Minor lint to make it easier to compile on Digital-unix. [Bug: 1659] * unix/configure.in: * unix/tclUnixPort.h: Applied patch for OS/390 to handle lack of sys/param.h. [Bug: 1725] * unix/configure.in: Fixed BSD/OS 4.* configuration to support shared libraries properly. [Bug: 1730] 1999-04-05 * win/tclWinDde.c: decrease timeout value for DDE calls to 30k [Bug: 1639] * generic/tcl.decls: * generic/tcl.h: * generic/tclDecls.h: * generic/tclInt.decls: * generic/tclInt.h: * generic/tclIntDecls.h: * generic/tclStubInit.c: * generic/tclUtil.c: Added more functions to the Tcl stubs table, including all Tcl_ functions not already in it (except Cmd functions) and Tcl_GetCwd() and Tcl_Chdir() (new functions). * tests/safe.test: * doc/safe.n: * generic/tclBasic.c: * library/safe.tcl: The encoding command is not safe as-is, so create a safe alias to mask out the "encoding system " but allow all other uses including "encoding system". Added test cases and updated the man page for Safe Tcl. 1999-04-05 * tests/winTime.test: * win/tclWinTime.c: Fixed crash in clock command that occurred when manipulating negative time values in timezones east of GMT. [Bug: 1142, 1458] * tests/platform.test: * tests/fileName.test: Fixed broken tests. * generic/tclFileName.c: Moved global regexps into thread local storage. * tests/socket.test: Changed so tests don't reuse sockets, since Windows is slow to release sockets. * win/tclWinConsole.c: * win/tclWinPipe.c: * win/tclWinSerial.c: Fixed race condition where background threads were terminated while they still held a lock in the notifier. 1999-04-02 * tests/http.test: Fixed bad test initialization code. * generic/tclThreadTest.c (ThreadExitProc): Fixed bug where static memory was being returned instead of a dynamically allocated result in error cases. 1999-04-02 * doc/dde.n: * tools/tcl.wse.in: * win/makefile.vc: * win/pkgIndex.tcl: * win/tclWinDde.c: Add new DDE package, code removed from Tk now separated into its own package. Changed DDE-based send code into "dde eval" command. Can be loaded into tclsh (not just wish). Windows only. 1999-04-02 * tests/expr.test: * tests/for-old.test: * tests/for.test: * tests/foreach.test: * tests/format.test: * tests/httpold.test: * tests/if.test: * tests/init.test: * tests/interp.test: * tests/while.test: Added some tests for known bugs (marked with knownBug constraint), and cleaned up a few bad tests. * generic/regc_locale.c: * generic/regcustom.h: * generic/tcl.decls: * generic/tclCmdIL.c: * generic/tclCmdMZ.c: * generic/tclInt.h: * generic/tclRegexp.c: * generic/tclScan.c: * generic/tclTest.c: * generic/tclUtf.c: * win/tclWinFCmd.c: * win/tclWinFile.c: Made various Unicode utility functions public. The following functions were made public and added to the stubs table: Tcl_UtfToUniCharDString, Tcl_UniCharToUtfDString, Tcl_UniCharLen, Tcl_UniCharNcmp, Tcl_UniCharIsAlnum, Tcl_UniCharIsAlpha, Tcl_UniCharIsDigit, Tcl_UniCharIsLower, Tcl_UniCharIsSpace, Tcl_UniCharIsUpper, Tcl_UniCharIsWordChar 1999-04-01 * tests/registry.test: * win/tclWinReg.c: Internationalized the registry code. It now uses Unicode interfaces on NT. [Bug: 1197] * tests/parse.test: * generic/tclParse.c: Fixed crash due to multiple frees in parser during error cleanup when parsing commands with more tokens than will fit in the static area of the parse structure. [Bug: 1681] * generic/tclInt.h: Removed duplicate declarations. * generic/tclInt.decls: * generic/tcl.decls: Added Tcl_WinUtfToTChar and Tcl_WinTCharToUtf to the tclPlat table. 1999-04-01 * generic/tcl.decls: * generic/tcl.h: * generic/tclBasic.c: * generic/tclDecls.h: * generic/StubInit.c: * tools/genStubs.tcl: * unix/Makefile.in: * win/makefile.vc: Applied patch from Jan Nijtmans to fix Ultrix multiple symbol definition problem. Now, even Tcl includes a copy of the Tcl stub library. Also fixed TCL_MEM_DEBUG mode (for Tk). 1999-03-31 * win/tclWinConsole.c: WinNT has a bug when reading a single character from the console. Rewrote the code for the console to read an entire line at a time using the reader thread. 1999-03-30 * unix/Makefile.in: Removed trailing backslash that broke the "depend" target. * unix/tclUnixInit.c (TclpSetInitialEncodings): Changed to avoid calling setlocale(). We now look directly at env(LANG) and env(LC_CTYPE) instead. [Bug: 1636] * generic/tclFileName.c: * generic/tclDecls.h: * generic/tcl.decls: Removed CONST from Tcl_JoinPath and Tcl_TranslateFileName because it changes the signature of Tcl_JoinPath in an incompatible manner. * generic/tclInt.h: * generic/tclLoad.c (TclFinalizeLoad): * generic/tclEvent.c (Tcl_Finalize): Defer unloading of loadable modules until all exit handlers have been invoked. [Bug: 998, 1273, 1573, 1593] 1999-03-29 * generic/tclFileName.c: * generic/tclDecls.h: * generic/tcl.decls: Added CONST to Tcl_JoinPath and Tcl_TranslateFileName. 1999-03-29 * tools/genStubs.tcl: * unix/configure.in: * unix/Makefile.in: * win/makefile.vc: * generic/tcl.h: * generic/tclBasic.c: * generic/tclDecls.h: * generic/tclIntDecls.h: * generic/tclPlatDecls.h: * generic/tclIntPlatDecls.h: Removed the stub functions and changed the stub macros to just use the name without params. Pass &tclStubs into the interp (don't use tclStubsPtr because of collisions with the stubs on Solaris). 1999-03-27 * win/makefile.bc: Removed makefile for Borland compiler, no longer supported. 1999-03-26 * win/tclWinSerial.c: * win/tclWinConsole.c: * win/tclWinPipe.c: Don't close the Win32 handle for a channel if it's a stdio handle (GetStdHandle()) during shutdown of a thread to prevent it from destroying the stdio of other threads. 1999-03-26 * unix/configure.in --nameble-shared is now the default and build Tcl as a shared library; specify --disable-shared to build a static Tcl library and shell. 1999-03-25 * tests/interp.test: * generic/tclInterp.c (AliasObjCmd): Changed so aliases are invoked at current scope in the target interpreter instead of at the global scope. This was an incompatibility introduced in 8.1 that is being removed. [Bug: 1153, 1556] * library/encoding/big5.enc: * library/encoding/gb2312.enc: * tools/encoding/big5.enc: * tools/encoding/gb2312.enc: Added ASCII to big5 and gb2312 encodings. [Bug: 632] * generic/tclPkg.c (Tcl_PkgRequireEx): Fixed broken clientData initialization in package code. * unix/Makefile.in (dist): Added tcl.decls and tclInt.decls to source distribution. [Bug: 1571] * doc/Thread.3: Updated documentation of Tcl_MutexLock to indicate that the recursive locking behavior is undefined. On Windows, it does not block, on Unix it deadlocks. [Bug: 1275] 1999-03-24 * tests/execute.test: * generic/tclExecute.c (TclExecuteByteCode): Fixed expression code that incorrectly returned floating point values for integers if the internal rep happened to be a double. Now we check to see if the object has a string rep that looks like an integer before using the double internal rep. [Bug: 1516] 1999-03-24 * generic/tclAlloc.c: * generic/tclEncoding.c: * generic/tclProc.c: * unix/tclUnixTime.c: * win/tclWinSerial.c: Fixed compilation warnings/errors for VC++ 5.0 and 6.0 and HP-UX native compiler without -Aa or -Ae. [Bug: 1323 1518 1324 1583 1585 1586] * win/tclWinSock.c: Make sockets thread-safe on Windows. The current implementation uses windows to handle events on the socket, one for each thread (thread local storage). Previously, there was only one window shared between threads, which didn't work. [Bug: 1326] 1999-03-23 * tools/tcl.wse: Fixed file association to look in the right place for the wish icon. [Bug: 1544] * tests/winNotify.test: * tests/ioCmd.test: * tests/event.test: Changed to use new style conditionals. * tests/encoding.test: Fixed nonportable test. * unix/dltest/configure.in: * unix/dltest/Makefile.in: Added missing DBGX macros. [Bug: 1564] * tests/winNotify.test: * mac/tclMacNotify.c: * win/tclWinNotify.c: * unix/tclUnixNotfy.c: * generic/tclNotify.c: Added a new Tcl_ServiceModeHook interface that is invoked whenever the service mode changes. This is needed to allow the Windows notifier to create a communication window the first time Tcl is about to enter an external modal event loop instead of at startup time. This will avoid the various problems that people have been seeing where the system hangs when tclsh is running outside of the event loop. [Bug: 783] * generic/tclInt.h: * generic/tcl.decls: Renamed TclpAlertNotifier back to Tcl_AlertNotifier since it is part of the public notifier driver API. 1999-03-23 * win/tclWinSerial.c: Fixed problem with fileevent on the serial port and nonblocking mode. Gets no longer hangs, fileevents fire whenever there is any character data on the port. * tests/winConsole.test: * win/tclWinConsole.c: Fixed problem with fileevents and gets from a console stdin. Previously, fileevents were firing before an entire line was available for reading, which meant that when you did a gets or read, it blocked (even in nonblocking mode). Now, it should work the same as Unix: fileevents fire when an entire line is ready, and gets and read do not block in non-blocking mode. Added an interactive test case to check for this. 1999-03-22 * tests/reg.test: * generic/regc_color.c: Applied regexp bug fix from Henry Spencer. 1999-03-19 * generic/tclCmdIL.c: Fixed the initialization of an array so that the Sun 5.0 C compiler wouldn't complain. * unix/configure.in: Added support for --enable-64bit. For now, this is only supported on Solaris 7 64bit (SunOS 5.7) using the Sun compiler (not gcc). 1999-03-18 * win/tclWinChan.c (TclpOpenFileChannel, Tcl_MakeFileChannel): Changed to only test for console or comm handles when the type is FILE_TYPE_CHAR to avoid useless tests on simple files. Also reordered tests so consoles are tested first as this is more common. * win/makefile.vc: Regularized usage of mkd and rmd and rm. * library/encoding/shiftjis.enc: * tools/encoding/shiftjis.txt: Missing/incorrect characters in shift-jis table. [Bug: 1008, 1526] * generic/tclInt.decls: * generic/tcl.decls: Eliminated use of "string" and "list" from argument lists to avoid conflicts with C++ STL. [Bug: 1181] * win/tclWinFile.c (TclpMatchFiles): Changed to ignore the FS_CASE_IS_PRESERVED bit and always return exactly what we get from the system. 1999-03-17 * win/README.binary: * win/README: * unix/configure.in: * generic/tcl.h: * README: Updated version to 8.1b3. 1999-03-14 * win/tclWinConsole.c: * win/tclWinPipe.c: * win/tclWinSerial.c: Changed so channel drivers wait for the reader/writer threads to exit before returning during a close operation. This ensures that the main thread is the last thread to exit, so the process return value is set properly. * generic/tclIntDecls.h: * generic/tclIntPlatDecls.h: * generic/tclIntPlatStubs.c: * generic/tclIntStubs.c: * generic/tclPlatDecls.h: * generic/tclPlatStubs.c: * generic/tclStubInit.c: * generic/tclStubs.c: Fixed bad eol characters. * generic/tclInt.decls: Changed "const" to "CONST" in declarations for better portability. * generic/tcl.decls: Renamed panic and panicVA to Tcl_Panic and Tcl_PanicVA in the stub files. * generic/tclInterp.c (Tcl_MakeSafe): Remove tcl_platform(user) from safe interps. 1999-03-11 * unix/Makefile.in: * unix/configure.in: Include compat files in the stub library in addition to the main library. Compat files are now built for dynamic use in all cases. * generic/tcl.h: Changed magic number so it doesn't match the plus patch, at Jan's request. * unix/tclConfig.sh.in: * unix/dltest/Makefile.in: * unix/dltest/configure.in: * unix/dltest/pkga.c: * unix/dltest/pkgb.c: * unix/dltest/pkgc.c: * unix/dltest/pkgd.c: * unix/dltest/pkge.c: * unix/dltest/pkgf.c: Changed package tests to build against the stubs library. 1999-03-10 * generic/tcl.h: * generic/tcl.decls: Changed Tcl_ReleaseType from an enum to macros so it can be used in .rc files. Added Tcl_GetString. * mac/tclMacNotify.c: * generic/tclNotify.c: * generic/tclInt.h: * win/tclWinNotify.c: * generic/tcl.h: Renamed Tcl_AlertNotifier to TclpAlertNotifier. * generic/tclInt.decls: Added TclWinAddProcess to make it possible for expect to use Tcl_WaitForPid(). This patch is from Gordon Chaffee. * mac/tclMacPort.h: * win/tclWinInit.c: * unix/tclUnixPort.h: * generic/tclAsync.c: Added TclpAsyncMark to fix bug in async handling on Windows where async events don't wake up the event loop. This patch comes from Gordon Chaffee. * generic/tcl.decls: Fixed declarations of reserved slots. 1999-03-10 * generic/tclCompile.h: Ensure that the ByteCode struct is binary compatible with the version in 8.0.6. * generic/tcl.h: * generic/tclBasic.c: Add Tcl_GetVersion() function to the public C API to allow programs to check the version number of the Tcl library at runtime. Also added an enum to clarify the release level (alpha, beta, final). 1999-03-09 * Integrated changes from Tcl 8.0 including: stubs mechanism configure patches from Jan Nijtmans rename of panic to Tcl_Panic 1999-03-08 * win/tclWin32Dll.c: Removed Dll instance from thread-local storage. 1999-03-08 * generic/tcl.h: Moved Tcl_Mutex, etc. macros above the inclusion of tclDecls.h to avoid macro conflicts. * generic/tclInt.h: * generic/regc_color.c: * generic/regcomp.c: * generic/tclCmdIL.c: * generic/tclCmdAH.c: * generic/tclIOCmd.c: * generic/tclParse.c: * generic/tclStringObj.c: * unix/tclUnixNotfy.c: Cleaned up various compiler warnings, eliminated UCHAR bugs. * unix/tclUnixNotfy.c: * unix/tclUnixThrd.c: * generic/tclThreadTest.c: * mac/tclMacThrd.c: Changed TclpCondition*() to Tcl_Condition*(). * INTEGRATED PATCHES FROM 8.0.6: * generic/tcl.decls: * generic/tcl.h: * generic/tclBasic.c: * generic/tclDecls.h: * generic/tclInt.decls: * generic/tclInt.h: * generic/tclIntDecls.h: * generic/tclIntPlatDecls.h: * generic/tclIntPlatStubs.c: * generic/tclIntStubs.c: * generic/tclPlatDecls.h: * generic/tclPlatStubs.c: * generic/tclStubInit.c: * generic/tclStubLib.c: * generic/tclStubs.c: * tools/genStubs.tcl: * unix/configure.in: * unix/Makefile.in: * unix/tclConfig.sh.in: * win/makefile.vc: * win/tclWinPort.h: Added Tcl stubs implementation. There are now two new macros USE_TCL_STUBS and USE_TCL_STUB_PROCS that enable use of stubs and disable stub macros respectively. All of the public and private function declarations from tcl.h and tclInt.h have moved into the *.decls files and the *Stubs.c and *Decls.h files are generated using the genStubs.tcl script. * unix/Makefile.in: * unix/configure.in: * unix/ldAix: Enhanced AIX shared library support. * win/tclWinSock.c: Removed a bunch of extraneous PASCAL FAR attributes from internal functions. * win/tclWinReg.c: Changed registry package to use stubs mechanism so it no longer depends on the specific version of Tcl. * doc/AddErrInfo.3: * doc/Eval.3: * doc/PkgRequire.3: * doc/SetResult.3: * doc/StringObj.3: * generic/tcl.h: * generic/tclBasic.c: * generic/tclPanic.c: * generic/tclStringObj.c: * generic/tclUtil.c: * unix/mkLinks: Added va_list versions of all VARARGS functions so they can be invoked from the stub functions. * doc/package.n: * doc/PkgRequire.3: * generic/tclPkg.c: Added Tcl_PkgProvideEx, Tcl_RequireEx, Tcl_PresentEx, and Tcl_PkgPresent. Added "package present" command. * generic/tclFileName.c: * mac/tclMacFile.c: * mac/tclMacShLib.exp: * unix/tclUnixFile.c: * win/tclWinFile.c: Changed so TclGetUserHome is defined on all platforms, even though it is currently a noop on mac and windows, and renamed it to TclpGetUserHome. * generic/tclPanic.c: * generic/panic.c: Renamed panic to Tcl_Panic. 1999-02-25 * win/makefile.vc: Added tclWinConsole.c and tclWinSerial.c * win/tclWinConsole.c: New code to properly deal with fileevents and nonblocking mode on consoles. * win/tclWinSerial.c: New code to properly deal with fileevents and nonblocking mode on serial ports. * win/tclWinPipe.c: * win/tclWinPort.h: Exported functions to allow creation of pipe channels from tclWinChan.c * win/tclWinChan.c: Check the type of a channel, including for the standard (stdin/stdout/stderr), and use the correct channel type to create the channel (file, serial, console, or pipe). 1999-02-11 * README: * generic/tcl.h: * win/README.binary: * win/README: * unix/configure.in: * mac/README: Updated version numbers to 8.1b2. 1999-02-10 * library/auto.tcl: Fixed auto_mkindex so it handles .tbc files. Did some general cleanup to handle bad eval statements that didn't use "list". * unix/mkLinks: * doc/SetVar.3: * generic/tcl.h: * generic/tclVar.c: Restored Tcl_ObjGetVar2 and Tcl_ObjSetVar2 from 8.0. Renamed Tcl_Get/SetObjVar2 to Tcl_GetVar2Ex and Tcl_SetVar2Ex. 1999-02-10 INTEGRATED PATCHES FROM 8.0.5b2: * test/winPipe.test: Changed to remove echoArgs.tcl temporary file when done. * tests/cmdAH.test: * generic/tclFileName.c (TclGetExtension): Changed behavior so the split happens at the last period in the name instead of the first period of the last run of periods. So, "foo..o" is split into "foo." and ".o" now. [Bug: 1126] * win/makefile.vc: Added better support for paths with spaces in the name. Added .lib and support .dlls to the install-binaries target. Added generate of a pkgIndex.tcl script to the install-libraries target. * win/tclAppInit.c: * unix/tclAppInit.c: * mac/tclMacAppInit.c: * generic/tclTest.c: Changed some EXTERN declarations to extern since they are not defining exported interfaces. This avoids generating useless declspec() attributes and makes the windows makefile simpler. * generic/tcl.h: Moved Tcl_AppInit declaration to end and cleared out TCL_STORAGE_CLASS so it is not declared with a declspec(). * tests/interp.test: * generic/tclInterp.c (DeleteAlias): Changed to use Tcl_DeleteCommandFromToken so we handle renames properly. This avoids senseless panic. [Bug: 736] * unix/tclUnixChan.c: * win/tclWinSock.c: * doc/socket.n: Applied Gordon Chaffee's patch to handle failures during asynchronous socket connection operations. This adds a new "-error" fconfgure option to socket channels. [Bug: 893] * generic/tclProc.c: * generic/tclNamesp.c: * generic/tclInt.h: * generic/tclCmdIL.c: * generic/tclBasic.c: * generic/tclVar.c: Applied patch from Viktor Dukhovni to rationalize TCL_LEAVE_ERR_MSG behavior when creating variables. * generic/tclVar.c: Fixed bug in namespace tail computation. Fixed bug where upvar could resurrect a namespace variable whose namespace had been deleted. * generic/tclCompile.c (TclCompileExprCmd): Eliminated yet another bogus optimization in expression compilation. * unix/configure.in: Added branch for BSD/OS-4* to shared library case statement. [Bug: 975] Fixed to correctly handle IRIX 6.5 n32 library support. [Bug: 1117] * win/winDumpExts.c: Patched to be pickier about stripping @'s. [Bug: 920] * library/http2.0/http.tcl: Added catch around eof test in CopyDone since the user may have already called http::reset. [Bug: 1108] * unix/configure.in: Changed Linux and IRIX to set SHLIB_LIBS to LIBS so shared libraries are linked with the system libraries. [Bug: 1018] * generic/tclCompile.c (CompileExprWord): Fixed exception stack overflow bug caused by missing statement. [Bug: 928] * generic/tclIOCmd.c: * generic/tclBasic.c: Objectified the "open" command. [Bug: 1113] * generic/tclPosixStr.c (Tcl_ErrnoId, Tcl_ErrnoMsg): When using egcs, ENOTSUP and EOPNOTSUPP are the same, so now we handle that case. [Bug: 1137] * library/init.tcl: Various small changes requested by Jan Nijtmans. - If the variable $tcl_library contains the empty string, this empty string will be put in $auto_path. This is not useful at all, it only slows down later package processing. - If the variable tcl_pkgPath is not set, the "unset __dir" fails. Thich makes init.tcl totally unusable. Better put a "catch" around it. - In the function tcl_findLibraries, the "string match" function only works correctly if $tcl_patchLevel is in one of the forms "?.?a?", "?.?b?" or "?.?.?". Could a "regexp" be used instead, then it allows anything to be appended to the patchLevel string. And it is more efficient. - The tclPkgSetup function assumes that if $type != "load" then the type must be "source". This needn't be true. Some users want to add their own setup types. [RFE: 1138] [Bug: 978] * win/tclWinReg.c: * doc/registry.n: Added support for HKEY_PERFORMANCE_DATA and HKEY_DYN_DATA keys. [Bug: 1109] * win/tclWinInit.c (TclPlatformInit): Added code to ensure tcl_pkgPath is set to "" when no registry entry is found. [Bug: 978] 1999-02-01 * generic/tclBasic.c: * generic/tclCmdAH.c: * generic/tclCmdIL.c: * generic/tclCmdMZ.c: * generic/tclExecute.c: * generic/tclHistory.c: * generic/tclIO.c: * generic/tclIOUtil.c: * generic/tclInterp.c: * generic/tclMain.c: * generic/tclNamesp.c: * generic/tclParse.c: * generic/tclProc.c: * generic/tclTest.c: * generic/tclTimer.c: * generic/tcl.h: Made eval interfaces compatible with 8.0 by renaming Tcl_EvalObj to Tcl_EvalObjEx, renaming Tcl_Eval2 to Tcl_EvalEx and restoring Tcl_EvalObj and Tcl_GlobalEvalObj interfaces so they match Tcl 8.0. 1999-01-28 * Merged Tcl 8.0.5b1 changes. * generic/tclUtil.c (Tcl_DStringSetLength): Changed so the buffer overallocates in a manner similar to Tcl_DStringAppend. This should improve performance for TclUniCharToUtfDString. 1998-12-11 === Tcl 8.1b1 Release === 1998-12-10 * Fixed lots of files that used TCL_THREAD instead of TCL_THREADS. * generic/tclEncoding.c (Tcl_FreeEncoding): Moved most of the code into a static FreeEncoding routine that does not grab the encodingMutex to avoid deadlocks/races when called from other routines that already have the mutex. 1998-12-09 * library/msgcat1.0/msgcat.tcl: Fixed bad export list, fixed so all locale strings are converted to lower case, including file names. * generic/regcomp.c (makescan): Fixed bug in longest match case that caused anchored patterns to fail. [Bug: 897] 1998-12-08 * library/msgcat1.0/msgcat.tcl: changed mc to invoke mcunknown in the calling context, changed locale lookups to be case insensitive 1998-12-07 * generic/tclAlloc.c (TclpRealloc): Fixed a memory allocation bug where big blocks that were reallocated into a different heap location were not being placed into the bigBlocks list. [Bug: 933] * tests/msgcat.test: Added message catalog test suite. * library/msgcat1.0/msgcat.tcl: minor bug fixes, integrated latest changes from Mark Harrison. 1998-12-04 * library/msgcat1.0/msgcat.tcl: Changed code to conform to Tcl coding standards. Changed to use file join for portability. * library/msgcat1.0: Added initial implementaion of Tcl message catalog package contributed by Mark Harrison. 1998-12-03 * win/tclWinPipe.c (BuildCommandLine): Fixed bug that kept arguments containing spaces from being properly quoted. * tests/defs: Changed so auto_path is set to only contain the Tcl library directory. This keeps the tests from accidentally picking up stuff in installed packages. * generic/tclUtil.c (Tcl_StringMatch): Changed to match 8.0 behavior in corner case where there is no closing bracket. 1998-12-02 * win/tclWinPipe.c (TclpCreateCommandChannel): Changed reader/writer threads to have THREAD_PRIORITY_HIGHEST so they will have a chance to run whenever there is something to do. * generic/tclIO.c (WriteBytes, WriteChars): Fixed so extraneous flushes do not happen in line mode. (TranslateOutputEOL): Made translation more efficient in line mode and fixed a buffer overflow bug in CRLF translation. [Bug: 887] 1998-12-02 * Updated patchlevel to 8.1b1 1998-12-02 * generic/regc_color.c (subcolor): Added check for error case to avoid an out of bounds array reference. * generic/tclCmdAH.c (Tcl_EncodingObjCmd): Changed to avoid using Tcl_DStringResult because it is not binary clean. * generic/tclParse.c (Tcl_ParseCommand): Fixed bug in comment parsing where a trailing comment looked like an incomplete command. 1998-12-02 * Merged changes from 8.0.4, especially the new pkg_mkIndex 1998-12-01 * generic/tclIO.c (Tcl_ReadChars): Added a call to UpdateInterest so we don't block when there is data sitting in the buffers. * generic/tclTest.c (TestevalobjvObjCmd): Updated for EvalObjv change. * tests/parse.test: Updated tests for EvalObjv change. * generic/tclParse.c (EvalObjv, Tcl_EvalObjv): Changed Tcl_EvalObjv interface to remove string and length arguments, preserved original interface as EvalObjv for internal use. * generic/tcl.h: Changed Tcl_EvalObjv interface to remove string and length arguments. * doc/Eval.3: Updated documentation for Tcl_EvalObjv to remove string and length arguments. * generic/tclCompCmds.c (TclCompileForeachCmd): Fixed code that corrupted the exceptDepth value in the compile environment when foreach failed to compile inline. [Bug: 884] * library/encoding/euc-kr.enc: * library/encoding/ksc5601.enc: * tools/encoding/ksc5601.txt: * unix/tclUnixInit.c: Added support for Korean EUC. * win/tclWinChan.c (TclpGetDefaultStdChannel): added check for a failure during Tcl_MakeFileChannel. 1998-11-30 * unix/tclUnixNotfy.c (Tcl_WaitForEvent): Fixed hang that occurs when trying to close a pipe that is currently being waited on by the notifier thread. [Bug: 607] * unix/tclUnixFCmd.c (GetPermissionsAttribute): Increase size of returnString buffer to avoid overflow. [Bug: 584] * generic/tclThreadTest.c (TclThreadSend): Fixed memory leak due to use of TCL_VOLATILE instead of TCL_DYNAMIC. * generic/tclThread.c (TclRememberSyncObject): Fixed memory leak caused by failure to reuse condition variables. * unix/tclUnixNotfy.c: (Tcl_AlertNotifier, Tcl_WaitForEvent, NotifierThreadProc, Tcl_InitNotifier): Fixed race condition caused by incorrect use of condition variables when sending messages between threads.. [Bug: 607] * generic/tclTestObj.c (TeststringobjCmd): MAX_STRINGS was off by one so the strings array was too small. * generic/tclCkalloc.c (Tcl_DbCkfree): Moved mutex lock so ValidateMemory is done inside the mutex to avoid a race condition when validate_memory is enabled. [Bug: 880] 1998-11-23 * regexec.c: more performance tuning from Henry Spencer. 1998-11-17 * tclScan.c: moved "scan" implementation out of tclCmdMZ.c and added Unicode support. This required a complete reimplementation of the command to avoid using scanf(), which isn't Unicode aware. Two new features were added in the process: %n to return the current number of characters consumed, and XPG3-style %n$ argument order specifiers similar to those provided by the "format" command. [Bug: 833] * tclAlloc.c: changed so allocated memory is always 8-byte aligned to improve memory performance and to ensure that it will work on systems that don't like accessing 4-byte aligned values (e.g. Solaris and HP-UX). [Bug: 834] 1998-11-06 * tclVar.c (TclGetIndexedScalar): Fixed bug 796, var name was getting lost before being passed to CallTraces. 1998-10-21 * added "encoding" command * Moved internal regexp declarations from tclInt.h to tclRegexp.h * integrated regexp updates from Henry Spencer 1998-10-15 * tclUtf.c: added Unicode character table support * tclInt.h: added TclUniCharIsWordChar * tclCmdMZ.c (Tcl_StringObjCmd): added "totitle" subcommand, changed "wordend" and "wordstart" to properly handle Unicode word characters and connector punctuation 1998-10-05 * auto.tcl, package.tcl: fixed SCCS strings * tclIndex: updated index to reflect 8.1 files * tclCompile.c (TclCompileScript): changed to avoid modifying the input string in place because name lookup operations could have arbitrary side effects * tclInterp.c: added guard against deleting current interpreter * tclMacFile.c, tclUnixFile.c, tclWinFile.c, tclFileName.c: added warnings around code that modifies strings in place * tclExecute.c: fixed off-by-one copying error, fixed merge bugs * tclEvent.c: changed so USE_TCLALLOC is tested for value instead of definition * tclCompCmds.c: replaced SCCS strings, added warnings around code that modifies strings in place * interp.test: added test for interp deleting itself 1998-09-30 * makefile.vc: fixed so TCL_LIBRARY is set before running tcltest * tclWin32Dll.c: removed TclpFinalize, cleanup of merges tcl8.4.20/ChangeLog.20010000644003604700454610000041770611737050674013071 0ustar dgp771div2001-12-28 Jeff Hobbs * library/init.tcl: make sure env(COMSPEC) on Windows is executed with the right case, as it may otherwise fail inexplicably. 2001-12-28 Don Porter * generic/tclCkalloc.c (MemoryCmd, TclFinalizeMemorySubsystem): Added the [memory onexit] command, intended to replace [checkmem]. * doc/DumpActiveMemory.3: * doc/memory.n: Updated documentation for [memory] and related matters. [Bug 487677] * mac/tclMacBOAMain.c (Tcl_Main, CheckmemCmd): Removed all the machinery for the [checkmem] command that is completely duplicated by code in generic/tclCkalloc.c. * generic/tclBinary.c: * generic/tclListObj.c: * generic/tclObj.c: * generic/tclStringObj.c: Removed references to [checkmem] in comments, referencing [memory active] instead, since it is documented. 2001-12-28 Daniel Steffen * mac/tclMacInit.c: * mac/tclMacTclCode.r: synced up tclInit features to unix/win: implemented TclSetPreInitScript support, use of existing tclInit proc if defined, check of default encoding dir if set. Changed script library resource names to lowercase (i.e. same as corresponding files). Used Tcl_JoinPath instead of string append. Check that system encoding could be loaded before utf translating the LibraryPath. * mac/tclMacApplication.r: * mac/tclMacLibrary.r: * mac/tclMacOSA.r: * mac/tclMacResource.r: minor version resources cleanup 2001-12-21 Mo DeJong * unix/tcl.m4 (SC_PATH_TCLCONFIG, SC_PATH_TKCONFIG): Search for config file using exec_prefix instead of prefix when no --with-tcl or --with-tk argument is used. [Bug 492418] 2001-12-21 Daniel Steffen * unix/tcl.m4: fixed incorrect SHLIB_LD_LIBS setting for MacOSX / Darwin. * unix/configure: Regen. * unix/mkLinks.tcl: improved case-insensitive filesystem support. * unix/mkLinks: Regen. 2001-12-19 Don Porter * unix/Makefile.in (dist): corrected use of eolFix.tcl on working files. It should operate on distributed files. [Bug 495120] 2001-12-19 David Gravereaux * tools/tcl.wse.in: Fix for #495120. tcl.wse.in was stored in cvs with improper . This resulted in corrupted when checked-out on translating CVS clients such as windows (CRCRLF) and mac (CRCR). 2001-12-19 Mo DeJong * unix/configure: * unix/tcl.m4 (SC_CONFIG_CFLAGS): Update SunOS 5.[0-6] target so that correct linker options are passed to gcc or ld. [Tk Bug 220863] 2001-12-19 Mo DeJong * unix/README: Update to account for changes in the unix/dltest directory, the way autoconf is run, and the new "make shell" target. 2001-12-19 Mo DeJong * unix/Makefile.in: Rename dltest to dlpkgs to fix problem where lib files were not getting built because dltest/ directory already existed. 2001-12-19 Jeff Hobbs * win/tclWinSerial.c (SerialCheckProc): corrected time calculations to be unsigned. (schroedter) 2001-12-18 Mo DeJong * unix/Makefile.in: Define new dltest target that simply does a cd to dltest/ before running make. There is no need for the separate configure script that was previously being used. * unix/configure: Regen. * unix/configure.in: Subst into dltest/Makefile. * unix/dltest/Makefile.in: Define LIBS using DL_LIBS, LIBS, and MATH_LIBS variables instead of TCL_LIBS variable from tclConfig.sh. * unix/dltest/README: Update readme to account for new configure free implementation. * unix/dltest/configure: Removed. * unix/dltest/configure.in: Removed. 2001-12-18 Donal K. Fellows * generic/tcl.h (TCL_STUB_MAGIC): Added cast to force type to be an int and get rid of a persistent and pointless warning with SunPro compiler. * generic/tclCkalloc.c (Tcl_AttemptDbCkalloc,Tcl_AttemptDbCkrealloc): * generic/tcl.decls (Tcl_AttemptDbCkalloc,Tcl_AttemptDbCkrealloc): Made the file parameters to these functions into CONST char *, like they always should have been to match the other Tcl*Db* API functions. 2001-12-17 Andreas Kupries * Applied #219311 on behalf of Rolf Schroedter to prevent fcopy on serial ports from flooding the event queue. 2001-12-11 Miguel Sofer * doc/CrtInterp.3: * generic/tclBasic.c: docs and comments corrections [Bug 493412] Bug & patch by Don Porter. 2001-12-14 Donal K. Fellows * win/tclWinNotify.c (Tcl_FinalizeNotifier): Stop Tcl on Windows from crashing when shutdown from a non-Tcl thread. Fixes Bug #217982 [orig. 5804] reported by Hugh Vu and Gene Leache. I'm not convinced that the shutdown process is right even with this, but it was definitely wrong without... 2001-12-13 Andreas Kupries * win/tclWinSock.c (TcpGetOptionProc): Fix for tcl bug item #478565 reported by an unknown person. Bypasses all calls to "gethostbyaddr" for address "0.0.0.0" to prevent delays on Win/NT. 2001-12-12 Jeff Hobbs * doc/Preserve.3: doc'd TCL_DYNAMIC use. [Patch #483989] (porter) 2001-12-12 Andreas Kupries * generic/tclIO.c (Tcl_GetsObj): Applied patch for bug #491341 as provided by Don Porter . Fixes the assumption of having an empty Tcl_Obj to work with. 2001-12-11 Miguel Sofer * generic/tclCompCmds.c: * generic/tclCompile.c: * generic/tclExecute.c: consistency patch, to make all instructions that pop a variable number of Tcl_Obj's off the execution stack take the number of popped objects as first operand. Modified *only* the new instructions INST_LIST_INDEX_MULTI and INST_LSET_FLAT, so this has no effect on bytecodes generated up to tcl8.4a3 inclusive. * generic/tclExecute.c: fix debug messages in INST_LSET_LIST. * generic/tclCompCmds.c (TclCompileLindexCmd): * generic/tclCompExpr.c (CompileMathFuncCall): removed the last two overestimates of the necessary stack depth for bytecodes in the fix of [Bug 483611]. 2001-12-10 Andreas Kupries * unix/tclUnixPipe.c (TclpCreateProcess): Applied Don Porter's patch fixing bug #437489. 2001-12-10 Miguel Sofer * generic/tclEvent.c: * tests/event.test: fix background error reporting in the absence of a bgerror proc [Bug 219142]. 2001-12-10 Don Porter * doc/Access.3: * doc/CrtChannel.3: * doc/DString.3: * doc/ExprLong.3: * doc/FileSystem.3: * doc/GetStdChan.3: * doc/OpenFileChnl.3: * doc/StdChannels.3: * doc/TCL_MEM_DEBUG.3: * doc/Tcl_Main.3: * doc/Utf.3: * doc/file.n: * doc/tclsh.1: Several typo and formatting corrections discovered during conversion to TMML. Thanks to Joe English. [Patch 490514] * unix/mkLinks: 'make mklinks' 2001-12-10 Miguel Sofer * generic/tclCompCmds.c: * generic/tclCompExpr.c: * generic/tclCompile.c: * generic/tclCompile.h: * generic/tclExecute.c: * generic/tclProc.c: fixed the calculation of the maximal stack depth required by bytecodes [Bug 483611]. 2001-12-07 Miguel Sofer * generic/tclVar.c: * tests/trace.test: restored consistency in refCount accounting by array traces [Bug #4484339], submitted by Don Porter. 2001-12-06 Donal K. Fellows * tests/parseExpr.test, tests/for.test, tests/expr.test: * tests/expr-old.test, tests/compile.test, tests/compExpr.test * tests/compExpr-old.test: Kept up to date with syntax errors. * generic/tclParseExpr.c (ParsePrimaryExpr): Rewrote to give even better syntax errors in the fairly common case of an identifier without decorations by guessing based on the currently available functions. Also made messages consistent between memdebug and ordinary builds. 2001-12-05 Miguel Sofer * generic/tclVar.c: * tests/trace.test: new algorithm for [array get], safe when there are traces that modify the array [Bug #449893]. 2001-12-04 Donal K. Fellows * tests/compExpr-old.test, tests/compExpr.test, tests/compile.test: * tests/expr-old.test, tests/expr.test, tests/for.test: * tests/while.test, tests/if.test: Rewrite to handle more specific syntax errors. * tests/parseExpr.test: Rewrite to get rid of dup test numbers and handle more specific syntax errors. * generic/tclParseExpr.c (LogSyntaxError): Added a detail message argument to help explain what the syntax error is. (Tcl_ParseExpr, ParseCondExpr, ParsePrimaryExpr): Added detail messages. (UNKNOWN_CHAR): New lexeme for characters that are always illegal in expressions outside strings. 2001-12-03 Donal K. Fellows * doc/expr.n: Various documentation improvements in relation to the function calls. Includes fix for Bug #487704 submitted by Devin Eyre. 2001-12-03 David Gravereaux * win/makefile.vc: Some install target bugs repaired along with $(TCLSTUBLIB) added to the dependencies rather than implicit through the dde and reg extensions which don't happen to always require it for some build types. 2001-11-30 Miguel Sofer * generic/tclVar.c: Tcl_Preserve'ing VarTrace structures to avoid memory corruption. Patch for [Bug: 484334] provided by Don Porter 2001-11-29 Miguel Sofer * tests/namespace.test: modified namespace-41.2, added 41.3 {knownbug} after discussion with Don Porter and Kevin Kenny. 2001-11-29 Miguel Sofer * tests/namespace.test: added namespace-41.2, a simpler test for [Bug: 231259] 2001-11-29 Donal K. Fellows * generic/tclBinary.c (BINARY_SCAN_MAX_CACHE, Tcl_BinaryObjCmd, ScanNumber): Added caching scheme to reduce number of object allocations when doing scans of large repetitive binary strings. See comments in file for reasoning behind implementation. Suggested by Miguel Sofer in Patch #429916, but independently implemented. 2001-11-28 Donal K. Fellows * doc/regsub.n, doc/regexp.n: Converted dangling references to METASYNTAX section into references to the re_syntax manual page. 2001-11-27 D. Richard Hipp * win/tclWinFCmd.c: Fix a coredump in the filename normalizer code for Win95/98. 2001-11-27 David Gravereaux * win/makefile.vc: Removed the Tk reference for the 'winhelp' target. Converge at install will need to be the solution for Tk and all other extensions. 2001-11-27 Donal K. Fellows * tests/cmdAH.test (cmdAH-24.2): Made test less sensitive to OS preemption, but perfection isn't practical [Bug 463189, reported by Don Porter.] * tests/switch.test (switch-9.*): Added tests to exercise more of the argument checking. (switch-7.2,switch-7.3): Test changed behaviour slightly. * generic/tclCmdMZ.c (Tcl_SwitchObjCmd): Reworked argument parsing to be stricter about what it accepts. This should make uses of the [switch] command be more maintainable. [Bug 475397, reported by Don Porter.] 2001-11-26 Don Porter * generic/tclIntPlatDecls.h: 'make genstubs' after changes in 2001-11-23 commit from Daniel Steffen. 2001-11-24 Mo DeJong * unix/Makefile.in: Add comments to better describe TCL_EXE and when it should be available. * win/Makefile.in: Add TCL_EXE variable to be used by rules like `make genstubs`. Don't set TCL_LIBRARY before running `make genstubs` since we will be running with a tclsh from the PATH not the one we build. 2001-11-24 Mo DeJong * win/configure: Regen. * win/tcl.m4 (SC_CONFIG_CFLAGS): Add comctl32.lib to wish link libs. This change was originally added to Tk on 2001-11-09 but was not committed to Tcl. 2001-11-23 Daniel Steffen * unix/Makefile.in: * unix/configure.in: * unix/install-sh: * unix/mkLinks: * unix/mkLinks.tcl: * unix/tclLoadDyld.c: * unix/tclMtherr.c: Mac OSX support: build system, dynamic code loading and support for case-insensitive filesystems in mkLinks (patch #435258) 2001-11-23 Daniel Steffen Up-port to 8.4 of mac code changes for 8.3.3 & various new changes for 8.4, some already backported to 8.3.4 (patch #435658) * generic/tclObj.c: added #include to fix missing prototype errors * generic/tcl.h: MAC_TCL: addition of ConditionalMacros.h and use of DLLIMPORT and DLLEXPORT like on other platforms. ( => no longer need the .exp files and can remove use of #pragma export that never worked well) removed line continuation in #if clause as this breaks the mac resource compiler (note that *.r files include tcl.h) * mac/tclMacFile.c: fixed bug in permission checking code * mac/tclMacLoad.c: corrected utf8 handling, comparison of package names to code fragment names changed to only match on the length of package name, this allows for fragment names with version numbers appended * mac/tclMacInt.h: * generic/tclInt.h: * mac/tclMacTime.c: * generic/tclIOUtil.c: moved declaration of TclpGetGMTOffset() * mac/tclMacShLib.exp: * mac/tclMacOSA.exp: * mac/tclMacMSLPrefix.h: removed files * unix/Makefile.in: removed reference to .exp files * mac/MW_TclBuildLibHeader.h: * mac/MW_TclBuildLibHeader.pch: * mac/MW_TclHeaderCommon.h: * mac/MW_TclStaticHeader.h: * mac/MW_TclStaticHeader.pch: new precompiled header files * mac/MW_TclAppleScriptHeader.pch: * mac/MW_TclHeader.pch: * mac/MW_TclTestHeader.pch: * mac/tclMacCommonPch.h: revised precompiled header handling: now include a common header file 'MW_TclHeaderCommon.h' from all .pch files, the .pch files themselves now only setup #defines (e.g. BUILD_tcl, STATIC_BUILD, TCL_DEBUG, TCL_THREADS) like in makefiles on other platforms. * mac/tclMac.h: * mac/tclMacPort.h: * mac/tclMacInt.h: use of BUILD_tcl and TCL_STORAGE_CLASS like on other platforms, standardize #include'd files to what's done on other platforms, removed use of #pragma export. * mac/tcltkMacBuildSupport.sea.hqx: new archive of mac build support files & suggested build environment directory hierarchy: 'Building MacTclTk' & 'CW Pro6 changes' readme's. projects for MoreFiles 1.5.2 static & shared libraries. project & sources for 'pseudoCarbonSupport', see below. included XML versions of the projects for CW Pro5 or Pro7 users. * mac/tclMacProjects.sea.hqx: updated mac build project files: build support for CodeWarrior Pro6, UnivIntf 3.4 & shared runtime libraries: the MSL libraries and MoreFiles are no longer compiled into Tcl.shlb, all non-static binaries now use the Pro6 shared runtime libraries and MoreFiles.shlb. These shlbs are merged into the standard Wish and TclShell, but 3rd party applications linking with Tcl.shlb or Tk.shlb need to setup access to them. (see the "(sh-ppc)" targets for how to do this.) included XML versions of the projects for CW Pro5 or Pro7 users. use compat/strtod.c instead of MSL's strtod() use WASTE versions of MSL for tcl test target to avoid text buffer cutoff at 32k. Merging the full MSL.shlb and the other shlbs into Wish & TclShell makes them a bit larger than before, use unmerged binaries to avoid copying the shared code with every application, e.g. when deploying numerous Wish based droplets. Note that using CW Pro5 to compile extensions is in principle still possible, but need to link with Pro6 runtime libraries. Tclapplescript now loads and runs on CFM68k. Highly experimental "pseudoCarbon" support for Tcl only on OS 8/9: binaries in "Build:(Carbon):" link against CarbonLib instead of InterfaceLib, however the actual code has not been carbonized! i.e. it will not run on OSX and may not even run properly with CarbonLib. This should in principle allow you to build & test OS9 CFM Carbon binaries that need to link with Tcl.shlb. On OSX you can use the native Tcl.framework, but you have to build a MachO binary as there is no CFM glue lib for Tcl.framework. the library pseudoCarbonSupport.shlb manually loads the symbols from InterfaceLib that are not in CarbonLib but are needed by the uncarbonized code in Tcl.shlb and TclShell. * generic/tclMain.c: MAC_TCL: workaround for broken/non-standard isatty on MW Pro6, #include instead of defining isatty * mac/tclMacPort.h: MW Pro6 changes for MSL fcntl.h, stat.h & isatty * mac/tclMacAppInit.c: add EXTERN to InstallConsole to enable DLL export via the TCL_STORAGE_CLASS mechanism. * mac/tclMacFCmd.c: fix for FSpDirectoryCopy API change * mac/tclMacLibrary.c: emit compile time error when TCL_REGISTER_LIBRARY and USE_TCL_STUBS are both defined at the same time in an extension, this use is not currently supported and will result in a crash when dynamically loading the extension. * mac/tclMacApplication.r: * mac/tclMacLibrary.r: * mac/tclMacOSA.r: * mac/tclMacResource.r: fixed obsolete copyrights/dates in version strings; updated version strings to standard usage; added support for '(Support Libraries)' subfolder for shared runtime libraries in unmerged binaries; commented out demo setting of "Tcl Environment Variables"; reorganized resources among these files to avoid multiple copies in applications and shared libraries, the script libraries are now no longer duplicated in Tclsh but are only included in the resources of Tcl.shlb. * mac/tclMacChan.c: * mac/tclMacSock.c: cast for *BlockMode * mac/tclMacUtil.c: * mac/tclMacMath.h: removed obsolete hypot() definition * generic/tclIntPlatDecls.h: * generic/tclInt.decls: * generic/tclStubInit.c: * mac/tclMacNotify.c: * mac/tclMacOSA.c: * mac/tclMacUtil.c: * generic/tclThreadTest.c: renamed routines conflicting with standard Apple or MoreFiles headers (at compile or link time): GetGlobalMouse -> GetGlobalMouseTcl FSpGetDirectoryID -> FSpGetDirectoryIDTcl FSpOpenResFileCompat -> FSpOpenResFileCompatTcl FSpCreateResFileCompat -> FSpCreateResFileCompatTcl NewThread -> NewTestThread the renamed MoreFiles *Tcl routines are just wrappers calling into the MoreFiles DLL. * mac/tclMacCommonPch.h: * mac/tclMacThrd.c: * mac/tclMacPanic.c: removed OLDROUTINENAMES define, renamed obsolete apple API names to modern equivalents; UH3.4 support: added #include , updated New*Proc() calls to New*UPP(). * mac/tclMacUnix.c: added missing (Tcl_Obj ***) cast to Tcl_ListObjGetElements call * mac/tclMacAlloc.c: modernized TclpSysAlloc() to use temporary memory instead of system heap memory when available (MacOS >= 7.5 and possibly earlier, use of system heap has been discouraged for a long time and has many disadvantages, e.g. memory isn't paged out, and errors can very easily bring the system down); fixed crashing bug in TclpSysRealloc() and CleanUpExitProc() where memory was being accessed after having been deallocated; fixed memory leak in (de)allocation code (for every block ever allocated with TclpSysAlloc, a Ptr was leaked), if temporary memory is available, don't track allocated memory, instead use RecoverHandle() to get Handle from Ptr, otherwise use doubly linked list to correctly track memory and free all allocated memory; added new option for ConfigureMemory: MEMORY_DONT_USE_TEMPMEM, disables use of temporary memory even when it would be available, only necessary when writing e.g. a driver (using tcl??); increased fraction of application heap reserved for OS routines to 512K * compat/strftime.c: * mac/tclMacTime.c: * mac/tclMacPort.h: * generic/tclInt.decls: * generic/tclIntPlatDecls.h: * generic/tclStubInit.c: timezone support for mac via TclpGetTZName() like on windows, using an inverse timezone table adapted from tclDate.c to map gmtoffset in seconds gotten from the MacOS APIs to a timezone string, as there is no good way to get this info from MacOS. I had to make up some unusual timezones and arbitrarily decide on the most standard of the multiple choices available for every timezone. * generic/tclExecute.c: workaround for a MSL bug/misfeature: for very small floats, MSL can return errno ERANGE but a non-zero value ( < LDBL_MIN however) * mac/tclMacAppInit.c: support for WASTE text library using temporary memory, setting has no effect if WASTE is not used. * mac/tclMacPanic.c: removed duplicate code from generic/tclPanic.c and added that file to projects instead. * tests/all.tcl: set tcltest::singleProcess 1 as multiple processes are not available on the mac. * tests/cmdAH.test: access time not available on the mac, skip the atime touch test * tests/appendComp.test: * tests/cmdMZ.test: * tests/compile.test: * tests/exec.test: * tests/fileName.test: * tests/lset.test: * tests/namespace.test: * tests/tcltest.test: added missing cleanups/tests/catches that caused tests to fail on the mac. * doc/tclvars.n: doc bug, env(PWD) should be env(HOME) [Bug 463834] 2001-11-21 Don Porter * tests/trace.test (trace-8.8): Corrected test for Bug 219393. * generic/tclBasic.c (Tcl_DeleteCommandFromToken,CallCommandTraces): * generic/tclCmdMZ>c (Tcl_UntraceCommand): Added Tcl_Preserve and Tcl_Release calls to prevent deletion of CommandTrace structures until all callers are done using them, preventing memory corruption. [Bug 453805] 2001-11-20 Kevin B. Kenny * doc/GetTime.3 (Tcl_GetTime): * generic/tcl.decls (Tcl_GetTime): * generic/tclClock.c (Tcl_ClockObjCmd): * generic/tclCompile.c (TclCleanupByteCode, TclInitByteCodeObj): * generic/tclCmdMZ.c (Tcl_TimeObjCmd): * generic/tclUtil.c (TclpGetTime): * generic/tclTest.c (GetTimesCmd): * generic/tclTimer.c (Tcl_CreateTimerHandler, TimerSetupProc, TimerCheckProc, TimerHandlerEventProc): * mac/tclMacNotify.c (Tcl_SetTimer): * mac/tclMacShLib.exp (Tcl_GetTime): * mac/tclMacTime.c (Tcl_GetTime): * unix/tclUnixChan.c (TclUnixWaitForFile): * unix/tclUnixEvent.c (Tcl_Sleep): * unix/tclUnixThrd.c (Tcl_ConditionWait): * unix/tclUnixTime.c (Tcl_GetTime): * win/tclWinNotify.c (Tcl_Sleep): * win/tclWinTest.c (TestwinclockCmd): * win/tclWinTime.c (TclpGetSeconds, TclpGetClicks, Tcl_GetTime): Changed all uses of TclpGetTime to Tcl_GetTime. Added Tcl_GetTime to the Stubs table and the library documentation. Added a TclpGetTime in tclUtil.c for backward compatibility of extensions. [Patch #483500, TIP#73] * generic/tclCmdMZ.c (Tcl_TimeObjCmd): Corrected an error in the [time] command that caused incorrect results to be returned if the total duration of all iterations exceeded 2**31 microseconds. [Bug #478847] * generic/tclInt.decls: * generic/tclInt.h: * generic/tclStubInit.h: Reran 'make genstubs' 2001-11-20 Miguel Sofer * generic/tclBasic.c * generic/tclCompile.h: * generic/tclExecute.c: moving all code relative to bytecodes from tclBasic.c to tclExecute.c - the functions RecordTracebackInfo and Tcl_ExprObj went to tclExecute.c, and new interface function was defined (TclCompEvalObj). The final objective of this sequence of moves is to provide a clean, clear-cut interface between Tcl's core and the compiler/engine subsystem. 2001-11-20 Miguel Sofer * generic/tclBasic.c * generic/tclCompile.h: * generic/tclExecute.c: factoring out of common code in tclBasic.c (new function TclInterpReady defined: it resets the interp's result, then checks that it hasn't been deleted and that the nesting level is acceptable). Passed the responsibility of calling it to the *callers* of TclEvalObjvInternal. 2001-11-20 Miguel Sofer * generic/tclBasic.c * generic/tclExecute.c: a better variant of the previous-to-last commit (restoring numLevels computations). The managing of the levels now has to be done by the *callers* of TclEvalObjvInternal 2001-11-20 Miguel Sofer * generic/tclExecute.c: missing variable declaration under TCL_COMPILE_DEBUG. 2001-11-20 Miguel Sofer * generic/tclExecute.c: * generic/tclProc.c: restoring the computations of iPtr->numLevels to the original logic (previous to buggy modifs on 2001-11-16). 2001-11-20 Jeff Hobbs * tools/eolFix.tcl (new-file): * unix/Makefile.in: added EOL correction for Windows bat files to dist target. [Bug #219409] (davygrvy) * unix/tclUnixInit.c (TclpSetInitialEncodings): update of patch from 2001-11-16 that uses the old Tcl encoding check mechanism as a fallback to the original. Also added a TCL_DEFAULT_ENCODING #define (defaults to iso8859-1). Tcl will first try setlocale and nl_langinfo, and if that fails, guess based on certain LANG|LC_* env vars. [Patch #418645] 2001-11-19 David Gravereaux * win/buildall.vc.bat: Added useful comments. 2001-11-19 Miguel Sofer * tests/compile.test: added a test for bug [Bug 483309] 2001-11-19 Vince Darley * win/tclWinFile.c: * win/tclWinFCmd.c: * win/tclWin32Dll.c: * doc/file.n: * tests/winFCmd.test: improved speed of file normalization for Win95/98, and clarified docs on differences in file normalization between NT/2000 and the older operating systems. Added test to ensure normalization is correct. 2001-11-19 Miguel Sofer * generic/tclBasic.c: * generic/tclParse.c: Code reorganisation. Moved all evaluation functions from tclParse.c to tclBasic.c, so that now tclParse.c deals exclusively with parsing and all evaluations are done by code in tclBasic.c. The functions moved are: TclEvalObjvInternal, Tcl_EvalObjv, Tcl_LogCommandInfo, Tcl_EvalTokensStandard, Tcl_EvalTokens, Tcl_EvalEx, Tcl_Eval, Tcl_EvalObj and Tcl_GlobalEvalObj. 2001-11-19 Donal K. Fellows * tests/trace.test (trace-8.8): Added adapted version of Bug #219393 as new test; the test won't reliably show up the old problem unless it is being run under something like Purify, but something is better than nothing... * generic/tclVar.c (Tcl_TraceVar2, Tcl_UntraceVar2): Added missing mask bits for trace result type and a check for a nonsense flag combination. * generic/tclCmdMZ.c (TraceVarProc): Added missing test for NULL when deleting a trace that doesn't cause an error. * doc/TraceVar.3: Added documentation for change due to TIP#68. * generic/tclCmdMZ.c (TraceVarInfo): Removed problematic errMsg field from structure. (TraceVarProc): Removed references to errMsg field and changed handling of errors so that they returned a Tcl_Obj* containing the error string. This minimizes the number of calls to the memory management subsystem. (TclTraceCommandObjCmd, TraceCommandProc): Removed references to errMsg field which was never used in command traces in any case. (Tcl_TraceObjCmd, TclTraceVariableObjCmd): Removed references to errMsg field and made variable traces register with TCL_TRACE_RESULT_OBJECT bit set. * generic/tcl.h (TCL_TRACE_RESULT_DYNAMIC,TCL_TRACE_RESULT_OBJECT): New constants to define how to handle the strings returned from trace callbacks [TIP#68] * generic/tclVar.c (CallTraces, Tcl_GetVar2Ex, TclGetIndexedScalar, TclGetElementOfIndexedArray, Tcl_SetVar2Ex, TclSetIndexedScalar, TclSetElementOfIndexedArray, Tcl_UnsetVar2, Tcl_ArrayObjCmd, TclDeleteVars, TclDeleteCompiledLocalVars, DeleteArray, TclVarTraceExists): Support for those new trace flags. 2001-11-19 Miguel Sofer * generic/tclCompCmds.c: patch for [Bug 483309] (petasis). 2001-11-16 Kevin B. Kenny * generic/tclListObj.c: removed a C++-style comment that was inadvertently left in the source code. 2001-11-16 Jeff Hobbs * tests/interp.test: * generic/tclInterp.c (SlaveObjCmd): Corrected argument checking for '$interp alias|aliases|issafe'. [Patch #479560] (thoyts, hobbs) * unix/tclUnixInit.c: added HAVE_LANGINFO code block. * unix/configure: regened * unix/configure.in: added SC_ENABLE_LANGINFO call * unix/tcl.m4: made SHLIB_LD_LIBS='${LIBS}' for FreeBSD* (meyer) Added modified version of Wagner patch to make use of nl_langinfo where possible to determine Unix platform encoding, instead of the inflexible built-in system. This is used by default when possible, and can be disabled with --enable-langinfo=no. [Patch #418645] (hobbs, wagner) 2001-11-16 Miguel Sofer * generic/tclCompile.h: * generic/tclExecute.c: * generic/tclObj.c: moved Tcl_GetCommandFromObj and all defining code for tclCmdNameType objects to tclObj.c (from tclExecute.c). This code has nothing to do with bytecodes. 2001-11-16 Miguel Sofer * generic/tclBasic.c: * generic/tclCompile.h: * generic/tclExecute.c: * generic/tclParse.c: * generic/tclProc.c: * tests/stack.test: consolidation of duplicated code (in TclExecuteByteCode and EvalObjv); renaming of EvalObjv to TclEvalObjv as it is not static anymore; restored consistency of level counts between compiled and directly evaled code. [Bug 480896] 2001-11-12 David Gravereaux * win/makefile.vc: * win/rules.vc: Small bug fixes. * win/README: added some docs pointing to the docs in makefile.vc for it's use. 2001-10-17 Kevin B. Kenny * doc/lappend.n: * doc/lindex.n: * doc/linsert.n: * doc/list.n: * doc/llength.n: * doc/lrange.n: * doc/lsearch.n: * doc/lset.n (new-file): * doc/lsort.n: * generic/tclBasic.c (builtInCmds, Tcl_EvalObjEx): * generic/tclCmdIL.c (Tcl_LindexObjCmd, Tcl_LindexList): (Tcl_LindexFlat, Tcl_LsetObjCmd): * generic/tclCompCmds.c (Tcl_CompileLindexCmd, Tcl_CompileLsetCmd): * generic/tclCompile.c: * generic/tclCompile.h: * generic/tclExecute.c (TclExecuteByteCode): * generic/tclInt.decls: * generic/tclInt.h: * generic/tclIntDecls.h: * generic/tclListObj.c (TclLsetList, TclLsetFlat, TclSetListElement): * generic/tclObj.c (TclInitObjSubsystem): * generic/tclStubInit.c: * generic/tclTestObj.c (TestobjCmd): * generic/tclUtil.c (TclGetIntForIndex, SetEndOffsetFromAny): * generic/tclVar.c (Tcl_LappendObjCmd): * tests/lindex.test: * tests/lset.test (new-file): * tests/lsetComp.test (new-file): * tests/obj.test: * tests/string.test: * tests/stringComp.test: Reference implementation of TIP's #22, #33 and #45. Adds the ability of the [lindex] command to have multiple index arguments, and adds the [lset] command. Both commands are byte-code compiled. [Patch #471874] (work by Kenny, commited by Hobbs) 2001-11-12 David Gravereaux * win/buildall.vc.bat(new): * win/makefile.vc: Small fix with deriving the "OriginalFilename" string in the .rc scripts. Added a quick batchfile for building the entire thing. 2001-11-12 Jeff Hobbs * doc/FileSystem.3: * doc/file.n: * doc/tcltest.n: converted use of \' to more reasonable format. 2001-11-10 Mo DeJong * unix/Makefile.in: * win/Makefile.in: Add "make gdb" target. This target can run tclsh inside either gdb or insight. 2001-11-10 David Gravereaux * win/makefile.vc: Added a check to make sure one runs the makefile from the /win directory only. * win/mkd.bat: * win/rmd.bat: Changes from Llyod Lim for better stability. [Patch #456759] 2001-11-09 David Gravereaux * win/makefile.vc: * win/tcl.dsp: winhelp target fixes for non-NT systems. It seems NMAKE under these remembers changed directories during commands. A new tcltest feature from Peter Spjuth to specify a pattern file from the commandline and redirecting output to a file when not under NT with it's scrollback console. Then it replays it, piped through more. Added 2 new static "configurations" to tcl.dsp. I could keep adding more, but I think we should leave it up to the user for customizing it. Sticky-points left: 'profile' option. 2001-11-09 Jeff Hobbs * doc/FileSystem.3: * doc/StdChannels.3: * doc/file.n: * doc/tcltest.n: * tools/man2help.tcl: * tools/man2help2.tcl: fixed winhelp generation problems [Patch #480268] * unix/configure: * unix/tcl.m4: added -lc to AIX libs, fixed path to ldAix 2001-11-09 Don Porter * tests/var.test: * generic/tclVar.c: Corrected bug in [global] when dealing with variable names matching :*. [Bug 480176] 2001-11-08 Mo DeJong Fixup stack size under OSF1. [Tcl patch 474790] * unix/configure: Regen. * unix/tcl.m4: Add HAVE_PTHREAD_ATTR_SETSTACKSIZE define to EXTRA_CFLAGS to adjust initial stack size. 2001-11-08 Mo DeJong Enable thread support under FreeBSD. [Tcl bug 473708] * unix/configure: Regen. * unix/tcl.m4 (SC_ENABLE_THREADS): Check for pthread functions in libc_r and enable thread support if found. * unix/dltest/Makefile.in: Set SHLIB_LD_LIBS and use it in the Makefile to properly link a shared library. 2001-11-08 Mo DeJong * unix/Makefile.in: * unix/dltest/Makefile.in: Avoid adding libc to the LIBS variable since it is not needed when linking with CC. If required when linking with LD it should be done on a case by case basis in tcl.m4. 2001-11-08 David Gravereaux * win/rules.vc: * win/makefile.vc: Fixed install target to adjust for the different build types. Added a 'linkexten' option to link the win extensions inside the shell when built static. Placed win/tclAppInit.c patch in SF patch DB for approval. 'profile' option not hooked in yet. Everything else know is done. * win/tcl.dsp(new): * win/tcl.dsw(new): Simple MsDev stub project files that calls makefile.vc. Will help run Tcl in the debugger easier without confusing MsDev for where the .pdb files are. 2001-11-07 Mo DeJong * unix/Makefile.in: * win/Makefile.in: Print a message indicating that the user should run "make genstubs" when the generated tclStubInit.c file is out of date. We can't regenerate automatically since there may be no tclsh on the system and that would cause bootstrap problems. [Tcl bug 465874] 2001-11-07 Mo DeJong Define TCL_INCLUDE_SPEC in tclConfig.sh. It should be included by extensions that need to find Tcl include headers in the install location. The user can override the include install dir with --includedir so we need to record this information for extensions. [Tcl bug 421835] * unix/configure: Regen. * unix/configure.in: Define TCL_INCLUDE_SPEC. * unix/tclConfig.sh.in: Define TCL_INCLUDE_SPEC. * win/configure: Regen. * win/configure.in: Define TCL_INCLUDE_SPEC. * win/tclConfig.sh.in: Define TCL_INCLUDE_SPEC. 2001-11-07 David Gravereaux * win/rules.vc: * win/makefile.vc: Dropped the NOMSVCRT macro and put it on the option list instead. It makes more sense to me this way as NOMSVCRT=0 would only be the valid setting. Fixed the dde and reg extension for building static. Improved, but not perfected, the winhelp target. 2001-11-07 Mo DeJong * win/README: Change minimum VC++ version to 5.X since 4.X is known not to work. Indicate that Mingw is required and building with Cygwin gcc is not supported. Include instructions that indicate how to install Mingw and what URLs folks should use to download the supported version of Mingw. * win/configure: Regen. * win/configure.in: Error out if user tries to compile the Windows version of Tcl with Cygwin gcc. Users should compile with Mingw gcc instead. 2001-11-06 Andreas Kupries * generic/tclIO.c (ReadChars): Fixed bug #478856 reported by Stuart Cassoff . The bug caused loss of fileevents when [read]ing less data from the channel than buffered. Due to an empty input buffer the flag CHANNEL_NEED_MORE_DATA was set but never reset, causing the I/O system to wait for more data instead of using a timer to synthesize fileevents and to flush the pending data out of the buffers. 2001-11-06 David Gravereaux * win/rules.vc (new): * win/makefile.vc: Complete over/under rewrite to support numerous build options all from the commandline itself without needing to edit the makefile. Now requires vcvars32.bat to be run prior to running nmake for bootstraping the environment. Fully doc'd usage for it is in makefile.vc. Commentary welcome. Sticky points left are: 1) winhelp target shows errors in the converting script. 2) .rc scripts aren't getting the right #defines to build the correct "OriginalFilename" strings. (have patch, won't commit yet) 3) Naming convention with suffixes describing the buildtype are 'tsdx' which will need public acceptance. ie. tclsh84tsx.exe is a (t) threaded shell (s) statically linked to the core and (x) uses msvcrt instead of libcmt. 2001-11-04 Vince Darley * library/init.tcl: made filesystem fallback proc ::tcl::CopyDirectory more robust to vagaries of non-native filesystems. 2001-11-02 Vince Darley * doc/file.n: * generic/tclIOUtil.c: updated documentation and comments to clarify behaviour of 'file copy' wrt soft links. 2001-10-29 Vince Darley * win/tclWinFile.c: fix to '-types {f r}' bug in TclpMatchInDirectory (which could cause a UMR, as well as returning wrong results). Also improved API for 'stat' to resolve [Bug#219258]. * win/tclWin32Dll.c * win/tclWinInt.h: addition of improved stat API to internal lookup table. * tests/fileName.test: two new tests for the above bug. * generic/tclIOUtil.c: some cleanup of comments and #ifdefs 2001-10-29 Donal K. Fellows * unix/tclUnixFile.c (TclpMatchInDirectory): Argument to access() was entryPtr->d_name instead of nativeEntry which failed when trying to check access for files in other than the current directory. [Bug 475941, reported by Georgios Petasis] 2001-10-25 Donal K. Fellows * unix/tclUnixChan.c: Added stateUpdated member to struct TtyState. (TtyCloseProc,TtySetOptionProc,TtyInit): Use stateUpdated member of TtyState to decide whether it is necessary to reset a serial port when Tcl closes it. Blindly resetting can cause Tcl to be sent an unexpected SIGTSTP when it is executing in the background [Bug 471374, reported by Chris Nelson] 2001-10-22 Andreas Kupries * doc/ObjectType.3: Minor documentation fix, reported by David N. Welton directly to me. 2001-10-22 Vince Darley * win/tclWinFCmd.c: fix to stop test suite from hanging process under some versions of WinNT. [Bug #466102] (Kevin Kenny) 2001-10-18 Jeff Hobbs * tests/clock.test (clock-8.1): * generic/tclDate.c (RelativeMonth): * generic/tclGetDate.y (RelativeMonth): corrected off-by-one-day error in clock scan with relative months and years during swing hours. [Bug #413397, Patch #414024] (lavana) 2001-10-18 Vince Darley * generic/tclIOUtil.c: fix to bug in Tcl_FSChdir shown up by recent tclkit builds. 2001-10-17 Jeff Hobbs * unix/tclUnixPipe.c (PipeInputProc, PipeOutputProc): do immediate retry when error is returned with errno == EINTR. [Bug #415131] (leger) 2001-10-16 Jeff Hobbs * unix/tclLoadAout.c (TclGuessPackageName): removed unused vars and fixed warnings. [Bug #446622] (lim) 2001-10-15 Miguel Sofer * generic/tclProc.c: changing a memcmp to strncmp to avoid a memory error detected by purify (thanks Jeff); modify style to agrre with the style guide. 2001-10-15 Andreas Kupries * generic/tclInt.decls (TclExpandCodeArray,TclGetInstructionTable): Added to internal stubs table. Tclcompiler (Tclpro project) needs them if used as loadable package under Windows. Changed signatures. We don't want to describe compiler internal structures in "tclInt.h". * generic/tclCompile.h: S.a. Removed function declarations. * generic/tclCompile.c: S.a. Adapted to changed signatures. 2001-10-15 Jeff Hobbs * unix/configure: * unix/configure.in: * win/configure: * win/configure.in: * win/tcl.m4: reworked to be a little cleaner in comparison to each other, and to AC_SUBST even empty vars for win/tclConfig.sh * generic/tclFileName.c: minor code cleanup * generic/tcl.h: moved #define of WIN32 to tcl.h where __WIN32__ is defined and added #ifndef check. * doc/open.n: moved all fconfigure option docs to fconfigure.n * doc/fconfigure.n: added serial config options * win/tclWinChan.c: * win/tclWinPort.h: * win/tclWinSerial.c: added TIP #35 Windows enhancements for serial configuration. [Patch #438509] (schroedter) 2001-10-15 Vince Darley * generic/tclFCmd.c: fix to memory leak in TclFileDeleteCmd on certain error conditions. * doc/FileSystem.3: fix to typo. 2001-10-12 Jeff Hobbs * library/encoding/ebcdic.enc: * tools/encoding/ebcdic.txt: EBCDIC charset mapping. [Patch #219323] (nijtmans) * library/encoding/tis-620.enc: * tools/encoding/tis-620.txt: TIS-620 charset mapping. [Patch #467423] (poonlap) * tests/http.test: added removeFile for outdata * tests/ioCmd.test: added catch around file removal, as Windows file locking throws errors. * tests/socket.test (socket-7.2): corrected to work on Win2K. 2001-10-12 Miguel Sofer * tests/compile.test: new tests for [Bug 467523]; they are only effective if TCL_MEM_DEBUG was set during compilation. 2001-10-11 Miguel Sofer * generic/tclLiteral.c (TclReleaseLiteral): insured that self-referential bytecodes are properly cleaned up on interpreter deletion [Bug 467523] (Ronnie Brunner) 2001-10-10 David Gravereaux * win/tclWinPort.h: #include needed to get moved to after #include or wierd misunderstandings took place when -D_WIN32_WINNT=0x0400 is set for outside code that requires knowledge of Tcl innards. General header macro magic applied liberally... 2001-10-10 Don Porter * tests/unixInit.test: Corrected restore of ::env(LANG). 2001-10-09 Jeff Hobbs * generic/tclFileName.c (Tcl_SplitPath): corrected mem leak intro'd with VFS code where the result obj from Tcl_FSSplitPath was not getting freed. 2001-10-09 Miguel Sofer * generic/tclLiteral.c: (TclReleaseLiteral) reverted previous patch for [Bug 467523] - cure is worse than the illness. 2001-10-05 Miguel Sofer * generic/tclLiteral.c: (TclReleaseLiteral) insured that self-referential bytecodes are properly cleaned up on interpreter deletion [Bug 467523] (Ronnie Brunner) 2001-10-04 Jeff Hobbs * tools/configure: * tools/configure.in: noted 8.4 as default Tcl version * library/encoding/cp936.enc: * library/encoding/cp949.enc: * library/encoding/cp950.enc: * library/encoding/iso8859-16.enc: * library/encoding/macCroatian.enc: * library/encoding/macCyrillic.enc: * library/encoding/macGreek.enc: * library/encoding/macIceland.enc: * library/encoding/macRoman.enc: * library/encoding/macTurkish.enc: * tools/encoding/cp1250.txt: * tools/encoding/cp1251.txt: * tools/encoding/cp1252.txt: * tools/encoding/cp1253.txt: * tools/encoding/cp1254.txt: * tools/encoding/cp1255.txt: * tools/encoding/cp1256.txt: * tools/encoding/cp1257.txt: * tools/encoding/cp1258.txt: * tools/encoding/cp874.txt: * tools/encoding/cp932.txt: * tools/encoding/cp936.txt: * tools/encoding/cp949.txt: * tools/encoding/cp950.txt: * tools/encoding/iso8859-1.txt: * tools/encoding/iso8859-10.txt: * tools/encoding/iso8859-13.txt: * tools/encoding/iso8859-14.txt: * tools/encoding/iso8859-15.txt: * tools/encoding/iso8859-16.txt: * tools/encoding/iso8859-2.txt: * tools/encoding/iso8859-3.txt: * tools/encoding/iso8859-4.txt: * tools/encoding/iso8859-5.txt: * tools/encoding/iso8859-6.txt: * tools/encoding/iso8859-7.txt: * tools/encoding/iso8859-8.txt: * tools/encoding/iso8859-9.txt: * tools/encoding/koi8-r.txt: * tools/encoding/macCentEuro.txt: * tools/encoding/macCroatian.txt: * tools/encoding/macCyrillic.txt: * tools/encoding/macGreek.txt: * tools/encoding/macIceland.txt: * tools/encoding/macRoman.txt: * tools/encoding/macTurkish.txt: Updated encodings with latest mappings from www.unicode.org. This did not include some Mac encodings that have special multi-unichar translations now (like symbols, dingbats and japanese). Also does not include big5, gb or euc* as those have different formats in the latest Unicode version that need new conversion tools. Not all related .enc files changed as some had been updates separately. 2001-10-03 Jeff Hobbs * generic/tclEvent.c (Tcl_FinalizeThread): moved freeing of tclLibraryPath to before the thread exit handlers are called. Slight modification to change on 2001-09-24. 2001-10-01 Jeff Hobbs * win/configure: regen'ed * win/tcl.m4: * win/makefile.vc: added Win64 SDK RC1 compilation support * win/Makefile.in: added $(LDFLAGS_CONSOLE) to TCLSH, TCLTEST and PIPE_DLL_FILE targets to get the link flags * win/tclWinInit.c: minor 64bit casts 2001-10-01 Miguel Sofer * generic/tclCmdIL.c: * generic/tclCmdMZ.c: * generic/tclParseExpr.c: removed unnecessary inclusion of tclCompile.h and made a small modification in (InfoBodyCmd) to improve the isolation of the compiler/engine subsystem. 2001-09-29 Vince Darley * generic/tclIOUtil.c: * doc/FileSystem.3: corrected and clarified documentation for 'Tcl_FSListVolumes(Proc)'. No code changes. 2001-09-28 Miguel Sofer * doc/FindExec.3: added a comment not to change the working directory before calling Tcl_GetNameOfExecutable [Bug 219215] 2001-09-28 Kevin Kenny * generic/tclIO.c: added two more '(ClientData)' casts on calls to Tcl_Preserve and Tcl_Release -- ones that Vince apparently missed. 2001-09-28 Donal K. Fellows * doc/lsort.n: Improved doc... * generic/tclCmdIL.c (Tcl_LsortObjCmd, SortCompare): Made offset-from-end indexing work, and factored out some "magic numbers" for easier understanding. [Bug #465674] * tests/cmdIL.test (cmdIL-1.26): Added test for offset-from-end indexing for lsort. 2001-09-28 Vince Darley * win/tclWinFCmd.c: * unix/tclUnixFCmd.c: fix to performance issue reported by jcw in which 'access("")' is called unnecessarily when normalizing any absolute path. * generic/tclIO.c: added '(ClientData)' cast to calls to Tcl_(Preserve|Release) newly introduced, fixing compile error on Windows. 2001-09-27 Don Porter * doc/FileSystem.3 (Tcl_FSLoadFile): * generic/tcl.decls (Tcl_FSLoadFile): * generic/tcl.h (Tcl_FSLoadFileProc): * generic/tclInt.h (TclpLoadFile): * generic/tclIOUtil.c (Tcl_FSLoadFile): * generic/tclLoadNone.c (TclpLoadFile): * generic/tclTest.c (TestReportLoadFile): * library/ldAout.tcl: * mac/tclMacLoad.c (TclpLoadFile): * unix/tclLoadAix.c (TclpLoadFile): * unix/tclLoadAout.c (TclpLoadFile): * unix/tclLoadDl.c (TclpLoadFile): * unix/tclLoadDld.c (TclpLoadFile): * unix/tclLoadDyld.c (TclpLoadFile): * unix/tclLoadNext.c (TclpLoadFile): * unix/tclLoadOSF.c (TclpLoadFile): * unix/tclLoadShl.c (TclpLoadFile): * win/tclWinLoad.c (TclpLoadFile): * win/tclWinFCmd.c (DoRemoveJustDirectory): More CONST poisoning fixes from the 2001-09-24 TIP 27 changes. CONST-ified Tcl_FSLoadFile and TclpLoadFile. Report and patch from Kevin Kenny. [Bug 465833] * generic/tclIO.c (ChannelTimerProc): Added Tcl_Preserve() and Tcl_Release() to fix segfault introduced by the 2001-09-26 changes. [Bug 465494] * doc/TCL_MEM_DEBUG.3: Updated out-of-date reference to #define GUARD_SIZE. * doc/UpVar.3 (Tcl_UpVar,Tcl_UpVar2): * generic/tcl.decls (Tcl_UpVar,Tcl_UpVar2): * generic/tclInt.decls (TclFindProc,TclGetFrame): * generic/tclInt.h (TclFindProc,TclGetFrame,TclLookupVar, TclPrecTraceProc,TclProcInterpProc}): * generic/tclProc.c (TclGetFrame,TclFindProc): * generic/tclVar.c (Tcl_UpVar,Tcl_UpVar2,MakeUpvar): Updated APIs in generic/tclProc.c and generic/tclVar.c according to the guidelines of TIP 27. [Patch 465442] * generic/tclDecls.h: * generic/tclIntDecls.h: make genstubs 2001-09-26 Andreas Kupries * doc/fileevent.n: Accepted [Patch #465279] adding an example to the fileevent manpage. Minor modifications to get a better formatting. Report and patch by David N. Welton . * The changes below fix [Bug #462317] where Expect tried to read more than was in the buffers and then blocked in the OS call as its pty channel driver provides no blockmodeproc through which the OS could be notified of blocking-behaviour. Because of this the general I/O core has to take more care than usual to preserve the semantics of non-blocking channels. The problem was reported by "Kevin O'Gorman" . * generic/tclIO.c (Tcl_ReadRaw): Do not read from the driver if the channel is non-blocking and the fileevent causing the read was generated by a timer. We do not know if there is data available from the OS. Instead of going to the OS for more and potentially blocking we simply signal EWOULDBLOCK to the higher levels to cause the system to wait for true fileevents. (GetInput): Same as before. (ChannelTimerProc): Added set and clear of CHANNEL_TIMER_FEV. * generic/tclIO.h (CHANNEL_TIMER_FEV): New flag for channels. Is set if a fileevent was generated by a timer, the channel is not blocking and the driver did not provide a blockmodeproc. In that case the I/O core has to be especially careful about going to the driver for more data. 2001-09-26 Don Porter * doc/SplitPath.3 (Tcl_GetPathType): * generic/tcl.decls (Tcl_GetPathType): * generic/tclFileName.c (Tcl_GetPathType): * win/tclWinFile.c (TclpMatchInDirectory, NativeStat): Vince Darley reports the 2001-09-24 TIP 27 changes left the win directory CONST poisoned. These changes should fix that. * generic/tclDecls.h: make genstubs 2001-09-25 Don Porter * doc/GetInt.3: * generic/tclInt.h (TclGetLong deleted): * generic/tcl.decls: * generic/tclInt.decls: * generic/tclGet.c: Updated APIs in generic/tclGet.c according to the guidelines of TIP 27. [Patch 464674] * generic/tclDecls.h: * generic/tclIntDecls.h: make genstubs 2001-09-25 Miguel Sofer * generic/tclVar.c: removed comments referring to unused flag TCL_PARSE_PART1. 2001-09-24 Don Porter * doc/Concat.3: * doc/DString.3: * doc/SplitList.3: * generic/tclInt.h (TclCheckBadOctal): * generic/tcl.decls: * generic/tclInt.decls: * generic/tclEncoding.c (OpenEncodingFile): * generic/tclMain.c (Tcl_Main): * generic/tclUtil.c: * unix/tclLoadDl.c (TclpLoadFile): Updated APIs in generic/tclUtil.c according to the guidelines of TIP 27. [Patch 464553] * generic/tclDecls.h: * generic/tclIntDecls.h: make genstubs 2001-09-24 Andreas Kupries * The change below fixes [Bug #464380]. The bug was reported by Ronnie Brunner . He also provided the patch. * generic/tclEvent.c (Tcl_Finalize): Moved release of 'tclLibraryPath' to Tcl_FinalizeThread. (Tcl_FinalizeThread): See above, new place for release of 'tclLibraryPath'. 2001-09-24 Donal K. Fellows * tools/encoding/cp1252.txt: File was missing part of the encoding [euro, ZCaron and zcaron]. * doc/OpenFileChnl.3: Add docs for Tcl_OutputBuffered; remove some old changebars. 2001-09-21 Jeff Hobbs * generic/tclExecute.c (TclExecuteByteCode): corrected INST_STR_CMP else case for strings to pass true utf char length to Tcl_UtfNCmp. 2001-09-20 Jeff Hobbs * win/tclWinInit.c: added extra processor definitions. (mstacy) * win/tclWinSock.c (SocketThread): corrected pointer cast for _WIN64. * win/tclWinNotify.c: removed unnecessary winsock include (it is already in from tclWinPort.h). * win/tclWinPort.h: changed winsock.h include to winsock2.h. Reverses change from 2000-11-16, but is necessary for WIN64. Extensions should comply with defined OS words, or use #ifndef. 2001-09-20 Donal K. Fellows * tests/socket.test: removed dependence on being run from same dir as remote.tcl, which only now needs to be in the same dir as this file. [Bug #219326] 2001-09-19 Jeff Hobbs * generic/tclTest.c (TestcmdtokenCmd): corrected pointer storage/retrieval for 64bit machines. * generic/tclCmdAH.c (Tcl_FormatObjCmd): * generic/tclScan.c (Tcl_ScanObjCmd): corrected handling of format and scan on 64-bit machines. [Bug #412696] (rmax) * unix/configure: regen'ed * unix/tcl.m4: added --enable-64bit support for HP-11 with the 64-bit kernel. * tests/basic.test: * tests/cmdInfo.test: improved skip reporting of missing commands * tests/winFCmd.test: simplified error check for winFCmd-7.9 * tests/winPipe.test: removed obsolete cat16 tests * generic/tclExecute.c (TclExecuteByteCode): fixed invalid usage of valuePtr in TRACE_WITH_OBJ in INST_EVAL_STK case. [Bug #462594] Changed INST_STR_CMP instruction to promote to Unicode strings only when one of the strings is already of Unicode type. * generic/tclExecute.c (TclExecuteByteCode): * generic/tclCompile.c (instructionTable): * generic/tclCompCmds.c (TclCompileStringCmd): INST_STR_MATCH - Updated to Int1 instruction type and added special case to use INST_STR_EQ instead when no glob chars are specified in a static string. * tests/{for.test,foreach.test,if.test,while.test}: * generic/tclCompCmds.c (TclCompileForCmd, TclCompileForeachCmd, TclCompileIfCmd, TclCompileWhileCmd): Corrected the overaggressive compiling of loop bodies enclosed in ""s. [Bug #219166] (msofer) 2001-09-19 Miguel Sofer * generic/tclExecute.c: insured that execution stack errors are also detected at abnormal returns. 2001-09-19 Donal K. Fellows * doc/socket.n: Added documentation to mention what happens when a server socket is created with port=0. Removed an old change bar, and no new change bar because Tcl has always behaved this way as it is really a poorly-documented standards-defined OS feature. * tests/util.test (util-8.1): Test derived from code to detect the problem, but the test always works in the C locale, so beware if you are maintaining the code. * generic/tclUtil.c (TclNeedSpace): Rewrote to be UTF-8 aware. [Bug 411825, but not that patch which would have added extra spaces if there was a real non-ASCII space involved. ] 2001-09-18 Andreas Kupries * generic/tclIOCmd.c (Tcl_PutsObjCmd): Rewritten to have saner and faster argument handling. Fixes bug #123552. Patch provided by Donal K. Fellows : #402564. 2001-09-18 Don Porter * unix/configure: Regen. * unix/tcl.m4 (SC_CONFIG_CFLAGS): On Linux, disable inlining when one of the compat/*.c routines is to be linked in. [Patch 440891] 2001-09-17 Jeff Hobbs * generic/tcl.h: removed forced #define USE_TCLALLOC 1 for Windows. This means the native system allocator will be used by default. This should be binary and source compatible with extensions, as Tcl_Alloc is a properly stubbed function. 2001-09-17 Miguel Sofer * generic/tclExecute.c: corrected small bug in [Patch 456668] - the varFramePtr was not restored in one possible exit. 2001-09-17 Miguel Sofer * doc/tclvars.n: * generic/tclCompile.c: * generic/tclCompile.h: * generic/tclExecute.c: * generic/tclProc.c: disabled all compile and execution tracing functionality in standard builds; TCL_COMPILE_DEBUG is now necessary to enable it. [Bug 451858] 2001-09-14 Andreas Kupries * doc/gets.n: * doc/read.n: * doc/puts.n: * doc/flush.n: * doc/fconfigure.n: * doc/flush.n: * doc/eof.n: * doc/seek.n: * doc/tell.n: * doc/close.n: * doc/fileevent.n: Added references to the Tcl standard channels. Item [219250], reported by David LeBlanc . Thanks to Christopher Nelson for doing editorial work. 2001-09-13 Andreas Kupries * win/Makefile.in: * win/configure.in: * win/makefile.bc: * win/makefile.vc: * library/dde/pkgIndex.tcl: Fixed version numbers from bogus tcl versions to independent versions for dde and registry packages. 2001-09-13 Jeff Hobbs * tests/regexp.test (regexp-20.1): * generic/tclCmdMZ.c (Tcl_RegsubObjCmd): had to adjust fix from 2001-08-06 to actually duplicate the objects in certain cases. This is really a place where feather would have been essential. [Bug #461322] * generic/tclUtf.c (Tcl_UtfPrev): corrected to return the proper location when the middle of a UTF-8 byte was passed in. [Tk Bug #450504] * ChangeLog.1999: * ChangeLog: broke changes from 199x into ChangeLog.1999 to reduce size of the main ChangeLog. 2001-09-13 Andreas Kupries * tests/ioCmd.test: Changed the computation of the result for iocmd-8.1[123] so that the tests work for single- and multi-process execution of the testsuite. Depending on the choice of the user stdout is a tty or not and thus reports different channel options. Fixes [460993] reported by Don Porter. 2001-09-13 Miguel Sofer * doc/ParseCmd.3: * generic/tcl.decls: * generic/tclCmdMZ.c (Tcl_SubstObjCmd): * generic/tclDecls.h: * generic/tclParse.c: * generic/tclStubInit.c: * tests/parse.test: Deprecate the use of Tcl_EvalTokens, replaced by the new Tcl_EvalTokensStandard. The new function performs the same duties but adheres to the standard return convention for Tcl evaluations; the deprecated function could only return TCL_OK or TCL_ERROR, which caused [Bug 219384] and [Bug 455151]. This patch implements [TIP 56]. 2001-09-12 Mo DeJong * unix/configure: Regen. * unix/tcl.m4: Invert the logic that checks for $GCC. Instead of checking for "$GCC" = "no" we check for "$GCC" != "yes" or simply swap the true and false blocks of code in an if statement. That way if GCC is set to "" everything will still work. [Bug 460991] 2001-09-12 Don Porter * tests/appendComp.test: * tests/lsearch.test: * tests/namespace.test: * tests/rename.test: * tests/split.test: Corrected tests to better isolate tests in one file from influencing tests in other files. [Bug 460591] 2001-09-12 Miguel Sofer * generic/tcl.decls: reserved stub #481 for the implementation of [TIP 56] 2001-09-11 Andreas Kupries * doc/OpenFileChnl.3: Added documentation for Tcl_WriteRaw and Tcl_ReadRaw [#414929]. * doc/CrtChannel.3: Added documentation for Tcl_ChannelBuffered and Tcl_GetTopChannel [#414929]. * The changes below are a fix for [219253]. * tests/socket.test: Removed _most_ instances of hardwired port numbers for listening sockets. Remaining are the ports in all tests with constraint 'doTestsWithRemoteServer'. These seem to be designed for a more controlled environment and are usually skipped when running the testsuite. * tests/io.test: Removed all instances of hardwired port numbers for listening sockets. 2001-09-10 Jeff Hobbs * generic/tclEvent.c (TclInExit): Corrected handling of tsd in late stages of finalization. [Bug #419449] (darley) * tests/stack.test: * generic/tclInterp.c (AliasObjCmd): Check the numLevels to ensure that we aren't hitting some alias loop condition. [Bug #443184] 2001-09-10 Mo DeJong * unix/configure: Regen. * unix/tcl.m4 (SC_CONFIG_CFLAGS): Don't include . characters in the Tcl library name when building on FreeBSD 3.X and later systems. [Patch 450725] 2001-09-10 Andreas Kupries * doc/tclsh.1: * doc/Tcl_Main.3: * doc/CrtChannel.3: * doc/OpenFileChnl.3: * doc/GetStdChan.3: Enhanced the manpages with cross-references to the new manpage and more explanations how these functions deal with the standard channels in various situations. * doc/StdChannels.3: New manpage describing handling of the standard channels by the Tcl library [402725]. 2001-09-10 Don Porter * unix/mkLinks (Tcl_FSLink): Updated to reflect 2001-08-23 file system changes. * unix/tclLoadShl.c: Added #include of tclInt.h; access to Tcl internals, notably TclpUnloadFile(), is required. Thanks to Bob Techentin for report and patch. [Bug 459305] * generic/tclInitScript.h (initScript): * win/tclWinInit.c (TCL_REGISTRY_KEY, TclpSetVariables): Removed vestiges of Tcl's old initialization from registry variables. [Bug 455645] 2001-09-10 Andreas Kupries * generic/tclInt.decls: Also added 'TclWinFlushDirtyChannels' to the internal platform specific stub table. * win/tclWinFile.c (TclpObjStat): Now added the call to 'TclWinFlushDirtyChannels' to this function. I don't know where my head was last thursday (2001-09-06), but the call was actually added to 'TclpObjChdir', i.e. the implementation of [cd]. Corrected this now. Thanks to Vince Darley for spotting this. 2001-09-10 Miguel Sofer * generic/tclProc.c: * tests/proc.test: made [proc] bytecompile a no-op for procs defined with _args_ as single argument and an empty body. [FQ 451441] 2001-09-09 Mo DeJong * unix/Makefile.in: * win/Makefile.in: Use () around variable name instead of {}. Use TCLTEST variable directly instead of depending on the tcltest alias. 2001-09-09 David Gravereaux * generic/tcl.h: * generic/tclPlatDecls.h: Reminder from David Cuthbert that I hadn't finished the Borland compatibility stuff. [Patch: 436116] 2001-09-09 Mo DeJong * tests/cmdAH.test: Modify cmdAH-20.5 and cmdAH-24.8 to display the file atime or mtime results if the test fails. 2001-09-08 David Gravereaux * win/mkd.bat: * win/rmd.bat: made these text files, text files again. [Patch: 451333] 2001-09-08 Mo DeJong * win/mkd.bat: * win/rmd.bat: Apply binary property (cvs admin -kb) to files and convert to CRLF linefeed format to fix the VC++ build. [Bug #219409] 2001-09-08 Vince Darley * generic/tclInt.h: * generic/tclFCmd.c: * doc/FileSystem.3: * generic/tclIOUtil.c: removed Tcl_FSCopyFile fallback to channel copying, since the channels will not have access to interpreters and the channel copying currently requires an interp. Code which required cross-platform copies always has interpreters, so that solves the problem. Fixes bug in TclKit. 2001-09-07 David Gravereaux * win/tcl.m4: Added -link50compat option so a VC6 linker makes a VC5 (pre sp3) compatible import library. [Bug: 219257] 2001-09-07 Mo DeJong * win/tclWinThrd.c (TclpThreadExit): Cast status argument to _endthreadex to unsigned instead of DWORD to match the Win32 function prototype. 2001-09-06 Andreas Kupries * All the changes below serve to fix bug [219148] which reports a 80x performance hit for file I/O on Win* systems. On my system it was closer to a 120x hit. Problem report by Uwe Traum . The fix goes like this: The obstacle is 'FlushFileBuffers', executed whenever Tcl writes data to the OS, as Tcl has to wait for the disk to complete I/O, and disks are slow. We remove that obstacle. This opens another problem, [file size] reports back wrong numbers. So for [file size] we add the call back in. As optimization we keep track of the channels which were written to and flush only these. * win/tclWinFile.c (TclpObjStat): Added a call to 'TclWinFlushDirtyChannels'. This ensures that [file size] and related commands report the correct size of a file even if Tcl has recently written to it. Unixoid OS's always report the correct size even for files with pending data, but Win* syssystem don't. They only report what is actually on disk. * win/tclWinInt.h: Added declaration of 'TclWinFlushDirtyChannels', making it available to other parts of the tcl core. * win/tclWinChan.c (TclWinFlushDirtyChannels): New, internal, procedure. Goes through the list of open file channels and forces the OS to flush its file buffers for all which were written to since the last call of this function. This is an expensive operation as Tcl has to wait for the OS to complete actual writes to the disk. (FileInfo): Added dirty flag required by the procedure above. (FileOutputProc): Removed flushing of file buffers, setting the dirty flag instead. This means that the previously incurred delays do not happen anymore. (TclWinOpenFileChannel): Added initialization of 'dirty' flag. 2001-09-06 Jeff Hobbs * doc/http.n: noted -binary, charset and coding state keys. * tests/http.test: * library/http/pkgIndex.tcl: * library/http/http.tcl (geturl): correctly get charset parameter and convert text according to specified encoding (if known). RFC iso8859-1 is used by default. Also recognize Content-encoding to see if we should do binary translation. Added a CYA -binary switch for the cases that were missed. [Bug #219211 #219399] * tests/ioUtil.test: changed to make better use of constraints and remove knownBug constraints that weren't valid. 2001-09-06 Don Porter * tests/unixInit.test (unixInit-3.2): Updated test to support newer HP-UX releases that properly report euc-jp as the system encoding for Japanese. Bug report and patch verification by Bob Techentin. [Bug 453883] * doc/http.n: * library/http/*.tcl: * tools/tcl.wse.in: * tools/tclmin.wse: * unix/Makefile.in: * win/{Mm}akefile.*: Updated http package to version 2.4, reflecting the new features just added. 2001-09-06 Vince Darley * generic/tclTest.c: tests of old-fs hooks no longer cause problems in threaded builds. Also removed unused unload proc. * generic/tcl.decls: * generic/tclIOUtilc: added Tcl_FSMountsChanged so that a vfs can inform the filesystem that the filesystem epoch must be changed (since cached filesystems may now be incorrect). Fixes problem running tclvfs extension. * library/tcltest/tcltest.tcl: if tests aren't in a native filesystem, then don't use pipes to run them. [Bug 458741] 2001-09-06 Donal K. Fellows * generic/tcl.decls (479 generic): * generic/tclIO.c (Tcl_Seek,Tcl_Tell,Tcl_OutputBuffered): Added public function to return the size of the output buffer and reworked other channel functions to use this shared functionality and that of Tcl_InputBuffered() too. [TIP#49, Rolf Schroedter] 2001-09-05 David Gravereaux * generic/tclPlatDecls.h: Another small trim finalizing Borland support. * win/tclWinPipe.c: * win/tclWinPort.h: More Borland compatibility fixes. Changed EDQUOT #define from 49 to 69. Borland had a clash as it was already using this number. Upon advice from Helmut Giese, EDQUOT has been found in other header files #defined as 69. [Patch: 436116] * win/.cvsignore: A few more glob patterns added. * win/makefile.bc (new): Borland lives once more! rejoice.. * generic/tclAlloc.c: Small Borland compatibility fix. * win/tclWinTime.c: More Borland compatibility fixes. [Patch: 436116] 2001-09-05 Vince Darley * tests/winFCmd.test: made notWin2000 constraint false if not running on Windows at all. 2001-09-04 David Gravereaux * win/tclWinThrd.c: Revisited _beginthreadex() stuff. Instead of assuming a c-runtime implimentation of _beginthreadex normal, I reversed the logic to not assume, and use when is by explicitly needing to add runtimes that support it such as Borland. * generic/tcl.h: * generic/tclPlatDecls.h: Borland compatibility change so ClientData was properly typed as a void* and TCHAR would not be defined twice. * generic/tcl.h: Removed a small mistake from before. Changes to the EXTERN macro for proper Borland compatibility will have to see a TIP. What's this with the MS compiler: __declspec(dllexport) int func (int a, int b); will have to be this with Borland: int __cdecl __export func (int a, int b); The order of the attribute needs to be after the return type. 2001-09-04 Don Porter * compat/strtod.c (strtod): Fixed failure to handle expressions like 3eq2 and failure to set errno on overflow. [Bug 440894] 2001-09-04 Miguel Sofer * generic/tclProc.c: * tests/proc.test: made [proc] check that formal args have simple names [Bug 458548] 2001-09-04 Vince Darley Minor bug fixes in filesystem, plus small vfs changes as a result of enabling the test filesystem to work properly. * tests/fileName.test: ensure new test cleans up after itself * doc/filename.n: * generic/tclFileName.c: improved Mac path handling and document why [Bug: 421842] on Windows handling of UNC paths is not valid. Documentation and code now much clearer on what is and is not a UNC path. * doc/FileSystem.3: * unix/tclUnixPipe.c: * generic/tclFCmd.c: * generic/tclIOUtil.c: fixed error message, fixed [Bug: 453512] about dangerous use of tmpnam, replaced with mkstemp. Documented all the changes. * generic/tclTest.c: made test vfs fully functional as a 'reporting filesystem'. * generic/tcl.stubs: * generic/tcl.h: * generic/tclInt.h: * generic/tclIOUtil.c: * doc/file.n: * various platform-specific 'TclpLoadFile': fixed comments about unload behaviour, and completed objectification of loading. Required change to Tcl_Filesystem lookup table, so incompatible with 8.4a3, but not older versions of Tcl. The change also allows 'link' and 'reporting' filesystems to function correctly when loading files. Implementation of 'file delete -force' copes with case where cwd is inside the directory. Moved overlooked Tcl_FSGetPathType from internal to external API. Made sure filesystems which are registered and then unregistered are only freed when all references to them are gone. Documented changes. * unix/tclUnixFCmd.c: when deleting directories recursively, make sure permissions are ok. Together with the above, this fixes [Bug: 219139] * tests/winFCmd.test: differentiated test results for win2k versus not. This fixes [Bug: 219239] * tests/fCmd.test: added tests for 'file delete -force' where the cwd is inside, and when permissions are inadequate. 2001-09-04 Miguel Sofer * generic/tclCompile.c: fixed incorrect operands for INST_LIST [Bug: 458241] (David Cuthbert, dacut@users.sourceforge.net) 2001-09-03 Jeff Hobbs * generic/tclExecute.c (TclExecuteByteCode): fixed missing comma in debug macro. 2001-09-03 Donal K. Fellows * doc/ExprLongObj.3: Fixed error in documentation of argument type to Tcl_ExprObj [Bug: 457435] 2001-09-02 David Gravereaux * win/tclWinThrd.c: Portability fix for Cygwin who's c-runtime, not surprisingly, doesn't have the MSVCRT specific _beginthreadex / _endthreadex pair. This might have to be revisited for proper Borland, lcc32, Watcom and other support as well. [Patch: 444255] * win/tclWinThrd.c: Moved FinalizeConditionEvent() proto to within the main #ifdef TCL_THREADS block to avoid mingw warning about it being there but unused. * win/makefile.vc: Added -Zl (zee el) to tclStubLib.c compile line to make sure the tclstub84.lib static library is built without requiring a specific C-runtime library at link-time for the end-use developer. It has been noted on c.l.t that this trips many first time users trying to make extensions. [Patch: 403533] 2001-08-31 Jeff Hobbs * generic/tclInt.h: added TclCompileListCmd header * generic/tclBasic.c: added TclCompileListCmd compile proc * generic/tclCompCmds.c (TclCompileListCmd): function to compile the 'list' command at parse time. * generic/tclExecute.c (TclExecuteByteCode): definition of INST_LIST bytecode. * doc/StringObj.3: added words of warning to use Tcl_ResetResult with the Tcl_Append* functions. * tests/compile.test: added compile-11.* interp result checks * generic/tclUtil.c (TclGetIntForIndex): added Tcl_ResetResult before Tcl_AppendStringsToObj to prevent shared object crash when called from bcc instruction. The Tcl_Append* calls that append to the result object that are invoked by bcc insts must remember to call Tcl_ResetResult because the bcc doesn't do this for us. [Bug #456892] 2001-08-30 Jeff Hobbs * generic/tclIndexObj.c: fixed some casting problems that upset Crays. [Bug #419528] (andreasen) 2001-08-30 Don Porter * generic/tcl.h: Silence warning from Sun compiler. [Bug 454374] 2001-08-30 Miguel Sofer * generic/tclExecute.c: allow cached fully-qualified command names to be usable from different namespaces within the same interpreter without forcing a new lookup. This speeds up scripts that pass command names in variables ("this" in some OO packages). [Patch 456668]. 2001-08-30 Vince Darley Further fs updates. After examining the most common Tcl extensions (TclX, BLT, Tk, TclPro, Mktclapp), it has been determined that only TclpGetCwd and the Access/Stat/Open insert/delete hooks of the internal fs functions are ever used. The remaining functions from Tcl's internal interfaces have therefore been removed, since Tcl now exports a more suitable public API (Tcl_FS...) * generic/tclInt.stubs: * generic/tclInt.h: updated for removed internal functions. Some new internal functions have been put in tclInt.h (and not exported in the stub table because good public equivalents exist). * generic/tclTest.c: some test functions used the internal private APIs. These tests have been retained, but modified to use public APIs. Also objectified the internal filesystem tests. * win/tclWinFile.c: removed TclpStat, TclpAccess and refactored code to use NativeAccess, NativeStat. This should speed up stat, access and glob commands. * win/tclWinFCmd.c: removed all TclpCopy/Rename/Delete File/Directory string-based procedures which aren't used any more. Improved efficiency of some other procedures. Ensure that filename conversions with a NULL interp do not crash Tcl. * mac/tclMacFCmd.c: wrapped long lines and cleaned up TclpObjNormalizePath, removed all TclpCopy/Rename/Delete File/Directory string-based procedures which aren't used any more. * mac/tclMacFile.c: removed obsolete TclpStat, TclpAccess, TclpChdir, etc. * unix/tclUnixFCmd.c: removed use of TclpAccess, removed all TclpCopy/Rename/Delete File/Directory string-based procedures which aren't used any more. * unix/tclUnixFile.c: removed obsolete TclpStat, TclpAccess, TclpChdir, etc. * tcl(Unix|Mac|Win)Chan.c: objectified TclpOpenFileChannel. * various 'load' implementations all objectified. * generic/tclFileName.c: removed redundant code. * generic/tclIOUtil.c: removed TclStat, TclAccess, TclpListVolumes. Fix to MatchInDirectory at the root of a volume. Also improved some documentation, and improved default path joining behaviour for virtual filesystems, especially regarding '~'. * tests/fileName.test: added tests to check for bugs fixed above. * doc/FileName.3: improved documentation 2001-08-30 David Gravereaux * generic/tclAsync.c: * generic/tclEvent.c: * generic/tclInt.h: Improper cleanup of asyncMutex in tclAsync.c repaired. TclFinalizeSynchronization() was trying to remove a registered mutex that was dumped earlier when the TSD it was stored in was cleared. This was only surfacing on *nix. Windows was being masked by mutexes not actually being returned to the system! That was repaired in a previous patch. Needed to add a private TclFinalizeAsync() to tclAsync.c and called from Tcl_FinalizeThread(). Pheww.. Is this done yet? [Bug: 414419] requested by Rob Ratcliff 2001-08-28 Jeff Hobbs * generic/tclCompCmds.c (TclPushVarName): noted 'static' defn. [Bug #453872] 2001-08-26 Don Porter * library/auto.tcl (tcl_findLibrary): * tests/unixInit.test (unixInit-2.{1,9}): * unix/tclUnixInit.c (TclpInitLibraryPath): * win/tclWinInit.c (TclpInitLibraryPath): Corrected inconsistency between the search path for script libraries and the directory name $DISTNAME into which distributions built by 'make test' unpack. [Bug 455642] 2001-08-24 Jeff Hobbs * tests/stringComp.test: added string-1.3 * generic/tclCompCmds.c (TclCompileStringCmd): changed to return TCL_OUT_LINE_COMPILE instead of TCL_ERROR when compiling and an unknown string method is called. This is necessary as the string command may be never called, or not until 'string' is redefined. 2001-08-24 Vince Darley * doc/glob.n: documented windows-style path issue with glob. [Bug: 219392] * doc/filename.n: documented windows path/file length limitation. [Bug: 454597] 2001-08-24 Don Porter * tests/unixInit.test (unixInit-2.9): Corrected expected result to match Tcl's quirky construction of its init library path. 2001-08-23 Andreas Kupries * win/tclWinPipe.c (BuildCommandLine): Fixed tcl Bug [432499]. Part of the code used the non-absolute path to the executable to determine quoting. This failed if the absolute path contained spaces, but the application name itself not. This bug caused no trouble on Win NT 5, but does for other variants in the Win* family. Report and fix due to Ken Poole . 2001-08-23 Jeff Hobbs * unix/configure: * unix/tcl.m4: added QNX-6 build support. [Bug #219410] (loverso) * unix/tclUnixFCmd.c: * generic/tclIOUtil.c: * generic/tclFileName.c: corrected minor compiler warnings. 2001-08-23 Vince Darley Variety of small filesystem and vfs issues fixed or improved. The new fs code allows many new opportunities for efficiency improvements through the objectified API. The main changes integrated here are such efficiency improvements. Some limitations of the original implementation have also now been lifted. Meanwhile a variety of fs bugs (some old, some new) have also been fixed. * generic/tclFileName.c: Made Tcl_FSSplitPath more efficient, and removed some static string-based procedures which are no longer used. Much more objectification. Tcl_FSJoinPath is now very efficient and more aware of virtual filesystems. Clarified where the Mac-specific code attempts to interpret Unix-style paths. Modified TclDoGlob to use lstat not access to fix [Bug: 434876, L. Virden] * tcl(Win|Unix|Mac)FCmd.c: * tcl(Win|Unix|Mac)File.c: replaced TclpListVolumes with TclpObjListVolumes with different signature, updated code due to more efficient signature of Tcl_FSGetTranslatedPath. Used cached native paths where possible to improve efficiency -- this was completed on MacOS, but on Unix and Win the traversal functions make the task much more complex, so there are still some improvements possible there. Removed unused TclpNormalizePath which had been left in tclWinFCmd.c. Objectified all 'file attributes' functions. Fixed the new [Bug:451571, Bruce Stephens] which is most obvious on Unix, but could occur on MacOS or Windows. This bug actually existed in Tcl 8.3.x but was only made obvious by the recent filesystem overhaul when the code was exercised more heavily. * tests/fileName.test: Three new tests to exercise the above bug, and make sure it is fixed correctly. * unix/tclUnixFile.c: avoid panic in glob when a link doesn't point anywhere. It would probably be good to define exactly what Tcl should do in circumstances like these, and make sure mac/win/unix all behave accordingly. [Bug: 417111, Hemang Lavana]. Also fixed misleading/obsolete comment in the code. * generic/tcl.stubs: changed signature of Tcl_FSGetTranslatedPath and added Tcl_FSGetTranslatedStringPath. These changes allow further optimisations in the FS code. * generic/tcl.h: changed signature of Tcl_FSListVolumes so that it doesn't require a Tcl interpreter plus result. Renamed Tcl_FSReadLink to Tcl_FSLink with additional argument so we can support making links in the future. [Patch: 450340] * generic/tclInt.h: added declaration for TclpObjListVolumes. Objectified internal call signatures for 'file attributes' functions, and added an internal objectified get path type function. * generic/tclIOUtil.c: added the moved function TclpListVolumes which calls platform specific code (needed for backwards compatibility), and improved efficiency of parts of the FS (particularly file normalization). Much less copying and memory allocation is required now. added new GetPathType so that changes in 'file volumes' can actually affect files' types, and objectified more code. Made current code work with test suite artificially changing current platform. Added 'static' keywords where required. * generic/tclIO.c: * generic/tclTest.c: Added 'static' keywords, fixing [Bug: 453872, Bob Techentin] * generic/tclCmdAH.c: file command implementation updated for API changes, removed unnecessary special-case SplitPath static function, since it no longer helps prevent code duplication. Moved setting of interpreter result to each individual location that actually required it, to avoid very large code separation between reading and setting the result. * doc/FileSystem.3: updated documentation for the new or changed APIs, and clarified some issues. * doc/SplitPath.3: added pointer to newer APIs in FileSystem.3 * doc/filename.n: clarified current implementation of tilde support on Mac/Win. [Bug:453514, Sergey Kuzmin] * doc/glob.n: improved documentation for '-directory' and '-path' options. There are now many private, obsolete, platform-specific 'Tclp' string-based filesystem APIs which could be removed. We should check whether any of these are used by extensions and, at least in Tcl 9, remove them. The above changes signify a ***POTENTIAL INCOMPATIBILITY*** with 8.4a3, since signatures of two functions in the new API have changed, but not with older versions of Tcl. 2001-08-23 Donal K. Fellows * generic/tclBinary.c (FormatNumber): Extract a long from the object and not an int, to stop [binary format] from being unable to format some input numbers on architectures where sizeof(int) is less than sizeof(long) (particularly Alpha.) [tiprender Bug #441861] * tests/format.test: Converted conditional execution of tests into a test constraint. 2001-08-22 Jeff Hobbs * win/Makefile.in: * win/makefile.vc: updated install target for dde1.2 * doc/dde.n: fixed dde man page (which was totally incorrect). * tests/winDde.test: * win/tclWinDde.c (Tcl_DdeObjCmd): added -binary option to dde request command to allow for returning binary data. [Bug #227482] Updated dde to 1.2 * tests/tcltest.test: added unixExecs constraint to files that used 'grep' in the test. [Bug #453143] * library/tcltest/tcltest.tcl: fixed stdio constraint test. [Patch #454050] (stanton) Simplified unixExecs constraint test. 2001-08-22 Don Porter * tests/ioUtil.test (ioUtil-3.*): Corrected errors in tests revealed by fix of overagressive compiler. [Bug 451200] 2001-08-21 Miguel Sofer * generic/tclCompCmds.c: * tests/compile.test: Fixed overagressive compilation of [catch]: it was catching errors at substitution time. [Bug #219184] 2001-08-21 Jeff Hobbs * tests/tcltest.test (tcltest-12.2): fixed test that would break when env vars weren't Tcl list friendly [Patch #454046] (stanton) 2001-08-20 Jeff Hobbs * library/http/http.tcl (geturl): added port number to Host: header to comply with HTTP/1.1 spec (RFC 2068). [Bug #452217] 2001-08-16 David Gravereaux * tools/tcl.wse.in: * tools/tcl.hpj.in: * win/tcl.hpj.in: Removed -kb storage in CVS to ensure these text files are checked-out in the translation mode CVS is in. Setting these as binary as part of an effort to make sure they are always in CRLF, no matter what the CVS translation, is bypassing how CVS works and is confusing. * tools/genStubs.tcl: Removed LF-only output. Having to reconvert back to CRLF before committing to CVS was giving me a headache. [Bug: 451333] * win/makefile.vc: replaced $(WINDIR) with $(include32) for the .rc.res inference rule. winver.h wasn't getting included. [Bug: 445630] 2001-08-14 Miguel Sofer * generic/tclBasic.c: make the intial maxNestingDepth of an interpreter be MAX_NESTING_DEPTH instead of a hardwired value [Bug: 232564] 2001-08-13 Miguel Sofer * tests/trace.test: Corrected test numbers [Bug: 449794] 2001-08-12 Mo DeJong * unix/configure: Regen. * unix/configure.in: * unix/tcl.m4: Use GCC variable set by AC_PROG_CC instead of defining our own using_gcc variable. 2001-08-11 Vince Darley Variety of small issues introduced by the vfs code fixed: * generic/tclIOUtil.c: uninitialised read. * generic/tclFCmd.c: possible memory leak in file delete with error condition. 2001-08-10 Miguel Sofer * generic/tclVar.c: * tests/trace.test: Insure that [array] traces work correctly for undefined variables [Bug: 449094] 2001-08-09 Mo DeJong * unix/Makefile.in: Delete the unused getcwd.o target. This fixes bug #440942. 2001-08-08 Don Porter * library/dde/pkgIndex.tcl: * library/http/http.tcl: * library/http/pkgIndex.tcl: * library/msgcat/msgcat.tcl: * library/msgcat/pkgIndex.tcl: * library/opt/optparse.tcl: * library/opt/pkgIndex.tcl: * library/reg/pkgIndex.tcl: * library/tcltest/tcltest.tcl: * library/tcltest/pkgIndex.tcl: Added checks for package dependencies. Bumped patchlevels of changed packages: http 2.3.2, msgcat 1.2.2, opt 0.4.3, tcltest 2.0.1. [Patch 448931] * README: * generic/tcl.h: * tools/tcl.wse.in: * unix/configure: * unix/configure.in: * unix/tcl.spec: * win/README.binary: * win/configure: * win/configure.in: Bumped up patchlevel to 8.4a4 to distinguish CVS snapshots from the 8.4a3 release. This does not necessarily mean there will be an 8.4a4 release. [Bug 448938]. 2001-08-06 Jeff Hobbs 8.4a3 RELEASE * changes: * README: * mac/README: * unix/README: * win/README.binary: updated for 8.4a3 release * generic/tclFileName.c (Tcl_FSSplitPath): update to Tcl style guide. * generic/tclFCmd.c (FileCopyRename): fixed mem leak in introduction of vfs code where a new Tcl_Obj wasn't freed. * generic/tclCmdMZ.c (Tcl_RegexpObjCmd, Tcl_RegsubObjCmd): reordered the retrieval of arguments to avoid shimmering bug when the pattern and string referenced the same object. * unix/configure: regenerated * unix/tcl.m4: added GNU (HURD) configuration target. (brinkmann) [Patch: #442974] * win/README: made note of URL for Windows compilation notes * win/tclWinThrd.c (TclpFinalizeMutex, TclpFinalizeCondition): added DeleteCriticalSection calls for cleanup [Patch: #419683] * unix/tclUnixPipe.c (TclpCreateTempFile): fixed use of tmpnam, which is dangerous. [Patch: #442636] (lim) The use of tmpnam in TclpTempFileName must still be changed. * tests/http.test (http-4.14): fixed variable error return. [Bug: 424252] 2001-08-03 Jeff Hobbs * win/configure: regenerated * win/tcl.m4: fixed DLLSUFFIX definition to always be ${DBGX}.dll. This is necessary for TEA compliant builds that build shared against a static-built Tcl. * win/Makefile.in ($(TCLSH)): added $(TCL_STUB_LIB_FILE) to build target, otherwise it wouldn't get generated in a static build. 2001-08-06 Andreas Kupries * generic/tclIOCmd.c (Tcl_GetsObjCmd): Applied patch from SF item [442665] to fix the bug reported by it. The function can corrupt a freed object if it is called with objc == 3. This is because it retrieves resultPtr and does not increment its reference count, but then calls Tcl_ObjSetVar2, which causes the retrieved resultPtr object to be released. 2001-08-06 Don Porter * doc/tclsh.1: Added note that the tclsh program is frequently installed with the Tcl version numer as part of the name. [Patch 402725] * generic/tclPkg.c: * tests/pkg.test: [package forget] now forgets all of the package arguments it receives, not stopping when a package is not found. [Bug 415273] 2001-08-02 Jeff Hobbs * generic/tclIOUtil.c (Tcl_FSMatchInDirectory): corrected uninitialized value. 2001-08-02 Mo DeJong * generic/tclPlatDecls.h: * win/tclWinPort.h: Revert related changes made to improve Cygwin support on 2001-07-18. This change ended up breaking the VC++ build because of conflicts between Windows APIs and internal Tk APIs. 2001-08-01 Jeff Hobbs * unix/tclUnixFCmd.c: minor casts to eliminate warnings. (lim) [Patch: #440218] * tests/parseOld.test: changed some tests that required testwordend to exist to skip in a proper tcltest manner. [Bug: #442663] * library/http/http.tcl (http::mapReply): the regsub'ing of \n and \t to escape them was unnecessary. 2001-07-31 Vince Darley Changes from TIP#17 "Redo Tcl's filesystem" The following files were impacted: * doc/Access.3: * doc/FileSystem.3: * doc/OpenFileChnl.3: * doc/file.n: * doc/glob.n: * generic/tcl.decls: * generic/tcl.h: * generic/tclCmdAH.c: * generic/tclCmdIL.c: * generic/tclCmdMZ.c: * generic/tclDate.c: * generic/tclDecls.h: * generic/tclEncoding.c: * generic/tclFCmd.c: * generic/tclFileName.c: * generic/tclGetDate.y: * generic/tclIO.c: * generic/tclIOCmd.c: * generic/tclIOUtil.c: * generic/tclInt.decls: * generic/tclInt.h: * generic/tclIntDecls.h: * generic/tclLoad.c: * generic/tclStubInit.c: * generic/tclTest.c: * generic/tclUtil.c: * library/init.tcl: * mac/tclMacFCmd.c: * mac/tclMacFile.c: * mac/tclMacInit.c: * mac/tclMacPort.h: * mac/tclMacResource.c: * mac/tclMacTime.c: * tests/cmdAH.test: * tests/event.test: * tests/fCmd.test: * tests/fileName.test: * tests/io.test: * tests/ioCmd.test: * tests/proc-old.test: * tests/registry.test: * tests/unixFCmd.test: * tests/winDde.test: * tests/winFCmd.test: * unix/mkLinks: * unix/tclUnixFCmd.c: * unix/tclUnixFile.c: * unix/tclUnixInit.c: * unix/tclUnixPipe.c: * win/tclWinFCmd.c: * win/tclWinFile.c: * win/tclWinInit.c: * win/tclWinPipe.c 2001-07-24 Mo DeJong * win/tclWinThrd.c (Tcl_CreateThread): Close Windows HANDLE returned by _beginthreadex. The MS documentation states that this handle is not closed by a later call to _endthreadex. 2001-07-21 Don Porter * doc/pkgMkindex.n: * library/package.tcl: Corrected documentation and usage message of [pkg_mkIndex]. 2001-07-18 Mo DeJong * generic/tclPlatDecls.h: Define TCHAR by including windows.h instead of tchar.h since Cygwin does not support the tchar.h header. Include CHECK_UNICODE_CALLS logic from tclWinPort.h. * win/tclWinPort.h: Remove CHECK_UNICODE_CALLS logic. Remove include of windows.h since this now done it tclPlatDecls.h. * win/tclWinReg.c: Remove duplicate include of windows.h. 2001-07-18 Andreas Kupries * generic/tclIO.c: Aftermath to [SF #427196]. Squash empty buffers if they are smaller than the requested buffersize, to prevent reusage of old buffers and to honor changes in the requested buffersize made by the user. 2001-07-17 Mo DeJong * win/tclWinFile.c (TclpReadlink): Add Cygwin specific definition for the TclpReadlink function. This method implements reading of symbolic links when build with Cygwin. 2001-07-17 Mo DeJong * win/tclWinPort.h: Add Cygwin specific defines for environ and timezone variables. 2001-07-17 Andreas Kupries * generic/tclIO.c (GetInput): Fixed [SF #427196]. Memory was overwritten because a buffer was used after a change of the requested buffersize together with that requested buffersize and not its actual size, which was smaller. Note that the continous reuse of the smaller buffer negatively impacts performance. The system never allocates a buffer with the newly requested bigger buffersize. 2001-07-16 Mo DeJong * generic/tcl.h: Define __WIN32__ when __CYGWIN__ or __MINGW32__ is defined. * generic/tclAlloc.c: Define caddr_t when compiling with VC++ or mingw. This type is already defined when compiling with Cygwin. 2001-07-16 Mo DeJong * win/tclWinConsole.c: * win/tclWinPipe.c: * win/tclWinPort.h: * win/tclWinSerial.c: * win/tclWinThrd.c: Remove unnecessary #includes of dos.h, direct.h, and tchar.h. This will help the Cygwin porting effort since these headers do not exist under Cygwin. 2001-07-16 Jeff Hobbs * win/tclWinPipe.c (PipeClose2Proc): constrained the mutex lock to just the TerminateThread call and waiting for termination. (jsmith) * generic/tclCmdMZ.c: Removed extra copy of the SCAN_* macros #defined in generic/tclScan.c. (porter) [Bug 441230] 2001-07-12 Donal K. Fellows * tests/unixInit.test (unixInit-2.8): Added extra constraint, notInstalledInTmp, to stop this test from damaging installations in /tmp; not much fun to have to reinstall the Tcl library every time you run the test suite! * tests/subst.test (subst-10.*): Updated tests to check new behaviour for 'break' in command substitutions. (subst-1.2,subst-7.1): Error messages changed. * doc/SubstObj.3: New file, to document Tcl_SubstObj. * doc/subst.n: Improved and updated documentation for 'subst' to help support the changed behaviour. * generic/tcl.decls (generic-437): Declaration for Tcl_SubstObj * generic/tcl.h (TCL_SUBST_*): Added flags for Tcl_SubstObj. * generic/tclCmdMZ.c (Tcl_SubstObj,Tcl_SubstObjCmd): Divided into two parts to allow people to access the innards of 'subst' and changed the behaviour when command substitutions do a 'break' to be different from 'continue'. Also now works with objects, which allows for some nifty optimisations with variable substitutions and a slight improvement with command substitutions. [TIP#36] 2001-07-10 Mo DeJong * unix/Makefile.in: Add AR variable for use in STLIB_LD. * unix/configure: Regen. * unix/configure.in: Use STLIB_LD when defining MAKE_LIB and MAKE_STUB_LIB. Subst RANLIB and AR. * unix/tcl.m4 (SC_CONFIG_CFLAGS): Add doc comment about STLIB_LD command. Check ${AR} env var when setting STLIB_LD and delay evaluation until make time. * win/configure: Regen. * win/tcl.m4 (SC_CONFIG_CFLAGS): Delay evaluation of ${AR} in STLIB_LD and add flags to better match the Unix implementation. Don't bother defining AR when using VC++ since it is not used. 2001-07-06 Mo DeJong * win/configure: Regen. * win/tcl.m4 (SC_CONFIG_CFLAGS): Pass -e _WinMain@16 in addition to the -mwindows flag to work around a problem with ld when it incorrectly use main() as the executable entry point when both WinMain() and main() are available. 2001-07-06 Donal K. Fellows * tests/cmdAH.test: Added leading zero to file modes to work around fault in HPUX strtol() which ignores the base parameter [Bug #438808] 2001-07-05 Mo DeJong * win/Makefile.in: Subst DEPARG directly instead of relying on a variable. This will make Cygwin builds faster since an extra exec will be avoided. * win/configure: Regen. * win/configure.in: Subst DEPARG. * win/tcl.m4 (SC_CONFIG_CFLAGS): Move AC_MSG_CHECKING after the AC_CHECK_PROG so that status messages do not get mixed together. Set DEPARG based on the results of the cygpath check so that we avoid using an extra exec when it is not needed. Use ac_cv_cygwin status flag instead of looking at the output of gcc -v, which works in the case where -mno-cygwin is set in the CFLAGS. 2001-07-04 Jeff Hobbs * README: * mac/README: * unix/README: * win/README: * win/README.binary: updated READMEs with purls 2001-07-03 Mo DeJong * win/Makefile.in: Remove PATHTYPE variable. * win/configure: Regen. * win/configure.in: Don't subst PATHTYPE. * win/tcl.m4 (SC_CONFIG_CFLAGS): Remove PATHTYPE variable. Set CYGPATH to "cygpath -w" if the cygpath executable is found on the path. This approach works for native Cygwin builds and cross compiles. 2001-07-03 Jeff Hobbs * tests/var.test: * generic/tclVar.c (Tcl_VariableObjCmd): added patch to check for number of args. [Patch #426038] * generic/tclVar.c (Tcl_GetVar2Ex): added ability to recognize TCL_TRACE_READS flags to cause creation of part1 in TclLookupVar to make sure newly created array will get read traces triggered appropriately. This is called by Tcl_ObjGetVar2, Tcl_GetVar, and Tcl_GetVar2. (TclSetIndexedScalar, TclSetElementOfIndexedArray): added read trace triggering for lappend case. (Tcl_LappendObjCmd): pass TCL_TRACE_READS to Tcl_ObjGetVar2 to trigger possible read traces for new arrays. * generic/tclExecute.c (TclExecuteByteCode): added TCL_TRACE_READS flag to INST_LAPPEND(_ARRAY)_STK case to trigger read traces for newly created arrays. Removed unnecessary #ifdef for TCL_COMPILE_DEBUG in INST_LOAD_SCALAR1 case. * tests/append.test: * tests/appendComp.test: added tests for read trace triggering for append and lappend. 2001-07-03 Mo DeJong * tests/clock.test (clock-2.5): Adjust test so that it passes when the time slice is 60 msecs, now passes under Windows 98. 2001-07-03 Mo DeJong * win/tcl.m4 (SC_CONFIG_CFLAGS): Don't pass the v flag to ${AR} when using gcc, verbose output is not needed. 2001-07-03 Don Porter * tests/unixInit.test (unixInit-2.8): Changed test back to using installation layout, adding comments explaining why the test writes to the directories it does, and checks to avoid destroying other files in /tmp. 2001-07-03 Donal K. Fellows * tests/unixInit.test (unixInit-1.2): Fixed faults reported in Bug#438070 - well, at least enough to work on Solaris - and added comments that should make what is going on in the test clearer. 2001-07-02 Jeff Hobbs * tests/util.test: added util-4.6 * generic/tclUtil.c (Tcl_ConcatObj): Corrected walking backwards over utf-8 chars. [Bug #227512] 2001-07-02 Don Porter * tests/unixInit.test (unixInit-2.8): Corrected test for all absolute pathnames in library path when executable is installed near root directory to use correct development directory layout. [Bug 438014] * tests/unixInit.test (unixInit-2.9): * unix/tclUnixInit.c (TclpInitLibraryPath): * win/tclWinInit.c (TclpInitLibraryPath): Corrected buggy construction of search path entries relative to executable. Added test for bad construction. [Bug 438014] 2001-06-28 Miguel Sofer * generic/tclNamesp.c: Correction to faulty patch from [Bug: 231259] 2001-06-28 Donal K. Fellows * tests/unixInit.test (unixInit-1.2): Modified so as not to require a local echo service, which fails on many systems which have that turned off for security reasons... 2001-06-27 Jeff Hobbs * generic/tclInt.h: * generic/tclObj.c: * unix/Makefile.in: added a -DPURIFY mode that makes Tcl_Obj's allocated and free singularly (instead of in alloc in blocks and never free) to allow checkers like Purify to operate better. * library/encoding/koi8-u.enc: added koi8-u (Ukranian variant) encoding. * tests/subst.test: * generic/tclUtf.c (Tcl_UtfBackslash): Corrected backslash handling of multibyte utf-8 chars. [Bug #217987] * generic/tclCmdIL.c (InfoProcsCmd): fixed potential mem leak in info procs that created objects without using them. * generic/tclCompCmds.c (TclCompileStringCmd): fixed mem leak when string command failed to parse the subcommand. * doc/interp.n: * doc/unknown.n: updated notes about what is in a safe interp. [Bug #218605] 2001-06-27 Donal K. Fellows * tests/event.test (event-11.5): Removed hard-coded port number which could fail on some systems. [Bug #436727] 2001-06-26 Mo DeJong * unix/Makefile.in: * win/Makefile.in: Add `make shell` target. This target will set the proper env vars before invoking tclsh from the build directory. 2001-06-26 Mo DeJong * win/Makefile.in: Use : to separate VPATH entries. This works for both Cygwin builds and cross builds, the VPSEP variable is simply unneeded complexity. * win/configure: Regen. * win/configure.in: Don't subst VPSEP. * win/tcl.m4 (SC_CONFIG_CFLAGS): Remove VPSEP variable. 2001-06-26 Mo DeJong * unix/configure: Regen. * unix/configure.in: Fix last checkin by removing export since that only works in bash. * win/configure: Regen. * win/configure.in: Ditto. 2001-06-26 Mo DeJong * unix/configure: Regen. * unix/configure.in: Set CFLAGS to "" if the user did not set CFLAGS in the env. This keeps AC_PROG_CC from adding "-g -O2" to the CFLAGS by default. * win/configure: Regen. * win/configure.in: Ditto. 2001-06-25 Mo DeJong * win/configure: Regen. * win/configure.in: Use RC_DEFINE flag from tcl.m4. * win/tcl.m4 (SC_CONFIG_CFLAGS): Set RC_DEFINE flag based on the compiler in use. 2001-06-25 Mo DeJong * win/tcl.m4 (SC_CONFIG_CFLAGS): Link to the imm32 library when building with mingw gcc. 2001-06-25 Mo DeJong * win/configure: Regen. * win/tcl.m4 (SC_CONFIG_CFLAGS): When building with gcc, don't attempt to link with LD or support dllwrap. Simply require a recent version of Cygwin gcc or Mingw gcc that supports -shared. When linking, use gcc instead of ld since gcc automatically includes libs like -lmsvcrt. 2001-06-22 Mo DeJong * win/configure: Regen. * win/configure.in: Add resource compiler fix from 8.3.3 to fix compiling with mingw. 2001-06-22 Mo DeJong * win/configure: Regen. * win/tcl.m4: Fix silly typo in last checkin. 2001-06-22 Mo DeJong * unix/Makefile.in: Set CFLAGS to @CFLAGS@ and @CFLAGS_DEFAULT@. Set LDFLAGS to @LDFLAGS@ and @LDFLAGS_DEFAULT@. Add LDFLAGS_DEBUG and LDFLAGS_OPTIMIZE to match the way CFLAGS_DEFAULT works. This will support user set CFLAGS or LDFLAGS at configure time. * unix/configure: Regen. * unix/configure.in: Don't set CFLAGS to CFLAGS_DEFAULT, instead subst CFLAGS_DEFAULT into the Makefile. Add AC_SUBST for CFLAGS_DEFAULT, LDFLAGS_DEFAULT, LDFLAGS_DEBUG, and LDFLAGS_OPTIMIZE. * unix/tcl.m4 (SC_ENABLE_SYMBOLS): Modify LDFLAGS_DEFAULT so that it uses a Makefile variable just like CFLAGS_DEFAULT. * win/Makefile.in: Set CFLAGS to @CFLAGS@ and @CFLAGS_DEFAULT@. Set LDFLAGS to @LDFLAGS@ and @LDFLAGS_DEFAULT@. This will support user set CFLAGS or LDFLAGS at configure time. * win/configure: Regen. * win/configure.in: Don't set CFLAGS or LDFLAGS, instead subst CFLAGS_DEFAULT and LDFLAGS_DEFAULT into the Makefile. * win/tcl.m4 (SC_ENABLE_SYMBOLS): Modify LDFLAGS_DEFAULT so that it uses a Makefile variable just like CFLAGS_DEFAULT. 2001-06-22 Mo DeJong * win/configure: * win/tcl.m4 (SC_CONFIG_CFLAGS): Don't set LDFLAGS_DEBUG to -g or LDFLAGS_OPTIMIZE to -O when compiling with gcc. These flags are not needed and can cause problems with the Cygwin version of ld. 2001-06-18 Donal K. Fellows * tests/unixInit.test (unixInit-1.2,unixInit-2.8): Added test for code described below, and fixed a couple of errors that caused problems during testing; the code to determine the installedTcl constraint was wrong, and test unixInit-2.8 assumed that /tmp/lib was free for use and could be deleted, which clashed nastily with my installation and made other tests fail unnecessarily! * unix/tclUnixChan.c (TtyInit,TclpOpenFileChannel, Tcl_MakeFileChannel,TclpGetDefaultStdChannel): Alterations so that the standard channels - stdin, stdout and stderr - have the correct type and fconfigure options. This required making the initialisation of serial lines a little more sophisticated to make the console behave correctly in interactive mode... [Bug #219137 and duplicates] 2001-06-16 Don Porter * generic/tclInt.decls: * generic/tclInt.h: * generic/tclPanic.c (Tcl_PanicVA): * mac/tclMacAppInit.c (main): * mac/tclMacPanic.c (TclpPanic): * unix/tclUnixPort.h: * win/tclWinPort.h: Replaced TclMacSetPanic with TclpPanic for setting a platform-specific panic handler. TclpPanic is NULL on Unix and Windows. Fixes broken wish on Mac due to earlier patches. [Patch 415648] * generic/tclIntPlatDecls.h: * generic/tclStubInit.c: `make gentubs` after above changes. 2001-06-13 Don Porter * mac/tclMacAppInit.c (main, Macintosh_Init): * mac/tclMacBOAAppInit.c (main): * mac/tclMacPanic.c: Applied patches from Dan Steffen correcting problems on the Macintosh in the 2001-06-08 changes. 2001-06-12 Donal K. Fellows * tests/regexp.test (regexp-18.12): * generic/tclCmdMZ.c (Tcl_RegexpObjCmd): Fixed so that submatches that do not match always have index pair {-1 -1} [Bug #219232] 2001-06-08 Don Porter * generic/tcl.h: * generic/tcl.decls: * generic/tclPanic.c: Added CONST to Tcl_*Panic* public interfaces. [Patch 415648, TIP 27] * generic/tclInt.decls: * mac/tclMacAppInit.c (main): * mac/tclMacBOAAppInit.c (main): * mac/tclMacPanic.c: Modified special Mac implementations of Tcl_*Panic* to be exact copies of the generic implementations. Added TclMacSetPanic. The generic implementations should be used directly, rather than copies, but that requires further changes by someone familiar with the Mac build systems. [Patch 415648] * generic/tclDecls.h: * generic/tclIntPlatDecls.h: * generic/tclStubInit.c: `make gentubs` after above changes. * doc/Panic.3: * unix/mkLinks: New file documenting Tcl_*Panic* public interfaces, followed by `make mklinks`. [Patch 415648, Bug 219170, Bug 414936] 2001-06-03 Jeff Hobbs * generic/tclUtil.c (Tcl_DStringAppendElement): patch to save an extra strlen call. [Bug #428572] 2001-05-30 Donal K. Fellows * generic/tclExecute.c (TclExecuteByteCode): Added two casts to INST_STR_CMP implementation to get rid of a couple warnings from the SUNWspro C compiler. * generic/tclBasic.c (Tcl_GetMathFuncInfo,Tcl_ListMathFuncs): * generic/tclCmdIL.c (Tcl_InfoObjCmd,InfoFunctionsCmd): * generic/tcl.decls (generic table, positions 435+436): * tests/info.test: * doc/CrtMathFnc.3: * doc/info.n: Changes due to TIP #15 "Functions to List and Detail Math Functions" 2001-05-28 Jeff Hobbs * library/init.tcl (unknown): removed errant " in error message 2001-05-27 Jeff Hobbs * generic/regc_locale.c: updated character class range data for Unicode v3.1.0 compliance. * generic/tclUniData.c: regenerated from Unicode v3.1.0 data file (new as of 2001-05-16). This brings Tcl to current unicode compliance. * tests/utf.test: added tests to check unicode 3 compliance * unix/Makefile.in (tclUtf.o): added tclUniData.c dependency. * tools/uniClass.tcl: added comments to output format and the script for clarification. * tools/uniParse.tcl: corrected filename output and GetDelta macro to use 'info' as param (was 'infO') 2001-05-26 Donal K. Fellows * generic/tclVar.c (tclArraySearchType,SetArraySearchObj, ParseSearchId): Added code to speed up array searching by reducing the amount of parsing needed for searchIds. * generic/tclObj.c (TclInitObjSubsystem): * generic/tclIndexObj.c (Tcl_GetIndexFromObjStruct): * generic/tclNamesp.c (TclInitNamespaceSubsystem): * generic/tclInt.h: Moved some Tcl_ObjType initialisation to TclInitObjSubsystem to be with the bulk of the rest. [Patch 424851] Committed by Miguel Sofer 2001-05-23 Jeff Hobbs * tests/io.test: changed io-52.[9-11] to not be platform sensitive with EOL translation. * library/encoding/cp1250.enc: * library/encoding/cp1251.enc: * library/encoding/cp1252.enc: * library/encoding/cp1253.enc: * library/encoding/cp1254.enc: * library/encoding/cp1255.enc: * library/encoding/cp1256.enc: * library/encoding/cp1257.enc: * library/encoding/cp1258.enc: * library/encoding/cp874.enc: * library/encoding/iso8859-6.enc: * library/encoding/iso8859-7.enc: * library/encoding/iso8859-8.enc: * library/encoding/iso8859-10.enc (new): * library/encoding/iso8859-13.enc (new): * library/encoding/iso8859-14.enc (new): updated encoding tables based on http://www.unicode.org/Public/MAPPINGS/. (kuhn) 2001-05-23 Mo DeJong * unix/tcl.m4 (SC_PATH_TCLCONFIG): Fix comments, and typo in cached variable name. 2001-05-23 Mo DeJong * unix/tcl.m4 (SC_LOAD_TKCONFIG): Remove use of undefined TCLCONFIG variable and call AC_MSG_RESULT to print the checking result. * win/tcl.m4: Ditto. 2001-05-22 Jeff Hobbs * generic/tclObj.c (TclAllocateFreeObjects): simplified objSizePlusPadding to use sizeof(Tcl_Obj) (max) Corrected use of tclObjsAlloced/Freed/Shared in TCL_MEM_DEBUG compile. 2001-05-22 Miguel Sofer * generic/tclExecute.c: removed Tcl_DuplicateObj in INST_DUP 2001-05-21 Jeff Hobbs * tests/tcltest.test (tcltest-19.1): fixed failing test that was getting affected by Windows env handling of empty valued elements. * unix/tcl.m4: added more common install directories in which to search for *Config.sh [Bug #419812] * tests/cmdMZ.test (cmdMZ-1.4): added notLinux constraint to test to prevent failure message on Linux due to OS caching bug. * tests/httpd (httpdRespond): added response to timeout value in query string. * tests/http.test: removed unused notLinux constraint setting * generic/tclRegexp.c (Tcl_RegExpExecObj): added use of Tcl_GetUnicodeFromObj. 2001-05-19 Andreas Kupries * Note that "tclbench" (see project "tcllib") was extended with performance benchmarks for [fcopy] too. * doc/fcopy.n: Updated to reflect the extended behaviour of 'fcopy'. * tests/io.test: Added tests 'io-52.9', 'io-52.10' and 'io-52.11' to test the handling of encodings by 'fcopy' / 'TclCopychannel' [Bug #209210]. * generic/tclIO.c: Split of both 'Tcl_ReadChars' and 'Tcl_WriteChars' into a public error checking and an internal working part. The public functions now use the new internal ones. The new functions are 'DoReadChars' and 'DoWriteChars'. Extended 'CopyData' to use the new functions 'DoXChars' when required by the encodings on the input and output channels [Bug #209210]. 2001-05-16 Jeff Hobbs * library/history.tcl (tcl::HistAdd): prevent empty calls from being added to the history (arndt) * tests/error.test: updated error-1.3 message to account for string index being compiled at toplevel. * tests/appendComp.test: * tests/stringComp.test: new files for extended bytecode testing * generic/tclBasic.c: added new CompileProc invocations to basic command initialization. * generic/tclCompCmds.c: added new compile commands for append, lappend, lindex and llength. Refactored set and incr compile commands to use new TclPushVarName function for handling the varname component during compilation (also used by append and lappend). Changed string compile command to compile toplevel code as well (when possible). * generic/tclCompile.c: added new instruction enums * generic/tclCompile.h: added debug info for new instructions * generic/tclExecute.c (TclExecuteByteCode): moved elemPtr to toplevel var (oft-used). Added definitions for new bytecode instructions INST_LIST_INDEX, INST_LIST_LENGTH, INST_APPEND_SCALAR1, INST_APPEND_SCALAR4, INST_APPEND_ARRAY1, INST_APPEND_ARRAY4, INST_APPEND_ARRAY_STK, INST_APPEND_STK, INST_LAPPEND_SCALAR1, INST_LAPPEND_SCALAR4, INST_LAPPEND_ARRAY1, INST_LAPPEND_ARRAY4, INST_LAPPEND_ARRAY_STK, INST_LAPPEND_STK. Refactored repititious code for reuse with INST_LOAD_STK (same as INST_LOAD_SCALAR_STK), INST_STORE_STK (same as INST_STORE_SCALAR_STK). Updated INST_STR_CMP with style of fix of 2001-04-06 Fellows [Bug #219201] as that fix only affected the runtime eval'ed "string" (string compare is normally byte-compiled now). We may want to back these out for speed in the future, noting the problems with \x00 comparisons in the docs. * generic/tclInt.h: declarations for new compile commands. * generic/tclVar.c: change TclGetIndexedScalar, TclGetElementOfIndexedArray, TclSetElementOfIndexedArray and TclSetIndexedScalar to use flags. The Set functions now support TCL_APPEND_ELEMENT and TCL_LIST_ELEMENT as well. * generic/tclInt.decls: * generic/tclIntDecls.h: minor signature changes for above. * generic/tclCmdMZ.c: made use of new Tcl_GetUnicodeFromObj. 2001-05-16 Donal K. Fellows * doc/console.n: Deleted. Put it in the wrong source tree! D'oh! 2001-05-15 Jeff Hobbs * generic/tcl.decls: * generic/tclDecls.h: * generic/tclStubInit.c: * generic/tclStringObj.c (Tcl_GetUnicodeFromObj): new function to parallel Tcl_GetStringFromObj (fix of an API oversight). * unix/tclUnixPipe.c: updated pipeChannelType to TCL_CHANNEL_VERSION_2 type specification. * tests/fileName.test: corrected tests not to fail on win when a C:/test dir exists. * generic/tclFileName.c (ExtractWinRoot): corrected ABR error 2001-05-15 Miguel Sofer * tests/lindex.test: added test for nested braces [Patch: 423617] 2001-05-15 Miguel Sofer * generic/tclInt.h * generic/tclNamesp.c: invalidate all bytecodes in a namespace if a new command shadows a bytecoded command. * tests/namespace.test Patched from [Bug: 231259] 2001-05-15 Donal K. Fellows * doc/console.n: Created. It seems very odd to me that the console implementation is part of the Tcl distribution and not part of Tk, but given the location of the source, the documentation must obviously match up... 2001-05-14 Donal K. Fellows * generic/tclCmdMZ.c (Tcl_StringObjCmd): * tests/string.test (string-4.14): Negative string indices should not be added as offsets to the result of [string first] but instead be treated as referring to the start of the string. [Bug: 423581] 2001-05-11 Mo DeJong * unix/Makefile.in: Add a LDFLAGS variable to the Makefile instead of directly substing @LDFLAGS@. * unix/configure: Regen. * unix/tcl.m4: Fix CFLAGS_DEFAULT so that the name of a Makefile variable is passed as @CFLAGS@. * win/Makefile.in: Move the setting of CFLAGS higher up in the Makefile. * win/configure: Regen. * win/configure.in: Use dnl to comment out macros so that they are not accidently expanded. * win/tcl.m4: Fix CFLAGS_DEFAULT so that the name of a Makefile variable is passed as @CFLAGS@. 2001-05-07 Miguel Sofer * generic/tclExecute.c: insure different rand() seeds in different threads [Bug 416643] 2001-05-03 Jeff Hobbs * tests/tcltest.test: removed extraneous 'c' (doh!) [Bug: 414031] * tools/tcltk-man2html.tcl: removed use of 'exec' for portability and fixed up code. 2001-05-03 Don Porter * doc/library.n: * library/init.tcl: * tests/autoMkindex.t*: Modified [auto_import] to apply pattern matching in the [namespace import] style. [Bug 420186] ***POTENTIAL INCOMPATIBILITY*** for any callers of [auto_import] from outside Tcl that expect the pattern matching to be like that of [string match]. 2001-05-03 Miguel Sofer * generic/tclParse.c: * tests/namespace.test: Insure consistent behaviour of the [unknown] command: when a command is unknown, it is always processed by [::unknown], ignoring any namespace proc which happens to be called "unknown" [Patch #421166, Bug #420507] 2001-05-02 Don Porter * tools/genStubs.tcl: Add a package require of Tcl 8 at the beginning of the script so that the script will print a descriptive error message when run in an old Tcl 7 shell. 2001-04-27 Kevin Kenny * generic/tclInt.decls: * generic/tclInt.h: * generic/tclCmdIL.c: * generic/tclProc.c: * generic/tclVar.c: Added another collection of missing CONSTs related to TclGetNamespaceForQualName. * generic/tclIntDecls.h: Regenerated. 2001-04-25 Mo DeJong * unix/configure: Regen. * unix/tcl.m4: Subst TCL_THREADS into tclConfig.sh. * unix/tclConfig.sh.in: Add TCL_THREADS variable. * win/configure: Regen. * win/tcl.m4: Subst TCL_THREADS into tclConfig.sh. * win/tclConfig.sh.in: Add TCL_THREADS variable. 2001-04-25 Mo DeJong * unix/configure: Regen. * unix/configure.in: Use $@ in MAKE_LIB and MAKE_STUB_LIB commands instead of using a delayed subst variable. Replace instances of STUB_LIB_FILE with TCL_STUB_LIB_FILE. 2001-04-25 Mo DeJong * unix/Makefile.in: Use TCL_STUB_LIB_FILE instead of STUB_LIB_FILE. * unix/configure: Regen. * unix/configure.in: Don't subst STUB_LIB_FILE, use TCL_STUB_LIB_FILE instead. 2001-04-25 Donal K. Fellows * tools/encoding/iso8859-15.txt: * library/encoding/iso8859-15.enc: Oops! Got the full encoding wrong. Should be fixed now... * tools/encoding/iso8859-15.txt: * library/encoding/iso8859-15.enc: * tools/tcl.wse.in: Added ISO 8859-15 (a.k.a. Latin-1 + Euro currency symbol) support. * generic/tclNamesp.c: * generic/tclBasic.c (TclRenameCommand): Missing CONST from several declarations relating to use of TclGetNamespaceForQualName 2001-04-24 Kevin B. Kenny * doc/AssocData.3: * doc/CrtCommand.3: * doc/CrtMathFnc.3: * doc/CrtObjCmd.3: * doc/ExprLong.3: * generic/tclBasic.c: * generic/tclCmdMZ.c: * doc/CrtSlave.3: * generic/tclNamesp.c: * generic/tcl.decls: * generic/tcl.h: * generic/tclInt.decls: * generic/tclInt.h: (TIP #27) Another round of CONST changes, this time adding CONST to the API's exported from tclBasic.c. [Patch #415179] ***POTENTIAL INCOMPATIBILITY*** from 8.4a2, in which Vince Darley's changes to command tracing were added. A const has been added to the type signature of one of the parameters to Tcl_CommandTraceProc. 2001-04-10 Kevin B. Kenny * unix/tclUnixTime.c: Altered code to use memcpy instead of structure assigments in an effort to achieve better K&R compatibility. 2001-04-10 Kevin B. Kenny * unix/tclUnixTime.c: Fixed silly typo in calls to 'gmtime' and 'localtime' that broke the Linux build. 2001-04-09 Kevin B. Kenny * unix/tclLoadShl.c: Added DYNAMIC_PATH to the load flags so that the SHLIB_PATH will be searched for other libraries. [Bug #219140] 2001-04-09 Kevin B. Kenny * unix/tcl.m4: Added _REENTRANT to Solaris build so that thread safe library routines are included. * unix/configure: Re-ran 'autoconf' with changed tcl.m4 * tclUnixTime.c: Modified for thread safety of 'gmtime' and 'localtime' system calls [Bugs #219136 and #232558] 2001-04-09 Donal K. Fellows * tests/expr.test (expr-21.*): Tests to check below fix. * generic/tclParseExpr.c (GetLexeme): Now recognises the non-numeric boolean literals for what they are. It no longer makes sense for anyone to create functions with the same name as one of them, but this was true in 7.* as well [Bug #217777; finally!] 2001-04-07 Miguel Sofer * generic/tclExecute.c: Avoid panic when there are extra items in the tcl stack [Bug #406709, Patch #414470] * tests/foreach.test: test to exercise the patch 2001-04-07 Miguel Sofer * doc/namespace.n: document correct functionality * generic/tclNamesp.c: corrected behaviour of [namespace code] (Bug #219385, Patch #403530) * library/init.tcl: * tests/namespace-old.test: test correct functionality * tests/namespace.test: test correct functionality 2001-04-07 Andreas Kupries * unix/Makefile.in (checkdoc): New target, checking the definitions as found in the compiled library against the manpages to find undocumented public functionality. * unix/mkLinks: Updated to include the new manpage. * doc/UniCharIsAlpha.3: New manpage documenting the Unicode character classification APIs [Bug #218720]. 2001-04-07 Andreas Kupries * unix/mkLinks: Updated to incorporate the changes below. * doc/StringObj.3: Added 'Tcl_AttemptSetObjLength' to the NAME section. [Bug #414435]. * doc/Alloc.3: Added both 'Tcl_AttemptAlloc' and 'Tcl_AttemptRealloc' to the NAME section. [Bug #414435]. * doc/Utf.3: Added both 'Tcl_UniCharCaseMatch' and 'Tcl_UniCharNcasecmp' to the NAME section. [Bug #414435]. 2001-04-06 Don Porter * library/init.tcl: * tests/init.test: Modified processing of $::errorInfo by [unknown] when the auto-loaded command throws an error to better cover the tracks of auto-loading. [Bug 219280, Patch 403551] 2001-04-06 Donal K. Fellows * doc/read.n: Added section on "USE WITH SERIAL PORTS" to resolve [Bug #219402] * tests/string.test (string-2.30): Test for this case * generic/tclCmdMZ.c (Tcl_StringObjCmd, STR_COMPARE branch): Fixed problem caused by Utf-rep of \x00 being more than Utf-rep of \x01 fooling memcmp by forcing everything through Utf-based comparisons. Added optimizations for case where objects have a string/unicode-rep or a bytearray-rep (i.e. where we can perform comparisons on fixed-size units.) [Bug #219201] * generic/tclUtf.c (Tcl_UtfNcmp): Corrected seriously erroneous comment. 2001-04-05 Andreas Kupries * doc/Macintosh.3: Removed duplicates from .SH line [Bug #413983]. 2001-04-05 Donal K. Fellows * generic/tclCmdMZ.c (Tcl_StringObjCmd): Fixed so will compile with K&R compilers [Patch #413844, Bug #413847] 2001-04-04 Don Porter * generic/tclMain.c: Patch from Kevin Kenny to restore support of pre-ANSI compilers. [Bug 413846, Patch 413842] 2001-04-04 Andreas Kupries * unix/mkLinks: Updated to contain the new manpage. * doc/Environment.3: New manpage, describes Tcl_PutEnv [Bug #219171]. * doc/Macintosh.3: New manpage describing the macintosh specific parts of the public API [Bug #219169]. 2001-04-04 Jeff Hobbs * unix/configure: * unix/tcl.m4: extended test of termios vs. termio vs. sgtty to better detect result on Linux and when certain configure redirections are being used. (max) [Patch #402923; Bug #227412, #219194] 2001-04-04 Andreas Kupries * generic/tclTest.c: * tests/io.tests: TIP #10 followup correcting a problem with the original patch because of the lack of 'testthread id' for a non-threaded compilation. 2001-04-04 Kevin Kenny * doc/ByteArrObj.3: * doc/DumpActiveMemory.3: * doc/InitStubs.3: * doc/PkgRequire.3: * doc/StringObj.3: * generic/tcl.decls: * generic/tcl.h: * generic/tclBinary.c: * generic/tclCkalloc.c: * generic/tclDecls.h: * generic/tclListObj.c: * generic/tclObj.c: * generic/tclPkg.c: * generic/tclStringObj.c: * generic/tclStubLib.c: (TIP#27) Changed a number of Tcl API's to accept "CONST char*" in place of simple "char*". (kennykb) [Patch #404026] 2001-04-04 Jeff Hobbs * generic/tclListObj.c (Tcl_SetListObj): set objPtr->length = 0 in empty object case to maintain sanctity of Tcl_Obj bytes/length pairing. (porter) [Patch #405998] 2001-04-03 Andreas Kupries * unix/mkLinks: Added 'Signal.3', 'Tcl_WaitPid'. * doc/DetachPids.3: Added description of 'Tcl_WaitPid' [Bug #219173]. * doc/Signal.3: New man page describing the public API procedures 'Tcl_SignalId' and 'Tcl_SignalMsg' [Bug #219172]. 2001-04-02 Jeff Hobbs * README: * win/README: * win/README.binary: further notes corrections. * win/configure: * win/tcl.m4 (SHLIB_LD): added -incremental:no. [Bug #219381] 2001-04-01 Jeff Hobbs * README: * mac/README: * win/README: * win/README.binary: * unix/README: updated patchlevel information to 8.4a3 and updated links and notes. * generic/tcl.h: * tools/tcl.wse.in: * win/configure.in (VER): * win/configure: * unix/configure: * unix/configure.in (VER): * unix/tcl.spec: updated patchlevel information to 8.4a3 2001-03-30 Jeff Hobbs * generic/tclCkalloc.c (TclFinalizeMemorySubsystem): set curTagPtr to NULL to allow for reuse. * generic/tclEvent.c (Tcl_Finalize): moved the tsdPtr initialization inside the subsystemsInitialized check to prevent it potentially getting called twice during finalization. (wu) [Patch #403532, Bug #219391] * generic/tclThreadTest.c (Tcl_ThreadObjCmd): cast fixes * generic/tclTest.c (TestChannelCmd): added cast to mollify Windows debug build. * win/tclWinSock.c (SocketEventProc): Fixed race condition in readability of socket on Windows. [Patch #410674, Bug #219205 #219333] * win/tcl.m4: added imm32.lib to LIBS_GUI for Tk IME support. * win/Makefile.in (install-libraries): removed extra \s that broke the target. (install-doc): improved install-* targets to use their base build dependency. 2001-03-30 Andreas Kupries * All of the changes below belong to TIP #10 [Tcl I/O Enhancement: Thread-Aware Channels]. See also [Patch #403358] at SF. * generic/tclIO.h (struct ChannelState, line 236f): Extended the structure with a new field of type 'Tcl_ThreadId' to hold the id of the thread currently managing all channels with this state. Note: This structure is shared by all channels in a stack of transformations. * generic/tclIO.c (Tcl_CreateChannel, lines 1058-1065): Modified to store the Id of the current thread in the 'ChannelState' of the new channel. * generic/tclIO.c (Tcl_SpliceChannel, lines 2265-2270): Modified in the same manner as 'Tcl_CreateChannel' as the channel will be managed by the current thread afterward. * generic/tclIO.c (Tcl_GetChannelThread, lines 1478-1503): * generic/tcl.decls (Tcl_GetChannelThread, lines 1504-1506): New API function to retrieve the Id of the managing thread from a channel. Implementation and declaration. * generic/tclTest.c (TestChannelCmd, lines 4520-4532): Added subcommand 'mthread' to query a channel about its managing thread. 2001-03-29 Mo DeJong * tests/interp.test: Print out warning when testinterpdelete command is not defined. Add tests that checks to make sure a child interp inherits the parent's cwd. 2001-03-29 Jeff Hobbs * doc/tcltest.n: corrected incorrect macro usage. * doc/lsort.n: corrected unbalanced nroff macros. * unix/tclUnixPipe.c (TclpCreateTempFile): prevent potential race condition and security leak in tmp filename creation. (max) [Patch #402924] * unix/configure: * unix/tcl.m4: corrected IRIX-5.x config to not use -n32. (english) [Patch #403626] * unix/tclUnixThrd.c (Tcl_ConditionWait): fixed handling of timeout for threads (corrects excessive CPU usage issue for Tk on Unix in threaded Tcl environment). (ruppert) [Bug #411603] 2001-03-29 Donal K. Fellows * doc/lsort.n: Added some notes that clarify the behaviour of [lsort] as well as a whole bunch of examples. [Bug #219202] 2001-03-27 Jeff Hobbs * doc/Alloc.3: corrected docs to note that Tcl_Attempt* return char *'s, not ints. [Bug #411388] * tests/regexp.test (regexp-19.1): * generic/tclCmdMZ.c (Tcl_RegsubObjCmd): fixed handling of nulls in subspec value. 2001-03-26 Don Porter * generic/tclDecls.h (Tcl_InitCustomHashTable): Correction to patch from 2001-01-18; tclDecls.h was not generated using 'make genstubs'. 2001-03-26 Donal K. Fellows * win/tclWinInt.h (tclWinTCharEncoding): Removed as now a static variable in win/tclWin32Dll.c instead. 2001-03-23 Jeff Hobbs * generic/tclVar.c (Tcl_ArrayObjCmd): Corrected retrieval of resultPtr to prevent possible corruption. * generic/tclNamesp.c (Tcl_Import): Correctly freed a DString. (lavana) [Patch #403755] 2001-03-15 Donal K. Fellows * tests/set-old.test (set-old-7.2): Changed error behaviour of [unset] to agree with documentation, so must change test as well. 2001-03-14 Don Porter * library/package.tcl (pkg_mkIndex): Added patch from Vince Darley to make [pkg_mkIndex -verbose] even more verbose. [Bug 219349, Patch 403529] 2001-03-13 Donal K. Fellows * doc/info.n: Improved documentation for [info hostname]. [Bug #403840] * generic/tclVar.c (Tcl_UnsetObjCmd): Made command behave as documented [issue remaining from bug #405769] * generic/tclCmdMZ.c (Tcl_StringObjCmd): A missing {return TCL_OK;} was causing memory corruption. [Bug #408002] * generic/tclExecute.c (TclDeleteExecEnv, GrowEvaluationStack, TclExecuteByteCode): Added some casts to ClientData that are apparently needed on some architectures. 2001-03-12 Donal K. Fellows * tests/string.test: Fixed some test numberings and added a test. [Patch #403229] 2001-03-06 Donal K. Fellows * generic/tclVar.c (Tcl_UnsetObjCmd): Rewrote argument parser to avoid a read off the end of the argument array that could occur when executing something like [unset -nocomplain] was executed. Improved the error message given when too few arguments are given (-nocomplain should obviously be *before* --, not after it) and also modified the test suite to take account of that and the documentation to use the same improvement. [Bug 405769] 2001-03-02 Donal K. Fellows * generic/tclExecute.c (TclExecuteByteCode): Fixed bug that could pass pointers to freed memory to command implementations, which most obviously caused some weird behaviour with [info level], but could have caused problems with user code and command traces too. [Bug 404865, Patch 405436] 2001-02-23 msofer * no changes; fixing up the missing comment in the previous one. Sorry. 2001-02-23 msofer * /cvsroot/tcl/tcl/tests/execute.test: added test for evaluation of an expression in a variable; evals once by compiling, second time using the previous compilation 2001-02-18 Kevin B. Kenny * doc/clock.n: Updated documentation to reflect the addition of compat/strftime.c, including the correct formatting of ISO-8601:1988 fiscal week number (%V). 2001-02-15 Donal K. Fellows * generic/tclCmdMZ.c (Tcl_SplitObjCmd): Improved efficiency of splitting strings into individual characters by adding hash so that only one Tcl_Obj per character is created. Improves performance of splitting of short strings and makes a huge difference to splitting of long strings, such as is done in the mime package in tcllib. [Bug #131523] 2001-01-31 Don Porter * win/makefile.vc (install-libraries): Corrected misdirected install directory for the msgcat 1.2 package. 2001-01-30 Don Porter * generic/tclIO.c (CopyData): Moved code that updates the count of how many bytes are left to copy. Corrects bug that when writing occurs in the background, the copy loop could be escaped without updating the count, causing CopyData() to try to copy more bytes than the toRead value originally passed to TclCopyChannel(), leading to hangs and misreporting of number of bytes copied. [Bug 118203, Patch 103432] 2001-01-18 Andreas Kupries * Everything below belongs together, it fixes bug #123153. * generic/tcl.h (line 342): A bit more explanation about the default value for TCL_PRESERVE_BINARY_COMPATABILITY. * generic/tcl.h (line 1208): Define the macro 'Tcl_InitHashTable' only when TCL_PRESERVE_BINARY_COMPATIBILITY is not set as it kills binary compatibility to 8.3 and earlier versions. This is the main part of the patch/change. * generic/tcl.decls (line 1469): * generic/tclHash.c (Tcl_InitHashTable): * generic/tclHash.c (Tcl_InitHashTableEx): * generic/tclObj.c (Tcl_InitObjHashTable): Changed 'Tcl_InitHashTableEx' to 'Tcl_InitCustomHashTable'. This change is more of an estethical nature, replacing the ubiquitous 'Ex' suffix with a more meaningful name. The introduced binary incompatibility is deemed acceptable as it is between alpha versions. Updated callers. * doc/Hash.3: * unix/mkLinks: Changed 'Tcl_InitHashTableEx' to 'Tcl_InitCustomHashTable'. 2001-01-10 Donal K. Fellows * tests/winPipe.test (winpipe-1.20): * tests/winDde.test (createChildProcess): * tests/pkgMkIndex.test (pkgtest::createIndex): Removed assumption that paths contain no spaces which causes problems with both [eval] and [open |...] due to the well-known differences between lists and strings. Fixes bug #119406 2001-01-04 Don Porter * tests/unixInit.test: * unix/tclUnixInit.c (TclpInitLibraryPath): * win/tclWinInit.c (TclpInitLibraryPath): Several entries in the library path ($tcl_libPath) are determined relative to the absolute path of the executable. When the executable is installed in or near the root directory of the file system, relative pathnames were being incorrectly generated, and in the worst case, memory access violations were crashing the program. [Bug 119416, Patch 102972] ****************************************************************** *** CHANGELOG ENTRIES FOR 2000 IN "ChangeLog.2000" *** *** CHANGELOG ENTRIES FOR 1999 AND EARLIER IN "ChangeLog.1999" *** ****************************************************************** tcl8.4.20/unix/0000755003604700454610000000000012153151143011664 5ustar dgp771divtcl8.4.20/unix/aclocal.m40000644003604700454610000000003012153151142013514 0ustar dgp771divbuiltin(include,tcl.m4) tcl8.4.20/unix/install-sh0000755003604700454610000000431712153151142013674 0ustar dgp771div#!/bin/sh # # install - install a program, script, or datafile # This comes from X11R5; it is not part of GNU. # # $XConsortium: install.sh,v 1.2 89/12/18 14:47:22 jim Exp $ # # This script is compatible with the BSD install script, but was written # from scratch. # # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" instcmd="$mvprog" chmodcmd="" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -S) stripcmd="$stripprog $2" shift shift continue;; *) if [ x"$src" = x ] then src=$1 else dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` fi # Make a temp file name in the proper directory. dstdir=`dirname $dst` dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp # and set any options; do chmod last to preserve setuid bits if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; fi if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; fi if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; fi if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; fi # Now rename the file to the real destination. $doit $rmcmd $dst $doit $mvcmd $dsttmp $dst exit 0 tcl8.4.20/unix/installManPage0000755003604700454610000000304012153151142014505 0ustar dgp771div#!/bin/sh ZIP=: while true; do case $1 in -s | --symlinks ) S="-s ";; -z | --compress ) ZIP=$2; shift ;; -e | --extension ) Z=$2; shift ;; -s | --suffix ) SUFFIX=$2; shift ;; *) break ;; esac shift done if test "$#" != 2; then echo "Usage: installManPages file dir" exit 1 fi MANPAGE=$1 DIR=$2 test -z "$S" && S="$DIR/" # A sed script to parse the alternative names out of a man page. # # /^\\.SH NAME/{ ;# Look for a line, that starts with .SH NAME # s/^.*$// ;# Delete the content of this line from the buffer # n ;# Read next line # s/,//g ;# Remove all commas ... # s/\\\ //g ;# .. and backslash-escaped spaces. # s/ \\\-.*// ;# Delete from \- to the end of line # p ;# print the result # q ;# exit # } # # Backslashes are trippled in the sed script, because it is in # backticks which don't pass backslashes literally. # # Please keep the commented version above updated if you # change anything to the script below. NAMES=`sed -n ' /^\\.SH NAME/{ s/^.*$// n s/,//g s/\\\ //g s/ \\\-.*// p q }' $MANPAGE` SECTION=`echo $MANPAGE | sed 's/.*\(.\)$/\1/'` SRCDIR=`dirname $MANPAGE` FIRST="" for f in $NAMES; do f=$f.$SECTION$SUFFIX if test -z "$FIRST" ; then FIRST=$f rm -f $DIR/$FIRST $DIR/$FIRST.* sed -e "/man\.macros/r $SRCDIR/man.macros" -e "/man\.macros/d" \ $MANPAGE > $DIR/$FIRST chmod 444 $DIR/$FIRST $ZIP $DIR/$FIRST else rm -f $DIR/$f $DIR/$f.* ln $S$FIRST$Z $DIR/$f$Z fi done tcl8.4.20/unix/tclUnixFCmd.c0000644003604700454610000015305111737050675014234 0ustar dgp771div/* * tclUnixFCmd.c * * This file implements the unix specific portion of file manipulation * subcommands of the "file" command. All filename arguments should * already be translated to native format. * * Copyright (c) 1996-1998 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * Portions of this code were derived from NetBSD source code which has * the following copyright notice: * * Copyright (c) 1988, 1993, 1994 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "tclInt.h" #include "tclPort.h" #include #include #ifndef HAVE_ST_BLKSIZE #ifndef NO_FSTATFS #include #endif #endif #ifdef HAVE_FTS #include #endif /* * The following constants specify the type of callback when * TraverseUnixTree() calls the traverseProc() */ #define DOTREE_PRED 1 /* pre-order directory */ #define DOTREE_POSTD 2 /* post-order directory */ #define DOTREE_F 3 /* regular file */ /* * Callbacks for file attributes code. */ static int GetGroupAttribute _ANSI_ARGS_((Tcl_Interp *interp, int objIndex, Tcl_Obj *fileName, Tcl_Obj **attributePtrPtr)); static int GetOwnerAttribute _ANSI_ARGS_((Tcl_Interp *interp, int objIndex, Tcl_Obj *fileName, Tcl_Obj **attributePtrPtr)); static int GetPermissionsAttribute _ANSI_ARGS_(( Tcl_Interp *interp, int objIndex, Tcl_Obj *fileName, Tcl_Obj **attributePtrPtr)); static int SetGroupAttribute _ANSI_ARGS_((Tcl_Interp *interp, int objIndex, Tcl_Obj *fileName, Tcl_Obj *attributePtr)); static int SetOwnerAttribute _ANSI_ARGS_((Tcl_Interp *interp, int objIndex, Tcl_Obj *fileName, Tcl_Obj *attributePtr)); static int SetPermissionsAttribute _ANSI_ARGS_(( Tcl_Interp *interp, int objIndex, Tcl_Obj *fileName, Tcl_Obj *attributePtr)); static int GetModeFromPermString _ANSI_ARGS_(( Tcl_Interp *interp, char *modeStringPtr, mode_t *modePtr)); /* * Prototype for the TraverseUnixTree callback function. */ typedef int (TraversalProc) _ANSI_ARGS_((Tcl_DString *srcPtr, Tcl_DString *dstPtr, CONST Tcl_StatBuf *statBufPtr, int type, Tcl_DString *errorPtr)); /* * Constants and variables necessary for file attributes subcommand. */ enum { UNIX_GROUP_ATTRIBUTE, UNIX_OWNER_ATTRIBUTE, UNIX_PERMISSIONS_ATTRIBUTE }; CONST char *tclpFileAttrStrings[] = { "-group", "-owner", "-permissions", (char *) NULL }; CONST TclFileAttrProcs tclpFileAttrProcs[] = { {GetGroupAttribute, SetGroupAttribute}, {GetOwnerAttribute, SetOwnerAttribute}, {GetPermissionsAttribute, SetPermissionsAttribute} }; /* * This is the maximum number of consecutive readdir/unlink calls that can be * made (with no intervening rewinddir or closedir/opendir) before triggering * a bug that makes readdir return NULL even though some directory entries * have not been processed. The bug afflicts SunOS's readdir when applied to * ufs file systems and Darwin 6.5's (and OSX v.10.3.8's) HFS+. JH found the * Darwin readdir to reset at 147, so 130 is chosen to be conservative. We * can't do a general rewind on failure as NFS can create special files that * recreate themselves when you try and delete them. 8.4.8 added a solution * that was affected by a single such NFS file, this solution should not be * affected by less than THRESHOLD such files. [Bug 1034337] */ #define MAX_READDIR_UNLINK_THRESHOLD 130 /* * Declarations for local procedures defined in this file: */ static int CopyFile _ANSI_ARGS_((CONST char *src, CONST char *dst, CONST Tcl_StatBuf *statBufPtr)); static int CopyFileAtts _ANSI_ARGS_((CONST char *src, CONST char *dst, CONST Tcl_StatBuf *statBufPtr)); static int DoCopyFile _ANSI_ARGS_((CONST char *srcPtr, CONST char *dstPtr, CONST Tcl_StatBuf *statBufPtr)); static int DoCreateDirectory _ANSI_ARGS_((CONST char *pathPtr)); static int DoRemoveDirectory _ANSI_ARGS_((Tcl_DString *pathPtr, int recursive, Tcl_DString *errorPtr)); static int DoRenameFile _ANSI_ARGS_((CONST char *src, CONST char *dst)); static int TraversalCopy _ANSI_ARGS_((Tcl_DString *srcPtr, Tcl_DString *dstPtr, CONST Tcl_StatBuf *statBufPtr, int type, Tcl_DString *errorPtr)); static int TraversalDelete _ANSI_ARGS_((Tcl_DString *srcPtr, Tcl_DString *dstPtr, CONST Tcl_StatBuf *statBufPtr, int type, Tcl_DString *errorPtr)); static int TraverseUnixTree _ANSI_ARGS_(( TraversalProc *traversalProc, Tcl_DString *sourcePtr, Tcl_DString *destPtr, Tcl_DString *errorPtr, int doRewind)); #ifdef PURIFY /* * realpath and purify don't mix happily. It has been noted that realpath * should not be used with purify because of bogus warnings, but just * memset'ing the resolved path will squelch those. This assumes we are * passing the standard MAXPATHLEN size resolved arg. */ static char * Realpath _ANSI_ARGS_((CONST char *path, char *resolved)); char * Realpath(path, resolved) CONST char *path; char *resolved; { memset(resolved, 0, MAXPATHLEN); return realpath(path, resolved); } #else #define Realpath realpath #endif #ifndef NO_REALPATH #if defined(__APPLE__) && defined(TCL_THREADS) && \ defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \ MAC_OS_X_VERSION_MIN_REQUIRED < 1030 /* * prior to Darwin 7, realpath is not threadsafe, c.f. bug 711232; * if we might potentially be running on pre-10.3 OSX, * check Darwin release at runtime before using realpath. */ extern long tclMacOSXDarwinRelease; #define haveRealpath (tclMacOSXDarwinRelease >= 7) #else #define haveRealpath 1 #endif #endif /* NO_REALPATH */ #ifdef HAVE_FTS #ifdef HAVE_STRUCT_STAT64 /* fts doesn't do stat64 */ #define noFtsStat 1 #elif defined(__APPLE__) && defined(__LP64__) && \ defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \ MAC_OS_X_VERSION_MIN_REQUIRED < 1050 /* * prior to Darwin 9, 64bit fts_open() without FTS_NOSTAT may crash (due to a * 64bit-unsafe ALIGN macro); if we could be running on pre-10.5 OSX, check * Darwin release at runtime and do a separate stat() if necessary. */ extern long tclMacOSXDarwinRelease; #define noFtsStat (tclMacOSXDarwinRelease < 9) #else #define noFtsStat 0 #endif #endif /* HAVE_FTS */ /* *--------------------------------------------------------------------------- * * TclpObjRenameFile, DoRenameFile -- * * Changes the name of an existing file or directory, from src to dst. * If src and dst refer to the same file or directory, does nothing * and returns success. Otherwise if dst already exists, it will be * deleted and replaced by src subject to the following conditions: * If src is a directory, dst may be an empty directory. * If src is a file, dst may be a file. * In any other situation where dst already exists, the rename will * fail. * * Results: * If the directory was successfully created, returns TCL_OK. * Otherwise the return value is TCL_ERROR and errno is set to * indicate the error. Some possible values for errno are: * * EACCES: src or dst parent directory can't be read and/or written. * EEXIST: dst is a non-empty directory. * EINVAL: src is a root directory or dst is a subdirectory of src. * EISDIR: dst is a directory, but src is not. * ENOENT: src doesn't exist, or src or dst is "". * ENOTDIR: src is a directory, but dst is not. * EXDEV: src and dst are on different filesystems. * * Side effects: * The implementation of rename may allow cross-filesystem renames, * but the caller should be prepared to emulate it with copy and * delete if errno is EXDEV. * *--------------------------------------------------------------------------- */ int TclpObjRenameFile(srcPathPtr, destPathPtr) Tcl_Obj *srcPathPtr; Tcl_Obj *destPathPtr; { return DoRenameFile(Tcl_FSGetNativePath(srcPathPtr), Tcl_FSGetNativePath(destPathPtr)); } static int DoRenameFile(src, dst) CONST char *src; /* Pathname of file or dir to be renamed * (native). */ CONST char *dst; /* New pathname of file or directory * (native). */ { if (rename(src, dst) == 0) { /* INTL: Native. */ return TCL_OK; } if (errno == ENOTEMPTY) { errno = EEXIST; } /* * IRIX returns EIO when you attept to move a directory into * itself. We just map EIO to EINVAL get the right message on SGI. * Most platforms don't return EIO except in really strange cases. */ if (errno == EIO) { errno = EINVAL; } #ifndef NO_REALPATH /* * SunOS 4.1.4 reports overwriting a non-empty directory with a * directory as EINVAL instead of EEXIST (first rule out the correct * EINVAL result code for moving a directory into itself). Must be * conditionally compiled because realpath() not defined on all systems. */ if (errno == EINVAL && haveRealpath) { char srcPath[MAXPATHLEN], dstPath[MAXPATHLEN]; DIR *dirPtr; Tcl_DirEntry *dirEntPtr; if ((Realpath((char *) src, srcPath) != NULL) /* INTL: Native. */ && (Realpath((char *) dst, dstPath) != NULL) /* INTL: Native. */ && (strncmp(srcPath, dstPath, strlen(srcPath)) != 0)) { dirPtr = opendir(dst); /* INTL: Native. */ if (dirPtr != NULL) { while (1) { dirEntPtr = TclOSreaddir(dirPtr); /* INTL: Native. */ if (dirEntPtr == NULL) { break; } if ((strcmp(dirEntPtr->d_name, ".") != 0) && (strcmp(dirEntPtr->d_name, "..") != 0)) { errno = EEXIST; closedir(dirPtr); return TCL_ERROR; } } closedir(dirPtr); } } errno = EINVAL; } #endif /* !NO_REALPATH */ if (strcmp(src, "/") == 0) { /* * Alpha reports renaming / as EBUSY and Linux reports it as EACCES, * instead of EINVAL. */ errno = EINVAL; } /* * DEC Alpha OSF1 V3.0 returns EACCES when attempting to move a * file across filesystems and the parent directory of that file is * not writable. Most other systems return EXDEV. Does nothing to * correct this behavior. */ return TCL_ERROR; } /* *--------------------------------------------------------------------------- * * TclpObjCopyFile, DoCopyFile -- * * Copy a single file (not a directory). If dst already exists and * is not a directory, it is removed. * * Results: * If the file was successfully copied, returns TCL_OK. Otherwise * the return value is TCL_ERROR and errno is set to indicate the * error. Some possible values for errno are: * * EACCES: src or dst parent directory can't be read and/or written. * EISDIR: src or dst is a directory. * ENOENT: src doesn't exist. src or dst is "". * * Side effects: * This procedure will also copy symbolic links, block, and * character devices, and fifos. For symbolic links, the links * themselves will be copied and not what they point to. For the * other special file types, the directory entry will be copied and * not the contents of the device that it refers to. * *--------------------------------------------------------------------------- */ int TclpObjCopyFile(srcPathPtr, destPathPtr) Tcl_Obj *srcPathPtr; Tcl_Obj *destPathPtr; { CONST char *src = Tcl_FSGetNativePath(srcPathPtr); Tcl_StatBuf srcStatBuf; if (TclOSlstat(src, &srcStatBuf) != 0) { /* INTL: Native. */ return TCL_ERROR; } return DoCopyFile(src, Tcl_FSGetNativePath(destPathPtr), &srcStatBuf); } static int DoCopyFile(src, dst, statBufPtr) CONST char *src; /* Pathname of file to be copied (native). */ CONST char *dst; /* Pathname of file to copy to (native). */ CONST Tcl_StatBuf *statBufPtr; /* Used to determine filetype. */ { Tcl_StatBuf dstStatBuf; if (S_ISDIR(statBufPtr->st_mode)) { errno = EISDIR; return TCL_ERROR; } /* * symlink, and some of the other calls will fail if the target * exists, so we remove it first */ if (TclOSlstat(dst, &dstStatBuf) == 0) { /* INTL: Native. */ if (S_ISDIR(dstStatBuf.st_mode)) { errno = EISDIR; return TCL_ERROR; } } if (unlink(dst) != 0) { /* INTL: Native. */ if (errno != ENOENT) { return TCL_ERROR; } } switch ((int) (statBufPtr->st_mode & S_IFMT)) { #ifndef DJGPP case S_IFLNK: { char link[MAXPATHLEN]; int length; length = readlink(src, link, sizeof(link)); /* INTL: Native. */ if (length == -1) { return TCL_ERROR; } link[length] = '\0'; if (symlink(link, dst) < 0) { /* INTL: Native. */ return TCL_ERROR; } #ifdef HAVE_COPYFILE #ifdef WEAK_IMPORT_COPYFILE if (copyfile != NULL) #endif copyfile(src, dst, NULL, COPYFILE_XATTR|COPYFILE_NOFOLLOW_SRC); #endif break; } #endif case S_IFBLK: case S_IFCHR: { if (mknod(dst, statBufPtr->st_mode, /* INTL: Native. */ statBufPtr->st_rdev) < 0) { return TCL_ERROR; } return CopyFileAtts(src, dst, statBufPtr); } case S_IFIFO: { if (mkfifo(dst, statBufPtr->st_mode) < 0) { /* INTL: Native. */ return TCL_ERROR; } return CopyFileAtts(src, dst, statBufPtr); } default: { return CopyFile(src, dst, statBufPtr); } } return TCL_OK; } /* *---------------------------------------------------------------------- * * CopyFile - * * Helper function for TclpCopyFile. Copies one regular file, * using read() and write(). * * Results: * A standard Tcl result. * * Side effects: * A file is copied. Dst will be overwritten if it exists. * *---------------------------------------------------------------------- */ static int CopyFile(src, dst, statBufPtr) CONST char *src; /* Pathname of file to copy (native). */ CONST char *dst; /* Pathname of file to create/overwrite * (native). */ CONST Tcl_StatBuf *statBufPtr; /* Used to determine mode and blocksize. */ { int srcFd; int dstFd; unsigned blockSize; /* Optimal I/O blocksize for filesystem */ char *buffer; /* Data buffer for copy */ size_t nread; if ((srcFd = TclOSopen(src, O_RDONLY, 0)) < 0) { /* INTL: Native. */ return TCL_ERROR; } dstFd = TclOSopen(dst, O_CREAT|O_TRUNC|O_WRONLY, /* INTL: Native. */ statBufPtr->st_mode); if (dstFd < 0) { close(srcFd); return TCL_ERROR; } #ifdef HAVE_ST_BLKSIZE blockSize = statBufPtr->st_blksize; #else #ifndef NO_FSTATFS { struct statfs fs; if (fstatfs(srcFd, &fs, sizeof(fs), 0) == 0) { blockSize = fs.f_bsize; } else { blockSize = 4096; } } #else blockSize = 4096; #endif #endif /* [SF Tcl Bug 1586470] Even if we HAVE_ST_BLKSIZE, there are * filesystems which report a bogus value for the blocksize. An * example is the Andrew Filesystem (afs), reporting a blocksize * of 0. When detecting such a situation we now simply fall back * to a hardwired default size. */ if (blockSize <= 0) { blockSize = 4096; } buffer = ckalloc(blockSize); while (1) { nread = read(srcFd, buffer, blockSize); if ((nread == (size_t) -1) || (nread == 0)) { break; } if (write(dstFd, buffer, nread) != (int)nread) { nread = (size_t) -1; break; } } ckfree(buffer); close(srcFd); if ((close(dstFd) != 0) || (nread == (size_t) -1)) { unlink(dst); /* INTL: Native. */ return TCL_ERROR; } if (CopyFileAtts(src, dst, statBufPtr) == TCL_ERROR) { /* * The copy succeeded, but setting the permissions failed, so be in * a consistent state, we remove the file that was created by the * copy. */ unlink(dst); /* INTL: Native. */ return TCL_ERROR; } return TCL_OK; } /* *--------------------------------------------------------------------------- * * TclpObjDeleteFile, TclpDeleteFile -- * * Removes a single file (not a directory). * * Results: * If the file was successfully deleted, returns TCL_OK. Otherwise * the return value is TCL_ERROR and errno is set to indicate the * error. Some possible values for errno are: * * EACCES: a parent directory can't be read and/or written. * EISDIR: path is a directory. * ENOENT: path doesn't exist or is "". * * Side effects: * The file is deleted, even if it is read-only. * *--------------------------------------------------------------------------- */ int TclpObjDeleteFile(pathPtr) Tcl_Obj *pathPtr; { return TclpDeleteFile(Tcl_FSGetNativePath(pathPtr)); } int TclpDeleteFile(path) CONST char *path; /* Pathname of file to be removed (native). */ { if (unlink(path) != 0) { /* INTL: Native. */ return TCL_ERROR; } return TCL_OK; } /* *--------------------------------------------------------------------------- * * TclpCreateDirectory, DoCreateDirectory -- * * Creates the specified directory. All parent directories of the * specified directory must already exist. The directory is * automatically created with permissions so that user can access * the new directory and create new files or subdirectories in it. * * Results: * If the directory was successfully created, returns TCL_OK. * Otherwise the return value is TCL_ERROR and errno is set to * indicate the error. Some possible values for errno are: * * EACCES: a parent directory can't be read and/or written. * EEXIST: path already exists. * ENOENT: a parent directory doesn't exist. * * Side effects: * A directory is created with the current umask, except that * permission for u+rwx will always be added. * *--------------------------------------------------------------------------- */ int TclpObjCreateDirectory(pathPtr) Tcl_Obj *pathPtr; { return DoCreateDirectory(Tcl_FSGetNativePath(pathPtr)); } static int DoCreateDirectory(path) CONST char *path; /* Pathname of directory to create (native). */ { mode_t mode; mode = umask(0); umask(mode); /* * umask return value is actually the inverse of the permissions. */ mode = (0777 & ~mode) | S_IRUSR | S_IWUSR | S_IXUSR; if (mkdir(path, mode) != 0) { /* INTL: Native. */ return TCL_ERROR; } return TCL_OK; } /* *--------------------------------------------------------------------------- * * TclpObjCopyDirectory -- * * Recursively copies a directory. The target directory dst must * not already exist. Note that this function does not merge two * directory hierarchies, even if the target directory is an an * empty directory. * * Results: * If the directory was successfully copied, returns TCL_OK. * Otherwise the return value is TCL_ERROR, errno is set to indicate * the error, and the pathname of the file that caused the error * is stored in errorPtr. See TclpObjCreateDirectory and * TclpObjCopyFile for a description of possible values for errno. * * Side effects: * An exact copy of the directory hierarchy src will be created * with the name dst. If an error occurs, the error will * be returned immediately, and remaining files will not be * processed. * *--------------------------------------------------------------------------- */ int TclpObjCopyDirectory(srcPathPtr, destPathPtr, errorPtr) Tcl_Obj *srcPathPtr; Tcl_Obj *destPathPtr; Tcl_Obj **errorPtr; { Tcl_DString ds; Tcl_DString srcString, dstString; int ret; Tcl_Obj *transPtr; transPtr = Tcl_FSGetTranslatedPath(NULL,srcPathPtr); Tcl_UtfToExternalDString(NULL, (transPtr != NULL ? Tcl_GetString(transPtr) : NULL), -1, &srcString); if (transPtr != NULL) { Tcl_DecrRefCount(transPtr); } transPtr = Tcl_FSGetTranslatedPath(NULL,destPathPtr); Tcl_UtfToExternalDString(NULL, (transPtr != NULL ? Tcl_GetString(transPtr) : NULL), -1, &dstString); if (transPtr != NULL) { Tcl_DecrRefCount(transPtr); } ret = TraverseUnixTree(TraversalCopy, &srcString, &dstString, &ds, 0); Tcl_DStringFree(&srcString); Tcl_DStringFree(&dstString); if (ret != TCL_OK) { *errorPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds), -1); Tcl_DStringFree(&ds); Tcl_IncrRefCount(*errorPtr); } return ret; } /* *--------------------------------------------------------------------------- * * TclpRemoveDirectory, DoRemoveDirectory -- * * Removes directory (and its contents, if the recursive flag is set). * * Results: * If the directory was successfully removed, returns TCL_OK. * Otherwise the return value is TCL_ERROR, errno is set to indicate * the error, and the pathname of the file that caused the error * is stored in errorPtr. Some possible values for errno are: * * EACCES: path directory can't be read and/or written. * EEXIST: path is a non-empty directory. * EINVAL: path is a root directory. * ENOENT: path doesn't exist or is "". * ENOTDIR: path is not a directory. * * Side effects: * Directory removed. If an error occurs, the error will be returned * immediately, and remaining files will not be deleted. * *--------------------------------------------------------------------------- */ int TclpObjRemoveDirectory(pathPtr, recursive, errorPtr) Tcl_Obj *pathPtr; int recursive; Tcl_Obj **errorPtr; { Tcl_DString ds; Tcl_DString pathString; int ret; Tcl_Obj *transPtr = Tcl_FSGetTranslatedPath(NULL, pathPtr); Tcl_UtfToExternalDString(NULL, (transPtr != NULL ? Tcl_GetString(transPtr) : NULL), -1, &pathString); if (transPtr != NULL) { Tcl_DecrRefCount(transPtr); } ret = DoRemoveDirectory(&pathString, recursive, &ds); Tcl_DStringFree(&pathString); if (ret != TCL_OK) { *errorPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds), -1); Tcl_DStringFree(&ds); Tcl_IncrRefCount(*errorPtr); } return ret; } static int DoRemoveDirectory(pathPtr, recursive, errorPtr) Tcl_DString *pathPtr; /* Pathname of directory to be removed * (native). */ int recursive; /* If non-zero, removes directories that * are nonempty. Otherwise, will only remove * empty directories. */ Tcl_DString *errorPtr; /* If non-NULL, uninitialized or free * DString filled with UTF-8 name of file * causing error. */ { CONST char *path; mode_t oldPerm = 0; int result; path = Tcl_DStringValue(pathPtr); if (recursive != 0) { /* We should try to change permissions so this can be deleted */ Tcl_StatBuf statBuf; int newPerm; if (TclOSstat(path, &statBuf) == 0) { oldPerm = (mode_t) (statBuf.st_mode & 0x00007FFF); } newPerm = oldPerm | (64+128+256); chmod(path, (mode_t) newPerm); } if (rmdir(path) == 0) { /* INTL: Native. */ return TCL_OK; } if (errno == ENOTEMPTY) { errno = EEXIST; } result = TCL_OK; if ((errno != EEXIST) || (recursive == 0)) { if (errorPtr != NULL) { Tcl_ExternalToUtfDString(NULL, path, -1, errorPtr); } result = TCL_ERROR; } /* * The directory is nonempty, but the recursive flag has been * specified, so we recursively remove all the files in the directory. */ if (result == TCL_OK) { result = TraverseUnixTree(TraversalDelete, pathPtr, NULL, errorPtr, 1); } if ((result != TCL_OK) && (recursive != 0)) { /* Try to restore permissions */ chmod(path, oldPerm); } return result; } /* *--------------------------------------------------------------------------- * * TraverseUnixTree -- * * Traverse directory tree specified by sourcePtr, calling the function * traverseProc for each file and directory encountered. If destPtr * is non-null, each of name in the sourcePtr directory is appended to * the directory specified by destPtr and passed as the second argument * to traverseProc() . * * Results: * Standard Tcl result. * * Side effects: * None caused by TraverseUnixTree, however the user specified * traverseProc() may change state. If an error occurs, the error will * be returned immediately, and remaining files will not be processed. * *--------------------------------------------------------------------------- */ static int TraverseUnixTree(traverseProc, sourcePtr, targetPtr, errorPtr, doRewind) TraversalProc *traverseProc;/* Function to call for every file and * directory in source hierarchy. */ Tcl_DString *sourcePtr; /* Pathname of source directory to be * traversed (native). */ Tcl_DString *targetPtr; /* Pathname of directory to traverse in * parallel with source directory (native). */ Tcl_DString *errorPtr; /* If non-NULL, uninitialized or free * DString filled with UTF-8 name of file * causing error. */ int doRewind; /* Flag indicating that to ensure complete * traversal of source hierarchy, the readdir * loop should be rewound whenever * traverseProc has returned TCL_OK; this is * required when traverseProc modifies the * source hierarchy, e.g. by deleting files. */ { Tcl_StatBuf statBuf; CONST char *source, *errfile; int result, sourceLen; int targetLen; #ifndef HAVE_FTS int numProcessed = 0; Tcl_DirEntry *dirEntPtr; DIR *dirPtr; #else CONST char *paths[2] = {NULL, NULL}; FTS *fts = NULL; FTSENT *ent; #endif errfile = NULL; result = TCL_OK; targetLen = 0; /* lint. */ source = Tcl_DStringValue(sourcePtr); if (TclOSlstat(source, &statBuf) != 0) { /* INTL: Native. */ errfile = source; goto end; } if (!S_ISDIR(statBuf.st_mode)) { /* * Process the regular file */ return (*traverseProc)(sourcePtr, targetPtr, &statBuf, DOTREE_F, errorPtr); } #ifndef HAVE_FTS dirPtr = opendir(source); /* INTL: Native. */ if (dirPtr == NULL) { /* * Can't read directory */ errfile = source; goto end; } result = (*traverseProc)(sourcePtr, targetPtr, &statBuf, DOTREE_PRED, errorPtr); if (result != TCL_OK) { closedir(dirPtr); return result; } Tcl_DStringAppend(sourcePtr, "/", 1); sourceLen = Tcl_DStringLength(sourcePtr); if (targetPtr != NULL) { Tcl_DStringAppend(targetPtr, "/", 1); targetLen = Tcl_DStringLength(targetPtr); } while ((dirEntPtr = TclOSreaddir(dirPtr)) != NULL) { /* INTL: Native. */ if ((dirEntPtr->d_name[0] == '.') && ((dirEntPtr->d_name[1] == '\0') || (strcmp(dirEntPtr->d_name, "..") == 0))) { continue; } /* * Append name after slash, and recurse on the file. */ Tcl_DStringAppend(sourcePtr, dirEntPtr->d_name, -1); if (targetPtr != NULL) { Tcl_DStringAppend(targetPtr, dirEntPtr->d_name, -1); } result = TraverseUnixTree(traverseProc, sourcePtr, targetPtr, errorPtr, doRewind); if (result != TCL_OK) { break; } else { numProcessed++; } /* * Remove name after slash. */ Tcl_DStringSetLength(sourcePtr, sourceLen); if (targetPtr != NULL) { Tcl_DStringSetLength(targetPtr, targetLen); } if (doRewind && (numProcessed > MAX_READDIR_UNLINK_THRESHOLD)) { /* * Call rewinddir if we've called unlink or rmdir so many times * (since the opendir or the previous rewinddir), to avoid * a NULL-return that may a symptom of a buggy readdir. */ rewinddir(dirPtr); numProcessed = 0; } } closedir(dirPtr); /* * Strip off the trailing slash we added */ Tcl_DStringSetLength(sourcePtr, sourceLen - 1); if (targetPtr != NULL) { Tcl_DStringSetLength(targetPtr, targetLen - 1); } if (result == TCL_OK) { /* * Call traverseProc() on a directory after visiting all the * files in that directory. */ result = (*traverseProc)(sourcePtr, targetPtr, &statBuf, DOTREE_POSTD, errorPtr); } #else /* HAVE_FTS */ paths[0] = source; fts = fts_open((char**)paths, FTS_PHYSICAL | FTS_NOCHDIR | (noFtsStat || doRewind ? FTS_NOSTAT : 0), NULL); if (fts == NULL) { errfile = source; goto end; } sourceLen = Tcl_DStringLength(sourcePtr); if (targetPtr != NULL) { targetLen = Tcl_DStringLength(targetPtr); } while ((ent = fts_read(fts)) != NULL) { unsigned short info = ent->fts_info; char * path = ent->fts_path + sourceLen; unsigned short pathlen = ent->fts_pathlen - sourceLen; int type; Tcl_StatBuf *statBufPtr = NULL; if (info == FTS_DNR || info == FTS_ERR || info == FTS_NS) { errfile = ent->fts_path; break; } Tcl_DStringAppend(sourcePtr, path, pathlen); if (targetPtr != NULL) { Tcl_DStringAppend(targetPtr, path, pathlen); } switch (info) { case FTS_D: type = DOTREE_PRED; break; case FTS_DP: type = DOTREE_POSTD; break; default: type = DOTREE_F; break; } if (!doRewind) { /* no need to stat for delete */ if (noFtsStat) { statBufPtr = &statBuf; if (TclOSlstat(ent->fts_path, statBufPtr) != 0) { errfile = ent->fts_path; break; } } else { statBufPtr = ent->fts_statp; } } result = (*traverseProc)(sourcePtr, targetPtr, statBufPtr, type, errorPtr); if (result != TCL_OK) { break; } Tcl_DStringSetLength(sourcePtr, sourceLen); if (targetPtr != NULL) { Tcl_DStringSetLength(targetPtr, targetLen); } } #endif /* HAVE_FTS */ end: if (errfile != NULL) { if (errorPtr != NULL) { Tcl_ExternalToUtfDString(NULL, errfile, -1, errorPtr); } result = TCL_ERROR; } #ifdef HAVE_FTS if (fts != NULL) { fts_close(fts); } #endif /* HAVE_FTS */ return result; } /* *---------------------------------------------------------------------- * * TraversalCopy * * Called from TraverseUnixTree in order to execute a recursive copy * of a directory. * * Results: * Standard Tcl result. * * Side effects: * The file or directory src may be copied to dst, depending on * the value of type. * *---------------------------------------------------------------------- */ static int TraversalCopy(srcPtr, dstPtr, statBufPtr, type, errorPtr) Tcl_DString *srcPtr; /* Source pathname to copy (native). */ Tcl_DString *dstPtr; /* Destination pathname of copy (native). */ CONST Tcl_StatBuf *statBufPtr; /* Stat info for file specified by srcPtr. */ int type; /* Reason for call - see TraverseUnixTree(). */ Tcl_DString *errorPtr; /* If non-NULL, uninitialized or free * DString filled with UTF-8 name of file * causing error. */ { switch (type) { case DOTREE_F: if (DoCopyFile(Tcl_DStringValue(srcPtr), Tcl_DStringValue(dstPtr), statBufPtr) == TCL_OK) { return TCL_OK; } break; case DOTREE_PRED: if (DoCreateDirectory(Tcl_DStringValue(dstPtr)) == TCL_OK) { return TCL_OK; } break; case DOTREE_POSTD: if (CopyFileAtts(Tcl_DStringValue(srcPtr), Tcl_DStringValue(dstPtr), statBufPtr) == TCL_OK) { return TCL_OK; } break; } /* * There shouldn't be a problem with src, because we already checked it * to get here. */ if (errorPtr != NULL) { Tcl_ExternalToUtfDString(NULL, Tcl_DStringValue(dstPtr), Tcl_DStringLength(dstPtr), errorPtr); } return TCL_ERROR; } /* *--------------------------------------------------------------------------- * * TraversalDelete -- * * Called by procedure TraverseUnixTree for every file and directory * that it encounters in a directory hierarchy. This procedure unlinks * files, and removes directories after all the containing files * have been processed. * * Results: * Standard Tcl result. * * Side effects: * Files or directory specified by src will be deleted. * *---------------------------------------------------------------------- */ static int TraversalDelete(srcPtr, ignore, statBufPtr, type, errorPtr) Tcl_DString *srcPtr; /* Source pathname (native). */ Tcl_DString *ignore; /* Destination pathname (not used). */ CONST Tcl_StatBuf *statBufPtr; /* Stat info for file specified by srcPtr. */ int type; /* Reason for call - see TraverseUnixTree(). */ Tcl_DString *errorPtr; /* If non-NULL, uninitialized or free * DString filled with UTF-8 name of file * causing error. */ { switch (type) { case DOTREE_F: { if (TclpDeleteFile(Tcl_DStringValue(srcPtr)) == 0) { return TCL_OK; } break; } case DOTREE_PRED: { return TCL_OK; } case DOTREE_POSTD: { if (DoRemoveDirectory(srcPtr, 0, NULL) == 0) { return TCL_OK; } break; } } if (errorPtr != NULL) { Tcl_ExternalToUtfDString(NULL, Tcl_DStringValue(srcPtr), Tcl_DStringLength(srcPtr), errorPtr); } return TCL_ERROR; } /* *--------------------------------------------------------------------------- * * CopyFileAtts -- * * Copy the file attributes such as owner, group, permissions, * and modification date from one file to another. * * Results: * Standard Tcl result. * * Side effects: * user id, group id, permission bits, last modification time, and * last access time are updated in the new file to reflect the * old file. * *--------------------------------------------------------------------------- */ static int CopyFileAtts(src, dst, statBufPtr) CONST char *src; /* Path name of source file (native). */ CONST char *dst; /* Path name of target file (native). */ CONST Tcl_StatBuf *statBufPtr; /* Stat info for source file */ { struct utimbuf tval; mode_t newMode; newMode = statBufPtr->st_mode & (S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO); /* * Note that if you copy a setuid file that is owned by someone * else, and you are not root, then the copy will be setuid to you. * The most correct implementation would probably be to have the * copy not setuid to anyone if the original file was owned by * someone else, but this corner case isn't currently handled. * It would require another lstat(), or getuid(). */ if (chmod(dst, newMode)) { /* INTL: Native. */ newMode &= ~(S_ISUID | S_ISGID); if (chmod(dst, newMode)) { /* INTL: Native. */ return TCL_ERROR; } } tval.actime = statBufPtr->st_atime; tval.modtime = statBufPtr->st_mtime; if (utime(dst, &tval)) { /* INTL: Native. */ return TCL_ERROR; } #ifdef HAVE_COPYFILE #ifdef WEAK_IMPORT_COPYFILE if (copyfile != NULL) #endif copyfile(src, dst, NULL, COPYFILE_XATTR|COPYFILE_ACL); #endif return TCL_OK; } /* *---------------------------------------------------------------------- * * GetGroupAttribute * * Gets the group attribute of a file. * * Results: * Standard TCL result. Returns a new Tcl_Obj in attributePtrPtr * if there is no error. * * Side effects: * A new object is allocated. * *---------------------------------------------------------------------- */ static int GetGroupAttribute(interp, objIndex, fileName, attributePtrPtr) Tcl_Interp *interp; /* The interp we are using for errors. */ int objIndex; /* The index of the attribute. */ Tcl_Obj *fileName; /* The name of the file (UTF-8). */ Tcl_Obj **attributePtrPtr; /* A pointer to return the object with. */ { Tcl_StatBuf statBuf; struct group *groupPtr; int result; result = TclpObjStat(fileName, &statBuf); if (result != 0) { Tcl_AppendResult(interp, "could not read \"", Tcl_GetString(fileName), "\": ", Tcl_PosixError(interp), (char *) NULL); return TCL_ERROR; } groupPtr = TclpGetGrGid(statBuf.st_gid); if (result == -1 || groupPtr == NULL) { *attributePtrPtr = Tcl_NewIntObj((int) statBuf.st_gid); } else { Tcl_DString ds; CONST char *utf; utf = Tcl_ExternalToUtfDString(NULL, groupPtr->gr_name, -1, &ds); *attributePtrPtr = Tcl_NewStringObj(utf, -1); Tcl_DStringFree(&ds); } endgrent(); return TCL_OK; } /* *---------------------------------------------------------------------- * * GetOwnerAttribute * * Gets the owner attribute of a file. * * Results: * Standard TCL result. Returns a new Tcl_Obj in attributePtrPtr * if there is no error. * * Side effects: * A new object is allocated. * *---------------------------------------------------------------------- */ static int GetOwnerAttribute(interp, objIndex, fileName, attributePtrPtr) Tcl_Interp *interp; /* The interp we are using for errors. */ int objIndex; /* The index of the attribute. */ Tcl_Obj *fileName; /* The name of the file (UTF-8). */ Tcl_Obj **attributePtrPtr; /* A pointer to return the object with. */ { Tcl_StatBuf statBuf; struct passwd *pwPtr; int result; result = TclpObjStat(fileName, &statBuf); if (result != 0) { Tcl_AppendResult(interp, "could not read \"", Tcl_GetString(fileName), "\": ", Tcl_PosixError(interp), (char *) NULL); return TCL_ERROR; } pwPtr = TclpGetPwUid(statBuf.st_uid); if (result == -1 || pwPtr == NULL) { *attributePtrPtr = Tcl_NewIntObj((int) statBuf.st_uid); } else { Tcl_DString ds; CONST char *utf; utf = Tcl_ExternalToUtfDString(NULL, pwPtr->pw_name, -1, &ds); *attributePtrPtr = Tcl_NewStringObj(utf, Tcl_DStringLength(&ds)); Tcl_DStringFree(&ds); } endpwent(); return TCL_OK; } /* *---------------------------------------------------------------------- * * GetPermissionsAttribute * * Gets the group attribute of a file. * * Results: * Standard TCL result. Returns a new Tcl_Obj in attributePtrPtr * if there is no error. The object will have ref count 0. * * Side effects: * A new object is allocated. * *---------------------------------------------------------------------- */ static int GetPermissionsAttribute(interp, objIndex, fileName, attributePtrPtr) Tcl_Interp *interp; /* The interp we are using for errors. */ int objIndex; /* The index of the attribute. */ Tcl_Obj *fileName; /* The name of the file (UTF-8). */ Tcl_Obj **attributePtrPtr; /* A pointer to return the object with. */ { Tcl_StatBuf statBuf; char returnString[7]; int result; result = TclpObjStat(fileName, &statBuf); if (result != 0) { Tcl_AppendResult(interp, "could not read \"", Tcl_GetString(fileName), "\": ", Tcl_PosixError(interp), (char *) NULL); return TCL_ERROR; } sprintf(returnString, "%0#5lo", (long) (statBuf.st_mode & 0x00007FFF)); *attributePtrPtr = Tcl_NewStringObj(returnString, -1); return TCL_OK; } /* *--------------------------------------------------------------------------- * * SetGroupAttribute -- * * Sets the group of the file to the specified group. * * Results: * Standard TCL result. * * Side effects: * As above. * *--------------------------------------------------------------------------- */ static int SetGroupAttribute(interp, objIndex, fileName, attributePtr) Tcl_Interp *interp; /* The interp for error reporting. */ int objIndex; /* The index of the attribute. */ Tcl_Obj *fileName; /* The name of the file (UTF-8). */ Tcl_Obj *attributePtr; /* New group for file. */ { long gid; int result; CONST char *native; if (Tcl_GetLongFromObj(NULL, attributePtr, &gid) != TCL_OK) { Tcl_DString ds; struct group *groupPtr; CONST char *string; int length; string = Tcl_GetStringFromObj(attributePtr, &length); native = Tcl_UtfToExternalDString(NULL, string, length, &ds); groupPtr = TclpGetGrNam(native); /* INTL: Native. */ Tcl_DStringFree(&ds); if (groupPtr == NULL) { endgrent(); Tcl_AppendResult(interp, "could not set group for file \"", Tcl_GetString(fileName), "\": group \"", string, "\" does not exist", (char *) NULL); return TCL_ERROR; } gid = groupPtr->gr_gid; } native = Tcl_FSGetNativePath(fileName); result = chown(native, (uid_t) -1, (gid_t) gid); /* INTL: Native. */ endgrent(); if (result != 0) { Tcl_AppendResult(interp, "could not set group for file \"", Tcl_GetString(fileName), "\": ", Tcl_PosixError(interp), (char *) NULL); return TCL_ERROR; } return TCL_OK; } /* *--------------------------------------------------------------------------- * * SetOwnerAttribute -- * * Sets the owner of the file to the specified owner. * * Results: * Standard TCL result. * * Side effects: * As above. * *--------------------------------------------------------------------------- */ static int SetOwnerAttribute(interp, objIndex, fileName, attributePtr) Tcl_Interp *interp; /* The interp for error reporting. */ int objIndex; /* The index of the attribute. */ Tcl_Obj *fileName; /* The name of the file (UTF-8). */ Tcl_Obj *attributePtr; /* New owner for file. */ { long uid; int result; CONST char *native; if (Tcl_GetLongFromObj(NULL, attributePtr, &uid) != TCL_OK) { Tcl_DString ds; struct passwd *pwPtr; CONST char *string; int length; string = Tcl_GetStringFromObj(attributePtr, &length); native = Tcl_UtfToExternalDString(NULL, string, length, &ds); pwPtr = TclpGetPwNam(native); /* INTL: Native. */ Tcl_DStringFree(&ds); if (pwPtr == NULL) { endpwent(); Tcl_AppendResult(interp, "could not set owner for file \"", Tcl_GetString(fileName), "\": user \"", string, "\" does not exist", (char *) NULL); return TCL_ERROR; } uid = pwPtr->pw_uid; } native = Tcl_FSGetNativePath(fileName); result = chown(native, (uid_t) uid, (gid_t) -1); /* INTL: Native. */ endpwent(); if (result != 0) { Tcl_AppendResult(interp, "could not set owner for file \"", Tcl_GetString(fileName), "\": ", Tcl_PosixError(interp), (char *) NULL); return TCL_ERROR; } return TCL_OK; } /* *--------------------------------------------------------------------------- * * SetPermissionsAttribute * * Sets the file to the given permission. * * Results: * Standard TCL result. * * Side effects: * The permission of the file is changed. * *--------------------------------------------------------------------------- */ static int SetPermissionsAttribute(interp, objIndex, fileName, attributePtr) Tcl_Interp *interp; /* The interp we are using for errors. */ int objIndex; /* The index of the attribute. */ Tcl_Obj *fileName; /* The name of the file (UTF-8). */ Tcl_Obj *attributePtr; /* The attribute to set. */ { long mode; mode_t newMode; int result; CONST char *native; /* * First try if the string is a number */ if (Tcl_GetLongFromObj(NULL, attributePtr, &mode) == TCL_OK) { newMode = (mode_t) (mode & 0x00007FFF); } else { Tcl_StatBuf buf; char *modeStringPtr = Tcl_GetString(attributePtr); /* * Try the forms "rwxrwxrwx" and "ugo=rwx" * * We get the current mode of the file, in order to allow for * ug+-=rwx style chmod strings. */ result = TclpObjStat(fileName, &buf); if (result != 0) { Tcl_AppendResult(interp, "could not read \"", Tcl_GetString(fileName), "\": ", Tcl_PosixError(interp), (char *) NULL); return TCL_ERROR; } newMode = (mode_t) (buf.st_mode & 0x00007FFF); if (GetModeFromPermString(NULL, modeStringPtr, &newMode) != TCL_OK) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "unknown permission string format \"", modeStringPtr, "\"", (char *) NULL); return TCL_ERROR; } } native = Tcl_FSGetNativePath(fileName); result = chmod(native, newMode); /* INTL: Native. */ if (result != 0) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "could not set permissions for file \"", Tcl_GetString(fileName), "\": ", Tcl_PosixError(interp), (char *) NULL); return TCL_ERROR; } return TCL_OK; } /* *--------------------------------------------------------------------------- * * TclpObjListVolumes -- * * Lists the currently mounted volumes, which on UNIX is just /. * * Results: * The list of volumes. * * Side effects: * None. * *--------------------------------------------------------------------------- */ Tcl_Obj* TclpObjListVolumes(void) { Tcl_Obj *resultPtr = Tcl_NewStringObj("/",1); Tcl_IncrRefCount(resultPtr); return resultPtr; } /* *---------------------------------------------------------------------- * * GetModeFromPermString -- * * This procedure is invoked to process the "file permissions" * Tcl command, to check for a "rwxrwxrwx" or "ugoa+-=rwxst" string. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ static int GetModeFromPermString(interp, modeStringPtr, modePtr) Tcl_Interp *interp; /* The interp we are using for errors. */ char *modeStringPtr; /* Permissions string */ mode_t *modePtr; /* pointer to the mode value */ { mode_t newMode; mode_t oldMode; /* Storage for the value of the old mode * (that is passed in), to allow for the * chmod style manipulation */ int i,n, who, op, what, op_found, who_found; /* * We start off checking for an "rwxrwxrwx" style permissions string */ if (strlen(modeStringPtr) != 9) { goto chmodStyleCheck; } newMode = 0; for (i = 0; i < 9; i++) { switch (*(modeStringPtr+i)) { case 'r': if ((i%3) != 0) { goto chmodStyleCheck; } newMode |= (1<<(8-i)); break; case 'w': if ((i%3) != 1) { goto chmodStyleCheck; } newMode |= (1<<(8-i)); break; case 'x': if ((i%3) != 2) { goto chmodStyleCheck; } newMode |= (1<<(8-i)); break; case 's': if (((i%3) != 2) || (i > 5)) { goto chmodStyleCheck; } newMode |= (1<<(8-i)); newMode |= (1<<(11-(i/3))); break; case 'S': if (((i%3) != 2) || (i > 5)) { goto chmodStyleCheck; } newMode |= (1<<(11-(i/3))); break; case 't': if (i != 8) { goto chmodStyleCheck; } newMode |= (1<<(8-i)); newMode |= (1<<9); break; case 'T': if (i != 8) { goto chmodStyleCheck; } newMode |= (1<<9); break; case '-': break; default: /* * Oops, not what we thought it was, so go on */ goto chmodStyleCheck; } } *modePtr = newMode; return TCL_OK; chmodStyleCheck: /* * We now check for an "ugoa+-=rwxst" style permissions string */ for (n = 0 ; *(modeStringPtr+n) != '\0' ; n = n + i) { oldMode = *modePtr; who = op = what = op_found = who_found = 0; for (i = 0 ; *(modeStringPtr+n+i) != '\0' ; i++ ) { if (!who_found) { /* who */ switch (*(modeStringPtr+n+i)) { case 'u' : who |= 0x9c0; continue; case 'g' : who |= 0x438; continue; case 'o' : who |= 0x207; continue; case 'a' : who |= 0xfff; continue; } } who_found = 1; if (who == 0) { who = 0xfff; } if (!op_found) { /* op */ switch (*(modeStringPtr+n+i)) { case '+' : op = 1; op_found = 1; continue; case '-' : op = 2; op_found = 1; continue; case '=' : op = 3; op_found = 1; continue; default : return TCL_ERROR; } } /* what */ switch (*(modeStringPtr+n+i)) { case 'r' : what |= 0x124; continue; case 'w' : what |= 0x92; continue; case 'x' : what |= 0x49; continue; case 's' : what |= 0xc00; continue; case 't' : what |= 0x200; continue; case ',' : break; default : return TCL_ERROR; } if (*(modeStringPtr+n+i) == ',') { i++; break; } } switch (op) { case 1 : *modePtr = oldMode | (who & what); continue; case 2 : *modePtr = oldMode & ~(who & what); continue; case 3 : *modePtr = (oldMode & ~who) | (who & what); continue; } } return TCL_OK; } /* *--------------------------------------------------------------------------- * * TclpObjNormalizePath -- * * This function scans through a path specification and replaces * it, in place, with a normalized version. A normalized version * is one in which all symlinks in the path are replaced with * their expanded form (except a symlink at the very end of the * path). * * Results: * The new 'nextCheckpoint' value, giving as far as we could * understand in the path. * * Side effects: * The pathPtr string, is modified. * *--------------------------------------------------------------------------- */ int TclpObjNormalizePath(interp, pathPtr, nextCheckpoint) Tcl_Interp *interp; Tcl_Obj *pathPtr; int nextCheckpoint; { char *currentPathEndPosition; int pathLen; char cur; char *path = Tcl_GetStringFromObj(pathPtr, &pathLen); #ifndef NO_REALPATH char normPath[MAXPATHLEN]; Tcl_DString ds; CONST char *nativePath; #endif /* * We add '1' here because if nextCheckpoint is zero we know * that '/' exists, and if it isn't zero, it must point at * a directory separator which we also know exists. */ currentPathEndPosition = path + nextCheckpoint; if (*currentPathEndPosition == '/') { currentPathEndPosition++; } #ifndef NO_REALPATH /* For speed, try to get the entire path in one go */ if (nextCheckpoint == 0 && haveRealpath) { char *lastDir = strrchr(currentPathEndPosition, '/'); if (lastDir != NULL) { nativePath = Tcl_UtfToExternalDString(NULL, path, lastDir - path, &ds); if (Realpath(nativePath, normPath) != NULL) { if (*nativePath != '/' && *normPath == '/') { /* * realpath has transformed a relative path into an * absolute path, we do not know how to handle this. */ } else { nextCheckpoint = lastDir - path; goto wholeStringOk; } } Tcl_DStringFree(&ds); } } /* Else do it the slow way */ #endif while (1) { cur = *currentPathEndPosition; if ((cur == '/') && (path != currentPathEndPosition)) { /* Reached directory separator */ Tcl_DString ds; CONST char *nativePath; int accessOk; nativePath = Tcl_UtfToExternalDString(NULL, path, currentPathEndPosition - path, &ds); accessOk = access(nativePath, F_OK); Tcl_DStringFree(&ds); if (accessOk != 0) { /* File doesn't exist */ break; } /* Update the acceptable point */ nextCheckpoint = currentPathEndPosition - path; } else if (cur == 0) { /* Reached end of string */ break; } currentPathEndPosition++; } /* * We should really now convert this to a canonical path. We do * that with 'realpath' if we have it available. Otherwise we could * step through every single path component, checking whether it is a * symlink, but that would be a lot of work, and most modern OSes * have 'realpath'. */ #ifndef NO_REALPATH if (haveRealpath) { /* * If we only had '/foo' or '/' then we never increment nextCheckpoint * and we don't need or want to go through 'Realpath'. Also, on some * platforms, passing an empty string to 'Realpath' will give us the * normalized pwd, which is not what we want at all! */ if (nextCheckpoint == 0) return 0; nativePath = Tcl_UtfToExternalDString(NULL, path, nextCheckpoint, &ds); if (Realpath(nativePath, normPath) != NULL) { int newNormLen; wholeStringOk: newNormLen = strlen(normPath); if ((newNormLen == Tcl_DStringLength(&ds)) && (strcmp(normPath, nativePath) == 0)) { /* String is unchanged */ Tcl_DStringFree(&ds); if (path[nextCheckpoint] != '\0') { nextCheckpoint++; } return nextCheckpoint; } /* * Free up the native path and put in its place the * converted, normalized path. */ Tcl_DStringFree(&ds); Tcl_ExternalToUtfDString(NULL, normPath, (int) newNormLen, &ds); if (path[nextCheckpoint] != '\0') { /* not at end, append remaining path */ int normLen = Tcl_DStringLength(&ds); Tcl_DStringAppend(&ds, path + nextCheckpoint, pathLen - nextCheckpoint); /* * We recognise up to and including the directory * separator. */ nextCheckpoint = normLen + 1; } else { /* We recognise the whole string */ nextCheckpoint = Tcl_DStringLength(&ds); } /* * Overwrite with the normalized path. */ Tcl_SetStringObj(pathPtr, Tcl_DStringValue(&ds), Tcl_DStringLength(&ds)); } Tcl_DStringFree(&ds); } #endif /* !NO_REALPATH */ return nextCheckpoint; } tcl8.4.20/unix/tclUnixEvent.c0000644003604700454610000000331111737050675014475 0ustar dgp771div/* * tclUnixEvent.c -- * * This file implements Unix specific event related routines. * * Copyright (c) 1997 by Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" /* *---------------------------------------------------------------------- * * Tcl_Sleep -- * * Delay execution for the specified number of milliseconds. * * Results: * None. * * Side effects: * Time passes. * *---------------------------------------------------------------------- */ void Tcl_Sleep(ms) int ms; /* Number of milliseconds to sleep. */ { struct timeval delay; Tcl_Time before, after; /* * The only trick here is that select appears to return early * under some conditions, so we have to check to make sure that * the right amount of time really has elapsed. If it's too * early, go back to sleep again. */ Tcl_GetTime(&before); after = before; after.sec += ms/1000; after.usec += (ms%1000)*1000; if (after.usec > 1000000) { after.usec -= 1000000; after.sec += 1; } while (1) { delay.tv_sec = after.sec - before.sec; delay.tv_usec = after.usec - before.usec; if (delay.tv_usec < 0) { delay.tv_usec += 1000000; delay.tv_sec -= 1; } /* * Special note: must convert delay.tv_sec to int before comparing * to zero, since delay.tv_usec is unsigned on some platforms. */ if ((((int) delay.tv_sec) < 0) || ((delay.tv_usec == 0) && (delay.tv_sec == 0))) { break; } (void) select(0, (SELECT_MASK *) 0, (SELECT_MASK *) 0, (SELECT_MASK *) 0, &delay); Tcl_GetTime(&before); } } tcl8.4.20/unix/tclUnixTime.c0000644003604700454610000002561611737050675014326 0ustar dgp771div/* * tclUnixTime.c -- * * Contains Unix specific versions of Tcl functions that obtain time * values from the operating system. * * Copyright (c) 1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" #include #define TM_YEAR_BASE 1900 #define IsLeapYear(x) (((x)%4 == 0) && ((x)%100 != 0 || (x)%400 == 0)) /* * TclpGetDate is coded to return a pointer to a 'struct tm'. For thread * safety, this structure must be in thread-specific data. The 'tmKey' * variable is the key to this buffer. */ static Tcl_ThreadDataKey tmKey; typedef struct ThreadSpecificData { struct tm gmtime_buf; struct tm localtime_buf; } ThreadSpecificData; /* * If we fall back on the thread-unsafe versions of gmtime and localtime, use * this mutex to try to protect them. */ TCL_DECLARE_MUTEX(tmMutex) static char *lastTZ = NULL; /* Holds the last setting of the TZ * environment variable, or an empty string if * the variable was not set. */ /* * Static functions declared in this file. */ static void SetTZIfNecessary _ANSI_ARGS_((void)); static void CleanupMemory _ANSI_ARGS_((ClientData)); /* *---------------------------------------------------------------------- * * TclpGetSeconds -- * * This procedure returns the number of seconds from the epoch. On most * Unix systems the epoch is Midnight Jan 1, 1970 GMT. * * Results: * Number of seconds from the epoch. * * Side effects: * None. * *---------------------------------------------------------------------- */ unsigned long TclpGetSeconds() { return time((time_t *) NULL); } /* *---------------------------------------------------------------------- * * TclpGetClicks -- * * This procedure returns a value that represents the highest resolution * clock available on the system. There are no garantees on what the * resolution will be. In Tcl we will call this value a "click". The * start time is also system dependant. * * Results: * Number of clicks from some start time. * * Side effects: * None. * *---------------------------------------------------------------------- */ unsigned long TclpGetClicks() { unsigned long now; #ifdef NO_GETTOD struct tms dummy; #else struct timeval date; #endif #ifdef NO_GETTOD now = (unsigned long) times(&dummy); #else gettimeofday(&date, NULL); now = date.tv_sec*1000000 + date.tv_usec; #endif return now; } /* *---------------------------------------------------------------------- * * TclpGetTimeZone -- * * Determines the current timezone. The method varies wildly between * different platform implementations, so its hidden in this function. * * Results: * The return value is the local time zone, measured in minutes away from * GMT (-ve for east, +ve for west). * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclpGetTimeZone(currentTime) Tcl_WideInt currentTime; { int timeZone; /* * We prefer first to use the time zone in "struct tm" if the structure * contains such a member. Following that, we try to locate the external * 'timezone' variable and use its value. If both of those methods fail, * we attempt to convert a known time to local time and use the difference * from UTC as the local time zone. In all cases, we need to undo any * Daylight Saving Time adjustment. */ #if defined(HAVE_TM_TZADJ) #define TCL_GOT_TIMEZONE /* * Struct tm contains tm_tzadj - that value may be used. */ time_t curTime = (time_t) currentTime; struct tm *timeDataPtr = TclpLocaltime((TclpTime_t) &curTime); timeZone = timeDataPtr->tm_tzadj / 60; if (timeDataPtr->tm_isdst) { timeZone += 60; } #endif #if defined(HAVE_TM_GMTOFF) && !defined (TCL_GOT_TIMEZONE) #define TCL_GOT_TIMEZONE /* * Struct tm contains tm_gmtoff - that value may be used. */ time_t curTime = (time_t) currentTime; struct tm *timeDataPtr = TclpLocaltime((TclpTime_t) &curTime); timeZone = -(timeDataPtr->tm_gmtoff / 60); if (timeDataPtr->tm_isdst) { timeZone += 60; } #endif #if defined(HAVE_TIMEZONE_VAR) && !defined(TCL_GOT_TIMEZONE) && !defined(USE_DELTA_FOR_TZ) #define TCL_GOT_TIMEZONE /* * The 'timezone' external var is present and may be used. */ SetTZIfNecessary(); /* * Note: this is not a typo in "timezone" below! See tzset documentation * for details. */ timeZone = timezone / 60; #endif #if !defined(TCL_GOT_TIMEZONE) #define TCL_GOT_TIMEZONE /* * Fallback - determine time zone with a known reference time. */ time_t tt; struct tm *stm; tt = 849268800L; /* 1996-11-29 12:00:00 GMT */ stm = TclpLocaltime((TclpTime_t) &tt); /* eg 1996-11-29 6:00:00 CST6CDT */ /* * The calculation below assumes a max of +12 or -12 hours from GMT. */ timeZone = (12 - stm->tm_hour)*60 + (0 - stm->tm_min); if (stm->tm_isdst) { timeZone += 60; } /* * Now have offset for our known reference time, eg +360 for CST6CDT. */ #endif #ifndef TCL_GOT_TIMEZONE /* * Cause fatal compile error, we don't know how to get timezone. */ #error autoconf did not figure out how to determine the timezone. #endif return timeZone; } /* *---------------------------------------------------------------------- * * Tcl_GetTime -- * * Gets the current system time in seconds and microseconds since the * beginning of the epoch: 00:00 UCT, January 1, 1970. * * Results: * Returns the current time in timePtr. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Tcl_GetTime(timePtr) Tcl_Time *timePtr; /* Location to store time information. */ { struct timeval tv; (void) gettimeofday(&tv, NULL); timePtr->sec = tv.tv_sec; timePtr->usec = tv.tv_usec; } /* *---------------------------------------------------------------------- * * TclpGetDate -- * * This function converts between seconds and struct tm. If useGMT is * true, then the returned date will be in Greenwich Mean Time (GMT). * Otherwise, it will be in the local time zone. * * Results: * Returns a static tm structure. * * Side effects: * None. * *---------------------------------------------------------------------- */ struct tm * TclpGetDate(time, useGMT) TclpTime_t time; int useGMT; { if (useGMT) { return TclpGmtime(time); } else { return TclpLocaltime(time); } } /* *---------------------------------------------------------------------- * * TclpStrftime -- * * On Unix, we can safely call the native strftime implementation, * and also ignore the useGMT parameter. * * Results: * The normal strftime result. * * Side effects: * None. * *---------------------------------------------------------------------- */ size_t TclpStrftime(s, maxsize, format, t, useGMT) char *s; size_t maxsize; CONST char *format; CONST struct tm *t; int useGMT; { if (format[0] == '%' && format[1] == 'Q') { /* Format as a stardate */ sprintf(s, "Stardate %2d%03d.%01d", (((t->tm_year + TM_YEAR_BASE) + 377) - 2323), (((t->tm_yday + 1) * 1000) / (365 + IsLeapYear((t->tm_year + TM_YEAR_BASE)))), (((t->tm_hour * 60) + t->tm_min)/144)); return(strlen(s)); } setlocale(LC_TIME, ""); return strftime(s, maxsize, format, t); } /* *---------------------------------------------------------------------- * * TclpGmtime -- * * Wrapper around the 'gmtime' library function to make it thread * safe. * * Results: * Returns a pointer to a 'struct tm' in thread-specific data. * * Side effects: * Invokes gmtime or gmtime_r as appropriate. * *---------------------------------------------------------------------- */ struct tm * TclpGmtime(tt) TclpTime_t_CONST tt; { CONST time_t *timePtr = (CONST time_t *) tt; /* Pointer to the number of seconds * since the local system's epoch */ /* * Get a thread-local buffer to hold the returned time. */ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tmKey); #ifdef HAVE_GMTIME_R gmtime_r(timePtr, &(tsdPtr->gmtime_buf)); #else Tcl_MutexLock(&tmMutex); memcpy((VOID *) &(tsdPtr->gmtime_buf), (VOID *) gmtime(timePtr), sizeof(struct tm)); Tcl_MutexUnlock(&tmMutex); #endif return &(tsdPtr->gmtime_buf); } /* *---------------------------------------------------------------------- * * TclpLocaltime -- * * Wrapper around the 'localtime' library function to make it thread * safe. * * Results: * Returns a pointer to a 'struct tm' in thread-specific data. * * Side effects: * Invokes localtime or localtime_r as appropriate. * *---------------------------------------------------------------------- */ struct tm * TclpLocaltime(tt) TclpTime_t_CONST tt; { CONST time_t *timePtr = (CONST time_t *) tt; /* Pointer to the number of seconds * since the local system's epoch */ /* * Get a thread-local buffer to hold the returned time. */ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tmKey); SetTZIfNecessary(); #ifdef HAVE_LOCALTIME_R localtime_r(timePtr, &(tsdPtr->localtime_buf)); #else Tcl_MutexLock(&tmMutex); memcpy((VOID *) &(tsdPtr -> localtime_buf), (VOID *) localtime(timePtr), sizeof(struct tm)); Tcl_MutexUnlock(&tmMutex); #endif return &(tsdPtr->localtime_buf); } /* *---------------------------------------------------------------------- * * SetTZIfNecessary -- * * Determines whether a call to 'tzset' is needed prior to the next call * to 'localtime' or examination of the 'timezone' variable. * * Results: * None. * * Side effects: * If 'tzset' has never been called in the current process, or if the * value of the environment variable TZ has changed since the last call * to 'tzset', then 'tzset' is called again. * *---------------------------------------------------------------------- */ static void SetTZIfNecessary() { CONST char *newTZ = getenv("TZ"); Tcl_MutexLock(&tmMutex); if (newTZ == NULL) { newTZ = ""; } if (lastTZ == NULL || strcmp(lastTZ, newTZ)) { tzset(); if (lastTZ == NULL) { Tcl_CreateExitHandler(CleanupMemory, (ClientData) NULL); } else { Tcl_Free(lastTZ); } lastTZ = ckalloc(strlen(newTZ) + 1); strcpy(lastTZ, newTZ); } Tcl_MutexUnlock(&tmMutex); } /* *---------------------------------------------------------------------- * * CleanupMemory -- * * Releases the private copy of the TZ environment variable upon exit * from Tcl. * * Results: * None. * * Side effects: * Frees allocated memory. * *---------------------------------------------------------------------- */ static void CleanupMemory(ignored) ClientData ignored; { ckfree(lastTZ); } /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ tcl8.4.20/unix/tclUnixChan.c0000644003604700454610000026274712052456744014307 0ustar dgp771div/* * tclUnixChan.c * * Common channel driver for Unix channels based on files, command * pipes and TCP sockets. * * Copyright (c) 1995-1997 Sun Microsystems, Inc. * Copyright (c) 1998-1999 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" /* Internal definitions for Tcl. */ #include "tclPort.h" /* Portability features for Tcl. */ #include "tclIO.h" /* To get Channel type declaration. */ /* * sys/ioctl.h has already been included by tclPort.h. Including termios.h * or termio.h causes a bunch of warning messages because some duplicate * (but not contradictory) #defines exist in termios.h and/or termio.h */ #undef NL0 #undef NL1 #undef CR0 #undef CR1 #undef CR2 #undef CR3 #undef TAB0 #undef TAB1 #undef TAB2 #undef XTABS #undef BS0 #undef BS1 #undef FF0 #undef FF1 #undef ECHO #undef NOFLSH #undef TOSTOP #undef FLUSHO #undef PENDIN #define SUPPORTS_TTY #ifdef USE_TERMIOS # include # ifdef HAVE_SYS_IOCTL_H # include # endif /* HAVE_SYS_IOCTL_H */ # ifdef HAVE_SYS_MODEM_H # include # endif /* HAVE_SYS_MODEM_H */ # define IOSTATE struct termios # define GETIOSTATE(fd, statePtr) tcgetattr((fd), (statePtr)) # define SETIOSTATE(fd, statePtr) tcsetattr((fd), TCSADRAIN, (statePtr)) # define GETCONTROL(fd, intPtr) ioctl((fd), TIOCMGET, (intPtr)) # define SETCONTROL(fd, intPtr) ioctl((fd), TIOCMSET, (intPtr)) /* * TIP #35 introduced a different on exit flush/close behavior that * doesn't work correctly with standard channels on all systems. * The problem is tcflush throws away waiting channel data. This may * be necessary for true serial channels that may block, but isn't * correct in the standard case. This might be replaced with tcdrain * instead, but that can block. For now, we revert to making this do * nothing, and TtyOutputProc being the same old FileOutputProc. * -- hobbs [Bug #525783] */ # define BAD_TIP35_FLUSH 0 # if BAD_TIP35_FLUSH # define TTYFLUSH(fd) tcflush((fd), TCIOFLUSH); # else # define TTYFLUSH(fd) # endif /* BAD_TIP35_FLUSH */ # ifdef FIONREAD # define GETREADQUEUE(fd, int) ioctl((fd), FIONREAD, &(int)) # elif defined(FIORDCHK) # define GETREADQUEUE(fd, int) int = ioctl((fd), FIORDCHK, NULL) # endif /* FIONREAD */ # ifdef TIOCOUTQ # define GETWRITEQUEUE(fd, int) ioctl((fd), TIOCOUTQ, &(int)) # endif /* TIOCOUTQ */ # if defined(TIOCSBRK) && defined(TIOCCBRK) /* * Can't use ?: operator below because that messes up types on either * Linux or Solaris (the two are mutually exclusive!) */ # define SETBREAK(fd, flag) \ if (flag) { \ ioctl((fd), TIOCSBRK, NULL); \ } else { \ ioctl((fd), TIOCCBRK, NULL); \ } # endif /* TIOCSBRK&TIOCCBRK */ # if !defined(CRTSCTS) && defined(CNEW_RTSCTS) # define CRTSCTS CNEW_RTSCTS # endif /* !CRTSCTS&CNEW_RTSCTS */ # if !defined(PAREXT) && defined(CMSPAR) # define PAREXT CMSPAR # endif /* !PAREXT&&CMSPAR */ #else /* !USE_TERMIOS */ #ifdef USE_TERMIO # include # define IOSTATE struct termio # define GETIOSTATE(fd, statePtr) ioctl((fd), TCGETA, (statePtr)) # define SETIOSTATE(fd, statePtr) ioctl((fd), TCSETAW, (statePtr)) #else /* !USE_TERMIO */ #ifdef USE_SGTTY # include # define IOSTATE struct sgttyb # define GETIOSTATE(fd, statePtr) ioctl((fd), TIOCGETP, (statePtr)) # define SETIOSTATE(fd, statePtr) ioctl((fd), TIOCSETP, (statePtr)) #else /* !USE_SGTTY */ # undef SUPPORTS_TTY #endif /* !USE_SGTTY */ #endif /* !USE_TERMIO */ #endif /* !USE_TERMIOS */ /* * This structure describes per-instance state of a file based channel. */ typedef struct FileState { Tcl_Channel channel; /* Channel associated with this file. */ int fd; /* File handle. */ int validMask; /* OR'ed combination of TCL_READABLE, * TCL_WRITABLE, or TCL_EXCEPTION: indicates * which operations are valid on the file. */ #ifdef DEPRECATED struct FileState *nextPtr; /* Pointer to next file in list of all * file channels. */ #endif /* DEPRECATED */ } FileState; #ifdef SUPPORTS_TTY /* * The following structure describes per-instance state of a tty-based * channel. */ typedef struct TtyState { FileState fs; /* Per-instance state of the file * descriptor. Must be the first field. */ int stateUpdated; /* Flag to say if the state has been * modified and needs resetting. */ IOSTATE savedState; /* Initial state of device. Used to reset * state when device closed. */ } TtyState; /* * The following structure is used to set or get the serial port * attributes in a platform-independant manner. */ typedef struct TtyAttrs { int baud; int parity; int data; int stop; } TtyAttrs; #endif /* !SUPPORTS_TTY */ #define UNSUPPORTED_OPTION(detail) \ if (interp) { \ Tcl_AppendResult(interp, (detail), \ " not supported for this platform", (char *) NULL); \ } #ifdef DEPRECATED typedef struct ThreadSpecificData { /* * List of all file channels currently open. This is per thread and is * used to match up fd's to channels, which rarely occurs. */ FileState *firstFilePtr; } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; #endif /* DEPRECATED */ /* * This structure describes per-instance state of a tcp based channel. */ typedef struct TcpState { Tcl_Channel channel; /* Channel associated with this file. */ int fd; /* The socket itself. */ int flags; /* ORed combination of the bitfields * defined below. */ Tcl_TcpAcceptProc *acceptProc; /* Proc to call on accept. */ ClientData acceptProcData; /* The data for the accept proc. */ } TcpState; /* * These bits may be ORed together into the "flags" field of a TcpState * structure. */ #define TCP_ASYNC_SOCKET (1<<0) /* Asynchronous socket. */ #define TCP_ASYNC_CONNECT (1<<1) /* Async connect in progress. */ /* * The following defines the maximum length of the listen queue. This is * the number of outstanding yet-to-be-serviced requests for a connection * on a server socket, more than this number of outstanding requests and * the connection request will fail. */ #ifndef SOMAXCONN # define SOMAXCONN 100 #endif /* SOMAXCONN */ #if (SOMAXCONN < 100) # undef SOMAXCONN # define SOMAXCONN 100 #endif /* SOMAXCONN < 100 */ /* * The following defines how much buffer space the kernel should maintain * for a socket. */ #define SOCKET_BUFSIZE 4096 /* * Static routines for this file: */ static TcpState * CreateSocket _ANSI_ARGS_((Tcl_Interp *interp, int port, CONST char *host, int server, CONST char *myaddr, int myport, int async)); static int CreateSocketAddress _ANSI_ARGS_( (struct sockaddr_in *sockaddrPtr, CONST char *host, int port)); static int FileBlockModeProc _ANSI_ARGS_(( ClientData instanceData, int mode)); static int FileCloseProc _ANSI_ARGS_((ClientData instanceData, Tcl_Interp *interp)); static int FileGetHandleProc _ANSI_ARGS_((ClientData instanceData, int direction, ClientData *handlePtr)); static int FileInputProc _ANSI_ARGS_((ClientData instanceData, char *buf, int toRead, int *errorCode)); static int FileOutputProc _ANSI_ARGS_(( ClientData instanceData, CONST char *buf, int toWrite, int *errorCode)); static int FileSeekProc _ANSI_ARGS_((ClientData instanceData, long offset, int mode, int *errorCode)); #ifdef DEPRECATED static void FileThreadActionProc _ANSI_ARGS_ (( ClientData instanceData, int action)); #endif static Tcl_WideInt FileWideSeekProc _ANSI_ARGS_((ClientData instanceData, Tcl_WideInt offset, int mode, int *errorCode)); static void FileWatchProc _ANSI_ARGS_((ClientData instanceData, int mask)); static void TcpAccept _ANSI_ARGS_((ClientData data, int mask)); static int TcpBlockModeProc _ANSI_ARGS_((ClientData data, int mode)); static int TcpCloseProc _ANSI_ARGS_((ClientData instanceData, Tcl_Interp *interp)); static int TcpGetHandleProc _ANSI_ARGS_((ClientData instanceData, int direction, ClientData *handlePtr)); static int TcpGetOptionProc _ANSI_ARGS_((ClientData instanceData, Tcl_Interp *interp, CONST char *optionName, Tcl_DString *dsPtr)); static int TcpInputProc _ANSI_ARGS_((ClientData instanceData, char *buf, int toRead, int *errorCode)); static int TcpOutputProc _ANSI_ARGS_((ClientData instanceData, CONST char *buf, int toWrite, int *errorCode)); static void TcpWatchProc _ANSI_ARGS_((ClientData instanceData, int mask)); #ifdef SUPPORTS_TTY static int TtyCloseProc _ANSI_ARGS_((ClientData instanceData, Tcl_Interp *interp)); static void TtyGetAttributes _ANSI_ARGS_((int fd, TtyAttrs *ttyPtr)); static int TtyGetOptionProc _ANSI_ARGS_((ClientData instanceData, Tcl_Interp *interp, CONST char *optionName, Tcl_DString *dsPtr)); static FileState * TtyInit _ANSI_ARGS_((int fd, int initialize)); #if BAD_TIP35_FLUSH static int TtyOutputProc _ANSI_ARGS_((ClientData instanceData, CONST char *buf, int toWrite, int *errorCode)); #endif /* BAD_TIP35_FLUSH */ static int TtyParseMode _ANSI_ARGS_((Tcl_Interp *interp, CONST char *mode, int *speedPtr, int *parityPtr, int *dataPtr, int *stopPtr)); static void TtySetAttributes _ANSI_ARGS_((int fd, TtyAttrs *ttyPtr)); static int TtySetOptionProc _ANSI_ARGS_((ClientData instanceData, Tcl_Interp *interp, CONST char *optionName, CONST char *value)); #endif /* SUPPORTS_TTY */ static int WaitForConnect _ANSI_ARGS_((TcpState *statePtr, int *errorCodePtr)); static Tcl_Channel MakeTcpClientChannelMode _ANSI_ARGS_( (ClientData tcpSocket, int mode)); /* * This structure describes the channel type structure for file based IO: */ static Tcl_ChannelType fileChannelType = { "file", /* Type name. */ TCL_CHANNEL_VERSION_4, /* v4 channel */ FileCloseProc, /* Close proc. */ FileInputProc, /* Input proc. */ FileOutputProc, /* Output proc. */ FileSeekProc, /* Seek proc. */ NULL, /* Set option proc. */ NULL, /* Get option proc. */ FileWatchProc, /* Initialize notifier. */ FileGetHandleProc, /* Get OS handles out of channel. */ NULL, /* close2proc. */ FileBlockModeProc, /* Set blocking or non-blocking mode.*/ NULL, /* flush proc. */ NULL, /* handler proc. */ FileWideSeekProc, /* wide seek proc. */ #ifdef DEPRECATED FileThreadActionProc, /* thread actions */ #else NULL, #endif }; #ifdef SUPPORTS_TTY /* * This structure describes the channel type structure for serial IO. * Note that this type is a subclass of the "file" type. */ static Tcl_ChannelType ttyChannelType = { "tty", /* Type name. */ TCL_CHANNEL_VERSION_4, /* v4 channel */ TtyCloseProc, /* Close proc. */ FileInputProc, /* Input proc. */ #if BAD_TIP35_FLUSH TtyOutputProc, /* Output proc. */ #else /* !BAD_TIP35_FLUSH */ FileOutputProc, /* Output proc. */ #endif /* BAD_TIP35_FLUSH */ NULL, /* Seek proc. */ TtySetOptionProc, /* Set option proc. */ TtyGetOptionProc, /* Get option proc. */ FileWatchProc, /* Initialize notifier. */ FileGetHandleProc, /* Get OS handles out of channel. */ NULL, /* close2proc. */ FileBlockModeProc, /* Set blocking or non-blocking mode.*/ NULL, /* flush proc. */ NULL, /* handler proc. */ NULL, /* wide seek proc. */ NULL, /* thread action proc. */ }; #endif /* SUPPORTS_TTY */ /* * This structure describes the channel type structure for TCP socket * based IO: */ static Tcl_ChannelType tcpChannelType = { "tcp", /* Type name. */ TCL_CHANNEL_VERSION_4, /* v4 channel */ TcpCloseProc, /* Close proc. */ TcpInputProc, /* Input proc. */ TcpOutputProc, /* Output proc. */ NULL, /* Seek proc. */ NULL, /* Set option proc. */ TcpGetOptionProc, /* Get option proc. */ TcpWatchProc, /* Initialize notifier. */ TcpGetHandleProc, /* Get OS handles out of channel. */ NULL, /* close2proc. */ TcpBlockModeProc, /* Set blocking or non-blocking mode.*/ NULL, /* flush proc. */ NULL, /* handler proc. */ NULL, /* wide seek proc. */ NULL, /* thread action proc. */ }; /* *---------------------------------------------------------------------- * * FileBlockModeProc -- * * Helper procedure to set blocking and nonblocking modes on a * file based channel. Invoked by generic IO level code. * * Results: * 0 if successful, errno when failed. * * Side effects: * Sets the device into blocking or non-blocking mode. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int FileBlockModeProc(instanceData, mode) ClientData instanceData; /* File state. */ int mode; /* The mode to set. Can be one of * TCL_MODE_BLOCKING or * TCL_MODE_NONBLOCKING. */ { FileState *fsPtr = (FileState *) instanceData; int curStatus; #ifndef USE_FIONBIO curStatus = fcntl(fsPtr->fd, F_GETFL); if (mode == TCL_MODE_BLOCKING) { curStatus &= (~(O_NONBLOCK)); } else { curStatus |= O_NONBLOCK; } if (fcntl(fsPtr->fd, F_SETFL, curStatus) < 0) { return errno; } curStatus = fcntl(fsPtr->fd, F_GETFL); #else /* USE_FIONBIO */ if (mode == TCL_MODE_BLOCKING) { curStatus = 0; } else { curStatus = 1; } if (ioctl(fsPtr->fd, (int) FIONBIO, &curStatus) < 0) { return errno; } #endif /* !USE_FIONBIO */ return 0; } /* *---------------------------------------------------------------------- * * FileInputProc -- * * This procedure is invoked from the generic IO level to read * input from a file based channel. * * Results: * The number of bytes read is returned or -1 on error. An output * argument contains a POSIX error code if an error occurs, or zero. * * Side effects: * Reads input from the input device of the channel. * *---------------------------------------------------------------------- */ static int FileInputProc(instanceData, buf, toRead, errorCodePtr) ClientData instanceData; /* File state. */ char *buf; /* Where to store data read. */ int toRead; /* How much space is available * in the buffer? */ int *errorCodePtr; /* Where to store error code. */ { FileState *fsPtr = (FileState *) instanceData; int bytesRead; /* How many bytes were actually * read from the input device? */ *errorCodePtr = 0; /* * Assume there is always enough input available. This will block * appropriately, and read will unblock as soon as a short read is * possible, if the channel is in blocking mode. If the channel is * nonblocking, the read will never block. */ bytesRead = read(fsPtr->fd, buf, (size_t) toRead); if (bytesRead > -1) { return bytesRead; } *errorCodePtr = errno; return -1; } /* *---------------------------------------------------------------------- * * FileOutputProc-- * * This procedure is invoked from the generic IO level to write * output to a file channel. * * Results: * The number of bytes written is returned or -1 on error. An * output argument contains a POSIX error code if an error occurred, * or zero. * * Side effects: * Writes output on the output device of the channel. * *---------------------------------------------------------------------- */ static int FileOutputProc(instanceData, buf, toWrite, errorCodePtr) ClientData instanceData; /* File state. */ CONST char *buf; /* The data buffer. */ int toWrite; /* How many bytes to write? */ int *errorCodePtr; /* Where to store error code. */ { FileState *fsPtr = (FileState *) instanceData; int written; *errorCodePtr = 0; if (toWrite == 0) { /* * SF Tcl Bug 465765. * Do not try to write nothing into a file. STREAM based * implementations will considers this as EOF (if there is a * pipe behind the file). */ return 0; } written = write(fsPtr->fd, buf, (size_t) toWrite); if (written > -1) { return written; } *errorCodePtr = errno; return -1; } /* *---------------------------------------------------------------------- * * FileCloseProc -- * * This procedure is called from the generic IO level to perform * channel-type-specific cleanup when a file based channel is closed. * * Results: * 0 if successful, errno if failed. * * Side effects: * Closes the device of the channel. * *---------------------------------------------------------------------- */ static int FileCloseProc(instanceData, interp) ClientData instanceData; /* File state. */ Tcl_Interp *interp; /* For error reporting - unused. */ { FileState *fsPtr = (FileState *) instanceData; int errorCode = 0; #ifdef DEPRECATED FileState **nextPtrPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); #endif /* DEPRECATED */ Tcl_DeleteFileHandler(fsPtr->fd); /* * Do not close standard channels while in thread-exit. */ if (!TclInThreadExit() || ((fsPtr->fd != 0) && (fsPtr->fd != 1) && (fsPtr->fd != 2))) { if (close(fsPtr->fd) < 0) { errorCode = errno; } } ckfree((char *) fsPtr); return errorCode; } /* *---------------------------------------------------------------------- * * FileSeekProc -- * * This procedure is called by the generic IO level to move the * access point in a file based channel. * * Results: * -1 if failed, the new position if successful. An output * argument contains the POSIX error code if an error occurred, * or zero. * * Side effects: * Moves the location at which the channel will be accessed in * future operations. * *---------------------------------------------------------------------- */ static int FileSeekProc(instanceData, offset, mode, errorCodePtr) ClientData instanceData; /* File state. */ long offset; /* Offset to seek to. */ int mode; /* Relative to where should we seek? Can be * one of SEEK_START, SEEK_SET or SEEK_END. */ int *errorCodePtr; /* To store error code. */ { FileState *fsPtr = (FileState *) instanceData; Tcl_WideInt oldLoc, newLoc; /* * Save our current place in case we need to roll-back the seek. */ oldLoc = TclOSseek(fsPtr->fd, (Tcl_SeekOffset) 0, SEEK_CUR); if (oldLoc == Tcl_LongAsWide(-1)) { /* * Bad things are happening. Error out... */ *errorCodePtr = errno; return -1; } newLoc = TclOSseek(fsPtr->fd, (Tcl_SeekOffset) offset, mode); /* * Check for expressability in our return type, and roll-back otherwise. */ if (newLoc > Tcl_LongAsWide(INT_MAX)) { *errorCodePtr = EOVERFLOW; TclOSseek(fsPtr->fd, (Tcl_SeekOffset) oldLoc, SEEK_SET); return -1; } else { *errorCodePtr = (newLoc == Tcl_LongAsWide(-1)) ? errno : 0; } return (int) Tcl_WideAsLong(newLoc); } /* *---------------------------------------------------------------------- * * FileWideSeekProc -- * * This procedure is called by the generic IO level to move the * access point in a file based channel, with offsets expressed * as wide integers. * * Results: * -1 if failed, the new position if successful. An output * argument contains the POSIX error code if an error occurred, * or zero. * * Side effects: * Moves the location at which the channel will be accessed in * future operations. * *---------------------------------------------------------------------- */ static Tcl_WideInt FileWideSeekProc(instanceData, offset, mode, errorCodePtr) ClientData instanceData; /* File state. */ Tcl_WideInt offset; /* Offset to seek to. */ int mode; /* Relative to where should we seek? Can be * one of SEEK_START, SEEK_CUR or SEEK_END. */ int *errorCodePtr; /* To store error code. */ { FileState *fsPtr = (FileState *) instanceData; Tcl_WideInt newLoc; newLoc = TclOSseek(fsPtr->fd, (Tcl_SeekOffset) offset, mode); *errorCodePtr = (newLoc == -1) ? errno : 0; return newLoc; } /* *---------------------------------------------------------------------- * * FileWatchProc -- * * Initialize the notifier to watch the fd from this channel. * * Results: * None. * * Side effects: * Sets up the notifier so that a future event on the channel will * be seen by Tcl. * *---------------------------------------------------------------------- */ static void FileWatchProc(instanceData, mask) ClientData instanceData; /* The file state. */ int mask; /* Events of interest; an OR-ed * combination of TCL_READABLE, * TCL_WRITABLE and TCL_EXCEPTION. */ { FileState *fsPtr = (FileState *) instanceData; /* * Make sure we only register for events that are valid on this file. * Note that we are passing Tcl_NotifyChannel directly to * Tcl_CreateFileHandler with the channel pointer as the client data. */ mask &= fsPtr->validMask; if (mask) { Tcl_CreateFileHandler(fsPtr->fd, mask, (Tcl_FileProc *) Tcl_NotifyChannel, (ClientData) fsPtr->channel); } else { Tcl_DeleteFileHandler(fsPtr->fd); } } /* *---------------------------------------------------------------------- * * FileGetHandleProc -- * * Called from Tcl_GetChannelHandle to retrieve OS handles from * a file based channel. * * Results: * Returns TCL_OK with the fd in handlePtr, or TCL_ERROR if * there is no handle for the specified direction. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int FileGetHandleProc(instanceData, direction, handlePtr) ClientData instanceData; /* The file state. */ int direction; /* TCL_READABLE or TCL_WRITABLE */ ClientData *handlePtr; /* Where to store the handle. */ { FileState *fsPtr = (FileState *) instanceData; if (direction & fsPtr->validMask) { *handlePtr = (ClientData) fsPtr->fd; return TCL_OK; } else { return TCL_ERROR; } } #ifdef SUPPORTS_TTY /* *---------------------------------------------------------------------- * * TtyCloseProc -- * * This procedure is called from the generic IO level to perform * channel-type-specific cleanup when a tty based channel is closed. * * Results: * 0 if successful, errno if failed. * * Side effects: * Closes the device of the channel. * *---------------------------------------------------------------------- */ static int TtyCloseProc(instanceData, interp) ClientData instanceData; /* Tty state. */ Tcl_Interp *interp; /* For error reporting - unused. */ { #if BAD_TIP35_FLUSH TtyState *ttyPtr = (TtyState *) instanceData; #endif /* BAD_TIP35_FLUSH */ #ifdef TTYFLUSH TTYFLUSH(ttyPtr->fs.fd); #endif /* TTYFLUSH */ #if 0 /* * TIP#35 agreed to remove the unsave so that TCL could be used as a * simple stty. * It would be cleaner to remove all the stuff related to * TtyState.stateUpdated * TtyState.savedState * Then the structure TtyState would be the same as FileState. * IMO this cleanup could better be done for the final 8.4 release * after nobody complained about the missing unsave. -- schroedter */ if (ttyPtr->stateUpdated) { SETIOSTATE(ttyPtr->fs.fd, &ttyPtr->savedState); } #endif return FileCloseProc(instanceData, interp); } /* *---------------------------------------------------------------------- * * TtyOutputProc-- * * This procedure is invoked from the generic IO level to write * output to a TTY channel. * * Results: * The number of bytes written is returned or -1 on error. An * output argument contains a POSIX error code if an error occurred, * or zero. * * Side effects: * Writes output on the output device of the channel * if the channel is not designated to be closed. * *---------------------------------------------------------------------- */ #if BAD_TIP35_FLUSH static int TtyOutputProc(instanceData, buf, toWrite, errorCodePtr) ClientData instanceData; /* File state. */ CONST char *buf; /* The data buffer. */ int toWrite; /* How many bytes to write? */ int *errorCodePtr; /* Where to store error code. */ { if (TclInExit()) { /* * Do not write data during Tcl exit. * Serial port may block preventing Tcl from exit. */ return toWrite; } else { return FileOutputProc(instanceData, buf, toWrite, errorCodePtr); } } #endif /* BAD_TIP35_FLUSH */ #ifdef USE_TERMIOS /* *---------------------------------------------------------------------- * * TtyModemStatusStr -- * * Converts a RS232 modem status list of readable flags * *---------------------------------------------------------------------- */ static void TtyModemStatusStr(status, dsPtr) int status; /* RS232 modem status */ Tcl_DString *dsPtr; /* Where to store string */ { #ifdef TIOCM_CTS Tcl_DStringAppendElement(dsPtr, "CTS"); Tcl_DStringAppendElement(dsPtr, (status & TIOCM_CTS) ? "1" : "0"); #endif /* TIOCM_CTS */ #ifdef TIOCM_DSR Tcl_DStringAppendElement(dsPtr, "DSR"); Tcl_DStringAppendElement(dsPtr, (status & TIOCM_DSR) ? "1" : "0"); #endif /* TIOCM_DSR */ #ifdef TIOCM_RNG Tcl_DStringAppendElement(dsPtr, "RING"); Tcl_DStringAppendElement(dsPtr, (status & TIOCM_RNG) ? "1" : "0"); #endif /* TIOCM_RNG */ #ifdef TIOCM_CD Tcl_DStringAppendElement(dsPtr, "DCD"); Tcl_DStringAppendElement(dsPtr, (status & TIOCM_CD) ? "1" : "0"); #endif /* TIOCM_CD */ } #endif /* USE_TERMIOS */ /* *---------------------------------------------------------------------- * * TtySetOptionProc -- * * Sets an option on a channel. * * Results: * A standard Tcl result. Also sets the interp's result on error if * interp is not NULL. * * Side effects: * May modify an option on a device. * Sets Error message if needed (by calling Tcl_BadChannelOption). * *---------------------------------------------------------------------- */ static int TtySetOptionProc(instanceData, interp, optionName, value) ClientData instanceData; /* File state. */ Tcl_Interp *interp; /* For error reporting - can be NULL. */ CONST char *optionName; /* Which option to set? */ CONST char *value; /* New value for option. */ { FileState *fsPtr = (FileState *) instanceData; unsigned int len, vlen; TtyAttrs tty; #ifdef USE_TERMIOS int flag, control, argc; CONST char **argv; IOSTATE iostate; #endif /* USE_TERMIOS */ len = strlen(optionName); vlen = strlen(value); /* * Option -mode baud,parity,databits,stopbits */ if ((len > 2) && (strncmp(optionName, "-mode", len) == 0)) { if (TtyParseMode(interp, value, &tty.baud, &tty.parity, &tty.data, &tty.stop) != TCL_OK) { return TCL_ERROR; } /* * system calls results should be checked there. -- dl */ TtySetAttributes(fsPtr->fd, &tty); ((TtyState *) fsPtr)->stateUpdated = 1; return TCL_OK; } #ifdef USE_TERMIOS /* * Option -handshake none|xonxoff|rtscts|dtrdsr */ if ((len > 1) && (strncmp(optionName, "-handshake", len) == 0)) { /* * Reset all handshake options * DTR and RTS are ON by default */ GETIOSTATE(fsPtr->fd, &iostate); iostate.c_iflag &= ~(IXON | IXOFF | IXANY); #ifdef CRTSCTS iostate.c_cflag &= ~CRTSCTS; #endif /* CRTSCTS */ if (strncasecmp(value, "NONE", vlen) == 0) { /* leave all handshake options disabled */ } else if (strncasecmp(value, "XONXOFF", vlen) == 0) { iostate.c_iflag |= (IXON | IXOFF | IXANY); } else if (strncasecmp(value, "RTSCTS", vlen) == 0) { #ifdef CRTSCTS iostate.c_cflag |= CRTSCTS; #else /* !CRTSTS */ UNSUPPORTED_OPTION("-handshake RTSCTS"); return TCL_ERROR; #endif /* CRTSCTS */ } else if (strncasecmp(value, "DTRDSR", vlen) == 0) { UNSUPPORTED_OPTION("-handshake DTRDSR"); return TCL_ERROR; } else { if (interp) { Tcl_AppendResult(interp, "bad value for -handshake: ", "must be one of xonxoff, rtscts, dtrdsr or none", (char *) NULL); } return TCL_ERROR; } SETIOSTATE(fsPtr->fd, &iostate); return TCL_OK; } /* * Option -xchar {\x11 \x13} */ if ((len > 1) && (strncmp(optionName, "-xchar", len) == 0)) { GETIOSTATE(fsPtr->fd, &iostate); if (Tcl_SplitList(interp, value, &argc, &argv) == TCL_ERROR) { return TCL_ERROR; } if (argc == 2) { iostate.c_cc[VSTART] = argv[0][0]; iostate.c_cc[VSTOP] = argv[1][0]; } else { if (interp) { Tcl_AppendResult(interp, "bad value for -xchar: should be a list of two elements", (char *) NULL); } ckfree((char *) argv); return TCL_ERROR; } SETIOSTATE(fsPtr->fd, &iostate); ckfree((char *) argv); return TCL_OK; } /* * Option -timeout msec */ if ((len > 2) && (strncmp(optionName, "-timeout", len) == 0)) { int msec; GETIOSTATE(fsPtr->fd, &iostate); if (Tcl_GetInt(interp, value, &msec) != TCL_OK) { return TCL_ERROR; } iostate.c_cc[VMIN] = 0; iostate.c_cc[VTIME] = (msec == 0) ? 0 : (msec < 100) ? 1 : (msec+50)/100; SETIOSTATE(fsPtr->fd, &iostate); return TCL_OK; } /* * Option -ttycontrol {DTR 1 RTS 0 BREAK 0} */ if ((len > 4) && (strncmp(optionName, "-ttycontrol", len) == 0)) { int i; if (Tcl_SplitList(interp, value, &argc, &argv) == TCL_ERROR) { return TCL_ERROR; } if ((argc % 2) == 1) { if (interp) { Tcl_AppendResult(interp, "bad value for -ttycontrol: should be a list of", "signal,value pairs", (char *) NULL); } ckfree((char *) argv); return TCL_ERROR; } GETCONTROL(fsPtr->fd, &control); for (i = 0; i < argc-1; i += 2) { if (Tcl_GetBoolean(interp, argv[i+1], &flag) == TCL_ERROR) { ckfree((char *) argv); return TCL_ERROR; } if (strncasecmp(argv[i], "DTR", strlen(argv[i])) == 0) { #ifdef TIOCM_DTR if (flag) { control |= TIOCM_DTR; } else { control &= ~TIOCM_DTR; } #else /* !TIOCM_DTR */ UNSUPPORTED_OPTION("-ttycontrol DTR"); ckfree((char *) argv); return TCL_ERROR; #endif /* TIOCM_DTR */ } else if (strncasecmp(argv[i], "RTS", strlen(argv[i])) == 0) { #ifdef TIOCM_RTS if (flag) { control |= TIOCM_RTS; } else { control &= ~TIOCM_RTS; } #else /* !TIOCM_RTS*/ UNSUPPORTED_OPTION("-ttycontrol RTS"); ckfree((char *) argv); return TCL_ERROR; #endif /* TIOCM_RTS*/ } else if (strncasecmp(argv[i], "BREAK", strlen(argv[i])) == 0) { #ifdef SETBREAK SETBREAK(fsPtr->fd, flag); #else /* !SETBREAK */ UNSUPPORTED_OPTION("-ttycontrol BREAK"); ckfree((char *) argv); return TCL_ERROR; #endif /* SETBREAK */ } else { if (interp) { Tcl_AppendResult(interp, "bad signal \"", argv[i], "\" for -ttycontrol: must be ", "DTR, RTS or BREAK", (char *) NULL); } ckfree((char *) argv); return TCL_ERROR; } } /* -ttycontrol options loop */ SETCONTROL(fsPtr->fd, &control); ckfree((char *) argv); return TCL_OK; } return Tcl_BadChannelOption(interp, optionName, "mode handshake timeout ttycontrol xchar "); #else /* !USE_TERMIOS */ return Tcl_BadChannelOption(interp, optionName, "mode"); #endif /* USE_TERMIOS */ } /* *---------------------------------------------------------------------- * * TtyGetOptionProc -- * * Gets a mode associated with an IO channel. If the optionName arg * is non NULL, retrieves the value of that option. If the optionName * arg is NULL, retrieves a list of alternating option names and * values for the given channel. * * Results: * A standard Tcl result. Also sets the supplied DString to the * string value of the option(s) returned. * * Side effects: * The string returned by this function is in static storage and * may be reused at any time subsequent to the call. * Sets Error message if needed (by calling Tcl_BadChannelOption). * *---------------------------------------------------------------------- */ static int TtyGetOptionProc(instanceData, interp, optionName, dsPtr) ClientData instanceData; /* File state. */ Tcl_Interp *interp; /* For error reporting - can be NULL. */ CONST char *optionName; /* Option to get. */ Tcl_DString *dsPtr; /* Where to store value(s). */ { FileState *fsPtr = (FileState *) instanceData; unsigned int len; char buf[3 * TCL_INTEGER_SPACE + 16]; TtyAttrs tty; int valid = 0; /* flag if valid option parsed */ if (optionName == NULL) { len = 0; } else { len = strlen(optionName); } if (len == 0) { Tcl_DStringAppendElement(dsPtr, "-mode"); } if (len==0 || (len>2 && strncmp(optionName, "-mode", len)==0)) { valid = 1; TtyGetAttributes(fsPtr->fd, &tty); sprintf(buf, "%d,%c,%d,%d", tty.baud, tty.parity, tty.data, tty.stop); Tcl_DStringAppendElement(dsPtr, buf); } #ifdef USE_TERMIOS /* * get option -xchar */ if (len == 0) { Tcl_DStringAppendElement(dsPtr, "-xchar"); Tcl_DStringStartSublist(dsPtr); } if (len==0 || (len>1 && strncmp(optionName, "-xchar", len)==0)) { IOSTATE iostate; valid = 1; GETIOSTATE(fsPtr->fd, &iostate); sprintf(buf, "%c", iostate.c_cc[VSTART]); Tcl_DStringAppendElement(dsPtr, buf); sprintf(buf, "%c", iostate.c_cc[VSTOP]); Tcl_DStringAppendElement(dsPtr, buf); } if (len == 0) { Tcl_DStringEndSublist(dsPtr); } /* * get option -queue * option is readonly and returned by [fconfigure chan -queue] * but not returned by unnamed [fconfigure chan] */ if ((len > 1) && (strncmp(optionName, "-queue", len) == 0)) { int inQueue=0, outQueue=0; int inBuffered, outBuffered; valid = 1; #ifdef GETREADQUEUE GETREADQUEUE(fsPtr->fd, inQueue); #endif /* GETREADQUEUE */ #ifdef GETWRITEQUEUE GETWRITEQUEUE(fsPtr->fd, outQueue); #endif /* GETWRITEQUEUE */ inBuffered = Tcl_InputBuffered(fsPtr->channel); outBuffered = Tcl_OutputBuffered(fsPtr->channel); sprintf(buf, "%d", inBuffered+inQueue); Tcl_DStringAppendElement(dsPtr, buf); sprintf(buf, "%d", outBuffered+outQueue); Tcl_DStringAppendElement(dsPtr, buf); } /* * get option -ttystatus * option is readonly and returned by [fconfigure chan -ttystatus] * but not returned by unnamed [fconfigure chan] */ if ((len > 4) && (strncmp(optionName, "-ttystatus", len) == 0)) { int status; valid = 1; GETCONTROL(fsPtr->fd, &status); TtyModemStatusStr(status, dsPtr); } #endif /* USE_TERMIOS */ if (valid) { return TCL_OK; } else { return Tcl_BadChannelOption(interp, optionName, #ifdef USE_TERMIOS "mode queue ttystatus xchar"); #else /* !USE_TERMIOS */ "mode"); #endif /* USE_TERMIOS */ } } #undef DIRECT_BAUD #ifdef B4800 # if (B4800 == 4800) # define DIRECT_BAUD # endif /* B4800 == 4800 */ #endif /* B4800 */ #ifdef DIRECT_BAUD # define TtyGetSpeed(baud) ((unsigned) (baud)) # define TtyGetBaud(speed) ((int) (speed)) #else /* !DIRECT_BAUD */ static CONST struct {int baud; unsigned long speed;} speeds[] = { #ifdef B0 {0, B0}, #endif #ifdef B50 {50, B50}, #endif #ifdef B75 {75, B75}, #endif #ifdef B110 {110, B110}, #endif #ifdef B134 {134, B134}, #endif #ifdef B150 {150, B150}, #endif #ifdef B200 {200, B200}, #endif #ifdef B300 {300, B300}, #endif #ifdef B600 {600, B600}, #endif #ifdef B1200 {1200, B1200}, #endif #ifdef B1800 {1800, B1800}, #endif #ifdef B2400 {2400, B2400}, #endif #ifdef B4800 {4800, B4800}, #endif #ifdef B9600 {9600, B9600}, #endif #ifdef B14400 {14400, B14400}, #endif #ifdef B19200 {19200, B19200}, #endif #ifdef EXTA {19200, EXTA}, #endif #ifdef B28800 {28800, B28800}, #endif #ifdef B38400 {38400, B38400}, #endif #ifdef EXTB {38400, EXTB}, #endif #ifdef B57600 {57600, B57600}, #endif #ifdef _B57600 {57600, _B57600}, #endif #ifdef B76800 {76800, B76800}, #endif #ifdef B115200 {115200, B115200}, #endif #ifdef _B115200 {115200, _B115200}, #endif #ifdef B153600 {153600, B153600}, #endif #ifdef B230400 {230400, B230400}, #endif #ifdef B307200 {307200, B307200}, #endif #ifdef B460800 {460800, B460800}, #endif {-1, 0} }; /* *--------------------------------------------------------------------------- * * TtyGetSpeed -- * * Given a baud rate, get the mask value that should be stored in * the termios, termio, or sgttyb structure in order to select that * baud rate. * * Results: * As above. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static unsigned long TtyGetSpeed(baud) int baud; /* The baud rate to look up. */ { int bestIdx, bestDiff, i, diff; bestIdx = 0; bestDiff = 1000000; /* * If the baud rate does not correspond to one of the known mask values, * choose the mask value whose baud rate is closest to the specified * baud rate. */ for (i = 0; speeds[i].baud >= 0; i++) { diff = speeds[i].baud - baud; if (diff < 0) { diff = -diff; } if (diff < bestDiff) { bestIdx = i; bestDiff = diff; } } return speeds[bestIdx].speed; } /* *--------------------------------------------------------------------------- * * TtyGetBaud -- * * Given a speed mask value from a termios, termio, or sgttyb * structure, get the baus rate that corresponds to that mask value. * * Results: * As above. If the mask value was not recognized, 0 is returned. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int TtyGetBaud(speed) unsigned long speed; /* Speed mask value to look up. */ { int i; for (i = 0; speeds[i].baud >= 0; i++) { if (speeds[i].speed == speed) { return speeds[i].baud; } } return 0; } #endif /* !DIRECT_BAUD */ /* *--------------------------------------------------------------------------- * * TtyGetAttributes -- * * Get the current attributes of the specified serial device. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static void TtyGetAttributes(fd, ttyPtr) int fd; /* Open file descriptor for serial port to * be queried. */ TtyAttrs *ttyPtr; /* Buffer filled with serial port * attributes. */ { IOSTATE iostate; int baud, parity, data, stop; GETIOSTATE(fd, &iostate); #ifdef USE_TERMIOS baud = TtyGetBaud(cfgetospeed(&iostate)); parity = 'n'; #ifdef PAREXT switch ((int) (iostate.c_cflag & (PARENB | PARODD | PAREXT))) { case PARENB : parity = 'e'; break; case PARENB | PARODD : parity = 'o'; break; case PARENB | PAREXT : parity = 's'; break; case PARENB | PARODD | PAREXT : parity = 'm'; break; } #else /* !PAREXT */ switch ((int) (iostate.c_cflag & (PARENB | PARODD))) { case PARENB : parity = 'e'; break; case PARENB | PARODD : parity = 'o'; break; } #endif /* !PAREXT */ data = iostate.c_cflag & CSIZE; data = (data == CS5) ? 5 : (data == CS6) ? 6 : (data == CS7) ? 7 : 8; stop = (iostate.c_cflag & CSTOPB) ? 2 : 1; #endif /* USE_TERMIOS */ #ifdef USE_TERMIO baud = TtyGetBaud(iostate.c_cflag & CBAUD); parity = 'n'; switch (iostate.c_cflag & (PARENB | PARODD | PAREXT)) { case PARENB : parity = 'e'; break; case PARENB | PARODD : parity = 'o'; break; case PARENB | PAREXT : parity = 's'; break; case PARENB | PARODD | PAREXT : parity = 'm'; break; } data = iostate.c_cflag & CSIZE; data = (data == CS5) ? 5 : (data == CS6) ? 6 : (data == CS7) ? 7 : 8; stop = (iostate.c_cflag & CSTOPB) ? 2 : 1; #endif /* USE_TERMIO */ #ifdef USE_SGTTY baud = TtyGetBaud(iostate.sg_ospeed); parity = 'n'; if (iostate.sg_flags & EVENP) { parity = 'e'; } else if (iostate.sg_flags & ODDP) { parity = 'o'; } data = (iostate.sg_flags & (EVENP | ODDP)) ? 7 : 8; stop = 1; #endif /* USE_SGTTY */ ttyPtr->baud = baud; ttyPtr->parity = parity; ttyPtr->data = data; ttyPtr->stop = stop; } /* *--------------------------------------------------------------------------- * * TtySetAttributes -- * * Set the current attributes of the specified serial device. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static void TtySetAttributes(fd, ttyPtr) int fd; /* Open file descriptor for serial port to * be modified. */ TtyAttrs *ttyPtr; /* Buffer containing new attributes for * serial port. */ { IOSTATE iostate; #ifdef USE_TERMIOS int parity, data, flag; GETIOSTATE(fd, &iostate); cfsetospeed(&iostate, TtyGetSpeed(ttyPtr->baud)); cfsetispeed(&iostate, TtyGetSpeed(ttyPtr->baud)); flag = 0; parity = ttyPtr->parity; if (parity != 'n') { flag |= PARENB; #ifdef PAREXT iostate.c_cflag &= ~PAREXT; if ((parity == 'm') || (parity == 's')) { flag |= PAREXT; } #endif /* PAREXT */ if ((parity == 'm') || (parity == 'o')) { flag |= PARODD; } } data = ttyPtr->data; flag |= (data == 5) ? CS5 : (data == 6) ? CS6 : (data == 7) ? CS7 : CS8; if (ttyPtr->stop == 2) { flag |= CSTOPB; } iostate.c_cflag &= ~(PARENB | PARODD | CSIZE | CSTOPB); iostate.c_cflag |= flag; #endif /* USE_TERMIOS */ #ifdef USE_TERMIO int parity, data, flag; GETIOSTATE(fd, &iostate); iostate.c_cflag &= ~CBAUD; iostate.c_cflag |= TtyGetSpeed(ttyPtr->baud); flag = 0; parity = ttyPtr->parity; if (parity != 'n') { flag |= PARENB; if ((parity == 'm') || (parity == 's')) { flag |= PAREXT; } if ((parity == 'm') || (parity == 'o')) { flag |= PARODD; } } data = ttyPtr->data; flag |= (data == 5) ? CS5 : (data == 6) ? CS6 : (data == 7) ? CS7 : CS8; if (ttyPtr->stop == 2) { flag |= CSTOPB; } iostate.c_cflag &= ~(PARENB | PARODD | PAREXT | CSIZE | CSTOPB); iostate.c_cflag |= flag; #endif /* USE_TERMIO */ #ifdef USE_SGTTY int parity; GETIOSTATE(fd, &iostate); iostate.sg_ospeed = TtyGetSpeed(ttyPtr->baud); iostate.sg_ispeed = TtyGetSpeed(ttyPtr->baud); parity = ttyPtr->parity; if (parity == 'e') { iostate.sg_flags &= ~ODDP; iostate.sg_flags |= EVENP; } else if (parity == 'o') { iostate.sg_flags &= ~EVENP; iostate.sg_flags |= ODDP; } #endif /* USE_SGTTY */ SETIOSTATE(fd, &iostate); } /* *--------------------------------------------------------------------------- * * TtyParseMode -- * * Parse the "-mode" argument to the fconfigure command. The argument * is of the form baud,parity,data,stop. * * Results: * The return value is TCL_OK if the argument was successfully * parsed, TCL_ERROR otherwise. If TCL_ERROR is returned, an * error message is left in the interp's result (if interp is non-NULL). * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int TtyParseMode(interp, mode, speedPtr, parityPtr, dataPtr, stopPtr) Tcl_Interp *interp; /* If non-NULL, interp for error return. */ CONST char *mode; /* Mode string to be parsed. */ int *speedPtr; /* Filled with baud rate from mode string. */ int *parityPtr; /* Filled with parity from mode string. */ int *dataPtr; /* Filled with data bits from mode string. */ int *stopPtr; /* Filled with stop bits from mode string. */ { int i, end; char parity; static char *bad = "bad value for -mode"; i = sscanf(mode, "%d,%c,%d,%d%n", speedPtr, &parity, dataPtr, stopPtr, &end); if ((i != 4) || (mode[end] != '\0')) { if (interp != NULL) { Tcl_AppendResult(interp, bad, ": should be baud,parity,data,stop", NULL); } return TCL_ERROR; } /* * Only allow setting mark/space parity on platforms that support it * Make sure to allow for the case where strchr is a macro. * [Bug: 5089] */ if ( #if defined(PAREXT) || defined(USE_TERMIO) strchr("noems", parity) == NULL #else strchr("noe", parity) == NULL #endif /* PAREXT|USE_TERMIO */ ) { if (interp != NULL) { Tcl_AppendResult(interp, bad, #if defined(PAREXT) || defined(USE_TERMIO) " parity: should be n, o, e, m, or s", #else " parity: should be n, o, or e", #endif /* PAREXT|USE_TERMIO */ NULL); } return TCL_ERROR; } *parityPtr = parity; if ((*dataPtr < 5) || (*dataPtr > 8)) { if (interp != NULL) { Tcl_AppendResult(interp, bad, " data: should be 5, 6, 7, or 8", NULL); } return TCL_ERROR; } if ((*stopPtr < 0) || (*stopPtr > 2)) { if (interp != NULL) { Tcl_AppendResult(interp, bad, " stop: should be 1 or 2", NULL); } return TCL_ERROR; } return TCL_OK; } /* *--------------------------------------------------------------------------- * * TtyInit -- * * Given file descriptor that refers to a serial port, * initialize the serial port to a set of sane values so that * Tcl can talk to a device located on the serial port. * Note that no initialization happens if the initialize flag * is not set; this is necessary for the correct handling of * UNIX console TTYs at startup. * * Results: * A pointer to a FileState suitable for use with Tcl_CreateChannel * and the ttyChannelType structure. * * Side effects: * Serial device initialized to non-blocking raw mode, similar to * sockets (if initialize flag is non-zero.) All other modes can * be simulated on top of this in Tcl. * *--------------------------------------------------------------------------- */ static FileState * TtyInit(fd, initialize) int fd; /* Open file descriptor for serial port to * be initialized. */ int initialize; { TtyState *ttyPtr; ttyPtr = (TtyState *) ckalloc((unsigned) sizeof(TtyState)); GETIOSTATE(fd, &ttyPtr->savedState); ttyPtr->stateUpdated = 0; if (initialize) { IOSTATE iostate = ttyPtr->savedState; #if defined(USE_TERMIOS) || defined(USE_TERMIO) if (iostate.c_iflag != IGNBRK || iostate.c_oflag != 0 || iostate.c_lflag != 0 || iostate.c_cflag & CREAD || iostate.c_cc[VMIN] != 1 || iostate.c_cc[VTIME] != 0) { ttyPtr->stateUpdated = 1; } iostate.c_iflag = IGNBRK; iostate.c_oflag = 0; iostate.c_lflag = 0; iostate.c_cflag |= CREAD; iostate.c_cc[VMIN] = 1; iostate.c_cc[VTIME] = 0; #endif /* USE_TERMIOS|USE_TERMIO */ #ifdef USE_SGTTY if ((iostate.sg_flags & (EVENP | ODDP)) || !(iostate.sg_flags & RAW)) { ttyPtr->stateUpdated = 1; } iostate.sg_flags &= (EVENP | ODDP); iostate.sg_flags |= RAW; #endif /* USE_SGTTY */ /* * Only update if we're changing anything to avoid possible * blocking. */ if (ttyPtr->stateUpdated) { SETIOSTATE(fd, &iostate); } } return &ttyPtr->fs; } #endif /* SUPPORTS_TTY */ /* *---------------------------------------------------------------------- * * TclpOpenFileChannel -- * * Open an file based channel on Unix systems. * * Results: * The new channel or NULL. If NULL, the output argument * errorCodePtr is set to a POSIX error and an error message is * left in the interp's result if interp is not NULL. * * Side effects: * May open the channel and may cause creation of a file on the * file system. * *---------------------------------------------------------------------- */ Tcl_Channel TclpOpenFileChannel(interp, pathPtr, mode, permissions) Tcl_Interp *interp; /* Interpreter for error reporting; * can be NULL. */ Tcl_Obj *pathPtr; /* Name of file to open. */ int mode; /* POSIX open mode. */ int permissions; /* If the open involves creating a * file, with what modes to create * it? */ { int fd, channelPermissions; FileState *fsPtr; CONST char *native, *translation; char channelName[16 + TCL_INTEGER_SPACE]; Tcl_ChannelType *channelTypePtr; #ifdef SUPPORTS_TTY int ctl_tty; #endif /* SUPPORTS_TTY */ #ifdef DEPRECATED ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); #endif /* DEPRECATED */ switch (mode & (O_RDONLY | O_WRONLY | O_RDWR)) { case O_RDONLY: channelPermissions = TCL_READABLE; break; case O_WRONLY: channelPermissions = TCL_WRITABLE; break; case O_RDWR: channelPermissions = (TCL_READABLE | TCL_WRITABLE); break; default: /* * This may occurr if modeString was "", for example. */ panic("TclpOpenFileChannel: invalid mode value"); return NULL; } native = Tcl_FSGetNativePath(pathPtr); if (native == NULL) { return NULL; } fd = TclOSopen(native, mode, permissions); #ifdef SUPPORTS_TTY ctl_tty = (strcmp (native, "/dev/tty") == 0); #endif /* SUPPORTS_TTY */ if (fd < 0) { if (interp != (Tcl_Interp *) NULL) { Tcl_AppendResult(interp, "couldn't open \"", Tcl_GetString(pathPtr), "\": ", Tcl_PosixError(interp), (char *) NULL); } return NULL; } /* * Set close-on-exec flag on the fd so that child processes will not * inherit this fd. */ fcntl(fd, F_SETFD, FD_CLOEXEC); sprintf(channelName, "file%d", fd); #ifdef SUPPORTS_TTY if (!ctl_tty && isatty(fd)) { /* * Initialize the serial port to a set of sane parameters. * Especially important if the remote device is set to echo and * the serial port driver was also set to echo -- as soon as a char * were sent to the serial port, the remote device would echo it, * then the serial driver would echo it back to the device, etc. */ translation = "auto crlf"; channelTypePtr = &ttyChannelType; fsPtr = TtyInit(fd, 1); } else #endif /* SUPPORTS_TTY */ { translation = NULL; channelTypePtr = &fileChannelType; fsPtr = (FileState *) ckalloc((unsigned) sizeof(FileState)); } #ifdef DEPRECATED if (channelTypePtr == &fileChannelType) { /* TIP #218. Removed the code inserting the new structure * into the global list. This is now handled in the thread * action callbacks, and only there. */ fsPtr->nextPtr = NULL; } #endif /* DEPRECATED */ fsPtr->validMask = channelPermissions | TCL_EXCEPTION; fsPtr->fd = fd; fsPtr->channel = Tcl_CreateChannel(channelTypePtr, channelName, (ClientData) fsPtr, channelPermissions); if (translation != NULL) { /* * Gotcha. Most modems need a "\r" at the end of the command * sequence. If you just send "at\n", the modem will not respond * with "OK" because it never got a "\r" to actually invoke the * command. So, by default, newlines are translated to "\r\n" on * output to avoid "bug" reports that the serial port isn't working. */ if (Tcl_SetChannelOption(interp, fsPtr->channel, "-translation", translation) != TCL_OK) { Tcl_Close(NULL, fsPtr->channel); return NULL; } } return fsPtr->channel; } /* *---------------------------------------------------------------------- * * Tcl_MakeFileChannel -- * * Makes a Tcl_Channel from an existing OS level file handle. * * Results: * The Tcl_Channel created around the preexisting OS level file handle. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_Channel Tcl_MakeFileChannel(handle, mode) ClientData handle; /* OS level handle. */ int mode; /* ORed combination of TCL_READABLE and * TCL_WRITABLE to indicate file mode. */ { FileState *fsPtr; char channelName[16 + TCL_INTEGER_SPACE]; int fd = (int) handle; Tcl_ChannelType *channelTypePtr; #ifdef DEPRECATED ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); #endif /* DEPRECATED */ struct sockaddr sockaddr; socklen_t sockaddrLen = sizeof(sockaddr); if (mode == 0) { return NULL; } /* * Look to see if a channel with this fd and the same mode already exists. * If the fd is used, but the mode doesn't match, return NULL. */ #ifdef DEPRECATED for (fsPtr = tsdPtr->firstFilePtr; fsPtr != NULL; fsPtr = fsPtr->nextPtr) { if (fsPtr->fd == fd) { return ((mode|TCL_EXCEPTION) == fsPtr->validMask) ? fsPtr->channel : NULL; } } #endif /* DEPRECATED */ sockaddr.sa_family = AF_UNSPEC; #ifdef SUPPORTS_TTY if (isatty(fd)) { fsPtr = TtyInit(fd, 0); channelTypePtr = &ttyChannelType; sprintf(channelName, "serial%d", fd); } else #endif /* SUPPORTS_TTY */ if (getsockname(fd, (struct sockaddr *)&sockaddr, &sockaddrLen) == 0 && sockaddrLen > 0 && sockaddr.sa_family == AF_INET) { return MakeTcpClientChannelMode((ClientData) fd, mode); } else { channelTypePtr = &fileChannelType; fsPtr = (FileState *) ckalloc((unsigned) sizeof(FileState)); sprintf(channelName, "file%d", fd); } #ifdef DEPRECATED if (channelTypePtr == &fileChannelType) { fsPtr->nextPtr = tsdPtr->firstFilePtr; tsdPtr->firstFilePtr = fsPtr; } #endif /* DEPRECATED */ fsPtr->fd = fd; fsPtr->validMask = mode | TCL_EXCEPTION; fsPtr->channel = Tcl_CreateChannel(channelTypePtr, channelName, (ClientData) fsPtr, mode); return fsPtr->channel; } /* *---------------------------------------------------------------------- * * TcpBlockModeProc -- * * This procedure is invoked by the generic IO level to set blocking * and nonblocking mode on a TCP socket based channel. * * Results: * 0 if successful, errno when failed. * * Side effects: * Sets the device into blocking or nonblocking mode. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int TcpBlockModeProc(instanceData, mode) ClientData instanceData; /* Socket state. */ int mode; /* The mode to set. Can be one of * TCL_MODE_BLOCKING or * TCL_MODE_NONBLOCKING. */ { TcpState *statePtr = (TcpState *) instanceData; int setting; #ifndef USE_FIONBIO setting = fcntl(statePtr->fd, F_GETFL); if (mode == TCL_MODE_BLOCKING) { statePtr->flags &= (~(TCP_ASYNC_SOCKET)); setting &= (~(O_NONBLOCK)); } else { statePtr->flags |= TCP_ASYNC_SOCKET; setting |= O_NONBLOCK; } if (fcntl(statePtr->fd, F_SETFL, setting) < 0) { return errno; } #else /* USE_FIONBIO */ if (mode == TCL_MODE_BLOCKING) { statePtr->flags &= (~(TCP_ASYNC_SOCKET)); setting = 0; if (ioctl(statePtr->fd, (int) FIONBIO, &setting) == -1) { return errno; } } else { statePtr->flags |= TCP_ASYNC_SOCKET; setting = 1; if (ioctl(statePtr->fd, (int) FIONBIO, &setting) == -1) { return errno; } } #endif /* !USE_FIONBIO */ return 0; } /* *---------------------------------------------------------------------- * * WaitForConnect -- * * Waits for a connection on an asynchronously opened socket to * be completed. * * Results: * None. * * Side effects: * The socket is connected after this function returns. * *---------------------------------------------------------------------- */ static int WaitForConnect(statePtr, errorCodePtr) TcpState *statePtr; /* State of the socket. */ int *errorCodePtr; /* Where to store errors? */ { int timeOut; /* How long to wait. */ int state; /* Of calling TclWaitForFile. */ int flags; /* fcntl flags for the socket. */ /* * If an asynchronous connect is in progress, attempt to wait for it * to complete before reading. */ if (statePtr->flags & TCP_ASYNC_CONNECT) { if (statePtr->flags & TCP_ASYNC_SOCKET) { timeOut = 0; } else { timeOut = -1; } errno = 0; state = TclUnixWaitForFile(statePtr->fd, TCL_WRITABLE | TCL_EXCEPTION, timeOut); if (!(statePtr->flags & TCP_ASYNC_SOCKET)) { #ifndef USE_FIONBIO flags = fcntl(statePtr->fd, F_GETFL); flags &= (~(O_NONBLOCK)); (void) fcntl(statePtr->fd, F_SETFL, flags); #else /* USE_FIONBIO */ flags = 0; (void) ioctl(statePtr->fd, FIONBIO, &flags); #endif /* !USE_FIONBIO */ } if (state & TCL_EXCEPTION) { return -1; } if (state & TCL_WRITABLE) { statePtr->flags &= (~(TCP_ASYNC_CONNECT)); } else if (timeOut == 0) { *errorCodePtr = errno = EWOULDBLOCK; return -1; } } return 0; } /* *---------------------------------------------------------------------- * * TcpInputProc -- * * This procedure is invoked by the generic IO level to read input * from a TCP socket based channel. * * NOTE: We cannot share code with FilePipeInputProc because here * we must use recv to obtain the input from the channel, not read. * * Results: * The number of bytes read is returned or -1 on error. An output * argument contains the POSIX error code on error, or zero if no * error occurred. * * Side effects: * Reads input from the input device of the channel. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int TcpInputProc(instanceData, buf, bufSize, errorCodePtr) ClientData instanceData; /* Socket state. */ char *buf; /* Where to store data read. */ int bufSize; /* How much space is available * in the buffer? */ int *errorCodePtr; /* Where to store error code. */ { TcpState *statePtr = (TcpState *) instanceData; int bytesRead, state; *errorCodePtr = 0; state = WaitForConnect(statePtr, errorCodePtr); if (state != 0) { return -1; } bytesRead = recv(statePtr->fd, buf, (size_t) bufSize, 0); if (bytesRead > -1) { return bytesRead; } if (errno == ECONNRESET) { /* * Turn ECONNRESET into a soft EOF condition. */ return 0; } *errorCodePtr = errno; return -1; } /* *---------------------------------------------------------------------- * * TcpOutputProc -- * * This procedure is invoked by the generic IO level to write output * to a TCP socket based channel. * * NOTE: We cannot share code with FilePipeOutputProc because here * we must use send, not write, to get reliable error reporting. * * Results: * The number of bytes written is returned. An output argument is * set to a POSIX error code if an error occurred, or zero. * * Side effects: * Writes output on the output device of the channel. * *---------------------------------------------------------------------- */ static int TcpOutputProc(instanceData, buf, toWrite, errorCodePtr) ClientData instanceData; /* Socket state. */ CONST char *buf; /* The data buffer. */ int toWrite; /* How many bytes to write? */ int *errorCodePtr; /* Where to store error code. */ { TcpState *statePtr = (TcpState *) instanceData; int written; int state; /* Of waiting for connection. */ *errorCodePtr = 0; state = WaitForConnect(statePtr, errorCodePtr); if (state != 0) { return -1; } written = send(statePtr->fd, buf, (size_t) toWrite, 0); if (written > -1) { return written; } *errorCodePtr = errno; return -1; } /* *---------------------------------------------------------------------- * * TcpCloseProc -- * * This procedure is invoked by the generic IO level to perform * channel-type-specific cleanup when a TCP socket based channel * is closed. * * Results: * 0 if successful, the value of errno if failed. * * Side effects: * Closes the socket of the channel. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int TcpCloseProc(instanceData, interp) ClientData instanceData; /* The socket to close. */ Tcl_Interp *interp; /* For error reporting - unused. */ { TcpState *statePtr = (TcpState *) instanceData; int errorCode = 0; /* * Delete a file handler that may be active for this socket if this * is a server socket - the file handler was created automatically * by Tcl as part of the mechanism to accept new client connections. * Channel handlers are already deleted in the generic IO channel * closing code that called this function, so we do not have to * delete them here. */ Tcl_DeleteFileHandler(statePtr->fd); if (close(statePtr->fd) < 0) { errorCode = errno; } ckfree((char *) statePtr); return errorCode; } /* *---------------------------------------------------------------------- * * TcpGetOptionProc -- * * Computes an option value for a TCP socket based channel, or a * list of all options and their values. * * Note: This code is based on code contributed by John Haxby. * * Results: * A standard Tcl result. The value of the specified option or a * list of all options and their values is returned in the * supplied DString. Sets Error message if needed. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TcpGetOptionProc(instanceData, interp, optionName, dsPtr) ClientData instanceData; /* Socket state. */ Tcl_Interp *interp; /* For error reporting - can be NULL. */ CONST char *optionName; /* Name of the option to * retrieve the value for, or * NULL to get all options and * their values. */ Tcl_DString *dsPtr; /* Where to store the computed * value; initialized by caller. */ { TcpState *statePtr = (TcpState *) instanceData; struct sockaddr_in sockname; struct sockaddr_in peername; struct hostent *hostEntPtr; socklen_t size = sizeof(struct sockaddr_in); size_t len = 0; char buf[TCL_INTEGER_SPACE]; if (optionName != (char *) NULL) { len = strlen(optionName); } if ((len > 1) && (optionName[1] == 'e') && (strncmp(optionName, "-error", len) == 0)) { socklen_t optlen = sizeof(int); int err, ret; ret = getsockopt(statePtr->fd, SOL_SOCKET, SO_ERROR, (char *)&err, &optlen); if (ret < 0) { err = errno; } if (err != 0) { Tcl_DStringAppend(dsPtr, Tcl_ErrnoMsg(err), -1); } return TCL_OK; } if ((len == 0) || ((len > 1) && (optionName[1] == 'p') && (strncmp(optionName, "-peername", len) == 0))) { if (getpeername(statePtr->fd, (struct sockaddr *) &peername, &size) >= 0) { if (len == 0) { Tcl_DStringAppendElement(dsPtr, "-peername"); Tcl_DStringStartSublist(dsPtr); } Tcl_DStringAppendElement(dsPtr, inet_ntoa(peername.sin_addr)); hostEntPtr = TclpGetHostByAddr( /* INTL: Native. */ (char *) &peername.sin_addr, sizeof(peername.sin_addr), AF_INET); if (hostEntPtr != (struct hostent *) NULL) { Tcl_DString ds; Tcl_ExternalToUtfDString(NULL, hostEntPtr->h_name, -1, &ds); Tcl_DStringAppendElement(dsPtr, Tcl_DStringValue(&ds)); Tcl_DStringFree(&ds); } else { Tcl_DStringAppendElement(dsPtr, inet_ntoa(peername.sin_addr)); } TclFormatInt(buf, ntohs(peername.sin_port)); Tcl_DStringAppendElement(dsPtr, buf); if (len == 0) { Tcl_DStringEndSublist(dsPtr); } else { return TCL_OK; } } else { /* * getpeername failed - but if we were asked for all the options * (len==0), don't flag an error at that point because it could * be an fconfigure request on a server socket. (which have * no peer). same must be done on win&mac. */ if (len) { if (interp) { Tcl_AppendResult(interp, "can't get peername: ", Tcl_PosixError(interp), (char *) NULL); } return TCL_ERROR; } } } if ((len == 0) || ((len > 1) && (optionName[1] == 's') && (strncmp(optionName, "-sockname", len) == 0))) { if (getsockname(statePtr->fd, (struct sockaddr *) &sockname, &size) >= 0) { if (len == 0) { Tcl_DStringAppendElement(dsPtr, "-sockname"); Tcl_DStringStartSublist(dsPtr); } Tcl_DStringAppendElement(dsPtr, inet_ntoa(sockname.sin_addr)); if (sockname.sin_addr.s_addr == INADDR_ANY) { /* * We don't want to resolve INADDR_ANY; it can sometimes cause * problems (and never has a name). */ hostEntPtr = NULL; } else { hostEntPtr = TclpGetHostByAddr( /* INTL: Native. */ (char *) &sockname.sin_addr, sizeof(sockname.sin_addr), AF_INET); } if (hostEntPtr != (struct hostent *) NULL) { Tcl_DString ds; Tcl_ExternalToUtfDString(NULL, hostEntPtr->h_name, -1, &ds); Tcl_DStringAppendElement(dsPtr, Tcl_DStringValue(&ds)); Tcl_DStringFree(&ds); } else { Tcl_DStringAppendElement(dsPtr, inet_ntoa(sockname.sin_addr)); } TclFormatInt(buf, ntohs(sockname.sin_port)); Tcl_DStringAppendElement(dsPtr, buf); if (len == 0) { Tcl_DStringEndSublist(dsPtr); } else { return TCL_OK; } } else { if (interp) { Tcl_AppendResult(interp, "can't get sockname: ", Tcl_PosixError(interp), (char *) NULL); } return TCL_ERROR; } } if (len > 0) { return Tcl_BadChannelOption(interp, optionName, "peername sockname"); } return TCL_OK; } /* *---------------------------------------------------------------------- * * TcpWatchProc -- * * Initialize the notifier to watch the fd from this channel. * * Results: * None. * * Side effects: * Sets up the notifier so that a future event on the channel will * be seen by Tcl. * *---------------------------------------------------------------------- */ static void TcpWatchProc(instanceData, mask) ClientData instanceData; /* The socket state. */ int mask; /* Events of interest; an OR-ed * combination of TCL_READABLE, * TCL_WRITABLE and TCL_EXCEPTION. */ { TcpState *statePtr = (TcpState *) instanceData; /* * Make sure we don't mess with server sockets since they will never * be readable or writable at the Tcl level. This keeps Tcl scripts * from interfering with the -accept behavior. */ if (!statePtr->acceptProc) { if (mask) { Tcl_CreateFileHandler(statePtr->fd, mask, (Tcl_FileProc *) Tcl_NotifyChannel, (ClientData) statePtr->channel); } else { Tcl_DeleteFileHandler(statePtr->fd); } } } /* *---------------------------------------------------------------------- * * TcpGetHandleProc -- * * Called from Tcl_GetChannelHandle to retrieve OS handles from inside * a TCP socket based channel. * * Results: * Returns TCL_OK with the fd in handlePtr, or TCL_ERROR if * there is no handle for the specified direction. * * Side effects: * None. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int TcpGetHandleProc(instanceData, direction, handlePtr) ClientData instanceData; /* The socket state. */ int direction; /* Not used. */ ClientData *handlePtr; /* Where to store the handle. */ { TcpState *statePtr = (TcpState *) instanceData; *handlePtr = (ClientData)statePtr->fd; return TCL_OK; } /* *---------------------------------------------------------------------- * * CreateSocket -- * * This function opens a new socket in client or server mode * and initializes the TcpState structure. * * Results: * Returns a new TcpState, or NULL with an error in the interp's * result, if interp is not NULL. * * Side effects: * Opens a socket. * *---------------------------------------------------------------------- */ static TcpState * CreateSocket(interp, port, host, server, myaddr, myport, async) Tcl_Interp *interp; /* For error reporting; can be NULL. */ int port; /* Port number to open. */ CONST char *host; /* Name of host on which to open port. * NULL implies INADDR_ANY */ int server; /* 1 if socket should be a server socket, * else 0 for a client socket. */ CONST char *myaddr; /* Optional client-side address */ int myport; /* Optional client-side port */ int async; /* If nonzero and creating a client socket, * attempt to do an async connect. Otherwise * do a synchronous connect or bind. */ { int status, sock, asyncConnect, curState, origState; struct sockaddr_in sockaddr; /* socket address */ struct sockaddr_in mysockaddr; /* Socket address for client */ TcpState *statePtr; sock = -1; origState = 0; if (! CreateSocketAddress(&sockaddr, host, port)) { goto addressError; } if ((myaddr != NULL || myport != 0) && ! CreateSocketAddress(&mysockaddr, myaddr, myport)) { goto addressError; } sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { goto addressError; } /* * Set the close-on-exec flag so that the socket will not get * inherited by child processes. */ fcntl(sock, F_SETFD, FD_CLOEXEC); /* * Set kernel space buffering */ TclSockMinimumBuffers(sock, SOCKET_BUFSIZE); asyncConnect = 0; status = 0; if (server) { /* * Set up to reuse server addresses automatically and bind to the * specified port. */ status = 1; (void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &status, sizeof(status)); status = bind(sock, (struct sockaddr *) &sockaddr, sizeof(struct sockaddr)); if (status != -1) { status = listen(sock, SOMAXCONN); } } else { if (myaddr != NULL || myport != 0) { curState = 1; (void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &curState, sizeof(curState)); status = bind(sock, (struct sockaddr *) &mysockaddr, sizeof(struct sockaddr)); if (status < 0) { goto bindError; } } /* * Attempt to connect. The connect may fail at present with an * EINPROGRESS but at a later time it will complete. The caller * will set up a file handler on the socket if she is interested in * being informed when the connect completes. */ if (async) { #ifndef USE_FIONBIO origState = fcntl(sock, F_GETFL); curState = origState | O_NONBLOCK; status = fcntl(sock, F_SETFL, curState); #else /* USE_FIONBIO */ curState = 1; status = ioctl(sock, FIONBIO, &curState); #endif /* !USE_FIONBIO */ } else { status = 0; } if (status > -1) { status = connect(sock, (struct sockaddr *) &sockaddr, sizeof(sockaddr)); if (status < 0) { if (errno == EINPROGRESS) { asyncConnect = 1; status = 0; } } else { /* * Here we are if the connect succeeds. In case of an * asynchronous connect we have to reset the channel to * blocking mode. This appears to happen not very often, * but e.g. on a HP 9000/800 under HP-UX B.11.00 we enter * this stage. [Bug: 4388] */ if (async) { #ifndef USE_FIONBIO origState = fcntl(sock, F_GETFL); curState = origState & ~(O_NONBLOCK); status = fcntl(sock, F_SETFL, curState); #else /* USE_FIONBIO */ curState = 0; status = ioctl(sock, FIONBIO, &curState); #endif /* !USE_FIONBIO */ } } } } bindError: if (status < 0) { if (interp != NULL) { Tcl_AppendResult(interp, "couldn't open socket: ", Tcl_PosixError(interp), (char *) NULL); } if (sock != -1) { close(sock); } return NULL; } /* * Allocate a new TcpState for this socket. */ statePtr = (TcpState *) ckalloc((unsigned) sizeof(TcpState)); statePtr->flags = 0; if (asyncConnect) { statePtr->flags = TCP_ASYNC_CONNECT; } statePtr->fd = sock; return statePtr; addressError: if (sock != -1) { close(sock); } if (interp != NULL) { Tcl_AppendResult(interp, "couldn't open socket: ", Tcl_PosixError(interp), (char *) NULL); } return NULL; } /* *---------------------------------------------------------------------- * * CreateSocketAddress -- * * This function initializes a sockaddr structure for a host and port. * * Results: * 1 if the host was valid, 0 if the host could not be converted to * an IP address. * * Side effects: * Fills in the *sockaddrPtr structure. * *---------------------------------------------------------------------- */ static int CreateSocketAddress(sockaddrPtr, host, port) struct sockaddr_in *sockaddrPtr; /* Socket address */ CONST char *host; /* Host. NULL implies INADDR_ANY */ int port; /* Port number */ { struct hostent *hostent; /* Host database entry */ struct in_addr addr; /* For 64/32 bit madness */ (void) memset((VOID *) sockaddrPtr, '\0', sizeof(struct sockaddr_in)); sockaddrPtr->sin_family = AF_INET; sockaddrPtr->sin_port = htons((unsigned short) (port & 0xFFFF)); if (host == NULL) { addr.s_addr = INADDR_ANY; } else { Tcl_DString ds; CONST char *native; if (host == NULL) { native = NULL; } else { native = Tcl_UtfToExternalDString(NULL, host, -1, &ds); } addr.s_addr = inet_addr(native); /* INTL: Native. */ /* * This is 0xFFFFFFFF to ensure that it compares as a 32bit -1 * on either 32 or 64 bits systems. */ if (addr.s_addr == 0xFFFFFFFF) { hostent = TclpGetHostByName(native); /* INTL: Native. */ if (hostent != (struct hostent *) NULL) { memcpy((VOID *) &addr, (VOID *) hostent->h_addr_list[0], (size_t) hostent->h_length); } else { #ifdef EHOSTUNREACH errno = EHOSTUNREACH; #else /* !EHOSTUNREACH */ #ifdef ENXIO errno = ENXIO; #endif /* ENXIO */ #endif /* EHOSTUNREACH */ if (native != NULL) { Tcl_DStringFree(&ds); } return 0; /* error */ } } if (native != NULL) { Tcl_DStringFree(&ds); } } /* * NOTE: On 64 bit machines the assignment below is rumored to not * do the right thing. Please report errors related to this if you * observe incorrect behavior on 64 bit machines such as DEC Alphas. * Should we modify this code to do an explicit memcpy? */ sockaddrPtr->sin_addr.s_addr = addr.s_addr; return 1; /* Success. */ } /* *---------------------------------------------------------------------- * * Tcl_OpenTcpClient -- * * Opens a TCP client socket and creates a channel around it. * * Results: * The channel or NULL if failed. An error message is returned * in the interpreter on failure. * * Side effects: * Opens a client socket and creates a new channel. * *---------------------------------------------------------------------- */ Tcl_Channel Tcl_OpenTcpClient(interp, port, host, myaddr, myport, async) Tcl_Interp *interp; /* For error reporting; can be NULL. */ int port; /* Port number to open. */ CONST char *host; /* Host on which to open port. */ CONST char *myaddr; /* Client-side address */ int myport; /* Client-side port */ int async; /* If nonzero, attempt to do an * asynchronous connect. Otherwise * we do a blocking connect. */ { TcpState *statePtr; char channelName[16 + TCL_INTEGER_SPACE]; /* * Create a new client socket and wrap it in a channel. */ statePtr = CreateSocket(interp, port, host, 0, myaddr, myport, async); if (statePtr == NULL) { return NULL; } statePtr->acceptProc = NULL; statePtr->acceptProcData = (ClientData) NULL; sprintf(channelName, "sock%d", statePtr->fd); statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, (ClientData) statePtr, (TCL_READABLE | TCL_WRITABLE)); if (Tcl_SetChannelOption(interp, statePtr->channel, "-translation", "auto crlf") == TCL_ERROR) { Tcl_Close((Tcl_Interp *) NULL, statePtr->channel); return NULL; } return statePtr->channel; } /* *---------------------------------------------------------------------- * * Tcl_MakeTcpClientChannel -- * * Creates a Tcl_Channel from an existing client TCP socket. * * Results: * The Tcl_Channel wrapped around the preexisting TCP socket. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_Channel Tcl_MakeTcpClientChannel(sock) ClientData sock; /* The socket to wrap up into a channel. */ { return MakeTcpClientChannelMode(sock, (TCL_READABLE | TCL_WRITABLE)); } /* *---------------------------------------------------------------------- * * MakeTcpClientChannelMode -- * * Creates a Tcl_Channel from an existing client TCP socket * with given mode. * * Results: * The Tcl_Channel wrapped around the preexisting TCP socket. * * Side effects: * None. * *---------------------------------------------------------------------- */ static Tcl_Channel MakeTcpClientChannelMode(sock, mode) ClientData sock; /* The socket to wrap up into a channel. */ int mode; /* ORed combination of TCL_READABLE and * TCL_WRITABLE to indicate file mode. */ { TcpState *statePtr; char channelName[16 + TCL_INTEGER_SPACE]; statePtr = (TcpState *) ckalloc((unsigned) sizeof(TcpState)); statePtr->fd = (int) sock; statePtr->flags = 0; statePtr->acceptProc = NULL; statePtr->acceptProcData = (ClientData) NULL; sprintf(channelName, "sock%d", statePtr->fd); statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, (ClientData) statePtr, mode); if (Tcl_SetChannelOption((Tcl_Interp *) NULL, statePtr->channel, "-translation", "auto crlf") == TCL_ERROR) { Tcl_Close((Tcl_Interp *) NULL, statePtr->channel); return NULL; } return statePtr->channel; } /* *---------------------------------------------------------------------- * * Tcl_OpenTcpServer -- * * Opens a TCP server socket and creates a channel around it. * * Results: * The channel or NULL if failed. If an error occurred, an * error message is left in the interp's result if interp is * not NULL. * * Side effects: * Opens a server socket and creates a new channel. * *---------------------------------------------------------------------- */ Tcl_Channel Tcl_OpenTcpServer(interp, port, myHost, acceptProc, acceptProcData) Tcl_Interp *interp; /* For error reporting - may be * NULL. */ int port; /* Port number to open. */ CONST char *myHost; /* Name of local host. */ Tcl_TcpAcceptProc *acceptProc; /* Callback for accepting connections * from new clients. */ ClientData acceptProcData; /* Data for the callback. */ { TcpState *statePtr; char channelName[16 + TCL_INTEGER_SPACE]; /* * Create a new client socket and wrap it in a channel. */ statePtr = CreateSocket(interp, port, myHost, 1, NULL, 0, 0); if (statePtr == NULL) { return NULL; } statePtr->acceptProc = acceptProc; statePtr->acceptProcData = acceptProcData; /* * Set up the callback mechanism for accepting connections * from new clients. */ Tcl_CreateFileHandler(statePtr->fd, TCL_READABLE, TcpAccept, (ClientData) statePtr); sprintf(channelName, "sock%d", statePtr->fd); statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, (ClientData) statePtr, 0); return statePtr->channel; } /* *---------------------------------------------------------------------- * * TcpAccept -- * Accept a TCP socket connection. This is called by the event loop. * * Results: * None. * * Side effects: * Creates a new connection socket. Calls the registered callback * for the connection acceptance mechanism. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static void TcpAccept(data, mask) ClientData data; /* Callback token. */ int mask; /* Not used. */ { TcpState *sockState; /* Client data of server socket. */ int newsock; /* The new client socket */ TcpState *newSockState; /* State for new socket. */ struct sockaddr_in addr; /* The remote address */ socklen_t len; /* For accept interface */ char channelName[16 + TCL_INTEGER_SPACE]; sockState = (TcpState *) data; len = sizeof(struct sockaddr_in); newsock = accept(sockState->fd, (struct sockaddr *) &addr, &len); if (newsock < 0) { return; } /* * Set close-on-exec flag to prevent the newly accepted socket from * being inherited by child processes. */ (void) fcntl(newsock, F_SETFD, FD_CLOEXEC); newSockState = (TcpState *) ckalloc((unsigned) sizeof(TcpState)); newSockState->flags = 0; newSockState->fd = newsock; newSockState->acceptProc = NULL; newSockState->acceptProcData = NULL; sprintf(channelName, "sock%d", newsock); newSockState->channel = Tcl_CreateChannel(&tcpChannelType, channelName, (ClientData) newSockState, (TCL_READABLE | TCL_WRITABLE)); Tcl_SetChannelOption(NULL, newSockState->channel, "-translation", "auto crlf"); if (sockState->acceptProc != NULL) { (*sockState->acceptProc)(sockState->acceptProcData, newSockState->channel, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); } } /* *---------------------------------------------------------------------- * * TclpGetDefaultStdChannel -- * * Creates channels for standard input, standard output or standard * error output if they do not already exist. * * Results: * Returns the specified default standard channel, or NULL. * * Side effects: * May cause the creation of a standard channel and the underlying * file. * *---------------------------------------------------------------------- */ Tcl_Channel TclpGetDefaultStdChannel(type) int type; /* One of TCL_STDIN, TCL_STDOUT, TCL_STDERR. */ { Tcl_Channel channel = NULL; int fd = 0; /* Initializations needed to prevent */ int mode = 0; /* compiler warning (used before set). */ char *bufMode = NULL; /* * Some #def's to make the code a little clearer! */ #define ZERO_OFFSET ((Tcl_SeekOffset) 0) #define ERROR_OFFSET ((Tcl_SeekOffset) -1) switch (type) { case TCL_STDIN: if ((TclOSseek(0, ZERO_OFFSET, SEEK_CUR) == ERROR_OFFSET) && (errno == EBADF)) { return (Tcl_Channel) NULL; } fd = 0; mode = TCL_READABLE; bufMode = "line"; break; case TCL_STDOUT: if ((TclOSseek(1, ZERO_OFFSET, SEEK_CUR) == ERROR_OFFSET) && (errno == EBADF)) { return (Tcl_Channel) NULL; } fd = 1; mode = TCL_WRITABLE; bufMode = "line"; break; case TCL_STDERR: if ((TclOSseek(2, ZERO_OFFSET, SEEK_CUR) == ERROR_OFFSET) && (errno == EBADF)) { return (Tcl_Channel) NULL; } fd = 2; mode = TCL_WRITABLE; bufMode = "none"; break; default: panic("TclGetDefaultStdChannel: Unexpected channel type"); break; } #undef ZERO_OFFSET #undef ERROR_OFFSET channel = Tcl_MakeFileChannel((ClientData) fd, mode); if (channel == NULL) { return NULL; } /* * Set up the normal channel options for stdio handles. */ if (Tcl_GetChannelType(channel) == &fileChannelType) { Tcl_SetChannelOption(NULL, channel, "-translation", "auto"); } else { Tcl_SetChannelOption(NULL, channel, "-translation", "auto crlf"); } Tcl_SetChannelOption(NULL, channel, "-buffering", bufMode); return channel; } /* *---------------------------------------------------------------------- * * Tcl_GetOpenFile -- * * Given a name of a channel registered in the given interpreter, * returns a FILE * for it. * * Results: * A standard Tcl result. If the channel is registered in the given * interpreter and it is managed by the "file" channel driver, and * it is open for the requested mode, then the output parameter * filePtr is set to a FILE * for the underlying file. On error, the * filePtr is not set, TCL_ERROR is returned and an error message is * left in the interp's result. * * Side effects: * May invoke fdopen to create the FILE * for the requested file. * *---------------------------------------------------------------------- */ int Tcl_GetOpenFile(interp, string, forWriting, checkUsage, filePtr) Tcl_Interp *interp; /* Interpreter in which to find file. */ CONST char *string; /* String that identifies file. */ int forWriting; /* 1 means the file is going to be used * for writing, 0 means for reading. */ int checkUsage; /* 1 means verify that the file was opened * in a mode that allows the access specified * by "forWriting". Ignored, we always * check that the channel is open for the * requested mode. */ ClientData *filePtr; /* Store pointer to FILE structure here. */ { Tcl_Channel chan; int chanMode; Tcl_ChannelType *chanTypePtr; ClientData data; int fd; FILE *f; chan = Tcl_GetChannel(interp, string, &chanMode); if (chan == (Tcl_Channel) NULL) { return TCL_ERROR; } if ((forWriting) && ((chanMode & TCL_WRITABLE) == 0)) { Tcl_AppendResult(interp, "\"", string, "\" wasn't opened for writing", (char *) NULL); return TCL_ERROR; } else if ((!(forWriting)) && ((chanMode & TCL_READABLE) == 0)) { Tcl_AppendResult(interp, "\"", string, "\" wasn't opened for reading", (char *) NULL); return TCL_ERROR; } /* * We allow creating a FILE * out of file based, pipe based and socket * based channels. We currently do not allow any other channel types, * because it is likely that stdio will not know what to do with them. */ chanTypePtr = Tcl_GetChannelType(chan); if ((chanTypePtr == &fileChannelType) #ifdef SUPPORTS_TTY || (chanTypePtr == &ttyChannelType) #endif /* SUPPORTS_TTY */ || (chanTypePtr == &tcpChannelType) || (strcmp(chanTypePtr->typeName, "pipe") == 0)) { if (Tcl_GetChannelHandle(chan, (forWriting ? TCL_WRITABLE : TCL_READABLE), (ClientData*) &data) == TCL_OK) { fd = (int) data; /* * The call to fdopen below is probably dangerous, since it will * truncate an existing file if the file is being opened * for writing.... */ f = fdopen(fd, (forWriting ? "w" : "r")); if (f == NULL) { Tcl_AppendResult(interp, "cannot get a FILE * for \"", string, "\"", (char *) NULL); return TCL_ERROR; } *filePtr = (ClientData) f; return TCL_OK; } } Tcl_AppendResult(interp, "\"", string, "\" cannot be used to get a FILE *", (char *) NULL); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TclUnixWaitForFile -- * * This procedure waits synchronously for a file to become readable * or writable, with an optional timeout. * * Results: * The return value is an OR'ed combination of TCL_READABLE, * TCL_WRITABLE, and TCL_EXCEPTION, indicating the conditions * that are present on file at the time of the return. This * procedure will not return until either "timeout" milliseconds * have elapsed or at least one of the conditions given by mask * has occurred for file (a return value of 0 means that a timeout * occurred). No normal events will be serviced during the * execution of this procedure. * * Side effects: * Time passes. * *---------------------------------------------------------------------- */ int TclUnixWaitForFile(fd, mask, timeout) int fd; /* Handle for file on which to wait. */ int mask; /* What to wait for: OR'ed combination of * TCL_READABLE, TCL_WRITABLE, and * TCL_EXCEPTION. */ int timeout; /* Maximum amount of time to wait for one * of the conditions in mask to occur, in * milliseconds. A value of 0 means don't * wait at all, and a value of -1 means * wait forever. */ { Tcl_Time abortTime = {0, 0}, now; /* silence gcc 4 warning */ struct timeval blockTime, *timeoutPtr; int numFound, result = 0; fd_set readableMask; fd_set writableMask; fd_set exceptionalMask; #ifndef _DARWIN_C_SOURCE /* * Sanity check fd. */ if (fd >= FD_SETSIZE) { Tcl_Panic("TclUnixWaitForFile can't handle file id %d", fd); /* must never get here, or select masks overrun will occur below */ } #endif /* * If there is a non-zero finite timeout, compute the time when * we give up. */ if (timeout > 0) { Tcl_GetTime(&now); abortTime.sec = now.sec + timeout/1000; abortTime.usec = now.usec + (timeout%1000)*1000; if (abortTime.usec >= 1000000) { abortTime.usec -= 1000000; abortTime.sec += 1; } timeoutPtr = &blockTime; } else if (timeout == 0) { timeoutPtr = &blockTime; blockTime.tv_sec = 0; blockTime.tv_usec = 0; } else { timeoutPtr = NULL; } /* * Initialize the select masks. */ FD_ZERO(&readableMask); FD_ZERO(&writableMask); FD_ZERO(&exceptionalMask); /* * Loop in a mini-event loop of our own, waiting for either the * file to become ready or a timeout to occur. */ while (1) { if (timeout > 0) { blockTime.tv_sec = abortTime.sec - now.sec; blockTime.tv_usec = abortTime.usec - now.usec; if (blockTime.tv_usec < 0) { blockTime.tv_sec -= 1; blockTime.tv_usec += 1000000; } if (blockTime.tv_sec < 0) { blockTime.tv_sec = 0; blockTime.tv_usec = 0; } } /* * Setup the select masks for the fd. */ if (mask & TCL_READABLE) { FD_SET(fd, &readableMask); } if (mask & TCL_WRITABLE) { FD_SET(fd, &writableMask); } if (mask & TCL_EXCEPTION) { FD_SET(fd, &exceptionalMask); } /* * Wait for the event or a timeout. */ numFound = select(fd + 1, &readableMask, &writableMask, &exceptionalMask, timeoutPtr); if (numFound == 1) { if (FD_ISSET(fd, &readableMask)) { result |= TCL_READABLE; } if (FD_ISSET(fd, &writableMask)) { result |= TCL_WRITABLE; } if (FD_ISSET(fd, &exceptionalMask)) { result |= TCL_EXCEPTION; } result &= mask; if (result) { break; } } if (timeout == 0) { break; } if (timeout < 0) { continue; } /* * The select returned early, so we need to recompute the timeout. */ Tcl_GetTime(&now); if ((abortTime.sec < now.sec) || ((abortTime.sec == now.sec) && (abortTime.usec <= now.usec))) { break; } } return result; } #ifdef DEPRECATED /* *---------------------------------------------------------------------- * * FileThreadActionProc -- * * Insert or remove any thread local refs to this channel. * * Results: * None. * * Side effects: * Changes thread local list of valid channels. * *---------------------------------------------------------------------- */ static void FileThreadActionProc (instanceData, action) ClientData instanceData; int action; { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); FileState *fsPtr = (FileState *) instanceData; if (action == TCL_CHANNEL_THREAD_INSERT) { fsPtr->nextPtr = tsdPtr->firstFilePtr; tsdPtr->firstFilePtr = fsPtr; } else { FileState **nextPtrPtr; int removed = 0; for (nextPtrPtr = &(tsdPtr->firstFilePtr); (*nextPtrPtr) != NULL; nextPtrPtr = &((*nextPtrPtr)->nextPtr)) { if ((*nextPtrPtr) == fsPtr) { (*nextPtrPtr) = fsPtr->nextPtr; removed = 1; break; } } /* * This could happen if the channel was created in one * thread and then moved to another without updating * the thread local data in each thread. */ if (!removed) { panic("file info ptr not on thread channel list"); } } } #endif /* DEPRECATED */ /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * tab-width: 8 * indent-tabs-mode: nil * End: */ tcl8.4.20/unix/tclUnixPort.h0000644003604700454610000004526112052456744014355 0ustar dgp771div/* * tclUnixPort.h -- * * This header file handles porting issues that occur because * of differences between systems. It reads in UNIX-related * header files and sets up UNIX-related macros for Tcl's UNIX * core. It should be the only file that contains #ifdefs to * handle different flavors of UNIX. This file sets up the * union of all UNIX-related things needed by any of the Tcl * core files. This file depends on configuration #defines such * as NO_DIRENT_H that are set up by the "configure" script. * * Much of the material in this file was originally contributed * by Karl Lehenbauer, Mark Diekhans and Peter da Silva. * * Copyright (c) 1991-1994 The Regents of the University of California. * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef _TCLUNIXPORT #define _TCLUNIXPORT #ifndef _TCLINT # include "tclInt.h" #endif /* *--------------------------------------------------------------------------- * The following sets of #includes and #ifdefs are required to get Tcl to * compile under the various flavors of unix. *--------------------------------------------------------------------------- */ #include #include #ifdef HAVE_NET_ERRNO_H # include #endif #include #include #ifdef HAVE_SYS_PARAM_H # include #endif #include #ifdef USE_DIRENT2_H # include "../compat/dirent2.h" #else #ifdef NO_DIRENT_H # include "../compat/dirent.h" #else # include #endif #endif /* *--------------------------------------------------------------------------- * Parameterize for 64-bit filesystem support. *--------------------------------------------------------------------------- */ #ifdef HAVE_STRUCT_DIRENT64 typedef struct dirent64 Tcl_DirEntry; # define TclOSreaddir readdir64 #else typedef struct dirent Tcl_DirEntry; # define TclOSreaddir readdir #endif #ifdef HAVE_TYPE_OFF64_T typedef off64_t Tcl_SeekOffset; # define TclOSseek lseek64 # define TclOSopen open64 #else typedef off_t Tcl_SeekOffset; # define TclOSseek lseek # define TclOSopen open #endif #ifdef __CYGWIN__ /* Make some symbols available without including */ # define DWORD unsigned int # define CP_UTF8 65001 # define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 0x00000004 # define HANDLE void * # define HINSTANCE void * # define SOCKET unsigned int # define WSAEWOULDBLOCK 10035 DLLIMPORT extern __stdcall int GetModuleHandleExW(unsigned int, const char *, void *); DLLIMPORT extern __stdcall int GetModuleFileNameW(void *, const char *, int); DLLIMPORT extern __stdcall int WideCharToMultiByte(int, int, const char *, int, const char *, int, const char *, const char *); DLLIMPORT extern int cygwin_conv_path(int, const void *, void *, int); EXTERN int TclOSstat(const char *name, Tcl_StatBuf *statBuf); EXTERN int TclOSlstat(const char *name, Tcl_StatBuf *statBuf); # define NO_FSTATFS # undef HAVE_FTS #elif defined(HAVE_STRUCT_STAT64) # define TclOSstat stat64 # define TclOSlstat lstat64 #else # define TclOSstat stat # define TclOSlstat lstat #endif #if !HAVE_STRTOLL && defined(TCL_WIDE_INT_TYPE) && !TCL_WIDE_INT_IS_LONG EXTERN Tcl_WideInt strtoll _ANSI_ARGS_((CONST char *string, char **endPtr, int base)); EXTERN Tcl_WideUInt strtoull _ANSI_ARGS_((CONST char *string, char **endPtr, int base)); #endif #include #ifdef HAVE_SYS_SELECT_H # include #endif #include #ifdef __CYGWIN__ # define timezone _timezone typedef long TIMEZONE_t; #else /* !__CYGWIN__ */ typedef int TIMEZONE_t; #endif /* !__CYGWIN__ */ #if TIME_WITH_SYS_TIME # include # include #else #if HAVE_SYS_TIME_H # include #else # include #endif #endif #ifndef NO_SYS_WAIT_H # include #endif #ifdef HAVE_UNISTD_H # include #else # include "../compat/unistd.h" #endif #ifdef USE_FIONBIO /* * Not using the Posix fcntl(...,O_NONBLOCK,...) interface, instead * we are using ioctl(..,FIONBIO,..). */ # ifdef HAVE_SYS_FILIO_H # include /* For FIONBIO. */ # endif # ifdef HAVE_SYS_IOCTL_H # include /* For FIONBIO. */ # endif #endif /* USE_FIONBIO */ #include /* * Socket support stuff: This likely needs more work to parameterize for * each system. */ #include /* struct sockaddr, SOCK_STREAM, ... */ #ifndef NO_UNAME # include /* uname system call. */ #endif #include /* struct in_addr, struct sockaddr_in */ #include /* inet_ntoa() */ #include /* gethostbyname() */ /* * Some platforms (e.g. SunOS) don't define FLT_MAX and FLT_MIN, so we * look for an alternative definition. If no other alternative is available * we use a reasonable guess. */ #ifndef NO_FLOAT_H # include #else #ifndef NO_VALUES_H # include #endif #endif #ifndef FLT_MAX # ifdef MAXFLOAT # define FLT_MAX MAXFLOAT # else # define FLT_MAX 3.402823466E+38F # endif #endif #ifndef FLT_MIN # ifdef MINFLOAT # define FLT_MIN MINFLOAT # else # define FLT_MIN 1.175494351E-38F # endif #endif /* * NeXT doesn't define O_NONBLOCK, so #define it here if necessary. */ #ifndef O_NONBLOCK # define O_NONBLOCK 0x80 #endif /* * HPUX needs the flag O_NONBLOCK to get the right non-blocking I/O * semantics, while most other systems need O_NDELAY. Define the * constant NBIO_FLAG to be one of these */ #ifdef HPUX # define NBIO_FLAG O_NONBLOCK #else # define NBIO_FLAG O_NDELAY #endif /* * The type of the status returned by wait varies from UNIX system * to UNIX system. The macro below defines it: */ #ifdef _AIX # define WAIT_STATUS_TYPE pid_t #else #ifndef NO_UNION_WAIT # define WAIT_STATUS_TYPE union wait #else # define WAIT_STATUS_TYPE int #endif #endif /* * Supply definitions for macros to query wait status, if not already * defined in header files above. */ #ifndef WIFEXITED # define WIFEXITED(stat) (((*((int *) &(stat))) & 0xff) == 0) #endif #ifndef WEXITSTATUS # define WEXITSTATUS(stat) (((*((int *) &(stat))) >> 8) & 0xff) #endif #ifndef WIFSIGNALED # define WIFSIGNALED(stat) (((*((int *) &(stat)))) && ((*((int *) &(stat))) == ((*((int *) &(stat))) & 0x00ff))) #endif #ifndef WTERMSIG # define WTERMSIG(stat) ((*((int *) &(stat))) & 0x7f) #endif #ifndef WIFSTOPPED # define WIFSTOPPED(stat) (((*((int *) &(stat))) & 0xff) == 0177) #endif #ifndef WSTOPSIG # define WSTOPSIG(stat) (((*((int *) &(stat))) >> 8) & 0xff) #endif /* * Define constants for waitpid() system call if they aren't defined * by a system header file. */ #ifndef WNOHANG # define WNOHANG 1 #endif #ifndef WUNTRACED # define WUNTRACED 2 #endif /* * Supply macros for seek offsets, if they're not already provided by * an include file. */ #ifndef SEEK_SET # define SEEK_SET 0 #endif #ifndef SEEK_CUR # define SEEK_CUR 1 #endif #ifndef SEEK_END # define SEEK_END 2 #endif /* * The stuff below is needed by the "time" command. If this system has no * gettimeofday call, then must use times and the CLK_TCK #define (from * sys/param.h) to compute elapsed time. Unfortunately, some systems only * have HZ and no CLK_TCK, and some might not even have HZ. */ #ifdef NO_GETTOD # include # include # ifndef CLK_TCK # ifdef HZ # define CLK_TCK HZ # else # define CLK_TCK 60 # endif # endif #endif #ifdef GETTOD_NOT_DECLARED EXTERN int gettimeofday _ANSI_ARGS_((struct timeval *tp, struct timezone *tzp)); #endif /* * Define access mode constants if they aren't already defined. */ #ifndef F_OK # define F_OK 00 #endif #ifndef X_OK # define X_OK 01 #endif #ifndef W_OK # define W_OK 02 #endif #ifndef R_OK # define R_OK 04 #endif /* * Define FD_CLOEEXEC (the close-on-exec flag bit) if it isn't * already defined. */ #ifndef FD_CLOEXEC # define FD_CLOEXEC 1 #endif /* * On systems without symbolic links (i.e. S_IFLNK isn't defined) * define "lstat" to use "stat" instead. */ #ifndef S_IFLNK # undef TclOSlstat # define lstat stat # define lstat64 stat64 # define TclOSlstat TclOSstat #endif /* * Define macros to query file type bits, if they're not already * defined. */ #ifndef S_ISREG # ifdef S_IFREG # define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) # else # define S_ISREG(m) 0 # endif #endif /* !S_ISREG */ #ifndef S_ISDIR # ifdef S_IFDIR # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) # else # define S_ISDIR(m) 0 # endif #endif /* !S_ISDIR */ #ifndef S_ISCHR # ifdef S_IFCHR # define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) # else # define S_ISCHR(m) 0 # endif #endif /* !S_ISCHR */ #ifndef S_ISBLK # ifdef S_IFBLK # define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) # else # define S_ISBLK(m) 0 # endif #endif /* !S_ISBLK */ #ifndef S_ISFIFO # ifdef S_IFIFO # define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) # else # define S_ISFIFO(m) 0 # endif #endif /* !S_ISFIFO */ #ifndef S_ISLNK # ifdef S_IFLNK # define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) # else # define S_ISLNK(m) 0 # endif #endif /* !S_ISLNK */ #ifndef S_ISSOCK # ifdef S_IFSOCK # define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) # else # define S_ISSOCK(m) 0 # endif #endif /* !S_ISSOCK */ /* * Make sure that MAXPATHLEN and MAXNAMLEN are defined. */ #ifndef MAXPATHLEN # ifdef PATH_MAX # define MAXPATHLEN PATH_MAX # else # define MAXPATHLEN 2048 # endif #endif #ifndef MAXNAMLEN # ifdef NAME_MAX # define MAXNAMLEN NAME_MAX # else # define MAXNAMLEN 255 # endif #endif /* * Make sure that L_tmpnam is defined. */ #ifndef L_tmpnam # define L_tmpnam 100 #endif /* * The following macro defines the type of the mask arguments to * select: */ #ifndef NO_FD_SET # define SELECT_MASK fd_set #else /* NO_FD_SET */ # ifndef _AIX typedef long fd_mask; # endif /* !AIX */ # if defined(_IBMR2) # define SELECT_MASK void # else /* !defined(_IBMR2) */ # define SELECT_MASK int # endif /* defined(_IBMR2) */ #endif /* !NO_FD_SET */ /* * Define "NBBY" (number of bits per byte) if it's not already defined. */ #ifndef NBBY # define NBBY 8 #endif /* * The following macro defines the number of fd_masks in an fd_set: */ #ifndef FD_SETSIZE # ifdef OPEN_MAX # define FD_SETSIZE OPEN_MAX # else # define FD_SETSIZE 256 # endif #endif /* FD_SETSIZE */ #if !defined(howmany) # define howmany(x, y) (((x)+((y)-1))/(y)) #endif /* !defined(howmany) */ #ifndef NFDBITS # define NFDBITS NBBY*sizeof(fd_mask) #endif /* NFDBITS */ #define MASK_SIZE howmany(FD_SETSIZE, NFDBITS) /* * Not all systems declare the errno variable in errno.h. so this * file does it explicitly. The list of system error messages also * isn't generally declared in a header file anywhere. */ #ifdef NO_ERRNO extern int errno; #endif /* * Not all systems declare all the errors that Tcl uses! Provide some * work-arounds... */ #ifndef EOVERFLOW # ifdef EFBIG # define EOVERFLOW EFBIG # else /* !EFBIG */ # define EOVERFLOW EINVAL # endif /* EFBIG */ #endif /* EOVERFLOW */ /* * Variables provided by the C library: */ #if defined(__APPLE__) && defined(__DYNAMIC__) # include # define environ (*_NSGetEnviron()) # define USE_PUTENV 1 #else # if defined(_sgi) || defined(__sgi) # define environ _environ # endif extern char **environ; #endif /* * At present (12/91) not all stdlib.h implementations declare strtod. * The declaration below is here to ensure that it's declared, so that * the compiler won't take the default approach of assuming it returns * an int. There's no ANSI prototype for it because there would end * up being too many conflicts with slightly-different prototypes. */ extern double strtod(); /* * There is no platform-specific panic routine for Unix in the Tcl internals. */ #define TclpPanic ((Tcl_PanicProc *) NULL) /* * Darwin specifc configure overrides. */ #ifdef __APPLE__ /* * Support for fat compiles: configure runs only once for multiple architectures */ # if defined(__LP64__) && defined (NO_COREFOUNDATION_64) # undef HAVE_COREFOUNDATION # endif /* __LP64__ && NO_COREFOUNDATION_64 */ # include # ifdef __DARWIN_UNIX03 # if __DARWIN_UNIX03 # undef HAVE_PUTENV_THAT_COPIES # else # define HAVE_PUTENV_THAT_COPIES 1 # endif # endif /* __DARWIN_UNIX03 */ /* * The termios configure test program relies on the configure script being run * from a terminal, which is not the case e.g. when configuring from Xcode. * Since termios is known to be present on all Mac OS X releases since 10.0, * override the configure defines for serial API here. [Bug 497147] */ # define USE_TERMIOS 1 # undef USE_TERMIO # undef USE_SGTTY /* * Include AvailabilityMacros.h here (when available) to ensure any symbolic * MAC_OS_X_VERSION_* constants passed on the command line are translated. */ # ifdef HAVE_AVAILABILITYMACROS_H # include # endif /* * Support for weak import. */ # ifdef HAVE_WEAK_IMPORT # if !defined(HAVE_AVAILABILITYMACROS_H) || !defined(MAC_OS_X_VERSION_MIN_REQUIRED) # undef HAVE_WEAK_IMPORT # else # ifndef WEAK_IMPORT_ATTRIBUTE # define WEAK_IMPORT_ATTRIBUTE __attribute__((weak_import)) # endif # endif # endif /* HAVE_WEAK_IMPORT */ /* * Support for MAC_OS_X_VERSION_MAX_ALLOWED define from AvailabilityMacros.h: * only use API available in the indicated OS version or earlier. */ # ifdef MAC_OS_X_VERSION_MAX_ALLOWED # if MAC_OS_X_VERSION_MAX_ALLOWED < 1050 && defined(__LP64__) # undef HAVE_COREFOUNDATION # endif # if MAC_OS_X_VERSION_MAX_ALLOWED < 1040 # undef HAVE_OSSPINLOCKLOCK # undef HAVE_PTHREAD_ATFORK # undef HAVE_COPYFILE # endif # if MAC_OS_X_VERSION_MAX_ALLOWED < 1030 # ifdef TCL_THREADS /* prior to 10.3, realpath is not threadsafe, c.f. bug 711232 */ # define NO_REALPATH 1 # endif # undef HAVE_LANGINFO # endif # endif /* MAC_OS_X_VERSION_MAX_ALLOWED */ # if defined(HAVE_COREFOUNDATION) && defined(__LP64__) && \ defined(HAVE_WEAK_IMPORT) && MAC_OS_X_VERSION_MIN_REQUIRED < 1050 # warning "Weak import of 64-bit CoreFoundation is not supported, will not run on Mac OS X < 10.5." # endif /* * At present, using vfork() instead of fork() causes execve() to fail * intermittently on Darwin x86_64. rdar://4685553 */ # if defined(__x86_64__) && !defined(FIXED_RDAR_4685553) # undef USE_VFORK # endif /* __x86_64__ */ /* Workaround problems with vfork() when building with llvm-gcc-4.2 */ # if defined (__llvm__) && \ (__GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ > 2 || \ (__GNUC_MINOR__ == 2 && __GNUC_PATCHLEVEL__ > 0)))) # undef USE_VFORK # endif /* __llvm__ */ #endif /* __APPLE__ */ /* * Darwin 8 copyfile API. */ #ifdef HAVE_COPYFILE #ifdef HAVE_COPYFILE_H #include #if defined(HAVE_WEAK_IMPORT) && MAC_OS_X_VERSION_MIN_REQUIRED < 1040 /* Support for weakly importing copyfile. */ #define WEAK_IMPORT_COPYFILE extern int copyfile(const char *from, const char *to, copyfile_state_t state, copyfile_flags_t flags) WEAK_IMPORT_ATTRIBUTE; #endif /* HAVE_WEAK_IMPORT */ #else /* HAVE_COPYFILE_H */ int copyfile(const char *from, const char *to, void *state, uint32_t flags); #define COPYFILE_ACL (1<<0) #define COPYFILE_XATTR (1<<2) #define COPYFILE_NOFOLLOW_SRC (1<<18) #if defined(HAVE_WEAK_IMPORT) && MAC_OS_X_VERSION_MIN_REQUIRED < 1040 /* Support for weakly importing copyfile. */ #define WEAK_IMPORT_COPYFILE extern int copyfile(const char *from, const char *to, void *state, uint32_t flags) WEAK_IMPORT_ATTRIBUTE; #endif /* HAVE_WEAK_IMPORT */ #endif /* HAVE_COPYFILE_H */ #endif /* HAVE_COPYFILE */ /* *--------------------------------------------------------------------------- * The following macros and declarations represent the interface between * generic and unix-specific parts of Tcl. Some of the macros may override * functions declared in tclInt.h. *--------------------------------------------------------------------------- */ /* * The default platform eol translation on Unix is TCL_TRANSLATE_LF. */ #ifdef DJGPP #define TCL_PLATFORM_TRANSLATION TCL_TRANSLATE_CRLF #else #define TCL_PLATFORM_TRANSLATION TCL_TRANSLATE_LF #endif /* * The following macros have trivial definitions, allowing generic code to * address platform-specific issues. */ #define TclpReleaseFile(file) /* Nothing. */ /* * The following defines wrap the system memory allocation routines for * use by tclAlloc.c. By default off unused on Unix. */ #if USE_TCLALLOC # define TclpSysAlloc(size, isBin) malloc((size_t)size) # define TclpSysFree(ptr) free((char*)ptr) # define TclpSysRealloc(ptr, size) realloc((char*)ptr, (size_t)size) #endif /* * The following macros and declaration wrap the C runtime library * functions. */ #define TclpExit exit /* * Platform specific mutex definition used by memory allocators. * These mutexes are statically allocated and explicitly initialized. * Most modules do not use this, but instead use Tcl_Mutex types and * Tcl_MutexLock and Tcl_MutexUnlock that are self-initializing. */ #ifdef TCL_THREADS #include typedef pthread_mutex_t TclpMutex; EXTERN void TclpMutexInit _ANSI_ARGS_((TclpMutex *mPtr)); EXTERN void TclpMutexLock _ANSI_ARGS_((TclpMutex *mPtr)); EXTERN void TclpMutexUnlock _ANSI_ARGS_((TclpMutex *mPtr)); EXTERN Tcl_DirEntry * TclpReaddir(DIR *); #ifndef TclpLocaltime EXTERN struct tm *TclpLocaltime(TclpTime_t_CONST); #endif #ifndef TclpGmtime EXTERN struct tm *TclpGmtime(TclpTime_t_CONST); #endif #define inet_ntoa(x) TclpInetNtoa(x) #else typedef int TclpMutex; #define TclpMutexInit(a) #define TclpMutexLock(a) #define TclpMutexUnlock(a) #endif /* TCL_THREADS */ /* * Set of MT-safe implementations of some * known-to-be-MT-unsafe library calls. * Instead of returning pointers to the * static storage, those return pointers * to the TSD data. */ #include #include EXTERN struct passwd* TclpGetPwNam(const char *name); EXTERN struct group* TclpGetGrNam(const char *name); EXTERN struct passwd* TclpGetPwUid(uid_t uid); EXTERN struct group* TclpGetGrGid(gid_t gid); EXTERN struct hostent* TclpGetHostByName(const char *name); EXTERN struct hostent* TclpGetHostByAddr(const char *addr, int length, int type); #include "tclPlatDecls.h" #include "tclIntPlatDecls.h" #endif /* _TCLUNIXPORT */ tcl8.4.20/unix/tclAppInit.c0000644003604700454610000001127111737050675014120 0ustar dgp771div/* * tclAppInit.c -- * * Provides a default version of the main program and Tcl_AppInit * procedure for Tcl applications (without Tk). * * Copyright (c) 1993 The Regents of the University of California. * Copyright (c) 1994-1997 Sun Microsystems, Inc. * Copyright (c) 1998-1999 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tcl.h" #ifdef TCL_TEST #include "tclInt.h" extern int Procbodytest_Init _ANSI_ARGS_((Tcl_Interp *interp)); extern int Procbodytest_SafeInit _ANSI_ARGS_((Tcl_Interp *interp)); extern int TclObjTest_Init _ANSI_ARGS_((Tcl_Interp *interp)); extern int Tcltest_Init _ANSI_ARGS_((Tcl_Interp *interp)); #ifdef TCL_THREADS extern int TclThread_Init _ANSI_ARGS_((Tcl_Interp *interp)); #endif #endif /* TCL_TEST */ #ifdef TCL_XT_TEST extern void XtToolkitInitialize _ANSI_ARGS_((void)); extern int Tclxttest_Init _ANSI_ARGS_((Tcl_Interp *interp)); #endif /* *---------------------------------------------------------------------- * * main -- * * This is the main program for the application. * * Results: * None: Tcl_Main never returns here, so this procedure never * returns either. * * Side effects: * Whatever the application does. * *---------------------------------------------------------------------- */ int main(argc, argv) int argc; /* Number of command-line arguments. */ char **argv; /* Values of command-line arguments. */ { /* * The following #if block allows you to change the AppInit * function by using a #define of TCL_LOCAL_APPINIT instead * of rewriting this entire file. The #if checks for that * #define and uses Tcl_AppInit if it doesn't exist. */ #ifndef TCL_LOCAL_APPINIT #define TCL_LOCAL_APPINIT Tcl_AppInit #endif extern int TCL_LOCAL_APPINIT _ANSI_ARGS_((Tcl_Interp *interp)); /* * The following #if block allows you to change how Tcl finds the startup * script, prime the library or encoding paths, fiddle with the argv, * etc., without needing to rewrite Tcl_Main() */ #ifdef TCL_LOCAL_MAIN_HOOK extern int TCL_LOCAL_MAIN_HOOK _ANSI_ARGS_((int *argc, char ***argv)); #endif #ifdef TCL_XT_TEST XtToolkitInitialize(); #endif #ifdef TCL_LOCAL_MAIN_HOOK TCL_LOCAL_MAIN_HOOK(&argc, &argv); #endif Tcl_Main(argc, argv, TCL_LOCAL_APPINIT); return 0; /* Needed only to prevent compiler warning. */ } /* *---------------------------------------------------------------------- * * Tcl_AppInit -- * * This procedure performs application-specific initialization. * Most applications, especially those that incorporate additional * packages, will have their own version of this procedure. * * Results: * Returns a standard Tcl completion code, and leaves an error * message in the interp's result if an error occurs. * * Side effects: * Depends on the startup script. * *---------------------------------------------------------------------- */ int Tcl_AppInit(interp) Tcl_Interp *interp; /* Interpreter for application. */ { if (Tcl_Init(interp) == TCL_ERROR) { return TCL_ERROR; } #ifdef TCL_TEST #ifdef TCL_XT_TEST if (Tclxttest_Init(interp) == TCL_ERROR) { return TCL_ERROR; } #endif if (Tcltest_Init(interp) == TCL_ERROR) { return TCL_ERROR; } Tcl_StaticPackage(interp, "Tcltest", Tcltest_Init, (Tcl_PackageInitProc *) NULL); if (TclObjTest_Init(interp) == TCL_ERROR) { return TCL_ERROR; } #ifdef TCL_THREADS if (TclThread_Init(interp) == TCL_ERROR) { return TCL_ERROR; } #endif if (Procbodytest_Init(interp) == TCL_ERROR) { return TCL_ERROR; } Tcl_StaticPackage(interp, "procbodytest", Procbodytest_Init, Procbodytest_SafeInit); #endif /* TCL_TEST */ /* * Call the init procedures for included packages. Each call should * look like this: * * if (Mod_Init(interp) == TCL_ERROR) { * return TCL_ERROR; * } * * where "Mod" is the name of the module. */ /* * Call Tcl_CreateCommand for application-specific commands, if * they weren't already created by the init procedures called above. */ /* * Specify a user-specific startup file to invoke if the application * is run interactively. Typically the startup file is "~/.apprc" * where "app" is the name of the application. If this line is deleted * then no user-specific startup file will be run under any conditions. */ #ifdef DJGPP Tcl_SetVar(interp, "tcl_rcFileName", "~/tclsh.rc", TCL_GLOBAL_ONLY); #else Tcl_SetVar(interp, "tcl_rcFileName", "~/.tclshrc", TCL_GLOBAL_ONLY); #endif return TCL_OK; } tcl8.4.20/unix/tclUnixPipe.c0000644003604700454610000010372412052456744014320 0ustar dgp771div/* * tclUnixPipe.c -- * * This file implements the UNIX-specific exec pipeline functions, * the "pipe" channel driver, and the "pid" Tcl command. * * Copyright (c) 1991-1994 The Regents of the University of California. * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" #ifdef USE_VFORK #define fork vfork #endif /* * Fallback temporary file location the temporary file generation code. Can be * overridden at compile time for when it is known that temp files can't be * written to /tmp (hello, iOS!). */ #ifndef TCL_TEMPORARY_FILE_DIRECTORY #define TCL_TEMPORARY_FILE_DIRECTORY "/tmp" #endif /* * The following macros convert between TclFile's and fd's. The conversion * simple involves shifting fd's up by one to ensure that no valid fd is ever * the same as NULL. */ #define MakeFile(fd) ((TclFile)(((int)fd)+1)) #define GetFd(file) (((int)file)-1) /* * This structure describes per-instance state of a pipe based channel. */ typedef struct PipeState { Tcl_Channel channel;/* Channel associated with this file. */ TclFile inFile; /* Output from pipe. */ TclFile outFile; /* Input to pipe. */ TclFile errorFile; /* Error output from pipe. */ int numPids; /* How many processes are attached to this pipe? */ Tcl_Pid *pidPtr; /* The process IDs themselves. Allocated by * the creator of the pipe. */ int isNonBlocking; /* Nonzero when the pipe is in nonblocking mode. * Used to decide whether to wait for the children * at close time. */ } PipeState; /* * Declarations for local procedures defined in this file: */ static int PipeBlockModeProc _ANSI_ARGS_((ClientData instanceData, int mode)); static int PipeCloseProc _ANSI_ARGS_((ClientData instanceData, Tcl_Interp *interp)); static int PipeGetHandleProc _ANSI_ARGS_((ClientData instanceData, int direction, ClientData *handlePtr)); static int PipeInputProc _ANSI_ARGS_((ClientData instanceData, char *buf, int toRead, int *errorCode)); static int PipeOutputProc _ANSI_ARGS_(( ClientData instanceData, CONST char *buf, int toWrite, int *errorCode)); static void PipeWatchProc _ANSI_ARGS_((ClientData instanceData, int mask)); static void RestoreSignals _ANSI_ARGS_((void)); static int SetupStdFile _ANSI_ARGS_((TclFile file, int type)); static CONST char * DefaultTempDir _ANSI_ARGS_((void)); /* * This structure describes the channel type structure for command pipe * based IO: */ static Tcl_ChannelType pipeChannelType = { "pipe", /* Type name. */ TCL_CHANNEL_VERSION_4, /* v4 channel */ PipeCloseProc, /* Close proc. */ PipeInputProc, /* Input proc. */ PipeOutputProc, /* Output proc. */ NULL, /* Seek proc. */ NULL, /* Set option proc. */ NULL, /* Get option proc. */ PipeWatchProc, /* Initialize notifier. */ PipeGetHandleProc, /* Get OS handles out of channel. */ NULL, /* close2proc. */ PipeBlockModeProc, /* Set blocking or non-blocking mode.*/ NULL, /* flush proc. */ NULL, /* handler proc. */ NULL, /* wide seek proc */ NULL, /* thread action proc */ }; /* *---------------------------------------------------------------------- * * TclpMakeFile -- * * Make a TclFile from a channel. * * Results: * Returns a new TclFile or NULL on failure. * * Side effects: * None. * *---------------------------------------------------------------------- */ TclFile TclpMakeFile(channel, direction) Tcl_Channel channel; /* Channel to get file from. */ int direction; /* Either TCL_READABLE or TCL_WRITABLE. */ { ClientData data; if (Tcl_GetChannelHandle(channel, direction, (ClientData *) &data) == TCL_OK) { return MakeFile((int)data); } else { return (TclFile) NULL; } } /* *---------------------------------------------------------------------- * * TclpOpenFile -- * * Open a file for use in a pipeline. * * Results: * Returns a new TclFile handle or NULL on failure. * * Side effects: * May cause a file to be created on the file system. * *---------------------------------------------------------------------- */ TclFile TclpOpenFile(fname, mode) CONST char *fname; /* The name of the file to open. */ int mode; /* In what mode to open the file? */ { int fd; CONST char *native; Tcl_DString ds; native = Tcl_UtfToExternalDString(NULL, fname, -1, &ds); fd = TclOSopen(native, mode, 0666); /* INTL: Native. */ Tcl_DStringFree(&ds); if (fd != -1) { fcntl(fd, F_SETFD, FD_CLOEXEC); /* * If the file is being opened for writing, seek to the end * so we can append to any data already in the file. */ if ((mode & O_WRONLY) && !(mode & O_APPEND)) { TclOSseek(fd, (Tcl_SeekOffset) 0, SEEK_END); } /* * Increment the fd so it can't be 0, which would conflict with * the NULL return for errors. */ return MakeFile(fd); } return NULL; } /* *---------------------------------------------------------------------- * * TclpCreateTempFile -- * * This function creates a temporary file initialized with an * optional string, and returns a file handle with the file pointer * at the beginning of the file. * * Results: * A handle to a file. * * Side effects: * None. * *---------------------------------------------------------------------- */ TclFile TclpCreateTempFile(contents) CONST char *contents; /* String to write into temp file, or NULL. */ { char fileName[L_tmpnam + 9]; CONST char *native; Tcl_DString dstring; int fd; /* * We should also check against making more then TMP_MAX of these. */ strcpy(fileName, DefaultTempDir()); /* INTL: Native. */ if (fileName[strlen(fileName) - 1] != '/') { strcat(fileName, "/"); /* INTL: Native. */ } strcat(fileName, "tclXXXXXX"); fd = mkstemp(fileName); /* INTL: Native. */ if (fd == -1) { return NULL; } fcntl(fd, F_SETFD, FD_CLOEXEC); unlink(fileName); /* INTL: Native. */ if (contents != NULL) { native = Tcl_UtfToExternalDString(NULL, contents, -1, &dstring); if (write(fd, native, Tcl_DStringLength(&dstring)) == -1) { close(fd); Tcl_DStringFree(&dstring); return NULL; } Tcl_DStringFree(&dstring); TclOSseek(fd, (Tcl_SeekOffset) 0, SEEK_SET); } return MakeFile(fd); } /* *---------------------------------------------------------------------- * * TclpTempFileName -- * * This function returns unique filename. * * Results: * Returns a valid Tcl_Obj* with refCount 0, or NULL on failure. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_Obj* TclpTempFileName() { char fileName[L_tmpnam + 9]; Tcl_Obj *result = NULL; int fd; /* * We should also check against making more then TMP_MAX of these. */ strcpy(fileName, DefaultTempDir()); /* INTL: Native. */ if (fileName[strlen(fileName) - 1] != '/') { strcat(fileName, "/"); /* INTL: Native. */ } strcat(fileName, "tclXXXXXX"); fd = mkstemp(fileName); /* INTL: Native. */ if (fd == -1) { return NULL; } fcntl(fd, F_SETFD, FD_CLOEXEC); unlink(fileName); /* INTL: Native. */ result = TclpNativeToNormalized((ClientData) fileName); close (fd); return result; } /* *---------------------------------------------------------------------- * * DefaultTempDir -- * * Helper that does *part* of what tempnam() does. * *---------------------------------------------------------------------- */ static CONST char * DefaultTempDir(void) { CONST char *dir; struct stat buf; dir = getenv("TMPDIR"); if (dir && dir[0] && stat(dir, &buf) == 0 && S_ISDIR(buf.st_mode) && access(dir, W_OK)) { return dir; } #ifdef P_tmpdir dir = P_tmpdir; if (stat(dir, &buf) == 0 && S_ISDIR(buf.st_mode) && access(dir, W_OK)) { return dir; } #endif /* * Assume that the default location ("/tmp" if not overridden) is always * an existing writable directory; we've no recovery mechanism if it * isn't. */ return TCL_TEMPORARY_FILE_DIRECTORY; } /* *---------------------------------------------------------------------- * * TclpCreatePipe -- * * Creates a pipe - simply calls the pipe() function. * * Results: * Returns 1 on success, 0 on failure. * * Side effects: * Creates a pipe. * *---------------------------------------------------------------------- */ int TclpCreatePipe(readPipe, writePipe) TclFile *readPipe; /* Location to store file handle for * read side of pipe. */ TclFile *writePipe; /* Location to store file handle for * write side of pipe. */ { int pipeIds[2]; if (pipe(pipeIds) != 0) { return 0; } fcntl(pipeIds[0], F_SETFD, FD_CLOEXEC); fcntl(pipeIds[1], F_SETFD, FD_CLOEXEC); *readPipe = MakeFile(pipeIds[0]); *writePipe = MakeFile(pipeIds[1]); return 1; } /* *---------------------------------------------------------------------- * * TclpCloseFile -- * * Implements a mechanism to close a UNIX file. * * Results: * Returns 0 on success, or -1 on error, setting errno. * * Side effects: * The file is closed. * *---------------------------------------------------------------------- */ int TclpCloseFile(file) TclFile file; /* The file to close. */ { int fd = GetFd(file); /* * Refuse to close the fds for stdin, stdout and stderr. */ if ((fd == 0) || (fd == 1) || (fd == 2)) { return 0; } Tcl_DeleteFileHandler(fd); return close(fd); } /* *--------------------------------------------------------------------------- * * TclpCreateProcess -- * * Create a child process that has the specified files as its * standard input, output, and error. The child process runs * asynchronously and runs with the same environment variables * as the creating process. * * The path is searched to find the specified executable. * * Results: * The return value is TCL_ERROR and an error message is left in * the interp's result if there was a problem creating the child * process. Otherwise, the return value is TCL_OK and *pidPtr is * filled with the process id of the child process. * * Side effects: * A process is created. * *--------------------------------------------------------------------------- */ /* ARGSUSED */ int TclpCreateProcess(interp, argc, argv, inputFile, outputFile, errorFile, pidPtr) Tcl_Interp *interp; /* Interpreter in which to leave errors that * occurred when creating the child process. * Error messages from the child process * itself are sent to errorFile. */ int argc; /* Number of arguments in following array. */ CONST char **argv; /* Array of argument strings in UTF-8. * argv[0] contains the name of the executable * translated using Tcl_TranslateFileName * call). Additional arguments have not been * converted. */ TclFile inputFile; /* If non-NULL, gives the file to use as * input for the child process. If inputFile * file is not readable or is NULL, the child * will receive no standard input. */ TclFile outputFile; /* If non-NULL, gives the file that * receives output from the child process. If * outputFile file is not writeable or is * NULL, output from the child will be * discarded. */ TclFile errorFile; /* If non-NULL, gives the file that * receives errors from the child process. If * errorFile file is not writeable or is NULL, * errors from the child will be discarded. * errorFile may be the same as outputFile. */ Tcl_Pid *pidPtr; /* If this procedure is successful, pidPtr * is filled with the process id of the child * process. */ { TclFile errPipeIn, errPipeOut; int count, status, fd; char errSpace[200 + TCL_INTEGER_SPACE]; Tcl_DString *dsArray; char **newArgv; int pid, i; errPipeIn = NULL; errPipeOut = NULL; pid = -1; /* * Create a pipe that the child can use to return error * information if anything goes wrong. */ if (TclpCreatePipe(&errPipeIn, &errPipeOut) == 0) { Tcl_AppendResult(interp, "couldn't create pipe: ", Tcl_PosixError(interp), (char *) NULL); goto error; } /* * We need to allocate and convert this before the fork * so it is properly deallocated later */ dsArray = (Tcl_DString *) ckalloc(argc * sizeof(Tcl_DString)); newArgv = (char **) ckalloc((argc+1) * sizeof(char *)); newArgv[argc] = NULL; for (i = 0; i < argc; i++) { newArgv[i] = Tcl_UtfToExternalDString(NULL, argv[i], -1, &dsArray[i]); } #ifdef USE_VFORK /* * After vfork(), do not call code in the child that changes global state, * because it is using the parent's memory space at that point and writes * might corrupt the parent: so ensure standard channels are initialized in * the parent, otherwise SetupStdFile() might initialize them in the child. */ if (!inputFile) { Tcl_GetStdChannel(TCL_STDIN); } if (!outputFile) { Tcl_GetStdChannel(TCL_STDOUT); } if (!errorFile) { Tcl_GetStdChannel(TCL_STDERR); } #endif pid = fork(); if (pid == 0) { int joinThisError = errorFile && (errorFile == outputFile); fd = GetFd(errPipeOut); /* * Set up stdio file handles for the child process. */ if (!SetupStdFile(inputFile, TCL_STDIN) || !SetupStdFile(outputFile, TCL_STDOUT) || (!joinThisError && !SetupStdFile(errorFile, TCL_STDERR)) || (joinThisError && ((dup2(1,2) == -1) || (fcntl(2, F_SETFD, 0) != 0)))) { sprintf(errSpace, "%dforked process couldn't set up input/output: ", errno); write(fd, errSpace, (size_t) strlen(errSpace)); _exit(1); } /* * Close the input side of the error pipe. */ RestoreSignals(); execvp(newArgv[0], newArgv); /* INTL: Native. */ sprintf(errSpace, "%dcouldn't execute \"%.150s\": ", errno, argv[0]); write(fd, errSpace, (size_t) strlen(errSpace)); _exit(1); } /* * Free the mem we used for the fork */ for (i = 0; i < argc; i++) { Tcl_DStringFree(&dsArray[i]); } ckfree((char *) dsArray); ckfree((char *) newArgv); if (pid == -1) { Tcl_AppendResult(interp, "couldn't fork child process: ", Tcl_PosixError(interp), (char *) NULL); goto error; } /* * Read back from the error pipe to see if the child started * up OK. The info in the pipe (if any) consists of a decimal * errno value followed by an error message. */ TclpCloseFile(errPipeOut); errPipeOut = NULL; fd = GetFd(errPipeIn); count = read(fd, errSpace, (size_t) (sizeof(errSpace) - 1)); if (count > 0) { char *end; errSpace[count] = 0; errno = strtol(errSpace, &end, 10); Tcl_AppendResult(interp, end, Tcl_PosixError(interp), (char *) NULL); goto error; } TclpCloseFile(errPipeIn); *pidPtr = (Tcl_Pid) pid; return TCL_OK; error: if (pid != -1) { /* * Reap the child process now if an error occurred during its * startup. We don't call this with WNOHANG because that can lead to * defunct processes on an MP system. We shouldn't have to worry * about hanging here, since this is the error case. [Bug: 6148] */ Tcl_WaitPid((Tcl_Pid) pid, &status, 0); } if (errPipeIn) { TclpCloseFile(errPipeIn); } if (errPipeOut) { TclpCloseFile(errPipeOut); } return TCL_ERROR; } /* *---------------------------------------------------------------------- * * RestoreSignals -- * * This procedure is invoked in a forked child process just before * exec-ing a new program to restore all signals to their default * settings. * * Results: * None. * * Side effects: * Signal settings get changed. * *---------------------------------------------------------------------- */ static void RestoreSignals() { #ifdef SIGABRT signal(SIGABRT, SIG_DFL); #endif #ifdef SIGALRM signal(SIGALRM, SIG_DFL); #endif #ifdef SIGFPE signal(SIGFPE, SIG_DFL); #endif #ifdef SIGHUP signal(SIGHUP, SIG_DFL); #endif #ifdef SIGILL signal(SIGILL, SIG_DFL); #endif #ifdef SIGINT signal(SIGINT, SIG_DFL); #endif #ifdef SIGPIPE signal(SIGPIPE, SIG_DFL); #endif #ifdef SIGQUIT signal(SIGQUIT, SIG_DFL); #endif #ifdef SIGSEGV signal(SIGSEGV, SIG_DFL); #endif #ifdef SIGTERM signal(SIGTERM, SIG_DFL); #endif #ifdef SIGUSR1 signal(SIGUSR1, SIG_DFL); #endif #ifdef SIGUSR2 signal(SIGUSR2, SIG_DFL); #endif #ifdef SIGCHLD signal(SIGCHLD, SIG_DFL); #endif #ifdef SIGCONT signal(SIGCONT, SIG_DFL); #endif #ifdef SIGTSTP signal(SIGTSTP, SIG_DFL); #endif #ifdef SIGTTIN signal(SIGTTIN, SIG_DFL); #endif #ifdef SIGTTOU signal(SIGTTOU, SIG_DFL); #endif } /* *---------------------------------------------------------------------- * * SetupStdFile -- * * Set up stdio file handles for the child process, using the * current standard channels if no other files are specified. * If no standard channel is defined, or if no file is associated * with the channel, then the corresponding standard fd is closed. * * Results: * Returns 1 on success, or 0 on failure. * * Side effects: * Replaces stdio fds. * *---------------------------------------------------------------------- */ static int SetupStdFile(file, type) TclFile file; /* File to dup, or NULL. */ int type; /* One of TCL_STDIN, TCL_STDOUT, TCL_STDERR */ { Tcl_Channel channel; int fd; int targetFd = 0; /* Initializations here needed only to */ int direction = 0; /* prevent warnings about using uninitialized * variables. */ switch (type) { case TCL_STDIN: targetFd = 0; direction = TCL_READABLE; break; case TCL_STDOUT: targetFd = 1; direction = TCL_WRITABLE; break; case TCL_STDERR: targetFd = 2; direction = TCL_WRITABLE; break; } if (!file) { channel = Tcl_GetStdChannel(type); if (channel) { file = TclpMakeFile(channel, direction); } } if (file) { fd = GetFd(file); if (fd != targetFd) { if (dup2(fd, targetFd) == -1) { return 0; } /* * Must clear the close-on-exec flag for the target FD, since * some systems (e.g. Ultrix) do not clear the CLOEXEC flag on * the target FD. */ fcntl(targetFd, F_SETFD, 0); } else { /* * Since we aren't dup'ing the file, we need to explicitly clear * the close-on-exec flag. */ fcntl(fd, F_SETFD, 0); } } else { close(targetFd); } return 1; } /* *---------------------------------------------------------------------- * * TclpCreateCommandChannel -- * * This function is called by the generic IO level to perform * the platform specific channel initialization for a command * channel. * * Results: * Returns a new channel or NULL on failure. * * Side effects: * Allocates a new channel. * *---------------------------------------------------------------------- */ Tcl_Channel TclpCreateCommandChannel(readFile, writeFile, errorFile, numPids, pidPtr) TclFile readFile; /* If non-null, gives the file for reading. */ TclFile writeFile; /* If non-null, gives the file for writing. */ TclFile errorFile; /* If non-null, gives the file where errors * can be read. */ int numPids; /* The number of pids in the pid array. */ Tcl_Pid *pidPtr; /* An array of process identifiers. * Allocated by the caller, freed when * the channel is closed or the processes * are detached (in a background exec). */ { char channelName[16 + TCL_INTEGER_SPACE]; int channelId; PipeState *statePtr = (PipeState *) ckalloc((unsigned) sizeof(PipeState)); int mode; statePtr->inFile = readFile; statePtr->outFile = writeFile; statePtr->errorFile = errorFile; statePtr->numPids = numPids; statePtr->pidPtr = pidPtr; statePtr->isNonBlocking = 0; mode = 0; if (readFile) { mode |= TCL_READABLE; } if (writeFile) { mode |= TCL_WRITABLE; } /* * Use one of the fds associated with the channel as the * channel id. */ if (readFile) { channelId = GetFd(readFile); } else if (writeFile) { channelId = GetFd(writeFile); } else if (errorFile) { channelId = GetFd(errorFile); } else { channelId = 0; } /* * For backward compatibility with previous versions of Tcl, we * use "file%d" as the base name for pipes even though it would * be more natural to use "pipe%d". */ sprintf(channelName, "file%d", channelId); statePtr->channel = Tcl_CreateChannel(&pipeChannelType, channelName, (ClientData) statePtr, mode); return statePtr->channel; } /* *---------------------------------------------------------------------- * * TclGetAndDetachPids -- * * This procedure is invoked in the generic implementation of a * background "exec" (An exec when invoked with a terminating "&") * to store a list of the PIDs for processes in a command pipeline * in the interp's result and to detach the processes. * * Results: * None. * * Side effects: * Modifies the interp's result. Detaches processes. * *---------------------------------------------------------------------- */ void TclGetAndDetachPids(interp, chan) Tcl_Interp *interp; Tcl_Channel chan; { PipeState *pipePtr; Tcl_ChannelType *chanTypePtr; int i; char buf[TCL_INTEGER_SPACE]; /* * Punt if the channel is not a command channel. */ chanTypePtr = Tcl_GetChannelType(chan); if (chanTypePtr != &pipeChannelType) { return; } pipePtr = (PipeState *) Tcl_GetChannelInstanceData(chan); for (i = 0; i < pipePtr->numPids; i++) { TclFormatInt(buf, (long) TclpGetPid(pipePtr->pidPtr[i])); Tcl_AppendElement(interp, buf); Tcl_DetachPids(1, &(pipePtr->pidPtr[i])); } if (pipePtr->numPids > 0) { ckfree((char *) pipePtr->pidPtr); pipePtr->numPids = 0; } } /* *---------------------------------------------------------------------- * * PipeBlockModeProc -- * * Helper procedure to set blocking and nonblocking modes on a * pipe based channel. Invoked by generic IO level code. * * Results: * 0 if successful, errno when failed. * * Side effects: * Sets the device into blocking or non-blocking mode. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int PipeBlockModeProc(instanceData, mode) ClientData instanceData; /* Pipe state. */ int mode; /* The mode to set. Can be one of * TCL_MODE_BLOCKING or * TCL_MODE_NONBLOCKING. */ { PipeState *psPtr = (PipeState *) instanceData; int curStatus; int fd; #ifndef USE_FIONBIO if (psPtr->inFile) { fd = GetFd(psPtr->inFile); curStatus = fcntl(fd, F_GETFL); if (mode == TCL_MODE_BLOCKING) { curStatus &= (~(O_NONBLOCK)); } else { curStatus |= O_NONBLOCK; } if (fcntl(fd, F_SETFL, curStatus) < 0) { return errno; } } if (psPtr->outFile) { fd = GetFd(psPtr->outFile); curStatus = fcntl(fd, F_GETFL); if (mode == TCL_MODE_BLOCKING) { curStatus &= (~(O_NONBLOCK)); } else { curStatus |= O_NONBLOCK; } if (fcntl(fd, F_SETFL, curStatus) < 0) { return errno; } } #endif /* !FIONBIO */ #ifdef USE_FIONBIO if (psPtr->inFile) { fd = GetFd(psPtr->inFile); if (mode == TCL_MODE_BLOCKING) { curStatus = 0; } else { curStatus = 1; } if (ioctl(fd, (int) FIONBIO, &curStatus) < 0) { return errno; } } if (psPtr->outFile != NULL) { fd = GetFd(psPtr->outFile); if (mode == TCL_MODE_BLOCKING) { curStatus = 0; } else { curStatus = 1; } if (ioctl(fd, (int) FIONBIO, &curStatus) < 0) { return errno; } } #endif /* USE_FIONBIO */ psPtr->isNonBlocking = (mode == TCL_MODE_NONBLOCKING); return 0; } /* *---------------------------------------------------------------------- * * PipeCloseProc -- * * This procedure is invoked by the generic IO level to perform * channel-type-specific cleanup when a command pipeline channel * is closed. * * Results: * 0 on success, errno otherwise. * * Side effects: * Closes the command pipeline channel. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int PipeCloseProc(instanceData, interp) ClientData instanceData; /* The pipe to close. */ Tcl_Interp *interp; /* For error reporting. */ { PipeState *pipePtr; Tcl_Channel errChan; int errorCode, result; errorCode = 0; result = 0; pipePtr = (PipeState *) instanceData; if (pipePtr->inFile) { if (TclpCloseFile(pipePtr->inFile) < 0) { errorCode = errno; } } if (pipePtr->outFile) { if ((TclpCloseFile(pipePtr->outFile) < 0) && (errorCode == 0)) { errorCode = errno; } } if (pipePtr->isNonBlocking || TclInExit()) { /* * If the channel is non-blocking or Tcl is being cleaned up, just * detach the children PIDs, reap them (important if we are in a * dynamic load module), and discard the errorFile. */ Tcl_DetachPids(pipePtr->numPids, pipePtr->pidPtr); Tcl_ReapDetachedProcs(); if (pipePtr->errorFile) { TclpCloseFile(pipePtr->errorFile); } } else { /* * Wrap the error file into a channel and give it to the cleanup * routine. */ if (pipePtr->errorFile) { errChan = Tcl_MakeFileChannel( (ClientData) GetFd(pipePtr->errorFile), TCL_READABLE); } else { errChan = NULL; } result = TclCleanupChildren(interp, pipePtr->numPids, pipePtr->pidPtr, errChan); } if (pipePtr->numPids != 0) { ckfree((char *) pipePtr->pidPtr); } ckfree((char *) pipePtr); if (errorCode == 0) { return result; } return errorCode; } /* *---------------------------------------------------------------------- * * PipeInputProc -- * * This procedure is invoked from the generic IO level to read * input from a command pipeline based channel. * * Results: * The number of bytes read is returned or -1 on error. An output * argument contains a POSIX error code if an error occurs, or zero. * * Side effects: * Reads input from the input device of the channel. * *---------------------------------------------------------------------- */ static int PipeInputProc(instanceData, buf, toRead, errorCodePtr) ClientData instanceData; /* Pipe state. */ char *buf; /* Where to store data read. */ int toRead; /* How much space is available * in the buffer? */ int *errorCodePtr; /* Where to store error code. */ { PipeState *psPtr = (PipeState *) instanceData; int bytesRead; /* How many bytes were actually * read from the input device? */ *errorCodePtr = 0; /* * Assume there is always enough input available. This will block * appropriately, and read will unblock as soon as a short read is * possible, if the channel is in blocking mode. If the channel is * nonblocking, the read will never block. * Some OSes can throw an interrupt error, for which we should * immediately retry. [Bug #415131] */ do { bytesRead = read (GetFd(psPtr->inFile), buf, (size_t) toRead); } while ((bytesRead < 0) && (errno == EINTR)); if (bytesRead < 0) { *errorCodePtr = errno; return -1; } else { return bytesRead; } } /* *---------------------------------------------------------------------- * * PipeOutputProc-- * * This procedure is invoked from the generic IO level to write * output to a command pipeline based channel. * * Results: * The number of bytes written is returned or -1 on error. An * output argument contains a POSIX error code if an error occurred, * or zero. * * Side effects: * Writes output on the output device of the channel. * *---------------------------------------------------------------------- */ static int PipeOutputProc(instanceData, buf, toWrite, errorCodePtr) ClientData instanceData; /* Pipe state. */ CONST char *buf; /* The data buffer. */ int toWrite; /* How many bytes to write? */ int *errorCodePtr; /* Where to store error code. */ { PipeState *psPtr = (PipeState *) instanceData; int written; *errorCodePtr = 0; /* * Some OSes can throw an interrupt error, for which we should * immediately retry. [Bug #415131] */ do { written = write(GetFd(psPtr->outFile), buf, (size_t) toWrite); } while ((written < 0) && (errno == EINTR)); if (written < 0) { *errorCodePtr = errno; return -1; } else { return written; } } /* *---------------------------------------------------------------------- * * PipeWatchProc -- * * Initialize the notifier to watch the fds from this channel. * * Results: * None. * * Side effects: * Sets up the notifier so that a future event on the channel will * be seen by Tcl. * *---------------------------------------------------------------------- */ static void PipeWatchProc(instanceData, mask) ClientData instanceData; /* The pipe state. */ int mask; /* Events of interest; an OR-ed * combination of TCL_READABLE, * TCL_WRITABEL and TCL_EXCEPTION. */ { PipeState *psPtr = (PipeState *) instanceData; int newmask; if (psPtr->inFile) { newmask = mask & (TCL_READABLE | TCL_EXCEPTION); if (newmask) { Tcl_CreateFileHandler(GetFd(psPtr->inFile), mask, (Tcl_FileProc *) Tcl_NotifyChannel, (ClientData) psPtr->channel); } else { Tcl_DeleteFileHandler(GetFd(psPtr->inFile)); } } if (psPtr->outFile) { newmask = mask & (TCL_WRITABLE | TCL_EXCEPTION); if (newmask) { Tcl_CreateFileHandler(GetFd(psPtr->outFile), mask, (Tcl_FileProc *) Tcl_NotifyChannel, (ClientData) psPtr->channel); } else { Tcl_DeleteFileHandler(GetFd(psPtr->outFile)); } } } /* *---------------------------------------------------------------------- * * PipeGetHandleProc -- * * Called from Tcl_GetChannelHandle to retrieve OS handles from * inside a command pipeline based channel. * * Results: * Returns TCL_OK with the fd in handlePtr, or TCL_ERROR if * there is no handle for the specified direction. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int PipeGetHandleProc(instanceData, direction, handlePtr) ClientData instanceData; /* The pipe state. */ int direction; /* TCL_READABLE or TCL_WRITABLE */ ClientData *handlePtr; /* Where to store the handle. */ { PipeState *psPtr = (PipeState *) instanceData; if (direction == TCL_READABLE && psPtr->inFile) { *handlePtr = (ClientData) GetFd(psPtr->inFile); return TCL_OK; } if (direction == TCL_WRITABLE && psPtr->outFile) { *handlePtr = (ClientData) GetFd(psPtr->outFile); return TCL_OK; } return TCL_ERROR; } /* *---------------------------------------------------------------------- * * Tcl_WaitPid -- * * Implements the waitpid system call on Unix systems. * * Results: * Result of calling waitpid. * * Side effects: * Waits for a process to terminate. * *---------------------------------------------------------------------- */ Tcl_Pid Tcl_WaitPid(pid, statPtr, options) Tcl_Pid pid; int *statPtr; int options; { int result; pid_t real_pid; real_pid = (pid_t) pid; while (1) { result = (int) waitpid(real_pid, statPtr, options); if ((result != -1) || (errno != EINTR)) { return (Tcl_Pid) result; } } } /* *---------------------------------------------------------------------- * * Tcl_PidObjCmd -- * * This procedure is invoked to process the "pid" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_PidObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST *objv; /* Argument strings. */ { Tcl_Channel chan; Tcl_ChannelType *chanTypePtr; PipeState *pipePtr; int i; Tcl_Obj *resultPtr, *longObjPtr; if (objc > 2) { Tcl_WrongNumArgs(interp, 1, objv, "?channelId?"); return TCL_ERROR; } if (objc == 1) { Tcl_SetLongObj(Tcl_GetObjResult(interp), (long) getpid()); } else { chan = Tcl_GetChannel(interp, Tcl_GetString(objv[1]), NULL); if (chan == (Tcl_Channel) NULL) { return TCL_ERROR; } chanTypePtr = Tcl_GetChannelType(chan); if (chanTypePtr != &pipeChannelType) { return TCL_OK; } pipePtr = (PipeState *) Tcl_GetChannelInstanceData(chan); resultPtr = Tcl_GetObjResult(interp); for (i = 0; i < pipePtr->numPids; i++) { longObjPtr = Tcl_NewLongObj((long) TclpGetPid(pipePtr->pidPtr[i])); Tcl_ListObjAppendElement(NULL, resultPtr, longObjPtr); } } return TCL_OK; } /* *---------------------------------------------------------------------- * * TclpFinalizePipes -- * * Cleans up the pipe subsystem from Tcl_FinalizeThread * * Results: * None. * * This procedure carries out no operation on Unix. * *---------------------------------------------------------------------- */ void TclpFinalizePipes() { } tcl8.4.20/unix/tclLoadDld.c0000644003604700454610000001266211737050675014064 0ustar dgp771div/* * tclLoadDld.c -- * * This procedure provides a version of the TclLoadFile that * works with the "dld_link" and "dld_get_func" library procedures * for dynamic loading. It has been tested on Linux 1.1.95 and * dld-3.2.7. This file probably isn't needed anymore, since it * makes more sense to use "dl_open" etc. * * Copyright (c) 1995-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "dld.h" /* * In some systems, like SunOS 4.1.3, the RTLD_NOW flag isn't defined * and this argument to dlopen must always be 1. */ #ifndef RTLD_NOW # define RTLD_NOW 1 #endif /* *---------------------------------------------------------------------- * * TclpDlopen -- * * Dynamically loads a binary code file into memory and returns * a handle to the new code. * * Results: * A standard Tcl completion code. If an error occurs, an error * message is left in the interp's result. * * Side effects: * New code suddenly appears in memory. * *---------------------------------------------------------------------- */ int TclpDlopen(interp, pathPtr, loadHandle, unloadProcPtr) Tcl_Interp *interp; /* Used for error reporting. */ Tcl_Obj *pathPtr; /* Name of the file containing the desired * code (UTF-8). */ Tcl_LoadHandle *loadHandle; /* Filled with token for dynamically loaded * file which will be passed back to * (*unloadProcPtr)() to unload the file. */ Tcl_FSUnloadFileProc **unloadProcPtr; /* Filled with address of Tcl_FSUnloadFileProc * function which should be used for * this file. */ { static int firstTime = 1; int returnCode; char *fileName; CONST char *native; /* * The dld package needs to know the pathname to the tcl binary. * If that's not known, return an error. */ if (firstTime) { if (tclExecutableName == NULL) { Tcl_SetResult(interp, "don't know name of application binary file, so can't initialize dynamic loader", TCL_STATIC); return TCL_ERROR; } returnCode = dld_init(tclExecutableName); if (returnCode != 0) { Tcl_AppendResult(interp, "initialization failed for dynamic loader: ", dld_strerror(returnCode), (char *) NULL); return TCL_ERROR; } firstTime = 0; } fileName = Tcl_GetString(pathPtr); /* * First try the full path the user gave us. This is particularly * important if the cwd is inside a vfs, and we are trying to load * using a relative path. */ native = Tcl_FSGetNativePath(pathPtr); returnCode = dld_link(native); if (returnCode != 0) { Tcl_DString ds; native = Tcl_UtfToExternalDString(NULL, fileName, -1, &ds); returnCode = dld_link(native); Tcl_DStringFree(&ds); } if (returnCode != 0) { Tcl_AppendResult(interp, "couldn't load file \"", fileName, "\": ", dld_strerror(returnCode), (char *) NULL); return TCL_ERROR; } *loadHandle = (Tcl_LoadHandle) strcpy( (char *) ckalloc((unsigned) (strlen(fileName) + 1)), fileName); *unloadProcPtr = &TclpUnloadFile; return TCL_OK; } /* *---------------------------------------------------------------------- * * TclpFindSymbol -- * * Looks up a symbol, by name, through a handle associated with * a previously loaded piece of code (shared library). * * Results: * Returns a pointer to the function associated with 'symbol' if * it is found. Otherwise returns NULL and may leave an error * message in the interp's result. * *---------------------------------------------------------------------- */ Tcl_PackageInitProc* TclpFindSymbol(interp, loadHandle, symbol) Tcl_Interp *interp; Tcl_LoadHandle loadHandle; CONST char *symbol; { return (Tcl_PackageInitProc *) dld_get_func(symbol); } /* *---------------------------------------------------------------------- * * TclpUnloadFile -- * * Unloads a dynamically loaded binary code file from memory. * Code pointers in the formerly loaded file are no longer valid * after calling this function. * * Results: * None. * * Side effects: * Code removed from memory. * *---------------------------------------------------------------------- */ void TclpUnloadFile(loadHandle) Tcl_LoadHandle loadHandle; /* loadHandle returned by a previous call * to TclpDlopen(). The loadHandle is * a token that represents the loaded * file. */ { char *fileName; handle = (char *) loadHandle; dld_unlink_by_file(handle, 0); ckfree(handle); } /* *---------------------------------------------------------------------- * * TclGuessPackageName -- * * If the "load" command is invoked without providing a package * name, this procedure is invoked to try to figure it out. * * Results: * Always returns 0 to indicate that we couldn't figure out a * package name; generic code will then try to guess the package * from the file name. A return value of 1 would have meant that * we figured out the package name and put it in bufPtr. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclGuessPackageName(fileName, bufPtr) CONST char *fileName; /* Name of file containing package (already * translated to local form if needed). */ Tcl_DString *bufPtr; /* Initialized empty dstring. Append * package name to this if possible. */ { return 0; } tcl8.4.20/unix/tclUnixCompat.c0000644003604700454610000004332612133546540014641 0ustar dgp771div/* * tclUnixCompat.c * * Written by: Zoran Vasiljevic (vasiljevic@users.sourceforge.net). * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" #include #include #include #include /* * Used to pad structures at size'd boundaries * * This macro assumes that the pointer 'buffer' was created from an * aligned pointer by adding the 'length'. If this 'length' was not a * multiple of the 'size' the result is unaligned and PadBuffer * corrects both the pointer, _and_ the 'length'. The latter means * that future increments of 'buffer' by 'length' stay aligned. */ #define PadBuffer(buffer, length, size) \ if (((length) % (size))) { \ (buffer) += ((size) - ((length) % (size))); \ (length) += ((size) - ((length) % (size))); \ } /* * Per-thread private storage used to store values * returned from MT-unsafe library calls. */ #ifdef TCL_THREADS typedef struct ThreadSpecificData { struct passwd pwd; char pbuf[2048]; struct group grp; char gbuf[2048]; #if !defined(HAVE_MTSAFE_GETHOSTBYNAME) || !defined(HAVE_MTSAFE_GETHOSTBYADDR) struct hostent hent; char hbuf[2048]; #endif } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; #if ((!defined(HAVE_GETHOSTBYNAME_R) || !defined(HAVE_GETHOSTBYADDR_R)) && \ (!defined(HAVE_MTSAFE_GETHOSTBYNAME) || !defined(HAVE_MTSAFE_GETHOSTBYADDR))) || \ !defined(HAVE_GETPWNAM_R) || !defined(HAVE_GETPWUID_R) || \ !defined(HAVE_GETGRNAM_R) || !defined(HAVE_GETGRGID_R) /* * Mutex to lock access to MT-unsafe calls. This is just to protect * our own usage. It does not protect us from others calling the * same functions without (or using some different) lock. */ static Tcl_Mutex compatLock; /* *--------------------------------------------------------------------------- * * CopyArray -- * * Copies array of NULL-terminated or fixed-length strings * to the private buffer, honouring the size of the buffer. * * Results: * Number of bytes copied on success or -1 on error (errno = ERANGE) * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int CopyArray(char **src, int elsize, char *buf, int buflen) { int i, j, len = 0; char *p, **new; if (src == NULL) { return 0; } for (i = 0; src[i] != NULL; i++) { /* Empty loop to count howmany */ } if ((sizeof(char *)*(i + 1)) > buflen) { return -1; } len = (sizeof(char *)*(i + 1)); /* Leave place for the array */ new = (char **)buf; p = buf + (sizeof(char *)*(i + 1)); for (j = 0; j < i; j++) { if (elsize < 0) { len += strlen(src[j]) + 1; } else { len += elsize; } if (len > buflen) { return -1; } if (elsize < 0) { strcpy(p, src[j]); } else { memcpy(p, src[j], elsize); } new[j] = p; p = buf + len; } new[j] = NULL; return len; } /* *--------------------------------------------------------------------------- * * CopyString -- * * Copies a NULL-terminated string to the private buffer, * honouring the size of the buffer * * Results: * 0 success or -1 on error (errno = ERANGE) * * Side effects: * None * *--------------------------------------------------------------------------- */ static int CopyString(CONST char *src, char *buf, int buflen) { int len = 0; if (src != NULL) { len += strlen(src) + 1; if (len > buflen) { return -1; } strcpy(buf, src); } return len; } #endif /* ((!defined(HAVE_GETHOSTBYNAME_R) || !defined(HAVE_GETHOSTBYADDR_R)) && \ (!defined(HAVE_MTSAFE_GETHOSTBYNAME) || !defined(HAVE_MTSAFE_GETHOSTBYADDR))) || \ !defined(HAVE_GETPWNAM_R) || !defined(HAVE_GETPWUID_R) || \ !defined(HAVE_GETGRNAM_R) || !defined(HAVE_GETGRGID_R) */ #if (!defined(HAVE_GETHOSTBYNAME_R) || !defined(HAVE_GETHOSTBYADDR_R)) && \ (!defined(HAVE_MTSAFE_GETHOSTBYNAME) || !defined(HAVE_MTSAFE_GETHOSTBYADDR)) /* *--------------------------------------------------------------------------- * * CopyHostnent -- * * Copies string fields of the hostnent structure to the * private buffer, honouring the size of the buffer. * * Results: * Number of bytes copied on success or -1 on error (errno = ERANGE) * * Side effects: * None * *--------------------------------------------------------------------------- */ static int CopyHostent(struct hostent *tgtPtr, char *buf, int buflen) { char *p = buf; int copied, len = 0; copied = CopyString(tgtPtr->h_name, p, buflen - len); if (copied == -1) { range: errno = ERANGE; return -1; } tgtPtr->h_name = (copied > 0) ? p : NULL; len += copied; p = buf + len; PadBuffer(p, len, sizeof(char *)); copied = CopyArray(tgtPtr->h_aliases, -1, p, buflen - len); if (copied == -1) { goto range; } tgtPtr->h_aliases = (copied > 0) ? (char **)p : NULL; len += copied; p += len; PadBuffer(p, len, sizeof(char *)); copied = CopyArray(tgtPtr->h_addr_list, tgtPtr->h_length, p, buflen - len); if (copied == -1) { goto range; } tgtPtr->h_addr_list = (copied > 0) ? (char **)p : NULL; return 0; } #endif /* (!defined(HAVE_GETHOSTBYNAME_R) || !defined(HAVE_GETHOSTBYADDR_R)) && \ (!defined(HAVE_MTSAFE_GETHOSTBYNAME) || !defined(HAVE_MTSAFE_GETHOSTBYADDR)) */ #if !defined(HAVE_GETPWNAM_R) || !defined(HAVE_GETPWUID_R) /* *--------------------------------------------------------------------------- * * CopyPwd -- * * Copies string fields of the passwd structure to the * private buffer, honouring the size of the buffer. * * Results: * 0 on success or -1 on error (errno = ERANGE) * * Side effects: * We are not copying the gecos field as it may not be supported * on all platforms. * *--------------------------------------------------------------------------- */ static int CopyPwd(struct passwd *tgtPtr, char *buf, int buflen) { char *p = buf; int copied, len = 0; copied = CopyString(tgtPtr->pw_name, p, buflen - len); if (copied == -1) { range: errno = ERANGE; return -1; } tgtPtr->pw_name = (copied > 0) ? p : NULL; len += copied; p = buf + len; copied = CopyString(tgtPtr->pw_passwd, p, buflen - len); if (copied == -1) { goto range; } tgtPtr->pw_passwd = (copied > 0) ? p : NULL; len += copied; p = buf + len; copied = CopyString(tgtPtr->pw_dir, p, buflen - len); if (copied == -1) { goto range; } tgtPtr->pw_dir = (copied > 0) ? p : NULL; len += copied; p = buf + len; copied = CopyString(tgtPtr->pw_shell, p, buflen - len); if (copied == -1) { goto range; } tgtPtr->pw_shell = (copied > 0) ? p : NULL; return 0; } #endif /* !defined(HAVE_GETPWNAM_R) || !defined(HAVE_GETPWUID_R) */ #if !defined(HAVE_GETGRNAM_R) || !defined(HAVE_GETGRGID_R) /* *--------------------------------------------------------------------------- * * CopyGrp -- * * Copies string fields of the group structure to the * private buffer, honouring the size of the buffer. * * Results: * 0 on success or -1 on error (errno = ERANGE) * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int CopyGrp(struct group *tgtPtr, char *buf, int buflen) { register char *p = buf; register int copied, len = 0; /* Copy username */ copied = CopyString(tgtPtr->gr_name, p, buflen - len); if (copied == -1) { range: errno = ERANGE; return -1; } tgtPtr->gr_name = (copied > 0) ? p : NULL; len += copied; p = buf + len; /* Copy password */ copied = CopyString(tgtPtr->gr_passwd, p, buflen - len); if (copied == -1) { goto range; } tgtPtr->gr_passwd = (copied > 0) ? p : NULL; len += copied; p = buf + len; /* Copy group members */ PadBuffer(p, len, sizeof(char *)); copied = CopyArray((char **)tgtPtr->gr_mem, -1, p, buflen - len); if (copied == -1) { goto range; } tgtPtr->gr_mem = (copied > 0) ? (char **)p : NULL; return 0; } #endif /* !defined(HAVE_GETGRNAM_R) || !defined(HAVE_GETGRGID_R) */ #endif /* TCL_THREADS */ /* *--------------------------------------------------------------------------- * * TclpGetPwNam -- * * Thread-safe wrappers for getpwnam(). * See "man getpwnam" for more details. * * Results: * Pointer to struct passwd on success or NULL on error. * * Side effects: * None. * *--------------------------------------------------------------------------- */ struct passwd * TclpGetPwNam(const char *name) { #if !defined(TCL_THREADS) return getpwnam(name); #else ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); #if defined(HAVE_GETPWNAM_R_5) struct passwd *pwPtr = NULL; return (getpwnam_r(name, &tsdPtr->pwd, tsdPtr->pbuf, sizeof(tsdPtr->pbuf), &pwPtr) == 0 && pwPtr != NULL) ? &tsdPtr->pwd : NULL; #elif defined(HAVE_GETPWNAM_R_4) return getpwnam_r(name, &tsdPtr->pwd, tsdPtr->pbuf, sizeof(tsdPtr->pbuf)); #else struct passwd *pwPtr; Tcl_MutexLock(&compatLock); pwPtr = getpwnam(name); if (pwPtr != NULL) { tsdPtr->pwd = *pwPtr; pwPtr = &tsdPtr->pwd; if (CopyPwd(&tsdPtr->pwd, tsdPtr->pbuf, sizeof(tsdPtr->pbuf)) == -1) { pwPtr = NULL; } } Tcl_MutexUnlock(&compatLock); return pwPtr; #endif return NULL; /* Not reached */ #endif /* TCL_THREADS */ } /* *--------------------------------------------------------------------------- * * TclpGetPwUid -- * * Thread-safe wrappers for getpwuid(). * See "man getpwuid" for more details. * * Results: * Pointer to struct passwd on success or NULL on error. * * Side effects: * None. * *--------------------------------------------------------------------------- */ struct passwd * TclpGetPwUid(uid_t uid) { #if !defined(TCL_THREADS) return getpwuid(uid); #else ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); #if defined(HAVE_GETPWUID_R_5) struct passwd *pwPtr = NULL; return (getpwuid_r(uid, &tsdPtr->pwd, tsdPtr->pbuf, sizeof(tsdPtr->pbuf), &pwPtr) == 0 && pwPtr != NULL) ? &tsdPtr->pwd : NULL; #elif defined(HAVE_GETPWUID_R_4) return getpwuid_r(uid, &tsdPtr->pwd, tsdPtr->pbuf, sizeof(tsdPtr->pbuf)); #else struct passwd *pwPtr; Tcl_MutexLock(&compatLock); pwPtr = getpwuid(uid); if (pwPtr != NULL) { tsdPtr->pwd = *pwPtr; pwPtr = &tsdPtr->pwd; if (CopyPwd(&tsdPtr->pwd, tsdPtr->pbuf, sizeof(tsdPtr->pbuf)) == -1) { pwPtr = NULL; } } Tcl_MutexUnlock(&compatLock); return pwPtr; #endif return NULL; /* Not reached */ #endif /* TCL_THREADS */ } /* *--------------------------------------------------------------------------- * * TclpGetGrNam -- * * Thread-safe wrappers for getgrnam(). * See "man getgrnam" for more details. * * Results: * Pointer to struct group on success or NULL on error. * * Side effects: * None. * *--------------------------------------------------------------------------- */ struct group * TclpGetGrNam(const char *name) { #if !defined(TCL_THREADS) return getgrnam(name); #else ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); #if defined(HAVE_GETGRNAM_R_5) struct group *grPtr = NULL; return (getgrnam_r(name, &tsdPtr->grp, tsdPtr->gbuf, sizeof(tsdPtr->gbuf), &grPtr) == 0 && grPtr != NULL) ? &tsdPtr->grp : NULL; #elif defined(HAVE_GETGRNAM_R_4) return getgrnam_r(name, &tsdPtr->grp, tsdPtr->gbuf, sizeof(tsdPtr->gbuf)); #else struct group *grPtr; Tcl_MutexLock(&compatLock); grPtr = getgrnam(name); if (grPtr != NULL) { tsdPtr->grp = *grPtr; grPtr = &tsdPtr->grp; if (CopyGrp(&tsdPtr->grp, tsdPtr->gbuf, sizeof(tsdPtr->gbuf)) == -1) { grPtr = NULL; } } Tcl_MutexUnlock(&compatLock); return grPtr; #endif return NULL; /* Not reached */ #endif /* TCL_THREADS */ } /* *--------------------------------------------------------------------------- * * TclpGetGrGid -- * * Thread-safe wrappers for getgrgid(). * See "man getgrgid" for more details. * * Results: * Pointer to struct group on success or NULL on error. * * Side effects: * None. * *--------------------------------------------------------------------------- */ struct group * TclpGetGrGid(gid_t gid) { #if !defined(TCL_THREADS) return getgrgid(gid); #else ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); #if defined(HAVE_GETGRGID_R_5) struct group *grPtr = NULL; return (getgrgid_r(gid, &tsdPtr->grp, tsdPtr->gbuf, sizeof(tsdPtr->gbuf), &grPtr) == 0 && grPtr != NULL) ? &tsdPtr->grp : NULL; #elif defined(HAVE_GETGRGID_R_4) return getgrgid_r(gid, &tsdPtr->grp, tsdPtr->gbuf, sizeof(tsdPtr->gbuf)); #else struct group *grPtr; Tcl_MutexLock(&compatLock); grPtr = getgrgid(gid); if (grPtr != NULL) { tsdPtr->grp = *grPtr; grPtr = &tsdPtr->grp; if (CopyGrp(&tsdPtr->grp, tsdPtr->gbuf, sizeof(tsdPtr->gbuf)) == -1) { grPtr = NULL; } } Tcl_MutexUnlock(&compatLock); return grPtr; #endif return NULL; /* Not reached */ #endif /* TCL_THREADS */ } /* *--------------------------------------------------------------------------- * * TclpGetHostByName -- * * Thread-safe wrappers for gethostbyname(). * See "man gethostbyname" for more details. * * Results: * Pointer to struct hostent on success or NULL on error. * * Side effects: * None. * *--------------------------------------------------------------------------- */ struct hostent * TclpGetHostByName(const char *name) { #if !defined(TCL_THREADS) || defined(HAVE_MTSAFE_GETHOSTBYNAME) return gethostbyname(name); #else ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); #if defined(HAVE_GETHOSTBYNAME_R_5) int h_errno; return gethostbyname_r(name, &tsdPtr->hent, tsdPtr->hbuf, sizeof(tsdPtr->hbuf), &h_errno); #elif defined(HAVE_GETHOSTBYNAME_R_6) struct hostent *hePtr; int result, h_errno; result = gethostbyname_r(name, &tsdPtr->hent, tsdPtr->hbuf, sizeof(tsdPtr->hbuf), &hePtr, &h_errno); return (result == 0) ? hePtr : NULL; #elif defined(HAVE_GETHOSTBYNAME_R_3) struct hostent_data data; return (gethostbyname_r(name, &tsdPtr->hent, &data) == 0) ? &tsdPtr->hent : NULL; #else struct hostent *hePtr; Tcl_MutexLock(&compatLock); hePtr = gethostbyname(name); if (hePtr != NULL) { tsdPtr->hent = *hePtr; hePtr = &tsdPtr->hent; if (CopyHostent(&tsdPtr->hent, tsdPtr->hbuf, sizeof(tsdPtr->hbuf)) == -1) { hePtr = NULL; } } Tcl_MutexUnlock(&compatLock); return hePtr; #endif return NULL; /* Not reached */ #endif /* TCL_THREADS */ } /* *--------------------------------------------------------------------------- * * TclpGetHostByAddr -- * * Thread-safe wrappers for gethostbyaddr(). * See "man gethostbyaddr" for more details. * * Results: * Pointer to struct hostent on success or NULL on error. * * Side effects: * None. * *--------------------------------------------------------------------------- */ struct hostent * TclpGetHostByAddr(const char *addr, int length, int type) { #if !defined(TCL_THREADS) || defined(HAVE_MTSAFE_GETHOSTBYADDR) return gethostbyaddr(addr, length, type); #else ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); #if defined(HAVE_GETHOSTBYADDR_R_7) int h_errno; return gethostbyaddr_r(addr, length, type, &tsdPtr->hent, tsdPtr->hbuf, sizeof(tsdPtr->hbuf), &h_errno); #elif defined(HAVE_GETHOSTBYADDR_R_8) struct hostent *hePtr; int h_errno; return (gethostbyaddr_r(addr, length, type, &tsdPtr->hent, tsdPtr->hbuf, sizeof(tsdPtr->hbuf), &hePtr, &h_errno) == 0) ? &tsdPtr->hent : NULL; #else struct hostent *hePtr; Tcl_MutexLock(&compatLock); hePtr = gethostbyaddr(addr, length, type); if (hePtr != NULL) { tsdPtr->hent = *hePtr; hePtr = &tsdPtr->hent; if (CopyHostent(&tsdPtr->hent, tsdPtr->hbuf, sizeof(tsdPtr->hbuf)) == -1) { hePtr = NULL; } } Tcl_MutexUnlock(&compatLock); return hePtr; #endif return NULL; /* Not reached */ #endif /* TCL_THREADS */ } /* *------------------------------------------------------------------------ * * TclWinCPUID -- * * Get CPU ID information on an Intel box under UNIX (either Linux or Cygwin) * * Results: * Returns TCL_OK if successful, TCL_ERROR if CPUID is not supported. * * Side effects: * If successful, stores EAX, EBX, ECX and EDX registers after the CPUID * instruction in the four integers designated by 'regsPtr' * *---------------------------------------------------------------------- */ int TclWinCPUID( unsigned int index, /* Which CPUID value to retrieve. */ unsigned int *regsPtr) /* Registers after the CPUID. */ { int status = TCL_ERROR; /* See: */ #if defined(HAVE_CPUID) #if defined(__x86_64__) || defined(_M_AMD64) || defined (_M_X64) __asm__ __volatile__("movq %%rbx, %%rsi \n\t" /* save %rbx */ "cpuid \n\t" "xchgq %%rsi, %%rbx \n\t" /* restore the old %rbx */ : "=a"(regsPtr[0]), "=S"(regsPtr[1]), "=c"(regsPtr[2]), "=d"(regsPtr[3]) : "a"(index)); #else __asm__ __volatile__("mov %%ebx, %%esi \n\t" /* save %ebx */ "cpuid \n\t" "xchg %%esi, %%ebx \n\t" /* restore the old %ebx */ : "=a"(regsPtr[0]), "=S"(regsPtr[1]), "=c"(regsPtr[2]), "=d"(regsPtr[3]) : "a"(index)); #endif status = TCL_OK; #endif return status; } /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ tcl8.4.20/unix/tclLoadAix.c0000644003604700454610000003157511737050675014106 0ustar dgp771div/* * tclLoadAix.c -- * * This file implements the dlopen and dlsym APIs under the * AIX operating system, to enable the Tcl "load" command to * work. This code was provided by Jens-Uwe Mager. * * This file is subject to the following copyright notice, which is * different from the notice used elsewhere in Tcl. The file has * been modified to incorporate the file dlfcn.h in-line. * * Copyright (c) 1992,1993,1995,1996, Jens-Uwe Mager, Helios Software GmbH * Not derived from licensed software. * Permission is granted to freely use, copy, modify, and redistribute * this software, provided that the author is not construed to be liable * for any results of using the software, alterations are clearly marked * as such, and this notice is not modified. * * Note: this file has been altered from the original in a few * ways in order to work properly with Tcl. */ /* * @(#)dlfcn.c 1.7 revision of 95/08/14 19:08:38 * This is an unpublished work copyright (c) 1992 HELIOS Software GmbH * 30159 Hannover, Germany */ #include #include #include #include #include #include #include #include #include "../compat/dlfcn.h" /* * We simulate dlopen() et al. through a call to load. Because AIX has * no call to find an exported symbol we read the loader section of the * loaded module and build a list of exported symbols and their virtual * address. */ typedef struct { char *name; /* the symbols's name */ void *addr; /* its relocated virtual address */ } Export, *ExportPtr; /* * xlC uses the following structure to list its constructors and * destructors. This is gleaned from the output of munch. */ typedef struct { void (*init)(void); /* call static constructors */ void (*term)(void); /* call static destructors */ } Cdtor, *CdtorPtr; /* * The void * handle returned from dlopen is actually a ModulePtr. */ typedef struct Module { struct Module *next; char *name; /* module name for refcounting */ int refCnt; /* the number of references */ void *entry; /* entry point from load */ struct dl_info *info; /* optional init/terminate functions */ CdtorPtr cdtors; /* optional C++ constructors */ int nExports; /* the number of exports found */ ExportPtr exports; /* the array of exports */ } Module, *ModulePtr; /* * We keep a list of all loaded modules to be able to call the fini * handlers and destructors at atexit() time. */ static ModulePtr modList; /* * The last error from one of the dl* routines is kept in static * variables here. Each error is returned only once to the caller. */ static char errbuf[BUFSIZ]; static int errvalid; static void caterr(char *); static int readExports(ModulePtr); static void terminate(void); static void *findMain(void); VOID *dlopen(const char *path, int mode) { register ModulePtr mp; static void *mainModule; /* * Upon the first call register a terminate handler that will * close all libraries. Also get a reference to the main module * for use with loadbind. */ if (!mainModule) { if ((mainModule = findMain()) == NULL) return NULL; atexit(terminate); } /* * Scan the list of modules if we have the module already loaded. */ for (mp = modList; mp; mp = mp->next) if (strcmp(mp->name, path) == 0) { mp->refCnt++; return (VOID *) mp; } if ((mp = (ModulePtr)calloc(1, sizeof(*mp))) == NULL) { errvalid++; strcpy(errbuf, "calloc: "); strcat(errbuf, strerror(errno)); return (VOID *) NULL; } mp->name = malloc((unsigned) (strlen(path) + 1)); strcpy(mp->name, path); /* * load should be declared load(const char *...). Thus we * cast the path to a normal char *. Ugly. */ if ((mp->entry = (void *)load((char *)path, L_NOAUTODEFER, NULL)) == NULL) { free(mp->name); free(mp); errvalid++; strcpy(errbuf, "dlopen: "); strcat(errbuf, path); strcat(errbuf, ": "); /* * If AIX says the file is not executable, the error * can be further described by querying the loader about * the last error. */ if (errno == ENOEXEC) { char *tmp[BUFSIZ/sizeof(char *)]; if (loadquery(L_GETMESSAGES, tmp, sizeof(tmp)) == -1) strcpy(errbuf, strerror(errno)); else { char **p; for (p = tmp; *p; p++) caterr(*p); } } else strcat(errbuf, strerror(errno)); return (VOID *) NULL; } mp->refCnt = 1; mp->next = modList; modList = mp; if (loadbind(0, mainModule, mp->entry) == -1) { dlclose(mp); errvalid++; strcpy(errbuf, "loadbind: "); strcat(errbuf, strerror(errno)); return (VOID *) NULL; } /* * If the user wants global binding, loadbind against all other * loaded modules. */ if (mode & RTLD_GLOBAL) { register ModulePtr mp1; for (mp1 = mp->next; mp1; mp1 = mp1->next) if (loadbind(0, mp1->entry, mp->entry) == -1) { dlclose(mp); errvalid++; strcpy(errbuf, "loadbind: "); strcat(errbuf, strerror(errno)); return (VOID *) NULL; } } if (readExports(mp) == -1) { dlclose(mp); return (VOID *) NULL; } /* * If there is a dl_info structure, call the init function. */ if (mp->info = (struct dl_info *)dlsym(mp, "dl_info")) { if (mp->info->init) (*mp->info->init)(); } else errvalid = 0; /* * If the shared object was compiled using xlC we will need * to call static constructors (and later on dlclose destructors). */ if (mp->cdtors = (CdtorPtr)dlsym(mp, "__cdtors")) { while (mp->cdtors->init) { (*mp->cdtors->init)(); mp->cdtors++; } } else errvalid = 0; return (VOID *) mp; } /* * Attempt to decipher an AIX loader error message and append it * to our static error message buffer. */ static void caterr(char *s) { register char *p = s; while (*p >= '0' && *p <= '9') p++; switch(atoi(s)) { /* INTL: "C", UTF safe. */ case L_ERROR_TOOMANY: strcat(errbuf, "to many errors"); break; case L_ERROR_NOLIB: strcat(errbuf, "can't load library"); strcat(errbuf, p); break; case L_ERROR_UNDEF: strcat(errbuf, "can't find symbol"); strcat(errbuf, p); break; case L_ERROR_RLDBAD: strcat(errbuf, "bad RLD"); strcat(errbuf, p); break; case L_ERROR_FORMAT: strcat(errbuf, "bad exec format in"); strcat(errbuf, p); break; case L_ERROR_ERRNO: strcat(errbuf, strerror(atoi(++p))); /* INTL: "C", UTF safe. */ break; default: strcat(errbuf, s); break; } } VOID *dlsym(void *handle, const char *symbol) { register ModulePtr mp = (ModulePtr)handle; register ExportPtr ep; register int i; /* * Could speed up the search, but I assume that one assigns * the result to function pointers anyways. */ for (ep = mp->exports, i = mp->nExports; i; i--, ep++) if (strcmp(ep->name, symbol) == 0) return ep->addr; errvalid++; strcpy(errbuf, "dlsym: undefined symbol "); strcat(errbuf, symbol); return NULL; } char *dlerror(void) { if (errvalid) { errvalid = 0; return errbuf; } return NULL; } int dlclose(void *handle) { register ModulePtr mp = (ModulePtr)handle; int result; register ModulePtr mp1; if (--mp->refCnt > 0) return 0; if (mp->info && mp->info->fini) (*mp->info->fini)(); if (mp->cdtors) while (mp->cdtors->term) { (*mp->cdtors->term)(); mp->cdtors++; } result = unload(mp->entry); if (result == -1) { errvalid++; strcpy(errbuf, strerror(errno)); } if (mp->exports) { register ExportPtr ep; register int i; for (ep = mp->exports, i = mp->nExports; i; i--, ep++) if (ep->name) free(ep->name); free(mp->exports); } if (mp == modList) modList = mp->next; else { for (mp1 = modList; mp1; mp1 = mp1->next) if (mp1->next == mp) { mp1->next = mp->next; break; } } free(mp->name); free(mp); return result; } static void terminate(void) { while (modList) dlclose(modList); } /* * Build the export table from the XCOFF .loader section. */ static int readExports(ModulePtr mp) { LDFILE *ldp = NULL; SCNHDR sh, shdata; LDHDR *lhp; char *ldbuf; LDSYM *ls; int i; ExportPtr ep; if ((ldp = ldopen(mp->name, ldp)) == NULL) { struct ld_info *lp; char *buf; int size = 4*1024; if (errno != ENOENT) { errvalid++; strcpy(errbuf, "readExports: "); strcat(errbuf, strerror(errno)); return -1; } /* * The module might be loaded due to the LIBPATH * environment variable. Search for the loaded * module using L_GETINFO. */ if ((buf = malloc(size)) == NULL) { errvalid++; strcpy(errbuf, "readExports: "); strcat(errbuf, strerror(errno)); return -1; } while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM) { free(buf); size += 4*1024; if ((buf = malloc(size)) == NULL) { errvalid++; strcpy(errbuf, "readExports: "); strcat(errbuf, strerror(errno)); return -1; } } if (i == -1) { errvalid++; strcpy(errbuf, "readExports: "); strcat(errbuf, strerror(errno)); free(buf); return -1; } /* * Traverse the list of loaded modules. The entry point * returned by load() does actually point to the data * segment origin. */ lp = (struct ld_info *)buf; while (lp) { if (lp->ldinfo_dataorg == mp->entry) { ldp = ldopen(lp->ldinfo_filename, ldp); break; } if (lp->ldinfo_next == 0) lp = NULL; else lp = (struct ld_info *)((char *)lp + lp->ldinfo_next); } free(buf); if (!ldp) { errvalid++; strcpy(errbuf, "readExports: "); strcat(errbuf, strerror(errno)); return -1; } } if (TYPE(ldp) != U802TOCMAGIC) { errvalid++; strcpy(errbuf, "readExports: bad magic"); while(ldclose(ldp) == FAILURE) ; return -1; } /* * Get the padding for the data section. This is needed for * AIX 4.1 compilers. This is used when building the final * function pointer to the exported symbol. */ if (ldnshread(ldp, _DATA, &shdata) != SUCCESS) { errvalid++; strcpy(errbuf, "readExports: cannot read data section header"); while(ldclose(ldp) == FAILURE) ; return -1; } if (ldnshread(ldp, _LOADER, &sh) != SUCCESS) { errvalid++; strcpy(errbuf, "readExports: cannot read loader section header"); while(ldclose(ldp) == FAILURE) ; return -1; } /* * We read the complete loader section in one chunk, this makes * finding long symbol names residing in the string table easier. */ if ((ldbuf = (char *)malloc(sh.s_size)) == NULL) { errvalid++; strcpy(errbuf, "readExports: "); strcat(errbuf, strerror(errno)); while(ldclose(ldp) == FAILURE) ; return -1; } if (FSEEK(ldp, sh.s_scnptr, BEGINNING) != OKFSEEK) { errvalid++; strcpy(errbuf, "readExports: cannot seek to loader section"); free(ldbuf); while(ldclose(ldp) == FAILURE) ; return -1; } if (FREAD(ldbuf, sh.s_size, 1, ldp) != 1) { errvalid++; strcpy(errbuf, "readExports: cannot read loader section"); free(ldbuf); while(ldclose(ldp) == FAILURE) ; return -1; } lhp = (LDHDR *)ldbuf; ls = (LDSYM *)(ldbuf+LDHDRSZ); /* * Count the number of exports to include in our export table. */ for (i = lhp->l_nsyms; i; i--, ls++) { if (!LDR_EXPORT(*ls)) continue; mp->nExports++; } if ((mp->exports = (ExportPtr)calloc(mp->nExports, sizeof(*mp->exports))) == NULL) { errvalid++; strcpy(errbuf, "readExports: "); strcat(errbuf, strerror(errno)); free(ldbuf); while(ldclose(ldp) == FAILURE) ; return -1; } /* * Fill in the export table. All entries are relative to * the entry point we got from load. */ ep = mp->exports; ls = (LDSYM *)(ldbuf+LDHDRSZ); for (i = lhp->l_nsyms; i; i--, ls++) { char *symname; char tmpsym[SYMNMLEN+1]; if (!LDR_EXPORT(*ls)) continue; if (ls->l_zeroes == 0) symname = ls->l_offset+lhp->l_stoff+ldbuf; else { /* * The l_name member is not zero terminated, we * must copy the first SYMNMLEN chars and make * sure we have a zero byte at the end. */ strncpy(tmpsym, ls->l_name, SYMNMLEN); tmpsym[SYMNMLEN] = '\0'; symname = tmpsym; } ep->name = malloc((unsigned) (strlen(symname) + 1)); strcpy(ep->name, symname); ep->addr = (void *)((unsigned long)mp->entry + ls->l_value - shdata.s_vaddr); ep++; } free(ldbuf); while(ldclose(ldp) == FAILURE) ; return 0; } /* * Find the main modules entry point. This is used as export pointer * for loadbind() to be able to resolve references to the main part. */ static void * findMain(void) { struct ld_info *lp; char *buf; int size = 4*1024; int i; void *ret; if ((buf = malloc(size)) == NULL) { errvalid++; strcpy(errbuf, "findMain: "); strcat(errbuf, strerror(errno)); return NULL; } while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM) { free(buf); size += 4*1024; if ((buf = malloc(size)) == NULL) { errvalid++; strcpy(errbuf, "findMain: "); strcat(errbuf, strerror(errno)); return NULL; } } if (i == -1) { errvalid++; strcpy(errbuf, "findMain: "); strcat(errbuf, strerror(errno)); free(buf); return NULL; } /* * The first entry is the main module. The entry point * returned by load() does actually point to the data * segment origin. */ lp = (struct ld_info *)buf; ret = lp->ldinfo_dataorg; free(buf); return ret; } tcl8.4.20/unix/tclUnixNotfy.c0000644003604700454610000010220412052456744014512 0ustar dgp771div/* * tclUnixNotify.c -- * * This file contains the implementation of the select-based * Unix-specific notifier, which is the lowest-level part of the * Tcl event loop. This file works together with * ../generic/tclNotify.c. * * Copyright (c) 1995-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" #ifndef HAVE_COREFOUNDATION /* Darwin/Mac OS X CoreFoundation notifier * is in tclMacOSXNotify.c */ #include extern TclStubs tclStubs; extern Tcl_NotifierProcs tclOriginalNotifier; /* * This structure is used to keep track of the notifier info for a * a registered file. */ typedef struct FileHandler { int fd; int mask; /* Mask of desired events: TCL_READABLE, * etc. */ int readyMask; /* Mask of events that have been seen since the * last time file handlers were invoked for * this file. */ Tcl_FileProc *proc; /* Procedure to call, in the style of * Tcl_CreateFileHandler. */ ClientData clientData; /* Argument to pass to proc. */ struct FileHandler *nextPtr;/* Next in list of all files we care about. */ } FileHandler; /* * The following structure is what is added to the Tcl event queue when * file handlers are ready to fire. */ typedef struct FileHandlerEvent { Tcl_Event header; /* Information that is standard for * all events. */ int fd; /* File descriptor that is ready. Used * to find the FileHandler structure for * the file (can't point directly to the * FileHandler structure because it could * go away while the event is queued). */ } FileHandlerEvent; /* * * The following structure contains a set of select() masks to track * readable, writable, and exceptional conditions. */ typedef struct SelectMasks { fd_set readable; fd_set writable; fd_set exceptional; } SelectMasks; /* * The following static structure contains the state information for the * select based implementation of the Tcl notifier. One of these structures * is created for each thread that is using the notifier. */ typedef struct ThreadSpecificData { FileHandler *firstFileHandlerPtr; /* Pointer to head of file handler list. */ SelectMasks checkMasks; /* This structure is used to build up the masks * to be used in the next call to select. * Bits are set in response to calls to * Tcl_CreateFileHandler. */ SelectMasks readyMasks; /* This array reflects the readable/writable * conditions that were found to exist by the * last call to select. */ int numFdBits; /* Number of valid bits in checkMasks * (one more than highest fd for which * Tcl_WatchFile has been called). */ #ifdef TCL_THREADS int onList; /* True if it is in this list */ unsigned int pollState; /* pollState is used to implement a polling * handshake between each thread and the * notifier thread. Bits defined below. */ struct ThreadSpecificData *nextPtr, *prevPtr; /* All threads that are currently waiting on * an event have their ThreadSpecificData * structure on a doubly-linked listed formed * from these pointers. You must hold the * notifierMutex lock before accessing these * fields. */ #ifdef __CYGWIN__ void *event; /* Any other thread alerts a notifier * that an event is ready to be processed * by sending this event. */ void *hwnd; /* Messaging window. */ #else /* !__CYGWIN__ */ Tcl_Condition waitCV; /* Any other thread alerts a notifier * that an event is ready to be processed * by signaling this condition variable. */ #endif /* __CYGWIN__ */ int eventReady; /* True if an event is ready to be processed. * Used as condition flag together with * waitCV above. */ #endif } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; #ifdef TCL_THREADS /* * The following static indicates the number of threads that have * initialized notifiers. * * You must hold the notifierMutex lock before accessing this variable. */ static int notifierCount = 0; /* * The following variable points to the head of a doubly-linked list of * of ThreadSpecificData structures for all threads that are currently * waiting on an event. * * You must hold the notifierMutex lock before accessing this list. */ static ThreadSpecificData *waitingListPtr = NULL; /* * The notifier thread spends all its time in select() waiting for a * file descriptor associated with one of the threads on the waitingListPtr * list to do something interesting. But if the contents of the * waitingListPtr list ever changes, we need to wake up and restart * the select() system call. You can wake up the notifier thread by * writing a single byte to the file descriptor defined below. This * file descriptor is the input-end of a pipe and the notifier thread is * listening for data on the output-end of the same pipe. Hence writing * to this file descriptor will cause the select() system call to return * and wake up the notifier thread. * * You must hold the notifierMutex lock before accessing this list. */ static int triggerPipe = -1; /* * The notifierMutex locks access to all of the global notifier state. */ TCL_DECLARE_MUTEX(notifierMutex) /* * The notifier thread signals the notifierCV when it has finished * initializing the triggerPipe and right before the notifier * thread terminates. */ static Tcl_Condition notifierCV; /* * The pollState bits * POLL_WANT is set by each thread before it waits on its condition * variable. It is checked by the notifier before it does * select. * POLL_DONE is set by the notifier if it goes into select after * seeing POLL_WANT. The idea is to ensure it tries a select * with the same bits the initial thread had set. */ #define POLL_WANT 0x1 #define POLL_DONE 0x2 /* * This is the thread ID of the notifier thread that does select. */ static Tcl_ThreadId notifierThread; #endif /* * Static routines defined in this file. */ #ifdef TCL_THREADS static void NotifierThreadProc _ANSI_ARGS_((ClientData clientData)); #endif static int FileHandlerEventProc _ANSI_ARGS_((Tcl_Event *evPtr, int flags)); /* *---------------------------------------------------------------------- * * Tcl_InitNotifier -- * * Initializes the platform specific notifier state. * * Results: * Returns a handle to the notifier state for this thread.. * * Side effects: * None. * *---------------------------------------------------------------------- */ #if defined(TCL_THREADS) && defined(__CYGWIN__) typedef struct { void *hwnd; unsigned int *message; int wParam; int lParam; int time; int x; int y; } MSG; typedef struct { unsigned int style; void *lpfnWndProc; int cbClsExtra; int cbWndExtra; void *hInstance; void *hIcon; void *hCursor; void *hbrBackground; void *lpszMenuName; void *lpszClassName; } WNDCLASS; extern unsigned char __stdcall PeekMessageW(MSG *, void *, int, int, int); extern unsigned char __stdcall GetMessageW(MSG *, void *, int, int); extern unsigned char __stdcall TranslateMessage(const MSG *); extern int __stdcall DispatchMessageW(const MSG *); extern void __stdcall PostQuitMessage(int); extern void * __stdcall CreateWindowExW(void *, void *, void *, DWORD, int, int, int, int, void *, void *, void *, void *); extern unsigned char __stdcall DestroyWindow(void *); extern unsigned char __stdcall PostMessageW(void *, unsigned int, void *, void *); extern void *__stdcall RegisterClassW(const WNDCLASS *); extern DWORD __stdcall DefWindowProcW(void *, int, void *, void *); extern void *__stdcall CreateEventW(void *, unsigned char, unsigned char, void *); extern void __stdcall CloseHandle(void *); extern void __stdcall MsgWaitForMultipleObjects(DWORD, void *, unsigned char, DWORD, DWORD); extern unsigned char __stdcall ResetEvent(void *); #endif ClientData Tcl_InitNotifier() { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); #ifdef TCL_THREADS tsdPtr->eventReady = 0; /* * Start the Notifier thread if necessary. */ Tcl_MutexLock(¬ifierMutex); if (notifierCount == 0) { if (TclpThreadCreate(¬ifierThread, NotifierThreadProc, NULL, TCL_THREAD_STACK_DEFAULT, TCL_THREAD_JOINABLE) != TCL_OK) { panic("Tcl_InitNotifier: unable to start notifier thread"); } } notifierCount++; /* * Wait for the notifier pipe to be created. */ while (triggerPipe < 0) { Tcl_ConditionWait(¬ifierCV, ¬ifierMutex, NULL); } Tcl_MutexUnlock(¬ifierMutex); #endif return (ClientData) tsdPtr; } /* *---------------------------------------------------------------------- * * Tcl_FinalizeNotifier -- * * This function is called to cleanup the notifier state before * a thread is terminated. * * Results: * None. * * Side effects: * May terminate the background notifier thread if this is the * last notifier instance. * *---------------------------------------------------------------------- */ void Tcl_FinalizeNotifier(clientData) ClientData clientData; /* Not used. */ { #ifdef TCL_THREADS ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); Tcl_MutexLock(¬ifierMutex); notifierCount--; /* * If this is the last thread to use the notifier, close the notifier * pipe and wait for the background thread to terminate. */ if (notifierCount == 0) { int result; if (triggerPipe < 0) { panic("Tcl_FinalizeNotifier: notifier pipe not initialized"); } /* * Send "q" message to the notifier thread so that it will * terminate. The notifier will return from its call to select() * and notice that a "q" message has arrived, it will then close * its side of the pipe and terminate its thread. Note the we can * not just close the pipe and check for EOF in the notifier * thread because if a background child process was created with * exec, select() would not register the EOF on the pipe until the * child processes had terminated. [Bug: 4139] [Bug: 1222872] */ write(triggerPipe, "q", 1); close(triggerPipe); while(triggerPipe >= 0) { Tcl_ConditionWait(¬ifierCV, ¬ifierMutex, NULL); } result = Tcl_JoinThread(notifierThread, NULL); if (result) { Tcl_Panic("Tcl_FinalizeNotifier: unable to join notifier thread"); } } /* * Clean up any synchronization objects in the thread local storage. */ #ifdef __CYGWIN__ CloseHandle(tsdPtr->event); #else /* __CYGWIN__ */ Tcl_ConditionFinalize(&(tsdPtr->waitCV)); #endif /* __CYGWIN__ */ Tcl_MutexUnlock(¬ifierMutex); #endif } /* *---------------------------------------------------------------------- * * Tcl_AlertNotifier -- * * Wake up the specified notifier from any thread. This routine * is called by the platform independent notifier code whenever * the Tcl_ThreadAlert routine is called. This routine is * guaranteed not to be called on a given notifier after * Tcl_FinalizeNotifier is called for that notifier. * * Results: * None. * * Side effects: * Signals the notifier condition variable for the specified * notifier. * *---------------------------------------------------------------------- */ void Tcl_AlertNotifier(clientData) ClientData clientData; { #ifdef TCL_THREADS ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData; Tcl_MutexLock(¬ifierMutex); tsdPtr->eventReady = 1; #ifdef __CYGWIN__ PostMessageW(tsdPtr->hwnd, 1024, 0, 0); #else Tcl_ConditionNotify(&tsdPtr->waitCV); #endif Tcl_MutexUnlock(¬ifierMutex); #endif } /* *---------------------------------------------------------------------- * * Tcl_SetTimer -- * * This procedure sets the current notifier timer value. This * interface is not implemented in this notifier because we are * always running inside of Tcl_DoOneEvent. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Tcl_SetTimer(timePtr) Tcl_Time *timePtr; /* Timeout value, may be NULL. */ { /* * The interval timer doesn't do anything in this implementation, * because the only event loop is via Tcl_DoOneEvent, which passes * timeout values to Tcl_WaitForEvent. */ if (tclStubs.tcl_SetTimer != tclOriginalNotifier.setTimerProc) { tclStubs.tcl_SetTimer(timePtr); } } /* *---------------------------------------------------------------------- * * Tcl_ServiceModeHook -- * * This function is invoked whenever the service mode changes. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Tcl_ServiceModeHook(mode) int mode; /* Either TCL_SERVICE_ALL, or * TCL_SERVICE_NONE. */ { } /* *---------------------------------------------------------------------- * * Tcl_CreateFileHandler -- * * This procedure registers a file handler with the select notifier. * * Results: * None. * * Side effects: * Creates a new file handler structure. * *---------------------------------------------------------------------- */ void Tcl_CreateFileHandler(fd, mask, proc, clientData) int fd; /* Handle of stream to watch. */ int mask; /* OR'ed combination of TCL_READABLE, * TCL_WRITABLE, and TCL_EXCEPTION: * indicates conditions under which * proc should be called. */ Tcl_FileProc *proc; /* Procedure to call for each * selected event. */ ClientData clientData; /* Arbitrary data to pass to proc. */ { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); FileHandler *filePtr; if (tclStubs.tcl_CreateFileHandler != tclOriginalNotifier.createFileHandlerProc) { tclStubs.tcl_CreateFileHandler(fd, mask, proc, clientData); return; } for (filePtr = tsdPtr->firstFileHandlerPtr; filePtr != NULL; filePtr = filePtr->nextPtr) { if (filePtr->fd == fd) { break; } } if (filePtr == NULL) { filePtr = (FileHandler*) ckalloc(sizeof(FileHandler)); filePtr->fd = fd; filePtr->readyMask = 0; filePtr->nextPtr = tsdPtr->firstFileHandlerPtr; tsdPtr->firstFileHandlerPtr = filePtr; } filePtr->proc = proc; filePtr->clientData = clientData; filePtr->mask = mask; /* * Update the check masks for this file. */ if ( mask & TCL_READABLE ) { FD_SET( fd, &(tsdPtr->checkMasks.readable) ); } else { FD_CLR( fd, &(tsdPtr->checkMasks.readable) ); } if ( mask & TCL_WRITABLE ) { FD_SET( fd, &(tsdPtr->checkMasks.writable) ); } else { FD_CLR( fd, &(tsdPtr->checkMasks.writable) ); } if ( mask & TCL_EXCEPTION ) { FD_SET( fd, &(tsdPtr->checkMasks.exceptional) ); } else { FD_CLR( fd, &(tsdPtr->checkMasks.exceptional) ); } if (tsdPtr->numFdBits <= fd) { tsdPtr->numFdBits = fd+1; } } /* *---------------------------------------------------------------------- * * Tcl_DeleteFileHandler -- * * Cancel a previously-arranged callback arrangement for * a file. * * Results: * None. * * Side effects: * If a callback was previously registered on file, remove it. * *---------------------------------------------------------------------- */ void Tcl_DeleteFileHandler(fd) int fd; /* Stream id for which to remove callback procedure. */ { FileHandler *filePtr, *prevPtr; int i; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (tclStubs.tcl_DeleteFileHandler != tclOriginalNotifier.deleteFileHandlerProc) { tclStubs.tcl_DeleteFileHandler(fd); return; } /* * Find the entry for the given file (and return if there isn't one). */ for (prevPtr = NULL, filePtr = tsdPtr->firstFileHandlerPtr; ; prevPtr = filePtr, filePtr = filePtr->nextPtr) { if (filePtr == NULL) { return; } if (filePtr->fd == fd) { break; } } /* * Update the check masks for this file. */ if (filePtr->mask & TCL_READABLE) { FD_CLR( fd, &(tsdPtr->checkMasks.readable) ); } if (filePtr->mask & TCL_WRITABLE) { FD_CLR( fd, &(tsdPtr->checkMasks.writable) ); } if (filePtr->mask & TCL_EXCEPTION) { FD_CLR( fd, &(tsdPtr->checkMasks.exceptional) ); } /* * Find current max fd. */ if (fd+1 == tsdPtr->numFdBits) { tsdPtr->numFdBits = 0; for (i = fd-1; i >= 0; i--) { if ( FD_ISSET( i, &(tsdPtr->checkMasks.readable) ) || FD_ISSET( i, &(tsdPtr->checkMasks.writable) ) || FD_ISSET( i, &(tsdPtr->checkMasks.exceptional ) ) ) { tsdPtr->numFdBits = i+1; break; } } } /* * Clean up information in the callback record. */ if (prevPtr == NULL) { tsdPtr->firstFileHandlerPtr = filePtr->nextPtr; } else { prevPtr->nextPtr = filePtr->nextPtr; } ckfree((char *) filePtr); } /* *---------------------------------------------------------------------- * * FileHandlerEventProc -- * * This procedure is called by Tcl_ServiceEvent when a file event * reaches the front of the event queue. This procedure is * responsible for actually handling the event by invoking the * callback for the file handler. * * Results: * Returns 1 if the event was handled, meaning it should be removed * from the queue. Returns 0 if the event was not handled, meaning * it should stay on the queue. The only time the event isn't * handled is if the TCL_FILE_EVENTS flag bit isn't set. * * Side effects: * Whatever the file handler's callback procedure does. * *---------------------------------------------------------------------- */ static int FileHandlerEventProc(evPtr, flags) Tcl_Event *evPtr; /* Event to service. */ int flags; /* Flags that indicate what events to * handle, such as TCL_FILE_EVENTS. */ { int mask; FileHandler *filePtr; FileHandlerEvent *fileEvPtr = (FileHandlerEvent *) evPtr; ThreadSpecificData *tsdPtr; if (!(flags & TCL_FILE_EVENTS)) { return 0; } /* * Search through the file handlers to find the one whose handle matches * the event. We do this rather than keeping a pointer to the file * handler directly in the event, so that the handler can be deleted * while the event is queued without leaving a dangling pointer. */ tsdPtr = TCL_TSD_INIT(&dataKey); for (filePtr = tsdPtr->firstFileHandlerPtr; filePtr != NULL; filePtr = filePtr->nextPtr) { if (filePtr->fd != fileEvPtr->fd) { continue; } /* * The code is tricky for two reasons: * 1. The file handler's desired events could have changed * since the time when the event was queued, so AND the * ready mask with the desired mask. * 2. The file could have been closed and re-opened since * the time when the event was queued. This is why the * ready mask is stored in the file handler rather than * the queued event: it will be zeroed when a new * file handler is created for the newly opened file. */ mask = filePtr->readyMask & filePtr->mask; filePtr->readyMask = 0; if (mask != 0) { (*filePtr->proc)(filePtr->clientData, mask); } break; } return 1; } #if defined(TCL_THREADS) && defined(__CYGWIN__) static DWORD __stdcall NotifierProc( void *hwnd, unsigned int message, void *wParam, void *lParam) { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (message != 1024) { return DefWindowProcW(hwnd, message, wParam, lParam); } /* * Process all of the runnable events. */ tsdPtr->eventReady = 1; Tcl_ServiceAll(); return 0; } #endif /* __CYGWIN__ */ /* *---------------------------------------------------------------------- * * Tcl_WaitForEvent -- * * This function is called by Tcl_DoOneEvent to wait for new * events on the message queue. If the block time is 0, then * Tcl_WaitForEvent just polls without blocking. * * Results: * Returns -1 if the select would block forever, otherwise * returns 0. * * Side effects: * Queues file events that are detected by the select. * *---------------------------------------------------------------------- */ int Tcl_WaitForEvent(timePtr) Tcl_Time *timePtr; /* Maximum block time, or NULL. */ { FileHandler *filePtr; FileHandlerEvent *fileEvPtr; int mask; #ifdef TCL_THREADS int waitForFiles; # ifdef __CYGWIN__ MSG msg; # endif #else /* Impl. notes: timeout & timeoutPtr are used if, and only if * threads are not enabled. They are the arguments for the regular * select() used when the core is not thread-enabled. */ struct timeval timeout, *timeoutPtr; int numFound; #endif ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (tclStubs.tcl_WaitForEvent != tclOriginalNotifier.waitForEventProc) { return tclStubs.tcl_WaitForEvent(timePtr); } #ifndef TCL_THREADS /* * Set up the timeout structure. Note that if there are no events to * check for, we return with a negative result rather than blocking * forever. */ if (timePtr) { timeout.tv_sec = timePtr->sec; timeout.tv_usec = timePtr->usec; timeoutPtr = &timeout; } else if (tsdPtr->numFdBits == 0) { /* * If there are no threads, no timeout, and no fds registered, * then there are no events possible and we must avoid deadlock. * Note that this is not entirely correct because there might * be a signal that could interrupt the select call, but we * don't handle that case if we aren't using threads. */ return -1; } else { timeoutPtr = NULL; } #endif #ifdef TCL_THREADS /* * Place this thread on the list of interested threads, signal the * notifier thread, and wait for a response or a timeout. */ Tcl_MutexLock(¬ifierMutex); waitForFiles = (tsdPtr->numFdBits > 0); if (timePtr != NULL && timePtr->sec == 0 && (timePtr->usec == 0 #if defined(__APPLE__) && defined(__LP64__) /* * On 64-bit Darwin, pthread_cond_timedwait() appears to have a bug * that causes it to wait forever when passed an absolute time which * has already been exceeded by the system time; as a workaround, * when given a very brief timeout, just do a poll. [Bug 1457797] */ || timePtr->usec < 10 #endif )) { /* * Cannot emulate a polling select with a polling condition variable. * Instead, pretend to wait for files and tell the notifier * thread what we are doing. The notifier thread makes sure * it goes through select with its select mask in the same state * as ours currently is. We block until that happens. */ waitForFiles = 1; tsdPtr->pollState = POLL_WANT; timePtr = NULL; } else { tsdPtr->pollState = 0; } #ifdef __CYGWIN__ if (!tsdPtr->hwnd) { WNDCLASS class; class.style = 0; class.cbClsExtra = 0; class.cbWndExtra = 0; class.hInstance = TclWinGetTclInstance(); class.hbrBackground = NULL; class.lpszMenuName = NULL; class.lpszClassName = L"TclNotifier"; class.lpfnWndProc = NotifierProc; class.hIcon = NULL; class.hCursor = NULL; RegisterClassW(&class); tsdPtr->hwnd = CreateWindowExW(NULL, class.lpszClassName, class.lpszClassName, 0, 0, 0, 0, 0, NULL, NULL, TclWinGetTclInstance(), NULL); tsdPtr->event = CreateEventW(NULL, 1 /* manual */, 0 /* !signaled */, NULL); } #endif if (waitForFiles) { /* * Add the ThreadSpecificData structure of this thread to the list * of ThreadSpecificData structures of all threads that are waiting * on file events. */ tsdPtr->nextPtr = waitingListPtr; if (waitingListPtr) { waitingListPtr->prevPtr = tsdPtr; } tsdPtr->prevPtr = 0; waitingListPtr = tsdPtr; tsdPtr->onList = 1; write(triggerPipe, "", 1); } FD_ZERO( &(tsdPtr->readyMasks.readable) ); FD_ZERO( &(tsdPtr->readyMasks.writable) ); FD_ZERO( &(tsdPtr->readyMasks.exceptional) ); if (!tsdPtr->eventReady) { #ifdef __CYGWIN__ if (!PeekMessageW(&msg, NULL, 0, 0, 0)) { DWORD timeout; if (timePtr) { timeout = timePtr->sec * 1000 + timePtr->usec / 1000; } else { timeout = 0xFFFFFFFF; } Tcl_MutexUnlock(¬ifierMutex); MsgWaitForMultipleObjects(1, &tsdPtr->event, 0, timeout, 1279); Tcl_MutexLock(¬ifierMutex); } #else Tcl_ConditionWait(&tsdPtr->waitCV, ¬ifierMutex, timePtr); #endif } tsdPtr->eventReady = 0; #ifdef __CYGWIN__ while (PeekMessageW(&msg, NULL, 0, 0, 0)) { /* * Retrieve and dispatch the message. */ DWORD result = GetMessageW(&msg, NULL, 0, 0); if (result == 0) { PostQuitMessage(msg.wParam); /* What to do here? */ } else if (result != (DWORD)-1) { TranslateMessage(&msg); DispatchMessageW(&msg); } } ResetEvent(tsdPtr->event); #endif if (waitForFiles && tsdPtr->onList) { /* * Remove the ThreadSpecificData structure of this thread from the * waiting list. Alert the notifier thread to recompute its select * masks - skipping this caused a hang when trying to close a pipe * which the notifier thread was still doing a select on. */ if (tsdPtr->prevPtr) { tsdPtr->prevPtr->nextPtr = tsdPtr->nextPtr; } else { waitingListPtr = tsdPtr->nextPtr; } if (tsdPtr->nextPtr) { tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr; } tsdPtr->nextPtr = tsdPtr->prevPtr = NULL; tsdPtr->onList = 0; write(triggerPipe, "", 1); } #else tsdPtr->readyMasks = tsdPtr->checkMasks; numFound = select( tsdPtr->numFdBits, &(tsdPtr->readyMasks.readable), &(tsdPtr->readyMasks.writable), &(tsdPtr->readyMasks.exceptional), timeoutPtr ); /* * Some systems don't clear the masks after an error, so * we have to do it here. */ if (numFound == -1) { FD_ZERO( &(tsdPtr->readyMasks.readable ) ); FD_ZERO( &(tsdPtr->readyMasks.writable ) ); FD_ZERO( &(tsdPtr->readyMasks.exceptional ) ); } #endif /* * Queue all detected file events before returning. */ for (filePtr = tsdPtr->firstFileHandlerPtr; (filePtr != NULL); filePtr = filePtr->nextPtr) { mask = 0; if ( FD_ISSET( filePtr->fd, &(tsdPtr->readyMasks.readable) ) ) { mask |= TCL_READABLE; } if ( FD_ISSET( filePtr->fd, &(tsdPtr->readyMasks.writable) ) ) { mask |= TCL_WRITABLE; } if ( FD_ISSET( filePtr->fd, &(tsdPtr->readyMasks.exceptional) ) ) { mask |= TCL_EXCEPTION; } if (!mask) { continue; } /* * Don't bother to queue an event if the mask was previously * non-zero since an event must still be on the queue. */ if (filePtr->readyMask == 0) { fileEvPtr = (FileHandlerEvent *) ckalloc( sizeof(FileHandlerEvent)); fileEvPtr->header.proc = FileHandlerEventProc; fileEvPtr->fd = filePtr->fd; Tcl_QueueEvent((Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL); } filePtr->readyMask = mask; } #ifdef TCL_THREADS Tcl_MutexUnlock(¬ifierMutex); #endif return 0; } #ifdef TCL_THREADS /* *---------------------------------------------------------------------- * * NotifierThreadProc -- * * This routine is the initial (and only) function executed by the * special notifier thread. Its job is to wait for file descriptors * to become readable or writable or to have an exception condition * and then to notify other threads who are interested in this * information by signalling a condition variable. Other threads * can signal this notifier thread of a change in their interests * by writing a single byte to a special pipe that the notifier * thread is monitoring. * * Result: * None. Once started, this routine never exits. It dies with * the overall process. * * Side effects: * The trigger pipe used to signal the notifier thread is created * when the notifier thread first starts. * *---------------------------------------------------------------------- */ static void NotifierThreadProc(clientData) ClientData clientData; /* Not used. */ { ThreadSpecificData *tsdPtr; fd_set readableMask; fd_set writableMask; fd_set exceptionalMask; int fds[2]; int i, status, numFdBits = 0, receivePipe; long found; struct timeval poll = {0., 0.}, *timePtr; char buf[2]; if (pipe(fds) != 0) { panic("NotifierThreadProc: could not create trigger pipe."); } receivePipe = fds[0]; #ifndef USE_FIONBIO status = fcntl(receivePipe, F_GETFL); status |= O_NONBLOCK; if (fcntl(receivePipe, F_SETFL, status) < 0) { panic("NotifierThreadProc: could not make receive pipe non blocking."); } status = fcntl(fds[1], F_GETFL); status |= O_NONBLOCK; if (fcntl(fds[1], F_SETFL, status) < 0) { panic("NotifierThreadProc: could not make trigger pipe non blocking."); } #else if (ioctl(receivePipe, (int) FIONBIO, &status) < 0) { panic("NotifierThreadProc: could not make receive pipe non blocking."); } if (ioctl(fds[1], (int) FIONBIO, &status) < 0) { panic("NotifierThreadProc: could not make trigger pipe non blocking."); } #endif /* * Install the write end of the pipe into the global variable. */ Tcl_MutexLock(¬ifierMutex); triggerPipe = fds[1]; /* * Signal any threads that are waiting. */ Tcl_ConditionNotify(¬ifierCV); Tcl_MutexUnlock(¬ifierMutex); /* * Look for file events and report them to interested threads. */ while (1) { FD_ZERO( &readableMask ); FD_ZERO( &writableMask ); FD_ZERO( &exceptionalMask ); /* * Compute the logical OR of the select masks from all the * waiting notifiers. */ Tcl_MutexLock(¬ifierMutex); timePtr = NULL; for (tsdPtr = waitingListPtr; tsdPtr; tsdPtr = tsdPtr->nextPtr) { for ( i = tsdPtr->numFdBits-1; i >= 0; --i ) { if ( FD_ISSET( i, &(tsdPtr->checkMasks.readable) ) ) { FD_SET( i, &readableMask ); } if ( FD_ISSET( i, &(tsdPtr->checkMasks.writable) ) ) { FD_SET( i, &writableMask ); } if ( FD_ISSET( i, &(tsdPtr->checkMasks.exceptional) ) ) { FD_SET( i, &exceptionalMask ); } } if ( tsdPtr->numFdBits > numFdBits ) { numFdBits = tsdPtr->numFdBits; } if (tsdPtr->pollState & POLL_WANT) { /* * Here we make sure we go through select() with the same * mask bits that were present when the thread tried to poll. */ tsdPtr->pollState |= POLL_DONE; timePtr = &poll; } } Tcl_MutexUnlock(¬ifierMutex); /* * Set up the select mask to include the receive pipe. */ if ( receivePipe >= numFdBits ) { numFdBits = receivePipe + 1; } FD_SET( receivePipe, &readableMask ); if ( select( numFdBits, &readableMask, &writableMask, &exceptionalMask, timePtr) == -1 ) { /* * Try again immediately on an error. */ continue; } /* * Alert any threads that are waiting on a ready file descriptor. */ Tcl_MutexLock(¬ifierMutex); for (tsdPtr = waitingListPtr; tsdPtr; tsdPtr = tsdPtr->nextPtr) { found = 0; for ( i = tsdPtr->numFdBits-1; i >= 0; --i ) { if ( FD_ISSET( i, &(tsdPtr->checkMasks.readable) ) && FD_ISSET( i, &readableMask ) ) { FD_SET( i, &(tsdPtr->readyMasks.readable) ); found = 1; } if ( FD_ISSET( i, &(tsdPtr->checkMasks.writable) ) && FD_ISSET( i, &writableMask ) ) { FD_SET( i, &(tsdPtr->readyMasks.writable) ); found = 1; } if ( FD_ISSET( i, &(tsdPtr->checkMasks.exceptional) ) && FD_ISSET( i, &exceptionalMask ) ) { FD_SET( i, &(tsdPtr->readyMasks.exceptional) ); found = 1; } } if (found || (tsdPtr->pollState & POLL_DONE)) { tsdPtr->eventReady = 1; if (tsdPtr->onList) { /* * Remove the ThreadSpecificData structure of this * thread from the waiting list. This prevents us from * continuously spining on select until the other * threads runs and services the file event. */ if (tsdPtr->prevPtr) { tsdPtr->prevPtr->nextPtr = tsdPtr->nextPtr; } else { waitingListPtr = tsdPtr->nextPtr; } if (tsdPtr->nextPtr) { tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr; } tsdPtr->nextPtr = tsdPtr->prevPtr = NULL; tsdPtr->onList = 0; tsdPtr->pollState = 0; } #ifdef __CYGWIN__ PostMessageW(tsdPtr->hwnd, 1024, 0, 0); #else /* __CYGWIN__ */ Tcl_ConditionNotify(&tsdPtr->waitCV); #endif /* __CYGWIN__ */ } } Tcl_MutexUnlock(¬ifierMutex); /* * Consume the next byte from the notifier pipe if the pipe was * readable. Note that there may be multiple bytes pending, but * to avoid a race condition we only read one at a time. */ if ( FD_ISSET( receivePipe, &readableMask ) ) { i = read(receivePipe, buf, 1); if ((i == 0) || ((i == 1) && (buf[0] == 'q'))) { /* * Someone closed the write end of the pipe or sent us a * Quit message [Bug: 4139] and then closed the write end * of the pipe so we need to shut down the notifier thread. */ break; } } } /* * Clean up the read end of the pipe and signal any threads waiting on * termination of the notifier thread. */ close(receivePipe); Tcl_MutexLock(¬ifierMutex); triggerPipe = -1; Tcl_ConditionNotify(¬ifierCV); Tcl_MutexUnlock(¬ifierMutex); TclpThreadExit (0); } #endif #endif /* HAVE_COREFOUNDATION */ tcl8.4.20/unix/configure.in0000775003604700454610000007251712153151142014215 0ustar dgp771div#! /bin/bash -norc dnl This file is an input file used by the GNU "autoconf" program to dnl generate the file "configure", which is run during Tcl installation dnl to configure the system for the local environment. AC_INIT(../generic/tcl.h) AC_PREREQ(2.13) TCL_VERSION=8.4 TCL_MAJOR_VERSION=8 TCL_MINOR_VERSION=4 TCL_PATCH_LEVEL=".20" VERSION=${TCL_VERSION} #------------------------------------------------------------------------ # Handle the --prefix=... option #------------------------------------------------------------------------ if test "${prefix}" = "NONE"; then prefix=/usr/local fi if test "${exec_prefix}" = "NONE"; then exec_prefix=$prefix fi # Make sure srcdir is fully qualified! srcdir=`cd $srcdir ; pwd` TCL_SRC_DIR=`cd $srcdir/..; pwd` #------------------------------------------------------------------------ # Compress and/or soft link the manpages? #------------------------------------------------------------------------ SC_CONFIG_MANPAGES([tcl]) #------------------------------------------------------------------------ # Standard compiler checks #------------------------------------------------------------------------ # If the user did not set CFLAGS, set it now to keep # the AC_PROG_CC macro from adding "-g -O2". if test "${CFLAGS+set}" != "set" ; then CFLAGS="" fi AC_PROG_CC #-------------------------------------------------------------------- # Supply substitutes for missing POSIX header files. Special notes: # - stdlib.h doesn't define strtol, strtoul, or # strtod insome versions of SunOS # - some versions of string.h don't declare procedures such # as strstr # Do this early, otherwise an autoconf bug throws errors on configure #-------------------------------------------------------------------- SC_MISSING_POSIX_HEADERS #------------------------------------------------------------------------ # If we're using GCC, see if the compiler understands -pipe. If so, use it. # It makes compiling go faster. (This is only a performance feature.) #------------------------------------------------------------------------ if test -z "$no_pipe" && test -n "$GCC"; then AC_CACHE_CHECK([if the compiler understands -pipe], tcl_cv_cc_pipe, [ hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -pipe" AC_TRY_COMPILE(,, tcl_cv_cc_pipe=yes, tcl_cv_cc_pipe=no) CFLAGS=$hold_cflags]) if test $tcl_cv_cc_pipe = yes; then CFLAGS="$CFLAGS -pipe" fi fi #------------------------------------------------------------------------ # Threads support #------------------------------------------------------------------------ SC_ENABLE_THREADS #-------------------------------------------------------------------- # Look for libraries that we will need when compiling the Tcl shell #-------------------------------------------------------------------- SC_TCL_LINK_LIBS # Add the threads support libraries LIBS="$LIBS$THREADS_LIBS" SC_ENABLE_SHARED #-------------------------------------------------------------------- # The statements below define a collection of compile flags. This # macro depends on the value of SHARED_BUILD, and should be called # after SC_ENABLE_SHARED checks the configure switches. #-------------------------------------------------------------------- SC_CONFIG_CFLAGS SC_ENABLE_SYMBOLS TCL_DBGX=${DBGX} #-------------------------------------------------------------------- # Detect what compiler flags to set for 64-bit support. #-------------------------------------------------------------------- SC_TCL_EARLY_FLAGS SC_TCL_64BIT_FLAGS #-------------------------------------------------------------------- # Check endianness because we can optimize comparisons of # Tcl_UniChar strings to memcmp on big-endian systems. #-------------------------------------------------------------------- AC_C_BIGENDIAN #-------------------------------------------------------------------- # Supply substitutes for missing POSIX library procedures, or # set flags so Tcl uses alternate procedures. #-------------------------------------------------------------------- # Check if Posix compliant getcwd exists, if not we'll use getwd. AC_CHECK_FUNCS(getcwd, , [AC_DEFINE(USEGETWD)]) # Nb: if getcwd uses popen and pwd(1) (like SunOS 4) we should really # define USEGETWD even if the posix getcwd exists. Add a test ? AC_REPLACE_FUNCS(opendir strstr strtol strtoll strtoull tmpnam waitpid) AC_CHECK_FUNC(strerror, , [AC_DEFINE(NO_STRERROR)]) AC_CHECK_FUNC(getwd, , [AC_DEFINE(NO_GETWD)]) AC_CHECK_FUNC(wait3, , [AC_DEFINE(NO_WAIT3)]) AC_CHECK_FUNC(uname, , [AC_DEFINE(NO_UNAME)]) if test "`uname -s`" = "Darwin" && test "${TCL_THREADS}" = 1 && \ test "`uname -r | awk -F. '{print [$]1}'`" -lt 7; then # prior to Darwin 7, realpath is not threadsafe, so don't # use it when threads are enabled, c.f. bug # 711232 ac_cv_func_realpath=no fi AC_CHECK_FUNC(realpath, , [AC_DEFINE(NO_REALPATH)]) #-------------------------------------------------------------------- # Look for thread-safe variants of some library functions. #-------------------------------------------------------------------- if test "${TCL_THREADS}" = 1; then SC_TCL_GETPWUID_R SC_TCL_GETPWNAM_R SC_TCL_GETGRGID_R SC_TCL_GETGRNAM_R if test "`uname -s`" = "Darwin" && \ test "`uname -r | awk -F. '{print [$]1}'`" -gt 5; then # Starting with Darwin 6 (Mac OSX 10.2), gethostbyX # are actually MT-safe as they always return pointers # from the TSD instead of the static storage. AC_DEFINE(HAVE_MTSAFE_GETHOSTBYNAME) AC_DEFINE(HAVE_MTSAFE_GETHOSTBYADDR) elif test "`uname -s`" = "HP-UX" && \ test "`uname -r|sed -e 's|B\.||' -e 's|\..*$||'`" -gt 10; then # Starting with HPUX 11.00 (we believe), gethostbyX # are actually MT-safe as they always return pointers # from TSD instead of static storage. AC_DEFINE(HAVE_MTSAFE_GETHOSTBYNAME) AC_DEFINE(HAVE_MTSAFE_GETHOSTBYADDR) else SC_TCL_GETHOSTBYNAME_R SC_TCL_GETHOSTBYADDR_R fi fi #--------------------------------------------------------------------------- # Determine which interface to use to talk to the serial port. # Note that #include lines must begin in leftmost column for # some compilers to recognize them as preprocessor directives. #--------------------------------------------------------------------------- SC_SERIAL_PORT #-------------------------------------------------------------------- # Include sys/select.h if it exists and if it supplies things # that appear to be useful and aren't already in sys/types.h. # This appears to be true only on the RS/6000 under AIX. Some # systems like OSF/1 have a sys/select.h that's of no use, and # other systems like SCO UNIX have a sys/select.h that's # pernicious. If "fd_set" isn't defined anywhere then set a # special flag. #-------------------------------------------------------------------- AC_CACHE_CHECK([for fd_set in sys/types], tcl_cv_type_fd_set, [ AC_TRY_COMPILE([#include ],[fd_set readMask, writeMask;], tcl_cv_type_fd_set=yes, tcl_cv_type_fd_set=no)]) tcl_ok=$tcl_cv_type_fd_set if test $tcl_ok = no; then AC_CACHE_CHECK([for fd_mask in sys/select], tcl_cv_grep_fd_mask, [ AC_EGREP_HEADER(fd_mask, sys/select.h, tcl_cv_grep_fd_mask=present, tcl_cv_grep_fd_mask=missing)]) if test $tcl_cv_grep_fd_mask = present; then AC_DEFINE(HAVE_SYS_SELECT_H) tcl_ok=yes fi fi if test $tcl_ok = no; then AC_DEFINE(NO_FD_SET) fi #------------------------------------------------------------------------------ # Find out all about time handling differences. #------------------------------------------------------------------------------ SC_TIME_HANDLER #-------------------------------------------------------------------- # Some systems (e.g., IRIX 4.0.5) lack the st_blksize field # in struct stat. But we might be able to use fstatfs instead. #-------------------------------------------------------------------- if test "$ac_cv_cygwin" != "yes"; then AC_STRUCT_ST_BLKSIZE fi AC_CHECK_FUNC(fstatfs, , [AC_DEFINE(NO_FSTATFS)]) #-------------------------------------------------------------------- # Some system have no memcmp or it does not work with 8 bit # data, this checks it and add memcmp.o to LIBOBJS if needed #-------------------------------------------------------------------- AC_FUNC_MEMCMP #-------------------------------------------------------------------- # Some system like SunOS 4 and other BSD like systems # have no memmove (we assume they have bcopy instead). # {The replacement define is in compat/string.h} #-------------------------------------------------------------------- AC_CHECK_FUNC(memmove, , [AC_DEFINE(NO_MEMMOVE) AC_DEFINE(NO_STRING_H)]) #-------------------------------------------------------------------- # On some systems strstr is broken: it returns a pointer even # even if the original string is empty. #-------------------------------------------------------------------- dnl only run if AC_REPLACE_FUNCS(strstr) hasn't already added strstr.o if test "x${ac_cv_func_strstr}" = "xyes"; then AC_CACHE_CHECK([proper strstr implementation], tcl_cv_strstr_unbroken, [ AC_TRY_RUN([ extern int strstr(); int main() { exit(strstr("\0test", "test") ? 1 : 0); }], tcl_cv_strstr_unbroken=ok, tcl_cv_strstr_unbroken=broken, tcl_cv_strstr_unbroken=broken)]) if test $tcl_cv_strstr_unbroken = broken; then LIBOBJS="$LIBOBJS strstr.o" fi fi #-------------------------------------------------------------------- # Check for strtoul function. This is tricky because under some # versions of AIX strtoul returns an incorrect terminator # pointer for the string "0". #-------------------------------------------------------------------- AC_CHECK_FUNC(strtoul, tcl_ok=1, tcl_ok=0) if test $tcl_ok = 1; then AC_CACHE_CHECK([proper strtoul implementation], tcl_cv_strtoul_unbroken, [ AC_TRY_RUN([ extern int strtoul(); int main() { char *string = "0"; char *term; int value; value = strtoul(string, &term, 0); if ((value != 0) || (term != (string+1))) { exit(1); } exit(0); }], tcl_cv_strtoul_unbroken=ok , tcl_cv_strtoul_unbroken=broken, tcl_cv_strtoul_unbroken=broken)]) if test $tcl_cv_strtoul_unbroken = broken; then tcl_ok=0 fi fi if test $tcl_ok = 0; then LIBOBJS="$LIBOBJS strtoul.o" fi #-------------------------------------------------------------------- # Check for the strtod function. This is tricky because in some # versions of Linux strtod mis-parses strings starting with "+". #-------------------------------------------------------------------- AC_CHECK_FUNC(strtod, tcl_ok=1, tcl_ok=0) if test $tcl_ok = 1; then AC_CACHE_CHECK([proper strtod implementation], tcl_cv_strtod_unbroken, [ AC_TRY_RUN([ extern double strtod(); int main() { char *string = " +69"; char *term; double value; value = strtod(string, &term); if ((value != 69) || (term != (string+4))) { exit(1); } exit(0); }], tcl_cv_strtod_unbroken=ok , tcl_cv_strtod_unbroken=broken, tcl_cv_strtod_unbroken=broken)]) if test $tcl_cv_strtod_unbroken = broken; then tcl_ok=0 fi fi if test $tcl_ok = 0; then LIBOBJS="$LIBOBJS strtod.o" fi #-------------------------------------------------------------------- # Under Solaris 2.4, strtod returns the wrong value for the # terminating character under some conditions. Check for this # and if the problem exists use a substitute procedure # "fixstrtod" that corrects the error. #-------------------------------------------------------------------- SC_BUGGY_STRTOD #-------------------------------------------------------------------- # Check for various typedefs and provide substitutes if # they don't exist. #-------------------------------------------------------------------- AC_TYPE_MODE_T AC_TYPE_PID_T AC_TYPE_SIZE_T AC_TYPE_UID_T AC_CACHE_CHECK([for socklen_t], ac_cv_type_socklen_t, [ AC_EGREP_CPP(changequote(<<,>>)dnl <<(^|[^a-zA-Z_0-9])socklen_t[^a-zA-Z_0-9]>>dnl changequote([,]),[ #include #include #if STDC_HEADERS #include #include #endif ], ac_cv_type_socklen_t=yes, ac_cv_type_socklen_t=no)]) if test $ac_cv_type_socklen_t = no; then AC_DEFINE(socklen_t, unsigned) fi #-------------------------------------------------------------------- # If a system doesn't have an opendir function (man, that's old!) # then we have to supply a different version of dirent.h which # is compatible with the substitute version of opendir that's # provided. This version only works with V7-style directories. #-------------------------------------------------------------------- AC_CHECK_FUNC(opendir, , [AC_DEFINE(USE_DIRENT2_H)]) #-------------------------------------------------------------------- # The check below checks whether defines the type # "union wait" correctly. It's needed because of weirdness in # HP-UX where "union wait" is defined in both the BSD and SYS-V # environments. Checking the usability of WIFEXITED seems to do # the trick. #-------------------------------------------------------------------- AC_CACHE_CHECK([union wait], tcl_cv_union_wait, [ AC_TRY_LINK([#include #include ], [ union wait x; WIFEXITED(x); /* Generates compiler error if WIFEXITED * uses an int. */ ], tcl_cv_union_wait=yes, tcl_cv_union_wait=no)]) if test $tcl_cv_union_wait = no; then AC_DEFINE(NO_UNION_WAIT) fi #-------------------------------------------------------------------- # Check whether there is an strncasecmp function on this system. # This is a bit tricky because under SCO it's in -lsocket and # under Sequent Dynix it's in -linet. #-------------------------------------------------------------------- AC_CHECK_FUNC(strncasecmp, tcl_ok=1, tcl_ok=0) if test "$tcl_ok" = 0; then AC_CHECK_LIB(socket, strncasecmp, tcl_ok=1, tcl_ok=0) fi if test "$tcl_ok" = 0; then AC_CHECK_LIB(inet, strncasecmp, tcl_ok=1, tcl_ok=0) fi if test "$tcl_ok" = 0; then LIBOBJS="$LIBOBJS strncasecmp.o" fi #-------------------------------------------------------------------- # The code below deals with several issues related to gettimeofday: # 1. Some systems don't provide a gettimeofday function at all # (set NO_GETTOD if this is the case). # 2. See if gettimeofday is declared in the header file. # if not, set the GETTOD_NOT_DECLARED flag so that tclPort.h can # declare it. #-------------------------------------------------------------------- AC_CHECK_FUNC(gettimeofday, , [AC_DEFINE(NO_GETTOD)]) AC_CACHE_CHECK([for gettimeofday declaration], tcl_cv_grep_gettimeofday, [ AC_EGREP_HEADER(gettimeofday, sys/time.h, tcl_cv_grep_gettimeofday=present, tcl_cv_grep_gettimeofday=missing)]) if test $tcl_cv_grep_gettimeofday = missing ; then AC_DEFINE(GETTOD_NOT_DECLARED) fi #-------------------------------------------------------------------- # The following code checks to see whether it is possible to get # signed chars on this platform. This is needed in order to # properly generate sign-extended ints from character values. #-------------------------------------------------------------------- AC_C_CHAR_UNSIGNED AC_CACHE_CHECK([signed char declarations], tcl_cv_char_signed, [ AC_TRY_COMPILE(, [ signed char *p; p = 0; ], tcl_cv_char_signed=yes, tcl_cv_char_signed=no)]) if test $tcl_cv_char_signed = yes; then AC_DEFINE(HAVE_SIGNED_CHAR) fi #-------------------------------------------------------------------- # Does putenv() copy or not? We need to know to avoid memory leaks. #-------------------------------------------------------------------- AC_CACHE_CHECK([for a putenv() that copies the buffer], tcl_cv_putenv_copy, [ AC_TRY_RUN([ #include #define OURVAR "havecopy=yes" int main (int argc, char *argv[]) { char *foo, *bar; foo = (char *)strdup(OURVAR); putenv(foo); strcpy((char *)(strchr(foo, '=') + 1), "no"); bar = getenv("havecopy"); if (!strcmp(bar, "no")) { /* doesnt copy */ return 0; } else { /* does copy */ return 1; } } ], tcl_cv_putenv_copy=no, tcl_cv_putenv_copy=yes, tcl_cv_putenv_copy=no)]) if test $tcl_cv_putenv_copy = yes; then AC_DEFINE(HAVE_PUTENV_THAT_COPIES) fi #-------------------------------------------------------------------- # Check for support of nl_langinfo function #-------------------------------------------------------------------- SC_ENABLE_LANGINFO #-------------------------------------------------------------------- # Darwin specific API checks and defines #-------------------------------------------------------------------- if test "`uname -s`" = "Darwin" ; then AC_CHECK_HEADERS(copyfile.h) AC_CHECK_FUNCS(copyfile) if test $tcl_corefoundation = yes; then AC_CHECK_HEADERS(libkern/OSAtomic.h) AC_CHECK_FUNCS(OSSpinLockLock) AC_CHECK_FUNCS(pthread_atfork) fi AC_DEFINE(USE_VFORK) AC_DEFINE(TCL_DEFAULT_ENCODING, "utf-8") AC_DEFINE(TCL_LOAD_FROM_MEMORY) AC_CHECK_HEADERS(AvailabilityMacros.h) if test "$ac_cv_header_AvailabilityMacros_h" = yes; then AC_CACHE_CHECK([if weak import is available], tcl_cv_cc_weak_import, [ hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -Werror" AC_TRY_LINK([ #ifdef __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ #if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1020 #error __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1020 #endif #elif MAC_OS_X_VERSION_MIN_REQUIRED < 1020 #error MAC_OS_X_VERSION_MIN_REQUIRED < 1020 #endif int rand(void) __attribute__((weak_import)); ], [rand();], tcl_cv_cc_weak_import=yes, tcl_cv_cc_weak_import=no) CFLAGS=$hold_cflags]) if test $tcl_cv_cc_weak_import = yes; then AC_DEFINE(HAVE_WEAK_IMPORT) fi fi fi #-------------------------------------------------------------------- # Check for support of fts functions (readdir replacement) #-------------------------------------------------------------------- AC_CACHE_CHECK([for fts], tcl_cv_api_fts, [ AC_TRY_LINK([ #include #include #include ], [ char*const p[2] = {"/", NULL}; FTS *f = fts_open(p, FTS_PHYSICAL|FTS_NOCHDIR|FTS_NOSTAT, NULL); FTSENT *e = fts_read(f); fts_close(f); ], tcl_cv_api_fts=yes, tcl_cv_api_fts=no)]) if test $tcl_cv_api_fts = yes; then AC_DEFINE(HAVE_FTS) fi #-------------------------------------------------------------------- # The statements below check for systems where POSIX-style # non-blocking I/O (O_NONBLOCK) doesn't work or is unimplemented. # On these systems (mostly older ones), use the old BSD-style # FIONBIO approach instead. #-------------------------------------------------------------------- SC_BLOCKING_STYLE #-------------------------------------------------------------------- # DTrace support #-------------------------------------------------------------------- AC_ARG_ENABLE(dtrace, [ --enable-dtrace build with DTrace support [--disable-dtrace]], [tcl_ok=$enableval], [tcl_ok=no]) if test $tcl_ok = yes; then AC_CHECK_HEADER(sys/sdt.h, [tcl_ok=yes], [tcl_ok=no]) fi if test $tcl_ok = yes; then AC_PATH_PROG(DTRACE, dtrace,, [$PATH:/usr/sbin]) test -z "$ac_cv_path_DTRACE" && tcl_ok=no fi AC_MSG_CHECKING([whether to enable DTrace support]) MAKEFILE_SHELL='/bin/sh' if test $tcl_ok = yes; then AC_DEFINE(USE_DTRACE) DTRACE_SRC="\${DTRACE_SRC}" DTRACE_HDR="\${DTRACE_HDR}" if test "`uname -s`" != "Darwin" ; then DTRACE_OBJ="\${DTRACE_OBJ}" if test "`uname -s`" = "SunOS" -a "$SHARED_BUILD" = "0" ; then # Need to create an intermediate object file to ensure tclDTrace.o # gets included when linking against the static tcl library. STLIB_LD='stlib_ld () { /usr/ccs/bin/ld -r -o $${1%.a}.o "$${@:2}" && '"${STLIB_LD}"' $${1} $${1%.a}.o ; } && stlib_ld' MAKEFILE_SHELL='/bin/bash' # Force use of Sun ar and ranlib, the GNU versions choke on # tclDTrace.o and the combined object file above. AR='/usr/ccs/bin/ar' RANLIB='/usr/ccs/bin/ranlib' fi fi fi AC_MSG_RESULT([$tcl_ok]) #-------------------------------------------------------------------- # The check below checks whether the cpuid instruction is usable. #-------------------------------------------------------------------- AC_CACHE_CHECK([whether the cpuid instruction is usable], tcl_cv_cpuid, [ AC_TRY_LINK(, [ int index,regsPtr[4]; __asm__ __volatile__("mov %%ebx, %%edi \n\t" "cpuid \n\t" "mov %%ebx, %%esi \n\t" "mov %%edi, %%ebx \n\t" : "=a"(regsPtr[0]), "=S"(regsPtr[1]), "=c"(regsPtr[2]), "=d"(regsPtr[3]) : "a"(index) : "edi"); ], tcl_cv_cpuid=yes, tcl_cv_cpuid=no)]) if test $tcl_cv_cpuid = yes; then AC_DEFINE(HAVE_CPUID, 1, [Is the cpuid instruction usable?]) fi #-------------------------------------------------------------------- # The statements below define a collection of symbols related to # building libtcl as a shared library instead of a static library. #-------------------------------------------------------------------- TCL_UNSHARED_LIB_SUFFIX=${UNSHARED_LIB_SUFFIX} TCL_SHARED_LIB_SUFFIX=${SHARED_LIB_SUFFIX} eval "TCL_LIB_FILE=libtcl${LIB_SUFFIX}" # tclConfig.sh needs a version of the _LIB_SUFFIX that has been eval'ed # so that the backslashes quoting the DBX braces are dropped. # Trick to replace DBGX with TCL_DBGX DBGX='${TCL_DBGX}' eval "TCL_LIB_FILE=${TCL_LIB_FILE}" TCL_LIBRARY='$(prefix)/lib/tcl$(VERSION)' PRIVATE_INCLUDE_DIR='$(includedir)' HTML_DIR='$(DISTDIR)/html' # Note: in the following variable, it's important to use the absolute # path name of the Tcl directory rather than "..": this is because # AIX remembers this path and will attempt to use it at run-time to look # up the Tcl library. if test "`uname -s`" = "Darwin" ; then SC_ENABLE_FRAMEWORK TCL_SHLIB_LD_EXTRAS="-compatibility_version ${TCL_VERSION} -current_version ${TCL_VERSION}`echo ${TCL_PATCH_LEVEL} | awk ['{match($0, "\\\.[0-9]+"); print substr($0,RSTART,RLENGTH)}']`" TCL_SHLIB_LD_EXTRAS="${TCL_SHLIB_LD_EXTRAS}"' -install_name ${DYLIB_INSTALL_DIR}/${TCL_LIB_FILE}' echo "$LDFLAGS " | grep -q -- '-prebind ' && TCL_SHLIB_LD_EXTRAS="${TCL_SHLIB_LD_EXTRAS}"' -seg1addr 0xa000000' TCL_SHLIB_LD_EXTRAS="${TCL_SHLIB_LD_EXTRAS}"' -sectcreate __TEXT __info_plist Tcl-Info.plist' EXTRA_TCLSH_LIBS='-sectcreate __TEXT __info_plist Tclsh-Info.plist' EXTRA_APP_CC_SWITCHES='-mdynamic-no-pic' tcl_config_files="${tcl_config_files} [Tcl-Info.plist:../macosx/Tcl-Info.plist.in Tclsh-Info.plist:../macosx/Tclsh-Info.plist.in]" TCL_YEAR="`date +%Y`" fi if test "$FRAMEWORK_BUILD" = "1" ; then AC_DEFINE(TCL_FRAMEWORK) # Construct a fake local framework structure to make linking with # '-framework Tcl' and running of tcltest work AC_OUTPUT_COMMANDS([test "$FRAMEWORK_BUILD" = "1" && n=Tcl && f=$n.framework && v=Versions/$VERSION && echo "creating $f" && rm -rf $f && mkdir -p $f/$v/Resources && ln -s $v/$n $v/Resources $f && ln -s ../../../$n $f/$v && ln -s ../../../../$n-Info.plist $f/$v/Resources/Info.plist && unset n f v ], [VERSION=${TCL_VERSION} FRAMEWORK_BUILD=${FRAMEWORK_BUILD}]) LD_LIBRARY_PATH_VAR="DYLD_FRAMEWORK_PATH" if test "${libdir}" = '${exec_prefix}/lib'; then # override libdir default libdir="/Library/Frameworks" fi TCL_LIB_FILE="Tcl" TCL_LIB_FLAG="-framework Tcl" TCL_BUILD_LIB_SPEC="-F`pwd` -framework Tcl" TCL_LIB_SPEC="-F${libdir} -framework Tcl" libdir="${libdir}/Tcl.framework/Versions/\${VERSION}" TCL_LIBRARY="${libdir}/Resources/Scripts" includedir="${libdir}/Headers" PRIVATE_INCLUDE_DIR="${libdir}/PrivateHeaders" HTML_DIR="${libdir}/Resources/Documentation/Reference/Tcl" EXTRA_INSTALL="install-private-headers html-tcl" EXTRA_BUILD_HTML='@ln -fs contents.htm $(HTML_INSTALL_DIR)/TclTOC.html' EXTRA_INSTALL_BINARIES='@echo "Installing Info.plist to $(LIB_INSTALL_DIR)/Resources" && mkdir -p "$(LIB_INSTALL_DIR)/Resources" && $(INSTALL_DATA) Tcl-Info.plist "$(LIB_INSTALL_DIR)/Resources/Info.plist"' EXTRA_INSTALL_BINARIES="$EXTRA_INSTALL_BINARIES"' && echo "Installing license.terms to $(LIB_INSTALL_DIR)/Resources" && $(INSTALL_DATA) "$(TOP_DIR)/license.terms" "$(LIB_INSTALL_DIR)/Resources"' EXTRA_INSTALL_BINARIES="$EXTRA_INSTALL_BINARIES"' && echo "Finalizing Tcl.framework" && rm -f "$(LIB_INSTALL_DIR)/../Current" && ln -s "$(VERSION)" "$(LIB_INSTALL_DIR)/../Current" && for f in "$(LIB_FILE)" tclConfig.sh Resources Headers PrivateHeaders; do rm -f "$(LIB_INSTALL_DIR)/../../$$f" && ln -s "Versions/Current/$$f" "$(LIB_INSTALL_DIR)/../.."; done && f="$(STUB_LIB_FILE)" && rm -f "$(LIB_INSTALL_DIR)/../../$$f" && ln -s "Versions/$(VERSION)/$$f" "$(LIB_INSTALL_DIR)/../.."' # Don't use AC_DEFINE for the following as the framework version define # needs to go into the Makefile even when using autoheader, so that we # can pick up a potential make override of VERSION. Also, don't put this # into CFLAGS as it should not go into tclConfig.sh EXTRA_CC_SWITCHES='-DTCL_FRAMEWORK_VERSION=\"$(VERSION)\"' else # libdir must be a fully qualified path and not ${exec_prefix}/lib eval libdir="$libdir" if test "$SHARED_BUILD" = "0" || test "$TCL_NEEDS_EXP_FILE" = "0"; then if test "${TCL_LIB_VERSIONS_OK}" = "ok"; then TCL_LIB_FLAG="-ltcl${TCL_VERSION}\${TCL_DBGX}" else TCL_LIB_FLAG="-ltcl`echo ${TCL_VERSION} | tr -d .`\${TCL_DBGX}" fi TCL_BUILD_LIB_SPEC="-L`pwd` ${TCL_LIB_FLAG}" TCL_LIB_SPEC="-L${libdir} ${TCL_LIB_FLAG}" else TCL_BUILD_EXP_FILE="lib.exp" eval "TCL_EXP_FILE=libtcl${TCL_EXPORT_FILE_SUFFIX}" # Replace DBGX with TCL_DBGX eval "TCL_EXP_FILE=\"${TCL_EXP_FILE}\"" if test "$GCC" = "yes" ; then TCL_BUILD_LIB_SPEC="-Wl,-bI:`pwd`/${TCL_BUILD_EXP_FILE} -L`pwd`" TCL_LIB_SPEC="-Wl,-bI:${libdir}/${TCL_EXP_FILE} -L`pwd`" else TCL_BUILD_LIB_SPEC="-bI:`pwd`/${TCL_BUILD_EXP_FILE}" TCL_LIB_SPEC="-bI:${libdir}/${TCL_EXP_FILE}" fi fi fi VERSION='${VERSION}' eval "CFG_TCL_SHARED_LIB_SUFFIX=${TCL_SHARED_LIB_SUFFIX}" eval "CFG_TCL_UNSHARED_LIB_SUFFIX=${TCL_UNSHARED_LIB_SUFFIX}" eval "CFG_TCL_EXPORT_FILE_SUFFIX=${TCL_EXPORT_FILE_SUFFIX}" VERSION=${TCL_VERSION} #-------------------------------------------------------------------- # The statements below define the symbol TCL_PACKAGE_PATH, which # gives a list of directories that may contain packages. The list # consists of one directory for machine-dependent binaries and # another for platform-independent scripts. #-------------------------------------------------------------------- if test "$FRAMEWORK_BUILD" = "1" ; then test -z "$TCL_PACKAGE_PATH" && \ TCL_PACKAGE_PATH="~/Library/Tcl /Library/Tcl /Network/Library/Tcl /System/Library/Tcl ~/Library/Frameworks /Library/Frameworks /Network/Library/Frameworks /System/Library/Frameworks" elif test "$prefix" != "$exec_prefix"; then TCL_PACKAGE_PATH="${libdir} ${prefix}/lib ${TCL_PACKAGE_PATH}" else TCL_PACKAGE_PATH="${prefix}/lib ${TCL_PACKAGE_PATH}" fi #-------------------------------------------------------------------- # The statements below define various symbols relating to Tcl # stub support. #-------------------------------------------------------------------- # Replace ${VERSION} with contents of ${TCL_VERSION} eval "TCL_STUB_LIB_FILE=libtclstub${TCL_UNSHARED_LIB_SUFFIX}" # Replace DBGX with TCL_DBGX eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\"" eval "TCL_STUB_LIB_DIR=${libdir}" if test "${TCL_LIB_VERSIONS_OK}" = "ok"; then TCL_STUB_LIB_FLAG="-ltclstub${TCL_VERSION}\${TCL_DBGX}" else TCL_STUB_LIB_FLAG="-ltclstub`echo ${TCL_VERSION} | tr -d .`\${TCL_DBGX}" fi TCL_BUILD_STUB_LIB_SPEC="-L`pwd` ${TCL_STUB_LIB_FLAG}" TCL_STUB_LIB_SPEC="-L${TCL_STUB_LIB_DIR} ${TCL_STUB_LIB_FLAG}" TCL_BUILD_STUB_LIB_PATH="`pwd`/${TCL_STUB_LIB_FILE}" TCL_STUB_LIB_PATH="${TCL_STUB_LIB_DIR}/${TCL_STUB_LIB_FILE}" # Install time header dir can be set via --includedir eval "TCL_INCLUDE_SPEC=\"-I${includedir}\"" #------------------------------------------------------------------------ # tclConfig.sh refers to this by a different name #------------------------------------------------------------------------ TCL_SHARED_BUILD=${SHARED_BUILD} AC_SUBST(TCL_VERSION) AC_SUBST(TCL_MAJOR_VERSION) AC_SUBST(TCL_MINOR_VERSION) AC_SUBST(TCL_PATCH_LEVEL) AC_SUBST(TCL_YEAR) AC_SUBST(TCL_LIB_FILE) AC_SUBST(TCL_LIB_FLAG) AC_SUBST(TCL_LIB_SPEC) AC_SUBST(TCL_STUB_LIB_FILE) AC_SUBST(TCL_STUB_LIB_FLAG) AC_SUBST(TCL_STUB_LIB_SPEC) AC_SUBST(TCL_STUB_LIB_PATH) AC_SUBST(TCL_INCLUDE_SPEC) AC_SUBST(TCL_BUILD_STUB_LIB_SPEC) AC_SUBST(TCL_BUILD_STUB_LIB_PATH) AC_SUBST(TCL_SRC_DIR) AC_SUBST(TCL_DBGX) AC_SUBST(CFG_TCL_SHARED_LIB_SUFFIX) AC_SUBST(CFG_TCL_UNSHARED_LIB_SUFFIX) AC_SUBST(CFG_TCL_EXPORT_FILE_SUFFIX) AC_SUBST(TCL_SHARED_BUILD) AC_SUBST(LD_LIBRARY_PATH_VAR) AC_SUBST(TCL_BUILD_LIB_SPEC) AC_SUBST(TCL_NEEDS_EXP_FILE) AC_SUBST(TCL_BUILD_EXP_FILE) AC_SUBST(TCL_EXP_FILE) AC_SUBST(TCL_LIB_VERSIONS_OK) AC_SUBST(TCL_SHARED_LIB_SUFFIX) AC_SUBST(TCL_UNSHARED_LIB_SUFFIX) AC_SUBST(TCL_HAS_LONGLONG) AC_SUBST(DTRACE_SRC) AC_SUBST(DTRACE_HDR) AC_SUBST(DTRACE_OBJ) AC_SUBST(MAKEFILE_SHELL) AC_SUBST(BUILD_DLTEST) AC_SUBST(TCL_PACKAGE_PATH) AC_SUBST(TCL_LIBRARY) AC_SUBST(PRIVATE_INCLUDE_DIR) AC_SUBST(HTML_DIR) AC_SUBST(EXTRA_CC_SWITCHES) AC_SUBST(EXTRA_APP_CC_SWITCHES) AC_SUBST(EXTRA_INSTALL) AC_SUBST(EXTRA_INSTALL_BINARIES) AC_SUBST(EXTRA_BUILD_HTML) AC_SUBST(EXTRA_TCLSH_LIBS) SC_OUTPUT_COMMANDS_PRE tcl_config_files="${tcl_config_files} [Makefile dltest/Makefile tclConfig.sh]" AC_OUTPUT([${tcl_config_files}]) tcl8.4.20/unix/tclLoadOSF.c0000644003604700454610000001330511737050675014003 0ustar dgp771div/* * tclLoadOSF.c -- * * This procedure provides a version of the TclLoadFile that works * under OSF/1 1.0/1.1/1.2 and related systems, utilizing the old OSF/1 * /sbin/loader and /usr/include/loader.h. OSF/1 versions from 1.3 and * on use ELF, rtld, and dlopen()[/usr/include/ldfcn.h]. * * This is useful for: * OSF/1 1.0, 1.1, 1.2 (from OSF) * includes: MK4 and AD1 (from OSF RI) * OSF/1 1.3 (from OSF) using ROSE * HP OSF/1 1.0 ("Acorn") using COFF * * This is likely to be useful for: * Paragon OSF/1 (from Intel) * HI-OSF/1 (from Hitachi) * * This is NOT to be used on: * Digitial Alpha OSF/1 systems * OSF/1 1.3 or later (from OSF) using ELF * includes: MK6, MK7, AD2, AD3 (from OSF RI) * * This approach to things was utter @&^#; thankfully, * OSF/1 eventually supported dlopen(). * * John Robert LoVerso * * Copyright (c) 1995-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include #include /* *---------------------------------------------------------------------- * * TclpDlopen -- * * Dynamically loads a binary code file into memory and returns * a handle to the new code. * * Results: * A standard Tcl completion code. If an error occurs, an error * message is left in the interp's result. * * Side effects: * New code suddenly appears in memory. * *---------------------------------------------------------------------- */ int TclpDlopen(interp, pathPtr, loadHandle, unloadProcPtr) Tcl_Interp *interp; /* Used for error reporting. */ Tcl_Obj *pathPtr; /* Name of the file containing the desired * code (UTF-8). */ Tcl_LoadHandle *loadHandle; /* Filled with token for dynamically loaded * file which will be passed back to * (*unloadProcPtr)() to unload the file. */ Tcl_FSUnloadFileProc **unloadProcPtr; /* Filled with address of Tcl_FSUnloadFileProc * function which should be used for * this file. */ { ldr_module_t lm; char *pkg; char *fileName = Tcl_GetString(pathPtr); CONST char *native; /* * First try the full path the user gave us. This is particularly * important if the cwd is inside a vfs, and we are trying to load * using a relative path. */ native = Tcl_FSGetNativePath(pathPtr); lm = (Tcl_PackageInitProc *) load(native, LDR_NOFLAGS); if (lm == LDR_NULL_MODULE) { /* * Let the OS loader examine the binary search path for * whatever string the user gave us which hopefully refers * to a file on the binary path */ Tcl_DString ds; native = Tcl_UtfToExternalDString(NULL, fileName, -1, &ds); lm = (Tcl_PackageInitProc *) load(native, LDR_NOFLAGS); Tcl_DStringFree(&ds); } if (lm == LDR_NULL_MODULE) { Tcl_AppendResult(interp, "couldn't load file \"", fileName, "\": ", Tcl_PosixError (interp), (char *) NULL); return TCL_ERROR; } *clientDataPtr = NULL; /* * My convention is to use a [OSF loader] package name the same as shlib, * since the idiots never implemented ldr_lookup() and it is otherwise * impossible to get a package name given a module. * * I build loadable modules with a makefile rule like * ld ... -export $@: -o $@ $(OBJS) */ if ((pkg = strrchr(fileName, '/')) == NULL) { pkg = fileName; } else { pkg++; } *loadHandle = pkg; *unloadProcPtr = &TclpUnloadFile; return TCL_OK; } /* *---------------------------------------------------------------------- * * TclpFindSymbol -- * * Looks up a symbol, by name, through a handle associated with * a previously loaded piece of code (shared library). * * Results: * Returns a pointer to the function associated with 'symbol' if * it is found. Otherwise returns NULL and may leave an error * message in the interp's result. * *---------------------------------------------------------------------- */ Tcl_PackageInitProc* TclpFindSymbol(interp, loadHandle, symbol) Tcl_Interp *interp; Tcl_LoadHandle loadHandle; CONST char *symbol; { return ldr_lookup_package((char *)loadHandle, symbol); } /* *---------------------------------------------------------------------- * * TclpUnloadFile -- * * Unloads a dynamically loaded binary code file from memory. * Code pointers in the formerly loaded file are no longer valid * after calling this function. * * Results: * None. * * Side effects: * Does nothing. Can anything be done? * *---------------------------------------------------------------------- */ void TclpUnloadFile(loadHandle) Tcl_LoadHandle loadHandle; /* loadHandle returned by a previous call * to TclpDlopen(). The loadHandle is * a token that represents the loaded * file. */ { } /* *---------------------------------------------------------------------- * * TclGuessPackageName -- * * If the "load" command is invoked without providing a package * name, this procedure is invoked to try to figure it out. * * Results: * Always returns 0 to indicate that we couldn't figure out a * package name; generic code will then try to guess the package * from the file name. A return value of 1 would have meant that * we figured out the package name and put it in bufPtr. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclGuessPackageName(fileName, bufPtr) CONST char *fileName; /* Name of file containing package (already * translated to local form if needed). */ Tcl_DString *bufPtr; /* Initialized empty dstring. Append * package name to this if possible. */ { return 0; } tcl8.4.20/unix/tclLoadDyld.c0000644003604700454610000005300711737050675014253 0ustar dgp771div/* * tclLoadDyld.c -- * * This procedure provides a version of the TclLoadFile that works with * Apple's dyld dynamic loading. * Original version of his file (superseded long ago) provided by * Wilfredo Sanchez (wsanchez@apple.com). * * Copyright (c) 1995 Apple Computer, Inc. * Copyright (c) 2001-2007 Daniel A. Steffen * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" #ifndef MODULE_SCOPE #define MODULE_SCOPE extern #endif #ifndef TCL_DYLD_USE_DLFCN /* * Use preferred dlfcn API on 10.4 and later */ # if !defined(NO_DLFCN_H) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1040 # define TCL_DYLD_USE_DLFCN 1 # else # define TCL_DYLD_USE_DLFCN 0 # endif #endif #ifndef TCL_DYLD_USE_NSMODULE /* * Use deprecated NSModule API only to support 10.3 and earlier: */ # if MAC_OS_X_VERSION_MIN_REQUIRED < 1040 # define TCL_DYLD_USE_NSMODULE 1 # else # define TCL_DYLD_USE_NSMODULE 0 # endif #endif #if TCL_DYLD_USE_DLFCN #include #if defined(HAVE_WEAK_IMPORT) && MAC_OS_X_VERSION_MIN_REQUIRED < 1040 /* * Support for weakly importing dlfcn API. */ extern void *dlopen(const char *path, int mode) WEAK_IMPORT_ATTRIBUTE; extern void *dlsym(void *handle, const char *symbol) WEAK_IMPORT_ATTRIBUTE; extern int dlclose(void *handle) WEAK_IMPORT_ATTRIBUTE; extern char *dlerror(void) WEAK_IMPORT_ATTRIBUTE; #endif #endif #if TCL_DYLD_USE_NSMODULE || defined(TCL_LOAD_FROM_MEMORY) #include #include #include #include #include #undef panic #include #include typedef struct Tcl_DyldModuleHandle { struct Tcl_DyldModuleHandle *nextPtr; NSModule module; } Tcl_DyldModuleHandle; #endif /* TCL_DYLD_USE_NSMODULE */ typedef struct Tcl_DyldLoadHandle { #if TCL_DYLD_USE_DLFCN void *dlHandle; #endif #if TCL_DYLD_USE_NSMODULE || defined(TCL_LOAD_FROM_MEMORY) const struct mach_header *dyldLibHeader; Tcl_DyldModuleHandle *modulePtr; #endif } Tcl_DyldLoadHandle; #if (TCL_DYLD_USE_DLFCN && MAC_OS_X_VERSION_MIN_REQUIRED < 1040) || \ defined(TCL_LOAD_FROM_MEMORY) MODULE_SCOPE long tclMacOSXDarwinRelease; #endif #ifdef TCL_DEBUG_LOAD #define TclLoadDbgMsg(m, ...) do { \ fprintf(stderr, "%s:%d: %s(): " m ".\n", \ strrchr(__FILE__, '/')+1, __LINE__, __func__, ##__VA_ARGS__); \ } while (0) #else #define TclLoadDbgMsg(m, ...) #endif #if TCL_DYLD_USE_NSMODULE || defined(TCL_LOAD_FROM_MEMORY) /* *---------------------------------------------------------------------- * * DyldOFIErrorMsg -- * * Converts a numerical NSObjectFileImage error into an error message * string. * * Results: * Error message string. * * Side effects: * None. * *---------------------------------------------------------------------- */ static CONST char* DyldOFIErrorMsg( int err) { switch(err) { case NSObjectFileImageSuccess: return NULL; case NSObjectFileImageFailure: return "object file setup failure"; case NSObjectFileImageInappropriateFile: return "not a Mach-O MH_BUNDLE file"; case NSObjectFileImageArch: return "no object for this architecture"; case NSObjectFileImageFormat: return "bad object file format"; case NSObjectFileImageAccess: return "can't read object file"; default: return "unknown error"; } } #endif /* TCL_DYLD_USE_NSMODULE */ /* *---------------------------------------------------------------------- * * TclpDlopen -- * * Dynamically loads a binary code file into memory and returns a handle * to the new code. * * Results: * A standard Tcl completion code. If an error occurs, an error message * is left in the interpreter's result. * * Side effects: * New code suddenly appears in memory. * *---------------------------------------------------------------------- */ MODULE_SCOPE int TclpDlopen( Tcl_Interp *interp, /* Used for error reporting. */ Tcl_Obj *pathPtr, /* Name of the file containing the desired * code (UTF-8). */ Tcl_LoadHandle *loadHandle, /* Filled with token for dynamically loaded * file which will be passed back to * (*unloadProcPtr)() to unload the file. */ Tcl_FSUnloadFileProc **unloadProcPtr) /* Filled with address of Tcl_FSUnloadFileProc * function which should be used for this * file. */ { Tcl_DyldLoadHandle *dyldLoadHandle; #if TCL_DYLD_USE_DLFCN void *dlHandle = NULL; #endif #if TCL_DYLD_USE_NSMODULE || defined(TCL_LOAD_FROM_MEMORY) const struct mach_header *dyldLibHeader = NULL; Tcl_DyldModuleHandle *modulePtr = NULL; #endif #if TCL_DYLD_USE_NSMODULE NSLinkEditErrors editError; int errorNumber; const char *errorName, *objFileImageErrMsg = NULL; #endif const char *errMsg = NULL; int result; Tcl_DString ds; char *fileName = NULL; const char *nativePath, *nativeFileName = NULL; /* * First try the full path the user gave us. This is particularly * important if the cwd is inside a vfs, and we are trying to load using a * relative path. */ nativePath = Tcl_FSGetNativePath(pathPtr); #if TCL_DYLD_USE_DLFCN #if MAC_OS_X_VERSION_MIN_REQUIRED < 1040 if (tclMacOSXDarwinRelease >= 8) #endif { dlHandle = dlopen(nativePath, RTLD_NOW | RTLD_LOCAL); if (!dlHandle) { /* * Let the OS loader examine the binary search path for whatever * string the user gave us which hopefully refers to a file on the * binary path. */ fileName = Tcl_GetString(pathPtr); nativeFileName = Tcl_UtfToExternalDString(NULL, fileName, -1, &ds); dlHandle = dlopen(nativeFileName, RTLD_NOW | RTLD_LOCAL); } if (dlHandle) { TclLoadDbgMsg("dlopen() successful"); } else { errMsg = dlerror(); TclLoadDbgMsg("dlopen() failed: %s", errMsg); } } if (!dlHandle) #endif /* TCL_DYLD_USE_DLFCN */ { #if TCL_DYLD_USE_NSMODULE dyldLibHeader = NSAddImage(nativePath, NSADDIMAGE_OPTION_RETURN_ON_ERROR); if (dyldLibHeader) { TclLoadDbgMsg("NSAddImage() successful"); } else { NSLinkEditError(&editError, &errorNumber, &errorName, &errMsg); if (editError == NSLinkEditFileAccessError) { /* * The requested file was not found. Let the OS loader examine * the binary search path for whatever string the user gave us * which hopefully refers to a file on the binary path. */ if (!fileName) { fileName = Tcl_GetString(pathPtr); nativeFileName = Tcl_UtfToExternalDString(NULL, fileName, -1, &ds); } dyldLibHeader = NSAddImage(nativeFileName, NSADDIMAGE_OPTION_WITH_SEARCHING | NSADDIMAGE_OPTION_RETURN_ON_ERROR); if (dyldLibHeader) { TclLoadDbgMsg("NSAddImage() successful"); } else { NSLinkEditError(&editError, &errorNumber, &errorName, &errMsg); TclLoadDbgMsg("NSAddImage() failed: %s", errMsg); } } else if ((editError == NSLinkEditFileFormatError && errorNumber == EBADMACHO) || editError == NSLinkEditOtherError){ NSObjectFileImageReturnCode err; NSObjectFileImage dyldObjFileImage; NSModule module; /* * The requested file was found but was not of type MH_DYLIB, * attempt to load it as a MH_BUNDLE. */ err = NSCreateObjectFileImageFromFile(nativePath, &dyldObjFileImage); if (err == NSObjectFileImageSuccess && dyldObjFileImage) { TclLoadDbgMsg("NSCreateObjectFileImageFromFile() " "successful"); module = NSLinkModule(dyldObjFileImage, nativePath, NSLINKMODULE_OPTION_BINDNOW | NSLINKMODULE_OPTION_RETURN_ON_ERROR); NSDestroyObjectFileImage(dyldObjFileImage); if (module) { modulePtr = (Tcl_DyldModuleHandle *) ckalloc(sizeof(Tcl_DyldModuleHandle)); modulePtr->module = module; modulePtr->nextPtr = NULL; TclLoadDbgMsg("NSLinkModule() successful"); } else { NSLinkEditError(&editError, &errorNumber, &errorName, &errMsg); TclLoadDbgMsg("NSLinkModule() failed: %s", errMsg); } } else { objFileImageErrMsg = DyldOFIErrorMsg(err); TclLoadDbgMsg("NSCreateObjectFileImageFromFile() failed: " "%s", objFileImageErrMsg); } } } #endif /* TCL_DYLD_USE_NSMODULE */ } if (0 #if TCL_DYLD_USE_DLFCN || dlHandle #endif #if TCL_DYLD_USE_NSMODULE || dyldLibHeader || modulePtr #endif ) { dyldLoadHandle = (Tcl_DyldLoadHandle *) ckalloc(sizeof(Tcl_DyldLoadHandle)); #if TCL_DYLD_USE_DLFCN dyldLoadHandle->dlHandle = dlHandle; #endif #if TCL_DYLD_USE_NSMODULE || defined(TCL_LOAD_FROM_MEMORY) dyldLoadHandle->dyldLibHeader = dyldLibHeader; dyldLoadHandle->modulePtr = modulePtr; #endif *loadHandle = (Tcl_LoadHandle) dyldLoadHandle; *unloadProcPtr = &TclpUnloadFile; result = TCL_OK; } else { Tcl_AppendResult(interp, errMsg, NULL); #if TCL_DYLD_USE_NSMODULE if (objFileImageErrMsg) { Tcl_AppendResult(interp, "\nNSCreateObjectFileImageFromFile() " "error: ", objFileImageErrMsg, NULL); } #endif result = TCL_ERROR; } if(fileName) { Tcl_DStringFree(&ds); } return result; } /* *---------------------------------------------------------------------- * * TclpFindSymbol -- * * Looks up a symbol, by name, through a handle associated with a * previously loaded piece of code (shared library). * * Results: * Returns a pointer to the function associated with 'symbol' if it is * found. Otherwise returns NULL and may leave an error message in the * interp's result. * *---------------------------------------------------------------------- */ MODULE_SCOPE Tcl_PackageInitProc * TclpFindSymbol( Tcl_Interp *interp, /* For error reporting. */ Tcl_LoadHandle loadHandle, /* Handle from TclpDlopen. */ CONST char *symbol) /* Symbol name to look up. */ { Tcl_DyldLoadHandle *dyldLoadHandle = (Tcl_DyldLoadHandle *) loadHandle; Tcl_PackageInitProc *proc = NULL; const char *errMsg = NULL; Tcl_DString ds; const char *native; native = Tcl_UtfToExternalDString(NULL, symbol, -1, &ds); #if TCL_DYLD_USE_DLFCN if (dyldLoadHandle->dlHandle) { proc = dlsym(dyldLoadHandle->dlHandle, native); if (proc) { TclLoadDbgMsg("dlsym() successful"); } else { errMsg = dlerror(); TclLoadDbgMsg("dlsym() failed: %s", errMsg); } } else #endif /* TCL_DYLD_USE_DLFCN */ { #if TCL_DYLD_USE_NSMODULE || defined(TCL_LOAD_FROM_MEMORY) NSSymbol nsSymbol = NULL; Tcl_DString newName; /* * dyld adds an underscore to the beginning of symbol names. */ Tcl_DStringInit(&newName); Tcl_DStringAppend(&newName, "_", 1); native = Tcl_DStringAppend(&newName, native, -1); if (dyldLoadHandle->dyldLibHeader) { nsSymbol = NSLookupSymbolInImage(dyldLoadHandle->dyldLibHeader, native, NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR); if (nsSymbol) { TclLoadDbgMsg("NSLookupSymbolInImage() successful"); #ifdef DYLD_SUPPORTS_DYLIB_UNLOADING /* * Until dyld supports unloading of MY_DYLIB binaries, the * following is not needed. */ NSModule module = NSModuleForSymbol(nsSymbol); Tcl_DyldModuleHandle *modulePtr = dyldLoadHandle->modulePtr; while (modulePtr != NULL) { if (module == modulePtr->module) { break; } modulePtr = modulePtr->nextPtr; } if (modulePtr == NULL) { modulePtr = (Tcl_DyldModuleHandle *) ckalloc(sizeof(Tcl_DyldModuleHandle)); modulePtr->module = module; modulePtr->nextPtr = dyldLoadHandle->modulePtr; dyldLoadHandle->modulePtr = modulePtr; } #endif /* DYLD_SUPPORTS_DYLIB_UNLOADING */ } else { NSLinkEditErrors editError; int errorNumber; const char *errorName; NSLinkEditError(&editError, &errorNumber, &errorName, &errMsg); TclLoadDbgMsg("NSLookupSymbolInImage() failed: %s", errMsg); } } else if (dyldLoadHandle->modulePtr) { nsSymbol = NSLookupSymbolInModule( dyldLoadHandle->modulePtr->module, native); if (nsSymbol) { TclLoadDbgMsg("NSLookupSymbolInModule() successful"); } else { TclLoadDbgMsg("NSLookupSymbolInModule() failed"); } } if (nsSymbol) { proc = NSAddressOfSymbol(nsSymbol); if (proc) { TclLoadDbgMsg("NSAddressOfSymbol() successful"); } else { TclLoadDbgMsg("NSAddressOfSymbol() failed"); } } Tcl_DStringFree(&newName); #endif /* TCL_DYLD_USE_NSMODULE */ } Tcl_DStringFree(&ds); if (errMsg) { Tcl_AppendResult(interp, errMsg, NULL); } return proc; } /* *---------------------------------------------------------------------- * * TclpUnloadFile -- * * Unloads a dynamically loaded binary code file from memory. Code * pointers in the formerly loaded file are no longer valid after calling * this function. * * Results: * None. * * Side effects: * Code dissapears from memory. Note that dyld currently only supports * unloading of binaries of type MH_BUNDLE loaded with NSLinkModule() in * TclpDlopen() above. * *---------------------------------------------------------------------- */ MODULE_SCOPE void TclpUnloadFile( Tcl_LoadHandle loadHandle) /* loadHandle returned by a previous call to * TclpDlopen(). The loadHandle is a token * that represents the loaded file. */ { Tcl_DyldLoadHandle *dyldLoadHandle = (Tcl_DyldLoadHandle *) loadHandle; #if TCL_DYLD_USE_DLFCN if (dyldLoadHandle->dlHandle) { int result; result = dlclose(dyldLoadHandle->dlHandle); if (!result) { TclLoadDbgMsg("dlclose() successful"); } else { TclLoadDbgMsg("dlclose() failed: %s", dlerror()); } } else #endif /* TCL_DYLD_USE_DLFCN */ { #if TCL_DYLD_USE_NSMODULE || defined(TCL_LOAD_FROM_MEMORY) Tcl_DyldModuleHandle *modulePtr = dyldLoadHandle->modulePtr; while (modulePtr != NULL) { void *ptr; bool result; result = NSUnLinkModule(modulePtr->module, NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES); if (result) { TclLoadDbgMsg("NSUnLinkModule() successful"); } else { TclLoadDbgMsg("NSUnLinkModule() failed"); } ptr = modulePtr; modulePtr = modulePtr->nextPtr; ckfree(ptr); } #endif /* TCL_DYLD_USE_NSMODULE */ } ckfree((char*) dyldLoadHandle); } /* *---------------------------------------------------------------------- * * TclGuessPackageName -- * * If the "load" command is invoked without providing a package name, * this procedure is invoked to try to figure it out. * * Results: * Always returns 0 to indicate that we couldn't figure out a package * name; generic code will then try to guess the package from the file * name. A return value of 1 would have meant that we figured out the * package name and put it in bufPtr. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclGuessPackageName( CONST char *fileName, /* Name of file containing package (already * translated to local form if needed). */ Tcl_DString *bufPtr) /* Initialized empty dstring. Append package * name to this if possible. */ { return 0; } #ifdef TCL_LOAD_FROM_MEMORY /* *---------------------------------------------------------------------- * * TclpLoadMemoryGetBuffer -- * * Allocate a buffer that can be used with TclpLoadMemory() below. * * Results: * Pointer to allocated buffer or NULL if an error occurs. * * Side effects: * Buffer is allocated. * *---------------------------------------------------------------------- */ MODULE_SCOPE void * TclpLoadMemoryGetBuffer( Tcl_Interp *interp, /* Used for error reporting. */ int size) /* Size of desired buffer. */ { void *buffer = NULL; /* * NSCreateObjectFileImageFromMemory is available but always fails * prior to Darwin 7. */ if (tclMacOSXDarwinRelease >= 7) { /* * We must allocate the buffer using vm_allocate, because * NSCreateObjectFileImageFromMemory will dispose of it using * vm_deallocate. */ if (vm_allocate(mach_task_self(), (vm_address_t *) &buffer, size, 1)) { buffer = NULL; } } return buffer; } /* *---------------------------------------------------------------------- * * TclpLoadMemory -- * * Dynamically loads binary code file from memory and returns a handle to * the new code. * * Results: * A standard Tcl completion code. If an error occurs, an error message * is left in the interpreter's result. * * Side effects: * New code is loaded from memory. * *---------------------------------------------------------------------- */ MODULE_SCOPE int TclpLoadMemory( Tcl_Interp *interp, /* Used for error reporting. */ void *buffer, /* Buffer containing the desired code * (allocated with TclpLoadMemoryGetBuffer). */ int size, /* Allocation size of buffer. */ int codeSize, /* Size of code data read into buffer or -1 if * an error occurred and the buffer should * just be freed. */ Tcl_LoadHandle *loadHandle, /* Filled with token for dynamically loaded * file which will be passed back to * (*unloadProcPtr)() to unload the file. */ Tcl_FSUnloadFileProc **unloadProcPtr) /* Filled with address of Tcl_FSUnloadFileProc * function which should be used for this * file. */ { Tcl_DyldLoadHandle *dyldLoadHandle; NSObjectFileImage dyldObjFileImage = NULL; Tcl_DyldModuleHandle *modulePtr; NSModule module; const char *objFileImageErrMsg = NULL; /* * Try to create an object file image that we can load from. */ if (codeSize >= 0) { NSObjectFileImageReturnCode err = NSObjectFileImageSuccess; const struct fat_header *fh = buffer; uint32_t ms = 0; #ifndef __LP64__ const struct mach_header *mh = NULL; #define mh_size sizeof(struct mach_header) #define mh_magic MH_MAGIC #define arch_abi 0 #else const struct mach_header_64 *mh = NULL; #define mh_size sizeof(struct mach_header_64) #define mh_magic MH_MAGIC_64 #define arch_abi CPU_ARCH_ABI64 #endif if ((size_t) codeSize >= sizeof(struct fat_header) && fh->magic == OSSwapHostToBigInt32(FAT_MAGIC)) { uint32_t fh_nfat_arch = OSSwapBigToHostInt32(fh->nfat_arch); /* * Fat binary, try to find mach_header for our architecture */ TclLoadDbgMsg("Fat binary, %d archs", fh_nfat_arch); if ((size_t) codeSize >= sizeof(struct fat_header) + fh_nfat_arch * sizeof(struct fat_arch)) { void *fatarchs = (char*)buffer + sizeof(struct fat_header); const NXArchInfo *arch = NXGetLocalArchInfo(); struct fat_arch *fa; if (fh->magic != FAT_MAGIC) { swap_fat_arch(fatarchs, fh_nfat_arch, arch->byteorder); } fa = NXFindBestFatArch(arch->cputype | arch_abi, arch->cpusubtype, fatarchs, fh_nfat_arch); if (fa) { TclLoadDbgMsg("NXFindBestFatArch() successful: " "local cputype %d subtype %d, " "fat cputype %d subtype %d", arch->cputype | arch_abi, arch->cpusubtype, fa->cputype, fa->cpusubtype); mh = (void*)((char*)buffer + fa->offset); ms = fa->size; } else { TclLoadDbgMsg("NXFindBestFatArch() failed"); err = NSObjectFileImageInappropriateFile; } if (fh->magic != FAT_MAGIC) { swap_fat_arch(fatarchs, fh_nfat_arch, arch->byteorder); } } else { TclLoadDbgMsg("Fat binary header failure"); err = NSObjectFileImageInappropriateFile; } } else { /* * Thin binary */ TclLoadDbgMsg("Thin binary"); mh = buffer; ms = codeSize; } if (ms && !(ms >= mh_size && mh->magic == mh_magic && mh->filetype == MH_BUNDLE)) { TclLoadDbgMsg("Inappropriate file: magic %x filetype %d", mh->magic, mh->filetype); err = NSObjectFileImageInappropriateFile; } if (err == NSObjectFileImageSuccess) { err = NSCreateObjectFileImageFromMemory(buffer, codeSize, &dyldObjFileImage); if (err == NSObjectFileImageSuccess) { TclLoadDbgMsg("NSCreateObjectFileImageFromMemory() " "successful"); } else { objFileImageErrMsg = DyldOFIErrorMsg(err); TclLoadDbgMsg("NSCreateObjectFileImageFromMemory() failed: %s", objFileImageErrMsg); } } else { objFileImageErrMsg = DyldOFIErrorMsg(err); } } /* * If it went wrong (or we were asked to just deallocate), get rid of the * memory block and create an error message. */ if (dyldObjFileImage == NULL) { vm_deallocate(mach_task_self(), (vm_address_t) buffer, size); if (objFileImageErrMsg != NULL) { Tcl_AppendResult(interp, "NSCreateObjectFileImageFromMemory() " "error: ", objFileImageErrMsg, NULL); } return TCL_ERROR; } /* * Extract the module we want from the image of the object file. */ module = NSLinkModule(dyldObjFileImage, "[Memory Based Bundle]", NSLINKMODULE_OPTION_BINDNOW | NSLINKMODULE_OPTION_RETURN_ON_ERROR); NSDestroyObjectFileImage(dyldObjFileImage); if (module) { TclLoadDbgMsg("NSLinkModule() successful"); } else { NSLinkEditErrors editError; int errorNumber; const char *errorName, *errMsg; NSLinkEditError(&editError, &errorNumber, &errorName, &errMsg); TclLoadDbgMsg("NSLinkModule() failed: %s", errMsg); Tcl_AppendResult(interp, errMsg, NULL); return TCL_ERROR; } /* * Stash the module reference within the load handle we create and return. */ modulePtr = (Tcl_DyldModuleHandle *) ckalloc(sizeof(Tcl_DyldModuleHandle)); modulePtr->module = module; modulePtr->nextPtr = NULL; dyldLoadHandle = (Tcl_DyldLoadHandle *) ckalloc(sizeof(Tcl_DyldLoadHandle)); #if TCL_DYLD_USE_DLFCN dyldLoadHandle->dlHandle = NULL; #endif dyldLoadHandle->dyldLibHeader = NULL; dyldLoadHandle->modulePtr = modulePtr; *loadHandle = (Tcl_LoadHandle) dyldLoadHandle; *unloadProcPtr = &TclpUnloadFile; return TCL_OK; } #endif /* TCL_LOAD_FROM_MEMORY */ /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 79 * End: */ tcl8.4.20/unix/tcl.spec0000644003604700454610000000320112153151142013315 0ustar dgp771div# This file is the basis for a binary Tcl RPM for Linux. %define version 8.4.20 %define directory /usr/local Summary: Tcl scripting language development environment Name: tcl Version: %{version} Release: 1 Copyright: BSD Group: Development/Languages Source: http://prdownloads.sourceforge.net/tcl/tcl%{version}-src.tar.gz URL: http://www.tcl.tk/ Packager: Carina Buildroot: /var/tmp/%{name}%{version} %description The Tcl (Tool Command Language) provides a powerful platform for creating integration applications that tie together diverse applications, protocols, devices, and frameworks. When paired with the Tk toolkit, Tcl provides the fastest and most powerful way to create GUI applications that run on PCs, Unix, and the Macintosh. Tcl can also be used for a variety of web-related tasks and for creating powerful command languages for applications. %prep %build ./configure --prefix %{directory} --exec-prefix %{directory} make CFLAGS=$RPM_OPT_FLAGS %install rm -rf $RPM_BUILD_ROOT make INSTALL_ROOT=$RPM_BUILD_ROOT install %clean rm -rf $RPM_BUILD_ROOT # to create the tcl files list, comment out tk in the install section above, # then run "rpm -bi" then do a find from the build root directory, # and remove the files in specific directories which suffice by themselves, # then to create the files list for tk, uncomment tk, comment out tcl, # then rm -rf $RPM_BUILD_ROOT then rpm --short-circuit -bi then redo a find, # and remove the files in specific directories which suffice by themselves. %files %defattr(-,root,root) %{directory}/lib %{directory}/bin %{directory}/include %{directory}/man/man1 %{directory}/man/man3 %{directory}/man/mann tcl8.4.20/unix/tcl.m40000644003604700454610000031242012153151142012711 0ustar dgp771div#------------------------------------------------------------------------ # SC_PATH_TCLCONFIG -- # # Locate the tclConfig.sh file and perform a sanity check on # the Tcl compile flags # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-tcl=... # # Defines the following vars: # TCL_BIN_DIR Full path to the directory containing # the tclConfig.sh file #------------------------------------------------------------------------ AC_DEFUN([SC_PATH_TCLCONFIG], [ # # Ok, lets find the tcl configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-tcl # if test x"${no_tcl}" = x ; then # we reset no_tcl in case something fails here no_tcl=true AC_ARG_WITH(tcl, [ --with-tcl directory containing tcl configuration (tclConfig.sh)], with_tclconfig=${withval}) AC_MSG_CHECKING([for Tcl configuration]) AC_CACHE_VAL(ac_cv_c_tclconfig,[ # First check to see if --with-tcl was specified. if test x"${with_tclconfig}" != x ; then case "${with_tclconfig}" in */tclConfig.sh ) if test -f "${with_tclconfig}"; then AC_MSG_WARN([--with-tcl argument should refer to directory containing tclConfig.sh, not to tclConfig.sh itself]) with_tclconfig="`echo "${with_tclconfig}" | sed 's!/tclConfig\.sh$!!'`" fi ;; esac if test -f "${with_tclconfig}/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd "${with_tclconfig}"; pwd)`" else AC_MSG_ERROR([${with_tclconfig} directory doesn't contain tclConfig.sh]) fi fi # then check for a private Tcl installation if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ ../tcl \ `ls -dr ../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../tcl[[8-9]].[[0-9]]* 2>/dev/null` \ ../../tcl \ `ls -dr ../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../tcl[[8-9]].[[0-9]]* 2>/dev/null` \ ../../../tcl \ `ls -dr ../../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do if test -f "$i/unix/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/unix; pwd)`" break fi done fi # on Darwin, check in Framework installation locations if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ `ls -d /Library/Frameworks 2>/dev/null` \ `ls -d /Network/Library/Frameworks 2>/dev/null` \ `ls -d /System/Library/Frameworks 2>/dev/null` \ ; do if test -f "$i/Tcl.framework/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/Tcl.framework; pwd)`" break fi done fi # check in a few common install locations if test x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ `ls -d /usr/lib64 2>/dev/null` \ ; do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i; pwd)`" break fi done fi # check in a few other private locations if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ ${srcdir}/../tcl \ `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do if test -f "$i/unix/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/unix; pwd)`" break fi done fi ]) if test x"${ac_cv_c_tclconfig}" = x ; then TCL_BIN_DIR="# no Tcl configs found" AC_MSG_ERROR([Can't find Tcl configuration definitions. Use --with-tcl to specify a directory containing tclConfig.sh]) else no_tcl= TCL_BIN_DIR="${ac_cv_c_tclconfig}" AC_MSG_RESULT([found ${TCL_BIN_DIR}/tclConfig.sh]) fi fi ]) #------------------------------------------------------------------------ # SC_PATH_TKCONFIG -- # # Locate the tkConfig.sh file # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-tk=... # # Defines the following vars: # TK_BIN_DIR Full path to the directory containing # the tkConfig.sh file #------------------------------------------------------------------------ AC_DEFUN([SC_PATH_TKCONFIG], [ # # Ok, lets find the tk configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-tk # if test x"${no_tk}" = x ; then # we reset no_tk in case something fails here no_tk=true AC_ARG_WITH(tk, [ --with-tk directory containing tk configuration (tkConfig.sh)], with_tkconfig=${withval}) AC_MSG_CHECKING([for Tk configuration]) AC_CACHE_VAL(ac_cv_c_tkconfig,[ # First check to see if --with-tkconfig was specified. if test x"${with_tkconfig}" != x ; then case "${with_tkconfig}" in */tkConfig.sh ) if test -f "${with_tkconfig}"; then AC_MSG_WARN([--with-tk argument should refer to directory containing tkConfig.sh, not to tkConfig.sh itself]) with_tkconfig="`echo "${with_tkconfig}" | sed 's!/tkConfig\.sh$!!'`" fi ;; esac if test -f "${with_tkconfig}/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd "${with_tkconfig}"; pwd)`" else AC_MSG_ERROR([${with_tkconfig} directory doesn't contain tkConfig.sh]) fi fi # then check for a private Tk library if test x"${ac_cv_c_tkconfig}" = x ; then for i in \ ../tk \ `ls -dr ../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../tk[[8-9]].[[0-9]]* 2>/dev/null` \ ../../tk \ `ls -dr ../../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../tk[[8-9]].[[0-9]]* 2>/dev/null` \ ../../../tk \ `ls -dr ../../../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do if test -f "$i/unix/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/unix; pwd)`" break fi done fi # on Darwin, check in Framework installation locations if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ `ls -d /Library/Frameworks 2>/dev/null` \ `ls -d /Network/Library/Frameworks 2>/dev/null` \ `ls -d /System/Library/Frameworks 2>/dev/null` \ ; do if test -f "$i/Tk.framework/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/Tk.framework; pwd)`" break fi done fi # check in a few common install locations if test x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ `ls -d /usr/lib64 2>/dev/null` \ ; do if test -f "$i/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i; pwd)`" break fi done fi # check in a few other private locations if test x"${ac_cv_c_tkconfig}" = x ; then for i in \ ${srcdir}/../tk \ `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do if test -f "$i/unix/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/unix; pwd)`" break fi done fi ]) if test x"${ac_cv_c_tkconfig}" = x ; then TK_BIN_DIR="# no Tk configs found" AC_MSG_ERROR([Can't find Tk configuration definitions. Use --with-tk to specify a directory containing tkConfig.sh]) else no_tk= TK_BIN_DIR="${ac_cv_c_tkconfig}" AC_MSG_RESULT([found ${TK_BIN_DIR}/tkConfig.sh]) fi fi ]) #------------------------------------------------------------------------ # SC_LOAD_TCLCONFIG -- # # Load the tclConfig.sh file # # Arguments: # # Requires the following vars to be set: # TCL_BIN_DIR # # Results: # # Subst the following vars: # TCL_BIN_DIR # TCL_SRC_DIR # TCL_LIB_FILE # #------------------------------------------------------------------------ AC_DEFUN([SC_LOAD_TCLCONFIG], [ AC_MSG_CHECKING([for existence of ${TCL_BIN_DIR}/tclConfig.sh]) if test -f "${TCL_BIN_DIR}/tclConfig.sh" ; then AC_MSG_RESULT([loading]) . "${TCL_BIN_DIR}/tclConfig.sh" else AC_MSG_RESULT([could not find ${TCL_BIN_DIR}/tclConfig.sh]) fi # eval is required to do the TCL_DBGX substitution eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\"" eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\"" # If the TCL_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable TCL_LIB_SPEC will be set to the value # of TCL_BUILD_LIB_SPEC. An extension should make use of TCL_LIB_SPEC # instead of TCL_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. if test -f "${TCL_BIN_DIR}/Makefile" ; then TCL_LIB_SPEC="${TCL_BUILD_LIB_SPEC}" TCL_STUB_LIB_SPEC="${TCL_BUILD_STUB_LIB_SPEC}" TCL_STUB_LIB_PATH="${TCL_BUILD_STUB_LIB_PATH}" elif test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use the libraries # from the framework at the given location so that linking works # against Tcl.framework installed in an arbitrary location. case ${TCL_DEFS} in *TCL_FRAMEWORK*) if test -f "${TCL_BIN_DIR}/${TCL_LIB_FILE}"; then for i in "`cd "${TCL_BIN_DIR}"; pwd`" \ "`cd "${TCL_BIN_DIR}"/../..; pwd`"; do if test "`basename "$i"`" = "${TCL_LIB_FILE}.framework"; then TCL_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TCL_LIB_FILE}" break fi done fi if test -f "${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}"; then TCL_STUB_LIB_SPEC="-L`echo "${TCL_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TCL_STUB_LIB_FLAG}" TCL_STUB_LIB_PATH="${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}" fi ;; esac fi # eval is required to do the TCL_DBGX substitution eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\"" eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\"" eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\"" eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\"" AC_SUBST(TCL_VERSION) AC_SUBST(TCL_PATCH_LEVEL) AC_SUBST(TCL_BIN_DIR) AC_SUBST(TCL_SRC_DIR) AC_SUBST(TCL_LIB_FILE) AC_SUBST(TCL_LIB_FLAG) AC_SUBST(TCL_LIB_SPEC) AC_SUBST(TCL_STUB_LIB_FILE) AC_SUBST(TCL_STUB_LIB_FLAG) AC_SUBST(TCL_STUB_LIB_SPEC) ]) #------------------------------------------------------------------------ # SC_LOAD_TKCONFIG -- # # Load the tkConfig.sh file # # Arguments: # # Requires the following vars to be set: # TK_BIN_DIR # # Results: # # Sets the following vars that should be in tkConfig.sh: # TK_BIN_DIR #------------------------------------------------------------------------ AC_DEFUN([SC_LOAD_TKCONFIG], [ AC_MSG_CHECKING([for existence of ${TK_BIN_DIR}/tkConfig.sh]) if test -f "${TK_BIN_DIR}/tkConfig.sh" ; then AC_MSG_RESULT([loading]) . "${TK_BIN_DIR}/tkConfig.sh" else AC_MSG_RESULT([could not find ${TK_BIN_DIR}/tkConfig.sh]) fi # eval is required to do the TK_DBGX substitution eval "TK_LIB_FILE=\"${TK_LIB_FILE}\"" eval "TK_STUB_LIB_FILE=\"${TK_STUB_LIB_FILE}\"" # If the TK_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable TK_LIB_SPEC will be set to the value # of TK_BUILD_LIB_SPEC. An extension should make use of TK_LIB_SPEC # instead of TK_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. if test -f "${TK_BIN_DIR}/Makefile" ; then TK_LIB_SPEC="${TK_BUILD_LIB_SPEC}" TK_STUB_LIB_SPEC="${TK_BUILD_STUB_LIB_SPEC}" TK_STUB_LIB_PATH="${TK_BUILD_STUB_LIB_PATH}" elif test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use the libraries # from the framework at the given location so that linking works # against Tk.framework installed in an arbitrary location. case ${TK_DEFS} in *TK_FRAMEWORK*) if test -f "${TK_BIN_DIR}/${TK_LIB_FILE}"; then for i in "`cd "${TK_BIN_DIR}"; pwd`" \ "`cd "${TK_BIN_DIR}"/../..; pwd`"; do if test "`basename "$i"`" = "${TK_LIB_FILE}.framework"; then TK_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TK_LIB_FILE}" break fi done fi if test -f "${TK_BIN_DIR}/${TK_STUB_LIB_FILE}"; then TK_STUB_LIB_SPEC="-L` echo "${TK_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TK_STUB_LIB_FLAG}" TK_STUB_LIB_PATH="${TK_BIN_DIR}/${TK_STUB_LIB_FILE}" fi ;; esac fi # eval is required to do the TK_DBGX substitution eval "TK_LIB_FLAG=\"${TK_LIB_FLAG}\"" eval "TK_LIB_SPEC=\"${TK_LIB_SPEC}\"" eval "TK_STUB_LIB_FLAG=\"${TK_STUB_LIB_FLAG}\"" eval "TK_STUB_LIB_SPEC=\"${TK_STUB_LIB_SPEC}\"" AC_SUBST(TK_VERSION) AC_SUBST(TK_BIN_DIR) AC_SUBST(TK_SRC_DIR) AC_SUBST(TK_LIB_FILE) AC_SUBST(TK_LIB_FLAG) AC_SUBST(TK_LIB_SPEC) AC_SUBST(TK_STUB_LIB_FILE) AC_SUBST(TK_STUB_LIB_FLAG) AC_SUBST(TK_STUB_LIB_SPEC) ]) #------------------------------------------------------------------------ # SC_PROG_TCLSH # Locate a tclsh shell installed on the system path. This macro # will only find a Tcl shell that already exists on the system. # It will not find a Tcl shell in the Tcl build directory or # a Tcl shell that has been installed from the Tcl build directory. # If a Tcl shell can't be located on the PATH, then TCLSH_PROG will # be set to "". Extensions should take care not to create Makefile # rules that are run by default and depend on TCLSH_PROG. An # extension can't assume that an executable Tcl shell exists at # build time. # # Arguments # none # # Results # Subst's the following values: # TCLSH_PROG #------------------------------------------------------------------------ AC_DEFUN([SC_PROG_TCLSH], [ AC_MSG_CHECKING([for tclsh]) AC_CACHE_VAL(ac_cv_path_tclsh, [ search_path=`echo ${PATH} | sed -e 's/:/ /g'` for dir in $search_path ; do for j in `ls -r $dir/tclsh[[8-9]]* 2> /dev/null` \ `ls -r $dir/tclsh* 2> /dev/null` ; do if test x"$ac_cv_path_tclsh" = x ; then if test -f "$j" ; then ac_cv_path_tclsh=$j break fi fi done done ]) if test -f "$ac_cv_path_tclsh" ; then TCLSH_PROG="$ac_cv_path_tclsh" AC_MSG_RESULT([$TCLSH_PROG]) else # It is not an error if an installed version of Tcl can't be located. TCLSH_PROG="" AC_MSG_RESULT([No tclsh found on PATH]) fi AC_SUBST(TCLSH_PROG) ]) #------------------------------------------------------------------------ # SC_BUILD_TCLSH # Determine the fully qualified path name of the tclsh executable # in the Tcl build directory. This macro will correctly determine # the name of the tclsh executable even if tclsh has not yet # been built in the build directory. The build tclsh must be used # when running tests from an extension build directory. It is not # correct to use the TCLSH_PROG in cases like this. # # Arguments # none # # Results # Subst's the following values: # BUILD_TCLSH #------------------------------------------------------------------------ AC_DEFUN([SC_BUILD_TCLSH], [ AC_MSG_CHECKING([for tclsh in Tcl build directory]) BUILD_TCLSH="${TCL_BIN_DIR}"/tclsh AC_MSG_RESULT([$BUILD_TCLSH]) AC_SUBST(BUILD_TCLSH) ]) #------------------------------------------------------------------------ # SC_ENABLE_SHARED -- # # Allows the building of shared libraries # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --enable-shared=yes|no # # Defines the following vars: # STATIC_BUILD Used for building import/export libraries # on Windows. # # Sets the following vars: # SHARED_BUILD Value of 1 or 0 #------------------------------------------------------------------------ AC_DEFUN([SC_ENABLE_SHARED], [ AC_MSG_CHECKING([how to build libraries]) AC_ARG_ENABLE(shared, [ --enable-shared build and link with shared libraries (default: on)], [tcl_ok=$enableval], [tcl_ok=yes]) if test "${enable_shared+set}" = set; then enableval="$enable_shared" tcl_ok=$enableval else tcl_ok=yes fi if test "$tcl_ok" = "yes" ; then AC_MSG_RESULT([shared]) SHARED_BUILD=1 else AC_MSG_RESULT([static]) SHARED_BUILD=0 AC_DEFINE(STATIC_BUILD, 1, [Is this a static build?]) fi ]) #------------------------------------------------------------------------ # SC_ENABLE_FRAMEWORK -- # # Allows the building of shared libraries into frameworks # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --enable-framework=yes|no # # Sets the following vars: # FRAMEWORK_BUILD Value of 1 or 0 #------------------------------------------------------------------------ AC_DEFUN([SC_ENABLE_FRAMEWORK], [ if test "`uname -s`" = "Darwin" ; then AC_MSG_CHECKING([how to package libraries]) AC_ARG_ENABLE(framework, [ --enable-framework package shared libraries in MacOSX frameworks (default: off)], [enable_framework=$enableval], [enable_framework=no]) if test $enable_framework = yes; then if test $SHARED_BUILD = 0; then AC_MSG_WARN([Frameworks can only be built if --enable-shared is yes]) enable_framework=no fi if test $tcl_corefoundation = no; then AC_MSG_WARN([Frameworks can only be used when CoreFoundation is available]) enable_framework=no fi fi if test $enable_framework = yes; then AC_MSG_RESULT([framework]) FRAMEWORK_BUILD=1 else if test $SHARED_BUILD = 1; then AC_MSG_RESULT([shared library]) else AC_MSG_RESULT([static library]) fi FRAMEWORK_BUILD=0 fi fi ]) #------------------------------------------------------------------------ # SC_ENABLE_THREADS -- # # Specify if thread support should be enabled. TCL_THREADS is # checked so that if you are compiling an extension against a # threaded core, your extension must be compiled threaded as well. # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --enable-threads # # Sets the following vars: # THREADS_LIBS Thread library(s) # # Defines the following vars: # TCL_THREADS # _REENTRANT # _THREAD_SAFE # #------------------------------------------------------------------------ AC_DEFUN([SC_ENABLE_THREADS], [ AC_ARG_ENABLE(threads, [ --enable-threads build with threads (default: off)], [tcl_ok=$enableval], [tcl_ok=no]) if test "${TCL_THREADS}" = 1; then tcl_threaded_core=1; fi if test "$tcl_ok" = "yes" -o "${TCL_THREADS}" = 1; then TCL_THREADS=1 # USE_THREAD_ALLOC tells us to try the special thread-based # allocator that significantly reduces lock contention AC_DEFINE(USE_THREAD_ALLOC, 1, [Do we want to use the threaded memory allocator?]) AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) if test "`uname -s`" = "SunOS" ; then AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, [Do we really want to follow the standard? Yes we do!]) fi AC_DEFINE(_THREAD_SAFE, 1, [Do we want the thread-safe OS API?]) AC_CHECK_LIB(pthread,pthread_mutex_init,tcl_ok=yes,tcl_ok=no) if test "$tcl_ok" = "no"; then # Check a little harder for __pthread_mutex_init in the same # library, as some systems hide it there until pthread.h is # defined. We could alternatively do an AC_TRY_COMPILE with # pthread.h, but that will work with libpthread really doesn't # exist, like AIX 4.2. [Bug: 4359] AC_CHECK_LIB(pthread, __pthread_mutex_init, tcl_ok=yes, tcl_ok=no) fi if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -lpthread" else AC_CHECK_LIB(pthreads, pthread_mutex_init, tcl_ok=yes, tcl_ok=no) if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -lpthreads" else AC_CHECK_LIB(c, pthread_mutex_init, tcl_ok=yes, tcl_ok=no) if test "$tcl_ok" = "no"; then AC_CHECK_LIB(c_r, pthread_mutex_init, tcl_ok=yes, tcl_ok=no) if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -pthread" else TCL_THREADS=0 AC_MSG_WARN([Don't know how to find pthread lib on your system - you must disable thread support or edit the LIBS in the Makefile...]) fi fi fi fi # Does the pthread-implementation provide # 'pthread_attr_setstacksize' ? ac_saved_libs=$LIBS LIBS="$LIBS $THREADS_LIBS" AC_CHECK_FUNCS(pthread_attr_setstacksize) AC_CHECK_FUNCS(pthread_atfork) LIBS=$ac_saved_libs else TCL_THREADS=0 fi # Do checking message here to not mess up interleaved configure output AC_MSG_CHECKING([for building with threads]) if test "${TCL_THREADS}" = 1; then AC_DEFINE(TCL_THREADS, 1, [Are we building with threads enabled?]) if test "${tcl_threaded_core}" = 1; then AC_MSG_RESULT([yes (threaded core)]) else AC_MSG_RESULT([yes]) fi else AC_MSG_RESULT([no (default)]) fi AC_SUBST(TCL_THREADS) ]) #------------------------------------------------------------------------ # SC_ENABLE_SYMBOLS -- # # Specify if debugging symbols should be used. # Memory (TCL_MEM_DEBUG) and compile (TCL_COMPILE_DEBUG) debugging # can also be enabled. # # Arguments: # none # # Requires the following vars to be set in the Makefile: # CFLAGS_DEBUG # CFLAGS_OPTIMIZE # LDFLAGS_DEBUG # LDFLAGS_OPTIMIZE # # Results: # # Adds the following arguments to configure: # --enable-symbols # # Defines the following vars: # CFLAGS_DEFAULT Sets to $(CFLAGS_DEBUG) if true # Sets to $(CFLAGS_OPTIMIZE) if false # LDFLAGS_DEFAULT Sets to $(LDFLAGS_DEBUG) if true # Sets to $(LDFLAGS_OPTIMIZE) if false # DBGX Debug library extension # #------------------------------------------------------------------------ AC_DEFUN([SC_ENABLE_SYMBOLS], [ AC_MSG_CHECKING([for build with symbols]) AC_ARG_ENABLE(symbols, [ --enable-symbols build with debugging symbols (default: off)], [tcl_ok=$enableval], [tcl_ok=no]) # FIXME: Currently, LDFLAGS_DEFAULT is not used, it should work like CFLAGS_DEFAULT. if test "$tcl_ok" = "no"; then CFLAGS_DEFAULT='$(CFLAGS_OPTIMIZE)' LDFLAGS_DEFAULT='$(LDFLAGS_OPTIMIZE)' DBGX="" AC_DEFINE(NDEBUG, 1, [Is no debugging enabled?]) AC_MSG_RESULT([no]) else CFLAGS_DEFAULT='$(CFLAGS_DEBUG)' LDFLAGS_DEFAULT='$(LDFLAGS_DEBUG)' DBGX=g if test "$tcl_ok" = "yes"; then AC_MSG_RESULT([yes (standard debugging)]) fi fi AC_SUBST(CFLAGS_DEFAULT) AC_SUBST(LDFLAGS_DEFAULT) if test "$tcl_ok" = "mem" -o "$tcl_ok" = "all"; then AC_DEFINE(TCL_MEM_DEBUG, 1, [Is memory debugging enabled?]) fi if test "$tcl_ok" = "compile" -o "$tcl_ok" = "all"; then AC_DEFINE(TCL_COMPILE_DEBUG, 1, [Is bytecode debugging enabled?]) AC_DEFINE(TCL_COMPILE_STATS, 1, [Are bytecode statistics enabled?]) fi if test "$tcl_ok" != "yes" -a "$tcl_ok" != "no"; then if test "$tcl_ok" = "all"; then AC_MSG_RESULT([enabled symbols mem compile debugging]) else AC_MSG_RESULT([enabled $tcl_ok debugging]) fi fi ]) #------------------------------------------------------------------------ # SC_ENABLE_LANGINFO -- # # Allows use of modern nl_langinfo check for better l10n. # This is only relevant for Unix. # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --enable-langinfo=yes|no (default is yes) # # Defines the following vars: # HAVE_LANGINFO Triggers use of nl_langinfo if defined. # #------------------------------------------------------------------------ AC_DEFUN([SC_ENABLE_LANGINFO], [ AC_ARG_ENABLE(langinfo, [ --enable-langinfo use nl_langinfo if possible to determine encoding at startup, otherwise use old heuristic (default: on)], [langinfo_ok=$enableval], [langinfo_ok=yes]) HAVE_LANGINFO=0 if test "$langinfo_ok" = "yes"; then AC_CHECK_HEADER(langinfo.h,[langinfo_ok=yes],[langinfo_ok=no]) fi AC_MSG_CHECKING([whether to use nl_langinfo]) if test "$langinfo_ok" = "yes"; then AC_CACHE_VAL(tcl_cv_langinfo_h, [ AC_TRY_COMPILE([#include ], [nl_langinfo(CODESET);], [tcl_cv_langinfo_h=yes],[tcl_cv_langinfo_h=no])]) AC_MSG_RESULT([$tcl_cv_langinfo_h]) if test $tcl_cv_langinfo_h = yes; then AC_DEFINE(HAVE_LANGINFO, 1, [Do we have nl_langinfo()?]) fi else AC_MSG_RESULT([$langinfo_ok]) fi ]) #-------------------------------------------------------------------- # SC_CONFIG_MANPAGES # # Decide whether to use symlinks for linking the manpages, # whether to compress the manpages after installation, and # whether to add a package name suffix to the installed # manpages to avoidfile name clashes. # If compression is enabled also find out what file name suffix # the given compression program is using. # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --enable-man-symlinks # --enable-man-compression=PROG # --enable-man-suffix[=STRING] # # Defines the following variable: # # MAN_FLAGS - The apropriate flags for installManPage # according to the user's selection. # #-------------------------------------------------------------------- AC_DEFUN([SC_CONFIG_MANPAGES], [ AC_MSG_CHECKING([whether to use symlinks for manpages]) AC_ARG_ENABLE(man-symlinks, [ --enable-man-symlinks use symlinks for the manpages (default: off)], test "$enableval" != "no" && MAN_FLAGS="$MAN_FLAGS --symlinks", enableval="no") AC_MSG_RESULT([$enableval]) AC_MSG_CHECKING([whether to compress the manpages]) AC_ARG_ENABLE(man-compression, [ --enable-man-compression=PROG compress the manpages with PROG (default: off)], [case $enableval in yes) AC_MSG_ERROR([missing argument to --enable-man-compression]);; no) ;; *) MAN_FLAGS="$MAN_FLAGS --compress $enableval";; esac], enableval="no") AC_MSG_RESULT([$enableval]) if test "$enableval" != "no"; then AC_MSG_CHECKING([for compressed file suffix]) touch TeST $enableval TeST Z=`ls TeST* | sed 's/^....//'` rm -f TeST* MAN_FLAGS="$MAN_FLAGS --extension $Z" AC_MSG_RESULT([$Z]) fi AC_MSG_CHECKING([whether to add a package name suffix for the manpages]) AC_ARG_ENABLE(man-suffix, [ --enable-man-suffix=STRING use STRING as a suffix to manpage file names (default: $1)], [case $enableval in yes) enableval="$1" MAN_FLAGS="$MAN_FLAGS --suffix $enableval";; no) ;; *) MAN_FLAGS="$MAN_FLAGS --suffix $enableval";; esac], enableval="no") AC_MSG_RESULT([$enableval]) AC_SUBST(MAN_FLAGS) ]) #-------------------------------------------------------------------- # SC_CONFIG_SYSTEM # # Determine what the system is (some things cannot be easily checked # on a feature-driven basis, alas). This can usually be done via the # "uname" command, but there are a few systems, like Next, where # this doesn't work. # # Arguments: # none # # Results: # Defines the following var: # # system - System/platform/version identification code. # #-------------------------------------------------------------------- AC_DEFUN([SC_CONFIG_SYSTEM], [ AC_CACHE_CHECK([system version], tcl_cv_sys_version, [ if test -f /usr/lib/NextStep/software_version; then tcl_cv_sys_version=NEXTSTEP-`awk '/3/,/3/' /usr/lib/NextStep/software_version` else tcl_cv_sys_version=`uname -s`-`uname -r` if test "$?" -ne 0 ; then AC_MSG_WARN([can't find uname command]) tcl_cv_sys_version=unknown else # Special check for weird MP-RAS system (uname returns weird # results, and the version is kept in special file). if test -r /etc/.relid -a "X`uname -n`" = "X`uname -s`" ; then tcl_cv_sys_version=MP-RAS-`awk '{print $[3]}' /etc/.relid` fi if test "`uname -s`" = "AIX" ; then tcl_cv_sys_version=AIX-`uname -v`.`uname -r` fi fi fi ]) system=$tcl_cv_sys_version ]) #-------------------------------------------------------------------- # SC_CONFIG_CFLAGS # # Try to determine the proper flags to pass to the compiler # for building shared libraries and other such nonsense. # # Arguments: # none # # Results: # # Defines and substitutes the following vars: # # DL_OBJS - Name of the object file that implements dynamic # loading for Tcl on this system. # DL_LIBS - Library file(s) to include in tclsh and other base # applications in order for the "load" command to work. # LDFLAGS - Flags to pass to the compiler when linking object # files into an executable application binary such # as tclsh. # LD_SEARCH_FLAGS-Flags to pass to ld, such as "-R /usr/local/tcl/lib", # that tell the run-time dynamic linker where to look # for shared libraries such as libtcl.so. Depends on # the variable LIB_RUNTIME_DIR in the Makefile. Could # be the same as CC_SEARCH_FLAGS if ${CC} is used to link. # CC_SEARCH_FLAGS-Flags to pass to ${CC}, such as "-Wl,-rpath,/usr/local/tcl/lib", # that tell the run-time dynamic linker where to look # for shared libraries such as libtcl.so. Depends on # the variable LIB_RUNTIME_DIR in the Makefile. # MAKE_LIB - Command to execute to build the a library; # differs when building shared or static. # MAKE_STUB_LIB - # Command to execute to build a stub library. # INSTALL_LIB - Command to execute to install a library; # differs when building shared or static. # INSTALL_STUB_LIB - # Command to execute to install a stub library. # STLIB_LD - Base command to use for combining object files # into a static library. # SHLIB_CFLAGS - Flags to pass to cc when compiling the components # of a shared library (may request position-independent # code, among other things). # SHLIB_LD - Base command to use for combining object files # into a shared library. # SHLIB_LD_LIBS - Dependent libraries for the linker to scan when # creating shared libraries. This symbol typically # goes at the end of the "ld" commands that build # shared libraries. The value of the symbol is # "${LIBS}" if all of the dependent libraries should # be specified when creating a shared library. If # dependent libraries should not be specified (as on # SunOS 4.x, where they cause the link to fail, or in # general if Tcl and Tk aren't themselves shared # libraries), then this symbol has an empty string # as its value. # SHLIB_SUFFIX - Suffix to use for the names of dynamically loadable # extensions. An empty string means we don't know how # to use shared libraries on this platform. # TCL_SHLIB_LD_EXTRAS - Additional element which are added to SHLIB_LD_LIBS # TK_SHLIB_LD_EXTRAS for the build of Tcl and Tk, but not recorded in the # tclConfig.sh, since they are only used for the build # of Tcl and Tk. # Examples: MacOS X records the library version and # compatibility version in the shared library. But # of course the Tcl version of this is only used for Tcl. # LIB_SUFFIX - Specifies everything that comes after the "libfoo" # in a static or shared library name, using the $VERSION variable # to put the version in the right place. This is used # by platforms that need non-standard library names. # Examples: ${VERSION}.so.1.1 on NetBSD, since it needs # to have a version after the .so, and ${VERSION}.a # on AIX, since a shared library needs to have # a .a extension whereas shared objects for loadable # extensions have a .so extension. Defaults to # ${VERSION}${SHLIB_SUFFIX}. # TCL_NEEDS_EXP_FILE - # 1 means that an export file is needed to link to a # shared library. # TCL_EXP_FILE - The name of the installed export / import file which # should be used to link to the Tcl shared library. # Empty if Tcl is unshared. # TCL_BUILD_EXP_FILE - # The name of the built export / import file which # should be used to link to the Tcl shared library. # Empty if Tcl is unshared. # CFLAGS_DEBUG - # Flags used when running the compiler in debug mode # CFLAGS_OPTIMIZE - # Flags used when running the compiler in optimize mode # CFLAGS - Additional CFLAGS added as necessary (usually 64-bit) # #-------------------------------------------------------------------- AC_DEFUN([SC_CONFIG_CFLAGS], [ # Step 0.a: Enable 64 bit support? AC_MSG_CHECKING([if 64bit support is requested]) AC_ARG_ENABLE(64bit,[ --enable-64bit enable 64bit support (where applicable)], [do64bit=$enableval], [do64bit=no]) AC_MSG_RESULT([$do64bit]) # Step 0.b: Enable Solaris 64 bit VIS support? AC_MSG_CHECKING([if 64bit Sparc VIS support is requested]) AC_ARG_ENABLE(64bit-vis,[ --enable-64bit-vis enable 64bit Sparc VIS support], [do64bitVIS=$enableval], [do64bitVIS=no]) AC_MSG_RESULT([$do64bitVIS]) if test "$do64bitVIS" = "yes"; then # Force 64bit on with VIS do64bit=yes fi # Step 0.d: Disable -rpath support? AC_MSG_CHECKING([if rpath support is requested]) AC_ARG_ENABLE(rpath,[ --disable-rpath disable rpath support (default: on)], [doRpath=$enableval], [doRpath=yes]) AC_MSG_RESULT([$doRpath]) # Step 1: set the variable "system" to hold the name and version number # for the system. SC_CONFIG_SYSTEM # Step 2: check for existence of -ldl library. This is needed because # Linux can use either -ldl or -ldld for dynamic loading. AC_CHECK_LIB(dl, dlopen, have_dl=yes, have_dl=no) # Require ranlib early so we can override it in special cases below. AC_REQUIRE([AC_PROG_RANLIB]) # Step 3: set configuration options based on system name and version. do64bit_ok=no # default to '{$LIBS}' and set to "" on per-platform necessary basis SHLIB_LD_LIBS='${LIBS}' LDFLAGS_ORIG="$LDFLAGS" TCL_EXPORT_FILE_SUFFIX="" UNSHARED_LIB_SUFFIX="" TCL_TRIM_DOTS='`echo ${VERSION} | tr -d .`' ECHO_VERSION='`echo ${VERSION}`' TCL_LIB_VERSIONS_OK=ok CFLAGS_DEBUG=-g CFLAGS_OPTIMIZE=-O if test "$GCC" = "yes" ; then CFLAGS_WARNING="-Wall -fno-strict-aliasing" else CFLAGS_WARNING="" fi TCL_NEEDS_EXP_FILE=0 TCL_BUILD_EXP_FILE="" TCL_EXP_FILE="" dnl FIXME: Replace AC_CHECK_PROG with AC_CHECK_TOOL once cross compiling is fixed. dnl AC_CHECK_TOOL(AR, ar) AC_CHECK_PROG(AR, ar, ar) if test "${AR}" = "" ; then AC_MSG_ERROR([Required archive tool 'ar' not found on PATH.]) fi STLIB_LD='${AR} cr' LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" PLAT_OBJS="" PLAT_SRCS="" case $system in AIX-*) if test "${TCL_THREADS}" = "1" -a "$GCC" != "yes" ; then # AIX requires the _r compiler when gcc isn't being used case "${CC}" in *_r|*_r\ *) # ok ... ;; *) # Make sure only first arg gets _r CC=`echo "$CC" | sed -e 's/^\([[^ ]]*\)/\1_r/'` ;; esac AC_MSG_RESULT([Using $CC for compiling with threads]) fi LIBS="$LIBS -lc" SHLIB_CFLAGS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" LD_LIBRARY_PATH_VAR="LIBPATH" # Check to enable 64-bit flags for compiler/linker on AIX 4+ if test "$do64bit" = "yes" -a "`uname -v`" -gt "3" ; then if test "$GCC" = "yes" ; then AC_MSG_WARN([64bit mode not supported with GCC on $system]) else do64bit_ok=yes CFLAGS="$CFLAGS -q64" LDFLAGS="$LDFLAGS -q64" RANLIB="${RANLIB} -X64" AR="${AR} -X64" SHLIB_LD_FLAGS="-b64" fi fi if test "`uname -m`" = "ia64" ; then # AIX-5 uses ELF style dynamic libraries on IA-64, but not PPC SHLIB_LD="/usr/ccs/bin/ld -G -z text" # AIX-5 has dl* in libc.so DL_LIBS="" if test "$GCC" = "yes" ; then CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' else CC_SEARCH_FLAGS='-R${LIB_RUNTIME_DIR}' fi LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' else if test "$GCC" = "yes" ; then SHLIB_LD="gcc -shared" else SHLIB_LD="/bin/ld -bhalt:4 -bM:SRE -bE:lib.exp -H512 -T512 -bnoentry" fi SHLIB_LD="${TCL_SRC_DIR}/unix/ldAix ${SHLIB_LD} ${SHLIB_LD_FLAGS}" DL_LIBS="-ldl" CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} TCL_NEEDS_EXP_FILE=1 TCL_EXPORT_FILE_SUFFIX='${VERSION}\$\{DBGX\}.exp' fi # AIX v<=4.1 has some different flags than 4.2+ if test "$system" = "AIX-4.1" -o "`uname -v`" -lt "4" ; then LIBOBJS="$LIBOBJS tclLoadAix.o" DL_LIBS="-lld" fi # On AIX <=v4 systems, libbsd.a has to be linked in to support # non-blocking file IO. This library has to be linked in after # the MATH_LIBS or it breaks the pow() function. The way to # insure proper sequencing, is to add it to the tail of MATH_LIBS. # This library also supplies gettimeofday. # # AIX does not have a timezone field in struct tm. When the AIX # bsd library is used, the timezone global and the gettimeofday # methods are to be avoided for timezone deduction instead, we # deduce the timezone by comparing the localtime result on a # known GMT value. AC_CHECK_LIB(bsd, gettimeofday, libbsd=yes, libbsd=no) if test $libbsd = yes; then MATH_LIBS="$MATH_LIBS -lbsd" AC_DEFINE(USE_DELTA_FOR_TZ, 1, [Use delta for TZ]) fi ;; BeOS*) SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -nostart' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" #----------------------------------------------------------- # Check for inet_ntoa in -lbind, for BeOS (which also needs # -lsocket, even if the network functions are in -lnet which # is always linked to, for compatibility. #----------------------------------------------------------- AC_CHECK_LIB(bind, inet_ntoa, [LIBS="$LIBS -lbind -lsocket"]) ;; BSD/OS-2.1*|BSD/OS-3*) SHLIB_CFLAGS="" SHLIB_LD="shlicc -r" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; BSD/OS-4.*) SHLIB_CFLAGS="-export-dynamic -fPIC" SHLIB_LD='${CC} -shared' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" LDFLAGS="$LDFLAGS -export-dynamic" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; CYGWIN_*|MINGW32*) SHLIB_CFLAGS="" SHLIB_LD='${CC} -shared' SHLIB_SUFFIX=".dll" DL_OBJS="tclLoadDl.o tclWinError.o" DL_LIBS="-ldl" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" TCL_SHLIB_LD_EXTRAS='-Wl,--out-implib,$[@].a' AC_CACHE_CHECK(for Cygwin version of gcc, ac_cv_cygwin, AC_TRY_COMPILE([ #ifdef __CYGWIN__ #error cygwin #endif ], [], ac_cv_cygwin=no, ac_cv_cygwin=yes) ) if test "$ac_cv_cygwin" = "no"; then AC_MSG_ERROR([${CC} is not a cygwin compiler.]) fi if test "x${TCL_THREADS}" = "x0"; then AC_MSG_ERROR([CYGWIN compile is only supported with --enable-threads]) fi if test "x${SHARED_BUILD}" = "x1" -a ! -f "../win/tcldde13.dll" -a ! -f "../win/tk84.dll"; then AC_MSG_ERROR([Please configure and make the ../win directory first.]) fi ;; dgux*) SHLIB_CFLAGS="-K PIC" SHLIB_LD='${CC} -G' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; Haiku*) LDFLAGS="$LDFLAGS -Wl,--export-dynamic" SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS}' DL_OBJS="tclLoadDl.o" DL_LIBS="-lroot" AC_CHECK_LIB(network, inet_ntoa, [LIBS="$LIBS -lnetwork"]) ;; HP-UX-*.11.*) # Use updated header definitions where possible AC_DEFINE(_XOPEN_SOURCE_EXTENDED, 1, [Do we want to use the XOPEN network library?]) AC_DEFINE(_XOPEN_SOURCE, 1, [Do we want to use the XOPEN network library?]) LIBS="$LIBS -lxnet" # Use the XOPEN network library if test "`uname -m`" = "ia64" ; then SHLIB_SUFFIX=".so" else SHLIB_SUFFIX=".sl" fi AC_CHECK_LIB(dld, shl_load, tcl_ok=yes, tcl_ok=no) if test "$tcl_ok" = yes; then SHLIB_CFLAGS="+z" SHLIB_LD="ld -b" DL_OBJS="tclLoadShl.o" DL_LIBS="-ldld" LDFLAGS="$LDFLAGS -Wl,-E" CC_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.' LD_SEARCH_FLAGS='+s +b ${LIB_RUNTIME_DIR}:.' LD_LIBRARY_PATH_VAR="SHLIB_PATH" fi if test "$GCC" = "yes" ; then SHLIB_LD='${CC} -shared' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} fi # Users may want PA-RISC 1.1/2.0 portable code - needs HP cc #CFLAGS="$CFLAGS +DAportable" # Check to enable 64-bit flags for compiler/linker if test "$do64bit" = "yes" ; then if test "$GCC" = "yes" ; then case `${CC} -dumpmachine` in hppa64*) # 64-bit gcc in use. Fix flags for GNU ld. do64bit_ok=yes SHLIB_LD='${CC} -shared' if test $doRpath = yes ; then CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ;; *) AC_MSG_WARN([64bit mode not supported with GCC on $system]) ;; esac else do64bit_ok=yes CFLAGS="$CFLAGS +DD64" LDFLAGS="$LDFLAGS +DD64" fi fi ;; HP-UX-*.08.*|HP-UX-*.09.*|HP-UX-*.10.*) SHLIB_SUFFIX=".sl" AC_CHECK_LIB(dld, shl_load, tcl_ok=yes, tcl_ok=no) if test "$tcl_ok" = yes; then SHLIB_CFLAGS="+z" SHLIB_LD="ld -b" SHLIB_LD_LIBS="" DL_OBJS="tclLoadShl.o" DL_LIBS="-ldld" LDFLAGS="$LDFLAGS -Wl,-E" CC_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.' LD_SEARCH_FLAGS='+s +b ${LIB_RUNTIME_DIR}:.' LD_LIBRARY_PATH_VAR="SHLIB_PATH" fi ;; IRIX-4.*) SHLIB_CFLAGS="-G 0" SHLIB_SUFFIX=".a" SHLIB_LD="echo tclLdAout $CC \{$SHLIB_CFLAGS\} | `pwd`/tclsh -r -G 0" DL_OBJS="tclLoadAout.o" DL_LIBS="" LDFLAGS="$LDFLAGS -Wl,-D,08000000" CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} SHARED_LIB_SUFFIX='${VERSION}\$\{DBGX\}.a' ;; IRIX-5.*) SHLIB_CFLAGS="" SHLIB_LD="ld -shared -rdata_shared" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" if test $doRpath = yes ; then CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' fi ;; IRIX-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" if test $doRpath = yes ; then CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' fi if test "$GCC" = "yes" ; then CFLAGS="$CFLAGS -mabi=n32" LDFLAGS="$LDFLAGS -mabi=n32" else case $system in IRIX-6.3) # Use to build 6.2 compatible binaries on 6.3. CFLAGS="$CFLAGS -n32 -D_OLD_TERMIOS" ;; *) CFLAGS="$CFLAGS -n32" ;; esac LDFLAGS="$LDFLAGS -n32" fi ;; IRIX64-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" if test $doRpath = yes ; then CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' fi # Check to enable 64-bit flags for compiler/linker if test "$do64bit" = "yes" ; then if test "$GCC" = "yes" ; then AC_MSG_WARN([64bit mode not supported by gcc]) else do64bit_ok=yes SHLIB_LD="ld -64 -shared -rdata_shared" CFLAGS="$CFLAGS -64" LDFLAGS="$LDFLAGS -64" fi fi ;; Linux*|GNU*|NetBSD-Debian) SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" CFLAGS_OPTIMIZE="-O2" # egcs-2.91.66 on Redhat Linux 6.0 generates lots of warnings # when you inline the string and math operations. Turn this off to # get rid of the warnings. #CFLAGS_OPTIMIZE="${CFLAGS_OPTIMIZE} -D__NO_STRING_INLINES -D__NO_MATH_INLINES" if test "$have_dl" = yes; then SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS}' DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" LDFLAGS="$LDFLAGS -Wl,--export-dynamic" if test $doRpath = yes ; then CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} else AC_CHECK_HEADER(dld.h, [ SHLIB_LD="ld -shared" DL_OBJS="tclLoadDld.o" DL_LIBS="-ldld" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS=""]) fi if test "`uname -m`" = "alpha" ; then CFLAGS="$CFLAGS -mieee" fi if test $do64bit = yes; then AC_CACHE_CHECK([if compiler accepts -m64 flag], tcl_cv_cc_m64, [ hold_cflags=$CFLAGS CFLAGS="$CFLAGS -m64" AC_TRY_LINK(,, tcl_cv_cc_m64=yes, tcl_cv_cc_m64=no) CFLAGS=$hold_cflags]) if test $tcl_cv_cc_m64 = yes; then CFLAGS="$CFLAGS -m64" do64bit_ok=yes fi fi # The combo of gcc + glibc has a bug related # to inlining of functions like strtod(). The # -fno-builtin flag should address this problem # but it does not work. The -fno-inline flag # is kind of overkill but it works. # Disable inlining only when one of the # files in compat/*.c is being linked in. if test x"${LIBOBJS}" != x ; then CFLAGS="$CFLAGS -fno-inline" fi AC_DEFINE(PEEK_XCLOSEIM, 1, [XIM peeking works under XFree86]) ;; Lynx*) SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" CFLAGS_OPTIMIZE=-02 SHLIB_LD='${CC} -shared' DL_OBJS="tclLoadDl.o" DL_LIBS="-mshared -ldl" LD_FLAGS="-Wl,--export-dynamic" if test $doRpath = yes ; then CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi ;; MP-RAS-02*) SHLIB_CFLAGS="-K PIC" SHLIB_LD='${CC} -G' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; MP-RAS-*) SHLIB_CFLAGS="-K PIC" SHLIB_LD='${CC} -G' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" LDFLAGS="$LDFLAGS -Wl,-Bexport" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; OpenBSD-*) arch=`arch -s` case "$arch" in m88k|vax) SHLIB_CFLAGS="" SHLIB_LD="echo tclLdAout $CC \{$SHLIB_CFLAGS\} | `pwd`/tclsh -r" SHLIB_SUFFIX=".a" DL_OBJS="tclLoadAout.o" DL_LIBS="" LDFLAGS="" CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.a' ;; *) # OpenBSD/SPARC[64] needs -fPIC, -fpic will not do. case `machine` in sparc|sparc64) SHLIB_CFLAGS="-fPIC";; *) SHLIB_CFLAGS="-fpic";; esac SHLIB_LD="${CC} -shared ${SHLIB_CFLAGS}" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" if test $doRpath = yes ; then CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.so.1.0' AC_CACHE_CHECK([for ELF], tcl_cv_ld_elf, [ AC_EGREP_CPP(yes, [ #ifdef __ELF__ yes #endif ], tcl_cv_ld_elf=yes, tcl_cv_ld_elf=no)]) if test $tcl_cv_ld_elf = yes; then LDFLAGS=-Wl,-export-dynamic else LDFLAGS="" fi ;; esac # OpenBSD doesn't do version numbers with dots. UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.a' TCL_LIB_VERSIONS_OK=nodots ;; NetBSD-*) # NetBSD has ELF and can use 'cc -shared' to build shared libs SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" LDFLAGS="$LDFLAGS -export-dynamic" if test $doRpath = yes ; then CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} if test "${TCL_THREADS}" = "1" ; then # The -pthread needs to go in the CFLAGS, not LIBS LIBS=`echo $LIBS | sed s/-pthread//` CFLAGS="$CFLAGS -pthread" LDFLAGS="$LDFLAGS -pthread" fi case $system in FreeBSD-3.*) # FreeBSD-3 doesn't handle version numbers with dots. UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so' TCL_LIB_VERSIONS_OK=nodots ;; esac ;; FreeBSD-*) # This configuration from FreeBSD Ports. SHLIB_CFLAGS="-fPIC" SHLIB_LD="${CC} -shared" TCL_SHLIB_LD_EXTRAS="-Wl,-soname,\$[@]" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" LDFLAGS="" if test $doRpath = yes ; then CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi if test "${TCL_THREADS}" = "1" ; then # The -pthread needs to go in the LDFLAGS, not LIBS LIBS=`echo $LIBS | sed s/-pthread//` CFLAGS="$CFLAGS $PTHREAD_CFLAGS" LDFLAGS="$LDFLAGS $PTHREAD_LIBS" fi # Version numbers are dot-stripped by system policy. TCL_TRIM_DOTS=`echo ${VERSION} | tr -d .` UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.so.1' TCL_LIB_VERSIONS_OK=nodots ;; Darwin-*) CFLAGS_OPTIMIZE="-Os" SHLIB_CFLAGS="-fno-common" # To avoid discrepancies between what headers configure sees during # preprocessing tests and compiling tests, move any -isysroot and # -mmacosx-version-min flags from CFLAGS to CPPFLAGS: CPPFLAGS="${CPPFLAGS} `echo " ${CFLAGS}" | \ awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ if ([$]i~/^(isysroot|mmacosx-version-min)/) print "-"[$]i}'`" CFLAGS="`echo " ${CFLAGS}" | \ awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ if (!([$]i~/^(isysroot|mmacosx-version-min)/)) print "-"[$]i}'`" if test $do64bit = yes; then case `arch` in ppc) AC_CACHE_CHECK([if compiler accepts -arch ppc64 flag], tcl_cv_cc_arch_ppc64, [ hold_cflags=$CFLAGS CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" AC_TRY_LINK(,, tcl_cv_cc_arch_ppc64=yes, tcl_cv_cc_arch_ppc64=no) CFLAGS=$hold_cflags]) if test $tcl_cv_cc_arch_ppc64 = yes; then CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" do64bit_ok=yes fi;; i386) AC_CACHE_CHECK([if compiler accepts -arch x86_64 flag], tcl_cv_cc_arch_x86_64, [ hold_cflags=$CFLAGS CFLAGS="$CFLAGS -arch x86_64" AC_TRY_LINK(,, tcl_cv_cc_arch_x86_64=yes, tcl_cv_cc_arch_x86_64=no) CFLAGS=$hold_cflags]) if test $tcl_cv_cc_arch_x86_64 = yes; then CFLAGS="$CFLAGS -arch x86_64" do64bit_ok=yes fi;; *) AC_MSG_WARN([Don't know how enable 64-bit on architecture `arch`]);; esac else # Check for combined 32-bit and 64-bit fat build echo "$CFLAGS " | grep -E -q -- '-arch (ppc64|x86_64) ' && \ echo "$CFLAGS " | grep -E -q -- '-arch (ppc|i386) ' && \ fat_32_64=yes fi SHLIB_LD='${CC} -dynamiclib ${CFLAGS} ${LDFLAGS}' AC_CACHE_CHECK([if ld accepts -single_module flag], tcl_cv_ld_single_module, [ hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -dynamiclib -Wl,-single_module" AC_TRY_LINK(, [int i;], tcl_cv_ld_single_module=yes, tcl_cv_ld_single_module=no) LDFLAGS=$hold_ldflags]) if test $tcl_cv_ld_single_module = yes; then SHLIB_LD="${SHLIB_LD} -Wl,-single_module" fi SHLIB_SUFFIX=".dylib" DL_OBJS="tclLoadDyld.o" DL_LIBS="" # Don't use -prebind when building for Mac OS X 10.4 or later only: test "`echo "${MACOSX_DEPLOYMENT_TARGET}" | awk -F '10\\.' '{print int([$]2)}'`" -lt 4 -a \ "`echo "${CPPFLAGS}" | awk -F '-mmacosx-version-min=10\\.' '{print int([$]2)}'`" -lt 4 && \ LDFLAGS="$LDFLAGS -prebind" LDFLAGS="$LDFLAGS -headerpad_max_install_names" AC_CACHE_CHECK([if ld accepts -search_paths_first flag], tcl_cv_ld_search_paths_first, [ hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -Wl,-search_paths_first" AC_TRY_LINK(, [int i;], tcl_cv_ld_search_paths_first=yes, tcl_cv_ld_search_paths_first=no) LDFLAGS=$hold_ldflags]) if test $tcl_cv_ld_search_paths_first = yes; then LDFLAGS="$LDFLAGS -Wl,-search_paths_first" fi CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" LD_LIBRARY_PATH_VAR="DYLD_LIBRARY_PATH" PLAT_OBJS=\$\(MAC\_OSX_OBJS\) PLAT_SRCS=\$\(MAC\_OSX_SRCS\) AC_MSG_CHECKING([whether to use CoreFoundation]) AC_ARG_ENABLE(corefoundation, [ --enable-corefoundation use CoreFoundation API [--enable-corefoundation]], [tcl_corefoundation=$enableval], [tcl_corefoundation=yes]) AC_MSG_RESULT([$tcl_corefoundation]) if test $tcl_corefoundation = yes; then AC_CACHE_CHECK([for CoreFoundation.framework], tcl_cv_lib_corefoundation, [ hold_libs=$LIBS if test "$fat_32_64" = yes; then for v in CFLAGS CPPFLAGS LDFLAGS; do # On Tiger there is no 64-bit CF, so remove 64-bit archs # from CFLAGS et al. while testing for presence of CF. # 64-bit CF is disabled in tclUnixPort.h if necessary. eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc64 / /g" -e "s/-arch x86_64 / /g"`"' done; fi LIBS="$LIBS -framework CoreFoundation" AC_TRY_LINK([#include ], [CFBundleRef b = CFBundleGetMainBundle();], tcl_cv_lib_corefoundation=yes, tcl_cv_lib_corefoundation=no) if test "$fat_32_64" = yes; then for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="$hold_'$v'"' done; fi; LIBS=$hold_libs]) if test $tcl_cv_lib_corefoundation = yes; then LIBS="$LIBS -framework CoreFoundation" AC_DEFINE(HAVE_COREFOUNDATION, 1, [Do we have access to Darwin CoreFoundation.framework?]) else tcl_corefoundation=no fi if test "$fat_32_64" = yes -a $tcl_corefoundation = yes; then AC_CACHE_CHECK([for 64-bit CoreFoundation], tcl_cv_lib_corefoundation_64, [ for v in CFLAGS CPPFLAGS LDFLAGS; do eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' done AC_TRY_LINK([#include ], [CFBundleRef b = CFBundleGetMainBundle();], tcl_cv_lib_corefoundation_64=yes, tcl_cv_lib_corefoundation_64=no) for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="$hold_'$v'"' done]) if test $tcl_cv_lib_corefoundation_64 = no; then AC_DEFINE(NO_COREFOUNDATION_64, 1, [Is Darwin CoreFoundation unavailable for 64-bit?]) fi fi fi AC_DEFINE(MAC_OSX_TCL) ;; NEXTSTEP-*) SHLIB_CFLAGS="" SHLIB_LD='${CC} -nostdlib -r' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadNext.o" DL_LIBS="" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; OS/390-*) SHLIB_LD_LIBS="" CFLAGS_OPTIMIZE="" # Optimizer is buggy AC_DEFINE(_OE_SOCKETS, 1, # needed in sys/socket.h [Should OS/390 do the right thing with sockets?]) ;; OSF1-1.0|OSF1-1.1|OSF1-1.2) # OSF/1 1.[012] from OSF, and derivatives, including Paragon OSF/1 SHLIB_CFLAGS="" # Hack: make package name same as library name SHLIB_LD='ld -R -export $@:' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadOSF.o" DL_LIBS="" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; OSF1-1.*) # OSF/1 1.3 from OSF using ELF, and derivatives, including AD2 SHLIB_CFLAGS="-fPIC" if test "$SHARED_BUILD" = "1" ; then SHLIB_LD="ld -shared" else SHLIB_LD="ld -non_shared" fi SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; OSF1-V*) # Digital OSF/1 SHLIB_CFLAGS="" if test "$SHARED_BUILD" = "1" ; then SHLIB_LD='ld -shared -expect_unresolved "*"' else SHLIB_LD='ld -non_shared -expect_unresolved "*"' fi SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" if test $doRpath = yes ; then CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' fi if test "$GCC" = "yes" ; then CFLAGS="$CFLAGS -mieee" else CFLAGS="$CFLAGS -DHAVE_TZSET -std1 -ieee" fi # see pthread_intro(3) for pthread support on osf1, k.furukawa if test "${TCL_THREADS}" = "1" ; then CFLAGS="$CFLAGS -DHAVE_PTHREAD_ATTR_SETSTACKSIZE" CFLAGS="$CFLAGS -DTCL_THREAD_STACK_MIN=PTHREAD_STACK_MIN*64" LIBS=`echo $LIBS | sed s/-lpthreads//` if test "$GCC" = "yes" ; then LIBS="$LIBS -lpthread -lmach -lexc" else CFLAGS="$CFLAGS -pthread" LDFLAGS="$LDFLAGS -pthread" fi fi ;; QNX-6*) # QNX RTP # This may work for all QNX, but it was only reported for v6. SHLIB_CFLAGS="-fPIC" SHLIB_LD="ld -Bshareable -x" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" # dlopen is in -lc on QNX DL_LIBS="" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; RISCos-*) SHLIB_CFLAGS="-G 0" SHLIB_LD="echo tclLdAout $CC \{$SHLIB_CFLAGS\} | `pwd`/tclsh -r -G 0" SHLIB_SUFFIX=".a" DL_OBJS="tclLoadAout.o" DL_LIBS="" LDFLAGS="$LDFLAGS -Wl,-D,08000000" CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ;; SCO_SV-3.2*) # Note, dlopen is available only on SCO 3.2.5 and greater. However, # this test works, since "uname -s" was non-standard in 3.2.4 and # below. if test "$GCC" = "yes" ; then SHLIB_CFLAGS="-fPIC -melf" LDFLAGS="$LDFLAGS -melf -Wl,-Bexport" else SHLIB_CFLAGS="-Kpic -belf" LDFLAGS="$LDFLAGS -belf -Wl,-Bexport" fi SHLIB_LD="ld -G" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SINIX*5.4*) SHLIB_CFLAGS="-K PIC" SHLIB_LD='${CC} -G' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SunOS-4*) SHLIB_CFLAGS="-PIC" SHLIB_LD="ld" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} # SunOS can't handle version numbers with dots in them in library # specs, like -ltcl7.5, so use -ltcl75 instead. Also, it # requires an extra version number at the end of .so file names. # So, the library has to have a name like libtcl75.so.1.0 SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.so.1.0' UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.a' TCL_LIB_VERSIONS_OK=nodots ;; SunOS-5.[[0-6]]) # Careful to not let 5.10+ fall into this case # Note: If _REENTRANT isn't defined, then Solaris # won't define thread-safe library routines. AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, [Do we really want to follow the standard? Yes we do!]) SHLIB_CFLAGS="-KPIC" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" if test "$GCC" = "yes" ; then SHLIB_LD='${CC} -shared' CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} else SHLIB_LD="/usr/ccs/bin/ld -G -z text" CC_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} fi ;; SunOS-5*) # Note: If _REENTRANT isn't defined, then Solaris # won't define thread-safe library routines. AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, [Do we really want to follow the standard? Yes we do!]) SHLIB_CFLAGS="-KPIC" # Check to enable 64-bit flags for compiler/linker if test "$do64bit" = "yes" ; then arch=`isainfo` if test "$arch" = "sparcv9 sparc" ; then if test "$GCC" = "yes" ; then if test "`gcc -dumpversion | awk -F. '{print [$]1}'`" -lt "3" ; then AC_MSG_WARN([64bit mode not supported with GCC < 3.2 on $system]) else do64bit_ok=yes CFLAGS="$CFLAGS -m64 -mcpu=v9" LDFLAGS="$LDFLAGS -m64 -mcpu=v9" SHLIB_CFLAGS="-fPIC" fi else do64bit_ok=yes if test "$do64bitVIS" = "yes" ; then CFLAGS="$CFLAGS -xarch=v9a" LDFLAGS="$LDFLAGS -xarch=v9a" else CFLAGS="$CFLAGS -xarch=v9" LDFLAGS="$LDFLAGS -xarch=v9" fi # Solaris 64 uses this as well #LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH_64" fi elif test "$arch" = "amd64 i386" ; then if test "$GCC" = "yes" ; then case $system in SunOS-5.1[[1-9]]*|SunOS-5.[[2-9]][[0-9]]*) do64bit_ok=yes CFLAGS="$CFLAGS -m64" LDFLAGS="$LDFLAGS -m64";; *) AC_MSG_WARN([64bit mode not supported with GCC on $system]);; esac else do64bit_ok=yes case $system in SunOS-5.1[[1-9]]*|SunOS-5.[[2-9]][[0-9]]*) CFLAGS="$CFLAGS -m64" LDFLAGS="$LDFLAGS -m64";; *) CFLAGS="$CFLAGS -xarch=amd64" LDFLAGS="$LDFLAGS -xarch=amd64";; esac fi else AC_MSG_WARN([64bit mode not supported for $arch]) fi fi SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" if test "$GCC" = "yes" ; then SHLIB_LD="$CC -shared" CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} if test "$do64bit_ok" = "yes" ; then if test "$arch" = "sparcv9 sparc" ; then # We need to specify -static-libgcc or we need to # add the path to the sparv9 libgcc. SHLIB_LD="$SHLIB_LD -m64 -mcpu=v9 -static-libgcc" # for finding sparcv9 libgcc, get the regular libgcc # path, remove so name and append 'sparcv9' #v9gcclibdir="`gcc -print-file-name=libgcc_s.so` | ..." #CC_SEARCH_FLAGS="${CC_SEARCH_FLAGS},-R,$v9gcclibdir" elif test "$arch" = "amd64 i386" ; then SHLIB_LD="$SHLIB_LD -m64 -static-libgcc" fi fi else case $system in SunOS-5.[[1-9]][[0-9]]*) SHLIB_LD='${CC} -G -z text ${LDFLAGS}';; *) SHLIB_LD="/usr/ccs/bin/ld -G -z text";; esac CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' fi ;; ULTRIX-4.*) SHLIB_CFLAGS="-G 0" SHLIB_SUFFIX=".a" SHLIB_LD="echo tclLdAout $CC \{$SHLIB_CFLAGS\} | `pwd`/tclsh -r -G 0" DL_OBJS="tclLoadAout.o" DL_LIBS="" LDFLAGS="$LDFLAGS -Wl,-D,08000000" CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} if test "$GCC" != "yes" ; then CFLAGS="$CFLAGS -DHAVE_TZSET -std1" fi ;; UNIX_SV* | UnixWare-5*) SHLIB_CFLAGS="-KPIC" SHLIB_LD='${CC} -G' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" # Some UNIX_SV* systems (unixware 1.1.2 for example) have linkers # that don't grok the -Bexport option. Test that it does. AC_CACHE_CHECK([for ld accepts -Bexport flag], tcl_cv_ld_Bexport, [ hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -Wl,-Bexport" AC_TRY_LINK(, [int i;], tcl_cv_ld_Bexport=yes, tcl_cv_ld_Bexport=no) LDFLAGS=$hold_ldflags]) if test $tcl_cv_ld_Bexport = yes; then LDFLAGS="$LDFLAGS -Wl,-Bexport" fi CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; esac if test "$do64bit" = "yes" -a "$do64bit_ok" = "no" ; then AC_MSG_WARN([64bit support being disabled -- don't know magic for this platform]) fi dnl # Add any CPPFLAGS set in the environment to our CFLAGS, but delay doing so dnl # until the end of configure, as configure's compile and link tests use dnl # both CPPFLAGS and CFLAGS (unlike our compile and link) but configure's dnl # preprocessing tests use only CPPFLAGS. SC_CONFIG_COMMANDS_PRE([CFLAGS="${CFLAGS} ${CPPFLAGS}"; CPPFLAGS=""]) # Step 4: If pseudo-static linking is in use (see K. B. Kenny, "Dynamic # Loading for Tcl -- What Became of It?". Proc. 2nd Tcl/Tk Workshop, # New Orleans, LA, Computerized Processes Unlimited, 1994), then we need # to determine which of several header files defines the a.out file # format (a.out.h, sys/exec.h, or sys/exec_aout.h). At present, we # support only a file format that is more or less version-7-compatible. # In particular, # - a.out files must begin with `struct exec'. # - the N_TXTOFF on the `struct exec' must compute the seek address # of the text segment # - The `struct exec' must contain a_magic, a_text, a_data, a_bss # and a_entry fields. # The following compilation should succeed if and only if either sys/exec.h # or a.out.h is usable for the purpose. # # Note that the modified COFF format used on MIPS Ultrix 4.x is usable; the # `struct exec' includes a second header that contains information that # duplicates the v7 fields that are needed. if test "x$DL_OBJS" = "xtclLoadAout.o" ; then AC_CACHE_CHECK([sys/exec.h], tcl_cv_sysexec_h, [ AC_TRY_COMPILE([#include ],[ struct exec foo; unsigned long seek; int flag; #if defined(__mips) || defined(mips) seek = N_TXTOFF (foo.ex_f, foo.ex_o); #else seek = N_TXTOFF (foo); #endif flag = (foo.a_magic == OMAGIC); return foo.a_text + foo.a_data + foo.a_bss + foo.a_entry; ], tcl_cv_sysexec_h=usable, tcl_cv_sysexec_h=unusable)]) if test $tcl_cv_sysexec_h = usable; then AC_DEFINE(USE_SYS_EXEC_H) else AC_CACHE_CHECK([a.out.h], tcl_cv_aout_h, [ AC_TRY_COMPILE([#include ],[ struct exec foo; unsigned long seek; int flag; #if defined(__mips) || defined(mips) seek = N_TXTOFF (foo.ex_f, foo.ex_o); #else seek = N_TXTOFF (foo); #endif flag = (foo.a_magic == OMAGIC); return foo.a_text + foo.a_data + foo.a_bss + foo.a_entry; ], tcl_cv_aout_h=usable, tcl_cv_aout_h=unusable)]) if test $tcl_cv_aout_h = usable; then AC_DEFINE(USE_A_OUT_H) else AC_CACHE_CHECK([sys/exec_aout.h], tcl_cv_sysexecaout_h, [ AC_TRY_COMPILE([#include ],[ struct exec foo; unsigned long seek; int flag; #if defined(__mips) || defined(mips) seek = N_TXTOFF (foo.ex_f, foo.ex_o); #else seek = N_TXTOFF (foo); #endif flag = (foo.a_midmag == OMAGIC); return foo.a_text + foo.a_data + foo.a_bss + foo.a_entry; ], tcl_cv_sysexecaout_h=usable, tcl_cv_sysexecaout_h=unusable)]) if test $tcl_cv_sysexecaout_h = usable; then AC_DEFINE(USE_SYS_EXEC_AOUT_H) else DL_OBJS="" fi fi fi fi # Step 5: disable dynamic loading if requested via a command-line switch. AC_ARG_ENABLE(load, [ --disable-load disallow dynamic loading and "load" command], [tcl_ok=$enableval], [tcl_ok=yes]) if test "$tcl_ok" = "no"; then DL_OBJS="" fi if test "x$DL_OBJS" != "x" ; then BUILD_DLTEST="\$(DLTEST_TARGETS)" else echo "Can't figure out how to do dynamic loading or shared libraries" echo "on this system." SHLIB_CFLAGS="" SHLIB_LD="" SHLIB_SUFFIX="" DL_OBJS="tclLoadNone.o" DL_LIBS="" LDFLAGS="$LDFLAGS_ORIG" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" BUILD_DLTEST="" fi # If we're running gcc, then change the C flags for compiling shared # libraries to the right flags for gcc, instead of those for the # standard manufacturer compiler. if test "$DL_OBJS" != "tclLoadNone.o" -a "$GCC" = yes ; then case $system in AIX-*) ;; BSD/OS*) ;; CYGWIN_*|MINGW32_*) ;; IRIX*) ;; NetBSD-*|FreeBSD-*|OpenBSD-*) ;; Darwin-*) ;; RISCos-*) ;; SCO_SV-3.2*) ;; ULTRIX-4.*) ;; *) SHLIB_CFLAGS="-fPIC" ;; esac fi if test "$SHARED_LIB_SUFFIX" = "" ; then SHARED_LIB_SUFFIX='${VERSION}\$\{DBGX\}${SHLIB_SUFFIX}' fi if test "$UNSHARED_LIB_SUFFIX" = "" ; then UNSHARED_LIB_SUFFIX='${VERSION}\$\{DBGX\}.a' fi DLL_INSTALL_DIR="\$(LIB_INSTALL_DIR)" if test "${SHARED_BUILD}" = "1" && test "${SHLIB_SUFFIX}" != "" ; then LIB_SUFFIX=${SHARED_LIB_SUFFIX} MAKE_LIB='${SHLIB_LD} -o [$]@ ${OBJS} ${SHLIB_LD_LIBS} ${TCL_SHLIB_LD_EXTRAS} ${TK_SHLIB_LD_EXTRAS} ${LD_SEARCH_FLAGS}' if test "${SHLIB_SUFFIX}" = ".dll"; then INSTALL_LIB='$(INSTALL_LIBRARY) $(LIB_FILE) "$(BIN_INSTALL_DIR)/$(LIB_FILE)"' DLL_INSTALL_DIR="\$(BIN_INSTALL_DIR)" else INSTALL_LIB='$(INSTALL_LIBRARY) $(LIB_FILE) "$(LIB_INSTALL_DIR)/$(LIB_FILE)"' fi else LIB_SUFFIX=${UNSHARED_LIB_SUFFIX} if test "$RANLIB" = "" ; then MAKE_LIB='$(STLIB_LD) [$]@ ${OBJS}' INSTALL_LIB='$(INSTALL_LIBRARY) $(LIB_FILE) "$(LIB_INSTALL_DIR)/$(LIB_FILE)"' else MAKE_LIB='${STLIB_LD} [$]@ ${OBJS} ; ${RANLIB} [$]@' INSTALL_LIB='$(INSTALL_LIBRARY) $(LIB_FILE) "$(LIB_INSTALL_DIR)/$(LIB_FILE)" ; (cd "$(LIB_INSTALL_DIR)" ; $(RANLIB) $(LIB_FILE))' fi fi # Stub lib does not depend on shared/static configuration if test "$RANLIB" = "" ; then MAKE_STUB_LIB='${STLIB_LD} [$]@ ${STUB_LIB_OBJS}' INSTALL_STUB_LIB='$(INSTALL_LIBRARY) $(STUB_LIB_FILE) "$(LIB_INSTALL_DIR)/$(STUB_LIB_FILE)"' else MAKE_STUB_LIB='${STLIB_LD} [$]@ ${STUB_LIB_OBJS} ; ${RANLIB} [$]@' INSTALL_STUB_LIB='$(INSTALL_LIBRARY) $(STUB_LIB_FILE) "$(LIB_INSTALL_DIR)/$(STUB_LIB_FILE)" ; (cd "$(LIB_INSTALL_DIR)" ; $(RANLIB) $(STUB_LIB_FILE))' fi # See if the compiler supports casting to a union type. # This is used to stop gcc from printing a compiler # warning when initializing a union member. AC_CACHE_CHECK(for cast to union support, tcl_cv_cast_to_union, AC_TRY_COMPILE([], [ union foo { int i; double d; }; union foo f = (union foo) (int) 0; ], tcl_cv_cast_to_union=yes, tcl_cv_cast_to_union=no) ) if test "$tcl_cv_cast_to_union" = "yes"; then AC_DEFINE(HAVE_CAST_TO_UNION, 1, [Defined when compiler supports casting to union type.]) fi AC_SUBST(DL_LIBS) AC_SUBST(DL_OBJS) AC_SUBST(PLAT_OBJS) AC_SUBST(PLAT_SRCS) AC_SUBST(CFLAGS) AC_SUBST(CFLAGS_DEBUG) AC_SUBST(CFLAGS_OPTIMIZE) AC_SUBST(CFLAGS_WARNING) AC_SUBST(LDFLAGS) AC_SUBST(LDFLAGS_DEBUG) AC_SUBST(LDFLAGS_OPTIMIZE) AC_SUBST(CC_SEARCH_FLAGS) AC_SUBST(LD_SEARCH_FLAGS) AC_SUBST(STLIB_LD) AC_SUBST(SHLIB_LD) AC_SUBST(TCL_SHLIB_LD_EXTRAS) AC_SUBST(TK_SHLIB_LD_EXTRAS) AC_SUBST(SHLIB_LD_LIBS) AC_SUBST(SHLIB_CFLAGS) AC_SUBST(SHLIB_SUFFIX) AC_SUBST(MAKE_LIB) AC_SUBST(MAKE_STUB_LIB) AC_SUBST(INSTALL_LIB) AC_SUBST(DLL_INSTALL_DIR) AC_SUBST(INSTALL_STUB_LIB) AC_SUBST(RANLIB) ]) #-------------------------------------------------------------------- # SC_SERIAL_PORT # # Determine which interface to use to talk to the serial port. # Note that #include lines must begin in leftmost column for # some compilers to recognize them as preprocessor directives, # and some build environments have stdin not pointing at a # pseudo-terminal (usually /dev/null instead.) # # Arguments: # none # # Results: # # Defines only one of the following vars: # HAVE_SYS_MODEM_H # USE_TERMIOS # USE_TERMIO # USE_SGTTY # #-------------------------------------------------------------------- AC_DEFUN([SC_SERIAL_PORT], [ AC_CHECK_HEADERS(sys/modem.h) AC_CACHE_CHECK([termios vs. termio vs. sgtty], tcl_cv_api_serial, [ AC_TRY_RUN([ #include int main() { struct termios t; if (tcgetattr(0, &t) == 0) { cfsetospeed(&t, 0); t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }], tcl_cv_api_serial=termios, tcl_cv_api_serial=no, tcl_cv_api_serial=no) if test $tcl_cv_api_serial = no ; then AC_TRY_RUN([ #include int main() { struct termio t; if (ioctl(0, TCGETA, &t) == 0) { t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }], tcl_cv_api_serial=termio, tcl_cv_api_serial=no, tcl_cv_api_serial=no) fi if test $tcl_cv_api_serial = no ; then AC_TRY_RUN([ #include int main() { struct sgttyb t; if (ioctl(0, TIOCGETP, &t) == 0) { t.sg_ospeed = 0; t.sg_flags |= ODDP | EVENP | RAW; return 0; } return 1; }], tcl_cv_api_serial=sgtty, tcl_cv_api_serial=no, tcl_cv_api_serial=no) fi if test $tcl_cv_api_serial = no ; then AC_TRY_RUN([ #include #include int main() { struct termios t; if (tcgetattr(0, &t) == 0 || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { cfsetospeed(&t, 0); t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }], tcl_cv_api_serial=termios, tcl_cv_api_serial=no, tcl_cv_api_serial=no) fi if test $tcl_cv_api_serial = no; then AC_TRY_RUN([ #include #include int main() { struct termio t; if (ioctl(0, TCGETA, &t) == 0 || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }], tcl_cv_api_serial=termio, tcl_cv_api_serial=no, tcl_cv_api_serial=no) fi if test $tcl_cv_api_serial = no; then AC_TRY_RUN([ #include #include int main() { struct sgttyb t; if (ioctl(0, TIOCGETP, &t) == 0 || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { t.sg_ospeed = 0; t.sg_flags |= ODDP | EVENP | RAW; return 0; } return 1; }], tcl_cv_api_serial=sgtty, tcl_cv_api_serial=none, tcl_cv_api_serial=none) fi]) case $tcl_cv_api_serial in termios) AC_DEFINE(USE_TERMIOS, 1, [Use the termios API for serial lines]);; termio) AC_DEFINE(USE_TERMIO, 1, [Use the termio API for serial lines]);; sgtty) AC_DEFINE(USE_SGTTY, 1, [Use the sgtty API for serial lines]);; esac ]) #-------------------------------------------------------------------- # SC_MISSING_POSIX_HEADERS # # Supply substitutes for missing POSIX header files. Special # notes: # - stdlib.h doesn't define strtol, strtoul, or # strtod insome versions of SunOS # - some versions of string.h don't declare procedures such # as strstr # # Arguments: # none # # Results: # # Defines some of the following vars: # NO_DIRENT_H # NO_ERRNO_H # NO_VALUES_H # HAVE_LIMITS_H or NO_LIMITS_H # NO_STDLIB_H # NO_STRING_H # NO_SYS_WAIT_H # NO_DLFCN_H # HAVE_UNISTD_H # HAVE_SYS_PARAM_H # # HAVE_STRING_H ? # #-------------------------------------------------------------------- AC_DEFUN([SC_MISSING_POSIX_HEADERS], [ AC_CACHE_CHECK([dirent.h], tcl_cv_dirent_h, [ AC_TRY_LINK([#include #include ], [ #ifndef _POSIX_SOURCE # ifdef __Lynx__ /* * Generate compilation error to make the test fail: Lynx headers * are only valid if really in the POSIX environment. */ missing_procedure(); # endif #endif DIR *d; struct dirent *entryPtr; char *p; d = opendir("foobar"); entryPtr = readdir(d); p = entryPtr->d_name; closedir(d); ], tcl_cv_dirent_h=yes, tcl_cv_dirent_h=no)]) if test $tcl_cv_dirent_h = no; then AC_DEFINE(NO_DIRENT_H, 1, [Do we have ?]) fi AC_CHECK_HEADER(errno.h, , [AC_DEFINE(NO_ERRNO_H, 1, [Do we have ?])]) AC_CHECK_HEADER(float.h, , [AC_DEFINE(NO_FLOAT_H, 1, [Do we have ?])]) AC_CHECK_HEADER(values.h, , [AC_DEFINE(NO_VALUES_H, 1, [Do we have ?])]) AC_CHECK_HEADER(limits.h, [AC_DEFINE(HAVE_LIMITS_H, 1, [Do we have ?])], [AC_DEFINE(NO_LIMITS_H, 1, [Do we have ?])]) AC_CHECK_HEADER(stdlib.h, tcl_ok=1, tcl_ok=0) AC_EGREP_HEADER(strtol, stdlib.h, , tcl_ok=0) AC_EGREP_HEADER(strtoul, stdlib.h, , tcl_ok=0) AC_EGREP_HEADER(strtod, stdlib.h, , tcl_ok=0) if test $tcl_ok = 0; then AC_DEFINE(NO_STDLIB_H, 1, [Do we have ?]) fi AC_CHECK_HEADER(string.h, tcl_ok=1, tcl_ok=0) AC_EGREP_HEADER(strstr, string.h, , tcl_ok=0) AC_EGREP_HEADER(strerror, string.h, , tcl_ok=0) # See also memmove check below for a place where NO_STRING_H can be # set and why. if test $tcl_ok = 0; then AC_DEFINE(NO_STRING_H, 1, [Do we have ?]) fi AC_CHECK_HEADER(sys/wait.h, , [AC_DEFINE(NO_SYS_WAIT_H, 1, [Do we have ?])]) AC_CHECK_HEADER(dlfcn.h, , [AC_DEFINE(NO_DLFCN_H, 1, [Do we have ?])]) # OS/390 lacks sys/param.h (and doesn't need it, by chance). AC_HAVE_HEADERS(unistd.h sys/param.h) ]) #-------------------------------------------------------------------- # SC_PATH_X # # Locate the X11 header files and the X11 library archive. Try # the ac_path_x macro first, but if it doesn't find the X stuff # (e.g. because there's no xmkmf program) then check through # a list of possible directories. Under some conditions the # autoconf macro will return an include directory that contains # no include files, so double-check its result just to be safe. # # Arguments: # none # # Results: # # Sets the following vars: # XINCLUDES # XLIBSW # #-------------------------------------------------------------------- AC_DEFUN([SC_PATH_X], [ AC_PATH_X not_really_there="" if test "$no_x" = ""; then if test "$x_includes" = ""; then AC_TRY_CPP([#include ], , not_really_there="yes") else if test ! -r $x_includes/X11/Intrinsic.h; then not_really_there="yes" fi fi fi if test "$no_x" = "yes" -o "$not_really_there" = "yes"; then AC_MSG_CHECKING([for X11 header files]) found_xincludes="no" AC_TRY_CPP([#include ], found_xincludes="yes", found_xincludes="no") if test "$found_xincludes" = "no"; then dirs="/usr/unsupported/include /usr/local/include /usr/X386/include /usr/X11R6/include /usr/X11R5/include /usr/include/X11R5 /usr/include/X11R4 /usr/openwin/include /usr/X11/include /usr/sww/include" for i in $dirs ; do if test -r $i/X11/Intrinsic.h; then AC_MSG_RESULT([$i]) XINCLUDES=" -I$i" found_xincludes="yes" break fi done fi else if test "$x_includes" != ""; then XINCLUDES="-I$x_includes" found_xincludes="yes" fi fi if test "$found_xincludes" = "no"; then AC_MSG_RESULT([couldn't find any!]) fi if test "$no_x" = yes; then AC_MSG_CHECKING([for X11 libraries]) XLIBSW=nope dirs="/usr/unsupported/lib /usr/local/lib /usr/X386/lib /usr/X11R6/lib /usr/X11R5/lib /usr/lib/X11R5 /usr/lib/X11R4 /usr/openwin/lib /usr/X11/lib /usr/sww/X11/lib" for i in $dirs ; do if test -r $i/libX11.a -o -r $i/libX11.so -o -r $i/libX11.sl -o -r $i/libX11.dylib; then AC_MSG_RESULT([$i]) XLIBSW="-L$i -lX11" x_libraries="$i" break fi done else if test "$x_libraries" = ""; then XLIBSW=-lX11 else XLIBSW="-L$x_libraries -lX11" fi fi if test "$XLIBSW" = nope ; then AC_CHECK_LIB(Xwindow, XCreateWindow, XLIBSW=-lXwindow) fi if test "$XLIBSW" = nope ; then AC_MSG_RESULT([could not find any! Using -lX11.]) XLIBSW=-lX11 fi ]) #-------------------------------------------------------------------- # SC_BLOCKING_STYLE # # The statements below check for systems where POSIX-style # non-blocking I/O (O_NONBLOCK) doesn't work or is unimplemented. # On these systems (mostly older ones), use the old BSD-style # FIONBIO approach instead. # # Arguments: # none # # Results: # # Defines some of the following vars: # HAVE_SYS_IOCTL_H # HAVE_SYS_FILIO_H # USE_FIONBIO # O_NONBLOCK # #-------------------------------------------------------------------- AC_DEFUN([SC_BLOCKING_STYLE], [ AC_CHECK_HEADERS(sys/ioctl.h) AC_CHECK_HEADERS(sys/filio.h) SC_CONFIG_SYSTEM AC_MSG_CHECKING([FIONBIO vs. O_NONBLOCK for nonblocking I/O]) case $system in OSF*) AC_DEFINE(USE_FIONBIO, 1, [Should we use FIONBIO?]) AC_MSG_RESULT([FIONBIO]) ;; SunOS-4*) AC_DEFINE(USE_FIONBIO, 1, [Should we use FIONBIO?]) AC_MSG_RESULT([FIONBIO]) ;; ULTRIX-4.*) AC_DEFINE(USE_FIONBIO, 1, [Should we use FIONBIO?]) AC_MSG_RESULT([FIONBIO]) ;; *) AC_MSG_RESULT([O_NONBLOCK]) ;; esac ]) #-------------------------------------------------------------------- # SC_TIME_HANLDER # # Checks how the system deals with time.h, what time structures # are used on the system, and what fields the structures have. # # Arguments: # none # # Results: # # Defines some of the following vars: # USE_DELTA_FOR_TZ # HAVE_TM_GMTOFF # HAVE_TM_TZADJ # HAVE_TIMEZONE_VAR # #-------------------------------------------------------------------- AC_DEFUN([SC_TIME_HANDLER], [ AC_CHECK_HEADERS(sys/time.h) AC_HEADER_TIME AC_STRUCT_TIMEZONE AC_CHECK_FUNCS(gmtime_r localtime_r) AC_CACHE_CHECK([tm_tzadj in struct tm], tcl_cv_member_tm_tzadj, [ AC_TRY_COMPILE([#include ], [struct tm tm; tm.tm_tzadj;], tcl_cv_member_tm_tzadj=yes, tcl_cv_member_tm_tzadj=no)]) if test $tcl_cv_member_tm_tzadj = yes ; then AC_DEFINE(HAVE_TM_TZADJ, 1, [Should we use the tm_tzadj field of struct tm?]) fi AC_CACHE_CHECK([tm_gmtoff in struct tm], tcl_cv_member_tm_gmtoff, [ AC_TRY_COMPILE([#include ], [struct tm tm; tm.tm_gmtoff;], tcl_cv_member_tm_gmtoff=yes, tcl_cv_member_tm_gmtoff=no)]) if test $tcl_cv_member_tm_gmtoff = yes ; then AC_DEFINE(HAVE_TM_GMTOFF, 1, [Should we use the tm_gmtoff field of struct tm?]) fi # # Its important to include time.h in this check, as some systems # (like convex) have timezone functions, etc. # AC_CACHE_CHECK([long timezone variable], tcl_cv_timezone_long, [ AC_TRY_COMPILE([#include ], [extern long timezone; timezone += 1; exit (0);], tcl_cv_timezone_long=yes, tcl_cv_timezone_long=no)]) if test $tcl_cv_timezone_long = yes ; then AC_DEFINE(HAVE_TIMEZONE_VAR, 1, [Should we use the global timezone variable?]) else # # On some systems (eg IRIX 6.2), timezone is a time_t and not a long. # AC_CACHE_CHECK([time_t timezone variable], tcl_cv_timezone_time, [ AC_TRY_COMPILE([#include ], [extern time_t timezone; timezone += 1; exit (0);], tcl_cv_timezone_time=yes, tcl_cv_timezone_time=no)]) if test $tcl_cv_timezone_time = yes ; then AC_DEFINE(HAVE_TIMEZONE_VAR, 1, [Should we use the global timezone variable?]) fi fi ]) #-------------------------------------------------------------------- # SC_BUGGY_STRTOD # # Under Solaris 2.4, strtod returns the wrong value for the # terminating character under some conditions. Check for this # and if the problem exists use a substitute procedure # "fixstrtod" (provided by Tcl) that corrects the error. # Also, on Compaq's Tru64 Unix 5.0, # strtod(" ") returns 0.0 instead of a failure to convert. # # Arguments: # none # # Results: # # Might defines some of the following vars: # strtod (=fixstrtod) # #-------------------------------------------------------------------- AC_DEFUN([SC_BUGGY_STRTOD], [ AC_CHECK_FUNC(strtod, tcl_strtod=1, tcl_strtod=0) if test "$tcl_strtod" = 1; then AC_CACHE_CHECK([for Solaris2.4/Tru64 strtod bugs], tcl_cv_strtod_buggy,[ AC_TRY_RUN([ extern double strtod(); int main() { char *infString="Inf", *nanString="NaN", *spaceString=" "; char *term; double value; value = strtod(infString, &term); if ((term != infString) && (term[-1] == 0)) { exit(1); } value = strtod(nanString, &term); if ((term != nanString) && (term[-1] == 0)) { exit(1); } value = strtod(spaceString, &term); if (term == (spaceString+1)) { exit(1); } exit(0); }], tcl_cv_strtod_buggy=ok, tcl_cv_strtod_buggy=buggy, tcl_cv_strtod_buggy=buggy)]) if test "$tcl_cv_strtod_buggy" = buggy; then LIBOBJS="$LIBOBJS fixstrtod.o" AC_DEFINE(strtod, fixstrtod, [Do we want to use the strtod() in compat?]) fi fi ]) #-------------------------------------------------------------------- # SC_TCL_LINK_LIBS # # Search for the libraries needed to link the Tcl shell. # Things like the math library (-lm) and socket stuff (-lsocket vs. # -lnsl) are dealt with here. # # Arguments: # Requires the following vars to be set in the Makefile: # DL_LIBS # LIBS # MATH_LIBS # # Results: # # Subst's the following var: # TCL_LIBS # MATH_LIBS # # Might append to the following vars: # LIBS # # Might define the following vars: # HAVE_NET_ERRNO_H # #-------------------------------------------------------------------- AC_DEFUN([SC_TCL_LINK_LIBS], [ #-------------------------------------------------------------------- # On a few very rare systems, all of the libm.a stuff is # already in libc.a. Set compiler flags accordingly. # Also, Linux requires the "ieee" library for math to work # right (and it must appear before "-lm"). #-------------------------------------------------------------------- AC_CHECK_FUNC(sin, MATH_LIBS="", MATH_LIBS="-lm") AC_CHECK_LIB(ieee, main, [MATH_LIBS="-lieee $MATH_LIBS"]) #-------------------------------------------------------------------- # Interactive UNIX requires -linet instead of -lsocket, plus it # needs net/errno.h to define the socket-related error codes. #-------------------------------------------------------------------- AC_CHECK_LIB(inet, main, [LIBS="$LIBS -linet"]) AC_CHECK_HEADER(net/errno.h, [ AC_DEFINE(HAVE_NET_ERRNO_H, 1, [Do we have ?])]) #-------------------------------------------------------------------- # Check for the existence of the -lsocket and -lnsl libraries. # The order here is important, so that they end up in the right # order in the command line generated by make. Here are some # special considerations: # 1. Use "connect" and "accept" to check for -lsocket, and # "gethostbyname" to check for -lnsl. # 2. Use each function name only once: can't redo a check because # autoconf caches the results of the last check and won't redo it. # 3. Use -lnsl and -lsocket only if they supply procedures that # aren't already present in the normal libraries. This is because # IRIX 5.2 has libraries, but they aren't needed and they're # bogus: they goof up name resolution if used. # 4. On some SVR4 systems, can't use -lsocket without -lnsl too. # To get around this problem, check for both libraries together # if -lsocket doesn't work by itself. #-------------------------------------------------------------------- tcl_checkBoth=0 AC_CHECK_FUNC(connect, tcl_checkSocket=0, tcl_checkSocket=1) if test "$tcl_checkSocket" = 1; then AC_CHECK_FUNC(setsockopt, , [AC_CHECK_LIB(socket, setsockopt, LIBS="$LIBS -lsocket", tcl_checkBoth=1)]) fi if test "$tcl_checkBoth" = 1; then tk_oldLibs=$LIBS LIBS="$LIBS -lsocket -lnsl" AC_CHECK_FUNC(accept, tcl_checkNsl=0, [LIBS=$tk_oldLibs]) fi AC_CHECK_FUNC(gethostbyname, , [AC_CHECK_LIB(nsl, gethostbyname, [LIBS="$LIBS -lnsl"])]) # Don't perform the eval of the libraries here because DL_LIBS # won't be set until we call SC_CONFIG_CFLAGS TCL_LIBS='${DL_LIBS} ${LIBS} ${MATH_LIBS}' AC_SUBST(TCL_LIBS) AC_SUBST(MATH_LIBS) ]) #-------------------------------------------------------------------- # SC_TCL_EARLY_FLAGS # # Check for what flags are needed to be passed so the correct OS # features are available. # # Arguments: # None # # Results: # # Might define the following vars: # _ISOC99_SOURCE # _LARGEFILE64_SOURCE # _LARGEFILE_SOURCE64 # #-------------------------------------------------------------------- AC_DEFUN([SC_TCL_EARLY_FLAG],[ AC_CACHE_VAL([tcl_cv_flag_]translit($1,[A-Z],[a-z]), AC_TRY_COMPILE([$2], $3, [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no, AC_TRY_COMPILE([[#define ]$1[ 1 ]$2], $3, [tcl_cv_flag_]translit($1,[A-Z],[a-z])=yes, [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no))) if test ["x${tcl_cv_flag_]translit($1,[A-Z],[a-z])[}" = "xyes"] ; then AC_DEFINE($1, 1, [Add the ]$1[ flag when building]) tcl_flags="$tcl_flags $1" fi ]) AC_DEFUN([SC_TCL_EARLY_FLAGS],[ AC_MSG_CHECKING([for required early compiler flags]) tcl_flags="" SC_TCL_EARLY_FLAG(_ISOC99_SOURCE,[#include ], [char *p = (char *)strtoll; char *q = (char *)strtoull;]) SC_TCL_EARLY_FLAG(_LARGEFILE64_SOURCE,[#include ], [struct stat64 buf; int i = stat64("/", &buf);]) SC_TCL_EARLY_FLAG(_LARGEFILE_SOURCE64,[#include ], [char *p = (char *)open64;]) if test "x${tcl_flags}" = "x" ; then AC_MSG_RESULT([none]) else AC_MSG_RESULT([${tcl_flags}]) fi ]) #-------------------------------------------------------------------- # SC_TCL_64BIT_FLAGS # # Check for what is defined in the way of 64-bit features. # # Arguments: # None # # Results: # # Might define the following vars: # TCL_WIDE_INT_IS_LONG # TCL_WIDE_INT_TYPE # HAVE_STRUCT_DIRENT64 # HAVE_STRUCT_STAT64 # HAVE_TYPE_OFF64_T # #-------------------------------------------------------------------- AC_DEFUN([SC_TCL_64BIT_FLAGS], [ AC_MSG_CHECKING([for 64-bit integer type]) AC_CACHE_VAL(tcl_cv_type_64bit,[ tcl_cv_type_64bit=none # See if the compiler knows natively about __int64 AC_TRY_COMPILE(,[__int64 value = (__int64) 0;], tcl_type_64bit=__int64, tcl_type_64bit="long long") # See if we should use long anyway Note that we substitute in the # type that is our current guess for a 64-bit type inside this check # program, so it should be modified only carefully... AC_TRY_COMPILE(,[switch (0) { case 1: case (sizeof(]${tcl_type_64bit}[)==sizeof(long)): ; }],tcl_cv_type_64bit=${tcl_type_64bit})]) if test "${tcl_cv_type_64bit}" = none ; then AC_DEFINE(TCL_WIDE_INT_IS_LONG, 1, [Are wide integers to be implemented with C 'long's?]) AC_MSG_RESULT([using long]) else AC_DEFINE_UNQUOTED(TCL_WIDE_INT_TYPE,${tcl_cv_type_64bit}, [What type should be used to define wide integers?]) AC_MSG_RESULT([${tcl_cv_type_64bit}]) # Now check for auxiliary declarations AC_CACHE_CHECK([for struct dirent64], tcl_cv_struct_dirent64,[ AC_TRY_COMPILE([#include #include ],[struct dirent64 p;], tcl_cv_struct_dirent64=yes,tcl_cv_struct_dirent64=no)]) if test "x${tcl_cv_struct_dirent64}" = "xyes" ; then AC_DEFINE(HAVE_STRUCT_DIRENT64, 1, [Is 'struct dirent64' in ?]) fi AC_CACHE_CHECK([for struct stat64], tcl_cv_struct_stat64,[ AC_TRY_COMPILE([#include ],[struct stat64 p; ], tcl_cv_struct_stat64=yes,tcl_cv_struct_stat64=no)]) if test "x${tcl_cv_struct_stat64}" = "xyes" ; then AC_DEFINE(HAVE_STRUCT_STAT64, 1, [Is 'struct stat64' in ?]) fi AC_CHECK_FUNCS(open64 lseek64) AC_MSG_CHECKING([for off64_t]) AC_CACHE_VAL(tcl_cv_type_off64_t,[ AC_TRY_COMPILE([#include ],[off64_t offset; ], tcl_cv_type_off64_t=yes,tcl_cv_type_off64_t=no)]) dnl Define HAVE_TYPE_OFF64_T only when the off64_t type and the dnl functions lseek64 and open64 are defined. if test "x${tcl_cv_type_off64_t}" = "xyes" && \ test "x${ac_cv_func_lseek64}" = "xyes" && \ test "x${ac_cv_func_open64}" = "xyes" ; then AC_DEFINE(HAVE_TYPE_OFF64_T, 1, [Is off64_t in ?]) AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi fi ]) #-------------------------------------------------------------------- # SC_TCL_GETHOSTBYADDR_R # # Check if we have MT-safe variant of gethostbyaddr(). # # Arguments: # None # # Results: # # Might define the following vars: # HAVE_GETHOSTBYADDR_R # HAVE_GETHOSTBYADDR_R_7 # HAVE_GETHOSTBYADDR_R_8 # #-------------------------------------------------------------------- AC_DEFUN([SC_TCL_GETHOSTBYADDR_R], [AC_CHECK_FUNC(gethostbyaddr_r, [ AC_CACHE_CHECK([for gethostbyaddr_r with 7 args], tcl_cv_api_gethostbyaddr_r_7, [ AC_TRY_COMPILE([ #include ], [ char *addr; int length; int type; struct hostent *result; char buffer[2048]; int buflen = 2048; int h_errnop; (void) gethostbyaddr_r(addr, length, type, result, buffer, buflen, &h_errnop); ], tcl_cv_api_gethostbyaddr_r_7=yes, tcl_cv_api_gethostbyaddr_r_7=no)]) tcl_ok=$tcl_cv_api_gethostbyaddr_r_7 if test "$tcl_ok" = yes; then AC_DEFINE(HAVE_GETHOSTBYADDR_R_7, 1, [Define to 1 if gethostbyaddr_r takes 7 args.]) else AC_CACHE_CHECK([for gethostbyaddr_r with 8 args], tcl_cv_api_gethostbyaddr_r_8, [ AC_TRY_COMPILE([ #include ], [ char *addr; int length; int type; struct hostent *result, *resultp; char buffer[2048]; int buflen = 2048; int h_errnop; (void) gethostbyaddr_r(addr, length, type, result, buffer, buflen, &resultp, &h_errnop); ], tcl_cv_api_gethostbyaddr_r_8=yes, tcl_cv_api_gethostbyaddr_r_8=no)]) tcl_ok=$tcl_cv_api_gethostbyaddr_r_8 if test "$tcl_ok" = yes; then AC_DEFINE(HAVE_GETHOSTBYADDR_R_8, 1, [Define to 1 if gethostbyaddr_r takes 8 args.]) fi fi if test "$tcl_ok" = yes; then AC_DEFINE(HAVE_GETHOSTBYADDR_R, 1, [Define to 1 if gethostbyaddr_r is available.]) fi ])]) #-------------------------------------------------------------------- # SC_TCL_GETHOSTBYNAME_R # # Check to see what variant of gethostbyname_r() we have. # Based on David Arnold's example from the comp.programming.threads # FAQ Q213 # # Arguments: # None # # Results: # # Might define the following vars: # HAVE_GETHOSTBYADDR_R # HAVE_GETHOSTBYADDR_R_3 # HAVE_GETHOSTBYADDR_R_5 # HAVE_GETHOSTBYADDR_R_6 # #-------------------------------------------------------------------- AC_DEFUN([SC_TCL_GETHOSTBYNAME_R], [AC_CHECK_FUNC(gethostbyname_r, [ AC_CACHE_CHECK([for gethostbyname_r with 6 args], tcl_cv_api_gethostbyname_r_6, [ AC_TRY_COMPILE([ #include ], [ char *name; struct hostent *he, *res; char buffer[2048]; int buflen = 2048; int h_errnop; (void) gethostbyname_r(name, he, buffer, buflen, &res, &h_errnop); ], tcl_cv_api_gethostbyname_r_6=yes, tcl_cv_api_gethostbyname_r_6=no)]) tcl_ok=$tcl_cv_api_gethostbyname_r_6 if test "$tcl_ok" = yes; then AC_DEFINE(HAVE_GETHOSTBYNAME_R_6, 1, [Define to 1 if gethostbyname_r takes 6 args.]) else AC_CACHE_CHECK([for gethostbyname_r with 5 args], tcl_cv_api_gethostbyname_r_5, [ AC_TRY_COMPILE([ #include ], [ char *name; struct hostent *he; char buffer[2048]; int buflen = 2048; int h_errnop; (void) gethostbyname_r(name, he, buffer, buflen, &h_errnop); ], tcl_cv_api_gethostbyname_r_5=yes, tcl_cv_api_gethostbyname_r_5=no)]) tcl_ok=$tcl_cv_api_gethostbyname_r_5 if test "$tcl_ok" = yes; then AC_DEFINE(HAVE_GETHOSTBYNAME_R_5, 1, [Define to 1 if gethostbyname_r takes 5 args.]) else AC_CACHE_CHECK([for gethostbyname_r with 3 args], tcl_cv_api_gethostbyname_r_3, [ AC_TRY_COMPILE([ #include ], [ char *name; struct hostent *he; struct hostent_data data; (void) gethostbyname_r(name, he, &data); ], tcl_cv_api_gethostbyname_r_3=yes, tcl_cv_api_gethostbyname_r_3=no)]) tcl_ok=$tcl_cv_api_gethostbyname_r_3 if test "$tcl_ok" = yes; then AC_DEFINE(HAVE_GETHOSTBYNAME_R_3, 1, [Define to 1 if gethostbyname_r takes 3 args.]) fi fi fi if test "$tcl_ok" = yes; then AC_DEFINE(HAVE_GETHOSTBYNAME_R, 1, [Define to 1 if gethostbyname_r is available.]) fi ])]) #-------------------------------------------------------------------- # SC_TCL_GETPWUID_R # # Check if we have MT-safe variant of getpwuid() and if yes, # which one exactly. # # Arguments: # None # # Results: # # Might define the following vars: # HAVE_GETPWUID_R # HAVE_GETPWUID_R_4 # HAVE_GETPWUID_R_5 # #-------------------------------------------------------------------- AC_DEFUN([SC_TCL_GETPWUID_R], [AC_CHECK_FUNC(getpwuid_r, [ AC_CACHE_CHECK([for getpwuid_r with 5 args], tcl_cv_api_getpwuid_r_5, [ AC_TRY_COMPILE([ #include #include ], [ uid_t uid; struct passwd pw, *pwp; char buf[512]; int buflen = 512; (void) getpwuid_r(uid, &pw, buf, buflen, &pwp); ], tcl_cv_api_getpwuid_r_5=yes, tcl_cv_api_getpwuid_r_5=no)]) tcl_ok=$tcl_cv_api_getpwuid_r_5 if test "$tcl_ok" = yes; then AC_DEFINE(HAVE_GETPWUID_R_5, 1, [Define to 1 if getpwuid_r takes 5 args.]) else AC_CACHE_CHECK([for getpwuid_r with 4 args], tcl_cv_api_getpwuid_r_4, [ AC_TRY_COMPILE([ #include #include ], [ uid_t uid; struct passwd pw; char buf[512]; int buflen = 512; (void)getpwnam_r(uid, &pw, buf, buflen); ], tcl_cv_api_getpwuid_r_4=yes, tcl_cv_api_getpwuid_r_4=no)]) tcl_ok=$tcl_cv_api_getpwuid_r_4 if test "$tcl_ok" = yes; then AC_DEFINE(HAVE_GETPWUID_R_4, 1, [Define to 1 if getpwuid_r takes 4 args.]) fi fi if test "$tcl_ok" = yes; then AC_DEFINE(HAVE_GETPWUID_R, 1, [Define to 1 if getpwuid_r is available.]) fi ])]) #-------------------------------------------------------------------- # SC_TCL_GETPWNAM_R # # Check if we have MT-safe variant of getpwnam() and if yes, # which one exactly. # # Arguments: # None # # Results: # # Might define the following vars: # HAVE_GETPWNAM_R # HAVE_GETPWNAM_R_4 # HAVE_GETPWNAM_R_5 # #-------------------------------------------------------------------- AC_DEFUN([SC_TCL_GETPWNAM_R], [AC_CHECK_FUNC(getpwnam_r, [ AC_CACHE_CHECK([for getpwnam_r with 5 args], tcl_cv_api_getpwnam_r_5, [ AC_TRY_COMPILE([ #include #include ], [ char *name; struct passwd pw, *pwp; char buf[512]; int buflen = 512; (void) getpwnam_r(name, &pw, buf, buflen, &pwp); ], tcl_cv_api_getpwnam_r_5=yes, tcl_cv_api_getpwnam_r_5=no)]) tcl_ok=$tcl_cv_api_getpwnam_r_5 if test "$tcl_ok" = yes; then AC_DEFINE(HAVE_GETPWNAM_R_5, 1, [Define to 1 if getpwnam_r takes 5 args.]) else AC_CACHE_CHECK([for getpwnam_r with 4 args], tcl_cv_api_getpwnam_r_4, [ AC_TRY_COMPILE([ #include #include ], [ char *name; struct passwd pw; char buf[512]; int buflen = 512; (void)getpwnam_r(name, &pw, buf, buflen); ], tcl_cv_api_getpwnam_r_4=yes, tcl_cv_api_getpwnam_r_4=no)]) tcl_ok=$tcl_cv_api_getpwnam_r_4 if test "$tcl_ok" = yes; then AC_DEFINE(HAVE_GETPWNAM_R_4, 1, [Define to 1 if getpwnam_r takes 4 args.]) fi fi if test "$tcl_ok" = yes; then AC_DEFINE(HAVE_GETPWNAM_R, 1, [Define to 1 if getpwnam_r is available.]) fi ])]) #-------------------------------------------------------------------- # SC_TCL_GETGRGID_R # # Check if we have MT-safe variant of getgrgid() and if yes, # which one exactly. # # Arguments: # None # # Results: # # Might define the following vars: # HAVE_GETGRGID_R # HAVE_GETGRGID_R_4 # HAVE_GETGRGID_R_5 # #-------------------------------------------------------------------- AC_DEFUN([SC_TCL_GETGRGID_R], [AC_CHECK_FUNC(getgrgid_r, [ AC_CACHE_CHECK([for getgrgid_r with 5 args], tcl_cv_api_getgrgid_r_5, [ AC_TRY_COMPILE([ #include #include ], [ gid_t gid; struct group gr, *grp; char buf[512]; int buflen = 512; (void) getgrgid_r(gid, &gr, buf, buflen, &grp); ], tcl_cv_api_getgrgid_r_5=yes, tcl_cv_api_getgrgid_r_5=no)]) tcl_ok=$tcl_cv_api_getgrgid_r_5 if test "$tcl_ok" = yes; then AC_DEFINE(HAVE_GETGRGID_R_5, 1, [Define to 1 if getgrgid_r takes 5 args.]) else AC_CACHE_CHECK([for getgrgid_r with 4 args], tcl_cv_api_getgrgid_r_4, [ AC_TRY_COMPILE([ #include #include ], [ gid_t gid; struct group gr; char buf[512]; int buflen = 512; (void)getgrgid_r(gid, &gr, buf, buflen); ], tcl_cv_api_getgrgid_r_4=yes, tcl_cv_api_getgrgid_r_4=no)]) tcl_ok=$tcl_cv_api_getgrgid_r_4 if test "$tcl_ok" = yes; then AC_DEFINE(HAVE_GETGRGID_R_4, 1, [Define to 1 if getgrgid_r takes 4 args.]) fi fi if test "$tcl_ok" = yes; then AC_DEFINE(HAVE_GETGRGID_R, 1, [Define to 1 if getgrgid_r is available.]) fi ])]) #-------------------------------------------------------------------- # SC_TCL_GETGRNAM_R # # Check if we have MT-safe variant of getgrnam() and if yes, # which one exactly. # # Arguments: # None # # Results: # # Might define the following vars: # HAVE_GETGRNAM_R # HAVE_GETGRNAM_R_4 # HAVE_GETGRNAM_R_5 # #-------------------------------------------------------------------- AC_DEFUN([SC_TCL_GETGRNAM_R], [AC_CHECK_FUNC(getgrnam_r, [ AC_CACHE_CHECK([for getgrnam_r with 5 args], tcl_cv_api_getgrnam_r_5, [ AC_TRY_COMPILE([ #include #include ], [ char *name; struct group gr, *grp; char buf[512]; int buflen = 512; (void) getgrnam_r(name, &gr, buf, buflen, &grp); ], tcl_cv_api_getgrnam_r_5=yes, tcl_cv_api_getgrnam_r_5=no)]) tcl_ok=$tcl_cv_api_getgrnam_r_5 if test "$tcl_ok" = yes; then AC_DEFINE(HAVE_GETGRNAM_R_5, 1, [Define to 1 if getgrnam_r takes 5 args.]) else AC_CACHE_CHECK([for getgrnam_r with 4 args], tcl_cv_api_getgrnam_r_4, [ AC_TRY_COMPILE([ #include #include ], [ char *name; struct group gr; char buf[512]; int buflen = 512; (void)getgrnam_r(name, &gr, buf, buflen); ], tcl_cv_api_getgrnam_r_4=yes, tcl_cv_api_getgrnam_r_4=no)]) tcl_ok=$tcl_cv_api_getgrnam_r_4 if test "$tcl_ok" = yes; then AC_DEFINE(HAVE_GETGRNAM_R_4, 1, [Define to 1 if getgrnam_r takes 4 args.]) fi fi if test "$tcl_ok" = yes; then AC_DEFINE(HAVE_GETGRNAM_R, 1, [Define to 1 if getgrnam_r is available.]) fi ])]) #-------------------------------------------------------------------- # SC_CONFIG_COMMANDS_PRE(CMDS) # # Replacement for autoconf 2.5x AC_COMMANDS_PRE: # Commands to run right before config.status is # created. Accumulates. # # Requires presence of SC_OUTPUT_COMMANDS_PRE at the end # of configure.in (right before AC_OUTPUT). # #-------------------------------------------------------------------- AC_DEFUN([SC_CONFIG_COMMANDS_PRE], [ define([SC_OUTPUT_COMMANDS_PRE], defn([SC_OUTPUT_COMMANDS_PRE])[$1 ])]) AC_DEFUN([SC_OUTPUT_COMMANDS_PRE]) # Local Variables: # mode: autoconf # End: tcl8.4.20/unix/tclLoadDl.c0000644003604700454610000001354011737050675013714 0ustar dgp771div/* * tclLoadDl.c -- * * This procedure provides a version of the TclLoadFile that * works with the "dlopen" and "dlsym" library procedures for * dynamic loading. * * Copyright (c) 1995-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #ifdef NO_DLFCN_H # include "../compat/dlfcn.h" #else # include #endif /* * In some systems, like SunOS 4.1.3, the RTLD_NOW flag isn't defined * and this argument to dlopen must always be 1. The RTLD_GLOBAL * flag is needed on some systems (e.g. SCO and UnixWare) but doesn't * exist on others; if it doesn't exist, set it to 0 so it has no effect. */ #ifndef RTLD_NOW # define RTLD_NOW 1 #endif #ifndef RTLD_GLOBAL # define RTLD_GLOBAL 0 #endif /* *--------------------------------------------------------------------------- * * TclpDlopen -- * * Dynamically loads a binary code file into memory and returns * a handle to the new code. * * Results: * A standard Tcl completion code. If an error occurs, an error * message is left in the interp's result. * * Side effects: * New code suddenly appears in memory. * *--------------------------------------------------------------------------- */ int TclpDlopen(interp, pathPtr, loadHandle, unloadProcPtr) Tcl_Interp *interp; /* Used for error reporting. */ Tcl_Obj *pathPtr; /* Name of the file containing the desired * code (UTF-8). */ Tcl_LoadHandle *loadHandle; /* Filled with token for dynamically loaded * file which will be passed back to * (*unloadProcPtr)() to unload the file. */ Tcl_FSUnloadFileProc **unloadProcPtr; /* Filled with address of Tcl_FSUnloadFileProc * function which should be used for * this file. */ { VOID *handle; CONST char *native; /* * First try the full path the user gave us. This is particularly * important if the cwd is inside a vfs, and we are trying to load * using a relative path. */ native = Tcl_FSGetNativePath(pathPtr); handle = dlopen(native, RTLD_NOW | RTLD_GLOBAL); if (handle == NULL) { /* * Let the OS loader examine the binary search path for * whatever string the user gave us which hopefully refers * to a file on the binary path */ Tcl_DString ds; char *fileName = Tcl_GetString(pathPtr); native = Tcl_UtfToExternalDString(NULL, fileName, -1, &ds); handle = dlopen(native, RTLD_NOW | RTLD_GLOBAL); Tcl_DStringFree(&ds); } if (handle == NULL) { /* * Write the string to a variable first to work around a compiler bug * in the Sun Forte 6 compiler. [Bug 1503729] */ CONST char *errorStr = dlerror(); Tcl_AppendResult(interp, "couldn't load file \"", Tcl_GetString(pathPtr), "\": ", errorStr, (char *) NULL); return TCL_ERROR; } *unloadProcPtr = &TclpUnloadFile; *loadHandle = (Tcl_LoadHandle)handle; return TCL_OK; } /* *---------------------------------------------------------------------- * * TclpFindSymbol -- * * Looks up a symbol, by name, through a handle associated with * a previously loaded piece of code (shared library). * * Results: * Returns a pointer to the function associated with 'symbol' if * it is found. Otherwise returns NULL and may leave an error * message in the interp's result. * *---------------------------------------------------------------------- */ Tcl_PackageInitProc* TclpFindSymbol(interp, loadHandle, symbol) Tcl_Interp *interp; Tcl_LoadHandle loadHandle; CONST char *symbol; { CONST char *native; Tcl_DString newName, ds; VOID *handle = (VOID*)loadHandle; Tcl_PackageInitProc *proc; /* * Some platforms still add an underscore to the beginning of symbol * names. If we can't find a name without an underscore, try again * with the underscore. */ native = Tcl_UtfToExternalDString(NULL, symbol, -1, &ds); proc = (Tcl_PackageInitProc *) dlsym(handle, /* INTL: Native. */ native); if (proc == NULL) { Tcl_DStringInit(&newName); Tcl_DStringAppend(&newName, "_", 1); native = Tcl_DStringAppend(&newName, native, -1); proc = (Tcl_PackageInitProc *) dlsym(handle, /* INTL: Native. */ native); Tcl_DStringFree(&newName); } Tcl_DStringFree(&ds); return proc; } /* *---------------------------------------------------------------------- * * TclpUnloadFile -- * * Unloads a dynamically loaded binary code file from memory. * Code pointers in the formerly loaded file are no longer valid * after calling this function. * * Results: * None. * * Side effects: * Code removed from memory. * *---------------------------------------------------------------------- */ void TclpUnloadFile(loadHandle) Tcl_LoadHandle loadHandle; /* loadHandle returned by a previous call * to TclpDlopen(). The loadHandle is * a token that represents the loaded * file. */ { VOID *handle; handle = (VOID *) loadHandle; dlclose(handle); } /* *---------------------------------------------------------------------- * * TclGuessPackageName -- * * If the "load" command is invoked without providing a package * name, this procedure is invoked to try to figure it out. * * Results: * Always returns 0 to indicate that we couldn't figure out a * package name; generic code will then try to guess the package * from the file name. A return value of 1 would have meant that * we figured out the package name and put it in bufPtr. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclGuessPackageName(fileName, bufPtr) CONST char *fileName; /* Name of file containing package (already * translated to local form if needed). */ Tcl_DString *bufPtr; /* Initialized empty dstring. Append * package name to this if possible. */ { return 0; } tcl8.4.20/unix/Makefile.in0000664003604700454610000014526212153151142013744 0ustar dgp771div# # This file is a Makefile for Tcl. If it has the name "Makefile.in" # then it is a template for a Makefile; to generate the actual Makefile, # run "./configure", which is a configuration script generated by the # "autoconf" program (constructs like "@foo@" will get replaced in the # actual Makefile. VERSION = @TCL_VERSION@ MAJOR_VERSION = @TCL_MAJOR_VERSION@ MINOR_VERSION = @TCL_MINOR_VERSION@ PATCH_LEVEL = @TCL_PATCH_LEVEL@ #---------------------------------------------------------------- # Things you can change to personalize the Makefile for your own # site (you can make these changes in either Makefile.in or # Makefile, but changes to Makefile will get lost if you re-run # the configuration script). #---------------------------------------------------------------- # Default top-level directories in which to install architecture- # specific files (exec_prefix) and machine-independent files such # as scripts (prefix). The values specified here may be overridden # at configure-time with the --exec-prefix and --prefix options # to the "configure" script. The *dir vars are standard configure # substitutions that are based off prefix and exec_prefix. prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ libdir = @libdir@ includedir = @includedir@ mandir = @mandir@ # The following definition can be set to non-null for special systems # like AFS with replication. It allows the pathnames used for installation # to be different than those used for actually reference files at # run-time. INSTALL_ROOT is prepended to $prefix and $exec_prefix # when installing files. INSTALL_ROOT = $(DESTDIR) # Path for the platform independent Tcl scripting libraries: TCL_LIBRARY = @TCL_LIBRARY@ # Path to use at runtime to refer to LIB_INSTALL_DIR: LIB_RUNTIME_DIR = $(libdir) # Directory in which to install the program tclsh: BIN_INSTALL_DIR = $(INSTALL_ROOT)$(bindir) # Directory in which to install libtcl.so or libtcl.a: LIB_INSTALL_DIR = $(INSTALL_ROOT)$(libdir) DLL_INSTALL_DIR = @DLL_INSTALL_DIR@ # Path name to use when installing library scripts. SCRIPT_INSTALL_DIR = $(INSTALL_ROOT)$(TCL_LIBRARY) # Directory in which to install the include file tcl.h: INCLUDE_INSTALL_DIR = $(INSTALL_ROOT)$(includedir) # Path to the private tcl header dir: PRIVATE_INCLUDE_DIR = @PRIVATE_INCLUDE_DIR@ # Directory in which to (optionally) install the private tcl headers: PRIVATE_INCLUDE_INSTALL_DIR = $(INSTALL_ROOT)$(PRIVATE_INCLUDE_DIR) # Top-level directory in which to install manual entries: MAN_INSTALL_DIR = $(INSTALL_ROOT)$(mandir) # Directory in which to install manual entry for tclsh: MAN1_INSTALL_DIR = $(MAN_INSTALL_DIR)/man1 # Directory in which to install manual entries for Tcl's C library # procedures: MAN3_INSTALL_DIR = $(MAN_INSTALL_DIR)/man3 # Directory in which to install manual entries for the built-in # Tcl commands: MANN_INSTALL_DIR = $(MAN_INSTALL_DIR)/mann # Path to the html documentation dir: HTML_DIR = @HTML_DIR@ # Directory in which to install html documentation: HTML_INSTALL_DIR = $(INSTALL_ROOT)$(HTML_DIR) # Package search path. TCL_PACKAGE_PATH = @TCL_PACKAGE_PATH@ # Libraries built with optimization switches have this additional extension TCL_DBGX = @TCL_DBGX@ # warning flags CFLAGS_WARNING = @CFLAGS_WARNING@ # The default switches for optimization or debugging CFLAGS_DEBUG = @CFLAGS_DEBUG@ CFLAGS_OPTIMIZE = @CFLAGS_OPTIMIZE@ # To change the compiler switches, for example to change from optimization to # debugging symbols, change the following line: #CFLAGS = $(CFLAGS_DEBUG) #CFLAGS = $(CFLAGS_OPTIMIZE) #CFLAGS = $(CFLAGS_DEBUG) $(CFLAGS_OPTIMIZE) CFLAGS = @CFLAGS_DEFAULT@ @CFLAGS@ -DTCL_DBGX=$(TCL_DBGX) # Flags to pass to the linker LDFLAGS_DEBUG = @LDFLAGS_DEBUG@ LDFLAGS_OPTIMIZE = @LDFLAGS_OPTIMIZE@ LDFLAGS = @LDFLAGS_DEFAULT@ @LDFLAGS@ # To disable ANSI-C procedure prototypes reverse the comment characters # on the following lines: PROTO_FLAGS = #PROTO_FLAGS = -DNO_PROTOTYPE # Mathematical functions like sin and atan2 are enabled for expressions # by default. To disable them, reverse the comment characters on the # following pairs of lines: MATH_FLAGS = #MATH_FLAGS = -DTCL_NO_MATH MATH_LIBS = @MATH_LIBS@ #MATH_LIBS = # If you use the setenv, putenv, or unsetenv procedures to modify # environment variables in your application and you'd like those # modifications to appear in the "env" Tcl variable, switch the # comments on the two lines below so that Tcl provides these # procedures instead of your standard C library. ENV_FLAGS = #ENV_FLAGS = -DTclSetEnv=setenv -DTcl_PutEnv=putenv -DTclUnsetEnv=unsetenv # To compile for non-UNIX systems (so that only the non-UNIX-specific # commands are available), reverse the comment characters on the # following pairs of lines. In addition, you'll have to provide your # own replacement for the "panic" procedure (see panic.c for what # the current one does). GENERIC_FLAGS = #GENERIC_FLAGS = -DTCL_GENERIC_ONLY UNIX_OBJS = tclUnixChan.o tclUnixEvent.o tclUnixFCmd.o \ tclUnixFile.o tclUnixPipe.o tclUnixSock.o \ tclUnixTime.o tclUnixInit.o tclUnixThrd.o \ tclUnixCompat.o #UNIX_OBJS = NOTIFY_OBJS = tclUnixNotfy.o #NOTIFY_OBJS = # To enable memory debugging reverse the comment characters on the following # lines or call configure with --enable-symbols=mem # Warning: if you enable memory debugging, you must do it *everywhere*, # including all the code that calls Tcl, and you must use ckalloc and # ckfree everywhere instead of malloc and free. MEM_DEBUG_FLAGS = #MEM_DEBUG_FLAGS = -DTCL_MEM_DEBUG TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@ #TCL_STUB_LIB_FILE = libtclstub.a # Generic stub lib name used in rules that apply to tcl and tk STUB_LIB_FILE = ${TCL_STUB_LIB_FILE} TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@ #TCL_STUB_LIB_FLAG = -ltclstub # To enable compilation debugging reverse the comment characters on one # of the following lines or call configure with --enable-symbols=compile COMPILE_DEBUG_FLAGS = #COMPILE_DEBUG_FLAGS = -DTCL_COMPILE_DEBUG -DTCL_COMPILE_STATS # To compile without backward compatibility and deprecated code # uncomment the following NO_DEPRECATED_FLAGS = #NO_DEPRECATED_FLAGS = -DTCL_NO_DEPRECATED # Some versions of make, like SGI's, use the following variable to # determine which shell to use for executing commands: SHELL = @MAKEFILE_SHELL@ # Tcl used to let the configure script choose which program to use # for installing, but there are just too many different versions of # "install" around; better to use the install-sh script that comes # with the distribution, which is slower but guaranteed to work. INSTALL_STRIP_PROGRAM = -s INSTALL_STRIP_LIBRARY = -S -S INSTALL = @srcdir@/install-sh -c INSTALL_PROGRAM = ${INSTALL} INSTALL_LIBRARY = ${INSTALL} INSTALL_DATA = ${INSTALL} -m 644 # TCL_EXE is the name of a tclsh executable that is available *BEFORE* # running make for the first time. Certain build targets (make genstubs) # need it to be available on the PATH. This executable should *NOT* be # required just to do a normal build although it can be required to run # make dist. TCL_EXE = tclsh # The symbols below provide support for dynamic loading and shared # libraries. See configure.in for a description of what the # symbols mean. The values of the symbols are normally set by the # configure script. You shouldn't normally need to modify any of # these definitions by hand. STLIB_LD = @STLIB_LD@ SHLIB_LD = @SHLIB_LD@ SHLIB_CFLAGS = @SHLIB_CFLAGS@ SHLIB_LD_LIBS = @SHLIB_LD_LIBS@ TCL_SHLIB_LD_EXTRAS = @TCL_SHLIB_LD_EXTRAS@ SHLIB_SUFFIX = @SHLIB_SUFFIX@ #SHLIB_SUFFIX = DLTEST_TARGETS = dltest.marker # Additional search flags needed to find the various shared libraries # at run-time. The first symbol is for use when creating a binary # with cc, and the second is for use when running ld directly. CC_SEARCH_FLAGS = @CC_SEARCH_FLAGS@ LD_SEARCH_FLAGS = @LD_SEARCH_FLAGS@ # The following symbol is defined to "$(DLTEST_TARGETS)" if dynamic # loading is available; this causes everything in the "dltest" # subdirectory to be built when making "tcltest. If dynamic loading # isn't available, configure defines this symbol to an empty string, # in which case the shared libraries aren't built. BUILD_DLTEST = @BUILD_DLTEST@ #BUILD_DLTEST = TCL_LIB_FILE = @TCL_LIB_FILE@ #TCL_LIB_FILE = libtcl.a # Generic lib name used in rules that apply to tcl and tk LIB_FILE = ${TCL_LIB_FILE} TCL_LIB_FLAG = @TCL_LIB_FLAG@ #TCL_LIB_FLAG = -ltcl TCL_EXP_FILE = @TCL_EXP_FILE@ TCL_BUILD_EXP_FILE = @TCL_BUILD_EXP_FILE@ # support for embedded libraries on Darwin / Mac OS X DYLIB_INSTALL_DIR = ${LIB_RUNTIME_DIR} #---------------------------------------------------------------- # The information below is modified by the configure script when # Makefile is generated from Makefile.in. You shouldn't normally # modify any of this stuff by hand. #---------------------------------------------------------------- COMPAT_OBJS = @LIBOBJS@ AC_FLAGS = @DEFS@ AR = @AR@ RANLIB = @RANLIB@ DTRACE = @DTRACE@ SRC_DIR = @srcdir@ TOP_DIR = $(SRC_DIR)/.. GENERIC_DIR = $(TOP_DIR)/generic COMPAT_DIR = $(TOP_DIR)/compat TOOL_DIR = $(TOP_DIR)/tools UNIX_DIR = $(TOP_DIR)/unix MAC_OSX_DIR = $(TOP_DIR)/macosx # Must be absolute because of the cd dltest $(DLTEST_DIR)/configure below. DLTEST_DIR = @TCL_SRC_DIR@/unix/dltest # Must be absolute to so the corresponding tcltest's tcl_library is absolute. TCL_BUILDTIME_LIBRARY = @TCL_SRC_DIR@/library CC = @CC@ #CC = purify -best-effort @CC@ -DPURIFY # Flags to be passed to installManPage to control whether the manpages # should be compressed and linked with softlinks MAN_FLAGS = @MAN_FLAGS@ #---------------------------------------------------------------- # The information below is usually usable as is. The configure # script won't modify it and it only exists to make working # around selected rare system configurations easier. #---------------------------------------------------------------- GDB = gdb DDD = ddd #---------------------------------------------------------------- # The information below should be usable as is. The configure # script won't modify it and you shouldn't need to modify it # either. #---------------------------------------------------------------- STUB_CC_SWITCHES = ${CFLAGS} ${CFLAGS_WARNING} ${SHLIB_CFLAGS} -I. \ -I${GENERIC_DIR} -I${SRC_DIR} ${AC_FLAGS} ${MATH_FLAGS} ${GENERIC_FLAGS} \ ${PROTO_FLAGS} ${MEM_DEBUG_FLAGS} ${COMPILE_DEBUG_FLAGS} ${ENV_FLAGS} \ -DTCL_SHLIB_EXT=\"${SHLIB_SUFFIX}\" @EXTRA_CC_SWITCHES@ CC_SWITCHES = $(STUB_CC_SWITCHES) ${NO_DEPRECATED_FLAGS} APP_CC_SWITCHES = $(CC_SWITCHES) @EXTRA_APP_CC_SWITCHES@ LIBS = @DL_LIBS@ @LIBS@ $(MATH_LIBS) DEPEND_SWITCHES = ${CFLAGS} -I${GENERIC_DIR} -I${SRC_DIR} \ ${AC_FLAGS} ${MATH_FLAGS} \ ${GENERIC_FLAGS} ${PROTO_FLAGS} ${MEM_DEBUG_FLAGS} \ -DTCL_SHLIB_EXT=\"${SHLIB_SUFFIX}\" @EXTRA_CC_SWITCHES@ TCLSH_OBJS = tclAppInit.o TCLTEST_OBJS = tclTestInit.o tclTest.o tclTestObj.o tclTestProcBodyObj.o \ tclThreadTest.o tclUnixTest.o XTTEST_OBJS = xtTestInit.o tclTest.o tclTestObj.o tclTestProcBodyObj.o \ tclThreadTest.o tclUnixTest.o tclXtNotify.o tclXtTest.o GENERIC_OBJS = regcomp.o regexec.o regfree.o regerror.o tclAlloc.o \ tclAsync.o tclBasic.o tclBinary.o \ tclCkalloc.o tclClock.o tclCmdAH.o tclCmdIL.o tclCmdMZ.o \ tclCompCmds.o tclCompExpr.o tclCompile.o tclDate.o tclEncoding.o \ tclEnv.o tclEvent.o tclExecute.o tclFCmd.o tclFileName.o tclGet.o \ tclHash.o tclHistory.o tclIndexObj.o tclInterp.o tclIO.o tclIOCmd.o \ tclIOGT.o tclIOSock.o tclIOUtil.o tclLink.o tclListObj.o \ tclLiteral.o tclLoad.o tclMain.o tclNamesp.o tclNotify.o \ tclObj.o tclPanic.o tclParse.o tclParseExpr.o tclPipe.o \ tclPkg.o tclPosixStr.o tclPreserve.o tclProc.o tclRegexp.o \ tclResolve.o tclResult.o tclScan.o tclStringObj.o tclThread.o \ tclThreadAlloc.o tclThreadJoin.o tclStubInit.o tclStubLib.o \ tclTimer.o tclUtf.o tclUtil.o tclVar.o STUB_LIB_OBJS = tclStubLib.o ${COMPAT_OBJS} MAC_OSX_OBJS = tclMacOSXBundle.o tclMacOSXNotify.o DTRACE_OBJ = tclDTrace.o TCL_OBJS = ${GENERIC_OBJS} ${UNIX_OBJS} ${NOTIFY_OBJS} ${COMPAT_OBJS} \ @DL_OBJS@ @PLAT_OBJS@ OBJS = ${TCL_OBJS} @DTRACE_OBJ@ TCL_DECLS = \ $(GENERIC_DIR)/tcl.decls \ $(GENERIC_DIR)/tclInt.decls GENERIC_HDRS = \ $(GENERIC_DIR)/tcl.h \ $(GENERIC_DIR)/tclDecls.h \ $(GENERIC_DIR)/tclInt.h \ $(GENERIC_DIR)/tclIntDecls.h \ $(GENERIC_DIR)/tclIntPlatDecls.h \ $(GENERIC_DIR)/tclPatch.h \ $(GENERIC_DIR)/tclPlatDecls.h \ $(GENERIC_DIR)/tclPort.h \ $(GENERIC_DIR)/tclRegexp.h GENERIC_SRCS = \ $(GENERIC_DIR)/regcomp.c \ $(GENERIC_DIR)/regexec.c \ $(GENERIC_DIR)/regfree.c \ $(GENERIC_DIR)/regerror.c \ $(GENERIC_DIR)/tclAlloc.c \ $(GENERIC_DIR)/tclAsync.c \ $(GENERIC_DIR)/tclBasic.c \ $(GENERIC_DIR)/tclBinary.c \ $(GENERIC_DIR)/tclCkalloc.c \ $(GENERIC_DIR)/tclClock.c \ $(GENERIC_DIR)/tclCmdAH.c \ $(GENERIC_DIR)/tclCmdIL.c \ $(GENERIC_DIR)/tclCmdMZ.c \ $(GENERIC_DIR)/tclCompCmds.c \ $(GENERIC_DIR)/tclCompExpr.c \ $(GENERIC_DIR)/tclCompile.c \ $(GENERIC_DIR)/tclDate.c \ $(GENERIC_DIR)/tclEncoding.c \ $(GENERIC_DIR)/tclEnv.c \ $(GENERIC_DIR)/tclEvent.c \ $(GENERIC_DIR)/tclExecute.c \ $(GENERIC_DIR)/tclFCmd.c \ $(GENERIC_DIR)/tclFileName.c \ $(GENERIC_DIR)/tclGet.c \ $(GENERIC_DIR)/tclHash.c \ $(GENERIC_DIR)/tclHistory.c \ $(GENERIC_DIR)/tclIndexObj.c \ $(GENERIC_DIR)/tclInterp.c \ $(GENERIC_DIR)/tclIO.c \ $(GENERIC_DIR)/tclIOCmd.c \ $(GENERIC_DIR)/tclIOGT.c \ $(GENERIC_DIR)/tclIOSock.c \ $(GENERIC_DIR)/tclIOUtil.c \ $(GENERIC_DIR)/tclLink.c \ $(GENERIC_DIR)/tclListObj.c \ $(GENERIC_DIR)/tclLiteral.c \ $(GENERIC_DIR)/tclLoad.c \ $(GENERIC_DIR)/tclMain.c \ $(GENERIC_DIR)/tclNamesp.c \ $(GENERIC_DIR)/tclNotify.c \ $(GENERIC_DIR)/tclObj.c \ $(GENERIC_DIR)/tclParse.c \ $(GENERIC_DIR)/tclParseExpr.c \ $(GENERIC_DIR)/tclPipe.c \ $(GENERIC_DIR)/tclPkg.c \ $(GENERIC_DIR)/tclPosixStr.c \ $(GENERIC_DIR)/tclPreserve.c \ $(GENERIC_DIR)/tclProc.c \ $(GENERIC_DIR)/tclRegexp.c \ $(GENERIC_DIR)/tclResolve.c \ $(GENERIC_DIR)/tclResult.c \ $(GENERIC_DIR)/tclScan.c \ $(GENERIC_DIR)/tclStubInit.c \ $(GENERIC_DIR)/tclStubLib.c \ $(GENERIC_DIR)/tclStringObj.c \ $(GENERIC_DIR)/tclTest.c \ $(GENERIC_DIR)/tclTestObj.c \ $(GENERIC_DIR)/tclTestProcBodyObj.c \ $(GENERIC_DIR)/tclThread.c \ $(GENERIC_DIR)/tclThreadAlloc.c \ $(GENERIC_DIR)/tclThreadJoin.c \ $(GENERIC_DIR)/tclTimer.c \ $(GENERIC_DIR)/tclUtil.c \ $(GENERIC_DIR)/tclVar.c STUB_SRCS = \ $(GENERIC_DIR)/tclStubLib.c UNIX_HDRS = \ $(UNIX_DIR)/tclUnixPort.h UNIX_SRCS = \ $(UNIX_DIR)/tclAppInit.c \ $(UNIX_DIR)/tclUnixChan.c \ $(UNIX_DIR)/tclUnixEvent.c \ $(UNIX_DIR)/tclUnixFCmd.c \ $(UNIX_DIR)/tclUnixFile.c \ $(UNIX_DIR)/tclUnixPipe.c \ $(UNIX_DIR)/tclUnixSock.c \ $(UNIX_DIR)/tclUnixTest.c \ $(UNIX_DIR)/tclUnixThrd.c \ $(UNIX_DIR)/tclUnixTime.c \ $(UNIX_DIR)/tclUnixInit.c \ $(UNIX_DIR)/tclUnixCompat.c NOTIFY_SRCS = \ $(UNIX_DIR)/tclUnixNotfy.c DL_SRCS = \ $(UNIX_DIR)/tclLoadAix.c \ $(UNIX_DIR)/tclLoadAout.c \ $(UNIX_DIR)/tclLoadDl.c \ $(UNIX_DIR)/tclLoadDl2.c \ $(UNIX_DIR)/tclLoadDld.c \ $(UNIX_DIR)/tclLoadDyld.c \ $(GENERIC_DIR)/tclLoadNone.c \ $(UNIX_DIR)/tclLoadOSF.c \ $(UNIX_DIR)/tclLoadShl.c MAC_OSX_SRCS = \ $(MAC_OSX_DIR)/tclMacOSXBundle.c \ $(MAC_OSX_DIR)/tclMacOSXNotify.c DTRACE_HDR = tclDTrace.h DTRACE_SRC = $(GENERIC_DIR)/tclDTrace.d # Note: don't include DL_SRCS or MAC_OSX_SRCS in SRCS: most of those # files won't compile on the current machine, and they will cause # problems for things like "make depend". SRCS = $(GENERIC_SRCS) $(UNIX_SRCS) $(NOTIFY_SRCS) $(STUB_SRCS) @PLAT_SRCS@ all: binaries libraries doc binaries: ${LIB_FILE} $(STUB_LIB_FILE) $(TCL_BUILD_EXP_FILE) tclsh libraries: doc: # The following target is configured by autoconf to generate either # a shared library or non-shared library for Tcl. ${LIB_FILE}: ${OBJS} ${STUB_LIB_FILE} rm -f $@ @MAKE_LIB@ ${STUB_LIB_FILE}: ${STUB_LIB_OBJS} rm -f $@ @MAKE_STUB_LIB@ # Make target which outputs the list of the .o contained in the Tcl lib # usefull to build a single big shared library containing Tcl and other # extensions. used for the Tcl Plugin. -- dl # The dependency on OBJS is not there because we just want the list # of objects here, not actually building them tclLibObjs: @echo ${OBJS} # This targets actually build the objects needed for the lib in the above # case objs: ${OBJS} tclsh: ${TCLSH_OBJS} ${TCL_LIB_FILE} ${CC} ${CFLAGS} ${LDFLAGS} ${TCLSH_OBJS} @TCL_BUILD_LIB_SPEC@ ${LIBS} @EXTRA_TCLSH_LIBS@ \ ${CC_SEARCH_FLAGS} -o tclsh # Resetting the LIB_RUNTIME_DIR below is required so that # the generated tcltest executable gets the build directory # burned into its ld search path. This keeps tcltest from # picking up an already installed version of the Tcl library. tcltest: ${TCLTEST_OBJS} ${TCL_LIB_FILE} ${BUILD_DLTEST} $(MAKE) tcltest-real LIB_RUNTIME_DIR=`pwd` tcltest-real: ${CC} ${CFLAGS} ${LDFLAGS} ${TCLTEST_OBJS} @TCL_BUILD_LIB_SPEC@ ${LIBS} @EXTRA_TCLSH_LIBS@ \ ${CC_SEARCH_FLAGS} -o tcltest # Note, in the target below TCL_LIBRARY needs to be set or else # "make test" won't work in the case where the compilation directory # isn't the same as the source directory. # Specifying TESTFLAGS on the command line is the standard way to pass # args to tcltest, ie: # % make test TESTFLAGS="-verbose bps -file fileName.test" test: tcltest @LD_LIBRARY_PATH_VAR@=`pwd`:$${@LD_LIBRARY_PATH_VAR@}; export @LD_LIBRARY_PATH_VAR@; \ TCL_LIBRARY="${TCL_BUILDTIME_LIBRARY}"; export TCL_LIBRARY; \ ./tcltest $(TOP_DIR)/tests/all.tcl $(TESTFLAGS) $(TCLTESTARGS) # Useful target to launch a built tcltest with the proper path,... runtest: tcltest @LD_LIBRARY_PATH_VAR@=`pwd`:$${@LD_LIBRARY_PATH_VAR@}; export @LD_LIBRARY_PATH_VAR@; \ TCL_LIBRARY="${TCL_BUILDTIME_LIBRARY}"; export TCL_LIBRARY; \ ./tcltest # Useful target for running the test suite with an unwritable current # directory... ro-test: tcltest @LD_LIBRARY_PATH_VAR@=`pwd`:$${@LD_LIBRARY_PATH_VAR@}; export @LD_LIBRARY_PATH_VAR@; \ TCL_LIBRARY="${TCL_BUILDTIME_LIBRARY}"; export TCL_LIBRARY; \ echo 'exec chmod -w .;package require tcltest;tcltest::temporaryDirectory /tmp;source ../tests/all.tcl;exec chmod +w .' | ./tcltest # This target can be used to run tclsh from the build directory # via `make shell SCRIPT=/tmp/foo.tcl` shell: tclsh @LD_LIBRARY_PATH_VAR@=`pwd`:$${@LD_LIBRARY_PATH_VAR@}; export @LD_LIBRARY_PATH_VAR@; \ TCL_LIBRARY="${TCL_BUILDTIME_LIBRARY}"; export TCL_LIBRARY; \ ./tclsh $(SCRIPT) # This target can be used to run tclsh inside either gdb or insight gdb: tclsh @echo "set env @LD_LIBRARY_PATH_VAR@=`pwd`:$${@LD_LIBRARY_PATH_VAR@}" > gdb.run @echo "set env TCL_LIBRARY=${TCL_BUILDTIME_LIBRARY}" >> gdb.run $(GDB) ./tclsh --command=gdb.run rm gdb.run # This target can be used to run tclsh inside ddd ddd: tclsh @echo "set env @LD_LIBRARY_PATH_VAR@=`pwd`:$${@LD_LIBRARY_PATH_VAR@}" > gdb.run @echo "set env TCL_LIBRARY=${TCL_BUILDTIME_LIBRARY}" >> gdb.run $(DDD) -command=gdb.run ./tclsh rm gdb.run VALGRINDARGS=--tool=memcheck --num-callers=8 --leak-resolution=high --leak-check=yes --show-reachable=yes -v valgrind: tclsh tcltest @LD_LIBRARY_PATH_VAR@=`pwd`:$${@LD_LIBRARY_PATH_VAR@}; export @LD_LIBRARY_PATH_VAR@; \ TCL_LIBRARY="${TCL_BUILDTIME_LIBRARY}"; export TCL_LIBRARY; \ valgrind $(VALGRINDARGS) ./tcltest $(TOP_DIR)/tests/all.tcl -singleproc 1 $(TESTFLAGS) $(TCLTESTARGS) valgrindshell: tclsh @LD_LIBRARY_PATH_VAR@=`pwd`:$${@LD_LIBRARY_PATH_VAR@}; export @LD_LIBRARY_PATH_VAR@; \ TCL_LIBRARY="${TCL_BUILDTIME_LIBRARY}"; export TCL_LIBRARY; \ valgrind $(VALGRINDARGS) ./tclsh $(SCRIPT) # The following target outputs the name of the top-level source directory # for Tcl (it is used by Tk's configure script, for example). The # .NO_PARALLEL line is needed to avoid problems under Sun's "pmake". # Note: this target is now obsolete (use the autoconf variable # TCL_SRC_DIR from tclConfig.sh instead). .NO_PARALLEL: topDirName topDirName: @cd $(TOP_DIR); pwd # The following target generates the file generic/tclDate.c # from the yacc grammar found in generic/tclGetDate.y. This is # only run by hand as yacc is not available in all environments. # The name of the .c file is different than the name of the .y file # so that make doesn't try to automatically regenerate the .c file. gendate: yacc -l $(GENERIC_DIR)/tclGetDate.y sed -e 's/yy/TclDate/g' -e '/^#include /d' \ -e 's?SCCSID?RCS: @(#) ?' \ -e '/#ifdef __STDC__/,/#endif/d' -e '/TclDateerrlab:/d' \ -e '/TclDatenewstate:/d' -e '/#pragma/d' \ -e '/#include /d' -e 's/const /CONST /g' \ $(GENERIC_DIR)/tclDate.c rm y.tab.c # The following target generates the shared libraries in dltest/ that # are used for testing; they are included as part of the "tcltest" # target (via the BUILD_DLTEST variable) if dynamic loading is supported # on this platform. The Makefile in the dltest subdirectory creates # the dltest.marker file in this directory after a successful build. dltest.marker: ${STUB_LIB_FILE} cd dltest ; $(MAKE) INSTALL_TARGETS = install-binaries install-libraries install-doc @EXTRA_INSTALL@ install: $(INSTALL_TARGETS) install-strip: $(MAKE) $(INSTALL_TARGETS) \ INSTALL_PROGRAM="$(INSTALL_PROGRAM) ${INSTALL_STRIP_PROGRAM}" \ INSTALL_LIBRARY="$(INSTALL_LIBRARY) ${INSTALL_STRIP_LIBRARY}" # Note: before running ranlib below, must cd to target directory because # some ranlibs write to current directory, and this might not always be # possible (e.g. if installing as root). install-binaries: binaries @for i in "$(LIB_INSTALL_DIR)" "$(BIN_INSTALL_DIR)" ; \ do \ if [ ! -d $$i ] ; then \ echo "Making directory $$i"; \ mkdir -p $$i; \ chmod 755 $$i; \ else true; \ fi; \ done; @if test ! -x $(SRC_DIR)/install-sh; then \ chmod +x $(SRC_DIR)/install-sh; \ fi @echo "Installing $(LIB_FILE) to $(DLL_INSTALL_DIR)/" @@INSTALL_LIB@ @chmod 555 $(DLL_INSTALL_DIR)/$(LIB_FILE) @if test "$(TCL_BUILD_EXP_FILE)" != ""; then \ echo "Installing $(TCL_EXP_FILE) to $(LIB_INSTALL_DIR)/"; \ $(INSTALL_DATA) $(TCL_BUILD_EXP_FILE) \ $(LIB_INSTALL_DIR)/$(TCL_EXP_FILE); \ fi @echo "Installing tclsh as $(BIN_INSTALL_DIR)/tclsh$(VERSION)" @$(INSTALL_PROGRAM) tclsh $(BIN_INSTALL_DIR)/tclsh$(VERSION) @echo "Installing tclConfig.sh to $(LIB_INSTALL_DIR)/" @$(INSTALL_DATA) tclConfig.sh $(LIB_INSTALL_DIR)/tclConfig.sh @if test "$(STUB_LIB_FILE)" != "" ; then \ echo "Installing $(STUB_LIB_FILE) to $(LIB_INSTALL_DIR)/"; \ @INSTALL_STUB_LIB@ ; \ fi @if test "x$(DLL_INSTALL_DIR)" = "x$(BIN_INSTALL_DIR)"; then\ for i in dde1.3 reg1.2; do \ if [ ! -d $(LIB_INSTALL_DIR)/$$i ] ; then \ echo "Making directory $(LIB_INSTALL_DIR)/$$i";\ mkdir -p $(LIB_INSTALL_DIR)/$$i;\ chmod 755 $(LIB_INSTALL_DIR)/$$i;\ else true;\ fi;\ done;\ echo "Installing tcldde13.dll";\ $(INSTALL_DATA) "$(TOP_DIR)/library/dde/pkgIndex.tcl" "$(LIB_INSTALL_DIR)/dde1.3";\ $(INSTALL_LIBRARY) "$(TOP_DIR)/win/tcldde13.dll" "$(LIB_INSTALL_DIR)/dde1.3";\ chmod 555 "$(LIB_INSTALL_DIR)/dde1.3/tcldde13.dll";\ echo "Installing tclreg12.dll";\ $(INSTALL_DATA) "$(TOP_DIR)/library/reg/pkgIndex.tcl" "$(LIB_INSTALL_DIR)/reg1.2";\ $(INSTALL_LIBRARY) "$(TOP_DIR)/win/tclreg12.dll" "$(LIB_INSTALL_DIR)/reg1.2";\ chmod 555 "$(LIB_INSTALL_DIR)/reg1.2/tclreg12.dll";\ fi @EXTRA_INSTALL_BINARIES@ install-libraries: libraries @for i in "$(INCLUDE_INSTALL_DIR)" "$(SCRIPT_INSTALL_DIR)"; \ do \ if [ ! -d $$i ] ; then \ echo "Making directory $$i"; \ mkdir -p $$i; \ chmod 755 $$i; \ else true; \ fi; \ done; @for i in platform http2.5 http1.0 opt0.4 encoding msgcat1.3 tcltest2.2; \ do \ if [ ! -d $(SCRIPT_INSTALL_DIR)/$$i ] ; then \ echo "Making directory $(SCRIPT_INSTALL_DIR)/$$i"; \ mkdir -p $(SCRIPT_INSTALL_DIR)/$$i; \ chmod 755 $(SCRIPT_INSTALL_DIR)/$$i; \ else true; \ fi; \ done; @if test ! -x $(SRC_DIR)/install-sh; then \ chmod +x $(SRC_DIR)/install-sh; \ fi @echo "Installing header files"; @for i in $(GENERIC_DIR)/tcl.h $(GENERIC_DIR)/tclDecls.h \ $(GENERIC_DIR)/tclPlatDecls.h; \ do \ $(INSTALL_DATA) $$i $(INCLUDE_INSTALL_DIR); \ done; @echo "Installing library files to $(SCRIPT_INSTALL_DIR)"; @for i in $(TOP_DIR)/library/*.tcl $(TOP_DIR)/library/tclIndex \ $(UNIX_DIR)/tclAppInit.c $(UNIX_DIR)/ldAix @DTRACE_SRC@; \ do \ $(INSTALL_DATA) $$i $(SCRIPT_INSTALL_DIR); \ done; @echo "Installing library platform directory"; @for j in $(TOP_DIR)/library/platform/*.tcl ; \ do \ $(INSTALL_DATA) $$j $(SCRIPT_INSTALL_DIR)/platform; \ done; @echo "Installing library http1.0 directory"; @for j in $(TOP_DIR)/library/http1.0/*.tcl ; \ do \ $(INSTALL_DATA) $$j $(SCRIPT_INSTALL_DIR)/http1.0; \ done; @echo "Installing library http2.5 directory"; @for j in $(TOP_DIR)/library/http/*.tcl ; \ do \ $(INSTALL_DATA) $$j $(SCRIPT_INSTALL_DIR)/http2.5; \ done; @echo "Installing library opt0.4 directory"; @for j in $(TOP_DIR)/library/opt/*.tcl ; \ do \ $(INSTALL_DATA) $$j $(SCRIPT_INSTALL_DIR)/opt0.4; \ done; @echo "Installing library msgcat1.3 directory"; @for j in $(TOP_DIR)/library/msgcat/*.tcl ; \ do \ $(INSTALL_DATA) $$j $(SCRIPT_INSTALL_DIR)/msgcat1.3; \ done; @echo "Installing library tcltest2.2 directory"; @for j in $(TOP_DIR)/library/tcltest/*.tcl ; \ do \ $(INSTALL_DATA) $$j $(SCRIPT_INSTALL_DIR)/tcltest2.2; \ done; @echo "Installing library encoding directory"; @for i in $(TOP_DIR)/library/encoding/*.enc ; do \ $(INSTALL_DATA) $$i $(SCRIPT_INSTALL_DIR)/encoding; \ done; install-doc: doc @if test ! -x $(UNIX_DIR)/installManPage; then \ chmod +x $(UNIX_DIR)/installManPage; \ fi @for i in $(MAN_INSTALL_DIR) $(MAN1_INSTALL_DIR) $(MAN3_INSTALL_DIR) $(MANN_INSTALL_DIR) ; \ do \ if [ ! -d $$i ] ; then \ echo "Making directory $$i"; \ mkdir -p $$i; \ chmod 755 $$i; \ else true; \ fi; \ done; @echo "Installing and cross-linking top-level (.1) docs"; @for i in $(TOP_DIR)/doc/*.1; do \ $(UNIX_DIR)/installManPage $(MAN_FLAGS) $$i $(MAN1_INSTALL_DIR); \ done @echo "Installing and cross-linking C API (.3) docs"; @for i in $(TOP_DIR)/doc/*.3; do \ $(UNIX_DIR)/installManPage $(MAN_FLAGS) $$i $(MAN3_INSTALL_DIR); \ done @echo "Installing and cross-linking command (.n) docs"; @for i in $(TOP_DIR)/doc/*.n; do \ $(UNIX_DIR)/installManPage $(MAN_FLAGS) $$i $(MANN_INSTALL_DIR); \ done # Optional target to install private headers install-private-headers: libraries @for i in $(PRIVATE_INCLUDE_INSTALL_DIR); \ do \ if [ ! -d $$i ] ; then \ echo "Making directory $$i"; \ mkdir -p $$i; \ chmod 755 $$i; \ else true; \ fi; \ done; @if test ! -x $(SRC_DIR)/install-sh; then \ chmod +x $(SRC_DIR)/install-sh; \ fi @echo "Installing private header files"; @for i in $(GENERIC_DIR)/tclInt.h $(GENERIC_DIR)/tclIntDecls.h \ $(GENERIC_DIR)/tclIntPlatDecls.h \ $(UNIX_DIR)/tclUnixPort.h $(GENERIC_DIR)/tclMath.h; \ do \ $(INSTALL_DATA) $$i $(PRIVATE_INCLUDE_INSTALL_DIR); \ done; @sed -e 's#\.\./unix/##' $(GENERIC_DIR)/tclPort.h > tclPort.h; \ $(INSTALL_DATA) tclPort.h $(PRIVATE_INCLUDE_INSTALL_DIR); \ rm -f tclPort.h Makefile: $(UNIX_DIR)/Makefile.in $(DLTEST_DIR)/Makefile.in $(SHELL) config.status clean: rm -f *.a *.o libtcl* core errs *~ \#* TAGS *.E a.out \ errors tclsh tcltest lib.exp Tcl @DTRACE_HDR@ cd dltest ; $(MAKE) clean distclean: clean rm -rf Makefile config.status config.cache config.log tclConfig.sh \ $(PACKAGE).* prototype *.plist Tcl.framework cd dltest ; $(MAKE) distclean depend: makedepend -- $(DEPEND_SWITCHES) -- $(SRCS) # Test binaries. The rules for tclTestInit.o and xtTestInit.o are # complicated because they are compiled from tclAppInit.c. Can't use # the "-o" option because this doesn't work on some strange compilers # (e.g. UnixWare). # To enable concurrent parallel make of tclsh and tcltest resp xttest, these # targets have to depend on tclsh, this ensures that linking of tclsh with # tclAppInit.o does not execute concurrently with the renaming and recompiling # of that same object file in the targets below. tclTestInit.o: $(UNIX_DIR)/tclAppInit.c tclsh @if test -f tclAppInit.o ; then \ rm -f tclAppInit.sav; \ mv tclAppInit.o tclAppInit.sav; \ fi; $(CC) -c $(APP_CC_SWITCHES) \ -DTCL_BUILDTIME_LIBRARY="\"${TCL_BUILDTIME_LIBRARY}\"" \ -DTCL_TEST $(UNIX_DIR)/tclAppInit.c rm -f tclTestInit.o mv tclAppInit.o tclTestInit.o @if test -f tclAppInit.sav ; then \ mv tclAppInit.sav tclAppInit.o; \ fi; xtTestInit.o: $(UNIX_DIR)/tclAppInit.c tclsh @if test -f tclAppInit.o ; then \ rm -f tclAppInit.sav; \ mv tclAppInit.o tclAppInit.sav; \ fi; $(CC) -c $(APP_CC_SWITCHES) \ -DTCL_BUILDTIME_LIBRARY="\"${TCL_BUILDTIME_LIBRARY}\"" \ -DTCL_TEST -DTCL_XT_TEST $(UNIX_DIR)/tclAppInit.c rm -f xtTestInit.o mv tclAppInit.o xtTestInit.o @if test -f tclAppInit.sav ; then \ mv tclAppInit.sav tclAppInit.o; \ fi; # Object files used on all Unix systems: REGHDRS=$(GENERIC_DIR)/regex.h $(GENERIC_DIR)/regguts.h \ $(GENERIC_DIR)/regcustom.h regcomp.o: $(REGHDRS) $(GENERIC_DIR)/regcomp.c $(GENERIC_DIR)/regc_lex.c \ $(GENERIC_DIR)/regc_color.c $(GENERIC_DIR)/regc_locale.c \ $(GENERIC_DIR)/regc_nfa.c $(GENERIC_DIR)/regc_cvec.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/regcomp.c regexec.o: $(REGHDRS) $(GENERIC_DIR)/regexec.c $(GENERIC_DIR)/rege_dfa.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/regexec.c regfree.o: $(REGHDRS) $(GENERIC_DIR)/regfree.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/regfree.c regerror.o: $(REGHDRS) $(GENERIC_DIR)/regerrs.h $(GENERIC_DIR)/regerror.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/regerror.c tclAppInit.o: $(UNIX_DIR)/tclAppInit.c $(CC) -c $(APP_CC_SWITCHES) $(UNIX_DIR)/tclAppInit.c tclAlloc.o: $(GENERIC_DIR)/tclAlloc.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclAlloc.c tclAsync.o: $(GENERIC_DIR)/tclAsync.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclAsync.c tclBasic.o: $(GENERIC_DIR)/tclBasic.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclBasic.c tclBinary.o: $(GENERIC_DIR)/tclBinary.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclBinary.c tclCkalloc.o: $(GENERIC_DIR)/tclCkalloc.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclCkalloc.c tclClock.o: $(GENERIC_DIR)/tclClock.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclClock.c tclCmdAH.o: $(GENERIC_DIR)/tclCmdAH.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclCmdAH.c tclCmdIL.o: $(GENERIC_DIR)/tclCmdIL.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclCmdIL.c tclCmdMZ.o: $(GENERIC_DIR)/tclCmdMZ.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclCmdMZ.c tclDate.o: $(GENERIC_DIR)/tclDate.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclDate.c tclCompCmds.o: $(GENERIC_DIR)/tclCompCmds.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclCompCmds.c tclCompExpr.o: $(GENERIC_DIR)/tclCompExpr.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclCompExpr.c tclCompile.o: $(GENERIC_DIR)/tclCompile.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclCompile.c tclEncoding.o: $(GENERIC_DIR)/tclEncoding.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclEncoding.c tclEnv.o: $(GENERIC_DIR)/tclEnv.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclEnv.c tclEvent.o: $(GENERIC_DIR)/tclEvent.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclEvent.c tclExecute.o: $(GENERIC_DIR)/tclExecute.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclExecute.c tclFCmd.o: $(GENERIC_DIR)/tclFCmd.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclFCmd.c tclFileName.o: $(GENERIC_DIR)/tclFileName.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclFileName.c tclGet.o: $(GENERIC_DIR)/tclGet.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclGet.c tclHash.o: $(GENERIC_DIR)/tclHash.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclHash.c tclHistory.o: $(GENERIC_DIR)/tclHistory.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclHistory.c tclIndexObj.o: $(GENERIC_DIR)/tclIndexObj.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclIndexObj.c tclInterp.o: $(GENERIC_DIR)/tclInterp.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclInterp.c tclIO.o: $(GENERIC_DIR)/tclIO.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclIO.c tclIOCmd.o: $(GENERIC_DIR)/tclIOCmd.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclIOCmd.c tclIOGT.o: $(GENERIC_DIR)/tclIOGT.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclIOGT.c tclIOSock.o: $(GENERIC_DIR)/tclIOSock.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclIOSock.c tclIOUtil.o: $(GENERIC_DIR)/tclIOUtil.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclIOUtil.c tclLink.o: $(GENERIC_DIR)/tclLink.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclLink.c tclListObj.o: $(GENERIC_DIR)/tclListObj.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclListObj.c tclLiteral.o: $(GENERIC_DIR)/tclLiteral.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclLiteral.c tclObj.o: $(GENERIC_DIR)/tclObj.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclObj.c tclLoad.o: $(GENERIC_DIR)/tclLoad.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclLoad.c tclLoadAix.o: $(UNIX_DIR)/tclLoadAix.c $(CC) -c $(CC_SWITCHES) $(UNIX_DIR)/tclLoadAix.c tclLoadAout.o: $(UNIX_DIR)/tclLoadAout.c $(CC) -c $(CC_SWITCHES) $(UNIX_DIR)/tclLoadAout.c tclLoadDl.o: $(UNIX_DIR)/tclLoadDl.c $(CC) -c $(CC_SWITCHES) $(UNIX_DIR)/tclLoadDl.c tclLoadDl2.o: $(UNIX_DIR)/tclLoadDl2.c $(CC) -c $(CC_SWITCHES) $(UNIX_DIR)/tclLoadDl2.c tclLoadDld.o: $(UNIX_DIR)/tclLoadDld.c $(CC) -c $(CC_SWITCHES) $(UNIX_DIR)/tclLoadDld.c tclLoadDyld.o: $(UNIX_DIR)/tclLoadDyld.c $(CC) -c $(CC_SWITCHES) $(UNIX_DIR)/tclLoadDyld.c tclLoadNone.o: $(GENERIC_DIR)/tclLoadNone.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclLoadNone.c tclLoadOSF.o: $(UNIX_DIR)/tclLoadOSF.c $(CC) -c $(CC_SWITCHES) $(UNIX_DIR)/tclLoadOSF.c tclLoadShl.o: $(UNIX_DIR)/tclLoadShl.c $(CC) -c $(CC_SWITCHES) $(UNIX_DIR)/tclLoadShl.c tclMain.o: $(GENERIC_DIR)/tclMain.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclMain.c tclNamesp.o: $(GENERIC_DIR)/tclNamesp.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclNamesp.c tclNotify.o: $(GENERIC_DIR)/tclNotify.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclNotify.c tclParse.o: $(GENERIC_DIR)/tclParse.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclParse.c tclParseExpr.o: $(GENERIC_DIR)/tclParseExpr.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclParseExpr.c tclPanic.o: $(GENERIC_DIR)/tclPanic.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclPanic.c tclPipe.o: $(GENERIC_DIR)/tclPipe.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclPipe.c tclPkg.o: $(GENERIC_DIR)/tclPkg.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclPkg.c tclPosixStr.o: $(GENERIC_DIR)/tclPosixStr.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclPosixStr.c tclPreserve.o: $(GENERIC_DIR)/tclPreserve.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclPreserve.c tclProc.o: $(GENERIC_DIR)/tclProc.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclProc.c tclRegexp.o: $(GENERIC_DIR)/tclRegexp.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclRegexp.c tclResolve.o: $(GENERIC_DIR)/tclResolve.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclResolve.c tclResult.o: $(GENERIC_DIR)/tclResult.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclResult.c tclScan.o: $(GENERIC_DIR)/tclScan.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclScan.c tclStringObj.o: $(GENERIC_DIR)/tclStringObj.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclStringObj.c tclStubInit.o: $(GENERIC_DIR)/tclStubInit.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclStubInit.c tclUtil.o: $(GENERIC_DIR)/tclUtil.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclUtil.c tclUtf.o: $(GENERIC_DIR)/tclUtf.c $(GENERIC_DIR)/tclUniData.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclUtf.c tclVar.o: $(GENERIC_DIR)/tclVar.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclVar.c tclTest.o: $(GENERIC_DIR)/tclTest.c $(CC) -c $(APP_CC_SWITCHES) $(GENERIC_DIR)/tclTest.c tclTestObj.o: $(GENERIC_DIR)/tclTestObj.c $(CC) -c $(APP_CC_SWITCHES) $(GENERIC_DIR)/tclTestObj.c tclTestProcBodyObj.o: $(GENERIC_DIR)/tclTestProcBodyObj.c $(CC) -c $(APP_CC_SWITCHES) $(GENERIC_DIR)/tclTestProcBodyObj.c tclTimer.o: $(GENERIC_DIR)/tclTimer.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclTimer.c tclThread.o: $(GENERIC_DIR)/tclThread.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclThread.c tclThreadAlloc.o: $(GENERIC_DIR)/tclThreadAlloc.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclThreadAlloc.c tclThreadJoin.o: $(GENERIC_DIR)/tclThreadJoin.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclThreadJoin.c tclThreadTest.o: $(GENERIC_DIR)/tclThreadTest.c $(CC) -c $(APP_CC_SWITCHES) $(GENERIC_DIR)/tclThreadTest.c tclUnixChan.o: $(UNIX_DIR)/tclUnixChan.c $(CC) -c $(CC_SWITCHES) $(UNIX_DIR)/tclUnixChan.c tclUnixEvent.o: $(UNIX_DIR)/tclUnixEvent.c $(CC) -c $(CC_SWITCHES) $(UNIX_DIR)/tclUnixEvent.c tclUnixFCmd.o: $(UNIX_DIR)/tclUnixFCmd.c $(CC) -c $(CC_SWITCHES) $(UNIX_DIR)/tclUnixFCmd.c tclUnixFile.o: $(UNIX_DIR)/tclUnixFile.c $(CC) -c $(CC_SWITCHES) $(UNIX_DIR)/tclUnixFile.c tclUnixNotfy.o: $(UNIX_DIR)/tclUnixNotfy.c $(CC) -c $(CC_SWITCHES) $(UNIX_DIR)/tclUnixNotfy.c tclUnixPipe.o: $(UNIX_DIR)/tclUnixPipe.c $(CC) -c $(CC_SWITCHES) $(UNIX_DIR)/tclUnixPipe.c tclUnixSock.o: $(UNIX_DIR)/tclUnixSock.c $(CC) -c $(CC_SWITCHES) $(UNIX_DIR)/tclUnixSock.c tclUnixTest.o: $(UNIX_DIR)/tclUnixTest.c $(CC) -c $(APP_CC_SWITCHES) $(UNIX_DIR)/tclUnixTest.c tclUnixThrd.o: $(UNIX_DIR)/tclUnixThrd.c $(CC) -c $(CC_SWITCHES) $(UNIX_DIR)/tclUnixThrd.c tclUnixTime.o: $(UNIX_DIR)/tclUnixTime.c $(CC) -c $(CC_SWITCHES) $(UNIX_DIR)/tclUnixTime.c tclUnixInit.o: $(UNIX_DIR)/tclUnixInit.c $(GENERIC_DIR)/tclInitScript.h tclConfig.sh $(CC) -c $(CC_SWITCHES) -DTCL_LIBRARY=\"${TCL_LIBRARY}\" \ -DTCL_PACKAGE_PATH="\"${TCL_PACKAGE_PATH}\"" \ $(UNIX_DIR)/tclUnixInit.c tclUnixCompat.o: $(UNIX_DIR)/tclUnixCompat.c $(CC) -c $(CC_SWITCHES) $(UNIX_DIR)/tclUnixCompat.c # The following are Mac OS X only sources: tclMacOSXBundle.o: $(MAC_OSX_DIR)/tclMacOSXBundle.c $(CC) -c $(CC_SWITCHES) $(MAC_OSX_DIR)/tclMacOSXBundle.c tclMacOSXNotify.o: $(MAC_OSX_DIR)/tclMacOSXNotify.c $(CC) -c $(CC_SWITCHES) $(MAC_OSX_DIR)/tclMacOSXNotify.c # The following is a CYGWIN only source: tclWinError.o: $(TOP_DIR)/win/tclWinError.c $(CC) -c $(CC_SWITCHES) $(TOP_DIR)/win/tclWinError.c # DTrace support $(TCL_OBJS) $(STUB_LIB_OBJS) $(TCLSH_OBJS) $(TCLTEST_OBJS) $(XTTEST_OBJS): @DTRACE_HDR@ $(DTRACE_HDR): $(DTRACE_SRC) $(DTRACE) -h $(DTRACE_SWITCHES) -o $@ -s $(DTRACE_SRC) $(DTRACE_OBJ): $(DTRACE_SRC) $(TCL_OBJS) $(DTRACE) -G $(DTRACE_SWITCHES) -o $@ -s $(DTRACE_SRC) $(TCL_OBJS) # The following targets are not completely general. They are provide # purely for documentation purposes so people who are interested in # the Xt based notifier can modify them to suit their own installation. xttest: ${XTTEST_OBJS} ${GENERIC_OBJS} ${UNIX_OBJS} ${COMPAT_OBJS} \ @DL_OBJS@ ${BUILD_DLTEST} ${CC} ${XTTEST_OBJS} ${GENERIC_OBJS} ${UNIX_OBJS} ${COMPAT_OBJS} \ @DL_OBJS@ @TCL_BUILD_LIB_SPEC@ ${LIBS} \ ${CC_SEARCH_FLAGS} -L/usr/openwin/lib -lXt -o xttest tclXtNotify.o: $(UNIX_DIR)/tclXtNotify.c $(CC) -c $(APP_CC_SWITCHES) -I/usr/openwin/include \ $(UNIX_DIR)/tclXtNotify.c tclXtTest.o: $(UNIX_DIR)/tclXtTest.c $(CC) -c $(APP_CC_SWITCHES) -I/usr/openwin/include \ $(UNIX_DIR)/tclXtTest.c # compat binaries, these must be compiled for use in a shared library # even though they may be placed in a static executable or library. Since # they are included in both the tcl library and the stub library, they # need to be relocatable. fixstrtod.o: $(COMPAT_DIR)/fixstrtod.c $(CC) -c $(STUB_CC_SWITCHES) $(COMPAT_DIR)/fixstrtod.c opendir.o: $(COMPAT_DIR)/opendir.c $(CC) -c $(STUB_CC_SWITCHES) $(COMPAT_DIR)/opendir.c memcmp.o: $(COMPAT_DIR)/memcmp.c $(CC) -c $(STUB_CC_SWITCHES) $(COMPAT_DIR)/memcmp.c strncasecmp.o: $(COMPAT_DIR)/strncasecmp.c $(CC) -c $(STUB_CC_SWITCHES) $(COMPAT_DIR)/strncasecmp.c strstr.o: $(COMPAT_DIR)/strstr.c $(CC) -c $(STUB_CC_SWITCHES) $(COMPAT_DIR)/strstr.c strtod.o: $(COMPAT_DIR)/strtod.c $(CC) -c $(STUB_CC_SWITCHES) $(COMPAT_DIR)/strtod.c strtol.o: $(COMPAT_DIR)/strtol.c $(CC) -c $(STUB_CC_SWITCHES) $(COMPAT_DIR)/strtol.c strtoll.o: $(COMPAT_DIR)/strtoll.c $(CC) -c $(STUB_CC_SWITCHES) $(COMPAT_DIR)/strtoll.c strtoul.o: $(COMPAT_DIR)/strtoul.c $(CC) -c $(STUB_CC_SWITCHES) $(COMPAT_DIR)/strtoul.c strtoull.o: $(COMPAT_DIR)/strtoull.c $(CC) -c $(STUB_CC_SWITCHES) $(COMPAT_DIR)/strtoull.c tmpnam.o: $(COMPAT_DIR)/tmpnam.c $(CC) -c $(STUB_CC_SWITCHES) $(COMPAT_DIR)/tmpnam.c waitpid.o: $(COMPAT_DIR)/waitpid.c $(CC) -c $(STUB_CC_SWITCHES) $(COMPAT_DIR)/waitpid.c # Stub library binaries, these must be compiled for use in a shared library # even though they will be placed in a static archive tclStubLib.o: $(GENERIC_DIR)/tclStubLib.c $(CC) -c $(STUB_CC_SWITCHES) $(GENERIC_DIR)/tclStubLib.c .c.o: $(CC) -c $(CC_SWITCHES) $< # # Target to regenerate header files and stub files from the *.decls tables. # $(GENERIC_DIR)/tclStubInit.c: $(GENERIC_DIR)/tcl.decls \ $(GENERIC_DIR)/tclInt.decls @echo "Warning: tclStubInit.c may be out of date." @echo "Developers may want to run \"make genstubs\" to regenerate." @echo "This warning can be safely ignored, do not report as a bug!" genstubs: $(TCL_EXE) $(TOOL_DIR)/genStubs.tcl $(GENERIC_DIR) \ $(GENERIC_DIR)/tcl.decls $(GENERIC_DIR)/tclInt.decls # # Target to check that all exported functions have an entry in the stubs # tables. # checkstubs: $(TCL_LIB_FILE) -@for i in `nm -p $(TCL_LIB_FILE) \ | awk '$$2 ~ /^[TDBCS]$$/ { sub("^_", "", $$3); print $$3 }' \ | sort -n`; do \ match=0; \ for j in $(TCL_DECLS); do \ if [ `grep -c "$$i *(" $$j` -gt 0 ]; then \ match=1; \ fi; \ done; \ if [ $$match -eq 0 ]; then echo $$i; fi \ done # # Target to check that all public APIs which are not command # implementations have an entry in section three of the distributed # manpages. # checkdoc: $(TCL_LIB_FILE) -@for i in `nm -p $(TCL_LIB_FILE) | awk '$$3 ~ /Tcl_/ { print $$3 }' \ | grep -v 'Cmd$$' | sort -n`; do \ match=0; \ for j in $(TOP_DIR)/doc/*.3; do \ if [ `grep '\-' $$j | grep -c $$i` -gt 0 ]; then \ match=1; \ fi; \ done; \ if [ $$match -eq 0 ]; then echo $$i; fi \ done # # Target to check for proper usage of UCHAR macro. # checkuchar: -egrep isalnum\|isalpha\|iscntrl\|isdigit\|islower\|isprint\|ispunct\|isspace\|isupper\|isxdigit\|toupper\|tolower $(SRCS) | grep -v UCHAR # # Target to make sure that only symbols with "Tcl" prefixes are # exported. # checkexports: $(TCL_LIB_FILE) -@nm -p $(TCL_LIB_FILE) \ | awk '$$2 ~ /^[TDBCS]$$/ { sub("^_", "", $$3); print $$3 }' \ | sort -n | grep -E -v '^[Tt]cl' || true # # Target to create a Tcl RPM for Linux. Requires that you be on a Linux # system. # rpm: all /bin/rpm rm -f THIS.TCL.SPEC echo "%define _builddir `pwd`" > THIS.TCL.SPEC echo "%define _rpmdir `pwd`/RPMS" >> THIS.TCL.SPEC cat tcl.spec >> THIS.TCL.SPEC mkdir -p RPMS/i386 rpm -bb THIS.TCL.SPEC mv RPMS/i386/*.rpm . rm -rf RPMS THIS.TCL.SPEC # # Target to create a proper Tcl distribution from information in the # master source directory. DISTDIR must be defined to indicate where # to put the distribution. DISTDIR must be an absolute path name. # DISTROOT = /tmp/dist DISTNAME = tcl${VERSION}${PATCH_LEVEL} ZIPNAME = tcl${MAJOR_VERSION}${MINOR_VERSION}${PATCH_LEVEL}-src.zip DISTDIR = $(DISTROOT)/$(DISTNAME) dist: rm -rf $(DISTDIR) mkdir -p $(DISTDIR)/unix cp -p $(UNIX_DIR)/*.c $(UNIX_DIR)/*.h $(DISTDIR)/unix cp $(UNIX_DIR)/Makefile.in $(DISTDIR)/unix chmod 664 $(DISTDIR)/unix/Makefile.in cp $(UNIX_DIR)/configure $(UNIX_DIR)/configure.in \ $(UNIX_DIR)/tcl.m4 $(UNIX_DIR)/aclocal.m4 \ $(UNIX_DIR)/tclConfig.sh.in $(UNIX_DIR)/install-sh \ $(UNIX_DIR)/README $(UNIX_DIR)/ldAix $(UNIX_DIR)/tcl.spec \ $(UNIX_DIR)/installManPage \ $(DISTDIR)/unix chmod 775 $(DISTDIR)/unix/configure $(DISTDIR)/unix/configure.in chmod 775 $(DISTDIR)/unix/ldAix chmod +x $(DISTDIR)/unix/install-sh mkdir $(DISTDIR)/generic cp -p $(GENERIC_DIR)/*.[cdh] $(DISTDIR)/generic cp -p $(GENERIC_DIR)/*.decls $(DISTDIR)/generic cp -p $(GENERIC_DIR)/README $(DISTDIR)/generic cp -p $(GENERIC_DIR)/tclGetDate.y $(DISTDIR)/generic cp -p $(TOP_DIR)/changes $(TOP_DIR)/ChangeLog $(TOP_DIR)/README* \ $(TOP_DIR)/ChangeLog.[12]??? $(TOP_DIR)/license.terms \ $(DISTDIR) mkdir $(DISTDIR)/library cp -p $(TOP_DIR)/license.terms $(TOP_DIR)/library/*.tcl \ $(TOP_DIR)/library/tclIndex $(DISTDIR)/library for i in http1.0 http opt msgcat reg dde tcltest platform; \ do \ mkdir $(DISTDIR)/library/$$i ;\ cp -p $(TOP_DIR)/library/$$i/*.tcl $(DISTDIR)/library/$$i; \ done; mkdir $(DISTDIR)/library/encoding cp -p $(TOP_DIR)/library/encoding/*.enc $(DISTDIR)/library/encoding mkdir $(DISTDIR)/doc cp -p $(TOP_DIR)/license.terms $(TOP_DIR)/doc/*.[13n] \ $(TOP_DIR)/doc/man.macros $(DISTDIR)/doc mkdir $(DISTDIR)/compat cp -p $(TOP_DIR)/license.terms $(COMPAT_DIR)/*.c \ $(COMPAT_DIR)/*.h $(COMPAT_DIR)/README \ $(DISTDIR)/compat mkdir $(DISTDIR)/tests cp -p $(TOP_DIR)/license.terms $(DISTDIR)/tests cp -p $(TOP_DIR)/tests/*.test $(TOP_DIR)/tests/README \ $(TOP_DIR)/tests/httpd $(TOP_DIR)/tests/*.tcl \ $(DISTDIR)/tests mkdir $(DISTDIR)/win cp $(TOP_DIR)/win/Makefile.in $(DISTDIR)/win cp $(TOP_DIR)/win/configure.in $(TOP_DIR)/win/configure \ $(TOP_DIR)/win/tclConfig.sh.in \ $(TOP_DIR)/win/tcl.m4 $(TOP_DIR)/win/aclocal.m4 \ $(DISTDIR)/win cp -p $(TOP_DIR)/win/*.c $(TOP_DIR)/win/*.h \ $(TOP_DIR)/win/*.ico $(TOP_DIR)/win/*.rc \ $(DISTDIR)/win cp -p $(TOP_DIR)/win/*.bat $(DISTDIR)/win $(TCL_EXE) $(TOOL_DIR)/eolFix.tcl -crlf $(DISTDIR)/win/*.bat cp -p $(TOP_DIR)/win/makefile.* $(DISTDIR)/win $(TCL_EXE) $(TOOL_DIR)/eolFix.tcl -crlf $(DISTDIR)/win/makefile.* cp -p $(TOP_DIR)/win/rules.vc $(DISTDIR)/win $(TCL_EXE) $(TOOL_DIR)/eolFix.tcl -crlf $(DISTDIR)/win/rules.vc cp -p $(TOP_DIR)/win/coffbase.txt $(DISTDIR)/win $(TCL_EXE) $(TOOL_DIR)/eolFix.tcl -crlf $(DISTDIR)/win/coffbase.txt cp -p $(TOP_DIR)/win/tcl.hpj.in $(DISTDIR)/win $(TCL_EXE) $(TOOL_DIR)/eolFix.tcl -crlf $(DISTDIR)/win/tcl.hpj.in cp -p $(TOP_DIR)/win/tcl.ds* $(DISTDIR)/win $(TCL_EXE) $(TOOL_DIR)/eolFix.tcl -crlf $(DISTDIR)/win/tcl.ds* cp -p $(TOP_DIR)/win/README $(DISTDIR)/win cp -p $(TOP_DIR)/license.terms $(DISTDIR)/win mkdir $(DISTDIR)/macosx cp -p $(MAC_OSX_DIR)/Makefile $(MAC_OSX_DIR)/README \ $(MAC_OSX_DIR)/*.c $(MAC_OSX_DIR)/*.in \ $(DISTDIR)/macosx cp -p $(TOP_DIR)/license.terms $(DISTDIR)/macosx mkdir $(DISTDIR)/macosx/Tcl.pbproj cp -p $(MAC_OSX_DIR)/Tcl.pbproj/*.pbx* $(DISTDIR)/macosx/Tcl.pbproj mkdir $(DISTDIR)/unix/dltest cp -p $(UNIX_DIR)/dltest/*.c $(UNIX_DIR)/dltest/Makefile.in \ $(UNIX_DIR)/dltest/README \ $(DISTDIR)/unix/dltest mkdir $(DISTDIR)/tools cp -p $(TOOL_DIR)/Makefile.in $(TOOL_DIR)/README \ $(TOOL_DIR)/configure $(TOOL_DIR)/configure.in \ $(TOOL_DIR)/*.tcl $(TOOL_DIR)/man2tcl.c \ $(TOOL_DIR)/tcl.wse.in $(TOOL_DIR)/*.bmp \ $(TOOL_DIR)/tcl.hpj.in \ $(DISTDIR)/tools $(TCL_EXE) $(TOOL_DIR)/eolFix.tcl -crlf $(DISTDIR)/tools/tcl.hpj.in \ $(DISTDIR)/tools/tcl.wse.in # # The following target can only be used for non-patch releases. Use # the "allpatch" target below for patch releases. # alldist: dist rm -f $(DISTROOT)/$(DISTNAME)-src.tar.gz $(DISTROOT)/$(ZIPNAME) cd $(DISTROOT); tar cf $(DISTNAME)-src.tar $(DISTNAME); \ gzip -9 $(DISTNAME)-src.tar; zip -qr8 $(ZIPNAME) $(DISTNAME) # # The target below is similar to "alldist" except it works for patch # releases. It is needed because patch releases are peculiar: the # patch designation appears in the name of the compressed file # (e.g. tcl8.0p1.tar.gz) but the extracted source directory doesn't # include the patch designation (e.g. tcl8.0). # allpatch: dist rm -f $(DISTROOT)/$(DISTNAME)-src.tar.gz $(DISTROOT)/$(ZIPNAME) mv $(DISTROOT)/tcl${VERSION} $(DISTROOT)/old mv $(DISTROOT)/$(DISTNAME) $(DISTROOT)/tcl${VERSION} cd $(DISTROOT); tar cf $(DISTNAME)-src.tar tcl${VERSION}; \ gzip -9 $(DISTNAME)-src.tar; zip -r8 $(ZIPNAME) tcl${VERSION} mv $(DISTROOT)/tcl${VERSION} $(DISTROOT)/$(DISTNAME) mv $(DISTROOT)/old $(DISTROOT)/tcl${VERSION} # # This target creates the HTML folder for Tcl & Tk and places it # in DISTDIR/html. It uses the tcltk-man2html.tcl tool from # the Tcl group's tool workspace. It depends on the Tcl & Tk being # in directories called tcl8.* & tk8.* up two directories from the # TOOL_DIR. # html: tclsh $(BUILD_HTML) @EXTRA_BUILD_HTML@ html-tcl: tclsh $(BUILD_HTML) --tcl @EXTRA_BUILD_HTML@ html-tk: tclsh $(BUILD_HTML) --tk @EXTRA_BUILD_HTML@ BUILD_HTML = \ @@LD_LIBRARY_PATH_VAR@=`pwd`:$${@LD_LIBRARY_PATH_VAR@}; export @LD_LIBRARY_PATH_VAR@; \ TCL_LIBRARY="${TCL_BUILDTIME_LIBRARY}"; export TCL_LIBRARY; \ ./tclsh $(TOOL_DIR)/tcltk-man2html.tcl --htmldir=$(HTML_INSTALL_DIR) \ --srcdir=$(TOP_DIR)/.. $(BUILD_HTML_FLAGS) # # Targets to build Solaris package of the distribution for the current # architecture. To build stream packages for both sun4 and i86pc # architectures: # # On the sun4 machine, execute the following: # make distclean; ./configure # make DISTDIR= package # # Once the build is complete, execute the following on the i86pc # machine: # make DISTDIR= package-quick # # is the absolute path to a directory where the build should # take place. These steps will generate the $(PACKAGE).sun4 and # $(PACKAGE).i86pc stream packages. It is important that the packages be # built in this fashion in order to ensure that the architecture # independent files are exactly the same, including timestamps, in # both packages. # PACKAGE=SCRPtcl package: dist package-config package-common package-binaries package-generate package-quick: package-config package-binaries package-generate # # Configure for the current architecture in the dist directory. # package-config: mkdir -p $(DISTDIR)/unix/`arch` cd $(DISTDIR)/unix/`arch`; \ ../configure --prefix=/opt/$(PACKAGE)/$(VERSION) \ --exec_prefix=/opt/$(PACKAGE)/$(VERSION)/`arch` \ --enable-shared mkdir -p $(DISTDIR)/$(PACKAGE)/$(VERSION) mkdir -p $(DISTDIR)/$(PACKAGE)/$(VERSION)/`arch` # # Build and install the architecture independent files in the dist directory. # package-common: cd $(DISTDIR)/unix/`arch`;\ $(MAKE); \ $(MAKE) prefix=$(DISTDIR)/$(PACKAGE)/$(VERSION) \ exec_prefix=$(DISTDIR)/$(PACKAGE)/$(VERSION)/`arch` \ install-libraries install-man mkdir -p $(DISTDIR)/$(PACKAGE)/$(VERSION)/bin sed -e "s/TCLVERSION/$(VERSION)/g" < $(UNIX_DIR)/tclsh.sh \ > $(DISTDIR)/$(PACKAGE)/$(VERSION)/bin/tclsh$(VERSION) chmod 755 $(DISTDIR)/$(PACKAGE)/$(VERSION)/bin/tclsh$(VERSION) # # Build and install the architecture specific files in the dist directory. # package-binaries: cd $(DISTDIR)/unix/`arch`; \ $(MAKE); \ $(MAKE) install-binaries prefix=$(DISTDIR)/$(PACKAGE)/$(VERSION) \ exec_prefix=$(DISTDIR)/$(PACKAGE)/$(VERSION)/`arch` # # Generate a package from the installed files in the dist directory for the # current architecture. # package-generate: pkgproto $(DISTDIR)/$(PACKAGE)/$(VERSION)/bin=bin \ $(DISTDIR)/$(PACKAGE)/$(VERSION)/include=include \ $(DISTDIR)/$(PACKAGE)/$(VERSION)/lib=lib \ $(DISTDIR)/$(PACKAGE)/$(VERSION)/man=man \ $(DISTDIR)/$(PACKAGE)/$(VERSION)/`arch`=`arch` \ | $(TCL_EXE) $(UNIX_DIR)/mkProto.tcl \ $(VERSION) $(UNIX_DIR) > prototype pkgmk -o -d . -f prototype -a `arch` pkgtrans -s . $(PACKAGE).`arch` $(PACKAGE) rm -rf $(PACKAGE) # DO NOT DELETE THIS LINE -- make depend depends on it. tcl8.4.20/unix/configure0000775003604700454610000102626712153151142013612 0ustar dgp771div#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated automatically using autoconf version 2.13 # Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. # Defaults: ac_help= ac_default_prefix=/usr/local # Any additions from configure.in: ac_help="$ac_help --enable-man-symlinks use symlinks for the manpages (default: off)" ac_help="$ac_help --enable-man-compression=PROG compress the manpages with PROG (default: off)" ac_help="$ac_help --enable-man-suffix=STRING use STRING as a suffix to manpage file names (default: tcl)" ac_help="$ac_help --enable-threads build with threads (default: off)" ac_help="$ac_help --enable-shared build and link with shared libraries (default: on)" ac_help="$ac_help --enable-64bit enable 64bit support (where applicable)" ac_help="$ac_help --enable-64bit-vis enable 64bit Sparc VIS support" ac_help="$ac_help --disable-rpath disable rpath support (default: on)" ac_help="$ac_help --enable-corefoundation use CoreFoundation API [--enable-corefoundation]" ac_help="$ac_help --disable-load disallow dynamic loading and "load" command" ac_help="$ac_help --enable-symbols build with debugging symbols (default: off)" ac_help="$ac_help --enable-langinfo use nl_langinfo if possible to determine encoding at startup, otherwise use old heuristic (default: on)" ac_help="$ac_help --enable-dtrace build with DTrace support [--disable-dtrace]" ac_help="$ac_help --enable-framework package shared libraries in MacOSX frameworks (default: off)" # Initialize some variables set by options. # The variables have the same names as the options, with # dashes changed to underlines. build=NONE cache_file=./config.cache exec_prefix=NONE host=NONE no_create= nonopt=NONE no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= target=NONE verbose= x_includes=NONE x_libraries=NONE bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datadir='${prefix}/share' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' libdir='${exec_prefix}/lib' includedir='${prefix}/include' oldincludedir='/usr/include' infodir='${prefix}/info' mandir='${prefix}/man' # Initialize some other variables. subdirs= MFLAGS= MAKEFLAGS= SHELL=${CONFIG_SHELL-/bin/sh} # Maximum number of lines to put in a shell here document. ac_max_here_lines=12 ac_prev= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval "$ac_prev=\$ac_option" ac_prev= continue fi case "$ac_option" in -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; *) ac_optarg= ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case "$ac_option" in -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir="$ac_optarg" ;; -build | --build | --buil | --bui | --bu) ac_prev=build ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build="$ac_optarg" ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file="$ac_optarg" ;; -datadir | --datadir | --datadi | --datad | --data | --dat | --da) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ | --da=*) datadir="$ac_optarg" ;; -disable-* | --disable-*) ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } fi ac_feature=`echo $ac_feature| sed 's/-/_/g'` eval "enable_${ac_feature}=no" ;; -enable-* | --enable-*) ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } fi ac_feature=`echo $ac_feature| sed 's/-/_/g'` case "$ac_option" in *=*) ;; *) ac_optarg=yes ;; esac eval "enable_${ac_feature}='$ac_optarg'" ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix="$ac_optarg" ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he) # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat << EOF Usage: configure [options] [host] Options: [defaults in brackets after descriptions] Configuration: --cache-file=FILE cache test results in FILE --help print this message --no-create do not create output files --quiet, --silent do not print \`checking...' messages --version print the version of autoconf that created configure Directory and file names: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [same as prefix] --bindir=DIR user executables in DIR [EPREFIX/bin] --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] --libexecdir=DIR program executables in DIR [EPREFIX/libexec] --datadir=DIR read-only architecture-independent data in DIR [PREFIX/share] --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data in DIR [PREFIX/com] --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] --libdir=DIR object code libraries in DIR [EPREFIX/lib] --includedir=DIR C header files in DIR [PREFIX/include] --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] --infodir=DIR info documentation in DIR [PREFIX/info] --mandir=DIR man documentation in DIR [PREFIX/man] --srcdir=DIR find the sources in DIR [configure dir or ..] --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names EOF cat << EOF Host type: --build=BUILD configure for building on BUILD [BUILD=HOST] --host=HOST configure for HOST [guessed] --target=TARGET configure for TARGET [TARGET=HOST] Features and packages: --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --x-includes=DIR X include files are in DIR --x-libraries=DIR X library files are in DIR EOF if test -n "$ac_help"; then echo "--enable and --with options recognized:$ac_help" fi exit 0 ;; -host | --host | --hos | --ho) ac_prev=host ;; -host=* | --host=* | --hos=* | --ho=*) host="$ac_optarg" ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir="$ac_optarg" ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir="$ac_optarg" ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir="$ac_optarg" ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir="$ac_optarg" ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst \ | --locals | --local | --loca | --loc | --lo) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* \ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) localstatedir="$ac_optarg" ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir="$ac_optarg" ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir="$ac_optarg" ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix="$ac_optarg" ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix="$ac_optarg" ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix="$ac_optarg" ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name="$ac_optarg" ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir="$ac_optarg" ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir="$ac_optarg" ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site="$ac_optarg" ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir="$ac_optarg" ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir="$ac_optarg" ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target="$ac_optarg" ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers) echo "configure generated by autoconf version 2.13" exit 0 ;; -with-* | --with-*) ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } fi ac_package=`echo $ac_package| sed 's/-/_/g'` case "$ac_option" in *=*) ;; *) ac_optarg=yes ;; esac eval "with_${ac_package}='$ac_optarg'" ;; -without-* | --without-*) ac_package=`echo $ac_option|sed -e 's/-*without-//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } fi ac_package=`echo $ac_package| sed 's/-/_/g'` eval "with_${ac_package}=no" ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes="$ac_optarg" ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries="$ac_optarg" ;; -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } ;; *) if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then echo "configure: warning: $ac_option: invalid host type" 1>&2 fi if test "x$nonopt" != xNONE; then { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } fi nonopt="$ac_option" ;; esac done if test -n "$ac_prev"; then { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } fi trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 # File descriptor usage: # 0 standard input # 1 file creation # 2 errors and warnings # 3 some systems may open it to /dev/tty # 4 used on the Kubota Titan # 6 checking for... messages and results # 5 compiler messages saved in config.log if test "$silent" = yes; then exec 6>/dev/null else exec 6>&1 fi exec 5>./config.log echo "\ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. " 1>&5 # Strip out --no-create and --no-recursion so they do not pile up. # Also quote any args containing shell metacharacters. ac_configure_args= for ac_arg do case "$ac_arg" in -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c) ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) ac_configure_args="$ac_configure_args '$ac_arg'" ;; *) ac_configure_args="$ac_configure_args $ac_arg" ;; esac done # NLS nuisances. # Only set these to C if already set. These must not be set unconditionally # because not all systems understand e.g. LANG=C (notably SCO). # Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! # Non-C LC_CTYPE values break the ctype check. if test "${LANG+set}" = set; then LANG=C; export LANG; fi if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -rf conftest* confdefs.h # AIX cpp loses on an empty file, so make sure it contains at least a newline. echo > confdefs.h # A filename unique to this package, relative to the directory that # configure is in, which we can look for to find out if srcdir is correct. ac_unique_file=../generic/tcl.h # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then its parent. ac_prog=$0 ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. srcdir=$ac_confdir if test ! -r $srcdir/$ac_unique_file; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r $srcdir/$ac_unique_file; then if test "$ac_srcdir_defaulted" = yes; then { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } else { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } fi fi srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` # Prefer explicitly selected file to automatically selected ones. if test -z "$CONFIG_SITE"; then if test "x$prefix" != xNONE; then CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" else CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi fi for ac_site_file in $CONFIG_SITE; do if test -r "$ac_site_file"; then echo "loading site script $ac_site_file" . "$ac_site_file" fi done if test -r "$cache_file"; then echo "loading cache $cache_file" . $cache_file else echo "creating cache $cache_file" > $cache_file fi ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. ac_cpp='$CPP $CPPFLAGS' ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' cross_compiling=$ac_cv_prog_cc_cross ac_exeext= ac_objext=o if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then ac_n= ac_c=' ' ac_t=' ' else ac_n=-n ac_c= ac_t= fi else ac_n= ac_c='\c' ac_t= fi TCL_VERSION=8.4 TCL_MAJOR_VERSION=8 TCL_MINOR_VERSION=4 TCL_PATCH_LEVEL=".20" VERSION=${TCL_VERSION} #------------------------------------------------------------------------ # Handle the --prefix=... option #------------------------------------------------------------------------ if test "${prefix}" = "NONE"; then prefix=/usr/local fi if test "${exec_prefix}" = "NONE"; then exec_prefix=$prefix fi # Make sure srcdir is fully qualified! srcdir=`cd $srcdir ; pwd` TCL_SRC_DIR=`cd $srcdir/..; pwd` #------------------------------------------------------------------------ # Compress and/or soft link the manpages? #------------------------------------------------------------------------ echo $ac_n "checking whether to use symlinks for manpages""... $ac_c" 1>&6 echo "configure:585: checking whether to use symlinks for manpages" >&5 # Check whether --enable-man-symlinks or --disable-man-symlinks was given. if test "${enable_man_symlinks+set}" = set; then enableval="$enable_man_symlinks" test "$enableval" != "no" && MAN_FLAGS="$MAN_FLAGS --symlinks" else enableval="no" fi echo "$ac_t""$enableval" 1>&6 echo $ac_n "checking whether to compress the manpages""... $ac_c" 1>&6 echo "configure:597: checking whether to compress the manpages" >&5 # Check whether --enable-man-compression or --disable-man-compression was given. if test "${enable_man_compression+set}" = set; then enableval="$enable_man_compression" case $enableval in yes) { echo "configure: error: missing argument to --enable-man-compression" 1>&2; exit 1; };; no) ;; *) MAN_FLAGS="$MAN_FLAGS --compress $enableval";; esac else enableval="no" fi echo "$ac_t""$enableval" 1>&6 if test "$enableval" != "no"; then echo $ac_n "checking for compressed file suffix""... $ac_c" 1>&6 echo "configure:613: checking for compressed file suffix" >&5 touch TeST $enableval TeST Z=`ls TeST* | sed 's/^....//'` rm -f TeST* MAN_FLAGS="$MAN_FLAGS --extension $Z" echo "$ac_t""$Z" 1>&6 fi echo $ac_n "checking whether to add a package name suffix for the manpages""... $ac_c" 1>&6 echo "configure:623: checking whether to add a package name suffix for the manpages" >&5 # Check whether --enable-man-suffix or --disable-man-suffix was given. if test "${enable_man_suffix+set}" = set; then enableval="$enable_man_suffix" case $enableval in yes) enableval="tcl" MAN_FLAGS="$MAN_FLAGS --suffix $enableval";; no) ;; *) MAN_FLAGS="$MAN_FLAGS --suffix $enableval";; esac else enableval="no" fi echo "$ac_t""$enableval" 1>&6 #------------------------------------------------------------------------ # Standard compiler checks #------------------------------------------------------------------------ # If the user did not set CFLAGS, set it now to keep # the AC_PROG_CC macro from adding "-g -O2". if test "${CFLAGS+set}" != "set" ; then CFLAGS="" fi # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo "configure:654: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" ac_dummy="$PATH" for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_prog_CC="gcc" break fi done IFS="$ac_save_ifs" fi fi CC="$ac_cv_prog_CC" if test -n "$CC"; then echo "$ac_t""$CC" 1>&6 else echo "$ac_t""no" 1>&6 fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo "configure:684: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" ac_prog_rejected=no ac_dummy="$PATH" for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" break fi done IFS="$ac_save_ifs" if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# -gt 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift set dummy "$ac_dir/$ac_word" "$@" shift ac_cv_prog_CC="$@" fi fi fi fi CC="$ac_cv_prog_CC" if test -n "$CC"; then echo "$ac_t""$CC" 1>&6 else echo "$ac_t""no" 1>&6 fi if test -z "$CC"; then case "`uname -s`" in *win32* | *WIN32*) # Extract the first word of "cl", so it can be a program name with args. set dummy cl; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo "configure:735: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" ac_dummy="$PATH" for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_prog_CC="cl" break fi done IFS="$ac_save_ifs" fi fi CC="$ac_cv_prog_CC" if test -n "$CC"; then echo "$ac_t""$CC" 1>&6 else echo "$ac_t""no" 1>&6 fi ;; esac fi test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } fi echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 echo "configure:767: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. ac_cpp='$CPP $CPPFLAGS' ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' cross_compiling=$ac_cv_prog_cc_cross cat > conftest.$ac_ext << EOF #line 778 "configure" #include "confdefs.h" main(){return(0);} EOF if { (eval echo configure:783: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then ac_cv_prog_cc_works=yes # If we can't run a trivial program, we are probably using a cross compiler. if (./conftest; exit) 2>/dev/null; then ac_cv_prog_cc_cross=no else ac_cv_prog_cc_cross=yes fi else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 ac_cv_prog_cc_works=no fi rm -fr conftest* ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. ac_cpp='$CPP $CPPFLAGS' ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' cross_compiling=$ac_cv_prog_cc_cross echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 if test $ac_cv_prog_cc_works = no; then { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } fi echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 echo "configure:809: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 cross_compiling=$ac_cv_prog_cc_cross echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 echo "configure:814: checking whether we are using GNU C" >&5 if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then ac_cv_prog_gcc=yes else ac_cv_prog_gcc=no fi fi echo "$ac_t""$ac_cv_prog_gcc" 1>&6 if test $ac_cv_prog_gcc = yes; then GCC=yes else GCC= fi ac_test_CFLAGS="${CFLAGS+set}" ac_save_CFLAGS="$CFLAGS" CFLAGS= echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 echo "configure:842: checking whether ${CC-cc} accepts -g" >&5 if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else echo 'void f(){}' > conftest.c if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then ac_cv_prog_cc_g=yes else ac_cv_prog_cc_g=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 if test "$ac_test_CFLAGS" = set; then CFLAGS="$ac_save_CFLAGS" elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi #-------------------------------------------------------------------- # Supply substitutes for missing POSIX header files. Special notes: # - stdlib.h doesn't define strtol, strtoul, or # strtod insome versions of SunOS # - some versions of string.h don't declare procedures such # as strstr # Do this early, otherwise an autoconf bug throws errors on configure #-------------------------------------------------------------------- echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 echo "configure:884: checking how to run the C preprocessor" >&5 # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else # This must be in double quotes, not single quotes, because CPP may get # substituted into the Makefile and "${CC-cc}" will confuse make. CPP="${CC-cc} -E" # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. cat > conftest.$ac_ext < Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:905: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* CPP="${CC-cc} -E -traditional-cpp" cat > conftest.$ac_ext < Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:922: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* CPP="${CC-cc} -nologo -E" cat > conftest.$ac_ext < Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:939: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* CPP=/lib/cpp fi rm -f conftest* fi rm -f conftest* fi rm -f conftest* ac_cv_prog_CPP="$CPP" fi CPP="$ac_cv_prog_CPP" else ac_cv_prog_CPP="$CPP" fi echo "$ac_t""$CPP" 1>&6 echo $ac_n "checking dirent.h""... $ac_c" 1>&6 echo "configure:965: checking dirent.h" >&5 if eval "test \"`echo '$''{'tcl_cv_dirent_h'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include int main() { #ifndef _POSIX_SOURCE # ifdef __Lynx__ /* * Generate compilation error to make the test fail: Lynx headers * are only valid if really in the POSIX environment. */ missing_procedure(); # endif #endif DIR *d; struct dirent *entryPtr; char *p; d = opendir("foobar"); entryPtr = readdir(d); p = entryPtr->d_name; closedir(d); ; return 0; } EOF if { (eval echo configure:997: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* tcl_cv_dirent_h=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_dirent_h=no fi rm -f conftest* fi echo "$ac_t""$tcl_cv_dirent_h" 1>&6 if test $tcl_cv_dirent_h = no; then cat >> confdefs.h <<\EOF #define NO_DIRENT_H 1 EOF fi ac_safe=`echo "errno.h" | sed 'y%./+-%__p_%'` echo $ac_n "checking for errno.h""... $ac_c" 1>&6 echo "configure:1020: checking for errno.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:1030: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 : else echo "$ac_t""no" 1>&6 cat >> confdefs.h <<\EOF #define NO_ERRNO_H 1 EOF fi ac_safe=`echo "float.h" | sed 'y%./+-%__p_%'` echo $ac_n "checking for float.h""... $ac_c" 1>&6 echo "configure:1057: checking for float.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:1067: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 : else echo "$ac_t""no" 1>&6 cat >> confdefs.h <<\EOF #define NO_FLOAT_H 1 EOF fi ac_safe=`echo "values.h" | sed 'y%./+-%__p_%'` echo $ac_n "checking for values.h""... $ac_c" 1>&6 echo "configure:1094: checking for values.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:1104: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 : else echo "$ac_t""no" 1>&6 cat >> confdefs.h <<\EOF #define NO_VALUES_H 1 EOF fi ac_safe=`echo "limits.h" | sed 'y%./+-%__p_%'` echo $ac_n "checking for limits.h""... $ac_c" 1>&6 echo "configure:1131: checking for limits.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:1141: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 cat >> confdefs.h <<\EOF #define HAVE_LIMITS_H 1 EOF else echo "$ac_t""no" 1>&6 cat >> confdefs.h <<\EOF #define NO_LIMITS_H 1 EOF fi ac_safe=`echo "stdlib.h" | sed 'y%./+-%__p_%'` echo $ac_n "checking for stdlib.h""... $ac_c" 1>&6 echo "configure:1171: checking for stdlib.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:1181: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 tcl_ok=1 else echo "$ac_t""no" 1>&6 tcl_ok=0 fi cat > conftest.$ac_ext < EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "strtol" >/dev/null 2>&1; then : else rm -rf conftest* tcl_ok=0 fi rm -f conftest* cat > conftest.$ac_ext < EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "strtoul" >/dev/null 2>&1; then : else rm -rf conftest* tcl_ok=0 fi rm -f conftest* cat > conftest.$ac_ext < EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "strtod" >/dev/null 2>&1; then : else rm -rf conftest* tcl_ok=0 fi rm -f conftest* if test $tcl_ok = 0; then cat >> confdefs.h <<\EOF #define NO_STDLIB_H 1 EOF fi ac_safe=`echo "string.h" | sed 'y%./+-%__p_%'` echo $ac_n "checking for string.h""... $ac_c" 1>&6 echo "configure:1253: checking for string.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:1263: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 tcl_ok=1 else echo "$ac_t""no" 1>&6 tcl_ok=0 fi cat > conftest.$ac_ext < EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "strstr" >/dev/null 2>&1; then : else rm -rf conftest* tcl_ok=0 fi rm -f conftest* cat > conftest.$ac_ext < EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "strerror" >/dev/null 2>&1; then : else rm -rf conftest* tcl_ok=0 fi rm -f conftest* # See also memmove check below for a place where NO_STRING_H can be # set and why. if test $tcl_ok = 0; then cat >> confdefs.h <<\EOF #define NO_STRING_H 1 EOF fi ac_safe=`echo "sys/wait.h" | sed 'y%./+-%__p_%'` echo $ac_n "checking for sys/wait.h""... $ac_c" 1>&6 echo "configure:1326: checking for sys/wait.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:1336: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 : else echo "$ac_t""no" 1>&6 cat >> confdefs.h <<\EOF #define NO_SYS_WAIT_H 1 EOF fi ac_safe=`echo "dlfcn.h" | sed 'y%./+-%__p_%'` echo $ac_n "checking for dlfcn.h""... $ac_c" 1>&6 echo "configure:1363: checking for dlfcn.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:1373: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 : else echo "$ac_t""no" 1>&6 cat >> confdefs.h <<\EOF #define NO_DLFCN_H 1 EOF fi # OS/390 lacks sys/param.h (and doesn't need it, by chance). for ac_hdr in unistd.h sys/param.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 echo "configure:1404: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:1414: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` cat >> confdefs.h <&6 fi done #------------------------------------------------------------------------ # If we're using GCC, see if the compiler understands -pipe. If so, use it. # It makes compiling go faster. (This is only a performance feature.) #------------------------------------------------------------------------ if test -z "$no_pipe" && test -n "$GCC"; then echo $ac_n "checking if the compiler understands -pipe""... $ac_c" 1>&6 echo "configure:1449: checking if the compiler understands -pipe" >&5 if eval "test \"`echo '$''{'tcl_cv_cc_pipe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -pipe" cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_cv_cc_pipe=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_cc_pipe=no fi rm -f conftest* CFLAGS=$hold_cflags fi echo "$ac_t""$tcl_cv_cc_pipe" 1>&6 if test $tcl_cv_cc_pipe = yes; then CFLAGS="$CFLAGS -pipe" fi fi #------------------------------------------------------------------------ # Threads support #------------------------------------------------------------------------ # Check whether --enable-threads or --disable-threads was given. if test "${enable_threads+set}" = set; then enableval="$enable_threads" tcl_ok=$enableval else tcl_ok=no fi if test "${TCL_THREADS}" = 1; then tcl_threaded_core=1; fi if test "$tcl_ok" = "yes" -o "${TCL_THREADS}" = 1; then TCL_THREADS=1 # USE_THREAD_ALLOC tells us to try the special thread-based # allocator that significantly reduces lock contention cat >> confdefs.h <<\EOF #define USE_THREAD_ALLOC 1 EOF cat >> confdefs.h <<\EOF #define _REENTRANT 1 EOF if test "`uname -s`" = "SunOS" ; then cat >> confdefs.h <<\EOF #define _POSIX_PTHREAD_SEMANTICS 1 EOF fi cat >> confdefs.h <<\EOF #define _THREAD_SAFE 1 EOF echo $ac_n "checking for pthread_mutex_init in -lpthread""... $ac_c" 1>&6 echo "configure:1523: checking for pthread_mutex_init in -lpthread" >&5 ac_lib_var=`echo pthread'_'pthread_mutex_init | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lpthread $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 tcl_ok=yes else echo "$ac_t""no" 1>&6 tcl_ok=no fi if test "$tcl_ok" = "no"; then # Check a little harder for __pthread_mutex_init in the same # library, as some systems hide it there until pthread.h is # defined. We could alternatively do an AC_TRY_COMPILE with # pthread.h, but that will work with libpthread really doesn't # exist, like AIX 4.2. [Bug: 4359] echo $ac_n "checking for __pthread_mutex_init in -lpthread""... $ac_c" 1>&6 echo "configure:1570: checking for __pthread_mutex_init in -lpthread" >&5 ac_lib_var=`echo pthread'_'__pthread_mutex_init | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lpthread $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 tcl_ok=yes else echo "$ac_t""no" 1>&6 tcl_ok=no fi fi if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -lpthread" else echo $ac_n "checking for pthread_mutex_init in -lpthreads""... $ac_c" 1>&6 echo "configure:1617: checking for pthread_mutex_init in -lpthreads" >&5 ac_lib_var=`echo pthreads'_'pthread_mutex_init | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lpthreads $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 tcl_ok=yes else echo "$ac_t""no" 1>&6 tcl_ok=no fi if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -lpthreads" else echo $ac_n "checking for pthread_mutex_init in -lc""... $ac_c" 1>&6 echo "configure:1662: checking for pthread_mutex_init in -lc" >&5 ac_lib_var=`echo c'_'pthread_mutex_init | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lc $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 tcl_ok=yes else echo "$ac_t""no" 1>&6 tcl_ok=no fi if test "$tcl_ok" = "no"; then echo $ac_n "checking for pthread_mutex_init in -lc_r""... $ac_c" 1>&6 echo "configure:1704: checking for pthread_mutex_init in -lc_r" >&5 ac_lib_var=`echo c_r'_'pthread_mutex_init | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lc_r $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 tcl_ok=yes else echo "$ac_t""no" 1>&6 tcl_ok=no fi if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -pthread" else TCL_THREADS=0 echo "configure: warning: Don't know how to find pthread lib on your system - you must disable thread support or edit the LIBS in the Makefile..." 1>&2 fi fi fi fi # Does the pthread-implementation provide # 'pthread_attr_setstacksize' ? ac_saved_libs=$LIBS LIBS="$LIBS $THREADS_LIBS" for ac_func in pthread_attr_setstacksize do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 echo "configure:1763: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else $ac_func(); #endif ; return 0; } EOF if { (eval echo configure:1791: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_$ac_func=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` cat >> confdefs.h <&6 fi done for ac_func in pthread_atfork do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 echo "configure:1818: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else $ac_func(); #endif ; return 0; } EOF if { (eval echo configure:1846: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_$ac_func=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` cat >> confdefs.h <&6 fi done LIBS=$ac_saved_libs else TCL_THREADS=0 fi # Do checking message here to not mess up interleaved configure output echo $ac_n "checking for building with threads""... $ac_c" 1>&6 echo "configure:1876: checking for building with threads" >&5 if test "${TCL_THREADS}" = 1; then cat >> confdefs.h <<\EOF #define TCL_THREADS 1 EOF if test "${tcl_threaded_core}" = 1; then echo "$ac_t""yes (threaded core)" 1>&6 else echo "$ac_t""yes" 1>&6 fi else echo "$ac_t""no (default)" 1>&6 fi #-------------------------------------------------------------------- # Look for libraries that we will need when compiling the Tcl shell #-------------------------------------------------------------------- #-------------------------------------------------------------------- # On a few very rare systems, all of the libm.a stuff is # already in libc.a. Set compiler flags accordingly. # Also, Linux requires the "ieee" library for math to work # right (and it must appear before "-lm"). #-------------------------------------------------------------------- echo $ac_n "checking for sin""... $ac_c" 1>&6 echo "configure:1907: checking for sin" >&5 if eval "test \"`echo '$''{'ac_cv_func_sin'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char sin(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_sin) || defined (__stub___sin) choke me #else sin(); #endif ; return 0; } EOF if { (eval echo configure:1935: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_sin=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_sin=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'sin`\" = yes"; then echo "$ac_t""yes" 1>&6 MATH_LIBS="" else echo "$ac_t""no" 1>&6 MATH_LIBS="-lm" fi echo $ac_n "checking for main in -lieee""... $ac_c" 1>&6 echo "configure:1956: checking for main in -lieee" >&5 ac_lib_var=`echo ieee'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lieee $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 MATH_LIBS="-lieee $MATH_LIBS" else echo "$ac_t""no" 1>&6 fi #-------------------------------------------------------------------- # Interactive UNIX requires -linet instead of -lsocket, plus it # needs net/errno.h to define the socket-related error codes. #-------------------------------------------------------------------- echo $ac_n "checking for main in -linet""... $ac_c" 1>&6 echo "configure:1998: checking for main in -linet" >&5 ac_lib_var=`echo inet'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-linet $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 LIBS="$LIBS -linet" else echo "$ac_t""no" 1>&6 fi ac_safe=`echo "net/errno.h" | sed 'y%./+-%__p_%'` echo $ac_n "checking for net/errno.h""... $ac_c" 1>&6 echo "configure:2035: checking for net/errno.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:2045: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 cat >> confdefs.h <<\EOF #define HAVE_NET_ERRNO_H 1 EOF else echo "$ac_t""no" 1>&6 fi #-------------------------------------------------------------------- # Check for the existence of the -lsocket and -lnsl libraries. # The order here is important, so that they end up in the right # order in the command line generated by make. Here are some # special considerations: # 1. Use "connect" and "accept" to check for -lsocket, and # "gethostbyname" to check for -lnsl. # 2. Use each function name only once: can't redo a check because # autoconf caches the results of the last check and won't redo it. # 3. Use -lnsl and -lsocket only if they supply procedures that # aren't already present in the normal libraries. This is because # IRIX 5.2 has libraries, but they aren't needed and they're # bogus: they goof up name resolution if used. # 4. On some SVR4 systems, can't use -lsocket without -lnsl too. # To get around this problem, check for both libraries together # if -lsocket doesn't work by itself. #-------------------------------------------------------------------- tcl_checkBoth=0 echo $ac_n "checking for connect""... $ac_c" 1>&6 echo "configure:2091: checking for connect" >&5 if eval "test \"`echo '$''{'ac_cv_func_connect'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char connect(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_connect) || defined (__stub___connect) choke me #else connect(); #endif ; return 0; } EOF if { (eval echo configure:2119: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_connect=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_connect=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'connect`\" = yes"; then echo "$ac_t""yes" 1>&6 tcl_checkSocket=0 else echo "$ac_t""no" 1>&6 tcl_checkSocket=1 fi if test "$tcl_checkSocket" = 1; then echo $ac_n "checking for setsockopt""... $ac_c" 1>&6 echo "configure:2141: checking for setsockopt" >&5 if eval "test \"`echo '$''{'ac_cv_func_setsockopt'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char setsockopt(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_setsockopt) || defined (__stub___setsockopt) choke me #else setsockopt(); #endif ; return 0; } EOF if { (eval echo configure:2169: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_setsockopt=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_setsockopt=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'setsockopt`\" = yes"; then echo "$ac_t""yes" 1>&6 : else echo "$ac_t""no" 1>&6 echo $ac_n "checking for setsockopt in -lsocket""... $ac_c" 1>&6 echo "configure:2187: checking for setsockopt in -lsocket" >&5 ac_lib_var=`echo socket'_'setsockopt | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lsocket $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 LIBS="$LIBS -lsocket" else echo "$ac_t""no" 1>&6 tcl_checkBoth=1 fi fi fi if test "$tcl_checkBoth" = 1; then tk_oldLibs=$LIBS LIBS="$LIBS -lsocket -lnsl" echo $ac_n "checking for accept""... $ac_c" 1>&6 echo "configure:2234: checking for accept" >&5 if eval "test \"`echo '$''{'ac_cv_func_accept'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char accept(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_accept) || defined (__stub___accept) choke me #else accept(); #endif ; return 0; } EOF if { (eval echo configure:2262: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_accept=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_accept=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'accept`\" = yes"; then echo "$ac_t""yes" 1>&6 tcl_checkNsl=0 else echo "$ac_t""no" 1>&6 LIBS=$tk_oldLibs fi fi echo $ac_n "checking for gethostbyname""... $ac_c" 1>&6 echo "configure:2284: checking for gethostbyname" >&5 if eval "test \"`echo '$''{'ac_cv_func_gethostbyname'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char gethostbyname(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_gethostbyname) || defined (__stub___gethostbyname) choke me #else gethostbyname(); #endif ; return 0; } EOF if { (eval echo configure:2312: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_gethostbyname=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_gethostbyname=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'gethostbyname`\" = yes"; then echo "$ac_t""yes" 1>&6 : else echo "$ac_t""no" 1>&6 echo $ac_n "checking for gethostbyname in -lnsl""... $ac_c" 1>&6 echo "configure:2330: checking for gethostbyname in -lnsl" >&5 ac_lib_var=`echo nsl'_'gethostbyname | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lnsl $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 LIBS="$LIBS -lnsl" else echo "$ac_t""no" 1>&6 fi fi # Don't perform the eval of the libraries here because DL_LIBS # won't be set until we call SC_CONFIG_CFLAGS TCL_LIBS='${DL_LIBS} ${LIBS} ${MATH_LIBS}' # Add the threads support libraries LIBS="$LIBS$THREADS_LIBS" echo $ac_n "checking how to build libraries""... $ac_c" 1>&6 echo "configure:2385: checking how to build libraries" >&5 # Check whether --enable-shared or --disable-shared was given. if test "${enable_shared+set}" = set; then enableval="$enable_shared" tcl_ok=$enableval else tcl_ok=yes fi if test "${enable_shared+set}" = set; then enableval="$enable_shared" tcl_ok=$enableval else tcl_ok=yes fi if test "$tcl_ok" = "yes" ; then echo "$ac_t""shared" 1>&6 SHARED_BUILD=1 else echo "$ac_t""static" 1>&6 SHARED_BUILD=0 cat >> confdefs.h <<\EOF #define STATIC_BUILD 1 EOF fi #-------------------------------------------------------------------- # The statements below define a collection of compile flags. This # macro depends on the value of SHARED_BUILD, and should be called # after SC_ENABLE_SHARED checks the configure switches. #-------------------------------------------------------------------- # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo "configure:2424: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" ac_dummy="$PATH" for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_prog_RANLIB="ranlib" break fi done IFS="$ac_save_ifs" test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":" fi fi RANLIB="$ac_cv_prog_RANLIB" if test -n "$RANLIB"; then echo "$ac_t""$RANLIB" 1>&6 else echo "$ac_t""no" 1>&6 fi # Step 0.a: Enable 64 bit support? echo $ac_n "checking if 64bit support is requested""... $ac_c" 1>&6 echo "configure:2456: checking if 64bit support is requested" >&5 # Check whether --enable-64bit or --disable-64bit was given. if test "${enable_64bit+set}" = set; then enableval="$enable_64bit" do64bit=$enableval else do64bit=no fi echo "$ac_t""$do64bit" 1>&6 # Step 0.b: Enable Solaris 64 bit VIS support? echo $ac_n "checking if 64bit Sparc VIS support is requested""... $ac_c" 1>&6 echo "configure:2470: checking if 64bit Sparc VIS support is requested" >&5 # Check whether --enable-64bit-vis or --disable-64bit-vis was given. if test "${enable_64bit_vis+set}" = set; then enableval="$enable_64bit_vis" do64bitVIS=$enableval else do64bitVIS=no fi echo "$ac_t""$do64bitVIS" 1>&6 if test "$do64bitVIS" = "yes"; then # Force 64bit on with VIS do64bit=yes fi # Step 0.d: Disable -rpath support? echo $ac_n "checking if rpath support is requested""... $ac_c" 1>&6 echo "configure:2489: checking if rpath support is requested" >&5 # Check whether --enable-rpath or --disable-rpath was given. if test "${enable_rpath+set}" = set; then enableval="$enable_rpath" doRpath=$enableval else doRpath=yes fi echo "$ac_t""$doRpath" 1>&6 # Step 1: set the variable "system" to hold the name and version number # for the system. echo $ac_n "checking system version""... $ac_c" 1>&6 echo "configure:2505: checking system version" >&5 if eval "test \"`echo '$''{'tcl_cv_sys_version'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -f /usr/lib/NextStep/software_version; then tcl_cv_sys_version=NEXTSTEP-`awk '/3/,/3/' /usr/lib/NextStep/software_version` else tcl_cv_sys_version=`uname -s`-`uname -r` if test "$?" -ne 0 ; then echo "configure: warning: can't find uname command" 1>&2 tcl_cv_sys_version=unknown else # Special check for weird MP-RAS system (uname returns weird # results, and the version is kept in special file). if test -r /etc/.relid -a "X`uname -n`" = "X`uname -s`" ; then tcl_cv_sys_version=MP-RAS-`awk '{print $3}' /etc/.relid` fi if test "`uname -s`" = "AIX" ; then tcl_cv_sys_version=AIX-`uname -v`.`uname -r` fi fi fi fi echo "$ac_t""$tcl_cv_sys_version" 1>&6 system=$tcl_cv_sys_version # Step 2: check for existence of -ldl library. This is needed because # Linux can use either -ldl or -ldld for dynamic loading. echo $ac_n "checking for dlopen in -ldl""... $ac_c" 1>&6 echo "configure:2540: checking for dlopen in -ldl" >&5 ac_lib_var=`echo dl'_'dlopen | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-ldl $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 have_dl=yes else echo "$ac_t""no" 1>&6 have_dl=no fi # Require ranlib early so we can override it in special cases below. # Step 3: set configuration options based on system name and version. do64bit_ok=no # default to '{$LIBS}' and set to "" on per-platform necessary basis SHLIB_LD_LIBS='${LIBS}' LDFLAGS_ORIG="$LDFLAGS" TCL_EXPORT_FILE_SUFFIX="" UNSHARED_LIB_SUFFIX="" TCL_TRIM_DOTS='`echo ${VERSION} | tr -d .`' ECHO_VERSION='`echo ${VERSION}`' TCL_LIB_VERSIONS_OK=ok CFLAGS_DEBUG=-g CFLAGS_OPTIMIZE=-O if test "$GCC" = "yes" ; then CFLAGS_WARNING="-Wall -fno-strict-aliasing" else CFLAGS_WARNING="" fi TCL_NEEDS_EXP_FILE=0 TCL_BUILD_EXP_FILE="" TCL_EXP_FILE="" # Extract the first word of "ar", so it can be a program name with args. set dummy ar; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo "configure:2609: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_AR'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" ac_dummy="$PATH" for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_prog_AR="ar" break fi done IFS="$ac_save_ifs" fi fi AR="$ac_cv_prog_AR" if test -n "$AR"; then echo "$ac_t""$AR" 1>&6 else echo "$ac_t""no" 1>&6 fi if test "${AR}" = "" ; then { echo "configure: error: Required archive tool 'ar' not found on PATH." 1>&2; exit 1; } fi STLIB_LD='${AR} cr' LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" PLAT_OBJS="" PLAT_SRCS="" case $system in AIX-*) if test "${TCL_THREADS}" = "1" -a "$GCC" != "yes" ; then # AIX requires the _r compiler when gcc isn't being used case "${CC}" in *_r|*_r\ *) # ok ... ;; *) # Make sure only first arg gets _r CC=`echo "$CC" | sed -e 's/^\([^ ]*\)/\1_r/'` ;; esac echo "$ac_t""Using $CC for compiling with threads" 1>&6 fi LIBS="$LIBS -lc" SHLIB_CFLAGS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" LD_LIBRARY_PATH_VAR="LIBPATH" # Check to enable 64-bit flags for compiler/linker on AIX 4+ if test "$do64bit" = "yes" -a "`uname -v`" -gt "3" ; then if test "$GCC" = "yes" ; then echo "configure: warning: 64bit mode not supported with GCC on $system" 1>&2 else do64bit_ok=yes CFLAGS="$CFLAGS -q64" LDFLAGS="$LDFLAGS -q64" RANLIB="${RANLIB} -X64" AR="${AR} -X64" SHLIB_LD_FLAGS="-b64" fi fi if test "`uname -m`" = "ia64" ; then # AIX-5 uses ELF style dynamic libraries on IA-64, but not PPC SHLIB_LD="/usr/ccs/bin/ld -G -z text" # AIX-5 has dl* in libc.so DL_LIBS="" if test "$GCC" = "yes" ; then CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' else CC_SEARCH_FLAGS='-R${LIB_RUNTIME_DIR}' fi LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' else if test "$GCC" = "yes" ; then SHLIB_LD="gcc -shared" else SHLIB_LD="/bin/ld -bhalt:4 -bM:SRE -bE:lib.exp -H512 -T512 -bnoentry" fi SHLIB_LD="${TCL_SRC_DIR}/unix/ldAix ${SHLIB_LD} ${SHLIB_LD_FLAGS}" DL_LIBS="-ldl" CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} TCL_NEEDS_EXP_FILE=1 TCL_EXPORT_FILE_SUFFIX='${VERSION}\$\{DBGX\}.exp' fi # AIX v<=4.1 has some different flags than 4.2+ if test "$system" = "AIX-4.1" -o "`uname -v`" -lt "4" ; then LIBOBJS="$LIBOBJS tclLoadAix.o" DL_LIBS="-lld" fi # On AIX <=v4 systems, libbsd.a has to be linked in to support # non-blocking file IO. This library has to be linked in after # the MATH_LIBS or it breaks the pow() function. The way to # insure proper sequencing, is to add it to the tail of MATH_LIBS. # This library also supplies gettimeofday. # # AIX does not have a timezone field in struct tm. When the AIX # bsd library is used, the timezone global and the gettimeofday # methods are to be avoided for timezone deduction instead, we # deduce the timezone by comparing the localtime result on a # known GMT value. echo $ac_n "checking for gettimeofday in -lbsd""... $ac_c" 1>&6 echo "configure:2722: checking for gettimeofday in -lbsd" >&5 ac_lib_var=`echo bsd'_'gettimeofday | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lbsd $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 libbsd=yes else echo "$ac_t""no" 1>&6 libbsd=no fi if test $libbsd = yes; then MATH_LIBS="$MATH_LIBS -lbsd" cat >> confdefs.h <<\EOF #define USE_DELTA_FOR_TZ 1 EOF fi ;; BeOS*) SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -nostart' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" #----------------------------------------------------------- # Check for inet_ntoa in -lbind, for BeOS (which also needs # -lsocket, even if the network functions are in -lnet which # is always linked to, for compatibility. #----------------------------------------------------------- echo $ac_n "checking for inet_ntoa in -lbind""... $ac_c" 1>&6 echo "configure:2783: checking for inet_ntoa in -lbind" >&5 ac_lib_var=`echo bind'_'inet_ntoa | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lbind $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 LIBS="$LIBS -lbind -lsocket" else echo "$ac_t""no" 1>&6 fi ;; BSD/OS-2.1*|BSD/OS-3*) SHLIB_CFLAGS="" SHLIB_LD="shlicc -r" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; BSD/OS-4.*) SHLIB_CFLAGS="-export-dynamic -fPIC" SHLIB_LD='${CC} -shared' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" LDFLAGS="$LDFLAGS -export-dynamic" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; CYGWIN_*|MINGW32*) SHLIB_CFLAGS="" SHLIB_LD='${CC} -shared' SHLIB_SUFFIX=".dll" DL_OBJS="tclLoadDl.o tclWinError.o" DL_LIBS="-ldl" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" TCL_SHLIB_LD_EXTRAS='-Wl,--out-implib,$@.a' echo $ac_n "checking for Cygwin version of gcc""... $ac_c" 1>&6 echo "configure:2852: checking for Cygwin version of gcc" >&5 if eval "test \"`echo '$''{'ac_cv_cygwin'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_cygwin=no else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* ac_cv_cygwin=yes fi rm -f conftest* fi echo "$ac_t""$ac_cv_cygwin" 1>&6 if test "$ac_cv_cygwin" = "no"; then { echo "configure: error: ${CC} is not a cygwin compiler." 1>&2; exit 1; } fi if test "x${TCL_THREADS}" = "x0"; then { echo "configure: error: CYGWIN compile is only supported with --enable-threads" 1>&2; exit 1; } fi if test "x${SHARED_BUILD}" = "x1" -a ! -f "../win/tcldde13.dll" -a ! -f "../win/tk84.dll"; then { echo "configure: error: Please configure and make the ../win directory first." 1>&2; exit 1; } fi ;; dgux*) SHLIB_CFLAGS="-K PIC" SHLIB_LD='${CC} -G' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; Haiku*) LDFLAGS="$LDFLAGS -Wl,--export-dynamic" SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS}' DL_OBJS="tclLoadDl.o" DL_LIBS="-lroot" echo $ac_n "checking for inet_ntoa in -lnetwork""... $ac_c" 1>&6 echo "configure:2910: checking for inet_ntoa in -lnetwork" >&5 ac_lib_var=`echo network'_'inet_ntoa | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lnetwork $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 LIBS="$LIBS -lnetwork" else echo "$ac_t""no" 1>&6 fi ;; HP-UX-*.11.*) # Use updated header definitions where possible cat >> confdefs.h <<\EOF #define _XOPEN_SOURCE_EXTENDED 1 EOF cat >> confdefs.h <<\EOF #define _XOPEN_SOURCE 1 EOF LIBS="$LIBS -lxnet" # Use the XOPEN network library if test "`uname -m`" = "ia64" ; then SHLIB_SUFFIX=".so" else SHLIB_SUFFIX=".sl" fi echo $ac_n "checking for shl_load in -ldld""... $ac_c" 1>&6 echo "configure:2968: checking for shl_load in -ldld" >&5 ac_lib_var=`echo dld'_'shl_load | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-ldld $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 tcl_ok=yes else echo "$ac_t""no" 1>&6 tcl_ok=no fi if test "$tcl_ok" = yes; then SHLIB_CFLAGS="+z" SHLIB_LD="ld -b" DL_OBJS="tclLoadShl.o" DL_LIBS="-ldld" LDFLAGS="$LDFLAGS -Wl,-E" CC_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.' LD_SEARCH_FLAGS='+s +b ${LIB_RUNTIME_DIR}:.' LD_LIBRARY_PATH_VAR="SHLIB_PATH" fi if test "$GCC" = "yes" ; then SHLIB_LD='${CC} -shared' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} fi # Users may want PA-RISC 1.1/2.0 portable code - needs HP cc #CFLAGS="$CFLAGS +DAportable" # Check to enable 64-bit flags for compiler/linker if test "$do64bit" = "yes" ; then if test "$GCC" = "yes" ; then case `${CC} -dumpmachine` in hppa64*) # 64-bit gcc in use. Fix flags for GNU ld. do64bit_ok=yes SHLIB_LD='${CC} -shared' if test $doRpath = yes ; then CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ;; *) echo "configure: warning: 64bit mode not supported with GCC on $system" 1>&2 ;; esac else do64bit_ok=yes CFLAGS="$CFLAGS +DD64" LDFLAGS="$LDFLAGS +DD64" fi fi ;; HP-UX-*.08.*|HP-UX-*.09.*|HP-UX-*.10.*) SHLIB_SUFFIX=".sl" echo $ac_n "checking for shl_load in -ldld""... $ac_c" 1>&6 echo "configure:3053: checking for shl_load in -ldld" >&5 ac_lib_var=`echo dld'_'shl_load | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-ldld $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 tcl_ok=yes else echo "$ac_t""no" 1>&6 tcl_ok=no fi if test "$tcl_ok" = yes; then SHLIB_CFLAGS="+z" SHLIB_LD="ld -b" SHLIB_LD_LIBS="" DL_OBJS="tclLoadShl.o" DL_LIBS="-ldld" LDFLAGS="$LDFLAGS -Wl,-E" CC_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.' LD_SEARCH_FLAGS='+s +b ${LIB_RUNTIME_DIR}:.' LD_LIBRARY_PATH_VAR="SHLIB_PATH" fi ;; IRIX-4.*) SHLIB_CFLAGS="-G 0" SHLIB_SUFFIX=".a" SHLIB_LD="echo tclLdAout $CC \{$SHLIB_CFLAGS\} | `pwd`/tclsh -r -G 0" DL_OBJS="tclLoadAout.o" DL_LIBS="" LDFLAGS="$LDFLAGS -Wl,-D,08000000" CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} SHARED_LIB_SUFFIX='${VERSION}\$\{DBGX\}.a' ;; IRIX-5.*) SHLIB_CFLAGS="" SHLIB_LD="ld -shared -rdata_shared" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" if test $doRpath = yes ; then CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' fi ;; IRIX-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" if test $doRpath = yes ; then CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' fi if test "$GCC" = "yes" ; then CFLAGS="$CFLAGS -mabi=n32" LDFLAGS="$LDFLAGS -mabi=n32" else case $system in IRIX-6.3) # Use to build 6.2 compatible binaries on 6.3. CFLAGS="$CFLAGS -n32 -D_OLD_TERMIOS" ;; *) CFLAGS="$CFLAGS -n32" ;; esac LDFLAGS="$LDFLAGS -n32" fi ;; IRIX64-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" if test $doRpath = yes ; then CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' fi # Check to enable 64-bit flags for compiler/linker if test "$do64bit" = "yes" ; then if test "$GCC" = "yes" ; then echo "configure: warning: 64bit mode not supported by gcc" 1>&2 else do64bit_ok=yes SHLIB_LD="ld -64 -shared -rdata_shared" CFLAGS="$CFLAGS -64" LDFLAGS="$LDFLAGS -64" fi fi ;; Linux*|GNU*|NetBSD-Debian) SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" CFLAGS_OPTIMIZE="-O2" # egcs-2.91.66 on Redhat Linux 6.0 generates lots of warnings # when you inline the string and math operations. Turn this off to # get rid of the warnings. #CFLAGS_OPTIMIZE="${CFLAGS_OPTIMIZE} -D__NO_STRING_INLINES -D__NO_MATH_INLINES" if test "$have_dl" = yes; then SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS}' DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" LDFLAGS="$LDFLAGS -Wl,--export-dynamic" if test $doRpath = yes ; then CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} else ac_safe=`echo "dld.h" | sed 'y%./+-%__p_%'` echo $ac_n "checking for dld.h""... $ac_c" 1>&6 echo "configure:3199: checking for dld.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:3209: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 SHLIB_LD="ld -shared" DL_OBJS="tclLoadDld.o" DL_LIBS="-ldld" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" else echo "$ac_t""no" 1>&6 fi fi if test "`uname -m`" = "alpha" ; then CFLAGS="$CFLAGS -mieee" fi if test $do64bit = yes; then echo $ac_n "checking if compiler accepts -m64 flag""... $ac_c" 1>&6 echo "configure:3241: checking if compiler accepts -m64 flag" >&5 if eval "test \"`echo '$''{'tcl_cv_cc_m64'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else hold_cflags=$CFLAGS CFLAGS="$CFLAGS -m64" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* tcl_cv_cc_m64=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_cc_m64=no fi rm -f conftest* CFLAGS=$hold_cflags fi echo "$ac_t""$tcl_cv_cc_m64" 1>&6 if test $tcl_cv_cc_m64 = yes; then CFLAGS="$CFLAGS -m64" do64bit_ok=yes fi fi # The combo of gcc + glibc has a bug related # to inlining of functions like strtod(). The # -fno-builtin flag should address this problem # but it does not work. The -fno-inline flag # is kind of overkill but it works. # Disable inlining only when one of the # files in compat/*.c is being linked in. if test x"${LIBOBJS}" != x ; then CFLAGS="$CFLAGS -fno-inline" fi cat >> confdefs.h <<\EOF #define PEEK_XCLOSEIM 1 EOF ;; Lynx*) SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" CFLAGS_OPTIMIZE=-02 SHLIB_LD='${CC} -shared' DL_OBJS="tclLoadDl.o" DL_LIBS="-mshared -ldl" LD_FLAGS="-Wl,--export-dynamic" if test $doRpath = yes ; then CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi ;; MP-RAS-02*) SHLIB_CFLAGS="-K PIC" SHLIB_LD='${CC} -G' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; MP-RAS-*) SHLIB_CFLAGS="-K PIC" SHLIB_LD='${CC} -G' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" LDFLAGS="$LDFLAGS -Wl,-Bexport" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; OpenBSD-*) arch=`arch -s` case "$arch" in m88k|vax) SHLIB_CFLAGS="" SHLIB_LD="echo tclLdAout $CC \{$SHLIB_CFLAGS\} | `pwd`/tclsh -r" SHLIB_SUFFIX=".a" DL_OBJS="tclLoadAout.o" DL_LIBS="" LDFLAGS="" CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.a' ;; *) # OpenBSD/SPARC[64] needs -fPIC, -fpic will not do. case `machine` in sparc|sparc64) SHLIB_CFLAGS="-fPIC";; *) SHLIB_CFLAGS="-fpic";; esac SHLIB_LD="${CC} -shared ${SHLIB_CFLAGS}" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" if test $doRpath = yes ; then CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.so.1.0' echo $ac_n "checking for ELF""... $ac_c" 1>&6 echo "configure:3359: checking for ELF" >&5 if eval "test \"`echo '$''{'tcl_cv_ld_elf'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5 | egrep "yes" >/dev/null 2>&1; then rm -rf conftest* tcl_cv_ld_elf=yes else rm -rf conftest* tcl_cv_ld_elf=no fi rm -f conftest* fi echo "$ac_t""$tcl_cv_ld_elf" 1>&6 if test $tcl_cv_ld_elf = yes; then LDFLAGS=-Wl,-export-dynamic else LDFLAGS="" fi ;; esac # OpenBSD doesn't do version numbers with dots. UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.a' TCL_LIB_VERSIONS_OK=nodots ;; NetBSD-*) # NetBSD has ELF and can use 'cc -shared' to build shared libs SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" LDFLAGS="$LDFLAGS -export-dynamic" if test $doRpath = yes ; then CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} if test "${TCL_THREADS}" = "1" ; then # The -pthread needs to go in the CFLAGS, not LIBS LIBS=`echo $LIBS | sed s/-pthread//` CFLAGS="$CFLAGS -pthread" LDFLAGS="$LDFLAGS -pthread" fi case $system in FreeBSD-3.*) # FreeBSD-3 doesn't handle version numbers with dots. UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so' TCL_LIB_VERSIONS_OK=nodots ;; esac ;; FreeBSD-*) # This configuration from FreeBSD Ports. SHLIB_CFLAGS="-fPIC" SHLIB_LD="${CC} -shared" TCL_SHLIB_LD_EXTRAS="-Wl,-soname,\$@" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" LDFLAGS="" if test $doRpath = yes ; then CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi if test "${TCL_THREADS}" = "1" ; then # The -pthread needs to go in the LDFLAGS, not LIBS LIBS=`echo $LIBS | sed s/-pthread//` CFLAGS="$CFLAGS $PTHREAD_CFLAGS" LDFLAGS="$LDFLAGS $PTHREAD_LIBS" fi # Version numbers are dot-stripped by system policy. TCL_TRIM_DOTS=`echo ${VERSION} | tr -d .` UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.so.1' TCL_LIB_VERSIONS_OK=nodots ;; Darwin-*) CFLAGS_OPTIMIZE="-Os" SHLIB_CFLAGS="-fno-common" # To avoid discrepancies between what headers configure sees during # preprocessing tests and compiling tests, move any -isysroot and # -mmacosx-version-min flags from CFLAGS to CPPFLAGS: CPPFLAGS="${CPPFLAGS} `echo " ${CFLAGS}" | \ awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ if ($i~/^(isysroot|mmacosx-version-min)/) print "-"$i}'`" CFLAGS="`echo " ${CFLAGS}" | \ awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ if (!($i~/^(isysroot|mmacosx-version-min)/)) print "-"$i}'`" if test $do64bit = yes; then case `arch` in ppc) echo $ac_n "checking if compiler accepts -arch ppc64 flag""... $ac_c" 1>&6 echo "configure:3466: checking if compiler accepts -arch ppc64 flag" >&5 if eval "test \"`echo '$''{'tcl_cv_cc_arch_ppc64'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else hold_cflags=$CFLAGS CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* tcl_cv_cc_arch_ppc64=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_cc_arch_ppc64=no fi rm -f conftest* CFLAGS=$hold_cflags fi echo "$ac_t""$tcl_cv_cc_arch_ppc64" 1>&6 if test $tcl_cv_cc_arch_ppc64 = yes; then CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" do64bit_ok=yes fi;; i386) echo $ac_n "checking if compiler accepts -arch x86_64 flag""... $ac_c" 1>&6 echo "configure:3501: checking if compiler accepts -arch x86_64 flag" >&5 if eval "test \"`echo '$''{'tcl_cv_cc_arch_x86_64'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else hold_cflags=$CFLAGS CFLAGS="$CFLAGS -arch x86_64" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* tcl_cv_cc_arch_x86_64=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_cc_arch_x86_64=no fi rm -f conftest* CFLAGS=$hold_cflags fi echo "$ac_t""$tcl_cv_cc_arch_x86_64" 1>&6 if test $tcl_cv_cc_arch_x86_64 = yes; then CFLAGS="$CFLAGS -arch x86_64" do64bit_ok=yes fi;; *) echo "configure: warning: Don't know how enable 64-bit on architecture `arch`" 1>&2;; esac else # Check for combined 32-bit and 64-bit fat build echo "$CFLAGS " | grep -E -q -- '-arch (ppc64|x86_64) ' && \ echo "$CFLAGS " | grep -E -q -- '-arch (ppc|i386) ' && \ fat_32_64=yes fi SHLIB_LD='${CC} -dynamiclib ${CFLAGS} ${LDFLAGS}' echo $ac_n "checking if ld accepts -single_module flag""... $ac_c" 1>&6 echo "configure:3545: checking if ld accepts -single_module flag" >&5 if eval "test \"`echo '$''{'tcl_cv_ld_single_module'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -dynamiclib -Wl,-single_module" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* tcl_cv_ld_single_module=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_ld_single_module=no fi rm -f conftest* LDFLAGS=$hold_ldflags fi echo "$ac_t""$tcl_cv_ld_single_module" 1>&6 if test $tcl_cv_ld_single_module = yes; then SHLIB_LD="${SHLIB_LD} -Wl,-single_module" fi SHLIB_SUFFIX=".dylib" DL_OBJS="tclLoadDyld.o" DL_LIBS="" # Don't use -prebind when building for Mac OS X 10.4 or later only: test "`echo "${MACOSX_DEPLOYMENT_TARGET}" | awk -F '10\\.' '{print int($2)}'`" -lt 4 -a \ "`echo "${CPPFLAGS}" | awk -F '-mmacosx-version-min=10\\.' '{print int($2)}'`" -lt 4 && \ LDFLAGS="$LDFLAGS -prebind" LDFLAGS="$LDFLAGS -headerpad_max_install_names" echo $ac_n "checking if ld accepts -search_paths_first flag""... $ac_c" 1>&6 echo "configure:3586: checking if ld accepts -search_paths_first flag" >&5 if eval "test \"`echo '$''{'tcl_cv_ld_search_paths_first'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -Wl,-search_paths_first" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* tcl_cv_ld_search_paths_first=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_ld_search_paths_first=no fi rm -f conftest* LDFLAGS=$hold_ldflags fi echo "$ac_t""$tcl_cv_ld_search_paths_first" 1>&6 if test $tcl_cv_ld_search_paths_first = yes; then LDFLAGS="$LDFLAGS -Wl,-search_paths_first" fi CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" LD_LIBRARY_PATH_VAR="DYLD_LIBRARY_PATH" PLAT_OBJS=\$\(MAC\_OSX_OBJS\) PLAT_SRCS=\$\(MAC\_OSX_SRCS\) echo $ac_n "checking whether to use CoreFoundation""... $ac_c" 1>&6 echo "configure:3624: checking whether to use CoreFoundation" >&5 # Check whether --enable-corefoundation or --disable-corefoundation was given. if test "${enable_corefoundation+set}" = set; then enableval="$enable_corefoundation" tcl_corefoundation=$enableval else tcl_corefoundation=yes fi echo "$ac_t""$tcl_corefoundation" 1>&6 if test $tcl_corefoundation = yes; then echo $ac_n "checking for CoreFoundation.framework""... $ac_c" 1>&6 echo "configure:3636: checking for CoreFoundation.framework" >&5 if eval "test \"`echo '$''{'tcl_cv_lib_corefoundation'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else hold_libs=$LIBS if test "$fat_32_64" = yes; then for v in CFLAGS CPPFLAGS LDFLAGS; do # On Tiger there is no 64-bit CF, so remove 64-bit archs # from CFLAGS et al. while testing for presence of CF. # 64-bit CF is disabled in tclUnixPort.h if necessary. eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc64 / /g" -e "s/-arch x86_64 / /g"`"' done; fi LIBS="$LIBS -framework CoreFoundation" cat > conftest.$ac_ext < int main() { CFBundleRef b = CFBundleGetMainBundle(); ; return 0; } EOF if { (eval echo configure:3657: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* tcl_cv_lib_corefoundation=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_lib_corefoundation=no fi rm -f conftest* if test "$fat_32_64" = yes; then for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="$hold_'$v'"' done; fi; LIBS=$hold_libs fi echo "$ac_t""$tcl_cv_lib_corefoundation" 1>&6 if test $tcl_cv_lib_corefoundation = yes; then LIBS="$LIBS -framework CoreFoundation" cat >> confdefs.h <<\EOF #define HAVE_COREFOUNDATION 1 EOF else tcl_corefoundation=no fi if test "$fat_32_64" = yes -a $tcl_corefoundation = yes; then echo $ac_n "checking for 64-bit CoreFoundation""... $ac_c" 1>&6 echo "configure:3684: checking for 64-bit CoreFoundation" >&5 if eval "test \"`echo '$''{'tcl_cv_lib_corefoundation_64'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else for v in CFLAGS CPPFLAGS LDFLAGS; do eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' done cat > conftest.$ac_ext < int main() { CFBundleRef b = CFBundleGetMainBundle(); ; return 0; } EOF if { (eval echo configure:3700: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* tcl_cv_lib_corefoundation_64=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_lib_corefoundation_64=no fi rm -f conftest* for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="$hold_'$v'"' done fi echo "$ac_t""$tcl_cv_lib_corefoundation_64" 1>&6 if test $tcl_cv_lib_corefoundation_64 = no; then cat >> confdefs.h <<\EOF #define NO_COREFOUNDATION_64 1 EOF fi fi fi cat >> confdefs.h <<\EOF #define MAC_OSX_TCL 1 EOF ;; NEXTSTEP-*) SHLIB_CFLAGS="" SHLIB_LD='${CC} -nostdlib -r' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadNext.o" DL_LIBS="" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; OS/390-*) SHLIB_LD_LIBS="" CFLAGS_OPTIMIZE="" # Optimizer is buggy cat >> confdefs.h <<\EOF #define _OE_SOCKETS 1 EOF ;; OSF1-1.0|OSF1-1.1|OSF1-1.2) # OSF/1 1.[012] from OSF, and derivatives, including Paragon OSF/1 SHLIB_CFLAGS="" # Hack: make package name same as library name SHLIB_LD='ld -R -export :' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadOSF.o" DL_LIBS="" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; OSF1-1.*) # OSF/1 1.3 from OSF using ELF, and derivatives, including AD2 SHLIB_CFLAGS="-fPIC" if test "$SHARED_BUILD" = "1" ; then SHLIB_LD="ld -shared" else SHLIB_LD="ld -non_shared" fi SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; OSF1-V*) # Digital OSF/1 SHLIB_CFLAGS="" if test "$SHARED_BUILD" = "1" ; then SHLIB_LD='ld -shared -expect_unresolved "*"' else SHLIB_LD='ld -non_shared -expect_unresolved "*"' fi SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" if test $doRpath = yes ; then CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' fi if test "$GCC" = "yes" ; then CFLAGS="$CFLAGS -mieee" else CFLAGS="$CFLAGS -DHAVE_TZSET -std1 -ieee" fi # see pthread_intro(3) for pthread support on osf1, k.furukawa if test "${TCL_THREADS}" = "1" ; then CFLAGS="$CFLAGS -DHAVE_PTHREAD_ATTR_SETSTACKSIZE" CFLAGS="$CFLAGS -DTCL_THREAD_STACK_MIN=PTHREAD_STACK_MIN*64" LIBS=`echo $LIBS | sed s/-lpthreads//` if test "$GCC" = "yes" ; then LIBS="$LIBS -lpthread -lmach -lexc" else CFLAGS="$CFLAGS -pthread" LDFLAGS="$LDFLAGS -pthread" fi fi ;; QNX-6*) # QNX RTP # This may work for all QNX, but it was only reported for v6. SHLIB_CFLAGS="-fPIC" SHLIB_LD="ld -Bshareable -x" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" # dlopen is in -lc on QNX DL_LIBS="" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; RISCos-*) SHLIB_CFLAGS="-G 0" SHLIB_LD="echo tclLdAout $CC \{$SHLIB_CFLAGS\} | `pwd`/tclsh -r -G 0" SHLIB_SUFFIX=".a" DL_OBJS="tclLoadAout.o" DL_LIBS="" LDFLAGS="$LDFLAGS -Wl,-D,08000000" CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ;; SCO_SV-3.2*) # Note, dlopen is available only on SCO 3.2.5 and greater. However, # this test works, since "uname -s" was non-standard in 3.2.4 and # below. if test "$GCC" = "yes" ; then SHLIB_CFLAGS="-fPIC -melf" LDFLAGS="$LDFLAGS -melf -Wl,-Bexport" else SHLIB_CFLAGS="-Kpic -belf" LDFLAGS="$LDFLAGS -belf -Wl,-Bexport" fi SHLIB_LD="ld -G" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SINIX*5.4*) SHLIB_CFLAGS="-K PIC" SHLIB_LD='${CC} -G' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SunOS-4*) SHLIB_CFLAGS="-PIC" SHLIB_LD="ld" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} # SunOS can't handle version numbers with dots in them in library # specs, like -ltcl7.5, so use -ltcl75 instead. Also, it # requires an extra version number at the end of .so file names. # So, the library has to have a name like libtcl75.so.1.0 SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.so.1.0' UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.a' TCL_LIB_VERSIONS_OK=nodots ;; SunOS-5.[0-6]) # Careful to not let 5.10+ fall into this case # Note: If _REENTRANT isn't defined, then Solaris # won't define thread-safe library routines. cat >> confdefs.h <<\EOF #define _REENTRANT 1 EOF cat >> confdefs.h <<\EOF #define _POSIX_PTHREAD_SEMANTICS 1 EOF SHLIB_CFLAGS="-KPIC" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" if test "$GCC" = "yes" ; then SHLIB_LD='${CC} -shared' CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} else SHLIB_LD="/usr/ccs/bin/ld -G -z text" CC_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} fi ;; SunOS-5*) # Note: If _REENTRANT isn't defined, then Solaris # won't define thread-safe library routines. cat >> confdefs.h <<\EOF #define _REENTRANT 1 EOF cat >> confdefs.h <<\EOF #define _POSIX_PTHREAD_SEMANTICS 1 EOF SHLIB_CFLAGS="-KPIC" # Check to enable 64-bit flags for compiler/linker if test "$do64bit" = "yes" ; then arch=`isainfo` if test "$arch" = "sparcv9 sparc" ; then if test "$GCC" = "yes" ; then if test "`gcc -dumpversion | awk -F. '{print $1}'`" -lt "3" ; then echo "configure: warning: 64bit mode not supported with GCC < 3.2 on $system" 1>&2 else do64bit_ok=yes CFLAGS="$CFLAGS -m64 -mcpu=v9" LDFLAGS="$LDFLAGS -m64 -mcpu=v9" SHLIB_CFLAGS="-fPIC" fi else do64bit_ok=yes if test "$do64bitVIS" = "yes" ; then CFLAGS="$CFLAGS -xarch=v9a" LDFLAGS="$LDFLAGS -xarch=v9a" else CFLAGS="$CFLAGS -xarch=v9" LDFLAGS="$LDFLAGS -xarch=v9" fi # Solaris 64 uses this as well #LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH_64" fi elif test "$arch" = "amd64 i386" ; then if test "$GCC" = "yes" ; then case $system in SunOS-5.1[1-9]*|SunOS-5.[2-9][0-9]*) do64bit_ok=yes CFLAGS="$CFLAGS -m64" LDFLAGS="$LDFLAGS -m64";; *) echo "configure: warning: 64bit mode not supported with GCC on $system" 1>&2;; esac else do64bit_ok=yes case $system in SunOS-5.1[1-9]*|SunOS-5.[2-9][0-9]*) CFLAGS="$CFLAGS -m64" LDFLAGS="$LDFLAGS -m64";; *) CFLAGS="$CFLAGS -xarch=amd64" LDFLAGS="$LDFLAGS -xarch=amd64";; esac fi else echo "configure: warning: 64bit mode not supported for $arch" 1>&2 fi fi SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" if test "$GCC" = "yes" ; then SHLIB_LD="$CC -shared" CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} if test "$do64bit_ok" = "yes" ; then if test "$arch" = "sparcv9 sparc" ; then # We need to specify -static-libgcc or we need to # add the path to the sparv9 libgcc. SHLIB_LD="$SHLIB_LD -m64 -mcpu=v9 -static-libgcc" # for finding sparcv9 libgcc, get the regular libgcc # path, remove so name and append 'sparcv9' #v9gcclibdir="`gcc -print-file-name=libgcc_s.so` | ..." #CC_SEARCH_FLAGS="${CC_SEARCH_FLAGS},-R,$v9gcclibdir" elif test "$arch" = "amd64 i386" ; then SHLIB_LD="$SHLIB_LD -m64 -static-libgcc" fi fi else case $system in SunOS-5.[1-9][0-9]*) SHLIB_LD='${CC} -G -z text ${LDFLAGS}';; *) SHLIB_LD="/usr/ccs/bin/ld -G -z text";; esac CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' fi ;; ULTRIX-4.*) SHLIB_CFLAGS="-G 0" SHLIB_SUFFIX=".a" SHLIB_LD="echo tclLdAout $CC \{$SHLIB_CFLAGS\} | `pwd`/tclsh -r -G 0" DL_OBJS="tclLoadAout.o" DL_LIBS="" LDFLAGS="$LDFLAGS -Wl,-D,08000000" CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} if test "$GCC" != "yes" ; then CFLAGS="$CFLAGS -DHAVE_TZSET -std1" fi ;; UNIX_SV* | UnixWare-5*) SHLIB_CFLAGS="-KPIC" SHLIB_LD='${CC} -G' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" # Some UNIX_SV* systems (unixware 1.1.2 for example) have linkers # that don't grok the -Bexport option. Test that it does. echo $ac_n "checking for ld accepts -Bexport flag""... $ac_c" 1>&6 echo "configure:4029: checking for ld accepts -Bexport flag" >&5 if eval "test \"`echo '$''{'tcl_cv_ld_Bexport'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -Wl,-Bexport" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* tcl_cv_ld_Bexport=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_ld_Bexport=no fi rm -f conftest* LDFLAGS=$hold_ldflags fi echo "$ac_t""$tcl_cv_ld_Bexport" 1>&6 if test $tcl_cv_ld_Bexport = yes; then LDFLAGS="$LDFLAGS -Wl,-Bexport" fi CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; esac if test "$do64bit" = "yes" -a "$do64bit_ok" = "no" ; then echo "configure: warning: 64bit support being disabled -- don't know magic for this platform" 1>&2 fi # Step 4: If pseudo-static linking is in use (see K. B. Kenny, "Dynamic # Loading for Tcl -- What Became of It?". Proc. 2nd Tcl/Tk Workshop, # New Orleans, LA, Computerized Processes Unlimited, 1994), then we need # to determine which of several header files defines the a.out file # format (a.out.h, sys/exec.h, or sys/exec_aout.h). At present, we # support only a file format that is more or less version-7-compatible. # In particular, # - a.out files must begin with `struct exec'. # - the N_TXTOFF on the `struct exec' must compute the seek address # of the text segment # - The `struct exec' must contain a_magic, a_text, a_data, a_bss # and a_entry fields. # The following compilation should succeed if and only if either sys/exec.h # or a.out.h is usable for the purpose. # # Note that the modified COFF format used on MIPS Ultrix 4.x is usable; the # `struct exec' includes a second header that contains information that # duplicates the v7 fields that are needed. if test "x$DL_OBJS" = "xtclLoadAout.o" ; then echo $ac_n "checking sys/exec.h""... $ac_c" 1>&6 echo "configure:4094: checking sys/exec.h" >&5 if eval "test \"`echo '$''{'tcl_cv_sysexec_h'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { struct exec foo; unsigned long seek; int flag; #if defined(__mips) || defined(mips) seek = N_TXTOFF (foo.ex_f, foo.ex_o); #else seek = N_TXTOFF (foo); #endif flag = (foo.a_magic == OMAGIC); return foo.a_text + foo.a_data + foo.a_bss + foo.a_entry; ; return 0; } EOF if { (eval echo configure:4118: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_cv_sysexec_h=usable else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_sysexec_h=unusable fi rm -f conftest* fi echo "$ac_t""$tcl_cv_sysexec_h" 1>&6 if test $tcl_cv_sysexec_h = usable; then cat >> confdefs.h <<\EOF #define USE_SYS_EXEC_H 1 EOF else echo $ac_n "checking a.out.h""... $ac_c" 1>&6 echo "configure:4138: checking a.out.h" >&5 if eval "test \"`echo '$''{'tcl_cv_aout_h'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { struct exec foo; unsigned long seek; int flag; #if defined(__mips) || defined(mips) seek = N_TXTOFF (foo.ex_f, foo.ex_o); #else seek = N_TXTOFF (foo); #endif flag = (foo.a_magic == OMAGIC); return foo.a_text + foo.a_data + foo.a_bss + foo.a_entry; ; return 0; } EOF if { (eval echo configure:4162: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_cv_aout_h=usable else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_aout_h=unusable fi rm -f conftest* fi echo "$ac_t""$tcl_cv_aout_h" 1>&6 if test $tcl_cv_aout_h = usable; then cat >> confdefs.h <<\EOF #define USE_A_OUT_H 1 EOF else echo $ac_n "checking sys/exec_aout.h""... $ac_c" 1>&6 echo "configure:4182: checking sys/exec_aout.h" >&5 if eval "test \"`echo '$''{'tcl_cv_sysexecaout_h'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { struct exec foo; unsigned long seek; int flag; #if defined(__mips) || defined(mips) seek = N_TXTOFF (foo.ex_f, foo.ex_o); #else seek = N_TXTOFF (foo); #endif flag = (foo.a_midmag == OMAGIC); return foo.a_text + foo.a_data + foo.a_bss + foo.a_entry; ; return 0; } EOF if { (eval echo configure:4206: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_cv_sysexecaout_h=usable else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_sysexecaout_h=unusable fi rm -f conftest* fi echo "$ac_t""$tcl_cv_sysexecaout_h" 1>&6 if test $tcl_cv_sysexecaout_h = usable; then cat >> confdefs.h <<\EOF #define USE_SYS_EXEC_AOUT_H 1 EOF else DL_OBJS="" fi fi fi fi # Step 5: disable dynamic loading if requested via a command-line switch. # Check whether --enable-load or --disable-load was given. if test "${enable_load+set}" = set; then enableval="$enable_load" tcl_ok=$enableval else tcl_ok=yes fi if test "$tcl_ok" = "no"; then DL_OBJS="" fi if test "x$DL_OBJS" != "x" ; then BUILD_DLTEST="\$(DLTEST_TARGETS)" else echo "Can't figure out how to do dynamic loading or shared libraries" echo "on this system." SHLIB_CFLAGS="" SHLIB_LD="" SHLIB_SUFFIX="" DL_OBJS="tclLoadNone.o" DL_LIBS="" LDFLAGS="$LDFLAGS_ORIG" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" BUILD_DLTEST="" fi # If we're running gcc, then change the C flags for compiling shared # libraries to the right flags for gcc, instead of those for the # standard manufacturer compiler. if test "$DL_OBJS" != "tclLoadNone.o" -a "$GCC" = yes ; then case $system in AIX-*) ;; BSD/OS*) ;; CYGWIN_*|MINGW32_*) ;; IRIX*) ;; NetBSD-*|FreeBSD-*|OpenBSD-*) ;; Darwin-*) ;; RISCos-*) ;; SCO_SV-3.2*) ;; ULTRIX-4.*) ;; *) SHLIB_CFLAGS="-fPIC" ;; esac fi if test "$SHARED_LIB_SUFFIX" = "" ; then SHARED_LIB_SUFFIX='${VERSION}\$\{DBGX\}${SHLIB_SUFFIX}' fi if test "$UNSHARED_LIB_SUFFIX" = "" ; then UNSHARED_LIB_SUFFIX='${VERSION}\$\{DBGX\}.a' fi DLL_INSTALL_DIR="\$(LIB_INSTALL_DIR)" if test "${SHARED_BUILD}" = "1" && test "${SHLIB_SUFFIX}" != "" ; then LIB_SUFFIX=${SHARED_LIB_SUFFIX} MAKE_LIB='${SHLIB_LD} -o $@ ${OBJS} ${SHLIB_LD_LIBS} ${TCL_SHLIB_LD_EXTRAS} ${TK_SHLIB_LD_EXTRAS} ${LD_SEARCH_FLAGS}' if test "${SHLIB_SUFFIX}" = ".dll"; then INSTALL_LIB='$(INSTALL_LIBRARY) $(LIB_FILE) "$(BIN_INSTALL_DIR)/$(LIB_FILE)"' DLL_INSTALL_DIR="\$(BIN_INSTALL_DIR)" else INSTALL_LIB='$(INSTALL_LIBRARY) $(LIB_FILE) "$(LIB_INSTALL_DIR)/$(LIB_FILE)"' fi else LIB_SUFFIX=${UNSHARED_LIB_SUFFIX} if test "$RANLIB" = "" ; then MAKE_LIB='$(STLIB_LD) $@ ${OBJS}' INSTALL_LIB='$(INSTALL_LIBRARY) $(LIB_FILE) "$(LIB_INSTALL_DIR)/$(LIB_FILE)"' else MAKE_LIB='${STLIB_LD} $@ ${OBJS} ; ${RANLIB} $@' INSTALL_LIB='$(INSTALL_LIBRARY) $(LIB_FILE) "$(LIB_INSTALL_DIR)/$(LIB_FILE)" ; (cd "$(LIB_INSTALL_DIR)" ; $(RANLIB) $(LIB_FILE))' fi fi # Stub lib does not depend on shared/static configuration if test "$RANLIB" = "" ; then MAKE_STUB_LIB='${STLIB_LD} $@ ${STUB_LIB_OBJS}' INSTALL_STUB_LIB='$(INSTALL_LIBRARY) $(STUB_LIB_FILE) "$(LIB_INSTALL_DIR)/$(STUB_LIB_FILE)"' else MAKE_STUB_LIB='${STLIB_LD} $@ ${STUB_LIB_OBJS} ; ${RANLIB} $@' INSTALL_STUB_LIB='$(INSTALL_LIBRARY) $(STUB_LIB_FILE) "$(LIB_INSTALL_DIR)/$(STUB_LIB_FILE)" ; (cd "$(LIB_INSTALL_DIR)" ; $(RANLIB) $(STUB_LIB_FILE))' fi # See if the compiler supports casting to a union type. # This is used to stop gcc from printing a compiler # warning when initializing a union member. echo $ac_n "checking for cast to union support""... $ac_c" 1>&6 echo "configure:4324: checking for cast to union support" >&5 if eval "test \"`echo '$''{'tcl_cv_cast_to_union'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_cv_cast_to_union=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_cast_to_union=no fi rm -f conftest* fi echo "$ac_t""$tcl_cv_cast_to_union" 1>&6 if test "$tcl_cv_cast_to_union" = "yes"; then cat >> confdefs.h <<\EOF #define HAVE_CAST_TO_UNION 1 EOF fi echo $ac_n "checking for build with symbols""... $ac_c" 1>&6 echo "configure:4394: checking for build with symbols" >&5 # Check whether --enable-symbols or --disable-symbols was given. if test "${enable_symbols+set}" = set; then enableval="$enable_symbols" tcl_ok=$enableval else tcl_ok=no fi # FIXME: Currently, LDFLAGS_DEFAULT is not used, it should work like CFLAGS_DEFAULT. if test "$tcl_ok" = "no"; then CFLAGS_DEFAULT='$(CFLAGS_OPTIMIZE)' LDFLAGS_DEFAULT='$(LDFLAGS_OPTIMIZE)' DBGX="" cat >> confdefs.h <<\EOF #define NDEBUG 1 EOF echo "$ac_t""no" 1>&6 else CFLAGS_DEFAULT='$(CFLAGS_DEBUG)' LDFLAGS_DEFAULT='$(LDFLAGS_DEBUG)' DBGX=g if test "$tcl_ok" = "yes"; then echo "$ac_t""yes (standard debugging)" 1>&6 fi fi if test "$tcl_ok" = "mem" -o "$tcl_ok" = "all"; then cat >> confdefs.h <<\EOF #define TCL_MEM_DEBUG 1 EOF fi if test "$tcl_ok" = "compile" -o "$tcl_ok" = "all"; then cat >> confdefs.h <<\EOF #define TCL_COMPILE_DEBUG 1 EOF cat >> confdefs.h <<\EOF #define TCL_COMPILE_STATS 1 EOF fi if test "$tcl_ok" != "yes" -a "$tcl_ok" != "no"; then if test "$tcl_ok" = "all"; then echo "$ac_t""enabled symbols mem compile debugging" 1>&6 else echo "$ac_t""enabled $tcl_ok debugging" 1>&6 fi fi TCL_DBGX=${DBGX} #-------------------------------------------------------------------- # Detect what compiler flags to set for 64-bit support. #-------------------------------------------------------------------- echo $ac_n "checking for required early compiler flags""... $ac_c" 1>&6 echo "configure:4459: checking for required early compiler flags" >&5 tcl_flags="" if eval "test \"`echo '$''{'tcl_cv_flag__isoc99_source'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { char *p = (char *)strtoll; char *q = (char *)strtoull; ; return 0; } EOF if { (eval echo configure:4473: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_cv_flag__isoc99_source=no else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* cat > conftest.$ac_ext < int main() { char *p = (char *)strtoll; char *q = (char *)strtoull; ; return 0; } EOF if { (eval echo configure:4489: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_cv_flag__isoc99_source=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_flag__isoc99_source=no fi rm -f conftest* fi rm -f conftest* fi if test "x${tcl_cv_flag__isoc99_source}" = "xyes" ; then cat >> confdefs.h <<\EOF #define _ISOC99_SOURCE 1 EOF tcl_flags="$tcl_flags _ISOC99_SOURCE" fi if eval "test \"`echo '$''{'tcl_cv_flag__largefile64_source'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { struct stat64 buf; int i = stat64("/", &buf); ; return 0; } EOF if { (eval echo configure:4523: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_cv_flag__largefile64_source=no else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* cat > conftest.$ac_ext < int main() { struct stat64 buf; int i = stat64("/", &buf); ; return 0; } EOF if { (eval echo configure:4539: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_cv_flag__largefile64_source=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_flag__largefile64_source=no fi rm -f conftest* fi rm -f conftest* fi if test "x${tcl_cv_flag__largefile64_source}" = "xyes" ; then cat >> confdefs.h <<\EOF #define _LARGEFILE64_SOURCE 1 EOF tcl_flags="$tcl_flags _LARGEFILE64_SOURCE" fi if eval "test \"`echo '$''{'tcl_cv_flag__largefile_source64'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { char *p = (char *)open64; ; return 0; } EOF if { (eval echo configure:4573: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_cv_flag__largefile_source64=no else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* cat > conftest.$ac_ext < int main() { char *p = (char *)open64; ; return 0; } EOF if { (eval echo configure:4589: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_cv_flag__largefile_source64=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_flag__largefile_source64=no fi rm -f conftest* fi rm -f conftest* fi if test "x${tcl_cv_flag__largefile_source64}" = "xyes" ; then cat >> confdefs.h <<\EOF #define _LARGEFILE_SOURCE64 1 EOF tcl_flags="$tcl_flags _LARGEFILE_SOURCE64" fi if test "x${tcl_flags}" = "x" ; then echo "$ac_t""none" 1>&6 else echo "$ac_t""${tcl_flags}" 1>&6 fi echo $ac_n "checking for 64-bit integer type""... $ac_c" 1>&6 echo "configure:4620: checking for 64-bit integer type" >&5 if eval "test \"`echo '$''{'tcl_cv_type_64bit'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else tcl_cv_type_64bit=none # See if the compiler knows natively about __int64 cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_type_64bit=__int64 else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_type_64bit="long long" fi rm -f conftest* # See if we should use long anyway Note that we substitute in the # type that is our current guess for a 64-bit type inside this check # program, so it should be modified only carefully... cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_cv_type_64bit=${tcl_type_64bit} else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 fi rm -f conftest* fi if test "${tcl_cv_type_64bit}" = none ; then cat >> confdefs.h <<\EOF #define TCL_WIDE_INT_IS_LONG 1 EOF echo "$ac_t""using long" 1>&6 else cat >> confdefs.h <&6 # Now check for auxiliary declarations echo $ac_n "checking for struct dirent64""... $ac_c" 1>&6 echo "configure:4683: checking for struct dirent64" >&5 if eval "test \"`echo '$''{'tcl_cv_struct_dirent64'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include int main() { struct dirent64 p; ; return 0; } EOF if { (eval echo configure:4697: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_cv_struct_dirent64=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_struct_dirent64=no fi rm -f conftest* fi echo "$ac_t""$tcl_cv_struct_dirent64" 1>&6 if test "x${tcl_cv_struct_dirent64}" = "xyes" ; then cat >> confdefs.h <<\EOF #define HAVE_STRUCT_DIRENT64 1 EOF fi echo $ac_n "checking for struct stat64""... $ac_c" 1>&6 echo "configure:4718: checking for struct stat64" >&5 if eval "test \"`echo '$''{'tcl_cv_struct_stat64'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { struct stat64 p; ; return 0; } EOF if { (eval echo configure:4732: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_cv_struct_stat64=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_struct_stat64=no fi rm -f conftest* fi echo "$ac_t""$tcl_cv_struct_stat64" 1>&6 if test "x${tcl_cv_struct_stat64}" = "xyes" ; then cat >> confdefs.h <<\EOF #define HAVE_STRUCT_STAT64 1 EOF fi for ac_func in open64 lseek64 do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 echo "configure:4755: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else $ac_func(); #endif ; return 0; } EOF if { (eval echo configure:4783: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_$ac_func=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` cat >> confdefs.h <&6 fi done echo $ac_n "checking for off64_t""... $ac_c" 1>&6 echo "configure:4808: checking for off64_t" >&5 if eval "test \"`echo '$''{'tcl_cv_type_off64_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { off64_t offset; ; return 0; } EOF if { (eval echo configure:4822: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_cv_type_off64_t=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_type_off64_t=no fi rm -f conftest* fi if test "x${tcl_cv_type_off64_t}" = "xyes" && \ test "x${ac_cv_func_lseek64}" = "xyes" && \ test "x${ac_cv_func_open64}" = "xyes" ; then cat >> confdefs.h <<\EOF #define HAVE_TYPE_OFF64_T 1 EOF echo "$ac_t""yes" 1>&6 else echo "$ac_t""no" 1>&6 fi fi #-------------------------------------------------------------------- # Check endianness because we can optimize comparisons of # Tcl_UniChar strings to memcmp on big-endian systems. #-------------------------------------------------------------------- echo $ac_n "checking whether byte ordering is bigendian""... $ac_c" 1>&6 echo "configure:4854: checking whether byte ordering is bigendian" >&5 if eval "test \"`echo '$''{'ac_cv_c_bigendian'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_cv_c_bigendian=unknown # See if sys/param.h defines the BYTE_ORDER macro. cat > conftest.$ac_ext < #include int main() { #if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN bogus endian macros #endif ; return 0; } EOF if { (eval echo configure:4872: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* # It does; now see whether it defined to BIG_ENDIAN or not. cat > conftest.$ac_ext < #include int main() { #if BYTE_ORDER != BIG_ENDIAN not big endian #endif ; return 0; } EOF if { (eval echo configure:4887: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_c_bigendian=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* ac_cv_c_bigendian=no fi rm -f conftest* else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 fi rm -f conftest* if test $ac_cv_c_bigendian = unknown; then if test "$cross_compiling" = yes; then { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_c_bigendian=no else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* ac_cv_c_bigendian=yes fi rm -fr conftest* fi fi fi echo "$ac_t""$ac_cv_c_bigendian" 1>&6 if test $ac_cv_c_bigendian = yes; then cat >> confdefs.h <<\EOF #define WORDS_BIGENDIAN 1 EOF fi #-------------------------------------------------------------------- # Supply substitutes for missing POSIX library procedures, or # set flags so Tcl uses alternate procedures. #-------------------------------------------------------------------- # Check if Posix compliant getcwd exists, if not we'll use getwd. for ac_func in getcwd do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 echo "configure:4953: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else $ac_func(); #endif ; return 0; } EOF if { (eval echo configure:4981: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_$ac_func=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` cat >> confdefs.h <&6 cat >> confdefs.h <<\EOF #define USEGETWD 1 EOF fi done # Nb: if getcwd uses popen and pwd(1) (like SunOS 4) we should really # define USEGETWD even if the posix getcwd exists. Add a test ? for ac_func in opendir strstr strtol strtoll strtoull tmpnam waitpid do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 echo "configure:5015: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else $ac_func(); #endif ; return 0; } EOF if { (eval echo configure:5043: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_$ac_func=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` cat >> confdefs.h <&6 LIBOBJS="$LIBOBJS ${ac_func}.${ac_objext}" fi done echo $ac_n "checking for strerror""... $ac_c" 1>&6 echo "configure:5070: checking for strerror" >&5 if eval "test \"`echo '$''{'ac_cv_func_strerror'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char strerror(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_strerror) || defined (__stub___strerror) choke me #else strerror(); #endif ; return 0; } EOF if { (eval echo configure:5098: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_strerror=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_strerror=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'strerror`\" = yes"; then echo "$ac_t""yes" 1>&6 : else echo "$ac_t""no" 1>&6 cat >> confdefs.h <<\EOF #define NO_STRERROR 1 EOF fi echo $ac_n "checking for getwd""... $ac_c" 1>&6 echo "configure:5122: checking for getwd" >&5 if eval "test \"`echo '$''{'ac_cv_func_getwd'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char getwd(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_getwd) || defined (__stub___getwd) choke me #else getwd(); #endif ; return 0; } EOF if { (eval echo configure:5150: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_getwd=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_getwd=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'getwd`\" = yes"; then echo "$ac_t""yes" 1>&6 : else echo "$ac_t""no" 1>&6 cat >> confdefs.h <<\EOF #define NO_GETWD 1 EOF fi echo $ac_n "checking for wait3""... $ac_c" 1>&6 echo "configure:5174: checking for wait3" >&5 if eval "test \"`echo '$''{'ac_cv_func_wait3'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char wait3(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_wait3) || defined (__stub___wait3) choke me #else wait3(); #endif ; return 0; } EOF if { (eval echo configure:5202: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_wait3=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_wait3=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'wait3`\" = yes"; then echo "$ac_t""yes" 1>&6 : else echo "$ac_t""no" 1>&6 cat >> confdefs.h <<\EOF #define NO_WAIT3 1 EOF fi echo $ac_n "checking for uname""... $ac_c" 1>&6 echo "configure:5226: checking for uname" >&5 if eval "test \"`echo '$''{'ac_cv_func_uname'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char uname(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_uname) || defined (__stub___uname) choke me #else uname(); #endif ; return 0; } EOF if { (eval echo configure:5254: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_uname=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_uname=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'uname`\" = yes"; then echo "$ac_t""yes" 1>&6 : else echo "$ac_t""no" 1>&6 cat >> confdefs.h <<\EOF #define NO_UNAME 1 EOF fi if test "`uname -s`" = "Darwin" && test "${TCL_THREADS}" = 1 && \ test "`uname -r | awk -F. '{print $1}'`" -lt 7; then # prior to Darwin 7, realpath is not threadsafe, so don't # use it when threads are enabled, c.f. bug # 711232 ac_cv_func_realpath=no fi echo $ac_n "checking for realpath""... $ac_c" 1>&6 echo "configure:5285: checking for realpath" >&5 if eval "test \"`echo '$''{'ac_cv_func_realpath'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char realpath(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_realpath) || defined (__stub___realpath) choke me #else realpath(); #endif ; return 0; } EOF if { (eval echo configure:5313: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_realpath=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_realpath=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'realpath`\" = yes"; then echo "$ac_t""yes" 1>&6 : else echo "$ac_t""no" 1>&6 cat >> confdefs.h <<\EOF #define NO_REALPATH 1 EOF fi #-------------------------------------------------------------------- # Look for thread-safe variants of some library functions. #-------------------------------------------------------------------- if test "${TCL_THREADS}" = 1; then echo $ac_n "checking for getpwuid_r""... $ac_c" 1>&6 echo "configure:5343: checking for getpwuid_r" >&5 if eval "test \"`echo '$''{'ac_cv_func_getpwuid_r'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char getpwuid_r(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_getpwuid_r) || defined (__stub___getpwuid_r) choke me #else getpwuid_r(); #endif ; return 0; } EOF if { (eval echo configure:5371: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_getpwuid_r=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_getpwuid_r=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'getpwuid_r`\" = yes"; then echo "$ac_t""yes" 1>&6 echo $ac_n "checking for getpwuid_r with 5 args""... $ac_c" 1>&6 echo "configure:5387: checking for getpwuid_r with 5 args" >&5 if eval "test \"`echo '$''{'tcl_cv_api_getpwuid_r_5'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include int main() { uid_t uid; struct passwd pw, *pwp; char buf[512]; int buflen = 512; (void) getpwuid_r(uid, &pw, buf, buflen, &pwp); ; return 0; } EOF if { (eval echo configure:5410: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_cv_api_getpwuid_r_5=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_api_getpwuid_r_5=no fi rm -f conftest* fi echo "$ac_t""$tcl_cv_api_getpwuid_r_5" 1>&6 tcl_ok=$tcl_cv_api_getpwuid_r_5 if test "$tcl_ok" = yes; then cat >> confdefs.h <<\EOF #define HAVE_GETPWUID_R_5 1 EOF else echo $ac_n "checking for getpwuid_r with 4 args""... $ac_c" 1>&6 echo "configure:5431: checking for getpwuid_r with 4 args" >&5 if eval "test \"`echo '$''{'tcl_cv_api_getpwuid_r_4'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include int main() { uid_t uid; struct passwd pw; char buf[512]; int buflen = 512; (void)getpwnam_r(uid, &pw, buf, buflen); ; return 0; } EOF if { (eval echo configure:5454: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_cv_api_getpwuid_r_4=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_api_getpwuid_r_4=no fi rm -f conftest* fi echo "$ac_t""$tcl_cv_api_getpwuid_r_4" 1>&6 tcl_ok=$tcl_cv_api_getpwuid_r_4 if test "$tcl_ok" = yes; then cat >> confdefs.h <<\EOF #define HAVE_GETPWUID_R_4 1 EOF fi fi if test "$tcl_ok" = yes; then cat >> confdefs.h <<\EOF #define HAVE_GETPWUID_R 1 EOF fi else echo "$ac_t""no" 1>&6 fi echo $ac_n "checking for getpwnam_r""... $ac_c" 1>&6 echo "configure:5487: checking for getpwnam_r" >&5 if eval "test \"`echo '$''{'ac_cv_func_getpwnam_r'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char getpwnam_r(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_getpwnam_r) || defined (__stub___getpwnam_r) choke me #else getpwnam_r(); #endif ; return 0; } EOF if { (eval echo configure:5515: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_getpwnam_r=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_getpwnam_r=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'getpwnam_r`\" = yes"; then echo "$ac_t""yes" 1>&6 echo $ac_n "checking for getpwnam_r with 5 args""... $ac_c" 1>&6 echo "configure:5531: checking for getpwnam_r with 5 args" >&5 if eval "test \"`echo '$''{'tcl_cv_api_getpwnam_r_5'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include int main() { char *name; struct passwd pw, *pwp; char buf[512]; int buflen = 512; (void) getpwnam_r(name, &pw, buf, buflen, &pwp); ; return 0; } EOF if { (eval echo configure:5554: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_cv_api_getpwnam_r_5=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_api_getpwnam_r_5=no fi rm -f conftest* fi echo "$ac_t""$tcl_cv_api_getpwnam_r_5" 1>&6 tcl_ok=$tcl_cv_api_getpwnam_r_5 if test "$tcl_ok" = yes; then cat >> confdefs.h <<\EOF #define HAVE_GETPWNAM_R_5 1 EOF else echo $ac_n "checking for getpwnam_r with 4 args""... $ac_c" 1>&6 echo "configure:5575: checking for getpwnam_r with 4 args" >&5 if eval "test \"`echo '$''{'tcl_cv_api_getpwnam_r_4'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include int main() { char *name; struct passwd pw; char buf[512]; int buflen = 512; (void)getpwnam_r(name, &pw, buf, buflen); ; return 0; } EOF if { (eval echo configure:5598: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_cv_api_getpwnam_r_4=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_api_getpwnam_r_4=no fi rm -f conftest* fi echo "$ac_t""$tcl_cv_api_getpwnam_r_4" 1>&6 tcl_ok=$tcl_cv_api_getpwnam_r_4 if test "$tcl_ok" = yes; then cat >> confdefs.h <<\EOF #define HAVE_GETPWNAM_R_4 1 EOF fi fi if test "$tcl_ok" = yes; then cat >> confdefs.h <<\EOF #define HAVE_GETPWNAM_R 1 EOF fi else echo "$ac_t""no" 1>&6 fi echo $ac_n "checking for getgrgid_r""... $ac_c" 1>&6 echo "configure:5631: checking for getgrgid_r" >&5 if eval "test \"`echo '$''{'ac_cv_func_getgrgid_r'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char getgrgid_r(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_getgrgid_r) || defined (__stub___getgrgid_r) choke me #else getgrgid_r(); #endif ; return 0; } EOF if { (eval echo configure:5659: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_getgrgid_r=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_getgrgid_r=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'getgrgid_r`\" = yes"; then echo "$ac_t""yes" 1>&6 echo $ac_n "checking for getgrgid_r with 5 args""... $ac_c" 1>&6 echo "configure:5675: checking for getgrgid_r with 5 args" >&5 if eval "test \"`echo '$''{'tcl_cv_api_getgrgid_r_5'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include int main() { gid_t gid; struct group gr, *grp; char buf[512]; int buflen = 512; (void) getgrgid_r(gid, &gr, buf, buflen, &grp); ; return 0; } EOF if { (eval echo configure:5698: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_cv_api_getgrgid_r_5=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_api_getgrgid_r_5=no fi rm -f conftest* fi echo "$ac_t""$tcl_cv_api_getgrgid_r_5" 1>&6 tcl_ok=$tcl_cv_api_getgrgid_r_5 if test "$tcl_ok" = yes; then cat >> confdefs.h <<\EOF #define HAVE_GETGRGID_R_5 1 EOF else echo $ac_n "checking for getgrgid_r with 4 args""... $ac_c" 1>&6 echo "configure:5719: checking for getgrgid_r with 4 args" >&5 if eval "test \"`echo '$''{'tcl_cv_api_getgrgid_r_4'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include int main() { gid_t gid; struct group gr; char buf[512]; int buflen = 512; (void)getgrgid_r(gid, &gr, buf, buflen); ; return 0; } EOF if { (eval echo configure:5742: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_cv_api_getgrgid_r_4=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_api_getgrgid_r_4=no fi rm -f conftest* fi echo "$ac_t""$tcl_cv_api_getgrgid_r_4" 1>&6 tcl_ok=$tcl_cv_api_getgrgid_r_4 if test "$tcl_ok" = yes; then cat >> confdefs.h <<\EOF #define HAVE_GETGRGID_R_4 1 EOF fi fi if test "$tcl_ok" = yes; then cat >> confdefs.h <<\EOF #define HAVE_GETGRGID_R 1 EOF fi else echo "$ac_t""no" 1>&6 fi echo $ac_n "checking for getgrnam_r""... $ac_c" 1>&6 echo "configure:5775: checking for getgrnam_r" >&5 if eval "test \"`echo '$''{'ac_cv_func_getgrnam_r'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char getgrnam_r(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_getgrnam_r) || defined (__stub___getgrnam_r) choke me #else getgrnam_r(); #endif ; return 0; } EOF if { (eval echo configure:5803: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_getgrnam_r=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_getgrnam_r=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'getgrnam_r`\" = yes"; then echo "$ac_t""yes" 1>&6 echo $ac_n "checking for getgrnam_r with 5 args""... $ac_c" 1>&6 echo "configure:5819: checking for getgrnam_r with 5 args" >&5 if eval "test \"`echo '$''{'tcl_cv_api_getgrnam_r_5'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include int main() { char *name; struct group gr, *grp; char buf[512]; int buflen = 512; (void) getgrnam_r(name, &gr, buf, buflen, &grp); ; return 0; } EOF if { (eval echo configure:5842: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_cv_api_getgrnam_r_5=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_api_getgrnam_r_5=no fi rm -f conftest* fi echo "$ac_t""$tcl_cv_api_getgrnam_r_5" 1>&6 tcl_ok=$tcl_cv_api_getgrnam_r_5 if test "$tcl_ok" = yes; then cat >> confdefs.h <<\EOF #define HAVE_GETGRNAM_R_5 1 EOF else echo $ac_n "checking for getgrnam_r with 4 args""... $ac_c" 1>&6 echo "configure:5863: checking for getgrnam_r with 4 args" >&5 if eval "test \"`echo '$''{'tcl_cv_api_getgrnam_r_4'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include int main() { char *name; struct group gr; char buf[512]; int buflen = 512; (void)getgrnam_r(name, &gr, buf, buflen); ; return 0; } EOF if { (eval echo configure:5886: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_cv_api_getgrnam_r_4=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_api_getgrnam_r_4=no fi rm -f conftest* fi echo "$ac_t""$tcl_cv_api_getgrnam_r_4" 1>&6 tcl_ok=$tcl_cv_api_getgrnam_r_4 if test "$tcl_ok" = yes; then cat >> confdefs.h <<\EOF #define HAVE_GETGRNAM_R_4 1 EOF fi fi if test "$tcl_ok" = yes; then cat >> confdefs.h <<\EOF #define HAVE_GETGRNAM_R 1 EOF fi else echo "$ac_t""no" 1>&6 fi if test "`uname -s`" = "Darwin" && \ test "`uname -r | awk -F. '{print $1}'`" -gt 5; then # Starting with Darwin 6 (Mac OSX 10.2), gethostbyX # are actually MT-safe as they always return pointers # from the TSD instead of the static storage. cat >> confdefs.h <<\EOF #define HAVE_MTSAFE_GETHOSTBYNAME 1 EOF cat >> confdefs.h <<\EOF #define HAVE_MTSAFE_GETHOSTBYADDR 1 EOF elif test "`uname -s`" = "HP-UX" && \ test "`uname -r|sed -e 's|B\.||' -e 's|\..*$||'`" -gt 10; then # Starting with HPUX 11.00 (we believe), gethostbyX # are actually MT-safe as they always return pointers # from TSD instead of static storage. cat >> confdefs.h <<\EOF #define HAVE_MTSAFE_GETHOSTBYNAME 1 EOF cat >> confdefs.h <<\EOF #define HAVE_MTSAFE_GETHOSTBYADDR 1 EOF else echo $ac_n "checking for gethostbyname_r""... $ac_c" 1>&6 echo "configure:5946: checking for gethostbyname_r" >&5 if eval "test \"`echo '$''{'ac_cv_func_gethostbyname_r'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char gethostbyname_r(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_gethostbyname_r) || defined (__stub___gethostbyname_r) choke me #else gethostbyname_r(); #endif ; return 0; } EOF if { (eval echo configure:5974: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_gethostbyname_r=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_gethostbyname_r=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'gethostbyname_r`\" = yes"; then echo "$ac_t""yes" 1>&6 echo $ac_n "checking for gethostbyname_r with 6 args""... $ac_c" 1>&6 echo "configure:5990: checking for gethostbyname_r with 6 args" >&5 if eval "test \"`echo '$''{'tcl_cv_api_gethostbyname_r_6'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { char *name; struct hostent *he, *res; char buffer[2048]; int buflen = 2048; int h_errnop; (void) gethostbyname_r(name, he, buffer, buflen, &res, &h_errnop); ; return 0; } EOF if { (eval echo configure:6013: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_cv_api_gethostbyname_r_6=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_api_gethostbyname_r_6=no fi rm -f conftest* fi echo "$ac_t""$tcl_cv_api_gethostbyname_r_6" 1>&6 tcl_ok=$tcl_cv_api_gethostbyname_r_6 if test "$tcl_ok" = yes; then cat >> confdefs.h <<\EOF #define HAVE_GETHOSTBYNAME_R_6 1 EOF else echo $ac_n "checking for gethostbyname_r with 5 args""... $ac_c" 1>&6 echo "configure:6034: checking for gethostbyname_r with 5 args" >&5 if eval "test \"`echo '$''{'tcl_cv_api_gethostbyname_r_5'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { char *name; struct hostent *he; char buffer[2048]; int buflen = 2048; int h_errnop; (void) gethostbyname_r(name, he, buffer, buflen, &h_errnop); ; return 0; } EOF if { (eval echo configure:6057: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_cv_api_gethostbyname_r_5=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_api_gethostbyname_r_5=no fi rm -f conftest* fi echo "$ac_t""$tcl_cv_api_gethostbyname_r_5" 1>&6 tcl_ok=$tcl_cv_api_gethostbyname_r_5 if test "$tcl_ok" = yes; then cat >> confdefs.h <<\EOF #define HAVE_GETHOSTBYNAME_R_5 1 EOF else echo $ac_n "checking for gethostbyname_r with 3 args""... $ac_c" 1>&6 echo "configure:6078: checking for gethostbyname_r with 3 args" >&5 if eval "test \"`echo '$''{'tcl_cv_api_gethostbyname_r_3'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { char *name; struct hostent *he; struct hostent_data data; (void) gethostbyname_r(name, he, &data); ; return 0; } EOF if { (eval echo configure:6099: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_cv_api_gethostbyname_r_3=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_api_gethostbyname_r_3=no fi rm -f conftest* fi echo "$ac_t""$tcl_cv_api_gethostbyname_r_3" 1>&6 tcl_ok=$tcl_cv_api_gethostbyname_r_3 if test "$tcl_ok" = yes; then cat >> confdefs.h <<\EOF #define HAVE_GETHOSTBYNAME_R_3 1 EOF fi fi fi if test "$tcl_ok" = yes; then cat >> confdefs.h <<\EOF #define HAVE_GETHOSTBYNAME_R 1 EOF fi else echo "$ac_t""no" 1>&6 fi echo $ac_n "checking for gethostbyaddr_r""... $ac_c" 1>&6 echo "configure:6133: checking for gethostbyaddr_r" >&5 if eval "test \"`echo '$''{'ac_cv_func_gethostbyaddr_r'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char gethostbyaddr_r(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_gethostbyaddr_r) || defined (__stub___gethostbyaddr_r) choke me #else gethostbyaddr_r(); #endif ; return 0; } EOF if { (eval echo configure:6161: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_gethostbyaddr_r=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_gethostbyaddr_r=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'gethostbyaddr_r`\" = yes"; then echo "$ac_t""yes" 1>&6 echo $ac_n "checking for gethostbyaddr_r with 7 args""... $ac_c" 1>&6 echo "configure:6177: checking for gethostbyaddr_r with 7 args" >&5 if eval "test \"`echo '$''{'tcl_cv_api_gethostbyaddr_r_7'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { char *addr; int length; int type; struct hostent *result; char buffer[2048]; int buflen = 2048; int h_errnop; (void) gethostbyaddr_r(addr, length, type, result, buffer, buflen, &h_errnop); ; return 0; } EOF if { (eval echo configure:6203: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_cv_api_gethostbyaddr_r_7=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_api_gethostbyaddr_r_7=no fi rm -f conftest* fi echo "$ac_t""$tcl_cv_api_gethostbyaddr_r_7" 1>&6 tcl_ok=$tcl_cv_api_gethostbyaddr_r_7 if test "$tcl_ok" = yes; then cat >> confdefs.h <<\EOF #define HAVE_GETHOSTBYADDR_R_7 1 EOF else echo $ac_n "checking for gethostbyaddr_r with 8 args""... $ac_c" 1>&6 echo "configure:6224: checking for gethostbyaddr_r with 8 args" >&5 if eval "test \"`echo '$''{'tcl_cv_api_gethostbyaddr_r_8'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { char *addr; int length; int type; struct hostent *result, *resultp; char buffer[2048]; int buflen = 2048; int h_errnop; (void) gethostbyaddr_r(addr, length, type, result, buffer, buflen, &resultp, &h_errnop); ; return 0; } EOF if { (eval echo configure:6250: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_cv_api_gethostbyaddr_r_8=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_api_gethostbyaddr_r_8=no fi rm -f conftest* fi echo "$ac_t""$tcl_cv_api_gethostbyaddr_r_8" 1>&6 tcl_ok=$tcl_cv_api_gethostbyaddr_r_8 if test "$tcl_ok" = yes; then cat >> confdefs.h <<\EOF #define HAVE_GETHOSTBYADDR_R_8 1 EOF fi fi if test "$tcl_ok" = yes; then cat >> confdefs.h <<\EOF #define HAVE_GETHOSTBYADDR_R 1 EOF fi else echo "$ac_t""no" 1>&6 fi fi fi #--------------------------------------------------------------------------- # Determine which interface to use to talk to the serial port. # Note that #include lines must begin in leftmost column for # some compilers to recognize them as preprocessor directives. #--------------------------------------------------------------------------- for ac_hdr in sys/modem.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 echo "configure:6296: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:6306: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` cat >> confdefs.h <&6 fi done echo $ac_n "checking termios vs. termio vs. sgtty""... $ac_c" 1>&6 echo "configure:6333: checking termios vs. termio vs. sgtty" >&5 if eval "test \"`echo '$''{'tcl_cv_api_serial'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$cross_compiling" = yes; then tcl_cv_api_serial=no else cat > conftest.$ac_ext < int main() { struct termios t; if (tcgetattr(0, &t) == 0) { cfsetospeed(&t, 0); t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; } EOF if { (eval echo configure:6357: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then tcl_cv_api_serial=termios else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* tcl_cv_api_serial=no fi rm -fr conftest* fi if test $tcl_cv_api_serial = no ; then if test "$cross_compiling" = yes; then tcl_cv_api_serial=no else cat > conftest.$ac_ext < int main() { struct termio t; if (ioctl(0, TCGETA, &t) == 0) { t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; } EOF if { (eval echo configure:6388: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then tcl_cv_api_serial=termio else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* tcl_cv_api_serial=no fi rm -fr conftest* fi fi if test $tcl_cv_api_serial = no ; then if test "$cross_compiling" = yes; then tcl_cv_api_serial=no else cat > conftest.$ac_ext < int main() { struct sgttyb t; if (ioctl(0, TIOCGETP, &t) == 0) { t.sg_ospeed = 0; t.sg_flags |= ODDP | EVENP | RAW; return 0; } return 1; } EOF if { (eval echo configure:6421: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then tcl_cv_api_serial=sgtty else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* tcl_cv_api_serial=no fi rm -fr conftest* fi fi if test $tcl_cv_api_serial = no ; then if test "$cross_compiling" = yes; then tcl_cv_api_serial=no else cat > conftest.$ac_ext < #include int main() { struct termios t; if (tcgetattr(0, &t) == 0 || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { cfsetospeed(&t, 0); t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; } EOF if { (eval echo configure:6456: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then tcl_cv_api_serial=termios else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* tcl_cv_api_serial=no fi rm -fr conftest* fi fi if test $tcl_cv_api_serial = no; then if test "$cross_compiling" = yes; then tcl_cv_api_serial=no else cat > conftest.$ac_ext < #include int main() { struct termio t; if (ioctl(0, TCGETA, &t) == 0 || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; } EOF if { (eval echo configure:6490: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then tcl_cv_api_serial=termio else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* tcl_cv_api_serial=no fi rm -fr conftest* fi fi if test $tcl_cv_api_serial = no; then if test "$cross_compiling" = yes; then tcl_cv_api_serial=none else cat > conftest.$ac_ext < #include int main() { struct sgttyb t; if (ioctl(0, TIOCGETP, &t) == 0 || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { t.sg_ospeed = 0; t.sg_flags |= ODDP | EVENP | RAW; return 0; } return 1; } EOF if { (eval echo configure:6525: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then tcl_cv_api_serial=sgtty else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* tcl_cv_api_serial=none fi rm -fr conftest* fi fi fi echo "$ac_t""$tcl_cv_api_serial" 1>&6 case $tcl_cv_api_serial in termios) cat >> confdefs.h <<\EOF #define USE_TERMIOS 1 EOF ;; termio) cat >> confdefs.h <<\EOF #define USE_TERMIO 1 EOF ;; sgtty) cat >> confdefs.h <<\EOF #define USE_SGTTY 1 EOF ;; esac #-------------------------------------------------------------------- # Include sys/select.h if it exists and if it supplies things # that appear to be useful and aren't already in sys/types.h. # This appears to be true only on the RS/6000 under AIX. Some # systems like OSF/1 have a sys/select.h that's of no use, and # other systems like SCO UNIX have a sys/select.h that's # pernicious. If "fd_set" isn't defined anywhere then set a # special flag. #-------------------------------------------------------------------- echo $ac_n "checking for fd_set in sys/types""... $ac_c" 1>&6 echo "configure:6568: checking for fd_set in sys/types" >&5 if eval "test \"`echo '$''{'tcl_cv_type_fd_set'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { fd_set readMask, writeMask; ; return 0; } EOF if { (eval echo configure:6581: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_cv_type_fd_set=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_type_fd_set=no fi rm -f conftest* fi echo "$ac_t""$tcl_cv_type_fd_set" 1>&6 tcl_ok=$tcl_cv_type_fd_set if test $tcl_ok = no; then echo $ac_n "checking for fd_mask in sys/select""... $ac_c" 1>&6 echo "configure:6597: checking for fd_mask in sys/select" >&5 if eval "test \"`echo '$''{'tcl_cv_grep_fd_mask'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "fd_mask" >/dev/null 2>&1; then rm -rf conftest* tcl_cv_grep_fd_mask=present else rm -rf conftest* tcl_cv_grep_fd_mask=missing fi rm -f conftest* fi echo "$ac_t""$tcl_cv_grep_fd_mask" 1>&6 if test $tcl_cv_grep_fd_mask = present; then cat >> confdefs.h <<\EOF #define HAVE_SYS_SELECT_H 1 EOF tcl_ok=yes fi fi if test $tcl_ok = no; then cat >> confdefs.h <<\EOF #define NO_FD_SET 1 EOF fi #------------------------------------------------------------------------------ # Find out all about time handling differences. #------------------------------------------------------------------------------ echo $ac_n "checking whether struct tm is in sys/time.h or time.h""... $ac_c" 1>&6 echo "configure:6640: checking whether struct tm is in sys/time.h or time.h" >&5 if eval "test \"`echo '$''{'ac_cv_struct_tm'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include int main() { struct tm *tp; tp->tm_sec; ; return 0; } EOF if { (eval echo configure:6653: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_struct_tm=time.h else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* ac_cv_struct_tm=sys/time.h fi rm -f conftest* fi echo "$ac_t""$ac_cv_struct_tm" 1>&6 if test $ac_cv_struct_tm = sys/time.h; then cat >> confdefs.h <<\EOF #define TM_IN_SYS_TIME 1 EOF fi for ac_hdr in sys/time.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 echo "configure:6678: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:6688: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` cat >> confdefs.h <&6 fi done echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6 echo "configure:6715: checking whether time.h and sys/time.h may both be included" >&5 if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include #include int main() { struct tm *tp; ; return 0; } EOF if { (eval echo configure:6729: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_header_time=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* ac_cv_header_time=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_header_time" 1>&6 if test $ac_cv_header_time = yes; then cat >> confdefs.h <<\EOF #define TIME_WITH_SYS_TIME 1 EOF fi echo $ac_n "checking for tm_zone in struct tm""... $ac_c" 1>&6 echo "configure:6750: checking for tm_zone in struct tm" >&5 if eval "test \"`echo '$''{'ac_cv_struct_tm_zone'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include <$ac_cv_struct_tm> int main() { struct tm tm; tm.tm_zone; ; return 0; } EOF if { (eval echo configure:6763: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_struct_tm_zone=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* ac_cv_struct_tm_zone=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_struct_tm_zone" 1>&6 if test "$ac_cv_struct_tm_zone" = yes; then cat >> confdefs.h <<\EOF #define HAVE_TM_ZONE 1 EOF else echo $ac_n "checking for tzname""... $ac_c" 1>&6 echo "configure:6783: checking for tzname" >&5 if eval "test \"`echo '$''{'ac_cv_var_tzname'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #ifndef tzname /* For SGI. */ extern char *tzname[]; /* RS6000 and others reject char **tzname. */ #endif int main() { atoi(*tzname); ; return 0; } EOF if { (eval echo configure:6798: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ac_cv_var_tzname=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* ac_cv_var_tzname=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_var_tzname" 1>&6 if test $ac_cv_var_tzname = yes; then cat >> confdefs.h <<\EOF #define HAVE_TZNAME 1 EOF fi fi for ac_func in gmtime_r localtime_r do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 echo "configure:6823: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else $ac_func(); #endif ; return 0; } EOF if { (eval echo configure:6851: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_$ac_func=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` cat >> confdefs.h <&6 fi done echo $ac_n "checking tm_tzadj in struct tm""... $ac_c" 1>&6 echo "configure:6877: checking tm_tzadj in struct tm" >&5 if eval "test \"`echo '$''{'tcl_cv_member_tm_tzadj'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { struct tm tm; tm.tm_tzadj; ; return 0; } EOF if { (eval echo configure:6890: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_cv_member_tm_tzadj=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_member_tm_tzadj=no fi rm -f conftest* fi echo "$ac_t""$tcl_cv_member_tm_tzadj" 1>&6 if test $tcl_cv_member_tm_tzadj = yes ; then cat >> confdefs.h <<\EOF #define HAVE_TM_TZADJ 1 EOF fi echo $ac_n "checking tm_gmtoff in struct tm""... $ac_c" 1>&6 echo "configure:6911: checking tm_gmtoff in struct tm" >&5 if eval "test \"`echo '$''{'tcl_cv_member_tm_gmtoff'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { struct tm tm; tm.tm_gmtoff; ; return 0; } EOF if { (eval echo configure:6924: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_cv_member_tm_gmtoff=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_member_tm_gmtoff=no fi rm -f conftest* fi echo "$ac_t""$tcl_cv_member_tm_gmtoff" 1>&6 if test $tcl_cv_member_tm_gmtoff = yes ; then cat >> confdefs.h <<\EOF #define HAVE_TM_GMTOFF 1 EOF fi # # Its important to include time.h in this check, as some systems # (like convex) have timezone functions, etc. # echo $ac_n "checking long timezone variable""... $ac_c" 1>&6 echo "configure:6949: checking long timezone variable" >&5 if eval "test \"`echo '$''{'tcl_cv_timezone_long'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { extern long timezone; timezone += 1; exit (0); ; return 0; } EOF if { (eval echo configure:6964: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_cv_timezone_long=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_timezone_long=no fi rm -f conftest* fi echo "$ac_t""$tcl_cv_timezone_long" 1>&6 if test $tcl_cv_timezone_long = yes ; then cat >> confdefs.h <<\EOF #define HAVE_TIMEZONE_VAR 1 EOF else # # On some systems (eg IRIX 6.2), timezone is a time_t and not a long. # echo $ac_n "checking time_t timezone variable""... $ac_c" 1>&6 echo "configure:6987: checking time_t timezone variable" >&5 if eval "test \"`echo '$''{'tcl_cv_timezone_time'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { extern time_t timezone; timezone += 1; exit (0); ; return 0; } EOF if { (eval echo configure:7002: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_cv_timezone_time=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_timezone_time=no fi rm -f conftest* fi echo "$ac_t""$tcl_cv_timezone_time" 1>&6 if test $tcl_cv_timezone_time = yes ; then cat >> confdefs.h <<\EOF #define HAVE_TIMEZONE_VAR 1 EOF fi fi #-------------------------------------------------------------------- # Some systems (e.g., IRIX 4.0.5) lack the st_blksize field # in struct stat. But we might be able to use fstatfs instead. #-------------------------------------------------------------------- if test "$ac_cv_cygwin" != "yes"; then echo $ac_n "checking for st_blksize in struct stat""... $ac_c" 1>&6 echo "configure:7030: checking for st_blksize in struct stat" >&5 if eval "test \"`echo '$''{'ac_cv_struct_st_blksize'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include int main() { struct stat s; s.st_blksize; ; return 0; } EOF if { (eval echo configure:7043: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_struct_st_blksize=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* ac_cv_struct_st_blksize=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_struct_st_blksize" 1>&6 if test $ac_cv_struct_st_blksize = yes; then cat >> confdefs.h <<\EOF #define HAVE_ST_BLKSIZE 1 EOF fi fi echo $ac_n "checking for fstatfs""... $ac_c" 1>&6 echo "configure:7065: checking for fstatfs" >&5 if eval "test \"`echo '$''{'ac_cv_func_fstatfs'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char fstatfs(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_fstatfs) || defined (__stub___fstatfs) choke me #else fstatfs(); #endif ; return 0; } EOF if { (eval echo configure:7093: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_fstatfs=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_fstatfs=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'fstatfs`\" = yes"; then echo "$ac_t""yes" 1>&6 : else echo "$ac_t""no" 1>&6 cat >> confdefs.h <<\EOF #define NO_FSTATFS 1 EOF fi #-------------------------------------------------------------------- # Some system have no memcmp or it does not work with 8 bit # data, this checks it and add memcmp.o to LIBOBJS if needed #-------------------------------------------------------------------- echo $ac_n "checking for 8-bit clean memcmp""... $ac_c" 1>&6 echo "configure:7122: checking for 8-bit clean memcmp" >&5 if eval "test \"`echo '$''{'ac_cv_func_memcmp_clean'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$cross_compiling" = yes; then ac_cv_func_memcmp_clean=no else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_func_memcmp_clean=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* ac_cv_func_memcmp_clean=no fi rm -fr conftest* fi fi echo "$ac_t""$ac_cv_func_memcmp_clean" 1>&6 test $ac_cv_func_memcmp_clean = no && LIBOBJS="$LIBOBJS memcmp.${ac_objext}" #-------------------------------------------------------------------- # Some system like SunOS 4 and other BSD like systems # have no memmove (we assume they have bcopy instead). # {The replacement define is in compat/string.h} #-------------------------------------------------------------------- echo $ac_n "checking for memmove""... $ac_c" 1>&6 echo "configure:7164: checking for memmove" >&5 if eval "test \"`echo '$''{'ac_cv_func_memmove'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char memmove(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_memmove) || defined (__stub___memmove) choke me #else memmove(); #endif ; return 0; } EOF if { (eval echo configure:7192: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_memmove=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_memmove=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'memmove`\" = yes"; then echo "$ac_t""yes" 1>&6 : else echo "$ac_t""no" 1>&6 cat >> confdefs.h <<\EOF #define NO_MEMMOVE 1 EOF cat >> confdefs.h <<\EOF #define NO_STRING_H 1 EOF fi #-------------------------------------------------------------------- # On some systems strstr is broken: it returns a pointer even # even if the original string is empty. #-------------------------------------------------------------------- if test "x${ac_cv_func_strstr}" = "xyes"; then echo $ac_n "checking proper strstr implementation""... $ac_c" 1>&6 echo "configure:7225: checking proper strstr implementation" >&5 if eval "test \"`echo '$''{'tcl_cv_strstr_unbroken'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$cross_compiling" = yes; then tcl_cv_strstr_unbroken=broken else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then tcl_cv_strstr_unbroken=ok else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* tcl_cv_strstr_unbroken=broken fi rm -fr conftest* fi fi echo "$ac_t""$tcl_cv_strstr_unbroken" 1>&6 if test $tcl_cv_strstr_unbroken = broken; then LIBOBJS="$LIBOBJS strstr.o" fi fi #-------------------------------------------------------------------- # Check for strtoul function. This is tricky because under some # versions of AIX strtoul returns an incorrect terminator # pointer for the string "0". #-------------------------------------------------------------------- echo $ac_n "checking for strtoul""... $ac_c" 1>&6 echo "configure:7270: checking for strtoul" >&5 if eval "test \"`echo '$''{'ac_cv_func_strtoul'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char strtoul(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_strtoul) || defined (__stub___strtoul) choke me #else strtoul(); #endif ; return 0; } EOF if { (eval echo configure:7298: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_strtoul=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_strtoul=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'strtoul`\" = yes"; then echo "$ac_t""yes" 1>&6 tcl_ok=1 else echo "$ac_t""no" 1>&6 tcl_ok=0 fi if test $tcl_ok = 1; then echo $ac_n "checking proper strtoul implementation""... $ac_c" 1>&6 echo "configure:7320: checking proper strtoul implementation" >&5 if eval "test \"`echo '$''{'tcl_cv_strtoul_unbroken'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$cross_compiling" = yes; then tcl_cv_strtoul_unbroken=broken else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then tcl_cv_strtoul_unbroken=ok else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* tcl_cv_strtoul_unbroken=broken fi rm -fr conftest* fi fi echo "$ac_t""$tcl_cv_strtoul_unbroken" 1>&6 if test $tcl_cv_strtoul_unbroken = broken; then tcl_ok=0 fi fi if test $tcl_ok = 0; then LIBOBJS="$LIBOBJS strtoul.o" fi #-------------------------------------------------------------------- # Check for the strtod function. This is tricky because in some # versions of Linux strtod mis-parses strings starting with "+". #-------------------------------------------------------------------- echo $ac_n "checking for strtod""... $ac_c" 1>&6 echo "configure:7374: checking for strtod" >&5 if eval "test \"`echo '$''{'ac_cv_func_strtod'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char strtod(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_strtod) || defined (__stub___strtod) choke me #else strtod(); #endif ; return 0; } EOF if { (eval echo configure:7402: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_strtod=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_strtod=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'strtod`\" = yes"; then echo "$ac_t""yes" 1>&6 tcl_ok=1 else echo "$ac_t""no" 1>&6 tcl_ok=0 fi if test $tcl_ok = 1; then echo $ac_n "checking proper strtod implementation""... $ac_c" 1>&6 echo "configure:7424: checking proper strtod implementation" >&5 if eval "test \"`echo '$''{'tcl_cv_strtod_unbroken'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$cross_compiling" = yes; then tcl_cv_strtod_unbroken=broken else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then tcl_cv_strtod_unbroken=ok else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* tcl_cv_strtod_unbroken=broken fi rm -fr conftest* fi fi echo "$ac_t""$tcl_cv_strtod_unbroken" 1>&6 if test $tcl_cv_strtod_unbroken = broken; then tcl_ok=0 fi fi if test $tcl_ok = 0; then LIBOBJS="$LIBOBJS strtod.o" fi #-------------------------------------------------------------------- # Under Solaris 2.4, strtod returns the wrong value for the # terminating character under some conditions. Check for this # and if the problem exists use a substitute procedure # "fixstrtod" that corrects the error. #-------------------------------------------------------------------- echo $ac_n "checking for strtod""... $ac_c" 1>&6 echo "configure:7481: checking for strtod" >&5 if eval "test \"`echo '$''{'ac_cv_func_strtod'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char strtod(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_strtod) || defined (__stub___strtod) choke me #else strtod(); #endif ; return 0; } EOF if { (eval echo configure:7509: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_strtod=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_strtod=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'strtod`\" = yes"; then echo "$ac_t""yes" 1>&6 tcl_strtod=1 else echo "$ac_t""no" 1>&6 tcl_strtod=0 fi if test "$tcl_strtod" = 1; then echo $ac_n "checking for Solaris2.4/Tru64 strtod bugs""... $ac_c" 1>&6 echo "configure:7531: checking for Solaris2.4/Tru64 strtod bugs" >&5 if eval "test \"`echo '$''{'tcl_cv_strtod_buggy'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$cross_compiling" = yes; then tcl_cv_strtod_buggy=buggy else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then tcl_cv_strtod_buggy=ok else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* tcl_cv_strtod_buggy=buggy fi rm -fr conftest* fi fi echo "$ac_t""$tcl_cv_strtod_buggy" 1>&6 if test "$tcl_cv_strtod_buggy" = buggy; then LIBOBJS="$LIBOBJS fixstrtod.o" cat >> confdefs.h <<\EOF #define strtod fixstrtod EOF fi fi #-------------------------------------------------------------------- # Check for various typedefs and provide substitutes if # they don't exist. #-------------------------------------------------------------------- echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 echo "configure:7594: checking for ANSI C header files" >&5 if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include #include #include EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:7607: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* ac_cv_header_stdc=yes else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* ac_cv_header_stdc=no fi rm -f conftest* if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat > conftest.$ac_ext < EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "memchr" >/dev/null 2>&1; then : else rm -rf conftest* ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat > conftest.$ac_ext < EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "free" >/dev/null 2>&1; then : else rm -rf conftest* ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : else cat > conftest.$ac_ext < #define ISLOWER(c) ('a' <= (c) && (c) <= 'z') #define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); exit (0); } EOF if { (eval echo configure:7674: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then : else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* ac_cv_header_stdc=no fi rm -fr conftest* fi fi fi echo "$ac_t""$ac_cv_header_stdc" 1>&6 if test $ac_cv_header_stdc = yes; then cat >> confdefs.h <<\EOF #define STDC_HEADERS 1 EOF fi echo $ac_n "checking for mode_t""... $ac_c" 1>&6 echo "configure:7698: checking for mode_t" >&5 if eval "test \"`echo '$''{'ac_cv_type_mode_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #if STDC_HEADERS #include #include #endif EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "(^|[^a-zA-Z_0-9])mode_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then rm -rf conftest* ac_cv_type_mode_t=yes else rm -rf conftest* ac_cv_type_mode_t=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_type_mode_t" 1>&6 if test $ac_cv_type_mode_t = no; then cat >> confdefs.h <<\EOF #define mode_t int EOF fi echo $ac_n "checking for pid_t""... $ac_c" 1>&6 echo "configure:7731: checking for pid_t" >&5 if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #if STDC_HEADERS #include #include #endif EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "(^|[^a-zA-Z_0-9])pid_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then rm -rf conftest* ac_cv_type_pid_t=yes else rm -rf conftest* ac_cv_type_pid_t=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_type_pid_t" 1>&6 if test $ac_cv_type_pid_t = no; then cat >> confdefs.h <<\EOF #define pid_t int EOF fi echo $ac_n "checking for size_t""... $ac_c" 1>&6 echo "configure:7764: checking for size_t" >&5 if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #if STDC_HEADERS #include #include #endif EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "(^|[^a-zA-Z_0-9])size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then rm -rf conftest* ac_cv_type_size_t=yes else rm -rf conftest* ac_cv_type_size_t=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_type_size_t" 1>&6 if test $ac_cv_type_size_t = no; then cat >> confdefs.h <<\EOF #define size_t unsigned EOF fi echo $ac_n "checking for uid_t in sys/types.h""... $ac_c" 1>&6 echo "configure:7797: checking for uid_t in sys/types.h" >&5 if eval "test \"`echo '$''{'ac_cv_type_uid_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "uid_t" >/dev/null 2>&1; then rm -rf conftest* ac_cv_type_uid_t=yes else rm -rf conftest* ac_cv_type_uid_t=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_type_uid_t" 1>&6 if test $ac_cv_type_uid_t = no; then cat >> confdefs.h <<\EOF #define uid_t int EOF cat >> confdefs.h <<\EOF #define gid_t int EOF fi echo $ac_n "checking for socklen_t""... $ac_c" 1>&6 echo "configure:7832: checking for socklen_t" >&5 if eval "test \"`echo '$''{'ac_cv_type_socklen_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include #if STDC_HEADERS #include #include #endif EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "(^|[^a-zA-Z_0-9])socklen_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then rm -rf conftest* ac_cv_type_socklen_t=yes else rm -rf conftest* ac_cv_type_socklen_t=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_type_socklen_t" 1>&6 if test $ac_cv_type_socklen_t = no; then cat >> confdefs.h <<\EOF #define socklen_t unsigned EOF fi #-------------------------------------------------------------------- # If a system doesn't have an opendir function (man, that's old!) # then we have to supply a different version of dirent.h which # is compatible with the substitute version of opendir that's # provided. This version only works with V7-style directories. #-------------------------------------------------------------------- echo $ac_n "checking for opendir""... $ac_c" 1>&6 echo "configure:7877: checking for opendir" >&5 if eval "test \"`echo '$''{'ac_cv_func_opendir'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char opendir(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_opendir) || defined (__stub___opendir) choke me #else opendir(); #endif ; return 0; } EOF if { (eval echo configure:7905: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_opendir=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_opendir=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'opendir`\" = yes"; then echo "$ac_t""yes" 1>&6 : else echo "$ac_t""no" 1>&6 cat >> confdefs.h <<\EOF #define USE_DIRENT2_H 1 EOF fi #-------------------------------------------------------------------- # The check below checks whether defines the type # "union wait" correctly. It's needed because of weirdness in # HP-UX where "union wait" is defined in both the BSD and SYS-V # environments. Checking the usability of WIFEXITED seems to do # the trick. #-------------------------------------------------------------------- echo $ac_n "checking union wait""... $ac_c" 1>&6 echo "configure:7938: checking union wait" >&5 if eval "test \"`echo '$''{'tcl_cv_union_wait'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include int main() { union wait x; WIFEXITED(x); /* Generates compiler error if WIFEXITED * uses an int. */ ; return 0; } EOF if { (eval echo configure:7956: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* tcl_cv_union_wait=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_union_wait=no fi rm -f conftest* fi echo "$ac_t""$tcl_cv_union_wait" 1>&6 if test $tcl_cv_union_wait = no; then cat >> confdefs.h <<\EOF #define NO_UNION_WAIT 1 EOF fi #-------------------------------------------------------------------- # Check whether there is an strncasecmp function on this system. # This is a bit tricky because under SCO it's in -lsocket and # under Sequent Dynix it's in -linet. #-------------------------------------------------------------------- echo $ac_n "checking for strncasecmp""... $ac_c" 1>&6 echo "configure:7983: checking for strncasecmp" >&5 if eval "test \"`echo '$''{'ac_cv_func_strncasecmp'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char strncasecmp(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_strncasecmp) || defined (__stub___strncasecmp) choke me #else strncasecmp(); #endif ; return 0; } EOF if { (eval echo configure:8011: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_strncasecmp=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_strncasecmp=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'strncasecmp`\" = yes"; then echo "$ac_t""yes" 1>&6 tcl_ok=1 else echo "$ac_t""no" 1>&6 tcl_ok=0 fi if test "$tcl_ok" = 0; then echo $ac_n "checking for strncasecmp in -lsocket""... $ac_c" 1>&6 echo "configure:8033: checking for strncasecmp in -lsocket" >&5 ac_lib_var=`echo socket'_'strncasecmp | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lsocket $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 tcl_ok=1 else echo "$ac_t""no" 1>&6 tcl_ok=0 fi fi if test "$tcl_ok" = 0; then echo $ac_n "checking for strncasecmp in -linet""... $ac_c" 1>&6 echo "configure:8076: checking for strncasecmp in -linet" >&5 ac_lib_var=`echo inet'_'strncasecmp | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-linet $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=no" fi rm -f conftest* LIBS="$ac_save_LIBS" fi if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then echo "$ac_t""yes" 1>&6 tcl_ok=1 else echo "$ac_t""no" 1>&6 tcl_ok=0 fi fi if test "$tcl_ok" = 0; then LIBOBJS="$LIBOBJS strncasecmp.o" fi #-------------------------------------------------------------------- # The code below deals with several issues related to gettimeofday: # 1. Some systems don't provide a gettimeofday function at all # (set NO_GETTOD if this is the case). # 2. See if gettimeofday is declared in the header file. # if not, set the GETTOD_NOT_DECLARED flag so that tclPort.h can # declare it. #-------------------------------------------------------------------- echo $ac_n "checking for gettimeofday""... $ac_c" 1>&6 echo "configure:8131: checking for gettimeofday" >&5 if eval "test \"`echo '$''{'ac_cv_func_gettimeofday'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char gettimeofday(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_gettimeofday) || defined (__stub___gettimeofday) choke me #else gettimeofday(); #endif ; return 0; } EOF if { (eval echo configure:8159: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_gettimeofday=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_gettimeofday=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'gettimeofday`\" = yes"; then echo "$ac_t""yes" 1>&6 : else echo "$ac_t""no" 1>&6 cat >> confdefs.h <<\EOF #define NO_GETTOD 1 EOF fi echo $ac_n "checking for gettimeofday declaration""... $ac_c" 1>&6 echo "configure:8183: checking for gettimeofday declaration" >&5 if eval "test \"`echo '$''{'tcl_cv_grep_gettimeofday'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "gettimeofday" >/dev/null 2>&1; then rm -rf conftest* tcl_cv_grep_gettimeofday=present else rm -rf conftest* tcl_cv_grep_gettimeofday=missing fi rm -f conftest* fi echo "$ac_t""$tcl_cv_grep_gettimeofday" 1>&6 if test $tcl_cv_grep_gettimeofday = missing ; then cat >> confdefs.h <<\EOF #define GETTOD_NOT_DECLARED 1 EOF fi #-------------------------------------------------------------------- # The following code checks to see whether it is possible to get # signed chars on this platform. This is needed in order to # properly generate sign-extended ints from character values. #-------------------------------------------------------------------- echo $ac_n "checking whether char is unsigned""... $ac_c" 1>&6 echo "configure:8220: checking whether char is unsigned" >&5 if eval "test \"`echo '$''{'ac_cv_c_char_unsigned'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$GCC" = yes; then # GCC predefines this symbol on systems where it applies. cat > conftest.$ac_ext <&5 | egrep "yes" >/dev/null 2>&1; then rm -rf conftest* ac_cv_c_char_unsigned=yes else rm -rf conftest* ac_cv_c_char_unsigned=no fi rm -f conftest* else if test "$cross_compiling" = yes; then { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_c_char_unsigned=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* ac_cv_c_char_unsigned=no fi rm -fr conftest* fi fi fi echo "$ac_t""$ac_cv_c_char_unsigned" 1>&6 if test $ac_cv_c_char_unsigned = yes && test "$GCC" != yes; then cat >> confdefs.h <<\EOF #define __CHAR_UNSIGNED__ 1 EOF fi echo $ac_n "checking signed char declarations""... $ac_c" 1>&6 echo "configure:8283: checking signed char declarations" >&5 if eval "test \"`echo '$''{'tcl_cv_char_signed'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_cv_char_signed=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_char_signed=no fi rm -f conftest* fi echo "$ac_t""$tcl_cv_char_signed" 1>&6 if test $tcl_cv_char_signed = yes; then cat >> confdefs.h <<\EOF #define HAVE_SIGNED_CHAR 1 EOF fi #-------------------------------------------------------------------- # Does putenv() copy or not? We need to know to avoid memory leaks. #-------------------------------------------------------------------- echo $ac_n "checking for a putenv() that copies the buffer""... $ac_c" 1>&6 echo "configure:8324: checking for a putenv() that copies the buffer" >&5 if eval "test \"`echo '$''{'tcl_cv_putenv_copy'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$cross_compiling" = yes; then tcl_cv_putenv_copy=no else cat > conftest.$ac_ext < #define OURVAR "havecopy=yes" int main (int argc, char *argv[]) { char *foo, *bar; foo = (char *)strdup(OURVAR); putenv(foo); strcpy((char *)(strchr(foo, '=') + 1), "no"); bar = getenv("havecopy"); if (!strcmp(bar, "no")) { /* doesnt copy */ return 0; } else { /* does copy */ return 1; } } EOF if { (eval echo configure:8355: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then tcl_cv_putenv_copy=no else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* tcl_cv_putenv_copy=yes fi rm -fr conftest* fi fi echo "$ac_t""$tcl_cv_putenv_copy" 1>&6 if test $tcl_cv_putenv_copy = yes; then cat >> confdefs.h <<\EOF #define HAVE_PUTENV_THAT_COPIES 1 EOF fi #-------------------------------------------------------------------- # Check for support of nl_langinfo function #-------------------------------------------------------------------- # Check whether --enable-langinfo or --disable-langinfo was given. if test "${enable_langinfo+set}" = set; then enableval="$enable_langinfo" langinfo_ok=$enableval else langinfo_ok=yes fi HAVE_LANGINFO=0 if test "$langinfo_ok" = "yes"; then ac_safe=`echo "langinfo.h" | sed 'y%./+-%__p_%'` echo $ac_n "checking for langinfo.h""... $ac_c" 1>&6 echo "configure:8395: checking for langinfo.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:8405: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 langinfo_ok=yes else echo "$ac_t""no" 1>&6 langinfo_ok=no fi fi echo $ac_n "checking whether to use nl_langinfo""... $ac_c" 1>&6 echo "configure:8429: checking whether to use nl_langinfo" >&5 if test "$langinfo_ok" = "yes"; then if eval "test \"`echo '$''{'tcl_cv_langinfo_h'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { nl_langinfo(CODESET); ; return 0; } EOF if { (eval echo configure:8443: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_cv_langinfo_h=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_langinfo_h=no fi rm -f conftest* fi echo "$ac_t""$tcl_cv_langinfo_h" 1>&6 if test $tcl_cv_langinfo_h = yes; then cat >> confdefs.h <<\EOF #define HAVE_LANGINFO 1 EOF fi else echo "$ac_t""$langinfo_ok" 1>&6 fi #-------------------------------------------------------------------- # Darwin specific API checks and defines #-------------------------------------------------------------------- if test "`uname -s`" = "Darwin" ; then for ac_hdr in copyfile.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 echo "configure:8476: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:8486: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` cat >> confdefs.h <&6 fi done for ac_func in copyfile do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 echo "configure:8515: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else $ac_func(); #endif ; return 0; } EOF if { (eval echo configure:8543: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_$ac_func=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` cat >> confdefs.h <&6 fi done if test $tcl_corefoundation = yes; then for ac_hdr in libkern/OSAtomic.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 echo "configure:8572: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:8582: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` cat >> confdefs.h <&6 fi done for ac_func in OSSpinLockLock do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 echo "configure:8611: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else $ac_func(); #endif ; return 0; } EOF if { (eval echo configure:8639: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_$ac_func=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` cat >> confdefs.h <&6 fi done for ac_func in pthread_atfork do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 echo "configure:8666: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func(); int main() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else $ac_func(); #endif ; return 0; } EOF if { (eval echo configure:8694: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_func_$ac_func=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` cat >> confdefs.h <&6 fi done fi cat >> confdefs.h <<\EOF #define USE_VFORK 1 EOF cat >> confdefs.h <<\EOF #define TCL_DEFAULT_ENCODING "utf-8" EOF cat >> confdefs.h <<\EOF #define TCL_LOAD_FROM_MEMORY 1 EOF for ac_hdr in AvailabilityMacros.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 echo "configure:8735: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:8745: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` cat >> confdefs.h <&6 fi done if test "$ac_cv_header_AvailabilityMacros_h" = yes; then echo $ac_n "checking if weak import is available""... $ac_c" 1>&6 echo "configure:8773: checking if weak import is available" >&5 if eval "test \"`echo '$''{'tcl_cv_cc_weak_import'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -Werror" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* tcl_cv_cc_weak_import=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_cc_weak_import=no fi rm -f conftest* CFLAGS=$hold_cflags fi echo "$ac_t""$tcl_cv_cc_weak_import" 1>&6 if test $tcl_cv_cc_weak_import = yes; then cat >> confdefs.h <<\EOF #define HAVE_WEAK_IMPORT 1 EOF fi fi fi #-------------------------------------------------------------------- # Check for support of fts functions (readdir replacement) #-------------------------------------------------------------------- echo $ac_n "checking for fts""... $ac_c" 1>&6 echo "configure:8824: checking for fts" >&5 if eval "test \"`echo '$''{'tcl_cv_api_fts'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include #include int main() { char*const p[2] = {"/", NULL}; FTS *f = fts_open(p, FTS_PHYSICAL|FTS_NOCHDIR|FTS_NOSTAT, NULL); FTSENT *e = fts_read(f); fts_close(f); ; return 0; } EOF if { (eval echo configure:8845: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* tcl_cv_api_fts=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_api_fts=no fi rm -f conftest* fi echo "$ac_t""$tcl_cv_api_fts" 1>&6 if test $tcl_cv_api_fts = yes; then cat >> confdefs.h <<\EOF #define HAVE_FTS 1 EOF fi #-------------------------------------------------------------------- # The statements below check for systems where POSIX-style # non-blocking I/O (O_NONBLOCK) doesn't work or is unimplemented. # On these systems (mostly older ones), use the old BSD-style # FIONBIO approach instead. #-------------------------------------------------------------------- for ac_hdr in sys/ioctl.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 echo "configure:8877: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:8887: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` cat >> confdefs.h <&6 fi done for ac_hdr in sys/filio.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 echo "configure:8917: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:8927: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` cat >> confdefs.h <&6 fi done echo $ac_n "checking system version""... $ac_c" 1>&6 echo "configure:8955: checking system version" >&5 if eval "test \"`echo '$''{'tcl_cv_sys_version'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -f /usr/lib/NextStep/software_version; then tcl_cv_sys_version=NEXTSTEP-`awk '/3/,/3/' /usr/lib/NextStep/software_version` else tcl_cv_sys_version=`uname -s`-`uname -r` if test "$?" -ne 0 ; then echo "configure: warning: can't find uname command" 1>&2 tcl_cv_sys_version=unknown else # Special check for weird MP-RAS system (uname returns weird # results, and the version is kept in special file). if test -r /etc/.relid -a "X`uname -n`" = "X`uname -s`" ; then tcl_cv_sys_version=MP-RAS-`awk '{print $3}' /etc/.relid` fi if test "`uname -s`" = "AIX" ; then tcl_cv_sys_version=AIX-`uname -v`.`uname -r` fi fi fi fi echo "$ac_t""$tcl_cv_sys_version" 1>&6 system=$tcl_cv_sys_version echo $ac_n "checking FIONBIO vs. O_NONBLOCK for nonblocking I/O""... $ac_c" 1>&6 echo "configure:8986: checking FIONBIO vs. O_NONBLOCK for nonblocking I/O" >&5 case $system in OSF*) cat >> confdefs.h <<\EOF #define USE_FIONBIO 1 EOF echo "$ac_t""FIONBIO" 1>&6 ;; SunOS-4*) cat >> confdefs.h <<\EOF #define USE_FIONBIO 1 EOF echo "$ac_t""FIONBIO" 1>&6 ;; ULTRIX-4.*) cat >> confdefs.h <<\EOF #define USE_FIONBIO 1 EOF echo "$ac_t""FIONBIO" 1>&6 ;; *) echo "$ac_t""O_NONBLOCK" 1>&6 ;; esac #-------------------------------------------------------------------- # DTrace support #-------------------------------------------------------------------- # Check whether --enable-dtrace or --disable-dtrace was given. if test "${enable_dtrace+set}" = set; then enableval="$enable_dtrace" tcl_ok=$enableval else tcl_ok=no fi if test $tcl_ok = yes; then ac_safe=`echo "sys/sdt.h" | sed 'y%./+-%__p_%'` echo $ac_n "checking for sys/sdt.h""... $ac_c" 1>&6 echo "configure:9030: checking for sys/sdt.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:9040: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 tcl_ok=yes else echo "$ac_t""no" 1>&6 tcl_ok=no fi fi if test $tcl_ok = yes; then # Extract the first word of "dtrace", so it can be a program name with args. set dummy dtrace; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo "configure:9067: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_DTRACE'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else case "$DTRACE" in /*) ac_cv_path_DTRACE="$DTRACE" # Let the user override the test with a path. ;; ?:/*) ac_cv_path_DTRACE="$DTRACE" # Let the user override the test with a dos path. ;; *) IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" ac_dummy="$PATH:/usr/sbin" for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_path_DTRACE="$ac_dir/$ac_word" break fi done IFS="$ac_save_ifs" ;; esac fi DTRACE="$ac_cv_path_DTRACE" if test -n "$DTRACE"; then echo "$ac_t""$DTRACE" 1>&6 else echo "$ac_t""no" 1>&6 fi test -z "$ac_cv_path_DTRACE" && tcl_ok=no fi echo $ac_n "checking whether to enable DTrace support""... $ac_c" 1>&6 echo "configure:9102: checking whether to enable DTrace support" >&5 MAKEFILE_SHELL='/bin/sh' if test $tcl_ok = yes; then cat >> confdefs.h <<\EOF #define USE_DTRACE 1 EOF DTRACE_SRC="\${DTRACE_SRC}" DTRACE_HDR="\${DTRACE_HDR}" if test "`uname -s`" != "Darwin" ; then DTRACE_OBJ="\${DTRACE_OBJ}" if test "`uname -s`" = "SunOS" -a "$SHARED_BUILD" = "0" ; then # Need to create an intermediate object file to ensure tclDTrace.o # gets included when linking against the static tcl library. STLIB_LD='stlib_ld () { /usr/ccs/bin/ld -r -o $${1%.a}.o "$${@:2}" && '"${STLIB_LD}"' $${1} $${1%.a}.o ; } && stlib_ld' MAKEFILE_SHELL='/bin/bash' # Force use of Sun ar and ranlib, the GNU versions choke on # tclDTrace.o and the combined object file above. AR='/usr/ccs/bin/ar' RANLIB='/usr/ccs/bin/ranlib' fi fi fi echo "$ac_t""$tcl_ok" 1>&6 #-------------------------------------------------------------------- # The check below checks whether the cpuid instruction is usable. #-------------------------------------------------------------------- echo $ac_n "checking whether the cpuid instruction is usable""... $ac_c" 1>&6 echo "configure:9132: checking whether the cpuid instruction is usable" >&5 if eval "test \"`echo '$''{'tcl_cv_cpuid'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* tcl_cv_cpuid=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_cpuid=no fi rm -f conftest* fi echo "$ac_t""$tcl_cv_cpuid" 1>&6 if test $tcl_cv_cpuid = yes; then cat >> confdefs.h <<\EOF #define HAVE_CPUID 1 EOF fi #-------------------------------------------------------------------- # The statements below define a collection of symbols related to # building libtcl as a shared library instead of a static library. #-------------------------------------------------------------------- TCL_UNSHARED_LIB_SUFFIX=${UNSHARED_LIB_SUFFIX} TCL_SHARED_LIB_SUFFIX=${SHARED_LIB_SUFFIX} eval "TCL_LIB_FILE=libtcl${LIB_SUFFIX}" # tclConfig.sh needs a version of the _LIB_SUFFIX that has been eval'ed # so that the backslashes quoting the DBX braces are dropped. # Trick to replace DBGX with TCL_DBGX DBGX='${TCL_DBGX}' eval "TCL_LIB_FILE=${TCL_LIB_FILE}" TCL_LIBRARY='$(prefix)/lib/tcl$(VERSION)' PRIVATE_INCLUDE_DIR='$(includedir)' HTML_DIR='$(DISTDIR)/html' # Note: in the following variable, it's important to use the absolute # path name of the Tcl directory rather than "..": this is because # AIX remembers this path and will attempt to use it at run-time to look # up the Tcl library. if test "`uname -s`" = "Darwin" ; then if test "`uname -s`" = "Darwin" ; then echo $ac_n "checking how to package libraries""... $ac_c" 1>&6 echo "configure:9202: checking how to package libraries" >&5 # Check whether --enable-framework or --disable-framework was given. if test "${enable_framework+set}" = set; then enableval="$enable_framework" enable_framework=$enableval else enable_framework=no fi if test $enable_framework = yes; then if test $SHARED_BUILD = 0; then echo "configure: warning: Frameworks can only be built if --enable-shared is yes" 1>&2 enable_framework=no fi if test $tcl_corefoundation = no; then echo "configure: warning: Frameworks can only be used when CoreFoundation is available" 1>&2 enable_framework=no fi fi if test $enable_framework = yes; then echo "$ac_t""framework" 1>&6 FRAMEWORK_BUILD=1 else if test $SHARED_BUILD = 1; then echo "$ac_t""shared library" 1>&6 else echo "$ac_t""static library" 1>&6 fi FRAMEWORK_BUILD=0 fi fi TCL_SHLIB_LD_EXTRAS="-compatibility_version ${TCL_VERSION} -current_version ${TCL_VERSION}`echo ${TCL_PATCH_LEVEL} | awk '{match($0, "\\\.[0-9]+"); print substr($0,RSTART,RLENGTH)}'`" TCL_SHLIB_LD_EXTRAS="${TCL_SHLIB_LD_EXTRAS}"' -install_name ${DYLIB_INSTALL_DIR}/${TCL_LIB_FILE}' echo "$LDFLAGS " | grep -q -- '-prebind ' && TCL_SHLIB_LD_EXTRAS="${TCL_SHLIB_LD_EXTRAS}"' -seg1addr 0xa000000' TCL_SHLIB_LD_EXTRAS="${TCL_SHLIB_LD_EXTRAS}"' -sectcreate __TEXT __info_plist Tcl-Info.plist' EXTRA_TCLSH_LIBS='-sectcreate __TEXT __info_plist Tclsh-Info.plist' EXTRA_APP_CC_SWITCHES='-mdynamic-no-pic' tcl_config_files="${tcl_config_files} Tcl-Info.plist:../macosx/Tcl-Info.plist.in Tclsh-Info.plist:../macosx/Tclsh-Info.plist.in" TCL_YEAR="`date +%Y`" fi if test "$FRAMEWORK_BUILD" = "1" ; then cat >> confdefs.h <<\EOF #define TCL_FRAMEWORK 1 EOF # Construct a fake local framework structure to make linking with # '-framework Tcl' and running of tcltest work LD_LIBRARY_PATH_VAR="DYLD_FRAMEWORK_PATH" if test "${libdir}" = '${exec_prefix}/lib'; then # override libdir default libdir="/Library/Frameworks" fi TCL_LIB_FILE="Tcl" TCL_LIB_FLAG="-framework Tcl" TCL_BUILD_LIB_SPEC="-F`pwd` -framework Tcl" TCL_LIB_SPEC="-F${libdir} -framework Tcl" libdir="${libdir}/Tcl.framework/Versions/\${VERSION}" TCL_LIBRARY="${libdir}/Resources/Scripts" includedir="${libdir}/Headers" PRIVATE_INCLUDE_DIR="${libdir}/PrivateHeaders" HTML_DIR="${libdir}/Resources/Documentation/Reference/Tcl" EXTRA_INSTALL="install-private-headers html-tcl" EXTRA_BUILD_HTML='@ln -fs contents.htm $(HTML_INSTALL_DIR)/TclTOC.html' EXTRA_INSTALL_BINARIES='@echo "Installing Info.plist to $(LIB_INSTALL_DIR)/Resources" && mkdir -p "$(LIB_INSTALL_DIR)/Resources" && $(INSTALL_DATA) Tcl-Info.plist "$(LIB_INSTALL_DIR)/Resources/Info.plist"' EXTRA_INSTALL_BINARIES="$EXTRA_INSTALL_BINARIES"' && echo "Installing license.terms to $(LIB_INSTALL_DIR)/Resources" && $(INSTALL_DATA) "$(TOP_DIR)/license.terms" "$(LIB_INSTALL_DIR)/Resources"' EXTRA_INSTALL_BINARIES="$EXTRA_INSTALL_BINARIES"' && echo "Finalizing Tcl.framework" && rm -f "$(LIB_INSTALL_DIR)/../Current" && ln -s "$(VERSION)" "$(LIB_INSTALL_DIR)/../Current" && for f in "$(LIB_FILE)" tclConfig.sh Resources Headers PrivateHeaders; do rm -f "$(LIB_INSTALL_DIR)/../../$$f" && ln -s "Versions/Current/$$f" "$(LIB_INSTALL_DIR)/../.."; done && f="$(STUB_LIB_FILE)" && rm -f "$(LIB_INSTALL_DIR)/../../$$f" && ln -s "Versions/$(VERSION)/$$f" "$(LIB_INSTALL_DIR)/../.."' # Don't use AC_DEFINE for the following as the framework version define # needs to go into the Makefile even when using autoheader, so that we # can pick up a potential make override of VERSION. Also, don't put this # into CFLAGS as it should not go into tclConfig.sh EXTRA_CC_SWITCHES='-DTCL_FRAMEWORK_VERSION=\"$(VERSION)\"' else # libdir must be a fully qualified path and not ${exec_prefix}/lib eval libdir="$libdir" if test "$SHARED_BUILD" = "0" || test "$TCL_NEEDS_EXP_FILE" = "0"; then if test "${TCL_LIB_VERSIONS_OK}" = "ok"; then TCL_LIB_FLAG="-ltcl${TCL_VERSION}\${TCL_DBGX}" else TCL_LIB_FLAG="-ltcl`echo ${TCL_VERSION} | tr -d .`\${TCL_DBGX}" fi TCL_BUILD_LIB_SPEC="-L`pwd` ${TCL_LIB_FLAG}" TCL_LIB_SPEC="-L${libdir} ${TCL_LIB_FLAG}" else TCL_BUILD_EXP_FILE="lib.exp" eval "TCL_EXP_FILE=libtcl${TCL_EXPORT_FILE_SUFFIX}" # Replace DBGX with TCL_DBGX eval "TCL_EXP_FILE=\"${TCL_EXP_FILE}\"" if test "$GCC" = "yes" ; then TCL_BUILD_LIB_SPEC="-Wl,-bI:`pwd`/${TCL_BUILD_EXP_FILE} -L`pwd`" TCL_LIB_SPEC="-Wl,-bI:${libdir}/${TCL_EXP_FILE} -L`pwd`" else TCL_BUILD_LIB_SPEC="-bI:`pwd`/${TCL_BUILD_EXP_FILE}" TCL_LIB_SPEC="-bI:${libdir}/${TCL_EXP_FILE}" fi fi fi VERSION='${VERSION}' eval "CFG_TCL_SHARED_LIB_SUFFIX=${TCL_SHARED_LIB_SUFFIX}" eval "CFG_TCL_UNSHARED_LIB_SUFFIX=${TCL_UNSHARED_LIB_SUFFIX}" eval "CFG_TCL_EXPORT_FILE_SUFFIX=${TCL_EXPORT_FILE_SUFFIX}" VERSION=${TCL_VERSION} #-------------------------------------------------------------------- # The statements below define the symbol TCL_PACKAGE_PATH, which # gives a list of directories that may contain packages. The list # consists of one directory for machine-dependent binaries and # another for platform-independent scripts. #-------------------------------------------------------------------- if test "$FRAMEWORK_BUILD" = "1" ; then test -z "$TCL_PACKAGE_PATH" && \ TCL_PACKAGE_PATH="~/Library/Tcl /Library/Tcl /Network/Library/Tcl /System/Library/Tcl ~/Library/Frameworks /Library/Frameworks /Network/Library/Frameworks /System/Library/Frameworks" elif test "$prefix" != "$exec_prefix"; then TCL_PACKAGE_PATH="${libdir} ${prefix}/lib ${TCL_PACKAGE_PATH}" else TCL_PACKAGE_PATH="${prefix}/lib ${TCL_PACKAGE_PATH}" fi #-------------------------------------------------------------------- # The statements below define various symbols relating to Tcl # stub support. #-------------------------------------------------------------------- # Replace ${VERSION} with contents of ${TCL_VERSION} eval "TCL_STUB_LIB_FILE=libtclstub${TCL_UNSHARED_LIB_SUFFIX}" # Replace DBGX with TCL_DBGX eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\"" eval "TCL_STUB_LIB_DIR=${libdir}" if test "${TCL_LIB_VERSIONS_OK}" = "ok"; then TCL_STUB_LIB_FLAG="-ltclstub${TCL_VERSION}\${TCL_DBGX}" else TCL_STUB_LIB_FLAG="-ltclstub`echo ${TCL_VERSION} | tr -d .`\${TCL_DBGX}" fi TCL_BUILD_STUB_LIB_SPEC="-L`pwd` ${TCL_STUB_LIB_FLAG}" TCL_STUB_LIB_SPEC="-L${TCL_STUB_LIB_DIR} ${TCL_STUB_LIB_FLAG}" TCL_BUILD_STUB_LIB_PATH="`pwd`/${TCL_STUB_LIB_FILE}" TCL_STUB_LIB_PATH="${TCL_STUB_LIB_DIR}/${TCL_STUB_LIB_FILE}" # Install time header dir can be set via --includedir eval "TCL_INCLUDE_SPEC=\"-I${includedir}\"" #------------------------------------------------------------------------ # tclConfig.sh refers to this by a different name #------------------------------------------------------------------------ TCL_SHARED_BUILD=${SHARED_BUILD} CFLAGS="${CFLAGS} ${CPPFLAGS}"; CPPFLAGS="" tcl_config_files="${tcl_config_files} Makefile dltest/Makefile tclConfig.sh" trap '' 1 2 15 cat > confcache <<\EOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs. It is not useful on other systems. # If it contains results you don't want to keep, you may remove or edit it. # # By default, configure uses ./config.cache as the cache file, # creating it if it does not exist already. You can give configure # the --cache-file=FILE option to use a different cache file; that is # what configure does when it calls configure scripts in # subdirectories, so they share the cache. # Giving --cache-file=/dev/null disables caching, for debugging configure. # config.status only pays attention to the cache file if you give it the # --recheck option to rerun configure. # EOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, don't put newlines in cache variables' values. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. (set) 2>&1 | case `(ac_space=' '; set | grep ac_space) 2>&1` in *ac_space=\ *) # `set' does not quote correctly, so add quotes (double-quote substitution # turns \\\\ into \\, and sed turns \\ into \). sed -n \ -e "s/'/'\\\\''/g" \ -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" ;; *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' ;; esac >> confcache if cmp -s $cache_file confcache; then : else if test -w $cache_file; then echo "updating cache $cache_file" cat confcache > $cache_file else echo "not updating unwritable cache $cache_file" fi fi rm -f confcache trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Any assignment to VPATH causes Sun make to only execute # the first set of double-colon rules, so remove it if not needed. # If there is a colon in the path, we need to keep it. if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' fi trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. cat > conftest.defs <<\EOF s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%-D\1=\2%g s%[ `~#$^&*(){}\\|;'"<>?]%\\&%g s%\[%\\&%g s%\]%\\&%g s%\$%$$%g EOF DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '` rm -f conftest.defs # Without the "./", some shells look in PATH for config.status. : ${CONFIG_STATUS=./config.status} echo creating $CONFIG_STATUS rm -f $CONFIG_STATUS cat > $CONFIG_STATUS </dev/null | sed 1q`: # # $0 $ac_configure_args # # Compiler output produced by configure, useful for debugging # configure, is in ./config.log if it exists. ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" for ac_option do case "\$ac_option" in -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; -version | --version | --versio | --versi | --vers | --ver | --ve | --v) echo "$CONFIG_STATUS generated by autoconf version 2.13" exit 0 ;; -help | --help | --hel | --he | --h) echo "\$ac_cs_usage"; exit 0 ;; *) echo "\$ac_cs_usage"; exit 1 ;; esac done ac_given_srcdir=$srcdir trap 'rm -fr `echo "${tcl_config_files}" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 EOF cat >> $CONFIG_STATUS < conftest.subs <<\\CEOF $ac_vpsub $extrasub s%@SHELL@%$SHELL%g s%@CFLAGS@%$CFLAGS%g s%@CPPFLAGS@%$CPPFLAGS%g s%@CXXFLAGS@%$CXXFLAGS%g s%@FFLAGS@%$FFLAGS%g s%@DEFS@%$DEFS%g s%@LDFLAGS@%$LDFLAGS%g s%@LIBS@%$LIBS%g s%@exec_prefix@%$exec_prefix%g s%@prefix@%$prefix%g s%@program_transform_name@%$program_transform_name%g s%@bindir@%$bindir%g s%@sbindir@%$sbindir%g s%@libexecdir@%$libexecdir%g s%@datadir@%$datadir%g s%@sysconfdir@%$sysconfdir%g s%@sharedstatedir@%$sharedstatedir%g s%@localstatedir@%$localstatedir%g s%@libdir@%$libdir%g s%@includedir@%$includedir%g s%@oldincludedir@%$oldincludedir%g s%@infodir@%$infodir%g s%@mandir@%$mandir%g s%@MAN_FLAGS@%$MAN_FLAGS%g s%@CC@%$CC%g s%@CPP@%$CPP%g s%@TCL_THREADS@%$TCL_THREADS%g s%@TCL_LIBS@%$TCL_LIBS%g s%@MATH_LIBS@%$MATH_LIBS%g s%@RANLIB@%$RANLIB%g s%@AR@%$AR%g s%@DL_LIBS@%$DL_LIBS%g s%@DL_OBJS@%$DL_OBJS%g s%@PLAT_OBJS@%$PLAT_OBJS%g s%@PLAT_SRCS@%$PLAT_SRCS%g s%@CFLAGS_DEBUG@%$CFLAGS_DEBUG%g s%@CFLAGS_OPTIMIZE@%$CFLAGS_OPTIMIZE%g s%@CFLAGS_WARNING@%$CFLAGS_WARNING%g s%@LDFLAGS_DEBUG@%$LDFLAGS_DEBUG%g s%@LDFLAGS_OPTIMIZE@%$LDFLAGS_OPTIMIZE%g s%@CC_SEARCH_FLAGS@%$CC_SEARCH_FLAGS%g s%@LD_SEARCH_FLAGS@%$LD_SEARCH_FLAGS%g s%@STLIB_LD@%$STLIB_LD%g s%@SHLIB_LD@%$SHLIB_LD%g s%@TCL_SHLIB_LD_EXTRAS@%$TCL_SHLIB_LD_EXTRAS%g s%@TK_SHLIB_LD_EXTRAS@%$TK_SHLIB_LD_EXTRAS%g s%@SHLIB_LD_LIBS@%$SHLIB_LD_LIBS%g s%@SHLIB_CFLAGS@%$SHLIB_CFLAGS%g s%@SHLIB_SUFFIX@%$SHLIB_SUFFIX%g s%@MAKE_LIB@%$MAKE_LIB%g s%@MAKE_STUB_LIB@%$MAKE_STUB_LIB%g s%@INSTALL_LIB@%$INSTALL_LIB%g s%@DLL_INSTALL_DIR@%$DLL_INSTALL_DIR%g s%@INSTALL_STUB_LIB@%$INSTALL_STUB_LIB%g s%@CFLAGS_DEFAULT@%$CFLAGS_DEFAULT%g s%@LDFLAGS_DEFAULT@%$LDFLAGS_DEFAULT%g s%@LIBOBJS@%$LIBOBJS%g s%@DTRACE@%$DTRACE%g s%@TCL_VERSION@%$TCL_VERSION%g s%@TCL_MAJOR_VERSION@%$TCL_MAJOR_VERSION%g s%@TCL_MINOR_VERSION@%$TCL_MINOR_VERSION%g s%@TCL_PATCH_LEVEL@%$TCL_PATCH_LEVEL%g s%@TCL_YEAR@%$TCL_YEAR%g s%@TCL_LIB_FILE@%$TCL_LIB_FILE%g s%@TCL_LIB_FLAG@%$TCL_LIB_FLAG%g s%@TCL_LIB_SPEC@%$TCL_LIB_SPEC%g s%@TCL_STUB_LIB_FILE@%$TCL_STUB_LIB_FILE%g s%@TCL_STUB_LIB_FLAG@%$TCL_STUB_LIB_FLAG%g s%@TCL_STUB_LIB_SPEC@%$TCL_STUB_LIB_SPEC%g s%@TCL_STUB_LIB_PATH@%$TCL_STUB_LIB_PATH%g s%@TCL_INCLUDE_SPEC@%$TCL_INCLUDE_SPEC%g s%@TCL_BUILD_STUB_LIB_SPEC@%$TCL_BUILD_STUB_LIB_SPEC%g s%@TCL_BUILD_STUB_LIB_PATH@%$TCL_BUILD_STUB_LIB_PATH%g s%@TCL_SRC_DIR@%$TCL_SRC_DIR%g s%@TCL_DBGX@%$TCL_DBGX%g s%@CFG_TCL_SHARED_LIB_SUFFIX@%$CFG_TCL_SHARED_LIB_SUFFIX%g s%@CFG_TCL_UNSHARED_LIB_SUFFIX@%$CFG_TCL_UNSHARED_LIB_SUFFIX%g s%@CFG_TCL_EXPORT_FILE_SUFFIX@%$CFG_TCL_EXPORT_FILE_SUFFIX%g s%@TCL_SHARED_BUILD@%$TCL_SHARED_BUILD%g s%@LD_LIBRARY_PATH_VAR@%$LD_LIBRARY_PATH_VAR%g s%@TCL_BUILD_LIB_SPEC@%$TCL_BUILD_LIB_SPEC%g s%@TCL_NEEDS_EXP_FILE@%$TCL_NEEDS_EXP_FILE%g s%@TCL_BUILD_EXP_FILE@%$TCL_BUILD_EXP_FILE%g s%@TCL_EXP_FILE@%$TCL_EXP_FILE%g s%@TCL_LIB_VERSIONS_OK@%$TCL_LIB_VERSIONS_OK%g s%@TCL_SHARED_LIB_SUFFIX@%$TCL_SHARED_LIB_SUFFIX%g s%@TCL_UNSHARED_LIB_SUFFIX@%$TCL_UNSHARED_LIB_SUFFIX%g s%@TCL_HAS_LONGLONG@%$TCL_HAS_LONGLONG%g s%@DTRACE_SRC@%$DTRACE_SRC%g s%@DTRACE_HDR@%$DTRACE_HDR%g s%@DTRACE_OBJ@%$DTRACE_OBJ%g s%@MAKEFILE_SHELL@%$MAKEFILE_SHELL%g s%@BUILD_DLTEST@%$BUILD_DLTEST%g s%@TCL_PACKAGE_PATH@%$TCL_PACKAGE_PATH%g s%@TCL_LIBRARY@%$TCL_LIBRARY%g s%@PRIVATE_INCLUDE_DIR@%$PRIVATE_INCLUDE_DIR%g s%@HTML_DIR@%$HTML_DIR%g s%@EXTRA_CC_SWITCHES@%$EXTRA_CC_SWITCHES%g s%@EXTRA_APP_CC_SWITCHES@%$EXTRA_APP_CC_SWITCHES%g s%@EXTRA_INSTALL@%$EXTRA_INSTALL%g s%@EXTRA_INSTALL_BINARIES@%$EXTRA_INSTALL_BINARIES%g s%@EXTRA_BUILD_HTML@%$EXTRA_BUILD_HTML%g s%@EXTRA_TCLSH_LIBS@%$EXTRA_TCLSH_LIBS%g CEOF EOF cat >> $CONFIG_STATUS <<\EOF # Split the substitutions into bite-sized pieces for seds with # small command number limits, like on Digital OSF/1 and HP-UX. ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. ac_file=1 # Number of current file. ac_beg=1 # First line for current file. ac_end=$ac_max_sed_cmds # Line after last line for current file. ac_more_lines=: ac_sed_cmds="" while $ac_more_lines; do if test $ac_beg -gt 1; then sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file else sed "${ac_end}q" conftest.subs > conftest.s$ac_file fi if test ! -s conftest.s$ac_file; then ac_more_lines=false rm -f conftest.s$ac_file else if test -z "$ac_sed_cmds"; then ac_sed_cmds="sed -f conftest.s$ac_file" else ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" fi ac_file=`expr $ac_file + 1` ac_beg=$ac_end ac_end=`expr $ac_end + $ac_max_sed_cmds` fi done if test -z "$ac_sed_cmds"; then ac_sed_cmds=cat fi EOF cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". case "$ac_file" in *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; *) ac_file_in="${ac_file}.in" ;; esac # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. # Remove last slash and all that follows it. Not all systems have dirname. ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then # The file is in a subdirectory. test ! -d "$ac_dir" && mkdir "$ac_dir" ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" # A "../" for each directory in $ac_dir_suffix. ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` else ac_dir_suffix= ac_dots= fi case "$ac_given_srcdir" in .) srcdir=. if test -z "$ac_dots"; then top_srcdir=. else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; *) # Relative path. srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" top_srcdir="$ac_dots$ac_given_srcdir" ;; esac echo creating "$ac_file" rm -f "$ac_file" configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." case "$ac_file" in *Makefile*) ac_comsub="1i\\ # $configure_input" ;; *) ac_comsub= ;; esac ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` sed -e "$ac_comsub s%@configure_input@%$configure_input%g s%@srcdir@%$srcdir%g s%@top_srcdir@%$top_srcdir%g " $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file fi; done rm -f conftest.s* EOF cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF test "$FRAMEWORK_BUILD" = "1" && n=Tcl && f=$n.framework && v=Versions/$VERSION && echo "creating $f" && rm -rf $f && mkdir -p $f/$v/Resources && ln -s $v/$n $v/Resources $f && ln -s ../../../$n $f/$v && ln -s ../../../../$n-Info.plist $f/$v/Resources/Info.plist && unset n f v exit 0 EOF chmod +x $CONFIG_STATUS rm -fr confdefs* $ac_clean_files test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 tcl8.4.20/unix/tclUnixTest.c0000644003604700454610000005274611737050675014353 0ustar dgp771div/* * tclUnixTest.c -- * * Contains platform specific test commands for the Unix platform. * * Copyright (c) 1996-1997 Sun Microsystems, Inc. * Copyright (c) 1998 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" /* * The headers are needed for the testalarm command that verifies the * use of SA_RESTART in signal handlers. */ #include #include /* * The following macros convert between TclFile's and fd's. The conversion * simple involves shifting fd's up by one to ensure that no valid fd is ever * the same as NULL. Note that this code is duplicated from tclUnixPipe.c */ #define MakeFile(fd) ((TclFile)((fd)+1)) #define GetFd(file) (((int)file)-1) /* * The stuff below is used to keep track of file handlers created and * exercised by the "testfilehandler" command. */ typedef struct Pipe { TclFile readFile; /* File handle for reading from the * pipe. NULL means pipe doesn't exist yet. */ TclFile writeFile; /* File handle for writing from the * pipe. */ int readCount; /* Number of times the file handler for * this file has triggered and the file * was readable. */ int writeCount; /* Number of times the file handler for * this file has triggered and the file * was writable. */ } Pipe; #define MAX_PIPES 10 static Pipe testPipes[MAX_PIPES]; /* * The stuff below is used by the testalarm and testgotsig ommands. */ static char *gotsig = "0"; /* * Forward declarations of procedures defined later in this file: */ static void TestFileHandlerProc _ANSI_ARGS_((ClientData clientData, int mask)); static int TestfilehandlerCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int TestfilewaitCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int TestfindexecutableCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int TestgetopenfileCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int TestgetdefencdirCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int TestsetdefencdirCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); int TclplatformtestInit _ANSI_ARGS_((Tcl_Interp *interp)); static int TestalarmCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static int TestgotsigCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); static void AlarmHandler _ANSI_ARGS_(()); static int TestchmodCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST char **argv)); /* *---------------------------------------------------------------------- * * TclplatformtestInit -- * * Defines commands that test platform specific functionality for * Unix platforms. * * Results: * A standard Tcl result. * * Side effects: * Defines new commands. * *---------------------------------------------------------------------- */ int TclplatformtestInit(interp) Tcl_Interp *interp; /* Interpreter to add commands to. */ { Tcl_CreateCommand(interp, "testchmod", TestchmodCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testfilehandler", TestfilehandlerCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testfilewait", TestfilewaitCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testfindexecutable", TestfindexecutableCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testgetopenfile", TestgetopenfileCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testgetdefenc", TestgetdefencdirCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testsetdefenc", TestsetdefencdirCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testalarm", TestalarmCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testgotsig", TestgotsigCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); return TCL_OK; } /* *---------------------------------------------------------------------- * * TestfilehandlerCmd -- * * This procedure implements the "testfilehandler" command. It is * used to test Tcl_CreateFileHandler, Tcl_DeleteFileHandler, and * TclWaitForFile. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TestfilehandlerCmd(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { Pipe *pipePtr; int i, mask, timeout; static int initialized = 0; char buffer[4000]; TclFile file; /* * NOTE: When we make this code work on Windows also, the following * variable needs to be made Unix-only. */ if (!initialized) { for (i = 0; i < MAX_PIPES; i++) { testPipes[i].readFile = NULL; } initialized = 1; } if (argc < 2) { Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0], " option ... \"", (char *) NULL); return TCL_ERROR; } pipePtr = NULL; if (argc >= 3) { if (Tcl_GetInt(interp, argv[2], &i) != TCL_OK) { return TCL_ERROR; } if (i >= MAX_PIPES) { Tcl_AppendResult(interp, "bad index ", argv[2], (char *) NULL); return TCL_ERROR; } pipePtr = &testPipes[i]; } if (strcmp(argv[1], "close") == 0) { for (i = 0; i < MAX_PIPES; i++) { if (testPipes[i].readFile != NULL) { TclpCloseFile(testPipes[i].readFile); testPipes[i].readFile = NULL; TclpCloseFile(testPipes[i].writeFile); testPipes[i].writeFile = NULL; } } } else if (strcmp(argv[1], "clear") == 0) { if (argc != 3) { Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0], " clear index\"", (char *) NULL); return TCL_ERROR; } pipePtr->readCount = pipePtr->writeCount = 0; } else if (strcmp(argv[1], "counts") == 0) { char buf[TCL_INTEGER_SPACE * 2]; if (argc != 3) { Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0], " counts index\"", (char *) NULL); return TCL_ERROR; } sprintf(buf, "%d %d", pipePtr->readCount, pipePtr->writeCount); Tcl_SetResult(interp, buf, TCL_VOLATILE); } else if (strcmp(argv[1], "create") == 0) { if (argc != 5) { Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0], " create index readMode writeMode\"", (char *) NULL); return TCL_ERROR; } if (pipePtr->readFile == NULL) { if (!TclpCreatePipe(&pipePtr->readFile, &pipePtr->writeFile)) { Tcl_AppendResult(interp, "couldn't open pipe: ", Tcl_PosixError(interp), (char *) NULL); return TCL_ERROR; } #ifdef O_NONBLOCK fcntl(GetFd(pipePtr->readFile), F_SETFL, O_NONBLOCK); fcntl(GetFd(pipePtr->writeFile), F_SETFL, O_NONBLOCK); #else Tcl_SetResult(interp, "can't make pipes non-blocking", TCL_STATIC); return TCL_ERROR; #endif } pipePtr->readCount = 0; pipePtr->writeCount = 0; if (strcmp(argv[3], "readable") == 0) { Tcl_CreateFileHandler(GetFd(pipePtr->readFile), TCL_READABLE, TestFileHandlerProc, (ClientData) pipePtr); } else if (strcmp(argv[3], "off") == 0) { Tcl_DeleteFileHandler(GetFd(pipePtr->readFile)); } else if (strcmp(argv[3], "disabled") == 0) { Tcl_CreateFileHandler(GetFd(pipePtr->readFile), 0, TestFileHandlerProc, (ClientData) pipePtr); } else { Tcl_AppendResult(interp, "bad read mode \"", argv[3], "\"", (char *) NULL); return TCL_ERROR; } if (strcmp(argv[4], "writable") == 0) { Tcl_CreateFileHandler(GetFd(pipePtr->writeFile), TCL_WRITABLE, TestFileHandlerProc, (ClientData) pipePtr); } else if (strcmp(argv[4], "off") == 0) { Tcl_DeleteFileHandler(GetFd(pipePtr->writeFile)); } else if (strcmp(argv[4], "disabled") == 0) { Tcl_CreateFileHandler(GetFd(pipePtr->writeFile), 0, TestFileHandlerProc, (ClientData) pipePtr); } else { Tcl_AppendResult(interp, "bad read mode \"", argv[4], "\"", (char *) NULL); return TCL_ERROR; } } else if (strcmp(argv[1], "empty") == 0) { if (argc != 3) { Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0], " empty index\"", (char *) NULL); return TCL_ERROR; } while (read(GetFd(pipePtr->readFile), buffer, 4000) > 0) { /* Empty loop body. */ } } else if (strcmp(argv[1], "fill") == 0) { if (argc != 3) { Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0], " fill index\"", (char *) NULL); return TCL_ERROR; } memset((VOID *) buffer, 'a', 4000); while (write(GetFd(pipePtr->writeFile), buffer, 4000) > 0) { /* Empty loop body. */ } } else if (strcmp(argv[1], "fillpartial") == 0) { char buf[TCL_INTEGER_SPACE]; if (argc != 3) { Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0], " fillpartial index\"", (char *) NULL); return TCL_ERROR; } memset((VOID *) buffer, 'b', 10); TclFormatInt(buf, write(GetFd(pipePtr->writeFile), buffer, 10)); Tcl_SetResult(interp, buf, TCL_VOLATILE); } else if (strcmp(argv[1], "oneevent") == 0) { Tcl_DoOneEvent(TCL_FILE_EVENTS|TCL_DONT_WAIT); } else if (strcmp(argv[1], "wait") == 0) { if (argc != 5) { Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0], " wait index readable|writable timeout\"", (char *) NULL); return TCL_ERROR; } if (pipePtr->readFile == NULL) { Tcl_AppendResult(interp, "pipe ", argv[2], " doesn't exist", (char *) NULL); return TCL_ERROR; } if (strcmp(argv[3], "readable") == 0) { mask = TCL_READABLE; file = pipePtr->readFile; } else { mask = TCL_WRITABLE; file = pipePtr->writeFile; } if (Tcl_GetInt(interp, argv[4], &timeout) != TCL_OK) { return TCL_ERROR; } i = TclUnixWaitForFile(GetFd(file), mask, timeout); if (i & TCL_READABLE) { Tcl_AppendElement(interp, "readable"); } if (i & TCL_WRITABLE) { Tcl_AppendElement(interp, "writable"); } } else if (strcmp(argv[1], "windowevent") == 0) { Tcl_DoOneEvent(TCL_WINDOW_EVENTS|TCL_DONT_WAIT); } else { Tcl_AppendResult(interp, "bad option \"", argv[1], "\": must be close, clear, counts, create, empty, fill, ", "fillpartial, oneevent, wait, or windowevent", (char *) NULL); return TCL_ERROR; } return TCL_OK; } static void TestFileHandlerProc(clientData, mask) ClientData clientData; /* Points to a Pipe structure. */ int mask; /* Indicates which events happened: * TCL_READABLE or TCL_WRITABLE. */ { Pipe *pipePtr = (Pipe *) clientData; if (mask & TCL_READABLE) { pipePtr->readCount++; } if (mask & TCL_WRITABLE) { pipePtr->writeCount++; } } /* *---------------------------------------------------------------------- * * TestfilewaitCmd -- * * This procedure implements the "testfilewait" command. It is * used to test TclUnixWaitForFile. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TestfilewaitCmd(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { int mask, result, timeout; Tcl_Channel channel; int fd; ClientData data; if (argc != 4) { Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0], " file readable|writable|both timeout\"", (char *) NULL); return TCL_ERROR; } channel = Tcl_GetChannel(interp, argv[1], NULL); if (channel == NULL) { return TCL_ERROR; } if (strcmp(argv[2], "readable") == 0) { mask = TCL_READABLE; } else if (strcmp(argv[2], "writable") == 0){ mask = TCL_WRITABLE; } else if (strcmp(argv[2], "both") == 0){ mask = TCL_WRITABLE|TCL_READABLE; } else { Tcl_AppendResult(interp, "bad argument \"", argv[2], "\": must be readable, writable, or both", (char *) NULL); return TCL_ERROR; } if (Tcl_GetChannelHandle(channel, (mask & TCL_READABLE) ? TCL_READABLE : TCL_WRITABLE, (ClientData*) &data) != TCL_OK) { Tcl_SetResult(interp, "couldn't get channel file", TCL_STATIC); return TCL_ERROR; } fd = (int) data; if (Tcl_GetInt(interp, argv[3], &timeout) != TCL_OK) { return TCL_ERROR; } result = TclUnixWaitForFile(fd, mask, timeout); if (result & TCL_READABLE) { Tcl_AppendElement(interp, "readable"); } if (result & TCL_WRITABLE) { Tcl_AppendElement(interp, "writable"); } return TCL_OK; } /* *---------------------------------------------------------------------- * * TestfindexecutableCmd -- * * This procedure implements the "testfindexecutable" command. It is * used to test Tcl_FindExecutable. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TestfindexecutableCmd(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { char *oldName; char *oldNativeName; if (argc != 2) { Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0], " argv0\"", (char *) NULL); return TCL_ERROR; } oldName = tclExecutableName; oldNativeName = tclNativeExecutableName; tclExecutableName = NULL; tclNativeExecutableName = NULL; Tcl_FindExecutable(argv[1]); if (tclExecutableName != NULL) { Tcl_SetResult(interp, tclExecutableName, TCL_VOLATILE); ckfree(tclExecutableName); } if (tclNativeExecutableName != NULL) { ckfree(tclNativeExecutableName); } tclExecutableName = oldName; tclNativeExecutableName = oldNativeName; return TCL_OK; } /* *---------------------------------------------------------------------- * * TestgetopenfileCmd -- * * This procedure implements the "testgetopenfile" command. It is * used to get a FILE * value from a registered channel. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TestgetopenfileCmd(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { ClientData filePtr; if (argc != 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " channelName forWriting\"", (char *) NULL); return TCL_ERROR; } if (Tcl_GetOpenFile(interp, argv[1], atoi(argv[2]), 1, &filePtr) == TCL_ERROR) { return TCL_ERROR; } if (filePtr == (ClientData) NULL) { Tcl_AppendResult(interp, "Tcl_GetOpenFile succeeded but FILE * NULL!", (char *) NULL); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * TestsetdefencdirCmd -- * * This procedure implements the "testsetdefenc" command. It is * used to set the value of tclDefaultEncodingDir. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TestsetdefencdirCmd(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { if (argc != 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " defaultDir\"", (char *) NULL); return TCL_ERROR; } if (tclDefaultEncodingDir != NULL) { ckfree(tclDefaultEncodingDir); tclDefaultEncodingDir = NULL; } if (*argv[1] != '\0') { tclDefaultEncodingDir = (char *) ckalloc((unsigned) strlen(argv[1]) + 1); strcpy(tclDefaultEncodingDir, argv[1]); } return TCL_OK; } /* *---------------------------------------------------------------------- * * TestgetdefencdirCmd -- * * This procedure implements the "testgetdefenc" command. It is * used to get the value of tclDefaultEncodingDir. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TestgetdefencdirCmd(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { if (argc != 1) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], (char *) NULL); return TCL_ERROR; } if (tclDefaultEncodingDir != NULL) { Tcl_AppendResult(interp, tclDefaultEncodingDir, (char *) NULL); } return TCL_OK; } /* *---------------------------------------------------------------------- * TestalarmCmd -- * * Test that EINTR is handled correctly by generating and * handling a signal. This requires using the SA_RESTART * flag when registering the signal handler. * * Results: * None. * * Side Effects: * Sets up an signal and async handlers. * *---------------------------------------------------------------------- */ static int TestalarmCmd(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { #ifdef SA_RESTART unsigned int sec; struct sigaction action; if (argc > 1) { Tcl_GetInt(interp, argv[1], (int *)&sec); } else { sec = 1; } /* * Setup the signal handling that automatically retries * any interupted I/O system calls. */ action.sa_handler = AlarmHandler; memset((void *)&action.sa_mask, 0, sizeof(sigset_t)); action.sa_flags = SA_RESTART; if (sigaction(SIGALRM, &action, NULL) < 0) { Tcl_AppendResult(interp, "sigaction: ", Tcl_PosixError(interp), NULL); return TCL_ERROR; } (void)alarm(sec); return TCL_OK; #else Tcl_AppendResult(interp, "warning: sigaction SA_RESTART not support on this platform", NULL); return TCL_ERROR; #endif } /* *---------------------------------------------------------------------- * * AlarmHandler -- * * Signal handler for the alarm command. * * Results: * None. * * Side effects: * Calls the Tcl Async handler. * *---------------------------------------------------------------------- */ static void AlarmHandler() { gotsig = "1"; } /* *---------------------------------------------------------------------- * TestgotsigCmd -- * * Verify the signal was handled after the testalarm command. * * Results: * None. * * Side Effects: * Resets the value of gotsig back to '0'. * *---------------------------------------------------------------------- */ static int TestgotsigCmd(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { Tcl_AppendResult(interp, gotsig, (char *) NULL); gotsig = "0"; return TCL_OK; } /* *--------------------------------------------------------------------------- * * TestchmodCmd -- * * Implements the "testchmod" cmd. Used when testing "file" command. * The only attribute used by the Windows platform is the user write * flag; if this is not set, the file is made read-only. Otehrwise, the * file is made read-write. * * Results: * A standard Tcl result. * * Side effects: * Changes permissions of specified files. * *--------------------------------------------------------------------------- */ static int TestchmodCmd(dummy, interp, argc, argv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { int i, mode; char *rest; if (argc < 2) { usage: Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " mode file ?file ...?", NULL); return TCL_ERROR; } mode = (int) strtol(argv[1], &rest, 8); if ((rest == argv[1]) || (*rest != '\0')) { goto usage; } for (i = 2; i < argc; i++) { Tcl_DString buffer; CONST char *translated; translated = Tcl_TranslateFileName(interp, argv[i], &buffer); if (translated == NULL) { return TCL_ERROR; } if (chmod(translated, (unsigned) mode) != 0) { Tcl_AppendResult(interp, translated, ": ", Tcl_PosixError(interp), NULL); return TCL_ERROR; } Tcl_DStringFree(&buffer); } return TCL_OK; } tcl8.4.20/unix/dltest/0000755003604700454610000000000012153151143013163 5ustar dgp771divtcl8.4.20/unix/dltest/Makefile.in0000644003604700454610000000355411737050675015256 0ustar dgp771div# This Makefile is used to create several test cases for Tcl's load # command. It also illustrates how to take advantage of configuration # exported by Tcl to set up Makefiles for shared libraries. TCL_DBGX = @TCL_DBGX@ CC = @CC@ LIBS = @TCL_BUILD_STUB_LIB_SPEC@ @DL_LIBS@ @LIBS@ @MATH_LIBS@ AC_FLAGS = @DEFS@ SHLIB_CFLAGS = @SHLIB_CFLAGS@ SHLIB_LD = @SHLIB_LD@ SHLIB_LD_LIBS = @SHLIB_LD_LIBS@ SHLIB_SUFFIX = @SHLIB_SUFFIX@ SRC_DIR = @srcdir@ TCL_VERSION= @TCL_VERSION@ CFLAGS_DEBUG = @CFLAGS_DEBUG@ CFLAGS_OPTIMIZE = @CFLAGS_OPTIMIZE@ CFLAGS = @CFLAGS_DEFAULT@ @CFLAGS@ LDFLAGS_DEBUG = @LDFLAGS_DEBUG@ LDFLAGS_OPTIMIZE = @LDFLAGS_OPTIMIZE@ LDFLAGS = @LDFLAGS_DEFAULT@ @LDFLAGS@ CC_SWITCHES = $(CFLAGS) -I${SRC_DIR}/../../generic -DTCL_MEM_DEBUG \ ${SHLIB_CFLAGS} -DUSE_TCL_STUBS ${AC_FLAGS} all: pkga${SHLIB_SUFFIX} pkgb${SHLIB_SUFFIX} pkgc${SHLIB_SUFFIX} pkgd${SHLIB_SUFFIX} pkge${SHLIB_SUFFIX} @touch ../dltest.marker pkga${SHLIB_SUFFIX}: $(SRC_DIR)/pkga.c $(CC) -c $(CC_SWITCHES) $(SRC_DIR)/pkga.c ${SHLIB_LD} -o pkga${SHLIB_SUFFIX} pkga.o ${SHLIB_LD_LIBS} pkgb${SHLIB_SUFFIX}: $(SRC_DIR)/pkgb.c $(CC) -c $(CC_SWITCHES) $(SRC_DIR)/pkgb.c ${SHLIB_LD} -o pkgb${SHLIB_SUFFIX} pkgb.o ${SHLIB_LD_LIBS} pkgc${SHLIB_SUFFIX}: $(SRC_DIR)/pkgc.c $(CC) -c $(CC_SWITCHES) $(SRC_DIR)/pkgc.c ${SHLIB_LD} -o pkgc${SHLIB_SUFFIX} pkgc.o ${SHLIB_LD_LIBS} pkgd${SHLIB_SUFFIX}: $(SRC_DIR)/pkgd.c $(CC) -c $(CC_SWITCHES) $(SRC_DIR)/pkgd.c ${SHLIB_LD} -o pkgd${SHLIB_SUFFIX} pkgd.o ${SHLIB_LD_LIBS} pkge${SHLIB_SUFFIX}: $(SRC_DIR)/pkge.c $(CC) -c $(CC_SWITCHES) $(SRC_DIR)/pkge.c ${SHLIB_LD} -o pkge${SHLIB_SUFFIX} pkge.o ${SHLIB_LD_LIBS} clean: rm -f *.o config.cache config.log config.status rm -f lib.exp ../dltest.marker @if test "$(SHLIB_SUFFIX)" != ""; then \ echo "rm -f *${SHLIB_SUFFIX}" ; \ rm -f *${SHLIB_SUFFIX} ; \ fi distclean: clean rm -f Makefile tcl8.4.20/unix/dltest/pkgb.c0000644003604700454610000001071512133546540014265 0ustar dgp771div/* * pkgb.c -- * * This file contains a simple Tcl package "pkgb" that is intended for * testing the Tcl dynamic loading facilities. It can be used in both * safe and unsafe interpreters. * * Copyright (c) 1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tcl.h" /* * Prototypes for procedures defined later in this file: */ static int Pkgb_SubObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int Pkgb_UnsafeObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); /* *---------------------------------------------------------------------- * * Pkgb_SubObjCmd -- * * This procedure is invoked to process the "pkgb_sub" Tcl command. It * expects two arguments and returns their difference. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ #ifndef Tcl_GetErrorLine # define Tcl_GetErrorLine(interp) ((interp)->errorLine) #endif static int Pkgb_SubObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { int first, second; if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "num num"); return TCL_ERROR; } if ((Tcl_GetIntFromObj(interp, objv[1], &first) != TCL_OK) || (Tcl_GetIntFromObj(interp, objv[2], &second) != TCL_OK)) { char buf[TCL_INTEGER_SPACE]; sprintf(buf, "%d", Tcl_GetErrorLine(interp)); Tcl_AppendResult(interp, " in line: ", buf, NULL); return TCL_ERROR; } Tcl_SetObjResult(interp, Tcl_NewIntObj(first - second)); return TCL_OK; } /* *---------------------------------------------------------------------- * * Pkgb_UnsafeObjCmd -- * * This procedure is invoked to process the "pkgb_unsafe" Tcl command. It * just returns a constant string. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ static int Pkgb_UnsafeObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { return Tcl_EvalEx(interp, "list unsafe command invoked", -1, TCL_EVAL_GLOBAL); } /* *---------------------------------------------------------------------- * * Pkgb_Init -- * * This is a package initialization procedure, which is called by Tcl * when this package is to be added to an interpreter. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ DLLEXPORT int Pkgb_Init(interp) Tcl_Interp *interp; /* Interpreter in which the package is to be * made available. */ { int code; if (Tcl_InitStubs(interp, "8.4", 0) == NULL) { if (Tcl_InitStubs(interp, "8.4-", 0) == NULL) { return TCL_ERROR; } Tcl_ResetResult(interp); } code = Tcl_PkgProvide(interp, "Pkgb", "2.3"); if (code != TCL_OK) { return code; } Tcl_CreateObjCommand(interp, "pkgb_sub", Pkgb_SubObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "pkgb_unsafe", Pkgb_UnsafeObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); return TCL_OK; } /* *---------------------------------------------------------------------- * * Pkgb_SafeInit -- * * This is a package initialization procedure, which is called by Tcl * when this package is to be added to a safe interpreter. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ DLLEXPORT int Pkgb_SafeInit(interp) Tcl_Interp *interp; /* Interpreter in which the package is to be * made available. */ { int code; if (Tcl_InitStubs(interp, "8.4", 0) == NULL) { if (Tcl_InitStubs(interp, "8.4-", 0) == NULL) { return TCL_ERROR; } Tcl_ResetResult(interp); } code = Tcl_PkgProvide(interp, "Pkgb", "2.3"); if (code != TCL_OK) { return code; } Tcl_CreateObjCommand(interp, "pkgb_sub", Pkgb_SubObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); return TCL_OK; } tcl8.4.20/unix/dltest/pkgf.c0000644003604700454610000000262111737050675014276 0ustar dgp771div/* * pkgf.c -- * * This file contains a simple Tcl package "pkgf" that is intended * for testing the Tcl dynamic loading facilities. Its Init * procedure returns an error in order to test how this is handled. * * Copyright (c) 1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tcl.h" /* * Prototypes for procedures defined later in this file: */ static int Pkgd_SubCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int argc, char **argv)); static int Pkgd_UnsafeCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int argc, char **argv)); /* *---------------------------------------------------------------------- * * Pkgf_Init -- * * This is a package initialization procedure, which is called * by Tcl when this package is to be added to an interpreter. * * Results: * Returns TCL_ERROR and leaves an error message in interp->result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Pkgf_Init(interp) Tcl_Interp *interp; /* Interpreter in which the package is * to be made available. */ { static char script[] = "if 44 {open non_existent}"; if (Tcl_InitStubs(interp, TCL_VERSION, 1) == NULL) { return TCL_ERROR; } return Tcl_Eval(interp, script); } tcl8.4.20/unix/dltest/pkgd.c0000644003604700454610000001013111737050675014267 0ustar dgp771div/* * pkgd.c -- * * This file contains a simple Tcl package "pkgd" that is intended * for testing the Tcl dynamic loading facilities. It can be used * in both safe and unsafe interpreters. * * Copyright (c) 1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tcl.h" /* * Prototypes for procedures defined later in this file: */ static int Pkgd_SubObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj * CONST objv[])); static int Pkgd_UnsafeObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj * CONST objv[])); /* *---------------------------------------------------------------------- * * Pkgd_SubObjCmd -- * * This procedure is invoked to process the "pkgd_sub" Tcl command. * It expects two arguments and returns their difference. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ static int Pkgd_SubObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj * CONST objv[]; /* Argument objects. */ { int first, second; if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "num num"); return TCL_ERROR; } if ((Tcl_GetIntFromObj(interp, objv[1], &first) != TCL_OK) || (Tcl_GetIntFromObj(interp, objv[2], &second) != TCL_OK)) { return TCL_ERROR; } Tcl_SetObjResult(interp, Tcl_NewIntObj(first - second)); return TCL_OK; } /* *---------------------------------------------------------------------- * * Pkgd_UnsafeCmd -- * * This procedure is invoked to process the "pkgd_unsafe" Tcl command. * It just returns a constant string. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ static int Pkgd_UnsafeObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj * CONST objv[]; /* Argument objects. */ { Tcl_SetObjResult(interp, Tcl_NewStringObj("unsafe command invoked", -1)); return TCL_OK; } /* *---------------------------------------------------------------------- * * Pkgd_Init -- * * This is a package initialization procedure, which is called * by Tcl when this package is to be added to an interpreter. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Pkgd_Init(interp) Tcl_Interp *interp; /* Interpreter in which the package is * to be made available. */ { int code; if (Tcl_InitStubs(interp, TCL_VERSION, 1) == NULL) { return TCL_ERROR; } code = Tcl_PkgProvide(interp, "Pkgd", "7.3"); if (code != TCL_OK) { return code; } Tcl_CreateObjCommand(interp, "pkgd_sub", Pkgd_SubObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "pkgd_unsafe", Pkgd_UnsafeObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); return TCL_OK; } /* *---------------------------------------------------------------------- * * Pkgd_SafeInit -- * * This is a package initialization procedure, which is called * by Tcl when this package is to be added to an unsafe interpreter. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Pkgd_SafeInit(interp) Tcl_Interp *interp; /* Interpreter in which the package is * to be made available. */ { int code; if (Tcl_InitStubs(interp, TCL_VERSION, 1) == NULL) { return TCL_ERROR; } code = Tcl_PkgProvide(interp, "Pkgd", "7.3"); if (code != TCL_OK) { return code; } Tcl_CreateObjCommand(interp, "pkgd_sub", Pkgd_SubObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); return TCL_OK; } tcl8.4.20/unix/dltest/pkgc.c0000644003604700454610000001014111737050675014267 0ustar dgp771div/* * pkgc.c -- * * This file contains a simple Tcl package "pkgc" that is intended * for testing the Tcl dynamic loading facilities. It can be used * in both safe and unsafe interpreters. * * Copyright (c) 1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tcl.h" /* * Prototypes for procedures defined later in this file: */ static int Pkgc_SubObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj * CONST objv[])); static int Pkgc_UnsafeObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj * CONST objv[])); /* *---------------------------------------------------------------------- * * Pkgc_SubObjCmd -- * * This procedure is invoked to process the "pkgc_sub" Tcl command. * It expects two arguments and returns their difference. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ static int Pkgc_SubObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj * CONST objv[]; /* Argument objects. */ { int first, second; if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "num num"); return TCL_ERROR; } if ((Tcl_GetIntFromObj(interp, objv[1], &first) != TCL_OK) || (Tcl_GetIntFromObj(interp, objv[2], &second) != TCL_OK)) { return TCL_ERROR; } Tcl_SetObjResult(interp, Tcl_NewIntObj(first - second)); return TCL_OK; } /* *---------------------------------------------------------------------- * * Pkgc_UnsafeCmd -- * * This procedure is invoked to process the "pkgc_unsafe" Tcl command. * It just returns a constant string. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ static int Pkgc_UnsafeObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj * CONST objv[]; /* Argument objects. */ { Tcl_SetObjResult(interp, Tcl_NewStringObj("unsafe command invoked", -1)); return TCL_OK; } /* *---------------------------------------------------------------------- * * Pkgc_Init -- * * This is a package initialization procedure, which is called * by Tcl when this package is to be added to an interpreter. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Pkgc_Init(interp) Tcl_Interp *interp; /* Interpreter in which the package is * to be made available. */ { int code; if (Tcl_InitStubs(interp, TCL_VERSION, 1) == NULL) { return TCL_ERROR; } code = Tcl_PkgProvide(interp, "Pkgc", "1.7.2"); if (code != TCL_OK) { return code; } Tcl_CreateObjCommand(interp, "pkgc_sub", Pkgc_SubObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "pkgc_unsafe", Pkgc_UnsafeObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); return TCL_OK; } /* *---------------------------------------------------------------------- * * Pkgc_SafeInit -- * * This is a package initialization procedure, which is called * by Tcl when this package is to be added to an unsafe interpreter. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Pkgc_SafeInit(interp) Tcl_Interp *interp; /* Interpreter in which the package is * to be made available. */ { int code; if (Tcl_InitStubs(interp, TCL_VERSION, 1) == NULL) { return TCL_ERROR; } code = Tcl_PkgProvide(interp, "Pkgc", "1.7.2"); if (code != TCL_OK) { return code; } Tcl_CreateObjCommand(interp, "pkgc_sub", Pkgc_SubObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); return TCL_OK; } tcl8.4.20/unix/dltest/README0000644003604700454610000000035611737050675014066 0ustar dgp771divThis directory contains several files for testing Tcl's dynamic loading capabilities. If shared libraries are supported then the build system in the parent directory will create the shared libs and load them into the tcltest executable. tcl8.4.20/unix/dltest/pkge.c0000644003604700454610000000216211737050675014275 0ustar dgp771div/* * pkge.c -- * * This file contains a simple Tcl package "pkge" that is intended * for testing the Tcl dynamic loading facilities. Its Init * procedure returns an error in order to test how this is handled. * * Copyright (c) 1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tcl.h" /* *---------------------------------------------------------------------- * * Pkge_Init -- * * This is a package initialization procedure, which is called * by Tcl when this package is to be added to an interpreter. * * Results: * Returns TCL_ERROR and leaves an error message in interp->result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Pkge_Init(interp) Tcl_Interp *interp; /* Interpreter in which the package is * to be made available. */ { static char script[] = "if 44 {open non_existent}"; if (Tcl_InitStubs(interp, TCL_VERSION, 1) == NULL) { return TCL_ERROR; } return Tcl_Eval(interp, script); } tcl8.4.20/unix/dltest/pkga.c0000644003604700454610000000671011737050675014274 0ustar dgp771div/* * pkga.c -- * * This file contains a simple Tcl package "pkga" that is intended * for testing the Tcl dynamic loading facilities. * * Copyright (c) 1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tcl.h" /* * Prototypes for procedures defined later in this file: */ static int Pkga_EqObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj * CONST objv[])); static int Pkga_QuoteObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj * CONST objv[])); /* *---------------------------------------------------------------------- * * Pkga_EqObjCmd -- * * This procedure is invoked to process the "pkga_eq" Tcl command. * It expects two arguments and returns 1 if they are the same, * 0 if they are different. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ static int Pkga_EqObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj * CONST objv[]; /* Argument objects. */ { int result; CONST char *str1, *str2; int len1, len2; if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "string1 string2"); return TCL_ERROR; } str1 = Tcl_GetStringFromObj(objv[1], &len1); str2 = Tcl_GetStringFromObj(objv[2], &len2); if (len1 == len2) { result = (Tcl_UtfNcmp(str1, str2, len1) == 0); } else { result = 0; } Tcl_SetObjResult(interp, Tcl_NewIntObj(result)); return TCL_OK; } /* *---------------------------------------------------------------------- * * Pkga_QuoteObjCmd -- * * This procedure is invoked to process the "pkga_quote" Tcl command. * It expects one argument, which it returns as result. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ static int Pkga_QuoteObjCmd(dummy, interp, objc, objv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj * CONST objv[]; /* Argument strings. */ { if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "value"); return TCL_ERROR; } Tcl_SetObjResult(interp, objv[1]); return TCL_OK; } /* *---------------------------------------------------------------------- * * Pkga_Init -- * * This is a package initialization procedure, which is called * by Tcl when this package is to be added to an interpreter. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Pkga_Init(interp) Tcl_Interp *interp; /* Interpreter in which the package is * to be made available. */ { int code; if (Tcl_InitStubs(interp, TCL_VERSION, 1) == NULL) { return TCL_ERROR; } code = Tcl_PkgProvide(interp, "Pkga", "1.0"); if (code != TCL_OK) { return code; } Tcl_CreateObjCommand(interp, "pkga_eq", Pkga_EqObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "pkga_quote", Pkga_QuoteObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); return TCL_OK; } tcl8.4.20/unix/tclUnixInit.c0000644003604700454610000010575212052456744014331 0ustar dgp771div/* * tclUnixInit.c -- * * Contains the Unix-specific interpreter initialization functions. * * Copyright (c) 1995-1997 Sun Microsystems, Inc. * Copyright (c) 1999 by Scriptics Corporation. * All rights reserved. */ #if defined(HAVE_COREFOUNDATION) #include #endif #include "tclInt.h" #include "tclPort.h" #include #ifdef HAVE_LANGINFO # include # ifdef __APPLE__ # if defined(HAVE_WEAK_IMPORT) && MAC_OS_X_VERSION_MIN_REQUIRED < 1030 /* Support for weakly importing nl_langinfo on Darwin. */ # define WEAK_IMPORT_NL_LANGINFO extern char *nl_langinfo(nl_item) WEAK_IMPORT_ATTRIBUTE; # endif # endif #endif #if defined(__FreeBSD__) && defined(__GNUC__) # include #endif #if defined(__bsdi__) # include # if _BSDI_VERSION > 199501 # include # endif #endif #ifdef __CYGWIN__ DLLIMPORT extern __stdcall unsigned char GetVersionExA(void *); DLLIMPORT extern __stdcall void GetSystemInfo(void *); #define NUMPLATFORMS 4 static const char *const platforms[NUMPLATFORMS] = { "Win32s", "Windows 95", "Windows NT", "Windows CE" }; #define NUMPROCESSORS 11 static const char *const processors[NUMPROCESSORS] = { "intel", "mips", "alpha", "ppc", "shx", "arm", "ia64", "alpha64", "msil", "amd64", "ia32_on_win64" }; typedef struct _SYSTEM_INFO { union { DWORD dwOemId; struct { int wProcessorArchitecture; int wReserved; }; }; DWORD dwPageSize; void *lpMinimumApplicationAddress; void *lpMaximumApplicationAddress; void *dwActiveProcessorMask; DWORD dwNumberOfProcessors; DWORD dwProcessorType; DWORD dwAllocationGranularity; int wProcessorLevel; int wProcessorRevision; } SYSTEM_INFO; typedef struct _OSVERSIONINFOA { DWORD dwOSVersionInfoSize; DWORD dwMajorVersion; DWORD dwMinorVersion; DWORD dwBuildNumber; DWORD dwPlatformId; char szCSDVersion[128]; } OSVERSIONINFOA; #endif /* * The Init script (common to Windows and Unix platforms) is * defined in tkInitScript.h */ #include "tclInitScript.h" /* Used to store the encoding used for binary files */ static Tcl_Encoding binaryEncoding = NULL; /* Has the basic library path encoding issue been fixed */ static int libraryPathEncodingFixed = 0; /* * Tcl tries to use standard and homebrew methods to guess the right * encoding on the platform. However, there is always a final fallback, * and this value is it. Make sure it is a real Tcl encoding. */ #ifndef TCL_DEFAULT_ENCODING #define TCL_DEFAULT_ENCODING "iso8859-1" #endif /* * Default directory in which to look for Tcl library scripts. The * symbol is defined by Makefile. */ static char defaultLibraryDir[sizeof(TCL_LIBRARY)+200] = TCL_LIBRARY; /* * Directory in which to look for packages (each package is typically * installed as a subdirectory of this directory). The symbol is * defined by Makefile. */ static char pkgPath[sizeof(TCL_PACKAGE_PATH)+200] = TCL_PACKAGE_PATH; /* * The following table is used to map from Unix locale strings to * encoding files. If HAVE_LANGINFO is defined, then this is a fallback * table when the result from nl_langinfo isn't a recognized encoding. * Otherwise this is the first list checked for a mapping from env * encoding to Tcl encoding name. */ typedef struct LocaleTable { CONST char *lang; CONST char *encoding; } LocaleTable; static CONST LocaleTable localeTable[] = { #ifdef HAVE_LANGINFO {"gb2312-1980", "gb2312"}, {"ansi-1251", "cp1251"}, /* Solaris gets this wrong. */ #ifdef __hpux {"SJIS", "shiftjis"}, {"eucjp", "euc-jp"}, {"euckr", "euc-kr"}, {"euctw", "euc-cn"}, {"greek8", "cp869"}, {"iso88591", "iso8859-1"}, {"iso88592", "iso8859-2"}, {"iso88595", "iso8859-5"}, {"iso88596", "iso8859-6"}, {"iso88597", "iso8859-7"}, {"iso88598", "iso8859-8"}, {"iso88599", "iso8859-9"}, {"iso885915", "iso8859-15"}, {"roman8", "iso8859-1"}, {"tis620", "tis-620"}, {"turkish8", "cp857"}, {"utf8", "utf-8"}, #endif /* __hpux */ #endif /* HAVE_LANGINFO */ {"ja_JP.SJIS", "shiftjis"}, {"ja_JP.EUC", "euc-jp"}, {"ja_JP.eucJP", "euc-jp"}, {"ja_JP.JIS", "iso2022-jp"}, {"ja_JP.mscode", "shiftjis"}, {"ja_JP.ujis", "euc-jp"}, {"ja_JP", "euc-jp"}, {"Ja_JP", "shiftjis"}, {"Jp_JP", "shiftjis"}, {"japan", "euc-jp"}, #ifdef hpux {"japanese", "shiftjis"}, {"ja", "shiftjis"}, #else {"japanese", "euc-jp"}, {"ja", "euc-jp"}, #endif {"japanese.sjis", "shiftjis"}, {"japanese.euc", "euc-jp"}, {"japanese-sjis", "shiftjis"}, {"japanese-ujis", "euc-jp"}, {"ko", "euc-kr"}, {"ko_KR", "euc-kr"}, {"ko_KR.EUC", "euc-kr"}, {"ko_KR.euc", "euc-kr"}, {"ko_KR.eucKR", "euc-kr"}, {"korean", "euc-kr"}, {"ru", "iso8859-5"}, {"ru_RU", "iso8859-5"}, {"ru_SU", "iso8859-5"}, {"zh", "cp936"}, {"zh_CN.gb2312", "euc-cn"}, {"zh_CN.GB2312", "euc-cn"}, {"zh_CN.GBK", "euc-cn"}, {"zh_TW.Big5", "big5"}, {"zh_TW", "euc-tw"}, {NULL, NULL} }; #ifdef HAVE_COREFOUNDATION static int MacOSXGetLibraryPath _ANSI_ARGS_(( Tcl_Interp *interp, int maxPathLen, char *tclLibPath)); #endif /* HAVE_COREFOUNDATION */ #if defined(__APPLE__) && (defined(TCL_LOAD_FROM_MEMORY) || ( \ defined(MAC_OS_X_VERSION_MIN_REQUIRED) && ( \ (defined(TCL_THREADS) && MAC_OS_X_VERSION_MIN_REQUIRED < 1030) || \ (defined(__LP64__) && MAC_OS_X_VERSION_MIN_REQUIRED < 1050) || \ (defined(HAVE_COREFOUNDATION) && MAC_OS_X_VERSION_MIN_REQUIRED < 1050)\ ))) /* * Need to check Darwin release at runtime in tclUnixFCmd.c and tclLoadDyld.c: * initialize release global at startup from uname(). */ #define GET_DARWIN_RELEASE 1 long tclMacOSXDarwinRelease = 0; #endif /* *--------------------------------------------------------------------------- * * TclpInitPlatform -- * * Initialize all the platform-dependant things like signals and * floating-point error handling. * * Called at process initialization time. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ void TclpInitPlatform() { tclPlatform = TCL_PLATFORM_UNIX; /* * Make sure, that the standard FDs exist. [Bug 772288] */ if (TclOSseek(0, (Tcl_SeekOffset) 0, SEEK_CUR) == -1 && errno == EBADF) { open("/dev/null", O_RDONLY); } if (TclOSseek(1, (Tcl_SeekOffset) 0, SEEK_CUR) == -1 && errno == EBADF) { open("/dev/null", O_WRONLY); } if (TclOSseek(2, (Tcl_SeekOffset) 0, SEEK_CUR) == -1 && errno == EBADF) { open("/dev/null", O_WRONLY); } /* * The code below causes SIGPIPE (broken pipe) errors to * be ignored. This is needed so that Tcl processes don't * die if they create child processes (e.g. using "exec" or * "open") that terminate prematurely. The signal handler * is only set up when the first interpreter is created; * after this the application can override the handler with * a different one of its own, if it wants. */ #ifdef SIGPIPE (void) signal(SIGPIPE, SIG_IGN); #endif /* SIGPIPE */ #if defined(__FreeBSD__) && defined(__GNUC__) /* * Adjust the rounding mode to be more conventional. Note that FreeBSD * only provides the __fpsetreg() used by the following two for the GNU * Compiler. When using, say, Intel's icc they break. (Partially based on * patch in BSD ports system from root@celsius.bychok.com) */ fpsetround(FP_RN); fpsetmask(0L); #endif #if defined(__bsdi__) && (_BSDI_VERSION > 199501) /* * Find local symbols. Don't report an error if we fail. */ (void) dlopen (NULL, RTLD_NOW); /* INTL: Native. */ #endif #ifdef GET_DARWIN_RELEASE { struct utsname name; if (!uname(&name)) { tclMacOSXDarwinRelease = strtol(name.release, NULL, 10); } } #endif } /* *--------------------------------------------------------------------------- * * TclpInitLibraryPath -- * * Initialize the library path at startup. We have a minor * metacircular problem that we don't know the encoding of the * operating system but we may need to talk to operating system * to find the library directories so that we know how to talk to * the operating system. * * We do not know the encoding of the operating system. * We do know that the encoding is some multibyte encoding. * In that multibyte encoding, the characters 0..127 are equivalent * to ascii. * * So although we don't know the encoding, it's safe: * to look for the last slash character in a path in the encoding. * to append an ascii string to a path. * to pass those strings back to the operating system. * * But any strings that we remembered before we knew the encoding of * the operating system must be translated to UTF-8 once we know the * encoding so that the rest of Tcl can use those strings. * * This call sets the library path to strings in the unknown native * encoding. TclpSetInitialEncodings() will translate the library * path from the native encoding to UTF-8 as soon as it determines * what the native encoding actually is. * * Called at process initialization time. * * Results: * Return 1, indicating that the UTF may be dirty and require "cleanup" * after encodings are initialized. * * Side effects: * None. * *--------------------------------------------------------------------------- */ int TclpInitLibraryPath(path) CONST char *path; /* Path to the executable in native * multi-byte encoding. */ { #define LIBRARY_SIZE 32 Tcl_Obj *pathPtr, *objPtr; CONST char *str; Tcl_DString buffer, ds; int pathc; CONST char **pathv; char installLib[LIBRARY_SIZE], developLib[LIBRARY_SIZE]; Tcl_DStringInit(&ds); pathPtr = Tcl_NewObj(); /* * Initialize the substrings used when locating an executable. The * installLib variable computes the path as though the executable * is installed. The developLib computes the path as though the * executable is run from a develpment directory. */ sprintf(installLib, "lib/tcl%s", TCL_VERSION); sprintf(developLib, "tcl%s/library", TCL_PATCH_LEVEL); /* * Look for the library relative to default encoding dir. */ str = Tcl_GetDefaultEncodingDir(); if ((str != NULL) && (str[0] != '\0')) { objPtr = Tcl_NewStringObj(str, -1); Tcl_ListObjAppendElement(NULL, pathPtr, objPtr); } /* * Look for the library relative to the TCL_LIBRARY env variable. * If the last dirname in the TCL_LIBRARY path does not match the * last dirname in the installLib variable, use the last dir name * of installLib in addition to the orginal TCL_LIBRARY path. */ str = getenv("TCL_LIBRARY"); /* INTL: Native. */ Tcl_ExternalToUtfDString(NULL, str, -1, &buffer); str = Tcl_DStringValue(&buffer); if ((str != NULL) && (str[0] != '\0')) { /* * If TCL_LIBRARY is set, search there. */ objPtr = Tcl_NewStringObj(str, -1); Tcl_ListObjAppendElement(NULL, pathPtr, objPtr); Tcl_SplitPath(str, &pathc, &pathv); if ((pathc > 0) && (strcasecmp(installLib + 4, pathv[pathc-1]) != 0)) { /* * If TCL_LIBRARY is set but refers to a different tcl * installation than the current version, try fiddling with the * specified directory to make it refer to this installation by * removing the old "tclX.Y" and substituting the current * version string. */ pathv[pathc - 1] = installLib + 4; str = Tcl_JoinPath(pathc, pathv, &ds); objPtr = Tcl_NewStringObj(str, Tcl_DStringLength(&ds)); Tcl_ListObjAppendElement(NULL, pathPtr, objPtr); Tcl_DStringFree(&ds); } ckfree((char *) pathv); } /* * Look for the library relative to the executable. This algorithm * should be the same as the one in the tcl_findLibrary procedure. * * This code looks in the following directories: * * /../ * (e.g. /usr/local/bin/../lib/tcl8.4) * /../../ * (e.g. /usr/local/TclPro/solaris-sparc/bin/../../lib/tcl8.4) * /../library * (e.g. /usr/src/tcl8.4.0/unix/../library) * /../../library * (e.g. /usr/src/tcl8.4.0/unix/solaris-sparc/../../library) * /../../ * (e.g. /usr/src/tcl8.4.0/unix/../../tcl8.4.0/library) * /../../../ * (e.g. /usr/src/tcl8.4.0/unix/solaris-sparc/../../../tcl8.4.0/library) */ /* * The variable path holds an absolute path. Take care not to * overwrite pathv[0] since that might produce a relative path. */ if (path != NULL) { int i, origc; CONST char **origv; Tcl_SplitPath(path, &origc, &origv); pathc = 0; pathv = (CONST char **) ckalloc((unsigned int)(origc * sizeof(char *))); for (i=0; i< origc; i++) { if (origv[i][0] == '.') { if (strcmp(origv[i], ".") == 0) { /* do nothing */ } else if (strcmp(origv[i], "..") == 0) { pathc--; } else { pathv[pathc++] = origv[i]; } } else { pathv[pathc++] = origv[i]; } } if (pathc > 2) { str = pathv[pathc - 2]; pathv[pathc - 2] = installLib; path = Tcl_JoinPath(pathc - 1, pathv, &ds); pathv[pathc - 2] = str; objPtr = Tcl_NewStringObj(path, Tcl_DStringLength(&ds)); Tcl_ListObjAppendElement(NULL, pathPtr, objPtr); Tcl_DStringFree(&ds); } if (pathc > 3) { str = pathv[pathc - 3]; pathv[pathc - 3] = installLib; path = Tcl_JoinPath(pathc - 2, pathv, &ds); pathv[pathc - 3] = str; objPtr = Tcl_NewStringObj(path, Tcl_DStringLength(&ds)); Tcl_ListObjAppendElement(NULL, pathPtr, objPtr); Tcl_DStringFree(&ds); } if (pathc > 2) { str = pathv[pathc - 2]; pathv[pathc - 2] = "library"; path = Tcl_JoinPath(pathc - 1, pathv, &ds); pathv[pathc - 2] = str; objPtr = Tcl_NewStringObj(path, Tcl_DStringLength(&ds)); Tcl_ListObjAppendElement(NULL, pathPtr, objPtr); Tcl_DStringFree(&ds); } if (pathc > 3) { str = pathv[pathc - 3]; pathv[pathc - 3] = "library"; path = Tcl_JoinPath(pathc - 2, pathv, &ds); pathv[pathc - 3] = str; objPtr = Tcl_NewStringObj(path, Tcl_DStringLength(&ds)); Tcl_ListObjAppendElement(NULL, pathPtr, objPtr); Tcl_DStringFree(&ds); } if (pathc > 3) { str = pathv[pathc - 3]; pathv[pathc - 3] = developLib; path = Tcl_JoinPath(pathc - 2, pathv, &ds); pathv[pathc - 3] = str; objPtr = Tcl_NewStringObj(path, Tcl_DStringLength(&ds)); Tcl_ListObjAppendElement(NULL, pathPtr, objPtr); Tcl_DStringFree(&ds); } if (pathc > 4) { str = pathv[pathc - 4]; pathv[pathc - 4] = developLib; path = Tcl_JoinPath(pathc - 3, pathv, &ds); pathv[pathc - 4] = str; objPtr = Tcl_NewStringObj(path, Tcl_DStringLength(&ds)); Tcl_ListObjAppendElement(NULL, pathPtr, objPtr); Tcl_DStringFree(&ds); } ckfree((char *) origv); ckfree((char *) pathv); } /* * Finally, look for the library relative to the compiled-in path. * This is needed when users install Tcl with an exec-prefix that * is different from the prtefix. */ { #ifdef HAVE_COREFOUNDATION char tclLibPath[MAXPATHLEN + 1]; if (MacOSXGetLibraryPath(NULL, MAXPATHLEN, tclLibPath) == TCL_OK) { str = tclLibPath; } else #endif /* HAVE_COREFOUNDATION */ { str = defaultLibraryDir; } if (str[0] != '\0') { objPtr = Tcl_NewStringObj(str, -1); Tcl_ListObjAppendElement(NULL, pathPtr, objPtr); } } TclSetLibraryPath(pathPtr); Tcl_DStringFree(&buffer); return 1; /* 1 indicates that pathPtr may be dirty utf (needs cleaning) */ } /* *--------------------------------------------------------------------------- * * TclpSetInitialEncodings -- * * Based on the locale, determine the encoding of the operating * system and the default encoding for newly opened files. * * Called at process initialization time, and part way through * startup, we verify that the initial encodings were correctly * setup. Depending on Tcl's environment, there may not have been * enough information first time through (above). * * Results: * None. * * Side effects: * The Tcl library path is converted from native encoding to UTF-8, * on the first call, and the encodings may be changed on first or * second call. * *--------------------------------------------------------------------------- */ void TclpSetInitialEncodings() { CONST char *encoding = NULL; int i, setSysEncCode = TCL_ERROR; Tcl_Obj *pathPtr; /* * Determine the current encoding from the LC_* or LANG environment * variables. We previously used setlocale() to determine the locale, * but this does not work on some systems (e.g. Linux/i386 RH 5.0). */ #ifdef HAVE_LANGINFO if ( #ifdef WEAK_IMPORT_NL_LANGINFO nl_langinfo != NULL && #endif setlocale(LC_CTYPE, "") != NULL) { Tcl_DString ds; /* * Use a DString so we can overwrite it in name compatability * checks below. */ Tcl_DStringInit(&ds); encoding = Tcl_DStringAppend(&ds, nl_langinfo(CODESET), -1); Tcl_UtfToLower(Tcl_DStringValue(&ds)); #ifdef HAVE_LANGINFO_DEBUG fprintf(stderr, "encoding '%s'", encoding); #endif if (encoding[0] == 'i' && encoding[1] == 's' && encoding[2] == 'o' && encoding[3] == '-') { char *p, *q; /* need to strip '-' from iso-* encoding */ for(p = Tcl_DStringValue(&ds)+3, q = Tcl_DStringValue(&ds)+4; *p; *p++ = *q++); } else if (encoding[0] == 'i' && encoding[1] == 'b' && encoding[2] == 'm' && encoding[3] >= '0' && encoding[3] <= '9') { char *p, *q; /* if langinfo reports "ibm*" we should use "cp*" */ p = Tcl_DStringValue(&ds); *p++ = 'c'; *p++ = 'p'; for(q = p+1; *p ; *p++ = *q++); } else if ((*encoding == '\0') || !strcmp(encoding, "ansi_x3.4-1968")) { /* Use iso8859-1 for empty or 'ansi_x3.4-1968' encoding */ encoding = "iso8859-1"; } #ifdef HAVE_LANGINFO_DEBUG fprintf(stderr, " ?%s?", encoding); #endif setSysEncCode = Tcl_SetSystemEncoding(NULL, encoding); if (setSysEncCode != TCL_OK) { /* * If this doesn't return TCL_OK, the encoding returned by * nl_langinfo or as we translated it wasn't accepted. Do * this fallback check. If this fails, we will enter the * old fallback below. */ for (i = 0; localeTable[i].lang != NULL; i++) { if (strcmp(localeTable[i].lang, encoding) == 0) { setSysEncCode = Tcl_SetSystemEncoding(NULL, localeTable[i].encoding); break; } } } #ifdef HAVE_LANGINFO_DEBUG fprintf(stderr, " => '%s'\n", encoding); #endif Tcl_DStringFree(&ds); } #ifdef HAVE_LANGINFO_DEBUG else { fprintf(stderr, "setlocale returned NULL\n"); } #endif #endif /* HAVE_LANGINFO */ if (setSysEncCode != TCL_OK) { /* * Classic fallback check. This tries a homebrew algorithm to * determine what encoding should be used based on env vars. */ char *langEnv = getenv("LC_ALL"); encoding = NULL; if (langEnv == NULL || langEnv[0] == '\0') { langEnv = getenv("LC_CTYPE"); } if (langEnv == NULL || langEnv[0] == '\0') { langEnv = getenv("LANG"); } if (langEnv == NULL || langEnv[0] == '\0') { langEnv = NULL; } if (langEnv != NULL) { for (i = 0; localeTable[i].lang != NULL; i++) { if (strcmp(localeTable[i].lang, langEnv) == 0) { encoding = localeTable[i].encoding; break; } } /* * There was no mapping in the locale table. If there is an * encoding subfield, we can try to guess from that. */ if (encoding == NULL) { char *p; for (p = langEnv; *p != '\0'; p++) { if (*p == '.') { p++; break; } } if (*p != '\0') { Tcl_DString ds; Tcl_DStringInit(&ds); encoding = Tcl_DStringAppend(&ds, p, -1); Tcl_UtfToLower(Tcl_DStringValue(&ds)); setSysEncCode = Tcl_SetSystemEncoding(NULL, encoding); if (setSysEncCode != TCL_OK) { encoding = NULL; } Tcl_DStringFree(&ds); } } #ifdef HAVE_LANGINFO_DEBUG fprintf(stderr, "encoding fallback check '%s' => '%s'\n", langEnv, encoding); #endif } if (setSysEncCode != TCL_OK) { if (encoding == NULL) { encoding = TCL_DEFAULT_ENCODING; } Tcl_SetSystemEncoding(NULL, encoding); } /* * Initialize the C library's locale subsystem. This is required * for input methods to work properly on X11. We only do this for * LC_CTYPE because that's the necessary one, and we don't want to * affect LC_TIME here. The side effect of setting the default * locale should be to load any locale specific modules that are * needed by X. [BUG: 5422 3345 4236 2522 2521]. * In HAVE_LANGINFO, this call is already done above. */ #ifndef HAVE_LANGINFO setlocale(LC_CTYPE, ""); #endif } /* * In case the initial locale is not "C", ensure that the numeric * processing is done in "C" locale regardless. This is needed because * Tcl relies on routines like strtod, but should not have locale * dependent behavior. */ setlocale(LC_NUMERIC, "C"); if ((libraryPathEncodingFixed == 0) && strcmp("identity", Tcl_GetEncodingName(Tcl_GetEncoding(NULL, NULL))) ) { /* * Until the system encoding was actually set, the library path was * actually in the native multi-byte encoding, and not really UTF-8 * as advertised. We cheated as follows: * * 1. It was safe to allow the Tcl_SetSystemEncoding() call to * append the ASCII chars that make up the encoding's filename to * the names (in the native encoding) of directories in the library * path, since all Unix multi-byte encodings have ASCII in the * beginning. * * 2. To open the encoding file, the native bytes in the file name * were passed to the OS, without translating from UTF-8 to native, * because the name was already in the native encoding. * * Now that the system encoding was actually successfully set, * translate all the names in the library path to UTF-8. That way, * next time we search the library path, we'll translate the names * from UTF-8 to the system encoding which will be the native * encoding. */ pathPtr = TclGetLibraryPath(); if (pathPtr != NULL) { int objc; Tcl_Obj **objv; objc = 0; Tcl_ListObjGetElements(NULL, pathPtr, &objc, &objv); for (i = 0; i < objc; i++) { int length; char *string; Tcl_DString ds; string = Tcl_GetStringFromObj(objv[i], &length); Tcl_ExternalToUtfDString(NULL, string, length, &ds); Tcl_SetStringObj(objv[i], Tcl_DStringValue(&ds), Tcl_DStringLength(&ds)); Tcl_DStringFree(&ds); } } libraryPathEncodingFixed = 1; } /* This is only ever called from the startup thread */ if (binaryEncoding == NULL) { /* * Keep the iso8859-1 encoding preloaded. The IO package uses * it for gets on a binary channel. */ binaryEncoding = Tcl_GetEncoding(NULL, "iso8859-1"); } } /* *--------------------------------------------------------------------------- * * TclpSetVariables -- * * Performs platform-specific interpreter initialization related to * the tcl_library and tcl_platform variables, and other platform- * specific things. * * Results: * None. * * Side effects: * Sets "tclDefaultLibrary", "tcl_pkgPath", and "tcl_platform" Tcl * variables. * *---------------------------------------------------------------------- */ void TclpSetVariables(interp) Tcl_Interp *interp; { #ifdef __CYGWIN__ SYSTEM_INFO sysInfo; OSVERSIONINFOA osInfo; char buffer[TCL_INTEGER_SPACE * 2]; #elif !defined(NO_UNAME) struct utsname name; #endif int unameOK; CONST char *user; Tcl_DString ds; #ifdef HAVE_COREFOUNDATION char tclLibPath[MAXPATHLEN + 1]; #if MAC_OS_X_VERSION_MAX_ALLOWED > 1020 /* * Set msgcat fallback locale to current CFLocale identifier. */ CFLocaleRef localeRef; if (CFLocaleCopyCurrent != NULL && CFLocaleGetIdentifier != NULL && (localeRef = CFLocaleCopyCurrent())) { CFStringRef locale = CFLocaleGetIdentifier(localeRef); if (locale) { char loc[256]; if (CFStringGetCString(locale, loc, 256, kCFStringEncodingUTF8)) { if (!Tcl_CreateNamespace(interp, "::tcl::mac", NULL, NULL)) { Tcl_ResetResult(interp); } Tcl_SetVar(interp, "::tcl::mac::locale", loc, TCL_GLOBAL_ONLY); } } CFRelease(localeRef); } #endif if (MacOSXGetLibraryPath(interp, MAXPATHLEN, tclLibPath) == TCL_OK) { CONST char *str; Tcl_DString ds; CFBundleRef bundleRef; Tcl_SetVar(interp, "tclDefaultLibrary", tclLibPath, TCL_GLOBAL_ONLY); Tcl_SetVar(interp, "tcl_pkgPath", tclLibPath, TCL_GLOBAL_ONLY); Tcl_SetVar(interp, "tcl_pkgPath", " ", TCL_GLOBAL_ONLY | TCL_APPEND_VALUE); str = TclGetEnv("DYLD_FRAMEWORK_PATH", &ds); if ((str != NULL) && (str[0] != '\0')) { char *p = Tcl_DStringValue(&ds); /* convert DYLD_FRAMEWORK_PATH from colon to space separated */ do { if(*p == ':') *p = ' '; } while (*p++); Tcl_SetVar(interp, "tcl_pkgPath", Tcl_DStringValue(&ds), TCL_GLOBAL_ONLY | TCL_APPEND_VALUE); Tcl_SetVar(interp, "tcl_pkgPath", " ", TCL_GLOBAL_ONLY | TCL_APPEND_VALUE); Tcl_DStringFree(&ds); } if ((bundleRef = CFBundleGetMainBundle())) { CFURLRef frameworksURL; Tcl_StatBuf statBuf; if((frameworksURL = CFBundleCopyPrivateFrameworksURL(bundleRef))) { if(CFURLGetFileSystemRepresentation(frameworksURL, TRUE, (unsigned char*) tclLibPath, MAXPATHLEN) && ! TclOSstat(tclLibPath, &statBuf) && S_ISDIR(statBuf.st_mode)) { Tcl_SetVar(interp, "tcl_pkgPath", tclLibPath, TCL_GLOBAL_ONLY | TCL_APPEND_VALUE); Tcl_SetVar(interp, "tcl_pkgPath", " ", TCL_GLOBAL_ONLY | TCL_APPEND_VALUE); } CFRelease(frameworksURL); } if((frameworksURL = CFBundleCopySharedFrameworksURL(bundleRef))) { if(CFURLGetFileSystemRepresentation(frameworksURL, TRUE, (unsigned char*) tclLibPath, MAXPATHLEN) && ! TclOSstat(tclLibPath, &statBuf) && S_ISDIR(statBuf.st_mode)) { Tcl_SetVar(interp, "tcl_pkgPath", tclLibPath, TCL_GLOBAL_ONLY | TCL_APPEND_VALUE); Tcl_SetVar(interp, "tcl_pkgPath", " ", TCL_GLOBAL_ONLY | TCL_APPEND_VALUE); } CFRelease(frameworksURL); } } Tcl_SetVar(interp, "tcl_pkgPath", pkgPath, TCL_GLOBAL_ONLY | TCL_APPEND_VALUE); } else #endif /* HAVE_COREFOUNDATION */ { Tcl_SetVar(interp, "tclDefaultLibrary", defaultLibraryDir, TCL_GLOBAL_ONLY); Tcl_SetVar(interp, "tcl_pkgPath", pkgPath, TCL_GLOBAL_ONLY); } #ifdef DJGPP Tcl_SetVar2(interp, "tcl_platform", "platform", "dos", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "tcl_platform", "platform", "unix", TCL_GLOBAL_ONLY); #endif unameOK = 0; #ifdef __CYGWIN__ unameOK = 1; osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); GetVersionExA(&osInfo); GetSystemInfo(&sysInfo); if (osInfo.dwPlatformId < NUMPLATFORMS) { Tcl_SetVar2(interp, "tcl_platform", "os", platforms[osInfo.dwPlatformId], TCL_GLOBAL_ONLY); } sprintf(buffer, "%d.%d", osInfo.dwMajorVersion, osInfo.dwMinorVersion); Tcl_SetVar2(interp, "tcl_platform", "osVersion", buffer, TCL_GLOBAL_ONLY); if (sysInfo.wProcessorArchitecture < NUMPROCESSORS) { Tcl_SetVar2(interp, "tcl_platform", "machine", processors[sysInfo.wProcessorArchitecture], TCL_GLOBAL_ONLY); } #elif !defined NO_UNAME if (uname(&name) >= 0) { CONST char *native; unameOK = 1; native = Tcl_ExternalToUtfDString(NULL, name.sysname, -1, &ds); Tcl_SetVar2(interp, "tcl_platform", "os", native, TCL_GLOBAL_ONLY); Tcl_DStringFree(&ds); /* * The following code is a special hack to handle differences in * the way version information is returned by uname. On most * systems the full version number is available in name.release. * However, under AIX the major version number is in * name.version and the minor version number is in name.release. */ if ((strchr(name.release, '.') != NULL) || !isdigit(UCHAR(name.version[0]))) { /* INTL: digit */ Tcl_SetVar2(interp, "tcl_platform", "osVersion", name.release, TCL_GLOBAL_ONLY); } else { Tcl_SetVar2(interp, "tcl_platform", "osVersion", name.version, TCL_GLOBAL_ONLY); Tcl_SetVar2(interp, "tcl_platform", "osVersion", ".", TCL_GLOBAL_ONLY|TCL_APPEND_VALUE); Tcl_SetVar2(interp, "tcl_platform", "osVersion", name.release, TCL_GLOBAL_ONLY|TCL_APPEND_VALUE); } Tcl_SetVar2(interp, "tcl_platform", "machine", name.machine, TCL_GLOBAL_ONLY); } #endif if (!unameOK) { Tcl_SetVar2(interp, "tcl_platform", "os", "", TCL_GLOBAL_ONLY); Tcl_SetVar2(interp, "tcl_platform", "osVersion", "", TCL_GLOBAL_ONLY); Tcl_SetVar2(interp, "tcl_platform", "machine", "", TCL_GLOBAL_ONLY); } /* * Copy USER or LOGNAME environment variable into tcl_platform(user) */ Tcl_DStringInit(&ds); user = TclGetEnv("USER", &ds); if (user == NULL) { user = TclGetEnv("LOGNAME", &ds); if (user == NULL) { user = ""; } } Tcl_SetVar2(interp, "tcl_platform", "user", user, TCL_GLOBAL_ONLY); Tcl_DStringFree(&ds); } /* *---------------------------------------------------------------------- * * TclpFindVariable -- * * Locate the entry in environ for a given name. On Unix this * routine is case sensetive, on Windows this matches mixed case. * * Results: * The return value is the index in environ of an entry with the * name "name", or -1 if there is no such entry. The integer at * *lengthPtr is filled in with the length of name (if a matching * entry is found) or the length of the environ array (if no matching * entry is found). * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclpFindVariable(name, lengthPtr) CONST char *name; /* Name of desired environment variable * (native). */ int *lengthPtr; /* Used to return length of name (for * successful searches) or number of non-NULL * entries in environ (for unsuccessful * searches). */ { int i, result = -1; register CONST char *env, *p1, *p2; Tcl_DString envString; Tcl_DStringInit(&envString); for (i = 0, env = environ[i]; env != NULL; i++, env = environ[i]) { p1 = Tcl_ExternalToUtfDString(NULL, env, -1, &envString); p2 = name; for (; *p2 == *p1; p1++, p2++) { /* NULL loop body. */ } if ((*p1 == '=') && (*p2 == '\0')) { *lengthPtr = p2 - name; result = i; goto done; } Tcl_DStringFree(&envString); } *lengthPtr = i; done: Tcl_DStringFree(&envString); return result; } /* *---------------------------------------------------------------------- * * Tcl_Init -- * * This procedure is typically invoked by Tcl_AppInit procedures * to find and source the "init.tcl" script, which should exist * somewhere on the Tcl library path. * * Results: * Returns a standard Tcl completion code and sets the interp's * result if there is an error. * * Side effects: * Depends on what's in the init.tcl script. * *---------------------------------------------------------------------- */ int Tcl_Init(interp) Tcl_Interp *interp; /* Interpreter to initialize. */ { Tcl_Obj *pathPtr; if (tclPreInitScript != NULL) { if (Tcl_Eval(interp, tclPreInitScript) == TCL_ERROR) { return (TCL_ERROR); }; } pathPtr = TclGetLibraryPath(); if (pathPtr == NULL) { pathPtr = Tcl_NewObj(); } Tcl_IncrRefCount(pathPtr); Tcl_SetVar2Ex(interp, "tcl_libPath", NULL, pathPtr, TCL_GLOBAL_ONLY); Tcl_DecrRefCount(pathPtr); return Tcl_Eval(interp, initScript); } /* *---------------------------------------------------------------------- * * Tcl_SourceRCFile -- * * This procedure is typically invoked by Tcl_Main of Tk_Main * procedure to source an application specific rc file into the * interpreter at startup time. * * Results: * None. * * Side effects: * Depends on what's in the rc script. * *---------------------------------------------------------------------- */ void Tcl_SourceRCFile(interp) Tcl_Interp *interp; /* Interpreter to source rc file into. */ { Tcl_DString temp; CONST char *fileName; Tcl_Channel errChannel; fileName = Tcl_GetVar(interp, "tcl_rcFileName", TCL_GLOBAL_ONLY); if (fileName != NULL) { Tcl_Channel c; CONST char *fullName; Tcl_DStringInit(&temp); fullName = Tcl_TranslateFileName(interp, fileName, &temp); if (fullName == NULL) { /* * Couldn't translate the file name (e.g. it referred to a * bogus user or there was no HOME environment variable). * Just do nothing. */ } else { /* * Test for the existence of the rc file before trying to read it. */ c = Tcl_OpenFileChannel(NULL, fullName, "r", 0); if (c != (Tcl_Channel) NULL) { Tcl_Close(NULL, c); if (Tcl_EvalFile(interp, fullName) != TCL_OK) { errChannel = Tcl_GetStdChannel(TCL_STDERR); if (errChannel) { Tcl_WriteObj(errChannel, Tcl_GetObjResult(interp)); Tcl_WriteChars(errChannel, "\n", 1); } } } } Tcl_DStringFree(&temp); } } /* *---------------------------------------------------------------------- * * TclpCheckStackSpace -- * * Detect if we are about to blow the stack. Called before an * evaluation can happen when nesting depth is checked. * * Results: * 1 if there is enough stack space to continue; 0 if not. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclpCheckStackSpace() { /* * This function is unimplemented on Unix platforms. */ return 1; } /* *---------------------------------------------------------------------- * * MacOSXGetLibraryPath -- * * If we have a bundle structure for the Tcl installation, * then check there first to see if we can find the libraries * there. * * Results: * TCL_OK if we have found the tcl library; TCL_ERROR otherwise. * * Side effects: * Same as for Tcl_MacOSXOpenVersionedBundleResources. * *---------------------------------------------------------------------- */ #ifdef HAVE_COREFOUNDATION static int MacOSXGetLibraryPath(Tcl_Interp *interp, int maxPathLen, char *tclLibPath) { int foundInFramework = TCL_ERROR; #ifdef TCL_FRAMEWORK foundInFramework = Tcl_MacOSXOpenVersionedBundleResources(interp, "com.tcltk.tcllibrary", TCL_FRAMEWORK_VERSION, 0, maxPathLen, tclLibPath); #endif return foundInFramework; } #endif /* HAVE_COREFOUNDATION */ tcl8.4.20/unix/tclUnixSock.c0000644003604700454610000000732711737050675014326 0ustar dgp771div/* * tclUnixSock.c -- * * This file contains Unix-specific socket related code. * * Copyright (c) 1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tcl.h" #include "tclPort.h" /* * There is no portable macro for the maximum length * of host names returned by gethostbyname(). We should only * trust SYS_NMLN if it is at least 255 + 1 bytes to comply with DNS * host name limits. * * Note: SYS_NMLN is a restriction on "uname" not on gethostbyname! * * For example HP-UX 10.20 has SYS_NMLN == 9, while gethostbyname() * can return a fully qualified name from DNS of up to 255 bytes. * * Fix suggested by Viktor Dukhovni (viktor@esm.com) */ #if defined(SYS_NMLN) && SYS_NMLEN >= 256 #define TCL_HOSTNAME_LEN SYS_NMLEN #else #define TCL_HOSTNAME_LEN 256 #endif /* * The following variable holds the network name of this host. */ static char hostname[TCL_HOSTNAME_LEN + 1]; static int hostnameInited = 0; TCL_DECLARE_MUTEX(hostMutex) /* *---------------------------------------------------------------------- * * Tcl_GetHostName -- * * Returns the name of the local host. * * Results: * A string containing the network name for this machine, or * an empty string if we can't figure out the name. The caller * must not modify or free this string. * * Side effects: * None. * *---------------------------------------------------------------------- */ CONST char * Tcl_GetHostName() { #ifndef NO_UNAME struct utsname u; struct hostent *hp; #else char buffer[sizeof(hostname)]; #endif CONST char *native; Tcl_MutexLock(&hostMutex); if (hostnameInited) { Tcl_MutexUnlock(&hostMutex); return hostname; } native = NULL; #ifndef NO_UNAME (VOID *) memset((VOID *) &u, (int) 0, sizeof(struct utsname)); if (uname(&u) > -1) { /* INTL: Native. */ hp = TclpGetHostByName(u.nodename); /* INTL: Native. */ if (hp == NULL) { /* * Sometimes the nodename is fully qualified, but gets truncated * as it exceeds SYS_NMLN. See if we can just get the immediate * nodename and get a proper answer that way. */ char *dot = strchr(u.nodename, '.'); if (dot != NULL) { char *node = ckalloc((unsigned) (dot - u.nodename + 1)); memcpy(node, u.nodename, (size_t) (dot - u.nodename)); node[dot - u.nodename] = '\0'; hp = TclpGetHostByName(node); ckfree(node); } } if (hp != NULL) { native = hp->h_name; } else { native = u.nodename; } } #else /* * Uname doesn't exist; try gethostname instead. */ if (gethostname(buffer, sizeof(buffer)) > -1) { /* INTL: Native. */ native = buffer; } #endif if (native == NULL) { hostname[0] = 0; } else { Tcl_ExternalToUtf(NULL, NULL, native, -1, 0, NULL, hostname, sizeof(hostname), NULL, NULL, NULL); } hostnameInited = 1; Tcl_MutexUnlock(&hostMutex); return hostname; } /* *---------------------------------------------------------------------- * * TclpHasSockets -- * * Detect if sockets are available on this platform. * * Results: * Returns TCL_OK. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclpHasSockets(interp) Tcl_Interp *interp; /* Not used. */ { return TCL_OK; } /* *---------------------------------------------------------------------- * * TclpFinalizeSockets -- * * Performs per-thread socket subsystem finalization. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TclpFinalizeSockets() { return; } tcl8.4.20/unix/tclLoadAout.c0000644003604700454610000003545311737050675014274 0ustar dgp771div/* * tclLoadAout.c -- * * This procedure provides a version of the TclLoadFile that * provides pseudo-static linking using version-7 compatible * a.out files described in either sys/exec.h or sys/a.out.h. * * Copyright (c) 1995, by General Electric Company. All rights reserved. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * This work was supported in part by the ARPA Manufacturing Automation * and Design Engineering (MADE) Initiative through ARPA contract * F33615-94-C-4400. */ #include "tclInt.h" #include #ifdef HAVE_EXEC_AOUT_H # include #endif #ifdef HAVE_UNISTD_H # include #else # include "../compat/unistd.h" #endif /* * Some systems describe the a.out header in sys/exec.h, and some in * a.out.h. */ #ifdef USE_SYS_EXEC_H #include #endif #ifdef USE_A_OUT_H #include #endif #ifdef USE_SYS_EXEC_AOUT_H #include #define a_magic a_midmag #endif /* * TCL_LOADSHIM is the amount by which to shim the break when loading */ #ifndef TCL_LOADSHIM #define TCL_LOADSHIM 0x4000L #endif /* * TCL_LOADALIGN must be a power of 2, and is the alignment to which * to force the origin of load modules */ #ifndef TCL_LOADALIGN #define TCL_LOADALIGN 0x4000L #endif /* * TCL_LOADMAX is the maximum size of a load module, and is used as * a sanity check when loading */ #ifndef TCL_LOADMAX #define TCL_LOADMAX 2000000L #endif /* * Kernel calls that appear to be missing from the system .h files: */ extern char * brk _ANSI_ARGS_((char *)); extern char * sbrk _ANSI_ARGS_((size_t)); /* * The static variable SymbolTableFile contains the file name where the * result of the last link was stored. The file is kept because doing so * allows one load module to use the symbols defined in another. */ static char * SymbolTableFile = NULL; /* * Type of the dictionary function that begins each load module. */ typedef Tcl_PackageInitProc * (* DictFn) _ANSI_ARGS_ ((CONST char * symbol)); /* * Prototypes for procedures referenced only in this file: */ static int FindLibraries _ANSI_ARGS_((Tcl_Interp * interp, Tcl_Obj * pathPtr, Tcl_DString * buf)); static void UnlinkSymbolTable _ANSI_ARGS_((void)); /* *---------------------------------------------------------------------- * * TclpDlopen -- * * Dynamically loads a binary code file into memory and returns * a handle to the new code. * * Results: * A standard Tcl completion code. If an error occurs, an error * message is left in the interp's result. * * Side effects: * New code suddenly appears in memory. * * * Bugs: * This function does not attempt to handle the case where the * BSS segment is not executable. It will therefore fail on * Encore Multimax, Pyramid 90x, and similar machines. The * reason is that the mprotect() kernel call, which would * otherwise be employed to mark the newly-loaded text segment * executable, results in a system crash on BSD/386. * * In an effort to make it fast, this function eschews the * technique of linking the load module once, reading its header * to determine its size, allocating memory for it, and linking * it again. Instead, it `shims out' memory allocation by * placing the module TCL_LOADSHIM bytes beyond the break, * and assuming that any malloc() calls required to run the * linker will not advance the break beyond that point. If * the break is advanced beyonnd that point, the load will * fail with an `inconsistent memory allocation' error. * It perhaps ought to retry the link, but the failure has * not been observed in two years of daily use of this function. *---------------------------------------------------------------------- */ int TclpDlopen(interp, pathPtr, loadHandle, unloadProcPtr) Tcl_Interp *interp; /* Used for error reporting. */ Tcl_Obj *pathPtr; /* Name of the file containing the desired * code (UTF-8). */ Tcl_LoadHandle *loadHandle; /* Filled with token for dynamically loaded * file which will be passed back to * (*unloadProcPtr)() to unload the file. */ Tcl_FSUnloadFileProc **unloadProcPtr; /* Filled with address of Tcl_FSUnloadFileProc * function which should be used for * this file. */ { char * inputSymbolTable; /* Name of the file containing the * symbol table from the last link. */ Tcl_DString linkCommandBuf; /* Command to do the run-time relocation * of the module.*/ char * linkCommand; char relocatedFileName [L_tmpnam]; /* Name of the file holding the relocated */ /* text of the module */ int relocatedFd; /* File descriptor of the file holding * relocated text */ struct exec relocatedHead; /* Header of the relocated text */ unsigned long relocatedSize;/* Size of the relocated text */ char * startAddress; /* Starting address of the module */ int status; /* Status return from Tcl_ calls */ char * p; /* Find the file that contains the symbols for the run-time link. */ if (SymbolTableFile != NULL) { inputSymbolTable = SymbolTableFile; } else if (tclExecutableName == NULL) { Tcl_SetResult (interp, "can't find the tclsh executable", TCL_STATIC); return TCL_ERROR; } else { inputSymbolTable = tclExecutableName; } /* Construct the `ld' command that builds the relocated module */ tmpnam (relocatedFileName); Tcl_DStringInit (&linkCommandBuf); Tcl_DStringAppend (&linkCommandBuf, "exec ld -o ", -1); Tcl_DStringAppend (&linkCommandBuf, relocatedFileName, -1); #if defined(__mips) || defined(mips) Tcl_DStringAppend (&linkCommandBuf, " -G 0 ", -1); #endif Tcl_DStringAppend (&linkCommandBuf, " -u TclLoadDictionary_", -1); TclGuessPackageName(Tcl_GetString(pathPtr), &linkCommandBuf); Tcl_DStringAppend (&linkCommandBuf, " -A ", -1); Tcl_DStringAppend (&linkCommandBuf, inputSymbolTable, -1); Tcl_DStringAppend (&linkCommandBuf, " -N -T XXXXXXXX ", -1); Tcl_DStringAppend (&linkCommandBuf, Tcl_GetString(pathPtr), -1); Tcl_DStringAppend (&linkCommandBuf, " ", -1); if (FindLibraries (interp, pathPtr, &linkCommandBuf) != TCL_OK) { Tcl_DStringFree (&linkCommandBuf); return TCL_ERROR; } linkCommand = Tcl_DStringValue (&linkCommandBuf); /* Determine the starting address, and plug it into the command */ startAddress = (char *) (((unsigned long) sbrk (0) + TCL_LOADSHIM + TCL_LOADALIGN - 1) & (- TCL_LOADALIGN)); p = strstr (linkCommand, "-T") + 3; sprintf (p, "%08lx", (long) startAddress); p [8] = ' '; /* Run the linker */ status = Tcl_Eval (interp, linkCommand); Tcl_DStringFree (&linkCommandBuf); if (status != 0) { return TCL_ERROR; } /* Open the linker's result file and read the header */ relocatedFd = open (relocatedFileName, O_RDONLY); if (relocatedFd < 0) { goto ioError; } status= read (relocatedFd, (char *) & relocatedHead, sizeof relocatedHead); if (status < sizeof relocatedHead) { goto ioError; } /* Check the magic number */ if (relocatedHead.a_magic != OMAGIC) { Tcl_AppendResult (interp, "bad magic number in intermediate file \"", relocatedFileName, "\"", (char *) NULL); goto failure; } /* Make sure that memory allocation is still consistent */ if ((unsigned long) sbrk (0) > (unsigned long) startAddress) { Tcl_SetResult (interp, "can't load, memory allocation is inconsistent.", TCL_STATIC); goto failure; } /* Make sure that the relocated module's size is reasonable */ relocatedSize = relocatedHead.a_text + relocatedHead.a_data + relocatedHead.a_bss; if (relocatedSize > TCL_LOADMAX) { Tcl_SetResult (interp, "module too big to load", TCL_STATIC); goto failure; } /* Advance the break to protect the loaded module */ (void) brk (startAddress + relocatedSize); /* * Seek to the start of the module's text. * * Note that this does not really work with large files (i.e. where * lseek64 exists and is different to lseek), but anyone trying to * dynamically load a binary that is larger than what can fit in * addressable memory is in trouble anyway... */ #if defined(__mips) || defined(mips) status = lseek (relocatedFd, (off_t) N_TXTOFF (relocatedHead.ex_f, relocatedHead.ex_o), SEEK_SET); #else status = lseek (relocatedFd, (off_t) N_TXTOFF (relocatedHead), SEEK_SET); #endif if (status < 0) { goto ioError; } /* Read in the module's text and data */ relocatedSize = relocatedHead.a_text + relocatedHead.a_data; if (read (relocatedFd, startAddress, relocatedSize) < relocatedSize) { brk (startAddress); ioError: Tcl_AppendResult (interp, "error on intermediate file \"", relocatedFileName, "\": ", Tcl_PosixError (interp), (char *) NULL); failure: (void) unlink (relocatedFileName); return TCL_ERROR; } /* Close the intermediate file. */ (void) close (relocatedFd); /* Arrange things so that intermediate symbol tables eventually get * deleted. */ if (SymbolTableFile != NULL) { UnlinkSymbolTable (); } else { atexit (UnlinkSymbolTable); } SymbolTableFile = ckalloc (strlen (relocatedFileName) + 1); strcpy (SymbolTableFile, relocatedFileName); *loadHandle = startAddress; return TCL_OK; } /* *---------------------------------------------------------------------- * * TclpFindSymbol -- * * Looks up a symbol, by name, through a handle associated with * a previously loaded piece of code (shared library). * * Results: * Returns a pointer to the function associated with 'symbol' if * it is found. Otherwise returns NULL and may leave an error * message in the interp's result. * *---------------------------------------------------------------------- */ Tcl_PackageInitProc* TclpFindSymbol(interp, loadHandle, symbol) Tcl_Interp *interp; Tcl_LoadHandle loadHandle; CONST char *symbol; { /* Look up the entry point in the load module's dictionary. */ DictFn dictionary = (DictFn) loadHandle; return (Tcl_PackageInitProc*) dictionary(sym1); } /* *------------------------------------------------------------------------ * * FindLibraries -- * * Find the libraries needed to link a load module at run time. * * Results: * A standard Tcl completion code. If an error occurs, * an error message is left in the interp's result. The -l and -L * flags are concatenated onto the dynamic string `buf'. * *------------------------------------------------------------------------ */ static int FindLibraries (interp, pathPtr, buf) Tcl_Interp * interp; /* Used for error reporting */ Tcl_Obj * pathPtr; /* Name of the load module */ Tcl_DString * buf; /* Buffer where the -l an -L flags */ { FILE * f; /* The load module */ int c = 0; /* Byte from the load module */ char * p; CONST char *native; char *fileName = Tcl_GetString(pathPtr); /* Open the load module */ native = Tcl_FSGetNativePath(pathPtr); f = fopen(native, "rb"); /* INTL: Native. */ if (f == NULL) { Tcl_AppendResult (interp, "couldn't open \"", fileName, "\": ", Tcl_PosixError (interp), (char *) NULL); return TCL_ERROR; } /* Search for the library list in the load module */ p = "@LIBS: "; while (*p != '\0' && (c = getc (f)) != EOF) { if (c == *p) { ++p; } else { p = "@LIBS: "; if (c == *p) { ++p; } } } /* No library list -- this must be an ill-formed module */ if (c == EOF) { Tcl_AppendResult (interp, "File \"", fileName, "\" is not a Tcl load module.", (char *) NULL); (void) fclose (f); return TCL_ERROR; } /* Accumulate the library list */ while ((c = getc (f)) != '\0' && c != EOF) { char cc = c; Tcl_DStringAppend (buf, &cc, 1); } (void) fclose (f); if (c == EOF) { Tcl_AppendResult (interp, "Library directory in \"", fileName, "\" ends prematurely.", (char *) NULL); return TCL_ERROR; } return TCL_OK; } /* *------------------------------------------------------------------------ * * UnlinkSymbolTable -- * * Remove the symbol table file from the last dynamic link. * * Results: * None. * * Side effects: * The symbol table file from the last dynamic link is removed. * This function is called when (a) a new symbol table is present * because another dynamic link is complete, or (b) the process * is exiting. *------------------------------------------------------------------------ */ static void UnlinkSymbolTable () { (void) unlink (SymbolTableFile); ckfree (SymbolTableFile); SymbolTableFile = NULL; } /* *---------------------------------------------------------------------- * * TclpUnloadFile -- * * Unloads a dynamically loaded binary code file from memory. * Code pointers in the formerly loaded file are no longer valid * after calling this function. * * Results: * None. * * Side effects: * Does nothing. Can anything be done? * *---------------------------------------------------------------------- */ void TclpUnloadFile(loadHandle) Tcl_LoadHandle loadHandle; /* loadHandle returned by a previous call * to TclpDlopen(). The loadHandle is * a token that represents the loaded * file. */ { } /* *---------------------------------------------------------------------- * * TclGuessPackageName -- * * If the "load" command is invoked without providing a package * name, this procedure is invoked to try to figure it out. * * Results: * Always returns 0 to indicate that we couldn't figure out a * package name; generic code will then try to guess the package * from the file name. A return value of 1 would have meant that * we figured out the package name and put it in bufPtr. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclGuessPackageName(fileName, bufPtr) CONST char *fileName; /* Name of file containing package (already * translated to local form if needed). */ Tcl_DString *bufPtr; /* Initialized empty dstring. Append * package name to this if possible. */ { CONST char *p, *q; char *r; if ((q = strrchr(fileName,'/'))) { q++; } else { q = fileName; } if (!strncmp(q,"lib",3)) { q+=3; } p = q; while ((*p) && (*p != '.') && ((*p<'0') || (*p>'9'))) { p++; } if ((p>q+2) && !strncmp(p-2,"_G0.",4)) { p-=2; } if (p 4) && !strcasecmp(name + length - 4, ".exe")) { /* Strip '.exe' part. */ length -= 4; } tclNativeExecutableName = (char *) ckalloc(length + 1); memcpy(tclNativeExecutableName, name, length); tclNativeExecutableName[length] = '\0'; #else if (argv0 == NULL) { return NULL; } Tcl_DStringInit(&buffer); name = argv0; for (p = name; *p != '\0'; p++) { if (*p == '/') { /* * The name contains a slash, so use the name directly * without doing a path search. */ goto gotName; } } p = getenv("PATH"); /* INTL: Native. */ if (p == NULL) { /* * There's no PATH environment variable; use the default that * is used by sh. */ p = ":/bin:/usr/bin"; } else if (*p == '\0') { /* * An empty path is equivalent to ".". */ p = "./"; } /* * Search through all the directories named in the PATH variable * to see if argv[0] is in one of them. If so, use that file * name. */ while (1) { while (isspace(UCHAR(*p))) { /* INTL: BUG */ p++; } name = p; while ((*p != ':') && (*p != 0)) { p++; } Tcl_DStringSetLength(&buffer, 0); if (p != name) { Tcl_DStringAppend(&buffer, name, p - name); if (p[-1] != '/') { Tcl_DStringAppend(&buffer, "/", 1); } } name = Tcl_DStringAppend(&buffer, argv0, -1); /* * INTL: The following calls to access() and stat() should not be * converted to Tclp routines because they need to operate on native * strings directly. */ if ((access(name, X_OK) == 0) /* INTL: Native. */ && (TclOSstat(name, &statBuf) == 0) /* INTL: Native. */ && S_ISREG(statBuf.st_mode)) { goto gotName; } if (*p == '\0') { break; } else if (*(p+1) == 0) { p = "./"; } else { p++; } } goto done; /* * If the name starts with "/" then just copy it to tclExecutableName. */ gotName: #ifdef DJGPP if (name[1] == ':') { #else if (name[0] == '/') { #endif Tcl_ExternalToUtfDString(NULL, name, -1, &nameString); tclNativeExecutableName = (char *) ckalloc((unsigned) (Tcl_DStringLength(&nameString) + 1)); strcpy(tclNativeExecutableName, Tcl_DStringValue(&nameString)); Tcl_DStringFree(&nameString); goto done; } /* * The name is relative to the current working directory. First * strip off a leading "./", if any, then add the full path name of * the current working directory. */ if ((name[0] == '.') && (name[1] == '/')) { name += 2; } Tcl_ExternalToUtfDString(NULL, name, -1, &nameString); Tcl_DStringFree(&buffer); TclpGetCwd(NULL, &buffer); length = Tcl_DStringLength(&buffer) + Tcl_DStringLength(&nameString) + 2; tclNativeExecutableName = (char *) ckalloc((unsigned) length); strcpy(tclNativeExecutableName, Tcl_DStringValue(&buffer)); tclNativeExecutableName[Tcl_DStringLength(&buffer)] = '/'; strcpy(tclNativeExecutableName + Tcl_DStringLength(&buffer) + 1, Tcl_DStringValue(&nameString)); Tcl_DStringFree(&nameString); done: Tcl_DStringFree(&buffer); #endif return tclNativeExecutableName; } /* *---------------------------------------------------------------------- * * TclpMatchInDirectory -- * * This routine is used by the globbing code to search a * directory for all files which match a given pattern. * * Results: * The return value is a standard Tcl result indicating whether an * error occurred in globbing. Errors are left in interp, good * results are lappended to resultPtr (which must be a valid object) * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclpMatchInDirectory(interp, resultPtr, pathPtr, pattern, types) Tcl_Interp *interp; /* Interpreter to receive errors. */ Tcl_Obj *resultPtr; /* List object to lappend results. */ Tcl_Obj *pathPtr; /* Contains path to directory to search. */ CONST char *pattern; /* Pattern to match against. */ Tcl_GlobTypeData *types; /* Object containing list of acceptable types. * May be NULL. In particular the directory * flag is very important. */ { CONST char *native; Tcl_Obj *fileNamePtr; fileNamePtr = Tcl_FSGetTranslatedPath(interp, pathPtr); if (fileNamePtr == NULL) { return TCL_ERROR; } if (pattern == NULL || (*pattern == '\0')) { /* Match a file directly */ native = (CONST char*) Tcl_FSGetNativePath(pathPtr); if (NativeMatchType(native, types)) { Tcl_ListObjAppendElement(interp, resultPtr, pathPtr); } Tcl_DecrRefCount(fileNamePtr); return TCL_OK; } else { DIR *d; Tcl_DirEntry *entryPtr; CONST char *dirName; int dirLength; int matchHidden; int nativeDirLen; Tcl_StatBuf statBuf; Tcl_DString ds; /* native encoding of dir */ Tcl_DString dsOrig; /* utf-8 encoding of dir */ Tcl_DStringInit(&dsOrig); dirName = Tcl_GetStringFromObj(fileNamePtr, &dirLength); Tcl_DStringAppend(&dsOrig, dirName, dirLength); /* * Make sure that the directory part of the name really is a * directory. If the directory name is "", use the name "." * instead, because some UNIX systems don't treat "" like "." * automatically. Keep the "" for use in generating file names, * otherwise "glob foo.c" would return "./foo.c". */ if (dirLength == 0) { dirName = "."; } else { dirName = Tcl_DStringValue(&dsOrig); /* Make sure we have a trailing directory delimiter */ if (dirName[dirLength-1] != '/') { dirName = Tcl_DStringAppend(&dsOrig, "/", 1); dirLength++; } } Tcl_DecrRefCount(fileNamePtr); /* * Now open the directory for reading and iterate over the contents. */ native = Tcl_UtfToExternalDString(NULL, dirName, -1, &ds); if ((TclOSstat(native, &statBuf) != 0) /* INTL: Native. */ || !S_ISDIR(statBuf.st_mode)) { Tcl_DStringFree(&dsOrig); Tcl_DStringFree(&ds); return TCL_OK; } d = opendir(native); /* INTL: Native. */ if (d == NULL) { Tcl_DStringFree(&ds); Tcl_ResetResult(interp); Tcl_AppendResult(interp, "couldn't read directory \"", Tcl_DStringValue(&dsOrig), "\": ", Tcl_PosixError(interp), (char *) NULL); Tcl_DStringFree(&dsOrig); return TCL_ERROR; } nativeDirLen = Tcl_DStringLength(&ds); /* * Check to see if -type or the pattern requests hidden files. */ matchHidden = ((types && (types->perm & TCL_GLOB_PERM_HIDDEN)) || ((pattern[0] == '.') || ((pattern[0] == '\\') && (pattern[1] == '.')))); while ((entryPtr = TclOSreaddir(d)) != NULL) { /* INTL: Native. */ Tcl_DString utfDs; CONST char *utfname; /* * Skip this file if it doesn't agree with the hidden * parameters requested by the user (via -type or pattern). */ if (*entryPtr->d_name == '.') { if (!matchHidden) continue; } else { if (matchHidden) continue; } /* * Now check to see if the file matches, according to both type * and pattern. If so, add the file to the result. */ utfname = Tcl_ExternalToUtfDString(NULL, entryPtr->d_name, -1, &utfDs); if (Tcl_StringCaseMatch(utfname, pattern, 0)) { int typeOk = 1; if (types != NULL) { Tcl_DStringSetLength(&ds, nativeDirLen); native = Tcl_DStringAppend(&ds, entryPtr->d_name, -1); typeOk = NativeMatchType(native, types); } if (typeOk) { Tcl_ListObjAppendElement(interp, resultPtr, TclNewFSPathObj(pathPtr, utfname, Tcl_DStringLength(&utfDs))); } } Tcl_DStringFree(&utfDs); } closedir(d); Tcl_DStringFree(&ds); Tcl_DStringFree(&dsOrig); return TCL_OK; } } static int NativeMatchType( CONST char* nativeEntry, /* Native path to check */ Tcl_GlobTypeData *types) /* Type description to match against */ { Tcl_StatBuf buf; if (types == NULL) { /* * Simply check for the file's existence, but do it * with lstat, in case it is a link to a file which * doesn't exist (since that case would not show up * if we used 'access' or 'stat') */ if (TclOSlstat(nativeEntry, &buf) != 0) { return 0; } } else { if (types->perm != 0) { if (TclOSstat(nativeEntry, &buf) != 0) { /* * Either the file has disappeared between the * 'readdir' call and the 'stat' call, or * the file is a link to a file which doesn't * exist (which we could ascertain with * lstat), or there is some other strange * problem. In all these cases, we define this * to mean the file does not match any defined * permission, and therefore it is not * added to the list of files to return. */ return 0; } /* * readonly means that there are NO write permissions * (even for user), but execute is OK for anybody */ if (((types->perm & TCL_GLOB_PERM_RONLY) && (buf.st_mode & (S_IWOTH|S_IWGRP|S_IWUSR))) || ((types->perm & TCL_GLOB_PERM_R) && (access(nativeEntry, R_OK) != 0)) || ((types->perm & TCL_GLOB_PERM_W) && (access(nativeEntry, W_OK) != 0)) || ((types->perm & TCL_GLOB_PERM_X) && (access(nativeEntry, X_OK) != 0)) ) { return 0; } } if (types->type != 0) { if (types->perm == 0) { /* We haven't yet done a stat on the file */ if (TclOSstat(nativeEntry, &buf) != 0) { /* * Posix error occurred. The only ok * case is if this is a link to a nonexistent * file, and the user did 'glob -l'. So * we check that here: */ if (types->type & TCL_GLOB_TYPE_LINK) { if (TclOSlstat(nativeEntry, &buf) == 0) { if (S_ISLNK(buf.st_mode)) { return 1; } } } return 0; } } /* * In order bcdpfls as in 'find -t' */ if ( ((types->type & TCL_GLOB_TYPE_BLOCK) && S_ISBLK(buf.st_mode)) || ((types->type & TCL_GLOB_TYPE_CHAR) && S_ISCHR(buf.st_mode)) || ((types->type & TCL_GLOB_TYPE_DIR) && S_ISDIR(buf.st_mode)) || ((types->type & TCL_GLOB_TYPE_PIPE) && S_ISFIFO(buf.st_mode)) || ((types->type & TCL_GLOB_TYPE_FILE) && S_ISREG(buf.st_mode)) #ifdef S_ISSOCK || ((types->type & TCL_GLOB_TYPE_SOCK) && S_ISSOCK(buf.st_mode)) #endif /* S_ISSOCK */ ) { /* Do nothing -- this file is ok */ } else { #ifdef S_ISLNK if (types->type & TCL_GLOB_TYPE_LINK) { if (TclOSlstat(nativeEntry, &buf) == 0) { if (S_ISLNK(buf.st_mode)) { return 1; } } } #endif /* S_ISLNK */ return 0; } } } return 1; } /* *--------------------------------------------------------------------------- * * TclpGetUserHome -- * * This function takes the specified user name and finds their * home directory. * * Results: * The result is a pointer to a string specifying the user's home * directory, or NULL if the user's home directory could not be * determined. Storage for the result string is allocated in * bufferPtr; the caller must call Tcl_DStringFree() when the result * is no longer needed. * * Side effects: * None. * *---------------------------------------------------------------------- */ char * TclpGetUserHome(name, bufferPtr) CONST char *name; /* User name for desired home directory. */ Tcl_DString *bufferPtr; /* Uninitialized or free DString filled * with name of user's home directory. */ { struct passwd *pwPtr; Tcl_DString ds; CONST char *native; native = Tcl_UtfToExternalDString(NULL, name, -1, &ds); pwPtr = getpwnam(native); /* INTL: Native. */ Tcl_DStringFree(&ds); if (pwPtr == NULL) { endpwent(); return NULL; } Tcl_ExternalToUtfDString(NULL, pwPtr->pw_dir, -1, bufferPtr); endpwent(); return Tcl_DStringValue(bufferPtr); } /* *--------------------------------------------------------------------------- * * TclpObjAccess -- * * This function replaces the library version of access(). * * Results: * See access() documentation. * * Side effects: * See access() documentation. * *--------------------------------------------------------------------------- */ int TclpObjAccess(pathPtr, mode) Tcl_Obj *pathPtr; /* Path of file to access */ int mode; /* Permission setting. */ { CONST char *path = Tcl_FSGetNativePath(pathPtr); if (path == NULL) { return -1; } else { return access(path, mode); } } /* *--------------------------------------------------------------------------- * * TclpObjChdir -- * * This function replaces the library version of chdir(). * * Results: * See chdir() documentation. * * Side effects: * See chdir() documentation. * *--------------------------------------------------------------------------- */ int TclpObjChdir(pathPtr) Tcl_Obj *pathPtr; /* Path to new working directory */ { CONST char *path = Tcl_FSGetNativePath(pathPtr); if (path == NULL) { return -1; } else { return chdir(path); } } /* *---------------------------------------------------------------------- * * TclpObjLstat -- * * This function replaces the library version of lstat(). * * Results: * See lstat() documentation. * * Side effects: * See lstat() documentation. * *---------------------------------------------------------------------- */ int TclpObjLstat(pathPtr, bufPtr) Tcl_Obj *pathPtr; /* Path of file to stat */ Tcl_StatBuf *bufPtr; /* Filled with results of stat call. */ { return TclOSlstat(Tcl_FSGetNativePath(pathPtr), bufPtr); } /* *--------------------------------------------------------------------------- * * TclpObjGetCwd -- * * This function replaces the library version of getcwd(). * * Results: * The result is a pointer to a string specifying the current * directory, or NULL if the current directory could not be * determined. If NULL is returned, an error message is left in the * interp's result. Storage for the result string is allocated in * bufferPtr; the caller must call Tcl_DStringFree() when the result * is no longer needed. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_Obj* TclpObjGetCwd(interp) Tcl_Interp *interp; { Tcl_DString ds; if (TclpGetCwd(interp, &ds) != NULL) { Tcl_Obj *cwdPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds), -1); Tcl_IncrRefCount(cwdPtr); Tcl_DStringFree(&ds); return cwdPtr; } else { return NULL; } } /* Older string based version */ CONST char * TclpGetCwd(interp, bufferPtr) Tcl_Interp *interp; /* If non-NULL, used for error reporting. */ Tcl_DString *bufferPtr; /* Uninitialized or free DString filled * with name of current directory. */ { char buffer[MAXPATHLEN+1]; #ifdef USEGETWD if (getwd(buffer) == NULL) { /* INTL: Native. */ #else if (getcwd(buffer, MAXPATHLEN + 1) == NULL) { /* INTL: Native. */ #endif if (interp != NULL) { Tcl_AppendResult(interp, "error getting working directory name: ", Tcl_PosixError(interp), (char *) NULL); } return NULL; } return Tcl_ExternalToUtfDString(NULL, buffer, -1, bufferPtr); } /* *--------------------------------------------------------------------------- * * TclpReadlink -- * * This function replaces the library version of readlink(). * * Results: * The result is a pointer to a string specifying the contents * of the symbolic link given by 'path', or NULL if the symbolic * link could not be read. Storage for the result string is * allocated in bufferPtr; the caller must call Tcl_DStringFree() * when the result is no longer needed. * * Side effects: * See readlink() documentation. * *--------------------------------------------------------------------------- */ char * TclpReadlink(path, linkPtr) CONST char *path; /* Path of file to readlink (UTF-8). */ Tcl_DString *linkPtr; /* Uninitialized or free DString filled * with contents of link (UTF-8). */ { #ifndef DJGPP char link[MAXPATHLEN]; int length; CONST char *native; Tcl_DString ds; native = Tcl_UtfToExternalDString(NULL, path, -1, &ds); length = readlink(native, link, sizeof(link)); /* INTL: Native. */ Tcl_DStringFree(&ds); if (length < 0) { return NULL; } Tcl_ExternalToUtfDString(NULL, link, length, linkPtr); return Tcl_DStringValue(linkPtr); #else return NULL; #endif } /* *---------------------------------------------------------------------- * * TclpObjStat -- * * This function replaces the library version of stat(). * * Results: * See stat() documentation. * * Side effects: * See stat() documentation. * *---------------------------------------------------------------------- */ int TclpObjStat(pathPtr, bufPtr) Tcl_Obj *pathPtr; /* Path of file to stat */ Tcl_StatBuf *bufPtr; /* Filled with results of stat call. */ { CONST char *path = Tcl_FSGetNativePath(pathPtr); if (path == NULL) { return -1; } else { return TclOSstat(path, bufPtr); } } #ifdef S_IFLNK Tcl_Obj* TclpObjLink(pathPtr, toPtr, linkAction) Tcl_Obj *pathPtr; Tcl_Obj *toPtr; int linkAction; { if (toPtr != NULL) { CONST char *src = Tcl_FSGetNativePath(pathPtr); CONST char *target = Tcl_FSGetNativePath(toPtr); if (src == NULL || target == NULL) { return NULL; } if (access(src, F_OK) != -1) { /* src exists */ errno = EEXIST; return NULL; } if (access(target, F_OK) == -1) { /* target doesn't exist */ errno = ENOENT; return NULL; } /* * Check symbolic link flag first, since we prefer to * create these. */ if (linkAction & TCL_CREATE_SYMBOLIC_LINK) { if (symlink(target, src) != 0) return NULL; } else if (linkAction & TCL_CREATE_HARD_LINK) { if (link(target, src) != 0) return NULL; } else { errno = ENODEV; return NULL; } return toPtr; } else { Tcl_Obj* linkPtr = NULL; char link[MAXPATHLEN]; int length; Tcl_DString ds; Tcl_Obj *transPtr; transPtr = Tcl_FSGetTranslatedPath(NULL, pathPtr); if (transPtr == NULL) { return NULL; } Tcl_DecrRefCount(transPtr); length = readlink(Tcl_FSGetNativePath(pathPtr), link, sizeof(link)); if (length < 0) { return NULL; } Tcl_ExternalToUtfDString(NULL, link, length, &ds); linkPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds), Tcl_DStringLength(&ds)); Tcl_DStringFree(&ds); if (linkPtr != NULL) { Tcl_IncrRefCount(linkPtr); } return linkPtr; } } #endif /* *--------------------------------------------------------------------------- * * TclpFilesystemPathType -- * * This function is part of the native filesystem support, and * returns the path type of the given path. Right now it simply * returns NULL. In the future it could return specific path * types, like 'nfs', 'samba', 'FAT32', etc. * * Results: * NULL at present. * * Side effects: * None. * *--------------------------------------------------------------------------- */ Tcl_Obj* TclpFilesystemPathType(pathObjPtr) Tcl_Obj* pathObjPtr; { /* All native paths are of the same type */ return NULL; } /* *--------------------------------------------------------------------------- * * TclpUtime -- * * Set the modification date for a file. * * Results: * 0 on success, -1 on error. * * Side effects: * None. * *--------------------------------------------------------------------------- */ int TclpUtime(pathPtr, tval) Tcl_Obj *pathPtr; /* File to modify */ struct utimbuf *tval; /* New modification date structure */ { return utime(Tcl_FSGetNativePath(pathPtr),tval); } #ifdef __CYGWIN__ int TclOSstat(const char *name, Tcl_StatBuf *statBuf) { struct stat buf; int result = stat(name, &buf); statBuf->st_mode = buf.st_mode; statBuf->st_ino = buf.st_ino; statBuf->st_dev = buf.st_dev; statBuf->st_rdev = buf.st_rdev; statBuf->st_nlink = buf.st_nlink; statBuf->st_uid = buf.st_uid; statBuf->st_gid = buf.st_gid; statBuf->st_size = buf.st_size; statBuf->st_atime = buf.st_atime; statBuf->st_mtime = buf.st_mtime; statBuf->st_ctime = buf.st_ctime; return result; } int TclOSlstat(const char *name, Tcl_StatBuf *statBuf) { struct stat buf; int result = lstat(name, &buf); statBuf->st_mode = buf.st_mode; statBuf->st_ino = buf.st_ino; statBuf->st_dev = buf.st_dev; statBuf->st_rdev = buf.st_rdev; statBuf->st_nlink = buf.st_nlink; statBuf->st_uid = buf.st_uid; statBuf->st_gid = buf.st_gid; statBuf->st_size = buf.st_size; statBuf->st_atime = buf.st_atime; statBuf->st_mtime = buf.st_mtime; statBuf->st_ctime = buf.st_ctime; return result; } #endif /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ tcl8.4.20/unix/tclXtNotify.c0000644003604700454610000004122211737050675014337 0ustar dgp771div/* * tclXtNotify.c -- * * This file contains the notifier driver implementation for the * Xt intrinsics. * * Copyright (c) 1997 by Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include #include /* * This structure is used to keep track of the notifier info for a * a registered file. */ typedef struct FileHandler { int fd; int mask; /* Mask of desired events: TCL_READABLE, etc. */ int readyMask; /* Events that have been seen since the last time FileHandlerEventProc was called for this file. */ XtInputId read; /* Xt read callback handle. */ XtInputId write; /* Xt write callback handle. */ XtInputId except; /* Xt exception callback handle. */ Tcl_FileProc *proc; /* Procedure to call, in the style of * Tcl_CreateFileHandler. */ ClientData clientData; /* Argument to pass to proc. */ struct FileHandler *nextPtr;/* Next in list of all files we care about. */ } FileHandler; /* * The following structure is what is added to the Tcl event queue when * file handlers are ready to fire. */ typedef struct FileHandlerEvent { Tcl_Event header; /* Information that is standard for * all events. */ int fd; /* File descriptor that is ready. Used * to find the FileHandler structure for * the file (can't point directly to the * FileHandler structure because it could * go away while the event is queued). */ } FileHandlerEvent; /* * The following static structure contains the state information for the * Xt based implementation of the Tcl notifier. */ static struct NotifierState { XtAppContext appContext; /* The context used by the Xt * notifier. Can be set with * TclSetAppContext. */ int appContextCreated; /* Was it created by us? */ XtIntervalId currentTimeout; /* Handle of current timer. */ FileHandler *firstFileHandlerPtr; /* Pointer to head of file handler * list. */ } notifier; /* * The following static indicates whether this module has been initialized. */ static int initialized = 0; /* * Static routines defined in this file. */ static int FileHandlerEventProc _ANSI_ARGS_((Tcl_Event *evPtr, int flags)); static void FileProc _ANSI_ARGS_((caddr_t clientData, int *source, XtInputId *id)); void InitNotifier _ANSI_ARGS_((void)); static void NotifierExitHandler _ANSI_ARGS_(( ClientData clientData)); static void TimerProc _ANSI_ARGS_((caddr_t clientData, XtIntervalId *id)); static void CreateFileHandler _ANSI_ARGS_((int fd, int mask, Tcl_FileProc * proc, ClientData clientData)); static void DeleteFileHandler _ANSI_ARGS_((int fd)); static void SetTimer _ANSI_ARGS_((Tcl_Time * timePtr)); static int WaitForEvent _ANSI_ARGS_((Tcl_Time * timePtr)); /* * Functions defined in this file for use by users of the Xt Notifier: */ EXTERN XtAppContext TclSetAppContext _ANSI_ARGS_((XtAppContext ctx)); /* *---------------------------------------------------------------------- * * TclSetAppContext -- * * Set the notifier application context. * * Results: * None. * * Side effects: * Sets the application context used by the notifier. Panics if * the context is already set when called. * *---------------------------------------------------------------------- */ XtAppContext TclSetAppContext(appContext) XtAppContext appContext; { if (!initialized) { InitNotifier(); } /* * If we already have a context we check whether we were asked to set a * new context. If so, we panic because we try to prevent switching * contexts by mistake. Otherwise, we return the one we have. */ if (notifier.appContext != NULL) { if (appContext != NULL) { /* * We already have a context. We do not allow switching contexts * after initialization, so we panic. */ panic("TclSetAppContext: multiple application contexts"); } } else { /* * If we get here we have not yet gotten a context, so either create * one or use the one supplied by our caller. */ if (appContext == NULL) { /* * We must create a new context and tell our caller what it is, so * she can use it too. */ notifier.appContext = XtCreateApplicationContext(); notifier.appContextCreated = 1; } else { /* * Otherwise we remember the context that our caller gave us * and use it. */ notifier.appContextCreated = 0; notifier.appContext = appContext; } } return notifier.appContext; } /* *---------------------------------------------------------------------- * * InitNotifier -- * * Initializes the notifier state. * * Results: * None. * * Side effects: * Creates a new exit handler. * *---------------------------------------------------------------------- */ void InitNotifier() { Tcl_NotifierProcs notifier; /* * Only reinitialize if we are not in exit handling. The notifier * can get reinitialized after its own exit handler has run, because * of exit handlers for the I/O and timer sub-systems (order dependency). */ if (TclInExit()) { return; } notifier.createFileHandlerProc = CreateFileHandler; notifier.deleteFileHandlerProc = DeleteFileHandler; notifier.setTimerProc = SetTimer; notifier.waitForEventProc = WaitForEvent; Tcl_SetNotifier(¬ifier); /* * DO NOT create the application context yet; doing so would prevent * external applications from setting it for us to their own ones. */ initialized = 1; memset(¬ifier, 0, sizeof(notifier)); Tcl_CreateExitHandler(NotifierExitHandler, NULL); } /* *---------------------------------------------------------------------- * * NotifierExitHandler -- * * This function is called to cleanup the notifier state before * Tcl is unloaded. * * Results: * None. * * Side effects: * Destroys the notifier window. * *---------------------------------------------------------------------- */ static void NotifierExitHandler( ClientData clientData) /* Not used. */ { if (notifier.currentTimeout != 0) { XtRemoveTimeOut(notifier.currentTimeout); } for (; notifier.firstFileHandlerPtr != NULL; ) { Tcl_DeleteFileHandler(notifier.firstFileHandlerPtr->fd); } if (notifier.appContextCreated) { XtDestroyApplicationContext(notifier.appContext); notifier.appContextCreated = 0; notifier.appContext = NULL; } initialized = 0; } /* *---------------------------------------------------------------------- * * SetTimer -- * * This procedure sets the current notifier timeout value. * * Results: * None. * * Side effects: * Replaces any previous timer. * *---------------------------------------------------------------------- */ static void SetTimer(timePtr) Tcl_Time *timePtr; /* Timeout value, may be NULL. */ { long timeout; if (!initialized) { InitNotifier(); } TclSetAppContext(NULL); if (notifier.currentTimeout != 0) { XtRemoveTimeOut(notifier.currentTimeout); } if (timePtr) { timeout = timePtr->sec * 1000 + timePtr->usec / 1000; notifier.currentTimeout = XtAppAddTimeOut(notifier.appContext, (unsigned long) timeout, TimerProc, NULL); } else { notifier.currentTimeout = 0; } } /* *---------------------------------------------------------------------- * * TimerProc -- * * This procedure is the XtTimerCallbackProc used to handle * timeouts. * * Results: * None. * * Side effects: * Processes all queued events. * *---------------------------------------------------------------------- */ static void TimerProc(data, id) caddr_t data; /* Not used. */ XtIntervalId *id; { if (*id != notifier.currentTimeout) { return; } notifier.currentTimeout = 0; Tcl_ServiceAll(); } /* *---------------------------------------------------------------------- * * CreateFileHandler -- * * This procedure registers a file handler with the Xt notifier. * * Results: * None. * * Side effects: * Creates a new file handler structure and registers one or more * input procedures with Xt. * *---------------------------------------------------------------------- */ static void CreateFileHandler(fd, mask, proc, clientData) int fd; /* Handle of stream to watch. */ int mask; /* OR'ed combination of TCL_READABLE, * TCL_WRITABLE, and TCL_EXCEPTION: * indicates conditions under which * proc should be called. */ Tcl_FileProc *proc; /* Procedure to call for each * selected event. */ ClientData clientData; /* Arbitrary data to pass to proc. */ { FileHandler *filePtr; if (!initialized) { InitNotifier(); } TclSetAppContext(NULL); for (filePtr = notifier.firstFileHandlerPtr; filePtr != NULL; filePtr = filePtr->nextPtr) { if (filePtr->fd == fd) { break; } } if (filePtr == NULL) { filePtr = (FileHandler*) ckalloc(sizeof(FileHandler)); filePtr->fd = fd; filePtr->read = 0; filePtr->write = 0; filePtr->except = 0; filePtr->readyMask = 0; filePtr->mask = 0; filePtr->nextPtr = notifier.firstFileHandlerPtr; notifier.firstFileHandlerPtr = filePtr; } filePtr->proc = proc; filePtr->clientData = clientData; /* * Register the file with the Xt notifier, if it hasn't been done yet. */ if (mask & TCL_READABLE) { if (!(filePtr->mask & TCL_READABLE)) { filePtr->read = XtAppAddInput(notifier.appContext, fd, XtInputReadMask, FileProc, filePtr); } } else { if (filePtr->mask & TCL_READABLE) { XtRemoveInput(filePtr->read); } } if (mask & TCL_WRITABLE) { if (!(filePtr->mask & TCL_WRITABLE)) { filePtr->write = XtAppAddInput(notifier.appContext, fd, XtInputWriteMask, FileProc, filePtr); } } else { if (filePtr->mask & TCL_WRITABLE) { XtRemoveInput(filePtr->write); } } if (mask & TCL_EXCEPTION) { if (!(filePtr->mask & TCL_EXCEPTION)) { filePtr->except = XtAppAddInput(notifier.appContext, fd, XtInputExceptMask, FileProc, filePtr); } } else { if (filePtr->mask & TCL_EXCEPTION) { XtRemoveInput(filePtr->except); } } filePtr->mask = mask; } /* *---------------------------------------------------------------------- * * DeleteFileHandler -- * * Cancel a previously-arranged callback arrangement for * a file. * * Results: * None. * * Side effects: * If a callback was previously registered on file, remove it. * *---------------------------------------------------------------------- */ static void DeleteFileHandler(fd) int fd; /* Stream id for which to remove * callback procedure. */ { FileHandler *filePtr, *prevPtr; if (!initialized) { InitNotifier(); } TclSetAppContext(NULL); /* * Find the entry for the given file (and return if there * isn't one). */ for (prevPtr = NULL, filePtr = notifier.firstFileHandlerPtr; ; prevPtr = filePtr, filePtr = filePtr->nextPtr) { if (filePtr == NULL) { return; } if (filePtr->fd == fd) { break; } } /* * Clean up information in the callback record. */ if (prevPtr == NULL) { notifier.firstFileHandlerPtr = filePtr->nextPtr; } else { prevPtr->nextPtr = filePtr->nextPtr; } if (filePtr->mask & TCL_READABLE) { XtRemoveInput(filePtr->read); } if (filePtr->mask & TCL_WRITABLE) { XtRemoveInput(filePtr->write); } if (filePtr->mask & TCL_EXCEPTION) { XtRemoveInput(filePtr->except); } ckfree((char *) filePtr); } /* *---------------------------------------------------------------------- * * FileProc -- * * These procedures are called by Xt when a file becomes readable, * writable, or has an exception. * * Results: * None. * * Side effects: * Makes an entry on the Tcl event queue if the event is * interesting. * *---------------------------------------------------------------------- */ static void FileProc(clientData, fd, id) caddr_t clientData; int *fd; XtInputId *id; { FileHandler *filePtr = (FileHandler *)clientData; FileHandlerEvent *fileEvPtr; int mask = 0; /* * Determine which event happened. */ if (*id == filePtr->read) { mask = TCL_READABLE; } else if (*id == filePtr->write) { mask = TCL_WRITABLE; } else if (*id == filePtr->except) { mask = TCL_EXCEPTION; } /* * Ignore unwanted or duplicate events. */ if (!(filePtr->mask & mask) || (filePtr->readyMask & mask)) { return; } /* * This is an interesting event, so put it onto the event queue. */ filePtr->readyMask |= mask; fileEvPtr = (FileHandlerEvent *) ckalloc(sizeof(FileHandlerEvent)); fileEvPtr->header.proc = FileHandlerEventProc; fileEvPtr->fd = filePtr->fd; Tcl_QueueEvent((Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL); /* * Process events on the Tcl event queue before returning to Xt. */ Tcl_ServiceAll(); } /* *---------------------------------------------------------------------- * * FileHandlerEventProc -- * * This procedure is called by Tcl_ServiceEvent when a file event * reaches the front of the event queue. This procedure is * responsible for actually handling the event by invoking the * callback for the file handler. * * Results: * Returns 1 if the event was handled, meaning it should be removed * from the queue. Returns 0 if the event was not handled, meaning * it should stay on the queue. The only time the event isn't * handled is if the TCL_FILE_EVENTS flag bit isn't set. * * Side effects: * Whatever the file handler's callback procedure does. * *---------------------------------------------------------------------- */ static int FileHandlerEventProc(evPtr, flags) Tcl_Event *evPtr; /* Event to service. */ int flags; /* Flags that indicate what events to * handle, such as TCL_FILE_EVENTS. */ { FileHandler *filePtr; FileHandlerEvent *fileEvPtr = (FileHandlerEvent *) evPtr; int mask; if (!(flags & TCL_FILE_EVENTS)) { return 0; } /* * Search through the file handlers to find the one whose handle matches * the event. We do this rather than keeping a pointer to the file * handler directly in the event, so that the handler can be deleted * while the event is queued without leaving a dangling pointer. */ for (filePtr = notifier.firstFileHandlerPtr; filePtr != NULL; filePtr = filePtr->nextPtr) { if (filePtr->fd != fileEvPtr->fd) { continue; } /* * The code is tricky for two reasons: * 1. The file handler's desired events could have changed * since the time when the event was queued, so AND the * ready mask with the desired mask. * 2. The file could have been closed and re-opened since * the time when the event was queued. This is why the * ready mask is stored in the file handler rather than * the queued event: it will be zeroed when a new * file handler is created for the newly opened file. */ mask = filePtr->readyMask & filePtr->mask; filePtr->readyMask = 0; if (mask != 0) { (*filePtr->proc)(filePtr->clientData, mask); } break; } return 1; } /* *---------------------------------------------------------------------- * * WaitForEvent -- * * This function is called by Tcl_DoOneEvent to wait for new * events on the message queue. If the block time is 0, then * Tcl_WaitForEvent just polls without blocking. * * Results: * Returns 1 if an event was found, else 0. This ensures that * Tcl_DoOneEvent will return 1, even if the event is handled * by non-Tcl code. * * Side effects: * Queues file events that are detected by the select. * *---------------------------------------------------------------------- */ static int WaitForEvent( Tcl_Time *timePtr) /* Maximum block time, or NULL. */ { int timeout; if (!initialized) { InitNotifier(); } TclSetAppContext(NULL); if (timePtr) { timeout = timePtr->sec * 1000 + timePtr->usec / 1000; if (timeout == 0) { if (XtAppPending(notifier.appContext)) { goto process; } else { return 0; } } else { Tcl_SetTimer(timePtr); } } process: XtAppProcessEvent(notifier.appContext, XtIMAll); return 1; } tcl8.4.20/unix/tclXtTest.c0000644003604700454610000000607311737050675014013 0ustar dgp771div/* * tclXtTest.c -- * * Contains commands for Xt notifier specific tests on Unix. * * Copyright (c) 1997 by Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include #include "tcl.h" static int TesteventloopCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int argc, CONST char **argv)); extern void InitNotifier _ANSI_ARGS_((void)); /* *---------------------------------------------------------------------- * * Tclxttest_Init -- * * This procedure performs application-specific initialization. * Most applications, especially those that incorporate additional * packages, will have their own version of this procedure. * * Results: * Returns a standard Tcl completion code, and leaves an error * message in the interp's result if an error occurs. * * Side effects: * Depends on the startup script. * *---------------------------------------------------------------------- */ int Tclxttest_Init(interp) Tcl_Interp *interp; /* Interpreter for application. */ { if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL) { return TCL_ERROR; } XtToolkitInitialize(); InitNotifier(); Tcl_CreateCommand(interp, "testeventloop", TesteventloopCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); return TCL_OK; } /* *---------------------------------------------------------------------- * * TesteventloopCmd -- * * This procedure implements the "testeventloop" command. It is * used to test the Tcl notifier from an "external" event loop * (i.e. not Tcl_DoOneEvent()). * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TesteventloopCmd(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST char **argv; /* Argument strings. */ { static int *framePtr = NULL; /* Pointer to integer on stack frame of * innermost invocation of the "wait" * subcommand. */ if (argc < 2) { Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0], " option ... \"", (char *) NULL); return TCL_ERROR; } if (strcmp(argv[1], "done") == 0) { *framePtr = 1; } else if (strcmp(argv[1], "wait") == 0) { int *oldFramePtr; int done; int oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL); /* * Save the old stack frame pointer and set up the current frame. */ oldFramePtr = framePtr; framePtr = &done; /* * Enter an Xt event loop until the flag changes. * Note that we do not explicitly call Tcl_ServiceEvent(). */ done = 0; while (!done) { XtAppProcessEvent(TclSetAppContext(NULL), XtIMAll); } (void) Tcl_SetServiceMode(oldMode); framePtr = oldFramePtr; } else { Tcl_AppendResult(interp, "bad option \"", argv[1], "\": must be done or wait", (char *) NULL); return TCL_ERROR; } return TCL_OK; } tcl8.4.20/unix/ldAix0000775003604700454610000000535112153151142012660 0ustar dgp771div#!/bin/sh # # ldAix ldCmd ldArg ldArg ... # # This shell script provides a wrapper for ld under AIX in order to # create the .exp file required for linking. Its arguments consist # of the name and arguments that would normally be provided to the # ld command. This script extracts the names of the object files # from the argument list, creates a .exp file describing all of the # symbols exported by those files, and then invokes "ldCmd" to # perform the real link. # Extract from the arguments the names of all of the object files. args=$* ofiles="" for i do x=`echo $i | grep '[^.].o$'` if test "$x" != ""; then ofiles="$ofiles $i" fi done # Extract the name of the object file that we're linking. outputFile=`echo $args | sed -e 's/.*-o \([^ ]*\).*/\1/'` # Create the export file from all of the object files, using nm followed # by sed editing. Here are some tricky aspects of this: # # 1. Nm produces different output under AIX 4.1 than under AIX 3.2.5; # the following statements handle both versions. # 2. Use the -g switch to nm instead of -e under 4.1 (this shows just # externals, not statics; -g isn't available under 3.2.5, though). # 3. Use the -X32_64 switch to nm on AIX-4+ to handle 32 or 64bit compiles. # 4. Eliminate lines that end in ":": these are the names of object # files (relevant in 4.1 only). # 5. Eliminate entries with the "U" key letter; these are undefined # symbols (relevant in 4.1 only). # 6. Eliminate lines that contain the string "0|extern" preceded by space; # in 3.2.5, these are undefined symbols (address 0). # 7. Eliminate lines containing the "unamex" symbol. In 3.2.5, these # are also undefined symbols. # 8. If a line starts with ".", delete the leading ".", since this will # just cause confusion later. # 9. Eliminate everything after the first field in a line, so that we're # left with just the symbol name. nmopts="-g -C" osver=`uname -v` if test $osver -eq 3; then nmopts="-e" fi if test $osver -gt 3; then nmopts="$nmopts -X32_64" fi rm -f lib.exp echo "#! $outputFile" >lib.exp /usr/ccs/bin/nm $nmopts -h $ofiles | sed -e '/:$/d' -e '/ U /d' -e '/[ ]0|extern/d' -e '/unamex/d' -e 's/^\.//' -e 's/[ |].*//' | sort | uniq >>lib.exp # If we're linking a .a file, then link all the objects together into a # single file "shr.o" and then put that into the archive. Otherwise link # the object files directly into the .a file. outputFile=`echo $args | sed -e 's/.*-o \([^ ]*\).*/\1/'` noDotA=`echo $outputFile | sed -e '/\.a$/d'` echo "noDotA=\"$noDotA\"" if test "$noDotA" = "" ; then linkArgs=`echo $args | sed -e 's/-o .*\.a /-o shr.o /'` echo $linkArgs eval $linkArgs echo ar cr $outputFile shr.o ar cr $outputFile shr.o rm -f shr.o else eval $args fi tcl8.4.20/unix/tclUnixThrd.c0000644003604700454610000005252511737050675014330 0ustar dgp771div/* * tclUnixThrd.c -- * * This file implements the UNIX-specific thread support. * * Copyright (c) 1991-1994 The Regents of the University of California. * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" #ifdef TCL_THREADS #include "pthread.h" typedef struct ThreadSpecificData { char nabuf[16]; } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; /* * masterLock is used to serialize creation of mutexes, condition * variables, and thread local storage. * This is the only place that can count on the ability to statically * initialize the mutex. */ static pthread_mutex_t masterLock = PTHREAD_MUTEX_INITIALIZER; /* * initLock is used to serialize initialization and finalization * of Tcl. It cannot use any dyamically allocated storage. */ static pthread_mutex_t initLock = PTHREAD_MUTEX_INITIALIZER; /* * allocLock is used by Tcl's version of malloc for synchronization. * For obvious reasons, cannot use any dyamically allocated storage. */ static pthread_mutex_t allocLock = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t *allocLockPtr = &allocLock; /* * These are for the critical sections inside this file. */ #define MASTER_LOCK pthread_mutex_lock(&masterLock) #define MASTER_UNLOCK pthread_mutex_unlock(&masterLock) #endif /* TCL_THREADS */ /* *---------------------------------------------------------------------- * * TclpThreadCreate -- * * This procedure creates a new thread. * * Results: * TCL_OK if the thread could be created. The thread ID is * returned in a parameter. * * Side effects: * A new thread is created. * *---------------------------------------------------------------------- */ int TclpThreadCreate(idPtr, proc, clientData, stackSize, flags) Tcl_ThreadId *idPtr; /* Return, the ID of the thread */ Tcl_ThreadCreateProc proc; /* Main() function of the thread */ ClientData clientData; /* The one argument to Main() */ int stackSize; /* Size of stack for the new thread */ int flags; /* Flags controlling behaviour of * the new thread */ { #ifdef TCL_THREADS pthread_attr_t attr; pthread_t theThread; int result; pthread_attr_init(&attr); pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); #ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE if (stackSize != TCL_THREAD_STACK_DEFAULT) { pthread_attr_setstacksize(&attr, (size_t) stackSize); #ifdef TCL_THREAD_STACK_MIN } else { /* * Certain systems define a thread stack size that by default is * too small for many operations. The user has the option of * defining TCL_THREAD_STACK_MIN to a value large enough to work * for their needs. This would look like (for 128K min stack): * make MEM_DEBUG_FLAGS=-DTCL_THREAD_STACK_MIN=131072L * * This solution is not optimal, as we should allow the user to * specify a size at runtime, but we don't want to slow this function * down, and that would still leave the main thread at the default. */ size_t size; result = pthread_attr_getstacksize(&attr, &size); if (!result && (size < TCL_THREAD_STACK_MIN)) { pthread_attr_setstacksize(&attr, (size_t) TCL_THREAD_STACK_MIN); } #endif } #endif if (! (flags & TCL_THREAD_JOINABLE)) { pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); } if (pthread_create(&theThread, &attr, (void * (*)())proc, (void *)clientData) && pthread_create(&theThread, NULL, (void * (*)())proc, (void *)clientData)) { result = TCL_ERROR; } else { *idPtr = (Tcl_ThreadId)theThread; result = TCL_OK; } pthread_attr_destroy(&attr); return result; #else return TCL_ERROR; #endif /* TCL_THREADS */ } /* *---------------------------------------------------------------------- * * Tcl_JoinThread -- * * This procedure waits upon the exit of the specified thread. * * Results: * TCL_OK if the wait was successful, TCL_ERROR else. * * Side effects: * The result area is set to the exit code of the thread we * waited upon. * *---------------------------------------------------------------------- */ int Tcl_JoinThread(threadId, state) Tcl_ThreadId threadId; /* Id of the thread to wait upon */ int* state; /* Reference to the storage the result * of the thread we wait upon will be * written into. */ { #ifdef TCL_THREADS int result; unsigned long retcode; result = pthread_join((pthread_t) threadId, (void**) &retcode); if (state) { *state = (int) retcode; } return (result == 0) ? TCL_OK : TCL_ERROR; #else return TCL_ERROR; #endif } #ifdef TCL_THREADS /* *---------------------------------------------------------------------- * * TclpThreadExit -- * * This procedure terminates the current thread. * * Results: * None. * * Side effects: * This procedure terminates the current thread. * *---------------------------------------------------------------------- */ void TclpThreadExit(status) int status; { pthread_exit((VOID *)status); } #endif /* TCL_THREADS */ /* *---------------------------------------------------------------------- * * Tcl_GetCurrentThread -- * * This procedure returns the ID of the currently running thread. * * Results: * A thread ID. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_ThreadId Tcl_GetCurrentThread() { #ifdef TCL_THREADS return (Tcl_ThreadId) pthread_self(); #else return (Tcl_ThreadId) 0; #endif } /* *---------------------------------------------------------------------- * * TclpInitLock * * This procedure is used to grab a lock that serializes initialization * and finalization of Tcl. On some platforms this may also initialize * the mutex used to serialize creation of more mutexes and thread * local storage keys. * * Results: * None. * * Side effects: * Acquire the initialization mutex. * *---------------------------------------------------------------------- */ void TclpInitLock() { #ifdef TCL_THREADS pthread_mutex_lock(&initLock); #endif } /* *---------------------------------------------------------------------- * * TclpFinalizeLock * * This procedure is used to destroy all private resources used in * this file. * * Results: * None. * * Side effects: * Destroys everything private. TclpInitLock must be held * entering this function. * *---------------------------------------------------------------------- */ void TclFinalizeLock () { #ifdef TCL_THREADS /* * You do not need to destroy mutexes that were created with the * PTHREAD_MUTEX_INITIALIZER macro. These mutexes do not need * any destruction: masterLock, allocLock, and initLock. */ pthread_mutex_unlock(&initLock); #endif } /* *---------------------------------------------------------------------- * * TclpInitUnlock * * This procedure is used to release a lock that serializes initialization * and finalization of Tcl. * * Results: * None. * * Side effects: * Release the initialization mutex. * *---------------------------------------------------------------------- */ void TclpInitUnlock() { #ifdef TCL_THREADS pthread_mutex_unlock(&initLock); #endif } /* *---------------------------------------------------------------------- * * TclpMasterLock * * This procedure is used to grab a lock that serializes creation * and finalization of serialization objects. This interface is * only needed in finalization; it is hidden during * creation of the objects. * * This lock must be different than the initLock because the * initLock is held during creation of syncronization objects. * * Results: * None. * * Side effects: * Acquire the master mutex. * *---------------------------------------------------------------------- */ void TclpMasterLock() { #ifdef TCL_THREADS pthread_mutex_lock(&masterLock); #endif } /* *---------------------------------------------------------------------- * * TclpMasterUnlock * * This procedure is used to release a lock that serializes creation * and finalization of synchronization objects. * * Results: * None. * * Side effects: * Release the master mutex. * *---------------------------------------------------------------------- */ void TclpMasterUnlock() { #ifdef TCL_THREADS pthread_mutex_unlock(&masterLock); #endif } /* *---------------------------------------------------------------------- * * Tcl_GetAllocMutex * * This procedure returns a pointer to a statically initialized * mutex for use by the memory allocator. The alloctor must * use this lock, because all other locks are allocated... * * Results: * A pointer to a mutex that is suitable for passing to * Tcl_MutexLock and Tcl_MutexUnlock. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_Mutex * Tcl_GetAllocMutex() { #ifdef TCL_THREADS return (Tcl_Mutex *)&allocLockPtr; #else return NULL; #endif } #ifdef TCL_THREADS /* *---------------------------------------------------------------------- * * Tcl_MutexLock -- * * This procedure is invoked to lock a mutex. This procedure * handles initializing the mutex, if necessary. The caller * can rely on the fact that Tcl_Mutex is an opaque pointer. * This routine will change that pointer from NULL after first use. * * Results: * None. * * Side effects: * May block the current thread. The mutex is aquired when * this returns. Will allocate memory for a pthread_mutex_t * and initialize this the first time this Tcl_Mutex is used. * *---------------------------------------------------------------------- */ void Tcl_MutexLock(mutexPtr) Tcl_Mutex *mutexPtr; /* Really (pthread_mutex_t **) */ { pthread_mutex_t *pmutexPtr; if (*mutexPtr == NULL) { MASTER_LOCK; if (*mutexPtr == NULL) { /* * Double inside master lock check to avoid a race condition. */ pmutexPtr = (pthread_mutex_t *)ckalloc(sizeof(pthread_mutex_t)); pthread_mutex_init(pmutexPtr, NULL); *mutexPtr = (Tcl_Mutex)pmutexPtr; TclRememberMutex(mutexPtr); } MASTER_UNLOCK; } pmutexPtr = *((pthread_mutex_t **)mutexPtr); pthread_mutex_lock(pmutexPtr); } /* *---------------------------------------------------------------------- * * Tcl_MutexUnlock -- * * This procedure is invoked to unlock a mutex. The mutex must * have been locked by Tcl_MutexLock. * * Results: * None. * * Side effects: * The mutex is released when this returns. * *---------------------------------------------------------------------- */ void Tcl_MutexUnlock(mutexPtr) Tcl_Mutex *mutexPtr; /* Really (pthread_mutex_t **) */ { pthread_mutex_t *pmutexPtr = *(pthread_mutex_t **)mutexPtr; pthread_mutex_unlock(pmutexPtr); } /* *---------------------------------------------------------------------- * * TclpFinalizeMutex -- * * This procedure is invoked to clean up one mutex. This is only * safe to call at the end of time. * * This assumes the Master Lock is held. * * Results: * None. * * Side effects: * The mutex list is deallocated. * *---------------------------------------------------------------------- */ void TclpFinalizeMutex(mutexPtr) Tcl_Mutex *mutexPtr; { pthread_mutex_t *pmutexPtr = *(pthread_mutex_t **)mutexPtr; if (pmutexPtr != NULL) { pthread_mutex_destroy(pmutexPtr); ckfree((char *)pmutexPtr); *mutexPtr = NULL; } } /* *---------------------------------------------------------------------- * * TclpThreadDataKeyInit -- * * This procedure initializes a thread specific data block key. * Each thread has table of pointers to thread specific data. * all threads agree on which table entry is used by each module. * this is remembered in a "data key", that is just an index into * this table. To allow self initialization, the interface * passes a pointer to this key and the first thread to use * the key fills in the pointer to the key. The key should be * a process-wide static. * * Results: * None. * * Side effects: * Will allocate memory the first time this process calls for * this key. In this case it modifies its argument * to hold the pointer to information about the key. * *---------------------------------------------------------------------- */ void TclpThreadDataKeyInit(keyPtr) Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk, * really (pthread_key_t **) */ { pthread_key_t *pkeyPtr; MASTER_LOCK; if (*keyPtr == NULL) { pkeyPtr = (pthread_key_t *)ckalloc(sizeof(pthread_key_t)); pthread_key_create(pkeyPtr, NULL); *keyPtr = (Tcl_ThreadDataKey)pkeyPtr; TclRememberDataKey(keyPtr); } MASTER_UNLOCK; } /* *---------------------------------------------------------------------- * * TclpThreadDataKeyGet -- * * This procedure returns a pointer to a block of thread local storage. * * Results: * A thread-specific pointer to the data structure, or NULL * if the memory has not been assigned to this key for this thread. * * Side effects: * None. * *---------------------------------------------------------------------- */ VOID * TclpThreadDataKeyGet(keyPtr) Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk, * really (pthread_key_t **) */ { pthread_key_t *pkeyPtr = *(pthread_key_t **)keyPtr; if (pkeyPtr == NULL) { return NULL; } else { return (VOID *)pthread_getspecific(*pkeyPtr); } } /* *---------------------------------------------------------------------- * * TclpThreadDataKeySet -- * * This procedure sets the pointer to a block of thread local storage. * * Results: * None. * * Side effects: * Sets up the thread so future calls to TclpThreadDataKeyGet with * this key will return the data pointer. * *---------------------------------------------------------------------- */ void TclpThreadDataKeySet(keyPtr, data) Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk, * really (pthread_key_t **) */ VOID *data; /* Thread local storage */ { pthread_key_t *pkeyPtr = *(pthread_key_t **)keyPtr; pthread_setspecific(*pkeyPtr, data); } /* *---------------------------------------------------------------------- * * TclpFinalizeThreadData -- * * This procedure cleans up the thread-local storage. This is * called once for each thread. * * Results: * None. * * Side effects: * Frees up all thread local storage. * *---------------------------------------------------------------------- */ void TclpFinalizeThreadData(keyPtr) Tcl_ThreadDataKey *keyPtr; { VOID *result; pthread_key_t *pkeyPtr; if (*keyPtr != NULL) { pkeyPtr = *(pthread_key_t **)keyPtr; result = (VOID *)pthread_getspecific(*pkeyPtr); if (result != NULL) { ckfree((char *)result); pthread_setspecific(*pkeyPtr, (void *)NULL); } } } /* *---------------------------------------------------------------------- * * TclpFinalizeThreadDataKey -- * * This procedure is invoked to clean up one key. This is a * process-wide storage identifier. The thread finalization code * cleans up the thread local storage itself. * * This assumes the master lock is held. * * Results: * None. * * Side effects: * The key is deallocated. * *---------------------------------------------------------------------- */ void TclpFinalizeThreadDataKey(keyPtr) Tcl_ThreadDataKey *keyPtr; { pthread_key_t *pkeyPtr; if (*keyPtr != NULL) { pkeyPtr = *(pthread_key_t **)keyPtr; pthread_key_delete(*pkeyPtr); ckfree((char *)pkeyPtr); *keyPtr = NULL; } } /* *---------------------------------------------------------------------- * * Tcl_ConditionWait -- * * This procedure is invoked to wait on a condition variable. * The mutex is automically released as part of the wait, and * automatically grabbed when the condition is signaled. * * The mutex must be held when this procedure is called. * * Results: * None. * * Side effects: * May block the current thread. The mutex is aquired when * this returns. Will allocate memory for a pthread_mutex_t * and initialize this the first time this Tcl_Mutex is used. * *---------------------------------------------------------------------- */ void Tcl_ConditionWait(condPtr, mutexPtr, timePtr) Tcl_Condition *condPtr; /* Really (pthread_cond_t **) */ Tcl_Mutex *mutexPtr; /* Really (pthread_mutex_t **) */ Tcl_Time *timePtr; /* Timeout on waiting period */ { pthread_cond_t *pcondPtr; pthread_mutex_t *pmutexPtr; struct timespec ptime; if (*condPtr == NULL) { MASTER_LOCK; /* * Double check inside mutex to avoid race, * then initialize condition variable if necessary. */ if (*condPtr == NULL) { pcondPtr = (pthread_cond_t *)ckalloc(sizeof(pthread_cond_t)); pthread_cond_init(pcondPtr, NULL); *condPtr = (Tcl_Condition)pcondPtr; TclRememberCondition(condPtr); } MASTER_UNLOCK; } pmutexPtr = *((pthread_mutex_t **)mutexPtr); pcondPtr = *((pthread_cond_t **)condPtr); if (timePtr == NULL) { pthread_cond_wait(pcondPtr, pmutexPtr); } else { Tcl_Time now; /* * Make sure to take into account the microsecond component of the * current time, including possible overflow situations. [Bug #411603] */ Tcl_GetTime(&now); ptime.tv_sec = timePtr->sec + now.sec + (timePtr->usec + now.usec) / 1000000; ptime.tv_nsec = 1000 * ((timePtr->usec + now.usec) % 1000000); pthread_cond_timedwait(pcondPtr, pmutexPtr, &ptime); } } /* *---------------------------------------------------------------------- * * Tcl_ConditionNotify -- * * This procedure is invoked to signal a condition variable. * * The mutex must be held during this call to avoid races, * but this interface does not enforce that. * * Results: * None. * * Side effects: * May unblock another thread. * *---------------------------------------------------------------------- */ void Tcl_ConditionNotify(condPtr) Tcl_Condition *condPtr; { pthread_cond_t *pcondPtr = *((pthread_cond_t **)condPtr); if (pcondPtr != NULL) { pthread_cond_broadcast(pcondPtr); } else { /* * Noone has used the condition variable, so there are no waiters. */ } } /* *---------------------------------------------------------------------- * * TclpFinalizeCondition -- * * This procedure is invoked to clean up a condition variable. * This is only safe to call at the end of time. * * This assumes the Master Lock is held. * * Results: * None. * * Side effects: * The condition variable is deallocated. * *---------------------------------------------------------------------- */ void TclpFinalizeCondition(condPtr) Tcl_Condition *condPtr; { pthread_cond_t *pcondPtr = *(pthread_cond_t **)condPtr; if (pcondPtr != NULL) { pthread_cond_destroy(pcondPtr); ckfree((char *)pcondPtr); *condPtr = NULL; } } #endif /* TCL_THREADS */ /* *---------------------------------------------------------------------- * * TclpReaddir, TclpInetNtoa -- * * These procedures replace core C versions to be used in a * threaded environment. * * Results: * See documentation of C functions. * * Side effects: * See documentation of C functions. * * Notes: * TclpReaddir is no longer used by the core (see 1095909), * but it appears in the internal stubs table (see #589526). *---------------------------------------------------------------------- */ Tcl_DirEntry * TclpReaddir(DIR * dir) { return TclOSreaddir(dir); } char * TclpInetNtoa(struct in_addr addr) { #ifdef TCL_THREADS ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); unsigned char *b = (unsigned char*) &addr.s_addr; sprintf(tsdPtr->nabuf, "%u.%u.%u.%u", b[0], b[1], b[2], b[3]); return tsdPtr->nabuf; #else return inet_ntoa(addr); #endif } #if defined(TCL_THREADS) && defined(USE_THREAD_ALLOC) && !defined(TCL_MEM_DEBUG) /* * Additions by AOL for specialized thread memory allocator. */ #ifdef USE_THREAD_ALLOC static volatile int initialized = 0; static pthread_key_t key; typedef struct allocMutex { Tcl_Mutex tlock; pthread_mutex_t plock; } allocMutex; Tcl_Mutex * TclpNewAllocMutex(void) { struct allocMutex *lockPtr; lockPtr = malloc(sizeof(struct allocMutex)); if (lockPtr == NULL) { panic("could not allocate lock"); } lockPtr->tlock = (Tcl_Mutex) &lockPtr->plock; pthread_mutex_init(&lockPtr->plock, NULL); return &lockPtr->tlock; } void TclpFreeAllocMutex(mutex) Tcl_Mutex *mutex; /* The alloc mutex to free. */ { allocMutex* lockPtr = (allocMutex*) mutex; if (!lockPtr) return; pthread_mutex_destroy(&lockPtr->plock); free(lockPtr); } void TclpFreeAllocCache(ptr) void *ptr; { if (ptr != NULL) { /* * Called by the pthread lib when a thread exits */ TclFreeAllocCache(ptr); } else if (initialized) { /* * Called by us in TclFinalizeThreadAlloc() during * the library finalization initiated from Tcl_Finalize() */ pthread_key_delete(key); initialized = 0; } } void * TclpGetAllocCache(void) { if (!initialized) { pthread_mutex_lock(allocLockPtr); if (!initialized) { pthread_key_create(&key, TclpFreeAllocCache); initialized = 1; } pthread_mutex_unlock(allocLockPtr); } return pthread_getspecific(key); } void TclpSetAllocCache(void *arg) { pthread_setspecific(key, arg); } #endif /* USE_THREAD_ALLOC */ #endif /* TCL_THREADS */ tcl8.4.20/unix/tclLoadShl.c0000644003604700454610000001341511737050675014104 0ustar dgp771div/* * tclLoadShl.c -- * * This procedure provides a version of the TclLoadFile that works * with the "shl_load" and "shl_findsym" library procedures for * dynamic loading (e.g. for HP machines). * * Copyright (c) 1995-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include /* * On some HP machines, dl.h defines EXTERN; remove that definition. */ #ifdef EXTERN # undef EXTERN #endif #include "tclInt.h" /* *---------------------------------------------------------------------- * * TclpDlopen -- * * Dynamically loads a binary code file into memory and returns * a handle to the new code. * * Results: * A standard Tcl completion code. If an error occurs, an error * message is left in the interp's result. * * Side effects: * New code suddenly appears in memory. * *---------------------------------------------------------------------- */ int TclpDlopen(interp, pathPtr, loadHandle, unloadProcPtr) Tcl_Interp *interp; /* Used for error reporting. */ Tcl_Obj *pathPtr; /* Name of the file containing the desired * code (UTF-8). */ Tcl_LoadHandle *loadHandle; /* Filled with token for dynamically loaded * file which will be passed back to * (*unloadProcPtr)() to unload the file. */ Tcl_FSUnloadFileProc **unloadProcPtr; /* Filled with address of Tcl_FSUnloadFileProc * function which should be used for * this file. */ { shl_t handle; CONST char *native; char *fileName = Tcl_GetString(pathPtr); /* * The flags below used to be BIND_IMMEDIATE; they were changed at * the suggestion of Wolfgang Kechel (wolfgang@prs.de): "This * enables verbosity for missing symbols when loading a shared lib * and allows to load libtk8.0.sl into tclsh8.0 without problems. * In general, this delays resolving symbols until they are actually * needed. Shared libs do no longer need all libraries linked in * when they are build." */ /* * First try the full path the user gave us. This is particularly * important if the cwd is inside a vfs, and we are trying to load * using a relative path. */ native = Tcl_FSGetNativePath(pathPtr); handle = shl_load(native, BIND_DEFERRED|BIND_VERBOSE, 0L); if (handle == NULL) { /* * Let the OS loader examine the binary search path for * whatever string the user gave us which hopefully refers * to a file on the binary path */ Tcl_DString ds; native = Tcl_UtfToExternalDString(NULL, fileName, -1, &ds); handle = shl_load(native, BIND_DEFERRED|BIND_VERBOSE|DYNAMIC_PATH, 0L); Tcl_DStringFree(&ds); } if (handle == NULL) { Tcl_AppendResult(interp, "couldn't load file \"", fileName, "\": ", Tcl_PosixError(interp), (char *) NULL); return TCL_ERROR; } *loadHandle = (Tcl_LoadHandle) handle; *unloadProcPtr = &TclpUnloadFile; return TCL_OK; } /* *---------------------------------------------------------------------- * * TclpFindSymbol -- * * Looks up a symbol, by name, through a handle associated with * a previously loaded piece of code (shared library). * * Results: * Returns a pointer to the function associated with 'symbol' if * it is found. Otherwise returns NULL and may leave an error * message in the interp's result. * *---------------------------------------------------------------------- */ Tcl_PackageInitProc* TclpFindSymbol(interp, loadHandle, symbol) Tcl_Interp *interp; Tcl_LoadHandle loadHandle; CONST char *symbol; { Tcl_DString newName; Tcl_PackageInitProc *proc=NULL; shl_t handle = (shl_t)loadHandle; /* * Some versions of the HP system software still use "_" at the * beginning of exported symbols while others don't; try both * forms of each name. */ if (shl_findsym(&handle, symbol, (short) TYPE_PROCEDURE, (void *) &proc) != 0) { Tcl_DStringInit(&newName); Tcl_DStringAppend(&newName, "_", 1); Tcl_DStringAppend(&newName, symbol, -1); if (shl_findsym(&handle, Tcl_DStringValue(&newName), (short) TYPE_PROCEDURE, (void *) &proc) != 0) { proc = NULL; } Tcl_DStringFree(&newName); } return proc; } /* *---------------------------------------------------------------------- * * TclpUnloadFile -- * * Unloads a dynamically loaded binary code file from memory. * Code pointers in the formerly loaded file are no longer valid * after calling this function. * * Results: * None. * * Side effects: * Code removed from memory. * *---------------------------------------------------------------------- */ void TclpUnloadFile(loadHandle) Tcl_LoadHandle loadHandle; /* loadHandle returned by a previous call * to TclpDlopen(). The loadHandle is * a token that represents the loaded * file. */ { shl_t handle; handle = (shl_t) loadHandle; shl_unload(handle); } /* *---------------------------------------------------------------------- * * TclGuessPackageName -- * * If the "load" command is invoked without providing a package * name, this procedure is invoked to try to figure it out. * * Results: * Always returns 0 to indicate that we couldn't figure out a * package name; generic code will then try to guess the package * from the file name. A return value of 1 would have meant that * we figured out the package name and put it in bufPtr. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclGuessPackageName(fileName, bufPtr) CONST char *fileName; /* Name of file containing package (already * translated to local form if needed). */ Tcl_DString *bufPtr; /* Initialized empty dstring. Append * package name to this if possible. */ { return 0; } tcl8.4.20/unix/tclLoadNext.c0000644003604700454610000001203411737050675014270 0ustar dgp771div/* * tclLoadNext.c -- * * This procedure provides a version of the TclLoadFile that * works with NeXTs rld_* dynamic loading. This file provided * by Pedja Bogdanovich. * * Copyright (c) 1995-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include #include /* *---------------------------------------------------------------------- * * TclpDlopen -- * * Dynamically loads a binary code file into memory and returns * a handle to the new code. * * Results: * A standard Tcl completion code. If an error occurs, an error * message is left in the interp's result. * * Side effects: * New code suddenly appears in memory. * *---------------------------------------------------------------------- */ int TclpDlopen(interp, pathPtr, loadHandle, unloadProcPtr) Tcl_Interp *interp; /* Used for error reporting. */ Tcl_Obj *pathPtr; /* Name of the file containing the desired * code (UTF-8). */ Tcl_LoadHandle *loadHandle; /* Filled with token for dynamically loaded * file which will be passed back to * (*unloadProcPtr)() to unload the file. */ Tcl_FSUnloadFileProc **unloadProcPtr; /* Filled with address of Tcl_FSUnloadFileProc * function which should be used for * this file. */ { struct mach_header *header; char *fileName; char *files[2]; CONST char *native; int result = 1; NXStream *errorStream = NXOpenMemory(0,0,NX_READWRITE); fileName = Tcl_GetString(pathPtr); /* * First try the full path the user gave us. This is particularly * important if the cwd is inside a vfs, and we are trying to load * using a relative path. */ native = Tcl_FSGetNativePath(pathPtr); files = {native,NULL}; result = rld_load(errorStream, &header, files, NULL); if (!result) { /* * Let the OS loader examine the binary search path for * whatever string the user gave us which hopefully refers * to a file on the binary path */ Tcl_DString ds; native = Tcl_UtfToExternalDString(NULL, fileName, -1, &ds); files = {native,NULL}; result = rld_load(errorStream, &header, files, NULL); Tcl_DStringFree(&ds); } if (!result) { char *data; int len, maxlen; NXGetMemoryBuffer(errorStream,&data,&len,&maxlen); Tcl_AppendResult(interp, "couldn't load file \"", fileName, "\": ", data, NULL); NXCloseMemory(errorStream, NX_FREEBUFFER); return TCL_ERROR; } NXCloseMemory(errorStream, NX_FREEBUFFER); *loadHandle = (Tcl_LoadHandle)1; /* A dummy non-NULL value */ *unloadProcPtr = &TclpUnloadFile; return TCL_OK; } /* *---------------------------------------------------------------------- * * TclpFindSymbol -- * * Looks up a symbol, by name, through a handle associated with * a previously loaded piece of code (shared library). * * Results: * Returns a pointer to the function associated with 'symbol' if * it is found. Otherwise returns NULL and may leave an error * message in the interp's result. * *---------------------------------------------------------------------- */ Tcl_PackageInitProc* TclpFindSymbol(interp, loadHandle, symbol) Tcl_Interp *interp; Tcl_LoadHandle loadHandle; CONST char *symbol; { Tcl_PackageInitProc *proc=NULL; if(symbol) { char sym[strlen(symbol)+2]; sym[0]='_'; sym[1]=0; strcat(sym,symbol); rld_lookup(NULL,sym,(unsigned long *)&proc); } return proc; } /* *---------------------------------------------------------------------- * * TclpUnloadFile -- * * Unloads a dynamically loaded binary code file from memory. * Code pointers in the formerly loaded file are no longer valid * after calling this function. * * Results: * None. * * Side effects: * Does nothing. Can anything be done? * *---------------------------------------------------------------------- */ void TclpUnloadFile(loadHandle) Tcl_LoadHandle loadHandle; /* loadHandle returned by a previous call * to TclpDlopen(). The loadHandle is * a token that represents the loaded * file. */ { } /* *---------------------------------------------------------------------- * * TclGuessPackageName -- * * If the "load" command is invoked without providing a package * name, this procedure is invoked to try to figure it out. * * Results: * Always returns 0 to indicate that we couldn't figure out a * package name; generic code will then try to guess the package * from the file name. A return value of 1 would have meant that * we figured out the package name and put it in bufPtr. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclGuessPackageName(fileName, bufPtr) CONST char *fileName; /* Name of file containing package (already * translated to local form if needed). */ Tcl_DString *bufPtr; /* Initialized empty dstring. Append * package name to this if possible. */ { return 0; } tcl8.4.20/unix/README0000644003604700454610000001570712153151142012555 0ustar dgp771divTcl UNIX README --------------- This is the directory where you configure, compile, test, and install UNIX versions of Tcl. This directory also contains source files for Tcl that are specific to UNIX. Some of the files in this directory are used on the PC or Mac platform too, but they all depend on UNIX (POSIX/ANSI C) interfaces and some of them only make sense under UNIX. Updated forms of the information found in this file is available at: http://www.tcl.tk/doc/howto/compile.html#unix For information on platforms where Tcl is known to compile, along with any porting notes for getting it to work on those platforms, see: http://www.tcl.tk/software/tcltk/platforms.html The rest of this file contains instructions on how to do this. The release should compile and run either "out of the box" or with trivial changes on any UNIX-like system that approximates POSIX, BSD, or System V. We know that it runs on workstations from Sun, H-P, DEC, IBM, and SGI, as well as PCs running Linux, BSDI, and SCO UNIX. To compile for a PC running Windows, see the README file in the directory ../win. To compile for Max OS X, see the README in the directory ../macosx. How To Compile And Install Tcl: ------------------------------- (a) If you have already compiled Tcl once in this directory and are now preparing to compile again in the same directory but for a different platform, or if you have applied patches, type "make distclean" to discard all the configuration information computed previously. (b) If you need to reconfigure because you changed any of the .in or .m4 files, you will need to run autoconf to create a new ./configure script. Most users will NOT need to do this since a configure script is already provided. (in the tcl/unix directory) autoconf (c) Type "./configure". This runs a configuration script created by GNU autoconf, which configures Tcl for your system and creates a Makefile. The configure script allows you to customize the Tcl configuration for your site; for details on how you can do this, type "./configure -help" or refer to the autoconf documentation (not included here). Tcl's "configure" supports the following special switches in addition to the standard ones: --enable-threads If this switch is set, Tcl will compile itself with multithreading support. --disable-load If this switch is specified then Tcl will configure itself not to allow dynamic loading, even if your system appears to support it. Normally you can leave this switch out and Tcl will build itself for dynamic loading if your system supports it. --enable-shared If this switch is specified, Tcl will compile itself as a shared library if it can figure out how to do that on this platform. This is the default on platforms where we know how to build shared libraries. --disable-shared If this switch is specified, Tcl will compile itself as a static library. --enable-symbols build with debugging symbols. By default standard debugging symbols are used. You can specify the value "mem" to include TCL_MEM_DEBUG memory debugging, "compile" to include TCL_COMPILE_DEBUG debugging, or "all" to enable all internal debugging. --disable-symbols build without debugging symbols --enable-64bit enable 64bit support (where applicable) --disable-64bit disable 64bit support (where applicable) --enable-64bit-vis enable 64bit Sparc VIS support --disable-64bit-vis disable 64bit Sparc VIS support --enable-langinfo Allows use of modern nl_langinfo check for better localization support. This is on by default on platforms where nl_langinfo is found. --disable-langinfo Specifically disables use of nl_langinfo. --enable-man-symlinks Use symlinks for linking the manpages that should be reachable under several names. --enable-man-compression=PROG Compress the manpages using PROG. --enable-dtrace Enable tcl DTrace provider (if DTrace is available on the platform), c.f. tclDTrace.d for descriptions of the probes made available, see http://wiki.tcl.tk/DTrace for more details. Mac OS X only: --enable-framework package Tcl as a framework. --disable-corefoundation disable use of CoreFoundation API and revert to standard select based notifier, required when using naked fork (i.e. not followed by execve). Note: by default gcc will be used if it can be located on the PATH. if you want to use cc instead of gcc, set the CC environment variable to "cc" before running configure. It is not safe to edit the Makefile to use gcc after configure is run. Also note that you should use the same compiler when building extensions. Note: be sure to use only absolute path names (those starting with "/") in the --prefix and --exec-prefix options. (d) Type "make". This will create a library archive called "libtcl.a" or "libtcl.so" and an interpreter application called "tclsh" that allows you to type Tcl commands interactively or execute script files. (e) If the make fails then you'll have to personalize the Makefile for your site or possibly modify the distribution in other ways. First check the porting Web page above to see if there are hints for compiling on your system. If you need to modify Makefile, are comments at the beginning of it that describe the things you might want to change and how to change them. (f) Type "make install" to install Tcl binaries and script files in standard places. You'll need write permission on the installation directories to do this. The installation directories are determined by the "configure" script and may be specified with the --prefix and --exec-prefix options to "configure". See the Makefile for information on what directories were chosen; you can override these choices by modifying the "prefix" and "exec_prefix" variables in the Makefile. (g) At this point you can play with Tcl by running "make shell" and typing Tcl commands at the prompt. If you have trouble compiling Tcl, see the URL noted above about working platforms. It contains information that people have provided about changes they had to make to compile Tcl in various environments. We're also interested in hearing how to change the configuration setup so that Tcl compiles on additional platforms "out of the box". Test suite ---------- There is a relatively complete test suite for all of the Tcl core in the subdirectory "tests". To use it just type "make test" in this directory. You should then see a printout of the test files processed. If any errors occur, you'll see a much more substantial printout for each error. See the README file in the "tests" directory for more information on the test suite. Note: don't run the tests as superuser: this will cause several of them to fail. If a test is failing consistently, please send us a bug report with as much detail as you can manage. Please use the online database at http://tcl.sourceforge.net/ tcl8.4.20/unix/tclUnixThrd.h0000644003604700454610000000060711737050675014327 0ustar dgp771div/* * tclUnixThrd.h -- * * This header file defines things for thread support. * * Copyright (c) 1998 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef _TCLUNIXTHRD #define _TCLUNIXTHRD #ifdef TCL_THREADS #endif /* TCL_THREADS */ #endif /* _TCLUNIXTHRD */ tcl8.4.20/macosx/0000755003604700454610000000000012153151143012173 5ustar dgp771divtcl8.4.20/macosx/tclMacOSXBundle.c0000644003604700454610000001730011737050674015305 0ustar dgp771div/* * tclMacOSXBundle.c -- * * This file implements functions that inspect CFBundle structures on * MacOS X. * * Copyright 2001, Apple Computer, Inc. * Copyright (c) 2003-2009 Daniel A. Steffen * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * * The following terms apply to all files originating from Apple * Computer, Inc. ("Apple") and associated with the software unless * explicitly disclaimed in individual files. * * Apple hereby grants permission to use, copy, modify, distribute, and * license this software and its documentation for any purpose, provided * that existing copyright notices are retained in all copies and that * this notice is included verbatim in any distributions. No written * agreement, license, or royalty fee is required for any of the * authorized uses. Modifications to this software may be copyrighted by * their authors and need not follow the licensing terms described here, * provided that the new terms are clearly indicated on the first page of * each file where they apply. * * IN NO EVENT SHALL APPLE, THE AUTHORS OR DISTRIBUTORS OF THE SOFTWARE * BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS * DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN IF APPLE OR THE * AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. APPLE, * THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND * NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND * APPLE,THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * * GOVERNMENT USE: If you are acquiring this software on behalf of the * U.S. government, the Government shall have only "Restricted Rights" in * the software and related documentation as defined in the Federal * Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are * acquiring the software on behalf of the Department of Defense, the * software shall be classified as "Commercial Computer Software" and the * Government shall have only "Restricted Rights" as defined in Clause * 252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the * authors grant the U.S. Government and others acting in its behalf * permission to use and distribute the software in accordance with the * terms specified in this license. */ #include "tclPort.h" #ifdef HAVE_COREFOUNDATION #include #include #if MAC_OS_X_VERSION_MIN_REQUIRED < 1050 MODULE_SCOPE long tclMacOSXDarwinRelease; #endif #endif /* HAVE_COREFOUNDATION */ /* *---------------------------------------------------------------------- * * Tcl_MacOSXOpenBundleResources -- * * Given the bundle name for a shared library, this routine sets * libraryPath to the Resources/Scripts directory in the framework * package. If hasResourceFile is true, it will also open the main * resource file for the bundle. * * Results: * TCL_OK if the bundle could be opened, and the Scripts folder found. * TCL_ERROR otherwise. * * Side effects: * libraryVariableName may be set, and the resource file opened. * *---------------------------------------------------------------------- */ int Tcl_MacOSXOpenBundleResources( Tcl_Interp *interp, CONST char *bundleName, int hasResourceFile, int maxPathLen, char *libraryPath) { return Tcl_MacOSXOpenVersionedBundleResources(interp, bundleName, NULL, hasResourceFile, maxPathLen, libraryPath); } /* *---------------------------------------------------------------------- * * Tcl_MacOSXOpenVersionedBundleResources -- * * Given the bundle and version name for a shared library (version name * can be NULL to indicate latest version), this routine sets libraryPath * to the Resources/Scripts directory in the framework package. If * hasResourceFile is true, it will also open the main resource file for * the bundle. * * Results: * TCL_OK if the bundle could be opened, and the Scripts folder found. * TCL_ERROR otherwise. * * Side effects: * libraryVariableName may be set, and the resource file opened. * *---------------------------------------------------------------------- */ int Tcl_MacOSXOpenVersionedBundleResources( Tcl_Interp *interp, CONST char *bundleName, CONST char *bundleVersion, int hasResourceFile, int maxPathLen, char *libraryPath) { #ifdef HAVE_COREFOUNDATION CFBundleRef bundleRef, versionedBundleRef = NULL; CFStringRef bundleNameRef; CFURLRef libURL; libraryPath[0] = '\0'; bundleNameRef = CFStringCreateWithCString(NULL, bundleName, kCFStringEncodingUTF8); bundleRef = CFBundleGetBundleWithIdentifier(bundleNameRef); CFRelease(bundleNameRef); if (bundleVersion && bundleRef) { /* * Create bundle from bundleVersion subdirectory of 'Versions'. */ CFURLRef bundleURL = CFBundleCopyBundleURL(bundleRef); if (bundleURL) { CFStringRef bundleVersionRef = CFStringCreateWithCString(NULL, bundleVersion, kCFStringEncodingUTF8); if (bundleVersionRef) { CFComparisonResult versionComparison = kCFCompareLessThan; CFStringRef bundleTailRef = CFURLCopyLastPathComponent( bundleURL); if (bundleTailRef) { versionComparison = CFStringCompare(bundleTailRef, bundleVersionRef, 0); CFRelease(bundleTailRef); } if (versionComparison != kCFCompareEqualTo) { CFURLRef versURL = CFURLCreateCopyAppendingPathComponent( NULL, bundleURL, CFSTR("Versions"), TRUE); if (versURL) { CFURLRef versionedBundleURL = CFURLCreateCopyAppendingPathComponent( NULL, versURL, bundleVersionRef, TRUE); if (versionedBundleURL) { versionedBundleRef = CFBundleCreate(NULL, versionedBundleURL); if (versionedBundleRef) { bundleRef = versionedBundleRef; } CFRelease(versionedBundleURL); } CFRelease(versURL); } } CFRelease(bundleVersionRef); } CFRelease(bundleURL); } } if (bundleRef) { if (hasResourceFile) { /* * Dynamically acquire address for CFBundleOpenBundleResourceMap * symbol, since it is only present in full CoreFoundation on Mac * OS X and not in CFLite on pure Darwin. */ static int initialized = FALSE; static short (*openresourcemap)(CFBundleRef) = NULL; if (!initialized) { NSSymbol nsSymbol = NULL; if (NSIsSymbolNameDefinedWithHint( "_CFBundleOpenBundleResourceMap", "CoreFoundation")) { nsSymbol = NSLookupAndBindSymbolWithHint( "_CFBundleOpenBundleResourceMap","CoreFoundation"); if (nsSymbol) { openresourcemap = NSAddressOfSymbol(nsSymbol); } } initialized = TRUE; } if (openresourcemap) { short refNum; refNum = openresourcemap(bundleRef); } } libURL = CFBundleCopyResourceURL(bundleRef, CFSTR("Scripts"), NULL, NULL); if (libURL) { /* * FIXME: This is a quick fix, it is probably not right for * internationalization. */ CFURLGetFileSystemRepresentation(libURL, TRUE, (unsigned char*) libraryPath, maxPathLen); CFRelease(libURL); } if (versionedBundleRef) { #if MAC_OS_X_VERSION_MIN_REQUIRED < 1050 /* Workaround CFBundle bug in Tiger and earlier. [Bug 2569449] */ if (tclMacOSXDarwinRelease >= 9) #endif { CFRelease(versionedBundleRef); } } } if (libraryPath[0]) { return TCL_OK; } else { return TCL_ERROR; } #else /* HAVE_COREFOUNDATION */ return TCL_ERROR; #endif /* HAVE_COREFOUNDATION */ } tcl8.4.20/macosx/Tclsh-Info.plist.in0000644003604700454610000000236311737050674015645 0ustar dgp771div CFBundleDevelopmentRegion English CFBundleExecutable tclsh@TCL_VERSION@ CFBundleGetInfoString Tcl Shell @TCL_VERSION@@TCL_PATCH_LEVEL@, Copyright ТЉ @TCL_YEAR@ Tcl Core Team, Copyright ТЉ 2001-@TCL_YEAR@ Daniel A. Steffen, Initial MacOS X Port by Jim Ingham & Ian Reid, Copyright ТЉ 2001-2002, Apple Computer, Inc. CFBundleIdentifier com.tcltk.tclsh CFBundleInfoDictionaryVersion 6.0 CFBundleName tclsh CFBundlePackageType APPL CFBundleShortVersionString @TCL_VERSION@@TCL_PATCH_LEVEL@ CFBundleSignature TclS CFBundleVersion @TCL_VERSION@@TCL_PATCH_LEVEL@ tcl8.4.20/macosx/Tcl-Info.plist.in0000644003604700454610000000237211737050674015312 0ustar dgp771div CFBundleDevelopmentRegion English CFBundleExecutable @TCL_LIB_FILE@ CFBundleGetInfoString Tcl @TCL_VERSION@@TCL_PATCH_LEVEL@, Copyright ТЉ @TCL_YEAR@ Tcl Core Team, Copyright ТЉ 2001-@TCL_YEAR@ Daniel A. Steffen, Initial MacOS X Port by Jim Ingham & Ian Reid, Copyright ТЉ 2001-2002, Apple Computer, Inc. CFBundleIdentifier com.tcltk.tcllibrary CFBundleInfoDictionaryVersion 6.0 CFBundleName Tcl @TCL_VERSION@ CFBundlePackageType FMWK CFBundleShortVersionString @TCL_VERSION@@TCL_PATCH_LEVEL@ CFBundleSignature Tcl CFBundleVersion @TCL_VERSION@@TCL_PATCH_LEVEL@ tcl8.4.20/macosx/license.terms0000644003604700454610000000432111737050674014707 0ustar dgp771divThis software is copyrighted by the Regents of the University of California, Sun Microsystems, Inc., Scriptics Corporation, ActiveState Corporation and other parties. The following terms apply to all files associated with the software unless explicitly disclaimed in individual files. The authors hereby grant permission to use, copy, modify, distribute, and license this software and its documentation for any purpose, provided that existing copyright notices are retained in all copies and that this notice is included verbatim in any distributions. No written agreement, license, or royalty fee is required for any of the authorized uses. Modifications to this software may be copyrighted by their authors and need not follow the licensing terms described here, provided that the new terms are clearly indicated on the first page of each file where they apply. IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. GOVERNMENT USE: If you are acquiring this software on behalf of the U.S. government, the Government shall have only "Restricted Rights" in the software and related documentation as defined in the Federal Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are acquiring the software on behalf of the Department of Defense, the software shall be classified as "Commercial Computer Software" and the Government shall have only "Restricted Rights" as defined in Clause 252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the authors grant the U.S. Government and others acting in its behalf permission to use and distribute the software in accordance with the terms specified in this license. tcl8.4.20/macosx/Makefile0000644003604700454610000001565711737050674013667 0ustar dgp771div######################################################################################################## # # Makefile wrapper to build tcl on Mac OS X in a way compatible with the tk/macosx Xcode buildsystem # uses the standard unix build system in tcl/unix (which can be used directly instead of this # if you are not using the tk/macosx projects). # # Copyright (c) 2002-2007 Daniel A. Steffen # # See the file "license.terms" for information on usage and redistribution of # this file, and for a DISCLAIMER OF ALL WARRANTIES. # ######################################################################################################## #------------------------------------------------------------------------------------------------------- # customizable settings DESTDIR ?= INSTALL_ROOT ?= ${DESTDIR} BUILD_DIR ?= ${CURDIR}/../../build SYMROOT ?= ${BUILD_DIR}/${PROJECT} OBJROOT ?= ${SYMROOT} EXTRA_CONFIGURE_ARGS ?= EXTRA_MAKE_ARGS ?= INSTALL_PATH ?= /Library/Frameworks PREFIX ?= /usr/local BINDIR ?= ${PREFIX}/bin LIBDIR ?= ${INSTALL_PATH} MANDIR ?= ${PREFIX}/man # set to non-empty value to install manpages in addition to html help: INSTALL_MANPAGES ?= #------------------------------------------------------------------------------------------------------- # meta targets meta := all install embedded install-embedded clean distclean test styles := develop deploy all := ${styles} all : ${all} install := ${styles:%=install-%} install : ${install} install-%: action := install- embedded := ${styles:%=embedded-%} embedded : embedded-deploy install-embedded := ${embedded:%=install-%} install-embedded : install-embedded-deploy clean := ${styles:%=clean-%} clean : ${clean} clean-%: action := clean- distclean := ${styles:%=distclean-%} distclean : ${distclean} distclean-%: action := distclean- test := ${styles:%=test-%} test : ${test} test-%: action := test- targets := $(foreach v,${meta},${$v}) #------------------------------------------------------------------------------------------------------- # build styles BUILD_STYLE = CONFIGURE_ARGS = OBJ_DIR = ${OBJROOT}/${BUILD_STYLE} develop_make_args := BUILD_STYLE=Development CONFIGURE_ARGS=--enable-symbols deploy_make_args := BUILD_STYLE=Deployment INSTALL_TARGET=install-strip \ GENERIC_FLAGS=-DNDEBUG embedded_make_args := EMBEDDED_BUILD=1 install_make_args := INSTALL_BUILD=1 ${targets}: ${MAKE} ${action}${PROJECT} \ $(foreach s,${styles} embedded install,$(if $(findstring $s,$@),${${s}_make_args})) #------------------------------------------------------------------------------------------------------- # project specific settings PROJECT := tcl PRODUCT_NAME := Tcl UNIX_DIR := ${CURDIR}/../unix VERSION := $(shell awk -F= '/^TCL_VERSION/ {print $$2; nextfile}' ${UNIX_DIR}/configure.in) TCLSH := tclsh${VERSION} BUILD_TARGET := all tcltest INSTALL_TARGET := install export CPPROG := cp -p INSTALL_TARGETS = install-binaries install-libraries ifeq (${EMBEDDED_BUILD},) INSTALL_TARGETS += install-private-headers endif ifeq (${INSTALL_BUILD}_${EMBEDDED_BUILD}_${BUILD_STYLE},1__Deployment) INSTALL_TARGETS += html-tcl ifneq (${INSTALL_MANPAGES},) INSTALL_TARGETS += install-doc endif endif MAKE_VARS := INSTALL_ROOT INSTALL_TARGETS VERSION GENERIC_FLAGS MAKE_ARGS_V = $(foreach v,${MAKE_VARS},$v='${$v}') build-${PROJECT}: target = ${BUILD_TARGET} install-${PROJECT}: target = ${INSTALL_TARGET} clean-${PROJECT} distclean-${PROJECT} test-${PROJECT}: \ target = $* DO_MAKE = +${MAKE} -C ${OBJ_DIR} ${target} ${MAKE_ARGS_V} ${MAKE_ARGS} ${EXTRA_MAKE_ARGS} #------------------------------------------------------------------------------------------------------- # build rules ${PROJECT}: ${MAKE} install-${PROJECT} INSTALL_ROOT=${OBJ_DIR}/ ${OBJ_DIR}/Makefile: ${UNIX_DIR}/Makefile.in ${UNIX_DIR}/configure \ ${UNIX_DIR}/tclConfig.sh.in Tcl-Info.plist.in mkdir -p ${OBJ_DIR} && cd ${OBJ_DIR} && \ if [ ${UNIX_DIR}/configure -nt config.status ]; then ${UNIX_DIR}/configure \ --prefix=${PREFIX} --bindir=${BINDIR} --libdir=${LIBDIR} \ --mandir=${MANDIR} --enable-threads --enable-framework --enable-dtrace \ ${CONFIGURE_ARGS} ${EXTRA_CONFIGURE_ARGS}; else ./config.status; fi build-${PROJECT}: ${OBJ_DIR}/Makefile ${DO_MAKE} ifeq (${INSTALL_BUILD},) # symolic link hackery to trick # 'make install INSTALL_ROOT=${OBJ_DIR}' # into building Tcl.framework and tclsh in ${SYMROOT} @cd ${OBJ_DIR} && mkdir -p $(dir ./${LIBDIR}) $(dir ./${BINDIR}) ${SYMROOT} && \ rm -f ./${LIBDIR} ./${BINDIR} && ln -fs ${SYMROOT} ./${LIBDIR} && \ ln -fs ${SYMROOT} ./${BINDIR} && ln -fs ${OBJ_DIR}/tcltest ${SYMROOT} endif install-${PROJECT}: build-${PROJECT} ifeq (${EMBEDDED_BUILD}_${INSTALL_ROOT},1_) @echo "Cannot install-embedded with empty INSTALL_ROOT !" && false endif ifeq (${EMBEDDED_BUILD},1) @rm -rf "${INSTALL_ROOT}/${LIBDIR}/Tcl.framework" endif ${DO_MAKE} ifeq (${INSTALL_BUILD},1) ifeq (${EMBEDDED_BUILD},1) # if we are embedding frameworks, don't install tclsh @rm -f "${INSTALL_ROOT}${BINDIR}/${TCLSH}" && \ rmdir -p "${INSTALL_ROOT}${BINDIR}" 2>&- || true else # redo prebinding (when not building for Mac OS X 10.4 or later only) @if [ "`echo "$${MACOSX_DEPLOYMENT_TARGET}" | \ awk -F '10\\.' '{print int($$2)}'`" -lt 4 -a "`echo "$${CFLAGS}" | \ awk -F '-mmacosx-version-min=10\\.' '{print int($$2)}'`" -lt 4 ]; \ then cd ${INSTALL_ROOT}/; \ if [ ! -d usr/lib ]; then mkdir -p usr && ln -fs /usr/lib usr/ && RM_USRLIB=1; fi; \ if [ ! -d System ]; then ln -fs /System . && RM_SYSTEM=1; fi; \ redo_prebinding -r . "./${LIBDIR}/${PRODUCT_NAME}.framework/Versions/${VERSION}/${PRODUCT_NAME}"; \ redo_prebinding -r . "./${BINDIR}/${TCLSH}"; \ if [ -n "$${RM_USRLIB:-}" ]; then rm -f usr/lib; rmdir -p usr 2>&-; fi; \ if [ -n "$${RM_SYSTEM:-}" ]; then rm -f System; fi; fi # install tclsh symbolic link @ln -fs ${TCLSH} ${INSTALL_ROOT}${BINDIR}/tclsh endif endif ifeq (${BUILD_STYLE}_${EMBEDDED_BUILD},Development_) # keep copy of debug library around, so that # Deployment build can be installed on top # of Development build without overwriting # the debug library @cd ${INSTALL_ROOT}${LIBDIR}/${PRODUCT_NAME}.framework/Versions/${VERSION} && \ ln -f "${PRODUCT_NAME}" "${PRODUCT_NAME}_debug" endif clean-${PROJECT}: %-${PROJECT}: ${DO_MAKE} rm -rf ${SYMROOT}/{${PRODUCT_NAME}.framework,${TCLSH},tcltest} rm -f ${OBJ_DIR}{${LIBDIR},${BINDIR}} && \ rmdir -p ${OBJ_DIR}$(dir ${LIBDIR}) 2>&- || true && \ rmdir -p ${OBJ_DIR}$(dir ${BINDIR}) 2>&- || true distclean-${PROJECT}: %-${PROJECT}: clean-${PROJECT} ${DO_MAKE} rm -rf ${OBJ_DIR} test-${PROJECT}: %-${PROJECT}: build-${PROJECT} ${DO_MAKE} #------------------------------------------------------------------------------------------------------- .PHONY: ${meta} ${targets} ${PROJECT} build-${PROJECT} install-${PROJECT} \ clean-${PROJECT} distclean-${PROJECT} .NOTPARALLEL: #------------------------------------------------------------------------------------------------------- tcl8.4.20/macosx/tclMacOSXNotify.c0000644003604700454610000010573311737050674015354 0ustar dgp771div/* * tclMacOSXNotify.c -- * * This file contains the implementation of a merged CFRunLoop/select() * based notifier, which is the lowest-level part of the Tcl event loop. * This file works together with generic/tclNotify.c. * * Copyright (c) 1995-1997 Sun Microsystems, Inc. * Copyright 2001, Apple Computer, Inc. * Copyright (c) 2005-2008 Daniel A. Steffen * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" #ifdef HAVE_COREFOUNDATION /* Traditional unix select-based notifier is * in tclUnixNotfy.c */ #include #include extern TclStubs tclStubs; extern Tcl_NotifierProcs tclOriginalNotifier; /* * This structure is used to keep track of the notifier info for a registered * file. */ typedef struct FileHandler { int fd; int mask; /* Mask of desired events: TCL_READABLE, * etc. */ int readyMask; /* Mask of events that have been seen since * the last time file handlers were invoked * for this file. */ Tcl_FileProc *proc; /* Function to call, in the style of * Tcl_CreateFileHandler. */ ClientData clientData; /* Argument to pass to proc. */ struct FileHandler *nextPtr;/* Next in list of all files we care about. */ } FileHandler; /* * The following structure is what is added to the Tcl event queue when file * handlers are ready to fire. */ typedef struct FileHandlerEvent { Tcl_Event header; /* Information that is standard for all * events. */ int fd; /* File descriptor that is ready. Used to find * the FileHandler structure for the file * (can't point directly to the FileHandler * structure because it could go away while * the event is queued). */ } FileHandlerEvent; /* * The following structure contains a set of select() masks to track readable, * writable, and exceptional conditions. */ typedef struct SelectMasks { fd_set readable; fd_set writable; fd_set exceptional; } SelectMasks; /* * The following static structure contains the state information for the * select based implementation of the Tcl notifier. One of these structures is * created for each thread that is using the notifier. */ typedef struct ThreadSpecificData { FileHandler *firstFileHandlerPtr; /* Pointer to head of file handler list. */ SelectMasks checkMasks; /* This structure is used to build up the * masks to be used in the next call to * select. Bits are set in response to calls * to Tcl_CreateFileHandler. */ SelectMasks readyMasks; /* This array reflects the readable/writable * conditions that were found to exist by the * last call to select. */ int numFdBits; /* Number of valid bits in checkMasks (one * more than highest fd for which * Tcl_WatchFile has been called). */ int onList; /* True if it is in this list */ unsigned int pollState; /* pollState is used to implement a polling * handshake between each thread and the * notifier thread. Bits defined below. */ struct ThreadSpecificData *nextPtr, *prevPtr; /* All threads that are currently waiting on * an event have their ThreadSpecificData * structure on a doubly-linked listed formed * from these pointers. You must hold the * notifierLock before accessing these * fields. */ CFRunLoopSourceRef runLoopSource; /* Any other thread alerts a notifier that an * event is ready to be processed by signaling * this CFRunLoopSource. */ CFRunLoopRef runLoop; /* This thread's CFRunLoop, needs to be woken * up whenever the runLoopSource is * signaled. */ int eventReady; /* True if an event is ready to be * processed. */ } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; /* * The following static indicates the number of threads that have initialized * notifiers. * * You must hold the notifierInitLock before accessing this variable. */ static int notifierCount = 0; /* * The following variable points to the head of a doubly-linked list of * ThreadSpecificData structures for all threads that are currently waiting on * an event. * * You must hold the notifierLock before accessing this list. */ static ThreadSpecificData *waitingListPtr = NULL; /* * The notifier thread spends all its time in select() waiting for a file * descriptor associated with one of the threads on the waitingListPtr list to * do something interesting. But if the contents of the waitingListPtr list * ever changes, we need to wake up and restart the select() system call. You * can wake up the notifier thread by writing a single byte to the file * descriptor defined below. This file descriptor is the input-end of a pipe * and the notifier thread is listening for data on the output-end of the same * pipe. Hence writing to this file descriptor will cause the select() system * call to return and wake up the notifier thread. * * You must hold the notifierLock lock before writing to the pipe. */ static int triggerPipe = -1; static int receivePipe = -1; /* Output end of triggerPipe */ /* * We use the Darwin-native spinlock API rather than pthread mutexes for * notifier locking: this radically simplifies the implementation and lowers * overhead. Note that these are not pure spinlocks, they employ various * strategies to back off and relinquish the processor, making them immune to * most priority-inversion livelocks (c.f. 'man 3 OSSpinLockLock' and Darwin * sources: xnu/osfmk/{ppc,i386}/commpage/spinlocks.s). */ #if defined(HAVE_LIBKERN_OSATOMIC_H) && defined(HAVE_OSSPINLOCKLOCK) /* * Use OSSpinLock API where available (Tiger or later). */ #include #if defined(HAVE_WEAK_IMPORT) && MAC_OS_X_VERSION_MIN_REQUIRED < 1040 /* * Support for weakly importing spinlock API. */ #define WEAK_IMPORT_SPINLOCKLOCK #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 #define VOLATILE volatile #else #define VOLATILE #endif #ifndef bool #define bool int #endif extern void OSSpinLockLock(VOLATILE OSSpinLock *lock) WEAK_IMPORT_ATTRIBUTE; extern void OSSpinLockUnlock(VOLATILE OSSpinLock *lock) WEAK_IMPORT_ATTRIBUTE; extern bool OSSpinLockTry(VOLATILE OSSpinLock *lock) WEAK_IMPORT_ATTRIBUTE; extern void _spin_lock(VOLATILE OSSpinLock *lock) WEAK_IMPORT_ATTRIBUTE; extern void _spin_unlock(VOLATILE OSSpinLock *lock) WEAK_IMPORT_ATTRIBUTE; extern bool _spin_lock_try(VOLATILE OSSpinLock *lock) WEAK_IMPORT_ATTRIBUTE; static void (* lockLock)(VOLATILE OSSpinLock *lock) = NULL; static void (* lockUnlock)(VOLATILE OSSpinLock *lock) = NULL; static bool (* lockTry)(VOLATILE OSSpinLock *lock) = NULL; #undef VOLATILE static pthread_once_t spinLockLockInitControl = PTHREAD_ONCE_INIT; static void SpinLockLockInit(void) { lockLock = OSSpinLockLock != NULL ? OSSpinLockLock : _spin_lock; lockUnlock = OSSpinLockUnlock != NULL ? OSSpinLockUnlock : _spin_unlock; lockTry = OSSpinLockTry != NULL ? OSSpinLockTry : _spin_lock_try; if (lockLock == NULL || lockUnlock == NULL) { Tcl_Panic("SpinLockLockInit: no spinlock API available"); } } #define SpinLockLock(p) lockLock(p) #define SpinLockUnlock(p) lockUnlock(p) #define SpinLockTry(p) lockTry(p) #else #define SpinLockLock(p) OSSpinLockLock(p) #define SpinLockUnlock(p) OSSpinLockUnlock(p) #define SpinLockTry(p) OSSpinLockTry(p) #endif /* HAVE_WEAK_IMPORT */ #define SPINLOCK_INIT OS_SPINLOCK_INIT #else /* * Otherwise, use commpage spinlock SPI directly. */ typedef uint32_t OSSpinLock; extern void _spin_lock(OSSpinLock *lock); extern void _spin_unlock(OSSpinLock *lock); extern int _spin_lock_try(OSSpinLock *lock); #define SpinLockLock(p) _spin_lock(p) #define SpinLockUnlock(p) _spin_unlock(p) #define SpinLockTry(p) _spin_lock_try(p) #define SPINLOCK_INIT 0 #endif /* HAVE_LIBKERN_OSATOMIC_H && HAVE_OSSPINLOCKLOCK */ /* * These spinlocks lock access to the global notifier state. */ static OSSpinLock notifierInitLock = SPINLOCK_INIT; static OSSpinLock notifierLock = SPINLOCK_INIT; /* * Macros abstracting notifier locking/unlocking */ #define LOCK_NOTIFIER_INIT SpinLockLock(¬ifierInitLock) #define UNLOCK_NOTIFIER_INIT SpinLockUnlock(¬ifierInitLock) #define LOCK_NOTIFIER SpinLockLock(¬ifierLock) #define UNLOCK_NOTIFIER SpinLockUnlock(¬ifierLock) /* * The pollState bits * POLL_WANT is set by each thread before it waits on its condition * variable. It is checked by the notifier before it does select. * POLL_DONE is set by the notifier if it goes into select after seeing * POLL_WANT. The idea is to ensure it tries a select with the * same bits the initial thread had set. */ #define POLL_WANT 0x1 #define POLL_DONE 0x2 /* * This is the thread ID of the notifier thread that does select. */ static pthread_t notifierThread; /* * Custom run loop mode containing only the run loop source for the * notifier thread. */ #ifndef TCL_EVENTS_ONLY_RUN_LOOP_MODE #define TCL_EVENTS_ONLY_RUN_LOOP_MODE "com.tcltk.tclEventsOnlyRunLoopMode" #endif #ifdef __CONSTANT_CFSTRINGS__ #define tclEventsOnlyRunLoopMode CFSTR(TCL_EVENTS_ONLY_RUN_LOOP_MODE) #else static CFStringRef tclEventsOnlyRunLoopMode = NULL; #endif /* * Static routines defined in this file. */ static void NotifierThreadProc(ClientData clientData) __attribute__ ((__noreturn__)); static int FileHandlerEventProc(Tcl_Event *evPtr, int flags); #ifdef HAVE_PTHREAD_ATFORK static int atForkInit = 0; static void AtForkPrepare(void); static void AtForkParent(void); static void AtForkChild(void); #if defined(HAVE_WEAK_IMPORT) && MAC_OS_X_VERSION_MIN_REQUIRED < 1040 /* Support for weakly importing pthread_atfork. */ #define WEAK_IMPORT_PTHREAD_ATFORK extern int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)) WEAK_IMPORT_ATTRIBUTE; #endif /* HAVE_WEAK_IMPORT */ /* * On Darwin 9 and later, it is not possible to call CoreFoundation after * a fork. */ #if !defined(MAC_OS_X_VERSION_MIN_REQUIRED) || \ MAC_OS_X_VERSION_MIN_REQUIRED < 1050 MODULE_SCOPE long tclMacOSXDarwinRelease; #define noCFafterFork (tclMacOSXDarwinRelease >= 9) #else /* MAC_OS_X_VERSION_MIN_REQUIRED */ #define noCFafterFork 1 #endif /* MAC_OS_X_VERSION_MIN_REQUIRED */ #endif /* HAVE_PTHREAD_ATFORK */ /* *---------------------------------------------------------------------- * * Tcl_InitNotifier -- * * Initializes the platform specific notifier state. * * Results: * Returns a handle to the notifier state for this thread. * * Side effects: * None. * *---------------------------------------------------------------------- */ ClientData Tcl_InitNotifier(void) { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); tsdPtr->eventReady = 0; #ifdef WEAK_IMPORT_SPINLOCKLOCK /* * Initialize support for weakly imported spinlock API. */ if (pthread_once(&spinLockLockInitControl, SpinLockLockInit)) { Tcl_Panic("Tcl_InitNotifier: pthread_once failed"); } #endif #ifndef __CONSTANT_CFSTRINGS__ if (!tclEventsOnlyRunLoopMode) { tclEventsOnlyRunLoopMode = CFSTR(TCL_EVENTS_ONLY_RUN_LOOP_MODE); } #endif /* * Initialize CFRunLoopSource and add it to CFRunLoop of this thread. */ if (!tsdPtr->runLoop) { CFRunLoopRef runLoop = CFRunLoopGetCurrent(); CFRunLoopSourceRef runLoopSource; CFRunLoopSourceContext runLoopSourceContext; bzero(&runLoopSourceContext, sizeof(CFRunLoopSourceContext)); runLoopSourceContext.info = tsdPtr; runLoopSource = CFRunLoopSourceCreate(NULL, 0, &runLoopSourceContext); if (!runLoopSource) { Tcl_Panic("Tcl_InitNotifier: could not create CFRunLoopSource"); } CFRunLoopAddSource(runLoop, runLoopSource, kCFRunLoopCommonModes); CFRunLoopAddSource(runLoop, runLoopSource, tclEventsOnlyRunLoopMode); tsdPtr->runLoopSource = runLoopSource; tsdPtr->runLoop = runLoop; } LOCK_NOTIFIER_INIT; #ifdef HAVE_PTHREAD_ATFORK /* * Install pthread_atfork handlers to reinitialize the notifier in the * child of a fork. */ if ( #ifdef WEAK_IMPORT_PTHREAD_ATFORK pthread_atfork != NULL && #endif !atForkInit) { int result = pthread_atfork(AtForkPrepare, AtForkParent, AtForkChild); if (result) { Tcl_Panic("Tcl_InitNotifier: pthread_atfork failed"); } atForkInit = 1; } #endif if (notifierCount == 0) { int fds[2], status; /* * Initialize trigger pipe. */ if (pipe(fds) != 0) { Tcl_Panic("Tcl_InitNotifier: could not create trigger pipe"); } status = fcntl(fds[0], F_GETFL); status |= O_NONBLOCK; if (fcntl(fds[0], F_SETFL, status) < 0) { Tcl_Panic("Tcl_InitNotifier: could not make receive pipe non blocking"); } status = fcntl(fds[1], F_GETFL); status |= O_NONBLOCK; if (fcntl(fds[1], F_SETFL, status) < 0) { Tcl_Panic("Tcl_InitNotifier: could not make trigger pipe non blocking"); } receivePipe = fds[0]; triggerPipe = fds[1]; /* * Create notifier thread lazily in Tcl_WaitForEvent() to avoid * interfering with fork() followed immediately by execve() * (cannot execve() when more than one thread is present). */ notifierThread = 0; } notifierCount++; UNLOCK_NOTIFIER_INIT; return (ClientData) tsdPtr; } /* *---------------------------------------------------------------------- * * Tcl_FinalizeNotifier -- * * This function is called to cleanup the notifier state before a thread * is terminated. * * Results: * None. * * Side effects: * May terminate the background notifier thread if this is the last * notifier instance. * *---------------------------------------------------------------------- */ void Tcl_FinalizeNotifier( ClientData clientData) /* Not used. */ { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); LOCK_NOTIFIER_INIT; notifierCount--; /* * If this is the last thread to use the notifier, close the notifier pipe * and wait for the background thread to terminate. */ if (notifierCount == 0) { int result; if (triggerPipe < 0) { Tcl_Panic("Tcl_FinalizeNotifier: notifier pipe not initialized"); } /* * Send "q" message to the notifier thread so that it will terminate. * The notifier will return from its call to select() and notice that * a "q" message has arrived, it will then close its side of the pipe * and terminate its thread. Note the we can not just close the pipe * and check for EOF in the notifier thread because if a background * child process was created with exec, select() would not register * the EOF on the pipe until the child processes had terminated. [Bug: * 4139] [Bug: 1222872] */ write(triggerPipe, "q", 1); close(triggerPipe); if (notifierThread) { result = pthread_join(notifierThread, NULL); if (result) { Tcl_Panic("Tcl_FinalizeNotifier: unable to join notifier thread"); } notifierThread = 0; } close(receivePipe); triggerPipe = -1; } UNLOCK_NOTIFIER_INIT; LOCK_NOTIFIER; /* for concurrency with Tcl_AlertNotifier */ if (tsdPtr->runLoop) { tsdPtr->runLoop = NULL; /* * Remove runLoopSource from all CFRunLoops and release it. */ CFRunLoopSourceInvalidate(tsdPtr->runLoopSource); CFRelease(tsdPtr->runLoopSource); tsdPtr->runLoopSource = NULL; } UNLOCK_NOTIFIER; } /* *---------------------------------------------------------------------- * * Tcl_AlertNotifier -- * * Wake up the specified notifier from any thread. This routine is called * by the platform independent notifier code whenever the Tcl_ThreadAlert * routine is called. This routine is guaranteed not to be called on a * given notifier after Tcl_FinalizeNotifier is called for that notifier. * * Results: * None. * * Side effects: * Signals the notifier condition variable for the specified notifier. * *---------------------------------------------------------------------- */ void Tcl_AlertNotifier( ClientData clientData) { ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData; LOCK_NOTIFIER; if (tsdPtr->runLoop) { tsdPtr->eventReady = 1; CFRunLoopSourceSignal(tsdPtr->runLoopSource); CFRunLoopWakeUp(tsdPtr->runLoop); } UNLOCK_NOTIFIER; } /* *---------------------------------------------------------------------- * * Tcl_SetTimer -- * * This function sets the current notifier timer value. This interface is * not implemented in this notifier because we are always running inside * of Tcl_DoOneEvent. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Tcl_SetTimer( Tcl_Time *timePtr) /* Timeout value, may be NULL. */ { /* * The interval timer doesn't do anything in this implementation, because * the only event loop is via Tcl_DoOneEvent, which passes timeout values * to Tcl_WaitForEvent. */ if (tclStubs.tcl_SetTimer != tclOriginalNotifier.setTimerProc) { tclStubs.tcl_SetTimer(timePtr); } } /* *---------------------------------------------------------------------- * * Tcl_ServiceModeHook -- * * This function is invoked whenever the service mode changes. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Tcl_ServiceModeHook( int mode) /* Either TCL_SERVICE_ALL, or * TCL_SERVICE_NONE. */ { } /* *---------------------------------------------------------------------- * * Tcl_CreateFileHandler -- * * This function registers a file handler with the select notifier. * * Results: * None. * * Side effects: * Creates a new file handler structure. * *---------------------------------------------------------------------- */ void Tcl_CreateFileHandler( int fd, /* Handle of stream to watch. */ int mask, /* OR'ed combination of TCL_READABLE, * TCL_WRITABLE, and TCL_EXCEPTION: indicates * conditions under which proc should be * called. */ Tcl_FileProc *proc, /* Function to call for each selected * event. */ ClientData clientData) /* Arbitrary data to pass to proc. */ { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); FileHandler *filePtr; if (tclStubs.tcl_CreateFileHandler != tclOriginalNotifier.createFileHandlerProc) { tclStubs.tcl_CreateFileHandler(fd, mask, proc, clientData); return; } for (filePtr = tsdPtr->firstFileHandlerPtr; filePtr != NULL; filePtr = filePtr->nextPtr) { if (filePtr->fd == fd) { break; } } if (filePtr == NULL) { filePtr = (FileHandler*) ckalloc(sizeof(FileHandler)); filePtr->fd = fd; filePtr->readyMask = 0; filePtr->nextPtr = tsdPtr->firstFileHandlerPtr; tsdPtr->firstFileHandlerPtr = filePtr; } filePtr->proc = proc; filePtr->clientData = clientData; filePtr->mask = mask; /* * Update the check masks for this file. */ if (mask & TCL_READABLE) { FD_SET(fd, &(tsdPtr->checkMasks.readable)); } else { FD_CLR(fd, &(tsdPtr->checkMasks.readable)); } if (mask & TCL_WRITABLE) { FD_SET(fd, &(tsdPtr->checkMasks.writable)); } else { FD_CLR(fd, &(tsdPtr->checkMasks.writable)); } if (mask & TCL_EXCEPTION) { FD_SET(fd, &(tsdPtr->checkMasks.exceptional)); } else { FD_CLR(fd, &(tsdPtr->checkMasks.exceptional)); } if (tsdPtr->numFdBits <= fd) { tsdPtr->numFdBits = fd+1; } } /* *---------------------------------------------------------------------- * * Tcl_DeleteFileHandler -- * * Cancel a previously-arranged callback arrangement for a file. * * Results: * None. * * Side effects: * If a callback was previously registered on file, remove it. * *---------------------------------------------------------------------- */ void Tcl_DeleteFileHandler( int fd) /* Stream id for which to remove callback * function. */ { FileHandler *filePtr, *prevPtr; int i; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (tclStubs.tcl_DeleteFileHandler != tclOriginalNotifier.deleteFileHandlerProc) { tclStubs.tcl_DeleteFileHandler(fd); return; } /* * Find the entry for the given file (and return if there isn't one). */ for (prevPtr = NULL, filePtr = tsdPtr->firstFileHandlerPtr; ; prevPtr = filePtr, filePtr = filePtr->nextPtr) { if (filePtr == NULL) { return; } if (filePtr->fd == fd) { break; } } /* * Update the check masks for this file. */ if (filePtr->mask & TCL_READABLE) { FD_CLR(fd, &(tsdPtr->checkMasks.readable)); } if (filePtr->mask & TCL_WRITABLE) { FD_CLR(fd, &(tsdPtr->checkMasks.writable)); } if (filePtr->mask & TCL_EXCEPTION) { FD_CLR(fd, &(tsdPtr->checkMasks.exceptional)); } /* * Find current max fd. */ if (fd+1 == tsdPtr->numFdBits) { tsdPtr->numFdBits = 0; for (i = fd-1; i >= 0; i--) { if (FD_ISSET(i, &(tsdPtr->checkMasks.readable)) || FD_ISSET(i, &(tsdPtr->checkMasks.writable)) || FD_ISSET(i, &(tsdPtr->checkMasks.exceptional))) { tsdPtr->numFdBits = i+1; break; } } } /* * Clean up information in the callback record. */ if (prevPtr == NULL) { tsdPtr->firstFileHandlerPtr = filePtr->nextPtr; } else { prevPtr->nextPtr = filePtr->nextPtr; } ckfree((char *) filePtr); } /* *---------------------------------------------------------------------- * * FileHandlerEventProc -- * * This function is called by Tcl_ServiceEvent when a file event reaches * the front of the event queue. This function is responsible for * actually handling the event by invoking the callback for the file * handler. * * Results: * Returns 1 if the event was handled, meaning it should be removed from * the queue. Returns 0 if the event was not handled, meaning it should * stay on the queue. The only time the event isn't handled is if the * TCL_FILE_EVENTS flag bit isn't set. * * Side effects: * Whatever the file handler's callback function does. * *---------------------------------------------------------------------- */ static int FileHandlerEventProc( Tcl_Event *evPtr, /* Event to service. */ int flags) /* Flags that indicate what events to handle, * such as TCL_FILE_EVENTS. */ { int mask; FileHandler *filePtr; FileHandlerEvent *fileEvPtr = (FileHandlerEvent *) evPtr; ThreadSpecificData *tsdPtr; if (!(flags & TCL_FILE_EVENTS)) { return 0; } /* * Search through the file handlers to find the one whose handle matches * the event. We do this rather than keeping a pointer to the file handler * directly in the event, so that the handler can be deleted while the * event is queued without leaving a dangling pointer. */ tsdPtr = TCL_TSD_INIT(&dataKey); for (filePtr = tsdPtr->firstFileHandlerPtr; filePtr != NULL; filePtr = filePtr->nextPtr) { if (filePtr->fd != fileEvPtr->fd) { continue; } /* * The code is tricky for two reasons: * 1. The file handler's desired events could have changed since the * time when the event was queued, so AND the ready mask with the * desired mask. * 2. The file could have been closed and re-opened since the time * when the event was queued. This is why the ready mask is stored * in the file handler rather than the queued event: it will be * zeroed when a new file handler is created for the newly opened * file. */ mask = filePtr->readyMask & filePtr->mask; filePtr->readyMask = 0; if (mask != 0) { (*filePtr->proc)(filePtr->clientData, mask); } break; } return 1; } /* *---------------------------------------------------------------------- * * Tcl_WaitForEvent -- * * This function is called by Tcl_DoOneEvent to wait for new events on * the message queue. If the block time is 0, then Tcl_WaitForEvent just * polls without blocking. * * Results: * Returns -1 if the select would block forever, otherwise returns 0. * * Side effects: * Queues file events that are detected by the select. * *---------------------------------------------------------------------- */ int Tcl_WaitForEvent( Tcl_Time *timePtr) /* Maximum block time, or NULL. */ { FileHandler *filePtr; FileHandlerEvent *fileEvPtr; int mask; int waitForFiles; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (tclStubs.tcl_WaitForEvent != tclOriginalNotifier.waitForEventProc) { return tclStubs.tcl_WaitForEvent(timePtr); } /* * Start notifier thread if necessary. */ LOCK_NOTIFIER_INIT; if (!notifierCount) { Tcl_Panic("Tcl_WaitForEvent: notifier not initialized"); } if (!notifierThread) { int result; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); pthread_attr_setstacksize(&attr, 60 * 1024); result = pthread_create(¬ifierThread, &attr, (void * (*)(void *))NotifierThreadProc, NULL); pthread_attr_destroy(&attr); if (result || !notifierThread) { Tcl_Panic("Tcl_WaitForEvent: unable to start notifier thread"); } } UNLOCK_NOTIFIER_INIT; /* * Place this thread on the list of interested threads, signal the * notifier thread, and wait for a response or a timeout. */ LOCK_NOTIFIER; if (!tsdPtr->runLoop) { Tcl_Panic("Tcl_WaitForEvent: CFRunLoop not initialized"); } waitForFiles = (tsdPtr->numFdBits > 0); if (timePtr != NULL && timePtr->sec == 0 && timePtr->usec == 0) { /* * Cannot emulate a polling select with a polling condition variable. * Instead, pretend to wait for files and tell the notifier thread * what we are doing. The notifier thread makes sure it goes through * select with its select mask in the same state as ours currently is. * We block until that happens. */ waitForFiles = 1; tsdPtr->pollState = POLL_WANT; timePtr = NULL; } else { tsdPtr->pollState = 0; } if (waitForFiles) { /* * Add the ThreadSpecificData structure of this thread to the list of * ThreadSpecificData structures of all threads that are waiting on * file events. */ tsdPtr->nextPtr = waitingListPtr; if (waitingListPtr) { waitingListPtr->prevPtr = tsdPtr; } tsdPtr->prevPtr = 0; waitingListPtr = tsdPtr; tsdPtr->onList = 1; write(triggerPipe, "", 1); } FD_ZERO(&(tsdPtr->readyMasks.readable)); FD_ZERO(&(tsdPtr->readyMasks.writable)); FD_ZERO(&(tsdPtr->readyMasks.exceptional)); if (!tsdPtr->eventReady) { CFTimeInterval waitTime; CFStringRef runLoopMode; if (timePtr == NULL) { waitTime = 1.0e10; /* Wait forever, as per CFRunLoop.c */ } else { waitTime = timePtr->sec + 1.0e-6 * timePtr->usec; } /* * If the run loop is already running (e.g. if Tcl_WaitForEvent was * called recursively), re-run it in a custom run loop mode containing * only the source for the notifier thread, otherwise wakeups from other * sources added to the common run loop modes might get lost. */ if ((runLoopMode = CFRunLoopCopyCurrentMode(tsdPtr->runLoop))) { CFRelease(runLoopMode); runLoopMode = tclEventsOnlyRunLoopMode; } else { runLoopMode = kCFRunLoopDefaultMode; } UNLOCK_NOTIFIER; CFRunLoopRunInMode(runLoopMode, waitTime, TRUE); LOCK_NOTIFIER; } tsdPtr->eventReady = 0; if (waitForFiles && tsdPtr->onList) { /* * Remove the ThreadSpecificData structure of this thread from the * waiting list. Alert the notifier thread to recompute its select * masks - skipping this caused a hang when trying to close a pipe * which the notifier thread was still doing a select on. */ if (tsdPtr->prevPtr) { tsdPtr->prevPtr->nextPtr = tsdPtr->nextPtr; } else { waitingListPtr = tsdPtr->nextPtr; } if (tsdPtr->nextPtr) { tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr; } tsdPtr->nextPtr = tsdPtr->prevPtr = NULL; tsdPtr->onList = 0; write(triggerPipe, "", 1); } /* * Queue all detected file events before returning. */ for (filePtr = tsdPtr->firstFileHandlerPtr; (filePtr != NULL); filePtr = filePtr->nextPtr) { mask = 0; if (FD_ISSET(filePtr->fd, &(tsdPtr->readyMasks.readable))) { mask |= TCL_READABLE; } if (FD_ISSET(filePtr->fd, &(tsdPtr->readyMasks.writable))) { mask |= TCL_WRITABLE; } if (FD_ISSET(filePtr->fd, &(tsdPtr->readyMasks.exceptional))) { mask |= TCL_EXCEPTION; } if (!mask) { continue; } /* * Don't bother to queue an event if the mask was previously non-zero * since an event must still be on the queue. */ if (filePtr->readyMask == 0) { fileEvPtr = (FileHandlerEvent *) ckalloc(sizeof(FileHandlerEvent)); fileEvPtr->header.proc = FileHandlerEventProc; fileEvPtr->fd = filePtr->fd; Tcl_QueueEvent((Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL); } filePtr->readyMask = mask; } UNLOCK_NOTIFIER; return 0; } /* *---------------------------------------------------------------------- * * NotifierThreadProc -- * * This routine is the initial (and only) function executed by the * special notifier thread. Its job is to wait for file descriptors to * become readable or writable or to have an exception condition and then * to notify other threads who are interested in this information by * signalling a condition variable. Other threads can signal this * notifier thread of a change in their interests by writing a single * byte to a special pipe that the notifier thread is monitoring. * * Result: * None. Once started, this routine never exits. It dies with the overall * process. * * Side effects: * The trigger pipe used to signal the notifier thread is created when * the notifier thread first starts. * *---------------------------------------------------------------------- */ static void NotifierThreadProc( ClientData clientData) /* Not used. */ { ThreadSpecificData *tsdPtr; fd_set readableMask; fd_set writableMask; fd_set exceptionalMask; int i, numFdBits = 0; long found; struct timeval poll = {0., 0.}, *timePtr; char buf[2]; /* * Look for file events and report them to interested threads. */ while (1) { FD_ZERO(&readableMask); FD_ZERO(&writableMask); FD_ZERO(&exceptionalMask); /* * Compute the logical OR of the select masks from all the waiting * notifiers. */ LOCK_NOTIFIER; timePtr = NULL; for (tsdPtr = waitingListPtr; tsdPtr; tsdPtr = tsdPtr->nextPtr) { for (i = tsdPtr->numFdBits-1; i >= 0; --i) { if (FD_ISSET(i, &(tsdPtr->checkMasks.readable))) { FD_SET(i, &readableMask); } if (FD_ISSET(i, &(tsdPtr->checkMasks.writable))) { FD_SET(i, &writableMask); } if (FD_ISSET(i, &(tsdPtr->checkMasks.exceptional))) { FD_SET(i, &exceptionalMask); } } if (tsdPtr->numFdBits > numFdBits) { numFdBits = tsdPtr->numFdBits; } if (tsdPtr->pollState & POLL_WANT) { /* * Here we make sure we go through select() with the same mask * bits that were present when the thread tried to poll. */ tsdPtr->pollState |= POLL_DONE; timePtr = &poll; } } UNLOCK_NOTIFIER; /* * Set up the select mask to include the receive pipe. */ if (receivePipe >= numFdBits) { numFdBits = receivePipe + 1; } FD_SET(receivePipe, &readableMask); if (select(numFdBits, &readableMask, &writableMask, &exceptionalMask, timePtr) == -1) { /* * Try again immediately on an error. */ continue; } /* * Alert any threads that are waiting on a ready file descriptor. */ LOCK_NOTIFIER; for (tsdPtr = waitingListPtr; tsdPtr; tsdPtr = tsdPtr->nextPtr) { found = 0; for (i = tsdPtr->numFdBits-1; i >= 0; --i) { if (FD_ISSET(i, &(tsdPtr->checkMasks.readable)) && FD_ISSET(i, &readableMask)) { FD_SET(i, &(tsdPtr->readyMasks.readable)); found = 1; } if (FD_ISSET(i, &(tsdPtr->checkMasks.writable)) && FD_ISSET(i, &writableMask)) { FD_SET(i, &(tsdPtr->readyMasks.writable)); found = 1; } if (FD_ISSET(i, &(tsdPtr->checkMasks.exceptional)) && FD_ISSET(i, &exceptionalMask)) { FD_SET(i, &(tsdPtr->readyMasks.exceptional)); found = 1; } } if (found || (tsdPtr->pollState & POLL_DONE)) { tsdPtr->eventReady = 1; if (tsdPtr->onList) { /* * Remove the ThreadSpecificData structure of this thread * from the waiting list. This prevents us from * continuously spining on select until the other threads * runs and services the file event. */ if (tsdPtr->prevPtr) { tsdPtr->prevPtr->nextPtr = tsdPtr->nextPtr; } else { waitingListPtr = tsdPtr->nextPtr; } if (tsdPtr->nextPtr) { tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr; } tsdPtr->nextPtr = tsdPtr->prevPtr = NULL; tsdPtr->onList = 0; tsdPtr->pollState = 0; } if (tsdPtr->runLoop) { CFRunLoopSourceSignal(tsdPtr->runLoopSource); CFRunLoopWakeUp(tsdPtr->runLoop); } } } UNLOCK_NOTIFIER; /* * Consume the next byte from the notifier pipe if the pipe was * readable. Note that there may be multiple bytes pending, but to * avoid a race condition we only read one at a time. */ if (FD_ISSET(receivePipe, &readableMask)) { i = read(receivePipe, buf, 1); if ((i == 0) || ((i == 1) && (buf[0] == 'q'))) { /* * Someone closed the write end of the pipe or sent us a Quit * message [Bug: 4139] and then closed the write end of the * pipe so we need to shut down the notifier thread. */ break; } } } pthread_exit(0); } #ifdef HAVE_PTHREAD_ATFORK /* *---------------------------------------------------------------------- * * AtForkPrepare -- * * Lock the notifier in preparation for a fork. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void AtForkPrepare(void) { LOCK_NOTIFIER_INIT; LOCK_NOTIFIER; } /* *---------------------------------------------------------------------- * * AtForkParent -- * * Unlock the notifier in the parent after a fork. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void AtForkParent(void) { UNLOCK_NOTIFIER; UNLOCK_NOTIFIER_INIT; } /* *---------------------------------------------------------------------- * * AtForkChild -- * * Unlock and reinstall the notifier in the child after a fork. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void AtForkChild(void) { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); UNLOCK_NOTIFIER; UNLOCK_NOTIFIER_INIT; if (tsdPtr->runLoop) { tsdPtr->runLoop = NULL; if (!noCFafterFork) { CFRunLoopSourceInvalidate(tsdPtr->runLoopSource); } CFRelease(tsdPtr->runLoopSource); tsdPtr->runLoopSource = NULL; } if (notifierCount > 0) { notifierCount = 0; /* * Assume that the return value of Tcl_InitNotifier in the child will * be identical to the one stored as clientData in tclNotify.c's * ThreadSpecificData by the parent's TclInitNotifier, so discard the * return value here. This assumption may require the fork() to be * executed in the main thread of the parent, otherwise * Tcl_AlertNotifier may break in the child. */ if (!noCFafterFork) { Tcl_InitNotifier(); } } } #endif /* HAVE_PTHREAD_ATFORK */ #endif /* HAVE_COREFOUNDATION */ tcl8.4.20/macosx/Tcl.pbproj/0000755003604700454610000000000012153151143014210 5ustar dgp771divtcl8.4.20/macosx/Tcl.pbproj/jingham.pbxuser0000644003604700454610000001026111737050674017255 0ustar dgp771div// !$*UTF8*$! { 00E2F845016E82EB0ACA28DC = { activeBuildStyle = 00E2F847016E82EB0ACA28DC; activeExecutable = F594E5F1030774B1016F146B; activeTarget = 00E2F84C016E8B780ACA28DC; addToTargets = ( ); codeSenseManager = F9D167E40610239A0027C147; executables = ( F53ACC52031D9AFE016F146B, F594E5F1030774B1016F146B, ); sourceControlManager = F9D167E30610239A0027C147; userBuildSettings = { SYMROOT = "${SRCROOT}/../../build/tcl"; }; }; 00E2F84C016E8B780ACA28DC = { activeExec = 0; }; F53ACC52031D9AFE016F146B = { activeArgIndex = 2147483647; activeArgIndices = ( NO, NO, ); argumentStrings = ( "${SRCROOT}/../../tcl/tests/all.tcl", "-verbose \"\"", ); configStateDict = { "PBXLSLaunchAction-0" = { PBXLSLaunchAction = 0; PBXLSLaunchStartAction = 1; PBXLSLaunchStdioStyle = 2; PBXLSLaunchStyle = 0; class = PBXLSRunLaunchConfig; displayName = "Executable Runner"; identifier = com.apple.Xcode.launch.runConfig; remoteHostInfo = ""; startActionInfo = ""; }; "PBXLSLaunchAction-1" = { PBXLSLaunchAction = 1; PBXLSLaunchStartAction = 1; PBXLSLaunchStdioStyle = 2; PBXLSLaunchStyle = 0; class = PBXGDB_LaunchConfig; displayName = GDB; identifier = com.apple.Xcode.launch.GDBMI_Config; remoteHostInfo = ""; startActionInfo = ""; }; }; cppStopOnCatchEnabled = 0; cppStopOnThrowEnabled = 0; customDataFormattersEnabled = 1; debuggerPlugin = GDBDebugging; disassemblyDisplayState = 0; dylibVariantSuffix = _debug; enableDebugStr = 0; environmentEntries = ( { active = YES; name = TCL_LIBRARY; value = "${SRCROOT}/../../tcl/library"; }, { active = NO; name = DYLD_PRINT_LIBRARIES; }, ); isa = PBXExecutable; launchableReference = F5C37CF303D5BEDF016F146B; libgmallocEnabled = 0; name = tcltest; shlibInfoDictList = ( ); sourceDirectories = ( ); startupPath = "<>"; }; F594E5F1030774B1016F146B = { activeArgIndex = 2147483647; activeArgIndices = ( ); argumentStrings = ( ); configStateDict = { "PBXLSLaunchAction-0" = { PBXLSLaunchAction = 0; PBXLSLaunchStartAction = 1; PBXLSLaunchStdioStyle = 2; PBXLSLaunchStyle = 0; class = PBXLSRunLaunchConfig; displayName = "Executable Runner"; identifier = com.apple.Xcode.launch.runConfig; remoteHostInfo = ""; startActionInfo = ""; }; "PBXLSLaunchAction-1" = { PBXLSLaunchAction = 1; PBXLSLaunchStartAction = 1; PBXLSLaunchStdioStyle = 2; PBXLSLaunchStyle = 0; class = PBXGDB_LaunchConfig; displayName = GDB; identifier = com.apple.Xcode.launch.GDBMI_Config; remoteHostInfo = ""; startActionInfo = ""; }; }; cppStopOnCatchEnabled = 0; cppStopOnThrowEnabled = 0; customDataFormattersEnabled = 1; debuggerPlugin = GDBDebugging; disassemblyDisplayState = 0; dylibVariantSuffix = _debug; enableDebugStr = 0; environmentEntries = ( { active = NO; name = DYLD_PRINT_LIBRARIES; }, ); isa = PBXExecutable; launchableReference = F98F02E608E7EF9A00D0320A; libgmallocEnabled = 0; name = tclsh; shlibInfoDictList = ( ); sourceDirectories = ( ); startupPath = "<>"; }; F5C37CF303D5BEDF016F146B = { isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; path = tcltest; refType = 3; sourceTree = BUILT_PRODUCTS_DIR; }; F98F02E608E7EF9A00D0320A = { isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; path = tclsh8.4; refType = 3; sourceTree = BUILT_PRODUCTS_DIR; }; F9D167E30610239A0027C147 = { fallbackIsa = XCSourceControlManager; isSCMEnabled = 0; isa = PBXSourceControlManager; scmConfiguration = { }; scmType = scm.cvs; }; F9D167E40610239A0027C147 = { indexTemplatePath = ""; isa = PBXCodeSenseManager; usesDefaults = 1; wantsCodeCompletion = 1; wantsCodeCompletionAutoSuggestions = 1; wantsCodeCompletionCaseSensitivity = 1; wantsCodeCompletionListAlways = 1; wantsCodeCompletionOnlyMatchingItems = 1; wantsCodeCompletionParametersIncluded = 1; wantsCodeCompletionPlaceholdersInserted = 1; wantsCodeCompletionTabCompletes = 1; wantsIndex = 1; }; } tcl8.4.20/macosx/Tcl.pbproj/project.pbxproj0000644003604700454610000011213011737050674017300 0ustar dgp771div// !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 39; objects = { 00E2F845016E82EB0ACA28DC = { buildSettings = { }; buildStyles = ( 00E2F847016E82EB0ACA28DC, 00E2F848016E82EB0ACA28DC, ); hasScannedForEncodings = 1; isa = PBXProject; mainGroup = 00E2F846016E82EB0ACA28DC; productRefGroup = 00E2F84A016E8A830ACA28DC; projectDirPath = ""; targets = ( 00E2F84C016E8B780ACA28DC, ); }; 00E2F846016E82EB0ACA28DC = { children = ( F5306CA003CAC9AE016F146B, F5306C9F03CAC979016F146B, F5C88655017D604601DC9062, F5F24FEE016ED0DF01DC9062, 00E2F855016E922C0ACA28DC, 00E2F857016E92B00ACA28DC, 00E2F85A016E92B00ACA28DC, 00E2F84A016E8A830ACA28DC, ); isa = PBXGroup; refType = 4; sourceTree = ""; }; 00E2F847016E82EB0ACA28DC = { buildSettings = { MAKE_TARGET = develop; }; isa = PBXBuildStyle; name = Development; }; 00E2F848016E82EB0ACA28DC = { buildSettings = { MAKE_TARGET = deploy; }; isa = PBXBuildStyle; name = Deployment; }; 00E2F84A016E8A830ACA28DC = { children = ( F53ACC73031DA405016F146B, F53ACC5C031D9D11016F146B, F9A61C9D04C2B4E3006F5A0B, ); isa = PBXGroup; name = Products; refType = 4; sourceTree = ""; }; 00E2F84C016E8B780ACA28DC = { buildArgumentsString = "-c \"cd \\\"${TCL_SRCROOT}/macosx\\\" && ACTION=${ACTION} && gnumake \\${ACTION:+\\${ACTION/clean/distclean}-}${MAKE_TARGET} INSTALL_ROOT=\\\"${DSTROOT}\\\" INSTALL_PATH=\\\"${INSTALL_PATH}\\\" PREFIX=\\\"${PREFIX}\\\" BINDIR=\\\"${BINDIR}\\\" MANDIR=\\\"${MANDIR}\\\" \\${EXTRA_MAKE_FLAGS} ${ALL_SETTINGS}\""; buildPhases = ( ); buildSettings = { BINDIR = "${PREFIX}/bin"; INSTALL_PATH = /Library/Frameworks; MANDIR = "${PREFIX}/man"; PREFIX = /usr/local; PRODUCT_NAME = Tcl; TCL_SRCROOT = "${SRCROOT}/../../tcl"; TEMP_DIR = "${PROJECT_TEMP_DIR}"; }; buildToolPath = /bin/bash; buildWorkingDirectory = "${SRCROOT}"; dependencies = ( ); isa = PBXLegacyTarget; name = Tcl; passBuildSettingsInEnvironment = 0; productName = Tcl; }; 00E2F854016E922C0ACA28DC = { children = ( F5F24F87016ECAFC01DC9062, F5F24F88016ECAFC01DC9062, F5F24F89016ECAFC01DC9062, F5F24F8A016ECAFC01DC9062, F5F24F8B016ECAFC01DC9062, F5F24F8C016ECAFC01DC9062, F5F24F8D016ECAFC01DC9062, F5F24F8E016ECAFC01DC9062, F5F24F8F016ECAFC01DC9062, F5F24F90016ECAFC01DC9062, F5F24F91016ECAFC01DC9062, F5F24F92016ECAFC01DC9062, F5F24F93016ECAFC01DC9062, F5F24F94016ECAFC01DC9062, F5F24F95016ECAFC01DC9062, F5F24F96016ECAFC01DC9062, F5F24F97016ECAFC01DC9062, F5F24F98016ECAFC01DC9062, F5F24F99016ECAFC01DC9062, F5F24F9A016ECAFC01DC9062, F5F24F9B016ECAFC01DC9062, F5F24F9C016ECAFC01DC9062, F5F24F9D016ECAFC01DC9062, F5F24F9E016ECAFC01DC9062, F5F24F9F016ECAFC01DC9062, F5F24FA0016ECAFC01DC9062, F5F24FA1016ECAFC01DC9062, F5F24FA2016ECAFC01DC9062, F5F24FA3016ECAFC01DC9062, F5F24FA4016ECAFC01DC9062, F5F24FA5016ECAFC01DC9062, F5F24FA6016ECAFC01DC9062, F5F24FA7016ECAFC01DC9062, F5F24FA8016ECAFC01DC9062, F5F24FA9016ECAFC01DC9062, F5F24FAA016ECAFC01DC9062, F5F24FAB016ECAFC01DC9062, F5F24FAC016ECAFC01DC9062, F5F24FAD016ECAFC01DC9062, F5F24FAE016ECAFC01DC9062, F5F24FAF016ECAFC01DC9062, F5F24FB0016ECAFC01DC9062, F5F24FB1016ECAFC01DC9062, F5F24FB2016ECAFC01DC9062, F5F24FB3016ECAFC01DC9062, F5F24FB4016ECAFC01DC9062, F5F24FB5016ECAFC01DC9062, F5F24FB6016ECAFC01DC9062, F5F24FB7016ECAFC01DC9062, F5F24FB8016ECAFC01DC9062, F5F24FB9016ECAFC01DC9062, F5F24FBA016ECAFC01DC9062, F5F24FBB016ECAFC01DC9062, F5F24FD3016ECB4901DC9062, F5F24FBC016ECAFC01DC9062, F5F24FBD016ECAFC01DC9062, F5F24FBE016ECAFC01DC9062, F5F24FBF016ECAFC01DC9062, F5F24FC0016ECAFC01DC9062, F5F24FC1016ECAFC01DC9062, F5F24FC2016ECAFC01DC9062, F5F24FC3016ECAFC01DC9062, F5F24FC4016ECAFC01DC9062, F5F24FC5016ECAFC01DC9062, F5F24FC6016ECAFC01DC9062, F5F24FC7016ECAFC01DC9062, F5F24FC8016ECAFC01DC9062, F5F24FC9016ECAFC01DC9062, F5F24FCA016ECAFC01DC9062, F5F24FCB016ECAFC01DC9062, F5F24FCC016ECAFC01DC9062, F5F24FCD016ECAFC01DC9062, F5F24FCE016ECAFC01DC9062, F5F24FCF016ECAFC01DC9062, F5F24FD0016ECAFC01DC9062, ); isa = PBXGroup; name = Sources; path = ""; refType = 4; sourceTree = ""; }; 00E2F855016E922C0ACA28DC = { children = ( 00E2F856016E92B00ACA28DC, 00E2F854016E922C0ACA28DC, ); isa = PBXGroup; name = generic; refType = 4; sourceTree = ""; }; 00E2F856016E92B00ACA28DC = { children = ( F5F24F6B016ECAA401DC9062, F5F24F6C016ECAA401DC9062, F5F24F6D016ECAA401DC9062, F5F24F6E016ECAA401DC9062, F5F24F6F016ECAA401DC9062, F5F24F70016ECAA401DC9062, F5F24F71016ECAA401DC9062, F5F24F72016ECAA401DC9062, F5F24F73016ECAA401DC9062, F5F24F74016ECAA401DC9062, F5F24F75016ECAA401DC9062, F5F24F76016ECAA401DC9062, F5F24F77016ECAA401DC9062, F5F24F78016ECAA401DC9062, F5F24FD1016ECB1E01DC9062, F5F24FD2016ECB1E01DC9062, ); isa = PBXGroup; name = Headers; refType = 4; sourceTree = ""; }; 00E2F857016E92B00ACA28DC = { children = ( 00E2F858016E92B00ACA28DC, 00E2F859016E92B00ACA28DC, ); isa = PBXGroup; name = macosx; refType = 4; sourceTree = ""; }; 00E2F858016E92B00ACA28DC = { children = ( ); isa = PBXGroup; name = Headers; refType = 4; sourceTree = ""; }; 00E2F859016E92B00ACA28DC = { children = ( F5A1836F018242A501DC9062, ); isa = PBXGroup; name = Sources; refType = 4; sourceTree = ""; }; 00E2F85A016E92B00ACA28DC = { children = ( 00E2F85B016E92B00ACA28DC, 00E2F85C016E92B00ACA28DC, ); isa = PBXGroup; name = unix; refType = 4; sourceTree = ""; }; 00E2F85B016E92B00ACA28DC = { children = ( F5F24FD6016ECC0F01DC9062, F5F24FD7016ECC0F01DC9062, ); isa = PBXGroup; name = Headers; refType = 4; sourceTree = ""; }; 00E2F85C016E92B00ACA28DC = { children = ( F5F24FD8016ECC0F01DC9062, F5F24FD9016ECC0F01DC9062, F5F24FDB016ECC0F01DC9062, F5F24FDC016ECC0F01DC9062, F5F24FDD016ECC0F01DC9062, F5F24FDE016ECC0F01DC9062, F5F24FDF016ECC0F01DC9062, F5F24FE0016ECC0F01DC9062, F5F24FE1016ECC0F01DC9062, F5F24FE2016ECC0F01DC9062, F5F24FE3016ECC0F01DC9062, F5F24FE4016ECC0F01DC9062, F5F24FE5016ECC0F01DC9062, F5F24FE6016ECC0F01DC9062, F5F24FE7016ECC0F01DC9062, ); isa = PBXGroup; name = Sources; refType = 4; sourceTree = ""; }; //000 //001 //002 //003 //004 //F50 //F51 //F52 //F53 //F54 F5306C9F03CAC979016F146B = { children = ( F5306CA303CAC9DE016F146B, F5306CA103CAC9DE016F146B, F5306CA203CAC9DE016F146B, ); isa = PBXGroup; name = "Build System"; refType = 4; sourceTree = ""; }; F5306CA003CAC9AE016F146B = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = text; name = ChangeLog; path = ../ChangeLog; refType = 2; sourceTree = SOURCE_ROOT; }; F5306CA103CAC9DE016F146B = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = text.script.sh; name = configure.in; path = ../unix/configure.in; refType = 2; sourceTree = SOURCE_ROOT; }; F5306CA203CAC9DE016F146B = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = text; name = Makefile.in; path = ../unix/Makefile.in; refType = 2; sourceTree = SOURCE_ROOT; }; F5306CA303CAC9DE016F146B = { isa = PBXFileReference; lastKnownFileType = text; name = tcl.m4; path = ../unix/tcl.m4; refType = 2; sourceTree = SOURCE_ROOT; }; F53ACC5C031D9D11016F146B = { isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; path = tclsh8.4; refType = 3; sourceTree = BUILT_PRODUCTS_DIR; }; F53ACC73031DA405016F146B = { isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; path = tcltest; refType = 3; sourceTree = BUILT_PRODUCTS_DIR; }; F5A1836F018242A501DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = tclMacOSXBundle.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5C88655017D604601DC9062 = { children = ( F5C88656017D604601DC9062, F5C88657017D60C901DC9062, F5C88658017D60C901DC9062, ); isa = PBXGroup; name = "Header Tools"; refType = 4; sourceTree = ""; }; F5C88656017D604601DC9062 = { isa = PBXFileReference; lastKnownFileType = text; name = genStubs.tcl; path = ../tools/genStubs.tcl; refType = 2; sourceTree = SOURCE_ROOT; }; F5C88657017D60C901DC9062 = { isa = PBXFileReference; lastKnownFileType = text; name = tcl.decls; path = ../generic/tcl.decls; refType = 2; sourceTree = SOURCE_ROOT; }; F5C88658017D60C901DC9062 = { isa = PBXFileReference; lastKnownFileType = text; name = tclInt.decls; path = ../generic/tclInt.decls; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24F6B016ECAA401DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = regcustom.h; path = ../generic/regcustom.h; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24F6C016ECAA401DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = regerrs.h; path = ../generic/regerrs.h; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24F6D016ECAA401DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = regguts.h; path = ../generic/regguts.h; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24F6E016ECAA401DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = tcl.h; path = ../generic/tcl.h; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24F6F016ECAA401DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = tclCompile.h; path = ../generic/tclCompile.h; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24F70016ECAA401DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = tclDecls.h; path = ../generic/tclDecls.h; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24F71016ECAA401DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = tclInitScript.h; path = ../generic/tclInitScript.h; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24F72016ECAA401DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = tclInt.h; path = ../generic/tclInt.h; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24F73016ECAA401DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = tclIntDecls.h; path = ../generic/tclIntDecls.h; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24F74016ECAA401DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = tclIntPlatDecls.h; path = ../generic/tclIntPlatDecls.h; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24F75016ECAA401DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = tclIO.h; path = ../generic/tclIO.h; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24F76016ECAA401DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = tclMath.h; path = ../generic/tclMath.h; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24F77016ECAA401DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = tclPlatDecls.h; path = ../generic/tclPlatDecls.h; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24F78016ECAA401DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = tclRegexp.h; path = ../generic/tclRegexp.h; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24F87016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = regc_color.c; path = ../generic/regc_color.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24F88016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = regc_cvec.c; path = ../generic/regc_cvec.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24F89016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = regc_lex.c; path = ../generic/regc_lex.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24F8A016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = regc_locale.c; path = ../generic/regc_locale.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24F8B016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = regc_nfa.c; path = ../generic/regc_nfa.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24F8C016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = regcomp.c; path = ../generic/regcomp.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24F8D016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = rege_dfa.c; path = ../generic/rege_dfa.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24F8E016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = regerror.c; path = ../generic/regerror.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24F8F016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = regexec.c; path = ../generic/regexec.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24F90016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = regfree.c; path = ../generic/regfree.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24F91016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = regfronts.c; path = ../generic/regfronts.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24F92016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclAlloc.c; path = ../generic/tclAlloc.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24F93016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclAsync.c; path = ../generic/tclAsync.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24F94016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclBasic.c; path = ../generic/tclBasic.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24F95016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclBinary.c; path = ../generic/tclBinary.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24F96016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclCkalloc.c; path = ../generic/tclCkalloc.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24F97016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclClock.c; path = ../generic/tclClock.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24F98016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclCmdAH.c; path = ../generic/tclCmdAH.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24F99016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclCmdIL.c; path = ../generic/tclCmdIL.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24F9A016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclCmdMZ.c; path = ../generic/tclCmdMZ.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24F9B016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclCompCmds.c; path = ../generic/tclCompCmds.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24F9C016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclCompExpr.c; path = ../generic/tclCompExpr.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24F9D016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclCompile.c; path = ../generic/tclCompile.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24F9E016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclDate.c; path = ../generic/tclDate.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24F9F016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclEncoding.c; path = ../generic/tclEncoding.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FA0016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclEnv.c; path = ../generic/tclEnv.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FA1016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclEvent.c; path = ../generic/tclEvent.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FA2016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclExecute.c; path = ../generic/tclExecute.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FA3016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclFCmd.c; path = ../generic/tclFCmd.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FA4016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclFileName.c; path = ../generic/tclFileName.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FA5016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclGet.c; path = ../generic/tclGet.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FA6016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclHash.c; path = ../generic/tclHash.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FA7016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclHistory.c; path = ../generic/tclHistory.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FA8016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclIndexObj.c; path = ../generic/tclIndexObj.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FA9016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclInterp.c; path = ../generic/tclInterp.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FAA016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclIO.c; path = ../generic/tclIO.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FAB016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclIOCmd.c; path = ../generic/tclIOCmd.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FAC016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclIOGT.c; path = ../generic/tclIOGT.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FAD016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclIOSock.c; path = ../generic/tclIOSock.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FAE016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclIOUtil.c; path = ../generic/tclIOUtil.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FAF016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclLink.c; path = ../generic/tclLink.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FB0016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclListObj.c; path = ../generic/tclListObj.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FB1016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclLiteral.c; path = ../generic/tclLiteral.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FB2016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclLoad.c; path = ../generic/tclLoad.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FB3016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclLoadNone.c; path = ../generic/tclLoadNone.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FB4016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclMain.c; path = ../generic/tclMain.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FB5016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclNamesp.c; path = ../generic/tclNamesp.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FB6016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclNotify.c; path = ../generic/tclNotify.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FB7016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclObj.c; path = ../generic/tclObj.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FB8016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclPanic.c; path = ../generic/tclPanic.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FB9016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclParse.c; path = ../generic/tclParse.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FBA016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclParseExpr.c; path = ../generic/tclParseExpr.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FBB016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclPipe.c; path = ../generic/tclPipe.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FBC016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclPosixStr.c; path = ../generic/tclPosixStr.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FBD016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclPreserve.c; path = ../generic/tclPreserve.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FBE016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclProc.c; path = ../generic/tclProc.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FBF016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclRegexp.c; path = ../generic/tclRegexp.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FC0016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclResolve.c; path = ../generic/tclResolve.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FC1016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclResult.c; path = ../generic/tclResult.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FC2016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclScan.c; path = ../generic/tclScan.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FC3016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclStringObj.c; path = ../generic/tclStringObj.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FC4016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclStubInit.c; path = ../generic/tclStubInit.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FC5016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclStubLib.c; path = ../generic/tclStubLib.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FC6016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclTest.c; path = ../generic/tclTest.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FC7016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclTestObj.c; path = ../generic/tclTestObj.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FC8016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclTestProcBodyObj.c; path = ../generic/tclTestProcBodyObj.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FC9016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclThread.c; path = ../generic/tclThread.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FCA016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclThreadJoin.c; path = ../generic/tclThreadJoin.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FCB016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclThreadTest.c; path = ../generic/tclThreadTest.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FCC016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclTimer.c; path = ../generic/tclTimer.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FCD016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclUniData.c; path = ../generic/tclUniData.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FCE016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclUtf.c; path = ../generic/tclUtf.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FCF016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclUtil.c; path = ../generic/tclUtil.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FD0016ECAFC01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclVar.c; path = ../generic/tclVar.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FD1016ECB1E01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = regex.h; path = ../generic/regex.h; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FD2016ECB1E01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = tclPort.h; path = ../generic/tclPort.h; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FD3016ECB4901DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclPkg.c; path = ../generic/tclPkg.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FD6016ECC0F01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = tclUnixPort.h; path = ../unix/tclUnixPort.h; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FD7016ECC0F01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = tclUnixThrd.h; path = ../unix/tclUnixThrd.h; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FD8016ECC0F01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclAppInit.c; path = ../unix/tclAppInit.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FD9016ECC0F01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclLoadDyld.c; path = ../unix/tclLoadDyld.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FDB016ECC0F01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclUnixChan.c; path = ../unix/tclUnixChan.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FDC016ECC0F01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclUnixEvent.c; path = ../unix/tclUnixEvent.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FDD016ECC0F01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclUnixFCmd.c; path = ../unix/tclUnixFCmd.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FDE016ECC0F01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclUnixFile.c; path = ../unix/tclUnixFile.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FDF016ECC0F01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclUnixInit.c; path = ../unix/tclUnixInit.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FE0016ECC0F01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclUnixNotfy.c; path = ../unix/tclUnixNotfy.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FE1016ECC0F01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclUnixPipe.c; path = ../unix/tclUnixPipe.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FE2016ECC0F01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclUnixSock.c; path = ../unix/tclUnixSock.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FE3016ECC0F01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclUnixTest.c; path = ../unix/tclUnixTest.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FE4016ECC0F01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclUnixThrd.c; path = ../unix/tclUnixThrd.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FE5016ECC0F01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclUnixTime.c; path = ../unix/tclUnixTime.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FE6016ECC0F01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclXtNotify.c; path = ../unix/tclXtNotify.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FE7016ECC0F01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tclXtTest.c; path = ../unix/tclXtTest.c; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FEE016ED0DF01DC9062 = { children = ( F5F24FEF016ED0DF01DC9062, F5F24FF0016ED0DF01DC9062, F5F24FF3016ED0DF01DC9062, F5F24FF4016ED0DF01DC9062, F5F24FF5016ED0DF01DC9062, F5F24FF6016ED0DF01DC9062, F5F24FFA016ED0DF01DC9062, F5F24FFB016ED0DF01DC9062, F5F24FFC016ED0DF01DC9062, F5F24FFE016ED0DF01DC9062, F5F25001016ED0DF01DC9062, F5F25002016ED0DF01DC9062, F5F25003016ED0DF01DC9062, F5F25005016ED0DF01DC9062, F5F25007016ED0DF01DC9062, F5F25008016ED0DF01DC9062, F5F2500A016ED0DF01DC9062, ); isa = PBXGroup; name = Scripts; refType = 4; sourceTree = ""; }; F5F24FEF016ED0DF01DC9062 = { isa = PBXFileReference; lastKnownFileType = text; name = auto.tcl; path = ../library/auto.tcl; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FF0016ED0DF01DC9062 = { includeInIndex = 0; isa = PBXFileReference; lastKnownFileType = folder; name = dde; path = ../library/dde; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FF3016ED0DF01DC9062 = { includeInIndex = 0; isa = PBXFileReference; lastKnownFileType = folder; name = encoding; path = ../library/encoding; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FF4016ED0DF01DC9062 = { isa = PBXFileReference; lastKnownFileType = text; name = history.tcl; path = ../library/history.tcl; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FF5016ED0DF01DC9062 = { includeInIndex = 0; isa = PBXFileReference; lastKnownFileType = folder; name = http; path = ../library/http; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FF6016ED0DF01DC9062 = { includeInIndex = 0; isa = PBXFileReference; lastKnownFileType = folder; name = http1.0; path = ../library/http1.0; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FFA016ED0DF01DC9062 = { isa = PBXFileReference; lastKnownFileType = text; name = init.tcl; path = ../library/init.tcl; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FFB016ED0DF01DC9062 = { isa = PBXFileReference; lastKnownFileType = text; name = ldAout.tcl; path = ../library/ldAout.tcl; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FFC016ED0DF01DC9062 = { includeInIndex = 0; isa = PBXFileReference; lastKnownFileType = folder; name = msgcat; path = ../library/msgcat; refType = 2; sourceTree = SOURCE_ROOT; }; F5F24FFE016ED0DF01DC9062 = { includeInIndex = 0; isa = PBXFileReference; lastKnownFileType = folder; name = opt; path = ../library/opt; refType = 2; sourceTree = SOURCE_ROOT; }; F5F25001016ED0DF01DC9062 = { isa = PBXFileReference; lastKnownFileType = text; name = package.tcl; path = ../library/package.tcl; refType = 2; sourceTree = SOURCE_ROOT; }; F5F25002016ED0DF01DC9062 = { isa = PBXFileReference; lastKnownFileType = text; name = parray.tcl; path = ../library/parray.tcl; refType = 2; sourceTree = SOURCE_ROOT; }; F5F25003016ED0DF01DC9062 = { includeInIndex = 0; isa = PBXFileReference; lastKnownFileType = folder; name = reg; path = ../library/reg; refType = 2; sourceTree = SOURCE_ROOT; }; F5F25005016ED0DF01DC9062 = { isa = PBXFileReference; lastKnownFileType = text; name = safe.tcl; path = ../library/safe.tcl; refType = 2; sourceTree = SOURCE_ROOT; }; F5F25007016ED0DF01DC9062 = { fileEncoding = 5; isa = PBXFileReference; lastKnownFileType = text; name = tclIndex; path = ../library/tclIndex; refType = 2; sourceTree = SOURCE_ROOT; }; F5F25008016ED0DF01DC9062 = { includeInIndex = 0; isa = PBXFileReference; lastKnownFileType = folder; name = tcltest; path = ../library/tcltest; refType = 2; sourceTree = SOURCE_ROOT; }; F5F2500A016ED0DF01DC9062 = { isa = PBXFileReference; lastKnownFileType = text; name = word.tcl; path = ../library/word.tcl; refType = 2; sourceTree = SOURCE_ROOT; }; //F50 //F51 //F52 //F53 //F54 //F90 //F91 //F92 //F93 //F94 F9A61C9D04C2B4E3006F5A0B = { explicitFileType = wrapper.framework; isa = PBXFileReference; path = Tcl.framework; refType = 3; sourceTree = BUILT_PRODUCTS_DIR; }; }; rootObject = 00E2F845016E82EB0ACA28DC; } tcl8.4.20/macosx/Tcl.pbproj/default.pbxuser0000644003604700454610000001026111737050674017264 0ustar dgp771div// !$*UTF8*$! { 00E2F845016E82EB0ACA28DC = { activeBuildStyle = 00E2F847016E82EB0ACA28DC; activeExecutable = F594E5F1030774B1016F146B; activeTarget = 00E2F84C016E8B780ACA28DC; addToTargets = ( ); codeSenseManager = F9D167E40610239A0027C147; executables = ( F53ACC52031D9AFE016F146B, F594E5F1030774B1016F146B, ); sourceControlManager = F9D167E30610239A0027C147; userBuildSettings = { SYMROOT = "${SRCROOT}/../../build/tcl"; }; }; 00E2F84C016E8B780ACA28DC = { activeExec = 0; }; F53ACC52031D9AFE016F146B = { activeArgIndex = 2147483647; activeArgIndices = ( NO, NO, ); argumentStrings = ( "${SRCROOT}/../../tcl/tests/all.tcl", "-verbose \"\"", ); configStateDict = { "PBXLSLaunchAction-0" = { PBXLSLaunchAction = 0; PBXLSLaunchStartAction = 1; PBXLSLaunchStdioStyle = 2; PBXLSLaunchStyle = 0; class = PBXLSRunLaunchConfig; displayName = "Executable Runner"; identifier = com.apple.Xcode.launch.runConfig; remoteHostInfo = ""; startActionInfo = ""; }; "PBXLSLaunchAction-1" = { PBXLSLaunchAction = 1; PBXLSLaunchStartAction = 1; PBXLSLaunchStdioStyle = 2; PBXLSLaunchStyle = 0; class = PBXGDB_LaunchConfig; displayName = GDB; identifier = com.apple.Xcode.launch.GDBMI_Config; remoteHostInfo = ""; startActionInfo = ""; }; }; cppStopOnCatchEnabled = 0; cppStopOnThrowEnabled = 0; customDataFormattersEnabled = 1; debuggerPlugin = GDBDebugging; disassemblyDisplayState = 0; dylibVariantSuffix = _debug; enableDebugStr = 0; environmentEntries = ( { active = YES; name = TCL_LIBRARY; value = "${SRCROOT}/../../tcl/library"; }, { active = NO; name = DYLD_PRINT_LIBRARIES; }, ); isa = PBXExecutable; launchableReference = F5C37CF303D5BEDF016F146B; libgmallocEnabled = 0; name = tcltest; shlibInfoDictList = ( ); sourceDirectories = ( ); startupPath = "<>"; }; F594E5F1030774B1016F146B = { activeArgIndex = 2147483647; activeArgIndices = ( ); argumentStrings = ( ); configStateDict = { "PBXLSLaunchAction-0" = { PBXLSLaunchAction = 0; PBXLSLaunchStartAction = 1; PBXLSLaunchStdioStyle = 2; PBXLSLaunchStyle = 0; class = PBXLSRunLaunchConfig; displayName = "Executable Runner"; identifier = com.apple.Xcode.launch.runConfig; remoteHostInfo = ""; startActionInfo = ""; }; "PBXLSLaunchAction-1" = { PBXLSLaunchAction = 1; PBXLSLaunchStartAction = 1; PBXLSLaunchStdioStyle = 2; PBXLSLaunchStyle = 0; class = PBXGDB_LaunchConfig; displayName = GDB; identifier = com.apple.Xcode.launch.GDBMI_Config; remoteHostInfo = ""; startActionInfo = ""; }; }; cppStopOnCatchEnabled = 0; cppStopOnThrowEnabled = 0; customDataFormattersEnabled = 1; debuggerPlugin = GDBDebugging; disassemblyDisplayState = 0; dylibVariantSuffix = _debug; enableDebugStr = 0; environmentEntries = ( { active = NO; name = DYLD_PRINT_LIBRARIES; }, ); isa = PBXExecutable; launchableReference = F98F02E608E7EF9A00D0320A; libgmallocEnabled = 0; name = tclsh; shlibInfoDictList = ( ); sourceDirectories = ( ); startupPath = "<>"; }; F5C37CF303D5BEDF016F146B = { isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; path = tcltest; refType = 3; sourceTree = BUILT_PRODUCTS_DIR; }; F98F02E608E7EF9A00D0320A = { isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; path = tclsh8.4; refType = 3; sourceTree = BUILT_PRODUCTS_DIR; }; F9D167E30610239A0027C147 = { fallbackIsa = XCSourceControlManager; isSCMEnabled = 0; isa = PBXSourceControlManager; scmConfiguration = { }; scmType = scm.cvs; }; F9D167E40610239A0027C147 = { indexTemplatePath = ""; isa = PBXCodeSenseManager; usesDefaults = 1; wantsCodeCompletion = 1; wantsCodeCompletionAutoSuggestions = 1; wantsCodeCompletionCaseSensitivity = 1; wantsCodeCompletionListAlways = 1; wantsCodeCompletionOnlyMatchingItems = 1; wantsCodeCompletionParametersIncluded = 1; wantsCodeCompletionPlaceholdersInserted = 1; wantsCodeCompletionTabCompletes = 1; wantsIndex = 1; }; } tcl8.4.20/macosx/README0000644003604700454610000001521211737050674013072 0ustar dgp771divTcl Mac OS X README ------------------- This is the README file for the Mac OS X/Darwin version of Tcl. 1. Where to go for support -------------------------- - The tcl-mac mailing list on sourceforge is the best place to ask questions specific to Tcl & Tk on Mac OS X: http://lists.sourceforge.net/lists/listinfo/tcl-mac (this page also has a link to searchable archives of the list, please check them before asking on the list, many questions have already been answered). - For general Tcl/Tk questions, the newsgroup comp.lang.tcl is your best bet: http://groups.google.com/group/comp.lang.tcl/ - The Tcl'ers Wiki also has many pages dealing with Tcl & Tk on Mac OS X, see http://wiki.tcl.tk/_/ref?N=3753 http://wiki.tcl.tk/_/ref?N=8361 - Please report bugs with Tcl or Tk on Mac OS X to the sourceforge bug trackers: http://tcl.sourceforge.net/ 2. Using Tcl on Mac OS X ------------------------ - At a minimum, Mac OS X 10.1 is required to run Tcl, but OS X 10.3 or higher is recommended (certain [file] operations behave incorrectly on earlier releases). - Unless weak-linking is used, Tcl built on Mac OS X 10.x will not run on 10.y with y < x; on the other hand Tcl built on 10.y will always run on 10.x with y <= x (but without any of the fixes and optimizations that would be available in a binary built on 10.x). Weak-linking is available on OS X 10.2 or later, it additionally allows Tcl built on 10.x to run on any 10.y with x > y >= z (for a chosen z >= 2). - Tcl extensions can be installed in any of: $HOME/Library/Tcl /Library/Tcl /Network/Library/Tcl /System/Library/Tcl $HOME/Library/Frameworks /Library/Frameworks /Network/Library/Frameworks /System/Library/Frameworks (searched in that order). Given a potential package directory $pkg, Tcl on OSX checks for the file $pkg/Resources/Scripts/pkgIndex.tcl as well as the usual $pkg/pkgIndex.tcl. This allows building extensions as frameworks with all script files contained in the Resources/Scripts directory of the framework. - [load]able binary extensions can linked as either ordinary shared libraries (.dylib) or as MachO bundles (since 8.4.10/8.5a3); only bundles can be unloaded, and bundles are also loaded more efficiently from VFS (no temporary copy to the native filesystem required). - The 'deploy' target of macosx/Makefile installs the html manpages into the standard documentation location in the Tcl framework: Tcl.framework/Resources/Documentation/Reference/Tcl No nroff manpages are installed by default by the Makefile. - The Tcl framework can be installed in any of the system's standard framework directories: $HOME/Library/Frameworks /Library/Frameworks /Network/Library/Frameworks /System/Library/Frameworks 3. Building Tcl on Mac OS X --------------------------- - At least Mac OS X 10.1 is required to build Tcl, and Apple's Developer Tools need to be installed (only the most recent version matching your OS release is supported). The Developer Tools installer is available on Mac OS X retail disks or is present in /Applications/Installers on Macs that came with OS X preinstalled. The most recent version can be downloaded from the ADC website http://connect.apple.com (after you register for free ADC membership). - Tcl is most easily built as a Mac OS X framework via Makefile in tcl/macosx (see below for details), but can also be built with the standard unix configure and make buildsystem in tcl/unix as on any other unix platform (indeed, the Makefile is just a wrapper around the unix buildsystem). The Mac OS X specific configure flags are --enable-framework and --disable-corefoundation (which disables CF and notably reverts to the standard select based notifier). - It is also possible to build with Apple's IDE via the tcl/macosx/Tcl.pbproj project, this simply calls through to the tcl/macosx/Makefile. - To build universal binaries, set CFLAGS as follows: export CFLAGS="-arch ppc -arch ppc64 -arch i386 -arch x86_64 \ -isysroot /Developer/SDKs/MacOSX10.4u.sdk -mmacosx-version-min=10.4" This requires Mac OS X 10.4 and Xcode 2.4 (or Xcode 2.2 if -arch x86_64 is omitted, but _not_ Xcode 2.1) and will work on any of the architectures (the -isysroot flag is only required on PowerPC Tiger). Note that configure requires CFLAGS to contain a least one architecture that can be run on the build machine (i.e. ppc on G3/G4, ppc or ppc64 on G5, ppc or i386 on Core and ppc, i386 or x86_64 on Core2/Xeon). Universal builds of Tcl TEA extensions are also possible with CFLAGS set as above, they will be [load]able by universal as well as thin binaries of Tcl. - To enable weak-linking, set the MACOSX_DEPLOYMENT_TARGET environment variable to the minimal OS version (>= 10.2) the binaries should be able to run on, e.g: export MACOSX_DEPLOYMENT_TARGET=10.2 This requires Mac OS X 10.2 and gcc 3.1; if you have gcc 4 or later you can set CFLAGS instead: export CFLAGS="-mmacosx-version-min=10.2" Support for weak-linking was added to the code for 8.4.14/8.5a5. Detailed Instructions for building with macosx/Makefile ------------------------------------------------------- - Unpack the tcl source release archive. - The following instructions assume the tcl source tree is named "tcl${ver}", where ${ver} is a shell variable containing the tcl version number (for example '8.4.12'). Setup the shell variable as follows: set ver="8.4.12" ;: if your shell is csh ver="8.4.12" ;: if your shell is sh The source tree will be named this way only if you are building from a release archive, if you are building from CVS, the version numbers will be missing; so set ${ver} to the empty string instead: set ver="" ;: if your shell is csh ver="" ;: if your shell is sh - The following steps will build Tcl from the Terminal, assuming you are located in the directory containing the tcl source tree: make -C tcl${ver}/macosx and the following will then install Tcl onto the root volume (admin password required): sudo make -C tcl${ver}/macosx install if you don't have the admin password, you can install into your home directory, instead by passing an INSTALL_ROOT argument to make: make -C tcl${ver}/macosx install INSTALL_ROOT="${HOME}/" - The default Makefile targets will build _both_ debug and optimized versions of the Tcl framework with the standard convention of naming the debug library Tcl.framework/Tcl_debug. This allows switching to the debug libraries at runtime by setting export DYLD_IMAGE_SUFFIX=_debug (c.f. man dyld for more details) If you only want to build and install the debug or optimized build, use the 'develop' or 'deploy' target variants of the Makefiles, respectively. For example, to build and install only the optimized versions: make -C tcl${ver}/macosx deploy sudo make -C tcl${ver}/macosx install-deploy tcl8.4.20/README0000644003604700454610000001461212052456743011601 0ustar dgp771divREADME: Tcl This is the Tcl 8.4.20 source distribution. http://tcl.sourceforge.net/ You can get any source release of Tcl from the file distributions link at the above URL. Contents -------- 1. Introduction 2. Documentation 3. Compiling and installing Tcl 4. Development tools 5. Tcl newsgroup 6. The Tcler's Wiki 7. Mailing lists 8. Support and Training 9. Tracking Development 10. Thank You 1. Introduction --------------- Tcl provides a powerful platform for creating integration applications that tie together diverse applications, protocols, devices, and frameworks. When paired with the Tk toolkit, Tcl provides the fastest and most powerful way to create GUI applications that run on PCs, Unix, and the Macintosh. Tcl can also be used for a variety of web-related tasks and for creating powerful command languages for applications. Tcl is maintained, enhanced, and distributed freely by the Tcl community. The home for Tcl/Tk releases and bug/patch database is on SourceForge: http://tcl.sourceforge.net/ with the Tcl Developer Xchange hosted at: http://www.tcl.tk/ Tcl is a freely available open source package. You can do virtually anything you like with it, such as modifying it, redistributing it, and selling it either in whole or in part. See the file "license.terms" for complete information. 2. Documentation ---------------- Extensive documentation is available at our website. The home page for this release, including new features, is http://www.tcl.tk/software/tcltk/8.4.html Detailed release notes can be found at the file distributions page by clicking on the relevant version. http://sourceforge.net/projects/tcl/files/ Information about Tcl itself can be found at http://www.tcl.tk/about/ There have been many Tcl books on the market. Many are mentioned in the Wiki: http://wiki.tcl.tk/_/ref?N=25206 To view the complete set of reference manual entries for Tcl 8.4 online, visit the URL: http://www.tcl.tk/man/tcl8.4/ 2a. Unix Documentation ---------------------- The "doc" subdirectory in this release contains a complete set of reference manual entries for Tcl. Files with extension ".1" are for programs (for example, tclsh.1); files with extension ".3" are for C library procedures; and files with extension ".n" describe Tcl commands. The file "doc/Tcl.n" gives a quick summary of the Tcl language syntax. To print any of the man pages on Unix, cd to the "doc" directory and invoke your favorite variant of troff using the normal -man macros, for example ditroff -man Tcl.n to print Tcl.n. If Tcl has been installed correctly and your "man" program supports it, you should be able to access the Tcl manual entries using the normal "man" mechanisms, such as man Tcl 2b. Windows Documentation ------------------------- The "doc" subdirectory in this release contains a complete set of Windows help files for Tcl. Once you install this Tcl release, a shortcut to the Windows help Tcl documentation will appear in the "Start" menu: Start | Programs | Tcl | Tcl Help 3. Compiling and installing Tcl ------------------------------- There are brief notes in the unix/README, win/README, and macosx/README about compiling on these different platforms. There is additional information about building Tcl from sources at http://www.tcl.tk/doc/howto/compile.html 4. Development tools --------------------------- ActiveState produces a high quality set of commercial quality development tools that is available to accelerate your Tcl application development. Tcl Dev Kit builds on the earlier TclPro toolset and provides a debugger, static code checker, single-file wrapping utility, bytecode compiler and more. More information can be found at http://www.ActiveState.com/Tcl 5. Tcl newsgroup ---------------- There is a USENET news group, "comp.lang.tcl", intended for the exchange of information about Tcl, Tk, and related applications. The newsgroup is a great place to ask general information questions. For bug reports, please see the "Support and bug fixes" section below. 6. The Tcler's Wiki ------------------- A Wiki-based open community site covering all aspects of Tcl/Tk is at: http://wiki.tcl.tk/ It is dedicated to the Tcl programming language and its extensions. A wealth of useful information can be found there. It contains code snippets, references to papers, books, and FAQs, as well as pointers to development tools, extensions, and applications. You can also recommend additional URLs by editing the wiki yourself. 7. Mailing lists ---------------- Several mailing lists are hosted at SourceForge to discuss development or use issues (like Macintosh and Windows topics). For more information and to subscribe, visit: http://sourceforge.net/projects/tcl/ and go to the Mailing Lists page. 8. Support and Training ------------------------ We are very interested in receiving bug reports, patches, and suggestions for improvements. We prefer that you send this information to us via the bug form at SourceForge, rather than emailing us directly. The bug database is at: http://tcl.sourceforge.net/ The bug form was designed to give uniform structure to bug reports as well as to solicit enough information to minimize followup questions. We will log and follow-up on each bug, although we cannot promise a specific turn-around time. Enhancements, reported via the Feature Requests form at the same web site, may take longer and may not happen at all unless there is widespread support for them (we're trying to slow the rate at which Tcl/Tk turns into a kitchen sink). It's very difficult to make incompatible changes to Tcl/Tk at this point, due to the size of the installed base. The Tcl community is too large for us to provide much individual support for users. If you need help we suggest that you post questions to comp.lang.tcl. We read the newsgroup and will attempt to answer esoteric questions for which no one else is likely to know the answer. In addition, see the following page on the Wiki for links to other organizations that offer Tcl/Tk training: http://wiki.tcl.tk/training 9. Tracking Development ----------------------- Tcl is developed in public. To keep an eye on how Tcl is changing, see http://core.tcl.tk/ 10. Thank You ------------- We'd like to express our thanks to the Tcl community for all the helpful suggestions, bug reports, and patches we have received. Tcl/Tk has improved vastly and will continue to do so with your help. tcl8.4.20/ChangeLog.20000000644003604700454610000027066211737050674013066 0ustar dgp771div2000-12-14 Don Porter * generic/tclExecute.c: * tests/expr-old.test: Re-wrote Tcl's [expr rand()] and [expr srand($seed)] implementations, fixing a range error on some 64-bit platforms. Added tests that detect the bug. The rewrite changes the seed -> sequence map on 64-bit platforms, only for seed >= 2^31, a slight incompatibility. [Bug 121072, Patch 102781] 2000-12-10 Don Porter * library/init.tcl: * library/msgcat/msgcat.tcl: * library/msgcat/pkgIndex.tcl: * library/opt/optparse.tcl: * library/opt/pkgIndex.tcl: Where [uplevel] is used in a proc to evaluate a Tcl built-in command in the caller's context, the built-in commands are now fully namespace-qualified. This prevents problems when the caller context is in a namespace where the built-in command name has been used by a command in the namespace. (For example, [::ns::set] might be called instead of the intended [::set]). [Bug #119422, Patch #102545] 2000-12-09 jeff hobbs * win/tclWinTime.c (CalibrationThread): added lint return value to prevent compiler warning. [Bug #125005] * docs/scan.n: * tests/scan.test: * generic/tclScan.c (Tcl_ScanObjCmd): changed %o and %x to use strtoul instead of strtol to correctly preserve scan<>format conversion of large integers. [Patch #102663, Bug #124600] * generic/tclExecute.c (TclExecuteByteCode): Commited patch fixing handling of {!} in expressions. [Patch #102702] 2000-12-08 jeff hobbs * library/init.tcl: Added support for PATHEXT variable in auto_execok, recognizing the proper set of executable extensions on Windows. [Patch #102719] 2000-12-08 Andreas Kupries * generic/tclEncoding.c (LoadTableEncoding): Changed dangerous code to something less critical. This fixes bug 119417, part A without affecting the speed when loading encodings. 2000-12-08 Donal K. Fellows * doc/open.n: Added xref to fconfigure and advice on the opening of binary files. Should help prevent a recurrence of bugs like #124558 2000-12-07 jeff hobbs * generic/tcl.h: added note about need to updated library/dde/pkgIndex.tcl with minor version increment. * library/dde/pkgIndex.tcl: updated to use 84 version to reflect the makefile. Should probably be updated to use its real version at some point. [Patch #102560, Bug #119421] 2000-12-06 eric melski * generic/tcl.h (attemptckalloc): Fixed typo for #define of attemptckalloc (was defined to Tcl_AttempDbCkalloc, should have been Tcl_AttemptDbCkalloc). [Bug: 124384] * generic/tclCkalloc.c: Added TCL_MEM_DEBUG versions of Tcl_AttemptDbCkrealloc and Tcl_AttemptDbCkalloc. [Bug: 124384]. 2000-11-24 Donal K. Fellows * generic/tclExecute.c (TclExecuteByteCode): Logical negation "!" can now handle string booleans, provided those values are placed in variables. * tests/expr.test (expr-13.17): Check that [expr {!$var}] can negate the string-versions of booleans "yes", "false", etc. * library/tcltest/tcltest.tcl (getMatchingFiles, getMatchingDirectories): * tools/man2html.tcl (doDir): * tools/man2help.tcl (doDir): * library/package.tcl (tclPkgUnknown,tclMacPkgSearch): * library/safe.tcl (AddSubDirs): [glob] uses -directory instead of unsafe [file join] to fix Bug #123313 * generic/tclIndexObj.c: * generic/tclTestObj.c (TestindexobjCmd): Changed internal representation of index objects to fix Bug #119082; fix shouldn't be visible to outside world... * generic/tclTest.c (TestGetIndexFromObjStructObjCmd): * tests/indexObj.test: (indexObj-6.*) Added to test for presence of Bug #119082. 2000-11-23 Donal K. Fellows * generic/tclCmdIL.c (Tcl_LsortObjCmd): Fixed memory leak from Bug #119398 * library/init.tcl (unknown): Added specific level parameters to all uplevel invokations to boost performance; didn't dare touch the "namespace inscope" stuff though, since it looks sensitive to me! Should fix Bug #123217, though testing is tricky... 2000-11-21 Andreas Kupries * All of the changes below are described in TIP #7 ~ Specification and result from the application of the patch contained therein. Creator of the patch is Kevin Kenny . The patch used here is actually a bit different. Two MS specific constant values (format FOOui64) were replaced with a more portable formatting of the values and an additional cast to LONGLONG. My cross-compiling gcc was unable to process the original form. The SF Id of the patch is 102459. * tclWinTime.c: Add to the static data a set of variables that manage the phase-locked techniques, including a ''CRITICAL_SECTION'' to guard them so that multi-threaded code is stable. * tclWinTime.c: Modify ''TclpGetSeconds'' to call ''TclpGetTime'' and return the 'seconds' portion of the result. This change is necessary to make sure that the two times are consistent near the rollover from one second to another. * tclWinTime.c: Modify ''TclpGetClicks'' to use TclpGetTime to determine the click count as a number of microseconds. * tclWinTime.c: Modify ''TclpGetTime'' to return the time as M*Q+B, where Q is the result of ''QueryPerformanceCounter'', and M and B are variables maintained by the phase-locked loop to keep the result as close as possible to the system clock. The ''TclpGetTime'' call will also launch the phase-lock management in a separate thread the first time that it is invoked. If the performance counter is unavailable, or if its frequency is not one of the two common 8254-compatible rates, then ''TclpGetTime'' will return the result of ''ftime'' as it does in Tcl 8.3.2. * tclWinTime.c: Add the clock calibration procedure. The calibration is somewhat complex; to save space, the reader is referred to the reference implementation for the details of how the time base and frequency are maintained. * tclWinNotify.c: Modify ''Tcl_Sleep'' to test that the process has, in fact, slept for the requisite time by calling ''TclpGetTime'' and comparing with the desired time. Otherwise, roundoff errors may cause the process to awaken early. * tclWinTest.c: Add a ''testwinclock'' command. This command returns a four element list comprising the seconds and microseconds portions of the system clock and the seconds and microseconds portions of the Tcl clock. * winTime.test: Add to the test suite a test that makes sure that the Tcl clock stays within 1.1 ms of the system clock over the duration of the test. 2000-11-21 Donal K. Fellows * doc/global.n: * doc/upvar.n: * doc/variable.n: Improved documentation to mention that variables so created are listed in [info locals] and added a few more cross-links between these commands. Fixes bug #119387 2000-11-17 Donal K. Fellows * tests/safe.test: (safe-4.3): * generic/tclVar.c (TclLookupVar): Changed again. Now passes all the tests, though one needed modifying since it required the wrong answer. (Why on earth do we have inline modification of argument strings? This sort of thing is horrendous to debug and doesn't work well in a multithreaded environment!) Fixes bug 119192. * tests/var.test: (var-1.19) If my attempts to fix the problem aren't right yet, my attempts to describe it look pretty good to me... 2000-11-16 Andreas Kupries * win/tclWinPort.h (line 69): Changed reference to winsock2.h into winsock.h. This was a leftover from a foray into using winsock version 2 (History lesson from Scott Redman and Jeff Hobbs). This code was no problem when compiling Tcl itself, but could trip extensions. Fixes bug 122568. 2000-11-15 jeff hobbs * unix/Makefile.in: removed bp.c references (hasn't existed in a long time). Corrected 'make dist' to make dist with unversioned library directories (same as out of cvs), so make install works correctly with either source tree. 2000-11-15 jeff hobbs * generic/tclVar.c (TclLookupVar): reverted fix below as it broke all other array unset error reporting. Bug-119192 is still open. 2000-11-15 Donal K. Fellows * generic/tclVar.c (TclLookupVar): Changed references to part2 to use elName instead in various error message generating spots, so as to fix Bug-119192. 2000-11-03 David Gravereaux * win/.cvsignore: Removed 'configure' from the glob list now that it's included. 2000-11-03 Jeff Hobbs 8.4a2 RELEASE * unix/Makefile.in (install-libraries, dist): * win/makefile.vc (install-libraries): * win/Makefile.in (install-libraries): updated to install unversioned library directories into versioned directories. * tools/tcl.wse.in: updated for unversioning of library dirs * unix/mkLinks: updated mkLinks with latest doc updates * doc/Tcl_Main.3: added docs for Tcl_SetMainLoop * generic/tclStubInit.c: * generic/tclDecls.h: * generic/tcl.decls: added Tcl_SetMainLoop proc that allows people to set a main loop that will run for tclsh. * generic/tcl.h: added Tcl_MainLoopProc typedef * generic/tclMain.c (Tcl_SetMainLoop, StdinProc, Prompt): new StdinProc and Prompt static procs and Tcl_SetMainLoop stubs proc. The first two handle a fileevent based prompt (taken from tkMain.c). Tcl_SetMainLoop enables the interactive setting of a main loop procedure. This enables Tk to be a loadable package. 2000-11-02 David Gravereaux * generic/tclEvent.c: tclLibraryPath Tcl_Obj didn't have a way to share its data among threads. This caused Tcl_Init() to always fail in threads. Added a way to pass the data around with a global char*. [BUG: 5301] 2000-11-02 Jeff Hobbs * unix/configure: * unix/dltest/configure: * win/configure: * tools/configure: checked in configure scripts so people doing CVS checkouts aren't required to have autoconf. Changes to configure.in in the future will require the corresponding configure script to also be re-autoconf'ed and checked in. * win/makefile.vc: * win/tcl.m4: makefile fixes for Win64 support * generic/tclIndexObj.c (Tcl_GetIndexFromObjStruct): minor cast changes. 2000-11-01 Jeff Hobbs * unix/tcl.m4: removed use of -lbsd and -ldl for AIX-5. * tests/subst.test: added tests for non-zero return code handling by subst. * generic/tclParse.c (Tcl_EvalEx): corrected handling of non-zero, non-error return code cases for subst. [BUG: 119829] * generic/tclVar.c (TclVarTraceExists): Corrected excessive mem use when info exists was called on a non-existent array element. [BUG: 119213, 119336] 2000-10-30 David Gravereaux * win/configure.in: * win/Makefile.in: * win/makefile.vc: * win/tcl.rc: * win/tclsh.rc: Added logic to derive filenames better in the resource scripts based on compile options. 2000-10-30 Jeff Hobbs * unix/tclUnixInit.c: added default encoding map from "ja_JP.eucJP" to "euc-jp". (takahashi) * tests/clock.test: corrected clock-2.* test numbering * unix/configure.in (SC_TCL_LINK_LIBS): removed code that was commented out (it had been moved to tcl.m4's SC_TCL_LINK_LIBS already). * unix/tcl.m4: consolidated gettimeofday check for AIX. 2000-10-27 Jeff Hobbs * unix/configure.in: * unix/tcl.m4: added support for AIX-5. * generic/tclIO.c (Tcl_NotifyChannel): removed #ifdef around code for old channel structures, placed preserve/release around statePtr * generic/tclIO.c (CloseChannel): the statePtr for a channel was not being freed when the last channel in a stack was freed, causing a mem leak. * unix/tclUnixChan.c: updated channel types to strict TCL_CHANNEL_VERSION_2 style to avoid compiler warnings. They work either way, but this avoids compiler warnings (that worries people). 2000-10-27 Jennifer Hom * library/tcltest1.0/tcltest.tcl: Removed a cd into the test directory in runAllTests that screwed up the temporary directory setting, effectively preventing users from running tests on multiple platforms at the same time. 2000-10-26 David Gravereaux * win/tclWinFile.c (TclpMatchFilesTypes): NULL was being set to "attr" which was a DWORD. Changed NULL to zero because a 'void *' can't be set to a DWORD to avoid the compiler warning. 2000-10-24 Jennifer Hom * tests/all.tcl: Removed support for tcltest 1.0. * tests/tcltest.test: * library/tcltest1.0/tcltest.tcl: * library/tcltest1.0/pkgIndex.tcl: * docs/tcltest.n: Moved tcltest2 code so that it's the standard version of tcltest. Removed all tcltest2 files (tests/tcltest2.test, library/tcltest1.0/tcltest2.tcl, docs/tcltest2.n). 2000-10-20 Jeff Hobbs * win/tclWinFile.c (TclpMatchFilesTypes): made the stat call only occur when necessary (for 'glob' command). Significantly speeds up glob command from 8.3. [BUG: 6216] 2000-10-19 Jennifer Hom * library/tcltest1.0/tcltest2.tcl: * tests/tcltest2 * doc/tcltest2.n: Code and documentation cleanup. Modified -verbose to take list of keywords as well as string of letters. Removed Tcl version information from tcltest. Removed tcltest::grep from tcltest package. Added optional 3rd directory argument to makeFile/makeDirectory and removeFile/removeDirectory. * tests/basic.test: Changed references to tcltest::tclVersion to hardcoded numbers. * generic/tcl.h: Changed reference to tcltest2.tcl and tcltest.tcl in comments to tests/basic.test. 2000-10-06 David Gravereaux * win/tclWinChan.c: moved Win2K bug case test with GetStdHandle() from TclpGetDefaultStdChannel into Tcl_MakeFileChannel to enable a more general method in detecting invalid OS handles rather than just a specific known case. [BUG: 5971] 2000-10-06 Jeff Hobbs * tests/cmdAH.test: extra tests for 'file channels' that include multiple interpreter tests and channel sharing * generic/tclIO.c (Tcl_GetChannelNamesEx): corrected function (and consequently 'file channels') to return channels that are actually registered for this specific interp, rather than this thread. * doc/CrtChannel.3: fixed spelling mistakes 2000-09-29 Jennifer Hom * library/tcltest1.0/tcltest2.tcl: * tests/tcltest2.test: * doc/tcltest2.n: Modified the new form of the test command to accept both attribute-value pairs and command line options. Updated the tests and the documentation for this new format. Also changed the option names for the test command. 2000-09-29 Jeff Hobbs * win/tclWinSerial.c (SerialGetOptionProc): corrected reporting of space parity on Windows (Eason) [Bug 6057]. * win/Makefile.in: commented use of TESTFLAGS * unix/Makefile.in: added TESTFLAGS to test target to conform with Windows makefile and TEA style. * tests/stack.test: prevented possible crash on systems with low default stacksize (Tru64, AIX) in infinite recursion test. A solution to check remaining stack space in the core is best, but hard to do in a cross-platform manner. * generic/tclIOGT.c (FLUSH_DELAY): renamed DELAY define to FLUSH_DELAY to avoid defn conflict using Tru64's cc. 2000-09-28 Jeff Hobbs * tools/tcl.wse.in: added tclPlatDecls.h and tkPlatDecls.h to the Windows .exe install. * tests/fCmd.test (fCmd-6.20): corrected test to remove c:/tcl8975@ after creating it. * tests/fileName.test: cleaned up the testing of glob patterns for c:/globTest (Windows) to directly create/remove directory. 2000-09-27 Jeff Hobbs * generic/tcl.decls: * generic/tclIO.c: updated Tcl_IsChannelShared, Tcl_IsChannelRegistered, Tcl_CutChannel, Tcl_SpliceChannel, Tcl_IsChannelExisting, and Tcl_ClearChannelHandlers to conform to the new stacked channel implementation. Their stub slots were also moved to give preference to the new 8.3.2 stub functions. This will cause an incompatability with 8.4a1 only. (StopCopy): fixed a bug introduced by a partial fix in 8.3.2 that didn't set nonBlocking correctly when resetting the flags for the write side. [Bug: 6261] * doc/ChnlStack.3: * doc/CrtChannel.3: * generic/tcl.decls: * generic/tcl.h: * generic/tclDecls.h: * generic/tclIO.c: * generic/tclIO.h: * generic/tclIOGT.c: * generic/tclInt.decls: * generic/tclIntDecls.h: * generic/tclStubInit.c: * generic/tclTest.c: * tests/iogt.test: * unix/Makefile.in: * win/Makefile.in: * win/makefile.vc: * win/tclConfig.sh.in: * win/tclWinChan.c: * win/tclWinConsole.c: * win/tclWinPipe.c: * win/tclWinSerial.c: * win/tclWinSock.c: Up-port of changes made in 8.3.2 to 8.4a2 code base. Most of these changes relate to the rewrite of the stacked channel implementation, with a few config related fixes. Following is an asynchronous include of the applicable ChangeLog entries from 8.3.2. ******************************************************** ** START OF ASYNCHRONOUS UP-PORT LOG (8.3.2 -> 8.4a2) ** ******************************************************** 2000-08-07 Jeff Hobbs * doc/ChnlStack.3: * doc/CrtChannel.3: updated the docs to be aware of the TCL_CHANNEL_VERSION_2 style of Tcl channels. * generic/tclIO.c (Tcl_CreateChannel): added assertion to verify that the new channel versioning will be binary compatible with older channel drivers. 2000-08-05 Jeff Hobbs * generic/tclIOGT.c (TclChannelTransform): fixed segfault that would occur when transforming a channel with a proc that did not yet exist. (Kupries) * generic/tclTest.c (TestChannelCmd): added some lint init'ing of statePtr and chan vars. 2000-07-26 Jeff Hobbs * merged core-8-3-1-io-rewrite back into core-8-3-1-branch. The core-8-3-1-io-rewrite branch should now be considered defunct. * generic/tclStubInit.c: * generic/tclDecls.h: * generic/tcl.decls: * generic/tcl.h: * generic/tclIO.c: moved the Tcl_Channel* macros from tcl.h to tclIO.c and made them proper stubbed functions. These are: Tcl_ChannelName, Tcl_ChannelVersion, Tcl_ChannelBlockModeProc, Tcl_ChannelCloseProc, Tcl_ChannelClose2Proc, Tcl_ChannelInputProc, Tcl_ChannelOutputProc, Tcl_ChannelSeekProc, Tcl_ChannelSetOptionProc, Tcl_ChannelGetOptionProc, Tcl_ChannelWatchProc, Tcl_ChannelGetHandleProc, Tcl_ChannelFlushProc, and Tcl_ChannelHandlerProc. These should be used to access the Tcl_ChannelType structure instead of direct pointer dereferencing. * tests/iogt.test: added RCS string, marked tests 2.* to be unixOnly due to underlying system differences. 2000-07-25 Andreas Kupries * tests/iogt.test: (line 866f) New tests iogt-6.[01], highlighting buffering trouble when stacking and unstacking transformations. iogt-6.0 is solved, see the changes below. iogt-6.1 remains, for now, due to the perceived complexity of solutions. * generic/tclIO.h: (line 139f) struct Channel, added a buffer queue, to hold data pushed back when stacking a transformation. * generic/tclIO.c: (line 91f, line 7434f) New internal function 'CopyBuffer'. Derived from 'CopyAndTranslateBuffer', with translation removed. (line 1025f, line 1212f): Initialization of new queue. (line 1164f, Tcl_StackChannel): Pushback of input queue. (line 1293f, Tcl_UnstackChannel): Discard input and pushback. (line 3748f, Tcl_ReadRaw): Modified to use data in the push back area before going to the driver. Uses 'CopyBuffer', s.a. (line 4702f, GetInput): Modified to use data in the push back area before going to the driver. (line 4867f, Tcl_Seek): Modified to take pushback of the topmost channel in a stack into account. (line 5620f, Tcl_InputBuffered): See above. Added 'Tcl_ChannelBuffered'. Analogue to 'Tcl_InputBuffered' but for the buffer area in the channel. * generic/tcl.decls: New public API 'Tcl_ChannelBuffered'. S.a. 2000-07-17 Jeff Hobbs * unix/Makefile.in: * win/Makefile.in: * win/makefile.vc: added tclIOGT.c to objects list to compile. * generic/tclStubInit.c: * generic/tclIntDecls.h: * generic/tclInt.decls: commented out internal decls for TclTestChannelCmd and TclTestChannelEventCmd as they were moved to tclTest.c. Added new decls for TclChannelEventScriptInvoker and TclChannelTransform. * generic/tclIO.c (CloseChannel): stopped masking out of the TCL_READABLE|TCL_WRITABLE bits from the state flags in CloseChannel, instead adding extra intelligence to CheckChannelErrors with a new CHANNEL_RAW_MODE bit for special behavior when called from Raw channel APIs. 2000-07-13 Jeff Hobbs * generic/tclIO.c (StackSetBlockMode): moved set of chanPtr outside of blockModeProc check to avoid infinite loop when blockModeProc was NULL (Kupries). updated TransformSeekProc to not call Tcl_Seek directly (Kupries). * win/tclWinChan.c: updated fileChannelType to v2 channel struct * win/tclWinConsole.c: updated consoleChannelType to v2 channel struct * win/tclWinPipe.c: updated pipeChannelType to v2 channel struct * win/tclWinSerial.c: updated serialChannelType to v2 channel struct * win/tclWinSock.c: updated tcpChannelType to v2 channel struct 2000-07-11 Brent Welch * win/tclConfig.sh.in (TCL_LIBS): Cleaned up unix-specific autoconf variables. 2000-07-11 Jeff Hobbs * tests/iogt.test: made tests [345].0 not run by default as they were failing in the new design, but I'm not convinced that the returned result isn't correct. * generic/tclDecls.h: * generic/tclStubInit.c: * generic/tcl.decls: added Tcl_GetTopChannel C API that returns the current top channel of a channel stack. Tcl_GetChannel was changed earlier to return the bottommost channel of a stack because that is the one that is guaranteed to stay around the longest, and this was needed to compensate for certain operations that want to look at the state of the main channel. Most channel APIs already compensate for grabbing the top, so it shouldn't be needed often. * generic/tclIO.c (Tcl_StackChannel, Tcl_UnstackChannel): Added flushing of buffers (Kupries), removed use of DownChannel macro, added Tcl_GetTopChannel public API to get to the top channel of the channel stack (necessary for TLS). Rewrote Tcl_NotifyChannel for new channel design (Kupries). Did some code cleanup in the transform code. tclIO.c must still be broken into bits (separate out test code and giot code, create tclIO.h). 2000-07-10 Andreas Kupries * tests/iogt.test: Reverted some earlier changes as a fix by Jeff revived the original and correct behaviour. IOW, the tests showed a genuine error and I didn't see it :(. * generic/tclIO.c (Tcl_Read|Write_Raw): Changed to directly use the drivers and not DoRead|DoWrite. The latter use the buffering system, encoding and eol-translation and this wreaks havoc with the data going through the transformations. Both procedures use CheckForchannelErrors and let it believe that there is no background copy in progress or else stacked channels could not be used for that. * generic/tclIO.c (TclCopyChannel, CopyData): Moved access to the topmost channel from the first to the second procedure to make the decision about that at the last possible time (Callbacks can change the stacking). test suite: failures of iogt-[345].0 2000-07-06 Jeff Hobbs * tests/iogt.test: new tests for stacked channel stuff based off new 'testchannel transform|unstack' code (Kupries IOGT extension). * generic/tcl.decls: * generic/tcl.h: * generic/tclDecls.h: * generic/tclStubsInit.c: * generic/tclIO.c: complete rewrite of Tcl Channel code for stacked channels. Channels are now designed to work in a more stacked fashion with a shared ChannelState data structure. 2000-06-02 Jeff Hobbs * generic/tclIO.c (CloseChannel): removed the &ing out of (TCL_READABLE|TCL_WRITABLE) from the flags, as CloseChannel does this on the next pass through for the top channel, and it appeared to be causing hangs by not allowing the final flush. 2000-06-01 Jeff Hobbs * generic/tclIO.c (CloseChannel): Rewrote CloseChannel code to unstack a channel during the close process. Fixed a refcount bug in Tcl_UnstackChannel. [Bug: 5623] (CloseChannel): further extended CloseChannel in the stacked case to effect certain operations on the next channel that would have been done in Tcl_Close. Also added CHANNEL_CLOSED and removed (TCL_READABLE|TCL_WRITABLE) bits from chanPtr->flags. Changed final reset of the WatchProc to check the chanDownPtr's (next) interestMask. ****************************************************** ** END OF ASYNCHRONOUS UP-PORT LOG (8.3.2 -> 8.4a2) ** ****************************************************** 2000-09-20 Jeff Hobbs * tests/socket.test: removed doTestsWithRemoteServer constraint from socket-12.*. It requires 'exec', not a remote server. Cleaned up some coding errors. 2000-09-20 Jennifer Hom * library/tcltest1.0/pkgIndex.tcl: Updated to load tcltest 2.0. * library/tcltest1.0/tcltest2.tcl: New version of tcltest. Cleanup of command line parsing: allows users to specify command line arguments through an environment variable named TCLTEST_OPTIONS [RFE: 3748], does not respond to incorrect arguments, and forces usage of entire flag name when using command line arguments. Defines accessor procs for all tcltest variables. Allows users to use 'return' in test scripts. Allow users to specify whether test files should be sourced or run in a separate process. 'all.tcl' code moved to tcltest package. 'test' proc modified to use attribute-value pairs. Allow users to specify what return codes, output, and errors can be compared and whether these values should be compared using regexp, glob, or exact matching. makeDirectory & removeDirectory now operate with respect to temporaryDirectory [Bug: 6001]. Test results from tests run in slave interpreters are now included in test totals [Bug: 1493]. Test files that return error values are now reported. * tests/all.tcl: Added code to check for the tcltest version loaded; modified to figure out which tests to run based on the tcltest version loaded. * tests/tcltest.test: Modified to explicitly load version 1.0 of tcltest. * tests/tcltest2.test: New test suite for tcltest; includes all of the old tests plus new ones reflecting changes made for version 2.0. * tests/cmdAH.test: Added singleTestInterp constraint to cmdAH-31.2; this test does not run if tests aren't sourced into a single interpreter. * tests/socket.test: Fixed two tests that were referencing variables outside of scope. * tools/tcl.wse.in: Added code to install tcltest2.tcl. * doc/tcltest2.n: New documentation for tcltest version 2.0. Removes documentation for tcltest namespace variables. Adds documentation for new tcltest procs. * unix/mkLinks: Added code to link to tcltest2.n. * generic/tcl.h: Added comment to modify tcltest2.tcl as well as tcltest.tcl for version changes. 2000-09-19 Eric Melski * generic/tclCmdMZ.c (Tcl_RegexpObjCmd): When using -all, all attempts after the first to match the regexp against the string should include the TCL_REG_NOTBOL flag, to avoid erroneously matching ^ in the middle of the string. Added code to set this flag after the first pass through the matching loop. [Bug: 6284]. 2000-09-19 David Gravereaux * doc/Eval.3: Added a note about the script argument to Tcl_Eval() should be in UTF-8 or risk implied conversion errors when possible combinations of upper ascii can be valid UTF-8 special codes. 2000-09-17 Eric Melski * tests/cmdIL.test: Added a test for fix for [Bug: 6212]. * generic/tclCmdIL.c (Tcl_LsortObjCmd): Applied patch from [Bug: 6212], which corrected an error in the handling of the -index option. 2000-09-14 Eric Melski * doc/Alloc.3: Added entries for Tcl_AttemptAlloc, Tcl_AttempRealloc. * doc/StringObj.3: Added entry for Tcl_AttemptSetObjLength. * generic/tclDecls.h: * generic/tclStubInit.c: Regen'ed stubs files from new tcl.decls. * generic/tcl.decls: Added stubs for the Tcl_Attempt* memory allocators and for Tcl_AttemptSetObjLength. * generic/tcl.h: Added #define's for attemptckalloc, attemptckrealloc, which map to the Tcl_Attempt* memory allocators. * generic/tclCkalloc.c: Added non-panic'ing versions of Tcl_Alloc, Tcl_Realloc, etc.; these are called Tcl_AttemptAlloc, Tcl_AttemptRealloc, etc. These are used by Tcl_AttemptSetObjLength and the string obj append functions. * generic/tclStringObj.c: Modified string growth algorithm to use doubling algorithm as long as possible, and only fall back when that fails. Added Tcl_AttemptSetObjLength, and modified AppendUnicodeToUnicodeRep, AppendUtfToUtfRep, and Tcl_AppendStringsToObjVA to support this. 2000-09-07 David Gravereaux * win/.cvsignore: changed the glob patterns a bit to exclude VC++ project conversion backups. * win/tclWinPipe.c: Stage-1 bug fix for TR#2460 "exec leaks memory". Added more logic around the close-down of the pipe reader thread so as to avoid, at all cost, a TerminateThread. Most cases with exec are fixed, but I don't consider 2460 done yet. Closing down the read side of a pipe before the child process, doesn't really fit the windows model. [BUG: 2460] 2000-09-07 Jeff Hobbs * doc/trace.n: minor doc cleanup 2000-09-06 Andrщ Pіnitz * doc/*.n: added or changed "SEE ALSO:" section 2000-09-06 Jeff Hobbs * win/tclWinLoad.c (TclpLoadFile): added special message for ERROR_PROC_NOT_FOUND exception in loading a dll. * win/tclWinError.c: changed ERROR_PROC_NOT_FOUND to map from ESRCH (POSIX: no such process) to EINVAL because there is no good mapping for "procedure not found". * README: * generic/tcl.h: * library/tcltest1.0/tcltest.tcl: * tools/tcl.wse.in: * tools/tcltk-man2html.tcl: * unix/configure.in: * unix/tcl.spec: * win/README.binary: * win/configure.in: updated patchlevel to 8.4a2 * unix/tclUnixPipe.c (TclpCreateProcess): Removed WNOHANG from Tcl_WaitPid call in error case of process creation on Unix, as it would lead to defunct processes. [Bug: 6148] * tests/string.test: extended string repeat tests * generic/tclCmdMZ.c (Tcl_StringObjCmd): changed STR_REPEAT to preallocate the full space of the final string, avoided repeated appends. * doc/source.n: * doc/Eval.3: added extra note about how to safe use ^Z in code, as it is now a cross-platform (was just Windows) EOF char. 2000-09-05 Jeff Hobbs * generic/tclHash.c: fixed pedantic warning of incorrectly placed #endif * generic/tclExecute.c (TclExecuteByteCode): INST_STR_INDEX fixed pedantic cast warning. Corrected support for building with -DTCL_COMPILE_STATS. Added efficiency check of object equality. 2000-08-29 Eric Melski * generic/tclStringObj.c: Applied patch from Gerhard Hintermayer to provide a more conservative string growth algorithm for strings larger than one megabyte; this allows more efficient use of memory for very large strings. 2000-08-25 Eric Melski * tests/trace.test: Extended array tracing tests. * doc/trace.n: Clarified information about when array traces will be fired. * generic/tclVar.c (Tcl_ArrayObjCmd): Corrected call to CallTraces (for TCL_TRACE_ARRAY) to only be called when the variable is either an array or is undefined, to ensure that array traces do not fire for scalar variables. 2000-08-24 Eric Melski * doc/man.macros: Tweaked tab settings for .SO (Standard Options) sections, based on suggestion from Peter Spjuth. 2000-08-24 Mo DeJong * unix/README: Update to account for removal of --enable-gcc. * unix/configure.in: * unix/tcl.m4 (SC_ENABLE_GCC): Remove --enable-gcc option. * win/README: Add note about building with Cygwin. * win/configure.in: * win/tcl.m4 (SC_ENABLE_GCC): Remove --enable-gcc option. Remove quick hack that provided cross compile support for windows builds. 2000-08-24 Eric Melski Overall change: Added support for command rename/delete traces and new trace syntax, from patch from Vince Darley. Added support for array traces for variables. [RFE: 5048, 5967]. * doc/trace.n: Updated documentation for new syntax; flagged old syntax as deprecated; added documentation for command rename/delete traces and variable array traces. * tests/trace.test: Updated tests for new trace syntax; new tests for command rename/delete traces; new tests for array traces. * generic/tclVar.c: Support for new trace syntax; support for TCL_TRACE_ARRAY. * generic/tclStubInit.c: * generic/tclDecls.h: * generic/tcl.decls: Stub functions for command rename/delete traces. * generic/tcl.h: * generic/tclInt.h: * generic/tclBasic.c: Support for command traces. * generic/tclCmdMZ.c (TclTraceVariableObjCmd): Patched to support new [trace] syntax: trace {add|remove|list} {variable|command} name ops command Added support for command traces (rename, delete operations). Added support for TCL_TRACE_ARRAY at Tcl level (array operation for variable traces). 2000-08-20 Eric Melski * generic/tclVar.c: Added check for non-arrays for [array statistics] command (patch from Mark Patton). 2000-08-19 David Gravereaux * generic/tclPlatDecls.h: without a previous '#include ', tclPlatDecls.h can't be parsed due to a missing definition of TCHAR. Added a check to include it when not defined. ***POSSIBLE OBSCURE BUG*** could be caused when the compile flags for the core happen to be different than a project who uses these publics regarding -D_MBCS and -D_UNICODE. This added check might have to be revisited later with a better understanding of the reprocusions. I think TCHAR should be replaced with it's expansion. 2000-08-18 David Gravereaux * win/.cvsignore (added): provides a cleaner build environment with graphical CVS clients. 2000-08-15 Eric Melski * library/tcltest1.0/tcltest.tcl: Set debug level in tcltest::restoreState to 2, for consistancy with the debug level in tcltest::saveState [Bug: 4505]. 2000-08-14 Eric Melski * win/makefile.vc: * win/Makefile.in: * unix/Makefile.in: Added tclPlatDecls.h to the list of installed headers, for more complete stubs support. [Bug: 5241]. * generic/tcl.h: Added #include "tclPlatDecls.h" to get platform-specific stubs declarations (Tcl_WinTCharToUtf, etc) [Bug: 5241]. * README: Updated link for instructions on compiling Tcl from sources to point to correct location (http://dev.scriptics.com/doc/... instead of http://dev.scriptics.com/support/...). 2000-08-11 Eric Melski * generic/tclEnv.c (TclUnsetEnv): Changed declaration of length variable from "unsigned int" to "int", to match usage when passed to TclpFindVariable [Bug: 6126]. 2000-08-10 Eric Melski * library/msgcat1.0/pkgIndex.tcl: Bumped version number to 1.2 [Bug: 6100]. * library/msgcat1.0/msgcat.tcl: Removed erroneous [package forget] in msgcat namespace initializer. Bumped version number to 1.2 [Bug: 6100]. 2000-08-10 David Gravereaux * generic/tclObj.c: r1.15 accidentally changed a global mutex name tclObjMutex to ObjMutex. Put the correct name back. 2000-08-07 Eric Melski * tests/indexObj.test: Added tests using the [testwrongnumargs] command to test Tcl_WrongNumArgs. * generic/tclTest.c (TestWrongNumArgsObjCmd): Added test function for the Tcl_WrongNumArgs function. * generic/tclIndexObj.c (Tcl_WrongNumArgs): Corrected algorithm to not insert a space before the message component when objc == 0 [Bug: 6078]. 2000-07-27 Mo DeJong * win/configure.in: TCL_STUB_LIB_FLAG should not include ${TCL_DBGX} in win/tclConfig.sh, fix that. 2000-07-25 David Gravereaux * doc/Async.3: * generic/tclAsync.c: * generic/tclInt.decls: * generic/tclIntPlatDecls.h: * generic/tclStubInit.c: * generic/tclTest.c: * mac/tclMacPort.h: * unix/tclUnixPort.h: * win/tclWinInit.c: Thread-safe rewrite for tclAsync.c. Added notifier alerting on all platforms as it was only working on Win before. Removed older Win hacks that would end-up waking the wrong notifier in the presence of a threaded build. All tests pass as before. New test cases will be added soon for the new behavior. [BUG: 5791] 2000-07-25 Eric Melski * generic/tclVar.c (CallTraces): Added check for VAR_TRACE_ACTIVE on the array containing the variable before executing traces on that array, to conform with normal variable traces and the documentation, which states that while executing a trace, other traces on that variable are disabled. [Bug: 6049]. * win/tclWinPipe.c (BuildCommandLine): Added Tcl_DStringFree call to prevent potential memory leaks [Bug: 6041]. 2000-07-24 Eric Melski * doc/msgcat.n: Added documentation about the selection of the default locale on Windows. 2000-07-23 Joe English * doc/AddErrInfo.3: * doc/ChnlStack.3: * doc/Exit.3: * doc/GetIndex.3: * doc/Notifier.3: * doc/Object.3: * doc/RegExp.3: * doc/SetResult.3: * doc/SplitList.3: * doc/Thread.3: Added missing entries to NAME section. * doc/AddErrInfo.3: * doc/CrtObjCmd.3: * doc/RecEvalObj.3: Changed Tcl_EvalObj to Tcl_EvalObjEx 2000-07-21 Eric Melski * generic/tclStubInit.c: * generic/tclObj.c: * generic/tclInt.h: * generic/tclHash.c: * generic/tclDecls.h: * generic/tcl.h: * generic/tcl.decls: * doc/Hash.3: Reapplied patch from Paul Duffin to extend hash tables to allow custom key types, such as Tcl_Obj *'s, and others. * doc/binary.n: Noted that the example in the introduction assumes a 32-bit system [Bug: 6035]. 2000-07-21 Mo DeJong * win/configure.in: Define ${prefix} and ${exec_prefix} like unix/configure.in. Fix or add TCL_SRC_DIR, TCL_STUB_LIB_FILE, TCL_STUB_LIB_FLAG, TCL_BUILD_STUB_LIB_SPEC, TCL_STUB_LIB_SPEC, TCL_BUILD_STUB_LIB_PATH, TCL_STUB_LIB_PATH. 2000-07-20 Eric Melski * generic/tclStubInit.c: * generic/tclObj.c: * generic/tclInt.h: * generic/tclHash.c: * generic/tclDecls.h: * generic/tcl.h: * generic/tcl.decls: * doc/Hash.3: Reverted patch from Paul Duffin to extend hash tables to allow custom key types, such as Tcl_Obj *'s, and others; it seems to break Tk. 2000-07-19 Eric Melski * generic/tclStubInit.c: * generic/tclObj.c: * generic/tclInt.h: * generic/tclHash.c: * generic/tclDecls.h: * generic/tcl.h: * generic/tcl.decls: * doc/Hash.3: Applied patch from Paul Duffin to extend hash tables to allow custom key types, such as Tcl_Obj *'s, and others. * tests/pkgMkIndex.test: Added tests for pkg_compareExtension. * library/package.tcl: Enhanced pkg_compareExtension to handle Unixes which tack the version number on to the end of library names (eg, foo.so.1.2); such filenames will be correctly matched. (Patch from Vince Darley). * win/makefile.vc: Applied patch from Don Porter to provide better nmake support for NT/Alpha [RFE: 5938]. 2000-07-18 Mo DeJong * unix/configure.in: * unix/tcl.m4: * win/tcl.m4: Properly quote arguments to m4 macros. This allows Tcl to work with the new version of autoconf. 2000-07-18 Eric Melski * tests/opt.test: Removed references to Lfirst, Lrest functions. * library/opt0.4/optparse.tcl: Applied patch from Chris Nelson, which replaces the [Lfirst] function with an inline [lindex ... 0] and [Lrest] with [lrange ... 1 end], for better performance. [RFE: 6019] 2000-07-18 Eric Melski * compat/string.h: Fixed function prototypes for strpbrk and strtok [Bug: 6020]. 2000-07-17 David Gravereaux * win/tclWinChan.c: Win2K OS bug with GetStdHandle(STD_OUTPUT_HANDLE) giving the wrong answer. This made TclpGetDefaultStdChannel grab what it thought was a valid native stdout handle. Added a new WriteFile() test to make sure it's really valid. This OS bug doesn't affect the shells. Only -subsystem:windows (aka WinMain) application that dynamically load tclXX.dll [BUG: 5971] 2000-07-17 Eric Melski * library/msgcat1.0/msgcat.tcl: * doc/msgcat.n: * tests/msgcat.test: Applied patches from Chris Nelson, to provide the mcmset function, which allows the translator to set multiple string translations in a single function call, rather than requiring many calls to mcset. [RFE: 6000, 5993]. In addition, these patches correct mcload to use utf-8 encoding on when reading message catalog files, and provides for better default behavior for determining the locale on a Windows system. 2000-07-17 Mo DeJong * unix/tcl.m4 (SC_ENABLE_GCC): Don't set CC=gcc before running AC_PROG_CC if CC is already set. 2000-07-13 Andrщ Pіnitz * doc/lappend.n: * doc/lindex.n: * doc/linsert.n: * doc/list.n: * doc/llength.n: * doc/lrange.n: * doc/lreplace.n: * doc/lsearch.n: * doc/lsort.n: Added SEE ALSO sections. 2000-07-07 Mo DeJong * win/configure.in: Fix definition of TCL_SRC_DIR so that it matches the Unix version. * win/tclConfig.sh.in: Removed duplicate variables. 2000-07-06 Eric Melski * tests/msgcat.test: * library/msgcat1.0/msgcat.tcl: Applied patch from Christian Krone, to provide extended args support for msgcat::unknown, which is used for strings without a known translation in the current locale [Bug: 5984]. 2000-06-29 Eric Melski * doc/msgcat.n: Doc's for mcmax function. * library/msgcat1.0/msgcat.tcl: Applied patches from Laurent Duperval, to add mcmax function, which computes the length of the longest of several translated strings. Bumped version number to 1.1. 2000-06-27 Eric Melski * tests/stringObj.test: Tweaked tests to avoid hardcoded high-ASCII characters (which will fail in multibyte locales); instead used \uXXXX syntax. [Bug: 3842]. 2000-06-26 Eric Melski * doc/package.n: Corrected information about [package forget] arguments [Bug: 5418]. 2000-06-23 Eric Melski * doc/Hash.3: Added documentation patch for Tcl_Obj *'s as keys in Tcl hash tables [RFE: 5934]. * generic/tcl.h: * generic/tclHash.c: Applied patch from [RFE: 5934], which extends Tcl hash tables to allow Tcl_Obj *'s as the key. 2000-06-20 Eric Melski * tests/opt.test: * library/opt0.4/optparse.tcl: Applied patch from [Bug: 5922], which corrected an incorrect use of [string match]. * unix/tclConfig.sh.in: * win/tclConfig.sh.in: Applied patch from [Bug: 5921], which corrects a typo in the comments in these files. 2000-06-19 Eric Melski * doc/RegExp.3: Replaced instances of "Tcl_GetRegExpInfo" with "Tcl_RegExpGetInfo", the correct name of the function [Bug: 5901]. 2000-06-13 Eric Melski * win/tcl.m4: * win/configure.in: * win/Makefile.in: Applied patch from [RFE: 5844], to extend support for mingw compile environment on Windows. * win/tclWinDde.c: * win/tclWinInit.c: * win/tclWinNotify.c: * win/tclWinPipe.c: * win/tclWinReg.c: * win/tclWinThrd.c: Applied patch from [Bug: 5794], to fix compiler warnings when using mingw on Windows. 2000-05-31 Jeff Hobbs * tests/set-old.test: * doc/unset.n: * generic/tclVar.c (Tcl_UnsetObjCmd): added -nocomplain and -- options to unset, to allow for a silent unset operation. 2000-05-31 Eric Melski * generic/tclVar.c (Tcl_ArrayObjCmd): Added support for regexp and exact matching for [array names] command. [RFE: 3684]. * doc/array.n: Added documentation for [array names -exact/-regexp/-glob] [RFE: 3684]. * tests/set-old.test: Added tests for [array names -exact/-regexp/-glob] [RFE: 3684]. 2000-06-06 Jeff Hobbs 8.4a1 RELEASE * generic/tclExecute.c (TclExecuteByteCode INST_STR_CMP): added test of iResult return from memcmp, as memcmp isn't required to return only -1,0,1. 2000-06-03 Jeff Hobbs * generic/tclIndexObj.c (Tcl_GetIndexFromObjStruct): Corrected caching of the index ptr to account for offsets != sizeof(char *). [Bug: 5153] 2000-05-29 Sandeep Tamhankar * tests/http.test * doc/http.n * library/http2.3/http.tcl: Fixed bug 5741, where unsuccessful geturl calls sometimes leaked memory and resources (sockets). Also, switched around some of the logic so that http::wait never throws an exception. This is because in an asynchronous geturl, the command callback will probably end up doing all the error handling anyway, and in an asynchronous situation, the user expects to check the state when the transaction completes, as opposed to being thrown an exception. For the http package, this menas the user can check http::status for "error" and http::error for the error message after doing the http::wait. 2000-05-27 Jeff Hobbs * tests/info.test: * doc/info.n: * generic/tclIOUtil.c (Tcl_EvalFile): * generic/tclCmdIL.c (InfoScriptCmd): added ability to set the info script return value [info script ?newFileName?]. This will be beneficial for virtual file system programs. [Bug: 4225] 2000-05-26 Jeff Hobbs * generic/tclCmdMZ.c (Tcl_RegsubObjCmd): reworked to operate in Unicode, tweaked for performance. (Tcl_StringObjCmd) changed STR_FIRST/STR_LAST error message to something more understandable, reworked STR_FIRST, STR_LAST, STR_MAP, STR_MATCH, STR_RANGE, STR_REPLACE to operate in Unicode. Removed inneffectual STR_RANGE "special" ByteArray support. Optimized STR_MAP algorithm, especially optimized for one-pair case. Fixed possible mem overrun in STR_INDEX bytearray case. * generic/tclCompExpr.c: changed INST_STREQ -> INST_STR_EQ, INST_STRNEQ -> INST_STR_NEQ * generic/tclCompile.c: added streq, strneq, strcmp, strlen & strmatch to the compiled stats instructionTable * generic/tclCompile.h: added instructions INST_STR_CMP, INST_STR_INDEX, INST_STR_MATCH * generic/tclCompCmds.c: added byte compiler support for [string compare|match|index]. * generic/tclExecute.c: Changed INST_STR_(N)EQ to return an Int object and not bother trying to reuse the top stack object. Added INST_STR_CMP, INST_STR_INDEX, INST_STR_MATCH bytecode ops. Extended evalstats output info with Tcl_IsShared stat info. * generic/tclInt.h: * generic/tclObj.c (Tcl_DbIsShared): added support for checking result of Tcl_IsShared in evalstats (TCL_COMPILE_STATS). * generic/tclStringObj.c (Tcl_AppendUnicodeToObj): removed dead code. (AppendUnicodeToUnicodeRep) removed overallocation by extra sizeof(Tcl_UniChar) multiplier. * tests/string.test: added string map tests for the one-pair case, corrected tests to reflect improved error messages in first/last. Added tests against mem overrun in string index bytearray case. 2000-05-23 Eric Melski * generic/tclInt.h: Added function prototypes for TclCompileStringCmd and TclCompileReturnCmd. * generic/tclCompile.h: Added definition of INST_STRLEN opcode and updated LAST_INST_OPCODE value. * generic/tclBasic.c: Added information about TclCompileStringCmd and TclCompileReturnCmd to BuiltInCmds table. * generic/tclExecute.c (TclExecuteByteCode): Added support for the INST_STRLEN opcode. * generic/tclCompCmds.c (TclCompileStringCmd): Basic implementation of byte-compiled [string] command. Not all subcommands are implemented; those that are not an out-line compiled. (TclCompileReturnCmd): Byte-compiled implementation of [return] command. Only "simple" returns are byte-compiled; in particular, if the -code, -errorinfo or -errorcode flags are used, the command is not byte-compiled. 2000-05-22 Jeff Hobbs * doc/scan.n: * doc/array.n: minor doc fixes [Bug: 5396] * generic/tclEnv.c: cast cleanup [Bug: 5624] * win/tclWinConsole.c: cast and header cleanup [Bug: 5625] * win/tclWinSerial.c: cast cleanup [Bug: 5626] * win/tclWinFCmd.c: cast cleanup [Bug: 5627] 2000-05-19 Jeff Hobbs * generic/tclTest.c: * generic/tclIO.c: moved channel test commands from tclIO.c to tclTest.c. * generic/tclIO.h: new file, split out from tclIO.c to allow test commands to be moved to tclTest.c. * generic/tclStubInit.c: * generic/tclIntDecls.h: * generic/tclInt.decls: removed TclTestChannel*Cmd from internal stubs table and added TclChannelEventScriptInvoker to the internal stubs table so it can be used from the test code. 2000-05-18 Eric Melski * tests/clock.test: Added test for "2 days 2 hours ago" style specifications. * generic/tclDate.c: Regenerated from tclGetDate.y. * generic/tclGetDate.y: Tweaked grammar to properly handle the "ago" keyword when it follows multiple relative unit specifiers, as in "2 days 2 hours ago". [Bug: 5497]. 2000-05-18 Jeff Hobbs * win/{tcl.m4,Makefile.in,configure.in}: added support for mingw compile env and cross-compiling. [Bug: 5499] * generic/tclClock.c (FormatClock): correct code to handle locale specific return values from strftime, if any. [Bug: 3345] * unix/tclUnixInit.c (TclpSetInitialEncodings): attempt to correct setlocale calls for XIM support and locale issues. [BUG: 5422 3345 4236 2522 2521] 2000-05-17 Jeff Hobbs * library/init.tcl (auto_import): added check to see if a valid pattern was coming in, to avoid simple error cases [Bug: 3326] * doc/regsub.n: correct regsub docs [Bug: 5346] 2000-05-15 Eric Melski * library/history.tcl: Corrected an off-by-one error in HistIndex, which was causing [history redo] to start its search at the wrong event index. [Bug: 1269]. 2000-05-10 Jeff Hobbs * generic/tclPosixStr.c (Tcl_SignalMsg): clarified #defines for Linux on Sparc to compile correctly. [Bug: 5364] * doc/namespace.n: * tests/namespace.test: * generic/tclNamesp.c (Tcl_NamespaceObjCmd): added 'namespace exists' command. [Bug: 4665] * doc/source.n: * doc/Eval.3: * tests/source.test: * generic/tclIOUtil.c (Tcl_EvalFile): added explicit \32 (^Z) eofchar (affects Tcl_EvalFile in C, "source" in Tcl). This was implicit on Windows already, and is now cross-platform to allow for scripted documents. 2000-05-09 Andreas Kupries operating as proxy for David Gravereaux * win/tclWinThrd.c (TclpInitLock, TclpMasterLock): Added missing initialization of joinLock. 2000-05-09 Eric Melski * tests/lsearch.test: * doc/lsearch.n: * generic/tclCmdIL.c (Tcl_LsearchObjCmd): Extended [lsearch] to support sorted list searching and typed list searching. [RFE: 4098]. 2000-05-08 Jeff Hobbs * doc/expr.n: * tests/expr.test: * tests/expr-old.test: added tests for 'eq' and 'ne' * generic/tclExecute.c: * generic/tclCompile.h: added INST_STREQ and INST_STRNEQ opcodes that do strict string comparisons. * generic/tclCompExpr.c: added 'eq' and 'ne' string comparison operators. * generic/tclParseExpr.c (GetLexeme): added 'eq' and 'ne' expr parse terms (string (in)equality check). * generic/tclCmdIL.c (Tcl_LinsertObjCmd): made use of Tcl_DuplicateObj where code was otherwise duplicated. Made special case of inserting one element at the end work again (where index == len). (Tcl_LreplaceObjCmd): moved Tcl_DuplicateObj call lower and cleaned up use of other arguments. * generic/tclObj.c (Tcl_DuplicateObj): simplified code to call TclInitStringRep, which the code was just duplicating in part. * doc/Utf.3: * generic/tclStubInit.c: * generic/tcl.decls: * generic/tclDecls.h: * generic/tclUtf.c: Added new functions Tcl_UniCharNcasecmp and Tcl_UniCharCaseMatch (unicode parallel to Tcl_StringCaseMatch) * generic/tclUtil.c: rewrote Tcl_StringCaseMatch algorithm for optimization and made Tcl_StringMatch just call Tcl_StringCaseMatch * tests/string.test: extended string match tests 2000-05-08 Eric Melski * tests/set-old.test: * doc/array.n: * generic/tclVar.c: Added [array statistics] command [RFE: 4557] 2000-05-06 Andreas Kupries operating as proxy for David Gravereaux * tclThreadJoin.c: Fixed several places with missing a & in arguments to calls of Tcl_Mutex(Un)lock and Tcl_ConditionNotify functions. 2000-05-02 Jeff Hobbs * README: * generic/tcl.h: * library/init.tcl: * library/reg1.0/pkgIndex.tcl: * library/tcltest1.0/tcltest.tcl: * mac/README: * tools/tcl.hpj.in: * tools/tcl.wse.in: * unix/README: * unix/configure.in: * unix/tcl.spec: * win/README: * win/README.binary: * win/configure.in: * win/makefile.vc: * win/tcl.m4: updated patchlevel to 8.4a1 * tests/compile.test: * tests/init.test: * tests/proc.test: * tests/proc-old.test: * tests/rename.test: * generic/tclProc.c: reworked error return for procedures with incorrect args to be like the C Tcl_WrongNumArgs, where a "wrong # args: ..." message is printed out with the args list. * unix/Makefile.in: add tclsh.ico and tcl.spec to dist target 2000-05-02 Andreas Kupries * Overall changes: (1) Implementation of joinable threads for all platforms. (2) Additional API's for channels. Required to allow the thread extension to move channels between threads. * generic/tcl.decls (lines 1360f): Added Tcl_JoinThread, Tcl_IsChannelShared, Tcl_IsChannelRegistered, Tcl_CutChannel, Tcl_SpliceChannel, Tcl_IsChannelExisting and Tcl_ClearChannelHandlers (slots 394 to 400). * generic/tclIO.c: Implemented Tcl_IsChannelRegistered, Tcl_IsChannelShared, Tcl_CutChannel, Tcl_SpliceChannel, Tcl_IsChannelExisting and Tcl_ClearChannelHandlers. Tcl_CutChannel uses code from CloseChannel. Replaced this code by a call to Tcl_CutChannel. Replaced several code fragments adding channels to the channel list with calls to Tcl_SpliceChannel. Removed now unused variables from CloseChannel and Tcl_UnstackChannel. Tcl_ClearChannelHandlers uses code from Tcl_Close. Replaced this code by a call to Tcl_ClearChannelHandlers. Removed now unused variables from Tcl_Close. Added the subcommands 'cut', 'forgetch', 'splice' and 'isshared' to the test code (TclTestChannelCmd). * unix/tclUnixThread.c: Implemented Tcl_JoinThread using the pthread-functionality. * win/tclWinThrd.c: Fixed several small typos in comments. Implemented Tcl_JoinThread using a platform independent emulation layer (see generic/tclThreadJoin.c below). Added 'joinLock' to serialize Tcl_CreateThread and TclpExitThread to prevent a race for joinable threads. * mac/tclMacThrd.c: Implemented Tcl_JoinThread using a platform independent emulation layer (see generic/tclThreadJoin.c below). Due to the cooperative nature of threading on this platform the race mentioned above is not present. * generic/tclThreadJoin.c: New file. Contains a platform independent emulation layer helping in the implementation of joinable threads for the win and mac platforms. * generic/tclInt.h: Added declarations for TclJoinThread, TclRememberJoinableThread and TclSignalExitThread. These procedures define the API of the emulation layer for joinable threads (see generic/tclThreadJoin.c above). * win/Makefile.in: * win/makefile.vc: Added generic/tclTheadJoin.o to the rules. * mac/: I don't know to which file generic/tclTheadJoin.o has to be added to so that it compiles. Sorry. * unix/tclUnixChan.c: #ifdef'd the thread-local list of file channels as it prevents us from transfering channels. To restore this we may need an extended interface to drivers in the future. Target: 9.0. Found while testing the new transfer of channels. The information in this list for a channel was left behind and then crashed the system during finalization. * generic/tclThreadTest.c: Added -joinable flag to 'testthread create'. Added subcommand 'testthread join'. * doc/CrtChannel.3: Added documentation for Tcl_IsChannelRegistered, Tcl_IsChannelShared, Tcl_CutChannel, Tcl_SpliceChannel, Tcl_IsChannelExisting and Tcl_ClearChannelHandlers. * doc/Thread.3: Added documentation for Tcl_JoinThread. * tests/thread.test: Added tests for joining of threads. 2000-04-27 Eric Melski * doc/library.n: Added entries for auto_qualify and auto_import [Bug: 1271]. * doc/Init.3: Manual entry for Tcl_Init [Bug: 1820]. * doc/expr.n: Added documentation for each of the math library functions that expr supports [Bug: 1054]. 2000-04-26 Eric Melski * doc/memory.n: Man page for Tcl "memory" command, which is created when TCL_MEM_DEBUG is defined at compile time. * doc/TCL_MEM_DEBUG.3: Man page with overall information about TCL_MEM_DEBUG usage. * doc/DumpActiveMemory.3: Man page for Tcl_DumpActiveMemory, Tcl_InitMemory, and Tcl_ValidateAllMemory [Bug: 1816, 1835]. * generic/tclCkalloc.c: Fixed some function headers. * unix/mkLinks: Regen'd with new mkLinks.tcl. * unix/mkLinks.tcl: Fixed indentation, made link setup more intelligent (only do one existance test per man page, instead of one per function). * doc/library.n: Fixed .SH NAME macro to include each function documented on the page, so that mkLinks will know about the functions listed there, and so that the Windows help file index will get set up correctly [Bug: 1898, 5273]. 2000-04-26 Jeff Hobbs 8.3.1 RELEASE * README: * mac/README: * tools/tcl.wse.in: * unix/README: * unix/tcl.spec: * win/README: * win/README.binary: Updating URLs to reference dev.scriptics.com 2000-04-25 Jeff Hobbs * unix/Makefile.in: * win/Makefile.in: * win/makefile.vc: updated for http change and some cleanup * library/http2.[13]: moved dir http2.1 to http2.3 to match version * doc/Utf.3: clarified docs for Tcl_(UniChar|Utf)AtIndex * unix/tclUnixThrd.c: removed {}s around PTHREAD_MUTEX_INITIALIZER [Bug: 5254] * unix/tclLoadDyld.c (TclpLoadFile): removed use of interp->result 2000-04-25 Eric Melski * unix/mkLinks: * doc/AddErrInfo.3: Added information about Tcl_LogCommandInfo [Bug: 1818]. 2000-04-24 Eric Melski * unix/mkLinks: * doc/OpenFileChnl.3: Added man entry for Tcl_Ungets [Bug: 1834]. * unix/mkLinks: * doc/SourceRCFile.3: Man page for Tcl_SourceRCFile [Bug: 1833]. * unix/mkLinks: * doc/ParseCmd.3: Added documentation for Tcl_ParseVar [Bug: 1828]. 2000-04-24 Jeff Hobbs * unix/tclUnixNotfy.c (Tcl_FinalizeNotifier, NotifierThreadProc): added write of 'q' into triggerPipe for notifier in threaded case, so that Tcl doesn't hang when children are still running [Bug: 4139] * unix/tclUnixThrd.c (Tcl_MutexLock): minor comment fixes. 2000-04-23 Jim Ingham These changes make some error handling marginally better for Mac sockets. It is still somewhat flakey, however. * mac/tclMacSock.c (TcpClose): Add timeouts to the close - these don't seem to be honored, however. Use a separate PB for the release, since an async connect socket will still be using the original buffer. Make sure TCPRelease returns noErr before freeing the recvBuff. If the call returns an error, then the buffer is not right. * mac/tclMacSock.c (CreateSocket): Add timeouts to the async create. These don't seem to trigger, however. Sigh... * mac/tclMacSock.c (WaitForSocketEvent): If an TCP_ASYNC_CONNECT socket errors out, then return EWOULDBLOCK & error out. * mac/tclMacSock.c (NotifyRoutine): Added a NotifyRoutine for experimenting with MacTCP. 2000-04-22 Jim Ingham * library/package.tcl (tclPkgUnknown): Fixed a typo in the Mac package search part of tclPkgUnknown. 2000-04-21 Sandeep Tamhankar * library/http2.1/http.tcl: Fixed a newly introduced bug where if there's a -command callback and something goes wrong, geturl threw an exception, called the callback, and unset the token. I changed it so that it will not call the callback when throwing an exception (so the caller only finds out about a given error from one place). Also, fixed http::ncode so that it actually gives you back the http return code (i.e. 200, 404, etc.) instead of the first digit of the version of HTTP being used (i.e. 1). 2000-04-21 Brent Welch * library/http2.1/http.tcl: More thrashing with the "server closes without reading post data" scenario. Reverted to the previous filevent configuratiuon, which seems to work better with small amounts of post data. 2000-04-20 Jeff Hobbs * generic/tclAlloc.c: wrapped caddr_t define to not be done on Unix * unix/tclUnixPort.h: added Tclp*Alloc defines to allow the use of USE_TCLALLOC on Unix. [Bug: 4731] 2000-04-19 Jeff Hobbs * library/dde1.1/pkgIndex.tcl: * library/reg1.0/pkgIndex.tcl: * win/tclWinChan.c: * win/tclWinThrd.c: converted CRLF to LF the */tcl.hpj.in files were not converted, as it confuses hcw locally. [Bug: 5096] * win/Makefile.in: expanded cleanup target for help files * doc/Thread.3: minor macro cleanup * generic/tclFileName.c (SplitUnixPath): added support for QNX node ids. 2000-04-18 Jeff Hobbs * README: * generic/tcl.h: * tools/tcl.wse.in: * unix/configure.in: * unix/tcl.spec: * win/configure.in: * win/README.binary: bumped version to 8.3.1 * win/tcl.hpj.in: updated copyright date * generic/tclEnv.c: environment support for Mac OS/X * unix/tclUnixPort.h: environment support for Mac OS/X * unix/tclLoadDyld.c: new file for Mac OS/X dl functions * unix/Makefile.in: added install-strip target; bindir, libdir, mandir, includedir vars; tclLoadDyld.c target [Bug: 2527] * unix/tclUnixChan.c (CreateSocket): force a socket back into blocking mode (default state) after a -async connect succeeds. [Bug: 4388] * generic/tclEvent.c (TclInitSubsystems): Moved tclLibraryPath to thread-local storage to prevent thread-related race condition. [Bug: 5033] * unix/tclAppInit.c (main): removed #ifdef TCL_TEST that sets the library path as it was unnecessary and conflicts with move of tclLibraryPath to thread-local storage. 2000-04-18 Scott Redman * win/Makefile.in: * win/tcl.rc: * win/tclsh.rc: * win/tclsh.ico: Modified copyright dates in Windows resource files. Added an icon for tclsh.exe. 2000-04-17 Brent Welch * generic/tcl.h, generic/tclThreadTest.c, unix/tclUnixThrd.c, win/tclWinThread.c, mac/tclMacThread.c: Added Tcl_CreateThreadType and TCL_RETURN_THREAD_TYPE macros for declaring the NewThread callback proc. 2000-04-14 Jeff Hobbs * unix/tclUnixChan.c (TtyParseMode): Only allow setting mark/space parity on platforms that support it [Bug: 5089] * generic/tclBasic.c (Tcl_GetVersion): adjusted use of major/minor to not conflict with global decl on some systems [Bug: 2882] * doc/AppInit.3: * doc/Async.3: * doc/BackgdErr.3: * doc/CrtChannel.3: * doc/CrtInterp.3: * doc/CrtMathFnc.3: * doc/DString.3: * doc/Eval.3: * doc/ExprLong.3: * doc/GetInt.3: * doc/GetOpnFl.3: * doc/Interp.3: * doc/LinkVar.3: * doc/OpenFileChnl.3: * doc/OpenTcp.3: * doc/PkgRequire.3: * doc/RecordEval.3: * doc/SetResult.3: * doc/SplitList.3: * doc/StaticPkg.3: * doc/TraceVar.3: * doc/Translate.3: * doc/UpVar.3: * doc/load.n: removed or updated references to interp->result use. 2000-04-13 Jeff Hobbs * doc/regexp.n: doc clarification [Bug: 5037] * doc/update.n: typo fix [Bug: 4996] * unix/tcl.m4 (SC_ENABLE_THREADS): enhanced the detection of pthread_mutex_init [Bug: 4359] and (SC_CONFIG_CFLAGS) added --enable-64bit-vis switch for Sparc VIS compilation [Bug: 4995] 2000-04-12 Jeff Hobbs * doc/dde.n: corrected dde poke docs. [Bug: 4991] 2000-04-11 Eric Melski * win/tclWinPipe.c: Added "CONST" keyword to declaration of char *native in TclpCreateTempFile, to supress compiler warnings. 2000-04-10 Brent Welch * generic/tcl.h: Fixed Tcl_CreateThread declaration. * library/tcltest1.0/tcltest.tcl: Fixed the "mainThread" initialization to work with either testthread or the thread extension * unix/tclUnixThrd.c: Fixed compiler warning when compiling with -DTCL_THREADS 2000-04-10 Eric Melski * win/tclWinPipe.c (TclpCreateTempFile): Added conversion of contents string from UTF to native encoding [Bug: 4030]. * tests/regexp.test: Added tests for infinite looping in [regexp -all]. * generic/tclCmdMZ.c: Fixed infinite loop bug with [regexp -all] [Bug: 4981]. * tests/*.test: Changed all occurances of "namespace import ::tcltest" to "namespace import -force ::tcltest" [Bug: 3948]. 2000-04-09 Brent Welch * lib/httpd2.1/http.tcl: Worked on the "server closes before reading post data" case, which unfortunately causes different error cases on Solaris, which can read the reply, and Linux and Windows, which cannot read anything. This is all in the loop-back case - client and server on the same host. Also unified the error handling so the "ioerror" status goes away and errors are reflected in a more uniform way. Updated the man page to document the behavior. 2000-04-09 Jeff Hobbs * tests/reg.test (matchexpected): corrected tests to use tcltest constraint types to skip certain tests. * generic/tclBasic.c (Tcl_SetCommandInfo): comment fix * unix/tclUnixThrd.c (Tcl_CreateThread): moved TCL_THREADS ifdef inside of func as it is declared for non-threads builds as well. In the non-threads case, it always returns TCL_ERROR (couldn't create thread). 2000-04-08 Andreas Kupries * Overall change: Definition of a public API for the creation of new threads. * generic/tclInt.h (line 1802f): Removed the definition of 'TclpThreadCreate'. (line 793f) Removed the definition of 'Tcl_ThreadCreateProc'. * generic/tcl.h (line 388f): Readded the definition of 'Tcl_ThreadCreateProc'. Added Win32 stuff send in by David Graveraux to that too (__stdcall, ...). Added macros for the default stacksize and allowed flags. * generic/tcl.decls (line 1356f): Added definition of 'Tcl_CreateThread', slot 393 of the stub table. Two new arguments in the public API, for stacksize and flags. * win/tclWinThrd.c: * mac/tclMacThrd.c: Renamed TclpThreadCreate to Tcl_CreateThread, added handling of the stacksize. Flags are currently ignored. * unix/tclUnixThrd.c: See above, but handles joinable flag. Ignores the specified stacksize if the macro HAVE_PTHREAD_ATTR_SETSTACKSIZE is not defined. * generic/tclThreadTest.c (line 363): See below. * unix/tclUnixNotfy.c (line 210): Adapted to the changes above. Uses default stacksize and no flags now. * unic/tcl.m4 (line 382f): Added a check for 'pthread_attr_setstacksize' to detect platforms not implementing this feature of pthreads. If it is implemented, configure will define the macro HAVE_PTHREAD_ATTR_SETSTACKSIZE (See unix/tclUnixThrd.c too). * doc/Thread.3: Added Tcl_CreateThread and its arguments to the list of described functions. Removed stuff about not providing a public C-API for thread-creation. 2000-04-07 Jeff Hobbs * doc/binary.n: clarified docs on sign extension in binary scan [Bug: 3466] * library/tcltest1.0/tcltest.tcl (initConstraints): removed win32s references (no longer supported) * tests/fCmd.test: marked test 8.1 knownBug because it is dangerous on poorly configured systems [Bug: 3881] and added 8.2 to keep essence of 8.1 tested. 2000-04-05 Andreas Kupries * generic/tclIO.c (Tcl_UnstackChannel, line 1831): Forcing interest mask to the correct value after an unstack and re-initialization of the notifier via the watchProc. Without this the first fileevent after an unstack will come through and be processed, but no more. [Bug: ??]. 2000-03-04 Brent Welch * {win,unix}/Makefile.in: added dependency of tclStubInit.c on tcl.decls and tclInt.decls * generic/tclThread.c: Tweak so this compiles w/out TCL_THREADS * generic/{tcl.decls,tclStubInit.c}: Just touched the tcl.decls and regenerated the tclStubInit.c file 2000-03-29 Sandeep Tamhankar * library/http2.1/http.tcl: For the -querychannel option, fconfigure the socket to be binary so that we don't translate anything while reading the data. This is because we determine the content length of the data on the channel by using seek (to the end of the file) and tell on the file handle, and we need the content-length to match the amount of data actually sent, and translation can affect the number of bytes posted. 2000-04-03 Andreas Kupries * Overall change: Definition of public API's for the finalization of conditions and mutexes. [Bug: 4199]. * generic/tclInt.h: Removed definitions of TclFinalizeMutex and TclFinalizeCondition. * generic/tcl.decls: Added declarations of Tcl_MutexFinalize and Tcl_ConditionFinalize. * generic/tclThread.c: Renamed TclFinalizeMutex to Tcl_MutexFinalize. Renamed TclFinalizeCondition to Tcl_ConditionFinalize. * generic/tclNotify.c: Changed usage of TclFinalizeMutex to Tcl_MutexFinalize. * unix/tclUnixNotfy.c: * generic/tclThreadTest.c: Changed usages of TclFinalizeCondition to Tcl_ConditionFinalize. * generic/tcl.h: Added empty macros for Tcl_MutexFinalize and Tcl_ConditionFinalize, to be used when the core is compiled without threads. * doc/Thread.3: Added description the new API's. 2000-04-03 Jeff Hobbs * generic/tclCmdIL.c (InfoVarsCmd): checked for non-NULL procPtr to prevent itcl info override crash [Bug: 4064] * tests/foreach.test: * tests/namespace.test: * tests/var.test: Added lsorts to avoid random sorted return problems. [Bug: 2682] * tests/fileName.test: fixed 14.1 test fragility [Bug: 1482] * tools/man2help2.tcl: fixed winhelp cross-linking error [Bug: 4156] improved translation to winhelp [Bug: 3679] * unix/Makefile.in (MAN_INSTALL_DIR): patch to accept --mandir correctly [Bug: 4085] * unix/dltest/pkg[a-e].c: Cleaned up test packages [Bug: 2293] 2000-04-03 Eric Melski * unix/tclUnixFCmd.c (SetGroupAttribute): * unix/tclUnixFCmd.c (SetOwnerAttribute): Added (uid_t) and (gid_t) casts to avoid compiler warnings. 2000-03-31 Eric Melski * generic/tclGet.c (Tcl_GetDouble): Added additional conditions to error test (previously only errno was checked, but the return value of strtod() should be checked as well). [Bug: 4118]. * tests/exec.test: Added test for proper conversion of UTF data when used with "<< $dataWithUTF" on exec's. * unix/tclUnixPipe.c (TclpCreateTempFile): Added Tcl_UtfToExternalDString call, so that if there is UTF content in the string it will be properly converted to the system encoding before being written [Bug: 4030]. (TclpCreateTempFile): Added a check on the return value of tmpnam; some systems (Linux, for example) will start to return NULL after tmpnam has been called TMP_MAX times; not checking for this can have bad results (overwriting temp files, core dumps, etc.) 2000-03-30 Jeff Hobbs * generic/tclBasic.c (Tcl_DeleteCommandFromToken): Added comments noting the need to pair ckalloc with ckfree. [Bug: 4262] * generic/tclInt.decls: * generic/tclIntPlatDecls.h: * generic/tclStubInit.c: * win/tclWin32Dll.c: removed TclWinSynchSpawn (vestige of Win32s support). * win/tclWinReg.c: made use of TclWinGetPlatformId instead of getting info again * win/tclWinPort.h: * win/Makefile.in: * win/configure.in: * win/tcl.m4: Added support for gcc/mingw on Windows [Bug: 4234] 2000-03-29 Jeff Hobbs * generic/tclCompile.c (TclCleanupByteCode): made ByteCode cleanup more aware of TCL_BYTECODE_PRECOMPILED flagged structs (gen'd by tbcload), to correctly clean them up. * generic/tclClock.c (FormatClock): moved check for empty format earlier, commented 0 result return value 2000-03-29 Sandeep Tamhankar * library/http2.1/http.tcl: Removed an unnecessary fileevent statement from the error processing part of the Write method. Also, fixed two potential memory leaks in wait and reset, in which the state array wasn't being unset before throwing an exception. Prior to this version, Brent checked in a fix to catch a fileevent statement that was sometimes causing a stack trace when geturl was called with -timeout. I believe Brent's fix is necessary because TLS closes bad sockets for secure connections, and the fileevent was trying to act on a socket that no longer existed. 2000-03-27 Jeff Hobbs * tests/httpd: removed unnecessary 'puts stderr "Post Dispatch"' * tests/namespace.test: * generic/tclNamesp.c (Tcl_Export): added a uniq'ing test to the export list so only one instance of each export pattern would exist in the list. * generic/tclExecute.c (TclExecuteByteCode): optimized case for the empty string in ==/!= comparisons 2000-03-27 Eric Melski * unix/tclUnixChan.c: Added (off_t) type casts in lseek() call [Bug: 4409]. * unix/tclLoadAout.c: * unix/tclUnixPipe.c: Added (off_t) type casts in lseek() calls [Bug: 4410]. 2000-03-22 Sandeep Tamhankar * library/http2.1/http.tcl: Fixed a bug where string query data that was bigger than queryblocksize would get duplicate characters at block boundaries. 2000-03-22 Sandeep Tamhankar * library/http2.1/http.tcl: Fixed bug 4463, where we were getting a stack trace if we tried to publish a project to a good host but a port where there was no server listening. It turned out the problem was a stray fileevent that needed to be cleared. Also, fixed a bug where http::code could stack trace if called on a bad token (one which didn't represent a successful geturl) by adding an http element to the state array in geturl. 2000-03-21 Eric Melski * tests/clock.test: Modified some tests that were not robust with respect to the time zone in which they were run and were thus failing. * doc/clock.n: Clarified meaning of -gmt with respect to -base when used with [clock scan] (-gmt does not affect the interpretation of -base). 2000-03-19 Sandeep Tamhankar * library/http2.1/http.tcl: geturl used to throw an exception when the connection failed; I accidentally returned a token with the error info, breaking backwards compatibility. I changed it back to throwing an exception, but unsetting the state array first (thus still eliminating the original memory leak problem). 2000-03-19 Sandeep Tamhankar * library/http2.1/http.tcl: Added -querychannel option and altered some of Brent's modifications to allow asynchronous posts (via -command). Also modified -queryprogress so that it calls the query callback as to be consistent with -progress. Added -queryblocksize option with default 8192 bytes for post blocksize. Fixed a bunch of potential memory leaks for the case when geturl receives bad args or can't open a socket, etc. Overall, the package really rocks now. * doc/http.n: Added -queryblocksize, -querychannel, and -queryprogress. Also, changed the description of -blocksize, which states that the -progress callback will be called for each block, to now qualify that with an "if -progress is specified". * tests/http.test: Added a querychannel test for synchronous and asynchronous posts, altered the queryprogress test such that the callback conforms to the -progress format. Also, had to use the -queryblocksize option to do the post 16K at a time to match Brent's expected results (and to test that -queryblocksize works). 2000-03-15 Brent Welch * library/http2.1/http.tcl: Added -queryprogress callback to http::geturl and also changed it so that writing the post data is event driven if the queryprogress callback or a timeout is given. This allows a timeout to occur when writing lots of post data. The queryprogress callback is called after each block of query data is posted. It has the same signature as the -progress callback. 2000-03-06 Eric Melski * library/package.tcl: Applied patch from Bug: 2570; rather than setting geometry of slave interp to 0x0 when Tk was loaded, it now does "wm withdraw .". Both remove the main window from the display, but the former caused some internal structures to get initialized to zero, which caused crashes with some extensions. 2000-03-02 Jeff Hobbs * library/package.tcl (tclPkgUnknown): extended to allow recognizes changes in the auto_path while sourcing in other pkgIndex.tcl files * doc/FindExec.3: fixed doc for declaration of Tcl_FindExecutable [Bug: 4275] * generic/tclFileName.c (Tcl_TranslateFileName): Applied patch from Newman to significantly speedup file split/join on Windows (replaces regexp with custom parser). [Bug: 2867] * win/README.binary: change mailing lists from @consortium.org to @scriptics.com [Bug: 4173] 2000-02-28 Eric Melski * tests/clock.test: Added test for ISO bases < 100000 * generic/tclDate.c: (generated on Solaris) * generic/tclGetDate.y: Changed condition for deciding if a number is an ISO 8601 base from number >= 100000 to numberOfDigits >= 6. Previously it would fail to recognize 000000 as an ISO base. 2000-02-14 Eric Melski * unix/Makefile.in: Added rpm target to generate Tcl binary RPM. * unix/tcl.spec: RPM specification file for a Tcl binary RPM for Linux. 2000-02-10 Jeff Hobbs 8.3.0 RELEASE * changes: updated for 8.3.0 release * doc/load.n: added notes about dll load errors on Windows * unix/README: * unix/Makefile.in (dist): removed porting.notes and porting.old from distribution and CVS. The information was very outdated. Now refer to http://dev.scriptics.com/services/support/platforms.html * tests/unixInit.test: fixed japanese LANG encoding test [Bug: 3549] * unix/configure.in: * unix/tcl.m4: correct CFLAG_WARNING setting, fixed gcc config for AIX, added -export-dynamic to LDFLAGS for FreeBSD-3+ [Bug: 2998] * win/tclWinLoad.c (TclpLoadFile): improved error message for load failures, could perhaps be even more intelligent. 2000-02-09 Jim Ingham * mac/tclMacSock.c: Don't panic when you get an error closing an async socket. This doesn't seem to hurt anything, and we return the error so the caller can do the right thing. New Files: * mac/MW_TclHeader.h: * mac/MW_TclTestHeader.h: * mac/MW_TclTestHeader.pch: * mac/MW_TclAppleScriptHeader.h: More convenient to use .h prefix files in the preference panels... The above are curtesy of Daniel Steffen (steffen@math.mq.edu.au) 2000-02-08 Eric Melski * tests/clock.test: Added tests for "next monthname" constructs. * generic/tclDate.c: * generic/tclGetDate.y (Message): Added a grammar rule for "next monthname" so that we can handle "next january" and similar constructs (bug #4146). 2000-02-08 Jeff Hobbs * README: * tools/tcl.wse.in: * unix/configure.in: * win/configure.in: * win/README: * win/README.binary: * generic/tcl.h (TCL_RELEASE_SERIAL): Moved to 8.3.0 patchlevel * doc/library.n: * library/auto.tcl: fixed crufty puts code and docs [Bug: 4122] * library/tcltest1.0/tcltest.tcl: correctly protected searchDirectory list to allow dirnames with spaces * unix/tcl.m4: changed all -fpic to -fPIC * generic/tclDecls.h: * generic/tcl.decls: change Tcl_GetOpenFile to use decl of 'int forWriting' instead of 'int write' to avoid shadowing [Bug: 4121] * tests/httpold.test: changed test script to source in the httpd server procs from httpd instead of having its own set. * tests/httpd: improved query support in test httpd to handle fix in http.tcl. [Bug: 4089 change 2000-02-01] * unix/README: fixed notes about --enable-shared and add note about --disable-shared. 2000-02-07 Eric Melski * tests/package.test: * library/tclIndex: * library/package.tcl: Renamed ::package namespace to ::pkg. 2000-02-03 Eric Melski * doc/Package.n: * doc/packagens.n: Renamed Package.n -> packagens.n because Windows can't deal with case-sensitive names. 2000-02-02 Jeff Hobbs * tests/regexp.test: added tests for -all and -inline switches * doc/regexp.n: added docs for -all and -inline switches * generic/tclCmdMZ.c (Tcl_RegexpObjCmd): added extra comments for new -all and -inline switches to regexp command 2000-02-01 Eric Melski * library/init.tcl: Applied patch from rfe 1734 regarding auto_load errors not setting error message and errorInfo properly. 2000-02-01 Jeff Hobbs * win/Makefile.in (install-*): reduced verbosity of install * generic/tclFileName.c (Tcl_JoinPath): improved support for special QNX node id prefixes in pathnames [Bug: 4053] * library/http1.0/http.tcl: * library/http2.1/http.tcl: The query data POSTed was newline terminated when it shouldn't be altered [Bug: 4089] 2000-01-31 Eric Melski * tests/package.test: * library/tclIndex: * library/package.tcl: Added ::package namespace and ::package::create function. * library/init.tcl: Fixed problem with auto_load and determining if commands were loaded. * library/auto.tcl: "Fixed" issues with $ in files to be auto indexed. * doc/Package.n: New man page for package::create function. * doc/pkgMkIndex.n: Added additional information. * doc/library.n: Added additional qualification regarding auto_mkindex. 2000-01-28 Eric Melski * tests/pkg/magicchar2.tcl: * tests/autoMkindex.test: Test for auto loader fix (bug #2480). * library/init.tcl: auto_load was using [info commands $name] to determine if a given command was available; if the command name had * or [] it, this would fail because info commands uses glob-style matching. This is fixed. (Bug #2480). * tests/pkg/spacename.tcl: * tests/pkgMkIndex.test: Tests for fix for bug #2360. * library/package.tcl: Fixed to extract only the first element of the list returned by auto_qualify (bug #2360). * tests/pkg/magicchar.tcl: * tests/autoMkindex.test: Test for fix for bug #2611. * library/auto.tcl: Fixed the regular expression that performs $ escaping before sourcing a file to index. It was erroneously adding \ escapes even to $'s that were already escaped, effectively "un-escaping" those $'s. (bug #2611). 2000-01-27 Eric Melski * tests/autoMkindex.test: * library/auto.tcl: Applied patch (with slight modification) from bug #2701: auto_mkIndex uses platform dependent file paths. Added test for fix. 2000-01-27 Jennifer Hom * library/tcltest1.0/tcltest.tcl: Changed NormalizePath to normalizePath and exported it as a public proc. This proc creates an absolute path given the name of the variable containing the path to modify. The path is modified in place. * library/tcltest1.0/pkgIndex.tcl: Added normalizePath. * tests/all.tcl: Changed code to use normalizePath. 2000-01-27 Eric Melski * tests/pkg/samename.tcl: test file for bug #1983 * tests/pkgMkIndex.test: * doc/pkgMkIndex.n: * library/package.tcl: Per rfe #4097, optimized creation of direct load packages to bypass computing the list of commands added by the new package. Also made direct loading the default, and added a -lazy option. Fixed bug #1983, dealing with pkg_mkIndex incorrectly handling situations with two procs by the same name but in different namespaces (ie, foo::baz and bar::baz). 2000-01-26 Eric Melski * generic/tclNamesp.c: Undid fix for #956, which broke backwards compatibility. * doc/variable.n: * doc/trace.n: * doc/namespace.n: * doc/info.n: Added further information about differences between "namespace which" and "info exists". * doc/SetErrno.3: Added descriptions of ErrnoId() and ErrnoMsg() functions. 2000-01-25 Jeff Hobbs * unix/tcl.m4: modified EXTRA_CFLAGS to add -DHAVE_TZSET for OSF1-V* and ULTRIX-4.* when not using gcc. Also added higher min stack size for OSF1-V* when building with threads. [Bug: 4063] * generic/tclClock.c (FormatClock): inlined resultPtr, as it conflicted with var creation for HAVE_TZSET #def [Bug: 4063] * generic/tclCmdIL.c (Tcl_LsortObjCmd): fixed potential leak when calling lsort -command with bad command [Bug: 4067] * generic/tclFileName.c (Tcl_JoinPath): added support for special QNX node id prefixes in pathnames [Bug: 4053] * doc/ListObj.3: clarified Tcl_ListObjGetElements docs [Bug: 4080] * doc/glob.n: clarified Mac path separator determination docs. * win/makefile.vc: added some support for building helpfile on Windows 2000-01-23 Jeff Hobbs * library/init.tcl (auto_execok): added 'start' to list of recognized built-in commands for COMSPEC on NT. [Bug: 2858] * unix/tclUnixPort.h: moved include of lower since some systems (UTS) require sys/types.h to be included first [Bug: 4031] * unix/tclUnixChan.c (CreateSocketAddress): changed comparison with -1 to 0xFFFFFFFF, to ensure 32 bit comparison even on 64 bit systems. [Bug: 3878] * generic/tclFileName.c: improved guessing of path separator for the Mac. (Darley) * generic/tclInt.h: * generic/tcl.decls: moved Tcl_ProcObjCmd to stubs table [Bug: 3827] and removed 'register' from stub definition of Tcl_AppendUnicodeToObj [Bug: 4038] 2000-01-21 Eric Melski * unix/mkLinks: * doc/GetHostName.3: Man page for Tcl_GetHostName (bug #1817). * doc/lreplace.n: Corrected man page with respect to treatment of empty lists, and "prettied up" the page. (bug #1705). 2000-01-20 Eric Melski * tests/namespace.test: Added test for undefined variables with namespace which (bug #956). * generic/tclNamesp.c: Added check for undefined variables in NamespaceWhichCmd (bug #956). * tests/var.test: Added tests for corrected variable behavior (bug #981). * doc/upvar.n: Expanded explanation of upvar behavior with respect to variable traces. (bugs 3917 1433 2110). * generic/tclVar.c: Changed behavior of variable command when name refers to an element in an array (ie, "variable foo(x)") to always return an error, regardless of existance of that element in the array (now behavior is consistant with docs too) (bug #981). 2000-01-20 Jeff Hobbs * generic/tclCmdIL.c (InfoBodyCmd): made [info body] return a string if the body has been bytecompiled. * generic/tclBasic.c (Tcl_EvalObjEx): added pedantic check for originating proc body of bytecompiled code, #def'd out as the change for [info body] should make it unnecessary * unix/tclUnixNotfy.c (Tcl_InitNotifier): added cast for tsdPtr * tests/set.test: added test for complex array elem name compiling * generic/tclCompCmds.c (TclCompileSetCmd): Fixed parsing of array elements during compiling, and slightly optimised same [Bug: 3889] * doc/tclvars.n: added definitions for tcl_(non)wordchars * doc/vwait.n: added notes about requirement for vwait var being globally scoped [Bug: 3329] * library/word.tcl: changed tcl_(non)wordchars settings to use new unicode regexp char class escapes instead of char sequences 2000-01-14 Eric Melski * tests/var.test: Added a test for the array multiple delete protection in Tcl_UnsetVar2. * generic/tclVar.c: Added protection in Tcl_UnsetVar2 against attempts to multiply delete arrays when unsetting them (bug #3453). This could happen if there was an unset trace on an array element and the trace proc made a global or upvar link to the array, and then the array was unset at the global level. See the bug reference for more information. * unix/tclUnixTime.c: New clock format format. * compat/strftime.c: New clock format format. * generic/tclGetDate.y: New clock scan format. 2000-01-13 Jeff Hobbs * changes: updated changes file to reflect 8.3b2 mods * README: * generic/tcl.h: * tools/tcl.wse.in: * unix/configure.in: * unix/tcl.m4: * win/README.binary: * win/configure.in: updated to patchlevel 8.3b2 * generic/regexec.c: added var initialization to prevent compiler warning 2000-01-13 Eric Melski * tests/cmdIL.test: Added tests for lsort -dictionary with characters that occur between Z and a in ASCII. * generic/tclCmdIL.c: Modified DictionaryCompare function (used by lsort -dictionary) to do upper/lower case equivalency before doing character comparisons, instead of after. This fixes bug #1357, in which lsort -dictionary [list ` AA c CC] and lsort -dictionary [list AA c ` CC] gave different (and both wrong) results. 2000-01-12 Eric Melski * tests/clock.test: Added tests for "next " and "" Added tests for "monday 1 week ago", etc, from RFE #3671. * doc/tests/clock.test: Added numerous tests for clock scan. * doc/generic/tclGetDate.y: Fixed some shift/reduce conflicts in clock grammar. * doc/doc/clock.n: Added documentation for new supported clock scan formats and additional explanation of daylight savings time correction algorithm. 2000-01-12 Jeff Hobbs * doc/file.n: * tests/unixFCmd.test: * unix/tclUnixFCmd.c: added support for symbolic permissions setting in SetPermissionsAttribute (file attr $file -perm ...) [Bug: 3970] * generic/tclClock.c: fixed support for 64bit handling of clock values [Bug: 1806] * generic/tclThreadTest.c: upped a buffer size to hold double * tests/info.test: * generic/tclCmdIL.c: fixed 'info procs ::namesp::*' behavior (Dejong) * generic/tclNamesp.c: made imported commands also import their compile proc [Bug: 2100] * tests/expr.test: * unix/Makefile.in: * unix/configure.in: * unix/tcl.m4: recognize strtod bug on Tru64 v5.0 [Bug: 3378] and added tests to prevent unnecessary chmod +x in sources while installing, as well as more intelligent setsockopt/gethostbyname checks [Bug: 3366, 3389] * unix/tclUnixThrd.c: added compile time support (through use of the TCL_THREAD_STACK_MIN define) for increasing the default stack size for a thread. [Bug: 3797, 1966] 2000-01-11 Eric Melski * generic/tclGetDate.y: Added comments for the Convert function. Added a fix for daylight savings time handling for relative time spans of days, weeks or fortnights. (bug 3441, 3868). * generic/tclDate.c: Fixed compiler warning issues. 2000-01-10 Jeff Hobbs * compat/waitpid.c: use pid_t type instead of int [Bug: 3999] * tests/utf.test: fixed test that allowed \8 as octal value * generic/tclUtf.c: changed Tcl_UtfBackslash to not allow non-octal digits (8,9) in \ooo substs. [Bug: 3975] * generic/tcl.h: noted need to change win/tcl.m4 and tools/tclSplash.bmp for minor version changes * library/http2.1/http.tcl: trim value for $state(meta) key * unix/tclUnixFile.c: fixed signature style on functions * unix/Makefile.in: made sure tcl.m4 would be installed with dist * unix/tcl.m4: added ELF support for NetBSD [Bug: 3959] 2000-01-10 Eric Melski * generic/tclGetDate.y: Added rules for ISO 8601 formats (BUG #847): CCYY-MM-DD CCYYMMDD YY-MM-DD YYMMDD CCYYMMDDTHHMMSS CCYYMMDD HHMMSS CCYYMMDDTHH:MM:SS Fixed "clock scan " to scan the number as an hour for the current day, rather than a minute after 00:00 for the current day (bug #2732). 2000-01-07 Eric Melski * generic/tclClock.c: Changed switch in Tcl_ClockObjCmd to use enumerated values instead of constants. (ie, COMMAND_SCAN instead of 3). tcl8.4.20/win/0000755003604700454610000000000012153151143011476 5ustar dgp771divtcl8.4.20/win/tcl.hpj.in0000644003604700454610000000053712153151143013375 0ustar dgp771div; This file is maintained by HCW. Do not modify this file directly. [OPTIONS] HCW=0 LCID=0x409 0x0 0x0 ;English (United States) REPORT=Yes TITLE=Tcl/Tk Reference Manual CNT=tcl84.cnt COPYRIGHT=Copyright ТЉ 2000 Ajuba Solutions HLP=tcl84.hlp [FILES] tcl.rtf [WINDOWS] main="Tcl/Tk Reference Manual",,0 [CONFIG] BrowseButtons() tcl8.4.20/win/buildall.vc.bat0000644003604700454610000000310212153151142014360 0ustar dgp771div@echo off :: This is an example batchfile for building everything. Please :: edit this (or make your own) for your needs and wants using :: the instructions for calling makefile.vc found in makefile.vc echo Sit back and have a cup of coffee while this grinds through ;) echo You asked for *everything*, remember? echo. title Building Tcl, please wait... if "%MSVCDir%" == "" call c:\dev\devstudio60\vc98\bin\vcvars32.bat ::if "%MSVCDir%" == "" call "C:\Program Files\Microsoft Developer Studio\vc98\bin\vcvars32.bat" set INSTALLDIR=C:\Program Files\Tcl :: Build the normal stuff along with the help file. :: nmake -nologo -f makefile.vc release winhelp OPTS=none if errorlevel 1 goto error :: Build the static core, dlls and shell. :: nmake -nologo -f makefile.vc release OPTS=static if errorlevel 1 goto error :: Build the special static libraries that use the dynamic runtime. :: nmake -nologo -f makefile.vc core dlls OPTS=static,msvcrt if errorlevel 1 goto error :: Build the core and shell for thread support. :: nmake -nologo -f makefile.vc shell OPTS=threads if errorlevel 1 goto error :: Build a static, thread support core library (no shell). :: nmake -nologo -f makefile.vc core OPTS=static,threads if errorlevel 1 goto error :: Build the special static libraries the use the dynamic runtime, :: but now with thread support. :: nmake -nologo -f makefile.vc core dlls OPTS=static,msvcrt,threads if errorlevel 1 goto error goto end :error echo *** BOOM! *** :end title Building Tcl, please wait...DONE! echo DONE! pause tcl8.4.20/win/aclocal.m40000644003604700454610000000003012153151142013326 0ustar dgp771divbuiltin(include,tcl.m4) tcl8.4.20/win/tcl.rc0000644003604700454610000000275111737050675012632 0ustar dgp771div// Version Resource Script // #include #include // // build-up the name suffix that defines the type of build this is. // #ifdef TCL_THREADS #define SUFFIX_THREADS "t" #else #define SUFFIX_THREADS "" #endif #ifdef DEBUG #define SUFFIX_DEBUG "d" #else #define SUFFIX_DEBUG "" #endif #define SUFFIX SUFFIX_THREADS SUFFIX_DEBUG LANGUAGE 0x9, 0x1 /* LANG_ENGLISH, SUBLANG_DEFAULT */ VS_VERSION_INFO VERSIONINFO FILEVERSION TCL_MAJOR_VERSION,TCL_MINOR_VERSION,TCL_RELEASE_LEVEL,TCL_RELEASE_SERIAL PRODUCTVERSION TCL_MAJOR_VERSION,TCL_MINOR_VERSION,TCL_RELEASE_LEVEL,TCL_RELEASE_SERIAL FILEFLAGSMASK 0x3fL #ifdef DEBUG FILEFLAGS VS_FF_DEBUG #else FILEFLAGS 0x0L #endif FILEOS VOS__WINDOWS32 FILETYPE VFT_DLL FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" /* LANG_ENGLISH/SUBLANG_ENGLISH_US, Unicode CP */ BEGIN VALUE "FileDescription", "Tcl DLL\0" VALUE "OriginalFilename", "tcl" STRINGIFY(JOIN(TCL_MAJOR_VERSION,TCL_MINOR_VERSION)) SUFFIX ".dll\0" VALUE "CompanyName", "ActiveState Corporation\0" VALUE "FileVersion", TCL_PATCH_LEVEL VALUE "LegalCopyright", "Copyright \251 2001 by ActiveState Corporation, et al\0" VALUE "ProductName", "Tcl " TCL_VERSION " for Windows\0" VALUE "ProductVersion", TCL_PATCH_LEVEL END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END tcl8.4.20/win/tclWinFCmd.c0000644003604700454610000015670412052456744013666 0ustar dgp771div/* * tclWinFCmd.c * * This file implements the Windows specific portion of file manipulation * subcommands of the "file" command. * * Copyright (c) 1996-1998 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclWinInt.h" /* * The following constants specify the type of callback when * TraverseWinTree() calls the traverseProc() */ #define DOTREE_PRED 1 /* pre-order directory */ #define DOTREE_POSTD 2 /* post-order directory */ #define DOTREE_F 3 /* regular file */ /* * Callbacks for file attributes code. */ static int GetWinFileAttributes _ANSI_ARGS_((Tcl_Interp *interp, int objIndex, Tcl_Obj *fileName, Tcl_Obj **attributePtrPtr)); static int GetWinFileLongName _ANSI_ARGS_((Tcl_Interp *interp, int objIndex, Tcl_Obj *fileName, Tcl_Obj **attributePtrPtr)); static int GetWinFileShortName _ANSI_ARGS_((Tcl_Interp *interp, int objIndex, Tcl_Obj *fileName, Tcl_Obj **attributePtrPtr)); static int SetWinFileAttributes _ANSI_ARGS_((Tcl_Interp *interp, int objIndex, Tcl_Obj *fileName, Tcl_Obj *attributePtr)); static int CannotSetAttribute _ANSI_ARGS_((Tcl_Interp *interp, int objIndex, Tcl_Obj *fileName, Tcl_Obj *attributePtr)); /* * Constants and variables necessary for file attributes subcommand. */ enum { WIN_ARCHIVE_ATTRIBUTE, WIN_HIDDEN_ATTRIBUTE, WIN_LONGNAME_ATTRIBUTE, WIN_READONLY_ATTRIBUTE, WIN_SHORTNAME_ATTRIBUTE, WIN_SYSTEM_ATTRIBUTE }; static const int attributeArray[] = {FILE_ATTRIBUTE_ARCHIVE, FILE_ATTRIBUTE_HIDDEN, 0, FILE_ATTRIBUTE_READONLY, 0, FILE_ATTRIBUTE_SYSTEM}; CONST char *tclpFileAttrStrings[] = { "-archive", "-hidden", "-longname", "-readonly", "-shortname", "-system", (char *) NULL }; CONST TclFileAttrProcs tclpFileAttrProcs[] = { {GetWinFileAttributes, SetWinFileAttributes}, {GetWinFileAttributes, SetWinFileAttributes}, {GetWinFileLongName, CannotSetAttribute}, {GetWinFileAttributes, SetWinFileAttributes}, {GetWinFileShortName, CannotSetAttribute}, {GetWinFileAttributes, SetWinFileAttributes}}; #ifdef HAVE_NO_SEH /* * Unlike Borland and Microsoft, we don't register exception handlers * by pushing registration records onto the runtime stack. Instead, we * register them by creating an EXCEPTION_REGISTRATION within the activation * record. */ typedef struct EXCEPTION_REGISTRATION { struct EXCEPTION_REGISTRATION* link; EXCEPTION_DISPOSITION (*handler)( struct _EXCEPTION_RECORD*, void*, struct _CONTEXT*, void* ); void* ebp; void* esp; int status; } EXCEPTION_REGISTRATION; #endif /* * Prototype for the TraverseWinTree callback function. */ typedef int (TraversalProc)(CONST TCHAR *srcPtr, CONST TCHAR *dstPtr, int type, Tcl_DString *errorPtr); /* * Declarations for local procedures defined in this file: */ static void StatError(Tcl_Interp *interp, Tcl_Obj *fileName); static int ConvertFileNameFormat(Tcl_Interp *interp, int objIndex, Tcl_Obj *fileName, int longShort, Tcl_Obj **attributePtrPtr); static int DoCopyFile(CONST TCHAR *srcPtr, CONST TCHAR *dstPtr); static int DoCreateDirectory(CONST TCHAR *pathPtr); static int DoRemoveJustDirectory(CONST TCHAR *nativeSrc, int ignoreError, Tcl_DString *errorPtr); static int DoRemoveDirectory(Tcl_DString *pathPtr, int recursive, Tcl_DString *errorPtr); static int DoRenameFile(CONST TCHAR *nativeSrc, CONST TCHAR *dstPtr); static int TraversalCopy(CONST TCHAR *srcPtr, CONST TCHAR *dstPtr, int type, Tcl_DString *errorPtr); static int TraversalDelete(CONST TCHAR *srcPtr, CONST TCHAR *dstPtr, int type, Tcl_DString *errorPtr); static int TraverseWinTree(TraversalProc *traverseProc, Tcl_DString *sourcePtr, Tcl_DString *dstPtr, Tcl_DString *errorPtr); /* *--------------------------------------------------------------------------- * * TclpObjRenameFile, DoRenameFile -- * * Changes the name of an existing file or directory, from src to dst. * If src and dst refer to the same file or directory, does nothing * and returns success. Otherwise if dst already exists, it will be * deleted and replaced by src subject to the following conditions: * If src is a directory, dst may be an empty directory. * If src is a file, dst may be a file. * In any other situation where dst already exists, the rename will * fail. * * Results: * If the file or directory was successfully renamed, returns TCL_OK. * Otherwise the return value is TCL_ERROR and errno is set to * indicate the error. Some possible values for errno are: * * ENAMETOOLONG: src or dst names are too long. * EACCES: src or dst parent directory can't be read and/or written. * EEXIST: dst is a non-empty directory. * EINVAL: src is a root directory or dst is a subdirectory of src. * EISDIR: dst is a directory, but src is not. * ENOENT: src doesn't exist. src or dst is "". * ENOTDIR: src is a directory, but dst is not. * EXDEV: src and dst are on different filesystems. * * EACCES: exists an open file already referring to src or dst. * EACCES: src or dst specify the current working directory (NT). * EACCES: src specifies a char device (nul:, com1:, etc.) * EEXIST: dst specifies a char device (nul:, com1:, etc.) (NT) * EACCES: dst specifies a char device (nul:, com1:, etc.) (95) * * Side effects: * The implementation supports cross-filesystem renames of files, * but the caller should be prepared to emulate cross-filesystem * renames of directories if errno is EXDEV. * *--------------------------------------------------------------------------- */ int TclpObjRenameFile(srcPathPtr, destPathPtr) Tcl_Obj *srcPathPtr; Tcl_Obj *destPathPtr; { return DoRenameFile(Tcl_FSGetNativePath(srcPathPtr), Tcl_FSGetNativePath(destPathPtr)); } static int DoRenameFile( CONST TCHAR *nativeSrc, /* Pathname of file or dir to be renamed * (native). */ CONST TCHAR *nativeDst) /* New pathname for file or directory * (native). */ { #if defined(HAVE_NO_SEH) && !defined(_WIN64) EXCEPTION_REGISTRATION registration; #endif DWORD srcAttr, dstAttr; int retval = -1; /* * The MoveFile API acts differently under Win95/98 and NT * WRT NULL and "". Avoid passing these values. */ if (nativeSrc == NULL || nativeSrc[0] == '\0' || nativeDst == NULL || nativeDst[0] == '\0') { Tcl_SetErrno(ENOENT); return TCL_ERROR; } /* * The MoveFile API would throw an exception under NT * if one of the arguments is a char block device. */ #if defined(HAVE_NO_SEH) && !defined(_WIN64) /* * Don't have SEH available, do things the hard way. * Note that this needs to be one block of asm, to avoid stack * imbalance; also, it is illegal for one asm block to contain * a jump to another. */ __asm__ __volatile__ ( /* * Pick up params before messing with the stack */ "movl %[nativeDst], %%ebx" "\n\t" "movl %[nativeSrc], %%ecx" "\n\t" /* * Construct an EXCEPTION_REGISTRATION to protect the * call to MoveFile */ "leal %[registration], %%edx" "\n\t" "movl %%fs:0, %%eax" "\n\t" "movl %%eax, 0x0(%%edx)" "\n\t" /* link */ "leal 1f, %%eax" "\n\t" "movl %%eax, 0x4(%%edx)" "\n\t" /* handler */ "movl %%ebp, 0x8(%%edx)" "\n\t" /* ebp */ "movl %%esp, 0xc(%%edx)" "\n\t" /* esp */ "movl $0, 0x10(%%edx)" "\n\t" /* status */ /* Link the EXCEPTION_REGISTRATION on the chain */ "movl %%edx, %%fs:0" "\n\t" /* Call MoveFile( nativeSrc, nativeDst ) */ "pushl %%ebx" "\n\t" "pushl %%ecx" "\n\t" "movl %[moveFile], %%eax" "\n\t" "call *%%eax" "\n\t" /* * Come here on normal exit. Recover the EXCEPTION_REGISTRATION * and put the status return from MoveFile into it. */ "movl %%fs:0, %%edx" "\n\t" "movl %%eax, 0x10(%%edx)" "\n\t" "jmp 2f" "\n" /* * Come here on an exception. Recover the EXCEPTION_REGISTRATION */ "1:" "\t" "movl %%fs:0, %%edx" "\n\t" "movl 0x8(%%edx), %%edx" "\n\t" /* * Come here however we exited. Restore context from the * EXCEPTION_REGISTRATION in case the stack is unbalanced. */ "2:" "\t" "movl 0xc(%%edx), %%esp" "\n\t" "movl 0x8(%%edx), %%ebp" "\n\t" "movl 0x0(%%edx), %%eax" "\n\t" "movl %%eax, %%fs:0" "\n\t" : /* No outputs */ : [registration] "m" (registration), [nativeDst] "m" (nativeDst), [nativeSrc] "m" (nativeSrc), [moveFile] "r" (tclWinProcs->moveFileProc) : "%eax", "%ebx", "%ecx", "%edx", "memory" ); if (registration.status != FALSE) { retval = TCL_OK; } #else #ifndef HAVE_NO_SEH __try { #endif if ((*tclWinProcs->moveFileProc)(nativeSrc, nativeDst) != FALSE) { retval = TCL_OK; } #ifndef HAVE_NO_SEH } __except (EXCEPTION_EXECUTE_HANDLER) {} #endif #endif if (retval != -1) return retval; TclWinConvertError(GetLastError()); srcAttr = (*tclWinProcs->getFileAttributesProc)(nativeSrc); dstAttr = (*tclWinProcs->getFileAttributesProc)(nativeDst); if (srcAttr == 0xffffffff) { if ((*tclWinProcs->getFullPathNameProc)(nativeSrc, 0, NULL, NULL) >= MAX_PATH) { errno = ENAMETOOLONG; return TCL_ERROR; } srcAttr = 0; } if (dstAttr == 0xffffffff) { if ((*tclWinProcs->getFullPathNameProc)(nativeDst, 0, NULL, NULL) >= MAX_PATH) { errno = ENAMETOOLONG; return TCL_ERROR; } dstAttr = 0; } if (errno == EBADF) { errno = EACCES; return TCL_ERROR; } if (errno == EACCES) { decode: if (srcAttr & FILE_ATTRIBUTE_DIRECTORY) { TCHAR *nativeSrcRest, *nativeDstRest; CONST char **srcArgv, **dstArgv; int size, srcArgc, dstArgc; WCHAR nativeSrcPath[MAX_PATH]; WCHAR nativeDstPath[MAX_PATH]; Tcl_DString srcString, dstString; CONST char *src, *dst; size = (*tclWinProcs->getFullPathNameProc)(nativeSrc, MAX_PATH, nativeSrcPath, &nativeSrcRest); if ((size == 0) || (size > MAX_PATH)) { return TCL_ERROR; } size = (*tclWinProcs->getFullPathNameProc)(nativeDst, MAX_PATH, nativeDstPath, &nativeDstRest); if ((size == 0) || (size > MAX_PATH)) { return TCL_ERROR; } (*tclWinProcs->charLowerProc)((TCHAR *) nativeSrcPath); (*tclWinProcs->charLowerProc)((TCHAR *) nativeDstPath); src = Tcl_WinTCharToUtf((TCHAR *) nativeSrcPath, -1, &srcString); dst = Tcl_WinTCharToUtf((TCHAR *) nativeDstPath, -1, &dstString); if (strncmp(src, dst, (size_t) Tcl_DStringLength(&srcString)) == 0) { /* * Trying to move a directory into itself. */ errno = EINVAL; Tcl_DStringFree(&srcString); Tcl_DStringFree(&dstString); return TCL_ERROR; } Tcl_SplitPath(src, &srcArgc, &srcArgv); Tcl_SplitPath(dst, &dstArgc, &dstArgv); Tcl_DStringFree(&srcString); Tcl_DStringFree(&dstString); if (srcArgc == 1) { /* * They are trying to move a root directory. Whether * or not it is across filesystems, this cannot be * done. */ Tcl_SetErrno(EINVAL); } else if ((srcArgc > 0) && (dstArgc > 0) && (strcmp(srcArgv[0], dstArgv[0]) != 0)) { /* * If src is a directory and dst filesystem != src * filesystem, errno should be EXDEV. It is very * important to get this behavior, so that the caller * can respond to a cross filesystem rename by * simulating it with copy and delete. The MoveFile * system call already handles the case of moving a * file between filesystems. */ Tcl_SetErrno(EXDEV); } ckfree((char *) srcArgv); ckfree((char *) dstArgv); } /* * Other types of access failure is that dst is a read-only * filesystem, that an open file referred to src or dest, or that * src or dest specified the current working directory on the * current filesystem. EACCES is returned for those cases. */ } else if (Tcl_GetErrno() == EEXIST) { /* * Reports EEXIST any time the target already exists. If it makes * sense, remove the old file and try renaming again. */ if (srcAttr & FILE_ATTRIBUTE_DIRECTORY) { if (dstAttr & FILE_ATTRIBUTE_DIRECTORY) { /* * Overwrite empty dst directory with src directory. The * following call will remove an empty directory. If it * fails, it's because it wasn't empty. */ if (DoRemoveJustDirectory(nativeDst, 0, NULL) == TCL_OK) { /* * Now that that empty directory is gone, we can try * renaming again. If that fails, we'll put this empty * directory back, for completeness. */ if ((*tclWinProcs->moveFileProc)(nativeSrc, nativeDst) != FALSE) { return TCL_OK; } /* * Some new error has occurred. Don't know what it * could be, but report this one. */ TclWinConvertError(GetLastError()); (*tclWinProcs->createDirectoryProc)(nativeDst, NULL); (*tclWinProcs->setFileAttributesProc)(nativeDst, dstAttr); if (Tcl_GetErrno() == EACCES) { /* * Decode the EACCES to a more meaningful error. */ goto decode; } } } else { /* (dstAttr & FILE_ATTRIBUTE_DIRECTORY) == 0 */ Tcl_SetErrno(ENOTDIR); } } else { /* (srcAttr & FILE_ATTRIBUTE_DIRECTORY) == 0 */ if (dstAttr & FILE_ATTRIBUTE_DIRECTORY) { Tcl_SetErrno(EISDIR); } else { /* * Overwrite existing file by: * * 1. Rename existing file to temp name. * 2. Rename old file to new name. * 3. If success, delete temp file. If failure, * put temp file back to old name. */ TCHAR *nativeRest, *nativeTmp, *nativePrefix; int result, size; WCHAR tempBuf[MAX_PATH]; size = (*tclWinProcs->getFullPathNameProc)(nativeDst, MAX_PATH, tempBuf, &nativeRest); if ((size == 0) || (size > MAX_PATH) || (nativeRest == NULL)) { return TCL_ERROR; } nativeTmp = (TCHAR *) tempBuf; ((char *) nativeRest)[0] = '\0'; ((char *) nativeRest)[1] = '\0'; /* In case it's Unicode. */ result = TCL_ERROR; nativePrefix = (tclWinProcs->useWide) ? (TCHAR *) L"tclr" : (TCHAR *) "tclr"; if ((*tclWinProcs->getTempFileNameProc)(nativeTmp, nativePrefix, 0, tempBuf) != 0) { /* * Strictly speaking, need the following DeleteFile and * MoveFile to be joined as an atomic operation so no * other app comes along in the meantime and creates the * same temp file. */ nativeTmp = (TCHAR *) tempBuf; (*tclWinProcs->deleteFileProc)(nativeTmp); if ((*tclWinProcs->moveFileProc)(nativeDst, nativeTmp) != FALSE) { if ((*tclWinProcs->moveFileProc)(nativeSrc, nativeDst) != FALSE) { (*tclWinProcs->setFileAttributesProc)(nativeTmp, FILE_ATTRIBUTE_NORMAL); (*tclWinProcs->deleteFileProc)(nativeTmp); return TCL_OK; } else { (*tclWinProcs->deleteFileProc)(nativeDst); (*tclWinProcs->moveFileProc)(nativeTmp, nativeDst); } } /* * Can't backup dst file or move src file. Return that * error. Could happen if an open file refers to dst. */ TclWinConvertError(GetLastError()); if (Tcl_GetErrno() == EACCES) { /* * Decode the EACCES to a more meaningful error. */ goto decode; } } return result; } } } return TCL_ERROR; } /* *--------------------------------------------------------------------------- * * TclpObjCopyFile, DoCopyFile -- * * Copy a single file (not a directory). If dst already exists and * is not a directory, it is removed. * * Results: * If the file was successfully copied, returns TCL_OK. Otherwise * the return value is TCL_ERROR and errno is set to indicate the * error. Some possible values for errno are: * * EACCES: src or dst parent directory can't be read and/or written. * EISDIR: src or dst is a directory. * ENOENT: src doesn't exist. src or dst is "". * * EACCES: exists an open file already referring to dst (95). * EACCES: src specifies a char device (nul:, com1:, etc.) (NT) * ENOENT: src specifies a char device (nul:, com1:, etc.) (95) * * Side effects: * It is not an error to copy to a char device. * *--------------------------------------------------------------------------- */ int TclpObjCopyFile(srcPathPtr, destPathPtr) Tcl_Obj *srcPathPtr; Tcl_Obj *destPathPtr; { return DoCopyFile(Tcl_FSGetNativePath(srcPathPtr), Tcl_FSGetNativePath(destPathPtr)); } static int DoCopyFile( CONST TCHAR *nativeSrc, /* Pathname of file to be copied (native). */ CONST TCHAR *nativeDst) /* Pathname of file to copy to (native). */ { #if defined(HAVE_NO_SEH) && !defined(_WIN64) EXCEPTION_REGISTRATION registration; #endif int retval = -1; /* * The CopyFile API acts differently under Win95/98 and NT * WRT NULL and "". Avoid passing these values. */ if (nativeSrc == NULL || nativeSrc[0] == '\0' || nativeDst == NULL || nativeDst[0] == '\0') { Tcl_SetErrno(ENOENT); return TCL_ERROR; } /* * The CopyFile API would throw an exception under NT if one * of the arguments is a char block device. */ #if defined(HAVE_NO_SEH) && !defined(_WIN64) /* * Don't have SEH available, do things the hard way. * Note that this needs to be one block of asm, to avoid stack * imbalance; also, it is illegal for one asm block to contain * a jump to another. */ __asm__ __volatile__ ( /* * Pick up parameters before messing with the stack */ "movl %[nativeDst], %%ebx" "\n\t" "movl %[nativeSrc], %%ecx" "\n\t" /* * Construct an EXCEPTION_REGISTRATION to protect the * call to CopyFile */ "leal %[registration], %%edx" "\n\t" "movl %%fs:0, %%eax" "\n\t" "movl %%eax, 0x0(%%edx)" "\n\t" /* link */ "leal 1f, %%eax" "\n\t" "movl %%eax, 0x4(%%edx)" "\n\t" /* handler */ "movl %%ebp, 0x8(%%edx)" "\n\t" /* ebp */ "movl %%esp, 0xc(%%edx)" "\n\t" /* esp */ "movl $0, 0x10(%%edx)" "\n\t" /* status */ /* Link the EXCEPTION_REGISTRATION on the chain */ "movl %%edx, %%fs:0" "\n\t" /* Call CopyFile( nativeSrc, nativeDst, 0 ) */ "movl %[copyFile], %%eax" "\n\t" "pushl $0" "\n\t" "pushl %%ebx" "\n\t" "pushl %%ecx" "\n\t" "call *%%eax" "\n\t" /* * Come here on normal exit. Recover the EXCEPTION_REGISTRATION * and put the status return from CopyFile into it. */ "movl %%fs:0, %%edx" "\n\t" "movl %%eax, 0x10(%%edx)" "\n\t" "jmp 2f" "\n" /* * Come here on an exception. Recover the EXCEPTION_REGISTRATION */ "1:" "\t" "movl %%fs:0, %%edx" "\n\t" "movl 0x8(%%edx), %%edx" "\n\t" /* * Come here however we exited. Restore context from the * EXCEPTION_REGISTRATION in case the stack is unbalanced. */ "2:" "\t" "movl 0xc(%%edx), %%esp" "\n\t" "movl 0x8(%%edx), %%ebp" "\n\t" "movl 0x0(%%edx), %%eax" "\n\t" "movl %%eax, %%fs:0" "\n\t" : /* No outputs */ : [registration] "m" (registration), [nativeDst] "m" (nativeDst), [nativeSrc] "m" (nativeSrc), [copyFile] "r" (tclWinProcs->copyFileProc) : "%eax", "%ebx", "%ecx", "%edx", "memory" ); if (registration.status != FALSE) { retval = TCL_OK; } #else #ifndef HAVE_NO_SEH __try { #endif if ((*tclWinProcs->copyFileProc)(nativeSrc, nativeDst, 0) != FALSE) { retval = TCL_OK; } #ifndef HAVE_NO_SEH } __except (EXCEPTION_EXECUTE_HANDLER) {} #endif #endif if (retval != -1) return retval; TclWinConvertError(GetLastError()); if (Tcl_GetErrno() == EBADF) { Tcl_SetErrno(EACCES); return TCL_ERROR; } if (Tcl_GetErrno() == EACCES) { DWORD srcAttr, dstAttr; srcAttr = (*tclWinProcs->getFileAttributesProc)(nativeSrc); dstAttr = (*tclWinProcs->getFileAttributesProc)(nativeDst); if (srcAttr != 0xffffffff) { if (dstAttr == 0xffffffff) { dstAttr = 0; } if ((srcAttr & FILE_ATTRIBUTE_DIRECTORY) || (dstAttr & FILE_ATTRIBUTE_DIRECTORY)) { if (srcAttr & FILE_ATTRIBUTE_REPARSE_POINT) { /* Source is a symbolic link -- copy it */ if (TclWinSymLinkCopyDirectory(nativeSrc, nativeDst) == 0) { return TCL_OK; } } Tcl_SetErrno(EISDIR); } if (dstAttr & FILE_ATTRIBUTE_READONLY) { (*tclWinProcs->setFileAttributesProc)(nativeDst, dstAttr & ~((DWORD)FILE_ATTRIBUTE_READONLY)); if ((*tclWinProcs->copyFileProc)(nativeSrc, nativeDst, 0) != FALSE) { return TCL_OK; } /* * Still can't copy onto dst. Return that error, and * restore attributes of dst. */ TclWinConvertError(GetLastError()); (*tclWinProcs->setFileAttributesProc)(nativeDst, dstAttr); } } } return TCL_ERROR; } /* *--------------------------------------------------------------------------- * * TclpObjDeleteFile, TclpDeleteFile -- * * Removes a single file (not a directory). * * Results: * If the file was successfully deleted, returns TCL_OK. Otherwise * the return value is TCL_ERROR and errno is set to indicate the * error. Some possible values for errno are: * * EACCES: a parent directory can't be read and/or written. * EISDIR: path is a directory. * ENOENT: path doesn't exist or is "". * * EACCES: exists an open file already referring to path. * EACCES: path is a char device (nul:, com1:, etc.) * * Side effects: * The file is deleted, even if it is read-only. * *--------------------------------------------------------------------------- */ int TclpObjDeleteFile(pathPtr) Tcl_Obj *pathPtr; { return TclpDeleteFile(Tcl_FSGetNativePath(pathPtr)); } int TclpDeleteFile( CONST TCHAR *nativePath) /* Pathname of file to be removed (native). */ { DWORD attr; /* * The DeleteFile API acts differently under Win95/98 and NT * WRT NULL and "". Avoid passing these values. */ if (nativePath == NULL || nativePath[0] == '\0') { Tcl_SetErrno(ENOENT); return TCL_ERROR; } if ((*tclWinProcs->deleteFileProc)(nativePath) != FALSE) { return TCL_OK; } TclWinConvertError(GetLastError()); if (Tcl_GetErrno() == EACCES) { attr = (*tclWinProcs->getFileAttributesProc)(nativePath); if (attr != 0xffffffff) { if (attr & FILE_ATTRIBUTE_DIRECTORY) { if (attr & FILE_ATTRIBUTE_REPARSE_POINT) { /* It is a symbolic link -- remove it */ if (TclWinSymLinkDelete(nativePath, 0) == 0) { return TCL_OK; } } /* * If we fall through here, it is a directory. * * Windows NT reports removing a directory as EACCES instead * of EISDIR. */ Tcl_SetErrno(EISDIR); } else if (attr & FILE_ATTRIBUTE_READONLY) { int res = (*tclWinProcs->setFileAttributesProc)(nativePath, attr & ~((DWORD)FILE_ATTRIBUTE_READONLY)); if ((res != 0) && ((*tclWinProcs->deleteFileProc)(nativePath) != FALSE)) { return TCL_OK; } TclWinConvertError(GetLastError()); if (res != 0) { (*tclWinProcs->setFileAttributesProc)(nativePath, attr); } } } } else if (Tcl_GetErrno() == ENOENT) { attr = (*tclWinProcs->getFileAttributesProc)(nativePath); if (attr != 0xffffffff) { if (attr & FILE_ATTRIBUTE_DIRECTORY) { /* * Windows 95 reports removing a directory as ENOENT instead * of EISDIR. */ Tcl_SetErrno(EISDIR); } } } else if (Tcl_GetErrno() == EINVAL) { /* * Windows NT reports removing a char device as EINVAL instead of * EACCES. */ Tcl_SetErrno(EACCES); } return TCL_ERROR; } /* *--------------------------------------------------------------------------- * * TclpObjCreateDirectory -- * * Creates the specified directory. All parent directories of the * specified directory must already exist. The directory is * automatically created with permissions so that user can access * the new directory and create new files or subdirectories in it. * * Results: * If the directory was successfully created, returns TCL_OK. * Otherwise the return value is TCL_ERROR and errno is set to * indicate the error. Some possible values for errno are: * * EACCES: a parent directory can't be read and/or written. * EEXIST: path already exists. * ENOENT: a parent directory doesn't exist. * * Side effects: * A directory is created. * *--------------------------------------------------------------------------- */ int TclpObjCreateDirectory(pathPtr) Tcl_Obj *pathPtr; { return DoCreateDirectory(Tcl_FSGetNativePath(pathPtr)); } static int DoCreateDirectory( CONST TCHAR *nativePath) /* Pathname of directory to create (native). */ { DWORD error; if ((*tclWinProcs->createDirectoryProc)(nativePath, NULL) == 0) { error = GetLastError(); TclWinConvertError(error); return TCL_ERROR; } return TCL_OK; } /* *--------------------------------------------------------------------------- * * TclpObjCopyDirectory -- * * Recursively copies a directory. The target directory dst must * not already exist. Note that this function does not merge two * directory hierarchies, even if the target directory is an an * empty directory. * * Results: * If the directory was successfully copied, returns TCL_OK. * Otherwise the return value is TCL_ERROR, errno is set to indicate * the error, and the pathname of the file that caused the error * is stored in errorPtr. See TclpCreateDirectory and TclpCopyFile * for a description of possible values for errno. * * Side effects: * An exact copy of the directory hierarchy src will be created * with the name dst. If an error occurs, the error will * be returned immediately, and remaining files will not be * processed. * *--------------------------------------------------------------------------- */ int TclpObjCopyDirectory(srcPathPtr, destPathPtr, errorPtr) Tcl_Obj *srcPathPtr; Tcl_Obj *destPathPtr; Tcl_Obj **errorPtr; { Tcl_DString ds; Tcl_DString srcString, dstString; Tcl_Obj *normSrcPtr, *normDestPtr; int ret; normSrcPtr = Tcl_FSGetNormalizedPath(NULL,srcPathPtr); if (normSrcPtr == NULL) { return TCL_ERROR; } Tcl_WinUtfToTChar(Tcl_GetString(normSrcPtr), -1, &srcString); normDestPtr = Tcl_FSGetNormalizedPath(NULL,destPathPtr); if (normDestPtr == NULL) { return TCL_ERROR; } Tcl_WinUtfToTChar(Tcl_GetString(normDestPtr), -1, &dstString); ret = TraverseWinTree(TraversalCopy, &srcString, &dstString, &ds); Tcl_DStringFree(&srcString); Tcl_DStringFree(&dstString); if (ret != TCL_OK) { if (!strcmp(Tcl_DStringValue(&ds), Tcl_GetString(normSrcPtr))) { *errorPtr = srcPathPtr; } else if (!strcmp(Tcl_DStringValue(&ds), Tcl_GetString(normDestPtr))) { *errorPtr = destPathPtr; } else { *errorPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds), -1); } Tcl_DStringFree(&ds); Tcl_IncrRefCount(*errorPtr); } return ret; } /* *---------------------------------------------------------------------- * * TclpObjRemoveDirectory, DoRemoveDirectory -- * * Removes directory (and its contents, if the recursive flag is set). * * Results: * If the directory was successfully removed, returns TCL_OK. * Otherwise the return value is TCL_ERROR, errno is set to indicate * the error, and the pathname of the file that caused the error * is stored in errorPtr. Some possible values for errno are: * * EACCES: path directory can't be read and/or written. * EEXIST: path is a non-empty directory. * EINVAL: path is root directory or current directory. * ENOENT: path doesn't exist or is "". * ENOTDIR: path is not a directory. * * EACCES: path is a char device (nul:, com1:, etc.) (95) * EINVAL: path is a char device (nul:, com1:, etc.) (NT) * * Side effects: * Directory removed. If an error occurs, the error will be returned * immediately, and remaining files will not be deleted. * *---------------------------------------------------------------------- */ int TclpObjRemoveDirectory(pathPtr, recursive, errorPtr) Tcl_Obj *pathPtr; int recursive; Tcl_Obj **errorPtr; { Tcl_DString ds; Tcl_Obj *normPtr = NULL; int ret; if (recursive) { /* * In the recursive case, the string rep is used to construct a * Tcl_DString which may be used extensively, so we can't * optimize this case easily. */ Tcl_DString native; normPtr = Tcl_FSGetNormalizedPath(NULL, pathPtr); if (normPtr == NULL) { return TCL_ERROR; } Tcl_WinUtfToTChar(Tcl_GetString(normPtr), -1, &native); ret = DoRemoveDirectory(&native, recursive, &ds); Tcl_DStringFree(&native); } else { ret = DoRemoveJustDirectory(Tcl_FSGetNativePath(pathPtr), 0, &ds); } if (ret != TCL_OK) { int len = Tcl_DStringLength(&ds); if (len > 0) { if (normPtr != NULL && !strcmp(Tcl_DStringValue(&ds), Tcl_GetString(normPtr))) { *errorPtr = pathPtr; } else { *errorPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds), -1); } Tcl_IncrRefCount(*errorPtr); } Tcl_DStringFree(&ds); } return ret; } static int DoRemoveJustDirectory( CONST TCHAR *nativePath, /* Pathname of directory to be removed * (native). */ int ignoreError, /* If non-zero, don't initialize the * errorPtr under some circumstances * on return. */ Tcl_DString *errorPtr) /* If non-NULL, uninitialized or free * DString filled with UTF-8 name of file * causing error. */ { /* * The RemoveDirectory API acts differently under Win95/98 and NT * WRT NULL and "". Avoid passing these values. */ if (nativePath == NULL || nativePath[0] == '\0') { Tcl_SetErrno(ENOENT); goto end; } if ((*tclWinProcs->removeDirectoryProc)(nativePath) != FALSE) { return TCL_OK; } TclWinConvertError(GetLastError()); if (Tcl_GetErrno() == EACCES) { DWORD attr = (*tclWinProcs->getFileAttributesProc)(nativePath); if (attr != 0xffffffff) { if ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0) { /* * Windows 95 reports calling RemoveDirectory on a file as an * EACCES, not an ENOTDIR. */ Tcl_SetErrno(ENOTDIR); goto end; } if (attr & FILE_ATTRIBUTE_REPARSE_POINT) { /* It is a symbolic link -- remove it */ if (TclWinSymLinkDelete(nativePath, 1) != 0) { goto end; } } if (attr & FILE_ATTRIBUTE_READONLY) { attr &= ~FILE_ATTRIBUTE_READONLY; if ((*tclWinProcs->setFileAttributesProc)(nativePath, attr) == FALSE) { goto end; } if ((*tclWinProcs->removeDirectoryProc)(nativePath) != FALSE) { return TCL_OK; } TclWinConvertError(GetLastError()); (*tclWinProcs->setFileAttributesProc)(nativePath, attr | FILE_ATTRIBUTE_READONLY); } /* * Windows 95 and Win32s report removing a non-empty directory * as EACCES, not EEXIST. If the directory is not empty, * change errno so caller knows what's going on. */ if (TclWinGetPlatformId() != VER_PLATFORM_WIN32_NT) { CONST char *path, *find; HANDLE handle; WIN32_FIND_DATAA data; Tcl_DString buffer; int len; path = (CONST char *) nativePath; Tcl_DStringInit(&buffer); len = strlen(path); find = Tcl_DStringAppend(&buffer, path, len); if ((len > 0) && (find[len - 1] != '\\')) { Tcl_DStringAppend(&buffer, "\\", 1); } find = Tcl_DStringAppend(&buffer, "*.*", 3); handle = FindFirstFileA(find, &data); if (handle != INVALID_HANDLE_VALUE) { while (1) { if ((strcmp(data.cFileName, ".") != 0) && (strcmp(data.cFileName, "..") != 0)) { /* * Found something in this directory. */ Tcl_SetErrno(EEXIST); break; } if (FindNextFileA(handle, &data) == FALSE) { break; } } FindClose(handle); } Tcl_DStringFree(&buffer); } } } if (Tcl_GetErrno() == ENOTEMPTY) { /* * The caller depends on EEXIST to signify that the directory is * not empty, not ENOTEMPTY. */ Tcl_SetErrno(EEXIST); } if ((ignoreError != 0) && (Tcl_GetErrno() == EEXIST)) { /* * If we're being recursive, this error may actually * be ok, so we don't want to initialise the errorPtr * yet. */ return TCL_ERROR; } end: if (errorPtr != NULL) { Tcl_WinTCharToUtf(nativePath, -1, errorPtr); } return TCL_ERROR; } static int DoRemoveDirectory( Tcl_DString *pathPtr, /* Pathname of directory to be removed * (native). */ int recursive, /* If non-zero, removes directories that * are nonempty. Otherwise, will only remove * empty directories. */ Tcl_DString *errorPtr) /* If non-NULL, uninitialized or free * DString filled with UTF-8 name of file * causing error. */ { int res = DoRemoveJustDirectory(Tcl_DStringValue(pathPtr), recursive, errorPtr); if ((res == TCL_ERROR) && (recursive != 0) && (Tcl_GetErrno() == EEXIST)) { /* * The directory is nonempty, but the recursive flag has been * specified, so we recursively remove all the files in the directory. */ return TraverseWinTree(TraversalDelete, pathPtr, NULL, errorPtr); } else { return res; } } /* *--------------------------------------------------------------------------- * * TraverseWinTree -- * * Traverse directory tree specified by sourcePtr, calling the function * traverseProc for each file and directory encountered. If destPtr * is non-null, each of name in the sourcePtr directory is appended to * the directory specified by destPtr and passed as the second argument * to traverseProc() . * * Results: * Standard Tcl result. * * Side effects: * None caused by TraverseWinTree, however the user specified * traverseProc() may change state. If an error occurs, the error will * be returned immediately, and remaining files will not be processed. * *--------------------------------------------------------------------------- */ static int TraverseWinTree( TraversalProc *traverseProc,/* Function to call for every file and * directory in source hierarchy. */ Tcl_DString *sourcePtr, /* Pathname of source directory to be * traversed (native). */ Tcl_DString *targetPtr, /* Pathname of directory to traverse in * parallel with source directory (native), * may be NULL. */ Tcl_DString *errorPtr) /* If non-NULL, uninitialized or free * DString filled with UTF-8 name of file * causing error. */ { DWORD sourceAttr; TCHAR *nativeSource, *nativeTarget, *nativeErrfile; int result, found, sourceLen, targetLen = 0, oldSourceLen, oldTargetLen; HANDLE handle; WIN32_FIND_DATAT data; nativeErrfile = NULL; result = TCL_OK; oldTargetLen = 0; /* lint. */ nativeSource = (TCHAR *) Tcl_DStringValue(sourcePtr); nativeTarget = (TCHAR *) (targetPtr == NULL ? NULL : Tcl_DStringValue(targetPtr)); oldSourceLen = Tcl_DStringLength(sourcePtr); sourceAttr = (*tclWinProcs->getFileAttributesProc)(nativeSource); if (sourceAttr == 0xffffffff) { nativeErrfile = nativeSource; goto end; } if ((sourceAttr & FILE_ATTRIBUTE_DIRECTORY) == 0) { /* * Process the regular file */ return (*traverseProc)(nativeSource, nativeTarget, DOTREE_F, errorPtr); } if (tclWinProcs->useWide) { Tcl_DStringAppend(sourcePtr, (char *) L"\\*.*", 4 * sizeof(WCHAR) + 1); Tcl_DStringSetLength(sourcePtr, Tcl_DStringLength(sourcePtr) - 1); } else { Tcl_DStringAppend(sourcePtr, "\\*.*", 4); } nativeSource = (TCHAR *) Tcl_DStringValue(sourcePtr); handle = (*tclWinProcs->findFirstFileProc)(nativeSource, &data); if (handle == INVALID_HANDLE_VALUE) { /* * Can't read directory */ TclWinConvertError(GetLastError()); nativeErrfile = nativeSource; goto end; } nativeSource[oldSourceLen + 1] = '\0'; Tcl_DStringSetLength(sourcePtr, oldSourceLen); result = (*traverseProc)(nativeSource, nativeTarget, DOTREE_PRED, errorPtr); if (result != TCL_OK) { FindClose(handle); return result; } sourceLen = oldSourceLen; if (tclWinProcs->useWide) { sourceLen += sizeof(WCHAR); Tcl_DStringAppend(sourcePtr, (char *) L"\\", sizeof(WCHAR) + 1); Tcl_DStringSetLength(sourcePtr, sourceLen); } else { sourceLen += 1; Tcl_DStringAppend(sourcePtr, "\\", 1); } if (targetPtr != NULL) { oldTargetLen = Tcl_DStringLength(targetPtr); targetLen = oldTargetLen; if (tclWinProcs->useWide) { targetLen += sizeof(WCHAR); Tcl_DStringAppend(targetPtr, (char *) L"\\", sizeof(WCHAR) + 1); Tcl_DStringSetLength(targetPtr, targetLen); } else { targetLen += 1; Tcl_DStringAppend(targetPtr, "\\", 1); } } found = 1; for ( ; found; found = (*tclWinProcs->findNextFileProc)(handle, &data)) { TCHAR *nativeName; int len; if (tclWinProcs->useWide) { WCHAR *wp; wp = data.w.cFileName; if (*wp == '.') { wp++; if (*wp == '.') { wp++; } if (*wp == '\0') { continue; } } nativeName = (TCHAR *) data.w.cFileName; len = wcslen(data.w.cFileName) * sizeof(WCHAR); } else { if ((strcmp(data.a.cFileName, ".") == 0) || (strcmp(data.a.cFileName, "..") == 0)) { continue; } nativeName = (TCHAR *) data.a.cFileName; len = strlen(data.a.cFileName); } /* * Append name after slash, and recurse on the file. */ Tcl_DStringAppend(sourcePtr, (char *) nativeName, len + 1); Tcl_DStringSetLength(sourcePtr, Tcl_DStringLength(sourcePtr) - 1); if (targetPtr != NULL) { Tcl_DStringAppend(targetPtr, (char *) nativeName, len + 1); Tcl_DStringSetLength(targetPtr, Tcl_DStringLength(targetPtr) - 1); } result = TraverseWinTree(traverseProc, sourcePtr, targetPtr, errorPtr); if (result != TCL_OK) { break; } /* * Remove name after slash. */ Tcl_DStringSetLength(sourcePtr, sourceLen); if (targetPtr != NULL) { Tcl_DStringSetLength(targetPtr, targetLen); } } FindClose(handle); /* * Strip off the trailing slash we added */ Tcl_DStringSetLength(sourcePtr, oldSourceLen + 1); Tcl_DStringSetLength(sourcePtr, oldSourceLen); if (targetPtr != NULL) { Tcl_DStringSetLength(targetPtr, oldTargetLen + 1); Tcl_DStringSetLength(targetPtr, oldTargetLen); } if (result == TCL_OK) { /* * Call traverseProc() on a directory after visiting all the * files in that directory. */ result = (*traverseProc)(Tcl_DStringValue(sourcePtr), (targetPtr == NULL ? NULL : Tcl_DStringValue(targetPtr)), DOTREE_POSTD, errorPtr); } end: if (nativeErrfile != NULL) { TclWinConvertError(GetLastError()); if (errorPtr != NULL) { Tcl_WinTCharToUtf(nativeErrfile, -1, errorPtr); } result = TCL_ERROR; } return result; } /* *---------------------------------------------------------------------- * * TraversalCopy * * Called from TraverseUnixTree in order to execute a recursive * copy of a directory. * * Results: * Standard Tcl result. * * Side effects: * Depending on the value of type, src may be copied to dst. * *---------------------------------------------------------------------- */ static int TraversalCopy( CONST TCHAR *nativeSrc, /* Source pathname to copy. */ CONST TCHAR *nativeDst, /* Destination pathname of copy. */ int type, /* Reason for call - see TraverseWinTree() */ Tcl_DString *errorPtr) /* If non-NULL, initialized DString filled * with UTF-8 name of file causing error. */ { switch (type) { case DOTREE_F: { if (DoCopyFile(nativeSrc, nativeDst) == TCL_OK) { return TCL_OK; } break; } case DOTREE_PRED: { if (DoCreateDirectory(nativeDst) == TCL_OK) { DWORD attr = (*tclWinProcs->getFileAttributesProc)(nativeSrc); if ((*tclWinProcs->setFileAttributesProc)(nativeDst, attr) != FALSE) { return TCL_OK; } TclWinConvertError(GetLastError()); } break; } case DOTREE_POSTD: { return TCL_OK; } } /* * There shouldn't be a problem with src, because we already * checked it to get here. */ if (errorPtr != NULL) { Tcl_WinTCharToUtf(nativeDst, -1, errorPtr); } return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TraversalDelete -- * * Called by procedure TraverseWinTree for every file and * directory that it encounters in a directory hierarchy. This * procedure unlinks files, and removes directories after all the * containing files have been processed. * * Results: * Standard Tcl result. * * Side effects: * Files or directory specified by src will be deleted. If an * error occurs, the windows error is converted to a Posix error * and errno is set accordingly. * *---------------------------------------------------------------------- */ static int TraversalDelete( CONST TCHAR *nativeSrc, /* Source pathname to delete. */ CONST TCHAR *dstPtr, /* Not used. */ int type, /* Reason for call - see TraverseWinTree() */ Tcl_DString *errorPtr) /* If non-NULL, initialized DString filled * with UTF-8 name of file causing error. */ { switch (type) { case DOTREE_F: { if (TclpDeleteFile(nativeSrc) == TCL_OK) { return TCL_OK; } break; } case DOTREE_PRED: { return TCL_OK; } case DOTREE_POSTD: { if (DoRemoveJustDirectory(nativeSrc, 0, NULL) == TCL_OK) { return TCL_OK; } break; } } if (errorPtr != NULL) { Tcl_WinTCharToUtf(nativeSrc, -1, errorPtr); } return TCL_ERROR; } /* *---------------------------------------------------------------------- * * StatError -- * * Sets the object result with the appropriate error. * * Results: * None. * * Side effects: * The interp's object result is set with an error message * based on the objIndex, fileName and errno. * *---------------------------------------------------------------------- */ static void StatError( Tcl_Interp *interp, /* The interp that has the error */ Tcl_Obj *fileName) /* The name of the file which caused the * error. */ { TclWinConvertError(GetLastError()); Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "could not read \"", Tcl_GetString(fileName), "\": ", Tcl_PosixError(interp), (char *) NULL); } /* *---------------------------------------------------------------------- * * GetWinFileAttributes -- * * Returns a Tcl_Obj containing the value of a file attribute. * This routine gets the -hidden, -readonly or -system attribute. * * Results: * Standard Tcl result and a Tcl_Obj in attributePtrPtr. The object * will have ref count 0. If the return value is not TCL_OK, * attributePtrPtr is not touched. * * Side effects: * A new object is allocated if the file is valid. * *---------------------------------------------------------------------- */ static int GetWinFileAttributes( Tcl_Interp *interp, /* The interp we are using for errors. */ int objIndex, /* The index of the attribute. */ Tcl_Obj *fileName, /* The name of the file. */ Tcl_Obj **attributePtrPtr) /* A pointer to return the object with. */ { DWORD result; CONST TCHAR *nativeName; int attr; nativeName = Tcl_FSGetNativePath(fileName); result = (*tclWinProcs->getFileAttributesProc)(nativeName); if (result == 0xffffffff) { StatError(interp, fileName); return TCL_ERROR; } attr = (int)(result & attributeArray[objIndex]); if ((objIndex == WIN_HIDDEN_ATTRIBUTE) && (attr != 0)) { /* * It is hidden. However there is a bug on some Windows * OSes in which root volumes (drives) formatted as NTFS * are declared hidden when they are not (and cannot be). * * We test for, and fix that case, here. */ int len; char *str = Tcl_GetStringFromObj(fileName,&len); if (len < 4) { if (len == 0) { /* * Not sure if this is possible, but we pass it on * anyway */ } else if (len == 1 && (str[0] == '/' || str[0] == '\\')) { /* Path is pointing to the root volume */ attr = 0; } else if ((str[1] == ':') && (len == 2 || (str[2] == '/' || str[2] == '\\'))) { /* Path is of the form 'x:' or 'x:/' or 'x:\' */ attr = 0; } } } *attributePtrPtr = Tcl_NewBooleanObj(attr); return TCL_OK; } /* *---------------------------------------------------------------------- * * ConvertFileNameFormat -- * * Returns a Tcl_Obj containing either the long or short version of the * file name. * * Results: * Standard Tcl result and a Tcl_Obj in attributePtrPtr. The object * will have ref count 0. If the return value is not TCL_OK, * attributePtrPtr is not touched. * * Warning: if you pass this function a drive name like 'c:' it * will actually return the current working directory on that * drive. To avoid this, make sure the drive name ends in a * slash, like this 'c:/'. * * Side effects: * A new object is allocated if the file is valid. * *---------------------------------------------------------------------- */ static int ConvertFileNameFormat( Tcl_Interp *interp, /* The interp we are using for errors. */ int objIndex, /* The index of the attribute. */ Tcl_Obj *fileName, /* The name of the file. */ int longShort, /* 0 to short name, 1 to long name. */ Tcl_Obj **attributePtrPtr) /* A pointer to return the object with. */ { int pathc, i; Tcl_Obj *splitPath; int result = TCL_OK; splitPath = Tcl_FSSplitPath(fileName, &pathc); if (splitPath == NULL || pathc == 0) { if (interp != NULL) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "could not read \"", Tcl_GetString(fileName), "\": no such file or directory", (char *) NULL); } result = TCL_ERROR; goto cleanup; } for (i = 0; i < pathc; i++) { Tcl_Obj *elt; char *pathv; int pathLen; Tcl_ListObjIndex(NULL, splitPath, i, &elt); pathv = Tcl_GetStringFromObj(elt, &pathLen); if ((pathv[0] == '/') || ((pathLen == 3) && (pathv[1] == ':')) || (strcmp(pathv, ".") == 0) || (strcmp(pathv, "..") == 0)) { /* * Handle "/", "//machine/export", "c:/", "." or ".." by just * copying the string literally. Uppercase the drive letter, * just because it looks better under Windows to do so. */ simple: /* Here we are modifying the string representation in place */ /* I believe this is legal, since this won't affect any * file representation this thing may have. */ pathv[0] = (char) Tcl_UniCharToUpper(UCHAR(pathv[0])); } else { Tcl_Obj *tempPath; Tcl_DString ds; Tcl_DString dsTemp; TCHAR *nativeName; char *tempString; int tempLen; WIN32_FIND_DATAT data; HANDLE handle; DWORD attr; tempPath = Tcl_FSJoinPath(splitPath, i+1); Tcl_IncrRefCount(tempPath); /* * We'd like to call Tcl_FSGetNativePath(tempPath) * but that is likely to lead to infinite loops */ Tcl_DStringInit(&ds); tempString = Tcl_GetStringFromObj(tempPath,&tempLen); nativeName = Tcl_WinUtfToTChar(tempString, tempLen, &ds); Tcl_DecrRefCount(tempPath); handle = (*tclWinProcs->findFirstFileProc)(nativeName, &data); if (handle == INVALID_HANDLE_VALUE) { /* * FindFirstFile() doesn't like root directories. We * would only get a root directory here if the caller * specified "c:" or "c:." and the current directory on the * drive was the root directory */ attr = (*tclWinProcs->getFileAttributesProc)(nativeName); if ((attr != 0xFFFFFFFF) && (attr & FILE_ATTRIBUTE_DIRECTORY)) { Tcl_DStringFree(&ds); goto simple; } } if (handle == INVALID_HANDLE_VALUE) { Tcl_DStringFree(&ds); if (interp != NULL) { StatError(interp, fileName); } result = TCL_ERROR; goto cleanup; } if (tclWinProcs->useWide) { nativeName = (TCHAR *) data.w.cAlternateFileName; if (longShort) { if (data.w.cFileName[0] != '\0') { nativeName = (TCHAR *) data.w.cFileName; } } else { if (data.w.cAlternateFileName[0] == '\0') { nativeName = (TCHAR *) data.w.cFileName; } } } else { nativeName = (TCHAR *) data.a.cAlternateFileName; if (longShort) { if (data.a.cFileName[0] != '\0') { nativeName = (TCHAR *) data.a.cFileName; } } else { if (data.a.cAlternateFileName[0] == '\0') { nativeName = (TCHAR *) data.a.cFileName; } } } /* * Purify reports a extraneous UMR in Tcl_WinTCharToUtf() trying * to dereference nativeName as a Unicode string. I have proven * to myself that purify is wrong by running the following * example when nativeName == data.w.cAlternateFileName and * noting that purify doesn't complain about the first line, * but does complain about the second. * * fprintf(stderr, "%d\n", data.w.cAlternateFileName[0]); * fprintf(stderr, "%d\n", ((WCHAR *) nativeName)[0]); */ Tcl_DStringInit(&dsTemp); Tcl_WinTCharToUtf(nativeName, -1, &dsTemp); /* Deal with issues of tildes being absolute */ if (Tcl_DStringValue(&dsTemp)[0] == '~') { tempPath = Tcl_NewStringObj("./",2); Tcl_AppendToObj(tempPath, Tcl_DStringValue(&dsTemp), Tcl_DStringLength(&dsTemp)); } else { tempPath = Tcl_NewStringObj(Tcl_DStringValue(&dsTemp), Tcl_DStringLength(&dsTemp)); } Tcl_ListObjReplace(NULL, splitPath, i, 1, 1, &tempPath); Tcl_DStringFree(&ds); Tcl_DStringFree(&dsTemp); FindClose(handle); } } *attributePtrPtr = Tcl_FSJoinPath(splitPath, -1); cleanup: if (splitPath != NULL) { Tcl_DecrRefCount(splitPath); } return result; } /* *---------------------------------------------------------------------- * * GetWinFileLongName -- * * Returns a Tcl_Obj containing the long version of the file * name. * * Results: * Standard Tcl result and a Tcl_Obj in attributePtrPtr. The object * will have ref count 0. If the return value is not TCL_OK, * attributePtrPtr is not touched. * * Side effects: * A new object is allocated if the file is valid. * *---------------------------------------------------------------------- */ static int GetWinFileLongName( Tcl_Interp *interp, /* The interp we are using for errors. */ int objIndex, /* The index of the attribute. */ Tcl_Obj *fileName, /* The name of the file. */ Tcl_Obj **attributePtrPtr) /* A pointer to return the object with. */ { return ConvertFileNameFormat(interp, objIndex, fileName, 1, attributePtrPtr); } /* *---------------------------------------------------------------------- * * GetWinFileShortName -- * * Returns a Tcl_Obj containing the short version of the file * name. * * Results: * Standard Tcl result and a Tcl_Obj in attributePtrPtr. The object * will have ref count 0. If the return value is not TCL_OK, * attributePtrPtr is not touched. * * Side effects: * A new object is allocated if the file is valid. * *---------------------------------------------------------------------- */ static int GetWinFileShortName( Tcl_Interp *interp, /* The interp we are using for errors. */ int objIndex, /* The index of the attribute. */ Tcl_Obj *fileName, /* The name of the file. */ Tcl_Obj **attributePtrPtr) /* A pointer to return the object with. */ { return ConvertFileNameFormat(interp, objIndex, fileName, 0, attributePtrPtr); } /* *---------------------------------------------------------------------- * * SetWinFileAttributes -- * * Set the file attributes to the value given by attributePtr. * This routine sets the -hidden, -readonly, or -system attributes. * * Results: * Standard TCL error. * * Side effects: * The file's attribute is set. * *---------------------------------------------------------------------- */ static int SetWinFileAttributes( Tcl_Interp *interp, /* The interp we are using for errors. */ int objIndex, /* The index of the attribute. */ Tcl_Obj *fileName, /* The name of the file. */ Tcl_Obj *attributePtr) /* The new value of the attribute. */ { DWORD fileAttributes; int yesNo; int result; CONST TCHAR *nativeName; nativeName = Tcl_FSGetNativePath(fileName); fileAttributes = (*tclWinProcs->getFileAttributesProc)(nativeName); if (fileAttributes == 0xffffffff) { StatError(interp, fileName); return TCL_ERROR; } result = Tcl_GetBooleanFromObj(interp, attributePtr, &yesNo); if (result != TCL_OK) { return result; } if (yesNo) { fileAttributes |= (attributeArray[objIndex]); } else { fileAttributes &= ~(attributeArray[objIndex]); } if (!(*tclWinProcs->setFileAttributesProc)(nativeName, fileAttributes)) { StatError(interp, fileName); return TCL_ERROR; } return result; } /* *---------------------------------------------------------------------- * * SetWinFileLongName -- * * The attribute in question is a readonly attribute and cannot * be set. * * Results: * TCL_ERROR * * Side effects: * The object result is set to a pertinent error message. * *---------------------------------------------------------------------- */ static int CannotSetAttribute( Tcl_Interp *interp, /* The interp we are using for errors. */ int objIndex, /* The index of the attribute. */ Tcl_Obj *fileName, /* The name of the file. */ Tcl_Obj *attributePtr) /* The new value of the attribute. */ { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "cannot set attribute \"", tclpFileAttrStrings[objIndex], "\" for file \"", Tcl_GetString(fileName), "\": attribute is readonly", (char *) NULL); return TCL_ERROR; } /* *--------------------------------------------------------------------------- * * TclpObjListVolumes -- * * Lists the currently mounted volumes * * Results: * The list of volumes. * * Side effects: * None * *--------------------------------------------------------------------------- */ Tcl_Obj* TclpObjListVolumes(void) { Tcl_Obj *resultPtr, *elemPtr; char buf[40 * 4]; /* There couldn't be more than 30 drives??? */ int i; char *p; resultPtr = Tcl_NewObj(); /* * On Win32s: * GetLogicalDriveStrings() isn't implemented. * GetLogicalDrives() returns incorrect information. */ if (GetLogicalDriveStringsA(sizeof(buf), buf) == 0) { /* * GetVolumeInformation() will detects all drives, but causes * chattering on empty floppy drives. We only do this if * GetLogicalDriveStrings() didn't work. It has also been reported * that on some laptops it takes a while for GetVolumeInformation() * to return when pinging an empty floppy drive, another reason to * try to avoid calling it. */ buf[1] = ':'; buf[2] = '/'; buf[3] = '\0'; for (i = 0; i < 26; i++) { buf[0] = (char) ('a' + i); if (GetVolumeInformationA(buf, NULL, 0, NULL, NULL, NULL, NULL, 0) || (GetLastError() == ERROR_NOT_READY)) { elemPtr = Tcl_NewStringObj(buf, -1); Tcl_ListObjAppendElement(NULL, resultPtr, elemPtr); } } } else { for (p = buf; *p != '\0'; p += 4) { p[2] = '/'; elemPtr = Tcl_NewStringObj(p, -1); Tcl_ListObjAppendElement(NULL, resultPtr, elemPtr); } } Tcl_IncrRefCount(resultPtr); return resultPtr; } tcl8.4.20/win/tclAppInit.c0000644003604700454610000002606111737050675013735 0ustar dgp771div/* * tclAppInit.c -- * * Provides a default version of the main program and Tcl_AppInit * procedure for Tcl applications (without Tk). Note that this * program must be built in Win32 console mode to work properly. * * Copyright (c) 1996-1997 by Sun Microsystems, Inc. * Copyright (c) 1998-1999 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tcl.h" #include #include #ifdef TCL_TEST extern int Procbodytest_Init _ANSI_ARGS_((Tcl_Interp *interp)); extern int Procbodytest_SafeInit _ANSI_ARGS_((Tcl_Interp *interp)); extern int Tcltest_Init _ANSI_ARGS_((Tcl_Interp *interp)); extern int TclObjTest_Init _ANSI_ARGS_((Tcl_Interp *interp)); #ifdef TCL_THREADS extern int TclThread_Init _ANSI_ARGS_((Tcl_Interp *interp)); #endif #endif /* TCL_TEST */ static void setargv _ANSI_ARGS_((int *argcPtr, char ***argvPtr)); static BOOL __stdcall sigHandler (DWORD fdwCtrlType); static Tcl_AsyncProc asyncExit; static void AppInitExitHandler(ClientData clientData); static char ** argvSave = NULL; static Tcl_AsyncHandler exitToken = NULL; static DWORD exitErrorCode = 0; /* *---------------------------------------------------------------------- * * main -- * * This is the main program for the application. * * Results: * None: Tcl_Main never returns here, so this procedure never * returns either. * * Side effects: * Whatever the application does. * *---------------------------------------------------------------------- */ int main(argc, argv) int argc; /* Number of command-line arguments. */ char **argv; /* Values of command-line arguments. */ { /* * The following #if block allows you to change the AppInit * function by using a #define of TCL_LOCAL_APPINIT instead * of rewriting this entire file. The #if checks for that * #define and uses Tcl_AppInit if it doesn't exist. */ #ifndef TCL_LOCAL_APPINIT #define TCL_LOCAL_APPINIT Tcl_AppInit #endif extern int TCL_LOCAL_APPINIT _ANSI_ARGS_((Tcl_Interp *interp)); /* * The following #if block allows you to change how Tcl finds the startup * script, prime the library or encoding paths, fiddle with the argv, * etc., without needing to rewrite Tcl_Main() */ #ifdef TCL_LOCAL_MAIN_HOOK extern int TCL_LOCAL_MAIN_HOOK _ANSI_ARGS_((int *argc, char ***argv)); #endif char buffer[MAX_PATH +1]; char *p; /* * Set up the default locale to be standard "C" locale so parsing * is performed correctly. */ setlocale(LC_ALL, "C"); setargv(&argc, &argv); /* * Save this for later, so we can free it. */ argvSave = argv; /* * Replace argv[0] with full pathname of executable, and forward * slashes substituted for backslashes. */ GetModuleFileName(NULL, buffer, sizeof(buffer)); argv[0] = buffer; for (p = buffer; *p != '\0'; p++) { if (*p == '\\') { *p = '/'; } } #ifdef TCL_LOCAL_MAIN_HOOK TCL_LOCAL_MAIN_HOOK(&argc, &argv); #endif Tcl_Main(argc, argv, TCL_LOCAL_APPINIT); return 0; /* Needed only to prevent compiler warning. */ } /* *---------------------------------------------------------------------- * * Tcl_AppInit -- * * This procedure performs application-specific initialization. * Most applications, especially those that incorporate additional * packages, will have their own version of this procedure. * * Results: * Returns a standard Tcl completion code, and leaves an error * message in the interp's result if an error occurs. * * Side effects: * Depends on the startup script. * *---------------------------------------------------------------------- */ int Tcl_AppInit(interp) Tcl_Interp *interp; /* Interpreter for application. */ { if (Tcl_Init(interp) == TCL_ERROR) { return TCL_ERROR; } /* * Install a signal handler to the win32 console tclsh is running in. */ SetConsoleCtrlHandler(sigHandler, TRUE); exitToken = Tcl_AsyncCreate(asyncExit, NULL); /* * This exit handler will be used to free the * resources allocated in this file. */ Tcl_CreateExitHandler(AppInitExitHandler, NULL); #ifdef TCL_TEST if (Tcltest_Init(interp) == TCL_ERROR) { return TCL_ERROR; } Tcl_StaticPackage(interp, "Tcltest", Tcltest_Init, (Tcl_PackageInitProc *) NULL); if (TclObjTest_Init(interp) == TCL_ERROR) { return TCL_ERROR; } #ifdef TCL_THREADS if (TclThread_Init(interp) == TCL_ERROR) { return TCL_ERROR; } #endif if (Procbodytest_Init(interp) == TCL_ERROR) { return TCL_ERROR; } Tcl_StaticPackage(interp, "procbodytest", Procbodytest_Init, Procbodytest_SafeInit); #endif /* TCL_TEST */ #if defined(STATIC_BUILD) && defined(TCL_USE_STATIC_PACKAGES) { extern Tcl_PackageInitProc Registry_Init; extern Tcl_PackageInitProc Dde_Init; if (Registry_Init(interp) == TCL_ERROR) { return TCL_ERROR; } Tcl_StaticPackage(interp, "registry", Registry_Init, NULL); if (Dde_Init(interp) == TCL_ERROR) { return TCL_ERROR; } Tcl_StaticPackage(interp, "dde", Dde_Init, NULL); } #endif /* * Call the init procedures for included packages. Each call should * look like this: * * if (Mod_Init(interp) == TCL_ERROR) { * return TCL_ERROR; * } * * where "Mod" is the name of the module. */ /* * Call Tcl_CreateCommand for application-specific commands, if * they weren't already created by the init procedures called above. */ /* * Specify a user-specific startup file to invoke if the application * is run interactively. Typically the startup file is "~/.apprc" * where "app" is the name of the application. If this line is deleted * then no user-specific startup file will be run under any conditions. */ Tcl_SetVar(interp, "tcl_rcFileName", "~/tclshrc.tcl", TCL_GLOBAL_ONLY); return TCL_OK; } /* *---------------------------------------------------------------------- * * AppInitExitHandler -- * * This function is called to cleanup the app init resources before * Tcl is unloaded. * * Results: * None. * * Side effects: * Frees the saved argv and deletes the async exit handler. * *---------------------------------------------------------------------- */ static void AppInitExitHandler( ClientData clientData) { if (argvSave != NULL) { ckfree((char *)argvSave); argvSave = NULL; } if (exitToken != NULL) { /* * This should be safe to do even if we * are in an async exit right now. */ Tcl_AsyncDelete(exitToken); exitToken = NULL; } } /* *------------------------------------------------------------------------- * * setargv -- * * Parse the Windows command line string into argc/argv. Done here * because we don't trust the builtin argument parser in crt0. * Windows applications are responsible for breaking their command * line into arguments. * * 2N backslashes + quote -> N backslashes + begin quoted string * 2N + 1 backslashes + quote -> literal * N backslashes + non-quote -> literal * quote + quote in a quoted string -> single quote * quote + quote not in quoted string -> empty string * quote -> begin quoted string * * Results: * Fills argcPtr with the number of arguments and argvPtr with the * array of arguments. * * Side effects: * Memory allocated. * *-------------------------------------------------------------------------- */ static void setargv(argcPtr, argvPtr) int *argcPtr; /* Filled with number of argument strings. */ char ***argvPtr; /* Filled with argument strings (malloc'd). */ { char *cmdLine, *p, *arg, *argSpace; char **argv; int argc, size, inquote, copy, slashes; cmdLine = GetCommandLine(); /* INTL: BUG */ /* * Precompute an overly pessimistic guess at the number of arguments * in the command line by counting non-space spans. */ size = 2; for (p = cmdLine; *p != '\0'; p++) { if ((*p == ' ') || (*p == '\t')) { /* INTL: ISO space. */ size++; while ((*p == ' ') || (*p == '\t')) { /* INTL: ISO space. */ p++; } if (*p == '\0') { break; } } } argSpace = (char *) ckalloc( (unsigned) (size * sizeof(char *) + strlen(cmdLine) + 1)); argv = (char **) argSpace; argSpace += size * sizeof(char *); size--; p = cmdLine; for (argc = 0; argc < size; argc++) { argv[argc] = arg = argSpace; while ((*p == ' ') || (*p == '\t')) { /* INTL: ISO space. */ p++; } if (*p == '\0') { break; } inquote = 0; slashes = 0; while (1) { copy = 1; while (*p == '\\') { slashes++; p++; } if (*p == '"') { if ((slashes & 1) == 0) { copy = 0; if ((inquote) && (p[1] == '"')) { p++; copy = 1; } else { inquote = !inquote; } } slashes >>= 1; } while (slashes) { *arg = '\\'; arg++; slashes--; } if ((*p == '\0') || (!inquote && ((*p == ' ') || (*p == '\t')))) { /* INTL: ISO space. */ break; } if (copy != 0) { *arg = *p; arg++; } p++; } *arg = '\0'; argSpace = arg + 1; } argv[argc] = NULL; *argcPtr = argc; *argvPtr = argv; } /* *---------------------------------------------------------------------- * * asyncExit -- * * The AsyncProc for the exitToken. * * Results: * doesn't actually return. * * Side effects: * tclsh cleanly exits. * *---------------------------------------------------------------------- */ int asyncExit (ClientData clientData, Tcl_Interp *interp, int code) { Tcl_Exit((int)exitErrorCode); /* NOTREACHED */ return code; } /* *---------------------------------------------------------------------- * * sigHandler -- * * Signal handler for the Win32 OS. Catches Ctrl+C, Ctrl+Break and * other exits. This is needed so tclsh can do it's real clean-up * and not an unclean crash terminate. * * Results: * TRUE. * * Side effects: * Effects the way the app exits from a signal. This is an * operating system supplied thread and unsafe to call ANY * Tcl commands except for Tcl_AsyncMark. * *---------------------------------------------------------------------- */ BOOL __stdcall sigHandler(DWORD fdwCtrlType) { HANDLE hStdIn; if (!exitToken) { /* Async token must have been destroyed, punt gracefully. */ return FALSE; } /* * If Tcl is currently executing some bytecode or in the eventloop, * this will cause Tcl to enter asyncExit at the next command * boundry. */ exitErrorCode = fdwCtrlType; Tcl_AsyncMark(exitToken); /* * This will cause Tcl_Gets in Tcl_Main() to drop-out with an * should it be blocked on input and our Tcl_AsyncMark didn't grab * the attention of the interpreter. */ hStdIn = GetStdHandle(STD_INPUT_HANDLE); if (hStdIn) { CloseHandle(hStdIn); } /* indicate to the OS not to call the default terminator */ return TRUE; } tcl8.4.20/win/tclWinPipe.c0000644003604700454610000024337612052456744013754 0ustar dgp771div/* * tclWinPipe.c -- * * This file implements the Windows-specific exec pipeline functions, * the "pipe" channel driver, and the "pid" Tcl command. * * Copyright (c) 1996-1997 by Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclWinInt.h" #include #include #include /* * The following variable is used to tell whether this module has been * initialized. */ static int initialized = 0; /* * The pipeMutex locks around access to the initialized and procList variables, * and it is used to protect background threads from being terminated while * they are using APIs that hold locks. */ TCL_DECLARE_MUTEX(pipeMutex) /* * The following defines identify the various types of applications that * run under windows. There is special case code for the various types. */ #define APPL_NONE 0 #define APPL_DOS 1 #define APPL_WIN3X 2 #define APPL_WIN32 3 /* * The following constants and structures are used to encapsulate the state * of various types of files used in a pipeline. * This used to have a 1 && 2 that supported Win32s. */ #define WIN_FILE 3 /* Basic Win32 file. */ /* * This structure encapsulates the common state associated with all file * types used in a pipeline. */ typedef struct WinFile { int type; /* One of the file types defined above. */ HANDLE handle; /* Open file handle. */ } WinFile; /* * This list is used to map from pids to process handles. */ typedef struct ProcInfo { HANDLE hProcess; DWORD dwProcessId; struct ProcInfo *nextPtr; } ProcInfo; static ProcInfo *procList; /* * Bit masks used in the flags field of the PipeInfo structure below. */ #define PIPE_PENDING (1<<0) /* Message is pending in the queue. */ #define PIPE_ASYNC (1<<1) /* Channel is non-blocking. */ /* * Bit masks used in the sharedFlags field of the PipeInfo structure below. */ #define PIPE_EOF (1<<2) /* Pipe has reached EOF. */ #define PIPE_EXTRABYTE (1<<3) /* The reader thread has consumed one byte. */ /* * This structure describes per-instance data for a pipe based channel. */ typedef struct PipeInfo { struct PipeInfo *nextPtr; /* Pointer to next registered pipe. */ Tcl_Channel channel; /* Pointer to channel structure. */ int validMask; /* OR'ed combination of TCL_READABLE, * TCL_WRITABLE, or TCL_EXCEPTION: indicates * which operations are valid on the file. */ int watchMask; /* OR'ed combination of TCL_READABLE, * TCL_WRITABLE, or TCL_EXCEPTION: indicates * which events should be reported. */ int flags; /* State flags, see above for a list. */ TclFile readFile; /* Output from pipe. */ TclFile writeFile; /* Input from pipe. */ TclFile errorFile; /* Error output from pipe. */ int numPids; /* Number of processes attached to pipe. */ Tcl_Pid *pidPtr; /* Pids of attached processes. */ Tcl_ThreadId threadId; /* Thread to which events should be reported. * This value is used by the reader/writer * threads. */ HANDLE writeThread; /* Handle to writer thread. */ HANDLE readThread; /* Handle to reader thread. */ HANDLE writable; /* Manual-reset event to signal when the * writer thread has finished waiting for * the current buffer to be written. */ HANDLE readable; /* Manual-reset event to signal when the * reader thread has finished waiting for * input. */ HANDLE startWriter; /* Auto-reset event used by the main thread to * signal when the writer thread should attempt * to write to the pipe. */ HANDLE stopWriter; /* Manual-reset event used to alert the reader * thread to fall-out and exit */ HANDLE startReader; /* Auto-reset event used by the main thread to * signal when the reader thread should attempt * to read from the pipe. */ HANDLE stopReader; /* Manual-reset event used to alert the reader * thread to fall-out and exit */ DWORD writeError; /* An error caused by the last background * write. Set to 0 if no error has been * detected. This word is shared with the * writer thread so access must be * synchronized with the writable object. */ char *writeBuf; /* Current background output buffer. * Access is synchronized with the writable * object. */ int writeBufLen; /* Size of write buffer. Access is * synchronized with the writable * object. */ int toWrite; /* Current amount to be written. Access is * synchronized with the writable object. */ int readFlags; /* Flags that are shared with the reader * thread. Access is synchronized with the * readable object. */ char extraByte; /* Buffer for extra character consumed by * reader thread. This byte is shared with * the reader thread so access must be * synchronized with the readable object. */ } PipeInfo; typedef struct ThreadSpecificData { /* * The following pointer refers to the head of the list of pipes * that are being watched for file events. */ PipeInfo *firstPipePtr; } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; /* * The following structure is what is added to the Tcl event queue when * pipe events are generated. */ typedef struct PipeEvent { Tcl_Event header; /* Information that is standard for * all events. */ PipeInfo *infoPtr; /* Pointer to pipe info structure. Note * that we still have to verify that the * pipe exists before dereferencing this * pointer. */ } PipeEvent; /* * Declarations for functions used only in this file. */ static int ApplicationType(Tcl_Interp *interp, const char *fileName, char *fullName); static void BuildCommandLine(const char *executable, int argc, CONST char **argv, Tcl_DString *linePtr); static BOOL HasConsole(void); static int PipeBlockModeProc(ClientData instanceData, int mode); static void PipeCheckProc(ClientData clientData, int flags); static int PipeClose2Proc(ClientData instanceData, Tcl_Interp *interp, int flags); static int PipeEventProc(Tcl_Event *evPtr, int flags); static int PipeGetHandleProc(ClientData instanceData, int direction, ClientData *handlePtr); static void PipeInit(void); static int PipeInputProc(ClientData instanceData, char *buf, int toRead, int *errorCode); static int PipeOutputProc(ClientData instanceData, CONST char *buf, int toWrite, int *errorCode); static DWORD WINAPI PipeReaderThread(LPVOID arg); static void PipeSetupProc(ClientData clientData, int flags); static void PipeWatchProc(ClientData instanceData, int mask); static DWORD WINAPI PipeWriterThread(LPVOID arg); static int TempFileName(WCHAR name[MAX_PATH]); static int WaitForRead(PipeInfo *infoPtr, int blocking); static void PipeThreadActionProc _ANSI_ARGS_ (( ClientData instanceData, int action)); /* * This structure describes the channel type structure for command pipe * based IO. */ static Tcl_ChannelType pipeChannelType = { "pipe", /* Type name. */ TCL_CHANNEL_VERSION_4, /* v4 channel */ TCL_CLOSE2PROC, /* Close proc. */ PipeInputProc, /* Input proc. */ PipeOutputProc, /* Output proc. */ NULL, /* Seek proc. */ NULL, /* Set option proc. */ NULL, /* Get option proc. */ PipeWatchProc, /* Set up notifier to watch the channel. */ PipeGetHandleProc, /* Get an OS handle from channel. */ PipeClose2Proc, /* close2proc */ PipeBlockModeProc, /* Set blocking or non-blocking mode.*/ NULL, /* flush proc. */ NULL, /* handler proc. */ NULL, /* wide seek proc */ PipeThreadActionProc, /* thread action proc */ }; /* *---------------------------------------------------------------------- * * PipeInit -- * * This function initializes the static variables for this file. * * Results: * None. * * Side effects: * Creates a new event source. * *---------------------------------------------------------------------- */ static void PipeInit() { ThreadSpecificData *tsdPtr; /* * Check the initialized flag first, then check again in the mutex. * This is a speed enhancement. */ if (!initialized) { Tcl_MutexLock(&pipeMutex); if (!initialized) { initialized = 1; procList = NULL; } Tcl_MutexUnlock(&pipeMutex); } tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); if (tsdPtr == NULL) { tsdPtr = TCL_TSD_INIT(&dataKey); tsdPtr->firstPipePtr = NULL; Tcl_CreateEventSource(PipeSetupProc, PipeCheckProc, NULL); } } /* *---------------------------------------------------------------------- * * TclpFinalizePipes -- * * This function is called from Tcl_FinalizeThread to finalize the * platform specific pipe subsystem. * * Results: * None. * * Side effects: * Removes the pipe event source. * *---------------------------------------------------------------------- */ void TclpFinalizePipes() { ThreadSpecificData *tsdPtr; tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); if (tsdPtr != NULL) { Tcl_DeleteEventSource(PipeSetupProc, PipeCheckProc, NULL); } } /* *---------------------------------------------------------------------- * * PipeSetupProc -- * * This procedure is invoked before Tcl_DoOneEvent blocks waiting * for an event. * * Results: * None. * * Side effects: * Adjusts the block time if needed. * *---------------------------------------------------------------------- */ void PipeSetupProc( ClientData data, /* Not used. */ int flags) /* Event flags as passed to Tcl_DoOneEvent. */ { PipeInfo *infoPtr; Tcl_Time blockTime = { 0, 0 }; int block = 1; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (!(flags & TCL_FILE_EVENTS)) { return; } /* * Look to see if any events are already pending. If they are, poll. */ for (infoPtr = tsdPtr->firstPipePtr; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { if (infoPtr->watchMask & TCL_WRITABLE) { if (WaitForSingleObject(infoPtr->writable, 0) != WAIT_TIMEOUT) { block = 0; } } if (infoPtr->watchMask & TCL_READABLE) { if (WaitForRead(infoPtr, 0) >= 0) { block = 0; } } } if (!block) { Tcl_SetMaxBlockTime(&blockTime); } } /* *---------------------------------------------------------------------- * * PipeCheckProc -- * * This procedure is called by Tcl_DoOneEvent to check the pipe * event source for events. * * Results: * None. * * Side effects: * May queue an event. * *---------------------------------------------------------------------- */ static void PipeCheckProc( ClientData data, /* Not used. */ int flags) /* Event flags as passed to Tcl_DoOneEvent. */ { PipeInfo *infoPtr; PipeEvent *evPtr; int needEvent; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (!(flags & TCL_FILE_EVENTS)) { return; } /* * Queue events for any ready pipes that don't already have events * queued. */ for (infoPtr = tsdPtr->firstPipePtr; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { if (infoPtr->flags & PIPE_PENDING) { continue; } /* * Queue an event if the pipe is signaled for reading or writing. */ needEvent = 0; if ((infoPtr->watchMask & TCL_WRITABLE) && (WaitForSingleObject(infoPtr->writable, 0) != WAIT_TIMEOUT)) { needEvent = 1; } if ((infoPtr->watchMask & TCL_READABLE) && (WaitForRead(infoPtr, 0) >= 0)) { needEvent = 1; } if (needEvent) { infoPtr->flags |= PIPE_PENDING; evPtr = (PipeEvent *) ckalloc(sizeof(PipeEvent)); evPtr->header.proc = PipeEventProc; evPtr->infoPtr = infoPtr; Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL); } } } /* *---------------------------------------------------------------------- * * TclWinMakeFile -- * * This function constructs a new TclFile from a given data and * type value. * * Results: * Returns a newly allocated WinFile as a TclFile. * * Side effects: * None. * *---------------------------------------------------------------------- */ TclFile TclWinMakeFile( HANDLE handle) /* Type-specific data. */ { WinFile *filePtr; filePtr = (WinFile *) ckalloc(sizeof(WinFile)); filePtr->type = WIN_FILE; filePtr->handle = handle; return (TclFile)filePtr; } /* *---------------------------------------------------------------------- * * TempFileName -- * * Gets a temporary file name and deals with the fact that the * temporary file path provided by Windows may not actually exist * if the TMP or TEMP environment variables refer to a * non-existent directory. * * Results: * 0 if error, non-zero otherwise. If non-zero is returned, the * name buffer will be filled with a name that can be used to * construct a temporary file. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TempFileName(name) WCHAR name[MAX_PATH]; /* Buffer in which name for temporary * file gets stored. */ { TCHAR *prefix; prefix = (tclWinProcs->useWide) ? (TCHAR *) L"TCL" : (TCHAR *) "TCL"; if ((*tclWinProcs->getTempPathProc)(MAX_PATH, name) != 0) { if ((*tclWinProcs->getTempFileNameProc)((TCHAR *) name, prefix, 0, name) != 0) { return 1; } } if (tclWinProcs->useWide) { ((WCHAR *) name)[0] = '.'; ((WCHAR *) name)[1] = '\0'; } else { ((char *) name)[0] = '.'; ((char *) name)[1] = '\0'; } return (*tclWinProcs->getTempFileNameProc)((TCHAR *) name, prefix, 0, name); } /* *---------------------------------------------------------------------- * * TclpMakeFile -- * * Make a TclFile from a channel. * * Results: * Returns a new TclFile or NULL on failure. * * Side effects: * None. * *---------------------------------------------------------------------- */ TclFile TclpMakeFile(channel, direction) Tcl_Channel channel; /* Channel to get file from. */ int direction; /* Either TCL_READABLE or TCL_WRITABLE. */ { HANDLE handle; if (Tcl_GetChannelHandle(channel, direction, (ClientData *) &handle) == TCL_OK) { return TclWinMakeFile(handle); } else { return (TclFile) NULL; } } /* *---------------------------------------------------------------------- * * TclpOpenFile -- * * This function opens files for use in a pipeline. * * Results: * Returns a newly allocated TclFile structure containing the * file handle. * * Side effects: * None. * *---------------------------------------------------------------------- */ TclFile TclpOpenFile(path, mode) CONST char *path; /* The name of the file to open. */ int mode; /* In what mode to open the file? */ { HANDLE handle; DWORD accessMode, createMode, shareMode, flags; Tcl_DString ds; CONST TCHAR *nativePath; /* * Map the access bits to the NT access mode. */ switch (mode & (O_RDONLY | O_WRONLY | O_RDWR)) { case O_RDONLY: accessMode = GENERIC_READ; break; case O_WRONLY: accessMode = GENERIC_WRITE; break; case O_RDWR: accessMode = (GENERIC_READ | GENERIC_WRITE); break; default: TclWinConvertError(ERROR_INVALID_FUNCTION); return NULL; } /* * Map the creation flags to the NT create mode. */ switch (mode & (O_CREAT | O_EXCL | O_TRUNC)) { case (O_CREAT | O_EXCL): case (O_CREAT | O_EXCL | O_TRUNC): createMode = CREATE_NEW; break; case (O_CREAT | O_TRUNC): createMode = CREATE_ALWAYS; break; case O_CREAT: createMode = OPEN_ALWAYS; break; case O_TRUNC: case (O_TRUNC | O_EXCL): createMode = TRUNCATE_EXISTING; break; default: createMode = OPEN_EXISTING; break; } nativePath = Tcl_WinUtfToTChar(path, -1, &ds); /* * If the file is not being created, use the existing file attributes. */ flags = 0; if (!(mode & O_CREAT)) { flags = (*tclWinProcs->getFileAttributesProc)(nativePath); if (flags == 0xFFFFFFFF) { flags = 0; } } /* * Set up the file sharing mode. We want to allow simultaneous access. */ shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; /* * Now we get to create the file. */ handle = (*tclWinProcs->createFileProc)(nativePath, accessMode, shareMode, NULL, createMode, flags, NULL); Tcl_DStringFree(&ds); if (handle == INVALID_HANDLE_VALUE) { DWORD err; err = GetLastError(); if ((err & 0xffffL) == ERROR_OPEN_FAILED) { err = (mode & O_CREAT) ? ERROR_FILE_EXISTS : ERROR_FILE_NOT_FOUND; } TclWinConvertError(err); return NULL; } /* * Seek to the end of file if we are writing. */ if (mode & (O_WRONLY|O_APPEND)) { SetFilePointer(handle, 0, NULL, FILE_END); } return TclWinMakeFile(handle); } /* *---------------------------------------------------------------------- * * TclpCreateTempFile -- * * This function opens a unique file with the property that it * will be deleted when its file handle is closed. The temporary * file is created in the system temporary directory. * * Results: * Returns a valid TclFile, or NULL on failure. * * Side effects: * Creates a new temporary file. * *---------------------------------------------------------------------- */ TclFile TclpCreateTempFile(contents) CONST char *contents; /* String to write into temp file, or NULL. */ { WCHAR name[MAX_PATH]; CONST char *native; Tcl_DString dstring; HANDLE handle; if (TempFileName(name) == 0) { return NULL; } handle = (*tclWinProcs->createFileProc)((TCHAR *) name, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY|FILE_FLAG_DELETE_ON_CLOSE, NULL); if (handle == INVALID_HANDLE_VALUE) { goto error; } /* * Write the file out, doing line translations on the way. */ if (contents != NULL) { DWORD result, length; CONST char *p; int toCopy; /* * Convert the contents from UTF to native encoding */ native = Tcl_UtfToExternalDString(NULL, contents, -1, &dstring); toCopy = Tcl_DStringLength(&dstring); for (p = native; toCopy > 0; p++, toCopy--) { if (*p == '\n') { length = p - native; if (length > 0) { if (!WriteFile(handle, native, length, &result, NULL)) { goto error; } } if (!WriteFile(handle, "\r\n", 2, &result, NULL)) { goto error; } native = p+1; } } length = p - native; if (length > 0) { if (!WriteFile(handle, native, length, &result, NULL)) { goto error; } } Tcl_DStringFree(&dstring); if (SetFilePointer(handle, 0, NULL, FILE_BEGIN) == 0xFFFFFFFF) { goto error; } } return TclWinMakeFile(handle); error: /* Free the native representation of the contents if necessary */ if (contents != NULL) { Tcl_DStringFree(&dstring); } TclWinConvertError(GetLastError()); CloseHandle(handle); (*tclWinProcs->deleteFileProc)((TCHAR *) name); return NULL; } /* *---------------------------------------------------------------------- * * TclpTempFileName -- * * This function returns a unique filename. * * Results: * Returns a valid Tcl_Obj* with refCount 0, or NULL on failure. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_Obj* TclpTempFileName() { WCHAR fileName[MAX_PATH]; if (TempFileName(fileName) == 0) { return NULL; } return TclpNativeToNormalized((ClientData) fileName); } /* *---------------------------------------------------------------------- * * TclpCreatePipe -- * * Creates an anonymous pipe. * * Results: * Returns 1 on success, 0 on failure. * * Side effects: * Creates a pipe. * *---------------------------------------------------------------------- */ int TclpCreatePipe( TclFile *readPipe, /* Location to store file handle for * read side of pipe. */ TclFile *writePipe) /* Location to store file handle for * write side of pipe. */ { HANDLE readHandle, writeHandle; if (CreatePipe(&readHandle, &writeHandle, NULL, 0) != 0) { *readPipe = TclWinMakeFile(readHandle); *writePipe = TclWinMakeFile(writeHandle); return 1; } TclWinConvertError(GetLastError()); return 0; } /* *---------------------------------------------------------------------- * * TclpCloseFile -- * * Closes a pipeline file handle. These handles are created by * TclpOpenFile, TclpCreatePipe, or TclpMakeFile. * * Results: * 0 on success, -1 on failure. * * Side effects: * The file is closed and deallocated. * *---------------------------------------------------------------------- */ int TclpCloseFile( TclFile file) /* The file to close. */ { WinFile *filePtr = (WinFile *) file; switch (filePtr->type) { case WIN_FILE: /* * Don't close the Win32 handle if the handle is a standard channel * during the thread exit process. Otherwise, one thread may kill * the stdio of another. */ if (!TclInThreadExit() || ((GetStdHandle(STD_INPUT_HANDLE) != filePtr->handle) && (GetStdHandle(STD_OUTPUT_HANDLE) != filePtr->handle) && (GetStdHandle(STD_ERROR_HANDLE) != filePtr->handle))) { if (filePtr->handle != NULL && CloseHandle(filePtr->handle) == FALSE) { TclWinConvertError(GetLastError()); ckfree((char *) filePtr); return -1; } } break; default: panic("TclpCloseFile: unexpected file type"); } ckfree((char *) filePtr); return 0; } /* *-------------------------------------------------------------------------- * * TclpGetPid -- * * Given a HANDLE to a child process, return the process id for that * child process. * * Results: * Returns the process id for the child process. If the pid was not * known by Tcl, either because the pid was not created by Tcl or the * child process has already been reaped, -1 is returned. * * Side effects: * None. * *-------------------------------------------------------------------------- */ int TclpGetPid( Tcl_Pid pid) /* The HANDLE of the child process. */ { ProcInfo *infoPtr; PipeInit(); Tcl_MutexLock(&pipeMutex); for (infoPtr = procList; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { if (infoPtr->hProcess == (HANDLE) pid) { Tcl_MutexUnlock(&pipeMutex); return infoPtr->dwProcessId; } } Tcl_MutexUnlock(&pipeMutex); return (unsigned long) -1; } /* *---------------------------------------------------------------------- * * TclpCreateProcess -- * * Create a child process that has the specified files as its * standard input, output, and error. The child process runs * asynchronously under Windows NT and Windows 9x, and runs * with the same environment variables as the creating process. * * The complete Windows search path is searched to find the specified * executable. If an executable by the given name is not found, * automatically tries appending ".com", ".exe", and ".bat" to the * executable name. * * Results: * The return value is TCL_ERROR and an error message is left in * the interp's result if there was a problem creating the child * process. Otherwise, the return value is TCL_OK and *pidPtr is * filled with the process id of the child process. * * Side effects: * A process is created. * *---------------------------------------------------------------------- */ int TclpCreateProcess( Tcl_Interp *interp, /* Interpreter in which to leave errors that * occurred when creating the child process. * Error messages from the child process * itself are sent to errorFile. */ int argc, /* Number of arguments in following array. */ CONST char **argv, /* Array of argument strings. argv[0] * contains the name of the executable * converted to native format (using the * Tcl_TranslateFileName call). Additional * arguments have not been converted. */ TclFile inputFile, /* If non-NULL, gives the file to use as * input for the child process. If inputFile * file is not readable or is NULL, the child * will receive no standard input. */ TclFile outputFile, /* If non-NULL, gives the file that * receives output from the child process. If * outputFile file is not writeable or is * NULL, output from the child will be * discarded. */ TclFile errorFile, /* If non-NULL, gives the file that * receives errors from the child process. If * errorFile file is not writeable or is NULL, * errors from the child will be discarded. * errorFile may be the same as outputFile. */ Tcl_Pid *pidPtr) /* If this procedure is successful, pidPtr * is filled with the process id of the child * process. */ { int result, applType, createFlags; Tcl_DString cmdLine; /* Complete command line (TCHAR). */ STARTUPINFOA startInfo; PROCESS_INFORMATION procInfo; SECURITY_ATTRIBUTES secAtts; HANDLE hProcess, h, inputHandle, outputHandle, errorHandle; char execPath[MAX_PATH * TCL_UTF_MAX]; WinFile *filePtr; PipeInit(); applType = ApplicationType(interp, argv[0], execPath); if (applType == APPL_NONE) { return TCL_ERROR; } result = TCL_ERROR; Tcl_DStringInit(&cmdLine); hProcess = GetCurrentProcess(); /* * STARTF_USESTDHANDLES must be used to pass handles to child process. * Using SetStdHandle() and/or dup2() only works when a console mode * parent process is spawning an attached console mode child process. */ ZeroMemory(&startInfo, sizeof(startInfo)); startInfo.cb = sizeof(startInfo); startInfo.dwFlags = STARTF_USESTDHANDLES; startInfo.hStdInput = INVALID_HANDLE_VALUE; startInfo.hStdOutput= INVALID_HANDLE_VALUE; startInfo.hStdError = INVALID_HANDLE_VALUE; secAtts.nLength = sizeof(SECURITY_ATTRIBUTES); secAtts.lpSecurityDescriptor = NULL; secAtts.bInheritHandle = TRUE; /* * We have to check the type of each file, since we cannot duplicate * some file types. */ inputHandle = INVALID_HANDLE_VALUE; if (inputFile != NULL) { filePtr = (WinFile *)inputFile; if (filePtr->type == WIN_FILE) { inputHandle = filePtr->handle; } } outputHandle = INVALID_HANDLE_VALUE; if (outputFile != NULL) { filePtr = (WinFile *)outputFile; if (filePtr->type == WIN_FILE) { outputHandle = filePtr->handle; } } errorHandle = INVALID_HANDLE_VALUE; if (errorFile != NULL) { filePtr = (WinFile *)errorFile; if (filePtr->type == WIN_FILE) { errorHandle = filePtr->handle; } } /* * Duplicate all the handles which will be passed off as stdin, stdout * and stderr of the child process. The duplicate handles are set to * be inheritable, so the child process can use them. */ if (inputHandle == INVALID_HANDLE_VALUE) { /* * If handle was not set, stdin should return immediate EOF. * Under Windows95, some applications (both 16 and 32 bit!) * cannot read from the NUL device; they read from console * instead. When running tk, this is fatal because the child * process would hang forever waiting for EOF from the unmapped * console window used by the helper application. * * Fortunately, the helper application detects a closed pipe * as an immediate EOF and can pass that information to the * child process. */ if (CreatePipe(&startInfo.hStdInput, &h, &secAtts, 0) != FALSE) { CloseHandle(h); } } else { DuplicateHandle(hProcess, inputHandle, hProcess, &startInfo.hStdInput, 0, TRUE, DUPLICATE_SAME_ACCESS); } if (startInfo.hStdInput == INVALID_HANDLE_VALUE) { TclWinConvertError(GetLastError()); Tcl_AppendResult(interp, "couldn't duplicate input handle: ", Tcl_PosixError(interp), (char *) NULL); goto end; } if (outputHandle == INVALID_HANDLE_VALUE) { /* * If handle was not set, output should be sent to an infinitely * deep sink. Under Windows 95, some 16 bit applications cannot * have stdout redirected to NUL; they send their output to * the console instead. Some applications, like "more" or "dir /p", * when outputting multiple pages to the console, also then try and * read from the console to go the next page. When running tk, this * is fatal because the child process would hang forever waiting * for input from the unmapped console window used by the helper * application. * * Fortunately, the helper application will detect a closed pipe * as a sink. */ if ((TclWinGetPlatformId() == VER_PLATFORM_WIN32_WINDOWS) && (applType == APPL_DOS)) { if (CreatePipe(&h, &startInfo.hStdOutput, &secAtts, 0) != FALSE) { CloseHandle(h); } } else { startInfo.hStdOutput = CreateFileA("NUL:", GENERIC_WRITE, 0, &secAtts, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); } } else { DuplicateHandle(hProcess, outputHandle, hProcess, &startInfo.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS); } if (startInfo.hStdOutput == INVALID_HANDLE_VALUE) { TclWinConvertError(GetLastError()); Tcl_AppendResult(interp, "couldn't duplicate output handle: ", Tcl_PosixError(interp), (char *) NULL); goto end; } if (errorHandle == INVALID_HANDLE_VALUE) { /* * If handle was not set, errors should be sent to an infinitely * deep sink. */ startInfo.hStdError = CreateFileA("NUL:", GENERIC_WRITE, 0, &secAtts, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); } else { DuplicateHandle(hProcess, errorHandle, hProcess, &startInfo.hStdError, 0, TRUE, DUPLICATE_SAME_ACCESS); } if (startInfo.hStdError == INVALID_HANDLE_VALUE) { TclWinConvertError(GetLastError()); Tcl_AppendResult(interp, "couldn't duplicate error handle: ", Tcl_PosixError(interp), (char *) NULL); goto end; } /* * If we do not have a console window, then we must run DOS and * WIN32 console mode applications as detached processes. This tells * the loader that the child application should not inherit the * console, and that it should not create a new console window for * the child application. The child application should get its stdio * from the redirection handles provided by this application, and run * in the background. * * If we are starting a GUI process, they don't automatically get a * console, so it doesn't matter if they are started as foreground or * detached processes. The GUI window will still pop up to the * foreground. */ if (TclWinGetPlatformId() == VER_PLATFORM_WIN32_NT) { if (HasConsole()) { createFlags = 0; } else if (applType == APPL_DOS) { /* * Under NT, 16-bit DOS applications will not run unless they * can be attached to a console. If we are running without a * console, run the 16-bit program as an normal process inside * of a hidden console application, and then run that hidden * console as a detached process. */ startInfo.wShowWindow = SW_HIDE; startInfo.dwFlags |= STARTF_USESHOWWINDOW; createFlags = CREATE_NEW_CONSOLE; Tcl_DStringAppend(&cmdLine, "cmd.exe /c", -1); } else { createFlags = DETACHED_PROCESS; } } else { if (HasConsole()) { createFlags = 0; } else { createFlags = DETACHED_PROCESS; } if (applType == APPL_DOS) { /* * Under Windows 95, 16-bit DOS applications do not work well * with pipes: * * 1. EOF on a pipe between a detached 16-bit DOS application * and another application is not seen at the other * end of the pipe, so the listening process blocks forever on * reads. This inablity to detect EOF happens when either a * 16-bit app or the 32-bit app is the listener. * * 2. If a 16-bit DOS application (detached or not) blocks when * writing to a pipe, it will never wake up again, and it * eventually brings the whole system down around it. * * The 16-bit application is run as a normal process inside * of a hidden helper console app, and this helper may be run * as a detached process. If any of the stdio handles is * a pipe, the helper application accumulates information * into temp files and forwards it to or from the DOS * application as appropriate. This means that DOS apps * must receive EOF from a stdin pipe before they will actually * begin, and must finish generating stdout or stderr before * the data will be sent to the next stage of the pipe. * * The helper app should be located in the same directory as * the tcl dll. */ if (createFlags != 0) { startInfo.wShowWindow = SW_HIDE; startInfo.dwFlags |= STARTF_USESHOWWINDOW; createFlags = CREATE_NEW_CONSOLE; } { Tcl_Obj *tclExePtr, *pipeDllPtr; int i, fileExists; char *start,*end; Tcl_DString pipeDll; Tcl_DStringInit(&pipeDll); Tcl_DStringAppend(&pipeDll, TCL_PIPE_DLL, -1); tclExePtr = Tcl_NewStringObj(TclpFindExecutable(""), -1); start = Tcl_GetStringFromObj(tclExePtr, &i); for (end = start + (i-1); end > start; end--) { if (*end == '/') break; } if (*end != '/') panic("no / in executable path name"); i = (end - start) + 1; pipeDllPtr = Tcl_NewStringObj(start, i); Tcl_AppendToObj(pipeDllPtr, Tcl_DStringValue(&pipeDll), -1); Tcl_IncrRefCount(pipeDllPtr); if (Tcl_FSConvertToPathType(interp, pipeDllPtr) != TCL_OK) panic("Tcl_FSConvertToPathType failed"); fileExists = (Tcl_FSAccess(pipeDllPtr, F_OK) == 0); if (!fileExists) { panic("Tcl pipe dll \"%s\" not found", Tcl_DStringValue(&pipeDll)); } Tcl_DStringAppend(&cmdLine, Tcl_DStringValue(&pipeDll), -1); Tcl_DecrRefCount(tclExePtr); Tcl_DecrRefCount(pipeDllPtr); Tcl_DStringFree(&pipeDll); } } } /* * cmdLine gets the full command line used to invoke the executable, * including the name of the executable itself. The command line * arguments in argv[] are stored in cmdLine separated by spaces. * Special characters in individual arguments from argv[] must be * quoted when being stored in cmdLine. * * When calling any application, bear in mind that arguments that * specify a path name are not converted. If an argument contains * forward slashes as path separators, it may or may not be * recognized as a path name, depending on the program. In general, * most applications accept forward slashes only as option * delimiters and backslashes only as paths. * * Additionally, when calling a 16-bit dos or windows application, * all path names must use the short, cryptic, path format (e.g., * using ab~1.def instead of "a b.default"). */ BuildCommandLine(execPath, argc, argv, &cmdLine); if ((*tclWinProcs->createProcessProc)(NULL, (TCHAR *) Tcl_DStringValue(&cmdLine), NULL, NULL, TRUE, (DWORD) createFlags, NULL, NULL, &startInfo, &procInfo) == 0) { TclWinConvertError(GetLastError()); Tcl_AppendResult(interp, "couldn't execute \"", argv[0], "\": ", Tcl_PosixError(interp), (char *) NULL); goto end; } /* * This wait is used to force the OS to give some time to the DOS * process. */ if (applType == APPL_DOS) { WaitForSingleObject(procInfo.hProcess, 50); } /* * "When an application spawns a process repeatedly, a new thread * instance will be created for each process but the previous * instances may not be cleaned up. This results in a significant * virtual memory loss each time the process is spawned. If there * is a WaitForInputIdle() call between CreateProcess() and * CloseHandle(), the problem does not occur." PSS ID Number: Q124121 */ WaitForInputIdle(procInfo.hProcess, 5000); CloseHandle(procInfo.hThread); *pidPtr = (Tcl_Pid) procInfo.hProcess; if (*pidPtr != 0) { TclWinAddProcess(procInfo.hProcess, procInfo.dwProcessId); } result = TCL_OK; end: Tcl_DStringFree(&cmdLine); if (startInfo.hStdInput != INVALID_HANDLE_VALUE) { CloseHandle(startInfo.hStdInput); } if (startInfo.hStdOutput != INVALID_HANDLE_VALUE) { CloseHandle(startInfo.hStdOutput); } if (startInfo.hStdError != INVALID_HANDLE_VALUE) { CloseHandle(startInfo.hStdError); } return result; } /* *---------------------------------------------------------------------- * * HasConsole -- * * Determines whether the current application is attached to a * console. * * Results: * Returns TRUE if this application has a console, else FALSE. * * Side effects: * None. * *---------------------------------------------------------------------- */ static BOOL HasConsole() { HANDLE handle; handle = CreateFileA("CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (handle != INVALID_HANDLE_VALUE) { CloseHandle(handle); return TRUE; } else { return FALSE; } } /* *-------------------------------------------------------------------- * * ApplicationType -- * * Search for the specified program and identify if it refers to a DOS, * Windows 3.X, or Win32 program. Used to determine how to invoke * a program, or if it can even be invoked. * * It is possible to almost positively identify DOS and Windows * applications that contain the appropriate magic numbers. However, * DOS .com files do not seem to contain a magic number; if the program * name ends with .com and could not be identified as a Windows .com * file, it will be assumed to be a DOS application, even if it was * just random data. If the program name does not end with .com, no * such assumption is made. * * The Win32 procedure GetBinaryType incorrectly identifies any * junk file that ends with .exe as a dos executable and some * executables that don't end with .exe as not executable. Plus it * doesn't exist under win95, so I won't feel bad about reimplementing * functionality. * * Results: * The return value is one of APPL_DOS, APPL_WIN3X, or APPL_WIN32 * if the filename referred to the corresponding application type. * If the file name could not be found or did not refer to any known * application type, APPL_NONE is returned and an error message is * left in interp. .bat files are identified as APPL_DOS. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int ApplicationType(interp, originalName, fullName) Tcl_Interp *interp; /* Interp, for error message. */ const char *originalName; /* Name of the application to find. */ char fullName[]; /* Filled with complete path to * application. */ { int applType, i, nameLen, found; HANDLE hFile; TCHAR *rest; char *ext; char buf[2]; DWORD attr, read; IMAGE_DOS_HEADER header; Tcl_DString nameBuf, ds; CONST TCHAR *nativeName; WCHAR nativeFullPath[MAX_PATH]; static const char extensions[][5] = {"", ".com", ".exe", ".bat"}; /* Look for the program as an external program. First try the name * as it is, then try adding .com, .exe, and .bat, in that order, to * the name, looking for an executable. * * Using the raw SearchPath() procedure doesn't do quite what is * necessary. If the name of the executable already contains a '.' * character, it will not try appending the specified extension when * searching (in other words, SearchPath will not find the program * "a.b.exe" if the arguments specified "a.b" and ".exe"). * So, first look for the file as it is named. Then manually append * the extensions, looking for a match. */ applType = APPL_NONE; Tcl_DStringInit(&nameBuf); Tcl_DStringAppend(&nameBuf, originalName, -1); nameLen = Tcl_DStringLength(&nameBuf); for (i = 0; i < (int) (sizeof(extensions) / sizeof(extensions[0])); i++) { Tcl_DStringSetLength(&nameBuf, nameLen); Tcl_DStringAppend(&nameBuf, extensions[i], -1); nativeName = Tcl_WinUtfToTChar(Tcl_DStringValue(&nameBuf), Tcl_DStringLength(&nameBuf), &ds); found = (*tclWinProcs->searchPathProc)(NULL, nativeName, NULL, MAX_PATH, nativeFullPath, &rest); Tcl_DStringFree(&ds); if (found == 0) { continue; } /* * Ignore matches on directories or data files, return if identified * a known type. */ attr = (*tclWinProcs->getFileAttributesProc)((TCHAR *) nativeFullPath); if ((attr == 0xffffffff) || (attr & FILE_ATTRIBUTE_DIRECTORY)) { continue; } strcpy(fullName, Tcl_WinTCharToUtf((TCHAR *) nativeFullPath, -1, &ds)); Tcl_DStringFree(&ds); ext = strrchr(fullName, '.'); if ((ext != NULL) && (stricmp(ext, ".bat") == 0)) { applType = APPL_DOS; break; } hFile = (*tclWinProcs->createFileProc)((TCHAR *) nativeFullPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { continue; } header.e_magic = 0; ReadFile(hFile, (void *) &header, sizeof(header), &read, NULL); if (header.e_magic != IMAGE_DOS_SIGNATURE) { /* * Doesn't have the magic number for relocatable executables. If * filename ends with .com, assume it's a DOS application anyhow. * Note that we didn't make this assumption at first, because some * supposed .com files are really 32-bit executables with all the * magic numbers and everything. */ CloseHandle(hFile); if ((ext != NULL) && (stricmp(ext, ".com") == 0)) { applType = APPL_DOS; break; } continue; } if (header.e_lfarlc != sizeof(header)) { /* * All Windows 3.X and Win32 and some DOS programs have this value * set here. If it doesn't, assume that since it already had the * other magic number it was a DOS application. */ CloseHandle(hFile); applType = APPL_DOS; break; } /* * The DWORD at header.e_lfanew points to yet another magic number. */ buf[0] = '\0'; SetFilePointer(hFile, header.e_lfanew, NULL, FILE_BEGIN); ReadFile(hFile, (void *) buf, 2, &read, NULL); CloseHandle(hFile); if ((buf[0] == 'N') && (buf[1] == 'E')) { applType = APPL_WIN3X; } else if ((buf[0] == 'P') && (buf[1] == 'E')) { applType = APPL_WIN32; } else { /* * Strictly speaking, there should be a test that there * is an 'L' and 'E' at buf[0..1], to identify the type as * DOS, but of course we ran into a DOS executable that * _doesn't_ have the magic number -- specifically, one * compiled using the Lahey Fortran90 compiler. */ applType = APPL_DOS; } break; } Tcl_DStringFree(&nameBuf); if (applType == APPL_NONE) { TclWinConvertError(GetLastError()); Tcl_AppendResult(interp, "couldn't execute \"", originalName, "\": ", Tcl_PosixError(interp), (char *) NULL); return APPL_NONE; } if ((applType == APPL_DOS) || (applType == APPL_WIN3X)) { /* * Replace long path name of executable with short path name for * 16-bit applications. Otherwise the application may not be able * to correctly parse its own command line to separate off the * application name from the arguments. */ (*tclWinProcs->getShortPathNameProc)((TCHAR *) nativeFullPath, nativeFullPath, MAX_PATH); strcpy(fullName, Tcl_WinTCharToUtf((TCHAR *) nativeFullPath, -1, &ds)); Tcl_DStringFree(&ds); } return applType; } /* *---------------------------------------------------------------------- * * BuildCommandLine -- * * The command line arguments are stored in linePtr separated * by spaces, in a form that CreateProcess() understands. Special * characters in individual arguments from argv[] must be quoted * when being stored in cmdLine. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void BuildCommandLine( CONST char *executable, /* Full path of executable (including * extension). Replacement for argv[0]. */ int argc, /* Number of arguments. */ CONST char **argv, /* Argument strings in UTF. */ Tcl_DString *linePtr) /* Initialized Tcl_DString that receives the * command line (TCHAR). */ { CONST char *arg, *start, *special; int quote, i; Tcl_DString ds; Tcl_DStringInit(&ds); /* * Prime the path. Add a space separator if we were primed with * something. */ Tcl_DStringAppend(&ds, Tcl_DStringValue(linePtr), -1); if (Tcl_DStringLength(&ds) > 0) Tcl_DStringAppend(&ds, " ", 1); for (i = 0; i < argc; i++) { if (i == 0) { arg = executable; } else { arg = argv[i]; Tcl_DStringAppend(&ds, " ", 1); } quote = 0; if (arg[0] == '\0') { quote = 1; } else { int count; Tcl_UniChar ch; for (start = arg; *start != '\0'; start += count) { count = Tcl_UtfToUniChar(start, &ch); if (Tcl_UniCharIsSpace(ch)) { /* INTL: ISO space. */ quote = 1; break; } } } if (quote) { Tcl_DStringAppend(&ds, "\"", 1); } start = arg; for (special = arg; ; ) { if ((*special == '\\') && (special[1] == '\\' || special[1] == '"' || (quote && special[1] == '\0'))) { Tcl_DStringAppend(&ds, start, (int) (special - start)); start = special; while (1) { special++; if (*special == '"' || (quote && *special == '\0')) { /* * N backslashes followed a quote -> insert * N * 2 + 1 backslashes then a quote. */ Tcl_DStringAppend(&ds, start, (int) (special - start)); break; } if (*special != '\\') { break; } } Tcl_DStringAppend(&ds, start, (int) (special - start)); start = special; } if (*special == '"') { Tcl_DStringAppend(&ds, start, (int) (special - start)); Tcl_DStringAppend(&ds, "\\\"", 2); start = special + 1; } if (*special == '\0') { break; } special++; } Tcl_DStringAppend(&ds, start, (int) (special - start)); if (quote) { Tcl_DStringAppend(&ds, "\"", 1); } } Tcl_DStringFree(linePtr); Tcl_WinUtfToTChar(Tcl_DStringValue(&ds), Tcl_DStringLength(&ds), linePtr); Tcl_DStringFree(&ds); } /* *---------------------------------------------------------------------- * * TclpCreateCommandChannel -- * * This function is called by Tcl_OpenCommandChannel to perform * the platform specific channel initialization for a command * channel. * * Results: * Returns a new channel or NULL on failure. * * Side effects: * Allocates a new channel. * *---------------------------------------------------------------------- */ Tcl_Channel TclpCreateCommandChannel( TclFile readFile, /* If non-null, gives the file for reading. */ TclFile writeFile, /* If non-null, gives the file for writing. */ TclFile errorFile, /* If non-null, gives the file where errors * can be read. */ int numPids, /* The number of pids in the pid array. */ Tcl_Pid *pidPtr) /* An array of process identifiers. */ { char channelName[16 + TCL_INTEGER_SPACE]; DWORD id; PipeInfo *infoPtr = (PipeInfo *) ckalloc((unsigned) sizeof(PipeInfo)); PipeInit(); infoPtr->watchMask = 0; infoPtr->flags = 0; infoPtr->readFlags = 0; infoPtr->readFile = readFile; infoPtr->writeFile = writeFile; infoPtr->errorFile = errorFile; infoPtr->numPids = numPids; infoPtr->pidPtr = pidPtr; infoPtr->writeBuf = 0; infoPtr->writeBufLen = 0; infoPtr->writeError = 0; infoPtr->channel = (Tcl_Channel) NULL; infoPtr->validMask = 0; infoPtr->threadId = Tcl_GetCurrentThread(); if (readFile != NULL) { /* * Start the background reader thread. */ infoPtr->readable = CreateEvent(NULL, TRUE, TRUE, NULL); infoPtr->startReader = CreateEvent(NULL, FALSE, FALSE, NULL); infoPtr->stopReader = CreateEvent(NULL, TRUE, FALSE, NULL); infoPtr->readThread = CreateThread(NULL, 256, PipeReaderThread, infoPtr, 0, &id); SetThreadPriority(infoPtr->readThread, THREAD_PRIORITY_HIGHEST); infoPtr->validMask |= TCL_READABLE; } else { infoPtr->readThread = 0; } if (writeFile != NULL) { /* * Start the background writer thread. */ infoPtr->writable = CreateEvent(NULL, TRUE, TRUE, NULL); infoPtr->startWriter = CreateEvent(NULL, FALSE, FALSE, NULL); infoPtr->stopWriter = CreateEvent(NULL, TRUE, FALSE, NULL); infoPtr->writeThread = CreateThread(NULL, 256, PipeWriterThread, infoPtr, 0, &id); SetThreadPriority(infoPtr->readThread, THREAD_PRIORITY_HIGHEST); infoPtr->validMask |= TCL_WRITABLE; } /* * For backward compatibility with previous versions of Tcl, we * use "file%d" as the base name for pipes even though it would * be more natural to use "pipe%d". * Use the pointer to keep the channel names unique, in case * channels share handles (stdin/stdout). */ wsprintfA(channelName, "file%lx", infoPtr); infoPtr->channel = Tcl_CreateChannel(&pipeChannelType, channelName, (ClientData) infoPtr, infoPtr->validMask); /* * Pipes have AUTO translation mode on Windows and ^Z eof char, which * means that a ^Z will be appended to them at close. This is needed * for Windows programs that expect a ^Z at EOF. */ Tcl_SetChannelOption((Tcl_Interp *) NULL, infoPtr->channel, "-translation", "auto"); Tcl_SetChannelOption((Tcl_Interp *) NULL, infoPtr->channel, "-eofchar", "\032 {}"); return infoPtr->channel; } /* *---------------------------------------------------------------------- * * TclGetAndDetachPids -- * * Stores a list of the command PIDs for a command channel in * the interp's result. * * Results: * None. * * Side effects: * Modifies the interp's result. * *---------------------------------------------------------------------- */ void TclGetAndDetachPids( Tcl_Interp *interp, Tcl_Channel chan) { PipeInfo *pipePtr; Tcl_ChannelType *chanTypePtr; int i; char buf[TCL_INTEGER_SPACE]; /* * Punt if the channel is not a command channel. */ chanTypePtr = Tcl_GetChannelType(chan); if (chanTypePtr != &pipeChannelType) { return; } pipePtr = (PipeInfo *) Tcl_GetChannelInstanceData(chan); for (i = 0; i < pipePtr->numPids; i++) { wsprintfA(buf, "%lu", TclpGetPid(pipePtr->pidPtr[i])); Tcl_AppendElement(interp, buf); Tcl_DetachPids(1, &(pipePtr->pidPtr[i])); } if (pipePtr->numPids > 0) { ckfree((char *) pipePtr->pidPtr); pipePtr->numPids = 0; } } /* *---------------------------------------------------------------------- * * PipeBlockModeProc -- * * Set blocking or non-blocking mode on channel. * * Results: * 0 if successful, errno when failed. * * Side effects: * Sets the device into blocking or non-blocking mode. * *---------------------------------------------------------------------- */ static int PipeBlockModeProc( ClientData instanceData, /* Instance data for channel. */ int mode) /* TCL_MODE_BLOCKING or * TCL_MODE_NONBLOCKING. */ { PipeInfo *infoPtr = (PipeInfo *) instanceData; /* * Pipes on Windows can not be switched between blocking and nonblocking, * hence we have to emulate the behavior. This is done in the input * function by checking against a bit in the state. We set or unset the * bit here to cause the input function to emulate the correct behavior. */ if (mode == TCL_MODE_NONBLOCKING) { infoPtr->flags |= PIPE_ASYNC; } else { infoPtr->flags &= ~(PIPE_ASYNC); } return 0; } /* *---------------------------------------------------------------------- * * PipeClose2Proc -- * * Closes a pipe based IO channel. * * Results: * 0 on success, errno otherwise. * * Side effects: * Closes the physical channel. * *---------------------------------------------------------------------- */ static int PipeClose2Proc( ClientData instanceData, /* Pointer to PipeInfo structure. */ Tcl_Interp *interp, /* For error reporting. */ int flags) /* Flags that indicate which side to close. */ { PipeInfo *pipePtr = (PipeInfo *) instanceData; Tcl_Channel errChan; int errorCode, result; PipeInfo *infoPtr, **nextPtrPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); DWORD exitCode; errorCode = 0; if ((!flags || (flags == TCL_CLOSE_READ)) && (pipePtr->readFile != NULL)) { /* * Clean up the background thread if necessary. Note that this * must be done before we can close the file, since the * thread may be blocking trying to read from the pipe. */ if (pipePtr->readThread) { /* * The thread may already have closed on it's own. Check it's * exit code. */ GetExitCodeThread(pipePtr->readThread, &exitCode); if (exitCode == STILL_ACTIVE) { /* * Set the stop event so that if the reader thread is blocked * in PipeReaderThread on WaitForMultipleEvents, it will exit * cleanly. */ SetEvent(pipePtr->stopReader); /* * Wait at most 20 milliseconds for the reader thread to close. */ if (WaitForSingleObject(pipePtr->readThread, 20) == WAIT_TIMEOUT) { /* * The thread must be blocked waiting for the pipe to * become readable in ReadFile(). There isn't a clean way * to exit the thread from this condition. We should * terminate the child process instead to get the reader * thread to fall out of ReadFile with a FALSE. (below) is * not the correct way to do this, but will stay here until * a better solution is found. * * Note that we need to guard against terminating the * thread while it is in the middle of Tcl_ThreadAlert * because it won't be able to release the notifier lock. */ Tcl_MutexLock(&pipeMutex); /* BUG: this leaks memory */ TerminateThread(pipePtr->readThread, 0); Tcl_MutexUnlock(&pipeMutex); } } CloseHandle(pipePtr->readThread); CloseHandle(pipePtr->readable); CloseHandle(pipePtr->startReader); CloseHandle(pipePtr->stopReader); pipePtr->readThread = NULL; } if (TclpCloseFile(pipePtr->readFile) != 0) { errorCode = errno; } pipePtr->validMask &= ~TCL_READABLE; pipePtr->readFile = NULL; } if ((!flags || (flags & TCL_CLOSE_WRITE)) && (pipePtr->writeFile != NULL)) { if (pipePtr->writeThread) { /* * Wait for the writer thread to finish the current buffer, * then terminate the thread and close the handles. If the * channel is nonblocking, there should be no pending write * operations. */ WaitForSingleObject(pipePtr->writable, INFINITE); /* * The thread may already have closed on it's own. Check it's * exit code. */ GetExitCodeThread(pipePtr->writeThread, &exitCode); if (exitCode == STILL_ACTIVE) { /* * Set the stop event so that if the reader thread is blocked * in PipeReaderThread on WaitForMultipleEvents, it will exit * cleanly. */ SetEvent(pipePtr->stopWriter); /* * Wait at most 20 milliseconds for the reader thread to close. */ if (WaitForSingleObject(pipePtr->writeThread, 20) == WAIT_TIMEOUT) { /* * The thread must be blocked waiting for the pipe to * consume input in WriteFile(). There isn't a clean way * to exit the thread from this condition. We should * terminate the child process instead to get the writer * thread to fall out of WriteFile with a FALSE. (below) is * not the correct way to do this, but will stay here until * a better solution is found. * * Note that we need to guard against terminating the * thread while it is in the middle of Tcl_ThreadAlert * because it won't be able to release the notifier lock. */ Tcl_MutexLock(&pipeMutex); /* BUG: this leaks memory */ TerminateThread(pipePtr->writeThread, 0); Tcl_MutexUnlock(&pipeMutex); } } CloseHandle(pipePtr->writeThread); CloseHandle(pipePtr->writable); CloseHandle(pipePtr->startWriter); CloseHandle(pipePtr->stopWriter); pipePtr->writeThread = NULL; } if (TclpCloseFile(pipePtr->writeFile) != 0) { if (errorCode == 0) { errorCode = errno; } } pipePtr->validMask &= ~TCL_WRITABLE; pipePtr->writeFile = NULL; } pipePtr->watchMask &= pipePtr->validMask; /* * Don't free the channel if any of the flags were set. */ if (flags) { return errorCode; } /* * Remove the file from the list of watched files. */ for (nextPtrPtr = &(tsdPtr->firstPipePtr), infoPtr = *nextPtrPtr; infoPtr != NULL; nextPtrPtr = &infoPtr->nextPtr, infoPtr = *nextPtrPtr) { if (infoPtr == (PipeInfo *)pipePtr) { *nextPtrPtr = infoPtr->nextPtr; break; } } if ((pipePtr->flags & PIPE_ASYNC) || TclInExit()) { /* * If the channel is non-blocking or Tcl is being cleaned up, * just detach the children PIDs, reap them (important if we are * in a dynamic load module), and discard the errorFile. */ Tcl_DetachPids(pipePtr->numPids, pipePtr->pidPtr); Tcl_ReapDetachedProcs(); if (pipePtr->errorFile) { if (TclpCloseFile(pipePtr->errorFile) != 0) { if ( errorCode == 0 ) { errorCode = errno; } } } result = 0; } else { /* * Wrap the error file into a channel and give it to the cleanup * routine. */ if (pipePtr->errorFile) { WinFile *filePtr; filePtr = (WinFile*)pipePtr->errorFile; errChan = Tcl_MakeFileChannel((ClientData) filePtr->handle, TCL_READABLE); ckfree((char *) filePtr); } else { errChan = NULL; } result = TclCleanupChildren(interp, pipePtr->numPids, pipePtr->pidPtr, errChan); } if (pipePtr->numPids > 0) { ckfree((char *) pipePtr->pidPtr); } if (pipePtr->writeBuf != NULL) { ckfree(pipePtr->writeBuf); } ckfree((char*) pipePtr); if (errorCode == 0) { return result; } return errorCode; } /* *---------------------------------------------------------------------- * * PipeInputProc -- * * Reads input from the IO channel into the buffer given. Returns * count of how many bytes were actually read, and an error indication. * * Results: * A count of how many bytes were read is returned and an error * indication is returned in an output argument. * * Side effects: * Reads input from the actual channel. * *---------------------------------------------------------------------- */ static int PipeInputProc( ClientData instanceData, /* Pipe state. */ char *buf, /* Where to store data read. */ int bufSize, /* How much space is available * in the buffer? */ int *errorCode) /* Where to store error code. */ { PipeInfo *infoPtr = (PipeInfo *) instanceData; WinFile *filePtr = (WinFile*) infoPtr->readFile; DWORD count, bytesRead = 0; int result; *errorCode = 0; /* * Synchronize with the reader thread. */ result = WaitForRead(infoPtr, (infoPtr->flags & PIPE_ASYNC) ? 0 : 1); /* * If an error occurred, return immediately. */ if (result == -1) { *errorCode = errno; return -1; } if (infoPtr->readFlags & PIPE_EXTRABYTE) { /* * The reader thread consumed 1 byte as a side effect of * waiting so we need to move it into the buffer. */ *buf = infoPtr->extraByte; infoPtr->readFlags &= ~PIPE_EXTRABYTE; buf++; bufSize--; bytesRead = 1; /* * If further read attempts would block, return what we have. */ if (result == 0) { return bytesRead; } } /* * Attempt to read bufSize bytes. The read will return immediately * if there is any data available. Otherwise it will block until * at least one byte is available or an EOF occurs. */ if (ReadFile(filePtr->handle, (LPVOID) buf, (DWORD) bufSize, &count, (LPOVERLAPPED) NULL) == TRUE) { return bytesRead + count; } else if (bytesRead) { /* * Ignore errors if we have data to return. */ return bytesRead; } TclWinConvertError(GetLastError()); if (errno == EPIPE) { infoPtr->readFlags |= PIPE_EOF; return 0; } *errorCode = errno; return -1; } /* *---------------------------------------------------------------------- * * PipeOutputProc -- * * Writes the given output on the IO channel. Returns count of how * many characters were actually written, and an error indication. * * Results: * A count of how many characters were written is returned and an * error indication is returned in an output argument. * * Side effects: * Writes output on the actual channel. * *---------------------------------------------------------------------- */ static int PipeOutputProc( ClientData instanceData, /* Pipe state. */ CONST char *buf, /* The data buffer. */ int toWrite, /* How many bytes to write? */ int *errorCode) /* Where to store error code. */ { PipeInfo *infoPtr = (PipeInfo *) instanceData; WinFile *filePtr = (WinFile*) infoPtr->writeFile; DWORD bytesWritten, timeout; *errorCode = 0; timeout = (infoPtr->flags & PIPE_ASYNC) ? 0 : INFINITE; if (WaitForSingleObject(infoPtr->writable, timeout) == WAIT_TIMEOUT) { /* * The writer thread is blocked waiting for a write to complete * and the channel is in non-blocking mode. */ errno = EAGAIN; goto error; } /* * Check for a background error on the last write. */ if (infoPtr->writeError) { TclWinConvertError(infoPtr->writeError); infoPtr->writeError = 0; goto error; } if (infoPtr->flags & PIPE_ASYNC) { /* * The pipe is non-blocking, so copy the data into the output * buffer and restart the writer thread. */ if (toWrite > infoPtr->writeBufLen) { /* * Reallocate the buffer to be large enough to hold the data. */ if (infoPtr->writeBuf) { ckfree(infoPtr->writeBuf); } infoPtr->writeBufLen = toWrite; infoPtr->writeBuf = ckalloc((unsigned int) toWrite); } memcpy(infoPtr->writeBuf, buf, (size_t) toWrite); infoPtr->toWrite = toWrite; ResetEvent(infoPtr->writable); SetEvent(infoPtr->startWriter); bytesWritten = toWrite; } else { /* * In the blocking case, just try to write the buffer directly. * This avoids an unnecessary copy. */ if (WriteFile(filePtr->handle, (LPVOID) buf, (DWORD) toWrite, &bytesWritten, (LPOVERLAPPED) NULL) == FALSE) { TclWinConvertError(GetLastError()); goto error; } } return bytesWritten; error: *errorCode = errno; return -1; } /* *---------------------------------------------------------------------- * * PipeEventProc -- * * This function is invoked by Tcl_ServiceEvent when a file event * reaches the front of the event queue. This procedure invokes * Tcl_NotifyChannel on the pipe. * * Results: * Returns 1 if the event was handled, meaning it should be removed * from the queue. Returns 0 if the event was not handled, meaning * it should stay on the queue. The only time the event isn't * handled is if the TCL_FILE_EVENTS flag bit isn't set. * * Side effects: * Whatever the notifier callback does. * *---------------------------------------------------------------------- */ static int PipeEventProc( Tcl_Event *evPtr, /* Event to service. */ int flags) /* Flags that indicate what events to * handle, such as TCL_FILE_EVENTS. */ { PipeEvent *pipeEvPtr = (PipeEvent *)evPtr; PipeInfo *infoPtr; int mask; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (!(flags & TCL_FILE_EVENTS)) { return 0; } /* * Search through the list of watched pipes for the one whose handle * matches the event. We do this rather than simply dereferencing * the handle in the event so that pipes can be deleted while the * event is in the queue. */ for (infoPtr = tsdPtr->firstPipePtr; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { if (pipeEvPtr->infoPtr == infoPtr) { infoPtr->flags &= ~(PIPE_PENDING); break; } } /* * Remove stale events. */ if (!infoPtr) { return 1; } /* * Check to see if the pipe is readable. Note * that we can't tell if a pipe is writable, so we always report it * as being writable unless we have detected EOF. */ mask = 0; if ((infoPtr->watchMask & TCL_WRITABLE) && (WaitForSingleObject(infoPtr->writable, 0) != WAIT_TIMEOUT)) { mask = TCL_WRITABLE; } if ((infoPtr->watchMask & TCL_READABLE) && (WaitForRead(infoPtr, 0) >= 0)) { if (infoPtr->readFlags & PIPE_EOF) { mask = TCL_READABLE; } else { mask |= TCL_READABLE; } } /* * Inform the channel of the events. */ Tcl_NotifyChannel(infoPtr->channel, infoPtr->watchMask & mask); return 1; } /* *---------------------------------------------------------------------- * * PipeWatchProc -- * * Called by the notifier to set up to watch for events on this * channel. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void PipeWatchProc( ClientData instanceData, /* Pipe state. */ int mask) /* What events to watch for, OR-ed * combination of TCL_READABLE, * TCL_WRITABLE and TCL_EXCEPTION. */ { PipeInfo **nextPtrPtr, *ptr; PipeInfo *infoPtr = (PipeInfo *) instanceData; int oldMask = infoPtr->watchMask; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); /* * Since most of the work is handled by the background threads, * we just need to update the watchMask and then force the notifier * to poll once. */ infoPtr->watchMask = mask & infoPtr->validMask; if (infoPtr->watchMask) { Tcl_Time blockTime = { 0, 0 }; if (!oldMask) { infoPtr->nextPtr = tsdPtr->firstPipePtr; tsdPtr->firstPipePtr = infoPtr; } Tcl_SetMaxBlockTime(&blockTime); } else { if (oldMask) { /* * Remove the pipe from the list of watched pipes. */ for (nextPtrPtr = &(tsdPtr->firstPipePtr), ptr = *nextPtrPtr; ptr != NULL; nextPtrPtr = &ptr->nextPtr, ptr = *nextPtrPtr) { if (infoPtr == ptr) { *nextPtrPtr = ptr->nextPtr; break; } } } } } /* *---------------------------------------------------------------------- * * PipeGetHandleProc -- * * Called from Tcl_GetChannelHandle to retrieve OS handles from * inside a command pipeline based channel. * * Results: * Returns TCL_OK with the fd in handlePtr, or TCL_ERROR if * there is no handle for the specified direction. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int PipeGetHandleProc( ClientData instanceData, /* The pipe state. */ int direction, /* TCL_READABLE or TCL_WRITABLE */ ClientData *handlePtr) /* Where to store the handle. */ { PipeInfo *infoPtr = (PipeInfo *) instanceData; WinFile *filePtr; if (direction == TCL_READABLE && infoPtr->readFile) { filePtr = (WinFile*) infoPtr->readFile; *handlePtr = (ClientData) filePtr->handle; return TCL_OK; } if (direction == TCL_WRITABLE && infoPtr->writeFile) { filePtr = (WinFile*) infoPtr->writeFile; *handlePtr = (ClientData) filePtr->handle; return TCL_OK; } return TCL_ERROR; } /* *---------------------------------------------------------------------- * * Tcl_WaitPid -- * * Emulates the waitpid system call. * * Results: * Returns 0 if the process is still alive, -1 on an error, or * the pid on a clean close. * * Side effects: * Unless WNOHANG is set and the wait times out, the process * information record will be deleted and the process handle * will be closed. * *---------------------------------------------------------------------- */ Tcl_Pid Tcl_WaitPid( Tcl_Pid pid, int *statPtr, int options) { ProcInfo *infoPtr = NULL, **prevPtrPtr; DWORD flags; Tcl_Pid result; DWORD ret, exitCode; PipeInit(); /* * If no pid is specified, do nothing. */ if (pid == 0) { *statPtr = 0; return 0; } /* * Find the process and cut it from the process list. * SF Tcl Bug 859820, Backport of its fix. * SF Tcl Bug 1381436, asking for the backport. * * [x] Cutting the infoPtr after the closehandle allows the * pointer to become stale. We do it here, and compensate if the * process was not done yet. */ Tcl_MutexLock(&pipeMutex); prevPtrPtr = &procList; for (infoPtr = procList; infoPtr != NULL; prevPtrPtr = &infoPtr->nextPtr, infoPtr = infoPtr->nextPtr) { if (infoPtr->hProcess == (HANDLE) pid) { *prevPtrPtr = infoPtr->nextPtr; break; } } Tcl_MutexUnlock(&pipeMutex); /* * If the pid is not one of the processes we know about (we started it) * then do nothing. */ if (infoPtr == NULL) { *statPtr = 0; return 0; } /* * Officially "wait" for it to finish. We either poll (WNOHANG) or * wait for an infinite amount of time. */ if (options & WNOHANG) { flags = 0; } else { flags = INFINITE; } ret = WaitForSingleObject(infoPtr->hProcess, flags); if (ret == WAIT_TIMEOUT) { *statPtr = 0; if (options & WNOHANG) { /* * Re-insert the cut infoPtr back on the list. * See [x] for explanation. */ Tcl_MutexLock(&pipeMutex); infoPtr->nextPtr = procList; procList = infoPtr; Tcl_MutexUnlock(&pipeMutex); return 0; } else { result = 0; } } else if (ret == WAIT_OBJECT_0) { GetExitCodeProcess(infoPtr->hProcess, &exitCode); if (exitCode & 0xC0000000) { /* * A fatal exception occured. */ switch (exitCode) { case EXCEPTION_FLT_DENORMAL_OPERAND: case EXCEPTION_FLT_DIVIDE_BY_ZERO: case EXCEPTION_FLT_INEXACT_RESULT: case EXCEPTION_FLT_INVALID_OPERATION: case EXCEPTION_FLT_OVERFLOW: case EXCEPTION_FLT_STACK_CHECK: case EXCEPTION_FLT_UNDERFLOW: case EXCEPTION_INT_DIVIDE_BY_ZERO: case EXCEPTION_INT_OVERFLOW: *statPtr = 0xC0000000 | SIGFPE; break; case EXCEPTION_PRIV_INSTRUCTION: case EXCEPTION_ILLEGAL_INSTRUCTION: *statPtr = 0xC0000000 | SIGILL; break; case EXCEPTION_ACCESS_VIOLATION: case EXCEPTION_DATATYPE_MISALIGNMENT: case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: case EXCEPTION_STACK_OVERFLOW: case EXCEPTION_NONCONTINUABLE_EXCEPTION: case EXCEPTION_INVALID_DISPOSITION: case EXCEPTION_GUARD_PAGE: case EXCEPTION_INVALID_HANDLE: *statPtr = 0xC0000000 | SIGSEGV; break; case CONTROL_C_EXIT: *statPtr = 0xC0000000 | SIGINT; break; default: *statPtr = 0xC0000000 | SIGABRT; break; } } else { *statPtr = exitCode; } result = pid; } else { errno = ECHILD; *statPtr = 0xC0000000 | ECHILD; result = (Tcl_Pid) -1; } /* * Officially close the process handle. */ CloseHandle(infoPtr->hProcess); ckfree((char*)infoPtr); return result; } /* *---------------------------------------------------------------------- * * TclWinAddProcess -- * * Add a process to the process list so that we can use * Tcl_WaitPid on the process. * * Results: * None * * Side effects: * Adds the specified process handle to the process list so * Tcl_WaitPid knows about it. * *---------------------------------------------------------------------- */ void TclWinAddProcess(hProcess, id) HANDLE hProcess; /* Handle to process */ DWORD id; /* Global process identifier */ { ProcInfo *procPtr = (ProcInfo *) ckalloc(sizeof(ProcInfo)); PipeInit(); procPtr->hProcess = hProcess; procPtr->dwProcessId = id; Tcl_MutexLock(&pipeMutex); procPtr->nextPtr = procList; procList = procPtr; Tcl_MutexUnlock(&pipeMutex); } /* *---------------------------------------------------------------------- * * Tcl_PidObjCmd -- * * This procedure is invoked to process the "pid" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ int Tcl_PidObjCmd( ClientData dummy, /* Not used. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST *objv) /* Argument strings. */ { Tcl_Channel chan; Tcl_ChannelType *chanTypePtr; PipeInfo *pipePtr; int i; Tcl_Obj *resultPtr; char buf[TCL_INTEGER_SPACE]; if (objc > 2) { Tcl_WrongNumArgs(interp, 1, objv, "?channelId?"); return TCL_ERROR; } if (objc == 1) { resultPtr = Tcl_GetObjResult(interp); wsprintfA(buf, "%lu", (unsigned long) getpid()); Tcl_SetStringObj(resultPtr, buf, -1); } else { chan = Tcl_GetChannel(interp, Tcl_GetStringFromObj(objv[1], NULL), NULL); if (chan == (Tcl_Channel) NULL) { return TCL_ERROR; } chanTypePtr = Tcl_GetChannelType(chan); if (chanTypePtr != &pipeChannelType) { return TCL_OK; } pipePtr = (PipeInfo *) Tcl_GetChannelInstanceData(chan); resultPtr = Tcl_GetObjResult(interp); for (i = 0; i < pipePtr->numPids; i++) { wsprintfA(buf, "%lu", TclpGetPid(pipePtr->pidPtr[i])); Tcl_ListObjAppendElement(/*interp*/ NULL, resultPtr, Tcl_NewStringObj(buf, -1)); } } return TCL_OK; } /* *---------------------------------------------------------------------- * * WaitForRead -- * * Wait until some data is available, the pipe is at * EOF or the reader thread is blocked waiting for data (if the * channel is in non-blocking mode). * * Results: * Returns 1 if pipe is readable. Returns 0 if there is no data * on the pipe, but there is buffered data. Returns -1 if an * error occurred. If an error occurred, the threads may not * be synchronized. * * Side effects: * Updates the shared state flags and may consume 1 byte of data * from the pipe. If no error occurred, the reader thread is * blocked waiting for a signal from the main thread. * *---------------------------------------------------------------------- */ static int WaitForRead( PipeInfo *infoPtr, /* Pipe state. */ int blocking) /* Indicates whether call should be * blocking or not. */ { DWORD timeout, count; HANDLE *handle = ((WinFile *) infoPtr->readFile)->handle; while (1) { /* * Synchronize with the reader thread. */ timeout = blocking ? INFINITE : 0; if (WaitForSingleObject(infoPtr->readable, timeout) == WAIT_TIMEOUT) { /* * The reader thread is blocked waiting for data and the channel * is in non-blocking mode. */ errno = EAGAIN; return -1; } /* * At this point, the two threads are synchronized, so it is safe * to access shared state. */ /* * If the pipe has hit EOF, it is always readable. */ if (infoPtr->readFlags & PIPE_EOF) { return 1; } /* * Check to see if there is any data sitting in the pipe. */ if (PeekNamedPipe(handle, (LPVOID) NULL, (DWORD) 0, (LPDWORD) NULL, &count, (LPDWORD) NULL) != TRUE) { TclWinConvertError(GetLastError()); /* * Check to see if the peek failed because of EOF. */ if (errno == EPIPE) { infoPtr->readFlags |= PIPE_EOF; return 1; } /* * Ignore errors if there is data in the buffer. */ if (infoPtr->readFlags & PIPE_EXTRABYTE) { return 0; } else { return -1; } } /* * We found some data in the pipe, so it must be readable. */ if (count > 0) { return 1; } /* * The pipe isn't readable, but there is some data sitting * in the buffer, so return immediately. */ if (infoPtr->readFlags & PIPE_EXTRABYTE) { return 0; } /* * There wasn't any data available, so reset the thread and * try again. */ ResetEvent(infoPtr->readable); SetEvent(infoPtr->startReader); } } /* *---------------------------------------------------------------------- * * PipeReaderThread -- * * This function runs in a separate thread and waits for input * to become available on a pipe. * * Results: * None. * * Side effects: * Signals the main thread when input become available. May * cause the main thread to wake up by posting a message. May * consume one byte from the pipe for each wait operation. Will * cause a memory leak of ~4k, if forcefully terminated with * TerminateThread(). * *---------------------------------------------------------------------- */ static DWORD WINAPI PipeReaderThread(LPVOID arg) { PipeInfo *infoPtr = (PipeInfo *)arg; HANDLE *handle = ((WinFile *) infoPtr->readFile)->handle; DWORD count, err; int done = 0; HANDLE wEvents[2]; DWORD waitResult; wEvents[0] = infoPtr->stopReader; wEvents[1] = infoPtr->startReader; while (!done) { /* * Wait for the main thread to signal before attempting to wait * on the pipe becoming readable. */ waitResult = WaitForMultipleObjects(2, wEvents, FALSE, INFINITE); if (waitResult != (WAIT_OBJECT_0 + 1)) { /* * The start event was not signaled. It might be the stop event * or an error, so exit. */ break; } /* * Try waiting for 0 bytes. This will block until some data is * available on NT, but will return immediately on Win 95. So, * if no data is available after the first read, we block until * we can read a single byte off of the pipe. */ if ((ReadFile(handle, NULL, 0, &count, NULL) == FALSE) || (PeekNamedPipe(handle, NULL, 0, NULL, &count, NULL) == FALSE)) { /* * The error is a result of an EOF condition, so set the * EOF bit before signalling the main thread. */ err = GetLastError(); if (err == ERROR_BROKEN_PIPE) { infoPtr->readFlags |= PIPE_EOF; done = 1; } else if (err == ERROR_INVALID_HANDLE) { break; } } else if (count == 0) { if (ReadFile(handle, &(infoPtr->extraByte), 1, &count, NULL) != FALSE) { /* * One byte was consumed as a side effect of waiting * for the pipe to become readable. */ infoPtr->readFlags |= PIPE_EXTRABYTE; } else { err = GetLastError(); if (err == ERROR_BROKEN_PIPE) { /* * The error is a result of an EOF condition, so set the * EOF bit before signalling the main thread. */ infoPtr->readFlags |= PIPE_EOF; done = 1; } else if (err == ERROR_INVALID_HANDLE) { break; } } } /* * Signal the main thread by signalling the readable event and * then waking up the notifier thread. */ SetEvent(infoPtr->readable); /* * Alert the foreground thread. Note that we need to treat this like * a critical section so the foreground thread does not terminate * this thread while we are holding a mutex in the notifier code. */ Tcl_MutexLock(&pipeMutex); if (infoPtr->threadId != NULL) { /* TIP #218. When in flight ignore the event, no one will receive it anyway */ Tcl_ThreadAlert(infoPtr->threadId); } Tcl_MutexUnlock(&pipeMutex); } return 0; } /* *---------------------------------------------------------------------- * * PipeWriterThread -- * * This function runs in a separate thread and writes data * onto a pipe. * * Results: * Always returns 0. * * Side effects: * Signals the main thread when an output operation is completed. * May cause the main thread to wake up by posting a message. * *---------------------------------------------------------------------- */ static DWORD WINAPI PipeWriterThread(LPVOID arg) { PipeInfo *infoPtr = (PipeInfo *)arg; HANDLE *handle = ((WinFile *) infoPtr->writeFile)->handle; DWORD count, toWrite; char *buf; int done = 0; HANDLE wEvents[2]; DWORD waitResult; wEvents[0] = infoPtr->stopWriter; wEvents[1] = infoPtr->startWriter; while (!done) { /* * Wait for the main thread to signal before attempting to write. */ waitResult = WaitForMultipleObjects(2, wEvents, FALSE, INFINITE); if (waitResult != (WAIT_OBJECT_0 + 1)) { /* * The start event was not signaled. It might be the stop event * or an error, so exit. */ break; } buf = infoPtr->writeBuf; toWrite = infoPtr->toWrite; /* * Loop until all of the bytes are written or an error occurs. */ while (toWrite > 0) { if (WriteFile(handle, buf, toWrite, &count, NULL) == FALSE) { infoPtr->writeError = GetLastError(); done = 1; break; } else { toWrite -= count; buf += count; } } /* * Signal the main thread by signalling the writable event and * then waking up the notifier thread. */ SetEvent(infoPtr->writable); /* * Alert the foreground thread. Note that we need to treat this like * a critical section so the foreground thread does not terminate * this thread while we are holding a mutex in the notifier code. */ Tcl_MutexLock(&pipeMutex); if (infoPtr->threadId != NULL) { /* TIP #218. When in flight ignore the event, no one will receive it anyway */ Tcl_ThreadAlert(infoPtr->threadId); } Tcl_MutexUnlock(&pipeMutex); } return 0; } /* *---------------------------------------------------------------------- * * PipeThreadActionProc -- * * Insert or remove any thread local refs to this channel. * * Results: * None. * * Side effects: * Changes thread local list of valid channels. * *---------------------------------------------------------------------- */ static void PipeThreadActionProc (instanceData, action) ClientData instanceData; int action; { PipeInfo *infoPtr = (PipeInfo *) instanceData; /* We do not access firstPipePtr in the thread structures. This is * not for all pipes managed by the thread, but only those we are * watching. Removal of the filevent handlers before transfer thus * takes care of this structure. */ Tcl_MutexLock(&pipeMutex); if (action == TCL_CHANNEL_THREAD_INSERT) { /* We can't copy the thread information from the channel when * the channel is created. At this time the channel back * pointer has not been set yet. However in that case the * threadId has already been set by TclpCreateCommandChannel * itself, so the structure is still good. */ PipeInit (); if (infoPtr->channel != NULL) { infoPtr->threadId = Tcl_GetChannelThread (infoPtr->channel); } } else { infoPtr->threadId = NULL; } Tcl_MutexUnlock(&pipeMutex); } tcl8.4.20/win/tcl.dsw0000644003604700454610000000102312153151143012773 0ustar dgp771divMicrosoft Developer Studio Workspace File, Format Version 6.00 # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! ############################################################################### Project: "tcl"=.\tcl.dsp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ }}} ############################################################################### Global: Package=<5> {{{ }}} Package=<3> {{{ }}} ############################################################################### tcl8.4.20/win/tclWinError.c0000644003604700454610000002575112052456744014143 0ustar dgp771div/* * tclWinError.c -- * * This file contains code for converting from Win32 errors to errno * errors. * * Copyright (c) 1995-1996 by Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" /* * The following table contains the mapping from Win32 errors to errno errors. */ static CONST unsigned char errorTable[] = { 0, EINVAL, /* ERROR_INVALID_FUNCTION 1 */ ENOENT, /* ERROR_FILE_NOT_FOUND 2 */ ENOENT, /* ERROR_PATH_NOT_FOUND 3 */ EMFILE, /* ERROR_TOO_MANY_OPEN_FILES 4 */ EACCES, /* ERROR_ACCESS_DENIED 5 */ EBADF, /* ERROR_INVALID_HANDLE 6 */ ENOMEM, /* ERROR_ARENA_TRASHED 7 */ ENOMEM, /* ERROR_NOT_ENOUGH_MEMORY 8 */ ENOMEM, /* ERROR_INVALID_BLOCK 9 */ E2BIG, /* ERROR_BAD_ENVIRONMENT 10 */ ENOEXEC, /* ERROR_BAD_FORMAT 11 */ EACCES, /* ERROR_INVALID_ACCESS 12 */ EINVAL, /* ERROR_INVALID_DATA 13 */ EFAULT, /* ERROR_OUT_OF_MEMORY 14 */ ENOENT, /* ERROR_INVALID_DRIVE 15 */ EACCES, /* ERROR_CURRENT_DIRECTORY 16 */ EXDEV, /* ERROR_NOT_SAME_DEVICE 17 */ ENOENT, /* ERROR_NO_MORE_FILES 18 */ EROFS, /* ERROR_WRITE_PROTECT 19 */ ENXIO, /* ERROR_BAD_UNIT 20 */ EBUSY, /* ERROR_NOT_READY 21 */ EIO, /* ERROR_BAD_COMMAND 22 */ EIO, /* ERROR_CRC 23 */ EIO, /* ERROR_BAD_LENGTH 24 */ EIO, /* ERROR_SEEK 25 */ EIO, /* ERROR_NOT_DOS_DISK 26 */ ENXIO, /* ERROR_SECTOR_NOT_FOUND 27 */ EBUSY, /* ERROR_OUT_OF_PAPER 28 */ EIO, /* ERROR_WRITE_FAULT 29 */ EIO, /* ERROR_READ_FAULT 30 */ EIO, /* ERROR_GEN_FAILURE 31 */ EACCES, /* ERROR_SHARING_VIOLATION 32 */ EACCES, /* ERROR_LOCK_VIOLATION 33 */ ENXIO, /* ERROR_WRONG_DISK 34 */ ENFILE, /* ERROR_FCB_UNAVAILABLE 35 */ ENFILE, /* ERROR_SHARING_BUFFER_EXCEEDED 36 */ EINVAL, /* 37 */ EINVAL, /* 38 */ ENOSPC, /* ERROR_HANDLE_DISK_FULL 39 */ EINVAL, /* 40 */ EINVAL, /* 41 */ EINVAL, /* 42 */ EINVAL, /* 43 */ EINVAL, /* 44 */ EINVAL, /* 45 */ EINVAL, /* 46 */ EINVAL, /* 47 */ EINVAL, /* 48 */ EINVAL, /* 49 */ ENODEV, /* ERROR_NOT_SUPPORTED 50 */ EBUSY, /* ERROR_REM_NOT_LIST 51 */ EEXIST, /* ERROR_DUP_NAME 52 */ ENOENT, /* ERROR_BAD_NETPATH 53 */ EBUSY, /* ERROR_NETWORK_BUSY 54 */ ENODEV, /* ERROR_DEV_NOT_EXIST 55 */ EAGAIN, /* ERROR_TOO_MANY_CMDS 56 */ EIO, /* ERROR_ADAP_HDW_ERR 57 */ EIO, /* ERROR_BAD_NET_RESP 58 */ EIO, /* ERROR_UNEXP_NET_ERR 59 */ EINVAL, /* ERROR_BAD_REM_ADAP 60 */ EFBIG, /* ERROR_PRINTQ_FULL 61 */ ENOSPC, /* ERROR_NO_SPOOL_SPACE 62 */ ENOENT, /* ERROR_PRINT_CANCELLED 63 */ ENOENT, /* ERROR_NETNAME_DELETED 64 */ EACCES, /* ERROR_NETWORK_ACCESS_DENIED 65 */ ENODEV, /* ERROR_BAD_DEV_TYPE 66 */ ENOENT, /* ERROR_BAD_NET_NAME 67 */ ENFILE, /* ERROR_TOO_MANY_NAMES 68 */ EIO, /* ERROR_TOO_MANY_SESS 69 */ EAGAIN, /* ERROR_SHARING_PAUSED 70 */ EINVAL, /* ERROR_REQ_NOT_ACCEP 71 */ EAGAIN, /* ERROR_REDIR_PAUSED 72 */ EINVAL, /* 73 */ EINVAL, /* 74 */ EINVAL, /* 75 */ EINVAL, /* 76 */ EINVAL, /* 77 */ EINVAL, /* 78 */ EINVAL, /* 79 */ EEXIST, /* ERROR_FILE_EXISTS 80 */ EINVAL, /* 81 */ ENOSPC, /* ERROR_CANNOT_MAKE 82 */ EIO, /* ERROR_FAIL_I24 83 */ ENFILE, /* ERROR_OUT_OF_STRUCTURES 84 */ EEXIST, /* ERROR_ALREADY_ASSIGNED 85 */ EPERM, /* ERROR_INVALID_PASSWORD 86 */ EINVAL, /* ERROR_INVALID_PARAMETER 87 */ EIO, /* ERROR_NET_WRITE_FAULT 88 */ EAGAIN, /* ERROR_NO_PROC_SLOTS 89 */ EINVAL, /* 90 */ EINVAL, /* 91 */ EINVAL, /* 92 */ EINVAL, /* 93 */ EINVAL, /* 94 */ EINVAL, /* 95 */ EINVAL, /* 96 */ EINVAL, /* 97 */ EINVAL, /* 98 */ EINVAL, /* 99 */ EINVAL, /* 100 */ EINVAL, /* 101 */ EINVAL, /* 102 */ EINVAL, /* 103 */ EINVAL, /* 104 */ EINVAL, /* 105 */ EINVAL, /* 106 */ EXDEV, /* ERROR_DISK_CHANGE 107 */ EAGAIN, /* ERROR_DRIVE_LOCKED 108 */ EPIPE, /* ERROR_BROKEN_PIPE 109 */ ENOENT, /* ERROR_OPEN_FAILED 110 */ EINVAL, /* ERROR_BUFFER_OVERFLOW 111 */ ENOSPC, /* ERROR_DISK_FULL 112 */ EMFILE, /* ERROR_NO_MORE_SEARCH_HANDLES 113 */ EBADF, /* ERROR_INVALID_TARGET_HANDLE 114 */ EFAULT, /* ERROR_PROTECTION_VIOLATION 115 */ EINVAL, /* 116 */ EINVAL, /* 117 */ EINVAL, /* 118 */ EINVAL, /* 119 */ EINVAL, /* 120 */ EINVAL, /* 121 */ EINVAL, /* 122 */ ENOENT, /* ERROR_INVALID_NAME 123 */ EINVAL, /* 124 */ EINVAL, /* 125 */ EINVAL, /* 126 */ EINVAL, /* ERROR_PROC_NOT_FOUND 127 */ ECHILD, /* ERROR_WAIT_NO_CHILDREN 128 */ ECHILD, /* ERROR_CHILD_NOT_COMPLETE 129 */ EBADF, /* ERROR_DIRECT_ACCESS_HANDLE 130 */ EINVAL, /* ERROR_NEGATIVE_SEEK 131 */ ESPIPE, /* ERROR_SEEK_ON_DEVICE 132 */ EINVAL, /* 133 */ EINVAL, /* 134 */ EINVAL, /* 135 */ EINVAL, /* 136 */ EINVAL, /* 137 */ EINVAL, /* 138 */ EINVAL, /* 139 */ EINVAL, /* 140 */ EINVAL, /* 141 */ EAGAIN, /* ERROR_BUSY_DRIVE 142 */ EINVAL, /* 143 */ EINVAL, /* 144 */ EEXIST, /* ERROR_DIR_NOT_EMPTY 145 */ EINVAL, /* 146 */ EINVAL, /* 147 */ EINVAL, /* 148 */ EINVAL, /* 149 */ EINVAL, /* 150 */ EINVAL, /* 151 */ EINVAL, /* 152 */ EINVAL, /* 153 */ EINVAL, /* 154 */ EINVAL, /* 155 */ EINVAL, /* 156 */ EINVAL, /* 157 */ EACCES, /* ERROR_NOT_LOCKED 158 */ EINVAL, /* 159 */ EINVAL, /* 160 */ ENOENT, /* ERROR_BAD_PATHNAME 161 */ EINVAL, /* 162 */ EINVAL, /* 163 */ EINVAL, /* 164 */ EINVAL, /* 165 */ EINVAL, /* 166 */ EACCES, /* ERROR_LOCK_FAILED 167 */ EINVAL, /* 168 */ EINVAL, /* 169 */ EINVAL, /* 170 */ EINVAL, /* 171 */ EINVAL, /* 172 */ EINVAL, /* 173 */ EINVAL, /* 174 */ EINVAL, /* 175 */ EINVAL, /* 176 */ EINVAL, /* 177 */ EINVAL, /* 178 */ EINVAL, /* 179 */ EINVAL, /* 180 */ EINVAL, /* 181 */ EINVAL, /* 182 */ EEXIST, /* ERROR_ALREADY_EXISTS 183 */ ECHILD, /* ERROR_NO_CHILD_PROCESS 184 */ EINVAL, /* 185 */ EINVAL, /* 186 */ EINVAL, /* 187 */ EINVAL, /* 188 */ EINVAL, /* 189 */ EINVAL, /* 190 */ EINVAL, /* 191 */ EINVAL, /* 192 */ EINVAL, /* 193 */ EINVAL, /* 194 */ EINVAL, /* 195 */ EINVAL, /* 196 */ EINVAL, /* 197 */ EINVAL, /* 198 */ EINVAL, /* 199 */ EINVAL, /* 200 */ EINVAL, /* 201 */ EINVAL, /* 202 */ EINVAL, /* 203 */ EINVAL, /* 204 */ EINVAL, /* 205 */ ENAMETOOLONG,/* ERROR_FILENAME_EXCED_RANGE 206 */ EINVAL, /* 207 */ EINVAL, /* 208 */ EINVAL, /* 209 */ EINVAL, /* 210 */ EINVAL, /* 211 */ EINVAL, /* 212 */ EINVAL, /* 213 */ EINVAL, /* 214 */ EINVAL, /* 215 */ EINVAL, /* 216 */ EINVAL, /* 217 */ EINVAL, /* 218 */ EINVAL, /* 219 */ EINVAL, /* 220 */ EINVAL, /* 221 */ EINVAL, /* 222 */ EINVAL, /* 223 */ EINVAL, /* 224 */ EINVAL, /* 225 */ EINVAL, /* 226 */ EINVAL, /* 227 */ EINVAL, /* 228 */ EINVAL, /* 229 */ EPIPE, /* ERROR_BAD_PIPE 230 */ EAGAIN, /* ERROR_PIPE_BUSY 231 */ EPIPE, /* ERROR_NO_DATA 232 */ EPIPE, /* ERROR_PIPE_NOT_CONNECTED 233 */ EINVAL, /* 234 */ EINVAL, /* 235 */ EINVAL, /* 236 */ EINVAL, /* 237 */ EINVAL, /* 238 */ EINVAL, /* 239 */ EINVAL, /* 240 */ EINVAL, /* 241 */ EINVAL, /* 242 */ EINVAL, /* 243 */ EINVAL, /* 244 */ EINVAL, /* 245 */ EINVAL, /* 246 */ EINVAL, /* 247 */ EINVAL, /* 248 */ EINVAL, /* 249 */ EINVAL, /* 250 */ EINVAL, /* 251 */ EINVAL, /* 252 */ EINVAL, /* 253 */ EINVAL, /* 254 */ EINVAL, /* 255 */ EINVAL, /* 256 */ EINVAL, /* 257 */ EINVAL, /* 258 */ EINVAL, /* 259 */ EINVAL, /* 260 */ EINVAL, /* 261 */ EINVAL, /* 262 */ EINVAL, /* 263 */ EINVAL, /* 264 */ EINVAL, /* 265 */ EINVAL, /* 266 */ ENOTDIR /* ERROR_DIRECTORY 267 */ }; /* * The following table contains the mapping from WinSock errors to * errno errors. */ static CONST int wsaErrorTable[] = { EWOULDBLOCK, /* WSAEWOULDBLOCK */ EINPROGRESS, /* WSAEINPROGRESS */ EALREADY, /* WSAEALREADY */ ENOTSOCK, /* WSAENOTSOCK */ EDESTADDRREQ, /* WSAEDESTADDRREQ */ EMSGSIZE, /* WSAEMSGSIZE */ EPROTOTYPE, /* WSAEPROTOTYPE */ ENOPROTOOPT, /* WSAENOPROTOOPT */ EPROTONOSUPPORT, /* WSAEPROTONOSUPPORT */ ESOCKTNOSUPPORT, /* WSAESOCKTNOSUPPORT */ EOPNOTSUPP, /* WSAEOPNOTSUPP */ EPFNOSUPPORT, /* WSAEPFNOSUPPORT */ EAFNOSUPPORT, /* WSAEAFNOSUPPORT */ EADDRINUSE, /* WSAEADDRINUSE */ EADDRNOTAVAIL, /* WSAEADDRNOTAVAIL */ ENETDOWN, /* WSAENETDOWN */ ENETUNREACH, /* WSAENETUNREACH */ ENETRESET, /* WSAENETRESET */ ECONNABORTED, /* WSAECONNABORTED */ ECONNRESET, /* WSAECONNRESET */ ENOBUFS, /* WSAENOBUFS */ EISCONN, /* WSAEISCONN */ ENOTCONN, /* WSAENOTCONN */ ESHUTDOWN, /* WSAESHUTDOWN */ ETOOMANYREFS, /* WSAETOOMANYREFS */ ETIMEDOUT, /* WSAETIMEDOUT */ ECONNREFUSED, /* WSAECONNREFUSED */ ELOOP, /* WSAELOOP */ ENAMETOOLONG, /* WSAENAMETOOLONG */ EHOSTDOWN, /* WSAEHOSTDOWN */ EHOSTUNREACH, /* WSAEHOSTUNREACH */ ENOTEMPTY, /* WSAENOTEMPTY */ EAGAIN, /* WSAEPROCLIM */ EUSERS, /* WSAEUSERS */ EDQUOT, /* WSAEDQUOT */ ESTALE, /* WSAESTALE */ EREMOTE /* WSAEREMOTE */ }; /* *---------------------------------------------------------------------- * * TclWinConvertError -- * * This routine converts a Win32 error into an errno value. * * Results: * None. * * Side effects: * Sets the errno global variable. * *---------------------------------------------------------------------- */ void TclWinConvertError( DWORD errCode) /* Win32 error code. */ { if (errCode >= sizeof(errorTable)/sizeof(errorTable[0])) { errCode -= WSAEWOULDBLOCK; if (errCode >= sizeof(wsaErrorTable)/sizeof(wsaErrorTable[0])) { Tcl_SetErrno(errorTable[1]); } else { Tcl_SetErrno(wsaErrorTable[errCode]); } } else { Tcl_SetErrno(errorTable[errCode]); } } /* *---------------------------------------------------------------------- * * TclWinConvertWSAError -- * * This routine converts a WinSock error into an errno value. * * Results: * None. * * Side effects: * Sets the errno global variable. * *---------------------------------------------------------------------- */ void TclWinConvertWSAError( DWORD errCode) /* Win32 error code. */ { if (errCode >= sizeof(errorTable)/sizeof(errorTable[0])) { errCode -= WSAEWOULDBLOCK; if (errCode >= sizeof(wsaErrorTable)/sizeof(wsaErrorTable[0])) { Tcl_SetErrno(errorTable[1]); } else { Tcl_SetErrno(wsaErrorTable[errCode]); } } else { Tcl_SetErrno(errorTable[errCode]); } } /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * tab-width: 8 * End: */ tcl8.4.20/win/configure.in0000644003604700454610000002450612153151142014015 0ustar dgp771div#! /bin/bash -norc # This file is an input file used by the GNU "autoconf" program to # generate the file "configure", which is run during Tcl installation # to configure the system for the local environment. AC_INIT(../generic/tcl.h) AC_PREREQ(2.13) TCL_VERSION=8.4 TCL_MAJOR_VERSION=8 TCL_MINOR_VERSION=4 TCL_PATCH_LEVEL=".20" VER=$TCL_MAJOR_VERSION$TCL_MINOR_VERSION TCL_DDE_VERSION=1.3 TCL_DDE_MAJOR_VERSION=1 TCL_DDE_MINOR_VERSION=3 DDEVER=$TCL_DDE_MAJOR_VERSION$TCL_DDE_MINOR_VERSION TCL_REG_VERSION=1.2 TCL_REG_MAJOR_VERSION=1 TCL_REG_MINOR_VERSION=2 REGVER=$TCL_REG_MAJOR_VERSION$TCL_REG_MINOR_VERSION #------------------------------------------------------------------------ # Handle the --prefix=... option #------------------------------------------------------------------------ if test "${prefix}" = "NONE"; then prefix=/usr/local fi if test "${exec_prefix}" = "NONE"; then exec_prefix=$prefix fi # libdir must be a fully qualified path (not ${exec_prefix}/lib) eval libdir="$libdir" #------------------------------------------------------------------------ # Standard compiler checks #------------------------------------------------------------------------ # If the user did not set CFLAGS, set it now to keep # the AC_PROG_CC macro from adding "-g -O2". if test "${CFLAGS+set}" != "set" ; then CFLAGS="" fi AC_PROG_CC # To properly support cross-compilation, one would # need to use these tool checks instead of # the ones below and reconfigure with # autoconf 2.50. You can also just set # the CC, AR, RANLIB, and RC environment # variables if you want to cross compile. dnl AC_CHECK_TOOL(AR, ar) dnl AC_CHECK_TOOL(RANLIB, ranlib) dnl AC_CHECK_TOOL(RC, windres) if test "${GCC}" = "yes" ; then AC_CHECK_PROG(AR, ar, ar) AC_CHECK_PROG(RANLIB, ranlib, ranlib) AC_CHECK_PROG(RC, windres, windres) if test "${AR}" = "" ; then AC_MSG_ERROR([Required archive tool 'ar' not found on PATH.]) fi if test "${RANLIB}" = "" ; then AC_MSG_ERROR([Required archive index tool 'ranlib' not found on PATH.]) fi if test "${RC}" = "" ; then AC_MSG_ERROR([Required resource tool 'windres' not found on PATH.]) fi fi #-------------------------------------------------------------------- # Checks to see if the make program sets the $MAKE variable. #-------------------------------------------------------------------- AC_PROG_MAKE_SET #-------------------------------------------------------------------- # Determines the correct binary file extension (.o, .obj, .exe etc.) #-------------------------------------------------------------------- AC_OBJEXT AC_EXEEXT #-------------------------------------------------------------------- # Check whether --enable-threads or --disable-threads was given. #-------------------------------------------------------------------- SC_ENABLE_THREADS #-------------------------------------------------------------------- # The statements below define a collection of symbols related to # building libtcl as a shared library instead of a static library. #-------------------------------------------------------------------- SC_ENABLE_SHARED #-------------------------------------------------------------------- # The statements below define a collection of compile flags. This # macro depends on the value of SHARED_BUILD, and should be called # after SC_ENABLE_SHARED checks the configure switches. #-------------------------------------------------------------------- SC_CONFIG_CFLAGS #-------------------------------------------------------------------- # Perform additinal compiler tests. #-------------------------------------------------------------------- if test "${GCC}" = "yes" ; then # Check to see if the winsock2.h include file provided contains # typedefs like LPFN_ACCEPT and friends. # AC_CACHE_CHECK(for LPFN_ACCEPT support in winsock2.h, tcl_cv_lpfn_decls, AC_TRY_COMPILE([ #define WIN32_LEAN_AND_MEAN #define INCL_WINSOCK_API_TYPEDEFS 1 #include #undef WIN32_LEAN_AND_MEAN #include ], [ LPFN_ACCEPT accept; ], tcl_cv_lpfn_decls=yes, tcl_cv_lpfn_decls=no) ) if test "$tcl_cv_lpfn_decls" = "no" ; then AC_DEFINE(HAVE_NO_LPFN_DECLS, 1, [Defined when cygwin/mingw does not support LPFN_ACCEPT and friends.]) fi # Check to see if malloc.h is missing the alloca function # declaration. This is known to be a problem with Mingw. # If we compiled without the function declaration, it # would work but we would get a warning message from gcc. # If we add the function declaration ourselves, it # would not compile correctly because the _alloca # function expects the argument to be passed in a # register and not on the stack. Instead, we just # call it from inline asm code. AC_CACHE_CHECK(for alloca declaration in malloc.h, tcl_cv_malloc_decl_alloca, AC_TRY_COMPILE([ #include ], [ size_t arg = 0; void* ptr; ptr = alloca; ptr = alloca(arg); ], tcl_cv_malloc_decl_alloca=yes, tcl_cv_malloc_decl_alloca=no) ) if test "$tcl_cv_malloc_decl_alloca" = "no" && test "${GCC}" = "yes" ; then AC_DEFINE(HAVE_ALLOCA_GCC_INLINE, 1, [Defined when gcc should use inline ASM to call alloca.]) fi fi #-------------------------------------------------------------------- # Set the default compiler switches based on the --enable-symbols # option. This macro depends on C flags, and should be called # after SC_CONFIG_CFLAGS macro is called. #-------------------------------------------------------------------- SC_ENABLE_SYMBOLS TCL_DBGX=${DBGX} #-------------------------------------------------------------------- # man2tcl needs this so that it can use errno.h #-------------------------------------------------------------------- AC_CHECK_HEADER(errno.h, , MAN2TCLFLAGS="-DNO_ERRNO_H") AC_SUBST(MAN2TCLFLAGS) #------------------------------------------------------------------------ # tclConfig.sh refers to this by a different name #------------------------------------------------------------------------ TCL_SHARED_BUILD=${SHARED_BUILD} #-------------------------------------------------------------------- # Perform final evaluations of variables with possible substitutions. #-------------------------------------------------------------------- TCL_SHARED_LIB_SUFFIX="\${NODOT_VERSION}${DLLSUFFIX}" TCL_UNSHARED_LIB_SUFFIX="\${NODOT_VERSION}${LIBSUFFIX}" TCL_EXPORT_FILE_SUFFIX="\${NODOT_VERSION}${LIBSUFFIX}" eval "TCL_SRC_DIR=\"`cd $srcdir/..; pwd`\"" eval "TCL_DLL_FILE=tcl${VER}${DLLSUFFIX}" eval "TCL_LIB_FILE=${LIBPREFIX}tcl$VER${LIBSUFFIX}" eval "TCL_LIB_FLAG=\"-ltcl${VER}${LIBFLAGSUFFIX}\"" eval "TCL_BUILD_LIB_SPEC=\"-L`pwd` ${TCL_LIB_FLAG}\"" eval "TCL_LIB_SPEC=\"-L${libdir} ${TCL_LIB_FLAG}\"" eval "TCL_STUB_LIB_FILE=\"${LIBPREFIX}tclstub${VER}${LIBSUFFIX}\"" eval "TCL_STUB_LIB_FLAG=\"-ltclstub${VER}${LIBFLAGSUFFIX}\"" eval "TCL_BUILD_STUB_LIB_SPEC=\"-L`pwd` ${TCL_STUB_LIB_FLAG}\"" eval "TCL_STUB_LIB_SPEC=\"-L${libdir} ${TCL_STUB_LIB_FLAG}\"" eval "TCL_BUILD_STUB_LIB_PATH=\"`pwd`/${TCL_STUB_LIB_FILE}\"" eval "TCL_STUB_LIB_PATH=\"${libdir}/${TCL_STUB_LIB_FILE}\"" # Install time header dir can be set via --includedir eval "TCL_INCLUDE_SPEC=\"-I${includedir}\"" eval "DLLSUFFIX=${DLLSUFFIX}" eval "LIBPREFIX=${LIBPREFIX}" eval "LIBSUFFIX=${LIBSUFFIX}" eval "EXESUFFIX=${EXESUFFIX}" CFG_TCL_SHARED_LIB_SUFFIX=${TCL_SHARED_LIB_SUFFIX} CFG_TCL_UNSHARED_LIB_SUFFIX=${TCL_UNSHARED_LIB_SUFFIX} CFG_TCL_EXPORT_FILE_SUFFIX=${TCL_EXPORT_FILE_SUFFIX} #-------------------------------------------------------------------- # Adjust the defines for how the resources are built depending # on symbols and static vs. shared. #-------------------------------------------------------------------- if test ${SHARED_BUILD} = 0 ; then if test "${DBGX}" = "g"; then RC_DEFINES="${RC_DEFINE} STATIC_BUILD ${RC_DEFINE} DEBUG" else RC_DEFINES="${RC_DEFINE} STATIC_BUILD" fi else if test "${DBGX}" = "g"; then RC_DEFINES="${RC_DEFINE} DEBUG" else RC_DEFINES="" fi fi #-------------------------------------------------------------------- # The statements below define the symbol TCL_PACKAGE_PATH, which # gives a list of directories that may contain packages. The list # consists of one directory for machine-dependent binaries and # another for platform-independent scripts. #-------------------------------------------------------------------- if test "$prefix/lib" != "$libdir"; then TCL_PACKAGE_PATH="${libdir} ${prefix}/lib" else TCL_PACKAGE_PATH="${prefix}/lib" fi AC_SUBST(TCL_VERSION) AC_SUBST(TCL_MAJOR_VERSION) AC_SUBST(TCL_MINOR_VERSION) AC_SUBST(TCL_PATCH_LEVEL) AC_SUBST(TCL_LIB_FILE) AC_SUBST(TCL_LIB_FLAG) # empty on win AC_SUBST(TCL_LIB_SPEC) AC_SUBST(TCL_STUB_LIB_FILE) AC_SUBST(TCL_STUB_LIB_FLAG) AC_SUBST(TCL_STUB_LIB_SPEC) AC_SUBST(TCL_STUB_LIB_PATH) AC_SUBST(TCL_INCLUDE_SPEC) AC_SUBST(TCL_BUILD_STUB_LIB_SPEC) AC_SUBST(TCL_BUILD_STUB_LIB_PATH) AC_SUBST(TCL_DLL_FILE) AC_SUBST(TCL_SRC_DIR) AC_SUBST(TCL_BIN_DIR) AC_SUBST(TCL_DBGX) AC_SUBST(CFG_TCL_SHARED_LIB_SUFFIX) AC_SUBST(CFG_TCL_UNSHARED_LIB_SUFFIX) AC_SUBST(CFG_TCL_EXPORT_FILE_SUFFIX) # win/tcl.m4 doesn't set (CFLAGS) AC_SUBST(CFLAGS_DEFAULT) AC_SUBST(EXTRA_CFLAGS) AC_SUBST(CYGPATH) AC_SUBST(DEPARG) AC_SUBST(CC_OBJNAME) AC_SUBST(CC_EXENAME) # win/tcl.m4 doesn't set (LDFLAGS) AC_SUBST(LDFLAGS_DEFAULT) AC_SUBST(LDFLAGS_DEBUG) AC_SUBST(LDFLAGS_OPTIMIZE) AC_SUBST(LDFLAGS_CONSOLE) AC_SUBST(LDFLAGS_WINDOW) AC_SUBST(AR) AC_SUBST(RANLIB) AC_SUBST(STLIB_LD) AC_SUBST(SHLIB_LD) AC_SUBST(SHLIB_LD_LIBS) AC_SUBST(SHLIB_CFLAGS) AC_SUBST(SHLIB_SUFFIX) AC_SUBST(TCL_SHARED_BUILD) AC_SUBST(LIBS) AC_SUBST(LIBS_GUI) AC_SUBST(DLLSUFFIX) AC_SUBST(LIBPREFIX) AC_SUBST(LIBSUFFIX) AC_SUBST(EXESUFFIX) AC_SUBST(LIBRARIES) AC_SUBST(MAKE_LIB) AC_SUBST(POST_MAKE_LIB) AC_SUBST(MAKE_DLL) AC_SUBST(MAKE_EXE) # empty on win, but needs sub'ing AC_SUBST(TCL_BUILD_LIB_SPEC) AC_SUBST(TCL_LD_SEARCH_FLAGS) AC_SUBST(TCL_NEEDS_EXP_FILE) AC_SUBST(TCL_BUILD_EXP_FILE) AC_SUBST(TCL_EXP_FILE) AC_SUBST(DL_LIBS) AC_SUBST(LIBOBJS) AC_SUBST(TCL_LIB_VERSIONS_OK) AC_SUBST(TCL_PACKAGE_PATH) # win only AC_SUBST(TCL_DDE_VERSION) AC_SUBST(TCL_DDE_MAJOR_VERSION) AC_SUBST(TCL_DDE_MINOR_VERSION) AC_SUBST(TCL_REG_VERSION) AC_SUBST(TCL_REG_MAJOR_VERSION) AC_SUBST(TCL_REG_MINOR_VERSION) AC_SUBST(RC) AC_SUBST(RC_OUT) AC_SUBST(RC_TYPE) AC_SUBST(RC_INCLUDE) AC_SUBST(RC_DEFINE) AC_SUBST(RC_DEFINES) AC_SUBST(RES) AC_OUTPUT(Makefile tclConfig.sh tcl.hpj) dnl Local Variables: dnl mode: autoconf; dnl End: tcl8.4.20/win/makefile.vc0000644003604700454610000006356112153151142013617 0ustar dgp771div#------------------------------------------------------------------------------ # makefile.vc -- # # Microsoft Visual C++ makefile for use with nmake.exe v1.62+ (VC++ 5.0+) # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # Copyright (c) 1995-1996 Sun Microsystems, Inc. # Copyright (c) 1998-2000 Ajuba Solutions. # Copyright (c) 2001-2005 ActiveState Corporation. # Copyright (c) 2001-2002 David Gravereaux. #------------------------------------------------------------------------------ # Check to see we are configured to build with MSVC (MSDEVDIR, MSVCDIR or # VCINSTALLDIR) or with the MS Platform SDK (MSSDK or WindowsSDKDir) !if !defined(MSDEVDIR) && !defined(MSVCDIR) && !defined(VCINSTALLDIR) && !defined(MSSDK) && !defined(WINDOWSSDKDIR) MSG = ^ You need to run vcvars32.bat from Developer Studio or setenv.bat from the^ Platform SDK first to setup the environment. Jump to this line to read^ the build instructions. !error $(MSG) !endif #------------------------------------------------------------------------------ # HOW TO USE this makefile: # # 1) It is now necessary to have MSVCDir, MSDevDir or MSSDK set in the # environment. This is used as a check to see if vcvars32.bat had been # run prior to running nmake or during the installation of Microsoft # Visual C++, MSVCDir had been set globally and the PATH adjusted. # Either way is valid. # # You'll need to run vcvars32.bat contained in the MsDev's vc(98)/bin # directory to setup the proper environment, if needed, for your # current setup. This is a needed bootstrap requirement and allows the # swapping of different environments to be easier. # # 2) To use the Platform SDK (not expressly needed), run setenv.bat after # vcvars32.bat according to the instructions for it. This can also # turn on the 64-bit compiler, if your SDK has it. # # 3) Targets are: # release -- Builds the core, the shell and the dlls. (default) # dlls -- Just builds the windows extensions and the 16-bit DOS # pipe/thunk helper app. # shell -- Just builds the shell and the core. # core -- Only builds the core [tclXX.(dll|lib)]. # all -- Builds everything. # test -- Builds and runs the test suite. # tcltest -- Just builds the test shell. # install -- Installs the built binaries and libraries to $(INSTALLDIR) # as the root of the install tree. # tidy/clean/hose -- varying levels of cleaning. # genstubs -- Rebuilds the Stubs table and support files (dev only). # depend -- Generates an accurate set of source dependancies for this # makefile. Helpful to avoid problems when the sources are # refreshed and you rebuild, but can "overbuild" when common # headers like tclInt.h just get small changes. # winhelp -- Builds the windows .hlp file for Tcl from the troff man # files found in $(ROOT)\doc . # # 4) Macros usable on the commandline: # INSTALLDIR= # Sets where to install Tcl from the built binaries. # C:\Progra~1\Tcl is assumed when not specified. # # OPTS=static,msvcrt,staticpkg,threads,symbols,profile,loimpact,none # Sets special options for the core. The default is for none. # Any combination of the above may be used (comma separated). # 'none' will over-ride everything to nothing. # # static = Builds a static library of the core instead of a # dll. The shell will be static (and large), as well. # msvcrt = Effects the static option only to switch it from # using libcmt(d) as the C runtime [by default] to # msvcrt(d). This is useful for static embedding # support. # staticpkg = Effects the static option only to switch # tclshXX.exe to have the dde and reg extension linked # inside it. # threads = Turns on full multithreading support. # thrdalloc = Use the thread allocator (shared global free pool). # symbols = Adds symbols for step debugging. # profile = Adds profiling hooks. Map file is assumed. # loimpact = Adds a flag for how NT treats the heap to keep memory # in use, low. This is said to impact alloc performance. # # STATS=memdbg,compdbg,none # Sets optional memory and bytecode compiler debugging code added # to the core. The default is for none. Any combination of the # above may be used (comma separated). 'none' will over-ride # everything to nothing. # # memdbg = Enables the debugging memory allocator. # compdbg = Enables byte compilation logging. # # MACHINE=(IX86|IA64|AMD64|ALPHA) # Set the machine type used for the compiler, linker, and # resource compiler. This hook is needed to tell the tools # when alternate platforms are requested. IX86 is the default # when not specified. # # TMP_DIR= # OUT_DIR= # Hooks to allow the intermediate and output directories to be # changed. $(OUT_DIR) is assumed to be # $(BINROOT)\(Release|Debug) based on if symbols are requested. # $(TMP_DIR) will de $(OUT_DIR)\ by default. # # TESTPAT= # Reads the tests requested to be run from this file. # # 5) Examples: # # Basic syntax of calling nmake looks like this: # nmake [-nologo] -f makefile.vc [target|macrodef [target|macrodef] [...]] # # Standard (no frills) # c:\tcl_src\win\>c:\progra~1\micros~1\vc98\bin\vcvars32.bat # Setting environment for using Microsoft Visual C++ tools. # c:\tcl_src\win\>nmake -f makefile.vc release # c:\tcl_src\win\>nmake -f makefile.vc install INSTALLDIR=c:\progra~1\tcl # # Building for Win64 # c:\tcl_src\win\>c:\progra~1\micros~1\vc98\bin\vcvars32.bat # Setting environment for using Microsoft Visual C++ tools. # c:\tcl_src\win\>c:\progra~1\platfo~1\setenv.bat /pre64 /RETAIL # Targeting Windows pre64 RETAIL # c:\tcl_src\win\>nmake -f makefile.vc MACHINE=IA64 # #------------------------------------------------------------------------------ #============================================================================== ############################################################################### # //==================================================================\\ # >>[ -> Do not modify below this line. <- ]<< # >>[ Please, use the commandline macros to modify how Tcl is built. ]<< # >>[ If you need more features, send us a patch for more macros. ]<< # \\==================================================================// ############################################################################### #============================================================================== #------------------------------------------------------------------------------ !if !exist("makefile.vc") MSG = ^ You must run this makefile only from the directory it is in.^ Please `cd` to its location first. !error $(MSG) !endif PROJECT = tcl !include "rules.vc" STUBPREFIX = $(PROJECT)stub DOTVERSION = 8.4 VERSION = $(DOTVERSION:.=) DDEDOTVERSION = 1.3 DDEVERSION = $(DDEDOTVERSION:.=) REGDOTVERSION = 1.2 REGVERSION = $(REGDOTVERSION:.=) BINROOT = . ROOT = .. TCLIMPLIB = $(OUT_DIR)\$(PROJECT)$(VERSION)$(SUFX).lib TCLLIBNAME = $(PROJECT)$(VERSION)$(SUFX).$(EXT) TCLLIB = $(OUT_DIR)\$(TCLLIBNAME) TCLSTUBLIBNAME = $(STUBPREFIX)$(VERSION).lib TCLSTUBLIB = $(OUT_DIR)\$(TCLSTUBLIBNAME) TCLSHNAME = $(PROJECT)sh$(VERSION)$(SUFX).exe TCLSH = $(OUT_DIR)\$(TCLSHNAME) TCLPIPEDLLNAME = $(PROJECT)pip$(VERSION)$(SUFX:t=).dll TCLPIPEDLL = $(OUT_DIR)\$(TCLPIPEDLLNAME) TCLREGLIBNAME = $(PROJECT)reg$(REGVERSION)$(SUFX:t=).$(EXT) TCLREGLIB = $(OUT_DIR)\$(TCLREGLIBNAME) TCLDDELIBNAME = $(PROJECT)dde$(DDEVERSION)$(SUFX:t=).$(EXT) TCLDDELIB = $(OUT_DIR)\$(TCLDDELIBNAME) TCLTEST = $(OUT_DIR)\$(PROJECT)test.exe CAT32 = $(OUT_DIR)\cat32.exe ### Make sure we use backslash only. LIB_INSTALL_DIR = $(_INSTALLDIR)\lib BIN_INSTALL_DIR = $(_INSTALLDIR)\bin DOC_INSTALL_DIR = $(_INSTALLDIR)\doc SCRIPT_INSTALL_DIR = $(_INSTALLDIR)\lib\tcl$(DOTVERSION) INCLUDE_INSTALL_DIR = $(_INSTALLDIR)\include TCLSHOBJS = \ $(TMP_DIR)\tclAppInit.obj \ !if $(TCL_USE_STATIC_PACKAGES) $(TMP_DIR)\tclWinReg.obj \ $(TMP_DIR)\tclWinDde.obj \ !endif $(TMP_DIR)\tclsh.res TCLTESTOBJS = \ $(TMP_DIR)\tclTest.obj \ $(TMP_DIR)\tclTestObj.obj \ $(TMP_DIR)\tclTestProcBodyObj.obj \ $(TMP_DIR)\tclThreadTest.obj \ $(TMP_DIR)\tclWinTest.obj \ !if $(TCL_USE_STATIC_PACKAGES) $(TMP_DIR)\tclWinReg.obj \ $(TMP_DIR)\tclWinDde.obj \ !endif $(TMP_DIR)\testMain.obj TCLOBJS = \ $(TMP_DIR)\regcomp.obj \ $(TMP_DIR)\regerror.obj \ $(TMP_DIR)\regexec.obj \ $(TMP_DIR)\regfree.obj \ $(TMP_DIR)\strftime.obj \ $(TMP_DIR)\strtoll.obj \ $(TMP_DIR)\strtoull.obj \ $(TMP_DIR)\tclAlloc.obj \ $(TMP_DIR)\tclAsync.obj \ $(TMP_DIR)\tclBasic.obj \ $(TMP_DIR)\tclBinary.obj \ $(TMP_DIR)\tclCkalloc.obj \ $(TMP_DIR)\tclClock.obj \ $(TMP_DIR)\tclCmdAH.obj \ $(TMP_DIR)\tclCmdIL.obj \ $(TMP_DIR)\tclCmdMZ.obj \ $(TMP_DIR)\tclCompCmds.obj \ $(TMP_DIR)\tclCompExpr.obj \ $(TMP_DIR)\tclCompile.obj \ $(TMP_DIR)\tclDate.obj \ $(TMP_DIR)\tclEncoding.obj \ $(TMP_DIR)\tclEnv.obj \ $(TMP_DIR)\tclEvent.obj \ $(TMP_DIR)\tclExecute.obj \ $(TMP_DIR)\tclFCmd.obj \ $(TMP_DIR)\tclFileName.obj \ $(TMP_DIR)\tclGet.obj \ $(TMP_DIR)\tclHash.obj \ $(TMP_DIR)\tclHistory.obj \ $(TMP_DIR)\tclIndexObj.obj \ $(TMP_DIR)\tclInterp.obj \ $(TMP_DIR)\tclIO.obj \ $(TMP_DIR)\tclIOCmd.obj \ $(TMP_DIR)\tclIOGT.obj \ $(TMP_DIR)\tclIOSock.obj \ $(TMP_DIR)\tclIOUtil.obj \ $(TMP_DIR)\tclLink.obj \ $(TMP_DIR)\tclListObj.obj \ $(TMP_DIR)\tclLiteral.obj \ $(TMP_DIR)\tclLoad.obj \ $(TMP_DIR)\tclMain.obj \ $(TMP_DIR)\tclNamesp.obj \ $(TMP_DIR)\tclNotify.obj \ $(TMP_DIR)\tclObj.obj \ $(TMP_DIR)\tclPanic.obj \ $(TMP_DIR)\tclParse.obj \ $(TMP_DIR)\tclParseExpr.obj \ $(TMP_DIR)\tclPipe.obj \ $(TMP_DIR)\tclPkg.obj \ $(TMP_DIR)\tclPosixStr.obj \ $(TMP_DIR)\tclPreserve.obj \ $(TMP_DIR)\tclProc.obj \ $(TMP_DIR)\tclRegexp.obj \ $(TMP_DIR)\tclResolve.obj \ $(TMP_DIR)\tclResult.obj \ $(TMP_DIR)\tclScan.obj \ $(TMP_DIR)\tclStringObj.obj \ $(TMP_DIR)\tclStubInit.obj \ $(TMP_DIR)\tclStubLib.obj \ $(TMP_DIR)\tclThread.obj \ $(TMP_DIR)\tclThreadAlloc.obj \ $(TMP_DIR)\tclThreadJoin.obj \ $(TMP_DIR)\tclTimer.obj \ $(TMP_DIR)\tclUtf.obj \ $(TMP_DIR)\tclUtil.obj \ $(TMP_DIR)\tclVar.obj \ $(TMP_DIR)\tclWin32Dll.obj \ $(TMP_DIR)\tclWinChan.obj \ $(TMP_DIR)\tclWinConsole.obj \ $(TMP_DIR)\tclWinSerial.obj \ $(TMP_DIR)\tclWinError.obj \ $(TMP_DIR)\tclWinFCmd.obj \ $(TMP_DIR)\tclWinFile.obj \ $(TMP_DIR)\tclWinInit.obj \ $(TMP_DIR)\tclWinLoad.obj \ $(TMP_DIR)\tclWinMtherr.obj \ $(TMP_DIR)\tclWinNotify.obj \ $(TMP_DIR)\tclWinPipe.obj \ $(TMP_DIR)\tclWinSock.obj \ $(TMP_DIR)\tclWinThrd.obj \ $(TMP_DIR)\tclWinTime.obj \ !if !$(STATIC_BUILD) $(TMP_DIR)\tcl.res !endif TCLSTUBOBJS = $(TMP_DIR)\tclStubLib.obj ### The following paths CANNOT have spaces in them. COMPATDIR = $(ROOT)\compat DOCDIR = $(ROOT)\doc GENERICDIR = $(ROOT)\generic TOOLSDIR = $(ROOT)\tools WINDIR = $(ROOT)\win #--------------------------------------------------------------------- # Compile flags #--------------------------------------------------------------------- !if !$(DEBUG) !if $(OPTIMIZING) ### This cranks the optimization level to maximize speed cdebug = -O2 $(OPTIMIZATIONS) !else cdebug = !endif !else if "$(MACHINE)" == "IA64" || "$(MACHINE)" == "AMD64" ### Warnings are too many, can't support warnings into errors. cdebug = -Zi -Od $(DEBUGFLAGS) !else cdebug = -Zi -WX $(DEBUGFLAGS) !endif ### Declarations common to all compiler options cwarn = -D _CRT_SECURE_NO_DEPRECATE -D _CRT_NONSTDC_NO_DEPRECATE cflags = -nologo -c $(COMPILERFLAGS) $(cwarn) -Fp$(TMP_DIR)^\ !if $(FULLWARNINGS) cflags = $(cflags) -W4 !else cflags = $(cflags) -W3 !endif !if $(MSVCRT) !if "$(DBGX)" == "" crt = -MD !else crt = -MDd !endif !else !if "$(DBGX)" == "" crt = -MT !else crt = -MTd !endif !endif TCL_INCLUDES = -I"$(WINDIR)" -I"$(GENERICDIR)" BASE_CFLAGS = $(cflags) $(cdebug) $(crt) $(TCL_INCLUDES) \ -DTCL_PIPE_DLL=\"$(TCLPIPEDLLNAME)\" CON_CFLAGS = $(cflags) $(cdebug) $(crt) -DCONSOLE TCL_CFLAGS = $(BASE_CFLAGS) $(OPTDEFINES) #--------------------------------------------------------------------- # Link flags #--------------------------------------------------------------------- !if $(DEBUG) ldebug = -debug -debugtype:cv !else ldebug = -release -opt:ref -opt:icf,3 !endif ### Declarations common to all linker options lflags = -nologo -machine:$(MACHINE) $(LINKERFLAGS) $(ldebug) !if $(FULLWARNINGS) lflags = $(lflags) -warn:3 !endif !if $(PROFILE) lflags = $(lflags) -profile !endif !if $(ALIGN98_HACK) && !$(STATIC_BUILD) ### Align sections for PE size savings. lflags = $(lflags) -opt:nowin98 !else if !$(ALIGN98_HACK) && $(STATIC_BUILD) ### Align sections for speed in loading by choosing the virtual page size. lflags = $(lflags) -align:4096 !endif !if $(LOIMPACT) lflags = $(lflags) -ws:aggressive !endif dlllflags = $(lflags) -dll conlflags = $(lflags) -subsystem:console guilflags = $(lflags) -subsystem:windows baselibs = kernel32.lib advapi32.lib user32.lib # Avoid 'unresolved external symbol __security_cookie' errors. # c.f. http://support.microsoft.com/?id=894573 !if "$(MACHINE)" == "IA64" || "$(MACHINE)" == "AMD64" baselibs = $(baselibs) bufferoverflowU.lib !endif #--------------------------------------------------------------------- # TclTest flags #--------------------------------------------------------------------- !if "$(TESTPAT)" != "" TESTFLAGS = $(TESTFLAGS) -file $(TESTPAT) !endif #--------------------------------------------------------------------- # Project specific targets #--------------------------------------------------------------------- release: setup $(TCLSH) $(TCLSTUBLIB) dlls core: setup $(TCLLIB) $(TCLSTUBLIB) shell: setup $(TCLSH) dlls: setup $(TCLPIPEDLL) $(TCLREGLIB) $(TCLDDELIB) all: setup $(TCLSH) $(TCLSTUBLIB) dlls $(CAT32) tcltest: setup $(TCLTEST) dlls $(CAT32) install: install-binaries install-libraries install-docs test: setup $(TCLTEST) dlls $(CAT32) set TCL_LIBRARY=$(ROOT)/library !if "$(OS)" == "Windows_NT" || "$(MSVCDIR)" == "IDE" $(TCLTEST) "$(ROOT)/tests/all.tcl" $(TESTFLAGS) !else $(TCLTEST) "$(ROOT)/tests/all.tcl" $(TESTFLAGS) > tests.log type tests.log | more !endif runtest: setup $(TCLTEST) dlls $(CAT32) set TCL_LIBRARY=$(ROOT)/library $(TCLTEST) setup: @if not exist $(OUT_DIR)\nul mkdir $(OUT_DIR) @if not exist $(TMP_DIR)\nul mkdir $(TMP_DIR) !if !$(STATIC_BUILD) $(TCLIMPLIB): $(TCLLIB) !endif $(TCLLIB): $(TCLOBJS) !if $(STATIC_BUILD) $(lib32) -nologo -out:$@ @<< $** << !else $(link32) $(dlllflags) -base:@$(WINDIR)\coffbase.txt,tcl -out:$@ \ $(baselibs) @<< $** << $(_VC_MANIFEST_EMBED_DLL) -@del $*.exp !endif $(TCLSTUBLIB): $(TCLSTUBOBJS) $(lib32) -nologo -out:$@ $(TCLSTUBOBJS) $(TCLSH): $(TCLSHOBJS) $(TCLIMPLIB) $(link32) $(conlflags) -stack:2300000 -out:$@ $(baselibs) $** $(_VC_MANIFEST_EMBED_EXE) $(TCLTEST): $(TCLTESTOBJS) $(TCLIMPLIB) $(link32) $(conlflags) -stack:2300000 -out:$@ $(baselibs) $** $(_VC_MANIFEST_EMBED_EXE) $(TCLPIPEDLL): $(WINDIR)\stub16.c $(cc32) $(CON_CFLAGS) -Fo$(TMP_DIR)\ $(WINDIR)\stub16.c $(link32) $(conlflags) -out:$@ $(TMP_DIR)\stub16.obj $(baselibs) $(_VC_MANIFEST_EMBED_DLL) !if $(STATIC_BUILD) $(TCLDDELIB): $(TMP_DIR)\tclWinDde.obj $(lib32) -nologo -out:$@ $(TMP_DIR)\tclWinDde.obj !else $(TCLDDELIB): $(TMP_DIR)\tclWinDde.obj $(TCLSTUBLIB) $(link32) $(dlllflags) -base:@$(WINDIR)\coffbase.txt,tcldde -out:$@ \ $** $(baselibs) $(_VC_MANIFEST_EMBED_DLL) -@del $*.exp -@del $*.lib !endif !if $(STATIC_BUILD) $(TCLREGLIB): $(TMP_DIR)\tclWinReg.obj $(lib32) -nologo -out:$@ $(TMP_DIR)\tclWinReg.obj !else $(TCLREGLIB): $(TMP_DIR)\tclWinReg.obj $(TCLSTUBLIB) $(link32) $(dlllflags) -base:@$(WINDIR)\coffbase.txt,tclreg -out:$@ \ $** $(baselibs) $(_VC_MANIFEST_EMBED_DLL) -@del $*.exp -@del $*.lib !endif $(CAT32): $(WINDIR)\cat.c $(cc32) $(CON_CFLAGS) -Fo$(TMP_DIR)\ $? $(link32) $(conlflags) -out:$@ -stack:16384 $(TMP_DIR)\cat.obj \ $(baselibs) $(_VC_MANIFEST_EMBED_EXE) #--------------------------------------------------------------------- # Regenerate the stubs files. [Development use only] #--------------------------------------------------------------------- genstubs: !if !exist($(TCLSH)) @echo Build tclsh first! !else $(TCLSH) $(TOOLSDIR:\=/)\genStubs.tcl $(GENERICDIR:\=/) \ $(GENERICDIR:\=/)/tcl.decls $(GENERICDIR:\=/)/tclInt.decls !endif #--------------------------------------------------------------------- # Generate the makefile depedancies. #--------------------------------------------------------------------- depend: !if !exist($(TCLSH)) @echo Build tclsh first! !else $(TCLSH) $(TOOLSDIR:\=/)/mkdepend.tcl -vc32 -out:"$(OUT_DIR)\depend.mk" \ -passthru:"-DBUILD_tcl $(TCL_INCLUDES:"="")" $(GENERICDIR) \ $(COMPATDIR) $(WINDIR) @<< $(TCLOBJS) << !endif #--------------------------------------------------------------------- # Build the windows help file. #--------------------------------------------------------------------- TCLHLPBASE = $(PROJECT)$(VERSION) HELPFILE = $(OUT_DIR)\$(TCLHLPBASE).hlp HELPCNT = $(OUT_DIR)\$(TCLHLPBASE).cnt DOCTMP_DIR = $(OUT_DIR)\$(PROJECT)_docs HELPRTF = $(DOCTMP_DIR)\$(PROJECT).rtf MAN2HELP = $(DOCTMP_DIR)\man2help.tcl MAN2HELP2 = $(DOCTMP_DIR)\man2help2.tcl INDEX = $(DOCTMP_DIR)\index.tcl BMP = $(DOCTMP_DIR)\feather.bmp BMP_NOPATH = feather.bmp MAN2TCL = $(DOCTMP_DIR)\man2tcl.exe winhelp: docsetup $(HELPFILE) docsetup: @if not exist $(DOCTMP_DIR)\nul mkdir $(DOCTMP_DIR) $(MAN2HELP) $(MAN2HELP2) $(INDEX) $(BMP): $(TOOLSDIR)\$$(@F) @$(CPY) $(TOOLSDIR)\$(@F) $(@D) $(HELPFILE): $(HELPRTF) $(BMP) cd $(DOCTMP_DIR) start /wait hcrtf.exe -x <<$(PROJECT).hpj [OPTIONS] COMPRESS=12 Hall Zeck LCID=0x409 0x0 0x0 ; English (United States) TITLE=Tcl/Tk Reference Manual BMROOT=. CNT=$(@B).cnt HLP=$(@B).hlp [FILES] $(PROJECT).rtf [WINDOWS] main="Tcl/Tk Reference Manual",,27648,(r15263976),(r65535) [CONFIG] BrowseButtons() CreateButton(1, "Web", ExecFile("http://www.tcl.tk")) CreateButton(2, "SF", ExecFile("http://sf.net/projects/tcl")) CreateButton(3, "Wiki", ExecFile("http://wiki.tcl.tk")) CreateButton(4, "FAQ", ExecFile("http://www.purl.org/NET/Tcl-FAQ/")) << cd $(MAKEDIR) @$(CPY) "$(DOCTMP_DIR)\$(@B).hlp" "$(OUT_DIR)" @$(CPY) "$(DOCTMP_DIR)\$(@B).cnt" "$(OUT_DIR)" $(MAN2TCL): $(TOOLSDIR)\$$(@B).c $(cc32) $(TCL_CFLAGS) -Fo$(@D)\ $(TOOLSDIR)\$(@B).c $(link32) $(conlflags) -out:$@ -stack:16384 $(@D)\man2tcl.obj $(_VC_MANIFEST_EMBED_EXE) $(HELPRTF): $(MAN2TCL) $(MAN2HELP) $(MAN2HELP2) $(INDEX) $(DOCDIR)\* $(TCLSH) $(MAN2HELP) -bitmap $(BMP_NOPATH) $(PROJECT) $(VERSION) $(DOCDIR:\=/) install-docs: !if exist($(HELPFILE)) @$(CPY) "$(HELPFILE)" "$(DOC_INSTALL_DIR)\" @$(CPY) "$(HELPCNT)" "$(DOC_INSTALL_DIR)\" !endif #--------------------------------------------------------------------- # Special case object file targets #--------------------------------------------------------------------- $(TMP_DIR)\testMain.obj: $(WINDIR)\tclAppInit.c !if $(TCL_USE_STATIC_PACKAGES) $(cc32) $(TCL_CFLAGS) -DTCL_TEST -DTCL_USE_STATIC_PACKAGES -Fo$@ $? !else $(cc32) $(TCL_CFLAGS) -DTCL_TEST -Fo$@ $? !endif $(TMP_DIR)\tclTest.obj: $(GENERICDIR)\tclTest.c $(cc32) $(TCL_CFLAGS) -Fo$@ $? $(TMP_DIR)\tclTestObj.obj: $(GENERICDIR)\tclTestObj.c $(cc32) $(TCL_CFLAGS) -Fo$@ $? $(TMP_DIR)\tclWinTest.obj: $(WINDIR)\tclWinTest.c $(cc32) $(TCL_CFLAGS) -Fo$@ $? $(TMP_DIR)\tclAppInit.obj: $(WINDIR)\tclAppInit.c !if $(TCL_USE_STATIC_PACKAGES) $(cc32) $(TCL_CFLAGS) -DTCL_USE_STATIC_PACKAGES -Fo$@ $? !else $(cc32) $(TCL_CFLAGS) -Fo$@ $? !endif ### The following objects should be built using the stub interfaces ### *ALL* extensions need to built with -DTCL_THREADS=1 $(TMP_DIR)\tclWinReg.obj: $(WINDIR)\tclWinReg.c !if $(STATIC_BUILD) $(cc32) $(BASE_CFLAGS) -DTCL_THREADS=1 -DSTATIC_BUILD -Fo$@ $? !else $(cc32) $(BASE_CFLAGS) -DTCL_THREADS=1 -DUSE_TCL_STUBS -Fo$@ $? !endif $(TMP_DIR)\tclWinDde.obj: $(WINDIR)\tclWinDde.c !if $(STATIC_BUILD) $(cc32) $(BASE_CFLAGS) -DTCL_THREADS=1 -DSTATIC_BUILD -Fo$@ $? !else $(cc32) $(BASE_CFLAGS) -DTCL_THREADS=1 -DUSE_TCL_STUBS -Fo$@ $? !endif ### The following objects are part of the stub library and should not ### be built as DLL objects. -Zl is used to avoid a dependancy on any ### specific C run-time. $(TMP_DIR)\tclStubLib.obj: $(GENERICDIR)\tclStubLib.c $(cc32) $(cdebug) $(cflags) -Zl -DSTATIC_BUILD $(TCL_INCLUDES) -Fo$@ $? #--------------------------------------------------------------------- # Dedependency rules #--------------------------------------------------------------------- $(GENERICDIR)\regcomp.c: \ $(GENERICDIR)\regguts.h \ $(GENERICDIR)\regc_lex.c \ $(GENERICDIR)\regc_color.c \ $(GENERICDIR)\regc_nfa.c \ $(GENERICDIR)\regc_cvec.c \ $(GENERICDIR)\regc_locale.c $(GENERICDIR)\regcustom.h: \ $(GENERICDIR)\tclInt.h \ $(GENERICDIR)\tclPort.h \ $(GENERICDIR)\regex.h $(GENERICDIR)\regexec.c: \ $(GENERICDIR)\rege_dfa.c \ $(GENERICDIR)\regguts.h $(GENERICDIR)\regerror.c: $(GENERICDIR)\regguts.h $(GENERICDIR)\regfree.c: $(GENERICDIR)\regguts.h $(GENERICDIR)\regfronts.c: $(GENERICDIR)\regguts.h $(GENERICDIR)\regguts.h: $(GENERICDIR)\regcustom.h !if exist("$(OUT_DIR)\depend.mk") !include "$(OUT_DIR)\depend.mk" !message *** Dependency rules in effect. !else !message *** Dependency rules are not being used. !endif ### add a spacer in the output !message #--------------------------------------------------------------------- # Implicit rules #--------------------------------------------------------------------- {$(WINDIR)}.c{$(TMP_DIR)}.obj:: $(cc32) $(TCL_CFLAGS) -DBUILD_tcl -Fo$(TMP_DIR)\ @<< $< << {$(GENERICDIR)}.c{$(TMP_DIR)}.obj:: $(cc32) $(TCL_CFLAGS) -DBUILD_tcl -Fo$(TMP_DIR)\ @<< $< << {$(COMPATDIR)}.c{$(TMP_DIR)}.obj:: $(cc32) $(TCL_CFLAGS) -DBUILD_tcl -Fo$(TMP_DIR)\ @<< $< << {$(WINDIR)}.rc{$(TMP_DIR)}.res: $(rc32) -fo $@ -r -i "$(GENERICDIR)" -D__WIN32__ \ !if $(DEBUG) -d DEBUG \ !endif !if $(TCL_THREADS) -d TCL_THREADS \ !endif !if $(STATIC_BUILD) -d STATIC_BUILD \ !endif $< .SUFFIXES: .SUFFIXES:.c .rc #--------------------------------------------------------------------- # Installation. #--------------------------------------------------------------------- install-binaries: @echo Installing to '$(_INSTALLDIR)' @echo installing $(TCLLIBNAME) !if "$(TCLLIB)" != "$(TCLIMPLIB)" @$(CPY) "$(TCLLIB)" "$(BIN_INSTALL_DIR)\" !endif @$(CPY) "$(TCLIMPLIB)" "$(LIB_INSTALL_DIR)\" !if exist($(TCLSH)) @echo installing $(TCLSHNAME) @$(CPY) "$(TCLSH)" "$(BIN_INSTALL_DIR)\" !endif !if exist($(TCLPIPEDLL)) @echo installing $(TCLPIPEDLLNAME) @$(CPY) "$(TCLPIPEDLL)" "$(BIN_INSTALL_DIR)\" !endif @echo installing $(TCLSTUBLIBNAME) @$(CPY) "$(TCLSTUBLIB)" "$(LIB_INSTALL_DIR)\" install-libraries: @echo installing http1.0 @$(CPY) "$(ROOT)\library\http1.0\*.tcl" \ "$(SCRIPT_INSTALL_DIR)\http1.0\" @echo installing http2.5 @$(CPY) "$(ROOT)\library\http\*.tcl" \ "$(SCRIPT_INSTALL_DIR)\http2.5\" @echo installing opt0.4 @$(CPY) "$(ROOT)\library\opt\*.tcl" \ "$(SCRIPT_INSTALL_DIR)\opt0.4\" @echo installing msgcat1.3 @$(CPY) "$(ROOT)\library\msgcat\*.tcl" \ "$(SCRIPT_INSTALL_DIR)\msgcat1.3\" @echo installing tcltest2.2 @$(CPY) "$(ROOT)\library\tcltest\*.tcl" \ "$(SCRIPT_INSTALL_DIR)\tcltest2.2\" @echo installing $(TCLDDELIBNAME) !if $(STATIC_BUILD) @$(CPY) "$(TCLDDELIB)" "$(LIB_INSTALL_DIR)\" !else @$(CPY) "$(TCLDDELIB)" "$(LIB_INSTALL_DIR)\dde$(DDEDOTVERSION)\" @$(CPY) "$(ROOT)\library\dde\pkgIndex.tcl" \ "$(LIB_INSTALL_DIR)\dde$(DDEDOTVERSION)\" !endif @echo installing $(TCLREGLIBNAME) !if $(STATIC_BUILD) @$(CPY) "$(TCLREGLIB)" "$(LIB_INSTALL_DIR)\" !else @$(CPY) "$(TCLREGLIB)" "$(LIB_INSTALL_DIR)\reg$(REGDOTVERSION)\" @$(CPY) "$(ROOT)\library\reg\pkgIndex.tcl" \ "$(LIB_INSTALL_DIR)\reg$(REGDOTVERSION)\" !endif @echo installing encoding files @$(CPY) "$(ROOT)\library\encoding\*.enc" \ "$(SCRIPT_INSTALL_DIR)\encoding\" @echo installing library files @$(CPY) "$(GENERICDIR)\tcl.h" "$(INCLUDE_INSTALL_DIR)\" @$(CPY) "$(GENERICDIR)\tclDecls.h" "$(INCLUDE_INSTALL_DIR)\" @$(CPY) "$(GENERICDIR)\tclPlatDecls.h" "$(INCLUDE_INSTALL_DIR)\" @$(CPY) "$(ROOT)\library\history.tcl" "$(SCRIPT_INSTALL_DIR)\" @$(CPY) "$(ROOT)\library\init.tcl" "$(SCRIPT_INSTALL_DIR)\" @$(CPY) "$(ROOT)\library\ldAout.tcl" "$(SCRIPT_INSTALL_DIR)\" @$(CPY) "$(ROOT)\library\parray.tcl" "$(SCRIPT_INSTALL_DIR)\" @$(CPY) "$(ROOT)\library\safe.tcl" "$(SCRIPT_INSTALL_DIR)\" @$(CPY) "$(ROOT)\library\tclIndex" "$(SCRIPT_INSTALL_DIR)\" @$(CPY) "$(ROOT)\library\package.tcl" "$(SCRIPT_INSTALL_DIR)\" @$(CPY) "$(ROOT)\library\word.tcl" "$(SCRIPT_INSTALL_DIR)\" @$(CPY) "$(ROOT)\library\auto.tcl" "$(SCRIPT_INSTALL_DIR)\" #--------------------------------------------------------------------- # Clean up #--------------------------------------------------------------------- tidy: @echo Removing $(TCLLIB) ... @if exist $(TCLLIB) del $(TCLLIB) @echo Removing $(TCLSH) ... @if exist $(TCLSH) del $(TCLSH) @echo Removing $(TCLTEST) ... @if exist $(TCLTEST) del $(TCLTEST) @echo Removing $(TCLDDELIB) ... @if exist $(TCLDDELIB) del $(TCLDDELIB) @echo Removing $(TCLREGLIB) ... @if exist $(TCLREGLIB) del $(TCLREGLIB) clean: @echo Cleaning $(TMP_DIR)\* ... @if exist $(TMP_DIR)\nul $(RMDIR) $(TMP_DIR) hose: @echo Hosing $(OUT_DIR)\* ... @if exist $(OUT_DIR)\nul $(RMDIR) $(OUT_DIR) tcl8.4.20/win/tclWinSock.c0000644003604700454610000023136012052456744013744 0ustar dgp771div/* * tclWinSock.c -- * * This file contains Windows-specific socket related code. * * Copyright (c) 1995-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * ----------------------------------------------------------------------- * * General information on how this module works. * * - Each Tcl-thread with its sockets maintains an internal window to receive * socket messages from the OS. * * - To ensure that message reception is always running this window is * actually owned and handled by an internal thread. This we call the * co-thread of Tcl's thread. * * - The whole structure is set up by InitSockets() which is called for each * Tcl thread. The implementation of the co-thread is in SocketThread(), * and the messages are handled by SocketProc(). The connection between * both is not directly visible, it is done through a Win32 window class. * This class is initialized by InitSockets() as well, and used in the * creation of the message receiver windows. * * - An important thing to note is that *both* thread and co-thread have * access to the list of sockets maintained in the private TSD data of the * thread. The co-thread was given access to it upon creation through the * new thread's client-data. * * Because of this dual access the TSD data contains an OS mutex, the * "socketListLock", to mediate exclusion between thread and co-thread. * * The co-thread's access is all in SocketProc(). The thread's access is * through SocketEventProc() (1) and the functions called by it. * * (Ad 1) This is the handler function for all queued socket events, which * all the OS messages are translated to through the EventSource (2) * driven by the OS messages. * * (Ad 2) The main functions for this are SocketSetupProc() and * SocketCheckProc(). */ #include "tclWinInt.h" /* * Make sure to remove the redirection defines set in tclWinPort.h * that is in use in other sections of the core, except for us. */ #undef getservbyname #undef getsockopt #undef ntohs #undef setsockopt /* * The following variable is used to tell whether this module has been * initialized. */ static int initialized = 0; static int hostnameInitialized = 0; static char hostname[255]; /* This buffer should be big enough for * hostname plus domain name. */ TCL_DECLARE_MUTEX(socketMutex) /* * Mingw and Cygwin may not have LPFN_* typedefs. */ #ifdef HAVE_NO_LPFN_DECLS typedef SOCKET (PASCAL FAR *LPFN_ACCEPT)(SOCKET s, struct sockaddr FAR * addr, int FAR * addrlen); typedef int (PASCAL FAR *LPFN_BIND)(SOCKET s, const struct sockaddr FAR *addr, int namelen); typedef int (PASCAL FAR *LPFN_CLOSESOCKET)(SOCKET s); typedef int (PASCAL FAR *LPFN_CONNECT)(SOCKET s, const struct sockaddr FAR *name, int namelen); typedef struct hostent FAR * (PASCAL FAR *LPFN_GETHOSTBYADDR) (const char FAR *addr, int addrlen, int addrtype); typedef struct hostent FAR * (PASCAL FAR *LPFN_GETHOSTBYNAME) (const char FAR * name); typedef int (PASCAL FAR *LPFN_GETHOSTNAME)(char FAR * name, int namelen); typedef int (PASCAL FAR *LPFN_GETPEERNAME)(SOCKET sock, struct sockaddr FAR *name, int FAR *namelen); typedef struct servent FAR * (PASCAL FAR *LPFN_GETSERVBYNAME) (const char FAR * name, const char FAR * proto); typedef int (PASCAL FAR *LPFN_GETSOCKNAME)(SOCKET sock, struct sockaddr FAR *name, int FAR *namelen); typedef int (PASCAL FAR *LPFN_GETSOCKOPT)(SOCKET s, int level, int optname, char FAR * optval, int FAR *optlen); typedef unsigned short (PASCAL FAR *LPFN_HTONS)(unsigned short hostshort); typedef unsigned long (PASCAL FAR *LPFN_INET_ADDR) (const char FAR * cp); typedef char FAR * (PASCAL FAR *LPFN_INET_NTOA) (struct in_addr in); typedef int (PASCAL FAR *LPFN_IOCTLSOCKET)(SOCKET s, long cmd, u_long FAR *argp); typedef int (PASCAL FAR *LPFN_LISTEN)(SOCKET s, int backlog); typedef unsigned short (PASCAL FAR *LPFN_NTOHS)(unsigned short netshort); typedef int (PASCAL FAR *LPFN_RECV)(SOCKET s, char FAR * buf, int len, int flags); typedef int (PASCAL FAR *LPFN_SELECT)(int nfds, fd_set FAR * readfds, fd_set FAR * writefds, fd_set FAR * exceptfds, const struct timeval FAR * timeout); typedef int (PASCAL FAR *LPFN_SEND)(SOCKET s, const char FAR * buf, int len, int flags); typedef int (PASCAL FAR *LPFN_SETSOCKOPT)(SOCKET s, int level, int optname, const char FAR * optval, int optlen); typedef SOCKET (PASCAL FAR *LPFN_SOCKET)(int af, int type, int protocol); typedef int (PASCAL FAR *LPFN_WSAASYNCSELECT)(SOCKET s, HWND hWnd, u_int wMsg, long lEvent); typedef int (PASCAL FAR *LPFN_WSACLEANUP)(void); typedef int (PASCAL FAR *LPFN_WSAGETLASTERROR)(void); typedef int (PASCAL FAR *LPFN_WSASTARTUP)(WORD wVersionRequired, LPWSADATA lpWSAData); #endif /* * The following structure contains pointers to all of the WinSock API * entry points used by Tcl. It is initialized by InitSockets. Since * we dynamically load the Winsock DLL on demand, we must use this * function table to refer to functions in the winsock API. */ static struct { HMODULE hModule; /* Handle to WinSock library. */ /* Winsock 1.1 functions */ LPFN_ACCEPT accept; LPFN_BIND bind; LPFN_CLOSESOCKET closesocket; LPFN_CONNECT connect; LPFN_GETHOSTBYADDR gethostbyaddr; LPFN_GETHOSTBYNAME gethostbyname; LPFN_GETHOSTNAME gethostname; LPFN_GETPEERNAME getpeername; LPFN_GETSERVBYNAME getservbyname; LPFN_GETSOCKNAME getsockname; LPFN_GETSOCKOPT getsockopt; LPFN_HTONS htons; LPFN_INET_ADDR inet_addr; LPFN_INET_NTOA inet_ntoa; LPFN_IOCTLSOCKET ioctlsocket; LPFN_LISTEN listen; LPFN_NTOHS ntohs; LPFN_RECV recv; LPFN_SELECT select; LPFN_SEND send; LPFN_SETSOCKOPT setsockopt; LPFN_SOCKET socket; LPFN_WSAASYNCSELECT WSAAsyncSelect; LPFN_WSACLEANUP WSACleanup; LPFN_WSAGETLASTERROR WSAGetLastError; LPFN_WSASTARTUP WSAStartup; } winSock; /* * The following defines declare the messages used on socket windows. */ #define SOCKET_MESSAGE WM_USER+1 #define SOCKET_SELECT WM_USER+2 #define SOCKET_TERMINATE WM_USER+3 #define SELECT TRUE #define UNSELECT FALSE /* * The following structure is used to store the data associated with * each socket. */ typedef struct SocketInfo { Tcl_Channel channel; /* Channel associated with this * socket. */ SOCKET socket; /* Windows SOCKET handle. */ int flags; /* Bit field comprised of the flags * described below. */ int watchEvents; /* OR'ed combination of FD_READ, * FD_WRITE, FD_CLOSE, FD_ACCEPT and * FD_CONNECT that indicate which * events are interesting. */ int readyEvents; /* OR'ed combination of FD_READ, * FD_WRITE, FD_CLOSE, FD_ACCEPT and * FD_CONNECT that indicate which * events have occurred. */ int selectEvents; /* OR'ed combination of FD_READ, * FD_WRITE, FD_CLOSE, FD_ACCEPT and * FD_CONNECT that indicate which * events are currently being * selected. */ int acceptEventCount; /* Count of the current number of * FD_ACCEPTs that have arrived and * not yet processed. */ Tcl_TcpAcceptProc *acceptProc; /* Proc to call on accept. */ ClientData acceptProcData; /* The data for the accept proc. */ int lastError; /* Error code from last message. */ struct SocketInfo *nextPtr; /* The next socket on the per-thread * socket list. */ } SocketInfo; /* * The following structure is what is added to the Tcl event queue when * a socket event occurs. */ typedef struct SocketEvent { Tcl_Event header; /* Information that is standard for * all events. */ SOCKET socket; /* Socket descriptor that is ready. Used * to find the SocketInfo structure for * the file (can't point directly to the * SocketInfo structure because it could * go away while the event is queued). */ } SocketEvent; /* * This defines the minimum buffersize maintained by the kernel. */ #define TCP_BUFFER_SIZE 4096 /* * The following macros may be used to set the flags field of * a SocketInfo structure. */ #define SOCKET_ASYNC (1<<0) /* The socket is in blocking * mode. */ #define SOCKET_EOF (1<<1) /* A zero read happened on * the socket. */ #define SOCKET_ASYNC_CONNECT (1<<2) /* This socket uses async * connect. */ #define SOCKET_PENDING (1<<3) /* A message has been sent * for this socket */ typedef struct ThreadSpecificData { HWND hwnd; /* Handle to window for socket messages. */ HANDLE socketThread; /* Thread handling the window */ Tcl_ThreadId threadId; /* Parent thread. */ HANDLE readyEvent; /* Event indicating that a socket event is * ready. Also used to indicate that the * socketThread has been initialized and has * started. */ HANDLE socketListLock; /* Win32 Event to lock the socketList */ SocketInfo *socketList; /* Every open socket in this thread has an * entry on this list. */ } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; static WNDCLASS windowClass; /* * Static functions defined in this file. */ static SocketInfo * CreateSocket _ANSI_ARGS_((Tcl_Interp *interp, int port, CONST char *host, int server, CONST char *myaddr, int myport, int async)); static int CreateSocketAddress _ANSI_ARGS_( (LPSOCKADDR_IN sockaddrPtr, CONST char *host, int port)); static void InitSockets _ANSI_ARGS_((void)); static SocketInfo * NewSocketInfo _ANSI_ARGS_((SOCKET socket)); static Tcl_EventCheckProc SocketCheckProc; static Tcl_EventProc SocketEventProc; static void SocketExitHandler _ANSI_ARGS_(( ClientData clientData)); static LRESULT CALLBACK SocketProc _ANSI_ARGS_((HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)); static Tcl_EventSetupProc SocketSetupProc; static int SocketsEnabled _ANSI_ARGS_((void)); static void TcpAccept _ANSI_ARGS_((SocketInfo *infoPtr)); static Tcl_DriverBlockModeProc TcpBlockProc; static Tcl_DriverCloseProc TcpCloseProc; static Tcl_DriverSetOptionProc TcpSetOptionProc; static Tcl_DriverGetOptionProc TcpGetOptionProc; static Tcl_DriverInputProc TcpInputProc; static Tcl_DriverOutputProc TcpOutputProc; static Tcl_DriverWatchProc TcpWatchProc; static Tcl_DriverGetHandleProc TcpGetHandleProc; static int WaitForSocketEvent _ANSI_ARGS_(( SocketInfo *infoPtr, int events, int *errorCodePtr)); static DWORD WINAPI SocketThread _ANSI_ARGS_((LPVOID arg)); static void TcpThreadActionProc _ANSI_ARGS_ (( ClientData instanceData, int action)); /* * This structure describes the channel type structure for TCP socket * based IO. */ static Tcl_ChannelType tcpChannelType = { "tcp", /* Type name. */ TCL_CHANNEL_VERSION_4, /* v4 channel */ TcpCloseProc, /* Close proc. */ TcpInputProc, /* Input proc. */ TcpOutputProc, /* Output proc. */ NULL, /* Seek proc. */ TcpSetOptionProc, /* Set option proc. */ TcpGetOptionProc, /* Get option proc. */ TcpWatchProc, /* Set up notifier to watch this channel. */ TcpGetHandleProc, /* Get an OS handle from channel. */ NULL, /* close2proc. */ TcpBlockProc, /* Set socket into (non-)blocking mode. */ NULL, /* flush proc. */ NULL, /* handler proc. */ NULL, /* wide seek proc */ TcpThreadActionProc, /* thread action proc */ }; /* *---------------------------------------------------------------------- * * InitSockets -- * * Initialize the socket module. Attempts to load the wsock32.dll * library and set up the winSock function table. If successful, * registers the event window for the socket notifier code. * * Assumes socketMutex is held. * * Results: * None. * * Side effects: * Dynamically loads wsock32.dll, and registers a new window * class and creates a window for use in asynchronous socket * notification. * *---------------------------------------------------------------------- */ static void InitSockets() { DWORD id; WSADATA wsaData; DWORD err; ThreadSpecificData *tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); if (!initialized) { initialized = 1; TclCreateLateExitHandler(SocketExitHandler, (ClientData) NULL); winSock.hModule = LoadLibraryA("wsock32.dll"); if (winSock.hModule == NULL) { return; } /* * Initialize the function table. */ winSock.accept = (LPFN_ACCEPT) GetProcAddress(winSock.hModule, "accept"); winSock.bind = (LPFN_BIND) GetProcAddress(winSock.hModule, "bind"); winSock.closesocket = (LPFN_CLOSESOCKET) GetProcAddress(winSock.hModule, "closesocket"); winSock.connect = (LPFN_CONNECT) GetProcAddress(winSock.hModule, "connect"); winSock.gethostbyaddr = (LPFN_GETHOSTBYADDR) GetProcAddress(winSock.hModule, "gethostbyaddr"); winSock.gethostbyname = (LPFN_GETHOSTBYNAME) GetProcAddress(winSock.hModule, "gethostbyname"); winSock.gethostname = (LPFN_GETHOSTNAME) GetProcAddress(winSock.hModule, "gethostname"); winSock.getpeername = (LPFN_GETPEERNAME) GetProcAddress(winSock.hModule, "getpeername"); winSock.getservbyname = (LPFN_GETSERVBYNAME) GetProcAddress(winSock.hModule, "getservbyname"); winSock.getsockname = (LPFN_GETSOCKNAME) GetProcAddress(winSock.hModule, "getsockname"); winSock.getsockopt = (LPFN_GETSOCKOPT) GetProcAddress(winSock.hModule, "getsockopt"); winSock.htons = (LPFN_HTONS) GetProcAddress(winSock.hModule, "htons"); winSock.inet_addr = (LPFN_INET_ADDR) GetProcAddress(winSock.hModule, "inet_addr"); winSock.inet_ntoa = (LPFN_INET_NTOA) GetProcAddress(winSock.hModule, "inet_ntoa"); winSock.ioctlsocket = (LPFN_IOCTLSOCKET) GetProcAddress(winSock.hModule, "ioctlsocket"); winSock.listen = (LPFN_LISTEN) GetProcAddress(winSock.hModule, "listen"); winSock.ntohs = (LPFN_NTOHS) GetProcAddress(winSock.hModule, "ntohs"); winSock.recv = (LPFN_RECV) GetProcAddress(winSock.hModule, "recv"); winSock.select = (LPFN_SELECT) GetProcAddress(winSock.hModule, "select"); winSock.send = (LPFN_SEND) GetProcAddress(winSock.hModule, "send"); winSock.setsockopt = (LPFN_SETSOCKOPT) GetProcAddress(winSock.hModule, "setsockopt"); winSock.socket = (LPFN_SOCKET) GetProcAddress(winSock.hModule, "socket"); winSock.WSAAsyncSelect = (LPFN_WSAASYNCSELECT) GetProcAddress(winSock.hModule, "WSAAsyncSelect"); winSock.WSACleanup = (LPFN_WSACLEANUP) GetProcAddress(winSock.hModule, "WSACleanup"); winSock.WSAGetLastError = (LPFN_WSAGETLASTERROR) GetProcAddress(winSock.hModule, "WSAGetLastError"); winSock.WSAStartup = (LPFN_WSASTARTUP) GetProcAddress(winSock.hModule, "WSAStartup"); /* * Now check that all fields are properly initialized. If not, * return zero to indicate that we failed to initialize * properly. */ if ((winSock.accept == NULL) || (winSock.bind == NULL) || (winSock.closesocket == NULL) || (winSock.connect == NULL) || (winSock.gethostbyname == NULL) || (winSock.gethostbyaddr == NULL) || (winSock.gethostname == NULL) || (winSock.getpeername == NULL) || (winSock.getservbyname == NULL) || (winSock.getsockname == NULL) || (winSock.getsockopt == NULL) || (winSock.htons == NULL) || (winSock.inet_addr == NULL) || (winSock.inet_ntoa == NULL) || (winSock.ioctlsocket == NULL) || (winSock.listen == NULL) || (winSock.ntohs == NULL) || (winSock.recv == NULL) || (winSock.select == NULL) || (winSock.send == NULL) || (winSock.setsockopt == NULL) || (winSock.socket == NULL) || (winSock.WSAAsyncSelect == NULL) || (winSock.WSACleanup == NULL) || (winSock.WSAGetLastError == NULL) || (winSock.WSAStartup == NULL)) { goto unloadLibrary; } /* * Create the async notification window with a new class. We * must create a new class to avoid a Windows 95 bug that causes * us to get the wrong message number for socket events if the * message window is a subclass of a static control. */ windowClass.style = 0; windowClass.cbClsExtra = 0; windowClass.cbWndExtra = 0; windowClass.hInstance = TclWinGetTclInstance(); windowClass.hbrBackground = NULL; windowClass.lpszMenuName = NULL; windowClass.lpszClassName = "TclSocket"; windowClass.lpfnWndProc = SocketProc; windowClass.hIcon = NULL; windowClass.hCursor = NULL; if (!RegisterClassA(&windowClass)) { TclWinConvertError(GetLastError()); goto unloadLibrary; } /* * Initialize the winsock library and check the interface * version actually loaded. We only ask for the 1.1 interface * and do require that it not be less than 1.1. */ #define WSA_VERSION_MAJOR 1 #define WSA_VERSION_MINOR 1 #define WSA_VERSION_REQD MAKEWORD(WSA_VERSION_MAJOR, WSA_VERSION_MINOR) if ((err = winSock.WSAStartup(WSA_VERSION_REQD, &wsaData)) != 0) { TclWinConvertWSAError(err); goto unloadLibrary; } /* * Note the byte positions are swapped for the comparison, so * that 0x0002 (2.0, MAKEWORD(2,0)) doesn't look less than 0x0101 * (1.1). We want the comparison to be 0x0200 < 0x0101. */ if (MAKEWORD(HIBYTE(wsaData.wVersion), LOBYTE(wsaData.wVersion)) < MAKEWORD(WSA_VERSION_MINOR, WSA_VERSION_MAJOR)) { TclWinConvertWSAError(WSAVERNOTSUPPORTED); winSock.WSACleanup(); goto unloadLibrary; } #undef WSA_VERSION_REQD #undef WSA_VERSION_MAJOR #undef WSA_VERSION_MINOR } /* * Check for per-thread initialization. */ if (tsdPtr == NULL) { tsdPtr = TCL_TSD_INIT(&dataKey); tsdPtr->socketList = NULL; tsdPtr->hwnd = NULL; tsdPtr->threadId = Tcl_GetCurrentThread(); tsdPtr->readyEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if (tsdPtr->readyEvent == NULL) { goto unloadLibrary; } tsdPtr->socketListLock = CreateEvent(NULL, FALSE, TRUE, NULL); if (tsdPtr->socketListLock == NULL) { goto unloadLibrary; } tsdPtr->socketThread = CreateThread(NULL, 256, SocketThread, tsdPtr, 0, &id); if (tsdPtr->socketThread == NULL) { goto unloadLibrary; } SetThreadPriority(tsdPtr->socketThread, THREAD_PRIORITY_HIGHEST); /* * Wait for the thread to signal when the window has * been created and if it is ready to go. */ WaitForSingleObject(tsdPtr->readyEvent, INFINITE); if (tsdPtr->hwnd == NULL) { goto unloadLibrary; /* Trouble creating the window */ } Tcl_CreateEventSource(SocketSetupProc, SocketCheckProc, NULL); } return; unloadLibrary: TclpFinalizeSockets(); FreeLibrary(winSock.hModule); winSock.hModule = NULL; return; } /* *---------------------------------------------------------------------- * * SocketsEnabled -- * * Check that the WinSock DLL is loaded and ready. * * Results: * 1 if it is. * * Side effects: * None. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int SocketsEnabled() { int enabled; Tcl_MutexLock(&socketMutex); enabled = (winSock.hModule != NULL); Tcl_MutexUnlock(&socketMutex); return enabled; } /* *---------------------------------------------------------------------- * * SocketExitHandler -- * * Callback invoked during app exit clean up to delete the socket * communication window and to release the WinSock DLL. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static void SocketExitHandler(clientData) ClientData clientData; /* Not used. */ { Tcl_MutexLock(&socketMutex); if (winSock.hModule) { /* * Make sure the socket event handling window is cleaned-up * for, at most, this thread. */ TclpFinalizeSockets(); UnregisterClass("TclSocket", TclWinGetTclInstance()); winSock.WSACleanup(); FreeLibrary(winSock.hModule); winSock.hModule = NULL; } initialized = 0; hostnameInitialized = 0; Tcl_MutexUnlock(&socketMutex); } /* *---------------------------------------------------------------------- * * TclpFinalizeSockets -- * * This function is called from Tcl_FinalizeThread to finalize * the platform specific socket subsystem. * Also, it may be called from within this module to cleanup * the state if unable to initialize the sockets subsystem. * * Results: * None. * * Side effects: * Deletes the event source and destroys the socket thread. * *---------------------------------------------------------------------- */ void TclpFinalizeSockets() { ThreadSpecificData *tsdPtr; tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); if (tsdPtr != NULL) { if (tsdPtr->socketThread != NULL) { if (tsdPtr->hwnd != NULL) { if (PostMessage(tsdPtr->hwnd, SOCKET_TERMINATE, 0, 0)) { /* * Wait for the thread to exit. This ensures that we are * completely cleaned up before we leave this function. */ WaitForSingleObject(tsdPtr->readyEvent, INFINITE); } tsdPtr->hwnd = NULL; } CloseHandle(tsdPtr->socketThread); tsdPtr->socketThread = NULL; } if (tsdPtr->readyEvent != NULL) { CloseHandle(tsdPtr->readyEvent); tsdPtr->readyEvent = NULL; } if (tsdPtr->socketListLock != NULL) { CloseHandle(tsdPtr->socketListLock); tsdPtr->socketListLock = NULL; } Tcl_DeleteEventSource(SocketSetupProc, SocketCheckProc, NULL); } } /* *---------------------------------------------------------------------- * * TclpHasSockets -- * * This function determines whether sockets are available on the * current system and returns an error in interp if they are not. * Note that interp may be NULL. * * Results: * Returns TCL_OK if the system supports sockets, or TCL_ERROR with * an error in interp. * * Side effects: * If not already prepared, initializes the TSD structure and * socket message handling thread associated to the calling thread * for the subsystem of the driver. * *---------------------------------------------------------------------- */ int TclpHasSockets(interp) Tcl_Interp *interp; { Tcl_MutexLock(&socketMutex); InitSockets(); Tcl_MutexUnlock(&socketMutex); if (SocketsEnabled()) { return TCL_OK; } if (interp != NULL) { Tcl_AppendResult(interp, "sockets are not available on this system", NULL); } return TCL_ERROR; } /* *---------------------------------------------------------------------- * * SocketSetupProc -- * * This procedure is invoked before Tcl_DoOneEvent blocks waiting * for an event. * * Results: * None. * * Side effects: * Adjusts the block time if needed. * *---------------------------------------------------------------------- */ void SocketSetupProc(data, flags) ClientData data; /* Not used. */ int flags; /* Event flags as passed to Tcl_DoOneEvent. */ { SocketInfo *infoPtr; Tcl_Time blockTime = { 0, 0 }; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (!(flags & TCL_FILE_EVENTS)) { return; } /* * Check to see if there is a ready socket. If so, poll. */ WaitForSingleObject(tsdPtr->socketListLock, INFINITE); for (infoPtr = tsdPtr->socketList; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { if (infoPtr->readyEvents & infoPtr->watchEvents) { Tcl_SetMaxBlockTime(&blockTime); break; } } SetEvent(tsdPtr->socketListLock); } /* *---------------------------------------------------------------------- * * SocketCheckProc -- * * This procedure is called by Tcl_DoOneEvent to check the socket * event source for events. * * Results: * None. * * Side effects: * May queue an event. * *---------------------------------------------------------------------- */ static void SocketCheckProc(data, flags) ClientData data; /* Not used. */ int flags; /* Event flags as passed to Tcl_DoOneEvent. */ { SocketInfo *infoPtr; SocketEvent *evPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (!(flags & TCL_FILE_EVENTS)) { return; } /* * Queue events for any ready sockets that don't already have events * queued (caused by persistent states that won't generate WinSock * events). */ WaitForSingleObject(tsdPtr->socketListLock, INFINITE); for (infoPtr = tsdPtr->socketList; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { if ((infoPtr->readyEvents & infoPtr->watchEvents) && !(infoPtr->flags & SOCKET_PENDING)) { infoPtr->flags |= SOCKET_PENDING; evPtr = (SocketEvent *) ckalloc(sizeof(SocketEvent)); evPtr->header.proc = SocketEventProc; evPtr->socket = infoPtr->socket; Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL); } } SetEvent(tsdPtr->socketListLock); } /* *---------------------------------------------------------------------- * * SocketEventProc -- * * This procedure is called by Tcl_ServiceEvent when a socket event * reaches the front of the event queue. This procedure is * responsible for notifying the generic channel code. * * Results: * Returns 1 if the event was handled, meaning it should be removed * from the queue. Returns 0 if the event was not handled, meaning * it should stay on the queue. The only time the event isn't * handled is if the TCL_FILE_EVENTS flag bit isn't set. * * Side effects: * Whatever the channel callback procedures do. * *---------------------------------------------------------------------- */ static int SocketEventProc(evPtr, flags) Tcl_Event *evPtr; /* Event to service. */ int flags; /* Flags that indicate what events to * handle, such as TCL_FILE_EVENTS. */ { SocketInfo *infoPtr; SocketEvent *eventPtr = (SocketEvent *) evPtr; int mask = 0; int events; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (!(flags & TCL_FILE_EVENTS)) { return 0; } /* * Find the specified socket on the socket list. */ WaitForSingleObject(tsdPtr->socketListLock, INFINITE); for (infoPtr = tsdPtr->socketList; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { if (infoPtr->socket == eventPtr->socket) { break; } } SetEvent(tsdPtr->socketListLock); /* * Discard events that have gone stale. */ if (!infoPtr) { return 1; } infoPtr->flags &= ~SOCKET_PENDING; /* * Handle connection requests directly. */ if (infoPtr->readyEvents & FD_ACCEPT) { TcpAccept(infoPtr); return 1; } /* * Mask off unwanted events and compute the read/write mask so * we can notify the channel. */ events = infoPtr->readyEvents & infoPtr->watchEvents; if (events & FD_CLOSE) { /* * If the socket was closed and the channel is still interested * in read events, then we need to ensure that we keep polling * for this event until someone does something with the channel. * Note that we do this before calling Tcl_NotifyChannel so we don't * have to watch out for the channel being deleted out from under * us. This may cause a redundant trip through the event loop, but * it's simpler than trying to do unwind protection. */ Tcl_Time blockTime = { 0, 0 }; Tcl_SetMaxBlockTime(&blockTime); mask |= TCL_READABLE|TCL_WRITABLE; } else if (events & FD_READ) { fd_set readFds; struct timeval timeout; /* * We must check to see if data is really available, since someone * could have consumed the data in the meantime. Turn off async * notification so select will work correctly. If the socket is * still readable, notify the channel driver, otherwise reset the * async select handler and keep waiting. */ SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) UNSELECT, (LPARAM) infoPtr); FD_ZERO(&readFds); FD_SET(infoPtr->socket, &readFds); timeout.tv_usec = 0; timeout.tv_sec = 0; if (winSock.select(0, &readFds, NULL, NULL, &timeout) != 0) { mask |= TCL_READABLE; } else { infoPtr->readyEvents &= ~(FD_READ); SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT, (LPARAM) infoPtr); } } if (events & (FD_WRITE | FD_CONNECT)) { mask |= TCL_WRITABLE; if (events & FD_CONNECT && infoPtr->lastError != NO_ERROR) { /* connect errors should also fire the readable handler. */ mask |= TCL_READABLE; } } if (mask) { Tcl_NotifyChannel(infoPtr->channel, mask); } return 1; } /* *---------------------------------------------------------------------- * * TcpBlockProc -- * * Sets a socket into blocking or non-blocking mode. * * Results: * 0 if successful, errno if there was an error. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TcpBlockProc(instanceData, mode) ClientData instanceData; /* The socket to block/un-block. */ int mode; /* TCL_MODE_BLOCKING or * TCL_MODE_NONBLOCKING. */ { SocketInfo *infoPtr = (SocketInfo *) instanceData; if (mode == TCL_MODE_NONBLOCKING) { infoPtr->flags |= SOCKET_ASYNC; } else { infoPtr->flags &= ~(SOCKET_ASYNC); } return 0; } /* *---------------------------------------------------------------------- * * TcpCloseProc -- * * This procedure is called by the generic IO level to perform * channel type specific cleanup on a socket based channel * when the channel is closed. * * Results: * 0 if successful, the value of errno if failed. * * Side effects: * Closes the socket. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int TcpCloseProc(instanceData, interp) ClientData instanceData; /* The socket to close. */ Tcl_Interp *interp; /* Unused. */ { SocketInfo *infoPtr = (SocketInfo *) instanceData; /* TIP #218 */ int errorCode = 0; /* * Check that WinSock is initialized; do not call it if not, to * prevent system crashes. This can happen at exit time if the exit * handler for WinSock ran before other exit handlers that want to * use sockets. */ if (SocketsEnabled()) { /* * Clean up the OS socket handle. The default Windows setting * for a socket is SO_DONTLINGER, which does a graceful shutdown * in the background. */ if (winSock.closesocket(infoPtr->socket) == SOCKET_ERROR) { TclWinConvertWSAError((DWORD) winSock.WSAGetLastError()); errorCode = Tcl_GetErrno(); } } /* TIP #218. Removed the code removing the structure * from the global socket list. This is now done by * the thread action callbacks, and only there. This * happens before this code is called. We can free * without fear of damanging the list. */ ckfree((char *) infoPtr); return errorCode; } /* *---------------------------------------------------------------------- * * NewSocketInfo -- * * This function allocates and initializes a new SocketInfo * structure. * * Results: * Returns a newly allocated SocketInfo. * * Side effects: * None, except for allocation of memory. * *---------------------------------------------------------------------- */ static SocketInfo * NewSocketInfo(socket) SOCKET socket; { SocketInfo *infoPtr; infoPtr = (SocketInfo *) ckalloc((unsigned) sizeof(SocketInfo)); infoPtr->socket = socket; infoPtr->flags = 0; infoPtr->watchEvents = 0; infoPtr->readyEvents = 0; infoPtr->selectEvents = 0; infoPtr->acceptEventCount = 0; infoPtr->acceptProc = NULL; infoPtr->lastError = 0; /* TIP #218. Removed the code inserting the new structure * into the global list. This is now handled in the thread * action callbacks, and only there. */ infoPtr->nextPtr = NULL; return infoPtr; } /* *---------------------------------------------------------------------- * * CreateSocket -- * * This function opens a new socket and initializes the * SocketInfo structure. * * Results: * Returns a new SocketInfo, or NULL with an error in interp. * * Side effects: * None, except for allocation of memory. * *---------------------------------------------------------------------- */ static SocketInfo * CreateSocket(interp, port, host, server, myaddr, myport, async) Tcl_Interp *interp; /* For error reporting; can be NULL. */ int port; /* Port number to open. */ CONST char *host; /* Name of host on which to open port. */ int server; /* 1 if socket should be a server socket, * else 0 for a client socket. */ CONST char *myaddr; /* Optional client-side address */ int myport; /* Optional client-side port */ int async; /* If nonzero, connect client socket * asynchronously. */ { u_long flag = 1; /* Indicates nonblocking mode. */ int asyncConnect = 0; /* Will be 1 if async connect is * in progress. */ SOCKADDR_IN sockaddr; /* Socket address */ SOCKADDR_IN mysockaddr; /* Socket address for client */ SOCKET sock = INVALID_SOCKET; SocketInfo *infoPtr; /* The returned value. */ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); /* * Check that WinSock is initialized; do not call it if not, to * prevent system crashes. This can happen at exit time if the exit * handler for WinSock ran before other exit handlers that want to * use sockets. */ if (!SocketsEnabled()) { return NULL; } if (! CreateSocketAddress(&sockaddr, host, port)) { goto error; } if ((myaddr != NULL || myport != 0) && ! CreateSocketAddress(&mysockaddr, myaddr, myport)) { goto error; } sock = winSock.socket(AF_INET, SOCK_STREAM, 0); if (sock == INVALID_SOCKET) { goto error; } /* * Win-NT has a misfeature that sockets are inherited in child * processes by default. Turn off the inherit bit. */ SetHandleInformation( (HANDLE) sock, HANDLE_FLAG_INHERIT, 0 ); /* * Set kernel space buffering */ TclSockMinimumBuffers((void *)sock, TCP_BUFFER_SIZE); if (server) { /* * Bind to the specified port. Note that we must not call setsockopt * with SO_REUSEADDR because Microsoft allows addresses to be reused * even if they are still in use. * * Bind should not be affected by the socket having already been * set into nonblocking mode. If there is trouble, this is one place * to look for bugs. */ if (winSock.bind(sock, (SOCKADDR *) &sockaddr, sizeof(SOCKADDR_IN)) == SOCKET_ERROR) { goto error; } /* * Set the maximum number of pending connect requests to the * max value allowed on each platform (Win32 and Win32s may be * different, and there may be differences between TCP/IP stacks). */ if (winSock.listen(sock, SOMAXCONN) == SOCKET_ERROR) { goto error; } /* * Add this socket to the global list of sockets. */ infoPtr = NewSocketInfo(sock); /* * Set up the select mask for connection request events. */ infoPtr->selectEvents = FD_ACCEPT; infoPtr->watchEvents |= FD_ACCEPT; } else { /* * Try to bind to a local port, if specified. */ if (myaddr != NULL || myport != 0) { if (winSock.bind(sock, (SOCKADDR *) &mysockaddr, sizeof(SOCKADDR_IN)) == SOCKET_ERROR) { goto error; } } /* * Set the socket into nonblocking mode if the connect should be * done in the background. */ if (async) { if (winSock.ioctlsocket(sock, (long) FIONBIO, &flag) == SOCKET_ERROR) { goto error; } } /* * Attempt to connect to the remote socket. */ if (winSock.connect(sock, (SOCKADDR *) &sockaddr, sizeof(SOCKADDR_IN)) == SOCKET_ERROR) { TclWinConvertWSAError((DWORD) winSock.WSAGetLastError()); if (Tcl_GetErrno() != EWOULDBLOCK) { goto error; } /* * The connection is progressing in the background. */ asyncConnect = 1; } /* * Add this socket to the global list of sockets. */ infoPtr = NewSocketInfo(sock); /* * Set up the select mask for read/write events. If the connect * attempt has not completed, include connect events. */ infoPtr->selectEvents = FD_READ | FD_WRITE | FD_CLOSE; if (asyncConnect) { infoPtr->flags |= SOCKET_ASYNC_CONNECT; infoPtr->selectEvents |= FD_CONNECT; } } /* * Register for interest in events in the select mask. Note that this * automatically places the socket into non-blocking mode. */ winSock.ioctlsocket(sock, (long) FIONBIO, &flag); SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT, (LPARAM) infoPtr); return infoPtr; error: TclWinConvertWSAError((DWORD) winSock.WSAGetLastError()); if (interp != NULL) { Tcl_AppendResult(interp, "couldn't open socket: ", Tcl_PosixError(interp), (char *) NULL); } if (sock != INVALID_SOCKET) { winSock.closesocket(sock); } return NULL; } /* *---------------------------------------------------------------------- * * CreateSocketAddress -- * * This function initializes a sockaddr structure for a host and port. * * Results: * 1 if the host was valid, 0 if the host could not be converted to * an IP address. * * Side effects: * Fills in the *sockaddrPtr structure. * *---------------------------------------------------------------------- */ static int CreateSocketAddress(sockaddrPtr, host, port) LPSOCKADDR_IN sockaddrPtr; /* Socket address */ CONST char *host; /* Host. NULL implies INADDR_ANY */ int port; /* Port number */ { struct hostent *hostent; /* Host database entry */ struct in_addr addr; /* For 64/32 bit madness */ /* * Check that WinSock is initialized; do not call it if not, to * prevent system crashes. This can happen at exit time if the exit * handler for WinSock ran before other exit handlers that want to * use sockets. */ if (!SocketsEnabled()) { Tcl_SetErrno(EFAULT); return 0; } ZeroMemory(sockaddrPtr, sizeof(SOCKADDR_IN)); sockaddrPtr->sin_family = AF_INET; sockaddrPtr->sin_port = winSock.htons((unsigned short) (port & 0xFFFF)); if (host == NULL) { addr.s_addr = INADDR_ANY; } else { addr.s_addr = winSock.inet_addr(host); if (addr.s_addr == INADDR_NONE) { hostent = winSock.gethostbyname(host); if (hostent != NULL) { memcpy(&addr, hostent->h_addr, (size_t) hostent->h_length); } else { #ifdef EHOSTUNREACH Tcl_SetErrno(EHOSTUNREACH); #else #ifdef ENXIO Tcl_SetErrno(ENXIO); #endif #endif return 0; /* Error. */ } } } /* * NOTE: On 64 bit machines the assignment below is rumored to not * do the right thing. Please report errors related to this if you * observe incorrect behavior on 64 bit machines such as DEC Alphas. * Should we modify this code to do an explicit memcpy? */ sockaddrPtr->sin_addr.s_addr = addr.s_addr; return 1; /* Success. */ } /* *---------------------------------------------------------------------- * * WaitForSocketEvent -- * * Waits until one of the specified events occurs on a socket. * * Results: * Returns 1 on success or 0 on failure, with an error code in * errorCodePtr. * * Side effects: * Processes socket events off the system queue. * *---------------------------------------------------------------------- */ static int WaitForSocketEvent(infoPtr, events, errorCodePtr) SocketInfo *infoPtr; /* Information about this socket. */ int events; /* Events to look for. */ int *errorCodePtr; /* Where to store errors? */ { int result = 1; int oldMode; ThreadSpecificData *tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); /* * Be sure to disable event servicing so we are truly modal. */ oldMode = Tcl_SetServiceMode(TCL_SERVICE_NONE); /* * Reset WSAAsyncSelect so we have a fresh set of events pending. */ SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) UNSELECT, (LPARAM) infoPtr); SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT, (LPARAM) infoPtr); while (1) { if (infoPtr->lastError) { *errorCodePtr = infoPtr->lastError; result = 0; break; } else if (infoPtr->readyEvents & events) { break; } else if (infoPtr->flags & SOCKET_ASYNC) { *errorCodePtr = EWOULDBLOCK; result = 0; break; } /* * Wait until something happens. */ WaitForSingleObject(tsdPtr->readyEvent, INFINITE); } (void) Tcl_SetServiceMode(oldMode); return result; } /* *---------------------------------------------------------------------- * * Tcl_OpenTcpClient -- * * Opens a TCP client socket and creates a channel around it. * * Results: * The channel or NULL if failed. An error message is returned * in the interpreter on failure. * * Side effects: * Opens a client socket and creates a new channel. * *---------------------------------------------------------------------- */ Tcl_Channel Tcl_OpenTcpClient(interp, port, host, myaddr, myport, async) Tcl_Interp *interp; /* For error reporting; can be NULL. */ int port; /* Port number to open. */ CONST char *host; /* Host on which to open port. */ CONST char *myaddr; /* Client-side address */ int myport; /* Client-side port */ int async; /* If nonzero, should connect * client socket asynchronously. */ { SocketInfo *infoPtr; char channelName[16 + TCL_INTEGER_SPACE]; if (TclpHasSockets(interp) != TCL_OK) { return NULL; } /* * Create a new client socket and wrap it in a channel. */ infoPtr = CreateSocket(interp, port, host, 0, myaddr, myport, async); if (infoPtr == NULL) { return NULL; } wsprintfA(channelName, "sock%d", infoPtr->socket); infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, (ClientData) infoPtr, (TCL_READABLE | TCL_WRITABLE)); if (Tcl_SetChannelOption(interp, infoPtr->channel, "-translation", "auto crlf") == TCL_ERROR) { Tcl_Close((Tcl_Interp *) NULL, infoPtr->channel); return (Tcl_Channel) NULL; } if (Tcl_SetChannelOption(NULL, infoPtr->channel, "-eofchar", "") == TCL_ERROR) { Tcl_Close((Tcl_Interp *) NULL, infoPtr->channel); return (Tcl_Channel) NULL; } return infoPtr->channel; } /* *---------------------------------------------------------------------- * * Tcl_MakeTcpClientChannel -- * * Creates a Tcl_Channel from an existing client TCP socket. * * Results: * The Tcl_Channel wrapped around the preexisting TCP socket. * * Side effects: * None. * * NOTE: Code contributed by Mark Diekhans (markd@grizzly.com) * *---------------------------------------------------------------------- */ Tcl_Channel Tcl_MakeTcpClientChannel(sock) ClientData sock; /* The socket to wrap up into a channel. */ { SocketInfo *infoPtr; char channelName[16 + TCL_INTEGER_SPACE]; ThreadSpecificData *tsdPtr; if (TclpHasSockets(NULL) != TCL_OK) { return NULL; } tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); /* * Set kernel space buffering and non-blocking. */ TclSockMinimumBuffers(sock, TCP_BUFFER_SIZE); infoPtr = NewSocketInfo((SOCKET) sock); /* * Start watching for read/write events on the socket. */ infoPtr->selectEvents = FD_READ | FD_CLOSE | FD_WRITE; SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT, (LPARAM) infoPtr); wsprintfA(channelName, "sock%d", infoPtr->socket); infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, (ClientData) infoPtr, (TCL_READABLE | TCL_WRITABLE)); Tcl_SetChannelOption(NULL, infoPtr->channel, "-translation", "auto crlf"); return infoPtr->channel; } /* *---------------------------------------------------------------------- * * Tcl_OpenTcpServer -- * * Opens a TCP server socket and creates a channel around it. * * Results: * The channel or NULL if failed. An error message is returned * in the interpreter on failure. * * Side effects: * Opens a server socket and creates a new channel. * *---------------------------------------------------------------------- */ Tcl_Channel Tcl_OpenTcpServer(interp, port, host, acceptProc, acceptProcData) Tcl_Interp *interp; /* For error reporting - may be * NULL. */ int port; /* Port number to open. */ CONST char *host; /* Name of local host. */ Tcl_TcpAcceptProc *acceptProc; /* Callback for accepting connections * from new clients. */ ClientData acceptProcData; /* Data for the callback. */ { SocketInfo *infoPtr; char channelName[16 + TCL_INTEGER_SPACE]; if (TclpHasSockets(interp) != TCL_OK) { return NULL; } /* * Create a new client socket and wrap it in a channel. */ infoPtr = CreateSocket(interp, port, host, 1, NULL, 0, 0); if (infoPtr == NULL) { return NULL; } infoPtr->acceptProc = acceptProc; infoPtr->acceptProcData = acceptProcData; wsprintfA(channelName, "sock%d", infoPtr->socket); infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, (ClientData) infoPtr, 0); if (Tcl_SetChannelOption(interp, infoPtr->channel, "-eofchar", "") == TCL_ERROR) { Tcl_Close((Tcl_Interp *) NULL, infoPtr->channel); return (Tcl_Channel) NULL; } return infoPtr->channel; } /* *---------------------------------------------------------------------- * * TcpAccept -- * Accept a TCP socket connection. This is called by * SocketEventProc and it in turns calls the registered accept * procedure. * * Results: * None. * * Side effects: * Invokes the accept proc which may invoke arbitrary Tcl code. * *---------------------------------------------------------------------- */ static void TcpAccept(infoPtr) SocketInfo *infoPtr; /* Socket to accept. */ { SOCKET newSocket; SocketInfo *newInfoPtr; SOCKADDR_IN addr; int len; char channelName[16 + TCL_INTEGER_SPACE]; ThreadSpecificData *tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); /* * Accept the incoming connection request. */ len = sizeof(SOCKADDR_IN); newSocket = winSock.accept(infoPtr->socket, (SOCKADDR *)&addr, &len); /* * Protect access to sockets (acceptEventCount, readyEvents) in socketList * by the lock. Fix for SF Tcl Bug 3056775. */ WaitForSingleObject(tsdPtr->socketListLock, INFINITE); /* * Clear the ready mask so we can detect the next connection request. * Note that connection requests are level triggered, so if there is * a request already pending, a new event will be generated. */ if (newSocket == INVALID_SOCKET) { infoPtr->acceptEventCount = 0; infoPtr->readyEvents &= ~(FD_ACCEPT); SetEvent(tsdPtr->socketListLock); return; } /* * It is possible that more than one FD_ACCEPT has been sent, so an extra * count must be kept. Decrement the count, and reset the readyEvent bit * if the count is no longer > 0. */ infoPtr->acceptEventCount--; if (infoPtr->acceptEventCount <= 0) { infoPtr->readyEvents &= ~(FD_ACCEPT); } SetEvent(tsdPtr->socketListLock); /* * Win-NT has a misfeature that sockets are inherited in child * processes by default. Turn off the inherit bit. */ SetHandleInformation( (HANDLE) newSocket, HANDLE_FLAG_INHERIT, 0 ); /* * Add this socket to the global list of sockets. */ newInfoPtr = NewSocketInfo(newSocket); /* * Select on read/write events and create the channel. */ newInfoPtr->selectEvents = (FD_READ | FD_WRITE | FD_CLOSE); SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT, (LPARAM) newInfoPtr); wsprintfA(channelName, "sock%d", newInfoPtr->socket); newInfoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, (ClientData) newInfoPtr, (TCL_READABLE | TCL_WRITABLE)); if (Tcl_SetChannelOption(NULL, newInfoPtr->channel, "-translation", "auto crlf") == TCL_ERROR) { Tcl_Close((Tcl_Interp *) NULL, newInfoPtr->channel); return; } if (Tcl_SetChannelOption(NULL, newInfoPtr->channel, "-eofchar", "") == TCL_ERROR) { Tcl_Close((Tcl_Interp *) NULL, newInfoPtr->channel); return; } /* * Invoke the accept callback procedure. */ if (infoPtr->acceptProc != NULL) { (infoPtr->acceptProc) (infoPtr->acceptProcData, newInfoPtr->channel, winSock.inet_ntoa(addr.sin_addr), winSock.ntohs(addr.sin_port)); } } /* *---------------------------------------------------------------------- * * TcpInputProc -- * * This procedure is called by the generic IO level to read data from * a socket based channel. * * Results: * The number of bytes read or -1 on error. * * Side effects: * Consumes input from the socket. * *---------------------------------------------------------------------- */ static int TcpInputProc(instanceData, buf, toRead, errorCodePtr) ClientData instanceData; /* The socket state. */ char *buf; /* Where to store data. */ int toRead; /* Maximum number of bytes to read. */ int *errorCodePtr; /* Where to store error codes. */ { SocketInfo *infoPtr = (SocketInfo *) instanceData; int bytesRead; DWORD error; ThreadSpecificData *tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); *errorCodePtr = 0; /* * Check that WinSock is initialized; do not call it if not, to * prevent system crashes. This can happen at exit time if the exit * handler for WinSock ran before other exit handlers that want to * use sockets. */ if (!SocketsEnabled()) { *errorCodePtr = EFAULT; return -1; } /* * First check to see if EOF was already detected, to prevent * calling the socket stack after the first time EOF is detected. */ if (infoPtr->flags & SOCKET_EOF) { return 0; } /* * Check to see if the socket is connected before trying to read. */ if ((infoPtr->flags & SOCKET_ASYNC_CONNECT) && ! WaitForSocketEvent(infoPtr, FD_CONNECT, errorCodePtr)) { return -1; } /* * No EOF, and it is connected, so try to read more from the socket. * Note that we clear the FD_READ bit because read events are level * triggered so a new event will be generated if there is still data * available to be read. We have to simulate blocking behavior here * since we are always using non-blocking sockets. */ while (1) { SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) UNSELECT, (LPARAM) infoPtr); bytesRead = winSock.recv(infoPtr->socket, buf, toRead, 0); infoPtr->readyEvents &= ~(FD_READ); /* * Check for end-of-file condition or successful read. */ if (bytesRead == 0) { infoPtr->flags |= SOCKET_EOF; } if (bytesRead != SOCKET_ERROR) { break; } /* * If an error occurs after the FD_CLOSE has arrived, * then ignore the error and report an EOF. */ if (infoPtr->readyEvents & FD_CLOSE) { infoPtr->flags |= SOCKET_EOF; bytesRead = 0; break; } error = winSock.WSAGetLastError(); /* * If an RST comes, then ignore the error and report an EOF just like * on unix. */ if (error == WSAECONNRESET) { infoPtr->flags |= SOCKET_EOF; bytesRead = 0; break; } /* * Check for error condition or underflow in non-blocking case. */ if ((infoPtr->flags & SOCKET_ASYNC) || (error != WSAEWOULDBLOCK)) { TclWinConvertWSAError(error); *errorCodePtr = Tcl_GetErrno(); bytesRead = -1; break; } /* * In the blocking case, wait until the file becomes readable * or closed and try again. */ if (!WaitForSocketEvent(infoPtr, FD_READ|FD_CLOSE, errorCodePtr)) { bytesRead = -1; break; } } SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT, (LPARAM) infoPtr); return bytesRead; } /* *---------------------------------------------------------------------- * * TcpOutputProc -- * * This procedure is called by the generic IO level to write data * to a socket based channel. * * Results: * The number of bytes written or -1 on failure. * * Side effects: * Produces output on the socket. * *---------------------------------------------------------------------- */ static int TcpOutputProc(instanceData, buf, toWrite, errorCodePtr) ClientData instanceData; /* The socket state. */ CONST char *buf; /* Where to get data. */ int toWrite; /* Maximum number of bytes to write. */ int *errorCodePtr; /* Where to store error codes. */ { SocketInfo *infoPtr = (SocketInfo *) instanceData; int bytesWritten; DWORD error; ThreadSpecificData *tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); *errorCodePtr = 0; /* * Check that WinSock is initialized; do not call it if not, to * prevent system crashes. This can happen at exit time if the exit * handler for WinSock ran before other exit handlers that want to * use sockets. */ if (!SocketsEnabled()) { *errorCodePtr = EFAULT; return -1; } /* * Check to see if the socket is connected before trying to write. */ if ((infoPtr->flags & SOCKET_ASYNC_CONNECT) && ! WaitForSocketEvent(infoPtr, FD_CONNECT, errorCodePtr)) { return -1; } while (1) { SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) UNSELECT, (LPARAM) infoPtr); bytesWritten = winSock.send(infoPtr->socket, buf, toWrite, 0); if (bytesWritten != SOCKET_ERROR) { /* * Since Windows won't generate a new write event until we hit * an overflow condition, we need to force the event loop to * poll until the condition changes. */ if (infoPtr->watchEvents & FD_WRITE) { Tcl_Time blockTime = { 0, 0 }; Tcl_SetMaxBlockTime(&blockTime); } break; } /* * Check for error condition or overflow. In the event of overflow, we * need to clear the FD_WRITE flag so we can detect the next writable * event. Note that Windows only sends a new writable event after a * send fails with WSAEWOULDBLOCK. */ error = winSock.WSAGetLastError(); if (error == WSAEWOULDBLOCK) { infoPtr->readyEvents &= ~(FD_WRITE); if (infoPtr->flags & SOCKET_ASYNC) { *errorCodePtr = EWOULDBLOCK; bytesWritten = -1; break; } } else { TclWinConvertWSAError(error); *errorCodePtr = Tcl_GetErrno(); bytesWritten = -1; break; } /* * In the blocking case, wait until the file becomes writable * or closed and try again. */ if (!WaitForSocketEvent(infoPtr, FD_WRITE|FD_CLOSE, errorCodePtr)) { bytesWritten = -1; break; } } SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT, (LPARAM) infoPtr); return bytesWritten; } /* *---------------------------------------------------------------------- * * TcpSetOptionProc -- * * Sets Tcp channel specific options. * * Results: * None, unless an error happens. * * Side effects: * Changes attributes of the socket at the system level. * *---------------------------------------------------------------------- */ static int TcpSetOptionProc ( ClientData instanceData, /* Socket state. */ Tcl_Interp *interp, /* For error reporting - can be NULL. */ CONST char *optionName, /* Name of the option to set. */ CONST char *value) /* New value for option. */ { /* SocketInfo *infoPtr; SOCKET sock; BOOL val = FALSE; int boolVar, rtn; */ /* * Check that WinSock is initialized; do not call it if not, to * prevent system crashes. This can happen at exit time if the exit * handler for WinSock ran before other exit handlers that want to * use sockets. */ if (!SocketsEnabled()) { if (interp) { Tcl_AppendResult(interp, "winsock is not initialized", NULL); } return TCL_ERROR; } /* infoPtr = (SocketInfo *) instanceData; sock = infoPtr->socket; if (!stricmp(optionName, "-keepalive")) { if (Tcl_GetBoolean(interp, value, &boolVar) != TCL_OK) { return TCL_ERROR; } if (boolVar) val = TRUE; rtn = winSock.setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (const char *) &val, sizeof(BOOL)); if (rtn != 0) { TclWinConvertWSAError(winSock.WSAGetLastError()); if (interp) { Tcl_AppendResult(interp, "couldn't set socket option: ", Tcl_PosixError(interp), NULL); } return TCL_ERROR; } return TCL_OK; } else if (!stricmp(optionName, "-nagle")) { if (Tcl_GetBoolean(interp, value, &boolVar) != TCL_OK) { return TCL_ERROR; } if (!boolVar) val = TRUE; rtn = winSock.setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (const char *) &val, sizeof(BOOL)); if (rtn != 0) { TclWinConvertWSAError(winSock.WSAGetLastError()); if (interp) { Tcl_AppendResult(interp, "couldn't set socket option: ", Tcl_PosixError(interp), NULL); } return TCL_ERROR; } return TCL_OK; } return Tcl_BadChannelOption(interp, optionName, "keepalive nagle"); */ return Tcl_BadChannelOption(interp, optionName, ""); } /* *---------------------------------------------------------------------- * * TcpGetOptionProc -- * * Computes an option value for a TCP socket based channel, or a * list of all options and their values. * * Note: This code is based on code contributed by John Haxby. * * Results: * A standard Tcl result. The value of the specified option or a * list of all options and their values is returned in the * supplied DString. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TcpGetOptionProc(instanceData, interp, optionName, dsPtr) ClientData instanceData; /* Socket state. */ Tcl_Interp *interp; /* For error reporting - can be NULL */ CONST char *optionName; /* Name of the option to * retrieve the value for, or * NULL to get all options and * their values. */ Tcl_DString *dsPtr; /* Where to store the computed * value; initialized by caller. */ { SocketInfo *infoPtr; SOCKADDR_IN sockname; SOCKADDR_IN peername; struct hostent *hostEntPtr; SOCKET sock; int size = sizeof(SOCKADDR_IN); size_t len = 0; char buf[TCL_INTEGER_SPACE]; /* * Check that WinSock is initialized; do not call it if not, to * prevent system crashes. This can happen at exit time if the exit * handler for WinSock ran before other exit handlers that want to * use sockets. */ if (!SocketsEnabled()) { if (interp) { Tcl_AppendResult(interp, "winsock is not initialized", NULL); } return TCL_ERROR; } infoPtr = (SocketInfo *) instanceData; sock = (int) infoPtr->socket; if (optionName != (char *) NULL) { len = strlen(optionName); } if ((len > 1) && (optionName[1] == 'e') && (strncmp(optionName, "-error", len) == 0)) { int optlen; DWORD err; int ret; optlen = sizeof(int); ret = TclWinGetSockOpt(sock, SOL_SOCKET, SO_ERROR, (char *)&err, &optlen); if (ret == SOCKET_ERROR) { err = winSock.WSAGetLastError(); } if (err) { TclWinConvertWSAError(err); Tcl_DStringAppend(dsPtr, Tcl_ErrnoMsg(Tcl_GetErrno()), -1); } return TCL_OK; } if ((len == 0) || ((len > 1) && (optionName[1] == 'p') && (strncmp(optionName, "-peername", len) == 0))) { if (winSock.getpeername(sock, (LPSOCKADDR) &peername, &size) == 0) { if (len == 0) { Tcl_DStringAppendElement(dsPtr, "-peername"); Tcl_DStringStartSublist(dsPtr); } Tcl_DStringAppendElement(dsPtr, winSock.inet_ntoa(peername.sin_addr)); if (peername.sin_addr.s_addr == 0) { hostEntPtr = (struct hostent *) NULL; } else { hostEntPtr = winSock.gethostbyaddr( (char *) &(peername.sin_addr), sizeof(peername.sin_addr), AF_INET); } if (hostEntPtr != (struct hostent *) NULL) { Tcl_DStringAppendElement(dsPtr, hostEntPtr->h_name); } else { Tcl_DStringAppendElement(dsPtr, winSock.inet_ntoa(peername.sin_addr)); } TclFormatInt(buf, winSock.ntohs(peername.sin_port)); Tcl_DStringAppendElement(dsPtr, buf); if (len == 0) { Tcl_DStringEndSublist(dsPtr); } else { return TCL_OK; } } else { /* * getpeername failed - but if we were asked for all the options * (len==0), don't flag an error at that point because it could * be an fconfigure request on a server socket. (which have * no peer). {copied from unix/tclUnixChan.c} */ if (len) { TclWinConvertWSAError((DWORD) winSock.WSAGetLastError()); if (interp) { Tcl_AppendResult(interp, "can't get peername: ", Tcl_PosixError(interp), (char *) NULL); } return TCL_ERROR; } } } if ((len == 0) || ((len > 1) && (optionName[1] == 's') && (strncmp(optionName, "-sockname", len) == 0))) { if (winSock.getsockname(sock, (LPSOCKADDR) &sockname, &size) == 0) { if (len == 0) { Tcl_DStringAppendElement(dsPtr, "-sockname"); Tcl_DStringStartSublist(dsPtr); } Tcl_DStringAppendElement(dsPtr, winSock.inet_ntoa(sockname.sin_addr)); if (sockname.sin_addr.s_addr == 0) { hostEntPtr = (struct hostent *) NULL; } else { hostEntPtr = winSock.gethostbyaddr( (char *) &(sockname.sin_addr), sizeof(peername.sin_addr), AF_INET); } if (hostEntPtr != (struct hostent *) NULL) { Tcl_DStringAppendElement(dsPtr, hostEntPtr->h_name); } else { Tcl_DStringAppendElement(dsPtr, winSock.inet_ntoa(sockname.sin_addr)); } TclFormatInt(buf, winSock.ntohs(sockname.sin_port)); Tcl_DStringAppendElement(dsPtr, buf); if (len == 0) { Tcl_DStringEndSublist(dsPtr); } else { return TCL_OK; } } else { if (interp) { TclWinConvertWSAError((DWORD) winSock.WSAGetLastError()); Tcl_AppendResult(interp, "can't get sockname: ", Tcl_PosixError(interp), (char *) NULL); } return TCL_ERROR; } } /* if (len == 0 || !strncmp(optionName, "-keepalive", len)) { int optlen; BOOL opt = FALSE; if (len == 0) { Tcl_DStringAppendElement(dsPtr, "-keepalive"); } optlen = sizeof(BOOL); winSock.getsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&opt, &optlen); if (opt) { Tcl_DStringAppendElement(dsPtr, "1"); } else { Tcl_DStringAppendElement(dsPtr, "0"); } if (len > 0) return TCL_OK; } if (len == 0 || !strncmp(optionName, "-nagle", len)) { int optlen; BOOL opt = FALSE; if (len == 0) { Tcl_DStringAppendElement(dsPtr, "-nagle"); } optlen = sizeof(BOOL); winSock.getsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&opt, &optlen); if (opt) { Tcl_DStringAppendElement(dsPtr, "0"); } else { Tcl_DStringAppendElement(dsPtr, "1"); } if (len > 0) return TCL_OK; } */ if (len > 0) { /*return Tcl_BadChannelOption(interp, optionName, "peername sockname keepalive nagle");*/ return Tcl_BadChannelOption(interp, optionName, "peername sockname"); } return TCL_OK; } /* *---------------------------------------------------------------------- * * TcpWatchProc -- * * Informs the channel driver of the events that the generic * channel code wishes to receive on this socket. * * Results: * None. * * Side effects: * May cause the notifier to poll if any of the specified * conditions are already true. * *---------------------------------------------------------------------- */ static void TcpWatchProc(instanceData, mask) ClientData instanceData; /* The socket state. */ int mask; /* Events of interest; an OR-ed * combination of TCL_READABLE, * TCL_WRITABLE and TCL_EXCEPTION. */ { SocketInfo *infoPtr = (SocketInfo *) instanceData; /* * Update the watch events mask. Only if the socket is not a * server socket. Fix for SF Tcl Bug #557878. */ if (!infoPtr->acceptProc) { infoPtr->watchEvents = 0; if (mask & TCL_READABLE) { infoPtr->watchEvents |= (FD_READ|FD_CLOSE|FD_ACCEPT); } if (mask & TCL_WRITABLE) { infoPtr->watchEvents |= (FD_WRITE|FD_CLOSE|FD_CONNECT); } /* * If there are any conditions already set, then tell the notifier to poll * rather than block. */ if (infoPtr->readyEvents & infoPtr->watchEvents) { Tcl_Time blockTime = { 0, 0 }; Tcl_SetMaxBlockTime(&blockTime); } } } /* *---------------------------------------------------------------------- * * TcpGetProc -- * * Called from Tcl_GetChannelHandle to retrieve an OS handle from inside * a TCP socket based channel. * * Results: * Returns TCL_OK with the socket in handlePtr. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TcpGetHandleProc(instanceData, direction, handlePtr) ClientData instanceData; /* The socket state. */ int direction; /* Not used. */ ClientData *handlePtr; /* Where to store the handle. */ { SocketInfo *statePtr = (SocketInfo *) instanceData; *handlePtr = (ClientData) statePtr->socket; return TCL_OK; } /* *---------------------------------------------------------------------- * * SocketThread -- * * Helper thread used to manage the socket event handling window. * * Results: * 1 if unable to create socket event window, 0 otherwise. * * Side effects: * None. * *---------------------------------------------------------------------- */ static DWORD WINAPI SocketThread(LPVOID arg) { MSG msg; ThreadSpecificData *tsdPtr = (ThreadSpecificData *)(arg); /* * Create a dummy window receiving socket events. */ tsdPtr->hwnd = CreateWindow("TclSocket", "TclSocket", WS_TILED, 0, 0, 0, 0, NULL, NULL, windowClass.hInstance, arg); /* * Signalize thread creator that we are done creating the window. */ SetEvent(tsdPtr->readyEvent); /* * If unable to create the window, exit this thread immediately. */ if (tsdPtr->hwnd == NULL) { return 1; } /* * Process all messages on the socket window until WM_QUIT. * This threads exits only when instructed to do so by the * call to PostMessage(SOCKET_TERMINATE) in TclpFinalizeSockets(). */ while (GetMessage(&msg, NULL, 0, 0) > 0) { DispatchMessage(&msg); } /* * This releases waiters on thread exit in TclpFinalizeSockets() */ SetEvent(tsdPtr->readyEvent); return (DWORD)msg.wParam; } /* *---------------------------------------------------------------------- * * SocketProc -- * * This function is called when WSAAsyncSelect has been used * to register interest in a socket event, and the event has * occurred. * * Results: * 0 on success. * * Side effects: * The flags for the given socket are updated to reflect the * event that occured. * *---------------------------------------------------------------------- */ static LRESULT CALLBACK SocketProc(hwnd, message, wParam, lParam) HWND hwnd; UINT message; WPARAM wParam; LPARAM lParam; { int event, error; SOCKET socket; SocketInfo *infoPtr; ThreadSpecificData *tsdPtr = #ifdef _WIN64 (ThreadSpecificData *) GetWindowLongPtr(hwnd, GWLP_USERDATA); #else (ThreadSpecificData *) GetWindowLong(hwnd, GWL_USERDATA); #endif switch (message) { default: return DefWindowProc(hwnd, message, wParam, lParam); break; case WM_CREATE: /* * store the initial tsdPtr, it's from a different thread, so it's * not directly accessible, but needed. */ #ifdef _WIN64 SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) ((LPCREATESTRUCT)lParam)->lpCreateParams); #else SetWindowLong(hwnd, GWL_USERDATA, (LONG) ((LPCREATESTRUCT)lParam)->lpCreateParams); #endif break; case WM_DESTROY: PostQuitMessage(0); break; case SOCKET_MESSAGE: event = WSAGETSELECTEVENT(lParam); error = WSAGETSELECTERROR(lParam); socket = (SOCKET) wParam; /* * Find the specified socket on the socket list and update its * eventState flag. */ WaitForSingleObject(tsdPtr->socketListLock, INFINITE); for (infoPtr = tsdPtr->socketList; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { if (infoPtr->socket == socket) { /* * Update the socket state. */ /* * A count of FD_ACCEPTS is stored, so if an FD_CLOSE * event happens, then clear the FD_ACCEPT count. * Otherwise, increment the count if the current * event is an FD_ACCEPT. */ if (event & FD_CLOSE) { infoPtr->acceptEventCount = 0; infoPtr->readyEvents &= ~(FD_WRITE|FD_ACCEPT); } else if (event & FD_ACCEPT) { infoPtr->acceptEventCount++; } if (event & FD_CONNECT) { /* * The socket is now connected, * clear the async connect flag. */ infoPtr->flags &= ~(SOCKET_ASYNC_CONNECT); /* * Remember any error that occurred so we can report * connection failures. */ if (error != ERROR_SUCCESS) { TclWinConvertWSAError((DWORD) error); infoPtr->lastError = Tcl_GetErrno(); } } if(infoPtr->flags & SOCKET_ASYNC_CONNECT) { infoPtr->flags &= ~(SOCKET_ASYNC_CONNECT); if (error != ERROR_SUCCESS) { TclWinConvertWSAError((DWORD) error); infoPtr->lastError = Tcl_GetErrno(); } infoPtr->readyEvents |= FD_WRITE; } infoPtr->readyEvents |= event; /* * Wake up the Main Thread. */ SetEvent(tsdPtr->readyEvent); Tcl_ThreadAlert(tsdPtr->threadId); break; } } SetEvent(tsdPtr->socketListLock); break; case SOCKET_SELECT: infoPtr = (SocketInfo *) lParam; if (wParam == SELECT) { winSock.WSAAsyncSelect(infoPtr->socket, hwnd, SOCKET_MESSAGE, infoPtr->selectEvents); } else { /* * Clear the selection mask */ winSock.WSAAsyncSelect(infoPtr->socket, hwnd, 0, 0); } break; case SOCKET_TERMINATE: DestroyWindow(hwnd); break; } return 0; } /* *---------------------------------------------------------------------- * * Tcl_GetHostName -- * * Returns the name of the local host. * * Results: * A string containing the network name for this machine, or * an empty string if we can't figure out the name. The caller * must not modify or free this string. * * Side effects: * None. * *---------------------------------------------------------------------- */ CONST char * Tcl_GetHostName() { DWORD length; WCHAR wbuf[MAX_COMPUTERNAME_LENGTH + 1]; Tcl_MutexLock(&socketMutex); InitSockets(); if (!hostnameInitialized) { /* * Convert hostname from native to UTF then change to lowercase. */ Tcl_DString ds; length = sizeof(hostname); /* same as SocketsEnabled without the socketMutex lock */ if ((winSock.hModule != NULL) && (winSock.gethostname(hostname, length) == 0)) { Tcl_ExternalToUtfDString(NULL, hostname, -1, &ds); } else if ((*tclWinProcs->getComputerNameProc)(wbuf, &length) != 0) { Tcl_WinTCharToUtf((TCHAR *) wbuf, -1, &ds); } else { Tcl_DStringInit(&ds); Tcl_DStringSetLength(&ds, 0); } lstrcpynA(hostname, Tcl_DStringValue(&ds), sizeof(hostname)); Tcl_DStringFree(&ds); Tcl_UtfToLower(hostname); hostnameInitialized = 1; } Tcl_MutexUnlock(&socketMutex); return hostname; } /* *---------------------------------------------------------------------- * * TclWinGetSockOpt, et al. -- * * These functions are wrappers that let us bind the WinSock * API dynamically so we can run on systems that don't have * the wsock32.dll. We need wrappers for these interfaces * because they are called from the generic Tcl code. * * Results: * As defined for each function. * * Side effects: * As defined for each function. * *---------------------------------------------------------------------- */ int TclWinGetSockOpt(SOCKET s, int level, int optname, char * optval, int *optlen) { /* * Check that WinSock is initialized; do not call it if not, to * prevent system crashes. This can happen at exit time if the exit * handler for WinSock ran before other exit handlers that want to * use sockets. */ if (!SocketsEnabled()) { return SOCKET_ERROR; } return winSock.getsockopt(s, level, optname, optval, optlen); } int TclWinSetSockOpt(SOCKET s, int level, int optname, const char * optval, int optlen) { /* * Check that WinSock is initialized; do not call it if not, to * prevent system crashes. This can happen at exit time if the exit * handler for WinSock ran before other exit handlers that want to * use sockets. */ if (!SocketsEnabled()) { return SOCKET_ERROR; } return winSock.setsockopt(s, level, optname, optval, optlen); } unsigned short TclWinNToHS(unsigned short netshort) { /* * Check that WinSock is initialized; do not call it if not, to * prevent system crashes. This can happen at exit time if the exit * handler for WinSock ran before other exit handlers that want to * use sockets. */ if (!SocketsEnabled()) { return (unsigned short) -1; } return winSock.ntohs(netshort); } char * TclpInetNtoa(struct in_addr addr) { /* * Check that WinSock is initialized; do not call it if not, to * prevent system crashes. This can happen at exit time if the exit * handler for WinSock ran before other exit handlers that want to * use sockets. */ if (!SocketsEnabled()) { return NULL; } return winSock.inet_ntoa(addr); } struct servent * TclWinGetServByName(const char * name, const char * proto) { /* * Check that WinSock is initialized; do not call it if not, to * prevent system crashes. This can happen at exit time if the exit * handler for WinSock ran before other exit handlers that want to * use sockets. */ if (!SocketsEnabled()) { return (struct servent *) NULL; } return winSock.getservbyname(name, proto); } /* *---------------------------------------------------------------------- * * TcpThreadActionProc -- * * Insert or remove any thread local refs to this channel. * * Results: * None. * * Side effects: * Changes thread local list of valid channels. * *---------------------------------------------------------------------- */ static void TcpThreadActionProc (instanceData, action) ClientData instanceData; int action; { ThreadSpecificData *tsdPtr; SocketInfo *infoPtr = (SocketInfo *) instanceData; int notifyCmd; if (action == TCL_CHANNEL_THREAD_INSERT) { /* * Ensure that socket subsystem is initialized in this thread, or * else sockets will not work. */ Tcl_MutexLock(&socketMutex); InitSockets(); Tcl_MutexUnlock(&socketMutex); tsdPtr = TCL_TSD_INIT(&dataKey); WaitForSingleObject(tsdPtr->socketListLock, INFINITE); infoPtr->nextPtr = tsdPtr->socketList; tsdPtr->socketList = infoPtr; SetEvent(tsdPtr->socketListLock); notifyCmd = SELECT; } else { SocketInfo **nextPtrPtr; int removed = 0; tsdPtr = TCL_TSD_INIT(&dataKey); /* TIP #218, Bugfix: All access to socketList has to be protected by the lock */ WaitForSingleObject(tsdPtr->socketListLock, INFINITE); for (nextPtrPtr = &(tsdPtr->socketList); (*nextPtrPtr) != NULL; nextPtrPtr = &((*nextPtrPtr)->nextPtr)) { if ((*nextPtrPtr) == infoPtr) { (*nextPtrPtr) = infoPtr->nextPtr; removed = 1; break; } } SetEvent(tsdPtr->socketListLock); /* * This could happen if the channel was created in one thread * and then moved to another without updating the thread * local data in each thread. */ if (!removed) { Tcl_Panic("file info ptr not on thread channel list"); } notifyCmd = UNSELECT; } /* * Ensure that, or stop, notifications for the socket occur in this thread. */ SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) notifyCmd, (LPARAM) infoPtr); } tcl8.4.20/win/nmakehlp.c0000644003604700454610000004205612052456744013465 0ustar dgp771div/* * ---------------------------------------------------------------------------- * nmakehlp.c -- * * This is used to fix limitations within nmake and the environment. * * Copyright (c) 2002 by David Gravereaux. * Copyright (c) 2006 by Pat Thoyts * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * ---------------------------------------------------------------------------- */ #define _CRT_SECURE_NO_DEPRECATE #include #define NO_SHLWAPI_GDI #define NO_SHLWAPI_STREAM #define NO_SHLWAPI_REG #include #pragma comment (lib, "user32.lib") #pragma comment (lib, "kernel32.lib") #pragma comment (lib, "shlwapi.lib") #include #include /* * This library is required for x64 builds with _some_ versions of MSVC */ #if defined(_M_IA64) || defined(_M_AMD64) #if _MSC_VER >= 1400 && _MSC_VER < 1500 #pragma comment(lib, "bufferoverflowU") #endif #endif /* ISO hack for dumb VC++ */ #ifdef _MSC_VER #define snprintf _snprintf #endif /* protos */ static int CheckForCompilerFeature(const char *option); static int CheckForLinkerFeature(const char *option); static int IsIn(const char *string, const char *substring); static int SubstituteFile(const char *substs, const char *filename); static int QualifyPath(const char *path); static const char *GetVersionFromFile(const char *filename, const char *match, int numdots); static DWORD WINAPI ReadFromPipe(LPVOID args); /* globals */ #define CHUNK 25 #define STATICBUFFERSIZE 1000 typedef struct { HANDLE pipe; char buffer[STATICBUFFERSIZE]; } pipeinfo; pipeinfo Out = {INVALID_HANDLE_VALUE, '\0'}; pipeinfo Err = {INVALID_HANDLE_VALUE, '\0'}; /* * exitcodes: 0 == no, 1 == yes, 2 == error */ int main( int argc, char *argv[]) { char msg[300]; DWORD dwWritten; int chars; /* * Make sure children (cl.exe and link.exe) are kept quiet. */ SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); /* * Make sure the compiler and linker aren't effected by the outside world. */ SetEnvironmentVariable("CL", ""); SetEnvironmentVariable("LINK", ""); if (argc > 1 && *argv[1] == '-') { switch (*(argv[1]+1)) { case 'c': if (argc != 3) { chars = snprintf(msg, sizeof(msg) - 1, "usage: %s -c \n" "Tests for whether cl.exe supports an option\n" "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 2; } return CheckForCompilerFeature(argv[2]); case 'l': if (argc != 3) { chars = snprintf(msg, sizeof(msg) - 1, "usage: %s -l \n" "Tests for whether link.exe supports an option\n" "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 2; } return CheckForLinkerFeature(argv[2]); case 'f': if (argc == 2) { chars = snprintf(msg, sizeof(msg) - 1, "usage: %s -f \n" "Find a substring within another\n" "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 2; } else if (argc == 3) { /* * If the string is blank, there is no match. */ return 0; } else { return IsIn(argv[2], argv[3]); } case 's': if (argc == 2) { chars = snprintf(msg, sizeof(msg) - 1, "usage: %s -s \n" "Perform a set of string map type substutitions on a file\n" "exitcodes: 0\n", argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 2; } return SubstituteFile(argv[2], argv[3]); case 'V': if (argc != 4) { chars = snprintf(msg, sizeof(msg) - 1, "usage: %s -V filename matchstring\n" "Extract a version from a file:\n" "eg: pkgIndex.tcl \"package ifneeded http\"", argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 0; } printf("%s\n", GetVersionFromFile(argv[2], argv[3], *(argv[1]+2) - '0')); return 0; case 'Q': if (argc != 3) { chars = snprintf(msg, sizeof(msg) - 1, "usage: %s -Q path\n" "Emit the fully qualified path\n" "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 2; } return QualifyPath(argv[2]); } } chars = snprintf(msg, sizeof(msg) - 1, "usage: %s -c|-f|-l|-Q|-s|-V ...\n" "This is a little helper app to equalize shell differences between WinNT and\n" "Win9x and get nmake.exe to accomplish its job.\n", argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 2; } static int CheckForCompilerFeature( const char *option) { STARTUPINFO si; PROCESS_INFORMATION pi; SECURITY_ATTRIBUTES sa; DWORD threadID; char msg[300]; BOOL ok; HANDLE hProcess, h, pipeThreads[2]; char cmdline[100]; hProcess = GetCurrentProcess(); ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); ZeroMemory(&si, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.dwFlags = STARTF_USESTDHANDLES; si.hStdInput = INVALID_HANDLE_VALUE; ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = FALSE; /* * Create a non-inheritible pipe. */ CreatePipe(&Out.pipe, &h, &sa, 0); /* * Dupe the write side, make it inheritible, and close the original. */ DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); /* * Same as above, but for the error side. */ CreatePipe(&Err.pipe, &h, &sa, 0); DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); /* * Base command line. */ lstrcpy(cmdline, "cl.exe -nologo -c -TC -Zs -X -Fp.\\_junk.pch "); /* * Append our option for testing */ lstrcat(cmdline, option); /* * Filename to compile, which exists, but is nothing and empty. */ lstrcat(cmdline, " .\\nul"); ok = CreateProcess( NULL, /* Module name. */ cmdline, /* Command line. */ NULL, /* Process handle not inheritable. */ NULL, /* Thread handle not inheritable. */ TRUE, /* yes, inherit handles. */ DETACHED_PROCESS, /* No console for you. */ NULL, /* Use parent's environment block. */ NULL, /* Use parent's starting directory. */ &si, /* Pointer to STARTUPINFO structure. */ &pi); /* Pointer to PROCESS_INFORMATION structure. */ if (!ok) { DWORD err = GetLastError(); int chars = snprintf(msg, sizeof(msg) - 1, "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err); FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS| FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID)&msg[chars], (300-chars), 0); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL); return 2; } /* * Close our references to the write handles that have now been inherited. */ CloseHandle(si.hStdOutput); CloseHandle(si.hStdError); WaitForInputIdle(pi.hProcess, 5000); CloseHandle(pi.hThread); /* * Start the pipe reader threads. */ pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID); pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID); /* * Block waiting for the process to end. */ WaitForSingleObject(pi.hProcess, INFINITE); CloseHandle(pi.hProcess); /* * Wait for our pipe to get done reading, should it be a little slow. */ WaitForMultipleObjects(2, pipeThreads, TRUE, 500); CloseHandle(pipeThreads[0]); CloseHandle(pipeThreads[1]); /* * Look for the commandline warning code in both streams. * - in MSVC 6 & 7 we get D4002, in MSVC 8 we get D9002. */ return !(strstr(Out.buffer, "D4002") != NULL || strstr(Err.buffer, "D4002") != NULL || strstr(Out.buffer, "D9002") != NULL || strstr(Err.buffer, "D9002") != NULL || strstr(Out.buffer, "D2021") != NULL || strstr(Err.buffer, "D2021") != NULL); } static int CheckForLinkerFeature( const char *option) { STARTUPINFO si; PROCESS_INFORMATION pi; SECURITY_ATTRIBUTES sa; DWORD threadID; char msg[300]; BOOL ok; HANDLE hProcess, h, pipeThreads[2]; char cmdline[100]; hProcess = GetCurrentProcess(); ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); ZeroMemory(&si, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.dwFlags = STARTF_USESTDHANDLES; si.hStdInput = INVALID_HANDLE_VALUE; ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; /* * Create a non-inheritible pipe. */ CreatePipe(&Out.pipe, &h, &sa, 0); /* * Dupe the write side, make it inheritible, and close the original. */ DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); /* * Same as above, but for the error side. */ CreatePipe(&Err.pipe, &h, &sa, 0); DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); /* * Base command line. */ lstrcpy(cmdline, "link.exe -nologo "); /* * Append our option for testing. */ lstrcat(cmdline, option); ok = CreateProcess( NULL, /* Module name. */ cmdline, /* Command line. */ NULL, /* Process handle not inheritable. */ NULL, /* Thread handle not inheritable. */ TRUE, /* yes, inherit handles. */ DETACHED_PROCESS, /* No console for you. */ NULL, /* Use parent's environment block. */ NULL, /* Use parent's starting directory. */ &si, /* Pointer to STARTUPINFO structure. */ &pi); /* Pointer to PROCESS_INFORMATION structure. */ if (!ok) { DWORD err = GetLastError(); int chars = snprintf(msg, sizeof(msg) - 1, "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err); FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS| FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID)&msg[chars], (300-chars), 0); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL); return 2; } /* * Close our references to the write handles that have now been inherited. */ CloseHandle(si.hStdOutput); CloseHandle(si.hStdError); WaitForInputIdle(pi.hProcess, 5000); CloseHandle(pi.hThread); /* * Start the pipe reader threads. */ pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID); pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID); /* * Block waiting for the process to end. */ WaitForSingleObject(pi.hProcess, INFINITE); CloseHandle(pi.hProcess); /* * Wait for our pipe to get done reading, should it be a little slow. */ WaitForMultipleObjects(2, pipeThreads, TRUE, 500); CloseHandle(pipeThreads[0]); CloseHandle(pipeThreads[1]); /* * Look for the commandline warning code in the stderr stream. */ return !(strstr(Out.buffer, "LNK1117") != NULL || strstr(Err.buffer, "LNK1117") != NULL || strstr(Out.buffer, "LNK4044") != NULL || strstr(Err.buffer, "LNK4044") != NULL); } static DWORD WINAPI ReadFromPipe( LPVOID args) { pipeinfo *pi = (pipeinfo *) args; char *lastBuf = pi->buffer; DWORD dwRead; BOOL ok; again: if (lastBuf - pi->buffer + CHUNK > STATICBUFFERSIZE) { CloseHandle(pi->pipe); return (DWORD)-1; } ok = ReadFile(pi->pipe, lastBuf, CHUNK, &dwRead, 0L); if (!ok || dwRead == 0) { CloseHandle(pi->pipe); return 0; } lastBuf += dwRead; goto again; return 0; /* makes the compiler happy */ } static int IsIn( const char *string, const char *substring) { return (strstr(string, substring) != NULL); } /* * GetVersionFromFile -- * Looks for a match string in a file and then returns the version * following the match where a version is anything acceptable to * package provide or package ifneeded. */ static const char * GetVersionFromFile( const char *filename, const char *match, int numdots) { size_t cbBuffer = 100; static char szBuffer[100]; char *szResult = NULL; FILE *fp = fopen(filename, "rt"); if (fp != NULL) { /* * Read data until we see our match string. */ while (fgets(szBuffer, cbBuffer, fp) != NULL) { LPSTR p, q; p = strstr(szBuffer, match); if (p != NULL) { /* * Skip to first digit. */ while (*p && !isdigit(*p)) { ++p; } /* * Find ending whitespace. */ q = p; while (*q && (strchr("0123456789.ab", *q)) && ((!strchr(".ab", *q) && (!strchr("ab", q[-1])) || --numdots))) { ++q; } memcpy(szBuffer, p, q - p); szBuffer[q-p] = 0; szResult = szBuffer; break; } } fclose(fp); } return szResult; } /* * List helpers for the SubstituteFile function */ typedef struct list_item_t { struct list_item_t *nextPtr; char * key; char * value; } list_item_t; /* insert a list item into the list (list may be null) */ static list_item_t * list_insert(list_item_t **listPtrPtr, const char *key, const char *value) { list_item_t *itemPtr = malloc(sizeof(list_item_t)); if (itemPtr) { itemPtr->key = strdup(key); itemPtr->value = strdup(value); itemPtr->nextPtr = NULL; while(*listPtrPtr) { listPtrPtr = &(*listPtrPtr)->nextPtr; } *listPtrPtr = itemPtr; } return itemPtr; } static void list_free(list_item_t **listPtrPtr) { list_item_t *tmpPtr, *listPtr = *listPtrPtr; while (listPtr) { tmpPtr = listPtr; listPtr = listPtr->nextPtr; free(tmpPtr->key); free(tmpPtr->value); free(tmpPtr); } } /* * SubstituteFile -- * As windows doesn't provide anything useful like sed and it's unreliable * to use the tclsh you are building against (consider x-platform builds - * eg compiling AMD64 target from IX86) we provide a simple substitution * option here to handle autoconf style substitutions. * The substitution file is whitespace and line delimited. The file should * consist of lines matching the regular expression: * \s*\S+\s+\S*$ * * Usage is something like: * nmakehlp -S << $** > $@ * @PACKAGE_NAME@ $(PACKAGE_NAME) * @PACKAGE_VERSION@ $(PACKAGE_VERSION) * << */ static int SubstituteFile( const char *substitutions, const char *filename) { size_t cbBuffer = 1024; static char szBuffer[1024], szCopy[1024]; char *szResult = NULL; list_item_t *substPtr = NULL; FILE *fp, *sp; fp = fopen(filename, "rt"); if (fp != NULL) { /* * Build a list of substutitions from the first filename */ sp = fopen(substitutions, "rt"); if (sp != NULL) { while (fgets(szBuffer, cbBuffer, sp) != NULL) { char *ks, *ke, *vs, *ve; ks = szBuffer; while (ks && *ks && isspace(*ks)) ++ks; ke = ks; while (ke && *ke && !isspace(*ke)) ++ke; vs = ke; while (vs && *vs && isspace(*vs)) ++vs; ve = vs; while (ve && *ve && !(*ve == '\r' || *ve == '\n')) ++ve; *ke = 0, *ve = 0; list_insert(&substPtr, ks, vs); } fclose(sp); } /* debug: dump the list */ #ifdef _DEBUG { int n = 0; list_item_t *p = NULL; for (p = substPtr; p != NULL; p = p->nextPtr, ++n) { fprintf(stderr, "% 3d '%s' => '%s'\n", n, p->key, p->value); } } #endif /* * Run the substitutions over each line of the input */ while (fgets(szBuffer, cbBuffer, fp) != NULL) { list_item_t *p = NULL; for (p = substPtr; p != NULL; p = p->nextPtr) { char *m = strstr(szBuffer, p->key); if (m) { char *cp, *op, *sp; cp = szCopy; op = szBuffer; while (op != m) *cp++ = *op++; sp = p->value; while (sp && *sp) *cp++ = *sp++; op += strlen(p->key); while (*op) *cp++ = *op++; *cp = 0; memcpy(szBuffer, szCopy, sizeof(szCopy)); } } printf(szBuffer); } list_free(&substPtr); } fclose(fp); return 0; } /* * QualifyPath -- * * This composes the current working directory with a provided path * and returns the fully qualified and normalized path. * Mostly needed to setup paths for testing. */ static int QualifyPath( const char *szPath) { char szCwd[MAX_PATH + 1]; char szTmp[MAX_PATH + 1]; char *p; GetCurrentDirectory(MAX_PATH, szCwd); while ((p = strchr(szPath, '/')) && *p) *p = '\\'; PathCombine(szTmp, szCwd, szPath); PathCanonicalize(szCwd, szTmp); printf("%s\n", szCwd); return 0; } /* * Local variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * indent-tabs-mode: t * tab-width: 8 * End: */ tcl8.4.20/win/tclWinTime.c0000644003604700454610000007454412151137515013744 0ustar dgp771div/* * tclWinTime.c -- * * Contains Windows specific versions of Tcl functions that * obtain time values from the operating system. * * Copyright 1995-1998 by Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #if defined(_WIN32) && !defined(_WIN64) # define _USE_32BIT_TIME_T #endif #include "tclWinInt.h" #define SECSPERDAY (60L * 60L * 24L) #define SECSPERYEAR (SECSPERDAY * 365L) #define SECSPER4YEAR (SECSPERYEAR * 4L + SECSPERDAY) /* * Number of samples over which to estimate the performance counter */ #define SAMPLES 64 /* * The following arrays contain the day of year for the last day of * each month, where index 1 is January. */ static const int normalDays[] = { -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364 }; static const int leapDays[] = { -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; typedef struct ThreadSpecificData { char tzName[64]; /* Time zone name */ struct tm tm; /* time information */ } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; /* * Data for managing high-resolution timers. */ typedef struct TimeInfo { CRITICAL_SECTION cs; /* Mutex guarding this structure */ int initialized; /* Flag == 1 if this structure is * initialized. */ int perfCounterAvailable; /* Flag == 1 if the hardware has a * performance counter */ HANDLE calibrationThread; /* Handle to the thread that keeps the * virtual clock calibrated. */ HANDLE readyEvent; /* System event used to * trigger the requesting thread * when the clock calibration procedure * is initialized for the first time */ HANDLE exitEvent; /* Event to signal out of an exit handler * to tell the calibration loop to * terminate */ LARGE_INTEGER nominalFreq; /* Nominal frequency of the system * performance counter, that is, the value * returned from QueryPerformanceFrequency. */ /* * The following values are used for calculating virtual time. * Virtual time is always equal to: * lastFileTime + (current perf counter - lastCounter) * * 10000000 / curCounterFreq * and lastFileTime and lastCounter are updated any time that * virtual time is returned to a caller. */ ULARGE_INTEGER fileTimeLastCall; LARGE_INTEGER perfCounterLastCall; LARGE_INTEGER curCounterFreq; /* * Data used in developing the estimate of performance counter * frequency */ Tcl_WideUInt fileTimeSample[SAMPLES]; /* Last 64 samples of system time */ Tcl_WideInt perfCounterSample[SAMPLES]; /* Last 64 samples of performance counter */ int sampleNo; /* Current sample number */ } TimeInfo; static TimeInfo timeInfo = { { NULL }, 0, 0, (HANDLE) NULL, (HANDLE) NULL, (HANDLE) NULL, #ifdef HAVE_CAST_TO_UNION (LARGE_INTEGER) (Tcl_WideInt) 0, (ULARGE_INTEGER) (DWORDLONG) 0, (LARGE_INTEGER) (Tcl_WideInt) 0, (LARGE_INTEGER) (Tcl_WideInt) 0, #else 0, 0, 0, 0, #endif { 0 }, { 0 }, 0 }; static CONST FILETIME posixEpoch = { 0xD53E8000, 0x019DB1DE }; /* * Declarations for functions defined later in this file. */ static struct tm * ComputeGMT _ANSI_ARGS_((const time_t *tp)); static void StopCalibration _ANSI_ARGS_(( ClientData )); static DWORD WINAPI CalibrationThread _ANSI_ARGS_(( LPVOID arg )); static void UpdateTimeEachSecond _ANSI_ARGS_(( void )); static void ResetCounterSamples _ANSI_ARGS_(( Tcl_WideUInt fileTime, Tcl_WideInt perfCounter, Tcl_WideInt perfFreq )); static Tcl_WideInt AccumulateSample _ANSI_ARGS_(( Tcl_WideInt perfCounter, Tcl_WideUInt fileTime )); /* *---------------------------------------------------------------------- * * TclpGetSeconds -- * * This procedure returns the number of seconds from the epoch. * On most Unix systems the epoch is Midnight Jan 1, 1970 GMT. * * Results: * Number of seconds from the epoch. * * Side effects: * None. * *---------------------------------------------------------------------- */ unsigned long TclpGetSeconds() { Tcl_Time t; Tcl_GetTime( &t ); return t.sec; } /* *---------------------------------------------------------------------- * * TclpGetClicks -- * * This procedure returns a value that represents the highest * resolution clock available on the system. There are no * guarantees on what the resolution will be. In Tcl we will * call this value a "click". The start time is also system * dependant. * * Results: * Number of clicks from some start time. * * Side effects: * None. * *---------------------------------------------------------------------- */ unsigned long TclpGetClicks() { /* * Use the Tcl_GetTime abstraction to get the time in microseconds, * as nearly as we can, and return it. */ Tcl_Time now; /* Current Tcl time */ unsigned long retval; /* Value to return */ Tcl_GetTime( &now ); retval = ( now.sec * 1000000 ) + now.usec; return retval; } /* *---------------------------------------------------------------------- * * TclpGetTimeZone -- * * Determines the current timezone. The method varies wildly * between different Platform implementations, so its hidden in * this function. * * Results: * Minutes west of GMT. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclpGetTimeZone (currentTime) Tcl_WideInt currentTime; { int timeZone; tzset(); timeZone = _timezone / 60; return timeZone; } /* *---------------------------------------------------------------------- * * Tcl_GetTime -- * * Gets the current system time in seconds and microseconds * since the beginning of the epoch: 00:00 UCT, January 1, 1970. * * Results: * Returns the current time in timePtr. * * Side effects: * On the first call, initializes a set of static variables to * keep track of the base value of the performance counter, the * corresponding wall clock (obtained through ftime) and the * frequency of the performance counter. Also spins a thread * whose function is to wake up periodically and monitor these * values, adjusting them as necessary to correct for drift * in the performance counter's oscillator. * *---------------------------------------------------------------------- */ void Tcl_GetTime(timePtr) Tcl_Time *timePtr; /* Location to store time information. */ { struct _timeb t; int useFtime = 1; /* Flag == TRUE if we need to fall back * on ftime rather than using the perf * counter */ /* Initialize static storage on the first trip through. */ /* * Note: Outer check for 'initialized' is a performance win * since it avoids an extra mutex lock in the common case. */ if ( !timeInfo.initialized ) { TclpInitLock(); if ( !timeInfo.initialized ) { timeInfo.perfCounterAvailable = QueryPerformanceFrequency( &timeInfo.nominalFreq ); /* * Some hardware abstraction layers use the CPU clock * in place of the real-time clock as a performance counter * reference. This results in: * - inconsistent results among the processors on * multi-processor systems. * - unpredictable changes in performance counter frequency * on "gearshift" processors such as Transmeta and * SpeedStep. * * There seems to be no way to test whether the performance * counter is reliable, but a useful heuristic is that * if its frequency is 1.193182 MHz or 3.579545 MHz, it's * derived from a colorburst crystal and is therefore * the RTC rather than the TSC. * * A sloppier but serviceable heuristic is that the RTC crystal * is normally less than 15 MHz while the TSC crystal is * virtually assured to be greater than 100 MHz. Since Win98SE * appears to fiddle with the definition of the perf counter * frequency (perhaps in an attempt to calibrate the clock?) * we use the latter rule rather than an exact match. */ if ( timeInfo.perfCounterAvailable /* The following lines would do an exact match on * crystal frequency: * && timeInfo.nominalFreq.QuadPart != (Tcl_WideInt) 1193182 * && timeInfo.nominalFreq.QuadPart != (Tcl_WideInt) 3579545 */ && timeInfo.nominalFreq.QuadPart > (Tcl_WideInt) 15000000 ) { /* * As an exception, if every logical processor on the system * is on the same chip, we use the performance counter anyway, * presuming that everyone's TSC is locked to the same * oscillator. */ SYSTEM_INFO systemInfo; unsigned int regs[4]; GetSystemInfo( &systemInfo ); if ( TclWinCPUID( 0, regs ) == TCL_OK && regs[1] == 0x756e6547 /* "Genu" */ && regs[3] == 0x49656e69 /* "ineI" */ && regs[2] == 0x6c65746e /* "ntel" */ && TclWinCPUID( 1, regs ) == TCL_OK && ( (regs[0] & 0x00000F00) == 0x00000F00 /* Pentium 4 */ || ( (regs[0] & 0x00F00000) /* Extended family */ && (regs[3] & 0x10000000) ) ) /* Hyperthread */ && ( ( ( regs[1] & 0x00FF0000 ) >> 16 ) /* CPU count */ == systemInfo.dwNumberOfProcessors ) ) { timeInfo.perfCounterAvailable = TRUE; } else { timeInfo.perfCounterAvailable = FALSE; } } /* * If the performance counter is available, start a thread to * calibrate it. */ if ( timeInfo.perfCounterAvailable ) { DWORD id; InitializeCriticalSection( &timeInfo.cs ); timeInfo.readyEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); timeInfo.exitEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); timeInfo.calibrationThread = CreateThread( NULL, 256, CalibrationThread, (LPVOID) NULL, 0, &id ); SetThreadPriority( timeInfo.calibrationThread, THREAD_PRIORITY_HIGHEST ); /* * Wait for the thread just launched to start running, * and create an exit handler that kills it so that it * doesn't outlive unloading tclXX.dll */ WaitForSingleObject( timeInfo.readyEvent, INFINITE ); CloseHandle( timeInfo.readyEvent ); Tcl_CreateExitHandler( StopCalibration, (ClientData) NULL ); } timeInfo.initialized = TRUE; } TclpInitUnlock(); } if ( timeInfo.perfCounterAvailable ) { /* * Query the performance counter and use it to calculate the * current time. */ LARGE_INTEGER curCounter; /* Current performance counter */ Tcl_WideInt curFileTime; /* Current estimated time, expressed * as 100-ns ticks since the Windows epoch */ static LARGE_INTEGER posixEpoch; /* Posix epoch expressed as 100-ns ticks * since the windows epoch */ Tcl_WideInt usecSincePosixEpoch; /* Current microseconds since Posix epoch */ posixEpoch.LowPart = 0xD53E8000; posixEpoch.HighPart = 0x019DB1DE; EnterCriticalSection( &timeInfo.cs ); QueryPerformanceCounter( &curCounter ); /* * If it appears to be more than 1.1 seconds since the last trip * through the calibration loop, the performance counter may * have jumped forward. (See MSDN Knowledge Base article * Q274323 for a description of the hardware problem that makes * this test necessary.) If the counter jumps, we don't want * to use it directly. Instead, we must return system time. * Eventually, the calibration loop should recover. */ if ( curCounter.QuadPart - timeInfo.perfCounterLastCall.QuadPart < 11 * timeInfo.curCounterFreq.QuadPart / 10 ) { curFileTime = timeInfo.fileTimeLastCall.QuadPart + ( ( curCounter.QuadPart - timeInfo.perfCounterLastCall.QuadPart ) * 10000000 / timeInfo.curCounterFreq.QuadPart ); timeInfo.fileTimeLastCall.QuadPart = curFileTime; timeInfo.perfCounterLastCall.QuadPart = curCounter.QuadPart; usecSincePosixEpoch = ( curFileTime - posixEpoch.QuadPart ) / 10; timePtr->sec = (long) ( usecSincePosixEpoch / 1000000 ); timePtr->usec = (unsigned long ) ( usecSincePosixEpoch % 1000000 ); useFtime = 0; } LeaveCriticalSection( &timeInfo.cs ); } if ( useFtime ) { /* High resolution timer is not available. Just use ftime */ _ftime(&t); timePtr->sec = (long)t.time; timePtr->usec = t.millitm * 1000; } } /* *---------------------------------------------------------------------- * * StopCalibration -- * * Turns off the calibration thread in preparation for exiting the * process. * * Results: * None. * * Side effects: * Sets the 'exitEvent' event in the 'timeInfo' structure to ask * the thread in question to exit, and waits for it to do so. * *---------------------------------------------------------------------- */ static void StopCalibration( ClientData unused ) /* Client data is unused */ { SetEvent( timeInfo.exitEvent ); WaitForSingleObject( timeInfo.calibrationThread, INFINITE ); CloseHandle( timeInfo.exitEvent ); CloseHandle( timeInfo.calibrationThread ); } /* *---------------------------------------------------------------------- * * TclpGetTZName -- * * Gets the current timezone string. * * Results: * Returns a pointer to a static string, or NULL on failure. * * Side effects: * None. * *---------------------------------------------------------------------- */ char * TclpGetTZName(int dst) { size_t len; char *zone, *p; TIME_ZONE_INFORMATION tz; Tcl_Encoding encoding; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); char *name = tsdPtr->tzName; /* * tzset() under Borland doesn't seem to set up tzname[] at all. * tzset() under MSVC has the following weird observed behavior: * First time we call "clock format [clock seconds] -format %Z -gmt 1" * we get "GMT", but on all subsequent calls we get the current time * zone string, even though env(TZ) is GMT and the variable _timezone * is 0. */ name[0] = '\0'; zone = getenv("TZ"); if (zone != NULL) { /* * TZ is of form "NST-4:30NDT", where "NST" would be the * name of the standard time zone for this area, "-4:30" is * the offset from GMT in hours, and "NDT is the name of * the daylight savings time zone in this area. The offset * and DST strings are optional. */ len = strlen(zone); if (len > 3) { len = 3; } if (dst != 0) { /* * Skip the offset string and get the DST string. */ p = zone + len; p += strspn(p, "+-:0123456789"); if (*p != '\0') { zone = p; len = strlen(zone); if (len > 3) { len = 3; } } } Tcl_ExternalToUtf(NULL, NULL, zone, (int)len, 0, NULL, name, sizeof(tsdPtr->tzName), NULL, NULL, NULL); } if (name[0] == '\0') { if (GetTimeZoneInformation(&tz) == TIME_ZONE_ID_UNKNOWN) { /* * MSDN: On NT this is returned if DST is not used in * the current TZ */ dst = 0; } encoding = Tcl_GetEncoding(NULL, "unicode"); Tcl_ExternalToUtf(NULL, encoding, (char *) ((dst) ? tz.DaylightName : tz.StandardName), -1, 0, NULL, name, sizeof(tsdPtr->tzName), NULL, NULL, NULL); Tcl_FreeEncoding(encoding); } return name; } /* *---------------------------------------------------------------------- * * TclpGetDate -- * * This function converts between seconds and struct tm. If * useGMT is true, then the returned date will be in Greenwich * Mean Time (GMT). Otherwise, it will be in the local time zone. * * Results: * Returns a static tm structure. * * Side effects: * None. * *---------------------------------------------------------------------- */ struct tm * TclpGetDate(t, useGMT) TclpTime_t t; int useGMT; { const time_t *tp = (const time_t *) t; struct tm *tmPtr; time_t time; if (!useGMT) { tzset(); /* * If we are in the valid range, let the C run-time library * handle it. Otherwise we need to fake it. Note that this * algorithm ignores daylight savings time before the epoch. */ if (*tp >= 0) { return localtime(tp); } time = *tp - _timezone; /* * If we aren't near to overflowing the long, just add the bias and * use the normal calculation. Otherwise we will need to adjust * the result at the end. */ if (*tp < (LONG_MAX - 2 * SECSPERDAY) && *tp > (LONG_MIN + 2 * SECSPERDAY)) { tmPtr = ComputeGMT(&time); } else { tmPtr = ComputeGMT(tp); tzset(); /* * Add the bias directly to the tm structure to avoid overflow. * Propagate seconds overflow into minutes, hours and days. */ time = tmPtr->tm_sec - _timezone; tmPtr->tm_sec = (int)(time % 60); if (tmPtr->tm_sec < 0) { tmPtr->tm_sec += 60; time -= 60; } time = tmPtr->tm_min + time/60; tmPtr->tm_min = (int)(time % 60); if (tmPtr->tm_min < 0) { tmPtr->tm_min += 60; time -= 60; } time = tmPtr->tm_hour + time/60; tmPtr->tm_hour = (int)(time % 24); if (tmPtr->tm_hour < 0) { tmPtr->tm_hour += 24; time -= 24; } time /= 24; tmPtr->tm_mday += (int)time; tmPtr->tm_yday += (int)time; tmPtr->tm_wday = (tmPtr->tm_wday + (int)time) % 7; } } else { tmPtr = ComputeGMT(tp); } return tmPtr; } /* *---------------------------------------------------------------------- * * ComputeGMT -- * * This function computes GMT given the number of seconds since * the epoch (midnight Jan 1 1970). * * Results: * Returns a (per thread) statically allocated struct tm. * * Side effects: * Updates the values of the static struct tm. * *---------------------------------------------------------------------- */ static struct tm * ComputeGMT(tp) const time_t *tp; { struct tm *tmPtr; long tmp, rem; int isLeap; const int *days; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); tmPtr = &tsdPtr->tm; /* * Compute the 4 year span containing the specified time. */ tmp = (long)(*tp / SECSPER4YEAR); rem = (LONG)(*tp % SECSPER4YEAR); /* * Correct for weird mod semantics so the remainder is always positive. */ if (rem < 0) { tmp--; rem += SECSPER4YEAR; } /* * Compute the year after 1900 by taking the 4 year span and adjusting * for the remainder. This works because 2000 is a leap year, and * 1900/2100 are out of the range. */ tmp = (tmp * 4) + 70; isLeap = 0; if (rem >= SECSPERYEAR) { /* 1971, etc. */ tmp++; rem -= SECSPERYEAR; if (rem >= SECSPERYEAR) { /* 1972, etc. */ tmp++; rem -= SECSPERYEAR; if (rem >= SECSPERYEAR + SECSPERDAY) { /* 1973, etc. */ tmp++; rem -= SECSPERYEAR + SECSPERDAY; } else { isLeap = 1; } } } tmPtr->tm_year = tmp; /* * Compute the day of year and leave the seconds in the current day in * the remainder. */ tmPtr->tm_yday = rem / SECSPERDAY; rem %= SECSPERDAY; /* * Compute the time of day. */ tmPtr->tm_hour = rem / 3600; rem %= 3600; tmPtr->tm_min = rem / 60; tmPtr->tm_sec = rem % 60; /* * Compute the month and day of month. */ days = (isLeap) ? leapDays : normalDays; for (tmp = 1; days[tmp] < tmPtr->tm_yday; tmp++) { } tmPtr->tm_mon = --tmp; tmPtr->tm_mday = tmPtr->tm_yday - days[tmp]; /* * Compute day of week. Epoch started on a Thursday. */ tmPtr->tm_wday = (long)(*tp / SECSPERDAY) + 4; if ((*tp % SECSPERDAY) < 0) { tmPtr->tm_wday--; } tmPtr->tm_wday %= 7; if (tmPtr->tm_wday < 0) { tmPtr->tm_wday += 7; } return tmPtr; } /* *---------------------------------------------------------------------- * * CalibrationThread -- * * Thread that manages calibration of the hi-resolution time * derived from the performance counter, to keep it synchronized * with the system clock. * * Parameters: * arg -- Client data from the CreateThread call. This parameter * points to the static TimeInfo structure. * * Return value: * None. This thread embeds an infinite loop. * * Side effects: * At an interval of 1 s, this thread performs virtual time discipline. * * Note: When this thread is entered, TclpInitLock has been called * to safeguard the static storage. There is therefore no synchronization * in the body of this procedure. * *---------------------------------------------------------------------- */ static DWORD WINAPI CalibrationThread( LPVOID arg ) { FILETIME curFileTime; DWORD waitResult; /* Get initial system time and performance counter */ GetSystemTimeAsFileTime( &curFileTime ); QueryPerformanceCounter( &timeInfo.perfCounterLastCall ); QueryPerformanceFrequency( &timeInfo.curCounterFreq ); timeInfo.fileTimeLastCall.LowPart = curFileTime.dwLowDateTime; timeInfo.fileTimeLastCall.HighPart = curFileTime.dwHighDateTime; ResetCounterSamples( timeInfo.fileTimeLastCall.QuadPart, timeInfo.perfCounterLastCall.QuadPart, timeInfo.curCounterFreq.QuadPart ); /* * Wake up the calling thread. When it wakes up, it will release the * initialization lock. */ SetEvent( timeInfo.readyEvent ); /* Run the calibration once a second */ for ( ; ; ) { /* If the exitEvent is set, break out of the loop. */ waitResult = WaitForSingleObjectEx(timeInfo.exitEvent, 1000, FALSE); if ( waitResult == WAIT_OBJECT_0 ) { break; } UpdateTimeEachSecond(); } /* lint */ return (DWORD) 0; } /* *---------------------------------------------------------------------- * * UpdateTimeEachSecond -- * * Callback from the waitable timer in the clock calibration thread * that updates system time. * * Parameters: * info -- Pointer to the static TimeInfo structure * * Results: * None. * * Side effects: * Performs virtual time calibration discipline. * *---------------------------------------------------------------------- */ static void UpdateTimeEachSecond() { LARGE_INTEGER curPerfCounter; /* Current value returned from * QueryPerformanceCounter */ FILETIME curSysTime; /* Current system time */ LARGE_INTEGER curFileTime; /* File time at the time this callback * was scheduled. */ Tcl_WideInt estFreq; /* Estimated perf counter frequency */ Tcl_WideInt vt0; /* Tcl time right now */ Tcl_WideInt vt1; /* Tcl time one second from now */ Tcl_WideInt tdiff; /* Difference between system clock and * Tcl time. */ Tcl_WideInt driftFreq; /* Frequency needed to drift virtual time * into step over 1 second */ /* * Sample performance counter and system time. */ QueryPerformanceCounter( &curPerfCounter ); GetSystemTimeAsFileTime( &curSysTime ); curFileTime.LowPart = curSysTime.dwLowDateTime; curFileTime.HighPart = curSysTime.dwHighDateTime; EnterCriticalSection( &timeInfo.cs ); /* * Several things may have gone wrong here that have to * be checked for. * (1) The performance counter may have jumped. * (2) The system clock may have been reset. * * In either case, we'll need to reinitialize the circular buffer * with samples relative to the current system time and the NOMINAL * performance frequency (not the actual, because the actual has * probably run slow in the first case). Our estimated frequency * will be the nominal frequency. */ /* * Store the current sample into the circular buffer of samples, * and estimate the performance counter frequency. */ estFreq = AccumulateSample( curPerfCounter.QuadPart, (Tcl_WideUInt) curFileTime.QuadPart ); /* * We want to adjust things so that time appears to be continuous. * Virtual file time, right now, is * * vt0 = 10000000 * ( curPerfCounter - perfCounterLastCall ) * / curCounterFreq * + fileTimeLastCall * * Ideally, we would like to drift the clock into place over a * period of 2 sec, so that virtual time 2 sec from now will be * * vt1 = 20000000 + curFileTime * * The frequency that we need to use to drift the counter back into * place is estFreq * 20000000 / ( vt1 - vt0 ) */ vt0 = 10000000 * ( curPerfCounter.QuadPart - timeInfo.perfCounterLastCall.QuadPart ) / timeInfo.curCounterFreq.QuadPart + timeInfo.fileTimeLastCall.QuadPart; vt1 = 20000000 + curFileTime.QuadPart; /* * If we've gotten more than a second away from system time, * then drifting the clock is going to be pretty hopeless. * Just let it jump. Otherwise, compute the drift frequency and * fill in everything. */ tdiff = vt0 - curFileTime.QuadPart; if ( tdiff > 10000000 || tdiff < -10000000 ) { timeInfo.fileTimeLastCall.QuadPart = curFileTime.QuadPart; timeInfo.curCounterFreq.QuadPart = estFreq; } else { driftFreq = estFreq * 20000000 / ( vt1 - vt0 ); if ( driftFreq > 1003 * estFreq / 1000 ) { driftFreq = 1003 * estFreq / 1000; } if ( driftFreq < 997 * estFreq / 1000 ) { driftFreq = 997 * estFreq / 1000; } timeInfo.fileTimeLastCall.QuadPart = vt0; timeInfo.curCounterFreq.QuadPart = driftFreq; } timeInfo.perfCounterLastCall.QuadPart = curPerfCounter.QuadPart; LeaveCriticalSection( &timeInfo.cs ); } /* *---------------------------------------------------------------------- * * ResetCounterSamples -- * * Fills the sample arrays in 'timeInfo' with dummy values that will * yield the current performance counter and frequency. * * Results: * None. * * Side effects: * The array of samples is filled in so that it appears that there * are SAMPLES samples at one-second intervals, separated by precisely * the given frequency. * *---------------------------------------------------------------------- */ static void ResetCounterSamples( Tcl_WideUInt fileTime, /* Current file time */ Tcl_WideInt perfCounter, /* Current performance counter */ Tcl_WideInt perfFreq ) /* Target performance frequency */ { int i; for ( i = SAMPLES-1; i >= 0; --i ) { timeInfo.perfCounterSample[i] = perfCounter; timeInfo.fileTimeSample[i] = fileTime; perfCounter -= perfFreq; fileTime -= 10000000; } timeInfo.sampleNo = 0; } /* *---------------------------------------------------------------------- * * AccumulateSample -- * * Updates the circular buffer of performance counter and system * time samples with a new data point. * * Results: * None. * * Side effects: * The new data point replaces the oldest point in the circular * buffer, and the descriptive statistics are updated to accumulate * the new point. * * Several things may have gone wrong here that have to * be checked for. * (1) The performance counter may have jumped. * (2) The system clock may have been reset. * * In either case, we'll need to reinitialize the circular buffer * with samples relative to the current system time and the NOMINAL * performance frequency (not the actual, because the actual has * probably run slow in the first case). */ static Tcl_WideInt AccumulateSample( Tcl_WideInt perfCounter, Tcl_WideUInt fileTime ) { Tcl_WideUInt workFTSample; /* File time sample being removed * from or added to the circular buffer */ Tcl_WideInt workPCSample; /* Performance counter sample being * removed from or added to the circular * buffer */ Tcl_WideUInt lastFTSample; /* Last file time sample recorded */ Tcl_WideInt lastPCSample; /* Last performance counter sample recorded */ Tcl_WideInt FTdiff; /* Difference between last FT and current */ Tcl_WideInt PCdiff; /* Difference between last PC and current */ Tcl_WideInt estFreq; /* Estimated performance counter frequency */ /* Test for jumps and reset the samples if we have one. */ if ( timeInfo.sampleNo == 0 ) { lastPCSample = timeInfo.perfCounterSample[ timeInfo.sampleNo + SAMPLES - 1 ]; lastFTSample = timeInfo.fileTimeSample[ timeInfo.sampleNo + SAMPLES - 1 ]; } else { lastPCSample = timeInfo.perfCounterSample[ timeInfo.sampleNo - 1 ]; lastFTSample = timeInfo.fileTimeSample[ timeInfo.sampleNo - 1 ]; } PCdiff = perfCounter - lastPCSample; FTdiff = fileTime - lastFTSample; if ( PCdiff < timeInfo.nominalFreq.QuadPart * 9 / 10 || PCdiff > timeInfo.nominalFreq.QuadPart * 11 / 10 || FTdiff < 9000000 || FTdiff > 11000000 ) { ResetCounterSamples( fileTime, perfCounter, timeInfo.nominalFreq.QuadPart ); return timeInfo.nominalFreq.QuadPart; } else { /* Estimate the frequency */ workPCSample = timeInfo.perfCounterSample[ timeInfo.sampleNo ]; workFTSample = timeInfo.fileTimeSample[ timeInfo.sampleNo ]; estFreq = 10000000 * ( perfCounter - workPCSample ) / ( fileTime - workFTSample ); timeInfo.perfCounterSample[ timeInfo.sampleNo ] = perfCounter; timeInfo.fileTimeSample[ timeInfo.sampleNo ] = (Tcl_WideInt) fileTime; /* Advance the sample number */ if ( ++timeInfo.sampleNo >= SAMPLES ) { timeInfo.sampleNo = 0; } return estFreq; } } /* *---------------------------------------------------------------------- * * TclpGmtime -- * * Wrapper around the 'gmtime' library function to make it thread * safe. * * Results: * Returns a pointer to a 'struct tm' in thread-specific data. * * Side effects: * Invokes gmtime or gmtime_r as appropriate. * *---------------------------------------------------------------------- */ struct tm * TclpGmtime( tt ) TclpTime_t_CONST tt; { CONST time_t *timePtr = (CONST time_t *) tt; /* Pointer to the number of seconds * since the local system's epoch */ /* * The MS implementation of gmtime is thread safe because * it returns the time in a block of thread-local storage, * and Windows does not provide a Posix gmtime_r function. */ return gmtime( timePtr ); } /* *---------------------------------------------------------------------- * * TclpLocaltime -- * * Wrapper around the 'localtime' library function to make it thread * safe. * * Results: * Returns a pointer to a 'struct tm' in thread-specific data. * * Side effects: * Invokes localtime or localtime_r as appropriate. * *---------------------------------------------------------------------- */ struct tm * TclpLocaltime( tt ) TclpTime_t_CONST tt; { CONST time_t *timePtr = (CONST time_t *) tt; /* Pointer to the number of seconds * since the local system's epoch */ /* * The MS implementation of localtime is thread safe because * it returns the time in a block of thread-local storage, * and Windows does not provide a Posix localtime_r function. */ return localtime( timePtr ); } tcl8.4.20/win/license.terms0000644003604700454610000000432111737050674014212 0ustar dgp771divThis software is copyrighted by the Regents of the University of California, Sun Microsystems, Inc., Scriptics Corporation, ActiveState Corporation and other parties. The following terms apply to all files associated with the software unless explicitly disclaimed in individual files. The authors hereby grant permission to use, copy, modify, distribute, and license this software and its documentation for any purpose, provided that existing copyright notices are retained in all copies and that this notice is included verbatim in any distributions. No written agreement, license, or royalty fee is required for any of the authorized uses. Modifications to this software may be copyrighted by their authors and need not follow the licensing terms described here, provided that the new terms are clearly indicated on the first page of each file where they apply. IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. GOVERNMENT USE: If you are acquiring this software on behalf of the U.S. government, the Government shall have only "Restricted Rights" in the software and related documentation as defined in the Federal Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are acquiring the software on behalf of the Department of Defense, the software shall be classified as "Commercial Computer Software" and the Government shall have only "Restricted Rights" as defined in Clause 252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the authors grant the U.S. Government and others acting in its behalf permission to use and distribute the software in accordance with the terms specified in this license. tcl8.4.20/win/tcl.m40000644003604700454610000010740012153151142012523 0ustar dgp771div#------------------------------------------------------------------------ # SC_PATH_TCLCONFIG -- # # Locate the tclConfig.sh file and perform a sanity check on # the Tcl compile flags # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-tcl=... # # Defines the following vars: # TCL_BIN_DIR Full path to the directory containing # the tclConfig.sh file #------------------------------------------------------------------------ AC_DEFUN([SC_PATH_TCLCONFIG], [ # # Ok, lets find the tcl configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-tcl # if test x"${no_tcl}" = x ; then # we reset no_tcl in case something fails here no_tcl=true AC_ARG_WITH(tcl, [ --with-tcl directory containing tcl configuration (tclConfig.sh)], with_tclconfig=${withval}) AC_MSG_CHECKING([for Tcl configuration]) AC_CACHE_VAL(ac_cv_c_tclconfig,[ # First check to see if --with-tcl was specified. if test x"${with_tclconfig}" != x ; then case "${with_tclconfig}" in */tclConfig.sh ) if test -f "${with_tclconfig}"; then AC_MSG_WARN([--with-tcl argument should refer to directory containing tclConfig.sh, not to tclConfig.sh itself]) with_tclconfig="`echo "${with_tclconfig}" | sed 's!/tclConfig\.sh$!!'`" fi ;; esac if test -f "${with_tclconfig}/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd "${with_tclconfig}"; pwd)`" else AC_MSG_ERROR([${with_tclconfig} directory doesn't contain tclConfig.sh]) fi fi # then check for a private Tcl installation if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ ../tcl \ `ls -dr ../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../tcl[[8-9]].[[0-9]]* 2>/dev/null` \ ../../tcl \ `ls -dr ../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../tcl[[8-9]].[[0-9]]* 2>/dev/null` \ ../../../tcl \ `ls -dr ../../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do if test -f "$i/win/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/win; pwd)`" break fi done fi # check in a few common install locations if test x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /cygdrive/c/Tcl/lib 2>/dev/null` \ `ls -d /cygdrive/c/Progra~1/Tcl/lib 2>/dev/null` \ `ls -d /c/Tcl/lib 2>/dev/null` \ `ls -d /c/Progra~1/Tcl/lib 2>/dev/null` \ `ls -d C:/Tcl/lib 2>/dev/null` \ `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ ; do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i; pwd)`" break fi done fi # check in a few other private locations if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ ${srcdir}/../tcl \ `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do if test -f "$i/win/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/win; pwd)`" break fi done fi ]) if test x"${ac_cv_c_tclconfig}" = x ; then TCL_BIN_DIR="# no Tcl configs found" AC_MSG_ERROR([Can't find Tcl configuration definitions. Use --with-tcl to specify a directory containing tclConfig.sh]) else no_tcl= TCL_BIN_DIR="${ac_cv_c_tclconfig}" AC_MSG_RESULT([found ${TCL_BIN_DIR}/tclConfig.sh]) fi fi ]) #------------------------------------------------------------------------ # SC_PATH_TKCONFIG -- # # Locate the tkConfig.sh file # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-tk=... # # Defines the following vars: # TK_BIN_DIR Full path to the directory containing # the tkConfig.sh file #------------------------------------------------------------------------ AC_DEFUN([SC_PATH_TKCONFIG], [ # # Ok, lets find the tk configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-tk # if test x"${no_tk}" = x ; then # we reset no_tk in case something fails here no_tk=true AC_ARG_WITH(tk, [ --with-tk directory containing tk configuration (tkConfig.sh)], with_tkconfig=${withval}) AC_MSG_CHECKING([for Tk configuration]) AC_CACHE_VAL(ac_cv_c_tkconfig,[ # First check to see if --with-tkconfig was specified. if test x"${with_tkconfig}" != x ; then case "${with_tkconfig}" in */tkConfig.sh ) if test -f "${with_tkconfig}"; then AC_MSG_WARN([--with-tk argument should refer to directory containing tkConfig.sh, not to tkConfig.sh itself]) with_tkconfig="`echo "${with_tkconfig}" | sed 's!/tkConfig\.sh$!!'`" fi ;; esac if test -f "${with_tkconfig}/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd "${with_tkconfig}"; pwd)`" else AC_MSG_ERROR([${with_tkconfig} directory doesn't contain tkConfig.sh]) fi fi # then check for a private Tk library if test x"${ac_cv_c_tkconfig}" = x ; then for i in \ ../tk \ `ls -dr ../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../tk[[8-9]].[[0-9]]* 2>/dev/null` \ ../../tk \ `ls -dr ../../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../tk[[8-9]].[[0-9]]* 2>/dev/null` \ ../../../tk \ `ls -dr ../../../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do if test -f "$i/win/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/win; pwd)`" break fi done fi # check in a few common install locations if test x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /cygdrive/c/Tcl/lib 2>/dev/null` \ `ls -d /cygdrive/c/Progra~1/Tcl/lib 2>/dev/null` \ `ls -d /c/Tcl/lib 2>/dev/null` \ `ls -d /c/Progra~1/Tcl/lib 2>/dev/null` \ `ls -d C:/Tcl/lib 2>/dev/null` \ `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ ; do if test -f "$i/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i; pwd)`" break fi done fi # check in a few other private locations if test x"${ac_cv_c_tkconfig}" = x ; then for i in \ ${srcdir}/../tk \ `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do if test -f "$i/win/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/win; pwd)`" break fi done fi ]) if test x"${ac_cv_c_tkconfig}" = x ; then TK_BIN_DIR="# no Tk configs found" AC_MSG_ERROR([Can't find Tk configuration definitions. Use --with-tk to specify a directory containing tkConfig.sh]) else no_tk= TK_BIN_DIR="${ac_cv_c_tkconfig}" AC_MSG_RESULT([found ${TK_BIN_DIR}/tkConfig.sh]) fi fi ]) #------------------------------------------------------------------------ # SC_LOAD_TCLCONFIG -- # # Load the tclConfig.sh file. # # Arguments: # # Requires the following vars to be set: # TCL_BIN_DIR # # Results: # # Subst the following vars: # TCL_BIN_DIR # TCL_SRC_DIR # TCL_LIB_FILE # #------------------------------------------------------------------------ AC_DEFUN([SC_LOAD_TCLCONFIG], [ AC_MSG_CHECKING([for existence of ${TCL_BIN_DIR}/tclConfig.sh]) if test -f "${TCL_BIN_DIR}/tclConfig.sh" ; then AC_MSG_RESULT([loading]) . "${TCL_BIN_DIR}/tclConfig.sh" else AC_MSG_RESULT([could not find ${TCL_BIN_DIR}/tclConfig.sh]) fi # # If the TCL_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable TCL_LIB_SPEC will be set to the value # of TCL_BUILD_LIB_SPEC. An extension should make use of TCL_LIB_SPEC # instead of TCL_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. # if test -f $TCL_BIN_DIR/Makefile ; then TCL_LIB_SPEC=${TCL_BUILD_LIB_SPEC} TCL_STUB_LIB_SPEC=${TCL_BUILD_STUB_LIB_SPEC} TCL_STUB_LIB_PATH=${TCL_BUILD_STUB_LIB_PATH} fi # # eval is required to do the TCL_DBGX substitution # eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\"" eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\"" eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\"" eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\"" eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\"" eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\"" AC_SUBST(TCL_VERSION) AC_SUBST(TCL_BIN_DIR) AC_SUBST(TCL_SRC_DIR) AC_SUBST(TCL_LIB_FILE) AC_SUBST(TCL_LIB_FLAG) AC_SUBST(TCL_LIB_SPEC) AC_SUBST(TCL_STUB_LIB_FILE) AC_SUBST(TCL_STUB_LIB_FLAG) AC_SUBST(TCL_STUB_LIB_SPEC) AC_SUBST(TCL_DEFS) ]) #------------------------------------------------------------------------ # SC_LOAD_TKCONFIG -- # # Load the tkConfig.sh file # # Arguments: # # Requires the following vars to be set: # TK_BIN_DIR # # Results: # # Sets the following vars that should be in tkConfig.sh: # TK_BIN_DIR #------------------------------------------------------------------------ AC_DEFUN([SC_LOAD_TKCONFIG], [ AC_MSG_CHECKING([for existence of ${TK_BIN_DIR}/tkConfig.sh]) if test -f "${TK_BIN_DIR}/tkConfig.sh" ; then AC_MSG_RESULT([loading]) . "${TK_BIN_DIR}/tkConfig.sh" else AC_MSG_RESULT([could not find ${TK_BIN_DIR}/tkConfig.sh]) fi AC_SUBST(TK_BIN_DIR) AC_SUBST(TK_SRC_DIR) AC_SUBST(TK_LIB_FILE) ]) #------------------------------------------------------------------------ # SC_ENABLE_SHARED -- # # Allows the building of shared libraries # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --enable-shared=yes|no # # Defines the following vars: # STATIC_BUILD Used for building import/export libraries # on Windows. # # Sets the following vars: # SHARED_BUILD Value of 1 or 0 #------------------------------------------------------------------------ AC_DEFUN([SC_ENABLE_SHARED], [ AC_MSG_CHECKING([how to build libraries]) AC_ARG_ENABLE(shared, [ --enable-shared build and link with shared libraries (default: on)], [tcl_ok=$enableval], [tcl_ok=yes]) if test "${enable_shared+set}" = set; then enableval="$enable_shared" tcl_ok=$enableval else tcl_ok=yes fi if test "$tcl_ok" = "yes" ; then AC_MSG_RESULT([shared]) SHARED_BUILD=1 else AC_MSG_RESULT([static]) SHARED_BUILD=0 AC_DEFINE(STATIC_BUILD, 1, [Is this a static build?]) fi ]) #------------------------------------------------------------------------ # SC_ENABLE_THREADS -- # # Specify if thread support should be enabled # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --enable-threads=yes|no # # Defines the following vars: # TCL_THREADS #------------------------------------------------------------------------ AC_DEFUN([SC_ENABLE_THREADS], [ AC_MSG_CHECKING(for building with threads) AC_ARG_ENABLE(threads, [ --enable-threads build with threads (default: off)], [tcl_ok=$enableval], [tcl_ok=no]) if test "$tcl_ok" = "yes"; then AC_MSG_RESULT(yes) TCL_THREADS=1 AC_DEFINE(TCL_THREADS) # USE_THREAD_ALLOC tells us to try the special thread-based # allocator that significantly reduces lock contention AC_DEFINE(USE_THREAD_ALLOC) else TCL_THREADS=0 AC_MSG_RESULT([no (default)]) fi AC_SUBST(TCL_THREADS) ]) #------------------------------------------------------------------------ # SC_ENABLE_SYMBOLS -- # # Specify if debugging symbols should be used. # Memory (TCL_MEM_DEBUG) and compile (TCL_COMPILE_DEBUG) debugging # can also be enabled. # # Arguments: # none # # Requires the following vars to be set in the Makefile: # CFLAGS_DEBUG # CFLAGS_OPTIMIZE # # Results: # # Adds the following arguments to configure: # --enable-symbols # # Defines the following vars: # CFLAGS_DEFAULT Sets to $(CFLAGS_DEBUG) if true # Sets to $(CFLAGS_OPTIMIZE) if false # LDFLAGS_DEFAULT Sets to $(LDFLAGS_DEBUG) if true # Sets to $(LDFLAGS_OPTIMIZE) if false # DBGX Debug library extension # #------------------------------------------------------------------------ AC_DEFUN([SC_ENABLE_SYMBOLS], [ AC_MSG_CHECKING([for build with symbols]) AC_ARG_ENABLE(symbols, [ --enable-symbols build with debugging symbols (default: off)], [tcl_ok=$enableval], [tcl_ok=no]) # FIXME: Currently, LDFLAGS_DEFAULT is not used, it should work like CFLAGS_DEFAULT. if test "$tcl_ok" = "no"; then CFLAGS_DEFAULT='$(CFLAGS_OPTIMIZE)' LDFLAGS_DEFAULT='$(LDFLAGS_OPTIMIZE)' DBGX="" AC_DEFINE(NDEBUG, 1, [Is no debugging enabled?]) AC_MSG_RESULT([no]) else CFLAGS_DEFAULT='$(CFLAGS_DEBUG)' LDFLAGS_DEFAULT='$(LDFLAGS_DEBUG)' DBGX=g if test "$tcl_ok" = "yes"; then AC_MSG_RESULT([yes (standard debugging)]) fi fi AC_SUBST(CFLAGS_DEFAULT) AC_SUBST(LDFLAGS_DEFAULT) if test "$tcl_ok" = "mem" -o "$tcl_ok" = "all"; then AC_DEFINE(TCL_MEM_DEBUG, 1, [Is memory debugging enabled?]) fi if test "$tcl_ok" = "compile" -o "$tcl_ok" = "all"; then AC_DEFINE(TCL_COMPILE_DEBUG, 1, [Is bytecode debugging enabled?]) AC_DEFINE(TCL_COMPILE_STATS, 1, [Are bytecode statistics enabled?]) fi if test "$tcl_ok" != "yes" -a "$tcl_ok" != "no"; then if test "$tcl_ok" = "all"; then AC_MSG_RESULT([enabled symbols mem compile debugging]) else AC_MSG_RESULT([enabled $tcl_ok debugging]) fi fi ]) #-------------------------------------------------------------------- # SC_CONFIG_CFLAGS # # Try to determine the proper flags to pass to the compiler # for building shared libraries and other such nonsense. # # NOTE: The backslashes in quotes below are substituted twice # due to the fact that they are in a macro and then inlined # in the final configure script. # # Arguments: # none # # Results: # # Can the following vars: # EXTRA_CFLAGS # CFLAGS_DEBUG # CFLAGS_OPTIMIZE # CFLAGS_WARNING # LDFLAGS_DEBUG # LDFLAGS_OPTIMIZE # LDFLAGS_CONSOLE # LDFLAGS_WINDOW # CC_OBJNAME # CC_EXENAME # CYGPATH # STLIB_LD # SHLIB_LD # SHLIB_LD_LIBS # LIBS # AR # RC # RES # # MAKE_LIB # MAKE_EXE # MAKE_DLL # # LIBSUFFIX # LIBFLAGSUFFIX # LIBPREFIX # LIBRARIES # EXESUFFIX # DLLSUFFIX # #-------------------------------------------------------------------- AC_DEFUN([SC_CONFIG_CFLAGS], [ # Step 0: Enable 64 bit support? AC_MSG_CHECKING([if 64bit support is requested]) AC_ARG_ENABLE(64bit,[ --enable-64bit enable 64bit support (where applicable)], [do64bit=$enableval], [do64bit=no]) AC_MSG_RESULT($do64bit) # Cross-compiling options for Windows/CE builds AC_MSG_CHECKING([if Windows/CE build is requested]) AC_ARG_ENABLE(wince,[ --enable-wince enable Win/CE support (where applicable)], [doWince=$enableval], [doWince=no]) AC_MSG_RESULT($doWince) AC_MSG_CHECKING([for Windows/CE celib directory]) AC_ARG_WITH(celib,[ --with-celib=DIR use Windows/CE support library from DIR], CELIB_DIR=$withval, CELIB_DIR=NO_CELIB) AC_MSG_RESULT([$CELIB_DIR]) # Set some defaults (may get changed below) EXTRA_CFLAGS="" AC_CHECK_PROG(CYGPATH, cygpath, cygpath -w, echo) SHLIB_SUFFIX=".dll" # MACHINE is IX86 for LINK, but this is used by the manifest, # which requires x86|amd64|ia64. MACHINE="X86" if test "$GCC" = "yes"; then AC_CACHE_CHECK(for cross-compile version of gcc, ac_cv_cross, AC_TRY_COMPILE([ #ifndef __WIN32__ #error cross-compiler #endif ], [], ac_cv_cross=no, ac_cv_cross=yes) ) if test "$ac_cv_cross" = "yes"; then case "$do64bit" in amd64|x64|yes) CC="x86_64-w64-mingw32-gcc" LD="x86_64-w64-mingw32-ld" AR="x86_64-w64-mingw32-ar" RANLIB="x86_64-w64-mingw32-ranlib" RC="x86_64-w64-mingw32-windres" ;; *) CC="i686-w64-mingw32-gcc" LD="i686-w64-mingw32-ld" AR="i686-w64-mingw32-ar" RANLIB="i686-w64-mingw32-ranlib" RC="i686-w64-mingw32-windres" ;; esac fi fi # Check for a bug in gcc's windres that causes the # compile to fail when a Windows native path is # passed into windres. The mingw toolchain requires # Windows native paths while Cygwin should work # with both. Avoid the bug by passing a POSIX # path when using the Cygwin toolchain. if test "$GCC" = "yes" && test "$CYGPATH" != "echo" ; then conftest=/tmp/conftest.rc echo "STRINGTABLE BEGIN" > $conftest echo "101 \"name\"" >> $conftest echo "END" >> $conftest AC_MSG_CHECKING([for Windows native path bug in windres]) cyg_conftest=`$CYGPATH $conftest` if AC_TRY_COMMAND($RC -o conftest.res.o $cyg_conftest) ; then AC_MSG_RESULT([no]) else AC_MSG_RESULT([yes]) CYGPATH=echo fi conftest= cyg_conftest= fi if test "$CYGPATH" = "echo"; then DEPARG='"$<"' else DEPARG='"$(shell $(CYGPATH) $<)"' fi # set various compiler flags depending on whether we are using gcc or cl if test "${GCC}" = "yes" ; then AC_CACHE_CHECK(for mingw32 version of gcc, ac_cv_win32, AC_TRY_COMPILE([ #ifdef __WIN32__ #error win32 #endif ], [], ac_cv_win32=no, ac_cv_win32=yes) ) if test "$ac_cv_win32" != "yes"; then AC_MSG_ERROR([${CC} cannot produce win32 executables.]) fi fi AC_MSG_CHECKING([compiler flags]) if test "${GCC}" = "yes" ; then SHLIB_LD="" SHLIB_LD_LIBS="" LIBS="" LIBS_GUI="-lgdi32 -lcomdlg32 -limm32 -lcomctl32 -lshell32" STLIB_LD='${AR} cr' RC_OUT=-o RC_TYPE= RC_INCLUDE=--include RC_DEFINE=--define RES=res.o MAKE_LIB="\${STLIB_LD} \[$]@" POST_MAKE_LIB="\${RANLIB} \[$]@" MAKE_EXE="\${CC} -o \[$]@" LIBPREFIX="lib" extra_cflags="-pipe" extra_ldflags="-pipe" if test "${SHARED_BUILD}" = "0" ; then # static AC_MSG_RESULT([using static flags]) runtime= MAKE_DLL="echo " LIBSUFFIX="s\${DBGX}.a" LIBFLAGSUFFIX="s\${DBGX}" LIBRARIES="\${STATIC_LIBRARIES}" EXESUFFIX="s\${DBGX}.exe" else # dynamic AC_MSG_RESULT([using shared flags]) # ad-hoc check to see if CC supports -shared. if "${CC}" -shared 2>&1 | egrep ': -shared not supported' >/dev/null; then AC_MSG_ERROR([${CC} does not support the -shared option. You will need to upgrade to a newer version of the toolchain.]) fi runtime= # Link with gcc since ld does not link to default libs like # -luser32 and -lmsvcrt by default. Make sure CFLAGS is # included so -mno-cygwin passed the correct libs to the linker. SHLIB_LD='${CC} -shared ${CFLAGS}' SHLIB_LD_LIBS='${LIBS}' # Add SHLIB_LD_LIBS to the Make rule, not here. MAKE_DLL="\${SHLIB_LD} \$(LDFLAGS) -o \[$]@ ${extra_ldflags} \ -Wl,--out-implib,\$(patsubst %.dll,lib%.a,\[$]@)" LIBSUFFIX="\${DBGX}.a" LIBFLAGSUFFIX="\${DBGX}" EXESUFFIX="\${DBGX}.exe" LIBRARIES="\${SHARED_LIBRARIES}" fi # DLLSUFFIX is separate because it is the building block for # users of tclConfig.sh that may build shared or static. DLLSUFFIX="\${DBGX}.dll" SHLIB_SUFFIX=.dll EXTRA_CFLAGS="${extra_cflags}" CFLAGS_DEBUG=-g CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" CFLAGS_WARNING="-Wall -fno-strict-aliasing" LDFLAGS_DEBUG= LDFLAGS_OPTIMIZE= # Specify the CC output file names based on the target name CC_OBJNAME="-o \[$]@" CC_EXENAME="-o \[$]@" # Specify linker flags depending on the type of app being # built -- Console vs. Window. # # ORIGINAL COMMENT: # We need to pass -e _WinMain@16 so that ld will use # WinMain() instead of main() as the entry point. We can't # use autoconf to check for this case since it would need # to run an executable and that does not work when # cross compiling. Remove this -e workaround once we # require a gcc that does not have this bug. # # MK NOTE: Tk should use a different mechanism. This causes # interesting problems, such as wish dying at startup. #LDFLAGS_WINDOW="-mwindows -e _WinMain@16 ${extra_ldflags}" LDFLAGS_CONSOLE="-mconsole ${extra_ldflags}" LDFLAGS_WINDOW="-mwindows ${extra_ldflags}" case "$do64bit" in amd64|x64|yes) MACHINE="AMD64" ; # assume AMD64 as default 64-bit build AC_MSG_RESULT([ Using 64-bit $MACHINE mode]) ;; ia64) MACHINE="IA64" AC_MSG_RESULT([ Using 64-bit $MACHINE mode]) ;; *) AC_TRY_COMPILE([ #ifndef _WIN64 #error 32-bit #endif ], [], tcl_win_64bit=yes, tcl_win_64bit=no ) if test "$tcl_win_64bit" = "yes" ; then do64bit=amd64 MACHINE="AMD64" AC_MSG_RESULT([ Using 64-bit $MACHINE mode]) fi ;; esac else if test "${SHARED_BUILD}" = "0" ; then # static AC_MSG_RESULT([using static flags]) runtime=-MT MAKE_DLL="echo " LIBSUFFIX="s\${DBGX}.lib" LIBFLAGSUFFIX="s\${DBGX}" LIBRARIES="\${STATIC_LIBRARIES}" EXESUFFIX="s\${DBGX}.exe" SHLIB_LD_LIBS="" else # dynamic AC_MSG_RESULT([using shared flags]) runtime=-MD # Add SHLIB_LD_LIBS to the Make rule, not here. MAKE_DLL="\${SHLIB_LD} \$(LDFLAGS) -out:\[$]@" LIBSUFFIX="\${DBGX}.lib" LIBFLAGSUFFIX="\${DBGX}" EXESUFFIX="\${DBGX}.exe" LIBRARIES="\${SHARED_LIBRARIES}" SHLIB_LD_LIBS='${LIBS}' fi # DLLSUFFIX is separate because it is the building block for # users of tclConfig.sh that may build shared or static. DLLSUFFIX="\${DBGX}.dll" # This is a 2-stage check to make sure we have the 64-bit SDK # We have to know where the SDK is installed. # This magic is based on MS Platform SDK for Win2003 SP1 - hobbs if test "$do64bit" != "no" ; then if test "x${MSSDK}x" = "xx" ; then MSSDK="C:/Progra~1/Microsoft Platform SDK" fi MSSDK=`echo "$MSSDK" | sed -e 's!\\\!/!g'` PATH64="" case "$do64bit" in amd64|x64|yes) MACHINE="AMD64" ; # assume AMD64 as default 64-bit build PATH64="${MSSDK}/Bin/Win64/x86/AMD64" ;; ia64) MACHINE="IA64" PATH64="${MSSDK}/Bin/Win64" ;; esac if test ! -d "${PATH64}" ; then AC_MSG_WARN([Could not find 64-bit $MACHINE SDK to enable 64bit mode]) AC_MSG_WARN([Ensure latest Platform SDK is installed]) do64bit="no" else AC_MSG_RESULT([ Using 64-bit $MACHINE mode]) fi fi LIBS="user32.lib advapi32.lib" if test "$do64bit" != "no" ; then # The space-based-path will work for the Makefile, but will # not work if AC_TRY_COMPILE is called. TEA has the # TEA_PATH_NOSPACE to avoid this issue. CC="\"${PATH64}/cl.exe\" -I\"${MSSDK}/Include\" \ -I\"${MSSDK}/Include/crt\" -I\"${MSSDK}/Include/crt/sys\"" RC="\"${MSSDK}/bin/rc.exe\"" CFLAGS_DEBUG="-nologo -Zi -Od ${runtime}d" # Do not use -O2 for Win64 - this has proved buggy in code gen. CFLAGS_OPTIMIZE="-nologo -O1 ${runtime}" lflags="-nologo -MACHINE:${MACHINE} -LIBPATH:\"${MSSDK}/Lib/${MACHINE}\"" LINKBIN="\"${PATH64}/link.exe\"" # Avoid 'unresolved external symbol __security_cookie' errors. # c.f. http://support.microsoft.com/?id=894573 LIBS="$LIBS bufferoverflowU.lib" else RC="rc" # -Od - no optimization # -WX - warnings as errors CFLAGS_DEBUG="-nologo -Z7 -Od -WX ${runtime}d" # -O2 - create fast code (/Og /Oi /Ot /Oy /Ob2 /Gs /GF /Gy) CFLAGS_OPTIMIZE="-nologo -O2 ${runtime}" lflags="-nologo" LINKBIN="link" fi if test "$doWince" != "no" ; then # Set defaults for common evc4/PPC2003 setup # Currently Tcl requires 300+, possibly 420+ for sockets CEVERSION=420; # could be 211 300 301 400 420 ... TARGETCPU=ARMV4; # could be ARMV4 ARM MIPS SH3 X86 ... ARCH=ARM; # could be ARM MIPS X86EM ... PLATFORM="Pocket PC 2003"; # or "Pocket PC 2002" if test "$doWince" != "yes"; then # If !yes then the user specified something # Reset ARCH to allow user to skip specifying it ARCH= eval `echo $doWince | awk -F "," '{ \ if (length([$]1)) { printf "CEVERSION=\"%s\"\n", [$]1; \ if ([$]1 < 400) { printf "PLATFORM=\"Pocket PC 2002\"\n" } }; \ if (length([$]2)) { printf "TARGETCPU=\"%s\"\n", toupper([$]2) }; \ if (length([$]3)) { printf "ARCH=\"%s\"\n", toupper([$]3) }; \ if (length([$]4)) { printf "PLATFORM=\"%s\"\n", [$]4 }; \ }'` if test "x${ARCH}" = "x" ; then ARCH=$TARGETCPU; fi fi OSVERSION=WCE$CEVERSION; if test "x${WCEROOT}" = "x" ; then WCEROOT="C:/Program Files/Microsoft eMbedded C++ 4.0" if test ! -d "${WCEROOT}" ; then WCEROOT="C:/Program Files/Microsoft eMbedded Tools" fi fi if test "x${SDKROOT}" = "x" ; then SDKROOT="C:/Program Files/Windows CE Tools" if test ! -d "${SDKROOT}" ; then SDKROOT="C:/Windows CE Tools" fi fi # The space-based-path will work for the Makefile, but will # not work if AC_TRY_COMPILE is called. WCEROOT=`echo "$WCEROOT" | sed -e 's!\\\!/!g'` SDKROOT=`echo "$SDKROOT" | sed -e 's!\\\!/!g'` CELIB_DIR=`echo "$CELIB_DIR" | sed -e 's!\\\!/!g'` if test ! -d "${CELIB_DIR}/inc"; then AC_MSG_ERROR([Invalid celib directory "${CELIB_DIR}"]) fi if test ! -d "${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}"\ -o ! -d "${WCEROOT}/EVC/${OSVERSION}/bin"; then AC_MSG_ERROR([could not find PocketPC SDK or target compiler to enable WinCE mode [$CEVERSION,$TARGETCPU,$ARCH,$PLATFORM]]) else CEINCLUDE="${SDKROOT}/${OSVERSION}/${PLATFORM}/include" if test -d "${CEINCLUDE}/${TARGETCPU}" ; then CEINCLUDE="${CEINCLUDE}/${TARGETCPU}" fi CELIBPATH="${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" fi fi if test "$doWince" != "no" ; then CEBINROOT="${WCEROOT}/EVC/${OSVERSION}/bin" if test "${TARGETCPU}" = "X86"; then CC="${CEBINROOT}/cl.exe" else CC="${CEBINROOT}/cl${ARCH}.exe" fi CC="\"${CC}\" -I\"${CELIB_DIR}/inc\" -I\"${CEINCLUDE}\"" RC="\"${WCEROOT}/Common/EVC/bin/rc.exe\"" arch=`echo ${ARCH} | awk '{print tolower([$]0)}'` defs="${ARCH} _${ARCH}_ ${arch} PALM_SIZE _MT _DLL _WINDOWS" for i in $defs ; do AC_DEFINE_UNQUOTED($i) done # if test "${ARCH}" = "X86EM"; then # AC_DEFINE_UNQUOTED(_WIN32_WCE_EMULATION) # fi AC_DEFINE_UNQUOTED(_WIN32_WCE, $CEVERSION) AC_DEFINE_UNQUOTED(UNDER_CE, $CEVERSION) CFLAGS_DEBUG="-nologo -Zi -Od" CFLAGS_OPTIMIZE="-nologo -O2" lversion=`echo ${CEVERSION} | sed -e 's/\(.\)\(..\)/\1\.\2/'` lflags="-nodefaultlib -MACHINE:${ARCH} -LIBPATH:\"${CELIBPATH}\" -subsystem:windowsce,${lversion} -nologo" LINKBIN="\"${CEBINROOT}/link.exe\"" AC_SUBST(CELIB_DIR) if test "${CEVERSION}" -lt 400 ; then LIBS="coredll.lib corelibc.lib winsock.lib" else LIBS="coredll.lib corelibc.lib ws2.lib" fi # celib currently stuck at wce300 status #LIBS="$LIBS \${CELIB_DIR}/wince-${ARCH}-pocket-${OSVERSION}-release/celib.lib" LIBS="$LIBS \"\${CELIB_DIR}/wince-${ARCH}-pocket-wce300-release/celib.lib\"" LIBS_GUI="commctrl.lib commdlg.lib" else LIBS_GUI="gdi32.lib comdlg32.lib imm32.lib comctl32.lib shell32.lib" fi SHLIB_LD="${LINKBIN} -dll -incremental:no ${lflags}" # link -lib only works when -lib is the first arg STLIB_LD="${LINKBIN} -lib ${lflags}" RC_OUT=-fo RC_TYPE=-r RC_INCLUDE=-i RC_DEFINE=-d RES=res MAKE_LIB="\${STLIB_LD} -out:\[$]@" POST_MAKE_LIB= MAKE_EXE="\${CC} -Fe\[$]@" LIBPREFIX="" CFLAGS_DEBUG="${CFLAGS_DEBUG} -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE" CFLAGS_OPTIMIZE="${CFLAGS_OPTIMIZE} -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE" EXTRA_CFLAGS="" CFLAGS_WARNING="-W3" LDFLAGS_DEBUG="-debug" LDFLAGS_OPTIMIZE="-release" # Specify the CC output file names based on the target name CC_OBJNAME="-Fo\[$]@" CC_EXENAME="-Fe\"\$(shell \$(CYGPATH) '\[$]@')\"" # Specify linker flags depending on the type of app being # built -- Console vs. Window. if test "$doWince" != "no" -a "${TARGETCPU}" != "X86"; then LDFLAGS_CONSOLE="-link ${lflags}" LDFLAGS_WINDOW=${LDFLAGS_CONSOLE} else LDFLAGS_CONSOLE="-link -subsystem:console ${lflags}" LDFLAGS_WINDOW="-link -subsystem:windows ${lflags}" fi fi if test "${GCC}" = "yes" ; then AC_CACHE_CHECK(for SEH support in compiler, tcl_cv_seh, AC_TRY_RUN([ #define WIN32_LEAN_AND_MEAN #include #undef WIN32_LEAN_AND_MEAN int main(int argc, char** argv) { int a, b = 0; __try { a = 666 / b; } __except (EXCEPTION_EXECUTE_HANDLER) { return 0; } return 1; } ], tcl_cv_seh=yes, tcl_cv_seh=no, tcl_cv_seh=no) ) if test "$tcl_cv_seh" = "no" ; then AC_DEFINE(HAVE_NO_SEH, 1, [Defined when mingw does not support SEH]) fi # # Check to see if the excpt.h include file provided contains the # definition for EXCEPTION_DISPOSITION; if not, which is the case # with Cygwin's version as of 2002-04-10, define it to be int, # sufficient for getting the current code to work. # AC_CACHE_CHECK(for EXCEPTION_DISPOSITION support in include files, tcl_cv_eh_disposition, AC_TRY_COMPILE([ # define WIN32_LEAN_AND_MEAN # include # undef WIN32_LEAN_AND_MEAN ],[ EXCEPTION_DISPOSITION x; ], tcl_cv_eh_disposition=yes, tcl_cv_eh_disposition=no) ) if test "$tcl_cv_eh_disposition" = "no" ; then AC_DEFINE(EXCEPTION_DISPOSITION, int, [Defined when cygwin/mingw does not support EXCEPTION DISPOSITION]) fi # Check to see if winnt.h defines CHAR, SHORT, and LONG # even if VOID has already been #defined. The win32api # used by mingw and cygwin is known to do this. AC_CACHE_CHECK(for winnt.h that ignores VOID define, tcl_cv_winnt_ignore_void, AC_TRY_COMPILE([ #define VOID void #define WIN32_LEAN_AND_MEAN #include #undef WIN32_LEAN_AND_MEAN ], [ CHAR c; SHORT s; LONG l; ], tcl_cv_winnt_ignore_void=yes, tcl_cv_winnt_ignore_void=no) ) if test "$tcl_cv_winnt_ignore_void" = "yes" ; then AC_DEFINE(HAVE_WINNT_IGNORE_VOID, 1, [Defined when cygwin/mingw ignores VOID define in winnt.h]) fi # See if the compiler supports casting to a union type. # This is used to stop gcc from printing a compiler # warning when initializing a union member. AC_CACHE_CHECK(for cast to union support, tcl_cv_cast_to_union, AC_TRY_COMPILE([], [ union foo { int i; double d; }; union foo f = (union foo) (int) 0; ], tcl_cv_cast_to_union=yes, tcl_cv_cast_to_union=no) ) if test "$tcl_cv_cast_to_union" = "yes"; then AC_DEFINE(HAVE_CAST_TO_UNION, 1, [Defined when compiler supports casting to union type.]) fi fi # DL_LIBS is empty, but then we match the Unix version AC_SUBST(DL_LIBS) AC_SUBST(CFLAGS_DEBUG) AC_SUBST(CFLAGS_OPTIMIZE) AC_SUBST(CFLAGS_WARNING) ]) #------------------------------------------------------------------------ # SC_WITH_TCL -- # # Location of the Tcl build directory. # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-tcl=... # # Defines the following vars: # TCL_BIN_DIR Full path to the tcl build dir. #------------------------------------------------------------------------ AC_DEFUN([SC_WITH_TCL], [ if test -d ../../tcl8.4$1/win; then TCL_BIN_DEFAULT=../../tcl8.4$1/win else TCL_BIN_DEFAULT=../../tcl8.4/win fi AC_ARG_WITH(tcl, [ --with-tcl=DIR use Tcl 8.4 binaries from DIR], TCL_BIN_DIR=$withval, TCL_BIN_DIR=`cd $TCL_BIN_DEFAULT; pwd`) if test ! -d $TCL_BIN_DIR; then AC_MSG_ERROR(Tcl directory $TCL_BIN_DIR does not exist) fi if test ! -f $TCL_BIN_DIR/Makefile; then AC_MSG_ERROR(There is no Makefile in $TCL_BIN_DIR: perhaps you did not specify the Tcl *build* directory (not the toplevel Tcl directory) or you forgot to configure Tcl?) else echo "building against Tcl binaries in: $TCL_BIN_DIR" fi AC_SUBST(TCL_BIN_DIR) ]) #------------------------------------------------------------------------ # SC_PROG_TCLSH # Locate a tclsh shell installed on the system path. This macro # will only find a Tcl shell that already exists on the system. # It will not find a Tcl shell in the Tcl build directory or # a Tcl shell that has been installed from the Tcl build directory. # If a Tcl shell can't be located on the PATH, then TCLSH_PROG will # be set to "". Extensions should take care not to create Makefile # rules that are run by default and depend on TCLSH_PROG. An # extension can't assume that an executable Tcl shell exists at # build time. # # Arguments # none # # Results # Subst's the following values: # TCLSH_PROG #------------------------------------------------------------------------ AC_DEFUN([SC_PROG_TCLSH], [ AC_MSG_CHECKING([for tclsh]) AC_CACHE_VAL(ac_cv_path_tclsh, [ search_path=`echo ${PATH} | sed -e 's/:/ /g'` for dir in $search_path ; do for j in `ls -r $dir/tclsh[[8-9]]*.exe 2> /dev/null` \ `ls -r $dir/tclsh* 2> /dev/null` ; do if test x"$ac_cv_path_tclsh" = x ; then if test -f "$j" ; then ac_cv_path_tclsh=$j break fi fi done done ]) if test -f "$ac_cv_path_tclsh" ; then TCLSH_PROG="$ac_cv_path_tclsh" AC_MSG_RESULT($TCLSH_PROG) else # It is not an error if an installed version of Tcl can't be located. TCLSH_PROG="" AC_MSG_RESULT([No tclsh found on PATH]) fi AC_SUBST(TCLSH_PROG) ]) #------------------------------------------------------------------------ # SC_BUILD_TCLSH # Determine the fully qualified path name of the tclsh executable # in the Tcl build directory. This macro will correctly determine # the name of the tclsh executable even if tclsh has not yet # been built in the build directory. The build tclsh must be used # when running tests from an extension build directory. It is not # correct to use the TCLSH_PROG in cases like this. # # Arguments # none # # Results # Subst's the following values: # BUILD_TCLSH #------------------------------------------------------------------------ AC_DEFUN([SC_BUILD_TCLSH], [ AC_MSG_CHECKING([for tclsh in Tcl build directory]) BUILD_TCLSH=${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT} AC_MSG_RESULT($BUILD_TCLSH) AC_SUBST(BUILD_TCLSH) ]) #-------------------------------------------------------------------- # SC_EMBED_MANIFEST # # Figure out if we can embed the manifest where necessary # # Arguments: # An optional manifest to merge into DLL/EXE. # # Results: # Will define the following vars: # VC_MANIFEST_EMBED_DLL # VC_MANIFEST_EMBED_EXE # #-------------------------------------------------------------------- AC_DEFUN([SC_EMBED_MANIFEST], [ AC_MSG_CHECKING(whether to embed manifest) AC_ARG_ENABLE(embedded-manifest, [ --enable-embedded-manifest embed manifest if possible (default: yes)], [embed_ok=$enableval], [embed_ok=yes]) VC_MANIFEST_EMBED_DLL= VC_MANIFEST_EMBED_EXE= result=no if test "$embed_ok" = "yes" -a "${SHARED_BUILD}" = "1" \ -a "$GCC" != "yes" ; then # Add the magic to embed the manifest into the dll/exe AC_EGREP_CPP([manifest needed], [ #if defined(_MSC_VER) && _MSC_VER >= 1400 print("manifest needed") #endif ], [ # Could do a CHECK_PROG for mt, but should always be with MSVC8+ # Could add 'if test -f' check, but manifest should be created # in this compiler case # Add in a manifest argument that may be specified # XXX Needs improvement so that the test for existence accounts # XXX for a provided (known) manifest VC_MANIFEST_EMBED_DLL="if test -f \[$]@.manifest ; then mt.exe -nologo -manifest \[$]@.manifest $1 -outputresource:\[$]@\;2 ; fi" VC_MANIFEST_EMBED_EXE="if test -f \[$]@.manifest ; then mt.exe -nologo -manifest \[$]@.manifest $1 -outputresource:\[$]@\;1 ; fi" result=yes if test "x$1" != x ; then result="yes ($1)" fi ]) fi AC_MSG_RESULT([$result]) AC_SUBST(VC_MANIFEST_EMBED_DLL) AC_SUBST(VC_MANIFEST_EMBED_EXE) ]) tcl8.4.20/win/tclWinNotify.c0000644003604700454610000003431211737050675014315 0ustar dgp771div/* * tclWinNotify.c -- * * This file contains Windows-specific procedures for the notifier, * which is the lowest-level part of the Tcl event loop. This file * works together with ../generic/tclNotify.c. * * Copyright (c) 1995-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclWinInt.h" /* * The follwing static indicates whether this module has been initialized. */ #define INTERVAL_TIMER 1 /* Handle of interval timer. */ #define WM_WAKEUP WM_USER /* Message that is send by * Tcl_AlertNotifier. */ /* * The following static structure contains the state information for the * Windows implementation of the Tcl notifier. One of these structures * is created for each thread that is using the notifier. */ typedef struct ThreadSpecificData { CRITICAL_SECTION crit; /* Monitor for this notifier. */ DWORD thread; /* Identifier for thread associated with this * notifier. */ HANDLE event; /* Event object used to wake up the notifier * thread. */ int pending; /* Alert message pending, this field is * locked by the notifierMutex. */ HWND hwnd; /* Messaging window. */ int timeout; /* Current timeout value. */ int timerActive; /* 1 if interval timer is running. */ } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; extern TclStubs tclStubs; extern Tcl_NotifierProcs tclOriginalNotifier; /* * The following static indicates the number of threads that have * initialized notifiers. It controls the lifetime of the TclNotifier * window class. * * You must hold the notifierMutex lock before accessing this variable. */ static int notifierCount = 0; TCL_DECLARE_MUTEX(notifierMutex) /* * Static routines defined in this file. */ static LRESULT CALLBACK NotifierProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); /* *---------------------------------------------------------------------- * * Tcl_InitNotifier -- * * Initializes the platform specific notifier state. * * Results: * Returns a handle to the notifier state for this thread.. * * Side effects: * None. * *---------------------------------------------------------------------- */ ClientData Tcl_InitNotifier() { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); WNDCLASS class; /* * Register Notifier window class if this is the first thread to * use this module. */ Tcl_MutexLock(¬ifierMutex); if (notifierCount == 0) { class.style = 0; class.cbClsExtra = 0; class.cbWndExtra = 0; class.hInstance = TclWinGetTclInstance(); class.hbrBackground = NULL; class.lpszMenuName = NULL; class.lpszClassName = "TclNotifier"; class.lpfnWndProc = NotifierProc; class.hIcon = NULL; class.hCursor = NULL; if (!RegisterClassA(&class)) { panic("Unable to register TclNotifier window class"); } } notifierCount++; Tcl_MutexUnlock(¬ifierMutex); tsdPtr->pending = 0; tsdPtr->timerActive = 0; InitializeCriticalSection(&tsdPtr->crit); tsdPtr->hwnd = NULL; tsdPtr->thread = GetCurrentThreadId(); tsdPtr->event = CreateEvent(NULL, TRUE /* manual */, FALSE /* !signaled */, NULL); return (ClientData) tsdPtr; } /* *---------------------------------------------------------------------- * * Tcl_FinalizeNotifier -- * * This function is called to cleanup the notifier state before * a thread is terminated. * * Results: * None. * * Side effects: * May dispose of the notifier window and class. * *---------------------------------------------------------------------- */ void Tcl_FinalizeNotifier(clientData) ClientData clientData; /* Pointer to notifier data. */ { ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData; /* * Only finalize the notifier if a notifier was installed in the * current thread; there is a route in which this is not * guaranteed to be true (when tclWin32Dll.c:DllMain() is called * with the flag DLL_PROCESS_DETACH by the OS, which could be * doing so from a thread that's never previously been involved * with Tcl, e.g. the task manager) so this check is important. * * Fixes Bug #217982 reported by Hugh Vu and Gene Leache. */ if (tsdPtr == NULL) { return; } DeleteCriticalSection(&tsdPtr->crit); CloseHandle(tsdPtr->event); /* * Clean up the timer and messaging window for this thread. */ if (tsdPtr->hwnd) { KillTimer(tsdPtr->hwnd, INTERVAL_TIMER); DestroyWindow(tsdPtr->hwnd); } /* * If this is the last thread to use the notifier, unregister * the notifier window class. */ Tcl_MutexLock(¬ifierMutex); notifierCount--; if (notifierCount == 0) { UnregisterClassA("TclNotifier", TclWinGetTclInstance()); } Tcl_MutexUnlock(¬ifierMutex); } /* *---------------------------------------------------------------------- * * Tcl_AlertNotifier -- * * Wake up the specified notifier from any thread. This routine * is called by the platform independent notifier code whenever * the Tcl_ThreadAlert routine is called. This routine is * guaranteed not to be called on a given notifier after * Tcl_FinalizeNotifier is called for that notifier. This routine * is typically called from a thread other than the notifier's * thread. * * Results: * None. * * Side effects: * Sends a message to the messaging window for the notifier * if there isn't already one pending. * *---------------------------------------------------------------------- */ void Tcl_AlertNotifier(clientData) ClientData clientData; /* Pointer to thread data. */ { ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData; /* * Note that we do not need to lock around access to the hwnd * because the race condition has no effect since any race condition * implies that the notifier thread is already awake. */ if (tsdPtr->hwnd) { /* * We do need to lock around access to the pending flag. */ EnterCriticalSection(&tsdPtr->crit); if (!tsdPtr->pending) { PostMessage(tsdPtr->hwnd, WM_WAKEUP, 0, 0); } tsdPtr->pending = 1; LeaveCriticalSection(&tsdPtr->crit); } else { SetEvent(tsdPtr->event); } } /* *---------------------------------------------------------------------- * * Tcl_SetTimer -- * * This procedure sets the current notifier timer value. The * notifier will ensure that Tcl_ServiceAll() is called after * the specified interval, even if no events have occurred. * * Results: * None. * * Side effects: * Replaces any previous timer. * *---------------------------------------------------------------------- */ void Tcl_SetTimer( Tcl_Time *timePtr) /* Maximum block time, or NULL. */ { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); UINT timeout; /* * Allow the notifier to be hooked. This may not make sense * on Windows, but mirrors the UNIX hook. */ if (tclStubs.tcl_SetTimer != tclOriginalNotifier.setTimerProc) { tclStubs.tcl_SetTimer(timePtr); return; } /* * We only need to set up an interval timer if we're being called * from an external event loop. If we don't have a window handle * then we just return immediately and let Tcl_WaitForEvent handle * timeouts. */ if (!tsdPtr->hwnd) { return; } if (!timePtr) { timeout = 0; } else { /* * Make sure we pass a non-zero value into the timeout argument. * Windows seems to get confused by zero length timers. */ timeout = timePtr->sec * 1000 + timePtr->usec / 1000; if (timeout == 0) { timeout = 1; } } tsdPtr->timeout = timeout; if (timeout != 0) { tsdPtr->timerActive = 1; SetTimer(tsdPtr->hwnd, INTERVAL_TIMER, (unsigned long) tsdPtr->timeout, NULL); } else { tsdPtr->timerActive = 0; KillTimer(tsdPtr->hwnd, INTERVAL_TIMER); } } /* *---------------------------------------------------------------------- * * Tcl_ServiceModeHook -- * * This function is invoked whenever the service mode changes. * * Results: * None. * * Side effects: * If this is the first time the notifier is set into * TCL_SERVICE_ALL, then the communication window is created. * *---------------------------------------------------------------------- */ void Tcl_ServiceModeHook(mode) int mode; /* Either TCL_SERVICE_ALL, or * TCL_SERVICE_NONE. */ { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); /* * If this is the first time that the notifier has been used from a * modal loop, then create a communication window. Note that after * this point, the application needs to service events in a timely * fashion or Windows will hang waiting for the window to respond * to synchronous system messages. At some point, we may want to * consider destroying the window if we leave the modal loop, but * for now we'll leave it around. */ if (mode == TCL_SERVICE_ALL && !tsdPtr->hwnd) { tsdPtr->hwnd = CreateWindowA("TclNotifier", "TclNotifier", WS_TILED, 0, 0, 0, 0, NULL, NULL, TclWinGetTclInstance(), NULL); /* * Send an initial message to the window to ensure that we wake up the * notifier once we get into the modal loop. This will force the * notifier to recompute the timeout value and schedule a timer * if one is needed. */ Tcl_AlertNotifier((ClientData)tsdPtr); } } /* *---------------------------------------------------------------------- * * NotifierProc -- * * This procedure is invoked by Windows to process events on * the notifier window. Messages will be sent to this window * in response to external timer events or calls to * TclpAlertTsdPtr-> * * Results: * A standard windows result. * * Side effects: * Services any pending events. * *---------------------------------------------------------------------- */ static LRESULT CALLBACK NotifierProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (message == WM_WAKEUP) { EnterCriticalSection(&tsdPtr->crit); tsdPtr->pending = 0; LeaveCriticalSection(&tsdPtr->crit); } else if (message != WM_TIMER) { return DefWindowProc(hwnd, message, wParam, lParam); } /* * Process all of the runnable events. */ Tcl_ServiceAll(); return 0; } /* *---------------------------------------------------------------------- * * Tcl_WaitForEvent -- * * This function is called by Tcl_DoOneEvent to wait for new * events on the message queue. If the block time is 0, then * Tcl_WaitForEvent just polls the event queue without blocking. * * Results: * Returns -1 if a WM_QUIT message is detected, returns 1 if * a message was dispatched, otherwise returns 0. * * Side effects: * Dispatches a message to a window procedure, which could do * anything. * *---------------------------------------------------------------------- */ int Tcl_WaitForEvent( Tcl_Time *timePtr) /* Maximum block time, or NULL. */ { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); MSG msg; DWORD timeout, result; int status; /* * Allow the notifier to be hooked. This may not make * sense on windows, but mirrors the UNIX hook. */ if (tclStubs.tcl_WaitForEvent != tclOriginalNotifier.waitForEventProc) { return tclStubs.tcl_WaitForEvent(timePtr); } /* * Compute the timeout in milliseconds. */ if (timePtr) { timeout = timePtr->sec * 1000 + timePtr->usec / 1000; } else { timeout = INFINITE; } /* * Check to see if there are any messages in the queue before waiting * because MsgWaitForMultipleObjects will not wake up if there are events * currently sitting in the queue. */ if (!PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) { /* * Wait for something to happen (a signal from another thread, a * message, or timeout). */ result = MsgWaitForMultipleObjects(1, &tsdPtr->event, FALSE, timeout, QS_ALLINPUT); } /* * Check to see if there are any messages to process. */ if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) { /* * Retrieve and dispatch the first message. */ result = GetMessage(&msg, NULL, 0, 0); if (result == 0) { /* * We received a request to exit this thread (WM_QUIT), so * propagate the quit message and start unwinding. */ PostQuitMessage((int) msg.wParam); status = -1; } else if (result == (DWORD)-1) { /* * We got an error from the system. I have no idea why this would * happen, so we'll just unwind. */ status = -1; } else { TranslateMessage(&msg); DispatchMessage(&msg); status = 1; } } else { status = 0; } ResetEvent(tsdPtr->event); return status; } /* *---------------------------------------------------------------------- * * Tcl_Sleep -- * * Delay execution for the specified number of milliseconds. * * Results: * None. * * Side effects: * Time passes. * *---------------------------------------------------------------------- */ void Tcl_Sleep(ms) int ms; /* Number of milliseconds to sleep. */ { /* * Simply calling 'Sleep' for the requisite number of milliseconds * can make the process appear to wake up early because it isn't * synchronized with the CPU performance counter that is used in * tclWinTime.c. This behavior is probably benign, but messes * up some of the corner cases in the test suite. We get around * this problem by repeating the 'Sleep' call as many times * as necessary to make the clock advance by the requisite amount. */ Tcl_Time now; /* Current wall clock time */ Tcl_Time desired; /* Desired wakeup time */ DWORD sleepTime = ms; /* Time to sleep */ Tcl_GetTime( &now ); desired.sec = now.sec + ( ms / 1000 ); desired.usec = now.usec + 1000 * ( ms % 1000 ); if ( desired.usec > 1000000 ) { ++desired.sec; desired.usec -= 1000000; } for ( ; ; ) { Sleep( sleepTime ); Tcl_GetTime( &now ); if ( now.sec > desired.sec ) { break; } else if ( ( now.sec == desired.sec ) && ( now.usec >= desired.usec ) ) { break; } sleepTime = ( ( 1000 * ( desired.sec - now.sec ) ) + ( ( desired.usec - now.usec ) / 1000 ) ); } } tcl8.4.20/win/Makefile.in0000644003604700454610000004475312153151142013557 0ustar dgp771div# # This file is a Makefile for Tcl. If it has the name "Makefile.in" # then it is a template for a Makefile; to generate the actual Makefile, # run "./configure", which is a configuration script generated by the # "autoconf" program (constructs like "@foo@" will get replaced in the # actual Makefile. VERSION = @TCL_VERSION@ #---------------------------------------------------------------- # Things you can change to personalize the Makefile for your own # site (you can make these changes in either Makefile.in or # Makefile, but changes to Makefile will get lost if you re-run # the configuration script). #---------------------------------------------------------------- # Default top-level directories in which to install architecture- # specific files (exec_prefix) and machine-independent files such # as scripts (prefix). The values specified here may be overridden # at configure-time with the --exec-prefix and --prefix options # to the "configure" script. prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ libdir = @libdir@ includedir = @includedir@ mandir = @mandir@ # The following definition can be set to non-null for special systems # like AFS with replication. It allows the pathnames used for installation # to be different than those used for actually reference files at # run-time. INSTALL_ROOT is prepended to $prefix and $exec_prefix # when installing files. INSTALL_ROOT = # Directory from which applications will reference the library of Tcl # scripts (note: you can set the TCL_LIBRARY environment variable at # run-time to override this value): TCL_LIBRARY = $(prefix)/lib/tcl$(VERSION) # Path to use at runtime to refer to LIB_INSTALL_DIR: LIB_RUNTIME_DIR = $(libdir) # Directory in which to install the program tclsh: BIN_INSTALL_DIR = $(INSTALL_ROOT)$(bindir) # Directory in which to install the .a or .so binary for the Tcl library: LIB_INSTALL_DIR = $(INSTALL_ROOT)$(libdir) # Path name to use when installing library scripts. SCRIPT_INSTALL_DIR = $(INSTALL_ROOT)$(TCL_LIBRARY) # Directory in which to install the include file tcl.h: INCLUDE_INSTALL_DIR = $(INSTALL_ROOT)$(includedir) # Directory in which to (optionally) install the private tcl headers: PRIVATE_INCLUDE_INSTALL_DIR = $(INSTALL_ROOT)$(includedir) # Top-level directory in which to install manual entries: MAN_INSTALL_DIR = $(INSTALL_ROOT)$(mandir) # Directory in which to install manual entry for tclsh: MAN1_INSTALL_DIR = $(MAN_INSTALL_DIR)/man1 # Directory in which to install manual entries for Tcl's C library # procedures: MAN3_INSTALL_DIR = $(MAN_INSTALL_DIR)/man3 # Directory in which to install manual entries for the built-in # Tcl commands: MANN_INSTALL_DIR = $(MAN_INSTALL_DIR)/mann # Libraries built with optimization switches have this additional extension TCL_DBGX = @TCL_DBGX@ # warning flags CFLAGS_WARNING = @CFLAGS_WARNING@ # The default switches for optimization or debugging CFLAGS_DEBUG = @CFLAGS_DEBUG@ CFLAGS_OPTIMIZE = @CFLAGS_OPTIMIZE@ # To change the compiler switches, for example to change from optimization to # debugging symbols, change the following line: #CFLAGS = $(CFLAGS_DEBUG) #CFLAGS = $(CFLAGS_OPTIMIZE) #CFLAGS = $(CFLAGS_DEBUG) $(CFLAGS_OPTIMIZE) CFLAGS = @CFLAGS@ @CFLAGS_DEFAULT@ # To enable compilation debugging reverse the comment characters on # one of the following lines. COMPILE_DEBUG_FLAGS = #COMPILE_DEBUG_FLAGS = -DTCL_COMPILE_DEBUG #COMPILE_DEBUG_FLAGS = -DTCL_COMPILE_DEBUG -DTCL_COMPILE_STATS # Special compiler flags to use when building man2tcl on Windows. MAN2TCLFLAGS = @MAN2TCLFLAGS@ SRC_DIR = @srcdir@ ROOT_DIR = @srcdir@/.. GENERIC_DIR = @srcdir@/../generic WIN_DIR = @srcdir@ COMPAT_DIR = @srcdir@/../compat # Converts a POSIX path to a Windows native path. CYGPATH = @CYGPATH@ GENERIC_DIR_NATIVE = $(shell $(CYGPATH) '$(GENERIC_DIR)' | sed 's!\\!/!g') WIN_DIR_NATIVE = $(shell $(CYGPATH) '$(WIN_DIR)' | sed 's!\\!/!g') ROOT_DIR_NATIVE = $(shell $(CYGPATH) '$(ROOT_DIR)' | sed 's!\\!/!g') LIBRARY_DIR = $(ROOT_DIR_NATIVE)/library DLLSUFFIX = @DLLSUFFIX@ LIBSUFFIX = @LIBSUFFIX@ EXESUFFIX = @EXESUFFIX@ TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@ TCL_DLL_FILE = @TCL_DLL_FILE@ TCL_LIB_FILE = @TCL_LIB_FILE@ DDE_DLL_FILE = tcldde$(DDEVER)${DLLSUFFIX} DDE_LIB_FILE = tcldde$(DDEVER)${LIBSUFFIX} REG_DLL_FILE = tclreg$(REGVER)${DLLSUFFIX} REG_LIB_FILE = tclreg$(REGVER)${LIBSUFFIX} PIPE_DLL_FILE = tclpip$(VER)${DLLSUFFIX} SHARED_LIBRARIES = $(TCL_DLL_FILE) $(TCL_STUB_LIB_FILE) \ $(DDE_DLL_FILE) $(REG_DLL_FILE) $(PIPE_DLL_FILE) STATIC_LIBRARIES = $(TCL_LIB_FILE) $(REG_LIB_FILE) $(DDE_LIB_FILE) # To compile without backward compatibility and deprecated code # uncomment the following NO_DEPRECATED_FLAGS = #NO_DEPRECATED_FLAGS = -DTCL_NO_DEPRECATED # TCL_EXE is the name of a tclsh executable that is available *BEFORE* # running make for the first time. Certain build targets (make genstubs) # need it to be available on the PATH. This executable should *NOT* be # required just to do a normal build although it can be required to run # make dist. TCL_EXE = tclsh TCLSH = tclsh$(VER)${EXESUFFIX} TCLTEST = tcltest${EXEEXT} CAT32 = cat32$(EXEEXT) MAN2TCL = man2tcl$(EXEEXT) @SET_MAKE@ # Setting the VPATH variable to a list of paths will cause the # makefile to look into these paths when resolving .c to .obj # dependencies. VPATH = $(GENERIC_DIR):$(WIN_DIR):$(COMPAT_DIR) AR = @AR@ RANLIB = @RANLIB@ CC = @CC@ RC = @RC@ RES = @RES@ AC_FLAGS = @EXTRA_CFLAGS@ @DEFS@ CPPFLAGS = @CPPFLAGS@ LDFLAGS_DEBUG = @LDFLAGS_DEBUG@ LDFLAGS_OPTIMIZE = @LDFLAGS_OPTIMIZE@ LDFLAGS = @LDFLAGS@ @LDFLAGS_DEFAULT@ LDFLAGS_CONSOLE = @LDFLAGS_CONSOLE@ LDFLAGS_WINDOW = @LDFLAGS_WINDOW@ EXEEXT = @EXEEXT@ OBJEXT = @OBJEXT@ STLIB_LD = @STLIB_LD@ SHLIB_LD = @SHLIB_LD@ SHLIB_LD_LIBS = @SHLIB_LD_LIBS@ $(LIBS) SHLIB_CFLAGS = @SHLIB_CFLAGS@ SHLIB_SUFFIX = @SHLIB_SUFFIX@ VER = @TCL_MAJOR_VERSION@@TCL_MINOR_VERSION@ DOTVER = @TCL_MAJOR_VERSION@.@TCL_MINOR_VERSION@ DDEVER = @TCL_DDE_MAJOR_VERSION@@TCL_DDE_MINOR_VERSION@ DDEDOTVER = @TCL_DDE_MAJOR_VERSION@.@TCL_DDE_MINOR_VERSION@ REGVER = @TCL_REG_MAJOR_VERSION@@TCL_REG_MINOR_VERSION@ REGDOTVER = @TCL_REG_MAJOR_VERSION@.@TCL_REG_MINOR_VERSION@ LIBS = @LIBS@ RMDIR = rm -rf MKDIR = mkdir -p SHELL = @SHELL@ RM = rm -f COPY = cp CC_SWITCHES = ${CFLAGS} ${CFLAGS_WARNING} ${TCL_SHLIB_CFLAGS} \ -I"${GENERIC_DIR_NATIVE}" -I"${WIN_DIR_NATIVE}" ${AC_FLAGS} \ ${COMPILE_DEBUG_FLAGS} ${NO_DEPRECATED_FLAGS} CC_OBJNAME = @CC_OBJNAME@ CC_EXENAME = @CC_EXENAME@ STUB_CC_SWITCHES = ${CFLAGS} ${CFLAGS_WARNING} ${SHLIB_CFLAGS} \ -I"${GENERIC_DIR_NATIVE}" -I"${WIN_DIR_NATIVE}" ${AC_FLAGS} \ ${COMPILE_DEBUG_FLAGS} TCLTEST_OBJS = \ tclTest.$(OBJEXT) \ tclTestObj.$(OBJEXT) \ tclTestProcBodyObj.$(OBJEXT) \ tclThreadTest.$(OBJEXT) \ tclWinTest.$(OBJEXT) \ testMain.$(OBJEXT) GENERIC_OBJS = \ regcomp.$(OBJEXT) \ regexec.$(OBJEXT) \ regfree.$(OBJEXT) \ regerror.$(OBJEXT) \ tclAlloc.$(OBJEXT) \ tclAsync.$(OBJEXT) \ tclBasic.$(OBJEXT) \ tclBinary.$(OBJEXT) \ tclCkalloc.$(OBJEXT) \ tclClock.$(OBJEXT) \ tclCmdAH.$(OBJEXT) \ tclCmdIL.$(OBJEXT) \ tclCmdMZ.$(OBJEXT) \ tclCompCmds.$(OBJEXT) \ tclCompExpr.$(OBJEXT) \ tclCompile.$(OBJEXT) \ tclDate.$(OBJEXT) \ tclEncoding.$(OBJEXT) \ tclEnv.$(OBJEXT) \ tclEvent.$(OBJEXT) \ tclExecute.$(OBJEXT) \ tclFCmd.$(OBJEXT) \ tclFileName.$(OBJEXT) \ tclGet.$(OBJEXT) \ tclHash.$(OBJEXT) \ tclHistory.$(OBJEXT) \ tclIndexObj.$(OBJEXT) \ tclInterp.$(OBJEXT) \ tclIO.$(OBJEXT) \ tclIOCmd.$(OBJEXT) \ tclIOGT.$(OBJEXT) \ tclIOSock.$(OBJEXT) \ tclIOUtil.$(OBJEXT) \ tclLink.$(OBJEXT) \ tclLiteral.$(OBJEXT) \ tclListObj.$(OBJEXT) \ tclLoad.$(OBJEXT) \ tclMain.$(OBJEXT) \ tclNamesp.$(OBJEXT) \ tclNotify.$(OBJEXT) \ tclObj.$(OBJEXT) \ tclPanic.$(OBJEXT) \ tclParse.$(OBJEXT) \ tclParseExpr.$(OBJEXT) \ tclPipe.$(OBJEXT) \ tclPkg.$(OBJEXT) \ tclPosixStr.$(OBJEXT) \ tclPreserve.$(OBJEXT) \ tclProc.$(OBJEXT) \ tclRegexp.$(OBJEXT) \ tclResolve.$(OBJEXT) \ tclResult.$(OBJEXT) \ tclScan.$(OBJEXT) \ tclStringObj.$(OBJEXT) \ tclStubInit.$(OBJEXT) \ tclStubLib.$(OBJEXT) \ tclThread.$(OBJEXT) \ tclThreadAlloc.$(OBJEXT) \ tclThreadJoin.$(OBJEXT) \ tclTimer.$(OBJEXT) \ tclUtf.$(OBJEXT) \ tclUtil.$(OBJEXT) \ tclVar.$(OBJEXT) WIN_OBJS = \ tclWin32Dll.$(OBJEXT) \ tclWinChan.$(OBJEXT) \ tclWinConsole.$(OBJEXT) \ tclWinSerial.$(OBJEXT) \ tclWinError.$(OBJEXT) \ tclWinFCmd.$(OBJEXT) \ tclWinFile.$(OBJEXT) \ tclWinInit.$(OBJEXT) \ tclWinLoad.$(OBJEXT) \ tclWinMtherr.$(OBJEXT) \ tclWinNotify.$(OBJEXT) \ tclWinPipe.$(OBJEXT) \ tclWinSock.$(OBJEXT) \ tclWinThrd.$(OBJEXT) \ tclWinTime.$(OBJEXT) COMPAT_OBJS = \ strftime.$(OBJEXT) strtoll.$(OBJEXT) strtoull.$(OBJEXT) PIPE_OBJS = stub16.$(OBJEXT) DDE_OBJS = tclWinDde.$(OBJEXT) REG_OBJS = tclWinReg.$(OBJEXT) STUB_OBJS = tclStubLib.$(OBJEXT) TCLSH_OBJS = tclAppInit.$(OBJEXT) TCL_OBJS = ${GENERIC_OBJS} ${WIN_OBJS} ${COMPAT_OBJS} TCL_DOCS = "$(ROOT_DIR_NATIVE)"/doc/*.[13n] all: binaries libraries doc tcltest: $(TCLTEST) binaries: @LIBRARIES@ $(TCLSH) libraries: doc: winhelp: $(ROOT_DIR)/tools/man2help.tcl $(MAN2TCL) TCL_LIBRARY="$(LIBRARY_DIR)"; export TCL_LIBRARY; \ ./$(TCLSH) "$(ROOT_DIR_NATIVE)"/tools/man2help.tcl tcl "$(VER)" $(TCL_DOCS) hcw /c /e tcl.hpj $(MAN2TCL): $(ROOT_DIR)/tools/man2tcl.c $(CC) $(CFLAGS_OPTIMIZE) $(MAN2TCLFLAGS) -o $(MAN2TCL) "$(ROOT_DIR_NATIVE)"/tools/man2tcl.c $(TCLSH): $(TCL_LIB_FILE) $(TCL_STUB_LIB_FILE) $(TCLSH_OBJS) tclsh.$(RES) $(CC) $(CFLAGS) $(TCLSH_OBJS) $(TCL_LIB_FILE) $(LIBS) \ tclsh.$(RES) $(CC_EXENAME) $(LDFLAGS_CONSOLE) $(TCLTEST): $(TCL_LIB_FILE) $(TCLTEST_OBJS) $(CAT32) tclsh.$(RES) $(CC) $(CFLAGS) $(TCLTEST_OBJS) $(TCL_LIB_FILE) $(LIBS) \ tclsh.$(RES) $(CC_EXENAME) $(LDFLAGS_CONSOLE) cat32.$(OBJEXT): cat.c $(CC) -c $(CC_SWITCHES) @DEPARG@ $(CC_OBJNAME) $(CAT32): cat32.$(OBJEXT) $(CC) $(CFLAGS) cat32.$(OBJEXT) $(CC_EXENAME) $(LIBS) $(LDFLAGS_CONSOLE) # The following targets are configured by autoconf to generate either # a shared library or static library ${TCL_STUB_LIB_FILE}: ${STUB_OBJS} @$(RM) ${TCL_STUB_LIB_FILE} @MAKE_LIB@ ${STUB_OBJS} @POST_MAKE_LIB@ ${TCL_DLL_FILE}: ${TCL_OBJS} tcl.$(RES) @$(RM) ${TCL_DLL_FILE} @MAKE_DLL@ ${TCL_OBJS} tcl.$(RES) $(SHLIB_LD_LIBS) ${TCL_LIB_FILE}: ${TCL_OBJS} @$(RM) ${TCL_LIB_FILE} @MAKE_LIB@ ${TCL_OBJS} @POST_MAKE_LIB@ ${DDE_DLL_FILE}: ${DDE_OBJS} ${TCL_STUB_LIB_FILE} @$(RM) ${DDE_DLL_FILE} @MAKE_DLL@ ${DDE_OBJS} $(TCL_STUB_LIB_FILE) $(SHLIB_LD_LIBS) ${DDE_LIB_FILE}: ${DDE_OBJS} ${TCL_LIB_FILE} @$(RM) ${DDE_LIB_FILE} @MAKE_LIB@ ${DDE_OBJS} ${TCL_LIB_FILE} ${REG_DLL_FILE}: ${REG_OBJS} ${TCL_STUB_LIB_FILE} @$(RM) ${REG_DLL_FILE} @MAKE_DLL@ ${REG_OBJS} $(TCL_STUB_LIB_FILE) $(SHLIB_LD_LIBS) ${REG_LIB_FILE}: ${REG_OBJS} ${TCL_LIB_FILE} @$(RM) ${REG_LIB_FILE} @MAKE_LIB@ ${REG_OBJS} ${TCL_LIB_FILE} # PIPE_DLL_FILE is actually an executable, don't build it # like a DLL. ${PIPE_DLL_FILE}: ${PIPE_OBJS} @$(RM) ${PIPE_DLL_FILE} @MAKE_EXE@ $(CFLAGS) ${PIPE_OBJS} $(LIBS) $(LDFLAGS_CONSOLE) # Add the object extension to the implicit rules. By default .obj is not # automatically added. .SUFFIXES: .${OBJEXT} .SUFFIXES: .$(RES) .SUFFIXES: .rc # Special case object targets tclWinInit.${OBJEXT}: tclWinInit.c $(CC) -c $(CC_SWITCHES) -DBUILD_tcl $(EXTFLAGS) @DEPARG@ $(CC_OBJNAME) tclWinPipe.${OBJEXT}: tclWinPipe.c $(CC) -c $(CC_SWITCHES) -DBUILD_tcl -DTCL_PIPE_DLL=\"$(PIPE_DLL_FILE)\" \ $(EXTFLAGS) @DEPARG@ $(CC_OBJNAME) testMain.${OBJEXT}: tclAppInit.c $(CC) -c $(CC_SWITCHES) -DTCL_TEST @DEPARG@ $(CC_OBJNAME) tclTest.${OBJEXT}: tclTest.c $(CC) -c $(CC_SWITCHES) @DEPARG@ $(CC_OBJNAME) tclTestObj.${OBJEXT}: tclTestObj.c $(CC) -c $(CC_SWITCHES) @DEPARG@ $(CC_OBJNAME) tclWinTest.${OBJEXT}: tclWinTest.c $(CC) -c $(CC_SWITCHES) @DEPARG@ $(CC_OBJNAME) tclAppInit.${OBJEXT} : tclAppInit.c $(CC) -c $(CC_SWITCHES) @DEPARG@ $(CC_OBJNAME) # The following objects should be built using the stub interfaces tclWinReg.${OBJEXT} : tclWinReg.c $(CC) -c $(CC_SWITCHES) -DUSE_TCL_STUBS @DEPARG@ $(CC_OBJNAME) tclWinDde.${OBJEXT} : tclWinDde.c $(CC) -c $(CC_SWITCHES) -DUSE_TCL_STUBS @DEPARG@ $(CC_OBJNAME) # The following objects are part of the stub library and should not # be built as DLL objects but none of the symbols should be exported tclStubLib.${OBJEXT}: tclStubLib.c $(CC) -c $(CC_SWITCHES) -DSTATIC_BUILD @DEPARG@ $(CC_OBJNAME) # Implicit rule for all object files that will end up in the Tcl library .c.${OBJEXT}: $(CC) -c $(CC_SWITCHES) -DBUILD_tcl @DEPARG@ $(CC_OBJNAME) .rc.$(RES): $(RC) @RC_OUT@ $@ @RC_TYPE@ @RC_DEFINES@ @RC_INCLUDE@ "$(GENERIC_DIR_NATIVE)" @RC_INCLUDE@ "$(WIN_DIR_NATIVE)" @DEPARG@ install: all install-binaries install-libraries install-doc install-binaries: binaries @for i in "$(LIB_INSTALL_DIR)" "$(BIN_INSTALL_DIR)" ; \ do \ if [ ! -d $$i ] ; then \ echo "Making directory $$i"; \ $(MKDIR) $$i; \ chmod 755 $$i; \ else true; \ fi; \ done; @for i in dde$(DDEDOTVER) reg$(REGDOTVER); \ do \ if [ ! -d $(LIB_INSTALL_DIR)/$$i ] ; then \ echo "Making directory $(LIB_INSTALL_DIR)/$$i"; \ $(MKDIR) $(LIB_INSTALL_DIR)/$$i; \ else true; \ fi; \ done; @for i in $(TCL_DLL_FILE) $(TCLSH) $(PIPE_DLL_FILE); \ do \ if [ -f $$i ]; then \ echo "Installing $$i to $(BIN_INSTALL_DIR)/"; \ $(COPY) $$i "$(BIN_INSTALL_DIR)"; \ fi; \ done @for i in tclConfig.sh $(TCL_LIB_FILE) $(TCL_STUB_LIB_FILE); \ do \ if [ -f $$i ]; then \ echo "Installing $$i to $(LIB_INSTALL_DIR)/"; \ $(COPY) $$i "$(LIB_INSTALL_DIR)"; \ fi; \ done @if [ -f $(DDE_DLL_FILE) ]; then \ echo installing $(DDE_DLL_FILE); \ $(COPY) $(DDE_DLL_FILE) $(LIB_INSTALL_DIR)/dde$(DDEDOTVER); \ $(COPY) $(ROOT_DIR)/library/dde/pkgIndex.tcl \ $(LIB_INSTALL_DIR)/dde$(DDEDOTVER); \ fi @if [ -f $(DDE_LIB_FILE) ]; then \ echo installing $(DDE_LIB_FILE); \ $(COPY) $(DDE_LIB_FILE) $(LIB_INSTALL_DIR)/dde$(DDEDOTVER); \ fi @if [ -f $(REG_DLL_FILE) ]; then \ echo installing $(REG_DLL_FILE); \ $(COPY) $(REG_DLL_FILE) $(LIB_INSTALL_DIR)/reg$(REGDOTVER); \ $(COPY) $(ROOT_DIR)/library/reg/pkgIndex.tcl \ $(LIB_INSTALL_DIR)/reg$(REGDOTVER); \ fi @if [ -f $(REG_LIB_FILE) ]; then \ echo installing $(REG_LIB_FILE); \ $(COPY) $(REG_LIB_FILE) $(LIB_INSTALL_DIR)/reg$(REGDOTVER); \ fi install-libraries: libraries @for i in $(prefix)/lib $(INCLUDE_INSTALL_DIR) \ $(SCRIPT_INSTALL_DIR); \ do \ if [ ! -d $$i ] ; then \ echo "Making directory $$i"; \ $(MKDIR) $$i; \ else true; \ fi; \ done; @for i in platform http1.0 http2.5 opt0.4 encoding msgcat1.3 tcltest2.2; \ do \ if [ ! -d $(SCRIPT_INSTALL_DIR)/$$i ] ; then \ echo "Making directory $(SCRIPT_INSTALL_DIR)/$$i"; \ $(MKDIR) $(SCRIPT_INSTALL_DIR)/$$i; \ else true; \ fi; \ done; @echo "Installing header files"; @for i in "$(GENERIC_DIR)/tcl.h" "$(GENERIC_DIR)/tclDecls.h" \ "$(GENERIC_DIR)/tclPlatDecls.h" ; \ do \ $(COPY) "$$i" "$(INCLUDE_INSTALL_DIR)"; \ done; @echo "Installing library files to $(SCRIPT_INSTALL_DIR)"; @for i in $(ROOT_DIR)/library/*.tcl $(ROOT_DIR)/library/tclIndex; \ do \ $(COPY) "$$i" "$(SCRIPT_INSTALL_DIR)"; \ done; @echo "Installing library platform directory"; @for j in $(ROOT_DIR)/library/platform/*.tcl; \ do \ $(COPY) "$$j" "$(SCRIPT_INSTALL_DIR)/platform"; \ done; @echo "Installing library http1.0 directory"; @for j in $(ROOT_DIR)/library/http1.0/*.tcl; \ do \ $(COPY) "$$j" "$(SCRIPT_INSTALL_DIR)/http1.0"; \ done; @echo "Installing library http2.5 directory"; @for j in $(ROOT_DIR)/library/http/*.tcl; \ do \ $(COPY) "$$j" "$(SCRIPT_INSTALL_DIR)/http2.5"; \ done; @echo "Installing library opt0.4 directory"; @for j in $(ROOT_DIR)/library/opt/*.tcl; \ do \ $(COPY) "$$j" "$(SCRIPT_INSTALL_DIR)/opt0.4"; \ done; @echo "Installing library msgcat1.3 directory"; @for j in $(ROOT_DIR)/library/msgcat/*.tcl; \ do \ $(COPY) "$$j" "$(SCRIPT_INSTALL_DIR)/msgcat1.3"; \ done; @echo "Installing library tcltest2.2 directory"; @for j in $(ROOT_DIR)/library/tcltest/*.tcl; \ do \ $(COPY) "$$j" "$(SCRIPT_INSTALL_DIR)/tcltest2.2"; \ done; @echo "Installing encodings"; @for i in $(ROOT_DIR)/library/encoding/*.enc ; do \ $(COPY) "$$i" "$(SCRIPT_INSTALL_DIR)/encoding"; \ done; install-doc: doc # Optional target to install private headers install-private-headers: libraries @for i in $(PRIVATE_INCLUDE_INSTALL_DIR); \ do \ if [ ! -d $$i ] ; then \ echo "Making directory $$i"; \ $(MKDIR) $$i; \ chmod 755 $$i; \ else true; \ fi; \ done; @echo "Installing private header files to $(PRIVATE_INCLUDE_INSTALL_DIR)/"; @for i in "$(GENERIC_DIR)/tclInt.h" "$(GENERIC_DIR)/tclIntDecls.h" \ "$(GENERIC_DIR)/tclIntPlatDecls.h" "$(GENERIC_DIR)/tclPort.h" \ "$(WIN_DIR)/tclWinPort.h" ; \ do \ $(COPY) "$$i" "$(PRIVATE_INCLUDE_INSTALL_DIR)"; \ done; # Specifying TESTFLAGS on the command line is the standard way to pass # args to tcltest, ie: # % make test TESTFLAGS="-verbose bps -file fileName.test" test: binaries $(TCLTEST) TCL_LIBRARY="$(LIBRARY_DIR)"; export TCL_LIBRARY; \ ./$(TCLTEST) "$(ROOT_DIR_NATIVE)/tests/all.tcl" $(TESTFLAGS) \ | ./$(CAT32) # Useful target to launch a built tcltest with the proper path,... runtest: binaries $(TCLTEST) @TCL_LIBRARY="$(LIBRARY_DIR)"; export TCL_LIBRARY; \ ./$(TCLTEST) $(TESTFLAGS) $(SCRIPT) # This target can be used to run tclsh from the build directory # via `make shell SCRIPT=foo.tcl` shell: binaries @TCL_LIBRARY="$(LIBRARY_DIR)"; export TCL_LIBRARY; \ ./$(TCLSH) $(SCRIPT) # This target can be used to run tclsh inside either gdb or insight gdb: binaries @echo "set env TCL_LIBRARY=$(LIBRARY_DIR)" > gdb.run gdb ./tclsh --command=gdb.run rm gdb.run depend: Makefile: $(SRC_DIR)/Makefile.in ./config.status cleanhelp: $(RM) *.hlp *.cnt *.GID *.rtf man2tcl.exe clean: cleanhelp $(RM) *.lib *.a *.exp *.dll *.$(RES) *.${OBJEXT} *~ \#* TAGS a.out $(RM) $(TCLSH) $(TCLTEST) $(CAT32) $(RM) *.pch *.ilk *.pdb distclean: clean $(RM) Makefile config.status config.cache config.log tclConfig.sh \ tcl.hpj # # Regenerate the stubs files. # $(GENERIC_DIR)/tclStubInit.c: $(GENERIC_DIR)/tcl.decls \ $(GENERIC_DIR)/tclInt.decls @echo "Warning: tclStubInit.c may be out of date." @echo "Developers may want to run \"make genstubs\" to regenerate." @echo "This warning can be safely ignored, do not report as a bug!" genstubs: $(TCL_EXE) "$(ROOT_DIR_NATIVE)/tools/genStubs.tcl" \ "$(GENERIC_DIR_NATIVE)" \ "$(GENERIC_DIR_NATIVE)/tcl.decls" \ "$(GENERIC_DIR_NATIVE)/tclInt.decls" tcl8.4.20/win/tclWinReg.c0000644003604700454610000012232712144442333013553 0ustar dgp771div/* * tclWinReg.c -- * * This file contains the implementation of the "registry" Tcl built-in * command. This command is built as a dynamically loadable extension in * a separate DLL. * * Copyright (c) 1997 by Sun Microsystems, Inc. * Copyright (c) 1998-1999 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" #ifdef _MSC_VER # pragma comment (lib, "advapi32.lib") #endif #include /* * TCL_STORAGE_CLASS is set unconditionally to DLLEXPORT because the * Registry_Init declaration is in the source file itself, which is only * accessed when we are building a library. */ #undef TCL_STORAGE_CLASS #define TCL_STORAGE_CLASS DLLEXPORT /* * The maximum length of a sub-key name. */ #ifndef MAX_KEY_LENGTH #define MAX_KEY_LENGTH 256 #endif /* * The following macros convert between different endian ints. */ #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x)) #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x))) /* * The following flag is used in OpenKeys to indicate that the specified key * should be created if it doesn't currently exist. */ #define REG_CREATE 1 /* * The following tables contain the mapping from registry root names to the * system predefined keys. */ static CONST char *rootKeyNames[] = { "HKEY_LOCAL_MACHINE", "HKEY_USERS", "HKEY_CLASSES_ROOT", "HKEY_CURRENT_USER", "HKEY_CURRENT_CONFIG", "HKEY_PERFORMANCE_DATA", "HKEY_DYN_DATA", NULL }; static const HKEY rootKeys[] = { HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, HKEY_CURRENT_CONFIG, HKEY_PERFORMANCE_DATA, HKEY_DYN_DATA }; static CONST char REGISTRY_ASSOC_KEY[] = "registry::command"; /* * The following table maps from registry types to strings. Note that the * indices for this array are the same as the constants for the known registry * types so we don't need a separate table to hold the mapping. */ static CONST char *typeNames[] = { "none", "sz", "expand_sz", "binary", "dword", "dword_big_endian", "link", "multi_sz", "resource_list", NULL }; static DWORD lastType = REG_RESOURCE_LIST; /* * The following structures allow us to select between the Unicode and ASCII * interfaces at run time based on whether Unicode APIs are available. The * Unicode APIs are preferable because they will handle characters outside of * the current code page. */ typedef struct RegWinProcs { int useWide; LONG (WINAPI *regConnectRegistryProc)(CONST TCHAR *, HKEY, PHKEY); LONG (WINAPI *regCreateKeyExProc)(HKEY, CONST TCHAR *, DWORD, TCHAR *, DWORD, REGSAM, SECURITY_ATTRIBUTES *, HKEY *, DWORD *); LONG (WINAPI *regDeleteKeyProc)(HKEY, CONST TCHAR *); LONG (WINAPI *regDeleteValueProc)(HKEY, CONST TCHAR *); LONG (WINAPI *regEnumKeyProc)(HKEY, DWORD, TCHAR *, DWORD); LONG (WINAPI *regEnumKeyExProc)(HKEY, DWORD, TCHAR *, DWORD *, DWORD *, TCHAR *, DWORD *, FILETIME *); LONG (WINAPI *regEnumValueProc)(HKEY, DWORD, TCHAR *, DWORD *, DWORD *, DWORD *, BYTE *, DWORD *); LONG (WINAPI *regOpenKeyExProc)(HKEY, CONST TCHAR *, DWORD, REGSAM, HKEY *); LONG (WINAPI *regQueryValueExProc)(HKEY, CONST TCHAR *, DWORD *, DWORD *, BYTE *, DWORD *); LONG (WINAPI *regSetValueExProc)(HKEY, CONST TCHAR *, DWORD, DWORD, CONST BYTE*, DWORD); } RegWinProcs; static RegWinProcs *regWinProcs; static RegWinProcs asciiProcs = { 0, (LONG (WINAPI *)(CONST TCHAR *, HKEY, PHKEY)) RegConnectRegistryA, (LONG (WINAPI *)(HKEY, CONST TCHAR *, DWORD, TCHAR *, DWORD, REGSAM, SECURITY_ATTRIBUTES *, HKEY *, DWORD *)) RegCreateKeyExA, (LONG (WINAPI *)(HKEY, CONST TCHAR *)) RegDeleteKeyA, (LONG (WINAPI *)(HKEY, CONST TCHAR *)) RegDeleteValueA, (LONG (WINAPI *)(HKEY, DWORD, TCHAR *, DWORD)) RegEnumKeyA, (LONG (WINAPI *)(HKEY, DWORD, TCHAR *, DWORD *, DWORD *, TCHAR *, DWORD *, FILETIME *)) RegEnumKeyExA, (LONG (WINAPI *)(HKEY, DWORD, TCHAR *, DWORD *, DWORD *, DWORD *, BYTE *, DWORD *)) RegEnumValueA, (LONG (WINAPI *)(HKEY, CONST TCHAR *, DWORD, REGSAM, HKEY *)) RegOpenKeyExA, (LONG (WINAPI *)(HKEY, CONST TCHAR *, DWORD *, DWORD *, BYTE *, DWORD *)) RegQueryValueExA, (LONG (WINAPI *)(HKEY, CONST TCHAR *, DWORD, DWORD, CONST BYTE*, DWORD)) RegSetValueExA, }; static RegWinProcs unicodeProcs = { 1, (LONG (WINAPI *)(CONST TCHAR *, HKEY, PHKEY)) RegConnectRegistryW, (LONG (WINAPI *)(HKEY, CONST TCHAR *, DWORD, TCHAR *, DWORD, REGSAM, SECURITY_ATTRIBUTES *, HKEY *, DWORD *)) RegCreateKeyExW, (LONG (WINAPI *)(HKEY, CONST TCHAR *)) RegDeleteKeyW, (LONG (WINAPI *)(HKEY, CONST TCHAR *)) RegDeleteValueW, (LONG (WINAPI *)(HKEY, DWORD, TCHAR *, DWORD)) RegEnumKeyW, (LONG (WINAPI *)(HKEY, DWORD, TCHAR *, DWORD *, DWORD *, TCHAR *, DWORD *, FILETIME *)) RegEnumKeyExW, (LONG (WINAPI *)(HKEY, DWORD, TCHAR *, DWORD *, DWORD *, DWORD *, BYTE *, DWORD *)) RegEnumValueW, (LONG (WINAPI *)(HKEY, CONST TCHAR *, DWORD, REGSAM, HKEY *)) RegOpenKeyExW, (LONG (WINAPI *)(HKEY, CONST TCHAR *, DWORD *, DWORD *, BYTE *, DWORD *)) RegQueryValueExW, (LONG (WINAPI *)(HKEY, CONST TCHAR *, DWORD, DWORD, CONST BYTE*, DWORD)) RegSetValueExW, }; /* * Declarations for functions defined in this file. */ static void AppendSystemError(Tcl_Interp *interp, DWORD error); static int BroadcastValue(Tcl_Interp *interp, int objc, Tcl_Obj * CONST objv[]); static DWORD ConvertDWORD(DWORD type, DWORD value); static void DeleteCmd(ClientData clientData); static int DeleteKey(Tcl_Interp *interp, Tcl_Obj *keyNameObj); static int DeleteValue(Tcl_Interp *interp, Tcl_Obj *keyNameObj, Tcl_Obj *valueNameObj); static int GetKeyNames(Tcl_Interp *interp, Tcl_Obj *keyNameObj, Tcl_Obj *patternObj); static int GetType(Tcl_Interp *interp, Tcl_Obj *keyNameObj, Tcl_Obj *valueNameObj); static int GetValue(Tcl_Interp *interp, Tcl_Obj *keyNameObj, Tcl_Obj *valueNameObj); static int GetValueNames(Tcl_Interp *interp, Tcl_Obj *keyNameObj, Tcl_Obj *patternObj); static int OpenKey(Tcl_Interp *interp, Tcl_Obj *keyNameObj, REGSAM mode, int flags, HKEY *keyPtr); static DWORD OpenSubKey(char *hostName, HKEY rootKey, char *keyName, REGSAM mode, int flags, HKEY *keyPtr); static int ParseKeyName(Tcl_Interp *interp, char *name, char **hostNamePtr, HKEY *rootKeyPtr, char **keyNamePtr); static DWORD RecursiveDeleteKey(HKEY hStartKey, CONST TCHAR * pKeyName); static int RegistryObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj * CONST objv[]); static int SetValue(Tcl_Interp *interp, Tcl_Obj *keyNameObj, Tcl_Obj *valueNameObj, Tcl_Obj *dataObj, Tcl_Obj *typeObj); EXTERN int Registry_Init(Tcl_Interp *interp); EXTERN int Registry_Unload(Tcl_Interp *interp, int flags); /* *---------------------------------------------------------------------- * * Registry_Init -- * * This function initializes the registry command. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Registry_Init( Tcl_Interp *interp) { Tcl_Command cmd; if (Tcl_InitStubs(interp, "8.1", 0) == NULL) { return TCL_ERROR; } /* * Determine if the unicode interfaces are available and select the * appropriate registry function table. */ if (TclWinGetPlatformId() == VER_PLATFORM_WIN32_NT) { regWinProcs = &unicodeProcs; } else { regWinProcs = &asciiProcs; } cmd = Tcl_CreateObjCommand(interp, "registry", RegistryObjCmd, (ClientData)interp, DeleteCmd); Tcl_SetAssocData(interp, REGISTRY_ASSOC_KEY, NULL, (ClientData)cmd); return Tcl_PkgProvide(interp, "registry", "1.2.2"); } /* *---------------------------------------------------------------------- * * Registry_Unload -- * * This function removes the registry command. * * Results: * A standard Tcl result. * * Side effects: * The registry command is deleted and the dll may be unloaded. * *---------------------------------------------------------------------- */ int Registry_Unload( Tcl_Interp *interp, /* Interpreter for unloading */ int flags) /* Flags passed by the unload system */ { Tcl_Command cmd; Tcl_Obj *objv[3]; /* * Unregister the registry package. There is no Tcl_PkgForget() */ objv[0] = Tcl_NewStringObj("package", -1); objv[1] = Tcl_NewStringObj("forget", -1); objv[2] = Tcl_NewStringObj("registry", -1); Tcl_EvalObjv(interp, 3, objv, TCL_EVAL_GLOBAL); /* * Delete the originally registered command. */ cmd = (Tcl_Command)Tcl_GetAssocData(interp, REGISTRY_ASSOC_KEY, NULL); if (cmd != NULL) { Tcl_DeleteCommandFromToken(interp, cmd); } return TCL_OK; } /* *---------------------------------------------------------------------- * * DeleteCmd -- * * Cleanup the interp command token so that unloading doesn't try to * re-delete the command (which will crash). * * Results: * None. * * Side effects: * The unload command will not attempt to delete this command. * *---------------------------------------------------------------------- */ static void DeleteCmd( ClientData clientData) { Tcl_Interp *interp = clientData; Tcl_SetAssocData(interp, REGISTRY_ASSOC_KEY, NULL, (ClientData)NULL); } /* *---------------------------------------------------------------------- * * RegistryObjCmd -- * * This function implements the Tcl "registry" command. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int RegistryObjCmd( ClientData clientData, /* Not used. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj * CONST objv[]) /* Argument values. */ { int index; char *errString = NULL; static CONST char *subcommands[] = { "broadcast", "delete", "get", "keys", "set", "type", "values", NULL }; enum SubCmdIdx { BroadcastIdx, DeleteIdx, GetIdx, KeysIdx, SetIdx, TypeIdx, ValuesIdx }; if (objc < 2) { Tcl_WrongNumArgs(interp, objc, objv, "option ?arg arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[1], subcommands, "option", 0, &index) != TCL_OK) { return TCL_ERROR; } switch (index) { case BroadcastIdx: /* broadcast */ return BroadcastValue(interp, objc, objv); break; case DeleteIdx: /* delete */ if (objc == 3) { return DeleteKey(interp, objv[2]); } else if (objc == 4) { return DeleteValue(interp, objv[2], objv[3]); } errString = "keyName ?valueName?"; break; case GetIdx: /* get */ if (objc == 4) { return GetValue(interp, objv[2], objv[3]); } errString = "keyName valueName"; break; case KeysIdx: /* keys */ if (objc == 3) { return GetKeyNames(interp, objv[2], NULL); } else if (objc == 4) { return GetKeyNames(interp, objv[2], objv[3]); } errString = "keyName ?pattern?"; break; case SetIdx: /* set */ if (objc == 3) { HKEY key; /* * Create the key and then close it immediately. */ if (OpenKey(interp, objv[2], KEY_ALL_ACCESS, 1, &key) != TCL_OK) { return TCL_ERROR; } RegCloseKey(key); return TCL_OK; } else if (objc == 5 || objc == 6) { Tcl_Obj *typeObj = (objc == 5) ? NULL : objv[5]; return SetValue(interp, objv[2], objv[3], objv[4], typeObj); } errString = "keyName ?valueName data ?type??"; break; case TypeIdx: /* type */ if (objc == 4) { return GetType(interp, objv[2], objv[3]); } errString = "keyName valueName"; break; case ValuesIdx: /* values */ if (objc == 3) { return GetValueNames(interp, objv[2], NULL); } else if (objc == 4) { return GetValueNames(interp, objv[2], objv[3]); } errString = "keyName ?pattern?"; break; } Tcl_WrongNumArgs(interp, 2, objv, errString); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * DeleteKey -- * * This function deletes a registry key. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int DeleteKey( Tcl_Interp *interp, /* Current interpreter. */ Tcl_Obj *keyNameObj) /* Name of key to delete. */ { char *tail, *buffer, *hostName, *keyName; CONST char *nativeTail; HKEY rootKey, subkey; DWORD result; int length; Tcl_DString buf; /* * Find the parent of the key being deleted and open it. */ keyName = Tcl_GetStringFromObj(keyNameObj, &length); buffer = ckalloc((unsigned int) length + 1); strcpy(buffer, keyName); if (ParseKeyName(interp, buffer, &hostName, &rootKey, &keyName) != TCL_OK) { ckfree(buffer); return TCL_ERROR; } if (*keyName == '\0') { Tcl_SetObjResult(interp, Tcl_NewStringObj( "bad key: cannot delete root keys", -1)); ckfree(buffer); return TCL_ERROR; } tail = strrchr(keyName, '\\'); if (tail) { *tail++ = '\0'; } else { tail = keyName; keyName = NULL; } result = OpenSubKey(hostName, rootKey, keyName, KEY_ENUMERATE_SUB_KEYS | DELETE, 0, &subkey); if (result != ERROR_SUCCESS) { ckfree(buffer); if (result == ERROR_FILE_NOT_FOUND) { return TCL_OK; } Tcl_SetObjResult(interp, Tcl_NewStringObj( "unable to delete key: ", -1)); AppendSystemError(interp, result); return TCL_ERROR; } /* * Now we recursively delete the key and everything below it. */ nativeTail = Tcl_WinUtfToTChar(tail, -1, &buf); result = RecursiveDeleteKey(subkey, nativeTail); Tcl_DStringFree(&buf); if (result != ERROR_SUCCESS && result != ERROR_FILE_NOT_FOUND) { Tcl_SetObjResult(interp, Tcl_NewStringObj("unable to delete key: ", -1)); AppendSystemError(interp, result); result = TCL_ERROR; } else { result = TCL_OK; } RegCloseKey(subkey); ckfree(buffer); return result; } /* *---------------------------------------------------------------------- * * DeleteValue -- * * This function deletes a value from a registry key. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int DeleteValue( Tcl_Interp *interp, /* Current interpreter. */ Tcl_Obj *keyNameObj, /* Name of key. */ Tcl_Obj *valueNameObj) /* Name of value to delete. */ { HKEY key; char *valueName; int length; DWORD result; Tcl_DString ds; /* * Attempt to open the key for deletion. */ if (OpenKey(interp, keyNameObj, KEY_SET_VALUE, 0, &key) != TCL_OK) { return TCL_ERROR; } valueName = Tcl_GetStringFromObj(valueNameObj, &length); Tcl_WinUtfToTChar(valueName, length, &ds); result = (*regWinProcs->regDeleteValueProc)(key, Tcl_DStringValue(&ds)); Tcl_DStringFree(&ds); if (result != ERROR_SUCCESS) { Tcl_AppendResult(interp, "unable to delete value \"", Tcl_GetString(valueNameObj), "\" from key \"", Tcl_GetString(keyNameObj), "\": ", NULL); AppendSystemError(interp, result); result = TCL_ERROR; } else { result = TCL_OK; } RegCloseKey(key); return result; } /* *---------------------------------------------------------------------- * * GetKeyNames -- * * This function enumerates the subkeys of a given key. If the optional * pattern is supplied, then only keys that match the pattern will be * returned. * * Results: * Returns the list of subkeys in the result object of the interpreter, * or an error message on failure. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int GetKeyNames( Tcl_Interp *interp, /* Current interpreter. */ Tcl_Obj *keyNameObj, /* Key to enumerate. */ Tcl_Obj *patternObj) /* Optional match pattern. */ { char *pattern; /* Pattern being matched against subkeys */ HKEY key; /* Handle to the key being examined */ TCHAR buffer[MAX_KEY_LENGTH*2]; /* Buffer to hold the subkey name */ DWORD bufSize; /* Size of the buffer */ DWORD index; /* Position of the current subkey */ char *name; /* Subkey name */ Tcl_Obj *resultPtr; /* List of subkeys being accumulated */ int result = TCL_OK; /* Return value from this command */ Tcl_DString ds; /* Buffer to translate subkey name to UTF-8 */ if (patternObj) { pattern = Tcl_GetString(patternObj); } else { pattern = NULL; } /* Attempt to open the key for enumeration. */ if (OpenKey(interp, keyNameObj, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, 0, &key) != TCL_OK) { return TCL_ERROR; } /* Enumerate the subkeys */ resultPtr = Tcl_NewObj(); for (index = 0;; ++index) { bufSize = MAX_KEY_LENGTH; result = (*regWinProcs->regEnumKeyExProc) (key, index, buffer, &bufSize, NULL, NULL, NULL, NULL); if (result != ERROR_SUCCESS) { if (result == ERROR_NO_MORE_ITEMS) { result = TCL_OK; } else { Tcl_SetObjResult(interp, Tcl_NewObj()); Tcl_AppendResult(interp, "unable to enumerate subkeys of \"", Tcl_GetString(keyNameObj), "\": ", NULL); AppendSystemError(interp, result); result = TCL_ERROR; } break; } if (regWinProcs->useWide) { Tcl_WinTCharToUtf((TCHAR *) buffer, bufSize * sizeof(WCHAR), &ds); } else { Tcl_WinTCharToUtf((TCHAR *) buffer, bufSize, &ds); } name = Tcl_DStringValue(&ds); if (pattern && !Tcl_StringMatch(name, pattern)) { Tcl_DStringFree(&ds); continue; } result = Tcl_ListObjAppendElement(interp, resultPtr, Tcl_NewStringObj(name, Tcl_DStringLength(&ds))); Tcl_DStringFree(&ds); if (result != TCL_OK) { break; } } if (result == TCL_OK) { Tcl_SetObjResult(interp, resultPtr); } else { Tcl_DecrRefCount(resultPtr); /* BUGFIX: Don't leak on failure. */ } RegCloseKey(key); return result; } /* *---------------------------------------------------------------------- * * GetType -- * * This function gets the type of a given registry value and places it in * the interpreter result. * * Results: * Returns a normal Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int GetType( Tcl_Interp *interp, /* Current interpreter. */ Tcl_Obj *keyNameObj, /* Name of key. */ Tcl_Obj *valueNameObj) /* Name of value to get. */ { HKEY key; DWORD result; DWORD type; Tcl_DString ds; char *valueName; CONST char *nativeValue; int length; /* * Attempt to open the key for reading. */ if (OpenKey(interp, keyNameObj, KEY_QUERY_VALUE, 0, &key) != TCL_OK) { return TCL_ERROR; } /* * Get the type of the value. */ valueName = Tcl_GetStringFromObj(valueNameObj, &length); nativeValue = Tcl_WinUtfToTChar(valueName, length, &ds); result = (*regWinProcs->regQueryValueExProc)(key, nativeValue, NULL, &type, NULL, NULL); Tcl_DStringFree(&ds); RegCloseKey(key); if (result != ERROR_SUCCESS) { Tcl_AppendResult(interp, "unable to get type of value \"", Tcl_GetString(valueNameObj), "\" from key \"", Tcl_GetString(keyNameObj), "\": ", NULL); AppendSystemError(interp, result); return TCL_ERROR; } /* * Set the type into the result. Watch out for unknown types. If we don't * know about the type, just use the numeric value. */ if (type > lastType) { Tcl_SetObjResult(interp, Tcl_NewIntObj((int) type)); } else { Tcl_SetObjResult(interp, Tcl_NewStringObj(typeNames[type], -1)); } return TCL_OK; } /* *---------------------------------------------------------------------- * * GetValue -- * * This function gets the contents of a registry value and places a list * containing the data and the type in the interpreter result. * * Results: * Returns a normal Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int GetValue( Tcl_Interp *interp, /* Current interpreter. */ Tcl_Obj *keyNameObj, /* Name of key. */ Tcl_Obj *valueNameObj) /* Name of value to get. */ { HKEY key; char *valueName; CONST char *nativeValue; DWORD result, length, type; Tcl_DString data, buf; int nameLen; /* * Attempt to open the key for reading. */ if (OpenKey(interp, keyNameObj, KEY_QUERY_VALUE, 0, &key) != TCL_OK) { return TCL_ERROR; } /* * Initialize a Dstring to maximum statically allocated size we could get * one more byte by avoiding Tcl_DStringSetLength() and just setting * length to TCL_DSTRING_STATIC_SIZE, but this should be safer if the * implementation of Dstrings changes. * * This allows short values to be read from the registy in one call. * Longer values need a second call with an expanded DString. */ Tcl_DStringInit(&data); Tcl_DStringSetLength(&data, TCL_DSTRING_STATIC_SIZE - 1); length = TCL_DSTRING_STATIC_SIZE / (regWinProcs->useWide ? 2 : 1) - 1; valueName = Tcl_GetStringFromObj(valueNameObj, &nameLen); nativeValue = Tcl_WinUtfToTChar(valueName, nameLen, &buf); result = (*regWinProcs->regQueryValueExProc)(key, nativeValue, NULL, &type, (BYTE *) Tcl_DStringValue(&data), &length); while (result == ERROR_MORE_DATA) { /* * The Windows docs say that in this error case, we just need to * expand our buffer and request more data. Required for * HKEY_PERFORMANCE_DATA */ length = Tcl_DStringLength(&data) * (regWinProcs->useWide ? 1 : 2); Tcl_DStringSetLength(&data, (int) length * (regWinProcs->useWide ? 2 : 1)); result = (*regWinProcs->regQueryValueExProc)(key, (char *) nativeValue, NULL, &type, (BYTE *) Tcl_DStringValue(&data), &length); } Tcl_DStringFree(&buf); RegCloseKey(key); if (result != ERROR_SUCCESS) { Tcl_AppendResult(interp, "unable to get value \"", Tcl_GetString(valueNameObj), "\" from key \"", Tcl_GetString(keyNameObj), "\": ", NULL); AppendSystemError(interp, result); Tcl_DStringFree(&data); return TCL_ERROR; } /* * If the data is a 32-bit quantity, store it as an integer object. If it * is a multi-string, store it as a list of strings. For null-terminated * strings, append up the to first null. Otherwise, store it as a binary * string. */ if (type == REG_DWORD || type == REG_DWORD_BIG_ENDIAN) { Tcl_SetObjResult(interp, Tcl_NewIntObj((int) ConvertDWORD(type, *((DWORD*) Tcl_DStringValue(&data))))); } else if (type == REG_MULTI_SZ) { char *p = Tcl_DStringValue(&data); char *end = Tcl_DStringValue(&data) + length; Tcl_Obj *resultPtr = Tcl_NewObj(); /* * Multistrings are stored as an array of null-terminated strings, * terminated by two null characters. Also do a bounds check in case * we get bogus data. */ while (p < end && ((regWinProcs->useWide) ? *((Tcl_UniChar *)p) : *p) != 0) { Tcl_WinTCharToUtf((TCHAR *) p, -1, &buf); Tcl_ListObjAppendElement(interp, resultPtr, Tcl_NewStringObj(Tcl_DStringValue(&buf), Tcl_DStringLength(&buf))); if (regWinProcs->useWide) { Tcl_UniChar* up = (Tcl_UniChar*) p; while (*up++ != 0) {} p = (char*) up; } else { while (*p++ != '\0') {} } Tcl_DStringFree(&buf); } Tcl_SetObjResult(interp, resultPtr); } else if ((type == REG_SZ) || (type == REG_EXPAND_SZ)) { Tcl_WinTCharToUtf((TCHAR *) Tcl_DStringValue(&data), -1, &buf); Tcl_DStringResult(interp, &buf); } else { /* * Save binary data as a byte array. */ Tcl_SetObjResult(interp, Tcl_NewByteArrayObj( (BYTE *) Tcl_DStringValue(&data), (int) length)); } Tcl_DStringFree(&data); return result; } /* *---------------------------------------------------------------------- * * GetValueNames -- * * This function enumerates the values of the a given key. If the * optional pattern is supplied, then only value names that match the * pattern will be returned. * * Results: * Returns the list of value names in the result object of the * interpreter, or an error message on failure. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int GetValueNames( Tcl_Interp *interp, /* Current interpreter. */ Tcl_Obj *keyNameObj, /* Key to enumerate. */ Tcl_Obj *patternObj) /* Optional match pattern. */ { HKEY key; Tcl_Obj *resultPtr; DWORD index, size, result; Tcl_DString buffer, ds; char *pattern, *name; /* * Attempt to open the key for enumeration. */ if (OpenKey(interp, keyNameObj, KEY_QUERY_VALUE, 0, &key) != TCL_OK) { return TCL_ERROR; } resultPtr = Tcl_NewObj(); Tcl_DStringInit(&buffer); Tcl_DStringSetLength(&buffer, (int) ((regWinProcs->useWide) ? MAX_KEY_LENGTH*2 : MAX_KEY_LENGTH)); index = 0; result = TCL_OK; if (patternObj) { pattern = Tcl_GetString(patternObj); } else { pattern = NULL; } /* * Enumerate the values under the given subkey until we get an error, * indicating the end of the list. Note that we need to reset size after * each iteration because RegEnumValue smashes the old value. */ size = MAX_KEY_LENGTH; while ((*regWinProcs->regEnumValueProc)(key, index, Tcl_DStringValue(&buffer), &size, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) { if (regWinProcs->useWide) { size *= 2; } Tcl_WinTCharToUtf((TCHAR *) Tcl_DStringValue(&buffer), (int) size, &ds); name = Tcl_DStringValue(&ds); if (!pattern || Tcl_StringMatch(name, pattern)) { result = Tcl_ListObjAppendElement(interp, resultPtr, Tcl_NewStringObj(name, Tcl_DStringLength(&ds))); if (result != TCL_OK) { Tcl_DStringFree(&ds); break; } } Tcl_DStringFree(&ds); index++; size = MAX_KEY_LENGTH; } Tcl_SetObjResult(interp, resultPtr); Tcl_DStringFree(&buffer); RegCloseKey(key); return result; } /* *---------------------------------------------------------------------- * * OpenKey -- * * This function opens the specified key. This function is a simple * wrapper around ParseKeyName and OpenSubKey. * * Results: * Returns the opened key in the keyPtr argument and a Tcl result code. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int OpenKey( Tcl_Interp *interp, /* Current interpreter. */ Tcl_Obj *keyNameObj, /* Key to open. */ REGSAM mode, /* Access mode. */ int flags, /* 0 or REG_CREATE. */ HKEY *keyPtr) /* Returned HKEY. */ { char *keyName, *buffer, *hostName; int length; HKEY rootKey; DWORD result; keyName = Tcl_GetStringFromObj(keyNameObj, &length); buffer = ckalloc((unsigned int) length + 1); strcpy(buffer, keyName); result = ParseKeyName(interp, buffer, &hostName, &rootKey, &keyName); if (result == TCL_OK) { result = OpenSubKey(hostName, rootKey, keyName, mode, flags, keyPtr); if (result != ERROR_SUCCESS) { Tcl_SetObjResult(interp, Tcl_NewStringObj("unable to open key: ", -1)); AppendSystemError(interp, result); result = TCL_ERROR; } else { result = TCL_OK; } } ckfree(buffer); return result; } /* *---------------------------------------------------------------------- * * OpenSubKey -- * * This function opens a given subkey of a root key on the specified * host. * * Results: * Returns the opened key in the keyPtr and a Windows error code as the * return value. * * Side effects: * None. * *---------------------------------------------------------------------- */ static DWORD OpenSubKey( char *hostName, /* Host to access, or NULL for local. */ HKEY rootKey, /* Root registry key. */ char *keyName, /* Subkey name. */ REGSAM mode, /* Access mode. */ int flags, /* 0 or REG_CREATE. */ HKEY *keyPtr) /* Returned HKEY. */ { DWORD result; Tcl_DString buf; /* * Attempt to open the root key on a remote host if necessary. */ if (hostName) { hostName = (char *) Tcl_WinUtfToTChar(hostName, -1, &buf); result = (*regWinProcs->regConnectRegistryProc)(hostName, rootKey, &rootKey); Tcl_DStringFree(&buf); if (result != ERROR_SUCCESS) { return result; } } /* * Now open the specified key with the requested permissions. Note that * this key must be closed by the caller. */ keyName = (char *) Tcl_WinUtfToTChar(keyName, -1, &buf); if (flags & REG_CREATE) { DWORD create; result = (*regWinProcs->regCreateKeyExProc)(rootKey, keyName, 0, NULL, REG_OPTION_NON_VOLATILE, mode, NULL, keyPtr, &create); } else if (rootKey == HKEY_PERFORMANCE_DATA) { /* * Here we fudge it for this special root key. See MSDN for more info * on HKEY_PERFORMANCE_DATA and the peculiarities surrounding it. */ *keyPtr = HKEY_PERFORMANCE_DATA; result = ERROR_SUCCESS; } else { result = (*regWinProcs->regOpenKeyExProc)(rootKey, keyName, 0, mode, keyPtr); } Tcl_DStringFree(&buf); /* * Be sure to close the root key since we are done with it now. */ if (hostName) { RegCloseKey(rootKey); } return result; } /* *---------------------------------------------------------------------- * * ParseKeyName -- * * This function parses a key name into the host, root, and subkey parts. * * Results: * The pointers to the start of the host and subkey names are returned in * the hostNamePtr and keyNamePtr variables. The specified root HKEY is * returned in rootKeyPtr. Returns a standard Tcl result. * * Side effects: * Modifies the name string by inserting nulls. * *---------------------------------------------------------------------- */ static int ParseKeyName( Tcl_Interp *interp, /* Current interpreter. */ char *name, char **hostNamePtr, HKEY *rootKeyPtr, char **keyNamePtr) { char *rootName; int result, index; Tcl_Obj *rootObj; /* * Split the key into host and root portions. */ *hostNamePtr = *keyNamePtr = rootName = NULL; if (name[0] == '\\') { if (name[1] == '\\') { *hostNamePtr = name; for (rootName = name+2; *rootName != '\0'; rootName++) { if (*rootName == '\\') { *rootName++ = '\0'; break; } } } } else { rootName = name; } if (!rootName) { Tcl_AppendResult(interp, "bad key \"", name, "\": must start with a valid root", NULL); return TCL_ERROR; } /* * Split the root into root and subkey portions. */ for (*keyNamePtr = rootName; **keyNamePtr != '\0'; (*keyNamePtr)++) { if (**keyNamePtr == '\\') { **keyNamePtr = '\0'; (*keyNamePtr)++; break; } } /* * Look for a matching root name. */ rootObj = Tcl_NewStringObj(rootName, -1); result = Tcl_GetIndexFromObj(interp, rootObj, rootKeyNames, "root name", TCL_EXACT, &index); Tcl_DecrRefCount(rootObj); if (result != TCL_OK) { return TCL_ERROR; } *rootKeyPtr = rootKeys[index]; return TCL_OK; } /* *---------------------------------------------------------------------- * * RecursiveDeleteKey -- * * This function recursively deletes all the keys below a starting key. * Although Windows 95 does this automatically, we still need to do this * for Windows NT. * * Results: * Returns a Windows error code. * * Side effects: * Deletes all of the keys and values below the given key. * *---------------------------------------------------------------------- */ static DWORD RecursiveDeleteKey( HKEY startKey, /* Parent of key to be deleted. */ CONST char *keyName) /* Name of key to be deleted in external * encoding, not UTF. */ { DWORD result, size; Tcl_DString subkey; HKEY hKey; /* * Do not allow NULL or empty key name. */ if (!keyName || *keyName == '\0') { return ERROR_BADKEY; } result = (*regWinProcs->regOpenKeyExProc)(startKey, keyName, 0, KEY_ENUMERATE_SUB_KEYS | DELETE | KEY_QUERY_VALUE, &hKey); if (result != ERROR_SUCCESS) { return result; } Tcl_DStringInit(&subkey); Tcl_DStringSetLength(&subkey, (int) ((regWinProcs->useWide) ? MAX_KEY_LENGTH * 2 : MAX_KEY_LENGTH)); while (result == ERROR_SUCCESS) { /* * Always get index 0 because key deletion changes ordering. */ size = MAX_KEY_LENGTH; result=(*regWinProcs->regEnumKeyExProc)(hKey, 0, Tcl_DStringValue(&subkey), &size, NULL, NULL, NULL, NULL); if (result == ERROR_NO_MORE_ITEMS) { result = (*regWinProcs->regDeleteKeyProc)(startKey, keyName); break; } else if (result == ERROR_SUCCESS) { result = RecursiveDeleteKey(hKey, Tcl_DStringValue(&subkey)); } } Tcl_DStringFree(&subkey); RegCloseKey(hKey); return result; } /* *---------------------------------------------------------------------- * * SetValue -- * * This function sets the contents of a registry value. If the key or * value does not exist, it will be created. If it does exist, then the * data and type will be replaced. * * Results: * Returns a normal Tcl result. * * Side effects: * May create new keys or values. * *---------------------------------------------------------------------- */ static int SetValue( Tcl_Interp *interp, /* Current interpreter. */ Tcl_Obj *keyNameObj, /* Name of key. */ Tcl_Obj *valueNameObj, /* Name of value to set. */ Tcl_Obj *dataObj, /* Data to be written. */ Tcl_Obj *typeObj) /* Type of data to be written. */ { int type; DWORD result; HKEY key; int length; char *valueName; Tcl_DString nameBuf; if (typeObj == NULL) { type = REG_SZ; } else if (Tcl_GetIndexFromObj(interp, typeObj, typeNames, "type", 0, (int *) &type) != TCL_OK) { if (Tcl_GetIntFromObj(NULL, typeObj, (int*) &type) != TCL_OK) { return TCL_ERROR; } Tcl_ResetResult(interp); } if (OpenKey(interp, keyNameObj, KEY_ALL_ACCESS, 1, &key) != TCL_OK) { return TCL_ERROR; } valueName = Tcl_GetStringFromObj(valueNameObj, &length); valueName = (char *) Tcl_WinUtfToTChar(valueName, length, &nameBuf); if (type == REG_DWORD || type == REG_DWORD_BIG_ENDIAN) { int value; if (Tcl_GetIntFromObj(interp, dataObj, &value) != TCL_OK) { RegCloseKey(key); Tcl_DStringFree(&nameBuf); return TCL_ERROR; } value = ConvertDWORD((DWORD)type, (DWORD)value); result = (*regWinProcs->regSetValueExProc)(key, valueName, 0, (DWORD) type, (BYTE *) &value, sizeof(DWORD)); } else if (type == REG_MULTI_SZ) { Tcl_DString data, buf; int objc, i; Tcl_Obj **objv; if (Tcl_ListObjGetElements(interp, dataObj, &objc, &objv) != TCL_OK) { RegCloseKey(key); Tcl_DStringFree(&nameBuf); return TCL_ERROR; } /* * Append the elements as null terminated strings. Note that we must * not assume the length of the string in case there are embedded * nulls, which aren't allowed in REG_MULTI_SZ values. */ Tcl_DStringInit(&data); for (i = 0; i < objc; i++) { Tcl_DStringAppend(&data, Tcl_GetString(objv[i]), -1); /* * Add a null character to separate this value from the next. We * accomplish this by growing the string by one byte. Since the * DString always tacks on an extra null byte, the new byte will * already be set to null. */ Tcl_DStringSetLength(&data, Tcl_DStringLength(&data)+1); } Tcl_WinUtfToTChar(Tcl_DStringValue(&data), Tcl_DStringLength(&data)+1, &buf); result = (*regWinProcs->regSetValueExProc)(key, valueName, 0, (DWORD) type, (BYTE *) Tcl_DStringValue(&buf), (DWORD) Tcl_DStringLength(&buf)); Tcl_DStringFree(&data); Tcl_DStringFree(&buf); } else if (type == REG_SZ || type == REG_EXPAND_SZ) { Tcl_DString buf; CONST char *data = Tcl_GetStringFromObj(dataObj, &length); data = Tcl_WinUtfToTChar(data, length, &buf); /* * Include the null in the length, padding if needed for Unicode. */ if (regWinProcs->useWide) { Tcl_DStringSetLength(&buf, Tcl_DStringLength(&buf)+1); } length = Tcl_DStringLength(&buf) + 1; result = (*regWinProcs->regSetValueExProc)(key, valueName, 0, (DWORD) type, (BYTE *) data, (DWORD) length); Tcl_DStringFree(&buf); } else { BYTE *data; /* * Store binary data in the registry. */ data = (BYTE *) Tcl_GetByteArrayFromObj(dataObj, &length); result = (*regWinProcs->regSetValueExProc)(key, valueName, 0, (DWORD) type, data, (DWORD) length); } Tcl_DStringFree(&nameBuf); RegCloseKey(key); if (result != ERROR_SUCCESS) { Tcl_SetObjResult(interp, Tcl_NewStringObj("unable to set value: ", -1)); AppendSystemError(interp, result); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * BroadcastValue -- * * This function broadcasts a WM_SETTINGCHANGE message to indicate to * other programs that we have changed the contents of a registry value. * * Results: * Returns a normal Tcl result. * * Side effects: * Will cause other programs to reload their system settings. * *---------------------------------------------------------------------- */ static int BroadcastValue( Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[]) /* Argument values. */ { LRESULT result; DWORD_PTR sendResult; UINT timeout = 3000; int len; CONST char *str; Tcl_Obj *objPtr; if ((objc != 3) && (objc != 5)) { Tcl_WrongNumArgs(interp, 2, objv, "keyName ?-timeout millisecs?"); return TCL_ERROR; } if (objc > 3) { str = Tcl_GetStringFromObj(objv[3], &len); if ((len < 2) || (*str != '-') || strncmp(str, "-timeout", (size_t) len)) { Tcl_WrongNumArgs(interp, 2, objv, "keyName ?-timeout millisecs?"); return TCL_ERROR; } if (Tcl_GetIntFromObj(interp, objv[4], (int *) &timeout) != TCL_OK) { return TCL_ERROR; } } str = Tcl_GetStringFromObj(objv[2], &len); if (len == 0) { str = NULL; } /* * Use the ignore the result. */ result = SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, (WPARAM) 0, (LPARAM) str, SMTO_ABORTIFHUNG, timeout, &sendResult); objPtr = Tcl_NewObj(); Tcl_ListObjAppendElement(NULL, objPtr, Tcl_NewLongObj((long) result)); Tcl_ListObjAppendElement(NULL, objPtr, Tcl_NewLongObj((long) sendResult)); Tcl_SetObjResult(interp, objPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * AppendSystemError -- * * This routine formats a Windows system error message and places it into * the interpreter result. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void AppendSystemError( Tcl_Interp *interp, /* Current interpreter. */ DWORD error) /* Result code from error. */ { int length; WCHAR *wMsgPtr, **wMsgPtrPtr = &wMsgPtr; char *msg; char id[TCL_INTEGER_SPACE], msgBuf[24 + TCL_INTEGER_SPACE]; Tcl_DString ds; Tcl_Obj *resultPtr = Tcl_GetObjResult(interp); if (Tcl_IsShared(resultPtr)) { resultPtr = Tcl_DuplicateObj(resultPtr); } length = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (WCHAR *) wMsgPtrPtr, 0, NULL); if (length == 0) { char *msgPtr; length = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char *) &msgPtr, 0, NULL); if (length > 0) { wMsgPtr = (WCHAR *) LocalAlloc(LPTR, (length + 1) * sizeof(WCHAR)); MultiByteToWideChar(CP_ACP, 0, msgPtr, length + 1, wMsgPtr, length + 1); LocalFree(msgPtr); } } if (length == 0) { if (error == ERROR_CALL_NOT_IMPLEMENTED) { msg = "function not supported under Win32s"; } else { sprintf(msgBuf, "unknown error: %ld", error); msg = msgBuf; } } else { Tcl_Encoding encoding; encoding = Tcl_GetEncoding(NULL, "unicode"); Tcl_ExternalToUtfDString(encoding, (char *) wMsgPtr, -1, &ds); Tcl_FreeEncoding(encoding); LocalFree(wMsgPtr); msg = Tcl_DStringValue(&ds); length = Tcl_DStringLength(&ds); /* * Trim the trailing CR/LF from the system message. */ if (msg[length-1] == '\n') { msg[--length] = 0; } if (msg[length-1] == '\r') { msg[--length] = 0; } } sprintf(id, "%ld", error); Tcl_SetErrorCode(interp, "WINDOWS", id, msg, NULL); Tcl_AppendToObj(resultPtr, msg, length); Tcl_SetObjResult(interp, resultPtr); if (length != 0) { Tcl_DStringFree(&ds); } } /* *---------------------------------------------------------------------- * * ConvertDWORD -- * * This function determines whether a DWORD needs to be byte swapped, and * returns the appropriately swapped value. * * Results: * Returns a converted DWORD. * * Side effects: * None. * *---------------------------------------------------------------------- */ static DWORD ConvertDWORD( DWORD type, /* Either REG_DWORD or REG_DWORD_BIG_ENDIAN */ DWORD value) /* The value to be converted. */ { DWORD order = 1; DWORD localType; /* * Check to see if the low bit is in the first byte. */ localType = (*((char*) &order) == 1) ? REG_DWORD : REG_DWORD_BIG_ENDIAN; return (type != localType) ? (DWORD) SWAPLONG(value) : value; } /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ tcl8.4.20/win/tclWinConsole.c0000644003604700454610000011171511737050675014452 0ustar dgp771div/* * tclWinConsole.c -- * * This file implements the Windows-specific console functions, * and the "console" channel driver. * * Copyright (c) 1999 by Scriptics Corp. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclWinInt.h" #include #include #include /* * The following variable is used to tell whether this module has been * initialized. */ static int initialized = 0; /* * The consoleMutex locks around access to the initialized variable, and it is * used to protect background threads from being terminated while they are * using APIs that hold locks. */ TCL_DECLARE_MUTEX(consoleMutex) /* * Bit masks used in the flags field of the ConsoleInfo structure below. */ #define CONSOLE_PENDING (1<<0) /* Message is pending in the queue. */ #define CONSOLE_ASYNC (1<<1) /* Channel is non-blocking. */ /* * Bit masks used in the sharedFlags field of the ConsoleInfo structure below. */ #define CONSOLE_EOF (1<<2) /* Console has reached EOF. */ #define CONSOLE_BUFFERED (1<<3) /* data was read into a buffer by the reader thread */ #define CONSOLE_BUFFER_SIZE (8*1024) /* * This structure describes per-instance data for a console based channel. */ typedef struct ConsoleInfo { HANDLE handle; int type; struct ConsoleInfo *nextPtr;/* Pointer to next registered console. */ Tcl_Channel channel; /* Pointer to channel structure. */ int validMask; /* OR'ed combination of TCL_READABLE, * TCL_WRITABLE, or TCL_EXCEPTION: indicates * which operations are valid on the file. */ int watchMask; /* OR'ed combination of TCL_READABLE, * TCL_WRITABLE, or TCL_EXCEPTION: indicates * which events should be reported. */ int flags; /* State flags, see above for a list. */ Tcl_ThreadId threadId; /* Thread to which events should be reported. * This value is used by the reader/writer * threads. */ HANDLE writeThread; /* Handle to writer thread. */ HANDLE readThread; /* Handle to reader thread. */ HANDLE writable; /* Manual-reset event to signal when the * writer thread has finished waiting for * the current buffer to be written. */ HANDLE readable; /* Manual-reset event to signal when the * reader thread has finished waiting for * input. */ HANDLE startWriter; /* Auto-reset event used by the main thread to * signal when the writer thread should attempt * to write to the console. */ HANDLE stopWriter; /* Auto-reset event used by the main thread to * signal when the writer thread should exit. */ HANDLE startReader; /* Auto-reset event used by the main thread to * signal when the reader thread should attempt * to read from the console. */ HANDLE stopReader; /* Auto-reset event used by the main thread to * signal when the reader thread should exit. */ DWORD writeError; /* An error caused by the last background * write. Set to 0 if no error has been * detected. This word is shared with the * writer thread so access must be * synchronized with the writable object. */ char *writeBuf; /* Current background output buffer. * Access is synchronized with the writable * object. */ int writeBufLen; /* Size of write buffer. Access is * synchronized with the writable * object. */ int toWrite; /* Current amount to be written. Access is * synchronized with the writable object. */ int readFlags; /* Flags that are shared with the reader * thread. Access is synchronized with the * readable object. */ int bytesRead; /* number of bytes in the buffer */ int offset; /* number of bytes read out of the buffer */ char buffer[CONSOLE_BUFFER_SIZE]; /* Data consumed by reader thread. */ } ConsoleInfo; typedef struct ThreadSpecificData { /* * The following pointer refers to the head of the list of consoles * that are being watched for file events. */ ConsoleInfo *firstConsolePtr; } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; /* * The following structure is what is added to the Tcl event queue when * console events are generated. */ typedef struct ConsoleEvent { Tcl_Event header; /* Information that is standard for * all events. */ ConsoleInfo *infoPtr; /* Pointer to console info structure. Note * that we still have to verify that the * console exists before dereferencing this * pointer. */ } ConsoleEvent; /* * Declarations for functions used only in this file. */ static int ConsoleBlockModeProc(ClientData instanceData, int mode); static void ConsoleCheckProc(ClientData clientData, int flags); static int ConsoleCloseProc(ClientData instanceData, Tcl_Interp *interp); static int ConsoleEventProc(Tcl_Event *evPtr, int flags); static void ConsoleExitHandler(ClientData clientData); static int ConsoleGetHandleProc(ClientData instanceData, int direction, ClientData *handlePtr); static void ConsoleInit(void); static int ConsoleInputProc(ClientData instanceData, char *buf, int toRead, int *errorCode); static int ConsoleOutputProc(ClientData instanceData, CONST char *buf, int toWrite, int *errorCode); static DWORD WINAPI ConsoleReaderThread(LPVOID arg); static void ConsoleSetupProc(ClientData clientData, int flags); static void ConsoleWatchProc(ClientData instanceData, int mask); static DWORD WINAPI ConsoleWriterThread(LPVOID arg); static void ProcExitHandler(ClientData clientData); static int WaitForRead(ConsoleInfo *infoPtr, int blocking); static void ConsoleThreadActionProc _ANSI_ARGS_ (( ClientData instanceData, int action)); /* * This structure describes the channel type structure for command console * based IO. */ static Tcl_ChannelType consoleChannelType = { "console", /* Type name. */ TCL_CHANNEL_VERSION_4, /* v4 channel */ ConsoleCloseProc, /* Close proc. */ ConsoleInputProc, /* Input proc. */ ConsoleOutputProc, /* Output proc. */ NULL, /* Seek proc. */ NULL, /* Set option proc. */ NULL, /* Get option proc. */ ConsoleWatchProc, /* Set up notifier to watch the channel. */ ConsoleGetHandleProc, /* Get an OS handle from channel. */ NULL, /* close2proc. */ ConsoleBlockModeProc, /* Set blocking or non-blocking mode.*/ NULL, /* flush proc. */ NULL, /* handler proc. */ NULL, /* wide seek proc */ ConsoleThreadActionProc, /* thread action proc */ }; /* *---------------------------------------------------------------------- * * ConsoleInit -- * * This function initializes the static variables for this file. * * Results: * None. * * Side effects: * Creates a new event source. * *---------------------------------------------------------------------- */ static void ConsoleInit() { ThreadSpecificData *tsdPtr; /* * Check the initialized flag first, then check again in the mutex. * This is a speed enhancement. */ if (!initialized) { Tcl_MutexLock(&consoleMutex); if (!initialized) { initialized = 1; Tcl_CreateExitHandler(ProcExitHandler, NULL); } Tcl_MutexUnlock(&consoleMutex); } tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); if (tsdPtr == NULL) { tsdPtr = TCL_TSD_INIT(&dataKey); tsdPtr->firstConsolePtr = NULL; Tcl_CreateEventSource(ConsoleSetupProc, ConsoleCheckProc, NULL); Tcl_CreateThreadExitHandler(ConsoleExitHandler, NULL); } } /* *---------------------------------------------------------------------- * * ConsoleExitHandler -- * * This function is called to cleanup the console module before * Tcl is unloaded. * * Results: * None. * * Side effects: * Removes the console event source. * *---------------------------------------------------------------------- */ static void ConsoleExitHandler( ClientData clientData) /* Old window proc */ { Tcl_DeleteEventSource(ConsoleSetupProc, ConsoleCheckProc, NULL); } /* *---------------------------------------------------------------------- * * ProcExitHandler -- * * This function is called to cleanup the process list before * Tcl is unloaded. * * Results: * None. * * Side effects: * Resets the process list. * *---------------------------------------------------------------------- */ static void ProcExitHandler( ClientData clientData) /* Old window proc */ { Tcl_MutexLock(&consoleMutex); initialized = 0; Tcl_MutexUnlock(&consoleMutex); } /* *---------------------------------------------------------------------- * * ConsoleSetupProc -- * * This procedure is invoked before Tcl_DoOneEvent blocks waiting * for an event. * * Results: * None. * * Side effects: * Adjusts the block time if needed. * *---------------------------------------------------------------------- */ void ConsoleSetupProc( ClientData data, /* Not used. */ int flags) /* Event flags as passed to Tcl_DoOneEvent. */ { ConsoleInfo *infoPtr; Tcl_Time blockTime = { 0, 0 }; int block = 1; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (!(flags & TCL_FILE_EVENTS)) { return; } /* * Look to see if any events are already pending. If they are, poll. */ for (infoPtr = tsdPtr->firstConsolePtr; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { if (infoPtr->watchMask & TCL_WRITABLE) { if (WaitForSingleObject(infoPtr->writable, 0) != WAIT_TIMEOUT) { block = 0; } } if (infoPtr->watchMask & TCL_READABLE) { if (WaitForRead(infoPtr, 0) >= 0) { block = 0; } } } if (!block) { Tcl_SetMaxBlockTime(&blockTime); } } /* *---------------------------------------------------------------------- * * ConsoleCheckProc -- * * This procedure is called by Tcl_DoOneEvent to check the console * event source for events. * * Results: * None. * * Side effects: * May queue an event. * *---------------------------------------------------------------------- */ static void ConsoleCheckProc( ClientData data, /* Not used. */ int flags) /* Event flags as passed to Tcl_DoOneEvent. */ { ConsoleInfo *infoPtr; ConsoleEvent *evPtr; int needEvent; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (!(flags & TCL_FILE_EVENTS)) { return; } /* * Queue events for any ready consoles that don't already have events * queued. */ for (infoPtr = tsdPtr->firstConsolePtr; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { if (infoPtr->flags & CONSOLE_PENDING) { continue; } /* * Queue an event if the console is signaled for reading or writing. */ needEvent = 0; if (infoPtr->watchMask & TCL_WRITABLE) { if (WaitForSingleObject(infoPtr->writable, 0) != WAIT_TIMEOUT) { needEvent = 1; } } if (infoPtr->watchMask & TCL_READABLE) { if (WaitForRead(infoPtr, 0) >= 0) { needEvent = 1; } } if (needEvent) { infoPtr->flags |= CONSOLE_PENDING; evPtr = (ConsoleEvent *) ckalloc(sizeof(ConsoleEvent)); evPtr->header.proc = ConsoleEventProc; evPtr->infoPtr = infoPtr; Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL); } } } /* *---------------------------------------------------------------------- * * ConsoleBlockModeProc -- * * Set blocking or non-blocking mode on channel. * * Results: * 0 if successful, errno when failed. * * Side effects: * Sets the device into blocking or non-blocking mode. * *---------------------------------------------------------------------- */ static int ConsoleBlockModeProc( ClientData instanceData, /* Instance data for channel. */ int mode) /* TCL_MODE_BLOCKING or * TCL_MODE_NONBLOCKING. */ { ConsoleInfo *infoPtr = (ConsoleInfo *) instanceData; /* * Consoles on Windows can not be switched between blocking and nonblocking, * hence we have to emulate the behavior. This is done in the input * function by checking against a bit in the state. We set or unset the * bit here to cause the input function to emulate the correct behavior. */ if (mode == TCL_MODE_NONBLOCKING) { infoPtr->flags |= CONSOLE_ASYNC; } else { infoPtr->flags &= ~(CONSOLE_ASYNC); } return 0; } /* *---------------------------------------------------------------------- * * ConsoleCloseProc -- * * Closes a console based IO channel. * * Results: * 0 on success, errno otherwise. * * Side effects: * Closes the physical channel. * *---------------------------------------------------------------------- */ static int ConsoleCloseProc( ClientData instanceData, /* Pointer to ConsoleInfo structure. */ Tcl_Interp *interp) /* For error reporting. */ { ConsoleInfo *consolePtr = (ConsoleInfo *) instanceData; int errorCode; ConsoleInfo *infoPtr, **nextPtrPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); DWORD exitCode; errorCode = 0; /* * Clean up the background thread if necessary. Note that this * must be done before we can close the file, since the * thread may be blocking trying to read from the console. */ if (consolePtr->readThread) { /* * The thread may already have closed on it's own. Check it's * exit code. */ GetExitCodeThread(consolePtr->readThread, &exitCode); if (exitCode == STILL_ACTIVE) { /* * Set the stop event so that if the reader thread is blocked * in ConsoleReaderThread on WaitForMultipleEvents, it will exit * cleanly. */ SetEvent(consolePtr->stopReader); /* * Wait at most 20 milliseconds for the reader thread to close. */ if (WaitForSingleObject(consolePtr->readThread, 20) == WAIT_TIMEOUT) { /* * Forcibly terminate the background thread as a last * resort. Note that we need to guard against * terminating the thread while it is in the middle of * Tcl_ThreadAlert because it won't be able to release * the notifier lock. */ Tcl_MutexLock(&consoleMutex); /* BUG: this leaks memory. */ TerminateThread(consolePtr->readThread, 0); Tcl_MutexUnlock(&consoleMutex); } } CloseHandle(consolePtr->readThread); CloseHandle(consolePtr->readable); CloseHandle(consolePtr->startReader); CloseHandle(consolePtr->stopReader); consolePtr->readThread = NULL; } consolePtr->validMask &= ~TCL_READABLE; /* * Wait for the writer thread to finish the current buffer, then * terminate the thread and close the handles. If the channel is * nonblocking, there should be no pending write operations. */ if (consolePtr->writeThread) { if (consolePtr->toWrite) { /* * We only need to wait if there is something to write. * This may prevent infinite wait on exit. [python bug 216289] */ WaitForSingleObject(consolePtr->writable, INFINITE); } /* * The thread may already have closed on it's own. Check it's * exit code. */ GetExitCodeThread(consolePtr->writeThread, &exitCode); if (exitCode == STILL_ACTIVE) { /* * Set the stop event so that if the reader thread is blocked * in ConsoleWriterThread on WaitForMultipleEvents, it will * exit cleanly. */ SetEvent(consolePtr->stopWriter); /* * Wait at most 20 milliseconds for the writer thread to close. */ if (WaitForSingleObject(consolePtr->writeThread, 20) == WAIT_TIMEOUT) { /* * Forcibly terminate the background thread as a last * resort. Note that we need to guard against * terminating the thread while it is in the middle of * Tcl_ThreadAlert because it won't be able to release * the notifier lock. */ Tcl_MutexLock(&consoleMutex); /* BUG: this leaks memory. */ TerminateThread(consolePtr->writeThread, 0); Tcl_MutexUnlock(&consoleMutex); } } CloseHandle(consolePtr->writeThread); CloseHandle(consolePtr->writable); CloseHandle(consolePtr->startWriter); CloseHandle(consolePtr->stopWriter); consolePtr->writeThread = NULL; } consolePtr->validMask &= ~TCL_WRITABLE; /* * Don't close the Win32 handle if the handle is a standard channel * during the thread exit process. Otherwise, one thread may kill * the stdio of another. */ if (!TclInThreadExit() || ((GetStdHandle(STD_INPUT_HANDLE) != consolePtr->handle) && (GetStdHandle(STD_OUTPUT_HANDLE) != consolePtr->handle) && (GetStdHandle(STD_ERROR_HANDLE) != consolePtr->handle))) { if (CloseHandle(consolePtr->handle) == FALSE) { TclWinConvertError(GetLastError()); errorCode = errno; } } consolePtr->watchMask &= consolePtr->validMask; /* * Remove the file from the list of watched files. */ for (nextPtrPtr = &(tsdPtr->firstConsolePtr), infoPtr = *nextPtrPtr; infoPtr != NULL; nextPtrPtr = &infoPtr->nextPtr, infoPtr = *nextPtrPtr) { if (infoPtr == (ConsoleInfo *)consolePtr) { *nextPtrPtr = infoPtr->nextPtr; break; } } if (consolePtr->writeBuf != NULL) { ckfree(consolePtr->writeBuf); consolePtr->writeBuf = 0; } ckfree((char*) consolePtr); return errorCode; } /* *---------------------------------------------------------------------- * * ConsoleInputProc -- * * Reads input from the IO channel into the buffer given. Returns * count of how many bytes were actually read, and an error indication. * * Results: * A count of how many bytes were read is returned and an error * indication is returned in an output argument. * * Side effects: * Reads input from the actual channel. * *---------------------------------------------------------------------- */ static int ConsoleInputProc( ClientData instanceData, /* Console state. */ char *buf, /* Where to store data read. */ int bufSize, /* How much space is available * in the buffer? */ int *errorCode) /* Where to store error code. */ { ConsoleInfo *infoPtr = (ConsoleInfo *) instanceData; DWORD count, bytesRead = 0; int result; *errorCode = 0; /* * Synchronize with the reader thread. */ result = WaitForRead(infoPtr, (infoPtr->flags & CONSOLE_ASYNC) ? 0 : 1); /* * If an error occurred, return immediately. */ if (result == -1) { *errorCode = errno; return -1; } if (infoPtr->readFlags & CONSOLE_BUFFERED) { /* * Data is stored in the buffer. */ if (bufSize < (infoPtr->bytesRead - infoPtr->offset)) { memcpy(buf, &infoPtr->buffer[infoPtr->offset], (size_t) bufSize); bytesRead = bufSize; infoPtr->offset += bufSize; } else { memcpy(buf, &infoPtr->buffer[infoPtr->offset], (size_t) bufSize); bytesRead = infoPtr->bytesRead - infoPtr->offset; /* * Reset the buffer */ infoPtr->readFlags &= ~CONSOLE_BUFFERED; infoPtr->offset = 0; } return bytesRead; } /* * Attempt to read bufSize bytes. The read will return immediately * if there is any data available. Otherwise it will block until * at least one byte is available or an EOF occurs. */ if (ReadConsole(infoPtr->handle, (LPVOID) buf, (DWORD) bufSize, &count, NULL) == TRUE) { buf[count] = '\0'; return count; } return -1; } /* *---------------------------------------------------------------------- * * ConsoleOutputProc -- * * Writes the given output on the IO channel. Returns count of how * many characters were actually written, and an error indication. * * Results: * A count of how many characters were written is returned and an * error indication is returned in an output argument. * * Side effects: * Writes output on the actual channel. * *---------------------------------------------------------------------- */ static int ConsoleOutputProc( ClientData instanceData, /* Console state. */ CONST char *buf, /* The data buffer. */ int toWrite, /* How many bytes to write? */ int *errorCode) /* Where to store error code. */ { ConsoleInfo *infoPtr = (ConsoleInfo *) instanceData; DWORD bytesWritten, timeout; *errorCode = 0; timeout = (infoPtr->flags & CONSOLE_ASYNC) ? 0 : INFINITE; if (WaitForSingleObject(infoPtr->writable, timeout) == WAIT_TIMEOUT) { /* * The writer thread is blocked waiting for a write to complete * and the channel is in non-blocking mode. */ errno = EAGAIN; goto error; } /* * Check for a background error on the last write. */ if (infoPtr->writeError) { TclWinConvertError(infoPtr->writeError); infoPtr->writeError = 0; goto error; } if (infoPtr->flags & CONSOLE_ASYNC) { /* * The console is non-blocking, so copy the data into the output * buffer and restart the writer thread. */ if (toWrite > infoPtr->writeBufLen) { /* * Reallocate the buffer to be large enough to hold the data. */ if (infoPtr->writeBuf) { ckfree(infoPtr->writeBuf); } infoPtr->writeBufLen = toWrite; infoPtr->writeBuf = ckalloc((unsigned int) toWrite); } memcpy(infoPtr->writeBuf, buf, (size_t) toWrite); infoPtr->toWrite = toWrite; ResetEvent(infoPtr->writable); SetEvent(infoPtr->startWriter); bytesWritten = toWrite; } else { /* * In the blocking case, just try to write the buffer directly. * This avoids an unnecessary copy. */ if (WriteFile(infoPtr->handle, (LPVOID) buf, (DWORD) toWrite, &bytesWritten, (LPOVERLAPPED) NULL) == FALSE) { TclWinConvertError(GetLastError()); goto error; } } return bytesWritten; error: *errorCode = errno; return -1; } /* *---------------------------------------------------------------------- * * ConsoleEventProc -- * * This function is invoked by Tcl_ServiceEvent when a file event * reaches the front of the event queue. This procedure invokes * Tcl_NotifyChannel on the console. * * Results: * Returns 1 if the event was handled, meaning it should be removed * from the queue. Returns 0 if the event was not handled, meaning * it should stay on the queue. The only time the event isn't * handled is if the TCL_FILE_EVENTS flag bit isn't set. * * Side effects: * Whatever the notifier callback does. * *---------------------------------------------------------------------- */ static int ConsoleEventProc( Tcl_Event *evPtr, /* Event to service. */ int flags) /* Flags that indicate what events to * handle, such as TCL_FILE_EVENTS. */ { ConsoleEvent *consoleEvPtr = (ConsoleEvent *)evPtr; ConsoleInfo *infoPtr; int mask; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (!(flags & TCL_FILE_EVENTS)) { return 0; } /* * Search through the list of watched consoles for the one whose handle * matches the event. We do this rather than simply dereferencing * the handle in the event so that consoles can be deleted while the * event is in the queue. */ for (infoPtr = tsdPtr->firstConsolePtr; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { if (consoleEvPtr->infoPtr == infoPtr) { infoPtr->flags &= ~(CONSOLE_PENDING); break; } } /* * Remove stale events. */ if (!infoPtr) { return 1; } /* * Check to see if the console is readable. Note * that we can't tell if a console is writable, so we always report it * as being writable unless we have detected EOF. */ mask = 0; if (infoPtr->watchMask & TCL_WRITABLE) { if (WaitForSingleObject(infoPtr->writable, 0) != WAIT_TIMEOUT) { mask = TCL_WRITABLE; } } if (infoPtr->watchMask & TCL_READABLE) { if (WaitForRead(infoPtr, 0) >= 0) { if (infoPtr->readFlags & CONSOLE_EOF) { mask = TCL_READABLE; } else { mask |= TCL_READABLE; } } } /* * Inform the channel of the events. */ Tcl_NotifyChannel(infoPtr->channel, infoPtr->watchMask & mask); return 1; } /* *---------------------------------------------------------------------- * * ConsoleWatchProc -- * * Called by the notifier to set up to watch for events on this * channel. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void ConsoleWatchProc( ClientData instanceData, /* Console state. */ int mask) /* What events to watch for, OR-ed * combination of TCL_READABLE, * TCL_WRITABLE and TCL_EXCEPTION. */ { ConsoleInfo **nextPtrPtr, *ptr; ConsoleInfo *infoPtr = (ConsoleInfo *) instanceData; int oldMask = infoPtr->watchMask; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); /* * Since most of the work is handled by the background threads, * we just need to update the watchMask and then force the notifier * to poll once. */ infoPtr->watchMask = mask & infoPtr->validMask; if (infoPtr->watchMask) { Tcl_Time blockTime = { 0, 0 }; if (!oldMask) { infoPtr->nextPtr = tsdPtr->firstConsolePtr; tsdPtr->firstConsolePtr = infoPtr; } Tcl_SetMaxBlockTime(&blockTime); } else { if (oldMask) { /* * Remove the console from the list of watched consoles. */ for (nextPtrPtr = &(tsdPtr->firstConsolePtr), ptr = *nextPtrPtr; ptr != NULL; nextPtrPtr = &ptr->nextPtr, ptr = *nextPtrPtr) { if (infoPtr == ptr) { *nextPtrPtr = ptr->nextPtr; break; } } } } } /* *---------------------------------------------------------------------- * * ConsoleGetHandleProc -- * * Called from Tcl_GetChannelHandle to retrieve OS handles from * inside a command consoleline based channel. * * Results: * Returns TCL_OK with the fd in handlePtr, or TCL_ERROR if * there is no handle for the specified direction. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int ConsoleGetHandleProc( ClientData instanceData, /* The console state. */ int direction, /* TCL_READABLE or TCL_WRITABLE */ ClientData *handlePtr) /* Where to store the handle. */ { ConsoleInfo *infoPtr = (ConsoleInfo *) instanceData; *handlePtr = (ClientData) infoPtr->handle; return TCL_OK; } /* *---------------------------------------------------------------------- * * WaitForRead -- * * Wait until some data is available, the console is at * EOF or the reader thread is blocked waiting for data (if the * channel is in non-blocking mode). * * Results: * Returns 1 if console is readable. Returns 0 if there is no data * on the console, but there is buffered data. Returns -1 if an * error occurred. If an error occurred, the threads may not * be synchronized. * * Side effects: * Updates the shared state flags. If no error occurred, * the reader thread is blocked waiting for a signal from the * main thread. * *---------------------------------------------------------------------- */ static int WaitForRead( ConsoleInfo *infoPtr, /* Console state. */ int blocking) /* Indicates whether call should be * blocking or not. */ { DWORD timeout, count; HANDLE *handle = infoPtr->handle; INPUT_RECORD input; while (1) { /* * Synchronize with the reader thread. */ timeout = blocking ? INFINITE : 0; if (WaitForSingleObject(infoPtr->readable, timeout) == WAIT_TIMEOUT) { /* * The reader thread is blocked waiting for data and the channel * is in non-blocking mode. */ errno = EAGAIN; return -1; } /* * At this point, the two threads are synchronized, so it is safe * to access shared state. */ /* * If the console has hit EOF, it is always readable. */ if (infoPtr->readFlags & CONSOLE_EOF) { return 1; } if (PeekConsoleInput(handle, &input, 1, &count) == FALSE) { /* * Check to see if the peek failed because of EOF. */ TclWinConvertError(GetLastError()); if (errno == EOF) { infoPtr->readFlags |= CONSOLE_EOF; return 1; } /* * Ignore errors if there is data in the buffer. */ if (infoPtr->readFlags & CONSOLE_BUFFERED) { return 0; } else { return -1; } } /* * If there is data in the buffer, the console must be * readable (since it is a line-oriented device). */ if (infoPtr->readFlags & CONSOLE_BUFFERED) { return 1; } /* * There wasn't any data available, so reset the thread and * try again. */ ResetEvent(infoPtr->readable); SetEvent(infoPtr->startReader); } } /* *---------------------------------------------------------------------- * * ConsoleReaderThread -- * * This function runs in a separate thread and waits for input * to become available on a console. * * Results: * None. * * Side effects: * Signals the main thread when input become available. May * cause the main thread to wake up by posting a message. May * one line from the console for each wait operation. * *---------------------------------------------------------------------- */ static DWORD WINAPI ConsoleReaderThread(LPVOID arg) { ConsoleInfo *infoPtr = (ConsoleInfo *)arg; HANDLE *handle = infoPtr->handle; DWORD waitResult; HANDLE wEvents[2]; /* The first event takes precedence. */ wEvents[0] = infoPtr->stopReader; wEvents[1] = infoPtr->startReader; for (;;) { /* * Wait for the main thread to signal before attempting to wait. */ waitResult = WaitForMultipleObjects(2, wEvents, FALSE, INFINITE); if (waitResult != (WAIT_OBJECT_0 + 1)) { /* * The start event was not signaled. It must be the stop event * or an error, so exit this thread. */ break; } /* * Look for data on the console, but first ignore any events * that are not KEY_EVENTs */ if (ReadConsoleA(handle, infoPtr->buffer, CONSOLE_BUFFER_SIZE, (LPDWORD) &infoPtr->bytesRead, NULL) != FALSE) { /* * Data was stored in the buffer. */ infoPtr->readFlags |= CONSOLE_BUFFERED; } else { DWORD err; err = GetLastError(); if (err == (DWORD)EOF) { infoPtr->readFlags = CONSOLE_EOF; } } /* * Signal the main thread by signalling the readable event and * then waking up the notifier thread. */ SetEvent(infoPtr->readable); /* * Alert the foreground thread. Note that we need to treat this like * a critical section so the foreground thread does not terminate * this thread while we are holding a mutex in the notifier code. */ Tcl_MutexLock(&consoleMutex); if (infoPtr->threadId != NULL) { /* TIP #218. When in flight ignore the event, no one will receive it anyway */ Tcl_ThreadAlert(infoPtr->threadId); } Tcl_MutexUnlock(&consoleMutex); } return 0; } /* *---------------------------------------------------------------------- * * ConsoleWriterThread -- * * This function runs in a separate thread and writes data * onto a console. * * Results: * Always returns 0. * * Side effects: * Signals the main thread when an output operation is completed. * May cause the main thread to wake up by posting a message. * *---------------------------------------------------------------------- */ static DWORD WINAPI ConsoleWriterThread(LPVOID arg) { ConsoleInfo *infoPtr = (ConsoleInfo *)arg; HANDLE *handle = infoPtr->handle; DWORD count, toWrite, waitResult; char *buf; HANDLE wEvents[2]; /* The first event takes precedence. */ wEvents[0] = infoPtr->stopWriter; wEvents[1] = infoPtr->startWriter; for (;;) { /* * Wait for the main thread to signal before attempting to write. */ waitResult = WaitForMultipleObjects(2, wEvents, FALSE, INFINITE); if (waitResult != (WAIT_OBJECT_0 + 1)) { /* * The start event was not signaled. It must be the stop event * or an error, so exit this thread. */ break; } buf = infoPtr->writeBuf; toWrite = infoPtr->toWrite; /* * Loop until all of the bytes are written or an error occurs. */ while (toWrite > 0) { if (WriteConsoleA(handle, buf, toWrite, &count, NULL) == FALSE) { infoPtr->writeError = GetLastError(); break; } else { toWrite -= count; buf += count; } } /* * Signal the main thread by signalling the writable event and * then waking up the notifier thread. */ SetEvent(infoPtr->writable); /* * Alert the foreground thread. Note that we need to treat this like * a critical section so the foreground thread does not terminate * this thread while we are holding a mutex in the notifier code. */ Tcl_MutexLock(&consoleMutex); if (infoPtr->threadId != NULL) { /* TIP #218. When in flight ignore the event, no one will receive it anyway */ Tcl_ThreadAlert(infoPtr->threadId); } Tcl_MutexUnlock(&consoleMutex); } return 0; } /* *---------------------------------------------------------------------- * * TclWinOpenConsoleChannel -- * * Constructs a Console channel for the specified standard OS handle. * This is a helper function to break up the construction of * channels into File, Console, or Serial. * * Results: * Returns the new channel, or NULL. * * Side effects: * May open the channel * *---------------------------------------------------------------------- */ Tcl_Channel TclWinOpenConsoleChannel(handle, channelName, permissions) HANDLE handle; char *channelName; int permissions; { char encoding[4 + TCL_INTEGER_SPACE]; ConsoleInfo *infoPtr; DWORD id, modes; ConsoleInit(); /* * See if a channel with this handle already exists. */ infoPtr = (ConsoleInfo *) ckalloc((unsigned) sizeof(ConsoleInfo)); memset(infoPtr, 0, sizeof(ConsoleInfo)); infoPtr->validMask = permissions; infoPtr->handle = handle; infoPtr->channel = (Tcl_Channel) NULL; wsprintfA(encoding, "cp%d", GetConsoleCP()); infoPtr->threadId = Tcl_GetCurrentThread(); /* * Use the pointer for the name of the result channel. * This keeps the channel names unique, since some may share * handles (stdin/stdout/stderr for instance). */ wsprintfA(channelName, "file%lx", (int) infoPtr); infoPtr->channel = Tcl_CreateChannel(&consoleChannelType, channelName, (ClientData) infoPtr, permissions); if (permissions & TCL_READABLE) { /* * Make sure the console input buffer is ready for only character * input notifications and the buffer is set for line buffering. * IOW, we only want to catch when complete lines are ready for * reading. */ GetConsoleMode(infoPtr->handle, &modes); modes &= ~(ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT); modes |= ENABLE_LINE_INPUT; SetConsoleMode(infoPtr->handle, modes); infoPtr->readable = CreateEvent(NULL, TRUE, TRUE, NULL); infoPtr->startReader = CreateEvent(NULL, FALSE, FALSE, NULL); infoPtr->stopReader = CreateEvent(NULL, FALSE, FALSE, NULL); infoPtr->readThread = CreateThread(NULL, 256, ConsoleReaderThread, infoPtr, 0, &id); SetThreadPriority(infoPtr->readThread, THREAD_PRIORITY_HIGHEST); } if (permissions & TCL_WRITABLE) { infoPtr->writable = CreateEvent(NULL, TRUE, TRUE, NULL); infoPtr->startWriter = CreateEvent(NULL, FALSE, FALSE, NULL); infoPtr->stopWriter = CreateEvent(NULL, FALSE, FALSE, NULL); infoPtr->writeThread = CreateThread(NULL, 256, ConsoleWriterThread, infoPtr, 0, &id); SetThreadPriority(infoPtr->writeThread, THREAD_PRIORITY_HIGHEST); } /* * Files have default translation of AUTO and ^Z eof char, which * means that a ^Z will be accepted as EOF when reading. */ Tcl_SetChannelOption(NULL, infoPtr->channel, "-translation", "auto"); Tcl_SetChannelOption(NULL, infoPtr->channel, "-eofchar", "\032 {}"); Tcl_SetChannelOption(NULL, infoPtr->channel, "-encoding", encoding); return infoPtr->channel; } /* *---------------------------------------------------------------------- * * ConsoleThreadActionProc -- * * Insert or remove any thread local refs to this channel. * * Results: * None. * * Side effects: * Changes thread local list of valid channels. * *---------------------------------------------------------------------- */ static void ConsoleThreadActionProc (instanceData, action) ClientData instanceData; int action; { ConsoleInfo *infoPtr = (ConsoleInfo *) instanceData; /* We do not access firstConsolePtr in the thread structures. This is * not for all serials managed by the thread, but only those we are * watching. Removal of the filevent handlers before transfer thus * takes care of this structure. */ Tcl_MutexLock(&consoleMutex); if (action == TCL_CHANNEL_THREAD_INSERT) { /* We can't copy the thread information from the channel when * the channel is created. At this time the channel back * pointer has not been set yet. However in that case the * threadId has already been set by TclpCreateCommandChannel * itself, so the structure is still good. */ ConsoleInit (); if (infoPtr->channel != NULL) { infoPtr->threadId = Tcl_GetChannelThread (infoPtr->channel); } } else { infoPtr->threadId = NULL; } Tcl_MutexUnlock(&consoleMutex); } tcl8.4.20/win/configure0000755003604700454610000023360712153151142013417 0ustar dgp771div#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated automatically using autoconf version 2.13 # Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. # Defaults: ac_help= ac_default_prefix=/usr/local # Any additions from configure.in: ac_help="$ac_help --enable-threads build with threads (default: off)" ac_help="$ac_help --enable-shared build and link with shared libraries (default: on)" ac_help="$ac_help --enable-64bit enable 64bit support (where applicable)" ac_help="$ac_help --enable-wince enable Win/CE support (where applicable)" ac_help="$ac_help --with-celib=DIR use Windows/CE support library from DIR" ac_help="$ac_help --enable-symbols build with debugging symbols (default: off)" # Initialize some variables set by options. # The variables have the same names as the options, with # dashes changed to underlines. build=NONE cache_file=./config.cache exec_prefix=NONE host=NONE no_create= nonopt=NONE no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= target=NONE verbose= x_includes=NONE x_libraries=NONE bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datadir='${prefix}/share' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' libdir='${exec_prefix}/lib' includedir='${prefix}/include' oldincludedir='/usr/include' infodir='${prefix}/info' mandir='${prefix}/man' # Initialize some other variables. subdirs= MFLAGS= MAKEFLAGS= SHELL=${CONFIG_SHELL-/bin/sh} # Maximum number of lines to put in a shell here document. ac_max_here_lines=12 ac_prev= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval "$ac_prev=\$ac_option" ac_prev= continue fi case "$ac_option" in -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; *) ac_optarg= ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case "$ac_option" in -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir="$ac_optarg" ;; -build | --build | --buil | --bui | --bu) ac_prev=build ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build="$ac_optarg" ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file="$ac_optarg" ;; -datadir | --datadir | --datadi | --datad | --data | --dat | --da) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ | --da=*) datadir="$ac_optarg" ;; -disable-* | --disable-*) ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } fi ac_feature=`echo $ac_feature| sed 's/-/_/g'` eval "enable_${ac_feature}=no" ;; -enable-* | --enable-*) ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } fi ac_feature=`echo $ac_feature| sed 's/-/_/g'` case "$ac_option" in *=*) ;; *) ac_optarg=yes ;; esac eval "enable_${ac_feature}='$ac_optarg'" ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix="$ac_optarg" ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he) # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat << EOF Usage: configure [options] [host] Options: [defaults in brackets after descriptions] Configuration: --cache-file=FILE cache test results in FILE --help print this message --no-create do not create output files --quiet, --silent do not print \`checking...' messages --version print the version of autoconf that created configure Directory and file names: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [same as prefix] --bindir=DIR user executables in DIR [EPREFIX/bin] --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] --libexecdir=DIR program executables in DIR [EPREFIX/libexec] --datadir=DIR read-only architecture-independent data in DIR [PREFIX/share] --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data in DIR [PREFIX/com] --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] --libdir=DIR object code libraries in DIR [EPREFIX/lib] --includedir=DIR C header files in DIR [PREFIX/include] --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] --infodir=DIR info documentation in DIR [PREFIX/info] --mandir=DIR man documentation in DIR [PREFIX/man] --srcdir=DIR find the sources in DIR [configure dir or ..] --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names EOF cat << EOF Host type: --build=BUILD configure for building on BUILD [BUILD=HOST] --host=HOST configure for HOST [guessed] --target=TARGET configure for TARGET [TARGET=HOST] Features and packages: --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --x-includes=DIR X include files are in DIR --x-libraries=DIR X library files are in DIR EOF if test -n "$ac_help"; then echo "--enable and --with options recognized:$ac_help" fi exit 0 ;; -host | --host | --hos | --ho) ac_prev=host ;; -host=* | --host=* | --hos=* | --ho=*) host="$ac_optarg" ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir="$ac_optarg" ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir="$ac_optarg" ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir="$ac_optarg" ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir="$ac_optarg" ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst \ | --locals | --local | --loca | --loc | --lo) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* \ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) localstatedir="$ac_optarg" ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir="$ac_optarg" ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir="$ac_optarg" ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix="$ac_optarg" ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix="$ac_optarg" ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix="$ac_optarg" ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name="$ac_optarg" ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir="$ac_optarg" ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir="$ac_optarg" ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site="$ac_optarg" ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir="$ac_optarg" ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir="$ac_optarg" ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target="$ac_optarg" ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers) echo "configure generated by autoconf version 2.13" exit 0 ;; -with-* | --with-*) ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } fi ac_package=`echo $ac_package| sed 's/-/_/g'` case "$ac_option" in *=*) ;; *) ac_optarg=yes ;; esac eval "with_${ac_package}='$ac_optarg'" ;; -without-* | --without-*) ac_package=`echo $ac_option|sed -e 's/-*without-//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } fi ac_package=`echo $ac_package| sed 's/-/_/g'` eval "with_${ac_package}=no" ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes="$ac_optarg" ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries="$ac_optarg" ;; -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } ;; *) if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then echo "configure: warning: $ac_option: invalid host type" 1>&2 fi if test "x$nonopt" != xNONE; then { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } fi nonopt="$ac_option" ;; esac done if test -n "$ac_prev"; then { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } fi trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 # File descriptor usage: # 0 standard input # 1 file creation # 2 errors and warnings # 3 some systems may open it to /dev/tty # 4 used on the Kubota Titan # 6 checking for... messages and results # 5 compiler messages saved in config.log if test "$silent" = yes; then exec 6>/dev/null else exec 6>&1 fi exec 5>./config.log echo "\ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. " 1>&5 # Strip out --no-create and --no-recursion so they do not pile up. # Also quote any args containing shell metacharacters. ac_configure_args= for ac_arg do case "$ac_arg" in -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c) ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) ac_configure_args="$ac_configure_args '$ac_arg'" ;; *) ac_configure_args="$ac_configure_args $ac_arg" ;; esac done # NLS nuisances. # Only set these to C if already set. These must not be set unconditionally # because not all systems understand e.g. LANG=C (notably SCO). # Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! # Non-C LC_CTYPE values break the ctype check. if test "${LANG+set}" = set; then LANG=C; export LANG; fi if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -rf conftest* confdefs.h # AIX cpp loses on an empty file, so make sure it contains at least a newline. echo > confdefs.h # A filename unique to this package, relative to the directory that # configure is in, which we can look for to find out if srcdir is correct. ac_unique_file=../generic/tcl.h # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then its parent. ac_prog=$0 ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. srcdir=$ac_confdir if test ! -r $srcdir/$ac_unique_file; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r $srcdir/$ac_unique_file; then if test "$ac_srcdir_defaulted" = yes; then { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } else { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } fi fi srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` # Prefer explicitly selected file to automatically selected ones. if test -z "$CONFIG_SITE"; then if test "x$prefix" != xNONE; then CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" else CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi fi for ac_site_file in $CONFIG_SITE; do if test -r "$ac_site_file"; then echo "loading site script $ac_site_file" . "$ac_site_file" fi done if test -r "$cache_file"; then echo "loading cache $cache_file" . $cache_file else echo "creating cache $cache_file" > $cache_file fi ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. ac_cpp='$CPP $CPPFLAGS' ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' cross_compiling=$ac_cv_prog_cc_cross ac_exeext= ac_objext=o if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then ac_n= ac_c=' ' ac_t=' ' else ac_n=-n ac_c= ac_t= fi else ac_n= ac_c='\c' ac_t= fi TCL_VERSION=8.4 TCL_MAJOR_VERSION=8 TCL_MINOR_VERSION=4 TCL_PATCH_LEVEL=".20" VER=$TCL_MAJOR_VERSION$TCL_MINOR_VERSION TCL_DDE_VERSION=1.3 TCL_DDE_MAJOR_VERSION=1 TCL_DDE_MINOR_VERSION=3 DDEVER=$TCL_DDE_MAJOR_VERSION$TCL_DDE_MINOR_VERSION TCL_REG_VERSION=1.2 TCL_REG_MAJOR_VERSION=1 TCL_REG_MINOR_VERSION=2 REGVER=$TCL_REG_MAJOR_VERSION$TCL_REG_MINOR_VERSION #------------------------------------------------------------------------ # Handle the --prefix=... option #------------------------------------------------------------------------ if test "${prefix}" = "NONE"; then prefix=/usr/local fi if test "${exec_prefix}" = "NONE"; then exec_prefix=$prefix fi # libdir must be a fully qualified path (not ${exec_prefix}/lib) eval libdir="$libdir" #------------------------------------------------------------------------ # Standard compiler checks #------------------------------------------------------------------------ # If the user did not set CFLAGS, set it now to keep # the AC_PROG_CC macro from adding "-g -O2". if test "${CFLAGS+set}" != "set" ; then CFLAGS="" fi # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo "configure:581: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" ac_dummy="$PATH" for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_prog_CC="gcc" break fi done IFS="$ac_save_ifs" fi fi CC="$ac_cv_prog_CC" if test -n "$CC"; then echo "$ac_t""$CC" 1>&6 else echo "$ac_t""no" 1>&6 fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo "configure:611: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" ac_prog_rejected=no ac_dummy="$PATH" for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" break fi done IFS="$ac_save_ifs" if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# -gt 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift set dummy "$ac_dir/$ac_word" "$@" shift ac_cv_prog_CC="$@" fi fi fi fi CC="$ac_cv_prog_CC" if test -n "$CC"; then echo "$ac_t""$CC" 1>&6 else echo "$ac_t""no" 1>&6 fi if test -z "$CC"; then case "`uname -s`" in *win32* | *WIN32*) # Extract the first word of "cl", so it can be a program name with args. set dummy cl; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo "configure:662: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" ac_dummy="$PATH" for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_prog_CC="cl" break fi done IFS="$ac_save_ifs" fi fi CC="$ac_cv_prog_CC" if test -n "$CC"; then echo "$ac_t""$CC" 1>&6 else echo "$ac_t""no" 1>&6 fi ;; esac fi test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } fi echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 echo "configure:694: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. ac_cpp='$CPP $CPPFLAGS' ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' cross_compiling=$ac_cv_prog_cc_cross cat > conftest.$ac_ext << EOF #line 705 "configure" #include "confdefs.h" main(){return(0);} EOF if { (eval echo configure:710: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then ac_cv_prog_cc_works=yes # If we can't run a trivial program, we are probably using a cross compiler. if (./conftest; exit) 2>/dev/null; then ac_cv_prog_cc_cross=no else ac_cv_prog_cc_cross=yes fi else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 ac_cv_prog_cc_works=no fi rm -fr conftest* ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. ac_cpp='$CPP $CPPFLAGS' ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' cross_compiling=$ac_cv_prog_cc_cross echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 if test $ac_cv_prog_cc_works = no; then { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } fi echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 echo "configure:736: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 cross_compiling=$ac_cv_prog_cc_cross echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 echo "configure:741: checking whether we are using GNU C" >&5 if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then ac_cv_prog_gcc=yes else ac_cv_prog_gcc=no fi fi echo "$ac_t""$ac_cv_prog_gcc" 1>&6 if test $ac_cv_prog_gcc = yes; then GCC=yes else GCC= fi ac_test_CFLAGS="${CFLAGS+set}" ac_save_CFLAGS="$CFLAGS" CFLAGS= echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 echo "configure:769: checking whether ${CC-cc} accepts -g" >&5 if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else echo 'void f(){}' > conftest.c if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then ac_cv_prog_cc_g=yes else ac_cv_prog_cc_g=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 if test "$ac_test_CFLAGS" = set; then CFLAGS="$ac_save_CFLAGS" elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi # To properly support cross-compilation, one would # need to use these tool checks instead of # the ones below and reconfigure with # autoconf 2.50. You can also just set # the CC, AR, RANLIB, and RC environment # variables if you want to cross compile. if test "${GCC}" = "yes" ; then # Extract the first word of "ar", so it can be a program name with args. set dummy ar; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo "configure:812: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_AR'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" ac_dummy="$PATH" for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_prog_AR="ar" break fi done IFS="$ac_save_ifs" fi fi AR="$ac_cv_prog_AR" if test -n "$AR"; then echo "$ac_t""$AR" 1>&6 else echo "$ac_t""no" 1>&6 fi # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo "configure:841: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" ac_dummy="$PATH" for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_prog_RANLIB="ranlib" break fi done IFS="$ac_save_ifs" fi fi RANLIB="$ac_cv_prog_RANLIB" if test -n "$RANLIB"; then echo "$ac_t""$RANLIB" 1>&6 else echo "$ac_t""no" 1>&6 fi # Extract the first word of "windres", so it can be a program name with args. set dummy windres; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo "configure:870: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_RC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$RC"; then ac_cv_prog_RC="$RC" # Let the user override the test. else IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" ac_dummy="$PATH" for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_prog_RC="windres" break fi done IFS="$ac_save_ifs" fi fi RC="$ac_cv_prog_RC" if test -n "$RC"; then echo "$ac_t""$RC" 1>&6 else echo "$ac_t""no" 1>&6 fi if test "${AR}" = "" ; then { echo "configure: error: Required archive tool 'ar' not found on PATH." 1>&2; exit 1; } fi if test "${RANLIB}" = "" ; then { echo "configure: error: Required archive index tool 'ranlib' not found on PATH." 1>&2; exit 1; } fi if test "${RC}" = "" ; then { echo "configure: error: Required resource tool 'windres' not found on PATH." 1>&2; exit 1; } fi fi #-------------------------------------------------------------------- # Checks to see if the make program sets the $MAKE variable. #-------------------------------------------------------------------- echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6 echo "configure:913: checking whether ${MAKE-make} sets \${MAKE}" >&5 set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftestmake <<\EOF all: @echo 'ac_maketemp="${MAKE}"' EOF # GNU make sometimes prints "make[1]: Entering...", which would confuse us. eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=` if test -n "$ac_maketemp"; then eval ac_cv_prog_make_${ac_make}_set=yes else eval ac_cv_prog_make_${ac_make}_set=no fi rm -f conftestmake fi if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then echo "$ac_t""yes" 1>&6 SET_MAKE= else echo "$ac_t""no" 1>&6 SET_MAKE="MAKE=${MAKE-make}" fi #-------------------------------------------------------------------- # Determines the correct binary file extension (.o, .obj, .exe etc.) #-------------------------------------------------------------------- echo $ac_n "checking for object suffix""... $ac_c" 1>&6 echo "configure:945: checking for object suffix" >&5 if eval "test \"`echo '$''{'ac_cv_objext'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else rm -f conftest* echo 'int i = 1;' > conftest.$ac_ext if { (eval echo configure:951: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then for ac_file in conftest.*; do case $ac_file in *.c) ;; *) ac_cv_objext=`echo $ac_file | sed -e s/conftest.//` ;; esac done else { echo "configure: error: installation or configuration problem; compiler does not work" 1>&2; exit 1; } fi rm -f conftest* fi echo "$ac_t""$ac_cv_objext" 1>&6 OBJEXT=$ac_cv_objext ac_objext=$ac_cv_objext echo $ac_n "checking for Cygwin environment""... $ac_c" 1>&6 echo "configure:969: checking for Cygwin environment" >&5 if eval "test \"`echo '$''{'ac_cv_cygwin'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_cygwin=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* ac_cv_cygwin=no fi rm -f conftest* rm -f conftest* fi echo "$ac_t""$ac_cv_cygwin" 1>&6 CYGWIN= test "$ac_cv_cygwin" = yes && CYGWIN=yes echo $ac_n "checking for mingw32 environment""... $ac_c" 1>&6 echo "configure:1002: checking for mingw32 environment" >&5 if eval "test \"`echo '$''{'ac_cv_mingw32'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_mingw32=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* ac_cv_mingw32=no fi rm -f conftest* rm -f conftest* fi echo "$ac_t""$ac_cv_mingw32" 1>&6 MINGW32= test "$ac_cv_mingw32" = yes && MINGW32=yes echo $ac_n "checking for executable suffix""... $ac_c" 1>&6 echo "configure:1033: checking for executable suffix" >&5 if eval "test \"`echo '$''{'ac_cv_exeext'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$CYGWIN" = yes || test "$MINGW32" = yes; then ac_cv_exeext=.exe else rm -f conftest* echo 'int main () { return 0; }' > conftest.$ac_ext ac_cv_exeext= if { (eval echo configure:1043: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then for file in conftest.*; do case $file in *.c | *.o | *.obj) ;; *) ac_cv_exeext=`echo $file | sed -e s/conftest//` ;; esac done else { echo "configure: error: installation or configuration problem: compiler cannot create executables." 1>&2; exit 1; } fi rm -f conftest* test x"${ac_cv_exeext}" = x && ac_cv_exeext=no fi fi EXEEXT="" test x"${ac_cv_exeext}" != xno && EXEEXT=${ac_cv_exeext} echo "$ac_t""${ac_cv_exeext}" 1>&6 ac_exeext=$EXEEXT #-------------------------------------------------------------------- # Check whether --enable-threads or --disable-threads was given. #-------------------------------------------------------------------- echo $ac_n "checking for building with threads""... $ac_c" 1>&6 echo "configure:1070: checking for building with threads" >&5 # Check whether --enable-threads or --disable-threads was given. if test "${enable_threads+set}" = set; then enableval="$enable_threads" tcl_ok=$enableval else tcl_ok=no fi if test "$tcl_ok" = "yes"; then echo "$ac_t""yes" 1>&6 TCL_THREADS=1 cat >> confdefs.h <<\EOF #define TCL_THREADS 1 EOF # USE_THREAD_ALLOC tells us to try the special thread-based # allocator that significantly reduces lock contention cat >> confdefs.h <<\EOF #define USE_THREAD_ALLOC 1 EOF else TCL_THREADS=0 echo "$ac_t""no (default)" 1>&6 fi #-------------------------------------------------------------------- # The statements below define a collection of symbols related to # building libtcl as a shared library instead of a static library. #-------------------------------------------------------------------- echo $ac_n "checking how to build libraries""... $ac_c" 1>&6 echo "configure:1107: checking how to build libraries" >&5 # Check whether --enable-shared or --disable-shared was given. if test "${enable_shared+set}" = set; then enableval="$enable_shared" tcl_ok=$enableval else tcl_ok=yes fi if test "${enable_shared+set}" = set; then enableval="$enable_shared" tcl_ok=$enableval else tcl_ok=yes fi if test "$tcl_ok" = "yes" ; then echo "$ac_t""shared" 1>&6 SHARED_BUILD=1 else echo "$ac_t""static" 1>&6 SHARED_BUILD=0 cat >> confdefs.h <<\EOF #define STATIC_BUILD 1 EOF fi #-------------------------------------------------------------------- # The statements below define a collection of compile flags. This # macro depends on the value of SHARED_BUILD, and should be called # after SC_ENABLE_SHARED checks the configure switches. #-------------------------------------------------------------------- # Step 0: Enable 64 bit support? echo $ac_n "checking if 64bit support is requested""... $ac_c" 1>&6 echo "configure:1148: checking if 64bit support is requested" >&5 # Check whether --enable-64bit or --disable-64bit was given. if test "${enable_64bit+set}" = set; then enableval="$enable_64bit" do64bit=$enableval else do64bit=no fi echo "$ac_t""$do64bit" 1>&6 # Cross-compiling options for Windows/CE builds echo $ac_n "checking if Windows/CE build is requested""... $ac_c" 1>&6 echo "configure:1162: checking if Windows/CE build is requested" >&5 # Check whether --enable-wince or --disable-wince was given. if test "${enable_wince+set}" = set; then enableval="$enable_wince" doWince=$enableval else doWince=no fi echo "$ac_t""$doWince" 1>&6 echo $ac_n "checking for Windows/CE celib directory""... $ac_c" 1>&6 echo "configure:1174: checking for Windows/CE celib directory" >&5 # Check whether --with-celib or --without-celib was given. if test "${with_celib+set}" = set; then withval="$with_celib" CELIB_DIR=$withval else CELIB_DIR=NO_CELIB fi echo "$ac_t""$CELIB_DIR" 1>&6 # Set some defaults (may get changed below) EXTRA_CFLAGS="" # Extract the first word of "cygpath", so it can be a program name with args. set dummy cygpath; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 echo "configure:1191: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CYGPATH'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$CYGPATH"; then ac_cv_prog_CYGPATH="$CYGPATH" # Let the user override the test. else IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" ac_dummy="$PATH" for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_prog_CYGPATH="cygpath -w" break fi done IFS="$ac_save_ifs" test -z "$ac_cv_prog_CYGPATH" && ac_cv_prog_CYGPATH="echo" fi fi CYGPATH="$ac_cv_prog_CYGPATH" if test -n "$CYGPATH"; then echo "$ac_t""$CYGPATH" 1>&6 else echo "$ac_t""no" 1>&6 fi SHLIB_SUFFIX=".dll" # MACHINE is IX86 for LINK, but this is used by the manifest, # which requires x86|amd64|ia64. MACHINE="X86" if test "$GCC" = "yes"; then echo $ac_n "checking for cross-compile version of gcc""... $ac_c" 1>&6 echo "configure:1228: checking for cross-compile version of gcc" >&5 if eval "test \"`echo '$''{'ac_cv_cross'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_cross=no else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* ac_cv_cross=yes fi rm -f conftest* fi echo "$ac_t""$ac_cv_cross" 1>&6 if test "$ac_cv_cross" = "yes"; then case "$do64bit" in amd64|x64|yes) CC="x86_64-w64-mingw32-gcc" LD="x86_64-w64-mingw32-ld" AR="x86_64-w64-mingw32-ar" RANLIB="x86_64-w64-mingw32-ranlib" RC="x86_64-w64-mingw32-windres" ;; *) CC="i686-w64-mingw32-gcc" LD="i686-w64-mingw32-ld" AR="i686-w64-mingw32-ar" RANLIB="i686-w64-mingw32-ranlib" RC="i686-w64-mingw32-windres" ;; esac fi fi # Check for a bug in gcc's windres that causes the # compile to fail when a Windows native path is # passed into windres. The mingw toolchain requires # Windows native paths while Cygwin should work # with both. Avoid the bug by passing a POSIX # path when using the Cygwin toolchain. if test "$GCC" = "yes" && test "$CYGPATH" != "echo" ; then conftest=/tmp/conftest.rc echo "STRINGTABLE BEGIN" > $conftest echo "101 \"name\"" >> $conftest echo "END" >> $conftest echo $ac_n "checking for Windows native path bug in windres""... $ac_c" 1>&6 echo "configure:1293: checking for Windows native path bug in windres" >&5 cyg_conftest=`$CYGPATH $conftest` if { ac_try='$RC -o conftest.res.o $cyg_conftest'; { (eval echo configure:1295: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } ; then echo "$ac_t""no" 1>&6 else echo "$ac_t""yes" 1>&6 CYGPATH=echo fi conftest= cyg_conftest= fi if test "$CYGPATH" = "echo"; then DEPARG='"$<"' else DEPARG='"$(shell $(CYGPATH) $<)"' fi # set various compiler flags depending on whether we are using gcc or cl if test "${GCC}" = "yes" ; then echo $ac_n "checking for mingw32 version of gcc""... $ac_c" 1>&6 echo "configure:1315: checking for mingw32 version of gcc" >&5 if eval "test \"`echo '$''{'ac_cv_win32'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_win32=no else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* ac_cv_win32=yes fi rm -f conftest* fi echo "$ac_t""$ac_cv_win32" 1>&6 if test "$ac_cv_win32" != "yes"; then { echo "configure: error: ${CC} cannot produce win32 executables." 1>&2; exit 1; } fi fi echo $ac_n "checking compiler flags""... $ac_c" 1>&6 echo "configure:1351: checking compiler flags" >&5 if test "${GCC}" = "yes" ; then SHLIB_LD="" SHLIB_LD_LIBS="" LIBS="" LIBS_GUI="-lgdi32 -lcomdlg32 -limm32 -lcomctl32 -lshell32" STLIB_LD='${AR} cr' RC_OUT=-o RC_TYPE= RC_INCLUDE=--include RC_DEFINE=--define RES=res.o MAKE_LIB="\${STLIB_LD} \$@" POST_MAKE_LIB="\${RANLIB} \$@" MAKE_EXE="\${CC} -o \$@" LIBPREFIX="lib" extra_cflags="-pipe" extra_ldflags="-pipe" if test "${SHARED_BUILD}" = "0" ; then # static echo "$ac_t""using static flags" 1>&6 runtime= MAKE_DLL="echo " LIBSUFFIX="s\${DBGX}.a" LIBFLAGSUFFIX="s\${DBGX}" LIBRARIES="\${STATIC_LIBRARIES}" EXESUFFIX="s\${DBGX}.exe" else # dynamic echo "$ac_t""using shared flags" 1>&6 # ad-hoc check to see if CC supports -shared. if "${CC}" -shared 2>&1 | egrep ': -shared not supported' >/dev/null; then { echo "configure: error: ${CC} does not support the -shared option. You will need to upgrade to a newer version of the toolchain." 1>&2; exit 1; } fi runtime= # Link with gcc since ld does not link to default libs like # -luser32 and -lmsvcrt by default. Make sure CFLAGS is # included so -mno-cygwin passed the correct libs to the linker. SHLIB_LD='${CC} -shared ${CFLAGS}' SHLIB_LD_LIBS='${LIBS}' # Add SHLIB_LD_LIBS to the Make rule, not here. MAKE_DLL="\${SHLIB_LD} \$(LDFLAGS) -o \$@ ${extra_ldflags} \ -Wl,--out-implib,\$(patsubst %.dll,lib%.a,\$@)" LIBSUFFIX="\${DBGX}.a" LIBFLAGSUFFIX="\${DBGX}" EXESUFFIX="\${DBGX}.exe" LIBRARIES="\${SHARED_LIBRARIES}" fi # DLLSUFFIX is separate because it is the building block for # users of tclConfig.sh that may build shared or static. DLLSUFFIX="\${DBGX}.dll" SHLIB_SUFFIX=.dll EXTRA_CFLAGS="${extra_cflags}" CFLAGS_DEBUG=-g CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" CFLAGS_WARNING="-Wall -fno-strict-aliasing" LDFLAGS_DEBUG= LDFLAGS_OPTIMIZE= # Specify the CC output file names based on the target name CC_OBJNAME="-o \$@" CC_EXENAME="-o \$@" # Specify linker flags depending on the type of app being # built -- Console vs. Window. # # ORIGINAL COMMENT: # We need to pass -e _WinMain@16 so that ld will use # WinMain() instead of main() as the entry point. We can't # use autoconf to check for this case since it would need # to run an executable and that does not work when # cross compiling. Remove this -e workaround once we # require a gcc that does not have this bug. # # MK NOTE: Tk should use a different mechanism. This causes # interesting problems, such as wish dying at startup. #LDFLAGS_WINDOW="-mwindows -e _WinMain@16 ${extra_ldflags}" LDFLAGS_CONSOLE="-mconsole ${extra_ldflags}" LDFLAGS_WINDOW="-mwindows ${extra_ldflags}" case "$do64bit" in amd64|x64|yes) MACHINE="AMD64" ; # assume AMD64 as default 64-bit build echo "$ac_t"" Using 64-bit $MACHINE mode" 1>&6 ;; ia64) MACHINE="IA64" echo "$ac_t"" Using 64-bit $MACHINE mode" 1>&6 ;; *) cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_win_64bit=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_win_64bit=no fi rm -f conftest* if test "$tcl_win_64bit" = "yes" ; then do64bit=amd64 MACHINE="AMD64" echo "$ac_t"" Using 64-bit $MACHINE mode" 1>&6 fi ;; esac else if test "${SHARED_BUILD}" = "0" ; then # static echo "$ac_t""using static flags" 1>&6 runtime=-MT MAKE_DLL="echo " LIBSUFFIX="s\${DBGX}.lib" LIBFLAGSUFFIX="s\${DBGX}" LIBRARIES="\${STATIC_LIBRARIES}" EXESUFFIX="s\${DBGX}.exe" SHLIB_LD_LIBS="" else # dynamic echo "$ac_t""using shared flags" 1>&6 runtime=-MD # Add SHLIB_LD_LIBS to the Make rule, not here. MAKE_DLL="\${SHLIB_LD} \$(LDFLAGS) -out:\$@" LIBSUFFIX="\${DBGX}.lib" LIBFLAGSUFFIX="\${DBGX}" EXESUFFIX="\${DBGX}.exe" LIBRARIES="\${SHARED_LIBRARIES}" SHLIB_LD_LIBS='${LIBS}' fi # DLLSUFFIX is separate because it is the building block for # users of tclConfig.sh that may build shared or static. DLLSUFFIX="\${DBGX}.dll" # This is a 2-stage check to make sure we have the 64-bit SDK # We have to know where the SDK is installed. # This magic is based on MS Platform SDK for Win2003 SP1 - hobbs if test "$do64bit" != "no" ; then if test "x${MSSDK}x" = "xx" ; then MSSDK="C:/Progra~1/Microsoft Platform SDK" fi MSSDK=`echo "$MSSDK" | sed -e 's!\\\!/!g'` PATH64="" case "$do64bit" in amd64|x64|yes) MACHINE="AMD64" ; # assume AMD64 as default 64-bit build PATH64="${MSSDK}/Bin/Win64/x86/AMD64" ;; ia64) MACHINE="IA64" PATH64="${MSSDK}/Bin/Win64" ;; esac if test ! -d "${PATH64}" ; then echo "configure: warning: Could not find 64-bit $MACHINE SDK to enable 64bit mode" 1>&2 echo "configure: warning: Ensure latest Platform SDK is installed" 1>&2 do64bit="no" else echo "$ac_t"" Using 64-bit $MACHINE mode" 1>&6 fi fi LIBS="user32.lib advapi32.lib" if test "$do64bit" != "no" ; then # The space-based-path will work for the Makefile, but will # not work if AC_TRY_COMPILE is called. TEA has the # TEA_PATH_NOSPACE to avoid this issue. CC="\"${PATH64}/cl.exe\" -I\"${MSSDK}/Include\" \ -I\"${MSSDK}/Include/crt\" -I\"${MSSDK}/Include/crt/sys\"" RC="\"${MSSDK}/bin/rc.exe\"" CFLAGS_DEBUG="-nologo -Zi -Od ${runtime}d" # Do not use -O2 for Win64 - this has proved buggy in code gen. CFLAGS_OPTIMIZE="-nologo -O1 ${runtime}" lflags="-nologo -MACHINE:${MACHINE} -LIBPATH:\"${MSSDK}/Lib/${MACHINE}\"" LINKBIN="\"${PATH64}/link.exe\"" # Avoid 'unresolved external symbol __security_cookie' errors. # c.f. http://support.microsoft.com/?id=894573 LIBS="$LIBS bufferoverflowU.lib" else RC="rc" # -Od - no optimization # -WX - warnings as errors CFLAGS_DEBUG="-nologo -Z7 -Od -WX ${runtime}d" # -O2 - create fast code (/Og /Oi /Ot /Oy /Ob2 /Gs /GF /Gy) CFLAGS_OPTIMIZE="-nologo -O2 ${runtime}" lflags="-nologo" LINKBIN="link" fi if test "$doWince" != "no" ; then # Set defaults for common evc4/PPC2003 setup # Currently Tcl requires 300+, possibly 420+ for sockets CEVERSION=420; # could be 211 300 301 400 420 ... TARGETCPU=ARMV4; # could be ARMV4 ARM MIPS SH3 X86 ... ARCH=ARM; # could be ARM MIPS X86EM ... PLATFORM="Pocket PC 2003"; # or "Pocket PC 2002" if test "$doWince" != "yes"; then # If !yes then the user specified something # Reset ARCH to allow user to skip specifying it ARCH= eval `echo $doWince | awk -F "," '{ \ if (length($1)) { printf "CEVERSION=\"%s\"\n", $1; \ if ($1 < 400) { printf "PLATFORM=\"Pocket PC 2002\"\n" } }; \ if (length($2)) { printf "TARGETCPU=\"%s\"\n", toupper($2) }; \ if (length($3)) { printf "ARCH=\"%s\"\n", toupper($3) }; \ if (length($4)) { printf "PLATFORM=\"%s\"\n", $4 }; \ }'` if test "x${ARCH}" = "x" ; then ARCH=$TARGETCPU; fi fi OSVERSION=WCE$CEVERSION; if test "x${WCEROOT}" = "x" ; then WCEROOT="C:/Program Files/Microsoft eMbedded C++ 4.0" if test ! -d "${WCEROOT}" ; then WCEROOT="C:/Program Files/Microsoft eMbedded Tools" fi fi if test "x${SDKROOT}" = "x" ; then SDKROOT="C:/Program Files/Windows CE Tools" if test ! -d "${SDKROOT}" ; then SDKROOT="C:/Windows CE Tools" fi fi # The space-based-path will work for the Makefile, but will # not work if AC_TRY_COMPILE is called. WCEROOT=`echo "$WCEROOT" | sed -e 's!\\\!/!g'` SDKROOT=`echo "$SDKROOT" | sed -e 's!\\\!/!g'` CELIB_DIR=`echo "$CELIB_DIR" | sed -e 's!\\\!/!g'` if test ! -d "${CELIB_DIR}/inc"; then { echo "configure: error: Invalid celib directory "${CELIB_DIR}"" 1>&2; exit 1; } fi if test ! -d "${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}"\ -o ! -d "${WCEROOT}/EVC/${OSVERSION}/bin"; then { echo "configure: error: could not find PocketPC SDK or target compiler to enable WinCE mode $CEVERSION,$TARGETCPU,$ARCH,$PLATFORM" 1>&2; exit 1; } else CEINCLUDE="${SDKROOT}/${OSVERSION}/${PLATFORM}/include" if test -d "${CEINCLUDE}/${TARGETCPU}" ; then CEINCLUDE="${CEINCLUDE}/${TARGETCPU}" fi CELIBPATH="${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" fi fi if test "$doWince" != "no" ; then CEBINROOT="${WCEROOT}/EVC/${OSVERSION}/bin" if test "${TARGETCPU}" = "X86"; then CC="${CEBINROOT}/cl.exe" else CC="${CEBINROOT}/cl${ARCH}.exe" fi CC="\"${CC}\" -I\"${CELIB_DIR}/inc\" -I\"${CEINCLUDE}\"" RC="\"${WCEROOT}/Common/EVC/bin/rc.exe\"" arch=`echo ${ARCH} | awk '{print tolower($0)}'` defs="${ARCH} _${ARCH}_ ${arch} PALM_SIZE _MT _DLL _WINDOWS" for i in $defs ; do cat >> confdefs.h <> confdefs.h <> confdefs.h <&6 echo "configure:1701: checking for SEH support in compiler" >&5 if eval "test \"`echo '$''{'tcl_cv_seh'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$cross_compiling" = yes; then tcl_cv_seh=no else cat > conftest.$ac_ext < #undef WIN32_LEAN_AND_MEAN int main(int argc, char** argv) { int a, b = 0; __try { a = 666 / b; } __except (EXCEPTION_EXECUTE_HANDLER) { return 0; } return 1; } EOF if { (eval echo configure:1728: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then tcl_cv_seh=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -fr conftest* tcl_cv_seh=no fi rm -fr conftest* fi fi echo "$ac_t""$tcl_cv_seh" 1>&6 if test "$tcl_cv_seh" = "no" ; then cat >> confdefs.h <<\EOF #define HAVE_NO_SEH 1 EOF fi # # Check to see if the excpt.h include file provided contains the # definition for EXCEPTION_DISPOSITION; if not, which is the case # with Cygwin's version as of 2002-04-10, define it to be int, # sufficient for getting the current code to work. # echo $ac_n "checking for EXCEPTION_DISPOSITION support in include files""... $ac_c" 1>&6 echo "configure:1758: checking for EXCEPTION_DISPOSITION support in include files" >&5 if eval "test \"`echo '$''{'tcl_cv_eh_disposition'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < # undef WIN32_LEAN_AND_MEAN int main() { EXCEPTION_DISPOSITION x; ; return 0; } EOF if { (eval echo configure:1776: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_cv_eh_disposition=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_eh_disposition=no fi rm -f conftest* fi echo "$ac_t""$tcl_cv_eh_disposition" 1>&6 if test "$tcl_cv_eh_disposition" = "no" ; then cat >> confdefs.h <<\EOF #define EXCEPTION_DISPOSITION int EOF fi # Check to see if winnt.h defines CHAR, SHORT, and LONG # even if VOID has already been #defined. The win32api # used by mingw and cygwin is known to do this. echo $ac_n "checking for winnt.h that ignores VOID define""... $ac_c" 1>&6 echo "configure:1802: checking for winnt.h that ignores VOID define" >&5 if eval "test \"`echo '$''{'tcl_cv_winnt_ignore_void'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #undef WIN32_LEAN_AND_MEAN int main() { CHAR c; SHORT s; LONG l; ; return 0; } EOF if { (eval echo configure:1823: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_cv_winnt_ignore_void=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_winnt_ignore_void=no fi rm -f conftest* fi echo "$ac_t""$tcl_cv_winnt_ignore_void" 1>&6 if test "$tcl_cv_winnt_ignore_void" = "yes" ; then cat >> confdefs.h <<\EOF #define HAVE_WINNT_IGNORE_VOID 1 EOF fi # See if the compiler supports casting to a union type. # This is used to stop gcc from printing a compiler # warning when initializing a union member. echo $ac_n "checking for cast to union support""... $ac_c" 1>&6 echo "configure:1849: checking for cast to union support" >&5 if eval "test \"`echo '$''{'tcl_cv_cast_to_union'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_cv_cast_to_union=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_cast_to_union=no fi rm -f conftest* fi echo "$ac_t""$tcl_cv_cast_to_union" 1>&6 if test "$tcl_cv_cast_to_union" = "yes"; then cat >> confdefs.h <<\EOF #define HAVE_CAST_TO_UNION 1 EOF fi fi # DL_LIBS is empty, but then we match the Unix version #-------------------------------------------------------------------- # Perform additinal compiler tests. #-------------------------------------------------------------------- if test "${GCC}" = "yes" ; then # Check to see if the winsock2.h include file provided contains # typedefs like LPFN_ACCEPT and friends. # echo $ac_n "checking for LPFN_ACCEPT support in winsock2.h""... $ac_c" 1>&6 echo "configure:1902: checking for LPFN_ACCEPT support in winsock2.h" >&5 if eval "test \"`echo '$''{'tcl_cv_lpfn_decls'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #undef WIN32_LEAN_AND_MEAN #include int main() { LPFN_ACCEPT accept; ; return 0; } EOF if { (eval echo configure:1922: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_cv_lpfn_decls=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_lpfn_decls=no fi rm -f conftest* fi echo "$ac_t""$tcl_cv_lpfn_decls" 1>&6 if test "$tcl_cv_lpfn_decls" = "no" ; then cat >> confdefs.h <<\EOF #define HAVE_NO_LPFN_DECLS 1 EOF fi # Check to see if malloc.h is missing the alloca function # declaration. This is known to be a problem with Mingw. # If we compiled without the function declaration, it # would work but we would get a warning message from gcc. # If we add the function declaration ourselves, it # would not compile correctly because the _alloca # function expects the argument to be passed in a # register and not on the stack. Instead, we just # call it from inline asm code. echo $ac_n "checking for alloca declaration in malloc.h""... $ac_c" 1>&6 echo "configure:1954: checking for alloca declaration in malloc.h" >&5 if eval "test \"`echo '$''{'tcl_cv_malloc_decl_alloca'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { size_t arg = 0; void* ptr; ptr = alloca; ptr = alloca(arg); ; return 0; } EOF if { (eval echo configure:1973: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* tcl_cv_malloc_decl_alloca=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* tcl_cv_malloc_decl_alloca=no fi rm -f conftest* fi echo "$ac_t""$tcl_cv_malloc_decl_alloca" 1>&6 if test "$tcl_cv_malloc_decl_alloca" = "no" && test "${GCC}" = "yes" ; then cat >> confdefs.h <<\EOF #define HAVE_ALLOCA_GCC_INLINE 1 EOF fi fi #-------------------------------------------------------------------- # Set the default compiler switches based on the --enable-symbols # option. This macro depends on C flags, and should be called # after SC_CONFIG_CFLAGS macro is called. #-------------------------------------------------------------------- echo $ac_n "checking for build with symbols""... $ac_c" 1>&6 echo "configure:2004: checking for build with symbols" >&5 # Check whether --enable-symbols or --disable-symbols was given. if test "${enable_symbols+set}" = set; then enableval="$enable_symbols" tcl_ok=$enableval else tcl_ok=no fi # FIXME: Currently, LDFLAGS_DEFAULT is not used, it should work like CFLAGS_DEFAULT. if test "$tcl_ok" = "no"; then CFLAGS_DEFAULT='$(CFLAGS_OPTIMIZE)' LDFLAGS_DEFAULT='$(LDFLAGS_OPTIMIZE)' DBGX="" cat >> confdefs.h <<\EOF #define NDEBUG 1 EOF echo "$ac_t""no" 1>&6 else CFLAGS_DEFAULT='$(CFLAGS_DEBUG)' LDFLAGS_DEFAULT='$(LDFLAGS_DEBUG)' DBGX=g if test "$tcl_ok" = "yes"; then echo "$ac_t""yes (standard debugging)" 1>&6 fi fi if test "$tcl_ok" = "mem" -o "$tcl_ok" = "all"; then cat >> confdefs.h <<\EOF #define TCL_MEM_DEBUG 1 EOF fi if test "$tcl_ok" = "compile" -o "$tcl_ok" = "all"; then cat >> confdefs.h <<\EOF #define TCL_COMPILE_DEBUG 1 EOF cat >> confdefs.h <<\EOF #define TCL_COMPILE_STATS 1 EOF fi if test "$tcl_ok" != "yes" -a "$tcl_ok" != "no"; then if test "$tcl_ok" = "all"; then echo "$ac_t""enabled symbols mem compile debugging" 1>&6 else echo "$ac_t""enabled $tcl_ok debugging" 1>&6 fi fi TCL_DBGX=${DBGX} #-------------------------------------------------------------------- # man2tcl needs this so that it can use errno.h #-------------------------------------------------------------------- echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 echo "configure:2068: checking how to run the C preprocessor" >&5 # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else # This must be in double quotes, not single quotes, because CPP may get # substituted into the Makefile and "${CC-cc}" will confuse make. CPP="${CC-cc} -E" # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. cat > conftest.$ac_ext < Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:2089: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* CPP="${CC-cc} -E -traditional-cpp" cat > conftest.$ac_ext < Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:2106: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* CPP="${CC-cc} -nologo -E" cat > conftest.$ac_ext < Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:2123: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* CPP=/lib/cpp fi rm -f conftest* fi rm -f conftest* fi rm -f conftest* ac_cv_prog_CPP="$CPP" fi CPP="$ac_cv_prog_CPP" else ac_cv_prog_CPP="$CPP" fi echo "$ac_t""$CPP" 1>&6 ac_safe=`echo "errno.h" | sed 'y%./+-%__p_%'` echo $ac_n "checking for errno.h""... $ac_c" 1>&6 echo "configure:2149: checking for errno.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" { (eval echo configure:2159: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 : else echo "$ac_t""no" 1>&6 MAN2TCLFLAGS="-DNO_ERRNO_H" fi #------------------------------------------------------------------------ # tclConfig.sh refers to this by a different name #------------------------------------------------------------------------ TCL_SHARED_BUILD=${SHARED_BUILD} #-------------------------------------------------------------------- # Perform final evaluations of variables with possible substitutions. #-------------------------------------------------------------------- TCL_SHARED_LIB_SUFFIX="\${NODOT_VERSION}${DLLSUFFIX}" TCL_UNSHARED_LIB_SUFFIX="\${NODOT_VERSION}${LIBSUFFIX}" TCL_EXPORT_FILE_SUFFIX="\${NODOT_VERSION}${LIBSUFFIX}" eval "TCL_SRC_DIR=\"`cd $srcdir/..; pwd`\"" eval "TCL_DLL_FILE=tcl${VER}${DLLSUFFIX}" eval "TCL_LIB_FILE=${LIBPREFIX}tcl$VER${LIBSUFFIX}" eval "TCL_LIB_FLAG=\"-ltcl${VER}${LIBFLAGSUFFIX}\"" eval "TCL_BUILD_LIB_SPEC=\"-L`pwd` ${TCL_LIB_FLAG}\"" eval "TCL_LIB_SPEC=\"-L${libdir} ${TCL_LIB_FLAG}\"" eval "TCL_STUB_LIB_FILE=\"${LIBPREFIX}tclstub${VER}${LIBSUFFIX}\"" eval "TCL_STUB_LIB_FLAG=\"-ltclstub${VER}${LIBFLAGSUFFIX}\"" eval "TCL_BUILD_STUB_LIB_SPEC=\"-L`pwd` ${TCL_STUB_LIB_FLAG}\"" eval "TCL_STUB_LIB_SPEC=\"-L${libdir} ${TCL_STUB_LIB_FLAG}\"" eval "TCL_BUILD_STUB_LIB_PATH=\"`pwd`/${TCL_STUB_LIB_FILE}\"" eval "TCL_STUB_LIB_PATH=\"${libdir}/${TCL_STUB_LIB_FILE}\"" # Install time header dir can be set via --includedir eval "TCL_INCLUDE_SPEC=\"-I${includedir}\"" eval "DLLSUFFIX=${DLLSUFFIX}" eval "LIBPREFIX=${LIBPREFIX}" eval "LIBSUFFIX=${LIBSUFFIX}" eval "EXESUFFIX=${EXESUFFIX}" CFG_TCL_SHARED_LIB_SUFFIX=${TCL_SHARED_LIB_SUFFIX} CFG_TCL_UNSHARED_LIB_SUFFIX=${TCL_UNSHARED_LIB_SUFFIX} CFG_TCL_EXPORT_FILE_SUFFIX=${TCL_EXPORT_FILE_SUFFIX} #-------------------------------------------------------------------- # Adjust the defines for how the resources are built depending # on symbols and static vs. shared. #-------------------------------------------------------------------- if test ${SHARED_BUILD} = 0 ; then if test "${DBGX}" = "g"; then RC_DEFINES="${RC_DEFINE} STATIC_BUILD ${RC_DEFINE} DEBUG" else RC_DEFINES="${RC_DEFINE} STATIC_BUILD" fi else if test "${DBGX}" = "g"; then RC_DEFINES="${RC_DEFINE} DEBUG" else RC_DEFINES="" fi fi #-------------------------------------------------------------------- # The statements below define the symbol TCL_PACKAGE_PATH, which # gives a list of directories that may contain packages. The list # consists of one directory for machine-dependent binaries and # another for platform-independent scripts. #-------------------------------------------------------------------- if test "$prefix/lib" != "$libdir"; then TCL_PACKAGE_PATH="${libdir} ${prefix}/lib" else TCL_PACKAGE_PATH="${prefix}/lib" fi # empty on win # win/tcl.m4 doesn't set (CFLAGS) # win/tcl.m4 doesn't set (LDFLAGS) # empty on win, but needs sub'ing # win only trap '' 1 2 15 cat > confcache <<\EOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs. It is not useful on other systems. # If it contains results you don't want to keep, you may remove or edit it. # # By default, configure uses ./config.cache as the cache file, # creating it if it does not exist already. You can give configure # the --cache-file=FILE option to use a different cache file; that is # what configure does when it calls configure scripts in # subdirectories, so they share the cache. # Giving --cache-file=/dev/null disables caching, for debugging configure. # config.status only pays attention to the cache file if you give it the # --recheck option to rerun configure. # EOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, don't put newlines in cache variables' values. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. (set) 2>&1 | case `(ac_space=' '; set | grep ac_space) 2>&1` in *ac_space=\ *) # `set' does not quote correctly, so add quotes (double-quote substitution # turns \\\\ into \\, and sed turns \\ into \). sed -n \ -e "s/'/'\\\\''/g" \ -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" ;; *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' ;; esac >> confcache if cmp -s $cache_file confcache; then : else if test -w $cache_file; then echo "updating cache $cache_file" cat confcache > $cache_file else echo "not updating unwritable cache $cache_file" fi fi rm -f confcache trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Any assignment to VPATH causes Sun make to only execute # the first set of double-colon rules, so remove it if not needed. # If there is a colon in the path, we need to keep it. if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' fi trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. # # If the first sed substitution is executed (which looks for macros that # take arguments), then we branch to the quote section. Otherwise, # look for a macro that doesn't take arguments. cat >confdef2opt.sed <<\_ACEOF t clear : clear s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\),-D\1=\2,g t quote s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\),-D\1=\2,g t quote d : quote s,[ `~#$^&*(){}\\|;'"<>?],\\&,g s,\[,\\&,g s,\],\\&,g s,\$,$$,g p _ACEOF # We use echo to avoid assuming a particular line-breaking character. # The extra dot is to prevent the shell from consuming trailing # line-breaks from the sub-command output. A line-break within # single-quotes doesn't work because, if this script is created in a # platform that uses two characters for line-breaks (e.g., DOS), tr # would break. ac_LF_and_DOT=`echo; echo .` DEFS=`sed -n -f confdef2opt.sed confdefs.h | tr "$ac_LF_and_DOT" ' .'` rm -f confdef2opt.sed # Without the "./", some shells look in PATH for config.status. : ${CONFIG_STATUS=./config.status} echo creating $CONFIG_STATUS rm -f $CONFIG_STATUS cat > $CONFIG_STATUS </dev/null | sed 1q`: # # $0 $ac_configure_args # # Compiler output produced by configure, useful for debugging # configure, is in ./config.log if it exists. ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" for ac_option do case "\$ac_option" in -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; -version | --version | --versio | --versi | --vers | --ver | --ve | --v) echo "$CONFIG_STATUS generated by autoconf version 2.13" exit 0 ;; -help | --help | --hel | --he | --h) echo "\$ac_cs_usage"; exit 0 ;; *) echo "\$ac_cs_usage"; exit 1 ;; esac done ac_given_srcdir=$srcdir trap 'rm -fr `echo "Makefile tclConfig.sh tcl.hpj" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 EOF cat >> $CONFIG_STATUS < conftest.subs <<\\CEOF $ac_vpsub $extrasub s%@SHELL@%$SHELL%g s%@CFLAGS@%$CFLAGS%g s%@CPPFLAGS@%$CPPFLAGS%g s%@CXXFLAGS@%$CXXFLAGS%g s%@FFLAGS@%$FFLAGS%g s%@DEFS@%$DEFS%g s%@LDFLAGS@%$LDFLAGS%g s%@LIBS@%$LIBS%g s%@exec_prefix@%$exec_prefix%g s%@prefix@%$prefix%g s%@program_transform_name@%$program_transform_name%g s%@bindir@%$bindir%g s%@sbindir@%$sbindir%g s%@libexecdir@%$libexecdir%g s%@datadir@%$datadir%g s%@sysconfdir@%$sysconfdir%g s%@sharedstatedir@%$sharedstatedir%g s%@localstatedir@%$localstatedir%g s%@libdir@%$libdir%g s%@includedir@%$includedir%g s%@oldincludedir@%$oldincludedir%g s%@infodir@%$infodir%g s%@mandir@%$mandir%g s%@CC@%$CC%g s%@AR@%$AR%g s%@RANLIB@%$RANLIB%g s%@RC@%$RC%g s%@SET_MAKE@%$SET_MAKE%g s%@OBJEXT@%$OBJEXT%g s%@EXEEXT@%$EXEEXT%g s%@TCL_THREADS@%$TCL_THREADS%g s%@CYGPATH@%$CYGPATH%g s%@CELIB_DIR@%$CELIB_DIR%g s%@DL_LIBS@%$DL_LIBS%g s%@CFLAGS_DEBUG@%$CFLAGS_DEBUG%g s%@CFLAGS_OPTIMIZE@%$CFLAGS_OPTIMIZE%g s%@CFLAGS_WARNING@%$CFLAGS_WARNING%g s%@CFLAGS_DEFAULT@%$CFLAGS_DEFAULT%g s%@LDFLAGS_DEFAULT@%$LDFLAGS_DEFAULT%g s%@CPP@%$CPP%g s%@MAN2TCLFLAGS@%$MAN2TCLFLAGS%g s%@TCL_VERSION@%$TCL_VERSION%g s%@TCL_MAJOR_VERSION@%$TCL_MAJOR_VERSION%g s%@TCL_MINOR_VERSION@%$TCL_MINOR_VERSION%g s%@TCL_PATCH_LEVEL@%$TCL_PATCH_LEVEL%g s%@TCL_LIB_FILE@%$TCL_LIB_FILE%g s%@TCL_LIB_FLAG@%$TCL_LIB_FLAG%g s%@TCL_LIB_SPEC@%$TCL_LIB_SPEC%g s%@TCL_STUB_LIB_FILE@%$TCL_STUB_LIB_FILE%g s%@TCL_STUB_LIB_FLAG@%$TCL_STUB_LIB_FLAG%g s%@TCL_STUB_LIB_SPEC@%$TCL_STUB_LIB_SPEC%g s%@TCL_STUB_LIB_PATH@%$TCL_STUB_LIB_PATH%g s%@TCL_INCLUDE_SPEC@%$TCL_INCLUDE_SPEC%g s%@TCL_BUILD_STUB_LIB_SPEC@%$TCL_BUILD_STUB_LIB_SPEC%g s%@TCL_BUILD_STUB_LIB_PATH@%$TCL_BUILD_STUB_LIB_PATH%g s%@TCL_DLL_FILE@%$TCL_DLL_FILE%g s%@TCL_SRC_DIR@%$TCL_SRC_DIR%g s%@TCL_BIN_DIR@%$TCL_BIN_DIR%g s%@TCL_DBGX@%$TCL_DBGX%g s%@CFG_TCL_SHARED_LIB_SUFFIX@%$CFG_TCL_SHARED_LIB_SUFFIX%g s%@CFG_TCL_UNSHARED_LIB_SUFFIX@%$CFG_TCL_UNSHARED_LIB_SUFFIX%g s%@CFG_TCL_EXPORT_FILE_SUFFIX@%$CFG_TCL_EXPORT_FILE_SUFFIX%g s%@EXTRA_CFLAGS@%$EXTRA_CFLAGS%g s%@DEPARG@%$DEPARG%g s%@CC_OBJNAME@%$CC_OBJNAME%g s%@CC_EXENAME@%$CC_EXENAME%g s%@LDFLAGS_DEBUG@%$LDFLAGS_DEBUG%g s%@LDFLAGS_OPTIMIZE@%$LDFLAGS_OPTIMIZE%g s%@LDFLAGS_CONSOLE@%$LDFLAGS_CONSOLE%g s%@LDFLAGS_WINDOW@%$LDFLAGS_WINDOW%g s%@STLIB_LD@%$STLIB_LD%g s%@SHLIB_LD@%$SHLIB_LD%g s%@SHLIB_LD_LIBS@%$SHLIB_LD_LIBS%g s%@SHLIB_CFLAGS@%$SHLIB_CFLAGS%g s%@SHLIB_SUFFIX@%$SHLIB_SUFFIX%g s%@TCL_SHARED_BUILD@%$TCL_SHARED_BUILD%g s%@LIBS_GUI@%$LIBS_GUI%g s%@DLLSUFFIX@%$DLLSUFFIX%g s%@LIBPREFIX@%$LIBPREFIX%g s%@LIBSUFFIX@%$LIBSUFFIX%g s%@EXESUFFIX@%$EXESUFFIX%g s%@LIBRARIES@%$LIBRARIES%g s%@MAKE_LIB@%$MAKE_LIB%g s%@POST_MAKE_LIB@%$POST_MAKE_LIB%g s%@MAKE_DLL@%$MAKE_DLL%g s%@MAKE_EXE@%$MAKE_EXE%g s%@TCL_BUILD_LIB_SPEC@%$TCL_BUILD_LIB_SPEC%g s%@TCL_LD_SEARCH_FLAGS@%$TCL_LD_SEARCH_FLAGS%g s%@TCL_NEEDS_EXP_FILE@%$TCL_NEEDS_EXP_FILE%g s%@TCL_BUILD_EXP_FILE@%$TCL_BUILD_EXP_FILE%g s%@TCL_EXP_FILE@%$TCL_EXP_FILE%g s%@LIBOBJS@%$LIBOBJS%g s%@TCL_LIB_VERSIONS_OK@%$TCL_LIB_VERSIONS_OK%g s%@TCL_PACKAGE_PATH@%$TCL_PACKAGE_PATH%g s%@TCL_DDE_VERSION@%$TCL_DDE_VERSION%g s%@TCL_DDE_MAJOR_VERSION@%$TCL_DDE_MAJOR_VERSION%g s%@TCL_DDE_MINOR_VERSION@%$TCL_DDE_MINOR_VERSION%g s%@TCL_REG_VERSION@%$TCL_REG_VERSION%g s%@TCL_REG_MAJOR_VERSION@%$TCL_REG_MAJOR_VERSION%g s%@TCL_REG_MINOR_VERSION@%$TCL_REG_MINOR_VERSION%g s%@RC_OUT@%$RC_OUT%g s%@RC_TYPE@%$RC_TYPE%g s%@RC_INCLUDE@%$RC_INCLUDE%g s%@RC_DEFINE@%$RC_DEFINE%g s%@RC_DEFINES@%$RC_DEFINES%g s%@RES@%$RES%g CEOF EOF cat >> $CONFIG_STATUS <<\EOF # Split the substitutions into bite-sized pieces for seds with # small command number limits, like on Digital OSF/1 and HP-UX. ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. ac_file=1 # Number of current file. ac_beg=1 # First line for current file. ac_end=$ac_max_sed_cmds # Line after last line for current file. ac_more_lines=: ac_sed_cmds="" while $ac_more_lines; do if test $ac_beg -gt 1; then sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file else sed "${ac_end}q" conftest.subs > conftest.s$ac_file fi if test ! -s conftest.s$ac_file; then ac_more_lines=false rm -f conftest.s$ac_file else if test -z "$ac_sed_cmds"; then ac_sed_cmds="sed -f conftest.s$ac_file" else ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" fi ac_file=`expr $ac_file + 1` ac_beg=$ac_end ac_end=`expr $ac_end + $ac_max_sed_cmds` fi done if test -z "$ac_sed_cmds"; then ac_sed_cmds=cat fi EOF cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". case "$ac_file" in *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; *) ac_file_in="${ac_file}.in" ;; esac # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. # Remove last slash and all that follows it. Not all systems have dirname. ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then # The file is in a subdirectory. test ! -d "$ac_dir" && mkdir "$ac_dir" ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" # A "../" for each directory in $ac_dir_suffix. ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` else ac_dir_suffix= ac_dots= fi case "$ac_given_srcdir" in .) srcdir=. if test -z "$ac_dots"; then top_srcdir=. else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; *) # Relative path. srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" top_srcdir="$ac_dots$ac_given_srcdir" ;; esac echo creating "$ac_file" rm -f "$ac_file" configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." case "$ac_file" in *Makefile*) ac_comsub="1i\\ # $configure_input" ;; *) ac_comsub= ;; esac ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` sed -e "$ac_comsub s%@configure_input@%$configure_input%g s%@srcdir@%$srcdir%g s%@top_srcdir@%$top_srcdir%g " $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file fi; done rm -f conftest.s* EOF cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF exit 0 EOF chmod +x $CONFIG_STATUS rm -fr confdefs* $ac_clean_files test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 tcl8.4.20/win/tcl.dsp0000644003604700454610000007077312153151143013006 0ustar dgp771div# Microsoft Developer Studio Project File - Name="tcl" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) External Target" 0x0106 CFG=tcl - Win32 Debug Static !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "tcl.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "tcl.mak" CFG="tcl - Win32 Debug Static" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "tcl - Win32 Release" (based on "Win32 (x86) External Target") !MESSAGE "tcl - Win32 Debug" (based on "Win32 (x86) External Target") !MESSAGE "tcl - Win32 Debug Static" (based on "Win32 (x86) External Target") !MESSAGE "tcl - Win32 Release Static" (based on "Win32 (x86) External Target") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" !IF "$(CFG)" == "tcl - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release\tcl_Dynamic" # PROP BASE Cmd_Line "nmake -nologo -f makefile.vc OPTS=none MSVCDIR=IDE" # PROP BASE Rebuild_Opt "-a" # PROP BASE Target_File "Release\tclsh84.exe" # PROP BASE Bsc_Name "" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release\tcl_Dynamic" # PROP Cmd_Line "nmake -nologo -f makefile.vc OPTS=none MSVCDIR=IDE" # PROP Rebuild_Opt "-a" # PROP Target_File "Release\tclsh84.exe" # PROP Bsc_Name "" # PROP Target_Dir "" !ELSEIF "$(CFG)" == "tcl - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug\tcl_Dynamic" # PROP BASE Cmd_Line "nmake -nologo -f makefile.vc OPTS=symbols MSVCDIR=IDE" # PROP BASE Rebuild_Opt "-a" # PROP BASE Target_File "Debug\tclsh84d.exe" # PROP BASE Bsc_Name "" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug\tcl_Dynamic" # PROP Cmd_Line "nmake -nologo -f makefile.vc OPTS=symbols MSVCDIR=IDE" # PROP Rebuild_Opt "-a" # PROP Target_File "Debug\tclsh84d.exe" # PROP Bsc_Name "" # PROP Target_Dir "" !ELSEIF "$(CFG)" == "tcl - Win32 Debug Static" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug\tcl_Static" # PROP BASE Cmd_Line "nmake -nologo -f makefile.vc OPTS=symbols,static MSVCDIR=IDE" # PROP BASE Rebuild_Opt "-a" # PROP BASE Target_File "Debug\tclsh84d.exe" # PROP BASE Bsc_Name "" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug\tcl_Static" # PROP Cmd_Line "nmake -nologo -f makefile.vc OPTS=symbols,static MSVCDIR=IDE" # PROP Rebuild_Opt "-a" # PROP Target_File "Debug\tclsh84sd.exe" # PROP Bsc_Name "" # PROP Target_Dir "" !ELSEIF "$(CFG)" == "tcl - Win32 Release Static" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release\tcl_Static" # PROP BASE Cmd_Line "nmake -nologo -f makefile.vc OPTS=static MSVCDIR=IDE" # PROP BASE Rebuild_Opt "-a" # PROP BASE Target_File "Release\tclsh84.exe" # PROP BASE Bsc_Name "" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release\tcl_Static" # PROP Cmd_Line "nmake -nologo -f makefile.vc OPTS=static MSVCDIR=IDE" # PROP Rebuild_Opt "-a" # PROP Target_File "Release\tclsh84s.exe" # PROP Bsc_Name "" # PROP Target_Dir "" !ENDIF # Begin Target # Name "tcl - Win32 Release" # Name "tcl - Win32 Debug" # Name "tcl - Win32 Debug Static" # Name "tcl - Win32 Release Static" !IF "$(CFG)" == "tcl - Win32 Release" !ELSEIF "$(CFG)" == "tcl - Win32 Debug" !ELSEIF "$(CFG)" == "tcl - Win32 Debug Static" !ELSEIF "$(CFG)" == "tcl - Win32 Release Static" !ENDIF # Begin Group "compat" # PROP Default_Filter "" # Begin Source File SOURCE=..\compat\dirent.h # End Source File # Begin Source File SOURCE=..\compat\dirent2.h # End Source File # Begin Source File SOURCE=..\compat\dlfcn.h # End Source File # Begin Source File SOURCE=..\compat\fixstrtod.c # End Source File # Begin Source File SOURCE=..\compat\float.h # End Source File # Begin Source File SOURCE=..\compat\gettod.c # End Source File # Begin Source File SOURCE=..\compat\limits.h # End Source File # Begin Source File SOURCE=..\compat\memcmp.c # End Source File # Begin Source File SOURCE=..\compat\opendir.c # End Source File # Begin Source File SOURCE=..\compat\README # End Source File # Begin Source File SOURCE=..\compat\stdlib.h # End Source File # Begin Source File SOURCE=..\compat\strftime.c # End Source File # Begin Source File SOURCE=..\compat\string.h # End Source File # Begin Source File SOURCE=..\compat\strncasecmp.c # End Source File # Begin Source File SOURCE=..\compat\strstr.c # End Source File # Begin Source File SOURCE=..\compat\strtod.c # End Source File # Begin Source File SOURCE=..\compat\strtol.c # End Source File # Begin Source File SOURCE=..\compat\strtoul.c # End Source File # Begin Source File SOURCE=..\compat\tclErrno.h # End Source File # Begin Source File SOURCE=..\compat\tmpnam.c # End Source File # Begin Source File SOURCE=..\compat\unistd.h # End Source File # Begin Source File SOURCE=..\compat\waitpid.c # End Source File # End Group # Begin Group "doc" # PROP Default_Filter "" # Begin Source File SOURCE=..\doc\Access.3 # End Source File # Begin Source File SOURCE=..\doc\AddErrInfo.3 # End Source File # Begin Source File SOURCE=..\doc\after.n # End Source File # Begin Source File SOURCE=..\doc\Alloc.3 # End Source File # Begin Source File SOURCE=..\doc\AllowExc.3 # End Source File # Begin Source File SOURCE=..\doc\append.n # End Source File # Begin Source File SOURCE=..\doc\AppInit.3 # End Source File # Begin Source File SOURCE=..\doc\array.n # End Source File # Begin Source File SOURCE=..\doc\AssocData.3 # End Source File # Begin Source File SOURCE=..\doc\Async.3 # End Source File # Begin Source File SOURCE=..\doc\BackgdErr.3 # End Source File # Begin Source File SOURCE=..\doc\Backslash.3 # End Source File # Begin Source File SOURCE=..\doc\bgerror.n # End Source File # Begin Source File SOURCE=..\doc\binary.n # End Source File # Begin Source File SOURCE=..\doc\BoolObj.3 # End Source File # Begin Source File SOURCE=..\doc\break.n # End Source File # Begin Source File SOURCE=..\doc\ByteArrObj.3 # End Source File # Begin Source File SOURCE=..\doc\CallDel.3 # End Source File # Begin Source File SOURCE=..\doc\case.n # End Source File # Begin Source File SOURCE=..\doc\catch.n # End Source File # Begin Source File SOURCE=..\doc\cd.n # End Source File # Begin Source File SOURCE=..\doc\ChnlStack.3 # End Source File # Begin Source File SOURCE=..\doc\clock.n # End Source File # Begin Source File SOURCE=..\doc\close.n # End Source File # Begin Source File SOURCE=..\doc\CmdCmplt.3 # End Source File # Begin Source File SOURCE=..\doc\Concat.3 # End Source File # Begin Source File SOURCE=..\doc\concat.n # End Source File # Begin Source File SOURCE=..\doc\continue.n # End Source File # Begin Source File SOURCE=..\doc\CrtChannel.3 # End Source File # Begin Source File SOURCE=..\doc\CrtChnlHdlr.3 # End Source File # Begin Source File SOURCE=..\doc\CrtCloseHdlr.3 # End Source File # Begin Source File SOURCE=..\doc\CrtCommand.3 # End Source File # Begin Source File SOURCE=..\doc\CrtFileHdlr.3 # End Source File # Begin Source File SOURCE=..\doc\CrtInterp.3 # End Source File # Begin Source File SOURCE=..\doc\CrtMathFnc.3 # End Source File # Begin Source File SOURCE=..\doc\CrtObjCmd.3 # End Source File # Begin Source File SOURCE=..\doc\CrtSlave.3 # End Source File # Begin Source File SOURCE=..\doc\CrtTimerHdlr.3 # End Source File # Begin Source File SOURCE=..\doc\CrtTrace.3 # End Source File # Begin Source File SOURCE=..\doc\dde.n # End Source File # Begin Source File SOURCE=..\doc\DetachPids.3 # End Source File # Begin Source File SOURCE=..\doc\DoOneEvent.3 # End Source File # Begin Source File SOURCE=..\doc\DoubleObj.3 # End Source File # Begin Source File SOURCE=..\doc\DoWhenIdle.3 # End Source File # Begin Source File SOURCE=..\doc\DString.3 # End Source File # Begin Source File SOURCE=..\doc\DumpActiveMemory.3 # End Source File # Begin Source File SOURCE=..\doc\Encoding.3 # End Source File # Begin Source File SOURCE=..\doc\encoding.n # End Source File # Begin Source File SOURCE=..\doc\Environment.3 # End Source File # Begin Source File SOURCE=..\doc\eof.n # End Source File # Begin Source File SOURCE=..\doc\error.n # End Source File # Begin Source File SOURCE=..\doc\Eval.3 # End Source File # Begin Source File SOURCE=..\doc\eval.n # End Source File # Begin Source File SOURCE=..\doc\exec.n # End Source File # Begin Source File SOURCE=..\doc\Exit.3 # End Source File # Begin Source File SOURCE=..\doc\exit.n # End Source File # Begin Source File SOURCE=..\doc\expr.n # End Source File # Begin Source File SOURCE=..\doc\ExprLong.3 # End Source File # Begin Source File SOURCE=..\doc\ExprLongObj.3 # End Source File # Begin Source File SOURCE=..\doc\fblocked.n # End Source File # Begin Source File SOURCE=..\doc\fconfigure.n # End Source File # Begin Source File SOURCE=..\doc\fcopy.n # End Source File # Begin Source File SOURCE=..\doc\file.n # End Source File # Begin Source File SOURCE=..\doc\fileevent.n # End Source File # Begin Source File SOURCE=..\doc\filename.n # End Source File # Begin Source File SOURCE=..\doc\FileSystem.3 # End Source File # Begin Source File SOURCE=..\doc\FindExec.3 # End Source File # Begin Source File SOURCE=..\doc\flush.n # End Source File # Begin Source File SOURCE=..\doc\for.n # End Source File # Begin Source File SOURCE=..\doc\foreach.n # End Source File # Begin Source File SOURCE=..\doc\format.n # End Source File # Begin Source File SOURCE=..\doc\GetCwd.3 # End Source File # Begin Source File SOURCE=..\doc\GetHostName.3 # End Source File # Begin Source File SOURCE=..\doc\GetIndex.3 # End Source File # Begin Source File SOURCE=..\doc\GetInt.3 # End Source File # Begin Source File SOURCE=..\doc\GetOpnFl.3 # End Source File # Begin Source File SOURCE=..\doc\gets.n # End Source File # Begin Source File SOURCE=..\doc\GetStdChan.3 # End Source File # Begin Source File SOURCE=..\doc\GetVersion.3 # End Source File # Begin Source File SOURCE=..\doc\glob.n # End Source File # Begin Source File SOURCE=..\doc\global.n # End Source File # Begin Source File SOURCE=..\doc\Hash.3 # End Source File # Begin Source File SOURCE=..\doc\history.n # End Source File # Begin Source File SOURCE=..\doc\http.n # End Source File # Begin Source File SOURCE=..\doc\if.n # End Source File # Begin Source File SOURCE=..\doc\incr.n # End Source File # Begin Source File SOURCE=..\doc\info.n # End Source File # Begin Source File SOURCE=..\doc\Init.3 # End Source File # Begin Source File SOURCE=..\doc\InitStubs.3 # End Source File # Begin Source File SOURCE=..\doc\Interp.3 # End Source File # Begin Source File SOURCE=..\doc\interp.n # End Source File # Begin Source File SOURCE=..\doc\IntObj.3 # End Source File # Begin Source File SOURCE=..\doc\join.n # End Source File # Begin Source File SOURCE=..\doc\lappend.n # End Source File # Begin Source File SOURCE=..\doc\library.n # End Source File # Begin Source File SOURCE=..\doc\lindex.n # End Source File # Begin Source File SOURCE=..\doc\LinkVar.3 # End Source File # Begin Source File SOURCE=..\doc\linsert.n # End Source File # Begin Source File SOURCE=..\doc\list.n # End Source File # Begin Source File SOURCE=..\doc\ListObj.3 # End Source File # Begin Source File SOURCE=..\doc\llength.n # End Source File # Begin Source File SOURCE=..\doc\load.n # End Source File # Begin Source File SOURCE=..\doc\lrange.n # End Source File # Begin Source File SOURCE=..\doc\lreplace.n # End Source File # Begin Source File SOURCE=..\doc\lsearch.n # End Source File # Begin Source File SOURCE=..\doc\lsort.n # End Source File # Begin Source File SOURCE=..\doc\man.macros # End Source File # Begin Source File SOURCE=..\doc\memory.n # End Source File # Begin Source File SOURCE=..\doc\msgcat.n # End Source File # Begin Source File SOURCE=..\doc\namespace.n # End Source File # Begin Source File SOURCE=..\doc\Notifier.3 # End Source File # Begin Source File SOURCE=..\doc\Object.3 # End Source File # Begin Source File SOURCE=..\doc\ObjectType.3 # End Source File # Begin Source File SOURCE=..\doc\open.n # End Source File # Begin Source File SOURCE=..\doc\OpenFileChnl.3 # End Source File # Begin Source File SOURCE=..\doc\OpenTcp.3 # End Source File # Begin Source File SOURCE=..\doc\package.n # End Source File # Begin Source File SOURCE=..\doc\packagens.n # End Source File # Begin Source File SOURCE=..\doc\Panic.3 # End Source File # Begin Source File SOURCE=..\doc\ParseCmd.3 # End Source File # Begin Source File SOURCE=..\doc\pid.n # End Source File # Begin Source File SOURCE=..\doc\pkgMkIndex.n # End Source File # Begin Source File SOURCE=..\doc\PkgRequire.3 # End Source File # Begin Source File SOURCE=..\doc\Preserve.3 # End Source File # Begin Source File SOURCE=..\doc\PrintDbl.3 # End Source File # Begin Source File SOURCE=..\doc\proc.n # End Source File # Begin Source File SOURCE=..\doc\puts.n # End Source File # Begin Source File SOURCE=..\doc\pwd.n # End Source File # Begin Source File SOURCE=..\doc\re_syntax.n # End Source File # Begin Source File SOURCE=..\doc\read.n # End Source File # Begin Source File SOURCE=..\doc\RecEvalObj.3 # End Source File # Begin Source File SOURCE=..\doc\RecordEval.3 # End Source File # Begin Source File SOURCE=..\doc\RegExp.3 # End Source File # Begin Source File SOURCE=..\doc\regexp.n # End Source File # Begin Source File SOURCE=..\doc\registry.n # End Source File # Begin Source File SOURCE=..\doc\regsub.n # End Source File # Begin Source File SOURCE=..\doc\rename.n # End Source File # Begin Source File SOURCE=..\doc\return.n # End Source File # Begin Source File SOURCE=..\doc\safe.n # End Source File # Begin Source File SOURCE=..\doc\SaveResult.3 # End Source File # Begin Source File SOURCE=..\doc\scan.n # End Source File # Begin Source File SOURCE=..\doc\seek.n # End Source File # Begin Source File SOURCE=..\doc\set.n # End Source File # Begin Source File SOURCE=..\doc\SetErrno.3 # End Source File # Begin Source File SOURCE=..\doc\SetRecLmt.3 # End Source File # Begin Source File SOURCE=..\doc\SetResult.3 # End Source File # Begin Source File SOURCE=..\doc\SetVar.3 # End Source File # Begin Source File SOURCE=..\doc\Signal.3 # End Source File # Begin Source File SOURCE=..\doc\Sleep.3 # End Source File # Begin Source File SOURCE=..\doc\socket.n # End Source File # Begin Source File SOURCE=..\doc\source.n # End Source File # Begin Source File SOURCE=..\doc\SourceRCFile.3 # End Source File # Begin Source File SOURCE=..\doc\split.n # End Source File # Begin Source File SOURCE=..\doc\SplitList.3 # End Source File # Begin Source File SOURCE=..\doc\SplitPath.3 # End Source File # Begin Source File SOURCE=..\doc\StaticPkg.3 # End Source File # Begin Source File SOURCE=..\doc\StdChannels.3 # End Source File # Begin Source File SOURCE=..\doc\string.n # End Source File # Begin Source File SOURCE=..\doc\StringObj.3 # End Source File # Begin Source File SOURCE=..\doc\StrMatch.3 # End Source File # Begin Source File SOURCE=..\doc\subst.n # End Source File # Begin Source File SOURCE=..\doc\SubstObj.3 # End Source File # Begin Source File SOURCE=..\doc\switch.n # End Source File # Begin Source File SOURCE=..\doc\Tcl.n # End Source File # Begin Source File SOURCE=..\doc\Tcl_Main.3 # End Source File # Begin Source File SOURCE=..\doc\TCL_MEM_DEBUG.3 # End Source File # Begin Source File SOURCE=..\doc\tclsh.1 # End Source File # Begin Source File SOURCE=..\doc\tcltest.n # End Source File # Begin Source File SOURCE=..\doc\tclvars.n # End Source File # Begin Source File SOURCE=..\doc\tell.n # End Source File # Begin Source File SOURCE=..\doc\Thread.3 # End Source File # Begin Source File SOURCE=..\doc\time.n # End Source File # Begin Source File SOURCE=..\doc\ToUpper.3 # End Source File # Begin Source File SOURCE=..\doc\trace.n # End Source File # Begin Source File SOURCE=..\doc\TraceVar.3 # End Source File # Begin Source File SOURCE=..\doc\Translate.3 # End Source File # Begin Source File SOURCE=..\doc\UniCharIsAlpha.3 # End Source File # Begin Source File SOURCE=..\doc\unknown.n # End Source File # Begin Source File SOURCE=..\doc\unset.n # End Source File # Begin Source File SOURCE=..\doc\update.n # End Source File # Begin Source File SOURCE=..\doc\uplevel.n # End Source File # Begin Source File SOURCE=..\doc\UpVar.3 # End Source File # Begin Source File SOURCE=..\doc\upvar.n # End Source File # Begin Source File SOURCE=..\doc\Utf.3 # End Source File # Begin Source File SOURCE=..\doc\variable.n # End Source File # Begin Source File SOURCE=..\doc\vwait.n # End Source File # Begin Source File SOURCE=..\doc\while.n # End Source File # Begin Source File SOURCE=..\doc\WrongNumArgs.3 # End Source File # End Group # Begin Group "generic" # PROP Default_Filter "" # Begin Source File SOURCE=..\generic\README # End Source File # Begin Source File SOURCE=..\generic\regc_color.c # End Source File # Begin Source File SOURCE=..\generic\regc_cvec.c # End Source File # Begin Source File SOURCE=..\generic\regc_lex.c # End Source File # Begin Source File SOURCE=..\generic\regc_locale.c # End Source File # Begin Source File SOURCE=..\generic\regc_nfa.c # End Source File # Begin Source File SOURCE=..\generic\regcomp.c # End Source File # Begin Source File SOURCE=..\generic\regcustom.h # End Source File # Begin Source File SOURCE=..\generic\rege_dfa.c # End Source File # Begin Source File SOURCE=..\generic\regerror.c # End Source File # Begin Source File SOURCE=..\generic\regerrs.h # End Source File # Begin Source File SOURCE=..\generic\regex.h # End Source File # Begin Source File SOURCE=..\generic\regexec.c # End Source File # Begin Source File SOURCE=..\generic\regfree.c # End Source File # Begin Source File SOURCE=..\generic\regfronts.c # End Source File # Begin Source File SOURCE=..\generic\regguts.h # End Source File # Begin Source File SOURCE=..\generic\tcl.decls # End Source File # Begin Source File SOURCE=..\generic\tcl.h # End Source File # Begin Source File SOURCE=..\generic\tclAlloc.c # End Source File # Begin Source File SOURCE=..\generic\tclAsync.c # End Source File # Begin Source File SOURCE=..\generic\tclBasic.c # End Source File # Begin Source File SOURCE=..\generic\tclBinary.c # End Source File # Begin Source File SOURCE=..\generic\tclCkalloc.c # End Source File # Begin Source File SOURCE=..\generic\tclClock.c # End Source File # Begin Source File SOURCE=..\generic\tclCmdAH.c # End Source File # Begin Source File SOURCE=..\generic\tclCmdIL.c # End Source File # Begin Source File SOURCE=..\generic\tclCmdMZ.c # End Source File # Begin Source File SOURCE=..\generic\tclCompCmds.c # End Source File # Begin Source File SOURCE=..\generic\tclCompExpr.c # End Source File # Begin Source File SOURCE=..\generic\tclCompile.c # End Source File # Begin Source File SOURCE=..\generic\tclCompile.h # End Source File # Begin Source File SOURCE=..\generic\tclDate.c # End Source File # Begin Source File SOURCE=..\generic\tclDecls.h # End Source File # Begin Source File SOURCE=..\generic\tclEncoding.c # End Source File # Begin Source File SOURCE=..\generic\tclEnv.c # End Source File # Begin Source File SOURCE=..\generic\tclEvent.c # End Source File # Begin Source File SOURCE=..\generic\tclExecute.c # End Source File # Begin Source File SOURCE=..\generic\tclFCmd.c # End Source File # Begin Source File SOURCE=..\generic\tclFileName.c # End Source File # Begin Source File SOURCE=..\generic\tclGet.c # End Source File # Begin Source File SOURCE=..\generic\tclGetDate.y # End Source File # Begin Source File SOURCE=..\generic\tclHash.c # End Source File # Begin Source File SOURCE=..\generic\tclHistory.c # End Source File # Begin Source File SOURCE=..\generic\tclIndexObj.c # End Source File # Begin Source File SOURCE=..\generic\tclInitScript.h # End Source File # Begin Source File SOURCE=..\generic\tclInt.decls # End Source File # Begin Source File SOURCE=..\generic\tclInt.h # End Source File # Begin Source File SOURCE=..\generic\tclIntDecls.h # End Source File # Begin Source File SOURCE=..\generic\tclInterp.c # End Source File # Begin Source File SOURCE=..\generic\tclIntPlatDecls.h # End Source File # Begin Source File SOURCE=..\generic\tclIO.c # End Source File # Begin Source File SOURCE=..\generic\tclIO.h # End Source File # Begin Source File SOURCE=..\generic\tclIOCmd.c # End Source File # Begin Source File SOURCE=..\generic\tclIOGT.c # End Source File # Begin Source File SOURCE=..\generic\tclIOSock.c # End Source File # Begin Source File SOURCE=..\generic\tclIOUtil.c # End Source File # Begin Source File SOURCE=..\generic\tclLink.c # End Source File # Begin Source File SOURCE=..\generic\tclListObj.c # End Source File # Begin Source File SOURCE=..\generic\tclLiteral.c # End Source File # Begin Source File SOURCE=..\generic\tclLoad.c # End Source File # Begin Source File SOURCE=..\generic\tclLoadNone.c # End Source File # Begin Source File SOURCE=..\generic\tclMain.c # End Source File # Begin Source File SOURCE=..\generic\tclMath.h # End Source File # Begin Source File SOURCE=..\generic\tclNamesp.c # End Source File # Begin Source File SOURCE=..\generic\tclNotify.c # End Source File # Begin Source File SOURCE=..\generic\tclObj.c # End Source File # Begin Source File SOURCE=..\generic\tclPanic.c # End Source File # Begin Source File SOURCE=..\generic\tclParse.c # End Source File # Begin Source File SOURCE=..\generic\tclParseExpr.c # End Source File # Begin Source File SOURCE=..\generic\tclPipe.c # End Source File # Begin Source File SOURCE=..\generic\tclPkg.c # End Source File # Begin Source File SOURCE=..\generic\tclPlatDecls.h # End Source File # Begin Source File SOURCE=..\generic\tclPort.h # End Source File # Begin Source File SOURCE=..\generic\tclPosixStr.c # End Source File # Begin Source File SOURCE=..\generic\tclPreserve.c # End Source File # Begin Source File SOURCE=..\generic\tclProc.c # End Source File # Begin Source File SOURCE=..\generic\tclRegexp.c # End Source File # Begin Source File SOURCE=..\generic\tclRegexp.h # End Source File # Begin Source File SOURCE=..\generic\tclResolve.c # End Source File # Begin Source File SOURCE=..\generic\tclResult.c # End Source File # Begin Source File SOURCE=..\generic\tclScan.c # End Source File # Begin Source File SOURCE=..\generic\tclStringObj.c # End Source File # Begin Source File SOURCE=..\generic\tclStubInit.c # End Source File # Begin Source File SOURCE=..\generic\tclStubLib.c # End Source File # Begin Source File SOURCE=..\generic\tclTest.c # End Source File # Begin Source File SOURCE=..\generic\tclTestObj.c # End Source File # Begin Source File SOURCE=..\generic\tclTestProcBodyObj.c # End Source File # Begin Source File SOURCE=..\generic\tclThread.c # End Source File # Begin Source File SOURCE=..\generic\tclThreadJoin.c # End Source File # Begin Source File SOURCE=..\generic\tclThreadTest.c # End Source File # Begin Source File SOURCE=..\generic\tclTimer.c # End Source File # Begin Source File SOURCE=..\generic\tclUniData.c # End Source File # Begin Source File SOURCE=..\generic\tclUtf.c # End Source File # Begin Source File SOURCE=..\generic\tclUtil.c # End Source File # Begin Source File SOURCE=..\generic\tclVar.c # End Source File # End Group # Begin Group "library" # PROP Default_Filter "" # Begin Source File SOURCE=..\library\auto.tcl # End Source File # Begin Source File SOURCE=..\library\history.tcl # End Source File # Begin Source File SOURCE=..\library\init.tcl # End Source File # Begin Source File SOURCE=..\library\ldAout.tcl # End Source File # Begin Source File SOURCE=..\library\package.tcl # End Source File # Begin Source File SOURCE=..\library\parray.tcl # End Source File # Begin Source File SOURCE=..\library\safe.tcl # End Source File # Begin Source File SOURCE=..\library\tclIndex # End Source File # Begin Source File SOURCE=..\library\word.tcl # End Source File # End Group # Begin Group "mac" # PROP Default_Filter "" # End Group # Begin Group "tests" # PROP Default_Filter "" # End Group # Begin Group "tools" # PROP Default_Filter "" # End Group # Begin Group "unix" # PROP Default_Filter "" # End Group # Begin Group "win" # PROP Default_Filter "" # Begin Source File SOURCE=.\aclocal.m4 # End Source File # Begin Source File SOURCE=.\cat.c # End Source File # Begin Source File SOURCE=.\configure # End Source File # Begin Source File SOURCE=.\configure.in # End Source File # Begin Source File SOURCE=.\makefile.bc # End Source File # Begin Source File SOURCE=.\Makefile.in # End Source File # Begin Source File SOURCE=.\makefile.vc # End Source File # Begin Source File SOURCE=.\mkd.bat # End Source File # Begin Source File SOURCE=.\README # End Source File # Begin Source File SOURCE=.\README.binary # End Source File # Begin Source File SOURCE=.\rmd.bat # End Source File # Begin Source File SOURCE=.\rules.vc # End Source File # Begin Source File SOURCE=.\stub16.c # End Source File # Begin Source File SOURCE=.\tcl.hpj.in # End Source File # Begin Source File SOURCE=.\tcl.m4 # End Source File # Begin Source File SOURCE=.\tcl.rc # End Source File # Begin Source File SOURCE=.\tclAppInit.c # End Source File # Begin Source File SOURCE=.\tclConfig.sh.in # End Source File # Begin Source File SOURCE=.\tclsh.ico # End Source File # Begin Source File SOURCE=.\tclsh.rc # End Source File # Begin Source File SOURCE=.\tclWin32Dll.c # End Source File # Begin Source File SOURCE=.\tclWinChan.c # End Source File # Begin Source File SOURCE=.\tclWinConsole.c # End Source File # Begin Source File SOURCE=.\tclWinDde.c # End Source File # Begin Source File SOURCE=.\tclWinError.c # End Source File # Begin Source File SOURCE=.\tclWinFCmd.c # End Source File # Begin Source File SOURCE=.\tclWinFile.c # End Source File # Begin Source File SOURCE=.\tclWinInit.c # End Source File # Begin Source File SOURCE=.\tclWinInt.h # End Source File # Begin Source File SOURCE=.\tclWinLoad.c # End Source File # Begin Source File SOURCE=.\tclWinMtherr.c # End Source File # Begin Source File SOURCE=.\tclWinNotify.c # End Source File # Begin Source File SOURCE=.\tclWinPipe.c # End Source File # Begin Source File SOURCE=.\tclWinPort.h # End Source File # Begin Source File SOURCE=.\tclWinReg.c # End Source File # Begin Source File SOURCE=.\tclWinSerial.c # End Source File # Begin Source File SOURCE=.\tclWinSock.c # End Source File # Begin Source File SOURCE=.\tclWinTest.c # End Source File # Begin Source File SOURCE=.\tclWinThrd.c # End Source File # Begin Source File SOURCE=.\tclWinThrd.h # End Source File # Begin Source File SOURCE=.\tclWinTime.c # End Source File # End Group # End Target # End Project tcl8.4.20/win/tclWinThrd.c0000644003604700454610000007362212052456744013753 0ustar dgp771div/* * tclWinThread.c -- * * This file implements the Windows-specific thread operations. * * Copyright (c) 1998 by Sun Microsystems, Inc. * Copyright (c) 1999 by Scriptics Corporation * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclWinInt.h" #include #include #include #include /* Workaround for mingw versions which don't provide this in float.h */ #ifndef _MCW_EM # define _MCW_EM 0x0008001F /* Error masks */ # define _MCW_RC 0x00000300 /* Rounding */ # define _MCW_PC 0x00030000 /* Precision */ _CRTIMP unsigned int __cdecl _controlfp (unsigned int unNew, unsigned int unMask); #endif /* * This is the master lock used to serialize access to other * serialization data structures. */ static CRITICAL_SECTION masterLock; static int init = 0; #define MASTER_LOCK TclpMasterLock() #define MASTER_UNLOCK TclpMasterUnlock() /* * This is the master lock used to serialize initialization and finalization * of Tcl as a whole. */ static CRITICAL_SECTION initLock; /* * allocLock is used by Tcl's version of malloc for synchronization. * For obvious reasons, cannot use any dyamically allocated storage. */ #ifdef TCL_THREADS static CRITICAL_SECTION allocLock; static Tcl_Mutex allocLockPtr = (Tcl_Mutex) &allocLock; static int allocOnce = 0; #endif /* TCL_THREADS */ /* * The joinLock serializes Create- and ExitThread. This is necessary to * prevent a race where a new joinable thread exits before the creating * thread had the time to create the necessary data structures in the * emulation layer. */ static CRITICAL_SECTION joinLock; /* * Condition variables are implemented with a combination of a * per-thread Windows Event and a per-condition waiting queue. * The idea is that each thread has its own Event that it waits * on when it is doing a ConditionWait; it uses the same event for * all condition variables because it only waits on one at a time. * Each condition variable has a queue of waiting threads, and a * mutex used to serialize access to this queue. * * Special thanks to David Nichols and * Jim Davidson for advice on the Condition Variable implementation. */ /* * The per-thread event and queue pointers. */ #ifdef TCL_THREADS typedef struct ThreadSpecificData { HANDLE condEvent; /* Per-thread condition event */ struct ThreadSpecificData *nextPtr; /* Queue pointers */ struct ThreadSpecificData *prevPtr; int flags; /* See flags below */ } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; #endif /* TCL_THREADS */ /* * Additions by AOL for specialized thread memory allocator. */ #if defined(USE_THREAD_ALLOC) && !defined(TCL_MEM_DEBUG) static int once; static DWORD tlsKey; typedef struct allocMutex { Tcl_Mutex tlock; CRITICAL_SECTION wlock; } allocMutex; #endif /* * State bits for the thread. * WIN_THREAD_UNINIT Uninitialized. Must be zero because * of the way ThreadSpecificData is created. * WIN_THREAD_RUNNING Running, not waiting. * WIN_THREAD_BLOCKED Waiting, or trying to wait. */ #define WIN_THREAD_UNINIT 0x0 #define WIN_THREAD_RUNNING 0x1 #define WIN_THREAD_BLOCKED 0x2 /* * The per condition queue pointers and the * Mutex used to serialize access to the queue. */ typedef struct WinCondition { CRITICAL_SECTION condLock; /* Lock to serialize queuing on the condition */ struct ThreadSpecificData *firstPtr; /* Queue pointers */ struct ThreadSpecificData *lastPtr; } WinCondition; /* * The per thread data passed from TclpThreadCreate * to TclWinThreadStart. */ typedef struct WinThread { LPTHREAD_START_ROUTINE lpStartAddress; /* Original startup routine */ LPVOID lpParameter; /* Original startup data */ unsigned int fpControl; /* Floating point control word from the * main thread */ } WinThread; /* *---------------------------------------------------------------------- * * TclWinThreadStart -- * * This procedure is the entry point for all new threads created * by Tcl on Windows. * * Results: * Various, depending on the result of the wrapped thread start * routine. * * Side effects: * Arbitrary, since user code is executed. * *---------------------------------------------------------------------- */ static DWORD WINAPI TclWinThreadStart( LPVOID lpParameter) /* The WinThread structure pointer passed * from TclpThreadCreate */ { WinThread *winThreadPtr = (WinThread *) lpParameter; unsigned int fpmask; LPTHREAD_START_ROUTINE lpOrigStartAddress; LPVOID lpOrigParameter; if (!winThreadPtr) { return TCL_ERROR; } fpmask = _MCW_EM | _MCW_RC | _MCW_PC; #if defined(_MSC_VER) && _MSC_VER >= 1200 fpmask |= _MCW_DN; #endif _controlfp(winThreadPtr->fpControl, fpmask); lpOrigStartAddress = winThreadPtr->lpStartAddress; lpOrigParameter = winThreadPtr->lpParameter; ckfree((char *)winThreadPtr); return lpOrigStartAddress(lpOrigParameter); } /* *---------------------------------------------------------------------- * * TclpThreadCreate -- * * This procedure creates a new thread. * * Results: * TCL_OK if the thread could be created. The thread ID is * returned in a parameter. * * Side effects: * A new thread is created. * *---------------------------------------------------------------------- */ int TclpThreadCreate(idPtr, proc, clientData, stackSize, flags) Tcl_ThreadId *idPtr; /* Return, the ID of the thread */ Tcl_ThreadCreateProc proc; /* Main() function of the thread */ ClientData clientData; /* The one argument to Main() */ int stackSize; /* Size of stack for the new thread */ int flags; /* Flags controlling behaviour of * the new thread */ { WinThread *winThreadPtr; /* Per-thread startup info */ HANDLE tHandle; winThreadPtr = (WinThread *)ckalloc(sizeof(WinThread)); winThreadPtr->lpStartAddress = (LPTHREAD_START_ROUTINE) proc; winThreadPtr->lpParameter = clientData; winThreadPtr->fpControl = _controlfp(0, 0); EnterCriticalSection(&joinLock); #if defined(_MSC_VER) || defined(__MSVCRT__) || defined(__BORLANDC__) tHandle = (HANDLE) _beginthreadex(NULL, (unsigned) stackSize, (Tcl_ThreadCreateProc*) TclWinThreadStart, winThreadPtr, 0, (unsigned *)idPtr); #else tHandle = CreateThread(NULL, (DWORD) stackSize, TclWinThreadStart, winThreadPtr, 0, (LPDWORD)idPtr); #endif if (tHandle == NULL) { LeaveCriticalSection(&joinLock); return TCL_ERROR; } else { if (flags & TCL_THREAD_JOINABLE) { TclRememberJoinableThread (*idPtr); } /* * The only purpose of this is to decrement the reference count so the * OS resources will be reaquired when the thread closes. */ CloseHandle(tHandle); LeaveCriticalSection(&joinLock); return TCL_OK; } } /* *---------------------------------------------------------------------- * * Tcl_JoinThread -- * * This procedure waits upon the exit of the specified thread. * * Results: * TCL_OK if the wait was successful, TCL_ERROR else. * * Side effects: * The result area is set to the exit code of the thread we * waited upon. * *---------------------------------------------------------------------- */ int Tcl_JoinThread(threadId, result) Tcl_ThreadId threadId; /* Id of the thread to wait upon */ int* result; /* Reference to the storage the result * of the thread we wait upon will be * written into. */ { return TclJoinThread (threadId, result); } /* *---------------------------------------------------------------------- * * TclpThreadExit -- * * This procedure terminates the current thread. * * Results: * None. * * Side effects: * This procedure terminates the current thread. * *---------------------------------------------------------------------- */ void TclpThreadExit(status) int status; { EnterCriticalSection(&joinLock); TclSignalExitThread (Tcl_GetCurrentThread (), status); LeaveCriticalSection(&joinLock); #if defined(_MSC_VER) || defined(__MSVCRT__) || defined(__BORLANDC__) _endthreadex((unsigned) status); #else ExitThread((DWORD) status); #endif } /* *---------------------------------------------------------------------- * * Tcl_GetCurrentThread -- * * This procedure returns the ID of the currently running thread. * * Results: * A thread ID. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_ThreadId Tcl_GetCurrentThread() { return (Tcl_ThreadId)GetCurrentThreadId(); } /* *---------------------------------------------------------------------- * * TclpInitLock * * This procedure is used to grab a lock that serializes initialization * and finalization of Tcl. On some platforms this may also initialize * the mutex used to serialize creation of more mutexes and thread * local storage keys. * * Results: * None. * * Side effects: * Acquire the initialization mutex. * *---------------------------------------------------------------------- */ void TclpInitLock() { if (!init) { /* * There is a fundamental race here that is solved by creating * the first Tcl interpreter in a single threaded environment. * Once the interpreter has been created, it is safe to create * more threads that create interpreters in parallel. */ init = 1; InitializeCriticalSection(&joinLock); InitializeCriticalSection(&initLock); InitializeCriticalSection(&masterLock); } EnterCriticalSection(&initLock); } /* *---------------------------------------------------------------------- * * TclpInitUnlock * * This procedure is used to release a lock that serializes initialization * and finalization of Tcl. * * Results: * None. * * Side effects: * Release the initialization mutex. * *---------------------------------------------------------------------- */ void TclpInitUnlock() { LeaveCriticalSection(&initLock); } /* *---------------------------------------------------------------------- * * TclpMasterLock * * This procedure is used to grab a lock that serializes creation * of mutexes, condition variables, and thread local storage keys. * * This lock must be different than the initLock because the * initLock is held during creation of syncronization objects. * * Results: * None. * * Side effects: * Acquire the master mutex. * *---------------------------------------------------------------------- */ void TclpMasterLock() { if (!init) { /* * There is a fundamental race here that is solved by creating * the first Tcl interpreter in a single threaded environment. * Once the interpreter has been created, it is safe to create * more threads that create interpreters in parallel. */ init = 1; InitializeCriticalSection(&joinLock); InitializeCriticalSection(&initLock); InitializeCriticalSection(&masterLock); } EnterCriticalSection(&masterLock); } /* *---------------------------------------------------------------------- * * TclpMasterUnlock * * This procedure is used to release a lock that serializes creation * and deletion of synchronization objects. * * Results: * None. * * Side effects: * Release the master mutex. * *---------------------------------------------------------------------- */ void TclpMasterUnlock() { LeaveCriticalSection(&masterLock); } /* *---------------------------------------------------------------------- * * Tcl_GetAllocMutex * * This procedure returns a pointer to a statically initialized * mutex for use by the memory allocator. The alloctor must * use this lock, because all other locks are allocated... * * Results: * A pointer to a mutex that is suitable for passing to * Tcl_MutexLock and Tcl_MutexUnlock. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_Mutex * Tcl_GetAllocMutex() { #ifdef TCL_THREADS if (!allocOnce) { InitializeCriticalSection(&allocLock); allocOnce = 1; } return &allocLockPtr; #else return NULL; #endif } /* *---------------------------------------------------------------------- * * TclpFinalizeLock * * This procedure is used to destroy all private resources used in * this file. * * Results: * None. * * Side effects: * Destroys everything private. TclpInitLock must be held * entering this function. * *---------------------------------------------------------------------- */ void TclFinalizeLock () { MASTER_LOCK; DeleteCriticalSection(&joinLock); /* Destroy the critical section that we are holding! */ DeleteCriticalSection(&masterLock); init = 0; #ifdef TCL_THREADS DeleteCriticalSection(&allocLock); allocOnce = 0; #endif /* Destroy the critical section that we are holding! */ DeleteCriticalSection(&initLock); } #ifdef TCL_THREADS /* locally used prototype */ static void FinalizeConditionEvent(ClientData data); /* *---------------------------------------------------------------------- * * Tcl_MutexLock -- * * This procedure is invoked to lock a mutex. This is a self * initializing mutex that is automatically finalized during * Tcl_Finalize. * * Results: * None. * * Side effects: * May block the current thread. The mutex is aquired when * this returns. * *---------------------------------------------------------------------- */ void Tcl_MutexLock(mutexPtr) Tcl_Mutex *mutexPtr; /* The lock */ { CRITICAL_SECTION *csPtr; if (*mutexPtr == NULL) { MASTER_LOCK; /* * Double inside master lock check to avoid a race. */ if (*mutexPtr == NULL) { csPtr = (CRITICAL_SECTION *)ckalloc(sizeof(CRITICAL_SECTION)); InitializeCriticalSection(csPtr); *mutexPtr = (Tcl_Mutex)csPtr; TclRememberMutex(mutexPtr); } MASTER_UNLOCK; } csPtr = *((CRITICAL_SECTION **)mutexPtr); EnterCriticalSection(csPtr); } /* *---------------------------------------------------------------------- * * Tcl_MutexUnlock -- * * This procedure is invoked to unlock a mutex. * * Results: * None. * * Side effects: * The mutex is released when this returns. * *---------------------------------------------------------------------- */ void Tcl_MutexUnlock(mutexPtr) Tcl_Mutex *mutexPtr; /* The lock */ { CRITICAL_SECTION *csPtr = *((CRITICAL_SECTION **)mutexPtr); LeaveCriticalSection(csPtr); } /* *---------------------------------------------------------------------- * * TclpFinalizeMutex -- * * This procedure is invoked to clean up one mutex. This is only * safe to call at the end of time. * * Results: * None. * * Side effects: * The mutex list is deallocated. * *---------------------------------------------------------------------- */ void TclpFinalizeMutex(mutexPtr) Tcl_Mutex *mutexPtr; { CRITICAL_SECTION *csPtr = *(CRITICAL_SECTION **)mutexPtr; if (csPtr != NULL) { DeleteCriticalSection(csPtr); ckfree((char *)csPtr); *mutexPtr = NULL; } } /* *---------------------------------------------------------------------- * * TclpThreadDataKeyInit -- * * This procedure initializes a thread specific data block key. * Each thread has table of pointers to thread specific data. * all threads agree on which table entry is used by each module. * this is remembered in a "data key", that is just an index into * this table. To allow self initialization, the interface * passes a pointer to this key and the first thread to use * the key fills in the pointer to the key. The key should be * a process-wide static. * * Results: * None. * * Side effects: * Will allocate memory the first time this process calls for * this key. In this case it modifies its argument * to hold the pointer to information about the key. * *---------------------------------------------------------------------- */ void TclpThreadDataKeyInit(keyPtr) Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk, * really (DWORD **) */ { DWORD *indexPtr; DWORD newKey; MASTER_LOCK; if (*keyPtr == NULL) { indexPtr = (DWORD *)ckalloc(sizeof(DWORD)); newKey = TlsAlloc(); if (newKey != TLS_OUT_OF_INDEXES) { *indexPtr = newKey; } else { panic("TlsAlloc failed from TclpThreadDataKeyInit!"); /* this should be a fatal error */ } *keyPtr = (Tcl_ThreadDataKey)indexPtr; TclRememberDataKey(keyPtr); } MASTER_UNLOCK; } /* *---------------------------------------------------------------------- * * TclpThreadDataKeyGet -- * * This procedure returns a pointer to a block of thread local storage. * * Results: * A thread-specific pointer to the data structure, or NULL * if the memory has not been assigned to this key for this thread. * * Side effects: * None. * *---------------------------------------------------------------------- */ VOID * TclpThreadDataKeyGet(keyPtr) Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk, * really (DWORD **) */ { DWORD *indexPtr = *(DWORD **)keyPtr; LPVOID result; if (indexPtr == NULL) { return NULL; } else { result = TlsGetValue(*indexPtr); if ((result == NULL) && (GetLastError() != NO_ERROR)) { panic("TlsGetValue failed from TclpThreadDataKeyGet!"); } return result; } } /* *---------------------------------------------------------------------- * * TclpThreadDataKeySet -- * * This procedure sets the pointer to a block of thread local storage. * * Results: * None. * * Side effects: * Sets up the thread so future calls to TclpThreadDataKeyGet with * this key will return the data pointer. * *---------------------------------------------------------------------- */ void TclpThreadDataKeySet(keyPtr, data) Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk, * really (pthread_key_t **) */ VOID *data; /* Thread local storage */ { DWORD *indexPtr = *(DWORD **)keyPtr; BOOL success; success = TlsSetValue(*indexPtr, (void *)data); if (!success) { panic("TlsSetValue failed from TclpThreadDataKeySet!"); } } /* *---------------------------------------------------------------------- * * TclpFinalizeThreadData -- * * This procedure cleans up the thread-local storage. This is * called once for each thread. * * Results: * None. * * Side effects: * Frees up the memory. * *---------------------------------------------------------------------- */ void TclpFinalizeThreadData(keyPtr) Tcl_ThreadDataKey *keyPtr; { VOID *result; DWORD *indexPtr; BOOL success; if (*keyPtr != NULL) { indexPtr = *(DWORD **)keyPtr; result = (VOID *)TlsGetValue(*indexPtr); if (result != NULL) { #if defined(USE_THREAD_ALLOC) && !defined(TCL_MEM_DEBUG) if (indexPtr == &tlsKey) { TclpFreeAllocCache(result); return; } #endif ckfree((char *)result); success = TlsSetValue(*indexPtr, (void *)NULL); if (!success) { panic("TlsSetValue failed from TclpFinalizeThreadData!"); } } else { if (GetLastError() != NO_ERROR) { panic("TlsGetValue failed from TclpFinalizeThreadData!"); } } } } /* *---------------------------------------------------------------------- * * TclpFinalizeThreadDataKey -- * * This procedure is invoked to clean up one key. This is a * process-wide storage identifier. The thread finalization code * cleans up the thread local storage itself. * * This assumes the master lock is held. * * Results: * None. * * Side effects: * The key is deallocated. * *---------------------------------------------------------------------- */ void TclpFinalizeThreadDataKey(keyPtr) Tcl_ThreadDataKey *keyPtr; { DWORD *indexPtr; BOOL success; if (*keyPtr != NULL) { indexPtr = *(DWORD **)keyPtr; success = TlsFree(*indexPtr); if (!success) { panic("TlsFree failed from TclpFinalizeThreadDataKey!"); } ckfree((char *)indexPtr); *keyPtr = NULL; } } /* *---------------------------------------------------------------------- * * Tcl_ConditionWait -- * * This procedure is invoked to wait on a condition variable. * The mutex is atomically released as part of the wait, and * automatically grabbed when the condition is signaled. * * The mutex must be held when this procedure is called. * * Results: * None. * * Side effects: * May block the current thread. The mutex is aquired when * this returns. Will allocate memory for a HANDLE * and initialize this the first time this Tcl_Condition is used. * *---------------------------------------------------------------------- */ void Tcl_ConditionWait(condPtr, mutexPtr, timePtr) Tcl_Condition *condPtr; /* Really (WinCondition **) */ Tcl_Mutex *mutexPtr; /* Really (CRITICAL_SECTION **) */ Tcl_Time *timePtr; /* Timeout on waiting period */ { WinCondition *winCondPtr; /* Per-condition queue head */ CRITICAL_SECTION *csPtr; /* Caller's Mutex, after casting */ DWORD wtime; /* Windows time value */ int timeout; /* True if we got a timeout */ int doExit = 0; /* True if we need to do exit setup */ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); /* * Self initialize the two parts of the condition. * The per-condition and per-thread parts need to be * handled independently. */ if (tsdPtr->flags == WIN_THREAD_UNINIT) { MASTER_LOCK; /* * Create the per-thread event and queue pointers. */ if (tsdPtr->flags == WIN_THREAD_UNINIT) { tsdPtr->condEvent = CreateEvent(NULL, TRUE /* manual reset */, FALSE /* non signaled */, NULL); tsdPtr->nextPtr = NULL; tsdPtr->prevPtr = NULL; tsdPtr->flags = WIN_THREAD_RUNNING; doExit = 1; } MASTER_UNLOCK; if (doExit) { /* * Create a per-thread exit handler to clean up the condEvent. * We must be careful to do this outside the Master Lock * because Tcl_CreateThreadExitHandler uses its own * ThreadSpecificData, and initializing that may drop * back into the Master Lock. */ Tcl_CreateThreadExitHandler(FinalizeConditionEvent, (ClientData) tsdPtr); } } if (*condPtr == NULL) { MASTER_LOCK; /* * Initialize the per-condition queue pointers and Mutex. */ if (*condPtr == NULL) { winCondPtr = (WinCondition *)ckalloc(sizeof(WinCondition)); InitializeCriticalSection(&winCondPtr->condLock); winCondPtr->firstPtr = NULL; winCondPtr->lastPtr = NULL; *condPtr = (Tcl_Condition)winCondPtr; TclRememberCondition(condPtr); } MASTER_UNLOCK; } csPtr = *((CRITICAL_SECTION **)mutexPtr); winCondPtr = *((WinCondition **)condPtr); if (timePtr == NULL) { wtime = INFINITE; } else { wtime = timePtr->sec * 1000 + timePtr->usec / 1000; } /* * Queue the thread on the condition, using * the per-condition lock for serialization. */ tsdPtr->flags = WIN_THREAD_BLOCKED; tsdPtr->nextPtr = NULL; EnterCriticalSection(&winCondPtr->condLock); tsdPtr->prevPtr = winCondPtr->lastPtr; /* A: */ winCondPtr->lastPtr = tsdPtr; if (tsdPtr->prevPtr != NULL) { tsdPtr->prevPtr->nextPtr = tsdPtr; } if (winCondPtr->firstPtr == NULL) { winCondPtr->firstPtr = tsdPtr; } /* * Unlock the caller's mutex and wait for the condition, or a timeout. * There is a minor issue here in that we don't count down the * timeout if we get notified, but another thread grabs the condition * before we do. In that race condition we'll wait again for the * full timeout. Timed waits are dubious anyway. Either you have * the locking protocol wrong and are masking a deadlock, * or you are using conditions to pause your thread. */ LeaveCriticalSection(csPtr); timeout = 0; while (!timeout && (tsdPtr->flags & WIN_THREAD_BLOCKED)) { ResetEvent(tsdPtr->condEvent); LeaveCriticalSection(&winCondPtr->condLock); if (WaitForSingleObject(tsdPtr->condEvent, wtime) == WAIT_TIMEOUT) { timeout = 1; } EnterCriticalSection(&winCondPtr->condLock); } /* * Be careful on timeouts because the signal might arrive right around * the time limit and someone else could have taken us off the queue. */ if (timeout) { if (tsdPtr->flags & WIN_THREAD_RUNNING) { timeout = 0; } else { /* * When dequeuing, we can leave the tsdPtr->nextPtr * and tsdPtr->prevPtr with dangling pointers because * they are reinitialilzed w/out reading them when the * thread is enqueued later. */ if (winCondPtr->firstPtr == tsdPtr) { winCondPtr->firstPtr = tsdPtr->nextPtr; } else { tsdPtr->prevPtr->nextPtr = tsdPtr->nextPtr; } if (winCondPtr->lastPtr == tsdPtr) { winCondPtr->lastPtr = tsdPtr->prevPtr; } else { tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr; } tsdPtr->flags = WIN_THREAD_RUNNING; } } LeaveCriticalSection(&winCondPtr->condLock); EnterCriticalSection(csPtr); } /* *---------------------------------------------------------------------- * * Tcl_ConditionNotify -- * * This procedure is invoked to signal a condition variable. * * The mutex must be held during this call to avoid races, * but this interface does not enforce that. * * Results: * None. * * Side effects: * May unblock another thread. * *---------------------------------------------------------------------- */ void Tcl_ConditionNotify(condPtr) Tcl_Condition *condPtr; { WinCondition *winCondPtr; ThreadSpecificData *tsdPtr; if (condPtr != NULL) { winCondPtr = *((WinCondition **)condPtr); if (winCondPtr == NULL) { return; } /* * Loop through all the threads waiting on the condition * and notify them (i.e., broadcast semantics). The queue * manipulation is guarded by the per-condition coordinating mutex. */ EnterCriticalSection(&winCondPtr->condLock); while (winCondPtr->firstPtr != NULL) { tsdPtr = winCondPtr->firstPtr; winCondPtr->firstPtr = tsdPtr->nextPtr; if (winCondPtr->lastPtr == tsdPtr) { winCondPtr->lastPtr = NULL; } tsdPtr->flags = WIN_THREAD_RUNNING; tsdPtr->nextPtr = NULL; tsdPtr->prevPtr = NULL; /* Not strictly necessary, see A: */ SetEvent(tsdPtr->condEvent); } LeaveCriticalSection(&winCondPtr->condLock); } else { /* * Noone has used the condition variable, so there are no waiters. */ } } /* *---------------------------------------------------------------------- * * FinalizeConditionEvent -- * * This procedure is invoked to clean up the per-thread * event used to implement condition waiting. * This is only safe to call at the end of time. * * Results: * None. * * Side effects: * The per-thread event is closed. * *---------------------------------------------------------------------- */ static void FinalizeConditionEvent(data) ClientData data; { ThreadSpecificData *tsdPtr = (ThreadSpecificData *)data; tsdPtr->flags = WIN_THREAD_UNINIT; CloseHandle(tsdPtr->condEvent); } /* *---------------------------------------------------------------------- * * TclpFinalizeCondition -- * * This procedure is invoked to clean up a condition variable. * This is only safe to call at the end of time. * * This assumes the Master Lock is held. * * Results: * None. * * Side effects: * The condition variable is deallocated. * *---------------------------------------------------------------------- */ void TclpFinalizeCondition(condPtr) Tcl_Condition *condPtr; { WinCondition *winCondPtr = *(WinCondition **)condPtr; /* * Note - this is called long after the thread-local storage is * reclaimed. The per-thread condition waiting event is * reclaimed earlier in a per-thread exit handler, which is * called before thread local storage is reclaimed. */ if (winCondPtr != NULL) { DeleteCriticalSection(&winCondPtr->condLock); ckfree((char *)winCondPtr); *condPtr = NULL; } } /* * Additions by AOL for specialized thread memory allocator. */ #if defined(USE_THREAD_ALLOC) && !defined(TCL_MEM_DEBUG) Tcl_Mutex * TclpNewAllocMutex(void) { struct allocMutex *lockPtr; lockPtr = malloc(sizeof(struct allocMutex)); if (lockPtr == NULL) { panic("could not allocate lock"); } lockPtr->tlock = (Tcl_Mutex) &lockPtr->wlock; InitializeCriticalSection(&lockPtr->wlock); return &lockPtr->tlock; } void TclpFreeAllocMutex(mutex) Tcl_Mutex *mutex; /* The alloc mutex to free. */ { allocMutex* lockPtr = (allocMutex*) mutex; if (!lockPtr) return; DeleteCriticalSection(&lockPtr->wlock); free(lockPtr); } void * TclpGetAllocCache(void) { VOID *result; if (!once) { /* * We need to make sure that TclpFreeAllocCache is called * on each thread that calls this, but only on threads that * call this. */ tlsKey = TlsAlloc(); once = 1; if (tlsKey == TLS_OUT_OF_INDEXES) { panic("could not allocate thread local storage"); } } result = TlsGetValue(tlsKey); if ((result == NULL) && (GetLastError() != NO_ERROR)) { panic("TlsGetValue failed from TclpGetAllocCache!"); } return result; } void TclpSetAllocCache(void *ptr) { BOOL success; success = TlsSetValue(tlsKey, ptr); if (!success) { panic("TlsSetValue failed from TclpSetAllocCache!"); } } void TclpFreeAllocCache(void *ptr) { BOOL success; if (ptr != NULL) { /* * Called by the pthread lib when a thread exits */ TclFreeAllocCache(ptr); success = TlsSetValue(tlsKey, NULL); if (!success) { panic("TlsSetValue failed from TclpFreeAllocCache!"); } } else if (once) { /* * Called by us in TclFinalizeThreadAlloc() during * the library finalization initiated from Tcl_Finalize() */ success = TlsFree(tlsKey); if (!success) { Tcl_Panic("TlsFree failed from TclpFreeAllocCache!"); } once = 0; /* reset for next time. */ } } #endif /* USE_THREAD_ALLOC */ #endif /* TCL_THREADS */ tcl8.4.20/win/rules.vc0000644003604700454610000003151712153151142013170 0ustar dgp771div#------------------------------------------------------------------------------ # rules.vc -- # # Microsoft Visual C++ makefile include for decoding the commandline # macros. This file does not need editing to build Tcl. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # Copyright (c) 2001-2003 David Gravereaux. # Copyright (c) 2003-2006 Patrick Thoyts #------------------------------------------------------------------------------ !ifndef _RULES_VC _RULES_VC = 1 cc32 = $(CC) # built-in default. link32 = link lib32 = lib rc32 = $(RC) # built-in default. !ifndef INSTALLDIR ### Assume the normal default. _INSTALLDIR = C:\Program Files\Tcl !else ### Fix the path separators. _INSTALLDIR = $(INSTALLDIR:/=\) !endif #---------------------------------------------------------- # Set the proper copy method to avoid overwrite questions # to the user when copying files and selecting the right # "delete all" method. #---------------------------------------------------------- !if "$(OS)" == "Windows_NT" RMDIR = rmdir /S /Q ERRNULL = 2>NUL !if ![ver | find "4.0" > nul] CPY = echo y | xcopy /i >NUL COPY = copy >NUL !else CPY = xcopy /i /y >NUL COPY = copy /y >NUL !endif !else # "$(OS)" != "Windows_NT" CPY = xcopy /i >_JUNK.OUT # On Win98 NUL does not work here. COPY = copy >_JUNK.OUT # On Win98 NUL does not work here. RMDIR = deltree /Y NULL = \NUL # Used in testing directory existence ERRNULL = >NUL # Win9x shell cannot redirect stderr !endif MKDIR = mkdir #------------------------------------------------------------------------------ # Determine the host and target architectures and compiler version. #------------------------------------------------------------------------------ _HASH=^# _VC_MANIFEST_EMBED_EXE= _VC_MANIFEST_EMBED_DLL= VCVER=0 !if ![echo VCVERSION=_MSC_VER > vercl.x] \ && ![echo $(_HASH)if defined(_M_IX86) >> vercl.x] \ && ![echo ARCH=IX86 >> vercl.x] \ && ![echo $(_HASH)elif defined(_M_AMD64) >> vercl.x] \ && ![echo ARCH=AMD64 >> vercl.x] \ && ![echo $(_HASH)endif >> vercl.x] \ && ![cl -nologo -TC -P vercl.x $(ERRNULL)] !include vercl.i !if ![echo VCVER= ^\> vercl.vc] \ && ![set /a $(VCVERSION) / 100 - 6 >> vercl.vc] !include vercl.vc !endif !endif !if ![del $(ERRNUL) /q/f vercl.x vercl.i vercl.vc] !endif !if ![reg query HKLM\Hardware\Description\System\CentralProcessor\0 /v Identifier | findstr /i x86] NATIVE_ARCH=IX86 !else NATIVE_ARCH=AMD64 !endif # Since MSVC8 we must deal with manifest resources. !if $(VCVERSION) >= 1400 _VC_MANIFEST_EMBED_EXE=if exist $@.manifest mt -nologo -manifest $@.manifest -outputresource:$@;1 _VC_MANIFEST_EMBED_DLL=if exist $@.manifest mt -nologo -manifest $@.manifest -outputresource:$@;2 !endif !ifndef MACHINE MACHINE=$(ARCH) !endif !ifndef CFG_ENCODING CFG_ENCODING = \"cp1252\" !endif !message =============================================================================== #---------------------------------------------------------- # build the helper app we need to overcome nmake's limiting # environment. #---------------------------------------------------------- !if !exist(nmakehlp.exe) !if [$(cc32) -nologo nmakehlp.c -link -subsystem:console > nul] !endif !endif #---------------------------------------------------------- # Test for compiler features #---------------------------------------------------------- ### test for optimizations !if [nmakehlp -c -Ot] !message *** Compiler has 'Optimizations' OPTIMIZING = 1 !else !message *** Compiler does not have 'Optimizations' OPTIMIZING = 0 !endif OPTIMIZATIONS = !if [nmakehlp -c -Ot] OPTIMIZATIONS = $(OPTIMIZATIONS) -Ot !endif !if [nmakehlp -c -Oi] OPTIMIZATIONS = $(OPTIMIZATIONS) -Oi !endif !if [nmakehlp -c -Op] OPTIMIZATIONS = $(OPTIMIZATIONS) -Op !endif !if [nmakehlp -c -fp:strict] OPTIMIZATIONS = $(OPTIMIZATIONS) -fp:strict !endif !if [nmakehlp -c -Gs] OPTIMIZATIONS = $(OPTIMIZATIONS) -Gs !endif !if [nmakehlp -c -GS] OPTIMIZATIONS = $(OPTIMIZATIONS) -GS !endif !if [nmakehlp -c -GL] OPTIMIZATIONS = $(OPTIMIZATIONS) -GL !endif DEBUGFLAGS = !if [nmakehlp -c -RTC1] DEBUGFLAGS = $(DEBUGFLAGS) -RTC1 !elseif [nmakehlp -c -GZ] DEBUGFLAGS = $(DEBUGFLAGS) -GZ !endif COMPILERFLAGS =-W3 # In v13 -GL and -YX are incompatible. !if [nmakehlp -c -YX] !if ![nmakehlp -c -GL] OPTIMIZATIONS = $(OPTIMIZATIONS) -YX !endif !endif !if "$(MACHINE)" == "IX86" ### test for pentium errata !if [nmakehlp -c -QI0f] !message *** Compiler has 'Pentium 0x0f fix' COMPILERFLAGS = $(COMPILERFLAGS) -QI0f !else !message *** Compiler does not have 'Pentium 0x0f fix' !endif !endif !if "$(MACHINE)" == "IA64" ### test for Itanium errata !if [nmakehlp -c -QIA64_Bx] !message *** Compiler has 'B-stepping errata workarounds' COMPILERFLAGS = $(COMPILERFLAGS) -QIA64_Bx !else !message *** Compiler does not have 'B-stepping errata workarounds' !endif !endif !if "$(MACHINE)" == "IX86" ### test for -align:4096, when align:512 will do. !if [nmakehlp -l -opt:nowin98] !message *** Linker has 'Win98 alignment problem' ALIGN98_HACK = 1 !else !message *** Linker does not have 'Win98 alignment problem' ALIGN98_HACK = 0 !endif !else ALIGN98_HACK = 0 !endif LINKERFLAGS = !if [nmakehlp -l -ltcg] LINKERFLAGS =-ltcg !endif #---------------------------------------------------------- # Decode the options requested. #---------------------------------------------------------- !if "$(OPTS)" == "" || [nmakehlp -f "$(OPTS)" "none"] STATIC_BUILD = 0 TCL_THREADS = 0 DEBUG = 0 PROFILE = 0 MSVCRT = 0 LOIMPACT = 0 TCL_USE_STATIC_PACKAGES = 0 USE_THREAD_ALLOC = 0 UNCHECKED = 0 !else !if [nmakehlp -f $(OPTS) "static"] !message *** Doing static STATIC_BUILD = 1 !else STATIC_BUILD = 0 !endif !if [nmakehlp -f $(OPTS) "msvcrt"] !message *** Doing msvcrt MSVCRT = 1 !else MSVCRT = 0 !endif !if [nmakehlp -f $(OPTS) "staticpkg"] !message *** Doing staticpkg TCL_USE_STATIC_PACKAGES = 1 !else TCL_USE_STATIC_PACKAGES = 0 !endif !if [nmakehlp -f $(OPTS) "threads"] !message *** Doing threads TCL_THREADS = 1 !else TCL_THREADS = 0 !endif !if [nmakehlp -f $(OPTS) "symbols"] !message *** Doing symbols DEBUG = 1 !else DEBUG = 0 !endif !if [nmakehlp -f $(OPTS) "profile"] !message *** Doing profile PROFILE = 1 !else PROFILE = 0 !endif !if [nmakehlp -f $(OPTS) "loimpact"] !message *** Doing loimpact LOIMPACT = 1 !else LOIMPACT = 0 !endif !if [nmakehlp -f $(OPTS) "thrdalloc"] !message *** Doing thrdalloc USE_THREAD_ALLOC = 1 !else USE_THREAD_ALLOC = 0 !endif !if [nmakehlp -f $(OPTS) "unchecked"] !message *** Doing unchecked UNCHECKED = 1 !else UNCHECKED = 0 !endif !endif !if !$(STATIC_BUILD) # Make sure we don't build overly fat DLLs. MSVCRT = 1 # We shouldn't statically put the extensions inside the shell when dynamic. TCL_USE_STATIC_PACKAGES = 0 !endif #---------------------------------------------------------- # Figure-out how to name our intermediate and output directories. # We wouldn't want different builds to use the same .obj files # by accident. #---------------------------------------------------------- #---------------------------------------- # Naming convention: # t = full thread support. # s = static library (as opposed to an # import library) # g = linked to the debug enabled C # run-time. # x = special static build when it # links to the dynamic C run-time. #---------------------------------------- SUFX = tsgx !if $(DEBUG) BUILDDIRTOP = Debug DBGX = g !else BUILDDIRTOP = Release DBGX = SUFX = $(SUFX:g=) !endif !if "$(MACHINE)" != "IX86" BUILDDIRTOP =$(BUILDDIRTOP)_$(MACHINE) !endif !if $(VCVER) > 6 BUILDDIRTOP =$(BUILDDIRTOP)_VC$(VCVER) !endif TMP_DIRFULL = .\$(BUILDDIRTOP)\$(PROJECT)_ThreadedDynamicStaticX !if !$(STATIC_BUILD) TMP_DIRFULL = $(TMP_DIRFULL:Static=) SUFX = $(SUFX:s=) EXT = dll !if $(MSVCRT) TMP_DIRFULL = $(TMP_DIRFULL:X=) SUFX = $(SUFX:x=) !endif !else TMP_DIRFULL = $(TMP_DIRFULL:Dynamic=) EXT = lib !if !$(MSVCRT) TMP_DIRFULL = $(TMP_DIRFULL:X=) SUFX = $(SUFX:x=) !endif !endif !if !$(TCL_THREADS) TMP_DIRFULL = $(TMP_DIRFULL:Threaded=) SUFX = $(SUFX:t=) !endif !ifndef TMP_DIR TMP_DIR = $(TMP_DIRFULL) !ifndef OUT_DIR OUT_DIR = .\$(BUILDDIRTOP) !endif !else !ifndef OUT_DIR OUT_DIR = $(TMP_DIR) !endif !endif #---------------------------------------------------------- # Decode the statistics requested. #---------------------------------------------------------- !if "$(STATS)" == "" || [nmakehlp -f "$(STATS)" "none"] TCL_MEM_DEBUG = 0 TCL_COMPILE_DEBUG = 0 !else !if [nmakehlp -f $(STATS) "memdbg"] !message *** Doing memdbg TCL_MEM_DEBUG = 1 !else TCL_MEM_DEBUG = 0 !endif !if [nmakehlp -f $(STATS) "compdbg"] !message *** Doing compdbg TCL_COMPILE_DEBUG = 1 !else TCL_COMPILE_DEBUG = 0 !endif !endif #---------------------------------------------------------- # Decode the checks requested. #---------------------------------------------------------- !if "$(CHECKS)" == "" || [nmakehlp -f "$(CHECKS)" "none"] TCL_NO_DEPRECATED = 0 FULLWARNINGS = 0 !else !if [nmakehlp -f $(CHECKS) "nodep"] !message *** Doing nodep check TCL_NO_DEPRECATED = 1 !else TCL_NO_DEPRECATED = 0 !endif !if [nmakehlp -f $(CHECKS) "fullwarn"] !message *** Doing full warnings check FULLWARNINGS = 1 !else FULLWARNINGS = 0 !endif !endif #---------------------------------------------------------- # Set our defines now armed with our options. #---------------------------------------------------------- OPTDEFINES = !if $(TCL_MEM_DEBUG) OPTDEFINES = $(OPTDEFINES) -DTCL_MEM_DEBUG !endif !if $(TCL_COMPILE_DEBUG) OPTDEFINES = $(OPTDEFINES) -DTCL_COMPILE_DEBUG -DTCL_COMPILE_STATS !endif !if $(TCL_THREADS) OPTDEFINES = $(OPTDEFINES) -DTCL_THREADS=1 !if $(USE_THREAD_ALLOC) OPTDEFINES = $(OPTDEFINES) -DUSE_THREAD_ALLOC=1 !endif !endif !if $(STATIC_BUILD) OPTDEFINES = $(OPTDEFINES) -DSTATIC_BUILD !endif !if !$(DEBUG) OPTDEFINES = $(OPTDEFINES) -DNDEBUG !if $(OPTIMIZING) OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_OPTIMIZED !endif !endif !if $(PROFILE) OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_PROFILED !endif !if "$(MACHINE)" == "IA64" || "$(MACHINE)" == "AMD64" OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_DO64BIT !endif !if $(VCVERSION) < 1300 OPTDEFINES = $(OPTDEFINES) -DNO_STRTOI64 !endif #---------------------------------------------------------- # Get common info used when building extensions. #---------------------------------------------------------- !if "$(PROJECT)" != "tcl" !if !defined(TCLDIR) !if exist("$(_INSTALLDIR)\include\tcl.h") TCLH = "$(_INSTALLDIR)\include\tcl.h" TCLINSTALL = 1 _TCLDIR = $(_INSTALLDIR) !else MSG=^ Failed to find tcl.h. Set the TCLDIR macro. !error $(MSG) !endif !else _TCLDIR = $(TCLDIR:/=\) !if exist("$(_TCLDIR)\include\tcl.h") TCLH = "$(_TCLDIR)\include\tcl.h" TCLINSTALL = 1 !elseif exist("$(_TCLDIR)\generic\tcl.h") TCLH = "$(_TCLDIR)\generic\tcl.h" TCLINSTALL = 0 !else MSG =^ Failed to find tcl.h. The TCLDIR macro does not appear correct. !error $(MSG) !endif !endif TCL_DOTVERSION = 8.4 TCL_VERSION = $(TCL_DOTVERSION:.=) !if $(TCLINSTALL) TCLSH = "$(_INSTALLDIR)\bin\tclsh$(TCL_VERSION)$(SUFX).exe" TCLSTUBLIB = "$(_INSTALLDIR)\lib\tclstub$(TCL_VERSION).lib" TCLIMPLIB = "$(_INSTALLDIR)\lib\tcl$(TCL_VERSION)$(SUFX).lib" TCL_LIBRARY = $(_INSTALLDIR)\lib TCLREGLIB = "$(_INSTALLDIR)\lib\tclreg12$(SUFX:t=).lib" TCLDDELIB = "$(_INSTALLDIR)\lib\tcldde13$(SUFX:t=).lib" COFFBASE = \must\have\tcl\sources\to\build\this\target TCLTOOLSDIR = \must\have\tcl\sources\to\build\this\target !else TCLSH = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tclsh$(TCL_VERSION)$(SUFX).exe" TCLSTUBLIB = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tclstub$(TCL_VERSION).lib" TCLIMPLIB = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tcl$(TCL_VERSION)$(SUFX).lib" TCL_LIBRARY = $(_TCLDIR)\library TCLREGLIB = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tclreg12$(SUFX:t=).lib" TCLDDELIB = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tcldde13$(SUFX:t=).lib" COFFBASE = "$(_TCLDIR)\win\coffbase.txt" TCLTOOLSDIR = $(_TCLDIR)\tools !endif !endif #---------------------------------------------------------- # Display stats being used. #---------------------------------------------------------- !message *** Intermediate directory will be '$(TMP_DIR)' !message *** Output directory will be '$(OUT_DIR)' !message *** Suffix for binaries will be '$(SUFX)' !message *** Optional defines are '$(OPTDEFINES)' !message *** Compiler version $(VCVER). Target machine is $(MACHINE) !message *** Compiler options '$(OPTIMIZATIONS) $(DEBUGFLAGS)' !message *** Link options '$(LINKERFLAGS)' !endif tcl8.4.20/win/tclWinTest.c0000644003604700454610000005262212052456744013766 0ustar dgp771div/* * tclWinTest.c -- * * Contains commands for platform specific tests on Windows. * * Copyright (c) 1996 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #define USE_COMPAT_CONST #include "tclWinInt.h" /* * For TestplatformChmod on Windows */ #ifdef __WIN32__ #include #endif /* * MinGW 3.4.2 does not define this. */ #ifndef INHERITED_ACE #define INHERITED_ACE (0x10) #endif /* * Forward declarations of procedures defined later in this file: */ int TclplatformtestInit _ANSI_ARGS_((Tcl_Interp *interp)); static int TesteventloopCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST84 char **argv)); static int TestvolumetypeCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int TestwinclockCmd _ANSI_ARGS_(( ClientData dummy, Tcl_Interp* interp, int objc, Tcl_Obj *CONST objv[] )); static int TestwinsleepCmd _ANSI_ARGS_(( ClientData dummy, Tcl_Interp* interp, int objc, Tcl_Obj *CONST objv[] )); static Tcl_ObjCmdProc TestExceptionCmd; static int TestplatformChmod _ANSI_ARGS_((CONST char *nativePath, int pmode)); static int TestchmodCmd _ANSI_ARGS_((ClientData dummy, Tcl_Interp *interp, int argc, CONST84 char **argv)); /* *---------------------------------------------------------------------- * * TclplatformtestInit -- * * Defines commands that test platform specific functionality for * Windows platforms. * * Results: * A standard Tcl result. * * Side effects: * Defines new commands. * *---------------------------------------------------------------------- */ int TclplatformtestInit(interp) Tcl_Interp *interp; /* Interpreter to add commands to. */ { /* * Add commands for platform specific tests for Windows here. */ Tcl_CreateCommand(interp, "testchmod", TestchmodCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateCommand(interp, "testeventloop", TesteventloopCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "testvolumetype", TestvolumetypeCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "testwinclock", TestwinclockCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "testwinsleep", TestwinsleepCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL ); Tcl_CreateObjCommand(interp, "testexcept", TestExceptionCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); return TCL_OK; } /* *---------------------------------------------------------------------- * * TesteventloopCmd -- * * This procedure implements the "testeventloop" command. It is * used to test the Tcl notifier from an "external" event loop * (i.e. not Tcl_DoOneEvent()). * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TesteventloopCmd(clientData, interp, argc, argv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST84 char **argv; /* Argument strings. */ { static int *framePtr = NULL; /* Pointer to integer on stack frame of * innermost invocation of the "wait" * subcommand. */ if (argc < 2) { Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0], " option ... \"", (char *) NULL); return TCL_ERROR; } if (strcmp(argv[1], "done") == 0) { *framePtr = 1; } else if (strcmp(argv[1], "wait") == 0) { int *oldFramePtr; int done; MSG msg; int oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL); /* * Save the old stack frame pointer and set up the current frame. */ oldFramePtr = framePtr; framePtr = &done; /* * Enter a standard Windows event loop until the flag changes. * Note that we do not explicitly call Tcl_ServiceEvent(). */ done = 0; while (!done) { if (!GetMessage(&msg, NULL, 0, 0)) { /* * The application is exiting, so repost the quit message * and start unwinding. */ PostQuitMessage((int)msg.wParam); break; } TranslateMessage(&msg); DispatchMessage(&msg); } (void) Tcl_SetServiceMode(oldMode); framePtr = oldFramePtr; } else { Tcl_AppendResult(interp, "bad option \"", argv[1], "\": must be done or wait", (char *) NULL); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * Testvolumetype -- * * This procedure implements the "testvolumetype" command. It is * used to check the volume type (FAT, NTFS) of a volume. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TestvolumetypeCmd(clientData, interp, objc, objv) ClientData clientData; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument objects. */ { #define VOL_BUF_SIZE 32 int found; char volType[VOL_BUF_SIZE]; char *path; if (objc > 2) { Tcl_WrongNumArgs(interp, 1, objv, "?name?"); return TCL_ERROR; } if (objc == 2) { /* * path has to be really a proper volume, but we don't * get query APIs for that until NT5 */ path = Tcl_GetString(objv[1]); } else { path = NULL; } found = GetVolumeInformationA(path, NULL, 0, NULL, NULL, NULL, volType, VOL_BUF_SIZE); if (found == 0) { Tcl_AppendResult(interp, "could not get volume type for \"", (path?path:""), "\"", (char *) NULL); TclWinConvertError(GetLastError()); return TCL_ERROR; } Tcl_SetResult(interp, volType, TCL_VOLATILE); return TCL_OK; #undef VOL_BUF_SIZE } /* *---------------------------------------------------------------------- * * TestwinclockCmd -- * * Command that returns the seconds and microseconds portions of * the system clock and of the Tcl clock so that they can be * compared to validate that the Tcl clock is staying in sync. * * Usage: * testclock * * Parameters: * None. * * Results: * Returns a standard Tcl result comprising a four-element list: * the seconds and microseconds portions of the system clock, * and the seconds and microseconds portions of the Tcl clock. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TestwinclockCmd( ClientData dummy, /* Unused */ Tcl_Interp* interp, /* Tcl interpreter */ int objc, /* Argument count */ Tcl_Obj *CONST objv[] ) /* Argument vector */ { static CONST FILETIME posixEpoch = { 0xD53E8000, 0x019DB1DE }; /* The Posix epoch, expressed as a * Windows FILETIME */ Tcl_Time tclTime; /* Tcl clock */ FILETIME sysTime; /* System clock */ Tcl_Obj* result; /* Result of the command */ LARGE_INTEGER t1, t2; LARGE_INTEGER p1, p2; if ( objc != 1 ) { Tcl_WrongNumArgs( interp, 1, objv, "" ); return TCL_ERROR; } QueryPerformanceCounter( &p1 ); Tcl_GetTime( &tclTime ); GetSystemTimeAsFileTime( &sysTime ); t1.LowPart = posixEpoch.dwLowDateTime; t1.HighPart = posixEpoch.dwHighDateTime; t2.LowPart = sysTime.dwLowDateTime; t2.HighPart = sysTime.dwHighDateTime; t2.QuadPart -= t1.QuadPart; QueryPerformanceCounter( &p2 ); result = Tcl_NewObj(); Tcl_ListObjAppendElement ( interp, result, Tcl_NewIntObj( (int) (t2.QuadPart / 10000000 ) ) ); Tcl_ListObjAppendElement ( interp, result, Tcl_NewIntObj( (int) ( (t2.QuadPart / 10 ) % 1000000 ) ) ); Tcl_ListObjAppendElement( interp, result, Tcl_NewIntObj( tclTime.sec ) ); Tcl_ListObjAppendElement( interp, result, Tcl_NewIntObj( tclTime.usec ) ); Tcl_ListObjAppendElement( interp, result, Tcl_NewWideIntObj( p1.QuadPart ) ); Tcl_ListObjAppendElement( interp, result, Tcl_NewWideIntObj( p2.QuadPart ) ); Tcl_SetObjResult( interp, result ); return TCL_OK; } /* *---------------------------------------------------------------------- * * TestwinsleepCmd -- * * Causes this process to wait for the given number of milliseconds * by means of a direct call to Sleep. * * Usage: * testwinsleep * * Parameters: * n - the number of milliseconds to sleep * * Results: * None. * * Side effects: * Sleeps for the requisite number of milliseconds. * *---------------------------------------------------------------------- */ static int TestwinsleepCmd( ClientData clientData, /* Unused */ Tcl_Interp* interp, /* Tcl interpreter */ int objc, /* Parameter count */ Tcl_Obj * CONST * objv ) /* Parameter vector */ { int ms; if ( objc != 2 ) { Tcl_WrongNumArgs( interp, 1, objv, "ms" ); return TCL_ERROR; } if ( Tcl_GetIntFromObj( interp, objv[1], &ms ) != TCL_OK ) { return TCL_ERROR; } Sleep( (DWORD) ms ); return TCL_OK; } /* *---------------------------------------------------------------------- * * TestExceptionCmd -- * * Causes this process to end with the named exception. Used for * testing Tcl_WaitPid(). * * Usage: * testexcept * * Parameters: * Type of exception. * * Results: * None, this process closes now and doesn't return. * * Side effects: * This Tcl process closes, hard... Bang! * *---------------------------------------------------------------------- */ static int TestExceptionCmd( ClientData dummy, /* Unused */ Tcl_Interp* interp, /* Tcl interpreter */ int objc, /* Argument count */ Tcl_Obj *CONST objv[]) /* Argument vector */ { static CONST84 char *cmds[] = { "access_violation", "datatype_misalignment", "array_bounds", "float_denormal", "float_divbyzero", "float_inexact", "float_invalidop", "float_overflow", "float_stack", "float_underflow", "int_divbyzero", "int_overflow", "private_instruction", "inpageerror", "illegal_instruction", "noncontinue", "stack_overflow", "invalid_disp", "guard_page", "invalid_handle", "ctrl+c", NULL }; static const DWORD exceptions[] = { EXCEPTION_ACCESS_VIOLATION, EXCEPTION_DATATYPE_MISALIGNMENT, EXCEPTION_ARRAY_BOUNDS_EXCEEDED, EXCEPTION_FLT_DENORMAL_OPERAND, EXCEPTION_FLT_DIVIDE_BY_ZERO, EXCEPTION_FLT_INEXACT_RESULT, EXCEPTION_FLT_INVALID_OPERATION, EXCEPTION_FLT_OVERFLOW, EXCEPTION_FLT_STACK_CHECK, EXCEPTION_FLT_UNDERFLOW, EXCEPTION_INT_DIVIDE_BY_ZERO, EXCEPTION_INT_OVERFLOW, EXCEPTION_PRIV_INSTRUCTION, EXCEPTION_IN_PAGE_ERROR, EXCEPTION_ILLEGAL_INSTRUCTION, EXCEPTION_NONCONTINUABLE_EXCEPTION, EXCEPTION_STACK_OVERFLOW, EXCEPTION_INVALID_DISPOSITION, EXCEPTION_GUARD_PAGE, EXCEPTION_INVALID_HANDLE, CONTROL_C_EXIT }; int cmd; if ( objc != 2 ) { Tcl_WrongNumArgs(interp, 0, objv, ""); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[1], cmds, "command", 0, &cmd) != TCL_OK) { return TCL_ERROR; } /* * Make sure the GPF dialog doesn't popup. */ SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); /* * As Tcl does not handle structured exceptions, this falls all the way * back up the instruction stack to the C run-time portion that called * main() where the process will now be terminated with this exception * code by the default handler the C run-time provides. */ /* SMASH! */ RaiseException(exceptions[cmd], EXCEPTION_NONCONTINUABLE, 0, NULL); /* NOTREACHED */ return TCL_OK; } static int TestplatformChmod(CONST char *nativePath, int pmode) { SID_IDENTIFIER_AUTHORITY userSidAuthority = { SECURITY_WORLD_SID_AUTHORITY }; typedef DWORD (WINAPI *getSidLengthRequiredDef) ( UCHAR ); typedef BOOL (WINAPI *initializeSidDef) ( PSID, PSID_IDENTIFIER_AUTHORITY, BYTE ); typedef PDWORD (WINAPI *getSidSubAuthorityDef) ( PSID, DWORD ); static getSidLengthRequiredDef getSidLengthRequiredProc; static initializeSidDef initializeSidProc; static getSidSubAuthorityDef getSidSubAuthorityProc; static const SECURITY_INFORMATION infoBits = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION; static const DWORD readOnlyMask = FILE_DELETE_CHILD | FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY | FILE_WRITE_EA | FILE_APPEND_DATA | FILE_WRITE_DATA | DELETE; PSECURITY_DESCRIPTOR secDesc = 0; DWORD secDescLen; const BOOL set_readOnly = !(pmode & 0222); BOOL acl_readOnly_found = FALSE; ACL_SIZE_INFORMATION ACLSize; BOOL curAclPresent, curAclDefaulted; PACL curAcl; PACL newAcl = 0; DWORD newAclSize; WORD j; SID *userSid = 0; TCHAR *userDomain = NULL; DWORD attr; int res = 0; /* * One time initialization, dynamically load Windows NT features */ typedef DWORD (WINAPI *setNamedSecurityInfoADef)( IN LPSTR, IN SE_OBJECT_TYPE, IN SECURITY_INFORMATION, IN PSID, IN PSID, IN PACL, IN PACL ); typedef BOOL (WINAPI *getAceDef) (PACL, DWORD, LPVOID *); typedef BOOL (WINAPI *addAceDef) ( PACL, DWORD, DWORD, LPVOID, DWORD ); typedef BOOL (WINAPI *equalSidDef) ( PSID, PSID ); typedef BOOL (WINAPI *addAccessDeniedAceDef) ( PACL, DWORD, DWORD, PSID ); typedef BOOL (WINAPI *initializeAclDef) ( PACL, DWORD, DWORD ); typedef DWORD (WINAPI *getLengthSidDef) ( PSID ); typedef BOOL (WINAPI *getAclInformationDef) (PACL, LPVOID, DWORD, ACL_INFORMATION_CLASS ); typedef BOOL (WINAPI *getSecurityDescriptorDaclDef) (PSECURITY_DESCRIPTOR, LPBOOL, PACL *, LPBOOL ); typedef BOOL (WINAPI *lookupAccountNameADef) ( LPCSTR, LPCSTR, PSID, PDWORD, LPSTR, LPDWORD, PSID_NAME_USE ); typedef BOOL (WINAPI *getFileSecurityADef) ( LPCSTR, SECURITY_INFORMATION, PSECURITY_DESCRIPTOR, DWORD, LPDWORD ); static setNamedSecurityInfoADef setNamedSecurityInfoProc; static getAceDef getAceProc; static addAceDef addAceProc; static equalSidDef equalSidProc; static addAccessDeniedAceDef addAccessDeniedAceProc; static initializeAclDef initializeAclProc; static getLengthSidDef getLengthSidProc; static getAclInformationDef getAclInformationProc; static getSecurityDescriptorDaclDef getSecurityDescriptorDaclProc; static lookupAccountNameADef lookupAccountNameProc; static getFileSecurityADef getFileSecurityProc; static int initialized = 0; if (!initialized) { TCL_DECLARE_MUTEX(initializeMutex) Tcl_MutexLock(&initializeMutex); if (!initialized) { HINSTANCE hInstance = LoadLibrary("Advapi32"); if (hInstance != NULL) { setNamedSecurityInfoProc = (setNamedSecurityInfoADef) GetProcAddress(hInstance, "SetNamedSecurityInfoA"); getFileSecurityProc = (getFileSecurityADef) GetProcAddress(hInstance, "GetFileSecurityA"); getAceProc = (getAceDef) GetProcAddress(hInstance, "GetAce"); addAceProc = (addAceDef) GetProcAddress(hInstance, "AddAce"); equalSidProc = (equalSidDef) GetProcAddress(hInstance, "EqualSid"); addAccessDeniedAceProc = (addAccessDeniedAceDef) GetProcAddress(hInstance, "AddAccessDeniedAce"); initializeAclProc = (initializeAclDef) GetProcAddress(hInstance, "InitializeAcl"); getLengthSidProc = (getLengthSidDef) GetProcAddress(hInstance, "GetLengthSid"); getAclInformationProc = (getAclInformationDef) GetProcAddress(hInstance, "GetAclInformation"); getSecurityDescriptorDaclProc = (getSecurityDescriptorDaclDef) GetProcAddress(hInstance, "GetSecurityDescriptorDacl"); lookupAccountNameProc = (lookupAccountNameADef) GetProcAddress(hInstance, "LookupAccountNameA"); getSidLengthRequiredProc = (getSidLengthRequiredDef) GetProcAddress(hInstance, "GetSidLengthRequired"); initializeSidProc = (initializeSidDef) GetProcAddress(hInstance, "InitializeSid"); getSidSubAuthorityProc = (getSidSubAuthorityDef) GetProcAddress(hInstance, "GetSidSubAuthority"); if (setNamedSecurityInfoProc && getAceProc && addAceProc && equalSidProc && addAccessDeniedAceProc && initializeAclProc && getLengthSidProc && getAclInformationProc && getSecurityDescriptorDaclProc && lookupAccountNameProc && getFileSecurityProc && getSidLengthRequiredProc && initializeSidProc && getSidSubAuthorityProc) initialized = 1; } if (!initialized) initialized = -1; } Tcl_MutexUnlock(&initializeMutex); } /* Process the chmod request */ attr = GetFileAttributes(nativePath); /* nativePath not found */ if (attr == 0xffffffff) { res = -1; goto done; } /* If no ACL API is present or nativePath is not a directory, * there is no special handling */ if (initialized < 0 || !(attr & FILE_ATTRIBUTE_DIRECTORY)) { goto done; } /* Set the result to error, if the ACL change is successful it will * be reset to 0 */ res = -1; /* * Read the security descriptor for the directory. Note the * first call obtains the size of the security descriptor. */ if (!getFileSecurityProc(nativePath, infoBits, NULL, 0, &secDescLen)) { if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { DWORD secDescLen2 = 0; secDesc = (PSECURITY_DESCRIPTOR) ckalloc(secDescLen); if (!getFileSecurityProc(nativePath, infoBits, secDesc, secDescLen, &secDescLen2) || (secDescLen < secDescLen2)) { goto done; } } else { goto done; } } /* Get the World SID */ userSid = (SID*) ckalloc(getSidLengthRequiredProc((UCHAR)1)); initializeSidProc( userSid, &userSidAuthority, (BYTE)1); *(getSidSubAuthorityProc( userSid, 0)) = SECURITY_WORLD_RID; /* If curAclPresent == false then curAcl and curAclDefaulted not valid */ if (!getSecurityDescriptorDaclProc(secDesc, &curAclPresent, &curAcl, &curAclDefaulted)) goto done; if (!curAclPresent || !curAcl) { ACLSize.AclBytesInUse = 0; ACLSize.AceCount = 0; } else if (!getAclInformationProc(curAcl, &ACLSize, sizeof(ACLSize), AclSizeInformation)) goto done; /* Allocate memory for the new ACL */ newAclSize = ACLSize.AclBytesInUse + sizeof (ACCESS_DENIED_ACE) + getLengthSidProc(userSid) - sizeof (DWORD); newAcl = (ACL *) ckalloc (newAclSize); /* Initialize the new ACL */ if(!initializeAclProc(newAcl, newAclSize, ACL_REVISION)) { goto done; } /* Add denied to make readonly, this will be known as a "read-only tag" */ if (set_readOnly && !addAccessDeniedAceProc(newAcl, ACL_REVISION, readOnlyMask, userSid)) { goto done; } acl_readOnly_found = FALSE; for (j = 0; j < ACLSize.AceCount; j++) { PACL *pACE2; ACE_HEADER *phACE2; if (! getAceProc (curAcl, j, (LPVOID*) &pACE2)) { goto done; } phACE2 = ((ACE_HEADER *) pACE2); /* Do NOT propagate inherited ACEs */ if (phACE2->AceFlags & INHERITED_ACE) { continue; } /* Skip the "read-only tag" restriction (either added above, or it * is being removed) */ if (phACE2->AceType == ACCESS_DENIED_ACE_TYPE) { ACCESS_DENIED_ACE *pACEd = (ACCESS_DENIED_ACE *)phACE2; if (pACEd->Mask == readOnlyMask && equalSidProc(userSid, (PSID)&(pACEd->SidStart))) { acl_readOnly_found = TRUE; continue; } } /* Copy the current ACE from the old to the new ACL */ if(! addAceProc (newAcl, ACL_REVISION, MAXDWORD, pACE2, ((PACE_HEADER) pACE2)->AceSize)) { goto done; } } /* Apply the new ACL */ if (set_readOnly == acl_readOnly_found || setNamedSecurityInfoProc((LPSTR)nativePath, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, newAcl, NULL) == ERROR_SUCCESS ) { res = 0; } done: if (secDesc) ckfree((char *)secDesc); if (newAcl) ckfree((char *)newAcl); if (userSid) ckfree((char *)userSid); if (userDomain) ckfree(userDomain); if (res != 0) return res; /* Run normal chmod command */ return chmod(nativePath, pmode); } /* *--------------------------------------------------------------------------- * * TestchmodCmd -- * * Implements the "testchmod" cmd. Used when testing "file" command. * The only attribute used by the Windows platform is the user write * flag; if this is not set, the file is made read-only. Otehrwise, the * file is made read-write. * * Results: * A standard Tcl result. * * Side effects: * Changes permissions of specified files. * *--------------------------------------------------------------------------- */ static int TestchmodCmd(dummy, interp, argc, argv) ClientData dummy; /* Not used. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ CONST84 char **argv; /* Argument strings. */ { int i, mode; char *rest; if (argc < 2) { usage: Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " mode file ?file ...?", NULL); return TCL_ERROR; } mode = (int) strtol(argv[1], &rest, 8); if ((rest == argv[1]) || (*rest != '\0')) { goto usage; } for (i = 2; i < argc; i++) { Tcl_DString buffer; CONST char *translated; translated = Tcl_TranslateFileName(interp, argv[i], &buffer); if (translated == NULL) { return TCL_ERROR; } if (TestplatformChmod(translated, mode) != 0) { Tcl_AppendResult(interp, translated, ": ", Tcl_PosixError(interp), NULL); return TCL_ERROR; } Tcl_DStringFree(&buffer); } return TCL_OK; } tcl8.4.20/win/coffbase.txt0000644003604700454610000000322712153151142014012 0ustar dgp771div; ; This file defines the virtual base addresses for the Dynamic Link Libraries ; that are part of the Tcl system. The first token on a line is the key (or name ; of the DLL) and the second token is the virtual base address, in hexidecimal. ; The third token is the maximum size of the DLL image file, including symbols. ; ; Using a specified "prefered load address" should speed loading time by avoiding ; relocations (NT supported only). It is assumed extension authors will contribute ; their modules to this grand-master list. You can use the dumpbin utility with ; the /headers option to get the "size of image" data (already in hex). If the ; maximum size is too small a linker warning will occur. Modules can overlap when ; they're mutually exclusive. This info is placed in the DLL's PE header by the ; linker with the `-base:@$(TCLDIR)\win\coffbase.txt,` option. tcl 0x10000000 0x00200000 tcldde 0x10200000 0x00010000 tclreg 0x10210000 0x00010000 tk 0x10220000 0x00200000 expect 0x10480000 0x00080000 itcl 0x10500000 0x00080000 itk 0x10580000 0x00080000 bltlite 0x10600000 0x00080000 blt 0x10680000 0x00080000 iocpsock 0x10700000 0x00080000 tls 0x10780000 0x00100000 winico 0x10880000 0x00010000 sample 0x108B0000 0x00010000 tile 0x10900000 0x00080000 memchan 0x109D0000 0x00010000 tdom 0x109E0000 0x00080000 tclvfs 0x10A70000 0x00010000 tkvideo 0x10B00000 0x00010000 tclsdl 0x10B20000 0x00080000 vqtcl 0x10C00000 0x00010000 tdbc 0x10C40000 0x00010000 thread 0x10C80000 0x00020000 ; ; insert new packages here ; snack 0x1E000000 0x00400000 sound 0x1E400000 0x00400000 snackogg 0x1E800000 0x00200000 tcl8.4.20/win/makefile.bc0000644003604700454610000004411512153151142013565 0ustar dgp771div# # Makefile for Borland C++ 5.5 (or C++ Builder 5), adapted from the makefile # for Visual C++ that came with tcl 8.3.3 # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # Copyright (c) 1995-1996 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # Have a look at the complete description on how to build and test Tcl with # the current Borland compilers at www.ratiosoft.com/tcl/borland. # # Usage: # - Adapt the paths below to match your compiler's location # - Make sure the compiler's bin directory is on your path # - Open a console # - To make a debug version enter # make -fmakefile.bc -DNODEBUG=0 xxx # where 'xxx' is the target you want (e.g. 'all', 'test', ...) # Please note: I omitted the 'd' suffix for debug versions because Tcl # will always call tclpip83.dll and not tclpip83d.dll, causing an error. # ^ # Besides, the debug version goes into a separate directory, so there # should be no problem having DLLs and EXEs with the same name. # If you prefer your debug version having the 'd' suffix just uncomment # the line # #DBGX = d # # - To make a 'normal' version enter # make -fmakefile.bc xxx # where 'xxx' is the target you want (e.g. 'all', 'test', ...) # # DISCLAIMER: # This makefile has an experimental status - that is those targets which # have been modified do in fact compile and link with Borland's C++ # Builder 5 and with the free Borland compiler (Borland C++ 5.5). # However the author assumes no responsiblity for any effect which the use of # this makefile or of the resulting programs might have on your system. # # Not yet modified: # - The 'plug-in-DLL' and the associated shell. # - The programs to create the windows help files. # # Suggestions and / or improvements are always welcome. # # May 2001, H. Giese (hgiese@ratiosoft.com) # # Does not depend on the presence of any environment variables in # order to compile tcl; all needed information is derived from # location of the compiler directories. # # Project directories # # ROOT = top of source tree # # TOOLS32 = location of Borland development tools. # # INSTALLDIR = where the install-targets should copy the binaries and # support files # ROOT = .. INSTALLDIR = c:\program files\tcl # If you have C++ Builder 5 or the free Borland C++ 5.5 compiler # adapt the following paths as appropriate for your system TOOLS32 = c:\dev\bcc55 TOOLS32_rc = c:\dev\bcc55 #TOOLS32 = c:\bc55 #TOOLS32_rc = c:\bc55 cc32 = "$(TOOLS32)\bin\bcc32.exe" link32 = "$(TOOLS32)\bin\ilink32.exe" lib32 = "$(TOOLS32)\bin\tlib.exe" rc32 = "$(TOOLS32_rc)\bin\brcc32.exe" include32 = -I"$(TOOLS32)\include" libpath32 = -L"$(TOOLS32)\lib" # Uncomment the following line to compile with thread support #THREADDEFINES = -DTCL_THREADS=1 # Allow definition of NDEBUG via command line # Set NODEBUG to 0 to compile with symbols !if !defined(NODEBUG) NODEBUG = 1 !endif # The following defines can be used to control the amount of debugging # code that is added to the compilation. # # -DTCL_MEM_DEBUG Enables the debugging memory allocator. # -DTCL_COMPILE_DEBUG Enables byte compilation logging. # -DTCL_COMPILE_STATS Enables byte compilation statistics gathering. # -DUSE_TCLALLOC=0 Disables the Tcl memory allocator in favor # of the native malloc implementation. This is # needed when using Purify. # #DEBUGDEFINES = -DTCL_MEM_DEBUG -DTCL_COMPILE_DEBUG -DTCL_COMPILE_STATS #DEBUGDEFINES = -DUSE_TCLALLOC=0 ###################################################################### # Do not modify below this line ###################################################################### NAMEPREFIX = tcl STUBPREFIX = $(NAMEPREFIX)stub DOTVERSION = 8.4 VERSION = 84 DDEVERSION = 13 DDEDOTVERSION = 1.3 REGVERSION = 12 REGDOTVERSION = 1.2 BINROOT = .. !IF "$(NODEBUG)" == "1" TMPDIRNAME = Release DBGX = !ELSE TMPDIRNAME = Debug #DBGX = d DBGX = !ENDIF TMPDIR = $(BINROOT)\$(TMPDIRNAME) OUTDIRNAME = $(TMPDIRNAME) OUTDIR = $(TMPDIR) TCLLIB = $(OUTDIR)\$(NAMEPREFIX)$(VERSION)$(DBGX).lib TCLDLLNAME = $(NAMEPREFIX)$(VERSION)$(DBGX).dll TCLDLL = $(OUTDIR)\$(TCLDLLNAME) TCLSTUBLIBNAME = $(STUBPREFIX)$(VERSION)$(DBGX).lib TCLSTUBLIB = $(OUTDIR)\$(TCLSTUBLIBNAME) TCLPLUGINLIB = $(OUTDIR)\$(NAMEPREFIX)$(VERSION)p$(DBGX).lib TCLPLUGINDLLNAME = $(NAMEPREFIX)$(VERSION)p$(DBGX).dll TCLPLUGINDLL = $(OUTDIR)\$(TCLPLUGINDLLNAME) TCLSH = $(OUTDIR)\$(NAMEPREFIX)sh$(VERSION)$(DBGX).exe TCLSHP = $(OUTDIR)\$(NAMEPREFIX)shp$(VERSION)$(DBGX).exe TCLPIPEDLLNAME = $(NAMEPREFIX)pip$(VERSION)$(DBGX).dll TCLPIPEDLL = $(OUTDIR)\$(TCLPIPEDLLNAME) TCLREGDLLNAME = $(NAMEPREFIX)reg$(REGVERSION)$(DBGX).dll TCLREGDLL = $(OUTDIR)\$(TCLREGDLLNAME) TCLDDEDLLNAME = $(NAMEPREFIX)dde$(DDEVERSION)$(DBGX).dll TCLDDEDLL = $(OUTDIR)\$(TCLDDEDLLNAME) TCLTEST = $(OUTDIR)\$(NAMEPREFIX)test.exe CAT32 = $(TMPDIR)\cat32.exe RMDIR = .\rmd.bat MKDIR = .\mkd.bat RM = del LIB_INSTALL_DIR = $(INSTALLDIR)\lib BIN_INSTALL_DIR = $(INSTALLDIR)\bin SCRIPT_INSTALL_DIR = $(INSTALLDIR)\lib\tcl$(DOTVERSION) INCLUDE_INSTALL_DIR = $(INSTALLDIR)\include TCLSHOBJS = \ $(TMPDIR)\tclAppInit.obj TCLTESTOBJS = \ $(TMPDIR)\tclTest.obj \ $(TMPDIR)\tclTestObj.obj \ $(TMPDIR)\tclTestProcBodyObj.obj \ $(TMPDIR)\tclThreadTest.obj \ $(TMPDIR)\tclWinTest.obj \ $(TMPDIR)\testMain.obj TCLOBJS = \ $(TMPDIR)\regcomp.obj \ $(TMPDIR)\regexec.obj \ $(TMPDIR)\regfree.obj \ $(TMPDIR)\regerror.obj \ $(TMPDIR)\strftime.obj \ $(TMPDIR)\strtoll.obj \ $(TMPDIR)\strtoull.obj \ $(TMPDIR)\tclAlloc.obj \ $(TMPDIR)\tclAsync.obj \ $(TMPDIR)\tclBasic.obj \ $(TMPDIR)\tclBinary.obj \ $(TMPDIR)\tclCkalloc.obj \ $(TMPDIR)\tclClock.obj \ $(TMPDIR)\tclCmdAH.obj \ $(TMPDIR)\tclCmdIL.obj \ $(TMPDIR)\tclCmdMZ.obj \ $(TMPDIR)\tclCompCmds.obj \ $(TMPDIR)\tclCompExpr.obj \ $(TMPDIR)\tclCompile.obj \ $(TMPDIR)\tclDate.obj \ $(TMPDIR)\tclEncoding.obj \ $(TMPDIR)\tclEnv.obj \ $(TMPDIR)\tclEvent.obj \ $(TMPDIR)\tclExecute.obj \ $(TMPDIR)\tclFCmd.obj \ $(TMPDIR)\tclFileName.obj \ $(TMPDIR)\tclGet.obj \ $(TMPDIR)\tclHash.obj \ $(TMPDIR)\tclHistory.obj \ $(TMPDIR)\tclIndexObj.obj \ $(TMPDIR)\tclInterp.obj \ $(TMPDIR)\tclIO.obj \ $(TMPDIR)\tclIOCmd.obj \ $(TMPDIR)\tclIOGT.obj \ $(TMPDIR)\tclIOSock.obj \ $(TMPDIR)\tclIOUtil.obj \ $(TMPDIR)\tclLink.obj \ $(TMPDIR)\tclLiteral.obj \ $(TMPDIR)\tclListObj.obj \ $(TMPDIR)\tclLoad.obj \ $(TMPDIR)\tclMain.obj \ $(TMPDIR)\tclNamesp.obj \ $(TMPDIR)\tclNotify.obj \ $(TMPDIR)\tclObj.obj \ $(TMPDIR)\tclPanic.obj \ $(TMPDIR)\tclParse.obj \ $(TMPDIR)\tclParseExpr.obj \ $(TMPDIR)\tclPipe.obj \ $(TMPDIR)\tclPkg.obj \ $(TMPDIR)\tclPosixStr.obj \ $(TMPDIR)\tclPreserve.obj \ $(TMPDIR)\tclProc.obj \ $(TMPDIR)\tclRegexp.obj \ $(TMPDIR)\tclResolve.obj \ $(TMPDIR)\tclResult.obj \ $(TMPDIR)\tclScan.obj \ $(TMPDIR)\tclStringObj.obj \ $(TMPDIR)\tclStubInit.obj \ $(TMPDIR)\tclStubLib.obj \ $(TMPDIR)\tclThread.obj \ $(TMPDIR)\tclThreadJoin.obj \ $(TMPDIR)\tclTimer.obj \ $(TMPDIR)\tclUtf.obj \ $(TMPDIR)\tclUtil.obj \ $(TMPDIR)\tclVar.obj \ $(TMPDIR)\tclWin32Dll.obj \ $(TMPDIR)\tclWinChan.obj \ $(TMPDIR)\tclWinConsole.obj \ $(TMPDIR)\tclWinSerial.obj \ $(TMPDIR)\tclWinError.obj \ $(TMPDIR)\tclWinFCmd.obj \ $(TMPDIR)\tclWinFile.obj \ $(TMPDIR)\tclWinInit.obj \ $(TMPDIR)\tclWinLoad.obj \ $(TMPDIR)\tclWinMtherr.obj \ $(TMPDIR)\tclWinNotify.obj \ $(TMPDIR)\tclWinPipe.obj \ $(TMPDIR)\tclWinSock.obj \ $(TMPDIR)\tclWinThrd.obj \ $(TMPDIR)\tclWinTime.obj TCLSTUBOBJS = $(TMPDIR)\tclStubLib.obj WINDIR = $(ROOT)\win GENERICDIR = $(ROOT)\generic TCL_INCLUDES = -I"$(WINDIR)" -I"$(GENERICDIR)" TCL_DEFINES = $(DEBUGDEFINES) $(THREADDEFINES) ###################################################################### # Compiler flags ###################################################################### !IF "$(NODEBUG)" == "1" # these macros cause maximum optimization and no symbols cdebug = -v- -vi- -O2 -D_DEBUG !ELSE # these macros enable debugging cdebug = -k -Od -r- -v -vi- -y !ENDIF SYSDEFINES = _MT;NO_STRICT;_NO_VCL # declarations common to all compiler options cbase = -c -q -3 -a4 -g0 -tWM -Ve -Vx -X- WARNINGS = -w-rch -w-pch -w-par -w-dup -w-pro -w-dpu ccons = -tWC INCLUDEPATH = $(include32) $(TCL_INCLUDES) CFLAGS = $(cdebug) $(cbase) $(INCLUDEPATH) $(WARNINGS) -D$(SYSDEFINES) TCL_CFLAGS = $(CFLAGS) $(TCL_DEFINES) CONS_CFLAGS = $(CFLAGS) $(TCL_DEFINES) $(ccons) ###################################################################### # Linker flags ###################################################################### !IF "$(NODEBUG)" == "1" ldebug = !ELSE ldebug = -v !ENDIF # declarations common to all linker options LNFLAGS = -D"" -Gn -I$(TMPDIR) -x $(ldebug) $(libpath32) # -Gi: create lib file (is -Gl in doc) # -aa: Windows app, -ap: Windows console app LNFLAGS_DLL = -ap -Gi -Tpd LNFLAGS_CONS = -ap -Tpe LNLIBS = import32 cw32mt ###################################################################### # Project specific targets ###################################################################### release: setup $(TCLSH) dlls dlls: setup $(TCLPIPEDLL) $(TCLREGDLL) $(TCLDDEDLL) all: setup $(TCLSH) dlls $(CAT32) tcltest: setup $(TCLTEST) dlls $(CAT32) plugin: setup $(TCLPLUGINDLL) $(TCLSHP) install: install-binaries install-libraries test: setup $(TCLTEST) dlls $(CAT32) set TCL_LIBRARY=$(ROOT)/library $(TCLTEST) $(ROOT)/tests/all.tcl setup: @if not exist $(OUT_DIR)\nul mkdir $(OUT_DIR) &\ echo *** Created directory '$(OUT_DIR)' @if not exist $(TMP_DIR)\nul mkdir $(TMP_DIR) &\ echo *** Created directory '$(TMP_DIR)' $(TCLLIB): $(TCLDLL) $(TCLDLL): $(TCLOBJS) $(TMPDIR)\$(NAMEPREFIX).res $(link32) $(ldebug) $(LNFLAGS) $(LNFLAGS_DLL) $(TOOLS32)\lib\c0d32 @&&! $(TCLOBJS), $@, -x, $(LNLIBS),, $(TMPDIR)\$(NAMEPREFIX).res ! $(TCLSTUBLIB): $(TCLSTUBOBJS) $(lib32) /u $@ $(TCLSTUBOBJS) $(TCLPLUGINLIB): $(TCLPLUGINDLL) $(TCLPLUGINDLL): $(TCLOBJS) $(TMPDIR)\tcl.res $(link32) $(ldebug) $(dlllflags) \ -out:$@ $(TMPDIR)\tcl.res $(guilibsdll) @&&! $(TCLOBJS) ! $(TCLSH): $(TCLSHOBJS) $(TCLLIB) $(TMPDIR)\$(NAMEPREFIX)sh.res $(link32) $(ldebug) -S:2400000 $(LNFLAGS) $(LNFLAGS_CONS) $(TOOLS32)\lib\c0x32 @&&! $(TCLSHOBJS), $@, -x, $(LNLIBS) $(TCLLIB),, $(TMPDIR)\$(NAMEPREFIX)sh.res ! $(TCLSHP): $(TCLSHOBJS) $(TCLPLUGINLIB) $(TMPDIR)\tclsh.res $(link32) $(ldebug) $(conlflags) $(TMPDIR)\tclsh.res -stack:2300000 \ -out:$@ $(conlibsdll) $(TCLPLUGINLIB) $(TCLSHOBJS) $(TCLTEST): $(TCLTESTOBJS) $(TCLLIB) $(TMPDIR)\$(NAMEPREFIX)sh.res $(link32) $(ldebug) -S:2400000 $(LNFLAGS) $(LNFLAGS_CONS) $(TOOLS32)\lib\c0x32 @&&! $(TCLTESTOBJS), $@, -x, $(LNLIBS) $(TCLLIB),, $(TMPDIR)\$(NAMEPREFIX)sh.res ! $(TCLPIPEDLL): $(WINDIR)\stub16.c $(cc32) $(CFLAGS) -o$(TMPDIR)\stub16.obj $(WINDIR)\stub16.c $(link32) $(ldebug) $(LNFLAGS) $(LNFLAGS_CONS) $(TOOLS32)\lib\c0x32 \ $(TMPDIR)\stub16.obj, $@, -x, $(LNLIBS),, $(TMPDIR)\$(NAMEPREFIX).res $(TCLDDEDLL): $(TMPDIR)\tclWinDde.obj $(TCLSTUBLIB) $(link32) $(ldebug) $(LNFLAGS) $(LNFLAGS_DLL) $(TOOLS32)\lib\c0d32 \ $(TMPDIR)\tclWinDde.obj, $@, -x, $(LNLIBS) $(TCLSTUBLIB),, \ $(TMPDIR)\$(NAMEPREFIX).res $(TCLREGDLL): $(TMPDIR)\tclWinReg.obj $(TCLSTUBLIB) $(link32) $(ldebug) $(LNFLAGS) $(LNFLAGS_DLL) $(TOOLS32)\lib\c0d32 \ $(TMPDIR)\tclWinReg.obj, $@, -x, $(LNLIBS) $(TCLSTUBLIB),, \ $(TMPDIR)\$(NAMEPREFIX).res $(CAT32): $(WINDIR)\cat.c $(cc32) $(CONS_CFLAGS) -o$(TMPDIR)\cat.obj $? $(link32) $(ldebug) $(LNFLAGS) $(LNFLAGS_CONS) $(TOOLS32)\lib\c0x32 \ $(TMPDIR)\cat.obj, $@, -x, $(LNLIBS),, install-binaries: $(TCLSH) $(MKDIR) "$(BIN_INSTALL_DIR)" $(MKDIR) "$(LIB_INSTALL_DIR)" @echo installing $(TCLDLLNAME) @copy "$(TCLDLL)" "$(BIN_INSTALL_DIR)" @copy "$(TCLLIB)" "$(LIB_INSTALL_DIR)" @echo installing "$(TCLSH)" @copy "$(TCLSH)" "$(BIN_INSTALL_DIR)" @echo installing $(TCLPIPEDLLNAME) @copy "$(TCLPIPEDLL)" "$(BIN_INSTALL_DIR)" @echo installing $(TCLSTUBLIBNAME) @copy "$(TCLSTUBLIB)" "$(LIB_INSTALL_DIR)" install-libraries: -@$(MKDIR) "$(LIB_INSTALL_DIR)" -@$(MKDIR) "$(INCLUDE_INSTALL_DIR)" -@$(MKDIR) "$(SCRIPT_INSTALL_DIR)" @echo installing http1.0 -@$(MKDIR) "$(SCRIPT_INSTALL_DIR)\http1.0" -@copy "$(ROOT)\library\http1.0\http.tcl" "$(SCRIPT_INSTALL_DIR)\http1.0" -@copy "$(ROOT)\library\http1.0\pkgIndex.tcl" "$(SCRIPT_INSTALL_DIR)\http1.0" @echo installing http2.5 -@$(MKDIR) "$(SCRIPT_INSTALL_DIR)\http2.5" -@copy "$(ROOT)\library\http\http.tcl" "$(SCRIPT_INSTALL_DIR)\http2.5" -@copy "$(ROOT)\library\http\pkgIndex.tcl" "$(SCRIPT_INSTALL_DIR)\http2.5" @echo installing opt0.4 -@$(MKDIR) "$(SCRIPT_INSTALL_DIR)\opt0.4" -@copy "$(ROOT)\library\opt\optparse.tcl" "$(SCRIPT_INSTALL_DIR)\opt0.4" -@copy "$(ROOT)\library\opt\pkgIndex.tcl" "$(SCRIPT_INSTALL_DIR)\opt0.4" @echo installing msgcat1.3 -@$(MKDIR) "$(SCRIPT_INSTALL_DIR)\msgcat1.3" -@copy "$(ROOT)\library\msgcat\msgcat.tcl" "$(SCRIPT_INSTALL_DIR)\msgcat1.3" -@copy "$(ROOT)\library\msgcat\pkgIndex.tcl" "$(SCRIPT_INSTALL_DIR)\msgcat1.3" @echo installing tcltest2.2 -@$(MKDIR) "$(SCRIPT_INSTALL_DIR)\tcltest2.2" -@copy "$(ROOT)\library\tcltest\tcltest.tcl" "$(SCRIPT_INSTALL_DIR)\tcltest2.2" -@copy "$(ROOT)\library\tcltest\pkgIndex.tcl" "$(SCRIPT_INSTALL_DIR)\tcltest2.2" @echo installing $(TCLDDEDLLNAME) -@$(MKDIR) "$(SCRIPT_INSTALL_DIR)\dde1.1" -@copy "$(TCLDDEDLL)" "$(SCRIPT_INSTALL_DIR)\dde1.1" -@copy "$(ROOT)\library\dde\pkgIndex.tcl" "$(SCRIPT_INSTALL_DIR)\dde1.1" @echo installing $(TCLREGDLLNAME) -@$(MKDIR) "$(SCRIPT_INSTALL_DIR)\reg1.1" -@copy "$(TCLREGDLL)" "$(SCRIPT_INSTALL_DIR)\reg1.1" -@copy "$(ROOT)\library\reg\pkgIndex.tcl" "$(SCRIPT_INSTALL_DIR)\reg1.1" @echo installing encoding files -@$(MKDIR) "$(SCRIPT_INSTALL_DIR)\encoding" -@copy "$(ROOT)\library\encoding\*.enc" "$(SCRIPT_INSTALL_DIR)\encoding" @echo installing library files -@copy "$(GENERICDIR)\tcl.h" "$(INCLUDE_INSTALL_DIR)" -@copy "$(GENERICDIR)\tclDecls.h" "$(INCLUDE_INSTALL_DIR)" -@copy "$(GENERICDIR)\tclPlatDecls.h" "$(INCLUDE_INSTALL_DIR)" -@copy "$(ROOT)\library\history.tcl" "$(SCRIPT_INSTALL_DIR)" -@copy "$(ROOT)\library\init.tcl" "$(SCRIPT_INSTALL_DIR)" -@copy "$(ROOT)\library\ldAout.tcl" "$(SCRIPT_INSTALL_DIR)" -@copy "$(ROOT)\library\parray.tcl" "$(SCRIPT_INSTALL_DIR)" -@copy "$(ROOT)\library\safe.tcl" "$(SCRIPT_INSTALL_DIR)" -@copy "$(ROOT)\library\tclIndex" "$(SCRIPT_INSTALL_DIR)" -@copy "$(ROOT)\library\package.tcl" "$(SCRIPT_INSTALL_DIR)" -@copy "$(ROOT)\library\word.tcl" "$(SCRIPT_INSTALL_DIR)" -@copy "$(ROOT)\library\auto.tcl" "$(SCRIPT_INSTALL_DIR)" # # Regenerate the stubs files. # genstubs: tclsh$(VERSION) $(ROOT)\tools\genStubs.tcl $(GENERICDIR) \ $(GENERICDIR)\tcl.decls $(GENERICDIR)\tclInt.decls # # Regenerate the windows help files. # TCLTOOLS = $(ROOT)/tools MAN2TCL = $(TCLTOOLS)/man2tcl TCLRTF = $(TCLTOOLS)/tcl.rtf TCLHPJ = $(TCLTOOLS)/tcl.hpj MAN2HELP = $(TCLTOOLS)/man2help.tcl HCRTF = $(TOOLS32)/bin/hcrtf.exe winhelp: $(TCLRTF) cd $(TCLTOOLS) start /wait $(HCRTF) -xn $(TCLHPJ) $(MAN2TCL).exe: $(MAN2TCL).obj cd $(TCLTOOLS) $(cc32) /nologo /G4 /ML /O2 $(MAN2TCL).c $(TCLRTF): $(MAN2TCL).exe $(TCLSH) cd $(TCLTOOLS) ..\win\$(TCLSH) $(MAN2HELP) $(NAMEPREFIX) $(VERSION) $(ROOT)/doc ../../tk$(DOTVERSION)/doc # # Special case object file targets # $(TMPDIR)\tclWinInit.obj: $(WINDIR)\tclWinInit.c $(cc32) -DBUILD_tcl $(TCL_CFLAGS) -o$(TMPDIR)\$@ $? $(TMPDIR)\testMain.obj: $(WINDIR)\tclAppInit.c $(cc32) $(TCL_CFLAGS) -DTCL_TEST -o$(TMPDIR)\testMain.obj $? $(TMPDIR)\tclTest.obj: $(GENERICDIR)\tclTest.c $(cc32) $(TCL_CFLAGS) -o$(TMPDIR)\$@ $? $(TMPDIR)\tclTestObj.obj: $(GENERICDIR)\tclTestObj.c $(cc32) $(TCL_CFLAGS) -o$(TMPDIR)\$@ $? $(TMPDIR)\tclWinTest.obj: $(WINDIR)\tclWinTest.c $(cc32) $(TCL_CFLAGS) -o$(TMPDIR)\$@ $? $(TMPDIR)\tclAppInit.obj : $(WINDIR)\tclAppInit.c $(cc32) $(TCL_CFLAGS) -o$(TMPDIR)\$@ $? # The following objects should be built using the stub interfaces # tclWinReg: Produces errors in ANSI mode $(TMPDIR)\tclWinReg.obj : $(WINDIR)\tclWinReg.c $(cc32) $(TCL_CFLAGS) -DUSE_TCL_STUBS -o$(TMPDIR)\$@ $? # tclWinDde: Produces errors in ANSI mode $(TMPDIR)\tclWinDde.obj : $(WINDIR)\tclWinDde.c $(cc32) $(TCL_CFLAGS) -DUSE_TCL_STUBS -o$(TMPDIR)\$@ $? # The following objects are part of the stub library and should not # be built as DLL objects but none of the symbols should be exported $(TMPDIR)\tclStubLib.obj : $(GENERICDIR)\tclStubLib.c $(cc32) $(TCL_CFLAGS) -DSTATIC_BUILD -o$(TMPDIR)\$@ $? # Dedependency rules $(GENERICDIR)\regcomp.c: \ $(GENERICDIR)\regguts.h \ $(GENERICDIR)\regc_lex.c \ $(GENERICDIR)\regc_color.c \ $(GENERICDIR)\regc_nfa.c \ $(GENERICDIR)\regc_cvec.c \ $(GENERICDIR)\regc_locale.c $(GENERICDIR)\regcustom.h: \ $(GENERICDIR)\tclInt.h \ $(GENERICDIR)\tclPort.h \ $(GENERICDIR)\regex.h $(GENERICDIR)\regexec.c: \ $(GENERICDIR)\rege_dfa.c \ $(GENERICDIR)\regguts.h $(GENERICDIR)\regerror.c: $(GENERICDIR)\regguts.h $(GENERICDIR)\regfree.c: $(GENERICDIR)\regguts.h $(GENERICDIR)\regfronts.c: $(GENERICDIR)\regguts.h $(GENERICDIR)\regguts.h: $(GENERICDIR)\regcustom.h # # Implicit rules # {$(WINDIR)}.c{$(TMPDIR)}.obj: $(cc32) -DBUILD_tcl $(TCL_CFLAGS) -o$@ $< {$(GENERICDIR)}.c{$(TMPDIR)}.obj: $(cc32) -DBUILD_tcl $(TCL_CFLAGS) -o$@ $< {$(ROOT)\compat}.c{$(TMPDIR)}.obj: $(cc32) -DBUILD_tcl $(TCL_CFLAGS) -o$@ $< {$(WINDIR)}.rc{$(TMPDIR)}.res: $(rc32) $(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -fo$@ $< clean: -@$(RM) $(OUTDIR)\*.exp -@$(RM) $(OUTDIR)\*.lib -@$(RM) $(OUTDIR)\*.dll -@$(RM) $(OUTDIR)\*.exe -@$(RM) $(OUTDIR)\*.pdb -@$(RM) $(TMPDIR)\*.pch -@$(RM) $(TMPDIR)\*.obj -@$(RM) $(TMPDIR)\*.res -@$(RM) $(TMPDIR)\*.exe -@$(RMDIR) $(OUTDIR) -@$(RMDIR) $(TMPDIR) tcl8.4.20/win/tclConfig.sh.in0000644003604700454610000001451612153151142014355 0ustar dgp771div# tclConfig.sh -- # # This shell script (for sh) is generated automatically by Tcl's # configure script. It will create shell variables for most of # the configuration options discovered by the configure script. # This script is intended to be included by the configure scripts # for Tcl extensions so that they don't have to figure this all # out for themselves. # # The information in this file is specific to a single platform. TCL_DLL_FILE="@TCL_DLL_FILE@" # Tcl's version number. TCL_VERSION='@TCL_VERSION@' TCL_MAJOR_VERSION='@TCL_MAJOR_VERSION@' TCL_MINOR_VERSION='@TCL_MINOR_VERSION@' TCL_PATCH_LEVEL='@TCL_PATCH_LEVEL@' # C compiler to use for compilation. TCL_CC='@CC@' # -D flags for use with the C compiler. TCL_DEFS='@DEFS@' # If TCL was built with debugging symbols, generated libraries contain # this string at the end of the library name (before the extension). TCL_DBGX=@TCL_DBGX@ # Default flags used in an optimized and debuggable build, respectively. TCL_CFLAGS_DEBUG='@CFLAGS_DEBUG@' TCL_CFLAGS_OPTIMIZE='@CFLAGS_OPTIMIZE@' # Default linker flags used in an optimized and debuggable build, respectively. TCL_LDFLAGS_DEBUG='@LDFLAGS_DEBUG@' TCL_LDFLAGS_OPTIMIZE='@LDFLAGS_OPTIMIZE@' # Flag, 1: we built a shared lib, 0 we didn't TCL_SHARED_BUILD=@TCL_SHARED_BUILD@ # The name of the Tcl library (may be either a .a file or a shared library): TCL_LIB_FILE='@TCL_LIB_FILE@' # Flag to indicate whether shared libraries need export files. TCL_NEEDS_EXP_FILE=@TCL_NEEDS_EXP_FILE@ # String that can be evaluated to generate the part of the export file # name that comes after the "libxxx" (includes version number, if any, # extension, and anything else needed). May depend on the variables # VERSION. On most UNIX systems this is ${VERSION}.exp. TCL_EXPORT_FILE_SUFFIX='@CFG_TCL_EXPORT_FILE_SUFFIX@' # Additional libraries to use when linking Tcl. TCL_LIBS='@LIBS@' # Top-level directory in which Tcl's platform-independent files are # installed. TCL_PREFIX='@prefix@' # Top-level directory in which Tcl's platform-specific files (e.g. # executables) are installed. TCL_EXEC_PREFIX='@exec_prefix@' # Flags to pass to cc when compiling the components of a shared library: TCL_SHLIB_CFLAGS='@SHLIB_CFLAGS@' # Flags to pass to cc to get warning messages TCL_CFLAGS_WARNING='@CFLAGS_WARNING@' # Extra flags to pass to cc: TCL_EXTRA_CFLAGS='@EXTRA_CFLAGS@' # Base command to use for combining object files into a shared library: TCL_SHLIB_LD='@SHLIB_LD@' # Base command to use for combining object files into a static library: TCL_STLIB_LD='@STLIB_LD@' # Either '$LIBS' (if dependent libraries should be included when linking # shared libraries) or an empty string. See Tcl's configure.in for more # explanation. TCL_SHLIB_LD_LIBS='@SHLIB_LD_LIBS@' # Suffix to use for the name of a shared library. TCL_SHLIB_SUFFIX='@SHLIB_SUFFIX@' # Library file(s) to include in tclsh and other base applications # in order to provide facilities needed by DLOBJ above. TCL_DL_LIBS='@DL_LIBS@' # Flags to pass to the compiler when linking object files into # an executable tclsh or tcltest binary. TCL_LD_FLAGS='@LDFLAGS@' # Flags to pass to ld, such as "-R /usr/local/tcl/lib", that tell the # run-time dynamic linker where to look for shared libraries such as # libtcl.so. Used when linking applications. Only works if there # is a variable "LIB_RUNTIME_DIR" defined in the Makefile. TCL_LD_SEARCH_FLAGS='@TCL_LD_SEARCH_FLAGS@' # Additional object files linked with Tcl to provide compatibility # with standard facilities from ANSI C or POSIX. TCL_COMPAT_OBJS='@LIBOBJS@' # Name of the ranlib program to use. TCL_RANLIB='@RANLIB@' # -l flag to pass to the linker to pick up the Tcl library TCL_LIB_FLAG='@TCL_LIB_FLAG@' # String to pass to linker to pick up the Tcl library from its # build directory. TCL_BUILD_LIB_SPEC='@TCL_BUILD_LIB_SPEC@' # String to pass to linker to pick up the Tcl library from its # installed directory. TCL_LIB_SPEC='@TCL_LIB_SPEC@' # String to pass to the compiler so that an extension can # find installed Tcl headers. TCL_INCLUDE_SPEC='@TCL_INCLUDE_SPEC@' # Indicates whether a version numbers should be used in -l switches # ("ok" means it's safe to use switches like -ltcl7.5; "nodots" means # use switches like -ltcl75). SunOS and FreeBSD require "nodots", for # example. TCL_LIB_VERSIONS_OK='@TCL_LIB_VERSIONS_OK@' # String that can be evaluated to generate the part of a shared library # name that comes after the "libxxx" (includes version number, if any, # extension, and anything else needed). May depend on the variables # VERSION and SHLIB_SUFFIX. On most UNIX systems this is # ${VERSION}${SHLIB_SUFFIX}. TCL_SHARED_LIB_SUFFIX='@CFG_TCL_SHARED_LIB_SUFFIX@' # String that can be evaluated to generate the part of an unshared library # name that comes after the "libxxx" (includes version number, if any, # extension, and anything else needed). May depend on the variable # VERSION. On most UNIX systems this is ${VERSION}.a. TCL_UNSHARED_LIB_SUFFIX='@CFG_TCL_UNSHARED_LIB_SUFFIX@' # Location of the top-level source directory from which Tcl was built. # This is the directory that contains a README file as well as # subdirectories such as generic, unix, etc. If Tcl was compiled in a # different place than the directory containing the source files, this # points to the location of the sources, not the location where Tcl was # compiled. TCL_SRC_DIR='@TCL_SRC_DIR@' # List of standard directories in which to look for packages during # "package require" commands. Contains the "prefix" directory plus also # the "exec_prefix" directory, if it is different. TCL_PACKAGE_PATH='@TCL_PACKAGE_PATH@' # Tcl supports stub. TCL_SUPPORTS_STUBS=1 # The name of the Tcl stub library (.a): TCL_STUB_LIB_FILE='@TCL_STUB_LIB_FILE@' # -l flag to pass to the linker to pick up the Tcl stub library TCL_STUB_LIB_FLAG='@TCL_STUB_LIB_FLAG@' # String to pass to linker to pick up the Tcl stub library from its # build directory. TCL_BUILD_STUB_LIB_SPEC='@TCL_BUILD_STUB_LIB_SPEC@' # String to pass to linker to pick up the Tcl stub library from its # installed directory. TCL_STUB_LIB_SPEC='@TCL_STUB_LIB_SPEC@' # Path to the Tcl stub library in the build directory. TCL_BUILD_STUB_LIB_PATH='@TCL_BUILD_STUB_LIB_PATH@' # Path to the Tcl stub library in the install directory. TCL_STUB_LIB_PATH='@TCL_STUB_LIB_PATH@' # Flag, 1: we built Tcl with threads enables, 0 we didn't TCL_THREADS=@TCL_THREADS@ tcl8.4.20/win/tclsh.ico0000644003604700454610000000705611737050675013336 0ustar dgp771div шF 0.(^ Ј†( @€€€€€€€€€€РРР€€€џџџџџџџџџџџџx€€p€€ŒЬФ€ЬЬЬ €ЬЬЬФ@€ Ч|ЬЬЬФˆ ЬwЬЬЬЬ@€ЬЧŒЬЬЬФЬЬ|ЬЬЬЬ@€ЬЬЧЬЬЬЬФ ЬЬ|ЬЬЬФ ЬЬЧЬЬЬФЬЬЬ|ЬЬФ ЬЬЧЬЬЬФ ЬЬЬ|ЬЬЬ@ЬЬЬШЬЬЬРЬЬЬЬŒЬЬФ ЬЬЬШЬЬЬ@ЬЬЬЬЬЬЬР€ ЬЬЬЬЬЬФ€€ЬЬЬЬЬЬЬ ЬЬЬЬЬЬ@€ЬЬЬЬЬЬР€ЬЬЬЬЬФˆ ЬЬЬЬЬ€ˆ ЬЬЬЬ ЬЬЬЬЬЯџџџяџџџчџџџїџџџћџџџєљџєўњџПљпј<џјќПќпќџўџўџџџџ€џ€?џР?џРџрџ№їјї|ћОћп§яРўѓрџ|јџџўџџџУ( @џџџяџџџчџџџїџџџѓџџџљџџџќљџўўћџПљпј€<џј@ќ@Пќ пќџўџўџџџџџ€€?џР@?џРџрџ№їјї|ћОћп§яРўѓрџ|јџџўџџџУ( Р€€€€€€€€€РРР€€€џџџџџџџџџџџџ€€Ь€РŒЬЬЬР€LРŒЬЬxЬРLЧŒЬLЬШЬЬЬЬЬLЬЬЬ€LЬЬР€LЬРDNПџŸџЯчућрпаoШ7Фр№№јЌЖл€яр( @€€€€€€€€€€РРРРмР№ЪІ """)))UUUMMMBBB999€|џPPџ“жџьЬЦжяжччЉ­3f™Ь3333f3™3Ь3џff3fff™fЬfџ™™3™f™™™Ь™џЬЬ3ЬfЬ™ЬЬЬџџfџ™џЬ3333f3™3Ь3џ3333333f33™33Ь33џ3f3f33ff3f™3fЬ3fџ3™3™33™f3™™3™Ь3™џ3Ь3Ь33Ьf3Ь™3ЬЬ3Ьџ3џ33џf3џ™3џЬ3џџff3fff™fЬfџf3f33f3ff3™f3Ьf3џffff3fffff™ffЬf™f™3f™ff™™f™Ьf™џfЬfЬ3fЬ™fЬЬfЬџfџfџ3fџ™fџЬЬџџЬ™™™3™™™™Ь™™33™f™3Ь™џ™f™f3™3f™f™™fЬ™3џ™™3™™f™™™™™Ь™™џ™Ь™Ь3fЬf™Ь™™ЬЬ™Ьџ™џ™џ3™Ьf™џ™™џЬ™џџЬ™3ЬfЬ™ЬЬ™3Ь33Ь3fЬ3™Ь3ЬЬ3џЬfЬf3™ffЬf™ЬfЬ™fџЬ™Ь™3Ь™fЬ™™Ь™ЬЬ™џЬЬЬЬ3ЬЬfЬЬ™ЬЬЬЬЬџЬџЬџ3™џfЬџ™ЬџЬЬџџЬ3џfџ™Ь3џ33џ3fџ3™џ3Ьџ3џџfџf3Ьffџf™џfЬЬfџџ™џ™3џ™fџ™™џ™Ьџ™џџЬџЬ3џЬfџЬ™џЬЬџЬџџџ3Ьџfџџ™џџЬffџfџffџџџffџfџџџf!Ѕ___www†††–––ЫЫЫВВВзззнннуууъъъёёёјјј№ћџЄ  €€€џџџџџџџџџџџџјјјјјјјјјЧЁЁЁјјјјЁЁЁЁЁЁјќјЧЁЁЁЁЁЁјЁќїЧЁЁЁЁЁЁЁјјЁќќїЁЁЁЁЁЁЁЁјЁќќјЁЁЁЁЁЁЁЁјЁќќќЧЁЁЁЁЁЁЁЁјЁќќќќЧЁЁЁЁЁЁЁЁЁќќќќЧЁЁЁЁЁЁЁЁќќќќќЧЁЁЁЁЁЁЁќќќќќїЁЁЁЁЁЁЁќќќќќїЁЁЁЁЁЁЁЁќќќќЧќїЁЁЁЁЁЁЁЁќЧќќќќјЁЁЁЁЁЁЁЁќќќќЧќЧјЁЁЁЁЁЁЁќќЧќЧќЧЎЁЁЁЁЁЁЁќќЧќЧЧЧќЁЁЁЁЁЁјЁЧќЧќЧЧЧќЁЁЁЁЁјјЁЧќЧЧЧЧЧќЁЁЁЁЁјјЁќЧЧЧЧЧЧќЁЁЁЁјјЁЁќЧЧЧЧЧќЁЁЁЁјјЁќЧЧЧЧЧќЁЁЁјјјЁЁќЧЧЧЧќЁЁЁјјјЁЁќЧЧЧќЁЁЁЁЁќЧќЁЁЁЁЁЯџџџяџџџчџџџїџџџћџџџєљџєўњџПљпј<џјќПќпќџўџўџџџџ€џ€?џР?џРџрџ№їјї|ћОћп§яРўѓрџ|јџџўџџџУtcl8.4.20/win/tclWinLoad.c0000644003604700454610000001512511737050675013725 0ustar dgp771div/* * tclWinLoad.c -- * * This procedure provides a version of the TclLoadFile that * works with the Windows "LoadLibrary" and "GetProcAddress" * API for dynamic loading. * * Copyright (c) 1995-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclWinInt.h" /* *---------------------------------------------------------------------- * * TclpDlopen -- * * Dynamically loads a binary code file into memory and returns * a handle to the new code. * * Results: * A standard Tcl completion code. If an error occurs, an error * message is left in the interp's result. * * Side effects: * New code suddenly appears in memory. * *---------------------------------------------------------------------- */ int TclpDlopen(interp, pathPtr, loadHandle, unloadProcPtr) Tcl_Interp *interp; /* Used for error reporting. */ Tcl_Obj *pathPtr; /* Name of the file containing the desired * code (UTF-8). */ Tcl_LoadHandle *loadHandle; /* Filled with token for dynamically loaded * file which will be passed back to * (*unloadProcPtr)() to unload the file. */ Tcl_FSUnloadFileProc **unloadProcPtr; /* Filled with address of Tcl_FSUnloadFileProc * function which should be used for * this file. */ { HINSTANCE handle; CONST TCHAR *nativeName; /* * First try the full path the user gave us. This is particularly * important if the cwd is inside a vfs, and we are trying to load * using a relative path. */ nativeName = Tcl_FSGetNativePath(pathPtr); handle = (*tclWinProcs->loadLibraryExProc)(nativeName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); if (handle == NULL) { /* * Let the OS loader examine the binary search path for * whatever string the user gave us which hopefully refers * to a file on the binary path */ Tcl_DString ds; char *fileName = Tcl_GetString(pathPtr); nativeName = Tcl_WinUtfToTChar(fileName, -1, &ds); handle = (*tclWinProcs->loadLibraryExProc)(nativeName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); Tcl_DStringFree(&ds); } *loadHandle = (Tcl_LoadHandle) handle; if (handle == NULL) { DWORD lastError = GetLastError(); #if 0 /* * It would be ideal if the FormatMessage stuff worked better, * but unfortunately it doesn't seem to want to... */ LPTSTR lpMsgBuf; char *buf; int size; size = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, lastError, 0, (LPTSTR) &lpMsgBuf, 0, NULL); buf = (char *) ckalloc((unsigned) TCL_INTEGER_SPACE + size + 1); sprintf(buf, "%d %s", lastError, (char *)lpMsgBuf); #endif Tcl_AppendResult(interp, "couldn't load library \"", Tcl_GetString(pathPtr), "\": ", (char *) NULL); /* * Check for possible DLL errors. This doesn't work quite right, * because Windows seems to only return ERROR_MOD_NOT_FOUND for * just about any problem, but it's better than nothing. It'd be * even better if there was a way to get what DLLs */ switch (lastError) { case ERROR_MOD_NOT_FOUND: case ERROR_DLL_NOT_FOUND: Tcl_AppendResult(interp, "this library or a dependent library", " could not be found in library path", (char *) NULL); break; case ERROR_PROC_NOT_FOUND: Tcl_AppendResult(interp, "could not find specified procedure", (char *) NULL); break; case ERROR_INVALID_DLL: Tcl_AppendResult(interp, "this library or a dependent library", " is damaged", (char *) NULL); break; case ERROR_DLL_INIT_FAILED: Tcl_AppendResult(interp, "the library initialization", " routine failed", (char *) NULL); break; default: TclWinConvertError(lastError); Tcl_AppendResult(interp, Tcl_PosixError(interp), (char *) NULL); } return TCL_ERROR; } else { *unloadProcPtr = &TclpUnloadFile; } return TCL_OK; } /* *---------------------------------------------------------------------- * * TclpFindSymbol -- * * Looks up a symbol, by name, through a handle associated with * a previously loaded piece of code (shared library). * * Results: * Returns a pointer to the function associated with 'symbol' if * it is found. Otherwise returns NULL and may leave an error * message in the interp's result. * *---------------------------------------------------------------------- */ Tcl_PackageInitProc* TclpFindSymbol(interp, loadHandle, symbol) Tcl_Interp *interp; Tcl_LoadHandle loadHandle; CONST char *symbol; { Tcl_PackageInitProc *proc = NULL; HINSTANCE handle = (HINSTANCE)loadHandle; /* * For each symbol, check for both Symbol and _Symbol, since Borland * generates C symbols with a leading '_' by default. */ proc = (Tcl_PackageInitProc *) GetProcAddress(handle, symbol); if (proc == NULL) { Tcl_DString ds; Tcl_DStringInit(&ds); Tcl_DStringAppend(&ds, "_", 1); symbol = Tcl_DStringAppend(&ds, symbol, -1); proc = (Tcl_PackageInitProc *) GetProcAddress(handle, symbol); Tcl_DStringFree(&ds); } return proc; } /* *---------------------------------------------------------------------- * * TclpUnloadFile -- * * Unloads a dynamically loaded binary code file from memory. * Code pointers in the formerly loaded file are no longer valid * after calling this function. * * Results: * None. * * Side effects: * Code removed from memory. * *---------------------------------------------------------------------- */ void TclpUnloadFile(loadHandle) Tcl_LoadHandle loadHandle; /* loadHandle returned by a previous call * to TclpDlopen(). The loadHandle is * a token that represents the loaded * file. */ { HINSTANCE handle; handle = (HINSTANCE) loadHandle; FreeLibrary(handle); } /* *---------------------------------------------------------------------- * * TclGuessPackageName -- * * If the "load" command is invoked without providing a package * name, this procedure is invoked to try to figure it out. * * Results: * Always returns 0 to indicate that we couldn't figure out a * package name; generic code will then try to guess the package * from the file name. A return value of 1 would have meant that * we figured out the package name and put it in bufPtr. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclGuessPackageName(fileName, bufPtr) CONST char *fileName; /* Name of file containing package (already * translated to local form if needed). */ Tcl_DString *bufPtr; /* Initialized empty dstring. Append * package name to this if possible. */ { return 0; } tcl8.4.20/win/cat.c0000644003604700454610000000111411737050675012425 0ustar dgp771div/* * cat.c -- * * Program used when testing tclWinPipe.c * * Copyright (c) 1996 by Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include #include #include int main() { char buf[1024]; int n; char *err; while (1) { n = read(0, buf, sizeof(buf)); if (n <= 0) { break; } write(1, buf, n); } err = (sizeof(int) == 2) ? "stderr16" : "stderr32"; write(2, err, strlen(err)); return 0; } tcl8.4.20/win/stub16.c0000644003604700454610000001267411737050675013017 0ustar dgp771div/* * stub16.c * * A helper program used for running 16-bit DOS applications under * Windows 95. * * Copyright (c) 1996 by Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #define STRICT #include #include static HANDLE CreateTempFile(void); /* *--------------------------------------------------------------------------- * * main * * Entry point for the 32-bit console mode app used by Windows 95 to * help run the 16-bit program specified on the command line. * * 1. EOF on a pipe that connects a detached 16-bit process and a * 32-bit process is never seen. So, this process runs the 16-bit * process _attached_, and then it is run detached from the calling * 32-bit process. * * 2. If a 16-bit process blocks reading from or writing to a pipe, * it never wakes up, and eventually brings the whole system down * with it if you try to kill the process. This app simulates * pipes. If any of the stdio handles is a pipe, this program * accumulates information into temp files and forwards it to or * from the DOS application as appropriate. This means that this * program must receive EOF from a stdin pipe before it will actually * start the DOS app, and the DOS app must finish generating stdout * or stderr before the data will be sent to the next stage of the * pipe. If the stdio handles are not pipes, no accumulation occurs * and the data is passed straight through to and from the DOS * application. * * Results: * None. * * Side effects: * The child process is created and this process waits for it to * complete. * *--------------------------------------------------------------------------- */ int main() { DWORD dwRead, dwWrite; char *cmdLine; HANDLE hStdInput, hStdOutput, hStdError; HANDLE hFileInput, hFileOutput, hFileError; STARTUPINFO si; PROCESS_INFORMATION pi; char buf[8192]; DWORD result; hFileInput = INVALID_HANDLE_VALUE; hFileOutput = INVALID_HANDLE_VALUE; hFileError = INVALID_HANDLE_VALUE; result = 1; /* * Don't get command line from argc, argv, because the command line * tokenizer will have stripped off all the escape sequences needed * for quotes and backslashes, and then we'd have to put them all * back in again. Get the raw command line and parse off what we * want ourselves. The command line should be of the form: * * stub16.exe program arg1 arg2 ... */ cmdLine = strchr(GetCommandLine(), ' '); if (cmdLine == NULL) { return 1; } cmdLine++; hStdInput = GetStdHandle(STD_INPUT_HANDLE); hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); hStdError = GetStdHandle(STD_ERROR_HANDLE); if (GetFileType(hStdInput) == FILE_TYPE_PIPE) { hFileInput = CreateTempFile(); if (hFileInput == INVALID_HANDLE_VALUE) { goto cleanup; } while (ReadFile(hStdInput, buf, sizeof(buf), &dwRead, NULL) != FALSE) { if (dwRead == 0) { break; } if (WriteFile(hFileInput, buf, dwRead, &dwWrite, NULL) == FALSE) { goto cleanup; } } SetFilePointer(hFileInput, 0, 0, FILE_BEGIN); SetStdHandle(STD_INPUT_HANDLE, hFileInput); } if (GetFileType(hStdOutput) == FILE_TYPE_PIPE) { hFileOutput = CreateTempFile(); if (hFileOutput == INVALID_HANDLE_VALUE) { goto cleanup; } SetStdHandle(STD_OUTPUT_HANDLE, hFileOutput); } if (GetFileType(hStdError) == FILE_TYPE_PIPE) { hFileError = CreateTempFile(); if (hFileError == INVALID_HANDLE_VALUE) { goto cleanup; } SetStdHandle(STD_ERROR_HANDLE, hFileError); } ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); if (CreateProcess(NULL, cmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi) == FALSE) { goto cleanup; } WaitForInputIdle(pi.hProcess, 5000); WaitForSingleObject(pi.hProcess, INFINITE); GetExitCodeProcess(pi.hProcess, &result); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); if (hFileOutput != INVALID_HANDLE_VALUE) { SetFilePointer(hFileOutput, 0, 0, FILE_BEGIN); while (ReadFile(hFileOutput, buf, sizeof(buf), &dwRead, NULL) != FALSE) { if (dwRead == 0) { break; } if (WriteFile(hStdOutput, buf, dwRead, &dwWrite, NULL) == FALSE) { break; } } } if (hFileError != INVALID_HANDLE_VALUE) { SetFilePointer(hFileError, 0, 0, FILE_BEGIN); while (ReadFile(hFileError, buf, sizeof(buf), &dwRead, NULL) != FALSE) { if (dwRead == 0) { break; } if (WriteFile(hStdError, buf, dwRead, &dwWrite, NULL) == FALSE) { break; } } } cleanup: if (hFileInput != INVALID_HANDLE_VALUE) { CloseHandle(hFileInput); } if (hFileOutput != INVALID_HANDLE_VALUE) { CloseHandle(hFileOutput); } if (hFileError != INVALID_HANDLE_VALUE) { CloseHandle(hFileError); } CloseHandle(hStdInput); CloseHandle(hStdOutput); CloseHandle(hStdError); ExitProcess(result); return 1; } static HANDLE CreateTempFile() { char name[MAX_PATH]; SECURITY_ATTRIBUTES sa; if (GetTempPath(sizeof(name), name) == 0) { return INVALID_HANDLE_VALUE; } if (GetTempFileName(name, "tcl", 0, name) == 0) { return INVALID_HANDLE_VALUE; } sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; return CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, NULL); } tcl8.4.20/win/tclWinPort.h0000644003604700454610000003053411737050675014000 0ustar dgp771div/* * tclWinPort.h -- * * This header file handles porting issues that occur because of * differences between Windows and Unix. It should be the only * file that contains #ifdefs to handle different flavors of OS. * * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef _TCLWINPORT #define _TCLWINPORT #ifndef _TCLINT # include "tclInt.h" #endif #ifdef CHECK_UNICODE_CALLS # define _UNICODE # define UNICODE # define __TCHAR_DEFINED typedef float *_TCHAR; # define _TCHAR_DEFINED typedef float *TCHAR; #endif /* CHECK_UNICODE_CALLS */ /* *--------------------------------------------------------------------------- * The following sets of #includes and #ifdefs are required to get Tcl to * compile under the windows compilers. *--------------------------------------------------------------------------- */ #include #include #include #include #include #include #include #include #include #include /* * Need to block out these includes for building extensions with MetroWerks * compiler for Win32. */ #ifndef __MWERKS__ #include #include # ifdef __BORLANDC__ # include # else # include # endif /* __BORLANDC__ */ #endif /* __MWERKS__ */ #include #define WIN32_LEAN_AND_MEAN #include #undef WIN32_LEAN_AND_MEAN /* Compatibility to older visual studio / windows platform SDK */ #if !defined(MAXULONG_PTR) typedef DWORD DWORD_PTR; typedef DWORD_PTR * PDWORD_PTR; #endif /* * Ask for the winsock function typedefs, also. */ #define INCL_WINSOCK_API_TYPEDEFS 1 #include #ifdef BUILD_tcl # undef TCL_STORAGE_CLASS # define TCL_STORAGE_CLASS DLLEXPORT #endif /* BUILD_tcl */ /* * Define EINPROGRESS in terms of WSAEINPROGRESS. */ #undef EINPROGRESS #define EINPROGRESS WSAEINPROGRESS /* * Define ENOTSUP to a value that will never occur. */ #undef ENOTSUP #define ENOTSUP -1030507 /* Those codes, from Visual Studio 2010, conflict with other values */ #undef ENODATA #undef ENOMSG #undef ENOSR #undef ENOSTR #undef EPROTO /* * The following defines redefine the Windows Socket errors as * BSD errors so Tcl_PosixError can do the right thing. */ #undef EWOULDBLOCK #define EWOULDBLOCK EAGAIN #undef EALREADY #define EALREADY 149 /* operation already in progress */ #undef ENOTSOCK #define ENOTSOCK 95 /* Socket operation on non-socket */ #undef EDESTADDRREQ #define EDESTADDRREQ 96 /* Destination address required */ #undef EMSGSIZE #define EMSGSIZE 97 /* Message too long */ #undef EPROTOTYPE #define EPROTOTYPE 98 /* Protocol wrong type for socket */ #undef ENOPROTOOPT #define ENOPROTOOPT 99 /* Protocol not available */ #undef EPROTONOSUPPORT #define EPROTONOSUPPORT 120 /* Protocol not supported */ #undef ESOCKTNOSUPPORT #define ESOCKTNOSUPPORT 121 /* Socket type not supported */ #undef EOPNOTSUPP #define EOPNOTSUPP 122 /* Operation not supported on socket */ #undef EPFNOSUPPORT #define EPFNOSUPPORT 123 /* Protocol family not supported */ #undef EAFNOSUPPORT #define EAFNOSUPPORT 124 /* Address family not supported */ #undef EADDRINUSE #define EADDRINUSE 125 /* Address already in use */ #undef EADDRNOTAVAIL #define EADDRNOTAVAIL 126 /* Can't assign requested address */ #undef ENETDOWN #define ENETDOWN 127 /* Network is down */ #undef ENETUNREACH #define ENETUNREACH 128 /* Network is unreachable */ #undef ENETRESET #define ENETRESET 129 /* Network dropped connection on reset */ #undef ECONNABORTED #define ECONNABORTED 130 /* Software caused connection abort */ #undef ECONNRESET #define ECONNRESET 131 /* Connection reset by peer */ #undef ENOBUFS #define ENOBUFS 132 /* No buffer space available */ #undef EISCONN #define EISCONN 133 /* Socket is already connected */ #undef ENOTCONN #define ENOTCONN 134 /* Socket is not connected */ #undef ESHUTDOWN #define ESHUTDOWN 143 /* Can't send after socket shutdown */ #undef ETOOMANYREFS #define ETOOMANYREFS 144 /* Too many references: can't splice */ #undef ETIMEDOUT #define ETIMEDOUT 145 /* Connection timed out */ #undef ECONNREFUSED #define ECONNREFUSED 146 /* Connection refused */ #undef ELOOP #define ELOOP 90 /* Symbolic link loop */ #undef EHOSTDOWN #define EHOSTDOWN 147 /* Host is down */ #undef EHOSTUNREACH #define EHOSTUNREACH 148 /* No route to host */ #undef ENOTEMPTY #define ENOTEMPTY 93 /* directory not empty */ #undef EUSERS #define EUSERS 94 /* Too many users (for UFS) */ #undef EDQUOT #define EDQUOT 69 /* Disc quota exceeded */ #undef ESTALE #define ESTALE 151 /* Stale NFS file handle */ #undef EREMOTE #define EREMOTE 66 /* The object is remote */ /* * It is very hard to determine how Windows reacts to attempting to * set a file pointer outside the input datatype's representable * region. So we fake the error code ourselves. */ #undef EOVERFLOW #define EOVERFLOW EFBIG /* The object couldn't fit in the datatype */ /* * Supply definitions for macros to query wait status, if not already * defined in header files above. */ #if TCL_UNION_WAIT # define WAIT_STATUS_TYPE union wait #else # define WAIT_STATUS_TYPE int #endif /* TCL_UNION_WAIT */ #ifndef WIFEXITED # define WIFEXITED(stat) (((*((int *) &(stat))) & 0xC0000000) == 0) #endif #ifndef WEXITSTATUS # define WEXITSTATUS(stat) (*((int *) &(stat))) #endif #ifndef WIFSIGNALED # define WIFSIGNALED(stat) ((*((int *) &(stat))) & 0xC0000000) #endif #ifndef WTERMSIG # define WTERMSIG(stat) ((*((int *) &(stat))) & 0x7f) #endif #ifndef WIFSTOPPED # define WIFSTOPPED(stat) 0 #endif #ifndef WSTOPSIG # define WSTOPSIG(stat) (((*((int *) &(stat))) >> 8) & 0xff) #endif /* * Define constants for waitpid() system call if they aren't defined * by a system header file. */ #ifndef WNOHANG # define WNOHANG 1 #endif #ifndef WUNTRACED # define WUNTRACED 2 #endif /* * Define access mode constants if they aren't already defined. */ #ifndef F_OK # define F_OK 00 #endif #ifndef X_OK # define X_OK 01 #endif #ifndef W_OK # define W_OK 02 #endif #ifndef R_OK # define R_OK 04 #endif /* * Define macros to query file type bits, if they're not already * defined. */ #ifndef S_IFLNK #define S_IFLNK 0120000 /* Symbolic Link */ #endif #ifndef S_ISREG # ifdef S_IFREG # define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) # else # define S_ISREG(m) 0 # endif #endif /* !S_ISREG */ #ifndef S_ISDIR # ifdef S_IFDIR # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) # else # define S_ISDIR(m) 0 # endif #endif /* !S_ISDIR */ #ifndef S_ISCHR # ifdef S_IFCHR # define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) # else # define S_ISCHR(m) 0 # endif #endif /* !S_ISCHR */ #ifndef S_ISBLK # ifdef S_IFBLK # define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) # else # define S_ISBLK(m) 0 # endif #endif /* !S_ISBLK */ #ifndef S_ISFIFO # ifdef S_IFIFO # define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) # else # define S_ISFIFO(m) 0 # endif #endif /* !S_ISFIFO */ #ifndef S_ISLNK # ifdef S_IFLNK # define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) # else # define S_ISLNK(m) 0 # endif #endif /* !S_ISLNK */ /* * Define MAXPATHLEN in terms of MAXPATH if available */ #ifndef MAXPATH #define MAXPATH MAX_PATH #endif /* MAXPATH */ #ifndef MAXPATHLEN #define MAXPATHLEN MAXPATH #endif /* MAXPATHLEN */ /* * Define pid_t and uid_t if they're not already defined. */ #if ! TCL_PID_T # define pid_t int #endif /* !TCL_PID_T */ #if ! TCL_UID_T # define uid_t int #endif /* !TCL_UID_T */ /* * Visual C++ has some odd names for common functions, so we need to * define a few macros to handle them. Also, it defines EDEADLOCK and * EDEADLK as the same value, which confuses Tcl_ErrnoId(). */ #if defined(_MSC_VER) || defined(__MINGW32__) # define environ _environ # if defined(_MSC_VER) && (_MSC_VER < 1600) # define hypot _hypot # endif # define exception _exception # undef EDEADLOCK # if defined(__MINGW32__) && !defined(__MSVCRT__) # define timezone _timezone # endif #endif /* _MSC_VER || __MINGW32__ */ /* * Borland's timezone and environ functions. */ #ifdef __BORLANDC__ # define timezone _timezone # define environ _environ #endif /* __BORLANDC__ */ /* * There is no platform-specific panic routine for Windows in the Tcl internals. */ #define TclpPanic ((Tcl_PanicProc *) NULL) /* *--------------------------------------------------------------------------- * The following macros and declarations represent the interface between * generic and windows-specific parts of Tcl. Some of the macros may * override functions declared in tclInt.h. *--------------------------------------------------------------------------- */ /* * The default platform eol translation on Windows is TCL_TRANSLATE_CRLF: */ #define TCL_PLATFORM_TRANSLATION TCL_TRANSLATE_CRLF /* * Declare dynamic loading extension macro. */ #define TCL_SHLIB_EXT ".dll" /* * The following define ensures that we use the native putenv * implementation to modify the environment array. This keeps * the C level environment in synch with the system level environment. */ #define USE_PUTENV 1 #define USE_PUTENV_FOR_UNSET 1 /* * Msvcrt's putenv() copies the string rather than takes ownership of it. */ #if defined(_MSC_VER) || defined(__MINGW32__) # define HAVE_PUTENV_THAT_COPIES 1 #endif /* * The following defines wrap the system memory allocation routines for * use by tclAlloc.c. */ #define TclpSysAlloc(size, isBin) ((void*)HeapAlloc(GetProcessHeap(), \ (DWORD)0, (DWORD)size)) #define TclpSysFree(ptr) (HeapFree(GetProcessHeap(), \ (DWORD)0, (HGLOBAL)ptr)) #define TclpSysRealloc(ptr, size) ((void*)HeapReAlloc(GetProcessHeap(), \ (DWORD)0, (LPVOID)ptr, (DWORD)size)) /* * The following defines map from standard socket names to our internal * wrappers that redirect through the winSock function table (see the * file tclWinSock.c). */ #define getservbyname TclWinGetServByName #define getsockopt TclWinGetSockOpt #define ntohs TclWinNToHS #define setsockopt TclWinSetSockOpt /* This type is not defined in the Windows headers */ #define socklen_t int /* * The following macros have trivial definitions, allowing generic code to * address platform-specific issues. */ #define TclpReleaseFile(file) ckfree((char *) file) /* * The following macros and declarations wrap the C runtime library * functions. */ #define TclpExit exit /* * Declarations for Windows-only functions. */ EXTERN HANDLE TclWinSerialReopen _ANSI_ARGS_(( HANDLE handle, CONST TCHAR *name, DWORD access)); EXTERN Tcl_Channel TclWinOpenSerialChannel _ANSI_ARGS_((HANDLE handle, char *channelName, int permissions)); EXTERN Tcl_Channel TclWinOpenConsoleChannel _ANSI_ARGS_((HANDLE handle, char *channelName, int permissions)); EXTERN Tcl_Channel TclWinOpenFileChannel _ANSI_ARGS_((HANDLE handle, char *channelName, int permissions, int appendMode)); EXTERN TclFile TclWinMakeFile _ANSI_ARGS_((HANDLE handle)); /* * Platform specific mutex definition used by memory allocators. * These mutexes are statically allocated and explicitly initialized. * Most modules do not use this, but instead use Tcl_Mutex types and * Tcl_MutexLock and Tcl_MutexUnlock that are self-initializing. */ #ifdef TCL_THREADS typedef CRITICAL_SECTION TclpMutex; EXTERN void TclpMutexInit _ANSI_ARGS_((TclpMutex *mPtr)); EXTERN void TclpMutexLock _ANSI_ARGS_((TclpMutex *mPtr)); EXTERN void TclpMutexUnlock _ANSI_ARGS_((TclpMutex *mPtr)); #else /* !TCL_THREADS */ typedef int TclpMutex; #define TclpMutexInit(a) #define TclpMutexLock(a) #define TclpMutexUnlock(a) #endif /* TCL_THREADS */ #ifdef TCL_WIDE_INT_TYPE EXTERN Tcl_WideInt strtoll _ANSI_ARGS_((CONST char *string, char **endPtr, int base)); EXTERN Tcl_WideUInt strtoull _ANSI_ARGS_((CONST char *string, char **endPtr, int base)); #endif /* TCL_WIDE_INT_TYPE */ #ifndef INVALID_SET_FILE_POINTER #define INVALID_SET_FILE_POINTER 0xFFFFFFFF #endif /* INVALID_SET_FILE_POINTER */ #ifndef LABEL_SECURITY_INFORMATION # define LABEL_SECURITY_INFORMATION (0x00000010L) #endif #include "tclPlatDecls.h" #include "tclIntPlatDecls.h" #undef TCL_STORAGE_CLASS #define TCL_STORAGE_CLASS DLLIMPORT #endif /* _TCLWINPORT */ tcl8.4.20/win/tclWinFile.c0000644003604700454610000022324012133546540013714 0ustar dgp771div/* * tclWinFile.c -- * * This file contains temporary wrappers around UNIX file handling * functions. These wrappers map the UNIX functions to Win32 HANDLE-style * files, which can be manipulated through the Win32 console redirection * interfaces. * * Copyright (c) 1995-1998 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef _WIN64 /* See [Bug 2935503]: file mtime sets wrong time */ # define _USE_32BIT_TIME_T #endif #include #include "tclWinInt.h" #include #include #include /* For TclpGetUserHome(). */ /* * The number of 100-ns intervals between the Windows system epoch (1601-01-01 * on the proleptic Gregorian calendar) and the Posix epoch (1970-01-01). */ #define POSIX_EPOCH_AS_FILETIME 116444736000000000 /* * Declarations for 'link' related information. This information * should come with VC++ 6.0, but is not in some older SDKs. * In any case it is not well documented. */ #ifndef IO_REPARSE_TAG_RESERVED_ONE # define IO_REPARSE_TAG_RESERVED_ONE 0x000000001 #endif #ifndef IO_REPARSE_TAG_RESERVED_RANGE # define IO_REPARSE_TAG_RESERVED_RANGE 0x000000001 #endif #ifndef IO_REPARSE_TAG_VALID_VALUES # define IO_REPARSE_TAG_VALID_VALUES 0x0E000FFFF #endif #ifndef IO_REPARSE_TAG_HSM # define IO_REPARSE_TAG_HSM 0x0C0000004 #endif #ifndef IO_REPARSE_TAG_NSS # define IO_REPARSE_TAG_NSS 0x080000005 #endif #ifndef IO_REPARSE_TAG_NSSRECOVER # define IO_REPARSE_TAG_NSSRECOVER 0x080000006 #endif #ifndef IO_REPARSE_TAG_SIS # define IO_REPARSE_TAG_SIS 0x080000007 #endif #ifndef IO_REPARSE_TAG_DFS # define IO_REPARSE_TAG_DFS 0x080000008 #endif #ifndef IO_REPARSE_TAG_RESERVED_ZERO # define IO_REPARSE_TAG_RESERVED_ZERO 0x00000000 #endif #ifndef FILE_FLAG_OPEN_REPARSE_POINT # define FILE_FLAG_OPEN_REPARSE_POINT 0x00200000 #endif #ifndef IO_REPARSE_TAG_MOUNT_POINT # define IO_REPARSE_TAG_MOUNT_POINT 0xA0000003 #endif #ifndef IsReparseTagValid # define IsReparseTagValid(x) (!((x)&~IO_REPARSE_TAG_VALID_VALUES)&&((x)>IO_REPARSE_TAG_RESERVED_RANGE)) #endif #ifndef IO_REPARSE_TAG_SYMBOLIC_LINK # define IO_REPARSE_TAG_SYMBOLIC_LINK IO_REPARSE_TAG_RESERVED_ZERO #endif #ifndef FILE_SPECIAL_ACCESS # define FILE_SPECIAL_ACCESS (FILE_ANY_ACCESS) #endif #ifndef FSCTL_SET_REPARSE_POINT # define FSCTL_SET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 41, METHOD_BUFFERED, FILE_SPECIAL_ACCESS) # define FSCTL_GET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS) # define FSCTL_DELETE_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 43, METHOD_BUFFERED, FILE_SPECIAL_ACCESS) #endif #ifndef INVALID_FILE_ATTRIBUTES #define INVALID_FILE_ATTRIBUTES ((DWORD)-1) #endif /* * Maximum reparse buffer info size. The max user defined reparse * data is 16KB, plus there's a header. */ #define MAX_REPARSE_SIZE 17000 /* * Undocumented REPARSE_MOUNTPOINT_HEADER_SIZE structure definition. * This is found in winnt.h. * * IMPORTANT: caution when using this structure, since the actual * structures used will want to store a full path in the 'PathBuffer' * field, but there isn't room (there's only a single WCHAR!). Therefore * one must artificially create a larger space of memory and then cast it * to this type. We use the 'DUMMY_REPARSE_BUFFER' struct just below to * deal with this problem. */ #define REPARSE_MOUNTPOINT_HEADER_SIZE 8 #ifndef REPARSE_DATA_BUFFER_HEADER_SIZE typedef struct _REPARSE_DATA_BUFFER { DWORD ReparseTag; WORD ReparseDataLength; WORD Reserved; union { struct { WORD SubstituteNameOffset; WORD SubstituteNameLength; WORD PrintNameOffset; WORD PrintNameLength; ULONG Flags; WCHAR PathBuffer[1]; } SymbolicLinkReparseBuffer; struct { WORD SubstituteNameOffset; WORD SubstituteNameLength; WORD PrintNameOffset; WORD PrintNameLength; WCHAR PathBuffer[1]; } MountPointReparseBuffer; struct { BYTE DataBuffer[1]; } GenericReparseBuffer; }; } REPARSE_DATA_BUFFER; #endif typedef struct { REPARSE_DATA_BUFFER dummy; WCHAR dummyBuf[MAX_PATH*3]; } DUMMY_REPARSE_BUFFER; #if defined(_MSC_VER) && ( _MSC_VER <= 1100 ) #define HAVE_NO_FINDEX_ENUMS #elif !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0400) #define HAVE_NO_FINDEX_ENUMS #endif #ifdef HAVE_NO_FINDEX_ENUMS /* These two aren't in VC++ 5.2 headers */ typedef enum _FINDEX_INFO_LEVELS { FindExInfoStandard, FindExInfoMaxInfoLevel } FINDEX_INFO_LEVELS; typedef enum _FINDEX_SEARCH_OPS { FindExSearchNameMatch, FindExSearchLimitToDirectories, FindExSearchLimitToDevices, FindExSearchMaxSearchOp } FINDEX_SEARCH_OPS; #endif /* HAVE_NO_FINDEX_ENUMS */ /* Other typedefs required by this code */ static time_t ToCTime(FILETIME fileTime); static void FromCTime(time_t posixTime, FILETIME *fileTime); typedef NET_API_STATUS NET_API_FUNCTION NETUSERGETINFOPROC (LPWSTR servername, LPWSTR username, DWORD level, LPBYTE *bufptr); typedef NET_API_STATUS NET_API_FUNCTION NETAPIBUFFERFREEPROC (LPVOID Buffer); typedef NET_API_STATUS NET_API_FUNCTION NETGETDCNAMEPROC (LPWSTR servername, LPWSTR domainname, LPBYTE *bufptr); /* * Declarations for local procedures defined in this file: */ static int NativeAccess(CONST TCHAR *path, int mode); static int NativeStat(CONST TCHAR *path, Tcl_StatBuf *statPtr, int checkLinks); static unsigned short NativeStatMode(DWORD attr, int checkLinks, int isExec); static int NativeIsExec(CONST TCHAR *path); static int NativeReadReparse(CONST TCHAR* LinkDirectory, REPARSE_DATA_BUFFER* buffer, DWORD desiredAccess); static int NativeWriteReparse(CONST TCHAR* LinkDirectory, REPARSE_DATA_BUFFER* buffer); static int NativeMatchType(int isDrive, DWORD attr, CONST TCHAR* nativeName, Tcl_GlobTypeData *types); static int WinIsDrive(CONST char *name, int nameLen); static int WinIsReserved(CONST char *path); static Tcl_Obj* WinReadLink(CONST TCHAR* LinkSource); static Tcl_Obj* WinReadLinkDirectory(CONST TCHAR* LinkDirectory); static int WinLink(CONST TCHAR* LinkSource, CONST TCHAR* LinkTarget, int linkAction); static int WinSymLinkDirectory(CONST TCHAR* LinkDirectory, CONST TCHAR* LinkTarget); /* *-------------------------------------------------------------------- * * WinLink * * Make a link from source to target. *-------------------------------------------------------------------- */ static int WinLink(LinkSource, LinkTarget, linkAction) CONST TCHAR* LinkSource; CONST TCHAR* LinkTarget; int linkAction; { WCHAR tempFileName[MAX_PATH]; TCHAR* tempFilePart; int attr; /* Get the full path referenced by the target */ if (!(*tclWinProcs->getFullPathNameProc)(LinkTarget, MAX_PATH, tempFileName, &tempFilePart)) { /* Invalid file */ TclWinConvertError(GetLastError()); return -1; } /* Make sure source file doesn't exist */ attr = (*tclWinProcs->getFileAttributesProc)(LinkSource); if (attr != -1) { Tcl_SetErrno(EEXIST); return -1; } /* Get the full path referenced by the directory */ if (!(*tclWinProcs->getFullPathNameProc)(LinkSource, MAX_PATH, tempFileName, &tempFilePart)) { /* Invalid file */ TclWinConvertError(GetLastError()); return -1; } /* Check the target */ attr = (*tclWinProcs->getFileAttributesProc)(LinkTarget); if (attr == -1) { /* The target doesn't exist */ TclWinConvertError(GetLastError()); return -1; } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0) { /* It is a file */ if (tclWinProcs->createHardLinkProc == NULL) { Tcl_SetErrno(ENOTDIR); return -1; } if (linkAction & TCL_CREATE_HARD_LINK) { if (!(*tclWinProcs->createHardLinkProc)(LinkSource, LinkTarget, NULL)) { TclWinConvertError(GetLastError()); return -1; } return 0; } else if (linkAction & TCL_CREATE_SYMBOLIC_LINK) { /* Can't symlink files */ Tcl_SetErrno(ENOTDIR); return -1; } else { Tcl_SetErrno(ENODEV); return -1; } } else { if (linkAction & TCL_CREATE_SYMBOLIC_LINK) { return WinSymLinkDirectory(LinkSource, LinkTarget); } else if (linkAction & TCL_CREATE_HARD_LINK) { /* Can't hard link directories */ Tcl_SetErrno(EISDIR); return -1; } else { Tcl_SetErrno(ENODEV); return -1; } } } /* *-------------------------------------------------------------------- * * WinReadLink * * What does 'LinkSource' point to? *-------------------------------------------------------------------- */ static Tcl_Obj* WinReadLink(LinkSource) CONST TCHAR* LinkSource; { WCHAR tempFileName[MAX_PATH]; TCHAR* tempFilePart; int attr; /* Get the full path referenced by the target */ if (!(*tclWinProcs->getFullPathNameProc)(LinkSource, MAX_PATH, tempFileName, &tempFilePart)) { /* Invalid file */ TclWinConvertError(GetLastError()); return NULL; } /* Make sure source file does exist */ attr = (*tclWinProcs->getFileAttributesProc)(LinkSource); if (attr == -1) { /* The source doesn't exist */ TclWinConvertError(GetLastError()); return NULL; } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0) { /* It is a file - this is not yet supported */ Tcl_SetErrno(ENOTDIR); return NULL; } else { return WinReadLinkDirectory(LinkSource); } } /* *-------------------------------------------------------------------- * * WinSymLinkDirectory * * This routine creates a NTFS junction, using the undocumented * FSCTL_SET_REPARSE_POINT structure Win2K uses for mount points * and junctions. * * Assumption that LinkTarget is a valid, existing directory. * * Returns zero on success. *-------------------------------------------------------------------- */ static int WinSymLinkDirectory(LinkDirectory, LinkTarget) CONST TCHAR* LinkDirectory; CONST TCHAR* LinkTarget; { DUMMY_REPARSE_BUFFER dummy; REPARSE_DATA_BUFFER *reparseBuffer = (REPARSE_DATA_BUFFER*)&dummy; int len; WCHAR nativeTarget[MAX_PATH]; WCHAR *loop; /* Make the native target name */ memcpy((VOID*)nativeTarget, (VOID*)L"\\??\\", 4*sizeof(WCHAR)); memcpy((VOID*)(nativeTarget + 4), (VOID*)LinkTarget, sizeof(WCHAR)*(1+wcslen((WCHAR*)LinkTarget))); len = wcslen(nativeTarget); /* * We must have backslashes only. This is VERY IMPORTANT. * If we have any forward slashes everything appears to work, * but the resulting symlink is useless! */ for (loop = nativeTarget; *loop != 0; loop++) { if (*loop == L'/') *loop = L'\\'; } if ((nativeTarget[len-1] == L'\\') && (nativeTarget[len-2] != L':')) { nativeTarget[len-1] = 0; } /* Build the reparse info */ memset(reparseBuffer, 0, sizeof(DUMMY_REPARSE_BUFFER)); reparseBuffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; reparseBuffer->MountPointReparseBuffer.SubstituteNameLength = wcslen(nativeTarget) * sizeof(WCHAR); reparseBuffer->Reserved = 0; reparseBuffer->MountPointReparseBuffer.PrintNameLength = 0; reparseBuffer->MountPointReparseBuffer.PrintNameOffset = reparseBuffer->MountPointReparseBuffer.SubstituteNameLength + sizeof(WCHAR); memcpy(reparseBuffer->MountPointReparseBuffer.PathBuffer, nativeTarget, sizeof(WCHAR) + reparseBuffer->MountPointReparseBuffer.SubstituteNameLength); reparseBuffer->ReparseDataLength = reparseBuffer->MountPointReparseBuffer.SubstituteNameLength + 12; return NativeWriteReparse(LinkDirectory, reparseBuffer); } /* *-------------------------------------------------------------------- * * TclWinSymLinkCopyDirectory * * Copy a Windows NTFS junction. This function assumes that * LinkOriginal exists and is a valid junction point, and that * LinkCopy does not exist. * * Returns zero on success. *-------------------------------------------------------------------- */ int TclWinSymLinkCopyDirectory(LinkOriginal, LinkCopy) CONST TCHAR* LinkOriginal; /* Existing junction - reparse point */ CONST TCHAR* LinkCopy; /* Will become a duplicate junction */ { DUMMY_REPARSE_BUFFER dummy; REPARSE_DATA_BUFFER *reparseBuffer = (REPARSE_DATA_BUFFER*)&dummy; if (NativeReadReparse(LinkOriginal, reparseBuffer, GENERIC_READ)) { return -1; } return NativeWriteReparse(LinkCopy, reparseBuffer); } /* *-------------------------------------------------------------------- * * TclWinSymLinkDelete * * Delete a Windows NTFS junction. Once the junction information * is deleted, the filesystem object becomes an ordinary directory. * Unless 'linkOnly' is given, that directory is also removed. * * Assumption that LinkOriginal is a valid, existing junction. * * Returns zero on success. *-------------------------------------------------------------------- */ int TclWinSymLinkDelete(LinkOriginal, linkOnly) CONST TCHAR* LinkOriginal; int linkOnly; { /* It is a symbolic link -- remove it */ DUMMY_REPARSE_BUFFER dummy; REPARSE_DATA_BUFFER *reparseBuffer = (REPARSE_DATA_BUFFER*)&dummy; HANDLE hFile; DWORD returnedLength; memset(reparseBuffer, 0, sizeof(DUMMY_REPARSE_BUFFER)); reparseBuffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; hFile = (*tclWinProcs->createFileProc)(LinkOriginal, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, NULL); if (hFile != INVALID_HANDLE_VALUE) { if (!DeviceIoControl(hFile, FSCTL_DELETE_REPARSE_POINT, reparseBuffer, REPARSE_MOUNTPOINT_HEADER_SIZE, NULL, 0, &returnedLength, NULL)) { /* Error setting junction */ TclWinConvertError(GetLastError()); CloseHandle(hFile); } else { CloseHandle(hFile); if (!linkOnly) { (*tclWinProcs->removeDirectoryProc)(LinkOriginal); } return 0; } } return -1; } /* *-------------------------------------------------------------------- * * WinReadLinkDirectory * * This routine reads a NTFS junction, using the undocumented * FSCTL_GET_REPARSE_POINT structure Win2K uses for mount points * and junctions. * * Assumption that LinkDirectory is a valid, existing directory. * * Returns a Tcl_Obj with refCount of 1 (i.e. owned by the caller), * or NULL if anything went wrong. * * In the future we should enhance this to return a path object * rather than a string. *-------------------------------------------------------------------- */ static Tcl_Obj* WinReadLinkDirectory(LinkDirectory) CONST TCHAR* LinkDirectory; { int attr; DUMMY_REPARSE_BUFFER dummy; REPARSE_DATA_BUFFER *reparseBuffer = (REPARSE_DATA_BUFFER*)&dummy; attr = (*tclWinProcs->getFileAttributesProc)(LinkDirectory); if (!(attr & FILE_ATTRIBUTE_REPARSE_POINT)) { Tcl_SetErrno(EINVAL); return NULL; } if (NativeReadReparse(LinkDirectory, reparseBuffer, 0)) { return NULL; } switch (reparseBuffer->ReparseTag) { case 0x80000000|IO_REPARSE_TAG_SYMBOLIC_LINK: case IO_REPARSE_TAG_SYMBOLIC_LINK: case IO_REPARSE_TAG_MOUNT_POINT: { Tcl_Obj *retVal; Tcl_DString ds; CONST char *copy; int len; int offset = 0; /* * Certain native path representations on Windows have a * special prefix to indicate that they are to be treated * specially. For example extremely long paths, or symlinks, * or volumes mounted inside directories. * * There is an assumption in this code that 'wide' interfaces * are being used (see tclWin32Dll.c), which is true for the * only systems which support reparse tags at present. If * that changes in the future, this code will have to be * generalised. */ if (reparseBuffer->MountPointReparseBuffer.PathBuffer[0] == L'\\') { /* Check whether this is a mounted volume */ if (wcsncmp(reparseBuffer->MountPointReparseBuffer.PathBuffer, L"\\??\\Volume{",11) == 0) { char drive; /* * There is some confusion between \??\ and \\?\ which * we have to fix here. It doesn't seem very well * documented. */ reparseBuffer->MountPointReparseBuffer .PathBuffer[1] = L'\\'; /* * Check if a corresponding drive letter exists, and * use that if it is found */ drive = TclWinDriveLetterForVolMountPoint(reparseBuffer ->MountPointReparseBuffer.PathBuffer); if (drive != -1) { char driveSpec[3] = { drive, ':', '\0' }; retVal = Tcl_NewStringObj(driveSpec,2); Tcl_IncrRefCount(retVal); return retVal; } /* * This is actually a mounted drive, which doesn't * exists as a DOS drive letter. This means the path * isn't actually a link, although we partially treat * it like one ('file type' will return 'link'), but * then the link will actually just be treated like * an ordinary directory. I don't believe any * serious inconsistency will arise from this, but it * is something to be aware of. */ Tcl_SetErrno(EINVAL); return NULL; } else if (wcsncmp(reparseBuffer->MountPointReparseBuffer .PathBuffer, L"\\\\?\\",4) == 0) { /* Strip off the prefix */ offset = 4; } else if (wcsncmp(reparseBuffer->MountPointReparseBuffer .PathBuffer, L"\\??\\",4) == 0) { /* Strip off the prefix */ offset = 4; } } Tcl_WinTCharToUtf( (CONST char*)reparseBuffer->MountPointReparseBuffer.PathBuffer, (int)reparseBuffer->MountPointReparseBuffer .SubstituteNameLength, &ds); copy = Tcl_DStringValue(&ds)+offset; len = Tcl_DStringLength(&ds)-offset; retVal = Tcl_NewStringObj(copy,len); Tcl_IncrRefCount(retVal); Tcl_DStringFree(&ds); return retVal; } } Tcl_SetErrno(EINVAL); return NULL; } /* *-------------------------------------------------------------------- * * NativeReadReparse * * Read the junction/reparse information from a given NTFS directory. * * Assumption that LinkDirectory is a valid, existing directory. * * Returns zero on success. *-------------------------------------------------------------------- */ static int NativeReadReparse(LinkDirectory, buffer, desiredAccess) CONST TCHAR* LinkDirectory; /* The junction to read */ REPARSE_DATA_BUFFER* buffer; /* Pointer to buffer. Cannot be NULL */ DWORD desiredAccess; { HANDLE hFile; DWORD returnedLength; hFile = (*tclWinProcs->createFileProc)(LinkDirectory, desiredAccess, 0, NULL, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, NULL); if (hFile == INVALID_HANDLE_VALUE) { /* Error creating directory */ TclWinConvertError(GetLastError()); return -1; } /* Get the link */ if (!DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, NULL, 0, buffer, sizeof(DUMMY_REPARSE_BUFFER), &returnedLength, NULL)) { /* Error setting junction */ TclWinConvertError(GetLastError()); CloseHandle(hFile); return -1; } CloseHandle(hFile); if (!IsReparseTagValid(buffer->ReparseTag)) { Tcl_SetErrno(EINVAL); return -1; } return 0; } /* *-------------------------------------------------------------------- * * NativeWriteReparse * * Write the reparse information for a given directory. * * Assumption that LinkDirectory does not exist. *-------------------------------------------------------------------- */ static int NativeWriteReparse(LinkDirectory, buffer) CONST TCHAR* LinkDirectory; REPARSE_DATA_BUFFER* buffer; { HANDLE hFile; DWORD returnedLength; /* Create the directory - it must not already exist */ if ((*tclWinProcs->createDirectoryProc)(LinkDirectory, NULL) == 0) { /* Error creating directory */ TclWinConvertError(GetLastError()); return -1; } hFile = (*tclWinProcs->createFileProc)(LinkDirectory, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, NULL); if (hFile == INVALID_HANDLE_VALUE) { /* Error creating directory */ TclWinConvertError(GetLastError()); return -1; } /* Set the link */ if (!DeviceIoControl(hFile, FSCTL_SET_REPARSE_POINT, buffer, (DWORD) buffer->ReparseDataLength + REPARSE_MOUNTPOINT_HEADER_SIZE, NULL, 0, &returnedLength, NULL)) { /* Error setting junction */ TclWinConvertError(GetLastError()); CloseHandle(hFile); (*tclWinProcs->removeDirectoryProc)(LinkDirectory); return -1; } CloseHandle(hFile); /* We succeeded */ return 0; } /* *--------------------------------------------------------------------------- * * TclpFindExecutable -- * * This procedure computes the absolute path name of the current * application, given its argv[0] value. * * Results: * A clean UTF string that is the path to the executable. At this * point we may not know the system encoding, but we convert the * string value to UTF-8 using core Windows functions. The path name * contains ASCII string and '/' chars do not conflict with other UTF * chars. * * Side effects: * The variable tclNativeExecutableName gets filled in with the file * name for the application, if we figured it out. If we couldn't * figure it out, tclNativeExecutableName is set to NULL. * *--------------------------------------------------------------------------- */ char * TclpFindExecutable(argv0) CONST char *argv0; /* The value of the application's argv[0] * (native). */ { WCHAR wName[MAX_PATH]; char name[MAX_PATH * TCL_UTF_MAX]; if (argv0 == NULL) { return NULL; } if (tclNativeExecutableName != NULL) { return tclNativeExecutableName; } /* * Under Windows we ignore argv0, and return the path for the file used to * create this process. */ if (GetModuleFileNameW(NULL, wName, MAX_PATH) == 0) { GetModuleFileNameA(NULL, name, sizeof(name)); } else { WideCharToMultiByte(CP_UTF8, 0, wName, -1, name, sizeof(name), NULL, NULL); } tclNativeExecutableName = ckalloc((unsigned) (strlen(name) + 1)); strcpy(tclNativeExecutableName, name); TclWinNoBackslash(tclNativeExecutableName); return tclNativeExecutableName; } /* *---------------------------------------------------------------------- * * TclpMatchInDirectory -- * * This routine is used by the globbing code to search a * directory for all files which match a given pattern. * * Results: * * The return value is a standard Tcl result indicating whether an * error occurred in globbing. Errors are left in interp, good * results are lappended to resultPtr (which must be a valid object) * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclpMatchInDirectory(interp, resultPtr, pathPtr, pattern, types) Tcl_Interp *interp; /* Interpreter to receive errors. */ Tcl_Obj *resultPtr; /* List object to lappend results. */ Tcl_Obj *pathPtr; /* Contains path to directory to search. */ CONST char *pattern; /* Pattern to match against. */ Tcl_GlobTypeData *types; /* Object containing list of acceptable types. * May be NULL. In particular the directory * flag is very important. */ { CONST TCHAR *native; if (pattern == NULL || (*pattern == '\0')) { Tcl_Obj *norm = Tcl_FSGetNormalizedPath(NULL, pathPtr); if (norm != NULL) { /* Match a single file directly */ int len; DWORD attr; CONST char *str = Tcl_GetStringFromObj(norm,&len); native = (CONST TCHAR*) Tcl_FSGetNativePath(pathPtr); if (tclWinProcs->getFileAttributesExProc == NULL) { attr = (*tclWinProcs->getFileAttributesProc)(native); if (attr == 0xffffffff) { return TCL_OK; } } else { WIN32_FILE_ATTRIBUTE_DATA data; if ((*tclWinProcs->getFileAttributesExProc)(native, GetFileExInfoStandard, &data) != TRUE) { return TCL_OK; } attr = data.dwFileAttributes; } if (NativeMatchType(WinIsDrive(str,len), attr, native, types)) { Tcl_ListObjAppendElement(interp, resultPtr, pathPtr); } } return TCL_OK; } else { DWORD attr; HANDLE handle; WIN32_FIND_DATAT data; CONST char *dirName; int dirLength; int matchSpecialDots; Tcl_DString ds; /* native encoding of dir */ Tcl_DString dsOrig; /* utf-8 encoding of dir */ Tcl_DString dirString; /* utf-8 encoding of dir with \'s */ Tcl_Obj *fileNamePtr; /* * Convert the path to normalized form since some interfaces only * accept backslashes. Also, ensure that the directory ends with a * separator character. */ fileNamePtr = Tcl_FSGetTranslatedPath(interp, pathPtr); if (fileNamePtr == NULL) { return TCL_ERROR; } Tcl_DStringInit(&dsOrig); dirName = Tcl_GetStringFromObj(fileNamePtr, &dirLength); Tcl_DStringAppend(&dsOrig, dirName, dirLength); Tcl_DStringInit(&dirString); if (dirLength == 0) { Tcl_DStringAppend(&dirString, ".\\", 2); } else { char *p; Tcl_DStringAppend(&dirString, dirName, dirLength); for (p = Tcl_DStringValue(&dirString); *p != '\0'; p++) { if (*p == '/') { *p = '\\'; } } p--; /* Make sure we have a trailing directory delimiter */ if ((*p != '\\') && (*p != ':')) { Tcl_DStringAppend(&dirString, "\\", 1); Tcl_DStringAppend(&dsOrig, "/", 1); dirLength++; } } dirName = Tcl_DStringValue(&dirString); Tcl_DecrRefCount(fileNamePtr); /* * First verify that the specified path is actually a directory. */ native = Tcl_WinUtfToTChar(dirName, Tcl_DStringLength(&dirString), &ds); attr = (*tclWinProcs->getFileAttributesProc)(native); Tcl_DStringFree(&ds); if ((attr == 0xffffffff) || ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0)) { Tcl_DStringFree(&dirString); return TCL_OK; } /* * We need to check all files in the directory, so append a *.* * to the path. */ dirName = Tcl_DStringAppend(&dirString, "*.*", 3); native = Tcl_WinUtfToTChar(dirName, -1, &ds); handle = (*tclWinProcs->findFirstFileProc)(native, &data); if (handle == INVALID_HANDLE_VALUE) { TclWinConvertError(GetLastError()); Tcl_DStringFree(&ds); Tcl_DStringFree(&dirString); Tcl_ResetResult(interp); Tcl_AppendResult(interp, "couldn't read directory \"", Tcl_DStringValue(&dsOrig), "\": ", Tcl_PosixError(interp), (char *) NULL); Tcl_DStringFree(&dsOrig); return TCL_ERROR; } Tcl_DStringFree(&ds); /* * Check to see if the pattern should match the special * . and .. names, referring to the current directory, * or the directory above. We need a special check for * this because paths beginning with a dot are not considered * hidden on Windows, and so otherwise a relative glob like * 'glob -join * *' will actually return './. ../..' etc. */ if ((pattern[0] == '.') || ((pattern[0] == '\\') && (pattern[1] == '.'))) { matchSpecialDots = 1; } else { matchSpecialDots = 0; } /* * Now iterate over all of the files in the directory, starting * with the first one we found. */ do { CONST char *utfname; int checkDrive = 0; int isDrive; DWORD attr; if (tclWinProcs->useWide) { native = (CONST TCHAR *) data.w.cFileName; attr = data.w.dwFileAttributes; } else { native = (CONST TCHAR *) data.a.cFileName; attr = data.a.dwFileAttributes; } utfname = Tcl_WinTCharToUtf(native, -1, &ds); if (!matchSpecialDots) { /* If it is exactly '.' or '..' then we ignore it */ if ((utfname[0] == '.') && (utfname[1] == '\0' || (utfname[1] == '.' && utfname[2] == '\0'))) { Tcl_DStringFree(&ds); continue; } } else if (utfname[0] == '.' && utfname[1] == '.' && utfname[2] == '\0') { /* * Have to check if this is a drive below, so we can * correctly match 'hidden' and not hidden files. */ checkDrive = 1; } /* * Check to see if the file matches the pattern. Note that * we are ignoring the case sensitivity flag because Windows * doesn't honor case even if the volume is case sensitive. * If the volume also doesn't preserve case, then we * previously returned the lower case form of the name. This * didn't seem quite right since there are * non-case-preserving volumes that actually return mixed * case. So now we are returning exactly what we get from * the system. */ if (Tcl_StringCaseMatch(utfname, pattern, 1)) { /* * If the file matches, then we need to process the remainder * of the path. */ if (checkDrive) { CONST char *fullname = Tcl_DStringAppend(&dsOrig, utfname, Tcl_DStringLength(&ds)); isDrive = WinIsDrive(fullname, Tcl_DStringLength(&dsOrig)); Tcl_DStringSetLength(&dsOrig, dirLength); } else { isDrive = 0; } if (NativeMatchType(isDrive, attr, native, types)) { Tcl_ListObjAppendElement(interp, resultPtr, TclNewFSPathObj(pathPtr, utfname, Tcl_DStringLength(&ds))); } } /* * Free ds here to ensure that native is valid above. */ Tcl_DStringFree(&ds); } while ((*tclWinProcs->findNextFileProc)(handle, &data) == TRUE); FindClose(handle); Tcl_DStringFree(&dirString); Tcl_DStringFree(&dsOrig); return TCL_OK; } } /* * Does the given path represent a root volume? We need this special * case because for NTFS root volumes, the getFileAttributesProc returns * a 'hidden' attribute when it should not. */ static int WinIsDrive( CONST char *name, /* Name (UTF-8) */ int len) /* Length of name */ { int remove = 0; while (len > 4) { if ((name[len-1] != '.' || name[len-2] != '.') || (name[len-3] != '/' && name[len-3] != '\\')) { /* We don't have '/..' at the end */ if (remove == 0) { break; } remove--; while (len > 0) { len--; if (name[len] == '/' || name[len] == '\\') { break; } } if (len < 4) { len++; break; } } else { /* We do have '/..' */ len -= 3; remove++; } } if (len < 4) { if (len == 0) { /* * Not sure if this is possible, but we pass it on * anyway */ } else if (len == 1 && (name[0] == '/' || name[0] == '\\')) { /* Path is pointing to the root volume */ return 1; } else if ((name[1] == ':') && (len == 2 || (name[2] == '/' || name[2] == '\\'))) { /* Path is of the form 'x:' or 'x:/' or 'x:\' */ return 1; } } return 0; } /* * Does the given path represent a reserved window path name? If not * return 0, if true, return the number of characters of the path that * we actually want (not any trailing :). */ static int WinIsReserved( CONST char *path) /* Path in UTF-8 */ { if ((path[0] == 'c' || path[0] == 'C') && (path[1] == 'o' || path[1] == 'O')) { if ((path[2] == 'm' || path[2] == 'M') && path[3] >= '1' && path[3] <= '4') { /* May have match for 'com[1-4]:?', which is a serial port */ if (path[4] == '\0') { return 4; } else if (path [4] == ':' && path[5] == '\0') { return 4; } } else if ((path[2] == 'n' || path[2] == 'N') && path[3] == '\0') { /* Have match for 'con' */ return 3; } } else if ((path[0] == 'l' || path[0] == 'L') && (path[1] == 'p' || path[1] == 'P') && (path[2] == 't' || path[2] == 'T')) { if (path[3] >= '1' && path[3] <= '3') { /* May have match for 'lpt[1-3]:?' */ if (path[4] == '\0') { return 4; } else if (path [4] == ':' && path[5] == '\0') { return 4; } } } else if (stricmp(path, "prn") == 0) { /* Have match for 'prn' */ return 3; } else if (stricmp(path, "nul") == 0) { /* Have match for 'nul' */ return 3; } else if (stricmp(path, "aux") == 0) { /* Have match for 'aux' */ return 3; } return 0; } /* *---------------------------------------------------------------------- * * NativeMatchType -- * * This function needs a special case for a path which is a root * volume, because for NTFS root volumes, the getFileAttributesProc * returns a 'hidden' attribute when it should not. * * We never make any calls to a 'get attributes' routine here, * since we have arranged things so that our caller already knows * such information. * * Results: * 0 = file doesn't match * 1 = file matches * *---------------------------------------------------------------------- */ static int NativeMatchType( int isDrive, /* Is this a drive */ DWORD attr, /* We already know the attributes * for the file */ CONST TCHAR* nativeName, /* Native path to check */ Tcl_GlobTypeData *types) /* Type description to match against */ { /* * 'attr' represents the attributes of the file, but we only * want to retrieve this info if it is absolutely necessary * because it is an expensive call. Unfortunately, to deal * with hidden files properly, we must always retrieve it. */ if (types == NULL) { /* If invisible, don't return the file */ if (attr & FILE_ATTRIBUTE_HIDDEN && !isDrive) { return 0; } } else { if (attr & FILE_ATTRIBUTE_HIDDEN && !isDrive) { /* If invisible */ if ((types->perm == 0) || !(types->perm & TCL_GLOB_PERM_HIDDEN)) { return 0; } } else { /* Visible */ if (types->perm & TCL_GLOB_PERM_HIDDEN) { return 0; } } if (types->perm != 0) { if ( ((types->perm & TCL_GLOB_PERM_RONLY) && !(attr & FILE_ATTRIBUTE_READONLY)) || ((types->perm & TCL_GLOB_PERM_R) && (0 /* File exists => R_OK on Windows */)) || ((types->perm & TCL_GLOB_PERM_W) && (attr & FILE_ATTRIBUTE_READONLY)) || ((types->perm & TCL_GLOB_PERM_X) && (!(attr & FILE_ATTRIBUTE_DIRECTORY) && !NativeIsExec(nativeName))) ) { return 0; } } if ((types->type & TCL_GLOB_TYPE_DIR) && (attr & FILE_ATTRIBUTE_DIRECTORY)) { /* Quicker test for directory, which is a common case */ return 1; } else if (types->type != 0) { unsigned short st_mode; int isExec = NativeIsExec(nativeName); st_mode = NativeStatMode(attr, 0, isExec); /* * In order bcdpfls as in 'find -t' */ if ( ((types->type & TCL_GLOB_TYPE_BLOCK) && S_ISBLK(st_mode)) || ((types->type & TCL_GLOB_TYPE_CHAR) && S_ISCHR(st_mode)) || ((types->type & TCL_GLOB_TYPE_DIR) && S_ISDIR(st_mode)) || ((types->type & TCL_GLOB_TYPE_PIPE) && S_ISFIFO(st_mode)) || ((types->type & TCL_GLOB_TYPE_FILE) && S_ISREG(st_mode)) #ifdef S_ISSOCK || ((types->type & TCL_GLOB_TYPE_SOCK) && S_ISSOCK(st_mode)) #endif ) { /* Do nothing -- this file is ok */ } else { #ifdef S_ISLNK if (types->type & TCL_GLOB_TYPE_LINK) { st_mode = NativeStatMode(attr, 1, isExec); if (S_ISLNK(st_mode)) { return 1; } } #endif return 0; } } } return 1; } /* *---------------------------------------------------------------------- * * TclpGetUserHome -- * * This function takes the passed in user name and finds the * corresponding home directory specified in the password file. * * Results: * The result is a pointer to a string specifying the user's home * directory, or NULL if the user's home directory could not be * determined. Storage for the result string is allocated in * bufferPtr; the caller must call Tcl_DStringFree() when the result * is no longer needed. * * Side effects: * None. * *---------------------------------------------------------------------- */ char * TclpGetUserHome(name, bufferPtr) CONST char *name; /* User name for desired home directory. */ Tcl_DString *bufferPtr; /* Uninitialized or free DString filled * with name of user's home directory. */ { char *result; HINSTANCE netapiInst; result = NULL; Tcl_DStringInit(bufferPtr); netapiInst = LoadLibraryA("netapi32.dll"); if (netapiInst != NULL) { NETAPIBUFFERFREEPROC *netApiBufferFreeProc; NETGETDCNAMEPROC *netGetDCNameProc; NETUSERGETINFOPROC *netUserGetInfoProc; netApiBufferFreeProc = (NETAPIBUFFERFREEPROC *) GetProcAddress(netapiInst, "NetApiBufferFree"); netGetDCNameProc = (NETGETDCNAMEPROC *) GetProcAddress(netapiInst, "NetGetDCName"); netUserGetInfoProc = (NETUSERGETINFOPROC *) GetProcAddress(netapiInst, "NetUserGetInfo"); if ((netUserGetInfoProc != NULL) && (netGetDCNameProc != NULL) && (netApiBufferFreeProc != NULL)) { USER_INFO_1 *uiPtr; Tcl_DString ds; int nameLen, badDomain; char *domain; WCHAR *wName, *wHomeDir, *wDomain; WCHAR buf[MAX_PATH]; badDomain = 0; nameLen = -1; wDomain = NULL; domain = strchr(name, '@'); if (domain != NULL) { Tcl_DStringInit(&ds); wName = Tcl_UtfToUniCharDString(domain + 1, -1, &ds); badDomain = (*netGetDCNameProc)(NULL, wName, (LPBYTE *) &wDomain); Tcl_DStringFree(&ds); nameLen = domain - name; } if (badDomain == 0) { Tcl_DStringInit(&ds); wName = Tcl_UtfToUniCharDString(name, nameLen, &ds); if ((*netUserGetInfoProc)(wDomain, wName, 1, (LPBYTE *) &uiPtr) == 0) { wHomeDir = uiPtr->usri1_home_dir; if ((wHomeDir != NULL) && (wHomeDir[0] != L'\0')) { Tcl_UniCharToUtfDString(wHomeDir, lstrlenW(wHomeDir), bufferPtr); } else { /* * User exists but has no home dir. Return * "{Windows Drive}:/users/default". */ GetWindowsDirectoryW(buf, MAX_PATH); Tcl_UniCharToUtfDString(buf, 2, bufferPtr); Tcl_DStringAppend(bufferPtr, "/users/default", -1); } result = Tcl_DStringValue(bufferPtr); (*netApiBufferFreeProc)((void *) uiPtr); } Tcl_DStringFree(&ds); } if (wDomain != NULL) { (*netApiBufferFreeProc)((void *) wDomain); } } FreeLibrary(netapiInst); } if (result == NULL) { /* * Look in the "Password Lists" section of system.ini for the * local user. There are also entries in that section that begin * with a "*" character that are used by Windows for other * purposes; ignore user names beginning with a "*". */ char buf[MAX_PATH]; if (name[0] != '*') { if (GetPrivateProfileStringA("Password Lists", name, "", buf, MAX_PATH, "system.ini") > 0) { /* * User exists, but there is no such thing as a home * directory in system.ini. Return "{Windows drive}:/". */ GetWindowsDirectoryA(buf, MAX_PATH); Tcl_DStringAppend(bufferPtr, buf, 3); result = Tcl_DStringValue(bufferPtr); } } } return result; } /* *--------------------------------------------------------------------------- * * NativeAccess -- * * This function replaces the library version of access(), fixing the * following bugs: * * 1. access() returns that all files have execute permission. * * Results: * See access documentation. * * Side effects: * See access documentation. * *--------------------------------------------------------------------------- */ static int NativeAccess( CONST TCHAR *nativePath, /* Path of file to access (UTF-8). */ int mode) /* Permission setting. */ { DWORD attr; attr = (*tclWinProcs->getFileAttributesProc)(nativePath); if (attr == 0xffffffff) { /* * File might not exist. */ DWORD lasterror = GetLastError(); if (lasterror != ERROR_SHARING_VIOLATION) { TclWinConvertError(lasterror); return -1; } } if (mode == F_OK) { /* * File exists, nothing else to check. */ return 0; } if ((mode & W_OK) && (attr & FILE_ATTRIBUTE_READONLY) && !(attr & FILE_ATTRIBUTE_DIRECTORY)) { /* * The attributes say the file is not writable. If the file is a * regular file (i.e., not a directory), then the file is not * writable, full stop. For directories, the read-only bit is * (mostly) ignored by Windows, so we can't ascertain anything about * directory access from the attrib data. However, if we have the * advanced 'getFileSecurityProc', then more robust ACL checks * will be done below. */ Tcl_SetErrno(EACCES); return -1; } if (mode & X_OK) { if (!(attr & FILE_ATTRIBUTE_DIRECTORY) && !NativeIsExec(nativePath)) { /* * It's not a directory and doesn't have the correct extension. * Therefore it can't be executable */ Tcl_SetErrno(EACCES); return -1; } } /* * It looks as if the permissions are ok, but if we are on NT, 2000 or XP, * we have a more complex permissions structure so we try to check that. * The code below is remarkably complex for such a simple thing as finding * what permissions the OS has set for a file. */ if (tclWinProcs->getFileSecurityProc != NULL) { SECURITY_DESCRIPTOR *sdPtr = NULL; unsigned long size; PSID pSid = 0; BOOL SidDefaulted; SID_IDENTIFIER_AUTHORITY samba_unmapped = {{0, 0, 0, 0, 0, 22}}; GENERIC_MAPPING genMap; HANDLE hToken = NULL; DWORD desiredAccess = 0; DWORD grantedAccess = 0; BOOL accessYesNo = FALSE; PRIVILEGE_SET privSet; DWORD privSetSize = sizeof(PRIVILEGE_SET); int error; /* * First find out how big the buffer needs to be */ size = 0; (*tclWinProcs->getFileSecurityProc)(nativePath, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION, 0, 0, &size); /* * Should have failed with ERROR_INSUFFICIENT_BUFFER */ error = GetLastError(); if (error != ERROR_INSUFFICIENT_BUFFER) { /* * Most likely case is ERROR_ACCESS_DENIED, which we will convert * to EACCES - just what we want! */ TclWinConvertError((DWORD)error); return -1; } /* * Now size contains the size of buffer needed */ sdPtr = (SECURITY_DESCRIPTOR *) HeapAlloc(GetProcessHeap(), 0, size); if (sdPtr == NULL) { goto accessError; } /* * Call GetFileSecurity() for real */ if (!(*tclWinProcs->getFileSecurityProc)(nativePath, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION, sdPtr, size, &size)) { /* * Error getting owner SD */ goto accessError; } /* * As of Samba 3.0.23 (10-Jul-2006), unmapped users and groups are * assigned to SID domains S-1-22-1 and S-1-22-2, where "22" is the * top-level authority. If the file owner and group is unmapped then * the ACL access check below will only test against world access, * which is likely to be more restrictive than the actual access * restrictions. Since the ACL tests are more likely wrong than * right, skip them. Moreover, the unix owner access permissions are * usually mapped to the Windows attributes, so if the user is the * file owner then the attrib checks above are correct (as far as they * go). */ if(!GetSecurityDescriptorOwner(sdPtr,&pSid,&SidDefaulted) || memcmp(GetSidIdentifierAuthority(pSid),&samba_unmapped, sizeof(SID_IDENTIFIER_AUTHORITY))==0) { HeapFree(GetProcessHeap(), 0, sdPtr); return 0; /* Attrib tests say access allowed. */ } /* * Perform security impersonation of the user and open the * resulting thread token. */ if (!(*tclWinProcs->impersonateSelfProc)(SecurityImpersonation)) { /* * Unable to perform security impersonation. */ goto accessError; } if (!(*tclWinProcs->openThreadTokenProc)(GetCurrentThread (), TOKEN_DUPLICATE | TOKEN_QUERY, FALSE, &hToken)) { /* * Unable to get current thread's token. */ goto accessError; } (*tclWinProcs->revertToSelfProc)(); /* * Setup desiredAccess according to the access priveleges we are * checking. */ if (mode & R_OK) { desiredAccess |= FILE_GENERIC_READ; } if (mode & W_OK) { desiredAccess |= FILE_GENERIC_WRITE; } if (mode & X_OK) { desiredAccess |= FILE_GENERIC_EXECUTE; } memset (&genMap, 0x0, sizeof (GENERIC_MAPPING)); genMap.GenericRead = FILE_GENERIC_READ; genMap.GenericWrite = FILE_GENERIC_WRITE; genMap.GenericExecute = FILE_GENERIC_EXECUTE; genMap.GenericAll = FILE_ALL_ACCESS; /* * Perform access check using the token. */ if (!(*tclWinProcs->accessCheckProc)(sdPtr, hToken, desiredAccess, &genMap, &privSet, &privSetSize, &grantedAccess, &accessYesNo)) { /* * Unable to perform access check. */ accessError: TclWinConvertError(GetLastError()); if (sdPtr != NULL) { HeapFree(GetProcessHeap(), 0, sdPtr); } if (hToken != NULL) { CloseHandle(hToken); } return -1; } /* * Clean up. */ HeapFree(GetProcessHeap (), 0, sdPtr); CloseHandle(hToken); if (!accessYesNo) { Tcl_SetErrno(EACCES); return -1; } } return 0; } /* *---------------------------------------------------------------------- * * NativeIsExec -- * * Determines if a path is executable. On windows this is * simply defined by whether the path ends in any of ".exe", * ".com", or ".bat" * * Results: * 1 = executable, 0 = not. * *---------------------------------------------------------------------- */ static int NativeIsExec(nativePath) CONST TCHAR *nativePath; { if (tclWinProcs->useWide) { CONST WCHAR *path; int len; path = (CONST WCHAR*)nativePath; len = wcslen(path); if (len < 5) { return 0; } if (path[len-4] != L'.') { return 0; } /* * Use wide-char case-insensitive comparison */ if ((_wcsicmp(path+len-3,L"exe") == 0) || (_wcsicmp(path+len-3,L"com") == 0) || (_wcsicmp(path+len-3,L"bat") == 0)) { return 1; } } else { CONST char *p; /* We are only looking for pure ascii */ p = strrchr((CONST char*)nativePath, '.'); if (p != NULL) { p++; /* * Note: in the old code, stat considered '.pif' files as * executable, whereas access did not. */ if ((stricmp(p, "exe") == 0) || (stricmp(p, "com") == 0) || (stricmp(p, "bat") == 0)) { /* * File that ends with .exe, .com, or .bat is executable. */ return 1; } } } return 0; } /* *---------------------------------------------------------------------- * * TclpObjChdir -- * * This function replaces the library version of chdir(). * * Results: * See chdir() documentation. * * Side effects: * See chdir() documentation. * *---------------------------------------------------------------------- */ int TclpObjChdir(pathPtr) Tcl_Obj *pathPtr; /* Path to new working directory. */ { int result; CONST TCHAR *nativePath; nativePath = (CONST TCHAR *) Tcl_FSGetNativePath(pathPtr); result = (*tclWinProcs->setCurrentDirectoryProc)(nativePath); if (result == 0) { TclWinConvertError(GetLastError()); return -1; } return 0; } /* *---------------------------------------------------------------------- * * TclpGetCwd -- * * This function replaces the library version of getcwd(). * * Results: * The result is a pointer to a string specifying the current * directory, or NULL if the current directory could not be * determined. If NULL is returned, an error message is left in the * interp's result. Storage for the result string is allocated in * bufferPtr; the caller must call Tcl_DStringFree() when the result * is no longer needed. * * Side effects: * None. * *---------------------------------------------------------------------- */ CONST char * TclpGetCwd(interp, bufferPtr) Tcl_Interp *interp; /* If non-NULL, used for error reporting. */ Tcl_DString *bufferPtr; /* Uninitialized or free DString filled * with name of current directory. */ { WCHAR buffer[MAX_PATH]; char *p; if ((*tclWinProcs->getCurrentDirectoryProc)(MAX_PATH, buffer) == 0) { TclWinConvertError(GetLastError()); if (interp != NULL) { Tcl_AppendResult(interp, "error getting working directory name: ", Tcl_PosixError(interp), (char *) NULL); } return NULL; } /* * Watch for the weird Windows c:\\UNC syntax. */ if (tclWinProcs->useWide) { WCHAR *native; native = (WCHAR *) buffer; if ((native[0] != '\0') && (native[1] == ':') && (native[2] == '\\') && (native[3] == '\\')) { native += 2; } Tcl_WinTCharToUtf((TCHAR *) native, -1, bufferPtr); } else { char *native; native = (char *) buffer; if ((native[0] != '\0') && (native[1] == ':') && (native[2] == '\\') && (native[3] == '\\')) { native += 2; } Tcl_WinTCharToUtf((TCHAR *) native, -1, bufferPtr); } /* * Convert to forward slashes for easier use in scripts. */ for (p = Tcl_DStringValue(bufferPtr); *p != '\0'; p++) { if (*p == '\\') { *p = '/'; } } return Tcl_DStringValue(bufferPtr); } int TclpObjStat(pathPtr, statPtr) Tcl_Obj *pathPtr; /* Path of file to stat */ Tcl_StatBuf *statPtr; /* Filled with results of stat call. */ { #ifdef OLD_API Tcl_Obj *transPtr; /* * Eliminate file names containing wildcard characters, or subsequent * call to FindFirstFile() will expand them, matching some other file. */ transPtr = Tcl_FSGetTranslatedPath(NULL, pathPtr); if (transPtr == NULL || (strpbrk(Tcl_GetString(transPtr), "?*") != NULL)) { if (transPtr != NULL) { Tcl_DecrRefCount(transPtr); } Tcl_SetErrno(ENOENT); return -1; } Tcl_DecrRefCount(transPtr); #endif /* * Ensure correct file sizes by forcing the OS to write any * pending data to disk. This is done only for channels which are * dirty, i.e. have been written to since the last flush here. */ TclWinFlushDirtyChannels (); return NativeStat((CONST TCHAR*) Tcl_FSGetNativePath(pathPtr), statPtr, 0); } /* *---------------------------------------------------------------------- * * NativeStat -- * * This function replaces the library version of stat(), fixing * the following bugs: * * 1. stat("c:") returns an error. * 2. Borland stat() return time in GMT instead of localtime. * 3. stat("\\server\mount") would return error. * 4. Accepts slashes or backslashes. * 5. st_dev and st_rdev were wrong for UNC paths. * * Results: * See stat documentation. * * Side effects: * See stat documentation. * *---------------------------------------------------------------------- */ static int NativeStat(nativePath, statPtr, checkLinks) CONST TCHAR *nativePath; /* Path of file to stat */ Tcl_StatBuf *statPtr; /* Filled with results of stat call. */ int checkLinks; /* If non-zero, behave like 'lstat' */ { Tcl_DString ds; DWORD attr; WCHAR nativeFullPath[MAX_PATH]; TCHAR *nativePart; CONST char *fullPath; int dev; unsigned short mode; if (tclWinProcs->getFileAttributesExProc == NULL) { /* * We don't have the faster attributes proc, so we're * probably running on Win95 */ WIN32_FIND_DATAT data; HANDLE handle; handle = (*tclWinProcs->findFirstFileProc)(nativePath, &data); if (handle == INVALID_HANDLE_VALUE) { /* * FindFirstFile() doesn't work on root directories, so call * GetFileAttributes() to see if the specified file exists. */ attr = (*tclWinProcs->getFileAttributesProc)(nativePath); if (attr == INVALID_FILE_ATTRIBUTES) { Tcl_SetErrno(ENOENT); return -1; } /* * Make up some fake information for this file. It has the * correct file attributes and a time of 0. */ memset(&data, 0, sizeof(data)); data.a.dwFileAttributes = attr; } else { FindClose(handle); } (*tclWinProcs->getFullPathNameProc)(nativePath, MAX_PATH, nativeFullPath, &nativePart); fullPath = Tcl_WinTCharToUtf((TCHAR *) nativeFullPath, -1, &ds); dev = -1; if ((fullPath[0] == '\\') && (fullPath[1] == '\\')) { CONST char *p; DWORD dw; CONST TCHAR *nativeVol; Tcl_DString volString; p = strchr(fullPath + 2, '\\'); p = strchr(p + 1, '\\'); if (p == NULL) { /* * Add terminating backslash to fullpath or * GetVolumeInformation() won't work. */ fullPath = Tcl_DStringAppend(&ds, "\\", 1); p = fullPath + Tcl_DStringLength(&ds); } else { p++; } nativeVol = Tcl_WinUtfToTChar(fullPath, p - fullPath, &volString); dw = (DWORD) -1; (*tclWinProcs->getVolumeInformationProc)(nativeVol, NULL, 0, &dw, NULL, NULL, NULL, 0); /* * GetFullPathName() turns special devices like "NUL" into * "\\.\NUL", but GetVolumeInformation() returns failure for * "\\.\NUL". This will cause "NUL" to get a drive number of * -1, which makes about as much sense as anything since the * special devices don't live on any drive. */ dev = dw; Tcl_DStringFree(&volString); } else if ((fullPath[0] != '\0') && (fullPath[1] == ':')) { dev = Tcl_UniCharToLower(fullPath[0]) - 'a'; } Tcl_DStringFree(&ds); attr = data.a.dwFileAttributes; statPtr->st_size = ((Tcl_WideInt)data.a.nFileSizeLow) | (((Tcl_WideInt)data.a.nFileSizeHigh) << 32); statPtr->st_atime = ToCTime(data.a.ftLastAccessTime); statPtr->st_mtime = ToCTime(data.a.ftLastWriteTime); statPtr->st_ctime = ToCTime(data.a.ftCreationTime); } else { WIN32_FILE_ATTRIBUTE_DATA data; if((*tclWinProcs->getFileAttributesExProc)(nativePath, GetFileExInfoStandard, &data) != TRUE) { HANDLE hFind; WIN32_FIND_DATAT ffd; DWORD lasterror = GetLastError(); if (lasterror != ERROR_SHARING_VIOLATION) { TclWinConvertError(lasterror); return -1; } hFind = (*tclWinProcs->findFirstFileProc)(nativePath, &ffd); if (hFind == INVALID_HANDLE_VALUE) { TclWinConvertError(GetLastError()); return -1; } memcpy(&data, &ffd, sizeof(data)); FindClose(hFind); } (*tclWinProcs->getFullPathNameProc)(nativePath, MAX_PATH, nativeFullPath, &nativePart); fullPath = Tcl_WinTCharToUtf((TCHAR *) nativeFullPath, -1, &ds); dev = -1; if ((fullPath[0] == '\\') && (fullPath[1] == '\\')) { CONST char *p; DWORD dw; CONST TCHAR *nativeVol; Tcl_DString volString; p = strchr(fullPath + 2, '\\'); p = strchr(p + 1, '\\'); if (p == NULL) { /* * Add terminating backslash to fullpath or * GetVolumeInformation() won't work. */ fullPath = Tcl_DStringAppend(&ds, "\\", 1); p = fullPath + Tcl_DStringLength(&ds); } else { p++; } nativeVol = Tcl_WinUtfToTChar(fullPath, p - fullPath, &volString); dw = (DWORD) -1; (*tclWinProcs->getVolumeInformationProc)(nativeVol, NULL, 0, &dw, NULL, NULL, NULL, 0); /* * GetFullPathName() turns special devices like "NUL" into * "\\.\NUL", but GetVolumeInformation() returns failure for * "\\.\NUL". This will cause "NUL" to get a drive number of * -1, which makes about as much sense as anything since the * special devices don't live on any drive. */ dev = dw; Tcl_DStringFree(&volString); } else if ((fullPath[0] != '\0') && (fullPath[1] == ':')) { dev = Tcl_UniCharToLower(fullPath[0]) - 'a'; } Tcl_DStringFree(&ds); attr = data.dwFileAttributes; statPtr->st_size = ((Tcl_WideInt)data.nFileSizeLow) | (((Tcl_WideInt)data.nFileSizeHigh) << 32); statPtr->st_atime = ToCTime(data.ftLastAccessTime); statPtr->st_mtime = ToCTime(data.ftLastWriteTime); statPtr->st_ctime = ToCTime(data.ftCreationTime); } mode = NativeStatMode(attr, checkLinks, NativeIsExec(nativePath)); statPtr->st_dev = (dev_t) dev; statPtr->st_ino = 0; statPtr->st_mode = mode; statPtr->st_nlink = 1; statPtr->st_uid = 0; statPtr->st_gid = 0; statPtr->st_rdev = (dev_t) dev; return 0; } /* *---------------------------------------------------------------------- * * NativeStatMode -- * * Calculate just the 'st_mode' field of a 'stat' structure. * *---------------------------------------------------------------------- */ static unsigned short NativeStatMode(DWORD attr, int checkLinks, int isExec) { int mode; if (checkLinks && (attr & FILE_ATTRIBUTE_REPARSE_POINT)) { /* It is a link */ mode = S_IFLNK; } else { mode = (attr & FILE_ATTRIBUTE_DIRECTORY) ? S_IFDIR | S_IEXEC : S_IFREG; } mode |= (attr & FILE_ATTRIBUTE_READONLY) ? S_IREAD : S_IREAD | S_IWRITE; if (isExec) { mode |= S_IEXEC; } /* * Propagate the S_IREAD, S_IWRITE, S_IEXEC bits to the group and * other positions. */ mode |= (mode & (S_IREAD|S_IWRITE|S_IEXEC)) >> 3; mode |= (mode & (S_IREAD|S_IWRITE|S_IEXEC)) >> 6; return (unsigned short)mode; } /* *------------------------------------------------------------------------ * * ToCTime -- * * Converts a Windows FILETIME to a time_t in UTC. * * Results: * Returns the count of seconds from the Posix epoch. * *------------------------------------------------------------------------ */ static time_t ToCTime( FILETIME fileTime) /* UTC time */ { LARGE_INTEGER convertedTime; convertedTime.LowPart = fileTime.dwLowDateTime; convertedTime.HighPart = (LONG) fileTime.dwHighDateTime; return (time_t) ((convertedTime.QuadPart - (Tcl_WideInt) POSIX_EPOCH_AS_FILETIME) / (Tcl_WideInt) 10000000); } /* *------------------------------------------------------------------------ * * FromCTime -- * * Converts a time_t to a Windows FILETIME * * Results: * Returns the count of 100-ns ticks seconds from the Windows epoch. * *------------------------------------------------------------------------ */ static void FromCTime( time_t posixTime, FILETIME* fileTime) /* UTC Time */ { LARGE_INTEGER convertedTime; convertedTime.QuadPart = ((LONGLONG) posixTime) * 10000000 + POSIX_EPOCH_AS_FILETIME; fileTime->dwLowDateTime = convertedTime.LowPart; fileTime->dwHighDateTime = convertedTime.HighPart; } #if 0 /* *------------------------------------------------------------------------- * * TclWinResolveShortcut -- * * Resolve a potential Windows shortcut to get the actual file or * directory in question. * * Results: * Returns 1 if the shortcut could be resolved, or 0 if there was * an error or if the filename was not a shortcut. * If bufferPtr did hold the name of a shortcut, it is modified to * hold the resolved target of the shortcut instead. * * Side effects: * Loads and unloads OLE package to determine if filename refers to * a shortcut. * *------------------------------------------------------------------------- */ int TclWinResolveShortcut(bufferPtr) Tcl_DString *bufferPtr; /* Holds name of file to resolve. On * return, holds resolved file name. */ { HRESULT hres; IShellLink *psl; IPersistFile *ppf; WIN32_FIND_DATA wfd; WCHAR wpath[MAX_PATH]; char *path, *ext; char realFileName[MAX_PATH]; /* * Windows system calls do not automatically resolve * shortcuts like UNIX automatically will with symbolic links. */ path = Tcl_DStringValue(bufferPtr); ext = strrchr(path, '.'); if ((ext == NULL) || (stricmp(ext, ".lnk") != 0)) { return 0; } CoInitialize(NULL); path = Tcl_DStringValue(bufferPtr); realFileName[0] = '\0'; hres = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLink, &psl); if (SUCCEEDED(hres)) { hres = psl->lpVtbl->QueryInterface(psl, &IID_IPersistFile, &ppf); if (SUCCEEDED(hres)) { MultiByteToWideChar(CP_ACP, 0, path, -1, wpath, sizeof(wpath)); hres = ppf->lpVtbl->Load(ppf, wpath, STGM_READ); if (SUCCEEDED(hres)) { hres = psl->lpVtbl->Resolve(psl, NULL, SLR_ANY_MATCH | SLR_NO_UI); if (SUCCEEDED(hres)) { hres = psl->lpVtbl->GetPath(psl, realFileName, MAX_PATH, &wfd, 0); } } ppf->lpVtbl->Release(ppf); } psl->lpVtbl->Release(psl); } CoUninitialize(); if (realFileName[0] != '\0') { Tcl_DStringSetLength(bufferPtr, 0); Tcl_DStringAppend(bufferPtr, realFileName, -1); return 1; } return 0; } #endif Tcl_Obj* TclpObjGetCwd(interp) Tcl_Interp *interp; { Tcl_DString ds; if (TclpGetCwd(interp, &ds) != NULL) { Tcl_Obj *cwdPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds), -1); Tcl_IncrRefCount(cwdPtr); Tcl_DStringFree(&ds); return cwdPtr; } else { return NULL; } } int TclpObjAccess(pathPtr, mode) Tcl_Obj *pathPtr; int mode; { return NativeAccess((CONST TCHAR*) Tcl_FSGetNativePath(pathPtr), mode); } int TclpObjLstat(pathPtr, statPtr) Tcl_Obj *pathPtr; Tcl_StatBuf *statPtr; { /* * Ensure correct file sizes by forcing the OS to write any * pending data to disk. This is done only for channels which are * dirty, i.e. have been written to since the last flush here. */ TclWinFlushDirtyChannels (); return NativeStat((CONST TCHAR*) Tcl_FSGetNativePath(pathPtr), statPtr, 1); } #ifdef S_IFLNK Tcl_Obj* TclpObjLink(pathPtr, toPtr, linkAction) Tcl_Obj *pathPtr; Tcl_Obj *toPtr; int linkAction; { if (toPtr != NULL) { int res; TCHAR* LinkTarget = (TCHAR*)Tcl_FSGetNativePath(toPtr); TCHAR* LinkSource = (TCHAR*)Tcl_FSGetNativePath(pathPtr); if (LinkSource == NULL || LinkTarget == NULL) { return NULL; } res = WinLink(LinkSource, LinkTarget, linkAction); if (res == 0) { return toPtr; } else { return NULL; } } else { TCHAR* LinkSource = (TCHAR*)Tcl_FSGetNativePath(pathPtr); if (LinkSource == NULL) { return NULL; } return WinReadLink(LinkSource); } } #endif /* *--------------------------------------------------------------------------- * * TclpFilesystemPathType -- * * This function is part of the native filesystem support, and * returns the path type of the given path. Returns NTFS or FAT * or whatever is returned by the 'volume information' proc. * * Results: * NULL at present. * * Side effects: * None. * *--------------------------------------------------------------------------- */ Tcl_Obj* TclpFilesystemPathType(pathObjPtr) Tcl_Obj* pathObjPtr; { #define VOL_BUF_SIZE 32 int found; WCHAR volType[VOL_BUF_SIZE]; char* firstSeparator; CONST char *path; Tcl_Obj *normPath = Tcl_FSGetNormalizedPath(NULL, pathObjPtr); if (normPath == NULL) return NULL; path = Tcl_GetString(normPath); if (path == NULL) return NULL; firstSeparator = strchr(path, '/'); if (firstSeparator == NULL) { found = tclWinProcs->getVolumeInformationProc( Tcl_FSGetNativePath(pathObjPtr), NULL, 0, NULL, NULL, NULL, (WCHAR *)volType, VOL_BUF_SIZE); } else { Tcl_Obj *driveName = Tcl_NewStringObj(path, firstSeparator - path+1); Tcl_IncrRefCount(driveName); found = tclWinProcs->getVolumeInformationProc( Tcl_FSGetNativePath(driveName), NULL, 0, NULL, NULL, NULL, (WCHAR *)volType, VOL_BUF_SIZE); Tcl_DecrRefCount(driveName); } if (found == 0) { return NULL; } else { Tcl_DString ds; Tcl_Obj *objPtr; Tcl_WinTCharToUtf((CONST char *)volType, -1, &ds); objPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds),Tcl_DStringLength(&ds)); Tcl_DStringFree(&ds); return objPtr; } #undef VOL_BUF_SIZE } /* *--------------------------------------------------------------------------- * * TclpObjNormalizePath -- * * This function scans through a path specification and replaces it, * in place, with a normalized version. This means using the * 'longname', and expanding any symbolic links contained within the * path. * * Results: * The new 'nextCheckpoint' value, giving as far as we could * understand in the path. * * Side effects: * The pathPtr string, which must contain a valid path, is * possibly modified in place. * *--------------------------------------------------------------------------- */ int TclpObjNormalizePath(interp, pathPtr, nextCheckpoint) Tcl_Interp *interp; Tcl_Obj *pathPtr; int nextCheckpoint; { char *lastValidPathEnd = NULL; /* This will hold the normalized string */ Tcl_DString dsNorm; char *path; char *currentPathEndPosition; Tcl_Obj *temp = NULL; Tcl_DStringInit(&dsNorm); path = Tcl_GetString(pathPtr); if (TclWinGetPlatformId() == VER_PLATFORM_WIN32_WINDOWS) { /* * We're on Win95, 98 or ME. There are two assumptions * in this block of code. First that the native (NULL) * encoding is basically ascii, and second that symbolic * links are not possible. Both of these assumptions * appear to be true of these operating systems. */ int isDrive = 1; Tcl_DString ds; currentPathEndPosition = path + nextCheckpoint; if (*currentPathEndPosition == '/') { currentPathEndPosition++; } while (1) { char cur = *currentPathEndPosition; if ((cur == '/' || cur == 0) && (path != currentPathEndPosition)) { /* Reached directory separator, or end of string */ CONST char *nativePath = Tcl_UtfToExternalDString(NULL, path, currentPathEndPosition - path, &ds); /* * Now we convert the tail of the current path to its * 'long form', and append it to 'dsNorm' which holds * the current normalized path, if the file exists. */ if (isDrive) { if (GetFileAttributesA(nativePath) == INVALID_FILE_ATTRIBUTES) { /* File doesn't exist */ if (isDrive) { int len = WinIsReserved(path); if (len > 0) { /* Actually it does exist - COM1, etc */ int i; for (i=0;i= 'a') { ((char*)nativePath)[i] -= ('a' - 'A'); } } Tcl_DStringAppend(&dsNorm, nativePath, len); lastValidPathEnd = currentPathEndPosition; } else if (nextCheckpoint == 0) { /* Path starts with a drive designation * that's not actually on the system. * We still must normalize up past the * first separator. [Bug 3603434] */ currentPathEndPosition++; } } Tcl_DStringFree(&ds); break; } if (nativePath[0] >= 'a') { ((char*)nativePath)[0] -= ('a' - 'A'); } Tcl_DStringAppend(&dsNorm,nativePath,Tcl_DStringLength(&ds)); } else { WIN32_FIND_DATA fData; HANDLE handle; handle = FindFirstFileA(nativePath, &fData); if (handle == INVALID_HANDLE_VALUE) { if (GetFileAttributesA(nativePath) == INVALID_FILE_ATTRIBUTES) { /* File doesn't exist */ Tcl_DStringFree(&ds); break; } /* This is usually the '/' in 'c:/' at end of string */ Tcl_DStringAppend(&dsNorm,"/", 1); } else { char *nativeName; if (fData.cFileName[0] != '\0') { nativeName = fData.cFileName; } else { nativeName = fData.cAlternateFileName; } FindClose(handle); Tcl_DStringAppend(&dsNorm,"/", 1); Tcl_DStringAppend(&dsNorm,nativeName,-1); } } Tcl_DStringFree(&ds); lastValidPathEnd = currentPathEndPosition; if (cur == 0) { break; } /* * If we get here, we've got past one directory * delimiter, so we know it is no longer a drive */ isDrive = 0; } currentPathEndPosition++; } } else { /* We're on WinNT or 2000 or XP */ int isDrive = 1; Tcl_DString ds; currentPathEndPosition = path + nextCheckpoint; if (*currentPathEndPosition == '/') { currentPathEndPosition++; } while (1) { char cur = *currentPathEndPosition; if ((cur == '/' || cur == 0) && (path != currentPathEndPosition)) { /* Reached directory separator, or end of string */ WIN32_FILE_ATTRIBUTE_DATA data; CONST char *nativePath = Tcl_WinUtfToTChar(path, currentPathEndPosition - path, &ds); if ((*tclWinProcs->getFileAttributesExProc)(nativePath, GetFileExInfoStandard, &data) != TRUE) { /* File doesn't exist */ if (isDrive) { int len = WinIsReserved(path); if (len > 0) { /* Actually it does exist - COM1, etc */ int i; for (i=0;i= L'a') { wc -= (L'a' - L'A'); ((WCHAR*)nativePath)[i] = wc; } } Tcl_DStringAppend(&dsNorm, nativePath, sizeof(WCHAR)*len); lastValidPathEnd = currentPathEndPosition; } else if (nextCheckpoint == 0) { /* Path starts with a drive designation * that's not actually on the system. * We still must normalize up past the * first separator. [Bug 3603434] */ currentPathEndPosition++; } } Tcl_DStringFree(&ds); break; } /* * File 'nativePath' does exist if we get here. We * now want to check if it is a symlink and otherwise * continue with the rest of the path. */ /* * Check for symlinks, except at last component * of path (we don't follow final symlinks). Also * a drive (C:/) for example, may sometimes have * the reparse flag set for some reason I don't * understand. We therefore don't perform this * check for drives. */ if (cur != 0 && !isDrive && (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { Tcl_Obj *to = WinReadLinkDirectory(nativePath); if (to != NULL) { /* Read the reparse point ok */ /* Tcl_GetStringFromObj(to, &pathLen); */ nextCheckpoint = 0; /* pathLen */ Tcl_AppendToObj(to, currentPathEndPosition, -1); /* Convert link to forward slashes */ for (path = Tcl_GetString(to); *path != 0; path++) { if (*path == '\\') *path = '/'; } path = Tcl_GetString(to); currentPathEndPosition = path + nextCheckpoint; if (temp != NULL) { Tcl_DecrRefCount(temp); } temp = to; /* Reset variables so we can restart normalization */ isDrive = 1; Tcl_DStringFree(&dsNorm); Tcl_DStringInit(&dsNorm); Tcl_DStringFree(&ds); continue; } } /* * Now we convert the tail of the current path to its * 'long form', and append it to 'dsNorm' which holds * the current normalized path */ if (isDrive) { WCHAR drive = ((WCHAR*)nativePath)[0]; if (drive >= L'a') { drive -= (L'a' - L'A'); ((WCHAR*)nativePath)[0] = drive; } Tcl_DStringAppend(&dsNorm,nativePath,Tcl_DStringLength(&ds)); } else { char *checkDots = NULL; if (lastValidPathEnd[1] == '.') { checkDots = lastValidPathEnd + 1; while (checkDots < currentPathEndPosition) { if (*checkDots != '.') { checkDots = NULL; break; } checkDots++; } } if (checkDots != NULL) { int dotLen = currentPathEndPosition - lastValidPathEnd; /* * Path is just dots. We shouldn't really * ever see a path like that. However, to be * nice we at least don't mangle the path -- * we just add the dots as a path segment and * continue */ Tcl_DStringAppend(&dsNorm, (TCHAR*)((WCHAR*)(nativePath + Tcl_DStringLength(&ds)) - dotLen), (int)(dotLen * sizeof(WCHAR))); } else { /* Normal path */ WIN32_FIND_DATAW fData; HANDLE handle; handle = FindFirstFileW((WCHAR*)nativePath, &fData); if (handle == INVALID_HANDLE_VALUE) { /* This is usually the '/' in 'c:/' at end of string */ Tcl_DStringAppend(&dsNorm,(CONST char*)L"/", sizeof(WCHAR)); } else { WCHAR *nativeName; if (fData.cFileName[0] != '\0') { nativeName = fData.cFileName; } else { nativeName = fData.cAlternateFileName; } FindClose(handle); Tcl_DStringAppend(&dsNorm,(CONST char*)L"/", sizeof(WCHAR)); Tcl_DStringAppend(&dsNorm,(TCHAR*)nativeName, (int) (wcslen(nativeName)*sizeof(WCHAR))); } } } Tcl_DStringFree(&ds); lastValidPathEnd = currentPathEndPosition; if (cur == 0) { break; } /* * If we get here, we've got past one directory * delimiter, so we know it is no longer a drive */ isDrive = 0; } currentPathEndPosition++; } } /* Common code path for all Windows platforms */ nextCheckpoint = currentPathEndPosition - path; if (lastValidPathEnd != NULL) { /* * Concatenate the normalized string in dsNorm with the * tail of the path which we didn't recognise. The * string in dsNorm is in the native encoding, so we * have to convert it to Utf. */ Tcl_DString dsTemp; Tcl_WinTCharToUtf(Tcl_DStringValue(&dsNorm), Tcl_DStringLength(&dsNorm), &dsTemp); nextCheckpoint = Tcl_DStringLength(&dsTemp); if (*lastValidPathEnd != 0) { /* Not the end of the string */ int len; char *path; Tcl_Obj *tmpPathPtr; tmpPathPtr = Tcl_NewStringObj(Tcl_DStringValue(&dsTemp), nextCheckpoint); Tcl_AppendToObj(tmpPathPtr, lastValidPathEnd, -1); path = Tcl_GetStringFromObj(tmpPathPtr, &len); Tcl_SetStringObj(pathPtr, path, len); Tcl_DecrRefCount(tmpPathPtr); } else { /* End of string was reached above */ Tcl_SetStringObj(pathPtr, Tcl_DStringValue(&dsTemp), nextCheckpoint); } Tcl_DStringFree(&dsTemp); } Tcl_DStringFree(&dsNorm); /* * This must be done after we are totally finished with 'path' as we are * sharing the same underlying string. */ if (temp != NULL) { Tcl_DecrRefCount(temp); } return nextCheckpoint; } /* *--------------------------------------------------------------------------- * * TclpUtime -- * * Set the modification date for a file. * * Results: * 0 on success, -1 on error. * * Side effects: * Sets errno to a representation of any Windows problem that's observed * in the process. * *--------------------------------------------------------------------------- */ int TclpUtime( Tcl_Obj *pathPtr, /* File to modify */ struct utimbuf *tval) /* New modification date structure */ { int res = 0; HANDLE fileHandle; CONST TCHAR *native; DWORD attr = 0; DWORD flags = FILE_ATTRIBUTE_NORMAL; FILETIME lastAccessTime, lastModTime; FromCTime(tval->actime, &lastAccessTime); FromCTime(tval->modtime, &lastModTime); native = (CONST TCHAR *)Tcl_FSGetNativePath(pathPtr); attr = (*tclWinProcs->getFileAttributesProc)(native); if (attr != INVALID_FILE_ATTRIBUTES && attr & FILE_ATTRIBUTE_DIRECTORY) { flags = FILE_FLAG_BACKUP_SEMANTICS; } /* * We use the native APIs (not 'utime') because there are some daylight * savings complications that utime gets wrong. */ fileHandle = (tclWinProcs->createFileProc) ( native, FILE_WRITE_ATTRIBUTES, 0, NULL, OPEN_EXISTING, flags, NULL); if (fileHandle == INVALID_HANDLE_VALUE || !SetFileTime(fileHandle, NULL, &lastAccessTime, &lastModTime)) { TclWinConvertError(GetLastError()); res = -1; } if (fileHandle != INVALID_HANDLE_VALUE) { CloseHandle(fileHandle); } return res; } tcl8.4.20/win/tclWin32Dll.c0000644003604700454610000011043111737050675013722 0ustar dgp771div/* * tclWin32Dll.c -- * * This file contains the DLL entry point. * * Copyright (c) 1995-1996 Sun Microsystems, Inc. * Copyright (c) 1998-2000 Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclWinInt.h" /* * The following data structures are used when loading the thunking * library for execing child processes under Win32s. */ typedef DWORD (WINAPI UT32PROC)(LPVOID lpBuff, DWORD dwUserDefined, LPVOID *lpTranslationList); typedef BOOL (WINAPI UTREGISTER)(HANDLE hModule, LPCSTR SixteenBitDLL, LPCSTR InitName, LPCSTR ProcName, UT32PROC **ThirtyTwoBitThunk, FARPROC UT32Callback, LPVOID Buff); typedef VOID (WINAPI UTUNREGISTER)(HANDLE hModule); /* * The following variables keep track of information about this DLL * on a per-instance basis. Each time this DLL is loaded, it gets its own * new data segment with its own copy of all static and global information. */ static HINSTANCE hInstance; /* HINSTANCE of this DLL. */ static int platformId; /* Running under NT, or 95/98? */ #ifdef HAVE_NO_SEH /* * Unlike Borland and Microsoft, we don't register exception handlers * by pushing registration records onto the runtime stack. Instead, we * register them by creating an EXCEPTION_REGISTRATION within the activation * record. */ typedef struct EXCEPTION_REGISTRATION { struct EXCEPTION_REGISTRATION* link; EXCEPTION_DISPOSITION (*handler)( struct _EXCEPTION_RECORD*, void*, struct _CONTEXT*, void* ); void* ebp; void* esp; int status; } EXCEPTION_REGISTRATION; #endif /* * VC++ 5.x has no 'cpuid' assembler instruction, so we * must emulate it */ #if defined(_MSC_VER) && ( _MSC_VER <= 1100 ) #define cpuid __asm __emit 0fh __asm __emit 0a2h #endif /* * The following function tables are used to dispatch to either the * wide-character or multi-byte versions of the operating system calls, * depending on whether the Unicode calls are available. */ static TclWinProcs asciiProcs = { 0, (BOOL (WINAPI *)(CONST TCHAR *, LPDCB)) BuildCommDCBA, (TCHAR *(WINAPI *)(TCHAR *)) CharLowerA, (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR *, BOOL)) CopyFileA, (BOOL (WINAPI *)(CONST TCHAR *, LPSECURITY_ATTRIBUTES)) CreateDirectoryA, (HANDLE (WINAPI *)(CONST TCHAR *, DWORD, DWORD, SECURITY_ATTRIBUTES *, DWORD, DWORD, HANDLE)) CreateFileA, (BOOL (WINAPI *)(CONST TCHAR *, TCHAR *, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, CONST TCHAR *, LPSTARTUPINFOA, LPPROCESS_INFORMATION)) CreateProcessA, (BOOL (WINAPI *)(CONST TCHAR *)) DeleteFileA, (HANDLE (WINAPI *)(CONST TCHAR *, WIN32_FIND_DATAT *)) FindFirstFileA, (BOOL (WINAPI *)(HANDLE, WIN32_FIND_DATAT *)) FindNextFileA, (BOOL (WINAPI *)(WCHAR *, LPDWORD)) GetComputerNameA, (DWORD (WINAPI *)(DWORD, WCHAR *)) GetCurrentDirectoryA, (DWORD (WINAPI *)(CONST TCHAR *)) GetFileAttributesA, (DWORD (WINAPI *)(CONST TCHAR *, DWORD nBufferLength, WCHAR *, TCHAR **)) GetFullPathNameA, (DWORD (WINAPI *)(HMODULE, WCHAR *, int)) GetModuleFileNameA, (DWORD (WINAPI *)(CONST TCHAR *, WCHAR *, DWORD)) GetShortPathNameA, (UINT (WINAPI *)(CONST TCHAR *, CONST TCHAR *, UINT uUnique, WCHAR *)) GetTempFileNameA, (DWORD (WINAPI *)(DWORD, WCHAR *)) GetTempPathA, (BOOL (WINAPI *)(CONST TCHAR *, WCHAR *, DWORD, LPDWORD, LPDWORD, LPDWORD, WCHAR *, DWORD)) GetVolumeInformationA, (HINSTANCE (WINAPI *)(const TCHAR *, HANDLE, DWORD)) LoadLibraryExA, (TCHAR (WINAPI *)(WCHAR *, CONST TCHAR *)) lstrcpyA, (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR *)) MoveFileA, (BOOL (WINAPI *)(CONST TCHAR *)) RemoveDirectoryA, (DWORD (WINAPI *)(CONST TCHAR *, CONST TCHAR *, CONST TCHAR *, DWORD, WCHAR *, TCHAR **)) SearchPathA, (BOOL (WINAPI *)(CONST TCHAR *)) SetCurrentDirectoryA, (BOOL (WINAPI *)(CONST TCHAR *, DWORD)) SetFileAttributesA, /* * The three NULL function pointers will only be set when * Tcl_FindExecutable is called. If you don't ever call that * function, the application will crash whenever WinTcl tries to call * functions through these null pointers. That is not a bug in Tcl * -- Tcl_FindExecutable is obligatory in recent Tcl releases. */ NULL, NULL, (int (__cdecl*)(CONST TCHAR *, struct _utimbuf *)) _utime, NULL, NULL, /* getLongPathNameProc */ NULL, /* Security SDK - not available on 95,98,ME */ NULL, NULL, NULL, NULL, NULL, NULL, /* ReadConsole and WriteConsole */ (BOOL (WINAPI *)(HANDLE, LPVOID, DWORD, LPDWORD, LPVOID)) ReadConsoleA, (BOOL (WINAPI *)(HANDLE, const VOID*, DWORD, LPDWORD, LPVOID)) WriteConsoleA }; static TclWinProcs unicodeProcs = { 1, (BOOL (WINAPI *)(CONST TCHAR *, LPDCB)) BuildCommDCBW, (TCHAR *(WINAPI *)(TCHAR *)) CharLowerW, (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR *, BOOL)) CopyFileW, (BOOL (WINAPI *)(CONST TCHAR *, LPSECURITY_ATTRIBUTES)) CreateDirectoryW, (HANDLE (WINAPI *)(CONST TCHAR *, DWORD, DWORD, SECURITY_ATTRIBUTES *, DWORD, DWORD, HANDLE)) CreateFileW, (BOOL (WINAPI *)(CONST TCHAR *, TCHAR *, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, CONST TCHAR *, LPSTARTUPINFOA, LPPROCESS_INFORMATION)) CreateProcessW, (BOOL (WINAPI *)(CONST TCHAR *)) DeleteFileW, (HANDLE (WINAPI *)(CONST TCHAR *, WIN32_FIND_DATAT *)) FindFirstFileW, (BOOL (WINAPI *)(HANDLE, WIN32_FIND_DATAT *)) FindNextFileW, (BOOL (WINAPI *)(WCHAR *, LPDWORD)) GetComputerNameW, (DWORD (WINAPI *)(DWORD, WCHAR *)) GetCurrentDirectoryW, (DWORD (WINAPI *)(CONST TCHAR *)) GetFileAttributesW, (DWORD (WINAPI *)(CONST TCHAR *, DWORD nBufferLength, WCHAR *, TCHAR **)) GetFullPathNameW, (DWORD (WINAPI *)(HMODULE, WCHAR *, int)) GetModuleFileNameW, (DWORD (WINAPI *)(CONST TCHAR *, WCHAR *, DWORD)) GetShortPathNameW, (UINT (WINAPI *)(CONST TCHAR *, CONST TCHAR *, UINT uUnique, WCHAR *)) GetTempFileNameW, (DWORD (WINAPI *)(DWORD, WCHAR *)) GetTempPathW, (BOOL (WINAPI *)(CONST TCHAR *, WCHAR *, DWORD, LPDWORD, LPDWORD, LPDWORD, WCHAR *, DWORD)) GetVolumeInformationW, (HINSTANCE (WINAPI *)(const TCHAR *, HANDLE, DWORD)) LoadLibraryExW, (TCHAR (WINAPI *)(WCHAR *, CONST TCHAR *)) lstrcpyW, (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR *)) MoveFileW, (BOOL (WINAPI *)(CONST TCHAR *)) RemoveDirectoryW, (DWORD (WINAPI *)(CONST TCHAR *, CONST TCHAR *, CONST TCHAR *, DWORD, WCHAR *, TCHAR **)) SearchPathW, (BOOL (WINAPI *)(CONST TCHAR *)) SetCurrentDirectoryW, (BOOL (WINAPI *)(CONST TCHAR *, DWORD)) SetFileAttributesW, /* * The three NULL function pointers will only be set when * Tcl_FindExecutable is called. If you don't ever call that * function, the application will crash whenever WinTcl tries to call * functions through these null pointers. That is not a bug in Tcl * -- Tcl_FindExecutable is obligatory in recent Tcl releases. */ NULL, NULL, (int (__cdecl*)(CONST TCHAR *, struct _utimbuf *)) _wutime, NULL, NULL, /* getLongPathNameProc */ NULL, /* Security SDK - will be filled in on NT,XP,2000,2003 */ NULL, NULL, NULL, NULL, NULL, NULL, /* ReadConsole and WriteConsole */ (BOOL (WINAPI *)(HANDLE, LPVOID, DWORD, LPDWORD, LPVOID)) ReadConsoleW, (BOOL (WINAPI *)(HANDLE, const VOID*, DWORD, LPDWORD, LPVOID)) WriteConsoleW }; TclWinProcs *tclWinProcs; static Tcl_Encoding tclWinTCharEncoding; #ifdef HAVE_NO_SEH /* Need to add noinline flag to DllMain declaration so that gcc -O3 * does not inline asm code into DllEntryPoint and cause a * compile time error because of redefined local labels. */ BOOL APIENTRY DllMain(HINSTANCE hInst, DWORD reason, LPVOID reserved) __attribute__ ((noinline)); #else /* * The following declaration is for the VC++ DLL entry point. */ BOOL APIENTRY DllMain(HINSTANCE hInst, DWORD reason, LPVOID reserved); #endif /* HAVE_NO_SEH */ /* * The following structure and linked list is to allow us to map between * volume mount points and drive letters on the fly (no Win API exists * for this). */ typedef struct MountPointMap { CONST WCHAR* volumeName; /* Native wide string volume name */ char driveLetter; /* Drive letter corresponding to * the volume name. */ struct MountPointMap* nextPtr; /* Pointer to next structure in list, * or NULL */ } MountPointMap; /* * This is the head of the linked list, which is protected by the * mutex which follows, for thread-enabled builds. */ MountPointMap *driveLetterLookup = NULL; TCL_DECLARE_MUTEX(mountPointMap) /* We will need this below */ extern Tcl_FSDupInternalRepProc TclNativeDupInternalRep; #ifdef __WIN32__ #ifndef STATIC_BUILD /* *---------------------------------------------------------------------- * * DllEntryPoint -- * * This wrapper function is used by Borland to invoke the * initialization code for Tcl. It simply calls the DllMain * routine. * * Results: * See DllMain. * * Side effects: * See DllMain. * *---------------------------------------------------------------------- */ BOOL APIENTRY DllEntryPoint(hInst, reason, reserved) HINSTANCE hInst; /* Library instance handle. */ DWORD reason; /* Reason this function is being called. */ LPVOID reserved; /* Not used. */ { return DllMain(hInst, reason, reserved); } /* *---------------------------------------------------------------------- * * DllMain -- * * This routine is called by the VC++ C run time library init * code, or the DllEntryPoint routine. It is responsible for * initializing various dynamically loaded libraries. * * Results: * TRUE on sucess, FALSE on failure. * * Side effects: * Establishes 32-to-16 bit thunk and initializes sockets library. * *---------------------------------------------------------------------- */ BOOL APIENTRY DllMain(hInst, reason, reserved) HINSTANCE hInst; /* Library instance handle. */ DWORD reason; /* Reason this function is being called. */ LPVOID reserved; /* Not used. */ { #if defined(HAVE_NO_SEH) && !defined(_WIN64) EXCEPTION_REGISTRATION registration; #endif switch (reason) { case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls(hInst); TclWinInit(hInst); return TRUE; case DLL_PROCESS_DETACH: /* * Protect the call to Tcl_Finalize. The OS could be unloading us from * an exception handler and the state of the stack might be unstable. */ #if defined(HAVE_NO_SEH) && !defined(_WIN64) __asm__ __volatile__ ( /* * Construct an EXCEPTION_REGISTRATION to protect the call to * Tcl_Finalize */ "leal %[registration], %%edx" "\n\t" "movl %%fs:0, %%eax" "\n\t" "movl %%eax, 0x0(%%edx)" "\n\t" /* link */ "leal 1f, %%eax" "\n\t" "movl %%eax, 0x4(%%edx)" "\n\t" /* handler */ "movl %%ebp, 0x8(%%edx)" "\n\t" /* ebp */ "movl %%esp, 0xc(%%edx)" "\n\t" /* esp */ "movl %[error], 0x10(%%edx)" "\n\t" /* status */ /* * Link the EXCEPTION_REGISTRATION on the chain */ "movl %%edx, %%fs:0" "\n\t" /* * Call Tcl_Finalize */ "call _Tcl_Finalize" "\n\t" /* * Come here on a normal exit. Recover the EXCEPTION_REGISTRATION * and store a TCL_OK status */ "movl %%fs:0, %%edx" "\n\t" "movl %[ok], %%eax" "\n\t" "movl %%eax, 0x10(%%edx)" "\n\t" "jmp 2f" "\n" /* * Come here on an exception. Get the EXCEPTION_REGISTRATION that * we previously put on the chain. */ "1:" "\t" "movl %%fs:0, %%edx" "\n\t" "movl 0x8(%%edx), %%edx" "\n" /* * Come here however we exited. Restore context from the * EXCEPTION_REGISTRATION in case the stack is unbalanced. */ "2:" "\t" "movl 0xc(%%edx), %%esp" "\n\t" "movl 0x8(%%edx), %%ebp" "\n\t" "movl 0x0(%%edx), %%eax" "\n\t" "movl %%eax, %%fs:0" "\n\t" : /* No outputs */ : [registration] "m" (registration), [ok] "i" (TCL_OK), [error] "i" (TCL_ERROR) : "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory" ); #else #ifndef HAVE_NO_SEH __try { #endif Tcl_Finalize(); #ifndef HAVE_NO_SEH } __except (EXCEPTION_EXECUTE_HANDLER) { /* empty handler body. */ } #endif #endif break; } return TRUE; } #endif /* !STATIC_BUILD */ #endif /* __WIN32__ */ /* *---------------------------------------------------------------------- * * TclWinGetTclInstance -- * * Retrieves the global library instance handle. * * Results: * Returns the global library instance handle. * * Side effects: * None. * *---------------------------------------------------------------------- */ HINSTANCE TclWinGetTclInstance() { return hInstance; } /* *---------------------------------------------------------------------- * * TclWinInit -- * * This function initializes the internal state of the tcl library. * * Results: * None. * * Side effects: * Initializes the tclPlatformId variable. * *---------------------------------------------------------------------- */ void TclWinInit(hInst) HINSTANCE hInst; /* Library instance handle. */ { OSVERSIONINFO os; hInstance = hInst; os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&os); platformId = os.dwPlatformId; /* * We no longer support Win32s, so just in case someone manages to * get a runtime there, make sure they know that. */ if (platformId == VER_PLATFORM_WIN32s) { panic("Win32s is not a supported platform"); } tclWinProcs = &asciiProcs; } /* *---------------------------------------------------------------------- * * TclWinGetPlatformId -- * * Determines whether running under NT, 95, or Win32s, to allow * runtime conditional code. * * Results: * The return value is one of: * VER_PLATFORM_WIN32s Win32s on Windows 3.1. (not supported) * VER_PLATFORM_WIN32_WINDOWS Win32 on Windows 95. * VER_PLATFORM_WIN32_NT Win32 on Windows NT * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclWinGetPlatformId() { return platformId; } /* *------------------------------------------------------------------------- * * TclWinNoBackslash -- * * We're always iterating through a string in Windows, changing the * backslashes to slashes for use in Tcl. * * Results: * All backslashes in given string are changed to slashes. * * Side effects: * None. * *------------------------------------------------------------------------- */ char * TclWinNoBackslash( char *path) /* String to change. */ { char *p; for (p = path; *p != '\0'; p++) { if (*p == '\\') { *p = '/'; } } return path; } /* *---------------------------------------------------------------------- * * TclpCheckStackSpace -- * * Detect if we are about to blow the stack. Called before an * evaluation can happen when nesting depth is checked. * * Results: * 1 if there is enough stack space to continue; 0 if not. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclpCheckStackSpace() { #if defined(HAVE_NO_SEH) && !defined(__WIN64__) EXCEPTION_REGISTRATION registration; #endif int retval = 0; /* * We can recurse only if there is at least TCL_WIN_STACK_THRESHOLD * bytes of stack space left. alloca() is cheap on windows; basically * it just subtracts from the stack pointer causing the OS to throw an * exception if the stack pointer is set below the bottom of the stack. */ #ifdef HAVE_NO_SEH # ifdef __WIN64__ /* TODO: How to call allocal on Win64? */ retval = 1; # else __asm__ __volatile__ ( /* * Construct an EXCEPTION_REGISTRATION to protect the * call to __alloca */ "leal %[registration], %%edx" "\n\t" "movl %%fs:0, %%eax" "\n\t" "movl %%eax, 0x0(%%edx)" "\n\t" /* link */ "leal 1f, %%eax" "\n\t" "movl %%eax, 0x4(%%edx)" "\n\t" /* handler */ "movl %%ebp, 0x8(%%edx)" "\n\t" /* ebp */ "movl %%esp, 0xc(%%edx)" "\n\t" /* esp */ "movl %[error], 0x10(%%edx)" "\n\t" /* status */ /* * Link the EXCEPTION_REGISTRATION on the chain */ "movl %%edx, %%fs:0" "\n\t" /* * Attempt a call to __alloca, to determine whether there's * sufficient memory to be had. */ "movl %[size], %%eax" "\n\t" "pushl %%eax" "\n\t" "call __alloca" "\n\t" /* * Come here on a normal exit. Recover the EXCEPTION_REGISTRATION * and store a TCL_OK status */ "movl %%fs:0, %%edx" "\n\t" "movl %[ok], %%eax" "\n\t" "movl %%eax, 0x10(%%edx)" "\n\t" "jmp 2f" "\n" /* * Come here on an exception. Get the EXCEPTION_REGISTRATION * that we previously put on the chain. */ "1:" "\t" "movl %%fs:0, %%edx" "\n\t" "movl 0x8(%%edx), %%edx" "\n\t" /* * Come here however we exited. Restore context from the * EXCEPTION_REGISTRATION in case the stack is unbalanced. */ "2:" "\t" "movl 0xc(%%edx), %%esp" "\n\t" "movl 0x8(%%edx), %%ebp" "\n\t" "movl 0x0(%%edx), %%eax" "\n\t" "movl %%eax, %%fs:0" "\n\t" : /* No outputs */ : [registration] "m" (registration), [ok] "i" (TCL_OK), [error] "i" (TCL_ERROR), [size] "i" (TCL_WIN_STACK_THRESHOLD) : "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory" ); retval = (registration.status == TCL_OK); # endif #else /* !HAVE_NO_SEH */ __try { #ifdef HAVE_ALLOCA_GCC_INLINE __asm__ __volatile__ ( "movl %0, %%eax" "\n\t" "call __alloca" "\n\t" : : "i"(TCL_WIN_STACK_THRESHOLD) : "%eax"); #else alloca(TCL_WIN_STACK_THRESHOLD); #endif /* HAVE_ALLOCA_GCC_INLINE */ retval = 1; } __except (EXCEPTION_EXECUTE_HANDLER) {} #endif /* HAVE_NO_SEH */ return retval; } /* *---------------------------------------------------------------------- * * TclWinGetPlatform -- * * This is a kludge that allows the test library to get access * the internal tclPlatform variable. * * Results: * Returns a pointer to the tclPlatform variable. * * Side effects: * None. * *---------------------------------------------------------------------- */ TclPlatformType * TclWinGetPlatform() { return &tclPlatform; } /* *--------------------------------------------------------------------------- * * TclWinSetInterfaces -- * * A helper proc that allows the test library to change the * tclWinProcs structure to dispatch to either the wide-character * or multi-byte versions of the operating system calls, depending * on whether Unicode is the system encoding. * * As well as this, we can also try to load in some additional * procs which may/may not be present depending on the current * Windows version (e.g. Win95 will not have the procs below). * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ void TclWinSetInterfaces( int wide) /* Non-zero to use wide interfaces, 0 * otherwise. */ { Tcl_FreeEncoding(tclWinTCharEncoding); if (wide) { tclWinProcs = &unicodeProcs; tclWinTCharEncoding = Tcl_GetEncoding(NULL, "unicode"); if (tclWinProcs->getFileAttributesExProc == NULL) { HINSTANCE hInstance = LoadLibraryA("kernel32"); if (hInstance != NULL) { tclWinProcs->getFileAttributesExProc = (BOOL (WINAPI *)(CONST TCHAR *, GET_FILEEX_INFO_LEVELS, LPVOID)) GetProcAddress(hInstance, "GetFileAttributesExW"); tclWinProcs->createHardLinkProc = (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR*, LPSECURITY_ATTRIBUTES)) GetProcAddress(hInstance, "CreateHardLinkW"); tclWinProcs->findFirstFileExProc = (HANDLE (WINAPI *)(CONST TCHAR*, UINT, LPVOID, UINT, LPVOID, DWORD)) GetProcAddress(hInstance, "FindFirstFileExW"); tclWinProcs->getVolumeNameForVMPProc = (BOOL (WINAPI *)(CONST TCHAR*, TCHAR*, DWORD)) GetProcAddress(hInstance, "GetVolumeNameForVolumeMountPointW"); FreeLibrary(hInstance); } hInstance = LoadLibraryA("advapi32"); if (hInstance != NULL) { tclWinProcs->getFileSecurityProc = (BOOL (WINAPI *)( LPCTSTR lpFileName, SECURITY_INFORMATION RequestedInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD nLength, LPDWORD lpnLengthNeeded)) GetProcAddress(hInstance, "GetFileSecurityW"); tclWinProcs->impersonateSelfProc = (BOOL (WINAPI *) ( SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)) GetProcAddress(hInstance, "ImpersonateSelf"); tclWinProcs->openThreadTokenProc = (BOOL (WINAPI *) ( HANDLE ThreadHandle, DWORD DesiredAccess, BOOL OpenAsSelf, PHANDLE TokenHandle)) GetProcAddress(hInstance, "OpenThreadToken"); tclWinProcs->revertToSelfProc = (BOOL (WINAPI *) (void)) GetProcAddress(hInstance, "RevertToSelf"); tclWinProcs->mapGenericMaskProc = (VOID (WINAPI *) ( PDWORD AccessMask, PGENERIC_MAPPING GenericMapping)) GetProcAddress(hInstance, "MapGenericMask"); tclWinProcs->accessCheckProc = (BOOL (WINAPI *)( PSECURITY_DESCRIPTOR pSecurityDescriptor, HANDLE ClientToken, DWORD DesiredAccess, PGENERIC_MAPPING GenericMapping, PPRIVILEGE_SET PrivilegeSet, LPDWORD PrivilegeSetLength, LPDWORD GrantedAccess, LPBOOL AccessStatus)) GetProcAddress(hInstance, "AccessCheck"); FreeLibrary(hInstance); } } } else { tclWinProcs = &asciiProcs; tclWinTCharEncoding = NULL; if (tclWinProcs->getFileAttributesExProc == NULL) { HINSTANCE hInstance = LoadLibraryA("kernel32"); if (hInstance != NULL) { tclWinProcs->getFileAttributesExProc = (BOOL (WINAPI *)(CONST TCHAR *, GET_FILEEX_INFO_LEVELS, LPVOID)) GetProcAddress(hInstance, "GetFileAttributesExA"); tclWinProcs->createHardLinkProc = (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR*, LPSECURITY_ATTRIBUTES)) GetProcAddress(hInstance, "CreateHardLinkA"); tclWinProcs->findFirstFileExProc = (HANDLE (WINAPI *)(CONST TCHAR*, UINT, LPVOID, UINT, LPVOID, DWORD)) GetProcAddress(hInstance, "FindFirstFileExA"); tclWinProcs->getLongPathNameProc = NULL; tclWinProcs->getVolumeNameForVMPProc = (BOOL (WINAPI *)(CONST TCHAR*, TCHAR*, DWORD)) GetProcAddress(hInstance, "GetVolumeNameForVolumeMountPointA"); FreeLibrary(hInstance); } } } } /* *--------------------------------------------------------------------------- * * TclWinResetInterfaceEncodings -- * * Called during finalization to free up any encodings we use. * The tclWinProcs-> look up table is still ok to use after * this call, provided no encoding conversion is required. * * We also clean up any memory allocated in our mount point * map which is used to follow certain kinds of symlinks. * That code should never be used once encodings are taken * down. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ void TclWinResetInterfaceEncodings() { MountPointMap *dlIter, *dlIter2; if (tclWinTCharEncoding != NULL) { Tcl_FreeEncoding(tclWinTCharEncoding); tclWinTCharEncoding = NULL; } /* Clean up the mount point map */ Tcl_MutexLock(&mountPointMap); dlIter = driveLetterLookup; while (dlIter != NULL) { dlIter2 = dlIter->nextPtr; ckfree((char*)dlIter->volumeName); ckfree((char*)dlIter); dlIter = dlIter2; } Tcl_MutexUnlock(&mountPointMap); } /* *--------------------------------------------------------------------------- * * TclWinResetInterfaces -- * * Called during finalization to reset us to a safe state for reuse. * After this call, it is best not to use the tclWinProcs-> look * up table since it is likely to be different to what is expected. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ void TclWinResetInterfaces() { tclWinProcs = &asciiProcs; } /* *-------------------------------------------------------------------- * * TclWinDriveLetterForVolMountPoint * * Unfortunately, Windows provides no easy way at all to get hold * of the drive letter for a volume mount point, but we need that * information to understand paths correctly. So, we have to * build an associated array to find these correctly, and allow * quick and easy lookup from volume mount points to drive letters. * * We assume here that we are running on a system for which the wide * character interfaces are used, which is valid for Win 2000 and WinXP * which are the only systems on which this function will ever be called. * * Result: the drive letter, or -1 if no drive letter corresponds to * the given mount point. * *-------------------------------------------------------------------- */ char TclWinDriveLetterForVolMountPoint(CONST WCHAR *mountPoint) { MountPointMap *dlIter, *dlPtr2; WCHAR Target[55]; /* Target of mount at mount point */ WCHAR drive[4] = { L'A', L':', L'\\', L'\0' }; /* * Detect the volume mounted there. Unfortunately, there is no * simple way to map a unique volume name to a DOS drive letter. * So, we have to build an associative array. */ Tcl_MutexLock(&mountPointMap); dlIter = driveLetterLookup; while (dlIter != NULL) { if (wcscmp(dlIter->volumeName, mountPoint) == 0) { /* * We need to check whether this information is * still valid, since either the user or various * programs could have adjusted the mount points on * the fly. */ drive[0] = L'A' + (dlIter->driveLetter - 'A'); /* Try to read the volume mount point and see where it points */ if ((*tclWinProcs->getVolumeNameForVMPProc)((TCHAR*)drive, (TCHAR*)Target, 55) != 0) { if (wcscmp((WCHAR*)dlIter->volumeName, Target) == 0) { /* Nothing has changed */ Tcl_MutexUnlock(&mountPointMap); return dlIter->driveLetter; } } /* * If we reach here, unfortunately, this mount point is * no longer valid at all */ if (driveLetterLookup == dlIter) { dlPtr2 = dlIter; driveLetterLookup = dlIter->nextPtr; } else { for (dlPtr2 = driveLetterLookup; dlPtr2 != NULL; dlPtr2 = dlPtr2->nextPtr) { if (dlPtr2->nextPtr == dlIter) { dlPtr2->nextPtr = dlIter->nextPtr; dlPtr2 = dlIter; break; } } } /* Now dlPtr2 points to the structure to free */ ckfree((char*)dlPtr2->volumeName); ckfree((char*)dlPtr2); /* * Restart the loop --- we could try to be clever * and continue half way through, but the logic is a * bit messy, so it's cleanest just to restart */ dlIter = driveLetterLookup; continue; } dlIter = dlIter->nextPtr; } /* We couldn't find it, so we must iterate over the letters */ for (drive[0] = L'A'; drive[0] <= L'Z'; drive[0]++) { /* Try to read the volume mount point and see where it points */ if ((*tclWinProcs->getVolumeNameForVMPProc)((TCHAR*)drive, (TCHAR*)Target, 55) != 0) { int alreadyStored = 0; for (dlIter = driveLetterLookup; dlIter != NULL; dlIter = dlIter->nextPtr) { if (wcscmp((WCHAR*)dlIter->volumeName, Target) == 0) { alreadyStored = 1; break; } } if (!alreadyStored) { dlPtr2 = (MountPointMap*) ckalloc(sizeof(MountPointMap)); dlPtr2->volumeName = TclNativeDupInternalRep(Target); dlPtr2->driveLetter = 'A' + (drive[0] - L'A'); dlPtr2->nextPtr = driveLetterLookup; driveLetterLookup = dlPtr2; } } } /* Try again */ for (dlIter = driveLetterLookup; dlIter != NULL; dlIter = dlIter->nextPtr) { if (wcscmp(dlIter->volumeName, mountPoint) == 0) { Tcl_MutexUnlock(&mountPointMap); return dlIter->driveLetter; } } /* * The volume doesn't appear to correspond to a drive letter -- we * remember that fact and store '-1' so we don't have to look it * up each time. */ dlPtr2 = (MountPointMap*) ckalloc(sizeof(MountPointMap)); dlPtr2->volumeName = TclNativeDupInternalRep((ClientData)mountPoint); dlPtr2->driveLetter = -1; dlPtr2->nextPtr = driveLetterLookup; driveLetterLookup = dlPtr2; Tcl_MutexUnlock(&mountPointMap); return -1; } /* *--------------------------------------------------------------------------- * * Tcl_WinUtfToTChar, Tcl_WinTCharToUtf -- * * Convert between UTF-8 and Unicode when running Windows NT or * the current ANSI code page when running Windows 95. * * On Mac, Unix, and Windows 95, all strings exchanged between Tcl * and the OS are "char" oriented. We need only one Tcl_Encoding to * convert between UTF-8 and the system's native encoding. We use * NULL to represent that encoding. * * On NT, some strings exchanged between Tcl and the OS are "char" * oriented, while others are in Unicode. We need two Tcl_Encoding * APIs depending on whether we are targeting a "char" or Unicode * interface. * * Calling Tcl_UtfToExternal() or Tcl_ExternalToUtf() with an * encoding of NULL should always used to convert between UTF-8 * and the system's "char" oriented encoding. The following two * functions are used in Windows-specific code to convert between * UTF-8 and Unicode strings (NT) or "char" strings(95). This saves * you the trouble of writing the following type of fragment over and * over: * * if (running NT) { * encoding <- Tcl_GetEncoding("unicode"); * nativeBuffer <- UtfToExternal(encoding, utfBuffer); * Tcl_FreeEncoding(encoding); * } else { * nativeBuffer <- UtfToExternal(NULL, utfBuffer); * } * * By convention, in Windows a TCHAR is a character in the ANSI code * page on Windows 95, a Unicode character on Windows NT. If you * plan on targeting a Unicode interfaces when running on NT and a * "char" oriented interface while running on 95, these functions * should be used. If you plan on targetting the same "char" * oriented function on both 95 and NT, use Tcl_UtfToExternal() * with an encoding of NULL. * * Results: * The result is a pointer to the string in the desired target * encoding. Storage for the result string is allocated in * dsPtr; the caller must call Tcl_DStringFree() when the result * is no longer needed. * * Side effects: * None. * *--------------------------------------------------------------------------- */ TCHAR * Tcl_WinUtfToTChar(string, len, dsPtr) CONST char *string; /* Source string in UTF-8. */ int len; /* Source string length in bytes, or < 0 for * strlen(). */ Tcl_DString *dsPtr; /* Uninitialized or free DString in which * the converted string is stored. */ { return (TCHAR *) Tcl_UtfToExternalDString(tclWinTCharEncoding, string, len, dsPtr); } char * Tcl_WinTCharToUtf(string, len, dsPtr) CONST TCHAR *string; /* Source string in Unicode when running * NT, ANSI when running 95. */ int len; /* Source string length in bytes, or < 0 for * platform-specific string length. */ Tcl_DString *dsPtr; /* Uninitialized or free DString in which * the converted string is stored. */ { return Tcl_ExternalToUtfDString(tclWinTCharEncoding, (CONST char *) string, len, dsPtr); } /* *------------------------------------------------------------------------ * * TclWinCPUID -- * * Get CPU ID information on an Intel box under Windows * * Results: * Returns TCL_OK if successful, TCL_ERROR if CPUID is not supported or * fails. * * Side effects: * If successful, stores EAX, EBX, ECX and EDX registers after the CPUID * instruction in the four integers designated by 'regsPtr' * *---------------------------------------------------------------------- */ int TclWinCPUID( unsigned int index, /* Which CPUID value to retrieve. */ unsigned int *regsPtr) /* Registers after the CPUID. */ { int status = TCL_ERROR; #if defined(__GNUC__) # if defined(_WIN64) /* * Execute the CPUID instruction with the given index, and store results * off 'regsPtr'. */ __asm__ __volatile__( /* * Do the CPUID instruction, and save the results in the 'regsPtr' * area. */ "movl %[rptr], %%edi" "\n\t" "movl %[index], %%eax" "\n\t" "cpuid" "\n\t" "movl %%eax, 0x0(%%edi)" "\n\t" "movl %%ebx, 0x4(%%edi)" "\n\t" "movl %%ecx, 0x8(%%edi)" "\n\t" "movl %%edx, 0xc(%%edi)" "\n\t" : /* No outputs */ : [index] "m" (index), [rptr] "m" (regsPtr) : "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory"); status = TCL_OK; # else EXCEPTION_REGISTRATION registration; /* * Execute the CPUID instruction with the given index, and store results * off 'regPtr'. */ __asm__ __volatile__( /* * Construct an EXCEPTION_REGISTRATION to protect the CPUID * instruction (early 486's don't have CPUID) */ "leal %[registration], %%edx" "\n\t" "movl %%fs:0, %%eax" "\n\t" "movl %%eax, 0x0(%%edx)" "\n\t" /* link */ "leal 1f, %%eax" "\n\t" "movl %%eax, 0x4(%%edx)" "\n\t" /* handler */ "movl %%ebp, 0x8(%%edx)" "\n\t" /* ebp */ "movl %%esp, 0xc(%%edx)" "\n\t" /* esp */ "movl %[error], 0x10(%%edx)" "\n\t" /* status */ /* * Link the EXCEPTION_REGISTRATION on the chain */ "movl %%edx, %%fs:0" "\n\t" /* * Do the CPUID instruction, and save the results in the 'regsPtr' * area. */ "movl %[rptr], %%edi" "\n\t" "movl %[index], %%eax" "\n\t" "cpuid" "\n\t" "movl %%eax, 0x0(%%edi)" "\n\t" "movl %%ebx, 0x4(%%edi)" "\n\t" "movl %%ecx, 0x8(%%edi)" "\n\t" "movl %%edx, 0xc(%%edi)" "\n\t" /* * Come here on a normal exit. Recover the EXCEPTION_REGISTRATION and * store a TCL_OK status. */ "movl %%fs:0, %%edx" "\n\t" "movl %[ok], %%eax" "\n\t" "movl %%eax, 0x10(%%edx)" "\n\t" "jmp 2f" "\n" /* * Come here on an exception. Get the EXCEPTION_REGISTRATION that we * previously put on the chain. */ "1:" "\t" "movl %%fs:0, %%edx" "\n\t" "movl 0x8(%%edx), %%edx" "\n\t" /* * Come here however we exited. Restore context from the * EXCEPTION_REGISTRATION in case the stack is unbalanced. */ "2:" "\t" "movl 0xc(%%edx), %%esp" "\n\t" "movl 0x8(%%edx), %%ebp" "\n\t" "movl 0x0(%%edx), %%eax" "\n\t" "movl %%eax, %%fs:0" "\n\t" : /* No outputs */ : [index] "m" (index), [rptr] "m" (regsPtr), [registration] "m" (registration), [ok] "i" (TCL_OK), [error] "i" (TCL_ERROR) : "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory"); status = registration.status; # endif /* !_WIN64 */ #elif defined(_MSC_VER) # if defined(_WIN64) __cpuid(regsPtr, index); status = TCL_OK; # else /* * Define a structure in the stack frame to hold the registers. */ struct { DWORD dw0; DWORD dw1; DWORD dw2; DWORD dw3; } regs; regs.dw0 = index; /* * Execute the CPUID instruction and save regs in the stack frame. */ _try { _asm { push ebx push ecx push edx mov eax, regs.dw0 cpuid mov regs.dw0, eax mov regs.dw1, ebx mov regs.dw2, ecx mov regs.dw3, edx pop edx pop ecx pop ebx } /* * Copy regs back out to the caller. */ regsPtr[0] = regs.dw0; regsPtr[1] = regs.dw1; regsPtr[2] = regs.dw2; regsPtr[3] = regs.dw3; status = TCL_OK; } __except(EXCEPTION_EXECUTE_HANDLER) { /* do nothing */ } # endif #else /* * Don't know how to do assembly code for this compiler and/or * architecture. */ #endif return status; } /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ tcl8.4.20/win/tclWinInit.c0000644003604700454610000005776412052456744013766 0ustar dgp771div/* * tclWinInit.c -- * * Contains the Windows-specific interpreter initialization functions. * * Copyright (c) 1994-1997 Sun Microsystems, Inc. * Copyright (c) 1998-1999 by Scriptics Corporation. * All rights reserved. */ #include "tclWinInt.h" #include #include #include /* * The following declaration is a workaround for some Microsoft brain damage. * The SYSTEM_INFO structure is different in various releases, even though the * layout is the same. So we overlay our own structure on top of it so we * can access the interesting slots in a uniform way. */ typedef struct { WORD wProcessorArchitecture; WORD wReserved; } OemId; /* * The following macros are missing from some versions of winnt.h. */ #ifndef PROCESSOR_ARCHITECTURE_INTEL #define PROCESSOR_ARCHITECTURE_INTEL 0 #endif #ifndef PROCESSOR_ARCHITECTURE_MIPS #define PROCESSOR_ARCHITECTURE_MIPS 1 #endif #ifndef PROCESSOR_ARCHITECTURE_ALPHA #define PROCESSOR_ARCHITECTURE_ALPHA 2 #endif #ifndef PROCESSOR_ARCHITECTURE_PPC #define PROCESSOR_ARCHITECTURE_PPC 3 #endif #ifndef PROCESSOR_ARCHITECTURE_SHX #define PROCESSOR_ARCHITECTURE_SHX 4 #endif #ifndef PROCESSOR_ARCHITECTURE_ARM #define PROCESSOR_ARCHITECTURE_ARM 5 #endif #ifndef PROCESSOR_ARCHITECTURE_IA64 #define PROCESSOR_ARCHITECTURE_IA64 6 #endif #ifndef PROCESSOR_ARCHITECTURE_ALPHA64 #define PROCESSOR_ARCHITECTURE_ALPHA64 7 #endif #ifndef PROCESSOR_ARCHITECTURE_MSIL #define PROCESSOR_ARCHITECTURE_MSIL 8 #endif #ifndef PROCESSOR_ARCHITECTURE_AMD64 #define PROCESSOR_ARCHITECTURE_AMD64 9 #endif #ifndef PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 #define PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 10 #endif #ifndef PROCESSOR_ARCHITECTURE_UNKNOWN #define PROCESSOR_ARCHITECTURE_UNKNOWN 0xFFFF #endif /* * The following arrays contain the human readable strings for the Windows * platform and processor values. */ #define NUMPLATFORMS 4 static char* platforms[NUMPLATFORMS] = { "Win32s", "Windows 95", "Windows NT", "Windows CE" }; #define NUMPROCESSORS 11 static char* processors[NUMPROCESSORS] = { "intel", "mips", "alpha", "ppc", "shx", "arm", "ia64", "alpha64", "msil", "amd64", "ia32_on_win64" }; /* Used to store the encoding used for binary files */ static Tcl_Encoding binaryEncoding = NULL; /* Has the basic library path encoding issue been fixed */ static int libraryPathEncodingFixed = 0; /* * The Init script (common to Windows and Unix platforms) is * defined in tkInitScript.h */ #include "tclInitScript.h" static void AppendEnvironment(Tcl_Obj *listPtr, CONST char *lib); static void AppendDllPath(Tcl_Obj *listPtr, HMODULE hModule, CONST char *lib); static int ToUtf(CONST WCHAR *wSrc, char *dst); /* *--------------------------------------------------------------------------- * * TclpInitPlatform -- * * Initialize all the platform-dependant things like signals and * floating-point error handling. * * Called at process initialization time. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ void TclpInitPlatform() { tclPlatform = TCL_PLATFORM_WINDOWS; /* * The following code stops Windows 3.X and Windows NT 3.51 from * automatically putting up Sharing Violation dialogs, e.g, when * someone tries to access a file that is locked or a drive with no * disk in it. Tcl already returns the appropriate error to the * caller, and they can decide to put up their own dialog in response * to that failure. * * Under 95 and NT 4.0, this is a NOOP because the system doesn't * automatically put up dialogs when the above operations fail. */ SetErrorMode(SetErrorMode(0) | SEM_FAILCRITICALERRORS); #ifdef STATIC_BUILD /* * If we are in a statically linked executable, then we need to * explicitly initialize the Windows function tables here since * DllMain() will not be invoked. */ TclWinInit(GetModuleHandle(NULL)); #endif } /* *--------------------------------------------------------------------------- * * TclpInitLibraryPath -- * * Initialize the library path at startup. * * This call sets the library path to strings in UTF-8. Any * pre-existing library path information is assumed to have been * in the native multibyte encoding. * * Called at process initialization time. * * Results: * Return 0, indicating that the UTF is clean. * * Side effects: * None. * *--------------------------------------------------------------------------- */ int TclpInitLibraryPath(path) CONST char *path; /* Potentially dirty UTF string that is */ /* the path to the executable name. */ { #define LIBRARY_SIZE 32 Tcl_Obj *pathPtr, *objPtr; CONST char *str; Tcl_DString ds; int pathc; CONST char **pathv; char installLib[LIBRARY_SIZE], developLib[LIBRARY_SIZE]; Tcl_DStringInit(&ds); pathPtr = Tcl_NewObj(); /* * Initialize the substrings used when locating an executable. The * installLib variable computes the path as though the executable * is installed. The developLib computes the path as though the * executable is run from a develpment directory. */ sprintf(installLib, "lib/tcl%s", TCL_VERSION); sprintf(developLib, "tcl%s/library", TCL_PATCH_LEVEL); /* * Look for the library relative to default encoding dir. */ str = Tcl_GetDefaultEncodingDir(); if ((str != NULL) && (str[0] != '\0')) { objPtr = Tcl_NewStringObj(str, -1); Tcl_ListObjAppendElement(NULL, pathPtr, objPtr); } /* * Look for the library relative to the TCL_LIBRARY env variable. * If the last dirname in the TCL_LIBRARY path does not match the * last dirname in the installLib variable, use the last dir name * of installLib in addition to the orginal TCL_LIBRARY path. */ AppendEnvironment(pathPtr, installLib); /* * Look for the library relative to the DLL. Only use the installLib * because in practice, the DLL is always installed. */ AppendDllPath(pathPtr, TclWinGetTclInstance(), installLib); /* * Look for the library relative to the executable. This algorithm * should be the same as the one in the tcl_findLibrary procedure. * * This code looks in the following directories: * * /../ * (e.g. /usr/local/bin/../lib/tcl8.4) * /../../ * (e.g. /usr/local/TclPro/solaris-sparc/bin/../../lib/tcl8.4) * /../library * (e.g. /usr/src/tcl8.4.0/unix/../library) * /../../library * (e.g. /usr/src/tcl8.4.0/unix/solaris-sparc/../../library) * /../../ * (e.g. /usr/src/tcl8.4.0/unix/../../tcl8.4.0/library) * /../../../ * (e.g. /usr/src/tcl8.4.0/unix/solaris-sparc/../../../tcl8.4.0/library) */ /* * The variable path holds an absolute path. Take care not to * overwrite pathv[0] since that might produce a relative path. */ if (path != NULL) { int i, origc; CONST char **origv; Tcl_SplitPath(path, &origc, &origv); pathc = 0; pathv = (CONST char **) ckalloc((unsigned int)(origc * sizeof(char *))); for (i=0; i< origc; i++) { if (origv[i][0] == '.') { if (strcmp(origv[i], ".") == 0) { /* do nothing */ } else if (strcmp(origv[i], "..") == 0) { pathc--; } else { pathv[pathc++] = origv[i]; } } else { pathv[pathc++] = origv[i]; } } if (pathc > 2) { str = pathv[pathc - 2]; pathv[pathc - 2] = installLib; path = Tcl_JoinPath(pathc - 1, pathv, &ds); pathv[pathc - 2] = str; objPtr = Tcl_NewStringObj(path, Tcl_DStringLength(&ds)); Tcl_ListObjAppendElement(NULL, pathPtr, objPtr); Tcl_DStringFree(&ds); } if (pathc > 3) { str = pathv[pathc - 3]; pathv[pathc - 3] = installLib; path = Tcl_JoinPath(pathc - 2, pathv, &ds); pathv[pathc - 3] = str; objPtr = Tcl_NewStringObj(path, Tcl_DStringLength(&ds)); Tcl_ListObjAppendElement(NULL, pathPtr, objPtr); Tcl_DStringFree(&ds); } if (pathc > 2) { str = pathv[pathc - 2]; pathv[pathc - 2] = "library"; path = Tcl_JoinPath(pathc - 1, pathv, &ds); pathv[pathc - 2] = str; objPtr = Tcl_NewStringObj(path, Tcl_DStringLength(&ds)); Tcl_ListObjAppendElement(NULL, pathPtr, objPtr); Tcl_DStringFree(&ds); } if (pathc > 3) { str = pathv[pathc - 3]; pathv[pathc - 3] = "library"; path = Tcl_JoinPath(pathc - 2, pathv, &ds); pathv[pathc - 3] = str; objPtr = Tcl_NewStringObj(path, Tcl_DStringLength(&ds)); Tcl_ListObjAppendElement(NULL, pathPtr, objPtr); Tcl_DStringFree(&ds); } if (pathc > 3) { str = pathv[pathc - 3]; pathv[pathc - 3] = developLib; path = Tcl_JoinPath(pathc - 2, pathv, &ds); pathv[pathc - 3] = str; objPtr = Tcl_NewStringObj(path, Tcl_DStringLength(&ds)); Tcl_ListObjAppendElement(NULL, pathPtr, objPtr); Tcl_DStringFree(&ds); } if (pathc > 4) { str = pathv[pathc - 4]; pathv[pathc - 4] = developLib; path = Tcl_JoinPath(pathc - 3, pathv, &ds); pathv[pathc - 4] = str; objPtr = Tcl_NewStringObj(path, Tcl_DStringLength(&ds)); Tcl_ListObjAppendElement(NULL, pathPtr, objPtr); Tcl_DStringFree(&ds); } ckfree((char *) origv); ckfree((char *) pathv); } TclSetLibraryPath(pathPtr); return 0; /* 0 indicates that pathPtr is clean (true) utf */ } /* *--------------------------------------------------------------------------- * * AppendEnvironment -- * * Append the value of the TCL_LIBRARY environment variable onto the * path pointer. If the env variable points to another version of * tcl (e.g. "tcl7.6") also append the path to this version (e.g., * "tcl7.6/../tcl8.2") * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static void AppendEnvironment( Tcl_Obj *pathPtr, CONST char *lib) { int pathc; WCHAR wBuf[MAX_PATH]; char buf[MAX_PATH * TCL_UTF_MAX]; Tcl_Obj *objPtr; Tcl_DString ds; CONST char **pathv; char *shortlib; /* * The shortlib value needs to be the tail component of the * lib path. For example, "lib/tcl8.4" -> "tcl8.4" while * "usr/share/tcl8.5" -> "tcl8.5". */ for (shortlib = (char *) (lib + strlen(lib) - 1); shortlib > lib ; shortlib--) { if (*shortlib == '/') { if (shortlib == (lib + strlen(lib) - 1)) { Tcl_Panic("last character in lib cannot be '/'"); } shortlib++; break; } } if (shortlib == lib) { Tcl_Panic("no '/' character found in lib"); } /* * The "L" preceeding the TCL_LIBRARY string is used to tell VC++ * that this is a unicode string. */ if (GetEnvironmentVariableW(L"TCL_LIBRARY", wBuf, MAX_PATH) == 0) { buf[0] = '\0'; GetEnvironmentVariableA("TCL_LIBRARY", buf, MAX_PATH); } else { ToUtf(wBuf, buf); } if (buf[0] != '\0') { objPtr = Tcl_NewStringObj(buf, -1); Tcl_ListObjAppendElement(NULL, pathPtr, objPtr); TclWinNoBackslash(buf); Tcl_SplitPath(buf, &pathc, &pathv); /* * The lstrcmpi() will work even if pathv[pathc - 1] is random * UTF-8 chars because I know shortlib is ascii. */ if ((pathc > 0) && (lstrcmpiA(shortlib, pathv[pathc - 1]) != 0)) { CONST char *str; /* * TCL_LIBRARY is set but refers to a different tcl * installation than the current version. Try fiddling with the * specified directory to make it refer to this installation by * removing the old "tclX.Y" and substituting the current * version string. */ pathv[pathc - 1] = shortlib; Tcl_DStringInit(&ds); str = Tcl_JoinPath(pathc, pathv, &ds); objPtr = Tcl_NewStringObj(str, Tcl_DStringLength(&ds)); Tcl_DStringFree(&ds); } else { objPtr = Tcl_NewStringObj(buf, -1); } Tcl_ListObjAppendElement(NULL, pathPtr, objPtr); ckfree((char *) pathv); } } /* *--------------------------------------------------------------------------- * * AppendDllPath -- * * Append a path onto the path pointer that tries to locate the Tcl * library relative to the location of the Tcl DLL. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static void AppendDllPath( Tcl_Obj *pathPtr, HMODULE hModule, CONST char *lib) { WCHAR wName[MAX_PATH + LIBRARY_SIZE]; char name[(MAX_PATH + LIBRARY_SIZE) * TCL_UTF_MAX]; if (GetModuleFileNameW(hModule, wName, MAX_PATH) == 0) { GetModuleFileNameA(hModule, name, MAX_PATH); } else { ToUtf(wName, name); } if (lib != NULL) { char *end, *p; end = strrchr(name, '\\'); *end = '\0'; p = strrchr(name, '\\'); if (p != NULL) { end = p; } *end = '\\'; strcpy(end + 1, lib); } TclWinNoBackslash(name); Tcl_ListObjAppendElement(NULL, pathPtr, Tcl_NewStringObj(name, -1)); } /* *--------------------------------------------------------------------------- * * ToUtf -- * * Convert a char string to a UTF string. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int ToUtf( CONST WCHAR *wSrc, char *dst) { char *start; start = dst; while (*wSrc != '\0') { dst += Tcl_UniCharToUtf(*wSrc, dst); wSrc++; } *dst = '\0'; return (int) (dst - start); } /* *--------------------------------------------------------------------------- * * TclWinEncodingsCleanup -- * * Reset information to its original state in finalization to * allow for reinitialization to be possible. This must not * be called until after the filesystem has been finalised, or * exit crashes may occur when using virtual filesystems. * * Results: * None. * * Side effects: * Static information reset to startup state. * *--------------------------------------------------------------------------- */ void TclWinEncodingsCleanup() { TclWinResetInterfaceEncodings(); libraryPathEncodingFixed = 0; if (binaryEncoding != NULL) { Tcl_FreeEncoding(binaryEncoding); binaryEncoding = NULL; } } /* *--------------------------------------------------------------------------- * * TclpSetInitialEncodings -- * * Based on the locale, determine the encoding of the operating * system and the default encoding for newly opened files. * * Called at process initialization time, and part way through * startup, we verify that the initial encodings were correctly * setup. Depending on Tcl's environment, there may not have been * enough information first time through (above). * * Results: * None. * * Side effects: * The Tcl library path is converted from native encoding to UTF-8, * on the first call, and the encodings may be changed on first or * second call. * *--------------------------------------------------------------------------- */ void TclpSetInitialEncodings() { CONST char *encoding; char buf[4 + TCL_INTEGER_SPACE]; if (libraryPathEncodingFixed == 0) { int platformId, useWide; platformId = TclWinGetPlatformId(); useWide = ((platformId == VER_PLATFORM_WIN32_NT) || (platformId == VER_PLATFORM_WIN32_CE)); TclWinSetInterfaces(useWide); wsprintfA(buf, "cp%d", GetACP()); Tcl_SetSystemEncoding(NULL, buf); if (!useWide) { Tcl_Obj *pathPtr = TclGetLibraryPath(); if (pathPtr != NULL) { int i, objc; Tcl_Obj **objv; objc = 0; Tcl_ListObjGetElements(NULL, pathPtr, &objc, &objv); for (i = 0; i < objc; i++) { int length; char *string; Tcl_DString ds; string = Tcl_GetStringFromObj(objv[i], &length); Tcl_ExternalToUtfDString(NULL, string, length, &ds); Tcl_SetStringObj(objv[i], Tcl_DStringValue(&ds), Tcl_DStringLength(&ds)); Tcl_DStringFree(&ds); } } } libraryPathEncodingFixed = 1; } else { wsprintfA(buf, "cp%d", GetACP()); Tcl_SetSystemEncoding(NULL, buf); } /* This is only ever called from the startup thread */ if (binaryEncoding == NULL) { /* * Keep this encoding preloaded. The IO package uses it for * gets on a binary channel. */ encoding = "iso8859-1"; binaryEncoding = Tcl_GetEncoding(NULL, encoding); } } /* *--------------------------------------------------------------------------- * * TclpSetVariables -- * * Performs platform-specific interpreter initialization related to * the tcl_platform and env variables, and other platform-specific * things. * * Results: * None. * * Side effects: * Sets "tcl_platform", and "env(HOME)" Tcl variables. * *---------------------------------------------------------------------- */ void TclpSetVariables(interp) Tcl_Interp *interp; /* Interp to initialize. */ { CONST char *ptr; char buffer[TCL_INTEGER_SPACE * 2]; SYSTEM_INFO sysInfo; OemId *oemId; OSVERSIONINFOA osInfo; Tcl_DString ds; TCHAR szUserName[ UNLEN+1 ]; DWORD dwUserNameLen = sizeof(szUserName); osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); GetVersionExA(&osInfo); oemId = (OemId *) &sysInfo; GetSystemInfo(&sysInfo); /* * Define the tcl_platform array. */ Tcl_SetVar2(interp, "tcl_platform", "platform", "windows", TCL_GLOBAL_ONLY); if (osInfo.dwPlatformId < NUMPLATFORMS) { Tcl_SetVar2(interp, "tcl_platform", "os", platforms[osInfo.dwPlatformId], TCL_GLOBAL_ONLY); } wsprintfA(buffer, "%d.%d", osInfo.dwMajorVersion, osInfo.dwMinorVersion); Tcl_SetVar2(interp, "tcl_platform", "osVersion", buffer, TCL_GLOBAL_ONLY); if (oemId->wProcessorArchitecture < NUMPROCESSORS) { Tcl_SetVar2(interp, "tcl_platform", "machine", processors[oemId->wProcessorArchitecture], TCL_GLOBAL_ONLY); } #ifndef NDEBUG /* * The existence of the "debug" element of the tcl_platform array indicates * that this particular Tcl shell has been compiled with debug information. * Using "info exists tcl_platform(debug)" a Tcl script can direct the * interpreter to load debug versions of DLLs with the load command. */ Tcl_SetVar2(interp, "tcl_platform", "debug", "1", TCL_GLOBAL_ONLY); #endif /* * Set up the HOME environment variable from the HOMEDRIVE & HOMEPATH * environment variables, if necessary. */ Tcl_DStringInit(&ds); ptr = Tcl_GetVar2(interp, "env", "HOME", TCL_GLOBAL_ONLY); if (ptr == NULL) { ptr = Tcl_GetVar2(interp, "env", "HOMEDRIVE", TCL_GLOBAL_ONLY); if (ptr != NULL) { Tcl_DStringAppend(&ds, ptr, -1); } ptr = Tcl_GetVar2(interp, "env", "HOMEPATH", TCL_GLOBAL_ONLY); if (ptr != NULL) { Tcl_DStringAppend(&ds, ptr, -1); } if (Tcl_DStringLength(&ds) > 0) { Tcl_SetVar2(interp, "env", "HOME", Tcl_DStringValue(&ds), TCL_GLOBAL_ONLY); } else { Tcl_SetVar2(interp, "env", "HOME", "c:\\", TCL_GLOBAL_ONLY); } } /* * Initialize the user name from the environment first, since this is much * faster than asking the system. */ Tcl_DStringInit( &ds ); if (TclGetEnv("USERNAME", &ds) == NULL) { if ( GetUserName( szUserName, &dwUserNameLen ) != 0 ) { Tcl_WinTCharToUtf( szUserName, dwUserNameLen, &ds ); } } Tcl_SetVar2(interp, "tcl_platform", "user", Tcl_DStringValue(&ds), TCL_GLOBAL_ONLY); Tcl_DStringFree(&ds); } /* *---------------------------------------------------------------------- * * TclpFindVariable -- * * Locate the entry in environ for a given name. On Unix this * routine is case sensetive, on Windows this matches mioxed case. * * Results: * The return value is the index in environ of an entry with the * name "name", or -1 if there is no such entry. The integer at * *lengthPtr is filled in with the length of name (if a matching * entry is found) or the length of the environ array (if no matching * entry is found). * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclpFindVariable(name, lengthPtr) CONST char *name; /* Name of desired environment variable * (UTF-8). */ int *lengthPtr; /* Used to return length of name (for * successful searches) or number of non-NULL * entries in environ (for unsuccessful * searches). */ { int i, length, result = -1; register CONST char *env, *p1, *p2; char *envUpper, *nameUpper; Tcl_DString envString; /* * Convert the name to all upper case for the case insensitive * comparison. */ length = strlen(name); nameUpper = (char *) ckalloc((unsigned) length+1); memcpy((VOID *) nameUpper, (VOID *) name, (size_t) length+1); Tcl_UtfToUpper(nameUpper); Tcl_DStringInit(&envString); for (i = 0, env = environ[i]; env != NULL; i++, env = environ[i]) { /* * Chop the env string off after the equal sign, then Convert * the name to all upper case, so we do not have to convert * all the characters after the equal sign. */ envUpper = Tcl_ExternalToUtfDString(NULL, env, -1, &envString); p1 = strchr(envUpper, '='); if (p1 == NULL) { continue; } length = (int) (p1 - envUpper); Tcl_DStringSetLength(&envString, length+1); Tcl_UtfToUpper(envUpper); p1 = envUpper; p2 = nameUpper; for (; *p2 == *p1; p1++, p2++) { /* NULL loop body. */ } if ((*p1 == '=') && (*p2 == '\0')) { *lengthPtr = length; result = i; goto done; } Tcl_DStringFree(&envString); } *lengthPtr = i; done: Tcl_DStringFree(&envString); ckfree(nameUpper); return result; } /* *---------------------------------------------------------------------- * * Tcl_Init -- * * This procedure is typically invoked by Tcl_AppInit procedures * to perform additional initialization for a Tcl interpreter, * such as sourcing the "init.tcl" script. * * Results: * Returns a standard Tcl completion code and sets the interp's * result if there is an error. * * Side effects: * Depends on what's in the init.tcl script. * *---------------------------------------------------------------------- */ int Tcl_Init(interp) Tcl_Interp *interp; /* Interpreter to initialize. */ { Tcl_Obj *pathPtr; if (tclPreInitScript != NULL) { if (Tcl_Eval(interp, tclPreInitScript) == TCL_ERROR) { return (TCL_ERROR); }; } pathPtr = TclGetLibraryPath(); if (pathPtr == NULL) { pathPtr = Tcl_NewObj(); } Tcl_IncrRefCount(pathPtr); Tcl_SetVar2Ex(interp, "tcl_libPath", NULL, pathPtr, TCL_GLOBAL_ONLY); Tcl_DecrRefCount(pathPtr); return Tcl_Eval(interp, initScript); } /* *---------------------------------------------------------------------- * * Tcl_SourceRCFile -- * * This procedure is typically invoked by Tcl_Main of Tk_Main * procedure to source an application specific rc file into the * interpreter at startup time. * * Results: * None. * * Side effects: * Depends on what's in the rc script. * *---------------------------------------------------------------------- */ void Tcl_SourceRCFile(interp) Tcl_Interp *interp; /* Interpreter to source rc file into. */ { Tcl_DString temp; CONST char *fileName; Tcl_Channel errChannel; fileName = Tcl_GetVar(interp, "tcl_rcFileName", TCL_GLOBAL_ONLY); if (fileName != NULL) { Tcl_Channel c; CONST char *fullName; Tcl_DStringInit(&temp); fullName = Tcl_TranslateFileName(interp, fileName, &temp); if (fullName == NULL) { /* * Couldn't translate the file name (e.g. it referred to a * bogus user or there was no HOME environment variable). * Just do nothing. */ } else { /* * Test for the existence of the rc file before trying to read it. */ c = Tcl_OpenFileChannel(NULL, fullName, "r", 0); if (c != (Tcl_Channel) NULL) { Tcl_Close(NULL, c); if (Tcl_EvalFile(interp, fullName) != TCL_OK) { errChannel = Tcl_GetStdChannel(TCL_STDERR); if (errChannel) { Tcl_WriteObj(errChannel, Tcl_GetObjResult(interp)); Tcl_WriteChars(errChannel, "\n", 1); } } } } Tcl_DStringFree(&temp); } } tcl8.4.20/win/tclWinChan.c0000644003604700454610000011417211737050675013721 0ustar dgp771div/* * tclWinChan.c * * Channel drivers for Windows channels based on files, command * pipes and TCP sockets. * * Copyright (c) 1995-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclWinInt.h" #include "tclIO.h" /* * State flags used in the info structures below. */ #define FILE_PENDING (1<<0) /* Message is pending in the queue. */ #define FILE_ASYNC (1<<1) /* Channel is non-blocking. */ #define FILE_APPEND (1<<2) /* File is in append mode. */ #define FILE_TYPE_SERIAL (FILE_TYPE_PIPE+1) #define FILE_TYPE_CONSOLE (FILE_TYPE_PIPE+2) /* * The following structure contains per-instance data for a file based channel. */ typedef struct FileInfo { Tcl_Channel channel; /* Pointer to channel structure. */ int validMask; /* OR'ed combination of TCL_READABLE, * TCL_WRITABLE, or TCL_EXCEPTION: indicates * which operations are valid on the file. */ int watchMask; /* OR'ed combination of TCL_READABLE, * TCL_WRITABLE, or TCL_EXCEPTION: indicates * which events should be reported. */ int flags; /* State flags, see above for a list. */ HANDLE handle; /* Input/output file. */ struct FileInfo *nextPtr; /* Pointer to next registered file. */ int dirty; /* Boolean flag. Set if the OS may have data * pending on the channel */ } FileInfo; typedef struct ThreadSpecificData { /* * List of all file channels currently open. */ FileInfo *firstFilePtr; } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; /* * The following structure is what is added to the Tcl event queue when * file events are generated. */ typedef struct FileEvent { Tcl_Event header; /* Information that is standard for * all events. */ FileInfo *infoPtr; /* Pointer to file info structure. Note * that we still have to verify that the * file exists before dereferencing this * pointer. */ } FileEvent; /* * Static routines for this file: */ static int FileBlockProc _ANSI_ARGS_((ClientData instanceData, int mode)); static void FileChannelExitHandler _ANSI_ARGS_(( ClientData clientData)); static void FileCheckProc _ANSI_ARGS_((ClientData clientData, int flags)); static int FileCloseProc _ANSI_ARGS_((ClientData instanceData, Tcl_Interp *interp)); static int FileEventProc _ANSI_ARGS_((Tcl_Event *evPtr, int flags)); static int FileGetHandleProc _ANSI_ARGS_((ClientData instanceData, int direction, ClientData *handlePtr)); static ThreadSpecificData *FileInit _ANSI_ARGS_((void)); static int FileInputProc _ANSI_ARGS_((ClientData instanceData, char *buf, int toRead, int *errorCode)); static int FileOutputProc _ANSI_ARGS_((ClientData instanceData, CONST char *buf, int toWrite, int *errorCode)); static int FileSeekProc _ANSI_ARGS_((ClientData instanceData, long offset, int mode, int *errorCode)); static Tcl_WideInt FileWideSeekProc _ANSI_ARGS_((ClientData instanceData, Tcl_WideInt offset, int mode, int *errorCode)); static void FileSetupProc _ANSI_ARGS_((ClientData clientData, int flags)); static void FileWatchProc _ANSI_ARGS_((ClientData instanceData, int mask)); static void FileThreadActionProc _ANSI_ARGS_ (( ClientData instanceData, int action)); static DWORD FileGetType _ANSI_ARGS_((HANDLE handle)); /* * This structure describes the channel type structure for file based IO. */ static Tcl_ChannelType fileChannelType = { "file", /* Type name. */ TCL_CHANNEL_VERSION_4, /* v4 channel */ FileCloseProc, /* Close proc. */ FileInputProc, /* Input proc. */ FileOutputProc, /* Output proc. */ FileSeekProc, /* Seek proc. */ NULL, /* Set option proc. */ NULL, /* Get option proc. */ FileWatchProc, /* Set up the notifier to watch the channel. */ FileGetHandleProc, /* Get an OS handle from channel. */ NULL, /* close2proc. */ FileBlockProc, /* Set blocking or non-blocking mode.*/ NULL, /* flush proc. */ NULL, /* handler proc. */ FileWideSeekProc, /* Wide seek proc. */ FileThreadActionProc, /* Thread action proc. */ }; #ifdef HAVE_NO_SEH /* * Unlike Borland and Microsoft, we don't register exception handlers * by pushing registration records onto the runtime stack. Instead, we * register them by creating an EXCEPTION_REGISTRATION within the activation * record. */ typedef struct EXCEPTION_REGISTRATION { struct EXCEPTION_REGISTRATION* link; EXCEPTION_DISPOSITION (*handler)( struct _EXCEPTION_RECORD*, void*, struct _CONTEXT*, void* ); void* ebp; void* esp; int status; } EXCEPTION_REGISTRATION; #endif /* *---------------------------------------------------------------------- * * FileInit -- * * This function creates the window used to simulate file events. * * Results: * None. * * Side effects: * Creates a new window and creates an exit handler. * *---------------------------------------------------------------------- */ static ThreadSpecificData * FileInit() { ThreadSpecificData *tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); if (tsdPtr == NULL) { tsdPtr = TCL_TSD_INIT(&dataKey); tsdPtr->firstFilePtr = NULL; Tcl_CreateEventSource(FileSetupProc, FileCheckProc, NULL); Tcl_CreateThreadExitHandler(FileChannelExitHandler, NULL); } return tsdPtr; } /* *---------------------------------------------------------------------- * * FileChannelExitHandler -- * * This function is called to cleanup the channel driver before * Tcl is unloaded. * * Results: * None. * * Side effects: * Destroys the communication window. * *---------------------------------------------------------------------- */ static void FileChannelExitHandler(clientData) ClientData clientData; /* Old window proc */ { Tcl_DeleteEventSource(FileSetupProc, FileCheckProc, NULL); } /* *---------------------------------------------------------------------- * * FileSetupProc -- * * This procedure is invoked before Tcl_DoOneEvent blocks waiting * for an event. * * Results: * None. * * Side effects: * Adjusts the block time if needed. * *---------------------------------------------------------------------- */ void FileSetupProc(data, flags) ClientData data; /* Not used. */ int flags; /* Event flags as passed to Tcl_DoOneEvent. */ { FileInfo *infoPtr; Tcl_Time blockTime = { 0, 0 }; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (!(flags & TCL_FILE_EVENTS)) { return; } /* * Check to see if there is a ready file. If so, poll. */ for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { if (infoPtr->watchMask) { Tcl_SetMaxBlockTime(&blockTime); break; } } } /* *---------------------------------------------------------------------- * * FileCheckProc -- * * This procedure is called by Tcl_DoOneEvent to check the file * event source for events. * * Results: * None. * * Side effects: * May queue an event. * *---------------------------------------------------------------------- */ static void FileCheckProc(data, flags) ClientData data; /* Not used. */ int flags; /* Event flags as passed to Tcl_DoOneEvent. */ { FileEvent *evPtr; FileInfo *infoPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (!(flags & TCL_FILE_EVENTS)) { return; } /* * Queue events for any ready files that don't already have events * queued (caused by persistent states that won't generate WinSock * events). */ for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { if (infoPtr->watchMask && !(infoPtr->flags & FILE_PENDING)) { infoPtr->flags |= FILE_PENDING; evPtr = (FileEvent *) ckalloc(sizeof(FileEvent)); evPtr->header.proc = FileEventProc; evPtr->infoPtr = infoPtr; Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL); } } } /*---------------------------------------------------------------------- * * FileEventProc -- * * This function is invoked by Tcl_ServiceEvent when a file event * reaches the front of the event queue. This procedure invokes * Tcl_NotifyChannel on the file. * * Results: * Returns 1 if the event was handled, meaning it should be removed * from the queue. Returns 0 if the event was not handled, meaning * it should stay on the queue. The only time the event isn't * handled is if the TCL_FILE_EVENTS flag bit isn't set. * * Side effects: * Whatever the notifier callback does. * *---------------------------------------------------------------------- */ static int FileEventProc(evPtr, flags) Tcl_Event *evPtr; /* Event to service. */ int flags; /* Flags that indicate what events to * handle, such as TCL_FILE_EVENTS. */ { FileEvent *fileEvPtr = (FileEvent *)evPtr; FileInfo *infoPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (!(flags & TCL_FILE_EVENTS)) { return 0; } /* * Search through the list of watched files for the one whose handle * matches the event. We do this rather than simply dereferencing * the handle in the event so that files can be deleted while the * event is in the queue. */ for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { if (fileEvPtr->infoPtr == infoPtr) { infoPtr->flags &= ~(FILE_PENDING); Tcl_NotifyChannel(infoPtr->channel, infoPtr->watchMask); break; } } return 1; } /* *---------------------------------------------------------------------- * * FileBlockProc -- * * Set blocking or non-blocking mode on channel. * * Results: * 0 if successful, errno when failed. * * Side effects: * Sets the device into blocking or non-blocking mode. * *---------------------------------------------------------------------- */ static int FileBlockProc(instanceData, mode) ClientData instanceData; /* Instance data for channel. */ int mode; /* TCL_MODE_BLOCKING or * TCL_MODE_NONBLOCKING. */ { FileInfo *infoPtr = (FileInfo *) instanceData; /* * Files on Windows can not be switched between blocking and nonblocking, * hence we have to emulate the behavior. This is done in the input * function by checking against a bit in the state. We set or unset the * bit here to cause the input function to emulate the correct behavior. */ if (mode == TCL_MODE_NONBLOCKING) { infoPtr->flags |= FILE_ASYNC; } else { infoPtr->flags &= ~(FILE_ASYNC); } return 0; } /* *---------------------------------------------------------------------- * * FileCloseProc -- * * Closes the IO channel. * * Results: * 0 if successful, the value of errno if failed. * * Side effects: * Closes the physical channel * *---------------------------------------------------------------------- */ static int FileCloseProc(instanceData, interp) ClientData instanceData; /* Pointer to FileInfo structure. */ Tcl_Interp *interp; /* Not used. */ { FileInfo *fileInfoPtr = (FileInfo *) instanceData; FileInfo *infoPtr; ThreadSpecificData *tsdPtr; int errorCode = 0; /* * Remove the file from the watch list. */ FileWatchProc(instanceData, 0); /* * Don't close the Win32 handle if the handle is a standard channel * during the thread exit process. Otherwise, one thread may kill * the stdio of another. */ if (!TclInThreadExit() || ((GetStdHandle(STD_INPUT_HANDLE) != fileInfoPtr->handle) && (GetStdHandle(STD_OUTPUT_HANDLE) != fileInfoPtr->handle) && (GetStdHandle(STD_ERROR_HANDLE) != fileInfoPtr->handle))) { if (CloseHandle(fileInfoPtr->handle) == FALSE) { TclWinConvertError(GetLastError()); errorCode = errno; } } /* * See if this FileInfo* is still on the thread local list. */ tsdPtr = TCL_TSD_INIT(&dataKey); for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { if (infoPtr == fileInfoPtr) { /* * This channel exists on the thread local list. It should * have been removed by an earlier Thread Action call, * but do that now since just deallocating fileInfoPtr would * leave an deallocated pointer on the thread local list. */ FileThreadActionProc(fileInfoPtr,TCL_CHANNEL_THREAD_REMOVE); break; } } ckfree((char *)fileInfoPtr); return errorCode; } /* *---------------------------------------------------------------------- * * FileSeekProc -- * * Seeks on a file-based channel. Returns the new position. * * Results: * -1 if failed, the new position if successful. If failed, it * also sets *errorCodePtr to the error code. * * Side effects: * Moves the location at which the channel will be accessed in * future operations. * *---------------------------------------------------------------------- */ static int FileSeekProc(instanceData, offset, mode, errorCodePtr) ClientData instanceData; /* File state. */ long offset; /* Offset to seek to. */ int mode; /* Relative to where should we seek? */ int *errorCodePtr; /* To store error code. */ { FileInfo *infoPtr = (FileInfo *) instanceData; DWORD moveMethod, newPos, oldPos; LONG newPosHigh, oldPosHigh; *errorCodePtr = 0; if (mode == SEEK_SET) { moveMethod = FILE_BEGIN; } else if (mode == SEEK_CUR) { moveMethod = FILE_CURRENT; } else { moveMethod = FILE_END; } /* * Save our current place in case we need to roll-back the seek. */ oldPosHigh = (LONG)0; oldPos = SetFilePointer(infoPtr->handle, (LONG)0, &oldPosHigh, FILE_CURRENT); if (oldPos == INVALID_SET_FILE_POINTER) { DWORD winError = GetLastError(); if (winError != NO_ERROR) { TclWinConvertError(winError); *errorCodePtr = errno; return -1; } } newPosHigh = (LONG)(offset < 0 ? -1 : 0); newPos = SetFilePointer(infoPtr->handle, (LONG) offset, &newPosHigh, moveMethod); if (newPos == INVALID_SET_FILE_POINTER) { DWORD winError = GetLastError(); if (winError != NO_ERROR) { TclWinConvertError(winError); *errorCodePtr = errno; return -1; } } /* * Check for expressability in our return type, and roll-back otherwise. */ if (newPosHigh != 0) { *errorCodePtr = EOVERFLOW; SetFilePointer(infoPtr->handle, (LONG)oldPos, &oldPosHigh, FILE_BEGIN); return -1; } return (int) newPos; } /* *---------------------------------------------------------------------- * * FileWideSeekProc -- * * Seeks on a file-based channel. Returns the new position. * * Results: * -1 if failed, the new position if successful. If failed, it * also sets *errorCodePtr to the error code. * * Side effects: * Moves the location at which the channel will be accessed in * future operations. * *---------------------------------------------------------------------- */ static Tcl_WideInt FileWideSeekProc(instanceData, offset, mode, errorCodePtr) ClientData instanceData; /* File state. */ Tcl_WideInt offset; /* Offset to seek to. */ int mode; /* Relative to where should we seek? */ int *errorCodePtr; /* To store error code. */ { FileInfo *infoPtr = (FileInfo *) instanceData; DWORD moveMethod, newPos; LONG newPosHigh; *errorCodePtr = 0; if (mode == SEEK_SET) { moveMethod = FILE_BEGIN; } else if (mode == SEEK_CUR) { moveMethod = FILE_CURRENT; } else { moveMethod = FILE_END; } newPosHigh = (DWORD)(offset >> 32); newPos = SetFilePointer(infoPtr->handle, (LONG) offset, &newPosHigh, moveMethod); if (newPos == INVALID_SET_FILE_POINTER) { DWORD winError = GetLastError(); if (winError != NO_ERROR) { TclWinConvertError(winError); *errorCodePtr = errno; return -1; } } return (((Tcl_WideInt)((unsigned)newPos)) | (Tcl_LongAsWide(newPosHigh) << 32)); } /* *---------------------------------------------------------------------- * * FileInputProc -- * * Reads input from the IO channel into the buffer given. Returns * count of how many bytes were actually read, and an error indication. * * Results: * A count of how many bytes were read is returned and an error * indication is returned in an output argument. * * Side effects: * Reads input from the actual channel. * *---------------------------------------------------------------------- */ static int FileInputProc(instanceData, buf, bufSize, errorCode) ClientData instanceData; /* File state. */ char *buf; /* Where to store data read. */ int bufSize; /* How much space is available * in the buffer? */ int *errorCode; /* Where to store error code. */ { FileInfo *infoPtr; DWORD bytesRead; *errorCode = 0; infoPtr = (FileInfo *) instanceData; /* * Note that we will block on reads from a console buffer until a * full line has been entered. The only way I know of to get * around this is to write a console driver. We should probably * do this at some point, but for now, we just block. The same * problem exists for files being read over the network. */ if (ReadFile(infoPtr->handle, (LPVOID) buf, (DWORD) bufSize, &bytesRead, (LPOVERLAPPED) NULL) != FALSE) { return bytesRead; } TclWinConvertError(GetLastError()); *errorCode = errno; if (errno == EPIPE) { return 0; } return -1; } /* *---------------------------------------------------------------------- * * FileOutputProc -- * * Writes the given output on the IO channel. Returns count of how * many characters were actually written, and an error indication. * * Results: * A count of how many characters were written is returned and an * error indication is returned in an output argument. * * Side effects: * Writes output on the actual channel. * *---------------------------------------------------------------------- */ static int FileOutputProc(instanceData, buf, toWrite, errorCode) ClientData instanceData; /* File state. */ CONST char *buf; /* The data buffer. */ int toWrite; /* How many bytes to write? */ int *errorCode; /* Where to store error code. */ { FileInfo *infoPtr = (FileInfo *) instanceData; DWORD bytesWritten; *errorCode = 0; /* * If we are writing to a file that was opened with O_APPEND, we need to * seek to the end of the file before writing the current buffer. */ if (infoPtr->flags & FILE_APPEND) { SetFilePointer(infoPtr->handle, 0, NULL, FILE_END); } if (WriteFile(infoPtr->handle, (LPVOID) buf, (DWORD) toWrite, &bytesWritten, (LPOVERLAPPED) NULL) == FALSE) { TclWinConvertError(GetLastError()); *errorCode = errno; return -1; } infoPtr->dirty = 1; return bytesWritten; } /* *---------------------------------------------------------------------- * * FileWatchProc -- * * Called by the notifier to set up to watch for events on this * channel. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void FileWatchProc(instanceData, mask) ClientData instanceData; /* File state. */ int mask; /* What events to watch for; OR-ed * combination of TCL_READABLE, * TCL_WRITABLE and TCL_EXCEPTION. */ { FileInfo *infoPtr = (FileInfo *) instanceData; Tcl_Time blockTime = { 0, 0 }; /* * Since the file is always ready for events, we set the block time * to zero so we will poll. */ infoPtr->watchMask = mask & infoPtr->validMask; if (infoPtr->watchMask) { Tcl_SetMaxBlockTime(&blockTime); } } /* *---------------------------------------------------------------------- * * FileGetHandleProc -- * * Called from Tcl_GetChannelHandle to retrieve OS handles from * a file based channel. * * Results: * Returns TCL_OK with the fd in handlePtr, or TCL_ERROR if * there is no handle for the specified direction. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int FileGetHandleProc(instanceData, direction, handlePtr) ClientData instanceData; /* The file state. */ int direction; /* TCL_READABLE or TCL_WRITABLE */ ClientData *handlePtr; /* Where to store the handle. */ { FileInfo *infoPtr = (FileInfo *) instanceData; if (direction & infoPtr->validMask) { *handlePtr = (ClientData) infoPtr->handle; return TCL_OK; } else { return TCL_ERROR; } } /* *---------------------------------------------------------------------- * * TclpOpenFileChannel -- * * Open an File based channel on Unix systems. * * Results: * The new channel or NULL. If NULL, the output argument * errorCodePtr is set to a POSIX error. * * Side effects: * May open the channel and may cause creation of a file on the * file system. * *---------------------------------------------------------------------- */ Tcl_Channel TclpOpenFileChannel(interp, pathPtr, mode, permissions) Tcl_Interp *interp; /* Interpreter for error reporting; * can be NULL. */ Tcl_Obj *pathPtr; /* Name of file to open. */ int mode; /* POSIX mode. */ int permissions; /* If the open involves creating a * file, with what modes to create * it? */ { Tcl_Channel channel = 0; int channelPermissions = 0; DWORD accessMode = 0, createMode, shareMode, flags; CONST TCHAR *nativeName; HANDLE handle; char channelName[16 + TCL_INTEGER_SPACE]; TclFile readFile = NULL; TclFile writeFile = NULL; nativeName = (TCHAR*) Tcl_FSGetNativePath(pathPtr); if (nativeName == NULL) { return NULL; } switch (mode & (O_RDONLY | O_WRONLY | O_RDWR)) { case O_RDONLY: accessMode = GENERIC_READ; channelPermissions = TCL_READABLE; break; case O_WRONLY: accessMode = GENERIC_WRITE; channelPermissions = TCL_WRITABLE; break; case O_RDWR: accessMode = (GENERIC_READ | GENERIC_WRITE); channelPermissions = (TCL_READABLE | TCL_WRITABLE); break; default: panic("TclpOpenFileChannel: invalid mode value"); break; } /* * Map the creation flags to the NT create mode. */ switch (mode & (O_CREAT | O_EXCL | O_TRUNC)) { case (O_CREAT | O_EXCL): case (O_CREAT | O_EXCL | O_TRUNC): createMode = CREATE_NEW; break; case (O_CREAT | O_TRUNC): createMode = CREATE_ALWAYS; break; case O_CREAT: createMode = OPEN_ALWAYS; break; case O_TRUNC: case (O_TRUNC | O_EXCL): createMode = TRUNCATE_EXISTING; break; default: createMode = OPEN_EXISTING; break; } /* * If the file is being created, get the file attributes from the * permissions argument, else use the existing file attributes. */ if (mode & O_CREAT) { if (permissions & S_IWRITE) { flags = FILE_ATTRIBUTE_NORMAL; } else { flags = FILE_ATTRIBUTE_READONLY; } } else { flags = (*tclWinProcs->getFileAttributesProc)(nativeName); if (flags == 0xFFFFFFFF) { flags = 0; } } /* * Set up the file sharing mode. We want to allow simultaneous access. */ shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; /* * Now we get to create the file. */ handle = (*tclWinProcs->createFileProc)(nativeName, accessMode, shareMode, NULL, createMode, flags, (HANDLE) NULL); if (handle == INVALID_HANDLE_VALUE) { DWORD err; err = GetLastError(); if ((err & 0xffffL) == ERROR_OPEN_FAILED) { err = (mode & O_CREAT) ? ERROR_FILE_EXISTS : ERROR_FILE_NOT_FOUND; } TclWinConvertError(err); if (interp != (Tcl_Interp *) NULL) { Tcl_AppendResult(interp, "couldn't open \"", Tcl_GetString(pathPtr), "\": ", Tcl_PosixError(interp), (char *) NULL); } return NULL; } channel = NULL; switch ( FileGetType(handle) ) { case FILE_TYPE_SERIAL: /* * Reopen channel for OVERLAPPED operation * Normally this shouldn't fail, because the channel exists */ handle = TclWinSerialReopen(handle, nativeName, accessMode); if (handle == INVALID_HANDLE_VALUE) { TclWinConvertError(GetLastError()); if (interp != (Tcl_Interp *) NULL) { Tcl_AppendResult(interp, "couldn't reopen serial \"", Tcl_GetString(pathPtr), "\": ", Tcl_PosixError(interp), (char *) NULL); } return NULL; } channel = TclWinOpenSerialChannel(handle, channelName, channelPermissions); break; case FILE_TYPE_CONSOLE: channel = TclWinOpenConsoleChannel(handle, channelName, channelPermissions); break; case FILE_TYPE_PIPE: if (channelPermissions & TCL_READABLE) { readFile = TclWinMakeFile(handle); } if (channelPermissions & TCL_WRITABLE) { writeFile = TclWinMakeFile(handle); } channel = TclpCreateCommandChannel(readFile, writeFile, NULL, 0, NULL); break; case FILE_TYPE_CHAR: case FILE_TYPE_DISK: case FILE_TYPE_UNKNOWN: channel = TclWinOpenFileChannel(handle, channelName, channelPermissions, (mode & O_APPEND) ? FILE_APPEND : 0); break; default: /* * The handle is of an unknown type, probably /dev/nul equivalent * or possibly a closed handle. */ channel = NULL; Tcl_AppendResult(interp, "couldn't open \"", Tcl_GetString(pathPtr), "\": ", "bad file type", (char *) NULL); break; } return channel; } /* *---------------------------------------------------------------------- * * Tcl_MakeFileChannel -- * * Creates a Tcl_Channel from an existing platform specific file * handle. * * Results: * The Tcl_Channel created around the preexisting file. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_Channel Tcl_MakeFileChannel(rawHandle, mode) ClientData rawHandle; /* OS level handle */ int mode; /* ORed combination of TCL_READABLE and * TCL_WRITABLE to indicate file mode. */ { #if defined(HAVE_NO_SEH) && !defined(_WIN64) EXCEPTION_REGISTRATION registration; #endif char channelName[16 + TCL_INTEGER_SPACE]; Tcl_Channel channel = NULL; HANDLE handle = (HANDLE) rawHandle; HANDLE dupedHandle; TclFile readFile = NULL; TclFile writeFile = NULL; BOOL result; if (mode == 0) { return NULL; } switch (FileGetType(handle)) { case FILE_TYPE_SERIAL: channel = TclWinOpenSerialChannel(handle, channelName, mode); break; case FILE_TYPE_CONSOLE: channel = TclWinOpenConsoleChannel(handle, channelName, mode); break; case FILE_TYPE_PIPE: if (mode & TCL_READABLE) { readFile = TclWinMakeFile(handle); } if (mode & TCL_WRITABLE) { writeFile = TclWinMakeFile(handle); } channel = TclpCreateCommandChannel(readFile, writeFile, NULL, 0, NULL); break; case FILE_TYPE_DISK: case FILE_TYPE_CHAR: channel = TclWinOpenFileChannel(handle, channelName, mode, 0); break; case FILE_TYPE_UNKNOWN: default: /* * The handle is of an unknown type. Test the validity of this OS * handle by duplicating it, then closing the dupe. The Win32 API * doesn't provide an IsValidHandle() function, so we have to emulate * it here. This test will not work on a console handle reliably, * which is why we can't test every handle that comes into this * function in this way. */ result = DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(), &dupedHandle, 0, FALSE, DUPLICATE_SAME_ACCESS); if (result == 0) { /* * Unable to make a duplicate. It's definately invalid at this * point. */ return NULL; } /* * Use structured exception handling (Win32 SEH) to protect the close * of this duped handle which might throw EXCEPTION_INVALID_HANDLE. */ result = 0; #if defined(HAVE_NO_SEH) && !defined(_WIN64) /* * Don't have SEH available, do things the hard way. * Note that this needs to be one block of asm, to avoid stack * imbalance; also, it is illegal for one asm block to contain * a jump to another. */ __asm__ __volatile__ ( /* * Pick up parameters before messing with the stack */ "movl %[dupedHandle], %%ebx" "\n\t" /* * Construct an EXCEPTION_REGISTRATION to protect the * call to CloseHandle */ "leal %[registration], %%edx" "\n\t" "movl %%fs:0, %%eax" "\n\t" "movl %%eax, 0x0(%%edx)" "\n\t" /* link */ "leal 1f, %%eax" "\n\t" "movl %%eax, 0x4(%%edx)" "\n\t" /* handler */ "movl %%ebp, 0x8(%%edx)" "\n\t" /* ebp */ "movl %%esp, 0xc(%%edx)" "\n\t" /* esp */ "movl $0, 0x10(%%edx)" "\n\t" /* status */ /* Link the EXCEPTION_REGISTRATION on the chain */ "movl %%edx, %%fs:0" "\n\t" /* Call CloseHandle( dupedHandle ) */ "pushl %%ebx" "\n\t" "call _CloseHandle@4" "\n\t" /* * Come here on normal exit. Recover the EXCEPTION_REGISTRATION * and put a TRUE status return into it. */ "movl %%fs:0, %%edx" "\n\t" "movl $1, %%eax" "\n\t" "movl %%eax, 0x10(%%edx)" "\n\t" "jmp 2f" "\n" /* * Come here on an exception. Recover the EXCEPTION_REGISTRATION */ "1:" "\t" "movl %%fs:0, %%edx" "\n\t" "movl 0x8(%%edx), %%edx" "\n\t" /* * Come here however we exited. Restore context from the * EXCEPTION_REGISTRATION in case the stack is unbalanced. */ "2:" "\t" "movl 0xc(%%edx), %%esp" "\n\t" "movl 0x8(%%edx), %%ebp" "\n\t" "movl 0x0(%%edx), %%eax" "\n\t" "movl %%eax, %%fs:0" "\n\t" : /* No outputs */ : [registration] "m" (registration), [dupedHandle] "m" (dupedHandle) : "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory" ); result = registration.status; #else #ifndef HAVE_NO_SEH __try { #endif CloseHandle(dupedHandle); result = 1; #ifndef HAVE_NO_SEH } __except (EXCEPTION_EXECUTE_HANDLER) {} #endif #endif if (result == FALSE) { return NULL; } /* Fall through, the handle is valid. */ /* * Create the undefined channel, anyways, because we know the handle * is valid to something. */ channel = TclWinOpenFileChannel(handle, channelName, mode, 0); } return channel; } /* *---------------------------------------------------------------------- * * TclpGetDefaultStdChannel -- * * Constructs a channel for the specified standard OS handle. * * Results: * Returns the specified default standard channel, or NULL. * * Side effects: * May cause the creation of a standard channel and the underlying * file. * *---------------------------------------------------------------------- */ Tcl_Channel TclpGetDefaultStdChannel(type) int type; /* One of TCL_STDIN, TCL_STDOUT, TCL_STDERR. */ { Tcl_Channel channel; HANDLE handle; int mode = -1; char *bufMode = NULL; DWORD handleId = (DWORD)INVALID_HANDLE_VALUE; /* Standard handle to retrieve. */ switch (type) { case TCL_STDIN: handleId = STD_INPUT_HANDLE; mode = TCL_READABLE; bufMode = "line"; break; case TCL_STDOUT: handleId = STD_OUTPUT_HANDLE; mode = TCL_WRITABLE; bufMode = "line"; break; case TCL_STDERR: handleId = STD_ERROR_HANDLE; mode = TCL_WRITABLE; bufMode = "none"; break; default: panic("TclGetDefaultStdChannel: Unexpected channel type"); break; } handle = GetStdHandle(handleId); /* * Note that we need to check for 0 because Windows may return 0 if this * is not a console mode application, even though this is not a valid * handle. */ if ((handle == INVALID_HANDLE_VALUE) || (handle == 0)) { return (Tcl_Channel) NULL; } channel = Tcl_MakeFileChannel(handle, mode); if (channel == NULL) { return (Tcl_Channel) NULL; } /* * Set up the normal channel options for stdio handles. */ if ((Tcl_SetChannelOption((Tcl_Interp *) NULL, channel, "-translation", "auto") == TCL_ERROR) || (Tcl_SetChannelOption((Tcl_Interp *) NULL, channel, "-eofchar", "\032 {}") == TCL_ERROR) || (Tcl_SetChannelOption((Tcl_Interp *) NULL, channel, "-buffering", bufMode) == TCL_ERROR)) { Tcl_Close((Tcl_Interp *) NULL, channel); return (Tcl_Channel) NULL; } return channel; } /* *---------------------------------------------------------------------- * * TclWinOpenFileChannel -- * * Constructs a File channel for the specified standard OS handle. * This is a helper function to break up the construction of * channels into File, Console, or Serial. * * Results: * Returns the new channel, or NULL. * * Side effects: * May open the channel and may cause creation of a file on the * file system. * *---------------------------------------------------------------------- */ Tcl_Channel TclWinOpenFileChannel(handle, channelName, permissions, appendMode) HANDLE handle; char *channelName; int permissions; int appendMode; { FileInfo *infoPtr; ThreadSpecificData *tsdPtr; tsdPtr = FileInit(); /* * See if a channel with this handle already exists. */ for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { if (infoPtr->handle == (HANDLE) handle) { return (permissions == infoPtr->validMask) ? infoPtr->channel : NULL; } } infoPtr = (FileInfo *) ckalloc((unsigned) sizeof(FileInfo)); /* TIP #218. Removed the code inserting the new structure * into the global list. This is now handled in the thread * action callbacks, and only there. */ infoPtr->nextPtr = NULL; infoPtr->validMask = permissions; infoPtr->watchMask = 0; infoPtr->flags = appendMode; infoPtr->handle = handle; infoPtr->dirty = 0; wsprintfA(channelName, "file%lx", (int) infoPtr); infoPtr->channel = Tcl_CreateChannel(&fileChannelType, channelName, (ClientData) infoPtr, permissions); /* * Files have default translation of AUTO and ^Z eof char, which * means that a ^Z will be accepted as EOF when reading. */ Tcl_SetChannelOption(NULL, infoPtr->channel, "-translation", "auto"); Tcl_SetChannelOption(NULL, infoPtr->channel, "-eofchar", "\032 {}"); return infoPtr->channel; } /* *---------------------------------------------------------------------- * * TclWinFlushDirtyChannels -- * * Flush all dirty channels to disk, so that requesting the * size of any file returns the correct value. * * Results: * None. * * Side effects: * Information is actually written to disk now, rather than * later. Don't call this too often, or there will be a * performance hit (i.e. only call when we need to ask for * the size of a file). * *---------------------------------------------------------------------- */ void TclWinFlushDirtyChannels () { FileInfo *infoPtr; ThreadSpecificData *tsdPtr; tsdPtr = FileInit(); /* * Flush all channels which are dirty, i.e. may have data pending * in the OS */ for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { if (infoPtr->dirty) { FlushFileBuffers(infoPtr->handle); infoPtr->dirty = 0; } } } /* *---------------------------------------------------------------------- * * FileThreadActionProc -- * * Insert or remove any thread local refs to this channel. * * Results: * None. * * Side effects: * Changes thread local list of valid channels. * *---------------------------------------------------------------------- */ static void FileThreadActionProc (instanceData, action) ClientData instanceData; int action; { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); FileInfo *infoPtr = (FileInfo *) instanceData; if (action == TCL_CHANNEL_THREAD_INSERT) { infoPtr->nextPtr = tsdPtr->firstFilePtr; tsdPtr->firstFilePtr = infoPtr; } else { FileInfo **nextPtrPtr; int removed = 0; for (nextPtrPtr = &(tsdPtr->firstFilePtr); (*nextPtrPtr) != NULL; nextPtrPtr = &((*nextPtrPtr)->nextPtr)) { if ((*nextPtrPtr) == infoPtr) { (*nextPtrPtr) = infoPtr->nextPtr; removed = 1; break; } } /* * This could happen if the channel was created in one thread * and then moved to another without updating the thread * local data in each thread. */ if (!removed) { panic("file info ptr not on thread channel list"); } } } /* *---------------------------------------------------------------------- * * FileGetType -- * * Given a file handle, return its type * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ DWORD FileGetType(handle) HANDLE handle; /* Opened file handle */ { DWORD type; DWORD consoleParams; DCB dcb; type = GetFileType(handle); /* * If the file is a character device, we need to try to figure out * whether it is a serial port, a console, or something else. We * test for the console case first because this is more common. */ if (type == FILE_TYPE_CHAR || (type == FILE_TYPE_UNKNOWN && !GetLastError())) { if (GetConsoleMode(handle, &consoleParams)) { type = FILE_TYPE_CONSOLE; } else { dcb.DCBlength = sizeof( DCB ) ; if (GetCommState(handle, &dcb)) { type = FILE_TYPE_SERIAL; } } } return type; } tcl8.4.20/win/tclsh.rc0000644003604700454610000000316711737050675013167 0ustar dgp771div// Version Resource Script // #include #include // // build-up the name suffix that defines the type of build this is. // #ifdef TCL_THREADS #define SUFFIX_THREADS "t" #else #define SUFFIX_THREADS "" #endif #ifdef STATIC_BUILD #define SUFFIX_STATIC "s" #else #define SUFFIX_STATIC "" #endif #ifdef DEBUG #define SUFFIX_DEBUG "d" #else #define SUFFIX_DEBUG "" #endif #define SUFFIX SUFFIX_THREADS SUFFIX_STATIC SUFFIX_DEBUG LANGUAGE 0x9, 0x1 /* LANG_ENGLISH, SUBLANG_DEFAULT */ VS_VERSION_INFO VERSIONINFO FILEVERSION TCL_MAJOR_VERSION,TCL_MINOR_VERSION,TCL_RELEASE_LEVEL,TCL_RELEASE_SERIAL PRODUCTVERSION TCL_MAJOR_VERSION,TCL_MINOR_VERSION,TCL_RELEASE_LEVEL,TCL_RELEASE_SERIAL FILEFLAGSMASK 0x3fL #ifdef DEBUG FILEFLAGS VS_FF_DEBUG #else FILEFLAGS 0x0L #endif FILEOS VOS__WINDOWS32 FILETYPE VFT_APP FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "FileDescription", "Tclsh Application\0" VALUE "OriginalFilename", "tclsh" STRINGIFY(JOIN(TCL_MAJOR_VERSION,TCL_MINOR_VERSION)) SUFFIX ".exe\0" VALUE "CompanyName", "ActiveState Corporation\0" VALUE "FileVersion", TCL_PATCH_LEVEL VALUE "LegalCopyright", "Copyright \251 2000 by ActiveState Corporation, et al\0" VALUE "ProductName", "Tcl " TCL_VERSION " for Windows\0" VALUE "ProductVersion", TCL_PATCH_LEVEL END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END // // Icon // tclsh ICON DISCARDABLE "tclsh.ico" tcl8.4.20/win/tclWinDde.c0000644003604700454610000013226312144442333013532 0ustar dgp771div/* * tclWinDde.c -- * * This file provides functions that implement the "send" command, * allowing commands to be passed from interpreter to interpreter. * * Copyright (c) 1997 by Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclPort.h" #include #include /* * TCL_STORAGE_CLASS is set unconditionally to DLLEXPORT because the Dde_Init * declaration is in the source file itself, which is only accessed when we * are building a library. DO NOT MOVE BEFORE ANY #include LINES. ONLY USE * EXTERN TO INDICATE EXPORTED FUNCTIONS FROM NOW ON. */ #undef TCL_STORAGE_CLASS #define TCL_STORAGE_CLASS DLLEXPORT /* * The following structure is used to keep track of the interpreters * registered by this process. */ typedef struct RegisteredInterp { struct RegisteredInterp *nextPtr; /* The next interp this application knows * about. */ char *name; /* Interpreter's name (malloc-ed). */ Tcl_Obj *handlerPtr; /* The server handler command */ Tcl_Interp *interp; /* The interpreter attached to this name. */ } RegisteredInterp; /* * Used to keep track of conversations. */ typedef struct Conversation { struct Conversation *nextPtr; /* The next conversation in the list. */ RegisteredInterp *riPtr; /* The info we know about the conversation. */ HCONV hConv; /* The DDE handle for this conversation. */ Tcl_Obj *returnPackagePtr; /* The result package for this conversation. */ } Conversation; typedef struct DdeEnumServices { Tcl_Interp *interp; int result; ATOM service; ATOM topic; HWND hwnd; } DdeEnumServices; typedef struct ThreadSpecificData { Conversation *currentConversations; /* A list of conversations currently being * processed. */ RegisteredInterp *interpListPtr; /* List of all interpreters registered in the * current process. */ } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; /* * The following variables cannot be placed in thread-local storage. The Mutex * ddeMutex guards access to the ddeInstance. */ static HSZ ddeServiceGlobal = 0; static DWORD ddeInstance; /* The application instance handle given to us * by DdeInitialize. */ static int ddeIsServer = 0; #define TCL_DDE_PACKAGE_NAME "dde" #define TCL_DDE_SERVICE_NAME "TclEval" #define TCL_DDE_EXECUTE_RESULT "$TCLEVAL$EXECUTE$RESULT" #define DDE_FLAG_ASYNC 1 #define DDE_FLAG_BINARY 2 #define DDE_FLAG_FORCE 4 TCL_DECLARE_MUTEX(ddeMutex) /* * Forward declarations for functions defined later in this file. */ static LRESULT CALLBACK DdeClientWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); static int DdeCreateClient(struct DdeEnumServices *es); static BOOL CALLBACK DdeEnumWindowsCallback(HWND hwndTarget, LPARAM lParam); static void DdeExitProc(ClientData clientData); static int DdeGetServicesList(Tcl_Interp *interp, const char *serviceName, const char *topicName); static HDDEDATA CALLBACK DdeServerProc(UINT uType, UINT uFmt, HCONV hConv, HSZ ddeTopic, HSZ ddeItem, HDDEDATA hData, DWORD dwData1, DWORD dwData2); static LRESULT DdeServicesOnAck(HWND hwnd, WPARAM wParam, LPARAM lParam); static void DeleteProc(ClientData clientData); static Tcl_Obj * ExecuteRemoteObject(RegisteredInterp *riPtr, Tcl_Obj *ddeObjectPtr); static int MakeDdeConnection(Tcl_Interp *interp, const char *name, HCONV *ddeConvPtr); static void SetDdeError(Tcl_Interp *interp); static int DdeObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); EXTERN int Dde_Init(Tcl_Interp *interp); EXTERN int Dde_SafeInit(Tcl_Interp *interp); /* *---------------------------------------------------------------------- * * Dde_Init -- * * This function initializes the dde command. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Dde_Init( Tcl_Interp *interp) { if (!Tcl_InitStubs(interp, "8.1", 0)) { return TCL_ERROR; } Tcl_CreateObjCommand(interp, "dde", DdeObjCmd, NULL, NULL); Tcl_CreateExitHandler(DdeExitProc, NULL); return Tcl_PkgProvide(interp, TCL_DDE_PACKAGE_NAME, "1.3.3"); } /* *---------------------------------------------------------------------- * * Dde_SafeInit -- * * This function initializes the dde command within a safe interp * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Dde_SafeInit( Tcl_Interp *interp) { int result = Dde_Init(interp); if (result == TCL_OK) { Tcl_HideCommand(interp, "dde", "dde"); } return result; } /* *---------------------------------------------------------------------- * * Initialize -- * * Initialize the global DDE instance. * * Results: * None. * * Side effects: * Registers the DDE server proc. * *---------------------------------------------------------------------- */ static void Initialize(void) { int nameFound = 0; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); /* * See if the application is already registered; if so, remove its current * name from the registry. The deletion of the command will take care of * disposing of this entry. */ if (tsdPtr->interpListPtr != NULL) { nameFound = 1; } /* * Make sure that the DDE server is there. This is done only once, add an * exit handler tear it down. */ if (ddeInstance == 0) { Tcl_MutexLock(&ddeMutex); if (ddeInstance == 0) { if (DdeInitialize(&ddeInstance, (PFNCALLBACK) DdeServerProc, CBF_SKIP_REGISTRATIONS | CBF_SKIP_UNREGISTRATIONS | CBF_FAIL_POKES, 0) != DMLERR_NO_ERROR) { ddeInstance = 0; } } Tcl_MutexUnlock(&ddeMutex); } if ((ddeServiceGlobal == 0) && (nameFound != 0)) { Tcl_MutexLock(&ddeMutex); if ((ddeServiceGlobal == 0) && (nameFound != 0)) { ddeIsServer = 1; Tcl_CreateExitHandler(DdeExitProc, NULL); ddeServiceGlobal = DdeCreateStringHandle(ddeInstance, TCL_DDE_SERVICE_NAME, 0); DdeNameService(ddeInstance, ddeServiceGlobal, 0L, DNS_REGISTER); } else { ddeIsServer = 0; } Tcl_MutexUnlock(&ddeMutex); } } /* *---------------------------------------------------------------------- * * DdeSetServerName -- * * This function is called to associate an ASCII name with a Dde server. * If the interpreter has already been named, the name replaces the old * one. * * Results: * The return value is the name actually given to the interp. This will * normally be the same as name, but if name was already in use for a Dde * Server then a name of the form "name #2" will be chosen, with a high * enough number to make the name unique. * * Side effects: * Registration info is saved, thereby allowing the "send" command to be * used later to invoke commands in the application. In addition, the * "send" command is created in the application's interpreter. The * registration will be removed automatically if the interpreter is * deleted or the "send" command is removed. * *---------------------------------------------------------------------- */ static const char * DdeSetServerName( Tcl_Interp *interp, const char *name, /* The name that will be used to refer to the * interpreter in later "send" commands. Must * be globally unique. */ int flags, /* DDE_FLAG_FORCE or 0 */ Tcl_Obj *handlerPtr) /* Name of the optional proc/command to handle * incoming Dde eval's */ { int suffix, offset; RegisteredInterp *riPtr, *prevPtr; Tcl_DString dString; const char *actualName; Tcl_Obj *srvListPtr = NULL, **srvPtrPtr = NULL; int n, srvCount = 0, lastSuffix, r = TCL_OK; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); /* * See if the application is already registered; if so, remove its current * name from the registry. The deletion of the command will take care of * disposing of this entry. */ for (riPtr = tsdPtr->interpListPtr, prevPtr = NULL; riPtr != NULL; prevPtr = riPtr, riPtr = riPtr->nextPtr) { if (riPtr->interp == interp) { if (name != NULL) { if (prevPtr == NULL) { tsdPtr->interpListPtr = tsdPtr->interpListPtr->nextPtr; } else { prevPtr->nextPtr = riPtr->nextPtr; } break; } else { /* * The name was NULL, so the caller is asking for the name of * the current interp. */ return riPtr->name; } } } if (name == NULL) { /* * The name was NULL, so the caller is asking for the name of the * current interp, but it doesn't have a name. */ return ""; } /* * Get the list of currently registered Tcl interpreters by calling the * internal implementation of the 'dde services' command. */ Tcl_DStringInit(&dString); actualName = name; if (!(flags & DDE_FLAG_FORCE)) { r = DdeGetServicesList(interp, TCL_DDE_SERVICE_NAME, NULL); if (r == TCL_OK) { srvListPtr = Tcl_GetObjResult(interp); } if (r == TCL_OK) { r = Tcl_ListObjGetElements(interp, srvListPtr, &srvCount, &srvPtrPtr); } if (r != TCL_OK) { OutputDebugString(Tcl_GetStringResult(interp)); return NULL; } /* * Pick a name to use for the application. Use "name" if it's not * already in use. Otherwise add a suffix such as " #2", trying larger * and larger numbers until we eventually find one that is unique. */ offset = lastSuffix = 0; suffix = 1; while (suffix != lastSuffix) { lastSuffix = suffix; if (suffix > 1) { if (suffix == 2) { Tcl_DStringAppend(&dString, name, -1); Tcl_DStringAppend(&dString, " #", 2); offset = Tcl_DStringLength(&dString); Tcl_DStringSetLength(&dString, offset + TCL_INTEGER_SPACE); actualName = Tcl_DStringValue(&dString); } sprintf(Tcl_DStringValue(&dString) + offset, "%d", suffix); } /* * See if the name is already in use, if so increment suffix. */ for (n = 0; n < srvCount; ++n) { Tcl_Obj* namePtr; Tcl_ListObjIndex(interp, srvPtrPtr[n], 1, &namePtr); if (strcmp(actualName, Tcl_GetString(namePtr)) == 0) { suffix++; break; } } } Tcl_DStringSetLength(&dString, offset + (int)strlen(Tcl_DStringValue(&dString)+offset)); } /* * We have found a unique name. Now add it to the registry. */ riPtr = (RegisteredInterp *) ckalloc(sizeof(RegisteredInterp)); riPtr->interp = interp; riPtr->name = ckalloc((unsigned int) strlen(actualName) + 1); riPtr->nextPtr = tsdPtr->interpListPtr; riPtr->handlerPtr = handlerPtr; if (riPtr->handlerPtr != NULL) { Tcl_IncrRefCount(riPtr->handlerPtr); } tsdPtr->interpListPtr = riPtr; strcpy(riPtr->name, actualName); if (Tcl_IsSafe(interp)) { Tcl_ExposeCommand(interp, "dde", "dde"); } Tcl_CreateObjCommand(interp, "dde", DdeObjCmd, (ClientData) riPtr, DeleteProc); if (Tcl_IsSafe(interp)) { Tcl_HideCommand(interp, "dde", "dde"); } Tcl_DStringFree(&dString); /* * Re-initialize with the new name. */ Initialize(); return riPtr->name; } /* *---------------------------------------------------------------------- * * DdeGetRegistrationPtr * * Retrieve the registration info for an interpreter. * * Results: * Returns a pointer to the registration structure or NULL * * Side effects: * None * *---------------------------------------------------------------------- */ static RegisteredInterp * DdeGetRegistrationPtr( Tcl_Interp *interp) { RegisteredInterp *riPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); for (riPtr = tsdPtr->interpListPtr; riPtr != NULL; riPtr = riPtr->nextPtr) { if (riPtr->interp == interp) { break; } } return riPtr; } /* *---------------------------------------------------------------------- * * DeleteProc * * This function is called when the command "dde" is destroyed. * * Results: * none * * Side effects: * The interpreter given by riPtr is unregistered. * *---------------------------------------------------------------------- */ static void DeleteProc( ClientData clientData) /* The interp we are deleting passed as * ClientData. */ { RegisteredInterp *riPtr = (RegisteredInterp *) clientData; RegisteredInterp *searchPtr, *prevPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); for (searchPtr = tsdPtr->interpListPtr, prevPtr = NULL; (searchPtr != NULL) && (searchPtr != riPtr); prevPtr = searchPtr, searchPtr = searchPtr->nextPtr) { /* * Empty loop body. */ } if (searchPtr != NULL) { if (prevPtr == NULL) { tsdPtr->interpListPtr = tsdPtr->interpListPtr->nextPtr; } else { prevPtr->nextPtr = searchPtr->nextPtr; } } ckfree(riPtr->name); if (riPtr->handlerPtr) { Tcl_DecrRefCount(riPtr->handlerPtr); } Tcl_EventuallyFree(clientData, TCL_DYNAMIC); } /* *---------------------------------------------------------------------- * * ExecuteRemoteObject -- * * Takes the package delivered by DDE and executes it in the server's * interpreter. * * Results: * A list Tcl_Obj * that describes what happened. The first element is * the numerical return code (TCL_ERROR, etc.). The second element is the * result of the script. If the return result was TCL_ERROR, then the * third element will be the value of the global "errorCode", and the * fourth will be the value of the global "errorInfo". The return result * will have a refCount of 0. * * Side effects: * A Tcl script is run, which can cause all kinds of other things to * happen. * *---------------------------------------------------------------------- */ static Tcl_Obj * ExecuteRemoteObject( RegisteredInterp *riPtr, /* Info about this server. */ Tcl_Obj *ddeObjectPtr) /* The object to execute. */ { Tcl_Obj *returnPackagePtr; int result = TCL_OK; if (riPtr->handlerPtr == NULL && Tcl_IsSafe(riPtr->interp)) { Tcl_SetObjResult(riPtr->interp, Tcl_NewStringObj("permission denied: " "a handler procedure must be defined for use in a safe " "interp", -1)); result = TCL_ERROR; } if (riPtr->handlerPtr != NULL) { /* * Add the dde request data to the handler proc list. */ Tcl_Obj *cmdPtr = Tcl_DuplicateObj(riPtr->handlerPtr); result = Tcl_ListObjAppendElement(riPtr->interp, cmdPtr, ddeObjectPtr); if (result == TCL_OK) { ddeObjectPtr = cmdPtr; } } if (result == TCL_OK) { result = Tcl_EvalObjEx(riPtr->interp, ddeObjectPtr, TCL_EVAL_GLOBAL); } returnPackagePtr = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(NULL, returnPackagePtr, Tcl_NewIntObj(result)); Tcl_ListObjAppendElement(NULL, returnPackagePtr, Tcl_GetObjResult(riPtr->interp)); if (result == TCL_ERROR) { Tcl_Obj *errorObjPtr = Tcl_GetVar2Ex(riPtr->interp, "errorCode", NULL, TCL_GLOBAL_ONLY); if (errorObjPtr) { Tcl_ListObjAppendElement(NULL, returnPackagePtr, errorObjPtr); } errorObjPtr = Tcl_GetVar2Ex(riPtr->interp, "errorInfo", NULL, TCL_GLOBAL_ONLY); if (errorObjPtr) { Tcl_ListObjAppendElement(NULL, returnPackagePtr, errorObjPtr); } } return returnPackagePtr; } /* *---------------------------------------------------------------------- * * DdeServerProc -- * * Handles all transactions for this server. Can handle execute, request, * and connect protocols. Dde will call this routine when a client * attempts to run a dde command using this server. * * Results: * A DDE Handle with the result of the dde command. * * Side effects: * Depending on which command is executed, arbitrary Tcl scripts can be * run. * *---------------------------------------------------------------------- */ static HDDEDATA CALLBACK DdeServerProc( UINT uType, /* The type of DDE transaction we are * performing. */ UINT uFmt, /* The format that data is sent or received */ HCONV hConv, /* The conversation associated with the * current transaction. */ HSZ ddeTopic, HSZ ddeItem, /* String handles. Transaction-type * dependent. */ HDDEDATA hData, /* DDE data. Transaction-type dependent. */ DWORD dwData1, DWORD dwData2) /* Transaction-dependent data. */ { Tcl_DString dString; int len; DWORD dlen; char *utilString; Tcl_Obj *ddeObjectPtr; HDDEDATA ddeReturn = NULL; RegisteredInterp *riPtr; Conversation *convPtr, *prevConvPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); switch(uType) { case XTYP_CONNECT: /* * Dde is trying to initialize a conversation with us. Check and make * sure we have a valid topic. */ len = DdeQueryString(ddeInstance, ddeTopic, NULL, 0, 0); Tcl_DStringInit(&dString); Tcl_DStringSetLength(&dString, len); utilString = Tcl_DStringValue(&dString); DdeQueryString(ddeInstance, ddeTopic, utilString, (DWORD) len + 1, CP_WINANSI); for (riPtr = tsdPtr->interpListPtr; riPtr != NULL; riPtr = riPtr->nextPtr) { if (stricmp(utilString, riPtr->name) == 0) { Tcl_DStringFree(&dString); return (HDDEDATA) TRUE; } } Tcl_DStringFree(&dString); return (HDDEDATA) FALSE; case XTYP_CONNECT_CONFIRM: /* * Dde has decided that we can connect, so it gives us a conversation * handle. We need to keep track of it so we know which execution * result to return in an XTYP_REQUEST. */ len = DdeQueryString(ddeInstance, ddeTopic, NULL, 0, 0); Tcl_DStringInit(&dString); Tcl_DStringSetLength(&dString, len); utilString = Tcl_DStringValue(&dString); DdeQueryString(ddeInstance, ddeTopic, utilString, (DWORD) len + 1, CP_WINANSI); for (riPtr = tsdPtr->interpListPtr; riPtr != NULL; riPtr = riPtr->nextPtr) { if (stricmp(riPtr->name, utilString) == 0) { convPtr = (Conversation *) ckalloc(sizeof(Conversation)); convPtr->nextPtr = tsdPtr->currentConversations; convPtr->returnPackagePtr = NULL; convPtr->hConv = hConv; convPtr->riPtr = riPtr; tsdPtr->currentConversations = convPtr; break; } } Tcl_DStringFree(&dString); return (HDDEDATA) TRUE; case XTYP_DISCONNECT: /* * The client has disconnected from our server. Forget this * conversation. */ for (convPtr = tsdPtr->currentConversations, prevConvPtr = NULL; convPtr != NULL; prevConvPtr = convPtr, convPtr = convPtr->nextPtr) { if (hConv == convPtr->hConv) { if (prevConvPtr == NULL) { tsdPtr->currentConversations = convPtr->nextPtr; } else { prevConvPtr->nextPtr = convPtr->nextPtr; } if (convPtr->returnPackagePtr != NULL) { Tcl_DecrRefCount(convPtr->returnPackagePtr); } ckfree((char *) convPtr); break; } } return (HDDEDATA) TRUE; case XTYP_REQUEST: /* * This could be either a request for a value of a Tcl variable, or it * could be the send command requesting the results of the last * execute. */ if ((uFmt != CF_TEXT) && (uFmt != CF_UNICODETEXT)) { return (HDDEDATA) FALSE; } ddeReturn = (HDDEDATA) FALSE; for (convPtr = tsdPtr->currentConversations; (convPtr != NULL) && (convPtr->hConv != hConv); convPtr = convPtr->nextPtr) { /* * Empty loop body. */ } if (convPtr != NULL) { char *returnString; len = DdeQueryString(ddeInstance, ddeItem, NULL, 0, CP_WINANSI); Tcl_DStringInit(&dString); Tcl_DStringSetLength(&dString, len); utilString = Tcl_DStringValue(&dString); DdeQueryString(ddeInstance, ddeItem, utilString, (DWORD) len + 1, CP_WINANSI); if (stricmp(utilString, TCL_DDE_EXECUTE_RESULT) == 0) { if (uFmt == CF_TEXT) { returnString = Tcl_GetStringFromObj(convPtr->returnPackagePtr, &len); } else { returnString = (char *) Tcl_GetUnicodeFromObj(convPtr->returnPackagePtr, &len); len = 2 * len + 1; } ddeReturn = DdeCreateDataHandle(ddeInstance, (BYTE *)returnString, (DWORD) len+1, 0, ddeItem, uFmt, 0); } else { if (Tcl_IsSafe(convPtr->riPtr->interp)) { ddeReturn = NULL; } else { Tcl_Obj *variableObjPtr = Tcl_GetVar2Ex( convPtr->riPtr->interp, utilString, NULL, TCL_GLOBAL_ONLY); if (variableObjPtr != NULL) { if (uFmt == CF_TEXT) { returnString = Tcl_GetStringFromObj( variableObjPtr, &len); } else { returnString = (char *) Tcl_GetUnicodeFromObj( variableObjPtr, &len); len = 2 * len + 1; } ddeReturn = DdeCreateDataHandle(ddeInstance, (BYTE *)returnString, (DWORD) len+1, 0, ddeItem, uFmt, 0); } else { ddeReturn = NULL; } } } Tcl_DStringFree(&dString); } return ddeReturn; case XTYP_EXECUTE: { /* * Execute this script. The results will be saved into a list object * which will be retreived later. See ExecuteRemoteObject. */ Tcl_Obj *returnPackagePtr; Tcl_UniChar *uniStr; for (convPtr = tsdPtr->currentConversations; (convPtr != NULL) && (convPtr->hConv != hConv); convPtr = convPtr->nextPtr) { /* * Empty loop body. */ } if (convPtr == NULL) { return (HDDEDATA) DDE_FNOTPROCESSED; } utilString = (char *) DdeAccessData(hData, &dlen); uniStr = (Tcl_UniChar *) utilString; if (!dlen) { /* Empty binary array. */ ddeObjectPtr = Tcl_NewObj(); } else if ((dlen & 1) || uniStr[(dlen>>1)-1]) { /* Cannot be unicode, so assume utf-8 */ if (!utilString[dlen-1]) { dlen--; } ddeObjectPtr = Tcl_NewStringObj(utilString, dlen); } else { /* unicode */ dlen >>= 1; ddeObjectPtr = Tcl_NewUnicodeObj(uniStr, dlen - 1); } Tcl_IncrRefCount(ddeObjectPtr); DdeUnaccessData(hData); if (convPtr->returnPackagePtr != NULL) { Tcl_DecrRefCount(convPtr->returnPackagePtr); } convPtr->returnPackagePtr = NULL; returnPackagePtr = ExecuteRemoteObject(convPtr->riPtr, ddeObjectPtr); Tcl_IncrRefCount(returnPackagePtr); for (convPtr = tsdPtr->currentConversations; (convPtr != NULL) && (convPtr->hConv != hConv); convPtr = convPtr->nextPtr) { /* * Empty loop body. */ } if (convPtr != NULL) { convPtr->returnPackagePtr = returnPackagePtr; } else { Tcl_DecrRefCount(returnPackagePtr); } Tcl_DecrRefCount(ddeObjectPtr); if (returnPackagePtr == NULL) { return (HDDEDATA) DDE_FNOTPROCESSED; } else { return (HDDEDATA) DDE_FACK; } } case XTYP_WILDCONNECT: { /* * Dde wants a list of services and topics that we support. */ HSZPAIR *returnPtr; int i; int numItems; for (i = 0, riPtr = tsdPtr->interpListPtr; riPtr != NULL; i++, riPtr = riPtr->nextPtr) { /* * Empty loop body. */ } numItems = i; ddeReturn = DdeCreateDataHandle(ddeInstance, NULL, (numItems + 1) * sizeof(HSZPAIR), 0, 0, 0, 0); returnPtr = (HSZPAIR *) DdeAccessData(ddeReturn, &dlen); len = dlen; for (i = 0, riPtr = tsdPtr->interpListPtr; i < numItems; i++, riPtr = riPtr->nextPtr) { returnPtr[i].hszSvc = DdeCreateStringHandle(ddeInstance, TCL_DDE_SERVICE_NAME, CP_WINANSI); returnPtr[i].hszTopic = DdeCreateStringHandle(ddeInstance, riPtr->name, CP_WINANSI); } returnPtr[i].hszSvc = NULL; returnPtr[i].hszTopic = NULL; DdeUnaccessData(ddeReturn); return ddeReturn; } default: return NULL; } } /* *---------------------------------------------------------------------- * * DdeExitProc -- * * Gets rid of our DDE server when we go away. * * Results: * None. * * Side effects: * The DDE server is deleted. * *---------------------------------------------------------------------- */ static void DdeExitProc( ClientData clientData) /* Not used in this handler. */ { DdeNameService(ddeInstance, NULL, 0, DNS_UNREGISTER); DdeUninitialize(ddeInstance); ddeInstance = 0; } /* *---------------------------------------------------------------------- * * MakeDdeConnection -- * * This function is a utility used to connect to a DDE server when given * a server name and a topic name. * * Results: * A standard Tcl result. * * Side effects: * Passes back a conversation through ddeConvPtr * *---------------------------------------------------------------------- */ static int MakeDdeConnection( Tcl_Interp *interp, /* Used to report errors. */ const char *name, /* The connection to use. */ HCONV *ddeConvPtr) { HSZ ddeTopic, ddeService; HCONV ddeConv; ddeService = DdeCreateStringHandle(ddeInstance, TCL_DDE_SERVICE_NAME, 0); ddeTopic = DdeCreateStringHandle(ddeInstance, name, 0); ddeConv = DdeConnect(ddeInstance, ddeService, ddeTopic, NULL); DdeFreeStringHandle(ddeInstance, ddeService); DdeFreeStringHandle(ddeInstance, ddeTopic); if (ddeConv == (HCONV) NULL) { if (interp != NULL) { Tcl_AppendResult(interp, "no registered server named \"", name, "\"", NULL); } return TCL_ERROR; } *ddeConvPtr = ddeConv; return TCL_OK; } /* *---------------------------------------------------------------------- * * DdeGetServicesList -- * * This function obtains the list of DDE services. * * The functions between here and this function are all involved with * handling the DDE callbacks for this. They are: DdeCreateClient, * DdeClientWindowProc, DdeServicesOnAck, and DdeEnumWindowsCallback * * Results: * A standard Tcl result. * * Side effects: * Sets the services list into the interp result. * *---------------------------------------------------------------------- */ static int DdeCreateClient( struct DdeEnumServices *es) { WNDCLASSEX wc; static const char *szDdeClientClassName = "TclEval client class"; static const char *szDdeClientWindowName = "TclEval client window"; memset(&wc, 0, sizeof(wc)); wc.cbSize = sizeof(wc); wc.lpfnWndProc = DdeClientWindowProc; wc.lpszClassName = szDdeClientClassName; wc.cbWndExtra = sizeof(struct DdeEnumServices *); /* * Register and create the callback window. */ RegisterClassEx(&wc); es->hwnd = CreateWindowEx(0, szDdeClientClassName, szDdeClientWindowName, WS_POPUP, 0, 0, 0, 0, NULL, NULL, NULL, (LPVOID)es); return TCL_OK; } static LRESULT CALLBACK DdeClientWindowProc( HWND hwnd, /* What window is the message for */ UINT uMsg, /* The type of message received */ WPARAM wParam, LPARAM lParam) /* (Potentially) our local handle */ { switch (uMsg) { case WM_CREATE: { LPCREATESTRUCT lpcs = (LPCREATESTRUCT) lParam; struct DdeEnumServices *es = (struct DdeEnumServices *) lpcs->lpCreateParams; #ifdef _WIN64 SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) es); #else SetWindowLong(hwnd, GWL_USERDATA, (LONG) es); #endif return (LRESULT) 0L; } case WM_DDE_ACK: return DdeServicesOnAck(hwnd, wParam, lParam); default: return DefWindowProc(hwnd, uMsg, wParam, lParam); } } static LRESULT DdeServicesOnAck( HWND hwnd, WPARAM wParam, LPARAM lParam) { HWND hwndRemote = (HWND)wParam; ATOM service = (ATOM)LOWORD(lParam); ATOM topic = (ATOM)HIWORD(lParam); struct DdeEnumServices *es; char sz[255]; #ifdef _WIN64 es = (struct DdeEnumServices *) GetWindowLongPtr(hwnd, GWLP_USERDATA); #else es = (struct DdeEnumServices *) GetWindowLong(hwnd, GWL_USERDATA); #endif if ((es->service == (ATOM)0 || es->service == service) && (es->topic == (ATOM)0 || es->topic == topic)) { Tcl_Obj *matchPtr = Tcl_NewListObj(0, NULL); Tcl_Obj *resultPtr = Tcl_GetObjResult(es->interp); GlobalGetAtomName(service, sz, 255); Tcl_ListObjAppendElement(NULL, matchPtr, Tcl_NewStringObj(sz, -1)); GlobalGetAtomName(topic, sz, 255); Tcl_ListObjAppendElement(NULL, matchPtr, Tcl_NewStringObj(sz, -1)); /* * Adding the hwnd as a third list element provides a unique * identifier in the case of multiple servers with the name * application and topic names. */ /* * Needs a TIP though: * Tcl_ListObjAppendElement(NULL, matchPtr, * Tcl_NewLongObj((long)hwndRemote)); */ if (Tcl_IsShared(resultPtr)) { resultPtr = Tcl_DuplicateObj(resultPtr); } if (Tcl_ListObjAppendElement(es->interp, resultPtr, matchPtr) == TCL_OK) { Tcl_SetObjResult(es->interp, resultPtr); } } /* * Tell the server we are no longer interested. */ PostMessage(hwndRemote, WM_DDE_TERMINATE, (WPARAM)hwnd, 0L); return 0L; } static BOOL CALLBACK DdeEnumWindowsCallback( HWND hwndTarget, LPARAM lParam) { DWORD_PTR dwResult = 0; struct DdeEnumServices *es = (struct DdeEnumServices *) lParam; SendMessageTimeout(hwndTarget, WM_DDE_INITIATE, (WPARAM)es->hwnd, MAKELONG(es->service, es->topic), SMTO_ABORTIFHUNG, 1000, &dwResult); return TRUE; } static int DdeGetServicesList( Tcl_Interp *interp, const char *serviceName, const char *topicName) { struct DdeEnumServices es; es.interp = interp; es.result = TCL_OK; es.service = (serviceName == NULL) ? (ATOM)0 : GlobalAddAtom(serviceName); es.topic = (topicName == NULL) ? (ATOM)0 : GlobalAddAtom(topicName); Tcl_ResetResult(interp); /* our list is to be appended to result. */ DdeCreateClient(&es); EnumWindows(DdeEnumWindowsCallback, (LPARAM)&es); if (IsWindow(es.hwnd)) { DestroyWindow(es.hwnd); } if (es.service != (ATOM)0) { GlobalDeleteAtom(es.service); } if (es.topic != (ATOM)0) { GlobalDeleteAtom(es.topic); } return es.result; } /* *---------------------------------------------------------------------- * * SetDdeError -- * * Sets the interp result to a cogent error message describing the last * DDE error. * * Results: * None. * * Side effects: * The interp's result object is changed. * *---------------------------------------------------------------------- */ static void SetDdeError( Tcl_Interp *interp) /* The interp to put the message in. */ { const char *errorMessage; switch (DdeGetLastError(ddeInstance)) { case DMLERR_DATAACKTIMEOUT: case DMLERR_EXECACKTIMEOUT: case DMLERR_POKEACKTIMEOUT: errorMessage = "remote interpreter did not respond"; break; case DMLERR_BUSY: errorMessage = "remote server is busy"; break; case DMLERR_NOTPROCESSED: errorMessage = "remote server cannot handle this command"; break; default: errorMessage = "dde command failed"; } Tcl_SetObjResult(interp, Tcl_NewStringObj(errorMessage, -1)); } /* *---------------------------------------------------------------------- * * DdeObjCmd -- * * This function is invoked to process the "dde" Tcl command. See the * user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ static int DdeObjCmd( ClientData clientData, /* Used only for deletion */ Tcl_Interp *interp, /* The interp we are sending from */ int objc, /* Number of arguments */ Tcl_Obj *const *objv) /* The arguments */ { static const char *ddeCommands[] = { "servername", "execute", "poke", "request", "services", "eval", (char *) NULL}; enum DdeSubcommands { DDE_SERVERNAME, DDE_EXECUTE, DDE_POKE, DDE_REQUEST, DDE_SERVICES, DDE_EVAL }; static const char *ddeSrvOptions[] = { "-force", "-handler", "--", NULL }; enum DdeSrvOptions { DDE_SERVERNAME_EXACT, DDE_SERVERNAME_HANDLER, DDE_SERVERNAME_LAST, }; static const char *ddeExecOptions[] = { "-async", NULL }; static const char *ddeReqOptions[] = { "-binary", NULL }; int index, i, length, argIndex; int flags = 0, result = TCL_OK, firstArg = 0; HSZ ddeService = NULL, ddeTopic = NULL, ddeItem = NULL, ddeCookie = NULL; HDDEDATA ddeData = NULL, ddeItemData = NULL, ddeReturn; HCONV hConv = NULL; const char *serviceName = NULL, *topicName = NULL, *string; DWORD ddeResult; Tcl_Obj *objPtr, *handlerPtr = NULL; /* * Initialize DDE server/client */ if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "command ?arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[1], ddeCommands, "command", 0, &index) != TCL_OK) { return TCL_ERROR; } switch ((enum DdeSubcommands) index) { case DDE_SERVERNAME: for (i = 2; i < objc; i++) { if (Tcl_GetIndexFromObj(interp, objv[i], ddeSrvOptions, "option", 0, &argIndex) != TCL_OK) { /* * If it is the last argument, it might be a server name * instead of a bad argument. */ if (i != objc-1) { return TCL_ERROR; } Tcl_ResetResult(interp); break; } if (argIndex == DDE_SERVERNAME_EXACT) { flags |= DDE_FLAG_FORCE; } else if (argIndex == DDE_SERVERNAME_HANDLER) { if ((objc - i) == 1) { /* return current handler */ RegisteredInterp *riPtr = DdeGetRegistrationPtr(interp); if (riPtr && riPtr->handlerPtr) { Tcl_SetObjResult(interp, riPtr->handlerPtr); } else { Tcl_ResetResult(interp); } return TCL_OK; } handlerPtr = objv[++i]; } else if (argIndex == DDE_SERVERNAME_LAST) { i++; break; } } if ((objc - i) > 1) { Tcl_ResetResult(interp); Tcl_WrongNumArgs(interp, 2, objv, "?-force? ?-handler proc? ?--? ?serverName?"); return TCL_ERROR; } firstArg = (objc == i) ? 1 : i; break; case DDE_EXECUTE: if (objc == 5) { firstArg = 2; break; } else if (objc == 6) { if (Tcl_GetIndexFromObj(NULL, objv[2], ddeExecOptions, "option", 0, &argIndex) == TCL_OK) { flags |= DDE_FLAG_ASYNC; firstArg = 3; break; } } /* otherwise... */ Tcl_WrongNumArgs(interp, 2, objv, "?-async? serviceName topicName value"); return TCL_ERROR; case DDE_POKE: if (objc != 6) { Tcl_WrongNumArgs(interp, 2, objv, "serviceName topicName item value"); return TCL_ERROR; } firstArg = 2; break; case DDE_REQUEST: if (objc == 5) { firstArg = 2; break; } else if (objc == 6) { int dummy; if (Tcl_GetIndexFromObj(NULL, objv[2], ddeReqOptions, "option", 0, &dummy) == TCL_OK) { flags |= DDE_FLAG_BINARY; firstArg = 3; break; } } /* * Otherwise ... */ Tcl_WrongNumArgs(interp, 2, objv, "?-binary? serviceName topicName value"); return TCL_ERROR; case DDE_SERVICES: if (objc != 4) { Tcl_WrongNumArgs(interp, 2, objv, "serviceName topicName"); return TCL_ERROR; } firstArg = 2; break; case DDE_EVAL: if (objc < 4) { wrongDdeEvalArgs: Tcl_WrongNumArgs(interp, 2, objv, "?-async? serviceName args"); return TCL_ERROR; } else { firstArg = 2; if (Tcl_GetIndexFromObj(NULL, objv[2], ddeExecOptions, "option", 0, &argIndex) == TCL_OK) { if (objc < 5) { goto wrongDdeEvalArgs; } flags |= DDE_FLAG_ASYNC; firstArg++; } break; } } Initialize(); if (firstArg != 1) { serviceName = Tcl_GetStringFromObj(objv[firstArg], &length); } else { length = 0; } if (length == 0) { serviceName = NULL; } else if ((index != DDE_SERVERNAME) && (index != DDE_EVAL)) { ddeService = DdeCreateStringHandle(ddeInstance, (void *) serviceName, CP_WINANSI); } if ((index != DDE_SERVERNAME) && (index != DDE_EVAL)) { topicName = Tcl_GetStringFromObj(objv[firstArg + 1], &length); if (length == 0) { topicName = NULL; } else { ddeTopic = DdeCreateStringHandle(ddeInstance, (void *) topicName, CP_WINANSI); } } switch ((enum DdeSubcommands) index) { case DDE_SERVERNAME: serviceName = DdeSetServerName(interp, serviceName, flags, handlerPtr); if (serviceName != NULL) { Tcl_SetObjResult(interp, Tcl_NewStringObj(serviceName, -1)); } else { Tcl_ResetResult(interp); } break; case DDE_EXECUTE: { int dataLength; BYTE *dataString = (BYTE *) Tcl_GetStringFromObj( objv[firstArg + 2], &dataLength); if (dataLength == 0) { Tcl_SetObjResult(interp, Tcl_NewStringObj("cannot execute null data", -1)); result = TCL_ERROR; break; } hConv = DdeConnect(ddeInstance, ddeService, ddeTopic, NULL); DdeFreeStringHandle(ddeInstance, ddeService); DdeFreeStringHandle(ddeInstance, ddeTopic); if (hConv == NULL) { SetDdeError(interp); result = TCL_ERROR; break; } ddeData = DdeCreateDataHandle(ddeInstance, dataString, (DWORD) dataLength+1, 0, 0, CF_TEXT, 0); if (ddeData != NULL) { if (flags & DDE_FLAG_ASYNC) { DdeClientTransaction((LPBYTE) ddeData, 0xFFFFFFFF, hConv, 0, CF_TEXT, XTYP_EXECUTE, TIMEOUT_ASYNC, &ddeResult); DdeAbandonTransaction(ddeInstance, hConv, ddeResult); } else { ddeReturn = DdeClientTransaction((LPBYTE) ddeData, 0xFFFFFFFF, hConv, 0, CF_TEXT, XTYP_EXECUTE, 30000, NULL); if (ddeReturn == 0) { SetDdeError(interp); result = TCL_ERROR; } } DdeFreeDataHandle(ddeData); } else { SetDdeError(interp); result = TCL_ERROR; } break; } case DDE_REQUEST: { const char *itemString = Tcl_GetStringFromObj(objv[firstArg + 2], &length); if (length == 0) { Tcl_SetObjResult(interp, Tcl_NewStringObj("cannot request value of null data", -1)); result = TCL_ERROR; goto cleanup; } hConv = DdeConnect(ddeInstance, ddeService, ddeTopic, NULL); DdeFreeStringHandle(ddeInstance, ddeService); DdeFreeStringHandle(ddeInstance, ddeTopic); if (hConv == NULL) { SetDdeError(interp); result = TCL_ERROR; } else { Tcl_Obj *returnObjPtr; ddeItem = DdeCreateStringHandle(ddeInstance, (void *)itemString, CP_WINANSI); if (ddeItem != NULL) { ddeData = DdeClientTransaction(NULL, 0, hConv, ddeItem, CF_TEXT, XTYP_REQUEST, 5000, NULL); if (ddeData == NULL) { SetDdeError(interp); result = TCL_ERROR; } else { DWORD tmp; const char *dataString = (const char *) DdeAccessData(ddeData, &tmp); if (flags & DDE_FLAG_BINARY) { returnObjPtr = Tcl_NewByteArrayObj((BYTE *) dataString, (int) tmp); } else { if (tmp && !dataString[tmp-1]) { --tmp; } returnObjPtr = Tcl_NewStringObj(dataString, (int) tmp); } DdeUnaccessData(ddeData); DdeFreeDataHandle(ddeData); Tcl_SetObjResult(interp, returnObjPtr); } } else { SetDdeError(interp); result = TCL_ERROR; } } break; } case DDE_POKE: { const char *itemString = Tcl_GetStringFromObj(objv[firstArg + 2], &length); BYTE *dataString; if (length == 0) { Tcl_SetObjResult(interp, Tcl_NewStringObj("cannot have a null item", -1)); result = TCL_ERROR; goto cleanup; } dataString = (BYTE *) Tcl_GetStringFromObj(objv[firstArg + 3], &length); hConv = DdeConnect(ddeInstance, ddeService, ddeTopic, NULL); DdeFreeStringHandle(ddeInstance, ddeService); DdeFreeStringHandle(ddeInstance, ddeTopic); if (hConv == NULL) { SetDdeError(interp); result = TCL_ERROR; } else { ddeItem = DdeCreateStringHandle(ddeInstance, (void *) itemString, CP_WINANSI); if (ddeItem != NULL) { ddeData = DdeClientTransaction(dataString, (DWORD) length+1, hConv, ddeItem, CF_TEXT, XTYP_POKE, 5000, NULL); if (ddeData == NULL) { SetDdeError(interp); result = TCL_ERROR; } } else { SetDdeError(interp); result = TCL_ERROR; } } break; } case DDE_SERVICES: result = DdeGetServicesList(interp, serviceName, topicName); break; case DDE_EVAL: { RegisteredInterp *riPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (serviceName == NULL) { Tcl_SetObjResult(interp, Tcl_NewStringObj("invalid service name \"\"", -1)); result = TCL_ERROR; goto cleanup; } objc -= firstArg + 1; objv += firstArg + 1; /* * See if the target interpreter is local. If so, execute the command * directly without going through the DDE server. Don't exchange * objects between interps. The target interp could compile an object, * producing a bytecode structure that refers to other objects owned * by the target interp. If the target interp is then deleted, the * bytecode structure would be referring to deallocated objects. */ for (riPtr = tsdPtr->interpListPtr; riPtr != NULL; riPtr = riPtr->nextPtr) { if (stricmp(serviceName, riPtr->name) == 0) { break; } } if (riPtr != NULL) { Tcl_Interp *sendInterp; /* * This command is to a local interp. No need to go through the * server. */ Tcl_Preserve((ClientData) riPtr); sendInterp = riPtr->interp; Tcl_Preserve((ClientData) sendInterp); /* * Don't exchange objects between interps. The target interp would * compile an object, producing a bytecode structure that refers * to other objects owned by the target interp. If the target * interp is then deleted, the bytecode structure would be * referring to deallocated objects. */ if (Tcl_IsSafe(riPtr->interp) && riPtr->handlerPtr == NULL) { Tcl_SetResult(riPtr->interp, "permission denied: " "a handler procedure must be defined for use in " "a safe interp", TCL_STATIC); result = TCL_ERROR; } if (result == TCL_OK) { if (objc == 1) objPtr = objv[0]; else { objPtr = Tcl_ConcatObj(objc, objv); } if (riPtr->handlerPtr != NULL) { /* add the dde request data to the handler proc list */ /* *result = Tcl_ListObjReplace(sendInterp, objPtr, 0, 0, 1, * &(riPtr->handlerPtr)); */ Tcl_Obj *cmdPtr = Tcl_DuplicateObj(riPtr->handlerPtr); result = Tcl_ListObjAppendElement(sendInterp, cmdPtr, objPtr); if (result == TCL_OK) { objPtr = cmdPtr; } } } if (result == TCL_OK) { Tcl_IncrRefCount(objPtr); result = Tcl_EvalObjEx(sendInterp, objPtr, TCL_EVAL_GLOBAL); Tcl_DecrRefCount(objPtr); } if (interp != sendInterp) { if (result == TCL_ERROR) { /* * An error occurred, so transfer error information from * the destination interpreter back to our interpreter. */ Tcl_ResetResult(interp); objPtr = Tcl_GetVar2Ex(sendInterp, "errorInfo", NULL, TCL_GLOBAL_ONLY); if (objPtr) { string = Tcl_GetStringFromObj(objPtr, &length); Tcl_AddObjErrorInfo(interp, string, length); } objPtr = Tcl_GetVar2Ex(sendInterp, "errorCode", NULL, TCL_GLOBAL_ONLY); if (objPtr) { Tcl_SetObjErrorCode(interp, objPtr); } } Tcl_SetObjResult(interp, Tcl_GetObjResult(sendInterp)); } Tcl_Release((ClientData) riPtr); Tcl_Release((ClientData) sendInterp); } else { /* * This is a non-local request. Send the script to the server and * poll it for a result. */ if (MakeDdeConnection(interp, serviceName, &hConv) != TCL_OK) { invalidServerResponse: Tcl_SetObjResult(interp, Tcl_NewStringObj("invalid data returned from server", -1)); result = TCL_ERROR; goto cleanup; } objPtr = Tcl_ConcatObj(objc, objv); string = Tcl_GetStringFromObj(objPtr, &length); ddeItemData = DdeCreateDataHandle(ddeInstance, (BYTE *) string, (DWORD) length+1, 0, 0, CF_TEXT, 0); if (flags & DDE_FLAG_ASYNC) { ddeData = DdeClientTransaction((LPBYTE) ddeItemData, 0xFFFFFFFF, hConv, 0, CF_TEXT, XTYP_EXECUTE, TIMEOUT_ASYNC, &ddeResult); DdeAbandonTransaction(ddeInstance, hConv, ddeResult); } else { ddeData = DdeClientTransaction((LPBYTE) ddeItemData, 0xFFFFFFFF, hConv, 0, CF_TEXT, XTYP_EXECUTE, 30000, NULL); if (ddeData != 0) { ddeCookie = DdeCreateStringHandle(ddeInstance, TCL_DDE_EXECUTE_RESULT, CP_WINANSI); ddeData = DdeClientTransaction(NULL, 0, hConv, ddeCookie, CF_TEXT, XTYP_REQUEST, 30000, NULL); } } Tcl_DecrRefCount(objPtr); if (ddeData == 0) { SetDdeError(interp); result = TCL_ERROR; } if (!(flags & DDE_FLAG_ASYNC)) { Tcl_Obj *resultPtr; /* * The return handle has a two or four element list in it. The * first element is the return code (TCL_OK, TCL_ERROR, etc.). * The second is the result of the script. If the return code * is TCL_ERROR, then the third element is the value of the * variable "errorCode", and the fourth is the value of the * variable "errorInfo". */ resultPtr = Tcl_NewObj(); length = DdeGetData(ddeData, NULL, 0, 0); Tcl_SetObjLength(resultPtr, length); string = Tcl_GetString(resultPtr); DdeGetData(ddeData, (BYTE *) string, (DWORD) length, 0); Tcl_SetObjLength(resultPtr, (int) strlen(string)); if (Tcl_ListObjIndex(NULL, resultPtr, 0, &objPtr) != TCL_OK) { Tcl_DecrRefCount(resultPtr); goto invalidServerResponse; } if (Tcl_GetIntFromObj(NULL, objPtr, &result) != TCL_OK) { Tcl_DecrRefCount(resultPtr); goto invalidServerResponse; } if (result == TCL_ERROR) { Tcl_ResetResult(interp); if (Tcl_ListObjIndex(NULL, resultPtr, 3, &objPtr) != TCL_OK) { Tcl_DecrRefCount(resultPtr); goto invalidServerResponse; } length = -1; string = Tcl_GetStringFromObj(objPtr, &length); Tcl_AddObjErrorInfo(interp, string, length); Tcl_ListObjIndex(NULL, resultPtr, 2, &objPtr); Tcl_SetObjErrorCode(interp, objPtr); } if (Tcl_ListObjIndex(NULL, resultPtr, 1, &objPtr) != TCL_OK) { Tcl_DecrRefCount(resultPtr); goto invalidServerResponse; } Tcl_SetObjResult(interp, objPtr); Tcl_DecrRefCount(resultPtr); } } } } cleanup: if (ddeCookie != NULL) { DdeFreeStringHandle(ddeInstance, ddeCookie); } if (ddeItem != NULL) { DdeFreeStringHandle(ddeInstance, ddeItem); } if (ddeItemData != NULL) { DdeFreeDataHandle(ddeItemData); } if (ddeData != NULL) { DdeFreeDataHandle(ddeData); } if (hConv != NULL) { DdeDisconnect(hConv); } return result; } /* * Local variables: * mode: c * indent-tabs-mode: t * tab-width: 8 * c-basic-offset: 4 * fill-column: 78 * End: */ tcl8.4.20/win/README0000644003604700454610000000576112052456744012404 0ustar dgp771divTcl 8.4 for Windows 1. Introduction --------------- This is the directory where you configure and compile the Windows version of Tcl. This directory also contains source files for Tcl that are specific to Microsoft Windows. The information in this file is maintained on the web at: http://www.tcl.tk/doc/howto/compile.html#win 2. Compiling Tcl ---------------- In order to compile Tcl for Windows, you need the following: Tcl 8.4 Source Distribution (plus any patches) and Visual C++ 6 or newer or Linux + MinGW-w64 [http://mingw-w64.sourceforge.net/] (win32 or win64) or Cygwin + MinGW-w64 [http://cygwin.com/install.html] (win32 or win64) or Darwin + MinGW-w64 [http://mingw-w64.sourceforge.net/] (win32 or win64) or Msys + MinGW-w64 [http://mingw-w64.sourceforge.net/] (win32 or win64) or Msys + MinGW [http://www.mingw.org/download.shtml] (win32 only) In practice, this release is built with Visual C++ 6.0 and the TEA Makefile. If you are building with Visual C++, in the "win" subdirectory of the source release, you will find "makefile.vc". This is the makefile for the Visual C++ compiler and uses the stock NMAKE tool. Detailed directions for using it, are in the comments of "makefile.vc". A quick example would be: C:\tcl_source\win\>nmake -f makefile.vc There is also a Developer Studio workspace and project file, too, if you would like to use them. If you are building with Linux, Cygwin or Msys, you can use the configure script that lives in the win subdirectory. The Linux/Cygwin/Msys based configure/build process works just like the UNIX one, so you will want to refer to ../unix/README for available configure options. If you want 64-bit executables (x86_64), you need to configure using the --enable-64bit option. Make sure that the x86_64-w64-mingw32 compiler is present. For Cygwin this compiler can be found in the "mingw64-x86_64-gcc-core" package, which can be installed through the normal Cygwin install process. If you only want 32-bit executables, the "mingw64-i686-gcc-core" package is what you need. For Linux, Darwin and Msys, you can download a suitable win32 or win64 compiler from [https://sourceforge.net/projects/mingw-w64/files/] Use the Makefile "install" target to install Tcl. It will install it according to the prefix options you provided in the correct directory structure. Note that in order to run tclsh84.exe, you must ensure that tcl84.dll and tclpip84.dll are on your path, in the system directory, or in the directory containing tclsh84.exe. Note: Tcl no longer provides support for Win32s. 3. Test suite ------------- This distribution contains an extensive test suite for Tcl. Some of the tests are timing dependent and will fail from time to time. If a test is failing consistently, please send us a bug report with as much detail as you can manage. Please use the online database at http://tcl.sourceforge.net/ In order to run the test suite, you build the "test" target using the appropriate makefile for your compiler. tcl8.4.20/win/tclWinInt.h0000644003604700454610000001547211737050675013612 0ustar dgp771div/* * tclWinInt.h -- * * Declarations of Windows-specific shared variables and procedures. * * Copyright (c) 1994-1996 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef _TCLWININT #define _TCLWININT #ifndef _TCLINT #include "tclInt.h" #endif #ifndef _TCLPORT #include "tclPort.h" #endif /* * The following specifies how much stack space TclpCheckStackSpace() * ensures is available. TclpCheckStackSpace() is called by Tcl_EvalObj() * to help avoid overflowing the stack in the case of infinite recursion. */ #define TCL_WIN_STACK_THRESHOLD 0x8000 #ifdef BUILD_tcl # undef TCL_STORAGE_CLASS # define TCL_STORAGE_CLASS DLLEXPORT #endif /* * Some versions of Borland C have a define for the OSVERSIONINFO for * Win32s and for NT, but not for Windows 95. * Define VER_PLATFORM_WIN32_CE for those without newer headers. */ #ifndef VER_PLATFORM_WIN32_WINDOWS #define VER_PLATFORM_WIN32_WINDOWS 1 #endif #ifndef VER_PLATFORM_WIN32_CE #define VER_PLATFORM_WIN32_CE 3 #endif /* * The following structure keeps track of whether we are using the * multi-byte or the wide-character interfaces to the operating system. * System calls should be made through the following function table. */ typedef union { WIN32_FIND_DATAA a; WIN32_FIND_DATAW w; } WIN32_FIND_DATAT; typedef struct TclWinProcs { int useWide; BOOL (WINAPI *buildCommDCBProc)(CONST TCHAR *, LPDCB); TCHAR *(WINAPI *charLowerProc)(TCHAR *); BOOL (WINAPI *copyFileProc)(CONST TCHAR *, CONST TCHAR *, BOOL); BOOL (WINAPI *createDirectoryProc)(CONST TCHAR *, LPSECURITY_ATTRIBUTES); HANDLE (WINAPI *createFileProc)(CONST TCHAR *, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE); BOOL (WINAPI *createProcessProc)(CONST TCHAR *, TCHAR *, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, CONST TCHAR *, LPSTARTUPINFOA, LPPROCESS_INFORMATION); BOOL (WINAPI *deleteFileProc)(CONST TCHAR *); HANDLE (WINAPI *findFirstFileProc)(CONST TCHAR *, WIN32_FIND_DATAT *); BOOL (WINAPI *findNextFileProc)(HANDLE, WIN32_FIND_DATAT *); BOOL (WINAPI *getComputerNameProc)(WCHAR *, LPDWORD); DWORD (WINAPI *getCurrentDirectoryProc)(DWORD, WCHAR *); DWORD (WINAPI *getFileAttributesProc)(CONST TCHAR *); DWORD (WINAPI *getFullPathNameProc)(CONST TCHAR *, DWORD nBufferLength, WCHAR *, TCHAR **); DWORD (WINAPI *getModuleFileNameProc)(HMODULE, WCHAR *, int); DWORD (WINAPI *getShortPathNameProc)(CONST TCHAR *, WCHAR *, DWORD); UINT (WINAPI *getTempFileNameProc)(CONST TCHAR *, CONST TCHAR *, UINT, WCHAR *); DWORD (WINAPI *getTempPathProc)(DWORD, WCHAR *); BOOL (WINAPI *getVolumeInformationProc)(CONST TCHAR *, WCHAR *, DWORD, LPDWORD, LPDWORD, LPDWORD, WCHAR *, DWORD); HINSTANCE (WINAPI *loadLibraryExProc)(const TCHAR *, HANDLE, DWORD); TCHAR (WINAPI *lstrcpyProc)(WCHAR *, CONST TCHAR *); BOOL (WINAPI *moveFileProc)(CONST TCHAR *, CONST TCHAR *); BOOL (WINAPI *removeDirectoryProc)(CONST TCHAR *); DWORD (WINAPI *searchPathProc)(CONST TCHAR *, CONST TCHAR *, CONST TCHAR *, DWORD, WCHAR *, TCHAR **); BOOL (WINAPI *setCurrentDirectoryProc)(CONST TCHAR *); BOOL (WINAPI *setFileAttributesProc)(CONST TCHAR *, DWORD); /* * These two function pointers will only be set when * Tcl_FindExecutable is called. If you don't ever call that * function, the application will crash whenever WinTcl tries to call * functions through these null pointers. That is not a bug in Tcl * -- Tcl_FindExecutable is obligatory in recent Tcl releases. */ BOOL (WINAPI *getFileAttributesExProc)(CONST TCHAR *, GET_FILEEX_INFO_LEVELS, LPVOID); BOOL (WINAPI *createHardLinkProc)(CONST TCHAR*, CONST TCHAR*, LPSECURITY_ATTRIBUTES); INT (__cdecl *utimeProc)(CONST TCHAR*, struct _utimbuf *); /* These two are also NULL at start; see comment above */ HANDLE (WINAPI *findFirstFileExProc)(CONST TCHAR*, UINT, LPVOID, UINT, LPVOID, DWORD); BOOL (WINAPI *getVolumeNameForVMPProc)(CONST TCHAR*, TCHAR*, DWORD); DWORD (WINAPI *getLongPathNameProc)(CONST TCHAR*, TCHAR*, DWORD); /* * These six are for the security sdk to get correct file * permissions on NT, 2000, XP, etc. On 95,98,ME they are * always null. */ BOOL (WINAPI *getFileSecurityProc)(LPCTSTR lpFileName, SECURITY_INFORMATION RequestedInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD nLength, LPDWORD lpnLengthNeeded); BOOL (WINAPI *impersonateSelfProc) (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel); BOOL (WINAPI *openThreadTokenProc) (HANDLE ThreadHandle, DWORD DesiredAccess, BOOL OpenAsSelf, PHANDLE TokenHandle); BOOL (WINAPI *revertToSelfProc) (void); VOID (WINAPI *mapGenericMaskProc) (PDWORD AccessMask, PGENERIC_MAPPING GenericMapping); BOOL (WINAPI *accessCheckProc)(PSECURITY_DESCRIPTOR pSecurityDescriptor, HANDLE ClientToken, DWORD DesiredAccess, PGENERIC_MAPPING GenericMapping, PPRIVILEGE_SET PrivilegeSet, LPDWORD PrivilegeSetLength, LPDWORD GrantedAccess, LPBOOL AccessStatus); /* * Unicode console support. WriteConsole and ReadConsole */ BOOL (WINAPI *readConsoleProc)(HANDLE hConsoleInput, LPVOID lpBuffer, DWORD nNumberOfCharsToRead, LPDWORD lpNumberOfCharsRead, LPVOID lpReserved); BOOL (WINAPI *writeConsoleProc)(HANDLE hConsoleOutput, const VOID* lpBuffer, DWORD nNumberOfCharsToWrite, LPDWORD lpNumberOfCharsWritten, LPVOID lpReserved); } TclWinProcs; EXTERN TclWinProcs *tclWinProcs; /* * Declarations of functions that are not accessible by way of the * stubs table. */ EXTERN void TclWinEncodingsCleanup(); EXTERN void TclWinResetInterfaceEncodings(); EXTERN void TclWinInit(HINSTANCE hInst); EXTERN int TclWinSymLinkCopyDirectory(CONST TCHAR* LinkOriginal, CONST TCHAR* LinkCopy); EXTERN int TclWinSymLinkDelete(CONST TCHAR* LinkOriginal, int linkOnly); EXTERN char TclWinDriveLetterForVolMountPoint(CONST WCHAR *mountPoint); #if defined(TCL_THREADS) && defined(USE_THREAD_ALLOC) EXTERN void TclWinFreeAllocCache(void); EXTERN void TclFreeAllocCache(void *); EXTERN Tcl_Mutex *TclpNewAllocMutex(void); EXTERN void *TclpGetAllocCache(void); EXTERN void TclpSetAllocCache(void *); #endif /* TCL_THREADS */ /* Needed by tclWinFile.c and tclWinFCmd.c */ #ifndef FILE_ATTRIBUTE_REPARSE_POINT #define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400 #endif #include "tclIntPlatDecls.h" # undef TCL_STORAGE_CLASS # define TCL_STORAGE_CLASS DLLIMPORT #endif /* _TCLWININT */ tcl8.4.20/win/tclWinMtherr.c0000644003604700454610000000224111737050675014302 0ustar dgp771div/* * tclWinMtherr.c -- * * This function provides a default implementation of the * _matherr function for Borland C++. * * Copyright (c) 1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclWinInt.h" #include #ifndef __MINGW32__ /* *---------------------------------------------------------------------- * * _matherr -- * * This procedure is invoked by Borland C++ when certain * errors occur in mathematical functions. This procedure * replaces the default implementation which generates pop-up * warnings. * * Results: * Returns 1 to indicate that we've handled the error * locally. * * Side effects: * Sets errno based on what's in xPtr. * *---------------------------------------------------------------------- */ int _matherr(xPtr) struct exception *xPtr; /* Describes error that occurred. */ { if ((xPtr->type == DOMAIN) #ifdef __BORLANDC__ || (xPtr->type == TLOSS) #endif || (xPtr->type == SING)) { errno = EDOM; } else { errno = ERANGE; } return 1; } #endif /* !__MINGW__ */ tcl8.4.20/win/tclWinSerial.c0000644003604700454610000017111411737050675014266 0ustar dgp771div/* * tclWinSerial.c -- * * This file implements the Windows-specific serial port functions, * and the "serial" channel driver. * * Copyright (c) 1999 by Scriptics Corp. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * Serial functionality implemented by Rolf.Schroedter@dlr.de */ #include "tclWinInt.h" #include #include #include /* * The following variable is used to tell whether this module has been * initialized. */ static int initialized = 0; /* * The serialMutex locks around access to the initialized variable, and it is * used to protect background threads from being terminated while they are * using APIs that hold locks. */ TCL_DECLARE_MUTEX(serialMutex) /* * Bit masks used in the flags field of the SerialInfo structure below. */ #define SERIAL_PENDING (1<<0) /* Message is pending in the queue. */ #define SERIAL_ASYNC (1<<1) /* Channel is non-blocking. */ /* * Bit masks used in the sharedFlags field of the SerialInfo structure below. */ #define SERIAL_EOF (1<<2) /* Serial has reached EOF. */ #define SERIAL_ERROR (1<<4) /* * Default time to block between checking status on the serial port. */ #define SERIAL_DEFAULT_BLOCKTIME 10 /* 10 msec */ /* * Define Win32 read/write error masks returned by ClearCommError() */ #define SERIAL_READ_ERRORS ( CE_RXOVER | CE_OVERRUN | CE_RXPARITY \ | CE_FRAME | CE_BREAK ) #define SERIAL_WRITE_ERRORS ( CE_TXFULL | CE_PTO ) /* * This structure describes per-instance data for a serial based channel. */ typedef struct SerialInfo { HANDLE handle; struct SerialInfo *nextPtr; /* Pointer to next registered serial. */ Tcl_Channel channel; /* Pointer to channel structure. */ int validMask; /* OR'ed combination of TCL_READABLE, * TCL_WRITABLE, or TCL_EXCEPTION: indicates * which operations are valid on the file. */ int watchMask; /* OR'ed combination of TCL_READABLE, * TCL_WRITABLE, or TCL_EXCEPTION: indicates * which events should be reported. */ int flags; /* State flags, see above for a list. */ int readable; /* flag that the channel is readable */ int writable; /* flag that the channel is writable */ int blockTime; /* max. blocktime in msec */ unsigned int lastEventTime; /* Time in milliseconds since last readable event */ /* Next readable event only after blockTime */ DWORD error; /* pending error code returned by * ClearCommError() */ DWORD lastError; /* last error code, can be fetched with * fconfigure chan -lasterror */ DWORD sysBufRead; /* Win32 system buffer size for read ops, * default=4096 */ DWORD sysBufWrite; /* Win32 system buffer size for write ops, * default=4096 */ Tcl_ThreadId threadId; /* Thread to which events should be reported. * This value is used by the reader/writer * threads. */ OVERLAPPED osRead; /* OVERLAPPED structure for read operations */ OVERLAPPED osWrite; /* OVERLAPPED structure for write operations */ HANDLE writeThread; /* Handle to writer thread. */ CRITICAL_SECTION csWrite; /* Writer thread synchronisation */ HANDLE evWritable; /* Manual-reset event to signal when the * writer thread has finished waiting for * the current buffer to be written. */ HANDLE evStartWriter; /* Auto-reset event used by the main thread to * signal when the writer thread should attempt * to write to the serial. */ HANDLE evStopWriter; /* Auto-reset event used by the main thread to * signal when the writer thread should close. */ DWORD writeError; /* An error caused by the last background * write. Set to 0 if no error has been * detected. This word is shared with the * writer thread so access must be * synchronized with the evWritable object. */ char *writeBuf; /* Current background output buffer. * Access is synchronized with the evWritable * object. */ int writeBufLen; /* Size of write buffer. Access is * synchronized with the evWritable * object. */ int toWrite; /* Current amount to be written. Access is * synchronized with the evWritable object. */ int writeQueue; /* Number of bytes pending in output queue. * Offset to DCB.cbInQue. * Used to query [fconfigure -queue] */ } SerialInfo; typedef struct ThreadSpecificData { /* * The following pointer refers to the head of the list of serials * that are being watched for file events. */ SerialInfo *firstSerialPtr; } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; /* * The following structure is what is added to the Tcl event queue when * serial events are generated. */ typedef struct SerialEvent { Tcl_Event header; /* Information that is standard for * all events. */ SerialInfo *infoPtr; /* Pointer to serial info structure. Note * that we still have to verify that the * serial exists before dereferencing this * pointer. */ } SerialEvent; /* * We don't use timeouts. */ static COMMTIMEOUTS no_timeout = { 0, /* ReadIntervalTimeout */ 0, /* ReadTotalTimeoutMultiplier */ 0, /* ReadTotalTimeoutConstant */ 0, /* WriteTotalTimeoutMultiplier */ 0, /* WriteTotalTimeoutConstant */ }; /* * Declarations for functions used only in this file. */ static int SerialBlockProc(ClientData instanceData, int mode); static void SerialCheckProc(ClientData clientData, int flags); static int SerialCloseProc(ClientData instanceData, Tcl_Interp *interp); static int SerialEventProc(Tcl_Event *evPtr, int flags); static void SerialExitHandler(ClientData clientData); static int SerialGetHandleProc(ClientData instanceData, int direction, ClientData *handlePtr); static ThreadSpecificData *SerialInit(void); static int SerialInputProc(ClientData instanceData, char *buf, int toRead, int *errorCode); static int SerialOutputProc(ClientData instanceData, CONST char *buf, int toWrite, int *errorCode); static void SerialSetupProc(ClientData clientData, int flags); static void SerialWatchProc(ClientData instanceData, int mask); static void ProcExitHandler(ClientData clientData); static int SerialGetOptionProc _ANSI_ARGS_((ClientData instanceData, Tcl_Interp *interp, CONST char *optionName, Tcl_DString *dsPtr)); static int SerialSetOptionProc _ANSI_ARGS_((ClientData instanceData, Tcl_Interp *interp, CONST char *optionName, CONST char *value)); static DWORD WINAPI SerialWriterThread(LPVOID arg); static void SerialThreadActionProc _ANSI_ARGS_ (( ClientData instanceData, int action)); /* * This structure describes the channel type structure for command serial * based IO. */ static Tcl_ChannelType serialChannelType = { "serial", /* Type name. */ TCL_CHANNEL_VERSION_4, /* v4 channel */ SerialCloseProc, /* Close proc. */ SerialInputProc, /* Input proc. */ SerialOutputProc, /* Output proc. */ NULL, /* Seek proc. */ SerialSetOptionProc, /* Set option proc. */ SerialGetOptionProc, /* Get option proc. */ SerialWatchProc, /* Set up notifier to watch the channel. */ SerialGetHandleProc, /* Get an OS handle from channel. */ NULL, /* close2proc. */ SerialBlockProc, /* Set blocking or non-blocking mode.*/ NULL, /* flush proc. */ NULL, /* handler proc. */ NULL, /* wide seek proc */ SerialThreadActionProc, /* thread action proc */ }; /* *---------------------------------------------------------------------- * * SerialInit -- * * This function initializes the static variables for this file. * * Results: * None. * * Side effects: * Creates a new event source. * *---------------------------------------------------------------------- */ static ThreadSpecificData * SerialInit() { ThreadSpecificData *tsdPtr; /* * Check the initialized flag first, then check it again in the mutex. * This is a speed enhancement. */ if (!initialized) { Tcl_MutexLock(&serialMutex); if (!initialized) { initialized = 1; Tcl_CreateExitHandler(ProcExitHandler, NULL); } Tcl_MutexUnlock(&serialMutex); } tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); if (tsdPtr == NULL) { tsdPtr = TCL_TSD_INIT(&dataKey); tsdPtr->firstSerialPtr = NULL; Tcl_CreateEventSource(SerialSetupProc, SerialCheckProc, NULL); Tcl_CreateThreadExitHandler(SerialExitHandler, NULL); } return tsdPtr; } /* *---------------------------------------------------------------------- * * SerialExitHandler -- * * This function is called to cleanup the serial module before * Tcl is unloaded. * * Results: * None. * * Side effects: * Removes the serial event source. * *---------------------------------------------------------------------- */ static void SerialExitHandler( ClientData clientData) /* Old window proc */ { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); SerialInfo *infoPtr; /* * Clear all eventually pending output. * Otherwise Tcl's exit could totally block, * because it performs a blocking flush on all open channels. * Note that serial write operations may be blocked due to handshake. */ for (infoPtr = tsdPtr->firstSerialPtr; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { PurgeComm(infoPtr->handle, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR); } Tcl_DeleteEventSource(SerialSetupProc, SerialCheckProc, NULL); } /* *---------------------------------------------------------------------- * * ProcExitHandler -- * * This function is called to cleanup the process list before * Tcl is unloaded. * * Results: * None. * * Side effects: * Resets the process list. * *---------------------------------------------------------------------- */ static void ProcExitHandler( ClientData clientData) /* Old window proc */ { Tcl_MutexLock(&serialMutex); initialized = 0; Tcl_MutexUnlock(&serialMutex); } /* *---------------------------------------------------------------------- * * SerialBlockTime -- * * Wrapper to set Tcl's block time in msec * * Results: * None. *---------------------------------------------------------------------- */ static void SerialBlockTime( int msec) /* milli-seconds */ { Tcl_Time blockTime; blockTime.sec = msec / 1000; blockTime.usec = (msec % 1000) * 1000; Tcl_SetMaxBlockTime(&blockTime); } /* *---------------------------------------------------------------------- * * SerialGetMilliseconds -- * * Get current time in milliseconds, * Don't care about integer overruns * * Results: * None. *---------------------------------------------------------------------- */ static unsigned int SerialGetMilliseconds( void) { Tcl_Time time; TclpGetTime(&time); return (time.sec * 1000 + time.usec / 1000); } /* *---------------------------------------------------------------------- * * SerialSetupProc -- * * This procedure is invoked before Tcl_DoOneEvent blocks waiting * for an event. * * Results: * None. * * Side effects: * Adjusts the block time if needed. * *---------------------------------------------------------------------- */ void SerialSetupProc( ClientData data, /* Not used. */ int flags) /* Event flags as passed to Tcl_DoOneEvent. */ { SerialInfo *infoPtr; int block = 1; int msec = INT_MAX; /* min. found block time */ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (!(flags & TCL_FILE_EVENTS)) { return; } /* * Look to see if any events handlers installed. If they are, do not block. */ for (infoPtr = tsdPtr->firstSerialPtr; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { if (infoPtr->watchMask & TCL_WRITABLE) { if (WaitForSingleObject(infoPtr->evWritable, 0) != WAIT_TIMEOUT) { block = 0; msec = min( msec, infoPtr->blockTime ); } } if( infoPtr->watchMask & TCL_READABLE ) { block = 0; msec = min( msec, infoPtr->blockTime ); } } if (!block) { SerialBlockTime(msec); } } /* *---------------------------------------------------------------------- * * SerialCheckProc -- * * This procedure is called by Tcl_DoOneEvent to check the serial * event source for events. * * Results: * None. * * Side effects: * May queue an event. * *---------------------------------------------------------------------- */ static void SerialCheckProc( ClientData data, /* Not used. */ int flags) /* Event flags as passed to Tcl_DoOneEvent. */ { SerialInfo *infoPtr; SerialEvent *evPtr; int needEvent; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); COMSTAT cStat; unsigned int time; if (!(flags & TCL_FILE_EVENTS)) { return; } /* * Queue events for any ready serials that don't already have events * queued. */ for (infoPtr = tsdPtr->firstSerialPtr; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { if (infoPtr->flags & SERIAL_PENDING) { continue; } needEvent = 0; /* * If WRITABLE watch mask is set * look for infoPtr->evWritable object */ if (infoPtr->watchMask & TCL_WRITABLE) { if (WaitForSingleObject(infoPtr->evWritable, 0) != WAIT_TIMEOUT) { infoPtr->writable = 1; needEvent = 1; } } /* * If READABLE watch mask is set * call ClearCommError to poll cbInQue * Window errors are ignored here */ if( infoPtr->watchMask & TCL_READABLE ) { if( ClearCommError( infoPtr->handle, &infoPtr->error, &cStat ) ) { /* * Look for characters already pending in windows queue. * If they are, poll. */ if( infoPtr->watchMask & TCL_READABLE ) { /* * force fileevent after serial read error */ if( (cStat.cbInQue > 0) || (infoPtr->error & SERIAL_READ_ERRORS) ) { infoPtr->readable = 1; time = SerialGetMilliseconds(); if ((unsigned int) (time - infoPtr->lastEventTime) >= (unsigned int) infoPtr->blockTime) { needEvent = 1; infoPtr->lastEventTime = time; } } } } } /* * Queue an event if the serial is signaled for reading or writing. */ if (needEvent) { infoPtr->flags |= SERIAL_PENDING; evPtr = (SerialEvent *) ckalloc(sizeof(SerialEvent)); evPtr->header.proc = SerialEventProc; evPtr->infoPtr = infoPtr; Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL); } } } /* *---------------------------------------------------------------------- * * SerialBlockProc -- * * Set blocking or non-blocking mode on channel. * * Results: * 0 if successful, errno when failed. * * Side effects: * Sets the device into blocking or non-blocking mode. * *---------------------------------------------------------------------- */ static int SerialBlockProc( ClientData instanceData, /* Instance data for channel. */ int mode) /* TCL_MODE_BLOCKING or * TCL_MODE_NONBLOCKING. */ { int errorCode = 0; SerialInfo *infoPtr = (SerialInfo *) instanceData; /* * Only serial READ can be switched between blocking & nonblocking * using COMMTIMEOUTS. * Serial write emulates blocking & nonblocking by the SerialWriterThread. */ if (mode == TCL_MODE_NONBLOCKING) { infoPtr->flags |= SERIAL_ASYNC; } else { infoPtr->flags &= ~(SERIAL_ASYNC); } return errorCode; } /* *---------------------------------------------------------------------- * * SerialCloseProc -- * * Closes a serial based IO channel. * * Results: * 0 on success, errno otherwise. * * Side effects: * Closes the physical channel. * *---------------------------------------------------------------------- */ static int SerialCloseProc( ClientData instanceData, /* Pointer to SerialInfo structure. */ Tcl_Interp *interp) /* For error reporting. */ { SerialInfo *serialPtr = (SerialInfo *) instanceData; int errorCode, result = 0; SerialInfo *infoPtr, **nextPtrPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); DWORD exitCode; errorCode = 0; if (serialPtr->validMask & TCL_READABLE) { PurgeComm(serialPtr->handle, PURGE_RXABORT | PURGE_RXCLEAR); CloseHandle(serialPtr->osRead.hEvent); } serialPtr->validMask &= ~TCL_READABLE; if (serialPtr->validMask & TCL_WRITABLE) { /* * Generally we cannot wait for a pending write operation * because it may hang due to handshake * WaitForSingleObject(serialPtr->evWritable, INFINITE); */ /* * The thread may have already closed on it's own. Check it's * exit code. */ GetExitCodeThread(serialPtr->writeThread, &exitCode); if (exitCode == STILL_ACTIVE) { /* * Set the stop event so that if the writer thread is * blocked in SerialWriterThread on WaitForMultipleEvents, it * will exit cleanly. */ SetEvent(serialPtr->evStopWriter); /* * Wait at most 20 milliseconds for the writer thread to * close. */ if (WaitForSingleObject(serialPtr->writeThread, 20) == WAIT_TIMEOUT) { /* * Forcibly terminate the background thread as a last * resort. Note that we need to guard against * terminating the thread while it is in the middle of * Tcl_ThreadAlert because it won't be able to release * the notifier lock. */ Tcl_MutexLock(&serialMutex); /* BUG: this leaks memory */ TerminateThread(serialPtr->writeThread, 0); Tcl_MutexUnlock(&serialMutex); } } CloseHandle(serialPtr->writeThread); CloseHandle(serialPtr->osWrite.hEvent); CloseHandle(serialPtr->evWritable); CloseHandle(serialPtr->evStartWriter); CloseHandle(serialPtr->evStopWriter); serialPtr->writeThread = NULL; PurgeComm(serialPtr->handle, PURGE_TXABORT | PURGE_TXCLEAR); } serialPtr->validMask &= ~TCL_WRITABLE; DeleteCriticalSection(&serialPtr->csWrite); /* * Don't close the Win32 handle if the handle is a standard channel * during the thread exit process. Otherwise, one thread may kill * the stdio of another. */ if (!TclInThreadExit() || ((GetStdHandle(STD_INPUT_HANDLE) != serialPtr->handle) && (GetStdHandle(STD_OUTPUT_HANDLE) != serialPtr->handle) && (GetStdHandle(STD_ERROR_HANDLE) != serialPtr->handle))) { if (CloseHandle(serialPtr->handle) == FALSE) { TclWinConvertError(GetLastError()); errorCode = errno; } } serialPtr->watchMask &= serialPtr->validMask; /* * Remove the file from the list of watched files. */ for (nextPtrPtr = &(tsdPtr->firstSerialPtr), infoPtr = *nextPtrPtr; infoPtr != NULL; nextPtrPtr = &infoPtr->nextPtr, infoPtr = *nextPtrPtr) { if (infoPtr == (SerialInfo *)serialPtr) { *nextPtrPtr = infoPtr->nextPtr; break; } } /* * Wrap the error file into a channel and give it to the cleanup * routine. */ if (serialPtr->writeBuf != NULL) { ckfree(serialPtr->writeBuf); serialPtr->writeBuf = NULL; } ckfree((char*) serialPtr); if (errorCode == 0) { return result; } return errorCode; } /* *---------------------------------------------------------------------- * * blockingRead -- * * Perform a blocking read into the buffer given. Returns * count of how many bytes were actually read, and an error indication. * * Results: * A count of how many bytes were read is returned and an error * indication is returned. * * Side effects: * Reads input from the actual channel. * *---------------------------------------------------------------------- */ static int blockingRead( SerialInfo *infoPtr, /* Serial info structure */ LPVOID buf, /* The input buffer pointer */ DWORD bufSize, /* The number of bytes to read */ LPDWORD lpRead, /* Returns number of bytes read */ LPOVERLAPPED osPtr ) /* OVERLAPPED structure */ { /* * Perform overlapped blocking read. * 1. Reset the overlapped event * 2. Start overlapped read operation * 3. Wait for completion */ /* * Set Offset to ZERO, otherwise NT4.0 may report an error. */ osPtr->Offset = osPtr->OffsetHigh = 0; ResetEvent(osPtr->hEvent); if (! ReadFile(infoPtr->handle, buf, bufSize, lpRead, osPtr) ) { if (GetLastError() != ERROR_IO_PENDING) { /* ReadFile failed, but it isn't delayed. Report error. */ return FALSE; } else { /* Read is pending, wait for completion, timeout ? */ if (! GetOverlappedResult(infoPtr->handle, osPtr, lpRead, TRUE) ) { return FALSE; } } } else { /* ReadFile completed immediately. */ } return TRUE; } /* *---------------------------------------------------------------------- * * blockingWrite -- * * Perform a blocking write from the buffer given. Returns * count of how many bytes were actually written, and an error indication. * * Results: * A count of how many bytes were written is returned and an error * indication is returned. * * Side effects: * Writes output to the actual channel. * *---------------------------------------------------------------------- */ static int blockingWrite( SerialInfo *infoPtr, /* Serial info structure */ LPVOID buf, /* The output buffer pointer */ DWORD bufSize, /* The number of bytes to write */ LPDWORD lpWritten, /* Returns number of bytes written */ LPOVERLAPPED osPtr ) /* OVERLAPPED structure */ { int result; /* * Perform overlapped blocking write. * 1. Reset the overlapped event * 2. Remove these bytes from the output queue counter * 3. Start overlapped write operation * 3. Remove these bytes from the output queue counter * 4. Wait for completion * 5. Adjust the output queue counter */ ResetEvent(osPtr->hEvent); EnterCriticalSection(&infoPtr->csWrite); infoPtr->writeQueue -= bufSize; /* * Set Offset to ZERO, otherwise NT4.0 may report an error */ osPtr->Offset = osPtr->OffsetHigh = 0; result = WriteFile(infoPtr->handle, buf, bufSize, lpWritten, osPtr); LeaveCriticalSection(&infoPtr->csWrite); if (result == FALSE ) { int err = GetLastError(); switch (err) { case ERROR_IO_PENDING: /* Write is pending, wait for completion */ if (! GetOverlappedResult(infoPtr->handle, osPtr, lpWritten, TRUE) ) { return FALSE; } break; case ERROR_COUNTER_TIMEOUT: /* Write timeout handled in SerialOutputProc */ break; default: /* WriteFile failed, but it isn't delayed. Report error */ return FALSE; } } else { /* WriteFile completed immediately. */ } EnterCriticalSection(&infoPtr->csWrite); infoPtr->writeQueue += (*lpWritten - bufSize); LeaveCriticalSection(&infoPtr->csWrite); return TRUE; } /* *---------------------------------------------------------------------- * * SerialInputProc -- * * Reads input from the IO channel into the buffer given. Returns * count of how many bytes were actually read, and an error indication. * * Results: * A count of how many bytes were read is returned and an error * indication is returned in an output argument. * * Side effects: * Reads input from the actual channel. * *---------------------------------------------------------------------- */ static int SerialInputProc( ClientData instanceData, /* Serial state. */ char *buf, /* Where to store data read. */ int bufSize, /* How much space is available * in the buffer? */ int *errorCode) /* Where to store error code. */ { SerialInfo *infoPtr = (SerialInfo *) instanceData; DWORD bytesRead = 0; COMSTAT cStat; *errorCode = 0; /* * Check if there is a CommError pending from SerialCheckProc */ if( infoPtr->error & SERIAL_READ_ERRORS ){ goto commError; } /* * Look for characters already pending in windows queue. * This is the mainly restored good old code from Tcl8.0 */ if( ClearCommError( infoPtr->handle, &infoPtr->error, &cStat ) ) { /* * Check for errors here, but not in the evSetup/Check procedures */ if( infoPtr->error & SERIAL_READ_ERRORS ) { goto commError; } if( infoPtr->flags & SERIAL_ASYNC ) { /* * NON_BLOCKING mode: * Avoid blocking by reading more bytes than available * in input buffer */ if( cStat.cbInQue > 0 ) { if( (DWORD) bufSize > cStat.cbInQue ) { bufSize = cStat.cbInQue; } } else { errno = *errorCode = EAGAIN; return -1; } } else { /* * BLOCKING mode: * Tcl trys to read a full buffer of 4 kBytes here */ if( cStat.cbInQue > 0 ) { if( (DWORD) bufSize > cStat.cbInQue ) { bufSize = cStat.cbInQue; } } else { bufSize = 1; } } } if( bufSize == 0 ) { return bytesRead = 0; } /* * Perform blocking read. Doesn't block in non-blocking mode, * because we checked the number of available bytes. */ if (blockingRead(infoPtr, (LPVOID) buf, (DWORD) bufSize, &bytesRead, &infoPtr->osRead) == FALSE) { goto error; } return bytesRead; error: TclWinConvertError(GetLastError()); *errorCode = errno; return -1; commError: infoPtr->lastError = infoPtr->error; /* save last error code */ infoPtr->error = 0; /* reset error code */ *errorCode = EIO; /* to return read-error only once */ return -1; } /* *---------------------------------------------------------------------- * * SerialOutputProc -- * * Writes the given output on the IO channel. Returns count of how * many characters were actually written, and an error indication. * * Results: * A count of how many characters were written is returned and an * error indication is returned in an output argument. * * Side effects: * Writes output on the actual channel. * *---------------------------------------------------------------------- */ static int SerialOutputProc( ClientData instanceData, /* Serial state. */ CONST char *buf, /* The data buffer. */ int toWrite, /* How many bytes to write? */ int *errorCode) /* Where to store error code. */ { SerialInfo *infoPtr = (SerialInfo *) instanceData; DWORD bytesWritten, timeout; *errorCode = 0; /* * At EXIT Tcl trys to flush all open channels in blocking mode. * We avoid blocking output after ExitProc or CloseHandler(chan) * has been called by checking the corrresponding variables. */ if( ! initialized || TclInExit() ) { return toWrite; } /* * Check if there is a CommError pending from SerialCheckProc */ if( infoPtr->error & SERIAL_WRITE_ERRORS ){ infoPtr->lastError = infoPtr->error; /* save last error code */ infoPtr->error = 0; /* reset error code */ errno = EIO; goto error; } timeout = (infoPtr->flags & SERIAL_ASYNC) ? 0 : INFINITE; if (WaitForSingleObject(infoPtr->evWritable, timeout) == WAIT_TIMEOUT) { /* * The writer thread is blocked waiting for a write to complete * and the channel is in non-blocking mode. */ errno = EWOULDBLOCK; goto error1; } /* * Check for a background error on the last write. */ if (infoPtr->writeError) { TclWinConvertError(infoPtr->writeError); infoPtr->writeError = 0; goto error1; } /* * Remember the number of bytes in output queue */ EnterCriticalSection(&infoPtr->csWrite); infoPtr->writeQueue += toWrite; LeaveCriticalSection(&infoPtr->csWrite); if (infoPtr->flags & SERIAL_ASYNC) { /* * The serial is non-blocking, so copy the data into the output * buffer and restart the writer thread. */ if (toWrite > infoPtr->writeBufLen) { /* * Reallocate the buffer to be large enough to hold the data. */ if (infoPtr->writeBuf) { ckfree(infoPtr->writeBuf); } infoPtr->writeBufLen = toWrite; infoPtr->writeBuf = ckalloc((unsigned int) toWrite); } memcpy(infoPtr->writeBuf, buf, (size_t) toWrite); infoPtr->toWrite = toWrite; ResetEvent(infoPtr->evWritable); SetEvent(infoPtr->evStartWriter); bytesWritten = (DWORD) toWrite; } else { /* * In the blocking case, just try to write the buffer directly. * This avoids an unnecessary copy. */ if (! blockingWrite(infoPtr, (LPVOID) buf, (DWORD) toWrite, &bytesWritten, &infoPtr->osWrite) ) { goto writeError; } if (bytesWritten != (DWORD) toWrite) { /* Write timeout */ infoPtr->lastError |= CE_PTO; errno = EIO; goto error; } } return (int) bytesWritten; writeError: TclWinConvertError(GetLastError()); error: /* * Reset the output queue counter on error during blocking output */ /* EnterCriticalSection(&infoPtr->csWrite); infoPtr->writeQueue = 0; LeaveCriticalSection(&infoPtr->csWrite); */ error1: *errorCode = errno; return -1; } /* *---------------------------------------------------------------------- * * SerialEventProc -- * * This function is invoked by Tcl_ServiceEvent when a file event * reaches the front of the event queue. This procedure invokes * Tcl_NotifyChannel on the serial. * * Results: * Returns 1 if the event was handled, meaning it should be removed * from the queue. Returns 0 if the event was not handled, meaning * it should stay on the queue. The only time the event isn't * handled is if the TCL_FILE_EVENTS flag bit isn't set. * * Side effects: * Whatever the notifier callback does. * *---------------------------------------------------------------------- */ static int SerialEventProc( Tcl_Event *evPtr, /* Event to service. */ int flags) /* Flags that indicate what events to * handle, such as TCL_FILE_EVENTS. */ { SerialEvent *serialEvPtr = (SerialEvent *)evPtr; SerialInfo *infoPtr; int mask; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (!(flags & TCL_FILE_EVENTS)) { return 0; } /* * Search through the list of watched serials for the one whose handle * matches the event. We do this rather than simply dereferencing * the handle in the event so that serials can be deleted while the * event is in the queue. */ for (infoPtr = tsdPtr->firstSerialPtr; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { if (serialEvPtr->infoPtr == infoPtr) { infoPtr->flags &= ~(SERIAL_PENDING); break; } } /* * Remove stale events. */ if (!infoPtr) { return 1; } /* * Check to see if the serial is readable. Note * that we can't tell if a serial is writable, so we always report it * as being writable unless we have detected EOF. */ mask = 0; if( infoPtr->watchMask & TCL_WRITABLE ) { if( infoPtr->writable ) { mask |= TCL_WRITABLE; infoPtr->writable = 0; } } if( infoPtr->watchMask & TCL_READABLE ) { if( infoPtr->readable ) { mask |= TCL_READABLE; infoPtr->readable = 0; } } /* * Inform the channel of the events. */ Tcl_NotifyChannel(infoPtr->channel, infoPtr->watchMask & mask); return 1; } /* *---------------------------------------------------------------------- * * SerialWatchProc -- * * Called by the notifier to set up to watch for events on this * channel. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void SerialWatchProc( ClientData instanceData, /* Serial state. */ int mask) /* What events to watch for, OR-ed * combination of TCL_READABLE, * TCL_WRITABLE and TCL_EXCEPTION. */ { SerialInfo **nextPtrPtr, *ptr; SerialInfo *infoPtr = (SerialInfo *) instanceData; int oldMask = infoPtr->watchMask; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); /* * Since the file is always ready for events, we set the block time * so we will poll. */ infoPtr->watchMask = mask & infoPtr->validMask; if (infoPtr->watchMask) { if (!oldMask) { infoPtr->nextPtr = tsdPtr->firstSerialPtr; tsdPtr->firstSerialPtr = infoPtr; } SerialBlockTime(infoPtr->blockTime); } else { if (oldMask) { /* * Remove the serial port from the list of watched serial ports. */ for (nextPtrPtr = &(tsdPtr->firstSerialPtr), ptr = *nextPtrPtr; ptr != NULL; nextPtrPtr = &ptr->nextPtr, ptr = *nextPtrPtr) { if (infoPtr == ptr) { *nextPtrPtr = ptr->nextPtr; break; } } } } } /* *---------------------------------------------------------------------- * * SerialGetHandleProc -- * * Called from Tcl_GetChannelHandle to retrieve OS handles from * inside a command serial port based channel. * * Results: * Returns TCL_OK with the fd in handlePtr, or TCL_ERROR if * there is no handle for the specified direction. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int SerialGetHandleProc( ClientData instanceData, /* The serial state. */ int direction, /* TCL_READABLE or TCL_WRITABLE */ ClientData *handlePtr) /* Where to store the handle. */ { SerialInfo *infoPtr = (SerialInfo *) instanceData; *handlePtr = (ClientData) infoPtr->handle; return TCL_OK; } /* *---------------------------------------------------------------------- * * SerialWriterThread -- * * This function runs in a separate thread and writes data * onto a serial. * * Results: * Always returns 0. * * Side effects: * Signals the main thread when an output operation is completed. * May cause the main thread to wake up by posting a message. * *---------------------------------------------------------------------- */ static DWORD WINAPI SerialWriterThread(LPVOID arg) { SerialInfo *infoPtr = (SerialInfo *)arg; DWORD bytesWritten, toWrite, waitResult; char *buf; OVERLAPPED myWrite; /* have an own OVERLAPPED in this thread */ HANDLE wEvents[2]; /* * The stop event takes precedence by being first in the list. */ wEvents[0] = infoPtr->evStopWriter; wEvents[1] = infoPtr->evStartWriter; for (;;) { /* * Wait for the main thread to signal before attempting to write. */ waitResult = WaitForMultipleObjects(2, wEvents, FALSE, INFINITE); if (waitResult != (WAIT_OBJECT_0 + 1)) { /* * The start event was not signaled. It might be the stop event * or an error, so exit. */ break; } buf = infoPtr->writeBuf; toWrite = infoPtr->toWrite; myWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); /* * Loop until all of the bytes are written or an error occurs. */ while (toWrite > 0) { /* * Check for pending writeError * Ignore all write operations until the user has been notified */ if (infoPtr->writeError) { break; } if (blockingWrite(infoPtr, (LPVOID) buf, (DWORD) toWrite, &bytesWritten, &myWrite) == FALSE) { infoPtr->writeError = GetLastError(); break; } if (bytesWritten != toWrite) { /* Write timeout */ infoPtr->writeError = ERROR_WRITE_FAULT; break; } toWrite -= bytesWritten; buf += bytesWritten; } CloseHandle(myWrite.hEvent); /* * Signal the main thread by signalling the evWritable event and * then waking up the notifier thread. */ SetEvent(infoPtr->evWritable); /* * Alert the foreground thread. Note that we need to treat this like * a critical section so the foreground thread does not terminate * this thread while we are holding a mutex in the notifier code. */ Tcl_MutexLock(&serialMutex); if (infoPtr->threadId != NULL) { /* TIP #218. When in flight ignore the event, no one will receive it anyway */ Tcl_ThreadAlert(infoPtr->threadId); } Tcl_MutexUnlock(&serialMutex); } return 0; } /* *---------------------------------------------------------------------- * * TclWinSerialReopen -- * * Reopens the serial port with the OVERLAPPED FLAG set * * Results: * Returns the new handle, or INVALID_HANDLE_VALUE * Normally there shouldn't be any error, * because the same channel has previously been succeesfully opened. * * Side effects: * May close the original handle * *---------------------------------------------------------------------- */ HANDLE TclWinSerialReopen(handle, name, access) HANDLE handle; CONST TCHAR *name; DWORD access; { SerialInit(); /* * Multithreaded I/O needs the overlapped flag set * otherwise ClearCommError blocks under Windows NT/2000 until serial * output is finished */ if (CloseHandle(handle) == FALSE) { return INVALID_HANDLE_VALUE; } handle = (*tclWinProcs->createFileProc)(name, access, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); return handle; } /* *---------------------------------------------------------------------- * * TclWinOpenSerialChannel -- * * Constructs a Serial port channel for the specified standard OS handle. * This is a helper function to break up the construction of * channels into File, Console, or Serial. * * Results: * Returns the new channel, or NULL. * * Side effects: * May open the channel * *---------------------------------------------------------------------- */ Tcl_Channel TclWinOpenSerialChannel(handle, channelName, permissions) HANDLE handle; char *channelName; int permissions; { SerialInfo *infoPtr; DWORD id; SerialInit(); infoPtr = (SerialInfo *) ckalloc((unsigned) sizeof(SerialInfo)); memset(infoPtr, 0, sizeof(SerialInfo)); infoPtr->validMask = permissions; infoPtr->handle = handle; infoPtr->channel = (Tcl_Channel) NULL; infoPtr->readable = 0; infoPtr->writable = 1; infoPtr->toWrite = infoPtr->writeQueue = 0; infoPtr->blockTime = SERIAL_DEFAULT_BLOCKTIME; infoPtr->lastEventTime = 0; infoPtr->lastError = infoPtr->error = 0; infoPtr->threadId = Tcl_GetCurrentThread(); infoPtr->sysBufRead = 4096; infoPtr->sysBufWrite = 4096; /* * Use the pointer to keep the channel names unique, in case * the handles are shared between multiple channels (stdin/stdout). */ wsprintfA(channelName, "file%lx", (int) infoPtr); infoPtr->channel = Tcl_CreateChannel(&serialChannelType, channelName, (ClientData) infoPtr, permissions); SetupComm(handle, infoPtr->sysBufRead, infoPtr->sysBufWrite); PurgeComm(handle, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR); /* * default is blocking */ SetCommTimeouts(handle, &no_timeout); InitializeCriticalSection(&infoPtr->csWrite); if (permissions & TCL_READABLE) { infoPtr->osRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); } if (permissions & TCL_WRITABLE) { /* * Initially the channel is writable * and the writeThread is idle. */ infoPtr->osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); infoPtr->evWritable = CreateEvent(NULL, TRUE, TRUE, NULL); infoPtr->evStartWriter = CreateEvent(NULL, FALSE, FALSE, NULL); infoPtr->evStopWriter = CreateEvent(NULL, FALSE, FALSE, NULL); infoPtr->writeThread = CreateThread(NULL, 256, SerialWriterThread, infoPtr, 0, &id); } /* * Files have default translation of AUTO and ^Z eof char, which * means that a ^Z will be accepted as EOF when reading. */ Tcl_SetChannelOption(NULL, infoPtr->channel, "-translation", "auto"); Tcl_SetChannelOption(NULL, infoPtr->channel, "-eofchar", "\032 {}"); return infoPtr->channel; } /* *---------------------------------------------------------------------- * * SerialErrorStr -- * * Converts a Win32 serial error code to a list of readable errors * *---------------------------------------------------------------------- */ static void SerialErrorStr(error, dsPtr) DWORD error; /* Win32 serial error code */ Tcl_DString *dsPtr; /* Where to store string */ { if( (error & CE_RXOVER) != 0) { Tcl_DStringAppendElement(dsPtr, "RXOVER"); } if( (error & CE_OVERRUN) != 0) { Tcl_DStringAppendElement(dsPtr, "OVERRUN"); } if( (error & CE_RXPARITY) != 0) { Tcl_DStringAppendElement(dsPtr, "RXPARITY"); } if( (error & CE_FRAME) != 0) { Tcl_DStringAppendElement(dsPtr, "FRAME"); } if( (error & CE_BREAK) != 0) { Tcl_DStringAppendElement(dsPtr, "BREAK"); } if( (error & CE_TXFULL) != 0) { Tcl_DStringAppendElement(dsPtr, "TXFULL"); } if( (error & CE_PTO) != 0) { /* PTO used to signal WRITE-TIMEOUT */ Tcl_DStringAppendElement(dsPtr, "TIMEOUT"); } if( (error & ~((DWORD) (SERIAL_READ_ERRORS | SERIAL_WRITE_ERRORS))) != 0) { char buf[TCL_INTEGER_SPACE + 1]; wsprintfA(buf, "%d", error); Tcl_DStringAppendElement(dsPtr, buf); } } /* *---------------------------------------------------------------------- * * SerialModemStatusStr -- * * Converts a Win32 modem status list of readable flags * *---------------------------------------------------------------------- */ static void SerialModemStatusStr(status, dsPtr) DWORD status; /* Win32 modem status */ Tcl_DString *dsPtr; /* Where to store string */ { Tcl_DStringAppendElement(dsPtr, "CTS"); Tcl_DStringAppendElement(dsPtr, (status & MS_CTS_ON) ? "1" : "0"); Tcl_DStringAppendElement(dsPtr, "DSR"); Tcl_DStringAppendElement(dsPtr, (status & MS_DSR_ON) ? "1" : "0"); Tcl_DStringAppendElement(dsPtr, "RING"); Tcl_DStringAppendElement(dsPtr, (status & MS_RING_ON) ? "1" : "0"); Tcl_DStringAppendElement(dsPtr, "DCD"); Tcl_DStringAppendElement(dsPtr, (status & MS_RLSD_ON) ? "1" : "0"); } /* *---------------------------------------------------------------------- * * SerialSetOptionProc -- * * Sets an option on a channel. * * Results: * A standard Tcl result. Also sets the interp's result on error if * interp is not NULL. * * Side effects: * May modify an option on a device. * *---------------------------------------------------------------------- */ static int SerialSetOptionProc(instanceData, interp, optionName, value) ClientData instanceData; /* File state. */ Tcl_Interp *interp; /* For error reporting - can be NULL. */ CONST char *optionName; /* Which option to set? */ CONST char *value; /* New value for option. */ { SerialInfo *infoPtr; DCB dcb; BOOL result, flag; size_t len, vlen; Tcl_DString ds; CONST TCHAR *native; int argc; CONST char **argv; infoPtr = (SerialInfo *) instanceData; /* * Parse options */ len = strlen(optionName); vlen = strlen(value); /* * Option -mode baud,parity,databits,stopbits */ if ((len > 2) && (strncmp(optionName, "-mode", len) == 0)) { if (! GetCommState(infoPtr->handle, &dcb)) { if (interp) { Tcl_AppendResult(interp, "can't get comm state", (char *) NULL); } return TCL_ERROR; } native = Tcl_WinUtfToTChar(value, -1, &ds); result = (*tclWinProcs->buildCommDCBProc)(native, &dcb); Tcl_DStringFree(&ds); if (result == FALSE) { if (interp) { Tcl_AppendResult(interp, "bad value for -mode: should be baud,parity,data,stop", (char *) NULL); } return TCL_ERROR; } /* Default settings for serial communications */ dcb.fBinary = TRUE; dcb.fErrorChar = FALSE; dcb.fNull = FALSE; dcb.fAbortOnError = FALSE; if (! SetCommState(infoPtr->handle, &dcb) ) { if (interp) { Tcl_AppendResult(interp, "can't set comm state", (char *) NULL); } return TCL_ERROR; } return TCL_OK; } /* * Option -handshake none|xonxoff|rtscts|dtrdsr */ if ((len > 1) && (strncmp(optionName, "-handshake", len) == 0)) { if (! GetCommState(infoPtr->handle, &dcb)) { if (interp) { Tcl_AppendResult(interp, "can't get comm state", (char *) NULL); } return TCL_ERROR; } /* * Reset all handshake options * DTR and RTS are ON by default */ dcb.fOutX = dcb.fInX = FALSE; dcb.fOutxCtsFlow = dcb.fOutxDsrFlow = dcb.fDsrSensitivity = FALSE; dcb.fDtrControl = DTR_CONTROL_ENABLE; dcb.fRtsControl = RTS_CONTROL_ENABLE; dcb.fTXContinueOnXoff = FALSE; /* * Adjust the handshake limits. * Yes, the XonXoff limits seem to influence even hardware handshake */ dcb.XonLim = (WORD) (infoPtr->sysBufRead*1/2); dcb.XoffLim = (WORD) (infoPtr->sysBufRead*1/4); if (strnicmp(value, "NONE", vlen) == 0) { /* leave all handshake options disabled */ } else if (strnicmp(value, "XONXOFF", vlen) == 0) { dcb.fOutX = dcb.fInX = TRUE; } else if (strnicmp(value, "RTSCTS", vlen) == 0) { dcb.fOutxCtsFlow = TRUE; dcb.fRtsControl = RTS_CONTROL_HANDSHAKE; } else if (strnicmp(value, "DTRDSR", vlen) == 0) { dcb.fOutxDsrFlow = TRUE; dcb.fDtrControl = DTR_CONTROL_HANDSHAKE; } else { if (interp) { Tcl_AppendResult(interp, "bad value for -handshake: ", "must be one of xonxoff, rtscts, dtrdsr or none", (char *) NULL); return TCL_ERROR; } } if (! SetCommState(infoPtr->handle, &dcb)) { if (interp) { Tcl_AppendResult(interp, "can't set comm state", (char *) NULL); } return TCL_ERROR; } return TCL_OK; } /* * Option -xchar {\x11 \x13} */ if ((len > 1) && (strncmp(optionName, "-xchar", len) == 0)) { if (! GetCommState(infoPtr->handle, &dcb)) { if (interp) { Tcl_AppendResult(interp, "can't get comm state", (char *) NULL); } return TCL_ERROR; } if (Tcl_SplitList(interp, value, &argc, &argv) == TCL_ERROR) { return TCL_ERROR; } if (argc == 2) { dcb.XonChar = argv[0][0]; dcb.XoffChar = argv[1][0]; ckfree((char *) argv); } else { if (interp) { Tcl_AppendResult(interp, "bad value for -xchar: should be a list of two elements", (char *) NULL); } ckfree((char *) argv); return TCL_ERROR; } if (! SetCommState(infoPtr->handle, &dcb)) { if (interp) { Tcl_AppendResult(interp, "can't set comm state", (char *) NULL); } return TCL_ERROR; } return TCL_OK; } /* * Option -ttycontrol {DTR 1 RTS 0 BREAK 0} */ if ((len > 4) && (strncmp(optionName, "-ttycontrol", len) == 0)) { int i, result = TCL_OK; if (Tcl_SplitList(interp, value, &argc, &argv) == TCL_ERROR) { return TCL_ERROR; } if ((argc % 2) == 1) { if (interp) { Tcl_AppendResult(interp, "bad value for -ttycontrol: should be a list of signal,value pairs", (char *) NULL); } ckfree((char *) argv); return TCL_ERROR; } for (i = 0; i < argc - 1; i += 2) { if (Tcl_GetBoolean(interp, argv[i+1], &flag) == TCL_ERROR) { result = TCL_ERROR; break; } if (strnicmp(argv[i], "DTR", strlen(argv[i])) == 0) { if (!EscapeCommFunction(infoPtr->handle, flag ? (DWORD) SETDTR : (DWORD) CLRDTR)) { if (interp) { Tcl_AppendResult(interp, "can't set DTR signal", (char *) NULL); } result = TCL_ERROR; break; } } else if (strnicmp(argv[i], "RTS", strlen(argv[i])) == 0) { if (!EscapeCommFunction(infoPtr->handle, flag ? (DWORD) SETRTS : (DWORD) CLRRTS)) { if (interp) { Tcl_AppendResult(interp, "can't set RTS signal", (char *) NULL); } result = TCL_ERROR; break; } } else if (strnicmp(argv[i], "BREAK", strlen(argv[i])) == 0) { if (!EscapeCommFunction(infoPtr->handle, flag ? (DWORD) SETBREAK : (DWORD) CLRBREAK)) { if (interp) { Tcl_AppendResult(interp, "can't set BREAK signal", (char *) NULL); } result = TCL_ERROR; break; } } else { if (interp) { Tcl_AppendResult(interp, "bad signal for -ttycontrol: ", "must be DTR, RTS or BREAK", (char *) NULL); } result = TCL_ERROR; break; } } ckfree((char *) argv); return result; } /* * Option -sysbuffer {read_size write_size} * Option -sysbuffer read_size */ if ((len > 1) && (strncmp(optionName, "-sysbuffer", len) == 0)) { /* * -sysbuffer 4096 or -sysbuffer {64536 4096} */ size_t inSize = (size_t) -1, outSize = (size_t) -1; if (Tcl_SplitList(interp, value, &argc, &argv) == TCL_ERROR) { return TCL_ERROR; } if (argc == 1) { inSize = atoi(argv[0]); outSize = infoPtr->sysBufWrite; } else if (argc == 2) { inSize = atoi(argv[0]); outSize = atoi(argv[1]); } ckfree((char *) argv); if ((inSize <= 0) || (outSize <= 0)) { if (interp) { Tcl_AppendResult(interp, "bad value for -sysbuffer: should be a list of one or two integers > 0", (char *) NULL); } return TCL_ERROR; } if (! SetupComm(infoPtr->handle, inSize, outSize)) { if (interp) { Tcl_AppendResult(interp, "can't setup comm buffers", (char *) NULL); } return TCL_ERROR; } infoPtr->sysBufRead = inSize; infoPtr->sysBufWrite = outSize; /* * Adjust the handshake limits. * Yes, the XonXoff limits seem to influence even hardware handshake */ if (! GetCommState(infoPtr->handle, &dcb)) { if (interp) { Tcl_AppendResult(interp, "can't get comm state", (char *) NULL); } return TCL_ERROR; } dcb.XonLim = (WORD) (infoPtr->sysBufRead*1/2); dcb.XoffLim = (WORD) (infoPtr->sysBufRead*1/4); if (! SetCommState(infoPtr->handle, &dcb)) { if (interp) { Tcl_AppendResult(interp, "can't set comm state", (char *) NULL); } return TCL_ERROR; } return TCL_OK; } /* * Option -pollinterval msec */ if ((len > 1) && (strncmp(optionName, "-pollinterval", len) == 0)) { if ( Tcl_GetInt(interp, value, &(infoPtr->blockTime)) != TCL_OK ) { return TCL_ERROR; } return TCL_OK; } /* * Option -timeout msec */ if ((len > 2) && (strncmp(optionName, "-timeout", len) == 0)) { int msec; COMMTIMEOUTS tout = {0,0,0,0,0}; if ( Tcl_GetInt(interp, value, &msec) != TCL_OK ) { return TCL_ERROR; } tout.ReadTotalTimeoutConstant = msec; if (! SetCommTimeouts(infoPtr->handle, &tout)) { if (interp) { Tcl_AppendResult(interp, "can't set comm timeouts", (char *) NULL); } return TCL_ERROR; } return TCL_OK; } return Tcl_BadChannelOption(interp, optionName, "mode handshake pollinterval sysbuffer timeout ttycontrol xchar"); } /* *---------------------------------------------------------------------- * * SerialGetOptionProc -- * * Gets a mode associated with an IO channel. If the optionName arg * is non NULL, retrieves the value of that option. If the optionName * arg is NULL, retrieves a list of alternating option names and * values for the given channel. * * Results: * A standard Tcl result. Also sets the supplied DString to the * string value of the option(s) returned. * * Side effects: * The string returned by this function is in static storage and * may be reused at any time subsequent to the call. * *---------------------------------------------------------------------- */ static int SerialGetOptionProc(instanceData, interp, optionName, dsPtr) ClientData instanceData; /* File state. */ Tcl_Interp *interp; /* For error reporting - can be NULL. */ CONST char *optionName; /* Option to get. */ Tcl_DString *dsPtr; /* Where to store value(s). */ { SerialInfo *infoPtr; DCB dcb; size_t len; int valid = 0; /* flag if valid option parsed */ infoPtr = (SerialInfo *) instanceData; if (optionName == NULL) { len = 0; } else { len = strlen(optionName); } /* * get option -mode */ if (len == 0) { Tcl_DStringAppendElement(dsPtr, "-mode"); } if ((len == 0) || ((len > 2) && (strncmp(optionName, "-mode", len) == 0))) { char parity; char *stop; char buf[2 * TCL_INTEGER_SPACE + 16]; if (! GetCommState(infoPtr->handle, &dcb)) { if (interp) { Tcl_AppendResult(interp, "can't get comm state", (char *) NULL); } return TCL_ERROR; } valid = 1; parity = 'n'; if (dcb.Parity <= 4) { parity = "noems"[dcb.Parity]; } stop = (dcb.StopBits == ONESTOPBIT) ? "1" : (dcb.StopBits == ONE5STOPBITS) ? "1.5" : "2"; wsprintfA(buf, "%d,%c,%d,%s", dcb.BaudRate, parity, dcb.ByteSize, stop); Tcl_DStringAppendElement(dsPtr, buf); } /* * get option -pollinterval */ if (len == 0) { Tcl_DStringAppendElement(dsPtr, "-pollinterval"); } if ((len == 0) || ((len > 1) && (strncmp(optionName, "-pollinterval", len) == 0))) { char buf[TCL_INTEGER_SPACE + 1]; valid = 1; wsprintfA(buf, "%d", infoPtr->blockTime); Tcl_DStringAppendElement(dsPtr, buf); } /* * get option -sysbuffer */ if (len == 0) { Tcl_DStringAppendElement(dsPtr, "-sysbuffer"); Tcl_DStringStartSublist(dsPtr); } if ((len == 0) || ((len > 1) && (strncmp(optionName, "-sysbuffer", len) == 0))) { char buf[TCL_INTEGER_SPACE + 1]; valid = 1; wsprintfA(buf, "%d", infoPtr->sysBufRead); Tcl_DStringAppendElement(dsPtr, buf); wsprintfA(buf, "%d", infoPtr->sysBufWrite); Tcl_DStringAppendElement(dsPtr, buf); } if (len == 0) { Tcl_DStringEndSublist(dsPtr); } /* * get option -xchar */ if (len == 0) { Tcl_DStringAppendElement(dsPtr, "-xchar"); Tcl_DStringStartSublist(dsPtr); } if ((len == 0) || ((len > 1) && (strncmp(optionName, "-xchar", len) == 0))) { char buf[4]; valid = 1; if (! GetCommState(infoPtr->handle, &dcb)) { if (interp) { Tcl_AppendResult(interp, "can't get comm state", (char *) NULL); } return TCL_ERROR; } sprintf(buf, "%c", dcb.XonChar); Tcl_DStringAppendElement(dsPtr, buf); sprintf(buf, "%c", dcb.XoffChar); Tcl_DStringAppendElement(dsPtr, buf); } if (len == 0) { Tcl_DStringEndSublist(dsPtr); } /* * get option -lasterror * option is readonly and returned by [fconfigure chan -lasterror] * but not returned by unnamed [fconfigure chan] */ if ( (len > 1) && (strncmp(optionName, "-lasterror", len) == 0) ) { valid = 1; SerialErrorStr(infoPtr->lastError, dsPtr); } /* * get option -queue * option is readonly and returned by [fconfigure chan -queue] */ if ((len > 1) && (strncmp(optionName, "-queue", len) == 0)) { char buf[TCL_INTEGER_SPACE + 1]; COMSTAT cStat; DWORD error; int inBuffered, outBuffered, count; valid = 1; /* * Query the pending data in Tcl's internal queues */ inBuffered = Tcl_InputBuffered(infoPtr->channel); outBuffered = Tcl_OutputBuffered(infoPtr->channel); /* * Query the number of bytes in our output queue: * 1. The bytes pending in the output thread * 2. The bytes in the system drivers buffer * The writer thread should not interfere this action. */ EnterCriticalSection(&infoPtr->csWrite); ClearCommError( infoPtr->handle, &error, &cStat ); count = (int)cStat.cbOutQue + infoPtr->writeQueue; LeaveCriticalSection(&infoPtr->csWrite); wsprintfA(buf, "%d", inBuffered + cStat.cbInQue); Tcl_DStringAppendElement(dsPtr, buf); wsprintfA(buf, "%d", outBuffered + count); Tcl_DStringAppendElement(dsPtr, buf); } /* * get option -ttystatus * option is readonly and returned by [fconfigure chan -ttystatus] * but not returned by unnamed [fconfigure chan] */ if ((len > 4) && (strncmp(optionName, "-ttystatus", len) == 0)) { DWORD status; if (! GetCommModemStatus(infoPtr->handle, &status)) { if (interp) { Tcl_AppendResult(interp, "can't get tty status", (char *) NULL); } return TCL_ERROR; } valid = 1; SerialModemStatusStr(status, dsPtr); } if (valid) { return TCL_OK; } else { return Tcl_BadChannelOption(interp, optionName, "mode pollinterval lasterror queue sysbuffer ttystatus xchar"); } } /* *---------------------------------------------------------------------- * * SerialThreadActionProc -- * * Insert or remove any thread local refs to this channel. * * Results: * None. * * Side effects: * Changes thread local list of valid channels. * *---------------------------------------------------------------------- */ static void SerialThreadActionProc (instanceData, action) ClientData instanceData; int action; { SerialInfo *infoPtr = (SerialInfo *) instanceData; /* We do not access firstSerialPtr in the thread structures. This is * not for all serials managed by the thread, but only those we are * watching. Removal of the filevent handlers before transfer thus * takes care of this structure. */ Tcl_MutexLock(&serialMutex); if (action == TCL_CHANNEL_THREAD_INSERT) { /* We can't copy the thread information from the channel when * the channel is created. At this time the channel back * pointer has not been set yet. However in that case the * threadId has already been set by TclpCreateCommandChannel * itself, so the structure is still good. */ SerialInit (); if (infoPtr->channel != NULL) { infoPtr->threadId = Tcl_GetChannelThread (infoPtr->channel); } } else { infoPtr->threadId = NULL; } Tcl_MutexUnlock(&serialMutex); } tcl8.4.20/win/tclWinThrd.h0000644003604700454610000000060311737050675013747 0ustar dgp771div/* * tclWinThrd.h -- * * This header file defines things for thread support. * * Copyright (c) 1998 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef _TCLWINTHRD #define _TCLWINTHRD #ifdef TCL_THREADS #endif /* TCL_THREADS */ #endif /* _TCLWINTHRD */